[pkg-java] r2739 - in branches: . tomcat5.5 tomcat5.5/upstream tomcat5.5/upstream/5.5.20 tomcat5.5/upstream/5.5.20/build tomcat5.5/upstream/5.5.20/build/resources tomcat5.5/upstream/5.5.20/build/resources/confinstall tomcat5.5/upstream/5.5.20/build/resources/deployer tomcat5.5/upstream/5.5.20/build/resources/mbeans tomcat5.5/upstream/5.5.20/connectors tomcat5.5/upstream/5.5.20/connectors/ajp tomcat5.5/upstream/5.5.20/connectors/ajp/ajplib tomcat5.5/upstream/5.5.20/connectors/ajp/ajplib/include tomcat5.5/upstream/5.5.20/connectors/ajp/ajplib/src tomcat5.5/upstream/5.5.20/connectors/ajp/ajplib/test tomcat5.5/upstream/5.5.20/connectors/ajp/proxy tomcat5.5/upstream/5.5.20/connectors/coyote tomcat5.5/upstream/5.5.20/connectors/coyote/src tomcat5.5/upstream/5.5.20/connectors/coyote/src/conf tomcat5.5/upstream/5.5.20/connectors/coyote/src/java tomcat5.5/upstream/5.5.20/connectors/coyote/src/java/org tomcat5.5/upstream/5.5.20/connectors/coyote/src/java/org/apache tomcat5.5/upstream/5.5.20/connectors/coyote/src/java/org/apache/coyote tomcat5.5/upstream/5.5.20/connectors/coyote/src/java/org/apache/coyote/memory tomcat5.5/upstream/5.5.20/connectors/coyote/src/java/org/apache/coyote/tomcat3 tomcat5.5/upstream/5.5.20/connectors/coyote/src/java/org/apache/coyote/tomcat4 tomcat5.5/upstream/5.5.20/connectors/coyote/src/test tomcat5.5/upstream/5.5.20/connectors/coyote/src/test/org tomcat5.5/upstream/5.5.20/connectors/coyote/src/test/org/apache tomcat5.5/upstream/5.5.20/connectors/coyote/src/test/org/apache/coyote tomcat5.5/upstream/5.5.20/connectors/doc tomcat5.5/upstream/5.5.20/connectors/http11 tomcat5.5/upstream/5.5.20/connectors/http11/src tomcat5.5/upstream/5.5.20/connectors/http11/src/conf tomcat5.5/upstream/5.5.20/connectors/http11/src/java tomcat5.5/upstream/5.5.20/connectors/http11/src/java/org tomcat5.5/upstream/5.5.20/connectors/http11/src/java/org/apache tomcat5.5/upstream/5.5.20/connectors/http11/src/java/org/apache/coyote tomcat5.5/upstream/5.5.20/connectors/http11/src/java/org/apache/coyote/http11 tomcat5.5/upstream/5.5.20/connectors/http11/src/java/org/apache/coyote/http11/filters tomcat5.5/upstream/5.5.20/connectors/http11/src/test tomcat5.5/upstream/5.5.20/connectors/http11/src/test/java tomcat5.5/upstream/5.5.20/connectors/http11/src/test/java/org tomcat5.5/upstream/5.5.20/connectors/http11/src/test/java/org/apache tomcat5.5/upstream/5.5.20/connectors/http11/src/test/java/org/apache/coyote tomcat5.5/upstream/5.5.20/connectors/http11/src/test/java/org/apache/coyote/http11 tomcat5.5/upstream/5.5.20/connectors/http11/src/test/tests tomcat5.5/upstream/5.5.20/connectors/jk tomcat5.5/upstream/5.5.20/connectors/jk/conf tomcat5.5/upstream/5.5.20/connectors/jk/java tomcat5.5/upstream/5.5.20/connectors/jk/java/org tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/ajp tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/ajp/tomcat33 tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/ajp/tomcat4 tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/ajp/tomcat4/config tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/coyote tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/coyote/ajp tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/apr tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/common tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/config tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/core tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/server tomcat5.5/upstream/5.5.20/connectors/jk/jkant tomcat5.5/upstream/5.5.20/connectors/jk/jkant/java tomcat5.5/upstream/5.5.20/connectors/jk/jkant/java/org tomcat5.5/upstream/5.5.20/connectors/jk/jkant/java/org/apache tomcat5.5/upstream/5.5.20/connectors/jk/jkant/java/org/apache/jk tomcat5.5/upstream/5.5.20/connectors/jk/jkant/java/org/apache/jk/ant tomcat5.5/upstream/5.5.20/connectors/jk/jkant/java/org/apache/jk/ant/compilers tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/build tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/build/classes tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/build/classes/org tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/build/classes/org/apache tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/build/classes/org/apache/jk tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/build/classes/org/apache/jk/status tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/conf tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/dist tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/example tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/src tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/src/share tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/src/share/org tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/src/share/org/apache tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/src/share/org/apache/jk tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/src/share/org/apache/jk/status tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/test tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/test/conf tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/test/src tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/test/src/share tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/test/src/share/org tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/test/src/share/org/apache tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/test/src/share/org/apache/jk tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/test/src/share/org/apache/jk/status tomcat5.5/upstream/5.5.20/connectors/jk/native tomcat5.5/upstream/5.5.20/connectors/jk/native/apache-1.3 tomcat5.5/upstream/5.5.20/connectors/jk/native/apache-2.0 tomcat5.5/upstream/5.5.20/connectors/jk/native/common tomcat5.5/upstream/5.5.20/connectors/jk/native/docs tomcat5.5/upstream/5.5.20/connectors/jk/native/docs/api tomcat5.5/upstream/5.5.20/connectors/jk/native/iis tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/installer tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/installer/bin tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/installer/conf tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/installer/log tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/doc tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/testdata tomcat5.5/upstream/5.5.20/connectors/jk/native/jni tomcat5.5/upstream/5.5.20/connectors/jk/native/netscape tomcat5.5/upstream/5.5.20/connectors/jk/native/nt_service tomcat5.5/upstream/5.5.20/connectors/jk/native/scripts tomcat5.5/upstream/5.5.20/connectors/jk/native/scripts/build tomcat5.5/upstream/5.5.20/connectors/jk/native/scripts/build/unix tomcat5.5/upstream/5.5.20/connectors/jk/support tomcat5.5/upstream/5.5.20/connectors/jk/test tomcat5.5/upstream/5.5.20/connectors/jk/test/org tomcat5.5/upstream/5.5.20/connectors/jk/test/org/apache tomcat5.5/upstream/5.5.20/connectors/jk/test/org/apache/ajp tomcat5.5/upstream/5.5.20/connectors/jk/test/org/apache/ajp/test tomcat5.5/upstream/5.5.20/connectors/jk/tools tomcat5.5/upstream/5.5.20/connectors/jk/tools/reports tomcat5.5/upstream/5.5.20/connectors/jk/xdocs tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/common tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/config tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/howto tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/images tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/jk2 tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/news tomcat5.5/upstream/5.5.20/connectors/jni tomcat5.5/upstream/5.5.20/connectors/jni/examples tomcat5.5/upstream/5.5.20/connectors/jni/examples/org tomcat5.5/upstream/5.5.20/connectors/jni/examples/org/apache tomcat5.5/upstream/5.5.20/connectors/jni/examples/org/apache/tomcat tomcat5.5/upstream/5.5.20/connectors/jni/examples/org/apache/tomcat/jni tomcat5.5/upstream/5.5.20/connectors/jni/java tomcat5.5/upstream/5.5.20/connectors/jni/java/org tomcat5.5/upstream/5.5.20/connectors/jni/java/org/apache tomcat5.5/upstream/5.5.20/connectors/jni/java/org/apache/tomcat tomcat5.5/upstream/5.5.20/connectors/jni/java/org/apache/tomcat/jni tomcat5.5/upstream/5.5.20/connectors/jni/native tomcat5.5/upstream/5.5.20/connectors/jni/native/build tomcat5.5/upstream/5.5.20/connectors/jni/native/build/rpm tomcat5.5/upstream/5.5.20/connectors/jni/native/include tomcat5.5/upstream/5.5.20/connectors/jni/native/os tomcat5.5/upstream/5.5.20/connectors/jni/native/os/netware tomcat5.5/upstream/5.5.20/connectors/jni/native/os/unix tomcat5.5/upstream/5.5.20/connectors/jni/native/os/win32 tomcat5.5/upstream/5.5.20/connectors/jni/native/src tomcat5.5/upstream/5.5.20/connectors/jni/test tomcat5.5/upstream/5.5.20/connectors/jni/test/org tomcat5.5/upstream/5.5.20/connectors/jni/test/org/apache tomcat5.5/upstream/5.5.20/connectors/jni/test/org/apache/tomcat tomcat5.5/upstream/5.5.20/connectors/jni/test/org/apache/tomcat/jni tomcat5.5/upstream/5.5.20/connectors/juli tomcat5.5/upstream/5.5.20/connectors/juli/src tomcat5.5/upstream/5.5.20/connectors/juli/src/conf tomcat5.5/upstream/5.5.20/connectors/juli/src/java tomcat5.5/upstream/5.5.20/connectors/juli/src/java/org tomcat5.5/upstream/5.5.20/connectors/juli/src/java/org/apache tomcat5.5/upstream/5.5.20/connectors/juli/src/java/org/apache/juli tomcat5.5/upstream/5.5.20/connectors/procrun tomcat5.5/upstream/5.5.20/connectors/procrun/bin tomcat5.5/upstream/5.5.20/connectors/scandoc tomcat5.5/upstream/5.5.20/connectors/util tomcat5.5/upstream/5.5.20/connectors/util/java tomcat5.5/upstream/5.5.20/connectors/util/java/org tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/buf tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/buf/res tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/collections tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/compat tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/digester tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/http tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/http/mapper tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/http/res tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/log tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/net tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/net/jsse tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/net/jsse/res tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/net/puretls tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/net/res tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/res tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/threads tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/threads/res tomcat5.5/upstream/5.5.20/connectors/util/loader tomcat5.5/upstream/5.5.20/connectors/util/loader/org tomcat5.5/upstream/5.5.20/connectors/util/loader/org/apache tomcat5.5/upstream/5.5.20/connectors/util/loader/org/apache/tomcat tomcat5.5/upstream/5.5.20/connectors/util/loader/org/apache/tomcat/util tomcat5.5/upstream/5.5.20/connectors/util/loader/org/apache/tomcat/util/loader tomcat5.5/upstream/5.5.20/container tomcat5.5/upstream/5.5.20/container/catalina tomcat5.5/upstream/5.5.20/container/catalina/etc tomcat5.5/upstream/5.5.20/container/catalina/src tomcat5.5/upstream/5.5.20/container/catalina/src/bin tomcat5.5/upstream/5.5.20/container/catalina/src/conf tomcat5.5/upstream/5.5.20/container/catalina/src/share tomcat5.5/upstream/5.5.20/container/catalina/src/share/org tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ant tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ant/jmx tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/authenticator tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/connector tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/core tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/deploy tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/launcher tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/loader tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/mbeans tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/realm tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/security tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/servlets tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/session tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ssi tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/startup tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/users tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/valves tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/factory tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/java tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/resources tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/resources/jndi tomcat5.5/upstream/5.5.20/container/catalina/src/temp tomcat5.5/upstream/5.5.20/container/catalina/src/test tomcat5.5/upstream/5.5.20/container/catalina/src/test/org tomcat5.5/upstream/5.5.20/container/catalina/src/test/org/apache tomcat5.5/upstream/5.5.20/container/catalina/src/test/org/apache/catalina tomcat5.5/upstream/5.5.20/container/catalina/src/test/org/apache/catalina/util tomcat5.5/upstream/5.5.20/container/catalina/src/test/org/apache/naming tomcat5.5/upstream/5.5.20/container/catalina/src/test/org/apache/naming/resources tomcat5.5/upstream/5.5.20/container/etc tomcat5.5/upstream/5.5.20/container/modules tomcat5.5/upstream/5.5.20/container/modules/cluster tomcat5.5/upstream/5.5.20/container/modules/cluster/etc tomcat5.5/upstream/5.5.20/container/modules/cluster/src tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/deploy tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/io tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/mcast tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/session tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/tcp tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/util tomcat5.5/upstream/5.5.20/container/modules/cluster/test tomcat5.5/upstream/5.5.20/container/modules/cluster/test/conf tomcat5.5/upstream/5.5.20/container/modules/cluster/test/src tomcat5.5/upstream/5.5.20/container/modules/cluster/test/src/share tomcat5.5/upstream/5.5.20/container/modules/cluster/test/src/share/org tomcat5.5/upstream/5.5.20/container/modules/cluster/test/src/share/org/apache tomcat5.5/upstream/5.5.20/container/modules/cluster/test/src/share/org/apache/catalina tomcat5.5/upstream/5.5.20/container/modules/cluster/test/src/share/org/apache/catalina/cluster tomcat5.5/upstream/5.5.20/container/modules/cluster/test/src/share/org/apache/catalina/cluster/io tomcat5.5/upstream/5.5.20/container/modules/cluster/test/src/share/org/apache/catalina/cluster/mcast tomcat5.5/upstream/5.5.20/container/modules/cluster/test/src/share/org/apache/catalina/cluster/session tomcat5.5/upstream/5.5.20/container/modules/cluster/test/src/share/org/apache/catalina/cluster/tcp tomcat5.5/upstream/5.5.20/container/modules/groupcom tomcat5.5/upstream/5.5.20/container/modules/groupcom/doc tomcat5.5/upstream/5.5.20/container/modules/groupcom/etc tomcat5.5/upstream/5.5.20/container/modules/groupcom/src tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/group tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/group/interceptors tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/io tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/membership tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/tipis tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/transport tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/transport/bio tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/transport/bio/util tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/transport/nio tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/util tomcat5.5/upstream/5.5.20/container/modules/groupcom/test tomcat5.5/upstream/5.5.20/container/modules/groupcom/test/java tomcat5.5/upstream/5.5.20/container/modules/groupcom/test/java/org tomcat5.5/upstream/5.5.20/container/modules/groupcom/test/java/org/apache tomcat5.5/upstream/5.5.20/container/modules/groupcom/test/java/org/apache/catalina tomcat5.5/upstream/5.5.20/container/modules/groupcom/test/java/org/apache/catalina/tribes tomcat5.5/upstream/5.5.20/container/modules/groupcom/test/java/org/apache/catalina/tribes/demos tomcat5.5/upstream/5.5.20/container/modules/groupcom/test/java/org/apache/catalina/tribes/group tomcat5.5/upstream/5.5.20/container/modules/groupcom/test/java/org/apache/catalina/tribes/test tomcat5.5/upstream/5.5.20/container/modules/groupcom/test/java/org/apache/catalina/tribes/test/channel tomcat5.5/upstream/5.5.20/container/modules/groupcom/test/java/org/apache/catalina/tribes/test/interceptors tomcat5.5/upstream/5.5.20/container/modules/groupcom/test/java/org/apache/catalina/tribes/test/io tomcat5.5/upstream/5.5.20/container/modules/groupcom/test/java/org/apache/catalina/tribes/test/membership tomcat5.5/upstream/5.5.20/container/modules/groupcom/test/java/org/apache/catalina/tribes/test/transport tomcat5.5/upstream/5.5.20/container/modules/ha tomcat5.5/upstream/5.5.20/container/modules/ha/etc tomcat5.5/upstream/5.5.20/container/modules/ha/src tomcat5.5/upstream/5.5.20/container/modules/ha/src/share tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/context tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/deploy tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/session tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/tcp tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/util tomcat5.5/upstream/5.5.20/container/modules/storeconfig tomcat5.5/upstream/5.5.20/container/modules/storeconfig/docs tomcat5.5/upstream/5.5.20/container/modules/storeconfig/src tomcat5.5/upstream/5.5.20/container/modules/storeconfig/src/share tomcat5.5/upstream/5.5.20/container/modules/storeconfig/src/share/org tomcat5.5/upstream/5.5.20/container/modules/storeconfig/src/share/org/apache tomcat5.5/upstream/5.5.20/container/modules/storeconfig/src/share/org/apache/catalina tomcat5.5/upstream/5.5.20/container/modules/storeconfig/src/share/org/apache/catalina/storeconfig tomcat5.5/upstream/5.5.20/container/modules/storeconfig/test tomcat5.5/upstream/5.5.20/container/modules/storeconfig/test/conf tomcat5.5/upstream/5.5.20/container/modules/storeconfig/test/src tomcat5.5/upstream/5.5.20/container/modules/storeconfig/test/src/share tomcat5.5/upstream/5.5.20/container/modules/storeconfig/test/src/share/org tomcat5.5/upstream/5.5.20/container/modules/storeconfig/test/src/share/org/apache tomcat5.5/upstream/5.5.20/container/modules/storeconfig/test/src/share/org/apache/catalina tomcat5.5/upstream/5.5.20/container/modules/storeconfig/test/src/share/org/apache/catalina/storeconfig tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/docs tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/src tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/src/share tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/src/share/org tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/src/share/org/apache tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/src/share/org/apache/catalina tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/src/share/org/apache/catalina/storeconfig tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/test tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/test/conf tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/test/src tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/test/src/share tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/test/src/share/org tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/test/src/share/org/apache tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/test/src/share/org/apache/catalina tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/test/src/share/org/apache/catalina/storeconfig tomcat5.5/upstream/5.5.20/container/tester tomcat5.5/upstream/5.5.20/container/tester/src tomcat5.5/upstream/5.5.20/container/tester/src/bin tomcat5.5/upstream/5.5.20/container/tester/src/conf tomcat5.5/upstream/5.5.20/container/tester/src/tester tomcat5.5/upstream/5.5.20/container/tester/src/tester/org tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/shared tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/unpshared tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/unshared tomcat5.5/upstream/5.5.20/container/tester/web tomcat5.5/upstream/5.5.20/container/tester/web/WEB-INF tomcat5.5/upstream/5.5.20/container/tester/web/WEB-INF/cgi tomcat5.5/upstream/5.5.20/container/tester/web/golden tomcat5.5/upstream/5.5.20/container/tester/web/ssidir tomcat5.5/upstream/5.5.20/container/webapps tomcat5.5/upstream/5.5.20/container/webapps/ROOT tomcat5.5/upstream/5.5.20/container/webapps/ROOT/WEB-INF tomcat5.5/upstream/5.5.20/container/webapps/ROOT/admin tomcat5.5/upstream/5.5.20/container/webapps/admin tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/connector tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/context tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/filters tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/host tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/realm tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/resources tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/server tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/service tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/users tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/valve tomcat5.5/upstream/5.5.20/container/webapps/admin/connector tomcat5.5/upstream/5.5.20/container/webapps/admin/context tomcat5.5/upstream/5.5.20/container/webapps/admin/host tomcat5.5/upstream/5.5.20/container/webapps/admin/images tomcat5.5/upstream/5.5.20/container/webapps/admin/realm tomcat5.5/upstream/5.5.20/container/webapps/admin/resources tomcat5.5/upstream/5.5.20/container/webapps/admin/server tomcat5.5/upstream/5.5.20/container/webapps/admin/service tomcat5.5/upstream/5.5.20/container/webapps/admin/users tomcat5.5/upstream/5.5.20/container/webapps/admin/valve tomcat5.5/upstream/5.5.20/container/webapps/balancer tomcat5.5/upstream/5.5.20/container/webapps/balancer/META-INF tomcat5.5/upstream/5.5.20/container/webapps/balancer/WEB-INF tomcat5.5/upstream/5.5.20/container/webapps/balancer/WEB-INF/classes tomcat5.5/upstream/5.5.20/container/webapps/balancer/WEB-INF/classes/org tomcat5.5/upstream/5.5.20/container/webapps/balancer/WEB-INF/classes/org/apache tomcat5.5/upstream/5.5.20/container/webapps/balancer/WEB-INF/classes/org/apache/webapp tomcat5.5/upstream/5.5.20/container/webapps/balancer/WEB-INF/classes/org/apache/webapp/balancer tomcat5.5/upstream/5.5.20/container/webapps/balancer/WEB-INF/classes/org/apache/webapp/balancer/rules tomcat5.5/upstream/5.5.20/container/webapps/balancer/WEB-INF/config tomcat5.5/upstream/5.5.20/container/webapps/docs tomcat5.5/upstream/5.5.20/container/webapps/docs/META-INF tomcat5.5/upstream/5.5.20/container/webapps/docs/WEB-INF tomcat5.5/upstream/5.5.20/container/webapps/docs/appdev tomcat5.5/upstream/5.5.20/container/webapps/docs/appdev/sample tomcat5.5/upstream/5.5.20/container/webapps/docs/appdev/sample/docs tomcat5.5/upstream/5.5.20/container/webapps/docs/appdev/sample/src tomcat5.5/upstream/5.5.20/container/webapps/docs/appdev/sample/src/mypackage tomcat5.5/upstream/5.5.20/container/webapps/docs/appdev/sample/web tomcat5.5/upstream/5.5.20/container/webapps/docs/appdev/sample/web/WEB-INF tomcat5.5/upstream/5.5.20/container/webapps/docs/appdev/sample/web/images tomcat5.5/upstream/5.5.20/container/webapps/docs/architecture tomcat5.5/upstream/5.5.20/container/webapps/docs/architecture/requestProcess tomcat5.5/upstream/5.5.20/container/webapps/docs/architecture/startup tomcat5.5/upstream/5.5.20/container/webapps/docs/catalina tomcat5.5/upstream/5.5.20/container/webapps/docs/catalina/docs tomcat5.5/upstream/5.5.20/container/webapps/docs/catalina/docs/api tomcat5.5/upstream/5.5.20/container/webapps/docs/config tomcat5.5/upstream/5.5.20/container/webapps/docs/funcspecs tomcat5.5/upstream/5.5.20/container/webapps/docs/images tomcat5.5/upstream/5.5.20/container/webapps/docs/jasper tomcat5.5/upstream/5.5.20/container/webapps/docs/jasper/docs tomcat5.5/upstream/5.5.20/container/webapps/docs/jasper/docs/api tomcat5.5/upstream/5.5.20/container/webapps/host-manager tomcat5.5/upstream/5.5.20/container/webapps/host-manager/WEB-INF tomcat5.5/upstream/5.5.20/container/webapps/host-manager/WEB-INF/classes tomcat5.5/upstream/5.5.20/container/webapps/host-manager/WEB-INF/classes/org tomcat5.5/upstream/5.5.20/container/webapps/host-manager/WEB-INF/classes/org/apache tomcat5.5/upstream/5.5.20/container/webapps/host-manager/WEB-INF/classes/org/apache/catalina tomcat5.5/upstream/5.5.20/container/webapps/host-manager/WEB-INF/classes/org/apache/catalina/hostmanager tomcat5.5/upstream/5.5.20/container/webapps/jmxremote tomcat5.5/upstream/5.5.20/container/webapps/jmxremote/WEB-INF tomcat5.5/upstream/5.5.20/container/webapps/jmxremote/WEB-INF/src tomcat5.5/upstream/5.5.20/container/webapps/jmxremote/WEB-INF/src/org tomcat5.5/upstream/5.5.20/container/webapps/jmxremote/WEB-INF/src/org/apache tomcat5.5/upstream/5.5.20/container/webapps/jmxremote/WEB-INF/src/org/apache/tomcat tomcat5.5/upstream/5.5.20/container/webapps/jmxremote/WEB-INF/src/org/apache/tomcat/servlets tomcat5.5/upstream/5.5.20/container/webapps/jmxremote/WEB-INF/src/org/apache/tomcat/servlets/jmxremote tomcat5.5/upstream/5.5.20/container/webapps/manager tomcat5.5/upstream/5.5.20/container/webapps/manager/WEB-INF tomcat5.5/upstream/5.5.20/container/webapps/manager/WEB-INF/classes tomcat5.5/upstream/5.5.20/container/webapps/manager/WEB-INF/classes/org tomcat5.5/upstream/5.5.20/container/webapps/manager/WEB-INF/classes/org/apache tomcat5.5/upstream/5.5.20/container/webapps/manager/WEB-INF/classes/org/apache/catalina tomcat5.5/upstream/5.5.20/container/webapps/manager/WEB-INF/classes/org/apache/catalina/manager tomcat5.5/upstream/5.5.20/container/webapps/webdav tomcat5.5/upstream/5.5.20/container/webapps/webdav/WEB-INF tomcat5.5/upstream/5.5.20/jasper tomcat5.5/upstream/5.5.20/jasper/doc tomcat5.5/upstream/5.5.20/jasper/src tomcat5.5/upstream/5.5.20/jasper/src/bin tomcat5.5/upstream/5.5.20/jasper/src/share tomcat5.5/upstream/5.5.20/jasper/src/share/org tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/tagplugin tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/resources tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/runtime tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/security tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/servlet tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/tagplugins tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/tagplugins/jstl tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/tagplugins/jstl/core tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/util tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/xmlparser tomcat5.5/upstream/5.5.20/servletapi tomcat5.5/upstream/5.5.20/servletapi/jsr152 tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/cal tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/checkbox tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/colors tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/compressionFilters tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/dates tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/error tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/examples tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/filters tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/jsp2 tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/jsp2/examples tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/jsp2/examples/el tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/jsp2/examples/simpletag tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/listeners tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/num tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/sessions tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/util tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/validators tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/jsp tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/jsp/applet tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/jsp2 tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/lib tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/tags tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/cal tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/checkbox tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/colors tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/dates tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/error tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/forward tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/images tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/include tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2 tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/el tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/jspattribute tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/jspx tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/misc tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/simpletag tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/tagfiles tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsptoserv tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/num tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/plugin tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/plugin/applet tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/security tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/security/protected tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/sessions tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/simpletag tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/snp tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/tagplugin tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/xml tomcat5.5/upstream/5.5.20/servletapi/jsr152/src tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/ant tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/ant/task tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/etc tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/dtd tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/el tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/tagext tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/tagext/doc-files tomcat5.5/upstream/5.5.20/servletapi/jsr154 tomcat5.5/upstream/5.5.20/servletapi/jsr154/examples tomcat5.5/upstream/5.5.20/servletapi/jsr154/examples/WEB-INF tomcat5.5/upstream/5.5.20/servletapi/jsr154/examples/WEB-INF/classes tomcat5.5/upstream/5.5.20/servletapi/jsr154/examples/WEB-INF/classes/compressionFilters tomcat5.5/upstream/5.5.20/servletapi/jsr154/examples/WEB-INF/classes/filters tomcat5.5/upstream/5.5.20/servletapi/jsr154/examples/WEB-INF/classes/listeners tomcat5.5/upstream/5.5.20/servletapi/jsr154/examples/WEB-INF/classes/util tomcat5.5/upstream/5.5.20/servletapi/jsr154/examples/images tomcat5.5/upstream/5.5.20/servletapi/jsr154/src tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/etc tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/dtd tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/http

Marcus Better marcusb-guest at alioth.debian.org
Tue Nov 14 15:48:53 CET 2006


Author: marcusb-guest
Date: 2006-11-14 15:47:19 +0100 (Tue, 14 Nov 2006)
New Revision: 2739

Added:
   branches/tomcat5.5/
   branches/tomcat5.5/upstream/
   branches/tomcat5.5/upstream/5.5.20/
   branches/tomcat5.5/upstream/5.5.20/build.xml
   branches/tomcat5.5/upstream/5.5.20/build/
   branches/tomcat5.5/upstream/5.5.20/build/.classpath
   branches/tomcat5.5/upstream/5.5.20/build/.project
   branches/tomcat5.5/upstream/5.5.20/build/BENCHMARKS.txt
   branches/tomcat5.5/upstream/5.5.20/build/BUILDING.txt
   branches/tomcat5.5/upstream/5.5.20/build/KEYS
   branches/tomcat5.5/upstream/5.5.20/build/LICENSE
   branches/tomcat5.5/upstream/5.5.20/build/NOTICE
   branches/tomcat5.5/upstream/5.5.20/build/RELEASE-NOTES
   branches/tomcat5.5/upstream/5.5.20/build/RELEASE-PLAN-5.0.txt
   branches/tomcat5.5/upstream/5.5.20/build/RELEASE-PLAN-5.5.txt
   branches/tomcat5.5/upstream/5.5.20/build/RUNNING.txt
   branches/tomcat5.5/upstream/5.5.20/build/build.properties.default
   branches/tomcat5.5/upstream/5.5.20/build/build.xml
   branches/tomcat5.5/upstream/5.5.20/build/resources/
   branches/tomcat5.5/upstream/5.5.20/build/resources/INSTALLLICENSE
   branches/tomcat5.5/upstream/5.5.20/build/resources/License.rtf
   branches/tomcat5.5/upstream/5.5.20/build/resources/build.xml
   branches/tomcat5.5/upstream/5.5.20/build/resources/catalina-main.manifest
   branches/tomcat5.5/upstream/5.5.20/build/resources/config.ini
   branches/tomcat5.5/upstream/5.5.20/build/resources/confinstall/
   branches/tomcat5.5/upstream/5.5.20/build/resources/confinstall/server_1.xml
   branches/tomcat5.5/upstream/5.5.20/build/resources/confinstall/server_2.xml
   branches/tomcat5.5/upstream/5.5.20/build/resources/confinstall/tomcat-users_1.xml
   branches/tomcat5.5/upstream/5.5.20/build/resources/confinstall/tomcat-users_2.xml
   branches/tomcat5.5/upstream/5.5.20/build/resources/deployer/
   branches/tomcat5.5/upstream/5.5.20/build/resources/deployer/build.xml
   branches/tomcat5.5/upstream/5.5.20/build/resources/header.bmp
   branches/tomcat5.5/upstream/5.5.20/build/resources/jvm.ini
   branches/tomcat5.5/upstream/5.5.20/build/resources/log4j.properties
   branches/tomcat5.5/upstream/5.5.20/build/resources/logging.properties
   branches/tomcat5.5/upstream/5.5.20/build/resources/main.ico
   branches/tomcat5.5/upstream/5.5.20/build/resources/mbeans/
   branches/tomcat5.5/upstream/5.5.20/build/resources/mbeans/tomcat5-ant.xml
   branches/tomcat5.5/upstream/5.5.20/build/resources/side_left.bmp
   branches/tomcat5.5/upstream/5.5.20/build/resources/tickno.bmp
   branches/tomcat5.5/upstream/5.5.20/build/resources/tickyes.bmp
   branches/tomcat5.5/upstream/5.5.20/build/resources/tomcat.ico
   branches/tomcat5.5/upstream/5.5.20/build/resources/tomcat.spec
   branches/tomcat5.5/upstream/5.5.20/build/resources/uninst.ico
   branches/tomcat5.5/upstream/5.5.20/build/resources/welcome.bin.html
   branches/tomcat5.5/upstream/5.5.20/build/resources/welcome.main.html
   branches/tomcat5.5/upstream/5.5.20/build/sign.bat
   branches/tomcat5.5/upstream/5.5.20/build/tag.bat
   branches/tomcat5.5/upstream/5.5.20/build/tomcat.nsi
   branches/tomcat5.5/upstream/5.5.20/connectors/
   branches/tomcat5.5/upstream/5.5.20/connectors/.classpath
   branches/tomcat5.5/upstream/5.5.20/connectors/.project
   branches/tomcat5.5/upstream/5.5.20/connectors/KEYS
   branches/tomcat5.5/upstream/5.5.20/connectors/LICENSE
   branches/tomcat5.5/upstream/5.5.20/connectors/NOTICE
   branches/tomcat5.5/upstream/5.5.20/connectors/README.txt
   branches/tomcat5.5/upstream/5.5.20/connectors/RELEASE-NOTES.txt
   branches/tomcat5.5/upstream/5.5.20/connectors/ajp/
   branches/tomcat5.5/upstream/5.5.20/connectors/ajp/CHANGES
   branches/tomcat5.5/upstream/5.5.20/connectors/ajp/ajplib/
   branches/tomcat5.5/upstream/5.5.20/connectors/ajp/ajplib/include/
   branches/tomcat5.5/upstream/5.5.20/connectors/ajp/ajplib/include/ajp.h
   branches/tomcat5.5/upstream/5.5.20/connectors/ajp/ajplib/include/ajp_header.h
   branches/tomcat5.5/upstream/5.5.20/connectors/ajp/ajplib/include/ajp_logon.h
   branches/tomcat5.5/upstream/5.5.20/connectors/ajp/ajplib/src/
   branches/tomcat5.5/upstream/5.5.20/connectors/ajp/ajplib/src/ajp_header.c
   branches/tomcat5.5/upstream/5.5.20/connectors/ajp/ajplib/src/ajp_link.c
   branches/tomcat5.5/upstream/5.5.20/connectors/ajp/ajplib/src/ajp_logon.c
   branches/tomcat5.5/upstream/5.5.20/connectors/ajp/ajplib/src/ajp_msg.c
   branches/tomcat5.5/upstream/5.5.20/connectors/ajp/ajplib/test/
   branches/tomcat5.5/upstream/5.5.20/connectors/ajp/ajplib/test/Makefile
   branches/tomcat5.5/upstream/5.5.20/connectors/ajp/ajplib/test/Makefile.netware
   branches/tomcat5.5/upstream/5.5.20/connectors/ajp/ajplib/test/httpd_wrap.c
   branches/tomcat5.5/upstream/5.5.20/connectors/ajp/ajplib/test/httpd_wrap.h
   branches/tomcat5.5/upstream/5.5.20/connectors/ajp/ajplib/test/test.sln
   branches/tomcat5.5/upstream/5.5.20/connectors/ajp/ajplib/test/testajp.c
   branches/tomcat5.5/upstream/5.5.20/connectors/ajp/ajplib/test/testajp.vcproj
   branches/tomcat5.5/upstream/5.5.20/connectors/ajp/proxy/
   branches/tomcat5.5/upstream/5.5.20/connectors/ajp/proxy/.indent.pro
   branches/tomcat5.5/upstream/5.5.20/connectors/ajp/proxy/CHANGES
   branches/tomcat5.5/upstream/5.5.20/connectors/ajp/proxy/JAKARTA
   branches/tomcat5.5/upstream/5.5.20/connectors/ajp/proxy/Makefile.in
   branches/tomcat5.5/upstream/5.5.20/connectors/ajp/proxy/NWGNUmakefile
   branches/tomcat5.5/upstream/5.5.20/connectors/ajp/proxy/NWGNUproxy
   branches/tomcat5.5/upstream/5.5.20/connectors/ajp/proxy/NWGNUproxycon
   branches/tomcat5.5/upstream/5.5.20/connectors/ajp/proxy/NWGNUproxyftp
   branches/tomcat5.5/upstream/5.5.20/connectors/ajp/proxy/NWGNUproxyhtp
   branches/tomcat5.5/upstream/5.5.20/connectors/ajp/proxy/config.m4
   branches/tomcat5.5/upstream/5.5.20/connectors/ajp/proxy/config.m4.patch
   branches/tomcat5.5/upstream/5.5.20/connectors/ajp/proxy/libproxy.exp
   branches/tomcat5.5/upstream/5.5.20/connectors/ajp/proxy/mod_proxy.c
   branches/tomcat5.5/upstream/5.5.20/connectors/ajp/proxy/mod_proxy.dsp
   branches/tomcat5.5/upstream/5.5.20/connectors/ajp/proxy/mod_proxy.h
   branches/tomcat5.5/upstream/5.5.20/connectors/ajp/proxy/mod_proxy_ajp.dsp
   branches/tomcat5.5/upstream/5.5.20/connectors/ajp/proxy/mod_proxy_balancer.dsp
   branches/tomcat5.5/upstream/5.5.20/connectors/ajp/proxy/mod_proxy_connect.dsp
   branches/tomcat5.5/upstream/5.5.20/connectors/ajp/proxy/mod_proxy_ftp.dsp
   branches/tomcat5.5/upstream/5.5.20/connectors/ajp/proxy/mod_proxy_http.dsp
   branches/tomcat5.5/upstream/5.5.20/connectors/ajp/proxy/proxy_ajp.c
   branches/tomcat5.5/upstream/5.5.20/connectors/ajp/proxy/proxy_balancer.c
   branches/tomcat5.5/upstream/5.5.20/connectors/ajp/proxy/proxy_connect.c
   branches/tomcat5.5/upstream/5.5.20/connectors/ajp/proxy/proxy_ftp.c
   branches/tomcat5.5/upstream/5.5.20/connectors/ajp/proxy/proxy_http.c
   branches/tomcat5.5/upstream/5.5.20/connectors/ajp/proxy/proxy_util.c
   branches/tomcat5.5/upstream/5.5.20/connectors/build.properties.default
   branches/tomcat5.5/upstream/5.5.20/connectors/build.xml
   branches/tomcat5.5/upstream/5.5.20/connectors/coyote/
   branches/tomcat5.5/upstream/5.5.20/connectors/coyote/build.properties.sample
   branches/tomcat5.5/upstream/5.5.20/connectors/coyote/build.xml
   branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/
   branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/conf/
   branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/conf/MANIFEST.MF
   branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/java/
   branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/java/org/
   branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/java/org/apache/
   branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/java/org/apache/coyote/
   branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/java/org/apache/coyote/ActionCode.java
   branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/java/org/apache/coyote/ActionHook.java
   branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/java/org/apache/coyote/Adapter.java
   branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/java/org/apache/coyote/Constants.java
   branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/java/org/apache/coyote/InputBuffer.java
   branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/java/org/apache/coyote/OutputBuffer.java
   branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/java/org/apache/coyote/Processor.java
   branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/java/org/apache/coyote/ProtocolHandler.java
   branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/java/org/apache/coyote/Request.java
   branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/java/org/apache/coyote/RequestGroupInfo.java
   branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/java/org/apache/coyote/RequestInfo.java
   branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/java/org/apache/coyote/Response.java
   branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/java/org/apache/coyote/memory/
   branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/java/org/apache/coyote/memory/MemoryProtocolHandler.java
   branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/java/org/apache/coyote/tomcat3/
   branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/java/org/apache/coyote/tomcat3/CoyoteInterceptor2.java
   branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/java/org/apache/coyote/tomcat3/Tomcat3Adapter.java
   branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/java/org/apache/coyote/tomcat3/Tomcat3Request.java
   branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/java/org/apache/coyote/tomcat3/Tomcat3Response.java
   branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/java/org/apache/coyote/tomcat4/
   branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/java/org/apache/coyote/tomcat4/Constants.java
   branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/java/org/apache/coyote/tomcat4/CoyoteAdapter.java
   branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/java/org/apache/coyote/tomcat4/CoyoteConnector.java
   branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/java/org/apache/coyote/tomcat4/CoyoteInputStream.java
   branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/java/org/apache/coyote/tomcat4/CoyoteOutputStream.java
   branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/java/org/apache/coyote/tomcat4/CoyotePrincipal.java
   branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/java/org/apache/coyote/tomcat4/CoyoteRequest.java
   branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/java/org/apache/coyote/tomcat4/CoyoteRequestFacade.java
   branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/java/org/apache/coyote/tomcat4/CoyoteResponse.java
   branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/java/org/apache/coyote/tomcat4/CoyoteResponseFacade.java
   branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/java/org/apache/coyote/tomcat4/CoyoteServerSocketFactory.java
   branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/java/org/apache/coyote/tomcat4/CoyoteWriter.java
   branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/java/org/apache/coyote/tomcat4/LocalStrings.properties
   branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/java/org/apache/coyote/tomcat4/LocalStrings_es.properties
   branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/java/org/apache/coyote/tomcat4/LocalStrings_fr.properties
   branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/java/org/apache/coyote/tomcat4/LocalStrings_ja.properties
   branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/java/org/apache/coyote/tomcat4/OutputBuffer.java
   branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/test/
   branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/test/org/
   branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/test/org/apache/
   branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/test/org/apache/coyote/
   branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/test/org/apache/coyote/SimpleAdapter.java
   branches/tomcat5.5/upstream/5.5.20/connectors/doc/
   branches/tomcat5.5/upstream/5.5.20/connectors/doc/install_tomcat33.html
   branches/tomcat5.5/upstream/5.5.20/connectors/doc/install_tomcat40.html
   branches/tomcat5.5/upstream/5.5.20/connectors/doc/install_tomcat41.html
   branches/tomcat5.5/upstream/5.5.20/connectors/http11/
   branches/tomcat5.5/upstream/5.5.20/connectors/http11/build.properties.sample
   branches/tomcat5.5/upstream/5.5.20/connectors/http11/build.xml
   branches/tomcat5.5/upstream/5.5.20/connectors/http11/src/
   branches/tomcat5.5/upstream/5.5.20/connectors/http11/src/conf/
   branches/tomcat5.5/upstream/5.5.20/connectors/http11/src/conf/MANIFEST.MF
   branches/tomcat5.5/upstream/5.5.20/connectors/http11/src/java/
   branches/tomcat5.5/upstream/5.5.20/connectors/http11/src/java/org/
   branches/tomcat5.5/upstream/5.5.20/connectors/http11/src/java/org/apache/
   branches/tomcat5.5/upstream/5.5.20/connectors/http11/src/java/org/apache/coyote/
   branches/tomcat5.5/upstream/5.5.20/connectors/http11/src/java/org/apache/coyote/http11/
   branches/tomcat5.5/upstream/5.5.20/connectors/http11/src/java/org/apache/coyote/http11/Constants.java
   branches/tomcat5.5/upstream/5.5.20/connectors/http11/src/java/org/apache/coyote/http11/Http11AprProcessor.java
   branches/tomcat5.5/upstream/5.5.20/connectors/http11/src/java/org/apache/coyote/http11/Http11AprProtocol.java
   branches/tomcat5.5/upstream/5.5.20/connectors/http11/src/java/org/apache/coyote/http11/Http11BaseProtocol.java
   branches/tomcat5.5/upstream/5.5.20/connectors/http11/src/java/org/apache/coyote/http11/Http11Processor.java
   branches/tomcat5.5/upstream/5.5.20/connectors/http11/src/java/org/apache/coyote/http11/Http11Protocol.java
   branches/tomcat5.5/upstream/5.5.20/connectors/http11/src/java/org/apache/coyote/http11/InputFilter.java
   branches/tomcat5.5/upstream/5.5.20/connectors/http11/src/java/org/apache/coyote/http11/InternalAprInputBuffer.java
   branches/tomcat5.5/upstream/5.5.20/connectors/http11/src/java/org/apache/coyote/http11/InternalAprOutputBuffer.java
   branches/tomcat5.5/upstream/5.5.20/connectors/http11/src/java/org/apache/coyote/http11/InternalInputBuffer.java
   branches/tomcat5.5/upstream/5.5.20/connectors/http11/src/java/org/apache/coyote/http11/InternalOutputBuffer.java
   branches/tomcat5.5/upstream/5.5.20/connectors/http11/src/java/org/apache/coyote/http11/LocalStrings.properties
   branches/tomcat5.5/upstream/5.5.20/connectors/http11/src/java/org/apache/coyote/http11/LocalStrings_es.properties
   branches/tomcat5.5/upstream/5.5.20/connectors/http11/src/java/org/apache/coyote/http11/LocalStrings_fr.properties
   branches/tomcat5.5/upstream/5.5.20/connectors/http11/src/java/org/apache/coyote/http11/LocalStrings_ja.properties
   branches/tomcat5.5/upstream/5.5.20/connectors/http11/src/java/org/apache/coyote/http11/OutputFilter.java
   branches/tomcat5.5/upstream/5.5.20/connectors/http11/src/java/org/apache/coyote/http11/filters/
   branches/tomcat5.5/upstream/5.5.20/connectors/http11/src/java/org/apache/coyote/http11/filters/BufferedInputFilter.java
   branches/tomcat5.5/upstream/5.5.20/connectors/http11/src/java/org/apache/coyote/http11/filters/ChunkedInputFilter.java
   branches/tomcat5.5/upstream/5.5.20/connectors/http11/src/java/org/apache/coyote/http11/filters/ChunkedOutputFilter.java
   branches/tomcat5.5/upstream/5.5.20/connectors/http11/src/java/org/apache/coyote/http11/filters/GzipOutputFilter.java
   branches/tomcat5.5/upstream/5.5.20/connectors/http11/src/java/org/apache/coyote/http11/filters/IdentityInputFilter.java
   branches/tomcat5.5/upstream/5.5.20/connectors/http11/src/java/org/apache/coyote/http11/filters/IdentityOutputFilter.java
   branches/tomcat5.5/upstream/5.5.20/connectors/http11/src/java/org/apache/coyote/http11/filters/SavedRequestInputFilter.java
   branches/tomcat5.5/upstream/5.5.20/connectors/http11/src/java/org/apache/coyote/http11/filters/VoidInputFilter.java
   branches/tomcat5.5/upstream/5.5.20/connectors/http11/src/java/org/apache/coyote/http11/filters/VoidOutputFilter.java
   branches/tomcat5.5/upstream/5.5.20/connectors/http11/src/test/
   branches/tomcat5.5/upstream/5.5.20/connectors/http11/src/test/java/
   branches/tomcat5.5/upstream/5.5.20/connectors/http11/src/test/java/org/
   branches/tomcat5.5/upstream/5.5.20/connectors/http11/src/test/java/org/apache/
   branches/tomcat5.5/upstream/5.5.20/connectors/http11/src/test/java/org/apache/coyote/
   branches/tomcat5.5/upstream/5.5.20/connectors/http11/src/test/java/org/apache/coyote/http11/
   branches/tomcat5.5/upstream/5.5.20/connectors/http11/src/test/java/org/apache/coyote/http11/FileTester.java
   branches/tomcat5.5/upstream/5.5.20/connectors/http11/src/test/java/org/apache/coyote/http11/RandomAdapter.java
   branches/tomcat5.5/upstream/5.5.20/connectors/http11/src/test/java/org/apache/coyote/http11/TestAdapter.java
   branches/tomcat5.5/upstream/5.5.20/connectors/http11/src/test/test.bat
   branches/tomcat5.5/upstream/5.5.20/connectors/http11/src/test/tests/
   branches/tomcat5.5/upstream/5.5.20/connectors/http11/src/test/tests/test1.txt
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/BUILD.txt
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/HOWTO-RELEASE
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/README.txt
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/build.properties.autoconf
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/build.properties.sample
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/build.xml
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/conf/
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/conf/jk2.manifest
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/conf/jk2.properties
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/conf/jkconf.ant.xml
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/conf/jkconfig.manifest
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/conf/shm.manifest
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/conf/tomcat-jk2.manifest
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/conf/uriworkermap.properties
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/conf/workers.properties
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/conf/workers.properties.minimal
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/conf/workers2.properties
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/conf/workers2.properties.minimal
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/ajp/
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/ajp/Ajp13.java
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/ajp/Ajp13Packet.java
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/ajp/AjpHandler.java
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/ajp/Logger.java
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/ajp/NegociationHandler.java
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/ajp/RequestHandler.java
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/ajp/tomcat33/
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/ajp/tomcat33/Ajp14Interceptor.java
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/ajp/tomcat4/
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/ajp/tomcat4/Ajp13Connector.java
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/ajp/tomcat4/Ajp13InputStream.java
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/ajp/tomcat4/Ajp13Logger.java
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/ajp/tomcat4/Ajp13OutputStream.java
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/ajp/tomcat4/Ajp13Processor.java
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/ajp/tomcat4/Ajp13Request.java
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/ajp/tomcat4/Ajp13Response.java
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/ajp/tomcat4/Constants.java
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/ajp/tomcat4/JkServlet.java
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/ajp/tomcat4/LocalStrings.properties
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/ajp/tomcat4/LocalStrings_es.properties
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/ajp/tomcat4/LocalStrings_fr.properties
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/ajp/tomcat4/LocalStrings_ja.properties
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/ajp/tomcat4/config/
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/ajp/tomcat4/config/ApacheConfig.java
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/ajp/tomcat4/config/BaseJkConfig.java
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/ajp/tomcat4/config/IISConfig.java
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/ajp/tomcat4/config/NSConfig.java
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/coyote/
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/coyote/ajp/
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/coyote/ajp/AjpAprProcessor.java
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/coyote/ajp/AjpAprProtocol.java
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/coyote/ajp/AjpMessage.java
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/coyote/ajp/Constants.java
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/coyote/ajp/LocalStrings.properties
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/apr/
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/apr/AprImpl.java
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/apr/TomcatStarter.java
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/common/
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/common/AjpConstants.java
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/common/ChannelJni.java
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/common/ChannelNioSocket.java
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/common/ChannelShm.java
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/common/ChannelSocket.java
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/common/ChannelUn.java
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/common/HandlerDispatch.java
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/common/HandlerRequest.java
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/common/JkInputStream.java
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/common/JkMX.java
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/common/JniHandler.java
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/common/ModJkMX.java
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/common/MsgAjp.java
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/common/Shm.java
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/common/Shm14.java
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/common/WorkerDummy.java
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/config/
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/config/ApacheConfig.java
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/config/BaseJkConfig.java
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/config/GeneratorApache2.java
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/config/GeneratorJk1.java
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/config/GeneratorJk2.java
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/config/IISConfig.java
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/config/NSConfig.java
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/config/WebXml2Jk.java
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/core/
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/core/JkChannel.java
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/core/JkHandler.java
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/core/Msg.java
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/core/MsgContext.java
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/core/WorkerEnv.java
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/core/package.html
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/mbeans-descriptors.xml
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/server/
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/server/JkCoyoteHandler.java
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/server/JkMain.java
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkant/
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkant/ant.tasks
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkant/buildJakarta.xml
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkant/java/
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkant/java/org/
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkant/java/org/apache/
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkant/java/org/apache/jk/
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkant/java/org/apache/jk/ant/
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkant/java/org/apache/jk/ant/ApacheConfig.java
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkant/java/org/apache/jk/ant/Def.java
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkant/java/org/apache/jk/ant/JkData.java
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkant/java/org/apache/jk/ant/JniConfig.java
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkant/java/org/apache/jk/ant/SoTask.java
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkant/java/org/apache/jk/ant/Source.java
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkant/java/org/apache/jk/ant/compilers/
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkant/java/org/apache/jk/ant/compilers/CcCompiler.java
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkant/java/org/apache/jk/ant/compilers/CompilerAdapter.java
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkant/java/org/apache/jk/ant/compilers/GcjCompiler.java
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkant/java/org/apache/jk/ant/compilers/GcjLinker.java
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkant/java/org/apache/jk/ant/compilers/LibtoolCompiler.java
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkant/java/org/apache/jk/ant/compilers/LibtoolLinker.java
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkant/java/org/apache/jk/ant/compilers/LinkerAdapter.java
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkant/java/org/apache/jk/ant/compilers/MsvcCompiler.java
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkant/java/org/apache/jk/ant/compilers/MsvcLinker.java
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkant/java/org/apache/jk/ant/compilers/MwccCompiler.java
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkant/java/org/apache/jk/ant/compilers/MwldLinker.java
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/build.xml
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/build/
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/build/classes/
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/build/classes/org/
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/build/classes/org/apache/
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/build/classes/org/apache/jk/
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/build/classes/org/apache/jk/status/
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/build/classes/org/apache/jk/status/JkBalancer.class
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/build/classes/org/apache/jk/status/JkBalancerMapping.class
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/build/classes/org/apache/jk/status/JkBalancerMember.class
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/build/classes/org/apache/jk/status/JkServer.class
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/build/classes/org/apache/jk/status/JkStatus.class
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/build/classes/org/apache/jk/status/JkStatusAccessor.class
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/build/classes/org/apache/jk/status/JkStatusParser.class
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/build/classes/org/apache/jk/status/JkStatusResetTask.class
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/build/classes/org/apache/jk/status/JkStatusTask.class
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/build/classes/org/apache/jk/status/JkStatusUpdateTask.class
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/build/classes/org/apache/jk/status/LocalStrings.properties
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/build/classes/org/apache/jk/status/antlib.xml
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/build/classes/org/apache/jk/status/jkstatus.tasks
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/build/classes/org/apache/jk/status/mbeans-descriptors.xml
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/conf/
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/conf/jkstatus-tasks.xml
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/dist/
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/dist/tomcat-jkstatus-ant.jar
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/example/
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/example/jkstatus.properties.default
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/example/jkstatus.xml
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/src/
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/src/share/
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/src/share/org/
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/src/share/org/apache/
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/src/share/org/apache/jk/
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/src/share/org/apache/jk/status/
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/src/share/org/apache/jk/status/JkBalancer.java
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/src/share/org/apache/jk/status/JkBalancerMapping.java
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/src/share/org/apache/jk/status/JkBalancerMember.java
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/src/share/org/apache/jk/status/JkServer.java
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/src/share/org/apache/jk/status/JkStatus.java
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/src/share/org/apache/jk/status/JkStatusAccessor.java
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/src/share/org/apache/jk/status/JkStatusParser.java
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/src/share/org/apache/jk/status/JkStatusResetTask.java
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/src/share/org/apache/jk/status/JkStatusTask.java
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/src/share/org/apache/jk/status/JkStatusUpdateTask.java
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/src/share/org/apache/jk/status/LocalStrings.properties
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/src/share/org/apache/jk/status/antlib.xml
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/src/share/org/apache/jk/status/jkstatus.tasks
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/src/share/org/apache/jk/status/mbeans-descriptors.xml
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/src/share/org/apache/jk/status/package.html
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/test/
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/test/build.xml
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/test/conf/
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/test/conf/jkstatus.xml
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/test/conf/log4j.xml
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/test/src/
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/test/src/share/
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/test/src/share/org/
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/test/src/share/org/apache/
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/test/src/share/org/apache/jk/
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/test/src/share/org/apache/jk/status/
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/test/src/share/org/apache/jk/status/JkStatusParserTest.java
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/BUILDING
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/CHANGES.txt
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/Makefile.am
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/README
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/STATUS.txt
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/TODO
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/apache-1.3/
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/apache-1.3/Makefile.apxs.in
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/apache-1.3/Makefile.in
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/apache-1.3/Makefile.libdir
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/apache-1.3/Makefile.netware
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/apache-1.3/Makefile.tmpl
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/apache-1.3/Makefile.vc
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/apache-1.3/NWGNUmakefile
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/apache-1.3/NWGNUmakefile.mak
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/apache-1.3/libjk.module
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/apache-1.3/mod_jk.c
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/apache-1.3/mod_jk.dsp
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/apache-1.3/mod_jk.exp
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/apache-2.0/
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/apache-2.0/Makefile.apxs.in
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/apache-2.0/Makefile.in
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/apache-2.0/Makefile.vc
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/apache-2.0/NWGNUmakefile
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/apache-2.0/bldjk.qclsrc
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/apache-2.0/config.m4
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/apache-2.0/mod_jk.c
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/apache-2.0/mod_jk.dsp
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/build.xml
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/buildconf.sh
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/.indent.pro
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/Makefile.in
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_ajp12_worker.c
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_ajp12_worker.h
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_ajp13.c
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_ajp13.h
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_ajp13_worker.c
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_ajp13_worker.h
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_ajp14.c
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_ajp14.h
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_ajp14_worker.c
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_ajp14_worker.h
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_ajp_common.c
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_ajp_common.h
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_connect.c
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_connect.h
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_context.c
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_context.h
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_global.h
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_jni_worker.c
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_jni_worker.h
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_lb_worker.c
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_lb_worker.h
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_logger.h
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_map.c
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_map.h
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_md5.c
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_md5.h
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_msg_buff.c
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_msg_buff.h
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_mt.h
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_nwmain.c
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_pool.c
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_pool.h
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_service.h
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_shm.c
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_shm.h
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_sockbuf.c
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_sockbuf.h
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_status.c
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_status.h
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_types.h.in
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_uri_worker_map.c
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_uri_worker_map.h
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_util.c
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_util.h
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_version.h
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_worker.c
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_worker.h
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_worker_list.h
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/list.mk.in
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/portable.h
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/portable.h.sample
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/configure.in
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/docs/
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/docs/api/
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/docs/api/README.txt
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/Makefile.vc
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/README
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/installer/
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/installer/LICENSE.TXT
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/installer/License.rtf
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/installer/bin/
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/installer/bin/README
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/installer/conf/
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/installer/conf/uriworkermap.properties
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/installer/conf/workers.properties.minimal
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/installer/iisfilter.vbs
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/installer/isapi-redirector-win32-msi.ism
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/installer/log/
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/installer/log/README
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/installer/tomcat.ico
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/isapi.def
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/isapi.dsp
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/isapi.dsw
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/isapi_install.vbs
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/isapi_redirect.rc
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/isapi_redirect.reg
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/jk_isapi_plugin.c
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/AUTHORS
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/COPYING
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/ChangeLog
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/INSTALL
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/LICENCE
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/Makefile.in
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/NEWS
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/NON-UNIX-USE
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/NWGNUmakefile
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/README
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/RunTest.in
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/config.hw
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/config.in
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/configure.in
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/dftables.c
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/dftables.dsp
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/dll.mk
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/doc/
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/doc/README_httpd
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/get.c
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/install-sh
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/internal.h
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/libpcre.def
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/libpcre.pc.in
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/libpcreposix.def
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/maketables.c
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/makevp.bat
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/mkinstalldirs
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/pcre-config.in
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/pcre.c
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/pcre.def
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/pcre.dsp
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/pcre.hw
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/pcre.in
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/pcredemo.c
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/pcregrep.c
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/pcreposix.c
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/pcreposix.dsp
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/pcreposix.h
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/pcretest.c
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/perltest
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/perltest8
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/pgrep.c
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/printint.c
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/study.c
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/testdata/
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/testdata/testinput1
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/testdata/testinput2
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/testdata/testinput3
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/testdata/testinput4
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/testdata/testinput5
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/testdata/testinput6
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/testdata/testoutput1
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/testdata/testoutput2
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/testdata/testoutput3
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/testdata/testoutput4
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/testdata/testoutput5
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/testdata/testoutput6
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/ucp.c
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/ucp.h
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/ucpinternal.h
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/ucptable.c
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/ucptypetable.c
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/jni/
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/jni/Makefile.in
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/jni/Makefile.linux
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/jni/Makefile.netware
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/jni/Makefile.solaris
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/jni/jk_jnicb.c
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/jni/jk_jnicb.exp
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/jni/jk_jnicb.h
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/jni/jni_connect.dsp
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/netscape/
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/netscape/Makefile.netware
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/netscape/Makefile.solaris
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/netscape/README
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/netscape/jk_nsapi_plugin.c
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/netscape/nsapi.dsp
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/nt_service/
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/nt_service/jk_nt_service.c
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/nt_service/nt_service.dsp
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/scripts/
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/scripts/build/
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/scripts/build/config_vars.mk
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/scripts/build/rules.mk
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/scripts/build/unix/
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/scripts/build/unix/dummy
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/support/
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/support/apache.m4
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/support/get_ver.awk
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/support/jk_apache_static.m4
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/support/jk_apr.m4
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/support/jk_apxs.m4
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/support/jk_dominohome.m4
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/support/jk_exec.m4
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/support/jk_java.m4
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/support/jk_pcre.m4
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/support/jk_tchome.m4
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/support/jk_ws.m4
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/support/os_apache.m4
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/test/
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/test/org/
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/test/org/apache/
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/test/org/apache/ajp/
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/test/org/apache/ajp/test/
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/test/org/apache/ajp/test/TestAjp13.java
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/test/org/apache/ajp/test/TestAll.java
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/tools/
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/tools/jkrelease.sh
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/tools/reports/
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/tools/reports/README.txt
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/tools/reports/tomcat_reports.pl
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/tools/reports/tomcat_trend.pl
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/build.xml
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/changelog.xml
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/common/
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/common/ajpv13a.xml
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/common/ajpv13ext.xml
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/common/project.xml
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/common/tools.xml
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/config/
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/config/apache.xml
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/config/iis.xml
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/config/project.xml
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/config/workers.xml
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/empty.xml
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/faq.xml
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/howto/
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/howto/apache.xml
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/howto/doccontrib.xml
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/howto/domino.xml
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/howto/iis.xml
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/howto/index.xml
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/howto/loadbalancers.xml
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/howto/nes.xml
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/howto/project.xml
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/howto/quick.xml
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/howto/workers.xml
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/images/
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/images/add.gif
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/images/code.gif
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/images/design.gif
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/images/docs.gif
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/images/fix.gif
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/images/jakarta-logo.gif
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/images/printer.gif
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/images/tomcat.gif
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/images/update.gif
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/images/void.gif
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/index.xml
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/jk2/
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/jk2/confighowto.xml
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/jk2/configtc.xml
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/jk2/configtccom.xml
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/jk2/configtcex.xml
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/jk2/configweb.xml
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/jk2/configwebcom.xml
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/jk2/configwebex.xml
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/jk2/davhowto.xml
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/jk2/installhowto.xml
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/jk2/vhosthowto.xml
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/news/
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/news/20041100.xml
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/news/20050101.xml
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/news/20060101.xml
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/news/project.xml
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/project.xml
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/proxy.xml
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/style.css
   branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/style.xsl
   branches/tomcat5.5/upstream/5.5.20/connectors/jni/
   branches/tomcat5.5/upstream/5.5.20/connectors/jni/NOTICE.txt
   branches/tomcat5.5/upstream/5.5.20/connectors/jni/README.txt
   branches/tomcat5.5/upstream/5.5.20/connectors/jni/build.properties.sample
   branches/tomcat5.5/upstream/5.5.20/connectors/jni/build.xml
   branches/tomcat5.5/upstream/5.5.20/connectors/jni/examples/
   branches/tomcat5.5/upstream/5.5.20/connectors/jni/examples/mkcerts
   branches/tomcat5.5/upstream/5.5.20/connectors/jni/examples/org/
   branches/tomcat5.5/upstream/5.5.20/connectors/jni/examples/org/apache/
   branches/tomcat5.5/upstream/5.5.20/connectors/jni/examples/org/apache/tomcat/
   branches/tomcat5.5/upstream/5.5.20/connectors/jni/examples/org/apache/tomcat/jni/
   branches/tomcat5.5/upstream/5.5.20/connectors/jni/examples/org/apache/tomcat/jni/Echo.java
   branches/tomcat5.5/upstream/5.5.20/connectors/jni/examples/org/apache/tomcat/jni/Echo.properties
   branches/tomcat5.5/upstream/5.5.20/connectors/jni/examples/org/apache/tomcat/jni/Local.properties
   branches/tomcat5.5/upstream/5.5.20/connectors/jni/examples/org/apache/tomcat/jni/LocalServer.java
   branches/tomcat5.5/upstream/5.5.20/connectors/jni/examples/org/apache/tomcat/jni/SSL.properties
   branches/tomcat5.5/upstream/5.5.20/connectors/jni/examples/org/apache/tomcat/jni/SSLServer.java
   branches/tomcat5.5/upstream/5.5.20/connectors/jni/java/
   branches/tomcat5.5/upstream/5.5.20/connectors/jni/java/org/
   branches/tomcat5.5/upstream/5.5.20/connectors/jni/java/org/apache/
   branches/tomcat5.5/upstream/5.5.20/connectors/jni/java/org/apache/tomcat/
   branches/tomcat5.5/upstream/5.5.20/connectors/jni/java/org/apache/tomcat/Apr.java
   branches/tomcat5.5/upstream/5.5.20/connectors/jni/java/org/apache/tomcat/apr.properties
   branches/tomcat5.5/upstream/5.5.20/connectors/jni/java/org/apache/tomcat/jni/
   branches/tomcat5.5/upstream/5.5.20/connectors/jni/java/org/apache/tomcat/jni/Address.java
   branches/tomcat5.5/upstream/5.5.20/connectors/jni/java/org/apache/tomcat/jni/BIOCallback.java
   branches/tomcat5.5/upstream/5.5.20/connectors/jni/java/org/apache/tomcat/jni/Directory.java
   branches/tomcat5.5/upstream/5.5.20/connectors/jni/java/org/apache/tomcat/jni/Error.java
   branches/tomcat5.5/upstream/5.5.20/connectors/jni/java/org/apache/tomcat/jni/File.java
   branches/tomcat5.5/upstream/5.5.20/connectors/jni/java/org/apache/tomcat/jni/FileInfo.java
   branches/tomcat5.5/upstream/5.5.20/connectors/jni/java/org/apache/tomcat/jni/Global.java
   branches/tomcat5.5/upstream/5.5.20/connectors/jni/java/org/apache/tomcat/jni/Library.java
   branches/tomcat5.5/upstream/5.5.20/connectors/jni/java/org/apache/tomcat/jni/Local.java
   branches/tomcat5.5/upstream/5.5.20/connectors/jni/java/org/apache/tomcat/jni/Lock.java
   branches/tomcat5.5/upstream/5.5.20/connectors/jni/java/org/apache/tomcat/jni/Mmap.java
   branches/tomcat5.5/upstream/5.5.20/connectors/jni/java/org/apache/tomcat/jni/Multicast.java
   branches/tomcat5.5/upstream/5.5.20/connectors/jni/java/org/apache/tomcat/jni/OS.java
   branches/tomcat5.5/upstream/5.5.20/connectors/jni/java/org/apache/tomcat/jni/PasswordCallback.java
   branches/tomcat5.5/upstream/5.5.20/connectors/jni/java/org/apache/tomcat/jni/Poll.java
   branches/tomcat5.5/upstream/5.5.20/connectors/jni/java/org/apache/tomcat/jni/Pool.java
   branches/tomcat5.5/upstream/5.5.20/connectors/jni/java/org/apache/tomcat/jni/PoolCallback.java
   branches/tomcat5.5/upstream/5.5.20/connectors/jni/java/org/apache/tomcat/jni/Proc.java
   branches/tomcat5.5/upstream/5.5.20/connectors/jni/java/org/apache/tomcat/jni/ProcErrorCallback.java
   branches/tomcat5.5/upstream/5.5.20/connectors/jni/java/org/apache/tomcat/jni/Procattr.java
   branches/tomcat5.5/upstream/5.5.20/connectors/jni/java/org/apache/tomcat/jni/Registry.java
   branches/tomcat5.5/upstream/5.5.20/connectors/jni/java/org/apache/tomcat/jni/SSL.java
   branches/tomcat5.5/upstream/5.5.20/connectors/jni/java/org/apache/tomcat/jni/SSLContext.java
   branches/tomcat5.5/upstream/5.5.20/connectors/jni/java/org/apache/tomcat/jni/SSLSocket.java
   branches/tomcat5.5/upstream/5.5.20/connectors/jni/java/org/apache/tomcat/jni/Shm.java
   branches/tomcat5.5/upstream/5.5.20/connectors/jni/java/org/apache/tomcat/jni/Sockaddr.java
   branches/tomcat5.5/upstream/5.5.20/connectors/jni/java/org/apache/tomcat/jni/Socket.java
   branches/tomcat5.5/upstream/5.5.20/connectors/jni/java/org/apache/tomcat/jni/Status.java
   branches/tomcat5.5/upstream/5.5.20/connectors/jni/java/org/apache/tomcat/jni/Stdlib.java
   branches/tomcat5.5/upstream/5.5.20/connectors/jni/java/org/apache/tomcat/jni/Thread.java
   branches/tomcat5.5/upstream/5.5.20/connectors/jni/java/org/apache/tomcat/jni/Time.java
   branches/tomcat5.5/upstream/5.5.20/connectors/jni/java/org/apache/tomcat/jni/User.java
   branches/tomcat5.5/upstream/5.5.20/connectors/jni/java/overview.html
   branches/tomcat5.5/upstream/5.5.20/connectors/jni/jnirelease.sh
   branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/
   branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/BUILDING
   branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/Makefile.in
   branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/build.conf
   branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/build/
   branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/build/buildcheck.sh
   branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/build/get-version.sh
   branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/build/lineends.pl
   branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/build/mkdir.sh
   branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/build/rpm/
   branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/build/rpm/tcnative.spec.in
   branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/build/tcnative.m4
   branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/buildconf
   branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/config.layout
   branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/configure.in
   branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/include/
   branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/include/ssl_private.h
   branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/include/tcn.h
   branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/include/tcn_api.h
   branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/include/tcn_version.h
   branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/libtcnative.dsp
   branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/libtcnative.dsw
   branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/os/
   branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/os/netware/
   branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/os/netware/system.c
   branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/os/unix/
   branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/os/unix/system.c
   branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/os/unix/uxpipe.c
   branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/os/win32/
   branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/os/win32/apache.ico
   branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/os/win32/libtcnative.rc
   branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/os/win32/logmessages.bin
   branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/os/win32/logmessages.mc
   branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/os/win32/ntpipe.c
   branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/os/win32/registry.c
   branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/os/win32/system.c
   branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/src/
   branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/src/address.c
   branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/src/dir.c
   branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/src/error.c
   branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/src/file.c
   branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/src/info.c
   branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/src/jnilib.c
   branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/src/lock.c
   branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/src/misc.c
   branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/src/mmap.c
   branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/src/multicast.c
   branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/src/network.c
   branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/src/os.c
   branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/src/poll.c
   branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/src/pool.c
   branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/src/proc.c
   branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/src/shm.c
   branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/src/ssl.c
   branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/src/sslcontext.c
   branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/src/sslinfo.c
   branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/src/sslnetwork.c
   branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/src/sslutils.c
   branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/src/stdlib.c
   branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/src/thread.c
   branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/src/user.c
   branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/tcnative.dsp
   branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/tcnative.pc.in
   branches/tomcat5.5/upstream/5.5.20/connectors/jni/test/
   branches/tomcat5.5/upstream/5.5.20/connectors/jni/test/org/
   branches/tomcat5.5/upstream/5.5.20/connectors/jni/test/org/apache/
   branches/tomcat5.5/upstream/5.5.20/connectors/jni/test/org/apache/tomcat/
   branches/tomcat5.5/upstream/5.5.20/connectors/jni/test/org/apache/tomcat/jni/
   branches/tomcat5.5/upstream/5.5.20/connectors/jni/test/org/apache/tomcat/jni/FileTestSuite.java
   branches/tomcat5.5/upstream/5.5.20/connectors/juli/
   branches/tomcat5.5/upstream/5.5.20/connectors/juli/build.xml
   branches/tomcat5.5/upstream/5.5.20/connectors/juli/src/
   branches/tomcat5.5/upstream/5.5.20/connectors/juli/src/conf/
   branches/tomcat5.5/upstream/5.5.20/connectors/juli/src/conf/logging.properties
   branches/tomcat5.5/upstream/5.5.20/connectors/juli/src/java/
   branches/tomcat5.5/upstream/5.5.20/connectors/juli/src/java/org/
   branches/tomcat5.5/upstream/5.5.20/connectors/juli/src/java/org/apache/
   branches/tomcat5.5/upstream/5.5.20/connectors/juli/src/java/org/apache/juli/
   branches/tomcat5.5/upstream/5.5.20/connectors/juli/src/java/org/apache/juli/ClassLoaderLogManager.java
   branches/tomcat5.5/upstream/5.5.20/connectors/juli/src/java/org/apache/juli/FileHandler.java
   branches/tomcat5.5/upstream/5.5.20/connectors/procrun/
   branches/tomcat5.5/upstream/5.5.20/connectors/procrun/README.txt
   branches/tomcat5.5/upstream/5.5.20/connectors/procrun/bin/
   branches/tomcat5.5/upstream/5.5.20/connectors/procrun/bin/tomcat5.exe
   branches/tomcat5.5/upstream/5.5.20/connectors/procrun/bin/tomcat5.exe.amd64
   branches/tomcat5.5/upstream/5.5.20/connectors/procrun/bin/tomcat5w.exe
   branches/tomcat5.5/upstream/5.5.20/connectors/procrun/bin/tomcat5w.exe.amd64
   branches/tomcat5.5/upstream/5.5.20/connectors/scandoc/
   branches/tomcat5.5/upstream/5.5.20/connectors/scandoc/scandoc.pl
   branches/tomcat5.5/upstream/5.5.20/connectors/scandoc/template.pl
   branches/tomcat5.5/upstream/5.5.20/connectors/util/
   branches/tomcat5.5/upstream/5.5.20/connectors/util/README.txt
   branches/tomcat5.5/upstream/5.5.20/connectors/util/build.properties.sample
   branches/tomcat5.5/upstream/5.5.20/connectors/util/build.xml
   branches/tomcat5.5/upstream/5.5.20/connectors/util/java/
   branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/
   branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/
   branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/
   branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/
   branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/IntrospectionUtils.java
   branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/buf/
   branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/buf/Ascii.java
   branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/buf/B2CConverter.java
   branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/buf/Base64.java
   branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/buf/ByteChunk.java
   branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/buf/C2BConverter.java
   branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/buf/CharChunk.java
   branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/buf/DateTool.java
   branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/buf/HexUtils.java
   branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/buf/MessageBytes.java
   branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/buf/StringCache.java
   branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/buf/TimeStamp.java
   branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/buf/UDecoder.java
   branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/buf/UEncoder.java
   branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/buf/UTF8Decoder.java
   branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/buf/package.html
   branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/buf/res/
   branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/buf/res/LocalStrings.properties
   branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/buf/res/LocalStrings_es.properties
   branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/buf/res/LocalStrings_fr.properties
   branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/buf/res/LocalStrings_ja.properties
   branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/collections/
   branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/collections/EmptyEnumeration.java
   branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/collections/LRUCache.java
   branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/collections/MultiMap.java
   branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/collections/MultiMapNamesEnumeration.java
   branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/collections/MultiMapValuesEnumeration.java
   branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/collections/Queue.java
   branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/collections/SimpleHashtable.java
   branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/collections/SimplePool.java
   branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/collections/package.html
   branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/compat/
   branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/compat/Jdk14Compat.java
   branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/compat/JdkCompat.java
   branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/digester/
   branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/digester/AbstractObjectCreationFactory.java
   branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/digester/AbstractRulesImpl.java
   branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/digester/ArrayStack.java
   branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/digester/CallMethodRule.java
   branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/digester/CallParamRule.java
   branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/digester/Digester.java
   branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/digester/FactoryCreateRule.java
   branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/digester/GenericParser.java
   branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/digester/NodeCreateRule.java
   branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/digester/ObjectCreateRule.java
   branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/digester/ObjectCreationFactory.java
   branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/digester/ObjectParamRule.java
   branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/digester/ParserFeatureSetterFactory.java
   branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/digester/PathCallParamRule.java
   branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/digester/Rule.java
   branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/digester/RuleSet.java
   branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/digester/RuleSetBase.java
   branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/digester/Rules.java
   branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/digester/RulesBase.java
   branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/digester/SetNextRule.java
   branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/digester/SetPropertiesRule.java
   branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/digester/SetPropertyRule.java
   branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/digester/SetRootRule.java
   branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/digester/SetTopRule.java
   branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/digester/WithDefaultsRulesWrapper.java
   branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/digester/XercesParser.java
   branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/digester/package.html
   branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/http/
   branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/http/AcceptLanguage.java
   branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/http/BaseRequest.java
   branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/http/ContentType.java
   branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/http/Cookies.java
   branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/http/FastHttpDateFormat.java
   branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/http/HttpMessages.java
   branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/http/MimeHeaders.java
   branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/http/MimeMap.java
   branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/http/Parameters.java
   branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/http/ServerCookie.java
   branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/http/mapper/
   branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/http/mapper/Mapper.java
   branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/http/mapper/MappingData.java
   branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/http/package.html
   branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/http/res/
   branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/http/res/LocalStrings.properties
   branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/http/res/LocalStrings_es.properties
   branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/http/res/LocalStrings_fr.properties
   branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/log/
   branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/log/CaptureLog.java
   branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/log/SystemLogHandler.java
   branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/net/
   branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/net/AprEndpoint.java
   branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/net/DefaultServerSocketFactory.java
   branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/net/LeaderFollowerWorkerThread.java
   branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/net/MasterSlaveWorkerThread.java
   branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/net/PoolTcpEndpoint.java
   branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/net/SSLImplementation.java
   branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/net/SSLSupport.java
   branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/net/ServerSocketFactory.java
   branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/net/TcpConnection.java
   branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/net/TcpConnectionHandler.java
   branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/net/URL.java
   branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/net/jsse/
   branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/net/jsse/JSSE13Factory.java
   branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/net/jsse/JSSE13SocketFactory.java
   branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/net/jsse/JSSE14Factory.java
   branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/net/jsse/JSSE14SocketFactory.java
   branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/net/jsse/JSSE14Support.java
   branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/net/jsse/JSSE15Factory.java
   branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/net/jsse/JSSE15SocketFactory.java
   branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/net/jsse/JSSEFactory.java
   branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/net/jsse/JSSEImplementation.java
   branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/net/jsse/JSSEKeyManager.java
   branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/net/jsse/JSSESocketFactory.java
   branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/net/jsse/JSSESupport.java
   branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/net/jsse/res/
   branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/net/jsse/res/LocalStrings.properties
   branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/net/jsse/res/LocalStrings_es.properties
   branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/net/jsse/res/LocalStrings_fr.properties
   branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/net/jsse/res/LocalStrings_ja.properties
   branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/net/puretls/
   branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/net/puretls/PureTLSImplementation.java
   branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/net/puretls/PureTLSSocket.java
   branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/net/puretls/PureTLSSocketFactory.java
   branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/net/puretls/PureTLSSupport.java
   branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/net/res/
   branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/net/res/LocalStrings.properties
   branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/net/res/LocalStrings_es.properties
   branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/net/res/LocalStrings_fr.properties
   branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/net/res/LocalStrings_ja.properties
   branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/res/
   branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/res/StringManager.java
   branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/threads/
   branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/threads/Expirer.java
   branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/threads/Reaper.java
   branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/threads/ThreadPool.java
   branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/threads/ThreadPoolRunnable.java
   branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/threads/ThreadWithAttributes.java
   branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/threads/res/
   branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/threads/res/LocalStrings.properties
   branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/threads/res/LocalStrings_es.properties
   branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/threads/res/LocalStrings_fr.properties
   branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/threads/res/LocalStrings_ja.properties
   branches/tomcat5.5/upstream/5.5.20/connectors/util/java/tomcat-util.manifest
   branches/tomcat5.5/upstream/5.5.20/connectors/util/loader/
   branches/tomcat5.5/upstream/5.5.20/connectors/util/loader/loader.properties
   branches/tomcat5.5/upstream/5.5.20/connectors/util/loader/org/
   branches/tomcat5.5/upstream/5.5.20/connectors/util/loader/org/apache/
   branches/tomcat5.5/upstream/5.5.20/connectors/util/loader/org/apache/tomcat/
   branches/tomcat5.5/upstream/5.5.20/connectors/util/loader/org/apache/tomcat/util/
   branches/tomcat5.5/upstream/5.5.20/connectors/util/loader/org/apache/tomcat/util/loader/
   branches/tomcat5.5/upstream/5.5.20/connectors/util/loader/org/apache/tomcat/util/loader/Loader.java
   branches/tomcat5.5/upstream/5.5.20/connectors/util/loader/org/apache/tomcat/util/loader/Module.java
   branches/tomcat5.5/upstream/5.5.20/connectors/util/loader/org/apache/tomcat/util/loader/ModuleClassLoader.java
   branches/tomcat5.5/upstream/5.5.20/connectors/util/loader/org/apache/tomcat/util/loader/ModuleListener.java
   branches/tomcat5.5/upstream/5.5.20/connectors/util/loader/org/apache/tomcat/util/loader/Repository.java
   branches/tomcat5.5/upstream/5.5.20/connectors/util/loader/org/apache/tomcat/util/loader/RepositoryClassLoader.java
   branches/tomcat5.5/upstream/5.5.20/connectors/util/loader/org/apache/tomcat/util/loader/package.html
   branches/tomcat5.5/upstream/5.5.20/connectors/util/loader/tomcat-loader.manifest
   branches/tomcat5.5/upstream/5.5.20/container/
   branches/tomcat5.5/upstream/5.5.20/container/${tomcat.build}/
   branches/tomcat5.5/upstream/5.5.20/container/.classpath
   branches/tomcat5.5/upstream/5.5.20/container/.project
   branches/tomcat5.5/upstream/5.5.20/container/LICENSE
   branches/tomcat5.5/upstream/5.5.20/container/NOTICE
   branches/tomcat5.5/upstream/5.5.20/container/Tomcat5.5.launch
   branches/tomcat5.5/upstream/5.5.20/container/build.xml
   branches/tomcat5.5/upstream/5.5.20/container/catalina/
   branches/tomcat5.5/upstream/5.5.20/container/catalina/build.xml
   branches/tomcat5.5/upstream/5.5.20/container/catalina/etc/
   branches/tomcat5.5/upstream/5.5.20/container/catalina/etc/bootstrap.MF
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/bin/
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/bin/catalina-tasks.xml
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/bin/catalina.bat
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/bin/catalina.sh
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/bin/catalina.xml
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/bin/cpappend.bat
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/bin/digest.bat
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/bin/digest.sh
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/bin/jmxaccessor-tasks.xml
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/bin/launcher.properties
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/bin/service.bat
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/bin/setclasspath.bat
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/bin/setclasspath.sh
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/bin/shutdown-using-launcher.bat
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/bin/shutdown-using-launcher.sh
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/bin/shutdown.bat
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/bin/shutdown.sh
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/bin/startup-using-launcher.bat
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/bin/startup-using-launcher.sh
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/bin/startup.bat
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/bin/startup.sh
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/bin/tool-wrapper-using-launcher.bat
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/bin/tool-wrapper-using-launcher.sh
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/bin/tool-wrapper.bat
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/bin/tool-wrapper.sh
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/bin/version.bat
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/bin/version.sh
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/conf/
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/conf/catalina.policy
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/conf/catalina.properties
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/conf/context.xml
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/conf/server-minimal.xml
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/conf/server.xml
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/conf/tomcat-users.xml
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/conf/web.xml
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/Authenticator.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/Cluster.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/Contained.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/Container.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ContainerEvent.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ContainerListener.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ContainerServlet.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/Context.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/Engine.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/Globals.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/Group.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/Host.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/InstanceEvent.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/InstanceListener.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/Lifecycle.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/LifecycleEvent.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/LifecycleException.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/LifecycleListener.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/Loader.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/Manager.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/Pipeline.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/Realm.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/Role.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/Server.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ServerFactory.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/Service.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/Session.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/SessionEvent.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/SessionListener.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/Store.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/User.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/UserDatabase.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/Valve.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/Wrapper.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ant/
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ant/AbstractCatalinaTask.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ant/BaseRedirectorHelperTask.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ant/DeployTask.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ant/InstallTask.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ant/JKStatusUpdateTask.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ant/JMXGetTask.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ant/JMXQueryTask.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ant/JMXSetTask.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ant/ListTask.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ant/ReloadTask.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ant/RemoveTask.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ant/ResourcesTask.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ant/RolesTask.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ant/ServerinfoTask.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ant/SessionsTask.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ant/StartTask.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ant/StopTask.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ant/UndeployTask.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ant/ValidatorTask.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ant/antlib.xml
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ant/catalina.tasks
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ant/jmx/
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ant/jmx/Arg.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ant/jmx/JMXAccessorCondition.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ant/jmx/JMXAccessorCreateTask.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ant/jmx/JMXAccessorEqualsCondition.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ant/jmx/JMXAccessorGetTask.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ant/jmx/JMXAccessorInvokeTask.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ant/jmx/JMXAccessorQueryTask.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ant/jmx/JMXAccessorSetTask.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ant/jmx/JMXAccessorTask.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ant/jmx/JMXAccessorUnregisterTask.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ant/jmx/antlib.xml
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ant/jmx/jmxaccessor.tasks
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ant/jmx/package.html
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ant/package.html
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/authenticator/
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/authenticator/AuthenticatorBase.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/authenticator/BasicAuthenticator.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/authenticator/Constants.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/authenticator/DigestAuthenticator.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/authenticator/FormAuthenticator.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/authenticator/LocalStrings.properties
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/authenticator/LocalStrings_es.properties
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/authenticator/LocalStrings_fr.properties
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/authenticator/LocalStrings_ja.properties
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/authenticator/NonLoginAuthenticator.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/authenticator/SSLAuthenticator.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/authenticator/SavedRequest.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/authenticator/SingleSignOn.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/authenticator/SingleSignOnEntry.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/authenticator/mbeans-descriptors.xml
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/authenticator/package.html
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/connector/
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/connector/ClientAbortException.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/connector/Connector.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/connector/Constants.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/connector/CoyoteAdapter.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/connector/CoyoteInputStream.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/connector/CoyoteOutputStream.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/connector/CoyotePrincipal.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/connector/CoyoteReader.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/connector/CoyoteWriter.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/connector/InputBuffer.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/connector/LocalStrings.properties
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/connector/LocalStrings_es.properties
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/connector/LocalStrings_fr.properties
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/connector/LocalStrings_ja.properties
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/connector/MapperListener.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/connector/OutputBuffer.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/connector/Request.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/connector/RequestFacade.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/connector/Response.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/connector/ResponseFacade.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/connector/mbeans-descriptors.xml
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/core/
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/core/ApplicationContext.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/core/ApplicationContextFacade.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/core/ApplicationDispatcher.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/core/ApplicationFilterChain.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/core/ApplicationFilterConfig.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/core/ApplicationFilterFactory.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/core/ApplicationHttpRequest.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/core/ApplicationHttpResponse.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/core/ApplicationRequest.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/core/ApplicationResponse.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/core/AprLifecycleListener.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/core/Constants.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/core/ContainerBase.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/core/DummyRequest.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/core/DummyResponse.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/core/LocalStrings.properties
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/core/LocalStrings_es.properties
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/core/LocalStrings_fr.properties
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/core/LocalStrings_ja.properties
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/core/NamingContextListener.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/core/StandardContext.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/core/StandardContextValve.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/core/StandardEngine.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/core/StandardEngineValve.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/core/StandardHost.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/core/StandardHostValve.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/core/StandardPipeline.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/core/StandardServer.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/core/StandardService.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/core/StandardWrapper.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/core/StandardWrapperFacade.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/core/StandardWrapperValve.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/core/mbeans-descriptors.xml
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/deploy/
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/deploy/ApplicationParameter.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/deploy/ContextEjb.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/deploy/ContextEnvironment.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/deploy/ContextLocalEjb.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/deploy/ContextResource.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/deploy/ContextResourceEnvRef.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/deploy/ContextResourceLink.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/deploy/ContextTransaction.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/deploy/ErrorPage.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/deploy/FilterDef.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/deploy/FilterMap.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/deploy/LoginConfig.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/deploy/MessageDestination.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/deploy/MessageDestinationRef.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/deploy/NamingResources.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/deploy/ResourceBase.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/deploy/SecurityCollection.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/deploy/SecurityConstraint.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/deploy/mbeans-descriptors.xml
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/deploy/package.html
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/launcher/
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/launcher/CatalinaLaunchFilter.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/loader/
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/loader/Constants.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/loader/LocaStrings_fr.properties
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/loader/LocalStrings.properties
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/loader/LocalStrings_es.properties
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/loader/LocalStrings_ja.properties
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/loader/Reloader.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/loader/ResourceEntry.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/loader/StandardClassLoader.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/loader/StandardClassLoaderMBean.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/loader/WebappClassLoader.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/loader/WebappLoader.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/loader/mbeans-descriptors.xml
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/mbeans-descriptors.xml
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/mbeans/
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/mbeans/ClassNameMBean.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/mbeans/ConnectorMBean.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/mbeans/ContextEnvironmentMBean.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/mbeans/ContextResourceLinkMBean.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/mbeans/ContextResourceMBean.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/mbeans/DefaultContextMBean.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/mbeans/GlobalResourcesLifecycleListener.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/mbeans/GroupMBean.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/mbeans/MBeanFactory.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/mbeans/MBeanUtils.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/mbeans/MemoryUserDatabaseMBean.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/mbeans/NamingResourcesMBean.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/mbeans/RoleMBean.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/mbeans/ServerLifecycleListener.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/mbeans/StandardContextMBean.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/mbeans/StandardEngineMBean.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/mbeans/StandardHostMBean.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/mbeans/StandardServerMBean.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/mbeans/StandardServiceMBean.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/mbeans/UserMBean.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/mbeans/mbeans-descriptors.xml
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/realm/
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/realm/Constants.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/realm/DataSourceRealm.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/realm/GenericPrincipal.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/realm/JAASCallbackHandler.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/realm/JAASMemoryLoginModule.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/realm/JAASRealm.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/realm/JDBCRealm.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/realm/JNDIRealm.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/realm/LocalStrings.properties
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/realm/LocalStrings_es.properties
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/realm/LocalStrings_fr.properties
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/realm/LocalStrings_ja.properties
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/realm/MemoryRealm.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/realm/MemoryRuleSet.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/realm/RealmBase.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/realm/UserDatabaseRealm.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/realm/mbeans-descriptors.xml
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/realm/package.html
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/security/
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/security/LocalStrings.properties
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/security/LocalStrings_es.properties
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/security/LocalStrings_fr.properties
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/security/LocalStrings_ja.properties
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/security/SecurityClassLoad.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/security/SecurityConfig.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/security/SecurityUtil.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/servlets/
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/servlets/CGIServlet.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/servlets/Constants.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/servlets/DefaultServlet.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/servlets/InvokerHttpRequest.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/servlets/InvokerServlet.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/servlets/LocalStrings.properties
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/servlets/LocalStrings_es.properties
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/servlets/LocalStrings_fr.properties
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/servlets/LocalStrings_ja.properties
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/servlets/WebdavServlet.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/servlets/package.html
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/session/
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/session/Constants.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/session/FileStore.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/session/JDBCStore.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/session/LocalStrings.properties
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/session/LocalStrings_es.properties
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/session/LocalStrings_fr.properties
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/session/LocalStrings_ja.properties
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/session/ManagerBase.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/session/PersistentManager.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/session/PersistentManagerBase.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/session/StandardManager.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/session/StandardSession.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/session/StandardSessionFacade.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/session/StoreBase.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/session/mbeans-descriptors.xml
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/session/package.html
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ssi/
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ssi/ByteArrayServletOutputStream.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ssi/ExpressionParseTree.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ssi/ExpressionTokenizer.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ssi/ResponseIncludeWrapper.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ssi/SSICommand.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ssi/SSIConditional.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ssi/SSIConditionalState.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ssi/SSIConfig.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ssi/SSIEcho.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ssi/SSIExec.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ssi/SSIExternalResolver.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ssi/SSIFilter.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ssi/SSIFlastmod.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ssi/SSIFsize.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ssi/SSIInclude.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ssi/SSIMediator.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ssi/SSIPrintenv.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ssi/SSIProcessor.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ssi/SSIServlet.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ssi/SSIServletExternalResolver.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ssi/SSIServletRequestUtil.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ssi/SSISet.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ssi/SSIStopProcessingException.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ssi/package.html
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/startup/
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/startup/Authenticators.properties
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/startup/Bootstrap.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/startup/Catalina.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/startup/CatalinaProperties.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/startup/ClassLoaderFactory.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/startup/ClusterRuleSetFactory.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/startup/ConnectorCreateRule.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/startup/Constants.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/startup/ContextConfig.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/startup/ContextRuleSet.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/startup/CopyParentClassLoaderRule.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/startup/DigesterFactory.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/startup/Embedded.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/startup/EngineConfig.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/startup/EngineRuleSet.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/startup/ExpandWar.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/startup/HomesUserDatabase.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/startup/HostConfig.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/startup/HostRuleSet.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/startup/LifecycleListenerRule.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/startup/LocalStrings.properties
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/startup/LocalStrings_es.properties
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/startup/LocalStrings_fr.properties
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/startup/LocalStrings_ja.properties
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/startup/NamingRuleSet.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/startup/PasswdUserDatabase.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/startup/SetAllPropertiesRule.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/startup/SetContextPropertiesRule.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/startup/SetNextNamingRule.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/startup/TldConfig.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/startup/TldRuleSet.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/startup/Tool.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/startup/UserConfig.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/startup/UserDatabase.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/startup/WebRuleSet.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/startup/catalina.properties
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/startup/mbeans-descriptors.xml
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/users/
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/users/AbstractGroup.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/users/AbstractRole.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/users/AbstractUser.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/users/Constants.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/users/LocalStrings.properties
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/users/LocalStrings_es.properties
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/users/LocalStrings_fr.properties
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/users/LocalStrings_ja.properties
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/users/MemoryGroup.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/users/MemoryRole.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/users/MemoryUser.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/users/MemoryUserDatabase.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/users/MemoryUserDatabaseFactory.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/users/mbeans-descriptors.xml
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/Base64.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/CGIProcessEnvironment.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/CharsetMapper.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/CharsetMapperDefault.properties
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/CookieTools.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/CustomObjectInputStream.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/DOMWriter.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/DateTool.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/Enumerator.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/Extension.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/ExtensionValidator.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/FastDateFormat.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/HexUtils.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/IOTools.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/InstanceSupport.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/LifecycleSupport.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/LocalStrings.properties
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/LocalStrings_es.properties
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/LocalStrings_fr.properties
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/LocalStrings_ja.properties
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/MD5Encoder.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/MIME2Java.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/ManifestResource.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/ParameterMap.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/ProcessEnvironment.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/ProcessHelper.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/Queue.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/RequestUtil.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/ResourceSet.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/SchemaResolver.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/ServerInfo.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/ServerInfo.properties
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/Strftime.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/StringManager.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/StringParser.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/TomcatCSS.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/URL.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/URLEncoder.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/XMLWriter.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/valves/
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/valves/AccessLogValve.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/valves/Constants.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/valves/ErrorReportValve.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/valves/ExtendedAccessLogValve.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/valves/FastCommonAccessLogValve.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/valves/JDBCAccessLogValve.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/valves/LocalStrings.properties
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/valves/LocalStrings_es.properties
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/valves/LocalStrings_fr.properties
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/valves/LocalStrings_ja.properties
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/valves/PersistentValve.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/valves/RemoteAddrValve.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/valves/RemoteHostValve.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/valves/RequestDumperValve.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/valves/RequestFilterValve.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/valves/SemaphoreValve.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/valves/ValveBase.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/valves/mbeans-descriptors.xml
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/valves/package.html
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/Constants.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/ContextAccessController.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/ContextBindings.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/EjbRef.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/JndiPermission.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/LocalStrings.properties
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/LocalStrings_es.properties
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/LocalStrings_fr.properties
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/LocalStrings_ja.properties
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/NameParserImpl.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/NamingContext.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/NamingContextBindingsEnumeration.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/NamingContextEnumeration.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/NamingEntry.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/NamingService.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/NamingServiceMBean.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/ResourceEnvRef.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/ResourceLinkRef.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/ResourceRef.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/SelectorContext.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/StringManager.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/TransactionRef.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/factory/
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/factory/BeanFactory.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/factory/Constants.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/factory/EjbFactory.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/factory/MailSessionFactory.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/factory/OpenEjbFactory.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/factory/ResourceEnvFactory.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/factory/ResourceFactory.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/factory/ResourceLinkFactory.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/factory/SendMailFactory.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/factory/TransactionFactory.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/factory/package.html
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/java/
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/java/javaURLContextFactory.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/java/package.html
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/package.html
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/resources/
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/resources/BaseDirContext.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/resources/CacheEntry.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/resources/Constants.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/resources/DirContextURLConnection.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/resources/DirContextURLStreamHandler.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/resources/DirContextURLStreamHandlerFactory.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/resources/FileDirContext.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/resources/ImmutableNameNotFoundException.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/resources/LocalStrings.properties
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/resources/LocalStrings_es.properties
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/resources/LocalStrings_fr.properties
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/resources/LocalStrings_ja.properties
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/resources/ProxyDirContext.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/resources/RecyclableNamingEnumeration.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/resources/Resource.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/resources/ResourceAttributes.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/resources/ResourceCache.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/resources/WARDirContext.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/resources/jndi/
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/resources/jndi/Handler.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/resources/package.html
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/temp/
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/temp/README.txt
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/test/
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/test/org/
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/test/org/apache/
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/test/org/apache/catalina/
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/test/org/apache/catalina/util/
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/test/org/apache/catalina/util/CookieToolsTestCase.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/test/org/apache/catalina/util/URLTestCase.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/test/org/apache/naming/
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/test/org/apache/naming/resources/
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/test/org/apache/naming/resources/BaseDirContextTestCase.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/test/org/apache/naming/resources/FileDirContextTestCase.java
   branches/tomcat5.5/upstream/5.5.20/container/catalina/src/test/org/apache/naming/resources/WARDirContextTestCase.java
   branches/tomcat5.5/upstream/5.5.20/container/etc/
   branches/tomcat5.5/upstream/5.5.20/container/etc/mx4j.license
   branches/tomcat5.5/upstream/5.5.20/container/modules/
   branches/tomcat5.5/upstream/5.5.20/container/modules/build.properties
   branches/tomcat5.5/upstream/5.5.20/container/modules/build.xml
   branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/
   branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/build.xml
   branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/etc/
   branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/etc/cluster-server.xml
   branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/
   branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/
   branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/
   branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/
   branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/
   branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/
   branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/CatalinaCluster.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/ClusterDeployer.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/ClusterManager.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/ClusterMessage.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/ClusterReceiver.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/ClusterRuleSet.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/ClusterSender.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/ClusterSession.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/ClusterValve.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/Constants.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/LocalStrings.properties
   branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/Member.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/MembershipListener.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/MembershipService.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/MessageListener.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/deploy/
   branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/deploy/FarmWarDeployer.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/deploy/FileChangeListener.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/deploy/FileMessage.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/deploy/FileMessageFactory.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/deploy/UndeployMessage.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/deploy/WarWatcher.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/io/
   branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/io/ListenCallback.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/io/ObjectReader.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/io/SocketObjectReader.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/io/XByteBuffer.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/mbeans-descriptors.xml
   branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/mcast/
   branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/mcast/Constants.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/mcast/LocalStrings.properties
   branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/mcast/McastMember.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/mcast/McastMembership.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/mcast/McastService.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/mcast/McastServiceImpl.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/mcast/mbeans-descriptors.xml
   branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/package.html
   branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/session/
   branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/session/ClusterListener.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/session/ClusterSessionListener.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/session/Constants.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/session/DeltaManager.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/session/DeltaRequest.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/session/DeltaSession.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/session/DeltaSessionFacade.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/session/JvmRouteBinderValve.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/session/JvmRouteSessionIDBinderLifecycleListener.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/session/JvmRouteSessionIDBinderListener.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/session/LocalStrings.properties
   branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/session/ReplicatedSession.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/session/ReplicationStream.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/session/SerializablePrincipal.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/session/SessionIDMessage.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/session/SessionMessage.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/session/SessionMessageImpl.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/session/SimpleTcpReplicationManager.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/session/mbeans-descriptors.xml
   branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/tcp/
   branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/tcp/AsyncSocketSender.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/tcp/ClusterData.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/tcp/ClusterReceiverBase.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/tcp/Constants.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/tcp/DataSender.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/tcp/DataSenders.properties
   branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/tcp/FastAsyncSocketSender.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/tcp/IDataSender.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/tcp/IDataSenderFactory.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/tcp/LocalStrings.properties
   branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/tcp/PooledSocketSender.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/tcp/ReplicationListener.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/tcp/ReplicationTransmitter.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/tcp/ReplicationValve.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/tcp/SendMessageData.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/tcp/SenderState.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/tcp/SimpleTcpCluster.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/tcp/SocketReplicationListener.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/tcp/SocketReplicationThread.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/tcp/SocketSender.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/tcp/TcpReplicationThread.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/tcp/ThreadPool.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/tcp/WorkerThread.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/tcp/mbeans-descriptors.xml
   branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/util/
   branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/util/FastQueue.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/util/IDynamicProperty.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/util/IQueue.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/util/LinkObject.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/util/SingleRemoveSynchronizedAddLock.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/util/SmartQueue.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/test/
   branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/test/build.xml
   branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/test/conf/
   branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/test/conf/log4j.xml
   branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/test/src/
   branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/test/src/share/
   branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/test/src/share/org/
   branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/test/src/share/org/apache/
   branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/test/src/share/org/apache/catalina/
   branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/test/src/share/org/apache/catalina/cluster/
   branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/test/src/share/org/apache/catalina/cluster/io/
   branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/test/src/share/org/apache/catalina/cluster/io/XByteBufferTest.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/test/src/share/org/apache/catalina/cluster/mcast/
   branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/test/src/share/org/apache/catalina/cluster/mcast/McastMemberTest.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/test/src/share/org/apache/catalina/cluster/session/
   branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/test/src/share/org/apache/catalina/cluster/session/DeltaManagerTest.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/test/src/share/org/apache/catalina/cluster/session/DeltaSessionTest.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/test/src/share/org/apache/catalina/cluster/tcp/
   branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/test/src/share/org/apache/catalina/cluster/tcp/DataSenderTest.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/test/src/share/org/apache/catalina/cluster/tcp/ReplicationTransmitterTest.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/test/src/share/org/apache/catalina/cluster/tcp/ReplicationValveTest.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/test/src/share/org/apache/catalina/cluster/tcp/SimpleTcpClusterTest.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/to-do.txt
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/VERSION
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/build.xml
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/doc/
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/doc/faq.xml
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/doc/introduction.xml
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/doc/leader-election-initiate-election.dia
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/doc/leader-election-initiate-election.jpg
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/doc/leader-election-message-arrives.dia
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/doc/leader-election-message-arrives.jpg
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/doc/project.xml
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/doc/setup.xml
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/doc/tomcat-docs.xsl
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/etc/
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/etc/cluster-server.xml
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/ByteMessage.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/Channel.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/ChannelException.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/ChannelInterceptor.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/ChannelListener.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/ChannelMessage.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/ChannelReceiver.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/ChannelSender.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/Constants.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/ErrorHandler.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/Heartbeat.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/LocalStrings.properties
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/ManagedChannel.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/Member.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/MembershipListener.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/MembershipService.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/MessageListener.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/RemoteProcessException.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/UniqueId.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/group/
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/group/AbsoluteOrder.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/group/ChannelCoordinator.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/group/ChannelInterceptorBase.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/group/GroupChannel.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/group/InterceptorPayload.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/group/Response.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/group/RpcCallback.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/group/RpcChannel.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/group/RpcMessage.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/group/interceptors/
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/group/interceptors/DomainFilterInterceptor.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/group/interceptors/FragmentationInterceptor.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/group/interceptors/GzipInterceptor.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/group/interceptors/MessageDispatch15Interceptor.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/group/interceptors/MessageDispatchInterceptor.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/group/interceptors/NonBlockingCoordinator.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/group/interceptors/OrderInterceptor.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/group/interceptors/StaticMembershipInterceptor.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/group/interceptors/TcpFailureDetector.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/group/interceptors/ThroughputInterceptor.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/group/interceptors/TwoPhaseCommitInterceptor.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/io/
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/io/BufferPool.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/io/BufferPool14Impl.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/io/BufferPool15Impl.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/io/ChannelData.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/io/DirectByteArrayOutputStream.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/io/ListenCallback.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/io/ObjectReader.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/io/ReplicationStream.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/io/XByteBuffer.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/mbeans-descriptors.xml
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/membership/
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/membership/Constants.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/membership/LocalStrings.properties
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/membership/McastService.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/membership/McastServiceImpl.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/membership/MemberImpl.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/membership/Membership.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/membership/mbeans-descriptors.xml
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/package.html
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/tipis/
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/tipis/AbstractReplicatedMap.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/tipis/LazyReplicatedMap.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/tipis/ReplicatedMap.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/tipis/ReplicatedMapEntry.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/tipis/Streamable.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/transport/
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/transport/AbstractSender.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/transport/Constants.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/transport/DataSender.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/transport/LocalStrings.properties
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/transport/MultiPointSender.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/transport/PooledSender.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/transport/ReceiverBase.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/transport/ReplicationTransmitter.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/transport/SenderState.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/transport/ThreadPool.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/transport/WorkerThread.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/transport/bio/
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/transport/bio/BioReceiver.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/transport/bio/BioReplicationThread.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/transport/bio/BioSender.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/transport/bio/MultipointBioSender.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/transport/bio/PooledMultiSender.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/transport/bio/util/
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/transport/bio/util/FastQueue.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/transport/bio/util/LinkObject.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/transport/bio/util/SingleRemoveSynchronizedAddLock.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/transport/mbeans-descriptors.xml
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/transport/nio/
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/transport/nio/NioReceiver.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/transport/nio/NioReplicationThread.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/transport/nio/NioSender.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/transport/nio/ParallelNioSender.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/transport/nio/PooledParallelSender.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/util/
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/util/Arrays.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/util/Logs.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/util/StringManager.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/util/UUIDGenerator.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/test-cases.txt
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/test/
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/test/java/
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/test/java/org/
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/test/java/org/apache/
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/test/java/org/apache/catalina/
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/test/java/org/apache/catalina/tribes/
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/test/java/org/apache/catalina/tribes/demos/
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/test/java/org/apache/catalina/tribes/demos/ChannelCreator.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/test/java/org/apache/catalina/tribes/demos/CoordinationDemo.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/test/java/org/apache/catalina/tribes/demos/EchoRpcTest.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/test/java/org/apache/catalina/tribes/demos/IntrospectionUtils.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/test/java/org/apache/catalina/tribes/demos/LoadTest.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/test/java/org/apache/catalina/tribes/demos/MapDemo.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/test/java/org/apache/catalina/tribes/group/
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/test/java/org/apache/catalina/tribes/group/interceptors/
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/test/java/org/apache/catalina/tribes/test/
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/test/java/org/apache/catalina/tribes/test/TestNioSender.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/test/java/org/apache/catalina/tribes/test/TribesTestSuite.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/test/java/org/apache/catalina/tribes/test/channel/
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/test/java/org/apache/catalina/tribes/test/channel/ChannelStartStop.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/test/java/org/apache/catalina/tribes/test/channel/TestChannelOptionFlag.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/test/java/org/apache/catalina/tribes/test/channel/TestDataIntegrity.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/test/java/org/apache/catalina/tribes/test/channel/TestRemoteProcessException.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/test/java/org/apache/catalina/tribes/test/interceptors/
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/test/java/org/apache/catalina/tribes/test/interceptors/TestNonBlockingCoordinator.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/test/java/org/apache/catalina/tribes/test/interceptors/TestTwoPhaseCommit.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/test/java/org/apache/catalina/tribes/test/io/
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/test/java/org/apache/catalina/tribes/test/io/TestSenderConnections.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/test/java/org/apache/catalina/tribes/test/io/TestSerialization.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/test/java/org/apache/catalina/tribes/test/membership/
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/test/java/org/apache/catalina/tribes/test/membership/MemberSerialization.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/test/java/org/apache/catalina/tribes/test/membership/TestDomainFilter.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/test/java/org/apache/catalina/tribes/test/membership/TestMemberArrival.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/test/java/org/apache/catalina/tribes/test/membership/TestTcpFailureDetector.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/test/java/org/apache/catalina/tribes/test/mina/
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/test/java/org/apache/catalina/tribes/test/transport/
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/test/java/org/apache/catalina/tribes/test/transport/SocketNioReceive.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/test/java/org/apache/catalina/tribes/test/transport/SocketNioSend.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/test/java/org/apache/catalina/tribes/test/transport/SocketNioValidateSend.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/test/java/org/apache/catalina/tribes/test/transport/SocketReceive.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/test/java/org/apache/catalina/tribes/test/transport/SocketSend.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/test/java/org/apache/catalina/tribes/test/transport/SocketTribesReceive.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/test/java/org/apache/catalina/tribes/test/transport/SocketValidateReceive.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/to-do.txt
   branches/tomcat5.5/upstream/5.5.20/container/modules/ha/
   branches/tomcat5.5/upstream/5.5.20/container/modules/ha/build.xml
   branches/tomcat5.5/upstream/5.5.20/container/modules/ha/etc/
   branches/tomcat5.5/upstream/5.5.20/container/modules/ha/etc/cluster-server.xml
   branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/
   branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/
   branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/
   branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/
   branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/
   branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/
   branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/CatalinaCluster.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/ClusterDeployer.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/ClusterListener.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/ClusterManager.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/ClusterMessage.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/ClusterMessageBase.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/ClusterRuleSet.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/ClusterSession.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/ClusterValve.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/Constants.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/LocalStrings.properties
   branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/context/
   branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/context/ReplicatedContext.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/deploy/
   branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/deploy/FarmWarDeployer.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/deploy/FileChangeListener.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/deploy/FileMessage.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/deploy/FileMessageFactory.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/deploy/UndeployMessage.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/deploy/WarWatcher.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/mbeans-descriptors.xml
   branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/package.html
   branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/session/
   branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/session/BackupManager.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/session/ClusterManagerBase.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/session/ClusterSessionListener.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/session/Constants.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/session/DeltaManager.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/session/DeltaRequest.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/session/DeltaSession.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/session/JvmRouteBinderValve.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/session/JvmRouteSessionIDBinderLifecycleListener.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/session/JvmRouteSessionIDBinderListener.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/session/LocalStrings.properties
   branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/session/ReplicatedSession.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/session/SerializablePrincipal.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/session/SessionIDMessage.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/session/SessionMessage.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/session/SessionMessageImpl.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/session/SimpleTcpReplicationManager.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/session/mbeans-descriptors.xml
   branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/tcp/
   branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/tcp/Constants.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/tcp/LocalStrings.properties
   branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/tcp/ReplicationValve.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/tcp/SendMessageData.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/tcp/SimpleTcpCluster.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/tcp/mbeans-descriptors.xml
   branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/util/
   branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/util/IDynamicProperty.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/ha/test/
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/build.xml
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/docs/
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/docs/Readme.txt
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/src/
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/src/share/
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/src/share/org/
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/src/share/org/apache/
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/src/share/org/apache/catalina/
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/src/share/org/apache/catalina/storeconfig/
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/src/share/org/apache/catalina/storeconfig/CatalinaClusterSF.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/src/share/org/apache/catalina/storeconfig/ConnectorSF.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/src/share/org/apache/catalina/storeconfig/ConnectorStoreAppender.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/src/share/org/apache/catalina/storeconfig/Constants.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/src/share/org/apache/catalina/storeconfig/GlobalNamingResourcesSF.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/src/share/org/apache/catalina/storeconfig/IDynamicPropertyStoreAppender.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/src/share/org/apache/catalina/storeconfig/IStoreConfig.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/src/share/org/apache/catalina/storeconfig/IStoreFactory.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/src/share/org/apache/catalina/storeconfig/InstanceListenerSF.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/src/share/org/apache/catalina/storeconfig/LoaderSF.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/src/share/org/apache/catalina/storeconfig/LocalStrings.properties
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/src/share/org/apache/catalina/storeconfig/ManagerSF.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/src/share/org/apache/catalina/storeconfig/NamingResourcesSF.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/src/share/org/apache/catalina/storeconfig/PersistentManagerSF.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/src/share/org/apache/catalina/storeconfig/StandardContextSF.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/src/share/org/apache/catalina/storeconfig/StandardEngineSF.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/src/share/org/apache/catalina/storeconfig/StandardHostSF.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/src/share/org/apache/catalina/storeconfig/StandardServerSF.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/src/share/org/apache/catalina/storeconfig/StandardServiceSF.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/src/share/org/apache/catalina/storeconfig/StoreAppender.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/src/share/org/apache/catalina/storeconfig/StoreConfig.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/src/share/org/apache/catalina/storeconfig/StoreConfigLifecycleListener.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/src/share/org/apache/catalina/storeconfig/StoreContextAppender.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/src/share/org/apache/catalina/storeconfig/StoreDescription.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/src/share/org/apache/catalina/storeconfig/StoreFactoryBase.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/src/share/org/apache/catalina/storeconfig/StoreFactoryRule.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/src/share/org/apache/catalina/storeconfig/StoreFileMover.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/src/share/org/apache/catalina/storeconfig/StoreLoader.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/src/share/org/apache/catalina/storeconfig/StoreRegistry.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/src/share/org/apache/catalina/storeconfig/WatchedResourceSF.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/src/share/org/apache/catalina/storeconfig/WrapperLifecycleSF.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/src/share/org/apache/catalina/storeconfig/WrapperListenerSF.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/src/share/org/apache/catalina/storeconfig/mbeans-descriptors.xml
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/src/share/org/apache/catalina/storeconfig/server-registry.xml
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/test/
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/test/build.xml
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/test/conf/
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/test/conf/catalina.keystore
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/test/conf/context.xml
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/test/conf/log4j.xml
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/test/conf/server-registry-test.xml
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/test/conf/server.xml
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/test/genstore.xml
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/test/src/
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/test/src/share/
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/test/src/share/org/
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/test/src/share/org/apache/
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/test/src/share/org/apache/catalina/
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/test/src/share/org/apache/catalina/storeconfig/
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/test/src/share/org/apache/catalina/storeconfig/ConnectorSFTest.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/test/src/share/org/apache/catalina/storeconfig/ConnectorStoreAppenderTest.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/test/src/share/org/apache/catalina/storeconfig/DescriptorHelper.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/test/src/share/org/apache/catalina/storeconfig/GlobalNamingResourcesSFTest.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/test/src/share/org/apache/catalina/storeconfig/InfoLifecycleListener.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/test/src/share/org/apache/catalina/storeconfig/LF.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/test/src/share/org/apache/catalina/storeconfig/LoaderSFTest.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/test/src/share/org/apache/catalina/storeconfig/ManagerSFTest.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/test/src/share/org/apache/catalina/storeconfig/ServerChildsTest.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/test/src/share/org/apache/catalina/storeconfig/StandardContextSFTest.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/test/src/share/org/apache/catalina/storeconfig/StandardEngineSFTest.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/test/src/share/org/apache/catalina/storeconfig/StandardHostSFTest.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/test/src/share/org/apache/catalina/storeconfig/StandardServiceSFTest.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/test/src/share/org/apache/catalina/storeconfig/StoreAppenderTest.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/test/src/share/org/apache/catalina/storeconfig/StoreContextAppenderTest.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/test/src/share/org/apache/catalina/storeconfig/StoreLoaderTest.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/test/src/share/org/apache/catalina/storeconfig/StoreRegistryTest.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/to-do.txt
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/build.xml
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/docs/
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/docs/Readme.txt
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/src/
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/src/share/
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/src/share/org/
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/src/share/org/apache/
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/src/share/org/apache/catalina/
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/src/share/org/apache/catalina/storeconfig/
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/src/share/org/apache/catalina/storeconfig/CatalinaClusterSF.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/src/share/org/apache/catalina/storeconfig/ConnectorSF.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/src/share/org/apache/catalina/storeconfig/ConnectorStoreAppender.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/src/share/org/apache/catalina/storeconfig/Constants.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/src/share/org/apache/catalina/storeconfig/GlobalNamingResourcesSF.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/src/share/org/apache/catalina/storeconfig/IDynamicPropertyStoreAppender.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/src/share/org/apache/catalina/storeconfig/IStoreConfig.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/src/share/org/apache/catalina/storeconfig/IStoreFactory.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/src/share/org/apache/catalina/storeconfig/InstanceListenerSF.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/src/share/org/apache/catalina/storeconfig/LoaderSF.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/src/share/org/apache/catalina/storeconfig/LocalStrings.properties
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/src/share/org/apache/catalina/storeconfig/ManagerSF.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/src/share/org/apache/catalina/storeconfig/NamingResourcesSF.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/src/share/org/apache/catalina/storeconfig/PersistentManagerSF.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/src/share/org/apache/catalina/storeconfig/StandardContextSF.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/src/share/org/apache/catalina/storeconfig/StandardEngineSF.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/src/share/org/apache/catalina/storeconfig/StandardHostSF.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/src/share/org/apache/catalina/storeconfig/StandardServerSF.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/src/share/org/apache/catalina/storeconfig/StandardServiceSF.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/src/share/org/apache/catalina/storeconfig/StoreAppender.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/src/share/org/apache/catalina/storeconfig/StoreConfig.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/src/share/org/apache/catalina/storeconfig/StoreConfigLifecycleListener.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/src/share/org/apache/catalina/storeconfig/StoreContextAppender.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/src/share/org/apache/catalina/storeconfig/StoreDescription.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/src/share/org/apache/catalina/storeconfig/StoreFactoryBase.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/src/share/org/apache/catalina/storeconfig/StoreFactoryRule.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/src/share/org/apache/catalina/storeconfig/StoreFileMover.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/src/share/org/apache/catalina/storeconfig/StoreLoader.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/src/share/org/apache/catalina/storeconfig/StoreRegistry.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/src/share/org/apache/catalina/storeconfig/WatchedResourceSF.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/src/share/org/apache/catalina/storeconfig/WrapperLifecycleSF.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/src/share/org/apache/catalina/storeconfig/WrapperListenerSF.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/src/share/org/apache/catalina/storeconfig/mbeans-descriptors.xml
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/src/share/org/apache/catalina/storeconfig/server-registry.xml
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/test/
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/test/build.xml
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/test/conf/
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/test/conf/catalina.keystore
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/test/conf/context.xml
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/test/conf/log4j.xml
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/test/conf/server-registry-test.xml
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/test/conf/server.xml
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/test/genstore.xml
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/test/src/
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/test/src/share/
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/test/src/share/org/
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/test/src/share/org/apache/
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/test/src/share/org/apache/catalina/
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/test/src/share/org/apache/catalina/storeconfig/
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/test/src/share/org/apache/catalina/storeconfig/ConnectorSFTest.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/test/src/share/org/apache/catalina/storeconfig/ConnectorStoreAppenderTest.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/test/src/share/org/apache/catalina/storeconfig/DescriptorHelper.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/test/src/share/org/apache/catalina/storeconfig/GlobalNamingResourcesSFTest.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/test/src/share/org/apache/catalina/storeconfig/InfoLifecycleListener.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/test/src/share/org/apache/catalina/storeconfig/LF.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/test/src/share/org/apache/catalina/storeconfig/LoaderSFTest.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/test/src/share/org/apache/catalina/storeconfig/ManagerSFTest.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/test/src/share/org/apache/catalina/storeconfig/ServerChildsTest.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/test/src/share/org/apache/catalina/storeconfig/StandardContextSFTest.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/test/src/share/org/apache/catalina/storeconfig/StandardEngineSFTest.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/test/src/share/org/apache/catalina/storeconfig/StandardHostSFTest.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/test/src/share/org/apache/catalina/storeconfig/StandardServiceSFTest.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/test/src/share/org/apache/catalina/storeconfig/StoreAppenderTest.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/test/src/share/org/apache/catalina/storeconfig/StoreContextAppenderTest.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/test/src/share/org/apache/catalina/storeconfig/StoreLoaderTest.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/test/src/share/org/apache/catalina/storeconfig/StoreRegistryTest.java
   branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/to-do.txt
   branches/tomcat5.5/upstream/5.5.20/container/tester/
   branches/tomcat5.5/upstream/5.5.20/container/tester/build.xml
   branches/tomcat5.5/upstream/5.5.20/container/tester/src/
   branches/tomcat5.5/upstream/5.5.20/container/tester/src/bin/
   branches/tomcat5.5/upstream/5.5.20/container/tester/src/bin/tester.xml
   branches/tomcat5.5/upstream/5.5.20/container/tester/src/conf/
   branches/tomcat5.5/upstream/5.5.20/container/tester/src/conf/tomcat-users.xml
   branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/
   branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/
   branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/
   branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/
   branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Aggregate01.java
   branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Aggregate02.java
   branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Authentication01.java
   branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Authentication02.java
   branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Authentication03.java
   branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Authentication05.java
   branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Authentication06.java
   branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/CharArrayResponse.java
   branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/CharArrayWriterUpperCase.java
   branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Context00.java
   branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Context01.java
   branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Context02.java
   branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/ContextBean.java
   branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/ContextListener01.java
   branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/ContextListener02.java
   branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/DatePropertyEditor.java
   branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Decoding01.java
   branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/ErrorPage01.java
   branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/ErrorPage02.java
   branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/ErrorPage03.java
   branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/ErrorPage04.java
   branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/ErrorPage05.java
   branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/ErrorPage06.java
   branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/ErrorPage07.java
   branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/FilterRequest01.java
   branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/FilterRequest02.java
   branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/FilterRequest02a.java
   branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/FilterResponse01.java
   branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/FilterResponse04.java
   branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/FilterResponse04a.java
   branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Forward00.java
   branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Forward00a.java
   branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Forward00d.java
   branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Forward01.java
   branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Forward03.java
   branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Forward03a.java
   branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Forward04.java
   branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Forward04a.java
   branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Forward04b.java
   branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Forward05.java
   branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Forward05a.java
   branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Forward05b.java
   branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Forward06.java
   branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Forward06a.java
   branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Forward06b.java
   branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Forward07.java
   branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Forward07a.java
   branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Forward07b.java
   branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Forward08.java
   branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Forward08a.java
   branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Forward08b.java
   branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Forward09.java
   branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/GetHeaders01.java
   branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/GetInputStream01.java
   branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/GetLocales01.java
   branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/GetLocales02.java
   branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/GetParameter01.java
   branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/GetParameterMap00.java
   branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/GetQueryString01.java
   branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Golden01.java
   branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Include00.java
   branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Include00a.java
   branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Include00d.java
   branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Include01.java
   branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Include02.java
   branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Include02a.java
   branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Include03.java
   branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Include03a.java
   branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Include04.java
   branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Include04a.java
   branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Include04b.java
   branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Include06a.java
   branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Include07.java
   branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Include07a.java
   branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Include07b.java
   branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Include07c.java
   branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Include09.java
   branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Include10.java
   branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Include10a.java
   branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Jndi01.java
   branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Jndi02.java
   branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Lifecycle01.java
   branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Lifecycle02.java
   branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Lifecycle03.java
   branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Redirect01.java
   branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Redirect01a.java
   branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Reflection01.java
   branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Request01.java
   branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/RequestListener01.java
   branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Reset01.java
   branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Resources01.java
   branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Resources01.txt
   branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Resources02.java
   branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Resources03.java
   branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Resources03.txt
   branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Resources04.java
   branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Resources05.java
   branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Resources05.txt
   branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Resources06.java
   branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/ResponseWrap01.java
   branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/ResponseWrap01a.java
   branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/ResponseWrap01c.java
   branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Session01.java
   branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Session02.java
   branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Session03.java
   branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Session04.java
   branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Session05.java
   branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Session06.java
   branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/SessionBean.java
   branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/SessionListener01.java
   branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/SessionListener02.java
   branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/SessionListener03.java
   branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/SetBufferSize01.java
   branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/SetLocale01.java
   branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/StaticFilter.java
   branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/StaticLogger.java
   branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/TestClient.java
   branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/TesterException.java
   branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/TesterHttpServletRequestWrapper.java
   branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/TesterHttpServletResponseWrapper.java
   branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/TesterServletRequestWrapper.java
   branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/TesterServletResponseWrapper.java
   branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/UpperCaseFilter.java
   branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/UpperCaseInputStream.java
   branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/UpperCaseOutputStream.java
   branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/UpperCaseReader.java
   branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/UpperCaseRequest.java
   branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/UpperCaseResponse.java
   branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/UpperCaseWriter.java
   branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/WrapperFilter.java
   branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Xerces01.java
   branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Xerces01Parser.java
   branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/shared/
   branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/shared/SharedSessionBean.java
   branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/unpshared/
   branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/unpshared/UnpSharedSessionBean.java
   branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/unshared/
   branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/unshared/UnsharedSessionBean.java
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/Authentication04.jsp
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/Encoding01.jsp
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/Encoding02.jsp
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/Encoding03.jsp
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/ErrorPage06.html
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/ErrorPage06.jsp
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/ErrorPage08.jsp
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/ErrorPage09.jsp
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/ErrorPage10.jsp
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/FilterResponse02.jsp
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/FilterResponse03.txt
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/Forward00b.jsp
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/Forward00c.jsp
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/Forward00e.jsp
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/Forward01.txt
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/Forward03b.jsp
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/Forward04.jsp
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/Forward04a.jsp
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/Forward04b.jsp
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/Forward05.jsp
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/Forward05a.jsp
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/Forward05b.jsp
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/Forward06.jsp
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/Forward06a.jsp
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/Forward06b.jsp
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/Include00b.jsp
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/Include00c.jsp
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/Include00e.jsp
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/Include01.txt
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/Include03b.jsp
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/Include03c.jsp
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/Include05.jsp
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/Include05a.jsp
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/Include05b.jsp
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/Include06.jsp
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/Include06b.jsp
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/JspBeans01.jsp
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/JspBeans02.jsp
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/JspBeans03.jsp
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/JspDoc01.jsp
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/JspDoc02.jsp
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/JspForward01.jsp
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/JspForward01a.jsp
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/JspInclude01.jsp
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/JspInclude01a.jsp
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/JspInclude02.jsp
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/JspInclude02a.jsp
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/JspParams01.jsp
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/JspParams02.jsp
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/Property01.jsp
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/Property02.jsp
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/Redirect02.jsp
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/Redirect02a.jsp
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/Redirect03.jsp
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/Redirect03a.jsp
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/ResponseWrap01b.jsp
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/ResponseWrap01d.jsp
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/SSIConditional01.shtml
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/SSIConditional02.shtml
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/SSIConditional03.shtml
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/SSIConditional04.shtml
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/SSIConditional05.shtml
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/SSIConditional06.shtml
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/SSIConditional07.shtml
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/SSIConditional08.shtml
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/SSIConfig01.shtml
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/SSIConfig03.shtml
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/SSIExecCGI.shtml
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/SSIExecCmd.shtml
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/SSIFsize01.shtml
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/SSIFsize02.shtml
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/SSIFsize03.shtml
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/SSIFsize04.shtml
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/SSIFsize05.shtml
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/SSIFsize06.shtml
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/SSIFsize07.shtml
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/SSIFsize08.shtml
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/SSIInclude01.shtml
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/SSIInclude02.shtml
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/SSIInclude03.shtml
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/SSIInclude04.shtml
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/SSIInclude05.shtml
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/SSIInclude06.shtml
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/SSIInclude07.shtml
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/SSIInclude08.shtml
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/SSIInclude09.shtml
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/SSIVarSub01.shtml
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/SSIVarSub02.shtml
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/SSIVarSub03.shtml
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/SSIVarSub04.shtml
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/SSIVarSub05.shtml
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/SSIVarSub06.shtml
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/Session07a.jsp
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/Session07b.jsp
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/WEB-INF/
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/WEB-INF/cgi/
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/WEB-INF/cgi/array.pl
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/WEB-INF/cgi/binary.pl
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/WEB-INF/cgi/concat.pl
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/WEB-INF/cgi/days.pl
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/WEB-INF/cgi/dowhile.pl
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/WEB-INF/cgi/else.pl
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/WEB-INF/cgi/elsif.pl
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/WEB-INF/cgi/exponents.pl
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/WEB-INF/cgi/for.pl
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/WEB-INF/cgi/getday.pl
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/WEB-INF/cgi/helloperl.pl
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/WEB-INF/cgi/if.pl
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/WEB-INF/cgi/increment.pl
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/WEB-INF/cgi/modifyall.pl
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/WEB-INF/cgi/preference.pl
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/WEB-INF/cgi/subparseform.lib
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/WEB-INF/cgi/subroutines.lib
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/WEB-INF/cgi/test-cgi.pl
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/WEB-INF/web.xml
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/WrappedFilterResponse02.jsp
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/WrappedFilterResponse03.txt
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/Xerces00.jsp
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/Xerces01.xml
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/Xerces02.jsp
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/Encoding01.txt
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/Encoding02.txt
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/Encoding03.txt
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/Golden01.txt
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/Include06.txt
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/Include07.txt
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/JspDoc01.txt
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/JspDoc02.txt
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/JspInclude01.txt
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/JspInclude01a.txt
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/JspInclude02.txt
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/JspInclude02a.txt
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/Property01.txt
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/SSIConditional01.txt
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/SSIConditional02.txt
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/SSIConditional03.txt
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/SSIConditional04.txt
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/SSIConditional05.txt
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/SSIConditional06.txt
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/SSIConditional07.txt
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/SSIConditional08.txt
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/SSIConfig01.txt
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/SSIConfig03.txt
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/SSIExecCGI.txt
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/SSIFsize02.txt
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/SSIInclude01.txt
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/SSIInclude02.txt
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/SSIInclude03.txt
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/SSIVarSub01.txt
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/SSIVarSub02.txt
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/SSIVarSub03.txt
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/SSIVarSub04.txt
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/SSIVarSub05.txt
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/Session05.txt
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/WrappedSession05.txt
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/array.txt
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/binary.txt
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/concat.txt
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/days.txt
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/dowhile.txt
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/else.txt
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/elsif.txt
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/exponents.txt
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/getday.txt
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/helloperl.txt
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/increment.txt
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/modifyall.txt
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/preference.txt
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/includeme.shtml
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/includeme.txt
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/index.shtml
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/ssidir/
   branches/tomcat5.5/upstream/5.5.20/container/tester/web/ssidir/includeme.txt
   branches/tomcat5.5/upstream/5.5.20/container/webapps/
   branches/tomcat5.5/upstream/5.5.20/container/webapps/ROOT/
   branches/tomcat5.5/upstream/5.5.20/container/webapps/ROOT/WEB-INF/
   branches/tomcat5.5/upstream/5.5.20/container/webapps/ROOT/WEB-INF/web.xml
   branches/tomcat5.5/upstream/5.5.20/container/webapps/ROOT/admin/
   branches/tomcat5.5/upstream/5.5.20/container/webapps/ROOT/admin/index.html
   branches/tomcat5.5/upstream/5.5.20/container/webapps/ROOT/asf-logo-wide.gif
   branches/tomcat5.5/upstream/5.5.20/container/webapps/ROOT/build.xml
   branches/tomcat5.5/upstream/5.5.20/container/webapps/ROOT/favicon.ico
   branches/tomcat5.5/upstream/5.5.20/container/webapps/ROOT/index.jsp
   branches/tomcat5.5/upstream/5.5.20/container/webapps/ROOT/tomcat-power.gif
   branches/tomcat5.5/upstream/5.5.20/container/webapps/ROOT/tomcat.gif
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/ActionTag.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/ActionsTag.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/ApplicationLocales.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/ApplicationResources.properties
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/ApplicationResources_es.properties
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/ApplicationResources_ja.properties
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/ApplicationServlet.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/AttributeTag.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/CommitChangesAction.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/DataTag.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/DumpRegistryAction.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/DumpServerAction.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/LabelTag.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/LabelValueBean.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/Lists.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/LogOutAction.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/RowTag.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/SetLocaleAction.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/SetLocaleForm.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/SetUpTreeAction.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/TableTag.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/TomcatTreeBuilder.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/TreeBuilder.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/TreeControl.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/TreeControlNode.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/TreeControlTag.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/TreeControlTestAction.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/connector/
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/connector/AddConnectorAction.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/connector/ConnectorForm.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/connector/ConnectorsForm.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/connector/DeleteConnectorAction.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/connector/DeleteConnectorsAction.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/connector/EditConnectorAction.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/connector/SaveConnectorAction.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/connector/patch.txt
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/context/
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/context/AddContextAction.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/context/ContextForm.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/context/ContextsForm.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/context/DeleteContextAction.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/context/DeleteContextsAction.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/context/EditContextAction.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/context/SaveContextAction.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/filters/
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/filters/SetCharacterEncodingFilter.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/host/
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/host/AddAliasAction.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/host/AddHostAction.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/host/AliasForm.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/host/AliasesForm.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/host/DeleteAliasAction.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/host/DeleteAliasForm.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/host/DeleteAliasesAction.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/host/DeleteHostAction.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/host/DeleteHostsAction.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/host/EditHostAction.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/host/HostForm.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/host/HostsForm.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/host/SaveAliasAction.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/host/SaveHostAction.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/realm/
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/realm/AddRealmAction.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/realm/DataSourceRealmForm.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/realm/DeleteRealmAction.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/realm/DeleteRealmsAction.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/realm/EditRealmAction.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/realm/JDBCRealmForm.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/realm/JNDIRealmForm.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/realm/MemoryRealmForm.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/realm/RealmForm.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/realm/RealmsForm.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/realm/SaveDataSourceRealmAction.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/realm/SaveJDBCRealmAction.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/realm/SaveJNDIRealmAction.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/realm/SaveMemoryRealmAction.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/realm/SaveUserDatabaseRealmAction.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/realm/UserDatabaseRealmForm.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/resources/
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/resources/BaseForm.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/resources/DataSourceForm.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/resources/DataSourcesForm.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/resources/DeleteDataSourcesAction.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/resources/DeleteEnvEntriesAction.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/resources/DeleteMailSessionsAction.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/resources/DeleteResourceLinksAction.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/resources/DeleteUserDatabasesAction.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/resources/EnvEntriesForm.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/resources/EnvEntryForm.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/resources/ListDataSourcesAction.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/resources/ListEnvEntriesAction.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/resources/ListMailSessionsAction.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/resources/ListResourceLinksAction.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/resources/ListUserDatabasesAction.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/resources/MailSessionForm.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/resources/MailSessionsForm.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/resources/ResourceLinkForm.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/resources/ResourceLinksForm.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/resources/ResourceUtils.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/resources/ResourcesTreeBuilder.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/resources/SaveDataSourceAction.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/resources/SaveEnvEntryAction.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/resources/SaveMailSessionAction.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/resources/SaveResourceLinkAction.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/resources/SaveUserDatabaseAction.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/resources/SetUpDataSourceAction.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/resources/SetUpEnvEntryAction.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/resources/SetUpMailSessionAction.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/resources/SetUpResourceLinkAction.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/resources/SetUpUserDatabaseAction.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/resources/UserDatabaseForm.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/resources/UserDatabasesForm.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/server/
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/server/EditServerAction.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/server/SaveServerAction.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/server/ServerForm.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/service/
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/service/AddServiceAction.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/service/DeleteServiceAction.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/service/DeleteServicesAction.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/service/EditServiceAction.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/service/SaveServiceAction.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/service/ServiceForm.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/service/ServicesForm.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/users/
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/users/BaseForm.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/users/DeleteGroupsAction.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/users/DeleteRolesAction.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/users/DeleteUsersAction.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/users/GroupForm.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/users/GroupsForm.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/users/ListGroupsAction.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/users/ListRolesAction.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/users/ListUsersAction.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/users/RoleForm.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/users/RolesForm.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/users/SaveGroupAction.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/users/SaveRoleAction.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/users/SaveUserAction.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/users/SetUpGroupAction.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/users/SetUpRoleAction.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/users/SetUpUserAction.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/users/UserForm.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/users/UserUtils.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/users/UsersForm.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/users/UsersTreeBuilder.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/valve/
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/valve/AccessLogValveForm.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/valve/AddValveAction.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/valve/DeleteValveAction.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/valve/DeleteValvesAction.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/valve/EditValveAction.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/valve/RemoteAddrValveForm.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/valve/RemoteHostValveForm.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/valve/RequestDumperValveForm.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/valve/SaveAccessLogValveAction.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/valve/SaveRemoteAddrValveAction.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/valve/SaveRemoteHostValveAction.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/valve/SaveRequestDumperValveAction.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/valve/SaveSingleSignOnValveAction.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/valve/SingleSignOnValveForm.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/valve/ValveForm.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/valve/ValveUtil.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/valve/ValvesForm.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/controls.tld
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/struts-config.xml
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/web.xml
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/admin.css
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/admin.xml
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/banner.jsp
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/blank.jsp
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/build.xml
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/buttons.jsp
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/connector/
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/connector/connector.jsp
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/connector/connectors.jsp
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/context/
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/context/context.jsp
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/context/contexts.jsp
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/dumpRegistry.jsp
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/dumpServer.jsp
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/error.jsp
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/footer.jsp
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/frameset.jsp
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/header.jsp
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/host/
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/host/alias.jsp
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/host/aliases.jsp
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/host/host.jsp
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/host/hosts.jsp
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/images/
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/images/BlueTile.gif
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/images/Connector.gif
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/images/Context.gif
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/images/Datasource.gif
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/images/DefaultContext.gif
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/images/EnvironmentEntries.gif
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/images/Groups.gif
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/images/Host.gif
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/images/Logger.gif
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/images/Login.jpg
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/images/LoginBackgroundTile.gif
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/images/Mailsession.gif
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/images/PaperTexture.gif
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/images/Realm.gif
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/images/ResourceLink.gif
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/images/Roles.gif
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/images/Server.gif
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/images/Service.gif
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/images/Thumbs.db
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/images/TomcatBanner.jpg
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/images/Users.gif
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/images/Valve.gif
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/images/folder_16_pad.gif
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/images/handledownlast.gif
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/images/handledownmiddle.gif
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/images/handlerightlast.gif
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/images/handlerightmiddle.gif
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/images/linelastnode.gif
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/images/linemiddlenode.gif
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/images/linevertical.gif
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/index.jsp
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/login.jsp
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/realm/
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/realm/dataSourceRealm.jsp
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/realm/jdbcRealm.jsp
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/realm/jndiRealm.jsp
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/realm/memoryRealm.jsp
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/realm/realms.jsp
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/realm/userDatabaseRealm.jsp
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/resources/
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/resources/dataSource.jsp
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/resources/dataSources.jspf
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/resources/deleteDataSources.jsp
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/resources/deleteEnvEntries.jsp
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/resources/deleteMailSessions.jsp
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/resources/deleteResourceLinks.jsp
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/resources/deleteUserDatabases.jsp
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/resources/envEntries.jspf
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/resources/envEntry.jsp
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/resources/listDataSources.jsp
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/resources/listDataSources.jspf
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/resources/listEnvEntries.jsp
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/resources/listEnvEntries.jspf
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/resources/listMailSessions.jsp
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/resources/listMailSessions.jspf
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/resources/listResourceLinks.jsp
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/resources/listResourceLinks.jspf
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/resources/listUserDatabases.jsp
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/resources/listUserDatabases.jspf
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/resources/mailSession.jsp
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/resources/mailSessions.jspf
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/resources/resourceLink.jsp
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/resources/resourceLinks.jspf
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/resources/userDatabase.jsp
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/resources/userDatabases.jspf
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/saved.jsp
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/savefail.jsp
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/server/
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/server/server.jsp
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/service/
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/service/service.jsp
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/service/services.jsp
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/tree-control-test.css
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/tree-control-test.jsp
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/users/
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/users/deleteGroups.jsp
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/users/deleteRoles.jsp
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/users/deleteUsers.jsp
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/users/footer.jsp
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/users/group.jsp
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/users/groups.jspf
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/users/header.jsp
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/users/listGroups.jsp
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/users/listGroups.jspf
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/users/listRoles.jsp
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/users/listRoles.jspf
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/users/listUsers.jsp
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/users/listUsers.jspf
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/users/role.jsp
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/users/roles.jspf
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/users/user.jsp
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/users/users.jspf
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/valve/
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/valve/accessLogValve.jsp
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/valve/remoteAddrValve.jsp
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/valve/remoteHostValve.jsp
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/valve/requestDumperValve.jsp
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/valve/singleSignOnValve.jsp
   branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/valve/valves.jsp
   branches/tomcat5.5/upstream/5.5.20/container/webapps/balancer/
   branches/tomcat5.5/upstream/5.5.20/container/webapps/balancer/META-INF/
   branches/tomcat5.5/upstream/5.5.20/container/webapps/balancer/META-INF/context.xml
   branches/tomcat5.5/upstream/5.5.20/container/webapps/balancer/WEB-INF/
   branches/tomcat5.5/upstream/5.5.20/container/webapps/balancer/WEB-INF/classes/
   branches/tomcat5.5/upstream/5.5.20/container/webapps/balancer/WEB-INF/classes/org/
   branches/tomcat5.5/upstream/5.5.20/container/webapps/balancer/WEB-INF/classes/org/apache/
   branches/tomcat5.5/upstream/5.5.20/container/webapps/balancer/WEB-INF/classes/org/apache/webapp/
   branches/tomcat5.5/upstream/5.5.20/container/webapps/balancer/WEB-INF/classes/org/apache/webapp/balancer/
   branches/tomcat5.5/upstream/5.5.20/container/webapps/balancer/WEB-INF/classes/org/apache/webapp/balancer/BalancerFilter.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/balancer/WEB-INF/classes/org/apache/webapp/balancer/Rule.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/balancer/WEB-INF/classes/org/apache/webapp/balancer/RuleChain.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/balancer/WEB-INF/classes/org/apache/webapp/balancer/RulesParser.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/balancer/WEB-INF/classes/org/apache/webapp/balancer/overview.html
   branches/tomcat5.5/upstream/5.5.20/container/webapps/balancer/WEB-INF/classes/org/apache/webapp/balancer/package.html
   branches/tomcat5.5/upstream/5.5.20/container/webapps/balancer/WEB-INF/classes/org/apache/webapp/balancer/rules/
   branches/tomcat5.5/upstream/5.5.20/container/webapps/balancer/WEB-INF/classes/org/apache/webapp/balancer/rules/AcceptEverythingRule.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/balancer/WEB-INF/classes/org/apache/webapp/balancer/rules/BaseRule.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/balancer/WEB-INF/classes/org/apache/webapp/balancer/rules/CharacterEncodingRule.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/balancer/WEB-INF/classes/org/apache/webapp/balancer/rules/RemoteAddressRule.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/balancer/WEB-INF/classes/org/apache/webapp/balancer/rules/RequestAttributeRule.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/balancer/WEB-INF/classes/org/apache/webapp/balancer/rules/RequestHeaderRule.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/balancer/WEB-INF/classes/org/apache/webapp/balancer/rules/RequestParameterRule.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/balancer/WEB-INF/classes/org/apache/webapp/balancer/rules/SessionAttributeRule.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/balancer/WEB-INF/classes/org/apache/webapp/balancer/rules/URLStringMatchRule.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/balancer/WEB-INF/classes/org/apache/webapp/balancer/rules/UserRoleRule.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/balancer/WEB-INF/classes/org/apache/webapp/balancer/rules/package.html
   branches/tomcat5.5/upstream/5.5.20/container/webapps/balancer/WEB-INF/config/
   branches/tomcat5.5/upstream/5.5.20/container/webapps/balancer/WEB-INF/config/rules.xml
   branches/tomcat5.5/upstream/5.5.20/container/webapps/balancer/WEB-INF/web.xml
   branches/tomcat5.5/upstream/5.5.20/container/webapps/balancer/build.xml
   branches/tomcat5.5/upstream/5.5.20/container/webapps/build.xml
   branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/
   branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/META-INF/
   branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/META-INF/context.xml
   branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/WEB-INF/
   branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/WEB-INF/web.xml
   branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/appdev/
   branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/appdev/build.xml.txt
   branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/appdev/deployment.xml
   branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/appdev/index.xml
   branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/appdev/installation.xml
   branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/appdev/introduction.xml
   branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/appdev/processes.xml
   branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/appdev/project.xml
   branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/appdev/sample/
   branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/appdev/sample/docs/
   branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/appdev/sample/docs/README.txt
   branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/appdev/sample/index.html
   branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/appdev/sample/sample.war
   branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/appdev/sample/src/
   branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/appdev/sample/src/mypackage/
   branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/appdev/sample/src/mypackage/Hello.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/appdev/sample/web/
   branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/appdev/sample/web/WEB-INF/
   branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/appdev/sample/web/WEB-INF/web.xml
   branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/appdev/sample/web/hello.jsp
   branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/appdev/sample/web/images/
   branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/appdev/sample/web/images/tomcat.gif
   branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/appdev/sample/web/index.html
   branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/appdev/source.xml
   branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/appdev/web.xml.txt
   branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/apr.xml
   branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/architecture/
   branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/architecture/index.xml
   branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/architecture/overview.xml
   branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/architecture/project.xml
   branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/architecture/requestProcess.xml
   branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/architecture/requestProcess/
   branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/architecture/requestProcess/requestProcess.pdf
   branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/architecture/requestProcess/roseModel.mdl
   branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/architecture/startup.xml
   branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/architecture/startup/
   branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/architecture/startup/serverStartup.pdf
   branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/architecture/startup/serverStartup.txt
   branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/balancer-howto.xml
   branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/build.xml
   branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/building.xml
   branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/catalina/
   branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/catalina/docs/
   branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/catalina/docs/api/
   branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/catalina/docs/api/index.html
   branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/cgi-howto.xml
   branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/changelog.xml
   branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/class-loader-howto.xml
   branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/cluster-howto.xml
   branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/config/
   branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/config/ajp.xml
   branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/config/context.xml
   branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/config/engine.xml
   branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/config/globalresources.xml
   branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/config/host.xml
   branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/config/http.xml
   branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/config/index.xml
   branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/config/loader.xml
   branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/config/manager.xml
   branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/config/project.xml
   branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/config/realm.xml
   branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/config/resources.xml
   branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/config/server.xml
   branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/config/service.xml
   branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/config/valve.xml
   branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/connectors.xml
   branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/default-servlet.xml
   branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/deployer-howto.xml
   branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/developers.xml
   branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/funcspecs/
   branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/funcspecs/fs-admin-apps.xml
   branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/funcspecs/fs-admin-objects.xml
   branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/funcspecs/fs-admin-opers.xml
   branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/funcspecs/fs-default.xml
   branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/funcspecs/fs-invoker.xml
   branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/funcspecs/fs-jdbc-realm.xml
   branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/funcspecs/fs-jndi-realm.xml
   branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/funcspecs/fs-memory-realm.xml
   branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/funcspecs/index.xml
   branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/funcspecs/mbean-names.xml
   branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/funcspecs/project.xml
   branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/html-manager-howto.xml
   branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/images/
   branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/images/add.gif
   branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/images/asf-logo.gif
   branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/images/code.gif
   branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/images/design.gif
   branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/images/docs.gif
   branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/images/fix.gif
   branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/images/printer.gif
   branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/images/tomcat.gif
   branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/images/update.gif
   branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/images/void.gif
   branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/index.xml
   branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/introduction.xml
   branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/jasper-howto.xml
   branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/jasper/
   branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/jasper/docs/
   branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/jasper/docs/api/
   branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/jasper/docs/api/index.html
   branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/jndi-datasource-examples-howto.xml
   branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/jndi-resources-howto.xml
   branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/logging.xml
   branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/manager-howto.xml
   branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/mbeans-descriptor-howto.xml
   branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/monitoring.xml
   branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/project.xml
   branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/proxy-howto.xml
   branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/realm-howto.xml
   branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/security-manager-howto.xml
   branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/setup.xml
   branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/ssi-howto.xml
   branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/ssl-howto.xml
   branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/status.xml
   branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/tomcat-docs.xsl
   branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/windows-service-howto.xml
   branches/tomcat5.5/upstream/5.5.20/container/webapps/host-manager/
   branches/tomcat5.5/upstream/5.5.20/container/webapps/host-manager/WEB-INF/
   branches/tomcat5.5/upstream/5.5.20/container/webapps/host-manager/WEB-INF/classes/
   branches/tomcat5.5/upstream/5.5.20/container/webapps/host-manager/WEB-INF/classes/org/
   branches/tomcat5.5/upstream/5.5.20/container/webapps/host-manager/WEB-INF/classes/org/apache/
   branches/tomcat5.5/upstream/5.5.20/container/webapps/host-manager/WEB-INF/classes/org/apache/catalina/
   branches/tomcat5.5/upstream/5.5.20/container/webapps/host-manager/WEB-INF/classes/org/apache/catalina/hostmanager/
   branches/tomcat5.5/upstream/5.5.20/container/webapps/host-manager/WEB-INF/classes/org/apache/catalina/hostmanager/Constants.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/host-manager/WEB-INF/classes/org/apache/catalina/hostmanager/HTMLHostManagerServlet.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/host-manager/WEB-INF/classes/org/apache/catalina/hostmanager/HostManagerServlet.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/host-manager/WEB-INF/classes/org/apache/catalina/hostmanager/LocalStrings.properties
   branches/tomcat5.5/upstream/5.5.20/container/webapps/host-manager/WEB-INF/web.xml
   branches/tomcat5.5/upstream/5.5.20/container/webapps/host-manager/build.xml
   branches/tomcat5.5/upstream/5.5.20/container/webapps/host-manager/host-manager.xml
   branches/tomcat5.5/upstream/5.5.20/container/webapps/host-manager/manager.xml
   branches/tomcat5.5/upstream/5.5.20/container/webapps/jmxremote/
   branches/tomcat5.5/upstream/5.5.20/container/webapps/jmxremote/README
   branches/tomcat5.5/upstream/5.5.20/container/webapps/jmxremote/WEB-INF/
   branches/tomcat5.5/upstream/5.5.20/container/webapps/jmxremote/WEB-INF/src/
   branches/tomcat5.5/upstream/5.5.20/container/webapps/jmxremote/WEB-INF/src/org/
   branches/tomcat5.5/upstream/5.5.20/container/webapps/jmxremote/WEB-INF/src/org/apache/
   branches/tomcat5.5/upstream/5.5.20/container/webapps/jmxremote/WEB-INF/src/org/apache/tomcat/
   branches/tomcat5.5/upstream/5.5.20/container/webapps/jmxremote/WEB-INF/src/org/apache/tomcat/servlets/
   branches/tomcat5.5/upstream/5.5.20/container/webapps/jmxremote/WEB-INF/src/org/apache/tomcat/servlets/jmxremote/
   branches/tomcat5.5/upstream/5.5.20/container/webapps/jmxremote/WEB-INF/src/org/apache/tomcat/servlets/jmxremote/JmxRemoteServlet.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/jmxremote/WEB-INF/web.xml
   branches/tomcat5.5/upstream/5.5.20/container/webapps/jmxremote/build.xml
   branches/tomcat5.5/upstream/5.5.20/container/webapps/manager/
   branches/tomcat5.5/upstream/5.5.20/container/webapps/manager/WEB-INF/
   branches/tomcat5.5/upstream/5.5.20/container/webapps/manager/WEB-INF/classes/
   branches/tomcat5.5/upstream/5.5.20/container/webapps/manager/WEB-INF/classes/org/
   branches/tomcat5.5/upstream/5.5.20/container/webapps/manager/WEB-INF/classes/org/apache/
   branches/tomcat5.5/upstream/5.5.20/container/webapps/manager/WEB-INF/classes/org/apache/catalina/
   branches/tomcat5.5/upstream/5.5.20/container/webapps/manager/WEB-INF/classes/org/apache/catalina/manager/
   branches/tomcat5.5/upstream/5.5.20/container/webapps/manager/WEB-INF/classes/org/apache/catalina/manager/Constants.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/manager/WEB-INF/classes/org/apache/catalina/manager/HTMLManagerServlet.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/manager/WEB-INF/classes/org/apache/catalina/manager/JMXProxyServlet.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/manager/WEB-INF/classes/org/apache/catalina/manager/LocalStrings.properties
   branches/tomcat5.5/upstream/5.5.20/container/webapps/manager/WEB-INF/classes/org/apache/catalina/manager/LocalStrings_de.properties
   branches/tomcat5.5/upstream/5.5.20/container/webapps/manager/WEB-INF/classes/org/apache/catalina/manager/LocalStrings_es.properties
   branches/tomcat5.5/upstream/5.5.20/container/webapps/manager/WEB-INF/classes/org/apache/catalina/manager/LocalStrings_fr.properties
   branches/tomcat5.5/upstream/5.5.20/container/webapps/manager/WEB-INF/classes/org/apache/catalina/manager/LocalStrings_ja.properties
   branches/tomcat5.5/upstream/5.5.20/container/webapps/manager/WEB-INF/classes/org/apache/catalina/manager/ManagerServlet.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/manager/WEB-INF/classes/org/apache/catalina/manager/ManagerServlet.java.orig
   branches/tomcat5.5/upstream/5.5.20/container/webapps/manager/WEB-INF/classes/org/apache/catalina/manager/StatusManagerServlet.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/manager/WEB-INF/classes/org/apache/catalina/manager/StatusTransformer.java
   branches/tomcat5.5/upstream/5.5.20/container/webapps/manager/WEB-INF/web.xml
   branches/tomcat5.5/upstream/5.5.20/container/webapps/manager/build.xml
   branches/tomcat5.5/upstream/5.5.20/container/webapps/manager/manager.xml
   branches/tomcat5.5/upstream/5.5.20/container/webapps/manager/status.xsd
   branches/tomcat5.5/upstream/5.5.20/container/webapps/manager/xform.xsl
   branches/tomcat5.5/upstream/5.5.20/container/webapps/webdav/
   branches/tomcat5.5/upstream/5.5.20/container/webapps/webdav/WEB-INF/
   branches/tomcat5.5/upstream/5.5.20/container/webapps/webdav/WEB-INF/web.xml
   branches/tomcat5.5/upstream/5.5.20/container/webapps/webdav/build.xml
   branches/tomcat5.5/upstream/5.5.20/container/webapps/webdav/index.html
   branches/tomcat5.5/upstream/5.5.20/container/webapps/webdav/tomcat-power.gif
   branches/tomcat5.5/upstream/5.5.20/container/webapps/webdav/tomcat.gif
   branches/tomcat5.5/upstream/5.5.20/jasper/
   branches/tomcat5.5/upstream/5.5.20/jasper/.classpath
   branches/tomcat5.5/upstream/5.5.20/jasper/.project
   branches/tomcat5.5/upstream/5.5.20/jasper/BUILDING.txt
   branches/tomcat5.5/upstream/5.5.20/jasper/LICENSE
   branches/tomcat5.5/upstream/5.5.20/jasper/README.txt
   branches/tomcat5.5/upstream/5.5.20/jasper/build.properties.sample
   branches/tomcat5.5/upstream/5.5.20/jasper/build.xml
   branches/tomcat5.5/upstream/5.5.20/jasper/doc/
   branches/tomcat5.5/upstream/5.5.20/jasper/doc/jspc.html
   branches/tomcat5.5/upstream/5.5.20/jasper/src/
   branches/tomcat5.5/upstream/5.5.20/jasper/src/bin/
   branches/tomcat5.5/upstream/5.5.20/jasper/src/bin/jasper.bat
   branches/tomcat5.5/upstream/5.5.20/jasper/src/bin/jasper.sh
   branches/tomcat5.5/upstream/5.5.20/jasper/src/bin/jasper.xml
   branches/tomcat5.5/upstream/5.5.20/jasper/src/bin/jspc-using-launcher.bat
   branches/tomcat5.5/upstream/5.5.20/jasper/src/bin/jspc-using-launcher.sh
   branches/tomcat5.5/upstream/5.5.20/jasper/src/bin/jspc.bat
   branches/tomcat5.5/upstream/5.5.20/jasper/src/bin/jspc.sh
   branches/tomcat5.5/upstream/5.5.20/jasper/src/share/
   branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/
   branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/
   branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/
   branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/Constants.java
   branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/EmbeddedServletOptions.java
   branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/JasperException.java
   branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/JspC.java
   branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/JspCompilationContext.java
   branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/Options.java
   branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/
   branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/AntCompiler.java
   branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/BeanRepository.java
   branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/Collector.java
   branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/Compiler.java
   branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/DefaultErrorHandler.java
   branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/Dumper.java
   branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/ELFunctionMapper.java
   branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/ELNode.java
   branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/ELParser.java
   branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/ErrorDispatcher.java
   branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/ErrorHandler.java
   branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/Generator.java
   branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/ImplicitTagLibraryInfo.java
   branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/JDTCompiler.java
   branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/JasperTagInfo.java
   branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/JavacErrorDetail.java
   branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/JspConfig.java
   branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/JspDocumentParser.java
   branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/JspReader.java
   branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/JspRuntimeContext.java
   branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/JspUtil.java
   branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/Localizer.java
   branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/Mark.java
   branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/Node.java
   branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/PageDataImpl.java
   branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/PageInfo.java
   branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/Parser.java
   branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/ParserController.java
   branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/ScriptingVariabler.java
   branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/ServletWriter.java
   branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/SmapGenerator.java
   branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/SmapStratum.java
   branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/SmapUtil.java
   branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/TagConstants.java
   branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/TagFileProcessor.java
   branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/TagLibraryInfoImpl.java
   branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/TagPluginManager.java
   branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/TextOptimizer.java
   branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/TldLocationsCache.java
   branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/Validator.java
   branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/tagplugin/
   branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/tagplugin/TagPlugin.java
   branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/tagplugin/TagPluginContext.java
   branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/resources/
   branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/resources/LocalStrings.properties
   branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/resources/LocalStrings_es.properties
   branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/resources/LocalStrings_fr.properties
   branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/resources/LocalStrings_ja.properties
   branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/runtime/
   branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/runtime/BodyContentImpl.java
   branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/runtime/HttpJspBase.java
   branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/runtime/JspContextWrapper.java
   branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/runtime/JspFactoryImpl.java
   branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/runtime/JspFragmentHelper.java
   branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/runtime/JspRuntimeLibrary.java
   branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/runtime/JspSourceDependent.java
   branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/runtime/JspWriterImpl.java
   branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/runtime/PageContextImpl.java
   branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/runtime/PerThreadTagHandlerPool.java
   branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/runtime/ProtectedFunctionMapper.java
   branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/runtime/ServletResponseWrapperInclude.java
   branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/runtime/TagHandlerPool.java
   branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/security/
   branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/security/SecurityClassLoad.java
   branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/security/SecurityUtil.java
   branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/servlet/
   branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/servlet/JasperLoader.java
   branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/servlet/JspCServletContext.java
   branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/servlet/JspServlet.java
   branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/servlet/JspServletWrapper.java
   branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/servlet/mbeans-descriptors.xml
   branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/tagplugins/
   branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/tagplugins/jstl/
   branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/tagplugins/jstl/Util.java
   branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/tagplugins/jstl/core/
   branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/tagplugins/jstl/core/Catch.java
   branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/tagplugins/jstl/core/Choose.java
   branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/tagplugins/jstl/core/ForEach.java
   branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/tagplugins/jstl/core/ForTokens.java
   branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/tagplugins/jstl/core/If.java
   branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/tagplugins/jstl/core/Import.java
   branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/tagplugins/jstl/core/Otherwise.java
   branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/tagplugins/jstl/core/Out.java
   branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/tagplugins/jstl/core/Param.java
   branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/tagplugins/jstl/core/Redirect.java
   branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/tagplugins/jstl/core/Remove.java
   branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/tagplugins/jstl/core/Set.java
   branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/tagplugins/jstl/core/Url.java
   branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/tagplugins/jstl/core/When.java
   branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/tagplugins/jstl/tagPlugins.xml
   branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/util/
   branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/util/FastDateFormat.java
   branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/util/Queue.java
   branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/util/SimplePool.java
   branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/util/SystemLogHandler.java
   branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/xmlparser/
   branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/xmlparser/ASCIIReader.java
   branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/xmlparser/EncodingMap.java
   branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/xmlparser/ParserUtils.java
   branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/xmlparser/SymbolTable.java
   branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/xmlparser/TreeNode.java
   branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/xmlparser/UCSReader.java
   branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/xmlparser/UTF8Reader.java
   branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/xmlparser/XMLChar.java
   branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/xmlparser/XMLEncodingDetector.java
   branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/xmlparser/XMLString.java
   branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/xmlparser/XMLStringBuffer.java
   branches/tomcat5.5/upstream/5.5.20/servletapi/
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/BUILDING.txt
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/LICENSE
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/README.txt
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/build.xml
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/cal/
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/cal/Entries.java
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/cal/Entry.java
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/cal/JspCalendar.java
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/cal/TableBean.java
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/checkbox/
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/checkbox/CheckTest.java
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/colors/
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/colors/ColorGameBean.java
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/compressionFilters/
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/compressionFilters/CompressionFilter.java
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/compressionFilters/CompressionFilterTestServlet.java
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/compressionFilters/CompressionResponseStream.java
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/compressionFilters/CompressionServletResponseWrapper.java
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/dates/
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/dates/JspCalendar.java
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/error/
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/error/Smart.java
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/examples/
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/examples/ExampleTagBase.java
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/examples/FooTag.java
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/examples/FooTagExtraInfo.java
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/examples/LogTag.java
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/examples/ShowSource.java
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/filters/
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/filters/ExampleFilter.java
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/filters/RequestDumperFilter.java
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/filters/SetCharacterEncodingFilter.java
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/jsp2/
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/jsp2/examples/
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/jsp2/examples/BookBean.java
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/jsp2/examples/FooBean.java
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/jsp2/examples/el/
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/jsp2/examples/el/Functions.java
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/jsp2/examples/simpletag/
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/jsp2/examples/simpletag/EchoAttributesTag.java
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/jsp2/examples/simpletag/FindBookSimpleTag.java
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/jsp2/examples/simpletag/HelloWorldSimpleTag.java
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/jsp2/examples/simpletag/RepeatSimpleTag.java
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/jsp2/examples/simpletag/ShuffleSimpleTag.java
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/jsp2/examples/simpletag/TileSimpleTag.java
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/listeners/
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/listeners/ContextListener.java
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/listeners/SessionListener.java
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/num/
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/num/NumberGuessBean.java
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/servletToJsp.java
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/sessions/
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/sessions/DummyCart.java
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/util/
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/util/HTMLFilter.java
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/validators/
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/validators/DebugValidator.java
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/jsp/
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/jsp/applet/
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/jsp/applet/Clock2.java
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/jsp/debug-taglib.tld
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/jsp/example-taglib.tld
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/jsp2/
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/jsp2/jsp2-example-taglib.tld
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/lib/
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/lib/jstl.jar
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/lib/standard.jar
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/tags/
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/tags/displayProducts.tag
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/tags/helloWorld.tag
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/tags/panel.tag
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/tags/xhtmlbasic.tag
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/web.xml
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/cal/
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/cal/cal1.jsp
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/cal/cal2.jsp
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/cal/calendar.html
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/cal/login.html
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/checkbox/
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/checkbox/CheckTest.html
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/checkbox/check.html
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/checkbox/checkresult.jsp
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/checkbox/cresult.html
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/colors/
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/colors/ColorGameBean.html
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/colors/clr.html
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/colors/colors.html
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/colors/colrs.jsp
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/dates/
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/dates/date.html
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/dates/date.jsp
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/error/
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/error/er.html
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/error/err.jsp
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/error/error.html
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/error/errorpge.jsp
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/forward/
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/forward/forward.jsp
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/forward/fwd.html
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/forward/one.jsp
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/forward/two.html
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/images/
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/images/code.gif
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/images/execute.gif
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/images/read.gif
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/images/return.gif
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/include/
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/include/foo.html
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/include/foo.jsp
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/include/inc.html
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/include/include.jsp
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/index.html
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/el/
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/el/basic-arithmetic.html
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/el/basic-arithmetic.jsp
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/el/basic-comparisons.html
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/el/basic-comparisons.jsp
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/el/functions.html
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/el/functions.jsp
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/el/implicit-objects.html
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/el/implicit-objects.jsp
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/jspattribute/
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/jspattribute/jspattribute.html
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/jspattribute/jspattribute.jsp
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/jspattribute/shuffle.html
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/jspattribute/shuffle.jsp
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/jspx/
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/jspx/basic.html
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/jspx/basic.jspx
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/jspx/svgexample.html
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/jspx/textRotate.html
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/jspx/textRotate.jpg
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/jspx/textRotate.jspx
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/misc/
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/misc/coda.jspf
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/misc/config.html
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/misc/config.jsp
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/misc/dynamicattrs.html
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/misc/dynamicattrs.jsp
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/misc/prelude.jspf
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/simpletag/
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/simpletag/book.html
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/simpletag/book.jsp
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/simpletag/hello.html
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/simpletag/hello.jsp
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/simpletag/repeat.html
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/simpletag/repeat.jsp
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/tagfiles/
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/tagfiles/hello.html
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/tagfiles/hello.jsp
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/tagfiles/panel.html
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/tagfiles/panel.jsp
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/tagfiles/products.html
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/tagfiles/products.jsp
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsptoserv/
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsptoserv/hello.jsp
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsptoserv/jsptoservlet.jsp
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsptoserv/jts.html
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/num/
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/num/numguess.html
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/num/numguess.jsp
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/plugin/
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/plugin/applet/
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/plugin/applet/Clock2.java
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/plugin/plugin.html
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/plugin/plugin.jsp
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/security/
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/security/protected/
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/security/protected/error.jsp
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/security/protected/index.jsp
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/security/protected/login.jsp
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/sessions/
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/sessions/DummyCart.html
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/sessions/carts.html
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/sessions/carts.jsp
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/sessions/crt.html
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/simpletag/
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/simpletag/foo.html
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/simpletag/foo.jsp
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/snp/
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/snp/snoop.html
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/snp/snoop.jsp
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/source.jsp
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/tagplugin/
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/tagplugin/choose.html
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/tagplugin/choose.jsp
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/tagplugin/foreach.html
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/tagplugin/foreach.jsp
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/tagplugin/howto.html
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/tagplugin/if.html
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/tagplugin/if.jsp
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/tagplugin/notes.html
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/xml/
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/xml/xml.html
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/xml/xml.jsp
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/ant/
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/ant/task/
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/ant/task/Txt2Html.java
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/etc/
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/etc/manifest
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/dtd/
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/dtd/jsp_2_0.xsd
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/dtd/jspxml.dtd
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/dtd/jspxml.xsd
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/dtd/web-jsptaglibrary_1_1.dtd
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/dtd/web-jsptaglibrary_1_2.dtd
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/dtd/web-jsptaglibrary_2_0.xsd
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/ErrorData.java
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/HttpJspPage.java
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/JspContext.java
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/JspEngineInfo.java
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/JspException.java
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/JspFactory.java
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/JspPage.java
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/JspTagException.java
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/JspWriter.java
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/PageContext.java
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/SkipPageException.java
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/el/
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/el/ELException.java
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/el/ELParseException.java
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/el/Expression.java
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/el/ExpressionEvaluator.java
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/el/FunctionMapper.java
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/el/VariableResolver.java
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/el/package.html
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/package.html
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/tagext/
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/tagext/BodyContent.java
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/tagext/BodyTag.java
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/tagext/BodyTagSupport.java
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/tagext/DynamicAttributes.java
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/tagext/FunctionInfo.java
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/tagext/IterationTag.java
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/tagext/JspFragment.java
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/tagext/JspTag.java
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/tagext/PageData.java
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/tagext/SimpleTag.java
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/tagext/SimpleTagSupport.java
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/tagext/Tag.java
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/tagext/TagAdapter.java
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/tagext/TagAttributeInfo.java
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/tagext/TagData.java
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/tagext/TagExtraInfo.java
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/tagext/TagFileInfo.java
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/tagext/TagInfo.java
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/tagext/TagLibraryInfo.java
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/tagext/TagLibraryValidator.java
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/tagext/TagSupport.java
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/tagext/TagVariableInfo.java
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/tagext/TryCatchFinally.java
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/tagext/ValidationMessage.java
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/tagext/VariableInfo.java
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/tagext/doc-files/
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/tagext/doc-files/BodyTagProtocol.gif
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/tagext/doc-files/IterationTagProtocol.gif
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/tagext/doc-files/TagProtocol.gif
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/tagext/doc-files/VariableInfo-1.gif
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/tagext/package.html
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/BUILDING.txt
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/LICENSE
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/README.txt
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/build.xml
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/examples/
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/examples/WEB-INF/
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/examples/WEB-INF/classes/
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/examples/WEB-INF/classes/CookieExample.java
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/examples/WEB-INF/classes/HelloWorldExample.java
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/examples/WEB-INF/classes/LocalStrings.properties
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/examples/WEB-INF/classes/LocalStrings_en.properties
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/examples/WEB-INF/classes/LocalStrings_es.properties
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/examples/WEB-INF/classes/LocalStrings_fr.properties
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/examples/WEB-INF/classes/LocalStrings_pt.properties
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/examples/WEB-INF/classes/RequestHeaderExample.java
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/examples/WEB-INF/classes/RequestInfoExample.java
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/examples/WEB-INF/classes/RequestParamExample.java
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/examples/WEB-INF/classes/SessionExample.java
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/examples/WEB-INF/classes/compressionFilters/
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/examples/WEB-INF/classes/compressionFilters/CompressionFilter.java
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/examples/WEB-INF/classes/compressionFilters/CompressionFilterTestServlet.java
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/examples/WEB-INF/classes/compressionFilters/CompressionResponseStream.java
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/examples/WEB-INF/classes/compressionFilters/CompressionServletResponseWrapper.java
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/examples/WEB-INF/classes/filters/
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/examples/WEB-INF/classes/filters/ExampleFilter.java
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/examples/WEB-INF/classes/filters/RequestDumperFilter.java
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/examples/WEB-INF/classes/filters/SetCharacterEncodingFilter.java
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/examples/WEB-INF/classes/listeners/
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/examples/WEB-INF/classes/listeners/ContextListener.java
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/examples/WEB-INF/classes/listeners/SessionListener.java
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/examples/WEB-INF/classes/util/
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/examples/WEB-INF/classes/util/HTMLFilter.java
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/examples/WEB-INF/web.xml
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/examples/cookies.html
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/examples/helloworld.html
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/examples/images/
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/examples/images/code.gif
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/examples/images/execute.gif
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/examples/images/return.gif
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/examples/index.html
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/examples/reqheaders.html
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/examples/reqinfo.html
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/examples/reqparams.html
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/examples/sessions.html
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/etc/
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/etc/manifest
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/dtd/
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/dtd/XMLSchema.dtd
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/dtd/datatypes.dtd
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/dtd/j2ee_1_4.xsd
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/dtd/j2ee_web_services_1_1.xsd
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/dtd/j2ee_web_services_client_1_1.xsd
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/dtd/jsp_2_0.xsd
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/dtd/jspxml.dtd
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/dtd/jspxml.xsd
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/dtd/web-app_2_2.dtd
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/dtd/web-app_2_3.dtd
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/dtd/web-app_2_4.xsd
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/dtd/web-jsptaglibrary_1_1.dtd
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/dtd/web-jsptaglibrary_1_2.dtd
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/dtd/web-jsptaglibrary_2_0.xsd
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/dtd/xml.xsd
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/Filter.java
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/FilterChain.java
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/FilterConfig.java
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/GenericServlet.java
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/LocalStrings.properties
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/LocalStrings_fr.properties
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/LocalStrings_ja.properties
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/RequestDispatcher.java
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/Servlet.java
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/ServletConfig.java
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/ServletContext.java
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/ServletContextAttributeEvent.java
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/ServletContextAttributeListener.java
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/ServletContextEvent.java
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/ServletContextListener.java
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/ServletException.java
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/ServletInputStream.java
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/ServletOutputStream.java
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/ServletRequest.java
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/ServletRequestAttributeEvent.java
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/ServletRequestAttributeListener.java
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/ServletRequestEvent.java
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/ServletRequestListener.java
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/ServletRequestWrapper.java
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/ServletResponse.java
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/ServletResponseWrapper.java
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/SingleThreadModel.java
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/UnavailableException.java
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/http/
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/http/Cookie.java
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/http/HttpServlet.java
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/http/HttpServletRequest.java
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/http/HttpServletRequestWrapper.java
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/http/HttpServletResponse.java
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/http/HttpServletResponseWrapper.java
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/http/HttpSession.java
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/http/HttpSessionActivationListener.java
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/http/HttpSessionAttributeListener.java
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/http/HttpSessionBindingEvent.java
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/http/HttpSessionBindingListener.java
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/http/HttpSessionContext.java
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/http/HttpSessionEvent.java
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/http/HttpSessionListener.java
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/http/HttpUtils.java
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/http/LocalStrings.properties
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/http/LocalStrings_es.properties
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/http/LocalStrings_fr.properties
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/http/LocalStrings_ja.properties
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/http/package.html
   branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/package.html
Log:
Import upstream sources.

Added: branches/tomcat5.5/upstream/5.5.20/build/.classpath
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/build/.classpath	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/build/.classpath	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+	<classpathentry kind="src" path="resources"/>
+	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
+	<classpathentry kind="output" path="bin"/>
+</classpath>

Added: branches/tomcat5.5/upstream/5.5.20/build/.project
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/build/.project	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/build/.project	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>build</name>
+	<comment></comment>
+	<projects>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>org.eclipse.jdt.core.javabuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>org.eclipse.jdt.core.javanature</nature>
+	</natures>
+</projectDescription>

Added: branches/tomcat5.5/upstream/5.5.20/build/BENCHMARKS.txt
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/build/BENCHMARKS.txt	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/build/BENCHMARKS.txt	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,38 @@
+
+Benchmarking Tomcat
+-------------------
+
+Tomcat benchmarks are more than welcome, and people who are interested are
+encouraged to post results.
+
+This guide is designed to be a FAQ on how to configure Tomcat for maximum
+performance.
+
+- Please upgrade to the latest available version of the Tomcat branch you
+  would like to benchmark. Small incremental performance improvements are often
+  made in each release.
+
+- Use the most recent JDK available whenever possible. Usually, results are
+  dependent on the JDK, so results obtained with different JDK should not be
+  compared directly.
+
+- When benchmarking Jasper, set it in production mode. To do that, add a
+  "development" init parameter (with value set to "false") in the Jasper
+  section of $CATALINA_HOME/conf/web.xml. This increases maximum throughtput
+  of JSPs by about 20%, as well as removing a synchronization point.
+
+- When benchmarking a web application which creates sessions on each request,
+  be careful about not exhausting memory by having too many active sessions. If
+  a max number of sessions is set in the manager to avoid memory problems, this
+  will lead to requests failing when session creation is denied. To avoid that,
+  either limit the total number of requests, or increase the JVM memory.
+
+- Do not enable access logging (unless that is required by the benchmark), 
+  or any debug log.
+
+- Please post the benchmark web application used along with the results, so
+  that people may attempt to reproduce the results.
+
+- Definition of a standard webapp workload may be desirable, and contibutors
+  interested in doing that are welcome to discuss it on the Tomcat developer
+  mailing list.

Added: branches/tomcat5.5/upstream/5.5.20/build/BUILDING.txt
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/build/BUILDING.txt	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/build/BUILDING.txt	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,135 @@
+$Id: BUILDING.txt 432252 2006-08-17 14:41:02Z jfclere $
+
+                 =============================================
+                 Building The Tomcat 5.5 Servlet/JSP Container
+                 =============================================
+
+This subproject contains the source code for Tomcat 5.5, a container that
+implements the Servlet 2.4 and JSP 2.0 specifications from the Java
+Community Process <http://www.jcp.org/>.  In order to build a binary
+distribution version of the container from a source distribution, 
+do the following:
+
+
+(0) Download and Install a Java Development Kit
+
+* If the JDK is already installed, skip to (1).
+
+* Download a Java Development Kit (JDK) release (version 1.4.x or later) from:
+
+    http://java.sun.com/j2se/
+
+* Install the JDK according to the instructions included with the release.
+
+* Set an environment variable JAVA_HOME to the pathname of the directory
+  into which you installed the JDK release.
+
+
+(1) Install Apache Ant 1.5.x on your computer
+
+* If Apache Ant 1.5.x is already installed on your computer, skip to (2).
+
+* Download a binary distribution of Ant 1.5.x from:
+
+    http://ant.apache.org/bindownload.cgi
+
+* Unpack the binary distribution into a convenient location so that the
+  Ant release resides in its own directory (conventionally named
+  "apache-ant-[version]").  For the purposes of the remainder of this document,
+  the symbolic name "${ant.home}" is used to refer to the full pathname of
+  the release directory.
+
+* Create an ANT_HOME environment variable to point the directory
+  ${ant.home}.
+
+* Modify the PATH environment variable to include the directory
+  ${ant.home}/bin in its list.  This makes the "ant" command line script
+  available, which will be used to actually perform the build.
+
+
+(2) Building Tomcat 5.5
+
+(2.1) Download main build script and build binary distribution
+
+* Download the main build.xml script from:
+  http://tomcat.apache.org/tomcat-5.5-doc/build.xml
+
+* Create a new directory, and copy the newly download build.xml to it. This
+  directory will be referred to as the ${tomcat.source} directory in the rest
+  of this document
+
+(2.2) Building
+
+* Go to that directory, and do:
+
+    cd ${tomcat.source}
+    ant
+
+* NOTE: Users accessing the Internet through a proxy must use a properties
+  file to indicate to Ant the proxy configuration. Read below.
+
+* WARNING: Running this command will checkout the Tomcat 5 sources from the Apache
+  source code repository, as
+  well as download binaries to the /usr/share/java directory. Make sure this is
+  appropriate to do on your computer. On Windows, this usually corresponds
+  to the "C:\usr\share\java" directory, unless Cygwin is used. Read below to 
+  customize the directory used to download the binaries.
+
+* The build can be controlled by creating a ${tomcat.source}/build.properties
+  file, and adding the following content to it:
+
+    # ----- Proxy setup -----
+    # Uncomment if using a proxy server
+    #proxy.host=proxy.domain
+    #proxy.port=8080
+    #proxy.use=on
+
+    # ----- Default Base Path for Dependent Packages -----
+    # Replace this path with the directory path where dependencies binaries
+    # should be downloaded
+    base.path=/usr/share/java
+
+
+(3) Updating sources
+
+It is recommended that you regularly update the downloaded Tomcat 5 sources. 
+To do this, execute the following commands:
+
+    cd ${tomcat.source}
+    ant checkout
+
+
+(4) Rebuilds
+
+For a quick rebuild of only modified code you can use 
+   
+    cd ${tomcat.source}
+    ant build
+
+In addition, "ant build-depends" will build packages that 
+tomcat depends on ( commons-logging for now ), to ease fixes
+and debuging in those packages.
+
+(5) Building The "compat" Package
+
+Tomcat 5.5 is designed to run on J2SE 5.0, but will run on
+J2SE versions 1.3 and 1.4 as well as long as the compatability
+package is placed in the server classpath.  See "RUNNING.txt"
+in this directory for running instructions.  To build the
+compat package, do
+
+    cd ${tomcat.source}
+    ant build-compat
+
+(6) Building the servlet and jsp API documentation
+
+The documentation can be easly rebuild, do
+    cd ${tomcat.source}/build
+    ant dist-javadoc
+
+(7) Building a release running tests:
+
+do
+    cd ${tomcat.source}/build
+    ant release
+

Added: branches/tomcat5.5/upstream/5.5.20/build/KEYS
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/build/KEYS	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/build/KEYS	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,331 @@
+This file contains the PGP&GPG keys of various Apache developers.
+Please don't use them for email unless you have to. Their main
+purpose is code signing.
+
+Apache users: pgp < KEYS
+Apache developers: 
+        (pgpk -ll <your name> && pgpk -xa <your name>) >> this file.
+      or
+        (gpg --fingerprint --list-sigs <your name>
+             && gpg --armor --export <your name>) >> this file.
+
+Apache developers: please ensure that your key is also available via the
+PGP keyservers (such as pgpkeys.mit.edu).
+
+
+Type Bits/KeyID    Date       User ID
+pub  2048/F22C4FED 2001/07/02 Andy Armstrong <andy at tagish.com>
+
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: PGPfreeware 7.0.3 for non-commercial use <http://www.pgp.com>
+
+mQGiBDtAWuURBADZ0KUEyUkSUiTA09e7tvEbX25STsjxrR+DNTainCls+XlkVOij
+gBv216lqge9tIsS0L6hCP4OQbFf/64qVtJssX4QXdyiZGb5wpmcj0Mz602Ew8r+N
+I0S5NvmogoYWW7BlP4r61jNxO5zrr03KaijM5r4ipJdLUxyOmM6P2jRPUwCg/5gm
+bpqiYl7pXX5FgDeB36tmD+UD/06iLqOnoiKO0vMbOk7URclhCObMNrHqxTxozMTS
+B9soYURbIeArei+plYo2n+1qB12ayybjhVu3uksXRdT9bEkyxMfslvLbIpDAG8Cz
+gNftTbKx/MVS7cQU0II8BKo2Akr+1FZah+sD4ovK8SfkMXUQUbTeefTntsAQKyyU
+9M9tA/9on9tBiHFl0qVJht6N4GiJ2G689v7rS2giLgKjetjiCduxBXEgvUSuyQID
+nF9ATrpXjITwsRlGKFmpZiFm5oCeCXihIVH0u6q066xNW2AXkLVoJ1l1Rs2Z0lsb
+0cq3xEAcwAmYLKQvCtgDV8CYgWKVmPi+49rSuQn7Lo9l02OUbLQgQW5keSBBcm1z
+dHJvbmcgPGFuZHlAdGFnaXNoLmNvbT6JAFgEEBECABgFAjtAWuUICwMJCAcCAQoC
+GQEFGwMAAAAACgkQajrT9PIsT+1plgCfXAovWnVL3MjrTfcGlFSKw7GHCSYAoJkz
+x+r2ANe8/0e+u5ZcYtSaSry+uQINBDtAWuUQCAD2Qle3CH8IF3KiutapQvMF6PlT
+ETlPtvFuuUs4INoBp1ajFOmPQFXz0AfGy0OplK33TGSGSfgMg71l6RfUodNQ+PVZ
+X9x2Uk89PY3bzpnhV5JZzf24rnRPxfx2vIPFRzBhznzJZv8V+bv9kV7HAarTW56N
+oKVyOtQa8L9GAFgr5fSI/VhOSdvNILSd5JEHNmszbDgNRR0PfIizHHxbLY7288kj
+wEPwpVsYjY67VYy4XTjTNP18F1dDox0YbN4zISy1Kv884bEpQBgRjXyEpwpy1obE
+AxnIByl6ypUM2Zafq9AKUJsCRtMIPWakXUGfnHy9iUsiGSa6q6Jew1XpMgs7AAIC
+B/0eHkYQ0Rv6s21TgpOzRBon+rQAv9ka0PlC7bj2eYWsCOBib8K7qO8hND0sW59p
+0uFQ01X7kC7L/4Ls1HTk0chEZMV0UrGAOKXHY1QFlxrNtFi5U3pTPITXDDfy+g/G
+6FTX3PLnGGvwXbtaiAq5UjQ6iXm03lh0BW6Q+kPtm8swPPfqfjYv0rrT+I8Ic3p2
+HplWKR2bpi3wqCSKB/AaTQJwTbh2x2+2cPVONPodgjZSJ9eQkErejkNSvqbumlTx
+dB81eoGa0Lo2xE7N+DNlCnILGE0X4hPMdj+N5fmyEbyx0WOB8crvCuODGGEQnXs/
+zbVO7FP+rj7YWjRh5pVD3bGiiQBMBBgRAgAMBQI7QFrlBRsMAAAAAAoJEGo60/Ty
+LE/tj/QAoOFNFa7rbAy+eT6mRNb7XztfcAbWAKD6Gd6S/7lEJU0k2TS5tozt4jMl
+vw==
+=/91Q
+-----END PGP PUBLIC KEY BLOCK-----
+
+Type Bits/KeyID    Date       User ID
+pub  1024D/86867BA6 2001-11-22 Jean-Frederic Clere (jfclere) <JFrederic.Clere at fjitsu-siemens.com>
+
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: GnuPG v1.0.5 (GNU/Linux)
+Comment: For info see http://www.gnupg.org
+
+mQGiBDv9Gx8RBADclmKwDLcibNVipQnhYW+bFIpuQjQnRrqRwn3gXM+/luzzJYJ4
+bbWpw13zjX0EkrAJ8qH2A/d0EIU1eZ0zHrLgRvMUfLGFUX7FFFw18JKFLTVGhG4/
+8sSl3ydHSA2Kd1PF6xjBP7iM7sg5dJfEkyMzvK5H4F0ZpTqy3087wsg1wwCgitRy
+Zg4x3lWZSkOwBj472qaO9GkD/2q6kyWfAK6XFe3GuB5AAs3poMfN1eqW+duM4TA8
+zUiWK0Wxx4JXJbL7n0i4d+JdXJsrjSjF++KKfelcxsrSxoUIBegez25MUSvHe09D
+R3nqkY8CVO+viEtzRBqkSgCMbUjAtfkQ+vp2jDnWSmmkNfY0OYAzt+KRyJKcjUSJ
+gvOOA/45+DN9wuTELoFTvsXh1JgOL/QvW1fmQ2HrcQk94BkzIsfVGWClCiig5gNw
+LCxTbfgA5htpI8U7vPR9/5gH7U8Wy3HR6xQUZxcbttMeYit2VbDEJzF5r5S0pJvD
+vyk3n1kiKU7r49sjhxGgE8J/VvDpO6YcIsDs8LoULwuJTg0DTrRDSmVhbi1GcmVk
+ZXJpYyBDbGVyZSAoamZjbGVyZSkgPEpGcmVkZXJpYy5DbGVyZUBmdWppdHN1LXNp
+ZW1lbnMuY29tPohXBBMRAgAXBQI7/RsfBQsHCgMEAxUDAgMWAgECF4AACgkQ0+/m
+toaGe6amGQCeJU5VZ8QCi8+PY0QJHPA63e5uPyoAmgOWIwFm8A/xmW8qjEvVAWtb
+TjZxuQENBDv9GyMQBACCbFlSF+udW/Qz2oknDen8Hoql4Q1Q7CUQTbPjoQAcYgZg
+LrsR6hc9aCIf3Kt4qZBgQ1Oe9M/AemOFhU04UNp3dgHk91EYRvx80Rua992p/8V7
+QOhwIBVb2XE8as5nL2j8w6Jz7eSs/bivxm9yD0AH/I5H01RAJivRbOTsUgSkDwAD
+BQP5ARlW2Nqc0U17asQsmMYvT1UMiOiyBwUD/DIEG2Xy1hlEvdljg8WU26jcjpGq
+MrT69T4Z+eZ2oVyiRQTW4qMUBKc0Nbz89hL0qv9K41ExxxH+JgE1csRVvmwAT8Iy
+lnhof7TJLRBtvan3+p21Kxl1uQ7MbmLT875u+vc+J098fIiIRgQYEQIABgUCO/0b
+IwAKCRDT7+a2hoZ7pn9UAJ9f0TK0QQOtjQBvxAissopYhDKHGACePZg0k9sj69yw
+nVWrBS9fvFC9jcA=
+=BTiM
+-----END PGP PUBLIC KEY BLOCK-----
+
+Type Bits/KeyID    Date       User ID
+pub  1024D/E86E29AC 2002-02-13 kevin seguin <seguin at apache.org>
+
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: GnuPG v1.0.6 (MingW32)
+Comment: For info see http://www.gnupg.org
+
+mQGiBDxqtR8RBACbySxGrtf+flbowryS1Hj4z3zzEXD4CAEq6RjSGMtIraCDRJfp
+6Gexs+lQ6IhpdC4GfX70SUMjXXvT5suhXYeGOM4iJHqUsksgzEKjUqcfj1l3qmOs
+/doE8lcGGHcYbMplBcfuop+shZYiv9GEJ3gutwn/dNnhs/QA9bCdIj03lwCgvAcy
+QpT5JdTym2p2icd5e91mGIUEAJMw6JHTTcCiyoTRy7k8Cf65d8S7bTDLr6pqJVE2
+XU41CvW/pgL31akYAxpeZJJnsBaLaUiqh6K0qgfEMlDwDeC6gVogHBxWkEXdK1dr
+tGL4GIUcxQ1+ZvQhGg7dtjanmfMlylVgS+C48awJySkinRmaQDbQ0MKdFchLc/y1
+OR3IA/0VkIvlidehMPbZCalqhS9AEsDiFq5/u5AsQzDEp2nmTGlmBqjhc39kEnu4
+qKq08az1Gt6Q7sxXbjH/jYtDgd49FW5Yg4k5B3hpTgnbyRE6SGlKksu8qTmYkDve
+4rej6pvJRHwp6hDKxDG8qQoLWIgOfVC8960nurqx56QdV9YMsLQga2V2aW4gc2Vn
+dWluIDxzZWd1aW5AYXBhY2hlLm9yZz6IVwQTEQIAFwUCPGq1HwULBwoDBAMVAwID
+FgIBAheAAAoJEKy3f8Lobims3E0An0x3rrUMIijUMFoqnoT7muNGwmAzAJ990TWj
+dZO4ayh1M+cWhjaw9W+44bkBDQQ8arUkEAQApaMm5HUB1Yk2x5MavAs/O4zfWnOx
+YFOeXIPfGvhlhF2/Lrjs9icaa/tOM/CTCes19nDWP5Fc+pQxmgSPrgt3fsShwZJe
+p3iYodLbM76uXEgSvI4Wh6kwViHbN4V1GxJAd2ZPVb1v+lauGUCOgPFGw99UV9sO
+tTRXSbFS6AgqQzMAAwUD/jq6boxlnab/GUmKrILeLkv1X0G2/AEXEGRmG0nkhVdj
+OShoqtPr4y/UhMzJUOequs2CdvRlTIyAyZqN7A0Qp4mFfmsvp0dYYssTtE4bCzZe
+WxSKgjtBWBHXnH+Qzjb5R2Tz28kAxNY+dt7yxC+CkXWDZq/rsPgsXNbWXT49FnF8
+iEYEGBECAAYFAjxqtSQACgkQrLd/wuhuKazl7QCfQkz5t/3T6EtXZCcXz/hlswyI
+z30AoLr/7hwXgedEepBk/Gm9HUsbMnM8
+=S1mb
+-----END PGP PUBLIC KEY BLOCK-----
+
+
+Type bits      keyID      Date       User ID
+pub  1024D/307A10A5 2002-07-18 Henri Gomez *** RPM SIGNING KEY ***
+                                           <hgomez at users.sourceforge.net>
+
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: GnuPG v1.0.6 (GNU/Linux)
+Comment: For info see http://www.gnupg.org
+
+mQGiBD02vbERBAC1v8fR6gjERpaz4UMfdy0hRVWCPSbOdF+Swm/IenjVzErco6zb
+MTa13umUNrDPBy/tTWiCCZrOnqi7fgDzWqPEqrXJjKAFVLEWE6MmKylPPEPG1/bm
+idkNGERSAZduvhKv777PzvEJJ/8eGe3wy/O8NbgIjCPtr4UklwCZS8cFuwCg8oMO
+UdT8qZRtzdxdAyu1m5fUb+MD/3IKJYWXsdtb6iBphCU4f/BoyjVC9EZJ1ywLuiVM
+siKbuaDUaXU9nWcbNKv+fx8uZ1NaadpfLokqqhnWcpnSiqw8HNR7SwsF1D33rkXK
+O4FSuVss/tIoqGdWFcJyPkP4yP5shxqR335narVw2vDa0+BiWkALbA2qVsSIdZDB
+LeFZA/47AMBS0U2BRk2rQT8LmMuFl7mR+wNBM4n7FUGdxsGn3TcYd4pXTNrEQPrV
+YNdooKlikgGk4hgFnIFX09Spmimqgq0goFue81rttVdZZ4uep8dTghY6gwmvcOxX
+jATbhWStBhdu9B35kzfHc+1QihD5Z94u4uyWIVBIzikcdiY8LbQqSGVucmkgR29t
+ZXogPGhnb21lekB1c2Vycy5zb3VyY2Vmb3JnZS5uZXQ+iFcEExECABcFAj02vbEF
+CwcKAwQDFQMCAxYCAQIXgAAKCRAZMdaEMHoQpYijAKCCP68ndU/kTXR9XAKLvibC
+3S8+1QCfUFQYte3Jo+MHKaWjsu9JGptRzo+5Ag0EPTa93RAIAKlsRJ5gOGTFsmaR
+W9k6MIh4c/MCy7J7HUxT5xTdHROa+3zUh+FAE/JaOx9ZtZtH863DFHA8cP4L+tpi
+PjBT6g2E94dwGcuH/OiSSCT4JSBukbGbOuLLdmFXqUl8+4gsL90Xal67FtNLwyLG
+1n7geLir0byD+OT7VLA5w+6G0NOpJEveV/FIa2qLgdRZ8vz73ybgMh18hBUrUmro
+jncp0rln2VU7VCH1C2aClKm7kK4mGAjIFIzKbguK+kM3b8NDHmXKpT6syyCtIM3h
+prkV1TUCAFqLI32aSdlTN79lpeA2zDga9k4/4X/RDHsFpRN2neRFGTNUtuUgYpQQ
+E5zWBmMAAwUH/RiGxyeBsad923IwE1+GAjxFl2tqF9xWk0J6yTnSK4nfhYAE9evV
+jwDEok9jRl4ILCcXx6YN/d/lWNuSbARKHz/3hLiTouPpwd3SSJ8is2x9PgpJz5JX
+cD0y1SkbPLvs3jH3ZmdcxZpuAmJeI/typqFKK5pWP44oXIH+XH/8nWDtmLEBkgKQ
+/ATQWenMTmZ6MIJ6aWKWGkO9QS6iYRz3PPPGQ1O8W02CeprM2wBtlb8J1Z3RxNhM
+rZcg/1Qi3V3D1HI4zw6tAFmDeBb8J4PaBQzqlhzx2EBTbfwNPhV8AlPvpxHEeGGn
+v+O1yhZr33SnyZdINNoNDn+owVMdmkobe9GIRgQYEQIABgUCPTa93QAKCRAZMdaE
+MHoQpRsTAJ4qst3MhLm48fBAEnzuzi/BIKr+AgCfYaCB/AvPoncQbHc8BcNGRimR
+P9A=
+=hQhz
+-----END PGP PUBLIC KEY BLOCK-----
+
+Type bits      keyID      Date       User ID
+DSS  3072/1024 0xA01422B5 2001/10/09 *** DEFAULT SIGNING KEY ***
+                                     Remy Maucherat <remm at apache.org>
+
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: PGP 6.5.8
+
+mQGiBDvDY+ERBADJ+GZ2SSlHMb0wRjfsHdJbb4zrRfHn4McEkYGUXyLtZJquAj3V
+8/JxrL3+wiBuXFQitf5qYXLDlRH+F1iFT17kqalFTvxZMA3Hg2kLB6ZUvIP8sTrD
+b8WJU18Lu2GwPMEUT1ito2eG3PDzgIVRwA0c5btLOhkwoRT+5bEl4ad8KwCg/0XV
+CEchMuZtOdJi6WOf8hfwF+cD/iTdfkuxGZEn6fK9erJb5GCr1v/0l83qKU36r8DX
+3kGpR6yac/2xv7+NEaKS1t9k/0seRsFQ/gWZA192HpsRhhe4C2lWmTh+YI7jS7mB
+Bw8dY304yhwPZuUYw86cLMpG5PXz9519kkDFGHlLG6MaxHnhfe0dXWzs/yv4uSsm
+35QfBACUx677GL4pEFJq2pP30aWhxc1but0ncLh5WDCael7wVuTGVSk8TorWoteM
+GcQkmDLo+my7xettXUTssijSn+NVRsFjcgMEpAWeJTBtfDRCyf312ECx7BM5G9oh
+HxtzMW4ZJYY4M1+3qklgpZaEYx1J8g8bIBv661vunbbcj1/OrLQgUmVteSBNYXVj
+aGVyYXQgPHJlbW1AYXBhY2hlLm9yZz6JAE4EEBECAA4FAjvDY+EECwMBAgIZAQAK
+CRB7QXnboBQitdfbAKD8zt0jeFHIlX6awuu9atxWyWaB3ACfb08JdEElpF7cTZhx
+yRpnKZDUvpa5Aw0EO8Nj5RAMAMwdd1ckOErixPDojhNnl06SE2H22+slDhf99pj3
+yHx5sHIdOHX79sFzxIMRJitDYMPj6NYK/aEoJguuqa6zZQ+iAFMBoHzWq6MSHvoP
+Ks4fdIRPyvMX86RA6dfSd7ZCLQI2wSbLaF6dfJgJCo1+Le3kXXn11JJPmxiO/Cqn
+S3wy9kJXtwh/CBdyorrWqULzBej5UxE5T7bxbrlLOCDaAadWoxTpj0BV89AHxstD
+qZSt90xkhkn4DIO9ZekX1KHTUPj1WV/cdlJPPT2N286Z4VeSWc39uK50T8X8dryD
+xUcwYc58yWb/Ffm7/ZFexwGq01uejaClcjrUGvC/RgBYK+X0iP1YTknbzSC0neSR
+BzZrM2w4DUUdD3yIsxx8Wy2O9vPJI8BD8KVbGI2Ou1WMuF040zT9fBdXQ6MdGGze
+MyEstSr/POGxKUAYEY18hKcKctaGxAMZyAcpesqVDNmWn6vQClCbAkbTCD1mpF1B
+n5x8vYlLIhkmuquiXsNV6UwybwACAgwAkwuQXCs1OPX398vydLxtt6AX9KreX4wm
+ykMG+hjgNUsUhYbi03fInYtqTd0TS9qtvSyFUP1aahoY7xKDECI8fyN20Xphb2ih
+fgipT6lBFH1tYX4cS1NHcQEdPU3b96Uat6cy7bma0/kUr3EZuxQlc6UVvsxD+lsT
+HsSqymY3om8Jx2yaDB58yK/VRUMs7/GPaqe/jQiHxbwyS7sWqhew7uNp+wJL5lEx
+x5PkbKj/eA2pKUpMrPKVJfK3E4nq5Q9feBgukhMCADxon2KYa4z4orU3EkM7I3sn
+wujj9dnCkoK2+P6/WvhNhR6q9fbdTHQqtDi4zSwip90m4CPWX/26RrEw2Lax1vC9
+LNJu5olQORxWvaDEoPFkU23kohGe9Qtxozqjn2Sya8VQoq1X5IMrQoCrf3MUWGrJ
++UzABENqSj4mM5XSGazkzTsx59hQMLEz/zKsFlQqTSaZ88VXNoRjj3Hm7b8KQeDE
+nTVtyjsrfoYjqPLSdhypI6HyNbUZ4mDJiQBGBBgRAgAGBQI7w2PlAAoJEHtBedug
+FCK1DkkAoJpMzhUJ2LrraHk7ALnqEeOlPnusAKCQ0vyLlJGktTxwzZ6yv2xwSj6O
+XQ==
+=1Jv0
+-----END PGP PUBLIC KEY BLOCK-----
+
+Type Bits/KeyID     Date       User ID
+pub  1024D/564C17A3 2003-01-11 Mladen Turk <mturk at apache.org>
+
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: GnuPG v1.0.6 (MingW32)
+
+mQGiBD4fwXIRBAC7WRS8PYxi2YH0T1mX4HCYsF8aHoqxBzMnyFR4J896m1s96vGM
+BTSAwH2NKbiVqtfLokTbQkUVxtrgrF2HMB5NfYBg/JzT7pZL/Q2ThWUS7SJQQA4f
+a7/DpiLiHalp6iX45om6JTdIWEyXv26csIVhmtlkGBEPRhNRX8X4//BM0wCg7wcA
+yQ7c5NmoOJLVs+uHsRrnHo0D/R/dMyuWt7/o0eGIEuRlDl2q+YL8xLuVyJMXQBnd
+jo7jKpQ+Q1zl93aVTzsJa7mP2zZ7jqaJ855sdz6rvwyhGF1/qYMtm6zrmgBy2XPm
+J+57sfwSZr0bhIeMpCWjIw98z9sObq0v2r2oA3+J9E3Na/BZsCVTZVb3ew7ILmEp
+F5D7A/4zvjY41dakCAJsD1Xo8TS6hSqJf4zq9vX3ayJVvUjeo8n4sHNOwcbEnnui
+9zZaUH3F0x+3cDo7mS1Y4pD8THuqCZoSbSkiHnlved6nLXsKbqvVrVo+esEhfZCn
+Iji3gp+2TVNwdHXGM+4BAzMJCLsdXjByO6SNzB9a+H8RsRlZKrQ8TWxhZGVuIFR1
+cmsgKCoqKiBERUZBVUxUIFNJR05JTkcgS0VZICoqKikgPG10dXJrQGFwYWNoZS5v
+cmc+iF0EExECAB0FAj4fwXIFCRLP94AFCwcKAwQDFQMCAxYCAQIXgAAKCRAcUGQH
+VkwXo0jxAKCgHzXPIB4IAgoD7GMAohPQfX7j2QCeL6pAsf4pPufmPvbrrpDp6rQH
+GOS5Ag0EPh/BhhAIAKWzq7+/+nNYGpc7sXGkDNo9xncxcx/KbbJVT0rBteuaonQ4
+vYar1ITjIhOPmF9yPmpUddNrqgQTSO+Or+ZrVOndn+qC1gdY3qpKIN3KTjXloW38
+0Y84ezwdRLznQNkhgXwNcB55l/Z9kLaW2MS8CJzOuYSQT1CYbXg7XP3684ZmV1KC
+cGgcUt9VkIGqwsa2RFDNGvMbySedSkJ/70Q+PJlkXN+W86f8hi3HTjw2MCkNa5NL
++Byg8FEAm95YWrO6kCY3qaJYV7NRt9oVd+2V/NNzwYp3Or/QoYofvfNerupfwBmU
+GEXPyZCqqNH6nDv6chscsWvEA9KzhsWnsdKhmHsAAwUH/R6LwfWgtpaO42dQI4ZS
+VRBmCeWrXCuyVk0d13Yz0xLi5Z5m4g3MON3d+cRVUiyNX+hbDGpi2mkbsnL559Ef
+iqmzDmSz5GQHDutolhOPtLxLrC537ODn2q7hnYQwIQYYIUtYD5sYlzfGYC8olGCB
+IcKIdlGRWcxxiFCIJm5CX/jnSBsyDRpanlSrdkxhzAGsifqj4NQ19ayoeNoZg2ZP
+9SLIY7vbmOxJeHEYkx8AG25xOY1PLotb/0buSXPB8e71zb/DCV1rAhhUxAr/2JOQ
+RqlZBq6PfcHKLRitXRCeVvfldRxuWBIzhuTLUfRPYR6phjP50EzZPlbJzIvGwsOI
+RheITAQYEQIADAUCPh/BhgUJEs/3gAAKCRAcUGQHVkwXoy0JAJ9WTfqfYzW/F6qi
+5MxmqDnU9/G+6ACfQVmhZNnGTSfcwQCttwCaW3CRhDY=
+=MWUr
+-----END PGP PUBLIC KEY BLOCK-----
+
+Type bits      keyID      Date       User ID
+DSS  3072/1024 0x7C037D42 2003/08/05 *** DEFAULT SIGNING KEY ***
+                                     Yoav Shapira <yoavs at apache.org>
+
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: PGP 6.5.8
+
+mQGiBD8u/mgRBAD5WKD5xF3CLrnABeS1DvQQhYH+tJjvAmyZgFkYwaQT7eiiOzLa
+PC5knbcBC4nuw+8OOPDFw0Ghb2MFogQzRxD6gpPH2t9eEUsrkPFax2Kw2vNTHRrQ
+RGAastmi+EYJsQAoktX2dPseTdrkeJBk240Bfj08ZUFg4uPuho9C45ND6QCg/6SO
+FMuan62QE+DwlUiMDo4ZcU0EAMDS8k6Dhb5m/0njO6w9OLTEyzohlsM9AP+4mfgB
+NOJYhrzfkFoElOcWSA/V3nmYn2VS0oIYDDtBnjXVWZidzTAWKsbT9/AepS3/P2tG
+KMhlXhas+uAiAbMpOglz8fdQ76ivQqyRdS99t4iy/cP2ZC3ShAqZQCacfWY5ZQ8Q
+kTILBADvp/eayw8fvtfWQXJ9EjBRbhO4THmP6z8J+4ypG6l0V/RBjDWZybrqibO9
+ejnOjQYJNCnfrfpzQ5l6dHyy86zLyg+bkFxeId4jp/IfDfJX90sGbuQahNYYwqTp
+SFiDMI3KN5ZhzhGnx+pKQh59pcux3HyKmcpPa4oB0CT828lWuLQfWW9hdiBTaGFw
+aXJhIDx5b2F2c0BhcGFjaGUub3JnPokATgQQEQIADgUCPy7+aAQLAwECAhkBAAoJ
+ECZhkcN8A31CGLkAoPRDGtLRwjkzS2F/OBPkRHKF9/atAKCIh3Fmcr2Cdn05P4qF
+kBe3QeWVt7kDDQQ/Lv5qEAwAzB13VyQ4SuLE8OiOE2eXTpITYfbb6yUOF/32mPfI
+fHmwch04dfv2wXPEgxEmK0Ngw+Po1gr9oSgmC66prrNlD6IAUwGgfNaroxIe+g8q
+zh90hE/K8xfzpEDp19J3tkItAjbBJstoXp18mAkKjX4t7eRdefXUkk+bGI78KqdL
+fDL2Qle3CH8IF3KiutapQvMF6PlTETlPtvFuuUs4INoBp1ajFOmPQFXz0AfGy0Op
+lK33TGSGSfgMg71l6RfUodNQ+PVZX9x2Uk89PY3bzpnhV5JZzf24rnRPxfx2vIPF
+RzBhznzJZv8V+bv9kV7HAarTW56NoKVyOtQa8L9GAFgr5fSI/VhOSdvNILSd5JEH
+NmszbDgNRR0PfIizHHxbLY7288kjwEPwpVsYjY67VYy4XTjTNP18F1dDox0YbN4z
+ISy1Kv884bEpQBgRjXyEpwpy1obEAxnIByl6ypUM2Zafq9AKUJsCRtMIPWakXUGf
+nHy9iUsiGSa6q6Jew1XpTDJvAAICC/4iJF383WNktP9/SxeGVIV74r7C7q5Cxr4a
+Liy7pEYs52DEft3JzTCLI5O4+NjOw+hEd3QiIytUJRW66V6zd50h4x9lBfK+eMYz
+GKNN7kd3aBmH/vXEsG9m9bK1ExwyWq4uyf76nRx1Ya9YthNWmxPUHQnSrOYNPU0/
+beA87ouZG4RL9tYqdu3NKJ4g/DYiaw+twvhSoCUkBEFHFfKLDlv8zyQvPTaPUSAM
+Ha5/G2Dj1D5RluMSCEMG1V8+YcYAFh63WEP7Afye0mR1LMJvmlba67ogh0ZSfR+I
+ju3lhJ9XOp/2W372F9ZbRJofgofVwHQV6INB5uX7KHAdXtPTss+l1nTmydLhsiPC
+5oh99ITPdOm8gRzrP10aFwCnwsqXvr+b7fX/CywpuCOQMIr4sbhbYTTClwDo6E0U
+TQ+Nb7PWE+8KuJuobTvMUqDQSQaQBnkpLcvRt3cPppANtkaADAeNf0RqKxxLlym4
+AltN8G8IMLtSJoH9xlQHTQA4tEUeKOeJAEYEGBECAAYFAj8u/moACgkQJmGRw3wD
+fUJh7ACdE7QuMkzSbxEzTXnbkS61AUPy06QAoI5b613vrWeqg5Gz9C7TzG+FEEoh
+=O17Z
+-----END PGP PUBLIC KEY BLOCK-----
+
+pub  1024D/33C60243 2004-09-12 Mark E D Thomas <markt at apache.org>
+     Key fingerprint = DCFD 35E0 BF8C A734 4752  DE8B 6FB2 1E89 33C6 0243
+sig         33C60243 2004-09-12   Mark E D Thomas <markt at apache.org>
+sub  2048g/0BECE548 2004-09-12
+sig         33C60243 2004-09-12   Mark E D Thomas <markt at apache.org>
+
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: GnuPG v1.2.1 (MingW32)
+
+mQGiBEFEjegRBADocGttfROvtLGrTOW3xRqZHmFWybmEaI6jmnRdN/1gGXmb3wQL
+rHsS3fLFIIOYLPph0Kov9q4qNq36LekShIvjMBDFoj2/wRxaUtFq81asaRZg8Mcw
+4kVeIoe8OIOuWmvYhU8SH2jJNUnVVrpTPAa6QWquTmseNi6UJMjLxuL7DwCg//9u
+k2yj0vk6e4WSO6Fe5+EkQDED/AjQsy0kj9TpNHkKSSUR2evRlWPYA0YtxBSbsgON
+tT0cYipAp5IcYt6Zq5QzHiZreyQXLAjItDS2oGCIXfNbTYJ3kxxJTCU/3wlefVdq
+LBh4ttm7gmWaiTDTgG4axLF5oMpAb3m4v6s1KvXVVj2pqkhBknfuoRh1wPqbtwks
+7HOIBADVezl1/vny5YzdoqsDx1ByXMLi7CuMexQPllhRbdN+an+ZiJ5YP8J9rPdl
+NCELsCCcDKLGLjlp43XfMxsgYAPEZNG2ObjKTarhk3uGYN3aJrx7s+G+c2bu8o2n
+SyAFQ1iDsjS87PgSPCONA2/36ZShmv1OjLWz5Vo7hGSPcW4ZdLQiTWFyayBFIEQg
+VGhvbWFzIDxtYXJrdEBhcGFjaGUub3JnPohdBBARAgAdBQJBRI3oBwsJCAcDAgoC
+GQEFGwMAAAAFHgEAAAAACgkQb7IeiTPGAkOkvgCg0AcTAfe8m2ZSWkbsoqplLDsM
+0+oAoNl4EjXT+T2j2z8jdUYPaA8LztJguQINBEFEjekQCAD2Qle3CH8IF3Kiutap
+QvMF6PlTETlPtvFuuUs4INoBp1ajFOmPQFXz0AfGy0OplK33TGSGSfgMg71l6RfU
+odNQ+PVZX9x2Uk89PY3bzpnhV5JZzf24rnRPxfx2vIPFRzBhznzJZv8V+bv9kV7H
+AarTW56NoKVyOtQa8L9GAFgr5fSI/VhOSdvNILSd5JEHNmszbDgNRR0PfIizHHxb
+LY7288kjwEPwpVsYjY67VYy4XTjTNP18F1dDox0YbN4zISy1Kv884bEpQBgRjXyE
+pwpy1obEAxnIByl6ypUM2Zafq9AKUJsCRtMIPWakXUGfnHy9iUsiGSa6q6Jew1Xp
+Mgs7AAICCACuLSE3vBSOeTMM04ezuPt4zZUp0PFQGQL3bzuZp24f18S8P3BemGAk
+2V3HZYJmzmNgd4L0vIC9xyFduICFgbiV9uyzKPwHvCgQwaupFvFLGn7Q9LJ0nlaw
+GN7Km13vJTG3rrT/UMKwLTk+IMEYQwUgBht6HTnBaM+UqVx/eB4PHobimt5Redz9
+CnT4DrlA0M6Oh3ePWBD69Nnhwo2AN42dX/W2KcnDe2iRNu/JEbOYsssj0e3VmHwE
+mwa064TpQpw1fClyW7sf4aWOcQvcT12R0hNvRhTR1TV0pzjIMkbRPkRezhIY55AT
+TIfcaZrw+Yubmmw/pp/1wIDRzHexOq9riEwEGBECAAwFAkFEjekFGwwAAAAACgkQ
+b7IeiTPGAkN8ogCg4tHmgylXw4Y3ujF+J4cf2ollGa0AnRkyX8X+u/NrMi2g2xhE
+vpsTbAGW
+=r1gT
+-----END PGP PUBLIC KEY BLOCK-----
+
+pub   1024D/D7B65864 8/22/2006 Filip Hanik (Filips Apache Key) <fhanik at apache.org>
+UserID                                              KeyId Long         Key Id
+Filip Hanik (Filips Apache Key) <fhanik at apache.org> 0x7B87E296D7B65864 0xD7B65864
+Fingerprint 1429 6D83 984C 223A 9761  F633 7B87 E296 D7B6 5864
+
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: GnuPG v1.4.5 (MingW32) - GPGshell v3.52
+
+mQGiBETrKsYRBACQmyglB/jdLFSU1gczfd42MmO5tA6YeZjhzejU/JJtLpgdSW1S
+1me/2SYDLsyuwrE7P5DVz1geWSfqXqzO9ThzY1Ixgqrg6n6o/3wq5SMBCxrAJXcN
+Zi6Vbwxt/LMcOzOfUKFPkGBUM+qsj3ItmInfsWBgOrwxQ37KtjCMgNHOowCg5o+D
+Nmmw8JEWjHq8XVMvcGUJR1UD/3lU6qiqOUH+75UdyYfAO1OZkccnUeR+5r1ZcjZL
+hJl+0TT18twa5v3UC5812TGPsTo0RRwpEqeO7urv26XulfofKV9b8JBRIVpunBd1
+9NpEN/SBfSQ+RzFWhg7xRirlBV0C30toFqhkI72vkYvbKhbaQKGqSt0daXLz0dU3
+NgxVA/9yOisu/gNHs2IsrPjCPO5uU7BIaiLfvTENVcfenV1O/YG0DjCsaccUBh0b
+34agdWldR+ak6beGKp8My+6m4+v9Mh5GI372EovUU5Aqyts71fDPyC+RHL7pFIPf
+HQNR+asb+QvY6Fgon8HUxL/bPFKN1JjnT3yWZTZrX9xUhe5cMbQzRmlsaXAgSGFu
+aWsgKEZpbGlwcyBBcGFjaGUgS2V5KSA8ZmhhbmlrQGFwYWNoZS5vcmc+iGAEExEC
+ACAFAkTrKsYCGwMGCwkIBwMCBBUCCAMEFgIDAQIeAQIXgAAKCRB7h+KW17ZYZFm8
+AKDTdlIxDHP802gyr22mQaB5xPsqnwCeI07ItFbIWz2izl5wltluNzfiUdu5Ag0E
+ROsq0hAIANOpE8Z+bXbiPp8W/0fkzgjtMojmF2sqFg728kzPrtADfqfsS8javY18
+Zu2kxbmiAnUxVhisfOB4DMeCqpKT1DNlPeNowXeO7x1XJcFyzc59cl9fPC52+qwS
+fb3w1R7/nbFZqZXgsNg0IuOUJ29weAWvhugLrd2mRqUO6NtmCvH8NlBVpminESLE
+L4hpfyGGSJeAxeEAT0B3amwJ77cv2xIoVD5zowiS+WM1qDvpXQm+b7uiz4YxviWO
+4ZKSHSQ2iq8SQc2JxoOOPlTHe8+h1MI+Uqmb7eQKEik8Y3hXuY7g+55cLYT0NMz0
+2Tn2tblghqu2QPphN9IQ/5iA1AQ4/SMAAwYH/2cTjiBXa6/2bAywR6csbrW1r0/s
+ugY882+p6xM1HFzl9pv9zdS9je8kWcDv3sEvhVfdAqeQ0SCA/5ZrjuIn0f77P/vR
+U4cZjjJUecrD2YjkFkXETd1Fr4TwtbiVWiDqLGZOaZnDYdhDNKXF0zfcAixjSP3x
+IXd9R3Slrg33TLYmWHdVWpp0GR+rdQwPFFXbi036aPLT2YB7kFjGeb/qUnlFPVn4
+my+STMKLuvl4qIZl9UE6TRc0G5L2vJeJ/43BNEEovyQpV0TIJ3NSK5wMUOF6bCA0
+yVoMPkWmQIGKk0bSD5L+LbV2zqKebpG9jbTcKmP8aSrnPsTzDC3rUkolj6iISQQY
+EQIACQUCROsq0gIbDAAKCRB7h+KW17ZYZJLjAJ9Av5B/TShKgq2C+D64050m871p
+4QCcD5ciTfRByolZe+fQ3lktOpO0Mpc=
+=ttOX
+-----END PGP PUBLIC KEY BLOCK-----
+

Added: branches/tomcat5.5/upstream/5.5.20/build/LICENSE
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/build/LICENSE	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/build/LICENSE	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,201 @@
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed 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.

Added: branches/tomcat5.5/upstream/5.5.20/build/NOTICE
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/build/NOTICE	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/build/NOTICE	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,18 @@
+This product includes software developed by
+The Apache Software Foundation (http://www.apache.org/).
+
+Java Management Extensions (JMX) support is provided by
+the MX4J package, which is open source software.  The
+original software and related information is available
+at http://mx4j.sourceforge.net.
+
+The Windows Installer is built with the Nullsoft
+Scriptable Install Sysem (NSIS), which is
+open source software.  The original software and
+related information is available at
+http://nsis.sourceforge.net.
+
+Java compilation software for JSP pages is provided by Eclipse, 
+which is open source software.  The orginal software and 
+related infomation is available at
+http://www.eclipse.org.

Added: branches/tomcat5.5/upstream/5.5.20/build/RELEASE-NOTES
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/build/RELEASE-NOTES	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/build/RELEASE-NOTES	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,180 @@
+
+
+                     Apache Tomcat Version @VERSION@
+                            Release Notes
+
+
+$Id: RELEASE-NOTES 439327 2006-09-01 14:06:34Z fhanik $
+
+
+=============================
+KNOWN ISSUES IN THIS RELEASE:
+=============================
+
+* Dependency Changes
+* JNI Based Applications
+* Bundled APIs
+* Web application reloading and static fields in shared libraries
+* Tomcat on Linux
+* Enabling SSI and CGI Support
+* Security manager URLs
+* Symlinking static resources
+* Enabling invoker servlet
+* Viewing the Tomcat Change Log
+* When all else fails
+
+
+===================
+Dependency Changes:
+===================
+Tomcat 5.5 is designed to run on J2SE 5.0 and later, and requires
+configuration to run on J2SE 1.4.  Make sure to read the "RUNNING.txt" 
+file in the fulldocs downloadable file(s) if you are using J2SE 1.4.
+
+In addition, Tomcat 5.5 uses the Eclipse JDT Java compiler for compiling
+JSP pages.  This means you no longer need to have the complete
+Java Development Kit (JDK) to run Tomcat, but a Java Runtime Environment
+(JRE) is sufficient.  The Eclipse JDT Java compiler is bundled with the 
+binary Tomcat distributions.  Tomcat can also be configured to use the
+compiler from the JDK to compile JSPs, or any other Java compiler supported 
+by Apache Ant.
+
+
+=======================
+JNI Based Applications:
+=======================
+Applications that require native libraries must ensure that the libraries have
+been loaded prior to use.  Typically, this is done with a call like:
+
+  static {
+    System.loadLibrary("path-to-library-file");
+  }
+
+in some class.  However, the application must also ensure that the library is
+not loaded more than once.  If the above code were placed in a class inside
+the web application (i.e. under /WEB-INF/classes or /WEB-INF/lib), and the
+application were reloaded, the loadLibrary() call would be attempted a second
+time.
+
+To avoid this problem, place classes that load native libraries outside of the
+web application, and ensure that the loadLibrary() call is executed only once
+during the lifetime of a particular JVM.
+
+
+=============
+Bundled APIs:
+=============
+A standard installation of Tomcat 5.5 makes all of the following APIs available
+for use by web applications (by placing them in "common/lib" or "shared/lib"):
+* commons-el.jar (Commons Expression Language 1.0)
+* commons-logging-api.jar (Commons Logging API 1.0.x)
+* jasper-compiler.jar (Jasper 2 Compiler)
+* jasper-compiler-jdt.jar (Eclipse JDT Java compiler)
+* jasper-runtime.jar (Jasper 2 Runtime)
+* jsp-api.jar (JSP 2.0 API)
+* naming-common.jar (JNDI Context implementation)
+* naming-factory.jar (JNDI object factories for J2EE ENC support)
+* naming-factory-dbcp.jar (DataSource implementation based on commons-dbcp)
+* naming-resources.jar (JNDI DirContext implementations)
+* servlet-api.jar (Servlet 2.4 API)
+
+Installing the compatibility package will add the following to the list, which are
+needed when running on J2SE 1.4:
+* jmx.jar (Java Management Extensions API 1.2 or later)
+* xercesImpl.jar (Xerces XML Parser, version 2.6.2 or later)
+
+You can make additional APIs available to all of your web applications by
+putting unpacked classes into a "classes" directory (not created by default),
+or by placing them in JAR files in the "lib" directory.
+
+To override the XML parser implementation or interfaces, use the endorsed
+mechanism of the JVM. The default configuration defines JARs located in 
+"common/endorsed" as endorsed.
+
+
+================================================================
+Web application reloading and static fields in shared libraries:
+================================================================
+Some shared libraries (many are part of the JDK) keep references to objects
+instantiated by the web application. To avoid class loading related problems
+(ClassCastExceptions, messages indicating that the classloader
+is stopped, etc.), the shared libraries state should be reinitialized.
+
+Something which might help is to avoid putting classes which would be
+referenced by a shared static field in the web application classloader,
+and putting them in the shared classloader instead (JARs should be put in the
+"lib" folder, and classes should be put in the "classes" folder).
+
+
+================
+Tomcat on Linux:
+================
+GLIBC 2.2 / Linux 2.4 users should define an environment variable:
+export LD_ASSUME_KERNEL=2.2.5
+
+Redhat Linux 9.0 users should use the following setting to avoid
+stability problems:
+export LD_ASSUME_KERNEL=2.4.1
+
+Please note, that these are only recommendations and may not apply in some cases.
+Before you change this variable, make sure you understand its impact, and what it does.
+A brief explanation can be found in the mailing archives at 
+http://marc.theaimsgroup.com/?l=tomcat-dev&m=115689139313901&w=2
+For further assistance, please consult your JVM vendor.
+
+
+=============================
+Enabling SSI and CGI Support:
+=============================
+Because of the security risks associated with CGI and SSI available
+to web applications, these features are disabled by default.  
+
+To enable and configure CGI support, please see the cgi-howto.html page.
+
+To enable and configue SSI support, please see the ssi-howto.html page.
+
+
+======================
+Security manager URLs:
+======================
+In order to grant security permissions to JARs located inside the
+web application repository, use URLs of of the following format
+in your policy file:
+
+file:${catalina.home}/webapps/examples/WEB-INF/lib/driver.jar
+
+
+============================
+Symlinking static resources:
+============================
+By default, Unix symlinks will not work when used in a web application to link
+resources located outside the web application root directory.
+
+This behavior is optional, and the "allowLinking" flag may be used to disable
+the check.
+
+
+=========================
+Enabling invoker servlet:
+=========================
+Starting with Tomcat 4.1.12, the invoker servlet is no longer available by
+default in all webapps. Enabling it for all webapps is possible by editing
+$CATALINA_HOME/conf/web.xml to uncomment the "/servlet/*" servlet-mapping
+definition.
+
+Using the invoker servlet in a production environment is not recommended and
+is unsupported.  More details are available on the Tomcat FAQ at
+http://tomcat.apache.org/faq/misc.html#invoker.
+
+
+==============================
+Viewing the Tomcat Change Log:
+==============================
+See changelog.html in this directory.
+
+
+====================
+When all else fails:
+====================
+See the FAQ
+http://tomcat.apache.org/faq/

Added: branches/tomcat5.5/upstream/5.5.20/build/RELEASE-PLAN-5.0.txt
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/build/RELEASE-PLAN-5.0.txt	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/build/RELEASE-PLAN-5.0.txt	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,70 @@
+$Id: RELEASE-PLAN-5.0.txt 304450 2003-08-04 08:17:02Z remm $
+
+                      Release Plan for Apache Tomcat 5.0
+                      ==================================
+
+
+Introduction:
+------------
+
+This document is a release plan for the final release of Apache Tomcat 5.0.
+
+The goal of the Apache Tomcat 5.0 final release is to provide a stable
+container that supports 100% of the mandatory requirements of the Servlet 2.4
+and JSP 2.0 specifications, as well as to improve and add many useful 
+additional features on top of the existing Apache Tomcat 4.1.x releases.
+
+Apache Tomcat 5.0 includes the following major new features over 
+Apache Tomcat 4.1:
+
+    * Performance optimizations and reduced garbage collection
+    * Refactored application deployer, with an optional standalone deployer 
+      allowing validation and compilation of a web application before putting 
+      it in production
+    * Complete server monitoring using JMX and the manager web application
+    * Scalability and reliability enhancements
+    * Improved Taglibs handling, including advanced pooling and tag plugins
+    * Improved platform integration, with native Windows and Unix wrappers
+    * Embedding of Tomcat using JMX
+    * Expanded documentation
+
+Apache Tomcat 5.0 will use the build numbering and release process first used 
+in the Apache HTTPd 2.0.x project.
+Milestone builds, numbered 5.0.x, will be released as needed and will 
+recieve a stability rating after a one week testing period. The rating can be
+either: Alpha, Beta, or Stable.
+
+This Release Plan proposes the following prospective target dates 
+for stability:
+
+  Middle of August, 2003
+  ----------------------
+
+Tomcat 5.0 should reach Beta status by this date.
+
+  Servlet 2.4 and JSP 2.0 Final Specification Releases (expected by 09/2003)
+  ----------------------------------------------------
+
+At least another Beta rated release should be made simultaneous to the release
+of the specification.
+
+  Two to four weeks after Final Specification Releases
+  ----------------------------------------------------
+
+Best effort should be made for Tomcat 5.0 to reach Stable status as soon as
+possible after the specification releases. However, it should be pointed out 
+that wide testing cannot occur before the specifications are released, so
+a Stable release should only be made after a period of time.
+
+In order to complete a first Stable release, all outstanding Bugzilla bug 
+reports against Tomcat 5.0 above NORMAL severity need to be fixed or deferred 
+for later releases.
+
+This Release Plan proposes the following classification of current outstanding
+bug reports in the bug tracking system, sorted by component and their ID
+numbers in our bug tracking system at:
+
+http://nagoya.apache.org/bugzilla/
+
+Please review the bug reports, and their severity accordingly. 
+

Added: branches/tomcat5.5/upstream/5.5.20/build/RELEASE-PLAN-5.5.txt
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/build/RELEASE-PLAN-5.5.txt	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/build/RELEASE-PLAN-5.5.txt	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,59 @@
+$Id: RELEASE-PLAN-5.5.txt 304598 2004-08-23 17:26:09Z remm $
+
+                      Release Plan for Apache Tomcat 5.5
+                      ==================================
+
+
+Introduction:
+------------
+
+This document is a release plan for the final release of Apache Tomcat 5.5.
+
+The goal of the Apache Tomcat 5.5 final release is to provide a stable
+container that supports 100% of the mandatory requirements of the Servlet 2.4
+and JSP 2.0 specifications, as well as to improve and add many useful 
+additional features on top of the existing Apache Tomcat 5.0.x releases.
+
+Apache Tomcat 5.5 includes the following major new features over 
+Apache Tomcat 5.0:
+
+    * Performance optimizations and startup time improvements
+    * Refactored application deployer
+    * Faster JSP compiler with in memory loading of depedencies, powered by
+      Eclipse JDT
+    * Dependencies repackaging
+    * Streamlined configuration (datasources and web application defaults)
+    * Support for J2SE JRE 5.0
+    * New native connector for Apache 2, based on mod_proxy
+
+Apache Tomcat 5.5 will use the build numbering and release process first used 
+in the Apache HTTPd 2.0.x project.
+Milestone builds, numbered 5.5.x, will be released as needed and will 
+recieve a stability rating after a one week testing period. The rating can be
+either: Alpha, Beta, or Stable.
+
+This Release Plan proposes the following prospective target dates 
+for stability:
+
+  August 30, 2004
+  ---------------
+
+Tomcat 5.5.0 should be tagged by this date.
+
+  End of September, 2003
+  ----------------------
+
+Tomcat 5.5 should reach beta status by then.
+
+In order to complete a first Stable release, all outstanding Bugzilla bug 
+reports against Tomcat 5.5 above NORMAL severity need to be fixed or deferred 
+for later releases.
+
+This Release Plan proposes the following classification of current outstanding
+bug reports in the bug tracking system, sorted by component and their ID
+numbers in our bug tracking system at:
+
+http://nagoya.apache.org/bugzilla/
+
+Please review the bug reports, and their severity accordingly. 
+

Added: branches/tomcat5.5/upstream/5.5.20/build/RUNNING.txt
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/build/RUNNING.txt	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/build/RUNNING.txt	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,182 @@
+$Id: RUNNING.txt 354430 2005-12-06 13:44:26Z yoavs $
+
+                 ============================================
+                 Running The Tomcat 5.5 Servlet/JSP Container
+                 ============================================
+
+Out of the box, Tomcat 5.5 requires the Java 2 Standard Edition Runtime
+Environment (JRE) version 5.0 or later.  However, you can also run Tomcat
+5.5 on earlier versions of the JRE, as detailed below.
+
+=============================
+Running With JRE 5.0 Or Later
+=============================
+
+(1) Download and Install the J2SE Runtime Environment (JRE)
+
+(1.1) Download the Java 2 Standard Edition Runtime Environment (JRE),
+      release version 5.0 or later, from http://java.sun.com/j2se.
+
+(1.2) Install the JRE according to the instructions included with the
+      release.
+
+(1.3) Set an environment variable named JAVA_HOME to the pathname of
+      the directory into which you installed the JRE, e.g. c:\j2sdk5.0
+      or /usr/local/java/j2sdk5.0.
+
+
+(2) Download and Install the Tomcat Binary Distribution
+
+NOTE:  As an alternative to downloading a binary distribution, you can create
+your own from the Tomcat source repository, as described in "BUILDING.txt".
+If you do this, the value to use for "${catalina.home}" will be the "dist"
+subdirectory of your source distribution.
+
+(2.1) Download a binary distribution of Tomcat from:
+
+      http://tomcat.apache.org
+
+(2.2) Unpack the binary distribution into a convenient location so that the
+      distribution resides in its own directory (conventionally named
+      "apache-tomcat-[version]").  For the purposes of the remainder of this document,
+      the symbolic name "$CATALINA_HOME" is used to refer to the full
+      pathname of the release directory.
+
+
+(3) Start Up Tomcat
+
+(3.1) Tomcat can be started by executing the following commands:
+
+      $CATALINA_HOME\bin\startup.bat          (Windows)
+
+      $CATALINA_HOME/bin/startup.sh           (Unix)
+
+(3.2) After startup, the default web applications included with Tomcat will be
+      available by visiting:
+
+      http://localhost:8080/
+
+(3.3) Further information about configuring and running Tomcat can be found in
+      the documentation included here, as well as on the Tomcat web site:
+
+      http://tomcat.apache.org
+
+
+(4) Shut Down Tomcat
+
+(4.1) Tomcat can be shut down by executing the following command:
+
+      $CATALINA_HOME\bin\shutdown            (Windows)
+
+      $CATALINA_HOME/bin/shutdown.sh         (Unix)
+
+
+
+====================================
+Running Tomcat With J2SE Version 1.4
+====================================
+
+(1) Obtain the compat package:
+
+(1.1) Download the compat package from the binary download site:
+      http://tomcat.apache.org
+
+      * Or build this package yourself from the source code: see 
+        "BUILDING.txt" in this directory.
+
+(2) Unzip the package in $CATALINA_HOME.  It will place the XML
+    parser APIs and Xerces implementation in the common/endorsed
+    directory, and the JMX API jar (jmx.jar from Sun) in the bin
+    directory.
+
+(3) Follow the same directions for starting and stopping the
+    server as if you were using J2SE 5.0.
+
+
+==================================================
+Advanced Configuration - Multiple Tomcat Instances
+==================================================
+
+In many circumstances, it is desirable to have a single copy of a Tomcat
+binary distribution shared among multiple users on the same server.  To make
+this possible, you can pass a "-Dcatalina.base=$CATALINA_BASE" argument when
+executing the startup command (see (2)). In this
+"-Dcatalina.base=$CATALINA_BASE" argument, replace $CATALINA_BASE with the
+directory that contains the files for your 'personal' Tomcat instance.
+
+When you use this "-Dcatalina.base=$CATALINA_BASE" argument, Tomcat will
+calculate all relative references for files in the following directories based
+on the value of $CATALINA_BASE instead of $CATALINA_HOME:
+
+* conf - Server configuration files (including server.xml)
+
+* logs - Log and output files
+
+* shared - For classes and resources that must be shared across all web
+           applications
+
+* webapps - Automatically loaded web applications
+
+* work - Temporary working directories for web applications
+
+* temp - Directory used by the JVM for temporary files (java.io.tmpdir)
+
+If you do not pass the "-Dcatalina.base=$CATALINA_BASE" argument to the
+startup command, $CATALINA_BASE will default to the same value as $CATALINA_HOME,
+ which means that the same directory is used for all relative path resolutions.
+
+The administration and manager web applications, which are defined in the
+$CATALINA_BASE/conf/Catalina/localhost/admin.xml
+and 
+$CATALINA_BASE/conf/Catalina/localhost/manager.xml files, will
+not run in that configuration, unless either:
+- The path specified in the docBase attribute of the Context element is made
+  absolute, and replaced respectively by $CATALINA_HOME/server/webapps/admin
+  and $CATALINA_HOME/server/webapps/manager
+- Both web applications are copied or moved to $CATALINA_BASE, 
+  and the path specified in the docBase attribute of the Context
+  element is modified appropriately.
+- Both web applications are disabled by removing
+  $CATALINA_BASE/conf/Catalina/localhost/admin.xml
+  and
+  $CATALINA_BASE/conf/Catalina/localhost/manager.xml.
+
+
+================
+Troubleshooting
+================
+
+There are only really 3 things likely to go wrong during the stand-alone
+Tomcat install:
+
+(1) The most common hiccup is when another web server (or any process for that
+    matter) has laid claim to port 8080.  This is the default HTTP port that
+    Tomcat attempts to bind to at startup.  To change this, open the file:
+
+       $CATALINA_HOME/conf/server.xml
+
+    and search for '8080'.  Change it to a port that isn't in use, and is
+    greater than 1024, as ports less than or equal to 1024 require superuser
+    access to bind under UNIX.
+
+   Restart Tomcat and you're in business.  Be sure that you replace the "8080"
+   in the URL you're using to access Tomcat.  For example, if you change the
+   port to 1977, you would request the URL http://localhost:1977/ in your browser.
+
+(2) An "out of environment space" error when running the batch files in
+    Windows 95, 98, or ME operating systems.
+
+    Right-click on the STARTUP.BAT and SHUTDOWN.BAT files.  Click on
+    "Properties", then on the "Memory" tab.  For the "Initial environment" field,
+    enter in something like 4096.
+
+    After you click apply, Windows will create shortcuts which you can use
+    to start and stop the container.
+
+(3) The 'localhost' machine isn't found.  This could happen if you're behind a
+    proxy.  If that's the case, make sure the proxy configuration for your
+    browser knows that you shouldn't be going through the proxy to access the
+    "localhost".
+
+    In Netscape, this is under Edit/Preferences -> Advanced/Proxies, and in
+    Internet Explorer, Tools -> Internet Options -> Connections -> LAN Settings.

Added: branches/tomcat5.5/upstream/5.5.20/build/build.properties.default
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/build/build.properties.default	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/build/build.properties.default	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,276 @@
+# -----------------------------------------------------------------------------
+# build.properties.default
+#
+# This is an example "build.properties" file, used to customize building Tomcat
+# for your local environment.  It defines the location of all external
+# 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 442598 2006-09-12 14:43:38Z fhanik $
+# -----------------------------------------------------------------------------
+
+# ----- Vesion Control Flags -----
+version.major=5
+version.minor=5
+version.build=20
+version.patch=0
+#Set the pretty version name
+version=5.5.20
+
+# ----- Compile Control Flags -----
+compile.debug=on
+compile.deprecation=off
+compile.optimize=off
+
+
+# ----- Build Control Flags
+
+#Build all components
+#full.dist=on
+
+#Hide configuration flags display
+#flags.hide=on
+
+
+# ----- Proxy setup -----
+#proxy.host=proxy.domain
+#proxy.port=8080
+#proxy.use=on
+
+
+# ----- CVS root for the jakarta repositories ------
+cvsroot=:pserver:anoncvs at cvs.apache.org:/home/cvspublic
+
+# ----- Default Base Path for Dependent Packages -----
+# Please note this path must be absolute, not relative,
+# as it is referenced with different working directory
+# contexts by the various build scripts.
+base.path=/usr/share/java
+#base.path=C:/path/to/the/repository
+#base.path=/usr/local
+
+# ----- Jakarta files base location -----
+base-jakarta.loc=http://archive.apache.org/dist/jakarta
+
+# ----- Logging files base location -----
+base-logging.loc=http://archive.apache.org/dist/logging
+
+# ----- XML files base location -----
+base-xml.loc=http://archive.apache.org/dist/xml
+
+# ----- Struts files base location -----
+base-struts.loc=http://archive.apache.org/dist/struts
+
+# ----- Sourceforge files base location -----
+base-sf.loc=http://switch.dl.sourceforge.net/sourceforge
+#base-sf.loc=http://heanet.dl.sourceforge.net/sourceforge
+#base-sf.loc=http://internap.dl.sourceforge.net/sourceforge
+
+# ----- Additional Tomcat files base location -----
+base-tomcat.loc=http://archive.apache.org/dist/tomcat
+
+# --------------------------------------------------
+#                REQUIRED LIBRARIES
+# --------------------------------------------------
+
+
+# ----- Commons Beanutils, version 1.4 or later -----
+commons-beanutils.home=${base.path}/commons-beanutils-1.7.0
+commons-beanutils.lib=${commons-beanutils.home}
+commons-beanutils.jar=${commons-beanutils.lib}/commons-beanutils.jar
+commons-beanutils.loc=${base-jakarta.loc}/commons/beanutils/binaries/commons-beanutils-1.7.0.tar.gz
+
+
+# ----- Commons Launcher, version 0.9 or later -----
+commons-launcher.home=${base.path}/commons-launcher-0.9
+commons-launcher.lib=${commons-launcher.home}
+commons-launcher.bin=${commons-launcher.home}/bin
+commons-launcher.jar=${commons-launcher.bin}/commons-launcher.jar
+commons-launcher.bootstrap.class=${commons-launcher.bin}/LauncherBootstrap.class
+commons-launcher.loc=${base-jakarta.loc}/commons/launcher/binaries/launcher-0.9.tar.gz
+
+
+# ----- Commons Daemon, version 1.0-Alpha or later -----
+commons-daemon.home=${base.path}/commons-daemon-1.0.1
+commons-daemon.lib=${commons-daemon.home}
+commons-daemon.jar=${commons-daemon.lib}/commons-daemon.jar
+commons-daemon.loc=${base-jakarta.loc}/commons/daemon/binaries/commons-daemon-1.0.1.tar.gz
+commons-daemon.jsvc.tar.gz=${commons-daemon.lib}/bin/jsvc.tar.gz
+
+
+# ----- Commons Digester, version 1.4 or later -----
+commons-digester.home=${base.path}/commons-digester-1.7
+commons-digester.lib=${commons-digester.home}
+commons-digester.jar=${commons-digester.lib}/commons-digester-1.7.jar
+commons-digester.loc=${base-jakarta.loc}/commons/digester/binaries/commons-digester-1.7.tar.gz
+
+
+# ----- Commons Expression Language (EL), version 1.0 or later -----
+commons-el.home=${base.path}/commons-el-1.0
+commons-el.lib=${commons-el.home}
+commons-el.jar=${commons-el.lib}/commons-el.jar
+commons-el.loc=${base-jakarta.loc}/commons/el/binaries/commons-el-1.0.tar.gz
+
+
+# ----- Commons Logging, version 1.0.1 or later -----
+commons-logging.home=${base.path}/commons-logging-1.0.4
+commons-logging.lib=${commons-logging.home}
+commons-logging-api.jar=${commons-logging.lib}/commons-logging-api.jar
+commons-logging.jar=${commons-logging.lib}/commons-logging.jar
+commons-logging.loc=${base-jakarta.loc}/commons/logging/binaries/commons-logging-1.0.4.tar.gz
+
+
+# ----- Commons Modeler, version 1.1 or later -----
+commons-modeler.home=${base.path}/commons-modeler-1.1
+commons-modeler.lib=${commons-modeler.home}
+commons-modeler.jar=${commons-modeler.lib}/commons-modeler.jar
+commons-modeler.loc=${base-jakarta.loc}/commons/modeler/binaries/modeler-1.1.tar.gz
+
+# ----- Xerces XML Parser, version 2.8.0 -----
+xerces.home=${base.path}/xerces-2_8_0
+xerces.lib=${xerces.home}
+xercesImpl.jar=${xerces.lib}/xercesImpl.jar
+xml-apis.jar=${xerces.lib}/xml-apis.jar
+xerces.loc=${base-xml.loc}/xerces-j/binaries/Xerces-J-bin.2.8.0.tar.gz
+
+
+# ----- Eclipse JDT, version 3.1.2 or later -----
+jdt.home=${base.path}/eclipse/plugins
+jdt.lib=${jdt.home}
+jdt.jar=${jdt.lib}/org.eclipse.jdt.core_3.1.2.jar
+jdt.loc=http://sunsite.informatik.rwth-aachen.de/eclipse/downloads/drops/R-3.1.2-200601181600/eclipse-JDT-3.1.2.zip
+
+
+# ----- Tomcat native library -----
+tomcat-native.home=${base.path}/tomcat-native-1.1.4
+tomcat-native.tar.gz=${tomcat-native.home}/tomcat-native.tar.gz
+tomcat-native.loc=${base-tomcat.loc}/tomcat-connectors/native/tomcat-native-1.1.4.tar.gz
+
+
+# --------------------------------------------------
+#              CORE OPTIONAL LIBRARIES
+# --------------------------------------------------
+
+
+# ----- Log4j, version 1.2 or later -----
+log4j.home=${base.path}/logging-log4j-1.2.12
+log4j.lib=${log4j.home}
+log4j.jar=${log4j.lib}/dist/lib/log4j-1.2.12.jar
+log4j.loc=${base-logging.loc}/log4j/1.2.12/logging-log4j-1.2.12.tar.gz
+
+
+# ----- Commons DBCP, version 1.1 or later -----
+commons-dbcp.version=1.2.1
+commons-dbcp.home=${base.path}/commons-dbcp-1.2.1
+commons-dbcp-src.loc=${base-jakarta.loc}/commons/dbcp/source/commons-dbcp-1.2.1-src.tar.gz
+
+
+# ----- Commons HttpClient, version 2.0 or later -----
+commons-httpclient.home=${base.path}/commons-httpclient-2.0
+commons-httpclient.lib=${commons-httpclient.home}
+commons-httpclient.jar=${commons-httpclient.lib}/commons-httpclient-2.0.jar
+commons-httpclient.loc=${base-jakarta.loc}/commons/httpclient/binary/commons-httpclient-2.0.tar.gz
+
+
+# ----- Commons Pool, version 1.1 or later -----
+commons-pool.home=${base.path}/commons-pool-1.2
+commons-pool-src.loc=${base-jakarta.loc}/commons/pool/source/commons-pool-1.2-src.tar.gz
+
+
+# ----- Commons Collections, version 2.0 or later -----
+commons-collections.home=${base.path}/commons-collections-3.1
+commons-collections.lib=${commons-collections.home}
+commons-collections.jar=${commons-collections.lib}/commons-collections-3.1.jar
+commons-collections.loc=${base-jakarta.loc}/commons/collections/binaries/commons-collections-3.1.tar.gz
+commons-collections-src.loc=${base-jakarta.loc}/commons/collections/source/commons-collections-3.1-src.tar.gz
+
+
+# ----- Commons FileUpload, version 1.0-20030531 or later -----
+commons-fileupload.home=${base.path}/commons-fileupload-1.0
+commons-fileupload.lib=${commons-fileupload.home}
+commons-fileupload.jar=${commons-fileupload.lib}/commons-fileupload-1.0.jar
+commons-fileupload.loc=${base-jakarta.loc}/commons/fileupload/binaries/commons-fileupload-1.0.tar.gz
+
+# ----- Java Management Extensions (JMX), JMX RI 1.2.1 or later or MX4J 2.0.1 or later -----
+jmx.home=${base.path}/mx4j-3.0.1
+jmx.lib=${jmx.home}/lib
+jmx.jar=${jmx.lib}/mx4j.jar
+jmx-tools.jar=${jmx.lib}/mx4j-tools.jar
+jmx-remote.jar=${jmx.lib}/mx4j-remote.jar
+jmx.loc=${base-sf.loc}/mx4j/mx4j-3.0.1.tar.gz
+
+
+# ----- JUnit Unit Test Suite, version 3.7 or later -----
+junit.home=${base.path}/junit3.8.1
+junit.lib=${junit.home}
+junit.jar=${junit.lib}/junit.jar
+junit.loc=${base-sf.loc}/junit/junit3.8.1.zip
+
+
+# ----- Rhino ------
+rhino.home=${base.path}/rhino1_6R2
+rhino.jar=${rhino.home}/js.jar
+rhino.loc=http://ftp.mozilla.org/pub/mozilla.org/js/rhino1_6R2.zip
+
+# ----- NSIS, version 2.0 or later -----
+nsis.home=${base.path}/nsis-2.0
+nsis.exe=${nsis.home}/makensis.exe
+nsis.installoptions.dll=${nsis.home}/Plugins/InstallOptions.dll
+nsis.nsexec.dll=${nsis.home}/Plugins/nsExec.dll
+nsis.nsisdl.dll=${nsis.home}/Plugins/nsisdl.dll
+nsis.loc=${base-sf.loc}/nsis/nsis20.exe
+
+
+# ----- Struts, version 1.2.4 or later -----
+struts.home=${base.path}/struts-1.2.7
+struts.lib=${struts.home}/lib
+struts.jar=${struts.lib}/struts.jar
+struts.loc=${base-struts.loc}/binaries/struts-1.2.7.tar.gz
+
+
+# --------------------------------------------------
+#                OPTIONAL LIBRARIES
+# --------------------------------------------------
+
+
+# ----- Java Activation Framework (JAF), version 1.0.1 or later -----
+activation.home=${base.path}/jaf-1.0.2
+activation.lib=${activation.home}
+activation.jar=${activation.lib}/activation.jar
+
+# ----- Java Secure Sockets Extension (JSSE), version 1.0.3 or later -----
+jsse.home=${base.path}/jsse-1.0.3
+jsse.lib=${jsse.home}/lib
+jcert.jar=${jsse.lib}/jcert.jar
+jnet.jar=${jsse.lib}/jnet.jar
+jsse.jar=${jsse.lib}/jsse.jar
+
+# ----- Java Transaction API (JTA), version 1.0.1a or later -----
+jta.home=${base.path}/jta-1_0_1b
+jta.lib=${jta.home}
+jta.jar=${jta.lib}/jta.jar
+
+# ----- Java Mail, version 1.2 or later -----
+mail.home=${base.path}/javamail-1.3.3_01
+mail.lib=${mail.home}
+mail.jar=${mail.lib}/mail.jar
+
+# ----- Java Activation Framework, version 1.0.1 or later -----
+activation.home=${base.path}/jaf-1.0.2
+activation.lib=${activation.home}
+activation.jar=${activation.lib}/activation.jar
+
+# ----- PureTLS Extension, version 0.9 or later -----
+puretls.home=${base.path}/puretls-0.9b4
+puretls.lib=${puretls.home}/build
+puretls.jar=${puretls.lib}/puretls.jar
+
+# ----- Servlet API v2.4 -----
+servlet-api.home=${base.path}/servlet-api-2.4
+servlet-api.lib=${servlet-api.home}/lib
+servlet-api.jar=${servlet-api.lib}/servlet-api.jar
+
+# ----- JSP API v2.0 -----
+jsp-api.home=${base.path}/jsp-api-2.0
+jsp-api.lib=${jsp-api.home}/lib
+jsp-api.jar=${jsp-api.lib}/jsp-api.jar

Added: branches/tomcat5.5/upstream/5.5.20/build/build.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/build/build.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/build/build.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,2067 @@
+<project name="Tomcat 5.5" default="deploy" basedir=".">
+
+
+  <!-- ===================== Initialize Property Values =================== -->
+
+  <!-- See "build.properties.sample" in the top level directory for all     -->
+  <!-- property values you must customize for successful building!!!        -->
+  <property file="${user.home}/build.properties"/>
+  <property file="build.properties"/>
+
+  <property file="build.properties.default"/>
+
+  <!-- Project Properties -->
+  <property name="name"                  value="Apache Tomcat" />
+  <property name="year"                  value="2005" />
+  <property name="version.major"         value="5" />
+  <property name="version.minor"         value="5" />
+  <property name="version.build"         value="0" />
+  <property name="version.patch"         value="0" />
+  <property name="version"               value="5.5.0-dev" />
+  <property name="version.number"        value="${version.major}.${version.minor}.${version.build}.${version.patch}" />
+
+  <property name="project"               value="apache-tomcat" />
+  <property name="final.name"            value="${project}-${version}" />
+  <property name="final-src.name"        value="${project}-${version}-src" />
+
+  <!-- Subprojects -->
+  <property name="api.project"           value="servletapi" />
+  <property name="tomcat.project"        value="build" />
+  <property name="catalina.project"      value="container" />
+  <property name="jtc.project"           value="connectors" />
+  <property name="jasper.project"        value="jasper" />
+  <property name="ant.jar"               value="${ant.home}/lib/ant.jar"/>
+  <property name="ant-launcher.jar"      value="${ant.home}/lib/ant-launcher.jar"/>
+
+  <!-- Source dependencies -->
+  <property name="api.home"
+           value="${basedir}/../${api.project}"/>
+  <property name="catalina.home"
+           value="${basedir}/../${catalina.project}"/>
+  <property name="jasper.home"
+           value="${basedir}/../${jasper.project}"/>
+  <property name="jtc.home"
+           value="${basedir}/../${jtc.project}"/>
+  <property name="tomcat.home"
+           value="${basedir}/../${tomcat.project}"/>
+
+  <!-- Build Defaults -->
+  <property name="catalina.build"   value="${catalina.home}/build"/>
+  <property name="jasper.build"     value="${jasper.home}/build"/>
+  <property name="tomcat.build"     value="${basedir}/build"/>
+  <property name="build.home"       value="${tomcat.build}"/>
+
+  <property name="tomcat.dist"      value="${basedir}/dist"/>
+  <property name="tomcat.embed"     value="${basedir}/embed"/>
+  <property name="tomcat.compat"    value="${basedir}/compat"/>
+  <property name="tomcat.deployer"  value="${basedir}/deployer"/>
+  <property name="tomcat.release"   value="${basedir}/release"/>
+  <property name="webapps.build"    value="${catalina.home}/webapps/build"/>
+  <property name="webapps.dist"     value="${catalina.home}/webapps/dist"/>
+  <property name="tomcat-dbcp.home" value="${base.path}/tomcat-deps" />
+  <property name="tomcat-dbcp.jar"
+       value="${tomcat-dbcp.home}/naming-factory-dbcp.jar"/>
+  <property name="jasper-compiler-jdt.home" value="${base.path}/tomcat-deps" />
+  <property name="jasper-compiler-jdt.jar"
+       value="${jasper-compiler-jdt.home}/jasper-compiler-jdt.jar"/>
+
+  <!-- Some compilers will disable debugging if true. And it doesn't do anything
+       in most cases -->
+  <property name="compile.optimize"     value="false"/>
+  <property name="compile.debug"        value="true" />
+  <property name="compile.deprecation"  value="false" />
+  <property name="compile.source"       value="1.4" />
+  <property name="tester.delay"         value="8" />
+  
+  <!-- constant to declare a file binary for md5sum -->
+  <property name="md5sum.binary-prefix" value=" *" />
+
+  <!-- =================== DETECT: Display configuration ================== -->
+  <target name="detect"
+   description="Display configuration and conditional compilation flags">
+
+    <echo message="--- ${name} ${version} Build ---"/>
+    <echo message="api.home=${api.home}"/>
+    <echo message="catalina.home=${catalina.home}"/>
+    <echo message="jasper.home=${jasper.home}"/>
+    <echo message="jtc.home=${jtc.home}"/>
+
+    <ant dir="${catalina.home}" target="flags.display"/>
+
+  </target>
+
+
+  <!-- ===================== DEPLOY: Create Directories =================== -->
+  <target name="init">
+    <mkdir dir="${tomcat.build}"/>
+    <mkdir dir="${tomcat.build}/classes" />
+    <mkdir dir="${tomcat.build}/server/lib" />
+    <mkdir dir="${tomcat.build}/common/lib" />
+
+    <uptodate property="servletapi.build.notrequired"
+              targetfile="${servlet-api.jar}">
+      <srcfiles dir="${api.home}/jsr154/src" includes="**" />
+    </uptodate>
+
+    <uptodate property="jspapi.build.notrequired"
+              targetfile="${jsp-api.jar}">
+      <srcfiles dir="${api.home}/jsr152/src" includes="**" />
+    </uptodate>
+
+    <uptodate property="tomcatutil.build.notrequired"
+              targetfile="${tomcat.build}/server/lib/tomcat-util.jar">
+      <srcfiles dir="${jtc.home}/util/java" includes="**" />
+    </uptodate>
+
+    <uptodate property="tomcatjk.build.notrequired"
+              targetfile="${tomcat.build}/server/lib/tomcat-ajp.jar">
+      <srcfiles dir="${jtc.home}/jk/java" includes="**" />
+    </uptodate>
+
+   <uptodate property="tomcatjkstatus.build.notrequired"
+              targetfile="${tomcat.build}/server/lib/tomcat-jkstatus-ant.jar">
+      <srcfiles dir="${jtc.home}/jk/jkstatus/src/share" includes="**" />
+    </uptodate>
+
+    <uptodate property="tomcatcoyote.build.notrequired"
+              targetfile="${tomcat.build}/server/lib/tomcat-coyote.jar">
+      <srcfiles dir="${jtc.home}/coyote/src" includes="**" />
+    </uptodate>
+
+    <uptodate property="tomcathttp11.build.notrequired"
+              targetfile="${tomcat.build}/server/lib/tomcat-http11.jar">
+      <srcfiles dir="${jtc.home}/http11/src" includes="**" />
+    </uptodate>
+
+    <uptodate property="admin.build.notrequired"
+              targetfile="${tomcat.build}/server/webapps/admin/WEB-INF/web.xml">
+      <srcfiles dir="${catalina.home}/webapps/admin" includes="**" />
+    </uptodate>
+
+  </target>
+
+
+  <!-- ====================== DEPLOY: Copy Static Files =================== -->
+  <target name="deploy-static" depends="init">
+    <copy file="${jsp-api.jar}"  todir="${tomcat.build}/common/lib"/>
+    <copy file="${servlet-api.jar}" todir="${tomcat.build}/common/lib"/>
+
+    <copy file="${commons-el.jar}"
+          todir="${tomcat.build}/common/lib"/>
+
+    <copy todir="${tomcat.build}/bin"
+           file="${commons-logging-api.jar}" />
+
+    <copy todir="${tomcat.build}/server/lib" file="${commons-modeler.jar}" />
+
+    <copy todir="${tomcat.build}/bin" file="${commons-daemon.jar}" />
+    <copy todir="${tomcat.build}/bin" file="${commons-daemon.jsvc.tar.gz}"
+            failonerror="false" />
+
+    <copy tofile="${tomcat.build}/bin/tomcat-native.tar.gz"
+            file="${tomcat-native.tar.gz}" />
+
+    <!-- <copy todir="${tomcat.build}/common/lib" file="${ant.jar}"/>
+    <copy todir="${tomcat.build}/common/lib" file="${ant-launcher.jar}"/> -->
+    <copy todir="${tomcat.build}/common/lib" file="${jasper-compiler-jdt.jar}"/>
+  </target>
+
+  <!-- ====================== Build all components =================== -->
+  <target name="build-servletapi" unless="servletapi.build.notrequired" description="Build servlet API">
+    <echo>========== Building: ${servlet-api.jar}</echo>
+    <ant dir="${api.home}/jsr154" target="dist" >
+      <property name="servlet-api.dist" value="${servlet-api.home}" />
+    </ant>
+  </target>
+
+  <target name="build-jspapi" unless="jspapi.build.notrequired" description="Build JSP API">
+    <echo>========== Building: ${jsp-api.jar}</echo>
+    <ant dir="${api.home}/jsr152" target="dist">
+        <property name="jsp-api.dist" value="${jsp-api.home}" />
+    </ant>
+  </target>
+
+  <target name="build-tomcatutil" unless="tomcatutil.build.notrequired" description="Build j-t-c/util">
+    <echo>========== Building: tomcat-util to ${tomcat.build} </echo>
+
+    <ant dir="${jtc.home}/util" target="build-main">
+       <property name="jmx.jar" value="${jmx.jar}" />
+       <property name="puretls.jar" value="${puretls.jar}" />
+       <property name="jsse.lib" value="${jsse.lib}" />
+
+       <property name="tomcat-util.build" value="${tomcat.build}" />
+       <property name="tomcat-util.lib" value="${tomcat.build}/server/lib" />
+    </ant>
+
+  </target>
+
+  <target name="build-tomcatjk" unless="tomcatjk.build.notrequired"
+          description="build j-t-c/jk" >
+    <echo>========== Building: tomcat-jk ${catalina.build} </echo>
+
+    <ant dir="${jtc.home}/jk" target="jkjava">
+      <property name="tomcat5.home" value="${catalina.build}"/>
+      <property name="tomcat5.detect" value="true"/>
+      <property name="commons-logging.jar" value="${commons-logging.jar}"/>
+      <property name="jmx.jar" value="${jmx.jar}"/>
+      <property name="jmx.detect" value="true"/>
+
+      <property name="jk.build" value="${tomcat.build}"/>
+
+      <property name="tomcat-coyote.jar" value="${tomcat.build}/server/lib/tomcat-coyote.jar" />
+        <!--
+      <property name="tomcat-coyote.jar" value="${tomcat.build}/server/lib/tomcat-coyote.jar" />
+      <property name="tomcat-jk2.jar" value="${tomcat.build}/server/lib/tomcat-ajp.jar" />
+      <property name="tomcat-jk.jar" value="${tomcat.build}/server/lib/tomcat-jk.jar" />
+      <property name="tomcat-jkconfig.jar" value="${tomcat.build}/server/lib/jkconfig.jar" />
+      <property name="tomcat-jkshm.jar" value="${tomcat.build}/server/lib/jkshm.jar" />
+      <property name="tomcat-jni.jar" value="${tomcat.build}/server/lib/tomcat-jni.jar" />
+      -->
+
+    </ant>
+
+    <!--
+    <copy file="${jtc.home}/jk/conf/jk2.properties"
+        todir="${tomcat.build}/conf" />
+    -->
+
+    <!-- Protocol handlers - AJP -->
+    <jar jarfile="${tomcat.build}/server/lib/tomcat-ajp.jar" index="true">
+      <fileset dir="${tomcat.build}/classes">
+        <include name="org/apache/coyote/ajp/**" />
+        <include name="org/apache/jk/**" />
+        <exclude name="org/apache/jk/ant/**" />
+        <!-- Javadoc and i18n exclusions -->
+        <exclude name="**/package.html" />
+        <exclude name="**/LocalStrings_*" />
+      </fileset>
+    </jar>
+
+  </target>
+
+  <target name="build-tomcatcoyote"
+          unless="tomcatcoyote.build.notrequired"
+          depends="init" description="Build j-t-c/coyote">
+    <echo>========== Building: tomcat-coyote </echo>
+
+    <ant dir="${jtc.home}/coyote" target="compile.tomcat5">
+      <property name="catalina.home" value="${tomcat.build}"/>
+      <property name="build.home" value="${tomcat.build}"/>
+      <property name="tomcat5.detect" value="true"/>
+      <property name="tomcat-util.jar"
+                value="${tomcat.build}/server/lib/tomcat-util.jar"/>
+      <property name="servlet.jar"   value="${servlet-api.jar}"/>
+    </ant>
+
+    <!-- Coyote API -->
+    <delete file="${tomcat.build}/server/lib/tomcat-coyote.jar" />
+    <jar jarfile="${tomcat.build}/server/lib/tomcat-coyote.jar" index="true">
+      <fileset dir="${tomcat.build}/classes">
+        <include name="org/apache/coyote/*" />
+        <include name="org/apache/coyote/memory/*" />
+        <!-- Javadoc and i18n exclusions -->
+        <exclude name="**/package.html" />
+        <exclude name="**/LocalStrings_*" />
+      </fileset>
+    </jar>
+
+  </target>
+
+  <target name="build-tomcatjkstatus" 
+          unless="tomcatjkstatus.build.notrequired" 
+          depends="init" description="Build j-t-c/jkstatus">
+    <echo>========== Building: tomcat-jkstatus-ant </echo>
+
+    <ant dir="${jtc.home}/jk/jkstatus" target="dist">
+      <property name="catalina.build" value="${tomcat.build}"/>
+      <property name="jtc.home" value="${jtc.home}"/>
+    </ant>
+
+  	<!-- jkstatus ant API -->
+  	<!--<delete file="${tomcat.build}/server/lib/tomcat-jkstatus-ant.jar" />-->
+    <ant dir="${jtc.home}/jk/jkstatus" target="copy">
+      <property name="catalina.build" value="${tomcat.build}"/>
+      <property name="jtc.home" value="${jtc.home}"/>
+    </ant>
+
+  </target>
+  
+  <target name="build-tomcathttp11"
+          unless="tomcathttp11.build.notrequired"
+          depends="init" description="builds j-t-c/http11">
+    <echo>========== Building: tomcat-http11 </echo>
+
+    <ant dir="${jtc.home}/http11" target="compile-only">
+      <property name="build.home" value="${tomcat.build}"/>
+      <!--
+      <property name="tomcat-http11.jar" value="${tomcat.build}/server/lib/tomcat-http11.jar"/>
+      <property name="tomcat-coyote.jar" value="${tomcat.build}/server/lib/tomcat-coyote.jar" />
+      -->
+      <property name="commons-logging.jar" value="${commons-logging.jar}"/>
+    </ant>
+
+    <!-- Protocol handlers - HTTP -->
+    <jar jarfile="${tomcat.build}/server/lib/tomcat-http.jar" index="true">
+      <fileset dir="${tomcat.build}/classes">
+        <include name="org/apache/coyote/http11/**" />
+        <!-- Javadoc and i18n exclusions -->
+        <exclude name="**/package.html" />
+        <exclude name="**/LocalStrings_*" />
+      </fileset>
+    </jar>
+
+  </target>
+
+      <target name="build-tomcatapr"
+              unless="tomcatapr.build.notrequired"
+              depends="init" description="builds j-t-c/apr">
+        <echo>========== Building: tomcat-apr </echo>
+
+        <ant dir="${jtc.home}/jni" target="compile-only">
+          <property name="build.home" value="${tomcat.build}"/>
+          <!--
+          <property name="tomcat-http11.jar" value="${tomcat.build}/server/lib/tomcat-http11.jar"/>
+          <property name="tomcat-coyote.jar" value="${tomcat.build}/server/lib/tomcat-coyote.jar" />
+          -->
+          <property name="commons-logging.jar" value="${commons-logging.jar}"/>
+        </ant>
+
+        <!-- APR -->
+        <jar jarfile="${tomcat.build}/server/lib/tomcat-apr.jar" index="true">
+          <fileset dir="${tomcat.build}/classes">
+            <include name="org/apache/tomcat/jni/**" />
+            <!-- Javadoc and i18n exclusions -->
+            <exclude name="**/package.html" />
+            <exclude name="**/LocalStrings_*" />
+          </fileset>
+        </jar>
+
+      </target>
+
+      <target name="build-juli"
+              unless="tomcatjuli.build.notrequired"
+              depends="init" description="builds j-t-c/juli">
+        <echo>========== Building: tomcat-juli </echo>
+
+        <ant dir="${jtc.home}/juli" target="compile-only">
+          <property name="build.home" value="${tomcat.build}"/>
+        </ant>
+
+        <!-- Java.util.logging Implementation -->
+        <jar jarfile="${tomcat.build}/bin/tomcat-juli.jar" index="true">
+          <fileset dir="${tomcat.build}/classes">
+            <include name="org/apache/juli/**" />
+            <!-- Javadoc and i18n exclusions -->
+            <exclude name="**/package.html" />
+            <exclude name="**/LocalStrings_*" />
+          </fileset>
+        </jar>
+
+        <copy file="${basedir}/resources/logging.properties"
+             todir="${tomcat.build}/conf" />
+
+      </target>
+
+  <target name="build-jasper"
+          unless="jasper.build.notrequired"
+          depends="init" description="build jasper">
+    <echo>========== Building: jasper </echo>
+
+    <ant dir="${jasper.home}"   target="build-only">
+      <property name="jasper.classes" value="${tomcat.build}/classes"/>
+      <property name="jasper.build" value="${tomcat.build}"/>
+      <property name="jasper-compiler.jar" value="${tomcat.build}/common/lib/jasper-compiler.jar"/>
+      <property name="jasper-runtime.jar" value="${tomcat.build}/common/lib/jasper-runtime.jar"/>
+      <property name="catalina.home" value="${tomcat.build}"/>
+      <property name="commons-el.jar" location="${commons-el.jar}" />
+    </ant>
+  </target>
+
+  <target name="build-admin" unless="admin.build.notrequired"
+          depends="init" description="build admin" >
+
+    <echo>========== Building: admin </echo>
+    <ant dir="${catalina.home}/webapps/admin" target="build-main">
+        <property name="webapps.build" value="${tomcat.build}/server/webapps" />
+        <property name="classes.dir" value="${tomcat.build}/classes" />
+        <property name="tomcat-util.jar" value="${tomcat.build}/server/lib/tomcat-util.jar"/>
+        <property name="catalina.deploy" value="${tomcat.build}" />
+        <property name="flags.hide" value="true" />
+    </ant>
+
+    <touch file="${tomcat.build}/server/webapps/admin/WEB-INF/web.xml" />
+  </target>
+
+  <target name="build-webapps-precompile"
+          depends="init" description="Precompile webapps" >
+
+    <!-- JSPC -->
+    <property name="admin.base" location="${tomcat.build}/server/webapps/admin" />
+    <property name="ROOT.base" location="${tomcat.build}/webapps/ROOT" />
+    <property name="jsp-examples.base" location="${tomcat.build}/webapps/jsp-examples" />
+
+    <mkdir dir="${admin.base}/WEB-INF/src/admin" />
+    <mkdir dir="${ROOT.base}/WEB-INF/src" />
+    <mkdir dir="${ROOT.base}/WEB-INF/classes" />
+    <mkdir dir="${jsp-examples.base}/WEB-INF/src" />
+
+    <path id="jspc.classpath">
+      <pathelement location="${java.home}/../lib/tools.jar"/>
+      <pathelement location="${commons-logging.jar}"/>
+      <pathelement location="${tomcat.build}/server/classes"/>
+      <fileset dir="${tomcat.build}/server/lib">
+        <include name="*.jar"/>
+      </fileset>
+      <pathelement location="${tomcat.build}/common/classes"/>
+      <fileset dir="${tomcat.build}/common/lib">
+        <include name="*.jar"/>
+      </fileset>
+      <pathelement location="${tomcat.build}/common/classes"/>
+      <fileset dir="${tomcat.build}/common/endorsed">
+        <include name="*.jar"/>
+      </fileset>
+      <fileset dir="${tomcat.build}/common/lib">
+        <include name="*.jar"/>
+      </fileset>
+    </path>
+
+    <taskdef classname="org.apache.jasper.JspC" name="jasper2" >
+      <classpath refid="jspc.classpath"/>
+    </taskdef>
+
+    <jasper2
+             compile="false"
+             validateXml="false"
+             uriroot="${ROOT.base}"
+             webXmlFragment="${ROOT.base}/WEB-INF/generated_web.xml"
+             addWebXmlMappings="true"
+             outputDir="${ROOT.base}/WEB-INF/src" />
+
+    <jasper2
+             compile="false"
+             validateXml="false"
+             uriroot="${jsp-examples.base}"
+         webXmlFragment="${jsp-examples.base}/WEB-INF/generated_web.xml"
+             addWebXmlMappings="true"
+             outputDir="${jsp-examples.base}/WEB-INF/src" />
+
+    <jasper2
+             package="admin"
+             compile="false"
+             validateXml="false"
+             uriroot="${admin.base}"
+             webXmlFragment="${admin.base}/WEB-INF/generated_web.xml"
+             addWebXmlMappings="true"
+             outputDir="${admin.base}/WEB-INF/src/admin" />
+
+    <javac destdir="${ROOT.base}/WEB-INF/classes"
+           optimize="off"
+           debug="${compile.debug}"
+           deprecation="${compile.deprecation}"
+           source="${compile.source}"
+           failonerror="false"
+           srcdir="${ROOT.base}/WEB-INF/src"
+       excludes="**/*.smap">
+      <classpath>
+        <pathelement location="${java.home}/../lib/tools.jar"/>
+        <fileset dir="${tomcat.build}/server/lib">
+          <include name="*.jar"/>
+        </fileset>
+        <fileset dir="${tomcat.build}/common/lib">
+          <include name="*.jar"/>
+        </fileset>
+        <pathelement location="${tomcat.build}/classes"/>
+      </classpath>
+      <include name="**" />
+    </javac>
+
+    <mkdir dir="${jsp-examples.base}/WEB-INF/src/tags"/>
+    <copy todir="${jsp-examples.base}/WEB-INF/classes">
+      <fileset dir="${jsp-examples.base}/WEB-INF/src">
+        <include name="**/*.class" />
+      </fileset>
+    </copy>
+
+    <javac destdir="${jsp-examples.base}/WEB-INF/classes"
+           optimize="off"
+           debug="${compile.debug}"
+           deprecation="${compile.deprecation}"
+           source="${compile.source}"
+           failonerror="false"
+           srcdir="${jsp-examples.base}/WEB-INF/src"
+       excludes="**/*.smap">
+      <classpath>
+        <pathelement location="${java.home}/../lib/tools.jar"/>
+        <fileset dir="${tomcat.build}/server/lib">
+          <include name="*.jar"/>
+        </fileset>
+        <fileset dir="${jsp-examples.base}/WEB-INF/lib">
+          <include name="*.jar"/>
+        </fileset>
+        <fileset dir="${tomcat.build}/common/lib">
+          <include name="*.jar"/>
+        </fileset>
+        <pathelement location="${tomcat.build}/classes"/>
+        <pathelement location="${jsp-examples.base}/WEB-INF/classes"/>
+      </classpath>
+      <include name="**" />
+      <exclude name="tags/**" />
+    </javac>
+
+    <javac destdir="${admin.base}/WEB-INF/classes"
+           optimize="off"
+           debug="${compile.debug}"
+           deprecation="${compile.deprecation}"
+           source="${compile.source}"
+           failonerror="false"
+           srcdir="${admin.base}/WEB-INF/src"
+       excludes="**/*.smap">
+      <classpath>
+        <pathelement location="${java.home}/../lib/tools.jar"/>
+        <fileset dir="${tomcat.build}/server/lib">
+          <include name="*.jar"/>
+        </fileset>
+        <fileset dir="${admin.base}/WEB-INF/lib">
+          <include name="*.jar"/>
+        </fileset>
+        <fileset dir="${tomcat.build}/common/lib">
+          <include name="*.jar"/>
+        </fileset>
+        <pathelement location="${tomcat.build}/classes"/>
+      </classpath>
+      <include name="admin/**" />
+    </javac>
+  </target>
+
+  <target name="build-catalina" depends="init" 
+          description="Builds catalina">
+    <echo>========== Building: catalina in ${tomcat.build}</echo>
+
+    <ant dir="${catalina.home}/catalina" target="build-static">
+        <property name="catalina.build" value="${tomcat.build}" />
+        <property name="classes.dir" value="${tomcat.build}/classes" />
+        <property name="tomcat-util.jar"
+                 value="${tomcat.build}/server/lib/tomcat-util.jar"/>
+        <property name="catalina.deploy" value="${tomcat.build}" />
+        <property name="flags.hide" value="true" />
+    </ant>
+
+    <ant dir="${catalina.home}/catalina" target="catalina-jars">
+        <!-- in-place building -->
+        <property name="tomcat-coyote.jar" value="${tomcat.build}/server/lib/tomcat-coyote.jar" />
+        <property name="catalina.build" value="${tomcat.build}" />
+        <property name="classes.dir" value="${tomcat.build}/classes" />
+        <property name="tomcat-util.jar"
+                 value="${tomcat.build}/server/lib/tomcat-util.jar"/>
+        <property name="catalina.deploy" value="${tomcat.build}" />
+        <property name="flags.hide" value="true" />
+    </ant>
+
+    <ant dir="${catalina.home}/catalina" target="deploy-static-only">
+        <property name="catalina.build" value="${tomcat.build}" />
+        <property name="classes.dir" value="${tomcat.build}/classes" />
+        <property name="tomcat-util.jar"
+                 value="${tomcat.build}/server/lib/tomcat-util.jar"/>
+        <property name="catalina.deploy" value="${tomcat.build}" />
+        <property name="flags.hide" value="false" />
+    </ant>
+
+    <ant dir="${catalina.home}/modules" target="build">
+        <property name="catalina.build" value="${tomcat.build}" />
+        <property name="cluster.dist" value="${tomcat.build}/server/lib" />
+        <property name="config.dist" value="${tomcat.build}/server/lib" />
+        <property name="catalina.deploy" value="${tomcat.build}" />
+        <property name="flags.hide" value="true" />
+    </ant>
+
+  </target>
+
+  <target name="build" depends="init"
+          description="Builds all components">
+
+    <antcall target="build-tomcatapr"/>
+    <antcall target="build-tomcatutil"/>
+    <antcall target="build-tomcatcoyote"/>
+    <antcall target="build-tomcathttp11"/>
+
+    <antcall target="build-catalina"/>
+
+    <antcall target="build-tomcatjk"/>
+    <antcall target="build-tomcatjkstatus"/>
+
+    <antcall target="build-juli"/>
+
+    <antcall target="build-jasper"/>
+
+    <antcall target="build-i18n"/>
+
+    <!-- Correct permissions and line endings on "bin" scripts -->
+    <fixcrlf srcdir="${tomcat.build}/bin"   includes="*.sh"  eol="lf"/>
+    <fixcrlf srcdir="${tomcat.build}/bin"   includes="*.bat" eol="crlf"/>
+    <chmod      dir="${tomcat.build}/bin"   includes="*.sh"  perm="+x"/>
+
+  </target>
+
+  <target name="build-i18n">
+
+    <!-- i18n JARs -->
+    <jar jarfile="${tomcat.build}/common/i18n/tomcat-i18n-es.jar">
+      <fileset dir="${tomcat.build}/classes">
+        <include name="**/LocalStrings_es.properties" />
+        <exclude name="**/tomcat4/**" />
+      </fileset>
+    </jar>
+    <jar jarfile="${tomcat.build}/common/i18n/tomcat-i18n-fr.jar">
+      <fileset dir="${tomcat.build}/classes">
+        <include name="**/LocalStrings_fr.properties" />
+        <exclude name="**/tomcat4/**" />
+      </fileset>
+    </jar>
+    <jar jarfile="${tomcat.build}/common/i18n/tomcat-i18n-ja.jar">
+      <fileset dir="${tomcat.build}/classes">
+        <include name="**/LocalStrings_ja.properties" />
+        <exclude name="**/tomcat4/**" />
+      </fileset>
+    </jar>
+
+    <!-- Build baseline _en bundle to ease -->
+    <copy todir="${tomcat.build}/classes" includeemptydirs="false">
+      <fileset dir="${tomcat.build}/classes">
+        <include name="**/LocalStrings.properties"/>
+      </fileset>
+      <mapper type="glob" from="*.properties" to="*_en.properties"/>
+    </copy>
+    <jar jarfile="${tomcat.build}/common/i18n/tomcat-i18n-en.jar">
+      <fileset dir="${tomcat.build}/classes">
+        <include name="**/LocalStrings_en.properties" />
+        <exclude name="**/tomcat4/**" />
+      </fileset>
+    </jar>
+
+  </target>
+
+  <!-- ====================== Build dependent code =================== -->
+
+  <target name="build-all" depends="init,deploy-static,build,build-webapps,compat,deployer"
+          description="build tomcat, webapps, embed, compat, deployer" />
+
+
+  <target name="build-depends" depends="init"
+          description="Builds various dependent components - APIs, commons-el, commons-modeler, daemon">
+    <antcall target="build-servletapi"/>
+    <antcall target="build-jspapi"/>
+
+    <!-- <antcall target="build-commons-modeler" /> -->
+    <!-- <antcall target="build-commons-daemon"  /> -->
+
+    <antcall target="downloadgz">
+      <param name="sourcefile" value="${commons-collections-src.loc}"/>
+      <param name="destfile" value="${tomcat-dbcp.jar}" />
+    </antcall>
+    <antcall target="downloadgz">
+      <param name="sourcefile" value="${commons-pool-src.loc}"/>
+      <param name="destfile" value="${tomcat-dbcp.jar}" />
+    </antcall>
+    <antcall target="downloadgz">
+      <param name="sourcefile" value="${commons-dbcp-src.loc}"/>
+      <param name="destfile" value="${tomcat-dbcp.jar}" />
+    </antcall>
+
+    <antcall target="build-tomcat-dbcp" />
+
+    <antcall target="downloadzip">
+      <param name="sourcefile" value="${jdt.loc}"/>
+      <param name="destfile" value="${jdt.jar}"/>
+      <param name="destdir" value="${base.path}"/>
+    </antcall>
+    <antcall target="build-jasper-compiler-jdt" />
+  </target>
+
+  <target name="build-tomcat-dbcp">
+   <mkdir dir="${tomcat-dbcp.home}"/>
+   <antcall target="-build-tomcat-dbcp">
+      <param name="basedir" value="${tomcat-dbcp.home}" />
+   </antcall>
+  </target>
+
+  <target name="-build-tomcat-dbcp">
+    <copy todir="${tomcat-dbcp.home}">
+        <fileset dir="${commons-collections.home}" >
+            <include name="**/collections/CursorableLinkedList.java" />
+            <include name="**/collections/KeyValue.java" />
+            <include name="**/collections/LRUMap.java" />
+            <include name="**/collections/SequencedHashMap.java" />
+        </fileset>
+        <fileset dir="${commons-pool.home}">
+            <include name="**/*.java" />
+            <exclude name="**/Stack*.java" />
+            <exclude name="**/SoftReferenceObjectPool.java" />
+            <exclude name="**/test/**" />
+        </fileset>
+        <fileset dir="${commons-dbcp.home}">
+            <include name="**/*.java" />
+            <exclude name="**/test/**" />
+        </fileset>
+    </copy>
+    <replace dir="${tomcat-dbcp.home}/src/java/org/apache/commons">
+        <replacefilter token="return UnmodifiableList.decorate(l);"
+            value="return l;" />
+        <replacefilter token="import org.apache.commons.collections.list.UnmodifiableList;"
+            value=" " />
+    </replace>
+    <replace dir="${tomcat-dbcp.home}/src/java/org/apache/commons" >
+        <replacefilter token="org.apache.commons"
+            value="org.apache.tomcat.dbcp" />
+    </replace>
+    <mkdir dir="${tomcat-dbcp.home}/src/java/org/apache/tomcat/dbcp" />
+    <move todir="${tomcat-dbcp.home}/src/java/org/apache/tomcat/dbcp">
+        <fileset dir="${tomcat-dbcp.home}/src/java/org/apache/commons" />
+    </move>
+    <mkdir dir="${tomcat-dbcp.home}/classes"/>
+    <javac destdir="classes"
+           optimize="off"
+           debug="${compile.debug}"
+           deprecation="${compile.deprecation}"
+           source="${compile.source}"
+           sourcepath="${tomcat-dbcp.home}/src/java"
+           srcdir="src/java" >
+      <include name="**" />
+    </javac>
+    <jar jarfile="${tomcat-dbcp.jar}"
+         index="true">
+       <fileset dir="${tomcat-dbcp.home}/classes">
+          <include name="**/*.class" />
+          <include name="**/*.properties" />
+       </fileset>
+    </jar>
+  </target>
+
+      <target name="build-jasper-compiler-jdt">
+       <mkdir dir="${jasper-compiler-jdt.home}"/>
+       <antcall target="-build-jasper-compiler-jdt">
+          <param name="basedir" value="${jasper-compiler-jdt.home}" />
+       </antcall>
+      </target>
+
+      <target name="-build-jasper-compiler-jdt">
+        <unjar src="${jdt.jar}" dest="${jasper-compiler-jdt.home}" />
+        <jar destfile="${jasper-compiler-jdt.jar}" index="true">
+            <fileset dir="${jasper-compiler-jdt.home}">
+                <include name="org/eclipse/jdt/core/compiler/**"/>
+                <include name="org/eclipse/jdt/internal/compiler/**"/>
+                <include name="org/eclipse/jdt/internal/core/util/CommentRecorder*"/>
+            </fileset>
+        </jar>
+      </target>
+
+  <target name="build-webapps" depends="init"
+          description="build  webapps">
+
+    <echo>========== Building: webapps </echo>
+
+    <mkdir dir="${tomcat.build}/webapps" />
+    <mkdir dir="${tomcat.build}/server/webapps" />
+
+    <!-- The build files are far too difficult to hack - just build it and copy -->
+    <ant dir="${api.home}/jsr154" target="dist">
+    </ant>
+    <ant dir="${api.home}/jsr152" target="dist">
+    </ant>
+
+    <mkdir dir="${tomcat.build}/webapps/servlets-examples"/>
+    <copy todir="${tomcat.build}/webapps/servlets-examples">
+      <fileset dir="${api.home}/jsr154/build/examples" includes="**"/>
+    </copy>
+
+    <mkdir dir="${tomcat.build}/webapps/jsp-examples"/>
+    <copy todir="${tomcat.build}/webapps/jsp-examples">
+      <fileset dir="${api.home}/jsr152/build/examples">
+        <exclude name="WEB-INF/tagPlugins.xml" />
+      </fileset>
+    </copy>
+
+    <ant dir="${catalina.home}/webapps/ROOT" target="build-main">
+        <property name="webapps.build" value="${tomcat.build}/webapps" />
+        <property name="classes.dir" value="${tomcat.build}/classes" />
+        <property name="tomcat-util.jar" value="${tomcat.build}/server/lib/tomcat-util.jar"/>
+        <property name="catalina.deploy" value="${tomcat.build}" />
+        <property name="flags.hide" value="true" />
+    </ant>
+
+    <ant dir="${catalina.home}/webapps/docs" target="build-main">
+        <property name="webapps.build" value="${tomcat.build}/webapps" />
+        <property name="classes.dir" value="${tomcat.build}/classes" />
+        <property name="tomcat-util.jar" value="${tomcat.build}/server/lib/tomcat-util.jar"/>
+        <property name="catalina.deploy" value="${tomcat.build}" />
+        <property name="flags.hide" value="true" />
+    </ant>
+
+    <antcall target="build-admin" />
+
+    <ant dir="${catalina.home}/webapps/manager" target="build-main">
+        <property name="webapps.build" value="${tomcat.build}/server/webapps" />
+        <property name="classes.dir" value="${tomcat.build}/classes" />
+        <property name="tomcat-util.jar" value="${tomcat.build}/server/lib/tomcat-util.jar"/>
+        <property name="catalina.deploy" value="${tomcat.build}" />
+        <property name="flags.hide" value="true" />
+    </ant>
+
+    <ant dir="${catalina.home}/webapps/host-manager" target="build-main">
+        <property name="webapps.build" value="${tomcat.build}/server/webapps" />
+        <property name="classes.dir" value="${tomcat.build}/classes" />
+        <property name="tomcat-util.jar" value="${tomcat.build}/server/lib/tomcat-util.jar"/>
+        <property name="catalina.deploy" value="${tomcat.build}" />
+        <property name="flags.hide" value="true" />
+    </ant>
+
+    <ant dir="${catalina.home}/webapps/balancer" target="build-main">
+        <property name="webapps.build" value="${tomcat.build}/webapps" />
+        <property name="classes.dir" value="${tomcat.build}/classes" />
+        <property name="tomcat-util.jar" value="${tomcat.build}/server/lib/tomcat-util.jar"/>
+        <property name="catalina.deploy" value="${tomcat.build}" />
+        <property name="flags.hide" value="true" />
+    </ant>
+
+    <ant dir="${catalina.home}/webapps/webdav" target="build-main">
+        <property name="webapps.build" value="${tomcat.build}/webapps" />
+    </ant>
+
+    <!-- Precompiling and fixing webapps -->
+    <antcall target="build-webapps-precompile" />
+    <antcall target="fix-webapps" />
+
+  </target>
+
+  <target name="fix-webapps" depends="init" >
+    <!-- Extra build steps for webapps -->
+
+    <filter token="VERSION" value="${version}"/>
+
+    <!-- Add release notes to the root webapp -->
+    <copy file="${basedir}/RELEASE-NOTES"
+        tofile="${tomcat.build}/webapps/ROOT/RELEASE-NOTES.txt"
+        filtering="true" />
+
+    <!-- Add documents to the tomcat-docs webapp -->
+    <copy file="${basedir}/resources/build.xml"
+        todir="${tomcat.build}/webapps/tomcat-docs" />
+    <copy file="./RELEASE-NOTES"
+        tofile="${tomcat.build}/webapps/tomcat-docs/RELEASE-NOTES.txt"
+        filtering="true" />
+
+    <!-- Build JARs for webapps classes -->
+    <mkdir dir="${tomcat.build}/server/webapps/admin/WEB-INF/lib" />
+    <jar jarfile="${tomcat.build}/server/webapps/admin/WEB-INF/lib/catalina-admin.jar"
+         index="true">
+       <fileset dir="${tomcat.build}/server/webapps/admin/WEB-INF/classes">
+          <include name="**/*.class" />
+          <include name="**/*.properties" />
+       </fileset>
+    </jar>
+    <mkdir dir="${tomcat.build}/server/webapps/manager/WEB-INF/lib" />
+    <jar jarfile="${tomcat.build}/server/webapps/manager/WEB-INF/lib/catalina-manager.jar"
+         index="true">
+       <fileset dir="${tomcat.build}/server/webapps/manager/WEB-INF/classes">
+          <include name="**/*.class" />
+          <include name="**/*.properties" />
+       </fileset>
+    </jar>
+    <mkdir dir="${tomcat.build}/server/webapps/host-manager/WEB-INF/lib" />
+    <jar jarfile="${tomcat.build}/server/webapps/host-manager/WEB-INF/lib/catalina-host-manager.jar"
+         index="true">
+       <fileset dir="${tomcat.build}/server/webapps/host-manager/WEB-INF/classes">
+          <include name="**/*.class" />
+          <include name="**/*.properties" />
+       </fileset>
+    </jar>
+    <mkdir dir="${tomcat.build}/webapps/balancer/WEB-INF/lib" />
+    <jar jarfile="${tomcat.build}/webapps/balancer/WEB-INF/lib/catalina-balancer.jar"
+         index="true">
+       <fileset dir="${tomcat.build}/webapps/balancer/WEB-INF/classes">
+          <include name="**/*.class" />
+          <include name="**/*.properties" />
+       </fileset>
+    </jar>
+    <mkdir dir="${tomcat.build}/webapps/ROOT/WEB-INF/lib" />
+    <jar jarfile="${tomcat.build}/webapps/ROOT/WEB-INF/lib/catalina-root.jar"
+         index="true">
+       <fileset dir="${tomcat.build}/webapps/ROOT/WEB-INF/classes">
+          <include name="**/*.class" />
+          <include name="**/*.properties" />
+       </fileset>
+    </jar>
+
+    <!-- Add XML declarations for admin, manager and balancer -->
+    <copy file="${tomcat.build}/server/webapps/manager/manager.xml"
+         todir="${tomcat.build}/conf/Catalina/localhost" />
+    <copy file="${tomcat.build}/server/webapps/host-manager/host-manager.xml"
+         todir="${tomcat.build}/conf/Catalina/localhost" />
+    <copy file="${tomcat.build}/server/webapps/admin/admin.xml"
+         todir="${tomcat.build}/conf/Catalina/localhost" />
+
+  </target>
+
+  <!-- ====================== Embed target =================== -->
+
+  <target name="embed" description="Create a set of jars for embedded tomcat" >
+
+    <!-- Generic libraries -->
+    <copy todir="embed/lib" file="${commons-logging.jar}"/>
+    <copy todir="embed/lib" file="${commons-modeler.jar}"/>
+
+    <!-- Connector -->
+    <copy todir="embed/lib">
+      <fileset dir="build/server/lib">
+        <!--<include name="tomcat-ajp.jar"/>-->
+        <include name="tomcat-coyote.jar"/>
+        <include name="tomcat-http.jar"/>
+        <include name="tomcat-util.jar"/>
+      </fileset>
+    </copy>
+
+    <!-- Servlet API implementation -->
+    <copy todir="embed/lib">
+      <fileset dir="build/common/lib">
+        <include name="naming-factory.jar"/>
+        <include name="servlet-api.jar"/>
+        <include name="naming-resources.jar"/>
+      </fileset>
+      <fileset dir="build/server/lib">
+        <include name="catalina.jar"/>
+        <include name="catalina-optional.jar"/>
+        <include name="servlets-default.jar"/>
+      </fileset>
+    </copy>
+
+    <!-- JNDI extra
+    <copy todir="embed/lib">
+      <fileset dir="build/common/lib">
+        <include name="naming-factory.jar"/>
+      </fileset>
+    </copy>
+    -->
+
+    <!-- JSP runtime -->
+    <copy todir="embed/lib">
+      <fileset dir="build/common/lib">
+        <include name="commons-el.jar"/>
+        <include name="jsp-api.jar"/>
+        <include name="jasper-runtime.jar"/>
+      </fileset>
+    </copy>
+
+    <!-- JSP compiler - not needed for an minimal server if it
+         uses precompilation -->
+    <copy todir="embed/lib">
+      <fileset dir="build/common/lib">
+        <include name="jasper-compiler.jar"/>
+        <include name="jasper-compiler-jdt.jar"/>
+      </fileset>
+    </copy>
+
+    <copy tofile="embed/build.xml" file="resources/mbeans/tomcat5-ant.xml" />
+    <!--
+    <copy tofile="embed/tomcat5-mbeans.xml" file="resources/mbeans/tomcat5-mbeans.xml" />
+    <copy tofile="embed/tomcat5-mlet.xml" file="resources/mbeans/tomcat5-mlet.xml" />
+    <copy tofile="embed/tomcat5-service.xml" file="resources/mbeans/tomcat5-service.xml" />
+    -->
+
+    <mkdir dir="embed/conf"/>
+    <delete file="embed/conf/context.xml" />
+    <copy todir="embed/conf">
+      <fileset dir="build/conf">
+         <include name="context.xml"/>
+         <include name="tomcat-users.xml"/>
+         <include name="web.xml"/>
+         <!-- no longer needed
+            <include name="server.xml"/>
+         -->
+      </fileset>
+    </copy>
+    <replace file="embed/conf/context.xml" token="&lt;Context" value="&lt;Context privileged='true'" />
+
+    <mkdir dir="embed/webapps"/>
+    <copy todir="embed/webapps" >
+       <fileset dir="dist/webapps" includes="ROOT/**"/>
+    </copy>
+    <copy todir="embed/webapps" >
+       <fileset dir="dist/server/webapps" includes="manager/**"/>
+    </copy>
+
+  </target>
+
+  <!-- ====================== Deployer target =================== -->
+
+  <target name="deployer" description="Create the Tomcat deployer binary" >
+
+    <!-- Servlet and JSP -->
+    <copy todir="${tomcat.deployer}/lib">
+      <fileset dir="${tomcat.build}/common/lib">
+        <include name="commons-el.jar"/>
+        <include name="jsp-api.jar"/>
+        <include name="jasper-runtime.jar"/>
+        <include name="jasper-compiler.jar"/>
+        <include name="servlet-api.jar"/>
+      </fileset>
+    </copy>
+
+    <!-- Digester and dependencies -->
+    <copy todir="${tomcat.deployer}/lib"
+           file="${tomcat.build}/server/lib/catalina-ant.jar"/>
+    <copy todir="${tomcat.deployer}/lib" file="${commons-logging.jar}"/>
+    <jar jarfile="${tomcat.deployer}/lib/catalina-deployer.jar">
+       <fileset dir="${tomcat.build}/classes">
+          <include name="org/apache/catalina/startup/DigesterFactory.class" />
+          <include name="org/apache/catalina/util/SchemaResolver.class" />
+          <include name="org/apache/catalina/util/StringManager.class" />
+          <include name="org/apache/tomcat/util/*" />
+          <include name="org/apache/tomcat/util/digester/*" />
+          <exclude name="**/package.html" />
+          <exclude name="**/LocalStrings_*" />
+       </fileset>
+    </jar>
+
+    <!-- Main build script -->
+    <copy todir="${tomcat.deployer}">
+      <fileset dir="${basedir}/resources/deployer" />
+    </copy>
+
+    <!-- Copy deployer documentation -->
+    <copy todir="${tomcat.deployer}">
+      <fileset dir="${tomcat.build}/webapps/tomcat-docs">
+        <include name="images/jakarta-logo.gif" />
+        <include name="images/tomcat.gif" />
+      </fileset>
+    </copy>
+    <copy tofile="${tomcat.deployer}/docs/manual.html"
+      file="${tomcat.build}/webapps/tomcat-docs/printer/deployer-howto.html" />
+
+  </target>
+
+  <!-- ====================== Compat target =================== -->
+
+  <target name="compat" description="Create compatibility binaries for JREs before 1.5" >
+
+    <copy todir="${tomcat.compat}/common/endorsed" file="${xercesImpl.jar}"/>
+    <copy todir="${tomcat.compat}/common/endorsed" file="${xml-apis.jar}"/>
+    <copy tofile="${tomcat.compat}/bin/jmx.jar" file="${jmx.jar}"/>
+
+  </target>
+
+  <!-- ====================== DEPLOY: Deploy Components =================== -->
+
+  <target name="deploy" depends="deploy-static,build-all,build-webapps"
+          description="Build and deploy all components" />
+
+  <target name="deploy.old" depends="deploy-static">
+
+    <echo>Target: Modeler - Dist ...</echo>
+    <ant dir="${commons-modeler.home}" target="dist"/>
+
+    <echo>Target: Catalina - Deploy ...</echo>
+    <ant dir="${catalina.home}" target="deploy"/>
+    <!--
+    <antcall target="build-tomcat-coyote"/>
+    <antcall target="build-tomcat-jk"/>
+    <antcall target="build-tomcat-http11"/>
+    <ant dir="${catalina.home}" target="deploy-catalina"/>
+     -->
+    <copy todir="${tomcat.build}">
+      <fileset dir="${catalina.home}/build"/>
+    </copy>
+
+    <filter token="VERSION" value="${version}"/>
+
+    <antcall target="build-jasper"/>
+
+    <!-- Correct permissions and line endings on "bin" scripts -->
+    <fixcrlf srcdir="${tomcat.build}/bin"   includes="*.sh"  eol="lf"/>
+    <fixcrlf srcdir="${tomcat.build}/bin"   includes="*.bat" eol="crlf"/>
+    <chmod      dir="${tomcat.build}/bin"   includes="*.sh"  perm="+x"/>
+
+    <antcall target="fix-webapps"/>
+
+    <!-- Copy the examples webapps -->
+    <copy todir="${tomcat.build}/webapps/jsp-examples">
+      <fileset dir="${api.home}/jsr152/build/examples"/>
+    </copy>
+    <copy todir="${tomcat.build}/webapps/servlets-examples">
+      <fileset dir="${api.home}/jsr154/build/examples"/>
+    </copy>
+
+    <!-- Copy Unix JSVC from commons-daemon -->
+    <copy file="${commons-daemon.jsvc.tar.gz}"
+        tofile="${tomcat.dist}/bin/jsvc.tar.gz" />
+    <copy todir="${tomcat.build}/bin" file="${commons-daemon.jar}" />
+
+    <echo>Target: Webapps precompilation ...</echo>
+
+    <antcall target="build-admin"/>
+
+    <ant dir="." target="build-webapps-precompile" />
+
+  </target>
+
+
+  <!-- ====================== COMBO: Clean All Directories ================ -->
+  <target name="clean"
+   description="Clean all components">
+
+    <delete dir="${tomcat.build}"/>
+
+    <delete dir="${tomcat.embed}"/>
+    <delete dir="${tomcat.compat}"/>
+    <delete dir="${tomcat.deployer}"/>
+
+    <echo>Target: Servlet API - Clean ...</echo>
+    <ant dir="${api.home}/jsr154" target="clean"/>
+
+    <echo>Target: JSP API - Clean ...</echo>
+    <ant dir="${api.home}/jsr152" target="clean"/>
+
+    <echo>Target: Catalina - Clean ...</echo>
+    <ant dir="${catalina.home}" target="clean"/>
+
+    <echo>Target: Jasper - Clean ...</echo>
+    <ant dir="${jasper.home}"   target="clean">
+      <property name="catalina.home" value="${tomcat.build}"/>
+    </ant>
+
+    <delete dir="${tomcat.dist}"/>
+
+  </target>
+
+
+  <!-- ======================= COMBO: Build All Components ================ -->
+  <target name="all"
+          description="Clean, build, and deploy all components">
+
+    <echo>Target: Servlet API - Dist ...</echo>
+    <ant dir="${api.home}/jsr154" target="dist"/>
+
+    <echo>Target: JSP API - Dist ...</echo>
+    <ant dir="${api.home}/jsr152" target="dist"/>
+
+    <echo>Target: Catalina - All ...</echo>
+    <ant dir="${catalina.home}" target="all"/>
+
+    <echo>Target: Jasper - All ...</echo>
+    <ant dir="${jasper.home}"   target="all">
+      <property name="catalina.home" value="${tomcat.build}"/>
+    </ant>
+  </target>
+
+
+  <!-- ======================= COMBO: Test All Components ================= -->
+  <target name="test"
+          description="Unit tests on all components">
+    <echo>Target: Catalina - Test ...</echo>
+    <ant dir="${catalina.home}" target="test"/>
+    <echo>Target: Jasper - Test ...</echo>
+    <ant dir="${jasper.home}"   target="test">
+      <property name="catalina.home" value="${tomcat.build}"/>
+    </ant>
+  </target>
+
+  <!-- ======================= TESTER: Run Catalina Tester Tests=========== -->
+
+   <target name="dist-tester"
+           description="Build the Catalina tester">
+
+    <ant dir="${catalina.home}/tester" target="dist">
+      <property name="tester.deploy" value="${tomcat.build}"/>
+    </ant>
+    <ant dir="${catalina.home}/tester" target="deploy">
+      <property name="tester.deploy" value="${tomcat.build}"/>
+    </ant>
+
+   </target>
+
+   <target name="clean-tester"
+           description="Clean the Catalina tester">
+
+    <ant dir="${catalina.home}/tester" target="clean" />
+
+   </target>
+
+  <target name="run-tester"
+   description="Catalina Tests" depends="dist-tester">
+
+    <!-- For Java 1.4 -->
+    <copy file="${jmx.jar}" tofile="${tomcat.build}/bin/jmx.jar" />
+    <copy todir="${tomcat.build}/common/endorsed" file="${xercesImpl.jar}"/>
+    <copy todir="${tomcat.build}/common/endorsed" file="${xml-apis.jar}"/>
+
+    <parallel>
+
+        <java classname="LauncherBootstrap" fork="yes">
+            <arg value="-launchfile"/>
+            <arg value="catalina.xml"/>
+            <arg value="-verbose"/>
+            <arg value="catalina"/>
+            <arg value="start"/>
+            <classpath>
+                <pathelement path="${java.class.path}"/>
+                <pathelement path="${tomcat.build}/bin"/>
+            </classpath>
+        </java>
+
+        <sequential>
+            <!-- Let tomcat starts before starting Tester -->
+            <sleep seconds="${tester.delay}"/>
+
+            <ant dir="${catalina.home}/tester/dist/bin" antfile="tester.xml"
+                 target="all">
+              <property name="catalina.home" value="${tomcat.build}"/>
+            </ant>
+
+            <java classname="LauncherBootstrap" fork="yes">
+                <arg value="-launchfile"/>
+                <arg value="catalina.xml"/>
+                <arg value="-verbose"/>
+                <arg value="catalina"/>
+                <arg value="stop"/>
+                <classpath>
+                    <pathelement path="${java.class.path}"/>
+                    <pathelement path="${tomcat.build}/bin"/>
+                </classpath>
+            </java>
+        </sequential>
+
+    </parallel>
+
+  </target>
+
+  <!-- ====================== DIST: Create Directories ==================== -->
+  <target name="dist-prepare">
+    <mkdir dir="${tomcat.dist}"/>
+    <mkdir dir="${tomcat.dist}/bin"/>
+    <mkdir dir="${tomcat.dist}/common"/>
+    <mkdir dir="${tomcat.dist}/common/classes"/>
+    <mkdir dir="${tomcat.dist}/common/endorsed"/>
+    <mkdir dir="${tomcat.dist}/common/lib"/>
+    <mkdir dir="${tomcat.dist}/conf"/>
+    <mkdir dir="${tomcat.dist}/logs"/>
+    <mkdir dir="${tomcat.dist}/server"/>
+    <mkdir dir="${tomcat.dist}/server/classes"/>
+    <mkdir dir="${tomcat.dist}/server/lib"/>
+    <mkdir dir="${tomcat.dist}/shared/classes"/>
+    <mkdir dir="${tomcat.dist}/shared/lib"/>
+    <mkdir dir="${tomcat.dist}/webapps"/>
+    <mkdir dir="${tomcat.dist}/work"/>
+    <mkdir dir="${tomcat.dist}/temp"/>
+  </target>
+
+
+  <!-- ====================== DIST: Copy Static Files ===================== -->
+  <target name="dist-static" depends="dist-prepare">
+
+    <!-- Copy the top-level documentation files -->
+    <copy todir="${tomcat.dist}">
+      <fileset dir=".">
+        <include name="INSTALLING.txt"/>
+        <include name="LICENSE"/>
+        <include name="NOTICE"/>
+        <include name="README.txt"/>
+        <include name="RELEASE*"/>
+        <include name="RUNNING.txt"/>
+      </fileset>
+    </copy>
+
+    <!-- Copy the contents of each "build" directory -->
+    <copy todir="${tomcat.dist}/bin">
+      <fileset dir="${tomcat.build}/bin">
+        <exclude name="catalina.xml"/>
+        <exclude name="commons-launcher.jar"/>
+        <exclude name="*-using-launcher.*"/>
+        <exclude name="LauncherBootstrap.class"/>
+        <exclude name="launcher.properties"/>
+      </fileset>
+    </copy>
+    <copy todir="${tomcat.dist}/common/classes">
+      <fileset dir="${tomcat.build}/common/classes" />
+    </copy>
+    <copy todir="${tomcat.dist}/common/endorsed">
+      <fileset dir="${tomcat.build}/common/endorsed" />
+    </copy>
+    <copy todir="${tomcat.dist}/common/i18n">
+      <fileset dir="${tomcat.build}/common/i18n" />
+    </copy>
+    <copy todir="${tomcat.dist}/common/lib">
+      <fileset dir="${tomcat.build}/common/lib" />
+    </copy>
+    <copy todir="${tomcat.dist}/conf">
+      <fileset dir="${tomcat.build}/conf">
+        <exclude name="MANIFEST.MF" />
+        <exclude name="jk2.manifest" />
+        <exclude name="jk2.properties" />
+        <exclude name="jkconf.ant.xml" />
+        <exclude name="jkconfig.manifest" />
+        <exclude name="shm.manifest" />
+        <exclude name="tomcat-jk2.manifest" />
+        <exclude name="uriworkermap.properties" />
+        <exclude name="workers2.properties" />
+        <exclude name="workers2.properties.minimal" />
+        <exclude name="workers.properties" />
+        <exclude name="workers.properties.minimal" />
+      </fileset>
+    </copy>
+    <copy todir="${tomcat.dist}/server/lib">
+      <fileset dir="${tomcat.build}/server/lib" />
+    </copy>
+    <copy todir="${tomcat.dist}/server/webapps">
+      <fileset dir="${tomcat.build}/server/webapps">
+        <exclude name="admin/**/*.jsp" />
+        <exclude name="admin/**/*.jspf" />
+        <exclude name="admin/WEB-INF/classes/**" />
+        <exclude name="admin/WEB-INF/src/**" />
+        <exclude name="manager/WEB-INF/classes/**" />
+        <exclude name="host-manager/WEB-INF/classes/**" />
+      </fileset>
+    </copy>
+<!--
+    <copy todir="${tomcat.dist}/shared/lib">
+      <fileset dir="${tomcat.build}/shared/lib" />
+    </copy>
+-->
+    <copy todir="${tomcat.dist}/webapps">
+      <fileset dir="${tomcat.build}/webapps">
+        <exclude name="**/balancer/WEB-INF/classes/**" />
+        <exclude name="**/ROOT/WEB-INF/classes/**" />
+        <exclude name="**/WEB-INF/src/**" />
+      </fileset>
+    </copy>
+
+    <!-- Bugzilla 37035: http://issues.apache.org/bugzilla/show_bug.cgi?id=37035 -->
+    <touch file="${tomcat.dist}/temp/bugzilla37035-safeToDelete.tmp" />
+
+    <!-- Correct permissions and line endings on "bin" scripts -->
+    <fixcrlf srcdir="${tomcat.dist}/bin"   includes="*.sh"  eol="lf"/>
+    <fixcrlf srcdir="${tomcat.dist}/bin"   includes="*.bat" eol="crlf"/>
+    <chmod      dir="${tomcat.dist}/bin"   includes="*.sh"  perm="+x"/>
+
+  </target>
+
+
+  <!-- ====================== DIST: Create Javadoc ======================== -->
+  <target name="dist-javadoc">
+    <!--
+    <ant dir="${catalina.home}" target="dist-javadoc"/>
+    <mkdir  dir="${tomcat.dist}/webapps/tomcat-docs/catalina/docs/api"/>
+    <copy todir="${tomcat.dist}/webapps/tomcat-docs/catalina/docs/api">
+      <fileset dir="${catalina.build}/javadoc" />
+    </copy>
+    <ant dir="${jasper.home}" target="javadoc"/>
+    <mkdir  dir="${tomcat.dist}/webapps/tomcat-docs/jasper/docs/api"/>
+    <copy todir="${tomcat.dist}/webapps/tomcat-docs/jasper/docs/api">
+      <fileset dir="${jasper.build}/javadoc" />
+    </copy>
+    -->
+    <mkdir  dir="${tomcat.dist}/webapps/tomcat-docs/servletapi"/>
+    <copy todir="${tomcat.dist}/webapps/tomcat-docs/servletapi">
+      <fileset dir="${api.home}/jsr154/dist/docs/api" />
+    </copy>
+    <mkdir  dir="${tomcat.dist}/webapps/tomcat-docs/jspapi"/>
+    <copy todir="${tomcat.dist}/webapps/tomcat-docs/jspapi">
+      <fileset dir="${api.home}/jsr152/dist/docs/api" />
+    </copy>
+  </target>
+
+
+  <!-- ====================== DIST: Create Sources ======================== -->
+  <target name="dist-source">
+
+    <mkdir  dir="${tomcat.dist}/src"/>
+    <mkdir  dir="${tomcat.dist}/src/${api.project}"/>
+    <mkdir  dir="${tomcat.dist}/src/${tomcat.project}"/>
+    <mkdir  dir="${tomcat.dist}/src/${catalina.project}"/>
+    <mkdir  dir="${tomcat.dist}/src/${jtc.project}"/>
+    <mkdir  dir="${tomcat.dist}/src/${jasper.project}"/>
+
+    <!-- Main build file -->
+    <copy todir="${tomcat.dist}/src">
+      <fileset dir="${basedir}/resources">
+        <include name="build.xml" />
+      </fileset>
+    </copy>
+
+    <!-- tomcat-5 source -->
+    <copy todir="${tomcat.dist}/src/${tomcat.project}">
+      <fileset dir="${basedir}">
+        <exclude name="build/**"/>
+        <exclude name="dist/**"/>
+        <exclude name="release/**"/>
+        <exclude name="compat/**"/>
+        <exclude name="deployer/**"/>
+        <exclude name="embed/**"/>
+        <exclude name="build.properties"/>
+      </fileset>
+    </copy>
+
+    <!-- servletapi-5 source -->
+    <copy todir="${tomcat.dist}/src/${api.project}">
+      <fileset dir="${api.home}">
+        <include name="jsr154/**"/>
+        <include name="jsr152/**"/>
+        <exclude name="**/build/**"/>
+        <exclude name="**/dist/**"/>
+        <exclude name="build.properties"/>
+      </fileset>
+    </copy>
+
+    <!-- tomcat container source -->
+    <copy todir="${tomcat.dist}/src/${catalina.project}">
+      <fileset dir="${catalina.home}">
+        <exclude name="**/build/**"/>
+        <exclude name="**/dist/**"/>
+      </fileset>
+    </copy>
+
+    <!-- tomcat jasper source -->
+    <copy todir="${tomcat.dist}/src/${jasper.project}">
+      <fileset dir="${jasper.home}">
+        <exclude name="**/build/**"/>
+        <exclude name="**/dist/**"/>
+      </fileset>
+    </copy>
+
+    <!-- tomcat connectors source -->
+    <copy todir="${tomcat.dist}/src/${jtc.project}">
+      <fileset dir="${jtc.home}">
+        <exclude name="coyote/build/**"/>
+        <exclude name="http11/build/**"/>
+        <exclude name="jk/build/**"/>
+        <exclude name="util/build/**"/>
+        <exclude name="webapp/**"/>
+        <exclude name="lib/**"/>
+        <exclude name="build.properties"/>
+      </fileset>
+    </copy>
+  </target>
+
+
+  <!-- ====================== DIST: Create Archives ======================= -->
+  <target name="dist" depends="deploy,dist-static,dist-javadoc,embed"
+   description="Create binary distribution">
+  </target>
+
+
+  <!-- ================= DIST: Create Windows Installer =================== -->
+  <target name="installer"
+   description="Create Windows installer" if="execute.installer">
+    <echo message="Builds a Windows installer based on Nullsoft Installer"/>
+    <copy todir="${tomcat.dist}">
+      <fileset dir="resources" />
+    </copy>
+    <copy file="${nsis.installoptions.dll}" todir="${tomcat.dist}" />
+    <copy file="${nsis.nsexec.dll}" todir="${tomcat.dist}" />
+    <copy file="${nsis.nsisdl.dll}" todir="${tomcat.dist}" />
+    <copy file="${jtc.home}/procrun/bin/tomcat5.exe"
+        tofile="${tomcat.dist}/bin/tomcat5.exe" />
+    <copy file="${jtc.home}/procrun/bin/tomcat5w.exe"
+        tofile="${tomcat.dist}/bin/tomcat5w.exe" />
+
+    <filter token="VERSION" value="${version}"/>
+    <filter token="VERSION_NUMBER" value="${version.number}"/>
+
+    <copy file="tomcat.nsi" tofile="${tomcat.dist}/tomcat.nsi" filtering="true"/>
+    <exec dir="${tomcat.dist}" executable="${nsis.exe}">
+      <arg value="/DNSISDIR=${nsis.home}" />
+      <arg value="tomcat.nsi" />
+    </exec>
+
+    <move file="${tomcat.dist}/tomcat-installer.exe" tofile="${tomcat.release}/v${version}/bin/${final.name}.exe" />
+
+    <checksum file="${tomcat.release}/v${version}/bin/${final.name}.exe"
+              forceOverwrite="yes" fileext=".md5" />
+    <echo     file="${tomcat.release}/v${version}/bin/${final.name}.exe.md5" 
+                      message="${md5sum.binary-prefix}${final.name}.exe${line.separator}" append="true" />
+  </target>
+
+
+  <!-- ==================== RELEASE: Create Release ======================= -->
+  <target name="release" depends="clean,dist,dist-source,prepare-release,installer,package-zip,package-tgz,package-embed-zip,package-embed-tgz,package-deployer-zip,package-deployer-tgz,package-compat-zip,package-compat-tgz,package-admin-zip,package-admin-tgz,package-src-zip,package-src-tgz,package-docs-tgz,clean-tester,run-tester"
+   description="Create a Tomcat 5 packaged distribution">
+
+    <filter token="VERSION" value="${version}"/>
+    <copy file="KEYS"
+         todir="${tomcat.release}/v${version}"/>
+    <copy file="RELEASE-NOTES"
+         todir="${tomcat.release}/v${version}"
+     filtering="true"/>
+    <copy file="resources/welcome.main.html"
+        tofile="${tomcat.release}/v${version}/README.html"
+     filtering="true"/>
+    <copy file="resources/welcome.bin.html"
+        tofile="${tomcat.release}/v${version}/bin/README.html"
+     filtering="true"/>
+
+  </target>
+
+  <!-- Packages the core zip distro -->
+  <target name="package-zip">
+    <zip zipfile="${tomcat.release}/v${version}/bin/${final.name}.zip">
+      <zipfileset dir="${tomcat.dist}" prefix="${final.name}">
+        <include name="bin/**"/>
+        <include name="common/**"/>
+        <include name="conf/**"/>
+        <include name="logs/**"/>
+        <include name="server/**"/>
+        <include name="shared/**"/>
+        <include name="webapps/**"/>
+        <include name="work/**"/>
+        <include name="temp/**"/>
+        <include name="LICENSE"/>
+        <include name="NOTICE"/>
+        <include name="README.txt"/>
+        <include name="RELEASE-NOTES"/>
+        <include name="RUNNING.txt"/>
+        <include name="BENCHMARKS.txt"/>
+        <exclude name="server/webapps/admin/**"/>
+        <exclude name="conf/Catalina/localhost/admin.xml"/>
+      </zipfileset>
+    </zip>
+
+    <checksum file="${tomcat.release}/v${version}/bin/${final.name}.zip"
+              forceOverwrite="yes" fileext=".md5" />
+    <echo     file="${tomcat.release}/v${version}/bin/${final.name}.zip.md5"
+                      message="${md5sum.binary-prefix}${final.name}.zip${line.separator}" append="true" />
+  </target>
+
+  <!-- Packages the embedded Tomcat distro in zip format -->
+  <target name="package-embed-zip">
+    <zip zipfile="${tomcat.release}/v${version}/bin/${final.name}-embed.zip">
+      <zipfileset dir="${tomcat.embed}" prefix="${final.name}-embed"
+                  includes="**" />
+      <zipfileset dir="${tomcat.dist}" prefix="${final.name}-embed"
+       includes="LICENSE" />
+      <zipfileset dir="${tomcat.dist}" prefix="${final.name}-embed"
+       includes="NOTICE" />
+      <zipfileset dir="${tomcat.dist}" prefix="${final.name}-embed"
+       includes="README.txt" />
+      <zipfileset dir="${tomcat.dist}" prefix="${final.name}-embed"
+       includes="RELEASE-NOTES" />
+    </zip>
+
+    <checksum file="${tomcat.release}/v${version}/bin/${final.name}-embed.zip"
+              forceOverwrite="yes" fileext=".md5" />
+    <echo     file="${tomcat.release}/v${version}/bin/${final.name}-embed.zip.md5"
+                      message="${md5sum.binary-prefix}${final.name}-embed.zip${line.separator}" append="true" />
+  </target>
+
+  <!-- Packages the deployer distribution in zip format -->
+  <target name="package-deployer-zip">
+    <zip zipfile="${tomcat.release}/v${version}/bin/${final.name}-deployer.zip">
+      <zipfileset dir="${tomcat.deployer}" prefix="${final.name}-deployer" includes="**" />
+      <zipfileset dir="${tomcat.dist}" prefix="${final.name}-deployer" includes="LICENSE" />
+      <zipfileset dir="${tomcat.dist}" prefix="${final.name}-deployer" includes="NOTICE" />
+      <zipfileset dir="${tomcat.dist}" prefix="${final.name}-deployer" includes="README.txt" />
+      <zipfileset dir="${tomcat.dist}" prefix="${final.name}-deployer" includes="RELEASE-NOTES" />
+    </zip>
+
+    <checksum file="${tomcat.release}/v${version}/bin/${final.name}-deployer.zip"
+              forceOverwrite="yes" fileext=".md5" />
+    <echo     file="${tomcat.release}/v${version}/bin/${final.name}-deployer.zip.md5"
+                      message="${md5sum.binary-prefix}${final.name}-deployer.zip${line.separator}" append="true" />
+  </target>
+
+  <!-- Packages the JDK 1.4 compatibility distro in zip format -->
+  <target name="package-compat-zip">
+    <zip zipfile="${tomcat.release}/v${version}/bin/${final.name}-compat.zip">
+      <zipfileset dir="${tomcat.compat}" prefix="${final.name}" includes="**" />
+      <zipfileset dir="${tomcat.dist}" prefix="${final.name}" includes="LICENSE" />
+      <zipfileset dir="${tomcat.dist}" prefix="${final.name}" includes="NOTICE" />
+      <zipfileset dir="${tomcat.dist}" prefix="${final.name}" includes="README.txt" />
+      <zipfileset dir="${tomcat.dist}" prefix="${final.name}" includes="RELEASE-NOTES" />
+    </zip>
+ 
+    <checksum file="${tomcat.release}/v${version}/bin/${final.name}-compat.zip"
+              forceOverwrite="yes" fileext=".md5" />
+    <echo     file="${tomcat.release}/v${version}/bin/${final.name}-compat.zip.md5"
+                      message="${md5sum.binary-prefix}${final.name}-compat.zip${line.separator}" append="true" />
+  </target>
+
+  <!-- Packages the admin webapp distro in zip format -->
+  <target name="package-admin-zip">
+    <zip zipfile="${tomcat.release}/v${version}/bin/${final.name}-admin.zip">
+      <zipfileset dir="${tomcat.dist}" prefix="${final.name}">
+        <include name="server/webapps/admin/**"/>
+        <include name="conf/Catalina/localhost/admin.xml"/>
+        <exclude name="*.jsp" />
+      </zipfileset>
+      <zipfileset dir="${tomcat.dist}" prefix="${final.name}" includes="LICENSE" />
+      <zipfileset dir="${tomcat.dist}" prefix="${final.name}" includes="NOTICE" />
+      <zipfileset dir="${tomcat.dist}" prefix="${final.name}" includes="README.txt" />
+      <zipfileset dir="${tomcat.dist}" prefix="${final.name}" includes="RELEASE-NOTES" />
+    </zip>
+   
+    <checksum file="${tomcat.release}/v${version}/bin/${final.name}-admin.zip"
+              forceOverwrite="yes" fileext=".md5" />
+    <echo     file="${tomcat.release}/v${version}/bin/${final.name}-admin.zip.md5"
+                      message="${md5sum.binary-prefix}${final.name}-admin.zip${line.separator}" append="true" />
+  </target>
+
+  <!-- Prepares for cutting the release -->
+  <target name="prepare-release">
+    <mkdir dir="${tomcat.release}"/>
+    <mkdir dir="${tomcat.release}/v${version}"/>
+    <mkdir dir="${tomcat.release}/v${version}/bin"/>
+    <mkdir dir="${tomcat.release}/v${version}/src"/>
+
+    <!-- This is why releasing must be done on a Windows box: 
+         otherwise this check fails and the .exe distro is not generated -->
+    <condition property="execute.installer">
+      <and>
+        <os family="windows" />
+        <available file="${nsis.exe}" />
+        <available file="${nsis.installoptions.dll}" />
+        <available file="${nsis.nsexec.dll}" />
+        <available file="${nsis.nsisdl.dll}" />
+      </and>
+    </condition>
+
+  </target>
+
+  <!-- Packages the core tar.gz distro -->
+  <target name="package-tgz">
+    <fixcrlf srcdir="${tomcat.dist}" includes="*.txt,LICENSE,NOTICE" eol="lf"/>
+    <fixcrlf srcdir="${tomcat.dist}/conf" eol="lf"/>
+    <tar longfile="gnu" compression="gzip"
+         tarfile="${tomcat.release}/v${version}/bin/${final.name}.tar.gz">
+      <tarfileset dir="${tomcat.dist}" mode="755" prefix="${final.name}">
+        <include name="bin/catalina.sh" />
+        <include name="bin/digest.sh" />
+        <include name="bin/jasper.sh" />
+        <include name="bin/jspc.sh" />
+        <include name="bin/setclasspath.sh" />
+        <include name="bin/startup.sh" />
+        <include name="bin/shutdown.sh" />
+        <include name="bin/tool-wrapper.sh" />
+        <include name="bin/tool-wrapper-using-launcher.sh" />
+        <include name="bin/shutdown-using-launcher.sh" />
+        <include name="bin/startup-using-launcher.sh" />
+      </tarfileset>
+      <tarfileset dir="${tomcat.dist}" mode="600" prefix="${final.name}">
+        <include name="conf/**" />
+        <exclude name="conf/Catalina/localhost/admin.xml" />
+      </tarfileset>
+      <tarfileset dir="${tomcat.dist}" prefix="${final.name}">
+        <include name="bin/**" />
+        <include name="common/**" />
+        <include name="logs/**" />
+        <include name="server/**" />
+        <include name="shared/**" />
+        <include name="temp/**" />
+        <include name="webapps/**" />
+        <include name="work/**" />
+        <include name="LICENSE" />
+        <include name="NOTICE" />
+        <include name="README.txt" />
+        <include name="RELEASE-NOTES" />
+        <include name="RUNNING.txt" />
+        <include name="BENCHMARKS.txt" />
+        <exclude name="bin/catalina.sh" />
+        <exclude name="bin/digest.sh" />
+        <exclude name="bin/jasper.sh" />
+        <exclude name="bin/jspc.sh" />
+        <exclude name="bin/setclasspath.sh" />
+        <exclude name="bin/startup.sh" />
+        <exclude name="bin/shutdown.sh" />
+        <exclude name="bin/tool-wrapper.sh" />
+        <exclude name="bin/tool-wrapper-using-launcher.sh" />
+        <exclude name="bin/shutdown-using-launcher.sh" />
+        <exclude name="bin/startup-using-launcher.sh" />
+        <exclude name="conf/**" />
+        <exclude name="src/**" />
+        <exclude name="server/webapps/admin/**" />
+      </tarfileset>
+    </tar>
+
+    <checksum file="${tomcat.release}/v${version}/bin/${final.name}.tar.gz"
+              forceOverwrite="yes" fileext=".md5" />
+    <echo     file="${tomcat.release}/v${version}/bin/${final.name}.tar.gz.md5"
+                      message="${md5sum.binary-prefix}${final.name}.tar.gz${line.separator}" append="true" />
+  </target>
+
+  <!-- Packages the embedded Tomcat distro in tar.gz format -->
+  <target name="package-embed-tgz">
+    <fixcrlf srcdir="${tomcat.dist}"
+     includes="*.txt,LICENSE,NOTICE" eol="lf"/>
+    <fixcrlf srcdir="${tomcat.embed}" includes="*.xml" eol="lf"/>
+    <tar longfile="gnu" compression="gzip"
+         tarfile="${tomcat.release}/v${version}/bin/${final.name}-embed.tar.gz">
+      <tarfileset dir="${tomcat.dist}" prefix="${final.name}-embed">
+        <include name="LICENSE" />
+        <include name="NOTICE" />
+        <include name="README.txt" />
+        <include name="RELEASE-NOTES" />
+      </tarfileset>
+      <tarfileset dir="${tomcat.embed}" prefix="${final.name}-embed">
+        <include name="**" />
+      </tarfileset>
+    </tar>
+
+    <checksum file="${tomcat.release}/v${version}/bin/${final.name}-embed.tar.gz"
+              forceOverwrite="yes" fileext=".md5" />
+    <echo     file="${tomcat.release}/v${version}/bin/${final.name}-embed.tar.gz.md5"
+                      message="${md5sum.binary-prefix}${final.name}-embed.tar.gz${line.separator}" append="true" />
+  </target>
+
+  <!-- Packages the deployer Tomcat distro in tar.gz format -->
+  <target name="package-deployer-tgz">
+    <fixcrlf srcdir="${tomcat.dist}"
+     includes="*.txt,LICENSE,NOTICE" eol="lf"/>
+    <fixcrlf srcdir="${tomcat.deployer}" includes="*.xml" eol="lf"/>
+
+    <tar longfile="gnu" compression="gzip"
+         tarfile="${tomcat.release}/v${version}/bin/${final.name}-deployer.tar.gz">
+      <tarfileset dir="${tomcat.dist}" prefix="${final.name}-deployer">
+        <include name="LICENSE" />
+        <include name="NOTICE" />
+        <include name="README.txt" />
+        <include name="RELEASE-NOTES" />
+      </tarfileset>
+      <tarfileset dir="${tomcat.deployer}" prefix="${final.name}-deployer">
+        <include name="**" />
+      </tarfileset>
+    </tar>
+
+    <checksum file="${tomcat.release}/v${version}/bin/${final.name}-deployer.tar.gz"
+              forceOverwrite="yes" fileext=".md5" />
+    <echo     file="${tomcat.release}/v${version}/bin/${final.name}-deployer.tar.gz.md5"
+                      message="${md5sum.binary-prefix}${final.name}-deployer.tar.gz${line.separator}" append="true" />
+  </target>
+
+  <!-- Packages the 1.4 compatibility distro in tar.gz format -->
+  <target name="package-compat-tgz">
+    <fixcrlf srcdir="${tomcat.dist}" includes="*.txt,LICENSE,NOTICE" eol="lf"/>
+
+    <tar longfile="gnu" compression="gzip"
+         tarfile="${tomcat.release}/v${version}/bin/${final.name}-compat.tar.gz">
+      <tarfileset dir="${tomcat.dist}" prefix="${final.name}">
+        <include name="LICENSE" />
+        <include name="NOTICE" />
+        <include name="README.txt" />
+        <include name="RELEASE-NOTES" />
+      </tarfileset>
+      <tarfileset dir="${tomcat.compat}" prefix="${final.name}">
+        <include name="**" />
+      </tarfileset>
+    </tar>
+
+    <checksum file="${tomcat.release}/v${version}/bin/${final.name}-compat.tar.gz"
+              forceOverwrite="yes" fileext=".md5" />
+    <echo     file="${tomcat.release}/v${version}/bin/${final.name}-compat.tar.gz.md5"
+                      message="${md5sum.binary-prefix}${final.name}-compat.tar.gz${line.separator}" append="true" />
+  </target>
+
+  <!-- Packages the admin webapp distro in tar.gz format -->
+  <target name="package-admin-tgz">
+    <fixcrlf srcdir="${tomcat.dist}" includes="*.txt,LICENSE,NOTICE" eol="lf"/>
+
+    <tar longfile="gnu" compression="gzip"
+         tarfile="${tomcat.release}/v${version}/bin/${final.name}-admin.tar.gz">
+      <tarfileset dir="${tomcat.dist}" prefix="${final.name}">
+        <include name="LICENSE" />
+        <include name="NOTICE" />
+        <include name="README.txt" />
+        <include name="RELEASE-NOTES" />
+      </tarfileset>
+      <tarfileset dir="${tomcat.dist}" prefix="${final.name}">
+        <include name="server/webapps/admin/**" />
+        <exclude name="*.jsp" />
+      </tarfileset>
+      <tarfileset dir="${tomcat.dist}" mode="600" prefix="${final.name}">
+        <include name="conf/Catalina/localhost/admin.xml" />
+      </tarfileset>
+    </tar>
+
+    <checksum file="${tomcat.release}/v${version}/bin/${final.name}-admin.tar.gz"
+              forceOverwrite="yes" fileext=".md5" />
+    <echo     file="${tomcat.release}/v${version}/bin/${final.name}-admin.tar.gz.md5"
+                      message="${md5sum.binary-prefix}${final.name}-admin.tar.gz${line.separator}" append="true" />
+  </target>
+
+  <!-- Packages the documentation distro in tar.gz format -->
+  <target name="package-docs-tgz" depends="prepare-release">
+    <!-- Generate docs -->
+    <ant dir="${catalina.home}" target="dist-javadoc"/>
+    <mkdir  dir="${tomcat.dist}/webapps/tomcat-docs/catalina/docs/api"/>
+    <copy todir="${tomcat.dist}/webapps/tomcat-docs/catalina/docs/api">
+      <fileset dir="${catalina.build}/javadoc" />
+    </copy>
+    <ant dir="${jasper.home}" target="javadoc"/>
+    <mkdir  dir="${tomcat.dist}/webapps/tomcat-docs/jasper/docs/api"/>
+    <copy todir="${tomcat.dist}/webapps/tomcat-docs/jasper/docs/api">
+      <fileset dir="${jasper.build}/javadoc" />
+    </copy>
+
+    <!-- Package gocs -->
+    <fixcrlf srcdir="${tomcat.dist}" includes="*.txt,LICENSE,NOTICE" eol="lf"/>
+
+    <tar longfile="gnu" compression="gzip"
+         tarfile="${tomcat.release}/v${version}/bin/${final.name}-fulldocs.tar.gz">
+      <tarfileset dir="${tomcat.dist}" prefix="tomcat-5.5-doc">
+        <include name="LICENSE" />
+        <include name="NOTICE" />
+        <include name="README.txt" />
+        <include name="RUNNING.txt" />
+      </tarfileset>
+      <tarfileset dir="${tomcat.dist}/webapps/tomcat-docs" prefix="tomcat-5.5-doc">
+        <include name="**" />
+      </tarfileset>
+    </tar>
+
+    <checksum file="${tomcat.release}/v${version}/bin/${final.name}-fulldocs.tar.gz"
+              forceOverwrite="yes" fileext=".md5" />
+    <echo     file="${tomcat.release}/v${version}/bin/${final.name}-fulldocs.tar.gz.md5"
+                      message="${md5sum.binary-prefix}${final.name}-fulldocs.tar.gz${line.separator}" append="true" />
+  </target>
+
+  <!-- Packages the source code distribution in zip format -->
+  <target name="package-src-zip">
+    <zip zipfile="${tomcat.release}/v${version}/src/${final-src.name}.zip">
+      <zipfileset dir="${tomcat.dist}/src" prefix="${final-src.name}" />
+    </zip>
+
+    <checksum file="${tomcat.release}/v${version}/src/${final-src.name}.zip"
+              forceOverwrite="yes" fileext=".md5" />
+    <echo     file="${tomcat.release}/v${version}/src/${final-src.name}.zip.md5"
+                      message="${md5sum.binary-prefix}${final-src.name}.zip${line.separator}" append="true" />
+  </target>
+
+  <!-- Packages the source code distribution in tar.gz format -->
+  <target name="package-src-tgz">
+    <fixcrlf srcdir="${tomcat.dist}"
+     excludes="**/*.jar,**/*.gif,**/*.bmp,**/*.jpg,**/*.ico,**/*.war" eol="lf"/>
+
+    <tar longfile="gnu" compression="gzip"
+         tarfile="${tomcat.release}/v${version}/src/${final-src.name}.tar.gz">
+      <tarfileset dir="${tomcat.dist}/src" mode="755" prefix="${final-src.name}">
+        <include name="${jtc.project}/jk/native/buildconf.sh" />
+        <include name="${jtc.project}/jk/native/apache-1.3/build-hpux-cc.sh" />
+        <include name="${jtc.project}/jk/native/apache-1.3/build-solaris.sh" />
+        <include name="${jtc.project}/jk/native/apache-1.3/build-unix.sh" />
+        <include name="${jtc.project}/jk/native/apache-2.0/build-unix.sh" />
+        <include name="${jtc.project}/jk/native/apache-2.0/install-unix.sh" />
+        <include name="${jtc.project}/jk/native/domino/mkini.sh" />
+      </tarfileset>
+      <tarfileset dir="${tomcat.dist}/src" prefix="${final-src.name}">
+        <exclude name="${jtc.project}/jk/native/buildconf.sh" />
+        <exclude name="${jtc.project}/jk/native/apache-1.3/build-hpux-cc.sh" />
+        <exclude name="${jtc.project}/jk/native/apache-1.3/build-solaris.sh" />
+        <exclude name="${jtc.project}/jk/native/apache-1.3/build-unix.sh" />
+        <exclude name="${jtc.project}/jk/native/apache-2.0/build-unix.sh" />
+        <exclude name="${jtc.project}/jk/native/apache-2.0/install-unix.sh" />
+        <exclude name="${jtc.project}/jk/native/domino/mkini.sh" />
+      </tarfileset>
+    </tar>
+
+    <checksum file="${tomcat.release}/v${version}/src/${final-src.name}.tar.gz"
+              forceOverwrite="yes" fileext=".md5" />
+    <echo     file="${tomcat.release}/v${version}/src/${final-src.name}.tar.gz.md5"
+                      message="${md5sum.binary-prefix}${final-src.name}.tar.gz${line.separator}" append="true" />
+  </target>
+
+  <!-- ==================== Download or build the required binary packages ==================== -->
+
+  <target name="download" depends="proxyflags"
+          description="Download binary packages" >
+    <mkdir dir="${base.path}" />
+
+    <!-- commons-digester needs ../LICENSE -->
+    <!-- That is ugly XXX needs a review -->
+    <copy file="LICENSE" tofile="../LICENSE"/>
+    <copy file="LICENSE" tofile="${base.path}/LICENSE"/>
+
+    <!-- Downdown any sub package or tools needed. -->
+    <antcall target="downloadgz">
+      <param name="sourcefile" value="${commons-beanutils.loc}"/>
+      <param name="destfile" value="${commons-beanutils.jar}"/>
+    </antcall>
+
+    <antcall target="downloadgz">
+      <param name="sourcefile" value="${commons-collections.loc}"/>
+      <param name="destfile" value="${commons-collections.jar}"/>
+    </antcall>
+
+    <antcall target="downloadgz">
+      <param name="sourcefile" value="${commons-el.loc}"/>
+      <param name="destfile" value="${commons-el.jar}"/>
+    </antcall>
+
+    <antcall target="downloadgz">
+      <param name="sourcefile" value="${commons-logging.loc}"/>
+      <param name="destfile" value="${commons-logging.jar}"/>
+    </antcall>
+
+    <antcall target="downloadgz">
+      <param name="sourcefile" value="${commons-modeler.loc}"/>
+      <param name="destfile" value="${commons-modeler.jar}"/>
+    </antcall>
+
+    <antcall target="downloadgz">
+      <param name="sourcefile" value="${log4j.loc}"/>
+      <param name="destfile" value="${log4j.jar}"/>
+    </antcall>
+
+    <antcall target="downloadgz">
+      <param name="sourcefile" value="${commons-digester.loc}"/>
+      <param name="destfile" value="${commons-digester.jar}"/>
+    </antcall>
+
+    <antcall target="downloadgz">
+      <param name="sourcefile" value="${commons-fileupload.loc}"/>
+      <param name="destfile" value="${commons-fileupload.jar}"/>
+    </antcall>
+
+    <antcall target="downloadgz">
+      <!-- xerces2 brings 2 files, test for one of them -->
+      <param name="sourcefile" value="${xerces.loc}"/>
+      <param name="destfile" value="${xml-apis.jar}"/>
+    </antcall>
+
+    <antcall target="downloadgz">
+      <param name="sourcefile" value="${jmx.loc}"/>
+      <param name="destfile" value="${jmx.jar}"/>
+    </antcall>
+
+    <antcall target="downloadzip">
+      <param name="sourcefile" value="${junit.loc}"/>
+      <param name="destfile" value="${junit.jar}"/>
+      <param name="destdir" value="${base.path}"/>
+    </antcall>
+    
+    <antcall target="downloadgz">
+      <param name="sourcefile" value="${commons-launcher.loc}"/>
+      <param name="destfile" value="${commons-launcher.jar}"/>
+    </antcall>
+
+    <!--
+    <antcall target="downloadgz">
+      <param name="sourcefile" value="${commons-pool.loc}"/>
+      <param name="destfile" value="${commons-pool.jar}"/>
+    </antcall>
+
+    <antcall target="downloadgz">
+      <param name="sourcefile" value="${commons-dbcp.loc}"/>
+      <param name="destfile" value="${commons-dbcp.jar}"/>
+      <param name="destdir" value="${base.path}"/>
+    </antcall>
+    -->
+
+    <antcall target="downloadgz">
+      <param name="sourcefile" value="${commons-httpclient.loc}"/>
+      <param name="destfile" value="${commons-httpclient.jar}"/>
+    </antcall>
+
+    <antcall target="downloadfile">
+      <param name="sourcefile" value="${nsis.loc}"/>
+      <param name="destfile" value="${nsis.exe}"/>
+      <param name="destdir" value="${nsis.home}"/>
+    </antcall>
+
+    <antcall target="downloadgz">
+      <param name="sourcefile" value="${struts.loc}"/>
+      <param name="destfile" value="${struts.jar}"/>
+    </antcall>
+
+    <antcall target="downloadgz">
+      <param name="sourcefile" value="${commons-daemon.loc}"/>
+      <param name="destfile" value="${commons-daemon.jar}"/>
+    </antcall>
+
+    <antcall target="downloadfile">
+      <param name="sourcefile" value="${tomcat-native.loc}"/>
+      <param name="destfile" value="${tomcat-native.tar.gz}"/>
+      <param name="destdir" value="${tomcat-native.home}"/>
+    </antcall>
+
+    <!-- Build the dependencies that are not yet released -->
+    <antcall target="build-depends"/>
+
+  </target>
+
+  <target name="proxyflags">
+    <!-- check proxy parameters. -->
+    <condition property="useproxy">
+      <equals arg1="${proxy.use}" arg2="on" />
+    </condition>
+  </target>
+
+  <target name="setproxy"  if="useproxy">
+    <taskdef name="setproxy"
+      classname="org.apache.tools.ant.taskdefs.optional.net.SetProxy" />
+    <setproxy proxyhost="${proxy.host}" proxyport="${proxy.port}"/>
+    <echo message="Using ${proxy.host}:${proxy.port} to download ${sourcefile}"/>
+  </target>
+
+  <target name="testexist">
+    <echo message="Testing  for ${destfile}"/>
+    <available file="${destfile}" property="exist"/>
+  </target>
+
+  <target name="downloadgz" unless="exist" depends="setproxy,testexist">
+    <!-- Download and extract the package -->
+    <get src="${sourcefile}" dest="${base.path}/file.tar.gz" />
+    <gunzip src="${base.path}/file.tar.gz" dest="${base.path}/file.tar"/>
+    <untar src="${base.path}/file.tar" dest="${base.path}"/>
+    <delete file="${base.path}/file.tar"/>
+    <delete file="${base.path}/file.tar.gz"/>
+  </target>
+
+  <target name="downloadzip" unless="exist" depends="setproxy,testexist">
+    <!-- Download and extract the package -->
+    <get src="${sourcefile}" dest="${base.path}/file.zip" />
+    <mkdir dir="${destdir}" />
+    <unzip src="${base.path}/file.zip" dest="${destdir}"/>
+    <delete file="${base.path}/file.zip"/>
+  </target>
+  
+
+  <target name="downloadfile" unless="exist" depends="setproxy,testexist">
+    <!-- Download extract the file -->
+    <mkdir dir="${destdir}" />
+    <get src="${sourcefile}" dest="${destfile}" />
+  </target>
+
+
+  <!-- ==================== Modeler tricks ====================
+  -->
+  <target name="convert-mbeans" description="Hack: regenerate the ser form of the descriptors">
+    <path id="tomcatCP" >
+      <fileset dir="${tomcat.build}/common/lib" includes="*.jar"/>
+      <fileset dir="${tomcat.build}/server/lib" includes="*.jar" />
+    </path>
+    <taskdef resource="org/apache/commons/modeler/ant/ant.properties"
+             classpathref="tomcatCP" />
+
+    <mbeans-descriptors file="${catalina.home}/catalina/src/share/org/apache/catalina/mbeans/mbeans-descriptors.xml"
+              out="build/classes/org/apache/catalina/mbeans/mbeans-descriptors.xml.ser" />
+    <mbeans-descriptors file="${catalina.home}/catalina/src/share/org/apache/catalina/core/mbeans-descriptors.xml"
+              out="build/classes/org/apache/catalina/core/mbeans-descriptors.xml.ser" />
+    <mbeans-descriptors file="${catalina.home}/catalina/src/share/org/apache/catalina/valves/mbeans-descriptors.xml"
+              out="build/classes/org/apache/catalina/valves/mbeans-descriptors.xml.ser" />
+    <mbeans-descriptors file="${jtc.home}/coyote/src/java/org/apache/coyote/tomcat5/mbeans-descriptors.xml"
+              out="build/classes/org/apache/coyote/tomcat5/mbeans-descriptors.xml.ser" />
+  </target>
+
+  <target name="gumpy-build" description="Target for Gump builds"
+       depends="gumpy-prepare,prepare-release,dist,dist-source,installer,package-zip,package-tgz,package-src-zip,package-src-tgz" />
+
+  <target name="gumpy-prepare" description="Collect Gump-built jar files" >
+    <mkdir dir="${tomcat.build}"/>
+    <mkdir dir="${tomcat.build}/classes" />
+    <mkdir dir="${tomcat.build}/server/lib" />
+    <mkdir dir="${tomcat.build}/common/lib" />
+    <copy file="${tomcat-util.jar}" tofile="${tomcat.build}/server/lib/tomcat-util.jar"/>
+    <copy file="${tomcat-ajp.jar}" tofile="${tomcat.build}/server/lib/tomcat-ajp.jar"/>
+    <copy file="${tomcat-coyote.jar}" tofile="${tomcat.build}/server/lib/tomcat-coyote.jar"/>
+    <copy file="${tomcat-http11.jar}" tofile="${tomcat.build}/server/lib/tomcat-http11.jar"/>
+    <copy file="${tomcat-jni.jar}" tofile="${tomcat.build}/server/lib/tomcat-apr.jar" /> 
+    <property name="tomcat.aprbuild.notrequired" value="true" />
+    <copy file="${jasper-runtime.jar}" tofile="${tomcat.build}/common/lib/jasper-runtime.jar"/>
+    <copy file="${jasper-compiler.jar}" tofile="${tomcat.build}/common/lib/jasper-compiler.jar"/>
+    <property name="jasper.build.notrequired" value="true" />
+  </target>
+</project>

Added: branches/tomcat5.5/upstream/5.5.20/build/resources/INSTALLLICENSE
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/build/resources/INSTALLLICENSE	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/build/resources/INSTALLLICENSE	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,201 @@
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed 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.

Added: branches/tomcat5.5/upstream/5.5.20/build/resources/License.rtf
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/build/resources/License.rtf	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/build/resources/License.rtf	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,266 @@
+{\rtf1\ansi\ansicpg1252\deff0{\fonttbl{\f0\fswiss\fprq2\fcharset0 Arial;}}
+\viewkind4\uc1\pard\qc\lang1033\b\f0\fs18 Apache License\par
+Version 2.0, January 2004\par
+http://www.apache.org/licenses/\par
+\b0\par
+\pard TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\par
+\par
+\pard\fi-180\li180 1. Definitions.\par
+\par
+\pard\li180 "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document.\par
+\par
+"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License.\par
+\par
+"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity.\par
+\par
+"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License.\par
+\par
+"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files.\par
+\par
+"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types.\par
+\par
+"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below).\par
+\par
+"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof.\par
+\par
+"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution."\par
+\par
+"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work.\par
+\pard\par
+\pard\fi-180\li180 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form.\par
+\par
+3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed.\par
+\par
+4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions:\par
+\pard\par
+\pard\fi-270\li450 (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and\par
+\par
+(b) You must cause any modified files to carry prominent notices stating that You changed the files; and\par
+\par
+(c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and\par
+\par
+(d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License.\par
+\pard\par
+\pard\li180 You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or  for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License.\par
+\pard\par
+\pard\fi-180\li180 5. Submission of Contributions. Unless You explicitly state otherwise,  any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions.\par
+\par
+6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file.\par
+\par
+7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License.\par
+\par
+8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages.\par
+\par
+9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability.\par
+\pard\par
+END OF TERMS AND CONDITIONS\par
+\par
+APPENDIX: How to apply the Apache License to your work.\par
+\par
+To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!)  The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives.\par
+\par
+\pard\li180 Copyright [yyyy] [name of copyright owner]\par
+\par
+Licensed 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\par
+\par
+\pard\li360 http://www.apache.org/licenses/LICENSE-2.0\par
+\pard\li180\par
+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.\par
+\pard\par
+\par
+\b APACHE HTTP SERVER SUBCOMPONENTS: \par
+\par
+\b0 The Apache HTTP Server includes a number of subcomponents with\par
+separate copyright notices and license terms. Your use of the source\par
+code for the these subcomponents is subject to the terms and\par
+conditions of the following licenses. \par
+\par
+\b For the mod_mime_magic component:\par
+\par
+\b0 mod_mime_magic: MIME type lookup via file magic numbers\par
+Copyright (c) 1996-1997 Cisco Systems, Inc.\par
+\par
+This software was submitted by Cisco Systems to the Apache Group in July 1997.  Future revisions and derivatives of this source code must acknowledge Cisco Systems as the original contributor of this module.  All other licensing and usage conditions are those of the Apache Group.\par
+\par
+Some of this code is derived from the free version of the file command originally posted to comp.sources.unix.  Copyright info for that program is included below as required.\par
+\par
+Copyright (c) Ian F. Darwin, 1987. Written by Ian F. Darwin.\par
+\par
+This software is not subject to any license of the American Telephone and Telegraph Company or of the Regents of the University of California.\par
+\par
+Permission is granted to anyone to use this software for any purpose on any computer system, and to alter it and redistribute it freely, subject to the following restrictions:\par
+\par
+1. The author is not responsible for the consequences of use of this software, no matter how awful, even if they arise from flaws in it.\par
+\par
+2. The origin of this software must not be misrepresented, either by explicit claim or by omission.  Since few users ever read sources, credits must appear in the documentation.\par
+\par
+3. Altered versions must be plainly marked as such, and must not be misrepresented as being the original software.  Since few users ever read sources, credits must appear in the documentation.\par
+\par
+4. This notice may not be removed or altered.\par
+\par
+\par
+\b For the  modules\\mappers\\mod_imap.c component:\par
+\par
+\b0 "macmartinized" polygon code copyright 1992 by Eric Haines, erich at eye.com\par
+\par
+\par
+\b For the  server\\util_md5.c component:\par
+\par
+\b0 NCSA HTTPd Server\par
+Software Development Group\par
+National Center for Supercomputing Applications\par
+University of Illinois at Urbana-Champaign\par
+605 E. Springfield, Champaign, IL 61820\par
+httpd at ncsa.uiuc.edu\par
+\par
+Copyright  (C)  1995, Board of Trustees of the University of Illinois\par
+\par
+md5.c: NCSA HTTPd code which uses the md5c.c RSA Code\par
+\par
+Original Code Copyright (C) 1994, Jeff Hostetler, Spyglass, Inc.\par
+Portions of Content-MD5 code Copyright (C) 1993, 1994 by Carnegie Mellon University (see Copyright below).\par
+Portions of Content-MD5 code Copyright (C) 1991 Bell Communications  Research, Inc. (Bellcore) (see Copyright below).\par
+Portions extracted from mpack, John G. Myers - jgm+ at cmu.edu\par
+Content-MD5 Code contributed by Martin Hamilton (martin at net.lut.ac.uk)\par
+\par
+these portions extracted from mpack, John G. Myers - jgm+ at cmu.edu\par
+(C) Copyright 1993,1994 by Carnegie Mellon University All Rights Reserved.\par
+\par
+Permission to use, copy, modify, distribute, and sell this software and its documentation for any purpose is hereby granted without fee, provided that the above copyright notice appear in all copies and that both that copyright notice and this permission notice appear in supporting documentation, and that the name of Carnegie Mellon University not be used in advertising or publicity pertaining to distribution of the software without specific, written prior permission.  Carnegie Mellon University makes no representations about the suitability of this software for any purpose.  It is provided "as is" without express or implied warranty.\par
+\par
+CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS\par
+SOFTWARE.\par
+\par
+Copyright (c) 1991 Bell Communications Research, Inc. (Bellcore)\par
+\par
+Permission to use, copy, modify, and distribute this material for any purpose and without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies, and that the name of Bellcore not be used in advertising or publicity pertaining to this material without the specific, prior written permission of an authorized representative of Bellcore.\par
+\par
+BELLCORE MAKES NO REPRESENTATIONS ABOUT THE ACCURACY OR SUITABILITY OF THIS MATERIAL FOR ANY PURPOSE.  IT IS PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES.\par
+\par
+\par
+\b For the  srclib\\apr\\passwd\\apr_md5.c and srclib\\apr\\include\\apr_md5.h components:\par
+\par
+\pard\b0 This is derived from material copyright RSA Data Security, Inc.  Their notice is reproduced below in its entirety.\par
+\pard\par
+Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All rights reserved.\par
+\par
+License to copy and use this software is granted provided that it is identified as the "RSA Data Security, Inc. MD5 Message-Digest Algorithm" in all material mentioning or referencing this software or this function.\par
+\par
+License is also granted to make and use derivative works provided that such works are identified as "derived from the RSA Data Security, Inc. MD5 Message-Digest Algorithm" in all material mentioning or referencing the derived work.\par
+\par
+RSA Data Security, Inc. makes no representations concerning either the merchantability of this software or the suitability of this software for any particular purpose. It is provided "as is" without express or implied warranty of any kind.\par
+\par
+These notices must be retained in any copies of any part of this documentation and/or software.\par
+\par
+The apr_md5_encode() routine uses much code obtained from the FreeBSD 3.0 MD5 crypt() function, which is licenced as follows:\par
+\par
+"THE BEER-WARE LICENSE" (Revision 42):\par
+<phk at login.dknet.dk> wrote this file.  As long as you retain this notice you can do whatever you want with this stuff. If we meet some day, and you think this stuff is worth it, you can buy me a beer in return.  Poul-Henning Kamp\par
+\par
+\par
+\b For the srclib\\apr-util\\crypto\\apr_md4.c and srclib\\apr-util\\include\\apr_md4.h components:\par
+\par
+\b0 This is derived from material copyright RSA Data Security, Inc.  Their notice is reproduced below in its entirety.\par
+\par
+Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All rights reserved.\par
+\par
+License to copy and use this software is granted provided that it is identified as the "RSA Data Security, Inc. MD4 Message-Digest Algorithm" in all material mentioning or referencing this software or this function.\par
+\par
+License is also granted to make and use derivative works provided that such works are identified as "derived from the RSA Data Security, Inc. MD4 Message-Digest Algorithm" in all material mentioning or referencing the derived work.\par
+\par
+RSA Data Security, Inc. makes no representations concerning either the merchantability of this software or the suitability of this software for any particular purpose. It is provided "as is" without express or implied warranty of any kind.\par
+\par
+These notices must be retained in any copies of any part of this documentation and/or software.\par
+\par
+\par
+\b For the srclib\\apr-util\\xml\\expat\\conftools\\install-sh and srclib\\pcre\\install-sh components:\par
+\par
+\b0 Copyright 1991 by the Massachusetts Institute of Technology\par
+\par
+Permission to use, copy, modify, distribute, and sell this software and its documentation for any purpose is hereby granted without fee, provided that the above copyright notice appear in all copies and that both that copyright notice and this permission notice appear in supporting documentation, and that the name of M.I.T. not be used in advertising or publicity pertaining to distribution of the software without specific, written prior permission.  M.I.T. makes no representations about the suitability of this software for any purpose.  It is provided "as is" without express or implied warranty.\par
+\par
+\b\par
+For the pcre component:\par
+\par
+\b0 PCRE LICENCE\par
+------------\par
+\par
+PCRE is a library of functions to support regular expressions whose syntax and semantics are as close as possible to those of the Perl 5 language.\par
+\par
+Written by: Philip Hazel <ph10 at cam.ac.uk>\par
+\par
+University of Cambridge Computing Service,\par
+Cambridge, England. Phone: +44 1223 334714.\par
+\par
+Copyright (c) 1997-2001 University of Cambridge\par
+\par
+Permission is granted to anyone to use this software for any purpose on any computer system, and to redistribute it freely, subject to the following restrictions:\par
+\par
+\pard\fi-180\li180 1. This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\par
+\pard\li180\par
+\pard\fi-180\li180 2. The origin of this software must not be misrepresented, either by explicit claim or by omission. In practice, this means that if you use PCRE in software which you distribute to others, commercially or otherwise, you must put a sentence like this\par
+\pard\li180\par
+\pard\li360 Regular expression support is provided by the PCRE library package, which is open source software, written by Philip Hazel, and copyright by the University of Cambridge, England.\par
+\pard\li180\par
+somewhere reasonably visible in your documentation and in any relevant files or online help data or similar. A reference to the ftp site for the source, that is, to\par
+\par
+\pard\li360 ftp://ftp.csx.cam.ac.uk/pub/software/programming/pcre/\par
+\pard\li180\par
+should also be given in the documentation.\par
+\par
+\pard\fi-180\li180 3. Altered versions must be plainly marked as such, and must not be misrepresented as being the original software.\par
+\pard\li180\par
+\pard\fi-180\li180 4. If PCRE is embedded in any software that is released under the GNU General Purpose Licence (GPL), or Lesser General Purpose Licence (LGPL), then the terms of that licence shall supersede any condition above with which it is incompatible.\par
+\pard\par
+The documentation for PCRE, supplied in the "doc" directory, is distributed under the same terms as the software itself.\par
+\par
+End PCRE LICENCE\par
+\par
+\par
+\b For the test\\zb.c component:\par
+\b0\par
+ZeusBench V1.01\par
+===============\par
+\par
+This program is Copyright (C) Zeus Technology Limited 1996.\par
+\par
+This program may be used and copied freely providing this copyright notice is not removed.\par
+\par
+This software is provided "as is" and any express or implied waranties, including but not limited to, the implied warranties of merchantability and fitness for a particular purpose are disclaimed.  In no event shall Zeus Technology Ltd. be liable for any direct, indirect, incidental, special, exemplary, or consequential damaged (including, but not limited to, procurement of substitute good or services; loss of use, data, or profits; or business interruption) however caused and on theory of liability.  Whether in contract, strict liability or tort (including negligence or otherwise) arising in any way out of the use of this software, even if advised of the possibility of such damage.\par
+\par
+  Written by Adam Twiss (adam at zeus.co.uk).  March 1996\par
+\par
+Thanks to the following people for their input:\par
+  Mike Belshe (mbelshe at netscape.com) \par
+  Michael Campanella (campanella at stevms.enet.dec.com)\par
+\par
+\b\par
+For the expat xml parser component:\par
+\b0\par
+Copyright (c) 1998, 1999, 2000 Thai Open Source Software Center Ltd and Clark Cooper\par
+\par
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\par
+\par
+The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\par
+\tab\par
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\par
+\par
+\b\par
+For the mod_deflate zlib compression component:\par
+\par
+\b0 (C) 1995-2002 Jean-loup Gailly and Mark Adler\par
+\par
+This software is provided 'as-is', without any express or implied warranty.  In no event will the authors be held liable for any damages arising from the use of this software.\par
+\par
+Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:\par
+\par
+\pard\fi-180\li180 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.\par
+2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.\par
+3. This notice may not be removed or altered from any source distribution.\par
+\pard\par
+Jean-loup Gailly\tab Mark Adler\par
+jloup at gzip.org\tab madler at alumni.caltech.edu\par
+\par
+\par
+}
+ 

Added: branches/tomcat5.5/upstream/5.5.20/build/resources/build.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/build/resources/build.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/build/resources/build.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,91 @@
+<project name="Tomcat 5.0 Netbuild" default="build" basedir=".">
+
+
+  <!-- ===================== Initialize Property Values =================== -->
+
+  <!-- See "build.properties.sample" in the top level directory for all     -->
+  <!-- property values you must customize for successful building!!!        -->
+  <property file="${user.home}/build.properties"/>
+  <property file="build.properties"/>
+  <property file="build.properties.default"/>
+
+  <!-- Project Properties -->
+  <property name="name"                  value="Apache Tomcat" />
+  <property name="year"                  value="2005" />
+  <property name="version"               value="5.5" />
+  <property name="project"               value="jakarta-tomcat" />
+  <property name="final.name"            value="${project}-${version}" />
+  <property name="final-src.name"        value="${project}-${version}-src" />
+
+  <!-- SVNROOT -->
+  <property name="svnroot" 
+           value="http://svn.apache.org/repos/asf/" />
+
+  <!-- Subprojects -->
+  <property name="api.project"           value="servletapi" />
+  <property name="tomcat.project"        value="build" />
+  <property name="catalina.project"      value="container" />
+  <property name="jtc.project"           value="connectors" />
+  <property name="jasper.project"        value="jasper" />
+
+  <property name="current.loc"           value="tomcat/current/tc5.5.x" />
+
+  <!-- Source dependencies -->
+  <property name="api.home"
+           value="${basedir}/${api.project}"/>
+  <property name="catalina.home" 
+           value="${basedir}/${catalina.project}"/>
+  <property name="jasper.home"
+           value="${basedir}/${jasper.project}"/>
+  <property name="jtc.home"
+           value="${basedir}/${jtc.project}"/>
+  <property name="tomcat.home"
+           value="${basedir}/${tomcat.project}"/>
+
+  <target name="build" depends="check.source,get.source"
+   description="Builds all components">
+
+    <ant dir="${tomcat.home}" target="download" />
+    <ant dir="${tomcat.home}" target="deploy" />
+
+  </target>
+
+  <!-- Top-level clean target added per Bugzilla 33325 -->
+  <target name="clean"
+          description="Clean (delete) all project files">
+    <echo message="Deleting all project files" />
+    <delete dir="${api.home}" />
+    <delete dir="${catalina.home}" />
+    <delete dir="${jasper.home}" />
+    <delete dir="${jtc.home}" />
+    <delete dir="${tomcat.home}" />
+  </target>
+
+  <target name="checkout"
+          description="Update or checkout required sources from SVN">
+
+    <echo level="info"
+        message="If the checkout fails, - todo - " />
+
+    <exec dir="${basedir}" executable="svn">
+         <arg line="checkout ${svnroot}/${current.loc} ${basedir}" />
+    </exec>
+
+  </target>
+
+  <!-- *************** UTILITY TARGETS *************** -->
+
+  <target name="check.source">
+
+    <available property="source.exists"
+                   file="${basedir}/${tomcat.project}" type="dir" />
+
+  </target>
+
+  <target name="get.source" unless="source.exists">
+
+    <antcall target="checkout" />
+
+  </target>
+
+</project>

Added: branches/tomcat5.5/upstream/5.5.20/build/resources/catalina-main.manifest
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/build/resources/catalina-main.manifest	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/build/resources/catalina-main.manifest	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,2 @@
+Main-Class: org.apache.catalina.startup.Catalina
+Class-Path: classes/ ../classes/ log4j.jar 

Added: branches/tomcat5.5/upstream/5.5.20/build/resources/config.ini
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/build/resources/config.ini	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/build/resources/config.ini	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,59 @@
+[Settings]
+NumFields=7
+
+[Field 1]
+Type=Label
+Text=HTTP/1.1 Connector Port
+left=0
+right=150
+top=5
+bottom=20
+
+[Field 2]
+Type=Text
+State=8080
+MaxLen=5
+left=150
+right=200
+top=5
+bottom=18
+
+[Field 3]
+Type=Label
+text=Administrator Login
+left=0
+right=300
+top=30
+bottom=45
+
+[Field 4]
+Type=Label
+Text=User Name
+left=0
+right=150
+top=50
+bottom=65
+
+[Field 5]
+Type=Text
+State=admin
+left=150
+right=250
+top=50
+bottom=63
+
+[Field 6]
+Type=Label
+Text=Password
+left=0
+right=150
+top=70
+bottom=85
+
+[Field 7]
+Type=Password
+left=150
+right=250
+top=70
+bottom=83
+

Added: branches/tomcat5.5/upstream/5.5.20/build/resources/confinstall/server_1.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/build/resources/confinstall/server_1.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/build/resources/confinstall/server_1.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,77 @@
+<!-- Example Server Configuration File -->
+<!-- Note that component elements are nested corresponding to their
+     parent-child relationships with each other -->
+
+<!-- A "Server" is a singleton element that represents the entire JVM,
+     which may contain one or more "Service" instances.  The Server
+     listens for a shutdown command on the indicated port.
+
+     Note:  A "Server" is not itself a "Container", so you may not
+     define subcomponents such as "Valves" or "Loggers" at this level.
+ -->
+
+<Server port="8005" shutdown="SHUTDOWN">
+
+  <!-- Comment these entries out to disable JMX MBeans support used for the 
+       administration web application -->
+  <Listener className="org.apache.catalina.core.AprLifecycleListener" />
+  <Listener className="org.apache.catalina.mbeans.ServerLifecycleListener" />
+  <Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" />
+  <Listener className="org.apache.catalina.storeconfig.StoreConfigLifecycleListener"/>
+
+  <!-- Global JNDI resources -->
+  <GlobalNamingResources>
+
+    <!-- Test entry for demonstration purposes -->
+    <Environment name="simpleValue" type="java.lang.Integer" value="30"/>
+
+    <!-- Editable user database that can also be used by
+         UserDatabaseRealm to authenticate users -->
+    <Resource name="UserDatabase" auth="Container"
+              type="org.apache.catalina.UserDatabase"
+       description="User database that can be updated and saved"
+           factory="org.apache.catalina.users.MemoryUserDatabaseFactory"
+          pathname="conf/tomcat-users.xml" />
+
+  </GlobalNamingResources>
+
+  <!-- A "Service" is a collection of one or more "Connectors" that share
+       a single "Container" (and therefore the web applications visible
+       within that Container).  Normally, that Container is an "Engine",
+       but this is not required.
+
+       Note:  A "Service" is not itself a "Container", so you may not
+       define subcomponents such as "Valves" or "Loggers" at this level.
+   -->
+
+  <!-- Define the Tomcat Stand-Alone Service -->
+  <Service name="Catalina">
+
+    <!-- A "Connector" represents an endpoint by which requests are received
+         and responses are returned.  Each Connector passes requests on to the
+         associated "Container" (normally an Engine) for processing.
+
+         By default, a non-SSL HTTP/1.1 Connector is established on port 8080.
+         You can also enable an SSL HTTP/1.1 Connector on port 8443 by
+         following the instructions below and uncommenting the second Connector
+         entry.  SSL support requires the following steps (see the SSL Config
+         HOWTO in the Tomcat 5 documentation bundle for more detailed
+         instructions):
+         * If your JDK version 1.3 or prior, download and install JSSE 1.0.2 or
+           later, and put the JAR files into "$JAVA_HOME/jre/lib/ext".
+         * Execute:
+             %JAVA_HOME%\bin\keytool -genkey -alias tomcat -keyalg RSA (Windows)
+             $JAVA_HOME/bin/keytool -genkey -alias tomcat -keyalg RSA  (Unix)
+           with a password value of "changeit" for both the certificate and
+           the keystore itself.
+
+         By default, DNS lookups are enabled when a web application calls
+         request.getRemoteHost().  This can have an adverse impact on
+         performance, so you can disable it by setting the
+         "enableLookups" attribute to "false".  When DNS lookups are disabled,
+         request.getRemoteHost() will return the String version of the
+         IP address of the remote client.
+    -->
+
+    <!-- Define a non-SSL HTTP/1.1 Connector on port 8080 -->
+    <Connector

Added: branches/tomcat5.5/upstream/5.5.20/build/resources/confinstall/server_2.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/build/resources/confinstall/server_2.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/build/resources/confinstall/server_2.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,287 @@
+               maxHttpHeaderSize="8192"
+               maxThreads="150" minSpareThreads="25" maxSpareThreads="75"
+               enableLookups="false" redirectPort="8443" acceptCount="100"
+               connectionTimeout="20000" disableUploadTimeout="true" />
+    <!-- Note : To disable connection timeouts, set connectionTimeout value
+     to 0 -->
+	
+	<!-- Note : To use gzip compression you could set the following properties :
+	
+			   compression="on" 
+			   compressionMinSize="2048" 
+			   noCompressionUserAgents="gozilla, traviata" 
+			   compressableMimeType="text/html,text/xml"
+	-->
+
+    <!-- Define a SSL HTTP/1.1 Connector on port 8443 -->
+    <!--
+    <Connector port="8443" maxHttpHeaderSize="8192"
+               maxThreads="150" minSpareThreads="25" maxSpareThreads="75"
+               enableLookups="false" disableUploadTimeout="true"
+               acceptCount="100" scheme="https" secure="true"
+               clientAuth="false" sslProtocol="TLS" />
+    -->
+
+    <!-- Define an AJP 1.3 Connector on port 8009 -->
+    <Connector port="8009" 
+               enableLookups="false" redirectPort="8443" protocol="AJP/1.3" />
+
+    <!-- Define a Proxied HTTP/1.1 Connector on port 8082 -->
+    <!-- See proxy documentation for more information about using this. -->
+    <!--
+    <Connector port="8082" 
+               maxThreads="150" minSpareThreads="25" maxSpareThreads="75"
+               enableLookups="false" acceptCount="100" connectionTimeout="20000"
+               proxyPort="80" disableUploadTimeout="true" />
+    -->
+
+    <!-- An Engine represents the entry point (within Catalina) that processes
+         every request.  The Engine implementation for Tomcat stand alone
+         analyzes the HTTP headers included with the request, and passes them
+         on to the appropriate Host (virtual host). -->
+
+    <!-- You should set jvmRoute to support load-balancing via AJP ie :
+    <Engine name="Standalone" defaultHost="localhost" jvmRoute="jvm1">         
+    --> 
+         
+    <!-- Define the top level container in our container hierarchy -->
+    <Engine name="Catalina" defaultHost="localhost">
+
+      <!-- The request dumper valve dumps useful debugging information about
+           the request headers and cookies that were received, and the response
+           headers and cookies that were sent, for all requests received by
+           this instance of Tomcat.  If you care only about requests to a
+           particular virtual host, or a particular application, nest this
+           element inside the corresponding <Host> or <Context> entry instead.
+
+           For a similar mechanism that is portable to all Servlet 2.4
+           containers, check out the "RequestDumperFilter" Filter in the
+           example application (the source for this filter may be found in
+           "$CATALINA_HOME/webapps/examples/WEB-INF/classes/filters").
+
+           Request dumping is disabled by default.  Uncomment the following
+           element to enable it. -->
+      <!--
+      <Valve className="org.apache.catalina.valves.RequestDumperValve"/>
+      -->
+
+      <!-- Because this Realm is here, an instance will be shared globally -->
+
+      <!-- This Realm uses the UserDatabase configured in the global JNDI
+           resources under the key "UserDatabase".  Any edits
+           that are performed against this UserDatabase are immediately
+           available for use by the Realm.  -->
+      <Realm className="org.apache.catalina.realm.UserDatabaseRealm"
+             resourceName="UserDatabase"/>
+
+      <!-- Comment out the old realm but leave here for now in case we
+           need to go back quickly -->
+      <!--
+      <Realm className="org.apache.catalina.realm.MemoryRealm" />
+      -->
+
+      <!-- Replace the above Realm with one of the following to get a Realm
+           stored in a database and accessed via JDBC -->
+
+      <!--
+      <Realm  className="org.apache.catalina.realm.JDBCRealm"
+             driverName="org.gjt.mm.mysql.Driver"
+          connectionURL="jdbc:mysql://localhost/authority"
+         connectionName="test" connectionPassword="test"
+              userTable="users" userNameCol="user_name" userCredCol="user_pass"
+          userRoleTable="user_roles" roleNameCol="role_name" />
+      -->
+
+      <!--
+      <Realm  className="org.apache.catalina.realm.JDBCRealm"
+             driverName="oracle.jdbc.driver.OracleDriver"
+          connectionURL="jdbc:oracle:thin:@ntserver:1521:ORCL"
+         connectionName="scott" connectionPassword="tiger"
+              userTable="users" userNameCol="user_name" userCredCol="user_pass"
+          userRoleTable="user_roles" roleNameCol="role_name" />
+      -->
+
+      <!--
+      <Realm  className="org.apache.catalina.realm.JDBCRealm"
+             driverName="sun.jdbc.odbc.JdbcOdbcDriver"
+          connectionURL="jdbc:odbc:CATALINA"
+              userTable="users" userNameCol="user_name" userCredCol="user_pass"
+          userRoleTable="user_roles" roleNameCol="role_name" />
+      -->
+
+      <!-- Define the default virtual host
+           Note: XML Schema validation will not work with Xerces 2.2.
+       -->
+      <Host name="localhost" appBase="webapps"
+       unpackWARs="true" autoDeploy="true"
+       xmlValidation="false" xmlNamespaceAware="false">
+
+        <!-- Defines a cluster for this node,
+             By defining this element, means that every manager will be changed.
+             So when running a cluster, only make sure that you have webapps in there
+             that need to be clustered and remove the other ones.
+             A cluster has the following parameters:
+
+             className = the fully qualified name of the cluster class
+
+             name = a descriptive name for your cluster, can be anything
+
+             mcastAddr = the multicast address, has to be the same for all the nodes
+
+             mcastPort = the multicast port, has to be the same for all the nodes
+             
+             mcastBindAddr = bind the multicast socket to a specific address
+             
+             mcastTTL = the multicast TTL if you want to limit your broadcast
+             
+             mcastSoTimeout = the multicast readtimeout 
+
+             mcastFrequency = the number of milliseconds in between sending a "I'm alive" heartbeat
+
+             mcastDropTime = the number a milliseconds before a node is considered "dead" if no heartbeat is received
+
+             tcpThreadCount = the number of threads to handle incoming replication requests, optimal would be the same amount of threads as nodes 
+
+             tcpListenAddress = the listen address (bind address) for TCP cluster request on this host, 
+                                in case of multiple ethernet cards.
+                                auto means that address becomes
+                                InetAddress.getLocalHost().getHostAddress()
+
+             tcpListenPort = the tcp listen port
+
+             tcpSelectorTimeout = the timeout (ms) for the Selector.select() method in case the OS
+                                  has a wakup bug in java.nio. Set to 0 for no timeout
+
+             printToScreen = true means that managers will also print to std.out
+
+             expireSessionsOnShutdown = true means that 
+
+             useDirtyFlag = true means that we only replicate a session after setAttribute,removeAttribute has been called.
+                            false means to replicate the session after each request.
+                            false means that replication would work for the following piece of code: (only for SimpleTcpReplicationManager)
+                            <%
+                            HashMap map = (HashMap)session.getAttribute("map");
+                            map.put("key","value");
+                            %>
+             replicationMode = can be either 'pooled', 'synchronous' or 'asynchronous'.
+                               * Pooled means that the replication happens using several sockets in a synchronous way. Ie, the data gets replicated, then the request return. This is the same as the 'synchronous' setting except it uses a pool of sockets, hence it is multithreaded. This is the fastest and safest configuration. To use this, also increase the nr of tcp threads that you have dealing with replication.
+                               * Synchronous means that the thread that executes the request, is also the
+                               thread the replicates the data to the other nodes, and will not return until all
+                               nodes have received the information.
+                               * Asynchronous means that there is a specific 'sender' thread for each cluster node,
+                               so the request thread will queue the replication request into a "smart" queue,
+                               and then return to the client.
+                               The "smart" queue is a queue where when a session is added to the queue, and the same session
+                               already exists in the queue from a previous request, that session will be replaced
+                               in the queue instead of replicating two requests. This almost never happens, unless there is a 
+                               large network delay.
+        -->             
+        <!--
+            When configuring for clustering, you also add in a valve to catch all the requests
+            coming in, at the end of the request, the session may or may not be replicated.
+            A session is replicated if and only if all the conditions are met:
+            1. useDirtyFlag is true or setAttribute or removeAttribute has been called AND
+            2. a session exists (has been created)
+            3. the request is not trapped by the "filter" attribute
+
+            The filter attribute is to filter out requests that could not modify the session,
+            hence we don't replicate the session after the end of this request.
+            The filter is negative, ie, anything you put in the filter, you mean to filter out,
+            ie, no replication will be done on requests that match one of the filters.
+            The filter attribute is delimited by ;, so you can't escape out ; even if you wanted to.
+
+            filter=".*\.gif;.*\.js;" means that we will not replicate the session after requests with the URI
+            ending with .gif and .js are intercepted.
+            
+            The deployer element can be used to deploy apps cluster wide.
+            Currently the deployment only deploys/undeploys to working members in the cluster
+            so no WARs are copied upons startup of a broken node.
+            The deployer watches a directory (watchDir) for WAR files when watchEnabled="true"
+            When a new war file is added the war gets deployed to the local instance,
+            and then deployed to the other instances in the cluster.
+            When a war file is deleted from the watchDir the war is undeployed locally 
+            and cluster wide
+        -->
+        
+        <!--
+        <Cluster className="org.apache.catalina.cluster.tcp.SimpleTcpCluster"
+                 managerClassName="org.apache.catalina.cluster.session.DeltaManager"
+                 expireSessionsOnShutdown="false"
+                 useDirtyFlag="true"
+                 notifyListenersOnReplication="true">
+
+            <Membership 
+                className="org.apache.catalina.cluster.mcast.McastService"
+                mcastAddr="228.0.0.4"
+                mcastPort="45564"
+                mcastFrequency="500"
+                mcastDropTime="3000"/>
+
+            <Receiver 
+                className="org.apache.catalina.cluster.tcp.ReplicationListener"
+                tcpListenAddress="auto"
+                tcpListenPort="4001"
+                tcpSelectorTimeout="100"
+                tcpThreadCount="6"/>
+
+            <Sender
+                className="org.apache.catalina.cluster.tcp.ReplicationTransmitter"
+                replicationMode="pooled"
+                ackTimeout="15000"/>
+
+            <Valve className="org.apache.catalina.cluster.tcp.ReplicationValve"
+                   filter=".*\.gif;.*\.js;.*\.jpg;.*\.htm;.*\.html;.*\.txt;"/>
+                   
+            <Deployer className="org.apache.catalina.cluster.deploy.FarmWarDeployer"
+                      tempDir="/tmp/war-temp/"
+                      deployDir="/tmp/war-deploy/"
+                      watchDir="/tmp/war-listen/"
+                      watchEnabled="false"/>
+        </Cluster>
+        -->        
+
+
+
+        <!-- Normally, users must authenticate themselves to each web app
+             individually.  Uncomment the following entry if you would like
+             a user to be authenticated the first time they encounter a
+             resource protected by a security constraint, and then have that
+             user identity maintained across *all* web applications contained
+             in this virtual host. -->
+        <!--
+        <Valve className="org.apache.catalina.authenticator.SingleSignOn" />
+        -->
+
+        <!-- Access log processes all requests for this virtual host.  By
+             default, log files are created in the "logs" directory relative to
+             $CATALINA_HOME.  If you wish, you can specify a different
+             directory with the "directory" attribute.  Specify either a relative
+             (to $CATALINA_HOME) or absolute path to the desired directory.
+        -->
+        <!--
+        <Valve className="org.apache.catalina.valves.AccessLogValve"
+                 directory="logs"  prefix="localhost_access_log." suffix=".txt"
+                 pattern="common" resolveHosts="false"/>
+        -->
+
+        <!-- Access log processes all requests for this virtual host.  By
+             default, log files are created in the "logs" directory relative to
+             $CATALINA_HOME.  If you wish, you can specify a different
+             directory with the "directory" attribute.  Specify either a relative
+             (to $CATALINA_HOME) or absolute path to the desired directory.
+             This access log implementation is optimized for maximum performance,
+             but is hardcoded to support only the "common" and "combined" patterns.
+        -->
+        <!--
+        <Valve className="org.apache.catalina.valves.FastCommonAccessLogValve"
+                 directory="logs"  prefix="localhost_access_log." suffix=".txt"
+                 pattern="common" resolveHosts="false"/>
+        -->
+
+      </Host>
+
+    </Engine>
+
+  </Service>
+
+</Server>

Added: branches/tomcat5.5/upstream/5.5.20/build/resources/confinstall/tomcat-users_1.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/build/resources/confinstall/tomcat-users_1.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/build/resources/confinstall/tomcat-users_1.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,6 @@
+<!--
+  NOTE:  By default, no user is included in the "manager" role required
+  to operate the "/manager" web application.  If you wish to use this app,
+  you must define such a user - the username and password are arbitrary.
+-->
+<tomcat-users>

Added: branches/tomcat5.5/upstream/5.5.20/build/resources/confinstall/tomcat-users_2.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/build/resources/confinstall/tomcat-users_2.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/build/resources/confinstall/tomcat-users_2.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,4 @@
+  <user name="tomcat" password="tomcat" roles="tomcat" />
+  <user name="role1"  password="tomcat" roles="role1"  />
+  <user name="both"   password="tomcat" roles="tomcat,role1" />
+</tomcat-users>

Added: branches/tomcat5.5/upstream/5.5.20/build/resources/deployer/build.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/build/resources/deployer/build.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/build/resources/deployer/build.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,101 @@
+<project name="Deployer" default="compile" basedir=".">
+
+  <property file="deployer.properties"/>
+
+  <!-- Configure the directory into which the web application is built -->
+  <property name="build"    value="${basedir}/build"/>
+
+  <!-- Configure the folder and context path for this application -->
+  <property name="webapp"   value="myapp"/>
+  <property name="path"     value="/myapp"/>
+
+  <!-- Configure properties to access the Manager application -->
+  <property name="url"      value="http://localhost:8080/manager"/>
+  <property name="username" value="tomcat"/>
+  <property name="password" value="tomcat"/>
+
+  <property name="webapp.path"     value="${build}/webapp${path}"/>
+
+  <path id="deployer.classpath">
+    <fileset dir="${basedir}/lib">
+      <include name="*.jar"/>
+    </fileset>
+  </path>
+
+  <!-- Configure the custom Ant tasks for the Manager application -->
+  <taskdef resource="org/apache/catalina/ant/catalina.tasks"
+           classpathref="deployer.classpath"/>
+
+  <!-- Executable Targets -->
+  <target name="clean" description="Removes build directory">
+    <delete dir="${build}" />
+  </target>
+
+  <target name="compile" description="Compile web application"
+          depends="clean">
+
+    <copy todir="${webapp.path}">
+      <fileset dir="${webapp}" />
+    </copy>
+
+    <jasper2 validateXml="false" 
+             uriroot="${webapp.path}" 
+             webXmlFragment="${webapp.path}/WEB-INF/generated_web.xml"
+             addWebXmlMappings="true"
+             outputDir="${webapp.path}/WEB-INF/classes" /> 
+
+    <validator path="${webapp.path}" />
+
+    <mkdir dir="${webapp.path}/WEB-INF/classes"/>
+    <mkdir dir="${webapp.path}/WEB-INF/lib"/>
+
+    <javac destdir="${webapp.path}/WEB-INF/classes"
+           optimize="off"
+           debug="${compile.debug}"
+           deprecation="${compile.deprecation}"
+           failonerror="false"
+           srcdir="${webapp.path}/WEB-INF/classes"
+           encoding="UTF-8"
+	   excludes="**/*.smap">
+      <classpath>
+        <fileset dir="${webapp.path}/WEB-INF/lib">
+          <include name="*.jar"/>
+        </fileset>
+        <fileset dir="${basedir}/lib">
+          <include name="*.jar"/>
+        </fileset>
+      </classpath>
+      <include name="**" />
+      <exclude name="tags/**" />
+    </javac>
+
+    <jar destfile="${webapp.path}.war"
+         basedir="${webapp.path}" />
+
+  </target>
+
+  <target name="deploy" description="Deploy web application">
+    <deploy url="${url}" username="${username}" password="${password}"
+            path="${path}" war="${webapp.path}.war" update="true" />
+  </target>
+
+  <target name="undeploy" description="Undeploy web application">
+    <undeploy url="${url}" username="${username}" password="${password}"
+              path="${path}"/>
+  </target>
+
+  <!-- Webapp lifecycle control -->
+  <target name="start" description="Start web application">
+    <start url="${url}" username="${username}" password="${password}"
+           path="${path}"/>
+  </target>
+  <target name="reload" description="Reload web application">
+    <reload url="${url}" username="${username}" password="${password}"
+            path="${path}"/>
+  </target>
+  <target name="stop" description="Stop web application">
+    <stop url="${url}" username="${username}" password="${password}"
+          path="${path}"/>
+  </target>
+
+</project>

Added: branches/tomcat5.5/upstream/5.5.20/build/resources/header.bmp
===================================================================
(Binary files differ)


Property changes on: branches/tomcat5.5/upstream/5.5.20/build/resources/header.bmp
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: branches/tomcat5.5/upstream/5.5.20/build/resources/jvm.ini
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/build/resources/jvm.ini	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/build/resources/jvm.ini	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,18 @@
+[Settings]
+NumFields=2
+
+[Field 1]
+Type=Label
+Text=Please select the path of a J2SE 5.0 JRE installed on your system:
+left=0
+right=300
+top=5
+bottom=20
+
+[Field 2]
+Type=DirRequest
+Left=0
+Right=-1
+Top=65
+Bottom=78
+

Added: branches/tomcat5.5/upstream/5.5.20/build/resources/log4j.properties
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/build/resources/log4j.properties	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/build/resources/log4j.properties	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,9 @@
+log4j.rootCategory=info, stdout
+
+log4j.appender.stdout=org.apache.log4j.ConsoleAppender
+log4j.appender.stdout.layout.ConversionPattern=%r [%t] %-5p\: %-15c{2} - %m%n
+log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
+
+#log4j.category.org.apache.catalina=info
+
+#log4j.category.org.apache.jasper.compiler.Compiler=debug

Added: branches/tomcat5.5/upstream/5.5.20/build/resources/logging.properties
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/build/resources/logging.properties	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/build/resources/logging.properties	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,55 @@
+handlers = 1catalina.org.apache.juli.FileHandler, 2localhost.org.apache.juli.FileHandler, 3manager.org.apache.juli.FileHandler, 4admin.org.apache.juli.FileHandler, 5host-manager.org.apache.juli.FileHandler, java.util.logging.ConsoleHandler
+
+.handlers = 1catalina.org.apache.juli.FileHandler, java.util.logging.ConsoleHandler
+
+############################################################
+# Handler specific properties.
+# Describes specific configuration info for Handlers.
+############################################################
+
+1catalina.org.apache.juli.FileHandler.level = FINE
+1catalina.org.apache.juli.FileHandler.directory = ${catalina.base}/logs
+1catalina.org.apache.juli.FileHandler.prefix = catalina.
+
+2localhost.org.apache.juli.FileHandler.level = FINE
+2localhost.org.apache.juli.FileHandler.directory = ${catalina.base}/logs
+2localhost.org.apache.juli.FileHandler.prefix = localhost.
+
+3manager.org.apache.juli.FileHandler.level = FINE
+3manager.org.apache.juli.FileHandler.directory = ${catalina.base}/logs
+3manager.org.apache.juli.FileHandler.prefix = manager.
+
+4admin.org.apache.juli.FileHandler.level = FINE
+4admin.org.apache.juli.FileHandler.directory = ${catalina.base}/logs
+4admin.org.apache.juli.FileHandler.prefix = admin.
+
+5host-manager.org.apache.juli.FileHandler.level = FINE
+5host-manager.org.apache.juli.FileHandler.directory = ${catalina.base}/logs
+5host-manager.org.apache.juli.FileHandler.prefix = host-manager.
+
+java.util.logging.ConsoleHandler.level = FINE
+java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter
+
+
+############################################################
+# Facility specific properties.
+# Provides extra control for each logger.
+############################################################
+
+org.apache.catalina.core.ContainerBase.[Catalina].[localhost].level = INFO
+org.apache.catalina.core.ContainerBase.[Catalina].[localhost].handlers = 2localhost.org.apache.juli.FileHandler
+
+org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/manager].level = INFO
+org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/manager].handlers = 3manager.org.apache.juli.FileHandler
+
+org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/admin].level = INFO
+org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/admin].handlers = 4admin.org.apache.juli.FileHandler
+
+org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/host-manager].level = INFO
+org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/host-manager].handlers = 5host-manager.org.apache.juli.FileHandler
+
+# For example, set the com.xyz.foo logger to only log SEVERE
+# messages:
+#org.apache.catalina.startup.ContextConfig.level = FINE
+#org.apache.catalina.startup.HostConfig.level = FINE
+#org.apache.catalina.session.ManagerBase.level = FINE

Added: branches/tomcat5.5/upstream/5.5.20/build/resources/main.ico
===================================================================
(Binary files differ)


Property changes on: branches/tomcat5.5/upstream/5.5.20/build/resources/main.ico
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: branches/tomcat5.5/upstream/5.5.20/build/resources/mbeans/tomcat5-ant.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/build/resources/mbeans/tomcat5-ant.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/build/resources/mbeans/tomcat5-ant.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,281 @@
+<project name="tomcat-embed" default="start" basedir=".">
+
+  <property file="${user.home}/build.properties"/>
+  <property file="build.properties"/>
+
+  <property name="tomcat.home" location="." />
+  <!-- This matches the build struct with build and embed at the same level -->
+  <property name="tomcat.webapps" location="${tomcat.home}/webapps" />
+
+  <path id="tomcatCP-extra" /> 
+
+  <target name="init" unless="init.done">
+
+    <path id="tomcatCP" >
+      <path refid="tomcatCP-extra"/>
+
+      <!-- Just include everything for now -->
+      <fileset dir="${tomcat.home}/lib" includes="*.jar"/>
+      <pathelement  path="${tomcat.home}/conf"/>
+      <!-- my log4j.properties -->
+      <pathelement  path="/ws/log4j"/>
+    </path>
+
+    <taskdef resource="org/apache/commons/modeler/ant/ant.properties"
+             classpathref="tomcatCP" />
+    <property name="init.done" value="true"/>
+
+    <available classname="com.sun.jdmk.comm.HtmlAdaptorServer"
+               property="jmxritools-available" 
+               classpathref="tomcatCP" />
+
+    <available classname="mx4j.adaptor.http.XSLTProcessor"
+               property="mx4jtools-available" 
+               classpathref="tomcatCP" />
+  </target>
+
+
+  <!-- ==================== Console - for debugging. ==================== 
+       Call this target if you want the console added.
+  -->
+
+  <target name="jmx-console" depends="jmx-console-ri,jmx-console-mx4j" />
+
+  <target name="jmx-console-ri" 
+          depends="init" 
+          description="Enable JMX-RI console ( web interface )" 
+          if="jmxritools-available">
+
+    <jmx-service>
+      <mbean code="com.sun.jdmk.comm.HtmlAdaptorServer"
+             name="jmx-console:type=HtmlAdaptorServer,port=9988">
+         <attribute name="Port" value="9988"/>
+     </mbean>
+    </jmx-service>    
+
+  </target>
+
+  <target name="jmx-console-mx4j" 
+          depends="init" 
+          description="Enable JMX console ( mx4j )" 
+          if="mx4jtools-available">
+
+    <jmx-service>
+      <mbean code="mx4j.adaptor.http.XSLTProcessor"
+             name="Http:name=XSLTProcessor">
+      </mbean>
+      <mbean code="mx4j.adaptor.http.HttpAdaptor"
+             name="Http:name=HttpAdaptor">
+         <attribute name="Port" value="9998"/>
+         <attribute name="ProcessorName" value="Http:name=XSLTProcessor"/>
+     </mbean>
+    </jmx-service>    
+
+  </target>
+
+  <!-- ======================= Proxy test ================ -->
+  <target name="proxy-run" depends="init,jmx-console,proxy" />
+
+  <target name="proxy" depends="init"
+        description="Start a JMX proxy service">
+    <property name="localDomain" value="catalina.proxy" />
+    <property name="remoteDomain" value="catalina" />
+
+    <jmx-service>
+       <mbean code="org.apache.commons.modeler.mbeans.SimpleRemoteConnector"
+              name="modjk:type=jmxProxy,name=apache80" 
+              modeler="true" >
+         <attribute name="webServerPort"  value="80"/>
+         <attribute name="statusPath"  value="/jkstatus"/>
+         <attribute name="filter"  value="*"/>
+         <attribute name="user"  value="tomcat"/>
+         <attribute name="pass"  value="tomcat"/>
+       </mbean>
+    </jmx-service>
+   
+    <jmx-service>
+       <mbean code="org.apache.commons.modeler.mbeans.SimpleRemoteConnector"
+              name="modjk:type=jmxProxy,name=apache8003" 
+              modeler="true" >
+         <attribute name="webServerPort"  value="8003"/>
+         <attribute name="statusPath"  value="/jkstatus"/>
+         <attribute name="filter"  value="*"/>
+         <attribute name="user"  value="tomcat"/>
+         <attribute name="pass"  value="tomcat"/>
+       </mbean>
+    </jmx-service>
+
+    <jmx-service>
+       <mbean code="org.apache.commons.modeler.mbeans.SimpleRemoteConnector"
+              name="Catalina9080:type=jmxProxy,name=tomcat9080" 
+              modeler="true" >
+         <attribute name="webServerPort"  value="9080"/>
+         <attribute name="statusPath"  value="/manager/jmxproxy"/>
+         <attribute name="domain"  value="Catalina"/>
+         <attribute name="user"  value="tomcat"/>
+         <attribute name="pass"  value="tomcat"/>
+       </mbean>
+    </jmx-service>
+
+    <jmx-service>
+       <mbean code="org.apache.commons.modeler.mbeans.SimpleRemoteConnector"
+              name="Catalina:type=jmxProxy,name=tomcat8080" 
+              modeler="true" >
+         <attribute name="webServerPort"  value="8080"/>
+         <attribute name="statusPath"  value="/manager/jmxproxy"/>
+         <attribute name="domain"  value="Catalina"/>
+         <attribute name="user"  value="tomcat"/>
+         <attribute name="pass"  value="tomcat"/>
+       </mbean>
+    </jmx-service>
+
+
+    <echo message="Proxy running"/>
+    <sleep hours="1"/>
+  </target>
+
+
+  <!-- ======================= Server.xml based - backward compat ================ -->
+
+  <property name="domain" value="Catalina" />
+  <property name="jsr77Domain" value="Catalina" />
+
+  <!-- ======================= JMX only  ================ -->
+
+  <target name="run" depends="init,jmx-console"
+        description="Start tomcat as an mbean, no server.xml">
+
+    <property name="catalina.useNaming" value="false" />
+
+<!--
+    <modelerRegistry resource="org/apache/catalina/mbeans/mbeans-descriptors.xml" />
+    <modelerRegistry resource="org/apache/catalina/loader/mbeans-descriptors.xml" />
+-->
+    <mkdir dir="${tomcat.home}/work/${domain}/" />
+
+    <jmx-service>
+<!--
+      Should be optional - but the name is used in several places.
+      The whole name should disapear - use domain instead
+-->
+       <mbean name="${domain}:type=Server" 
+              code="org.apache.catalina.core.StandardServer"
+              modeler="true">
+         <attribute name="port" value="9005"/>
+       </mbean>
+
+       <mbean name="${domain}:type=Service" 
+              code="org.apache.catalina.core.StandardService"
+              modeler="true">
+         <attribute name="name" value="Tomcat-Standalone"/>
+       </mbean>
+
+       <mbean name="${domain}:type=Engine" 
+              code="org.apache.catalina.core.StandardEngine"
+              modeler="true">
+         <attribute name="name" value="Tomcat-Standalone"/>
+         <attribute name="baseDir" value="${tomcat.home}"/>
+         <attribute name="defaultHost" value="localhost"/>
+       </mbean>
+
+<!--
+       <mbean name="${domain}:type=Realm" 
+              code="org.apache.catalina.realm.JAASRealm" modeler="true">
+       </mbean>
+-->
+
+       <mbean name="${domain}:type=Realm" 
+              code="org.apache.catalina.realm.MemoryRealm" modeler="true">
+         <attribute name="pathname"
+                    value="${tomcat.home}/conf/tomcat-users.xml" />
+       </mbean>
+
+       <mbean name="${domain}:type=Connector,port=9080" 
+              code="org.apache.catalina.connector.Connector"
+              modeler="true">
+          <attribute name="port" value="9080" />
+       </mbean>
+
+
+<!-- Optional: when the context is created it'll create a host if none is found. -->
+<!-- Setting appBase will make use of auto deployment. Regular deployment can be used using
+     static declarations of MBeans for each of the individual contexts -->
+
+       <mbean name="${domain}:type=Host,host=localhost" 
+              code="org.apache.catalina.core.StandardHost" modeler="true">
+         <attribute name="name" value="localhost"/>
+         <attribute name="appBase" value="webapps"/>
+       </mbean>
+
+       <!-- 
+       <mbean name="${jsr77Domain}:j2eeType=WebModule,name=//localhost/,J2EEApplication=none,J2EEServer=none" 
+              code="org.apache.catalina.core.StandardContext"  modeler="true">
+         <attribute name="docBase" value="${tomcat.webapps}/ROOT" />
+         <attribute name="privileged" value="true" />
+         <attribute name="engineName" value="${domain}" />
+       </mbean>
+
+       <mbean name="${jsr77Domain}:j2eeType=WebModule,name=//localhost/servlets-examples,J2EEApplication=none,J2EEServer=none" 
+              code="org.apache.catalina.core.StandardContext"  modeler="true">
+         <attribute name="docBase" value="${tomcat.webapps}/servlets-examples" />
+         <attribute name="privileged" value="true" />
+         <attribute name="engineName" value="${domain}" />
+       </mbean>
+
+       <mbean name="${jsr77Domain}:j2eeType=WebModule,name=//localhost/jsp-examples,J2EEApplication=none,J2EEServer=none" 
+              code="org.apache.catalina.core.StandardContext"  modeler="true">
+         <attribute name="docBase" value="${tomcat.webapps}/jsp-examples" />
+         <attribute name="privileged" value="true" />
+         <attribute name="engineName" value="${domain}" />
+       </mbean>
+
+       <mbean name="${jsr77Domain}:j2eeType=WebModule,name=//localhost/tomcat-docs,J2EEApplication=none,J2EEServer=none" 
+              code="org.apache.catalina.core.StandardContext"  modeler="true">
+         <attribute name="docBase" value="${tomcat.webapps}/tomcat-docs" />
+         <attribute name="privileged" value="true" />
+         <attribute name="engineName" value="${domain}" />
+       </mbean>
+
+       <mbean name="${jsr77Domain}:j2eeType=WebModule,name=//localhost/manager,J2EEApplication=none,J2EEServer=none" 
+              code="org.apache.catalina.core.StandardContext"  modeler="true">
+         <attribute name="docBase" value="${tomcat.webapps}/manager" />
+         <attribute name="engineName" value="${domain}" />
+         <attribute name="privileged" value="true" />
+       </mbean>
+       -->
+
+       <!-- The realm must be declared after the web module (for now).
+       <mbean name="${domain}:type=Realm,host=localhost,path=manager" 
+              code="org.apache.catalina.realm.MemoryRealm" modeler="true">
+         <attribute name="pathname"
+                    value="${tomcat.home}/conf/tomcat-users.xml" />
+       </mbean>
+       -->
+
+       <!--
+       <mbean name="${domain}:j2eeType=WebModule,name=//localhost/admin,J2EEApplication=none,J2EEServer=none" 
+              code="org.apache.catalina.core.StandardContext"  modeler="true">
+         <attribute name="docBase" value="${tomcat.webapps}/admin" />
+         <attribute name="privileged" value="true" />
+       </mbean>
+       -->
+
+    </jmx-service>
+  </target>
+
+
+  <!-- ==================== Await ==================== 
+       Call this target if you want the build file to hang in "await". Tomcat stop or ^C will stop the ant execution.
+    -->
+  <target name="await" depends="init"
+        description="Wait for tomcat stop. Call this target after run">
+    <jmx objectName="${domain}:type=Server"
+         operation="await" />
+    <sleep hours="1"/>
+  </target>
+
+  <target name="start"
+              depends="init,run,await" 
+  			  description="Start tomcat, wait for stop message"/>
+
+</project>

Added: branches/tomcat5.5/upstream/5.5.20/build/resources/side_left.bmp
===================================================================
(Binary files differ)


Property changes on: branches/tomcat5.5/upstream/5.5.20/build/resources/side_left.bmp
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: branches/tomcat5.5/upstream/5.5.20/build/resources/tickno.bmp
===================================================================
(Binary files differ)


Property changes on: branches/tomcat5.5/upstream/5.5.20/build/resources/tickno.bmp
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: branches/tomcat5.5/upstream/5.5.20/build/resources/tickyes.bmp
===================================================================
(Binary files differ)


Property changes on: branches/tomcat5.5/upstream/5.5.20/build/resources/tickyes.bmp
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: branches/tomcat5.5/upstream/5.5.20/build/resources/tomcat.ico
===================================================================
(Binary files differ)


Property changes on: branches/tomcat5.5/upstream/5.5.20/build/resources/tomcat.ico
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: branches/tomcat5.5/upstream/5.5.20/build/resources/tomcat.spec
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/build/resources/tomcat.spec	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/build/resources/tomcat.spec	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,89 @@
+%define version 5.0.25
+%define base /opt/jakarta-tomcat-%{version}
+
+Summary: Apache Jakarta Servlet/JSP server 
+Name: jakarta-tomcat
+Version: %{version}
+Release: 1asf
+Vendor: Apache Software Foundation
+Group: System Environment/Daemons
+Copyright: Apache License
+BuildArch: noarch
+URL: http://jakarta.apache.org/tomcat
+BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-buildroot 
+Provides: jakarta-tomcat tomcat tomcat5
+
+# No requires - Java should be installed, but it can be installed for Sun's site as binary ( no RPM ) or 
+# in some other form. Adding dependency would require the user to install some dummy java RPM  he doesn't want
+# 
+
+# This is a complete distribution - using exactly the same jar files that we used when testing tomcat.
+# While this may create duplication with other RPMs distributing Xerces or MX4J - our goal is to 
+# have the most stable tomcat, even if you waste few megs of  hard drive space. 
+
+# TODO: decide over /opt or /usr/local
+Prefix: /opt
+
+# We build from the official binary distribution - it should produce identical result as on all other OSes and linux variants.
+Source: http://www.apache.org/dist/jakarta/tomcat-5/v%{version}/bin/jakarta-tomcat-%{version}.tar.gz
+
+%description
+Servlet container for developing Web applications in Java. Used as basis for the Reference Implementation 
+of the Servlet and JSP specificiations. This RPM mirrors the layout used by official Tomcat distributions
+on all other OSes and linux variants. 
+
+If you want a FHS-based package - be warned that tomcat may not work very well. ( TODO: add more warnings !).
+
+If you still want FHS-based package - please use jpackage.org or an RPM that is using the same exact layout.
+
+
+%prep
+%setup -q -n jakarta-tomcat-%{version} -T -b 0
+
+%build
+
+
+%install
+# cd jakarta-tomcat-%{version}
+
+install -d %{buildroot}/opt/jakarta-tomcat-%{version}
+cp -a * ${RPM_BUILD_ROOT}/opt/jakarta-tomcat-%{version}
+
+%clean
+
+%pre
+grep '^tomcat:' /etc/group > /dev/null
+if [ $? eq 1 ] ; then 
+  %{_sbindir}/groupadd tomcat
+fi
+
+grep '^tomcat:' /etc/passwd > /dev/null
+
+if [ $? eq 1 ] ; then 
+  %{_sbindir}/useradd -c "Tomcat Server" -d /opt/jakarta-tomcat-4 -g tomcat tomcat 
+fi
+
+
+%post
+ln -s /opt/jakarta-tomcat-%{version}/bin/catalina.sh /etc/init.d
+
+%preun
+
+%files
+%defattr(-,tomcat,tomcat,0755)
+%config(noreplace) %{base}/conf
+%{base}/NOTICE
+%{base}/LICENSE
+%{base}/RELEASE-NOTES
+%{base}/*.txt
+%{base}/bin
+%{base}/server
+%{base}/common
+%{base}/temp
+%{base}/webapps
+
+
+%changelog
+* Mon May 17 2004 Costin Manolache <costin at apache.org> 0:4.1.30-1asf
+- Initial version
+  

Added: branches/tomcat5.5/upstream/5.5.20/build/resources/uninst.ico
===================================================================
(Binary files differ)


Property changes on: branches/tomcat5.5/upstream/5.5.20/build/resources/uninst.ico
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: branches/tomcat5.5/upstream/5.5.20/build/resources/welcome.bin.html
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/build/resources/welcome.bin.html	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/build/resources/welcome.bin.html	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,43 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<HTML><HEAD><TITLE>Apache Tomcat @VERSION@</TITLE>
+<META http-equiv=Content-Type content="text/html">
+</HEAD>
+<BODY>
+<P>
+<H3>Apache Tomcat @VERSION@</H3>
+<P></P>
+<p>Useful references:
+<ul>
+<li><a href="RELEASE-NOTES">Release notes</a>, with important information 
+about known issues</li>
+<li><a href="http://tomcat.apache.org/tomcat-5.5-doc/changelog.html">Changelog</a></li>
+<li><a href="http://tomcat.apache.org/tomcat-5.5-doc/status.html">Status</a></li>
+</ul>
+</p>
+
+<p><b>NOTE: The tar files in this distribution use GNU tar extensions, 
+and must be untarred with a GNU compatible version of tar. The version 
+of <CODE>tar</CODE> on Solaris and Mac OS X will not work with 
+these files.</b></P>
+
+<p><font color="red">Tomcat 5.5 requires JRE 5.0 by default.  Read the 
+RELEASE-NOTES and the RUNNING.txt file in the distribution for more details.
+</font></p>
+
+<p>Packaging Details (or "What Should I Download?")
+  <ul>
+    <li>apache-tomcat-[version].zip or .tar.gz: base distro, all non-embedded users download this.</li>
+    <li>apache-tomcat-[version].exe: Windows installer for Tomcat.  Please note that while this distribution includes the vast majority of the base distribution, some of the command-line scripts for launching Tomcat are not included.  This distribution is intended for those users planning to launch Tomcat through the Windows shortcuts or services.</li>
+    <li>apache-tomcat-[version]-admin.zip or .tar.gz: the Tomcat Administration webapp only.</li>
+    <li>apache-tomcat-[version]-compat.zip or .tar.gz: required in addition to the base distro for using Tomcat with a Java 1.4 environment.</li>
+    <li>apache-tomcat-[version]-deployer.zip or .tar.gz: the standalone Tomcat Web Application Deployer.</li>
+    <li>apache-tomcat-[version]-embed.zip or .tar.gz: for using Tomcat only as an embedded servlet container.</li>
+  </ul>
+</p>
+
+<P>Thank you for using <A href="http://tomcat.apache.org/">Tomcat</A>!. 
+</P>
+<P><B>The Apache Tomcat Project</B> <BR><A 
+href="http://tomcat.apache.org/">http://tomcat.apache.org/</A> </P>
+<P>
+<P></P></BODY></HTML>

Added: branches/tomcat5.5/upstream/5.5.20/build/resources/welcome.main.html
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/build/resources/welcome.main.html	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/build/resources/welcome.main.html	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,43 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<HTML><HEAD><TITLE>Apache Tomcat @VERSION@</TITLE>
+<META http-equiv=Content-Type content="text/html">
+</HEAD>
+<BODY>
+<P>
+<H3>Apache Tomcat @VERSION@</H3>
+<P></P>
+<p>Useful references:
+<ul>
+<li><a href="RELEASE-NOTES">Release notes</a>, with important information 
+about known issues</li>
+<li><a href="http://tomcat.apache.org/tomcat-5.5-doc/changelog.html">Changelog</a></li>
+<li><a href="http://tomcat.apache.org/tomcat-5.5-doc/status.html">Status</a></li>
+</ul>
+</p>
+
+<p><b>NOTE: The tar files in this distribution use GNU tar extensions, 
+and must be untarred with a GNU compatible version of tar. The version 
+of <CODE>tar</CODE> on Solaris and Mac OS X will not work with 
+these files.</b></P>
+
+<p><font color="red">Tomcat 5.5 requires JRE 5.0 by default.  Read the 
+RELEASE-NOTES and the RUNNING.txt file in the distribution for more details.
+</font></p>
+
+<p>Packaging Details (or "What Should I Download?")
+  <ul>
+    <li>apache-tomcat-[version].zip or .tar.gz: base distro, all non-embedded users download this.</li>
+    <li>apache-tomcat-[version].exe: Windows installer with base distro contents + Windows installation.</li>
+    <li>apache-tomcat-[version]-admin.zip or .tar.gz: the Tomcat Administration webapp only.</li>
+    <li>apache-tomcat-[version]-compat.zip or .tar.gz: required in addition to the base distro for using tomcat with a Java 1.4 environment.</li>
+    <li>apache-tomcat-[version]-deployer.zip or .tar.gz: the standalone Tomcat Web Application Deployer.</li>
+    <li>apache-tomcat-[version]-embed.zip or .tar.gz: for using Tomcat only as an embedded servlet container.</li>
+  </ul>
+</p>
+
+<P>Thank you for using <A href="http://tomcat.apache.org/">Tomcat</A>!. 
+</P>
+<P><B>The Apache Tomcat Project</B> <BR><A 
+href="http://tomcat.apache.org/">http://tomcat.apache.org/</A> </P>
+<P>
+<P></P></BODY></HTML>

Added: branches/tomcat5.5/upstream/5.5.20/build/sign.bat
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/build/sign.bat	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/build/sign.bat	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,12 @@
+
+rem Example script to sign the entire release
+rem pass in your password as the first argument, then this script will
+rem sign all the files in the release directory
+
+rem todo - make one for unix as well, and avoid signing the .md5 files
+
+ at echo off
+FOR /R %cd%\release\v5.5.20 %%i in (*.*) do (
+  echo Signing %%i
+  echo %1|gpg --passphrase-fd 0 -a -b %%i 
+)

Added: branches/tomcat5.5/upstream/5.5.20/build/tag.bat
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/build/tag.bat	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/build/tag.bat	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,20 @@
+ at echo off
+rem  Expects one argument, the tag name (no quotes needed, e.g. TOMCAT_5_5_13)
+
+rem  Build
+svn copy https://svn.apache.org/repos/asf/tomcat/build/tc5.5.x https://svn.apache.org/repos/asf/tomcat/build/tags/tc5.5.x/%1 -m "Tagging Tomcat version %1."
+
+rem  Connectors
+svn copy https://svn.apache.org/repos/asf/tomcat/connectors/trunk https://svn.apache.org/repos/asf/tomcat/connectors/tags/tc5.5.x/%1 -m "Tagging Tomcat version %1."
+
+rem  Container
+svn copy https://svn.apache.org/repos/asf/tomcat/container/tc5.5.x https://svn.apache.org/repos/asf/tomcat/container/tags/tc5.5.x/%1 -m "Tagging Tomcat version %1."
+
+rem  Jasper
+svn copy https://svn.apache.org/repos/asf/tomcat/jasper/tc5.5.x https://svn.apache.org/repos/asf/tomcat/jasper/tags/tc5.5.x/%1 -m "Tagging Tomcat version %1."
+
+rem  ServletAPI
+svn copy https://svn.apache.org/repos/asf/tomcat/servletapi/servlet2.4-jsp2.0-tc5.x https://svn.apache.org/repos/asf/tomcat/servletapi/tags/servlet2.4-jsp2.0-tc5.x/%1 -m "Tagging Tomcat version %1."
+
+rem  Site
+svn copy https://svn.apache.org/repos/asf/tomcat/site/trunk https://svn.apache.org/repos/asf/tomcat/site/tags/%1 -m "Tagging Tomcat version %1."

Added: branches/tomcat5.5/upstream/5.5.20/build/tomcat.nsi
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/build/tomcat.nsi	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/build/tomcat.nsi	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,700 @@
+
+; Tomcat script for Nullsoft Installer
+; $Id: tomcat.nsi 441019 2006-09-07 08:31:38Z mturk $
+
+  ;Compression options
+  CRCCheck on
+  SetCompress force
+  SetCompressor lzma
+  SetDatablockOptimize on
+
+  Name "Apache Tomcat"
+
+  ;Product information
+  VIAddVersionKey ProductName "Apache Tomcat"
+  VIAddVersionKey CompanyName "Apache Software Foundation"
+  VIAddVersionKey LegalCopyright "Copyright (c) 1999-2005 The Apache Software Foundation"
+  VIAddVersionKey FileDescription "Apache Tomcat Installer"
+  VIAddVersionKey FileVersion "2.0"
+  VIAddVersionKey ProductVersion "@VERSION@"
+  VIAddVersionKey Comments "tomcat.apache.org"
+  VIAddVersionKey InternalName "apache-tomcat- at VERSION@.exe"
+  VIProductVersion @VERSION_NUMBER@
+
+!include "MUI.nsh"
+!include "StrFunc.nsh"
+${StrRep}
+  Var "JavaHome"
+
+
+
+;--------------------------------
+;Configuration
+
+  !define MUI_HEADERIMAGE
+  !define MUI_HEADERIMAGE_RIGHT
+  !define MUI_HEADERIMAGE_BITMAP header.bmp
+  !define MUI_WELCOMEFINISHPAGE_BITMAP side_left.bmp 
+  !define MUI_FINISHPAGE_SHOWREADME "$INSTDIR\webapps\ROOT\RELEASE-NOTES.txt"
+  !define MUI_FINISHPAGE_RUN $INSTDIR\bin\tomcat5w.exe
+  !define MUI_FINISHPAGE_RUN_PARAMETERS //MR//Tomcat5
+  !define MUI_FINISHPAGE_NOREBOOTSUPPORT
+
+  !define MUI_ABORTWARNING
+
+  !define TEMP1 $R0
+  !define TEMP2 $R1
+
+  !define MUI_ICON tomcat.ico
+  !define MUI_UNICON tomcat.ico
+
+  ;General
+  OutFile tomcat-installer.exe
+
+  ;Install Options pages
+  LangString TEXT_JVM_TITLE ${LANG_ENGLISH} "Java Virtual Machine"
+  LangString TEXT_JVM_SUBTITLE ${LANG_ENGLISH} "Java Virtual Machine path selection."
+  LangString TEXT_JVM_PAGETITLE ${LANG_ENGLISH} ": Java Virtual Machine path selection"
+
+  LangString TEXT_CONF_TITLE ${LANG_ENGLISH} "Configuration"
+  LangString TEXT_CONF_SUBTITLE ${LANG_ENGLISH} "Tomcat basic configuration."
+  LangString TEXT_CONF_PAGETITLE ${LANG_ENGLISH} ": Configuration Options"
+
+  ;Install Page order
+  !insertmacro MUI_PAGE_WELCOME
+  !insertmacro MUI_PAGE_LICENSE INSTALLLICENSE
+  !insertmacro MUI_PAGE_COMPONENTS
+  !insertmacro MUI_PAGE_DIRECTORY
+  Page custom SetConfiguration Void "$(TEXT_CONF_PAGETITLE)"
+  Page custom SetChooseJVM Void "$(TEXT_JVM_PAGETITLE)"
+  !insertmacro MUI_PAGE_INSTFILES
+  Page custom CheckUserType
+  !insertmacro MUI_PAGE_FINISH
+
+  ;Uninstall Page order
+  !insertmacro MUI_UNPAGE_CONFIRM
+  !insertmacro MUI_UNPAGE_INSTFILES
+
+  ;License dialog
+  LicenseData License.rtf
+
+  ;Component-selection page
+    ;Descriptions
+    LangString DESC_SecTomcat ${LANG_ENGLISH} "Install the Tomcat Servlet container."
+    LangString DESC_SecTomcatCore ${LANG_ENGLISH} "Install the Tomcat Servlet container core."
+    LangString DESC_SecTomcatService ${LANG_ENGLISH} "Automatically start Tomcat when the computer is started. This requires Windows NT 4.0, Windows 2000 or Windows XP."
+    LangString DESC_SecTomcatNative ${LANG_ENGLISH} "Downloads and installs Tomcat native .dll for better performance and scalability in production environments."
+;    LangString DESC_SecTomcatSource ${LANG_ENGLISH} "Install the Tomcat source code."
+    LangString DESC_SecMenu ${LANG_ENGLISH} "Create a Start Menu program group for Tomcat."
+    LangString DESC_SecDocs ${LANG_ENGLISH} "Install the Tomcat documentation bundle. This include documentation on the servlet container and its configuration options, on the Jasper JSP page compiler, as well as on the native webserver connectors."
+    LangString DESC_SecExamples ${LANG_ENGLISH} "Installs some examples web applications."
+    LangString DESC_SecAdmin ${LANG_ENGLISH} "Installs the administration web application.";
+;    LangString DESC_SecWebapps ${LANG_ENGLISH} "Installs other utility web applications (WebDAV, balancer, etc)."
+;    LangString DESC_SecCompat ${LANG_ENGLISH} "Installs Java2™ compatibility package. This release of Apache Tomcat was packaged to run on J2SE 5.0 or later. It can be run on earlier JVMs by installng this package."
+
+  ;Language
+  !insertmacro MUI_LANGUAGE English
+
+  ;Folder-select dialog
+  InstallDir "$PROGRAMFILES\Apache Software Foundation\Tomcat 5.5"
+
+  ;Install types
+  InstType Normal
+  InstType Minimum
+  InstType Full
+
+  ; Main registry key
+  InstallDirRegKey HKLM "SOFTWARE\Apache Software Foundation\Tomcat\5.5" ""
+
+  !insertmacro MUI_RESERVEFILE_INSTALLOPTIONS
+  ReserveFile "jvm.ini"
+  ReserveFile "config.ini"
+
+;--------------------------------
+;Installer Sections
+
+SubSection "Tomcat" SecTomcat
+
+Section "Core" SecTomcatCore
+
+  SectionIn 1 2 3 RO
+
+  IfSilent +2 0
+  Call checkJvm
+
+  SetOutPath $INSTDIR
+  File tomcat.ico
+  File LICENSE
+  File /r common
+  File /nonfatal /r shared
+  File /nonfatal /r logs
+  File /nonfatal /r work
+  File /nonfatal /r temp
+  SetOutPath $INSTDIR\bin
+  File bin\bootstrap.jar
+  File bin\commons-logging-api.jar
+  File bin\tomcat-juli.jar
+  File bin\*.exe
+  SetOutPath $INSTDIR\conf
+  File conf\*.*
+  SetOutPath $INSTDIR\server
+  File /r server\lib
+  File /nonfatal /r server\classes
+  SetOutPath $INSTDIR\server\webapps
+  File /r server\webapps\manager
+  File /r server\webapps\host-manager
+  SetOutPath $INSTDIR\webapps
+  File /r webapps\ROOT
+  SetOutPath $INSTDIR\conf\Catalina\localhost
+  File conf\Catalina\localhost\manager.xml
+  File conf\Catalina\localhost\host-manager.xml
+
+  Call configure
+  Call findJavaPath
+  Pop $2
+
+  IfSilent +2 0
+  !insertmacro MUI_INSTALLOPTIONS_READ $2 "jvm.ini" "Field 2" "State"
+
+  StrCpy "$JavaHome" $2
+  Call findJVMPath
+  Pop $2
+
+  DetailPrint "Using Jvm: $2"
+
+  InstallRetry:
+  ClearErrors
+  nsExec::ExecToLog '"$INSTDIR\bin\tomcat5.exe" //IS//Tomcat5 --DisplayName "Apache Tomcat" --Description "Apache Tomcat @VERSION@ Server - http://tomcat.apache.org/" --LogPath "$INSTDIR\logs" --Install "$INSTDIR\bin\tomcat5.exe" --Jvm "$2" --StartPath "$INSTDIR" --StopPath "$INSTDIR"'
+  Pop $0
+  StrCmp $0 "0" InstallOk
+    MessageBox MB_ABORTRETRYIGNORE|MB_ICONSTOP \
+      "Failed to install Tomcat5 service.$\r$\nCheck your settings and permissions$\r$\nIgnore and continue anyway (not recommended)?" \
+       /SD IDIGNORE IDIGNORE InstallOk IDRETRY InstallRetry
+  Quit
+  InstallOk:
+  ClearErrors
+
+SectionEnd
+
+Section "Service" SecTomcatService
+
+  SectionIn 3
+
+  IfSilent 0 +3
+  Call findJavaPath
+  Pop $2
+
+  IfSilent +2 0
+  !insertmacro MUI_INSTALLOPTIONS_READ $2 "jvm.ini" "Field 2" "State"
+
+  StrCpy "$JavaHome" $2
+  Call findJVMPath
+  Pop $2
+
+  nsExec::ExecToLog '"$INSTDIR\bin\tomcat5.exe" //US//Tomcat5 --Startup auto'
+  ; Bahave like Apache Httpd (put the icon in try on login)
+  WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Run" "ApacheTomcatMonitor" '"$INSTDIR\bin\tomcat5w.exe" //MS//Tomcat5'
+
+  ClearErrors
+
+SectionEnd
+
+Section "Native" SecTomcatNative
+
+  SectionIn 3
+
+  NSISdl::download /TIMEOUT=30000 http://tomcat.heanet.ie/native/1.1.4/binaries/win32/tcnative-1.dll $INSTDIR\bin\tcnative-1.dll
+  Pop $0
+  StrCmp $0 success success
+    SetDetailsView show
+    DetailPrint "download failed from http://tomcat.heanet.ie/native/1.1.4/binaries/win32/tcnative-1.dll: $0"
+  success:
+
+  ClearErrors
+
+SectionEnd
+
+;Section "Source Code" SecTomcatSource
+;
+;  SectionIn 3
+;  SetOutPath $INSTDIR
+;  File /r src
+;
+;SectionEnd
+
+SubSectionEnd
+
+Section "Start Menu Items" SecMenu
+
+  SectionIn 1 2 3
+
+  !insertmacro MUI_INSTALLOPTIONS_READ $2 "jvm.ini" "Field 2" "State"
+
+  SetOutPath "$SMPROGRAMS\Apache Tomcat 5.5"
+
+  CreateShortCut "$SMPROGRAMS\Apache Tomcat 5.5\Tomcat Home Page.lnk" \
+                 "http://tomcat.apache.org/"
+
+  CreateShortCut "$SMPROGRAMS\Apache Tomcat 5.5\Welcome.lnk" \
+                 "http://127.0.0.1:$R0/"
+
+;  IfFileExists "$INSTDIR\server\webapps\admin" 0 NoAdminApp
+;
+;  CreateShortCut "$SMPROGRAMS\Apache Tomcat 5.5\Tomcat Administration.lnk" \
+;                 "http://127.0.0.1:$R0/admin/"
+;NoAdminApp:
+
+  IfFileExists "$INSTDIR\server\webapps\manager" 0 NoManagerApp
+
+  CreateShortCut "$SMPROGRAMS\Apache Tomcat 5.5\Tomcat Manager.lnk" \
+                 "http://127.0.0.1:$R0/manager/html"
+
+NoManagerApp:
+
+  IfFileExists "$INSTDIR\webapps\webapps\tomcat-docs" 0 NoDocumentaion
+
+  CreateShortCut "$SMPROGRAMS\Apache Tomcat 5.5\Tomcat Documentation.lnk" \
+                 "$INSTDIR\webapps\tomcat-docs\index.html"
+
+NoDocumentaion:
+
+  CreateShortCut "$SMPROGRAMS\Apache Tomcat 5.5\Uninstall Tomcat 5.5.lnk" \
+                 "$INSTDIR\Uninstall.exe"
+
+  CreateShortCut "$SMPROGRAMS\Apache Tomcat 5.5\Tomcat 5.5 Program Directory.lnk" \
+                 "$INSTDIR"
+
+  CreateShortCut "$SMPROGRAMS\Apache Tomcat 5.5\Monitor Tomcat.lnk" \
+                 "$INSTDIR\bin\tomcat5w.exe" \
+                 '//MS//Tomcat5' \
+                 "$INSTDIR\tomcat.ico" 0 SW_SHOWNORMAL
+
+  CreateShortCut "$SMPROGRAMS\Apache Tomcat 5.5\Configure Tomcat.lnk" \
+                 "$INSTDIR\bin\tomcat5w.exe" \
+                 '//ES//Tomcat5' \
+                 "$INSTDIR\tomcat.ico" 0 SW_SHOWNORMAL
+
+SectionEnd
+
+Section "Documentation" SecDocs
+
+  SectionIn 1 3
+  SetOutPath $INSTDIR\webapps
+  File /r webapps\tomcat-docs
+
+SectionEnd
+
+Section "Examples" SecExamples
+
+  SectionIn 3
+
+  SetOverwrite on
+  SetOutPath $INSTDIR\webapps
+  File /r webapps\jsp-examples
+  File /r webapps\servlets-examples
+
+SectionEnd
+
+;Section "Administration" SecAdmin
+;
+;  SectionIn 3
+;
+;  SetOutPath $INSTDIR\server\webapps
+;  File /r server\webapps\admin
+;  SetOutPath $INSTDIR\conf\Catalina\localhost
+;  File conf\Catalina\localhost\admin.xml
+;
+;SectionEnd
+
+Section "Webapps" SecWebapps
+
+  SectionIn 3
+
+  SetOutPath $INSTDIR\webapps
+  File /r webapps\balancer
+  File /r webapps\webdav
+
+SectionEnd
+
+;Section "Compatibility" SecCompat
+;
+;  SetOutPath $INSTDIR
+;  File /oname=bin\jmx.jar ..\compat\bin\jmx.jar
+;  File /oname=common\endorsed\xercesImpl.jar ..\compat\common\endorsed\xercesImpl.jar
+;  File /oname=common\endorsed\xml-apis.jar  ..\compat\common\endorsed\xml-apis.jar
+;
+;SectionEnd
+
+Section -post
+  nsExec::ExecToLog '"$INSTDIR\bin\tomcat5.exe" //US//Tomcat5 --Classpath "$INSTDIR\bin\bootstrap.jar" --StartClass org.apache.catalina.startup.Bootstrap --StopClass org.apache.catalina.startup.Bootstrap --StartParams start --StopParams stop  --StartMode jvm --StopMode jvm'
+  nsExec::ExecToLog '"$INSTDIR\bin\tomcat5.exe" //US//Tomcat5 --JvmOptions "-Dcatalina.home=$INSTDIR#-Dcatalina.base=$INSTDIR#-Djava.endorsed.dirs=$INSTDIR\common\endorsed#-Djava.io.tmpdir=$INSTDIR\temp#-Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager#-Djava.util.logging.config.file=$INSTDIR\conf\logging.properties" --StdOutput auto --StdError auto'
+
+  WriteUninstaller "$INSTDIR\Uninstall.exe"
+
+  WriteRegStr HKLM "SOFTWARE\Apache Software Foundation\Tomcat\5.5" "InstallPath" $INSTDIR
+  WriteRegStr HKLM "SOFTWARE\Apache Software Foundation\Tomcat\5.5" "Version" @VERSION@
+  WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Apache Tomcat 5.5" \
+                   "DisplayName" "Apache Tomcat 5.5 (remove only)"
+  WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Apache Tomcat 5.5" \
+                   "UninstallString" '"$INSTDIR\Uninstall.exe"'
+
+SectionEnd
+
+Function .onInit
+
+  ;Extract Install Options INI Files
+  !insertmacro MUI_INSTALLOPTIONS_EXTRACT "config.ini"
+  !insertmacro MUI_INSTALLOPTIONS_EXTRACT "jvm.ini"
+
+FunctionEnd
+
+Function SetChooseJVM
+  !insertmacro MUI_HEADER_TEXT "$(TEXT_JVM_TITLE)" "$(TEXT_JVM_SUBTITLE)"
+  Call findJavaPath
+  Pop $3
+  !insertmacro MUI_INSTALLOPTIONS_WRITE "jvm.ini" "Field 2" "State" $3
+  !insertmacro MUI_INSTALLOPTIONS_DISPLAY "jvm.ini"
+FunctionEnd
+
+Function SetConfiguration
+  !insertmacro MUI_HEADER_TEXT "$(TEXT_CONF_TITLE)" "$(TEXT_CONF_SUBTITLE)"
+  !insertmacro MUI_INSTALLOPTIONS_DISPLAY "config.ini"
+FunctionEnd
+
+Function Void
+FunctionEnd
+
+;--------------------------------
+;Descriptions
+
+!insertmacro MUI_FUNCTION_DESCRIPTION_BEGIN
+  !insertmacro MUI_DESCRIPTION_TEXT ${SecTomcat} $(DESC_SecTomcat)
+  !insertmacro MUI_DESCRIPTION_TEXT ${SecTomcatCore} $(DESC_SecTomcatCore)
+  !insertmacro MUI_DESCRIPTION_TEXT ${SecTomcatService} $(DESC_SecTomcatService)
+  !insertmacro MUI_DESCRIPTION_TEXT ${SecTomcatNative} $(DESC_SecTomcatNative)
+;  !insertmacro MUI_DESCRIPTION_TEXT ${SecTomcatSource} $(DESC_SecTomcatSource)
+;  !insertmacro MUI_DESCRIPTION_TEXT ${SecCompat} $(DESC_SecCompat)
+  !insertmacro MUI_DESCRIPTION_TEXT ${SecMenu} $(DESC_SecMenu)
+  !insertmacro MUI_DESCRIPTION_TEXT ${SecDocs} $(DESC_SecDocs)
+  !insertmacro MUI_DESCRIPTION_TEXT ${SecExamples} $(DESC_SecExamples)
+;  !insertmacro MUI_DESCRIPTION_TEXT ${SecAdmin} $(DESC_SecAdmin)
+  !insertmacro MUI_DESCRIPTION_TEXT ${SecWebapps} $(DESC_SecWebapps)
+!insertmacro MUI_FUNCTION_DESCRIPTION_END
+
+
+; =====================
+; CheckUserType Function
+; =====================
+;
+; Check the user type, and warn if it's not an administrator.
+; Taken from Examples/UserInfo that ships with NSIS.
+Function CheckUserType
+  ClearErrors
+  UserInfo::GetName
+  IfErrors Win9x
+  Pop $0
+  UserInfo::GetAccountType
+  Pop $1
+  StrCmp $1 "Admin" 0 +3
+    ; This is OK, do nothing
+    Goto done
+
+    MessageBox MB_OK|MB_ICONEXCLAMATION 'Note: the current user is not an administrator. \
+               To run Tomcat as a Windows service, you must be an administrator. \
+               You can still run Tomcat from the command-line as this type of user.'
+    Goto done
+
+  Win9x:
+    # This one means you don't need to care about admin or
+    # not admin because Windows 9x doesn't either
+    MessageBox MB_OK "Error! This DLL can't run under Windows 9x!"
+
+  done:
+FunctionEnd
+
+
+; =====================
+; FindJavaPath Function
+; =====================
+;
+; Find the JAVA_HOME used on the system, and put the result on the top of the
+; stack
+; Will return an empty string if the path cannot be determined
+;
+Function findJavaPath
+
+  ;ClearErrors
+
+  ;ReadEnvStr $1 JAVA_HOME
+
+  ;IfErrors 0 FoundJDK
+
+  ClearErrors
+
+  ReadRegStr $2 HKLM "SOFTWARE\JavaSoft\Java Runtime Environment" "CurrentVersion"
+  ReadRegStr $1 HKLM "SOFTWARE\JavaSoft\Java Runtime Environment\$2" "JavaHome"
+  ReadRegStr $3 HKLM "SOFTWARE\JavaSoft\Java Runtime Environment\$2" "RuntimeLib"
+
+  ;FoundJDK:
+
+  IfErrors 0 NoErrors
+  StrCpy $1 ""
+
+NoErrors:
+
+  ClearErrors
+
+  ; Put the result in the stack
+  Push $1
+
+FunctionEnd
+
+
+; ====================
+; FindJVMPath Function
+; ====================
+;
+; Find the full JVM path, and put the result on top of the stack
+; Argument: JVM base path (result of findJavaPath)
+; Will return an empty string if the path cannot be determined
+;
+Function findJVMPath
+
+  ClearErrors
+  
+  ;Step one: Is this a JRE path (Program Files\Java\XXX)
+  StrCpy $1 "$JavaHome"
+  
+  StrCpy $2 "$1\bin\hotspot\jvm.dll"
+  IfFileExists "$2" FoundJvmDll
+  StrCpy $2 "$1\bin\server\jvm.dll"
+  IfFileExists "$2" FoundJvmDll
+  StrCpy $2 "$1\bin\client\jvm.dll"  
+  IfFileExists "$2" FoundJvmDll
+  StrCpy $2 "$1\bin\classic\jvm.dll"
+  IfFileExists "$2" FoundJvmDll
+
+  ;Step two: Is this a JDK path (Program Files\XXX\jre)
+  StrCpy $1 "$JavaHome\jre"
+  
+  StrCpy $2 "$1\bin\hotspot\jvm.dll"
+  IfFileExists "$2" FoundJvmDll
+  StrCpy $2 "$1\bin\server\jvm.dll"
+  IfFileExists "$2" FoundJvmDll
+  StrCpy $2 "$1\bin\client\jvm.dll"  
+  IfFileExists "$2" FoundJvmDll
+  StrCpy $2 "$1\bin\classic\jvm.dll"
+  IfFileExists "$2" FoundJvmDll
+
+  ClearErrors
+  ;Step tree: Read defaults from registry
+  
+  ReadRegStr $1 HKLM "SOFTWARE\JavaSoft\Java Runtime Environment" "CurrentVersion"
+  ReadRegStr $2 HKLM "SOFTWARE\JavaSoft\Java Runtime Environment\$1" "RuntimeLib"
+  
+  IfErrors 0 FoundJvmDll
+  StrCpy $2 ""
+
+  FoundJvmDll:
+  ClearErrors
+
+  ; Put the result in the stack
+  Push $2
+
+FunctionEnd
+
+
+; ====================
+; CheckJvm Function
+; ====================
+;
+Function checkJvm
+
+  !insertmacro MUI_INSTALLOPTIONS_READ $3 "jvm.ini" "Field 2" "State"
+  IfFileExists "$3\bin\java.exe" NoErrors1
+  MessageBox MB_OK|MB_ICONSTOP "No Java Virtual Machine found in folder:$\r$\n$3"
+  Quit
+NoErrors1:
+  StrCpy "$JavaHome" $3
+  Call findJVMPath
+  Pop $4
+  StrCmp $4 "" 0 NoErrors2
+  MessageBox MB_OK|MB_ICONSTOP "No Java Virtual Machine found in folder:$\r$\n$3"
+  Quit
+NoErrors2:
+
+FunctionEnd
+
+; ==================
+; Configure Function
+; ==================
+;
+; Display the configuration dialog boxes, read the values entered by the user,
+; and build the configuration files
+;
+Function configure
+
+  !insertmacro MUI_INSTALLOPTIONS_READ $R0 "config.ini" "Field 2" "State"
+  !insertmacro MUI_INSTALLOPTIONS_READ $R1 "config.ini" "Field 5" "State"
+  !insertmacro MUI_INSTALLOPTIONS_READ $R2 "config.ini" "Field 7" "State"
+
+  IfSilent 0 +2
+  StrCpy $R4 'port="8080"'
+
+  IfSilent +2 0
+  StrCpy $R4 'port="$R0"'
+
+  IfSilent 0 +2
+  StrCpy $R5 ''
+
+  IfSilent Silent 0
+
+  ; Escape XML
+  Push $R1
+  Call xmlEscape
+  Pop $R1
+  Push $R2
+  Call xmlEscape
+  Pop $R2
+  
+  StrCpy $R5 '<user name="$R1" password="$R2" roles="admin,manager" />'
+
+Silent:
+  DetailPrint 'HTTP/1.1 Connector configured on port "$R0"'
+  DetailPrint 'Admin user added: "$R1"'
+
+  SetOutPath $TEMP
+  File /r confinstall
+
+  ; Build final server.xml
+  Delete "$INSTDIR\conf\server.xml"
+  FileOpen $R9 "$INSTDIR\conf\server.xml" w
+
+  Push "$TEMP\confinstall\server_1.xml"
+  Call copyFile
+  FileWrite $R9 $R4
+  Push "$TEMP\confinstall\server_2.xml"
+  Call copyFile
+
+  FileClose $R9
+
+  DetailPrint "server.xml written"
+
+  ; Build final tomcat-users.xml
+  
+  Delete "$INSTDIR\conf\tomcat-users.xml"
+  FileOpen $R9 "$INSTDIR\conf\tomcat-users.xml" w
+
+  Push "$TEMP\confinstall\tomcat-users_1.xml"
+  Call copyFile
+  FileWrite $R9 $R5
+  Push "$TEMP\confinstall\tomcat-users_2.xml"
+  Call copyFile
+
+  FileClose $R9
+
+  DetailPrint "tomcat-users.xml written"
+
+  RMDir /r "$TEMP\confinstall"
+
+FunctionEnd
+
+
+Function xmlEscape
+  Pop $0
+  ${StrRep} $0 $0 "&" "&amp;"
+  ${StrRep} $0 $0 "$\"" "&quot;"
+  ${StrRep} $0 $0 "<" "&lt;"
+  ${StrRep} $0 $0 ">" "&gt;"
+  Push $0
+FunctionEnd
+
+
+; =================
+; CopyFile Function
+; =================
+;
+; Copy specified file contents to $R9
+;
+Function copyFile
+
+  ClearErrors
+
+  Pop $0
+
+  FileOpen $1 $0 r
+
+ NoError:
+
+  FileRead $1 $2
+  IfErrors EOF 0
+  FileWrite $R9 $2
+
+  IfErrors 0 NoError
+
+ EOF:
+
+  FileClose $1
+
+  ClearErrors
+
+FunctionEnd
+
+
+;--------------------------------
+;Uninstaller Section
+
+Section Uninstall
+
+  Delete "$INSTDIR\modern.exe"
+  Delete "$INSTDIR\Uninstall.exe"
+
+  ; Stop Tomcat service monitor if running
+  nsExec::ExecToLog '"$INSTDIR\bin\tomcat5w.exe" //MQ//Tomcat5'
+  ; Delete Tomcat service
+  nsExec::ExecToLog '"$INSTDIR\bin\tomcat5.exe" //DS//Tomcat5'
+  ClearErrors
+
+  DeleteRegKey HKCR "JSPFile"
+  DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Apache Tomcat 5.5"
+  DeleteRegKey HKLM "SOFTWARE\Apache Software Foundation\Tomcat\5.5"
+  DeleteRegValue HKLM "Software\Microsoft\Windows\CurrentVersion\Run" "ApacheTomcatMonitor"
+  RMDir /r "$SMPROGRAMS\Apache Tomcat 5.5"
+  Delete "$INSTDIR\tomcat.ico"
+  Delete "$INSTDIR\LICENSE"
+  RMDir /r "$INSTDIR\bin"
+  RMDir /r "$INSTDIR\common"
+  Delete "$INSTDIR\conf\*.dtd"
+  RMDir /r "$INSTDIR\shared"
+  RMDir "$INSTDIR\logs"
+  RMDir /r "$INSTDIR\server"
+  RMDir /r "$INSTDIR\webapps\balancer"
+  RMDir /r "$INSTDIR\webapps\tomcat-docs"
+  RMDir /r "$INSTDIR\webapps\servlets-examples"
+  RMDir /r "$INSTDIR\webapps\jsp-examples"
+  RMDir /r "$INSTDIR\webapps\webdav"
+  RMDir /r "$INSTDIR\work"
+  RMDir /r "$INSTDIR\temp"
+  RMDir /r "$INSTDIR\src"
+  RMDir "$INSTDIR"
+
+  IfSilent Removed 0
+
+  ; if $INSTDIR was removed, skip these next ones
+  IfFileExists "$INSTDIR" 0 Removed 
+    MessageBox MB_YESNO|MB_ICONQUESTION \
+      "Remove all files in your Tomcat 5.5 directory? (If you have anything  \
+ you created that you want to keep, click No)" IDNO Removed
+    RMDir /r "$INSTDIR\webapps\ROOT" ; this would be skipped if the user hits no
+    RMDir "$INSTDIR\webapps"
+    Delete "$INSTDIR\*.*" 
+    RMDir /r "$INSTDIR"
+    Sleep 500
+    IfFileExists "$INSTDIR" 0 Removed 
+      MessageBox MB_OK|MB_ICONEXCLAMATION \
+                 "Note: $INSTDIR could not be removed."
+  Removed:
+
+SectionEnd
+
+;eof

Added: branches/tomcat5.5/upstream/5.5.20/build.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/build.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/build.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,91 @@
+<project name="Tomcat 5.0 Netbuild" default="build" basedir=".">
+
+
+  <!-- ===================== Initialize Property Values =================== -->
+
+  <!-- See "build.properties.sample" in the top level directory for all     -->
+  <!-- property values you must customize for successful building!!!        -->
+  <property file="${user.home}/build.properties"/>
+  <property file="build.properties"/>
+  <property file="build.properties.default"/>
+
+  <!-- Project Properties -->
+  <property name="name"                  value="Apache Tomcat" />
+  <property name="year"                  value="2005" />
+  <property name="version"               value="5.5" />
+  <property name="project"               value="jakarta-tomcat" />
+  <property name="final.name"            value="${project}-${version}" />
+  <property name="final-src.name"        value="${project}-${version}-src" />
+
+  <!-- SVNROOT -->
+  <property name="svnroot" 
+           value="http://svn.apache.org/repos/asf/" />
+
+  <!-- Subprojects -->
+  <property name="api.project"           value="servletapi" />
+  <property name="tomcat.project"        value="build" />
+  <property name="catalina.project"      value="container" />
+  <property name="jtc.project"           value="connectors" />
+  <property name="jasper.project"        value="jasper" />
+
+  <property name="current.loc"           value="tomcat/current/tc5.5.x" />
+
+  <!-- Source dependencies -->
+  <property name="api.home"
+           value="${basedir}/${api.project}"/>
+  <property name="catalina.home" 
+           value="${basedir}/${catalina.project}"/>
+  <property name="jasper.home"
+           value="${basedir}/${jasper.project}"/>
+  <property name="jtc.home"
+           value="${basedir}/${jtc.project}"/>
+  <property name="tomcat.home"
+           value="${basedir}/${tomcat.project}"/>
+
+  <target name="build" depends="check.source,get.source"
+   description="Builds all components">
+
+    <ant dir="${tomcat.home}" target="download" />
+    <ant dir="${tomcat.home}" target="deploy" />
+
+  </target>
+
+  <!-- Top-level clean target added per Bugzilla 33325 -->
+  <target name="clean"
+          description="Clean (delete) all project files">
+    <echo message="Deleting all project files" />
+    <delete dir="${api.home}" />
+    <delete dir="${catalina.home}" />
+    <delete dir="${jasper.home}" />
+    <delete dir="${jtc.home}" />
+    <delete dir="${tomcat.home}" />
+  </target>
+
+  <target name="checkout"
+          description="Update or checkout required sources from SVN">
+
+    <echo level="info"
+        message="If the checkout fails, - todo - " />
+
+    <exec dir="${basedir}" executable="svn">
+         <arg line="checkout ${svnroot}/${current.loc} ${basedir}" />
+    </exec>
+
+  </target>
+
+  <!-- *************** UTILITY TARGETS *************** -->
+
+  <target name="check.source">
+
+    <available property="source.exists"
+                   file="${basedir}/${tomcat.project}" type="dir" />
+
+  </target>
+
+  <target name="get.source" unless="source.exists">
+
+    <antcall target="checkout" />
+
+  </target>
+
+</project>

Added: branches/tomcat5.5/upstream/5.5.20/connectors/.classpath
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/.classpath	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/.classpath	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+	<classpathentry excluding="org/apache/coyote/tomcat3/|org/apache/coyote/tomcat4/" kind="src" path="coyote/src/java"/>
+	<classpathentry kind="src" path="http11/src/java"/>
+	<classpathentry kind="src" path="jni/examples"/>
+	<classpathentry kind="src" path="jni/java"/>
+	<classpathentry kind="src" path="juli/src/java"/>
+	<classpathentry excluding="org/apache/tomcat/util/net/puretls/" kind="src" path="util/java"/>
+	<classpathentry kind="src" path="util/loader"/>
+	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
+	<classpathentry kind="var" path="TOMCAT_LIBS_BASE/commons-logging-1.0.4/commons-logging-api.jar"/>
+	<classpathentry kind="var" path="TOMCAT_LIBS_BASE/mx4j-3.0.1/lib/mx4j.jar"/>
+	<classpathentry kind="var" path="TOMCAT_LIBS_BASE/commons-modeler-1.1/commons-modeler.jar"/>
+	<classpathentry kind="var" path="TOMCAT_LIBS_BASE/commons-collections-3.1/commons-collections-3.1.jar"/>
+	<classpathentry kind="var" path="ANT_HOME/lib/ant.jar"/>
+	<classpathentry kind="output" path="bin"/>
+</classpath>

Added: branches/tomcat5.5/upstream/5.5.20/connectors/.project
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/.project	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/.project	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>connectors</name>
+	<comment></comment>
+	<projects>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>org.eclipse.jdt.core.javabuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>org.eclipse.jdt.core.javanature</nature>
+	</natures>
+</projectDescription>

Added: branches/tomcat5.5/upstream/5.5.20/connectors/KEYS
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/KEYS	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/KEYS	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,462 @@
+This file contains the PGP&GPG keys of various Apache developers.
+Please don't use them for email unless you have to. Their main
+purpose is code signing.
+
+Apache users: pgp < KEYS
+Apache developers: 
+        (pgpk -ll <your name> && pgpk -xa <your name>) >> this file.
+      or
+        (gpg --fingerprint --list-sigs <your name>
+             && gpg --armor --export <your name>) >> this file.
+
+Apache developers: please ensure that your key is also available via the
+PGP keyservers (such as pgpkeys.mit.edu).
+
+
+Type Bits/KeyID    Date       User ID
+pub  2048/F22C4FED 2001/07/02 Andy Armstrong <andy at tagish.com>
+
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: PGPfreeware 7.0.3 for non-commercial use <http://www.pgp.com>
+
+mQGiBDtAWuURBADZ0KUEyUkSUiTA09e7tvEbX25STsjxrR+DNTainCls+XlkVOij
+gBv216lqge9tIsS0L6hCP4OQbFf/64qVtJssX4QXdyiZGb5wpmcj0Mz602Ew8r+N
+I0S5NvmogoYWW7BlP4r61jNxO5zrr03KaijM5r4ipJdLUxyOmM6P2jRPUwCg/5gm
+bpqiYl7pXX5FgDeB36tmD+UD/06iLqOnoiKO0vMbOk7URclhCObMNrHqxTxozMTS
+B9soYURbIeArei+plYo2n+1qB12ayybjhVu3uksXRdT9bEkyxMfslvLbIpDAG8Cz
+gNftTbKx/MVS7cQU0II8BKo2Akr+1FZah+sD4ovK8SfkMXUQUbTeefTntsAQKyyU
+9M9tA/9on9tBiHFl0qVJht6N4GiJ2G689v7rS2giLgKjetjiCduxBXEgvUSuyQID
+nF9ATrpXjITwsRlGKFmpZiFm5oCeCXihIVH0u6q066xNW2AXkLVoJ1l1Rs2Z0lsb
+0cq3xEAcwAmYLKQvCtgDV8CYgWKVmPi+49rSuQn7Lo9l02OUbLQgQW5keSBBcm1z
+dHJvbmcgPGFuZHlAdGFnaXNoLmNvbT6JAFgEEBECABgFAjtAWuUICwMJCAcCAQoC
+GQEFGwMAAAAACgkQajrT9PIsT+1plgCfXAovWnVL3MjrTfcGlFSKw7GHCSYAoJkz
+x+r2ANe8/0e+u5ZcYtSaSry+uQINBDtAWuUQCAD2Qle3CH8IF3KiutapQvMF6PlT
+ETlPtvFuuUs4INoBp1ajFOmPQFXz0AfGy0OplK33TGSGSfgMg71l6RfUodNQ+PVZ
+X9x2Uk89PY3bzpnhV5JZzf24rnRPxfx2vIPFRzBhznzJZv8V+bv9kV7HAarTW56N
+oKVyOtQa8L9GAFgr5fSI/VhOSdvNILSd5JEHNmszbDgNRR0PfIizHHxbLY7288kj
+wEPwpVsYjY67VYy4XTjTNP18F1dDox0YbN4zISy1Kv884bEpQBgRjXyEpwpy1obE
+AxnIByl6ypUM2Zafq9AKUJsCRtMIPWakXUGfnHy9iUsiGSa6q6Jew1XpMgs7AAIC
+B/0eHkYQ0Rv6s21TgpOzRBon+rQAv9ka0PlC7bj2eYWsCOBib8K7qO8hND0sW59p
+0uFQ01X7kC7L/4Ls1HTk0chEZMV0UrGAOKXHY1QFlxrNtFi5U3pTPITXDDfy+g/G
+6FTX3PLnGGvwXbtaiAq5UjQ6iXm03lh0BW6Q+kPtm8swPPfqfjYv0rrT+I8Ic3p2
+HplWKR2bpi3wqCSKB/AaTQJwTbh2x2+2cPVONPodgjZSJ9eQkErejkNSvqbumlTx
+dB81eoGa0Lo2xE7N+DNlCnILGE0X4hPMdj+N5fmyEbyx0WOB8crvCuODGGEQnXs/
+zbVO7FP+rj7YWjRh5pVD3bGiiQBMBBgRAgAMBQI7QFrlBRsMAAAAAAoJEGo60/Ty
+LE/tj/QAoOFNFa7rbAy+eT6mRNb7XztfcAbWAKD6Gd6S/7lEJU0k2TS5tozt4jMl
+vw==
+=/91Q
+-----END PGP PUBLIC KEY BLOCK-----
+
+Type Bits/KeyID    Date       User ID
+pub  1024D/86867BA6 2001-11-22 Jean-Frederic Clere (jfclere) <JFrederic.Clere at fjitsu-siemens.com>
+
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: GnuPG v1.0.5 (GNU/Linux)
+Comment: For info see http://www.gnupg.org
+
+mQGiBDv9Gx8RBADclmKwDLcibNVipQnhYW+bFIpuQjQnRrqRwn3gXM+/luzzJYJ4
+bbWpw13zjX0EkrAJ8qH2A/d0EIU1eZ0zHrLgRvMUfLGFUX7FFFw18JKFLTVGhG4/
+8sSl3ydHSA2Kd1PF6xjBP7iM7sg5dJfEkyMzvK5H4F0ZpTqy3087wsg1wwCgitRy
+Zg4x3lWZSkOwBj472qaO9GkD/2q6kyWfAK6XFe3GuB5AAs3poMfN1eqW+duM4TA8
+zUiWK0Wxx4JXJbL7n0i4d+JdXJsrjSjF++KKfelcxsrSxoUIBegez25MUSvHe09D
+R3nqkY8CVO+viEtzRBqkSgCMbUjAtfkQ+vp2jDnWSmmkNfY0OYAzt+KRyJKcjUSJ
+gvOOA/45+DN9wuTELoFTvsXh1JgOL/QvW1fmQ2HrcQk94BkzIsfVGWClCiig5gNw
+LCxTbfgA5htpI8U7vPR9/5gH7U8Wy3HR6xQUZxcbttMeYit2VbDEJzF5r5S0pJvD
+vyk3n1kiKU7r49sjhxGgE8J/VvDpO6YcIsDs8LoULwuJTg0DTrRDSmVhbi1GcmVk
+ZXJpYyBDbGVyZSAoamZjbGVyZSkgPEpGcmVkZXJpYy5DbGVyZUBmdWppdHN1LXNp
+ZW1lbnMuY29tPohXBBMRAgAXBQI7/RsfBQsHCgMEAxUDAgMWAgECF4AACgkQ0+/m
+toaGe6amGQCeJU5VZ8QCi8+PY0QJHPA63e5uPyoAmgOWIwFm8A/xmW8qjEvVAWtb
+TjZxuQENBDv9GyMQBACCbFlSF+udW/Qz2oknDen8Hoql4Q1Q7CUQTbPjoQAcYgZg
+LrsR6hc9aCIf3Kt4qZBgQ1Oe9M/AemOFhU04UNp3dgHk91EYRvx80Rua992p/8V7
+QOhwIBVb2XE8as5nL2j8w6Jz7eSs/bivxm9yD0AH/I5H01RAJivRbOTsUgSkDwAD
+BQP5ARlW2Nqc0U17asQsmMYvT1UMiOiyBwUD/DIEG2Xy1hlEvdljg8WU26jcjpGq
+MrT69T4Z+eZ2oVyiRQTW4qMUBKc0Nbz89hL0qv9K41ExxxH+JgE1csRVvmwAT8Iy
+lnhof7TJLRBtvan3+p21Kxl1uQ7MbmLT875u+vc+J098fIiIRgQYEQIABgUCO/0b
+IwAKCRDT7+a2hoZ7pn9UAJ9f0TK0QQOtjQBvxAissopYhDKHGACePZg0k9sj69yw
+nVWrBS9fvFC9jcA=
+=BTiM
+-----END PGP PUBLIC KEY BLOCK-----
+
+Type Bits/KeyID    Date       User ID
+pub  1024D/E86E29AC 2002-02-13 kevin seguin <seguin at apache.org>
+
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: GnuPG v1.0.6 (MingW32)
+Comment: For info see http://www.gnupg.org
+
+mQGiBDxqtR8RBACbySxGrtf+flbowryS1Hj4z3zzEXD4CAEq6RjSGMtIraCDRJfp
+6Gexs+lQ6IhpdC4GfX70SUMjXXvT5suhXYeGOM4iJHqUsksgzEKjUqcfj1l3qmOs
+/doE8lcGGHcYbMplBcfuop+shZYiv9GEJ3gutwn/dNnhs/QA9bCdIj03lwCgvAcy
+QpT5JdTym2p2icd5e91mGIUEAJMw6JHTTcCiyoTRy7k8Cf65d8S7bTDLr6pqJVE2
+XU41CvW/pgL31akYAxpeZJJnsBaLaUiqh6K0qgfEMlDwDeC6gVogHBxWkEXdK1dr
+tGL4GIUcxQ1+ZvQhGg7dtjanmfMlylVgS+C48awJySkinRmaQDbQ0MKdFchLc/y1
+OR3IA/0VkIvlidehMPbZCalqhS9AEsDiFq5/u5AsQzDEp2nmTGlmBqjhc39kEnu4
+qKq08az1Gt6Q7sxXbjH/jYtDgd49FW5Yg4k5B3hpTgnbyRE6SGlKksu8qTmYkDve
+4rej6pvJRHwp6hDKxDG8qQoLWIgOfVC8960nurqx56QdV9YMsLQga2V2aW4gc2Vn
+dWluIDxzZWd1aW5AYXBhY2hlLm9yZz6IVwQTEQIAFwUCPGq1HwULBwoDBAMVAwID
+FgIBAheAAAoJEKy3f8Lobims3E0An0x3rrUMIijUMFoqnoT7muNGwmAzAJ990TWj
+dZO4ayh1M+cWhjaw9W+44bkBDQQ8arUkEAQApaMm5HUB1Yk2x5MavAs/O4zfWnOx
+YFOeXIPfGvhlhF2/Lrjs9icaa/tOM/CTCes19nDWP5Fc+pQxmgSPrgt3fsShwZJe
+p3iYodLbM76uXEgSvI4Wh6kwViHbN4V1GxJAd2ZPVb1v+lauGUCOgPFGw99UV9sO
+tTRXSbFS6AgqQzMAAwUD/jq6boxlnab/GUmKrILeLkv1X0G2/AEXEGRmG0nkhVdj
+OShoqtPr4y/UhMzJUOequs2CdvRlTIyAyZqN7A0Qp4mFfmsvp0dYYssTtE4bCzZe
+WxSKgjtBWBHXnH+Qzjb5R2Tz28kAxNY+dt7yxC+CkXWDZq/rsPgsXNbWXT49FnF8
+iEYEGBECAAYFAjxqtSQACgkQrLd/wuhuKazl7QCfQkz5t/3T6EtXZCcXz/hlswyI
+z30AoLr/7hwXgedEepBk/Gm9HUsbMnM8
+=S1mb
+-----END PGP PUBLIC KEY BLOCK-----
+
+
+Type bits      keyID      Date       User ID
+pub  1024D/307A10A5 2002-07-18 Henri Gomez *** RPM SIGNING KEY ***
+                                           <hgomez at users.sourceforge.net>
+
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: GnuPG v1.0.6 (GNU/Linux)
+Comment: For info see http://www.gnupg.org
+
+mQGiBD02vbERBAC1v8fR6gjERpaz4UMfdy0hRVWCPSbOdF+Swm/IenjVzErco6zb
+MTa13umUNrDPBy/tTWiCCZrOnqi7fgDzWqPEqrXJjKAFVLEWE6MmKylPPEPG1/bm
+idkNGERSAZduvhKv777PzvEJJ/8eGe3wy/O8NbgIjCPtr4UklwCZS8cFuwCg8oMO
+UdT8qZRtzdxdAyu1m5fUb+MD/3IKJYWXsdtb6iBphCU4f/BoyjVC9EZJ1ywLuiVM
+siKbuaDUaXU9nWcbNKv+fx8uZ1NaadpfLokqqhnWcpnSiqw8HNR7SwsF1D33rkXK
+O4FSuVss/tIoqGdWFcJyPkP4yP5shxqR335narVw2vDa0+BiWkALbA2qVsSIdZDB
+LeFZA/47AMBS0U2BRk2rQT8LmMuFl7mR+wNBM4n7FUGdxsGn3TcYd4pXTNrEQPrV
+YNdooKlikgGk4hgFnIFX09Spmimqgq0goFue81rttVdZZ4uep8dTghY6gwmvcOxX
+jATbhWStBhdu9B35kzfHc+1QihD5Z94u4uyWIVBIzikcdiY8LbQqSGVucmkgR29t
+ZXogPGhnb21lekB1c2Vycy5zb3VyY2Vmb3JnZS5uZXQ+iFcEExECABcFAj02vbEF
+CwcKAwQDFQMCAxYCAQIXgAAKCRAZMdaEMHoQpYijAKCCP68ndU/kTXR9XAKLvibC
+3S8+1QCfUFQYte3Jo+MHKaWjsu9JGptRzo+5Ag0EPTa93RAIAKlsRJ5gOGTFsmaR
+W9k6MIh4c/MCy7J7HUxT5xTdHROa+3zUh+FAE/JaOx9ZtZtH863DFHA8cP4L+tpi
+PjBT6g2E94dwGcuH/OiSSCT4JSBukbGbOuLLdmFXqUl8+4gsL90Xal67FtNLwyLG
+1n7geLir0byD+OT7VLA5w+6G0NOpJEveV/FIa2qLgdRZ8vz73ybgMh18hBUrUmro
+jncp0rln2VU7VCH1C2aClKm7kK4mGAjIFIzKbguK+kM3b8NDHmXKpT6syyCtIM3h
+prkV1TUCAFqLI32aSdlTN79lpeA2zDga9k4/4X/RDHsFpRN2neRFGTNUtuUgYpQQ
+E5zWBmMAAwUH/RiGxyeBsad923IwE1+GAjxFl2tqF9xWk0J6yTnSK4nfhYAE9evV
+jwDEok9jRl4ILCcXx6YN/d/lWNuSbARKHz/3hLiTouPpwd3SSJ8is2x9PgpJz5JX
+cD0y1SkbPLvs3jH3ZmdcxZpuAmJeI/typqFKK5pWP44oXIH+XH/8nWDtmLEBkgKQ
+/ATQWenMTmZ6MIJ6aWKWGkO9QS6iYRz3PPPGQ1O8W02CeprM2wBtlb8J1Z3RxNhM
+rZcg/1Qi3V3D1HI4zw6tAFmDeBb8J4PaBQzqlhzx2EBTbfwNPhV8AlPvpxHEeGGn
+v+O1yhZr33SnyZdINNoNDn+owVMdmkobe9GIRgQYEQIABgUCPTa93QAKCRAZMdaE
+MHoQpRsTAJ4qst3MhLm48fBAEnzuzi/BIKr+AgCfYaCB/AvPoncQbHc8BcNGRimR
+P9A=
+=hQhz
+-----END PGP PUBLIC KEY BLOCK-----
+
+Type bits      keyID      Date       User ID
+DSS  1024      0x7572CDEF 2001/10/12 *** DEFAULT SIGNING KEY ***
+                                     Remy Maucherat <remm at apache.org>
+
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: PGP 6.5.1i
+
+mQGiBDvGnR4RBADPVhGl+eo6ie6UJ9E4sIW8xbBCYHQxIMwWalcLzbz2FKWl57VP
+JzoIaTZZP6op3yhRv4qRm7NGC/gpabRj/im8vK7eKgoh2VVKhqVdIjWbQW+u9pEb
+pXlp1AAFUbP4kqSIggV54s4lRulE6Uq0eDy6sXK8mBFLGRggwEFvLTHPYQCg/2qx
+u1/hBovB0I8+XJoSzconttMEAJVYrxD2W9FhnVCn3ffHhkjQBxUeXr8bQIRwid6R
+ukAqlcVkGohOngdJ94O7KL40mm2A0t9APFVC0tgEk0M7piB5cE1zAZjoLTrlvWrC
+0tH0LzEyaUgvHdG1fVeHtgwsiGW/raWDzCfiIvLCx80yiaMw2TtYXLmhjy+1qWv3
+v78JA/4idwIP7zEF8O6hSEcn5RopddUte5Ne+Ya+fsuSmKDCqPNnIkVvHYarFbkY
+QPDEiUA2fS9j1ShDz3t0Adt1TRbN2VbENH6rYbx9gwiQGu41jjRVit2Z9JM5YDyq
+VDyYH5PpyKOJkKPzuIFzq6Wn6dh/wczhDNn7YHXH49ES2nO+/LQgUmVteSBNYXVj
+aGVyYXQgPHJlbW1AYXBhY2hlLm9yZz6JAE4EEBECAA4FAjvGnR4ECwMBAgIZAQAK
+CRBuHJULdXLN72cHAKCbdPNI0ep6mGivq/xXoeQOPbBEBwCgpBbCFwc4Q6W+Y+VT
+KQh+f5jVojw=
+=1iBa
+-----END PGP PUBLIC KEY BLOCK-----
+
+Type Bits/KeyID     Date       User ID
+pub  1024D/564C17A3 2003-01-11 Mladen Turk <mturk at apache.org>
+
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: GnuPG v1.0.6 (MingW32)
+
+mQGiBD4fwXIRBAC7WRS8PYxi2YH0T1mX4HCYsF8aHoqxBzMnyFR4J896m1s96vGM
+BTSAwH2NKbiVqtfLokTbQkUVxtrgrF2HMB5NfYBg/JzT7pZL/Q2ThWUS7SJQQA4f
+a7/DpiLiHalp6iX45om6JTdIWEyXv26csIVhmtlkGBEPRhNRX8X4//BM0wCg7wcA
+yQ7c5NmoOJLVs+uHsRrnHo0D/R/dMyuWt7/o0eGIEuRlDl2q+YL8xLuVyJMXQBnd
+jo7jKpQ+Q1zl93aVTzsJa7mP2zZ7jqaJ855sdz6rvwyhGF1/qYMtm6zrmgBy2XPm
+J+57sfwSZr0bhIeMpCWjIw98z9sObq0v2r2oA3+J9E3Na/BZsCVTZVb3ew7ILmEp
+F5D7A/4zvjY41dakCAJsD1Xo8TS6hSqJf4zq9vX3ayJVvUjeo8n4sHNOwcbEnnui
+9zZaUH3F0x+3cDo7mS1Y4pD8THuqCZoSbSkiHnlved6nLXsKbqvVrVo+esEhfZCn
+Iji3gp+2TVNwdHXGM+4BAzMJCLsdXjByO6SNzB9a+H8RsRlZKrQ8TWxhZGVuIFR1
+cmsgKCoqKiBERUZBVUxUIFNJR05JTkcgS0VZICoqKikgPG10dXJrQGFwYWNoZS5v
+cmc+iF0EExECAB0FAj4fwXIFCRLP94AFCwcKAwQDFQMCAxYCAQIXgAAKCRAcUGQH
+VkwXo0jxAKCgHzXPIB4IAgoD7GMAohPQfX7j2QCeL6pAsf4pPufmPvbrrpDp6rQH
+GOS5Ag0EPh/BhhAIAKWzq7+/+nNYGpc7sXGkDNo9xncxcx/KbbJVT0rBteuaonQ4
+vYar1ITjIhOPmF9yPmpUddNrqgQTSO+Or+ZrVOndn+qC1gdY3qpKIN3KTjXloW38
+0Y84ezwdRLznQNkhgXwNcB55l/Z9kLaW2MS8CJzOuYSQT1CYbXg7XP3684ZmV1KC
+cGgcUt9VkIGqwsa2RFDNGvMbySedSkJ/70Q+PJlkXN+W86f8hi3HTjw2MCkNa5NL
++Byg8FEAm95YWrO6kCY3qaJYV7NRt9oVd+2V/NNzwYp3Or/QoYofvfNerupfwBmU
+GEXPyZCqqNH6nDv6chscsWvEA9KzhsWnsdKhmHsAAwUH/R6LwfWgtpaO42dQI4ZS
+VRBmCeWrXCuyVk0d13Yz0xLi5Z5m4g3MON3d+cRVUiyNX+hbDGpi2mkbsnL559Ef
+iqmzDmSz5GQHDutolhOPtLxLrC537ODn2q7hnYQwIQYYIUtYD5sYlzfGYC8olGCB
+IcKIdlGRWcxxiFCIJm5CX/jnSBsyDRpanlSrdkxhzAGsifqj4NQ19ayoeNoZg2ZP
+9SLIY7vbmOxJeHEYkx8AG25xOY1PLotb/0buSXPB8e71zb/DCV1rAhhUxAr/2JOQ
+RqlZBq6PfcHKLRitXRCeVvfldRxuWBIzhuTLUfRPYR6phjP50EzZPlbJzIvGwsOI
+RheITAQYEQIADAUCPh/BhgUJEs/3gAAKCRAcUGQHVkwXoy0JAJ9WTfqfYzW/F6qi
+5MxmqDnU9/G+6ACfQVmhZNnGTSfcwQCttwCaW3CRhDY=
+=MWUr
+-----END PGP PUBLIC KEY BLOCK-----
+
+Type bits      keyID      Date       User ID
+DSS  1024      0xFEA4C043 2001-06-24 Ignacio J. Ortega <nacho at apache.org>
+
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: PGPfreeware 7.0.3 for non-commercial use <http://www.pgp.com>
+
+mQGiBDs1PSgRBAD8g1RLIdDEk1+XW0DeaOrtzDPRUblHwty9S7a2UfiOEJA8GMZv
+GAT7HcEynxt6P4a58k3DceWvRw4kcu5PRF++qufzroWkSHK3V/gaDxva9XavfbS0
+vgQC5In4ZG+iKw1CbGeXzMnA28YIVbQztpKWFhyrD5q86DjrcBTefM2e0wCg/+iA
+J0DSHbKfiu9mqe8HzVcuXlsEALSSTdUJPRa80bmr6prsuc2heJLa22ddGHkJ5OXD
+pvY9mmY+fDe9wL5bnsbnDvmhwoDAsog/+jjWjJhleF+TR+wzEkmO5fYLv8qZPXet
+r6loSaY84XwrcN1ZMvGKfhfZMeAGg/McUeivT2q+3NH2dD5IK5tM960lPvq2kk6f
+41miA/4kxh/en3CG/qyfb0E33L6XY5xY+IMTnGX7tKFZuGcXtni04mqnmJAdGcoM
+Y8IwLQ1jyy3rJnXYKcJ59ZaIiku5fsOYOMu2MKRr7H6sBhC9wbmk1XfAHNJAaWTK
+GItHjCIIjneFZwZttC44PRspMI5bzb2sskSlH1gO7bt7nbDKMLQkSWduYWNpbyBK
+LiBPcnRlZ2EgPG5hY2hvQGFwYWNoZS5vcmc+iQBYBBARAgAYBQI7NT0oCAsDCQgH
+AgEKAhkBBRsDAAAAAAoJEAO7fiv+pMBDCqQAn08IyL3DNeIF6mo4DlE4BVk7rEN4
+AJ43Di7ytG4nj9y5qioBRhfBjkMZRIkARQQQEQIABgUCO4kqjAAKCRDUJrgPpMH8
+ePKfAKCKVXWM6aGJ1HlOPWdOFgq8r9TYEQCYnJBWcDiwjwzigr6NpL/PEvx4tYkB
+HAQQAQIABgUCPZ91XAAKCRCS/pCXKtS8kZrgCACTfC5BUNIyUVYrpWiJ/6Zqtemo
+0Oogx7N8Q2KaAKTLoopCXJGUiXAdwB1gBGVz/y1NHB4i0G1pZ4H+z4uYYeyqAXWD
+Yyi+8OqD+nW3FJe2xvAoAQJ/21wKhYK6MLCbK9KH3CFYHWBA5//N/rIHjees0U0i
+oCD3mrbWm1624Q3BhAMRTIMeut7d0PPoO5jGzvxoIiYshxLofV+Cgq5ZWwgjzXqZ
+aIggGRlA5dbJXQOT4Wl+zt68XKIiZfCYRhIUaGMO4anAA2sbud5y9Sf+l6iqGnBN
+CdKSIOky/Qp5NTwLrvZMwMlHxqMs4CbnHjjwfsV8Fim4Hdxq3HYnAv82FN+FuQEN
+BDs1PS0QBADYwkwjh6R0cTtgfQIS3U0bA+brKYjRCSDgvhsVe1rOBkAofSIlLr6S
+lDRbbCq339AoQ7Fv45C8QIKG77CAld/CDY/hmip3Be99Hy9mIxonTz5orWnbzSrG
+6GRvzZahOymcY4jSW/BemLWsxMNP6PsAe+6AV3C/1cWhOeiYOmb+2QACAgQAvWAu
+K9G82ViUVu5cSi5wPn/jyApB1Sw5Iv1YVOuhQLC6+stQl70QdxvRqIM1ENf8Iy3C
+bOcu0UxS15RAFaOIOKPf1ac8MhK9a+O1XGDXC2GU2wWp38zZKm8TVvjIjkjSM8BD
++3gtgPcM5D3jGpS8D/mhZv+Dngo1RANhsR/ZFhKJAEwEGBECAAwFAjs1PS0FGwwA
+AAAACgkQA7t+K/6kwEMaEQCdHPgrLNh7G5p0i9W47rAfFoqqcGMAnRmayWLtqL3n
+6TsHA6lbHce/xhZX
+=IWRP
+-----END PGP PUBLIC KEY BLOCK-----
+
+pub  1024D/142B509B 2001-06-15 Glenn L. Nielsen
+     (Sign jakarta.apache.org distributions) <glenn at apache.org>
+
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: GnuPG v1.0.6 (SunOS)
+Comment: For info see http://www.gnupg.org
+
+mQGiBDspb/8RBACIbKPrFGOmb//UfnUz0rGa1rRe8J8feycmbBmKFWZmiPhvnVuV
+3GCWGcxDD0pDkM1GX+CXUnzra6gou+JEPvDW2U1Te+Us4fCROying5GM9WnLzFdf
+a7KcbPUH8mwGXkJkbbyhbskIM5yHLKQSi+Pz3cHRVwjs1ZhkcmyI8dyEpwCgk6C+
+DpeiekUI0RCuDBGFvEpCoekD/jBOrIoeSxW5bqQ0cb4xSwo/il8wQNB3NcqoakOS
+ED1n841mxRFnYWtaSovpsS0uuALg4ryAywfJLtqie9Ks1CF6vHkZT0/TGaAaRQzs
+RTc0qeLYYmbKpzf91JnMtKlD1vLEBtb0Ljd6Kn1cZToKMSCilfsr3EdXzMd/9vk7
+mEAPA/9gP23rUTo/1cGURQAEn72ohM/KKgvQL1SnAIeqDu1QuiRRLmJw3kx67DQ1
+KbftH2RRo2AQUYJgZDb3BG+5R3joNNSfhjW+NXjds82252tKKq1W+5z0084xU+GJ
+7O68TZE3elEwp5FfynIc0eyAwqHwlDC1vKThJeOQiDiwc4cmMbRLR2xlbm4gTC4g
+TmllbHNlbiAoU2lnbiBqYWthcnRhLmFwYWNoZS5vcmcgZGlzdHJpYnV0aW9ucykg
+PGdsZW5uQGFwYWNoZS5vcmc+iFcEExECABcFAjspb/8FCwcKAwQDFQMCAxYCAQIX
+gAAKCRD6PI0mFCtQm1T3AJ47Psui/BfovFKySI3m+vJnLa8EewCcCZqn04plmpiu
+lmtXWDav9mO1Cfc=
+=Gfxf
+-----END PGP PUBLIC KEY BLOCK-----
+
+Type Bits/KeyID     Date       User ID
+pub  1024D/364D8C7E 2004-03-05 Kurt Miller <truk at apache.org>
+
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: GnuPG v1.2.2 (OpenBSD)
+
+mQGiBEBIwvcRBACNMkLDqN6defWFQeMEEJxbXhzna7pf5DmcJ5EI2BPc9NRXS9mT
+mA9Q1Uy2BeeG2YHrXTPL4H1mHvJQcwg1QFKRFbKgEmeVY9wMvAkne9YrZdqofTD5
+5Z8DbH0uHRcN3DhTuC8rQKJOhHyJuntE2iZAPD6ASYkiPvygEFgB31gTSwCg0OqZ
+azyrfopwc2oiqTWaoATGBMkD/1orgI1zD95f5Qu3lSguVcr9pf04BCt+d3Wq/Wc3
+DJ9BeyA2YdeH0LHE7jmwp2j4kzJyROubGGrOaynvZjf+UP1xSetnR0xgj+FQaK5h
+xB0rvpv2QJE/aMbQhV+P8Naa9K8yH0YfFTR6X4pSgGBgh+aKCtejrvhySibA5JWQ
+peB+A/9CBBNr3V2hN4k3irelWE7jPjHDM2O7s9Mkfr1wsTHxfBNREedgz42pefOz
+EDM4C0bMsbdiB9eEKG6y5ozKrUcAWNz/uOrRfWeZ3EmXqs/LBZeKPb6D3XV54qet
+nR4P2mAM5XnxXywFda7jm0uBtBNXFJKF93ntvZ9jwflaDUDehbQdS3VydCBNaWxs
+ZXIgPHRydWtAYXBhY2hlLm9yZz6IYQQTEQIAIQUCQEjC9wUJA8JnAAYLCQgHAwID
+FQIDAxYCAQIeAQIXgAAKCRC5eaEVNk2Mfl6lAJ9ilKDorZG8xCndE9Vl+TFg+vuV
++wCfb1VXPPJeGJFQ5JXcP7neb71ZWzm5Ag0EQEjDChAIAInQdEjA33llK0yok0M2
+ONst7PwXTd50lzY1zvNacjtRw1hOEGWYMuO4TfDCd50foWVSF+XaM36ar8kS571c
+Ykye/VrVeXYRZRuBolT4bffz8h0QGTmV25uVp8BOqxjHAQmATTpvpct6RiQPwaxv
+cZe6hU7ebYualvmf1N5hHVw8kKM/+BrPl9Q0WYVh/4Qb7Mv5PfNZZbRAHmrmNuzZ
+ATNe5D1o6BvIhl3i6DCYRCvKHbyZWBuDcGXZ8IldqouAFbE/iOVfj1GfvDxWQKla
+qDQfyfMJ8SMW7oTNDTilnZQpFrRGR9ejxnhYeXDYd9gZdleBjtCcEws1pXBJaDuW
+MNsAAwUH/12Y/FoXLT84OK2GXCS7z/FSS8XjTwi8QTB+g0qnQ9HuZ7KAOugCPmu9
+8FVtzrlJ4qSBsD+8czeZyuzvmsB+Sel0qeTltApb+/ZG/KIrM76qdi2xk1Mabb49
+YtbkvnfVpaO8SHgBm86EDKxKMvBlCKdfgS4aqkcjjOfahBXfn0d1EIm7UtLUoAuU
+TDG2lihxhDtzeMdM6W3fPjvVTsMoNSw4vyMW2jNwXOEi3ekjsDT37qtjYP7TjmyI
+NS20P9dgRQwVpc5IIwNg5CW/xkpYFJtWfXooZiMzXbX6u/zyDQY2dcdPzYJL6iZJ
+dnM1e+Z8aB8sNShKAsYxiLqj8qK0/JKITAQYEQIADAUCQEjDCgUJA8JnAAAKCRC5
+eaEVNk2MftEEAKCtCN/jQibduopySodv4eCB/ayr6QCgsks47qwddcpKOjj6t2dE
+LlyuImI=
+=FGUc
+-----END PGP PUBLIC KEY BLOCK-----
+
+Type Bits/KeyID     Date       User ID
+pub  1024D/36E67A94 2004-02-15 Jean-frederic Clere <jfclere at sinix.net>
+
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: GnuPG v1.2.4 (GNU/Linux)
+
+mQGiBEAvwq4RBACwe89USUq3kvB62DjSiMf4vqMFwkqXTwpAE4OY9Bnd2/X+IdW7
+sZP+7rEFWQrmuDufwunGgqFuFII0QZNePSQvp9sC7fynkJBXhq9h+8vhbjybrgQg
+1Ol5vyoCK9YJQ4rC4w+3dTSO3k8QHX7Pq5bLrFmAIA3mwH/2Umhr7PD6GwCgqXWD
+ODUYmJetCqRbyeu/etM6eeUD/0rEPOOBb5xC2Z23K8p8cIXyySMxZMtnCwnzSu55
+V69cwsUAe0lgKFY1m3dd28YRLZgJXndq+XItO3D6/ewlwoNJSJ4RRIy6hCJuLqAS
+jHuKtqr1bEAtD22FNQNx+l48TsuLaLq5qK09QPztNkUhie99tZ8uaLaQRYxkGgm7
+UjR5BACM1+0ViwywliydIjTkyis3L468Xi1ps/9VjnouwM/TvcwXVxiGFgN1NFD5
+8xOZsTWYt+RfkanJksUF20IYCkOt3OeHPEZVWLpk2AZgygKBBS9boWEpdqAOM1QD
+AUpuswhbABRnUyKDf1TpLkCOSmmItp4YvVMianTwQ9u/nuYpyrQnSmVhbi1mcmVk
+ZXJpYyBDbGVyZSA8amZjbGVyZUBzaW5peC5uZXQ+iFsEExECABsFAkAvwq4GCwkI
+BwMCAxUCAwMWAgECHgECF4AACgkQ+MMM5jbmepRqxQCfdaqkM9TpTmbigRGkvYVa
+vh3/8jQAoKZro8AOMFnoDFtdJxfkhIPwFptbiJwEEwECAAYFAkAxzQYACgkQN+P0
+X+5l4yGmKwP/c0+aSjy62sJRK+Y6W3P3HP1HGePLibTVHLX3I5Dt/lYBVjHVgADF
+2C8cz5oIIENZfyCMaerUY/yllC7vw0X6g28XPfLaMil58kBvxZTkKreqF7qm3NvA
+HsJU5UJ0EchnRo2YnUVq2oqWbdYpWuMXngYTcDXW9PAAud0Pz0BXRqa5AQ0EQC/C
+sxAEAIvO8n3BsjA3WVsM1ztuLXzZp/J1pEozTlz3BgB2Pr1ixf8IbnzlmFl2yvGF
+dJdkpZfmdMjC7TxOrG6+5MWESnrDcEZBQjS92nTvcG3auKQSsS4RVojLzZMwfznB
+2u+pgLVEs3sXu6YGyz33dib6B7GouxZbn6jcYSltRObFwS1bAAMFA/0c1G8MhNIt
+PUzuXxQNmLY2hZuRkImnEIvMkGqcYVu2ozmTMuuqqlsT6tccQOFiVjCYJ73LWTSr
+9hch/D3eRoZK/rTO+HdR25SM1CcgoYdvCpuAXenxvzVt9MT4mULYyP/GukAjVACW
+3G2gr883fKM9fqILDfLnOzUMKHYorkWJPIhGBBgRAgAGBQJAL8KzAAoJEPjDDOY2
+5nqUAjkAnj5RPx86y2gLNSJamLL8yM2hMWUqAJ4gs+wXl8LSYzHzca71SLZzqNKw
+oA==
+=Vfcm
+-----END PGP PUBLIC KEY BLOCK-----
+
+pub  1024D/08C975E5 1999-04-14 Jim Jagielski <jim at apache.org>
+uid                            Jim Jagielski <jim at jaguNET.com>
+uid                            Jim Jagielski <jim at jimjag.com>
+
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: GnuPG v1.2.1 (Darwin)
+
+mQGiBDcUl9QRBADl5tF8kOD0uddlnl9qsaG70/hwujGTsSXATnqoLseTsWORoVXf
+oBklokEAGmT2+Cl8XIXZ31Wh+GaJ3CTbEv8Ok1vapOt+ltPgOKzZEB4uP25EbhC2
+LWf+lUoafcd2Xi0KBV4fqXqEEuDGP1TAdZ6k7NVqgpjvbJ5TdqL0LrWOOwCg/0b4
++/p/avQr+uZRU2rdmYu/b/0D/2LnjcEqUjsslh2e9m0OgAu+gnYAmQH6Dbnp+iKl
+jffWPChwIMFZd/7FnGOzYDzoqnzTFyA4VE5PHWL61V2lpHJWB21K9D6rbEcx0iYB
+AHHxZQEmxSBU6PmGnbF+2P7vC0Jz9gZ5dCbjtGboYxd00/XQlZwCs8jHueTpSfx9
+n7dYBACFpW+v2pSlG0ReiS6Ult3gaGWiw81D0nFVvCp5BlxgQDymyF1MS6FbCj/g
+FGILosMhlsIHTFaC0DD0LSXyN1rm0ykPvi+vULIlKNJwW7fCi+33j1Azx+zfMNeO
+T5vqAfF6cvsZ6qPb9CcYvU4jEKvkovA1U3jMFehqcGkTV5sfvbQeSmltIEphZ2ll
+bHNraSA8amltQGFwYWNoZS5vcmc+iE4EEBECAA4ECwMCAQIZAQUCNxSX1QAKCRCL
+OmAfCMl15UklAKDq2PsXa7PbJPtGlXblJjD1OZgjTwCgkCz0EAdWS4Fuhi0mmSm7
+h1gtH/WIRgQQEQIABgUCOG/pBQAKCRAXWVXOQ77mqH+PAJ9dDpaaBXMgi3vGWOm9
+lYJW7u7ygwCgryMo/UAMLq1++TaIXP6+9aAD9PGIRgQQEQIABgUCPd09owAKCRAh
+RUrwzIsPfumzAJ9P9vDbz5dk0T8aPIcWeGY3q5U9WwCgwJnx7gXLt+k0eTr7mo1s
+/o1hvC2IRgQQEQIABgUCPdxFiQAKCRA0SoRNdR1/J0F1AJ4pqIkrFpHgtwwktfJN
+z/EvKYdlCACg0oFghrXkEC7JpBnYbGqXxb1f9xSIRgQSEQIABgUCPM7ulgAKCRBE
+NFayp7vgnD+kAJ4xS4K6DlOkpmNDhg8xKBT1EeYmvwCgprBsRuA7Op7cPegdvgiO
+ogQmjA2IRgQQEQIABgUCPdxEnQAKCRBVkeLAZmTAeB7vAKCkJ1Dr/pv4HqCKxnRU
+bxL/t06BQACgtHs2NqTZuDEp65k9hLroiT5zS8GIRgQQEQIABgUCPZzxgAAKCRBz
+uRv/obHYChzuAJ9fKiY6R0hFz6+xB3LX3AZ+O9Kf/ACcCzPtBJC6qknpOf3xg0xx
+gyIwZlaJARwEEAECAAYFAj0+5LgACgkQeNSOEHXh4lo+4wgAmYG1IaFDa5egQr5e
+T4Ew0jODmFyIyVJ6qdiNMXhQRNsNJ3TD5MuWpmXgc25ilBIF/x7DFnLf9XLTEtcC
+IkhgMMJ6phsuPt6lPfoSV42PTG9SqVtB/udiIiNed2NHlPdGh3zJEMIyMiywZGIh
+p23hP7jpxQQqfh6HchtLcxDDBETpGJJFIh1hx/Ps/ASvxDebnFKzNvdxlnNijJoC
+7wfP/ovkM0QJHQfctztMsmJ7LM1ZgQ4/XL3hM6GGRk2pJAoEaS0FDmrjWi58yY6f
+06/PaIYCzPhu7kz/uC8v3NlfJqGyr74BNkiC6hDKdceTAlEd1Pp7VfsyDigzP63X
+uOLILIhGBBMRAgAGBQI9pEHgAAoJEIvYLm8wuUtcRAUAn2hIyuND9XdZg4ttdIq+
+ytS6F1efAJwMuK2pkZZ98fgoBygiN+fImWHOa4kAlQMFED3cRGaazTzAqZ913QEB
+IBAD/00nrWc22FUeuCiTfwi0COY2JSv8zBjR3JQuloiqdiVlRdv14N2EldzDthhb
+2gaL/iU7xIbfOSk3DhDgDC+FvM2b07TuXXx7sksSP+PV7ubxSp6wNywv0XEqdDsV
+irTadFFvgQZ/Vlg0Dn11nRvEtul8xTfXI5MoD3Pbdp/ePey2iD8DBRA93ESn3bpk
+uiwxLS8RAt38AJ49/2yoSubOIMhEVVNqV4UKBM4p6gCdF/ZAZ7jtJac2O1eUlYuk
+mYufTbm0H0ppbSBKYWdpZWxza2kgPGppbUBqYWd1TkVULmNvbT6ISwQQEQIACwUC
+OsodagQLAwIBAAoJEIs6YB8IyXXlajkAoL2wNKsEorxLhZQAPRNa8kcv5uaCAKCc
+KvWB5TIgPvXc9KIyu7YwfYiLg4hGBBARAgAGBQI93T2lAAoJECFFSvDMiw9+NUcA
+n0K9Q9ePknWNHuQb4nkTve7kbYf2AJ9JR55QoQXLAC7y4jb9gxaqOdLMwYhGBBAR
+AgAGBQI9mcVrAAoJEEQ0VrKnu+CcznQAoIkcmrM+HAAzzEa7Nt0WFo0fLXc6AJ9P
+8javqUVxgWrx1pzYiOxI94xhL4hGBBARAgAGBQI93EncAAoJEFWR4sBmZMB4TN8A
+nRN3aMHwKTtDWJPRWHcNQfFgo5GPAJ45eMWtPyzO2DyX/W4LUq7SIQky9YhGBBAR
+AgAGBQI9nPGCAAoJEHO5G/+hsdgKxoUAnjKsp2V9in0fop9UA2Vbem+4cVYEAJ9b
+BnFkmkbUIzLhoC5RGe4RVXhWbIhGBBMRAgAGBQI9pEHiAAoJEIvYLm8wuUtcxokA
+niNbSTTL/lEMWtMN8AdOPsejHm5dAKCe9OF4wPI8gQa95IuMCkzaKBrO04kAlQMF
+ED3cRHmazTzAqZ913QEBJz4D/RJDlI4ji32MDqcCaaH1RISyRrvWUS99LC97OgcB
+/tbnEA+Yl/At0IwpYmJqff1tSsDHCi0QQbUtWAPhwoJ0gkqyfWFMkjd7Qwiu9mPC
+WYcGpUROne4y609uBkG/0g6t9WB/FZ80PmUTcrg1SBbx6HVqqOg89keWCo3h2asO
+mRYMiD8DBRA93ESw3bpkuiwxLS8RAiOiAKDyV9143Gqaspcnv3LbqBdl7l7iRgCg
++gmlTcPX9/HoxJgZAItwseZUfX20HkppbSBKYWdpZWxza2kgPGppbUBqaW1qYWcu
+Y29tPohcBBMRAgAcBQI9z/izAhsDBAsHAwIDFQIDAxYCAQIeAQIXgAAKCRCLOmAf
+CMl15W9wAKDjlNbPxfDyQMWEMAEJpSsWFJ2R3QCfbiFmNsNlFDKU8OObZCd8aZWs
+F2OIRgQQEQIABgUCPdxJ1AAKCRBVkeLAZmTAeOzsAKDqYkkBwxmnftHQXx//Vcpa
+aqLNzQCeODoA3Tx9SDvIugBd4lZiMruhgfuJAJUDBRA93ESFms08wKmfdd0BAZrx
+BACdG7OHGLy7nv7D5I09Nc/dhRZY4HRkPa0J19nTYUT0M4vGsH6mdBc49S/sDfmY
+Pt+4d5n8LGQb1DQ4WdCSq3pL+ZuNPKs2j86tilT4NTJwtjDnWEB2w1UZ1LsoXWOk
+HjSbf5EWKXgDJLUZdJxjeEmUshV+uw8UtutjTXjWYnsjkYg/AwUQPdxEud26ZLos
+MS0vEQIu4wCaA486Iwxc0WIteWo1/83j93XIZvoAoIX1B+ifAd+Af56INa39ymQ0
+eR9vuQINBDcUl9UQCAD2Qle3CH8IF3KiutapQvMF6PlTETlPtvFuuUs4INoBp1aj
+FOmPQFXz0AfGy0OplK33TGSGSfgMg71l6RfUodNQ+PVZX9x2Uk89PY3bzpnhV5JZ
+zf24rnRPxfx2vIPFRzBhznzJZv8V+bv9kV7HAarTW56NoKVyOtQa8L9GAFgr5fSI
+/VhOSdvNILSd5JEHNmszbDgNRR0PfIizHHxbLY7288kjwEPwpVsYjY67VYy4XTjT
+NP18F1dDox0YbN4zISy1Kv884bEpQBgRjXyEpwpy1obEAxnIByl6ypUM2Zafq9AK
+UJsCRtMIPWakXUGfnHy9iUsiGSa6q6Jew1XpMgs7AAICCACEhzcRGEc3y3/4YNaG
+89FmtIRpFU5zoaZxxDrmUiS1HdhqFykv8ozaTyjfImCuhq8i6DG15oGudxPma7Ey
+sCcA/qmQEBVrXFK2DYTFW3UnPyqiE822plo0d45u1csKzPvGpHYVGC4HOEKCghRy
+/54nH0fsKV3VSlIXAhRG3LIstzAtslrSYELW1Lov53GK+YZpRDJTbLAxjIYB8kEY
+hiQYzHm/cbBeRpjG9BpoBQh54dNOj22CU8HC4KvZSnDcLAzmDyrQFXFfffvJtQ7+
+HH2iIWKMFOjpRHh2ZK6uhJb03Yo/v+admKs1HSEFdV5VJUCkqymhKT0OiWnXmNHq
+QUfliEYEGBECAAYFAjcUl9UACgkQizpgHwjJdeUwTgCeKiAx5Xdgs1/oLVjb6TwX
+eu3RL84AoMcX7B/EsPMLGyhBvB6whQAqBvse
+=s/wJ
+-----END PGP PUBLIC KEY BLOCK-----
+
+pub  1024D/33C60243 2004-09-12 Mark E D Thomas <markt at apache.org>
+     Key fingerprint = DCFD 35E0 BF8C A734 4752  DE8B 6FB2 1E89 33C6 0243
+sig         33C60243 2004-09-12   Mark E D Thomas <markt at apache.org>
+sub  2048g/0BECE548 2004-09-12
+sig         33C60243 2004-09-12   Mark E D Thomas <markt at apache.org>
+
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: GnuPG v1.2.1 (MingW32)
+
+mQGiBEFEjegRBADocGttfROvtLGrTOW3xRqZHmFWybmEaI6jmnRdN/1gGXmb3wQL
+rHsS3fLFIIOYLPph0Kov9q4qNq36LekShIvjMBDFoj2/wRxaUtFq81asaRZg8Mcw
+4kVeIoe8OIOuWmvYhU8SH2jJNUnVVrpTPAa6QWquTmseNi6UJMjLxuL7DwCg//9u
+k2yj0vk6e4WSO6Fe5+EkQDED/AjQsy0kj9TpNHkKSSUR2evRlWPYA0YtxBSbsgON
+tT0cYipAp5IcYt6Zq5QzHiZreyQXLAjItDS2oGCIXfNbTYJ3kxxJTCU/3wlefVdq
+LBh4ttm7gmWaiTDTgG4axLF5oMpAb3m4v6s1KvXVVj2pqkhBknfuoRh1wPqbtwks
+7HOIBADVezl1/vny5YzdoqsDx1ByXMLi7CuMexQPllhRbdN+an+ZiJ5YP8J9rPdl
+NCELsCCcDKLGLjlp43XfMxsgYAPEZNG2ObjKTarhk3uGYN3aJrx7s+G+c2bu8o2n
+SyAFQ1iDsjS87PgSPCONA2/36ZShmv1OjLWz5Vo7hGSPcW4ZdLQiTWFyayBFIEQg
+VGhvbWFzIDxtYXJrdEBhcGFjaGUub3JnPohdBBARAgAdBQJBRI3oBwsJCAcDAgoC
+GQEFGwMAAAAFHgEAAAAACgkQb7IeiTPGAkOkvgCg0AcTAfe8m2ZSWkbsoqplLDsM
+0+oAoNl4EjXT+T2j2z8jdUYPaA8LztJguQINBEFEjekQCAD2Qle3CH8IF3Kiutap
+QvMF6PlTETlPtvFuuUs4INoBp1ajFOmPQFXz0AfGy0OplK33TGSGSfgMg71l6RfU
+odNQ+PVZX9x2Uk89PY3bzpnhV5JZzf24rnRPxfx2vIPFRzBhznzJZv8V+bv9kV7H
+AarTW56NoKVyOtQa8L9GAFgr5fSI/VhOSdvNILSd5JEHNmszbDgNRR0PfIizHHxb
+LY7288kjwEPwpVsYjY67VYy4XTjTNP18F1dDox0YbN4zISy1Kv884bEpQBgRjXyE
+pwpy1obEAxnIByl6ypUM2Zafq9AKUJsCRtMIPWakXUGfnHy9iUsiGSa6q6Jew1Xp
+Mgs7AAICCACuLSE3vBSOeTMM04ezuPt4zZUp0PFQGQL3bzuZp24f18S8P3BemGAk
+2V3HZYJmzmNgd4L0vIC9xyFduICFgbiV9uyzKPwHvCgQwaupFvFLGn7Q9LJ0nlaw
+GN7Km13vJTG3rrT/UMKwLTk+IMEYQwUgBht6HTnBaM+UqVx/eB4PHobimt5Redz9
+CnT4DrlA0M6Oh3ePWBD69Nnhwo2AN42dX/W2KcnDe2iRNu/JEbOYsssj0e3VmHwE
+mwa064TpQpw1fClyW7sf4aWOcQvcT12R0hNvRhTR1TV0pzjIMkbRPkRezhIY55AT
+TIfcaZrw+Yubmmw/pp/1wIDRzHexOq9riEwEGBECAAwFAkFEjekFGwwAAAAACgkQ
+b7IeiTPGAkN8ogCg4tHmgylXw4Y3ujF+J4cf2ollGa0AnRkyX8X+u/NrMi2g2xhE
+vpsTbAGW
+=r1gT
+-----END PGP PUBLIC KEY BLOCK-----
+
+pub   1024D/35C7E942 2006-06-28
+      Key fingerprint = 4DBE BB77 94DD A20A 01F4  482A 9038 4D9A 35C7 E942
+uid                  Rainer Jung (CODE SIGNING KEY) <rjung at apache.org>
+
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: GnuPG v1.4.4 (FreeBSD)
+
+mQGiBESizvgRBACA8YC9nvnfrnaZ4UlGAxsr3MyZbV9yqW8gzVvCRZrZbwoXFoYk
+yWAj7ZOB1t2aCTBUI/l8mZiwlQ7uMz0jv4AKW7I9wViHu4yy60lH2TDspWy/g1fC
+AJiPsCCE6WcP7aQR1iciUgsmWsX0W0y8ykhfSocOjw+JTd2m0PRa/o53JwCg+6hb
+UGX/hOX+OIXh8xhT1jR65JcD/2ly45aNAI8Tik5Aqon29CvJ74ZlpQ/LiwMq+1FT
+8n+dfROkcRTpZsN6m0v2Vn9IMT1UaDr5jui2wR4YqegslGxN9q3r5wZyGi1Bg/dU
++npdD9D3PH5kAnIvn0uOleexfU3OxbJ5qXy2SVeDr6cGDIJ7vySGx5nbeqyWvCpw
+h3LzA/9QM7jwWN+mk5mmbNOKOE82IlGwKqAXU9qjguxUQZxkq3KZJhdodRGNCfSW
+UUTyK7mMfMYXzg0yLp4iVLXiN9eW379R0Q/wDWEnIUrP+8fmWhyA37YukVCqO4n0
+7VgcaBxuTpgX8nut+MPSW0fMPe1/aro+k1uFRonpo7ikdgbKxrQxUmFpbmVyIEp1
+bmcgKENPREUgU0lHTklORyBLRVkpIDxyanVuZ0BhcGFjaGUub3JnPohgBBMRAgAg
+BQJEos74AhsDBgsJCAcDAgQVAggDBBYCAwECHgECF4AACgkQkDhNmjXH6UJy6ACe
+POKL9N3T3MkdexuGv1Fc41aWQRcAn3GUI1TJ4wJDGCPAJMb16IrnxUdt
+=C30m
+-----END PGP PUBLIC KEY BLOCK-----

Added: branches/tomcat5.5/upstream/5.5.20/connectors/LICENSE
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/LICENSE	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/LICENSE	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,202 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed 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.

Added: branches/tomcat5.5/upstream/5.5.20/connectors/NOTICE
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/NOTICE	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/NOTICE	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,2 @@
+This product includes software developed by
+The Apache Software Foundation (http://www.apache.org/).

Added: branches/tomcat5.5/upstream/5.5.20/connectors/README.txt
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/README.txt	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/README.txt	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,11 @@
+Tomcat Connector 
+
+This package contains only the tomcat connector:
+
+- tomcat-utils.jar includes general purpose utilities used in tomcat - buffers, 
+thread pools, network code, introspection
+- tomcat-coyote.jar includes the base representation of Request, Response and the code common
+to all protocols
+- tomcat-http11.jar includes the HTTP/1.1 implementation, based on coyote.
+- tomcat-jk2.jar includes the Ajp java implementation along with Jk2 java components
+

Added: branches/tomcat5.5/upstream/5.5.20/connectors/RELEASE-NOTES.txt
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/RELEASE-NOTES.txt	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/RELEASE-NOTES.txt	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,9 @@
+
+                     Tomcat Connectors Version @VERSION@
+                            Release Notes
+
+This version matches the version included with tomcat-5.0.2, and supports tomcat 3.3, 4.0, 4.1, 5.0.
+Bugs and issues will be tracked with tomcat5 - this file will list only issues related with
+older versions.
+
+

Added: branches/tomcat5.5/upstream/5.5.20/connectors/ajp/CHANGES
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/ajp/CHANGES	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/ajp/CHANGES	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,6 @@
+JAKARTA TOMCAT CONNECTORS AJP CHANGELOG:            -*-text-*-
+Last modified at [$Date: 2004-08-03 05:05:52 -0500 (Tue, 03 Aug 2004) $]
+
+Changes in AJP HEAD:
+    * Imported proxy sources from 2.1-HEAD
+      [Mladen Turk]

Added: branches/tomcat5.5/upstream/5.5.20/connectors/ajp/ajplib/include/ajp.h
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/ajp/ajplib/include/ajp.h	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/ajp/ajplib/include/ajp.h	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,453 @@
+/* Copyright 1999-2004 The Apache Software Foundation
+ *
+ * Licensed 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.
+ */
+
+#ifndef AJP_H
+#define AJP_H
+
+#include "apr_version.h"
+#include "apr.h"
+
+#include "apr_hooks.h"
+#include "apr_lib.h"
+#include "apr_strings.h"
+#include "apr_buckets.h"
+#include "apr_md5.h"
+#include "apr_network_io.h"
+#include "apr_pools.h"
+#include "apr_strings.h"
+#include "apr_uri.h"
+#include "apr_date.h"
+#include "apr_fnmatch.h"
+#define APR_WANT_STRFUNC
+#include "apr_want.h"
+
+#if APR_HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#if APR_HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+
+#define AJP13_DEF_HOST "127.0.0.1"
+#ifdef NETWARE
+#define AJP13_DEF_PORT 9009     /* default to 9009 since 8009 is used by OS */
+#else
+#define AJP13_DEF_PORT 8009
+#endif
+
+/* The following environment variables match mod_ssl! */
+#define AJP13_HTTPS_INDICATOR           "HTTPS"
+#define AJP13_SSL_CLIENT_CERT_INDICATOR "SSL_CLIENT_CERT"
+#define AJP13_SSL_CIPHER_INDICATOR      "SSL_CIPHER"
+#define AJP13_SSL_SESSION_INDICATOR     "SSL_SESSION_ID"
+#define AJP13_SSL_KEY_SIZE_INDICATOR    "SSL_CIPHER_USEKEYSIZE"
+
+#if APR_CHARSET_EBCDIC
+
+#define USE_CHARSET_EBCDIC
+#define ajp_xlate_to_ascii(b, l) ap_xlate_proto_to_ascii(b, l)
+#define ajp_xlate_from_ascii(b, l) ap_xlate_proto_from_ascii(b, l)
+
+#else                           /* APR_CHARSET_EBCDIC */
+
+#define ajp_xlate_to_ascii(b, l) 
+#define ajp_xlate_from_ascii(b, l) 
+
+#endif
+
+#ifdef AJP_USE_HTTPD_WRAP
+#include "httpd_wrap.h"
+#else
+#include "httpd.h"
+#include "http_config.h"
+#include "http_request.h"
+#include "http_core.h"
+#include "http_protocol.h"
+#include "http_main.h"
+#include "http_log.h"
+#endif
+
+
+/** AJP Specific error codes
+ */
+/** Buffer overflow exception */
+#define AJP_EOVERFLOW           (APR_OS_START_USERERR + 1) 
+/** Destination Buffer is to small */
+#define AJP_ETOSMALL            (APR_OS_START_USERERR + 2) 
+/** Invalid input parameters */
+#define AJP_EINVAL              (APR_OS_START_USERERR + 3) 
+/** Bad message signature */
+#define AJP_EBAD_SIGNATURE      (APR_OS_START_USERERR + 4) 
+/** Incoming message too bg */
+#define AJP_ETOBIG              (APR_OS_START_USERERR + 5) 
+/** Missing message header */
+#define AJP_ENO_HEADER          (APR_OS_START_USERERR + 6) 
+/** Bad message header */
+#define AJP_EBAD_HEADER         (APR_OS_START_USERERR + 7) 
+/** Bad message */
+#define AJP_EBAD_MESSAGE        (APR_OS_START_USERERR + 8) 
+/** Cant log via AJP14 */
+#define AJP_ELOGFAIL            (APR_OS_START_USERERR + 9) 
+
+/** A structure that represents ajp message */ 
+typedef struct ajp_msg ajp_msg_t;
+
+/** A structure that represents ajp message */ 
+struct ajp_msg
+{
+    /** The buffer holding a AJP message */ 
+    apr_byte_t  *buf;
+    /** The length of AJP message header (defaults to AJP_HEADER_LEN) */ 
+    apr_size_t  header_len;
+    /** The length of AJP message */ 
+    apr_size_t  len;
+    /** The current read position */ 
+    apr_size_t  pos;
+    /** Flag indicating the origing of the message */ 
+    int         server_side;
+};
+
+/**
+ * @defgroup AJP_defines AJP definitions 
+ * @{
+ */
+/**
+ * Signature for the messages sent from Apache to tomcat
+ */
+#define AJP13_WS_HEADER             0x1234
+#define AJP_HEADER_LEN              4
+#define AJP_HEADER_SZ_LEN           2
+#define AJP_MSG_BUFFER_SZ           (8*1024)
+#define AJP13_MAX_SEND_BODY_SZ      (AJP_MSG_BUFFER_SZ - 6)
+
+/** Send a request from web server to container*/
+#define CMD_AJP13_FORWARD_REQUEST   (unsigned char)2
+/** Write a body chunk from the servlet container to the web server */
+#define CMD_AJP13_SEND_BODY_CHUNK   (unsigned char)3
+/** Send response headers from the servlet container to the web server. */
+#define CMD_AJP13_SEND_HEADERS      (unsigned char)4
+/** Marks the end of response. */
+#define CMD_AJP13_END_RESPONSE      (unsigned char)5
+/** Get further data from the web server if it hasn't all been transferred yet. */
+#define CMD_AJP13_GET_BODY_CHUNK    (unsigned char)6
+/** The web server asks the container to shut itself down. */
+#define CMD_AJP13_SHUTDOWN          (unsigned char)7
+/** Webserver ask container to take control (logon phase) */
+#define CMD_AJP13_PING              (unsigned char)8
+/** Container response to cping request */
+#define CMD_AJP13_CPONG             (unsigned char)9
+/** Webserver check if container is alive, since container should respond by cpong */
+#define CMD_AJP13_CPING             (unsigned char)10
+
+/** @} */
+
+/**
+ * @defgroup AJP_api AJP API functions
+ * @{
+ */
+/**
+ * Check a new AJP Message by looking at signature and return its size
+ *
+ * @param msg       AJP Message to check
+ * @param len       Pointer to returned len
+ * @return          APR_SUCCESS or error
+ */
+apr_status_t ajp_msg_check_header(ajp_msg_t *msg, apr_size_t *len);
+
+/**
+ * Reset an AJP Message
+ *
+ * @param msg       AJP Message to reset
+ * @return          APR_SUCCESS or error
+ */
+apr_status_t ajp_msg_reset(ajp_msg_t *msg);
+
+/**
+ * Mark the end of an AJP Message
+ *
+ * @param msg       AJP Message to end
+ * @return          APR_SUCCESS or error
+ */
+apr_status_t ajp_msg_end(ajp_msg_t *msg);
+
+/**
+ * Add an unsigned 32bits value to AJP Message
+ *
+ * @param msg       AJP Message to get value from
+ * @param value     value to add to AJP Message
+ * @return          APR_SUCCESS or error
+ */
+apr_status_t ajp_msg_append_uint32(ajp_msg_t *msg, apr_uint32_t value);
+
+/**
+ * Add an unsigned 16bits value to AJP Message
+ *
+ * @param msg       AJP Message to get value from
+ * @param value     value to add to AJP Message
+ * @return          APR_SUCCESS or error
+ */
+apr_status_t ajp_msg_append_uint16(ajp_msg_t *msg, apr_uint16_t value);
+
+/**
+ * Add an unsigned 8bits value to AJP Message
+ *
+ * @param msg       AJP Message to get value from
+ * @param value     value to add to AJP Message
+ * @return          APR_SUCCESS or error
+ */
+apr_status_t ajp_msg_append_uint8(ajp_msg_t *msg, apr_byte_t value);
+
+/**
+ *  Add a String in AJP message, and transform the String in ASCII 
+ *  if convert is set and we're on an EBCDIC machine    
+ *
+ * @param msg       AJP Message to get value from
+ * @param value     Pointer to String
+ * @param convert   When set told to convert String to ASCII
+ * @return          APR_SUCCESS or error
+ */
+apr_status_t ajp_msg_append_string_ex(ajp_msg_t *msg, const char *value,
+                                      int convert);
+/**
+ *  Add a String in AJP message, and transform 
+ *  the String in ASCII if we're on an EBCDIC machine    
+ */
+#define ajp_msg_append_string(m, v) ajp_msg_append_string_ex(m, v, 1)
+
+/**
+ *  Add a String in AJP message. 
+ */
+#define ajp_msg_append_string_ascii(m, v) ajp_msg_append_string_ex(m, v, 0)
+
+/**
+ * Add a Byte array to AJP Message
+ *
+ * @param msg       AJP Message to get value from
+ * @param value     Pointer to Byte array
+ * @param valuelen  Byte array len
+ * @return          APR_SUCCESS or error
+ */
+apr_status_t ajp_msg_append_bytes(ajp_msg_t *msg, const apr_byte_t *value,
+                                  apr_size_t valuelen);
+
+/**
+ * Get a 32bits unsigned value from AJP Message
+ *
+ * @param msg       AJP Message to get value from
+ * @param rvalue    Pointer where value will be returned
+ * @return          APR_SUCCESS or error
+ */
+apr_status_t ajp_msg_get_uint32(ajp_msg_t *msg, apr_uint32_t *rvalue);
+
+/**
+ * Get a 16bits unsigned value from AJP Message
+ *
+ * @param msg       AJP Message to get value from
+ * @param rvalue    Pointer where value will be returned
+ * @return          APR_SUCCESS or error
+ */
+apr_status_t ajp_msg_get_uint16(ajp_msg_t *msg, apr_uint16_t *rvalue);
+
+/**
+ * Peek a 16bits unsigned value from AJP Message, position in message
+ * is not updated
+ *
+ * @param msg       AJP Message to get value from
+ * @param rvalue    Pointer where value will be returned
+ * @return          APR_SUCCESS or error
+ */
+apr_status_t ajp_msg_peek_uint16(ajp_msg_t *msg, apr_uint16_t *rvalue);
+
+/**
+ * Get a 8bits unsigned value from AJP Message
+ *
+ * @param msg       AJP Message to get value from
+ * @param rvalue    Pointer where value will be returned
+ * @return          APR_SUCCESS or error
+ */
+apr_status_t ajp_msg_get_uint8(ajp_msg_t *msg, apr_byte_t *rvalue);
+
+/**
+ * Peek a 8bits unsigned value from AJP Message, position in message
+ * is not updated
+ *
+ * @param msg       AJP Message to get value from
+ * @param rvalue    Pointer where value will be returned
+ * @return          APR_SUCCESS or error
+ */
+apr_status_t ajp_msg_peek_uint8(ajp_msg_t *msg, apr_byte_t *rvalue);
+
+/**
+ * Get a String value from AJP Message
+ *
+ * @param msg       AJP Message to get value from
+ * @param rvalue    Pointer where value will be returned
+ * @return          APR_SUCCESS or error
+ */
+apr_status_t ajp_msg_get_string(ajp_msg_t *msg, char **rvalue);
+
+
+/**
+ * Get a Byte array from AJP Message
+ *
+ * @param msg       AJP Message to get value from
+ * @param rvalue    Pointer where value will be returned
+ * @param rvalueLen Pointer where Byte array len will be returned
+ * @return          APR_SUCCESS or error
+ */
+apr_status_t ajp_msg_get_bytes(ajp_msg_t *msg, apr_byte_t **rvalue,
+                               apr_size_t *rvalue_len);
+
+/**
+ * Create an AJP Message from pool
+ *
+ * @param pool      memory pool to allocate AJP message from
+ * @param rmsg      Pointer to newly created AJP message
+ * @return          APR_SUCCESS or error
+ */
+apr_status_t ajp_msg_create(apr_pool_t *pool, ajp_msg_t **rmsg);
+
+/**
+ * Recopy an AJP Message to another
+ *
+ * @param smsg      source AJP message
+ * @param dmsg      destination AJP message
+ * @return          APR_SUCCESS or error
+ */
+apr_status_t ajp_msg_copy(ajp_msg_t *smsg, ajp_msg_t *dmsg);
+
+/**
+ * Serialize in an AJP Message a PING command
+ *
+ * +-----------------------+
+ * | PING CMD (1 byte)     |
+ * +-----------------------+
+ *
+ * @param smsg      AJP message to put serialized message
+ * @return          APR_SUCCESS or error
+ */
+apr_status_t ajp_msg_serialize_ping(ajp_msg_t *msg);
+
+/** 
+ * Serialize in an AJP Message a CPING command
+ *
+ * +-----------------------+
+ * | CPING CMD (1 byte)    |
+ * +-----------------------+
+ *
+ * @param smsg      AJP message to put serialized message
+ * @return          APR_SUCCESS or error
+ */
+apr_status_t ajp_msg_serialize_cping(ajp_msg_t *msg);
+
+/**
+ * Dump up to the first 1024 bytes on an AJP Message
+ *
+ * @param msg       AJP Message to dump
+ * @param err       error string to display
+ * @return          APR_SUCCESS or error
+ */
+apr_status_t ajp_msg_dump(ajp_msg_t *msg, char *err);
+
+/** 
+ * Send an AJP message to backend
+ *
+ * @param soct      backend socket
+ * @param smsg      AJP message to put serialized message
+ * @return          APR_SUCCESS or error
+ */
+apr_status_t ajp_ilink_send(apr_socket_t *sock, ajp_msg_t *msg);
+
+/** 
+ * Receive an AJP message from backend
+ *
+ * @param sock      backend socket
+ * @param smsg      AJP message to put serialized message
+ * @return          APR_SUCCESS or error
+ */
+apr_status_t ajp_ilink_receive(apr_socket_t *sock, ajp_msg_t *msg);
+
+/**
+ * Build the ajp header message and send it
+ * @param sock      backend socket
+ * @param r         current request
+ * @return          APR_SUCCESS or error
+ */
+apr_status_t ajp_send_header(apr_socket_t *sock, request_rec  *r);
+
+/**
+ * Read the ajp message and return the type of the message.
+ * @param sock      backend socket
+ * @param r         current request
+ * @param msg       returned AJP message
+ * @return          APR_SUCCESS or error
+ */
+apr_status_t ajp_read_header(apr_socket_t *sock,
+                             request_rec  *r,
+                             ajp_msg_t **msg);
+
+/**
+ * Allocate a msg to send data
+ * @param r         current request
+ * @param ptr       data buffer
+ * @param len       the length of allocated data buffer
+ * @param msg       returned AJP message
+ * @return          APR_SUCCESS or error
+ */
+apr_status_t  ajp_alloc_data_msg(request_rec *r, char **ptr, apr_size_t *len,
+                                 ajp_msg_t **msg);
+
+/**
+ * Send the data message
+ * @param sock      backend socket
+ * @param r         current request
+ * @param msg       AJP message to send
+ * @param len       AJP message length      
+ * @return          APR_SUCCESS or error
+ */
+apr_status_t  ajp_send_data_msg(apr_socket_t *sock, request_rec  *r,
+                                ajp_msg_t *msg, apr_size_t len);
+
+/**
+ * Parse the message type 
+ * @param r         current request
+ * @param msg       AJP message
+ * @return          AJP message type.
+ */
+int ajp_parse_type(request_rec  *r, ajp_msg_t *msg);
+
+/**
+ * Parse the header message from container 
+ * @param r         current request
+ * @param msg       AJP message
+ * @return          APR_SUCCESS or error
+ */
+apr_status_t ajp_parse_header(request_rec  *r, ajp_msg_t *msg);
+
+/** 
+ * Parse the message body and return data address and length 
+ * @param r         current request
+ * @param msg       AJP message
+ * @param len       returned AJP message length 
+ * @param ptr       returned data
+ * @return          APR_SUCCESS or error
+ */
+apr_status_t  ajp_parse_data(request_rec  *r, ajp_msg_t *msg,
+                             apr_uint16_t *len, char **ptr);
+
+/** @} */
+
+#endif /* AJP_H */
+

Added: branches/tomcat5.5/upstream/5.5.20/connectors/ajp/ajplib/include/ajp_header.h
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/ajp/ajplib/include/ajp_header.h	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/ajp/ajplib/include/ajp_header.h	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,165 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.
+ */
+#ifndef AJP_HEADER_H
+#define AJP_HEADER_H
+
+/*
+ * Conditional request attributes
+ * 
+ */
+#define SC_A_CONTEXT            (unsigned char)1
+#define SC_A_SERVLET_PATH       (unsigned char)2
+#define SC_A_REMOTE_USER        (unsigned char)3
+#define SC_A_AUTH_TYPE          (unsigned char)4
+#define SC_A_QUERY_STRING       (unsigned char)5
+#define SC_A_JVM_ROUTE          (unsigned char)6
+#define SC_A_SSL_CERT           (unsigned char)7
+#define SC_A_SSL_CIPHER         (unsigned char)8
+#define SC_A_SSL_SESSION        (unsigned char)9
+#define SC_A_REQ_ATTRIBUTE      (unsigned char)10
+#define SC_A_SSL_KEY_SIZE       (unsigned char)11       /* only in if JkOptions +ForwardKeySize */
+#define SC_A_SECRET             (unsigned char)12
+#define SC_A_ARE_DONE           (unsigned char)0xFF
+
+/*
+ * Request methods, coded as numbers instead of strings.
+ * The list of methods was taken from Section 5.1.1 of RFC 2616,
+ * RFC 2518, the ACL IETF draft, and the DeltaV IESG Proposed Standard.
+ *          Method        = "OPTIONS"
+ *                        | "GET"    
+ *                        | "HEAD"   
+ *                        | "POST"   
+ *                        | "PUT"    
+ *                        | "DELETE" 
+ *                        | "TRACE"  
+ *                        | "PROPFIND"
+ *                        | "PROPPATCH"
+ *                        | "MKCOL"
+ *                        | "COPY"
+ *                        | "MOVE"
+ *                        | "LOCK"
+ *                        | "UNLOCK"
+ *                        | "ACL"
+ *                        | "REPORT"
+ *                        | "VERSION-CONTROL"
+ *                        | "CHECKIN"
+ *                        | "CHECKOUT"
+ *                        | "UNCHECKOUT"
+ *                        | "SEARCH"
+ *                        | "MKWORKSPACE"
+ *                        | "UPDATE"
+ *                        | "LABEL"
+ *                        | "MERGE"
+ *                        | "BASELINE-CONTROL"
+ *                        | "MKACTIVITY"
+ * 
+ */
+#define SC_M_OPTIONS            (unsigned char)1
+#define SC_M_GET                (unsigned char)2
+#define SC_M_HEAD               (unsigned char)3
+#define SC_M_POST               (unsigned char)4
+#define SC_M_PUT                (unsigned char)5
+#define SC_M_DELETE             (unsigned char)6
+#define SC_M_TRACE              (unsigned char)7
+#define SC_M_PROPFIND           (unsigned char)8
+#define SC_M_PROPPATCH          (unsigned char)9
+#define SC_M_MKCOL              (unsigned char)10
+#define SC_M_COPY               (unsigned char)11
+#define SC_M_MOVE               (unsigned char)12
+#define SC_M_LOCK               (unsigned char)13
+#define SC_M_UNLOCK             (unsigned char)14
+#define SC_M_ACL                (unsigned char)15
+#define SC_M_REPORT             (unsigned char)16
+#define SC_M_VERSION_CONTROL    (unsigned char)17
+#define SC_M_CHECKIN            (unsigned char)18
+#define SC_M_CHECKOUT           (unsigned char)19
+#define SC_M_UNCHECKOUT         (unsigned char)20
+#define SC_M_SEARCH             (unsigned char)21
+#define SC_M_MKWORKSPACE        (unsigned char)22
+#define SC_M_UPDATE             (unsigned char)23
+#define SC_M_LABEL              (unsigned char)24
+#define SC_M_MERGE              (unsigned char)25
+#define SC_M_BASELINE_CONTROL   (unsigned char)26
+#define SC_M_MKACTIVITY         (unsigned char)27
+
+
+/*
+ * Frequent request headers, these headers are coded as numbers
+ * instead of strings.
+ * 
+ * Accept
+ * Accept-Charset
+ * Accept-Encoding
+ * Accept-Language
+ * Authorization
+ * Connection
+ * Content-Type
+ * Content-Length
+ * Cookie
+ * Cookie2
+ * Host
+ * Pragma
+ * Referer
+ * User-Agent
+ * 
+ */
+
+#define SC_ACCEPT               (unsigned short)0xA001
+#define SC_ACCEPT_CHARSET       (unsigned short)0xA002
+#define SC_ACCEPT_ENCODING      (unsigned short)0xA003
+#define SC_ACCEPT_LANGUAGE      (unsigned short)0xA004
+#define SC_AUTHORIZATION        (unsigned short)0xA005
+#define SC_CONNECTION           (unsigned short)0xA006
+#define SC_CONTENT_TYPE         (unsigned short)0xA007
+#define SC_CONTENT_LENGTH       (unsigned short)0xA008
+#define SC_COOKIE               (unsigned short)0xA009    
+#define SC_COOKIE2              (unsigned short)0xA00A
+#define SC_HOST                 (unsigned short)0xA00B
+#define SC_PRAGMA               (unsigned short)0xA00C
+#define SC_REFERER              (unsigned short)0xA00D
+#define SC_USER_AGENT           (unsigned short)0xA00E
+
+/*
+ * Frequent response headers, these headers are coded as numbers
+ * instead of strings.
+ * 
+ * Content-Type
+ * Content-Language
+ * Content-Length
+ * Date
+ * Last-Modified
+ * Location
+ * Set-Cookie
+ * Servlet-Engine
+ * Status
+ * WWW-Authenticate
+ * 
+ */
+
+#define SC_RESP_CONTENT_TYPE        (unsigned short)0xA001
+#define SC_RESP_CONTENT_LANGUAGE    (unsigned short)0xA002
+#define SC_RESP_CONTENT_LENGTH      (unsigned short)0xA003
+#define SC_RESP_DATE                (unsigned short)0xA004
+#define SC_RESP_LAST_MODIFIED       (unsigned short)0xA005
+#define SC_RESP_LOCATION            (unsigned short)0xA006
+#define SC_RESP_SET_COOKIE          (unsigned short)0xA007
+#define SC_RESP_SET_COOKIE2         (unsigned short)0xA008
+#define SC_RESP_SERVLET_ENGINE      (unsigned short)0xA009
+#define SC_RESP_STATUS              (unsigned short)0xA00A
+#define SC_RESP_WWW_AUTHENTICATE    (unsigned short)0xA00B
+#define SC_RES_HEADERS_NUM          11
+
+#endif /* AJP_HEADER_H */

Added: branches/tomcat5.5/upstream/5.5.20/connectors/ajp/ajplib/include/ajp_logon.h
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/ajp/ajplib/include/ajp_logon.h	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/ajp/ajplib/include/ajp_logon.h	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,51 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.
+ */
+
+
+/*
+ * +-------------------------+-------------------------+
+ * | LOGIN SEED CMD (1 byte) | MD5 of entropy (String) |
+ * +-------------------------+-------------------------+
+ *
+ * +--------------------+------------------------+------------------------------+
+ * | LOGOK CMD (1 byte) | NEGOCIED DATA (32bits) | SERVLET ENGINE INFO(CString) |
+ * +--------------------+------------------------+------------------------------+
+ *
+ *
+ * +---------------------+-----------------------+
+ * | LOGNOK CMD (1 byte) | FAILURE CODE (32bits) |
+ * +---------------------+-----------------------+
+ */
+ 
+/*
+ * Third Login Phase (web server -> servlet engine), md5 of seed + secret is sent
+ */
+#define AJP14_LOGCOMP_CMD	            (apr_byte_t)0x12
+
+/* web-server want context info after login */
+#define AJP14_CONTEXT_INFO_NEG          0x80000000
+
+/* web-server want context updates */
+#define AJP14_CONTEXT_UPDATE_NEG        0x40000000
+
+/* communication could use AJP14 */
+#define AJP14_PROTO_SUPPORT_AJP14_NEG   0x00010000
+
+#define AJP14_ENTROPY_SEED_LEN		    32      /* we're using MD5 => 32 chars */
+#define AJP14_COMPUTED_KEY_LEN		    32      /* we're using MD5 also */
+
+
+#define AJP14_MD5_DIGESTSIZE            16

Added: branches/tomcat5.5/upstream/5.5.20/connectors/ajp/ajplib/src/ajp_header.c
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/ajp/ajplib/src/ajp_header.c	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/ajp/ajplib/src/ajp_header.c	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,725 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.
+ */
+
+#include "ajp_header.h"
+#include "ajp.h"
+
+static const char *response_trans_headers[] = {
+    "Content-Type", 
+    "Content-Language", 
+    "Content-Length", 
+    "Date", 
+    "Last-Modified", 
+    "Location", 
+    "Set-Cookie", 
+    "Set-Cookie2", 
+    "Servlet-Engine", 
+    "Status", 
+    "WWW-Authenticate"
+};
+
+static const char *long_res_header_for_sc(int sc) 
+{
+    const char *rc = NULL;
+    sc = sc & 0X00FF;
+    if(sc <= SC_RES_HEADERS_NUM && sc > 0) {
+        rc = response_trans_headers[sc - 1];
+    }
+
+    return rc;
+}
+
+#define UNKNOWN_METHOD (-1)
+
+static int sc_for_req_header(const char *header_name)
+{
+    char header[16];
+    apr_size_t len = strlen(header_name);
+    const char *p = header_name;
+    int i = 0;
+
+    /* ACCEPT-LANGUAGE is the longest headeer
+     * that is of interest.
+     */
+    if (len < 4 || len > 15)
+        return UNKNOWN_METHOD;
+    
+    while (*p)
+        header[i++] = apr_toupper(*p++);
+    header[i] = '\0';
+    p = &header[1];
+
+    switch (header[0]) {
+        case 'A':
+            if (memcmp(p, "CCEPT", 5) == 0) {
+                if (!header[6])
+                    return SC_ACCEPT;
+                else if (header[6] == '-') {
+                    p += 6;
+                    if (memcmp(p, "CHARSET", 7) == 0)
+                        return SC_ACCEPT_CHARSET;
+                    else if (memcmp(p,  "ENCODING", 8) == 0)
+                        return SC_ACCEPT_ENCODING;
+                    else if (memcmp(p, "LANGUAGE", 8) == 0)
+                        return SC_ACCEPT_LANGUAGE;
+                    else
+                        return UNKNOWN_METHOD;
+                }
+                else
+                    return UNKNOWN_METHOD;
+            }
+            else if (memcmp(p, "UTHORIZATION", 12) == 0)
+                return SC_AUTHORIZATION;
+            else
+                return UNKNOWN_METHOD;
+        break;
+        case 'C':
+            if (memcmp(p, "OOKIE", 5) == 0)
+                return SC_COOKIE;
+            else if(memcmp(p, "ONNECTION", 9) == 0)
+                return SC_CONNECTION;
+            else if(memcmp(p, "ONTENT-TYPE", 11) == 0)
+                return SC_CONTENT_TYPE;
+            else if(memcmp(p, "ONTENT-LENGTH", 13) == 0)
+                return SC_CONTENT_LENGTH;
+            else if(memcmp(p, "OOKIE2", 6) == 0)
+                return SC_COOKIE2;
+            else
+                return UNKNOWN_METHOD;
+        break;
+        case 'H':
+            if(memcmp(p, "OST", 3) == 0)
+                return SC_HOST;
+            else
+                return UNKNOWN_METHOD;
+        break;
+        case 'P':
+            if(memcmp(p, "RAGMA", 5) == 0)
+                return SC_PRAGMA;
+            else
+                return UNKNOWN_METHOD;
+        break;
+        case 'R':
+            if(memcmp(p, "EFERER", 6) == 0)
+                return SC_REFERER;
+            else
+                return UNKNOWN_METHOD;
+        break;
+        case 'U':
+            if(memcmp(p, "SER-AGENT", 9) == 0)
+                return SC_USER_AGENT;
+            else
+                return UNKNOWN_METHOD;
+        break;
+        default:
+            return UNKNOWN_METHOD;
+    }
+
+    /* NOTREACHED */
+}
+
+/* Apache method number to SC methods transform table */
+static const unsigned char sc_for_req_method_table[] = {
+    SC_M_GET,
+    SC_M_PUT,
+    SC_M_POST,
+    SC_M_DELETE,
+    0,                      /* M_DELETE */
+    SC_M_OPTIONS,
+    SC_M_TRACE,
+    0,                      /* M_PATCH  */
+    SC_M_PROPFIND,
+    SC_M_PROPPATCH,
+    SC_M_MKCOL,
+    SC_M_COPY,
+    SC_M_MOVE,
+    SC_M_LOCK,
+    SC_M_UNLOCK,
+    SC_M_VERSION_CONTROL,
+    SC_M_CHECKOUT,
+    SC_M_UNCHECKOUT,
+    SC_M_CHECKIN,
+    SC_M_UPDATE,
+    SC_M_LABEL,
+    SC_M_REPORT,
+    SC_M_MKWORKSPACE,
+    SC_M_MKACTIVITY,
+    SC_M_BASELINE_CONTROL,
+    SC_M_MERGE,           
+    0                       /* M_INVALID */
+};
+
+static int sc_for_req_method_by_id(int method_id)
+{
+    if (method_id < 0 || method_id > M_INVALID)
+        return UNKNOWN_METHOD;
+    else
+        return sc_for_req_method_table[method_id] ?
+               sc_for_req_method_table[method_id] : UNKNOWN_METHOD;
+}
+
+/*
+ * Message structure
+ *
+ *
+AJPV13_REQUEST/AJPV14_REQUEST=
+    request_prefix (1) (byte)
+    method         (byte)
+    protocol       (string)
+    req_uri        (string)
+    remote_addr    (string)
+    remote_host    (string)
+    server_name    (string)
+    server_port    (short)
+    is_ssl         (boolean)
+    num_headers    (short)
+    num_headers*(req_header_name header_value)
+
+    ?context       (byte)(string)
+    ?servlet_path  (byte)(string)
+    ?remote_user   (byte)(string)
+    ?auth_type     (byte)(string)
+    ?query_string  (byte)(string)
+    ?jvm_route     (byte)(string)
+    ?ssl_cert      (byte)(string)
+    ?ssl_cipher    (byte)(string)
+    ?ssl_session   (byte)(string)
+    ?ssl_key_size  (byte)(int)      via JkOptions +ForwardKeySize
+    request_terminator (byte)
+    ?body          content_length*(var binary)
+
+ */
+
+static apr_status_t ajp_marshal_into_msgb(ajp_msg_t    *msg,
+                                 request_rec *r)
+{
+    int method;
+    apr_uint32_t i, num_headers = 0;
+    apr_byte_t is_ssl;
+    char *remote_host;
+    char *uri;
+    const char *session_route, *envvar;
+    const apr_array_header_t *arr = apr_table_elts(r->subprocess_env);
+    const apr_table_entry_t *elts = (const apr_table_entry_t *)arr->elts;
+
+    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+                         "Into ajp_marshal_into_msgb");
+
+    if ((method = sc_for_req_method_by_id(r->method_number)) == UNKNOWN_METHOD) { 
+        ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
+               "Error ajp_marshal_into_msgb - No such method %s",
+               r->method);
+        return APR_EGENERAL;
+    }
+
+    /* XXXX need something */
+    is_ssl = (apr_byte_t) 0; /* s->is_ssl */
+
+    if (r->headers_in && apr_table_elts(r->headers_in)) {
+        const apr_array_header_t *t = apr_table_elts(r->headers_in);
+        num_headers = t->nelts;
+    }
+
+    remote_host = (char *)ap_get_remote_host(r->connection, r->per_dir_config, REMOTE_HOST, NULL);
+
+    uri = apr_pstrdup(r->pool, r->uri);
+    if (uri != NULL) {
+        char *query_str = strchr(uri, '?');
+        if (query_str != NULL) {
+            *query_str = 0;
+        }
+    }
+    
+
+    ajp_msg_reset(msg);
+
+    if (ajp_msg_append_uint8(msg, CMD_AJP13_FORWARD_REQUEST)     ||
+        ajp_msg_append_uint8(msg, method)                        ||
+        ajp_msg_append_string(msg, r->protocol)                  ||
+        ajp_msg_append_string(msg, uri)                          ||
+        ajp_msg_append_string(msg, r->connection->remote_ip)     ||
+        ajp_msg_append_string(msg, remote_host)                  ||
+        ajp_msg_append_string(msg, ap_get_server_name(r))        ||
+        ajp_msg_append_uint16(msg, (apr_uint16_t)r->connection->local_addr->port) ||
+        ajp_msg_append_uint8(msg, is_ssl)                        ||
+        ajp_msg_append_uint16(msg, (apr_uint16_t) num_headers)) {
+
+        ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
+               "Error ajp_marshal_into_msgb - "
+               "Error appending the message begining");
+        return APR_EGENERAL;
+    }
+
+    for (i = 0 ; i < num_headers ; i++) {
+        int sc;
+        const apr_array_header_t *t = apr_table_elts(r->headers_in);
+        const apr_table_entry_t *elts = (apr_table_entry_t *)t->elts;
+
+        if ((sc = sc_for_req_header(elts[i].key)) != UNKNOWN_METHOD) {
+            if (ajp_msg_append_uint16(msg, (apr_uint16_t)sc)) {
+                ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
+                       "Error ajp_marshal_into_msgb - "
+                       "Error appending the header name");
+                return APR_EGENERAL;
+            }
+        }
+        else {
+            if (ajp_msg_append_string(msg, elts[i].key)) {
+                ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
+                       "Error ajp_marshal_into_msgb - "
+                       "Error appending the header name");
+                return APR_EGENERAL;
+            }
+        }
+        
+        if (ajp_msg_append_string(msg, elts[i].val)) {
+            ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
+                   "Error ajp_marshal_into_msgb - "
+                   "Error appending the header value");
+            return APR_EGENERAL;
+        }
+        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+                   "ajp_marshal_into_msgb: Header[%d] [%s] = [%s]",
+                   i, elts[i].key, elts[i].val);
+    }
+
+/* XXXX need to figure out how to do this
+    if (s->secret) {
+        if (ajp_msg_append_uint8(msg, SC_A_SECRET) ||
+            ajp_msg_append_string(msg, s->secret)) {
+            ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
+                   "Error ajp_marshal_into_msgb - "
+                   "Error appending secret");
+            return APR_EGENERAL;
+        }
+    }
+ */
+        
+    if (r->user) {
+        if (ajp_msg_append_uint8(msg, SC_A_REMOTE_USER) ||
+            ajp_msg_append_string(msg, r->user)) {
+            ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
+                   "Error ajp_marshal_into_msgb - "
+                   "Error appending the remote user");
+            return APR_EGENERAL;
+        }
+    }
+    if (r->ap_auth_type) {
+        if (ajp_msg_append_uint8(msg, SC_A_AUTH_TYPE) ||
+            ajp_msg_append_string(msg, r->ap_auth_type)) {
+            ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
+                   "Error ajp_marshal_into_msgb - "
+                   "Error appending the auth type");
+            return APR_EGENERAL;
+        }
+    }
+    /* XXXX  ebcdic (args converted?) */
+    if (r->args) {
+        if (ajp_msg_append_uint8(msg, SC_A_QUERY_STRING) ||
+            ajp_msg_append_string(msg, r->args)) {
+            ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
+                   "Error ajp_marshal_into_msgb - "
+                   "Error appending the query string");
+            return APR_EGENERAL;
+        }
+    }
+    if ((session_route = apr_table_get(r->notes, "session-route"))) {
+        if (ajp_msg_append_uint8(msg, SC_A_JVM_ROUTE) ||
+            ajp_msg_append_string(msg, session_route)) {
+            ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
+                   "Error ajp_marshal_into_msgb - "
+                   "Error appending the jvm route");
+            return APR_EGENERAL;
+        }
+    }
+/* XXX: Is the subprocess_env a right place?
+ * <Location /examples>
+ *   ProxyPass ajp://remote:8009/servlets-examples 
+ *   SetEnv SSL_SESSION_ID CUSTOM_SSL_SESSION_ID
+ * </Location>
+ */
+    if ((envvar = apr_table_get(r->subprocess_env,
+                                AJP13_SSL_CLIENT_CERT_INDICATOR))) {
+        if (ajp_msg_append_uint8(msg, SC_A_SSL_CERT) ||
+            ajp_msg_append_string(msg, envvar)) {
+            ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
+                   "Error ajp_marshal_into_msgb - "
+                   "Error appending the SSL certificates");
+            return APR_EGENERAL;
+        }
+    }
+
+    if ((envvar = apr_table_get(r->subprocess_env,
+                                AJP13_SSL_CIPHER_INDICATOR))) {
+        if (ajp_msg_append_uint8(msg, SC_A_SSL_CIPHER) ||
+            ajp_msg_append_string(msg, envvar)) {
+            ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
+                   "Error ajp_marshal_into_msgb - "
+                   "Error appending the SSL ciphers");
+            return APR_EGENERAL;
+        }
+    }
+
+    if ((envvar = apr_table_get(r->subprocess_env,
+                                AJP13_SSL_SESSION_INDICATOR))) {
+        if (ajp_msg_append_uint8(msg, SC_A_SSL_SESSION) ||
+            ajp_msg_append_string(msg, envvar)) {
+            ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
+                   "Error ajp_marshal_into_msgb - "
+                   "Error appending the SSL session");
+            return APR_EGENERAL;
+        }
+    }
+
+    /*
+     * ssl_key_size is required by Servlet 2.3 API
+     * added support only in ajp14 mode
+     * JFC removed: ae->proto == AJP14_PROTO
+     */
+ /* XXXX ignored for the moment
+    if (s->ssl_key_size != -1) {
+        if (ajp_msg_append_uint8(msg, SC_A_SSL_KEY_SIZE) ||
+            ajp_msg_append_uint16(msg, (unsigned short) s->ssl_key_size)) {
+            ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
+                   "Error ajp_marshal_into_msgb - "
+                   "Error appending the SSL key size");
+            return APR_EGENERAL;
+        }
+    }
+ */
+    /* Use the environment vars prefixed with AJP_
+     * and pass it to the header striping that prefix.
+     */
+    for (i = 0; i < (apr_uint32_t)arr->nelts; i++) {
+        if (!strncmp(elts[i].key, "AJP_", 4)) {
+            if (ajp_msg_append_uint8(msg, SC_A_REQ_ATTRIBUTE) ||
+                ajp_msg_append_string(msg, elts[i].key + 4)   ||
+                ajp_msg_append_string(msg, elts[i].val)) {
+                ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
+                        "Error ajp_marshal_into_msgb - "
+                        "Error appending attribute %s=%s",
+                        elts[i].key, elts[i].val);
+                return APR_EGENERAL;
+            }
+        }
+    }
+
+    if (ajp_msg_append_uint8(msg, SC_A_ARE_DONE)) {
+        ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
+               "Error ajp_marshal_into_msgb - "
+               "Error appending the message end");
+        return APR_EGENERAL;
+    }
+
+    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+           "ajp_marshal_into_msgb - Done");
+    return APR_SUCCESS;
+}
+
+/*
+AJPV13_RESPONSE/AJPV14_RESPONSE:=
+    response_prefix (2)
+    status          (short)
+    status_msg      (short)
+    num_headers     (short)
+    num_headers*(res_header_name header_value)
+    *body_chunk
+    terminator      boolean <! -- recycle connection or not  -->
+
+req_header_name := 
+    sc_req_header_name | (string)
+
+res_header_name := 
+    sc_res_header_name | (string)
+
+header_value :=
+    (string)
+
+body_chunk :=
+    length  (short)
+    body    length*(var binary)
+
+ */
+
+
+static apr_status_t ajp_unmarshal_response(ajp_msg_t   *msg,
+                                  request_rec  *r)
+{
+    apr_uint16_t status;
+    apr_status_t rc;
+    char *ptr;
+    apr_uint16_t  num_headers;
+    int i;
+
+    rc = ajp_msg_get_uint16(msg, &status);
+
+    if (rc != APR_SUCCESS) {
+         ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
+               "Error ajp_unmarshal_response - Null status");
+        return APR_EGENERAL;
+    }
+    r->status = status;
+
+    rc = ajp_msg_get_string(msg, &ptr);
+    if (rc == APR_SUCCESS) {
+        r->status_line =  apr_psprintf(r->pool, "%d %s", status, ptr);
+#if defined(AS400) || defined(_OSD_POSIX)
+        ap_xlate_proto_from_ascii(r->status_line, strlen(r->status_line));
+#endif
+    } else {
+        r->status_line = NULL;
+    }
+
+    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+           "ajp_unmarshal_response: status = %d", status);
+
+    rc = ajp_msg_get_uint16(msg, &num_headers);
+    if (rc == APR_SUCCESS) {
+        r->headers_out = apr_table_make(r->pool, num_headers);
+    } else {
+        r->headers_out = NULL;
+        num_headers = 0;
+    }
+
+    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+           "ajp_unmarshal_response: Number of headers is = %d",
+           num_headers);
+
+    for(i = 0 ; i < (int) num_headers ; i++) {
+        apr_uint16_t name;
+        char *stringname;
+        char *value;
+        rc  = ajp_msg_peek_uint16(msg, &name);
+        if (rc != APR_SUCCESS) {
+            return APR_EGENERAL;
+        }
+                
+        if ((name & 0XFF00) == 0XA000) {
+            ajp_msg_peek_uint16(msg, &name);
+            stringname = (char *)long_res_header_for_sc(name);
+            if (stringname == NULL) {
+                ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
+                       "Error ajp_unmarshal_response - "
+                       "No such sc (%08x)",
+                       name);
+                return APR_EGENERAL;
+            }
+        } else {
+            name = 0;
+            rc = ajp_msg_get_string(msg, &stringname);
+            if (rc != APR_SUCCESS) {
+                ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
+                       "Error ajp_unmarshal_response - "
+                       "Null header name");
+                return APR_EGENERAL;
+            }
+#if defined(AS400) || defined(_OSD_POSIX)
+            ap_xlate_proto_from_ascii(stringname, strlen(stringname));
+#endif
+        }
+
+        rc = ajp_msg_get_string(msg, &value);
+        if (rc != APR_SUCCESS) {
+            ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
+                   "Error ajp_unmarshal_response - "
+                   "Null header value");
+            return APR_EGENERAL;
+        }
+
+#if defined(AS400) || defined(_OSD_POSIX)
+        ap_xlate_proto_from_ascii(value, strlen(value));
+#endif
+        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+               "ajp_unmarshal_response: Header[%d] [%s] = [%s]", 
+                       i, stringname, value);
+        apr_table_add(r->headers_out, stringname, value);
+
+        /* Content-type needs an additional handling */
+        if (memcmp(stringname, "Content-Type", 12) == 0) {
+             /* add corresponding filter */
+            ap_set_content_type(r, apr_pstrdup(r->pool, value));
+            ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+               "ajp_unmarshal_response: ap_set_content_type done");
+        }
+    }
+
+    return APR_SUCCESS;
+}
+
+/*
+ * Build the ajp header message and send it
+ */
+apr_status_t ajp_send_header(apr_socket_t *sock,
+                                  request_rec  *r)
+{
+    ajp_msg_t *msg;
+    apr_status_t rc;
+
+    rc = ajp_msg_create(r->pool, &msg);
+    if (rc != APR_SUCCESS) {
+        ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
+               "ajp_send_header: ajp_msg_create failed");
+        return rc;
+    }
+
+    rc = ajp_marshal_into_msgb(msg, r);    
+    if (rc != APR_SUCCESS) {
+        ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
+               "ajp_send_header: ajp_marshal_into_msgb failed");
+        return rc;
+    }
+
+    rc = ajp_ilink_send(sock, msg);
+    if (rc != APR_SUCCESS) {
+        ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
+               "ajp_send_header: ajp_ilink_send failed");
+        return rc;
+    }
+
+    return APR_SUCCESS;
+}
+
+/*
+ * Read the ajp message and return the type of the message.
+ */
+apr_status_t ajp_read_header(apr_socket_t *sock,
+                             request_rec  *r,
+                             ajp_msg_t **msg)
+{
+    apr_byte_t result;
+    apr_status_t rc;
+    
+    rc = ajp_msg_create(r->pool, msg);
+    if (rc != APR_SUCCESS) {
+        ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
+               "ajp_read_header: ajp_msg_create failed");
+        return rc;
+    }
+    ajp_msg_reset(*msg);
+    rc = ajp_ilink_receive(sock, *msg);
+    if (rc != APR_SUCCESS) {
+        ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
+               "ajp_read_header: ajp_ilink_receive failed");
+        return rc;
+    }
+    rc = ajp_msg_peek_uint8(*msg, &result);
+    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+               "ajp_read_header: ajp_ilink_received %02x", result);
+    return APR_SUCCESS;
+}
+
+/* parse the msg to read the type */
+int ajp_parse_type(request_rec  *r, ajp_msg_t *msg)
+{
+    apr_byte_t result;
+    ajp_msg_peek_uint8(msg, &result);
+    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+               "ajp_parse_type: got %02x", result);
+    return (int) result;
+}
+
+/* parse the header */
+apr_status_t ajp_parse_header(request_rec  *r, ajp_msg_t *msg)
+{
+    apr_byte_t result;
+    apr_status_t rc;
+
+    rc = ajp_msg_get_uint8(msg, &result);
+    if (rc != APR_SUCCESS) {
+        ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
+               "ajp_parse_headers: ajp_msg_get_byte failed");
+        return rc;
+    }
+    if (result != CMD_AJP13_SEND_HEADERS) {
+        ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
+               "ajp_parse_headers: wrong type %02x expecting 0x04", result);
+        return APR_EGENERAL;
+    }
+    return ajp_unmarshal_response(msg, r);
+}
+
+/* parse the body and return data address and length */
+apr_status_t  ajp_parse_data(request_rec  *r, ajp_msg_t *msg,
+                             apr_uint16_t *len, char **ptr)
+{
+    apr_byte_t result;
+    apr_status_t rc;
+
+    rc = ajp_msg_get_uint8(msg, &result);
+    if (rc != APR_SUCCESS) {
+        ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
+               "ajp_parse_data: ajp_msg_get_byte failed");
+        return rc;
+    }
+    if (result != CMD_AJP13_SEND_BODY_CHUNK) {
+        ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
+               "ajp_parse_data: wrong type %02x expecting 0x03", result);
+        return APR_EGENERAL;
+    }
+    rc = ajp_msg_get_uint16(msg, len);
+    if (rc != APR_SUCCESS) {
+        return APR_EGENERAL;
+    }
+    *ptr = (char *)&(msg->buf[msg->pos]);
+    return APR_SUCCESS;
+}
+
+/*
+ * Allocate a msg to send data
+ */
+apr_status_t  ajp_alloc_data_msg(request_rec *r, char **ptr, apr_size_t *len,
+                                 ajp_msg_t **msg)
+{
+    apr_status_t rc;
+
+    rc = ajp_msg_create(r->pool, msg);
+    if (rc != APR_SUCCESS) {
+        ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
+               "ajp_alloc_data_msg: ajp_msg_create failed");
+        return rc;
+    }
+    ajp_msg_reset(*msg);
+    *ptr = (char *)&((*msg)->buf[6]);
+    *len = AJP_MSG_BUFFER_SZ-6;
+
+    return APR_SUCCESS;
+}
+
+/*
+ * Send the data message
+ */
+apr_status_t  ajp_send_data_msg(apr_socket_t *sock, request_rec  *r,
+                                ajp_msg_t *msg, apr_size_t len)
+{
+    apr_status_t rc;
+
+    msg->buf[4] = (apr_byte_t)((len >> 8) & 0xFF);
+    msg->buf[5] = (apr_byte_t)(len & 0xFF);
+
+    msg->len += len + 2; /* + 1 XXXX where is '\0' */
+
+    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+               "ajp_send_data_msg: sending %d", len);
+
+    rc = ajp_ilink_send(sock, msg);
+    if (rc != APR_SUCCESS) {
+        ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
+               "ajp_send_data_msg: ajp_ilink_send failed");
+        return rc;
+    }
+
+    return APR_SUCCESS;
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/ajp/ajplib/src/ajp_link.c
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/ajp/ajplib/src/ajp_link.c	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/ajp/ajplib/src/ajp_link.c	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,132 @@
+/* Copyright 1999-2004 The Apache Software Foundation
+ *
+ * Licensed 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.
+ */
+
+#include "ajp.h"
+
+
+apr_status_t ajp_ilink_send(apr_socket_t *sock, ajp_msg_t *msg)
+{
+    char         *buf;
+    apr_status_t status;
+    apr_size_t   length;
+
+    if (sock == NULL) {
+        ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL,
+                      "ajp_ilink_send(): NULL socket provided");
+        return AJP_EINVAL;
+    }
+    
+    ajp_msg_end(msg);
+    
+    length = msg->len;
+    buf    = (char *)msg->buf;
+
+    do {
+        apr_size_t written = length;
+
+        status = apr_socket_send(sock, buf, &written);
+        if (status != APR_SUCCESS) {
+            ap_log_error(APLOG_MARK, APLOG_ERR, status, NULL,
+                          "ajp_ilink_send(): send failed");
+            return status;
+        }
+        length -= written;
+        buf    += written;
+    } while (length);
+
+    return APR_SUCCESS;
+}
+
+
+static apr_status_t ilink_read(apr_socket_t *sock, char * buf,
+                               apr_size_t len)
+{
+    apr_size_t   length;
+    apr_status_t status;
+    apr_size_t   rdlen;
+
+    if (sock == NULL) {
+        ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL,
+                      "ajp_ilink_readN(): NULL socket provided");
+        return AJP_EINVAL;
+    }
+
+    rdlen  = 0;
+    length = len;
+    
+    while (rdlen < len) {
+
+        status = apr_socket_recv(sock, buf + rdlen, &length);
+
+        if (status == APR_EOF)
+            return status;          /* socket closed. */
+        else if (APR_STATUS_IS_EAGAIN(status))
+            continue;
+        else if (status != APR_SUCCESS)
+            return status;          /* any error. */
+            
+        rdlen += length;
+        length = len - rdlen;
+    }
+    return APR_SUCCESS;
+}
+
+
+apr_status_t ajp_ilink_receive(apr_socket_t *sock, ajp_msg_t *msg)
+{
+    apr_status_t status;
+    apr_size_t   hlen;
+    apr_size_t   blen;
+
+    if (sock == NULL) {
+        ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL,
+                      "ajp_ilink_receive(): NULL socket provided");
+        return AJP_EINVAL;
+    }
+
+    hlen = msg->header_len;
+    
+    status = ilink_read(sock, msg->buf, hlen);
+    
+    if (status != APR_SUCCESS) {
+        ap_log_error(APLOG_MARK, APLOG_ERR, status, NULL,
+                "ajp_ilink_receive() can't receive header\n");
+        return AJP_ENO_HEADER;
+    }
+    
+    status = ajp_msg_check_header(msg, &blen);
+
+    if (status != APR_SUCCESS) {
+        ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL,
+                      "ajp_ilink_receive() received bad header\n");
+        return AJP_EBAD_HEADER;
+    }
+
+    status = ilink_read(sock, msg->buf + hlen, blen);
+
+    if (status != APR_SUCCESS) {
+        ap_log_error(APLOG_MARK, APLOG_ERR, status, NULL,
+                      "ajp_ilink_receive() error while receiving message body %of length %d\n",
+                      hlen);
+        return AJP_EBAD_MESSAGE;
+    }
+
+    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, NULL,
+                  "ajp_ilink_receive() received packet len=%d type=%d\n",
+                  blen, (int)msg->buf[hlen]);
+
+    return APR_SUCCESS;
+}
+

Added: branches/tomcat5.5/upstream/5.5.20/connectors/ajp/ajplib/src/ajp_logon.c
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/ajp/ajplib/src/ajp_logon.c	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/ajp/ajplib/src/ajp_logon.c	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,214 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.
+ */
+
+#include "ajp_logon.h"
+#include "ajp.h"
+
+
+
+/**
+ * Binary to hex C String (null terminated)
+ *
+ * @param org        byte array to transform
+ * @param dst        string result
+ * @param n          len of byte array
+ * @return           APR_SUCCESS or error
+ */
+static char * hextocstr(apr_byte_t *org, char *dst, int n)
+{
+    char       *os = dst;
+    apr_byte_t  v;
+    static char zitohex[] = "0123456789ABCDEF";
+
+    while (--n >= 0) {
+        v = *org++;
+        *dst++ = zitohex[v >> 4];
+        *dst++ = zitohex[v & 0x0f];
+    }
+    *dst = 0;
+
+    return (os);
+}
+
+/**
+ * Compute the MD5 of org and (if not null org2) string
+ *
+ * @param org        First String to compute MD5 from
+ * @param org2       Second String to compute MD5 from (if null no action)
+ * @param dst        Destination MD5 Hex CString
+ * @return           APR_SUCCESS or error
+ */
+apr_status_t comp_md5(char *org, char *org2, char *dst)
+{
+    apr_md5_ctx_t ctx;
+    unsigned char buf[AJP14_MD5_DIGESTSIZE + 1];
+
+    apr_md5_init(&ctx);
+    apr_md5_update(&ctx, org, (apr_size_t)strlen(org));
+
+    if (org2 != NULL)
+        apr_md5_update(&ctx, org2, (apr_size_t)strlen(org2));
+
+    apr_md5_final(buf, &ctx);
+
+    hextocstr(buf, dst, AJP14_MD5_DIGESTSIZE);
+    
+    return APR_SUCCESS;
+}
+
+/**
+ * Decode the Incoming Login Command and build reply
+ *
+ * @param msg        AJP Message to be decoded and then filled
+ * @param secret     secret string to be used in logon phase
+ * @param servername local server name (ie: Apache 2.0.50)
+ * @return           APR_SUCCESS or error
+ */
+apr_status_t ajp_handle_login(ajp_msg_t *msg, char *secret, char *servername)
+{
+    int             status;
+    char            *entropy;
+    char            computedKey[AJP14_COMPUTED_KEY_LEN];
+
+    status = ajp_msg_get_string(msg, &entropy);
+    
+    if (status != APR_SUCCESS) {
+        ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL,
+                      "ajp_handle_login(): can't get seed");
+
+        return AJP_ELOGFAIL;
+    }
+
+    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, NULL,
+                 "ajp_handle_login(): received entropy %s",
+                 entropy);
+
+    comp_md5(entropy, secret, computedKey);
+
+    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, NULL,
+                 "ajp_handle_login(): computed md5 (%s/%s) -> (%s)",
+                 entropy, secret, computedKey);
+
+    ajp_msg_reset(msg);
+
+    /* LOGCOMP CMD */    
+    status = ajp_msg_append_uint8(msg, AJP14_LOGCOMP_CMD);
+    
+    if (status != APR_SUCCESS) {
+        ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL,
+                      "ajp_handle_login(): can't log command");
+
+        return AJP_ELOGFAIL;
+    }
+
+    /* COMPUTED-SEED */
+    status = ajp_msg_append_string(msg, computedKey);
+
+    if (status != APR_SUCCESS) {
+        ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL,
+                      "ajp_handle_login(): can't serialize computed secret");
+
+        return AJP_ELOGFAIL;
+    }
+
+    /* NEGOCIATION OPTION */    
+    status = ajp_msg_append_uint32(msg, AJP14_CONTEXT_INFO_NEG | AJP14_PROTO_SUPPORT_AJP14_NEG);
+
+    if (status != APR_SUCCESS) {
+        ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL,
+                      "ajp_handle_login(): can't append negociation header");
+
+        return AJP_ELOGFAIL;
+    }
+
+    /* SERVER NAME */    
+    status = ajp_msg_append_string(msg, servername);
+
+    if (status != APR_SUCCESS) {
+        ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL,
+                      "ajp_handle_login(): can't serialize server name");
+
+        return AJP_ELOGFAIL;
+    }
+
+    return APR_SUCCESS;
+}
+
+
+/**
+ * Decode the LogOk Command. After that we're done, the connection is
+ * perfect and ready.
+ *
+ * @param msg        AJP Message to be decoded
+ * @return           APR_SUCCESS or error
+ */
+apr_status_t ajp_handle_logok(ajp_msg_t *msg)
+{
+    apr_status_t status;
+    apr_uint32_t negociation;
+    char         *server_name;
+
+    status = ajp_msg_get_uint32(msg, &negociation);
+    
+    if (status != APR_SUCCESS) {
+        ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL,
+                      "ajp_handle_logok(): can't get negociation header");
+
+        return AJP_ELOGFAIL;
+    }
+
+    status = ajp_msg_get_string(msg, &server_name);
+
+    if (status != APR_SUCCESS) {
+        ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL,
+                      "ajp_handle_logok(): can't get servlet engine name");
+
+        return AJP_ELOGFAIL;
+    }
+
+    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, NULL,
+                 "ajp_handle_logok(): Successfully logged to %s",
+                 server_name);
+
+    return APR_SUCCESS;
+}
+
+
+/**
+ * Decode the Log Nok Command 
+ *
+ * @param msg        AJP Message to be decoded
+ */
+apr_status_t ajp_handle_lognok(ajp_msg_t *msg)
+{
+    apr_status_t status;
+    apr_uint32_t failurecode;
+
+    status = ajp_msg_get_uint32(msg, &failurecode);
+
+    if (status != APR_SUCCESS) {
+        ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL,
+                      "ajp_handle_lognok(): can't get failure code");
+
+        return AJP_ELOGFAIL;
+    }
+
+    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, NULL,
+                 "ajp_handle_logok(): logon failure code is %08lx",
+                 (long)failurecode);
+
+    return APR_SUCCESS;
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/ajp/ajplib/src/ajp_msg.c
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/ajp/ajplib/src/ajp_msg.c	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/ajp/ajplib/src/ajp_msg.c	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,607 @@
+/* Copyright 1999-2004 The Apache Software Foundation
+ *
+ * Licensed 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.
+ */
+
+#include "ajp.h"
+
+
+static char *hex_table = "0123456789ABCDEF";
+
+/**
+ * Dump up to the first 1024 bytes on an AJP Message
+ *
+ * @param msg       AJP Message to dump
+ * @param err       error string to display
+ * @return          APR_SUCCESS or error
+ */
+apr_status_t ajp_msg_dump(ajp_msg_t *msg, char *err)
+{
+    apr_size_t  i, j;
+    char        line[80];
+    char        *current;
+    apr_byte_t  x;
+    apr_size_t  len = msg->len;
+
+    /* Display only first 1024 bytes */
+    if (len > 1024)
+        len = 1024;
+
+    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, NULL,
+                  "ajp_msg_dump(): %s pos=%d len=%d max=%d",
+                  err, msg->pos, msg->len, AJP_MSG_BUFFER_SZ);
+
+    for (i = 0; i < len; i += 16) {
+        current = line;
+
+        for (j = 0; j < 16; j++) {
+             x = msg->buf[i + j];
+
+            *current++ = hex_table[x >> 4];
+            *current++ = hex_table[x & 0x0f];
+            *current++ = ' ';
+        }
+        *current++ = ' ';
+        *current++ = '-';
+        *current++ = ' ';
+        for (j = 0; j < 16; j++) {
+            x = msg->buf[i + j];
+
+            if (x > 0x20 && x < 0x7F) {
+                *current++ = x;
+            }
+            else {
+                *current++ = '.';
+            }
+        }
+
+        *current++ = '\0';
+
+        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, NULL,
+                      "ajp_msg_dump(): %.4x    %s",
+                      i, line);
+    }
+    
+    return APR_SUCCESS;
+}
+
+
+/**
+ * Check a new AJP Message by looking at signature and return its size
+ *
+ * @param msg       AJP Message to check
+ * @param len       Pointer to returned len
+ * @return          APR_SUCCESS or error
+ */
+apr_status_t ajp_msg_check_header(ajp_msg_t *msg, apr_size_t *len)
+{
+    apr_byte_t *head = msg->buf;
+    apr_size_t msglen;
+
+    if (!((head[0] == 0x41 && head[1] == 0x42) ||
+          (head[0] == 0x12 && head[1] == 0x34))) {
+
+        ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL,
+                      "ajp_check_msg_header() got bad signature %x%x",
+                      head[0], head[1]);
+
+        return AJP_EBAD_SIGNATURE;
+    }
+
+    msglen  = ((head[2] & 0xff) << 8);
+    msglen += (head[3] & 0xFF);
+
+    if (msglen > AJP_MSG_BUFFER_SZ) {
+        ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL,
+                      "ajp_check_msg_header() incoming message is too big %d, max is %d",
+                      msglen, AJP_MSG_BUFFER_SZ);
+        return AJP_ETOBIG;
+    }
+
+    msg->len = msglen + AJP_HEADER_LEN;
+    msg->pos = AJP_HEADER_LEN;
+    *len     = msglen;
+    
+    return APR_SUCCESS;
+}
+
+/**
+ * Reset an AJP Message
+ *
+ * @param msg       AJP Message to reset
+ * @return          APR_SUCCESS or error
+ */
+apr_status_t ajp_msg_reset(ajp_msg_t *msg)
+{
+    msg->len = AJP_HEADER_LEN;
+    msg->pos = AJP_HEADER_LEN;
+    
+    return APR_SUCCESS;
+}
+
+/**
+ * Mark the end of an AJP Message
+ *
+ * @param msg       AJP Message to end
+ * @return          APR_SUCCESS or error
+ */
+apr_status_t ajp_msg_end(ajp_msg_t *msg)
+{
+    apr_size_t len = msg->len - AJP_HEADER_LEN;
+
+    if (msg->server_side) {
+        msg->buf[0] = 0x41;
+        msg->buf[1] = 0x42;
+    }
+    else {
+        msg->buf[0] = 0x12;
+        msg->buf[1] = 0x34;
+    }
+
+    msg->buf[2] = (apr_byte_t)((len >> 8) & 0xFF);
+    msg->buf[3] = (apr_byte_t)(len & 0xFF);
+    
+    return APR_SUCCESS;
+}
+
+/**
+ * Add an unsigned 32bits value to AJP Message
+ *
+ * @param msg       AJP Message to get value from
+ * @param value     value to add to AJP Message
+ * @return          APR_SUCCESS or error
+ */
+apr_status_t ajp_msg_append_uint32(ajp_msg_t *msg, apr_uint32_t value)
+{
+    apr_size_t len = msg->len;
+
+    if ((len + 4) > AJP_MSG_BUFFER_SZ) {
+        ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL,
+                      "ajp_msg_append_uint32(): BufferOverflowException %d %d",
+                      msg->pos, msg->len);
+        return AJP_EOVERFLOW;
+    }
+
+    msg->buf[len]     = (apr_byte_t)((value >> 24) & 0xFF);
+    msg->buf[len + 1] = (apr_byte_t)((value >> 16) & 0xFF);
+    msg->buf[len + 2] = (apr_byte_t)((value >> 8) & 0xFF);
+    msg->buf[len + 3] = (apr_byte_t)(value & 0xFF);
+
+    msg->len += 4;
+
+    return APR_SUCCESS;
+}
+
+/**
+ * Add an unsigned 16bits value to AJP Message
+ *
+ * @param msg       AJP Message to get value from
+ * @param value     value to add to AJP Message
+ * @return          APR_SUCCESS or error
+ */
+apr_status_t ajp_msg_append_uint16(ajp_msg_t *msg, apr_uint16_t value)
+{
+    apr_size_t len = msg->len;
+
+    if ((len + 2) > AJP_MSG_BUFFER_SZ) {
+        ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL,
+                      "ajp_msg_append_uint16(): BufferOverflowException %d %d",
+                      msg->pos, msg->len);
+        return AJP_EOVERFLOW;
+    }
+
+    msg->buf[len]     = (apr_byte_t)((value >> 8) & 0xFF);
+    msg->buf[len + 1] = (apr_byte_t)(value & 0xFF);
+
+    msg->len += 2;
+
+    return APR_SUCCESS;
+}
+
+/**
+ * Add an unsigned 8bits value to AJP Message
+ *
+ * @param msg       AJP Message to get value from
+ * @param value     value to add to AJP Message
+ * @return          APR_SUCCESS or error
+ */
+apr_status_t ajp_msg_append_uint8(ajp_msg_t *msg, apr_byte_t value)
+{
+    apr_size_t len = msg->len;
+
+    if ((len + 1) > AJP_MSG_BUFFER_SZ) {
+        ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL,
+                      "ajp_msg_append_uint8(): BufferOverflowException %d %d",
+                      msg->pos, msg->len);
+        return AJP_EOVERFLOW;
+    }
+
+    msg->buf[len] = value;
+    msg->len += 1;
+
+    return APR_SUCCESS;
+}
+
+/**
+ *  Add a String in AJP message, and transform the String in ASCII 
+ *  if convert is set and we're on an EBCDIC machine    
+ *
+ * @param msg       AJP Message to get value from
+ * @param value     Pointer to String
+ * @param convert   When set told to convert String to ASCII
+ * @return          APR_SUCCESS or error
+ */
+apr_status_t ajp_msg_append_string_ex(ajp_msg_t *msg, const char *value,
+                                      int convert)
+{
+    size_t len;
+
+    if (value == NULL) {
+        return(ajp_msg_append_uint16(msg, 0xFFFF));
+    }
+
+    len = strlen(value);
+    if ((msg->len + len + 2) > AJP_MSG_BUFFER_SZ) {
+        ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL,
+            "ajp_msg_append_cvt_string(): BufferOverflowException %d %d",
+            msg->pos, msg->len);
+        return AJP_EOVERFLOW;
+    }
+
+    /* ignore error - we checked once */
+    ajp_msg_append_uint16(msg, (apr_uint16_t)len);
+
+    /* We checked for space !!  */
+    memcpy(msg->buf + msg->len, value, len + 1); /* including \0 */
+
+    if (convert)   /* convert from EBCDIC if needed */
+        ajp_xlate_to_ascii((char *)msg->buf + msg->len, len + 1);
+
+    msg->len += len + 1;
+
+    return APR_SUCCESS;
+}
+
+/**
+ * Add a Byte array to AJP Message
+ *
+ * @param msg       AJP Message to get value from
+ * @param value     Pointer to Byte array
+ * @param valuelen  Byte array len
+ * @return          APR_SUCCESS or error
+ */
+apr_status_t ajp_msg_append_bytes(ajp_msg_t *msg, const apr_byte_t *value,
+                                  apr_size_t valuelen)
+{
+    if (! valuelen) {
+        return APR_SUCCESS; /* Shouldn't we indicate an error ? */
+    }
+
+    if ((msg->len + valuelen) > AJP_MSG_BUFFER_SZ) {
+        ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL,
+                      "ajp_msg_append_bytes(): BufferOverflowException %d %d",
+                      msg->pos, msg->len);
+        return AJP_EOVERFLOW;
+    }
+
+    /* We checked for space !!  */
+    memcpy(msg->buf + msg->len, value, valuelen);
+    msg->len += valuelen;
+
+    return APR_SUCCESS;
+}
+
+/**
+ * Get a 32bits unsigned value from AJP Message
+ *
+ * @param msg       AJP Message to get value from
+ * @param rvalue    Pointer where value will be returned
+ * @return          APR_SUCCESS or error
+ */
+apr_status_t ajp_msg_get_uint32(ajp_msg_t *msg, apr_uint32_t *rvalue)
+{
+    apr_uint32_t value;
+
+    if ((msg->pos + 3) > msg->len) {
+        ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL,
+                      "ajp_msg_get_long(): BufferOverflowException %d %d",
+                      msg->pos, msg->len);
+
+        return AJP_EOVERFLOW;
+    }
+
+    value  = ((msg->buf[(msg->pos++)] & 0xFF) << 24);
+    value |= ((msg->buf[(msg->pos++)] & 0xFF) << 16);
+    value |= ((msg->buf[(msg->pos++)] & 0xFF) << 8);
+    value |= ((msg->buf[(msg->pos++)] & 0xFF));
+    
+    *rvalue = value;
+    return APR_SUCCESS;
+}
+
+
+/**
+ * Get a 16bits unsigned value from AJP Message
+ *
+ * @param msg       AJP Message to get value from
+ * @param rvalue    Pointer where value will be returned
+ * @return          APR_SUCCESS or error
+ */
+apr_status_t ajp_msg_get_uint16(ajp_msg_t *msg, apr_uint16_t *rvalue)
+{
+    apr_uint16_t value;
+    
+    if ((msg->pos + 1) > msg->len) {
+        ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL,
+                      "ajp_msg_get_int(): BufferOverflowException %d %d",
+                      msg->pos, msg->len);
+
+        return AJP_EOVERFLOW;
+    }
+
+    value  = ((msg->buf[(msg->pos++)] & 0xFF) << 8);
+    value += ((msg->buf[(msg->pos++)] & 0xFF));
+
+    *rvalue = value;
+    return APR_SUCCESS;
+}
+
+/**
+ * Peek a 16bits unsigned value from AJP Message, position in message
+ * is not updated
+ *
+ * @param msg       AJP Message to get value from
+ * @param rvalue    Pointer where value will be returned
+ * @return          APR_SUCCESS or error
+ */
+apr_status_t ajp_msg_peek_uint16(ajp_msg_t *msg, apr_uint16_t *rvalue)
+{
+    apr_uint16_t value;
+
+    if ((msg->pos + 1) > msg->len) {
+        ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL,
+                      "ajp_msg_peek_int(): BufferOverflowException %d %d",
+                      msg->pos, msg->len);
+
+        return AJP_EOVERFLOW;
+    }
+    
+    value = ((msg->buf[(msg->pos)] & 0xFF) << 8);
+    value += ((msg->buf[(msg->pos + 1)] & 0xFF));
+    
+    *rvalue = value;
+    return APR_SUCCESS;
+}
+
+/**
+ * Peek a 8bits unsigned value from AJP Message, position in message
+ * is not updated
+ *
+ * @param msg       AJP Message to get value from
+ * @param rvalue    Pointer where value will be returned
+ * @return          APR_SUCCESS or error
+ */
+apr_status_t ajp_msg_peek_uint8(ajp_msg_t *msg, apr_byte_t *rvalue)
+{
+    if (msg->pos > msg->len) {
+        ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL,
+                      "ajp_msg_peek_uint8(): BufferOverflowException %d %d",
+                      msg->pos, msg->len);
+
+        return AJP_EOVERFLOW;
+    }
+    
+    *rvalue = msg->buf[msg->pos];
+    return APR_SUCCESS;
+}
+
+/**
+ * Get a 8bits unsigned value from AJP Message
+ *
+ * @param msg       AJP Message to get value from
+ * @param rvalue    Pointer where value will be returned
+ * @return          APR_SUCCESS or error
+ */
+apr_status_t ajp_msg_get_uint8(ajp_msg_t *msg, apr_byte_t *rvalue)
+{
+
+    if (msg->pos > msg->len) {
+        ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL,
+                      "ajp_msg_get_uint8(): BufferOverflowException %d %d",
+                      msg->pos, msg->len);
+
+        return AJP_EOVERFLOW;
+    }
+    
+    *rvalue = msg->buf[msg->pos++];
+    return APR_SUCCESS;
+}
+
+
+/**
+ * Get a String value from AJP Message
+ *
+ * @param msg       AJP Message to get value from
+ * @param rvalue    Pointer where value will be returned
+ * @return          APR_SUCCESS or error
+ */
+apr_status_t ajp_msg_get_string(ajp_msg_t *msg, char **rvalue)
+{
+    apr_uint16_t size;
+    apr_size_t   start;
+    apr_status_t status;
+       
+    status = ajp_msg_get_uint16(msg, &size);
+    start = msg->pos;
+
+    if ((status != APR_SUCCESS) || (size + start > AJP_MSG_BUFFER_SZ)) {
+        ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL,
+                      "ajp_msg_get_string(): BufferOverflowException %d %d",
+                      msg->pos, msg->len);
+
+        return AJP_EOVERFLOW;
+    }
+
+    msg->pos += (apr_size_t)size;
+    msg->pos++;                   /* a String in AJP is NULL terminated */
+
+    *rvalue = (char *)(msg->buf + start);
+    return APR_SUCCESS;
+}
+
+
+/**
+ * Get a Byte array from AJP Message
+ *
+ * @param msg       AJP Message to get value from
+ * @param rvalue    Pointer where value will be returned
+ * @param rvalueLen Pointer where Byte array len will be returned
+ * @return          APR_SUCCESS or error
+ */
+apr_status_t ajp_msg_get_bytes(ajp_msg_t *msg, apr_byte_t **rvalue,
+                               apr_size_t *rvalue_len)
+{
+    apr_uint16_t size;
+    apr_size_t   start;
+    apr_status_t status;
+
+    status = ajp_msg_get_uint16(msg, &size);
+    /* save the current position */
+    start = msg->pos;
+
+    if ((status != APR_SUCCESS) || (size + start > AJP_MSG_BUFFER_SZ)) {
+        ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL,
+                      "ajp_msg_get_bytes(): BufferOverflowException %d %d",
+                      msg->pos, msg->len);
+        return AJP_EOVERFLOW;
+    }
+    msg->pos += (apr_size_t)size;   /* only bytes, no trailer */
+
+    *rvalue     = msg->buf + start;
+    *rvalue_len = size;
+
+    return APR_SUCCESS;
+}
+
+
+/**
+ * Create an AJP Message from pool
+ *
+ * @param pool      memory pool to allocate AJP message from
+ * @param rmsg      Pointer to newly created AJP message
+ * @return          APR_SUCCESS or error
+ */
+apr_status_t ajp_msg_create(apr_pool_t *pool, ajp_msg_t **rmsg)
+{
+    ajp_msg_t *msg = (ajp_msg_t *)apr_pcalloc(pool, sizeof(ajp_msg_t));
+
+    if (!msg) {
+        ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL,
+                      "ajp_msg_create(): can't allocate AJP message memory");
+        return APR_ENOPOOL;
+    }
+    
+    msg->server_side = 0;
+
+    msg->buf = (apr_byte_t *)apr_palloc(pool, AJP_MSG_BUFFER_SZ);
+    
+    /* XXX: This should never happen
+     * In case if the OS cannont allocate 8K of data
+     * we are in serious trouble
+     * No need to check the alloc return value, cause the
+     * core dump is probably the best solution anyhow.
+     */
+    if (msg->buf == NULL) {
+        ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL,
+                      "ajp_msg_create(): can't allocate AJP message memory");
+        return APR_ENOPOOL;
+    }
+
+    msg->len = 0;
+    msg->header_len = AJP_HEADER_LEN;
+    *rmsg = msg;
+    
+    return APR_SUCCESS;
+}
+
+/**
+ * Recopy an AJP Message to another
+ *
+ * @param smsg      source AJP message
+ * @param dmsg      destination AJP message
+ * @return          APR_SUCCESS or error
+ */
+apr_status_t ajp_msg_copy(ajp_msg_t *smsg, ajp_msg_t *dmsg)
+{
+    if (dmsg == NULL) {
+        ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL,
+                      "ajp_msg_copy(): destination msg is null");
+        return AJP_EINVAL;
+    }
+    
+    if (smsg->len > AJP_MSG_BUFFER_SZ) {
+        ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL,
+            "ajp_msg_copy(): destination buffer too small %d, max size is %d",
+            smsg->len, AJP_MSG_BUFFER_SZ);
+        return  AJP_ETOSMALL;
+    }
+
+    memcpy(dmsg->buf, smsg->buf, smsg->len);
+    dmsg->len = smsg->len;
+    dmsg->pos = smsg->pos;
+
+    return APR_SUCCESS;
+}
+
+
+/**
+ * Serialize in an AJP Message a PING command
+ *
+ * +-----------------------+
+ * | PING CMD (1 byte)     |
+ * +-----------------------+
+ *
+ * @param smsg      AJP message to put serialized message
+ * @return          APR_SUCCESS or error
+ */
+apr_status_t ajp_msg_serialize_ping(ajp_msg_t *msg)
+{
+    apr_status_t rc;
+    ajp_msg_reset(msg);
+
+    if ((rc = ajp_msg_append_uint8(msg, CMD_AJP13_PING)) != APR_SUCCESS)
+        return rc;
+        
+    return APR_SUCCESS;
+}
+
+/** 
+ * Serialize in an AJP Message a CPING command
+ *
+ * +-----------------------+
+ * | CPING CMD (1 byte)    |
+ * +-----------------------+
+ *
+ * @param smsg      AJP message to put serialized message
+ * @return          APR_SUCCESS or error
+ */
+apr_status_t ajp_msg_serialize_cping(ajp_msg_t *msg)
+{
+    apr_status_t rc;
+    ajp_msg_reset(msg);
+
+    if ((rc = ajp_msg_append_uint8(msg, CMD_AJP13_CPING)) != APR_SUCCESS)
+        return rc;
+        
+    return APR_SUCCESS;
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/ajp/ajplib/test/Makefile
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/ajp/ajplib/test/Makefile	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/ajp/ajplib/test/Makefile	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,40 @@
+#
+# You need an installed httpd-2.x to use this Makefile
+#
+
+APACHE_DIR=/home2/apache20/apache20
+APR_DIR=$(APACHE_DIR)
+APU_DIR=$(APACHE_DIR)
+
+include $(APR_DIR)/build/config_vars.mk
+
+# in httpd-2.x sources...
+#APR_DIR=$(APACHE_DIR)/srclib/apr
+#APU_DIR=$(APACHE_DIR)/srclib/apr-util
+
+APR_INCLUDE=$(APR_DIR)/include
+APU_INCLUDE=$(APU_DIR)/include
+APA_INCLUDE=$(APACHE_DIR)/include
+
+SRC_DIR=.
+INCLUDE=.
+AJP_OBJECTS = ajp_link.lo  ajp_msg.lo  httpd_wrap.lo ajp_header.lo
+AJP_PROGRAM = testajp.lo
+AJP_LIB     = lib_ajp.la
+
+INCLUDES = -I $(INCLUDE) -I $(APR_INCLUDE) -I $(APU_INCLUDE) -I $(APA_INCLUDE)
+
+include $(APR_DIR)/build/apr_rules.mk
+
+all: testajp
+
+testajp: $(AJP_PROGRAM) $(AJP_LIB)
+	$(LINK) $(AJP_PROGRAM) $(AJP_LIB) $(AP_LIBS)
+
+$(AJP_LIB): $(AJP_OBJECTS)
+	$(LINK) $(AJP_OBJECTS)
+
+clean:
+	rm -f *.o *.so *.lo *.la *.slo
+	rm -rf .libs
+	rm -f testajp

Added: branches/tomcat5.5/upstream/5.5.20/connectors/ajp/ajplib/test/Makefile.netware
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/ajp/ajplib/test/Makefile.netware	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/ajp/ajplib/test/Makefile.netware	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,328 @@
+#
+# Makefile for ajplib (NetWare version - gnu make)
+# created by Guenter Knauf <eflash at gmx.net>
+#
+
+# Edit the path below to point to the base of your Apache 2.x includes.
+ifndef AP_HOME
+AP_HOME	= c:/projects/gccnlm/apache_2.0.50-sdk
+endif
+# Edit the path below to point to the base of your NetWare Java SDK.
+ifndef NW_JDK
+NW_JDK	= c:/projects/sdks/java-nw
+endif
+# Edit the path below to point to the base of your Novell NDK.
+ifndef NDKBASE
+NDKBASE	= c:/novell
+endif
+
+ifndef INSTDIR
+INSTDIR	= ../dist-$(AJP_VERSION_STR)-bin-nw
+endif
+
+# Edit the vars below to change NLM target settings.
+TARGETS = testajp.nlm
+LTARGET = libajp.lib
+VERSION	= $(AJP_VERSION)
+COPYR	= Copyright (c) 2000-2004 The Apache Software Foundation. All rights reserved.
+DESCR	= AJP lib for Jakarta/Tomcat $(AJP_VERSION_STR)
+MTSAFE	= YES
+STACK	= 64000
+#SCREEN	= none
+MODULES	= aprlib
+#EXPORTS	=
+# Comment the line below if you dont want to load protected automatically.
+LDRING	= 3
+
+# Edit the var below to point to your lib architecture.
+ifndef LIBARCH
+LIBARCH = LIBC
+endif
+NW_WINSOCK = 1
+
+# must be equal to DEBUG or NDEBUG
+DB	= NDEBUG
+# DB	= DEBUG
+# DB	= CURLDEBUG
+# Optimization: -O<n> or debugging: -g
+ifeq ($(DB),NDEBUG)
+	OPT	= -O2
+	OBJDIR	= release
+else
+	OPT	= -g
+	OBJDIR	= debug
+endif
+
+# Include the version info retrieved from ajp.h
+#-include $(OBJDIR)/version.inc
+AJP_VERSION = 1,0,0
+AJP_VERSION_STR = 1.0.0-dev-beta
+
+# Check if we are on Linux in order to set the echo delimiter if needed.
+ifeq ($(findstring linux,$(OSTYPE)),linux)
+DL	= '
+#-include $(NDKBASE)/nlmconv/ncpfs.inc
+endif
+
+# The following line defines your compiler.
+ifdef METROWERKS
+	CC = mwccnlm
+else
+	CC = gcc
+endif
+YACC	= bison -y
+CP	= cp -afv
+# RM	= rm -f
+# if you want to mark the target as MTSAFE you will need a tool for
+# generating the xdc data for the linker; here's a minimal tool:
+# http://www.gknw.com/development/prgtools/mkxdc.zip
+MPKXDC	= mkxdc
+
+# Global flags for all compilers
+CFLAGS	= $(OPT) -D$(DB) -DNETWARE -DHAVE_CONFIG_H -nostdinc
+CFLAGS	+= -DAJP_USE_HTTPD_WRAP
+
+ifeq ($(CC),mwccnlm)
+LD	= mwldnlm
+LDFLAGS	= -nostdlib $(PRELUDE) $(OBJS) $(OBJWRAP) $(<:.def=.o) -o $@ -commandfile
+AR	= mwldnlm
+ARFLAGS	= -type library -w nocmdline $(OBJDIR)/*.o -o
+CFLAGS	+= -msgstyle gcc -gccinc -inline off -opt nointrinsics -proc 586
+CFLAGS	+= -relax_pointers
+CFLAGS	+= -w on,nounused
+ifeq ($(LIBARCH),LIBC)
+	PRELUDE = $(SDK_LIBC)/imports/libcpre.o
+	CFLAGS += -align 4
+else
+	PRELUDE = "$(METROWERKS)/Novell Support/libraries/runtime/prelude.obj"
+#	CFLAGS += -include "$(METROWERKS)/Novell Support/headers/nlm_prefix.h"
+	CFLAGS += -align 1
+endif
+else
+LD	= nlmconv
+LDFLAGS	= -T
+AR	= ar
+ARFLAGS	= -cq
+CFLAGS	+= -fno-builtin -fpack-struct -fpcc-struct-return
+CFLAGS	+= -Wall -Wno-format # -pedantic
+ifeq ($(LIBARCH),LIBC)
+	PRELUDE = $(SDK_LIBC)/imports/libcpre.gcc.o
+else
+	PRELUDE = $(SDK_CLIB)/imports/clibpre.gcc.o
+	CFLAGS += -include $(NDKBASE)/nlmconv/genlm.h
+endif
+endif
+
+NDK_ROOT = $(NDKBASE)/ndk
+SDK_CLIB = $(NDK_ROOT)/nwsdk
+SDK_LIBC = $(NDK_ROOT)/libc
+
+INCLUDES += -I$(AP_HOME)/include
+
+ifeq ($(LIBARCH),LIBC)
+	INCLUDES += -I$(SDK_LIBC)/include -I$(SDK_LIBC)/include/nks
+	INCLUDES += -I$(SDK_LIBC)/include/winsock
+	CFLAGS += -D_POSIX_SOURCE
+#	CFLAGS += -D__ANSIC__
+else
+	INCLUDES += -I$(SDK_CLIB)/include/nlm -I$(SDK_CLIB)/include
+	# INCLUDES += -I$(SDK_CLIB)/include/nlm/obsolete
+	CFLAGS += -DNETDB_USE_INTERNET
+endif
+CFLAGS	+= -I. $(INCLUDES)
+
+ifeq ($(MTSAFE),YES)
+	XDCOPT = -n
+endif
+ifeq ($(MTSAFE),NO)
+	XDCOPT = -u
+endif
+
+OBJS	= \
+	$(OBJDIR)/ajp_header.o \
+	$(OBJDIR)/ajp_link.o \
+	$(OBJDIR)/ajp_msg.o
+
+OBJWRAP	= $(OBJDIR)/httpd_wrap.o
+
+.PHONY: lib nlm prebuild dist install clean
+
+nlm: prebuild $(TARGETS) 
+
+lib: prebuild $(LTARGET)
+
+prebuild: $(OBJDIR) $(OBJDIR)/version.inc config.h
+
+dist: all
+	-$(RM) $(OBJS) $(OBJDIR)/*.map $(OBJDIR)/*.ncv
+	-$(RM) $(OBJDIR)/*.def $(OBJDIR)/*.xdc $(OBJDIR)/version.inc
+
+install: $(INSTDIR) all
+	@$(CP) *.nlm $(INSTDIR)
+	@$(CP) ../CHANGES $(INSTDIR)
+	@$(CP) ../COPYING $(INSTDIR)
+	@$(CP) ../README $(INSTDIR)
+	@$(CP) ../RELEASE-NOTES $(INSTDIR)
+
+clean:
+	-$(RM) $(LTARGET) $(TARGETS) $(OBJWRAP) config.h
+	-$(RM) -r $(OBJDIR)
+
+%.lib: $(OBJS)
+	@echo Creating $@
+	@-$(RM) $@
+	@$(AR) $(ARFLAGS) $@ $^
+
+%.nlm: $(OBJDIR)/%.def $(OBJDIR)/%.o $(OBJDIR)/%.xdc $(OBJS) $(OBJWRAP) 
+	@echo Linking $@
+	@-$(RM) $@
+	@$(LD) $(LDFLAGS) $<
+
+$(INSTDIR):
+	@mkdir $(INSTDIR)
+
+$(OBJDIR):
+	@mkdir $(OBJDIR)
+
+$(OBJDIR)/%.o: %.c
+#	@echo Compiling $<
+	$(CC) $(CFLAGS) -c $< -o $@
+
+$(OBJDIR)/version.inc: ajp.h $(OBJDIR)
+#	@echo Creating $@
+#	@awk -f ../packages/NetWare/get_ver.awk $< > $@
+
+$(OBJDIR)/%.xdc: Makefile.netware
+	@echo Creating $@
+	@$(MPKXDC) $(XDCOPT) $@
+
+$(OBJDIR)/%.def: Makefile.netware
+	@echo Creating $@
+	@echo $(DL)# DEF file for linking with $(LD)$(DL) > $@
+	@echo $(DL)# Do not edit this file - it is created by make!$(DL) >> $@
+	@echo $(DL)# All your changes will be lost!!$(DL) >> $@
+	@echo $(DL)#$(DL) >> $@
+	@echo $(DL)copyright "$(COPYR)"$(DL) >> $@
+	@echo $(DL)description "$(DESCR)"$(DL) >> $@
+	@echo $(DL)version $(VERSION)$(DL) >> $@
+ifdef NLMTYPE
+	@echo $(DL)type $(NLMTYPE)$(DL) >> $@
+endif
+ifdef STACK
+	@echo $(DL)stack $(STACK)$(DL) >> $@
+endif
+ifdef SCREEN
+	@echo $(DL)screenname "$(SCREEN)"$(DL) >> $@
+else
+	@echo $(DL)screenname "DEFAULT"$(DL) >> $@
+endif
+ifeq ($(DB),DEBUG)
+	@echo $(DL)debug$(DL) >> $@
+endif
+	@echo $(DL)threadname "$^"$(DL) >> $@
+ifdef XDCOPT
+	@echo $(DL)xdcdata $(@:.def=.xdc)$(DL) >> $@
+endif
+ifeq ($(LDRING),0)
+	@echo $(DL)flag_on 16$(DL) >> $@
+endif
+ifeq ($(LDRING),3)
+	@echo $(DL)flag_on 512$(DL) >> $@
+endif
+ifeq ($(LIBARCH),CLIB)
+	@echo $(DL)start _Prelude$(DL) >> $@
+	@echo $(DL)exit _Stop$(DL) >> $@
+	@echo $(DL)import @$(SDK_CLIB)/imports/clib.imp$(DL) >> $@
+	@echo $(DL)import @$(SDK_CLIB)/imports/threads.imp$(DL) >> $@
+	@echo $(DL)import @$(SDK_CLIB)/imports/nlmlib.imp$(DL) >> $@
+	@echo $(DL)import @$(SDK_CLIB)/imports/socklib.imp$(DL) >> $@
+	@echo $(DL)module clib$(DL) >> $@
+else
+	@echo $(DL)flag_on 64$(DL) >> $@
+	@echo $(DL)pseudopreemption$(DL) >> $@
+	@echo $(DL)start _LibCPrelude$(DL) >> $@
+	@echo $(DL)exit _LibCPostlude$(DL) >> $@
+	@echo $(DL)check _LibCCheckUnload$(DL) >> $@
+	@echo $(DL)import @$(SDK_LIBC)/imports/libc.imp$(DL) >> $@
+	@echo $(DL)import @$(SDK_LIBC)/imports/netware.imp$(DL) >> $@
+	@echo $(DL)module libc$(DL) >> $@
+endif
+	@echo $(DL)import @$(AP_HOME)/lib/aprlib.imp$(DL) >> $@
+ifdef MODULES
+	@echo $(DL)module $(MODULES)$(DL) >> $@
+endif
+ifdef EXPORTS
+	@echo $(DL)export $(EXPORTS)$(DL) >> $@
+endif
+ifdef IMPORTS
+	@echo $(DL)import $(IMPORTS)$(DL) >> $@
+endif
+ifeq ($(LD),nlmconv)
+	@echo $(DL)input $(OBJS)$(DL) >> $@
+	@echo $(DL)input $(OBJWRAP)$(DL) >> $@
+	@echo $(DL)input $(PRELUDE)$(DL) >> $@
+	@echo $(DL)output $(notdir $(@:.def=.nlm))$(DL) >> $@
+endif
+
+config.h: Makefile.netware
+	@echo Creating $@
+	@echo $(DL)/* $@ for NetWare target.$(DL) > $@
+	@echo $(DL)** Do not edit this file - it is created by make!$(DL) >> $@
+	@echo $(DL)** All your changes will be lost!!$(DL) >> $@
+	@echo $(DL)*/$(DL) >> $@
+	@echo $(DL)#define OS "i586-pc-NetWare"$(DL) >> $@
+	@echo $(DL)#define VERSION "$(AJP_VERSION_STR)"$(DL) >> $@
+	@echo $(DL)#define PACKAGE_BUGREPORT "ajp-bug at apache.org"$(DL) >> $@
+	@echo $(DL)#define HAVE_ARPA_INET_H 1$(DL) >> $@
+	@echo $(DL)#define HAVE_ASSERT_H 1$(DL) >> $@
+	@echo $(DL)#define HAVE_DLFCN_H 1$(DL) >> $@
+	@echo $(DL)#define HAVE_DLOPEN 1$(DL) >> $@
+	@echo $(DL)#define HAVE_ERR_H 1$(DL) >> $@
+	@echo $(DL)#define HAVE_FCNTL_H 1$(DL) >> $@
+	@echo $(DL)#define HAVE_FIONBIO 1$(DL) >> $@
+	@echo $(DL)#define HAVE_GETHOSTBYADDR 1$(DL) >> $@
+	@echo $(DL)#define HAVE_GETTIMEOFDAY 1$(DL) >> $@
+	@echo $(DL)#define HAVE_INET_ADDR 1$(DL) >> $@
+	@echo $(DL)#define HAVE_INET_NTOA 1$(DL) >> $@
+	@echo $(DL)#define HAVE_INET_PTON 1$(DL) >> $@
+	@echo $(DL)#define HAVE_INTTYPES_H 1$(DL) >> $@
+	@echo $(DL)#define HAVE_LIMITS_H 1$(DL) >> $@
+	@echo $(DL)#define HAVE_LONGLONG 1$(DL) >> $@
+	@echo $(DL)#define HAVE_MALLOC_H 1$(DL) >> $@
+	@echo $(DL)#define HAVE_NETINET_IN_H 1$(DL) >> $@
+	@echo $(DL)#define HAVE_SELECT 1$(DL) >> $@
+	@echo $(DL)#define HAVE_SETJMP_H 1$(DL) >> $@
+	@echo $(DL)#define HAVE_SIGNAL 1$(DL) >> $@
+	@echo $(DL)#define HAVE_SOCKET 1$(DL) >> $@
+	@echo $(DL)#define HAVE_STDINT_H 1$(DL) >> $@
+	@echo $(DL)#define HAVE_STDLIB_H 1$(DL) >> $@
+	@echo $(DL)#define HAVE_STRCASECMP 1$(DL) >> $@
+	@echo $(DL)#define HAVE_STRDUP 1$(DL) >> $@
+	@echo $(DL)#define HAVE_STRFTIME 1$(DL) >> $@
+	@echo $(DL)#define HAVE_STRING_H 1$(DL) >> $@
+	@echo $(DL)#define HAVE_STRLCAT 1$(DL) >> $@
+	@echo $(DL)#define HAVE_STRLCPY 1$(DL) >> $@
+	@echo $(DL)#define HAVE_STRSTR 1$(DL) >> $@
+	@echo $(DL)#define HAVE_SYS_PARAM_H 1$(DL) >> $@
+	@echo $(DL)#define HAVE_SYS_SELECT_H 1$(DL) >> $@
+	@echo $(DL)#define HAVE_SYS_STAT_H 1$(DL) >> $@
+	@echo $(DL)#define HAVE_SYS_TIME_H 1$(DL) >> $@
+	@echo $(DL)#define HAVE_TERMIOS_H 1$(DL) >> $@
+	@echo $(DL)#define HAVE_TIME_H 1$(DL) >> $@
+	@echo $(DL)#define HAVE_UNAME 1$(DL) >> $@
+	@echo $(DL)#define HAVE_UNISTD_H 1$(DL) >> $@
+	@echo $(DL)#define STDC_HEADERS 1$(DL) >> $@
+	@echo $(DL)#define TIME_WITH_SYS_TIME 1$(DL) >> $@
+ifdef NW_WINSOCK
+	@echo $(DL)#define HAVE_CLOSESOCKET 1$(DL) >> $@
+else
+	@echo $(DL)#define HAVE_SYS_TYPES_H 1$(DL) >> $@
+	@echo $(DL)#define HAVE_SYS_SOCKET_H 1$(DL) >> $@
+	@echo $(DL)#define HAVE_SYS_SOCKIO_H 1$(DL) >> $@
+	@echo $(DL)#define HAVE_NETDB_H 1$(DL) >> $@
+endif
+ifdef OLD_NOVELLSDK
+	@echo $(DL)#define socklen_t int$(DL) >> $@
+endif
+
+

Added: branches/tomcat5.5/upstream/5.5.20/connectors/ajp/ajplib/test/httpd_wrap.c
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/ajp/ajplib/test/httpd_wrap.c	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/ajp/ajplib/test/httpd_wrap.c	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,671 @@
+/* Copyright 2000-2004 The Apache Software Foundation
+ *
+ * Licensed 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.
+ */
+
+#include "apr.h"
+#include "apr_lib.h"
+#include "apr_strings.h"
+#include "apr_buckets.h"
+#include "apr_md5.h"
+#include "apr_network_io.h"
+#include "apr_pools.h"
+#include "apr_strings.h"
+#include "apr_uri.h"
+#include "apr_date.h"
+#include "apr_fnmatch.h"
+#define APR_WANT_STRFUNC
+#include "apr_want.h"
+ 
+#include "apr_hooks.h"
+#include "apr_optional_hooks.h"
+#include "apr_buckets.h"
+
+#include "httpd_wrap.h"
+
+int AP_DECLARE_DATA ap_default_loglevel = DEFAULT_LOGLEVEL;
+
+static const char *levels[] = {
+    "emerg",
+    "alert",
+    "crit",
+    "error",
+    "warn",
+    "notice",
+    "info",
+    "debug",
+    NULL
+};
+
+static void log_error_core(const char *file, int line, int level,
+                           apr_status_t status,
+                           const char *fmt, va_list args)
+{
+    FILE *stream;
+    char timstr[32];
+    char errstr[MAX_STRING_LEN];
+    
+    /* Skip the loging for lower levels */
+    if (level < 0 || level > ap_default_loglevel)
+        return;
+    if (level < APLOG_WARNING)
+        stream = stderr;
+    else
+        stream = stdout;
+    apr_ctime(&timstr[0], apr_time_now());
+    fprintf(stream, "[%s] [%s] ", timstr, levels[level]);
+    if (file && level == APLOG_DEBUG) {
+#ifndef WIN32
+        char *e = strrchr(file, '/');
+#else
+        char *e = strrchr(file, '\\');
+#endif
+        if (e)
+            fprintf(stream, "%s (%d) ", e + 1, line);
+    }
+
+    if (status != 0) {
+        if (status < APR_OS_START_EAIERR) {
+            fprintf(stream, "(%d)", status);
+        }
+        else if (status < APR_OS_START_SYSERR) {
+            fprintf(stream, "(EAI %d)", status - APR_OS_START_EAIERR);
+        }
+        else if (status < 100000 + APR_OS_START_SYSERR) {
+            fprintf(stream, "(OS %d)", status - APR_OS_START_SYSERR);
+        }
+        else {
+            fprintf(stream, "(os 0x%08x)", status - APR_OS_START_SYSERR);
+        }
+        apr_strerror(status, errstr, MAX_STRING_LEN);
+        fprintf(stream, " %s ", errstr);
+    }
+
+    apr_vsnprintf(errstr, MAX_STRING_LEN, fmt, args);
+    fputs(errstr, stream);
+    fputs("\n", stream);    
+    if (level < APLOG_WARNING)
+        fflush(stream);
+
+}
+
+AP_DECLARE(void) ap_log_error(const char *file, int line, int level,
+                              apr_status_t status, const server_rec *s,
+                              const char *fmt, ...)
+{
+    va_list args;
+
+    va_start(args, fmt);
+    log_error_core(file, line, level, status, fmt, args);
+    va_end(args);
+}
+
+AP_DECLARE(void) ap_log_perror(const char *file, int line, int level,
+                               apr_status_t status, apr_pool_t *p,
+                               const char *fmt, ...)
+{
+    va_list args;
+
+    va_start(args, fmt);
+    log_error_core(file, line, level, status, fmt, args);
+    va_end(args);
+}
+ 
+
+AP_DECLARE(void) ap_log_rerror(const char *file, int line, int level,
+                               apr_status_t status, const request_rec *r,
+                               const char *fmt, ...)
+{
+    va_list args;
+
+    va_start(args, fmt);
+    log_error_core(file, line, level, status, fmt, args);
+    va_end(args);
+}
+
+AP_DECLARE(request_rec *) ap_wrap_create_request(conn_rec *conn)
+{
+    request_rec *r;
+    apr_pool_t *p;
+
+    apr_pool_create(&p, conn->pool);
+    apr_pool_tag(p, "request");
+    r = apr_pcalloc(p, sizeof(request_rec));
+    r->pool            = p;
+    r->connection      = conn;
+    r->server          = conn->base_server;
+
+    r->user            = NULL;
+    r->ap_auth_type    = NULL;
+
+    r->headers_in      = apr_table_make(r->pool, 25);
+    r->subprocess_env  = apr_table_make(r->pool, 25);
+    r->headers_out     = apr_table_make(r->pool, 12);
+    r->err_headers_out = apr_table_make(r->pool, 5);
+    r->notes           = apr_table_make(r->pool, 5);
+
+
+    r->status          = HTTP_REQUEST_TIME_OUT;  /* Until we get a request */
+    r->the_request     = NULL;
+
+    r->status = HTTP_OK;                         /* Until further notice. */
+    return r;
+}
+
+AP_DECLARE(process_rec *) ap_wrap_create_process(int argc, const char * const *argv)
+{
+    process_rec *process;
+    apr_pool_t *cntx;
+    apr_status_t stat;
+
+    stat = apr_pool_create(&cntx, NULL);
+    if (stat != APR_SUCCESS) {
+        /* XXX From the time that we took away the NULL pool->malloc mapping
+         *     we have been unable to log here without segfaulting.
+         */
+        ap_log_error(APLOG_MARK, APLOG_ERR, stat, NULL,
+                     "apr_pool_create() failed to create "
+                     "initial context");
+        apr_terminate();
+        exit(1);
+    }
+
+    apr_pool_tag(cntx, "process");
+
+    process = apr_palloc(cntx, sizeof(process_rec));
+    process->pool = cntx;
+
+    apr_pool_create(&process->pconf, process->pool);
+    apr_pool_tag(process->pconf, "pconf");
+    process->argc = argc;
+    process->argv = argv;
+    process->short_name = apr_filepath_name_get(argv[0]);
+    return process;
+}
+
+AP_DECLARE(server_rec *) ap_wrap_create_server(process_rec *process, apr_pool_t *p)
+{
+    apr_status_t rv;
+    server_rec *s = (server_rec *) apr_pcalloc(p, sizeof(server_rec));
+
+    s->process = process;
+    s->port = 0;
+    s->server_admin = DEFAULT_ADMIN;
+    s->server_hostname = NULL;
+    s->loglevel = DEFAULT_LOGLEVEL;
+    s->limit_req_line = DEFAULT_LIMIT_REQUEST_LINE;
+    s->limit_req_fieldsize = DEFAULT_LIMIT_REQUEST_FIELDSIZE;
+    s->limit_req_fields = DEFAULT_LIMIT_REQUEST_FIELDS;
+    s->timeout = apr_time_from_sec(DEFAULT_TIMEOUT);
+    s->keep_alive_timeout = apr_time_from_sec(DEFAULT_KEEPALIVE_TIMEOUT);
+    s->keep_alive_max = DEFAULT_KEEPALIVE;
+    s->keep_alive = 1;
+    s->addrs = apr_pcalloc(p, sizeof(server_addr_rec));
+
+    /* NOT virtual host; don't match any real network interface */
+    rv = apr_sockaddr_info_get(&s->addrs->host_addr,
+                               NULL, APR_INET, 0, 0, p);
+
+    s->addrs->host_port = 0; /* matches any port */
+    s->addrs->virthost = ""; /* must be non-NULL */
+
+    return s;
+} 
+
+AP_DECLARE(conn_rec *) ap_run_create_connection(apr_pool_t *ptrans,
+                                  server_rec *server,
+                                  apr_socket_t *csd, long id, void *sbh,
+                                  apr_bucket_alloc_t *alloc)
+{
+    apr_status_t rv;
+    conn_rec *c = (conn_rec *) apr_pcalloc(ptrans, sizeof(conn_rec));
+
+    c->sbh = sbh;
+
+    c->conn_config = ap_create_conn_config(ptrans);
+    /* Got a connection structure, so initialize what fields we can
+     * (the rest are zeroed out by pcalloc).
+     */
+    c->notes = apr_table_make(ptrans, 5);
+
+    c->pool = ptrans;
+
+    /* Socket is used only for backend connections
+     * Since we don't have client socket skip the 
+     * creation of adresses. They will be default
+     * to 127.0.0.1:0 both local and remote
+     */
+    if (csd) {
+        if ((rv = apr_socket_addr_get(&c->local_addr, APR_LOCAL, csd))
+            != APR_SUCCESS) {
+                ap_log_error(APLOG_MARK, APLOG_INFO, rv, server,
+                    "apr_socket_addr_get(APR_LOCAL)");
+                apr_socket_close(csd);
+                return NULL;
+         }
+         if ((rv = apr_socket_addr_get(&c->remote_addr, APR_REMOTE, csd))
+                != APR_SUCCESS) {
+            ap_log_error(APLOG_MARK, APLOG_INFO, rv, server,
+                    "apr_socket_addr_get(APR_REMOTE)");
+                apr_socket_close(csd);
+            return NULL;
+         }
+    } 
+    else {
+        /* localhost should be reachable on all platforms */
+        if ((rv = apr_sockaddr_info_get(&c->local_addr, "localhost",
+                                        APR_UNSPEC, 0,
+                                        APR_IPV4_ADDR_OK, 
+                                        c->pool))
+            != APR_SUCCESS) {
+                ap_log_error(APLOG_MARK, APLOG_INFO, rv, server,
+                    "apr_sockaddr_info_get()");
+                return NULL;
+         }
+         c->remote_addr = c->local_addr;        
+    }
+    apr_sockaddr_ip_get(&c->local_ip, c->local_addr);
+    apr_sockaddr_ip_get(&c->remote_ip, c->remote_addr);
+    c->base_server = server;
+
+    c->id = id;
+    c->bucket_alloc = alloc;
+
+    return c;
+} 
+
+AP_DECLARE(const char *) ap_get_remote_host(conn_rec *conn, void *dir_config,
+                                            int type, int *str_is_ip)
+{
+    int ignored_str_is_ip;
+
+    if (!str_is_ip) { /* caller doesn't want to know */
+        str_is_ip = &ignored_str_is_ip;
+    }
+    *str_is_ip = 0;
+
+    /*
+     * Return the desired information; either the remote DNS name, if found,
+     * or either NULL (if the hostname was requested) or the IP address
+     * (if any identifier was requested).
+     */
+    if (conn->remote_host != NULL && conn->remote_host[0] != '\0') {
+        return conn->remote_host;
+    }
+    else {
+        if (type == REMOTE_HOST || type == REMOTE_DOUBLE_REV) {
+            return NULL;
+        }
+        else {
+            *str_is_ip = 1;
+            return conn->remote_ip;
+        }
+    }
+} 
+
+AP_DECLARE(const char *) ap_get_server_name(request_rec *r)
+{
+    /* default */
+    return r->server->server_hostname;
+} 
+
+AP_DECLARE(void) ap_set_content_type(request_rec *r, const char *ct)
+{
+    r->content_type = ct;
+}
+
+
+#define UNKNOWN_METHOD (-1)
+
+static int lookup_builtin_method(const char *method, apr_size_t len)
+{
+    /* Note: the following code was generated by the "shilka" tool from
+       the "cocom" parsing/compilation toolkit. It is an optimized lookup
+       based on analysis of the input keywords. Postprocessing was done
+       on the shilka output, but the basic structure and analysis is
+       from there. Should new HTTP methods be added, then manual insertion
+       into this code is fine, or simply re-running the shilka tool on
+       the appropriate input. */
+
+    /* Note: it is also quite reasonable to just use our method_registry,
+       but I'm assuming (probably incorrectly) we want more speed here
+       (based on the optimizations the previous code was doing). */
+
+    switch (len)
+    {
+    case 3:
+        switch (method[0])
+        {
+        case 'P':
+            return (method[1] == 'U'
+                    && method[2] == 'T'
+                    ? M_PUT : UNKNOWN_METHOD);
+        case 'G':
+            return (method[1] == 'E'
+                    && method[2] == 'T'
+                    ? M_GET : UNKNOWN_METHOD);
+        default:
+            return UNKNOWN_METHOD;
+        }
+
+    case 4:
+        switch (method[0])
+        {
+        case 'H':
+            return (method[1] == 'E'
+                    && method[2] == 'A'
+                    && method[3] == 'D'
+                    ? M_GET : UNKNOWN_METHOD);
+        case 'P':
+            return (method[1] == 'O'
+                    && method[2] == 'S'
+                    && method[3] == 'T'
+                    ? M_POST : UNKNOWN_METHOD);
+        case 'M':
+            return (method[1] == 'O'
+                    && method[2] == 'V'
+                    && method[3] == 'E'
+                    ? M_MOVE : UNKNOWN_METHOD);
+        case 'L':
+            return (method[1] == 'O'
+                    && method[2] == 'C'
+                    && method[3] == 'K'
+                    ? M_LOCK : UNKNOWN_METHOD);
+        case 'C':
+            return (method[1] == 'O'
+                    && method[2] == 'P'
+                    && method[3] == 'Y'
+                    ? M_COPY : UNKNOWN_METHOD);
+        default:
+            return UNKNOWN_METHOD;
+        }
+
+    case 5:
+        switch (method[2])
+        {
+        case 'T':
+            return (memcmp(method, "PATCH", 5) == 0
+                    ? M_PATCH : UNKNOWN_METHOD);
+        case 'R':
+            return (memcmp(method, "MERGE", 5) == 0
+                    ? M_MERGE : UNKNOWN_METHOD);
+        case 'C':
+            return (memcmp(method, "MKCOL", 5) == 0
+                    ? M_MKCOL : UNKNOWN_METHOD);
+        case 'B':
+            return (memcmp(method, "LABEL", 5) == 0
+                    ? M_LABEL : UNKNOWN_METHOD);
+        case 'A':
+            return (memcmp(method, "TRACE", 5) == 0
+                    ? M_TRACE : UNKNOWN_METHOD);
+        default:
+            return UNKNOWN_METHOD;
+        }
+
+    case 6:
+        switch (method[0])
+        {
+        case 'U':
+            switch (method[5])
+            {
+            case 'K':
+                return (memcmp(method, "UNLOCK", 6) == 0
+                        ? M_UNLOCK : UNKNOWN_METHOD);
+            case 'E':
+                return (memcmp(method, "UPDATE", 6) == 0
+                        ? M_UPDATE : UNKNOWN_METHOD);
+            default:
+                return UNKNOWN_METHOD;
+            }
+        case 'R':
+            return (memcmp(method, "REPORT", 6) == 0
+                    ? M_REPORT : UNKNOWN_METHOD);
+        case 'D':
+            return (memcmp(method, "DELETE", 6) == 0
+                    ? M_DELETE : UNKNOWN_METHOD);
+        default:
+            return UNKNOWN_METHOD;
+        }
+
+    case 7:
+        switch (method[1])
+        {
+        case 'P':
+            return (memcmp(method, "OPTIONS", 7) == 0
+                    ? M_OPTIONS : UNKNOWN_METHOD);
+        case 'O':
+            return (memcmp(method, "CONNECT", 7) == 0
+                    ? M_CONNECT : UNKNOWN_METHOD);
+        case 'H':
+            return (memcmp(method, "CHECKIN", 7) == 0
+                    ? M_CHECKIN : UNKNOWN_METHOD);
+        default:
+            return UNKNOWN_METHOD;
+        }
+
+    case 8:
+        switch (method[0])
+        {
+        case 'P':
+            return (memcmp(method, "PROPFIND", 8) == 0
+                    ? M_PROPFIND : UNKNOWN_METHOD);
+        case 'C':
+            return (memcmp(method, "CHECKOUT", 8) == 0
+                    ? M_CHECKOUT : UNKNOWN_METHOD);
+        default:
+            return UNKNOWN_METHOD;
+        }
+
+    case 9:
+        return (memcmp(method, "PROPPATCH", 9) == 0
+                ? M_PROPPATCH : UNKNOWN_METHOD);
+
+    case 10:
+        switch (method[0])
+        {
+        case 'U':
+            return (memcmp(method, "UNCHECKOUT", 10) == 0
+                    ? M_UNCHECKOUT : UNKNOWN_METHOD);
+        case 'M':
+            return (memcmp(method, "MKACTIVITY", 10) == 0
+                    ? M_MKACTIVITY : UNKNOWN_METHOD);
+        default:
+            return UNKNOWN_METHOD;
+        }
+
+    case 11:
+        return (memcmp(method, "MKWORKSPACE", 11) == 0
+                ? M_MKWORKSPACE : UNKNOWN_METHOD);
+
+    case 15:
+        return (memcmp(method, "VERSION-CONTROL", 15) == 0
+                ? M_VERSION_CONTROL : UNKNOWN_METHOD);
+
+    case 16:
+        return (memcmp(method, "BASELINE-CONTROL", 16) == 0
+                ? M_BASELINE_CONTROL : UNKNOWN_METHOD);
+
+    default:
+        return UNKNOWN_METHOD;
+    }
+
+    /* NOTREACHED */
+}
+
+/* Get the method number associated with the given string, assumed to
+ * contain an HTTP method.  Returns M_INVALID if not recognized.
+ *
+ * This is the first step toward placing method names in a configurable
+ * list.  Hopefully it (and other routines) can eventually be moved to
+ * something like a mod_http_methods.c, complete with config stuff.
+ */
+AP_DECLARE(int) ap_method_number_of(const char *method)
+{
+    apr_size_t len = strlen(method);
+    int which = lookup_builtin_method(method, len);
+
+    if (which != UNKNOWN_METHOD)
+        return which;
+
+    return M_INVALID;
+}
+
+static ap_conf_vector_t *create_empty_config(apr_pool_t *p)
+{
+    void *conf_vector = apr_pcalloc(p, sizeof(void *) *
+                                    (DYNAMIC_MODULE_LIMIT));
+    return conf_vector;
+}
+
+AP_CORE_DECLARE(ap_conf_vector_t *) ap_create_request_config(apr_pool_t *p)
+{
+    return create_empty_config(p);
+}
+
+AP_CORE_DECLARE(ap_conf_vector_t *) ap_create_conn_config(apr_pool_t *p)
+{
+    return create_empty_config(p);
+}
+
+AP_DECLARE(apr_status_t) ap_wrap_make_request(request_rec *r, const char *url,
+                                              const char *method,
+                                              const char *content_type,
+                                              const char *content_encoding,
+                                              apr_size_t content_length, char *content)
+{
+    apr_status_t rc;
+
+    if (!url) {
+        ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "Missing url");
+        return APR_EINVAL;
+    }
+    if (!method)
+        method = "GET";
+    if ((r->method_number = lookup_builtin_method(method, strlen(method))) ==
+                                UNKNOWN_METHOD) {
+        ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "Unknown HTTP metdod %s",
+                      method);
+        return APR_EINVAL;
+    }
+    r->method = method;
+    r->protocol = AP_SERVER_PROTOCOL;
+    r->proto_num = HTTP_VERSION(1, 1);
+    r->request_config  = ap_create_request_config(r->pool);
+
+    if ((rc = apr_uri_parse(r->pool, url, &r->parsed_uri)) != APR_SUCCESS) {
+        ap_log_rerror(APLOG_MARK, APLOG_ERR, rc, r, "error parsing uri");
+        return APR_EINVAL;
+    }
+    r->user = r->parsed_uri.user;
+    r->content_type = content_type;
+    r->content_encoding = content_encoding;
+    r->uri = r->parsed_uri.path;
+    if (r->parsed_uri.query)
+        r->unparsed_uri = apr_pstrcat(r->pool, r->parsed_uri.path, "?",
+                                      r->parsed_uri.query, NULL);
+    else
+        r->unparsed_uri = r->uri;
+    if (!r->parsed_uri.port)
+        r->parsed_uri.port = r->server->port;
+    
+    if (r->parsed_uri.hostname) {
+        if (r->parsed_uri.port)
+        apr_table_addn(r->headers_in, "Host",
+            apr_psprintf(r->pool, "%s:%d", r->parsed_uri.hostname, r->parsed_uri.port));
+        else
+            apr_table_addn(r->headers_in, "Host", r->parsed_uri.hostname);
+    }
+    if (r->content_type)
+        apr_table_addn(r->headers_in, "Content-Type", r->content_type);
+    if (r->content_encoding)
+        apr_table_addn(r->headers_in, "Transfer-Encoding", r->content_encoding);
+    if (content_length)
+        apr_table_addn(r->headers_in, "Content-Length", apr_itoa(r->pool,
+                                                       (int)content_length));
+    apr_table_addn(r->headers_in, "Accept", "*/*");
+    apr_table_addn(r->headers_in, "Pragma", "no-cache");
+    apr_table_addn(r->headers_in, "User-Agent", "httpd-wrap/1.0");
+    apr_table_addn(r->headers_in, "Accept-Charset", "iso-8859-2");
+    apr_table_addn(r->headers_in, "Accept-Language", "hr");
+
+    /* Create a simple bucket brigade for post data inside connection */
+    if (content) {
+        apr_bucket *e;
+        if (!r->connection->bucket_alloc)
+            r->connection->bucket_alloc = apr_bucket_alloc_create(r->connection->pool);
+        r->connection->bb = apr_brigade_create(r->connection->pool,
+                                               r->connection->bucket_alloc);
+        e = apr_bucket_transient_create(content, content_length, r->connection->bucket_alloc);
+        APR_BRIGADE_INSERT_TAIL(r->connection->bb, e);
+ 
+    }
+    return APR_SUCCESS;
+}
+
+AP_DECLARE(int) ap_setup_client_block(request_rec *r, int read_policy)
+{
+    const char *lenp = apr_table_get(r->headers_in, "Content-Length");
+    
+    r->remaining = 0;
+    r->read_length = 0;
+    if (lenp)
+        r->remaining = atoi(lenp);
+    return OK;
+}
+
+AP_DECLARE(int) ap_should_client_block(request_rec *r)
+{
+    /* First check if we have already read the request body */
+    /* Since we are not using chunked skip the readed checking */
+    if (r->read_length)
+        return 0;
+    else
+        return 1;
+}
+
+AP_DECLARE(long) ap_get_client_block(request_rec *r, char *buffer,
+                                     apr_size_t bufsiz)
+{
+    apr_status_t rv;
+ 
+    if (r->remaining < 0 || r->remaining == 0)
+        return 0;
+    
+    rv = apr_brigade_flatten(r->connection->bb, buffer, &bufsiz); 
+
+    if (rv != APR_SUCCESS) {
+        return -1;
+    }
+
+    r->read_length += bufsiz;
+    r->remaining   -= bufsiz;
+
+    /* Remove the readed part */
+    if (bufsiz) {
+        apr_bucket *e;
+        e = APR_BRIGADE_FIRST(r->connection->bb);
+        apr_bucket_split(e, bufsiz);
+        e = APR_BRIGADE_FIRST(r->connection->bb);
+        APR_BUCKET_REMOVE(e);
+    }
+
+    return (long)bufsiz; 
+
+}
+
+/* No op */
+AP_DECLARE(int) ap_discard_request_body(request_rec *r)
+{
+    return OK;
+}
+

Added: branches/tomcat5.5/upstream/5.5.20/connectors/ajp/ajplib/test/httpd_wrap.h
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/ajp/ajplib/test/httpd_wrap.h	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/ajp/ajplib/test/httpd_wrap.h	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,787 @@
+/* Copyright 2000-2004 The Apache Software Foundation
+ *
+ * Licensed 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.
+ */
+
+
+#ifndef HTTPD_WRAP_H
+#define HTTPD_WRAP_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "apr.h"
+#include "apr_hooks.h"
+#include "apr_optional_hooks.h"
+#include "apr_thread_proc.h"
+
+/* No WIN32 dll support */
+
+#define AP_DECLARE(type)            type
+#define AP_DECLARE_NONSTD(type)     type
+#define AP_DECLARE_DATA
+/**
+ * @internal
+ * modules should not used functions marked AP_CORE_DECLARE
+ */
+#ifndef AP_CORE_DECLARE
+# define AP_CORE_DECLARE	AP_DECLARE
+#endif 
+
+/** The default string lengths */
+#define MAX_STRING_LEN HUGE_STRING_LEN
+#define HUGE_STRING_LEN 8192
+
+/** The size of the server's internal read-write buffers */
+#define AP_IOBUFSIZE 8192
+
+#define DECLINED -1     /**< Module declines to handle */
+#define DONE -2         /**< Module has served the response completely 
+                 *  - it's safe to die() with no more output
+                 */
+#define OK 0            /**< Module has handled this stage. */
+
+
+/**
+ * @defgroup HTTP_Status HTTP Status Codes
+ * @{
+ */
+/**
+ * The size of the static array in http_protocol.c for storing
+ * all of the potential response status-lines (a sparse table).
+ * A future version should dynamically generate the apr_table_t at startup.
+ */
+#define RESPONSE_CODES 57
+
+#define HTTP_CONTINUE                      100
+#define HTTP_SWITCHING_PROTOCOLS           101
+#define HTTP_PROCESSING                    102
+#define HTTP_OK                            200
+#define HTTP_CREATED                       201
+#define HTTP_ACCEPTED                      202
+#define HTTP_NON_AUTHORITATIVE             203
+#define HTTP_NO_CONTENT                    204
+#define HTTP_RESET_CONTENT                 205
+#define HTTP_PARTIAL_CONTENT               206
+#define HTTP_MULTI_STATUS                  207
+#define HTTP_MULTIPLE_CHOICES              300
+#define HTTP_MOVED_PERMANENTLY             301
+#define HTTP_MOVED_TEMPORARILY             302
+#define HTTP_SEE_OTHER                     303
+#define HTTP_NOT_MODIFIED                  304
+#define HTTP_USE_PROXY                     305
+#define HTTP_TEMPORARY_REDIRECT            307
+#define HTTP_BAD_REQUEST                   400
+#define HTTP_UNAUTHORIZED                  401
+#define HTTP_PAYMENT_REQUIRED              402
+#define HTTP_FORBIDDEN                     403
+#define HTTP_NOT_FOUND                     404
+#define HTTP_METHOD_NOT_ALLOWED            405
+#define HTTP_NOT_ACCEPTABLE                406
+#define HTTP_PROXY_AUTHENTICATION_REQUIRED 407
+#define HTTP_REQUEST_TIME_OUT              408
+#define HTTP_CONFLICT                      409
+#define HTTP_GONE                          410
+#define HTTP_LENGTH_REQUIRED               411
+#define HTTP_PRECONDITION_FAILED           412
+#define HTTP_REQUEST_ENTITY_TOO_LARGE      413
+#define HTTP_REQUEST_URI_TOO_LARGE         414
+#define HTTP_UNSUPPORTED_MEDIA_TYPE        415
+#define HTTP_RANGE_NOT_SATISFIABLE         416
+#define HTTP_EXPECTATION_FAILED            417
+#define HTTP_UNPROCESSABLE_ENTITY          422
+#define HTTP_LOCKED                        423
+#define HTTP_FAILED_DEPENDENCY             424
+#define HTTP_UPGRADE_REQUIRED              426
+#define HTTP_INTERNAL_SERVER_ERROR         500
+#define HTTP_NOT_IMPLEMENTED               501
+#define HTTP_BAD_GATEWAY                   502
+#define HTTP_SERVICE_UNAVAILABLE           503
+#define HTTP_GATEWAY_TIME_OUT              504
+#define HTTP_VERSION_NOT_SUPPORTED         505
+#define HTTP_VARIANT_ALSO_VARIES           506
+#define HTTP_INSUFFICIENT_STORAGE          507
+#define HTTP_NOT_EXTENDED                  510
+
+/** is the status code informational */
+#define ap_is_HTTP_INFO(x)         (((x) >= 100)&&((x) < 200))
+/** is the status code OK ?*/
+#define ap_is_HTTP_SUCCESS(x)      (((x) >= 200)&&((x) < 300))
+/** is the status code a redirect */
+#define ap_is_HTTP_REDIRECT(x)     (((x) >= 300)&&((x) < 400))
+/** is the status code a error (client or server) */
+#define ap_is_HTTP_ERROR(x)        (((x) >= 400)&&((x) < 600))
+/** is the status code a client error  */
+#define ap_is_HTTP_CLIENT_ERROR(x) (((x) >= 400)&&((x) < 500))
+/** is the status code a server error  */
+#define ap_is_HTTP_SERVER_ERROR(x) (((x) >= 500)&&((x) < 600))
+
+/** should the status code drop the connection */
+#define ap_status_drops_connection(x) \
+                                   (((x) == HTTP_BAD_REQUEST)           || \
+                                    ((x) == HTTP_REQUEST_TIME_OUT)      || \
+                                    ((x) == HTTP_LENGTH_REQUIRED)       || \
+                                    ((x) == HTTP_REQUEST_ENTITY_TOO_LARGE) || \
+                                    ((x) == HTTP_REQUEST_URI_TOO_LARGE) || \
+                                    ((x) == HTTP_INTERNAL_SERVER_ERROR) || \
+                                    ((x) == HTTP_SERVICE_UNAVAILABLE) || \
+                    ((x) == HTTP_NOT_IMPLEMENTED))
+                    
+/* Maximum number of dynamically loaded modules */
+#ifndef DYNAMIC_MODULE_LIMIT
+#define DYNAMIC_MODULE_LIMIT 64
+#endif
+/* Default administrator's address */
+#define DEFAULT_ADMIN "[no address given]"
+/* The timeout for waiting for messages */
+#ifndef DEFAULT_TIMEOUT
+#define DEFAULT_TIMEOUT 300 
+#endif
+/* The timeout for waiting for keepalive timeout until next request */
+#ifndef DEFAULT_KEEPALIVE_TIMEOUT
+#define DEFAULT_KEEPALIVE_TIMEOUT 15
+#endif
+/* The number of requests to entertain per connection */
+#ifndef DEFAULT_KEEPALIVE
+#define DEFAULT_KEEPALIVE 100
+#endif
+#ifndef DEFAULT_LIMIT_REQUEST_LINE
+#define DEFAULT_LIMIT_REQUEST_LINE 8190
+#endif /* default limit on bytes in Request-Line (Method+URI+HTTP-version) */
+#ifndef DEFAULT_LIMIT_REQUEST_FIELDSIZE
+#define DEFAULT_LIMIT_REQUEST_FIELDSIZE 8190
+#endif /* default limit on bytes in any one header field  */
+#ifndef DEFAULT_LIMIT_REQUEST_FIELDS
+#define DEFAULT_LIMIT_REQUEST_FIELDS 100
+#endif /* default limit on number of request header fields */
+#ifndef DEFAULT_CONTENT_TYPE
+#define DEFAULT_CONTENT_TYPE "text/plain"
+#endif
+/**
+ * The address 255.255.255.255, when used as a virtualhost address,
+ * will become the "default" server when the ip doesn't match other vhosts.
+ */
+#define DEFAULT_VHOST_ADDR 0xfffffffful
+ 
+/* options for get_remote_host() */
+/* REMOTE_HOST returns the hostname, or NULL if the hostname
+ * lookup fails.  It will force a DNS lookup according to the
+ * HostnameLookups setting.
+ */
+#define REMOTE_HOST (0)
+
+/* REMOTE_NAME returns the hostname, or the dotted quad if the
+ * hostname lookup fails.  It will force a DNS lookup according
+ * to the HostnameLookups setting.
+ */
+#define REMOTE_NAME (1)
+
+/* REMOTE_NOLOOKUP is like REMOTE_NAME except that a DNS lookup is
+ * never forced.
+ */
+#define REMOTE_NOLOOKUP (2)
+
+/* REMOTE_DOUBLE_REV will always force a DNS lookup, and also force
+ * a double reverse lookup, regardless of the HostnameLookups
+ * setting.  The result is the (double reverse checked) hostname,
+ * or NULL if any of the lookups fail.
+ */
+#define REMOTE_DOUBLE_REV (3)
+                     
+/** @} */
+/**
+ * @defgroup Methods List of Methods recognized by the server
+ * @{
+ */
+/**
+ * Methods recognized (but not necessarily handled) by the server.
+ * These constants are used in bit shifting masks of size int, so it is
+ * unsafe to have more methods than bits in an int.  HEAD == M_GET.
+ * This list must be tracked by the list in http_protocol.c in routine
+ * ap_method_name_of().
+ */
+#define M_GET                   0       /* RFC 2616: HTTP */
+#define M_PUT                   1       /*  :             */
+#define M_POST                  2
+#define M_DELETE                3
+#define M_CONNECT               4
+#define M_OPTIONS               5
+#define M_TRACE                 6       /* RFC 2616: HTTP */
+#define M_PATCH                 7       /* no rfc(!)  ### remove this one? */
+#define M_PROPFIND              8       /* RFC 2518: WebDAV */
+#define M_PROPPATCH             9       /*  :               */
+#define M_MKCOL                 10
+#define M_COPY                  11
+#define M_MOVE                  12
+#define M_LOCK                  13
+#define M_UNLOCK                14      /* RFC 2518: WebDAV */
+#define M_VERSION_CONTROL       15      /* RFC 3253: WebDAV Versioning */
+#define M_CHECKOUT              16      /*  :                          */
+#define M_UNCHECKOUT            17
+#define M_CHECKIN               18
+#define M_UPDATE                19
+#define M_LABEL                 20
+#define M_REPORT                21
+#define M_MKWORKSPACE           22
+#define M_MKACTIVITY            23
+#define M_BASELINE_CONTROL      24
+#define M_MERGE                 25
+#define M_INVALID               26      /* RFC 3253: WebDAV Versioning */
+
+/**
+ * METHODS needs to be equal to the number of bits
+ * we are using for limit masks.
+ */
+#define METHODS     64
+
+/**
+ * The method mask bit to shift for anding with a bitmask.
+ */
+#define AP_METHOD_BIT ((apr_int64_t)1)
+
+/*
+ * This is a convenience macro to ease with checking a mask
+ * against a method name.
+ */
+#define AP_METHOD_CHECK_ALLOWED(mask, methname) \
+    ((mask) & (AP_METHOD_BIT << ap_method_number_of((methname))))
+
+/** @} */
+
+/** default HTTP Server protocol */
+#define AP_SERVER_PROTOCOL "HTTP/1.1"
+/** Internal representation for a HTTP protocol number, e.g., HTTP/1.1 */
+
+#define HTTP_VERSION(major,minor) (1000*(major)+(minor))
+/** Major part of HTTP protocol */
+#define HTTP_VERSION_MAJOR(number) ((number)/1000)
+/** Minor part of HTTP protocol */
+#define HTTP_VERSION_MINOR(number) ((number)%1000)
+
+/**
+ * @defgroup values_request_rec_body Possible values for request_rec.read_body 
+ * @{
+ * Possible values for request_rec.read_body (set by handling module):
+ */
+
+/** Send 413 error if message has any body */
+#define REQUEST_NO_BODY          0
+/** Send 411 error if body without Content-Length */
+#define REQUEST_CHUNKED_ERROR    1
+/** If chunked, remove the chunks for me. */
+#define REQUEST_CHUNKED_DECHUNK  2
+/** @} */
+ 
+
+/* fake structure declarations */
+typedef struct process_rec  process_rec;
+typedef struct request_rec  request_rec;
+typedef struct conn_rec     conn_rec;
+typedef struct server_rec   server_rec;
+typedef struct ap_conf_vector_t ap_conf_vector_t;
+ 
+
+/* fake structure definitions */
+/** A structure that represents one process */
+struct process_rec {
+    /** Global pool. Cleared upon normal exit */
+    apr_pool_t *pool;
+    /** Configuration pool. Cleared upon restart */
+    apr_pool_t *pconf;
+    /** Number of command line arguments passed to the program */
+    int argc;
+    /** The command line arguments */
+    const char * const *argv;
+    /** The program name used to execute the program */
+    const char *short_name;
+};
+
+/** A structure that represents the current request */
+struct request_rec {
+    /** The pool associated with the request */
+    apr_pool_t *pool;
+    /** The connection to the client */
+    conn_rec *connection;
+    /** The virtual host for this request */
+    server_rec *server;
+    /** First line of request */
+    char *the_request;
+    /** HTTP/0.9, "simple" request (e.g. GET /foo\n w/no headers) */
+    int assbackwards;
+    /** A proxy request (calculated during post_read_request/translate_name)
+     *  possible values PROXYREQ_NONE, PROXYREQ_PROXY, PROXYREQ_REVERSE,
+     *                  PROXYREQ_RESPONSE
+     */
+    int proxyreq;
+    /** HEAD request, as opposed to GET */
+    int header_only;
+    /** Protocol string, as given to us, or HTTP/0.9 */
+    char *protocol;
+    /** Protocol version number of protocol; 1.1 = 1001 */
+    int proto_num;
+    /** Host, as set by full URI or Host: */
+    const char *hostname;
+
+    /** Time when the request started */
+    apr_time_t request_time;
+
+    /** Status line, if set by script */
+    const char *status_line;
+    /** Status line */
+    int status;
+
+    /* Request method, two ways; also, protocol, etc..  Outside of protocol.c,
+     * look, but don't touch.
+     */
+
+    /** Request method (eg. GET, HEAD, POST, etc.) */
+    const char *method;
+    /** M_GET, M_POST, etc. */
+    int method_number;
+ 
+    /** MIME header environment from the request */
+    apr_table_t *headers_in;
+    /** MIME header environment for the response */
+    apr_table_t *headers_out;
+    /** MIME header environment for the response, printed even on errors and
+     * persist across internal redirects */
+    apr_table_t *err_headers_out;
+    /** Array of environment variables to be used for sub processes */
+    apr_table_t *subprocess_env;
+    /** Notes from one module to another */
+    apr_table_t *notes;
+
+    /* content_type, handler, content_encoding, and all content_languages 
+     * MUST be lowercased strings.  They may be pointers to static strings;
+     * they should not be modified in place.
+     */
+    /** The content-type for the current request */
+    const char *content_type;   /* Break these out --- we dispatch on 'em */
+    /** The handler string that we use to call a handler function */
+    const char *handler;    /* What we *really* dispatch on */
+
+    /** Remaining bytes left to read from the request body */
+    apr_off_t remaining;
+    /** Number of bytes that have been read  from the request body */
+    apr_off_t read_length;
+
+    /** How to encode the data */
+    const char *content_encoding;
+    /** Array of strings representing the content languages */
+    apr_array_header_t *content_languages;
+    /** If an authentication check was made, this gets set to the user name. */
+    char *user; 
+    /** If an authentication check was made, this gets set to the auth type. */
+    char *ap_auth_type;
+     /** The URI without any parsing performed */
+    char *unparsed_uri; 
+    /** The path portion of the URI */
+    char *uri;
+    /** The filename on disk corresponding to this response */
+    char *filename;
+    /* XXX: What does this mean? Please define "canonicalize" -aaron */
+    /** The true filename, we canonicalize r->filename if these don't match */
+    char *canonical_filename;
+    /** The PATH_INFO extracted from this request */
+    char *path_info;
+    /** The QUERY_ARGS extracted from this request */
+    char *args; 
+    /** ST_MODE set to zero if no such file */
+    apr_finfo_t finfo;
+    /** A struct containing the components of URI */
+    apr_uri_t parsed_uri;
+    /** Options set in config files, etc. */
+    struct ap_conf_vector_t *per_dir_config;
+    /** Notes on *this* request */
+    struct ap_conf_vector_t *request_config;         
+};
+
+/** Structure to store things which are per connection */
+struct conn_rec {
+    /** Pool associated with this connection */
+    apr_pool_t *pool;
+    /** Physical vhost this conn came in on */
+    server_rec *base_server;
+    /* Information about the connection itself */
+    /** local address */
+    apr_sockaddr_t *local_addr;
+    /** remote address */
+    apr_sockaddr_t *remote_addr;
+    /** Client's IP address */
+    char *remote_ip;
+    /** Client's DNS name, if known.  NULL if DNS hasn't been checked,
+     *  "" if it has and no address was found.  N.B. Only access this though
+     * get_remote_host() */
+    char *remote_host; 
+    /** How many times have we used it? */
+    int keepalives;
+    /** server IP address */
+    char *local_ip;
+    /** used for ap_get_server_name when UseCanonicalName is set to DNS
+     *  (ignores setting of HostnameLookups) */
+    char *local_host;
+     /** ID of this connection; unique at any point in time */
+    long id;
+    /** Notes on *this* connection */
+    struct ap_conf_vector_t *conn_config;
+    /** send note from one module to another, must remain valid for all
+     *  requests on this conn */
+    apr_table_t *notes; 
+    /** handle to scoreboard information for this connection */
+    void *sbh; 
+    /** The bucket allocator to use for all bucket/brigade creations */
+    struct apr_bucket_alloc_t *bucket_alloc;
+    /** This doesn't exists in the original, but it is here to simulate the network */
+    apr_bucket_brigade *bb;    
+};
+
+/** A structure to be used for Per-vhost config */
+typedef struct server_addr_rec server_addr_rec;
+struct server_addr_rec {
+    /** The next server in the list */
+    server_addr_rec *next;
+    /** The bound address, for this server */
+    apr_sockaddr_t *host_addr;
+    /** The bound port, for this server */
+    apr_port_t host_port;
+    /** The name given in <VirtualHost> */
+    char *virthost;
+};
+
+/** A structure to store information for each virtual server */
+struct server_rec {
+    /** The process this server is running in */
+    process_rec *process;
+    /* Contact information */
+    /** The admin's contact information */
+    char *server_admin;
+     /** The server hostname */
+    char *server_hostname;
+    /** for redirects, etc. */
+    apr_port_t port;
+    /** The log level for this server */
+    int loglevel;
+
+    server_addr_rec *addrs; 
+    /** Timeout, as an apr interval, before we give up */
+    apr_interval_time_t timeout;
+    /** The apr interval we will wait for another request */
+    apr_interval_time_t keep_alive_timeout;
+    /** Maximum requests per connection */
+    int keep_alive_max;
+    /** Use persistent connections? */
+    int keep_alive;
+ 
+    /** true if this is the virtual server */
+    int is_virtual; 
+    /** limit on size of the HTTP request line    */
+    int limit_req_line;
+    /** limit on size of any request header field */
+    int limit_req_fieldsize;
+    /** limit on number of request header fields  */
+    int limit_req_fields;
+
+};
+
+/* Apache logging support */
+#define APLOG_EMERG 0   /* system is unusable */
+#define APLOG_ALERT 1   /* action must be taken immediately */
+#define APLOG_CRIT  2   /* critical conditions */
+#define APLOG_ERR   3   /* error conditions */
+#define APLOG_WARNING   4   /* warning conditions */
+#define APLOG_NOTICE    5   /* normal but significant condition */
+#define APLOG_INFO  6   /* informational */
+#define APLOG_DEBUG 7   /* debug-level messages */
+
+#define APLOG_LEVELMASK 7   /* mask off the level value */
+
+
+/* APLOG_NOERRNO is ignored and should not be used.  It will be
+ * removed in a future release of Apache.
+ */
+#define APLOG_NOERRNO       (APLOG_LEVELMASK + 1)
+
+/* Use APLOG_TOCLIENT on ap_log_rerror() to give content
+ * handlers the option of including the error text in the 
+ * ErrorDocument sent back to the client. Setting APLOG_TOCLIENT
+ * will cause the error text to be saved in the request_rec->notes 
+ * table, keyed to the string "error-notes", if and only if:
+ * - the severity level of the message is APLOG_WARNING or greater
+ * - there are no other "error-notes" set in request_rec->notes
+ * Once error-notes is set, it is up to the content handler to
+ * determine whether this text should be sent back to the client.
+ * Note: Client generated text streams sent back to the client MUST 
+ * be escaped to prevent CSS attacks.
+ */
+#define APLOG_TOCLIENT          ((APLOG_LEVELMASK + 1) * 2)
+
+/* normal but significant condition on startup, usually printed to stderr */
+#define APLOG_STARTUP           ((APLOG_LEVELMASK + 1) * 4) 
+
+#ifndef DEFAULT_LOGLEVEL
+#define DEFAULT_LOGLEVEL    APLOG_WARNING
+#endif
+
+extern int AP_DECLARE_DATA ap_default_loglevel;
+
+#define APLOG_MARK  __FILE__,__LINE__
+
+
+/**
+ * One of the primary logging routines in Apache.  This uses a printf-like
+ * format to log messages to the error_log.
+ * @param file The file in which this function is called
+ * @param line The line number on which this function is called
+ * @param level The level of this error message
+ * @param status The status code from the previous command
+ * @param s The server on which we are logging
+ * @param fmt The format string
+ * @param ... The arguments to use to fill out fmt.
+ * @tip Use APLOG_MARK to fill out file and line
+ * @warning It is VERY IMPORTANT that you not include any raw data from 
+ * the network, such as the request-URI or request header fields, within 
+ * the format string.  Doing so makes the server vulnerable to a 
+ * denial-of-service attack and other messy behavior.  Instead, use a 
+ * simple format string like "%s", followed by the string containing the 
+ * untrusted data.
+ * @deffunc void ap_log_error(const char *file, int line, int level, apr_status_t status, const server_rec *s, const char *fmt, ...) 
+ */
+AP_DECLARE(void) ap_log_error(const char *file, int line, int level, 
+                             apr_status_t status, const server_rec *s, 
+                             const char *fmt, ...)
+                __attribute__((format(printf,6,7)));
+
+/**
+ * The second of the primary logging routines in Apache.  This uses 
+ * a printf-like format to log messages to the error_log.
+ * @param file The file in which this function is called
+ * @param line The line number on which this function is called
+ * @param level The level of this error message
+ * @param status The status code from the previous command
+ * @param p The pool which we are logging for
+ * @param fmt The format string
+ * @param ... The arguments to use to fill out fmt.
+ * @tip Use APLOG_MARK to fill out file and line
+ * @warning It is VERY IMPORTANT that you not include any raw data from 
+ * the network, such as the request-URI or request header fields, within 
+ * the format string.  Doing so makes the server vulnerable to a 
+ * denial-of-service attack and other messy behavior.  Instead, use a 
+ * simple format string like "%s", followed by the string containing the 
+ * untrusted data.
+ * @deffunc void ap_log_perror(const char *file, int line, int level, apr_status_t status, apr_pool_t *p, const char *fmt, ...) 
+ */
+AP_DECLARE(void) ap_log_perror(const char *file, int line, int level, 
+                             apr_status_t status, apr_pool_t *p, 
+                             const char *fmt, ...)
+                __attribute__((format(printf,6,7)));
+
+/**
+ * The last of the primary logging routines in Apache.  This uses 
+ * a printf-like format to log messages to the error_log.
+ * @param file The file in which this function is called
+ * @param line The line number on which this function is called
+ * @param level The level of this error message
+ * @param status The status code from the previous command
+ * @param s The request which we are logging for
+ * @param fmt The format string
+ * @param ... The arguments to use to fill out fmt.
+ * @tip Use APLOG_MARK to fill out file and line
+ * @warning It is VERY IMPORTANT that you not include any raw data from 
+ * the network, such as the request-URI or request header fields, within 
+ * the format string.  Doing so makes the server vulnerable to a 
+ * denial-of-service attack and other messy behavior.  Instead, use a 
+ * simple format string like "%s", followed by the string containing the 
+ * untrusted data.
+ * @deffunc void ap_log_rerror(const char *file, int line, int level, apr_status_t status, request_rec *r, const char *fmt, ...) 
+ */
+AP_DECLARE(void) ap_log_rerror(const char *file, int line, int level, 
+                               apr_status_t status, const request_rec *r, 
+                               const char *fmt, ...)
+                __attribute__((format(printf,6,7)));
+/**
+ * create_connection is a RUN_FIRST hook which allows modules to create 
+ * connections. In general, you should not install filters with the 
+ * create_connection hook. If you require vhost configuration information 
+ * to make filter installation decisions, you must use the pre_connection
+ * or install_network_transport hook. This hook should close the connection
+ * if it encounters a fatal error condition.
+ *
+ * @param p The pool from which to allocate the connection record
+ * @param csd The socket that has been accepted
+ * @param conn_id A unique identifier for this connection.  The ID only
+ *                needs to be unique at that time, not forever.
+ * @param sbh A handle to scoreboard information for this connection.
+ * @return An allocated connection record or NULL.
+ */ 
+AP_DECLARE(conn_rec *) ap_run_create_connection(apr_pool_t *ptrans,
+                                  server_rec *server,
+                                  apr_socket_t *csd, long id, void *sbh,
+                                  apr_bucket_alloc_t *alloc);
+
+/**
+ * Get the current server name from the request
+ * @param r The current request
+ * @return the server name
+ * @deffunc const char *ap_get_server_name(request_rec *r)
+ */
+AP_DECLARE(const char *) ap_get_server_name(request_rec *r);
+
+/**
+ * Lookup the remote client's DNS name or IP address
+ * @param conn The current connection
+ * @param dir_config The directory config vector from the request
+ * @param type The type of lookup to perform.  One of:
+ * <pre>
+ *     REMOTE_HOST returns the hostname, or NULL if the hostname
+ *                 lookup fails.  It will force a DNS lookup according to the
+ *                 HostnameLookups setting.
+ *     REMOTE_NAME returns the hostname, or the dotted quad if the
+ *                 hostname lookup fails.  It will force a DNS lookup according
+ *                 to the HostnameLookups setting.
+ *     REMOTE_NOLOOKUP is like REMOTE_NAME except that a DNS lookup is
+ *                     never forced.
+ *     REMOTE_DOUBLE_REV will always force a DNS lookup, and also force
+ *                   a double reverse lookup, regardless of the HostnameLookups
+ *                   setting.  The result is the (double reverse checked) 
+ *                   hostname, or NULL if any of the lookups fail.
+ * </pre>
+ * @param str_is_ip unless NULL is passed, this will be set to non-zero on output when an IP address 
+ *        string is returned
+ * @return The remote hostname
+ * @deffunc const char *ap_get_remote_host(conn_rec *conn, void *dir_config, int type, int *str_is_ip)
+ */
+AP_DECLARE(const char *) ap_get_remote_host(conn_rec *conn, void *dir_config, int type, int *str_is_ip);
+
+/* Reading a block of data from the client connection (e.g., POST arg) */
+
+/**
+ * Setup the client to allow Apache to read the request body.
+ * @param r The current request
+ * @param read_policy How the server should interpret a chunked 
+ *                    transfer-encoding.  One of: <pre>
+ *    REQUEST_NO_BODY          Send 413 error if message has any body
+ *    REQUEST_CHUNKED_ERROR    Send 411 error if body without Content-Length
+ *    REQUEST_CHUNKED_DECHUNK  If chunked, remove the chunks for me.
+ * </pre>
+ * @return either OK or an error code
+ * @deffunc int ap_setup_client_block(request_rec *r, int read_policy)
+ */
+AP_DECLARE(int) ap_setup_client_block(request_rec *r, int read_policy);
+
+/**
+ * Determine if the client has sent any data.  This also sends a 
+ * 100 Continue response to HTTP/1.1 clients, so modules should not be called
+ * until the module is ready to read content.
+ * @warning Never call this function more than once.
+ * @param r The current request
+ * @return 0 if there is no message to read, 1 otherwise
+ * @deffunc int ap_should_client_block(request_rec *r)
+ */
+AP_DECLARE(int) ap_should_client_block(request_rec *r);
+
+/**
+ * Call this in a loop.  It will put data into a buffer and return the length
+ * of the input block
+ * @param r The current request
+ * @param buffer The buffer in which to store the data
+ * @param bufsiz The size of the buffer
+ * @return Number of bytes inserted into the buffer.  When done reading, 0
+ *         if EOF, or -1 if there was an error
+ * @deffunc long ap_get_client_block(request_rec *r, char *buffer, apr_size_t bufsiz)
+ */
+AP_DECLARE(long) ap_get_client_block(request_rec *r, char *buffer, apr_size_t bufsiz);
+
+/**
+ * In HTTP/1.1, any method can have a body.  However, most GET handlers
+ * wouldn't know what to do with a request body if they received one.
+ * This helper routine tests for and reads any message body in the request,
+ * simply discarding whatever it receives.  We need to do this because
+ * failing to read the request body would cause it to be interpreted
+ * as the next request on a persistent connection.
+ * @param r The current request
+ * @return error status if request is malformed, OK otherwise 
+ * @deffunc int ap_discard_request_body(request_rec *r)
+ */
+AP_DECLARE(int) ap_discard_request_body(request_rec *r);
+
+/**
+ * Set the content type for this request (r->content_type). 
+ * @param r The current request
+ * @param ct The new content type
+ * @deffunc void ap_set_content_type(request_rec *r, const char* ct)
+ * @warning This function must be called to set r->content_type in order 
+ * for the AddOutputFilterByType directive to work correctly.
+ */
+AP_DECLARE(void) ap_set_content_type(request_rec *r, const char *ct);
+
+/**
+ * Setup the config vector for a request_rec
+ * @param p The pool to allocate the config vector from
+ * @return The config vector
+ */
+AP_CORE_DECLARE(ap_conf_vector_t*) ap_create_request_config(apr_pool_t *p);
+
+/* For http_connection.c... */
+/**
+ * Setup the config vector for a connection_rec
+ * @param p The pool to allocate the config vector from
+ * @return The config vector
+ */
+AP_CORE_DECLARE(ap_conf_vector_t*) ap_create_conn_config(apr_pool_t *p);
+
+/**
+ * Get the method number associated with the given string, assumed to
+ * contain an HTTP method.  Returns M_INVALID if not recognized.
+ * @param method A string containing a valid HTTP method
+ * @return The method number
+ */
+AP_DECLARE(int) ap_method_number_of(const char *method);
+
+/**
+ * create the request_rec structure from fake client connection 
+ */
+AP_DECLARE(request_rec *) ap_wrap_create_request(conn_rec *conn);
+
+/**
+ * create the server_rec structure from process_rec. 
+ */
+AP_DECLARE(server_rec *) ap_wrap_create_server(process_rec *process, apr_pool_t *p);
+
+/**
+ * create the main process_rec. 
+ */
+AP_DECLARE(process_rec *) ap_wrap_create_process(int argc, const char * const *argv);
+
+/**
+ * Fill the request_rec with data. 
+ * @param r      The current request
+ * @param url    The full url http://[username:password@]hostname[:port]/uri
+ * @param method Method "GET", "POST", etc...
+ * @param content_type The post data content type
+ * @param content_encoding The post data transfer encoding
+ * @param content_length The post data content length
+ * @param content The post content data.
+ * @return APR_SUCCESS or error
+ */
+AP_DECLARE(apr_status_t) ap_wrap_make_request(request_rec *r, const char *url,
+                                              const char *method,
+                                              const char *content_type,
+                                              const char *content_encoding,
+                                              apr_size_t content_length, char *content);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* HTTPD_WRAP_H */

Added: branches/tomcat5.5/upstream/5.5.20/connectors/ajp/ajplib/test/test.sln
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/ajp/ajplib/test/test.sln	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/ajp/ajplib/test/test.sln	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,94 @@
+Microsoft Visual Studio Solution File, Format Version 8.00
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testajp", "testajp.vcproj", "{398AC1EA-8B86-4746-B4F3-D174440703E0}"
+	ProjectSection(ProjectDependencies) = postProject
+		{A58AA747-485E-42FE-880F-15B9A498B75D} = {A58AA747-485E-42FE-880F-15B9A498B75D}
+		{54D9CF8D-ED01-4E87-89C4-F06F9D757EED} = {54D9CF8D-ED01-4E87-89C4-F06F9D757EED}
+	EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "apr", "..\srclib\apr\apr.vcproj", "{54C317DF-BBE3-4F62-96CF-A6D7344EB615}"
+	ProjectSection(ProjectDependencies) = postProject
+	EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libapr", "..\srclib\apr\libapr.vcproj", "{54D9CF8D-ED01-4E87-89C4-F06F9D757EED}"
+	ProjectSection(ProjectDependencies) = postProject
+	EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "aprutil", "..\srclib\apr-util\aprutil.vcproj", "{CA59109B-88A7-4547-BDCE-9568AB08DD53}"
+	ProjectSection(ProjectDependencies) = postProject
+		{315E11BD-4452-48FE-AF47-A39BF4EDD608} = {315E11BD-4452-48FE-AF47-A39BF4EDD608}
+		{EF7D84CE-5F76-47C8-A198-B3EF72870920} = {EF7D84CE-5F76-47C8-A198-B3EF72870920}
+	EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libaprutil", "..\srclib\apr-util\libaprutil.vcproj", "{A58AA747-485E-42FE-880F-15B9A498B75D}"
+	ProjectSection(ProjectDependencies) = postProject
+		{54D9CF8D-ED01-4E87-89C4-F06F9D757EED} = {54D9CF8D-ED01-4E87-89C4-F06F9D757EED}
+		{315E11BD-4452-48FE-AF47-A39BF4EDD608} = {315E11BD-4452-48FE-AF47-A39BF4EDD608}
+		{EF7D84CE-5F76-47C8-A198-B3EF72870920} = {EF7D84CE-5F76-47C8-A198-B3EF72870920}
+		{DDCAEED8-D4D0-4C34-A961-FCA7D8EC26B7} = {DDCAEED8-D4D0-4C34-A961-FCA7D8EC26B7}
+	EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gen_uri_delims", "..\srclib\apr-util\uri\gen_uri_delims.vcproj", "{315E11BD-4452-48FE-AF47-A39BF4EDD608}"
+	ProjectSection(ProjectDependencies) = postProject
+	EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xml", "..\srclib\apr-util\xml\expat\lib\xml.vcproj", "{EF7D84CE-5F76-47C8-A198-B3EF72870920}"
+	ProjectSection(ProjectDependencies) = postProject
+	EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "apriconv", "..\srclib\apr-iconv\apriconv.vcproj", "{DF70B25A-203A-47BB-857F-026F4F625A7D}"
+	ProjectSection(ProjectDependencies) = postProject
+	EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libapriconv", "..\srclib\apr-iconv\libapriconv.vcproj", "{DDCAEED8-D4D0-4C34-A961-FCA7D8EC26B7}"
+	ProjectSection(ProjectDependencies) = postProject
+		{54D9CF8D-ED01-4E87-89C4-F06F9D757EED} = {54D9CF8D-ED01-4E87-89C4-F06F9D757EED}
+	EndProjectSection
+EndProject
+Global
+	GlobalSection(SolutionConfiguration) = preSolution
+		Debug = Debug
+		Release = Release
+	EndGlobalSection
+	GlobalSection(ProjectConfiguration) = postSolution
+		{398AC1EA-8B86-4746-B4F3-D174440703E0}.Debug.ActiveCfg = Debug|Win32
+		{398AC1EA-8B86-4746-B4F3-D174440703E0}.Debug.Build.0 = Debug|Win32
+		{398AC1EA-8B86-4746-B4F3-D174440703E0}.Release.ActiveCfg = Release|Win32
+		{398AC1EA-8B86-4746-B4F3-D174440703E0}.Release.Build.0 = Release|Win32
+		{54C317DF-BBE3-4F62-96CF-A6D7344EB615}.Debug.ActiveCfg = Debug|Win32
+		{54C317DF-BBE3-4F62-96CF-A6D7344EB615}.Debug.Build.0 = Debug|Win32
+		{54C317DF-BBE3-4F62-96CF-A6D7344EB615}.Release.ActiveCfg = Release|Win32
+		{54C317DF-BBE3-4F62-96CF-A6D7344EB615}.Release.Build.0 = Release|Win32
+		{54D9CF8D-ED01-4E87-89C4-F06F9D757EED}.Debug.ActiveCfg = Debug|Win32
+		{54D9CF8D-ED01-4E87-89C4-F06F9D757EED}.Debug.Build.0 = Debug|Win32
+		{54D9CF8D-ED01-4E87-89C4-F06F9D757EED}.Release.ActiveCfg = Release|Win32
+		{54D9CF8D-ED01-4E87-89C4-F06F9D757EED}.Release.Build.0 = Release|Win32
+		{CA59109B-88A7-4547-BDCE-9568AB08DD53}.Debug.ActiveCfg = Debug|Win32
+		{CA59109B-88A7-4547-BDCE-9568AB08DD53}.Debug.Build.0 = Debug|Win32
+		{CA59109B-88A7-4547-BDCE-9568AB08DD53}.Release.ActiveCfg = Release|Win32
+		{CA59109B-88A7-4547-BDCE-9568AB08DD53}.Release.Build.0 = Release|Win32
+		{A58AA747-485E-42FE-880F-15B9A498B75D}.Debug.ActiveCfg = Debug|Win32
+		{A58AA747-485E-42FE-880F-15B9A498B75D}.Debug.Build.0 = Debug|Win32
+		{A58AA747-485E-42FE-880F-15B9A498B75D}.Release.ActiveCfg = Release|Win32
+		{A58AA747-485E-42FE-880F-15B9A498B75D}.Release.Build.0 = Release|Win32
+		{315E11BD-4452-48FE-AF47-A39BF4EDD608}.Debug.ActiveCfg = Debug|Win32
+		{315E11BD-4452-48FE-AF47-A39BF4EDD608}.Debug.Build.0 = Debug|Win32
+		{315E11BD-4452-48FE-AF47-A39BF4EDD608}.Release.ActiveCfg = Release|Win32
+		{315E11BD-4452-48FE-AF47-A39BF4EDD608}.Release.Build.0 = Release|Win32
+		{EF7D84CE-5F76-47C8-A198-B3EF72870920}.Debug.ActiveCfg = Debug|Win32
+		{EF7D84CE-5F76-47C8-A198-B3EF72870920}.Debug.Build.0 = Debug|Win32
+		{EF7D84CE-5F76-47C8-A198-B3EF72870920}.Release.ActiveCfg = Release|Win32
+		{EF7D84CE-5F76-47C8-A198-B3EF72870920}.Release.Build.0 = Release|Win32
+		{DF70B25A-203A-47BB-857F-026F4F625A7D}.Debug.ActiveCfg = Debug|Win32
+		{DF70B25A-203A-47BB-857F-026F4F625A7D}.Debug.Build.0 = Debug|Win32
+		{DF70B25A-203A-47BB-857F-026F4F625A7D}.Release.ActiveCfg = Release|Win32
+		{DF70B25A-203A-47BB-857F-026F4F625A7D}.Release.Build.0 = Release|Win32
+		{DDCAEED8-D4D0-4C34-A961-FCA7D8EC26B7}.Debug.ActiveCfg = Debug|Win32
+		{DDCAEED8-D4D0-4C34-A961-FCA7D8EC26B7}.Debug.Build.0 = Debug|Win32
+		{DDCAEED8-D4D0-4C34-A961-FCA7D8EC26B7}.Release.ActiveCfg = Release|Win32
+		{DDCAEED8-D4D0-4C34-A961-FCA7D8EC26B7}.Release.Build.0 = Release|Win32
+	EndGlobalSection
+	GlobalSection(ExtensibilityGlobals) = postSolution
+	EndGlobalSection
+	GlobalSection(ExtensibilityAddIns) = postSolution
+	EndGlobalSection
+EndGlobal

Added: branches/tomcat5.5/upstream/5.5.20/connectors/ajp/ajplib/test/testajp.c
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/ajp/ajplib/test/testajp.c	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/ajp/ajplib/test/testajp.c	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,283 @@
+/* Copyright 2000-2004 The Apache Software Foundation
+ *
+ * Licensed 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.
+ */
+#include "apr.h"
+#include "apr_lib.h"
+#include "apr_strings.h"
+#include "apr_buckets.h"
+#include "apr_md5.h"
+#include "apr_network_io.h"
+#include "apr_pools.h"
+#include "apr_strings.h"
+#include "apr_uri.h"
+#include "apr_date.h"
+#include "apr_fnmatch.h"
+#define APR_WANT_STRFUNC
+#include "apr_want.h"
+ 
+#include "apr_hooks.h"
+#include "apr_optional_hooks.h"
+#include "apr_buckets.h"
+
+#include "ajp.h"
+
+#if APR_HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#if APR_HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+
+#define TEST_POST_DATA "This document is a proposal of evolution of the current " \
+                       "Apache JServ Protocol version 1.3, also known as ajp13. " \
+                       "I'll not cover here the full protocol but only the add-on from ajp13. " \
+                       "This nth pass include comments from the tomcat-dev list and " \
+                       "misses discovered during developpment."
+
+#define TEST_CASE_URL "http://localhost/servlets-examples/servlet/RequestHeaderExample"
+
+/* Main process */
+static process_rec *main_process;
+/* Default server */
+static server_rec *main_server;
+
+/* This function is part of backend.
+ * The backend return connected socket and conn_rec
+ */
+static apr_status_t connect_to_backend(apr_socket_t **socket, conn_rec **con,
+                                       const char *host, apr_uint16_t port,
+                                       server_rec *server, apr_pool_t *pool)
+{
+    apr_status_t rv;
+    apr_sockaddr_t *remote_sa;
+    
+    if ((rv = apr_sockaddr_info_get(&remote_sa, host, APR_UNSPEC,
+                                    port, 0, pool)) != APR_SUCCESS)
+        return rv;
+    if ((rv = apr_socket_create(socket, remote_sa->family, SOCK_STREAM,
+#if (APR_MAJOR_VERSION > 0)
+                                APR_PROTO_TCP,
+#endif
+                                pool)) != APR_SUCCESS)
+        return rv;
+    if ((rv = apr_socket_timeout_set(*socket,
+                               apr_time_from_sec(3))) != APR_SUCCESS)  
+        return rv;
+    if ((rv = apr_socket_connect(*socket, remote_sa)) != APR_SUCCESS)
+        return rv;
+
+    if (!(*con = ap_run_create_connection(pool, server, *socket,
+                                          0, NULL, NULL)))
+        return APR_EGENERAL;
+
+    return APR_SUCCESS;
+}
+
+#if APR_HAS_THREADS
+
+#define TEST_THREAD_COUNT   10
+static apr_thread_t *threads[TEST_THREAD_COUNT];
+
+static void * APR_THREAD_FUNC thread_worker_func(apr_thread_t *thd, void *data)
+{
+    request_rec *r;
+    conn_rec *c = (conn_rec *)data;
+
+    /* Create an empty request */
+    if (!(r = ap_wrap_create_request(c)))
+        goto cleanup;
+
+    /* TODO: do something usefull */
+    apr_sleep(apr_time_from_sec(1));
+
+    /* Clean up the request */
+    apr_pool_destroy(r->pool);
+
+    apr_thread_exit(thd, APR_SUCCESS);
+    return NULL;
+cleanup:
+    apr_thread_exit(thd, APR_EGENERAL);
+    return NULL;
+}
+
+static int create_threads(server_rec *server)
+{
+    int i;
+    apr_status_t rv;
+
+    for (i = 0; i < TEST_THREAD_COUNT; i++) {
+        conn_rec *c;
+        /* Create a single client connection. The dummy one of course. */
+        if (!(c = ap_run_create_connection(server->process->pool, server,
+                                       NULL, 0, NULL, NULL)))
+            return -1;
+
+        if ((rv = apr_thread_create(&threads[i], NULL,
+                    thread_worker_func, (void *)c,
+                    server->process->pool)) != APR_SUCCESS) {
+            ap_log_error(APLOG_MARK, APLOG_INFO, rv, NULL, "apr_create_thread failed");
+            return -1;
+        }
+    }
+    ap_log_error(APLOG_MARK, APLOG_INFO, 0, NULL, "Created %d worker threads", i);
+    
+    return 0;
+}
+
+static int join_threads()
+{
+    int i, rc = 0;
+    apr_status_t rv;
+
+    for (i = 0; i < TEST_THREAD_COUNT; i++) {
+        apr_thread_join(&rv, threads[i]);
+        if (rv != APR_SUCCESS) {
+            ap_log_error(APLOG_MARK, APLOG_WARNING, 0, NULL, "Worker thread %d failed", i);
+            rc = -1;
+        }
+    }
+
+    ap_log_error(APLOG_MARK, APLOG_INFO, 0, NULL, "All (%d) worker threads joined", i);
+    
+    return rc;
+}
+
+#endif
+
+int main(int argc, const char * const * argv, const char * const *env)
+{
+    int rv = 0;
+    apr_status_t rc;
+    conn_rec *c, *con;
+    request_rec *r;
+    apr_socket_t *sock;
+    ajp_msg_t *msg;
+    char *buf;
+    apr_size_t len;
+
+    apr_app_initialize(&argc, &argv, &env);
+
+    /* This is done in httpd.conf using LogLevel debug directive.
+     * We are setting this directly.
+     */
+    ap_default_loglevel = APLOG_DEBUG;
+
+    ap_log_error(APLOG_MARK, APLOG_INFO, 0, NULL, "Testing ajp...");
+    ap_log_error(APLOG_MARK, APLOG_INFO, 0, NULL, "Creating main server...");
+
+    main_process = ap_wrap_create_process(argc, argv);
+    /* Create the main server_rec */
+    main_server  = ap_wrap_create_server(main_process, main_process->pool);    
+    /* Create a single client connection. The dummy one of course. */
+    if (!(c = ap_run_create_connection(main_process->pool, main_server,
+                                       NULL, 0, NULL, NULL))) {
+        rv = -1;
+        goto finished;
+    }    
+    /* ... and a empty request */
+    if (!(r = ap_wrap_create_request(c))) {
+        rv = -1;
+        goto finished;
+    }
+
+    
+    /* 0. Fill in the request data          */
+    if (ap_wrap_make_request(r, TEST_CASE_URL,
+                             "POST",
+                             NULL, //"application/x-www-form-urlencoded",
+                             NULL,
+                             sizeof(TEST_POST_DATA) - 1,
+                             TEST_POST_DATA) != APR_SUCCESS) {
+        goto finished;
+    }
+    /*
+     * Up to here HTTPD created that for each request.
+     * From now on, we have a server_rec, conn_rec, and request_rec
+     * Who will ever need something else :)
+     */
+
+    /* 1. Obtain a connection to backend    */
+    if ((rc = connect_to_backend(&sock, &con, AJP13_DEF_HOST, AJP13_DEF_PORT,
+            main_server, r->pool)) != APR_SUCCESS) {
+        ap_log_error(APLOG_MARK, APLOG_ERR, rc, NULL, "connect_to_backend");
+        rv = -1;
+        goto finished;
+    }
+
+    /* 2. Create AJP message                */
+    if ((rc = ajp_send_header(sock, r)) != APR_SUCCESS) {
+        ap_log_error(APLOG_MARK, APLOG_ERR, rc, NULL, "ajp_send_header");
+        rv = -1;
+        goto finished;
+    }
+    /* 3. Send AJP message                  */
+
+    ajp_alloc_data_msg(r, &buf, &len, &msg);
+
+    /* Send the initial POST BODY */
+    if (ap_setup_client_block(r, REQUEST_CHUNKED_DECHUNK)) {
+            ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
+                   "Error ajp_marshal_into_msgb - "
+                   "Can't setting client block");    
+    }
+    if (ap_should_client_block(r)) {
+        len = ap_get_client_block(r, buf, len);
+    }
+    else
+        len = ap_get_client_block(r, buf, len);
+
+
+    ajp_send_data_msg(sock, r, msg, len);
+
+    /* 4. Read AJP response                 */
+    if ((rc = ajp_read_header(sock, r, &msg)) != APR_SUCCESS) {
+        ap_log_error(APLOG_MARK, APLOG_ERR, rc, NULL, "ajp_read_header");
+        rv = -1;
+        goto finished;
+    }
+
+    ajp_msg_create(r->pool, &msg);
+    ajp_msg_reset(msg);
+    ajp_ilink_receive(sock, msg);
+
+    /* 5. Display results                   */
+#if 1
+    ajp_msg_dump(msg, "");
+#endif
+    {
+        apr_uint16_t blen;
+        ajp_parse_data(r, msg, &blen, &buf);
+        fputs(buf, stdout);
+    }
+    /* 6. Release the connection            */
+
+
+#if APR_HAS_THREADS_remove_this
+    /* or make the few requests in paralel 
+     * to test the threading.
+     * the upper 7 steps will go to thread_worker_func
+     */
+    if ((rv = create_threads(main_server)))
+        goto finished;
+    
+    if ((rv = join_threads()))
+        goto finished;
+#endif
+
+finished:
+    ap_log_error(APLOG_MARK, APLOG_INFO, 0, NULL, "%s", rv == 0 ? "OK" : "FAILED");
+    apr_terminate();
+
+    return rv;
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/ajp/ajplib/test/testajp.vcproj
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/ajp/ajplib/test/testajp.vcproj	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/ajp/ajplib/test/testajp.vcproj	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,161 @@
+<?xml version="1.0" encoding="windows-1250"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="7.10"
+	Name="testajp"
+	ProjectGUID="{398AC1EA-8B86-4746-B4F3-D174440703E0}"
+	Keyword="Win32Proj">
+	<Platforms>
+		<Platform
+			Name="Win32"/>
+	</Platforms>
+	<Configurations>
+		<Configuration
+			Name="Debug|Win32"
+			OutputDirectory="Debug"
+			IntermediateDirectory="Debug"
+			ConfigurationType="1"
+			CharacterSet="2">
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="0"
+				AdditionalIncludeDirectories="../srclib/apr/include;../srclib/apr-util/include"
+				PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;AJP_USE_HTTPD_WRAP"
+				MinimalRebuild="TRUE"
+				BasicRuntimeChecks="3"
+				RuntimeLibrary="3"
+				UsePrecompiledHeader="0"
+				WarningLevel="3"
+				Detect64BitPortabilityProblems="TRUE"
+				DebugInformationFormat="4"/>
+			<Tool
+				Name="VCCustomBuildTool"/>
+			<Tool
+				Name="VCLinkerTool"
+				OutputFile="$(OutDir)/testajp.exe"
+				LinkIncremental="2"
+				GenerateDebugInformation="TRUE"
+				ProgramDatabaseFile="$(OutDir)/testajp.pdb"
+				SubSystem="1"
+				TargetMachine="1"/>
+			<Tool
+				Name="VCMIDLTool"/>
+			<Tool
+				Name="VCPostBuildEventTool"/>
+			<Tool
+				Name="VCPreBuildEventTool"/>
+			<Tool
+				Name="VCPreLinkEventTool"/>
+			<Tool
+				Name="VCResourceCompilerTool"/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"/>
+			<Tool
+				Name="VCWebDeploymentTool"/>
+			<Tool
+				Name="VCManagedWrapperGeneratorTool"/>
+			<Tool
+				Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
+		</Configuration>
+		<Configuration
+			Name="Release|Win32"
+			OutputDirectory="Release"
+			IntermediateDirectory="Release"
+			ConfigurationType="1"
+			CharacterSet="2">
+			<Tool
+				Name="VCCLCompilerTool"
+				AdditionalIncludeDirectories="../srclib/apr/include;../srclib/apr-util/include"
+				PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;AJP_USE_HTTPD_WRAP"
+				RuntimeLibrary="2"
+				UsePrecompiledHeader="0"
+				WarningLevel="3"
+				Detect64BitPortabilityProblems="TRUE"
+				DebugInformationFormat="3"/>
+			<Tool
+				Name="VCCustomBuildTool"/>
+			<Tool
+				Name="VCLinkerTool"
+				OutputFile="$(OutDir)/testajp.exe"
+				LinkIncremental="1"
+				GenerateDebugInformation="TRUE"
+				SubSystem="1"
+				OptimizeReferences="2"
+				EnableCOMDATFolding="2"
+				TargetMachine="1"/>
+			<Tool
+				Name="VCMIDLTool"/>
+			<Tool
+				Name="VCPostBuildEventTool"/>
+			<Tool
+				Name="VCPreBuildEventTool"/>
+			<Tool
+				Name="VCPreLinkEventTool"/>
+			<Tool
+				Name="VCResourceCompilerTool"/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"/>
+			<Tool
+				Name="VCWebDeploymentTool"/>
+			<Tool
+				Name="VCManagedWrapperGeneratorTool"/>
+			<Tool
+				Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
+		</Configuration>
+	</Configurations>
+	<References>
+	</References>
+	<Files>
+		<Filter
+			Name="Source Files"
+			Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
+			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}">
+			<File
+				RelativePath=".\ajp_header.c">
+			</File>
+			<File
+				RelativePath=".\ajp_link.c">
+			</File>
+			<File
+				RelativePath=".\ajp_logon.c">
+			</File>
+			<File
+				RelativePath=".\ajp_msg.c">
+			</File>
+			<File
+				RelativePath=".\httpd_wrap.c">
+			</File>
+			<File
+				RelativePath=".\testajp.c">
+			</File>
+		</Filter>
+		<Filter
+			Name="Header Files"
+			Filter="h;hpp;hxx;hm;inl;inc;xsd"
+			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}">
+			<File
+				RelativePath=".\ajp.h">
+			</File>
+			<File
+				RelativePath=".\ajp_header.h">
+			</File>
+			<File
+				RelativePath=".\ajp_logon.h">
+			</File>
+			<File
+				RelativePath=".\httpd_wrap.h">
+			</File>
+		</Filter>
+		<Filter
+			Name="Resource Files"
+			Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
+			UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}">
+		</Filter>
+	</Files>
+	<Globals>
+	</Globals>
+</VisualStudioProject>

Added: branches/tomcat5.5/upstream/5.5.20/connectors/ajp/proxy/.indent.pro
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/ajp/proxy/.indent.pro	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/ajp/proxy/.indent.pro	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,58 @@
+-i4 -npsl -di0 -br -nce -d0 -cli0 -npcs -nfc1
+-TBUFF
+-TFILE
+-TTRANS
+-TUINT4
+-T_trans
+-Tallow_options_t
+-Tapache_sfio
+-Tarray_header
+-Tbool_int
+-Tapr_bucket_brigade
+-Tapr_pool_t
+-Tap_filter_t
+-Tbuf_area
+-Tbuff_struct
+-Tbuffy
+-Tcmd_how
+-Tcmd_parms
+-Tcommand_rec
+-Tcommand_struct
+-Tconn_rec
+-Tcore_dir_config
+-Tcore_server_config
+-Tdir_maker_func
+-Tevent
+-Tglobals_s
+-Thandler_func
+-Thandler_rec
+-Tjoblist_s
+-Tlisten_rec
+-Tmerger_func
+-Tmode_t
+-Tmodule
+-Tmodule_struct
+-Tmutex
+-Tn_long
+-Tother_child_rec
+-Toverrides_t
+-Tparent_score
+-Tpid_t
+-Tpiped_log
+-Tpool
+-Trequest_rec
+-Trequire_line
+-Trlim_t
+-Tscoreboard
+-Tsemaphore
+-Tserver_addr_rec
+-Tserver_rec
+-Tserver_rec_chain
+-Tshort_score
+-Ttable
+-Ttable_entry
+-Tthread
+-Tu_wide_int
+-Tvtime_t
+-Twide_int
+-Tproxy_server_conf

Added: branches/tomcat5.5/upstream/5.5.20/connectors/ajp/proxy/CHANGES
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/ajp/proxy/CHANGES	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/ajp/proxy/CHANGES	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,223 @@
+******************************************
+* PLEASE NOTE: Now that development for  *
+* mod_proxy has been folded back into    *
+* the httpd-2.1 tree, this file has      *
+* been depreciated. Proxy changes should *
+* be noted in httpd-2.1's CHANGES file.  *
+* This file exists for historical        *
+* purposes.                              *
+******************************************
+
+mod_proxy changes for httpd 2.0.29-dev
+  *) don't do keepalives for sub-requests. [Ian Holsman]
+  
+  *) fix up proxypass handling [Ian Holsman]
+
+  *) don't send If-Modified-Since, Cache-Control, or If-None-Match on 
+     a subrequest [Ian Holsman]
+
+mod_proxy changes for httpd 2.0.26-dev
+  *) Add New option 'HTTPProxyOverrideReturnedErrors'. By Turning the
+     Flag on, you will mask the error pages returned by the proxied
+     server, and will it will be handled as if your server generated
+     the error. This change was put in so that a 404 on a included
+     r-proxied component will act in the same manner as a 404 on a 
+     included file. [Ian Holsman <ianh at cnet.com>]
+
+mod_proxy changes for httpd 2.0.25-dev
+
+  *) Split proxy: space using <Proxy[Match] > directive blocks from
+     the <Directory[Match] > and <Files[Match] > blocks.  Mod_proxy
+     now bypasses the directory and files testing phase (and skips 
+     the http TRACE default handler on it's own, as well).  Note that 
+     <Location > blocks continue to be processed for proxy: requests.
+     [William Rowe <wrowe at covalent.net>]
+
+  *) apr_uri type/function namespace changes in apr_uri functions
+     [Doug MacEachern <dougm at covalent.net>]
+
+mod_proxy changes for httpd 2.0.23-dev
+
+  *) break the proxy_http_handler into multiple smaller functions.
+     [John Barbee <barbee at veribox.net>]
+
+  *) Fix the proxy when the origin server sends back a 100
+     Continue response.  [John Barbee <barbee at veribox.net>]
+
+  *) Change 'readbytes' from apr_size_t to apr_off_t due to change
+     in ap_get_brigade's parameters [John Barbee <barbee at veribox.net>]
+
+mod_proxy changes for httpd 2.0.20-dev
+  *) Timeout added for backend connections.
+     [Victor Orlikowski <v.j.orlikowski at gte.net>]
+
+  *) Fix abort code path in proxy_http.c, similar to FTP fix.
+     [Chuck Murcko <chuck at topsail.org>]
+
+  *) Fix FTP ABOR command execution path.
+     [Victor Orlikowski <v.j.orlikowski at gte.net>]
+
+  *) FTP return code variable cleanup; fixed problem in login
+     [Chuck Murcko <chuck at topsail.org>]
+
+  *) Get PORT working again in the ftp proxy.
+     [Victor Orlikowski <v.j.orlikowski at gte.net>]
+
+  *) Return result code check for FTP QUIT, after fixing
+     problems with passive connection handling.
+     [Victor Orlikowski <v.j.orlikowski at gte.net>]
+
+  *) Reorganize ap_proxy_string_read() internally to not process eos
+     buckets.
+     [Chuck Murcko <chuck at topsail.org>]
+     [Victor Orlikowski <v.j.orlikowski at gte.net>]
+
+  *) Remove result code check for FTP QUIT command. Some servers send
+     nothing at all back in response to QUIT.
+     [Chuck Murcko <chuck at topsail.org>]
+     [Victor Orlikowski <v.j.orlikowski at gte.net>]
+
+mod_proxy changes for httpd 2.0.19
+
+  *) Reverse previous patch since the core reverted.
+     [Chuck Murcko <chuck at topsail.org>]
+
+  *) Remove indirection on number of bytes to read for input filters.
+     [Chuck Murcko <chuck at topsail.org>]
+
+  *) Fixed a problem with directory listing corruption in the
+     PROXY_DIR filter.
+     [Graham Leggett <minfrin at sharp.fm>]
+
+  *) mod_proxy and the proxy submodules now build properly as DSOs.
+     [Graham Leggett <minfrin at sharp.fm>]
+
+  *) Stopped the HTTP proxy from trying to read entity bodies when there
+     wasn't one (response was 1xx, 204, 205 or 304).
+     [Graham Leggett <minfrin at sharp.fm>]
+
+  *) Made sure dates were canonicalised correctly when passed to the client
+     browser through the HTTP proxy.
+     [Graham Leggett <minfrin at sharp.fm>]
+
+  *) Split each individual proxy protocol into separate modules.
+     [Graham Leggett <minfrin at sharp.fm>]
+
+  *) Added Max-Forwards support for all request types so as to prevent
+     loops.
+     [Graham Leggett <minfrin at sharp.fm>]
+
+  *) Fix warnings about byte count type on Darwin (connect handler).
+     [Chuck Murcko <chuck at topsail.org>]
+
+mod_proxy changes for httpd 2.0.18
+
+  *) IPV6 EPSV support for IPV6 in FTP proxy.
+     [Graham Leggett <minfrin at sharp.fm>]
+
+  *) FTP directory filter works now.
+     [Graham Leggett <minfrin at sharp.fm>]
+
+  *) Fixed some thread-safety issues with the HTTP proxy in mod_proxy.
+     [Graham Leggett <minfrin at sharp.fm>]
+
+  *) PASV FTP works now.
+     [Graham Leggett <minfrin at sharp.fm>]
+
+  *) Reworked the line-at-a-time read from the control connection to
+     workaround a stray empty bucket returned by the HTTP_IN filter.
+     [Graham Leggett <minfrin at sharp.fm>]
+
+  *) Stopped the CORE filter from sending off an HTTP response when a
+     CONNECT tunnel was closed.
+     [Graham Leggett <minfrin at sharp.fm>]
+
+  *) Fixed the poll() loop in proxy_connect.c -> it works now!!!
+     [Graham Leggett <minfrin at sharp.fm>]
+
+  *) Converted send_dir() to ap_proxy_send_dir_filter() in proxy_ftp.c.
+     [Graham Leggett <minfrin at sharp.fm>]
+
+mod_proxy changes for httpd 2.0.17
+
+  *) Major rework of ap_proxy_ftp_handler() to use filters (begone foul
+     BUFF!!!). It compiles, but is untested, and the build environment needs
+     to be fixed to include proxy_ftp.c.
+     [Graham Leggett <minfrin at sharp.fm>]
+
+  *) Cleanup of dead functions within proxy_util.c.
+     [Graham Leggett <minfrin at sharp.fm>]
+
+  *) Reworked the storage of the client socket between keepalive connections
+     to fix some nasty problems with the socket lasting longer than the
+     memory pool it was allocated from.
+     [Graham Leggett <minfrin at sharp.fm>]
+
+  *) Fixed bug where a hostname without a "." in it (such as "localhost")
+     would not trigger an IP address check with ProxyBlock.
+     [Graham Leggett <minfrin at sharp.fm>]
+
+mod_proxy changes for httpd 2.0.16
+
+  *) Fixed ProxyBlock bugs with ap_proxy_http_handler() and
+     ap_proxy_connect_handler().
+     [Graham Leggett <minfrin at sharp.fm>]
+
+  *) Updated ap_proxy_connect_handler() to support APR, while
+     moving some common code between http_handler and connect_handler
+     to proxy_util.c.
+     [Graham Leggett <minfrin at sharp.fm>]
+
+  *) Updated mod_proxy.html docs to include v2.0 configuration.
+     [Graham Leggett <minfrin at sharp.fm>]
+
+  *) Fixed problem where responses without entity bodies would cause
+     the directly following proxy keepalive request to fail.
+     [Graham Leggett <minfrin at sharp.fm>]
+
+mod_proxy changes for httpd 2.0.15
+
+  *) Added support for downstream keepalives in mod_proxy.
+     [Graham Leggett <minfrin at sharp.fm>]
+
+  *) Changed mod_proxy ap_proxy_http_handler() to support APR properly.
+     [Graham Leggett <minfrin at sharp.fm>]
+
+  *) Fix problem where incoming response headers were not being returned
+     to the client in mod_proxy.
+     [Graham Leggett <minfrin at sharp.fm>]
+
+  *) Added X-Forwarded-For, X-Forwarded-Host and X-Forwarded-Server to
+     reverse proxied request headers in mod_proxy.
+     [Graham Leggett <minfrin at sharp.fm>]
+
+  *) replace INADDR_NONE with APR_INADDR_NONE [Ian Holsman <IanH at cnet.com>]
+
+  *) Fix problem with proxy configuration where globally set
+     configuration options were overridden inside virtual hosts.
+     [Graham Leggett <minfrin at sharp.fm>]
+
+  *) Fix ProxyReceiveBufferSize where default value was left
+     uninitialised.
+     [Graham Leggett <minfrin at sharp.fm>]
+
+  *) Some small changes:
+     - Ensured hop-by-hop headers were stripped as per
+       RFC2616 13.5.1.
+     - Upgraded version code to HTTP/1.1.
+     - Added Connection: close until Keepalives come.
+     - Some cosmetic fixes and commenting.
+     [Graham Leggett <minfrin at sharp.fm>]
+
+mod_proxy changes for httpd 2.0.14
+
+  *) removed ProxyNoCache and ProxyCacheForceCompletion config directives,
+     since we no longer directly cache from this module
+     [Chuck Murcko <chuck at topsail.org>]
+
+  *) removed cache
+     [Chuck Murcko <chuck at topsail.org>]
+
+  *) initial rerebuild for 2.0
+     [Chuck Murcko <chuck at topsail.org>]
+

Added: branches/tomcat5.5/upstream/5.5.20/connectors/ajp/proxy/JAKARTA
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/ajp/proxy/JAKARTA	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/ajp/proxy/JAKARTA	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,16 @@
+JAKARTA TOMCAT CONNECTORS AJP CHANGELOG FOR MOD_PROXY:  -*-text-*-
+Last modified at [$Date: 2004-08-03 07:08:22 -0500 (Tue, 03 Aug 2004) $]
+
+Changes in AJP HEAD:
+    * proxy_util.c: Enable compiling on 2.0-HEAD
+      Use apr_socket_create_ex for 0.9.x
+      [Mladen Turk]
+    * mod_proxy.c: Enable compiling on 2.0-HEAD
+      mod_ssl is not included in 2.0-HEAD
+      [Mladen Turk]
+    * mod_proxy.h: Change the proxy_module declaration so that we
+      can compile on WIN32
+      [Mladen Turk]      
+    * Imported proxy sources from 2.1-HEAD
+      Date: 2004/08/03 10:05:52
+      [Mladen Turk] 

Added: branches/tomcat5.5/upstream/5.5.20/connectors/ajp/proxy/Makefile.in
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/ajp/proxy/Makefile.in	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/ajp/proxy/Makefile.in	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,3 @@
+# a modules Makefile has no explicit targets -- they will be defined by
+# whatever modules are enabled. just grab special.mk to deal with this.
+include $(top_srcdir)/build/special.mk

Added: branches/tomcat5.5/upstream/5.5.20/connectors/ajp/proxy/NWGNUmakefile
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/ajp/proxy/NWGNUmakefile	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/ajp/proxy/NWGNUmakefile	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,247 @@
+#
+# Declare the sub-directories to be built here
+#
+
+SUBDIRS = \
+	$(EOLIST) 
+
+#
+# Get the 'head' of the build environment.  This includes default targets and
+# paths to tools
+#
+
+include $(AP_WORK)\build\NWGNUhead.inc
+
+#
+# build this level's files
+
+#
+# Make sure all needed macro's are defined
+#
+
+#
+# These directories will be at the beginning of the include list, followed by
+# INCDIRS
+#
+XINCDIRS	+= \
+			$(EOLIST)
+
+#
+# These flags will come after CFLAGS
+#
+XCFLAGS		+= \
+			$(EOLIST)
+
+#
+# These defines will come after DEFINES
+#
+XDEFINES	+= \
+			$(EOLIST)
+
+#
+# These flags will be added to the link.opt file
+#
+XLFLAGS		+= \
+			$(EOLIST)
+
+#
+# These values will be appended to the correct variables based on the value of
+# RELEASE
+#
+ifeq "$(RELEASE)" "debug"
+XINCDIRS	+= \
+			$(EOLIST)
+
+XCFLAGS		+= \
+			$(EOLIST)
+
+XDEFINES	+= \
+			$(EOLIST)
+
+XLFLAGS		+= \
+		   	$(EOLIST)
+endif
+
+ifeq "$(RELEASE)" "noopt"
+XINCDIRS	+= \
+			$(EOLIST)
+
+XCFLAGS		+= \
+			$(EOLIST)
+
+XDEFINES	+= \
+			$(EOLIST)
+
+XLFLAGS		+= \
+		   	$(EOLIST)
+endif
+
+ifeq "$(RELEASE)" "release"
+XINCDIRS	+= \
+			$(EOLIST)
+
+XCFLAGS		+= \
+			$(EOLIST)
+
+XDEFINES	+= \
+			$(EOLIST)
+
+XLFLAGS		+= \
+			$(EOLIST)
+endif
+
+#
+# These are used by the link target if an NLM is being generated
+# This is used by the link 'name' directive to name the nlm.  If left blank
+# TARGET_nlm (see below) will be used.
+#
+NLM_NAME		=
+
+#
+# This is used by the link '-desc ' directive. 
+# If left blank, NLM_NAME will be used.
+#
+NLM_DESCRIPTION	=
+
+#
+# This is used by the '-threadname' directive.  If left blank,
+# NLM_NAME Thread will be used.
+#
+NLM_THREAD_NAME	=
+
+#
+# If this is specified, it will override VERSION value in 
+# $(AP_WORK)\build\NWGNUenvironment.inc
+#
+NLM_VERSION		=
+
+#
+# If this is specified, it will override the default of 64K
+#
+NLM_STACK_SIZE	=
+
+
+#
+# If this is specified it will be used by the link '-entry' directive
+#
+NLM_ENTRY_SYM	=
+
+#
+# If this is specified it will be used by the link '-exit' directive
+#
+NLM_EXIT_SYM	=
+
+#
+# If this is specified it will be used by the link '-check' directive
+#
+NLM_CHECK_SYM	=
+
+#
+# If these are specified it will be used by the link '-flags' directive
+#
+NLM_FLAGS		=
+
+#
+# If this is specified it will be linked in with the XDCData option in the def 
+# file instead of the default of $(NWOS)/apache.xdc.  XDCData can be disabled
+# by setting APACHE_UNIPROC in the environment
+#
+XDCDATA         = 
+
+#
+# If there is an NLM target, put it here
+#
+TARGET_nlm = \
+	$(OBJDIR)/proxy.nlm \
+	$(OBJDIR)/proxycon.nlm \
+	$(OBJDIR)/proxyftp.nlm \
+	$(OBJDIR)/proxyhtp.nlm \
+	$(EOLIST)
+
+#
+# If there is an LIB target, put it here
+#
+TARGET_lib = \
+	$(EOLIST)
+
+#
+# These are the OBJ files needed to create the NLM target above.
+# Paths must all use the '/' character
+#
+FILES_nlm_objs = \
+	$(EOLIST)
+
+#
+# These are the LIB files needed to create the NLM target above.
+# These will be added as a library command in the link.opt file.
+#
+FILES_nlm_libs = \
+	$(EOLIST)
+
+#
+# These are the modules that the above NLM target depends on to load.
+# These will be added as a module command in the link.opt file.
+#
+FILES_nlm_modules = \
+	$(EOLIST)
+
+#
+# If the nlm has a msg file, put it's path here
+#
+FILE_nlm_msg =
+ 
+#
+# If the nlm has a hlp file put it's path here
+#
+FILE_nlm_hlp =
+
+#
+# If this is specified, it will override $(NWOS)\copyright.txt.
+#
+FILE_nlm_copyright =
+
+#
+# Any additional imports go here
+#
+FILES_nlm_Ximports = \
+	$(EOLIST)
+ 
+#   
+# Any symbols exported to here
+#
+FILES_nlm_exports = \
+	$(EOLIST)
+	
+#   
+# These are the OBJ files needed to create the LIB target above.
+# Paths must all use the '/' character
+#
+FILES_lib_objs = \
+		$(EOLIST)
+
+#
+# implement targets and dependancies (leave this section alone)
+#
+
+libs :: $(OBJDIR) $(TARGET_lib)
+
+nlms :: libs $(TARGET_nlm)
+
+#
+# Updated this target to create necessary directories and copy files to the 
+# correct place.  (See $(AP_WORK)\build\NWGNUhead.inc for examples)
+#
+install :: nlms FORCE
+	copy $(OBJDIR)\*.nlm $(INSTALL)\Apache2\modules\*.*
+
+#
+# Any specialized rules here
+#
+
+#
+# Include the 'tail' makefile that has targets that depend on variables defined
+# in this makefile
+#
+
+include $(AP_WORK)\build\NWGNUtail.inc
+	

Added: branches/tomcat5.5/upstream/5.5.20/connectors/ajp/proxy/NWGNUproxy
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/ajp/proxy/NWGNUproxy	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/ajp/proxy/NWGNUproxy	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,262 @@
+#
+# Make sure all needed macro's are defined
+#
+
+#
+# Get the 'head' of the build environment if necessary.  This includes default
+# targets and paths to tools
+#
+
+ifndef EnvironmentDefined
+include $(AP_WORK)\build\NWGNUhead.inc
+endif
+
+#
+# These directories will be at the beginning of the include list, followed by
+# INCDIRS
+#
+XINCDIRS	+= \
+			$(AP_WORK)/include \
+			$(NWOS) \
+			$(AP_WORK)/modules/http \
+			$(AP_WORK)/modules/arch/netware \
+			$(AP_WORK)/modules/ssl \
+			$(AP_WORK)/srclib/apr/include \
+			$(AP_WORK)/srclib/apr-util/include \
+			$(AP_WORK)/srclib/apr \
+			$(EOLIST)
+
+#
+# These flags will come after CFLAGS
+#
+XCFLAGS		+= \
+			-prefix pre_nw.h \
+			$(EOLIST)
+
+#
+# These defines will come after DEFINES
+#
+XDEFINES	+= \
+			$(EOLIST)
+
+#
+# These flags will be added to the link.opt file
+#
+XLFLAGS		+= \
+			$(EOLIST)
+
+#
+# These values will be appended to the correct variables based on the value of
+# RELEASE
+#
+ifeq "$(RELEASE)" "debug"
+XINCDIRS	+= \
+			$(EOLIST)
+
+XCFLAGS		+= \
+			$(EOLIST)
+
+XDEFINES	+= \
+			$(EOLIST)
+
+XLFLAGS		+= \
+		   	$(EOLIST)
+endif
+
+ifeq "$(RELEASE)" "noopt"
+XINCDIRS	+= \
+			$(EOLIST)
+
+XCFLAGS		+= \
+			$(EOLIST)
+
+XDEFINES	+= \
+			$(EOLIST)
+
+XLFLAGS		+= \
+		   	$(EOLIST)
+endif
+
+ifeq "$(RELEASE)" "release"
+XINCDIRS	+= \
+			$(EOLIST)
+
+XCFLAGS		+= \
+			$(EOLIST)
+
+XDEFINES	+= \
+			$(EOLIST)
+
+XLFLAGS		+= \
+			$(EOLIST)
+endif
+
+#
+# These are used by the link target if an NLM is being generated
+# This is used by the link 'name' directive to name the nlm.  If left blank
+# TARGET_nlm (see below) will be used.
+#
+NLM_NAME		= proxy
+
+#
+# This is used by the link '-desc ' directive. 
+# If left blank, NLM_NAME will be used.
+#
+NLM_DESCRIPTION	= Apache $(VERSION_STR) Proxy Module
+
+#
+# This is used by the '-threadname' directive.  If left blank,
+# NLM_NAME Thread will be used.
+#
+NLM_THREAD_NAME	= Proxy Module
+
+#
+# If this is specified, it will override VERSION value in 
+# $(AP_WORK)\build\NWGNUenvironment.inc
+#
+NLM_VERSION		=
+
+#
+# If this is specified, it will override the default of 64K
+#
+NLM_STACK_SIZE	= 8192
+
+
+#
+# If this is specified it will be used by the link '-entry' directive
+#
+NLM_ENTRY_SYM	= _LibCPrelude
+
+#
+# If this is specified it will be used by the link '-exit' directive
+#
+NLM_EXIT_SYM	= _LibCPostlude
+
+#
+# If this is specified it will be used by the link '-check' directive
+#
+NLM_CHECK_SYM	=
+
+#
+# If these are specified it will be used by the link '-flags' directive
+#
+NLM_FLAGS		=  AUTOUNLOAD, PSEUDOPREEMPTION
+
+#
+# If this is specified it will be linked in with the XDCData option in the def 
+# file instead of the default of $(NWOS)/apache.xdc.  XDCData can be disabled
+# by setting APACHE_UNIPROC in the environment
+#
+XDCDATA         = 
+
+#
+# If there is an NLM target, put it here
+#
+TARGET_nlm = \
+	$(OBJDIR)/proxy.nlm \
+	$(EOLIST)
+
+#
+# If there is an LIB target, put it here
+#
+TARGET_lib = \
+	$(EOLIST)
+
+#
+# These are the OBJ files needed to create the NLM target above.
+# Paths must all use the '/' character
+#
+FILES_nlm_objs = \
+	$(OBJDIR)/mod_proxy.o \
+	$(OBJDIR)/proxy_util.o \
+	$(OBJDIR)/libprews.o \
+	$(EOLIST)
+
+#
+# These are the LIB files needed to create the NLM target above.
+# These will be added as a library command in the link.opt file.
+#
+FILES_nlm_libs = \
+   	libcpre.o \
+	$(EOLIST)
+
+#
+# These are the modules that the above NLM target depends on to load.
+# These will be added as a module command in the link.opt file.
+#
+FILES_nlm_modules = \
+	aprlib \
+	libc \
+	$(EOLIST)
+
+#
+# If the nlm has a msg file, put it's path here
+#
+FILE_nlm_msg =
+ 
+#
+# If the nlm has a hlp file put it's path here
+#
+FILE_nlm_hlp =
+
+#
+# If this is specified, it will override $(NWOS)\copyright.txt.
+#
+FILE_nlm_copyright =
+
+#
+# Any additional imports go here
+#
+FILES_nlm_Ximports = \
+	@$(APR)/aprlib.imp \
+	@$(NWOS)/httpd.imp \
+	@libc.imp \
+	@ws2nlm.imp \
+	$(EOLIST)
+ 
+#   
+# Any symbols exported to here
+#
+FILES_nlm_exports = \
+	proxy_module \
+	proxy_hook_scheme_handler \
+	proxy_hook_canon_handler \
+	ap_proxy_ssl_enable \
+	ap_proxy_ssl_disable \
+	proxy_run_fixups \
+	$(EOLIST)
+	
+#   
+# These are the OBJ files needed to create the LIB target above.
+# Paths must all use the '/' character
+#
+FILES_lib_objs = \
+		$(EOLIST)
+
+#
+# implement targets and dependancies (leave this section alone)
+#
+
+libs :: $(OBJDIR) $(TARGET_lib)
+
+nlms :: libs $(TARGET_nlm)
+
+#
+# Updated this target to create necessary directories and copy files to the 
+# correct place.  (See $(AP_WORK)\build\NWGNUhead.inc for examples)
+#
+install :: nlms FORCE
+
+#
+# Any specialized rules here
+#
+
+vpath %.c ../arch/netware
+
+#
+# Include the 'tail' makefile that has targets that depend on variables defined
+# in this makefile
+#
+
+include $(AP_WORK)\build\NWGNUtail.inc
+

Added: branches/tomcat5.5/upstream/5.5.20/connectors/ajp/proxy/NWGNUproxycon
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/ajp/proxy/NWGNUproxycon	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/ajp/proxy/NWGNUproxycon	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,256 @@
+#
+# Make sure all needed macro's are defined
+#
+
+#
+# Get the 'head' of the build environment if necessary.  This includes default
+# targets and paths to tools
+#
+
+ifndef EnvironmentDefined
+include $(AP_WORK)\build\NWGNUhead.inc
+endif
+
+#
+# These directories will be at the beginning of the include list, followed by
+# INCDIRS
+#
+XINCDIRS	+= \
+			$(AP_WORK)/include \
+			$(NWOS) \
+			$(AP_WORK)/modules/http \
+			$(AP_WORK)/modules/arch/netware \
+			$(AP_WORK)/srclib/apr/include \
+			$(AP_WORK)/srclib/apr-util/include \
+			$(AP_WORK)/srclib/apr \
+			$(EOLIST)
+
+#
+# These flags will come after CFLAGS
+#
+XCFLAGS		+= \
+			-prefix pre_nw.h \
+			$(EOLIST)
+
+#
+# These defines will come after DEFINES
+#
+XDEFINES	+= \
+			$(EOLIST)
+
+#
+# These flags will be added to the link.opt file
+#
+XLFLAGS		+= \
+			$(EOLIST)
+
+#
+# These values will be appended to the correct variables based on the value of
+# RELEASE
+#
+ifeq "$(RELEASE)" "debug"
+XINCDIRS	+= \
+			$(EOLIST)
+
+XCFLAGS		+= \
+			$(EOLIST)
+
+XDEFINES	+= \
+			$(EOLIST)
+
+XLFLAGS		+= \
+		   	$(EOLIST)
+endif
+
+ifeq "$(RELEASE)" "noopt"
+XINCDIRS	+= \
+			$(EOLIST)
+
+XCFLAGS		+= \
+			$(EOLIST)
+
+XDEFINES	+= \
+			$(EOLIST)
+
+XLFLAGS		+= \
+		   	$(EOLIST)
+endif
+
+ifeq "$(RELEASE)" "release"
+XINCDIRS	+= \
+			$(EOLIST)
+
+XCFLAGS		+= \
+			$(EOLIST)
+
+XDEFINES	+= \
+			$(EOLIST)
+
+XLFLAGS		+= \
+			$(EOLIST)
+endif
+
+#
+# These are used by the link target if an NLM is being generated
+# This is used by the link 'name' directive to name the nlm.  If left blank
+# TARGET_nlm (see below) will be used.
+#
+NLM_NAME		= proxycon
+
+#
+# This is used by the link '-desc ' directive. 
+# If left blank, NLM_NAME will be used.
+#
+NLM_DESCRIPTION	= Apache $(VERSION_STR) Proxy Connection Sub-Module
+
+#
+# This is used by the '-threadname' directive.  If left blank,
+# NLM_NAME Thread will be used.
+#
+NLM_THREAD_NAME	= Proxy Conn Module
+
+#
+# If this is specified, it will override VERSION value in 
+# $(AP_WORK)\build\NWGNUenvironment.inc
+#
+NLM_VERSION		=
+
+#
+# If this is specified, it will override the default of 64K
+#
+NLM_STACK_SIZE	= 8192
+
+
+#
+# If this is specified it will be used by the link '-entry' directive
+#
+NLM_ENTRY_SYM	= _LibCPrelude
+
+#
+# If this is specified it will be used by the link '-exit' directive
+#
+NLM_EXIT_SYM	= _LibCPostlude
+
+#
+# If this is specified it will be used by the link '-check' directive
+#
+NLM_CHECK_SYM	=
+
+#
+# If these are specified it will be used by the link '-flags' directive
+#
+NLM_FLAGS		=  AUTOUNLOAD, PSEUDOPREEMPTION
+
+#
+# If this is specified it will be linked in with the XDCData option in the def 
+# file instead of the default of $(NWOS)/apache.xdc.  XDCData can be disabled
+# by setting APACHE_UNIPROC in the environment
+#
+XDCDATA         = 
+
+#
+# If there is an NLM target, put it here
+#
+TARGET_nlm = \
+	$(OBJDIR)/proxycon.nlm \
+	$(EOLIST)
+
+#
+# If there is an LIB target, put it here
+#
+TARGET_lib = \
+	$(EOLIST)
+
+#
+# These are the OBJ files needed to create the NLM target above.
+# Paths must all use the '/' character
+#
+FILES_nlm_objs = \
+	$(OBJDIR)/proxy_connect.o \
+	$(OBJDIR)/proxy_util.o \
+	$(EOLIST)
+
+#
+# These are the LIB files needed to create the NLM target above.
+# These will be added as a library command in the link.opt file.
+#
+FILES_nlm_libs = \
+   	libcpre.o \
+	$(EOLIST)
+
+#
+# These are the modules that the above NLM target depends on to load.
+# These will be added as a module command in the link.opt file.
+#
+FILES_nlm_modules = \
+	aprlib \
+	libc \
+	proxy \
+	$(EOLIST)
+
+#
+# If the nlm has a msg file, put it's path here
+#
+FILE_nlm_msg =
+ 
+#
+# If the nlm has a hlp file put it's path here
+#
+FILE_nlm_hlp =
+
+#
+# If this is specified, it will override $(NWOS)\copyright.txt.
+#
+FILE_nlm_copyright =
+
+#
+# Any additional imports go here
+#
+FILES_nlm_Ximports = \
+	@$(APR)/aprlib.imp \
+	@$(NWOS)/httpd.imp \
+	@libc.imp \
+	proxy_module \
+	proxy_hook_scheme_handler \
+	proxy_hook_canon_handler \
+	$(EOLIST)
+ 
+#   
+# Any symbols exported to here
+#
+FILES_nlm_exports = \
+	proxy_connect_module \
+	$(EOLIST)
+	
+#   
+# These are the OBJ files needed to create the LIB target above.
+# Paths must all use the '/' character
+#
+FILES_lib_objs = \
+		$(EOLIST)
+
+#
+# implement targets and dependancies (leave this section alone)
+#
+
+libs :: $(OBJDIR) $(TARGET_lib)
+
+nlms :: libs $(TARGET_nlm)
+
+#
+# Updated this target to create necessary directories and copy files to the 
+# correct place.  (See $(AP_WORK)\build\NWGNUhead.inc for examples)
+#
+install :: nlms FORCE
+
+#
+# Any specialized rules here
+#
+
+#
+# Include the 'tail' makefile that has targets that depend on variables defined
+# in this makefile
+#
+
+include $(AP_WORK)\build\NWGNUtail.inc
+

Added: branches/tomcat5.5/upstream/5.5.20/connectors/ajp/proxy/NWGNUproxyftp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/ajp/proxy/NWGNUproxyftp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/ajp/proxy/NWGNUproxyftp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,260 @@
+#
+# Make sure all needed macro's are defined
+#
+
+#
+# Get the 'head' of the build environment if necessary.  This includes default
+# targets and paths to tools
+#
+
+ifndef EnvironmentDefined
+include $(AP_WORK)\build\NWGNUhead.inc
+endif
+
+#
+# These directories will be at the beginning of the include list, followed by
+# INCDIRS
+#
+XINCDIRS	+= \
+			$(AP_WORK)/include \
+			$(NWOS) \
+			$(AP_WORK)/modules/http \
+			$(AP_WORK)/modules/arch/netware \
+			$(AP_WORK)/srclib/apr/include \
+			$(AP_WORK)/srclib/apr-util/include \
+			$(AP_WORK)/srclib/apr \
+			$(EOLIST)
+
+#
+# These flags will come after CFLAGS
+#
+XCFLAGS		+= \
+			-prefix pre_nw.h \
+			$(EOLIST)
+
+#
+# These defines will come after DEFINES
+#
+XDEFINES	+= \
+			$(EOLIST)
+
+#
+# These flags will be added to the link.opt file
+#
+XLFLAGS		+= \
+			$(EOLIST)
+
+#
+# These values will be appended to the correct variables based on the value of
+# RELEASE
+#
+ifeq "$(RELEASE)" "debug"
+XINCDIRS	+= \
+			$(EOLIST)
+
+XCFLAGS		+= \
+			$(EOLIST)
+
+XDEFINES	+= \
+			$(EOLIST)
+
+XLFLAGS		+= \
+		   	$(EOLIST)
+endif
+
+ifeq "$(RELEASE)" "noopt"
+XINCDIRS	+= \
+			$(EOLIST)
+
+XCFLAGS		+= \
+			$(EOLIST)
+
+XDEFINES	+= \
+			$(EOLIST)
+
+XLFLAGS		+= \
+		   	$(EOLIST)
+endif
+
+ifeq "$(RELEASE)" "release"
+XINCDIRS	+= \
+			$(EOLIST)
+
+XCFLAGS		+= \
+			$(EOLIST)
+
+XDEFINES	+= \
+			$(EOLIST)
+
+XLFLAGS		+= \
+			$(EOLIST)
+endif
+
+#
+# These are used by the link target if an NLM is being generated
+# This is used by the link 'name' directive to name the nlm.  If left blank
+# TARGET_nlm (see below) will be used.
+#
+NLM_NAME		= proxyftp
+
+#
+# This is used by the link '-desc ' directive. 
+# If left blank, NLM_NAME will be used.
+#
+NLM_DESCRIPTION	= Apache $(VERSION_STR) Proxy FTP Sub-Module
+
+#
+# This is used by the '-threadname' directive.  If left blank,
+# NLM_NAME Thread will be used.
+#
+NLM_THREAD_NAME	= Proxy FTP Module
+
+#
+# If this is specified, it will override VERSION value in 
+# $(AP_WORK)\build\NWGNUenvironment.inc
+#
+NLM_VERSION		=
+
+#
+# If this is specified, it will override the default of 64K
+#
+NLM_STACK_SIZE	= 8192
+
+
+#
+# If this is specified it will be used by the link '-entry' directive
+#
+NLM_ENTRY_SYM	= _LibCPrelude
+
+#
+# If this is specified it will be used by the link '-exit' directive
+#
+NLM_EXIT_SYM	= _LibCPostlude
+
+#
+# If this is specified it will be used by the link '-check' directive
+#
+NLM_CHECK_SYM	=
+
+#
+# If these are specified it will be used by the link '-flags' directive
+#
+NLM_FLAGS		=  AUTOUNLOAD, PSEUDOPREEMPTION
+
+#
+# If this is specified it will be linked in with the XDCData option in the def 
+# file instead of the default of $(NWOS)/apache.xdc.  XDCData can be disabled
+# by setting APACHE_UNIPROC in the environment
+#
+XDCDATA         = 
+
+#
+# If there is an NLM target, put it here
+#
+TARGET_nlm = \
+	$(OBJDIR)/proxyftp.nlm \
+	$(EOLIST)
+
+#
+# If there is an LIB target, put it here
+#
+TARGET_lib = \
+	$(EOLIST)
+
+#
+# These are the OBJ files needed to create the NLM target above.
+# Paths must all use the '/' character
+#
+FILES_nlm_objs = \
+	$(OBJDIR)/proxy_ftp.o \
+	$(OBJDIR)/proxy_util.o \
+	$(OBJDIR)/libprews.o \
+	$(EOLIST)
+
+#
+# These are the LIB files needed to create the NLM target above.
+# These will be added as a library command in the link.opt file.
+#
+FILES_nlm_libs = \
+   	libcpre.o \
+	$(EOLIST)
+
+#
+# These are the modules that the above NLM target depends on to load.
+# These will be added as a module command in the link.opt file.
+#
+FILES_nlm_modules = \
+	aprlib \
+	libc \
+	proxy \
+	$(EOLIST)
+
+#
+# If the nlm has a msg file, put it's path here
+#
+FILE_nlm_msg =
+ 
+#
+# If the nlm has a hlp file put it's path here
+#
+FILE_nlm_hlp =
+
+#
+# If this is specified, it will override $(NWOS)\copyright.txt.
+#
+FILE_nlm_copyright =
+
+#
+# Any additional imports go here
+#
+FILES_nlm_Ximports = \
+	@$(APR)/aprlib.imp \
+	@$(NWOS)/httpd.imp \
+	@libc.imp \
+	@ws2nlm.imp \
+	proxy_module \
+	proxy_hook_scheme_handler \
+	proxy_hook_canon_handler \
+	$(EOLIST)
+ 
+#   
+# Any symbols exported to here
+#
+FILES_nlm_exports = \
+	proxy_ftp_module \
+	$(EOLIST)
+	
+#   
+# These are the OBJ files needed to create the LIB target above.
+# Paths must all use the '/' character
+#
+FILES_lib_objs = \
+		$(EOLIST)
+
+#
+# implement targets and dependancies (leave this section alone)
+#
+
+libs :: $(OBJDIR) $(TARGET_lib)
+
+nlms :: libs $(TARGET_nlm)
+
+#
+# Updated this target to create necessary directories and copy files to the 
+# correct place.  (See $(AP_WORK)\build\NWGNUhead.inc for examples)
+#
+install :: nlms FORCE
+
+#
+# Any specialized rules here
+#
+
+vpath %.c ../arch/netware
+
+#
+# Include the 'tail' makefile that has targets that depend on variables defined
+# in this makefile
+#
+
+include $(AP_WORK)\build\NWGNUtail.inc
+

Added: branches/tomcat5.5/upstream/5.5.20/connectors/ajp/proxy/NWGNUproxyhtp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/ajp/proxy/NWGNUproxyhtp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/ajp/proxy/NWGNUproxyhtp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,263 @@
+#
+# Make sure all needed macro's are defined
+#
+
+#
+# Get the 'head' of the build environment if necessary.  This includes default
+# targets and paths to tools
+#
+
+ifndef EnvironmentDefined
+include $(AP_WORK)\build\NWGNUhead.inc
+endif
+
+#
+# These directories will be at the beginning of the include list, followed by
+# INCDIRS
+#
+XINCDIRS	+= \
+			$(AP_WORK)/include \
+			$(NWOS) \
+			$(AP_WORK)/modules/http \
+			$(AP_WORK)/modules/arch/netware \
+			$(AP_WORK)/srclib/apr/include \
+			$(AP_WORK)/srclib/apr-util/include \
+			$(AP_WORK)/srclib/apr \
+			$(EOLIST)
+
+#
+# These flags will come after CFLAGS
+#
+XCFLAGS		+= \
+			-prefix pre_nw.h \
+			$(EOLIST)
+
+#
+# These defines will come after DEFINES
+#
+XDEFINES	+= \
+			$(EOLIST)
+
+#
+# These flags will be added to the link.opt file
+#
+XLFLAGS		+= \
+			$(EOLIST)
+
+#
+# These values will be appended to the correct variables based on the value of
+# RELEASE
+#
+ifeq "$(RELEASE)" "debug"
+XINCDIRS	+= \
+			$(EOLIST)
+
+XCFLAGS		+= \
+			$(EOLIST)
+
+XDEFINES	+= \
+			$(EOLIST)
+
+XLFLAGS		+= \
+		   	$(EOLIST)
+endif
+
+ifeq "$(RELEASE)" "noopt"
+XINCDIRS	+= \
+			$(EOLIST)
+
+XCFLAGS		+= \
+			$(EOLIST)
+
+XDEFINES	+= \
+			$(EOLIST)
+
+XLFLAGS		+= \
+		   	$(EOLIST)
+endif
+
+ifeq "$(RELEASE)" "release"
+XINCDIRS	+= \
+			$(EOLIST)
+
+XCFLAGS		+= \
+			$(EOLIST)
+
+XDEFINES	+= \
+			$(EOLIST)
+
+XLFLAGS		+= \
+			$(EOLIST)
+endif
+
+#
+# These are used by the link target if an NLM is being generated
+# This is used by the link 'name' directive to name the nlm.  If left blank
+# TARGET_nlm (see below) will be used.
+#
+NLM_NAME		= proxyhtp
+
+#
+# This is used by the link '-desc ' directive. 
+# If left blank, NLM_NAME will be used.
+#
+NLM_DESCRIPTION	= Apache $(VERSION_STR) Proxy HTTP Sub-Module
+
+#
+# This is used by the '-threadname' directive.  If left blank,
+# NLM_NAME Thread will be used.
+#
+NLM_THREAD_NAME	= Proxy HTTP Module
+
+#
+# If this is specified, it will override VERSION value in 
+# $(AP_WORK)\build\NWGNUenvironment.inc
+#
+NLM_VERSION		=
+
+#
+# If this is specified, it will override the default of 64K
+#
+NLM_STACK_SIZE	= 8192
+
+
+#
+# If this is specified it will be used by the link '-entry' directive
+#
+NLM_ENTRY_SYM	= _LibCPrelude
+
+#
+# If this is specified it will be used by the link '-exit' directive
+#
+NLM_EXIT_SYM	= _LibCPostlude
+
+#
+# If this is specified it will be used by the link '-check' directive
+#
+NLM_CHECK_SYM	=
+
+#
+# If these are specified it will be used by the link '-flags' directive
+#
+NLM_FLAGS		=  AUTOUNLOAD, PSEUDOPREEMPTION
+
+#
+# If this is specified it will be linked in with the XDCData option in the def 
+# file instead of the default of $(NWOS)/apache.xdc.  XDCData can be disabled
+# by setting APACHE_UNIPROC in the environment
+#
+XDCDATA         = 
+
+#
+# If there is an NLM target, put it here
+#
+TARGET_nlm = \
+	$(OBJDIR)/proxyhtp.nlm \
+	$(EOLIST)
+
+#
+# If there is an LIB target, put it here
+#
+TARGET_lib = \
+	$(EOLIST)
+
+#
+# These are the OBJ files needed to create the NLM target above.
+# Paths must all use the '/' character
+#
+FILES_nlm_objs = \
+	$(OBJDIR)/proxy_http.o \
+	$(OBJDIR)/proxy_util.o \
+	$(OBJDIR)/libprews.o \
+	$(EOLIST)
+
+#
+# These are the LIB files needed to create the NLM target above.
+# These will be added as a library command in the link.opt file.
+#
+FILES_nlm_libs = \
+   	libcpre.o \
+	$(EOLIST)
+
+#
+# These are the modules that the above NLM target depends on to load.
+# These will be added as a module command in the link.opt file.
+#
+FILES_nlm_modules = \
+	aprlib \
+	libc \
+	proxy \
+	$(EOLIST)
+
+#
+# If the nlm has a msg file, put it's path here
+#
+FILE_nlm_msg =
+ 
+#
+# If the nlm has a hlp file put it's path here
+#
+FILE_nlm_hlp =
+
+#
+# If this is specified, it will override $(NWOS)\copyright.txt.
+#
+FILE_nlm_copyright =
+
+#
+# Any additional imports go here
+#
+FILES_nlm_Ximports = \
+	@$(APR)/aprlib.imp \
+	@$(NWOS)/httpd.imp \
+	@libc.imp \
+	@ws2nlm.imp \
+	proxy_module \
+	proxy_hook_scheme_handler \
+	proxy_hook_canon_handler \
+	proxy_run_fixups \
+	ap_proxy_ssl_enable \
+	ap_proxy_ssl_disable \
+	$(EOLIST)
+ 
+#   
+# Any symbols exported to here
+#
+FILES_nlm_exports = \
+	proxy_http_module \
+	$(EOLIST)
+	
+#   
+# These are the OBJ files needed to create the LIB target above.
+# Paths must all use the '/' character
+#
+FILES_lib_objs = \
+		$(EOLIST)
+
+#
+# implement targets and dependancies (leave this section alone)
+#
+
+libs :: $(OBJDIR) $(TARGET_lib)
+
+nlms :: libs $(TARGET_nlm)
+
+#
+# Updated this target to create necessary directories and copy files to the 
+# correct place.  (See $(AP_WORK)\build\NWGNUhead.inc for examples)
+#
+install :: nlms FORCE
+
+#
+# Any specialized rules here
+#
+
+vpath %.c ../arch/netware
+
+#
+# Include the 'tail' makefile that has targets that depend on variables defined
+# in this makefile
+#
+
+include $(AP_WORK)\build\NWGNUtail.inc
+

Added: branches/tomcat5.5/upstream/5.5.20/connectors/ajp/proxy/config.m4
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/ajp/proxy/config.m4	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/ajp/proxy/config.m4	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,40 @@
+dnl modules enabled in this directory by default
+
+APACHE_MODPATH_INIT(proxy)
+
+if test "$enable_proxy" = "shared"; then
+  proxy_mods_enable=shared
+elif test "$enable_proxy" = "yes"; then
+  proxy_mods_enable=yes
+else
+  proxy_mods_enable=no
+fi
+
+proxy_objs="mod_proxy.lo proxy_util.lo"
+APACHE_MODULE(proxy, Apache proxy module, $proxy_objs, , $proxy_mods_enable)
+
+proxy_connect_objs="proxy_connect.lo"
+proxy_ftp_objs="proxy_ftp.lo"
+proxy_http_objs="proxy_http.lo"
+proxy_ajp_objs="proxy_ajp.lo ajp_header.lo ajp_link.lo ajp_msg.lo"
+proxy_balancer_objs="proxy_balancer.lo"
+
+case "$host" in
+  *os2*)
+    # OS/2 DLLs must resolve all symbols at build time and
+    # these sub-modules need some from the main proxy module
+    proxy_connect_objs="$proxy_connect_objs mod_proxy.la"
+    proxy_ftp_objs="$proxy_ftp_objs mod_proxy.la"
+    proxy_http_objs="$proxy_http_objs mod_proxy.la"
+    proxy_balancer_objs="$proxy_balancer_objs mod_proxy.la"
+    ;;
+esac
+
+APR_ADDTO(INCLUDES, [-I../generators])
+APACHE_MODULE(proxy_connect, Apache proxy CONNECT module, $proxy_connect_objs, , $proxy_mods_enable)
+APACHE_MODULE(proxy_ftp, Apache proxy FTP module, $proxy_ftp_objs, , $proxy_mods_enable)
+APACHE_MODULE(proxy_http, Apache proxy HTTP module, $proxy_http_objs, , $proxy_mods_enable)
+APACHE_MODULE(proxy_balancer, Apache proxy BALANCER module, $proxy_balancer_objs, , $proxy_mods_enable)
+APR_ADDTO(INCLUDES, [-I./ajp])
+APACHE_MODULE(proxy_ajp, Apache proxy AJP module, $proxy_ajp_objs, , $proxy_mods_enable)
+APACHE_MODPATH_FINISH

Added: branches/tomcat5.5/upstream/5.5.20/connectors/ajp/proxy/config.m4.patch
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/ajp/proxy/config.m4.patch	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/ajp/proxy/config.m4.patch	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,23 @@
+Index: config.m4
+===================================================================
+RCS file: /home/cvspublic/httpd-2.0/modules/proxy/config.m4,v
+retrieving revision 1.17
+diff -u -r1.17 config.m4
+--- config.m4	25 Apr 2002 03:16:44 -0000	1.17
++++ config.m4	1 Aug 2004 14:07:06 -0000
+@@ -16,6 +16,7 @@
+ proxy_connect_objs="proxy_connect.lo"
+ proxy_ftp_objs="proxy_ftp.lo"
+ proxy_http_objs="proxy_http.lo"
++proxy_ajp_objs="proxy_ajp.lo ajp_header.lo ajp_link.lo ajp_msg.lo"
+ 
+ case "$host" in
+   *os2*)
+@@ -30,5 +31,6 @@
+ APACHE_MODULE(proxy_connect, Apache proxy CONNECT module, $proxy_connect_objs, , $proxy_mods_enable)
+ APACHE_MODULE(proxy_ftp, Apache proxy FTP module, $proxy_ftp_objs, , $proxy_mods_enable)
+ APACHE_MODULE(proxy_http, Apache proxy HTTP module, $proxy_http_objs, , $proxy_mods_enable)
+-
++APR_ADDTO(INCLUDES, [-I./ajp])
++APACHE_MODULE(proxy_ajp, Apache proxy AJP module, $proxy_ajp_objs, , $proxy_mods_enable)
+ APACHE_MODPATH_FINISH

Added: branches/tomcat5.5/upstream/5.5.20/connectors/ajp/proxy/libproxy.exp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/ajp/proxy/libproxy.exp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/ajp/proxy/libproxy.exp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1 @@
+proxy_module

Added: branches/tomcat5.5/upstream/5.5.20/connectors/ajp/proxy/mod_proxy.c
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/ajp/proxy/mod_proxy.c	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/ajp/proxy/mod_proxy.c	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,1719 @@
+#define FIX_15207
+/* Copyright 1999-2004 The Apache Software Foundation
+ *
+ * Licensed 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.
+ */
+
+#define CORE_PRIVATE
+
+#include "mod_proxy.h"
+#include "mod_core.h"
+#include "apr_optional.h"
+#include "mod_status.h"
+
+#if (MODULE_MAGIC_NUMBER_MAJOR > 20020903)
+#include "mod_ssl.h"
+#else
+APR_DECLARE_OPTIONAL_FN(int, ssl_proxy_enable, (conn_rec *));
+APR_DECLARE_OPTIONAL_FN(int, ssl_engine_disable, (conn_rec *));
+#endif
+
+#ifndef MAX
+#define MAX(x,y) ((x) >= (y) ? (x) : (y))
+#endif
+
+/*
+ * A Web proxy module. Stages:
+ *
+ *  translate_name: set filename to proxy:<URL>
+ *  map_to_storage: run proxy_walk (rather than directory_walk/file_walk)
+ *                  can't trust directory_walk/file_walk since these are
+ *                  not in our filesystem.  Prevents mod_http from serving
+ *                  the TRACE request we will set aside to handle later.
+ *  type_checker:   set type to PROXY_MAGIC_TYPE if filename begins proxy:
+ *  fix_ups:        convert the URL stored in the filename to the
+ *                  canonical form.
+ *  handler:        handle proxy requests
+ */
+
+/* -------------------------------------------------------------- */
+/* Translate the URL into a 'filename' */
+
+#ifdef FIX_15207
+/* XXX: EBCDIC safe? --nd */
+#define x2c(x) (((x >= '0') && (x <= '9'))         \
+                   ? (x - '0')                     \
+                   : (((x >= 'a') && (x <= 'f'))   \
+                       ? (10 + x - 'a')            \
+                       : ((x >= 'A') && (x <='F')) \
+                           ? (10 + x - 'A')        \
+                           : 0                     \
+                     )                             \
+               )
+
+static unsigned char hex2c(const char* p) {
+  const char c1 = p[1];
+  const char c2 = p[1] ? p[2]: '\0';
+  int i1 = c1 ? x2c(c1) : 0;
+  int i2 = c2 ? x2c(c2) : 0;
+  unsigned char ret = (i1 << 4) | i2;
+
+  return ret;
+}
+#endif
+
+#define PROXY_COPY_CONF_PARAMS(w, c) \
+    do {                             \
+        (w)->timeout              = (c)->timeout;               \
+        (w)->timeout_set          = (c)->timeout_set;           \
+        (w)->recv_buffer_size     = (c)->recv_buffer_size;      \
+        (w)->recv_buffer_size_set = (c)->recv_buffer_size_set;  \
+        (w)->io_buffer_size       = (c)->io_buffer_size;        \
+        (w)->io_buffer_size_set   = (c)->io_buffer_size_set;    \
+    } while (0)
+
+static const char *set_worker_param(apr_pool_t *p,
+                                    proxy_worker *worker,
+                                    const char *key,
+                                    const char *val)
+{
+
+    int ival;
+    if (!strcasecmp(key, "loadfactor")) {
+        worker->lbfactor = atoi(val);
+        if (worker->lbfactor < 1 || worker->lbfactor > 100)
+            return "LoadFactor must be number between 1..100";
+    }
+    else if (!strcasecmp(key, "retry")) {
+        ival = atoi(val);
+        if (ival < 1)
+            return "Retry must be at least one second";
+        worker->retry = apr_time_from_sec(ival);
+    }
+    else if (!strcasecmp(key, "ttl")) {
+        ival = atoi(val);
+        if (ival < 1)
+            return "TTL must be at least one second";
+        worker->ttl = apr_time_from_sec(ival);
+    }
+    else if (!strcasecmp(key, "min")) {
+        ival = atoi(val);
+        if (ival < 0)
+            return "Min must be a positive number";
+        worker->min = ival;
+    }
+    else if (!strcasecmp(key, "max")) {
+        ival = atoi(val);
+        if (ival < 0)
+            return "Max must be a positive number";
+        worker->hmax = ival;
+    }
+    /* XXX: More inteligent naming needed */
+    else if (!strcasecmp(key, "smax")) {
+        ival = atoi(val);
+        if (ival < 0)
+            return "Smax must be a positive number";
+        worker->smax = ival;
+    }
+    else if (!strcasecmp(key, "acquire")) {
+        ival = atoi(val);
+        if (ival < 1)
+            return "Acquire must be at least one mili second";
+        worker->acquire = apr_time_make(0, ival * 1000);
+        worker->acquire_set = 1;
+    }
+    else if (!strcasecmp(key, "timeout")) {
+        ival = atoi(val);
+        if (ival < 1)
+            return "Timeout must be at least one second";
+        worker->timeout = apr_time_from_sec(ival);
+        worker->timeout_set = 1;
+    }
+    else if (!strcasecmp(key, "iobuffersize")) {
+        long s = atol(val);
+        worker->io_buffer_size = ((s > AP_IOBUFSIZE) ? s : AP_IOBUFSIZE);
+        worker->io_buffer_size_set = 1;
+    }
+    else if (!strcasecmp(key, "receivebuffersize")) {
+        ival = atoi(val);
+        if (ival < 512 && ival != 0) {
+            return "ReceiveBufferSize must be >= 512 bytes, or 0 for system default.";
+        }
+        worker->recv_buffer_size = ival;
+        worker->recv_buffer_size_set = 1;
+    }
+    else if (!strcasecmp(key, "keepalive")) {
+        if (!strcasecmp(val, "on"))
+            worker->keepalive = 1;
+        else if (!strcasecmp(val, "off"))
+            worker->keepalive = 0;
+        else
+            return "KeepAlive must be On|Off";
+        worker->keepalive_set = 1;
+    }    
+    else if (!strcasecmp(key, "route")) {
+        worker->route = apr_pstrdup(p, val);
+    }
+    else if (!strcasecmp(key, "redirect")) {
+        worker->redirect = apr_pstrdup(p, val);
+    }
+    else {
+        return "unknown parameter";
+    }
+    return NULL;
+}
+
+static const char *set_balancer_param(apr_pool_t *p,
+                                      proxy_balancer *balancer,
+                                      const char *key,
+                                      const char *val)
+{
+
+    int ival;
+    if (!strcasecmp(key, "stickysession")) {
+        balancer->sticky = apr_pstrdup(p, val);
+    }
+    else if (!strcasecmp(key, "nofailover")) {
+        if (!strcasecmp(val, "on"))
+            balancer->sticky_force = 1;
+        else if (!strcasecmp(val, "off"))
+            balancer->sticky_force = 0;
+        else
+            return "failover must be On|Off";
+    }
+    else if (!strcasecmp(key, "timeout")) {
+        ival = atoi(val);
+        if (ival < 1)
+            return "timeout must be at least one second";
+        balancer->timeout = apr_time_from_sec(ival);
+    }
+    else {
+        return "unknown parameter";
+    }
+    return NULL;
+}
+
+static int alias_match(const char *uri, const char *alias_fakename)
+{
+    const char *end_fakename = alias_fakename + strlen(alias_fakename);
+    const char *aliasp = alias_fakename, *urip = uri;
+    const char *end_uri = uri + strlen(uri);
+    unsigned char uric, aliasc;
+
+    while (aliasp < end_fakename && urip < end_uri) {
+        if (*aliasp == '/') {
+            /* any number of '/' in the alias matches any number in
+             * the supplied URI, but there must be at least one...
+             */
+            if (*urip != '/')
+                return 0;
+
+            while (*aliasp == '/')
+                ++aliasp;
+            while (*urip == '/')
+                ++urip;
+        }
+        else {
+#ifndef FIX_15207
+            /* Other characters are compared literally */
+            if (*urip++ != *aliasp++)
+                return 0;
+#else
+            /* Other characters are canonicalised and compared literally */
+            if (*urip == '%') {
+                uric = hex2c(urip);
+                urip += 3;
+            } else {
+                uric = (unsigned char)*urip++;
+            }
+            if (*aliasp == '%') {
+                aliasc = hex2c(aliasp);
+                aliasp += 3;
+            } else {
+                aliasc = (unsigned char)*aliasp++;
+            }
+            if (uric != aliasc) {
+                return 0;
+            }
+#endif
+        }
+    }
+
+    /* fixup badly encoded stuff (e.g. % as last character) */
+    if (aliasp > end_fakename) {
+        aliasp = end_fakename;
+    }
+    if (urip > end_uri) {
+        urip = end_uri;
+    }
+
+    /* Check last alias path component matched all the way */
+    if (aliasp[-1] != '/' && *urip != '\0' && *urip != '/')
+        return 0;
+
+    /* Return number of characters from URI which matched (may be
+     * greater than length of alias, since we may have matched
+     * doubled slashes)
+     */
+
+    return urip - uri;
+}
+
+/* Detect if an absoluteURI should be proxied or not.  Note that we
+ * have to do this during this phase because later phases are
+ * "short-circuiting"... i.e. translate_names will end when the first
+ * module returns OK.  So for example, if the request is something like:
+ *
+ * GET http://othervhost/cgi-bin/printenv HTTP/1.0
+ *
+ * mod_alias will notice the /cgi-bin part and ScriptAlias it and
+ * short-circuit the proxy... just because of the ordering in the
+ * configuration file.
+ */
+static int proxy_detect(request_rec *r)
+{
+    void *sconf = r->server->module_config;
+    proxy_server_conf *conf =
+        (proxy_server_conf *) ap_get_module_config(sconf, &proxy_module);
+#ifdef FIX_15207
+    int i, len;
+    struct proxy_alias *ent = (struct proxy_alias *)conf->aliases->elts;
+#endif
+
+    /* Ick... msvc (perhaps others) promotes ternary short results to int */
+
+    if (conf->req && r->parsed_uri.scheme) {
+        /* but it might be something vhosted */
+        if (!(r->parsed_uri.hostname
+              && !strcasecmp(r->parsed_uri.scheme, ap_http_method(r))
+              && ap_matches_request_vhost(r, r->parsed_uri.hostname,
+                                          (apr_port_t)(r->parsed_uri.port_str ? r->parsed_uri.port 
+                                                       : ap_default_port(r))))) {
+            r->proxyreq = PROXYREQ_PROXY;
+            r->uri = r->unparsed_uri;
+            r->filename = apr_pstrcat(r->pool, "proxy:", r->uri, NULL);
+            r->handler = "proxy-server";
+        }
+    }
+    /* We need special treatment for CONNECT proxying: it has no scheme part */
+    else if (conf->req && r->method_number == M_CONNECT
+             && r->parsed_uri.hostname
+             && r->parsed_uri.port_str) {
+        r->proxyreq = PROXYREQ_PROXY;
+        r->uri = r->unparsed_uri;
+        r->filename = apr_pstrcat(r->pool, "proxy:", r->uri, NULL);
+        r->handler = "proxy-server";
+#ifdef FIX_15207
+    } else {
+        /* test for a ProxyPass */
+        for (i = 0; i < conf->aliases->nelts; i++) {
+            len = alias_match(r->unparsed_uri, ent[i].fake);
+            if (len > 0) {
+                r->filename = apr_pstrcat(r->pool, "proxy:", ent[i].real,
+                                          r->unparsed_uri + len, NULL);
+                r->handler = "proxy-server";
+                r->proxyreq = PROXYREQ_REVERSE;
+                r->uri = r->unparsed_uri;
+                break;
+            }
+        }
+#endif
+    }
+    return DECLINED;
+}
+
+static int proxy_trans(request_rec *r)
+{
+#ifndef FIX_15207
+    void *sconf = r->server->module_config;
+    proxy_server_conf *conf =
+    (proxy_server_conf *) ap_get_module_config(sconf, &proxy_module);
+    int i, len;
+    struct proxy_alias *ent = (struct proxy_alias *) conf->aliases->elts;
+#endif
+
+    if (r->proxyreq) {
+        /* someone has already set up the proxy, it was possibly ourselves
+         * in proxy_detect
+         */
+        return OK;
+    }
+
+#ifndef FIX_15207
+    /* XXX: since r->uri has been manipulated already we're not really
+     * compliant with RFC1945 at this point.  But this probably isn't
+     * an issue because this is a hybrid proxy/origin server.
+     */
+
+    for (i = 0; i < conf->aliases->nelts; i++) {
+        len = alias_match(r->uri, ent[i].fake);
+
+       if (len > 0) {
+           if ((ent[i].real[0] == '!') && (ent[i].real[1] == 0)) {
+               return DECLINED;
+           }
+
+           r->filename = apr_pstrcat(r->pool, "proxy:", ent[i].real,
+                                     r->uri + len, NULL);
+           r->handler = "proxy-server";
+           r->proxyreq = PROXYREQ_REVERSE;
+           return OK;
+       }
+    }
+#endif
+    return DECLINED;
+}
+
+static int proxy_walk(request_rec *r)
+{
+    proxy_server_conf *sconf = ap_get_module_config(r->server->module_config,
+                                                    &proxy_module);
+    ap_conf_vector_t *per_dir_defaults = r->server->lookup_defaults;
+    ap_conf_vector_t **sec_proxy = (ap_conf_vector_t **) sconf->sec_proxy->elts;
+    ap_conf_vector_t *entry_config;
+    proxy_dir_conf *entry_proxy;
+    int num_sec = sconf->sec_proxy->nelts;
+    /* XXX: shouldn't we use URI here?  Canonicalize it first?
+     * Pass over "proxy:" prefix 
+     */
+    const char *proxyname = r->filename + 6;
+    int j;
+
+    for (j = 0; j < num_sec; ++j) 
+    {
+        entry_config = sec_proxy[j];
+        entry_proxy = ap_get_module_config(entry_config, &proxy_module);
+
+        /* XXX: What about case insensitive matching ???
+         * Compare regex, fnmatch or string as appropriate
+         * If the entry doesn't relate, then continue 
+         */
+        if (entry_proxy->r 
+              ? ap_regexec(entry_proxy->r, proxyname, 0, NULL, 0)
+              : (entry_proxy->p_is_fnmatch
+                   ? apr_fnmatch(entry_proxy->p, proxyname, 0)
+                   : strncmp(proxyname, entry_proxy->p, 
+                                        strlen(entry_proxy->p)))) {
+            continue;
+        }
+        per_dir_defaults = ap_merge_per_dir_configs(r->pool, per_dir_defaults,
+                                                             entry_config);
+    }
+
+    r->per_dir_config = per_dir_defaults;
+
+    return OK;
+}
+
+static int proxy_map_location(request_rec *r)
+{
+    int access_status;
+
+    if (!r->proxyreq || !r->filename || strncmp(r->filename, "proxy:", 6) != 0)
+        return DECLINED;
+
+    /* Don't let the core or mod_http map_to_storage hooks handle this,
+     * We don't need directory/file_walk, and we want to TRACE on our own.
+     */
+    if ((access_status = proxy_walk(r))) {
+        ap_die(access_status, r);
+        return access_status;
+    }
+
+    return OK;
+}
+#ifndef FIX_15207
+/* -------------------------------------------------------------- */
+/* Fixup the filename */
+
+/*
+ * Canonicalise the URL
+ */
+static int proxy_fixup(request_rec *r)
+{
+    char *url, *p;
+    int access_status;
+
+    if (!r->proxyreq || !r->filename || strncmp(r->filename, "proxy:", 6) != 0)
+        return DECLINED;
+
+#ifdef FIX_15207
+/* We definitely shouldn't canonicalize a proxy_pass.
+ * But should we really canonicalize a STD_PROXY??? -- Fahree
+ */
+    if (r->proxyreq == PROXYREQ_REVERSE) {
+        return OK;
+    }
+#endif
+
+    /* XXX: Shouldn't we try this before we run the proxy_walk? */
+    url = &r->filename[6];
+
+    /* canonicalise each specific scheme */
+    if ((access_status = proxy_run_canon_handler(r, url))) {
+        return access_status;
+    }
+
+    p = strchr(url, ':');
+    if (p == NULL || p == url)
+        return HTTP_BAD_REQUEST;
+
+    return OK;		/* otherwise; we've done the best we can */
+}
+#endif
+/* Send a redirection if the request contains a hostname which is not */
+/* fully qualified, i.e. doesn't have a domain name appended. Some proxy */
+/* servers like Netscape's allow this and access hosts from the local */
+/* domain in this case. I think it is better to redirect to a FQDN, since */
+/* these will later be found in the bookmarks files. */
+/* The "ProxyDomain" directive determines what domain will be appended */
+static int proxy_needsdomain(request_rec *r, const char *url, const char *domain)
+{
+    char *nuri;
+    const char *ref;
+
+    /* We only want to worry about GETs */
+    if (!r->proxyreq || r->method_number != M_GET || !r->parsed_uri.hostname)
+        return DECLINED;
+
+    /* If host does contain a dot already, or it is "localhost", decline */
+    if (strchr(r->parsed_uri.hostname, '.') != NULL
+     || strcasecmp(r->parsed_uri.hostname, "localhost") == 0)
+        return DECLINED;	/* host name has a dot already */
+
+    ref = apr_table_get(r->headers_in, "Referer");
+
+    /* Reassemble the request, but insert the domain after the host name */
+    /* Note that the domain name always starts with a dot */
+    r->parsed_uri.hostname = apr_pstrcat(r->pool, r->parsed_uri.hostname,
+                                         domain, NULL);
+    nuri = apr_uri_unparse(r->pool,
+                           &r->parsed_uri,
+                           APR_URI_UNP_REVEALPASSWORD);
+
+    apr_table_set(r->headers_out, "Location", nuri);
+    ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
+                  "Domain missing: %s sent to %s%s%s", r->uri,
+                  apr_uri_unparse(r->pool, &r->parsed_uri,
+                                  APR_URI_UNP_OMITUSERINFO),
+                  ref ? " from " : "", ref ? ref : "");
+
+    return HTTP_MOVED_PERMANENTLY;
+}
+
+/* -------------------------------------------------------------- */
+/* Invoke handler */
+
+static int proxy_handler(request_rec *r)
+{
+    char *url, *scheme, *p;
+    const char *p2;
+    void *sconf = r->server->module_config;
+    proxy_server_conf *conf = (proxy_server_conf *)
+        ap_get_module_config(sconf, &proxy_module);
+    apr_array_header_t *proxies = conf->proxies;
+    struct proxy_remote *ents = (struct proxy_remote *) proxies->elts;
+    int i, rc, access_status;
+    int direct_connect = 0;
+    const char *str;
+    long maxfwd;
+    proxy_balancer *balancer = NULL;
+    proxy_worker *worker = NULL;
+
+    /* is this for us? */
+    if (!r->proxyreq || !r->filename || strncmp(r->filename, "proxy:", 6) != 0)
+        return DECLINED;
+
+    /* handle max-forwards / OPTIONS / TRACE */
+    if ((str = apr_table_get(r->headers_in, "Max-Forwards"))) {
+        maxfwd = strtol(str, NULL, 10);
+        if (maxfwd < 1) {
+            switch (r->method_number) {
+            case M_TRACE: {
+                int access_status;
+                r->proxyreq = PROXYREQ_NONE;
+                if ((access_status = ap_send_http_trace(r)))
+                    ap_die(access_status, r);
+                else
+                    ap_finalize_request_protocol(r);
+                return OK;
+            }
+            case M_OPTIONS: {
+                int access_status;
+                r->proxyreq = PROXYREQ_NONE;
+                if ((access_status = ap_send_http_options(r)))
+                    ap_die(access_status, r);
+                else
+                    ap_finalize_request_protocol(r);
+                return OK;
+            }
+            default: {
+                return ap_proxyerror(r, HTTP_BAD_GATEWAY,
+                                     "Max-Forwards has reached zero - proxy loop?");
+            }
+            }
+        }
+        maxfwd = (maxfwd > 0) ? maxfwd - 1 : 0;
+    }
+    else {
+        /* set configured max-forwards */
+        maxfwd = conf->maxfwd;
+    }
+    apr_table_set(r->headers_in, "Max-Forwards", 
+                  apr_psprintf(r->pool, "%ld", (maxfwd > 0) ? maxfwd : 0));
+
+    url = r->filename + 6;
+    p = strchr(url, ':');
+    if (p == NULL) {
+        ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
+                      "proxy_handler no URL in %s", r->filename);
+        return HTTP_BAD_REQUEST;
+    }
+
+    /* If the host doesn't have a domain name, add one and redirect. */
+    if (conf->domain != NULL) {
+        rc = proxy_needsdomain(r, url, conf->domain);
+        if (ap_is_HTTP_REDIRECT(rc))
+            return HTTP_MOVED_PERMANENTLY;
+    }
+
+    *p = '\0';
+    scheme = apr_pstrdup(r->pool, url);
+    *p = ':';
+
+    /* Check URI's destination host against NoProxy hosts */
+    /* Bypass ProxyRemote server lookup if configured as NoProxy */
+    /* we only know how to handle communication to a proxy via http */
+    /*if (strcasecmp(scheme, "http") == 0) */
+    {
+        int ii;
+        struct dirconn_entry *list = (struct dirconn_entry *) conf->dirconn->elts;
+
+        for (direct_connect = ii = 0; ii < conf->dirconn->nelts && !direct_connect; ii++) {
+            direct_connect = list[ii].matcher(&list[ii], r);
+        }
+#if DEBUGGING
+        ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
+                      (direct_connect) ? "NoProxy for %s" : "UseProxy for %s",
+                      r->uri);
+#endif
+    }
+    
+    /* Try to obtain the most suitable worker */
+    access_status = ap_proxy_pre_request(&worker, &balancer, r, conf, &url);
+    if (access_status != OK)
+        return access_status;
+    
+    /* firstly, try a proxy, unless a NoProxy directive is active */
+    if (!direct_connect) {
+        for (i = 0; i < proxies->nelts; i++) {
+            p2 = ap_strchr_c(ents[i].scheme, ':');  /* is it a partial URL? */
+            if (strcmp(ents[i].scheme, "*") == 0 ||
+                (ents[i].use_regex && ap_regexec(ents[i].regexp, url, 0,NULL, 0)) ||
+                (p2 == NULL && strcasecmp(scheme, ents[i].scheme) == 0) ||
+                (p2 != NULL &&
+                 strncasecmp(url, ents[i].scheme, strlen(ents[i].scheme)) == 0)) {
+
+                /* handle the scheme */
+                ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+                             "Trying to run scheme_handler against proxy");
+                access_status = proxy_run_scheme_handler(r, worker, conf, url, ents[i].hostname, ents[i].port);
+
+                /* an error or success */
+                if (access_status != DECLINED && access_status != HTTP_BAD_GATEWAY) {
+                    goto cleanup;
+                }
+                /* we failed to talk to the upstream proxy */
+            }
+        }
+    }
+
+    /* otherwise, try it direct */
+    /* N.B. what if we're behind a firewall, where we must use a proxy or
+     * give up??
+     */
+
+    /* handle the scheme */
+    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+                 "Trying to run scheme_handler");
+    access_status = proxy_run_scheme_handler(r, worker, conf, url, NULL, 0);
+    if (DECLINED == access_status) {
+        ap_log_error(APLOG_MARK, APLOG_WARNING, 0, r->server,
+                    "proxy: No protocol handler was valid for the URL %s. "
+                    "If you are using a DSO version of mod_proxy, make sure "
+                    "the proxy submodules are included in the configuration "
+                    "using LoadModule.", r->uri);
+        access_status = HTTP_FORBIDDEN;
+        goto cleanup;
+    }
+
+cleanup:
+    if (balancer) {
+        int post_status = proxy_run_post_request(worker, balancer, r, conf);
+        if (post_status == DECLINED) {
+            post_status = OK; /* no post_request handler available */
+            /* TODO: reclycle direct worker */
+        }
+    }
+    return access_status;
+}
+
+/* -------------------------------------------------------------- */
+/* Setup configurable data */
+
+static void * create_proxy_config(apr_pool_t *p, server_rec *s)
+{
+    proxy_server_conf *ps = apr_pcalloc(p, sizeof(proxy_server_conf));
+
+    ps->sec_proxy = apr_array_make(p, 10, sizeof(ap_conf_vector_t *));
+    ps->proxies = apr_array_make(p, 10, sizeof(struct proxy_remote));
+    ps->aliases = apr_array_make(p, 10, sizeof(struct proxy_alias));
+    ps->raliases = apr_array_make(p, 10, sizeof(struct proxy_alias));
+    ps->cookie_paths = apr_array_make(p, 10, sizeof(struct proxy_alias));
+    ps->cookie_domains = apr_array_make(p, 10, sizeof(struct proxy_alias));
+    ps->cookie_path_str = apr_strmatch_precompile(p, "path=", 0);
+    ps->cookie_domain_str = apr_strmatch_precompile(p, "domain=", 0);
+    ps->noproxies = apr_array_make(p, 10, sizeof(struct noproxy_entry));
+    ps->dirconn = apr_array_make(p, 10, sizeof(struct dirconn_entry));
+    ps->allowed_connect_ports = apr_array_make(p, 10, sizeof(int));
+    ps->workers = apr_array_make(p, 10, sizeof(proxy_worker));
+    ps->balancers = apr_array_make(p, 10, sizeof(proxy_balancer));
+    ps->domain = NULL;
+    ps->viaopt = via_off; /* initially backward compatible with 1.3.1 */
+    ps->viaopt_set = 0; /* 0 means default */
+    ps->req = 0;
+    ps->req_set = 0;
+    ps->recv_buffer_size = 0; /* this default was left unset for some reason */
+    ps->recv_buffer_size_set = 0;
+    ps->io_buffer_size = AP_IOBUFSIZE;
+    ps->io_buffer_size_set = 0;
+    ps->maxfwd = DEFAULT_MAX_FORWARDS;
+    ps->maxfwd_set = 0;
+    ps->error_override = 0; 
+    ps->error_override_set = 0; 
+    ps->preserve_host_set = 0;
+    ps->preserve_host = 0;    
+    ps->timeout = 0;
+    ps->timeout_set = 0;
+    ps->badopt = bad_error;
+    ps->badopt_set = 0;
+    return ps;
+}
+
+static void * merge_proxy_config(apr_pool_t *p, void *basev, void *overridesv)
+{
+    proxy_server_conf *ps = apr_pcalloc(p, sizeof(proxy_server_conf));
+    proxy_server_conf *base = (proxy_server_conf *) basev;
+    proxy_server_conf *overrides = (proxy_server_conf *) overridesv;
+
+    ps->proxies = apr_array_append(p, base->proxies, overrides->proxies);
+    ps->sec_proxy = apr_array_append(p, base->sec_proxy, overrides->sec_proxy);
+    ps->aliases = apr_array_append(p, base->aliases, overrides->aliases);
+    ps->raliases = apr_array_append(p, base->raliases, overrides->raliases);
+    ps->cookie_paths
+        = apr_array_append(p, base->cookie_paths, overrides->cookie_paths);
+    ps->cookie_domains
+        = apr_array_append(p, base->cookie_domains, overrides->cookie_domains);
+    ps->cookie_path_str = base->cookie_path_str;
+    ps->cookie_domain_str = base->cookie_domain_str;
+    ps->noproxies = apr_array_append(p, base->noproxies, overrides->noproxies);
+    ps->dirconn = apr_array_append(p, base->dirconn, overrides->dirconn);
+    ps->allowed_connect_ports = apr_array_append(p, base->allowed_connect_ports, overrides->allowed_connect_ports);
+    ps->workers = apr_array_append(p, base->workers, overrides->workers);
+    ps->balancers = apr_array_append(p, base->balancers, overrides->balancers);
+
+    ps->domain = (overrides->domain == NULL) ? base->domain : overrides->domain;
+    ps->viaopt = (overrides->viaopt_set == 0) ? base->viaopt : overrides->viaopt;
+    ps->req = (overrides->req_set == 0) ? base->req : overrides->req;
+    ps->recv_buffer_size = (overrides->recv_buffer_size_set == 0) ? base->recv_buffer_size : overrides->recv_buffer_size;
+    ps->io_buffer_size = (overrides->io_buffer_size_set == 0) ? base->io_buffer_size : overrides->io_buffer_size;
+    ps->maxfwd = (overrides->maxfwd_set == 0) ? base->maxfwd : overrides->maxfwd;
+    ps->error_override = (overrides->error_override_set == 0) ? base->error_override : overrides->error_override;
+    ps->preserve_host = (overrides->preserve_host_set == 0) ? base->preserve_host : overrides->preserve_host;
+    ps->timeout= (overrides->timeout_set == 0) ? base->timeout : overrides->timeout;
+    ps->badopt = (overrides->badopt_set == 0) ? base->badopt : overrides->badopt;
+
+    return ps;
+}
+
+static void *create_proxy_dir_config(apr_pool_t *p, char *dummy)
+{
+    proxy_dir_conf *new =
+        (proxy_dir_conf *) apr_pcalloc(p, sizeof(proxy_dir_conf));
+
+    /* Filled in by proxysection, when applicable */
+
+    return (void *) new;
+}
+
+static void *merge_proxy_dir_config(apr_pool_t *p, void *basev, void *addv)
+{
+    proxy_dir_conf *new = (proxy_dir_conf *) apr_pcalloc(p, sizeof(proxy_dir_conf));
+    proxy_dir_conf *add = (proxy_dir_conf *) addv;
+
+    new->p = add->p;
+    new->p_is_fnmatch = add->p_is_fnmatch;
+    new->r = add->r;
+    return new;
+}
+
+
+static const char *
+    add_proxy(cmd_parms *cmd, void *dummy, const char *f1, const char *r1, int regex)
+{
+    server_rec *s = cmd->server;
+    proxy_server_conf *conf =
+    (proxy_server_conf *) ap_get_module_config(s->module_config, &proxy_module);
+    struct proxy_remote *new;
+    char *p, *q;
+    char *r, *f, *scheme;
+    regex_t *reg = NULL;
+    int port;
+
+    r = apr_pstrdup(cmd->pool, r1);
+    scheme = apr_pstrdup(cmd->pool, r1);
+    f = apr_pstrdup(cmd->pool, f1);
+    p = strchr(r, ':');
+    if (p == NULL || p[1] != '/' || p[2] != '/' || p[3] == '\0') {
+        if (regex)
+            return "ProxyRemoteMatch: Bad syntax for a remote proxy server";
+        else
+            return "ProxyRemote: Bad syntax for a remote proxy server";
+    }
+    else {
+        scheme[p-r] = 0;
+    }
+    q = strchr(p + 3, ':');
+    if (q != NULL) {
+        if (sscanf(q + 1, "%u", &port) != 1 || port > 65535) {
+            if (regex)
+                return "ProxyRemoteMatch: Bad syntax for a remote proxy server (bad port number)";
+            else
+                return "ProxyRemote: Bad syntax for a remote proxy server (bad port number)";
+        }
+        *q = '\0';
+    }
+    else
+        port = -1;
+    *p = '\0';
+    if (regex) {
+        reg = ap_pregcomp(cmd->pool, f, REG_EXTENDED);
+        if (!reg)
+            return "Regular expression for ProxyRemoteMatch could not be compiled.";
+    }
+    else
+        if (strchr(f, ':') == NULL)
+            ap_str_tolower(f);		/* lowercase scheme */
+    ap_str_tolower(p + 3);		/* lowercase hostname */
+
+    if (port == -1) {
+        port = apr_uri_port_of_scheme(scheme);
+    }
+
+    new = apr_array_push(conf->proxies);
+    new->scheme = f;
+    new->protocol = r;
+    new->hostname = p + 3;
+    new->port = port;
+    new->regexp = reg;
+    new->use_regex = regex;
+    return NULL;
+}
+
+static const char *
+    add_proxy_noregex(cmd_parms *cmd, void *dummy, const char *f1, const char *r1)
+{
+    return add_proxy(cmd, dummy, f1, r1, 0);
+}
+
+static const char *
+    add_proxy_regex(cmd_parms *cmd, void *dummy, const char *f1, const char *r1)
+{
+    return add_proxy(cmd, dummy, f1, r1, 1);
+}
+
+static const char *
+    add_pass(cmd_parms *cmd, void *dummy, const char *arg)
+{
+    server_rec *s = cmd->server;
+    proxy_server_conf *conf =
+    (proxy_server_conf *) ap_get_module_config(s->module_config, &proxy_module);
+    struct proxy_alias *new;
+    char *f = cmd->path;
+    char *r = NULL;
+    char *word;
+    apr_table_t *params = apr_table_make(cmd->pool, 5);
+    const apr_array_header_t *arr;
+    const apr_table_entry_t *elts;
+    int i;
+    
+    while (*arg) {
+        word = ap_getword_conf(cmd->pool, &arg);
+        if (!f)
+            f = word;
+        else if (!r)
+            r = word;
+        else {
+            char *val = strchr(word, '=');
+            if (!val) {
+                if (cmd->path)
+                    return "Invalid ProxyPass parameter. Paramet must be in the form 'key=value'";
+                else
+                    return "ProxyPass can not have a path when defined in a location"; 
+            }
+            else
+                *val++ = '\0';
+            apr_table_setn(params, word, val);
+        }
+    };
+
+    if (r == NULL)
+        return "ProxyPass needs a path when not defined in a location";
+
+    new = apr_array_push(conf->aliases);
+    new->fake = apr_pstrdup(cmd->pool, f);
+    new->real = apr_pstrdup(cmd->pool, r);
+    
+    arr = apr_table_elts(params);
+    elts = (const apr_table_entry_t *)arr->elts;
+    /* Distinguish the balancer from woker */
+    if (strncasecmp(r, "balancer:", 9) == 0) {
+        proxy_balancer *balancer = ap_proxy_get_balancer(cmd->pool, conf, r);
+        if (!balancer) {
+            const char *err = ap_proxy_add_balancer(&balancer,
+                                                    cmd->pool,
+                                                    conf, r);
+            if (err)
+                return apr_pstrcat(cmd->temp_pool, "ProxyPass ", err, NULL);
+        }        
+        for (i = 0; i < arr->nelts; i++) {
+            const char *err = set_balancer_param(cmd->pool, balancer, elts[i].key,
+                                                 elts[i].val);
+            if (err)
+                return apr_pstrcat(cmd->temp_pool, "ProxyPass ", err, NULL);
+        }
+    }
+    else {
+        proxy_worker *worker = ap_proxy_get_worker(cmd->temp_pool, conf, r);
+        if (!worker) {
+            const char *err = ap_proxy_add_worker(&worker, cmd->pool, conf, r);
+            if (err)
+                return apr_pstrcat(cmd->temp_pool, "ProxyPass ", err, NULL);
+        }
+        PROXY_COPY_CONF_PARAMS(worker, conf);
+
+        for (i = 0; i < arr->nelts; i++) {
+            const char *err = set_worker_param(cmd->pool, worker, elts[i].key,
+                                               elts[i].val);
+            if (err)
+                return apr_pstrcat(cmd->temp_pool, "ProxyPass ", err, NULL);
+        }
+    }
+    return NULL;
+}
+
+static const char *
+    add_pass_reverse(cmd_parms *cmd, void *dummy, const char *f, const char *r)
+{
+    server_rec *s = cmd->server;
+    proxy_server_conf *conf;
+    struct proxy_alias *new;
+
+    conf = (proxy_server_conf *)ap_get_module_config(s->module_config, 
+                                                     &proxy_module);
+    if (r!=NULL && cmd->path == NULL ) {
+        new = apr_array_push(conf->raliases);
+        new->fake = f;
+        new->real = r;
+    } else if (r==NULL && cmd->path != NULL) {
+        new = apr_array_push(conf->raliases);
+        new->fake = cmd->path;
+        new->real = f;
+    } else {
+        if ( r == NULL)
+            return "ProxyPassReverse needs a path when not defined in a location";
+        else 
+            return "ProxyPassReverse can not have a path when defined in a location";
+    }
+
+    return NULL;
+}
+static const char*
+    cookie_path(cmd_parms *cmd, void *dummy, const char *f, const char *r)
+{
+    server_rec *s = cmd->server;
+    proxy_server_conf *conf;
+    struct proxy_alias *new;
+
+    conf = (proxy_server_conf *)ap_get_module_config(s->module_config,
+                                                     &proxy_module);
+    new = apr_array_push(conf->cookie_paths);
+    new->fake = f;
+    new->real = r;
+
+    return NULL;
+}
+static const char*
+    cookie_domain(cmd_parms *cmd, void *dummy, const char *f, const char *r)
+{
+    server_rec *s = cmd->server;
+    proxy_server_conf *conf;
+    struct proxy_alias *new;
+
+    conf = (proxy_server_conf *)ap_get_module_config(s->module_config,
+                                                     &proxy_module);
+    new = apr_array_push(conf->cookie_domains);
+    new->fake = f;
+    new->real = r;
+
+    return NULL;
+}
+
+static const char *
+    set_proxy_exclude(cmd_parms *parms, void *dummy, const char *arg)
+{
+    server_rec *s = parms->server;
+    proxy_server_conf *conf =
+    ap_get_module_config(s->module_config, &proxy_module);
+    struct noproxy_entry *new;
+    struct noproxy_entry *list = (struct noproxy_entry *) conf->noproxies->elts;
+    struct apr_sockaddr_t *addr;
+    int found = 0;
+    int i;
+
+    /* Don't duplicate entries */
+    for (i = 0; i < conf->noproxies->nelts; i++) {
+        if (apr_strnatcasecmp(arg, list[i].name) == 0) { /* ignore case for host names */
+            found = 1;
+        }
+    }
+
+    if (!found) {
+        new = apr_array_push(conf->noproxies);
+        new->name = arg;
+        if (APR_SUCCESS == apr_sockaddr_info_get(&addr, new->name, APR_UNSPEC, 0, 0, parms->pool)) {
+            new->addr = addr;
+        }
+        else {
+            new->addr = NULL;
+        }
+    }
+    return NULL;
+}
+
+/*
+ * Set the ports CONNECT can use
+ */
+static const char *
+    set_allowed_ports(cmd_parms *parms, void *dummy, const char *arg)
+{
+    server_rec *s = parms->server;
+    proxy_server_conf *conf =
+        ap_get_module_config(s->module_config, &proxy_module);
+    int *New;
+
+    if (!apr_isdigit(arg[0]))
+        return "AllowCONNECT: port number must be numeric";
+
+    New = apr_array_push(conf->allowed_connect_ports);
+    *New = atoi(arg);
+    return NULL;
+}
+
+/* Similar to set_proxy_exclude(), but defining directly connected hosts,
+ * which should never be accessed via the configured ProxyRemote servers
+ */
+static const char *
+    set_proxy_dirconn(cmd_parms *parms, void *dummy, const char *arg)
+{
+    server_rec *s = parms->server;
+    proxy_server_conf *conf =
+    ap_get_module_config(s->module_config, &proxy_module);
+    struct dirconn_entry *New;
+    struct dirconn_entry *list = (struct dirconn_entry *) conf->dirconn->elts;
+    int found = 0;
+    int i;
+
+    /* Don't duplicate entries */
+    for (i = 0; i < conf->dirconn->nelts; i++) {
+        if (strcasecmp(arg, list[i].name) == 0)
+            found = 1;
+    }
+
+    if (!found) {
+        New = apr_array_push(conf->dirconn);
+        New->name = apr_pstrdup(parms->pool, arg);
+        New->hostaddr = NULL;
+
+	if (ap_proxy_is_ipaddr(New, parms->pool)) {
+#if DEBUGGING
+            ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
+                         "Parsed addr %s", inet_ntoa(New->addr));
+            ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
+                         "Parsed mask %s", inet_ntoa(New->mask));
+#endif
+	}
+	else if (ap_proxy_is_domainname(New, parms->pool)) {
+            ap_str_tolower(New->name);
+#if DEBUGGING
+            ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
+                         "Parsed domain %s", New->name);
+#endif
+        }
+        else if (ap_proxy_is_hostname(New, parms->pool)) {
+            ap_str_tolower(New->name);
+#if DEBUGGING
+            ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
+                         "Parsed host %s", New->name);
+#endif
+        }
+        else {
+            ap_proxy_is_word(New, parms->pool);
+#if DEBUGGING
+            fprintf(stderr, "Parsed word %s\n", New->name);
+#endif
+        }
+    }
+    return NULL;
+}
+
+static const char *
+    set_proxy_domain(cmd_parms *parms, void *dummy, const char *arg)
+{
+    proxy_server_conf *psf =
+    ap_get_module_config(parms->server->module_config, &proxy_module);
+
+    if (arg[0] != '.')
+        return "ProxyDomain: domain name must start with a dot.";
+
+    psf->domain = arg;
+    return NULL;
+}
+
+static const char *
+    set_proxy_req(cmd_parms *parms, void *dummy, int flag)
+{
+    proxy_server_conf *psf =
+    ap_get_module_config(parms->server->module_config, &proxy_module);
+
+    psf->req = flag;
+    psf->req_set = 1;
+    return NULL;
+}
+static const char *
+    set_proxy_error_override(cmd_parms *parms, void *dummy, int flag)
+{
+    proxy_server_conf *psf =
+    ap_get_module_config(parms->server->module_config, &proxy_module);
+
+    psf->error_override = flag;
+    psf->error_override_set = 1;
+    return NULL;
+}
+static const char *
+    set_preserve_host(cmd_parms *parms, void *dummy, int flag)
+{
+    proxy_server_conf *psf =
+    ap_get_module_config(parms->server->module_config, &proxy_module);
+
+    psf->preserve_host = flag;
+    psf->preserve_host_set = 1;
+    return NULL;
+}
+
+static const char *
+    set_recv_buffer_size(cmd_parms *parms, void *dummy, const char *arg)
+{
+    proxy_server_conf *psf =
+    ap_get_module_config(parms->server->module_config, &proxy_module);
+    int s = atoi(arg);
+    if (s < 512 && s != 0) {
+        return "ProxyReceiveBufferSize must be >= 512 bytes, or 0 for system default.";
+    }
+
+    psf->recv_buffer_size = s;
+    psf->recv_buffer_size_set = 1;
+    return NULL;
+}
+
+static const char *
+    set_io_buffer_size(cmd_parms *parms, void *dummy, const char *arg)
+{
+    proxy_server_conf *psf =
+    ap_get_module_config(parms->server->module_config, &proxy_module);
+    long s = atol(arg);
+
+    psf->io_buffer_size = ((s > AP_IOBUFSIZE) ? s : AP_IOBUFSIZE);
+    psf->io_buffer_size_set = 1;
+    return NULL;
+}
+
+static const char *
+    set_max_forwards(cmd_parms *parms, void *dummy, const char *arg)
+{
+    proxy_server_conf *psf =
+    ap_get_module_config(parms->server->module_config, &proxy_module);
+    long s = atol(arg);
+    if (s < 0) {
+        return "ProxyMaxForwards must be greater or equal to zero..";
+    }
+
+    psf->maxfwd = s;
+    psf->maxfwd_set = 1;
+    return NULL;
+}
+static const char*
+    set_proxy_timeout(cmd_parms *parms, void *dummy, const char *arg)
+{
+    proxy_server_conf *psf =
+    ap_get_module_config(parms->server->module_config, &proxy_module);
+    int timeout;
+
+    timeout=atoi(arg);
+    if (timeout<1) {
+        return "Proxy Timeout must be at least 1 second.";
+    }
+    psf->timeout_set=1;
+    psf->timeout=apr_time_from_sec(timeout);
+
+    return NULL;    
+}
+
+static const char*
+    set_via_opt(cmd_parms *parms, void *dummy, const char *arg)
+{
+    proxy_server_conf *psf =
+    ap_get_module_config(parms->server->module_config, &proxy_module);
+
+    if (strcasecmp(arg, "Off") == 0)
+        psf->viaopt = via_off;
+    else if (strcasecmp(arg, "On") == 0)
+        psf->viaopt = via_on;
+    else if (strcasecmp(arg, "Block") == 0)
+        psf->viaopt = via_block;
+    else if (strcasecmp(arg, "Full") == 0)
+        psf->viaopt = via_full;
+    else {
+        return "ProxyVia must be one of: "
+            "off | on | full | block";
+    }
+
+    psf->viaopt_set = 1;
+    return NULL;    
+}
+
+static const char*
+    set_bad_opt(cmd_parms *parms, void *dummy, const char *arg)
+{
+    proxy_server_conf *psf =
+    ap_get_module_config(parms->server->module_config, &proxy_module);
+
+    if (strcasecmp(arg, "IsError") == 0)
+        psf->badopt = bad_error;
+    else if (strcasecmp(arg, "Ignore") == 0)
+        psf->badopt = bad_ignore;
+    else if (strcasecmp(arg, "StartBody") == 0)
+        psf->badopt = bad_body;
+    else {
+        return "ProxyBadHeader must be one of: "
+            "IsError | Ignore | StartBody";
+    }
+
+    psf->badopt_set = 1;
+    return NULL;    
+}
+
+static const char*
+    set_status_opt(cmd_parms *parms, void *dummy, const char *arg)
+{
+    proxy_server_conf *psf =
+    ap_get_module_config(parms->server->module_config, &proxy_module);
+
+    if (strcasecmp(arg, "Off") == 0)
+        psf->proxy_status = status_off;
+    else if (strcasecmp(arg, "On") == 0)
+        psf->proxy_status = status_on;
+    else if (strcasecmp(arg, "Full") == 0)
+        psf->proxy_status = status_full;
+    else {
+        return "ProxyStatus must be one of: "
+            "off | on | block";
+    }
+
+    psf->proxy_status_set = 1;
+    return NULL;    
+}
+
+static const char *add_member(cmd_parms *cmd, void *dummy, const char *arg)
+{
+    server_rec *s = cmd->server;
+    proxy_server_conf *conf =
+    ap_get_module_config(s->module_config, &proxy_module);
+    proxy_balancer *balancer;
+    proxy_worker *worker;
+    char *path = cmd->path;
+    char *name = NULL;
+    char *word;
+    apr_table_t *params = apr_table_make(cmd->pool, 5);
+    const apr_array_header_t *arr;
+    const apr_table_entry_t *elts;
+    int i;
+    
+    if (cmd->path)
+        path = apr_pstrdup(cmd->pool, cmd->path);
+    while (*arg) {
+        word = ap_getword_conf(cmd->pool, &arg);
+        if (!path)
+            path = word;
+        else if (!name)
+            name = word;
+        else {
+            char *val = strchr(word, '=');
+            if (!val)
+                if (cmd->path)
+                    return "BalancerMember can not have a balancer name when defined in a location";
+                else
+                    return "Invalid BalancerMember parameter. Paramet must be in the form 'key=value'";
+            else
+                *val++ = '\0';
+            apr_table_setn(params, word, val);
+        }
+    }
+    if (!path)
+        return "BalancerMember must define balancer name when outside <Proxy > section";
+    if (!name)
+        return "BalancerMember must define remote proxy server";
+    
+    ap_str_tolower(path);	/* lowercase scheme://hostname */
+    ap_str_tolower(name);	/* lowercase scheme://hostname */
+
+    /* Try to find existing worker */
+    worker = ap_proxy_get_worker(cmd->temp_pool, conf, name);
+    if (!worker) {
+        const char *err;
+        if ((err = ap_proxy_add_worker(&worker, cmd->pool, conf, name)) != NULL)
+            return apr_pstrcat(cmd->temp_pool, "BalancerMember ", err, NULL); 
+    }
+    PROXY_COPY_CONF_PARAMS(worker, conf);
+    
+    arr = apr_table_elts(params);
+    elts = (const apr_table_entry_t *)arr->elts;
+    for (i = 0; i < arr->nelts; i++) {
+        const char *err = set_worker_param(cmd->pool, worker, elts[i].key,
+                                           elts[i].val);
+        if (err)
+            return apr_pstrcat(cmd->temp_pool, "BalancerMember ", err, NULL);
+    }
+    /* Try to find the balancer */
+    balancer = ap_proxy_get_balancer(cmd->temp_pool, conf, path); 
+    if (!balancer) {
+        const char *err = ap_proxy_add_balancer(&balancer,
+                                                cmd->pool,
+                                                conf, path);
+        if (err)
+            return apr_pstrcat(cmd->temp_pool, "BalancerMember ", err, NULL);
+    }
+    /* Add the worker to the load balancer */
+    ap_proxy_add_worker_to_balancer(cmd->pool, balancer, worker);
+
+    return NULL;
+}
+
+static const char *
+    set_sticky_session(cmd_parms *cmd, void *dummy, const char *f, const char *r)
+{
+    server_rec *s = cmd->server;
+    proxy_server_conf *conf =
+    ap_get_module_config(s->module_config, &proxy_module);
+    proxy_balancer *balancer;
+    const char *name, *sticky;
+
+    if (r != NULL && cmd->path == NULL ) {
+        name = f;
+        sticky = r;
+    } else if (r == NULL && cmd->path != NULL) {
+        name = cmd->path;
+        sticky = f;
+    } else {
+        if (r == NULL)
+            return "BalancerStickySession needs a path when not defined in a location";
+        else 
+            return "BalancerStickySession can not have a path when defined in a location";
+    }
+    /* Try to find the balancer */
+    balancer = ap_proxy_get_balancer(cmd->temp_pool, conf, name);
+    if (!balancer)
+        return apr_pstrcat(cmd->temp_pool, "BalancerStickySession: can not find a load balancer '",
+                           name, "'", NULL);
+    if (!strcasecmp(sticky, "nofailover"))
+        balancer->sticky_force = 1;   
+    else
+        balancer->sticky = sticky;
+    return NULL;
+}
+
+static void ap_add_per_proxy_conf(server_rec *s, ap_conf_vector_t *dir_config)
+{
+    proxy_server_conf *sconf = ap_get_module_config(s->module_config,
+					            &proxy_module);
+    void **new_space = (void **)apr_array_push(sconf->sec_proxy);
+    
+    *new_space = dir_config;
+}
+
+static const char *proxysection(cmd_parms *cmd, void *mconfig, const char *arg)
+{
+    const char *errmsg;
+    const char *endp = ap_strrchr_c(arg, '>');
+    int old_overrides = cmd->override;
+    char *old_path = cmd->path;
+    proxy_dir_conf *conf;
+    ap_conf_vector_t *new_dir_conf = ap_create_per_dir_config(cmd->pool);
+    regex_t *r = NULL;
+    const command_rec *thiscmd = cmd->cmd;
+
+    const char *err = ap_check_cmd_context(cmd,
+                                           NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT);
+    if (err != NULL) {
+        return err;
+    }
+
+    if (endp == NULL) {
+        return apr_pstrcat(cmd->pool, cmd->cmd->name,
+                           "> directive missing closing '>'", NULL);
+    }
+
+    arg=apr_pstrndup(cmd->pool, arg, endp-arg);
+
+    if (!arg) {
+        if (thiscmd->cmd_data)
+            return "<ProxyMatch > block must specify a path";
+        else
+            return "<Proxy > block must specify a path";
+    }
+
+    cmd->path = ap_getword_conf(cmd->pool, &arg);
+    cmd->override = OR_ALL|ACCESS_CONF;
+
+    if (!strncasecmp(cmd->path, "proxy:", 6))
+        cmd->path += 6;
+
+    /* XXX Ignore case?  What if we proxy a case-insensitive server?!? 
+     * While we are at it, shouldn't we also canonicalize the entire
+     * scheme?  See proxy_fixup()
+     */
+    if (thiscmd->cmd_data) { /* <ProxyMatch> */
+        r = ap_pregcomp(cmd->pool, cmd->path, REG_EXTENDED);
+        if (!r) {
+            return "Regex could not be compiled";
+        }
+    }
+    else if (!strcmp(cmd->path, "~")) {
+        cmd->path = ap_getword_conf(cmd->pool, &arg);
+        if (!cmd->path)
+            return "<Proxy ~ > block must specify a path";
+        if (strncasecmp(cmd->path, "proxy:", 6))
+            cmd->path += 6;
+        r = ap_pregcomp(cmd->pool, cmd->path, REG_EXTENDED);
+        if (!r) {
+            return "Regex could not be compiled";
+        }
+    }
+
+    /* initialize our config and fetch it */
+    conf = ap_set_config_vectors(cmd->server, new_dir_conf, cmd->path,
+                                 &proxy_module, cmd->pool);
+
+    errmsg = ap_walk_config(cmd->directive->first_child, cmd, new_dir_conf);
+    if (errmsg != NULL)
+        return errmsg;
+
+    conf->r = r;
+    conf->p = cmd->path;
+    conf->p_is_fnmatch = apr_fnmatch_test(conf->p);
+
+    ap_add_per_proxy_conf(cmd->server, new_dir_conf);
+
+    if (*arg != '\0') {
+        return apr_pstrcat(cmd->pool, "Multiple ", thiscmd->name,
+                           "> arguments not (yet) supported.", NULL);
+    }
+
+    cmd->path = old_path;
+    cmd->override = old_overrides;
+
+    return NULL;
+}
+
+static const command_rec proxy_cmds[] =
+{
+    AP_INIT_RAW_ARGS("<Proxy", proxysection, NULL, RSRC_CONF, 
+    "Container for directives affecting resources located in the proxied "
+    "location"),
+    AP_INIT_RAW_ARGS("<ProxyMatch", proxysection, (void*)1, RSRC_CONF,
+    "Container for directives affecting resources located in the proxied "
+    "location, in regular expression syntax"),
+    AP_INIT_FLAG("ProxyRequests", set_proxy_req, NULL, RSRC_CONF,
+     "on if the true proxy requests should be accepted"),
+    AP_INIT_TAKE2("ProxyRemote", add_proxy_noregex, NULL, RSRC_CONF,
+     "a scheme, partial URL or '*' and a proxy server"),
+    AP_INIT_TAKE2("ProxyRemoteMatch", add_proxy_regex, NULL, RSRC_CONF,
+     "a regex pattern and a proxy server"),
+    AP_INIT_RAW_ARGS("ProxyPass", add_pass, NULL, RSRC_CONF|ACCESS_CONF,
+     "a virtual path and a URL"),
+    AP_INIT_TAKE12("ProxyPassReverse", add_pass_reverse, NULL, RSRC_CONF|ACCESS_CONF,
+     "a virtual path and a URL for reverse proxy behaviour"),
+    AP_INIT_TAKE2("ProxyPassReverseCookiePath", cookie_path, NULL,
+       RSRC_CONF|ACCESS_CONF, "Path rewrite rule for proxying cookies"),
+    AP_INIT_TAKE2("ProxyPassReverseCookieDomain", cookie_domain, NULL,
+       RSRC_CONF|ACCESS_CONF, "Domain rewrite rule for proxying cookies"),
+    AP_INIT_ITERATE("ProxyBlock", set_proxy_exclude, NULL, RSRC_CONF,
+     "A list of names, hosts or domains to which the proxy will not connect"),
+    AP_INIT_TAKE1("ProxyReceiveBufferSize", set_recv_buffer_size, NULL, RSRC_CONF,
+     "Receive buffer size for outgoing HTTP and FTP connections in bytes"),
+    AP_INIT_TAKE1("ProxyIOBufferSize", set_io_buffer_size, NULL, RSRC_CONF,
+     "IO buffer size for outgoing HTTP and FTP connections in bytes"),
+    AP_INIT_TAKE1("ProxyMaxForwards", set_max_forwards, NULL, RSRC_CONF,
+     "The maximum number of proxies a request may be forwarded through."),
+    AP_INIT_ITERATE("NoProxy", set_proxy_dirconn, NULL, RSRC_CONF,
+     "A list of domains, hosts, or subnets to which the proxy will connect directly"),
+    AP_INIT_TAKE1("ProxyDomain", set_proxy_domain, NULL, RSRC_CONF,
+     "The default intranet domain name (in absence of a domain in the URL)"),
+    AP_INIT_ITERATE("AllowCONNECT", set_allowed_ports, NULL, RSRC_CONF,
+     "A list of ports which CONNECT may connect to"),
+    AP_INIT_TAKE1("ProxyVia", set_via_opt, NULL, RSRC_CONF,
+     "Configure Via: proxy header header to one of: on | off | block | full"),
+    AP_INIT_FLAG("ProxyErrorOverride", set_proxy_error_override, NULL, RSRC_CONF,
+     "use our error handling pages instead of the servers' we are proxying"),
+    AP_INIT_FLAG("ProxyPreserveHost", set_preserve_host, NULL, RSRC_CONF,
+     "on if we should preserve host header while proxying"),
+    AP_INIT_TAKE1("ProxyTimeout", set_proxy_timeout, NULL, RSRC_CONF,
+     "Set the timeout (in seconds) for a proxied connection. "
+     "This overrides the server timeout"),
+    AP_INIT_TAKE1("ProxyBadHeader", set_bad_opt, NULL, RSRC_CONF,
+     "How to handle bad header line in response: IsError | Ignore | StartBody"),
+    AP_INIT_RAW_ARGS("BalancerMember", add_member, NULL, RSRC_CONF|ACCESS_CONF,
+     "A balancer name and scheme with list of params"), 
+    AP_INIT_TAKE12("BalancerStickySession", set_sticky_session, NULL, RSRC_CONF|ACCESS_CONF,
+     "A balancer and sticky session name"),
+    AP_INIT_TAKE1("ProxyStatus", set_status_opt, NULL, RSRC_CONF,
+     "Configure Status: proxy status to one of: on | off | full"),
+    {NULL}
+};
+
+static APR_OPTIONAL_FN_TYPE(ssl_proxy_enable) *proxy_ssl_enable = NULL;
+static APR_OPTIONAL_FN_TYPE(ssl_engine_disable) *proxy_ssl_disable = NULL;
+
+PROXY_DECLARE(int) ap_proxy_ssl_enable(conn_rec *c)
+{
+    /* 
+     * if c == NULL just check if the optional function was imported
+     * else run the optional function so ssl filters are inserted
+     */
+    if (proxy_ssl_enable) {
+        return c ? proxy_ssl_enable(c) : 1;
+    }
+
+    return 0;
+}
+
+PROXY_DECLARE(int) ap_proxy_ssl_disable(conn_rec *c)
+{
+    if (proxy_ssl_disable) {
+        return proxy_ssl_disable(c);
+    }
+
+    return 0;
+}
+
+static int proxy_post_config(apr_pool_t *pconf, apr_pool_t *plog,
+                             apr_pool_t *ptemp, server_rec *s)
+{
+    proxy_ssl_enable = APR_RETRIEVE_OPTIONAL_FN(ssl_proxy_enable);
+    proxy_ssl_disable = APR_RETRIEVE_OPTIONAL_FN(ssl_engine_disable);
+
+    return OK;
+}
+
+
+#define KBYTE 1024
+#define MBYTE 1048576L
+#define GBYTE 1073741824L
+
+/* Format the number of bytes nicely */
+static void format_byte_out(request_rec *r, apr_off_t bytes)
+{
+
+    if (bytes < (5 * KBYTE))
+        ap_rprintf(r, "%d B", (int) bytes);
+    else if (bytes < (MBYTE / 2))
+        ap_rprintf(r, "%.1f kB", (float) bytes / KBYTE);
+    else if (bytes < (GBYTE / 2))
+        ap_rprintf(r, "%.1f MB", (float) bytes / MBYTE);
+    else
+        ap_rprintf(r, "%.1f GB", (float) bytes / GBYTE);
+}
+
+/*
+ *  proxy Extension to mod_status
+ */
+static int proxy_status_hook(request_rec *r, int flags)
+{
+    int i, n;
+    void *sconf = r->server->module_config;
+    proxy_server_conf *conf = (proxy_server_conf *)
+        ap_get_module_config(sconf, &proxy_module);
+    proxy_balancer *balancer = NULL;
+    proxy_runtime_worker *worker = NULL;
+
+    if (flags & AP_STATUS_SHORT || conf->balancers->nelts == 0 ||
+        conf->proxy_status == status_off)
+        return OK;
+
+    balancer = (proxy_balancer *)conf->balancers->elts;
+    for (i = 0; i < conf->balancers->nelts; i++) {
+        ap_rputs("<hr />\n<h1>Proxy LoadBalancer Status for ", r);
+        ap_rvputs(r, balancer->name, "</h1>\n\n", NULL);
+        ap_rputs("\n\n<table border=\"0\"><tr>"
+                 "<th>SSes</th><th>Timeout</th>"
+                 "</tr>\n<tr>", r);                
+        ap_rvputs(r, "<td>", balancer->sticky, NULL);
+        ap_rprintf(r, "</td><td>%d</td>\n",
+                   apr_time_sec(balancer->timeout));
+        ap_rputs("</table>\n", r);
+        ap_rputs("\n\n<table border=\"0\"><tr>"
+                 "<th>Sch</th><th>Host</th>"
+                 "<th>Route</th><th>Redir</th>"
+                 "<th>F</th><th>Acc</th><th>Wr</th><th>Rd</th>"
+                 "</tr>\n", r);
+
+        worker = (proxy_runtime_worker *)balancer->workers->elts;
+        for (n = 0; n < balancer->workers->nelts; n++) {
+
+            ap_rvputs(r, "<tr>\n<td>", worker->w->scheme, "</td>", NULL);
+            ap_rvputs(r, "<td>", worker->w->hostname, "</td>", NULL);
+            ap_rvputs(r, "<td>", worker->w->route, NULL);
+            ap_rvputs(r, "</td><td>", worker->w->redirect, NULL);
+            ap_rprintf(r, "</td><td>%.2f</td>", worker->s->lbfactor);
+            ap_rprintf(r, "<td>%d</td><td>", (int)(worker->s->elected));
+            format_byte_out(r, worker->s->transfered);
+            ap_rputs("</td><td>", r);
+            format_byte_out(r, worker->s->transfered);
+            ap_rputs("</td>\n", r);
+
+            /* TODO: Add the rest of dynamic worker data */
+            ap_rputs("</tr>\n", r);
+
+            ++worker;
+        }
+        ap_rputs("</table>\n", r);
+        ++balancer;
+    }
+    ap_rputs("<hr /><table>\n"
+             "<tr><th>SSes</th><td>Sticky session name</td></tr>\n"
+             "<tr><th>Timeout</th><td>Balancer Timeout</td></tr>\n"
+             "<tr><th>Sch</th><td>Connection scheme</td></tr>\n"
+             "<tr><th>Host</th><td>Backend Hostname</td></tr>\n"
+             "<tr><th>Route</th><td>Session Route</td></tr>\n"
+             "<tr><th>Redir</th><td>Session Route Redirection</td></tr>\n"
+             "<tr><th>F</th><td>Load Balancer Factor in %</td></tr>\n"
+             "<tr><th>Acc</th><td>Number of requests</td></tr>\n"
+             "<tr><th>Wr</th><td>Number of bytes transfered</td></tr>\n"
+             "<tr><th>Rd</th><td>Number of bytes readed</td></tr>\n"
+             "</table>", r);
+
+    return OK;
+}
+
+/*
+ * This routine is called before the server processes the configuration
+ * files.  There is no return value.
+ */
+static int proxy_pre_config(apr_pool_t *pconf, apr_pool_t *plog,
+                            apr_pool_t *ptemp)
+{
+    APR_OPTIONAL_HOOK(ap, status_hook, proxy_status_hook, NULL, NULL,
+                      APR_HOOK_MIDDLE);
+    return OK;
+}
+
+static void register_hooks(apr_pool_t *p)
+{
+    /* fixup before mod_rewrite, so that the proxied url will not
+     * escaped accidentally by our fixup.
+     */
+#ifndef FIX_15207
+    static const char * const aszSucc[]={ "mod_rewrite.c", NULL };
+#endif
+
+    /* handler */
+    ap_hook_handler(proxy_handler, NULL, NULL, APR_HOOK_FIRST);
+    /* filename-to-URI translation */
+    ap_hook_translate_name(proxy_trans, NULL, NULL, APR_HOOK_FIRST);
+    /* walk <Proxy > entries and suppress default TRACE behavior */
+    ap_hook_map_to_storage(proxy_map_location, NULL,NULL, APR_HOOK_FIRST);
+#ifndef FIX_15207
+    /* fixups */
+    ap_hook_fixups(proxy_fixup, NULL, aszSucc, APR_HOOK_FIRST);
+#endif
+    /* post read_request handling */
+    ap_hook_post_read_request(proxy_detect, NULL, NULL, APR_HOOK_FIRST);
+    /* pre config handling */
+    ap_hook_pre_config(proxy_pre_config, NULL, NULL, APR_HOOK_MIDDLE); 
+    /* post config handling */
+    ap_hook_post_config(proxy_post_config, NULL, NULL, APR_HOOK_MIDDLE);
+}
+
+module AP_MODULE_DECLARE_DATA proxy_module =
+{
+    STANDARD20_MODULE_STUFF,
+    create_proxy_dir_config,    /* create per-directory config structure */
+    merge_proxy_dir_config,     /* merge per-directory config structures */
+    create_proxy_config,	/* create per-server config structure */
+    merge_proxy_config,		/* merge per-server config structures */
+    proxy_cmds,			/* command table */
+    register_hooks
+};
+
+APR_HOOK_STRUCT(
+	APR_HOOK_LINK(scheme_handler)
+	APR_HOOK_LINK(canon_handler)
+	APR_HOOK_LINK(pre_request)
+	APR_HOOK_LINK(post_request)
+)
+
+APR_IMPLEMENT_EXTERNAL_HOOK_RUN_FIRST(proxy, PROXY, int, scheme_handler, 
+                                     (request_rec *r, proxy_worker *worker,
+                                      proxy_server_conf *conf, 
+                                      char *url, const char *proxyhost, 
+                                      apr_port_t proxyport),(r,worker,conf,
+                                      url,proxyhost,proxyport),DECLINED)
+APR_IMPLEMENT_EXTERNAL_HOOK_RUN_FIRST(proxy, PROXY, int, canon_handler, 
+                                      (request_rec *r, char *url),(r,
+                                      url),DECLINED)
+APR_IMPLEMENT_EXTERNAL_HOOK_RUN_FIRST(proxy, PROXY, int, pre_request, (
+                                      proxy_worker **worker,
+                                      proxy_balancer **balancer,
+                                      request_rec *r, 
+                                      proxy_server_conf *conf,
+                                      char **url),(worker,balancer,
+                                      r,conf,url),DECLINED)
+APR_IMPLEMENT_EXTERNAL_HOOK_RUN_FIRST(proxy, PROXY, int, post_request,
+                                      (proxy_worker *worker,
+                                       proxy_balancer *balancer,
+                                       request_rec *r,
+                                       proxy_server_conf *conf),(worker,
+                                       balancer,r,conf),DECLINED)
+APR_IMPLEMENT_OPTIONAL_HOOK_RUN_ALL(proxy, PROXY, int, fixups,
+				    (request_rec *r), (r),
+				    OK, DECLINED)

Added: branches/tomcat5.5/upstream/5.5.20/connectors/ajp/proxy/mod_proxy.dsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/ajp/proxy/mod_proxy.dsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/ajp/proxy/mod_proxy.dsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,140 @@
+# Microsoft Developer Studio Project File - Name="mod_proxy" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
+
+CFG=mod_proxy - Win32 Release
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE 
+!MESSAGE NMAKE /f "mod_proxy.mak".
+!MESSAGE 
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE 
+!MESSAGE NMAKE /f "mod_proxy.mak" CFG="mod_proxy - Win32 Release"
+!MESSAGE 
+!MESSAGE Possible choices for configuration are:
+!MESSAGE 
+!MESSAGE "mod_proxy - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "mod_proxy - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE 
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+MTL=midl.exe
+RSC=rc.exe
+
+!IF  "$(CFG)" == "mod_proxy - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MD /W3 /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /FD /c
+# ADD CPP /nologo /MD /W3 /Zi /O2 /I "../ssl" /I "../../include" /I "../../srclib/apr/include" /I "../../srclib/apr-util/include" /I "../generators" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "PROXY_DECLARE_EXPORT" /Fd"Release\mod_proxy_src" /FD /c
+# ADD BASE MTL /nologo /D "NDEBUG" /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x809 /d "NDEBUG"
+# ADD RSC /l 0x809 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib ws2_32.lib mswsock.lib /nologo /subsystem:windows /dll /machine:I386 /out:"Release/mod_proxy.so" /base:@..\..\os\win32\BaseAddr.ref,mod_proxy.so
+# ADD LINK32 kernel32.lib ws2_32.lib mswsock.lib /nologo /subsystem:windows /dll /debug /machine:I386 /out:"Release/mod_proxy.so" /base:@..\..\os\win32\BaseAddr.ref,mod_proxy.so /opt:ref
+
+!ELSEIF  "$(CFG)" == "mod_proxy - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MDd /W3 /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FD /c
+# ADD CPP /nologo /MDd /W3 /GX /Zi /Od /I "../ssl" /I "../../include" /I "../../srclib/apr/include" /I "../../srclib/apr-util/include" /I "../generators" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "PROXY_DECLARE_EXPORT" /Fd"Debug\mod_proxy_src" /FD /c
+# ADD BASE MTL /nologo /D "_DEBUG" /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x809 /d "_DEBUG"
+# ADD RSC /l 0x809 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib ws2_32.lib mswsock.lib /nologo /subsystem:windows /dll /incremental:no /debug /machine:I386 /out:"Debug/mod_proxy.so" /base:@..\..\os\win32\BaseAddr.ref,mod_proxy.so
+# ADD LINK32 kernel32.lib ws2_32.lib mswsock.lib /nologo /subsystem:windows /dll /incremental:no /debug /machine:I386 /out:"Debug/mod_proxy.so" /base:@..\..\os\win32\BaseAddr.ref,mod_proxy.so
+
+!ENDIF 
+
+# Begin Target
+
+# Name "mod_proxy - Win32 Release"
+# Name "mod_proxy - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;hpj;bat;for;f90"
+# Begin Source File
+
+SOURCE=.\mod_proxy.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\proxy_util.c
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl;fi;fd"
+# Begin Source File
+
+SOURCE=.\mod_proxy.h
+# End Source File
+# End Group
+# Begin Source File
+
+SOURCE=..\..\build\win32\win32ver.awk
+
+!IF  "$(CFG)" == "mod_proxy - Win32 Release"
+
+# PROP Ignore_Default_Tool 1
+# Begin Custom Build - Creating Version Resource
+InputPath=..\..\build\win32\win32ver.awk
+
+".\mod_proxy.rc" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+	awk -f ../../build/win32/win32ver.awk mod_proxy.so "proxy_module for Apache" ../../include/ap_release.h > .\mod_proxy.rc
+
+# End Custom Build
+
+!ELSEIF  "$(CFG)" == "mod_proxy - Win32 Debug"
+
+# PROP Ignore_Default_Tool 1
+# Begin Custom Build - Creating Version Resource
+InputPath=..\..\build\win32\win32ver.awk
+
+".\mod_proxy.rc" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+	awk -f ../../build/win32/win32ver.awk mod_proxy.so "proxy_module for Apache" ../../include/ap_release.h > .\mod_proxy.rc
+
+# End Custom Build
+
+!ENDIF 
+
+# End Source File
+# End Target
+# End Project

Added: branches/tomcat5.5/upstream/5.5.20/connectors/ajp/proxy/mod_proxy.h
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/ajp/proxy/mod_proxy.h	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/ajp/proxy/mod_proxy.h	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,414 @@
+/* Copyright 1999-2004 The Apache Software Foundation
+ *
+ * Licensed 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.
+ */
+
+#ifndef MOD_PROXY_H
+#define MOD_PROXY_H 
+
+/*
+ * Main include file for the Apache proxy
+ */
+
+/*
+
+   Also note numerous FIXMEs and CHECKMEs which should be eliminated.
+
+   This code is once again experimental!
+
+   Things to do:
+
+   1. Make it completely work (for FTP too)
+
+   2. HTTP/1.1
+
+   Chuck Murcko <chuck at topsail.org> 02-06-01
+
+ */
+
+#define CORE_PRIVATE
+
+#include "apr_hooks.h"
+#include "apr.h"
+#include "apr_lib.h"
+#include "apr_strings.h"
+#include "apr_buckets.h"
+#include "apr_md5.h"
+#include "apr_network_io.h"
+#include "apr_pools.h"
+#include "apr_strings.h"
+#include "apr_uri.h"
+#include "apr_date.h"
+#include "apr_strmatch.h"
+#include "apr_fnmatch.h"
+#include "apr_reslist.h"
+#define APR_WANT_STRFUNC
+#include "apr_want.h"
+
+#include "httpd.h"
+#include "http_config.h"
+#include "ap_config.h"
+#include "http_core.h"
+#include "http_protocol.h"
+#include "http_request.h"
+#include "http_vhost.h"
+#include "http_main.h"
+#include "http_log.h"
+#include "http_connection.h"
+#include "util_filter.h"
+#include "util_ebcdic.h"
+
+#if APR_HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#if APR_HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+
+/* for proxy_canonenc() */
+enum enctype {
+    enc_path, enc_search, enc_user, enc_fpath, enc_parm
+};
+
+#if APR_CHARSET_EBCDIC
+#define CRLF   "\r\n"
+#else /*APR_CHARSET_EBCDIC*/
+#define CRLF   "\015\012"
+#endif /*APR_CHARSET_EBCDIC*/
+
+/* default Max-Forwards header setting */
+#define DEFAULT_MAX_FORWARDS	10
+
+/* static information about a remote proxy */
+struct proxy_remote {
+    const char *scheme;		/* the schemes handled by this proxy, or '*' */
+    const char *protocol;	/* the scheme used to talk to this proxy */
+    const char *hostname;	/* the hostname of this proxy */
+    apr_port_t  port;		/* the port for this proxy */
+    regex_t *regexp;		/* compiled regex (if any) for the remote */
+    int use_regex;		/* simple boolean. True if we have a regex pattern */
+};
+
+struct proxy_alias {
+    const char  *real;
+    const char  *fake;
+};
+
+struct dirconn_entry {
+    char *name;
+    struct in_addr addr, mask;
+    struct apr_sockaddr_t *hostaddr;
+    int (*matcher) (struct dirconn_entry * This, request_rec *r);
+};
+
+struct noproxy_entry {
+    const char *name;
+    struct apr_sockaddr_t *addr;
+};
+
+typedef struct {
+    apr_array_header_t *proxies;
+    apr_array_header_t *sec_proxy;
+    apr_array_header_t *aliases;
+    apr_array_header_t *raliases;
+    apr_array_header_t *noproxies;
+    apr_array_header_t *dirconn;
+    apr_array_header_t *allowed_connect_ports;
+    apr_array_header_t *workers;
+    apr_array_header_t *balancers;
+    const char *domain;		/* domain name to use in absence of a domain name in the request */
+    int req;			/* true if proxy requests are enabled */
+    char req_set;
+    enum {
+      via_off,
+      via_on,
+      via_block,
+      via_full
+    } viaopt;                   /* how to deal with proxy Via: headers */
+    char viaopt_set;
+    apr_size_t recv_buffer_size;
+    char recv_buffer_size_set;
+    apr_size_t io_buffer_size;
+    char io_buffer_size_set;
+    long maxfwd;
+    char maxfwd_set;
+    /** 
+     * the following setting masks the error page
+     * returned from the 'proxied server' and just 
+     * forwards the status code upwards.
+     * This allows the main server (us) to generate
+     * the error page, (so it will look like a error
+     * returned from the rest of the system 
+     */
+    int error_override;
+    int error_override_set;
+    int preserve_host;
+    int preserve_host_set;
+    apr_interval_time_t timeout;
+    char timeout_set;
+    enum {
+      bad_error,
+      bad_ignore,
+      bad_body
+    } badopt;                   /* how to deal with bad headers */
+    char badopt_set;
+/* putting new stuff on the end maximises binary back-compatibility.
+ * the strmatch_patterns are really a const just to have a
+ * case-independent strstr.
+ */
+    apr_array_header_t* cookie_paths;
+    apr_array_header_t* cookie_domains;
+    const apr_strmatch_pattern* cookie_path_str;
+    const apr_strmatch_pattern* cookie_domain_str;
+    enum {
+        status_off,
+        status_on,
+        status_full
+    } proxy_status;             /* Status display options */
+    char proxy_status_set;
+
+} proxy_server_conf;
+
+typedef struct proxy_balancer  proxy_balancer;
+typedef struct proxy_worker    proxy_worker;
+typedef struct proxy_conn_pool proxy_conn_pool;
+
+typedef struct {
+    const char *p;            /* The path */
+    int         p_is_fnmatch; /* Is this path an fnmatch candidate? */
+    regex_t    *r;            /* Is this a regex? */
+} proxy_dir_conf;
+
+typedef struct {
+    conn_rec     *connection;
+    const char   *hostname;
+    apr_port_t   port;
+    int          is_ssl;
+    apr_pool_t   *pool;     /* Subpool used for creating socket */
+    apr_socket_t *sock;     /* Connection socket */
+    apr_uint32_t flags;     /* Conection flags */
+    int          close;     /* Close 'this' connection */
+    int          close_on_recycle; /* Close the connection when returning to pool */
+    proxy_worker *worker;   /* Connection pool this connection belogns to */
+    void         *data;     /* per scheme connection data */
+} proxy_conn_rec;
+
+typedef struct {
+        float cache_completion; /* completion percentage */
+        int content_length; /* length of the content */
+} proxy_completion;
+
+/* Connection pool */
+struct proxy_conn_pool {
+    apr_pool_t     *pool;   /* The pool used in constructor and destructor calls */
+    apr_sockaddr_t *addr;   /* Preparsed remote address info */
+#if APR_HAS_THREADS
+    apr_reslist_t  *res;    /* Connection resource list */
+#endif
+    int            nfree;   /* Balancer free count number */
+    proxy_conn_rec *conn;   /* Single connection for prefork mpm's */
+};
+
+/* woker status flags */
+#define PROXY_WORKER_INITIALIZED    0x0001
+#define PROXY_WORKER_IN_SHUTDOWN    0x0010
+#define PROXY_WORKER_DISABLED       0x0020
+#define PROXY_WORKER_IN_ERROR       0x0040
+
+#define PROXY_WORKER_IS_USABLE(f)   (!((f)->status & 0x00F0))
+
+
+/* Worker configuration */
+struct proxy_worker {
+    int             status;
+    apr_time_t      error_time; /* time of the last error */
+    apr_interval_time_t retry;  /* retry interval */
+    int             retries;    /* number of retries on this worker */
+    int             lbfactor;   /* initial load balancing factor */
+    const char      *name;
+    const char      *scheme;    /* scheme to use ajp|http|https */
+    const char      *hostname;  /* remote backend address */
+    const char      *route;     /* balancing route */
+    const char      *redirect;  /* temporary balancing redirection route */
+    apr_port_t      port;
+    int             min;        /* Desired minimum number of available connections */
+    int             smax;       /* Soft maximum on the total number of connections */
+    int             hmax;       /* Hard maximum on the total number of connections */
+    apr_interval_time_t ttl;    /* maximum amount of time in seconds a connection
+                                 * may be available while exceeding the soft limit */
+    apr_interval_time_t timeout; /* connection timeout */
+    char                timeout_set;
+    apr_interval_time_t acquire; /* acquire timeout when the maximum number of connections is exceeded */
+    char                acquire_set;
+    apr_size_t          recv_buffer_size;
+    char                recv_buffer_size_set;
+    apr_size_t          io_buffer_size;
+    char                io_buffer_size_set;
+    char                keepalive;
+    char                keepalive_set;
+    proxy_conn_pool *cp;        /* Connection pool to use */
+    void            *opaque;    /* per scheme worker data */
+};
+
+/* Runtime worker status informations. Shared in scoreboard */
+typedef struct {
+    int             id;         /* scoreboard id */
+    double          lbstatus;   /* Current lbstatus */
+    double          lbfactor;   /* dynamic lbfactor */
+    apr_size_t      transfered; /* Number of bytes transfered to remote */
+    apr_size_t      readed;     /* Number of bytes readed from remote */
+    apr_size_t      elected;    /* Number of times the worker was elected */
+} proxy_runtime_stat;
+
+/* Runtime worker. */
+typedef struct {
+    proxy_balancer     *b;         /* balancer containing this worker */
+    proxy_worker       *w;
+    proxy_runtime_stat *s;
+} proxy_runtime_worker;
+
+struct proxy_balancer {
+    apr_array_header_t *workers; /* array of proxy_runtime_workers */
+    const char *name;            /* name of the load balancer */
+    const char *sticky;          /* sticky session identifier */
+    int         sticky_force;    /* Disable failover for sticky sessions */
+    apr_interval_time_t timeout; /* Timeout for waiting on free connection */
+    /* XXX: Perhaps we will need the proc mutex too.
+     * Altrough we are only using arithmetic operations
+     * it may lead to a incorrect calculations.
+     * For now use only the thread mutex.
+     */
+#if APR_HAS_THREADS
+    apr_thread_mutex_t  *mutex;  /* Thread lock for updating lb params */
+#endif
+};
+
+/* hooks */
+
+/* Create a set of PROXY_DECLARE(type), PROXY_DECLARE_NONSTD(type) and 
+ * PROXY_DECLARE_DATA with appropriate export and import tags for the platform
+ */
+#if !defined(WIN32)
+#define PROXY_DECLARE(type)            type
+#define PROXY_DECLARE_NONSTD(type)     type
+#define PROXY_DECLARE_DATA
+#elif defined(PROXY_DECLARE_STATIC)
+#define PROXY_DECLARE(type)            type __stdcall
+#define PROXY_DECLARE_NONSTD(type)     type
+#define PROXY_DECLARE_DATA
+#elif defined(PROXY_DECLARE_EXPORT)
+#define PROXY_DECLARE(type)            __declspec(dllexport) type __stdcall
+#define PROXY_DECLARE_NONSTD(type)     __declspec(dllexport) type
+#define PROXY_DECLARE_DATA             __declspec(dllexport)
+#else
+#define PROXY_DECLARE(type)            __declspec(dllimport) type __stdcall
+#define PROXY_DECLARE_NONSTD(type)     __declspec(dllimport) type
+#define PROXY_DECLARE_DATA             __declspec(dllimport)
+#endif
+
+/**
+ * Hook an optional proxy hook.  Unlike static hooks, this uses a macro
+ * instead of a function.
+ */
+#define PROXY_OPTIONAL_HOOK(name,fn,pre,succ,order) \
+        APR_OPTIONAL_HOOK(proxy,name,fn,pre,succ,order)
+
+APR_DECLARE_EXTERNAL_HOOK(proxy, PROXY, int, scheme_handler, (request_rec *r, 
+                          proxy_worker *worker, proxy_server_conf *conf, char *url, 
+                          const char *proxyhost, apr_port_t proxyport))
+APR_DECLARE_EXTERNAL_HOOK(proxy, PROXY, int, canon_handler, (request_rec *r, 
+                          char *url))
+
+APR_DECLARE_EXTERNAL_HOOK(proxy, PROXY, int, create_req, (request_rec *r, request_rec *pr))
+APR_DECLARE_EXTERNAL_HOOK(proxy, PROXY, int, fixups, (request_rec *r)) 
+
+/**
+ * pre request hook.
+ * It will return the most suitable worker at the moment
+ * and coresponding balancer.
+ * The url is rewritten from balancer://cluster/uri to scheme://host:port/uri
+ * and then the scheme_handler is called.
+ *
+ */
+APR_DECLARE_EXTERNAL_HOOK(proxy, PROXY, int, pre_request, (proxy_worker **worker,
+                          proxy_balancer **balancer,
+                          request_rec *r,
+                          proxy_server_conf *conf, char **url))                          
+/**
+ * post request hook.
+ * It is called after request for updating runtime balancer status.
+ */
+APR_DECLARE_EXTERNAL_HOOK(proxy, PROXY, int, post_request, (proxy_worker *worker,
+                          proxy_balancer *balancer, request_rec *r,
+                          proxy_server_conf *conf))
+
+
+/* proxy_util.c */
+
+PROXY_DECLARE(request_rec *)ap_proxy_make_fake_req(conn_rec *c, request_rec *r);
+PROXY_DECLARE(int) ap_proxy_hex2c(const char *x);
+PROXY_DECLARE(void) ap_proxy_c2hex(int ch, char *x);
+PROXY_DECLARE(char *)ap_proxy_canonenc(apr_pool_t *p, const char *x, int len, enum enctype t,
+			int isenc);
+PROXY_DECLARE(char *)ap_proxy_canon_netloc(apr_pool_t *p, char **const urlp, char **userp,
+			 char **passwordp, char **hostp, apr_port_t *port);
+PROXY_DECLARE(const char *)ap_proxy_date_canon(apr_pool_t *p, const char *x);
+PROXY_DECLARE(int) ap_proxy_liststr(const char *list, const char *val);
+PROXY_DECLARE(char *)ap_proxy_removestr(apr_pool_t *pool, const char *list, const char *val);
+PROXY_DECLARE(int) ap_proxy_hex2sec(const char *x);
+PROXY_DECLARE(void) ap_proxy_sec2hex(int t, char *y);
+PROXY_DECLARE(int) ap_proxyerror(request_rec *r, int statuscode, const char *message);
+PROXY_DECLARE(int) ap_proxy_is_ipaddr(struct dirconn_entry *This, apr_pool_t *p);
+PROXY_DECLARE(int) ap_proxy_is_domainname(struct dirconn_entry *This, apr_pool_t *p);
+PROXY_DECLARE(int) ap_proxy_is_hostname(struct dirconn_entry *This, apr_pool_t *p);
+PROXY_DECLARE(int) ap_proxy_is_word(struct dirconn_entry *This, apr_pool_t *p);
+PROXY_DECLARE(int) ap_proxy_checkproxyblock(request_rec *r, proxy_server_conf *conf, apr_sockaddr_t *uri_addr);
+PROXY_DECLARE(int) ap_proxy_pre_http_request(conn_rec *c, request_rec *r);
+PROXY_DECLARE(apr_status_t) ap_proxy_string_read(conn_rec *c, apr_bucket_brigade *bb, char *buff, size_t bufflen, int *eos);
+PROXY_DECLARE(void) ap_proxy_table_unmerge(apr_pool_t *p, apr_table_t *t, char *key);
+/* DEPRECATED (will be replaced with ap_proxy_connect_backend */
+PROXY_DECLARE(int) ap_proxy_connect_to_backend(apr_socket_t **, const char *, apr_sockaddr_t *, const char *, proxy_server_conf *, server_rec *, apr_pool_t *);
+PROXY_DECLARE(int) ap_proxy_ssl_enable(conn_rec *c);
+PROXY_DECLARE(int) ap_proxy_ssl_disable(conn_rec *c);
+
+/* Connection pool API */
+PROXY_DECLARE(proxy_worker *) ap_proxy_get_worker(apr_pool_t *p, proxy_server_conf *conf, const char *url);
+PROXY_DECLARE(const char *) ap_proxy_add_worker(proxy_worker **worker, apr_pool_t *p, proxy_server_conf *conf, const char *url);
+PROXY_DECLARE(struct proxy_balancer *) ap_proxy_get_balancer(apr_pool_t *p, proxy_server_conf *conf, const char *url);
+PROXY_DECLARE(const char *) ap_proxy_add_balancer(proxy_balancer **balancer, apr_pool_t *p, proxy_server_conf *conf, const char *url);
+PROXY_DECLARE(void) ap_proxy_add_worker_to_balancer(apr_pool_t *pool, proxy_balancer *balancer, proxy_worker *worker);
+PROXY_DECLARE(int) ap_proxy_pre_request(proxy_worker **worker, proxy_balancer **balancer, request_rec *r, proxy_server_conf *conf, char **url);
+PROXY_DECLARE(int) ap_proxy_determine_connection(apr_pool_t *p, request_rec *r, proxy_server_conf *conf, proxy_worker *worker, proxy_conn_rec *conn,
+                                                 apr_pool_t *ppool, apr_uri_t *uri, char **url, const char *proxyname, apr_port_t proxyport,
+                                                 char *server_portstr, int server_portstr_size);
+PROXY_DECLARE(int) ap_proxy_retry_worker(const char *proxy_function, proxy_worker *worker, server_rec *s);
+PROXY_DECLARE(int) ap_proxy_acquire_connection(const char *proxy_function, proxy_conn_rec **conn, proxy_worker *worker, server_rec *s);
+PROXY_DECLARE(int) ap_proxy_release_connection(const char *proxy_function, proxy_conn_rec *conn, server_rec *s);
+PROXY_DECLARE(apr_status_t) ap_proxy_close_connection(proxy_conn_rec *conn);
+PROXY_DECLARE(int) ap_proxy_connect_backend(const char *proxy_function, proxy_conn_rec *conn, proxy_worker *worker, server_rec *s);
+PROXY_DECLARE(int) ap_proxy_connection_create(const char *proxy_function, proxy_conn_rec *conn, conn_rec *c, server_rec *s);
+
+/* Scoreboard */
+#if MODULE_MAGIC_NUMBER_MAJOR > 20020903
+#define PROXY_HAS_SCOREBOARD 1
+#else
+#define PROXY_HAS_SCOREBOARD 0
+#endif
+/* The number of dynamic balancers that can be added */
+#define PROXY_DYNAMIC_BALANCER_LIMIT    16
+PROXY_DECLARE(int) ap_proxy_lb_workers(void);
+
+/* For proxy_util */
+extern module PROXY_DECLARE_DATA proxy_module;
+
+#endif /*MOD_PROXY_H*/

Added: branches/tomcat5.5/upstream/5.5.20/connectors/ajp/proxy/mod_proxy_ajp.dsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/ajp/proxy/mod_proxy_ajp.dsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/ajp/proxy/mod_proxy_ajp.dsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,168 @@
+# Microsoft Developer Studio Project File - Name="mod_proxy_ajp" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
+
+CFG=mod_proxy_ajp - Win32 Release
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE 
+!MESSAGE NMAKE /f "mod_proxy_ajp.mak".
+!MESSAGE 
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE 
+!MESSAGE NMAKE /f "mod_proxy_ajp.mak" CFG="mod_proxy_ajp - Win32 Release"
+!MESSAGE 
+!MESSAGE Possible choices for configuration are:
+!MESSAGE 
+!MESSAGE "mod_proxy_ajp - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "mod_proxy_ajp - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE 
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+MTL=midl.exe
+RSC=rc.exe
+
+!IF  "$(CFG)" == "mod_proxy_ajp - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MD /W3 /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /FD /c
+# ADD CPP /nologo /MD /W3 /Zi /O2 /I "../../include" /I "../../srclib/apr/include" /I "../../srclib/apr-util/include" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /Fd"Release\mod_proxy_ajp_src" /FD /c
+# ADD BASE MTL /nologo /D "NDEBUG" /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x809 /d "NDEBUG"
+# ADD RSC /l 0x809 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib ws2_32.lib mswsock.lib /nologo /subsystem:windows /dll /machine:I386 /out:"Release/mod_proxy_ajp.so" /base:@..\..\os\win32\BaseAddr.ref,mod_proxy_ajp.so
+# ADD LINK32 kernel32.lib ws2_32.lib mswsock.lib /nologo /subsystem:windows /dll /debug /machine:I386 /out:"Release/mod_proxy_ajp.so" /base:@..\..\os\win32\BaseAddr.ref,mod_proxy_ajp.so /opt:ref
+
+!ELSEIF  "$(CFG)" == "mod_proxy_ajp - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MDd /W3 /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FD /c
+# ADD CPP /nologo /MDd /W3 /GX /Zi /Od /I "../../include" /I "../../srclib/apr/include" /I "../../srclib/apr-util/include" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /Fd"Debug\mod_proxy_ajp_src" /FD /c
+# ADD BASE MTL /nologo /D "_DEBUG" /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x809 /d "_DEBUG"
+# ADD RSC /l 0x809 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib ws2_32.lib mswsock.lib /nologo /subsystem:windows /dll /incremental:no /debug /machine:I386 /out:"Debug/mod_proxy_ajp.so" /base:@..\..\os\win32\BaseAddr.ref,mod_proxy_ajp.so
+# ADD LINK32 kernel32.lib ws2_32.lib mswsock.lib /nologo /subsystem:windows /dll /incremental:no /debug /machine:I386 /out:"Debug/mod_proxy_ajp.so" /base:@..\..\os\win32\BaseAddr.ref,mod_proxy_ajp.so
+
+!ENDIF 
+
+# Begin Target
+
+# Name "mod_proxy_ajp - Win32 Release"
+# Name "mod_proxy_ajp - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;hpj;bat;for;f90"
+# Begin Source File
+
+SOURCE=.\proxy_ajp.c
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter ".h"
+# Begin Source File
+
+SOURCE=.\mod_proxy.h
+# End Source File
+# End Group
+# Begin Group "Ajp Files"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=.\ajp\ajp.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\ajp\ajp_header.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\ajp\ajp_header.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\ajp\ajp_link.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\ajp\ajp_logon.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\ajp\ajp_logon.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\ajp\ajp_msg.c
+# End Source File
+# End Group
+# Begin Source File
+
+SOURCE=..\..\build\win32\win32ver.awk
+
+!IF  "$(CFG)" == "mod_proxy_ajp - Win32 Release"
+
+# PROP Ignore_Default_Tool 1
+# Begin Custom Build - Creating Version Resource
+InputPath=..\..\build\win32\win32ver.awk
+
+".\mod_proxy_ajp.rc" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+	awk -f ../../build/win32/win32ver.awk mod_proxy_ajp.so "proxy_ajp_module for Apache" ../../include/ap_release.h > .\mod_proxy_ajp.rc
+
+# End Custom Build
+
+!ELSEIF  "$(CFG)" == "mod_proxy_ajp - Win32 Debug"
+
+# PROP Ignore_Default_Tool 1
+# Begin Custom Build - Creating Version Resource
+InputPath=..\..\build\win32\win32ver.awk
+
+".\mod_proxy_ajp.rc" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+	awk -f ../../build/win32/win32ver.awk mod_proxy_ajp.so "proxy_ajp_module for Apache" ../../include/ap_release.h > .\mod_proxy_ajp.rc
+
+# End Custom Build
+
+!ENDIF 
+
+# End Source File
+# End Target
+# End Project

Added: branches/tomcat5.5/upstream/5.5.20/connectors/ajp/proxy/mod_proxy_balancer.dsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/ajp/proxy/mod_proxy_balancer.dsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/ajp/proxy/mod_proxy_balancer.dsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,136 @@
+# Microsoft Developer Studio Project File - Name="mod_proxy_balancer" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
+
+CFG=mod_proxy_balancer - Win32 Release
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE 
+!MESSAGE NMAKE /f "mod_proxy_balancer.mak".
+!MESSAGE 
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE 
+!MESSAGE NMAKE /f "mod_proxy_balancer.mak" CFG="mod_proxy_balancer - Win32 Release"
+!MESSAGE 
+!MESSAGE Possible choices for configuration are:
+!MESSAGE 
+!MESSAGE "mod_proxy_balancer - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "mod_proxy_balancer - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE 
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+MTL=midl.exe
+RSC=rc.exe
+
+!IF  "$(CFG)" == "mod_proxy_balancer - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MD /W3 /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /FD /c
+# ADD CPP /nologo /MD /W3 /Zi /O2 /I "../../include" /I "../../srclib/apr/include" /I "../../srclib/apr-util/include" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /Fd"Release\mod_proxy_balancer_src" /FD /c
+# ADD BASE MTL /nologo /D "NDEBUG" /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x809 /d "NDEBUG"
+# ADD RSC /l 0x809 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib ws2_32.lib mswsock.lib /nologo /subsystem:windows /dll /machine:I386 /out:"Release/mod_proxy_balancer.so" /base:@..\..\os\win32\BaseAddr.ref,mod_proxy_balancer.so
+# ADD LINK32 kernel32.lib ws2_32.lib mswsock.lib /nologo /subsystem:windows /dll /incremental:no /debug /machine:I386 /out:"Release/mod_proxy_balancer.so" /base:@..\..\os\win32\BaseAddr.ref,mod_proxy_balancer.so /opt:ref
+
+!ELSEIF  "$(CFG)" == "mod_proxy_balancer - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MDd /W3 /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FD /c
+# ADD CPP /nologo /MDd /W3 /GX /Zi /Od /I "../../include" /I "../../srclib/apr/include" /I "../../srclib/apr-util/include" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /Fd"Debug\mod_proxy_balancer_src" /FD /c
+# ADD BASE MTL /nologo /D "_DEBUG" /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x809 /d "_DEBUG"
+# ADD RSC /l 0x809 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib ws2_32.lib mswsock.lib /nologo /subsystem:windows /dll /incremental:no /debug /machine:I386 /out:"Debug/mod_proxy_balancer.so" /base:@..\..\os\win32\BaseAddr.ref,mod_proxy_balancer.so
+# ADD LINK32 kernel32.lib ws2_32.lib mswsock.lib /nologo /subsystem:windows /dll /incremental:no /debug /machine:I386 /out:"Debug/mod_proxy_balancer.so" /base:@..\..\os\win32\BaseAddr.ref,mod_proxy_balancer.so
+
+!ENDIF 
+
+# Begin Target
+
+# Name "mod_proxy_balancer - Win32 Release"
+# Name "mod_proxy_balancer - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;hpj;bat;for;f90"
+# Begin Source File
+
+SOURCE=.\proxy_balancer.c
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter ".h"
+# Begin Source File
+
+SOURCE=.\mod_proxy.h
+# End Source File
+# End Group
+# Begin Source File
+
+SOURCE=..\..\build\win32\win32ver.awk
+
+!IF  "$(CFG)" == "mod_proxy_balancer - Win32 Release"
+
+# PROP Ignore_Default_Tool 1
+# Begin Custom Build - Creating Version Resource
+InputPath=..\..\build\win32\win32ver.awk
+
+".\mod_proxy_balancer.rc" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+	awk -f ../../build/win32/win32ver.awk mod_proxy_balancer.so "proxy_balancer_module for Apache" ../../include/ap_release.h > .\mod_proxy_balancer.rc
+
+# End Custom Build
+
+!ELSEIF  "$(CFG)" == "mod_proxy_balancer - Win32 Debug"
+
+# PROP Ignore_Default_Tool 1
+# Begin Custom Build - Creating Version Resource
+InputPath=..\..\build\win32\win32ver.awk
+
+".\mod_proxy_balancer.rc" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+	awk -f ../../build/win32/win32ver.awk mod_proxy_balancer.so "proxy_balancer_module for Apache" ../../include/ap_release.h > .\mod_proxy_balancer.rc
+
+# End Custom Build
+
+!ENDIF 
+
+# End Source File
+# End Target
+# End Project

Added: branches/tomcat5.5/upstream/5.5.20/connectors/ajp/proxy/mod_proxy_connect.dsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/ajp/proxy/mod_proxy_connect.dsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/ajp/proxy/mod_proxy_connect.dsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,136 @@
+# Microsoft Developer Studio Project File - Name="mod_proxy_connect" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
+
+CFG=mod_proxy_connect - Win32 Release
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE 
+!MESSAGE NMAKE /f "mod_proxy_connect.mak".
+!MESSAGE 
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE 
+!MESSAGE NMAKE /f "mod_proxy_connect.mak" CFG="mod_proxy_connect - Win32 Release"
+!MESSAGE 
+!MESSAGE Possible choices for configuration are:
+!MESSAGE 
+!MESSAGE "mod_proxy_connect - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "mod_proxy_connect - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE 
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+MTL=midl.exe
+RSC=rc.exe
+
+!IF  "$(CFG)" == "mod_proxy_connect - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MD /W3 /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /FD /c
+# ADD CPP /nologo /MD /W3 /Zi /O2 /I "../../include" /I "../../srclib/apr/include" /I "../../srclib/apr-util/include" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /Fd"Release\mod_proxy_connect_src" /FD /c
+# ADD BASE MTL /nologo /D "NDEBUG" /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x809 /d "NDEBUG"
+# ADD RSC /l 0x809 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib ws2_32.lib mswsock.lib /nologo /subsystem:windows /dll /machine:I386 /out:"Release/mod_proxy_connect.so" /base:@..\..\os\win32\BaseAddr.ref,mod_proxy_connect.so
+# ADD LINK32 kernel32.lib ws2_32.lib mswsock.lib /nologo /subsystem:windows /dll /incremental:no /debug /machine:I386 /out:"Release/mod_proxy_connect.so" /base:@..\..\os\win32\BaseAddr.ref,mod_proxy_connect.so /opt:ref
+
+!ELSEIF  "$(CFG)" == "mod_proxy_connect - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MDd /W3 /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FD /c
+# ADD CPP /nologo /MDd /W3 /GX /Zi /Od /I "../../include" /I "../../srclib/apr/include" /I "../../srclib/apr-util/include" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /Fd"Debug\mod_proxy_connect_src" /FD /c
+# ADD BASE MTL /nologo /D "_DEBUG" /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x809 /d "_DEBUG"
+# ADD RSC /l 0x809 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib ws2_32.lib mswsock.lib /nologo /subsystem:windows /dll /incremental:no /debug /machine:I386 /out:"Debug/mod_proxy_connect.so" /base:@..\..\os\win32\BaseAddr.ref,mod_proxy_connect.so
+# ADD LINK32 kernel32.lib ws2_32.lib mswsock.lib /nologo /subsystem:windows /dll /incremental:no /debug /machine:I386 /out:"Debug/mod_proxy_connect.so" /base:@..\..\os\win32\BaseAddr.ref,mod_proxy_connect.so
+
+!ENDIF 
+
+# Begin Target
+
+# Name "mod_proxy_connect - Win32 Release"
+# Name "mod_proxy_connect - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;hpj;bat;for;f90"
+# Begin Source File
+
+SOURCE=.\proxy_connect.c
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter ".h"
+# Begin Source File
+
+SOURCE=.\mod_proxy.h
+# End Source File
+# End Group
+# Begin Source File
+
+SOURCE=..\..\build\win32\win32ver.awk
+
+!IF  "$(CFG)" == "mod_proxy_connect - Win32 Release"
+
+# PROP Ignore_Default_Tool 1
+# Begin Custom Build - Creating Version Resource
+InputPath=..\..\build\win32\win32ver.awk
+
+".\mod_proxy_connect.rc" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+	awk -f ../../build/win32/win32ver.awk mod_proxy_connect.so "proxy_connect_module for Apache" ../../include/ap_release.h > .\mod_proxy_connect.rc
+
+# End Custom Build
+
+!ELSEIF  "$(CFG)" == "mod_proxy_connect - Win32 Debug"
+
+# PROP Ignore_Default_Tool 1
+# Begin Custom Build - Creating Version Resource
+InputPath=..\..\build\win32\win32ver.awk
+
+".\mod_proxy_connect.rc" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+	awk -f ../../build/win32/win32ver.awk mod_proxy_connect.so "proxy_connect_module for Apache" ../../include/ap_release.h > .\mod_proxy_connect.rc
+
+# End Custom Build
+
+!ENDIF 
+
+# End Source File
+# End Target
+# End Project

Added: branches/tomcat5.5/upstream/5.5.20/connectors/ajp/proxy/mod_proxy_ftp.dsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/ajp/proxy/mod_proxy_ftp.dsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/ajp/proxy/mod_proxy_ftp.dsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,136 @@
+# Microsoft Developer Studio Project File - Name="mod_proxy_ftp" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
+
+CFG=mod_proxy_ftp - Win32 Release
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE 
+!MESSAGE NMAKE /f "mod_proxy_ftp.mak".
+!MESSAGE 
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE 
+!MESSAGE NMAKE /f "mod_proxy_ftp.mak" CFG="mod_proxy_ftp - Win32 Release"
+!MESSAGE 
+!MESSAGE Possible choices for configuration are:
+!MESSAGE 
+!MESSAGE "mod_proxy_ftp - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "mod_proxy_ftp - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE 
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+MTL=midl.exe
+RSC=rc.exe
+
+!IF  "$(CFG)" == "mod_proxy_ftp - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MD /W3 /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /FD /c
+# ADD CPP /nologo /MD /W3 /Zi /O2 /I "../../include" /I "../../srclib/apr/include" /I "../../srclib/apr-util/include" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /Fd"Release\mod_proxy_ftp_src" /FD /c
+# ADD BASE MTL /nologo /D "NDEBUG" /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x809 /d "NDEBUG"
+# ADD RSC /l 0x809 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib ws2_32.lib mswsock.lib /nologo /subsystem:windows /dll /machine:I386 /out:"Release/mod_proxy_ftp.so" /base:@..\..\os\win32\BaseAddr.ref,mod_proxy_ftp.so
+# ADD LINK32 kernel32.lib ws2_32.lib mswsock.lib /nologo /subsystem:windows /dll /incremental:no /debug /machine:I386 /out:"Release/mod_proxy_ftp.so" /base:@..\..\os\win32\BaseAddr.ref,mod_proxy_ftp.so /opt:ref
+
+!ELSEIF  "$(CFG)" == "mod_proxy_ftp - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MDd /W3 /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FD /c
+# ADD CPP /nologo /MDd /W3 /GX /Zi /Od /I "../../include" /I "../../srclib/apr/include" /I "../../srclib/apr-util/include" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /Fd"Debug\mod_proxy_ftp_src" /FD /c
+# ADD BASE MTL /nologo /D "_DEBUG" /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x809 /d "_DEBUG"
+# ADD RSC /l 0x809 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib ws2_32.lib mswsock.lib /nologo /subsystem:windows /dll /incremental:no /debug /machine:I386 /out:"Debug/mod_proxy_ftp.so" /base:@..\..\os\win32\BaseAddr.ref,mod_proxy_ftp.so
+# ADD LINK32 kernel32.lib ws2_32.lib mswsock.lib /nologo /subsystem:windows /dll /incremental:no /debug /machine:I386 /out:"Debug/mod_proxy_ftp.so" /base:@..\..\os\win32\BaseAddr.ref,mod_proxy_ftp.so
+
+!ENDIF 
+
+# Begin Target
+
+# Name "mod_proxy_ftp - Win32 Release"
+# Name "mod_proxy_ftp - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;hpj;bat;for;f90"
+# Begin Source File
+
+SOURCE=.\proxy_ftp.c
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter ".h"
+# Begin Source File
+
+SOURCE=.\mod_proxy.h
+# End Source File
+# End Group
+# Begin Source File
+
+SOURCE=..\..\build\win32\win32ver.awk
+
+!IF  "$(CFG)" == "mod_proxy_ftp - Win32 Release"
+
+# PROP Ignore_Default_Tool 1
+# Begin Custom Build - Creating Version Resource
+InputPath=..\..\build\win32\win32ver.awk
+
+".\mod_proxy_ftp.rc" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+	awk -f ../../build/win32/win32ver.awk mod_proxy_ftp.so "proxy_ftp_module for Apache" ../../include/ap_release.h > .\mod_proxy_ftp.rc
+
+# End Custom Build
+
+!ELSEIF  "$(CFG)" == "mod_proxy_ftp - Win32 Debug"
+
+# PROP Ignore_Default_Tool 1
+# Begin Custom Build - Creating Version Resource
+InputPath=..\..\build\win32\win32ver.awk
+
+".\mod_proxy_ftp.rc" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+	awk -f ../../build/win32/win32ver.awk mod_proxy_ftp.so "proxy_ftp_module for Apache" ../../include/ap_release.h > .\mod_proxy_ftp.rc
+
+# End Custom Build
+
+!ENDIF 
+
+# End Source File
+# End Target
+# End Project

Added: branches/tomcat5.5/upstream/5.5.20/connectors/ajp/proxy/mod_proxy_http.dsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/ajp/proxy/mod_proxy_http.dsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/ajp/proxy/mod_proxy_http.dsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,136 @@
+# Microsoft Developer Studio Project File - Name="mod_proxy_http" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
+
+CFG=mod_proxy_http - Win32 Release
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE 
+!MESSAGE NMAKE /f "mod_proxy_http.mak".
+!MESSAGE 
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE 
+!MESSAGE NMAKE /f "mod_proxy_http.mak" CFG="mod_proxy_http - Win32 Release"
+!MESSAGE 
+!MESSAGE Possible choices for configuration are:
+!MESSAGE 
+!MESSAGE "mod_proxy_http - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "mod_proxy_http - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE 
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+MTL=midl.exe
+RSC=rc.exe
+
+!IF  "$(CFG)" == "mod_proxy_http - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MD /W3 /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /FD /c
+# ADD CPP /nologo /MD /W3 /Zi /O2 /I "../../include" /I "../../srclib/apr/include" /I "../../srclib/apr-util/include" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /Fd"Release\mod_proxy_http_src" /FD /c
+# ADD BASE MTL /nologo /D "NDEBUG" /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x809 /d "NDEBUG"
+# ADD RSC /l 0x809 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib ws2_32.lib mswsock.lib /nologo /subsystem:windows /dll /machine:I386 /out:"Release/mod_proxy_http.so" /base:@..\..\os\win32\BaseAddr.ref,mod_proxy_http.so
+# ADD LINK32 kernel32.lib ws2_32.lib mswsock.lib /nologo /subsystem:windows /dll /incremental:no /debug /machine:I386 /out:"Release/mod_proxy_http.so" /base:@..\..\os\win32\BaseAddr.ref,mod_proxy_http.so /opt:ref
+
+!ELSEIF  "$(CFG)" == "mod_proxy_http - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MDd /W3 /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FD /c
+# ADD CPP /nologo /MDd /W3 /GX /Zi /Od /I "../../include" /I "../../srclib/apr/include" /I "../../srclib/apr-util/include" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /Fd"Debug\mod_proxy_http_src" /FD /c
+# ADD BASE MTL /nologo /D "_DEBUG" /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x809 /d "_DEBUG"
+# ADD RSC /l 0x809 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib ws2_32.lib mswsock.lib /nologo /subsystem:windows /dll /incremental:no /debug /machine:I386 /out:"Debug/mod_proxy_http.so" /base:@..\..\os\win32\BaseAddr.ref,mod_proxy_http.so
+# ADD LINK32 kernel32.lib ws2_32.lib mswsock.lib /nologo /subsystem:windows /dll /incremental:no /debug /machine:I386 /out:"Debug/mod_proxy_http.so" /base:@..\..\os\win32\BaseAddr.ref,mod_proxy_http.so
+
+!ENDIF 
+
+# Begin Target
+
+# Name "mod_proxy_http - Win32 Release"
+# Name "mod_proxy_http - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;hpj;bat;for;f90"
+# Begin Source File
+
+SOURCE=.\proxy_http.c
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter ".h"
+# Begin Source File
+
+SOURCE=.\mod_proxy.h
+# End Source File
+# End Group
+# Begin Source File
+
+SOURCE=..\..\build\win32\win32ver.awk
+
+!IF  "$(CFG)" == "mod_proxy_http - Win32 Release"
+
+# PROP Ignore_Default_Tool 1
+# Begin Custom Build - Creating Version Resource
+InputPath=..\..\build\win32\win32ver.awk
+
+".\mod_proxy_http.rc" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+	awk -f ../../build/win32/win32ver.awk mod_proxy_http.so "proxy_http_module for Apache" ../../include/ap_release.h > .\mod_proxy_http.rc
+
+# End Custom Build
+
+!ELSEIF  "$(CFG)" == "mod_proxy_http - Win32 Debug"
+
+# PROP Ignore_Default_Tool 1
+# Begin Custom Build - Creating Version Resource
+InputPath=..\..\build\win32\win32ver.awk
+
+".\mod_proxy_http.rc" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+	awk -f ../../build/win32/win32ver.awk mod_proxy_http.so "proxy_http_module for Apache" ../../include/ap_release.h > .\mod_proxy_http.rc
+
+# End Custom Build
+
+!ENDIF 
+
+# End Source File
+# End Target
+# End Project

Added: branches/tomcat5.5/upstream/5.5.20/connectors/ajp/proxy/proxy_ajp.c
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/ajp/proxy/proxy_ajp.c	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/ajp/proxy/proxy_ajp.c	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,420 @@
+/* Copyright 1999-2004 The Apache Software Foundation
+ *
+ * Licensed 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.
+ */
+
+/* AJP routines for Apache proxy */
+
+#include "mod_proxy.h"
+#include "ajp.h"
+
+module AP_MODULE_DECLARE_DATA proxy_ajp_module;
+
+/*
+ * Canonicalise http-like URLs.
+ *  scheme is the scheme for the URL
+ *  url    is the URL starting with the first '/'
+ *  def_port is the default port for this scheme.
+ */
+int ap_proxy_ajp_canon(request_rec *r, char *url)
+{
+    char *host, *path, *search, sport[7];
+    const char *err;
+    const char *scheme;
+    apr_port_t port, def_port;
+
+    ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
+             "proxy: AJP: canonicalising URL %s", url);
+
+    /* ap_port_of_scheme() */
+    if (strncasecmp(url, "ajp:", 4) == 0) {
+        url += 4;
+        scheme = "ajp";
+    }    
+    /* XXX This is probably faulty */ 
+    else if (strncasecmp(url, "ajps:", 5) == 0) {
+        url += 5;
+        scheme = "ajps";
+    }
+    else {
+        return DECLINED;
+    }
+    def_port = apr_uri_port_of_scheme(scheme);
+
+    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+             "proxy: AJP: canonicalising URL %s", url);
+
+    /* do syntatic check.
+     * We break the URL into host, port, path, search
+     */
+    port = def_port;
+    err = ap_proxy_canon_netloc(r->pool, &url, NULL, NULL, &host, &port);
+    if (err) {
+        ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+                      "error parsing URL %s: %s",
+                      url, err);
+        return HTTP_BAD_REQUEST;
+    }
+
+    /* now parse path/search args, according to rfc1738 */
+    /* N.B. if this isn't a true proxy request, then the URL _path_
+     * has already been decoded.  True proxy requests have r->uri
+     * == r->unparsed_uri, and no others have that property.
+     */
+    if (r->uri == r->unparsed_uri) {
+        search = strchr(url, '?');
+        if (search != NULL)
+            *(search++) = '\0';
+    }
+    else
+        search = r->args;
+
+    /* process path */
+    path = ap_proxy_canonenc(r->pool, url, strlen(url), enc_path, r->proxyreq);
+    if (path == NULL)
+        return HTTP_BAD_REQUEST;
+
+    if (port != def_port)
+        apr_snprintf(sport, sizeof(sport), ":%d", port);
+    else
+        sport[0] = '\0';
+
+    if (ap_strchr_c(host, ':')) { /* if literal IPv6 address */
+        host = apr_pstrcat(r->pool, "[", host, "]", NULL);
+    }
+    r->filename = apr_pstrcat(r->pool, "proxy:", scheme, "://", host, sport, 
+            "/", path, (search) ? "?" : "", (search) ? search : "", NULL);
+    return OK;
+}
+ 
+static int ap_proxy_ajp_request(apr_pool_t *p, request_rec *r,
+                                proxy_conn_rec *conn, 
+                                conn_rec *origin, 
+                                proxy_server_conf *conf,
+                                apr_uri_t *uri,
+                                char *url, char *server_portstr)
+{
+    apr_status_t status;
+    int result;
+    apr_bucket_brigade *input_brigade;
+
+    /*
+     * Send the AJP request to the remote server
+     */
+
+    /* send request headers */
+    status = ajp_send_header(conn->sock, r);
+    if (status != APR_SUCCESS) {
+        conn->close++;
+        ap_log_error(APLOG_MARK, APLOG_ERR, status, r->server,
+                     "proxy: AJP: request failed to %pI (%s)",
+                     conn->worker->cp->addr,
+                     conn->worker->hostname);
+        return HTTP_SERVICE_UNAVAILABLE;
+    }
+
+    /* read the first bloc of data */
+    input_brigade = apr_brigade_create(p, r->connection->bucket_alloc);
+    status = ap_get_brigade(r->input_filters, input_brigade,
+                            AP_MODE_READBYTES, APR_BLOCK_READ,
+                            AJP13_MAX_SEND_BODY_SZ);
+ 
+    if (status != APR_SUCCESS) {
+        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+                     "proxy: ap_get_brigade failed");
+        apr_brigade_destroy(input_brigade);
+        return HTTP_INTERNAL_SERVER_ERROR;
+    }
+
+    /* have something */
+    if (APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(input_brigade))) {
+        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+                     "proxy: APR_BUCKET_IS_EOS");
+    }
+
+    if (1) { /* XXXX only when something to send ? */
+        ajp_msg_t *msg;
+        apr_size_t bufsiz;
+        char *buff;
+        status = ajp_alloc_data_msg(r, &buff, &bufsiz, &msg);
+        if (status != APR_SUCCESS) {
+            return status;
+        }
+        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+                     "proxy: data to read (max %d at %08x)", bufsiz, buff);
+
+        /* XXXX calls apr_brigade_flatten... */
+        status = apr_brigade_flatten(input_brigade, buff, &bufsiz);
+        if (status != APR_SUCCESS) {
+             ap_log_error(APLOG_MARK, APLOG_ERR, status, r->server,
+                     "proxy: apr_brigade_flatten");
+            return HTTP_INTERNAL_SERVER_ERROR;
+        }
+
+        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+                     "proxy: got %d byte of data", bufsiz);
+        if (bufsiz > 0) {
+            status = ajp_send_data_msg(conn->sock, r, msg, bufsiz);
+            if (status != APR_SUCCESS) {
+                ap_log_error(APLOG_MARK, APLOG_ERR, status, r->server,
+                             "proxy: request failed to %pI (%s)",
+                             conn->worker->cp->addr,
+                             conn->worker->hostname);
+                return HTTP_SERVICE_UNAVAILABLE;
+            }
+        }
+    }
+
+    /* read the response */
+    status = ajp_read_header(conn->sock, r,
+                             (ajp_msg_t **)&(conn->data));
+    if (status != APR_SUCCESS) {
+        ap_log_error(APLOG_MARK, APLOG_ERR, status, r->server,
+                     "proxy: request failed to %pI (%s)",
+                     conn->worker->cp->addr,
+                     conn->worker->hostname);
+        return HTTP_SERVICE_UNAVAILABLE;
+    }
+
+    /* parse the reponse */
+    result = ajp_parse_type(r, conn->data);
+    if (result == CMD_AJP13_SEND_HEADERS) {
+        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+                     "proxy: got response from %pI (%s)",
+                     conn->worker->cp->addr,
+                     conn->worker->hostname);
+        return HTTP_SERVICE_UNAVAILABLE;
+    }
+
+    /* XXXX: need logic to send the rest of the data */
+/*
+    status = ajp_send_data(p_conn->sock,r);
+    if (status != APR_SUCCESS) {
+        ap_log_error(APLOG_MARK, APLOG_ERR, status, r->server,
+                     "proxy: request failed to %pI (%s)",
+                     p_conn->addr, p_conn->name);
+        return status;
+    }
+ */
+
+    return OK;
+}
+
+/*
+ * Process the AJP response, data already contains the first part of it.
+ */
+static int ap_proxy_ajp_process_response(apr_pool_t * p, request_rec *r,
+                                         conn_rec *origin,
+                                         proxy_conn_rec *backend,
+                                         proxy_server_conf *conf,
+                                         char *server_portstr) 
+{
+    conn_rec *c = r->connection;
+    apr_bucket *e;
+    apr_bucket_brigade *bb;
+    int type;
+    apr_status_t status;
+
+    bb = apr_brigade_create(p, c->bucket_alloc);
+    
+    type = ajp_parse_type(r, backend->data);
+    status = APR_SUCCESS;
+    while (type != CMD_AJP13_END_RESPONSE) {
+        if (type == CMD_AJP13_SEND_HEADERS) {
+            /* AJP13_SEND_HEADERS: process them */
+            status = ajp_parse_header(r, backend->data); 
+            if (status != APR_SUCCESS) {
+                break;
+            }
+        } 
+        else if  (type == CMD_AJP13_SEND_BODY_CHUNK) {
+            /* AJP13_SEND_BODY_CHUNK: piece of data */
+            apr_uint16_t size;
+            char *buff;
+
+            status = ajp_parse_data(r, backend->data, &size, &buff);
+            e = apr_bucket_transient_create(buff, size, c->bucket_alloc);
+            APR_BRIGADE_INSERT_TAIL(bb, e);
+        } 
+        else {
+            status = APR_EGENERAL;
+            break;
+        }
+        /* Read the next message */
+        status = ajp_read_header(backend->sock, r,
+                                 (ajp_msg_t **)&(backend->data));
+        if (status != APR_SUCCESS) {
+            break;
+        }
+        type = ajp_parse_type(r, backend->data);
+    }
+    if (status != APR_SUCCESS) {
+        ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+                      "proxy: error reading headers from remote "
+                      "server %s:%d",
+                      backend->worker->cp->addr,
+                      backend->worker->hostname);
+        return ap_proxyerror(r, HTTP_BAD_GATEWAY,
+                             "Error reading from remote server");
+    }
+
+    /* The page is ready give it to the rest of the logic */
+    e = apr_bucket_eos_create(c->bucket_alloc);
+    APR_BRIGADE_INSERT_TAIL(bb, e);
+    if (ap_pass_brigade(r->output_filters, bb) != APR_SUCCESS) {
+        ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+                      "proxy: error processing body");
+        return ap_proxyerror(r, HTTP_BAD_GATEWAY,
+                             "Error reading from remote server");
+    } 
+
+    return OK;
+}
+
+/*
+ * This handles http:// URLs, and other URLs using a remote proxy over http
+ * If proxyhost is NULL, then contact the server directly, otherwise
+ * go via the proxy.
+ * Note that if a proxy is used, then URLs other than http: can be accessed,
+ * also, if we have trouble which is clearly specific to the proxy, then
+ * we return DECLINED so that we can try another proxy. (Or the direct
+ * route.)
+ */
+int ap_proxy_ajp_handler(request_rec *r, proxy_worker *worker,
+                         proxy_server_conf *conf,
+                         char *url, const char *proxyname, 
+                         apr_port_t proxyport)
+{
+    int status;
+    char server_portstr[32];
+    conn_rec *origin = NULL;
+    proxy_conn_rec *backend = NULL;
+    int is_ssl = 0;
+    const char *scheme = "AJP";
+
+    /* Note: Memory pool allocation.
+     * A downstream keepalive connection is always connected to the existence
+     * (or not) of an upstream keepalive connection. If this is not done then
+     * load balancing against multiple backend servers breaks (one backend
+     * server ends up taking 100% of the load), and the risk is run of
+     * downstream keepalive connections being kept open unnecessarily. This
+     * keeps webservers busy and ties up resources.
+     *
+     * As a result, we allocate all sockets out of the upstream connection
+     * pool, and when we want to reuse a socket, we check first whether the
+     * connection ID of the current upstream connection is the same as that
+     * of the connection when the socket was opened.
+     */
+    apr_pool_t *p = r->connection->pool;
+    conn_rec *c = r->connection;
+    apr_uri_t *uri = apr_palloc(r->connection->pool, sizeof(*uri));
+
+    
+    if (strncasecmp(url, "ajp:", 4) != 0) {
+        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+                     "proxy: AJP: declining URL %s", url);
+        return DECLINED;
+    }
+    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+             "proxy: AJP: serving URL %s", url);
+    
+
+    /* only use stored info for top-level pages. Sub requests don't share 
+     * in keepalives
+     */
+#if 0
+    if (!r->main) {
+        backend = (proxy_conn_rec *) ap_get_module_config(c->conn_config,
+                                                      &proxy_ajp_module);
+    }
+#endif
+    /* create space for state information */
+    if (!backend) {
+        status = ap_proxy_acquire_connection(scheme, &backend, worker, r->server);
+        if (status != OK) {
+            if (backend) {
+                backend->close_on_recycle = 1;
+                ap_proxy_release_connection(scheme, backend, r->server);
+            }
+            return status;
+        }
+#if 0
+        if (!r->main) {
+            ap_set_module_config(c->conn_config, &proxy_ajp_module, backend);
+        }
+#endif
+    }
+
+    backend->is_ssl = 0;
+    backend->close_on_recycle = 0;
+
+    /* Step One: Determine Who To Connect To */
+    status = ap_proxy_determine_connection(p, r, conf, worker, backend, c->pool,
+                                           uri, &url, proxyname, proxyport,
+                                           server_portstr,
+                                           sizeof(server_portstr));
+
+    if (status != OK)
+        goto cleanup;
+    /* Step Two: Make the Connection */
+    if (ap_proxy_connect_backend(scheme, backend, worker, r->server)) {
+        status = HTTP_SERVICE_UNAVAILABLE;
+        goto cleanup;
+    }
+#if 0
+    /* XXX: we don't need to create the bound client connection */
+
+    /* Step Three: Create conn_rec */
+    if (!backend->connection) {
+        status = ap_proxy_connection_create(scheme, backend, c, r->server);
+        if (status != OK)
+            goto cleanup;
+    }
+#endif
+   
+   
+    /* Step Four: Send the Request */
+    status = ap_proxy_ajp_request(p, r, backend, origin, conf, uri, url,
+                                  server_portstr);
+    if (status != OK)
+        goto cleanup;
+
+    /* Step Five: Receive the Response */
+    status = ap_proxy_ajp_process_response(p, r, origin, backend,
+                                           conf, server_portstr);
+cleanup:
+#if 0
+    /* Clear the module config */
+    ap_set_module_config(c->conn_config, &proxy_ajp_module, NULL);
+#endif
+    /* Do not close the socket */
+    ap_proxy_release_connection(scheme, backend, r->server);
+    return status;
+}
+
+static void ap_proxy_http_register_hook(apr_pool_t *p)
+{
+    proxy_hook_scheme_handler(ap_proxy_ajp_handler, NULL, NULL, APR_HOOK_FIRST);
+    proxy_hook_canon_handler(ap_proxy_ajp_canon, NULL, NULL, APR_HOOK_FIRST);
+}
+
+module AP_MODULE_DECLARE_DATA proxy_ajp_module = {
+    STANDARD20_MODULE_STUFF,
+    NULL,              /* create per-directory config structure */
+    NULL,              /* merge per-directory config structures */
+    NULL,              /* create per-server config structure */
+    NULL,              /* merge per-server config structures */
+    NULL,              /* command apr_table_t */
+    ap_proxy_http_register_hook/* register hooks */
+};
+

Added: branches/tomcat5.5/upstream/5.5.20/connectors/ajp/proxy/proxy_balancer.c
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/ajp/proxy/proxy_balancer.c	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/ajp/proxy/proxy_balancer.c	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,387 @@
+/* Copyright 1999-2004 The Apache Software Foundation
+ *
+ * Licensed 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.
+ */
+
+/* Load balancer module for Apache proxy */
+
+#define CORE_PRIVATE
+
+#include "mod_proxy.h"
+#include "ap_mpm.h"
+#include "apr_version.h"
+
+module AP_MODULE_DECLARE_DATA proxy_balancer_module;
+
+#if APR_HAS_THREADS
+#define PROXY_BALANCER_LOCK(b)      apr_thread_mutex_lock((b)->mutex)
+#define PROXY_BALANCER_UNLOCK(b)    apr_thread_mutex_unlock((b)->mutex)
+#else
+#define PROXY_BALANCER_LOCK(b)      APR_SUCCESS
+#define PROXY_BALANCER_UNLOCK(b)    APR_SUCCESS
+#endif
+
+
+/* Retrieve the parameter with the given name                                */
+static char *get_path_param(apr_pool_t *pool, char *url,
+                            const char *name)
+{
+    char *path = NULL;
+    
+    for (path = strstr(url, name); path; path = strstr(path + 1, name)) {
+        path += (strlen(name) + 1);
+        if (*path == '=') {
+            /*
+             * Session path was found, get it's value
+             */
+            ++path;
+            if (strlen(path)) {
+                char *q;
+                path = apr_pstrdup(pool, path);
+                if ((q = strchr(path, '?')))
+                    *q = '\0';
+                return path;
+            }
+        }
+    }
+    return NULL;
+}
+
+static char *get_cookie_param(request_rec *r, const char *name)
+{
+    const char *cookies;
+    const char *start_cookie;
+
+    if ((cookies = apr_table_get(r->headers_in, "Cookie"))) {
+        for (start_cookie = strstr(cookies, name); start_cookie; 
+             start_cookie = strstr(start_cookie + 1, name)) {
+            if (start_cookie == cookies ||
+                start_cookie[-1] == ';' ||
+                start_cookie[-1] == ',' ||
+                isspace(start_cookie[-1])) {
+                
+                start_cookie += strlen(name);
+                while(*start_cookie && isspace(*start_cookie))
+                    ++start_cookie;
+                if (*start_cookie == '=' && start_cookie[1]) {
+                    /*
+                     * Session cookie was found, get it's value
+                     */
+                    char *end_cookie, *cookie;
+                    ++start_cookie;
+                    cookie = apr_pstrdup(r->pool, start_cookie);
+                    if ((end_cookie = strchr(cookie, ';')) != NULL)
+                        *end_cookie = '\0';
+                    if((end_cookie = strchr(cookie, ',')) != NULL)
+                        *end_cookie = '\0';
+                    return cookie;
+                }
+            }
+        }     
+    }
+    return NULL;
+}
+
+static proxy_runtime_worker *find_route_worker(proxy_balancer *balancer,
+                                               const char *route)
+{
+    int i;
+    proxy_runtime_worker *worker = (proxy_runtime_worker *)balancer->workers->elts;
+    for (i = 0; i < balancer->workers->nelts; i++) {
+        if (worker->w->route && strcmp(worker->w->route, route) == 0) {
+            return worker;
+        }
+        worker++;
+    }
+    return NULL;
+}
+
+static proxy_runtime_worker *find_session_route(proxy_balancer *balancer,
+                                                request_rec *r,
+                                                char **route,
+                                                char **url)
+{
+    if (!balancer->sticky)
+        return NULL;
+    /* Try to find the sticky route inside url */
+    *route = get_path_param(r->pool, *url, balancer->sticky);
+    if (!*route)
+        *route = get_cookie_param(r, balancer->sticky);
+    if (*route) {
+        proxy_runtime_worker *worker =  find_route_worker(balancer, *route);
+        /* TODO: make worker status codes */
+        /* See if we have a redirection route */
+        if (worker && !PROXY_WORKER_IS_USABLE(worker->w)) {
+            if (worker->w->redirect)
+                worker = find_route_worker(balancer, worker->w->redirect);
+            /* Check if the redirect worker is usable */
+            if (worker && !PROXY_WORKER_IS_USABLE(worker->w))
+                worker = NULL;
+        }
+        else
+            worker = NULL;
+        return worker;
+    }
+    else
+        return NULL;
+}
+
+static proxy_runtime_worker *find_best_worker(proxy_balancer *balancer,
+                                              request_rec *r)
+{
+    int i;
+    double total_factor = 0.0;
+    proxy_runtime_worker *worker = (proxy_runtime_worker *)balancer->workers->elts;
+    proxy_runtime_worker *candidate = NULL;
+
+    /* First try to see if we have available candidate */
+    for (i = 0; i < balancer->workers->nelts; i++) {
+        /* See if the retry timeout is ellapsed
+         * for the workers flagged as IN_ERROR
+         */
+        if (!PROXY_WORKER_IS_USABLE(worker->w))
+            ap_proxy_retry_worker("BALANCER", worker->w, r->server);
+        /* If the worker is not in error state
+         * or not disabled.
+         */
+        if (PROXY_WORKER_IS_USABLE(worker->w)) {
+            if (!candidate)
+                candidate = worker;
+            else {
+                /* See if the worker has a larger number of free channels */
+                if (worker->w->cp->nfree > candidate->w->cp->nfree)
+                    candidate = worker;
+            }
+            /* Total factor should allways be 100.
+             * This is for cases when worker is in error state.
+             * It will force the even request distribution
+             */
+            total_factor += worker->s->lbfactor;
+        }
+        worker++;
+    }
+    if (!candidate) {
+        /* All the workers are in error state or disabled.
+         * If the balancer has a timeout wait.
+         */
+#if APR_HAS_THREADS
+        if (balancer->timeout) {
+            /* XXX: This can perhaps be build using some 
+             * smarter mechanism, like tread_cond.
+             * But since the statuses can came from 
+             * different childs, use the provided algo. 
+             */
+            apr_interval_time_t timeout = balancer->timeout;
+            apr_interval_time_t step, tval = 0;
+            balancer->timeout = 0;
+            step = timeout / 100;
+            while (tval < timeout) {
+                apr_sleep(step);
+                /* Try again */
+                if ((candidate = find_best_worker(balancer, r)))
+                    break;
+                tval += step;
+            }
+            /* restore the timeout */
+            balancer->timeout = timeout;
+        }
+#endif
+    }
+    else {
+        /* We have at least one candidate that is not in
+         * error state or disabled.
+         * Now calculate the appropriate one 
+         */
+        worker = (proxy_runtime_worker *)balancer->workers->elts;
+        for (i = 0; i < balancer->workers->nelts; i++) {
+            /* If the worker is not error state
+             * or not in disabled mode
+             */
+            if (PROXY_WORKER_IS_USABLE(worker->w)) {
+                /* 1. Find the worker with higher lbstatus.
+                 * Lbstatus is of higher importance then
+                 * the number of empty slots.
+                 */
+                if (worker->s->lbstatus > candidate->s->lbstatus) {
+                    candidate = worker;
+                }
+            }
+            worker++;
+        }
+        worker = (proxy_runtime_worker *)balancer->workers->elts;
+        for (i = 0; i < balancer->workers->nelts; i++) {
+            /* If the worker is not error state
+             * or not in disabled mode
+             */
+            if (PROXY_WORKER_IS_USABLE(worker->w)) {
+                /* XXX: The lbfactor can be update using bytes transfered
+                 * Right now, use the round-robin scheme
+                 */
+                worker->s->lbstatus += worker->s->lbfactor;
+                if (worker->s->lbstatus >= total_factor)
+                    worker->s->lbstatus = worker->s->lbfactor;
+            }
+            worker++;
+        }
+    }
+    return candidate;
+}
+
+static int rewrite_url(request_rec *r, proxy_worker *worker,
+                        char **url)
+{
+    const char *scheme = strstr(*url, "://");
+    const char *path = NULL;
+    
+    if (scheme)
+        path = strchr(scheme + 3, '/');
+
+    /* we break the URL into host, port, uri */
+    if (!worker) {
+        return ap_proxyerror(r, HTTP_BAD_REQUEST, apr_pstrcat(r->pool,
+                             "missing worker. URI cannot be parsed: ", *url,
+                             NULL));
+    }
+
+    *url = apr_pstrcat(r->pool, worker->name, path, NULL);
+   
+    return OK;
+}
+
+static int proxy_balancer_pre_request(proxy_worker **worker,
+                                      proxy_balancer **balancer,
+                                      request_rec *r,
+                                      proxy_server_conf *conf, char **url)
+{
+    int access_status;
+    proxy_runtime_worker *runtime;
+    char *route;
+    apr_status_t rv;
+
+    *worker = NULL;
+    /* Spet 1: check if the url is for us */
+    if (!(*balancer = ap_proxy_get_balancer(r->pool, conf, *url)))
+        return DECLINED;
+    
+    /* Step 2: find the session route */
+    
+    runtime = find_session_route(*balancer, r, &route, url);
+    if (!runtime) {
+        if (route && (*balancer)->sticky_force) {
+            ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
+                         "proxy: BALANCER: (%s). All workers are in error state for route (%s)",
+                         (*balancer)->name, route);
+            return HTTP_SERVICE_UNAVAILABLE;
+        }
+    }
+    else {
+        int i;
+        proxy_runtime_worker *workers;
+        /* We have a sticky load balancer */
+        *worker = runtime->w;
+        /* Update the workers status 
+         * so that even session routes get
+         * into account.
+         */
+        workers = (proxy_runtime_worker *)(*balancer)->workers->elts;
+        for (i = 0; i < (*balancer)->workers->nelts; i++) {
+            /* For now assume that all workers are OK */
+            workers->s->lbstatus += workers->s->lbfactor;
+            if (workers->s->lbstatus >= 100.0)
+                workers->s->lbstatus = workers->s->lbfactor;
+            workers++;
+        }
+    }
+    /* Lock the LoadBalancer
+     * XXX: perhaps we need the process lock here
+     */
+    if ((rv = PROXY_BALANCER_LOCK(*balancer)) != APR_SUCCESS) {
+        ap_log_error(APLOG_MARK, APLOG_ERR, rv, r->server,
+                     "proxy: BALANCER: lock");
+        return DECLINED;
+    }
+    if (!*worker) {
+        runtime = find_best_worker(*balancer, r);
+        if (!runtime) {
+            ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
+                         "proxy: BALANCER: (%s). All workers are in error state",
+                         (*balancer)->name);
+        
+            PROXY_BALANCER_UNLOCK(*balancer);
+            return HTTP_SERVICE_UNAVAILABLE;
+        }
+        *worker = runtime->w;
+    }
+    /* Decrease the free channels number */
+    if ((*worker)->cp->nfree)
+        --(*worker)->cp->nfree;
+
+    PROXY_BALANCER_UNLOCK(*balancer);
+    
+    access_status = rewrite_url(r, *worker, url);
+    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+                 "proxy_balancer_pre_request rewriting to %s", *url);
+    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+                 "proxy_balancer_pre_request worker (%s) free %d",
+                 (*worker)->name,
+                 (*worker)->cp->nfree);
+
+    return access_status;
+} 
+
+static int proxy_balancer_post_request(proxy_worker *worker,
+                                       proxy_balancer *balancer,
+                                       request_rec *r,
+                                       proxy_server_conf *conf)
+{
+    int access_status;
+    if (!balancer)
+        access_status = DECLINED;
+    else { 
+        apr_status_t rv;
+        if ((rv = PROXY_BALANCER_LOCK(balancer)) != APR_SUCCESS) {
+            ap_log_error(APLOG_MARK, APLOG_ERR, rv, r->server,
+                         "proxy: BALANCER: lock");
+            return HTTP_INTERNAL_SERVER_ERROR;
+        }
+        /* increase the free channels number */
+        if (worker->cp->nfree)
+            worker->cp->nfree++;
+        /* TODO: calculate the bytes transfered */
+
+        /* TODO: update the scoreboard status */
+
+        PROXY_BALANCER_UNLOCK(balancer);        
+        access_status = OK;
+    }
+    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+             "proxy_balancer_post_request for (%s)", balancer->name);
+
+    return access_status;
+} 
+
+static void ap_proxy_balancer_register_hook(apr_pool_t *p)
+{
+    proxy_hook_pre_request(proxy_balancer_pre_request, NULL, NULL, APR_HOOK_FIRST);    
+    proxy_hook_post_request(proxy_balancer_post_request, NULL, NULL, APR_HOOK_FIRST);    
+}
+
+module AP_MODULE_DECLARE_DATA proxy_balancer_module = {
+    STANDARD20_MODULE_STUFF,
+    NULL,		/* create per-directory config structure */
+    NULL,		/* merge per-directory config structures */
+    NULL,		/* create per-server config structure */
+    NULL,		/* merge per-server config structures */
+    NULL,		/* command apr_table_t */
+    ap_proxy_balancer_register_hook	/* register hooks */
+};

Added: branches/tomcat5.5/upstream/5.5.20/connectors/ajp/proxy/proxy_connect.c
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/ajp/proxy/proxy_connect.c	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/ajp/proxy/proxy_connect.c	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,386 @@
+/* Copyright 1999-2004 The Apache Software Foundation
+ *
+ * Licensed 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.
+ */
+
+/* CONNECT method for Apache proxy */
+
+#define CORE_PRIVATE
+
+#include "mod_proxy.h"
+#include "apr_poll.h"
+
+module AP_MODULE_DECLARE_DATA proxy_connect_module;
+
+int ap_proxy_connect_canon(request_rec *r, char *url);
+int ap_proxy_connect_handler(request_rec *r, proxy_server_conf *conf, 
+                             char *url, const char *proxyname, 
+                             apr_port_t proxyport);
+
+/*  
+ * This handles Netscape CONNECT method secure proxy requests.
+ * A connection is opened to the specified host and data is
+ * passed through between the WWW site and the browser.
+ *
+ * This code is based on the INTERNET-DRAFT document
+ * "Tunneling SSL Through a WWW Proxy" currently at
+ * http://www.mcom.com/newsref/std/tunneling_ssl.html.
+ *
+ * If proxyhost and proxyport are set, we send a CONNECT to 
+ * the specified proxy..  
+ *
+ * FIXME: this doesn't log the number of bytes sent, but
+ *        that may be okay, since the data is supposed to
+ *        be transparent. In fact, this doesn't log at all
+ *        yet. 8^)
+ * FIXME: doesn't check any headers initally sent from the
+ *        client.
+ * FIXME: should allow authentication, but hopefully the
+ *        generic proxy authentication is good enough.
+ * FIXME: no check for r->assbackwards, whatever that is.
+ */
+
+static int
+allowed_port(proxy_server_conf *conf, int port)
+{
+    int i;
+    int *list = (int *) conf->allowed_connect_ports->elts;
+
+    for(i = 0; i < conf->allowed_connect_ports->nelts; i++) {
+	if(port == list[i])
+	    return 1;
+    }
+    return 0;
+}
+
+/* canonicalise CONNECT URLs. */
+int ap_proxy_connect_canon(request_rec *r, char *url)
+{
+
+    if (r->method_number != M_CONNECT) {
+	return DECLINED;
+    }
+    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+		 "proxy: CONNECT: canonicalising URL %s", url);
+
+    return OK;
+}
+
+/* CONNECT handler */
+int ap_proxy_connect_handler(request_rec *r, proxy_server_conf *conf, 
+                             char *url, const char *proxyname, 
+                             apr_port_t proxyport)
+{
+    apr_pool_t *p = r->pool;
+    apr_socket_t *sock;
+    apr_status_t err, rv;
+    apr_size_t i, o, nbytes;
+    char buffer[HUGE_STRING_LEN];
+    apr_socket_t *client_socket = ap_get_module_config(r->connection->conn_config, &core_module);
+    int failed;
+    apr_pollset_t *pollset;
+    apr_pollfd_t pollfd;
+    const apr_pollfd_t *signalled;
+    apr_int32_t pollcnt;
+    apr_int16_t pollevent;
+    apr_sockaddr_t *uri_addr, *connect_addr;
+
+    apr_uri_t uri;
+    const char *connectname;
+    int connectport = 0;
+
+    /* is this for us? */
+    if (r->method_number != M_CONNECT) {
+        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+		     "proxy: CONNECT: declining URL %s", url);
+	return DECLINED;
+    }
+    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+		 "proxy: CONNECT: serving URL %s", url);
+
+
+    /*
+     * Step One: Determine Who To Connect To
+     *
+     * Break up the URL to determine the host to connect to
+     */
+
+    /* we break the URL into host, port, uri */
+    if (APR_SUCCESS != apr_uri_parse_hostinfo(p, url, &uri)) {
+	return ap_proxyerror(r, HTTP_BAD_REQUEST,
+			     apr_pstrcat(p, "URI cannot be parsed: ", url, NULL));
+    }
+
+    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+		 "proxy: CONNECT: connecting %s to %s:%d", url, uri.hostname, uri.port);
+
+    /* do a DNS lookup for the destination host */
+    err = apr_sockaddr_info_get(&uri_addr, uri.hostname, APR_UNSPEC, uri.port, 0, p);
+
+    /* are we connecting directly, or via a proxy? */
+    if (proxyname) {
+	connectname = proxyname;
+	connectport = proxyport;
+        err = apr_sockaddr_info_get(&connect_addr, proxyname, APR_UNSPEC, proxyport, 0, p);
+    }
+    else {
+	connectname = uri.hostname;
+	connectport = uri.port;
+	connect_addr = uri_addr;
+    }
+    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+		 "proxy: CONNECT: connecting to remote proxy %s on port %d", connectname, connectport);
+
+    /* check if ProxyBlock directive on this host */
+    if (OK != ap_proxy_checkproxyblock(r, conf, uri_addr)) {
+	return ap_proxyerror(r, HTTP_FORBIDDEN,
+			     "Connect to remote machine blocked");
+    }
+
+    /* Check if it is an allowed port */
+    if (conf->allowed_connect_ports->nelts == 0) {
+	/* Default setting if not overridden by AllowCONNECT */
+	switch (uri.port) {
+	    case APR_URI_HTTPS_DEFAULT_PORT:
+	    case APR_URI_SNEWS_DEFAULT_PORT:
+		break;
+	    default:
+                /* XXX can we call ap_proxyerror() here to get a nice log message? */
+		return HTTP_FORBIDDEN;
+	}
+    } else if(!allowed_port(conf, uri.port)) {
+        /* XXX can we call ap_proxyerror() here to get a nice log message? */
+	return HTTP_FORBIDDEN;
+    }
+
+    /*
+     * Step Two: Make the Connection
+     *
+     * We have determined who to connect to. Now make the connection.
+     */
+
+    /* get all the possible IP addresses for the destname and loop through them
+     * until we get a successful connection
+     */
+    if (APR_SUCCESS != err) {
+	return ap_proxyerror(r, HTTP_BAD_GATEWAY, apr_pstrcat(p,
+                             "DNS lookup failure for: ",
+                             connectname, NULL));
+    }
+
+    /*
+     * At this point we have a list of one or more IP addresses of
+     * the machine to connect to. If configured, reorder this
+     * list so that the "best candidate" is first try. "best
+     * candidate" could mean the least loaded server, the fastest
+     * responding server, whatever.
+     *
+     * For now we do nothing, ie we get DNS round robin.
+     * XXX FIXME
+     */
+    failed = ap_proxy_connect_to_backend(&sock, "CONNECT", connect_addr,
+                                         connectname, conf, r->server,
+                                         r->pool);
+
+    /* handle a permanent error from the above loop */
+    if (failed) {
+        if (proxyname) {
+            return DECLINED;
+        }
+        else {
+            return HTTP_BAD_GATEWAY;
+        }
+    }
+
+    /*
+     * Step Three: Send the Request
+     *
+     * Send the HTTP/1.1 CONNECT request to the remote server
+     */
+
+    /* we are acting as a tunnel - the output filter stack should
+     * be completely empty, because when we are done here we are done completely.
+     * We add the NULL filter to the stack to do this...
+     */
+    r->output_filters = NULL;
+    r->connection->output_filters = NULL;
+
+
+    /* If we are connecting through a remote proxy, we need to pass
+     * the CONNECT request on to it.
+     */
+    if (proxyport) {
+	/* FIXME: Error checking ignored.
+	 */
+        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+		     "proxy: CONNECT: sending the CONNECT request to the remote proxy");
+        nbytes = apr_snprintf(buffer, sizeof(buffer),
+			      "CONNECT %s HTTP/1.0" CRLF, r->uri);
+        apr_socket_send(sock, buffer, &nbytes);
+        nbytes = apr_snprintf(buffer, sizeof(buffer),
+			      "Proxy-agent: %s" CRLF CRLF, ap_get_server_version());
+        apr_socket_send(sock, buffer, &nbytes);
+    }
+    else {
+        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+		     "proxy: CONNECT: Returning 200 OK Status");
+        nbytes = apr_snprintf(buffer, sizeof(buffer),
+			      "HTTP/1.0 200 Connection Established" CRLF);
+        ap_xlate_proto_to_ascii(buffer, nbytes);
+        apr_socket_send(client_socket, buffer, &nbytes);
+        nbytes = apr_snprintf(buffer, sizeof(buffer),
+			      "Proxy-agent: %s" CRLF CRLF, ap_get_server_version());
+        ap_xlate_proto_to_ascii(buffer, nbytes);
+        apr_socket_send(client_socket, buffer, &nbytes);
+#if 0
+        /* This is safer code, but it doesn't work yet.  I'm leaving it 
+         * here so that I can fix it later.
+         */
+        r->status = HTTP_OK;
+        r->header_only = 1;
+        apr_table_set(r->headers_out, "Proxy-agent: %s", ap_get_server_version());
+        ap_rflush(r);
+#endif
+    }
+
+    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+		 "proxy: CONNECT: setting up poll()");
+
+    /*
+     * Step Four: Handle Data Transfer
+     *
+     * Handle two way transfer of data over the socket (this is a tunnel).
+     */
+
+/*    r->sent_bodyct = 1;*/
+
+    if ((rv = apr_pollset_create(&pollset, 2, r->pool, 0)) != APR_SUCCESS)
+    {
+	apr_socket_close(sock);
+        ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
+            "proxy: CONNECT: error apr_pollset_create()");
+        return HTTP_INTERNAL_SERVER_ERROR;
+    }
+
+    /* Add client side to the poll */
+    pollfd.p = r->pool;
+    pollfd.desc_type = APR_POLL_SOCKET;
+    pollfd.reqevents = APR_POLLIN;
+    pollfd.desc.s = client_socket;
+    pollfd.client_data = NULL;
+    apr_pollset_add(pollset, &pollfd);
+
+    /* Add the server side to the poll */
+    pollfd.desc.s = sock;
+    apr_pollset_add(pollset, &pollfd);
+
+    while (1) { /* Infinite loop until error (one side closes the connection) */
+        if ((rv = apr_pollset_poll(pollset, -1, &pollcnt, &signalled)) != APR_SUCCESS) {
+	    apr_socket_close(sock);
+            ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, "proxy: CONNECT: error apr_poll()");
+            return HTTP_INTERNAL_SERVER_ERROR;
+        }
+/*	ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+                     "proxy: CONNECT: woke from select(), i=%d", pollcnt);*/
+
+        for (i = 0; i < pollcnt; i++) {
+            const apr_pollfd_t *cur = &signalled[i];
+
+            if (cur->desc.s == sock) {
+                pollevent = cur->rtnevents;
+                if (pollevent & APR_POLLIN) {
+/*		ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+                             "proxy: CONNECT: sock was set");*/
+                    nbytes = sizeof(buffer);
+                    if (apr_socket_recv(sock, buffer, &nbytes) == APR_SUCCESS) {
+                        o = 0;
+                        i = nbytes;
+                        while(i > 0)
+                        {
+                            nbytes = i;
+    /* This is just plain wrong.  No module should ever write directly
+     * to the client.  For now, this works, but this is high on my list of
+     * things to fix.  The correct line is:
+     * if ((nbytes = ap_rwrite(buffer + o, nbytes, r)) < 0)
+     * rbb
+     */
+                            if (apr_socket_send(client_socket, buffer + o, &nbytes) != APR_SUCCESS)
+                                break;
+                            o += nbytes;
+                            i -= nbytes;
+                        }
+                    }
+                    else
+                        break;
+                }
+                else if ((pollevent & APR_POLLERR) || (pollevent & APR_POLLHUP))
+                    break;
+            }
+            else if (cur->desc.s == client_socket) {
+                pollevent = cur->rtnevents;
+                if (pollevent & APR_POLLIN) {
+/*		ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+                             "proxy: CONNECT: client was set");*/
+                    nbytes = sizeof(buffer);
+                    if (apr_socket_recv(client_socket, buffer, &nbytes) == APR_SUCCESS) {
+                        o = 0;
+                        i = nbytes;
+                        while(i > 0)
+                        {
+                            nbytes = i;
+                            if (apr_socket_send(sock, buffer + o, &nbytes) != APR_SUCCESS)
+                                break;
+                            o += nbytes;
+                            i -= nbytes;
+                        }
+                    }
+                    else
+                        break;
+                }
+                else if ((pollevent & APR_POLLERR) || (pollevent & APR_POLLHUP))
+                    break;
+            }
+            else
+                break;
+        }
+    }
+
+    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+		 "proxy: CONNECT: finished with poll() - cleaning up");
+
+    /*
+     * Step Five: Clean Up
+     *
+     * Close the socket and clean up
+     */
+
+    apr_socket_close(sock);
+
+    return OK;
+}
+
+static void ap_proxy_connect_register_hook(apr_pool_t *p)
+{
+    proxy_hook_scheme_handler(ap_proxy_connect_handler, NULL, NULL, APR_HOOK_MIDDLE);
+    proxy_hook_canon_handler(ap_proxy_connect_canon, NULL, NULL, APR_HOOK_MIDDLE);
+}
+
+module AP_MODULE_DECLARE_DATA proxy_connect_module = {
+    STANDARD20_MODULE_STUFF,
+    NULL,		/* create per-directory config structure */
+    NULL,		/* merge per-directory config structures */
+    NULL,		/* create per-server config structure */
+    NULL,		/* merge per-server config structures */
+    NULL,		/* command apr_table_t */
+    ap_proxy_connect_register_hook	/* register hooks */
+};

Added: branches/tomcat5.5/upstream/5.5.20/connectors/ajp/proxy/proxy_ftp.c
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/ajp/proxy/proxy_ftp.c	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/ajp/proxy/proxy_ftp.c	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,1869 @@
+/* Copyright 1999-2004 The Apache Software Foundation
+ *
+ * Licensed 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.
+ */
+
+/* FTP routines for Apache proxy */
+
+#include "mod_proxy.h"
+#if APR_HAVE_TIME_H
+#include <time.h>
+#endif
+#include "apr_version.h"
+
+#if (APR_MAJOR_VERSION < 1)
+#undef apr_socket_create
+#define apr_socket_create apr_socket_create_ex
+#endif
+
+#define AUTODETECT_PWD
+/* Automatic timestamping (Last-Modified header) based on MDTM is used if:
+ * 1) the FTP server supports the MDTM command and
+ * 2) HAVE_TIMEGM (preferred) or HAVE_GMTOFF is available at compile time
+ */
+#define USE_MDTM
+
+
+module AP_MODULE_DECLARE_DATA proxy_ftp_module;
+
+int ap_proxy_ftp_canon(request_rec *r, char *url);
+int ap_proxy_ftp_handler(request_rec *r, proxy_worker *worker, proxy_server_conf *conf,
+                             char *url, const char *proxyhost,
+                             apr_port_t proxyport);
+apr_status_t ap_proxy_send_dir_filter(ap_filter_t * f,
+                                                   apr_bucket_brigade *bb);
+
+
+/*
+ * Decodes a '%' escaped string, and returns the number of characters
+ */
+static int decodeenc(char *x)
+{
+    int i, j, ch;
+
+    if (x[0] == '\0')
+        return 0;               /* special case for no characters */
+    for (i = 0, j = 0; x[i] != '\0'; i++, j++) {
+        /* decode it if not already done */
+        ch = x[i];
+        if (ch == '%' && apr_isxdigit(x[i + 1]) && apr_isxdigit(x[i + 2])) {
+            ch = ap_proxy_hex2c(&x[i + 1]);
+            i += 2;
+        }
+        x[j] = ch;
+    }
+    x[j] = '\0';
+    return j;
+}
+
+/*
+ * Escape the globbing characters in a path used as argument to
+ * the FTP commands (SIZE, CWD, RETR, MDTM, ...).
+ * ftpd assumes '\\' as a quoting character to escape special characters.
+ * Returns: escaped string
+ */
+#define FTP_GLOBBING_CHARS "*?[{~"
+static char *ftp_escape_globbingchars(apr_pool_t *p, const char *path)
+{
+    char *ret = apr_palloc(p, 2*strlen(path)+sizeof(""));
+    char *d;
+    for (d = ret; *path; ++path) {
+        if (strchr(FTP_GLOBBING_CHARS, *path) != NULL)
+            *d++ = '\\';
+        *d++ = *path;
+    }
+    *d = '\0';
+    return ret;
+}
+
+/*
+ * Check for globbing characters in a path used as argument to
+ * the FTP commands (SIZE, CWD, RETR, MDTM, ...).
+ * ftpd assumes '\\' as a quoting character to escape special characters.
+ * Returns: 0 (no globbing chars, or all globbing chars escaped), 1 (globbing chars)
+ */
+static int ftp_check_globbingchars(const char *path)
+{
+    for ( ; *path; ++path) {
+        if (*path == '\\')
+	    ++path;
+        if (path != '\0' && strchr(FTP_GLOBBING_CHARS, *path) != NULL)
+            return TRUE;
+    }
+    return FALSE;
+}
+
+/*
+ * checks an encoded ftp string for bad characters, namely, CR, LF or
+ * non-ascii character
+ */
+static int ftp_check_string(const char *x)
+{
+    int i, ch = 0;
+#if APR_CHARSET_EBCDIC
+    char buf[1];
+#endif
+
+    for (i = 0; x[i] != '\0'; i++) {
+        ch = x[i];
+        if (ch == '%' && apr_isxdigit(x[i + 1]) && apr_isxdigit(x[i + 2])) {
+            ch = ap_proxy_hex2c(&x[i + 1]);
+            i += 2;
+        }
+#if !APR_CHARSET_EBCDIC
+        if (ch == '\015' || ch == '\012' || (ch & 0x80))
+#else                           /* APR_CHARSET_EBCDIC */
+        if (ch == '\r' || ch == '\n')
+            return 0;
+        buf[0] = ch;
+        ap_xlate_proto_to_ascii(buf, 1);
+        if (buf[0] & 0x80)
+#endif                          /* APR_CHARSET_EBCDIC */
+            return 0;
+    }
+    return 1;
+}
+
+/*
+ * Canonicalise ftp URLs.
+ */
+int ap_proxy_ftp_canon(request_rec *r, char *url)
+{
+    char *user, *password, *host, *path, *parms, *strp, sport[7];
+    apr_pool_t *p = r->pool;
+    const char *err;
+    apr_port_t port, def_port;
+
+    /* */
+    if (strncasecmp(url, "ftp:", 4) == 0) {
+        url += 4;
+    }
+    else {
+        return DECLINED;
+    }
+    def_port = apr_uri_port_of_scheme("ftp");
+
+    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+                 "proxy: FTP: canonicalising URL %s", url);
+
+    port = def_port;
+    err = ap_proxy_canon_netloc(p, &url, &user, &password, &host, &port);
+    if (err)
+        return HTTP_BAD_REQUEST;
+    if (user != NULL && !ftp_check_string(user))
+        return HTTP_BAD_REQUEST;
+    if (password != NULL && !ftp_check_string(password))
+        return HTTP_BAD_REQUEST;
+
+    /* now parse path/parameters args, according to rfc1738 */
+    /*
+     * N.B. if this isn't a true proxy request, then the URL path (but not
+     * query args) has already been decoded. This gives rise to the problem
+     * of a ; being decoded into the path.
+     */
+    strp = strchr(url, ';');
+    if (strp != NULL) {
+        *(strp++) = '\0';
+        parms = ap_proxy_canonenc(p, strp, strlen(strp), enc_parm,
+                                  r->proxyreq);
+        if (parms == NULL)
+            return HTTP_BAD_REQUEST;
+    }
+    else
+        parms = "";
+
+    path = ap_proxy_canonenc(p, url, strlen(url), enc_path, r->proxyreq);
+    if (path == NULL)
+        return HTTP_BAD_REQUEST;
+    if (!ftp_check_string(path))
+        return HTTP_BAD_REQUEST;
+
+    if (r->proxyreq && r->args != NULL) {
+        if (strp != NULL) {
+            strp = ap_proxy_canonenc(p, r->args, strlen(r->args), enc_parm, 1);
+            if (strp == NULL)
+                return HTTP_BAD_REQUEST;
+            parms = apr_pstrcat(p, parms, "?", strp, NULL);
+        }
+        else {
+            strp = ap_proxy_canonenc(p, r->args, strlen(r->args), enc_fpath, 1);
+            if (strp == NULL)
+                return HTTP_BAD_REQUEST;
+            path = apr_pstrcat(p, path, "?", strp, NULL);
+        }
+        r->args = NULL;
+    }
+
+/* now, rebuild URL */
+
+    if (port != def_port)
+        apr_snprintf(sport, sizeof(sport), ":%d", port);
+    else
+        sport[0] = '\0';
+
+    if (ap_strchr_c(host, ':')) { /* if literal IPv6 address */
+        host = apr_pstrcat(p, "[", host, "]", NULL);
+    }
+    r->filename = apr_pstrcat(p, "proxy:ftp://", (user != NULL) ? user : "",
+                              (password != NULL) ? ":" : "",
+                              (password != NULL) ? password : "",
+                          (user != NULL) ? "@" : "", host, sport, "/", path,
+                              (parms[0] != '\0') ? ";" : "", parms, NULL);
+
+    return OK;
+}
+
+/* we chop lines longer than 80 characters */
+#define MAX_LINE_LEN 80
+
+/*
+ * Reads response lines, returns both the ftp status code and
+ * remembers the response message in the supplied buffer
+ */
+static int ftp_getrc_msg(conn_rec *ftp_ctrl, apr_bucket_brigade *bb, char *msgbuf, int msglen)
+{
+    int status;
+    char response[MAX_LINE_LEN];
+    char buff[5];
+    char *mb = msgbuf, *me = &msgbuf[msglen];
+    apr_status_t rv;
+    int eos;
+
+    if (APR_SUCCESS != (rv = ap_proxy_string_read(ftp_ctrl, bb, response, sizeof(response), &eos))) {
+        return -1;
+    }
+/*
+    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, NULL,
+                 "proxy: <FTP: %s", response);
+*/
+    if (!apr_isdigit(response[0]) || !apr_isdigit(response[1]) ||
+    !apr_isdigit(response[2]) || (response[3] != ' ' && response[3] != '-'))
+        status = 0;
+    else
+        status = 100 * response[0] + 10 * response[1] + response[2] - 111 * '0';
+
+    mb = apr_cpystrn(mb, response + 4, me - mb);
+
+    if (response[3] == '-') {
+        memcpy(buff, response, 3);
+        buff[3] = ' ';
+        do {
+            if (APR_SUCCESS != (rv = ap_proxy_string_read(ftp_ctrl, bb, response, sizeof(response), &eos))) {
+                return -1;
+            }
+            mb = apr_cpystrn(mb, response + (' ' == response[0] ? 1 : 4), me - mb);
+        } while (memcmp(response, buff, 4) != 0);
+    }
+
+    return status;
+}
+
+/* this is a filter that turns a raw ASCII directory listing into pretty HTML */
+
+/* ideally, mod_proxy should simply send the raw directory list up the filter
+ * stack to mod_autoindex, which in theory should turn the raw ascii into
+ * pretty html along with all the bells and whistles it provides...
+ *
+ * all in good time...! :)
+ */
+
+typedef struct {
+    apr_bucket_brigade *in;
+    char buffer[MAX_STRING_LEN];
+    enum {
+        HEADER, BODY, FOOTER
+    }    state;
+}      proxy_dir_ctx_t;
+
+/* fallback regex for ls -s1;  ($0..$2) == 3 */
+#define LS_REG_PATTERN "^ *([0-9]+) +([^ ]+)$"
+#define LS_REG_MATCH   3
+
+apr_status_t ap_proxy_send_dir_filter(ap_filter_t *f, apr_bucket_brigade *in)
+{
+    request_rec *r = f->r;
+    conn_rec *c = r->connection;
+    apr_pool_t *p = r->pool;
+    apr_bucket_brigade *out = apr_brigade_create(p, c->bucket_alloc);
+    apr_status_t rv;
+
+    register int n;
+    char *dir, *path, *reldir, *site, *str, *type;
+
+    const char *pwd = apr_table_get(r->notes, "Directory-PWD");
+    const char *readme = apr_table_get(r->notes, "Directory-README");
+
+    proxy_dir_ctx_t *ctx = f->ctx;
+
+    if (!ctx) {
+        f->ctx = ctx = apr_pcalloc(p, sizeof(*ctx));
+        ctx->in = apr_brigade_create(p, c->bucket_alloc);
+        ctx->buffer[0] = 0;
+        ctx->state = HEADER;
+    }
+
+    /* combine the stored and the new */
+    APR_BRIGADE_CONCAT(ctx->in, in);
+
+    if (HEADER == ctx->state) {
+
+        /* basedir is either "", or "/%2f" for the "squid %2f hack" */
+        const char *basedir = "";  /* By default, path is relative to the $HOME dir */
+        char *wildcard = NULL;
+
+        /* Save "scheme://site" prefix without password */
+        site = apr_uri_unparse(p, &f->r->parsed_uri, APR_URI_UNP_OMITPASSWORD | APR_URI_UNP_OMITPATHINFO);
+        /* ... and path without query args */
+        path = apr_uri_unparse(p, &f->r->parsed_uri, APR_URI_UNP_OMITSITEPART | APR_URI_UNP_OMITQUERY);
+
+        /* If path began with /%2f, change the basedir */
+        if (strncasecmp(path, "/%2f", 4) == 0) {
+            basedir = "/%2f";
+        }
+
+        /* Strip off a type qualifier. It is ignored for dir listings */
+        if ((type = strstr(path, ";type=")) != NULL)
+            *type++ = '\0';
+
+        (void)decodeenc(path);
+
+        while (path[1] == '/') /* collapse multiple leading slashes to one */
+            ++path;
+
+        reldir = strrchr(path, '/');
+        if (reldir != NULL && ftp_check_globbingchars(reldir)) {
+            wildcard = &reldir[1];
+            reldir[0] = '\0'; /* strip off the wildcard suffix */
+        }
+
+        /* Copy path, strip (all except the last) trailing slashes */
+        /* (the trailing slash is needed for the dir component loop below) */
+        path = dir = apr_pstrcat(p, path, "/", NULL);
+        for (n = strlen(path); n > 1 && path[n - 1] == '/' && path[n - 2] == '/'; --n)
+            path[n - 1] = '\0';
+
+        /* Add a link to the root directory (if %2f hack was used) */
+        str = (basedir[0] != '\0') ? "<a href=\"/%2f/\">%2f</a>/" : "";
+
+        /* print "ftp://host/" */
+        str = apr_psprintf(p, DOCTYPE_HTML_3_2
+                "<html>\n <head>\n  <title>%s%s%s</title>\n"
+                "  <base href=\"%s%s%s\">\n </head>\n"
+                " <body>\n  <h2>Directory of "
+                "<a href=\"/\">%s</a>/%s",
+                site, basedir, ap_escape_html(p, path),
+                site, basedir, ap_escape_uri(p, path),
+                site, str);
+
+        APR_BRIGADE_INSERT_TAIL(out, apr_bucket_pool_create(str, strlen(str),
+                                                          p, c->bucket_alloc));
+
+        for (dir = path+1; (dir = strchr(dir, '/')) != NULL; )
+        {
+            *dir = '\0';
+            if ((reldir = strrchr(path+1, '/'))==NULL) {
+                reldir = path+1;
+            }
+            else
+                ++reldir;
+            /* print "path/" component */
+            str = apr_psprintf(p, "<a href=\"%s%s/\">%s</a>/", basedir,
+                        ap_escape_uri(p, path),
+                        ap_escape_html(p, reldir));
+            *dir = '/';
+            while (*dir == '/')
+              ++dir;
+            APR_BRIGADE_INSERT_TAIL(out, apr_bucket_pool_create(str,
+                                                           strlen(str), p,
+                                                           c->bucket_alloc));
+        }
+        if (wildcard != NULL) {
+            APR_BRIGADE_INSERT_TAIL(out, apr_bucket_pool_create(wildcard,
+                                                           strlen(wildcard), p,
+                                                           c->bucket_alloc));
+        }
+
+        /* If the caller has determined the current directory, and it differs */
+        /* from what the client requested, then show the real name */
+        if (pwd == NULL || strncmp(pwd, path, strlen(pwd)) == 0) {
+            str = apr_psprintf(p, "</h2>\n\n  <hr />\n\n<pre>");
+        }
+        else {
+            str = apr_psprintf(p, "</h2>\n\n(%s)\n\n  <hr />\n\n<pre>",
+                               ap_escape_html(p, pwd));
+        }
+        APR_BRIGADE_INSERT_TAIL(out, apr_bucket_pool_create(str, strlen(str),
+                                                           p, c->bucket_alloc));
+
+        /* print README */
+        if (readme) {
+            str = apr_psprintf(p, "%s\n</pre>\n\n<hr />\n\n<pre>\n",
+                               ap_escape_html(p, readme));
+
+            APR_BRIGADE_INSERT_TAIL(out, apr_bucket_pool_create(str,
+                                                           strlen(str), p,
+                                                           c->bucket_alloc));
+        }
+
+        /* make sure page intro gets sent out */
+        APR_BRIGADE_INSERT_TAIL(out, apr_bucket_flush_create(c->bucket_alloc));
+        if (APR_SUCCESS != (rv = ap_pass_brigade(f->next, out))) {
+            return rv;
+        }
+        apr_brigade_cleanup(out);
+
+        ctx->state = BODY;
+    }
+
+    /* loop through each line of directory */
+    while (BODY == ctx->state) {
+        char *filename;
+        int found = 0;
+        int eos = 0;
+
+        regex_t *re = NULL;
+        regmatch_t re_result[LS_REG_MATCH];
+
+        /* Compile the output format of "ls -s1" as a fallback for non-unix ftp listings */
+        re = ap_pregcomp(p, LS_REG_PATTERN, REG_EXTENDED);
+        ap_assert(re != NULL);
+
+        /* get a complete line */
+        /* if the buffer overruns - throw data away */
+        while (!found && !APR_BRIGADE_EMPTY(ctx->in)) {
+            char *pos, *response;
+            apr_size_t len, max;
+            apr_bucket *e;
+
+            e = APR_BRIGADE_FIRST(ctx->in);
+            if (APR_BUCKET_IS_EOS(e)) {
+                eos = 1;
+                break;
+            }
+            if (APR_SUCCESS != (rv = apr_bucket_read(e, (const char **)&response, &len, APR_BLOCK_READ))) {
+                return rv;
+            }
+            pos = memchr(response, APR_ASCII_LF, len);
+            if (pos != NULL) {
+                if ((response + len) != (pos + 1)) {
+                    len = pos - response + 1;
+                    apr_bucket_split(e, pos - response + 1);
+                }
+                found = 1;
+            }
+            max = sizeof(ctx->buffer) - strlen(ctx->buffer) - 1;
+            if (len > max) {
+                len = max;
+            }
+
+            /* len+1 to leave space for the trailing nil char */
+            apr_cpystrn(ctx->buffer+strlen(ctx->buffer), response, len+1);
+
+            APR_BUCKET_REMOVE(e);
+            apr_bucket_destroy(e);
+        }
+
+        /* EOS? jump to footer */
+        if (eos) {
+            ctx->state = FOOTER;
+            break;
+        }
+
+        /* not complete? leave and try get some more */
+        if (!found) {
+            return APR_SUCCESS;
+        }
+
+        {
+            apr_size_t n = strlen(ctx->buffer);
+            if (ctx->buffer[n-1] == CRLF[1])  /* strip trailing '\n' */
+                ctx->buffer[--n] = '\0';
+            if (ctx->buffer[n-1] == CRLF[0])  /* strip trailing '\r' if present */
+                ctx->buffer[--n] = '\0';
+        }
+
+        /* a symlink? */
+        if (ctx->buffer[0] == 'l' && (filename = strstr(ctx->buffer, " -> ")) != NULL) {
+            char *link_ptr = filename;
+
+            do {
+                filename--;
+            } while (filename[0] != ' ' && filename > ctx->buffer);
+            if (filename > ctx->buffer)
+                *(filename++) = '\0';
+            *(link_ptr++) = '\0';
+            str = apr_psprintf(p, "%s <a href=\"%s\">%s %s</a>\n",
+                               ap_escape_html(p, ctx->buffer),
+                               ap_escape_uri(p, filename),
+                               ap_escape_html(p, filename),
+                               ap_escape_html(p, link_ptr));
+        }
+
+        /* a directory/file? */
+        else if (ctx->buffer[0] == 'd' || ctx->buffer[0] == '-' || ctx->buffer[0] == 'l' || apr_isdigit(ctx->buffer[0])) {
+            int searchidx = 0;
+            char *searchptr = NULL;
+            int firstfile = 1;
+            if (apr_isdigit(ctx->buffer[0])) {  /* handle DOS dir */
+                searchptr = strchr(ctx->buffer, '<');
+                if (searchptr != NULL)
+                    *searchptr = '[';
+                searchptr = strchr(ctx->buffer, '>');
+                if (searchptr != NULL)
+                    *searchptr = ']';
+            }
+
+            filename = strrchr(ctx->buffer, ' ');
+            *(filename++) = '\0';
+
+            /* handle filenames with spaces in 'em */
+            if (!strcmp(filename, ".") || !strcmp(filename, "..") || firstfile) {
+                firstfile = 0;
+                searchidx = filename - ctx->buffer;
+            }
+            else if (searchidx != 0 && ctx->buffer[searchidx] != 0) {
+                *(--filename) = ' ';
+                ctx->buffer[searchidx - 1] = '\0';
+                filename = &ctx->buffer[searchidx];
+            }
+
+            /* Append a slash to the HREF link for directories */
+            if (!strcmp(filename, ".") || !strcmp(filename, "..") || ctx->buffer[0] == 'd') {
+                str = apr_psprintf(p, "%s <a href=\"%s/\">%s</a>\n",
+                                   ap_escape_html(p, ctx->buffer),
+                                   ap_escape_uri(p, filename),
+                                   ap_escape_html(p, filename));
+            }
+            else {
+                str = apr_psprintf(p, "%s <a href=\"%s\">%s</a>\n",
+                                   ap_escape_html(p, ctx->buffer),
+                                   ap_escape_uri(p, filename),
+                                   ap_escape_html(p, filename));
+            }
+        }
+        /* Try a fallback for listings in the format of "ls -s1" */
+        else if (0 == ap_regexec(re, ctx->buffer, LS_REG_MATCH, re_result, 0)) {
+
+            filename = apr_pstrndup(p, &ctx->buffer[re_result[2].rm_so], re_result[2].rm_eo - re_result[2].rm_so);
+
+            str = apr_pstrcat(p, ap_escape_html(p, apr_pstrndup(p, ctx->buffer, re_result[2].rm_so)),
+                              "<a href=\"", ap_escape_uri(p, filename), "\">",
+                              ap_escape_html(p, filename), "</a>\n", NULL);
+        }
+        else {
+            strcat(ctx->buffer, "\n"); /* re-append the newline */
+            str = ap_escape_html(p, ctx->buffer);
+        }
+
+        /* erase buffer for next time around */
+        ctx->buffer[0] = 0;
+
+        APR_BRIGADE_INSERT_TAIL(out, apr_bucket_pool_create(str, strlen(str), p,
+                                                            c->bucket_alloc));
+        APR_BRIGADE_INSERT_TAIL(out, apr_bucket_flush_create(c->bucket_alloc));
+        if (APR_SUCCESS != (rv = ap_pass_brigade(f->next, out))) {
+            return rv;
+        }
+        apr_brigade_cleanup(out);
+
+    }
+
+    if (FOOTER == ctx->state) {
+        str = apr_psprintf(p, "</pre>\n\n  <hr />\n\n  %s\n\n </body>\n</html>\n", ap_psignature("", r));
+        APR_BRIGADE_INSERT_TAIL(out, apr_bucket_pool_create(str, strlen(str), p,
+                                                            c->bucket_alloc));
+        APR_BRIGADE_INSERT_TAIL(out, apr_bucket_flush_create(c->bucket_alloc));
+        APR_BRIGADE_INSERT_TAIL(out, apr_bucket_eos_create(c->bucket_alloc));
+        if (APR_SUCCESS != (rv = ap_pass_brigade(f->next, out))) {
+            return rv;
+        }
+        apr_brigade_destroy(out);
+    }
+
+    return APR_SUCCESS;
+}
+
+/*
+ * Generic "send FTP command to server" routine, using the control socket.
+ * Returns the FTP returncode (3 digit code)
+ * Allows for tracing the FTP protocol (in LogLevel debug)
+ */
+static int
+proxy_ftp_command(const char *cmd, request_rec *r, conn_rec *ftp_ctrl,
+                  apr_bucket_brigade *bb, char **pmessage)
+{
+    char *crlf;
+    int rc;
+    char message[HUGE_STRING_LEN];
+
+    /* If cmd == NULL, we retrieve the next ftp response line */
+    if (cmd != NULL) {
+        conn_rec *c = r->connection;
+        APR_BRIGADE_INSERT_TAIL(bb, apr_bucket_pool_create(cmd, strlen(cmd), r->pool, c->bucket_alloc));
+        APR_BRIGADE_INSERT_TAIL(bb, apr_bucket_flush_create(c->bucket_alloc));
+        ap_pass_brigade(ftp_ctrl->output_filters, bb);
+
+        /* strip off the CRLF for logging */
+        apr_cpystrn(message, cmd, sizeof(message));
+        if ((crlf = strchr(message, '\r')) != NULL ||
+            (crlf = strchr(message, '\n')) != NULL)
+            *crlf = '\0';
+        if (strncmp(message,"PASS ", 5) == 0)
+            strcpy(&message[5], "****");
+        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+                     "proxy:>FTP: %s", message);
+    }
+
+    rc = ftp_getrc_msg(ftp_ctrl, bb, message, sizeof message);
+    if (rc == -1 || rc == 421)
+        strcpy(message,"<unable to read result>");
+    if ((crlf = strchr(message, '\r')) != NULL ||
+        (crlf = strchr(message, '\n')) != NULL)
+        *crlf = '\0';
+    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+                 "proxy:<FTP: %3.3u %s", rc, message);
+
+    if (pmessage != NULL)
+        *pmessage = apr_pstrdup(r->pool, message);
+
+    return rc;
+}
+
+/* Set ftp server to TYPE {A,I,E} before transfer of a directory or file */
+static int ftp_set_TYPE(char xfer_type, request_rec *r, conn_rec *ftp_ctrl,
+                  apr_bucket_brigade *bb, char **pmessage)
+{
+    char old_type[2] = { 'A', '\0' }; /* After logon, mode is ASCII */
+    int ret = HTTP_OK;
+    int rc;
+
+    /* set desired type */
+    old_type[0] = xfer_type;
+
+    rc = proxy_ftp_command(apr_pstrcat(r->pool, "TYPE ", old_type, CRLF, NULL),
+                           r, ftp_ctrl, bb, pmessage);
+/* responses: 200, 421, 500, 501, 504, 530 */
+    /* 200 Command okay. */
+    /* 421 Service not available, closing control connection. */
+    /* 500 Syntax error, command unrecognized. */
+    /* 501 Syntax error in parameters or arguments. */
+    /* 504 Command not implemented for that parameter. */
+    /* 530 Not logged in. */
+    if (rc == -1 || rc == 421) {
+        ret = ap_proxyerror(r, HTTP_BAD_GATEWAY,
+                             "Error reading from remote server");
+    }
+    else if (rc != 200 && rc != 504) {
+        ret = ap_proxyerror(r, HTTP_BAD_GATEWAY,
+                             "Unable to set transfer type");
+    }
+/* Allow not implemented */
+    else if (rc == 504)
+        /* ignore it silently */;
+
+    return ret;
+}
+
+
+/* Return the current directory which we have selected on the FTP server, or NULL */
+static char *ftp_get_PWD(request_rec *r, conn_rec *ftp_ctrl, apr_bucket_brigade *bb)
+{
+    char *cwd = NULL;
+    char *ftpmessage = NULL;
+
+    /* responses: 257, 500, 501, 502, 421, 550 */
+    /* 257 "<directory-name>" <commentary> */
+    /* 421 Service not available, closing control connection. */
+    /* 500 Syntax error, command unrecognized. */
+    /* 501 Syntax error in parameters or arguments. */
+    /* 502 Command not implemented. */
+    /* 550 Requested action not taken. */
+    switch (proxy_ftp_command("PWD" CRLF, r, ftp_ctrl, bb, &ftpmessage)) {
+        case -1:
+        case 421:
+        case 550:
+            ap_proxyerror(r, HTTP_BAD_GATEWAY,
+                             "Failed to read PWD on ftp server");
+            break;
+
+        case 257: {
+            const char *dirp = ftpmessage;
+            cwd = ap_getword_conf(r->pool, &dirp);
+        }
+    }
+    return cwd;
+}
+
+
+/* Common routine for failed authorization (i.e., missing or wrong password)
+ * to an ftp service. This causes most browsers to retry the request
+ * with username and password (which was presumably queried from the user)
+ * supplied in the Authorization: header.
+ * Note that we "invent" a realm name which consists of the
+ * ftp://user@host part of the reqest (sans password -if supplied but invalid-)
+ */
+static int ftp_unauthorized(request_rec *r, int log_it)
+{
+    r->proxyreq = PROXYREQ_NONE;
+    /*
+     * Log failed requests if they supplied a password (log username/password
+     * guessing attempts)
+     */
+    if (log_it)
+        ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
+                      "proxy: missing or failed auth to %s",
+                      apr_uri_unparse(r->pool,
+                                 &r->parsed_uri, APR_URI_UNP_OMITPATHINFO));
+
+    apr_table_setn(r->err_headers_out, "WWW-Authenticate",
+                   apr_pstrcat(r->pool, "Basic realm=\"",
+                               apr_uri_unparse(r->pool, &r->parsed_uri,
+                       APR_URI_UNP_OMITPASSWORD | APR_URI_UNP_OMITPATHINFO),
+                               "\"", NULL));
+
+    return HTTP_UNAUTHORIZED;
+}
+
+static
+apr_status_t proxy_ftp_cleanup(request_rec *r, proxy_conn_rec *backend)
+{
+
+    backend->close_on_recycle = 1;
+    ap_set_module_config(r->connection->conn_config, &proxy_ftp_module, NULL);
+    ap_proxy_release_connection("FTP", backend, r->server);    
+
+    return OK;
+}
+
+static ftp_proxyerror(request_rec *r, proxy_conn_rec *conn, int statuscode, const char *message)
+{
+    proxy_ftp_cleanup(r, conn);
+    return ap_proxyerror(r, statuscode, message);
+}
+/*
+ * Handles direct access of ftp:// URLs
+ * Original (Non-PASV) version from
+ * Troy Morrison <spiffnet at zoom.com>
+ * PASV added by Chuck
+ * Filters by [Graham Leggett <minfrin at sharp.fm>]
+ */
+int ap_proxy_ftp_handler(request_rec *r, proxy_worker *worker, proxy_server_conf *conf,
+                             char *url, const char *proxyhost,
+                             apr_port_t proxyport)
+{
+    apr_pool_t *p = r->pool;
+    conn_rec *c = r->connection;
+    proxy_conn_rec *backend;
+    apr_socket_t *sock, *local_sock, *data_sock = NULL;
+    apr_sockaddr_t *connect_addr;
+    apr_status_t rv;
+    conn_rec *origin, *data = NULL;
+    apr_status_t err = APR_SUCCESS;
+    apr_bucket_brigade *bb = apr_brigade_create(p, c->bucket_alloc);
+    char *buf, *connectname;
+    apr_port_t connectport;
+    char buffer[MAX_STRING_LEN];
+    char *ftpmessage = NULL;
+    char *path, *strp, *type_suffix, *cwd = NULL;
+    apr_uri_t uri; 
+    char *user = NULL;
+/*    char *account = NULL; how to supply an account in a URL? */
+    const char *password = NULL;
+    int len, rc;
+    int one = 1;
+    char *size = NULL;
+    apr_socket_t *origin_sock = NULL;
+    char xfer_type = 'A'; /* after ftp login, the default is ASCII */
+    int  dirlisting = 0;
+#if defined(USE_MDTM) && (defined(HAVE_TIMEGM) || defined(HAVE_GMTOFF))
+    apr_time_t mtime = 0L;
+#endif
+
+    /* stuff for PASV mode */
+    int connect = 0, use_port = 0;
+    char dates[APR_RFC822_DATE_LEN];
+    int status;
+
+    /* is this for us? */
+    if (proxyhost) {
+        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+                     "proxy: FTP: declining URL %s - proxyhost %s specified:", url, proxyhost);
+        return DECLINED;        /* proxy connections are via HTTP */
+    }
+    if (strncasecmp(url, "ftp:", 4)) {
+        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+                     "proxy: FTP: declining URL %s - not ftp:", url);
+        return DECLINED;        /* only interested in FTP */
+    }
+    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+                 "proxy: FTP: serving URL %s", url);
+
+
+    /*
+     * I: Who Do I Connect To? -----------------------
+     *
+     * Break up the URL to determine the host to connect to
+     */
+
+    /* we only support GET and HEAD */
+    if (r->method_number != M_GET)
+        return HTTP_NOT_IMPLEMENTED;
+
+    /* We break the URL into host, port, path-search */
+    if (r->parsed_uri.hostname == NULL) {
+        if (APR_SUCCESS != apr_uri_parse(p, url, &uri)) {
+            return ap_proxyerror(r, HTTP_BAD_REQUEST,
+                apr_psprintf(p, "URI cannot be parsed: %s", url));
+        }
+        connectname = uri.hostname;
+        connectport = uri.port;
+        path = apr_pstrdup(p, uri.path);
+    }
+    else {
+        connectname = r->parsed_uri.hostname;
+        connectport = r->parsed_uri.port;
+        path = apr_pstrdup(p, r->parsed_uri.path);
+    }
+    if (connectport == 0) {
+        connectport = apr_uri_port_of_scheme("ftp");
+    }
+    path = (path != NULL && path[0] != '\0') ? &path[1] : "";
+
+    type_suffix = strchr(path, ';');
+    if (type_suffix != NULL)
+        *(type_suffix++) = '\0';
+
+    if (type_suffix != NULL && strncmp(type_suffix, "type=", 5) == 0
+        && apr_isalpha(type_suffix[5])) {
+        /* "type=d" forces a dir listing.
+         * The other types (i|a|e) are directly used for the ftp TYPE command
+         */
+        if ( ! (dirlisting = (apr_tolower(type_suffix[5]) == 'd')))
+            xfer_type = apr_toupper(type_suffix[5]);
+
+        /* Check valid types, rather than ignoring invalid types silently: */
+        if (strchr("AEI", xfer_type) == NULL)
+            return ap_proxyerror(r, HTTP_BAD_REQUEST, apr_pstrcat(r->pool,
+                                    "ftp proxy supports only types 'a', 'i', or 'e': \"",
+                                    type_suffix, "\" is invalid.", NULL));
+    }
+    else {
+        /* make binary transfers the default */
+        xfer_type = 'I';
+    }
+
+
+    /*
+     * The "Authorization:" header must be checked first. We allow the user
+     * to "override" the URL-coded user [ & password ] in the Browsers'
+     * User&Password Dialog. NOTE that this is only marginally more secure
+     * than having the password travel in plain as part of the URL, because
+     * Basic Auth simply uuencodes the plain text password. But chances are
+     * still smaller that the URL is logged regularly.
+     */
+    if ((password = apr_table_get(r->headers_in, "Authorization")) != NULL
+        && strcasecmp(ap_getword(r->pool, &password, ' '), "Basic") == 0
+        && (password = ap_pbase64decode(r->pool, password))[0] != ':') {
+        /*
+         * Note that this allocation has to be made from r->connection->pool
+         * because it has the lifetime of the connection.  The other
+         * allocations are temporary and can be tossed away any time.
+         */
+        user = ap_getword_nulls(r->connection->pool, &password, ':');
+        r->ap_auth_type = "Basic";
+        r->user = r->parsed_uri.user = user;
+    }
+    else if ((user = r->parsed_uri.user) != NULL) {
+        user = apr_pstrdup(p, user);
+        decodeenc(user);
+        if ((password = r->parsed_uri.password) != NULL) {
+            char *tmp = apr_pstrdup(p, password);
+            decodeenc(tmp);
+            password = tmp;
+        }
+    }
+    else {
+        user = "anonymous";
+        password = "apache-proxy@";
+    }
+
+    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+       "proxy: FTP: connecting %s to %s:%d", url, connectname, connectport);
+
+    /* do a DNS lookup for the destination host */
+    if (!worker->cp->addr)
+        err = apr_sockaddr_info_get(&(worker->cp->addr),
+                                    connectname, APR_UNSPEC,
+                                    connectport, 0,
+                                    worker->cp->pool);
+    /*
+     * get all the possible IP addresses for the destname and loop through
+     * them until we get a successful connection
+     */
+    if (APR_SUCCESS != err) {
+        return ap_proxyerror(r, HTTP_BAD_GATEWAY, apr_pstrcat(p,
+                                                 "DNS lookup failure for: ",
+                                                        connectname, NULL));
+    }
+
+    /* check if ProxyBlock directive on this host */
+    if (OK != ap_proxy_checkproxyblock(r, conf, worker->cp->addr)) {
+        return ap_proxyerror(r, HTTP_FORBIDDEN,
+                             "Connect to remote machine blocked");
+    }
+
+    /* create space for state information */
+    backend = (proxy_conn_rec *) ap_get_module_config(c->conn_config, &proxy_ftp_module);
+    if (!backend) {
+        status = ap_proxy_acquire_connection("FTP", &backend, worker, r->server);
+        if (status != OK) {
+            if (backend) {
+                backend->close_on_recycle = 1;
+                ap_proxy_release_connection("FTP", backend, r->server);
+            }
+            return status;
+        }
+        ap_set_module_config(c->conn_config, &proxy_ftp_module, backend);
+    }
+
+
+    /*
+     * II: Make the Connection -----------------------
+     *
+     * We have determined who to connect to. Now make the connection.
+     */
+
+
+    if (ap_proxy_connect_backend("FTP", backend, worker, r->server)) {
+        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+                     "proxy: FTP: an error occurred creating a new connection to %pI (%s)",
+                     worker->cp->addr, connectname);
+        proxy_ftp_cleanup(r, backend);
+        return HTTP_SERVICE_UNAVAILABLE;
+    }
+
+    if (!backend->connection) {
+        status = ap_proxy_connection_create("FTP", backend, c, r->server);
+        if (status != OK) {
+            proxy_ftp_cleanup(r, backend);
+            return status;
+        }
+    }
+
+    /* Use old naming */
+    origin = backend->connection;
+    connect_addr = worker->cp->addr;
+    sock = backend->sock;
+
+    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+                 "proxy: FTP: control connection complete");
+
+
+    /*
+     * III: Send Control Request -------------------------
+     *
+     * Log into the ftp server, send the username & password, change to the
+     * correct directory...
+     */
+
+
+    /* possible results: */
+    /* 120 Service ready in nnn minutes. */
+    /* 220 Service ready for new user. */
+    /* 421 Service not available, closing control connection. */
+    rc = proxy_ftp_command(NULL, r, origin, bb, &ftpmessage);
+    if (rc == -1 || rc == 421) {
+        return ftp_proxyerror(r, backend, HTTP_BAD_GATEWAY, "Error reading from remote server");
+    }
+    if (rc == 120) {
+        /*
+         * RFC2616 states: 14.37 Retry-After
+         *
+         * The Retry-After response-header field can be used with a 503 (Service
+         * Unavailable) response to indicate how long the service is expected
+         * to be unavailable to the requesting client. [...] The value of
+         * this field can be either an HTTP-date or an integer number of
+         * seconds (in decimal) after the time of the response. Retry-After
+         * = "Retry-After" ":" ( HTTP-date | delta-seconds )
+         */
+        char *secs_str = ftpmessage;
+        time_t secs;
+
+        /* Look for a number, preceded by whitespace */
+        while (*secs_str)
+            if ((secs_str==ftpmessage || apr_isspace(secs_str[-1])) &&
+                apr_isdigit(secs_str[0]))
+                break;
+        if (*secs_str != '\0') {
+            secs = atol(secs_str);
+            apr_table_add(r->headers_out, "Retry-After",
+                          apr_psprintf(p, "%lu", (unsigned long)(60 * secs)));
+        }
+        return ftp_proxyerror(r, backend, HTTP_SERVICE_UNAVAILABLE, ftpmessage);
+    }
+    if (rc != 220) {
+        return ftp_proxyerror(r, backend, HTTP_BAD_GATEWAY, ftpmessage);
+    }
+
+    rc = proxy_ftp_command(apr_pstrcat(p, "USER ", user, CRLF, NULL),
+                           r, origin, bb, &ftpmessage);
+    /* possible results; 230, 331, 332, 421, 500, 501, 530 */
+    /* states: 1 - error, 2 - success; 3 - send password, 4,5 fail */
+    /* 230 User logged in, proceed. */
+    /* 331 User name okay, need password. */
+    /* 332 Need account for login. */
+    /* 421 Service not available, closing control connection. */
+    /* 500 Syntax error, command unrecognized. */
+    /* (This may include errors such as command line too long.) */
+    /* 501 Syntax error in parameters or arguments. */
+    /* 530 Not logged in. */
+    if (rc == -1 || rc == 421) {
+        return ftp_proxyerror(r, backend, HTTP_BAD_GATEWAY, "Error reading from remote server");
+    }
+    if (rc == 530) {
+        proxy_ftp_cleanup(r, backend);
+        return ftp_unauthorized(r, 1);  /* log it: user name guessing
+                                         * attempt? */
+    }
+    if (rc != 230 && rc != 331) {
+        return ftp_proxyerror(r, backend, HTTP_BAD_GATEWAY, ftpmessage);
+    }
+
+    if (rc == 331) {            /* send password */
+        if (password == NULL) {
+            proxy_ftp_cleanup(r, backend);
+            return ftp_unauthorized(r, 0);
+        }
+
+        rc = proxy_ftp_command(apr_pstrcat(p, "PASS ", password, CRLF, NULL),
+                           r, origin, bb, &ftpmessage);
+        /* possible results 202, 230, 332, 421, 500, 501, 503, 530 */
+        /* 230 User logged in, proceed. */
+        /* 332 Need account for login. */
+        /* 421 Service not available, closing control connection. */
+        /* 500 Syntax error, command unrecognized. */
+        /* 501 Syntax error in parameters or arguments. */
+        /* 503 Bad sequence of commands. */
+        /* 530 Not logged in. */
+        if (rc == -1 || rc == 421) {
+            return ftp_proxyerror(r, backend, HTTP_BAD_GATEWAY,
+                                  "Error reading from remote server");
+        }
+        if (rc == 332) {
+            return ftp_proxyerror(r, backend, HTTP_UNAUTHORIZED,
+                  apr_pstrcat(p, "Need account for login: ", ftpmessage, NULL));
+        }
+        /* @@@ questionable -- we might as well return a 403 Forbidden here */
+        if (rc == 530) {
+            proxy_ftp_cleanup(r, backend);
+            return ftp_unauthorized(r, 1);      /* log it: passwd guessing
+                                                 * attempt? */
+        }
+        if (rc != 230 && rc != 202) {
+            return ftp_proxyerror(r, backend, HTTP_BAD_GATEWAY, ftpmessage);
+        }
+    }
+    apr_table_set(r->notes, "Directory-README", ftpmessage);
+
+
+    /* Special handling for leading "%2f": this enforces a "cwd /"
+     * out of the $HOME directory which was the starting point after login
+     */
+    if (strncasecmp(path, "%2f", 3) == 0) {
+        path += 3;
+        while (*path == '/') /* skip leading '/' (after root %2f) */
+            ++path;
+
+        rc = proxy_ftp_command("CWD /" CRLF, r, origin, bb, &ftpmessage);
+        if (rc == -1 || rc == 421)
+            return ftp_proxyerror(r, backend, HTTP_BAD_GATEWAY,
+                                  "Error reading from remote server");
+    }
+
+    /*
+     * set the directory (walk directory component by component): this is
+     * what we must do if we don't know the OS type of the remote machine
+     */
+    for (;;) {
+        strp = strchr(path, '/');
+        if (strp == NULL)
+            break;
+        *strp = '\0';
+
+        len = decodeenc(path); /* Note! This decodes a %2f -> "/" */
+
+        if (strchr(path, '/')) { /* are there now any '/' characters? */
+            return ftp_proxyerror(r, backend, HTTP_BAD_REQUEST,
+                                  "Use of /%2f is only allowed at the base directory");
+        }
+
+        /* NOTE: FTP servers do globbing on the path.
+         * So we need to escape the URI metacharacters.
+         * We use a special glob-escaping routine to escape globbing chars.
+         * We could also have extended gen_test_char.c with a special T_ESCAPE_FTP_PATH
+         */
+        rc = proxy_ftp_command(apr_pstrcat(p, "CWD ",
+                           ftp_escape_globbingchars(p, path), CRLF, NULL),
+                           r, origin, bb, &ftpmessage);
+        *strp = '/';
+        /* responses: 250, 421, 500, 501, 502, 530, 550 */
+        /* 250 Requested file action okay, completed. */
+        /* 421 Service not available, closing control connection. */
+        /* 500 Syntax error, command unrecognized. */
+        /* 501 Syntax error in parameters or arguments. */
+        /* 502 Command not implemented. */
+        /* 530 Not logged in. */
+        /* 550 Requested action not taken. */
+        if (rc == -1 || rc == 421) {
+            return ftp_proxyerror(r, backend, HTTP_BAD_GATEWAY,
+                                  "Error reading from remote server");
+        }
+        if (rc == 550) {
+            return ftp_proxyerror(r, backend, HTTP_NOT_FOUND, ftpmessage);
+        }
+        if (rc != 250) {
+            return ftp_proxyerror(r, backend, HTTP_BAD_GATEWAY, ftpmessage);
+        }
+
+        path = strp + 1;
+    }
+
+    /*
+     * IV: Make Data Connection? -------------------------
+     *
+     * Try EPSV, if that fails... try PASV, if that fails... try PORT.
+     */
+/* this temporarily switches off EPSV/PASV */
+/*goto bypass;*/
+
+    /* set up data connection - EPSV */
+    {
+        apr_sockaddr_t *data_addr;
+        char *data_ip;
+        apr_port_t data_port;
+
+        /*
+         * The EPSV command replaces PASV where both IPV4 and IPV6 is
+         * supported. Only the port is returned, the IP address is always the
+         * same as that on the control connection. Example: Entering Extended
+         * Passive Mode (|||6446|)
+         */
+        rc = proxy_ftp_command("EPSV" CRLF,
+                           r, origin, bb, &ftpmessage);
+        /* possible results: 227, 421, 500, 501, 502, 530 */
+        /* 227 Entering Passive Mode (h1,h2,h3,h4,p1,p2). */
+        /* 421 Service not available, closing control connection. */
+        /* 500 Syntax error, command unrecognized. */
+        /* 501 Syntax error in parameters or arguments. */
+        /* 502 Command not implemented. */
+        /* 530 Not logged in. */
+        if (rc == -1 || rc == 421) {
+            return ftp_proxyerror(r, backend, HTTP_BAD_GATEWAY,
+                                  "Error reading from remote server");
+        }
+        if (rc != 229 && rc != 500 && rc != 501 && rc != 502) {
+            return ftp_proxyerror(r, backend, HTTP_BAD_GATEWAY, ftpmessage);
+        }
+        else if (rc == 229) {
+            char *pstr;
+            char *tok_cntx;
+
+            pstr = ftpmessage;
+            pstr = apr_strtok(pstr, " ", &tok_cntx);    /* separate result code */
+            if (pstr != NULL) {
+                if (*(pstr + strlen(pstr) + 1) == '=') {
+                    pstr += strlen(pstr) + 2;
+                }
+                else {
+                    pstr = apr_strtok(NULL, "(", &tok_cntx);    /* separate address &
+                                                                 * port params */
+                    if (pstr != NULL)
+                        pstr = apr_strtok(NULL, ")", &tok_cntx);
+                }
+            }
+
+            if (pstr) {
+                apr_sockaddr_t *epsv_addr;
+                data_port = atoi(pstr + 3);
+
+                ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+                       "proxy: FTP: EPSV contacting remote host on port %d",
+                             data_port);
+
+                if ((rv = apr_socket_create(&data_sock, connect_addr->family, SOCK_STREAM, 0, r->pool)) != APR_SUCCESS) {
+                    ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
+                                  "proxy: FTP: error creating EPSV socket");
+                    proxy_ftp_cleanup(r, backend);
+                    return HTTP_INTERNAL_SERVER_ERROR;
+                }
+
+#if !defined (TPF) && !defined(BEOS)
+                if (conf->recv_buffer_size > 0 
+                        && (rv = apr_socket_opt_set(data_sock, APR_SO_RCVBUF,
+                                                    conf->recv_buffer_size))) {
+                    ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
+                                  "proxy: FTP: apr_socket_opt_set(SO_RCVBUF): Failed to set ProxyReceiveBufferSize, using default");
+                }
+#endif
+
+                /* make the connection */
+                apr_socket_addr_get(&data_addr, APR_REMOTE, sock);
+                apr_sockaddr_ip_get(&data_ip, data_addr);
+                apr_sockaddr_info_get(&epsv_addr, data_ip, connect_addr->family, data_port, 0, p);
+                rv = apr_socket_connect(data_sock, epsv_addr);
+                if (rv != APR_SUCCESS) {
+                    ap_log_error(APLOG_MARK, APLOG_ERR, rv, r->server,
+                                 "proxy: FTP: EPSV attempt to connect to %pI failed - Firewall/NAT?", epsv_addr);
+                    return ftp_proxyerror(r, backend, HTTP_BAD_GATEWAY, apr_psprintf(r->pool,
+                                                                           "EPSV attempt to connect to %pI failed - firewall/NAT?", epsv_addr));
+                }
+                else {
+                    connect = 1;
+                }
+            }
+            else {
+                /* and try the regular way */
+                apr_socket_close(data_sock);
+            }
+        }
+    }
+
+    /* set up data connection - PASV */
+    if (!connect) {
+        rc = proxy_ftp_command("PASV" CRLF,
+                           r, origin, bb, &ftpmessage);
+        /* possible results: 227, 421, 500, 501, 502, 530 */
+        /* 227 Entering Passive Mode (h1,h2,h3,h4,p1,p2). */
+        /* 421 Service not available, closing control connection. */
+        /* 500 Syntax error, command unrecognized. */
+        /* 501 Syntax error in parameters or arguments. */
+        /* 502 Command not implemented. */
+        /* 530 Not logged in. */
+        if (rc == -1 || rc == 421) {
+            return ftp_proxyerror(r, backend, HTTP_BAD_GATEWAY,
+                                  "Error reading from remote server");
+        }
+        if (rc != 227 && rc != 502) {
+            return ftp_proxyerror(r, backend, HTTP_BAD_GATEWAY, ftpmessage);
+        }
+        else if (rc == 227) {
+            unsigned int h0, h1, h2, h3, p0, p1;
+            char *pstr;
+            char *tok_cntx;
+
+/* FIXME: Check PASV against RFC1123 */
+
+            pstr = ftpmessage;
+            pstr = apr_strtok(pstr, " ", &tok_cntx);    /* separate result code */
+            if (pstr != NULL) {
+                if (*(pstr + strlen(pstr) + 1) == '=') {
+                    pstr += strlen(pstr) + 2;
+                }
+                else {
+                    pstr = apr_strtok(NULL, "(", &tok_cntx);    /* separate address &
+                                                                 * port params */
+                    if (pstr != NULL)
+                        pstr = apr_strtok(NULL, ")", &tok_cntx);
+                }
+            }
+
+/* FIXME: Only supports IPV4 - fix in RFC2428 */
+
+            if (pstr != NULL && (sscanf(pstr,
+                 "%d,%d,%d,%d,%d,%d", &h3, &h2, &h1, &h0, &p1, &p0) == 6)) {
+
+                apr_sockaddr_t *pasv_addr;
+                apr_port_t pasvport = (p1 << 8) + p0;
+                ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+                          "proxy: FTP: PASV contacting host %d.%d.%d.%d:%d",
+                             h3, h2, h1, h0, pasvport);
+
+                if ((rv = apr_socket_create(&data_sock, connect_addr->family, SOCK_STREAM, 0, r->pool)) != APR_SUCCESS) {
+                    ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
+                                  "proxy: error creating PASV socket");
+                    proxy_ftp_cleanup(r, backend);
+                    return HTTP_INTERNAL_SERVER_ERROR;
+                }
+
+#if !defined (TPF) && !defined(BEOS)
+                if (conf->recv_buffer_size > 0 
+                        && (rv = apr_socket_opt_set(data_sock, APR_SO_RCVBUF,
+                                                    conf->recv_buffer_size))) {
+                    ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
+                                  "proxy: FTP: apr_socket_opt_set(SO_RCVBUF): Failed to set ProxyReceiveBufferSize, using default");
+                }
+#endif
+
+                /* make the connection */
+                apr_sockaddr_info_get(&pasv_addr, apr_psprintf(p, "%d.%d.%d.%d", h3, h2, h1, h0), connect_addr->family, pasvport, 0, p);
+                rv = apr_socket_connect(data_sock, pasv_addr);
+                if (rv != APR_SUCCESS) {
+                    ap_log_error(APLOG_MARK, APLOG_ERR, rv, r->server,
+                                 "proxy: FTP: PASV attempt to connect to %pI failed - Firewall/NAT?", pasv_addr);
+                    return ftp_proxyerror(r, backend, HTTP_BAD_GATEWAY, apr_psprintf(r->pool,
+                                                                           "PASV attempt to connect to %pI failed - firewall/NAT?", pasv_addr));
+                }
+                else {
+                    connect = 1;
+                }
+            }
+            else {
+                /* and try the regular way */
+                apr_socket_close(data_sock);
+            }
+        }
+    }
+/*bypass:*/
+
+    /* set up data connection - PORT */
+    if (!connect) {
+        apr_sockaddr_t *local_addr;
+        char *local_ip;
+        apr_port_t local_port;
+        unsigned int h0, h1, h2, h3, p0, p1;
+
+        if ((rv = apr_socket_create(&local_sock, connect_addr->family, SOCK_STREAM, 0, r->pool)) != APR_SUCCESS) {
+            ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
+                          "proxy: FTP: error creating local socket");
+            proxy_ftp_cleanup(r, backend);
+            return HTTP_INTERNAL_SERVER_ERROR;
+        }
+        apr_socket_addr_get(&local_addr, APR_LOCAL, sock);
+        local_port = local_addr->port;
+        apr_sockaddr_ip_get(&local_ip, local_addr);
+
+        if ((rv = apr_socket_opt_set(local_sock, APR_SO_REUSEADDR, one)) 
+                != APR_SUCCESS) {
+#ifndef _OSD_POSIX              /* BS2000 has this option "always on" */
+            ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
+                          "proxy: FTP: error setting reuseaddr option");
+            proxy_ftp_cleanup(r, backend);
+            return HTTP_INTERNAL_SERVER_ERROR;
+#endif                          /* _OSD_POSIX */
+        }
+
+        apr_sockaddr_info_get(&local_addr, local_ip, APR_UNSPEC, local_port, 0, r->pool);
+
+        if ((rv = apr_socket_bind(local_sock, local_addr)) != APR_SUCCESS) {
+            ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
+            "proxy: FTP: error binding to ftp data socket %pI", local_addr);
+            proxy_ftp_cleanup(r, backend);
+            return HTTP_INTERNAL_SERVER_ERROR;
+        }
+
+        /* only need a short queue */
+        if ((rv = apr_socket_listen(local_sock, 2)) != APR_SUCCESS) {
+            ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
+                          "proxy: FTP: error listening to ftp data socket %pI", local_addr);
+            proxy_ftp_cleanup(r, backend);
+            return HTTP_INTERNAL_SERVER_ERROR;
+        }
+
+/* FIXME: Sent PORT here */
+
+        if (local_ip && (sscanf(local_ip,
+                                "%d.%d.%d.%d", &h3, &h2, &h1, &h0) == 4)) {
+            p1 = (local_port >> 8);
+            p0 = (local_port & 0xFF);
+
+            rc = proxy_ftp_command(apr_psprintf(p, "PORT %d,%d,%d,%d,%d,%d" CRLF, h3, h2, h1, h0, p1, p0),
+                           r, origin, bb, &ftpmessage);
+            /* possible results: 200, 421, 500, 501, 502, 530 */
+            /* 200 Command okay. */
+            /* 421 Service not available, closing control connection. */
+            /* 500 Syntax error, command unrecognized. */
+            /* 501 Syntax error in parameters or arguments. */
+            /* 502 Command not implemented. */
+            /* 530 Not logged in. */
+            if (rc == -1 || rc == 421) {
+                return ftp_proxyerror(r, backend, HTTP_BAD_GATEWAY,
+                                      "Error reading from remote server");
+            }
+            if (rc != 200) {
+                return ftp_proxyerror(r, backend, HTTP_BAD_GATEWAY, buffer);
+            }
+
+            /* signal that we must use the EPRT/PORT loop */
+            use_port = 1;
+        }
+        else {
+/* IPV6 FIXME:
+ * The EPRT command replaces PORT where both IPV4 and IPV6 is supported. The first
+ * number (1,2) indicates the protocol type. Examples:
+ *   EPRT |1|132.235.1.2|6275|
+ *   EPRT |2|1080::8:800:200C:417A|5282|
+ */
+            return ftp_proxyerror(r, backend, HTTP_NOT_IMPLEMENTED,
+                                  "Connect to IPV6 ftp server using EPRT not supported. Enable EPSV.");
+        }
+    }
+
+
+    /*
+     * V: Set The Headers -------------------
+     *
+     * Get the size of the request, set up the environment for HTTP.
+     */
+
+    /* set request; "path" holds last path component */
+    len = decodeenc(path);
+
+    if (strchr(path, '/')) { /* are there now any '/' characters? */
+       return ftp_proxyerror(r, backend, HTTP_BAD_REQUEST,
+                             "Use of /%2f is only allowed at the base directory");
+    }
+
+    /* If len == 0 then it must be a directory (you can't RETR nothing)
+     * Also, don't allow to RETR by wildcard. Instead, create a dirlisting
+     */
+    if (len == 0 || ftp_check_globbingchars(path)) {
+        dirlisting = 1;
+    }
+    else {
+        /* (from FreeBSD ftpd):
+         * SIZE is not in RFC959, but Postel has blessed it and
+         * it will be in the updated RFC.
+         *
+         * Return size of file in a format suitable for
+         * using with RESTART (we just count bytes).
+         */
+        /* from draft-ietf-ftpext-mlst-14.txt:
+         * This value will
+         * change depending on the current STRUcture, MODE and TYPE of the data
+         * connection, or a data connection which would be created were one
+         * created now.  Thus, the result of the SIZE command is dependent on
+         * the currently established STRU, MODE and TYPE parameters.
+         */
+        /* Therefore: switch to binary if the user did not specify ";type=a" */
+        ftp_set_TYPE(xfer_type, r, origin, bb, &ftpmessage);
+        rc = proxy_ftp_command(apr_pstrcat(p, "SIZE ",
+                           ftp_escape_globbingchars(p, path), CRLF, NULL),
+                           r, origin, bb, &ftpmessage);
+        if (rc == -1 || rc == 421) {
+            return ftp_proxyerror(r, backend, HTTP_BAD_GATEWAY,
+                                  "Error reading from remote server");
+        }
+        else if (rc == 213) {/* Size command ok */
+            int j;
+            for (j = 0; apr_isdigit(ftpmessage[j]); j++)
+                ;
+            ftpmessage[j] = '\0';
+            if (ftpmessage[0] != '\0')
+                 size = ftpmessage; /* already pstrdup'ed: no copy necessary */
+        }
+        else if (rc == 550) {    /* Not a regular file */
+            ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+                             "proxy: FTP: SIZE shows this is a directory");
+            dirlisting = 1;
+            rc = proxy_ftp_command(apr_pstrcat(p, "CWD ", 
+                           ftp_escape_globbingchars(p, path), CRLF, NULL),
+                           r, origin, bb, &ftpmessage);
+            /* possible results: 250, 421, 500, 501, 502, 530, 550 */
+            /* 250 Requested file action okay, completed. */
+            /* 421 Service not available, closing control connection. */
+            /* 500 Syntax error, command unrecognized. */
+            /* 501 Syntax error in parameters or arguments. */
+            /* 502 Command not implemented. */
+            /* 530 Not logged in. */
+            /* 550 Requested action not taken. */
+            if (rc == -1 || rc == 421) {
+                return ftp_proxyerror(r, backend, HTTP_BAD_GATEWAY,
+                                      "Error reading from remote server");
+            }
+            if (rc == 550) {
+                return ftp_proxyerror(r, backend, HTTP_NOT_FOUND, ftpmessage);
+            }
+            if (rc != 250) {
+                return ftp_proxyerror(r, backend, HTTP_BAD_GATEWAY, ftpmessage);
+            }
+            path = "";
+            len = 0;
+        }
+    }
+
+    cwd = ftp_get_PWD(r, origin, bb);
+    if (cwd != NULL) {
+        apr_table_set(r->notes, "Directory-PWD", cwd);
+    }
+
+    if (dirlisting) {
+        ftp_set_TYPE('A', r, origin, bb, NULL);
+        /* If the current directory contains no slash, we are talking to
+         * a non-unix ftp system. Try LIST instead of "LIST -lag", it
+         * should return a long listing anyway (unlike NLST).
+         * Some exotic FTP servers might choke on the "-lag" switch.
+         */
+        /* Note that we do not escape the path here, to allow for
+         * queries like: ftp://user@host/apache/src/server/http_*.c
+         */
+        if (len != 0)
+            buf = apr_pstrcat(p, "LIST ", path, CRLF, NULL);
+        else if (cwd == NULL || strchr(cwd, '/') != NULL)
+            buf = apr_pstrcat(p, "LIST -lag", CRLF, NULL);
+        else
+            buf = "LIST" CRLF;
+    }
+    else {
+        /* switch to binary if the user did not specify ";type=a" */
+        ftp_set_TYPE(xfer_type, r, origin, bb, &ftpmessage);
+#if defined(USE_MDTM) && (defined(HAVE_TIMEGM) || defined(HAVE_GMTOFF))
+        /* from draft-ietf-ftpext-mlst-14.txt:
+         *   The FTP command, MODIFICATION TIME (MDTM), can be used to determine
+         *   when a file in the server NVFS was last modified.     <..>
+         *   The syntax of a time value is:
+         *           time-val       = 14DIGIT [ "." 1*DIGIT ]      <..>
+         *     Symbolically, a time-val may be viewed as
+         *           YYYYMMDDHHMMSS.sss
+         *     The "." and subsequent digits ("sss") are optional. <..>
+         *     Time values are always represented in UTC (GMT)
+         */
+        rc = proxy_ftp_command(apr_pstrcat(p, "MDTM ", ftp_escape_globbingchars(p, path), CRLF, NULL),
+                               r, origin, bb, &ftpmessage);
+        /* then extract the Last-Modified time from it (YYYYMMDDhhmmss or YYYYMMDDhhmmss.xxx GMT). */
+        if (rc == 213) {
+	    struct {
+	        char YYYY[4+1];
+		char MM[2+1];
+		char DD[2+1];
+		char hh[2+1];
+		char mm[2+1];
+		char ss[2+1];
+	    } time_val;
+	    if (6 == sscanf(ftpmessage, "%4[0-9]%2[0-9]%2[0-9]%2[0-9]%2[0-9]%2[0-9]",
+	        time_val.YYYY, time_val.MM, time_val.DD, time_val.hh, time_val.mm, time_val.ss)) {
+                struct tm tms;
+		memset (&tms, '\0', sizeof tms);
+		tms.tm_year = atoi(time_val.YYYY) - 1900;
+		tms.tm_mon  = atoi(time_val.MM)   - 1;
+		tms.tm_mday = atoi(time_val.DD);
+		tms.tm_hour = atoi(time_val.hh);
+		tms.tm_min  = atoi(time_val.mm);
+		tms.tm_sec  = atoi(time_val.ss);
+#ifdef HAVE_TIMEGM /* Does system have timegm()? */
+		mtime = timegm(&tms);
+		mtime *= APR_USEC_PER_SEC;
+#elif HAVE_GMTOFF /* does struct tm have a member tm_gmtoff? */
+                /* mktime will subtract the local timezone, which is not what we want.
+		 * Add it again because the MDTM string is GMT
+		 */
+		mtime = mktime(&tms);
+		mtime += tms.tm_gmtoff;
+		mtime *= APR_USEC_PER_SEC;
+#else
+		mtime = 0L;
+#endif
+            }
+	}
+#endif /* USE_MDTM */
+/* FIXME: Handle range requests - send REST */
+        buf = apr_pstrcat(p, "RETR ", ftp_escape_globbingchars(p, path), CRLF, NULL);
+    }
+    rc = proxy_ftp_command(buf, r, origin, bb, &ftpmessage);
+    /* rc is an intermediate response for the LIST or RETR commands */
+
+    /*
+     * RETR: 110, 125, 150, 226, 250, 421, 425, 426, 450, 451, 500, 501, 530,
+     * 550 NLST: 125, 150, 226, 250, 421, 425, 426, 450, 451, 500, 501, 502,
+     * 530
+     */
+    /* 110 Restart marker reply. */
+    /* 125 Data connection already open; transfer starting. */
+    /* 150 File status okay; about to open data connection. */
+    /* 226 Closing data connection. */
+    /* 250 Requested file action okay, completed. */
+    /* 421 Service not available, closing control connection. */
+    /* 425 Can't open data connection. */
+    /* 426 Connection closed; transfer aborted. */
+    /* 450 Requested file action not taken. */
+    /* 451 Requested action aborted. Local error in processing. */
+    /* 500 Syntax error, command unrecognized. */
+    /* 501 Syntax error in parameters or arguments. */
+    /* 530 Not logged in. */
+    /* 550 Requested action not taken. */
+    if (rc == -1 || rc == 421) {
+        return ftp_proxyerror(r, backend, HTTP_BAD_GATEWAY,
+                              "Error reading from remote server");
+    }
+    if (rc == 550) {
+        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+                     "proxy: FTP: RETR failed, trying LIST instead");
+
+        /* Directory Listings should always be fetched in ASCII mode */
+        dirlisting = 1;
+        ftp_set_TYPE('A', r, origin, bb, NULL);
+
+        rc = proxy_ftp_command(apr_pstrcat(p, "CWD ",
+                               ftp_escape_globbingchars(p, path), CRLF, NULL),
+                               r, origin, bb, &ftpmessage);
+        /* possible results: 250, 421, 500, 501, 502, 530, 550 */
+        /* 250 Requested file action okay, completed. */
+        /* 421 Service not available, closing control connection. */
+        /* 500 Syntax error, command unrecognized. */
+        /* 501 Syntax error in parameters or arguments. */
+        /* 502 Command not implemented. */
+        /* 530 Not logged in. */
+        /* 550 Requested action not taken. */
+        if (rc == -1 || rc == 421) {
+            return ftp_proxyerror(r, backend, HTTP_BAD_GATEWAY,
+                                  "Error reading from remote server");
+        }
+        if (rc == 550) {
+            return ftp_proxyerror(r, backend, HTTP_NOT_FOUND, ftpmessage);
+        }
+        if (rc != 250) {
+            return ftp_proxyerror(r, backend, HTTP_BAD_GATEWAY, ftpmessage);
+        }
+
+        /* Update current directory after CWD */
+        cwd = ftp_get_PWD(r, origin, bb);
+        if (cwd != NULL) {
+            apr_table_set(r->notes, "Directory-PWD", cwd);
+        }
+
+        /* See above for the "LIST" vs. "LIST -lag" discussion. */
+        rc = proxy_ftp_command((cwd == NULL || strchr(cwd, '/') != NULL)
+                               ? "LIST -lag" CRLF : "LIST" CRLF,
+                               r, origin, bb, &ftpmessage);
+
+        /* rc is an intermediate response for the LIST command (125 transfer starting, 150 opening data connection) */
+        if (rc == -1 || rc == 421)
+            return ftp_proxyerror(r, backend, HTTP_BAD_GATEWAY,
+                                  "Error reading from remote server");
+    }
+    if (rc != 125 && rc != 150 && rc != 226 && rc != 250) {
+        return ftp_proxyerror(r, backend, HTTP_BAD_GATEWAY, ftpmessage);
+    }
+
+    r->status = HTTP_OK;
+    r->status_line = "200 OK";
+
+    apr_rfc822_date(dates, r->request_time);
+    apr_table_setn(r->headers_out, "Date", dates);
+    apr_table_setn(r->headers_out, "Server", ap_get_server_version());
+
+    /* set content-type */
+    if (dirlisting) {
+        ap_set_content_type(r, "text/html");
+    }
+    else {
+        if (r->content_type) {
+            ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+                     "proxy: FTP: Content-Type set to %s", r->content_type);
+        }
+        else {
+            ap_set_content_type(r, ap_default_type(r));
+        }
+        if (xfer_type != 'A' && size != NULL) {
+            /* We "trust" the ftp server to really serve (size) bytes... */
+            apr_table_setn(r->headers_out, "Content-Length", size);
+            ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+                         "proxy: FTP: Content-Length set to %s", size);
+        }
+    }
+    apr_table_setn(r->headers_out, "Content-Type", r->content_type);
+    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+                 "proxy: FTP: Content-Type set to %s", r->content_type);
+
+#if defined(USE_MDTM) && (defined(HAVE_TIMEGM) || defined(HAVE_GMTOFF))
+    if (mtime != 0L) {
+        char datestr[APR_RFC822_DATE_LEN];
+        apr_rfc822_date(datestr, mtime);
+        apr_table_set(r->headers_out, "Last-Modified", datestr);
+        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+                 "proxy: FTP: Last-Modified set to %s", datestr);
+    }
+#endif /* USE_MDTM */
+
+    /* If an encoding has been set by mistake, delete it.
+     * @@@ FIXME (e.g., for ftp://user@host/file*.tar.gz,
+     * @@@        the encoding is currently set to x-gzip)
+     */
+    if (dirlisting && r->content_encoding != NULL)
+        r->content_encoding = NULL;
+
+    /* set content-encoding (not for dir listings, they are uncompressed)*/
+    if (r->content_encoding != NULL && r->content_encoding[0] != '\0') {
+        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+             "proxy: FTP: Content-Encoding set to %s", r->content_encoding);
+        apr_table_setn(r->headers_out, "Content-Encoding", r->content_encoding);
+    }
+
+    /* wait for connection */
+    if (use_port) {
+        for (;;) {
+            rv = apr_socket_accept(&data_sock, local_sock, r->pool);
+            if (rv == APR_EINTR) {
+                continue;
+            }
+            else if (rv == APR_SUCCESS) {
+                break;
+            }
+            else {
+                ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
+                            "proxy: FTP: failed to accept data connection");
+                proxy_ftp_cleanup(r, backend);
+                return HTTP_BAD_GATEWAY;
+            }
+        }
+    }
+
+    /* the transfer socket is now open, create a new connection */
+    data = ap_run_create_connection(p, r->server, data_sock, r->connection->id,
+                                    r->connection->sbh, c->bucket_alloc);
+    if (!data) {
+        /*
+         * the peer reset the connection already; ap_run_create_connection() closed
+         * the socket
+         */
+        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+          "proxy: FTP: an error occurred creating the transfer connection");
+        proxy_ftp_cleanup(r, backend);
+        return HTTP_INTERNAL_SERVER_ERROR;
+    }
+
+    /* set up the connection filters */
+    ap_run_pre_connection(data, data_sock);
+
+    /*
+     * VI: Receive the Response ------------------------
+     *
+     * Get response from the remote ftp socket, and pass it up the filter chain.
+     */
+
+    /* send response */
+    r->sent_bodyct = 1;
+
+    if (dirlisting) {
+        /* insert directory filter */
+        ap_add_output_filter("PROXY_SEND_DIR", NULL, r, r->connection);
+    }
+
+    /* send body */
+    if (!r->header_only) {
+        apr_bucket *e;
+        int finish = FALSE;
+
+        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+                     "proxy: FTP: start body send");
+
+        /* read the body, pass it to the output filters */
+        while (ap_get_brigade(data->input_filters, 
+                              bb, 
+                              AP_MODE_READBYTES, 
+                              APR_BLOCK_READ, 
+                              conf->io_buffer_size) == APR_SUCCESS) {
+#if DEBUGGING
+            {
+                apr_off_t readbytes;
+                apr_brigade_length(bb, 0, &readbytes);
+                ap_log_error(APLOG_MARK, APLOG_DEBUG, 0,
+                             r->server, "proxy (PID %d): readbytes: %#x",
+                             getpid(), readbytes);
+            }
+#endif
+            /* sanity check */
+            if (APR_BRIGADE_EMPTY(bb)) {
+                apr_brigade_cleanup(bb);
+                break;
+            }
+
+            /* found the last brigade? */
+            if (APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(bb))) {
+                /* if this is the last brigade, cleanup the
+                 * backend connection first to prevent the
+                 * backend server from hanging around waiting
+                 * for a slow client to eat these bytes
+                 */
+                ap_flush_conn(data);
+                apr_socket_close(data_sock);
+                data_sock = NULL;
+                ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+                             "proxy: FTP: data connection closed");
+                /* signal that we must leave */
+                finish = TRUE;
+            }
+
+            /* if no EOS yet, then we must flush */
+            if (FALSE == finish) {
+                e = apr_bucket_flush_create(c->bucket_alloc);
+                APR_BRIGADE_INSERT_TAIL(bb, e);
+            }
+
+            /* try send what we read */
+            if (ap_pass_brigade(r->output_filters, bb) != APR_SUCCESS) {
+                /* Ack! Phbtt! Die! User aborted! */
+                finish = TRUE;
+            }
+
+            /* make sure we always clean up after ourselves */
+            apr_brigade_cleanup(bb);
+
+            /* if we are done, leave */
+            if (TRUE == finish) {
+                break;
+            }
+        }
+        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+                     "proxy: FTP: end body send");
+
+    }
+    if (data_sock) {
+        ap_flush_conn(data);
+        apr_socket_close(data_sock);
+        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+                     "proxy: FTP: data connection closed");
+    }
+
+    /* Retrieve the final response for the RETR or LIST commands */
+    rc = proxy_ftp_command(NULL, r, origin, bb, &ftpmessage);
+    apr_brigade_cleanup(bb);
+
+    /*
+     * VII: Clean Up -------------
+     *
+     * If there are no KeepAlives, or if the connection has been signalled to
+     * close, close the socket and clean up
+     */
+
+    /* finish */
+    rc = proxy_ftp_command("QUIT" CRLF,
+                           r, origin, bb, &ftpmessage);
+    /* responses: 221, 500 */
+    /* 221 Service closing control connection. */
+    /* 500 Syntax error, command unrecognized. */
+    ap_flush_conn(origin);
+    proxy_ftp_cleanup(r, backend);
+
+    apr_brigade_destroy(bb);
+    return OK;
+}
+
+static void ap_proxy_ftp_register_hook(apr_pool_t *p)
+{
+    /* hooks */
+    proxy_hook_scheme_handler(ap_proxy_ftp_handler, NULL, NULL, APR_HOOK_MIDDLE);
+    proxy_hook_canon_handler(ap_proxy_ftp_canon, NULL, NULL, APR_HOOK_MIDDLE);
+    /* filters */
+    ap_register_output_filter("PROXY_SEND_DIR", ap_proxy_send_dir_filter,
+                              NULL, AP_FTYPE_RESOURCE);
+}
+
+module AP_MODULE_DECLARE_DATA proxy_ftp_module = {
+    STANDARD20_MODULE_STUFF,
+    NULL,                       /* create per-directory config structure */
+    NULL,                       /* merge per-directory config structures */
+    NULL,                       /* create per-server config structure */
+    NULL,                       /* merge per-server config structures */
+    NULL,                       /* command apr_table_t */
+    ap_proxy_ftp_register_hook  /* register hooks */
+};

Added: branches/tomcat5.5/upstream/5.5.20/connectors/ajp/proxy/proxy_http.c
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/ajp/proxy/proxy_http.c	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/ajp/proxy/proxy_http.c	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,1262 @@
+/* Copyright 1999-2004 The Apache Software Foundation
+ *
+ * Licensed 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.
+ */
+
+/* HTTP routines for Apache proxy */
+
+#include "mod_proxy.h"
+
+module AP_MODULE_DECLARE_DATA proxy_http_module;
+
+int ap_proxy_http_canon(request_rec *r, char *url);
+int ap_proxy_http_handler(request_rec *r, proxy_worker *worker,
+                          proxy_server_conf *conf,
+                          char *url, const char *proxyname, 
+                          apr_port_t proxyport);
+
+static apr_status_t ap_proxy_http_cleanup(const char *scheme,
+                                          request_rec *r,
+                                          proxy_conn_rec *backend);
+
+/*
+ * Canonicalise http-like URLs.
+ *  scheme is the scheme for the URL
+ *  url    is the URL starting with the first '/'
+ *  def_port is the default port for this scheme.
+ */
+int ap_proxy_http_canon(request_rec *r, char *url)
+{
+    char *host, *path, *search, sport[7];
+    const char *err;
+    const char *scheme;
+    apr_port_t port, def_port;
+
+    /* ap_port_of_scheme() */
+    if (strncasecmp(url, "http:", 5) == 0) {
+        url += 5;
+        scheme = "http";
+    }
+    else if (strncasecmp(url, "https:", 6) == 0) {
+        url += 6;
+        scheme = "https";
+    }
+    else {
+        return DECLINED;
+    }
+    def_port = apr_uri_port_of_scheme(scheme);
+
+    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+             "proxy: HTTP: canonicalising URL %s", url);
+
+    /* do syntatic check.
+     * We break the URL into host, port, path, search
+     */
+    port = def_port;
+    err = ap_proxy_canon_netloc(r->pool, &url, NULL, NULL, &host, &port);
+    if (err) {
+        ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+                      "error parsing URL %s: %s",
+                      url, err);
+        return HTTP_BAD_REQUEST;
+    }
+
+    /* now parse path/search args, according to rfc1738 */
+    /* N.B. if this isn't a true proxy request, then the URL _path_
+     * has already been decoded.  True proxy requests have r->uri
+     * == r->unparsed_uri, and no others have that property.
+     */
+    if (r->uri == r->unparsed_uri) {
+        search = strchr(url, '?');
+        if (search != NULL)
+            *(search++) = '\0';
+    }
+    else
+        search = r->args;
+
+    /* process path */
+    path = ap_proxy_canonenc(r->pool, url, strlen(url), enc_path, r->proxyreq);
+    if (path == NULL)
+        return HTTP_BAD_REQUEST;
+
+    if (port != def_port)
+        apr_snprintf(sport, sizeof(sport), ":%d", port);
+    else
+        sport[0] = '\0';
+
+    if (ap_strchr_c(host, ':')) { /* if literal IPv6 address */
+        host = apr_pstrcat(r->pool, "[", host, "]", NULL);
+    }
+    r->filename = apr_pstrcat(r->pool, "proxy:", scheme, "://", host, sport, 
+            "/", path, (search) ? "?" : "", (search) ? search : "", NULL);
+    return OK;
+}
+ 
+static const char *ap_proxy_location_reverse_map(request_rec *r, proxy_server_conf *conf, const char *url)
+{
+    struct proxy_alias *ent;
+    int i, l1, l2;
+    char *u;
+
+    /* XXX FIXME: Make sure this handled the ambiguous case of the :80
+     * after the hostname */
+
+    l1 = strlen(url);
+    ent = (struct proxy_alias *)conf->raliases->elts;
+    for (i = 0; i < conf->raliases->nelts; i++) {
+        l2 = strlen(ent[i].real);
+        if (l1 >= l2 && strncasecmp(ent[i].real, url, l2) == 0) {
+            u = apr_pstrcat(r->pool, ent[i].fake, &url[l2], NULL);
+            return ap_construct_url(r->pool, u, r);
+        }
+    }
+    return url;
+}
+/* cookies are a bit trickier to match: we've got two substrings to worry
+ * about, and we can't just find them with strstr 'cos of case.  Regexp
+ * matching would be an easy fix, but for better consistency with all the
+ * other matches we'll refrain and use apr_strmatch to find path=/domain=
+ * and stick to plain strings for the config values.
+ */
+static const char *proxy_cookie_reverse_map(request_rec *r,
+                          proxy_server_conf *conf, const char *str)
+{
+    struct proxy_alias *ent;
+    size_t len = strlen(str);
+    const char* newpath = NULL ;
+    const char* newdomain = NULL ;
+    const char* pathp ;
+    const char* domainp ;
+    const char* pathe = NULL;
+    const char* domaine = NULL;
+    size_t l1, l2, poffs = 0, doffs = 0 ;
+    int i;
+    int ddiff = 0 ;
+    int pdiff = 0 ;
+    char* ret ;
+
+/* find the match and replacement, but save replacing until we've done
+   both path and domain so we know the new strlen
+*/
+    if ( pathp = apr_strmatch(conf->cookie_path_str, str, len) , pathp ) {
+        pathp += 5 ;
+        poffs = pathp - str ;
+        pathe = ap_strchr_c(pathp, ';') ;
+        l1 = pathe ? (pathe-pathp) : strlen(pathp) ;
+        pathe = pathp + l1 ;
+        ent = (struct proxy_alias *)conf->cookie_paths->elts;
+        for (i = 0; i < conf->cookie_paths->nelts; i++) {
+            l2 = strlen(ent[i].fake);
+            if (l1 >= l2 && strncmp(ent[i].fake, pathp, l2) == 0) {
+                newpath = ent[i].real ;
+                pdiff = strlen(newpath) - l1 ;
+                break ;
+            }
+        }
+    }
+    if ( domainp = apr_strmatch(conf->cookie_domain_str, str, len) , domainp ) {
+        domainp += 7 ;
+        doffs = domainp - str ;
+        domaine = ap_strchr_c(domainp, ';') ;
+        l1 = domaine ? (domaine-domainp) : strlen(domainp) ;
+        domaine = domainp + l1 ;
+        ent = (struct proxy_alias *)conf->cookie_domains->elts;
+        for (i = 0; i < conf->cookie_domains->nelts; i++) {
+            l2 = strlen(ent[i].fake);
+            if (l1 >= l2 && strncasecmp(ent[i].fake, domainp, l2) == 0) {
+                newdomain = ent[i].real ;
+                ddiff = strlen(newdomain) - l1 ;
+                break ;
+            }
+        }
+    }
+    if ( newpath ) {
+        ret = apr_palloc(r->pool, len+pdiff+ddiff+1) ;
+        l1 = strlen(newpath) ;
+        if ( newdomain ) {
+            l2 = strlen(newdomain) ;
+            if ( doffs > poffs ) {
+                memcpy(ret, str, poffs) ;
+                memcpy(ret+poffs, newpath, l1) ;
+                memcpy(ret+poffs+l1, pathe, domainp-pathe) ;
+                memcpy(ret+doffs+pdiff, newdomain, l2) ;
+                strcpy(ret+doffs+pdiff+l2, domaine) ;
+            } else {
+                memcpy(ret, str, doffs) ;
+                memcpy(ret+doffs, newdomain, l2) ;
+                memcpy(ret+doffs+l2, domaine, pathp-domaine) ;
+                memcpy(ret+poffs+ddiff, newpath, l1) ;
+                strcpy(ret+poffs+ddiff+l1, pathe) ;
+            }
+        } else {
+            memcpy(ret, str, poffs) ;
+            memcpy(ret+poffs, newpath, l1) ;
+            strcpy(ret+poffs+l1, pathe) ;
+        }
+    } else {
+        if ( newdomain ) {
+            ret = apr_palloc(r->pool, len+pdiff+ddiff+1) ;
+            l2 = strlen(newdomain) ;
+            memcpy(ret, str, doffs) ;
+            memcpy(ret+doffs, newdomain, l2) ;
+            strcpy(ret+doffs+l2, domaine) ;
+        } else {
+            ret = (char*) str ;        /* no change */
+        }
+    }
+    return ret ;
+}
+
+/* Clear all connection-based headers from the incoming headers table */
+static void ap_proxy_clear_connection(apr_pool_t *p, apr_table_t *headers)
+{
+    const char *name;
+    char *next = apr_pstrdup(p, apr_table_get(headers, "Connection"));
+
+    apr_table_unset(headers, "Proxy-Connection");
+    if (!next)
+        return;
+
+    while (*next) {
+        name = next;
+        while (*next && !apr_isspace(*next) && (*next != ',')) {
+            ++next;
+        }
+        while (*next && (apr_isspace(*next) || (*next == ','))) {
+            *next = '\0';
+            ++next;
+        }
+        apr_table_unset(headers, name);
+    }
+    apr_table_unset(headers, "Connection");
+}
+
+static
+apr_status_t ap_proxy_http_request(apr_pool_t *p, request_rec *r,
+                                   proxy_conn_rec *conn, conn_rec *origin, 
+                                   proxy_server_conf *conf,
+                                   apr_uri_t *uri,
+                                   char *url, char *server_portstr)
+{
+    conn_rec *c = r->connection;
+    char *buf;
+    apr_bucket *e, *last_header_bucket = NULL;
+    const apr_array_header_t *headers_in_array;
+    const apr_table_entry_t *headers_in;
+    int counter, seen_eos, send_chunks;
+    apr_status_t status;
+    apr_bucket_brigade *header_brigade, *body_brigade, *input_brigade;
+
+    header_brigade = apr_brigade_create(p, origin->bucket_alloc);
+    body_brigade = apr_brigade_create(p, origin->bucket_alloc);
+    input_brigade = apr_brigade_create(p, origin->bucket_alloc);
+
+    /*
+     * Send the HTTP/1.1 request to the remote server
+     */
+
+    /* strip connection listed hop-by-hop headers from the request */
+    /* even though in theory a connection: close coming from the client
+     * should not affect the connection to the server, it's unlikely
+     * that subsequent client requests will hit this thread/process, so
+     * we cancel server keepalive if the client does.
+     */
+    conn->close += ap_proxy_liststr(apr_table_get(r->headers_in,
+                                                  "Connection"), "close");
+
+    /* sub-requests never use keepalives */
+    if (r->main) {
+        conn->close++;
+    }
+
+    ap_proxy_clear_connection(p, r->headers_in);
+    if (conn->close) {
+        apr_table_setn(r->headers_in, "Connection", "close");
+        origin->keepalive = AP_CONN_CLOSE;
+    }
+
+    /* By default, we can not send chunks. That means we must buffer
+     * the entire request before sending it along to ensure we have
+     * the correct Content-Length attached.
+     */
+    send_chunks = 0;
+
+    if (apr_table_get(r->subprocess_env, "force-proxy-request-1.0")) {
+        buf = apr_pstrcat(p, r->method, " ", url, " HTTP/1.0" CRLF, NULL);
+    } else {
+        buf = apr_pstrcat(p, r->method, " ", url, " HTTP/1.1" CRLF, NULL);
+        if (apr_table_get(r->subprocess_env, "proxy-sendchunks")) {
+            send_chunks = 1;
+        }
+    }
+    if (apr_table_get(r->subprocess_env, "proxy-nokeepalive")) {
+        apr_table_unset(r->headers_in, "Connection");
+        origin->keepalive = AP_CONN_CLOSE;
+    }
+    ap_xlate_proto_to_ascii(buf, strlen(buf));
+    e = apr_bucket_pool_create(buf, strlen(buf), p, c->bucket_alloc);
+    APR_BRIGADE_INSERT_TAIL(header_brigade, e);
+    if (conf->preserve_host == 0) {
+        if (uri->port_str && uri->port != DEFAULT_HTTP_PORT) {
+            buf = apr_pstrcat(p, "Host: ", uri->hostname, ":", uri->port_str,
+                              CRLF, NULL);
+        } else {
+            buf = apr_pstrcat(p, "Host: ", uri->hostname, CRLF, NULL);
+        }
+    } 
+    else {
+        /* don't want to use r->hostname, as the incoming header might have a 
+         * port attached 
+         */
+        const char* hostname = apr_table_get(r->headers_in,"Host");        
+        if (!hostname) {
+            hostname =  r->server->server_hostname;
+            ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r,
+                          "proxy: no HTTP 0.9 request (with no host line) "
+                          "on incoming request and preserve host set "
+                          "forcing hostname to be %s for uri %s", 
+                          hostname, 
+                          r->uri );
+        }
+        buf = apr_pstrcat(p, "Host: ", hostname, CRLF, NULL);
+    }
+    ap_xlate_proto_to_ascii(buf, strlen(buf));
+    e = apr_bucket_pool_create(buf, strlen(buf), p, c->bucket_alloc);        
+    APR_BRIGADE_INSERT_TAIL(header_brigade, e);
+
+    /* handle Via */
+    if (conf->viaopt == via_block) {
+        /* Block all outgoing Via: headers */
+        apr_table_unset(r->headers_in, "Via");
+    } else if (conf->viaopt != via_off) {
+        const char *server_name = ap_get_server_name(r);
+        /* If USE_CANONICAL_NAME_OFF was configured for the proxy virtual host,
+         * then the server name returned by ap_get_server_name() is the
+         * origin server name (which does make too much sense with Via: headers)
+         * so we use the proxy vhost's name instead.
+         */
+        if (server_name == r->hostname)
+            server_name = r->server->server_hostname;
+        /* Create a "Via:" request header entry and merge it */
+        /* Generate outgoing Via: header with/without server comment: */
+        apr_table_mergen(r->headers_in, "Via",
+                         (conf->viaopt == via_full)
+                         ? apr_psprintf(p, "%d.%d %s%s (%s)",
+                                        HTTP_VERSION_MAJOR(r->proto_num),
+                                        HTTP_VERSION_MINOR(r->proto_num),
+                                        server_name, server_portstr,
+                                        AP_SERVER_BASEVERSION)
+                         : apr_psprintf(p, "%d.%d %s%s",
+                                        HTTP_VERSION_MAJOR(r->proto_num),
+                                        HTTP_VERSION_MINOR(r->proto_num),
+                                        server_name, server_portstr)
+        );
+    }
+
+    /* X-Forwarded-*: handling
+     *
+     * XXX Privacy Note:
+     * -----------------
+     *
+     * These request headers are only really useful when the mod_proxy
+     * is used in a reverse proxy configuration, so that useful info
+     * about the client can be passed through the reverse proxy and on
+     * to the backend server, which may require the information to
+     * function properly.
+     *
+     * In a forward proxy situation, these options are a potential
+     * privacy violation, as information about clients behind the proxy
+     * are revealed to arbitrary servers out there on the internet.
+     *
+     * The HTTP/1.1 Via: header is designed for passing client
+     * information through proxies to a server, and should be used in
+     * a forward proxy configuation instead of X-Forwarded-*. See the
+     * ProxyVia option for details.
+     */
+
+    if (PROXYREQ_REVERSE == r->proxyreq) {
+        const char *buf;
+
+        /* Add X-Forwarded-For: so that the upstream has a chance to
+         * determine, where the original request came from.
+         */
+        apr_table_mergen(r->headers_in, "X-Forwarded-For",
+                       r->connection->remote_ip);
+
+        /* Add X-Forwarded-Host: so that upstream knows what the
+         * original request hostname was.
+         */
+        if ((buf = apr_table_get(r->headers_in, "Host"))) {
+            apr_table_mergen(r->headers_in, "X-Forwarded-Host", buf);
+        }
+
+        /* Add X-Forwarded-Server: so that upstream knows what the
+         * name of this proxy server is (if there are more than one)
+         * XXX: This duplicates Via: - do we strictly need it?
+         */
+        apr_table_mergen(r->headers_in, "X-Forwarded-Server",
+                       r->server->server_hostname);
+    }
+
+    /* send request headers */
+    proxy_run_fixups(r);
+    headers_in_array = apr_table_elts(r->headers_in);
+    headers_in = (const apr_table_entry_t *) headers_in_array->elts;
+    for (counter = 0; counter < headers_in_array->nelts; counter++) {
+        if (headers_in[counter].key == NULL || headers_in[counter].val == NULL
+
+        /* Clear out hop-by-hop request headers not to send
+         * RFC2616 13.5.1 says we should strip these headers
+         */
+                /* Already sent */
+            || !apr_strnatcasecmp(headers_in[counter].key, "Host")
+
+            || !apr_strnatcasecmp(headers_in[counter].key, "Keep-Alive")
+            || !apr_strnatcasecmp(headers_in[counter].key, "TE")
+            || !apr_strnatcasecmp(headers_in[counter].key, "Trailer")
+            || !apr_strnatcasecmp(headers_in[counter].key, "Transfer-Encoding")
+            || !apr_strnatcasecmp(headers_in[counter].key, "Upgrade")
+
+            /* We have no way of knowing whether this Content-Length will
+             * be accurate, so we must not include it.
+             */
+            || !apr_strnatcasecmp(headers_in[counter].key, "Content-Length")
+        /* XXX: @@@ FIXME: "Proxy-Authorization" should *only* be 
+         * suppressed if THIS server requested the authentication,
+         * not when a frontend proxy requested it!
+         *
+         * The solution to this problem is probably to strip out
+         * the Proxy-Authorisation header in the authorisation
+         * code itself, not here. This saves us having to signal
+         * somehow whether this request was authenticated or not.
+         */
+            || !apr_strnatcasecmp(headers_in[counter].key,"Proxy-Authorization")
+            || !apr_strnatcasecmp(headers_in[counter].key,"Proxy-Authenticate")) {
+            continue;
+        }
+        /* for sub-requests, ignore freshness/expiry headers */
+        if (r->main) {
+                if (headers_in[counter].key == NULL || headers_in[counter].val == NULL
+                     || !apr_strnatcasecmp(headers_in[counter].key, "If-Match")
+                     || !apr_strnatcasecmp(headers_in[counter].key, "If-Modified-Since")
+                     || !apr_strnatcasecmp(headers_in[counter].key, "If-Range")
+                     || !apr_strnatcasecmp(headers_in[counter].key, "If-Unmodified-Since")                     
+                     || !apr_strnatcasecmp(headers_in[counter].key, "If-None-Match")) {
+                    continue;
+                }
+        }
+
+
+        buf = apr_pstrcat(p, headers_in[counter].key, ": ",
+                          headers_in[counter].val, CRLF,
+                          NULL);
+        ap_xlate_proto_to_ascii(buf, strlen(buf));
+        e = apr_bucket_pool_create(buf, strlen(buf), p, c->bucket_alloc);
+        APR_BRIGADE_INSERT_TAIL(header_brigade, e);
+    }
+
+    /* If we can send chunks, do so! */
+    if (send_chunks) {
+        const char *te_hdr = "Transfer-Encoding: chunked" CRLF;
+
+        buf = apr_pmemdup(p, te_hdr, sizeof(te_hdr)-1);
+        ap_xlate_proto_to_ascii(buf, sizeof(te_hdr)-1);
+
+        e = apr_bucket_pool_create(buf, strlen(buf), p, c->bucket_alloc);
+        APR_BRIGADE_INSERT_TAIL(header_brigade, e);
+    }
+    else {
+        last_header_bucket = APR_BRIGADE_LAST(header_brigade);
+    }
+
+    /* add empty line at the end of the headers */
+#if APR_CHARSET_EBCDIC
+    e = apr_bucket_immortal_create("\015\012", 2, c->bucket_alloc);
+#else
+    e = apr_bucket_immortal_create(CRLF, sizeof(CRLF)-1, c->bucket_alloc);
+#endif
+    APR_BRIGADE_INSERT_TAIL(header_brigade, e);
+    e = apr_bucket_flush_create(c->bucket_alloc);
+    APR_BRIGADE_INSERT_TAIL(header_brigade, e);
+
+    if (send_chunks) {
+        status = ap_pass_brigade(origin->output_filters, header_brigade);
+
+        if (status != APR_SUCCESS) {
+            ap_log_error(APLOG_MARK, APLOG_ERR, status, r->server,
+                         "proxy: request failed to %pI (%s)",
+                         conn->worker->cp->addr, conn->hostname);
+            return status;
+        }
+    }
+
+    /* send the request data, if any. */
+    seen_eos = 0;
+    do {
+        char chunk_hdr[20];  /* must be here due to transient bucket. */
+
+        status = ap_get_brigade(r->input_filters, input_brigade,
+                                AP_MODE_READBYTES, APR_BLOCK_READ,
+                                HUGE_STRING_LEN);
+
+        if (status != APR_SUCCESS) {
+            return status;
+        }
+
+        /* If this brigade contain EOS, either stop or remove it. */
+        if (APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(input_brigade))) {
+            seen_eos = 1;
+
+            /* As a shortcut, if this brigade is simply an EOS bucket,
+             * don't send anything down the filter chain.
+             */
+            if (APR_BUCKET_IS_EOS(APR_BRIGADE_FIRST(input_brigade))) {
+                break;
+            }
+
+            /* We can't pass this EOS to the output_filters. */
+            e = APR_BRIGADE_LAST(input_brigade);
+            apr_bucket_delete(e);
+        }
+
+        if (send_chunks) {
+#define ASCII_CRLF  "\015\012"
+#define ASCII_ZERO  "\060"
+            apr_size_t hdr_len;
+            apr_off_t bytes;
+
+            apr_brigade_length(input_brigade, 1, &bytes);
+
+            hdr_len = apr_snprintf(chunk_hdr, sizeof(chunk_hdr),
+                                   "%" APR_UINT64_T_HEX_FMT CRLF, 
+                                   (apr_uint64_t)bytes);
+
+            ap_xlate_proto_to_ascii(chunk_hdr, hdr_len);
+            e = apr_bucket_transient_create(chunk_hdr, hdr_len,
+                                            body_brigade->bucket_alloc);
+            APR_BRIGADE_INSERT_HEAD(input_brigade, e);
+
+            /*
+             * Append the end-of-chunk CRLF
+             */
+            e = apr_bucket_immortal_create(ASCII_CRLF, 2, c->bucket_alloc);
+            APR_BRIGADE_INSERT_TAIL(input_brigade, e);
+        }
+
+        e = apr_bucket_flush_create(c->bucket_alloc);
+        APR_BRIGADE_INSERT_TAIL(input_brigade, e);
+
+        APR_BRIGADE_CONCAT(body_brigade, input_brigade);
+
+        if (send_chunks) {
+            status = ap_pass_brigade(origin->output_filters, body_brigade);
+
+            if (status != APR_SUCCESS) {
+                ap_log_error(APLOG_MARK, APLOG_ERR, status, r->server,
+                             "proxy: pass request data failed to %pI (%s)",
+                         conn->worker->cp->addr, conn->hostname);
+                return status;
+            }
+
+            apr_brigade_cleanup(body_brigade);
+        }
+
+    } while (!seen_eos);
+
+    if (send_chunks) {
+        e = apr_bucket_immortal_create(ASCII_ZERO ASCII_CRLF
+                                       /* <trailers> */
+                                       ASCII_CRLF, 5, c->bucket_alloc);
+        APR_BRIGADE_INSERT_TAIL(body_brigade, e);
+    }
+
+    if (!send_chunks) {
+        apr_off_t bytes;
+
+        apr_brigade_length(body_brigade, 1, &bytes);
+
+        if (bytes) {
+            const char *cl_hdr = "Content-Length", *cl_val;
+            cl_val = apr_off_t_toa(c->pool, bytes);
+            buf = apr_pstrcat(p, cl_hdr, ": ", cl_val, CRLF, NULL);
+            ap_xlate_proto_to_ascii(buf, strlen(buf));
+            e = apr_bucket_pool_create(buf, strlen(buf), p, c->bucket_alloc);
+            APR_BUCKET_INSERT_AFTER(last_header_bucket, e);
+        }
+        status = ap_pass_brigade(origin->output_filters, header_brigade);
+        if (status != APR_SUCCESS) {
+            ap_log_error(APLOG_MARK, APLOG_ERR, status, r->server,
+                         "proxy: pass request data failed to %pI (%s)",
+                         conn->worker->cp->addr, conn->hostname);
+            return status;
+        }
+
+        apr_brigade_cleanup(header_brigade);
+    }
+
+    status = ap_pass_brigade(origin->output_filters, body_brigade);
+
+    if (status != APR_SUCCESS) {
+        ap_log_error(APLOG_MARK, APLOG_ERR, status, r->server,
+                     "proxy: pass request data failed to %pI (%s)",
+                      conn->worker->cp->addr, conn->hostname);
+        return status;
+    }
+ 
+    apr_brigade_cleanup(body_brigade);
+
+    return APR_SUCCESS;
+}
+static void process_proxy_header(request_rec* r, proxy_server_conf* c,
+                      const char* key, const char* value)
+{
+    static const char* date_hdrs[]
+        = { "Date", "Expires", "Last-Modified", NULL } ;
+    static const struct {
+        const char* name ;
+        const char* (*func)(request_rec*, proxy_server_conf*, const char*) ;
+    } transform_hdrs[] = {
+        { "Location", ap_proxy_location_reverse_map } ,
+        { "Content-Location", ap_proxy_location_reverse_map } ,
+        { "URI", ap_proxy_location_reverse_map } ,
+        { "Set-Cookie", proxy_cookie_reverse_map } ,
+        { NULL, NULL }
+    } ;
+    int i ;
+    for ( i = 0 ; date_hdrs[i] ; ++i ) {
+        if ( !strcasecmp(date_hdrs[i], key) ) {
+            apr_table_add(r->headers_out, key,
+                ap_proxy_date_canon(r->pool, value)) ;
+            return ;
+        }
+    }
+    for ( i = 0 ; transform_hdrs[i].name ; ++i ) {
+        if ( !strcasecmp(transform_hdrs[i].name, key) ) {
+            apr_table_add(r->headers_out, key,
+                (*transform_hdrs[i].func)(r, c, value)) ;
+            return ;
+       }
+    }
+    apr_table_add(r->headers_out, key, value) ;
+    return ;
+}
+
+static void ap_proxy_read_headers(request_rec *r, request_rec *rr, char *buffer, int size, conn_rec *c)
+{
+    int len;
+    char *value, *end;
+    char field[MAX_STRING_LEN];
+    int saw_headers = 0;
+    void *sconf = r->server->module_config;
+    proxy_server_conf *psc;
+
+    psc = (proxy_server_conf *) ap_get_module_config(sconf, &proxy_module);
+
+    r->headers_out = apr_table_make(r->pool, 20);
+
+    /*
+     * Read header lines until we get the empty separator line, a read error,
+     * the connection closes (EOF), or we timeout.
+     */
+    while ((len = ap_getline(buffer, size, rr, 1)) > 0) {
+
+        if (!(value = strchr(buffer, ':'))) {     /* Find the colon separator */
+
+            /* We may encounter invalid headers, usually from buggy
+             * MS IIS servers, so we need to determine just how to handle
+             * them. We can either ignore them, assume that they mark the
+             * start-of-body (eg: a missing CRLF) or (the default) mark
+             * the headers as totally bogus and return a 500. The sole
+             * exception is an extra "HTTP/1.0 200, OK" line sprinkled
+             * in between the usual MIME headers, which is a favorite
+             * IIS bug.
+             */
+             /* XXX: The mask check is buggy if we ever see an HTTP/1.10 */
+
+            if (!apr_date_checkmask(buffer, "HTTP/#.# ###*")) {
+                if (psc->badopt == bad_error) {
+                    /* Nope, it wasn't even an extra HTTP header. Give up. */
+                    return ;
+                }
+                else if (psc->badopt == bad_body) {
+                    /* if we've already started loading headers_out, then
+                     * return what we've accumulated so far, in the hopes
+                     * that they are useful. Otherwise, we completely bail.
+                     */
+                    /* FIXME: We've already scarfed the supposed 1st line of
+                     * the body, so the actual content may end up being bogus
+                     * as well. If the content is HTML, we may be lucky.
+                     */
+                    if (saw_headers) {
+                        ap_log_error(APLOG_MARK, APLOG_WARNING, 0, r->server,
+                         "proxy: Starting body due to bogus non-header in headers "
+                         "returned by %s (%s)", r->uri, r->method);
+                        return ;
+                    } else {
+                         ap_log_error(APLOG_MARK, APLOG_WARNING, 0, r->server,
+                         "proxy: No HTTP headers "
+                         "returned by %s (%s)", r->uri, r->method);
+                        return ;
+                    }
+                }
+            }
+            /* this is the psc->badopt == bad_ignore case */
+            ap_log_error(APLOG_MARK, APLOG_WARNING, 0, r->server,
+                         "proxy: Ignoring bogus HTTP header "
+                         "returned by %s (%s)", r->uri, r->method);
+            continue;
+        }
+
+        *value = '\0';
+        ++value;
+        /* XXX: RFC2068 defines only SP and HT as whitespace, this test is
+         * wrong... and so are many others probably.
+         */
+        while (apr_isspace(*value))
+            ++value;            /* Skip to start of value   */
+
+        /* should strip trailing whitespace as well */
+        for (end = &value[strlen(value)-1]; end > value && apr_isspace(*end); --
+end)
+            *end = '\0';
+
+        /* make sure we add so as not to destroy duplicated headers
+         * Modify headers requiring canonicalisation and/or affected
+         * by ProxyPassReverse and family with process_proxy_header
+         */
+        process_proxy_header(r, psc, buffer, value) ;
+        saw_headers = 1;
+
+        /* the header was too long; at the least we should skip extra data */
+        if (len >= size - 1) {
+            while ((len = ap_getline(field, MAX_STRING_LEN, rr, 1))
+                    >= MAX_STRING_LEN - 1) {
+                /* soak up the extra data */
+            }
+            if (len == 0) /* time to exit the larger loop as well */
+                break;
+        }
+    }
+}
+
+
+
+static int addit_dammit(void *v, const char *key, const char *val)
+{
+    apr_table_addn(v, key, val);
+    return 1;
+}
+
+static
+apr_status_t ap_proxy_http_process_response(apr_pool_t * p, request_rec *r,
+                                            proxy_conn_rec *backend,
+                                            conn_rec *origin,
+                                            proxy_server_conf *conf,
+                                            char *server_portstr) {
+    conn_rec *c = r->connection;
+    char buffer[HUGE_STRING_LEN];
+    char keepchar;
+    request_rec *rp;
+    apr_bucket *e;
+    apr_bucket_brigade *bb;
+    int len, backasswards;
+    int interim_response; /* non-zero whilst interim 1xx responses
+                           * are being read. */
+    apr_table_t *save_table;
+
+    bb = apr_brigade_create(p, c->bucket_alloc);
+
+    /* Get response from the remote server, and pass it up the
+     * filter chain
+     */
+
+    rp = ap_proxy_make_fake_req(origin, r);
+    /* In case anyone needs to know, this is a fake request that is really a
+     * response.
+     */
+    rp->proxyreq = PROXYREQ_RESPONSE;
+
+    do {
+        apr_brigade_cleanup(bb);
+
+        len = ap_getline(buffer, sizeof(buffer), rp, 0);
+        if (len == 0) {
+            /* handle one potential stray CRLF */
+            len = ap_getline(buffer, sizeof(buffer), rp, 0);
+        }
+        if (len <= 0) {
+            ap_proxy_http_cleanup(NULL, r, backend);
+            ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+                          "proxy: error reading status line from remote "
+                          "server %s", backend->hostname);
+            return ap_proxyerror(r, HTTP_BAD_GATEWAY,
+                                 "Error reading from remote server");
+        }
+
+       /* Is it an HTTP/1 response?
+        * This is buggy if we ever see an HTTP/1.10
+        */
+        if (apr_date_checkmask(buffer, "HTTP/#.# ###*")) {
+            int major, minor;
+
+            if (2 != sscanf(buffer, "HTTP/%u.%u", &major, &minor)) {
+                major = 1;
+                minor = 1;
+            }
+            /* If not an HTTP/1 message or
+             * if the status line was > 8192 bytes
+             */
+            else if ((buffer[5] != '1') || (len >= sizeof(buffer)-1)) {
+                ap_proxy_http_cleanup(NULL, r, backend);
+                return ap_proxyerror(r, HTTP_BAD_GATEWAY,
+                apr_pstrcat(p, "Corrupt status line returned by remote "
+                            "server: ", buffer, NULL));
+            }
+            backasswards = 0;
+
+            keepchar = buffer[12];
+            buffer[12] = '\0';
+            r->status = atoi(&buffer[9]);
+
+            if (keepchar != '\0') {
+                buffer[12] = keepchar;
+            } else {
+                /* 2616 requires the space in Status-Line; the origin
+                 * server may have sent one but ap_rgetline_core will
+                 * have stripped it. */
+                buffer[12] = ' ';
+                buffer[13] = '\0';
+            }
+            r->status_line = apr_pstrdup(p, &buffer[9]);
+            
+
+            /* read the headers. */
+            /* N.B. for HTTP/1.0 clients, we have to fold line-wrapped headers*/
+            /* Also, take care with headers with multiple occurences. */
+
+            /* First, tuck away all already existing cookies */
+            save_table = apr_table_make(r->pool, 2);
+            apr_table_do(addit_dammit, save_table, r->headers_out,
+                         "Set-Cookie", NULL);
+
+	    /* shove the headers direct into r->headers_out */
+            ap_proxy_read_headers(r, rp, buffer, sizeof(buffer), origin);
+
+            if (r->headers_out == NULL) {
+                ap_log_error(APLOG_MARK, APLOG_WARNING, 0,
+                             r->server, "proxy: bad HTTP/%d.%d header "
+                             "returned by %s (%s)", major, minor, r->uri,
+                             r->method);
+                backend->close += 1;
+                /*
+                 * ap_send_error relies on a headers_out to be present. we
+                 * are in a bad position here.. so force everything we send out
+                 * to have nothing to do with the incoming packet
+                 */
+                r->headers_out = apr_table_make(r->pool,1);
+                r->status = HTTP_BAD_GATEWAY;
+                r->status_line = "bad gateway";
+                return r->status;
+
+            } else {
+                const char *buf;
+
+                /* Now, add in the just read cookies */
+                apr_table_do(addit_dammit, save_table, r->headers_out,
+        	             "Set-Cookie", NULL);
+
+                /* and now load 'em all in */
+                if (!apr_is_empty_table(save_table)) {
+                    apr_table_unset(r->headers_out, "Set-Cookie");
+                    r->headers_out = apr_table_overlay(r->pool,
+                                                       r->headers_out,
+                                                       save_table);
+                }
+                
+                /* strip connection listed hop-by-hop headers from response */
+                backend->close += ap_proxy_liststr(apr_table_get(r->headers_out,
+                                                                 "Connection"),
+                                                  "close");
+                ap_proxy_clear_connection(p, r->headers_out);
+                if ((buf = apr_table_get(r->headers_out, "Content-Type"))) {
+                    ap_set_content_type(r, apr_pstrdup(p, buf));
+                }            
+                ap_proxy_pre_http_request(origin,rp);
+            }
+
+            /* handle Via header in response */
+            if (conf->viaopt != via_off && conf->viaopt != via_block) {
+                const char *server_name = ap_get_server_name(r);
+                /* If USE_CANONICAL_NAME_OFF was configured for the proxy virtual host,
+                 * then the server name returned by ap_get_server_name() is the
+                 * origin server name (which does make too much sense with Via: headers)
+                 * so we use the proxy vhost's name instead.
+                 */
+                if (server_name == r->hostname)
+                    server_name = r->server->server_hostname;
+                /* create a "Via:" response header entry and merge it */
+                apr_table_mergen(r->headers_out, "Via",
+                                 (conf->viaopt == via_full)
+                                     ? apr_psprintf(p, "%d.%d %s%s (%s)",
+                                           HTTP_VERSION_MAJOR(r->proto_num),
+                                           HTTP_VERSION_MINOR(r->proto_num),
+                                           server_name,
+                                           server_portstr,
+                                           AP_SERVER_BASEVERSION)
+                                     : apr_psprintf(p, "%d.%d %s%s",
+                                           HTTP_VERSION_MAJOR(r->proto_num),
+                                           HTTP_VERSION_MINOR(r->proto_num),
+                                           server_name,
+                                           server_portstr)
+                );
+            }
+
+            /* cancel keepalive if HTTP/1.0 or less */
+            if ((major < 1) || (minor < 1)) {
+                backend->close += 1;
+                origin->keepalive = AP_CONN_CLOSE;
+            }
+        } else {
+            /* an http/0.9 response */
+            backasswards = 1;
+            r->status = 200;
+            r->status_line = "200 OK";
+            backend->close += 1;
+        }
+
+        interim_response = ap_is_HTTP_INFO(r->status);
+        if (interim_response) {
+            ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, NULL,
+                         "proxy: HTTP: received interim %d response",
+                         r->status);
+        }
+        /* Moved the fixups of Date headers and those affected by
+         * ProxyPassReverse/etc from here to ap_proxy_read_headers
+         */
+
+        if ((r->status == 401) && (conf->error_override != 0)) {
+            const char *buf;
+            const char *wa = "WWW-Authenticate";
+            if ((buf = apr_table_get(r->headers_out, wa))) {
+                apr_table_set(r->err_headers_out, wa, buf);
+            } else {
+                ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+                             "proxy: origin server sent 401 without WWW-Authenticate header");
+            }
+        }
+
+        r->sent_bodyct = 1;
+        /* Is it an HTTP/0.9 response? If so, send the extra data */
+        if (backasswards) {
+            apr_ssize_t cntr = len;
+            /*@@@FIXME:
+             * At this point in response processing of a 0.9 response,
+             * we don't know yet whether data is binary or not.
+             * mod_charset_lite will get control later on, so it cannot
+             * decide on the conversion of this buffer full of data.
+             * However, chances are that we are not really talking to an
+             * HTTP/0.9 server, but to some different protocol, therefore
+             * the best guess IMHO is to always treat the buffer as "text/x":
+             */
+            ap_xlate_proto_to_ascii(buffer, len);
+            e = apr_bucket_heap_create(buffer, cntr, NULL, c->bucket_alloc);
+            APR_BRIGADE_INSERT_TAIL(bb, e);
+        }
+
+        /* send body - but only if a body is expected */
+        if ((!r->header_only) &&                   /* not HEAD request */
+            !interim_response &&                   /* not any 1xx response */
+            (r->status != HTTP_NO_CONTENT) &&      /* not 204 */
+            (r->status != HTTP_RESET_CONTENT) &&   /* not 205 */
+            (r->status != HTTP_NOT_MODIFIED)) {    /* not 304 */
+
+            /* We need to copy the output headers and treat them as input
+             * headers as well.  BUT, we need to do this before we remove
+             * TE, so that they are preserved accordingly for
+             * ap_http_filter to know where to end.
+             */
+            rp->headers_in = apr_table_copy(r->pool, r->headers_out);
+
+            apr_table_unset(r->headers_out,"Transfer-Encoding");
+
+            ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+                         "proxy: start body send");
+             
+            /*
+             * if we are overriding the errors, we can't put the content
+             * of the page into the brigade
+             */
+            if (conf->error_override == 0 || ap_is_HTTP_SUCCESS(r->status)) {
+
+                /* read the body, pass it to the output filters */
+                int finish = FALSE;
+                while (ap_get_brigade(rp->input_filters, 
+                                      bb, 
+                                      AP_MODE_READBYTES, 
+                                      APR_BLOCK_READ, 
+                                      conf->io_buffer_size) == APR_SUCCESS) {
+#if DEBUGGING
+                    {
+                    apr_off_t readbytes;
+                    apr_brigade_length(bb, 0, &readbytes);
+                    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0,
+                                 r->server, "proxy (PID %d): readbytes: %#x",
+                                 getpid(), readbytes);
+                    }
+#endif
+                    /* sanity check */
+                    if (APR_BRIGADE_EMPTY(bb)) {
+                        apr_brigade_cleanup(bb);
+                        break;
+                    }
+
+                    /* found the last brigade? */
+                    if (APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(bb))) {
+                        /* if this is the last brigade, cleanup the
+                         * backend connection first to prevent the
+                         * backend server from hanging around waiting
+                         * for a slow client to eat these bytes
+                         */
+                        backend->close = 1;
+                        /* signal that we must leave */
+                        finish = TRUE;
+                    }
+
+                    /* try send what we read */
+                    if (ap_pass_brigade(r->output_filters, bb) != APR_SUCCESS) {
+                        /* Ack! Phbtt! Die! User aborted! */
+                        backend->close = 1;  /* this causes socket close below */
+                        finish = TRUE;
+                    }
+
+                    /* make sure we always clean up after ourselves */
+                    apr_brigade_cleanup(bb);
+
+                    /* if we are done, leave */
+                    if (TRUE == finish) {
+                        break;
+                    }
+                }
+            }
+            ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+                         "proxy: end body send");
+        } else {
+            ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+                         "proxy: header only");
+        }
+    } while (interim_response);
+
+    if (conf->error_override) {
+        /* the code above this checks for 'OK' which is what the hook expects */
+        if (ap_is_HTTP_SUCCESS(r->status))
+            return OK;
+        else {
+            /* clear r->status for override error, otherwise ErrorDocument
+             * thinks that this is a recursive error, and doesn't find the
+             * custom error page
+             */
+            int status = r->status;
+            r->status = HTTP_OK;
+            /* Discard body, if one is expected */
+            if ((status != HTTP_NO_CONTENT) && /* not 204 */
+                (status != HTTP_RESET_CONTENT) && /* not 205 */
+                (status != HTTP_NOT_MODIFIED)) { /* not 304 */
+               ap_discard_request_body(rp);
+           }
+            return status;
+        }
+    } else 
+        return OK;
+}
+
+static
+apr_status_t ap_proxy_http_cleanup(const char *scheme, request_rec *r,
+                                   proxy_conn_rec *backend)
+{
+    /* If there are no KeepAlives, or if the connection has been signalled
+     * to close, close the socket and clean up
+     */
+
+    /* if the connection is < HTTP/1.1, or Connection: close,
+     * we close the socket, otherwise we leave it open for KeepAlive support
+     */
+    if (backend->close || (r->proto_num < HTTP_VERSION(1,1))) {
+        backend->close_on_recycle = 1;
+        ap_set_module_config(r->connection->conn_config, &proxy_http_module, NULL);
+        ap_proxy_release_connection(scheme, backend, r->server);    
+    }
+    return OK;
+}
+
+/*
+ * This handles http:// URLs, and other URLs using a remote proxy over http
+ * If proxyhost is NULL, then contact the server directly, otherwise
+ * go via the proxy.
+ * Note that if a proxy is used, then URLs other than http: can be accessed,
+ * also, if we have trouble which is clearly specific to the proxy, then
+ * we return DECLINED so that we can try another proxy. (Or the direct
+ * route.)
+ */
+int ap_proxy_http_handler(request_rec *r, proxy_worker *worker,
+                          proxy_server_conf *conf,
+                          char *url, const char *proxyname, 
+                          apr_port_t proxyport)
+{
+    int status;
+    char server_portstr[32];
+    char *scheme;
+    const char *proxy_function;
+    const char *u;
+    proxy_conn_rec *backend = NULL;
+    int is_ssl = 0;
+
+    /* Note: Memory pool allocation.
+     * A downstream keepalive connection is always connected to the existence
+     * (or not) of an upstream keepalive connection. If this is not done then
+     * load balancing against multiple backend servers breaks (one backend
+     * server ends up taking 100% of the load), and the risk is run of
+     * downstream keepalive connections being kept open unnecessarily. This
+     * keeps webservers busy and ties up resources.
+     *
+     * As a result, we allocate all sockets out of the upstream connection
+     * pool, and when we want to reuse a socket, we check first whether the
+     * connection ID of the current upstream connection is the same as that
+     * of the connection when the socket was opened.
+     */
+    apr_pool_t *p = r->connection->pool;
+    conn_rec *c = r->connection;
+    apr_uri_t *uri = apr_palloc(r->connection->pool, sizeof(*uri));
+
+    /* find the scheme */
+    u = strchr(url, ':');
+    if (u == NULL || u[1] != '/' || u[2] != '/' || u[3] == '\0')
+       return DECLINED;
+    if ((u - url) > 14)
+        return HTTP_BAD_REQUEST;
+    scheme = apr_pstrndup(c->pool, url, u - url);
+    /* scheme is lowercase */
+    apr_tolower(scheme);
+    /* is it for us? */
+    if (strcmp(scheme, "https") == 0) {
+        if (!ap_proxy_ssl_enable(NULL)) {
+            ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+                         "proxy: HTTPS: declining URL %s"
+                         " (mod_ssl not configured?)", url);
+            return DECLINED;
+        }
+        is_ssl = 1;
+        proxy_function = "HTTPS";
+    }
+    else if (!(strcmp(scheme, "http") == 0 || (strcmp(scheme, "ftp") == 0 && proxyname))) {
+        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+                     "proxy: HTTP: declining URL %s", url);
+        return DECLINED; /* only interested in HTTP, or FTP via proxy */
+    }
+    else {
+        if (*scheme == 'h')
+            proxy_function = "HTTP";
+        else
+            proxy_function = "FTP";
+    }
+    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+             "proxy: HTTP: serving URL %s", url);
+    
+    
+    /* only use stored info for top-level pages. Sub requests don't share 
+     * in keepalives
+     */
+    if (!r->main) {
+        backend = (proxy_conn_rec *) ap_get_module_config(c->conn_config,
+                                                      &proxy_http_module);
+    }
+    /* create space for state information */
+    if (!backend) {
+        status = ap_proxy_acquire_connection(proxy_function, &backend, worker, r->server);
+        if (status != OK) {
+            if (backend) {
+                backend->close_on_recycle = 1;
+                ap_proxy_release_connection(proxy_function, backend, r->server);
+            }
+            return status;
+        }
+        if (!r->main) {
+            ap_set_module_config(c->conn_config, &proxy_http_module, backend);
+        }
+    }
+
+    backend->is_ssl = is_ssl;
+    backend->close_on_recycle = 1;
+
+    /* Step One: Determine Who To Connect To */
+    status = ap_proxy_determine_connection(p, r, conf, worker, backend, c->pool,
+                                           uri, &url, proxyname, proxyport,
+                                           server_portstr,
+                                           sizeof(server_portstr));
+
+    if ( status != OK ) {
+        return status;
+    }
+
+    /* Step Two: Make the Connection */
+    if (ap_proxy_connect_backend(proxy_function, backend, worker, r->server)) {
+        return HTTP_SERVICE_UNAVAILABLE;
+    }
+
+    /* Step Three: Create conn_rec */
+    if (!backend->connection) {
+        status = ap_proxy_connection_create(proxy_function, backend, c, r->server);
+        if (status != OK)
+            return status;
+    }
+   
+    /* Step Four: Send the Request */
+    status = ap_proxy_http_request(p, r, backend, backend->connection, conf, uri, url,
+                                   server_portstr);
+    if ( status != OK ) {
+        return status;
+    }
+
+    /* Step Five: Receive the Response */
+    status = ap_proxy_http_process_response(p, r, backend, backend->connection, conf,
+                                            server_portstr);
+    if (status != OK) {
+        /* clean up even if there is an error */
+        ap_proxy_http_cleanup(proxy_function, r, backend);
+        return status;
+    }
+
+    /* Step Six: Clean Up */
+    status = ap_proxy_http_cleanup(proxy_function, r, backend);
+    if ( status != OK ) {
+        return status;
+    }
+
+    return OK;
+}
+
+static void ap_proxy_http_register_hook(apr_pool_t *p)
+{
+    proxy_hook_scheme_handler(ap_proxy_http_handler, NULL, NULL, APR_HOOK_FIRST);
+    proxy_hook_canon_handler(ap_proxy_http_canon, NULL, NULL, APR_HOOK_FIRST);
+}
+
+module AP_MODULE_DECLARE_DATA proxy_http_module = {
+    STANDARD20_MODULE_STUFF,
+    NULL,              /* create per-directory config structure */
+    NULL,              /* merge per-directory config structures */
+    NULL,              /* create per-server config structure */
+    NULL,              /* merge per-server config structures */
+    NULL,              /* command apr_table_t */
+    ap_proxy_http_register_hook/* register hooks */
+};
+

Added: branches/tomcat5.5/upstream/5.5.20/connectors/ajp/proxy/proxy_util.c
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/ajp/proxy/proxy_util.c	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/ajp/proxy/proxy_util.c	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,1877 @@
+/* Copyright 1999-2004 The Apache Software Foundation
+ *
+ * Licensed 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.
+ */
+
+/* Utility routines for Apache proxy */
+#include "mod_proxy.h"
+#include "ap_mpm.h"
+#include "scoreboard.h"
+#include "apr_version.h"
+
+#if (APR_MAJOR_VERSION < 1)
+#undef apr_socket_create
+#define apr_socket_create apr_socket_create_ex
+#endif
+
+/* Global balancer counter */
+static int lb_workers = 0;
+static int lb_workers_limit = 0;
+
+static int proxy_match_ipaddr(struct dirconn_entry *This, request_rec *r);
+static int proxy_match_domainname(struct dirconn_entry *This, request_rec *r);
+static int proxy_match_hostname(struct dirconn_entry *This, request_rec *r);
+static int proxy_match_word(struct dirconn_entry *This, request_rec *r);
+
+APR_IMPLEMENT_OPTIONAL_HOOK_RUN_ALL(proxy, PROXY, int, create_req, 
+                                   (request_rec *r, request_rec *pr), (r, pr),
+                                   OK, DECLINED)
+
+/* already called in the knowledge that the characters are hex digits */
+PROXY_DECLARE(int) ap_proxy_hex2c(const char *x)
+{
+    int i, ch;
+
+#if !APR_CHARSET_EBCDIC
+    ch = x[0];
+    if (apr_isdigit(ch))
+	i = ch - '0';
+    else if (apr_isupper(ch))
+	i = ch - ('A' - 10);
+    else
+	i = ch - ('a' - 10);
+    i <<= 4;
+
+    ch = x[1];
+    if (apr_isdigit(ch))
+	i += ch - '0';
+    else if (apr_isupper(ch))
+	i += ch - ('A' - 10);
+    else
+	i += ch - ('a' - 10);
+    return i;
+#else /*APR_CHARSET_EBCDIC*/
+    /* we assume that the hex value refers to an ASCII character
+     * so convert to EBCDIC so that it makes sense locally;
+     *
+     * example:
+     *
+     * client specifies %20 in URL to refer to a space char;
+     * at this point we're called with EBCDIC "20"; after turning
+     * EBCDIC "20" into binary 0x20, we then need to assume that 0x20
+     * represents an ASCII char and convert 0x20 to EBCDIC, yielding
+     * 0x40
+     */
+    char buf[1];
+
+    if (1 == sscanf(x, "%2x", &i)) {
+        buf[0] = i & 0xFF;
+        ap_xlate_proto_from_ascii(buf, 1);
+        return buf[0];
+    }
+    else {
+        return 0;
+    }
+#endif /*APR_CHARSET_EBCDIC*/
+}
+
+PROXY_DECLARE(void) ap_proxy_c2hex(int ch, char *x)
+{
+#if !APR_CHARSET_EBCDIC
+    int i;
+
+    x[0] = '%';
+    i = (ch & 0xF0) >> 4;
+    if (i >= 10)
+	x[1] = ('A' - 10) + i;
+    else
+	x[1] = '0' + i;
+
+    i = ch & 0x0F;
+    if (i >= 10)
+	x[2] = ('A' - 10) + i;
+    else
+	x[2] = '0' + i;
+#else /*APR_CHARSET_EBCDIC*/
+    static const char ntoa[] = { "0123456789ABCDEF" };
+    char buf[1];
+
+    ch &= 0xFF;
+
+    buf[0] = ch;
+    ap_xlate_proto_to_ascii(buf, 1);
+
+    x[0] = '%';
+    x[1] = ntoa[(buf[0] >> 4) & 0x0F];
+    x[2] = ntoa[buf[0] & 0x0F];
+    x[3] = '\0';
+#endif /*APR_CHARSET_EBCDIC*/
+}
+
+/*
+ * canonicalise a URL-encoded string
+ */
+
+/*
+ * Convert a URL-encoded string to canonical form.
+ * It decodes characters which need not be encoded,
+ * and encodes those which must be encoded, and does not touch
+ * those which must not be touched.
+ */
+PROXY_DECLARE(char *)ap_proxy_canonenc(apr_pool_t *p, const char *x, int len, enum enctype t,
+	int isenc)
+{
+    int i, j, ch;
+    char *y;
+    char *allowed;	/* characters which should not be encoded */
+    char *reserved;	/* characters which much not be en/de-coded */
+
+/* N.B. in addition to :@&=, this allows ';' in an http path
+ * and '?' in an ftp path -- this may be revised
+ * 
+ * Also, it makes a '+' character in a search string reserved, as
+ * it may be form-encoded. (Although RFC 1738 doesn't allow this -
+ * it only permits ; / ? : @ = & as reserved chars.)
+ */
+    if (t == enc_path)
+	allowed = "$-_.+!*'(),;:@&=";
+    else if (t == enc_search)
+	allowed = "$-_.!*'(),;:@&=";
+    else if (t == enc_user)
+	allowed = "$-_.+!*'(),;@&=";
+    else if (t == enc_fpath)
+	allowed = "$-_.+!*'(),?:@&=";
+    else			/* if (t == enc_parm) */
+	allowed = "$-_.+!*'(),?/:@&=";
+
+    if (t == enc_path)
+	reserved = "/";
+    else if (t == enc_search)
+	reserved = "+";
+    else
+	reserved = "";
+
+    y = apr_palloc(p, 3 * len + 1);
+
+    for (i = 0, j = 0; i < len; i++, j++) {
+/* always handle '/' first */
+	ch = x[i];
+	if (strchr(reserved, ch)) {
+	    y[j] = ch;
+	    continue;
+	}
+/* decode it if not already done */
+	if (isenc && ch == '%') {
+	    if (!apr_isxdigit(x[i + 1]) || !apr_isxdigit(x[i + 2]))
+		return NULL;
+	    ch = ap_proxy_hex2c(&x[i + 1]);
+	    i += 2;
+	    if (ch != 0 && strchr(reserved, ch)) {	/* keep it encoded */
+		ap_proxy_c2hex(ch, &y[j]);
+		j += 2;
+		continue;
+	    }
+	}
+/* recode it, if necessary */
+	if (!apr_isalnum(ch) && !strchr(allowed, ch)) {
+	    ap_proxy_c2hex(ch, &y[j]);
+	    j += 2;
+	}
+	else
+	    y[j] = ch;
+    }
+    y[j] = '\0';
+    return y;
+}
+
+/*
+ * Parses network-location.
+ *    urlp           on input the URL; on output the path, after the leading /
+ *    user           NULL if no user/password permitted
+ *    password       holder for password
+ *    host           holder for host
+ *    port           port number; only set if one is supplied.
+ *
+ * Returns an error string.
+ */
+PROXY_DECLARE(char *)
+     ap_proxy_canon_netloc(apr_pool_t *p, char **const urlp, char **userp,
+			char **passwordp, char **hostp, apr_port_t *port)
+{
+    char *addr, *scope_id, *strp, *host, *url = *urlp;
+    char *user = NULL, *password = NULL;
+    apr_port_t tmp_port;
+    apr_status_t rv;
+
+    if (url[0] != '/' || url[1] != '/')
+	return "Malformed URL";
+    host = url + 2;
+    url = strchr(host, '/');
+    if (url == NULL)
+	url = "";
+    else
+	*(url++) = '\0';	/* skip seperating '/' */
+
+    /* find _last_ '@' since it might occur in user/password part */
+    strp = strrchr(host, '@');
+
+    if (strp != NULL) {
+	*strp = '\0';
+	user = host;
+	host = strp + 1;
+
+/* find password */
+	strp = strchr(user, ':');
+	if (strp != NULL) {
+	    *strp = '\0';
+	    password = ap_proxy_canonenc(p, strp + 1, strlen(strp + 1), enc_user, 1);
+	    if (password == NULL)
+		return "Bad %-escape in URL (password)";
+	}
+
+	user = ap_proxy_canonenc(p, user, strlen(user), enc_user, 1);
+	if (user == NULL)
+	    return "Bad %-escape in URL (username)";
+    }
+    if (userp != NULL) {
+	*userp = user;
+    }
+    if (passwordp != NULL) {
+	*passwordp = password;
+    }
+
+    /* Parse the host string to separate host portion from optional port.
+     * Perform range checking on port.
+     */
+    rv = apr_parse_addr_port(&addr, &scope_id, &tmp_port, host, p);
+    if (rv != APR_SUCCESS || addr == NULL || scope_id != NULL) {
+        return "Invalid host/port";
+    }
+    if (tmp_port != 0) { /* only update caller's port if port was specified */
+        *port = tmp_port;
+    }
+
+    ap_str_tolower(addr); /* DNS names are case-insensitive */
+
+    *urlp = url;
+    *hostp = addr;
+
+    return NULL;
+}
+
+static const char * const lwday[7] =
+{"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};
+
+/*
+ * If the date is a valid RFC 850 date or asctime() date, then it
+ * is converted to the RFC 1123 format, otherwise it is not modified.
+ * This routine is not very fast at doing conversions, as it uses
+ * sscanf and sprintf. However, if the date is already correctly
+ * formatted, then it exits very quickly.
+ */
+PROXY_DECLARE(const char *)
+     ap_proxy_date_canon(apr_pool_t *p, const char *x1)
+{
+    char *x = apr_pstrdup(p, x1);
+    int wk, mday, year, hour, min, sec, mon;
+    char *q, month[4], zone[4], week[4];
+
+    q = strchr(x, ',');
+    /* check for RFC 850 date */
+    if (q != NULL && q - x > 3 && q[1] == ' ') {
+	*q = '\0';
+	for (wk = 0; wk < 7; wk++)
+	    if (strcmp(x, lwday[wk]) == 0)
+		break;
+	*q = ',';
+	if (wk == 7)
+	    return x;		/* not a valid date */
+	if (q[4] != '-' || q[8] != '-' || q[11] != ' ' || q[14] != ':' ||
+	    q[17] != ':' || strcmp(&q[20], " GMT") != 0)
+	    return x;
+	if (sscanf(q + 2, "%u-%3s-%u %u:%u:%u %3s", &mday, month, &year,
+		   &hour, &min, &sec, zone) != 7)
+	    return x;
+	if (year < 70)
+	    year += 2000;
+	else
+	    year += 1900;
+    }
+    else {
+/* check for acstime() date */
+	if (x[3] != ' ' || x[7] != ' ' || x[10] != ' ' || x[13] != ':' ||
+	    x[16] != ':' || x[19] != ' ' || x[24] != '\0')
+	    return x;
+	if (sscanf(x, "%3s %3s %u %u:%u:%u %u", week, month, &mday, &hour,
+		   &min, &sec, &year) != 7)
+	    return x;
+	for (wk = 0; wk < 7; wk++)
+	    if (strcmp(week, apr_day_snames[wk]) == 0)
+		break;
+	if (wk == 7)
+	    return x;
+    }
+
+/* check date */
+    for (mon = 0; mon < 12; mon++)
+	if (strcmp(month, apr_month_snames[mon]) == 0)
+	    break;
+    if (mon == 12)
+	return x;
+
+    q = apr_palloc(p, 30);
+    apr_snprintf(q, 30, "%s, %.2d %s %d %.2d:%.2d:%.2d GMT", apr_day_snames[wk],
+       mday, apr_month_snames[mon], year, hour, min, sec);
+    return q;
+}
+
+PROXY_DECLARE(request_rec *)ap_proxy_make_fake_req(conn_rec *c, request_rec *r)
+{
+    request_rec *rp = apr_pcalloc(c->pool, sizeof(*r));
+
+    rp->pool            = c->pool;
+    rp->status          = HTTP_OK;
+
+    rp->headers_in      = apr_table_make(c->pool, 50);
+    rp->subprocess_env  = apr_table_make(c->pool, 50);
+    rp->headers_out     = apr_table_make(c->pool, 12);
+    rp->err_headers_out = apr_table_make(c->pool, 5);
+    rp->notes           = apr_table_make(c->pool, 5);
+
+    rp->server = r->server;
+    rp->proxyreq = r->proxyreq;
+    rp->request_time = r->request_time;
+    rp->connection      = c;
+    rp->output_filters  = c->output_filters;
+    rp->input_filters   = c->input_filters;
+    rp->proto_output_filters  = c->output_filters;
+    rp->proto_input_filters   = c->input_filters;
+
+    rp->request_config  = ap_create_request_config(c->pool);
+    proxy_run_create_req(r, rp);
+
+    return rp;
+}
+
+
+/*
+ * list is a comma-separated list of case-insensitive tokens, with
+ * optional whitespace around the tokens.
+ * The return returns 1 if the token val is found in the list, or 0
+ * otherwise.
+ */
+PROXY_DECLARE(int) ap_proxy_liststr(const char *list, const char *val)
+{
+    int len, i;
+    const char *p;
+
+    len = strlen(val);
+
+    while (list != NULL) {
+	p = ap_strchr_c(list, ',');
+	if (p != NULL) {
+	    i = p - list;
+	    do
+		p++;
+	    while (apr_isspace(*p));
+	}
+	else
+	    i = strlen(list);
+
+	while (i > 0 && apr_isspace(list[i - 1]))
+	    i--;
+	if (i == len && strncasecmp(list, val, len) == 0)
+	    return 1;
+	list = p;
+    }
+    return 0;
+}
+
+/*
+ * list is a comma-separated list of case-insensitive tokens, with
+ * optional whitespace around the tokens.
+ * if val appears on the list of tokens, it is removed from the list,
+ * and the new list is returned.
+ */
+PROXY_DECLARE(char *)ap_proxy_removestr(apr_pool_t *pool, const char *list, const char *val)
+{
+    int len, i;
+    const char *p;
+    char *new = NULL;
+
+    len = strlen(val);
+
+    while (list != NULL) {
+	p = ap_strchr_c(list, ',');
+	if (p != NULL) {
+	    i = p - list;
+	    do
+		p++;
+	    while (apr_isspace(*p));
+	}
+	else
+	    i = strlen(list);
+
+	while (i > 0 && apr_isspace(list[i - 1]))
+	    i--;
+	if (i == len && strncasecmp(list, val, len) == 0) {
+	    /* do nothing */
+	}
+	else {
+	    if (new)
+		new = apr_pstrcat(pool, new, ",", apr_pstrndup(pool, list, i), NULL);
+	    else
+		new = apr_pstrndup(pool, list, i);
+	}
+	list = p;
+    }
+    return new;
+}
+
+/*
+ * Converts 8 hex digits to a time integer
+ */
+PROXY_DECLARE(int) ap_proxy_hex2sec(const char *x)
+{
+    int i, ch;
+    unsigned int j;
+
+    for (i = 0, j = 0; i < 8; i++) {
+	ch = x[i];
+	j <<= 4;
+	if (apr_isdigit(ch))
+	    j |= ch - '0';
+	else if (apr_isupper(ch))
+	    j |= ch - ('A' - 10);
+	else
+	    j |= ch - ('a' - 10);
+    }
+    if (j == 0xffffffff)
+	return -1;		/* so that it works with 8-byte ints */
+    else
+	return j;
+}
+
+/*
+ * Converts a time integer to 8 hex digits
+ */
+PROXY_DECLARE(void) ap_proxy_sec2hex(int t, char *y)
+{
+    int i, ch;
+    unsigned int j = t;
+
+    for (i = 7; i >= 0; i--) {
+	ch = j & 0xF;
+	j >>= 4;
+	if (ch >= 10)
+	    y[i] = ch + ('A' - 10);
+	else
+	    y[i] = ch + '0';
+    }
+    y[8] = '\0';
+}
+
+PROXY_DECLARE(int) ap_proxyerror(request_rec *r, int statuscode, const char *message)
+{
+    apr_table_setn(r->notes, "error-notes",
+	apr_pstrcat(r->pool, 
+		"The proxy server could not handle the request "
+		"<em><a href=\"", ap_escape_uri(r->pool, r->uri),
+		"\">", ap_escape_html(r->pool, r->method),
+		"&nbsp;", 
+		ap_escape_html(r->pool, r->uri), "</a></em>.<p>\n"
+		"Reason: <strong>",
+		ap_escape_html(r->pool, message), 
+		"</strong></p>", NULL));
+
+    /* Allow "error-notes" string to be printed by ap_send_error_response() */
+    apr_table_setn(r->notes, "verbose-error-to", apr_pstrdup(r->pool, "*"));
+
+    r->status_line = apr_psprintf(r->pool, "%3.3u Proxy Error", statuscode);
+    ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+			 "proxy: %s returned by %s", message, r->uri);
+    return statuscode;
+}
+
+static const char *
+     proxy_get_host_of_request(request_rec *r)
+{
+    char *url, *user = NULL, *password = NULL, *err, *host;
+    apr_port_t port;
+
+    if (r->hostname != NULL)
+	return r->hostname;
+
+    /* Set url to the first char after "scheme://" */
+    if ((url = strchr(r->uri, ':')) == NULL
+	|| url[1] != '/' || url[2] != '/')
+	return NULL;
+
+    url = apr_pstrdup(r->pool, &url[1]);	/* make it point to "//", which is what proxy_canon_netloc expects */
+
+    err = ap_proxy_canon_netloc(r->pool, &url, &user, &password, &host, &port);
+
+    if (err != NULL)
+	ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+		     "%s", err);
+
+    r->hostname = host;
+
+    return host;		/* ought to return the port, too */
+}
+
+/* Return TRUE if addr represents an IP address (or an IP network address) */
+PROXY_DECLARE(int) ap_proxy_is_ipaddr(struct dirconn_entry *This, apr_pool_t *p)
+{
+    const char *addr = This->name;
+    long ip_addr[4];
+    int i, quads;
+    long bits;
+
+    /* if the address is given with an explicit netmask, use that */
+    /* Due to a deficiency in apr_inet_addr(), it is impossible to parse */
+    /* "partial" addresses (with less than 4 quads) correctly, i.e.  */
+    /* 192.168.123 is parsed as 192.168.0.123, which is not what I want. */
+    /* I therefore have to parse the IP address manually: */
+    /*if (proxy_readmask(This->name, &This->addr.s_addr, &This->mask.s_addr) == 0) */
+    /* addr and mask were set by proxy_readmask() */
+    /*return 1; */
+
+    /* Parse IP addr manually, optionally allowing */
+    /* abbreviated net addresses like 192.168. */
+
+    /* Iterate over up to 4 (dotted) quads. */
+    for (quads = 0; quads < 4 && *addr != '\0'; ++quads) {
+	char *tmp;
+
+	if (*addr == '/' && quads > 0)	/* netmask starts here. */
+	    break;
+
+	if (!apr_isdigit(*addr))
+	    return 0;		/* no digit at start of quad */
+
+	ip_addr[quads] = strtol(addr, &tmp, 0);
+
+	if (tmp == addr)	/* expected a digit, found something else */
+	    return 0;
+
+	if (ip_addr[quads] < 0 || ip_addr[quads] > 255) {
+	    /* invalid octet */
+	    return 0;
+	}
+
+	addr = tmp;
+
+	if (*addr == '.' && quads != 3)
+	    ++addr;		/* after the 4th quad, a dot would be illegal */
+    }
+
+    for (This->addr.s_addr = 0, i = 0; i < quads; ++i)
+	This->addr.s_addr |= htonl(ip_addr[i] << (24 - 8 * i));
+
+    if (addr[0] == '/' && apr_isdigit(addr[1])) {	/* net mask follows: */
+	char *tmp;
+
+	++addr;
+
+	bits = strtol(addr, &tmp, 0);
+
+	if (tmp == addr)	/* expected a digit, found something else */
+	    return 0;
+
+	addr = tmp;
+
+	if (bits < 0 || bits > 32)	/* netmask must be between 0 and 32 */
+	    return 0;
+
+    }
+    else {
+	/* Determine (i.e., "guess") netmask by counting the */
+	/* number of trailing .0's; reduce #quads appropriately */
+	/* (so that 192.168.0.0 is equivalent to 192.168.)        */
+	while (quads > 0 && ip_addr[quads - 1] == 0)
+	    --quads;
+
+	/* "IP Address should be given in dotted-quad form, optionally followed by a netmask (e.g., 192.168.111.0/24)"; */
+	if (quads < 1)
+	    return 0;
+
+	/* every zero-byte counts as 8 zero-bits */
+	bits = 8 * quads;
+
+	if (bits != 32)		/* no warning for fully qualified IP address */
+            ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
+	      "Warning: NetMask not supplied with IP-Addr; guessing: %s/%ld\n",
+		 inet_ntoa(This->addr), bits);
+    }
+
+    This->mask.s_addr = htonl(APR_INADDR_NONE << (32 - bits));
+
+    if (*addr == '\0' && (This->addr.s_addr & ~This->mask.s_addr) != 0) {
+        ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
+	    "Warning: NetMask and IP-Addr disagree in %s/%ld\n",
+		inet_ntoa(This->addr), bits);
+	This->addr.s_addr &= This->mask.s_addr;
+        ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
+	    "         Set to %s/%ld\n",
+		inet_ntoa(This->addr), bits);
+    }
+
+    if (*addr == '\0') {
+	This->matcher = proxy_match_ipaddr;
+	return 1;
+    }
+    else
+	return (*addr == '\0');	/* okay iff we've parsed the whole string */
+}
+
+/* Return TRUE if addr represents an IP address (or an IP network address) */
+static int proxy_match_ipaddr(struct dirconn_entry *This, request_rec *r)
+{
+    int i, ip_addr[4];
+    struct in_addr addr, *ip;
+    const char *host = proxy_get_host_of_request(r);
+
+    if (host == NULL)   /* oops! */
+       return 0;
+
+    memset(&addr, '\0', sizeof addr);
+    memset(ip_addr, '\0', sizeof ip_addr);
+
+    if (4 == sscanf(host, "%d.%d.%d.%d", &ip_addr[0], &ip_addr[1], &ip_addr[2], &ip_addr[3])) {
+	for (addr.s_addr = 0, i = 0; i < 4; ++i)
+	    addr.s_addr |= htonl(ip_addr[i] << (24 - 8 * i));
+
+	if (This->addr.s_addr == (addr.s_addr & This->mask.s_addr)) {
+#if DEBUGGING
+        ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
+                         "1)IP-Match: %s[%s] <-> ", host, inet_ntoa(addr));
+        ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
+                         "%s/", inet_ntoa(This->addr));
+        ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
+                         "%s", inet_ntoa(This->mask));
+#endif
+	    return 1;
+	}
+#if DEBUGGING
+	else {
+        ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
+                         "1)IP-NoMatch: %s[%s] <-> ", host, inet_ntoa(addr));
+        ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
+                         "%s/", inet_ntoa(This->addr));
+        ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
+                         "%s", inet_ntoa(This->mask));
+	}
+#endif
+    }
+    else {
+	struct apr_sockaddr_t *reqaddr;
+
+        if (apr_sockaddr_info_get(&reqaddr, host, APR_UNSPEC, 0, 0, r->pool)
+	    != APR_SUCCESS) {
+#if DEBUGGING
+	    ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
+			 "2)IP-NoMatch: hostname=%s msg=Host not found", 
+			 host);
+#endif
+	    return 0;
+	}
+
+	/* Try to deal with multiple IP addr's for a host */
+	/* FIXME: This needs to be able to deal with IPv6 */
+	while (reqaddr) {
+	    ip = (struct in_addr *) reqaddr->ipaddr_ptr;
+	    if (This->addr.s_addr == (ip->s_addr & This->mask.s_addr)) {
+#if DEBUGGING
+		ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
+			     "3)IP-Match: %s[%s] <-> ", host, 
+			     inet_ntoa(*ip));
+		ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
+			     "%s/", inet_ntoa(This->addr));
+		ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
+			     "%s", inet_ntoa(This->mask));
+#endif
+		return 1;
+	    }
+#if DEBUGGING
+	    else {
+                ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
+			     "3)IP-NoMatch: %s[%s] <-> ", host, 
+			     inet_ntoa(*ip));
+                ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
+			     "%s/", inet_ntoa(This->addr));
+                ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
+			     "%s", inet_ntoa(This->mask));
+	    }
+#endif
+	    reqaddr = reqaddr->next;
+	}
+    }
+
+    return 0;
+}
+
+/* Return TRUE if addr represents a domain name */
+PROXY_DECLARE(int) ap_proxy_is_domainname(struct dirconn_entry *This, apr_pool_t *p)
+{
+    char *addr = This->name;
+    int i;
+
+    /* Domain name must start with a '.' */
+    if (addr[0] != '.')
+        return 0;
+
+    /* rfc1035 says DNS names must consist of "[-a-zA-Z0-9]" and '.' */
+    for (i = 0; apr_isalnum(addr[i]) || addr[i] == '-' || addr[i] == '.'; ++i)
+        continue;
+
+#if 0
+    if (addr[i] == ':') {
+    ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
+                     "@@@@ handle optional port in proxy_is_domainname()");
+	/* @@@@ handle optional port */
+    }
+#endif
+
+    if (addr[i] != '\0')
+        return 0;
+
+    /* Strip trailing dots */
+    for (i = strlen(addr) - 1; i > 0 && addr[i] == '.'; --i)
+        addr[i] = '\0';
+
+    This->matcher = proxy_match_domainname;
+    return 1;
+}
+
+/* Return TRUE if host "host" is in domain "domain" */
+static int proxy_match_domainname(struct dirconn_entry *This, request_rec *r)
+{
+    const char *host = proxy_get_host_of_request(r);
+    int d_len = strlen(This->name), h_len;
+
+    if (host == NULL)		/* some error was logged already */
+        return 0;
+
+    h_len = strlen(host);
+
+    /* @@@ do this within the setup? */
+    /* Ignore trailing dots in domain comparison: */
+    while (d_len > 0 && This->name[d_len - 1] == '.')
+        --d_len;
+    while (h_len > 0 && host[h_len - 1] == '.')
+        --h_len;
+    return h_len > d_len
+        && strncasecmp(&host[h_len - d_len], This->name, d_len) == 0;
+}
+
+/* Return TRUE if host represents a host name */
+PROXY_DECLARE(int) ap_proxy_is_hostname(struct dirconn_entry *This, apr_pool_t *p)
+{
+    struct apr_sockaddr_t *addr;
+    char *host = This->name;
+    int i;
+
+    /* Host names must not start with a '.' */
+    if (host[0] == '.')
+        return 0;
+
+    /* rfc1035 says DNS names must consist of "[-a-zA-Z0-9]" and '.' */
+    for (i = 0; apr_isalnum(host[i]) || host[i] == '-' || host[i] == '.'; ++i);
+
+    if (host[i] != '\0' || apr_sockaddr_info_get(&addr, host, APR_UNSPEC, 0, 0, p) != APR_SUCCESS)
+        return 0;
+    
+    This->hostaddr = addr;
+
+    /* Strip trailing dots */
+    for (i = strlen(host) - 1; i > 0 && host[i] == '.'; --i)
+        host[i] = '\0';
+
+    This->matcher = proxy_match_hostname;
+    return 1;
+}
+
+/* Return TRUE if host "host" is equal to host2 "host2" */
+static int proxy_match_hostname(struct dirconn_entry *This, request_rec *r)
+{
+    char *host = This->name;
+    const char *host2 = proxy_get_host_of_request(r);
+    int h2_len;
+    int h1_len;
+
+    if (host == NULL || host2 == NULL)
+        return 0; /* oops! */
+
+    h2_len = strlen(host2);
+    h1_len = strlen(host);
+
+#if 0
+    struct apr_sockaddr_t *addr = *This->hostaddr;
+
+    /* Try to deal with multiple IP addr's for a host */
+    while (addr) {
+        if (addr->ipaddr_ptr == ? ? ? ? ? ? ? ? ? ? ? ? ?)
+            return 1;
+        addr = addr->next;
+    }
+#endif
+
+    /* Ignore trailing dots in host2 comparison: */
+    while (h2_len > 0 && host2[h2_len - 1] == '.')
+        --h2_len;
+    while (h1_len > 0 && host[h1_len - 1] == '.')
+        --h1_len;
+    return h1_len == h2_len
+        && strncasecmp(host, host2, h1_len) == 0;
+}
+
+/* Return TRUE if addr is to be matched as a word */
+PROXY_DECLARE(int) ap_proxy_is_word(struct dirconn_entry *This, apr_pool_t *p)
+{
+    This->matcher = proxy_match_word;
+    return 1;
+}
+
+/* Return TRUE if string "str2" occurs literally in "str1" */
+static int proxy_match_word(struct dirconn_entry *This, request_rec *r)
+{
+    const char *host = proxy_get_host_of_request(r);
+    return host != NULL && ap_strstr_c(host, This->name) != NULL;
+}
+
+/* checks whether a host in uri_addr matches proxyblock */
+PROXY_DECLARE(int) ap_proxy_checkproxyblock(request_rec *r, proxy_server_conf *conf, 
+                             apr_sockaddr_t *uri_addr)
+{
+    int j;
+    apr_sockaddr_t * src_uri_addr = uri_addr;
+    /* XXX FIXME: conf->noproxies->elts is part of an opaque structure */
+    for (j = 0; j < conf->noproxies->nelts; j++) {
+        struct noproxy_entry *npent = (struct noproxy_entry *) conf->noproxies->elts;
+        struct apr_sockaddr_t *conf_addr = npent[j].addr;
+        uri_addr = src_uri_addr;
+        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+                     "proxy: checking remote machine [%s] against [%s]", uri_addr->hostname, npent[j].name);
+        if ((npent[j].name && ap_strstr_c(uri_addr->hostname, npent[j].name))
+            || npent[j].name[0] == '*') {
+            ap_log_error(APLOG_MARK, APLOG_WARNING, 0, r->server,
+                         "proxy: connect to remote machine %s blocked: name %s matched", uri_addr->hostname, npent[j].name);
+            return HTTP_FORBIDDEN;
+        }
+        while (conf_addr) {
+            while (uri_addr) {
+                char *conf_ip;
+                char *uri_ip;
+                apr_sockaddr_ip_get(&conf_ip, conf_addr);
+                apr_sockaddr_ip_get(&uri_ip, uri_addr);
+                ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+                             "proxy: ProxyBlock comparing %s and %s", conf_ip, uri_ip);
+                if (!apr_strnatcasecmp(conf_ip, uri_ip)) {
+                    ap_log_error(APLOG_MARK, APLOG_WARNING, 0, r->server,
+                                 "proxy: connect to remote machine %s blocked: IP %s matched", uri_addr->hostname, conf_ip);
+                    return HTTP_FORBIDDEN;
+                }
+                uri_addr = uri_addr->next;
+            }
+            conf_addr = conf_addr->next;
+        }
+    }
+    return OK;
+}
+
+/* set up the minimal filter set */
+PROXY_DECLARE(int) ap_proxy_pre_http_request(conn_rec *c, request_rec *r)
+{
+    ap_add_input_filter("HTTP_IN", NULL, r, c);
+    return OK;
+}
+
+/* converts a series of buckets into a string 
+ * XXX: BillS says this function performs essentially the same function as 
+ * ap_rgetline() in protocol.c. Deprecate this function and use ap_rgetline() 
+ * instead? I think ap_proxy_string_read() will not work properly on non ASCII
+ * (EBCDIC) machines either.
+ */
+PROXY_DECLARE(apr_status_t) ap_proxy_string_read(conn_rec *c, apr_bucket_brigade *bb,
+                                                 char *buff, apr_size_t bufflen, int *eos)
+{
+    apr_bucket *e;
+    apr_status_t rv;
+    char *pos = buff;
+    char *response;
+    int found = 0;
+    apr_size_t len;
+
+    /* start with an empty string */
+    buff[0] = 0;
+    *eos = 0;
+
+    /* loop through each brigade */
+    while (!found) {
+        /* get brigade from network one line at a time */
+        if (APR_SUCCESS != (rv = ap_get_brigade(c->input_filters, bb, 
+                                                AP_MODE_GETLINE,
+                                                APR_BLOCK_READ,
+                                                0))) {
+            return rv;
+        }
+        /* loop through each bucket */
+        while (!found) {
+            if (*eos || APR_BRIGADE_EMPTY(bb)) {
+                /* The connection aborted or timed out */
+                return APR_ECONNABORTED;
+            }
+            e = APR_BRIGADE_FIRST(bb);
+            if (APR_BUCKET_IS_EOS(e)) {
+                *eos = 1;
+            }
+            else {
+                if (APR_SUCCESS != apr_bucket_read(e, (const char **)&response, &len, APR_BLOCK_READ)) {
+                    return rv;
+                }
+                /* is string LF terminated? 
+                 * XXX: This check can be made more efficient by simply checking 
+                 * if the last character in the 'response' buffer is an ASCII_LF.
+                 * See ap_rgetline() for an example.
+                 */
+                if (memchr(response, APR_ASCII_LF, len)) {
+                    found = 1;
+                }
+                /* concat strings until buff is full - then throw the data away */
+                if (len > ((bufflen-1)-(pos-buff))) {
+                    len = (bufflen-1)-(pos-buff);
+                }
+                if (len > 0) {
+                    pos = apr_cpystrn(pos, response, len);
+                }
+            }
+            APR_BUCKET_REMOVE(e);
+            apr_bucket_destroy(e);
+        }
+    }
+
+    return APR_SUCCESS;
+}
+
+/* unmerge an element in the table */
+PROXY_DECLARE(void) ap_proxy_table_unmerge(apr_pool_t *p, apr_table_t *t, char *key)
+{
+    apr_off_t offset = 0;
+    apr_off_t count = 0;
+    char *value = NULL;
+
+    /* get the value to unmerge */
+    const char *initial = apr_table_get(t, key);
+    if (!initial) {
+        return;
+    }
+    value = apr_pstrdup(p, initial);
+
+    /* remove the value from the headers */
+    apr_table_unset(t, key);
+
+    /* find each comma */
+    while (value[count]) {
+        if (value[count] == ',') {
+            value[count] = 0;
+            apr_table_add(t, key, value + offset);
+            offset = count + 1;
+        }
+        count++;
+    }
+    apr_table_add(t, key, value + offset);
+}
+
+PROXY_DECLARE(proxy_balancer *) ap_proxy_get_balancer(apr_pool_t *p,
+                                                      proxy_server_conf *conf,
+                                                      const char *url)
+{
+    proxy_balancer *balancer;
+    char *c, *uri = apr_pstrdup(p, url);
+    int i;
+    
+    c = strchr(uri, ':');   
+    if (c == NULL || c[1] != '/' || c[2] != '/' || c[3] == '\0')
+       return NULL;
+    /* remove path from uri */
+    if ((c = strchr(c + 3, '/')))
+        *c = '\0';
+    balancer = (proxy_balancer *)conf->balancers->elts;
+    for (i = 0; i < conf->balancers->nelts; i++) {
+        if (strcasecmp(balancer->name, uri) == 0)
+            return balancer;
+        balancer++;
+    }
+    return NULL;
+}
+
+PROXY_DECLARE(const char *) ap_proxy_add_balancer(proxy_balancer **balancer,
+                                                  apr_pool_t *p,
+                                                  proxy_server_conf *conf,
+                                                  const char *url)
+{
+    char *c, *q, *uri = apr_pstrdup(p, url);
+    apr_status_t rc = 0;
+
+    c = strchr(uri, ':');   
+    if (c == NULL || c[1] != '/' || c[2] != '/' || c[3] == '\0')
+       return "Bad syntax for a balancer name";
+    /* remove path from uri */
+    if ((q = strchr(c + 3, '/')))
+        *q = '\0';
+
+    ap_str_tolower(uri);
+    *balancer = apr_array_push(conf->balancers);
+    (*balancer)->name = uri;
+    (*balancer)->workers = apr_array_make(p, 5, sizeof(proxy_runtime_worker));
+    /* XXX Is this a right place to create mutex */
+#if APR_HAS_THREADS
+    if ((rc = apr_thread_mutex_create(&((*balancer)->mutex),
+                APR_THREAD_MUTEX_DEFAULT, p)) != APR_SUCCESS) {
+            /* XXX: Do we need to log something here */
+            return "can not create thread mutex";
+    }
+#endif
+
+    return NULL;
+}
+
+PROXY_DECLARE(proxy_worker *) ap_proxy_get_worker(apr_pool_t *p,
+                                                  proxy_server_conf *conf,
+                                                  const char *url)
+{
+    proxy_worker *worker;
+    char *c, *uri = apr_pstrdup(p, url);
+    int i;
+    
+    c = strchr(uri, ':');   
+    if (c == NULL || c[1] != '/' || c[2] != '/' || c[3] == '\0')
+       return NULL;
+    /* remove path from uri */
+    if ((c = strchr(c + 3, '/')))
+        *c = '\0';
+
+    worker = (proxy_worker *)conf->workers->elts;
+    for (i = 0; i < conf->workers->nelts; i++) {
+        if (strcasecmp(worker->name, uri) == 0) {
+            return worker;
+        }
+        worker++;
+    }
+    return NULL;
+}
+
+static apr_status_t conn_pool_cleanup(void *thepool)
+{
+    proxy_conn_pool *cp = (proxy_conn_pool *)thepool;
+    /* Close the socket */
+    cp->addr = NULL;
+    return APR_SUCCESS;
+}
+
+static void init_conn_pool(apr_pool_t *p, proxy_worker *worker)
+{
+    apr_pool_t *pool;
+    proxy_conn_pool *cp;
+    
+    /* Create a connection pool's subpool. 
+     * This pool is used for connection recycling.
+     * Once the worker is added it is never removed but
+     * it can be disabled.
+     */
+    apr_pool_create(&pool, p);
+    /* Alloc from the same pool as worker.
+     * proxy_conn_pool is permanently attached to the worker. 
+     */
+    cp = (proxy_conn_pool *)apr_pcalloc(p, sizeof(proxy_conn_pool));
+    cp->pool = pool;    
+    worker->cp = cp;
+    apr_pool_cleanup_register(p, (void *)cp,
+                              conn_pool_cleanup,
+                              apr_pool_cleanup_null);      
+
+}
+
+PROXY_DECLARE(const char *) ap_proxy_add_worker(proxy_worker **worker,
+                                                apr_pool_t *p,
+                                                proxy_server_conf *conf,
+                                                const char *url)
+{
+    char *c, *q, *uri = apr_pstrdup(p, url);
+    int port;
+    
+    c = strchr(uri, ':');   
+    if (c == NULL || c[1] != '/' || c[2] != '/' || c[3] == '\0')
+       return "Bad syntax for a remote proxy server";
+    /* remove path from uri */
+    if ((q = strchr(c + 3, '/')))
+        *q = '\0';
+
+    q = strchr(c + 3, ':');
+    if (q != NULL) {
+        if (sscanf(q + 1, "%u", &port) != 1 || port > 65535) {
+            return "Bad syntax for a remote proxy server (bad port number)";
+        }
+    }
+    else
+        port = -1;
+    ap_str_tolower(uri);
+    *worker = apr_array_push(conf->workers);
+    memset(*worker, 0, sizeof(proxy_worker));
+    (*worker)->name = apr_pstrdup(p, uri);
+    *c = '\0';
+    (*worker)->scheme = uri;
+    (*worker)->hostname = c + 3;
+
+    if (port == -1)
+        port = apr_uri_port_of_scheme((*worker)->scheme);
+    (*worker)->port = port;
+
+    init_conn_pool(p, *worker);
+
+    return NULL;
+}
+
+PROXY_DECLARE(void) 
+ap_proxy_add_worker_to_balancer(apr_pool_t *pool, proxy_balancer *balancer, proxy_worker *worker)
+{
+    int i;
+    double median, ffactor = 0.0;
+    proxy_runtime_worker *runtime, *workers;    
+#if PROXY_HAS_SCOREBOARD
+    lb_score *score;
+#else
+    void *score;
+#endif
+
+#if PROXY_HAS_SCOREBOARD
+    int mpm_daemons;
+
+    ap_mpm_query(AP_MPMQ_HARD_LIMIT_DAEMONS, &mpm_daemons);
+    /* Check if we are prefork or single child */
+    if (worker->hmax && mpm_daemons > 1) {
+        /* Check only if workers_limit is set */
+        if (lb_workers_limit && (lb_workers + 1) > lb_workers_limit) {
+            ap_log_perror(APLOG_MARK, APLOG_ERR, 0, pool,
+                          "proxy: Can not add worker (%s) to balancer (%s)."
+                          " Dynamic limit reached.",
+                          worker->name, balancer->name);
+            return;
+        }
+        score = ap_get_scoreboard_lb(getpid(), lb_workers);
+    }
+    else
+#endif
+    {
+        /* Use the plain memory */
+        score = apr_pcalloc(pool, sizeof(proxy_runtime_stat));
+    }
+    if (!score)
+        return;
+    runtime = apr_array_push(balancer->workers);
+    runtime->w = worker;
+    runtime->s = (proxy_runtime_stat *)score;
+    runtime->s->id = lb_workers;
+    /* TODO: deal with the dynamic overflow */
+    ++lb_workers;
+
+    /* Recalculate lbfactors */
+    workers = (proxy_runtime_worker *)balancer->workers->elts;
+
+    for (i = 0; i < balancer->workers->nelts; i++) {
+        /* Set to the original configuration */
+        workers[i].s->lbfactor = workers[i].w->lbfactor;
+        ffactor += workers[i].s->lbfactor;
+    }
+    if (ffactor < 100.0) {
+        int z = 0;
+        for (i = 0; i < balancer->workers->nelts; i++) {
+            if (workers[i].s->lbfactor == 0.0) 
+                ++z;
+        }
+        if (z) {
+            median = (100.0 - ffactor) / z;
+            for (i = 0; i < balancer->workers->nelts; i++) {
+                if (workers[i].s->lbfactor == 0.0) 
+                    workers[i].s->lbfactor = median;
+            }
+        }
+        else {
+            median = (100.0 - ffactor) / balancer->workers->nelts;
+            for (i = 0; i < balancer->workers->nelts; i++)
+                workers[i].s->lbfactor += median;
+        }
+    }
+    else if (ffactor > 100.0) {
+        median = (ffactor - 100.0) / balancer->workers->nelts;
+        for (i = 0; i < balancer->workers->nelts; i++) {
+            if (workers[i].s->lbfactor > median)
+                workers[i].s->lbfactor -= median;
+        }
+    } 
+    for (i = 0; i < balancer->workers->nelts; i++) {
+        /* Update the status entires */
+        workers[i].s->lbstatus = workers[i].s->lbfactor;
+    }
+}
+
+PROXY_DECLARE(int) ap_proxy_pre_request(proxy_worker **worker,
+                                        proxy_balancer **balancer,
+                                        request_rec *r,
+                                        proxy_server_conf *conf, char **url)
+{
+    int access_status;
+
+    access_status = proxy_run_pre_request(worker, balancer, r, conf, url);
+    if (access_status == DECLINED && *balancer == NULL) {
+        *worker = ap_proxy_get_worker(r->pool, conf, *url);
+        if (*worker) {
+            *balancer = NULL;
+            access_status = OK;
+        }
+        else
+            access_status = DECLINED;
+    }
+    else if (access_status == DECLINED && balancer != NULL) {
+        /* All the workers are busy */
+        access_status = HTTP_SERVICE_UNAVAILABLE;
+    }
+    return access_status;
+}
+
+PROXY_DECLARE(int) ap_proxy_post_request(proxy_worker *worker,
+                                         proxy_balancer *balancer,
+                                         request_rec *r,
+                                         proxy_server_conf *conf)
+{
+    int access_status;
+    if (balancer)
+        access_status = proxy_run_post_request(worker, balancer, r, conf);
+    else { 
+        
+
+        access_status = OK;
+    }
+
+    return access_status;
+}
+
+/* DEPRECATED */
+PROXY_DECLARE(int) ap_proxy_connect_to_backend(apr_socket_t **newsock,
+                                               const char *proxy_function,
+                                               apr_sockaddr_t *backend_addr,
+                                               const char *backend_name,
+                                               proxy_server_conf *conf,
+                                               server_rec *s,
+                                               apr_pool_t *p)
+{
+    apr_status_t rv;
+    int connected = 0;
+    int loglevel;
+    
+    while (backend_addr && !connected) {
+        if ((rv = apr_socket_create(newsock, backend_addr->family,
+                                    SOCK_STREAM, 0, p)) != APR_SUCCESS) {
+            loglevel = backend_addr->next ? APLOG_DEBUG : APLOG_ERR;
+            ap_log_error(APLOG_MARK, loglevel, rv, s,
+                         "proxy: %s: error creating fam %d socket for target %s",
+                         proxy_function,
+                         backend_addr->family,
+                         backend_name);
+            /* this could be an IPv6 address from the DNS but the
+             * local machine won't give us an IPv6 socket; hopefully the
+             * DNS returned an additional address to try
+             */
+            backend_addr = backend_addr->next;
+            continue;
+        }
+
+#if !defined(TPF) && !defined(BEOS)
+        if (conf->recv_buffer_size > 0 &&
+            (rv = apr_socket_opt_set(*newsock, APR_SO_RCVBUF,
+                                     conf->recv_buffer_size))) {
+            ap_log_error(APLOG_MARK, APLOG_ERR, rv, s,
+                         "apr_socket_opt_set(SO_RCVBUF): Failed to set "
+                         "ProxyReceiveBufferSize, using default");
+        }
+#endif
+
+        /* Set a timeout on the socket */
+        if (conf->timeout_set == 1) {
+            apr_socket_timeout_set(*newsock, conf->timeout);
+        }
+        else {
+             apr_socket_timeout_set(*newsock, s->timeout);
+        }
+
+        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
+                     "proxy: %s: fam %d socket created to connect to %s",
+                     proxy_function, backend_addr->family, backend_name);
+
+        /* make the connection out of the socket */
+        rv = apr_socket_connect(*newsock, backend_addr);
+
+        /* if an error occurred, loop round and try again */
+        if (rv != APR_SUCCESS) {
+            apr_socket_close(*newsock);
+            loglevel = backend_addr->next ? APLOG_DEBUG : APLOG_ERR;
+            ap_log_error(APLOG_MARK, loglevel, rv, s,
+                         "proxy: %s: attempt to connect to %pI (%s) failed",
+                         proxy_function,
+                         backend_addr,
+                         backend_name);
+            backend_addr = backend_addr->next;
+            continue;
+        }
+        connected = 1;
+    }
+    return connected ? 0 : 1;
+}
+
+static apr_status_t proxy_conn_cleanup(void *theconn)
+{
+    proxy_conn_rec *conn = (proxy_conn_rec *)theconn;
+    /* Close the socket */
+    if (conn->sock)
+        apr_socket_close(conn->sock);
+    conn->sock = NULL;
+    conn->pool = NULL;
+    return APR_SUCCESS;
+}
+
+static apr_status_t connection_cleanup(void *theconn)
+{
+    proxy_conn_rec *conn = (proxy_conn_rec *)theconn;
+    proxy_worker *worker = conn->worker;
+    
+    /* deterimine if the connection need to be closed */
+    if (conn->close_on_recycle) {
+        if (conn->sock)
+            apr_socket_close(conn->sock);
+        conn->sock = NULL;
+    }
+#if APR_HAS_THREADS
+    if (worker->hmax && worker->cp->res) {
+        apr_reslist_release(worker->cp->res, (void *)conn);
+    }
+    else
+#endif
+    {
+        worker->cp->conn = conn;
+    }
+
+    /* Allways return the SUCCESS */
+    return APR_SUCCESS;
+}
+
+/* reslist constructor */
+static apr_status_t connection_constructor(void **resource, void *params,
+                                           apr_pool_t *pool)
+{
+    apr_pool_t *ctx;
+    proxy_conn_rec *conn;
+    server_rec *s = (server_rec *)params;
+    
+    /* Create the subpool for each connection
+     * This keeps the memory consumption constant
+     * when disconnecting from backend.
+     */
+    apr_pool_create(&ctx, pool);
+    conn = apr_pcalloc(ctx, sizeof(proxy_conn_rec));
+
+    conn->pool = ctx;
+    *resource = conn;
+    /* register the pool cleanup */
+    apr_pool_cleanup_register(ctx, (void *)conn,
+                              proxy_conn_cleanup,
+                              apr_pool_cleanup_null);      
+
+    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
+                 "proxy: socket is constructed");
+
+    return APR_SUCCESS;
+}
+
+/* reslist destructor */
+static apr_status_t connection_destructor(void *resource, void *params,
+                                          apr_pool_t *pool)
+{
+    proxy_conn_rec *conn = (proxy_conn_rec *)resource;
+    server_rec *s = (server_rec *)params;
+    
+#if 0
+    if (conn->sock)
+        apr_socket_close(conn->sock);
+    conn->sock = NULL;
+    apr_pool_cleanup_kill(conn->pool, conn, proxy_conn_cleanup);
+#endif
+    if (conn->pool)
+        apr_pool_destroy(conn->pool);
+    conn->pool = NULL;
+#if 0
+    if (s != NULL)
+        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
+                     "proxy: socket is destructed");
+#endif
+    return APR_SUCCESS;
+}
+
+/* Close the connection 
+ * The proxy_conn_rec from now on can not be used
+ */
+PROXY_DECLARE(apr_status_t) ap_proxy_close_connection(proxy_conn_rec *conn)
+{
+
+    if (conn->worker && conn->worker->cp)
+        conn->worker->cp->conn = NULL;
+    return connection_destructor(conn, NULL, NULL);
+}
+
+static apr_status_t init_conn_worker(proxy_worker *worker, server_rec *s)
+{
+    apr_status_t rv;
+
+#if APR_HAS_THREADS
+    int mpm_threads;
+
+    ap_mpm_query(AP_MPMQ_MAX_THREADS, &mpm_threads);
+    if (mpm_threads > 1) {
+        /* Set hard max to no more then mpm_threads */
+        if (worker->hmax == 0 || worker->hmax > mpm_threads)
+            worker->hmax = mpm_threads;
+        if (worker->smax == 0 || worker->smax > worker->hmax)
+            worker->smax = worker->hmax;
+        /* Set min to be lower then smax */
+        if (worker->min > worker->smax)
+            worker->min = worker->smax; 
+        worker->cp->nfree = worker->hmax;
+    }
+    else {
+        /* This will supress the apr_reslist creation */
+        worker->min = worker->smax = worker->hmax = 0;
+    }
+    if (worker->hmax) {
+        rv = apr_reslist_create(&(worker->cp->res),
+                                worker->min, worker->smax,
+                                worker->hmax, worker->ttl,
+                                connection_constructor, connection_destructor,
+                                s, worker->cp->pool);
+        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
+                     "proxy: initialized worker for (%s) min=%d max=%d smax=%d",
+                      worker->hostname, worker->min, worker->hmax, worker->smax);
+
+#if (APR_MAJOR_VERSION > 0)
+        /* Set the acquire timeout */
+        if (rv == APR_SUCCESS && worker->acquire_set)
+            apr_reslist_timeout_set(worker->cp->res, worker->acquire);
+#endif
+    }
+    else
+#endif
+    {
+        
+        connection_constructor((void **)&(worker->cp->conn), s, worker->cp->pool);
+        rv = APR_SUCCESS;
+        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
+                     "proxy: initialized single connection worker for (%s)",
+                      worker->hostname);
+    }
+
+    return rv;
+}
+
+PROXY_DECLARE(int) ap_proxy_retry_worker(const char *proxy_function,
+                                         proxy_worker *worker,
+                                         server_rec *s)
+{
+    if (worker->status & PROXY_WORKER_IN_ERROR) {
+        apr_interval_time_t diff;
+        apr_time_t now = apr_time_now();
+        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
+                    "proxy: %s: retrying the worker for (%s)",
+                     proxy_function, worker->hostname);
+        if (worker->retry)
+            diff = worker->retry;
+        else
+            diff = apr_time_from_sec((60 + 60 * worker->retries++));
+        if (now > worker->error_time + diff) {
+            worker->status &= ~PROXY_WORKER_IN_ERROR;
+            ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
+                         "proxy: %s: worker for (%s) has been marked for retry",
+                         proxy_function, worker->hostname);
+            return OK;
+        }
+        else
+            return DECLINED;
+    }
+    else
+        return OK;
+}
+
+PROXY_DECLARE(int) ap_proxy_acquire_connection(const char *proxy_function,
+                                               proxy_conn_rec **conn,
+                                               proxy_worker *worker,
+                                               server_rec *s)
+{
+    apr_status_t rv;
+
+    if (!(worker->status & PROXY_WORKER_INITIALIZED)) {
+        if ((rv = init_conn_worker(worker, s)) != APR_SUCCESS) {
+            ap_log_error(APLOG_MARK, APLOG_ERR, rv, s,
+                         "proxy: %s: failed to initialize worker for (%s)",
+                         proxy_function, worker->hostname);
+            return HTTP_INTERNAL_SERVER_ERROR;
+        }
+        worker->status = PROXY_WORKER_INITIALIZED;
+    }
+
+    if (!PROXY_WORKER_IS_USABLE(worker)) {
+        /* Retry the worker */
+        ap_proxy_retry_worker(proxy_function, worker, s);
+    
+        if (!PROXY_WORKER_IS_USABLE(worker)) {
+            ap_log_error(APLOG_MARK, APLOG_ERR, rv, s,
+                         "proxy: %s: disabled connection for (%s)",
+                         proxy_function, worker->hostname);
+            return HTTP_SERVICE_UNAVAILABLE;
+        }
+    }
+#if APR_HAS_THREADS
+    if (worker->hmax) {
+        rv = apr_reslist_acquire(worker->cp->res, (void **)conn);
+    }
+    else
+#endif
+    {
+        /* create the new connection if the previous was destroyed */
+        if (!worker->cp->conn)
+            connection_constructor((void **)conn, s, worker->cp->pool);
+        else {
+            *conn = worker->cp->conn;
+            worker->cp->conn = NULL;
+        }
+        rv = APR_SUCCESS;
+    }
+
+    if (rv != APR_SUCCESS) {
+        ap_log_error(APLOG_MARK, APLOG_ERR, rv, s,
+                     "proxy: %s: failed to acquire connection for (%s)",
+                     proxy_function, worker->hostname);
+        return HTTP_SERVICE_UNAVAILABLE;
+    }
+    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
+                 "proxy: %s: has acquired connection for (%s)",
+                 proxy_function, worker->hostname);
+
+    (*conn)->worker = worker;
+
+    return OK;
+}
+
+PROXY_DECLARE(int) ap_proxy_release_connection(const char *proxy_function,
+                                               proxy_conn_rec *conn,
+                                               server_rec *s)
+{
+    apr_status_t rv = APR_SUCCESS;
+
+    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
+                 "proxy: %s: has relesed connection for (%s)",
+                 proxy_function, conn->worker->hostname);
+    /* If there is a connection kill it's cleanup */
+    if (conn->connection)
+        apr_pool_cleanup_kill(conn->connection->pool, conn, connection_cleanup);
+    connection_cleanup(conn);
+    conn->connection = NULL;
+
+    return OK;
+}
+
+PROXY_DECLARE(int)
+ap_proxy_determine_connection(apr_pool_t *p, request_rec *r,
+                              proxy_server_conf *conf,
+                              proxy_worker *worker,
+                              proxy_conn_rec *conn,
+                              apr_pool_t *ppool,
+                              apr_uri_t *uri,
+                              char **url,
+                              const char *proxyname,
+                              apr_port_t proxyport,
+                              char *server_portstr,
+                              int server_portstr_size)
+{
+    int server_port;
+    apr_status_t err = APR_SUCCESS;
+    /*
+     * Break up the URL to determine the host to connect to
+     */
+
+    /* we break the URL into host, port, uri */
+    if (APR_SUCCESS != apr_uri_parse(p, *url, uri)) {
+        return ap_proxyerror(r, HTTP_BAD_REQUEST,
+                             apr_pstrcat(p,"URI cannot be parsed: ", *url,
+                                         NULL));
+    }
+    if (!uri->port) {
+        uri->port = apr_uri_port_of_scheme(uri->scheme);
+    }
+
+    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+                 "proxy: connecting %s to %s:%d", *url, uri->hostname,
+                 uri->port);
+
+    /* allocate these out of the specified connection pool 
+     * The scheme handler decides if this is permanent or
+     * short living pool.
+     */
+    /* are we connecting directly, or via a proxy? */
+    if (proxyname) {
+        conn->hostname = apr_pstrdup(ppool, proxyname);
+        conn->port = proxyport;
+    } else {
+        conn->hostname = apr_pstrdup(ppool, uri->hostname);
+        conn->port = uri->port;
+        *url = apr_pstrcat(p, uri->path, uri->query ? "?" : "",
+                           uri->query ? uri->query : "",
+                           uri->fragment ? "#" : "",
+                           uri->fragment ? uri->fragment : "", NULL);
+    }
+    /* Worker can have the single constant backend adress.
+     * The single DNS lookup is used once per worker.
+     * If dynamic change is needed then set the addr to NULL
+     * inside dynamic config to force the lookup.
+     */
+    if (!worker->cp->addr)
+        err = apr_sockaddr_info_get(&(worker->cp->addr),
+                                    conn->hostname, APR_UNSPEC,
+                                    conn->port, 0,
+                                    worker->cp->pool);
+
+    if (err != APR_SUCCESS) {
+        return ap_proxyerror(r, HTTP_BAD_GATEWAY,
+                             apr_pstrcat(p, "DNS lookup failure for: ",
+                                         conn->hostname, NULL));
+    }
+
+    /* Get the server port for the Via headers */
+    {
+        server_port = ap_get_server_port(r);
+        if (ap_is_default_port(server_port, r)) {
+            strcpy(server_portstr,"");
+        } else {
+            apr_snprintf(server_portstr, server_portstr_size, ":%d",
+                         server_port);
+        }
+    }
+
+    /* check if ProxyBlock directive on this host */
+    if (OK != ap_proxy_checkproxyblock(r, conf, worker->cp->addr)) {
+        return ap_proxyerror(r, HTTP_FORBIDDEN,
+                             "Connect to remote machine blocked");
+    }
+    return OK;
+}
+
+static int is_socket_connected(apr_socket_t *sock)
+
+{
+    apr_size_t buffer_len = 1;
+    char test_buffer[1]; 
+    apr_status_t socket_status;
+    apr_interval_time_t current_timeout;
+    
+    /* save timeout */
+    apr_socket_timeout_get(sock, &current_timeout);
+    /* set no timeout */
+    apr_socket_timeout_set(sock, 0);
+    socket_status = apr_socket_recv(sock, test_buffer, &buffer_len);
+    /* put back old timeout */
+    apr_socket_timeout_set(sock, current_timeout);
+    if (APR_STATUS_IS_EOF(socket_status))
+        return 0;
+    else
+        return 1;
+}
+
+PROXY_DECLARE(int) ap_proxy_connect_backend(const char *proxy_function,
+                                            proxy_conn_rec *conn,
+                                            proxy_worker *worker,
+                                            server_rec *s)
+{
+    apr_status_t rv;
+    int connected = 0;
+    int loglevel;
+    apr_sockaddr_t *backend_addr = worker->cp->addr;
+    apr_socket_t *newsock;
+    
+    if (conn->sock) {
+        /* This increases the connection pool size
+         * but the number of dropped connections is
+         * relatively small compared to connection lifetime
+         */
+        if (!(connected = is_socket_connected(conn->sock))) {        
+            apr_socket_close(conn->sock);
+            conn->sock = NULL;
+        }
+    }
+    while (backend_addr && !connected) {
+        if ((rv = apr_socket_create(&newsock, backend_addr->family,
+                                SOCK_STREAM, APR_PROTO_TCP,
+                                conn->pool)) != APR_SUCCESS) {
+            loglevel = backend_addr->next ? APLOG_DEBUG : APLOG_ERR;
+            ap_log_error(APLOG_MARK, loglevel, rv, s,
+                         "proxy: %s: error creating fam %d socket for target %s",
+                         proxy_function,
+                         backend_addr->family,
+                         worker->hostname);
+            /* this could be an IPv6 address from the DNS but the
+             * local machine won't give us an IPv6 socket; hopefully the
+             * DNS returned an additional address to try
+             */
+            backend_addr = backend_addr->next;
+            continue;
+        }
+
+#if !defined(TPF) && !defined(BEOS)
+        if (worker->recv_buffer_size > 0 &&
+            (rv = apr_socket_opt_set(newsock, APR_SO_RCVBUF,
+                                     worker->recv_buffer_size))) {
+            ap_log_error(APLOG_MARK, APLOG_ERR, rv, s,
+                         "apr_socket_opt_set(SO_RCVBUF): Failed to set "
+                         "ProxyReceiveBufferSize, using default");
+        }
+#endif
+
+        /* Set a timeout on the socket */
+        if (worker->timeout_set == 1) {
+            apr_socket_timeout_set(newsock, worker->timeout);
+        }
+        else {
+             apr_socket_timeout_set(newsock, s->timeout);
+        }
+        /* Set a keepalive option */
+        if (worker->keepalive) {
+            if ((rv = apr_socket_opt_set(newsock, 
+                            APR_SO_KEEPALIVE, 1)) != APR_SUCCESS) {
+                ap_log_error(APLOG_MARK, APLOG_ERR, rv, s,
+                             "apr_socket_opt_set(SO_KEEPALIVE): Failed to set"
+                             " Keepalive");
+            }
+        }
+        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
+                     "proxy: %s: fam %d socket created to connect to %s",
+                     proxy_function, backend_addr->family, worker->hostname);
+
+        /* make the connection out of the socket */
+        rv = apr_socket_connect(newsock, backend_addr);
+
+        /* if an error occurred, loop round and try again */
+        if (rv != APR_SUCCESS) {
+            apr_socket_close(newsock);
+            loglevel = backend_addr->next ? APLOG_DEBUG : APLOG_ERR;
+            ap_log_error(APLOG_MARK, loglevel, rv, s,
+                         "proxy: %s: attempt to connect to %pI (%s) failed",
+                         proxy_function,
+                         backend_addr,
+                         worker->hostname);
+            backend_addr = backend_addr->next;
+            continue;
+        }
+        
+        conn->sock   = newsock;
+        connected    = 1;
+    }
+    /* Put the entire worker to error state
+     * Altrough some connections may be alive
+     * no further connections to the worker could be made
+     */
+    if (!connected && PROXY_WORKER_IS_USABLE(worker)) {
+        worker->status |= PROXY_WORKER_IN_ERROR;
+        worker->error_time = apr_time_now();
+        ap_log_error(APLOG_MARK, APLOG_ERR, 0, s,
+            "ap_proxy_connect_backend disabling worker for (%s)",
+            worker->hostname);
+    }
+    else {
+        worker->error_time = 0;
+        worker->retries = 0;
+    }
+    return connected ? OK : DECLINED;
+}
+
+PROXY_DECLARE(int) ap_proxy_connection_create(const char *proxy_function,
+                                              proxy_conn_rec *conn,
+                                              conn_rec *c,
+                                              server_rec *s)
+{
+    proxy_worker *worker = conn->worker;
+    apr_sockaddr_t *backend_addr = worker->cp->addr;
+
+    /* The socket is now open, create a new backend server connection 
+    * 
+    */
+    conn->connection = ap_run_create_connection(c->pool, s, conn->sock,
+                                                c->id, c->sbh,
+                                                c->bucket_alloc);
+
+    if (!conn->connection) {
+        /* the peer reset the connection already; ap_run_create_connection() 
+        * closed the socket
+        */
+        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0,
+                     s, "proxy: %s: an error occurred creating a "
+                     "new connection to %pI (%s)", proxy_function,
+                     backend_addr, conn->hostname);
+        /* XXX: Will be closed when proxy_conn is closed */
+        apr_socket_close(conn->sock);
+        conn->sock = NULL;
+        return HTTP_INTERNAL_SERVER_ERROR;
+    }
+    /* register the connection cleanup to client connection
+     * so that the connection can be closed or reused
+     */
+    apr_pool_cleanup_register(c->pool, (void *)conn,
+                              connection_cleanup,
+                              apr_pool_cleanup_null);      
+
+    /* For ssl connection to backend */
+    if (conn->is_ssl) {
+        if (!ap_proxy_ssl_enable(conn->connection)) {
+            ap_log_error(APLOG_MARK, APLOG_ERR, 0,
+                         s, "proxy: %s: failed to enable ssl support "
+                         "for %pI (%s)", proxy_function, 
+                         backend_addr, conn->hostname);
+            return HTTP_INTERNAL_SERVER_ERROR;
+        }
+    }
+    else {
+        /* TODO: See if this will break FTP */
+        ap_proxy_ssl_disable(conn->connection);
+    }
+
+    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
+                 "proxy: %s: connection complete to %pI (%s)",
+                 proxy_function, backend_addr, conn->hostname);
+
+    /* set up the connection filters */
+    ap_run_pre_connection(conn->connection, conn->sock);
+
+    return OK;
+}
+
+PROXY_DECLARE(int) ap_proxy_lb_workers(void)
+{
+    /* Set the dynamic #workers limit */
+    lb_workers_limit = lb_workers + PROXY_DYNAMIC_BALANCER_LIMIT;
+    return lb_workers_limit;
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/build.properties.default
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/build.properties.default	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/build.properties.default	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,245 @@
+# -----------------------------------------------------------------------------
+# build.properties.sample
+#
+# This is an example "build.properties" file, used to customize building Tomcat
+# for your local environment.  It defines the location of all external
+# 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 392352 2006-04-07 18:10:44Z markt $
+# -----------------------------------------------------------------------------
+
+
+# ----- Compile Control Flags -----
+compile.debug=on
+compile.deprecation=off
+compile.optimize=on
+
+
+# ----- Build Control Flags
+
+#Version number
+version=4.1
+
+#Proxy to download subproject
+#proxy.host=proxy.domain
+#proxy.port=8080
+#proxy.use=on
+
+#CVS root for the jakarta subprojects that do not have released yet.
+cvsroot=":pserver:anoncvs at cvs.apache.org:/home/cvspublic"
+
+
+# ----- Default Base Path for Dependent Packages -----
+base.path=/usr/share/java
+
+
+# --------------------------------------------------
+#                REQUIRED LIBRARIES
+# --------------------------------------------------
+
+
+# ----- Commons Beanutils, version 1.1 or later -----
+commons-beanutils.home=${base.path}/commons-beanutils-1.6.1
+commons-beanutils.lib=${commons-beanutils.home}
+commons-beanutils.jar=${commons-beanutils.lib}/commons-beanutils.jar
+commons-beanutils.loc=http://www.apache.org/dist/jakarta/commons/beanutils/binaries/commons-beanutils-1.6.1.tar.gz
+
+
+# ----- Commons Collections, version 1.0 or later -----
+commons-collections.home=${base.path}/commons-collections-2.1
+commons-collections.lib=${commons-collections.home}
+commons-collections.jar=${commons-collections.lib}/commons-collections.jar
+commons-collections.loc=http://www.apache.org/dist/jakarta/commons/collections/binaries/collections-2.1.tar.gz
+
+
+# ----- Commons Digester, version 1.1.1 or later -----
+commons-digester.home=${base.path}/commons-digester-1.4.1
+commons-digester.lib=${commons-digester.home}
+commons-digester.jar=${commons-digester.lib}/commons-digester.jar
+commons-digester.loc=http://www.apache.org/dist/jakarta/commons/digester/binaries/commons-digester-1.4.1.tar.gz
+
+
+# ----- Commons FileUpload, nightly build -----
+commons-fileupload.home=${base.path}/commons-fileupload-1.0-beta-1
+commons-fileupload.lib=${commons-fileupload.home}
+commons-fileupload.jar=${commons-fileupload.lib}/commons-fileupload-1.0-beta-1.jar
+commons-fileupload.loc=http://www.apache.org/dist/jakarta/commons/fileupload/commons-fileupload-1.0-beta-1.tar.gz 
+
+
+# ----- Commons Logging, version 1.0.1 or later -----
+commons-logging.home=${base.path}/commons-logging-1.0.4
+commons-logging.lib=${commons-logging.home}
+commons-logging-api.jar=${commons-logging.lib}/commons-logging-api.jar
+commons-logging.jar=${commons-logging.lib}/commons-logging.jar
+commons-logging.loc=http://www.apache.org/dist/jakarta/commons/logging/binaries/commons-logging-1.0.4.tar.gz
+
+
+# ----- Java Naming and Directory Interface (JNDI), version 1.2 or later -----
+# Note: Optional with JDK 1.3+
+jndi.home=${base.path}/jndi-1.2.1
+jndi.lib=${jndi.home}/lib
+jndi.jar=${jndi.lib}/jndi.jar
+ldap.jar=${jndi.lib}/ldap.jar
+jaas.jar=${jndi.lib}/jaas.jar
+
+
+# ----- Jakarta Regular Expressions Library, version 1.3 -----
+regexp.home=${base.path}/jakarta-regexp-1.4
+regexp.lib=${regexp.home}
+regexp.jar=${regexp.lib}/jakarta-regexp-1.4.jar
+regexp.loc=http://www.apache.org/dist/jakarta/regexp/binaries/jakarta-regexp-1.4.tar.gz
+
+
+# ----- Jakarta Servlet API Classes (Servlet 2.3 / JSP 1.2) -----
+servlet.home=${base.path}/jakarta-servletapi-4
+servlet.lib=${servlet.home}/dist/lib
+servlet.jar=${servlet.lib}/servlet.jar
+servlet.loc=jakarta-servletapi-4
+
+
+# ----- Xerces XML Parser, version 1.4.4 to 2.0.0 Beta 4 -----
+# Note: Optional with JDK 1.4+
+#xerces.home=${base.path}/xerces-1_4_4
+#xerces.lib=${xerces.home}
+#xerces.jar=${xerces.lib}/xerces.jar
+
+
+# ----- Xerces XML Parser, version 2.0.0 or later -----
+# Note: Optional with JDK 1.4+, or if Xerces 1.x is present
+xerces.home=${base.path}/xerces-2_3_0
+xerces.lib=${xerces.home}
+xerces.loc=http://xml.apache.org/dist/xerces-j/old_xerces2/Xerces-J-bin.2.3.0.tar.gz
+xercesImpl.jar=${xerces.lib}/xercesImpl.jar
+xml-apis.jar=${xerces.lib}/xml-apis.jar
+
+
+# --------------------------------------------------
+#                OPTIONAL LIBRARIES
+# --------------------------------------------------
+
+# ----- Mirror ------
+mirror=http://www.apache.org/dist
+
+# ----- Java Activation Framework (JAF), version 1.0.1 or later -----
+activation.home=${base.path}/jaf-1.0.1
+activation.lib=${activation.home}
+activation.jar=${activation.lib}/activation.jar
+
+
+# ----- Commons Daemon, version 20020219 or later -----
+commons-daemon.home=${base.path}/commons-daemon
+commons-daemon.lib=${commons-daemon.home}/dist
+commons-daemon.jar=${commons-daemon.lib}/commons-daemon.jar
+commons-daemon.loc=jakarta-commons-sandbox/daemon
+
+
+# ----- Commons DBCP, version 1.0 or later -----
+commons-dbcp.version=1.1
+commons-dbcp.home=${base.path}/commons-dbcp-${commons-dbcp.version}
+commons-dbcp.lib=${commons-dbcp.home}/commons-dbcp-1.0
+commons-dbcp.jar=${commons-dbcp.lib}/commons-dbcp.jar
+commons-dbcp.loc=${mirror}/jakarta/commons/dbcp/binaries/commons-dbcp-${commons-dbcp.version}.tar.gz
+
+
+# ----- Commons Modeler, version 1.0 or later -----
+commons-modeler.version=1.1
+commons-modeler.home=${base.path}/commons-modeler-${commons-modeler.version}
+commons-modeler.lib=${commons-modeler.home}
+commons-modeler.jar=${commons-modeler.lib}/commons-modeler.jar
+commons-modeler.loc=${mirror}/jakarta/commons/modeler/binaries/modeler-${commons-modeler.version}.tar.gz
+
+
+# ----- Commons Pool, version 1.0 or later -----
+commons-pool.version=1.1
+commons-pool.home=${base.path}/commons-pool-${commons-pool.version}
+commons-pool.lib=${commons-pool.home}
+commons-pool.jar=${commons-pool.lib}/commons-pool.jar
+commons-pool.loc=${mirror}/jakarta/commons/pool/binaries/commons-pool-${commons-pool.version}.tar.gz
+
+
+# ----- Java Database Connectivity (JDBC) Optional Package, version 2.0 -----    
+jdbc20ext.home=${base.path}/jdbc2_0-stdext      
+jdbc20ext.lib=${jdbc20ext.home}         
+jdbc20ext.jar=${jdbc20ext.lib}/jdbc2_0-stdext.jar
+
+# ----- Java Management Extensions (JMX), JMX RI 1.0.1 or later or MX4J 1.0 or later -----
+jmx.version=3.0.1
+jmx.home=${base.path}/mx4j-${jmx.version}
+jmx.lib=${jmx.home}/lib
+jmx.jar=${jmx.lib}/mx4j-jmx.jar
+jmx.loc=http://download.sourceforge.net/mx4j/mx4j-${jmx.version}.tar.gz
+
+
+# ----- Java Secure Sockets Extension (JSSE), version 1.0.2 or later -----
+jsse.home=${base.path}/jsse-1.0.3
+jsse.lib=${jsse.home}/lib
+jcert.jar=${jsse.lib}/jcert.jar
+jnet.jar=${jsse.lib}/jnet.jar
+jsse.jar=${jsse.lib}/jsse.jar
+
+
+# ----- Java Transaction API (JTA), version 1.0.1 or later -----
+jta.home=${base.path}/jta-1_0_1a
+jta.lib=${jta.home}
+jta.jar=${jta.lib}/jta.jar
+
+
+# ----- JUnit Unit Test Suite, version 3.7 or later -----
+junit.home=${base.path}/junit3.7
+junit.lib=${junit.home}
+junit.jar=${junit.lib}/junit.jar
+junit.loc=http://download.sourceforge.net/junit/junit3.7.zip
+
+
+# ----- Java Mail, version 1.2 or later -----
+mail.home=${base.path}/javamail-1.2
+mail.lib=${mail.home}
+mail.jar=${mail.lib}/mail.jar
+
+
+# ----- NSIS, version 1.9x -----
+nsis.home=${base.path}/nsis
+nsis.loc=http://www.nullsoft.com/free/nsis/nsis198.exe
+
+
+# ----- PureTLS Extension, version 0.9 or later -----
+puretls.home=${base.path}/puretls-0.9b2
+puretls.lib=${puretls.home}/build
+puretls.jar=${puretls.lib}/puretls.jar
+
+
+# ----- Struts, version 1.0.1 or later -----
+struts.version=1.1
+struts.home=${base.path}/jakarta-struts-${struts.version}
+struts.lib=${struts.home}/lib
+struts.jar=${struts.lib}/struts.jar
+struts.loc=${mirror}/jakarta/struts/binaries/jakarta-struts-${struts.version}.tar.gz
+
+
+# ----- Tyrex Data Source, version 1.0 -----
+# Now tyrex is http://tyrex.sourceforge.net/
+tyrex.home=${base.path}/tyrex-1.0
+tyrex.lib=${tyrex.home}
+tyrex.jar=${tyrex.lib}/tyrex-1.0.jar
+tyrex.loc=http://belnet.dl.sourceforge.net/sourceforge/tyrex/tyrex-1.0.tgz
+
+# ----- Tomcat5.x.x -----
+tomcat5.version=5.5.15
+tomcat5.home=${base.path}/apache-tomcat-${tomcat5.version}
+tomcat5.jar=${tomcat5.home}/server/lib/catalina.jar
+servlet-api.jar=${tomcat5.home}/common/lib/servlet-api.jar
+tomcat5.loc=http://www.apache.org/dist/tomcat/tomcat-5/v${tomcat5.version}/bin/apache-tomcat-${tomcat5.version}.tar.gz 
+
+# ----- Tomcat4.1.x -----
+tomcat41.version=4.1.31
+tomcat41.home=${base.path}/jakarta-tomcat-${tomcat41.version}
+tomcat41.jar=${tomcat41.home}/server/lib/catalina.jar
+servlet-api.jar=${tomcat41.home}/common/lib/servlet.jar
+tomcat41.loc=http://www.apache.org/dist/tomcat/tomcat-4/v${tomcat41.version}/bin/jakarta-tomcat-${tomcat41.version}.tar.gz 
+
+# ----- Tomcat33 -----
+tomcat33.version=3.3.2
+tomcat33.home=${base.path}/jakarta-tomcat-${tomcat33.version}
+tomcat33.jar=${tomcat33.home}/lib/common/tomcat_core.jar
+tomcat33.loc=${mirror}/tomcat/tomcat-3/v${tomcat33.version}/bin/jakarta-tomcat-${tomcat33.version}.tar.gz

Added: branches/tomcat5.5/upstream/5.5.20/connectors/build.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/build.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/build.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,329 @@
+<project name="Jtc" default="dist" basedir=".">
+
+<!-- ========== Initialize Properties ===================================== -->
+
+
+  <property file="${user.home}/build.properties"/>   <!-- User local        -->
+  <property file="build.properties"/>                <!-- Component local   -->
+  <property file="build.properties.default"/>
+
+  <property name="dist.dir" location="dist" />
+  <property name="lib.dir" location="${dist.dir}/lib" />
+  <property name="build.dir" location="build" />
+
+  <target name="dist" 
+          description="Compile jtc distribution" depends="build,javadoc">
+    <copy todir="${dist.dir}" >
+      <fileset dir="." >
+        <include name="LICENSE" />
+        <include name="build.xml" />
+        <include name="build.properties.default" />
+        <include name="README.txt" />
+        <include name="RELEASE-NOTES.txt" />
+        <include name="doc/**" />
+      </fileset>
+    </copy>
+
+    <jar file="${dist.dir}/tomcat-connectors-src.jar">
+       <fileset dir="." includes="**" >        
+          <exclude name="webapp/**"/>
+          <exclude name="naming/**"/>
+          <exclude name="build/**"/>
+          <exclude name="dist/**"/>
+          <exclude name="release/**"/>
+          <exclude name="scandoc/**"/>
+       </fileset>
+     </jar>
+  </target>
+
+
+  <target name="build" 
+          description="Compile jtc">
+    <mkdir dir="${build.dir}/classes" />
+    <mkdir dir="${lib.dir}" />
+    
+    <ant dir="util">
+      <property name="puretls.jar" value="${puretls.jar}" />
+      <property name="jsse.lib" value="${jsse.lib}" />
+      <property name="tomcat-util.build" value="${build.dir}" />
+      <property name="tomcat-util.lib" value="${lib.dir}" />
+    </ant>
+
+    <ant dir="coyote" target="compile">
+      <property name="catalina.home" value="${tomcat41.home}"/>
+      <property name="tomcat33.home" value="${tomcat33.home}"/>
+      <property name="build.home" value="${build.dir}"/>
+      <property name="tomcat5.detect" value="true"/> <!-- This is a hack to disable ajp -->
+      <property name="servlet.jar" value="${tomcat41.home}/common/lib/servlet.jar" />
+
+      <property name="tomcat-coyote.jar" value="${lib.dir}/tomcat-coyote.jar" />
+      <property name="tomcat33-coyote.jar" value="${lib.dir}/tomcat33-coyote.jar" />
+      <property name="tomcat4-coyote.jar" value="${lib.dir}/tomcat4-coyote.jar" />
+      <property name="tomcat-util.jar"
+                value="${lib.dir}/tomcat-util.jar"/>
+      <property name="servlet.jar"   value="${servlet-api.jar}"/>
+    </ant>
+
+    <ant dir="http11">
+      <property name="build.home" value="${build.dir}"/>
+      <property name="tomcat-http11.jar" value="${lib.dir}/tomcat-http11.jar"/>
+      <property name="tomcat-coyote.jar" value="${lib.dir}/tomcat-coyote.jar" />
+      <property name="commons-logging.jar" value="${commons-logging.jar}"/>
+    </ant>
+
+    <ant dir="jk" target="build-jk">
+      <property name="commons-logging.jar" value="${commons-logging.jar}"/>
+      <property name="jmx.jar" value="${jmx.jar}"/>
+      <property name="jmx.detect" value="true"/>
+      <property name="tomcat-coyote.jar" value="${lib.dir}/tomcat-coyote.jar" />
+      <property name="jk.build" value="${build.dir}"/>
+
+      <property name="tomcat-jk2.jar" value="${lib.dir}/tomcat-jk2.jar" />
+      <property name="tomcat-jkconfig.jar" value="${lib.dir}/jkconfig.jar" />
+
+      <!-- don't include in dist -->
+      <property name="tomcat5.detect" value="true"/>
+      <property name="tomcat-jk.jar" value="${build.dir}/lib/tomcat-jk.jar" /> 
+      <property name="tomcat-jkshm.jar" value="${build.dir}/lib/jkshm.jar" />
+      <property name="tomcat-jni.jar" value="${build.dir}/lib/tomcat-jni.jar" />
+    </ant>
+
+    <jar file="${dist.dir}/lib/tomcat33-resources.jar" >
+      <fileset dir="${build.dir}/classes" >
+        <include name="**/*.properties" />
+      </fileset>
+    </jar>
+
+    <jar file="${dist.dir}/tomcat-connectors.jar" index="true" >
+      <fileset dir="${build.dir}/classes" >
+        <include name="**" />
+        <exclude name="org/apache/ajp/**" />
+      </fileset>
+    </jar>
+
+  </target>
+
+  <target name="javadoc" 
+          description="javadocs">
+    <mkdir dir="${dist.dir}/doc/api"/>
+    <path id="compile.classpath">
+        <pathelement location="${build.dir}/classes" />
+        <pathelement location="${jmx.jar}" />
+        <pathelement location="${jsse.jar}" />
+        <pathelement location="${java.home}/lib/jsse.jar" />
+        <pathelement location="${jnet.jar}" />
+        <pathelement location="${jcert.jar}" />
+        <pathelement location="${puretls.jar}" />
+        <pathelement location="${commons-logging.jar}" />
+        <pathelement location="${commons-modeler.jar}" />
+    </path>
+    <javadoc 
+      destdir="${dist.dir}/doc/api"
+      author="true"
+      version="true"
+      windowtitle="Tomcat Connector Documentation"
+      doctitle="Tomcat Connector"
+      bottom="Copyright &#169; 2003 Apache Software Foundation.  All Rights Reserved.">
+
+      <fileset dir="util/java" includes="**/*.java"/>
+      <fileset dir="coyote/src/java" includes="**/*.java">
+      </fileset>
+      <fileset dir="http11/src/java" includes="**/*.java"/>
+      <fileset dir="jk/java" includes="**/*.java">
+        <exclude name="org/apache/ajp/**"/>
+      </fileset>
+      <classpath refid="compile.classpath"/>
+    </javadoc>
+
+
+  </target>
+
+  <target name="coyote" 
+          description="Compile Coyote and all related protocols">
+    <ant dir="util" />
+    <ant dir="coyote" target="compile" />
+    <ant dir="http11" />
+    <ant dir="jk" target="build-jk"/>
+    
+    <jar jarfile="jtc.jar" 
+      manifest="coyote/src/conf/MANIFEST.MF" >
+      <fileset dir="util/build/classes" includes="org/apache/**" />
+      <fileset dir="coyote/build/classes" includes="org/apache/coyote/**" />
+      <fileset dir="http11/build/classes" includes="org/apache/coyote/**" />
+      <fileset dir="jk/build/classes" >
+        <include name="org/apache/**" />
+        <exclude name="org/apache/jk/ant/**" />
+      </fileset>
+    </jar>
+  </target>
+  
+
+  <target name="clean" description="Delete build and dist trees">
+    <delete dir="dist" />
+    <delete dir="build" />
+  </target>
+
+
+  <target name="download" depends="proxyflags" 
+    description="Download binary packages" >
+    
+    <mkdir dir="${base.path}" />
+    
+    <antcall target="downloadgz">
+      <param name="sourcefile" value="${commons-logging.loc}"/>
+      <param name="destfile" value="${commons-logging.jar}"/>
+    </antcall>
+
+    <antcall target="downloadgz">
+      <param name="sourcefile" value="${commons-modeler.loc}"/>
+      <param name="destfile" value="${commons-modeler.jar}"/>
+    </antcall>
+
+    <antcall target="downloadgz">
+      <param name="sourcefile" value="${jmx.loc}"/>
+      <param name="destfile" value="${jmx.jar}"/>
+    </antcall>
+
+    <antcall target="downloadgz">
+      <param name="sourcefile" value="${tomcat5.loc}"/>
+      <param name="destfile" value="${tomcat5.jar}"/>
+    </antcall>
+
+    <antcall target="downloadgz">
+      <param name="sourcefile" value="${tomcat41.loc}"/>
+      <param name="destfile" value="${tomcat41.jar}"/>
+    </antcall>
+
+    <antcall target="downloadgz">
+      <param name="sourcefile" value="${tomcat33.loc}"/>
+      <param name="destfile" value="${tomcat33.jar}"/>
+    </antcall>
+
+    <antcall target="downloadgz">
+      <param name="sourcefile" value="${regexp.loc}"/>
+      <param name="destfile" value="${regexp.jar}"/>
+    </antcall>
+
+  </target>
+
+
+
+  <!-- Common download targets - we should use an import with ant1.6. This is cut&paste from tocmat5 -->
+  
+  <target name="proxyflags">
+    <!-- check proxy parameters. -->
+    <condition property="useproxy">
+      <equals arg1="${proxy.use}" arg2="on" />
+    </condition>
+  </target>
+
+  <target name="setproxy"  if="useproxy">
+    <taskdef name="setproxy"
+      classname="org.apache.tools.ant.taskdefs.optional.net.SetProxy" />
+    <setproxy proxyhost="${proxy.host}" proxyport="${proxy.port}"/> 
+    <echo message="Using ${proxy.host}:${proxy.port} to download ${sourcefile}"/>
+  </target>
+
+  <target name="testexist">
+    <echo message="Testing  for ${destfile}"/>
+    <available file="${destfile}" property="exist"/>
+  </target>
+
+  <target name="testsrc">
+    <echo message="Testing  for ${destfile} versus ${cvs.base}/${location}/src"/>
+    <uptodate property="exist"
+              targetfile="${destfile}">
+      <srcfiles dir="${cvs.base}/${location}/src" includes="**" />
+    </uptodate>
+  </target>
+
+  <target name="downloadgz" unless="exist" depends="setproxy,testexist">
+    <!-- Download and extract the package -->
+    <get src="${sourcefile}" dest="${base.path}/file.tar.gz" />
+    <gunzip src="${base.path}/file.tar.gz" dest="${base.path}/file.tar"/>
+    <untar src="${base.path}/file.tar" dest="${base.path}"/>
+    <delete file="${base.path}/file.tar"/>
+    <delete file="${base.path}/file.tar.gz"/>
+  </target>
+
+  <target name="downloadzip" unless="exist" depends="setproxy,testexist">
+    <!-- Download and extract the package -->
+    <get src="${sourcefile}" dest="${base.path}/file.zip" />
+    <mkdir dir="${destdir}" />
+    <unzip src="${base.path}/file.zip" dest="${destdir}"/>
+    <delete file="${base.path}/file.zip"/>
+  </target>
+
+  <target name="downloadfile" unless="exist" depends="setproxy,testexist">
+    <!-- Download extract the file -->
+    <mkdir dir="${destdir}" />
+    <get src="${sourcefile}" dest="${destfile}" />
+  </target>
+
+
+  <target name="release" >
+    <property name="ver" value="1.1M1" />
+<!--
+    <property name="tag" value="JTC_1_1_M1" />
+-->
+    <property name="tag" value="HEAD" />
+    <property name="rel.name" value="tomcat-connectors" />
+
+<!--
+-->
+    <delete dir="release" />
+    <mkdir dir="release" />
+
+    <cvs command="checkout" 
+         package="jakarta-tomcat-connectors" 
+         cvsroot=":pserver:anoncvs at cvs.apache.org:/home/cvspublic"
+         dest="release" 
+         tag="${tag}"/> 
+
+    <rename src="release/jakarta-tomcat-connectors" dest="release/${rel.name}-${ver}-src" />
+
+    <zip file="release/${rel.name}-${ver}-src.zip" >
+      <fileset dir="release" >
+        <include name="${rel.name}-${ver}-src/**" />
+        <exclude name="${rel.name}-${ver}-src/webapp/**" />
+        <exclude name="${rel.name}-${ver}-src/build/**" />
+        <exclude name="${rel.name}-${ver}-src/dist/**" />
+        <exclude name="${rel.name}-${ver}-src/scandoc/**" />
+        <exclude name="${rel.name}-${ver}-src/naming/**" />
+      </fileset>
+    </zip>
+    <tar  tarfile="release/${rel.name}-${ver}-src.tar" >
+      <tarfileset dir="release" >
+        <include name="${rel.name}-${ver}-src/**" />
+        <exclude name="${rel.name}-${ver}-src/webapp/**" />
+        <exclude name="${rel.name}-${ver}-src/build/**" />
+        <exclude name="${rel.name}-${ver}-src/dist/**" />
+        <exclude name="${rel.name}-${ver}-src/scandoc/**" />
+        <exclude name="${rel.name}-${ver}-src/naming/**" />
+      </tarfileset>
+    </tar> 
+    <gzip zipfile="release/${rel.name}-${ver}-src.tar.gz" src="release/${rel.name}-${ver}-src.tar"/>
+    <delete file="release/${rel.name}-${ver}-src.tar" />
+
+<!--
+-->
+    <ant dir="release/${rel.name}-${ver}-src" target="download" />
+    <ant dir="release/${rel.name}-${ver}-src" target="dist" inheritAll="false" />
+
+    <mkdir dir="release/${rel.name}-${ver}" />
+    <copy todir="release/${rel.name}-${ver}" >
+       <fileset dir="release/${rel.name}-${ver}-src/dist" includes="**"/>
+    </copy>
+    <copy file="release/${rel.name}-${ver}/${rel.name}.jar" tofile="release/${rel.name}-${ver}.jar" />
+    <zip file="release/${rel.name}-${ver}.zip" >
+       <fileset dir="release" includes="${rel.name}-${ver}/**"/>
+    </zip>
+    <tar  tarfile="release/${rel.name}-${ver}.tar" >
+       <tarfileset dir="release" includes="${rel.name}-${ver}/**"/>
+    </tar> 
+    <gzip zipfile="release/${rel.name}-${ver}.tar.gz" src="release/${rel.name}-${ver}.tar"/>
+    
+  </target>
+
+  
+</project>

Added: branches/tomcat5.5/upstream/5.5.20/connectors/coyote/build.properties.sample
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/coyote/build.properties.sample	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/coyote/build.properties.sample	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,35 @@
+# -------------------------------------------------------------------
+# build.properties.sample
+#
+# This is an example "build.properties" file, used to customize 
+# building Jakarta Coyote for your local environment.  
+# Make any changes you need, and rename this file to 
+# "build.properties" 
+#
+# $Id: build.properties.sample 296515 2002-03-12 03:54:29Z remm $
+# -------------------------------------------------------------------
+
+
+# -------------------------------------------------------------------
+# CONFIGURATION OPTIONS
+# -------------------------------------------------------------------
+
+# 
+
+
+# -------------------------------------------------------------------
+# EXTERNAL DEPENDENCIES 
+# -------------------------------------------------------------------
+
+# tomcat33.home -- Tomcat 3.3 distribution directory
+tomcat33.home=../../jakarta-tomcat/build/tomcat
+
+# catalina.home -- Tomcat 4.x distribution directory
+catalina.home=../../jakarta-tomcat-4.0/build
+
+# tomcat-util.jar -- Tomcat util package
+tomcat-util.jar=../util/build/lib/tomcat-util.jar
+
+# junit.jar -- JUnit classes (http://junit.org)
+junit.jar=/java/junit/junit.jar
+

Added: branches/tomcat5.5/upstream/5.5.20/connectors/coyote/build.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/coyote/build.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/coyote/build.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,376 @@
+<project name="Coyote" default="compile" basedir=".">
+
+
+<!--
+        "Coyote" connector framework for Jakarta Tomcat
+        $Id: build.xml 301006 2005-07-30 11:39:50Z markt $
+-->
+
+
+<!-- ========== Initialize Properties ===================================== -->
+
+
+  <property file="${user.home}/build.properties"/>   <!-- User local        -->
+  <property file="build.properties"/>                <!-- Component local   -->
+  <property file="../build.properties"/>             <!-- Commons local     -->
+  <property file="../build.properties.default"/>             <!-- Commons local     -->
+
+
+<!-- ========== External Dependencies ===================================== -->
+
+
+  <!-- The directories corresponding to your necessary dependencies -->
+  <property name="junit.home"              value="/usr/local/junit3.5"/>
+
+  <!-- Dependencies within jakarta-tomcat-connectors -->
+  <property name="util.home"               value="../util"/>
+
+
+<!-- ========== Derived Values ============================================ -->
+
+
+  <!-- The locations of necessary jar files -->
+  <property name="tomcat-util.jar"  value="../util/build/lib/tomcat-util.jar"/>
+  <property name="junit.jar"        value="${junit.home}/junit.jar"/>
+
+  <property name="commons-modeler.jar" location="../../jakarta-commons/modeler/dist/commons-modeler.jar" />
+
+  <property name="jmx.jar" location="../lib/mx4j.jar" />
+
+
+<!-- ========== Component Declarations ==================================== -->
+
+
+  <!-- The name of this component -->
+  <property name="component.name"          value="coyote"/>
+  <!-- The title of this component -->
+  <property name="component.title"         value="Coyote"/>
+
+  <!-- The current version number of this component -->
+  <property name="component.version"       value="1.0-dev"/>
+
+  <!-- The base directory for compilation targets -->
+  <property name="build.home"              value="build"/>
+
+  <!-- The base directory for component configuration files -->
+  <property name="conf.home"               value="src/conf"/>
+
+  <!-- The base directory for component sources -->
+  <property name="source.home"             value="src/java"/>
+
+  <!-- The base directory for unit test sources -->
+  <property name="test.home"               value="src/test"/>
+
+<!-- ========== Compiler Defaults ========================================= -->
+
+
+  <!-- Should Java compilations set the 'debug' compiler option? -->
+  <property name="compile.debug"           value="true"/>
+
+  <!-- Should Java compilations set the 'deprecation' compiler option? -->
+  <property name="compile.deprecation"     value="false"/>
+
+  <!-- Should Java compilations set the 'optimize' compiler option? -->
+  <property name="compile.optimize"        value="true"/>
+
+    <!-- default locations -->
+    <property name="tomcat33.home" 
+	      location="${base.path}/jakarta-tomcat-3.3" />
+    <property name="catalina.home" 
+	      location="${base.path}/jakarta-tomcat-4.1.24" />
+
+    <property name="servlet.jar"
+              value="${catalina.home}/common/lib/servlet.jar" />
+
+  <!-- Construct compile classpath -->
+  <path id="compile.classpath">
+    <pathelement location="${build.home}/classes"/>
+    <pathelement location="${util.home}/build/classes"/>
+    <pathelement location="${commons-logging.jar}"/>
+    <pathelement location="${commons-modeler.jar}"/>
+    <pathelement location="${jmx.jar}"/>
+    <pathelement location="${tomcat-util.jar}"/>
+    <pathelement location="${catalina.home}/server/lib/catalina.jar"/>
+    <pathelement location="${servlet.jar}"/>
+  </path>
+  <path id="compile.classpath.tomcat33">
+    <pathelement location="${build.home}/classes"/>
+    <pathelement location="${util.home}/build/classes"/>
+    <pathelement location="${commons-logging.jar}"/>
+    <pathelement location="${commons-modeler.jar}"/>
+    <pathelement location="${jmx.jar}"/>
+    <pathelement location="${tomcat33.home}/lib/container/container_util.jar"/>
+    <pathelement location="${tomcat33.home}/lib/container/tomcat_modules.jar"/>
+    <pathelement location="${tomcat33.home}/lib/common/tomcat_core.jar"/>
+    <pathelement location="${tomcat33.home}/lib/common/core_util.jar"/>
+  </path>
+
+
+<!-- ========== Test Execution Defaults =================================== -->
+
+
+  <!-- Construct unit test classpath -->
+  <path id="test.classpath">
+    <pathelement location="${build.home}/classes"/>
+    <pathelement location="${build.home}/tests"/>
+    <pathelement location="${tomcat-util.jar}"/>
+    <pathelement location="${junit.jar}"/>
+  </path>
+
+  <!-- Should all tests fail if one does? -->
+  <property name="test.failonerror"        value="true"/>
+
+  <!-- The test runner to execute -->
+  <property name="test.runner"             value="junit.textui.TestRunner"/>
+  <property name="test.entry" value="org.apache.coyote.TestAll"/>
+
+
+<!-- ========== Detection and Reports ===================================== -->
+
+
+    <target name="report-tc5" if="tomcat5.detect" >
+	<echo message="Tomcat5 detected "  />
+    </target>
+    <target name="report-tc4" if="tomcat4.detect" >
+	<echo message="Tomcat4 detected "  />
+    </target>
+    <target name="report-tc33" if="tomcat33.detect" >
+	<echo message="Tomcat3.3 detected "  />
+    </target>
+
+    <target name="report" depends="report-tc5, report-tc4, report-tc33" />
+
+
+<!-- ========== Executable Targets ======================================== -->
+
+
+  <target name="init"
+   description="Initialize and evaluate conditionals">
+    <echo message="-------- ${component.title} ${component.version} --------"/>
+    <filter  token="name"                  value="${component.name}"/>
+    <filter  token="version"               value="${component.version}"/>
+  </target>
+
+
+  <target name="prepare" depends="init"
+   description="Prepare build directory">
+    <mkdir dir="${build.home}"/>
+    <mkdir dir="${build.home}/classes"/>
+    <mkdir dir="${build.home}/conf"/>
+    <mkdir dir="${build.home}/docs"/>
+    <mkdir dir="${build.home}/docs/api"/>
+    <mkdir dir="${build.home}/lib"/>
+    <mkdir dir="${build.home}/tests"/>
+    <condition property="tomcat5.detect">
+      <and>
+        <available file="${catalina.home}/server/lib/catalina.jar" />
+        <available
+          classname="javax.servlet.ServletRequestEvent"
+          classpath="${servlet.jar}"
+        />
+      </and>
+    </condition>
+    <condition property="tomcat4.detect">
+      <and>
+        <available file="${catalina.home}/server/lib/catalina.jar" />
+        <not>
+          <available
+            classname="javax.servlet.ServletRequestEvent"
+            classpath="${servlet.jar}"
+          />
+        </not>
+      </and>
+    </condition>
+    <available property="tomcat33.detect" file="${tomcat33.home}/lib/common/tomcat_core.jar" />
+  </target>
+
+
+  <target name="static" depends="prepare"
+   description="Copy static files to build directory">
+    <tstamp/>
+    <copy  todir="${build.home}/conf" filtering="on">
+      <fileset dir="${conf.home}" includes="*.MF"/>
+    </copy>
+  </target>
+
+
+  <target name="compile.shared"
+   description="Compile shareable components">
+    <mkdir dir="${build.home}/classes"/>
+    <javac  srcdir="${source.home}"
+           destdir="${build.home}/classes"
+             debug="${compile.debug}"
+       deprecation="${compile.deprecation}"
+          optimize="${compile.optimize}">
+      <classpath refid="compile.classpath"/>
+      <exclude name="org/apache/coyote/tomcat5/**" />
+      <exclude name="org/apache/coyote/tomcat4/**" />
+      <exclude name="org/apache/coyote/tomcat3/**" />
+    </javac>
+    <copy    todir="${build.home}/classes" filtering="on">
+      <fileset dir="${source.home}" excludes="**/*.java"/>
+    </copy>
+  </target>
+
+
+  <target name="compile.tomcat5" if="tomcat5.detect"
+   depends="static,compile.shared"
+   description="Compile Tomcat 5.x Adapter">
+    <javac  srcdir="${source.home}"
+           destdir="${build.home}/classes"
+             debug="${compile.debug}"
+       deprecation="${compile.deprecation}"
+          optimize="${compile.optimize}">
+      <classpath refid="compile.classpath"/>
+      <include name="org/apache/coyote/tomcat5/**" />
+    </javac>
+  </target>
+
+  <target name="jar.tomcat5" depends="compile.tomcat5" >
+    <jar  jarfile="${tomcat-coyote.jar}"
+         index="true"
+         basedir="${build.home}/classes"
+         manifest="${build.home}/conf/MANIFEST.MF"
+         excludes="**/tomcat3/*" >
+      <include name="org/apache/coyote/*.class" />
+      <include name="org/apache/coyote/memory/*.class" />
+      <!-- included with catalina.jar -->
+      <exclude name="org/apache/coyote/tomcat5/**" />
+    </jar>
+  </target>
+
+  <target name="compile.tomcat4" if="tomcat4.detect"
+   description="Compile Tomcat 4.x Adapter">
+    <javac  srcdir="${source.home}"
+           destdir="${build.home}/classes"
+             debug="${compile.debug}"
+       deprecation="${compile.deprecation}"
+          optimize="${compile.optimize}">
+      <classpath refid="compile.classpath"/>
+      <include name="org/apache/coyote/tomcat4/**" />
+    </javac>
+    <copy    todir="${build.home}/classes" filtering="on">
+      <fileset dir="${source.home}" excludes="**/*.java"/>
+    </copy>
+  </target>
+
+  <target name="compile.tomcat33" if="tomcat33.detect"
+   description="Compile Tomcat 3.3.x Adapter">
+    <javac  srcdir="${source.home}"
+           destdir="${build.home}/classes"
+             debug="${compile.debug}"
+       deprecation="${compile.deprecation}"
+          optimize="${compile.optimize}">
+      <classpath refid="compile.classpath.tomcat33"/>
+      <include name="org/apache/coyote/tomcat3/**" />
+    </javac>
+    <copy    todir="${build.home}/classes" filtering="on">
+      <fileset dir="${source.home}" excludes="**/*.java"/>
+    </copy>
+  </target>
+
+  <target name="shared.jar" depends="static,compile.shared"
+       description="Build shared Coyote jar"> 
+    <property name="tomcat-coyote.jar" value="${build.home}/lib/tomcat-${component.name}.jar" />
+    <jar    jarfile="${tomcat-coyote.jar}"
+            index="true"
+            manifest="${build.home}/conf/MANIFEST.MF">
+      <fileset dir="${build.home}/classes" >
+        <exclude name="**/tomcat3/*"/>
+        <exclude name="**/tomcat4/*"/>
+        <exclude name="**/tomcat5/*"/>
+        <include name="org/apache/coyote/**"/>
+      </fileset>
+    </jar>
+  </target>
+ 
+  <target name="tomcat4.jar" depends="static,compile.shared,compile.tomcat4"
+       description="Build Tomcat 4 Adapter jar" if="tomcat4.detect">
+    <property name="tomcat4-coyote.jar" value="${build.home}/lib/tomcat4-${component.name}.jar" />
+    <jar jarfile="${tomcat4-coyote.jar}"
+         index="true"
+         basedir="${build.home}/classes"
+         manifest="${build.home}/conf/MANIFEST.MF"
+         includes="org/apache/coyote/tomcat4/**" />
+  </target>
+
+  <target name="tomcat33.jar" depends="static,compile.shared,compile.tomcat33"
+       description="Build Tomcat 3.3 Adapter jar" if="tomcat33.detect">
+    <property name="tomcat33-coyote.jar" value="${build.home}/lib/tomcat33-${component.name}.jar" />
+    <jar jarfile="${tomcat33-coyote.jar}"
+         index="true"
+         basedir="${build.home}/classes"
+         manifest="${build.home}/conf/MANIFEST.MF"
+         includes="org/apache/coyote/tomcat3/**" /> 
+  </target>
+
+  <target name="compile" 
+   depends="static,report,shared.jar,tomcat4.jar,tomcat33.jar"
+   description="Compile Coyote and its Adapters">
+  </target>
+
+  <target name="compile.tests" depends="compile"
+   description="Compile unit test cases">
+    <javac  srcdir="${test.home}"
+           destdir="${build.home}/tests"
+             debug="${compile.debug}"
+       deprecation="${compile.deprecation}"
+          optimize="${compile.optimize}">
+      <classpath refid="test.classpath"/>
+    </javac>
+    <copy    todir="${build.home}/tests" filtering="on">
+      <fileset dir="${test.home}" excludes="**/*.java"/>
+    </copy>
+  </target>
+
+
+  <target name="clean"
+   description="Clean build and distribution directories">
+    <delete    dir="${build.home}"/>
+  </target>
+
+
+  <target name="all" depends="clean,compile"
+   description="Clean and compile all components"/>
+
+
+  <target name="javadoc" unless="docs-uptodate"
+   description="Create component Javadoc documentation">
+    <mkdir dir="${build.home}/docs/api"/>
+    <javadoc sourcepath="${source.home}"
+                destdir="${build.home}/docs/api"
+           packagenames="org.apache.coyote"
+                 author="true"
+                private="true"
+                version="true"
+               doctitle="&lt;h1&gt;${component.title}&lt;/h1&gt;"
+            windowtitle="${component.title} (Version ${component.version})"
+                 bottom="Copyright (c) 2001 - Apache Software Foundation">
+      <classpath refid="compile.classpath"/>
+    </javadoc>
+  </target>
+
+
+<!-- ========== Unit Test Targets ========================================= -->
+
+
+  <target name="test"  depends="compile.tests" if="test.entry"
+   description="Run all unit test cases">
+      <!--
+      <junit printsummary="yes" fork="on" haltonfailure="yes">
+      	<formatter type="plain" usefile="false"/>
+      	<test name="${test.entry}"/>
+        <classpath refid="test.classpath"/>
+      </junit>
+      -->
+
+      <java classname="${test.runner}" fork="yes"
+       failonerror="${test.failonerror}">
+        <jvmarg value="${java.protocol.handler.pkgs}"/>
+        <arg value="${test.entry}"/>
+        <classpath refid="test.classpath"/>
+      </java>
+  </target>
+
+
+</project>

Added: branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/conf/MANIFEST.MF
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/conf/MANIFEST.MF	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/conf/MANIFEST.MF	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,6 @@
+Extension-Name: @name@
+Specification-Vendor: Apache Software Foundation
+Specification-Version: 1.1
+Implementation-Vendor: Apache Software Foundation
+Implementation-Version: @version@
+

Added: branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/java/org/apache/coyote/ActionCode.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/java/org/apache/coyote/ActionCode.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/java/org/apache/coyote/ActionCode.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,153 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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;
+
+
+/**
+ * Enumerated class containing the adapter event codes.
+ * Actions represent callbacks from the servlet container to the coyote
+ * connector.
+ *
+ * Actions are implemented by ProtocolHandler, using the ActionHook interface.
+ *
+ * @see ProtocolHandler
+ * @see ActionHook
+ * @author Remy Maucherat
+ */
+public final class ActionCode {
+
+
+    // -------------------------------------------------------------- Constants
+
+
+    public static final ActionCode ACTION_ACK = new ActionCode(1);
+
+
+    public static final ActionCode ACTION_CLOSE = new ActionCode(2);
+
+
+    public static final ActionCode ACTION_COMMIT = new ActionCode(3);
+
+
+    /**
+     * A flush() operation originated by the client ( i.e. a flush() on
+     * the servlet output stream or writer, called by a servlet ).
+     * 
+     * Argument is the Response.
+     */
+    public static final ActionCode ACTION_CLIENT_FLUSH = new ActionCode(4);
+
+    
+    public static final ActionCode ACTION_CUSTOM = new ActionCode(5);
+
+
+    public static final ActionCode ACTION_RESET = new ActionCode(6);
+
+
+    public static final ActionCode ACTION_START = new ActionCode(7);
+
+
+    public static final ActionCode ACTION_STOP = new ActionCode(8);
+
+
+    public static final ActionCode ACTION_WEBAPP = new ActionCode(9);
+
+    /** Hook called after request, but before recycling. Can be used
+        for logging, to update counters, custom cleanup - the request
+        is still visible
+    */
+    public static final ActionCode ACTION_POST_REQUEST = new ActionCode(10);
+
+    /**
+     * Callback for lazy evaluation - extract the remote host address.
+     */
+    public static final ActionCode ACTION_REQ_HOST_ATTRIBUTE = 
+        new ActionCode(11);
+
+
+    /**
+     * Callback for lazy evaluation - extract the remote host infos (address, name, port) and local address.
+     */
+    public static final ActionCode ACTION_REQ_HOST_ADDR_ATTRIBUTE = new ActionCode(12);
+
+    /**
+     * Callback for lazy evaluation - extract the SSL-related attributes.
+     */
+    public static final ActionCode ACTION_REQ_SSL_ATTRIBUTE = new ActionCode(13);
+
+
+    /** Chain for request creation. Called each time a new request is created
+        ( requests are recycled ).
+     */
+    public static final ActionCode ACTION_NEW_REQUEST = new ActionCode(14);
+
+
+    /**
+     * Callback for lazy evaluation - extract the SSL-certificate 
+     * (including forcing a re-handshake if necessary)
+     */
+    public static final ActionCode ACTION_REQ_SSL_CERTIFICATE = new ActionCode(15);
+    
+    
+    /**
+     * Callback for lazy evaluation - socket remote port.
+     **/
+    public static final ActionCode ACTION_REQ_REMOTEPORT_ATTRIBUTE = new ActionCode(16);
+
+    
+    /**
+     * Callback for lazy evaluation - socket local port.
+     **/
+    public static final ActionCode ACTION_REQ_LOCALPORT_ATTRIBUTE = new ActionCode(17);
+    
+    
+    /**
+     * Callback for lazy evaluation - local address.
+     **/
+    public static final ActionCode ACTION_REQ_LOCAL_ADDR_ATTRIBUTE = new ActionCode(18);
+    
+    
+    /**
+     * Callback for lazy evaluation - local address.
+     **/
+    public static final ActionCode ACTION_REQ_LOCAL_NAME_ATTRIBUTE = new ActionCode(19);
+
+
+    /**
+     * Callback for setting FORM auth body replay
+     */
+    public static final ActionCode ACTION_REQ_SET_BODY_REPLAY = new ActionCode(20);
+
+
+    // ----------------------------------------------------------- Constructors
+    int code;
+
+    /**
+     * Private constructor.
+     */
+    private ActionCode(int code) {
+        this.code=code;
+    }
+
+    /** Action id, useable in switches and table indexes
+     */
+    public int getCode() {
+        return code;
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/java/org/apache/coyote/ActionHook.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/java/org/apache/coyote/ActionHook.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/java/org/apache/coyote/ActionHook.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,47 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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;
+
+
+/**
+ * Action hook. Actions represent the callback mechanism used by
+ * coyote servlet containers to request operations on the coyote connectors.
+ * Some standard actions are defined in ActionCode, however custom
+ * actions are permitted.
+ *
+ * The param object can be used to pass and return informations related with the
+ * action.
+ * 
+ *
+ * This interface is typically implemented by ProtocolHandlers, and the param
+ * is usually a Request or Response object.
+ *
+ * @author Remy Maucherat
+ */
+public interface ActionHook {
+
+
+    /**
+     * Send an action to the connector.
+     * 
+     * @param actionCode Type of the action
+     * @param param Action parameter
+     */
+    public void action(ActionCode actionCode, Object param);
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/java/org/apache/coyote/Adapter.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/java/org/apache/coyote/Adapter.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/java/org/apache/coyote/Adapter.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,49 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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;
+
+
+/**
+ * Adapter. This represents the entry point in a coyote-based servlet container.
+ *
+ *
+ * @author Remy Maucherat
+ * @see ProtocolHandler
+ */
+public interface Adapter {
+
+
+    /** 
+     * Call the service method, and notify all listeners
+     *
+     * @exception Exception if an error happens during handling of
+     *   the request. Common errors are:
+     *   <ul><li>IOException if an input/output error occurs and we are
+     *   processing an included servlet (otherwise it is swallowed and
+     *   handled by the top level error handler mechanism)
+     *       <li>ServletException if a servlet throws an exception and
+     *  we are processing an included servlet (otherwise it is swallowed
+     *  and handled by the top level error handler mechanism)
+     *  </ul>
+     *  Tomcat should be able to handle and log any other exception ( including
+     *  runtime exceptions )
+     */
+    public void service(Request req, Response res)
+	throws Exception;
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/java/org/apache/coyote/Constants.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/java/org/apache/coyote/Constants.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/java/org/apache/coyote/Constants.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,55 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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;
+
+import java.util.Locale;
+
+/**
+ * Constants.
+ *
+ * @author Remy Maucherat
+ */
+public final class Constants {
+
+
+    // -------------------------------------------------------------- Constants
+
+
+    public static final String DEFAULT_CHARACTER_ENCODING="ISO-8859-1";
+
+
+    public static final String LOCALE_DEFAULT = "en";
+
+
+    public static final Locale DEFAULT_LOCALE = new Locale(LOCALE_DEFAULT, "");
+
+
+    public static final int MAX_NOTES = 32;
+
+
+    // Request states
+    public static final int STAGE_NEW = 0;
+    public static final int STAGE_PARSE = 1;
+    public static final int STAGE_PREPARE = 2;
+    public static final int STAGE_SERVICE = 3;
+    public static final int STAGE_ENDINPUT = 4;
+    public static final int STAGE_ENDOUTPUT = 5;
+    public static final int STAGE_KEEPALIVE = 6;
+    public static final int STAGE_ENDED = 7;
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/java/org/apache/coyote/InputBuffer.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/java/org/apache/coyote/InputBuffer.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/java/org/apache/coyote/InputBuffer.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,45 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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;
+
+import java.io.IOException;
+
+import org.apache.tomcat.util.buf.ByteChunk;
+
+
+/**
+ * Input buffer.
+ *
+ * This class is used only in the protocol implementation. All reading from tomcat ( or adapter ) should be done
+ * using Request.doRead().
+ *
+ * 
+ * @author Remy Maucherat
+ */
+public interface InputBuffer {
+
+
+    /** Return from the input stream.
+        IMPORTANT: the current model assumes that the protocol will 'own' the
+        buffer and return a pointer to it in ByteChunk ( i.e. the param will
+        have chunk.getBytes()==null before call, and the result after the call ).
+    */
+    public int doRead(ByteChunk chunk, Request request) 
+        throws IOException;
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/java/org/apache/coyote/OutputBuffer.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/java/org/apache/coyote/OutputBuffer.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/java/org/apache/coyote/OutputBuffer.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,46 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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;
+
+import java.io.IOException;
+
+import org.apache.tomcat.util.buf.ByteChunk;
+
+
+/**
+ * Output buffer.
+ *
+ * This class is used internally by the protocol implementation. All writes from higher level code should happen
+ * via Resonse.doWrite().
+ * 
+ * @author Remy Maucherat
+ */
+public interface OutputBuffer {
+
+
+    /** Write the response. The caller ( tomcat ) owns the chunks.
+     *
+     * @param chunk data to write
+     * @param response used to allow buffers that can be shared by multiple responses.
+     * @return
+     * @throws IOException
+     */
+    public int doWrite(ByteChunk chunk, Response response)
+        throws IOException;
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/java/org/apache/coyote/Processor.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/java/org/apache/coyote/Processor.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/java/org/apache/coyote/Processor.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,44 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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;
+
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+
+
+/**
+ * Processor.
+ *
+ * Not really used, should be deprecated. 
+ *
+ * @author Remy Maucherat
+ */
+public interface Processor {
+
+
+    public void setAdapter(Adapter adapter);
+
+
+    public Adapter getAdapter();
+
+
+    public void process(InputStream input, OutputStream output)
+        throws IOException;
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/java/org/apache/coyote/ProtocolHandler.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/java/org/apache/coyote/ProtocolHandler.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/java/org/apache/coyote/ProtocolHandler.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,84 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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;
+
+import java.util.Iterator;
+
+
+/**
+ * Abstract the protocol implementation, including threading, etc.
+ * Processor is single threaded and specific to stream-based protocols,
+ * will not fit Jk protocols like JNI.
+ *
+ * This is the main interface to be implemented by a coyoute connector.
+ * Adapter is the main interface to be impleneted by a coyote servlet container.
+ *
+ * @author Remy Maucherat
+ * @author Costin Manolache
+ * @see Adapter
+ */
+public interface ProtocolHandler {
+
+
+    /**
+     * Pass config info.
+     */
+    public void setAttribute(String name, Object value);
+
+
+    public Object getAttribute(String name);
+    public Iterator getAttributeNames();
+
+    /**
+     * The adapter, used to call the connector.
+     */
+    public void setAdapter(Adapter adapter);
+
+
+    public Adapter getAdapter();
+
+
+    /**
+     * Init the protocol.
+     */
+    public void init()
+        throws Exception;
+
+
+    /**
+     * Start the protocol.
+     */
+    public void start()
+        throws Exception;
+
+    /**
+     * Pause the protocol (optional).
+     */
+    public void pause()
+        throws Exception;
+
+    /**
+     * Resume the protocol (optional).
+     */
+    public void resume()
+        throws Exception;
+
+    public void destroy()
+        throws Exception;
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/java/org/apache/coyote/Request.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/java/org/apache/coyote/Request.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/java/org/apache/coyote/Request.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,502 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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;
+
+import java.io.IOException;
+import java.util.HashMap;
+
+import org.apache.tomcat.util.buf.ByteChunk;
+import org.apache.tomcat.util.buf.MessageBytes;
+import org.apache.tomcat.util.buf.UDecoder;
+
+import org.apache.tomcat.util.http.MimeHeaders;
+import org.apache.tomcat.util.http.Parameters;
+import org.apache.tomcat.util.http.ContentType;
+import org.apache.tomcat.util.http.Cookies;
+
+/**
+ * This is a low-level, efficient representation of a server request. Most 
+ * fields are GC-free, expensive operations are delayed until the  user code 
+ * needs the information.
+ *
+ * Processing is delegated to modules, using a hook mechanism.
+ * 
+ * This class is not intended for user code - it is used internally by tomcat
+ * for processing the request in the most efficient way. Users ( servlets ) can
+ * access the information using a facade, which provides the high-level view
+ * of the request.
+ *
+ * For lazy evaluation, the request uses the getInfo() hook. The following ids
+ * are defined:
+ * <ul>
+ *  <li>req.encoding - returns the request encoding
+ *  <li>req.attribute - returns a module-specific attribute ( like SSL keys, etc ).
+ * </ul>
+ *
+ * Tomcat defines a number of attributes:
+ * <ul>
+ *   <li>"org.apache.tomcat.request" - allows access to the low-level
+ *       request object in trusted applications 
+ * </ul>
+ *
+ * @author James Duncan Davidson [duncan at eng.sun.com]
+ * @author James Todd [gonzo at eng.sun.com]
+ * @author Jason Hunter [jch at eng.sun.com]
+ * @author Harish Prabandham
+ * @author Alex Cruikshank [alex at epitonic.com]
+ * @author Hans Bergsten [hans at gefionsoftware.com]
+ * @author Costin Manolache
+ * @author Remy Maucherat
+ */
+public final class Request {
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    public Request() {
+
+        parameters.setQuery(queryMB);
+        parameters.setURLDecoder(urlDecoder);
+        parameters.setHeaders(headers);
+
+    }
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    private int serverPort = -1;
+    private MessageBytes serverNameMB = MessageBytes.newInstance();
+
+    private int remotePort;
+    private int localPort;
+
+    private MessageBytes schemeMB = MessageBytes.newInstance();
+
+    private MessageBytes methodMB = MessageBytes.newInstance();
+    private MessageBytes unparsedURIMB = MessageBytes.newInstance();
+    private MessageBytes uriMB = MessageBytes.newInstance();
+    private MessageBytes decodedUriMB = MessageBytes.newInstance();
+    private MessageBytes queryMB = MessageBytes.newInstance();
+    private MessageBytes protoMB = MessageBytes.newInstance();
+
+    // remote address/host
+    private MessageBytes remoteAddrMB = MessageBytes.newInstance();
+    private MessageBytes localNameMB = MessageBytes.newInstance();
+    private MessageBytes remoteHostMB = MessageBytes.newInstance();
+    private MessageBytes localAddrMB = MessageBytes.newInstance();
+     
+    private MimeHeaders headers = new MimeHeaders();
+
+    private MessageBytes instanceId = MessageBytes.newInstance();
+
+    /**
+     * Notes.
+     */
+    private Object notes[] = new Object[Constants.MAX_NOTES];
+
+
+    /**
+     * Associated input buffer.
+     */
+    private InputBuffer inputBuffer = null;
+
+
+    /**
+     * URL decoder.
+     */
+    private UDecoder urlDecoder = new UDecoder();
+
+
+    /**
+     * HTTP specific fields. (remove them ?)
+     */
+    private long contentLength = -1;
+    private MessageBytes contentTypeMB = null;
+    private String charEncoding = null;
+    private Cookies cookies = new Cookies(headers);
+    private Parameters parameters = new Parameters();
+
+    private MessageBytes remoteUser=MessageBytes.newInstance();
+    private MessageBytes authType=MessageBytes.newInstance();
+    private HashMap attributes=new HashMap();
+
+    private Response response;
+    private ActionHook hook;
+
+    private int bytesRead=0;
+    // Time of the request - usefull to avoid repeated calls to System.currentTime
+    private long startTime = 0L;
+
+    private RequestInfo reqProcessorMX=new RequestInfo(this);
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * Get the instance id (or JVM route). Curently Ajp is sending it with each
+     * request. In future this should be fixed, and sent only once ( or
+     * 'negociated' at config time so both tomcat and apache share the same name.
+     * 
+     * @return the instance id
+     */
+    public MessageBytes instanceId() {
+        return instanceId;
+    }
+
+
+    public MimeHeaders getMimeHeaders() {
+        return headers;
+    }
+
+
+    public UDecoder getURLDecoder() {
+        return urlDecoder;
+    }
+
+    // -------------------- Request data --------------------
+
+
+    public MessageBytes scheme() {
+        return schemeMB;
+    }
+    
+    public MessageBytes method() {
+        return methodMB;
+    }
+    
+    public MessageBytes unparsedURI() {
+        return unparsedURIMB;
+    }
+
+    public MessageBytes requestURI() {
+        return uriMB;
+    }
+
+    public MessageBytes decodedURI() {
+        return decodedUriMB;
+    }
+
+    public MessageBytes query() {
+        return queryMB;
+    }
+
+    public MessageBytes queryString() {
+        return queryMB;
+    }
+
+    public MessageBytes protocol() {
+        return protoMB;
+    }
+    
+    /** 
+     * Return the buffer holding the server name, if
+     * any. Use isNull() to check if there is no value
+     * set.
+     * This is the "virtual host", derived from the
+     * Host: header.
+     */
+    public MessageBytes serverName() {
+        return serverNameMB;
+    }
+
+    public int getServerPort() {
+        return serverPort;
+    }
+    
+    public void setServerPort(int serverPort ) {
+        this.serverPort=serverPort;
+    }
+
+    public MessageBytes remoteAddr() {
+        return remoteAddrMB;
+    }
+
+    public MessageBytes remoteHost() {
+        return remoteHostMB;
+    }
+
+    public MessageBytes localName() {
+        return localNameMB;
+    }    
+
+    public MessageBytes localAddr() {
+        return localAddrMB;
+    }
+    
+    public int getRemotePort(){
+        return remotePort;
+    }
+        
+    public void setRemotePort(int port){
+        this.remotePort = port;
+    }
+    
+    public int getLocalPort(){
+        return localPort;
+    }
+        
+    public void setLocalPort(int port){
+        this.localPort = port;
+    }
+
+    // -------------------- encoding/type --------------------
+
+
+    /**
+     * Get the character encoding used for this request.
+     */
+    public String getCharacterEncoding() {
+
+        if (charEncoding != null)
+            return charEncoding;
+
+        charEncoding = ContentType.getCharsetFromContentType(getContentType());
+        return charEncoding;
+
+    }
+
+
+    public void setCharacterEncoding(String enc) {
+        this.charEncoding = enc;
+    }
+
+
+    public void setContentLength(int len) {
+        this.contentLength = len;
+    }
+
+
+    public int getContentLength() {
+        long length = getContentLengthLong();
+
+        if (length < Integer.MAX_VALUE) {
+            return (int) length;
+        }
+        return -1;
+    }
+
+    public long getContentLengthLong() {
+        if( contentLength > -1 ) return contentLength;
+
+        MessageBytes clB = headers.getValue("content-length");
+        contentLength = (clB == null || clB.isNull()) ? -1 : clB.getLong();
+
+        return contentLength;
+    }
+
+    public String getContentType() {
+        contentType();
+        if ((contentTypeMB == null) || contentTypeMB.isNull()) 
+            return null;
+        return contentTypeMB.toString();
+    }
+
+
+    public void setContentType(String type) {
+        contentTypeMB.setString(type);
+    }
+
+
+    public MessageBytes contentType() {
+        if (contentTypeMB == null)
+            contentTypeMB = headers.getValue("content-type");
+        return contentTypeMB;
+    }
+
+
+    public void setContentType(MessageBytes mb) {
+        contentTypeMB=mb;
+    }
+
+
+    public String getHeader(String name) {
+        return headers.getHeader(name);
+    }
+
+    // -------------------- Associated response --------------------
+
+    public Response getResponse() {
+        return response;
+    }
+
+    public void setResponse( Response response ) {
+        this.response=response;
+        response.setRequest( this );
+    }
+    
+    public void action(ActionCode actionCode, Object param) {
+        if( hook==null && response!=null )
+            hook=response.getHook();
+        
+        if (hook != null) {
+            if( param==null ) 
+                hook.action(actionCode, this);
+            else
+                hook.action(actionCode, param);
+        }
+    }
+
+
+    // -------------------- Cookies --------------------
+
+
+    public Cookies getCookies() {
+        return cookies;
+    }
+
+
+    // -------------------- Parameters --------------------
+
+
+    public Parameters getParameters() {
+        return parameters;
+    }
+
+
+    // -------------------- Other attributes --------------------
+    // We can use notes for most - need to discuss what is of general interest
+    
+    public void setAttribute( String name, Object o ) {
+        attributes.put( name, o );
+    }
+
+    public HashMap getAttributes() {
+        return attributes;
+    }
+
+    public Object getAttribute(String name ) {
+        return attributes.get(name);
+    }
+    
+    public MessageBytes getRemoteUser() {
+        return remoteUser;
+    }
+
+    public MessageBytes getAuthType() {
+        return authType;
+    }
+
+    // -------------------- Input Buffer --------------------
+
+
+    public InputBuffer getInputBuffer() {
+        return inputBuffer;
+    }
+
+
+    public void setInputBuffer(InputBuffer inputBuffer) {
+        this.inputBuffer = inputBuffer;
+    }
+
+
+    /**
+     * Read data from the input buffer and put it into a byte chunk.
+     *
+     * The buffer is owned by the protocol implementation - it will be reused on the next read.
+     * The Adapter must either process the data in place or copy it to a separate buffer if it needs
+     * to hold it. In most cases this is done during byte->char conversions or via InputStream. Unlike
+     * InputStream, this interface allows the app to process data in place, without copy.
+     *
+     */
+    public int doRead(ByteChunk chunk) 
+        throws IOException {
+        int n = inputBuffer.doRead(chunk, this);
+        if (n > 0) {
+            bytesRead+=n;
+        }
+        return n;
+    }
+
+
+    // -------------------- debug --------------------
+
+    public String toString() {
+        return "R( " + requestURI().toString() + ")";
+    }
+
+    public long getStartTime() {
+        return startTime;
+    }
+
+    public void setStartTime(long startTime) {
+        this.startTime = startTime;
+    }
+
+    // -------------------- Per-Request "notes" --------------------
+
+
+    public final void setNote(int pos, Object value) {
+        notes[pos] = value;
+    }
+
+
+    public final Object getNote(int pos) {
+        return notes[pos];
+    }
+
+
+    // -------------------- Recycling -------------------- 
+
+
+    public void recycle() {
+        bytesRead=0;
+
+        contentLength = -1;
+        contentTypeMB = null;
+        charEncoding = null;
+        headers.recycle();
+        serverNameMB.recycle();
+        serverPort=-1;
+        localPort = -1;
+        remotePort = -1;
+
+        cookies.recycle();
+        parameters.recycle();
+
+        unparsedURIMB.recycle();
+        uriMB.recycle(); 
+        decodedUriMB.recycle();
+        queryMB.recycle();
+        methodMB.recycle();
+        protoMB.recycle();
+
+        schemeMB.recycle();
+
+        instanceId.recycle();
+        remoteUser.recycle();
+        authType.recycle();
+        attributes.clear();
+    }
+
+    // -------------------- Info  --------------------
+    public void updateCounters() {
+        reqProcessorMX.updateCounters();
+    }
+
+    public RequestInfo getRequestProcessor() {
+        return reqProcessorMX;
+    }
+
+    public int getBytesRead() {
+        return bytesRead;
+    }
+
+    public void setBytesRead(int bytesRead) {
+        this.bytesRead = bytesRead;
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/java/org/apache/coyote/RequestGroupInfo.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/java/org/apache/coyote/RequestGroupInfo.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/java/org/apache/coyote/RequestGroupInfo.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,163 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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;
+
+import java.util.ArrayList;
+
+/** This can be moved to top level ( eventually with a better name ).
+ *  It is currently used only as a JMX artifact, to agregate the data
+ *  collected from each RequestProcessor thread.
+ */
+public class RequestGroupInfo {
+    ArrayList processors=new ArrayList();
+    private long deadMaxTime = 0;
+    private long deadProcessingTime = 0;
+    private int deadRequestCount = 0;
+    private int deadErrorCount = 0;
+    private long deadBytesReceived = 0;
+    private long deadBytesSent = 0;
+
+    public synchronized void addRequestProcessor( RequestInfo rp ) {
+        processors.add( rp );
+    }
+
+    public synchronized void removeRequestProcessor( RequestInfo rp ) {
+        if( rp != null ) {
+            if( deadMaxTime < rp.getMaxTime() )
+                deadMaxTime = rp.getMaxTime();
+            deadProcessingTime += rp.getProcessingTime();
+            deadRequestCount += rp.getRequestCount();
+            deadErrorCount += rp.getErrorCount();
+            deadBytesReceived += rp.getBytesReceived();
+            deadBytesSent += rp.getBytesSent();
+
+            processors.remove( rp );
+        }
+    }
+
+    public synchronized long getMaxTime() {
+        long maxTime=deadMaxTime;
+        for( int i=0; i<processors.size(); i++ ) {
+            RequestInfo rp=(RequestInfo)processors.get( i );
+            if( maxTime < rp.getMaxTime() ) maxTime=rp.getMaxTime();
+        }
+        return maxTime;
+    }
+
+    // Used to reset the times
+    public synchronized void setMaxTime(long maxTime) {
+        deadMaxTime = maxTime;
+        for( int i=0; i<processors.size(); i++ ) {
+            RequestInfo rp=(RequestInfo)processors.get( i );
+            rp.setMaxTime(maxTime);
+        }
+    }
+
+    public synchronized long getProcessingTime() {
+        long time=deadProcessingTime;
+        for( int i=0; i<processors.size(); i++ ) {
+            RequestInfo rp=(RequestInfo)processors.get( i );
+            time += rp.getProcessingTime();
+        }
+        return time;
+    }
+
+    public synchronized void setProcessingTime(long totalTime) {
+        deadProcessingTime = totalTime;
+        for( int i=0; i<processors.size(); i++ ) {
+            RequestInfo rp=(RequestInfo)processors.get( i );
+            rp.setProcessingTime( totalTime );
+        }
+    }
+
+    public synchronized int getRequestCount() {
+        int requestCount=deadRequestCount;
+        for( int i=0; i<processors.size(); i++ ) {
+            RequestInfo rp=(RequestInfo)processors.get( i );
+            requestCount += rp.getRequestCount();
+        }
+        return requestCount;
+    }
+
+    public synchronized void setRequestCount(int requestCount) {
+        deadRequestCount = requestCount;
+        for( int i=0; i<processors.size(); i++ ) {
+            RequestInfo rp=(RequestInfo)processors.get( i );
+            rp.setRequestCount( requestCount );
+        }
+    }
+
+    public synchronized int getErrorCount() {
+        int requestCount=deadErrorCount;
+        for( int i=0; i<processors.size(); i++ ) {
+            RequestInfo rp=(RequestInfo)processors.get( i );
+            requestCount += rp.getErrorCount();
+        }
+        return requestCount;
+    }
+
+    public synchronized void setErrorCount(int errorCount) {
+        deadErrorCount = errorCount;
+        for( int i=0; i<processors.size(); i++ ) {
+            RequestInfo rp=(RequestInfo)processors.get( i );
+            rp.setErrorCount( errorCount);
+        }
+    }
+
+    public synchronized long getBytesReceived() {
+        long bytes=deadBytesReceived;
+        for( int i=0; i<processors.size(); i++ ) {
+            RequestInfo rp=(RequestInfo)processors.get( i );
+            bytes += rp.getBytesReceived();
+        }
+        return bytes;
+    }
+
+    public synchronized void setBytesReceived(long bytesReceived) {
+        deadBytesReceived = bytesReceived;
+        for( int i=0; i<processors.size(); i++ ) {
+            RequestInfo rp=(RequestInfo)processors.get( i );
+            rp.setBytesReceived( bytesReceived );
+        }
+    }
+
+    public synchronized long getBytesSent() {
+        long bytes=deadBytesSent;
+        for( int i=0; i<processors.size(); i++ ) {
+            RequestInfo rp=(RequestInfo)processors.get( i );
+            bytes += rp.getBytesSent();
+        }
+        return bytes;
+    }
+
+    public synchronized void setBytesSent(long bytesSent) {
+        deadBytesSent = bytesSent;
+        for( int i=0; i<processors.size(); i++ ) {
+            RequestInfo rp=(RequestInfo)processors.get( i );
+            rp.setBytesSent( bytesSent );
+        }
+    }
+
+    public void resetCounters() {
+        this.setBytesReceived(0);
+        this.setBytesSent(0);
+        this.setRequestCount(0);
+        this.setProcessingTime(0);
+        this.setMaxTime(0);
+        this.setErrorCount(0);
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/java/org/apache/coyote/RequestInfo.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/java/org/apache/coyote/RequestInfo.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/java/org/apache/coyote/RequestInfo.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,215 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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;
+
+
+/**
+ * Structure holding the Request and Response objects. It also holds statistical
+ * informations about request processing and provide management informations
+ * about the requests beeing processed.
+ *
+ * Each thread uses a Request/Response pair that is recycled on each request.
+ * This object provides a place to collect global low-level statistics - without
+ * having to deal with synchronization ( since each thread will have it's own
+ * RequestProcessorMX ).
+ *
+ * TODO: Request notifications will be registered here.
+ *
+ * @author Costin Manolache
+ */
+public class RequestInfo  {
+    RequestGroupInfo global=null;
+
+    // ----------------------------------------------------------- Constructors
+
+    public RequestInfo( Request req) {
+        this.req=req;
+    }
+
+    public RequestGroupInfo getGlobalProcessor() {
+        return global;
+    }
+    
+    public void setGlobalProcessor(RequestGroupInfo global) {
+        if( global != null) {
+            this.global=global;
+            global.addRequestProcessor( this );
+        } else {
+        	if (this.global != null) {
+                this.global.removeRequestProcessor( this ); 
+                this.global = null;
+            }
+        }
+    }
+
+
+    // ----------------------------------------------------- Instance Variables
+    Request req;
+    Response res;
+    int stage = Constants.STAGE_NEW;
+
+    // -------------------- Information about the current request  -----------
+    // This is usefull for long-running requests only
+
+    public String getMethod() {
+        return req.method().toString();
+    }
+
+    public String getCurrentUri() {
+        return req.requestURI().toString();
+    }
+
+    public String getCurrentQueryString() {
+        return req.queryString().toString();
+    }
+
+    public String getProtocol() {
+        return req.protocol().toString();
+    }
+
+    public String getVirtualHost() {
+        return req.serverName().toString();
+    }
+
+    public int getServerPort() {
+        return req.getServerPort();
+    }
+
+    public String getRemoteAddr() {
+        req.action(ActionCode.ACTION_REQ_HOST_ADDR_ATTRIBUTE, null);
+        return req.remoteAddr().toString();
+    }
+
+    public int getContentLength() {
+        return req.getContentLength();
+    }
+
+    public long getRequestBytesReceived() {
+        return req.getBytesRead();
+    }
+
+    public long getRequestBytesSent() {
+        return req.getResponse().getBytesWritten();
+    }
+
+    public long getRequestProcessingTime() {
+        return (System.currentTimeMillis() - req.getStartTime());
+    }
+
+    // -------------------- Statistical data  --------------------
+    // Collected at the end of each request.
+    private long bytesSent;
+    private long bytesReceived;
+
+    // Total time = divide by requestCount to get average.
+    private long processingTime;
+    // The longest response time for a request
+    private long maxTime;
+    // URI of the request that took maxTime
+    private String maxRequestUri;
+
+    private int requestCount;
+    // number of response codes >= 400
+    private int errorCount;
+
+
+    /** Called by the processor before recycling the request. It'll collect
+     * statistic information.
+     */
+    void updateCounters() {
+        bytesReceived+=req.getBytesRead();
+        bytesSent+=req.getResponse().getBytesWritten();
+
+        requestCount++;
+        if( req.getResponse().getStatus() >=400 )
+            errorCount++;
+        long t0=req.getStartTime();
+        long t1=System.currentTimeMillis();
+        long time=t1-t0;
+        processingTime+=time;
+        if( maxTime < time ) {
+            maxTime=time;
+            maxRequestUri=req.requestURI().toString();
+        }
+    }
+
+    public int getStage() {
+        return stage;
+    }
+
+    public void setStage(int stage) {
+        this.stage = stage;
+    }
+
+    public long getBytesSent() {
+        return bytesSent;
+    }
+
+    public void setBytesSent(long bytesSent) {
+        this.bytesSent = bytesSent;
+    }
+
+    public long getBytesReceived() {
+        return bytesReceived;
+    }
+
+    public void setBytesReceived(long bytesReceived) {
+        this.bytesReceived = bytesReceived;
+    }
+
+    public long getProcessingTime() {
+        return processingTime;
+    }
+
+    public void setProcessingTime(long processingTime) {
+        this.processingTime = processingTime;
+    }
+
+    public long getMaxTime() {
+        return maxTime;
+    }
+
+    public void setMaxTime(long maxTime) {
+        this.maxTime = maxTime;
+    }
+
+    public String getMaxRequestUri() {
+        return maxRequestUri;
+    }
+
+    public void setMaxRequestUri(String maxRequestUri) {
+        this.maxRequestUri = maxRequestUri;
+    }
+
+    public int getRequestCount() {
+        return requestCount;
+    }
+
+    public void setRequestCount(int requestCount) {
+        this.requestCount = requestCount;
+    }
+
+    public int getErrorCount() {
+        return errorCount;
+    }
+
+    public void setErrorCount(int errorCount) {
+        this.errorCount = errorCount;
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/java/org/apache/coyote/Response.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/java/org/apache/coyote/Response.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/java/org/apache/coyote/Response.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,591 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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;
+
+import java.io.IOException;
+import java.util.Locale;
+
+import org.apache.tomcat.util.buf.ByteChunk;
+import org.apache.tomcat.util.http.MimeHeaders;
+
+/**
+ * Response object.
+ * 
+ * @author James Duncan Davidson [duncan at eng.sun.com]
+ * @author Jason Hunter [jch at eng.sun.com]
+ * @author James Todd [gonzo at eng.sun.com]
+ * @author Harish Prabandham
+ * @author Hans Bergsten <hans at gefionsoftware.com>
+ * @author Remy Maucherat
+ */
+public final class Response {
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    public Response() {
+    }
+
+
+    // ----------------------------------------------------- Class Variables
+
+    /**
+     * Default locale as mandated by the spec.
+     */
+    private static Locale DEFAULT_LOCALE = Locale.getDefault();
+
+
+    // ----------------------------------------------------- Instance Variables
+
+    /**
+     * Status code.
+     */
+    protected int status = 200;
+
+
+    /**
+     * Status message.
+     */
+    protected String message = null;
+
+
+    /**
+     * Response headers.
+     */
+    protected MimeHeaders headers = new MimeHeaders();
+
+
+    /**
+     * Associated output buffer.
+     */
+    protected OutputBuffer outputBuffer;
+
+
+    /**
+     * Notes.
+     */
+    protected Object notes[] = new Object[Constants.MAX_NOTES];
+
+
+    /**
+     * Committed flag.
+     */
+    protected boolean commited = false;
+
+
+    /**
+     * Action hook.
+     */
+    public ActionHook hook;
+
+
+    /**
+     * HTTP specific fields.
+     */
+    protected String contentType = null;
+    protected String contentLanguage = null;
+    protected String characterEncoding = Constants.DEFAULT_CHARACTER_ENCODING;
+    protected long contentLength = -1;
+    private Locale locale = DEFAULT_LOCALE;
+
+    // General informations
+    private long bytesWritten=0;
+
+    /**
+     * Holds request error exception.
+     */
+    protected Exception errorException = null;
+
+    /**
+     * Has the charset been explicitly set.
+     */
+    protected boolean charsetSet = false;
+
+    /**
+     * Request error URI.
+     */
+    protected String errorURI = null;
+
+    protected Request req;
+
+    // ------------------------------------------------------------- Properties
+
+    public Request getRequest() {
+        return req;
+    }
+
+    public void setRequest( Request req ) {
+        this.req=req;
+    }
+
+    public OutputBuffer getOutputBuffer() {
+        return outputBuffer;
+    }
+
+
+    public void setOutputBuffer(OutputBuffer outputBuffer) {
+        this.outputBuffer = outputBuffer;
+    }
+
+
+    public MimeHeaders getMimeHeaders() {
+        return headers;
+    }
+
+
+    public ActionHook getHook() {
+        return hook;
+    }
+
+
+    public void setHook(ActionHook hook) {
+        this.hook = hook;
+    }
+
+
+    // -------------------- Per-Response "notes" --------------------
+
+
+    public final void setNote(int pos, Object value) {
+        notes[pos] = value;
+    }
+
+
+    public final Object getNote(int pos) {
+        return notes[pos];
+    }
+
+
+    // -------------------- Actions --------------------
+
+
+    public void action(ActionCode actionCode, Object param) {
+        if (hook != null) {
+            if( param==null ) 
+                hook.action(actionCode, this);
+            else
+                hook.action(actionCode, param);
+        }
+    }
+
+
+    // -------------------- State --------------------
+
+
+    public int getStatus() {
+        return status;
+    }
+
+    
+    /** 
+     * Set the response status 
+     */ 
+    public void setStatus( int status ) {
+        this.status = status;
+    }
+
+
+    /**
+     * Get the status message.
+     */
+    public String getMessage() {
+        return message;
+    }
+
+
+    /**
+     * Set the status message.
+     */
+    public void setMessage(String message) {
+        this.message = message;
+    }
+
+
+    public boolean isCommitted() {
+        return commited;
+    }
+
+
+    public void setCommitted(boolean v) {
+        this.commited = v;
+    }
+
+
+    // -----------------Error State --------------------
+
+
+    /** 
+     * Set the error Exception that occurred during
+     * request processing.
+     */
+    public void setErrorException(Exception ex) {
+    errorException = ex;
+    }
+
+
+    /** 
+     * Get the Exception that occurred during request
+     * processing.
+     */
+    public Exception getErrorException() {
+        return errorException;
+    }
+
+
+    public boolean isExceptionPresent() {
+        return ( errorException != null );
+    }
+
+
+    /** 
+     * Set request URI that caused an error during
+     * request processing.
+     */
+    public void setErrorURI(String uri) {
+        errorURI = uri;
+    }
+
+
+    /** Get the request URI that caused the original error.
+     */
+    public String getErrorURI() {
+        return errorURI;
+    }
+
+
+    // -------------------- Methods --------------------
+    
+    
+    public void reset() 
+        throws IllegalStateException {
+        
+        // Reset the headers only if this is the main request,
+        // not for included
+        contentType = null;
+        locale = DEFAULT_LOCALE;
+        contentLanguage = null;
+        characterEncoding = Constants.DEFAULT_CHARACTER_ENCODING;
+        contentLength = -1;
+        charsetSet = false;
+
+        status = 200;
+        message = null;
+        headers.clear();
+        
+        // Force the PrintWriter to flush its data to the output
+        // stream before resetting the output stream
+        //
+        // Reset the stream
+        if (commited) {
+            //String msg = sm.getString("servletOutputStreamImpl.reset.ise"); 
+            throw new IllegalStateException();
+        }
+        
+        action(ActionCode.ACTION_RESET, this);
+    }
+
+
+    public void finish() throws IOException {
+        action(ActionCode.ACTION_CLOSE, this);
+    }
+
+
+    public void acknowledge() throws IOException {
+        action(ActionCode.ACTION_ACK, this);
+    }
+
+
+    // -------------------- Headers --------------------
+    /**
+     * Warning: This method always returns <code>false<code> for Content-Type
+     * and Content-Length.
+     */
+    public boolean containsHeader(String name) {
+        return headers.getHeader(name) != null;
+    }
+
+
+    public void setHeader(String name, String value) {
+        char cc=name.charAt(0);
+        if( cc=='C' || cc=='c' ) {
+            if( checkSpecialHeader(name, value) )
+            return;
+        }
+        headers.setValue(name).setString( value);
+    }
+
+
+    public void addHeader(String name, String value) {
+        char cc=name.charAt(0);
+        if( cc=='C' || cc=='c' ) {
+            if( checkSpecialHeader(name, value) )
+            return;
+        }
+        headers.addValue(name).setString( value );
+    }
+
+    
+    /** 
+     * Set internal fields for special header names. 
+     * Called from set/addHeader.
+     * Return true if the header is special, no need to set the header.
+     */
+    private boolean checkSpecialHeader( String name, String value) {
+        // XXX Eliminate redundant fields !!!
+        // ( both header and in special fields )
+        if( name.equalsIgnoreCase( "Content-Type" ) ) {
+            setContentType( value );
+            return true;
+        }
+        if( name.equalsIgnoreCase( "Content-Length" ) ) {
+            try {
+                long cL=Long.parseLong( value );
+                setContentLength( cL );
+                return true;
+            } catch( NumberFormatException ex ) {
+                // Do nothing - the spec doesn't have any "throws" 
+                // and the user might know what he's doing
+                return false;
+            }
+        }
+        if( name.equalsIgnoreCase( "Content-Language" ) ) {
+            // XXX XXX Need to construct Locale or something else
+        }
+        return false;
+    }
+
+
+    /** Signal that we're done with the headers, and body will follow.
+     *  Any implementation needs to notify ContextManager, to allow
+     *  interceptors to fix headers.
+     */
+    public void sendHeaders() throws IOException {
+        action(ActionCode.ACTION_COMMIT, this);
+        commited = true;
+    }
+
+
+    // -------------------- I18N --------------------
+
+
+    public Locale getLocale() {
+        return locale;
+    }
+
+    /**
+     * Called explicitely by user to set the Content-Language and
+     * the default encoding
+     */
+    public void setLocale(Locale locale) {
+
+        if (locale == null) {
+            return;  // throw an exception?
+        }
+
+        // Save the locale for use by getLocale()
+        this.locale = locale;
+
+        // Set the contentLanguage for header output
+        contentLanguage = locale.getLanguage();
+        if ((contentLanguage != null) && (contentLanguage.length() > 0)) {
+            String country = locale.getCountry();
+            StringBuffer value = new StringBuffer(contentLanguage);
+            if ((country != null) && (country.length() > 0)) {
+                value.append('-');
+                value.append(country);
+            }
+            contentLanguage = value.toString();
+        }
+
+    }
+
+    /**
+     * Return the content language.
+     */
+    public String getContentLanguage() {
+        return contentLanguage;
+    }
+
+    /*
+     * Overrides the name of the character encoding used in the body
+     * of the response. This method must be called prior to writing output
+     * using getWriter().
+     *
+     * @param charset String containing the name of the chararacter encoding.
+     */
+    public void setCharacterEncoding(String charset) {
+
+        if (isCommitted())
+            return;
+        if (charset == null)
+            return;
+
+        characterEncoding = charset;
+        charsetSet=true;
+    }
+
+    public String getCharacterEncoding() {
+        return characterEncoding;
+    }
+
+    /**
+     * Sets the content type.
+     *
+     * This method must preserve any response charset that may already have 
+     * been set via a call to response.setContentType(), response.setLocale(),
+     * or response.setCharacterEncoding().
+     *
+     * @param type the content type
+     */
+    public void setContentType(String type) {
+
+        int semicolonIndex = -1;
+
+        if (type == null) {
+            this.contentType = null;
+            return;
+        }
+
+        /*
+         * Remove the charset param (if any) from the Content-Type, and use it
+         * to set the response encoding.
+         * The most recent response encoding setting will be appended to the
+         * response's Content-Type (as its charset param) by getContentType();
+         */
+        boolean hasCharset = false;
+        int len = type.length();
+        int index = type.indexOf(';');
+        while (index != -1) {
+            semicolonIndex = index;
+            index++;
+            while (index < len && Character.isSpace(type.charAt(index))) {
+                index++;
+            }
+            if (index+8 < len
+                    && type.charAt(index) == 'c'
+                    && type.charAt(index+1) == 'h'
+                    && type.charAt(index+2) == 'a'
+                    && type.charAt(index+3) == 'r'
+                    && type.charAt(index+4) == 's'
+                    && type.charAt(index+5) == 'e'
+                    && type.charAt(index+6) == 't'
+                    && type.charAt(index+7) == '=') {
+                hasCharset = true;
+                break;
+            }
+            index = type.indexOf(';', index);
+        }
+
+        if (!hasCharset) {
+            this.contentType = type;
+            return;
+        }
+
+        this.contentType = type.substring(0, semicolonIndex);
+        String tail = type.substring(index+8);
+        int nextParam = tail.indexOf(';');
+        String charsetValue = null;
+        if (nextParam != -1) {
+            this.contentType += tail.substring(nextParam);
+            charsetValue = tail.substring(0, nextParam);
+        } else {
+            charsetValue = tail;
+        }
+
+        // The charset value may be quoted, but must not contain any quotes.
+        if (charsetValue != null && charsetValue.length() > 0) {
+            charsetSet=true;
+            charsetValue = charsetValue.replace('"', ' ');
+            this.characterEncoding = charsetValue.trim();
+        }
+    }
+
+    public String getContentType() {
+
+        String ret = contentType;
+
+        if (ret != null 
+            && characterEncoding != null
+            && charsetSet) {
+            ret = ret + ";charset=" + characterEncoding;
+        }
+
+        return ret;
+    }
+    
+    public void setContentLength(int contentLength) {
+        this.contentLength = contentLength;
+    }
+
+    public void setContentLength(long contentLength) {
+        this.contentLength = contentLength;
+    }
+
+    public int getContentLength() {
+        long length = getContentLengthLong();
+        
+        if (length < Integer.MAX_VALUE) {
+            return (int) length;
+        }
+        return -1;
+    }
+    
+    public long getContentLengthLong() {
+        return contentLength;
+    }
+
+
+    /** 
+     * Write a chunk of bytes.
+     */
+    public void doWrite(ByteChunk chunk/*byte buffer[], int pos, int count*/)
+        throws IOException
+    {
+        outputBuffer.doWrite(chunk, this);
+        bytesWritten+=chunk.getLength();
+    }
+
+    // --------------------
+    
+    public void recycle() {
+        
+        contentType = null;
+        contentLanguage = null;
+        locale = DEFAULT_LOCALE;
+        characterEncoding = Constants.DEFAULT_CHARACTER_ENCODING;
+        charsetSet = false;
+        contentLength = -1;
+        status = 200;
+        message = null;
+        commited = false;
+        errorException = null;
+        errorURI = null;
+        headers.clear();
+
+        // update counters
+        bytesWritten=0;
+    }
+
+    public long getBytesWritten() {
+        return bytesWritten;
+    }
+
+    public void setBytesWritten(long bytesWritten) {
+        this.bytesWritten = bytesWritten;
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/java/org/apache/coyote/memory/MemoryProtocolHandler.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/java/org/apache/coyote/memory/MemoryProtocolHandler.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/java/org/apache/coyote/memory/MemoryProtocolHandler.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,166 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.memory;
+
+import java.io.IOException;
+import java.util.Iterator;
+import org.apache.tomcat.util.buf.ByteChunk;
+
+import org.apache.coyote.Adapter;
+import org.apache.coyote.InputBuffer;
+import org.apache.coyote.OutputBuffer;
+import org.apache.coyote.ProtocolHandler;
+import org.apache.coyote.Request;
+import org.apache.coyote.Response;
+
+
+/**
+ * Abstract the protocol implementation, including threading, etc.
+ * Processor is single threaded and specific to stream-based protocols,
+ * will not fit Jk protocols like JNI.
+ *
+ * @author Remy Maucherat
+ */
+public class MemoryProtocolHandler
+    implements ProtocolHandler {
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * Pass config info.
+     */
+    public void setAttribute(String name, Object value) {
+    }
+
+    public Object getAttribute(String name) {
+        return null;
+    }
+
+    public Iterator getAttributeNames() { return null ; }
+    /**
+     * Associated adapter.
+     */
+    protected Adapter adapter = null;
+
+    /**
+     * The adapter, used to call the connector.
+     */
+    public void setAdapter(Adapter adapter) {
+        this.adapter = adapter;
+    }
+
+    public Adapter getAdapter() {
+        return (adapter);
+    }
+
+
+    // ------------------------------------------------ ProtocolHandler Methods
+
+
+    /**
+     * Init the protocol.
+     */
+    public void init()
+        throws Exception {
+    }
+
+
+    /**
+     * Start the protocol.
+     */
+    public void start()
+        throws Exception {
+    }
+
+
+    public void pause() 
+        throws Exception {
+    }
+
+    public void resume() 
+        throws Exception {
+    }
+
+    public void destroy()
+        throws Exception {
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Process specified request.
+     */
+    public void process(Request request, ByteChunk input,
+                        Response response, ByteChunk output)
+        throws Exception {
+
+        InputBuffer inputBuffer = new ByteChunkInputBuffer(input);
+        OutputBuffer outputBuffer = new ByteChunkOutputBuffer(output);
+        request.setInputBuffer(inputBuffer);
+        response.setOutputBuffer(outputBuffer);
+
+        adapter.service(request, response);
+
+    }
+
+
+    // --------------------------------------------- ByteChunkInputBuffer Class
+
+
+    protected class ByteChunkInputBuffer
+        implements InputBuffer {
+
+        protected ByteChunk input = null;
+
+        public ByteChunkInputBuffer(ByteChunk input) {
+            this.input = input;
+        }
+
+        public int doRead(ByteChunk chunk, Request request) 
+            throws IOException {
+            return input.substract(chunk);
+        }
+
+    }
+
+
+    // -------------------------------------------- ByteChunkOuptutBuffer Class
+
+
+    protected class ByteChunkOutputBuffer
+        implements OutputBuffer {
+
+        protected ByteChunk output = null;
+
+        public ByteChunkOutputBuffer(ByteChunk output) {
+            this.output = output;
+        }
+
+        public int doWrite(ByteChunk chunk, Response response) 
+            throws IOException {
+            output.append(chunk);
+            return chunk.getLength();
+        }
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/java/org/apache/coyote/tomcat3/CoyoteInterceptor2.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/java/org/apache/coyote/tomcat3/CoyoteInterceptor2.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/java/org/apache/coyote/tomcat3/CoyoteInterceptor2.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,303 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.tomcat3;
+
+import java.util.Enumeration;
+import java.util.Hashtable;
+
+import org.apache.coyote.ActionCode;
+import org.apache.coyote.ProtocolHandler;
+import org.apache.tomcat.core.BaseInterceptor;
+import org.apache.tomcat.core.Context;
+import org.apache.tomcat.core.ContextManager;
+import org.apache.tomcat.core.TomcatException;
+import org.apache.tomcat.util.IntrospectionUtils;
+import org.apache.tomcat.util.net.SSLSupport;
+
+/** Standalone http.
+ *
+ *  Connector properties:
+ *  <ul>
+ *  <li> secure - will load a SSL socket factory and act as https server</li>
+ *  </ul>
+ *
+ *  Properties passed to the net layer:
+ *  <ul>
+ *  <li>timeout</li>
+ *  <li>backlog</li>
+ *  <li>address</li>
+ *  <li>port</li>
+ *  </ul>
+ * Thread pool properties:
+ *  <ul>
+ *  <li>minSpareThreads</li>
+ *  <li>maxSpareThreads</li>
+ *  <li>maxThreads</li>
+ *  <li>poolOn</li>
+ *  </ul>
+ * Properties for HTTPS:
+ *  <ul>
+ *  <li>keystore - certificates - default to ~/.keystore</li>
+ *  <li>keypass - password</li>
+ *  <li>clientauth - true if the server should authenticate the client using certs</li>
+ *  </ul>
+ * Properties for HTTP:
+ *  <ul>
+ *  <li>reportedname - name of server sent back to browser (security purposes)</li>
+ *  </ul>
+ *  <ul>
+ *  <li>compression - use gzip compression in HTTP 1.1 (on/off) - def off</li>
+ *  </ul>
+ *  <ul>
+ *  <li>compressionMinSize - minimum size content to use gzip compression in HTTP 1.1 - def 2048</li>
+ *  </ul>
+ *  <ul>
+ *  <li>noCompressionUserAgents - comma separated list of userAgents who didn't support gzip</li>
+ *  </ul>
+ *  <ul>
+ *  <li>restrictedUserAgents - comma separated list of userAgents who didn't support HTTP 1.1 (use HTTP 1.0)</li>
+ *  </ul>
+ *  <ul>
+ *  <li>compressableMimeTypes - comma separated list of mime types supported for compression - def text/html,text/xml,text/plain</li>
+ *  </ul>
+ */
+public class CoyoteInterceptor2 extends BaseInterceptor
+{
+    public static final String REDIRECT_PORT_ATTR = 
+	"org.apache.tomcat.request.redirectPort";
+    private String processorClassName="org.apache.coyote.http11.Http11Protocol";
+    Tomcat3Adapter adapter;
+    ProtocolHandler proto;
+    int protocolNote;
+    int redirectPort = -1;
+    
+    public CoyoteInterceptor2() {
+	super();
+	// defaults:
+        this.setAttribute( "port", "8080" );
+        this.setAttribute( "soLinger", "-1" );
+    }
+
+    // -------------------- PoolTcpConnector --------------------
+
+    /** Set the class of the processor to use.
+     */
+    public void setProcessorClassName(String pcn) {
+	processorClassName = pcn;
+    }
+
+    // -------------------- Start/stop --------------------
+    Hashtable attributes=new Hashtable();
+    
+    public void setAttribute( String prop, Object value) {
+	attributes.put( translateAttributeName(prop), value );
+    }
+
+
+    public void setProperty( String prop, String value ) {
+        setAttribute( prop, value );
+    }
+
+    /**
+     * Set the redirect port.
+     */
+    public void setRedirectPort(int rp) {
+	redirectPort = rp;
+	setAttribute("redirectPort", new Integer(rp));
+    }
+
+    /**
+     * Get the redirect port.
+     */
+    public int getRedirectPort() {
+	return redirectPort;
+    }
+
+    /** Called when the ContextManger is started
+     */
+    public void engineInit(ContextManager cm) throws TomcatException {
+	super.engineInit( cm );
+
+        protocolNote = cm.getNoteId(ContextManager.MODULE_NOTE,
+				    "coyote.protocol");
+        adapter=new Tomcat3Adapter(cm, this);
+        try {
+            Class c=Class.forName(processorClassName);
+            proto=(ProtocolHandler)c.newInstance();
+	    setNote(protocolNote, proto);
+        } catch( Exception ex ) {
+            ex.printStackTrace();
+        }
+        
+        this.setAttribute("jkHome", cm.getHome());
+
+        proto.setAdapter( adapter );
+        try {
+            Enumeration keys=attributes.keys();
+            while( keys.hasMoreElements() ) {
+                String k=(String)keys.nextElement();
+                Object o=attributes.get(k);
+                if( o instanceof String )
+                    IntrospectionUtils.setProperty( proto, k, (String)o );
+                else
+                    IntrospectionUtils.setAttribute( proto, k, o );
+            }
+	    proto.init();
+        } catch( Exception ex ) {
+            throw new TomcatException( "Error setting protocol properties ", ex );
+        }
+    }
+
+    /** Called when the ContextManger is started
+     */
+    public void engineStart(ContextManager cm) throws TomcatException {
+	try {
+            proto.start();
+	} catch( Exception ex ) {
+            ex.printStackTrace();
+	    throw new TomcatException( ex );
+	}
+    }
+
+    public void engineShutdown(ContextManager cm) throws TomcatException {
+	try {
+	    proto.destroy();	
+        } catch( Exception ex ) {
+	    throw new TomcatException( ex );
+	}
+    }
+
+    // -------------------- Handler implementation --------------------
+
+    /** Handle HTTP expectations.
+     */
+    public int preService(org.apache.tomcat.core.Request request,
+                          org.apache.tomcat.core.Response response) {
+	if(response instanceof Tomcat3Response) {
+	    try {
+		((Tomcat3Response)response).sendAcknowledgement();
+	    } catch(Exception ex) {
+		log("Can't send ACK", ex);
+	    }
+	}
+	return 0;
+    }
+
+    public int postRequest(org.apache.tomcat.core.Request request,
+                           org.apache.tomcat.core.Response response) {
+	if(request instanceof Tomcat3Request) {
+	    try {
+                Tomcat3Request httpReq=(Tomcat3Request)request;
+                org.apache.coyote.Request cReq = httpReq.getCoyoteRequest();
+                cReq.action( ActionCode.ACTION_POST_REQUEST , null);
+	    } catch(Exception ex) {
+		log("Can't send ACK", ex);
+	    }
+	}
+        return 0;
+    }
+    
+    /**
+       getInfo calls for SSL data
+       
+       @return the requested data
+    */
+    public Object getInfo( Context ctx, org.apache.tomcat.core.Request request,
+                           int id, String key ) {
+        if( ! ( request instanceof Tomcat3Request ) )
+            return null;
+
+        Tomcat3Request httpReq=(Tomcat3Request)request;
+
+        if( httpReq == null || httpReq.getConnector() != this ) {
+	    return null;
+	}
+
+        if(key!=null ){
+            org.apache.coyote.Request cReq = httpReq.getCoyoteRequest();
+            Object info = cReq.getAttribute(key);
+            if( info != null)
+                return info;
+            // XXX Should use MsgContext, pass the attribute we need.
+            // This will extract both 
+            if(isSSLAttribute(key)) {
+                cReq.action(ActionCode.ACTION_REQ_SSL_ATTRIBUTE,
+                            httpReq.getCoyoteRequest() );
+		// Only allowed a single cert under the 2.2 Spec.
+		Object [] value = (Object []) cReq.getAttribute(SSLSupport.CERTIFICATE_KEY);
+		if( value != null ) {
+		    cReq.setAttribute(SSLSupport.CERTIFICATE_KEY, value[0]);
+		}
+		
+                return cReq.getAttribute(key);
+            } else if(key.equals(REDIRECT_PORT_ATTR)) {
+		return new Integer(redirectPort);
+	    }
+
+            return cReq.getAttribute( key );
+        }
+        return super.getInfo(ctx,request,id,key);
+    }
+
+    public int setInfo( Context ctx, org.apache.tomcat.core.Request request,
+                         int id, String key, String object ) {
+        if( ! ( request instanceof Tomcat3Request ) )
+            return DECLINED;
+        
+        Tomcat3Request httpReq=(Tomcat3Request)request;
+        
+        if(key!=null && httpReq!=null ){
+            org.apache.coyote.Request cReq = httpReq.getCoyoteRequest();
+            cReq.setAttribute(key, object);
+	    return OK;
+        }
+	return super.setInfo(ctx, request, id, key, object);
+    }
+
+    /**
+     * Check if a string is a reserved SSL attribute key.
+     */
+    public static boolean isSSLAttribute(String key) {
+	return SSLSupport.CIPHER_SUITE_KEY.equals(key) ||
+	    SSLSupport.KEY_SIZE_KEY.equals(key)        ||
+	    SSLSupport.CERTIFICATE_KEY.equals(key)     ||
+	    SSLSupport.SESSION_ID_KEY.equals(key);
+    }
+
+    private String translateAttributeName(String name) {
+         if ("clientAuth".equals(name)) {
+             return "clientauth";
+         } else if ("keystoreFile".equals(name)) {
+             return "keystore";
+         } else if ("randomFile".equals(name)) {
+             return "randomfile";
+         } else if ("rootFile".equals(name)) {
+             return "rootfile";
+         } else if ("keystorePass".equals(name)) {
+             return "keypass";
+         } else if ("keystoreType".equals(name)) {
+             return "keytype";
+         } else if ("sslProtocol".equals(name)) {
+             return "protocol";
+         } else if ("sslProtocols".equals(name)) {
+             return "protocols";
+         }
+         return name;
+    }
+ 
+}
+

Added: branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/java/org/apache/coyote/tomcat3/Tomcat3Adapter.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/java/org/apache/coyote/tomcat3/Tomcat3Adapter.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/java/org/apache/coyote/tomcat3/Tomcat3Adapter.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,75 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.tomcat3;
+
+import org.apache.coyote.Adapter;
+import org.apache.tomcat.core.ContextManager;
+import org.apache.tomcat.core.BaseInterceptor;
+
+/** Adapter between Coyote and Tomcat.
+ *
+ *  This class handles the task of passing of an individual request to
+ *  Tomcat to handle.  Also some of the connection-specific methods are
+ *  delegated to here.
+ *
+ *  @author Bill Barker
+ */
+public class Tomcat3Adapter implements Adapter {
+    ContextManager cm;
+    BaseInterceptor connector;
+    
+    Tomcat3Adapter(ContextManager ctxman, CoyoteInterceptor2 conn) {
+	cm   = ctxman;
+	connector = conn;
+    }
+
+    static int containerRequestNOTE=1; // XXX Implement a NoteManager, namespaces.
+    
+    /** Pass off an individual request to Tomcat.
+     */
+    public void service(org.apache.coyote.Request request, 
+			org.apache.coyote.Response response) 
+	    throws Exception
+    {
+        Tomcat3Request reqA;
+        Tomcat3Response resA;
+
+        reqA=(Tomcat3Request)request.getNote( containerRequestNOTE );
+        if( reqA==null ) {
+            reqA=new Tomcat3Request();
+            resA=new Tomcat3Response();
+            cm.initRequest( reqA, resA );
+
+            reqA.setCoyoteRequest(request);
+            resA.setCoyoteResponse(response);
+	    reqA.setConnector(connector);
+            request.setNote( containerRequestNOTE, reqA );
+        } else {
+            resA=(Tomcat3Response)reqA.getResponse();
+        }
+        
+        if( reqA.scheme().isNull() ) {
+	    reqA.scheme().setString("http");
+	}
+	try {
+	    cm.service( reqA, resA );
+	} finally {
+	    reqA.recycle();
+	    resA.recycle();
+	}
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/java/org/apache/coyote/tomcat3/Tomcat3Request.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/java/org/apache/coyote/tomcat3/Tomcat3Request.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/java/org/apache/coyote/tomcat3/Tomcat3Request.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,236 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.tomcat3;
+
+import java.io.IOException;
+
+import org.apache.coyote.ActionCode;
+import org.apache.tomcat.util.buf.ByteChunk;
+import org.apache.tomcat.util.buf.MessageBytes;
+import org.apache.tomcat.core.BaseInterceptor;
+
+/** The Request to connect with Coyote.
+ *  This class handles the I/O requirements and transferring the request
+ *  line and Mime headers between Coyote and Tomcat.
+ * 
+ *  @author Bill Barker
+ *  @author Costin Manolache
+ */
+public class Tomcat3Request extends org.apache.tomcat.core.Request {
+
+    org.apache.coyote.Request coyoteRequest=null;
+    BaseInterceptor   connector = null;
+
+    // For SSL attributes we need to call an ActionHook to get
+    // info from the protocol handler.
+    //    SSLSupport sslSupport=null;
+
+    ByteChunk  readChunk = new ByteChunk(8096);
+    int  pos=-1;
+    int  end=-1;
+    byte [] readBuffer = null;
+
+
+    public Tomcat3Request() {
+        super();
+        remoteAddrMB.recycle();
+        remoteHostMB.recycle();
+    }
+
+    public void recycle() {
+	super.recycle();
+	if( coyoteRequest != null) coyoteRequest.recycle();
+
+        remoteAddrMB.recycle();
+        remoteHostMB.recycle();
+	readChunk.recycle();
+
+	readBuffer=null;
+	pos=-1;
+	end=-1;
+    }
+
+    public org.apache.coyote.Request getCoyoteRequest() {
+        return coyoteRequest;
+    }
+    
+    /** Attach the Coyote Request to this Request.
+     *  This is currently set pre-request to allow copying the request
+     *  attributes to the Tomcat attributes.
+     */
+    public void setCoyoteRequest(org.apache.coyote.Request cReq) {
+        coyoteRequest=cReq;
+
+        // The CoyoteRequest/Tomcat3Request are bound togheter, they
+        // don't change. That means we can use the same field ( which
+        // doesn't change as well.
+        schemeMB = coyoteRequest.scheme();
+        methodMB = coyoteRequest.method();
+        uriMB = coyoteRequest.requestURI();
+        queryMB = coyoteRequest.query();
+        protoMB = coyoteRequest.protocol();
+
+	headers  = coyoteRequest.getMimeHeaders();
+	scookies.setHeaders(headers);
+	params.setHeaders(headers);
+        params.setQuery( queryMB );
+        
+        remoteAddrMB = coyoteRequest.remoteAddr();
+	remoteHostMB = coyoteRequest.remoteHost();
+	serverNameMB = coyoteRequest.serverName();
+    }
+
+    /**
+     * Set the Connector that this request services
+     */
+    void setConnector(BaseInterceptor conn) {
+	connector = conn;
+    }
+
+    /**
+     * Get the Connector that this request services
+     */
+    BaseInterceptor getConnector() {
+	return connector;
+    }
+    
+    /** Read a single character from the request body.
+     */
+    public int doRead() throws IOException {
+	if( available == 0 ) 
+	    return -1;
+	// #3745
+	// if available == -1: unknown length, we'll read until end of stream.
+	if( available!= -1 )
+	    available--;
+	if(pos >= end) {
+	    if(readBytes() < 0)
+		return -1;
+	}
+	return readBuffer[pos++] & 0xFF;
+    }
+
+    /** Read a chunk from the request body.
+     */
+    public int doRead(byte[] b, int off, int len) throws IOException {
+	if( available == 0 )
+	    return -1;
+	// if available == -1: unknown length, we'll read until end of stream.
+	if(pos >= end) {
+	    if(readBytes() <= 0) 
+		return -1;
+	}
+	int rd = -1;
+	if((end - pos) > len) {
+	    rd = len;
+	} else {
+	    rd = end - pos;
+	}
+
+        System.arraycopy(readBuffer, pos, b, off, rd);
+	pos += rd;
+	if( available!= -1 )
+	    available -= rd;
+
+	return rd;
+    }
+    
+    /**
+     * Read bytes to the read chunk buffer.
+     */
+    protected int readBytes()
+        throws IOException {
+
+        int result = coyoteRequest.doRead(readChunk);
+        if (result > 0) {
+            readBuffer = readChunk.getBytes();
+            end = readChunk.getEnd();
+            pos = readChunk.getStart();
+        } else if( result < 0 ) {
+            throw new IOException( "Read bytes failed " + result );
+        }
+        return result;
+
+    }
+
+    // -------------------- override special methods
+
+    public MessageBytes remoteAddr() {
+	if( remoteAddrMB.isNull() ) {
+	    coyoteRequest.action( ActionCode.ACTION_REQ_HOST_ADDR_ATTRIBUTE, coyoteRequest );
+	}
+	return remoteAddrMB;
+    }
+
+    public MessageBytes remoteHost() {
+	if( remoteHostMB.isNull() ) {
+	    coyoteRequest.action( ActionCode.ACTION_REQ_HOST_ATTRIBUTE, coyoteRequest );
+	}
+	return remoteHostMB;
+    }
+
+    public String getLocalHost() {
+	return localHost;
+    }
+
+    public MessageBytes serverName(){
+        // That's set by protocol in advance, it's needed for mapping anyway,
+        // no need to do lazy eval.
+        return coyoteRequest.serverName();
+    }
+
+    public int getServerPort(){
+        return coyoteRequest.getServerPort();
+    }
+    
+    public void setServerPort(int i ) {
+	coyoteRequest.setServerPort( i );
+    }
+
+
+    public  void setRemoteUser( String s ) {
+	super.setRemoteUser(s);
+	coyoteRequest.getRemoteUser().setString(s);
+    }
+
+    public String getRemoteUser() {
+	String s=coyoteRequest.getRemoteUser().toString();
+	if( s == null )
+	    s=super.getRemoteUser();
+	return s;
+    }
+
+    public String getAuthType() {
+	return coyoteRequest.getAuthType().toString();
+    }
+    
+    public void setAuthType(String s ) {
+	coyoteRequest.getAuthType().setString(s);
+    }
+
+    public String getJvmRoute() {
+	return coyoteRequest.instanceId().toString();
+    }
+    
+    public void setJvmRoute(String s ) {
+	coyoteRequest.instanceId().setString(s);
+    }
+
+    public boolean isSecure() {
+	return "https".equalsIgnoreCase( coyoteRequest.scheme().toString());
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/java/org/apache/coyote/tomcat3/Tomcat3Response.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/java/org/apache/coyote/tomcat3/Tomcat3Response.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/java/org/apache/coyote/tomcat3/Tomcat3Response.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,152 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.tomcat3;
+
+import java.io.IOException;
+import java.util.Locale;
+
+import org.apache.coyote.ActionCode;
+import org.apache.tomcat.core.Response;
+import org.apache.tomcat.util.buf.ByteChunk;
+
+/** The Response to connect with Coyote.
+ *  This class mostly handles the I/O between Tomcat and Coyte.
+ *  @Author Bill Barker
+ */
+
+class Tomcat3Response extends  Response {
+    String reportedname=null;
+
+    org.apache.coyote.Response coyoteResponse=null;
+
+    ByteChunk outputChunk = new ByteChunk();
+
+    boolean  acknowledged=false;
+    
+    public Tomcat3Response() {
+        super();
+    }
+
+    /** Attach a Coyote Request to this request.
+     */
+    public void setCoyoteResponse(org.apache.coyote.Response cRes) {
+	coyoteResponse = cRes;
+	headers = coyoteResponse.getMimeHeaders();
+    }
+
+    public void init() {
+	super.init();
+    }
+
+    public void recycle() {
+	super.recycle();
+	if(coyoteResponse != null) coyoteResponse.recycle();
+	outputChunk.recycle();
+	acknowledged=false;
+    }
+
+    // XXX What is this ? */
+    public void setReported(String reported) {
+        reportedname = reported;
+    }
+
+    public void endHeaders()  throws IOException {
+	super.endHeaders();
+	coyoteResponse.setStatus(getStatus());
+	// Check that the content-length has been set.
+	int cLen = getContentLength();
+	if( cLen >= 0 ) {
+	    coyoteResponse.setContentLength(cLen);
+	}
+        // Calls a sendHeaders callback to the protocol
+	coyoteResponse.sendHeaders();
+    }
+
+    public void clientFlush() throws IOException {
+        coyoteResponse.action( ActionCode.ACTION_CLIENT_FLUSH, coyoteResponse );
+    }
+    
+    public void doWrite( byte buffer[], int pos, int count)
+	throws IOException
+    {
+	if( count > 0 ) {
+            // XXX should be an explicit callback as well.
+	    outputChunk.setBytes(buffer, pos, count);
+	    coyoteResponse.doWrite( outputChunk );
+	}
+    }
+
+    public void reset() throws IllegalStateException {
+	super.reset();
+	if( ! included )
+	    coyoteResponse.reset();
+    }
+    
+    public void finish() throws IOException {
+	super.finish();
+	coyoteResponse.finish();
+    }
+
+    /**
+     * Send an acknowledgment of a request.
+     * 
+     * @exception IOException if an input/output error occurs
+     */
+    public void sendAcknowledgement()
+        throws IOException {
+
+	if( status >= 300 ) // Don't ACK on errors.
+	    acknowledged = true;
+        // Don't ACK twice on the same request. (e.g. on a forward)
+	if(acknowledged)
+	    return;
+        // Ignore any call from an included servlet
+        if (isIncluded())
+            return; 
+        if (isBufferCommitted())
+            throw new IllegalStateException
+                (sm.getString("hsrf.error.ise"));
+
+	coyoteResponse.acknowledge();
+	acknowledged=true;
+    }
+
+    public void setLocale(Locale locale) {
+        if (locale == null || included) {
+            return;  // throw an exception?
+        }
+        this.locale = locale;
+        coyoteResponse.setLocale(locale);
+        contentLanguage = coyoteResponse.getContentLanguage();
+        // maintain Tomcat 3.3 behavior by setting the header too
+        // and by not trying to guess the characterEncoding
+        headers.setValue("Content-Language").setString(contentLanguage);
+    }
+
+    public void setContentType(String contentType) {
+        if (included) {
+            return;
+        }
+        coyoteResponse.setContentType(contentType);
+        this.contentType = coyoteResponse.getContentType();
+        this.characterEncoding = coyoteResponse.getCharacterEncoding();
+        this.haveCharacterEncoding = true;
+        // maintain Tomcat 3.3 behavior by setting the header too
+        headers.setValue("Content-Type").setString(contentType);
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/java/org/apache/coyote/tomcat4/Constants.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/java/org/apache/coyote/tomcat4/Constants.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/java/org/apache/coyote/tomcat4/Constants.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,50 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.tomcat4;
+
+
+/**
+ * Constants.
+ *
+ * @author Remy Maucherat
+ */
+public final class Constants {
+
+
+    // -------------------------------------------------------------- Constants
+
+
+    public static final String Package = "org.apache.coyote.tomcat4";
+    public static final int DEFAULT_CONNECTION_LINGER = -1;
+    public static final int DEFAULT_CONNECTION_TIMEOUT = 60000;
+    public static final int DEFAULT_CONNECTION_UPLOAD_TIMEOUT = 300000;
+    public static final int DEFAULT_SERVER_SOCKET_TIMEOUT = 0;
+
+    public static final int PROCESSOR_IDLE = 0;
+    public static final int PROCESSOR_ACTIVE = 1;
+
+    /**
+     * Default header names.
+     */
+    public static final String AUTHORIZATION_HEADER = "authorization";
+
+    /**
+     * SSL Certificate Request Attributite.
+     */
+    public static final String SSL_CERTIFICATE_ATTR = "org.apache.coyote.request.X509Certificate";
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/java/org/apache/coyote/tomcat4/CoyoteAdapter.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/java/org/apache/coyote/tomcat4/CoyoteAdapter.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/java/org/apache/coyote/tomcat4/CoyoteAdapter.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,687 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.tomcat4;
+
+
+import java.io.IOException;
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletRequest;
+
+import org.apache.tomcat.util.buf.B2CConverter;
+import org.apache.tomcat.util.buf.ByteChunk;
+import org.apache.tomcat.util.buf.CharChunk;
+import org.apache.tomcat.util.buf.MessageBytes;
+import org.apache.tomcat.util.http.Cookies;
+import org.apache.tomcat.util.http.ServerCookie;
+
+import org.apache.coyote.ActionCode;
+import org.apache.coyote.Adapter;
+import org.apache.coyote.Request;
+import org.apache.coyote.Response;
+
+import org.apache.catalina.Globals;
+import org.apache.catalina.Logger;
+import org.apache.catalina.util.StringManager;
+
+
+/**
+ * Implementation of a request processor which delegates the processing to a
+ * Coyote processor.
+ *
+ * @author Craig R. McClanahan
+ * @author Remy Maucherat
+ * @version $Revision: 299381 $ $Date: 2004-04-04 14:09:38 -0500 (Sun, 04 Apr 2004) $
+ */
+
+final class CoyoteAdapter
+    implements Adapter {
+
+
+    // -------------------------------------------------------------- Constants
+
+
+    public static final int ADAPTER_NOTES = 1;
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Construct a new CoyoteProcessor associated with the specified connector.
+     *
+     * @param connector CoyoteConnector that owns this processor
+     * @param id Identifier of this CoyoteProcessor (unique per connector)
+     */
+    public CoyoteAdapter(CoyoteConnector connector) {
+
+        super();
+        this.connector = connector;
+        this.debug = connector.getDebug();
+
+    }
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The CoyoteConnector with which this processor is associated.
+     */
+    private CoyoteConnector connector = null;
+
+
+    /**
+     * The debugging detail level for this component.
+     */
+    private int debug = 0;
+
+
+    /**
+     * The match string for identifying a session ID parameter.
+     */
+    private static final String match =
+        ";" + Globals.SESSION_PARAMETER_NAME + "=";
+
+
+    /**
+     * The match string for identifying a session ID parameter.
+     */
+    private static final char[] SESSION_ID = match.toCharArray();
+
+
+    /**
+     * The string manager for this package.
+     */
+    protected StringManager sm =
+        StringManager.getManager(Constants.Package);
+
+
+    // -------------------------------------------------------- Adapter Methods
+
+
+    /**
+     * Service method.
+     */
+    public void service(Request req, Response res)
+        throws Exception {
+
+        CoyoteRequest request = (CoyoteRequest) req.getNote(ADAPTER_NOTES);
+        CoyoteResponse response = (CoyoteResponse) res.getNote(ADAPTER_NOTES);
+
+        if (request == null) {
+
+            // Create objects
+            request = (CoyoteRequest) connector.createRequest();
+            request.setCoyoteRequest(req);
+            response = (CoyoteResponse) connector.createResponse();
+            response.setCoyoteResponse(res);
+
+            // Link objects
+            request.setResponse(response);
+            response.setRequest(request);
+
+            // Set as notes
+            req.setNote(ADAPTER_NOTES, request);
+            res.setNote(ADAPTER_NOTES, response);
+
+            // Set query string encoding
+            req.getParameters().setQueryStringEncoding
+                (connector.getURIEncoding());
+
+        }
+
+        try {
+            // Parse and set Catalina and configuration specific 
+            // request parameters
+            postParseRequest(req, request, res, response);
+            // Calling the container
+            connector.getContainer().invoke(request, response);
+            response.finishResponse();
+
+            req.action( ActionCode.ACTION_POST_REQUEST , null);
+        } catch (IOException e) {
+            ;
+        } catch (Throwable t) {
+            log(sm.getString("coyoteAdapter.service"), t);
+        } finally {
+            // Recycle the wrapper request and response
+            request.recycle();
+            response.recycle();
+        }
+
+    }
+
+
+    // ------------------------------------------------------ Protected Methods
+
+
+    /**
+     * Parse additional request parameters.
+     */
+    protected void postParseRequest(Request req, CoyoteRequest request,
+                                    Response res, CoyoteResponse response)
+        throws Exception {
+        // XXX the processor needs to set a correct scheme and port prior to this point, 
+        // in ajp13 protocols dont make sense to get the port from the connector..
+        // XXX the processor may have set a correct scheme and port prior to this point, 
+        // in ajp13 protocols dont make sense to get the port from the connector...
+        // otherwise, use connector configuration
+        if (! req.scheme().isNull()) {
+            // use processor specified scheme to determine secure state
+            request.setSecure(req.scheme().equals("https"));
+        } else {
+            // use connector scheme and secure configuration, (defaults to
+            // "http" and false respectively)
+            req.scheme().setString(connector.getScheme());
+            request.setSecure(connector.getSecure());
+        }
+ 
+        // Filter trace method
+        if (!connector.getAllowTrace() 
+            && req.method().equalsIgnoreCase("TRACE")) {
+            res.setStatus(403);
+            res.setMessage("TRACE method is not allowed");
+            throw new IOException("TRACE method is not allowed");
+        }
+
+        request.setAuthorization
+            (req.getHeader(Constants.AUTHORIZATION_HEADER));
+        // FIXME: the code below doesnt belongs to here, this is only  have sense 
+        // in Http11, not in ajp13..
+        // At this point the Host header has been processed.
+        // Override if the proxyPort/proxyHost are set 
+        String proxyName = connector.getProxyName();
+        int proxyPort = connector.getProxyPort();
+        if (proxyPort != 0) {
+            request.setServerPort(proxyPort);
+            req.setServerPort(proxyPort);
+        } else {
+            request.setServerPort(req.getServerPort());
+        }
+        if (proxyName != null) {
+            request.setServerName(proxyName);
+            req.serverName().setString(proxyName);
+        } else {
+            request.setServerName(req.serverName().toString());
+        }
+
+        // URI decoding
+        req.decodedURI().duplicate(req.requestURI());
+        try {
+          req.getURLDecoder().convert(req.decodedURI(), false);
+        } catch (IOException ioe) {
+            res.setStatus(400);
+            res.setMessage("Invalid URI");
+            throw ioe;
+        }
+
+        // Normalize decoded URI
+        if (!normalize(req.decodedURI())) {
+            res.setStatus(400);
+            res.setMessage("Invalid URI");
+            throw new IOException("Invalid URI");
+        }
+
+        // URI character decoding
+        convertURI(req.decodedURI(), request);
+
+        // Parse session Id
+        parseSessionId(req, request);
+
+        // Additional URI normalization and validation is needed for security 
+        // reasons on Tomcat 4.0.x
+        if (connector.getUseURIValidationHack()) {
+            String uri = validate(request.getRequestURI());
+            if (uri == null) {
+                res.setStatus(400);
+                res.setMessage("Invalid URI");
+                throw new IOException("Invalid URI");
+            } else {
+                req.requestURI().setString(uri);
+                // Redoing the URI decoding
+                req.decodedURI().duplicate(req.requestURI());
+                req.getURLDecoder().convert(req.decodedURI(), true);
+                convertURI(req.decodedURI(), request);
+            }
+        }
+
+        // Parse cookies
+        parseCookies(req, request);
+
+        // Set the SSL properties
+        if( request.isSecure() ) {
+            res.action(ActionCode.ACTION_REQ_SSL_ATTRIBUTE,
+                       request.getCoyoteRequest());
+            //Set up for getAttributeNames
+            request.getAttribute(Globals.CERTIFICATES_ATTR);
+            request.getAttribute(Globals.CIPHER_SUITE_ATTR);
+            request.getAttribute(Globals.KEY_SIZE_ATTR);
+        }
+
+        // Set the remote principal
+        String principal = req.getRemoteUser().toString();
+        if (principal != null) {
+            request.setUserPrincipal(new CoyotePrincipal(principal));
+        }
+
+        // Set the authorization type
+        String authtype = req.getAuthType().toString();
+        if (authtype != null) {
+            request.setAuthType(authtype);
+        }
+
+    }
+
+    /**
+     * Parse session id in URL.
+     * FIXME: Optimize this.
+     */
+    protected void parseSessionId(Request req, CoyoteRequest request) {
+
+        req.decodedURI().toChars();
+        CharChunk uriCC = req.decodedURI().getCharChunk();
+        int semicolon = uriCC.indexOf(match, 0, match.length(), 0);
+
+        if (semicolon > 0) {
+
+            // Parse session ID, and extract it from the decoded request URI
+            int start = uriCC.getStart();
+            int end = uriCC.getEnd();
+
+            int sessionIdStart = start + semicolon + match.length();
+            int semicolon2 = uriCC.indexOf(';', sessionIdStart);
+            if (semicolon2 >= 0) {
+                request.setRequestedSessionId
+                    (new String(uriCC.getBuffer(), sessionIdStart, 
+                                semicolon2 - semicolon - match.length()));
+                req.decodedURI().setString
+                    (new String(uriCC.getBuffer(), start, semicolon) + 
+                            new String(uriCC.getBuffer(),
+                                        semicolon2,
+                                        end-semicolon2));
+            } else {
+                request.setRequestedSessionId
+                    (new String(uriCC.getBuffer(), sessionIdStart, 
+                                end - sessionIdStart));
+                req.decodedURI().setString
+                    (new String(uriCC.getBuffer(), start, semicolon));
+            }
+            request.setRequestedSessionURL(true);
+
+            // Extract session ID from request URI
+            String uri = req.requestURI().toString();
+            semicolon = uri.indexOf(match);
+
+            if (semicolon > 0) {
+                String rest = uri.substring(semicolon + match.length());
+                semicolon2 = rest.indexOf(';');
+                if (semicolon2 >= 0) {
+                    rest = rest.substring(semicolon2);
+                } else {
+                    rest = "";
+                }
+                req.requestURI().setString(uri.substring(0, semicolon) + rest);
+            }
+
+        } else {
+            request.setRequestedSessionId(null);
+            request.setRequestedSessionURL(false);
+        }
+
+    }
+
+
+    /**
+     * Parse cookies.
+     */
+    protected void parseCookies(Request req, CoyoteRequest request) {
+
+        Cookies serverCookies = req.getCookies();
+        int count = serverCookies.getCookieCount();
+        if (count <= 0)
+            return;
+
+        Cookie[] cookies = new Cookie[count];
+
+        int idx=0;
+        for (int i = 0; i < count; i++) {
+            ServerCookie scookie = serverCookies.getCookie(i);
+            if (scookie.getName().equals(Globals.SESSION_COOKIE_NAME)) {
+                // Override anything requested in the URL
+                if (!request.isRequestedSessionIdFromCookie()) {
+                    // Accept only the first session id cookie
+                    request.setRequestedSessionId
+                        (scookie.getValue().toString());
+                    request.setRequestedSessionCookie(true);
+                    request.setRequestedSessionURL(false);
+                    if (debug >= 1)
+                        log(" Requested cookie session id is " +
+                            ((HttpServletRequest) request.getRequest())
+                            .getRequestedSessionId());
+                }
+            }
+            try {
+                Cookie cookie = new Cookie(scookie.getName().toString(),
+                                           scookie.getValue().toString());
+                cookie.setPath(scookie.getPath().toString());
+                cookie.setVersion(scookie.getVersion());
+                String domain = scookie.getDomain().toString();
+                if (domain != null) {
+                    cookie.setDomain(scookie.getDomain().toString());
+                }
+                cookies[idx++] = cookie;
+            } catch(Exception ex) {
+                log("Bad Cookie Name: " + scookie.getName() + 
+                    " /Value: " + scookie.getValue(),ex);
+            }
+        }
+        if( idx < count ) {
+            Cookie [] ncookies = new Cookie[idx];
+            System.arraycopy(cookies, 0, ncookies, 0, idx);
+            cookies = ncookies;
+        }
+
+        request.setCookies(cookies);
+
+    }
+
+
+    /**
+     * Return a context-relative path, beginning with a "/", that represents
+     * the canonical version of the specified path after ".." and "." elements
+     * are resolved out.  If the specified path attempts to go outside the
+     * boundaries of the current context (i.e. too many ".." path elements
+     * are present), return <code>null</code> instead.
+     * This code is not optimized, and is only needed for Tomcat 4.0.x.
+     *
+     * @param path Path to be validated
+     */
+    protected static String validate(String path) {
+
+        if (path == null)
+            return null;
+
+        // Create a place for the normalized path
+        String normalized = path;
+
+        // Normalize "/%7E" and "/%7e" at the beginning to "/~"
+        if (normalized.startsWith("/%7E") ||
+            normalized.startsWith("/%7e"))
+            normalized = "/~" + normalized.substring(4);
+
+        // Prevent encoding '%', '/', '.' and '\', which are special reserved
+        // characters
+        if ((normalized.indexOf("%25") >= 0)
+            || (normalized.indexOf("%2F") >= 0)
+            || (normalized.indexOf("%2E") >= 0)
+            || (normalized.indexOf("%5C") >= 0)
+            || (normalized.indexOf("%2f") >= 0)
+            || (normalized.indexOf("%2e") >= 0)
+            || (normalized.indexOf("%5c") >= 0)) {
+            return null;
+        }
+
+        if (normalized.equals("/."))
+            return "/";
+
+        // Normalize the slashes and add leading slash if necessary
+        if (normalized.indexOf('\\') >= 0)
+            normalized = normalized.replace('\\', '/');
+        if (!normalized.startsWith("/"))
+            normalized = "/" + normalized;
+
+        // Resolve occurrences of "//" in the normalized path
+        while (true) {
+            int index = normalized.indexOf("//");
+            if (index < 0)
+                break;
+            normalized = normalized.substring(0, index) +
+                normalized.substring(index + 1);
+        }
+
+        // Resolve occurrences of "/./" in the normalized path
+        while (true) {
+            int index = normalized.indexOf("/./");
+            if (index < 0)
+                break;
+            normalized = normalized.substring(0, index) +
+                normalized.substring(index + 2);
+        }
+
+        // Resolve occurrences of "/../" in the normalized path
+        while (true) {
+            int index = normalized.indexOf("/../");
+            if (index < 0)
+                break;
+            if (index == 0)
+                return (null);  // Trying to go outside our context
+            int index2 = normalized.lastIndexOf('/', index - 1);
+            normalized = normalized.substring(0, index2) +
+                normalized.substring(index + 3);
+        }
+
+        // Declare occurrences of "/..." (three or more dots) to be invalid
+        // (on some Windows platforms this walks the directory tree!!!)
+        if (normalized.indexOf("/...") >= 0)
+            return (null);
+
+        // Return the normalized path that we have completed
+        return (normalized);
+
+    }
+
+
+    /**
+     * Character conversion of the URI.
+     */
+    protected void convertURI(MessageBytes uri, CoyoteRequest request) 
+        throws Exception {
+
+        ByteChunk bc = uri.getByteChunk();
+        CharChunk cc = uri.getCharChunk();
+        cc.allocate(bc.getLength(), -1);
+
+        String enc = connector.getURIEncoding();
+        if (enc != null) {
+            B2CConverter conv = request.getURIConverter();
+            try {
+                if (conv == null) {
+                    conv = new B2CConverter(enc);
+                    request.setURIConverter(conv);
+                } else {
+                    conv.recycle();
+                }
+            } catch (IOException e) {
+                // Ignore
+                log("Invalid URI encoding; using HTTP default", e);
+                connector.setURIEncoding(null);
+            }
+            if (conv != null) {
+                try {
+                    conv.convert(bc, cc);
+                    uri.setChars(cc.getBuffer(), cc.getStart(), 
+                                 cc.getLength());
+                    return;
+                } catch (IOException e) {
+                    if (debug >= 1) {
+                        log("Invalid URI character encoding; trying ascii", e);
+                    }
+                    cc.recycle();
+                }
+            }
+        }
+
+        // Default encoding: fast conversion
+        byte[] bbuf = bc.getBuffer();
+        char[] cbuf = cc.getBuffer();
+        int start = bc.getStart();
+        for (int i = 0; i < bc.getLength(); i++) {
+            cbuf[i] = (char) (bbuf[i + start] & 0xff);
+        }
+        uri.setChars(cbuf, 0, bc.getLength());
+
+    }
+
+
+    /**
+     * Normalize URI.
+     * <p>
+     * This method normalizes "\", "//", "/./" and "/../". This method will
+     * return false when trying to go above the root, or if the URI contains
+     * a null byte.
+     * 
+     * @param uriMB URI to be normalized
+     */
+    public static boolean normalize(MessageBytes uriMB) {
+
+        ByteChunk uriBC = uriMB.getByteChunk();
+        byte[] b = uriBC.getBytes();
+        int start = uriBC.getStart();
+        int end = uriBC.getEnd();
+
+        // URL * is acceptable
+        if ((end - start == 1) && b[start] == (byte) '*')
+          return true;
+
+        int pos = 0;
+        int index = 0;
+
+        // Replace '\' with '/'
+        // Check for null byte
+        for (pos = start; pos < end; pos++) {
+            if (b[pos] == (byte) '\\')
+                b[pos] = (byte) '/';
+            if (b[pos] == (byte) 0)
+                return false;
+        }
+
+        // The URL must start with '/'
+        if (b[start] != (byte) '/') {
+            return false;
+        }
+
+        // Replace "//" with "/"
+        for (pos = start; pos < (end - 1); pos++) {
+            if (b[pos] == (byte) '/') {
+                while ((pos + 1 < end) && (b[pos + 1] == (byte) '/')) {
+                    copyBytes(b, pos, pos + 1, end - pos - 1);
+                    end--;
+                }
+            }
+        }
+
+        // If the URI ends with "/." or "/..", then we append an extra "/"
+        // Note: It is possible to extend the URI by 1 without any side effect
+        // as the next character is a non-significant WS.
+        if (((end - start) > 2) && (b[end - 1] == (byte) '.')) {
+            if ((b[end - 2] == (byte) '/') 
+                || ((b[end - 2] == (byte) '.') 
+                    && (b[end - 3] == (byte) '/'))) {
+                b[end] = (byte) '/';
+                end++;
+            }
+        }
+
+        uriBC.setEnd(end);
+
+        index = 0;
+
+        // Resolve occurrences of "/./" in the normalized path
+        while (true) {
+            index = uriBC.indexOf("/./", 0, 3, index);
+            if (index < 0)
+                break;
+            copyBytes(b, start + index, start + index + 2, 
+                      end - start - index - 2);
+            end = end - 2;
+            uriBC.setEnd(end);
+        }
+
+        index = 0;
+
+        // Resolve occurrences of "/../" in the normalized path
+        while (true) {
+            index = uriBC.indexOf("/../", 0, 4, index);
+            if (index < 0)
+                break;
+            // Prevent from going outside our context
+            if (index == 0)
+                return false;
+            int index2 = -1;
+            for (pos = start + index - 1; (pos >= 0) && (index2 < 0); pos --) {
+                if (b[pos] == (byte) '/') {
+                    index2 = pos;
+                }
+            }
+            copyBytes(b, start + index2, start + index + 3,
+                      end - start - index - 3);
+            end = end + index2 - index - 3;
+            uriBC.setEnd(end);
+            index = index2;
+        }
+
+        uriBC.setBytes(b, start, end);
+
+        return true;
+
+    }
+
+
+    // ------------------------------------------------------ Protected Methods
+
+
+    /**
+     * Copy an array of bytes to a different position. Used during 
+     * normalization.
+     */
+    protected static void copyBytes(byte[] b, int dest, int src, int len) {
+        for (int pos = 0; pos < len; pos++) {
+            b[pos + dest] = b[pos + src];
+        }
+    }
+
+
+    /**
+     * Log a message on the Logger associated with our Container (if any)
+     *
+     * @param message Message to be logged
+     */
+    protected void log(String message) {
+
+        Logger logger = connector.getContainer().getLogger();
+        if (logger != null)
+            logger.log("CoyoteAdapter " + message);
+
+    }
+
+
+    /**
+     * Log a message on the Logger associated with our Container (if any)
+     *
+     * @param message Message to be logged
+     * @param throwable Associated exception
+     */
+    protected void log(String message, Throwable throwable) {
+
+        Logger logger = connector.getContainer().getLogger();
+        if (logger != null)
+            logger.log("CoyoteAdapter " + message, throwable);
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/java/org/apache/coyote/tomcat4/CoyoteConnector.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/java/org/apache/coyote/tomcat4/CoyoteConnector.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/java/org/apache/coyote/tomcat4/CoyoteConnector.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,1425 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.tomcat4;
+
+
+import java.net.URLEncoder;
+import java.util.HashMap;
+
+import org.apache.tomcat.util.IntrospectionUtils;
+
+import org.apache.coyote.Adapter;
+import org.apache.coyote.ProtocolHandler;
+
+import org.apache.catalina.Connector;
+import org.apache.catalina.Container;
+import org.apache.catalina.Lifecycle;
+import org.apache.catalina.LifecycleException;
+import org.apache.catalina.LifecycleListener;
+import org.apache.catalina.Logger;
+import org.apache.catalina.Request;
+import org.apache.catalina.Response;
+import org.apache.catalina.Service;
+import org.apache.catalina.core.StandardEngine;
+import org.apache.catalina.net.DefaultServerSocketFactory;
+import org.apache.catalina.net.ServerSocketFactory;
+import org.apache.catalina.util.LifecycleSupport;
+import org.apache.catalina.util.StringManager;
+import org.apache.commons.modeler.Registry;
+
+import javax.management.MBeanRegistration;
+import javax.management.MalformedObjectNameException;
+import javax.management.ObjectName;
+import javax.management.MBeanServer;
+
+
+/**
+ * Implementation of a Coyote connector for Tomcat 4.x.
+ *
+ * @author Craig R. McClanahan
+ * @author Remy Maucherat
+ * @version $Revision: 395417 $ $Date: 2006-04-19 17:47:14 -0500 (Wed, 19 Apr 2006) $
+ */
+
+public final class CoyoteConnector
+    implements Connector, Lifecycle, MBeanRegistration {
+
+
+    // ------------------------------------------------------------ Constructor
+    
+    public CoyoteConnector() throws Exception {
+        this(null);
+    }
+    
+    public CoyoteConnector(String protocolHandlerClassName) throws Exception {
+        
+        if (protocolHandlerClassName != null) {
+            setProtocolHandlerClassName(protocolHandlerClassName);
+        }
+        
+        // Instantiate protocol handler
+        try {
+            Class clazz = Class.forName(this.protocolHandlerClassName);
+            protocolHandler = (ProtocolHandler) clazz.newInstance();
+        } catch (Exception e) {
+            e.printStackTrace();
+            throw new LifecycleException(sm.getString(
+                    "coyoteConnector.protocolHandlerInstantiationFailed", e));
+        }
+
+    }
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The <code>Service</code> we are associated with (if any).
+     */
+    private Service service = null;
+
+
+    /**
+     * The accept count for this Connector.
+     */
+    private int acceptCount = 10;
+
+
+    /**
+     * The IP address on which to bind, if any.  If <code>null</code>, all
+     * addresses on the server will be bound.
+     */
+    private String address = null;
+
+
+    /**
+     * Do we allow TRACE ?
+     */
+    private boolean allowTrace = false;
+
+
+    /**
+     * The input buffer size we should create on input streams.
+     */
+    private int bufferSize = 2048;
+
+
+    /**
+     * The Container used for processing requests received by this Connector.
+     */
+    protected Container container = null;
+
+
+    /**
+     * The current number of processors that have been created.
+     */
+    private int curProcessors = 0;
+
+
+    /**
+     * The debugging detail level for this component.
+     */
+    private int debug = 0;
+
+
+    /**
+     * The "enable DNS lookups" flag for this Connector.
+     */
+    private boolean enableLookups = false;
+
+
+    /**
+     * The server socket factory for this component.
+     */
+    private ServerSocketFactory factory = null;
+
+
+    /**
+     * Descriptive information about this Connector implementation.
+     */
+    private static final String info =
+        "org.apache.coyote.tomcat4.CoyoteConnector2/1.0";
+
+
+    /**
+     * The lifecycle event support for this component.
+     */
+    protected LifecycleSupport lifecycle = new LifecycleSupport(this);
+
+
+    /**
+     * The minimum number of idle processors to have available. This is also
+     * the number of processors that are started at initialization.
+     */
+    protected int minProcessors = 4;
+
+
+    /**
+     * The maximum amount of spare processors.
+     */
+    protected int maxSpareProcessors = 50;
+
+
+    /**
+     * The maximum number of processors allowed, or <0 for unlimited.
+     */
+    private int maxProcessors = 200;
+
+    /**
+     * The maximum permitted size of the request and response HTTP headers.
+     */
+    private int maxHttpHeaderSize = 4 * 1024;
+
+    /**
+     * Linger value on the incoming connection.
+     * Note : a value inferior to 0 means no linger.
+     */
+    private int connectionLinger = Constants.DEFAULT_CONNECTION_LINGER;
+
+
+    /**
+     * Timeout value on the incoming connection.
+     * Note : a value of 0 means no timeout.
+     */
+    private int connectionTimeout = Constants.DEFAULT_CONNECTION_TIMEOUT;
+
+
+    /**
+     * Timeout value on the incoming connection during request processing.
+     * Note : a value of 0 means no timeout.
+     */
+    private int connectionUploadTimeout = 
+        Constants.DEFAULT_CONNECTION_UPLOAD_TIMEOUT;
+
+
+    /**
+     * Timeout value on the server socket.
+     * Note : a value of 0 means no timeout.
+     */
+    private int serverSocketTimeout = Constants.DEFAULT_SERVER_SOCKET_TIMEOUT;
+
+
+    /**
+     * The port number on which we listen for requests.
+     */
+    private int port = 8080;
+
+
+    /**
+     * The server name to which we should pretend requests to this Connector
+     * were directed.  This is useful when operating Tomcat behind a proxy
+     * server, so that redirects get constructed accurately.  If not specified,
+     * the server name included in the <code>Host</code> header is used.
+     */
+    private String proxyName = null;
+
+
+    /**
+     * The server port to which we should pretent requests to this Connector
+     * were directed.  This is useful when operating Tomcat behind a proxy
+     * server, so that redirects get constructed accurately.  If not specified,
+     * the port number specified by the <code>port</code> property is used.
+     */
+    private int proxyPort = 0;
+
+
+    /**
+     * The redirect port for non-SSL to SSL redirects.
+     */
+    private int redirectPort = 443;
+
+
+    /**
+     * The request scheme that will be set on all requests received
+     * through this connector.
+     */
+    private String scheme = "http";
+
+
+    /**
+     * The secure connection flag that will be set on all requests received
+     * through this connector.
+     */
+    private boolean secure = false;
+
+    /** For jk, do tomcat authentication if true, trust server if false 
+     */ 
+    private boolean tomcatAuthentication = true;
+
+    /**
+     * The string manager for this package.
+     */
+    private StringManager sm =
+        StringManager.getManager(Constants.Package);
+
+
+    /**
+     * Has this component been initialized yet?
+     */
+    private boolean initialized = false;
+
+
+    /**
+     * Has this component been started yet?
+     */
+    private boolean started = false;
+
+
+    /**
+     * Use TCP no delay ?
+     */
+    private boolean tcpNoDelay = true;
+
+
+    /**
+     * Flag to disable setting a seperate time-out for uploads.
+     * If <code>true</code>, then the <code>timeout</code> parameter is
+     * ignored.  If <code>false</code>, then the <code>timeout</code>
+     * parameter is used to control uploads.
+     */
+    private boolean disableUploadTimeout = false;
+
+    /**
+     * Maximum number of Keep-Alive requests to honor per connection.
+     */
+    private int maxKeepAliveRequests = 100;
+
+
+    /**
+     * Compression value.
+     */
+    private String compressableMimeTypes = "text/html,text/xml,text/plain";
+    private String compression = "off";
+
+
+    /**
+     * Coyote Protocol handler class name.
+     * Defaults to the Coyote HTTP/1.1 protocolHandler.
+     */
+    private String protocolHandlerClassName =
+        "org.apache.coyote.http11.Http11Protocol";
+
+
+    /**
+     * Use URI validation for Tomcat 4.0.x.
+     */
+    private boolean useURIValidationHack = true;
+
+
+    /**
+     * Coyote protocol handler.
+     */
+    private ProtocolHandler protocolHandler = null;
+
+
+    /**
+     * Coyote adapter.
+     */
+    private Adapter adapter = null;
+
+
+     /**
+      * URI encoding.
+      */
+     private String URIEncoding = null;
+
+
+     /**
+      * URI encoding as body.
+      */
+     private boolean useBodyEncodingForURI = true;
+
+
+     protected static HashMap replacements = new HashMap();
+     static {
+         replacements.put("maxProcessors", "maxThreads");
+         replacements.put("minProcessors", "minSpareThreads");
+         replacements.put("maxSpareProcessors", "maxSpareThreads");
+         replacements.put("acceptCount", "backlog");
+         replacements.put("connectionLinger", "soLinger");
+         replacements.put("connectionTimeout", "soTimeout");
+         replacements.put("connectionUploadTimeout", "timeout");
+         replacements.put("serverSocketTimeout", "serverSoTimeout");
+         replacements.put("clientAuth", "clientauth");
+         replacements.put("keystoreFile", "keystore");
+         replacements.put("randomFile", "randomfile");
+         replacements.put("rootFile", "rootfile");
+         replacements.put("keystorePass", "keypass");
+         replacements.put("keystoreType", "keytype");
+         replacements.put("sslProtocol", "protocol");
+         replacements.put("sslProtocols", "protocols");
+     }
+
+     
+     // ------------------------------------------------------------- Properties
+
+
+     /**
+      * Return a configured property.
+      */
+     public Object getProperty(String name) {
+         String repl = name;
+         if (replacements.get(name) != null) {
+             repl = (String) replacements.get(name);
+         }
+         return IntrospectionUtils.getProperty(protocolHandler, repl);
+     }
+
+     
+     /**
+      * Set a configured property.
+      */
+     public void setProperty(String name, String value) {
+         String repl = name;
+         if (replacements.get(name) != null) {
+             repl = (String) replacements.get(name);
+         }
+         IntrospectionUtils.setProperty(protocolHandler, repl, value);
+     }
+
+     
+    /**
+     * Return the <code>Service</code> with which we are associated (if any).
+     */
+    public Service getService() {
+
+        return (this.service);
+
+    }
+
+
+    /**
+     * Set the <code>Service</code> with which we are associated (if any).
+     *
+     * @param service The service that owns this Engine
+     */
+    public void setService(Service service) {
+
+        this.service = service;
+
+    }
+
+
+    /**
+     * Return the connection linger for this Connector.
+     */
+    public int getConnectionLinger() {
+
+        return (connectionLinger);
+
+    }
+
+
+    /**
+     * Set the connection linger for this Connector.
+     *
+     * @param connectionLinger The new connection linger
+     */
+    public void setConnectionLinger(int connectionLinger) {
+
+        this.connectionLinger = connectionLinger;
+        setProperty("connectionLinger", String.valueOf(connectionLinger));
+    }
+
+
+    /**
+     * Return the connection timeout for this Connector.
+     */
+    public int getConnectionTimeout() {
+
+        return (connectionTimeout);
+
+    }
+
+
+    /**
+     * Set the connection timeout for this Connector.
+     *
+     * @param connectionTimeout The new connection timeout
+     */
+    public void setConnectionTimeout(int connectionTimeout) {
+
+        this.connectionTimeout = connectionTimeout;
+        setProperty("connectionTimeout", String.valueOf(connectionTimeout));
+    }
+
+
+    /**
+     * Return the connection upload timeout for this Connector.
+     */
+    public int getConnectionUploadTimeout() {
+
+        return (connectionUploadTimeout);
+
+    }
+
+
+    /**
+     * Set the connection upload timeout for this Connector.
+     *
+     * @param connectionUploadTimeout The new connection upload timeout
+     */
+    public void setConnectionUploadTimeout(int connectionUploadTimeout) {
+
+        this.connectionUploadTimeout = connectionUploadTimeout;
+        setProperty("connectionUploadTimeout",
+                    String.valueOf(connectionUploadTimeout));
+
+    }
+
+
+    /**
+     * Return the server socket timeout for this Connector.
+     */
+    public int getServerSocketTimeout() {
+
+        return (serverSocketTimeout);
+
+    }
+
+
+    /**
+     * Set the server socket timeout for this Connector.
+     *
+     * @param serverSocketTimeout The new server socket timeout
+     */
+    public void setServerSocketTimeout(int serverSocketTimeout) {
+
+        this.serverSocketTimeout = serverSocketTimeout;
+        setProperty("serverSocketTimeout", String.valueOf(serverSocketTimeout));
+
+    }
+
+
+    /**
+     * Return the accept count for this Connector.
+     */
+    public int getAcceptCount() {
+
+        return (acceptCount);
+
+    }
+
+
+    /**
+     * Set the accept count for this Connector.
+     *
+     * @param count The new accept count
+     */
+    public void setAcceptCount(int count) {
+
+        this.acceptCount = count;
+        setProperty("acceptCount", String.valueOf(acceptCount));
+    }
+
+
+    /**
+     * Return the bind IP address for this Connector.
+     */
+    public String getAddress() {
+
+        return (this.address);
+
+    }
+
+
+    /**
+     * Set the bind IP address for this Connector.
+     *
+     * @param address The bind IP address
+     */
+    public void setAddress(String address) {
+
+        this.address = address;
+        setProperty("address", address);
+        
+    }
+
+
+    /**
+     * True if the TRACE method is allowed.  Default value is "false".
+     */
+    public boolean getAllowTrace() {
+
+        return (this.allowTrace);
+
+    }
+
+
+    /**
+     * Set the allowTrace flag, to disable or enable the TRACE HTTP method.
+     *
+     * @param allowTrace The new allowTrace flag
+     */
+    public void setAllowTrace(boolean allowTrace) {
+
+        this.allowTrace = allowTrace;
+
+    }
+
+    /**
+     * Is this connector available for processing requests?
+     */
+    public boolean isAvailable() {
+
+        return (started);
+
+    }
+
+
+    /**
+     * Return the input buffer size for this Connector.
+     */
+    public int getBufferSize() {
+
+        return (this.bufferSize);
+
+    }
+
+
+    /**
+     * Set the input buffer size for this Connector.
+     *
+     * @param bufferSize The new input buffer size.
+     */
+    public void setBufferSize(int bufferSize) {
+
+        this.bufferSize = bufferSize;
+
+    }
+
+
+    /**
+     * Return the Container used for processing requests received by this
+     * Connector.
+     */
+    public Container getContainer() {
+
+        return (container);
+
+    }
+
+
+    /**
+     * Set the Container used for processing requests received by this
+     * Connector.
+     *
+     * @param container The new Container to use
+     */
+    public void setContainer(Container container) {
+
+        this.container = container;
+
+    }
+
+    /**
+     * Get the list of compressable MIME types.
+     */
+    public String getCompressableMimeType() {
+        return compressableMimeTypes;
+    }
+
+    /**
+     * Set the list of compressable MIME types.
+     * 
+     * @param compressableMimeTypes The new list of MIME types to enable for
+     * compression.
+     */
+    public void setCompressableMimeType(String compressableMimeTypes) {
+        this.compressableMimeTypes = compressableMimeTypes;
+        setProperty("compressableMimeTypes", compressableMimeTypes);
+    }
+
+    /**
+     * Get the value of compression.
+     */
+    public String getCompression() {
+
+        return (compression);
+
+    }
+
+
+    /**
+     * Set the value of compression.
+     *
+     * @param compression The new compression value, which can be "on", "off"
+     * or "force"
+     */
+    public void setCompression(String compression) {
+
+        this.compression = compression;
+        setProperty("compression", compression);
+        
+    }
+
+
+    /**
+     * Return the current number of processors that have been created.
+     */
+    public int getCurProcessors() {
+
+        return (curProcessors);
+
+    }
+
+
+    /**
+     * Return the debugging detail level for this component.
+     */
+    public int getDebug() {
+
+        return (debug);
+
+    }
+
+
+    /**
+     * Set the debugging detail level for this component.
+     *
+     * @param debug The new debugging detail level
+     */
+    public void setDebug(int debug) {
+
+        this.debug = debug;
+
+    }
+
+
+    /**
+     * Return the "enable DNS lookups" flag.
+     */
+    public boolean getEnableLookups() {
+
+        return (this.enableLookups);
+
+    }
+
+
+    /**
+     * Set the "enable DNS lookups" flag.
+     *
+     * @param enableLookups The new "enable DNS lookups" flag value
+     */
+    public void setEnableLookups(boolean enableLookups) {
+
+        this.enableLookups = enableLookups;
+
+    }
+
+
+    /**
+     * Return the server socket factory used by this Container.
+     */
+    public ServerSocketFactory getFactory() {
+
+        if (this.factory == null) {
+            synchronized (this) {
+                this.factory = new DefaultServerSocketFactory();
+            }
+        }
+        return (this.factory);
+
+    }
+
+
+    /**
+     * Set the server socket factory used by this Container.
+     *
+     * @param factory The new server socket factory
+     */
+    public void setFactory(ServerSocketFactory factory) {
+
+        this.factory = factory;
+
+    }
+
+
+    /**
+     * Return descriptive information about this Connector implementation.
+     */
+    public String getInfo() {
+
+        return (info);
+
+    }
+
+
+    /**
+     * Return the minimum number of processors to start at initialization.
+     */
+    public int getMinProcessors() {
+
+        return (minProcessors);
+
+    }
+
+
+    /**
+     * Set the minimum number of processors to start at initialization.
+     *
+     * @param minProcessors The new minimum processors
+     */
+    public void setMinProcessors(int minProcessors) {
+
+        this.minProcessors = minProcessors;
+        setProperty("minProcessors", String.valueOf(minProcessors));   
+        
+    }
+
+
+    /**
+     * Return the maximum number of processors allowed, or <0 for unlimited.
+     */
+    public int getMaxProcessors() {
+
+        return (maxProcessors);
+
+    }
+
+
+    /**
+     * Set the maximum number of processors allowed, or <0 for unlimited.
+     *
+     * @param maxProcessors The new maximum processors
+     */
+    public void setMaxProcessors(int maxProcessors) {
+
+        this.maxProcessors = maxProcessors;
+        setProperty("maxProcessors", String.valueOf(maxProcessors));
+    }
+
+
+    /**
+     * Return the maximum number of spare processors allowed.
+     */
+    public int getMaxSpareProcessors() {
+
+        return (maxSpareProcessors);
+
+    }
+
+
+    /**
+     * Set the maximum number of spare processors allowed.
+     *
+     * @param maxSpareProcessors The new maximum of spare processors
+     */
+    public void setMaxSpareProcessors(int maxSpareProcessors) {
+
+        this.maxSpareProcessors = maxSpareProcessors;
+        setProperty("maxSpareProcessors", String.valueOf(maxSpareProcessors));
+
+    }
+
+    /**
+     * Return the maximum permitted size of the HTTP request and response
+     * headers.
+     */
+    public int getMaxHttpHeaderSize() {
+        return maxHttpHeaderSize;
+    }
+
+    /**
+     * Set the maximum permitted size of the HTTP request and response
+     * headers.
+     * 
+     * @param maxHttpHeaderSize The new maximum header size in bytes.
+     */
+    public void setMaxHttpHeaderSize(int maxHttpHeaderSize) {
+        this.maxHttpHeaderSize = maxHttpHeaderSize;
+        setProperty("maxHttpHeaderSize", String.valueOf(maxHttpHeaderSize));
+    }
+
+    /**
+     * Return the port number on which we listen for requests.
+     */
+    public int getPort() {
+
+        return (this.port);
+
+    }
+
+
+    /**
+     * Set the port number on which we listen for requests.
+     *
+     * @param port The new port number
+     */
+    public void setPort(int port) {
+
+        this.port = port;
+        setProperty("port", String.valueOf(port));
+        
+    }
+
+
+    /**
+     * Return the protocol handler associated with the connector.
+     */
+    public ProtocolHandler getProtocolHandler() {
+
+        return (this.protocolHandler);
+
+    }
+    /**
+     * Return the class name of the Coyote protocol handler in use.
+     */
+    public String getProtocolHandlerClassName() {
+
+        return (this.protocolHandlerClassName);
+
+    }
+
+
+    /**
+     * Set the class name of the Coyote protocol handler which will be used
+     * by the connector.
+     *
+     * @param protocolHandlerClassName The new class name
+     */
+    public void setProtocolHandlerClassName(String protocolHandlerClassName) {
+
+        this.protocolHandlerClassName = protocolHandlerClassName;
+
+    }
+
+
+    /**
+     * Return the proxy server name for this Connector.
+     */
+    public String getProxyName() {
+
+        return (this.proxyName);
+
+    }
+
+
+    /**
+     * Set the proxy server name for this Connector.
+     *
+     * @param proxyName The new proxy server name
+     */
+    public void setProxyName(String proxyName) {
+
+        if(! "".equals(proxyName) ) {
+            this.proxyName = proxyName;
+        } else {
+            this.proxyName = null;
+        }
+
+    }
+
+
+    /**
+     * Return the proxy server port for this Connector.
+     */
+    public int getProxyPort() {
+
+        return (this.proxyPort);
+
+    }
+
+
+    /**
+     * Set the proxy server port for this Connector.
+     *
+     * @param proxyPort The new proxy server port
+     */
+    public void setProxyPort(int proxyPort) {
+
+        this.proxyPort = proxyPort;
+
+    }
+
+
+    /**
+     * Return the port number to which a request should be redirected if
+     * it comes in on a non-SSL port and is subject to a security constraint
+     * with a transport guarantee that requires SSL.
+     */
+    public int getRedirectPort() {
+
+        return (this.redirectPort);
+
+    }
+
+
+    /**
+     * Set the redirect port number.
+     *
+     * @param redirectPort The redirect port number (non-SSL to SSL)
+     */
+    public void setRedirectPort(int redirectPort) {
+
+        this.redirectPort = redirectPort;
+
+    }
+
+    /**
+     * Return the flag that specifies upload time-out behavior.
+     */
+    public boolean getDisableUploadTimeout() {
+        return disableUploadTimeout;
+    }
+
+    /**
+     * Set the flag to specify upload time-out behavior.
+     *
+     * @param isDisabled If <code>true</code>, then the <code>timeout</code>
+     * parameter is ignored.  If <code>false</code>, then the
+     * <code>timeout</code> parameter is used to control uploads.
+     */
+    public void setDisableUploadTimeout( boolean isDisabled ) {
+        disableUploadTimeout = isDisabled;
+        setProperty("disableUploadTimeout",
+                    String.valueOf(disableUploadTimeout));
+    }
+
+    /**
+     * Return the maximum number of Keep-Alive requests to honor per connection.
+     */
+    public int getMaxKeepAliveRequests() {
+        return maxKeepAliveRequests;
+    }
+
+    /**
+     * Set the maximum number of Keep-Alive requests to honor per connection.
+     */
+    public void setMaxKeepAliveRequests(int mkar) {
+        maxKeepAliveRequests = mkar;
+        setProperty("maxKeepAliveRequests",
+                    String.valueOf(maxKeepAliveRequests));
+    }
+
+    /**
+     * Return the scheme that will be assigned to requests received
+     * through this connector.  Default value is "http".
+     */
+    public String getScheme() {
+
+        return (this.scheme);
+
+    }
+
+
+    /**
+     * Set the scheme that will be assigned to requests received through
+     * this connector.
+     *
+     * @param scheme The new scheme
+     */
+    public void setScheme(String scheme) {
+
+        this.scheme = scheme;
+
+    }
+
+
+    /**
+     * Return the secure connection flag that will be assigned to requests
+     * received through this connector.  Default value is "false".
+     */
+    public boolean getSecure() {
+
+        return (this.secure);
+
+    }
+
+
+    /**
+     * Set the secure connection flag that will be assigned to requests
+     * received through this connector.
+     *
+     * @param secure The new secure connection flag
+     */
+    public void setSecure(boolean secure) {
+
+        this.secure = secure;
+        setProperty("secure",
+                String.valueOf(secure));
+
+    }
+
+    public boolean getTomcatAuthentication() {
+        return tomcatAuthentication;
+    }
+
+    public void setTomcatAuthentication(boolean tomcatAuthentication) {
+        this.tomcatAuthentication = tomcatAuthentication;
+        setProperty("tomcatAuthentication",
+                    String.valueOf(tomcatAuthentication));
+    }
+
+    /**
+     * Return the TCP no delay flag value.
+     */
+    public boolean getTcpNoDelay() {
+
+        return (this.tcpNoDelay);
+
+    }
+
+
+    /**
+     * Set the TCP no delay flag which will be set on the socket after
+     * accepting a connection.
+     *
+     * @param tcpNoDelay The new TCP no delay flag
+     */
+    public void setTcpNoDelay(boolean tcpNoDelay) {
+
+        this.tcpNoDelay = tcpNoDelay;
+        setProperty("tcpNoDelay", String.valueOf(tcpNoDelay));
+        
+    }
+
+
+     /**
+      * Return the character encoding to be used for the URI.
+      */
+     public String getURIEncoding() {
+
+         return (this.URIEncoding);
+
+     }
+
+
+     /**
+      * Set the URI encoding to be used for the URI.
+      *
+      * @param URIEncoding The new URI character encoding.
+      */
+     public void setURIEncoding(String URIEncoding) {
+
+         this.URIEncoding = URIEncoding;
+
+     }
+
+
+     /**
+      * Return the true if the entity body encoding should be used for the URI.
+      */
+     public boolean getUseBodyEncodingForURI() {
+
+         return (this.useBodyEncodingForURI);
+
+     }
+
+
+     /**
+      * Set if the entity body encoding should be used for the URI.
+      *
+      * @param useBodyEncodingForURI The new value for the flag.
+      */
+     public void setUseBodyEncodingForURI(boolean useBodyEncodingForURI) {
+
+         this.useBodyEncodingForURI = useBodyEncodingForURI;
+
+     }
+
+
+    /**
+     * Return the value of the Uri validation flag.
+     */
+    public boolean getUseURIValidationHack() {
+
+        return (this.useURIValidationHack);
+
+    }
+
+
+    /**
+     * Set the value of the Uri validation flag.
+     *
+     * @param useURIValidationHack The new flag value
+     */
+    public void setUseURIValidationHack(boolean useURIValidationHack) {
+
+        this.useURIValidationHack = useURIValidationHack;
+
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Create (or allocate) and return a Request object suitable for
+     * specifying the contents of a Request to the responsible Container.
+     */
+    public Request createRequest() {
+
+        CoyoteRequest request = new CoyoteRequest();
+        request.setConnector(this);
+        return (request);
+
+    }
+
+
+    /**
+     * Create (or allocate) and return a Response object suitable for
+     * receiving the contents of a Response from the responsible Container.
+     */
+    public Response createResponse() {
+
+        CoyoteResponse response = new CoyoteResponse();
+        response.setConnector(this);
+        return (response);
+
+    }
+
+
+    // -------------------------------------------------------- Private Methods
+
+
+    /**
+     * Log a message on the Logger associated with our Container (if any).
+     *
+     * @param message Message to be logged
+     */
+    private void log(String message) {
+
+        Logger logger = container.getLogger();
+        String localName = "CoyoteConnector";
+        if (logger != null)
+            logger.log(localName + " " + message);
+        else
+            System.out.println(localName + " " + message);
+
+    }
+
+
+    // ------------------------------------------------------ Lifecycle Methods
+
+
+    /**
+     * Add a lifecycle event listener to this component.
+     *
+     * @param listener The listener to add
+     */
+    public void addLifecycleListener(LifecycleListener listener) {
+
+        lifecycle.addLifecycleListener(listener);
+
+    }
+
+
+    /**
+     * Get the lifecycle listeners associated with this lifecycle. If this
+     * Lifecycle has no listeners registered, a zero-length array is returned.
+     */
+    public LifecycleListener[] findLifecycleListeners() {
+
+        return null;//lifecycle.findLifecycleListeners();
+
+    }
+
+
+    /**
+     * Remove a lifecycle event listener from this component.
+     *
+     * @param listener The listener to add
+     */
+    public void removeLifecycleListener(LifecycleListener listener) {
+
+        lifecycle.removeLifecycleListener(listener);
+
+    }
+
+    protected ObjectName createObjectName(String domain, String type)
+            throws MalformedObjectNameException {
+        String encodedAddr = null;
+        if (getProperty("address") != null) {
+            encodedAddr = URLEncoder.encode(getProperty("address").toString());
+        }
+        String addSuffix = (getProperty("address") == null) ? "" : ",address="
+                + encodedAddr;
+        ObjectName _oname = new ObjectName(domain + ":type=" + type + ",port="
+                + getPort() + addSuffix);
+        return _oname;
+}
+
+    
+    /**
+     * Initialize this connector (create ServerSocket here!)
+     */
+    public void initialize()
+        throws LifecycleException {
+
+        if (initialized)
+            throw new LifecycleException
+                (sm.getString("coyoteConnector.alreadyInitialized"));
+
+        this.initialized = true;
+
+        if( oname == null && (container instanceof StandardEngine)) {
+            try {
+                // we are loaded directly, via API - and no name was given to us
+                StandardEngine cb=(StandardEngine)container;
+                oname = createObjectName(cb.getName(), "Connector");
+                Registry.getRegistry(null, null)
+                    .registerComponent(this, oname, null);
+            } catch (Exception e) {
+                log ("Error registering connector " + e.toString());
+            }
+            if(debug > 0)
+                log("Creating name for connector " + oname);
+        }
+
+        // Initialize adapter
+        adapter = new CoyoteAdapter(this);
+
+        protocolHandler.setAdapter(adapter);
+
+        IntrospectionUtils.setProperty(protocolHandler, "jkHome",
+                                       System.getProperty("catalina.base"));
+
+        // Configure secure socket factory
+        if (factory instanceof CoyoteServerSocketFactory) {
+            IntrospectionUtils.setProperty(protocolHandler, "secure",
+                                           "" + true);
+            CoyoteServerSocketFactory ssf =
+                (CoyoteServerSocketFactory) factory;
+            IntrospectionUtils.setProperty(protocolHandler, "algorithm",
+                                           ssf.getAlgorithm());
+            IntrospectionUtils.setProperty(protocolHandler, "ciphers",
+                                           ssf.getCiphers());
+	        IntrospectionUtils.setProperty(protocolHandler, "clientauth",
+                                           ssf.getClientAuth());
+            IntrospectionUtils.setProperty(protocolHandler, "keystore",
+                                           ssf.getKeystoreFile());
+            IntrospectionUtils.setProperty(protocolHandler, "randomfile",
+                                           ssf.getRandomFile());
+            IntrospectionUtils.setProperty(protocolHandler, "rootfile",
+                                           ssf.getRootFile());
+
+            IntrospectionUtils.setProperty(protocolHandler, "keypass",
+                                           ssf.getKeystorePass());
+            IntrospectionUtils.setProperty(protocolHandler, "keytype",
+                                           ssf.getKeystoreType());
+            IntrospectionUtils.setProperty(protocolHandler, "protocol",
+                                           ssf.getProtocol());
+            IntrospectionUtils.setProperty(protocolHandler,
+                                           "sSLImplementation",
+                                           ssf.getSSLImplementation());
+        }
+
+        try {
+            protocolHandler.init();
+        } catch (Exception e) {
+            throw new LifecycleException
+                (sm.getString
+                 ("coyoteConnector.protocolHandlerInitializationFailed", e));
+        }
+    }
+
+
+    /**
+     * Begin processing requests via this Connector.
+     *
+     * @exception LifecycleException if a fatal startup error occurs
+     */
+    public void start() throws LifecycleException {
+
+        // Validate and update our current state
+        if (started)
+            throw new LifecycleException
+                (sm.getString("coyoteConnector.alreadyStarted"));
+        lifecycle.fireLifecycleEvent(START_EVENT, null);
+        started = true;
+
+        // We can't register earlier - the JMX registration of this happens
+        // in Server.start callback
+        if( this.oname != null ) {
+            // We are registred - register the adapter as well.
+            try {
+                Registry.getRegistry(null, null).registerComponent(
+                        protocolHandler,
+                        this.domain + ":type=protocolHandler,className=" +
+                        protocolHandlerClassName, null);
+            } catch( Exception ex ) {
+                ex.printStackTrace();
+            }
+        } else {
+            log( "Coyote can't register jmx for protocol");
+        }
+
+        try {
+            protocolHandler.start();
+        } catch (Exception e) {
+            throw new LifecycleException
+                (sm.getString
+                 ("coyoteConnector.protocolHandlerStartFailed", e));
+        }
+
+    }
+
+
+    /**
+     * Terminate processing requests via this Connector.
+     *
+     * @exception LifecycleException if a fatal shutdown error occurs
+     */
+    public void stop() throws LifecycleException {
+
+        // Validate and update our current state
+        if (!started)
+            throw new LifecycleException
+                (sm.getString("coyoteConnector.notStarted"));
+        lifecycle.fireLifecycleEvent(STOP_EVENT, null);
+        started = false;
+
+        try {
+            protocolHandler.destroy();
+        } catch (Exception e) {
+            throw new LifecycleException
+                (sm.getString
+                 ("coyoteConnector.protocolHandlerDestroyFailed", e));
+        }
+
+    }
+
+    protected String domain;
+    protected ObjectName oname;
+    protected MBeanServer mserver;
+
+    public ObjectName getObjectName() {
+        return oname;
+    }
+
+    public String getDomain() {
+        return domain;
+    }
+
+    public ObjectName preRegister(MBeanServer server,
+                                  ObjectName name) throws Exception {
+        oname=name;
+        mserver=server;
+        domain=name.getDomain();
+        return name;
+    }
+
+    public void postRegister(Boolean registrationDone) {
+    }
+
+    public void preDeregister() throws Exception {
+    }
+
+    public void postDeregister() {
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/java/org/apache/coyote/tomcat4/CoyoteInputStream.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/java/org/apache/coyote/tomcat4/CoyoteInputStream.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/java/org/apache/coyote/tomcat4/CoyoteInputStream.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,164 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.tomcat4;
+
+import java.io.IOException;
+
+import javax.servlet.ServletInputStream;
+
+import org.apache.coyote.Request;
+import org.apache.tomcat.util.buf.ByteChunk;
+
+
+/**
+ * This class handles the readin input bytes, as well as the input buffering.
+ * 
+ * @author Remy Maucherat
+ */
+public class CoyoteInputStream extends ServletInputStream {
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    private boolean closed = false;
+
+    private Request coyoteRequest;
+
+    private ByteChunk readChunk = new ByteChunk();
+
+    /**
+     * Current read position in the byte buffer.
+     */
+    private int pos = -1;
+    private int end = -1;
+    private byte[] readBuffer = null;
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    void setRequest(Request coyoteRequest) {
+        this.coyoteRequest = coyoteRequest;
+    }
+
+
+    /**
+     * Recycle the input stream.
+     */
+    void recycle() {
+        closed = false;
+        pos = -1;
+        end = -1;
+        readBuffer = null;
+    }
+
+
+    // --------------------------------------------- ServletInputStream Methods
+
+
+    public int read()
+        throws IOException {
+
+        if (closed)
+            throw new IOException("Stream closed");
+
+        // Read additional bytes if none are available
+        while (pos >= end) {
+            if (readBytes() < 0)
+                return -1;
+        }
+
+        return (readBuffer[pos++] & 0xFF);
+
+    }
+
+    public int available() throws IOException {
+        if( pos < end ) return end-pos;
+        return 0;
+    }
+
+    public int read(byte[] b) throws IOException {
+
+        return read(b, 0, b.length);
+
+    }
+
+
+    public int read(byte[] b, int off, int len)
+        throws IOException {
+
+        if (closed)
+            throw new IOException("Stream closed");
+
+        // Read additional bytes if none are available
+        while (pos >= end) {
+            if (readBytes() < 0)
+                return -1;
+        }
+
+        int n = -1;
+        if ((end - pos) > len) {
+            n = len;
+        } else {
+            n = end - pos;
+        }
+
+        System.arraycopy(readBuffer, pos, b, off, n);
+
+        pos += n;
+        return n;
+
+    }
+
+
+    public int readLine(byte[] b, int off, int len) throws IOException {
+        return super.readLine(b, off, len);
+    }
+
+
+    /** 
+     * Close the stream
+     * Since we re-cycle, we can't allow the call to super.close()
+     * which would permantely disable us.
+     */
+    public void close() {
+        closed = true;
+    }
+
+
+    // ------------------------------------------------------ Protected Methods
+
+
+    /**
+     * Read bytes to the read chunk buffer.
+     */
+    protected int readBytes()
+        throws IOException {
+
+        int result = coyoteRequest.doRead(readChunk);
+        if (result > 0) {
+            readBuffer = readChunk.getBytes();
+            end = readChunk.getEnd();
+            pos = readChunk.getStart();
+        }
+        return result;
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/java/org/apache/coyote/tomcat4/CoyoteOutputStream.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/java/org/apache/coyote/tomcat4/CoyoteOutputStream.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/java/org/apache/coyote/tomcat4/CoyoteOutputStream.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,93 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.tomcat4;
+
+import java.io.IOException;
+
+import javax.servlet.ServletOutputStream;
+
+/**
+ * Coyote implementation of the servlet output stream.
+ * 
+ * @author Costin Manolache
+ * @author Remy Maucherat
+ */
+final class CoyoteOutputStream 
+    extends ServletOutputStream {
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    protected OutputBuffer ob;
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    protected CoyoteOutputStream(OutputBuffer ob) {
+        this.ob = ob;
+    }
+
+
+    // --------------------------------------------------- OutputStream Methods
+
+
+    public void write(int i)
+        throws IOException {
+        ob.writeByte(i);
+    }
+
+
+    public void write(byte[] b)
+        throws IOException {
+        write(b, 0, b.length);
+    }
+
+
+    public void write(byte[] b, int off, int len)
+        throws IOException {
+        ob.write(b, off, len);
+    }
+
+
+    /**
+     * Will send the buffer to the client.
+     */
+    public void flush()
+        throws IOException {
+        ob.flush();
+    }
+
+
+    public void close()
+        throws IOException {
+        ob.close();
+    }
+
+
+    // -------------------------------------------- ServletOutputStream Methods
+
+
+    public void print(String s)
+        throws IOException {
+        ob.write(s);
+    }
+
+
+}
+

Added: branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/java/org/apache/coyote/tomcat4/CoyotePrincipal.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/java/org/apache/coyote/tomcat4/CoyotePrincipal.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/java/org/apache/coyote/tomcat4/CoyotePrincipal.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,73 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.tomcat4;
+
+import java.security.Principal;
+
+/**
+ * Generic implementation of <strong>java.security.Principal</strong> that
+ * is used to represent principals authenticated at the protocol handler level.
+ *
+ * @author Remy Maucherat
+ * @version $Revision: 299222 $ $Date: 2004-02-24 03:02:18 -0600 (Tue, 24 Feb 2004) $
+ */
+
+public class CoyotePrincipal 
+    implements Principal {
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    public CoyotePrincipal(String name) {
+
+        this.name = name;
+
+    }
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * The username of the user represented by this Principal.
+     */
+    protected String name = null;
+
+    public String getName() {
+        return (this.name);
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Return a String representation of this object, which exposes only
+     * information that should be public.
+     */
+    public String toString() {
+
+        StringBuffer sb = new StringBuffer("CoyotePrincipal[");
+        sb.append(this.name);
+        sb.append("]");
+        return (sb.toString());
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/java/org/apache/coyote/tomcat4/CoyoteRequest.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/java/org/apache/coyote/tomcat4/CoyoteRequest.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/java/org/apache/coyote/tomcat4/CoyoteRequest.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,2107 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.tomcat4;
+
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.UnsupportedEncodingException;
+import java.net.InetAddress;
+import java.net.Socket;
+import java.security.AccessController;
+import java.security.Principal;
+import java.security.PrivilegedAction;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Locale;
+import java.util.Map;
+import java.util.TreeMap;
+
+import javax.servlet.RequestDispatcher;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletInputStream;
+import javax.servlet.ServletRequest;
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+
+import org.apache.catalina.Connector;
+import org.apache.catalina.Context;
+import org.apache.catalina.Globals;
+import org.apache.catalina.HttpRequest;
+import org.apache.catalina.Manager;
+import org.apache.catalina.Realm;
+import org.apache.catalina.Session;
+import org.apache.catalina.Wrapper;
+import org.apache.catalina.util.Enumerator;
+import org.apache.catalina.util.ParameterMap;
+import org.apache.catalina.util.RequestUtil;
+import org.apache.catalina.util.StringManager;
+import org.apache.catalina.util.StringParser;
+import org.apache.coyote.ActionCode;
+import org.apache.coyote.Request;
+import org.apache.tomcat.util.buf.B2CConverter;
+import org.apache.tomcat.util.http.Parameters;
+
+/**
+ * Wrapper object for the Coyote request.
+ *
+ * @author Remy Maucherat
+ * @author Craig R. McClanahan
+ * @version $Revision: 392357 $ $Date: 2006-04-07 13:28:19 -0500 (Fri, 07 Apr 2006) $
+ */
+
+public class CoyoteRequest
+    implements HttpRequest, HttpServletRequest {
+
+
+    // --------------------------------------- PrivilegedGetSession Inner Class
+
+
+    protected class PrivilegedGetSession
+        implements PrivilegedAction {
+
+        private boolean create;
+
+        PrivilegedGetSession(boolean create) {
+            this.create = create;
+        }
+
+        public Object run() {
+            return doGetSession(create);
+        }
+
+    }
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * Coyote request.
+     */
+    protected Request coyoteRequest;
+
+    /**
+     * Set the Coyote request.
+     * 
+     * @param coyoteRequest The Coyote request
+     */
+    public void setCoyoteRequest(Request coyoteRequest) {
+        this.coyoteRequest = coyoteRequest;
+        inputStream.setRequest(coyoteRequest);
+    }
+
+    /**
+     * Get the Coyote request.
+     */
+    public Request getCoyoteRequest() {
+        return (this.coyoteRequest);
+    }
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The string manager for this package.
+     */
+    protected static StringManager sm =
+        StringManager.getManager(Constants.Package);
+
+
+    /**
+     * The set of cookies associated with this Request.
+     */
+    protected Cookie[] cookies = null;
+
+
+    /**
+     * The set of SimpleDateFormat formats to use in getDateHeader().
+     */
+    protected SimpleDateFormat formats[] = {
+        new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US),
+        new SimpleDateFormat("EEEEEE, dd-MMM-yy HH:mm:ss zzz", Locale.US),
+        new SimpleDateFormat("EEE MMMM d HH:mm:ss yyyy", Locale.US)
+    };
+
+
+    /**
+     * The default Locale if none are specified.
+     */
+    protected static Locale defaultLocale = Locale.getDefault();
+
+
+    /**
+     * The attributes associated with this Request, keyed by attribute name.
+     */
+    protected HashMap attributes = new HashMap();
+
+
+    /**
+     * The preferred Locales assocaited with this Request.
+     */
+    protected ArrayList locales = new ArrayList();
+
+
+    /**
+     * Internal notes associated with this request by Catalina components
+     * and event listeners.
+     */
+    private transient HashMap notes = new HashMap();
+
+
+    /**
+     * Authentication type.
+     */
+    protected String authType = null;
+
+
+    /**
+     * Reader.
+     * Note: At the moment, no attempt is being made at recycling the reader,
+     * but this could be implemented in the future, using a design like the one
+     * used for the output buffer.
+     */
+    protected BufferedReader reader = null;
+
+
+    /**
+     * ServletInputStream.
+     */
+    protected CoyoteInputStream inputStream = new CoyoteInputStream();
+
+
+    /**
+     * Using stream flag.
+     */
+    protected boolean usingInputStream = false;
+
+
+    /**
+     * Using writer flag.
+     */
+    protected boolean usingReader = false;
+
+
+    /**
+     * Context path.
+     */
+    protected String contextPath = "";
+
+
+    /**
+     * Path info.
+     */
+    protected String pathInfo = null;
+
+
+    /**
+     * Servlet path.
+     */
+    protected String servletPath = null;
+
+
+    /**
+     * User principal.
+     */
+    protected Principal userPrincipal = null;
+
+
+    /**
+     * Session parsed flag.
+     */
+    protected boolean sessionParsed = false;
+
+
+    /**
+     * Request parameters parsed flag.
+     */
+    protected boolean requestParametersParsed = false;
+
+
+    /**
+     * Secure flag.
+     */
+    protected boolean secure = false;
+
+
+    /**
+     * Post data buffer.
+     */
+    protected static int CACHED_POST_LEN = 8192;
+    protected byte[] postData = null;
+
+
+    /**
+     * Hash map used in the getParametersMap method.
+     */
+    protected ParameterMap parameterMap = new ParameterMap();
+
+
+    /**
+     * The currently active session for this request.
+     */
+    protected Session session = null;
+
+
+    /**
+     * Was the requested session ID received in a cookie?
+     */
+    protected boolean requestedSessionCookie = false;
+
+
+    /**
+     * The requested session ID (if any) for this request.
+     */
+    protected String requestedSessionId = null;
+
+
+    /**
+     * Was the requested session ID received in a URL?
+     */
+    protected boolean requestedSessionURL = false;
+
+
+    /**
+     * The socket through which this Request was received.
+     */
+    protected Socket socket = null;
+
+
+    /**
+     * Parse locales.
+     */
+    protected boolean localesParsed = false;
+
+
+    /**
+     * The string parser we will use for parsing request lines.
+     */
+    private StringParser parser = new StringParser();
+
+
+    /**
+     * Remote address.
+     */
+    protected String remoteAddr = null;
+
+
+    /**
+     * Remote host.
+     */
+    protected String remoteHost = null;
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Release all object references, and initialize instance variables, in
+     * preparation for reuse of this object.
+     */
+    public void recycle() {
+
+        context = null;
+        wrapper = null;
+
+        authorization = null;
+        authType = null;
+        usingInputStream = false;
+        usingReader = false;
+        contextPath = "";
+        pathInfo = null;
+        servletPath = null;
+        reader = null;
+        inputStream.recycle();
+        userPrincipal = null;
+        sessionParsed = false;
+        authorization = null;
+        requestParametersParsed = false;
+        locales.clear();
+        localesParsed = false;
+        secure = false;
+        remoteAddr = null;
+        remoteHost = null;
+
+        attributes.clear();
+        notes.clear();
+        cookies = null;
+
+        session = null;
+        requestedSessionCookie = false;
+        requestedSessionId = null;
+        requestedSessionURL = false;
+
+        parameterMap.setLocked(false);
+        parameterMap.clear();
+
+        if (facade != null) {
+            facade.clear();
+            facade = null;
+        }
+
+    }
+
+
+    // -------------------------------------------------------- Request Methods
+
+
+    /**
+     * The authorization credentials sent with this Request.
+     */
+    protected String authorization = null;
+
+    /**
+     * Return the authorization credentials sent with this request.
+     */
+    public String getAuthorization() {
+
+        return (this.authorization);
+
+    }
+
+    /**
+     * Set the authorization credentials sent with this request.
+     *
+     * @param authorization The new authorization credentials
+     */
+    public void setAuthorization(String authorization) {
+        this.authorization = authorization;
+    }
+
+
+    /**
+     * Associated Catalina connector.
+     */
+    protected CoyoteConnector connector;
+
+    /**
+     * Return the Connector through which this Request was received.
+     */
+    public Connector getConnector() {
+        return (this.connector);
+    }
+
+    /**
+     * Set the Connector through which this Request was received.
+     *
+     * @param connector The new connector
+     */
+    public void setConnector(Connector connector) {
+        this.connector = (CoyoteConnector) connector;
+    }
+
+    /**
+     * The Context within which this Request is being processed.
+     */
+    protected Context context = null;
+
+    /**
+     * Return the Context within which this Request is being processed.
+     */
+    public Context getContext() {
+        return (this.context);
+    }
+
+    /**
+     * Set the Context within which this Request is being processed.  This
+     * must be called as soon as the appropriate Context is identified, because
+     * it identifies the value to be returned by <code>getContextPath()</code>,
+     * and thus enables parsing of the request URI.
+     *
+     * @param context The newly associated Context
+     */
+    public void setContext(Context context) {
+        this.context = context;
+    }
+
+
+    /**
+     * Descriptive information about this Request implementation.
+     */
+    protected static final String info =
+        "org.apache.coyote.catalina.CoyoteRequest/1.0";
+
+    /**
+     * Return descriptive information about this Request implementation and
+     * the corresponding version number, in the format
+     * <code>&lt;description&gt;/&lt;version&gt;</code>.
+     */
+    public String getInfo() {
+        return (info);
+    }
+
+
+    /**
+     * The facade associated with this request.
+     */
+    protected CoyoteRequestFacade facade = null;
+
+    /**
+     * Return the <code>ServletRequest</code> for which this object
+     * is the facade.  This method must be implemented by a subclass.
+     */
+    public ServletRequest getRequest() {
+        if (facade == null) {
+            facade = new CoyoteRequestFacade(this);
+        }
+        return (facade);
+    }
+
+
+    /**
+     * The response with which this request is associated.
+     */
+    protected org.apache.catalina.Response response = null;
+
+    /**
+     * Return the Response with which this Request is associated.
+     */
+    public org.apache.catalina.Response getResponse() {
+        return (this.response);
+    }
+
+    /**
+     * Set the Response with which this Request is associated.
+     *
+     * @param response The new associated response
+     */
+    public void setResponse(org.apache.catalina.Response response) {
+        this.response = response;
+    }
+
+
+    /**
+     * Return the Socket (if any) through which this Request was received.
+     * This should <strong>only</strong> be used to access underlying state
+     * information about this Socket, such as the SSLSession associated with
+     * an SSLSocket.
+     */
+    public Socket getSocket() {
+        return (socket);
+    }
+
+    /**
+     * Set the Socket (if any) through which this Request was received.
+     *
+     * @param socket The socket through which this request was received
+     */
+    public void setSocket(Socket socket) {
+        this.socket = socket;
+        remoteHost = null;
+        remoteAddr = null;
+    }
+
+
+    /**
+     * Return the input stream associated with this Request.
+     */
+    public InputStream getStream() {
+        return inputStream;
+    }
+
+    /**
+     * Set the input stream associated with this Request.
+     *
+     * @param stream The new input stream
+     */
+    public void setStream(InputStream stream) {
+        // Ignore
+    }
+
+
+    /**
+     * URI byte to char converter (not recycled).
+     */
+    protected B2CConverter URIConverter = null;
+
+    /**
+     * Return the URI converter.
+     */
+    protected B2CConverter getURIConverter() {
+        return URIConverter;
+    }
+
+    /**
+     * Set the URI converter.
+     * 
+     * @param URIConverter the new URI connverter
+     */
+    protected void setURIConverter(B2CConverter URIConverter) {
+        this.URIConverter = URIConverter;
+    }
+
+
+    /**
+     * The Wrapper within which this Request is being processed.
+     */
+    protected Wrapper wrapper = null;
+
+    /**
+     * Return the Wrapper within which this Request is being processed.
+     */
+    public Wrapper getWrapper() {
+        return (this.wrapper);
+    }
+
+    /**
+     * Set the Wrapper within which this Request is being processed.  This
+     * must be called as soon as the appropriate Wrapper is identified, and
+     * before the Request is ultimately passed to an application servlet.
+     *
+     * @param wrapper The newly associated Wrapper
+     */
+    public void setWrapper(Wrapper wrapper) {
+        this.wrapper = wrapper;
+    }
+
+
+    // ------------------------------------------------- Request Public Methods
+
+
+    /**
+     * Create and return a ServletInputStream to read the content
+     * associated with this Request.
+     *
+     * @exception IOException if an input/output error occurs
+     */
+    public ServletInputStream createInputStream() 
+        throws IOException {
+        return inputStream;
+    }
+
+
+    /**
+     * Perform whatever actions are required to flush and close the input
+     * stream or reader, in a single operation.
+     *
+     * @exception IOException if an input/output error occurs
+     */
+    public void finishRequest() throws IOException {
+        // The reader and input stream don't need to be closed
+    }
+
+
+    /**
+     * Return the object bound with the specified name to the internal notes
+     * for this request, or <code>null</code> if no such binding exists.
+     *
+     * @param name Name of the note to be returned
+     */
+    public Object getNote(String name) {
+        return (notes.get(name));
+    }
+
+
+    /**
+     * Return an Iterator containing the String names of all notes bindings
+     * that exist for this request.
+     */
+    public Iterator getNoteNames() {
+        return (notes.keySet().iterator());
+    }
+
+
+    /**
+     * Remove any object bound to the specified name in the internal notes
+     * for this request.
+     *
+     * @param name Name of the note to be removed
+     */
+    public void removeNote(String name) {
+        notes.remove(name);
+    }
+
+
+    /**
+     * Bind an object to a specified name in the internal notes associated
+     * with this request, replacing any existing binding for this name.
+     *
+     * @param name Name to which the object should be bound
+     * @param value Object to be bound to the specified name
+     */
+    public void setNote(String name, Object value) {
+        notes.put(name, value);
+    }
+
+
+    /**
+     * Set the content length associated with this Request.
+     *
+     * @param length The new content length
+     */
+    public void setContentLength(int length) {
+        // Not used
+    }
+
+
+    /**
+     * Set the content type (and optionally the character encoding)
+     * associated with this Request.  For example,
+     * <code>text/html; charset=ISO-8859-4</code>.
+     *
+     * @param type The new content type
+     */
+    public void setContentType(String type) {
+        // Not used
+    }
+
+
+    /**
+     * Set the protocol name and version associated with this Request.
+     *
+     * @param protocol Protocol name and version
+     */
+    public void setProtocol(String protocol) {
+        // Not used
+    }
+
+
+    /**
+     * Set the IP address of the remote client associated with this Request.
+     *
+     * @param remoteAddr The remote IP address
+     */
+    public void setRemoteAddr(String remoteAddr) {
+        // Not used
+    }
+
+
+    /**
+     * Set the fully qualified name of the remote client associated with this
+     * Request.
+     *
+     * @param remoteHost The remote host name
+     */
+    public void setRemoteHost(String remoteHost) {
+        // Not used
+    }
+
+
+    /**
+     * Set the name of the scheme associated with this request.  Typical values
+     * are <code>http</code>, <code>https</code>, and <code>ftp</code>.
+     *
+     * @param scheme The scheme
+     */
+    public void setScheme(String scheme) {
+        // Not used
+    }
+
+
+    /**
+     * Set the value to be returned by <code>isSecure()</code>
+     * for this Request.
+     *
+     * @param secure The new isSecure value
+     */
+    public void setSecure(boolean secure) {
+        this.secure = secure;
+    }
+
+
+    /**
+     * Set the name of the server (virtual host) to process this request.
+     *
+     * @param name The server name
+     */
+    public void setServerName(String name) {
+        coyoteRequest.serverName().setString(name);
+    }
+
+
+    /**
+     * Set the port number of the server to process this request.
+     *
+     * @param port The server port
+     */
+    public void setServerPort(int port) {
+        coyoteRequest.setServerPort(port);
+    }
+
+
+    // ------------------------------------------------- ServletRequest Methods
+
+
+    /**
+     * Return the specified request attribute if it exists; otherwise, return
+     * <code>null</code>.
+     *
+     * @param name Name of the request attribute to return
+     */
+    public Object getAttribute(String name) {
+        Object attr=attributes.get(name);
+
+        if(attr!=null)
+            return(attr);
+
+        attr =  coyoteRequest.getAttribute(name);
+        if(attr != null) {
+            attributes.put(name, attr);
+            return attr;
+        }
+        // XXX Should move to Globals
+        if(Constants.SSL_CERTIFICATE_ATTR.equals(name)) {
+            coyoteRequest.action(ActionCode.ACTION_REQ_SSL_CERTIFICATE, null);
+            attr = getAttribute(Globals.CERTIFICATES_ATTR);
+            if(attr != null)
+                attributes.put(name, attr);
+        }
+        return attr;
+    }
+
+    /**
+     * Return the names of all request attributes for this Request, or an
+     * empty <code>Enumeration</code> if there are none.
+     */
+    public Enumeration getAttributeNames() {
+        return (new Enumerator(attributes.keySet()));
+    }
+
+
+    /**
+     * Return the character encoding for this Request.
+     */
+    public String getCharacterEncoding() {
+      return (coyoteRequest.getCharacterEncoding());
+    }
+
+
+    /**
+     * Return the content length for this Request.
+     */
+    public int getContentLength() {
+        return (coyoteRequest.getContentLength());
+    }
+
+
+    /**
+     * Return the content type for this Request.
+     */
+    public String getContentType() {
+        return (coyoteRequest.getContentType());
+    }
+
+
+    /**
+     * Return the servlet input stream for this Request.  The default
+     * implementation returns a servlet input stream created by
+     * <code>createInputStream()</code>.
+     *
+     * @exception IllegalStateException if <code>getReader()</code> has
+     *  already been called for this request
+     * @exception IOException if an input/output error occurs
+     */
+    public ServletInputStream getInputStream() throws IOException {
+
+        if (usingReader)
+            throw new IllegalStateException
+                (sm.getString("coyoteRequest.getInputStream.ise"));
+
+        usingInputStream = true;
+        return inputStream;
+
+    }
+
+
+    /**
+     * Return the preferred Locale that the client will accept content in,
+     * based on the value for the first <code>Accept-Language</code> header
+     * that was encountered.  If the request did not specify a preferred
+     * language, the server's default Locale is returned.
+     */
+    public Locale getLocale() {
+
+        if (!localesParsed)
+            parseLocales();
+
+        if (locales.size() > 0) {
+            return ((Locale) locales.get(0));
+        } else {
+            return (defaultLocale);
+        }
+
+    }
+
+
+    /**
+     * Return the set of preferred Locales that the client will accept
+     * content in, based on the values for any <code>Accept-Language</code>
+     * headers that were encountered.  If the request did not specify a
+     * preferred language, the server's default Locale is returned.
+     */
+    public Enumeration getLocales() {
+
+        if (!localesParsed)
+            parseLocales();
+
+        if (locales.size() > 0)
+            return (new Enumerator(locales));
+        ArrayList results = new ArrayList();
+        results.add(defaultLocale);
+        return (new Enumerator(results));
+
+    }
+
+
+    /**
+     * Return the value of the specified request parameter, if any; otherwise,
+     * return <code>null</code>.  If there is more than one value defined,
+     * return only the first one.
+     *
+     * @param name Name of the desired request parameter
+     */
+    public String getParameter(String name) {
+
+        if (!requestParametersParsed)
+            parseRequestParameters();
+
+        return coyoteRequest.getParameters().getParameter(name);
+
+    }
+
+
+
+    /**
+     * Returns a <code>Map</code> of the parameters of this request.
+     * Request parameters are extra information sent with the request.
+     * For HTTP servlets, parameters are contained in the query string
+     * or posted form data.
+     *
+     * @return A <code>Map</code> containing parameter names as keys
+     *  and parameter values as map values.
+     */
+    public Map getParameterMap() {
+
+        if (parameterMap.isLocked())
+            return parameterMap;
+
+        Enumeration paramNames = getParameterNames();
+        while (paramNames.hasMoreElements()) {
+            String name = paramNames.nextElement().toString();
+            String[] values = getParameterValues(name);
+            parameterMap.put(name, values);
+        }
+
+        parameterMap.setLocked(true);
+
+        return parameterMap;
+
+    }
+
+
+    /**
+     * Return the names of all defined request parameters for this request.
+     */
+    public Enumeration getParameterNames() {
+
+        if (!requestParametersParsed)
+            parseRequestParameters();
+
+        return coyoteRequest.getParameters().getParameterNames();
+
+    }
+
+
+    /**
+     * Return the defined values for the specified request parameter, if any;
+     * otherwise, return <code>null</code>.
+     *
+     * @param name Name of the desired request parameter
+     */
+    public String[] getParameterValues(String name) {
+
+        if (!requestParametersParsed)
+            parseRequestParameters();
+
+        return coyoteRequest.getParameters().getParameterValues(name);
+
+    }
+
+
+    /**
+     * Return the protocol and version used to make this Request.
+     */
+    public String getProtocol() {
+        return coyoteRequest.protocol().toString();
+    }
+
+
+    /**
+     * Read the Reader wrapping the input stream for this Request.  The
+     * default implementation wraps a <code>BufferedReader</code> around the
+     * servlet input stream returned by <code>createInputStream()</code>.
+     *
+     * @exception IllegalStateException if <code>getInputStream()</code>
+     *  has already been called for this request
+     * @exception IOException if an input/output error occurs
+     */
+    public BufferedReader getReader() throws IOException {
+
+        if (usingInputStream)
+            throw new IllegalStateException
+                (sm.getString("coyoteRequest.getReader.ise"));
+
+        usingReader = true;
+        if (reader == null) {
+            String encoding = getCharacterEncoding();
+            if (encoding == null) {
+                encoding = 
+                    org.apache.coyote.Constants.DEFAULT_CHARACTER_ENCODING;
+            }
+            InputStreamReader r = new InputStreamReader(inputStream, encoding);
+            reader = new BufferedReader(r);
+        }
+        return (reader);
+
+    }
+
+
+    /**
+     * Return the real path of the specified virtual path.
+     *
+     * @param path Path to be translated
+     *
+     * @deprecated As of version 2.1 of the Java Servlet API, use
+     *  <code>ServletContext.getRealPath()</code>.
+     */
+    public String getRealPath(String path) {
+
+        if (context == null)
+            return (null);
+        ServletContext servletContext = context.getServletContext();
+        if (servletContext == null)
+            return (null);
+        else {
+            try {
+                return (servletContext.getRealPath(path));
+            } catch (IllegalArgumentException e) {
+                return (null);
+            }
+        }
+
+    }
+
+
+    /**
+     * Return the remote IP address making this Request.
+     */
+    public String getRemoteAddr() {
+        if (remoteAddr == null) {
+            if (socket != null) {
+                InetAddress inet = socket.getInetAddress();
+                remoteAddr = inet.getHostAddress();
+            } else {
+                coyoteRequest.action
+                    (ActionCode.ACTION_REQ_HOST_ADDR_ATTRIBUTE, coyoteRequest);
+                remoteAddr = coyoteRequest.remoteAddr().toString();
+            }
+        }
+        return remoteAddr;
+    }
+
+
+    /**
+     * Return the remote host name making this Request.
+     */
+    public String getRemoteHost() {
+        if (remoteHost == null) {
+            if (!connector.getEnableLookups()) {
+                remoteHost = getRemoteAddr();
+            } else if (socket != null) {
+                InetAddress inet = socket.getInetAddress();
+                remoteHost = inet.getHostName();
+            } else {
+                coyoteRequest.action
+                    (ActionCode.ACTION_REQ_HOST_ATTRIBUTE, coyoteRequest);
+                remoteHost = coyoteRequest.remoteHost().toString();
+            }
+        }
+        return remoteHost;
+    }
+
+
+    /**
+     * Return a RequestDispatcher that wraps the resource at the specified
+     * path, which may be interpreted as relative to the current request path.
+     *
+     * @param path Path of the resource to be wrapped
+     */
+    public RequestDispatcher getRequestDispatcher(String path) {
+
+        if (context == null)
+            return (null);
+
+        // If the path is already context-relative, just pass it through
+        if (path == null)
+            return (null);
+        else if (path.startsWith("/"))
+            return (context.getServletContext().getRequestDispatcher(path));
+
+        // Convert a request-relative path to a context-relative one
+        String servletPath = (String) getAttribute(Globals.SERVLET_PATH_ATTR);
+        if (servletPath == null)
+            servletPath = getServletPath();
+
+        // Add the path info, if there is any
+        String pathInfo = getPathInfo();
+        String requestPath = null;
+
+        if (pathInfo == null) {
+            requestPath = servletPath;
+        } else {
+            requestPath = servletPath + pathInfo;
+        }
+
+        int pos = requestPath.lastIndexOf('/');
+        String relative = null;
+        if (pos >= 0) {
+            relative = RequestUtil.normalize
+                (requestPath.substring(0, pos + 1) + path);
+        } else {
+            relative = RequestUtil.normalize(requestPath + path);
+        }
+
+        return (context.getServletContext().getRequestDispatcher(relative));
+
+    }
+
+
+    /**
+     * Return the scheme used to make this Request.
+     */
+    public String getScheme() {
+        return (coyoteRequest.scheme().toString());
+    }
+
+
+    /**
+     * Return the server name responding to this Request.
+     */
+    public String getServerName() {
+        return (coyoteRequest.serverName().toString());
+    }
+
+
+    /**
+     * Return the server port responding to this Request.
+     */
+    public int getServerPort() {
+        return (coyoteRequest.getServerPort());
+    }
+
+
+    /**
+     * Was this request received on a secure connection?
+     */
+    public boolean isSecure() {
+        return (secure);
+    }
+
+
+    /**
+     * Remove the specified request attribute if it exists.
+     *
+     * @param name Name of the request attribute to remove
+     */
+    public void removeAttribute(String name) {
+        attributes.remove(name);
+    }
+
+
+    /**
+     * Set the specified request attribute to the specified value.
+     *
+     * @param name Name of the request attribute to set
+     * @param value The associated value
+     */
+    public void setAttribute(String name, Object value) {
+	
+        // Name cannot be null
+        if (name == null)
+            throw new IllegalArgumentException
+                (sm.getString("coyoteRequest.setAttribute.namenull"));
+
+        // Null value is the same as removeAttribute()
+        if (value == null) {
+            removeAttribute(name);
+            return;
+        }
+
+        attributes.put(name, value);
+
+    }
+
+
+    /**
+     * Overrides the name of the character encoding used in the body of
+     * this request.  This method must be called prior to reading request
+     * parameters or reading input using <code>getReader()</code>.
+     *
+     * @param enc The character encoding to be used
+     *
+     * @exception UnsupportedEncodingException if the specified encoding
+     *  is not supported
+     *
+     * @since Servlet 2.3
+     */
+    public void setCharacterEncoding(String enc)
+        throws UnsupportedEncodingException {
+
+        // Ensure that the specified encoding is valid
+        byte buffer[] = new byte[1];
+        buffer[0] = (byte) 'a';
+        String dummy = new String(buffer, enc);
+
+        // Save the validated encoding
+        coyoteRequest.setCharacterEncoding(enc);
+
+    }
+
+
+    // ---------------------------------------------------- HttpRequest Methods
+
+
+    /**
+     * Add a Cookie to the set of Cookies associated with this Request.
+     *
+     * @param cookie The new cookie
+     */
+    public void addCookie(Cookie cookie) {
+
+        // For compatibility only
+
+        int size = 0;
+        if (cookies != null) {
+            size = cookies.length;
+        }
+
+        Cookie[] newCookies = new Cookie[size + 1];
+        for (int i = 0; i < size; i++) {
+            newCookies[i] = cookies[i];
+        }
+        newCookies[size] = cookie;
+
+        cookies = newCookies;
+
+    }
+
+
+    /**
+     * Add a Header to the set of Headers associated with this Request.
+     *
+     * @param name The new header name
+     * @param value The new header value
+     */
+    public void addHeader(String name, String value) {
+        // Not used
+    }
+
+
+    /**
+     * Add a Locale to the set of preferred Locales for this Request.  The
+     * first added Locale will be the first one returned by getLocales().
+     *
+     * @param locale The new preferred Locale
+     */
+    public void addLocale(Locale locale) {
+        locales.add(locale);
+    }
+
+
+    /**
+     * Add a parameter name and corresponding set of values to this Request.
+     * (This is used when restoring the original request on a form based
+     * login).
+     *
+     * @param name Name of this request parameter
+     * @param values Corresponding values for this request parameter
+     */
+    public void addParameter(String name, String values[]) {
+        coyoteRequest.getParameters().addParameterValues(name, values);
+    }
+
+
+    /**
+     * Clear the collection of Cookies associated with this Request.
+     */
+    public void clearCookies() {
+        cookies = null;
+    }
+
+
+    /**
+     * Clear the collection of Headers associated with this Request.
+     */
+    public void clearHeaders() {
+        // Not used
+    }
+
+
+    /**
+     * Clear the collection of Locales associated with this Request.
+     */
+    public void clearLocales() {
+        locales.clear();
+    }
+
+
+    /**
+     * Clear the collection of parameters associated with this Request.
+     */
+    public void clearParameters() {
+        // Not used
+    }
+
+
+    /**
+     * Set the authentication type used for this request, if any; otherwise
+     * set the type to <code>null</code>.  Typical values are "BASIC",
+     * "DIGEST", or "SSL".
+     *
+     * @param type The authentication type used
+     */
+    public void setAuthType(String type) {
+        this.authType = type;
+    }
+
+
+    /**
+     * Set the context path for this Request.  This will normally be called
+     * when the associated Context is mapping the Request to a particular
+     * Wrapper.
+     *
+     * @param path The context path
+     */
+    public void setContextPath(String path) {
+
+        if (path == null) {
+            this.contextPath = "";
+        } else {
+            this.contextPath = path;
+        }
+
+    }
+
+
+    /**
+     * Set the HTTP request method used for this Request.
+     *
+     * @param method The request method
+     */
+    public void setMethod(String method) {
+        // Not used
+    }
+
+
+    /**
+     * Set the query string for this Request.  This will normally be called
+     * by the HTTP Connector, when it parses the request headers.
+     *
+     * @param query The query string
+     */
+    public void setQueryString(String query) {
+        // Not used
+    }
+
+
+    /**
+     * Set the path information for this Request.  This will normally be called
+     * when the associated Context is mapping the Request to a particular
+     * Wrapper.
+     *
+     * @param path The path information
+     */
+    public void setPathInfo(String path) {
+        this.pathInfo = path;
+    }
+
+
+    /**
+     * Set a flag indicating whether or not the requested session ID for this
+     * request came in through a cookie.  This is normally called by the
+     * HTTP Connector, when it parses the request headers.
+     *
+     * @param flag The new flag
+     */
+    public void setRequestedSessionCookie(boolean flag) {
+
+        this.requestedSessionCookie = flag;
+
+    }
+
+
+    /**
+     * Set the requested session ID for this request.  This is normally called
+     * by the HTTP Connector, when it parses the request headers.
+     *
+     * @param id The new session id
+     */
+    public void setRequestedSessionId(String id) {
+
+        this.requestedSessionId = id;
+
+    }
+
+
+    /**
+     * Set a flag indicating whether or not the requested session ID for this
+     * request came in through a URL.  This is normally called by the
+     * HTTP Connector, when it parses the request headers.
+     *
+     * @param flag The new flag
+     */
+    public void setRequestedSessionURL(boolean flag) {
+
+        this.requestedSessionURL = flag;
+
+    }
+
+
+    /**
+     * Set the unparsed request URI for this Request.  This will normally be
+     * called by the HTTP Connector, when it parses the request headers.
+     *
+     * @param uri The request URI
+     */
+    public void setRequestURI(String uri) {
+        // Not used
+    }
+
+
+    /**
+     * Set the decoded request URI.
+     * 
+     * @param uri The decoded request URI
+     */
+    public void setDecodedRequestURI(String uri) {
+        // Not used
+    }
+
+
+    /**
+     * Get the decoded request URI.
+     * 
+     * @return the URL decoded request URI
+     */
+    public String getDecodedRequestURI() {
+        return (coyoteRequest.decodedURI().toString());
+    }
+
+
+    /**
+     * Set the servlet path for this Request.  This will normally be called
+     * when the associated Context is mapping the Request to a particular
+     * Wrapper.
+     *
+     * @param path The servlet path
+     */
+    public void setServletPath(String path) {
+        this.servletPath = path;
+    }
+
+
+    /**
+     * Set the Principal who has been authenticated for this Request.  This
+     * value is also used to calculate the value to be returned by the
+     * <code>getRemoteUser()</code> method.
+     *
+     * @param principal The user Principal
+     */
+    public void setUserPrincipal(Principal principal) {
+        this.userPrincipal = principal;
+    }
+
+
+    // --------------------------------------------- HttpServletRequest Methods
+
+
+    /**
+     * Return the authentication type used for this Request.
+     */
+    public String getAuthType() {
+        return (authType);
+    }
+
+
+    /**
+     * Return the portion of the request URI used to select the Context
+     * of the Request.
+     */
+    public String getContextPath() {
+        return (contextPath);
+    }
+
+
+    /**
+     * Return the set of Cookies received with this Request.
+     */
+    public Cookie[] getCookies() {
+
+        return cookies;
+
+    }
+
+
+    /**
+     * Set the set of cookies recieved with this Request.
+     */
+    public void setCookies(Cookie[] cookies) {
+
+        this.cookies = cookies;
+
+    }
+
+
+    /**
+     * Return the value of the specified date header, if any; otherwise
+     * return -1.
+     *
+     * @param name Name of the requested date header
+     *
+     * @exception IllegalArgumentException if the specified header value
+     *  cannot be converted to a date
+     */
+    public long getDateHeader(String name) {
+
+        String value = getHeader(name);
+        if (value == null)
+            return (-1L);
+
+        // Work around a bug in SimpleDateFormat in pre-JDK1.2b4
+        // (Bug Parade bug #4106807)
+        value += " ";
+
+        // Attempt to convert the date header in a variety of formats
+        for (int i = 0; i < formats.length; i++) {
+            try {
+                Date date = formats[i].parse(value);
+                return (date.getTime());
+            } catch (ParseException e) {
+                ;
+            }
+        }
+        throw new IllegalArgumentException(value);
+
+    }
+
+
+    /**
+     * Return the first value of the specified header, if any; otherwise,
+     * return <code>null</code>
+     *
+     * @param name Name of the requested header
+     */
+    public String getHeader(String name) {
+        return coyoteRequest.getHeader(name);
+    }
+
+
+    /**
+     * Return all of the values of the specified header, if any; otherwise,
+     * return an empty enumeration.
+     *
+     * @param name Name of the requested header
+     */
+    public Enumeration getHeaders(String name) {
+        return coyoteRequest.getMimeHeaders().values(name);
+    }
+
+
+    /**
+     * Return the names of all headers received with this request.
+     */
+    public Enumeration getHeaderNames() {
+        return coyoteRequest.getMimeHeaders().names();
+    }
+
+
+    /**
+     * Return the value of the specified header as an integer, or -1 if there
+     * is no such header for this request.
+     *
+     * @param name Name of the requested header
+     *
+     * @exception IllegalArgumentException if the specified header value
+     *  cannot be converted to an integer
+     */
+    public int getIntHeader(String name) {
+
+        String value = getHeader(name);
+        if (value == null) {
+            return (-1);
+        } else {
+            return (Integer.parseInt(value));
+        }
+
+    }
+
+
+    /**
+     * Return the HTTP request method used in this Request.
+     */
+    public String getMethod() {
+        return coyoteRequest.method().toString();
+    }
+
+
+    /**
+     * Return the path information associated with this Request.
+     */
+    public String getPathInfo() {
+        return (pathInfo);
+    }
+
+
+    /**
+     * Return the extra path information for this request, translated
+     * to a real path.
+     */
+    public String getPathTranslated() {
+
+        if (context == null)
+            return (null);
+
+        if (pathInfo == null) {
+            return (null);
+        } else {
+            return (context.getServletContext().getRealPath(pathInfo));
+        }
+
+    }
+
+
+    /**
+     * Return the query string associated with this request.
+     */
+    public String getQueryString() {
+        String queryString = coyoteRequest.queryString().toString();
+        if (queryString == null || queryString.equals("")) {
+            return (null);
+        } else {
+            return queryString;
+        }
+    }
+
+
+    /**
+     * Return the name of the remote user that has been authenticated
+     * for this Request.
+     */
+    public String getRemoteUser() {
+
+        if (userPrincipal != null) {
+            return (userPrincipal.getName());
+        } else {
+            return (null);
+        }
+
+    }
+
+
+    /**
+     * Return the session identifier included in this request, if any.
+     */
+    public String getRequestedSessionId() {
+        return (requestedSessionId);
+    }
+
+
+    /**
+     * Return the request URI for this request.
+     */
+    public String getRequestURI() {
+        return coyoteRequest.requestURI().toString();
+    }
+
+
+    /**
+     * Reconstructs the URL the client used to make the request.
+     * The returned URL contains a protocol, server name, port
+     * number, and server path, but it does not include query
+     * string parameters.
+     * <p>
+     * Because this method returns a <code>StringBuffer</code>,
+     * not a <code>String</code>, you can modify the URL easily,
+     * for example, to append query parameters.
+     * <p>
+     * This method is useful for creating redirect messages and
+     * for reporting errors.
+     *
+     * @return A <code>StringBuffer</code> object containing the
+     *  reconstructed URL
+     */
+    public StringBuffer getRequestURL() {
+
+        StringBuffer url = new StringBuffer();
+        String scheme = getScheme();
+        int port = getServerPort();
+        if (port < 0)
+            port = 80; // Work around java.net.URL bug
+
+        url.append(scheme);
+        url.append("://");
+        url.append(getServerName());
+        if ((scheme.equals("http") && (port != 80))
+            || (scheme.equals("https") && (port != 443))) {
+            url.append(':');
+            url.append(port);
+        }
+        url.append(getRequestURI());
+
+        return (url);
+
+    }
+
+
+    /**
+     * Return the portion of the request URI used to select the servlet
+     * that will process this request.
+     */
+    public String getServletPath() {
+        return (servletPath);
+    }
+
+
+    /**
+     * Return the session associated with this Request, creating one
+     * if necessary.
+     */
+    public HttpSession getSession() {
+        return (getSession(true));
+    }
+
+
+    /**
+     * Return the session associated with this Request, creating one
+     * if necessary and requested.
+     *
+     * @param create Create a new session if one does not exist
+     */
+    public HttpSession getSession(boolean create) {
+
+        if (System.getSecurityManager() != null) {
+            PrivilegedGetSession dp = new PrivilegedGetSession(create);
+            return (HttpSession) AccessController.doPrivileged(dp);
+        }
+        return doGetSession(create);
+
+    }
+
+
+    /**
+     * Return <code>true</code> if the session identifier included in this
+     * request came from a cookie.
+     */
+    public boolean isRequestedSessionIdFromCookie() {
+
+        if (requestedSessionId != null)
+            return (requestedSessionCookie);
+        else
+            return (false);
+
+    }
+
+
+    /**
+     * Return <code>true</code> if the session identifier included in this
+     * request came from the request URI.
+     */
+    public boolean isRequestedSessionIdFromURL() {
+
+        if (requestedSessionId != null)
+            return (requestedSessionURL);
+        else
+            return (false);
+
+    }
+
+
+    /**
+     * Return <code>true</code> if the session identifier included in this
+     * request came from the request URI.
+     *
+     * @deprecated As of Version 2.1 of the Java Servlet API, use
+     *  <code>isRequestedSessionIdFromURL()</code> instead.
+     */
+    public boolean isRequestedSessionIdFromUrl() {
+        return (isRequestedSessionIdFromURL());
+    }
+
+
+    /**
+     * Return <code>true</code> if the session identifier included in this
+     * request identifies a valid session.
+     */
+    public boolean isRequestedSessionIdValid() {
+
+        if (requestedSessionId == null)
+            return (false);
+        if (context == null)
+            return (false);
+        Manager manager = context.getManager();
+        if (manager == null)
+            return (false);
+        Session session = null;
+        try {
+            session = manager.findSession(requestedSessionId);
+        } catch (IOException e) {
+            session = null;
+        }
+        if ((session != null) && session.isValid())
+            return (true);
+        else
+            return (false);
+
+    }
+
+
+    /**
+     * Return <code>true</code> if the authenticated user principal
+     * possesses the specified role name.
+     *
+     * @param role Role name to be validated
+     */
+    public boolean isUserInRole(String role) {
+
+        // Have we got an authenticated principal at all?
+        if (userPrincipal == null)
+            return (false);
+
+        // Identify the Realm we will use for checking role assignmenets
+        if (context == null)
+            return (false);
+        Realm realm = context.getRealm();
+        if (realm == null)
+            return (false);
+
+        // Check for a role alias defined in a <security-role-ref> element
+        if (wrapper != null) {
+            String realRole = wrapper.findSecurityReference(role);
+            if ((realRole != null) &&
+                realm.hasRole(userPrincipal, realRole))
+                return (true);
+        }
+
+        // Check for a role defined directly as a <security-role>
+        return (realm.hasRole(userPrincipal, role));
+
+    }
+
+
+    /**
+     * Return the principal that has been authenticated for this Request.
+     */
+    public Principal getUserPrincipal() {
+        return (userPrincipal);
+    }
+
+
+    // ------------------------------------------------------ Protected Methods
+
+
+    protected HttpSession doGetSession(boolean create) {
+
+        // There cannot be a session if no context has been assigned yet
+        if (context == null)
+            return (null);
+
+        // Return the current session if it exists and is valid
+        if ((session != null) && !session.isValid())
+            session = null;
+        if (session != null)
+            return (session.getSession());
+
+        // Return the requested session if it exists and is valid
+        Manager manager = null;
+        if (context != null)
+            manager = context.getManager();
+        if (manager == null)
+            return (null);      // Sessions are not supported
+        if (requestedSessionId != null) {
+            try {
+                session = manager.findSession(requestedSessionId);
+            } catch (IOException e) {
+                session = null;
+            }
+            if ((session != null) && !session.isValid())
+                session = null;
+            if (session != null) {
+                return (session.getSession());
+            }
+        }
+
+        // Create a new session if requested and the response is not committed
+        if (!create)
+            return (null);
+        if ((context != null) && (response != null) &&
+            context.getCookies() &&
+            response.getResponse().isCommitted()) {
+            throw new IllegalStateException
+              (sm.getString("coyoteRequest.sessionCreateCommitted"));
+        }
+
+        session = manager.createSession();
+
+        // Creating a new session cookie based on that session
+        if ((session != null) && (getContext() != null)
+            && getContext().getCookies()) {
+            Cookie cookie = new Cookie(Globals.SESSION_COOKIE_NAME,
+                                       session.getId());
+            cookie.setMaxAge(-1);
+            String contextPath = null;
+            if (context != null)
+                contextPath = context.getPath();
+            if ((contextPath != null) && (contextPath.length() > 0))
+                cookie.setPath(contextPath);
+            else
+                cookie.setPath("/");
+            if (isSecure())
+                cookie.setSecure(true);
+            ((HttpServletResponse) response).addCookie(cookie);
+        }
+
+        if (session != null)
+            return (session.getSession());
+        else
+            return (null);
+
+    }
+
+
+    /**
+     * Parse request parameters.
+     */
+    protected void parseRequestParameters() {
+
+        requestParametersParsed = true;
+
+        Parameters parameters = coyoteRequest.getParameters();
+
+        String enc = coyoteRequest.getCharacterEncoding();
+        boolean useBodyEncodingForURI = connector.getUseBodyEncodingForURI();
+        if (enc != null) {
+            parameters.setEncoding(enc);
+            if (useBodyEncodingForURI) {
+                parameters.setQueryStringEncoding(enc);
+            }
+        } else {
+            parameters.setEncoding
+                (org.apache.coyote.Constants.DEFAULT_CHARACTER_ENCODING);
+            if (useBodyEncodingForURI) {
+                parameters.setQueryStringEncoding
+                    (org.apache.coyote.Constants.DEFAULT_CHARACTER_ENCODING);
+            }
+        }
+
+        parameters.handleQueryParameters();
+
+        if (usingInputStream || usingReader)
+            return;
+
+        if (!getMethod().equalsIgnoreCase("POST"))
+            return;
+
+        String contentType = getContentType();
+        if (contentType == null)
+            contentType = "";
+        int semicolon = contentType.indexOf(';');
+        if (semicolon >= 0) {
+            contentType = contentType.substring(0, semicolon).trim();
+        } else {
+            contentType = contentType.trim();
+        }
+        if (!("application/x-www-form-urlencoded".equals(contentType)))
+            return;
+
+        int len = getContentLength();
+
+        if (len > 0) {
+            try {
+                byte[] formData = null;
+                if (len < CACHED_POST_LEN) {
+                    if (postData == null)
+                        postData = new byte[CACHED_POST_LEN];
+                    formData = postData;
+                } else {
+                    formData = new byte[len];
+                }
+                int actualLen = readPostBody(formData, len);
+                if (actualLen == len) {
+                    parameters.processParameters(formData, 0, len);
+                }
+            } catch (Throwable t) {
+                ; // Ignore
+            }
+        }
+
+    }
+
+
+    /**
+     * Read post body in an array.
+     */
+    protected int readPostBody(byte body[], int len)
+        throws IOException {
+
+        int offset = 0;
+        do {
+            int inputLen = getStream().read(body, offset, len - offset);
+            if (inputLen <= 0) {
+                return offset;
+            }
+            offset += inputLen;
+        } while ((len - offset) > 0);
+        return len;
+
+    }
+
+
+    /**
+     * Parse request locales.
+     */
+    protected void parseLocales() {
+
+        localesParsed = true;
+
+        Enumeration values = getHeaders("accept-language");
+
+        while (values.hasMoreElements()) {
+            String value = values.nextElement().toString();
+            parseLocalesHeader(value);
+        }
+
+    }
+
+
+    /**
+     * Parse accept-language header value.
+     */
+    protected void parseLocalesHeader(String value) {
+
+        // Store the accumulated languages that have been requested in
+        // a local collection, sorted by the quality value (so we can
+        // add Locales in descending order).  The values will be ArrayLists
+        // containing the corresponding Locales to be added
+        TreeMap locales = new TreeMap();
+
+        // Preprocess the value to remove all whitespace
+        int white = value.indexOf(' ');
+        if (white < 0)
+            white = value.indexOf('\t');
+        if (white >= 0) {
+            StringBuffer sb = new StringBuffer();
+            int len = value.length();
+            for (int i = 0; i < len; i++) {
+                char ch = value.charAt(i);
+                if ((ch != ' ') && (ch != '\t'))
+                    sb.append(ch);
+            }
+            value = sb.toString();
+        }
+
+        // Process each comma-delimited language specification
+        parser.setString(value);        // ASSERT: parser is available to us
+        int length = parser.getLength();
+        while (true) {
+
+            // Extract the next comma-delimited entry
+            int start = parser.getIndex();
+            if (start >= length)
+                break;
+            int end = parser.findChar(',');
+            String entry = parser.extract(start, end).trim();
+            parser.advance();   // For the following entry
+
+            // Extract the quality factor for this entry
+            double quality = 1.0;
+            int semi = entry.indexOf(";q=");
+            if (semi >= 0) {
+                try {
+                    quality = Double.parseDouble(entry.substring(semi + 3));
+                } catch (NumberFormatException e) {
+                    quality = 0.0;
+                }
+                entry = entry.substring(0, semi);
+            }
+
+            // Skip entries we are not going to keep track of
+            if (quality < 0.00005)
+                continue;       // Zero (or effectively zero) quality factors
+            if ("*".equals(entry))
+                continue;       // FIXME - "*" entries are not handled
+
+            // Extract the language and country for this entry
+            String language = null;
+            String country = null;
+            String variant = null;
+            int dash = entry.indexOf('-');
+            if (dash < 0) {
+                language = entry;
+                country = "";
+                variant = "";
+            } else {
+                language = entry.substring(0, dash);
+                country = entry.substring(dash + 1);
+                int vDash = country.indexOf('-');
+                if (vDash > 0) {
+                    String cTemp = country.substring(0, vDash);
+                    variant = country.substring(vDash + 1);
+                    country = cTemp;
+                } else {
+                    variant = "";
+                }
+            }
+
+            // Add a new Locale to the list of Locales for this quality level
+            Locale locale = new Locale(language, country, variant);
+            Double key = new Double(-quality);  // Reverse the order
+            ArrayList values = (ArrayList) locales.get(key);
+            if (values == null) {
+                values = new ArrayList();
+                locales.put(key, values);
+            }
+            values.add(locale);
+
+        }
+
+        // Process the quality values in highest->lowest order (due to
+        // negating the Double value when creating the key)
+        Iterator keys = locales.keySet().iterator();
+        while (keys.hasNext()) {
+            Double key = (Double) keys.next();
+            ArrayList list = (ArrayList) locales.get(key);
+            Iterator values = list.iterator();
+            while (values.hasNext()) {
+                Locale locale = (Locale) values.next();
+                addLocale(locale);
+            }
+        }
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/java/org/apache/coyote/tomcat4/CoyoteRequestFacade.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/java/org/apache/coyote/tomcat4/CoyoteRequestFacade.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/java/org/apache/coyote/tomcat4/CoyoteRequestFacade.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,342 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.tomcat4;
+
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.util.Enumeration;
+import java.util.Locale;
+import java.util.Map;
+
+import javax.servlet.RequestDispatcher;
+import javax.servlet.ServletInputStream;
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpSession;
+
+import org.apache.catalina.connector.RequestFacade;
+
+
+/**
+ * Facade class that wraps a Coyote request object.  
+ * All methods are delegated to the wrapped request.
+ *
+ * @author Craig R. McClanahan
+ * @author Remy Maucherat
+ * @version $Revision: 299222 $ $Date: 2004-02-24 03:02:18 -0600 (Tue, 24 Feb 2004) $
+ */
+
+public class CoyoteRequestFacade 
+    extends RequestFacade
+    implements HttpServletRequest {
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Construct a wrapper for the specified request.
+     *
+     * @param request The request to be wrapped
+     */
+    public CoyoteRequestFacade(CoyoteRequest request) {
+
+        super(request);
+        this.request = request;
+
+    }
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The wrapped request.
+     */
+    protected CoyoteRequest request = null;
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Clear facade.
+     */
+    public void clear() {
+        request = null;
+    }
+
+
+    // ------------------------------------------------- ServletRequest Methods
+
+
+    public Object getAttribute(String name) {
+        return request.getAttribute(name);
+    }
+
+
+    public Enumeration getAttributeNames() {
+        return request.getAttributeNames();
+    }
+
+
+    public String getCharacterEncoding() {
+        return request.getCharacterEncoding();
+    }
+
+
+    public void setCharacterEncoding(String env)
+        throws java.io.UnsupportedEncodingException {
+        request.setCharacterEncoding(env);
+    }
+
+
+    public int getContentLength() {
+        return request.getContentLength();
+    }
+
+
+    public String getContentType() {
+        return request.getContentType();
+    }
+
+
+    public ServletInputStream getInputStream()
+        throws IOException {
+        return request.getInputStream();
+    }
+
+
+    public String getParameter(String name) {
+        return request.getParameter(name);
+    }
+
+
+    public Enumeration getParameterNames() {
+        return request.getParameterNames();
+    }
+
+
+    public String[] getParameterValues(String name) {
+        return request.getParameterValues(name);
+    }
+
+
+    public Map getParameterMap() {
+        return request.getParameterMap();
+    }
+
+
+    public String getProtocol() {
+        return request.getProtocol();
+    }
+
+
+    public String getScheme() {
+        return request.getScheme();
+    }
+
+
+    public String getServerName() {
+        return request.getServerName();
+    }
+
+
+    public int getServerPort() {
+        return request.getServerPort();
+    }
+
+
+    public BufferedReader getReader()
+        throws IOException {
+        return request.getReader();
+    }
+
+
+    public String getRemoteAddr() {
+        return request.getRemoteAddr();
+    }
+
+
+    public String getRemoteHost() {
+        return request.getRemoteHost();
+    }
+
+
+    public void setAttribute(String name, Object o) {
+        request.setAttribute(name, o);
+    }
+
+
+    public void removeAttribute(String name) {
+        request.removeAttribute(name);
+    }
+
+
+    public Locale getLocale() {
+        return request.getLocale();
+    }
+
+
+    public Enumeration getLocales() {
+        return request.getLocales();
+    }
+
+
+    public boolean isSecure() {
+        return request.isSecure();
+    }
+
+
+    public RequestDispatcher getRequestDispatcher(String path) {
+        // TODO : Facade !!
+        return request.getRequestDispatcher(path);
+    }
+
+
+    public String getRealPath(String path) {
+        return request.getRealPath(path);
+    }
+
+
+    public String getAuthType() {
+        return request.getAuthType();
+    }
+
+
+    public Cookie[] getCookies() {
+        return request.getCookies();
+    }
+
+
+    public long getDateHeader(String name) {
+        return request.getDateHeader(name);
+    }
+
+
+    public String getHeader(String name) {
+        return request.getHeader(name);
+    }
+
+
+    public Enumeration getHeaders(String name) {
+        return request.getHeaders(name);
+    }
+
+
+    public Enumeration getHeaderNames() {
+        return request.getHeaderNames();
+    }
+
+
+    public int getIntHeader(String name) {
+        return request.getIntHeader(name);
+    }
+
+
+    public String getMethod() {
+        return request.getMethod();
+    }
+
+
+    public String getPathInfo() {
+        return request.getPathInfo();
+    }
+
+
+    public String getPathTranslated() {
+        return request.getPathTranslated();
+    }
+
+
+    public String getContextPath() {
+        return request.getContextPath();
+    }
+
+
+    public String getQueryString() {
+        return request.getQueryString();
+    }
+
+
+    public String getRemoteUser() {
+        return request.getRemoteUser();
+    }
+
+
+    public boolean isUserInRole(String role) {
+        return request.isUserInRole(role);
+    }
+
+
+    public java.security.Principal getUserPrincipal() {
+        return request.getUserPrincipal();
+    }
+
+
+    public String getRequestedSessionId() {
+        return request.getRequestedSessionId();
+    }
+
+
+    public String getRequestURI() {
+        return request.getRequestURI();
+    }
+
+
+    public StringBuffer getRequestURL() {
+        return request.getRequestURL();
+    }
+
+
+    public String getServletPath() {
+        return request.getServletPath();
+    }
+
+
+    public HttpSession getSession(boolean create) {
+        return request.getSession(create);
+    }
+
+
+    public HttpSession getSession() {
+        return getSession(true);
+    }
+
+
+    public boolean isRequestedSessionIdValid() {
+        return request.isRequestedSessionIdValid();
+    }
+
+
+    public boolean isRequestedSessionIdFromCookie() {
+        return request.isRequestedSessionIdFromCookie();
+    }
+
+
+    public boolean isRequestedSessionIdFromURL() {
+        return request.isRequestedSessionIdFromURL();
+    }
+
+
+    public boolean isRequestedSessionIdFromUrl() {
+        return request.isRequestedSessionIdFromURL();
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/java/org/apache/coyote/tomcat4/CoyoteResponse.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/java/org/apache/coyote/tomcat4/CoyoteResponse.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/java/org/apache/coyote/tomcat4/CoyoteResponse.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,1324 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.tomcat4;
+
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.PrintWriter;
+import java.net.MalformedURLException;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.Locale;
+import java.util.TimeZone;
+import java.util.Vector;
+
+import javax.servlet.ServletOutputStream;
+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 org.apache.catalina.Connector;
+import org.apache.catalina.Context;
+import org.apache.catalina.HttpResponse;
+import org.apache.catalina.util.CharsetMapper;
+import org.apache.catalina.util.StringManager;
+import org.apache.coyote.Response;
+import org.apache.tomcat.util.buf.CharChunk;
+import org.apache.tomcat.util.buf.UEncoder;
+import org.apache.tomcat.util.http.MimeHeaders;
+import org.apache.tomcat.util.http.ServerCookie;
+import org.apache.tomcat.util.net.URL;
+
+
+/**
+ * Wrapper object for the Coyote response.
+ *
+ * @author Remy Maucherat
+ * @author Craig R. McClanahan
+ * @version $Revision: 368124 $ $Date: 2006-01-11 14:45:30 -0600 (Wed, 11 Jan 2006) $
+ */
+
+public class CoyoteResponse
+    implements HttpResponse, HttpServletResponse {
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    public CoyoteResponse() {
+
+        format.setTimeZone(TimeZone.getTimeZone("GMT"));
+        urlEncoder.addSafeCharacter('/');
+
+    }
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The date format we will use for creating date headers.
+     */
+    protected final SimpleDateFormat format =
+        new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US);
+
+
+    /**
+     * Descriptive information about this Response implementation.
+     */
+    protected static final String info =
+        "org.apache.coyote.tomcat4.CoyoteResponse/1.0";
+
+
+    /**
+     * The string manager for this package.
+     */
+    protected static StringManager sm =
+        StringManager.getManager(Constants.Package);
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * Associated Catalina connector.
+     */
+    protected Connector connector;
+
+    /**
+     * Return the Connector through which this Request was received.
+     */
+    public Connector getConnector() {
+        return (this.connector);
+    }
+
+    /**
+     * Set the Connector through which this Request was received.
+     *
+     * @param connector The new connector
+     */
+    public void setConnector(Connector connector) {
+        this.connector = connector;
+    }
+
+
+    /**
+     * Coyote response.
+     */
+    protected Response coyoteResponse;
+
+    /**
+     * Set the Coyote response.
+     * 
+     * @param coyoteResponse The Coyote response
+     */
+    public void setCoyoteResponse(Response coyoteResponse) {
+        this.coyoteResponse = coyoteResponse;
+        outputBuffer.setResponse(coyoteResponse);
+    }
+
+    /**
+     * Get the Coyote response.
+     */
+    public Response getCoyoteResponse() {
+        return (coyoteResponse);
+    }
+
+
+    /**
+     * The Context within which this Request is being processed.
+     */
+    protected Context context = null;
+
+    /**
+     * Return the Context within which this Request is being processed.
+     */
+    public Context getContext() {
+        return (this.context);
+    }
+
+    /**
+     * Set the Context within which this Request is being processed.  This
+     * must be called as soon as the appropriate Context is identified, because
+     * it identifies the value to be returned by <code>getContextPath()</code>,
+     * and thus enables parsing of the request URI.
+     *
+     * @param context The newly associated Context
+     */
+    public void setContext(Context context) {
+        this.context = context;
+    }
+
+
+    /**
+     * The associated output buffer.
+     */
+    protected OutputBuffer outputBuffer = new OutputBuffer();
+
+
+    /**
+     * The associated output stream.
+     */
+    protected CoyoteOutputStream outputStream = 
+        new CoyoteOutputStream(outputBuffer);
+
+
+    /**
+     * The associated writer.
+     */
+    protected CoyoteWriter writer = new CoyoteWriter(outputBuffer);
+
+
+    /**
+     * The application commit flag.
+     */
+    protected boolean appCommitted = false;
+
+
+    /**
+     * The included flag.
+     */
+    protected boolean included = false;
+
+
+    /**
+     * The error flag.
+     */
+    protected boolean error = false;
+
+
+    /**
+     * The set of Cookies associated with this Response.
+     */
+    protected ArrayList cookies = new ArrayList();
+
+
+    /**
+     * Using output stream flag.
+     */
+    protected boolean usingOutputStream = false;
+
+
+    /**
+     * Using writer flag.
+     */
+    protected boolean usingWriter = false;
+
+
+    /**
+     * URL encoder.
+     */
+    protected UEncoder urlEncoder = new UEncoder();
+
+
+    /**
+     * Recyclable buffer to hold the redirect URL.
+     */
+    protected CharChunk redirectURLCC = new CharChunk();
+
+    
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Release all object references, and initialize instance variables, in
+     * preparation for reuse of this object.
+     */
+    public void recycle() {
+
+        outputBuffer.recycle();
+        usingOutputStream = false;
+        usingWriter = false;
+        appCommitted = false;
+        included = false;
+        error = false;
+        cookies.clear();
+
+        if (facade != null) {
+            facade.clear();
+            facade = null;
+        }
+
+        writer.recycle();
+    }
+
+
+    // ------------------------------------------------------- Response Methods
+
+
+    /**
+     * Return the number of bytes actually written to the output stream.
+     */
+    public int getContentCount() {
+        return outputBuffer.getContentWritten();
+    }
+
+
+    /**
+     * Set the application commit flag.
+     * 
+     * @param appCommitted The new application committed flag value
+     */
+    public void setAppCommitted(boolean appCommitted) {
+        this.appCommitted = appCommitted;
+    }
+
+
+    /**
+     * Application commit flag accessor.
+     */
+    public boolean isAppCommitted() {
+        return (this.appCommitted || isCommitted() || isSuspended());
+    }
+
+
+    /**
+     * Return the "processing inside an include" flag.
+     */
+    public boolean getIncluded() {
+        return included;
+    }
+
+
+    /**
+     * Set the "processing inside an include" flag.
+     *
+     * @param included <code>true</code> if we are currently inside a
+     *  RequestDispatcher.include(), else <code>false</code>
+     */
+    public void setIncluded(boolean included) {
+        this.included = included;
+    }
+
+
+    /**
+     * Return descriptive information about this Response implementation and
+     * the corresponding version number, in the format
+     * <code>&lt;description&gt;/&lt;version&gt;</code>.
+     */
+    public String getInfo() {
+        return (info);
+    }
+
+
+    /**
+     * The request with which this response is associated.
+     */
+    protected CoyoteRequest request = null;
+
+    /**
+     * Return the Request with which this Response is associated.
+     */
+    public org.apache.catalina.Request getRequest() {
+        return (this.request);
+    }
+
+    /**
+     * Set the Request with which this Response is associated.
+     *
+     * @param request The new associated request
+     */
+    public void setRequest(org.apache.catalina.Request request) {
+        this.request = (CoyoteRequest) request;
+    }
+
+
+    /**
+     * The facade associated with this response.
+     */
+    protected CoyoteResponseFacade facade = null;
+
+    /**
+     * Return the <code>ServletResponse</code> for which this object
+     * is the facade.
+     */
+    public ServletResponse getResponse() {
+        if (facade == null) {
+            facade = new CoyoteResponseFacade(this);
+        }
+        return (facade);
+    }
+
+
+    /**
+     * Return the output stream associated with this Response.
+     */
+    public OutputStream getStream() {
+        return outputStream;
+    }
+
+
+    /**
+     * Set the output stream associated with this Response.
+     *
+     * @param stream The new output stream
+     */
+    public void setStream(OutputStream stream) {
+        // This method is evil
+    }
+
+
+    /**
+     * Set the suspended flag.
+     * 
+     * @param suspended The new suspended flag value
+     */
+    public void setSuspended(boolean suspended) {
+        outputBuffer.setSuspended(suspended);
+    }
+
+
+    /**
+     * Suspended flag accessor.
+     */
+    public boolean isSuspended() {
+        return outputBuffer.isSuspended();
+    }
+
+
+    /**
+     * Set the error flag.
+     */
+    public void setError() {
+        error = true;
+    }
+
+
+    /**
+     * Error flag accessor.
+     */
+    public boolean isError() {
+        return error;
+    }
+
+
+    /**
+     * Create and return a ServletOutputStream to write the content
+     * associated with this Response.
+     *
+     * @exception IOException if an input/output error occurs
+     */
+    public ServletOutputStream createOutputStream() 
+        throws IOException {
+        // Probably useless
+        return outputStream;
+    }
+
+
+    /**
+     * Perform whatever actions are required to flush and close the output
+     * stream or writer, in a single operation.
+     *
+     * @exception IOException if an input/output error occurs
+     */
+    public void finishResponse() 
+        throws IOException {
+        // Writing leftover bytes
+        try {
+            outputBuffer.close();
+        } catch(IOException e) {
+            ;
+        } catch(Throwable t) {
+            t.printStackTrace();
+        }
+    }
+
+
+    /**
+     * Return the content length that was set or calculated for this Response.
+     */
+    public int getContentLength() {
+        return (coyoteResponse.getContentLength());
+    }
+
+
+    /**
+     * Return the content type that was set or calculated for this response,
+     * or <code>null</code> if no content type was set.
+     */
+    public String getContentType() {
+        return (coyoteResponse.getContentType());
+    }
+
+
+    /**
+     * Return a PrintWriter that can be used to render error messages,
+     * regardless of whether a stream or writer has already been acquired.
+     *
+     * @return Writer which can be used for error reports. If the response is
+     * not an error report returned using sendError or triggered by an
+     * unexpected exception thrown during the servlet processing
+     * (and only in that case), null will be returned if the response stream
+     * has already been used.
+     */
+    public PrintWriter getReporter() {
+        if (outputBuffer.isNew()) {
+            return writer;
+        } else {
+            return null;
+        }
+    }
+
+
+    // ------------------------------------------------ ServletResponse Methods
+
+
+    /**
+     * Flush the buffer and commit this response.
+     *
+     * @exception IOException if an input/output error occurs
+     */
+    public void flushBuffer() 
+        throws IOException {
+        outputBuffer.flush();
+    }
+
+
+    /**
+     * Return the actual buffer size used for this Response.
+     */
+    public int getBufferSize() {
+        return outputBuffer.getBufferSize();
+    }
+
+
+    /**
+     * Return the character encoding used for this Response.
+     */
+    public String getCharacterEncoding() {
+        return (coyoteResponse.getCharacterEncoding());
+    }
+
+
+    /**
+     * Return the servlet output stream associated with this Response.
+     *
+     * @exception IllegalStateException if <code>getWriter</code> has
+     *  already been called for this response
+     * @exception IOException if an input/output error occurs
+     */
+    public ServletOutputStream getOutputStream() 
+        throws IOException {
+
+        if (usingWriter)
+            throw new IllegalStateException
+                (sm.getString("coyoteResponse.getOutputStream.ise"));
+
+        usingOutputStream = true;
+        return outputStream;
+
+    }
+
+
+    /**
+     * Return the Locale assigned to this response.
+     */
+    public Locale getLocale() {
+        return (coyoteResponse.getLocale());
+    }
+
+
+    /**
+     * Return the writer associated with this Response.
+     *
+     * @exception IllegalStateException if <code>getOutputStream</code> has
+     *  already been called for this response
+     * @exception IOException if an input/output error occurs
+     */
+    public PrintWriter getWriter() 
+        throws IOException {
+
+        if (usingOutputStream)
+            throw new IllegalStateException
+                (sm.getString("coyoteResponse.getWriter.ise"));
+
+        usingWriter = true;
+        return writer;
+
+    }
+
+
+    /**
+     * Has the output of this response already been committed?
+     */
+    public boolean isCommitted() {
+        return (coyoteResponse.isCommitted());
+    }
+
+
+    /**
+     * Clear any content written to the buffer.
+     *
+     * @exception IllegalStateException if this response has already
+     *  been committed
+     */
+    public void reset() {
+
+        if (included)
+            return;     // Ignore any call from an included servlet
+
+        coyoteResponse.reset();
+        outputBuffer.reset();
+
+    }
+
+
+    /**
+     * Reset the data buffer but not any status or header information.
+     *
+     * @exception IllegalStateException if the response has already
+     *  been committed
+     */
+    public void resetBuffer() {
+
+        if (isCommitted())
+            throw new IllegalStateException
+                (sm.getString("coyoteResponse.resetBuffer.ise"));
+
+        outputBuffer.reset();
+
+    }
+
+
+    /**
+     * Set the buffer size to be used for this Response.
+     *
+     * @param size The new buffer size
+     *
+     * @exception IllegalStateException if this method is called after
+     *  output has been committed for this response
+     */
+    public void setBufferSize(int size) {
+
+        if (isCommitted() || !outputBuffer.isNew())
+            throw new IllegalStateException
+                (sm.getString("coyoteResponse.setBufferSize.ise"));
+
+        outputBuffer.setBufferSize(size);
+
+    }
+
+
+    /**
+     * Set the content length (in bytes) for this Response.
+     *
+     * @param length The new content length
+     */
+    public void setContentLength(int length) {
+
+        if (isCommitted())
+            return;
+
+        // Ignore any call from an included servlet
+        if (included)
+            return;
+
+        coyoteResponse.setContentLength(length);
+
+    }
+
+
+    /**
+     * Set the content type for this Response.
+     *
+     * @param type The new content type
+     */
+    public void setContentType(String type) {
+
+        if (isCommitted())
+            return;
+
+        // Ignore any call from an included servlet
+        if (included)
+            return;
+
+        coyoteResponse.setContentType(type);
+
+    }
+
+
+    /**
+     * Set the Locale that is appropriate for this response, including
+     * setting the appropriate character encoding.
+     *
+     * @param locale The new locale
+     */
+    public void setLocale(Locale locale) {
+
+        if (isCommitted())
+            return;
+
+        // Ignore any call from an included servlet
+        if (included)
+            return;
+
+        coyoteResponse.setLocale(locale);
+        
+        // Set the specified locale's default encoding of a response
+        CharsetMapper cm = context.getCharsetMapper();
+        String charset = cm.getCharset(locale);
+
+        if (charset != null) {
+            coyoteResponse.setCharacterEncoding(charset);
+        }
+    
+    }
+
+
+    // --------------------------------------------------- HttpResponse Methods
+
+
+    /**
+     * Return an array of all cookies set for this response, or
+     * a zero-length array if no cookies have been set.
+     */
+    public Cookie[] getCookies() {
+        return ((Cookie[]) cookies.toArray(new Cookie[cookies.size()]));
+    }
+
+
+    /**
+     * 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 getHeaderValues() to retrieve all
+     * of them.
+     *
+     * @param name Header name to look up
+     */
+    public String getHeader(String name) {
+        return coyoteResponse.getMimeHeaders().getHeader(name);
+    }
+
+
+    /**
+     * Return an array of all the header names set for this response, or
+     * a zero-length array if no headers have been set.
+     */
+    public String[] getHeaderNames() {
+
+        MimeHeaders headers = coyoteResponse.getMimeHeaders();
+        int n = headers.size();
+        String[] result = new String[n];
+        for (int i = 0; i < n; i++) {
+            result[i] = headers.getName(i).toString();
+        }
+        return result;
+
+    }
+
+
+    /**
+     * Return an array of all the header values associated with the
+     * specified header name, or an zero-length array if there are no such
+     * header values.
+     *
+     * @param name Header name to look up
+     */
+    public String[] getHeaderValues(String name) {
+
+        Enumeration headerValues = coyoteResponse.getMimeHeaders().values(name);
+        Vector result = new Vector();
+        while (headerValues.hasMoreElements()) {
+            result.addElement(headerValues.nextElement());
+        }
+        String[] resultArray = new String[result.size()];
+        result.copyInto(resultArray);
+        return resultArray;
+
+    }
+
+
+    /**
+     * Return the error message that was set with <code>sendError()</code>
+     * for this Response.
+     */
+    public String getMessage() {
+        return coyoteResponse.getMessage();
+    }
+
+
+    /**
+     * Return the HTTP status code associated with this Response.
+     */
+    public int getStatus() {
+        return coyoteResponse.getStatus();
+    }
+
+
+    /**
+     * Reset this response, and specify the values for the HTTP status code
+     * and corresponding message.
+     *
+     * @exception IllegalStateException if this response has already been
+     *  committed
+     */
+    public void reset(int status, String message) {
+        reset();
+        setStatus(status, message);
+    }
+
+
+    // -------------------------------------------- HttpServletResponse Methods
+
+
+    /**
+     * Add the specified Cookie to those that will be included with
+     * this Response.
+     *
+     * @param cookie Cookie to be added
+     */
+    public void addCookie(Cookie cookie) {
+
+        if (isCommitted())
+            return;
+
+        // Ignore any call from an included servlet
+        if (included)
+            return;
+
+        cookies.add(cookie);
+
+        StringBuffer sb = new StringBuffer();
+        ServerCookie.appendCookieValue
+            (sb, cookie.getVersion(), cookie.getName(), cookie.getValue(),
+             cookie.getPath(), cookie.getDomain(), cookie.getComment(), 
+             cookie.getMaxAge(), cookie.getSecure());
+        // the header name is Set-Cookie for both "old" and v.1 ( RFC2109 )
+        // RFC2965 is not supported by browsers and the Servlet spec
+        // asks for 2109.
+        addHeader("Set-Cookie", sb.toString());
+
+    }
+
+
+    /**
+     * Add the specified date header to the specified value.
+     *
+     * @param name Name of the header to set
+     * @param value Date value to be set
+     */
+    public void addDateHeader(String name, long value) {
+
+        if (isCommitted())
+            return;
+
+        // Ignore any call from an included servlet
+        if (included)
+            return;
+
+        addHeader(name, format.format(new Date(value)));
+
+    }
+
+
+    /**
+     * Add the specified header to the specified value.
+     *
+     * @param name Name of the header to set
+     * @param value Value to be set
+     */
+    public void addHeader(String name, String value) {
+
+        if (isCommitted())
+            return;
+
+        // Ignore any call from an included servlet
+        if (included)
+            return;
+
+        coyoteResponse.addHeader(name, value);
+
+    }
+
+
+    /**
+     * Add the specified integer header to the specified value.
+     *
+     * @param name Name of the header to set
+     * @param value Integer value to be set
+     */
+    public void addIntHeader(String name, int value) {
+
+        if (isCommitted())
+            return;
+
+        // Ignore any call from an included servlet
+        if (included)
+            return;
+
+        addHeader(name, "" + value);
+
+    }
+
+
+    /**
+     * Has the specified header been set already in this response?
+     *
+     * @param name Name of the header to check
+     */
+    public boolean containsHeader(String name) {
+        // Need special handling for Content-Type and Content-Length due to
+        // special handling of these in coyoteResponse
+        char cc=name.charAt(0);
+        if(cc=='C' || cc=='c') {
+            if(name.equalsIgnoreCase("Content-Type")) {
+                // Will return null if this has not been set
+                return (coyoteResponse.getContentType() != null);
+            }
+            if(name.equalsIgnoreCase("Content-Length")) {
+                // Can't use null test since this header is an int
+                return (coyoteResponse.getContentLengthLong() != -1);
+            }
+        }
+
+        return coyoteResponse.containsHeader(name);
+    }
+
+
+    /**
+     * Encode the session identifier associated with this response
+     * into the specified redirect URL, if necessary.
+     *
+     * @param url URL to be encoded
+     */
+    public String encodeRedirectURL(String url) {
+
+        if (isEncodeable(toAbsolute(url))) {
+            HttpServletRequest hreq =
+                (HttpServletRequest) request.getRequest();
+            return (toEncoded(url, hreq.getSession().getId()));
+        } else {
+            return (url);
+        }
+
+    }
+
+
+    /**
+     * Encode the session identifier associated with this response
+     * into the specified redirect URL, if necessary.
+     *
+     * @param url URL to be encoded
+     *
+     * @deprecated As of Version 2.1 of the Java Servlet API, use
+     *  <code>encodeRedirectURL()</code> instead.
+     */
+    public String encodeRedirectUrl(String url) {
+        return (encodeRedirectURL(url));
+    }
+
+
+    /**
+     * Encode the session identifier associated with this response
+     * into the specified URL, if necessary.
+     *
+     * @param url URL to be encoded
+     */
+    public String encodeURL(String url) {
+        
+        String absolute = toAbsolute(url);
+        if (isEncodeable(absolute)) {
+            HttpServletRequest hreq =
+                (HttpServletRequest) request.getRequest();
+            
+            // W3c spec clearly said 
+            if (url.equalsIgnoreCase("")){
+                url = absolute;
+            }
+            return (toEncoded(url, hreq.getSession().getId()));
+        } else {
+            return (url);
+        }
+
+    }
+
+
+    /**
+     * Encode the session identifier associated with this response
+     * into the specified URL, if necessary.
+     *
+     * @param url URL to be encoded
+     *
+     * @deprecated As of Version 2.1 of the Java Servlet API, use
+     *  <code>encodeURL()</code> instead.
+     */
+    public String encodeUrl(String url) {
+        return (encodeURL(url));
+    }
+
+
+    /**
+     * Send an acknowledgment of a request.
+     * 
+     * @exception IOException if an input/output error occurs
+     */
+    public void sendAcknowledgement()
+        throws IOException {
+
+        if (isCommitted())
+            return;
+
+        // Ignore any call from an included servlet
+        if (included)
+            return; 
+
+        coyoteResponse.acknowledge();
+
+    }
+
+
+    /**
+     * Send an error response with the specified status and a
+     * default message.
+     *
+     * @param status HTTP status code to send
+     *
+     * @exception IllegalStateException if this response has
+     *  already been committed
+     * @exception IOException if an input/output error occurs
+     */
+    public void sendError(int status) 
+        throws IOException {
+        sendError(status, null);
+    }
+
+
+    /**
+     * Send an error response with the specified status and message.
+     *
+     * @param status HTTP status code to send
+     * @param message Corresponding message to send
+     *
+     * @exception IllegalStateException if this response has
+     *  already been committed
+     * @exception IOException if an input/output error occurs
+     */
+    public void sendError(int status, String message) 
+        throws IOException {
+
+        if (isCommitted())
+            throw new IllegalStateException
+                (sm.getString("coyoteResponse.sendError.ise"));
+
+        // Ignore any call from an included servlet
+        if (included)
+            return; 
+
+        setError();
+
+        coyoteResponse.setStatus(status);
+        coyoteResponse.setMessage(message);
+
+        // Clear any data content that has been buffered
+        resetBuffer();
+
+        // Cause the response to be finished (from the application perspective)
+        setSuspended(true);
+
+    }
+
+
+    /**
+     * Send a temporary redirect to the specified redirect location URL.
+     *
+     * @param location Location URL to redirect to
+     *
+     * @exception IllegalStateException if this response has
+     *  already been committed
+     * @exception IOException if an input/output error occurs
+     */
+    public void sendRedirect(String location) 
+        throws IOException {
+
+        if (isCommitted())
+            throw new IllegalStateException
+                (sm.getString("coyoteResponse.sendRedirect.ise"));
+
+        // Ignore any call from an included servlet
+        if (included)
+            return; 
+
+        // Clear any data content that has been buffered
+        resetBuffer();
+
+        // Generate a temporary redirect to the specified location
+        try {
+            String absolute = toAbsolute(location);
+            setStatus(SC_MOVED_TEMPORARILY);
+            setHeader("Location", absolute);
+        } catch (IllegalArgumentException e) {
+            setStatus(SC_NOT_FOUND);
+        }
+
+        // Cause the response to be finished (from the application perspective)
+        setSuspended(true);
+
+    }
+
+
+    /**
+     * Set the specified date header to the specified value.
+     *
+     * @param name Name of the header to set
+     * @param value Date value to be set
+     */
+    public void setDateHeader(String name, long value) {
+
+        if (isCommitted())
+            return;
+
+        // Ignore any call from an included servlet
+        if (included)
+            return;
+
+        setHeader(name, format.format(new Date(value)));
+
+    }
+
+
+    /**
+     * Set the specified header to the specified value.
+     *
+     * @param name Name of the header to set
+     * @param value Value to be set
+     */
+    public void setHeader(String name, String value) {
+
+        if (isCommitted())
+            return;
+
+        // Ignore any call from an included servlet
+        if (included)
+            return;
+
+        coyoteResponse.setHeader(name, value);
+
+    }
+
+
+    /**
+     * Set the specified integer header to the specified value.
+     *
+     * @param name Name of the header to set
+     * @param value Integer value to be set
+     */
+    public void setIntHeader(String name, int value) {
+
+        if (isCommitted())
+            return;
+
+        // Ignore any call from an included servlet
+        if (included)
+            return;
+
+        setHeader(name, "" + value);
+
+    }
+
+
+    /**
+     * Set the HTTP status to be returned with this response.
+     *
+     * @param status The new HTTP status
+     */
+    public void setStatus(int status) {
+        setStatus(status, null);
+    }
+
+
+    /**
+     * Set the HTTP status and message to be returned with this response.
+     *
+     * @param status The new HTTP status
+     * @param message The associated text message
+     *
+     * @deprecated As of Version 2.1 of the Java Servlet API, this method
+     *  has been deprecated due to the ambiguous meaning of the message
+     *  parameter.
+     */
+    public void setStatus(int status, String message) {
+
+        if (isCommitted())
+            return;
+
+        // Ignore any call from an included servlet
+        if (included)
+            return;
+
+        coyoteResponse.setStatus(status);
+        coyoteResponse.setMessage(message);
+
+    }
+
+
+    // ------------------------------------------------------ Protected Methods
+
+
+    /**
+     * Return <code>true</code> if the specified URL should be encoded with
+     * a session identifier.  This will be true if all of the following
+     * conditions are met:
+     * <ul>
+     * <li>The request we are responding to asked for a valid session
+     * <li>The requested session ID was not received via a cookie
+     * <li>The specified URL points back to somewhere within the web
+     *     application that is responding to this request
+     * </ul>
+     *
+     * @param location Absolute URL to be validated
+     */
+    protected boolean isEncodeable(String location) {
+
+        if (location == null)
+            return (false);
+
+        // Is this an intra-document reference?
+        if (location.startsWith("#"))
+            return (false);
+
+        // Are we in a valid session that is not using cookies?
+        HttpServletRequest hreq = (HttpServletRequest) request.getRequest();
+        HttpSession session = hreq.getSession(false);
+        if (session == null)
+            return (false);
+        if (hreq.isRequestedSessionIdFromCookie())
+            return (false);
+
+        // Is this a valid absolute URL?
+        URL url = null;
+        try {
+            url = new URL(location);
+        } catch (MalformedURLException e) {
+            return (false);
+        }
+
+        // Does this URL match down to (and including) the context path?
+        if (!hreq.getScheme().equalsIgnoreCase(url.getProtocol()))
+            return (false);
+        if (!hreq.getServerName().equalsIgnoreCase(url.getHost()))
+            return (false);
+        int serverPort = hreq.getServerPort();
+        if (serverPort == -1) {
+            if ("https".equals(hreq.getScheme()))
+                serverPort = 443;
+            else
+                serverPort = 80;
+        }
+        int urlPort = url.getPort();
+        if (urlPort == -1) {
+            if ("https".equals(url.getProtocol()))
+                urlPort = 443;
+            else
+                urlPort = 80;
+        }
+        if (serverPort != urlPort)
+            return (false);
+
+        String contextPath = getContext().getPath();
+        if (contextPath != null) {
+            String file = url.getFile();
+            if ((file == null) || !file.startsWith(contextPath))
+                return (false);
+            if( file.indexOf(";jsessionid=" + session.getId()) >= 0 )
+                return (false);
+        }
+
+        // This URL belongs to our web application, so it is encodeable
+        return (true);
+
+    }
+
+
+    /**
+     * Convert (if necessary) and return the absolute URL that represents the
+     * resource referenced by this possibly relative URL.  If this URL is
+     * already absolute, return it unchanged.
+     *
+     * @param location URL to be (possibly) converted and then returned
+     *
+     * @exception IllegalArgumentException if a MalformedURLException is
+     *  thrown when converting the relative URL to an absolute one
+     */
+    private String toAbsolute(String location) {
+
+        if (location == null)
+            return (location);
+
+        // Construct a new absolute URL if possible (cribbed from
+        // the DefaultErrorPage servlet)
+        URL url = null;
+        try {
+            url = new URL(location);
+
+            if (url.getAuthority() == null)
+                return location;
+
+        } catch (MalformedURLException e1) {
+            String requrl = request.getRequestURL().toString();
+            try {
+                url = new URL(new URL(requrl), location);
+            } catch (MalformedURLException e2) {
+                throw new IllegalArgumentException(location);
+            }
+        }
+        return (url.toExternalForm());
+    }
+
+
+    /**
+     * Return the specified URL with the specified session identifier
+     * suitably encoded.
+     *
+     * @param url URL to be encoded with the session id
+     * @param sessionId Session id to be included in the encoded URL
+     */
+    private String toEncoded(String url, String sessionId) {
+
+        if ((url == null) || (sessionId == null))
+            return (url);
+
+        String path = url;
+        String query = "";
+        String anchor = "";
+        int question = url.indexOf('?');
+        if (question >= 0) {
+            path = url.substring(0, question);
+            query = url.substring(question);
+        }
+        int pound = path.indexOf('#');
+        if (pound >= 0) {
+            anchor = path.substring(pound);
+            path = path.substring(0, pound);
+        }
+        StringBuffer sb = new StringBuffer(path);
+        if( sb.length() > 0 ) { // jsessionid can't be first.
+            sb.append(";jsessionid=");
+            sb.append(sessionId);
+        }
+        sb.append(anchor);
+        sb.append(query);
+        return (sb.toString());
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/java/org/apache/coyote/tomcat4/CoyoteResponseFacade.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/java/org/apache/coyote/tomcat4/CoyoteResponseFacade.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/java/org/apache/coyote/tomcat4/CoyoteResponseFacade.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,380 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.tomcat4;
+
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.Locale;
+
+import javax.servlet.ServletOutputStream;
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.catalina.connector.ResponseFacade;
+
+/**
+ * Facade class that wraps a Coyote response object. 
+ * All methods are delegated to the wrapped response.
+ *
+ * @author Remy Maucherat
+ * @version $Revision: 299222 $ $Date: 2004-02-24 03:02:18 -0600 (Tue, 24 Feb 2004) $
+ */
+
+public class CoyoteResponseFacade 
+    extends ResponseFacade
+    implements HttpServletResponse {
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Construct a wrapper for the specified response.
+     *
+     * @param response The response to be wrapped
+     */
+    public CoyoteResponseFacade(CoyoteResponse response) {
+
+        super(response);
+        this.response = response;
+
+    }
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The wrapped response.
+     */
+    protected CoyoteResponse response = null;
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Clear facade.
+     */
+    public void clear() {
+        response = null;
+    }
+
+
+    public void finish() {
+
+        response.setSuspended(true);
+
+    }
+
+
+    public boolean isFinished() {
+
+        return response.isSuspended();
+
+    }
+
+
+    // ------------------------------------------------ ServletResponse Methods
+
+
+    public String getCharacterEncoding() {
+        return response.getCharacterEncoding();
+    }
+
+
+    public ServletOutputStream getOutputStream()
+        throws IOException {
+
+        //        if (isFinished())
+        //            throw new IllegalStateException
+        //                (/*sm.getString("responseFacade.finished")*/);
+
+        ServletOutputStream sos = response.getOutputStream();
+        if (isFinished())
+            response.setSuspended(true);
+        return (sos);
+
+    }
+
+
+    public PrintWriter getWriter()
+        throws IOException {
+
+        //        if (isFinished())
+        //            throw new IllegalStateException
+        //                (/*sm.getString("responseFacade.finished")*/);
+
+        PrintWriter writer = response.getWriter();
+        if (isFinished())
+            response.setSuspended(true);
+        return (writer);
+
+    }
+
+
+    public void setContentLength(int len) {
+
+        if (isCommitted())
+            return;
+
+        response.setContentLength(len);
+
+    }
+
+
+    public void setContentType(String type) {
+
+        if (isCommitted())
+            return;
+
+        response.setContentType(type);
+
+    }
+
+
+    public void setBufferSize(int size) {
+
+        if (isCommitted())
+            throw new IllegalStateException
+                (/*sm.getString("responseBase.reset.ise")*/);
+
+        response.setBufferSize(size);
+
+    }
+
+
+    public int getBufferSize() {
+        return response.getBufferSize();
+    }
+
+
+    public void flushBuffer()
+        throws IOException {
+
+        if (isFinished())
+            //            throw new IllegalStateException
+            //                (/*sm.getString("responseFacade.finished")*/);
+            return;
+
+        response.setAppCommitted(true);
+
+        response.flushBuffer();
+
+    }
+
+
+    public void resetBuffer() {
+
+        if (isCommitted())
+            throw new IllegalStateException
+                (/*sm.getString("responseBase.reset.ise")*/);
+
+        response.resetBuffer();
+
+    }
+
+
+    public boolean isCommitted() {
+        return (response.isAppCommitted());
+    }
+
+
+    public void reset() {
+
+        if (isCommitted())
+            throw new IllegalStateException
+                (/*sm.getString("responseBase.reset.ise")*/);
+
+        response.reset();
+
+    }
+
+
+    public void setLocale(Locale loc) {
+
+        if (isCommitted())
+            return;
+
+        response.setLocale(loc);
+    }
+
+
+    public Locale getLocale() {
+        return response.getLocale();
+    }
+
+
+    public void addCookie(Cookie cookie) {
+
+        if (isCommitted())
+            return;
+
+        response.addCookie(cookie);
+
+    }
+
+
+    public boolean containsHeader(String name) {
+        return response.containsHeader(name);
+    }
+
+
+    public String encodeURL(String url) {
+        return response.encodeURL(url);
+    }
+
+
+    public String encodeRedirectURL(String url) {
+        return response.encodeRedirectURL(url);
+    }
+
+
+    public String encodeUrl(String url) {
+        return response.encodeURL(url);
+    }
+
+
+    public String encodeRedirectUrl(String url) {
+        return response.encodeRedirectURL(url);
+    }
+
+
+    public void sendError(int sc, String msg)
+        throws IOException {
+
+        if (isCommitted())
+            throw new IllegalStateException
+                (/*sm.getString("responseBase.reset.ise")*/);
+
+        response.setAppCommitted(true);
+
+        response.sendError(sc, msg);
+
+    }
+
+
+    public void sendError(int sc)
+        throws IOException {
+
+        if (isCommitted())
+            throw new IllegalStateException
+                (/*sm.getString("responseBase.reset.ise")*/);
+
+        response.setAppCommitted(true);
+
+        response.sendError(sc);
+
+    }
+
+
+    public void sendRedirect(String location)
+        throws IOException {
+
+        if (isCommitted())
+            throw new IllegalStateException
+                (/*sm.getString("responseBase.reset.ise")*/);
+
+        response.setAppCommitted(true);
+
+        response.sendRedirect(location);
+
+    }
+
+
+    public void setDateHeader(String name, long date) {
+
+        if (isCommitted())
+            return;
+
+        response.setDateHeader(name, date);
+
+    }
+
+
+    public void addDateHeader(String name, long date) {
+
+        if (isCommitted())
+            return;
+
+        response.addDateHeader(name, date);
+
+    }
+
+
+    public void setHeader(String name, String value) {
+
+        if (isCommitted())
+            return;
+
+        response.setHeader(name, value);
+
+    }
+
+
+    public void addHeader(String name, String value) {
+
+        if (isCommitted())
+            return;
+
+        response.addHeader(name, value);
+
+    }
+
+
+    public void setIntHeader(String name, int value) {
+
+        if (isCommitted())
+            return;
+
+        response.setIntHeader(name, value);
+
+    }
+
+
+    public void addIntHeader(String name, int value) {
+
+        if (isCommitted())
+            return;
+
+        response.addIntHeader(name, value);
+
+    }
+
+
+    public void setStatus(int sc) {
+
+        if (isCommitted())
+            return;
+
+        response.setStatus(sc);
+
+    }
+
+
+    public void setStatus(int sc, String sm) {
+
+        if (isCommitted())
+            return;
+
+        response.setStatus(sc, sm);
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/java/org/apache/coyote/tomcat4/CoyoteServerSocketFactory.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/java/org/apache/coyote/tomcat4/CoyoteServerSocketFactory.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/java/org/apache/coyote/tomcat4/CoyoteServerSocketFactory.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,236 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.tomcat4;
+
+import java.io.File;
+import java.net.InetAddress;
+import java.net.ServerSocket;
+
+
+/**
+ * This socket factory holds secure socket factory parameters. Besides the usual
+ * configuration mechanism based on setting JavaBeans properties, this
+ * component may also be configured by passing a series of attributes set
+ * with calls to <code>setAttribute()</code>.  The following attribute
+ * names are recognized, with default values in square brackets:
+ * <ul>
+ * <li><strong>algorithm</strong> - Certificate encoding algorithm
+ *     to use. [SunX509]</li>
+ * <li><strong>clientAuth</strong> - Require client authentication if
+ *     set to <code>true</code>. Want client authentication if set to
+ *     <code>want</code>. (Note: Only supported in the JSSE included with 
+ *     J2SDK 1.4 and above.  Prior versions of JSSE and PureTLS will treat 
+ *     'want' as 'false'.) [false]</li>
+ * <li><strong>keystoreFile</strong> - Pathname to the Key Store file to be
+ *     loaded.  This must be an absolute path, or a relative path that
+ *     is resolved against the "catalina.base" system property.
+ *     ["./keystore" in the user home directory]</li>
+ * <li><strong>keystorePass</strong> - Password for the Key Store file to be
+ *     loaded. ["changeit"]</li>
+ * <li><strong>keystoreType</strong> - Type of the Key Store file to be
+ *     loaded. ["JKS"]</li>
+ * <li><strong>protocol</strong> - SSL protocol to use. [TLS]</li>
+ * </ul>
+ *
+ * @author Harish Prabandham
+ * @author Costin Manolache
+ * @author Craig McClanahan
+ */
+
+public class CoyoteServerSocketFactory
+    implements org.apache.catalina.net.ServerSocketFactory {
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * Certificate encoding algorithm to be used.
+     */
+    private String algorithm = null;
+
+    public String getAlgorithm() {
+        return (this.algorithm);
+    }
+
+    public void setAlgorithm(String algorithm) {
+        this.algorithm = algorithm;
+    }
+
+
+    /**
+     * Ciphers to be used.
+     */
+    private String ciphers;
+
+    public String getCiphers() {
+        return (this.ciphers);
+    }
+
+    public void setCiphers(String ciphers) {
+        this.ciphers = ciphers;
+    }
+
+
+    /**
+     * Should we require client authentication?
+     */
+    private String clientAuth = "false";
+
+    public String getClientAuth() {
+        return (this.clientAuth);
+    }
+
+    public void setClientAuth(String clientAuth) {
+        this.clientAuth = clientAuth;
+    }
+
+
+    /**
+     * Pathname to the key store file to be used.
+     */
+    private String keystoreFile =
+        System.getProperty("user.home") + File.separator + ".keystore";
+
+    public String getKeystoreFile() {
+        return (this.keystoreFile);
+    }
+
+    public void setKeystoreFile(String keystoreFile) {
+      
+        File file = new File(keystoreFile);
+        if (!file.isAbsolute())
+            file = new File(System.getProperty("catalina.base"),
+                            keystoreFile);
+        this.keystoreFile = file.getAbsolutePath();
+    }
+
+    /**
+     * Pathname to the random file to be used.
+     */
+    private String randomFile =
+        System.getProperty("user.home") + File.separator + "random.pem";
+
+    public String getRandomFile() {
+        return (this.randomFile);
+    }
+
+    public void setRandomFile(String randomFile) {
+      
+        File file = new File(randomFile);
+        if (!file.isAbsolute())
+            file = new File(System.getProperty("catalina.base"),
+                            randomFile);
+        this.randomFile = file.getAbsolutePath();
+    }
+
+    /**
+     * Pathname to the root list to be used.
+     */
+    private String rootFile =
+        System.getProperty("user.home") + File.separator + "root.pem";
+
+    public String getRootFile() {
+        return (this.rootFile);
+    }
+
+    public void setRootFile(String rootFile) {
+      
+        File file = new File(rootFile);
+        if (!file.isAbsolute())
+            file = new File(System.getProperty("catalina.base"),
+                            rootFile);
+        this.rootFile = file.getAbsolutePath();
+    }
+     
+    /**
+     * Password for accessing the key store file.
+     */
+    private String keystorePass = "changeit";
+
+    public String getKeystorePass() {
+        return (this.keystorePass);
+    }
+
+    public void setKeystorePass(String keystorePass) {
+        this.keystorePass = keystorePass;
+    }
+
+
+    /**
+     * Storeage type of the key store file to be used.
+     */
+    private String keystoreType = "JKS";
+
+    public String getKeystoreType() {
+        return (this.keystoreType);
+    }
+
+    public void setKeystoreType(String keystoreType) {
+        this.keystoreType = keystoreType;
+    }
+
+
+    /**
+     * SSL protocol variant to use.
+     */
+    private String protocol = "TLS";
+
+    public String getProtocol() {
+        return (this.protocol);
+    }
+
+    public void setProtocol(String protocol) {
+        this.protocol = protocol;
+    }
+
+
+    /**
+     * SSL implementation to use.
+     */
+    private String sslImplementation = null;
+
+    public String getSSLImplementation() {
+        return (this.sslImplementation);
+    }
+
+    public void setSSLImplementation(String sslImplementation) {
+        this.sslImplementation = sslImplementation;
+    }
+
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    public ServerSocket createSocket(int port) {
+        return (null);
+    }
+
+
+    public ServerSocket createSocket(int port, int backlog) {
+        return (null);
+    }
+
+
+    public ServerSocket createSocket(int port, int backlog,
+                                     InetAddress ifAddress) {
+        return (null);
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/java/org/apache/coyote/tomcat4/CoyoteWriter.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/java/org/apache/coyote/tomcat4/CoyoteWriter.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/java/org/apache/coyote/tomcat4/CoyoteWriter.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,267 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.tomcat4;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+
+/**
+ * Coyote implementation of the servlet writer.
+ * 
+ * @author Remy Maucherat
+ */
+final class CoyoteWriter
+    extends PrintWriter {
+
+
+    // -------------------------------------------------------------- Constants
+
+
+    private static final char[] LINE_SEP = { '\r', '\n' };
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    protected OutputBuffer ob;
+    protected boolean error = false;
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    public CoyoteWriter(OutputBuffer ob) {
+        super(ob);
+        this.ob = ob;
+    }
+
+
+    // -------------------------------------------------------- Package Methods
+
+
+    /**
+     * Recycle.
+     */
+    void recycle() {
+        error = false;
+    }
+
+
+    // --------------------------------------------------------- Writer Methods
+
+
+    public void flush() {
+
+        if (error)
+            return;
+
+        try {
+            ob.flush();
+        } catch (IOException e) {
+            error = true;
+        }
+
+    }
+
+
+    public void close() {
+
+        // We don't close the PrintWriter - super() is not called,
+        // so the stream can be reused. We close ob.
+        try {
+            ob.close();
+        } catch (IOException ex ) {
+            ;
+        }
+        error = false;
+
+    }
+
+
+    public boolean checkError() {
+        flush();
+        return error;
+    }
+
+
+    public void write(int c) {
+
+        if (error)
+            return;
+
+        try {
+            ob.write(c);
+        } catch (IOException e) {
+            error = true;
+        }
+
+    }
+
+
+    public void write(char buf[], int off, int len) {
+
+        if (error)
+            return;
+
+        try {
+            ob.write(buf, off, len);
+        } catch (IOException e) {
+            error = true;
+        }
+
+    }
+
+
+    public void write(char buf[]) {
+	write(buf, 0, buf.length);
+    }
+
+
+    public void write(String s, int off, int len) {
+
+        if (error)
+            return;
+
+        try {
+            ob.write(s, off, len);
+        } catch (IOException e) {
+            error = true;
+        }
+
+    }
+
+
+    public void write(String s) {
+        write(s, 0, s.length());
+    }
+
+
+    // ---------------------------------------------------- PrintWriter Methods
+
+
+    public void print(boolean b) {
+        if (b) {
+            write("true");
+        } else {
+            write("false");
+        }
+    }
+
+
+    public void print(char c) {
+        write(c);
+    }
+
+
+    public void print(int i) {
+        write(String.valueOf(i));
+    }
+
+
+    public void print(long l) {
+        write(String.valueOf(l));
+    }
+
+
+    public void print(float f) {
+        write(String.valueOf(f));
+    }
+
+
+    public void print(double d) {
+        write(String.valueOf(d));
+    }
+
+
+    public void print(char s[]) {
+        write(s);
+    }
+
+
+    public void print(String s) {
+        if (s == null) {
+            s = "null";
+        }
+        write(s);
+    }
+
+
+    public void print(Object obj) {
+        write(String.valueOf(obj));
+    }
+
+
+    public void println() {
+        write(LINE_SEP);
+    }
+
+
+    public void println(boolean b) {
+        print(b);
+        println();
+    }
+
+
+    public void println(char c) {
+        print(c);
+        println();
+    }
+
+
+    public void println(int i) {
+        print(i);
+        println();
+    }
+
+
+    public void println(long l) {
+        print(l);
+        println();
+    }
+
+
+    public void println(float f) {
+        print(f);
+        println();
+    }
+
+
+    public void println(double d) {
+        print(d);
+        println();
+    }
+
+
+    public void println(char c[]) {
+        print(c);
+        println();
+    }
+
+
+    public void println(String s) {
+        print(s);
+        println();
+    }
+
+
+    public void println(Object o) {
+        print(o);
+        println();
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/java/org/apache/coyote/tomcat4/LocalStrings.properties
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/java/org/apache/coyote/tomcat4/LocalStrings.properties	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/java/org/apache/coyote/tomcat4/LocalStrings.properties	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,38 @@
+
+#
+# CoyoteConnector
+#
+
+coyoteConnector.alreadyInitialized=The connector has already been initialized
+coyoteConnector.alreadyStarted=The connector has already been started
+coyoteConnector.notStarted=Coyote connector has not been started
+coyoteConnector.protocolHandlerDestroyFailed=Protocol handler destroy failed: {0}
+coyoteConnector.protocolHandlerInitializationFailed=Protocol handler initialization failed: {0}
+coyoteConnector.protocolHandlerInstantiationFailed=Protocol handler instantiation failed: {0}
+coyoteConnector.protocolHandlerStartFailed=Protocol handler start failed: {0}
+
+#
+# CoyoteAdapter
+#
+
+coyoteAdapter.service=An exception or error occurred in the container during the request processing
+
+#
+# CoyoteResponse
+#
+
+coyoteResponse.getOutputStream.ise=getWriter() has already been called for this response
+coyoteResponse.getWriter.ise=getOutputStream() has already been called for this response
+coyoteResponse.resetBuffer.ise=Cannot reset buffer after response has been committed
+coyoteResponse.sendError.ise=Cannot call sendError() after the response has been committed
+coyoteResponse.sendRedirect.ise=Cannot call sendRedirect() after the response has been committed
+coyoteResponse.setBufferSize.ise=Cannot change buffer size after data has been written
+
+#
+# CoyoteRequest
+#
+
+coyoteRequest.getInputStream.ise=getReader() has already been called for this request
+coyoteRequest.getReader.ise=getInputStream() has already been called for this request
+coyoteRequest.sessionCreateCommitted=Cannot create a session after the response has been committed
+coyoteRequest.setAttribute.namenull=Cannot call setAttribute with a null name

Added: branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/java/org/apache/coyote/tomcat4/LocalStrings_es.properties
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/java/org/apache/coyote/tomcat4/LocalStrings_es.properties	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/java/org/apache/coyote/tomcat4/LocalStrings_es.properties	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,38 @@
+
+#
+# CoyoteConnector
+#
+
+coyoteConnector.alreadyInitialized=Ya ha sido inicializado el conector
+coyoteConnector.alreadyStarted=Ya ha sido arrancado el conector
+coyoteConnector.notStarted=El conector Coyote no ha sido arrancado
+coyoteConnector.protocolHandlerDestroyFailed=Falló la destrucción del manejador de protocolo: {0}
+coyoteConnector.protocolHandlerInitializationFailed=Falló la inicialización del manejador de protocolo: {0}
+coyoteConnector.protocolHandlerInstantiationFailed=Falló la instanciación del manejador de protocolo: {0}
+coyoteConnector.protocolHandlerStartFailed=Falló el arranque del manejador de protocolo: {0}
+
+#
+# CoyoteAdapter
+#
+
+coyoteAdapter.service=Ha tenido lugar una excepción o error en el contenedor durante el procesamiento del requerimiento
+
+#
+# CoyoteResponse
+#
+
+coyoteResponse.getOutputStream.ise=getWriter() ya ha sido llamado para esta respuesta
+coyoteResponse.getWriter.ise=getOutputStream() ya ha sido llamado para esta respuesta
+coyoteResponse.resetBuffer.ise=No puedo limpiar el búfer después de que la repuesta ha sido llevada a cabo
+coyoteResponse.sendError.ise=No puedo llamar a sendError() tras llevar a cabo la respuesta
+coyoteResponse.sendRedirect.ise=No puedo llamar a sendRedirect() tras llevar a cabo la respuesta
+coyoteResponse.setBufferSize.ise=No puedo cambiar la medida del búfer tras escribir los datos
+
+#
+# CoyoteRequest
+#
+
+coyoteRequest.getInputStream.ise=getReader() ya ha sido llamado para este requerimiento
+coyoteRequest.getReader.ise=getInputStream() ya ha sido llamado para este requerimiento
+coyoteRequest.sessionCreateCommitted=No puedo crear una sesión después de llevar a cabo la respueta
+coyoteRequest.setAttribute.namenull=No pudeo llamar a setAttribute con un nombre nulo

Added: branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/java/org/apache/coyote/tomcat4/LocalStrings_fr.properties
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/java/org/apache/coyote/tomcat4/LocalStrings_fr.properties	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/java/org/apache/coyote/tomcat4/LocalStrings_fr.properties	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,38 @@
+
+#
+# CoyoteConnector
+#
+
+coyoteConnector.alreadyInitialized=Le connecteur a déjà été initialisé
+coyoteConnector.alreadyStarted=Le connecteur a déjà été démarré
+coyoteConnector.notStarted=Le connecteur Coyote n''a pas été démarré
+coyoteConnector.protocolHandlerDestroyFailed=La destruction du gestionnaire de protocole a échoué: {0}
+coyoteConnector.protocolHandlerInitializationFailed=L''initialisation du gestionnaire de protocole a échoué: {0}
+coyoteConnector.protocolHandlerInstantiationFailed=L''instantiation du gestionnaire de protocole a échoué: {0}
+coyoteConnector.protocolHandlerStartFailed=Le démarrage du gestionnaire de protocole a échoué: {0}
+
+#
+# CoyoteAdapter
+#
+
+coyoteAdapter.service=Une exception ou une erreur s''est produite dans le conteneur durant le traitement de la requête
+
+#
+# CoyoteResponse
+#
+
+coyoteResponse.getOutputStream.ise="getWriter()" a déjà été appelé pour cette réponse
+coyoteResponse.getWriter.ise="getOutputStream()" a déjà été appelé pour cette réponse
+coyoteResponse.resetBuffer.ise=Impossible de remettre à zéro le tampon après que la réponse ait été envoyée
+coyoteResponse.sendError.ise=Impossible d''appeler "sendError()" après que la réponse ait été envoyée
+coyoteResponse.sendRedirect.ise=Impossible d''appeler "sendRedirect()" après que la réponse ait été envoyée
+coyoteResponse.setBufferSize.ise=Impossible de changer la taille du tampon après que les données aient été écrites
+
+#
+# CoyoteRequest
+#
+
+coyoteRequest.getInputStream.ise="getReader()" a déjà été appelé pour cette requête
+coyoteRequest.getReader.ise="getInputStream()" a déjà été appelé pour cette requête
+coyoteRequest.sessionCreateCommitted=Impossible de créer une sessionaprès que la réponse ait été envoyée
+coyoteRequest.setAttribute.namenull=Impossible d''appeler "setAttribute" avec un nom nul

Added: branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/java/org/apache/coyote/tomcat4/LocalStrings_ja.properties
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/java/org/apache/coyote/tomcat4/LocalStrings_ja.properties	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/java/org/apache/coyote/tomcat4/LocalStrings_ja.properties	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,38 @@
+
+#
+# CoyoteConnector
+#
+
+coyoteConnector.alreadyInitialized=\u30b3\u30cd\u30af\u30bf\u306f\u65e2\u306b\u521d\u671f\u5316\u3055\u308c\u3066\u3044\u307e\u3059
+coyoteConnector.alreadyStarted=\u30b3\u30cd\u30af\u30bf\u306f\u65e2\u306b\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u3059
+coyoteConnector.notStarted=Coyote\u30b3\u30cd\u30af\u30bf\u306f\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u305b\u3093
+coyoteConnector.protocolHandlerDestroyFailed=\u30d7\u30ed\u30c8\u30b3\u30eb\u30cf\u30f3\u30c9\u30e9\u306e\u5ec3\u68c4\u306b\u5931\u6557\u3057\u307e\u3057\u305f: {0}
+coyoteConnector.protocolHandlerInitializationFailed=\u30d7\u30ed\u30c8\u30b3\u30eb\u30cf\u30f3\u30c9\u30e9\u306e\u521d\u671f\u5316\u306b\u5931\u6557\u3057\u307e\u3057\u305f: {0}
+coyoteConnector.protocolHandlerInstantiationFailed=\u30d7\u30ed\u30c8\u30b3\u30eb\u30cf\u30f3\u30c9\u30e9\u306e\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u5316\u306b\u5931\u6557\u3057\u307e\u3057\u305f: {0}
+coyoteConnector.protocolHandlerStartFailed=\u30d7\u30ed\u30c8\u30b3\u30eb\u30cf\u30f3\u30c9\u30e9\u306e\u8d77\u52d5\u306b\u5931\u6557\u3057\u307e\u3057\u305f: {0}
+
+#
+# CoyoteAdapter
+#
+
+coyoteAdapter.service=\u30ea\u30af\u30a8\u30b9\u30c8\u306e\u51e6\u7406\u4e2d\u306b\u30b3\u30cd\u30af\u30bf\u3067\u4f8b\u5916\u53c8\u306f\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f
+
+#
+# CoyoteResponse
+#
+
+coyoteResponse.getOutputStream.ise=getWriter()\u306f\u3053\u306e\u30ec\u30b9\u30dd\u30f3\u30b9\u306b\u5bfe\u3057\u3066\u65e2\u306b\u547c\u3073\u51fa\u3055\u308c\u3066\u3044\u307e\u3059
+coyoteResponse.getWriter.ise=getOutputStream()\u306f\u3053\u306e\u30ec\u30b9\u30dd\u30f3\u30b9\u306b\u5bfe\u3057\u3066\u65e2\u306b\u547c\u3073\u51fa\u3055\u308c\u3066\u3044\u307e\u3059
+coyoteResponse.resetBuffer.ise=\u30ec\u30b9\u30dd\u30f3\u30b9\u304c\u30b3\u30df\u30c3\u30c8\u3055\u308c\u305f\u5f8c\u3067\u30d0\u30c3\u30d5\u30a1\u3092\u30ea\u30bb\u30c3\u30c8\u3059\u308b\u3053\u3068\u306f\u3067\u304d\u307e\u305b\u3093
+coyoteResponse.sendError.ise=\u30ec\u30b9\u30dd\u30f3\u30b9\u304c\u30b3\u30df\u30c3\u30c8\u3055\u308c\u305f\u5f8c\u3067sendError()\u3092\u547c\u3073\u51fa\u3059\u3053\u3068\u306f\u3067\u304d\u307e\u305b\u3093
+coyoteResponse.sendRedirect.ise=\u30ec\u30b9\u30dd\u30f3\u30b9\u304c\u30b3\u30df\u30c3\u30c8\u3055\u308c\u305f\u5f8c\u3067sendRedirect()\u3092\u547c\u3073\u51fa\u3059\u3053\u3068\u306f\u3067\u304d\u307e\u305b\u3093
+coyoteResponse.setBufferSize.ise=\u30c7\u30fc\u30bf\u304c\u65e2\u306b\u66f8\u304d\u8fbc\u307e\u308c\u305f\u5f8c\u3067\u30d0\u30c3\u30d5\u30a1\u30b5\u30a4\u30ba\u3092\u5909\u66f4\u3059\u308b\u3053\u3068\u306f\u3067\u304d\u307e\u305b\u3093
+
+#
+# CoyoteRequest
+#
+
+coyoteRequest.getInputStream.ise=getReader()\u306f\u3053\u306e\u30ea\u30af\u30a8\u30b9\u30c8\u306b\u5bfe\u3057\u3066\u65e2\u306b\u547c\u3073\u51fa\u3055\u308c\u3066\u3044\u307e\u3059
+coyoteRequest.getReader.ise=getInputStream()\u306f\u3053\u306e\u30ea\u30af\u30a8\u30b9\u30c8\u306b\u5bfe\u3057\u3066\u65e2\u306b\u547c\u3073\u51fa\u3055\u308c\u3066\u3044\u307e\u3059
+coyoteRequest.sessionCreateCommitted=\u30ec\u30b9\u30dd\u30f3\u30b9\u3092\u30b3\u30df\u30c3\u30c8\u3057\u305f\u5f8c\u3067\u30bb\u30c3\u30b7\u30e7\u30f3\u3092\u4f5c\u6210\u3067\u304d\u307e\u305b\u3093
+coyoteRequest.setAttribute.namenull=setAttribute\u3092\u540d\u524d\u3092\u6307\u5b9a\u305b\u305a\u306b\u547c\u3073\u51fa\u3059\u3053\u3068\u306f\u3067\u304d\u307e\u305b\u3093

Added: branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/java/org/apache/coyote/tomcat4/OutputBuffer.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/java/org/apache/coyote/tomcat4/OutputBuffer.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/java/org/apache/coyote/tomcat4/OutputBuffer.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,675 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.tomcat4;
+
+import java.io.IOException;
+import java.io.Writer;
+import java.util.Hashtable;
+
+import org.apache.catalina.connector.ClientAbortException;
+import org.apache.coyote.ActionCode;
+import org.apache.coyote.Response;
+import org.apache.tomcat.util.buf.ByteChunk;
+import org.apache.tomcat.util.buf.C2BConverter;
+import org.apache.tomcat.util.buf.CharChunk;
+
+
+/**
+ * The buffer used by Tomcat response. This is a derivative of the Tomcat 3.3
+ * OutputBuffer, with the removal of some of the state handling (which in 
+ * Coyote is mostly the Processor's responsability).
+ *
+ * @author Costin Manolache
+ * @author Remy Maucherat
+ */
+public class OutputBuffer extends Writer
+    implements ByteChunk.ByteOutputChannel, CharChunk.CharOutputChannel {
+
+
+    private static org.apache.commons.logging.Log log=
+        org.apache.commons.logging.LogFactory.getLog( OutputBuffer.class );
+
+    // -------------------------------------------------------------- Constants
+
+
+    public static final String DEFAULT_ENCODING = 
+        org.apache.coyote.Constants.DEFAULT_CHARACTER_ENCODING;
+    public static final int DEFAULT_BUFFER_SIZE = 8*1024;
+    static final int debug = 0;
+
+
+    // The buffer can be used for byte[] and char[] writing
+    // ( this is needed to support ServletOutputStream and for
+    // efficient implementations of templating systems )
+    public final int INITIAL_STATE = 0;
+    public final int CHAR_STATE = 1;
+    public final int BYTE_STATE = 2;
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The byte buffer.
+     */
+    private ByteChunk bb;
+
+
+    /**
+     * The chunk buffer.
+     */
+    private CharChunk cb;
+
+
+    /**
+     * State of the output buffer.
+     */
+    private int state = 0;
+
+
+    /**
+     * Number of bytes written.
+     */
+    private int bytesWritten = 0;
+
+
+    /**
+     * Number of chars written.
+     */
+    private int charsWritten = 0;
+
+
+    /**
+     * Flag which indicates if the output buffer is closed.
+     */
+    private boolean closed = false;
+
+
+    /**
+     * Do a flush on the next operation.
+     */
+    private boolean doFlush = false;
+
+
+    /**
+     * Byte chunk used to output bytes.
+     */
+    private ByteChunk outputChunk = new ByteChunk();
+
+
+    /**
+     * Encoding to use.
+     */
+    private String enc;
+
+
+    /**
+     * Encoder is set.
+     */
+    private boolean gotEnc = false;
+
+
+    /**
+     * List of encoders.
+     */
+    protected Hashtable encoders = new Hashtable();
+
+
+    /**
+     * Current char to byte converter.
+     */
+    protected C2BConverter conv;
+
+
+    /**
+     * Associated Coyote response.
+     */
+    private Response coyoteResponse;
+
+
+    /**
+     * Suspended flag. All output bytes will be swallowed if this is true.
+     */
+    private boolean suspended = false;
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Default constructor. Allocate the buffer with the default buffer size.
+     */
+    public OutputBuffer() {
+
+        this(DEFAULT_BUFFER_SIZE);
+
+    }
+
+
+    /**
+     * Alternate constructor which allows specifying the initial buffer size.
+     * 
+     * @param size Buffer size to use
+     */
+    public OutputBuffer(int size) {
+
+        bb = new ByteChunk(size);
+        bb.setLimit(size);
+        bb.setByteOutputChannel(this);
+        cb = new CharChunk(size);
+        cb.setCharOutputChannel(this);
+        cb.setLimit(size);
+
+    }
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * Associated Coyote response.
+     * 
+     * @param coyoteResponse Associated Coyote response
+     */
+    public void setResponse(Response coyoteResponse) {
+	this.coyoteResponse = coyoteResponse;
+    }
+
+
+    /**
+     * Get associated Coyote response.
+     * 
+     * @return the associated Coyote response
+     */
+    public Response getResponse() {
+        return this.coyoteResponse;
+    }
+
+
+    /**
+     * Is the response output suspended ?
+     * 
+     * @return suspended flag value
+     */
+    public boolean isSuspended() {
+        return this.suspended;
+    }
+
+
+    /**
+     * Set the suspended flag.
+     * 
+     * @param suspended New suspended flag value
+     */
+    public void setSuspended(boolean suspended) {
+        this.suspended = suspended;
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Recycle the output buffer.
+     */
+    public void recycle() {
+
+	if (debug > 0)
+            log("recycle()");
+
+	state = INITIAL_STATE;
+	bytesWritten = 0;
+	charsWritten = 0;
+
+        cb.recycle();
+        bb.recycle(); 
+        closed = false;
+        suspended = false;
+
+        if (conv!= null) {
+            conv.recycle();
+        }
+
+        gotEnc = false;
+        enc = null;
+
+    }
+
+
+    /**
+     * Close the output buffer. This tries to calculate the response size if 
+     * the response has not been committed yet.
+     * 
+     * @throws IOException An underlying IOException occurred
+     */
+    public void close()
+        throws IOException {
+
+        if (closed)
+            return;
+        if (suspended)
+            return;
+
+        if ((!coyoteResponse.isCommitted()) 
+            && (coyoteResponse.getContentLengthLong() == -1)) {
+            // Flushing the char buffer
+            if (state == CHAR_STATE) {
+                cb.flushBuffer();
+                state = BYTE_STATE;
+            }
+            // If this didn't cause a commit of the response, the final content
+            // length can be calculated
+            if (!coyoteResponse.isCommitted()) {
+                coyoteResponse.setContentLength(bb.getLength());
+            }
+        }
+
+        doFlush(false);
+        closed = true;
+
+        coyoteResponse.finish();
+
+    }
+
+
+    /**
+     * Flush bytes or chars contained in the buffer.
+     * 
+     * @throws IOException An underlying IOException occurred
+     */
+    public void flush()
+        throws IOException {
+        doFlush(true);
+    }
+
+
+    /**
+     * Flush bytes or chars contained in the buffer.
+     * 
+     * @throws IOException An underlying IOException occurred
+     */
+    protected void doFlush(boolean realFlush)
+        throws IOException {
+
+        if (suspended)
+            return;
+
+        doFlush = true;
+        if (state == CHAR_STATE) {
+            cb.flushBuffer();
+            bb.flushBuffer();
+            state = BYTE_STATE;
+        } else if (state == BYTE_STATE) {
+            bb.flushBuffer();
+        } else if (state == INITIAL_STATE)
+            realWriteBytes(null, 0, 0);       // nothing written yet
+        doFlush = false;
+
+        if (realFlush) {
+            coyoteResponse.action(ActionCode.ACTION_CLIENT_FLUSH, 
+                                  coyoteResponse);
+            // If some exception occurred earlier, or if some IOE occurred
+            // here, notify the servlet with an IOE
+            if (coyoteResponse.isExceptionPresent()) {
+                throw new ClientAbortException
+                    (coyoteResponse.getErrorException());
+            }
+        }
+
+    }
+
+
+    // ------------------------------------------------- Bytes Handling Methods
+
+
+    /** 
+     * Sends the buffer data to the client output, checking the
+     * state of Response and calling the right interceptors.
+     * 
+     * @param buf Byte buffer to be written to the response
+     * @param off Offset
+     * @param cnt Length
+     * 
+     * @throws IOException An underlying IOException occurred
+     */
+    public void realWriteBytes(byte buf[], int off, int cnt)
+	throws IOException {
+
+        if (debug > 2)
+            log("realWrite(b, " + off + ", " + cnt + ") " + coyoteResponse);
+
+        if (closed)
+            return;
+        if (coyoteResponse == null)
+            return;
+
+        // If we really have something to write
+        if (cnt > 0) {
+            // real write to the adapter
+            outputChunk.setBytes(buf, off, cnt);
+            try {
+                coyoteResponse.doWrite(outputChunk);
+            } catch (IOException e) {
+                // An IOException on a write is almost always due to
+                // the remote client aborting the request.  Wrap this
+                // so that it can be handled better by the error dispatcher.
+                throw new ClientAbortException(e);
+            }
+        }
+
+    }
+
+
+    public void write(byte b[], int off, int len) throws IOException {
+
+        if (suspended)
+            return;
+
+        if (state == CHAR_STATE)
+            cb.flushBuffer();
+        state = BYTE_STATE;
+        writeBytes(b, off, len);
+
+    }
+
+
+    private void writeBytes(byte b[], int off, int len) 
+        throws IOException {
+
+        if (closed)
+            return;
+        if (debug > 0)
+            log("write(b,off,len)");
+
+        bb.append(b, off, len);
+        bytesWritten += len;
+
+        // if called from within flush(), then immediately flush
+        // remaining bytes
+        if (doFlush) {
+            bb.flushBuffer();
+        }
+
+    }
+
+
+    // XXX Char or byte ?
+    public void writeByte(int b)
+        throws IOException {
+
+        if (suspended)
+            return;
+
+        if (state == CHAR_STATE)
+            cb.flushBuffer();
+        state = BYTE_STATE;
+
+        if (debug > 0)
+            log("write(b)");
+
+        bb.append( (byte)b );
+        bytesWritten++;
+
+    }
+
+
+    // ------------------------------------------------- Chars Handling Methods
+
+
+    public void write(int c)
+        throws IOException {
+
+        if (suspended)
+            return;
+
+        state = CHAR_STATE;
+
+        if (debug > 0)
+            log("writeChar(b)");
+
+        cb.append((char) c);
+        charsWritten++;
+
+    }
+
+
+    public void write(char c[])
+        throws IOException {
+
+        if (suspended)
+            return;
+
+        write(c, 0, c.length);
+
+    }
+
+
+    public void write(char c[], int off, int len)
+        throws IOException {
+
+        if (suspended)
+            return;
+
+        state = CHAR_STATE;
+
+        if (debug > 0)
+            log("write(c,off,len)" + cb.getLength() + " " + cb.getLimit());
+
+        cb.append(c, off, len);
+        charsWritten += len;
+
+    }
+
+
+    public void write(StringBuffer sb)
+        throws IOException {
+
+        if (suspended)
+            return;
+
+        state = CHAR_STATE;
+
+        if (debug > 1)
+            log("write(s,off,len)");
+
+        int len = sb.length();
+        charsWritten += len;
+        cb.append(sb);
+
+    }
+
+
+    /**
+     * Append a string to the buffer
+     */
+    public void write(String s, int off, int len)
+        throws IOException {
+
+        if (suspended)
+            return;
+
+        state=CHAR_STATE;
+
+        if (debug > 1)
+            log("write(s,off,len)");
+
+        charsWritten += len;
+        if (s==null)
+            s="null";
+        cb.append( s, off, len );
+
+    }
+
+
+    public void write(String s)
+        throws IOException {
+
+        if (suspended)
+            return;
+
+        state = CHAR_STATE;
+        if (s==null)
+            s="null";
+        write(s, 0, s.length());
+
+    } 
+
+
+    public void flushChars()
+        throws IOException {
+
+        if (debug > 0)
+            log("flushChars() " + cb.getLength());
+
+        cb.flushBuffer();
+        state = BYTE_STATE;
+
+    }
+
+
+    public boolean flushCharsNeeded() {
+        return state == CHAR_STATE;
+    }
+
+
+    public void setEncoding(String s) {
+        enc = s;
+    }
+
+
+    public void realWriteChars(char c[], int off, int len) 
+        throws IOException {
+
+        if (debug > 0)
+            log("realWrite(c,o,l) " + cb.getOffset() + " " + len);
+
+        if (!gotEnc)
+            setConverter();
+
+        if (debug > 0)
+            log("encoder:  " + conv + " " + gotEnc);
+
+        conv.convert(c, off, len);
+        conv.flushBuffer();	// ???
+
+    }
+
+
+    protected void setConverter() {
+
+        if (coyoteResponse != null)
+            enc = coyoteResponse.getCharacterEncoding();
+
+        if (debug > 0)
+            log("Got encoding: " + enc);
+
+        gotEnc = true;
+        if (enc == null)
+            enc = DEFAULT_ENCODING;
+        conv = (C2BConverter) encoders.get(enc);
+        if (conv == null) {
+            try {
+                conv = new C2BConverter(bb, enc);
+                encoders.put(enc, conv);
+            } catch (IOException e) {
+                conv = (C2BConverter) encoders.get(DEFAULT_ENCODING);
+                if (conv == null) {
+                    try {
+                        conv = new C2BConverter(bb, DEFAULT_ENCODING);
+                        encoders.put(DEFAULT_ENCODING, conv);
+                    } catch (IOException ex) {
+                        // Ignore
+                    }
+                }
+            }
+        }
+    }
+
+    
+    // --------------------  BufferedOutputStream compatibility
+
+
+    /**
+     * Real write - this buffer will be sent to the client
+     */
+    public void flushBytes()
+        throws IOException {
+
+        if (debug > 0)
+            log("flushBytes() " + bb.getLength());
+        bb.flushBuffer();
+
+    }
+
+
+    public int getBytesWritten() {
+        return bytesWritten;
+    }
+
+
+    public int getCharsWritten() {
+        return charsWritten;
+    }
+
+
+    public int getContentWritten() {
+        return bytesWritten + charsWritten;
+    }
+
+
+    /** 
+     * True if this buffer hasn't been used ( since recycle() ) -
+     * i.e. no chars or bytes have been added to the buffer.  
+     */
+    public boolean isNew() {
+        return (bytesWritten == 0) && (charsWritten == 0);
+    }
+
+
+    public void setBufferSize(int size) {
+        if (size > bb.getLimit()) {// ??????
+	    bb.setLimit(size);
+	}
+    }
+
+
+    public void reset() {
+
+        //count=0;
+        bb.recycle();
+        bytesWritten = 0;
+        cb.recycle();
+        charsWritten = 0;
+        gotEnc = false;
+        enc = null;
+
+    }
+
+
+    public int getBufferSize() {
+	return bb.getLimit();
+    }
+
+
+
+    protected void log( String s ) {
+        if (log.isDebugEnabled()) 
+            log.debug("OutputBuffer: " + s);
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/test/org/apache/coyote/SimpleAdapter.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/test/org/apache/coyote/SimpleAdapter.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/coyote/src/test/org/apache/coyote/SimpleAdapter.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,51 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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;
+
+import org.apache.tomcat.util.buf.MessageBytes;
+import org.apache.tomcat.util.http.MimeHeaders;
+
+/**
+ * Simple adapter.
+ *
+ * @author Remy Maucherat
+ */
+public class Adapter {
+
+
+    public static final String CRLF = "\r\n";
+
+
+    /** 
+     * Service method, which dumps the request to the console.
+     */
+    public void service(Request req, Response res)
+	throws Exception {
+        
+        StringBuffer buf = new StringBuffer();
+        buf.append(req.method());
+        buf.append(" ");
+        buf.append(req.unparsedURI());
+        buf.append(" ");
+        buf.append(req.protocol());
+        buf.append(CRLF);
+        
+        
+        
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/doc/install_tomcat33.html
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/doc/install_tomcat33.html	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/doc/install_tomcat33.html	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,24 @@
+<html>
+<head>
+<title>Installing tomcat-connector in tomcat3.3</title>
+</head>
+<body>
+<h2>Installing tomcat-connector in tomcat3.3</h2>
+<ul>
+<li> copy mx4j-jmx.jar ( or jmxri.jar ) to lib/common</li>
+<li> copy tomcat-coyote.jar, tomcat33-coyote.jar, tomcat-jk2.jar,
+tomcat-http11.jar to lib/container</li>
+<li> replace lib/common/connector-util.jar with tomcat-util.jar</li>
+<li> copy commons-logging-api.jar and tomcat33-resources.jar to lib/common</li>
+<li> edit conf/modules.xml and insert:<br />
+&nbsp; &lt;module name="CoyoteConnector"
+&nbsp; javaClass="org.apache.coyote.tomcat3.CoyoteInterceptor2"/&gt; </li>
+<li>edit conf/server.xml and replace Http10Connector and Ajp13Connector  with: <br />
+&nbsp; &lt;CoyoteConnector port="8080" /&gt;
+&nbsp; <br /> and<br />
+&nbsp; &lt;CoyoteConnector port="8009"
+&nbsp; processorClassName="org.apache.jk.server.JkCoyoteHandler"/&gt;
+</li>
+</ul>
+</body>
+</html>

Added: branches/tomcat5.5/upstream/5.5.20/connectors/doc/install_tomcat40.html
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/doc/install_tomcat40.html	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/doc/install_tomcat40.html	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,28 @@
+<html>
+<head>
+<title>Installing tomcat-connector in tomcat4.0</title>
+</head>
+<body>
+<h2>Installing tomcat-connector in tomcat4.0</h2>
+</body>
+<ul>
+<li>replace tomcat-coyote.jar, tomcat-http11.jar, tomcat-jk2.jar
+and tomcat-util.jar in server/lib</li>
+<li>add tomcat4-coyote.jar to server/lib</li>
+<li>copy mx4j-jmx.jar ( or jmxri.jar ) to common/lib. </li>
+<li>edit server.xml, comment out the original connector (
+org.apache.catalina.connector.http.HttpConnector ) and uncomment the
+coyote connector ( in &lt;Connector className="org.apache.coyote.tomcat4.CoyoteConnector" /&gt; )
+</li>
+<li>also in server.xml, comment out the ajp connector (
+org.apache.ajp.tomcat4.Ajp13Connector ) and add a jk2 connector:
+<br />&nbsp; &lt;Connector className="org.apache.coyote.tomcat4.CoyoteConnector"
+&nbsp; port="8009" minProcessors="5" maxProcessors="75"
+&nbsp; enableLookups="true" redirectPort="8443"
+&nbsp; acceptCount="10" debug="0" connectionTimeout="0"
+&nbsp; useURIValidationHack="false"
+&nbsp; protocolHandlerClassName="org.apache.jk.server.JkCoyoteHandler"/&gt;
+</li>
+</ul>
+</body>
+</html>

Added: branches/tomcat5.5/upstream/5.5.20/connectors/doc/install_tomcat41.html
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/doc/install_tomcat41.html	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/doc/install_tomcat41.html	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,20 @@
+<html>
+<head>
+<title>Installing tomcat-connector in tomcat4.1</title>
+</head>
+<body>
+<h2>Installing tomcat-connector in tomcat4.1</h2>
+<ul>
+<li>get the new connector ( I'll post the URL soon )</li>
+<li>move mx4j-jmx.jar from server/lib to common/lib. This is not required, but allows you to use JMX. If you run
+ tomcat in a sandbox - you can replace mx4j-jmx with jmxri-1.2, which has policy-based security.</li>
+<li>in server/lib, replace tomcat-util.jar, tomcat-jk2.jar, tomcat-coyote.jar and tomcat-http11.jar with the new
+ versions.</li>
+<li>copy tomcat4-coyote.jar to server/lib. This is a new file containing the coyote adapter for tomcat4, used to
+ be in tomcat-coyote.jar</li>
+<li>remove bin/tomcat-jni.jar ( it is an odd file that causes several
+problems - if you use in-process tomcat we'll provide a different
+mechanism )</li>
+</ul>
+</body>
+</html>

Added: branches/tomcat5.5/upstream/5.5.20/connectors/http11/build.properties.sample
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/http11/build.properties.sample	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/http11/build.properties.sample	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,37 @@
+# -------------------------------------------------------------------
+# build.properties.sample
+#
+# This is an example "build.properties" file, used to customize 
+# building Jakarta Coyote for your local environment.  
+# Make any changes you need, and rename this file to 
+# "build.properties" 
+#
+# $Id: build.properties.sample 298963 2003-10-07 14:28:34Z hgomez $
+# -------------------------------------------------------------------
+
+
+# -------------------------------------------------------------------
+# CONFIGURATION OPTIONS
+# -------------------------------------------------------------------
+
+# 
+
+
+# -------------------------------------------------------------------
+# EXTERNAL DEPENDENCIES 
+# -------------------------------------------------------------------
+
+# tomcat-util.jar -- Tomcat util package
+tomcat-util.jar=../util/build/lib/tomcat-util.jar
+
+# coyote.jar -- Coyote package
+coyote.jar=../coyote/dist/coyote.jar
+
+# junit.jar -- JUnit classes (http://junit.org)
+junit.jar=/java/junit/junit.jar
+
+# commons-logging.jar -- Commons Logging 1.0 package
+commons-logging.jar=../lib/commons-logging.jar
+
+# ----- Jakarta Regular Expressions Library, version 1.3 -----
+regexp.jar=../lib/jakarta-regexp-1.3.jar

Added: branches/tomcat5.5/upstream/5.5.20/connectors/http11/build.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/http11/build.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/http11/build.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,241 @@
+<project name="Coyote" default="compile" basedir=".">
+
+
+<!--
+        "Coyote" connector framework for Jakarta Tomcat
+        $Id: build.xml 300446 2005-04-15 03:10:02Z billbarker $
+-->
+
+
+<!-- ========== Initialize Properties ===================================== -->
+
+
+  <property file="build.properties"/>                <!-- Component local   -->
+  <property file="../build.properties"/>             <!-- Commons local     -->
+  <property file="${user.home}/build.properties"/>   <!-- User local        -->
+
+
+<!-- ========== External Dependencies ===================================== -->
+
+
+  <!-- The directories corresponding to your necessary dependencies -->
+  <property name="junit.home"              value="/usr/local/junit3.5"/>
+
+  <!-- Dependencies within jakarta-tomcat-connectors -->
+  <property name="util.home" value="../util"/>
+  <property name="coyote.home" value="../coyote"/>
+
+
+<!-- ========== Derived Values ============================================ -->
+
+
+  <!-- The locations of necessary jar files -->
+  <property name="tomcat-util.jar"  value="${util.home}/build/lib/tomcat-util.jar"/>
+  <property name="tomcat-jni.jar" value="../jni/dist/tomcat-native-1.0.0.jar" />
+  <property name="tomcat-coyote.jar" value="${coyote.home}/build/lib/tomcat-coyote.jar"/>
+  <property name="tomcat33-coyote.jar" 
+          value="${coyote.home}/build/lib/tomcat33-coyote.jar"/>
+  <property name="junit.jar"        value="${junit.home}/junit.jar"/>
+  <property name="jmx.jar" location="../lib/mx4j.jar" />
+  <property name="commons-modeler.jar" location="../../jakarta-commons/modeler/dist/commons-modeler.jar" />
+  <property name="commons-logging.jar" value="../lib/commons-logging.jar" />
+  <property name="regexp.jar" value="../lib/jakarta-regexp-1.3.jar" />
+
+<!-- ========== Component Declarations ==================================== -->
+
+
+  <!-- The name of this component -->
+  <property name="component.name"          value="http11"/>
+
+  <!-- The title of this component -->
+  <property name="component.title"         value="Coyote HTTP/1.1 Connector"/>
+
+  <!-- The current version number of this component -->
+  <property name="component.version"       value="1.0-dev"/>
+
+  <!-- The base directory for compilation targets -->
+  <property name="build.home"              value="build"/>
+
+  <!-- The base directory for component configuration files -->
+  <property name="conf.home"               value="src/conf"/>
+
+  <!-- The base directory for component sources -->
+  <property name="source.home"             value="src/java"/>
+
+  <!-- The base directory for unit test sources -->
+  <property name="test.home"               value="src/test"/>
+
+<!-- ========== Compiler Defaults ========================================= -->
+
+
+  <!-- Should Java compilations set the 'debug' compiler option? -->
+  <property name="compile.debug"           value="true"/>
+
+  <!-- Should Java compilations set the 'deprecation' compiler option? -->
+  <property name="compile.deprecation"     value="false"/>
+
+  <!-- Should Java compilations set the 'optimize' compiler option? -->
+  <property name="compile.optimize"        value="true"/>
+
+  <!-- Construct compile classpath -->
+  <path id="compile.classpath">
+    <pathelement location="${build.home}/classes"/>
+    <pathelement location="${tomcat-util.jar}"/>
+    <pathelement location="${tomcat-coyote.jar}"/>
+    <pathelement location="${commons-logging.jar}"/>
+    <pathelement location="${commons-modeler.jar}"/>
+    <pathelement location="${regexp.jar}"/>
+    <pathelement location="${jmx.jar}"/>
+    <pathelement location="${tomcat-jni.jar}" />
+  </path>
+
+
+<!-- ========== Test Execution Defaults =================================== -->
+
+
+  <!-- Construct unit test classpath -->
+  <path id="test.classpath">
+    <pathelement location="${build.home}/classes"/>
+    <pathelement location="${build.home}/tests"/>
+    <pathelement location="${tomcat-util.jar}"/>
+    <pathelement location="${tomcat-coyote.jar}"/>
+    <pathelement location="${commons-logging.jar}"/>
+    <pathelement location="${junit.jar}"/>
+  </path>
+
+  <!-- Should all tests fail if one does? -->
+  <property name="test.failonerror"        value="true"/>
+
+  <!-- The test runner to execute -->
+  <property name="test.runner"             value="junit.textui.TestRunner"/>
+  <property name="test.entry" value="org.apache.coyote.http11.TestAll"/>
+
+
+<!-- ========== Executable Targets ======================================== -->
+
+
+  <target name="init"
+   description="Initialize and evaluate conditionals">
+    <echo message="-------- ${component.title} ${component.version} --------"/>
+    <filter  token="name"                  value="${component.name}"/>
+    <filter  token="version"               value="${component.version}"/>
+  </target>
+
+
+  <target name="prepare" depends="init"
+   description="Prepare build directory">
+    <mkdir dir="${build.home}"/>
+    <mkdir dir="${build.home}/classes"/>
+    <mkdir dir="${build.home}/conf"/>
+    <mkdir dir="${build.home}/lib"/>
+    <mkdir dir="${build.home}/docs"/>
+    <mkdir dir="${build.home}/docs/api"/>
+    <mkdir dir="${build.home}/tests"/>
+  </target>
+
+
+  <target name="static" depends="prepare"
+   description="Copy static files to build directory">
+    <tstamp/>
+    <copy  todir="${build.home}/conf" filtering="on">
+      <fileset dir="${conf.home}" includes="*.MF"/>
+    </copy>
+  </target>
+
+
+  <target name="javadoc" unless="docs-uptodate"
+   description="Create component Javadoc documentation">
+    <mkdir dir="${build.home}/docs/api"/>
+    <javadoc sourcepath="${source.home}"
+                destdir="${build.home}/docs/api"
+           packagenames="org.apache.coyote.*"
+                 author="true"
+                private="true"
+                version="true"
+               doctitle="&lt;h1&gt;${component.title}&lt;/h1&gt;"
+            windowtitle="${component.title} (Version ${component.version})"
+                 bottom="Copyright (c) 2001 - Apache Software Foundation">
+      <classpath refid="compile.classpath"/>
+    </javadoc>
+  </target>
+
+  <target name="compile-only" 
+          description="Compile shareable components">
+
+    <javac  srcdir="${source.home}"
+           destdir="${build.home}/classes"
+             debug="${compile.debug}"
+       deprecation="${compile.deprecation}"
+          optimize="${compile.optimize}">
+      <classpath refid="compile.classpath"/>
+    </javac>
+    <copy    todir="${build.home}/classes" filtering="on">
+      <fileset dir="${source.home}" excludes="**/*.java"/>
+    </copy>
+    <property name="tomcat-http11.jar" value="${build.home}/lib/tomcat-${component.name}.jar"/>
+    <jar    jarfile="${tomcat-http11.jar}"
+             index="true"
+            basedir="${build.home}/classes"
+             manifest="${build.home}/conf/MANIFEST.MF">
+      <include name="org/apache/coyote/http11/**"/>
+    </jar>
+  </target>
+
+  <target name="compile" depends="static,compile-only"
+          description="Compile shareable components">
+    <jar jarfile="${build.home}/lib/tomcat33-resource.jar"
+         index="true"
+         basedir="${build.home}/classes" 
+         includes="**/*.properties" />
+  </target>
+
+
+  <target name="compile.tests" depends="compile"
+   description="Compile unit test cases">
+    <javac  srcdir="${test.home}/java"
+           destdir="${build.home}/tests"
+             debug="${compile.debug}"
+       deprecation="${compile.deprecation}"
+          optimize="${compile.optimize}">
+      <classpath refid="test.classpath"/>
+    </javac>
+    <copy    todir="${build.home}/tests" filtering="on">
+      <fileset dir="${test.home}" excludes="**/*.java"/>
+    </copy>
+  </target>
+
+
+  <target name="clean"
+   description="Clean build and distribution directories">
+    <delete    dir="${build.home}"/>
+    <delete    dir="${dist.home}"/>
+  </target>
+
+
+  <target name="all" depends="clean,compile,compile.tests"
+   description="Clean and compile all components"/>
+
+
+<!-- ========== Unit Test Targets ========================================= -->
+
+
+  <target name="test"  depends="compile.tests" if="test.entry"
+   description="Run all unit test cases">
+      <!--
+      <junit printsummary="yes" fork="on" haltonfailure="yes">
+      	<formatter type="plain" usefile="false"/>
+      	<test name="${test.entry}"/>
+        <classpath refid="test.classpath"/>
+      </junit>
+      -->
+
+      <java classname="${test.runner}" fork="yes"
+       failonerror="${test.failonerror}">
+        <jvmarg value="${java.protocol.handler.pkgs}"/>
+        <arg value="${test.entry}"/>
+        <classpath refid="test.classpath"/>
+      </java>
+  </target>
+
+
+</project>

Added: branches/tomcat5.5/upstream/5.5.20/connectors/http11/src/conf/MANIFEST.MF
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/http11/src/conf/MANIFEST.MF	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/http11/src/conf/MANIFEST.MF	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,6 @@
+Extension-Name: @name@
+Specification-Vendor: Apache Software Foundation
+Specification-Version: 1.1
+Implementation-Vendor: Apache Software Foundation
+Implementation-Version: @version@
+

Added: branches/tomcat5.5/upstream/5.5.20/connectors/http11/src/java/org/apache/coyote/http11/Constants.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/http11/src/java/org/apache/coyote/http11/Constants.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/http11/src/java/org/apache/coyote/http11/Constants.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,208 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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;
+
+import org.apache.tomcat.util.buf.ByteChunk;
+
+
+/**
+ * Constants.
+ *
+ * @author Remy Maucherat
+ */
+public final class Constants {
+
+
+    // -------------------------------------------------------------- Constants
+
+
+    /**
+     * Package name.
+     */
+    public static final String Package = "org.apache.coyote.http11";
+
+    public static final int DEFAULT_CONNECTION_LINGER = -1;
+    public static final int DEFAULT_CONNECTION_TIMEOUT = 60000;
+    public static final int DEFAULT_CONNECTION_UPLOAD_TIMEOUT = 300000;
+    public static final int DEFAULT_SERVER_SOCKET_TIMEOUT = 0;
+    public static final boolean DEFAULT_TCP_NO_DELAY = true;
+    
+    
+    /**
+     * CRLF.
+     */
+    public static final String CRLF = "\r\n";
+
+    
+    /**
+     * Server string.
+     */
+    public static final byte[] SERVER_BYTES = 
+        ByteChunk.convertToBytes("Server: Apache-Coyote/1.1" + CRLF);
+
+    
+    /**
+     * CR.
+     */
+    public static final byte CR = (byte) '\r';
+
+
+    /**
+     * LF.
+     */
+    public static final byte LF = (byte) '\n';
+
+
+    /**
+     * SP.
+     */
+    public static final byte SP = (byte) ' ';
+
+
+    /**
+     * HT.
+     */
+    public static final byte HT = (byte) '\t';
+
+
+    /**
+     * COLON.
+     */
+    public static final byte COLON = (byte) ':';
+
+
+    /**
+     * 'A'.
+     */
+    public static final byte A = (byte) 'A';
+
+
+    /**
+     * 'a'.
+     */
+    public static final byte a = (byte) 'a';
+
+
+    /**
+     * 'Z'.
+     */
+    public static final byte Z = (byte) 'Z';
+
+
+    /**
+     * '?'.
+     */
+    public static final byte QUESTION = (byte) '?';
+
+
+    /**
+     * Lower case offset.
+     */
+    public static final byte LC_OFFSET = A - a;
+
+
+    /**
+     * Default HTTP header buffer size.
+     */
+    public static final int DEFAULT_HTTP_HEADER_BUFFER_SIZE = 48 * 1024;
+
+
+    /* Various constant "strings" */
+    public static final byte[] CRLF_BYTES = ByteChunk.convertToBytes(CRLF);
+    public static final byte[] COLON_BYTES = ByteChunk.convertToBytes(": ");
+    public static final String CONNECTION = "Connection";
+    public static final String CLOSE = "close";
+    public static final byte[] CLOSE_BYTES = 
+        ByteChunk.convertToBytes(CLOSE);
+    public static final String KEEPALIVE = "keep-alive";
+    public static final byte[] KEEPALIVE_BYTES = 
+        ByteChunk.convertToBytes(KEEPALIVE);
+    public static final String CHUNKED = "chunked";
+    public static final byte[] ACK_BYTES = 
+        ByteChunk.convertToBytes("HTTP/1.1 100 Continue" + CRLF + CRLF);
+    public static final String TRANSFERENCODING = "Transfer-Encoding";
+    public static final byte[] _200_BYTES = 
+        ByteChunk.convertToBytes("200");
+    public static final byte[] _400_BYTES = 
+        ByteChunk.convertToBytes("400");
+    public static final byte[] _404_BYTES = 
+        ByteChunk.convertToBytes("404");
+    
+
+    /**
+     * Identity filters (input and output).
+     */
+    public static final int IDENTITY_FILTER = 0;
+
+
+    /**
+     * Chunked filters (input and output).
+     */
+    public static final int CHUNKED_FILTER = 1;
+
+
+    /**
+     * Void filters (input and output).
+     */
+    public static final int VOID_FILTER = 2;
+
+
+    /**
+     * GZIP filter (output).
+     */
+    public static final int GZIP_FILTER = 3;
+
+
+    /**
+     * Buffered filter (input)
+     */
+    public static final int BUFFERED_FILTER = 3;
+
+
+    /**
+     * HTTP/1.0.
+     */
+    public static final String HTTP_10 = "HTTP/1.0";
+
+
+    /**
+     * HTTP/1.1.
+     */
+    public static final String HTTP_11 = "HTTP/1.1";
+    public static final byte[] HTTP_11_BYTES = 
+        ByteChunk.convertToBytes(HTTP_11);
+
+
+    /**
+     * GET.
+     */
+    public static final String GET = "GET";
+
+
+    /**
+     * HEAD.
+     */
+    public static final String HEAD = "HEAD";
+
+
+    /**
+     * POST.
+     */
+    public static final String POST = "POST";
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/http11/src/java/org/apache/coyote/http11/Http11AprProcessor.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/http11/src/java/org/apache/coyote/http11/Http11AprProcessor.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/http11/src/java/org/apache/coyote/http11/Http11AprProcessor.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,1757 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InterruptedIOException;
+import java.util.StringTokenizer;
+import java.util.regex.Pattern;
+import java.util.regex.PatternSyntaxException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+
+import org.apache.coyote.ActionCode;
+import org.apache.coyote.ActionHook;
+import org.apache.coyote.Adapter;
+import org.apache.coyote.Request;
+import org.apache.coyote.RequestInfo;
+import org.apache.coyote.Response;
+import org.apache.coyote.http11.filters.ChunkedInputFilter;
+import org.apache.coyote.http11.filters.ChunkedOutputFilter;
+import org.apache.coyote.http11.filters.GzipOutputFilter;
+import org.apache.coyote.http11.filters.IdentityInputFilter;
+import org.apache.coyote.http11.filters.IdentityOutputFilter;
+import org.apache.coyote.http11.filters.SavedRequestInputFilter;
+import org.apache.coyote.http11.filters.VoidInputFilter;
+import org.apache.coyote.http11.filters.VoidOutputFilter;
+import org.apache.coyote.http11.filters.BufferedInputFilter;
+import org.apache.tomcat.jni.Address;
+import org.apache.tomcat.jni.SSL;
+import org.apache.tomcat.jni.SSLSocket;
+import org.apache.tomcat.jni.Sockaddr;
+import org.apache.tomcat.jni.Socket;
+import org.apache.tomcat.util.buf.Ascii;
+import org.apache.tomcat.util.buf.ByteChunk;
+import org.apache.tomcat.util.buf.HexUtils;
+import org.apache.tomcat.util.buf.MessageBytes;
+import org.apache.tomcat.util.http.FastHttpDateFormat;
+import org.apache.tomcat.util.http.MimeHeaders;
+import org.apache.tomcat.util.net.AprEndpoint;
+import org.apache.tomcat.util.res.StringManager;
+import org.apache.tomcat.util.threads.ThreadWithAttributes;
+
+
+/**
+ * Processes HTTP requests.
+ *
+ * @author Remy Maucherat
+ */
+public class Http11AprProcessor implements ActionHook {
+
+
+    /**
+     * Logger.
+     */
+    protected static org.apache.commons.logging.Log log
+        = org.apache.commons.logging.LogFactory.getLog(Http11AprProcessor.class);
+
+    /**
+     * The string manager for this package.
+     */
+    protected static StringManager sm =
+        StringManager.getManager(Constants.Package);
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    public Http11AprProcessor(int headerBufferSize, AprEndpoint endpoint) {
+
+        this.endpoint = endpoint;
+        
+        request = new Request();
+        int readTimeout = endpoint.getFirstReadTimeout();
+        if (readTimeout == 0) {
+            readTimeout = 100;
+        } else if (readTimeout < 0) {
+            readTimeout = -1;
+        }
+        inputBuffer = new InternalAprInputBuffer(request, headerBufferSize,
+                readTimeout);
+        request.setInputBuffer(inputBuffer);
+
+        response = new Response();
+        response.setHook(this);
+        outputBuffer = new InternalAprOutputBuffer(response, headerBufferSize);
+        response.setOutputBuffer(outputBuffer);
+        request.setResponse(response);
+        
+        ssl = !"off".equalsIgnoreCase(endpoint.getSSLEngine());
+
+        initializeFilters();
+
+        // Cause loading of HexUtils
+        int foo = HexUtils.DEC[0];
+
+        // Cause loading of FastHttpDateFormat
+        FastHttpDateFormat.getCurrentDate();
+
+    }
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * Associated adapter.
+     */
+    protected Adapter adapter = null;
+
+
+    /**
+     * Request object.
+     */
+    protected Request request = null;
+
+
+    /**
+     * Response object.
+     */
+    protected Response response = null;
+
+
+    /**
+     * Input.
+     */
+    protected InternalAprInputBuffer inputBuffer = null;
+
+
+    /**
+     * Output.
+     */
+    protected InternalAprOutputBuffer outputBuffer = null;
+
+
+    /**
+     * State flag.
+     */
+    protected boolean started = false;
+
+
+    /**
+     * Error flag.
+     */
+    protected boolean error = false;
+
+
+    /**
+     * Keep-alive.
+     */
+    protected boolean keepAlive = true;
+
+
+    /**
+     * HTTP/1.1 flag.
+     */
+    protected boolean http11 = true;
+
+
+    /**
+     * HTTP/0.9 flag.
+     */
+    protected boolean http09 = false;
+
+
+    /**
+     * Sendfile data.
+     */
+    protected AprEndpoint.SendfileData sendfileData = null;
+
+
+    /**
+     * Content delimitator for the request (if false, the connection will
+     * be closed at the end of the request).
+     */
+    protected boolean contentDelimitation = true;
+
+
+    /**
+     * Is there an expectation ?
+     */
+    protected boolean expectation = false;
+
+
+    /**
+     * List of restricted user agents.
+     */
+    protected Pattern[] restrictedUserAgents = null;
+
+
+    /**
+     * Maximum number of Keep-Alive requests to honor.
+     */
+    protected int maxKeepAliveRequests = -1;
+
+
+    /**
+     * SSL enabled ?
+     */
+    protected boolean ssl = false;
+    
+
+    /**
+     * Socket associated with the current connection.
+     */
+    protected long socket = 0;
+
+
+    /**
+     * Remote Address associated with the current connection.
+     */
+    protected String remoteAddr = null;
+
+
+    /**
+     * Remote Host associated with the current connection.
+     */
+    protected String remoteHost = null;
+
+
+    /**
+     * Local Host associated with the current connection.
+     */
+    protected String localName = null;
+
+
+
+    /**
+     * Local port to which the socket is connected
+     */
+    protected int localPort = -1;
+
+
+    /**
+     * Remote port to which the socket is connected
+     */
+    protected int remotePort = -1;
+
+
+    /**
+     * The local Host address.
+     */
+    protected String localAddr = null;
+
+
+    /**
+     * Maximum timeout on uploads. 5 minutes as in Apache HTTPD server.
+     */
+    protected int timeout = 300000;
+
+
+    /**
+     * Flag to disable setting a different time-out on uploads.
+     */
+    protected boolean disableUploadTimeout = false;
+
+
+    /**
+     * Allowed compression level.
+     */
+    protected int compressionLevel = 0;
+
+
+    /**
+     * Minimum contentsize to make compression.
+     */
+    protected int compressionMinSize = 2048;
+
+
+    /**
+     * Socket buffering.
+     */
+    protected int socketBuffer = -1;
+
+
+    /**
+     * Max save post size.
+     */
+    protected int maxSavePostSize = 4 * 1024;
+
+
+    /**
+     * List of user agents to not use gzip with
+     */
+    protected Pattern noCompressionUserAgents[] = null;
+
+    /**
+     * List of MIMES which could be gzipped
+     */
+    protected String[] compressableMimeTypes =
+    { "text/html", "text/xml", "text/plain" };
+
+
+    /**
+     * Host name (used to avoid useless B2C conversion on the host name).
+     */
+    protected char[] hostNameC = new char[0];
+
+
+    /**
+     * Associated endpoint.
+     */
+    protected AprEndpoint endpoint;
+
+
+    /**
+     * Allow a customized the server header for the tin-foil hat folks.
+     */
+    protected String server = null;
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * Return compression level.
+     */
+    public String getCompression() {
+        switch (compressionLevel) {
+        case 0:
+            return "off";
+        case 1:
+            return "on";
+        case 2:
+            return "force";
+        }
+        return "off";
+    }
+
+
+    /**
+     * Set compression level.
+     */
+    public void setCompression(String compression) {
+        if (compression.equals("on")) {
+            this.compressionLevel = 1;
+        } else if (compression.equals("force")) {
+            this.compressionLevel = 2;
+        } else if (compression.equals("off")) {
+            this.compressionLevel = 0;
+        } else {
+            try {
+                // Try to parse compression as an int, which would give the
+                // minimum compression size
+                compressionMinSize = Integer.parseInt(compression);
+                this.compressionLevel = 1;
+            } catch (Exception e) {
+                this.compressionLevel = 0;
+            }
+        }
+    }
+
+    /**
+     * Set Minimum size to trigger compression.
+     */
+    public void setCompressionMinSize(int compressionMinSize) {
+        this.compressionMinSize = compressionMinSize;
+    }
+
+
+    /**
+     * Add user-agent for which gzip compression didn't works
+     * The user agent String given will be exactly matched
+     * to the user-agent header submitted by the client.
+     *
+     * @param userAgent user-agent string
+     */
+    public void addNoCompressionUserAgent(String userAgent) {
+        try {
+            Pattern nRule = Pattern.compile(userAgent);
+            noCompressionUserAgents =
+                addREArray(noCompressionUserAgents, nRule);
+        } catch (PatternSyntaxException pse) {
+            log.error(sm.getString("http11processor.regexp.error", userAgent), pse);
+        }
+    }
+
+
+    /**
+     * Set no compression user agent list (this method is best when used with
+     * a large number of connectors, where it would be better to have all of
+     * them referenced a single array).
+     */
+    public void setNoCompressionUserAgents(Pattern[] noCompressionUserAgents) {
+        this.noCompressionUserAgents = noCompressionUserAgents;
+    }
+
+
+    /**
+     * Set no compression user agent list.
+     * List contains users agents separated by ',' :
+     *
+     * ie: "gorilla,desesplorer,tigrus"
+     */
+    public void setNoCompressionUserAgents(String noCompressionUserAgents) {
+        if (noCompressionUserAgents != null) {
+            StringTokenizer st = new StringTokenizer(noCompressionUserAgents, ",");
+
+            while (st.hasMoreTokens()) {
+                addNoCompressionUserAgent(st.nextToken().trim());
+            }
+        }
+    }
+
+    /**
+     * Add a mime-type which will be compressable
+     * The mime-type String will be exactly matched
+     * in the response mime-type header .
+     *
+     * @param mimeType mime-type string
+     */
+    public void addCompressableMimeType(String mimeType) {
+        compressableMimeTypes =
+            addStringArray(compressableMimeTypes, mimeType);
+    }
+
+
+    /**
+     * Set compressable mime-type list (this method is best when used with
+     * a large number of connectors, where it would be better to have all of
+     * them referenced a single array).
+     */
+    public void setCompressableMimeTypes(String[] compressableMimeTypes) {
+        this.compressableMimeTypes = compressableMimeTypes;
+    }
+
+
+    /**
+     * Set compressable mime-type list
+     * List contains users agents separated by ',' :
+     *
+     * ie: "text/html,text/xml,text/plain"
+     */
+    public void setCompressableMimeTypes(String compressableMimeTypes) {
+        if (compressableMimeTypes != null) {
+            StringTokenizer st = new StringTokenizer(compressableMimeTypes, ",");
+
+            while (st.hasMoreTokens()) {
+                addCompressableMimeType(st.nextToken().trim());
+            }
+        }
+    }
+
+
+    /**
+     * Return the list of restricted user agents.
+     */
+    public String[] findCompressableMimeTypes() {
+        return (compressableMimeTypes);
+    }
+
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Add input or output filter.
+     *
+     * @param className class name of the filter
+     */
+    protected void addFilter(String className) {
+        try {
+            Class clazz = Class.forName(className);
+            Object obj = clazz.newInstance();
+            if (obj instanceof InputFilter) {
+                inputBuffer.addFilter((InputFilter) obj);
+            } else if (obj instanceof OutputFilter) {
+                outputBuffer.addFilter((OutputFilter) obj);
+            } else {
+                log.warn(sm.getString("http11processor.filter.unknown", className));
+            }
+        } catch (Exception e) {
+            log.error(sm.getString("http11processor.filter.error", className), e);
+        }
+    }
+
+
+    /**
+     * General use method
+     *
+     * @param sArray the StringArray
+     * @param value string
+     */
+    private String[] addStringArray(String sArray[], String value) {
+        String[] result = null;
+        if (sArray == null) {
+            result = new String[1];
+            result[0] = value;
+        }
+        else {
+            result = new String[sArray.length + 1];
+            for (int i = 0; i < sArray.length; i++)
+                result[i] = sArray[i];
+            result[sArray.length] = value;
+        }
+        return result;
+    }
+
+
+    /**
+     * General use method
+     *
+     * @param rArray the REArray
+     * @param value Obj
+     */
+    private Pattern[] addREArray(Pattern rArray[], Pattern value) {
+        Pattern[] result = null;
+        if (rArray == null) {
+            result = new Pattern[1];
+            result[0] = value;
+        }
+        else {
+            result = new Pattern[rArray.length + 1];
+            for (int i = 0; i < rArray.length; i++)
+                result[i] = rArray[i];
+            result[rArray.length] = value;
+        }
+        return result;
+    }
+
+
+    /**
+     * General use method
+     *
+     * @param sArray the StringArray
+     * @param value string
+     */
+    private boolean inStringArray(String sArray[], String value) {
+        for (int i = 0; i < sArray.length; i++) {
+            if (sArray[i].equals(value)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+
+    /**
+     * Checks if any entry in the string array starts with the specified value
+     *
+     * @param sArray the StringArray
+     * @param value string
+     */
+    private boolean startsWithStringArray(String sArray[], String value) {
+        if (value == null)
+           return false;
+        for (int i = 0; i < sArray.length; i++) {
+            if (value.startsWith(sArray[i])) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+
+    /**
+     * Add restricted user-agent (which will downgrade the connector
+     * to HTTP/1.0 mode). The user agent String given will be matched
+     * via regexp to the user-agent header submitted by the client.
+     *
+     * @param userAgent user-agent string
+     */
+    public void addRestrictedUserAgent(String userAgent) {
+        try {
+            Pattern nRule = Pattern.compile(userAgent);
+            restrictedUserAgents = addREArray(restrictedUserAgents, nRule);
+        } catch (PatternSyntaxException pse) {
+            log.error(sm.getString("http11processor.regexp.error", userAgent), pse);
+        }
+    }
+
+
+    /**
+     * Set restricted user agent list (this method is best when used with
+     * a large number of connectors, where it would be better to have all of
+     * them referenced a single array).
+     */
+    public void setRestrictedUserAgents(Pattern[] restrictedUserAgents) {
+        this.restrictedUserAgents = restrictedUserAgents;
+    }
+
+
+    /**
+     * Set restricted user agent list (which will downgrade the connector
+     * to HTTP/1.0 mode). List contains users agents separated by ',' :
+     *
+     * ie: "gorilla,desesplorer,tigrus"
+     */
+    public void setRestrictedUserAgents(String restrictedUserAgents) {
+        if (restrictedUserAgents != null) {
+            StringTokenizer st =
+                new StringTokenizer(restrictedUserAgents, ",");
+            while (st.hasMoreTokens()) {
+                addRestrictedUserAgent(st.nextToken().trim());
+            }
+        }
+    }
+
+
+    /**
+     * Return the list of restricted user agents.
+     */
+    public String[] findRestrictedUserAgents() {
+        String[] sarr = new String [restrictedUserAgents.length];
+
+        for (int i = 0; i < restrictedUserAgents.length; i++)
+            sarr[i] = restrictedUserAgents[i].toString();
+
+        return (sarr);
+    }
+
+
+    /**
+     * Set the maximum number of Keep-Alive requests to honor.
+     * This is to safeguard from DoS attacks.  Setting to a negative
+     * value disables the check.
+     */
+    public void setMaxKeepAliveRequests(int mkar) {
+        maxKeepAliveRequests = mkar;
+    }
+
+
+    /**
+     * Return the number of Keep-Alive requests that we will honor.
+     */
+    public int getMaxKeepAliveRequests() {
+        return maxKeepAliveRequests;
+    }
+
+
+    /**
+     * Set the maximum size of a POST which will be buffered in SSL mode.
+     */
+    public void setMaxSavePostSize(int msps) {
+        maxSavePostSize = msps;
+    }
+
+
+    /**
+     * Return the maximum size of a POST which will be buffered in SSL mode.
+     */
+    public int getMaxSavePostSize() {
+        return maxSavePostSize;
+    }
+
+
+    /**
+     * Set the flag to control upload time-outs.
+     */
+    public void setDisableUploadTimeout(boolean isDisabled) {
+        disableUploadTimeout = isDisabled;
+    }
+
+    /**
+     * Get the flag that controls upload time-outs.
+     */
+    public boolean getDisableUploadTimeout() {
+        return disableUploadTimeout;
+    }
+
+    /**
+     * Set the socket buffer flag.
+     */
+    public void setSocketBuffer(int socketBuffer) {
+        this.socketBuffer = socketBuffer;
+        outputBuffer.setSocketBuffer(socketBuffer);
+    }
+
+    /**
+     * Get the socket buffer flag.
+     */
+    public int getSocketBuffer() {
+        return socketBuffer;
+    }
+
+    /**
+     * Set the upload timeout.
+     */
+    public void setTimeout( int timeouts ) {
+        timeout = timeouts ;
+    }
+
+    /**
+     * Get the upload timeout.
+     */
+    public int getTimeout() {
+        return timeout;
+    }
+
+
+    /**
+     * Set the server header name.
+     */
+    public void setServer( String server ) {
+        if (server==null || server.equals("")) {
+            this.server = null;
+        } else {
+            this.server = server;
+        }
+    }
+
+    /**
+     * Get the server header name.
+     */
+    public String getServer() {
+        return server;
+    }
+
+
+    /** Get the request associated with this processor.
+     *
+     * @return The request
+     */
+    public Request getRequest() {
+        return request;
+    }
+
+    /**
+     * Process pipelined HTTP requests using the specified input and output
+     * streams.
+     *
+     * @throws IOException error during an I/O operation
+     */
+    public boolean process(long socket)
+        throws IOException {
+        ThreadWithAttributes thrA=
+                (ThreadWithAttributes)Thread.currentThread();
+        RequestInfo rp = request.getRequestProcessor();
+        thrA.setCurrentStage(endpoint, "parsing http request");
+        rp.setStage(org.apache.coyote.Constants.STAGE_PARSE);
+
+        // Set the remote address
+        remoteAddr = null;
+        remoteHost = null;
+        localAddr = null;
+        localName = null;
+        remotePort = -1;
+        localPort = -1;
+
+        // Setting up the socket
+        this.socket = socket;
+        inputBuffer.setSocket(socket);
+        outputBuffer.setSocket(socket);
+
+        // Error flag
+        error = false;
+        keepAlive = true;
+
+        int keepAliveLeft = maxKeepAliveRequests;
+        long soTimeout = endpoint.getSoTimeout();
+        
+        int limit = 0;
+        if (endpoint.getFirstReadTimeout() > 0 || endpoint.getFirstReadTimeout() < -1) {
+            limit = endpoint.getMaxThreads() / 2;
+        }
+
+        boolean keptAlive = false;
+        boolean openSocket = false;
+
+        while (started && !error && keepAlive) {
+
+            // Parsing the request header
+            try {
+                if( !disableUploadTimeout && keptAlive && soTimeout > 0 ) {
+                    Socket.timeoutSet(socket, soTimeout * 1000);
+                }
+                if (!inputBuffer.parseRequestLine
+                        (keptAlive && (endpoint.getCurrentThreadsBusy() > limit))) {
+                    // This means that no data is available right now
+                    // (long keepalive), so that the processor should be recycled
+                    // and the method should return true
+                    openSocket = true;
+                    // Add the socket to the poller
+                    endpoint.getPoller().add(socket);
+                    break;
+                }
+                request.setStartTime(System.currentTimeMillis());
+                thrA.setParam(endpoint, request.requestURI());
+                keptAlive = true;
+                if (!disableUploadTimeout) {
+                    Socket.timeoutSet(socket, timeout * 1000);
+                }
+                inputBuffer.parseHeaders();
+            } catch (IOException e) {
+                error = true;
+                break;
+            } catch (Throwable t) {
+                if (log.isDebugEnabled()) {
+                    log.debug(sm.getString("http11processor.header.parse"), t);
+                }
+                // 400 - Bad Request
+                response.setStatus(400);
+                error = true;
+            }
+
+            // Setting up filters, and parse some request headers
+            thrA.setCurrentStage(endpoint, "prepareRequest");
+            rp.setStage(org.apache.coyote.Constants.STAGE_PREPARE);
+            try {
+                prepareRequest();
+            } catch (Throwable t) {
+                if (log.isDebugEnabled()) {
+                    log.debug(sm.getString("http11processor.request.prepare"), t);
+                }
+                // 400 - Internal Server Error
+                response.setStatus(400);
+                error = true;
+            }
+
+            if (maxKeepAliveRequests > 0 && --keepAliveLeft == 0)
+                keepAlive = false;
+
+            // Process the request in the adapter
+            if (!error) {
+                try {
+                    thrA.setCurrentStage(endpoint, "service");
+                    rp.setStage(org.apache.coyote.Constants.STAGE_SERVICE);
+                    adapter.service(request, response);
+                    // Handle when the response was committed before a serious
+                    // error occurred.  Throwing a ServletException should both
+                    // set the status to 500 and set the errorException.
+                    // If we fail here, then the response is likely already
+                    // committed, so we can't try and set headers.
+                    if(keepAlive && !error) { // Avoid checking twice.
+                        error = response.getErrorException() != null ||
+                                statusDropsConnection(response.getStatus());
+                    }
+
+                } catch (InterruptedIOException e) {
+                    error = true;
+                } catch (Throwable t) {
+                    log.error(sm.getString("http11processor.request.process"), t);
+                    // 500 - Internal Server Error
+                    response.setStatus(500);
+                    error = true;
+                }
+            }
+
+            // Finish the handling of the request
+            try {
+                thrA.setCurrentStage(endpoint, "endRequestIB");
+                rp.setStage(org.apache.coyote.Constants.STAGE_ENDINPUT);
+                inputBuffer.endRequest();
+            } catch (IOException e) {
+                error = true;
+            } catch (Throwable t) {
+                log.error(sm.getString("http11processor.request.finish"), t);
+                // 500 - Internal Server Error
+                response.setStatus(500);
+                error = true;
+            }
+            try {
+                thrA.setCurrentStage(endpoint, "endRequestOB");
+                rp.setStage(org.apache.coyote.Constants.STAGE_ENDOUTPUT);
+                outputBuffer.endRequest();
+            } catch (IOException e) {
+                error = true;
+            } catch (Throwable t) {
+                log.error(sm.getString("http11processor.response.finish"), t);
+                error = true;
+            }
+
+            // If there was an error, make sure the request is counted as
+            // and error, and update the statistics counter
+            if (error) {
+                response.setStatus(500);
+            }
+            request.updateCounters();
+
+            thrA.setCurrentStage(endpoint, "ended");
+            rp.setStage(org.apache.coyote.Constants.STAGE_KEEPALIVE);
+
+            // Don't reset the param - we'll see it as ended. Next request
+            // will reset it
+            // thrA.setParam(null);
+            // Next request
+            inputBuffer.nextRequest();
+            outputBuffer.nextRequest();
+
+            // Do sendfile as needed: add socket to sendfile and end
+            if (sendfileData != null) {
+                sendfileData.socket = socket;
+                sendfileData.keepAlive = keepAlive;
+                if (!endpoint.getSendfile().add(sendfileData)) {
+                    openSocket = true;
+                    break;
+                }
+            }
+            
+        }
+
+        rp.setStage(org.apache.coyote.Constants.STAGE_ENDED);
+
+        // Recycle
+        inputBuffer.recycle();
+        outputBuffer.recycle();
+        this.socket = 0;
+
+        return openSocket;
+        
+    }
+
+
+    // ----------------------------------------------------- ActionHook Methods
+
+
+    /**
+     * Send an action to the connector.
+     *
+     * @param actionCode Type of the action
+     * @param param Action parameter
+     */
+    public void action(ActionCode actionCode, Object param) {
+
+        if (actionCode == ActionCode.ACTION_COMMIT) {
+            // Commit current response
+
+            if (response.isCommitted())
+                return;
+
+            // Validate and write response headers
+            prepareResponse();
+            try {
+                outputBuffer.commit();
+            } catch (IOException e) {
+                // Set error flag
+                error = true;
+            }
+
+        } else if (actionCode == ActionCode.ACTION_ACK) {
+
+            // Acknowlege request
+
+            // Send a 100 status back if it makes sense (response not committed
+            // yet, and client specified an expectation for 100-continue)
+
+            if ((response.isCommitted()) || !expectation)
+                return;
+
+            inputBuffer.setSwallowInput(true);
+            try {
+                outputBuffer.sendAck();
+            } catch (IOException e) {
+                // Set error flag
+                error = true;
+            }
+
+        } else if (actionCode == ActionCode.ACTION_CLIENT_FLUSH) {
+
+            try {
+                outputBuffer.flush();
+            } catch (IOException e) {
+                // Set error flag
+                error = true;
+                response.setErrorException(e);
+            }
+
+        } else if (actionCode == ActionCode.ACTION_CLOSE) {
+            // Close
+
+            // End the processing of the current request, and stop any further
+            // transactions with the client
+
+            try {
+                outputBuffer.endRequest();
+            } catch (IOException e) {
+                // Set error flag
+                error = true;
+            }
+
+        } else if (actionCode == ActionCode.ACTION_RESET) {
+
+            // Reset response
+
+            // Note: This must be called before the response is committed
+
+            outputBuffer.reset();
+
+        } else if (actionCode == ActionCode.ACTION_CUSTOM) {
+
+            // Do nothing
+
+        } else if (actionCode == ActionCode.ACTION_START) {
+
+            started = true;
+
+        } else if (actionCode == ActionCode.ACTION_STOP) {
+
+            started = false;
+
+        } else if (actionCode == ActionCode.ACTION_REQ_HOST_ADDR_ATTRIBUTE) {
+
+            // Get remote host address
+            if (remoteAddr == null && (socket != 0)) {
+                try {
+                    long sa = Address.get(Socket.APR_REMOTE, socket);
+                    remoteAddr = Address.getip(sa);
+                } catch (Exception e) {
+                    log.warn(sm.getString("http11processor.socket.info"), e);
+                }
+            }
+            request.remoteAddr().setString(remoteAddr);
+
+        } else if (actionCode == ActionCode.ACTION_REQ_LOCAL_NAME_ATTRIBUTE) {
+
+            // Get local host name
+            if (localName == null && (socket != 0)) {
+                try {
+                    long sa = Address.get(Socket.APR_LOCAL, socket);
+                    localName = Address.getnameinfo(sa, 0);
+                } catch (Exception e) {
+                    log.warn(sm.getString("http11processor.socket.info"), e);
+                }
+            }
+            request.localName().setString(localName);
+
+        } else if (actionCode == ActionCode.ACTION_REQ_HOST_ATTRIBUTE) {
+
+            // Get remote host name
+            if (remoteHost == null && (socket != 0)) {
+                try {
+                    long sa = Address.get(Socket.APR_REMOTE, socket);
+                    remoteHost = Address.getnameinfo(sa, 0);
+                } catch (Exception e) {
+                    log.warn(sm.getString("http11processor.socket.info"), e);
+                }
+            }
+            request.remoteHost().setString(remoteHost);
+
+        } else if (actionCode == ActionCode.ACTION_REQ_LOCAL_ADDR_ATTRIBUTE) {
+
+            // Get local host address
+            if (localAddr == null && (socket != 0)) {
+                try {
+                    long sa = Address.get(Socket.APR_LOCAL, socket);
+                    localAddr = Address.getip(sa);
+                } catch (Exception e) {
+                    log.warn(sm.getString("http11processor.socket.info"), e);
+                }
+            }
+
+            request.localAddr().setString(localAddr);
+
+        } else if (actionCode == ActionCode.ACTION_REQ_REMOTEPORT_ATTRIBUTE) {
+
+            // Get remote port
+            if (remotePort == -1 && (socket != 0)) {
+                try {
+                    long sa = Address.get(Socket.APR_REMOTE, socket);
+                    Sockaddr addr = Address.getInfo(sa);
+                    remotePort = addr.port;
+                } catch (Exception e) {
+                    log.warn(sm.getString("http11processor.socket.info"), e);
+                }
+            }
+            request.setRemotePort(remotePort);
+
+        } else if (actionCode == ActionCode.ACTION_REQ_LOCALPORT_ATTRIBUTE) {
+
+            // Get local port
+            if (localPort == -1 && (socket != 0)) {
+                try {
+                    long sa = Address.get(Socket.APR_LOCAL, socket);
+                    Sockaddr addr = Address.getInfo(sa);
+                    localPort = addr.port;
+                } catch (Exception e) {
+                    log.warn(sm.getString("http11processor.socket.info"), e);
+                }
+            }
+            request.setLocalPort(localPort);
+
+        } else if (actionCode == ActionCode.ACTION_REQ_SSL_ATTRIBUTE ) {
+
+            if (ssl && (socket != 0)) {
+                try {
+                    // Cipher suite
+                    Object sslO = SSLSocket.getInfoS(socket, SSL.SSL_INFO_CIPHER);
+                    if (sslO != null) {
+                        request.setAttribute
+                            (AprEndpoint.CIPHER_SUITE_KEY, sslO);
+                    }
+                    // Client certificate chain if present
+                    int certLength = SSLSocket.getInfoI(socket, SSL.SSL_INFO_CLIENT_CERT_CHAIN);
+                    X509Certificate[] certs = null;
+                    if (certLength > 0) {
+                        certs = new X509Certificate[certLength];
+                        for (int i = 0; i < certLength; i++) {
+                            byte[] data = SSLSocket.getInfoB(socket, SSL.SSL_INFO_CLIENT_CERT_CHAIN + i);
+                            CertificateFactory cf =
+                                CertificateFactory.getInstance("X.509");
+                            ByteArrayInputStream stream = new ByteArrayInputStream(data);
+                            certs[i] = (X509Certificate) cf.generateCertificate(stream);
+                        }
+                    }
+                    if (certs != null) {
+                        request.setAttribute
+                            (AprEndpoint.CERTIFICATE_KEY, certs);
+                    }
+                    // User key size
+                    sslO = new Integer(SSLSocket.getInfoI(socket, SSL.SSL_INFO_CIPHER_USEKEYSIZE));
+                    if (sslO != null) {
+                        request.setAttribute
+                            (AprEndpoint.KEY_SIZE_KEY, sslO);
+                    }
+                    // SSL session ID
+                    sslO = SSLSocket.getInfoS(socket, SSL.SSL_INFO_SESSION_ID);
+                    if (sslO != null) {
+                        request.setAttribute
+                            (AprEndpoint.SESSION_ID_KEY, sslO);
+                    }
+                } catch (Exception e) {
+                    log.warn(sm.getString("http11processor.socket.ssl"), e);
+                }
+            }
+
+        } else if (actionCode == ActionCode.ACTION_REQ_SSL_CERTIFICATE) {
+
+            if (ssl && (socket != 0)) {
+                 // Consume and buffer the request body, so that it does not
+                 // interfere with the client's handshake messages
+                InputFilter[] inputFilters = inputBuffer.getFilters();
+                ((BufferedInputFilter) inputFilters[Constants.BUFFERED_FILTER])
+                    .setLimit(maxSavePostSize);
+                inputBuffer.addActiveFilter
+                    (inputFilters[Constants.BUFFERED_FILTER]);
+                try {
+                    // Renegociate certificates
+                    SSLSocket.renegotiate(socket);
+                    // Client certificate chain if present
+                    int certLength = SSLSocket.getInfoI(socket, SSL.SSL_INFO_CLIENT_CERT_CHAIN);
+                    X509Certificate[] certs = null;
+                    if (certLength > 0) {
+                        certs = new X509Certificate[certLength];
+                        for (int i = 0; i < certLength; i++) {
+                            byte[] data = SSLSocket.getInfoB(socket, SSL.SSL_INFO_CLIENT_CERT_CHAIN + i);
+                            CertificateFactory cf =
+                                CertificateFactory.getInstance("X.509");
+                            ByteArrayInputStream stream = new ByteArrayInputStream(data);
+                            certs[i] = (X509Certificate) cf.generateCertificate(stream);
+                        }
+                    }
+                    if (certs != null) {
+                        request.setAttribute
+                            (AprEndpoint.CERTIFICATE_KEY, certs);
+                    }
+                } catch (Exception e) {
+                    log.warn(sm.getString("http11processor.socket.ssl"), e);
+                }
+            }
+
+        } else if (actionCode == ActionCode.ACTION_REQ_SET_BODY_REPLAY) {
+            ByteChunk body = (ByteChunk) param;
+            
+            InputFilter savedBody = new SavedRequestInputFilter(body);
+            savedBody.setRequest(request);
+            
+            InternalAprInputBuffer internalBuffer = (InternalAprInputBuffer)
+                request.getInputBuffer();
+            internalBuffer.addActiveFilter(savedBody);
+        }
+
+    }
+
+
+    // ------------------------------------------------------ Connector Methods
+
+
+    /**
+     * Set the associated adapter.
+     *
+     * @param adapter the new adapter
+     */
+    public void setAdapter(Adapter adapter) {
+        this.adapter = adapter;
+    }
+
+
+    /**
+     * Get the associated adapter.
+     *
+     * @return the associated adapter
+     */
+    public Adapter getAdapter() {
+        return adapter;
+    }
+
+
+    // ------------------------------------------------------ Protected Methods
+
+
+    /**
+     * After reading the request headers, we have to setup the request filters.
+     */
+    protected void prepareRequest() {
+
+        http11 = true;
+        http09 = false;
+        contentDelimitation = false;
+        expectation = false;
+        sendfileData = null;
+        if (ssl) {
+            request.scheme().setString("https");
+        }
+        MessageBytes protocolMB = request.protocol();
+        if (protocolMB.equals(Constants.HTTP_11)) {
+            http11 = true;
+            protocolMB.setString(Constants.HTTP_11);
+        } else if (protocolMB.equals(Constants.HTTP_10)) {
+            http11 = false;
+            keepAlive = false;
+            protocolMB.setString(Constants.HTTP_10);
+        } else if (protocolMB.equals("")) {
+            // HTTP/0.9
+            http09 = true;
+            http11 = false;
+            keepAlive = false;
+        } else {
+            // Unsupported protocol
+            http11 = false;
+            error = true;
+            // Send 505; Unsupported HTTP version
+            response.setStatus(505);
+        }
+
+        MessageBytes methodMB = request.method();
+        if (methodMB.equals(Constants.GET)) {
+            methodMB.setString(Constants.GET);
+        } else if (methodMB.equals(Constants.POST)) {
+            methodMB.setString(Constants.POST);
+        }
+
+        MimeHeaders headers = request.getMimeHeaders();
+
+        // Check connection header
+        MessageBytes connectionValueMB = headers.getValue("connection");
+        if (connectionValueMB != null) {
+            ByteChunk connectionValueBC = connectionValueMB.getByteChunk();
+            if (findBytes(connectionValueBC, Constants.CLOSE_BYTES) != -1) {
+                keepAlive = false;
+            } else if (findBytes(connectionValueBC,
+                                 Constants.KEEPALIVE_BYTES) != -1) {
+                keepAlive = true;
+            }
+        }
+
+        MessageBytes expectMB = null;
+        if (http11)
+            expectMB = headers.getValue("expect");
+        if ((expectMB != null)
+            && (expectMB.indexOfIgnoreCase("100-continue", 0) != -1)) {
+            inputBuffer.setSwallowInput(false);
+            expectation = true;
+        }
+
+        // Check user-agent header
+        if ((restrictedUserAgents != null) && ((http11) || (keepAlive))) {
+            MessageBytes userAgentValueMB = headers.getValue("user-agent");
+            // Check in the restricted list, and adjust the http11
+            // and keepAlive flags accordingly
+            if(userAgentValueMB != null) {
+                String userAgentValue = userAgentValueMB.toString();
+                for (int i = 0; i < restrictedUserAgents.length; i++) {
+                    if (restrictedUserAgents[i].matcher(userAgentValue).matches()) {
+                        http11 = false;
+                        keepAlive = false;
+                        break;
+                    }
+                }
+            }
+        }
+
+        // Check for a full URI (including protocol://host:port/)
+        ByteChunk uriBC = request.requestURI().getByteChunk();
+        if (uriBC.startsWithIgnoreCase("http", 0)) {
+
+            int pos = uriBC.indexOf("://", 0, 3, 4);
+            int uriBCStart = uriBC.getStart();
+            int slashPos = -1;
+            if (pos != -1) {
+                byte[] uriB = uriBC.getBytes();
+                slashPos = uriBC.indexOf('/', pos + 3);
+                if (slashPos == -1) {
+                    slashPos = uriBC.getLength();
+                    // Set URI as "/"
+                    request.requestURI().setBytes
+                        (uriB, uriBCStart + pos + 1, 1);
+                } else {
+                    request.requestURI().setBytes
+                        (uriB, uriBCStart + slashPos,
+                         uriBC.getLength() - slashPos);
+                }
+                MessageBytes hostMB = headers.setValue("host");
+                hostMB.setBytes(uriB, uriBCStart + pos + 3,
+                                slashPos - pos - 3);
+            }
+
+        }
+
+        // Input filter setup
+        InputFilter[] inputFilters = inputBuffer.getFilters();
+
+        // Parse transfer-encoding header
+        MessageBytes transferEncodingValueMB = null;
+        if (http11)
+            transferEncodingValueMB = headers.getValue("transfer-encoding");
+        if (transferEncodingValueMB != null) {
+            String transferEncodingValue = transferEncodingValueMB.toString();
+            // Parse the comma separated list. "identity" codings are ignored
+            int startPos = 0;
+            int commaPos = transferEncodingValue.indexOf(',');
+            String encodingName = null;
+            while (commaPos != -1) {
+                encodingName = transferEncodingValue.substring
+                    (startPos, commaPos).toLowerCase().trim();
+                if (!addInputFilter(inputFilters, encodingName)) {
+                    // Unsupported transfer encoding
+                    error = true;
+                    // 501 - Unimplemented
+                    response.setStatus(501);
+                }
+                startPos = commaPos + 1;
+                commaPos = transferEncodingValue.indexOf(',', startPos);
+            }
+            encodingName = transferEncodingValue.substring(startPos)
+                .toLowerCase().trim();
+            if (!addInputFilter(inputFilters, encodingName)) {
+                // Unsupported transfer encoding
+                error = true;
+                // 501 - Unimplemented
+                response.setStatus(501);
+            }
+        }
+
+        // Parse content-length header
+        long contentLength = request.getContentLengthLong();
+        if (contentLength >= 0 && !contentDelimitation) {
+            inputBuffer.addActiveFilter
+                (inputFilters[Constants.IDENTITY_FILTER]);
+            contentDelimitation = true;
+        }
+
+        MessageBytes valueMB = headers.getValue("host");
+
+        // Check host header
+        if (http11 && (valueMB == null)) {
+            error = true;
+            // 400 - Bad request
+            response.setStatus(400);
+        }
+
+        parseHost(valueMB);
+
+        if (!contentDelimitation) {
+            // If there's no content length 
+            // (broken HTTP/1.0 or HTTP/1.1), assume
+            // the client is not broken and didn't send a body
+            inputBuffer.addActiveFilter
+                    (inputFilters[Constants.VOID_FILTER]);
+            contentDelimitation = true;
+        }
+
+        // Advertise sendfile support through a request attribute
+        if (endpoint.getUseSendfile()) {
+            request.setAttribute("org.apache.tomcat.sendfile.support", Boolean.TRUE);
+        }
+        
+    }
+
+
+    /**
+     * Parse host.
+     */
+    public void parseHost(MessageBytes valueMB) {
+
+        if (valueMB == null || valueMB.isNull()) {
+            // HTTP/1.0
+            // Default is what the socket tells us. Overriden if a host is
+            // found/parsed
+            request.setServerPort(endpoint.getPort());
+            return;
+        }
+
+        ByteChunk valueBC = valueMB.getByteChunk();
+        byte[] valueB = valueBC.getBytes();
+        int valueL = valueBC.getLength();
+        int valueS = valueBC.getStart();
+        int colonPos = -1;
+        if (hostNameC.length < valueL) {
+            hostNameC = new char[valueL];
+        }
+
+        boolean ipv6 = (valueB[valueS] == '[');
+        boolean bracketClosed = false;
+        for (int i = 0; i < valueL; i++) {
+            char b = (char) valueB[i + valueS];
+            hostNameC[i] = b;
+            if (b == ']') {
+                bracketClosed = true;
+            } else if (b == ':') {
+                if (!ipv6 || bracketClosed) {
+                    colonPos = i;
+                    break;
+                }
+            }
+        }
+
+        if (colonPos < 0) {
+            if (!ssl) {
+                // 80 - Default HTTP port
+                request.setServerPort(80);
+            } else {
+                // 443 - Default HTTPS port
+                request.setServerPort(443);
+            }
+            request.serverName().setChars(hostNameC, 0, valueL);
+        } else {
+
+            request.serverName().setChars(hostNameC, 0, colonPos);
+
+            int port = 0;
+            int mult = 1;
+            for (int i = valueL - 1; i > colonPos; i--) {
+                int charValue = HexUtils.DEC[(int) valueB[i + valueS]];
+                if (charValue == -1) {
+                    // Invalid character
+                    error = true;
+                    // 400 - Bad request
+                    response.setStatus(400);
+                    break;
+                }
+                port = port + (charValue * mult);
+                mult = 10 * mult;
+            }
+            request.setServerPort(port);
+
+        }
+
+    }
+
+
+    /**
+     * Check for compression
+     */
+    private boolean isCompressable() {
+
+        // Nope Compression could works in HTTP 1.0 also
+        // cf: mod_deflate
+
+        // Compression only since HTTP 1.1
+        // if (! http11)
+        //    return false;
+
+        // Check if browser support gzip encoding
+        MessageBytes acceptEncodingMB =
+            request.getMimeHeaders().getValue("accept-encoding");
+
+        if ((acceptEncodingMB == null)
+            || (acceptEncodingMB.indexOf("gzip") == -1))
+            return false;
+
+        // Check if content is not allready gzipped
+        MessageBytes contentEncodingMB =
+            response.getMimeHeaders().getValue("Content-Encoding");
+
+        if ((contentEncodingMB != null)
+            && (contentEncodingMB.indexOf("gzip") != -1))
+            return false;
+
+        // If force mode, allways compress (test purposes only)
+        if (compressionLevel == 2)
+           return true;
+
+        // Check for incompatible Browser
+        if (noCompressionUserAgents != null) {
+            MessageBytes userAgentValueMB =
+                request.getMimeHeaders().getValue("user-agent");
+            if(userAgentValueMB != null) {
+                String userAgentValue = userAgentValueMB.toString();
+
+                // If one Regexp rule match, disable compression
+                for (int i = 0; i < noCompressionUserAgents.length; i++)
+                    if (noCompressionUserAgents[i].matcher(userAgentValue).matches())
+                        return false;
+            }
+        }
+
+        // Check if suffisant len to trig the compression
+        long contentLength = response.getContentLengthLong();
+        if ((contentLength == -1)
+            || (contentLength > compressionMinSize)) {
+            // Check for compatible MIME-TYPE
+            if (compressableMimeTypes != null) {
+                return (startsWithStringArray(compressableMimeTypes,
+                                              response.getContentType()));
+            }
+        }
+
+        return false;
+    }
+
+
+    /**
+     * When committing the response, we have to validate the set of headers, as
+     * well as setup the response filters.
+     */
+    protected void prepareResponse() {
+
+        boolean entityBody = true;
+        contentDelimitation = false;
+
+        OutputFilter[] outputFilters = outputBuffer.getFilters();
+
+        if (http09 == true) {
+            // HTTP/0.9
+            outputBuffer.addActiveFilter
+                (outputFilters[Constants.IDENTITY_FILTER]);
+            return;
+        }
+
+        int statusCode = response.getStatus();
+        if ((statusCode == 204) || (statusCode == 205)
+            || (statusCode == 304)) {
+            // No entity body
+            outputBuffer.addActiveFilter
+                (outputFilters[Constants.VOID_FILTER]);
+            entityBody = false;
+            contentDelimitation = true;
+        }
+
+        MessageBytes methodMB = request.method();
+        if (methodMB.equals("HEAD")) {
+            // No entity body
+            outputBuffer.addActiveFilter
+                (outputFilters[Constants.VOID_FILTER]);
+            contentDelimitation = true;
+        }
+
+        // Sendfile support
+        if (endpoint.getUseSendfile()) {
+            String fileName = (String) request.getAttribute("org.apache.tomcat.sendfile.filename");
+            if (fileName != null) {
+                // No entity body sent here
+                outputBuffer.addActiveFilter
+                    (outputFilters[Constants.VOID_FILTER]);
+                contentDelimitation = true;
+                sendfileData = new AprEndpoint.SendfileData();
+                sendfileData.fileName = fileName;
+                sendfileData.start = 
+                    ((Long) request.getAttribute("org.apache.tomcat.sendfile.start")).longValue();
+                sendfileData.end = 
+                    ((Long) request.getAttribute("org.apache.tomcat.sendfile.end")).longValue();
+            }
+        }
+        
+        // Check for compression
+        boolean useCompression = false;
+        if (entityBody && (compressionLevel > 0) && (sendfileData == null)) {
+            useCompression = isCompressable();
+            // Change content-length to -1 to force chunking
+            if (useCompression) {
+                response.setContentLength(-1);
+            }
+        }
+
+        MimeHeaders headers = response.getMimeHeaders();
+        if (!entityBody) {
+            response.setContentLength(-1);
+        } else {
+            String contentType = response.getContentType();
+            if (contentType != null) {
+                headers.setValue("Content-Type").setString(contentType);
+            }
+            String contentLanguage = response.getContentLanguage();
+            if (contentLanguage != null) {
+                headers.setValue("Content-Language")
+                    .setString(contentLanguage);
+            }
+        }
+
+        long contentLength = response.getContentLengthLong();
+        if (contentLength != -1) {
+            headers.setValue("Content-Length").setLong(contentLength);
+            outputBuffer.addActiveFilter
+                (outputFilters[Constants.IDENTITY_FILTER]);
+            contentDelimitation = true;
+        } else {
+            if (entityBody && http11 && keepAlive) {
+                outputBuffer.addActiveFilter
+                    (outputFilters[Constants.CHUNKED_FILTER]);
+                contentDelimitation = true;
+                headers.addValue(Constants.TRANSFERENCODING).setString(Constants.CHUNKED);
+            } else {
+                outputBuffer.addActiveFilter
+                    (outputFilters[Constants.IDENTITY_FILTER]);
+            }
+        }
+
+        if (useCompression) {
+            outputBuffer.addActiveFilter(outputFilters[Constants.GZIP_FILTER]);
+            headers.setValue("Content-Encoding").setString("gzip");
+            // Make Proxies happy via Vary (from mod_deflate)
+            headers.setValue("Vary").setString("Accept-Encoding");
+        }
+
+        // Add date header
+        headers.setValue("Date").setString(FastHttpDateFormat.getCurrentDate());
+
+        // FIXME: Add transfer encoding header
+
+        if ((entityBody) && (!contentDelimitation)) {
+            // Mark as close the connection after the request, and add the
+            // connection: close header
+            keepAlive = false;
+        }
+
+        // If we know that the request is bad this early, add the
+        // Connection: close header.
+        keepAlive = keepAlive && !statusDropsConnection(statusCode);
+        if (!keepAlive) {
+            headers.addValue(Constants.CONNECTION).setString(Constants.CLOSE);
+        } else if (!http11 && !error) {
+            headers.addValue(Constants.CONNECTION).setString(Constants.KEEPALIVE);
+        }
+
+        // Build the response header
+        outputBuffer.sendStatus();
+
+        // Add server header
+        if (server != null) {
+            headers.setValue("Server").setString(server);
+        } else {
+            outputBuffer.write(Constants.SERVER_BYTES);
+        }
+
+        int size = headers.size();
+        for (int i = 0; i < size; i++) {
+            outputBuffer.sendHeader(headers.getName(i), headers.getValue(i));
+        }
+        outputBuffer.endHeaders();
+
+    }
+
+
+    /**
+     * Initialize standard input and output filters.
+     */
+    protected void initializeFilters() {
+
+        // Create and add the identity filters.
+        inputBuffer.addFilter(new IdentityInputFilter());
+        outputBuffer.addFilter(new IdentityOutputFilter());
+
+        // Create and add the chunked filters.
+        inputBuffer.addFilter(new ChunkedInputFilter());
+        outputBuffer.addFilter(new ChunkedOutputFilter());
+
+        // Create and add the void filters.
+        inputBuffer.addFilter(new VoidInputFilter());
+        outputBuffer.addFilter(new VoidOutputFilter());
+
+        // Create and add buffered input filter
+        inputBuffer.addFilter(new BufferedInputFilter());
+
+        // Create and add the chunked filters.
+        //inputBuffer.addFilter(new GzipInputFilter());
+        outputBuffer.addFilter(new GzipOutputFilter());
+
+    }
+
+
+    /**
+     * Add an input filter to the current request.
+     *
+     * @return false if the encoding was not found (which would mean it is
+     * unsupported)
+     */
+    protected boolean addInputFilter(InputFilter[] inputFilters,
+                                     String encodingName) {
+        if (encodingName.equals("identity")) {
+            // Skip
+        } else if (encodingName.equals("chunked")) {
+            inputBuffer.addActiveFilter
+                (inputFilters[Constants.CHUNKED_FILTER]);
+            contentDelimitation = true;
+        } else {
+            for (int i = 2; i < inputFilters.length; i++) {
+                if (inputFilters[i].getEncodingName()
+                    .toString().equals(encodingName)) {
+                    inputBuffer.addActiveFilter(inputFilters[i]);
+                    return true;
+                }
+            }
+            return false;
+        }
+        return true;
+    }
+
+
+    /**
+     * Specialized utility method: find a sequence of lower case bytes inside
+     * a ByteChunk.
+     */
+    protected int findBytes(ByteChunk bc, byte[] b) {
+
+        byte first = b[0];
+        byte[] buff = bc.getBuffer();
+        int start = bc.getStart();
+        int end = bc.getEnd();
+
+    // Look for first char
+    int srcEnd = b.length;
+
+    for (int i = start; i <= (end - srcEnd); i++) {
+        if (Ascii.toLower(buff[i]) != first) continue;
+        // found first char, now look for a match
+            int myPos = i+1;
+        for (int srcPos = 1; srcPos < srcEnd; ) {
+                if (Ascii.toLower(buff[myPos++]) != b[srcPos++])
+            break;
+                if (srcPos == srcEnd) return i - start; // found it
+        }
+    }
+    return -1;
+
+    }
+
+    /**
+     * Determine if we must drop the connection because of the HTTP status
+     * code.  Use the same list of codes as Apache/httpd.
+     */
+    protected boolean statusDropsConnection(int status) {
+        return status == 400 /* SC_BAD_REQUEST */ ||
+               status == 408 /* SC_REQUEST_TIMEOUT */ ||
+               status == 411 /* SC_LENGTH_REQUIRED */ ||
+               status == 413 /* SC_REQUEST_ENTITY_TOO_LARGE */ ||
+               status == 414 /* SC_REQUEST_URI_TOO_LARGE */ ||
+               status == 500 /* SC_INTERNAL_SERVER_ERROR */ ||
+               status == 503 /* SC_SERVICE_UNAVAILABLE */ ||
+               status == 501 /* SC_NOT_IMPLEMENTED */;
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/http11/src/java/org/apache/coyote/http11/Http11AprProtocol.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/http11/src/java/org/apache/coyote/http11/Http11AprProtocol.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/http11/src/java/org/apache/coyote/http11/Http11AprProtocol.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,706 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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;
+
+import java.net.InetAddress;
+import java.net.URLEncoder;
+import java.util.Hashtable;
+import java.util.Iterator;
+
+import javax.management.MBeanRegistration;
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+
+import org.apache.commons.modeler.Registry;
+import org.apache.coyote.ActionCode;
+import org.apache.coyote.ActionHook;
+import org.apache.coyote.Adapter;
+import org.apache.coyote.ProtocolHandler;
+import org.apache.coyote.RequestGroupInfo;
+import org.apache.coyote.RequestInfo;
+import org.apache.tomcat.util.net.AprEndpoint;
+import org.apache.tomcat.util.net.AprEndpoint.Handler;
+import org.apache.tomcat.util.res.StringManager;
+
+
+/**
+ * Abstract the protocol implementation, including threading, etc.
+ * Processor is single threaded and specific to stream-based protocols,
+ * will not fit Jk protocols like JNI.
+ *
+ * @author Remy Maucherat
+ * @author Costin Manolache
+ */
+public class Http11AprProtocol implements ProtocolHandler, MBeanRegistration
+{
+    public Http11AprProtocol() {
+        cHandler = new Http11ConnectionHandler( this );
+        setSoLinger(Constants.DEFAULT_CONNECTION_LINGER);
+        setSoTimeout(Constants.DEFAULT_CONNECTION_TIMEOUT);
+        //setServerSoTimeout(Constants.DEFAULT_SERVER_SOCKET_TIMEOUT);
+        setTcpNoDelay(Constants.DEFAULT_TCP_NO_DELAY);
+    }
+
+    /**
+     * The string manager for this package.
+     */
+    protected static StringManager sm =
+        StringManager.getManager(Constants.Package);
+
+    /** Pass config info
+     */
+    public void setAttribute( String name, Object value ) {
+        if( log.isTraceEnabled())
+            log.trace(sm.getString("http11protocol.setattribute", name, value));
+
+        attributes.put(name, value);
+    }
+
+    public Object getAttribute( String key ) {
+        if( log.isTraceEnabled())
+            log.trace(sm.getString("http11protocol.getattribute", key));
+        return attributes.get(key);
+    }
+
+    public Iterator getAttributeNames() {
+        return attributes.keySet().iterator();
+    }
+
+    /**
+     * Set a property.
+     */
+    public void setProperty(String name, String value) {
+        setAttribute(name, value);
+    }
+
+    /**
+     * Get a property
+     */
+    public String getProperty(String name) {
+        return (String)getAttribute(name);
+    }
+
+    /** The adapter, used to call the connector
+     */
+    public void setAdapter(Adapter adapter) {
+        this.adapter=adapter;
+    }
+
+    public Adapter getAdapter() {
+        return adapter;
+    }
+
+
+    /** Start the protocol
+     */
+    public void init() throws Exception {
+        ep.setName(getName());
+        ep.setHandler(cHandler);
+
+        try {
+            ep.init();
+        } catch (Exception ex) {
+            log.error(sm.getString("http11protocol.endpoint.initerror"), ex);
+            throw ex;
+        }
+        if(log.isInfoEnabled())
+            log.info(sm.getString("http11protocol.init", getName()));
+
+    }
+
+    ObjectName tpOname;
+    ObjectName rgOname;
+
+    public void start() throws Exception {
+        if( this.domain != null ) {
+            try {
+                tpOname=new ObjectName
+                    (domain + ":" + "type=ThreadPool,name=" + getName());
+                Registry.getRegistry(null, null)
+                .registerComponent(ep, tpOname, null );
+            } catch (Exception e) {
+                log.error("Can't register threadpool" );
+            }
+            rgOname=new ObjectName
+                (domain + ":type=GlobalRequestProcessor,name=" + getName());
+            Registry.getRegistry(null, null).registerComponent
+                ( cHandler.global, rgOname, null );
+        }
+
+        try {
+            ep.start();
+        } catch (Exception ex) {
+            log.error(sm.getString("http11protocol.endpoint.starterror"), ex);
+            throw ex;
+        }
+        if(log.isInfoEnabled())
+            log.info(sm.getString("http11protocol.start", getName()));
+    }
+
+    public void pause() throws Exception {
+        try {
+            ep.pause();
+        } catch (Exception ex) {
+            log.error(sm.getString("http11protocol.endpoint.pauseerror"), ex);
+            throw ex;
+        }
+        if(log.isInfoEnabled())
+            log.info(sm.getString("http11protocol.pause", getName()));
+    }
+
+    public void resume() throws Exception {
+        try {
+            ep.resume();
+        } catch (Exception ex) {
+            log.error(sm.getString("http11protocol.endpoint.resumeerror"), ex);
+            throw ex;
+        }
+        if(log.isInfoEnabled())
+            log.info(sm.getString("http11protocol.resume", getName()));
+    }
+
+    public void destroy() throws Exception {
+        if(log.isInfoEnabled())
+            log.info(sm.getString("http11protocol.stop", getName()));
+        ep.destroy();
+        if( tpOname!=null )
+            Registry.getRegistry(null, null).unregisterComponent(tpOname);
+        if( rgOname != null )
+            Registry.getRegistry(null, null).unregisterComponent(rgOname);
+    }
+
+    // -------------------- Properties--------------------
+    protected AprEndpoint ep=new AprEndpoint();
+    protected boolean secure;
+
+    protected Hashtable attributes = new Hashtable();
+
+    private int maxKeepAliveRequests=100; // as in Apache HTTPD server
+    private int timeout = 300000;   // 5 minutes as in Apache HTTPD server
+    private int maxSavePostSize = 4 * 1024;
+    private int maxHttpHeaderSize = 8 * 1024;
+    private int socketCloseDelay=-1;
+    private boolean disableUploadTimeout = true;
+    private int socketBuffer = 9000;
+    private Adapter adapter;
+    private Http11ConnectionHandler cHandler;
+
+    /**
+     * Compression value.
+     */
+    private String compression = "off";
+    private String noCompressionUserAgents = null;
+    private String restrictedUserAgents = null;
+    private String compressableMimeTypes = "text/html,text/xml,text/plain";
+    private int compressionMinSize    = 2048;
+
+    private String server;
+
+    // -------------------- Pool setup --------------------
+
+    public int getMaxThreads() {
+        return ep.getMaxThreads();
+    }
+
+    public void setMaxThreads( int maxThreads ) {
+        ep.setMaxThreads(maxThreads);
+        setAttribute("maxThreads", "" + maxThreads);
+    }
+
+    public void setThreadPriority(int threadPriority) {
+      ep.setThreadPriority(threadPriority);
+      setAttribute("threadPriority", "" + threadPriority);
+    }
+
+    public int getThreadPriority() {
+      return ep.getThreadPriority();
+    }
+
+    // -------------------- Tcp setup --------------------
+
+    public int getBacklog() {
+        return ep.getBacklog();
+    }
+
+    public void setBacklog( int i ) {
+        ep.setBacklog(i);
+        setAttribute("backlog", "" + i);
+    }
+
+    public int getPort() {
+        return ep.getPort();
+    }
+
+    public void setPort( int port ) {
+        ep.setPort(port);
+        setAttribute("port", "" + port);
+    }
+
+    public int getFirstReadTimeout() {
+        return ep.getFirstReadTimeout();
+    }
+
+    public void setFirstReadTimeout( int i ) {
+        ep.setFirstReadTimeout(i);
+        setAttribute("firstReadTimeout", "" + i);
+    }
+
+    public int getPollTime() {
+        return ep.getPollTime();
+    }
+
+    public void setPollTime( int i ) {
+        ep.setPollTime(i);
+        setAttribute("pollTime", "" + i);
+    }
+
+    public void setPollerSize(int i) {
+        ep.setPollerSize(i); 
+        setAttribute("pollerSize", "" + i);
+    }
+    
+    public int getPollerSize() {
+        return ep.getPollerSize();
+    }
+    
+    public void setSendfileSize(int i) {
+        ep.setSendfileSize(i); 
+        setAttribute("sendfileSize", "" + i);
+    }
+    
+    public int getSendfileSize() {
+        return ep.getSendfileSize();
+    }
+    
+    public boolean getUseSendfile() {
+        return ep.getUseSendfile();
+    }
+
+    public void setUseSendfile(boolean useSendfile) {
+        ep.setUseSendfile(useSendfile);
+    }
+
+    public InetAddress getAddress() {
+        return ep.getAddress();
+    }
+
+    public void setAddress(InetAddress ia) {
+        ep.setAddress( ia );
+        setAttribute("address", "" + ia);
+    }
+
+    public String getName() {
+        String encodedAddr = "";
+        if (getAddress() != null) {
+            encodedAddr = "" + getAddress();
+            if (encodedAddr.startsWith("/"))
+                encodedAddr = encodedAddr.substring(1);
+            encodedAddr = URLEncoder.encode(encodedAddr) + "-";
+        }
+        return ("http-" + encodedAddr + ep.getPort());
+    }
+
+    public boolean getTcpNoDelay() {
+        return ep.getTcpNoDelay();
+    }
+
+    public void setTcpNoDelay( boolean b ) {
+        ep.setTcpNoDelay( b );
+        setAttribute("tcpNoDelay", "" + b);
+    }
+
+    public boolean getDisableUploadTimeout() {
+        return disableUploadTimeout;
+    }
+
+    public void setDisableUploadTimeout(boolean isDisabled) {
+        disableUploadTimeout = isDisabled;
+    }
+
+    public int getSocketBuffer() {
+        return socketBuffer;
+    }
+
+    public void setSocketBuffer(int valueI) {
+        socketBuffer = valueI;
+    }
+
+    public String getCompression() {
+        return compression;
+    }
+
+    public void setCompression(String valueS) {
+        compression = valueS;
+        setAttribute("compression", valueS);
+    }
+
+    public int getMaxSavePostSize() {
+        return maxSavePostSize;
+    }
+
+    public void setMaxSavePostSize(int valueI) {
+        maxSavePostSize = valueI;
+        setAttribute("maxSavePostSize", "" + valueI);
+    }
+
+    public int getMaxHttpHeaderSize() {
+        return maxHttpHeaderSize;
+    }
+
+    public void setMaxHttpHeaderSize(int valueI) {
+        maxHttpHeaderSize = valueI;
+        setAttribute("maxHttpHeaderSize", "" + valueI);
+    }
+
+    public String getRestrictedUserAgents() {
+        return restrictedUserAgents;
+    }
+
+    public void setRestrictedUserAgents(String valueS) {
+        restrictedUserAgents = valueS;
+        setAttribute("restrictedUserAgents", valueS);
+    }
+
+    public String getNoCompressionUserAgents() {
+        return noCompressionUserAgents;
+    }
+
+    public void setNoCompressionUserAgents(String valueS) {
+        noCompressionUserAgents = valueS;
+        setAttribute("noCompressionUserAgents", valueS);
+    }
+
+    public String getCompressableMimeType() {
+        return compressableMimeTypes;
+    }
+
+    public void setCompressableMimeType(String valueS) {
+        compressableMimeTypes = valueS;
+        setAttribute("compressableMimeTypes", valueS);
+    }
+
+    public int getCompressionMinSize() {
+        return compressionMinSize;
+    }
+
+    public void setCompressionMinSize(int valueI) {
+        compressionMinSize = valueI;
+        setAttribute("compressionMinSize", "" + valueI);
+    }
+
+    public int getSoLinger() {
+        return ep.getSoLinger();
+    }
+
+    public void setSoLinger( int i ) {
+        ep.setSoLinger( i );
+        setAttribute("soLinger", "" + i);
+    }
+
+    public int getSoTimeout() {
+        return ep.getSoTimeout();
+    }
+
+    public void setSoTimeout( int i ) {
+        ep.setSoTimeout(i);
+        setAttribute("soTimeout", "" + i);
+    }
+
+    public String getProtocol() {
+        return getProperty("protocol");
+    }
+
+    public void setProtocol( String k ) {
+        setSecure(true);
+        setAttribute("protocol", k);
+    }
+
+    public boolean getSecure() {
+        return secure;
+    }
+
+    public void setSecure( boolean b ) {
+        secure=b;
+        setAttribute("secure", "" + b);
+    }
+
+    public int getMaxKeepAliveRequests() {
+        return maxKeepAliveRequests;
+    }
+
+    /** Set the maximum number of Keep-Alive requests that we will honor.
+     */
+    public void setMaxKeepAliveRequests(int mkar) {
+        maxKeepAliveRequests = mkar;
+        setAttribute("maxKeepAliveRequests", "" + mkar);
+    }
+
+    /**
+     * Return the Keep-Alive policy for the connection.
+     */
+    public boolean getKeepAlive() {
+        return ((maxKeepAliveRequests != 0) && (maxKeepAliveRequests != 1));
+    }
+
+    /**
+     * Set the keep-alive policy for this connection.
+     */
+    public void setKeepAlive(boolean keepAlive) {
+        if (!keepAlive) {
+            setMaxKeepAliveRequests(1);
+        }
+    }
+
+    public int getSocketCloseDelay() {
+        return socketCloseDelay;
+    }
+
+    public void setSocketCloseDelay( int d ) {
+        socketCloseDelay=d;
+        setAttribute("socketCloseDelay", "" + d);
+    }
+
+    public void setServer( String server ) {
+        this.server = server;
+    }
+
+    public String getServer() {
+        return server;
+    }
+
+    public int getTimeout() {
+        return timeout;
+    }
+
+    public void setTimeout( int timeouts ) {
+        timeout = timeouts;
+        setAttribute("timeout", "" + timeouts);
+    }
+
+    // --------------------  SSL related properties --------------------
+
+    /**
+     * SSL engine.
+     */
+    public String getSSLEngine() { return ep.getSSLEngine(); }
+    public void setSSLEngine(String SSLEngine) { ep.setSSLEngine(SSLEngine); }
+
+
+    /**
+     * SSL protocol.
+     */
+    public String getSSLProtocol() { return ep.getSSLProtocol(); }
+    public void setSSLProtocol(String SSLProtocol) { ep.setSSLProtocol(SSLProtocol); }
+
+
+    /**
+     * SSL password (if a cert is encrypted, and no password has been provided, a callback
+     * will ask for a password).
+     */
+    public String getSSLPassword() { return ep.getSSLPassword(); }
+    public void setSSLPassword(String SSLPassword) { ep.setSSLPassword(SSLPassword); }
+
+
+    /**
+     * SSL cipher suite.
+     */
+    public String getSSLCipherSuite() { return ep.getSSLCipherSuite(); }
+    public void setSSLCipherSuite(String SSLCipherSuite) { ep.setSSLCipherSuite(SSLCipherSuite); }
+
+
+    /**
+     * SSL certificate file.
+     */
+    public String getSSLCertificateFile() { return ep.getSSLCertificateFile(); }
+    public void setSSLCertificateFile(String SSLCertificateFile) { ep.setSSLCertificateFile(SSLCertificateFile); }
+
+
+    /**
+     * SSL certificate key file.
+     */
+    public String getSSLCertificateKeyFile() { return ep.getSSLCertificateKeyFile(); }
+    public void setSSLCertificateKeyFile(String SSLCertificateKeyFile) { ep.setSSLCertificateKeyFile(SSLCertificateKeyFile); }
+
+
+    /**
+     * SSL certificate chain file.
+     */
+    public String getSSLCertificateChainFile() { return ep.getSSLCertificateChainFile(); }
+    public void setSSLCertificateChainFile(String SSLCertificateChainFile) { ep.setSSLCertificateChainFile(SSLCertificateChainFile); }
+
+
+    /**
+     * SSL CA certificate path.
+     */
+    public String getSSLCACertificatePath() { return ep.getSSLCACertificatePath(); }
+    public void setSSLCACertificatePath(String SSLCACertificatePath) { ep.setSSLCACertificatePath(SSLCACertificatePath); }
+
+
+    /**
+     * SSL CA certificate file.
+     */
+    public String getSSLCACertificateFile() { return ep.getSSLCACertificateFile(); }
+    public void setSSLCACertificateFile(String SSLCACertificateFile) { ep.setSSLCACertificateFile(SSLCACertificateFile); }
+
+
+    /**
+     * SSL CA revocation path.
+     */
+    public String getSSLCARevocationPath() { return ep.getSSLCARevocationPath(); }
+    public void setSSLCARevocationPath(String SSLCARevocationPath) { ep.setSSLCARevocationPath(SSLCARevocationPath); }
+
+
+    /**
+     * SSL CA revocation file.
+     */
+    public String getSSLCARevocationFile() { return ep.getSSLCARevocationFile(); }
+    public void setSSLCARevocationFile(String SSLCARevocationFile) { ep.setSSLCARevocationFile(SSLCARevocationFile); }
+
+
+    /**
+     * SSL verify client.
+     */
+    public String getSSLVerifyClient() { return ep.getSSLVerifyClient(); }
+    public void setSSLVerifyClient(String SSLVerifyClient) { ep.setSSLVerifyClient(SSLVerifyClient); }
+
+
+    /**
+     * SSL verify depth.
+     */
+    public int getSSLVerifyDepth() { return ep.getSSLVerifyDepth(); }
+    public void setSSLVerifyDepth(int SSLVerifyDepth) { ep.setSSLVerifyDepth(SSLVerifyDepth); }
+
+    // --------------------  Connection handler --------------------
+
+    static class Http11ConnectionHandler implements Handler {
+        Http11AprProtocol proto;
+        static int count=0;
+        RequestGroupInfo global=new RequestGroupInfo();
+        ThreadLocal localProcessor = new ThreadLocal();
+
+        Http11ConnectionHandler( Http11AprProtocol proto ) {
+            this.proto=proto;
+        }
+
+        public boolean process(long socket) {
+            Http11AprProcessor processor = null;
+            try {
+                processor = (Http11AprProcessor) localProcessor.get();
+                if (processor == null) {
+                    processor =
+                        new Http11AprProcessor(proto.maxHttpHeaderSize, proto.ep);
+                    processor.setAdapter(proto.adapter);
+                    processor.setMaxKeepAliveRequests(proto.maxKeepAliveRequests);
+                    processor.setTimeout(proto.timeout);
+                    processor.setDisableUploadTimeout(proto.disableUploadTimeout);
+                    processor.setCompression(proto.compression);
+                    processor.setCompressionMinSize(proto.compressionMinSize);
+                    processor.setNoCompressionUserAgents(proto.noCompressionUserAgents);
+                    processor.setCompressableMimeTypes(proto.compressableMimeTypes);
+                    processor.setRestrictedUserAgents(proto.restrictedUserAgents);
+                    processor.setSocketBuffer(proto.socketBuffer);
+                    processor.setMaxSavePostSize(proto.maxSavePostSize);
+                    processor.setServer(proto.server);
+                    localProcessor.set(processor);
+                    if (proto.getDomain() != null) {
+                        synchronized (this) {
+                            try {
+                                RequestInfo rp = processor.getRequest().getRequestProcessor();
+                                rp.setGlobalProcessor(global);
+                                ObjectName rpName = new ObjectName
+                                (proto.getDomain() + ":type=RequestProcessor,worker="
+                                        + proto.getName() + ",name=HttpRequest" + count++);
+                                Registry.getRegistry(null, null).registerComponent(rp, rpName, null);
+                            } catch (Exception e) {
+                                log.warn("Error registering request");
+                            }
+                        }
+                    }
+                }
+
+                if (processor instanceof ActionHook) {
+                    ((ActionHook) processor).action(ActionCode.ACTION_START, null);
+                }
+
+                return processor.process(socket);
+
+            } catch(java.net.SocketException e) {
+                // SocketExceptions are normal
+                Http11AprProtocol.log.debug
+                    (sm.getString
+                     ("http11protocol.proto.socketexception.debug"), e);
+            } catch (java.io.IOException e) {
+                // IOExceptions are normal
+                Http11AprProtocol.log.debug
+                    (sm.getString
+                     ("http11protocol.proto.ioexception.debug"), e);
+            }
+            // Future developers: if you discover any other
+            // rare-but-nonfatal exceptions, catch them here, and log as
+            // above.
+            catch (Throwable e) {
+                // 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.
+                Http11AprProtocol.log.error
+                    (sm.getString("http11protocol.proto.error"), e);
+            } finally {
+                //       if(proto.adapter != null) proto.adapter.recycle();
+                //                processor.recycle();
+
+                if (processor instanceof ActionHook) {
+                    ((ActionHook) processor).action(ActionCode.ACTION_STOP, null);
+                }
+            }
+            return false;
+        }
+    }
+
+    protected static org.apache.commons.logging.Log log
+        = org.apache.commons.logging.LogFactory.getLog(Http11AprProtocol.class);
+
+    // -------------------- Various implementation classes --------------------
+
+    protected String domain;
+    protected ObjectName oname;
+    protected MBeanServer mserver;
+
+    public ObjectName getObjectName() {
+        return oname;
+    }
+
+    public String getDomain() {
+        return domain;
+    }
+
+    public ObjectName preRegister(MBeanServer server,
+                                  ObjectName name) throws Exception {
+        oname=name;
+        mserver=server;
+        domain=name.getDomain();
+        return name;
+    }
+
+    public void postRegister(Boolean registrationDone) {
+    }
+
+    public void preDeregister() throws Exception {
+    }
+
+    public void postDeregister() {
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/http11/src/java/org/apache/coyote/http11/Http11BaseProtocol.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/http11/src/java/org/apache/coyote/http11/Http11BaseProtocol.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/http11/src/java/org/apache/coyote/http11/Http11BaseProtocol.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,746 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.InetAddress;
+import java.net.Socket;
+import java.net.URLEncoder;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Iterator;
+
+import org.apache.coyote.ActionCode;
+import org.apache.coyote.ActionHook;
+import org.apache.coyote.Adapter;
+import org.apache.coyote.ProtocolHandler;
+import org.apache.coyote.RequestGroupInfo;
+import org.apache.tomcat.util.net.PoolTcpEndpoint;
+import org.apache.tomcat.util.net.SSLImplementation;
+import org.apache.tomcat.util.net.SSLSupport;
+import org.apache.tomcat.util.net.ServerSocketFactory;
+import org.apache.tomcat.util.net.TcpConnection;
+import org.apache.tomcat.util.net.TcpConnectionHandler;
+import org.apache.tomcat.util.res.StringManager;
+import org.apache.tomcat.util.threads.ThreadPool;
+
+
+/**
+ * Abstract the protocol implementation, including threading, etc.
+ * Processor is single threaded and specific to stream-based protocols,
+ * will not fit Jk protocols like JNI.
+ *
+ * @author Remy Maucherat
+ * @author Costin Manolache
+ */
+public class Http11BaseProtocol implements ProtocolHandler
+{
+    public Http11BaseProtocol() {
+        setSoLinger(Constants.DEFAULT_CONNECTION_LINGER);
+        setSoTimeout(Constants.DEFAULT_CONNECTION_TIMEOUT);
+        setServerSoTimeout(Constants.DEFAULT_SERVER_SOCKET_TIMEOUT);
+        setTcpNoDelay(Constants.DEFAULT_TCP_NO_DELAY);
+    }
+
+    /**
+     * The string manager for this package.
+     */
+    protected static StringManager sm =
+        StringManager.getManager(Constants.Package);
+
+    /** Pass config info
+     */
+    public void setAttribute( String name, Object value ) {
+        if( log.isTraceEnabled())
+            log.trace(sm.getString("http11protocol.setattribute", name, value));
+
+        attributes.put(name, value);
+    }
+
+    public Object getAttribute( String key ) {
+        if( log.isTraceEnabled())
+            log.trace(sm.getString("http11protocol.getattribute", key));
+        return attributes.get(key);
+    }
+
+    public Iterator getAttributeNames() {
+        return attributes.keySet().iterator();
+    }
+
+    /**
+     * Set a property.
+     */
+    public void setProperty(String name, String value) {
+        setAttribute(name, value);
+    }
+
+    /**
+     * Get a property
+     */
+    public String getProperty(String name) {
+        return (String)getAttribute(name);
+    }
+
+    /** The adapter, used to call the connector
+     */
+    public void setAdapter(Adapter adapter) {
+        this.adapter=adapter;
+    }
+
+    public Adapter getAdapter() {
+        return adapter;
+    }
+    
+    protected Http11ConnectionHandler createConnectionHandler() {
+        return new Http11ConnectionHandler( this );
+    }
+
+    /** Start the protocol
+     */
+    public void init() throws Exception {
+        cHandler = createConnectionHandler() ;
+        ep.setConnectionHandler( cHandler );
+        try {
+            checkSocketFactory();
+        } catch( Exception ex ) {
+            log.error(sm.getString("http11protocol.socketfactory.initerror"),
+                      ex);
+            throw ex;
+        }
+
+        if( socketFactory!=null ) {
+            Enumeration attE=attributes.keys();
+            while( attE.hasMoreElements() ) {
+                String key=(String)attE.nextElement();
+                Object v=attributes.get( key );
+                socketFactory.setAttribute( key, v );
+            }
+        }
+
+        // XXX get domain from registration
+        try {
+            ep.initEndpoint();
+        } catch (Exception ex) {
+            log.error(sm.getString("http11protocol.endpoint.initerror"), ex);
+            throw ex;
+        }
+        if(log.isInfoEnabled())
+            log.info(sm.getString("http11protocol.init", getName()));
+
+    }
+
+    public void start() throws Exception {
+        try {
+            ep.startEndpoint();
+        } catch (Exception ex) {
+            log.error(sm.getString("http11protocol.endpoint.starterror"), ex);
+            throw ex;
+        }
+        if(log.isInfoEnabled())
+            log.info(sm.getString("http11protocol.start", getName()));
+    }
+
+    public void pause() throws Exception {
+        try {
+            ep.pauseEndpoint();
+        } catch (Exception ex) {
+            log.error(sm.getString("http11protocol.endpoint.pauseerror"), ex);
+            throw ex;
+        }
+        if(log.isInfoEnabled())
+            log.info(sm.getString("http11protocol.pause", getName()));
+    }
+
+    public void resume() throws Exception {
+        try {
+            ep.resumeEndpoint();
+        } catch (Exception ex) {
+            log.error(sm.getString("http11protocol.endpoint.resumeerror"), ex);
+            throw ex;
+        }
+        if(log.isInfoEnabled())
+            log.info(sm.getString("http11protocol.resume", getName()));
+    }
+
+    public void destroy() throws Exception {
+        if(log.isInfoEnabled())
+            log.info(sm.getString("http11protocol.stop", getName()));
+        ep.stopEndpoint();
+    }
+
+    // -------------------- Properties--------------------
+    protected ThreadPool tp=ThreadPool.createThreadPool(true);
+    protected PoolTcpEndpoint ep=new PoolTcpEndpoint(tp);
+    protected boolean secure;
+
+    protected ServerSocketFactory socketFactory;
+    protected SSLImplementation sslImplementation;
+    // socket factory attriubtes ( XXX replace with normal setters )
+    protected Hashtable attributes = new Hashtable();
+    protected String socketFactoryName=null;
+    protected String sslImplementationName=null;
+
+    private int maxKeepAliveRequests=100; // as in Apache HTTPD server
+    private int timeout = 300000;   // 5 minutes as in Apache HTTPD server
+    private int maxSavePostSize = 4 * 1024;
+    private int maxHttpHeaderSize = 8 * 1024;
+    private String reportedname;
+    private int socketCloseDelay=-1;
+    private boolean disableUploadTimeout = true;
+    private int socketBuffer = 9000;
+    private Adapter adapter;
+    protected Http11ConnectionHandler cHandler;
+
+    /**
+     * Compression value.
+     */
+    private String compression = "off";
+    private String noCompressionUserAgents = null;
+    private String restrictedUserAgents = null;
+    private String compressableMimeTypes = "text/html,text/xml,text/plain";
+    private int compressionMinSize    = 2048;
+
+    private String server;
+
+    // -------------------- Pool setup --------------------
+
+    public int getMaxThreads() {
+        return ep.getMaxThreads();
+    }
+
+    public void setMaxThreads( int maxThreads ) {
+        ep.setMaxThreads(maxThreads);
+        setAttribute("maxThreads", "" + maxThreads);
+    }
+
+    public int getMaxSpareThreads() {
+        return ep.getMaxSpareThreads();
+    }
+
+    public void setMaxSpareThreads( int maxThreads ) {
+        ep.setMaxSpareThreads(maxThreads);
+        setAttribute("maxSpareThreads", "" + maxThreads);
+    }
+
+    public int getMinSpareThreads() {
+        return ep.getMinSpareThreads();
+    }
+
+    public void setMinSpareThreads( int minSpareThreads ) {
+        ep.setMinSpareThreads(minSpareThreads);
+        setAttribute("minSpareThreads", "" + minSpareThreads);
+    }
+
+    public void setThreadPriority(int threadPriority) {
+      ep.setThreadPriority(threadPriority);
+      setAttribute("threadPriority", "" + threadPriority);
+    }
+
+    public int getThreadPriority() {
+      return ep.getThreadPriority();
+    }
+
+    public void setStrategy(String strategy) {
+        ep.setStrategy(strategy);
+        setAttribute("strategy", strategy);
+      }
+
+      public String getStrategy() {
+        return ep.getStrategy();
+      }
+
+    // -------------------- Tcp setup --------------------
+
+    public int getBacklog() {
+        return ep.getBacklog();
+    }
+
+    public void setBacklog( int i ) {
+        ep.setBacklog(i);
+        setAttribute("backlog", "" + i);
+    }
+
+    public int getPort() {
+        return ep.getPort();
+    }
+
+    public void setPort( int port ) {
+        ep.setPort(port);
+        setAttribute("port", "" + port);
+    }
+
+    public InetAddress getAddress() {
+        return ep.getAddress();
+    }
+
+    public void setAddress(InetAddress ia) {
+        ep.setAddress( ia );
+        setAttribute("address", "" + ia);
+    }
+
+    public String getName() {
+        String encodedAddr = "";
+        if (getAddress() != null) {
+            encodedAddr = "" + getAddress();
+            if (encodedAddr.startsWith("/"))
+                encodedAddr = encodedAddr.substring(1);
+            encodedAddr = URLEncoder.encode(encodedAddr) + "-";
+        }
+        return ("http-" + encodedAddr + ep.getPort());
+    }
+
+    public String getSocketFactory() {
+        return socketFactoryName;
+    }
+
+    public void setSocketFactory( String valueS ) {
+        socketFactoryName = valueS;
+        setAttribute("socketFactory", valueS);
+    }
+
+    public String getSSLImplementation() {
+        return sslImplementationName;
+    }
+
+    public void setSSLImplementation( String valueS) {
+        sslImplementationName = valueS;
+        setSecure(true);
+        setAttribute("sslImplementation", valueS);
+    }
+
+    public boolean getTcpNoDelay() {
+        return ep.getTcpNoDelay();
+    }
+
+    public void setTcpNoDelay( boolean b ) {
+        ep.setTcpNoDelay( b );
+        setAttribute("tcpNoDelay", "" + b);
+    }
+
+    public boolean getDisableUploadTimeout() {
+        return disableUploadTimeout;
+    }
+
+    public void setDisableUploadTimeout(boolean isDisabled) {
+        disableUploadTimeout = isDisabled;
+    }
+
+    public int getSocketBuffer() {
+        return socketBuffer;
+    }
+
+    public void setSocketBuffer(int valueI) {
+        socketBuffer = valueI;
+    }
+
+    public String getCompression() {
+        return compression;
+    }
+
+    public void setCompression(String valueS) {
+        compression = valueS;
+        setAttribute("compression", valueS);
+    }
+
+    public int getMaxSavePostSize() {
+        return maxSavePostSize;
+    }
+
+    public void setMaxSavePostSize(int valueI) {
+        maxSavePostSize = valueI;
+        setAttribute("maxSavePostSize", "" + valueI);
+    }
+
+    public int getMaxHttpHeaderSize() {
+        return maxHttpHeaderSize;
+    }
+
+    public void setMaxHttpHeaderSize(int valueI) {
+        maxHttpHeaderSize = valueI;
+        setAttribute("maxHttpHeaderSize", "" + valueI);
+    }
+
+    public String getRestrictedUserAgents() {
+        return restrictedUserAgents;
+    }
+
+    public void setRestrictedUserAgents(String valueS) {
+        restrictedUserAgents = valueS;
+        setAttribute("restrictedUserAgents", valueS);
+    }
+
+    public String getNoCompressionUserAgents() {
+        return noCompressionUserAgents;
+    }
+
+    public void setNoCompressionUserAgents(String valueS) {
+        noCompressionUserAgents = valueS;
+        setAttribute("noCompressionUserAgents", valueS);
+    }
+
+    public String getCompressableMimeType() {
+        return compressableMimeTypes;
+    }
+
+    public void setCompressableMimeType(String valueS) {
+        compressableMimeTypes = valueS;
+        setAttribute("compressableMimeTypes", valueS);
+    }
+
+    public int getCompressionMinSize() {
+        return compressionMinSize;
+    }
+
+    public void setCompressionMinSize(int valueI) {
+        compressionMinSize = valueI;
+        setAttribute("compressionMinSize", "" + valueI);
+    }
+
+    public int getSoLinger() {
+        return ep.getSoLinger();
+    }
+
+    public void setSoLinger( int i ) {
+        ep.setSoLinger( i );
+        setAttribute("soLinger", "" + i);
+    }
+
+    public int getSoTimeout() {
+        return ep.getSoTimeout();
+    }
+
+    public void setSoTimeout( int i ) {
+        ep.setSoTimeout(i);
+        setAttribute("soTimeout", "" + i);
+    }
+
+    public int getServerSoTimeout() {
+        return ep.getServerSoTimeout();
+    }
+
+    public void setServerSoTimeout( int i ) {
+        ep.setServerSoTimeout(i);
+        setAttribute("serverSoTimeout", "" + i);
+    }
+
+    public String getKeystore() {
+        return getProperty("keystore");
+    }
+
+    public void setKeystore( String k ) {
+        setAttribute("keystore", k);
+    }
+
+    public String getKeypass() {
+        return getProperty("keypass");
+    }
+
+    public void setKeypass( String k ) {
+        attributes.put("keypass", k);
+        //setAttribute("keypass", k);
+    }
+
+    public String getKeytype() {
+        return getProperty("keystoreType");
+    }
+
+    public void setKeytype( String k ) {
+        setAttribute("keystoreType", k);
+    }
+
+    public String getClientauth() {
+        return getProperty("clientauth");
+    }
+
+    public void setClientauth( String k ) {
+        setAttribute("clientauth", k);
+    }
+
+    public String getProtocol() {
+        return getProperty("protocol");
+    }
+
+    public void setProtocol( String k ) {
+        setSecure(true);
+        setAttribute("protocol", k);
+    }
+
+    public String getProtocols() {
+        return getProperty("protocols");
+    }
+
+    public void setProtocols(String k) {
+        setAttribute("protocols", k);
+    }
+
+    public String getAlgorithm() {
+        return getProperty("algorithm");
+    }
+
+    public void setAlgorithm( String k ) {
+        setAttribute("algorithm", k);
+    }
+
+    public boolean getSecure() {
+        return secure;
+    }
+
+    public void setSecure( boolean b ) {
+        secure=b;
+        setAttribute("secure", "" + b);
+    }
+
+    public String getCiphers() {
+        return getProperty("ciphers");
+    }
+
+    public void setCiphers(String ciphers) {
+        setAttribute("ciphers", ciphers);
+    }
+
+    public String getKeyAlias() {
+        return getProperty("keyAlias");
+    }
+
+    public void setKeyAlias(String keyAlias) {
+        setAttribute("keyAlias", keyAlias);
+    }
+
+    public int getMaxKeepAliveRequests() {
+        return maxKeepAliveRequests;
+    }
+
+    /** Set the maximum number of Keep-Alive requests that we will honor.
+     */
+    public void setMaxKeepAliveRequests(int mkar) {
+        maxKeepAliveRequests = mkar;
+        setAttribute("maxKeepAliveRequests", "" + mkar);
+    }
+
+    /**
+     * Return the Keep-Alive policy for the connection.
+     */
+    public boolean getKeepAlive() {
+        return ((maxKeepAliveRequests != 0) && (maxKeepAliveRequests != 1));
+    }
+
+    /**
+     * Set the keep-alive policy for this connection.
+     */
+    public void setKeepAlive(boolean keepAlive) {
+        if (!keepAlive) {
+            setMaxKeepAliveRequests(1);
+        }
+    }
+
+    public int getSocketCloseDelay() {
+        return socketCloseDelay;
+    }
+
+    public void setSocketCloseDelay( int d ) {
+        socketCloseDelay=d;
+        setAttribute("socketCloseDelay", "" + d);
+    }
+
+    public void setServer( String server ) {
+        this.server = server;
+    }
+
+    public String getServer() {
+        return server;
+    }
+
+
+    private static ServerSocketFactory string2SocketFactory( String val)
+    throws ClassNotFoundException, IllegalAccessException,
+    InstantiationException
+    {
+        Class chC=Class.forName( val );
+        return (ServerSocketFactory)chC.newInstance();
+    }
+
+    public int getTimeout() {
+        return timeout;
+    }
+
+    public void setTimeout( int timeouts ) {
+        timeout = timeouts;
+        setAttribute("timeout", "" + timeouts);
+    }
+
+    public String getReportedname() {
+        return reportedname;
+    }
+
+    public void setReportedname( String reportedName) {
+        reportedname = reportedName;
+    }
+
+    // --------------------  Connection handler --------------------
+    public static final int THREAD_DATA_PROCESSOR=1;
+    public static final int THREAD_DATA_OBJECT_NAME=2;
+
+    static class Http11ConnectionHandler implements TcpConnectionHandler {
+        Http11BaseProtocol proto;
+        static int count=0;
+        RequestGroupInfo global=new RequestGroupInfo();
+
+        Http11ConnectionHandler( Http11BaseProtocol proto ) {
+            this.proto=proto;
+        }
+
+        public void setAttribute( String name, Object value ) {
+        }
+
+        public void setServer( Object o ) {
+        }
+
+        public Object[] init() {
+            Object thData[]=new Object[3];
+
+            Http11Processor  processor =
+                new Http11Processor(proto.maxHttpHeaderSize);
+            processor.setAdapter( proto.adapter );
+            processor.setThreadPool( proto.tp );
+            processor.setEndpoint( proto.ep );
+            processor.setMaxKeepAliveRequests( proto.maxKeepAliveRequests );
+            processor.setTimeout( proto.timeout );
+            processor.setDisableUploadTimeout( proto.disableUploadTimeout );
+            processor.setCompression( proto.compression );
+            processor.setCompressionMinSize( proto.compressionMinSize);
+            processor.setNoCompressionUserAgents( proto.noCompressionUserAgents);
+            processor.setCompressableMimeTypes( proto.compressableMimeTypes);
+            processor.setRestrictedUserAgents( proto.restrictedUserAgents);
+            processor.setSocketBuffer( proto.socketBuffer );
+            processor.setMaxSavePostSize( proto.maxSavePostSize );
+            processor.setServer( proto.server );
+
+            thData[Http11BaseProtocol.THREAD_DATA_PROCESSOR]=processor;
+
+            return  thData;
+        }
+
+        public void processConnection(TcpConnection connection,
+                      Object thData[]) {
+            Socket socket=null;
+            Http11Processor  processor=null;
+            try {
+                processor=(Http11Processor)thData[Http11BaseProtocol.THREAD_DATA_PROCESSOR];
+
+                if (processor instanceof ActionHook) {
+                    ((ActionHook) processor).action(ActionCode.ACTION_START, null);
+                }
+                socket=connection.getSocket();
+
+                InputStream in = socket.getInputStream();
+                OutputStream out = socket.getOutputStream();
+
+                if( proto.secure ) {
+                    SSLSupport sslSupport=null;
+                    if(proto.sslImplementation != null)
+                        sslSupport = proto.sslImplementation.getSSLSupport(socket);
+                    processor.setSSLSupport(sslSupport);
+                } else {
+                    processor.setSSLSupport( null );
+                }
+                processor.setSocket( socket );
+
+                processor.process(in, out);
+
+                // If unread input arrives after the shutdownInput() call
+                // below and before or during the socket.close(), an error
+                // may be reported to the client.  To help troubleshoot this
+                // type of error, provide a configurable delay to give the
+                // unread input time to arrive so it can be successfully read
+                // and discarded by shutdownInput().
+                if( proto.socketCloseDelay >= 0 ) {
+                    try {
+                        Thread.sleep(proto.socketCloseDelay);
+                    } catch (InterruptedException ie) { /* ignore */ }
+                }
+
+                TcpConnection.shutdownInput( socket );
+            } catch(java.net.SocketException e) {
+                // SocketExceptions are normal
+                Http11BaseProtocol.log.debug
+                    (sm.getString
+                     ("http11protocol.proto.socketexception.debug"), e);
+            } catch (IOException e) {
+                // IOExceptions are normal
+                Http11BaseProtocol.log.debug
+                    (sm.getString
+                     ("http11protocol.proto.ioexception.debug"), e);
+            }
+            // Future developers: if you discover any other
+            // rare-but-nonfatal exceptions, catch them here, and log as
+            // above.
+            catch (Throwable e) {
+                // 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.
+                Http11BaseProtocol.log.error
+                    (sm.getString("http11protocol.proto.error"), e);
+            } finally {
+                //       if(proto.adapter != null) proto.adapter.recycle();
+                //                processor.recycle();
+
+                if (processor instanceof ActionHook) {
+                    ((ActionHook) processor).action(ActionCode.ACTION_STOP, null);
+                }
+                // recycle kernel sockets ASAP
+                try { if (socket != null) socket.close (); }
+                catch (IOException e) { /* ignore */ }
+            }
+        }
+    }
+
+    protected static org.apache.commons.logging.Log log
+        = org.apache.commons.logging.LogFactory.getLog(Http11BaseProtocol.class);
+
+    // -------------------- Various implementation classes --------------------
+
+    /** Sanity check and socketFactory setup.
+     *  IMHO it is better to stop the show on a broken connector,
+     *  then leave Tomcat running and broken.
+     *  @exception TomcatException Unable to resolve classes
+     */
+    private void checkSocketFactory() throws Exception {
+        if (secure) {
+            try {
+                // The SSL setup code has been moved into
+                // SSLImplementation since SocketFactory doesn't
+                // provide a wide enough interface
+                sslImplementation =
+                    SSLImplementation.getInstance(sslImplementationName);
+                socketFactory = sslImplementation.getServerSocketFactory();
+                ep.setServerSocketFactory(socketFactory);
+            } catch (ClassNotFoundException e){
+                throw e;
+            }
+        } else if (socketFactoryName != null) {
+            try {
+                socketFactory = string2SocketFactory(socketFactoryName);
+                ep.setServerSocketFactory(socketFactory);
+            } catch(Exception sfex) {
+                throw sfex;
+            }
+        }
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/http11/src/java/org/apache/coyote/http11/Http11Processor.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/http11/src/java/org/apache/coyote/http11/Http11Processor.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/http11/src/java/org/apache/coyote/http11/Http11Processor.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,1720 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InterruptedIOException;
+import java.io.OutputStream;
+import java.net.InetAddress;
+import java.net.Socket;
+import java.util.StringTokenizer;
+import java.util.regex.Pattern;
+import java.util.regex.PatternSyntaxException;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+
+import org.apache.coyote.ActionCode;
+import org.apache.coyote.ActionHook;
+import org.apache.coyote.Adapter;
+import org.apache.coyote.Processor;
+import org.apache.coyote.Request;
+import org.apache.coyote.RequestInfo;
+import org.apache.coyote.Response;
+import org.apache.coyote.http11.filters.ChunkedInputFilter;
+import org.apache.coyote.http11.filters.ChunkedOutputFilter;
+import org.apache.coyote.http11.filters.GzipOutputFilter;
+import org.apache.coyote.http11.filters.IdentityInputFilter;
+import org.apache.coyote.http11.filters.IdentityOutputFilter;
+import org.apache.coyote.http11.filters.SavedRequestInputFilter;
+import org.apache.coyote.http11.filters.VoidInputFilter;
+import org.apache.coyote.http11.filters.VoidOutputFilter;
+import org.apache.coyote.http11.filters.BufferedInputFilter;
+import org.apache.tomcat.util.buf.Ascii;
+import org.apache.tomcat.util.buf.ByteChunk;
+import org.apache.tomcat.util.buf.HexUtils;
+import org.apache.tomcat.util.buf.MessageBytes;
+import org.apache.tomcat.util.http.FastHttpDateFormat;
+import org.apache.tomcat.util.http.MimeHeaders;
+import org.apache.tomcat.util.net.PoolTcpEndpoint;
+import org.apache.tomcat.util.net.SSLSupport;
+import org.apache.tomcat.util.res.StringManager;
+import org.apache.tomcat.util.threads.ThreadPool;
+import org.apache.tomcat.util.threads.ThreadWithAttributes;
+
+
+/**
+ * Processes HTTP requests.
+ *
+ * @author Remy Maucherat
+ */
+public class Http11Processor implements Processor, ActionHook {
+
+
+    /**
+     * Logger.
+     */
+    protected static org.apache.commons.logging.Log log
+        = org.apache.commons.logging.LogFactory.getLog(Http11Processor.class);
+
+    /**
+     * The string manager for this package.
+     */
+    protected static StringManager sm =
+        StringManager.getManager(Constants.Package);
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Default constructor.
+     */
+    public Http11Processor() {
+        this(Constants.DEFAULT_HTTP_HEADER_BUFFER_SIZE);
+    }
+
+
+    public Http11Processor(int headerBufferSize) {
+
+        request = new Request();
+        inputBuffer = new InternalInputBuffer(request, headerBufferSize);
+        request.setInputBuffer(inputBuffer);
+
+        response = new Response();
+        response.setHook(this);
+        outputBuffer = new InternalOutputBuffer(response, headerBufferSize);
+        response.setOutputBuffer(outputBuffer);
+        request.setResponse(response);
+
+        initializeFilters();
+
+        // Cause loading of HexUtils
+        int foo = HexUtils.DEC[0];
+
+    }
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * Associated adapter.
+     */
+    protected Adapter adapter = null;
+
+
+    /**
+     * Request object.
+     */
+    protected Request request = null;
+
+
+    /**
+     * Response object.
+     */
+    protected Response response = null;
+
+
+    /**
+     * Input.
+     */
+    protected InternalInputBuffer inputBuffer = null;
+
+
+    /**
+     * Output.
+     */
+    protected InternalOutputBuffer outputBuffer = null;
+
+
+    /**
+     * State flag.
+     */
+    protected boolean started = false;
+
+
+    /**
+     * Error flag.
+     */
+    protected boolean error = false;
+
+
+    /**
+     * Keep-alive.
+     */
+    protected boolean keepAlive = true;
+
+
+    /**
+     * HTTP/1.1 flag.
+     */
+    protected boolean http11 = true;
+
+
+    /**
+     * HTTP/0.9 flag.
+     */
+    protected boolean http09 = false;
+
+
+    /**
+     * Content delimitator for the request (if false, the connection will
+     * be closed at the end of the request).
+     */
+    protected boolean contentDelimitation = true;
+
+
+    /**
+     * Is there an expectation ?
+     */
+    protected boolean expectation = false;
+
+
+    /**
+     * List of restricted user agents.
+     */
+    protected Pattern[] restrictedUserAgents = null;
+
+
+    /**
+     * Maximum number of Keep-Alive requests to honor.
+     */
+    protected int maxKeepAliveRequests = -1;
+
+
+    /**
+     * SSL information.
+     */
+    protected SSLSupport sslSupport;
+
+
+    /**
+     * Socket associated with the current connection.
+     */
+    protected Socket socket;
+
+
+    /**
+     * Remote Address associated with the current connection.
+     */
+    protected String remoteAddr = null;
+
+
+    /**
+     * Remote Host associated with the current connection.
+     */
+    protected String remoteHost = null;
+
+
+    /**
+     * Local Host associated with the current connection.
+     */
+    protected String localName = null;
+
+
+
+    /**
+     * Local port to which the socket is connected
+     */
+    protected int localPort = -1;
+
+
+    /**
+     * Remote port to which the socket is connected
+     */
+    protected int remotePort = -1;
+
+
+    /**
+     * The local Host address.
+     */
+    protected String localAddr = null;
+
+
+    /**
+     * Maximum timeout on uploads. 5 minutes as in Apache HTTPD server.
+     */
+    protected int timeout = 300000;
+
+
+    /**
+     * Flag to disable setting a different time-out on uploads.
+     */
+    protected boolean disableUploadTimeout = false;
+
+
+    /**
+     * Allowed compression level.
+     */
+    protected int compressionLevel = 0;
+
+
+    /**
+     * Minimum contentsize to make compression.
+     */
+    protected int compressionMinSize = 2048;
+
+
+    /**
+     * Socket buffering.
+     */
+    protected int socketBuffer = -1;
+
+
+    /**
+     * Max saved post size.
+     */
+    protected int maxSavePostSize = 4 * 1024;
+
+
+    /**
+     * List of user agents to not use gzip with
+     */
+    protected Pattern noCompressionUserAgents[] = null;
+
+    /**
+     * List of MIMES which could be gzipped
+     */
+    protected String[] compressableMimeTypes =
+    { "text/html", "text/xml", "text/plain" };
+
+
+    /**
+     * Host name (used to avoid useless B2C conversion on the host name).
+     */
+    protected char[] hostNameC = new char[0];
+
+
+    /**
+     * Associated thread pool.
+     */
+    protected ThreadPool threadPool;
+
+
+    /**
+     * Associated endpoint.
+     */
+    protected PoolTcpEndpoint endpoint;
+
+
+    /**
+     * Allow a customized the server header for the tin-foil hat folks.
+     */
+    protected String server = null;
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * Return compression level.
+     */
+    public String getCompression() {
+        switch (compressionLevel) {
+        case 0:
+            return "off";
+        case 1:
+            return "on";
+        case 2:
+            return "force";
+        }
+        return "off";
+    }
+
+
+    /**
+     * Set compression level.
+     */
+    public void setCompression(String compression) {
+        if (compression.equals("on")) {
+            this.compressionLevel = 1;
+        } else if (compression.equals("force")) {
+            this.compressionLevel = 2;
+        } else if (compression.equals("off")) {
+            this.compressionLevel = 0;
+        } else {
+            try {
+                // Try to parse compression as an int, which would give the
+                // minimum compression size
+                compressionMinSize = Integer.parseInt(compression);
+                this.compressionLevel = 1;
+            } catch (Exception e) {
+                this.compressionLevel = 0;
+            }
+        }
+    }
+
+    /**
+     * Set Minimum size to trigger compression.
+     */
+    public void setCompressionMinSize(int compressionMinSize) {
+        this.compressionMinSize = compressionMinSize;
+    }
+
+
+    public void setThreadPool(ThreadPool threadPool) {
+        this.threadPool = threadPool;
+    }
+
+    
+    public void setEndpoint(PoolTcpEndpoint endpoint) {
+        this.endpoint = endpoint;
+    }
+
+
+    /**
+     * Add user-agent for which gzip compression didn't works
+     * The user agent String given will be exactly matched
+     * to the user-agent header submitted by the client.
+     *
+     * @param userAgent user-agent string
+     */
+    public void addNoCompressionUserAgent(String userAgent) {
+        try {
+            Pattern nRule = Pattern.compile(userAgent);
+            noCompressionUserAgents =
+                addREArray(noCompressionUserAgents, nRule);
+        } catch (PatternSyntaxException pse) {
+            log.error(sm.getString("http11processor.regexp.error", userAgent), pse);
+        }
+    }
+
+
+    /**
+     * Set no compression user agent list (this method is best when used with
+     * a large number of connectors, where it would be better to have all of
+     * them referenced a single array).
+     */
+    public void setNoCompressionUserAgents(Pattern[] noCompressionUserAgents) {
+        this.noCompressionUserAgents = noCompressionUserAgents;
+    }
+
+
+    /**
+     * Set no compression user agent list.
+     * List contains users agents separated by ',' :
+     *
+     * ie: "gorilla,desesplorer,tigrus"
+     */
+    public void setNoCompressionUserAgents(String noCompressionUserAgents) {
+        if (noCompressionUserAgents != null) {
+            StringTokenizer st = new StringTokenizer(noCompressionUserAgents, ",");
+
+            while (st.hasMoreTokens()) {
+                addNoCompressionUserAgent(st.nextToken().trim());
+            }
+        }
+    }
+
+    /**
+     * Add a mime-type which will be compressable
+     * The mime-type String will be exactly matched
+     * in the response mime-type header .
+     *
+     * @param mimeType mime-type string
+     */
+    public void addCompressableMimeType(String mimeType) {
+        compressableMimeTypes =
+            addStringArray(compressableMimeTypes, mimeType);
+    }
+
+
+    /**
+     * Set compressable mime-type list (this method is best when used with
+     * a large number of connectors, where it would be better to have all of
+     * them referenced a single array).
+     */
+    public void setCompressableMimeTypes(String[] compressableMimeTypes) {
+        this.compressableMimeTypes = compressableMimeTypes;
+    }
+
+
+    /**
+     * Set compressable mime-type list
+     * List contains users agents separated by ',' :
+     *
+     * ie: "text/html,text/xml,text/plain"
+     */
+    public void setCompressableMimeTypes(String compressableMimeTypes) {
+        if (compressableMimeTypes != null) {
+            StringTokenizer st = new StringTokenizer(compressableMimeTypes, ",");
+
+            while (st.hasMoreTokens()) {
+                addCompressableMimeType(st.nextToken().trim());
+            }
+        }
+    }
+
+
+    /**
+     * Return the list of restricted user agents.
+     */
+    public String[] findCompressableMimeTypes() {
+        return (compressableMimeTypes);
+    }
+
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Add input or output filter.
+     *
+     * @param className class name of the filter
+     */
+    protected void addFilter(String className) {
+        try {
+            Class clazz = Class.forName(className);
+            Object obj = clazz.newInstance();
+            if (obj instanceof InputFilter) {
+                inputBuffer.addFilter((InputFilter) obj);
+            } else if (obj instanceof OutputFilter) {
+                outputBuffer.addFilter((OutputFilter) obj);
+            } else {
+                log.warn(sm.getString("http11processor.filter.unknown", className));
+            }
+        } catch (Exception e) {
+            log.error(sm.getString("http11processor.filter.error", className), e);
+        }
+    }
+
+
+    /**
+     * General use method
+     *
+     * @param sArray the StringArray
+     * @param value string
+     */
+    private String[] addStringArray(String sArray[], String value) {
+        String[] result = null;
+        if (sArray == null) {
+            result = new String[1];
+            result[0] = value;
+        }
+        else {
+            result = new String[sArray.length + 1];
+            for (int i = 0; i < sArray.length; i++)
+                result[i] = sArray[i];
+            result[sArray.length] = value;
+        }
+        return result;
+    }
+
+
+    /**
+     * General use method
+     *
+     * @param rArray the REArray
+     * @param value Obj
+     */
+    private Pattern[] addREArray(Pattern rArray[], Pattern value) {
+        Pattern[] result = null;
+        if (rArray == null) {
+            result = new Pattern[1];
+            result[0] = value;
+        }
+        else {
+            result = new Pattern[rArray.length + 1];
+            for (int i = 0; i < rArray.length; i++)
+                result[i] = rArray[i];
+            result[rArray.length] = value;
+        }
+        return result;
+    }
+
+
+    /**
+     * General use method
+     *
+     * @param sArray the StringArray
+     * @param value string
+     */
+    private boolean inStringArray(String sArray[], String value) {
+        for (int i = 0; i < sArray.length; i++) {
+            if (sArray[i].equals(value)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+
+    /**
+     * Checks if any entry in the string array starts with the specified value
+     *
+     * @param sArray the StringArray
+     * @param value string
+     */
+    private boolean startsWithStringArray(String sArray[], String value) {
+        if (value == null)
+           return false;
+        for (int i = 0; i < sArray.length; i++) {
+            if (value.startsWith(sArray[i])) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+
+    /**
+     * Add restricted user-agent (which will downgrade the connector
+     * to HTTP/1.0 mode). The user agent String given will be matched
+     * via regexp to the user-agent header submitted by the client.
+     *
+     * @param userAgent user-agent string
+     */
+    public void addRestrictedUserAgent(String userAgent) {
+        try {
+            Pattern nRule = Pattern.compile(userAgent);
+            restrictedUserAgents = addREArray(restrictedUserAgents, nRule);
+        } catch (PatternSyntaxException pse) {
+            log.error(sm.getString("http11processor.regexp.error", userAgent), pse);
+        }
+    }
+
+
+    /**
+     * Set restricted user agent list (this method is best when used with
+     * a large number of connectors, where it would be better to have all of
+     * them referenced a single array).
+     */
+    public void setRestrictedUserAgents(Pattern[] restrictedUserAgents) {
+        this.restrictedUserAgents = restrictedUserAgents;
+    }
+
+
+    /**
+     * Set restricted user agent list (which will downgrade the connector
+     * to HTTP/1.0 mode). List contains users agents separated by ',' :
+     *
+     * ie: "gorilla,desesplorer,tigrus"
+     */
+    public void setRestrictedUserAgents(String restrictedUserAgents) {
+        if (restrictedUserAgents != null) {
+            StringTokenizer st =
+                new StringTokenizer(restrictedUserAgents, ",");
+            while (st.hasMoreTokens()) {
+                addRestrictedUserAgent(st.nextToken().trim());
+            }
+        }
+    }
+
+
+    /**
+     * Return the list of restricted user agents.
+     */
+    public String[] findRestrictedUserAgents() {
+        String[] sarr = new String [restrictedUserAgents.length];
+
+        for (int i = 0; i < restrictedUserAgents.length; i++)
+            sarr[i] = restrictedUserAgents[i].toString();
+
+        return (sarr);
+    }
+
+
+    /**
+     * Set the maximum number of Keep-Alive requests to honor.
+     * This is to safeguard from DoS attacks.  Setting to a negative
+     * value disables the check.
+     */
+    public void setMaxKeepAliveRequests(int mkar) {
+        maxKeepAliveRequests = mkar;
+    }
+
+
+    /**
+     * Return the number of Keep-Alive requests that we will honor.
+     */
+    public int getMaxKeepAliveRequests() {
+        return maxKeepAliveRequests;
+    }
+
+
+    /**
+     * Set the maximum size of a POST which will be buffered in SSL mode.
+     */
+    public void setMaxSavePostSize(int msps) {
+        maxSavePostSize = msps;
+    }
+
+
+    /**
+     * Return the maximum size of a POST which will be buffered in SSL mode.
+     */
+    public int getMaxSavePostSize() {
+        return maxSavePostSize;
+    }
+
+
+    /**
+     * Set the SSL information for this HTTP connection.
+     */
+    public void setSSLSupport(SSLSupport sslSupport) {
+        this.sslSupport = sslSupport;
+    }
+
+
+    /**
+     * Set the socket associated with this HTTP connection.
+     */
+    public void setSocket(Socket socket)
+        throws IOException {
+        this.socket = socket;
+    }
+
+    /**
+     * Set the flag to control upload time-outs.
+     */
+    public void setDisableUploadTimeout(boolean isDisabled) {
+        disableUploadTimeout = isDisabled;
+    }
+
+    /**
+     * Get the flag that controls upload time-outs.
+     */
+    public boolean getDisableUploadTimeout() {
+        return disableUploadTimeout;
+    }
+
+    /**
+     * Set the socket buffer flag.
+     */
+    public void setSocketBuffer(int socketBuffer) {
+        this.socketBuffer = socketBuffer;
+        outputBuffer.setSocketBuffer(socketBuffer);
+    }
+
+    /**
+     * Get the socket buffer flag.
+     */
+    public int getSocketBuffer() {
+        return socketBuffer;
+    }
+
+    /**
+     * Set the upload timeout.
+     */
+    public void setTimeout( int timeouts ) {
+        timeout = timeouts ;
+    }
+
+    /**
+     * Get the upload timeout.
+     */
+    public int getTimeout() {
+        return timeout;
+    }
+
+
+    /**
+     * Set the server header name.
+     */
+    public void setServer( String server ) {
+        if (server==null || server.equals("")) {
+            this.server = null;
+        } else {
+            this.server = server;
+        }
+    }
+
+    /**
+     * Get the server header name.
+     */
+    public String getServer() {
+        return server;
+    }
+
+
+    /** Get the request associated with this processor.
+     *
+     * @return The request
+     */
+    public Request getRequest() {
+        return request;
+    }
+
+    /**
+     * Process pipelined HTTP requests using the specified input and output
+     * streams.
+     *
+     * @param input stream from which the HTTP requests will be read
+     * @param output stream which will be used to output the HTTP
+     * responses
+     * @throws IOException error during an I/O operation
+     */
+    public void process(InputStream input, OutputStream output)
+        throws IOException {
+        ThreadWithAttributes thrA=
+                (ThreadWithAttributes)Thread.currentThread();
+        RequestInfo rp = request.getRequestProcessor();
+        thrA.setCurrentStage(threadPool, "parsing http request");
+        rp.setStage(org.apache.coyote.Constants.STAGE_PARSE);
+
+        // Set the remote address
+        remoteAddr = null;
+        remoteHost = null;
+        localAddr = null;
+        localName = null;
+        remotePort = -1;
+        localPort = -1;
+
+        // Setting up the I/O
+        inputBuffer.setInputStream(input);
+        outputBuffer.setOutputStream(output);
+
+        // Error flag
+        error = false;
+        keepAlive = true;
+
+        int keepAliveLeft = maxKeepAliveRequests;
+        int soTimeout = socket.getSoTimeout();
+        int oldSoTimeout = soTimeout;
+
+        int threadRatio = 0;
+        if (threadPool.getCurrentThreadsBusy() > 0) {
+            threadRatio = (threadPool.getCurrentThreadsBusy() * 100)
+                / threadPool.getMaxThreads();
+        } else {
+            threadRatio = (endpoint.getCurrentThreadsBusy() * 100)
+                / endpoint.getMaxThreads();
+        }
+        if ((threadRatio > 33) && (threadRatio <= 66)) {
+            soTimeout = soTimeout / 2;
+        } else if ((threadRatio > 66) && (threadRatio <= 90)) {
+            soTimeout = soTimeout / 3;
+            keepAliveLeft = 1;
+        } else if (threadRatio > 90) {
+            soTimeout = soTimeout / 20;
+            keepAliveLeft = 1;
+        }
+        
+        if (soTimeout != oldSoTimeout) {
+            try {
+                socket.setSoTimeout(soTimeout);
+            } catch (Throwable t) {
+                log.debug(sm.getString("http11processor.socket.timeout"), t);
+                error = true;
+            }
+        }
+
+        boolean keptAlive = false;
+
+        while (started && !error && keepAlive) {
+
+            // Parsing the request header
+            try {
+                if( !disableUploadTimeout && keptAlive && soTimeout > 0 ) {
+                    socket.setSoTimeout(soTimeout);
+                }
+                inputBuffer.parseRequestLine();
+                request.setStartTime(System.currentTimeMillis());
+                thrA.setParam( threadPool, request.requestURI() );
+                keptAlive = true;
+                if (!disableUploadTimeout) {
+                    socket.setSoTimeout(timeout);
+                }
+                inputBuffer.parseHeaders();
+            } catch (IOException e) {
+                error = true;
+                break;
+            } catch (Throwable t) {
+                if (log.isDebugEnabled()) {
+                    log.debug(sm.getString("http11processor.header.parse"), t);
+                }
+                // 400 - Bad Request
+                response.setStatus(400);
+                error = true;
+            }
+
+            // Setting up filters, and parse some request headers
+            thrA.setCurrentStage(threadPool, "prepareRequest");
+            rp.setStage(org.apache.coyote.Constants.STAGE_PREPARE);
+            try {
+                prepareRequest();
+            } catch (Throwable t) {
+                if (log.isDebugEnabled()) {
+                    log.debug(sm.getString("http11processor.request.prepare"), t);
+                }
+                // 400 - Internal Server Error
+                response.setStatus(400);
+                error = true;
+            }
+
+            if (maxKeepAliveRequests > 0 && --keepAliveLeft == 0)
+                keepAlive = false;
+
+            // Process the request in the adapter
+            if (!error) {
+                try {
+                    thrA.setCurrentStage(threadPool, "service");
+                    rp.setStage(org.apache.coyote.Constants.STAGE_SERVICE);
+                    adapter.service(request, response);
+                    // Handle when the response was committed before a serious
+                    // error occurred.  Throwing a ServletException should both
+                    // set the status to 500 and set the errorException.
+                    // If we fail here, then the response is likely already
+                    // committed, so we can't try and set headers.
+                    if(keepAlive && !error) { // Avoid checking twice.
+                        error = response.getErrorException() != null ||
+                                statusDropsConnection(response.getStatus());
+                    }
+
+                } catch (InterruptedIOException e) {
+                    error = true;
+                } catch (Throwable t) {
+                    log.error(sm.getString("http11processor.request.process"), t);
+                    // 500 - Internal Server Error
+                    response.setStatus(500);
+                    error = true;
+                }
+            }
+
+            // Finish the handling of the request
+            try {
+                thrA.setCurrentStage(threadPool, "endRequestIB");
+                rp.setStage(org.apache.coyote.Constants.STAGE_ENDINPUT);
+                inputBuffer.endRequest();
+            } catch (IOException e) {
+                error = true;
+            } catch (Throwable t) {
+                log.error(sm.getString("http11processor.request.finish"), t);
+                // 500 - Internal Server Error
+                response.setStatus(500);
+                error = true;
+            }
+            try {
+                thrA.setCurrentStage(threadPool, "endRequestOB");
+                rp.setStage(org.apache.coyote.Constants.STAGE_ENDOUTPUT);
+                outputBuffer.endRequest();
+            } catch (IOException e) {
+                error = true;
+            } catch (Throwable t) {
+                log.error(sm.getString("http11processor.response.finish"), t);
+                error = true;
+            }
+
+            // If there was an error, make sure the request is counted as
+            // and error, and update the statistics counter
+            if (error) {
+                response.setStatus(500);
+            }
+            request.updateCounters();
+
+            thrA.setCurrentStage(threadPool, "ended");
+            rp.setStage(org.apache.coyote.Constants.STAGE_KEEPALIVE);
+
+            // Don't reset the param - we'll see it as ended. Next request
+            // will reset it
+            // thrA.setParam(null);
+            // Next request
+            inputBuffer.nextRequest();
+            outputBuffer.nextRequest();
+
+        }
+
+        rp.setStage(org.apache.coyote.Constants.STAGE_ENDED);
+
+        // Recycle
+        inputBuffer.recycle();
+        outputBuffer.recycle();
+
+        // Recycle ssl info
+        sslSupport = null;
+    }
+
+
+    // ----------------------------------------------------- ActionHook Methods
+
+
+    /**
+     * Send an action to the connector.
+     *
+     * @param actionCode Type of the action
+     * @param param Action parameter
+     */
+    public void action(ActionCode actionCode, Object param) {
+
+        if (actionCode == ActionCode.ACTION_COMMIT) {
+            // Commit current response
+
+            if (response.isCommitted())
+                return;
+
+            // Validate and write response headers
+            prepareResponse();
+            try {
+                outputBuffer.commit();
+            } catch (IOException e) {
+                // Set error flag
+                error = true;
+            }
+
+        } else if (actionCode == ActionCode.ACTION_ACK) {
+
+            // Acknowlege request
+
+            // Send a 100 status back if it makes sense (response not committed
+            // yet, and client specified an expectation for 100-continue)
+
+            if ((response.isCommitted()) || !expectation)
+                return;
+
+            inputBuffer.setSwallowInput(true);
+            try {
+                outputBuffer.sendAck();
+            } catch (IOException e) {
+                // Set error flag
+                error = true;
+            }
+
+        } else if (actionCode == ActionCode.ACTION_CLIENT_FLUSH) {
+
+            try {
+                outputBuffer.flush();
+            } catch (IOException e) {
+                // Set error flag
+                error = true;
+                response.setErrorException(e);
+            }
+
+        } else if (actionCode == ActionCode.ACTION_CLOSE) {
+            // Close
+
+            // End the processing of the current request, and stop any further
+            // transactions with the client
+
+            try {
+                outputBuffer.endRequest();
+            } catch (IOException e) {
+                // Set error flag
+                error = true;
+            }
+
+        } else if (actionCode == ActionCode.ACTION_RESET) {
+
+            // Reset response
+
+            // Note: This must be called before the response is committed
+
+            outputBuffer.reset();
+
+        } else if (actionCode == ActionCode.ACTION_CUSTOM) {
+
+            // Do nothing
+
+        } else if (actionCode == ActionCode.ACTION_START) {
+
+            started = true;
+
+        } else if (actionCode == ActionCode.ACTION_STOP) {
+
+            started = false;
+
+        } else if (actionCode == ActionCode.ACTION_REQ_SSL_ATTRIBUTE ) {
+
+            try {
+                if (sslSupport != null) {
+                    Object sslO = sslSupport.getCipherSuite();
+                    if (sslO != null)
+                        request.setAttribute
+                            (SSLSupport.CIPHER_SUITE_KEY, sslO);
+                    sslO = sslSupport.getPeerCertificateChain(false);
+                    if (sslO != null)
+                        request.setAttribute
+                            (SSLSupport.CERTIFICATE_KEY, sslO);
+                    sslO = sslSupport.getKeySize();
+                    if (sslO != null)
+                        request.setAttribute
+                            (SSLSupport.KEY_SIZE_KEY, sslO);
+                    sslO = sslSupport.getSessionId();
+                    if (sslO != null)
+                        request.setAttribute
+                            (SSLSupport.SESSION_ID_KEY, sslO);
+                }
+            } catch (Exception e) {
+                log.warn(sm.getString("http11processor.socket.ssl"), e);
+            }
+
+        } else if (actionCode == ActionCode.ACTION_REQ_HOST_ADDR_ATTRIBUTE) {
+
+            if ((remoteAddr == null) && (socket != null)) {
+                InetAddress inetAddr = socket.getInetAddress();
+                if (inetAddr != null) {
+                    remoteAddr = inetAddr.getHostAddress();
+                }
+            }
+            request.remoteAddr().setString(remoteAddr);
+
+        } else if (actionCode == ActionCode.ACTION_REQ_LOCAL_NAME_ATTRIBUTE) {
+
+            if ((localName == null) && (socket != null)) {
+                InetAddress inetAddr = socket.getLocalAddress();
+                if (inetAddr != null) {
+                    localName = inetAddr.getHostName();
+                }
+            }
+            request.localName().setString(localName);
+
+        } else if (actionCode == ActionCode.ACTION_REQ_HOST_ATTRIBUTE) {
+
+            if ((remoteHost == null) && (socket != null)) {
+                InetAddress inetAddr = socket.getInetAddress();
+                if (inetAddr != null) {
+                    remoteHost = inetAddr.getHostName();
+                }
+                if(remoteHost == null) {
+                    if(remoteAddr != null) {
+                        remoteHost = remoteAddr;
+                    } else { // all we can do is punt
+                        request.remoteHost().recycle();
+                    }
+                }
+            }
+            request.remoteHost().setString(remoteHost);
+
+        } else if (actionCode == ActionCode.ACTION_REQ_LOCAL_ADDR_ATTRIBUTE) {
+
+            if (localAddr == null)
+               localAddr = socket.getLocalAddress().getHostAddress();
+
+            request.localAddr().setString(localAddr);
+
+        } else if (actionCode == ActionCode.ACTION_REQ_REMOTEPORT_ATTRIBUTE) {
+
+            if ((remotePort == -1 ) && (socket !=null)) {
+                remotePort = socket.getPort();
+            }
+            request.setRemotePort(remotePort);
+
+        } else if (actionCode == ActionCode.ACTION_REQ_LOCALPORT_ATTRIBUTE) {
+
+            if ((localPort == -1 ) && (socket !=null)) {
+                localPort = socket.getLocalPort();
+            }
+            request.setLocalPort(localPort);
+
+        } else if (actionCode == ActionCode.ACTION_REQ_SSL_CERTIFICATE) {
+            if( sslSupport != null) {
+                /*
+                 * Consume and buffer the request body, so that it does not
+                 * interfere with the client's handshake messages
+                 */
+                InputFilter[] inputFilters = inputBuffer.getFilters();
+                ((BufferedInputFilter) inputFilters[Constants.BUFFERED_FILTER])
+                    .setLimit(maxSavePostSize);
+                inputBuffer.addActiveFilter
+                    (inputFilters[Constants.BUFFERED_FILTER]);
+                try {
+                    Object sslO = sslSupport.getPeerCertificateChain(true);
+                    if( sslO != null) {
+                        request.setAttribute
+                            (SSLSupport.CERTIFICATE_KEY, sslO);
+                    }
+                } catch (Exception e) {
+                    log.warn(sm.getString("http11processor.socket.ssl"), e);
+                }
+            }
+        } else if (actionCode == ActionCode.ACTION_REQ_SET_BODY_REPLAY) {
+            ByteChunk body = (ByteChunk) param;
+            
+            InputFilter savedBody = new SavedRequestInputFilter(body);
+            savedBody.setRequest(request);
+
+            InternalInputBuffer internalBuffer = (InternalInputBuffer)
+                request.getInputBuffer();
+            internalBuffer.addActiveFilter(savedBody);
+        }
+
+    }
+
+
+    // ------------------------------------------------------ Connector Methods
+
+
+    /**
+     * Set the associated adapter.
+     *
+     * @param adapter the new adapter
+     */
+    public void setAdapter(Adapter adapter) {
+        this.adapter = adapter;
+    }
+
+
+    /**
+     * Get the associated adapter.
+     *
+     * @return the associated adapter
+     */
+    public Adapter getAdapter() {
+        return adapter;
+    }
+
+
+    // ------------------------------------------------------ Protected Methods
+
+
+    /**
+     * After reading the request headers, we have to setup the request filters.
+     */
+    protected void prepareRequest() {
+
+        http11 = true;
+        http09 = false;
+        contentDelimitation = false;
+        expectation = false;
+        if (sslSupport != null) {
+            request.scheme().setString("https");
+        }
+        MessageBytes protocolMB = request.protocol();
+        if (protocolMB.equals(Constants.HTTP_11)) {
+            http11 = true;
+            protocolMB.setString(Constants.HTTP_11);
+        } else if (protocolMB.equals(Constants.HTTP_10)) {
+            http11 = false;
+            keepAlive = false;
+            protocolMB.setString(Constants.HTTP_10);
+        } else if (protocolMB.equals("")) {
+            // HTTP/0.9
+            http09 = true;
+            http11 = false;
+            keepAlive = false;
+        } else {
+            // Unsupported protocol
+            http11 = false;
+            error = true;
+            // Send 505; Unsupported HTTP version
+            response.setStatus(505);
+        }
+
+        MessageBytes methodMB = request.method();
+        if (methodMB.equals(Constants.GET)) {
+            methodMB.setString(Constants.GET);
+        } else if (methodMB.equals(Constants.POST)) {
+            methodMB.setString(Constants.POST);
+        }
+
+        MimeHeaders headers = request.getMimeHeaders();
+
+        // Check connection header
+        MessageBytes connectionValueMB = headers.getValue("connection");
+        if (connectionValueMB != null) {
+            ByteChunk connectionValueBC = connectionValueMB.getByteChunk();
+            if (findBytes(connectionValueBC, Constants.CLOSE_BYTES) != -1) {
+                keepAlive = false;
+            } else if (findBytes(connectionValueBC,
+                                 Constants.KEEPALIVE_BYTES) != -1) {
+                keepAlive = true;
+            }
+        }
+
+        MessageBytes expectMB = null;
+        if (http11)
+            expectMB = headers.getValue("expect");
+        if ((expectMB != null)
+            && (expectMB.indexOfIgnoreCase("100-continue", 0) != -1)) {
+            inputBuffer.setSwallowInput(false);
+            expectation = true;
+        }
+
+        // Check user-agent header
+        if ((restrictedUserAgents != null) && ((http11) || (keepAlive))) {
+            MessageBytes userAgentValueMB = headers.getValue("user-agent");
+            // Check in the restricted list, and adjust the http11
+            // and keepAlive flags accordingly
+            if(userAgentValueMB != null) {
+                String userAgentValue = userAgentValueMB.toString();
+                for (int i = 0; i < restrictedUserAgents.length; i++) {
+                    if (restrictedUserAgents[i].matcher(userAgentValue).matches()) {
+                        http11 = false;
+                        keepAlive = false;
+                        break;
+                    }
+                }
+            }
+        }
+
+        // Check for a full URI (including protocol://host:port/)
+        ByteChunk uriBC = request.requestURI().getByteChunk();
+        if (uriBC.startsWithIgnoreCase("http", 0)) {
+
+            int pos = uriBC.indexOf("://", 0, 3, 4);
+            int uriBCStart = uriBC.getStart();
+            int slashPos = -1;
+            if (pos != -1) {
+                byte[] uriB = uriBC.getBytes();
+                slashPos = uriBC.indexOf('/', pos + 3);
+                if (slashPos == -1) {
+                    slashPos = uriBC.getLength();
+                    // Set URI as "/"
+                    request.requestURI().setBytes
+                        (uriB, uriBCStart + pos + 1, 1);
+                } else {
+                    request.requestURI().setBytes
+                        (uriB, uriBCStart + slashPos,
+                         uriBC.getLength() - slashPos);
+                }
+                MessageBytes hostMB = headers.setValue("host");
+                hostMB.setBytes(uriB, uriBCStart + pos + 3,
+                                slashPos - pos - 3);
+            }
+
+        }
+
+        // Input filter setup
+        InputFilter[] inputFilters = inputBuffer.getFilters();
+
+        // Parse transfer-encoding header
+        MessageBytes transferEncodingValueMB = null;
+        if (http11)
+            transferEncodingValueMB = headers.getValue("transfer-encoding");
+        if (transferEncodingValueMB != null) {
+            String transferEncodingValue = transferEncodingValueMB.toString();
+            // Parse the comma separated list. "identity" codings are ignored
+            int startPos = 0;
+            int commaPos = transferEncodingValue.indexOf(',');
+            String encodingName = null;
+            while (commaPos != -1) {
+                encodingName = transferEncodingValue.substring
+                    (startPos, commaPos).toLowerCase().trim();
+                if (!addInputFilter(inputFilters, encodingName)) {
+                    // Unsupported transfer encoding
+                    error = true;
+                    // 501 - Unimplemented
+                    response.setStatus(501);
+                }
+                startPos = commaPos + 1;
+                commaPos = transferEncodingValue.indexOf(',', startPos);
+            }
+            encodingName = transferEncodingValue.substring(startPos)
+                .toLowerCase().trim();
+            if (!addInputFilter(inputFilters, encodingName)) {
+                // Unsupported transfer encoding
+                error = true;
+                // 501 - Unimplemented
+                response.setStatus(501);
+            }
+        }
+
+        // Parse content-length header
+        long contentLength = request.getContentLengthLong();
+        if (contentLength >= 0 && !contentDelimitation) {
+            inputBuffer.addActiveFilter
+                (inputFilters[Constants.IDENTITY_FILTER]);
+            contentDelimitation = true;
+        }
+
+        MessageBytes valueMB = headers.getValue("host");
+
+        // Check host header
+        if (http11 && (valueMB == null)) {
+            error = true;
+            // 400 - Bad request
+            response.setStatus(400);
+        }
+
+        parseHost(valueMB);
+
+        if (!contentDelimitation) {
+            // If there's no content length 
+            // (broken HTTP/1.0 or HTTP/1.1), assume
+            // the client is not broken and didn't send a body
+            inputBuffer.addActiveFilter
+                    (inputFilters[Constants.VOID_FILTER]);
+            contentDelimitation = true;
+        }
+
+    }
+
+
+    /**
+     * Parse host.
+     */
+    public void parseHost(MessageBytes valueMB) {
+
+        if (valueMB == null || valueMB.isNull()) {
+            // HTTP/1.0
+            // Default is what the socket tells us. Overriden if a host is
+            // found/parsed
+            request.setServerPort(socket.getLocalPort());
+            InetAddress localAddress = socket.getLocalAddress();
+            // Setting the socket-related fields. The adapter doesn't know
+            // about socket.
+            request.serverName().setString(localAddress.getHostName());
+            return;
+        }
+
+        ByteChunk valueBC = valueMB.getByteChunk();
+        byte[] valueB = valueBC.getBytes();
+        int valueL = valueBC.getLength();
+        int valueS = valueBC.getStart();
+        int colonPos = -1;
+        if (hostNameC.length < valueL) {
+            hostNameC = new char[valueL];
+        }
+
+        boolean ipv6 = (valueB[valueS] == '[');
+        boolean bracketClosed = false;
+        for (int i = 0; i < valueL; i++) {
+            char b = (char) valueB[i + valueS];
+            hostNameC[i] = b;
+            if (b == ']') {
+                bracketClosed = true;
+            } else if (b == ':') {
+                if (!ipv6 || bracketClosed) {
+                    colonPos = i;
+                    break;
+                }
+            }
+        }
+
+        if (colonPos < 0) {
+            if (sslSupport == null) {
+                // 80 - Default HTTP port
+                request.setServerPort(80);
+            } else {
+                // 443 - Default HTTPS port
+                request.setServerPort(443);
+            }
+            request.serverName().setChars(hostNameC, 0, valueL);
+        } else {
+
+            request.serverName().setChars(hostNameC, 0, colonPos);
+
+            int port = 0;
+            int mult = 1;
+            for (int i = valueL - 1; i > colonPos; i--) {
+                int charValue = HexUtils.DEC[(int) valueB[i + valueS]];
+                if (charValue == -1) {
+                    // Invalid character
+                    error = true;
+                    // 400 - Bad request
+                    response.setStatus(400);
+                    break;
+                }
+                port = port + (charValue * mult);
+                mult = 10 * mult;
+            }
+            request.setServerPort(port);
+
+        }
+
+    }
+
+
+    /**
+     * Check for compression
+     */
+    private boolean isCompressable() {
+
+        // Nope Compression could works in HTTP 1.0 also
+        // cf: mod_deflate
+
+        // Compression only since HTTP 1.1
+        // if (! http11)
+        //    return false;
+
+        // Check if browser support gzip encoding
+        MessageBytes acceptEncodingMB =
+            request.getMimeHeaders().getValue("accept-encoding");
+
+        if ((acceptEncodingMB == null)
+            || (acceptEncodingMB.indexOf("gzip") == -1))
+            return false;
+
+        // Check if content is not allready gzipped
+        MessageBytes contentEncodingMB =
+            response.getMimeHeaders().getValue("Content-Encoding");
+
+        if ((contentEncodingMB != null)
+            && (contentEncodingMB.indexOf("gzip") != -1))
+            return false;
+
+        // If force mode, allways compress (test purposes only)
+        if (compressionLevel == 2)
+           return true;
+
+        // Check for incompatible Browser
+        if (noCompressionUserAgents != null) {
+            MessageBytes userAgentValueMB =
+                request.getMimeHeaders().getValue("user-agent");
+            if(userAgentValueMB != null) {
+                String userAgentValue = userAgentValueMB.toString();
+
+                // If one Regexp rule match, disable compression
+                for (int i = 0; i < noCompressionUserAgents.length; i++)
+                    if (noCompressionUserAgents[i].matcher(userAgentValue).matches())
+                        return false;
+            }
+        }
+
+        // Check if suffisant len to trig the compression
+        long contentLength = response.getContentLengthLong();
+        if ((contentLength == -1)
+            || (contentLength > compressionMinSize)) {
+            // Check for compatible MIME-TYPE
+            if (compressableMimeTypes != null) {
+                return (startsWithStringArray(compressableMimeTypes,
+                                              response.getContentType()));
+            }
+        }
+
+        return false;
+    }
+
+
+    /**
+     * When committing the response, we have to validate the set of headers, as
+     * well as setup the response filters.
+     */
+    protected void prepareResponse() {
+
+        boolean entityBody = true;
+        contentDelimitation = false;
+
+        OutputFilter[] outputFilters = outputBuffer.getFilters();
+
+        if (http09 == true) {
+            // HTTP/0.9
+            outputBuffer.addActiveFilter
+                (outputFilters[Constants.IDENTITY_FILTER]);
+            return;
+        }
+
+        int statusCode = response.getStatus();
+        if ((statusCode == 204) || (statusCode == 205)
+            || (statusCode == 304)) {
+            // No entity body
+            outputBuffer.addActiveFilter
+                (outputFilters[Constants.VOID_FILTER]);
+            entityBody = false;
+            contentDelimitation = true;
+        }
+
+        MessageBytes methodMB = request.method();
+        if (methodMB.equals("HEAD")) {
+            // No entity body
+            outputBuffer.addActiveFilter
+                (outputFilters[Constants.VOID_FILTER]);
+            contentDelimitation = true;
+        }
+
+        // Check for compression
+        boolean useCompression = false;
+        if (entityBody && (compressionLevel > 0)) {
+            useCompression = isCompressable();
+
+            // Change content-length to -1 to force chunking
+            if (useCompression) {
+                response.setContentLength(-1);
+            }
+        }
+
+        MimeHeaders headers = response.getMimeHeaders();
+        if (!entityBody) {
+            response.setContentLength(-1);
+        } else {
+            String contentType = response.getContentType();
+            if (contentType != null) {
+                headers.setValue("Content-Type").setString(contentType);
+            }
+            String contentLanguage = response.getContentLanguage();
+            if (contentLanguage != null) {
+                headers.setValue("Content-Language")
+                    .setString(contentLanguage);
+            }
+        }
+
+        long contentLength = response.getContentLengthLong();
+        if (contentLength != -1) {
+            headers.setValue("Content-Length").setLong(contentLength);
+            outputBuffer.addActiveFilter
+                (outputFilters[Constants.IDENTITY_FILTER]);
+            contentDelimitation = true;
+        } else {
+            if (entityBody && http11 && keepAlive) {
+                outputBuffer.addActiveFilter
+                    (outputFilters[Constants.CHUNKED_FILTER]);
+                contentDelimitation = true;
+                headers.addValue(Constants.TRANSFERENCODING).setString(Constants.CHUNKED);
+            } else {
+                outputBuffer.addActiveFilter
+                    (outputFilters[Constants.IDENTITY_FILTER]);
+            }
+        }
+
+        if (useCompression) {
+            outputBuffer.addActiveFilter(outputFilters[Constants.GZIP_FILTER]);
+            headers.setValue("Content-Encoding").setString("gzip");
+            // Make Proxies happy via Vary (from mod_deflate)
+            headers.setValue("Vary").setString("Accept-Encoding");
+        }
+
+        // Add date header
+        String date = null;
+        if (System.getSecurityManager() != null){
+            date = (String)AccessController.doPrivileged(
+                    new PrivilegedAction() {
+                        public Object run(){
+                            return FastHttpDateFormat.getCurrentDate();
+                        }
+                    }
+            );
+        } else {
+            date = FastHttpDateFormat.getCurrentDate();
+        }
+        headers.setValue("Date").setString(date);
+
+        // FIXME: Add transfer encoding header
+
+        if ((entityBody) && (!contentDelimitation)) {
+            // Mark as close the connection after the request, and add the
+            // connection: close header
+            keepAlive = false;
+        }
+
+        // If we know that the request is bad this early, add the
+        // Connection: close header.
+        keepAlive = keepAlive && !statusDropsConnection(statusCode);
+        if (!keepAlive) {
+            headers.addValue(Constants.CONNECTION).setString(Constants.CLOSE);
+        } else if (!http11 && !error) {
+            headers.addValue(Constants.CONNECTION).setString(Constants.KEEPALIVE);
+        }
+
+        // Build the response header
+        outputBuffer.sendStatus();
+
+        // Add server header
+        if (server != null) {
+            headers.setValue("Server").setString(server);
+        } else {
+            outputBuffer.write(Constants.SERVER_BYTES);
+        }
+
+        int size = headers.size();
+        for (int i = 0; i < size; i++) {
+            outputBuffer.sendHeader(headers.getName(i), headers.getValue(i));
+        }
+        outputBuffer.endHeaders();
+
+    }
+
+
+    /**
+     * Initialize standard input and output filters.
+     */
+    protected void initializeFilters() {
+
+        // Create and add the identity filters.
+        inputBuffer.addFilter(new IdentityInputFilter());
+        outputBuffer.addFilter(new IdentityOutputFilter());
+
+        // Create and add the chunked filters.
+        inputBuffer.addFilter(new ChunkedInputFilter());
+        outputBuffer.addFilter(new ChunkedOutputFilter());
+
+        // Create and add the void filters.
+        inputBuffer.addFilter(new VoidInputFilter());
+        outputBuffer.addFilter(new VoidOutputFilter());
+
+        // Create and add buffered input filter
+        inputBuffer.addFilter(new BufferedInputFilter());
+
+        // Create and add the chunked filters.
+        //inputBuffer.addFilter(new GzipInputFilter());
+        outputBuffer.addFilter(new GzipOutputFilter());
+
+    }
+
+
+    /**
+     * Add an input filter to the current request.
+     *
+     * @return false if the encoding was not found (which would mean it is
+     * unsupported)
+     */
+    protected boolean addInputFilter(InputFilter[] inputFilters,
+                                     String encodingName) {
+        if (encodingName.equals("identity")) {
+            // Skip
+        } else if (encodingName.equals("chunked")) {
+            inputBuffer.addActiveFilter
+                (inputFilters[Constants.CHUNKED_FILTER]);
+            contentDelimitation = true;
+        } else {
+            for (int i = 2; i < inputFilters.length; i++) {
+                if (inputFilters[i].getEncodingName()
+                    .toString().equals(encodingName)) {
+                    inputBuffer.addActiveFilter(inputFilters[i]);
+                    return true;
+                }
+            }
+            return false;
+        }
+        return true;
+    }
+
+
+    /**
+     * Specialized utility method: find a sequence of lower case bytes inside
+     * a ByteChunk.
+     */
+    protected int findBytes(ByteChunk bc, byte[] b) {
+
+        byte first = b[0];
+        byte[] buff = bc.getBuffer();
+        int start = bc.getStart();
+        int end = bc.getEnd();
+
+    // Look for first char
+    int srcEnd = b.length;
+
+    for (int i = start; i <= (end - srcEnd); i++) {
+        if (Ascii.toLower(buff[i]) != first) continue;
+        // found first char, now look for a match
+            int myPos = i+1;
+        for (int srcPos = 1; srcPos < srcEnd; ) {
+                if (Ascii.toLower(buff[myPos++]) != b[srcPos++])
+            break;
+                if (srcPos == srcEnd) return i - start; // found it
+        }
+    }
+    return -1;
+
+    }
+
+    /**
+     * Determine if we must drop the connection because of the HTTP status
+     * code.  Use the same list of codes as Apache/httpd.
+     */
+    protected boolean statusDropsConnection(int status) {
+        return status == 400 /* SC_BAD_REQUEST */ ||
+               status == 408 /* SC_REQUEST_TIMEOUT */ ||
+               status == 411 /* SC_LENGTH_REQUIRED */ ||
+               status == 413 /* SC_REQUEST_ENTITY_TOO_LARGE */ ||
+               status == 414 /* SC_REQUEST_URI_TOO_LARGE */ ||
+               status == 500 /* SC_INTERNAL_SERVER_ERROR */ ||
+               status == 503 /* SC_SERVICE_UNAVAILABLE */ ||
+               status == 501 /* SC_NOT_IMPLEMENTED */;
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/http11/src/java/org/apache/coyote/http11/Http11Protocol.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/http11/src/java/org/apache/coyote/http11/Http11Protocol.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/http11/src/java/org/apache/coyote/http11/Http11Protocol.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,190 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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;
+
+import javax.management.MBeanRegistration;
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+
+import org.apache.commons.modeler.Registry;
+import org.apache.coyote.RequestInfo;
+import org.apache.tomcat.util.threads.ThreadPool;
+import org.apache.tomcat.util.threads.ThreadWithAttributes;
+
+
+/**
+ * Abstract the protocol implementation, including threading, etc.
+ * Processor is single threaded and specific to stream-based protocols,
+ * will not fit Jk protocols like JNI.
+ *
+ * @author Remy Maucherat
+ * @author Costin Manolache
+ */
+public class Http11Protocol extends Http11BaseProtocol implements MBeanRegistration
+{
+    public Http11Protocol() {
+    }
+    
+    protected Http11ConnectionHandler createConnectionHandler() {
+        return new JmxHttp11ConnectionHandler( this ) ;
+    }
+
+    ObjectName tpOname;
+    ObjectName rgOname;
+
+    public void start() throws Exception {
+        if( this.domain != null ) {
+            try {
+                // XXX We should be able to configure it separately
+                // XXX It should be possible to use a single TP
+                tpOname=new ObjectName
+                    (domain + ":" + "type=ThreadPool,name=" + getName());
+                if ("ms".equals(getStrategy())) {
+                    Registry.getRegistry(null, null)
+                        .registerComponent(ep, tpOname, null );
+                } else {
+                    Registry.getRegistry(null, null)
+                        .registerComponent(tp, tpOname, null );
+                }
+                tp.setName(getName());
+                tp.setDaemon(false);
+                tp.addThreadPoolListener(new MXPoolListener(this, tp));
+            } catch (Exception e) {
+                log.error("Can't register threadpool" );
+            }
+            rgOname=new ObjectName
+                (domain + ":type=GlobalRequestProcessor,name=" + getName());
+            Registry.getRegistry(null, null).registerComponent
+                ( cHandler.global, rgOname, null );
+        }
+
+        super.start();
+    }
+
+    public void destroy() throws Exception {
+        super.destroy();
+        if( tpOname!=null )
+            Registry.getRegistry(null, null).unregisterComponent(tpOname);
+        if( rgOname != null )
+            Registry.getRegistry(null, null).unregisterComponent(rgOname);
+    }
+
+    // --------------------  Connection handler --------------------
+
+    static class MXPoolListener implements ThreadPool.ThreadPoolListener {
+        MXPoolListener( Http11Protocol proto, ThreadPool control ) {
+
+        }
+
+        public void threadStart(ThreadPool tp, Thread t) {
+        }
+
+        public void threadEnd(ThreadPool tp, Thread t) {
+            // Register our associated processor
+            // TP uses only TWA
+            ThreadWithAttributes ta=(ThreadWithAttributes)t;
+            Object tpData[]=ta.getThreadData(tp);
+            if( tpData==null ) return;
+            // Weird artifact - it should be cleaned up, but that may break something
+            // and it won't gain us too much
+            if( tpData[1] instanceof Object[] ) {
+                tpData=(Object [])tpData[1];
+            }
+            ObjectName oname=(ObjectName)tpData[Http11BaseProtocol.THREAD_DATA_OBJECT_NAME];
+            if( oname==null ) return;
+            Registry.getRegistry(null, null).unregisterComponent(oname);
+            Http11Processor processor =
+                (Http11Processor) tpData[Http11Protocol.THREAD_DATA_PROCESSOR];
+            RequestInfo rp=processor.getRequest().getRequestProcessor();
+            rp.setGlobalProcessor(null);
+        }
+    }
+
+    static class JmxHttp11ConnectionHandler extends Http11ConnectionHandler  {
+        Http11Protocol proto;
+        static int count=0;
+
+        JmxHttp11ConnectionHandler( Http11Protocol proto ) {
+            super(proto);
+            this.proto = proto ;
+        }
+
+        public void setAttribute( String name, Object value ) {
+        }
+
+        public void setServer( Object o ) {
+        }
+
+        public Object[] init() {
+
+            Object thData[]=super.init();
+
+            // was set up by supper
+            Http11Processor  processor = (Http11Processor)
+                    thData[ Http11BaseProtocol.THREAD_DATA_PROCESSOR];
+
+            if( proto.getDomain() != null ) {
+                try {
+                    RequestInfo rp=processor.getRequest().getRequestProcessor();
+                    rp.setGlobalProcessor(global);
+                    ObjectName rpName=new ObjectName
+                        (proto.getDomain() + ":type=RequestProcessor,worker="
+                         + proto.getName() +",name=HttpRequest" + count++ );
+                    Registry.getRegistry(null, null).registerComponent( rp, rpName, null);
+                    thData[Http11BaseProtocol.THREAD_DATA_OBJECT_NAME]=rpName;
+                } catch( Exception ex ) {
+                    log.warn("Error registering request");
+                }
+            }
+
+            return  thData;
+        }
+    }
+
+    // -------------------- Various implementation classes --------------------
+
+
+    protected String domain;
+    protected ObjectName oname;
+    protected MBeanServer mserver;
+
+    public ObjectName getObjectName() {
+        return oname;
+    }
+
+    public String getDomain() {
+        return domain;
+    }
+
+    public ObjectName preRegister(MBeanServer server,
+                                  ObjectName name) throws Exception {
+        oname=name;
+        mserver=server;
+        domain=name.getDomain();
+        return name;
+    }
+
+    public void postRegister(Boolean registrationDone) {
+    }
+
+    public void preDeregister() throws Exception {
+    }
+
+    public void postDeregister() {
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/http11/src/java/org/apache/coyote/http11/InputFilter.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/http11/src/java/org/apache/coyote/http11/InputFilter.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/http11/src/java/org/apache/coyote/http11/InputFilter.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,81 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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;
+
+import java.io.IOException;
+
+import org.apache.tomcat.util.buf.ByteChunk;
+
+import org.apache.coyote.InputBuffer;
+import org.apache.coyote.Request;
+
+/**
+ * Input filter interface.
+ * 
+ * @author Remy Maucherat
+ */
+public interface InputFilter extends InputBuffer {
+
+
+    /**
+     * Read bytes.
+     * 
+     * @return Number of bytes read.
+     */
+    public int doRead(ByteChunk chunk, Request unused)
+        throws IOException;
+
+
+    /**
+     * Some filters need additional parameters from the request. All the 
+     * necessary reading can occur in that method, as this method is called
+     * after the request header processing is complete.
+     */
+    public void setRequest(Request request);
+
+
+    /**
+     * Make the filter ready to process the next request.
+     */
+    public void recycle();
+
+
+    /**
+     * Get the name of the encoding handled by this filter.
+     */
+    public ByteChunk getEncodingName();
+
+
+    /**
+     * Set the next buffer in the filter pipeline.
+     */
+    public void setBuffer(InputBuffer buffer);
+
+
+    /**
+     * End the current request.
+     * 
+     * @return 0 is the expected return value. A positive value indicates that
+     * too many bytes were read. This method is allowed to use buffer.doRead
+     * to consume extra bytes. The result of this method can't be negative (if
+     * an error happens, an IOException should be thrown instead).
+     */
+    public long end()
+        throws IOException;
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/http11/src/java/org/apache/coyote/http11/InternalAprInputBuffer.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/http11/src/java/org/apache/coyote/http11/InternalAprInputBuffer.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/http11/src/java/org/apache/coyote/http11/InternalAprInputBuffer.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,868 @@
+/*
+ *  Copyright 1999-2006 The Apache Software Foundation
+ *
+ *  Licensed 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;
+
+import java.io.IOException;
+import java.io.EOFException;
+import java.nio.ByteBuffer;
+
+import org.apache.tomcat.jni.Socket;
+import org.apache.tomcat.jni.Status;
+import org.apache.tomcat.util.buf.ByteChunk;
+import org.apache.tomcat.util.buf.MessageBytes;
+import org.apache.tomcat.util.http.MimeHeaders;
+import org.apache.tomcat.util.res.StringManager;
+
+import org.apache.coyote.InputBuffer;
+import org.apache.coyote.Request;
+
+/**
+ * Implementation of InputBuffer which provides HTTP request header parsing as
+ * well as transfer decoding.
+ *
+ * @author <a href="mailto:remm at apache.org">Remy Maucherat</a>
+ */
+public class InternalAprInputBuffer implements InputBuffer {
+
+
+    // -------------------------------------------------------------- Constants
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Alternate constructor.
+     */
+    public InternalAprInputBuffer(Request request, int headerBufferSize, 
+                                  long readTimeout) {
+
+        this.request = request;
+        headers = request.getMimeHeaders();
+
+        headerBuffer1 = new byte[headerBufferSize];
+        headerBuffer2 = new byte[headerBufferSize];
+        bodyBuffer = new byte[headerBufferSize];
+        buf = headerBuffer1;
+        bbuf = ByteBuffer.allocateDirect(headerBufferSize);
+
+        headerBuffer = new char[headerBufferSize];
+        ascbuf = headerBuffer;
+
+        inputStreamInputBuffer = new SocketInputBuffer();
+
+        filterLibrary = new InputFilter[0];
+        activeFilters = new InputFilter[0];
+        lastActiveFilter = -1;
+
+        parsingHeader = true;
+        swallowInput = true;
+        
+        if (readTimeout < 0) {
+            this.readTimeout = -1;
+        } else {
+            this.readTimeout = readTimeout * 1000;
+        }
+
+    }
+
+
+    // -------------------------------------------------------------- Variables
+
+
+    /**
+     * The string manager for this package.
+     */
+    protected static StringManager sm =
+        StringManager.getManager(Constants.Package);
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * Associated Coyote request.
+     */
+    protected Request request;
+
+
+    /**
+     * Headers of the associated request.
+     */
+    protected MimeHeaders headers;
+
+
+    /**
+     * State.
+     */
+    protected boolean parsingHeader;
+
+
+    /**
+     * Swallow input ? (in the case of an expectation)
+     */
+    protected boolean swallowInput;
+
+
+    /**
+     * Pointer to the current read buffer.
+     */
+    protected byte[] buf;
+
+
+    /**
+     * Pointer to the US-ASCII header buffer.
+     */
+    protected char[] ascbuf;
+
+
+    /**
+     * Last valid byte.
+     */
+    protected int lastValid;
+
+
+    /**
+     * Position in the buffer.
+     */
+    protected int pos;
+
+
+    /**
+     * HTTP header buffer no 1.
+     */
+    protected byte[] headerBuffer1;
+
+
+    /**
+     * HTTP header buffer no 2.
+     */
+    protected byte[] headerBuffer2;
+
+
+    /**
+     * HTTP body buffer.
+     */
+    protected byte[] bodyBuffer;
+
+
+    /**
+     * US-ASCII header buffer.
+     */
+    protected char[] headerBuffer;
+
+
+    /**
+     * Direct byte buffer used to perform actual reading.
+     */
+    protected ByteBuffer bbuf;
+
+
+    /**
+     * Underlying socket.
+     */
+    protected long socket;
+
+
+    /**
+     * Underlying input buffer.
+     */
+    protected InputBuffer inputStreamInputBuffer;
+
+
+    /**
+     * Filter library.
+     * Note: Filter[0] is always the "chunked" filter.
+     */
+    protected InputFilter[] filterLibrary;
+
+
+    /**
+     * Active filters (in order).
+     */
+    protected InputFilter[] activeFilters;
+
+
+    /**
+     * Index of the last active filter.
+     */
+    protected int lastActiveFilter;
+
+
+    /**
+     * The socket timeout used when reading the first block of the request
+     * header.
+     */
+    protected long readTimeout;
+    
+    
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * Set the underlying socket.
+     */
+    public void setSocket(long socket) {
+        this.socket = socket;
+        Socket.setrbb(this.socket, bbuf);
+    }
+
+
+    /**
+     * Get the underlying socket input stream.
+     */
+    public long getSocket() {
+        return socket;
+    }
+
+
+    /**
+     * Add an input filter to the filter library.
+     */
+    public void addFilter(InputFilter filter) {
+
+        InputFilter[] newFilterLibrary = 
+            new InputFilter[filterLibrary.length + 1];
+        for (int i = 0; i < filterLibrary.length; i++) {
+            newFilterLibrary[i] = filterLibrary[i];
+        }
+        newFilterLibrary[filterLibrary.length] = filter;
+        filterLibrary = newFilterLibrary;
+
+        activeFilters = new InputFilter[filterLibrary.length];
+
+    }
+
+
+    /**
+     * Get filters.
+     */
+    public InputFilter[] getFilters() {
+
+        return filterLibrary;
+
+    }
+
+
+    /**
+     * Clear filters.
+     */
+    public void clearFilters() {
+
+        filterLibrary = new InputFilter[0];
+        lastActiveFilter = -1;
+
+    }
+
+
+    /**
+     * Add an input filter to the filter library.
+     */
+    public void addActiveFilter(InputFilter filter) {
+
+        if (lastActiveFilter == -1) {
+            filter.setBuffer(inputStreamInputBuffer);
+        } else {
+            for (int i = 0; i <= lastActiveFilter; i++) {
+                if (activeFilters[i] == filter)
+                    return;
+            }
+            filter.setBuffer(activeFilters[lastActiveFilter]);
+        }
+
+        activeFilters[++lastActiveFilter] = filter;
+
+        filter.setRequest(request);
+
+    }
+
+
+    /**
+     * Set the swallow input flag.
+     */
+    public void setSwallowInput(boolean swallowInput) {
+        this.swallowInput = swallowInput;
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Recycle the input buffer. This should be called when closing the 
+     * connection.
+     */
+    public void recycle() {
+
+        // Recycle Request object
+        request.recycle();
+
+        socket = 0;
+        buf = headerBuffer1;
+        lastValid = 0;
+        pos = 0;
+        lastActiveFilter = -1;
+        parsingHeader = true;
+        swallowInput = true;
+
+    }
+
+
+    /**
+     * End processing of current HTTP request.
+     * Note: All bytes of the current request should have been already 
+     * consumed. This method only resets all the pointers so that we are ready
+     * to parse the next HTTP request.
+     */
+    public void nextRequest()
+        throws IOException {
+
+        // Recycle Request object
+        request.recycle();
+
+        // Determine the header buffer used for next request
+        byte[] newHeaderBuf = null;
+        if (buf == headerBuffer1) {
+            newHeaderBuf = headerBuffer2;
+        } else {
+            newHeaderBuf = headerBuffer1;
+        }
+
+        // Copy leftover bytes from buf to newHeaderBuf
+        System.arraycopy(buf, pos, newHeaderBuf, 0, lastValid - pos);
+
+        // Swap buffers
+        buf = newHeaderBuf;
+
+        // Recycle filters
+        for (int i = 0; i <= lastActiveFilter; i++) {
+            activeFilters[i].recycle();
+        }
+
+        // Reset pointers
+        lastValid = lastValid - pos;
+        pos = 0;
+        lastActiveFilter = -1;
+        parsingHeader = true;
+        swallowInput = true;
+
+    }
+
+
+    /**
+     * End request (consumes leftover bytes).
+     * 
+     * @throws IOException an undelying I/O error occured
+     */
+    public void endRequest()
+        throws IOException {
+
+        if (swallowInput && (lastActiveFilter != -1)) {
+            int extraBytes = (int) activeFilters[lastActiveFilter].end();
+            pos = pos - extraBytes;
+        }
+
+    }
+
+
+    /**
+     * Read the request line. This function is meant to be used during the 
+     * HTTP request header parsing. Do NOT attempt to read the request body 
+     * using it.
+     *
+     * @throws IOException If an exception occurs during the underlying socket
+     * read operations, or if the given buffer is not big enough to accomodate
+     * the whole line.
+     * @return true if data is properly fed; false if no data is available 
+     * immediately and thread should be freed
+     */
+    public boolean parseRequestLine(boolean useAvailableData)
+        throws IOException {
+
+        int start = 0;
+
+        //
+        // Skipping blank lines
+        //
+
+        byte chr = 0;
+        do {
+
+            // Read new bytes if needed
+            if (pos >= lastValid) {
+                if (useAvailableData) {
+                    return false;
+                }
+                if (readTimeout == -1) {
+                    if (!fill())
+                        throw new EOFException(sm.getString("iib.eof.error"));
+                } else {
+                    // Do a simple read with a short timeout
+                    bbuf.clear();
+                    int nRead = Socket.recvbbt
+                    (socket, 0, buf.length - lastValid, readTimeout);
+                    if (nRead > 0) {
+                        bbuf.limit(nRead);
+                        bbuf.get(buf, pos, nRead);
+                        lastValid = pos + nRead;
+                    } else {
+                        if ((-nRead) == Status.ETIMEDOUT || (-nRead) == Status.TIMEUP) {
+                            return false;
+                        } else {
+                            throw new IOException(sm.getString("iib.failedread"));
+                        }
+                    }
+                }
+            }
+
+            chr = buf[pos++];
+
+        } while ((chr == Constants.CR) || (chr == Constants.LF));
+
+        pos--;
+
+        // Mark the current buffer position
+        start = pos;
+
+        if (pos >= lastValid) {
+            if (useAvailableData) {
+                return false;
+            }
+            if (readTimeout == -1) {
+                if (!fill())
+                    throw new EOFException(sm.getString("iib.eof.error"));
+            } else {
+                // Do a simple read with a short timeout
+                bbuf.clear();
+                int nRead = Socket.recvbbt
+                    (socket, 0, buf.length - lastValid, readTimeout);
+                if (nRead > 0) {
+                    bbuf.limit(nRead);
+                    bbuf.get(buf, pos, nRead);
+                    lastValid = pos + nRead;
+                } else {
+                    if ((-nRead) == Status.ETIMEDOUT || (-nRead) == Status.TIMEUP) {
+                        return false;
+                    } else {
+                        throw new IOException(sm.getString("iib.failedread"));
+                    }
+                }
+            }
+        }
+
+        //
+        // Reading the method name
+        // Method name is always US-ASCII
+        //
+
+        boolean space = false;
+
+        while (!space) {
+
+            // Read new bytes if needed
+            if (pos >= lastValid) {
+                if (!fill())
+                    throw new EOFException(sm.getString("iib.eof.error"));
+            }
+
+            ascbuf[pos] = (char) buf[pos];
+
+            if (buf[pos] == Constants.SP) {
+                space = true;
+                request.method().setChars(ascbuf, start, pos - start);
+            }
+
+            pos++;
+
+        }
+
+        // Mark the current buffer position
+        start = pos;
+        int end = 0;
+        int questionPos = -1;
+
+        //
+        // Reading the URI
+        //
+
+        space = false;
+        boolean eol = false;
+
+        while (!space) {
+
+            // Read new bytes if needed
+            if (pos >= lastValid) {
+                if (!fill())
+                    throw new EOFException(sm.getString("iib.eof.error"));
+            }
+
+            if (buf[pos] == Constants.SP) {
+                space = true;
+                end = pos;
+            } else if ((buf[pos] == Constants.CR) 
+                       || (buf[pos] == Constants.LF)) {
+                // HTTP/0.9 style request
+                eol = true;
+                space = true;
+                end = pos;
+            } else if ((buf[pos] == Constants.QUESTION) 
+                       && (questionPos == -1)) {
+                questionPos = pos;
+            }
+
+            pos++;
+
+        }
+
+        request.unparsedURI().setBytes(buf, start, end - start);
+        if (questionPos >= 0) {
+            request.queryString().setBytes(buf, questionPos + 1, 
+                                           end - questionPos - 1);
+            request.requestURI().setBytes(buf, start, questionPos - start);
+        } else {
+            request.requestURI().setBytes(buf, start, end - start);
+        }
+
+        // Mark the current buffer position
+        start = pos;
+        end = 0;
+
+        //
+        // Reading the protocol
+        // Protocol is always US-ASCII
+        //
+
+        while (!eol) {
+
+            // Read new bytes if needed
+            if (pos >= lastValid) {
+                if (!fill())
+                    throw new EOFException(sm.getString("iib.eof.error"));
+            }
+
+            ascbuf[pos] = (char) buf[pos];
+
+            if (buf[pos] == Constants.CR) {
+                end = pos;
+            } else if (buf[pos] == Constants.LF) {
+                if (end == 0)
+                    end = pos;
+                eol = true;
+            }
+
+            pos++;
+
+        }
+
+        if ((end - start) > 0) {
+            request.protocol().setChars(ascbuf, start, end - start);
+        } else {
+            request.protocol().setString("");
+        }
+        
+        return true;
+
+    }
+
+
+    /**
+     * Parse the HTTP headers.
+     */
+    public void parseHeaders()
+        throws IOException {
+
+        while (parseHeader()) {
+        }
+
+        parsingHeader = false;
+
+    }
+
+
+    /**
+     * Parse an HTTP header.
+     * 
+     * @return false after reading a blank line (which indicates that the
+     * HTTP header parsing is done
+     */
+    public boolean parseHeader()
+        throws IOException {
+
+        //
+        // Check for blank line
+        //
+
+        byte chr = 0;
+        while (true) {
+
+            // Read new bytes if needed
+            if (pos >= lastValid) {
+                if (!fill())
+                    throw new EOFException(sm.getString("iib.eof.error"));
+            }
+
+            chr = buf[pos];
+
+            if ((chr == Constants.CR) || (chr == Constants.LF)) {
+                if (chr == Constants.LF) {
+                    pos++;
+                    return false;
+                }
+            } else {
+                break;
+            }
+
+            pos++;
+
+        }
+
+        // Mark the current buffer position
+        int start = pos;
+
+        //
+        // Reading the header name
+        // Header name is always US-ASCII
+        //
+
+        boolean colon = false;
+        MessageBytes headerValue = null;
+
+        while (!colon) {
+
+            // Read new bytes if needed
+            if (pos >= lastValid) {
+                if (!fill())
+                    throw new EOFException(sm.getString("iib.eof.error"));
+            }
+
+            if (buf[pos] == Constants.COLON) {
+                colon = true;
+                headerValue = headers.addValue(ascbuf, start, pos - start);
+            }
+            chr = buf[pos];
+            if ((chr >= Constants.A) && (chr <= Constants.Z)) {
+                buf[pos] = (byte) (chr - Constants.LC_OFFSET);
+            }
+
+            ascbuf[pos] = (char) buf[pos];
+
+            pos++;
+
+        }
+
+        // Mark the current buffer position
+        start = pos;
+        int realPos = pos;
+
+        //
+        // Reading the header value (which can be spanned over multiple lines)
+        //
+
+        boolean eol = false;
+        boolean validLine = true;
+
+        while (validLine) {
+
+            boolean space = true;
+
+            // Skipping spaces
+            while (space) {
+
+                // Read new bytes if needed
+                if (pos >= lastValid) {
+                    if (!fill())
+                        throw new EOFException(sm.getString("iib.eof.error"));
+                }
+
+                if ((buf[pos] == Constants.SP) || (buf[pos] == Constants.HT)) {
+                    pos++;
+                } else {
+                    space = false;
+                }
+
+            }
+
+            int lastSignificantChar = realPos;
+
+            // Reading bytes until the end of the line
+            while (!eol) {
+
+                // Read new bytes if needed
+                if (pos >= lastValid) {
+                    if (!fill())
+                        throw new EOFException(sm.getString("iib.eof.error"));
+                }
+
+                if (buf[pos] == Constants.CR) {
+                } else if (buf[pos] == Constants.LF) {
+                    eol = true;
+                } else if (buf[pos] == Constants.SP) {
+                    buf[realPos] = buf[pos];
+                    realPos++;
+                } else {
+                    buf[realPos] = buf[pos];
+                    realPos++;
+                    lastSignificantChar = realPos;
+                }
+
+                pos++;
+
+            }
+
+            realPos = lastSignificantChar;
+
+            // Checking the first character of the new line. If the character
+            // is a LWS, then it's a multiline header
+
+            // Read new bytes if needed
+            if (pos >= lastValid) {
+                if (!fill())
+                    throw new EOFException(sm.getString("iib.eof.error"));
+            }
+
+            chr = buf[pos];
+            if ((chr != Constants.SP) && (chr != Constants.HT)) {
+                validLine = false;
+            } else {
+                eol = false;
+                // Copying one extra space in the buffer (since there must
+                // be at least one space inserted between the lines)
+                buf[realPos] = chr;
+                realPos++;
+            }
+
+        }
+
+        // Set the header value
+        headerValue.setBytes(buf, start, realPos - start);
+
+        return true;
+
+    }
+
+
+    // ---------------------------------------------------- InputBuffer Methods
+
+
+    /**
+     * Read some bytes.
+     */
+    public int doRead(ByteChunk chunk, Request req) 
+        throws IOException {
+
+        if (lastActiveFilter == -1)
+            return inputStreamInputBuffer.doRead(chunk, req);
+        else
+            return activeFilters[lastActiveFilter].doRead(chunk,req);
+
+    }
+
+
+    // ------------------------------------------------------ Protected Methods
+
+
+    /**
+     * Fill the internal buffer using data from the undelying input stream.
+     * 
+     * @return false if at end of stream
+     */
+    protected boolean fill()
+        throws IOException {
+
+        int nRead = 0;
+
+        if (parsingHeader) {
+
+            if (lastValid == buf.length) {
+                throw new IOException
+                    (sm.getString("iib.requestheadertoolarge.error"));
+            }
+
+            bbuf.clear();
+            nRead = Socket.recvbb
+                (socket, 0, buf.length - lastValid);
+            if (nRead > 0) {
+                bbuf.limit(nRead);
+                bbuf.get(buf, pos, nRead);
+                lastValid = pos + nRead;
+            } else {
+                if ((-nRead) == Status.EAGAIN) {
+                    return false;
+                } else {
+                    throw new IOException(sm.getString("iib.failedread"));
+                }
+            }
+
+        } else {
+
+            buf = bodyBuffer;
+            pos = 0;
+            lastValid = 0;
+            bbuf.clear();
+            nRead = Socket.recvbb
+                (socket, 0, buf.length);
+            if (nRead > 0) {
+                bbuf.limit(nRead);
+                bbuf.get(buf, 0, nRead);
+                lastValid = nRead;
+            } else {
+                throw new IOException(sm.getString("iib.failedread"));
+            }
+
+        }
+
+        return (nRead > 0);
+
+    }
+
+
+    // ------------------------------------- InputStreamInputBuffer Inner Class
+
+
+    /**
+     * This class is an input buffer which will read its data from an input
+     * stream.
+     */
+    protected class SocketInputBuffer 
+        implements InputBuffer {
+
+
+        /**
+         * Read bytes into the specified chunk.
+         */
+        public int doRead(ByteChunk chunk, Request req ) 
+            throws IOException {
+
+            if (pos >= lastValid) {
+                if (!fill())
+                    return -1;
+            }
+
+            int length = lastValid - pos;
+            chunk.setBytes(buf, pos, length);
+            pos = lastValid;
+
+            return (length);
+
+        }
+
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/http11/src/java/org/apache/coyote/http11/InternalAprOutputBuffer.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/http11/src/java/org/apache/coyote/http11/InternalAprOutputBuffer.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/http11/src/java/org/apache/coyote/http11/InternalAprOutputBuffer.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,746 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+
+import org.apache.tomcat.jni.Socket;
+import org.apache.tomcat.util.buf.ByteChunk;
+import org.apache.tomcat.util.buf.CharChunk;
+import org.apache.tomcat.util.buf.MessageBytes;
+import org.apache.tomcat.util.http.HttpMessages;
+import org.apache.tomcat.util.http.MimeHeaders;
+import org.apache.tomcat.util.res.StringManager;
+
+import org.apache.coyote.ActionCode;
+import org.apache.coyote.OutputBuffer;
+import org.apache.coyote.Response;
+
+/**
+ * Output buffer.
+ * 
+ * @author <a href="mailto:remm at apache.org">Remy Maucherat</a>
+ */
+public class InternalAprOutputBuffer 
+    implements OutputBuffer {
+
+
+    // -------------------------------------------------------------- Constants
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Default constructor.
+     */
+    public InternalAprOutputBuffer(Response response) {
+        this(response, Constants.DEFAULT_HTTP_HEADER_BUFFER_SIZE);
+    }
+
+
+    /**
+     * Alternate constructor.
+     */
+    public InternalAprOutputBuffer(Response response, int headerBufferSize) {
+
+        this.response = response;
+        headers = response.getMimeHeaders();
+
+        headerBuffer = new byte[headerBufferSize];
+        buf = headerBuffer;
+
+        bbuf = ByteBuffer.allocateDirect((headerBufferSize / 1500 + 1) * 1500);
+
+        outputStreamOutputBuffer = new SocketOutputBuffer();
+
+        filterLibrary = new OutputFilter[0];
+        activeFilters = new OutputFilter[0];
+        lastActiveFilter = -1;
+
+        committed = false;
+        finished = false;
+
+        // Cause loading of HttpMessages
+        HttpMessages.getMessage(200);
+
+    }
+
+
+    // -------------------------------------------------------------- Variables
+
+
+    /**
+     * The string manager for this package.
+     */
+    protected static StringManager sm =
+        StringManager.getManager(Constants.Package);
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * Associated Coyote response.
+     */
+    protected Response response;
+
+
+    /**
+     * Headers of the associated request.
+     */
+    protected MimeHeaders headers;
+
+
+    /**
+     * Committed flag.
+     */
+    protected boolean committed;
+
+
+    /**
+     * Finished flag.
+     */
+    protected boolean finished;
+
+
+    /**
+     * Pointer to the current read buffer.
+     */
+    protected byte[] buf;
+
+
+    /**
+     * Position in the buffer.
+     */
+    protected int pos;
+
+
+    /**
+     * HTTP header buffer.
+     */
+    protected byte[] headerBuffer;
+
+
+    /**
+     * Underlying socket.
+     */
+    protected long socket;
+
+
+    /**
+     * Underlying output buffer.
+     */
+    protected OutputBuffer outputStreamOutputBuffer;
+
+
+    /**
+     * Filter library.
+     * Note: Filter[0] is always the "chunked" filter.
+     */
+    protected OutputFilter[] filterLibrary;
+
+
+    /**
+     * Active filter (which is actually the top of the pipeline).
+     */
+    protected OutputFilter[] activeFilters;
+
+
+    /**
+     * Index of the last active filter.
+     */
+    protected int lastActiveFilter;
+
+
+    /**
+     * Direct byte buffer used for writing.
+     */
+    protected ByteBuffer bbuf = null;
+
+    
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * Set the underlying socket.
+     */
+    public void setSocket(long socket) {
+        this.socket = socket;
+        Socket.setsbb(this.socket, bbuf);
+    }
+
+
+    /**
+     * Get the underlying socket input stream.
+     */
+    public long getSocket() {
+        return socket;
+    }
+
+
+    /**
+     * Set the socket buffer size.
+     */
+    public void setSocketBuffer(int socketBufferSize) {
+        // FIXME: Remove
+    }
+
+
+    /**
+     * Add an output filter to the filter library.
+     */
+    public void addFilter(OutputFilter filter) {
+
+        OutputFilter[] newFilterLibrary = 
+            new OutputFilter[filterLibrary.length + 1];
+        for (int i = 0; i < filterLibrary.length; i++) {
+            newFilterLibrary[i] = filterLibrary[i];
+        }
+        newFilterLibrary[filterLibrary.length] = filter;
+        filterLibrary = newFilterLibrary;
+
+        activeFilters = new OutputFilter[filterLibrary.length];
+
+    }
+
+
+    /**
+     * Get filters.
+     */
+    public OutputFilter[] getFilters() {
+
+        return filterLibrary;
+
+    }
+
+
+    /**
+     * Clear filters.
+     */
+    public void clearFilters() {
+
+        filterLibrary = new OutputFilter[0];
+        lastActiveFilter = -1;
+
+    }
+
+
+    /**
+     * Add an output filter to the filter library.
+     */
+    public void addActiveFilter(OutputFilter filter) {
+
+        if (lastActiveFilter == -1) {
+            filter.setBuffer(outputStreamOutputBuffer);
+        } else {
+            for (int i = 0; i <= lastActiveFilter; i++) {
+                if (activeFilters[i] == filter)
+                    return;
+            }
+            filter.setBuffer(activeFilters[lastActiveFilter]);
+        }
+
+        activeFilters[++lastActiveFilter] = filter;
+
+        filter.setResponse(response);
+
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Flush the response.
+     * 
+     * @throws IOException an undelying I/O error occured
+     */
+    public void flush()
+        throws IOException {
+
+        if (!committed) {
+
+            // Send the connector a request for commit. The connector should
+            // then validate the headers, send them (using sendHeader) and 
+            // set the filters accordingly.
+            response.action(ActionCode.ACTION_COMMIT, null);
+
+        }
+
+        // Flush the current buffer
+        flushBuffer();
+
+    }
+
+
+    /**
+     * Reset current response.
+     * 
+     * @throws IllegalStateException if the response has already been committed
+     */
+    public void reset() {
+
+        if (committed)
+            throw new IllegalStateException(/*FIXME:Put an error message*/);
+
+        // Recycle Request object
+        response.recycle();
+
+    }
+
+
+    /**
+     * Recycle the output buffer. This should be called when closing the 
+     * connection.
+     */
+    public void recycle() {
+
+        // Recycle Request object
+        response.recycle();
+        bbuf.clear();
+
+        socket = 0;
+        buf = headerBuffer;
+        pos = 0;
+        lastActiveFilter = -1;
+        committed = false;
+        finished = false;
+
+    }
+
+
+    /**
+     * End processing of current HTTP request.
+     * Note: All bytes of the current request should have been already 
+     * consumed. This method only resets all the pointers so that we are ready
+     * to parse the next HTTP request.
+     */
+    public void nextRequest() {
+
+        // Recycle Request object
+        response.recycle();
+
+        // Determine the header buffer used for next request
+        buf = headerBuffer;
+
+        // Recycle filters
+        for (int i = 0; i <= lastActiveFilter; i++) {
+            activeFilters[i].recycle();
+        }
+
+        // Reset pointers
+        pos = 0;
+        lastActiveFilter = -1;
+        committed = false;
+        finished = false;
+
+    }
+
+
+    /**
+     * End request.
+     * 
+     * @throws IOException an undelying I/O error occured
+     */
+    public void endRequest()
+        throws IOException {
+
+        if (!committed) {
+
+            // Send the connector a request for commit. The connector should
+            // then validate the headers, send them (using sendHeader) and 
+            // set the filters accordingly.
+            response.action(ActionCode.ACTION_COMMIT, null);
+
+        }
+
+        if (finished)
+            return;
+
+        if (lastActiveFilter != -1)
+            activeFilters[lastActiveFilter].end();
+
+        flushBuffer();
+
+        finished = true;
+
+    }
+
+
+    // ------------------------------------------------ HTTP/1.1 Output Methods
+
+
+    /**
+     * Send an acknoledgement.
+     */
+    public void sendAck()
+        throws IOException {
+
+        if (!committed) {
+            if (Socket.send(socket, Constants.ACK_BYTES, 0, Constants.ACK_BYTES.length) < 0)
+                throw new IOException(sm.getString("iib.failedwrite"));
+        }
+
+    }
+
+
+    /**
+     * Send the response status line.
+     */
+    public void sendStatus() {
+
+        // Write protocol name
+        write(Constants.HTTP_11_BYTES);
+        buf[pos++] = Constants.SP;
+
+        // Write status code
+        int status = response.getStatus();
+        switch (status) {
+        case 200:
+            write(Constants._200_BYTES);
+            break;
+        case 400:
+            write(Constants._400_BYTES);
+            break;
+        case 404:
+            write(Constants._404_BYTES);
+            break;
+        default:
+            write(status);
+        }
+
+        buf[pos++] = Constants.SP;
+
+        // Write message
+        String message = response.getMessage();
+        if (message == null) {
+            write(HttpMessages.getMessage(status));
+        } else {
+            write(message);
+        }
+
+        // End the response status line
+        buf[pos++] = Constants.CR;
+        buf[pos++] = Constants.LF;
+
+    }
+
+
+    /**
+     * Send a header.
+     * 
+     * @param name Header name
+     * @param value Header value
+     */
+    public void sendHeader(MessageBytes name, MessageBytes value) {
+
+        write(name);
+        buf[pos++] = Constants.COLON;
+        buf[pos++] = Constants.SP;
+        write(value);
+        buf[pos++] = Constants.CR;
+        buf[pos++] = Constants.LF;
+
+    }
+
+
+    /**
+     * Send a header.
+     * 
+     * @param name Header name
+     * @param value Header value
+     */
+    public void sendHeader(ByteChunk name, ByteChunk value) {
+
+        write(name);
+        buf[pos++] = Constants.COLON;
+        buf[pos++] = Constants.SP;
+        write(value);
+        buf[pos++] = Constants.CR;
+        buf[pos++] = Constants.LF;
+
+    }
+
+
+    /**
+     * Send a header.
+     * 
+     * @param name Header name
+     * @param value Header value
+     */
+    public void sendHeader(String name, String value) {
+
+        write(name);
+        buf[pos++] = Constants.COLON;
+        buf[pos++] = Constants.SP;
+        write(value);
+        buf[pos++] = Constants.CR;
+        buf[pos++] = Constants.LF;
+
+    }
+
+
+    /**
+     * End the header block.
+     */
+    public void endHeaders() {
+
+        buf[pos++] = Constants.CR;
+        buf[pos++] = Constants.LF;
+
+    }
+
+
+    // --------------------------------------------------- OutputBuffer Methods
+
+
+    /**
+     * Write the contents of a byte chunk.
+     * 
+     * @param chunk byte chunk
+     * @return number of bytes written
+     * @throws IOException an undelying I/O error occured
+     */
+    public int doWrite(ByteChunk chunk, Response res) 
+        throws IOException {
+
+        if (!committed) {
+
+            // Send the connector a request for commit. The connector should
+            // then validate the headers, send them (using sendHeaders) and 
+            // set the filters accordingly.
+            response.action(ActionCode.ACTION_COMMIT, null);
+
+        }
+
+        if (lastActiveFilter == -1)
+            return outputStreamOutputBuffer.doWrite(chunk, res);
+        else
+            return activeFilters[lastActiveFilter].doWrite(chunk, res);
+
+    }
+
+
+    // ------------------------------------------------------ Protected Methods
+
+
+    /**
+     * Commit the response.
+     * 
+     * @throws IOException an undelying I/O error occured
+     */
+    protected void commit()
+        throws IOException {
+
+        // The response is now committed
+        committed = true;
+        response.setCommitted(true);
+
+        if (pos > 0) {
+            // Sending the response header buffer
+            bbuf.put(buf, 0, pos);
+        }
+
+    }
+
+
+    /**
+     * This method will write the contents of the specyfied message bytes 
+     * buffer to the output stream, without filtering. This method is meant to
+     * be used to write the response header.
+     * 
+     * @param mb data to be written
+     */
+    protected void write(MessageBytes mb) {
+
+        if (mb.getType() == MessageBytes.T_BYTES) {
+            ByteChunk bc = mb.getByteChunk();
+            write(bc);
+        } else if (mb.getType() == MessageBytes.T_CHARS) {
+            CharChunk cc = mb.getCharChunk();
+            write(cc);
+        } else {
+            write(mb.toString());
+        }
+
+    }
+
+
+    /**
+     * This method will write the contents of the specyfied message bytes 
+     * buffer to the output stream, without filtering. This method is meant to
+     * be used to write the response header.
+     * 
+     * @param bc data to be written
+     */
+    protected void write(ByteChunk bc) {
+
+        // Writing the byte chunk to the output buffer
+        System.arraycopy(bc.getBytes(), bc.getStart(), buf, pos,
+                         bc.getLength());
+        pos = pos + bc.getLength();
+
+    }
+
+
+    /**
+     * This method will write the contents of the specyfied char 
+     * buffer to the output stream, without filtering. This method is meant to
+     * be used to write the response header.
+     * 
+     * @param cc data to be written
+     */
+    protected void write(CharChunk cc) {
+
+        int start = cc.getStart();
+        int end = cc.getEnd();
+        char[] cbuf = cc.getBuffer();
+        for (int i = start; i < end; i++) {
+            char c = cbuf[i];
+            // Note:  This is clearly incorrect for many strings,
+            // but is the only consistent approach within the current
+            // servlet framework.  It must suffice until servlet output
+            // streams properly encode their output.
+            if ((c <= 31) && (c != 9)) {
+                c = ' ';
+            } else if (c == 127) {
+                c = ' ';
+            }
+            buf[pos++] = (byte) c;
+        }
+
+    }
+
+
+    /**
+     * This method will write the contents of the specyfied byte 
+     * buffer to the output stream, without filtering. This method is meant to
+     * be used to write the response header.
+     * 
+     * @param b data to be written
+     */
+    public void write(byte[] b) {
+
+        // Writing the byte chunk to the output buffer
+        System.arraycopy(b, 0, buf, pos, b.length);
+        pos = pos + b.length;
+
+    }
+
+
+    /**
+     * This method will write the contents of the specyfied String to the 
+     * output stream, without filtering. This method is meant to be used to 
+     * write the response header.
+     * 
+     * @param s data to be written
+     */
+    protected void write(String s) {
+
+        if (s == null)
+            return;
+
+        // From the Tomcat 3.3 HTTP/1.0 connector
+        int len = s.length();
+        for (int i = 0; i < len; i++) {
+            char c = s.charAt (i);
+            // Note:  This is clearly incorrect for many strings,
+            // but is the only consistent approach within the current
+            // servlet framework.  It must suffice until servlet output
+            // streams properly encode their output.
+            if ((c <= 31) && (c != 9)) {
+                c = ' ';
+            } else if (c == 127) {
+                c = ' ';
+            }
+            buf[pos++] = (byte) c;
+        }
+
+    }
+
+
+    /**
+     * This method will print the specified integer to the output stream, 
+     * without filtering. This method is meant to be used to write the 
+     * response header.
+     * 
+     * @param i data to be written
+     */
+    protected void write(int i) {
+
+        write(String.valueOf(i));
+
+    }
+
+
+    /**
+     * Callback to write data from the buffer.
+     */
+    protected void flushBuffer()
+        throws IOException {
+        if (bbuf.position() > 0) {
+            if (Socket.sendbb(socket, 0, bbuf.position()) < 0) {
+                throw new IOException();
+            }
+            bbuf.clear();
+        }
+    }
+
+
+    // ----------------------------------- OutputStreamOutputBuffer Inner Class
+
+
+    /**
+     * This class is an output buffer which will write data to an output
+     * stream.
+     */
+    protected class SocketOutputBuffer 
+        implements OutputBuffer {
+
+
+        /**
+         * Write chunk.
+         */
+        public int doWrite(ByteChunk chunk, Response res) 
+            throws IOException {
+
+            int len = chunk.getLength();
+            int start = chunk.getStart();
+            byte[] b = chunk.getBuffer();
+            while (len > 0) {
+                int thisTime = len;
+                if (bbuf.position() == bbuf.capacity()) {
+                    flushBuffer();
+                }
+                if (thisTime > bbuf.capacity() - bbuf.position()) {
+                    thisTime = bbuf.capacity() - bbuf.position();
+                }
+                bbuf.put(b, start, thisTime);
+                len = len - thisTime;
+                start = start + thisTime;
+            }
+            return chunk.getLength();
+
+        }
+
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/http11/src/java/org/apache/coyote/http11/InternalInputBuffer.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/http11/src/java/org/apache/coyote/http11/InternalInputBuffer.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/http11/src/java/org/apache/coyote/http11/InternalInputBuffer.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,793 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.EOFException;
+
+import org.apache.tomcat.util.buf.ByteChunk;
+import org.apache.tomcat.util.buf.MessageBytes;
+import org.apache.tomcat.util.http.MimeHeaders;
+import org.apache.tomcat.util.res.StringManager;
+
+import org.apache.coyote.InputBuffer;
+import org.apache.coyote.Request;
+
+/**
+ * Implementation of InputBuffer which provides HTTP request header parsing as
+ * well as transfer decoding.
+ *
+ * @author <a href="mailto:remm at apache.org">Remy Maucherat</a>
+ */
+public class InternalInputBuffer implements InputBuffer {
+
+
+    // -------------------------------------------------------------- Constants
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Default constructor.
+     */
+    public InternalInputBuffer(Request request) {
+        this(request, Constants.DEFAULT_HTTP_HEADER_BUFFER_SIZE);
+    }
+
+
+    /**
+     * Alternate constructor.
+     */
+    public InternalInputBuffer(Request request, int headerBufferSize) {
+
+        this.request = request;
+        headers = request.getMimeHeaders();
+
+        headerBuffer1 = new byte[headerBufferSize];
+        headerBuffer2 = new byte[headerBufferSize];
+        bodyBuffer = new byte[headerBufferSize];
+        buf = headerBuffer1;
+
+        headerBuffer = new char[headerBufferSize];
+        ascbuf = headerBuffer;
+
+        inputStreamInputBuffer = new InputStreamInputBuffer();
+
+        filterLibrary = new InputFilter[0];
+        activeFilters = new InputFilter[0];
+        lastActiveFilter = -1;
+
+        parsingHeader = true;
+        swallowInput = true;
+
+    }
+
+
+    // -------------------------------------------------------------- Variables
+
+
+    /**
+     * The string manager for this package.
+     */
+    protected static StringManager sm =
+        StringManager.getManager(Constants.Package);
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * Associated Coyote request.
+     */
+    protected Request request;
+
+
+    /**
+     * Headers of the associated request.
+     */
+    protected MimeHeaders headers;
+
+
+    /**
+     * State.
+     */
+    protected boolean parsingHeader;
+
+
+    /**
+     * Swallow input ? (in the case of an expectation)
+     */
+    protected boolean swallowInput;
+
+
+    /**
+     * Pointer to the current read buffer.
+     */
+    protected byte[] buf;
+
+
+    /**
+     * Pointer to the US-ASCII header buffer.
+     */
+    protected char[] ascbuf;
+
+
+    /**
+     * Last valid byte.
+     */
+    protected int lastValid;
+
+
+    /**
+     * Position in the buffer.
+     */
+    protected int pos;
+
+
+    /**
+     * HTTP header buffer no 1.
+     */
+    protected byte[] headerBuffer1;
+
+
+    /**
+     * HTTP header buffer no 2.
+     */
+    protected byte[] headerBuffer2;
+
+
+    /**
+     * HTTP body buffer.
+     */
+    protected byte[] bodyBuffer;
+
+
+    /**
+     * US-ASCII header buffer.
+     */
+    protected char[] headerBuffer;
+
+
+    /**
+     * Underlying input stream.
+     */
+    protected InputStream inputStream;
+
+
+    /**
+     * Underlying input buffer.
+     */
+    protected InputBuffer inputStreamInputBuffer;
+
+
+    /**
+     * Filter library.
+     * Note: Filter[0] is always the "chunked" filter.
+     */
+    protected InputFilter[] filterLibrary;
+
+
+    /**
+     * Active filters (in order).
+     */
+    protected InputFilter[] activeFilters;
+
+
+    /**
+     * Index of the last active filter.
+     */
+    protected int lastActiveFilter;
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * Set the underlying socket input stream.
+     */
+    public void setInputStream(InputStream inputStream) {
+
+        // FIXME: Check for null ?
+
+        this.inputStream = inputStream;
+
+    }
+
+
+    /**
+     * Get the underlying socket input stream.
+     */
+    public InputStream getInputStream() {
+
+        return inputStream;
+
+    }
+
+
+    /**
+     * Add an input filter to the filter library.
+     */
+    public void addFilter(InputFilter filter) {
+
+        // FIXME: Check for null ?
+
+        InputFilter[] newFilterLibrary = 
+            new InputFilter[filterLibrary.length + 1];
+        for (int i = 0; i < filterLibrary.length; i++) {
+            newFilterLibrary[i] = filterLibrary[i];
+        }
+        newFilterLibrary[filterLibrary.length] = filter;
+        filterLibrary = newFilterLibrary;
+
+        activeFilters = new InputFilter[filterLibrary.length];
+
+    }
+
+
+    /**
+     * Get filters.
+     */
+    public InputFilter[] getFilters() {
+
+        return filterLibrary;
+
+    }
+
+
+    /**
+     * Clear filters.
+     */
+    public void clearFilters() {
+
+        filterLibrary = new InputFilter[0];
+        lastActiveFilter = -1;
+
+    }
+
+
+    /**
+     * Add an input filter to the filter library.
+     */
+    public void addActiveFilter(InputFilter filter) {
+
+        if (lastActiveFilter == -1) {
+            filter.setBuffer(inputStreamInputBuffer);
+        } else {
+            for (int i = 0; i <= lastActiveFilter; i++) {
+                if (activeFilters[i] == filter)
+                    return;
+            }
+            filter.setBuffer(activeFilters[lastActiveFilter]);
+        }
+
+        activeFilters[++lastActiveFilter] = filter;
+
+        filter.setRequest(request);
+
+    }
+
+
+    /**
+     * Set the swallow input flag.
+     */
+    public void setSwallowInput(boolean swallowInput) {
+        this.swallowInput = swallowInput;
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Recycle the input buffer. This should be called when closing the 
+     * connection.
+     */
+    public void recycle() {
+
+        // Recycle Request object
+        request.recycle();
+
+        inputStream = null;
+        buf = headerBuffer1;
+        lastValid = 0;
+        pos = 0;
+        lastActiveFilter = -1;
+        parsingHeader = true;
+        swallowInput = true;
+
+    }
+
+
+    /**
+     * End processing of current HTTP request.
+     * Note: All bytes of the current request should have been already 
+     * consumed. This method only resets all the pointers so that we are ready
+     * to parse the next HTTP request.
+     */
+    public void nextRequest()
+        throws IOException {
+
+        // Recycle Request object
+        request.recycle();
+
+        // Determine the header buffer used for next request
+        byte[] newHeaderBuf = null;
+        if (buf == headerBuffer1) {
+            newHeaderBuf = headerBuffer2;
+        } else {
+            newHeaderBuf = headerBuffer1;
+        }
+
+        // Copy leftover bytes from buf to newHeaderBuf
+        System.arraycopy(buf, pos, newHeaderBuf, 0, lastValid - pos);
+
+        // Swap buffers
+        buf = newHeaderBuf;
+
+        // Recycle filters
+        for (int i = 0; i <= lastActiveFilter; i++) {
+            activeFilters[i].recycle();
+        }
+
+        // Reset pointers
+        lastValid = lastValid - pos;
+        pos = 0;
+        lastActiveFilter = -1;
+        parsingHeader = true;
+        swallowInput = true;
+
+    }
+
+
+    /**
+     * End request (consumes leftover bytes).
+     * 
+     * @throws IOException an undelying I/O error occured
+     */
+    public void endRequest()
+        throws IOException {
+
+        if (swallowInput && (lastActiveFilter != -1)) {
+            int extraBytes = (int) activeFilters[lastActiveFilter].end();
+            pos = pos - extraBytes;
+        }
+
+    }
+
+
+    /**
+     * Read the request line. This function is meant to be used during the 
+     * HTTP request header parsing. Do NOT attempt to read the request body 
+     * using it.
+     *
+     * @throws IOException If an exception occurs during the underlying socket
+     * read operations, or if the given buffer is not big enough to accomodate
+     * the whole line.
+     */
+    public void parseRequestLine()
+        throws IOException {
+
+        int start = 0;
+
+        //
+        // Skipping blank lines
+        //
+
+        byte chr = 0;
+        do {
+
+            // Read new bytes if needed
+            if (pos >= lastValid) {
+                if (!fill())
+                    throw new EOFException(sm.getString("iib.eof.error"));
+            }
+
+            chr = buf[pos++];
+
+        } while ((chr == Constants.CR) || (chr == Constants.LF));
+
+        pos--;
+
+        // Mark the current buffer position
+        start = pos;
+
+        //
+        // Reading the method name
+        // Method name is always US-ASCII
+        //
+
+        boolean space = false;
+
+        while (!space) {
+
+            // Read new bytes if needed
+            if (pos >= lastValid) {
+                if (!fill())
+                    throw new EOFException(sm.getString("iib.eof.error"));
+            }
+
+            ascbuf[pos] = (char) buf[pos];
+
+            if (buf[pos] == Constants.SP) {
+                space = true;
+                request.method().setChars(ascbuf, start, pos - start);
+            }
+
+            pos++;
+
+        }
+
+        // Mark the current buffer position
+        start = pos;
+        int end = 0;
+        int questionPos = -1;
+
+        //
+        // Reading the URI
+        //
+
+        space = false;
+        boolean eol = false;
+
+        while (!space) {
+
+            // Read new bytes if needed
+            if (pos >= lastValid) {
+                if (!fill())
+                    throw new EOFException(sm.getString("iib.eof.error"));
+            }
+
+            if (buf[pos] == Constants.SP) {
+                space = true;
+                end = pos;
+            } else if ((buf[pos] == Constants.CR) 
+                       || (buf[pos] == Constants.LF)) {
+                // HTTP/0.9 style request
+                eol = true;
+                space = true;
+                end = pos;
+            } else if ((buf[pos] == Constants.QUESTION) 
+                       && (questionPos == -1)) {
+                questionPos = pos;
+            }
+
+            pos++;
+
+        }
+
+        request.unparsedURI().setBytes(buf, start, end - start);
+        if (questionPos >= 0) {
+            request.queryString().setBytes(buf, questionPos + 1, 
+                                           end - questionPos - 1);
+            request.requestURI().setBytes(buf, start, questionPos - start);
+        } else {
+            request.requestURI().setBytes(buf, start, end - start);
+        }
+
+        // Mark the current buffer position
+        start = pos;
+        end = 0;
+
+        //
+        // Reading the protocol
+        // Protocol is always US-ASCII
+        //
+
+        while (!eol) {
+
+            // Read new bytes if needed
+            if (pos >= lastValid) {
+                if (!fill())
+                    throw new EOFException(sm.getString("iib.eof.error"));
+            }
+
+            ascbuf[pos] = (char) buf[pos];
+
+            if (buf[pos] == Constants.CR) {
+                end = pos;
+            } else if (buf[pos] == Constants.LF) {
+                if (end == 0)
+                    end = pos;
+                eol = true;
+            }
+
+            pos++;
+
+        }
+
+        if ((end - start) > 0) {
+            request.protocol().setChars(ascbuf, start, end - start);
+        } else {
+            request.protocol().setString("");
+        }
+
+    }
+
+
+    /**
+     * Parse the HTTP headers.
+     */
+    public void parseHeaders()
+        throws IOException {
+
+        while (parseHeader()) {
+        }
+
+        parsingHeader = false;
+
+    }
+
+
+    /**
+     * Parse an HTTP header.
+     * 
+     * @return false after reading a blank line (which indicates that the
+     * HTTP header parsing is done
+     */
+    public boolean parseHeader()
+        throws IOException {
+
+        //
+        // Check for blank line
+        //
+
+        byte chr = 0;
+        while (true) {
+
+            // Read new bytes if needed
+            if (pos >= lastValid) {
+                if (!fill())
+                    throw new EOFException(sm.getString("iib.eof.error"));
+            }
+
+            chr = buf[pos];
+
+            if ((chr == Constants.CR) || (chr == Constants.LF)) {
+                if (chr == Constants.LF) {
+                    pos++;
+                    return false;
+                }
+            } else {
+                break;
+            }
+
+            pos++;
+
+        }
+
+        // Mark the current buffer position
+        int start = pos;
+
+        //
+        // Reading the header name
+        // Header name is always US-ASCII
+        //
+
+        boolean colon = false;
+        MessageBytes headerValue = null;
+
+        while (!colon) {
+
+            // Read new bytes if needed
+            if (pos >= lastValid) {
+                if (!fill())
+                    throw new EOFException(sm.getString("iib.eof.error"));
+            }
+
+            if (buf[pos] == Constants.COLON) {
+                colon = true;
+                headerValue = headers.addValue(ascbuf, start, pos - start);
+            }
+            chr = buf[pos];
+            if ((chr >= Constants.A) && (chr <= Constants.Z)) {
+                buf[pos] = (byte) (chr - Constants.LC_OFFSET);
+            }
+
+            ascbuf[pos] = (char) buf[pos];
+
+            pos++;
+
+        }
+
+        // Mark the current buffer position
+        start = pos;
+        int realPos = pos;
+
+        //
+        // Reading the header value (which can be spanned over multiple lines)
+        //
+
+        boolean eol = false;
+        boolean validLine = true;
+
+        while (validLine) {
+
+            boolean space = true;
+
+            // Skipping spaces
+            while (space) {
+
+                // Read new bytes if needed
+                if (pos >= lastValid) {
+                    if (!fill())
+                        throw new EOFException(sm.getString("iib.eof.error"));
+                }
+
+                if ((buf[pos] == Constants.SP) || (buf[pos] == Constants.HT)) {
+                    pos++;
+                } else {
+                    space = false;
+                }
+
+            }
+
+            int lastSignificantChar = realPos;
+
+            // Reading bytes until the end of the line
+            while (!eol) {
+
+                // Read new bytes if needed
+                if (pos >= lastValid) {
+                    if (!fill())
+                        throw new EOFException(sm.getString("iib.eof.error"));
+                }
+
+                if (buf[pos] == Constants.CR) {
+                } else if (buf[pos] == Constants.LF) {
+                    eol = true;
+                } else if (buf[pos] == Constants.SP) {
+                    buf[realPos] = buf[pos];
+                    realPos++;
+                } else {
+                    buf[realPos] = buf[pos];
+                    realPos++;
+                    lastSignificantChar = realPos;
+                }
+
+                pos++;
+
+            }
+
+            realPos = lastSignificantChar;
+
+            // Checking the first character of the new line. If the character
+            // is a LWS, then it's a multiline header
+
+            // Read new bytes if needed
+            if (pos >= lastValid) {
+                if (!fill())
+                    throw new EOFException(sm.getString("iib.eof.error"));
+            }
+
+            chr = buf[pos];
+            if ((chr != Constants.SP) && (chr != Constants.HT)) {
+                validLine = false;
+            } else {
+                eol = false;
+                // Copying one extra space in the buffer (since there must
+                // be at least one space inserted between the lines)
+                buf[realPos] = chr;
+                realPos++;
+            }
+
+        }
+
+        // Set the header value
+        headerValue.setBytes(buf, start, realPos - start);
+
+        return true;
+
+    }
+
+
+    // ---------------------------------------------------- InputBuffer Methods
+
+
+    /**
+     * Read some bytes.
+     */
+    public int doRead(ByteChunk chunk, Request req) 
+        throws IOException {
+
+        if (lastActiveFilter == -1)
+            return inputStreamInputBuffer.doRead(chunk, req);
+        else
+            return activeFilters[lastActiveFilter].doRead(chunk,req);
+
+    }
+
+
+    // ------------------------------------------------------ Protected Methods
+
+
+    /**
+     * Fill the internal buffer using data from the undelying input stream.
+     * 
+     * @return false if at end of stream
+     */
+    protected boolean fill()
+        throws IOException {
+
+        int nRead = 0;
+
+        if (parsingHeader) {
+
+            if (lastValid == buf.length) {
+                throw new IOException
+                    (sm.getString("iib.requestheadertoolarge.error"));
+            }
+
+            nRead = inputStream.read(buf, pos, buf.length - lastValid);
+            if (nRead > 0) {
+                lastValid = pos + nRead;
+            }
+
+        } else {
+
+            buf = bodyBuffer;
+            pos = 0;
+            lastValid = 0;
+            nRead = inputStream.read(buf, 0, buf.length);
+            if (nRead > 0) {
+                lastValid = nRead;
+            }
+
+        }
+
+        return (nRead > 0);
+
+    }
+
+
+    // ------------------------------------- InputStreamInputBuffer Inner Class
+
+
+    /**
+     * This class is an input buffer which will read its data from an input
+     * stream.
+     */
+    protected class InputStreamInputBuffer 
+        implements InputBuffer {
+
+
+        /**
+         * Read bytes into the specified chunk.
+         */
+        public int doRead(ByteChunk chunk, Request req ) 
+            throws IOException {
+
+            if (pos >= lastValid) {
+                if (!fill())
+                    return -1;
+            }
+
+            int length = lastValid - pos;
+            chunk.setBytes(buf, pos, length);
+            pos = lastValid;
+
+            return (length);
+
+        }
+
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/http11/src/java/org/apache/coyote/http11/InternalOutputBuffer.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/http11/src/java/org/apache/coyote/http11/InternalOutputBuffer.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/http11/src/java/org/apache/coyote/http11/InternalOutputBuffer.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,783 @@
+/*
+ *  Copyright 1999-2005 The Apache Software Foundation
+ *
+ *  Licensed 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;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+
+import org.apache.tomcat.util.buf.ByteChunk;
+import org.apache.tomcat.util.buf.CharChunk;
+import org.apache.tomcat.util.buf.MessageBytes;
+import org.apache.tomcat.util.http.HttpMessages;
+import org.apache.tomcat.util.http.MimeHeaders;
+import org.apache.tomcat.util.res.StringManager;
+
+import org.apache.coyote.ActionCode;
+import org.apache.coyote.OutputBuffer;
+import org.apache.coyote.Response;
+
+/**
+ * Output buffer.
+ * 
+ * @author <a href="mailto:remm at apache.org">Remy Maucherat</a>
+ */
+public class InternalOutputBuffer 
+    implements OutputBuffer, ByteChunk.ByteOutputChannel {
+
+    // -------------------------------------------------------------- Constants
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Default constructor.
+     */
+    public InternalOutputBuffer(Response response) {
+        this(response, Constants.DEFAULT_HTTP_HEADER_BUFFER_SIZE);
+    }
+
+
+    /**
+     * Alternate constructor.
+     */
+    public InternalOutputBuffer(Response response, int headerBufferSize) {
+
+        this.response = response;
+        headers = response.getMimeHeaders();
+
+        headerBuffer = new byte[headerBufferSize];
+        buf = headerBuffer;
+
+        outputStreamOutputBuffer = new OutputStreamOutputBuffer();
+
+        filterLibrary = new OutputFilter[0];
+        activeFilters = new OutputFilter[0];
+        lastActiveFilter = -1;
+
+        socketBuffer = new ByteChunk();
+        socketBuffer.setByteOutputChannel(this);
+
+        committed = false;
+        finished = false;
+
+    }
+
+
+    // -------------------------------------------------------------- Variables
+
+
+    /**
+     * The string manager for this package.
+     */
+    protected static StringManager sm =
+        StringManager.getManager(Constants.Package);
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * Associated Coyote response.
+     */
+    protected Response response;
+
+
+    /**
+     * Headers of the associated request.
+     */
+    protected MimeHeaders headers;
+
+
+    /**
+     * Committed flag.
+     */
+    protected boolean committed;
+
+
+    /**
+     * Finished flag.
+     */
+    protected boolean finished;
+
+
+    /**
+     * Pointer to the current read buffer.
+     */
+    protected byte[] buf;
+
+
+    /**
+     * Position in the buffer.
+     */
+    protected int pos;
+
+
+    /**
+     * HTTP header buffer.
+     */
+    protected byte[] headerBuffer;
+
+
+    /**
+     * Underlying output stream.
+     */
+    protected OutputStream outputStream;
+
+
+    /**
+     * Underlying output buffer.
+     */
+    protected OutputBuffer outputStreamOutputBuffer;
+
+
+    /**
+     * Filter library.
+     * Note: Filter[0] is always the "chunked" filter.
+     */
+    protected OutputFilter[] filterLibrary;
+
+
+    /**
+     * Active filter (which is actually the top of the pipeline).
+     */
+    protected OutputFilter[] activeFilters;
+
+
+    /**
+     * Index of the last active filter.
+     */
+    protected int lastActiveFilter;
+
+
+    /**
+     * Socket buffer.
+     */
+    protected ByteChunk socketBuffer;
+
+
+    /**
+     * Socket buffer (extra buffering to reduce number of packets sent).
+     */
+    protected boolean useSocketBuffer = false;
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * Set the underlying socket output stream.
+     */
+    public void setOutputStream(OutputStream outputStream) {
+
+        // FIXME: Check for null ?
+
+        this.outputStream = outputStream;
+
+    }
+
+
+    /**
+     * Get the underlying socket output stream.
+     */
+    public OutputStream getOutputStream() {
+
+        return outputStream;
+
+    }
+
+
+    /**
+     * Set the socket buffer size.
+     */
+    public void setSocketBuffer(int socketBufferSize) {
+
+        if (socketBufferSize > 500) {
+            useSocketBuffer = true;
+            socketBuffer.allocate(socketBufferSize, socketBufferSize);
+        } else {
+            useSocketBuffer = false;
+        }
+
+    }
+
+
+    /**
+     * Add an output filter to the filter library.
+     */
+    public void addFilter(OutputFilter filter) {
+
+        OutputFilter[] newFilterLibrary = 
+            new OutputFilter[filterLibrary.length + 1];
+        for (int i = 0; i < filterLibrary.length; i++) {
+            newFilterLibrary[i] = filterLibrary[i];
+        }
+        newFilterLibrary[filterLibrary.length] = filter;
+        filterLibrary = newFilterLibrary;
+
+        activeFilters = new OutputFilter[filterLibrary.length];
+
+    }
+
+
+    /**
+     * Get filters.
+     */
+    public OutputFilter[] getFilters() {
+
+        return filterLibrary;
+
+    }
+
+
+    /**
+     * Clear filters.
+     */
+    public void clearFilters() {
+
+        filterLibrary = new OutputFilter[0];
+        lastActiveFilter = -1;
+
+    }
+
+
+    /**
+     * Add an output filter to the filter library.
+     */
+    public void addActiveFilter(OutputFilter filter) {
+
+        if (lastActiveFilter == -1) {
+            filter.setBuffer(outputStreamOutputBuffer);
+        } else {
+            for (int i = 0; i <= lastActiveFilter; i++) {
+                if (activeFilters[i] == filter)
+                    return;
+            }
+            filter.setBuffer(activeFilters[lastActiveFilter]);
+        }
+
+        activeFilters[++lastActiveFilter] = filter;
+
+        filter.setResponse(response);
+
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Flush the response.
+     * 
+     * @throws IOException an undelying I/O error occured
+     */
+    public void flush()
+        throws IOException {
+
+        if (!committed) {
+
+            // Send the connector a request for commit. The connector should
+            // then validate the headers, send them (using sendHeader) and 
+            // set the filters accordingly.
+            response.action(ActionCode.ACTION_COMMIT, null);
+
+        }
+
+        // Flush the current buffer
+        if (useSocketBuffer) {
+            socketBuffer.flushBuffer();
+        }
+
+    }
+
+
+    /**
+     * Reset current response.
+     * 
+     * @throws IllegalStateException if the response has already been committed
+     */
+    public void reset() {
+
+        if (committed)
+            throw new IllegalStateException(/*FIXME:Put an error message*/);
+
+        // Recycle Request object
+        response.recycle();
+
+    }
+
+
+    /**
+     * Recycle the output buffer. This should be called when closing the 
+     * connection.
+     */
+    public void recycle() {
+
+        // Recycle Request object
+        response.recycle();
+        socketBuffer.recycle();
+
+        outputStream = null;
+        buf = headerBuffer;
+        pos = 0;
+        lastActiveFilter = -1;
+        committed = false;
+        finished = false;
+
+    }
+
+
+    /**
+     * End processing of current HTTP request.
+     * Note: All bytes of the current request should have been already 
+     * consumed. This method only resets all the pointers so that we are ready
+     * to parse the next HTTP request.
+     */
+    public void nextRequest() {
+
+        // Recycle Request object
+        response.recycle();
+        socketBuffer.recycle();
+
+        // Determine the header buffer used for next request
+        buf = headerBuffer;
+
+        // Recycle filters
+        for (int i = 0; i <= lastActiveFilter; i++) {
+            activeFilters[i].recycle();
+        }
+
+        // Reset pointers
+        pos = 0;
+        lastActiveFilter = -1;
+        committed = false;
+        finished = false;
+
+    }
+
+
+    /**
+     * End request.
+     * 
+     * @throws IOException an undelying I/O error occured
+     */
+    public void endRequest()
+        throws IOException {
+
+        if (!committed) {
+
+            // Send the connector a request for commit. The connector should
+            // then validate the headers, send them (using sendHeader) and 
+            // set the filters accordingly.
+            response.action(ActionCode.ACTION_COMMIT, null);
+
+        }
+
+        if (finished)
+            return;
+
+        if (lastActiveFilter != -1)
+            activeFilters[lastActiveFilter].end();
+
+        if (useSocketBuffer) {
+            socketBuffer.flushBuffer();
+        }
+
+        finished = true;
+
+    }
+
+
+    // ------------------------------------------------ HTTP/1.1 Output Methods
+
+
+    /**
+     * Send an acknoledgement.
+     */
+    public void sendAck()
+        throws IOException {
+
+        if (!committed)
+            outputStream.write(Constants.ACK_BYTES);
+
+    }
+
+
+    /**
+     * Send the response status line.
+     */
+    public void sendStatus() {
+
+        // Write protocol name
+        write(Constants.HTTP_11_BYTES);
+        buf[pos++] = Constants.SP;
+
+        // Write status code
+        int status = response.getStatus();
+        switch (status) {
+        case 200:
+            write(Constants._200_BYTES);
+            break;
+        case 400:
+            write(Constants._400_BYTES);
+            break;
+        case 404:
+            write(Constants._404_BYTES);
+            break;
+        default:
+            write(status);
+        }
+
+        buf[pos++] = Constants.SP;
+
+        // Write message
+        String message = response.getMessage();
+        if (message == null) {
+            write(getMessage(status));
+        } else {
+            write(message);
+        }
+
+        // End the response status line
+        if (System.getSecurityManager() != null){
+           AccessController.doPrivileged(
+                new PrivilegedAction(){
+                    public Object run(){
+                        buf[pos++] = Constants.CR;
+                        buf[pos++] = Constants.LF;
+                        return null;
+                    }
+                }
+           );
+        } else {
+            buf[pos++] = Constants.CR;
+            buf[pos++] = Constants.LF;
+        }
+
+    }
+
+    private String getMessage(final int message){
+        if (System.getSecurityManager() != null){
+           return (String)AccessController.doPrivileged(
+                new PrivilegedAction(){
+                    public Object run(){
+                        return HttpMessages.getMessage(message); 
+                    }
+                }
+           );
+        } else {
+            return HttpMessages.getMessage(message);
+        }
+    }
+
+    /**
+     * Send a header.
+     * 
+     * @param name Header name
+     * @param value Header value
+     */
+    public void sendHeader(MessageBytes name, MessageBytes value) {
+
+        write(name);
+        buf[pos++] = Constants.COLON;
+        buf[pos++] = Constants.SP;
+        write(value);
+        buf[pos++] = Constants.CR;
+        buf[pos++] = Constants.LF;
+
+    }
+
+
+    /**
+     * Send a header.
+     * 
+     * @param name Header name
+     * @param value Header value
+     */
+    public void sendHeader(ByteChunk name, ByteChunk value) {
+
+        write(name);
+        buf[pos++] = Constants.COLON;
+        buf[pos++] = Constants.SP;
+        write(value);
+        buf[pos++] = Constants.CR;
+        buf[pos++] = Constants.LF;
+
+    }
+
+
+    /**
+     * Send a header.
+     * 
+     * @param name Header name
+     * @param value Header value
+     */
+    public void sendHeader(String name, String value) {
+
+        write(name);
+        buf[pos++] = Constants.COLON;
+        buf[pos++] = Constants.SP;
+        write(value);
+        buf[pos++] = Constants.CR;
+        buf[pos++] = Constants.LF;
+
+    }
+
+
+    /**
+     * End the header block.
+     */
+    public void endHeaders() {
+
+        buf[pos++] = Constants.CR;
+        buf[pos++] = Constants.LF;
+
+    }
+
+
+    // --------------------------------------------------- OutputBuffer Methods
+
+
+    /**
+     * Write the contents of a byte chunk.
+     * 
+     * @param chunk byte chunk
+     * @return number of bytes written
+     * @throws IOException an undelying I/O error occured
+     */
+    public int doWrite(ByteChunk chunk, Response res) 
+        throws IOException {
+
+        if (!committed) {
+
+            // Send the connector a request for commit. The connector should
+            // then validate the headers, send them (using sendHeaders) and 
+            // set the filters accordingly.
+            response.action(ActionCode.ACTION_COMMIT, null);
+
+        }
+
+        if (lastActiveFilter == -1)
+            return outputStreamOutputBuffer.doWrite(chunk, res);
+        else
+            return activeFilters[lastActiveFilter].doWrite(chunk, res);
+
+    }
+
+
+    // ------------------------------------------------------ Protected Methods
+
+
+    /**
+     * Commit the response.
+     * 
+     * @throws IOException an undelying I/O error occured
+     */
+    protected void commit()
+        throws IOException {
+
+        // The response is now committed
+        committed = true;
+        response.setCommitted(true);
+
+        if (pos > 0) {
+            // Sending the response header buffer
+            if (useSocketBuffer) {
+                socketBuffer.append(buf, 0, pos);
+            } else {
+                outputStream.write(buf, 0, pos);
+            }
+        }
+
+    }
+
+
+    /**
+     * This method will write the contents of the specyfied message bytes 
+     * buffer to the output stream, without filtering. This method is meant to
+     * be used to write the response header.
+     * 
+     * @param mb data to be written
+     */
+    protected void write(MessageBytes mb) {
+
+        if (mb.getType() == MessageBytes.T_BYTES) {
+            ByteChunk bc = mb.getByteChunk();
+            write(bc);
+        } else if (mb.getType() == MessageBytes.T_CHARS) {
+            CharChunk cc = mb.getCharChunk();
+            write(cc);
+        } else {
+            write(mb.toString());
+        }
+
+    }
+
+
+    /**
+     * This method will write the contents of the specyfied message bytes 
+     * buffer to the output stream, without filtering. This method is meant to
+     * be used to write the response header.
+     * 
+     * @param bc data to be written
+     */
+    protected void write(ByteChunk bc) {
+
+        // Writing the byte chunk to the output buffer
+        System.arraycopy(bc.getBytes(), bc.getStart(), buf, pos,
+                         bc.getLength());
+        pos = pos + bc.getLength();
+
+    }
+
+
+    /**
+     * This method will write the contents of the specyfied char 
+     * buffer to the output stream, without filtering. This method is meant to
+     * be used to write the response header.
+     * 
+     * @param cc data to be written
+     */
+    protected void write(CharChunk cc) {
+
+        int start = cc.getStart();
+        int end = cc.getEnd();
+        char[] cbuf = cc.getBuffer();
+        for (int i = start; i < end; i++) {
+            char c = cbuf[i];
+            // Note:  This is clearly incorrect for many strings,
+            // but is the only consistent approach within the current
+            // servlet framework.  It must suffice until servlet output
+            // streams properly encode their output.
+            if ((c <= 31) && (c != 9)) {
+                c = ' ';
+            } else if (c == 127) {
+                c = ' ';
+            }
+            buf[pos++] = (byte) c;
+        }
+
+    }
+
+
+    /**
+     * This method will write the contents of the specyfied byte 
+     * buffer to the output stream, without filtering. This method is meant to
+     * be used to write the response header.
+     * 
+     * @param b data to be written
+     */
+    public void write(byte[] b) {
+
+        // Writing the byte chunk to the output buffer
+        System.arraycopy(b, 0, buf, pos, b.length);
+        pos = pos + b.length;
+
+    }
+
+
+    /**
+     * This method will write the contents of the specyfied String to the 
+     * output stream, without filtering. This method is meant to be used to 
+     * write the response header.
+     * 
+     * @param s data to be written
+     */
+    protected void write(String s) {
+
+        if (s == null)
+            return;
+
+        // From the Tomcat 3.3 HTTP/1.0 connector
+        int len = s.length();
+        for (int i = 0; i < len; i++) {
+            char c = s.charAt (i);
+            // Note:  This is clearly incorrect for many strings,
+            // but is the only consistent approach within the current
+            // servlet framework.  It must suffice until servlet output
+            // streams properly encode their output.
+            if ((c <= 31) && (c != 9)) {
+                c = ' ';
+            } else if (c == 127) {
+                c = ' ';
+            }
+            buf[pos++] = (byte) c;
+        }
+
+    }
+
+
+    /**
+     * This method will print the specified integer to the output stream, 
+     * without filtering. This method is meant to be used to write the 
+     * response header.
+     * 
+     * @param i data to be written
+     */
+    protected void write(int i) {
+
+        write(String.valueOf(i));
+
+    }
+
+
+    /**
+     * Callback to write data from the buffer.
+     */
+    public void realWriteBytes(byte cbuf[], int off, int len)
+        throws IOException {
+        if (len > 0) {
+            outputStream.write(cbuf, off, len);
+        }
+    }
+
+
+    // ----------------------------------- OutputStreamOutputBuffer Inner Class
+
+
+    /**
+     * This class is an output buffer which will write data to an output
+     * stream.
+     */
+    protected class OutputStreamOutputBuffer 
+        implements OutputBuffer {
+
+
+        /**
+         * Write chunk.
+         */
+        public int doWrite(ByteChunk chunk, Response res) 
+            throws IOException {
+
+            if (useSocketBuffer) {
+                socketBuffer.append(chunk.getBuffer(), chunk.getStart(), 
+                                   chunk.getLength());
+            } else {
+                outputStream.write(chunk.getBuffer(), chunk.getStart(), 
+                                   chunk.getLength());
+            }
+            return chunk.getLength();
+
+        }
+
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/http11/src/java/org/apache/coyote/http11/LocalStrings.properties
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/http11/src/java/org/apache/coyote/http11/LocalStrings.properties	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/http11/src/java/org/apache/coyote/http11/LocalStrings.properties	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,52 @@
+# $Id: LocalStrings.properties 414658 2006-06-15 19:21:24Z yoavs $
+
+# language 
+
+# package org.apache.coyote.http11
+
+#
+# Http11Protocol
+#
+
+http11protocol.endpoint.initerror=Error initializing endpoint
+http11protocol.endpoint.starterror=Error starting endpoint
+http11protocol.init=Initializing Coyote HTTP/1.1 on {0}
+http11protocol.proto.error=Error reading request, ignored
+http11protocol.proto.ioexception.debug=IOException reading request
+http11protocol.proto.ioexception.info=IOException reading request, ignored
+http11protocol.proto.socketexception.debug=SocketException reading request
+http11protocol.proto.socketexception.info=SocketException reading request, ignored
+http11protocol.getattribute=Attribute {0}
+http11protocol.setattribute=Attribute {0}: {1}
+http11protocol.socketfactory.initerror=Error initializing socket factory
+http11protocol.start=Starting Coyote HTTP/1.1 on {0}
+http11protocol.stop=Stopping Coyote HTTP/1.1 on {0}
+http11protocol.pause=Pausing Coyote HTTP/1.1 on {0}
+http11protocol.endpoint.pauseerror=Error pausing endpoint
+http11protocol.resume=Resuming Coyote HTTP/1.1 on {0}
+http11protocol.endpoint.resumeerror=Error resuming endpoint
+
+#
+# Http11Processor
+#
+
+http11processor.regexp.error=Error parsing regular expression {0}
+http11processor.filter.unknown=Unknown filter {0}
+http11processor.filter.error=Error intializing filter {0}
+http11processor.header.parse=Error parsing HTTP request header
+http11processor.request.prepare=Error preparing request
+http11processor.request.process=Error processing request
+http11processor.request.finish=Error finishing request
+http11processor.response.finish=Error finishing response
+http11processor.socket.info=Exception getting socket information
+http11processor.socket.ssl=Exception getting SSL attributes
+http11processor.socket.timeout=Error setting socket timeout
+
+#
+# InternalInputBuffer
+#
+
+iib.eof.error=Unexpected EOF read on the socket
+iib.failedread=Exception filling buffer with data from underlying input stream: not an EAGAIN status, so perhaps disconnected client?
+iib.requestheadertoolarge.error=Request header is too large
+

Added: branches/tomcat5.5/upstream/5.5.20/connectors/http11/src/java/org/apache/coyote/http11/LocalStrings_es.properties
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/http11/src/java/org/apache/coyote/http11/LocalStrings_es.properties	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/http11/src/java/org/apache/coyote/http11/LocalStrings_es.properties	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,34 @@
+# $Id: LocalStrings_es.properties 299220 2004-02-24 08:50:56Z hgomez $
+
+# language es
+
+# package org.apache.coyote.http11
+
+#
+# Http11Protocol
+#
+
+http11protocol.endpoint.initerror=Error inicializando punto final (endpoint)
+http11protocol.endpoint.starterror=Error arrancando punto final (endpoint)
+http11protocol.init=Inicializando Coyote HTTP/1.1 en puerto {0}
+http11protocol.proto.error=Error leyendo requerimiento, ignorado
+http11protocol.proto.ioexception.debug=IOException leyendo requerimiento
+http11protocol.proto.ioexception.info=IOException leyendo requerimiento, ignorada
+http11protocol.proto.socketexception.debug=SocketException leyendo requerimiento
+http11protocol.proto.socketexception.info=SocketException leyendo requerimiento, ignorada
+http11protocol.getattribute=Atributo {0}
+http11protocol.setattribute=Atributo {0}: {1}
+http11protocol.socketfactory.initerror=Error inicializando fábrica de enchufes (sockets)
+http11protocol.start=Arrancando Coyote HTTP/1.1 en puerto {0}
+
+#
+# Http11Processor
+#
+
+#
+# InternalInputBuffer
+#
+
+iib.eof.error=Inesperado Fin De Archivo (EOF) leído en el enchufe (socket)
+iib.requestheadertoolarge.error=La cabecera del requerimiento es demasido grande
+

Added: branches/tomcat5.5/upstream/5.5.20/connectors/http11/src/java/org/apache/coyote/http11/LocalStrings_fr.properties
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/http11/src/java/org/apache/coyote/http11/LocalStrings_fr.properties	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/http11/src/java/org/apache/coyote/http11/LocalStrings_fr.properties	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,36 @@
+# $Id: LocalStrings_fr.properties 299220 2004-02-24 08:50:56Z hgomez $
+
+# language fr
+
+# package org.apache.coyote.http11
+
+#
+# Http11Protocol
+#
+
+http11protocol.endpoint.initerror=Erreur à l'initialisation du point de contact
+http11protocol.endpoint.starterror=Erreur au démarrage du point de contact
+http11protocol.init=Initialisation de Coyote HTTP/1.1 sur {0}
+http11protocol.proto.error=Erreur à la lecture de la requête, ignoré
+http11protocol.proto.ioexception.debug=Exception d'entrée/sortie (IOException) à la lecture de la requête
+http11protocol.proto.ioexception.info=Exception d'entrée/sortie à la lecture de la requête, ignoré
+http11protocol.proto.socketexception.debug=Exception "Socket" (SocketException) à la lecture de la requête
+http11protocol.proto.socketexception.info=Exception "Socket" (SocketException) à la lecture de la requête, ignoré
+http11protocol.setattribute=Attribut {0}: {1}
+http11protocol.socketfactory.initerror=Erreur à l'initialisation du créateur de socket (socket factory)
+http11protocol.start=Démarrage de Coyote HTTP/1.1 sur {0}
+http11protocol.stop=Arrêt de Coyote HTTP/1.1 sur {0}
+http11protocol.pause=Suspension de Coyote HTTP/1.1 sur {0}
+http11protocol.resume=Redémarrage de Coyote HTTP/1.1 sur {0}
+
+#
+# Http11Processor
+#
+
+#
+# InternalInputBuffer
+#
+
+iib.eof.error=Fin de flux (EOF) inattendue à la lecture sur la socket
+iib.requestheadertoolarge.error=L'entête de requête est trop important
+

Added: branches/tomcat5.5/upstream/5.5.20/connectors/http11/src/java/org/apache/coyote/http11/LocalStrings_ja.properties
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/http11/src/java/org/apache/coyote/http11/LocalStrings_ja.properties	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/http11/src/java/org/apache/coyote/http11/LocalStrings_ja.properties	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,39 @@
+# $Id: LocalStrings_ja.properties 299758 2004-08-30 17:29:47Z amyroh $
+
+# language ja
+
+# package org.apache.coyote.http11
+
+#
+# Http11Protocol
+#
+
+http11protocol.endpoint.initerror=\u30a8\u30f3\u30c9\u30dd\u30a4\u30f3\u30c8\u3092\u521d\u671f\u5316\u4e2d\u306e\u30a8\u30e9\u30fc\u3067\u3059
+http11protocol.endpoint.starterror=\u30a8\u30f3\u30c9\u30dd\u30a4\u30f3\u30c8\u3092\u8d77\u52d5\u4e2d\u306e\u30a8\u30e9\u30fc\u3067\u3059
+http11protocol.init=Coyote HTTP/1.1\u3092 {0} \u3067\u521d\u671f\u5316\u3057\u307e\u3059
+http11protocol.proto.error=\u30ea\u30af\u30a8\u30b9\u30c8\u3092\u8aad\u307f\u8fbc\u307f\u4e2d\u306e\u30a8\u30e9\u30fc\u3067\u3059\u304c\u3001\u7121\u8996\u3055\u308c\u307e\u3057\u305f
+http11protocol.proto.ioexception.debug=\u30ea\u30af\u30a8\u30b9\u30c8\u3092\u8aad\u307f\u8fbc\u307f\u4e2d\u306eIOException\u3067\u3059
+http11protocol.proto.ioexception.info=\u30ea\u30af\u30a8\u30b9\u30c8\u3092\u8aad\u307f\u8fbc\u307f\u4e2d\u306eIOException\u3067\u3059\u304c\u3001\u7121\u8996\u3055\u308c\u307e\u3057\u305f
+http11protocol.proto.socketexception.debug=\u30ea\u30af\u30a8\u30b9\u30c8\u3092\u8aad\u307f\u8fbc\u307f\u4e2d\u306eSocketException\u3067\u3059
+http11protocol.proto.socketexception.info=\u30ea\u30af\u30a8\u30b9\u30c8\u3092\u8aad\u307f\u8fbc\u307f\u4e2d\u306eSocketException\u3067\u3059\u304c\u3001\u7121\u8996\u3055\u308c\u307e\u3057\u305f
+http11protocol.setattribute=\u5c5e\u6027 {0}: {1}
+http11protocol.socketfactory.initerror=\u30bd\u30b1\u30c3\u30c8\u30d5\u30a1\u30af\u30c8\u30ea\u3092\u521d\u671f\u5316\u4e2d\u306e\u30a8\u30e9\u30fc\u3067\u3059
+http11protocol.start=Coyote HTTP/1.1\u3092 {0} \u3067\u8d77\u52d5\u3057\u307e\u3059
+http11protocol.stop=Coyote HTTP/1.1\u3092 {0} \u3067\u505c\u6b62\u3057\u307e\u3059
+http11protocol.pause=Coyote HTTP/1.1\u3092 {0} \u3067\u4e00\u6642\u505c\u6b62\u3057\u307e\u3059
+http11protocol.endpoint.pauseerror=\u30a8\u30f3\u30c9\u30dd\u30a4\u30f3\u30c8\u306e\u4e00\u6642\u505c\u6b62\u4e2d\u306e\u30a8\u30e9\u30fc\u3067\u3059
+http11protocol.resume=Coyote HTTP/1.1\u3092 {0} \u3067\u518d\u958b\u3057\u307e\u3059
+http11protocol.endpoint.resumeerror=\u30a8\u30f3\u30c9\u30dd\u30a4\u30f3\u30c8\u306e\u518d\u958b\u4e2d\u306e\u30a8\u30e9\u30fc\u3067\u3059
+ 
+
+#
+# Http11Processor
+#
+
+#
+# InternalInputBuffer
+#
+
+iib.eof.error=\u30bd\u30b1\u30c3\u30c8\u304b\u3089\u4e88\u671f\u3057\u306a\u3044EOF\u3092\u8aad\u307f\u8fbc\u307f\u307e\u3057\u305f
+iib.requestheadertoolarge.error=\u30ea\u30af\u30a8\u30b9\u30c8\u30d8\u30c3\u30c0\u304c\u9577\u3059\u304e\u307e\u3059
+

Added: branches/tomcat5.5/upstream/5.5.20/connectors/http11/src/java/org/apache/coyote/http11/OutputFilter.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/http11/src/java/org/apache/coyote/http11/OutputFilter.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/http11/src/java/org/apache/coyote/http11/OutputFilter.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,82 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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;
+
+import java.io.IOException;
+
+import org.apache.tomcat.util.buf.ByteChunk;
+
+import org.apache.coyote.OutputBuffer;
+import org.apache.coyote.Response;
+
+/**
+ * Output filter.
+ * 
+ * @author Remy Maucherat
+ */
+public interface OutputFilter extends OutputBuffer {
+
+
+    /**
+     * Write some bytes.
+     * 
+     * @return number of bytes written by the filter
+     */
+    public int doWrite(ByteChunk chunk, Response unused)
+        throws IOException;
+
+
+    /**
+     * Some filters need additional parameters from the response. All the 
+     * necessary reading can occur in that method, as this method is called
+     * after the response header processing is complete.
+     */
+    public void setResponse(Response response);
+
+
+    /**
+     * Make the filter ready to process the next request.
+     */
+    public void recycle();
+
+
+    /**
+     * Get the name of the encoding handled by this filter.
+     */
+    public ByteChunk getEncodingName();
+
+
+    /**
+     * Set the next buffer in the filter pipeline.
+     */
+    public void setBuffer(OutputBuffer buffer);
+
+
+    /**
+     * End the current request. It is acceptable to write extra bytes using
+     * buffer.doWrite during the execution of this method.
+     * 
+     * @return Should return 0 unless the filter does some content length 
+     * delimitation, in which case the number is the amount of extra bytes or
+     * missing bytes, which would indicate an error. 
+     * Note: It is recommended that extra bytes be swallowed by the filter.
+     */
+    public long end()
+        throws IOException;
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/http11/src/java/org/apache/coyote/http11/filters/BufferedInputFilter.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/http11/src/java/org/apache/coyote/http11/filters/BufferedInputFilter.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/http11/src/java/org/apache/coyote/http11/filters/BufferedInputFilter.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,122 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.filters;
+
+import java.io.IOException;
+import org.apache.coyote.Request;
+import org.apache.coyote.InputBuffer;
+import org.apache.coyote.http11.InputFilter;
+import org.apache.tomcat.util.buf.ByteChunk;
+
+/**
+ * Input filter responsible for reading and buffering the request body, so that
+ * it does not interfere with client SSL handshake messages.
+ */
+public class BufferedInputFilter implements InputFilter {
+
+    // -------------------------------------------------------------- Constants
+
+    private static final String ENCODING_NAME = "buffered";
+    private static final ByteChunk ENCODING = new ByteChunk();
+
+
+    // ----------------------------------------------------- Instance Variables
+
+    private ByteChunk buffered = null;
+    private ByteChunk tempRead = new ByteChunk(1024);
+    private InputBuffer buffer;
+    private boolean hasRead = false;
+
+
+    // ----------------------------------------------------- Static Initializer
+
+    static {
+        ENCODING.setBytes(ENCODING_NAME.getBytes(), 0, ENCODING_NAME.length());
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Set the buffering limit. This should be reset every time the buffer is
+     * used.
+     */
+    public void setLimit(int limit) {
+        if (buffered == null) {
+            buffered = new ByteChunk(4048);
+            buffered.setLimit(limit);
+        }
+    }
+
+
+    // ---------------------------------------------------- InputBuffer Methods
+
+
+    /**
+     * Reads the request body and buffers it.
+     */
+    public void setRequest(Request request) {
+        // save off the Request body
+        try {
+            while (buffer.doRead(tempRead, request) >= 0) {
+                buffered.append(tempRead);
+                tempRead.recycle();
+            }
+        } catch(IOException iex) {
+            // Ignore
+        }
+    }
+
+    /**
+     * Fills the given ByteChunk with the buffered request body.
+     */
+    public int doRead(ByteChunk chunk, Request request) throws IOException {
+        if (hasRead || buffered.getLength() <= 0) {
+            return -1;
+        } else {
+            chunk.setBytes(buffered.getBytes(), buffered.getStart(),
+                           buffered.getLength());
+            hasRead = true;
+        }
+        return chunk.getLength();
+    }
+
+    public void setBuffer(InputBuffer buffer) {
+        this.buffer = buffer;
+    }
+
+    public void recycle() {
+        if (buffered.getBuffer().length > 65536) {
+            buffered = null;
+        } else {
+            buffered.recycle();
+        }
+        tempRead.recycle();
+        hasRead = false;
+        buffer = null;
+    }
+
+    public ByteChunk getEncodingName() {
+        return ENCODING;
+    }
+
+    public long end() throws IOException {
+        return 0;
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/http11/src/java/org/apache/coyote/http11/filters/ChunkedInputFilter.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/http11/src/java/org/apache/coyote/http11/filters/ChunkedInputFilter.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/http11/src/java/org/apache/coyote/http11/filters/ChunkedInputFilter.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,325 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.filters;
+
+import java.io.IOException;
+
+import org.apache.tomcat.util.buf.ByteChunk;
+import org.apache.tomcat.util.buf.HexUtils;
+
+import org.apache.coyote.InputBuffer;
+import org.apache.coyote.Request;
+import org.apache.coyote.http11.Constants;
+import org.apache.coyote.http11.InputFilter;
+
+/**
+ * Chunked input filter.
+ * 
+ * @author Remy Maucherat
+ */
+public class ChunkedInputFilter implements InputFilter {
+
+
+    // -------------------------------------------------------------- Constants
+
+
+    protected static final String ENCODING_NAME = "chunked";
+    protected static final ByteChunk ENCODING = new ByteChunk();
+
+
+    // ----------------------------------------------------- Static Initializer
+
+
+    static {
+        ENCODING.setBytes(ENCODING_NAME.getBytes(), 0, ENCODING_NAME.length());
+    }
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * Next buffer in the pipeline.
+     */
+    protected InputBuffer buffer;
+
+
+    /**
+     * Number of bytes remaining in the current chunk.
+     */
+    protected int remaining = 0;
+
+
+    /**
+     * Position in the buffer.
+     */
+    protected int pos = 0;
+
+
+    /**
+     * Last valid byte in the buffer.
+     */
+    protected int lastValid = 0;
+
+
+    /**
+     * Read bytes buffer.
+     */
+    protected byte[] buf = null;
+
+
+    /**
+     * Byte chunk used to read bytes.
+     */
+    protected ByteChunk readChunk = new ByteChunk();
+
+
+    /**
+     * Flag set to true when the end chunk has been read.
+     */
+    protected boolean endChunk = false;
+
+    /**
+     * Flag set to true if the next call to doRead() must parse a CRLF pair
+     * before doing anything else.
+     */
+    protected boolean needCRLFParse = false;
+
+    // ------------------------------------------------------------- Properties
+
+
+    // ---------------------------------------------------- InputBuffer Methods
+
+
+    /**
+     * Read bytes.
+     * 
+     * @return If the filter does request length control, this value is
+     * significant; it should be the number of bytes consumed from the buffer,
+     * up until the end of the current request body, or the buffer length, 
+     * whichever is greater. If the filter does not do request body length
+     * control, the returned value should be -1.
+     */
+    public int doRead(ByteChunk chunk, Request req)
+        throws IOException {
+
+        if (endChunk)
+            return -1;
+
+        if(needCRLFParse) {
+            needCRLFParse = false;
+            parseCRLF();
+        }
+
+        if (remaining <= 0) {
+            if (!parseChunkHeader()) {
+                throw new IOException("Invalid chunk");
+            }
+            if (endChunk) {
+                parseEndChunk();
+                return -1;
+            }
+        }
+
+        int result = 0;
+
+        if (pos >= lastValid) {
+            readBytes();
+        }
+
+        if (remaining > (lastValid - pos)) {
+            result = lastValid - pos;
+            remaining = remaining - result;
+            chunk.setBytes(buf, pos, result);
+            pos = lastValid;
+        } else {
+            result = remaining;
+            chunk.setBytes(buf, pos, remaining);
+            pos = pos + remaining;
+            remaining = 0;
+            needCRLFParse = true;
+        }
+
+        return result;
+
+    }
+
+
+    // ---------------------------------------------------- InputFilter Methods
+
+
+    /**
+     * Read the content length from the request.
+     */
+    public void setRequest(Request request) {
+    }
+
+
+    /**
+     * End the current request.
+     */
+    public long end()
+        throws IOException {
+
+        // Consume extra bytes : parse the stream until the end chunk is found
+        while (doRead(readChunk, null) >= 0) {
+        }
+
+        // Return the number of extra bytes which were consumed
+        return (lastValid - pos);
+
+    }
+
+
+    /**
+     * Set the next buffer in the filter pipeline.
+     */
+    public void setBuffer(InputBuffer buffer) {
+        this.buffer = buffer;
+    }
+
+
+    /**
+     * Make the filter ready to process the next request.
+     */
+    public void recycle() {
+        remaining = 0;
+        pos = 0;
+        lastValid = 0;
+        endChunk = false;
+    }
+
+
+    /**
+     * Return the name of the associated encoding; Here, the value is 
+     * "identity".
+     */
+    public ByteChunk getEncodingName() {
+        return ENCODING;
+    }
+
+
+    // ------------------------------------------------------ Protected Methods
+
+
+    /**
+     * Read bytes from the previous buffer.
+     */
+    protected int readBytes()
+        throws IOException {
+
+        int nRead = buffer.doRead(readChunk, null);
+        pos = readChunk.getStart();
+        lastValid = pos + nRead;
+        buf = readChunk.getBytes();
+
+        return nRead;
+
+    }
+
+
+    /**
+     * Parse the header of a chunk.
+     */
+    protected boolean parseChunkHeader()
+        throws IOException {
+
+        int result = 0;
+        boolean eol = false;
+        boolean readDigit = false;
+
+        while (!eol) {
+
+            if (pos >= lastValid) {
+                if (readBytes() <= 0)
+                    return false;
+            }
+
+            if (buf[pos] == Constants.CR) {
+            } else if (buf[pos] == Constants.LF) {
+                eol = true;
+            } else {
+                if (HexUtils.DEC[buf[pos]] != -1) {
+                    readDigit = true;
+                    result *= 16;
+                    result += HexUtils.DEC[buf[pos]];
+                }
+            }
+
+            pos++;
+
+        }
+
+        if (!readDigit)
+            return false;
+
+        if (result == 0)
+            endChunk = true;
+
+        remaining = result;
+        if (remaining < 0)
+            return false;
+
+        return true;
+
+    }
+
+
+    /**
+     * Parse CRLF at end of chunk.
+     */
+    protected boolean parseCRLF()
+        throws IOException {
+
+        boolean eol = false;
+
+        while (!eol) {
+
+            if (pos >= lastValid) {
+                if (readBytes() <= 0)
+                    throw new IOException("Invalid CRLF");
+            }
+
+            if (buf[pos] == Constants.CR) {
+            } else if (buf[pos] == Constants.LF) {
+                eol = true;
+            } else {
+                throw new IOException("Invalid CRLF");
+            }
+
+            pos++;
+
+        }
+
+        return true;
+
+    }
+
+
+    /**
+     * Parse end chunk data.
+     * FIXME: Handle trailers
+     */
+    protected boolean parseEndChunk()
+        throws IOException {
+
+        return parseCRLF(); // FIXME
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/http11/src/java/org/apache/coyote/http11/filters/ChunkedOutputFilter.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/http11/src/java/org/apache/coyote/http11/filters/ChunkedOutputFilter.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/http11/src/java/org/apache/coyote/http11/filters/ChunkedOutputFilter.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,186 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.filters;
+
+import java.io.IOException;
+
+import org.apache.tomcat.util.buf.ByteChunk;
+import org.apache.tomcat.util.buf.HexUtils;
+
+import org.apache.coyote.OutputBuffer;
+import org.apache.coyote.Response;
+import org.apache.coyote.http11.OutputFilter;
+
+/**
+ * Chunked output filter.
+ * 
+ * @author Remy Maucherat
+ */
+public class ChunkedOutputFilter implements OutputFilter {
+
+
+    // -------------------------------------------------------------- Constants
+
+
+    protected static final String ENCODING_NAME = "chunked";
+    protected static final ByteChunk ENCODING = new ByteChunk();
+
+
+    /**
+     * End chunk.
+     */
+    protected static final ByteChunk END_CHUNK = new ByteChunk();
+
+
+    // ----------------------------------------------------- Static Initializer
+
+
+    static {
+        ENCODING.setBytes(ENCODING_NAME.getBytes(), 0, ENCODING_NAME.length());
+        byte[] END_CHUNK_BYTES = {(byte) '0', (byte) '\r', (byte) '\n', 
+                                  (byte) '\r', (byte) '\n'};
+        END_CHUNK.setBytes(END_CHUNK_BYTES, 0, END_CHUNK_BYTES.length);
+    }
+
+
+    // ------------------------------------------------------------ Constructor
+
+
+    /**
+     * Default constructor.
+     */
+    public ChunkedOutputFilter() {
+        chunkLength = new byte[10];
+        chunkLength[8] = (byte) '\r';
+        chunkLength[9] = (byte) '\n';
+    }
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * Next buffer in the pipeline.
+     */
+    protected OutputBuffer buffer;
+
+
+    /**
+     * Buffer used for chunk length conversion.
+     */
+    protected byte[] chunkLength = new byte[10];
+
+
+    /**
+     * Chunk header.
+     */
+    protected ByteChunk chunkHeader = new ByteChunk();
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    // --------------------------------------------------- OutputBuffer Methods
+
+
+    /**
+     * Write some bytes.
+     * 
+     * @return number of bytes written by the filter
+     */
+    public int doWrite(ByteChunk chunk, Response res)
+        throws IOException {
+
+        int result = chunk.getLength();
+
+        if (result <= 0) {
+            return 0;
+        }
+
+        // Calculate chunk header
+        int pos = 7;
+        int current = result;
+        while (current > 0) {
+            int digit = current % 16;
+            current = current / 16;
+            chunkLength[pos--] = HexUtils.HEX[digit];
+        }
+        chunkHeader.setBytes(chunkLength, pos + 1, 9 - pos);
+        buffer.doWrite(chunkHeader, res);
+
+        buffer.doWrite(chunk, res);
+
+        chunkHeader.setBytes(chunkLength, 8, 2);
+        buffer.doWrite(chunkHeader, res);
+
+        return result;
+
+    }
+
+
+    // --------------------------------------------------- OutputFilter Methods
+
+
+    /**
+     * Some filters need additional parameters from the response. All the 
+     * necessary reading can occur in that method, as this method is called
+     * after the response header processing is complete.
+     */
+    public void setResponse(Response response) {
+    }
+
+
+    /**
+     * Set the next buffer in the filter pipeline.
+     */
+    public void setBuffer(OutputBuffer buffer) {
+        this.buffer = buffer;
+    }
+
+
+    /**
+     * End the current request. It is acceptable to write extra bytes using
+     * buffer.doWrite during the execution of this method.
+     */
+    public long end()
+        throws IOException {
+
+        // Write end chunk
+        buffer.doWrite(END_CHUNK, null);
+        
+        return 0;
+
+    }
+
+
+    /**
+     * Make the filter ready to process the next request.
+     */
+    public void recycle() {
+    }
+
+
+    /**
+     * Return the name of the associated encoding; Here, the value is 
+     * "identity".
+     */
+    public ByteChunk getEncodingName() {
+        return ENCODING;
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/http11/src/java/org/apache/coyote/http11/filters/GzipOutputFilter.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/http11/src/java/org/apache/coyote/http11/filters/GzipOutputFilter.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/http11/src/java/org/apache/coyote/http11/filters/GzipOutputFilter.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,170 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.filters;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.zip.GZIPOutputStream;
+
+import org.apache.tomcat.util.buf.ByteChunk;
+
+import org.apache.coyote.OutputBuffer;
+import org.apache.coyote.Response;
+import org.apache.coyote.http11.OutputFilter;
+
+/**
+ * Gzip output filter.
+ * 
+ * @author Remy Maucherat
+ */
+public class GzipOutputFilter implements OutputFilter {
+
+
+    // -------------------------------------------------------------- Constants
+
+
+    protected static final String ENCODING_NAME = "gzip";
+    protected static final ByteChunk ENCODING = new ByteChunk();
+
+
+    // ----------------------------------------------------- Static Initializer
+
+
+    static {
+        ENCODING.setBytes(ENCODING_NAME.getBytes(), 0, ENCODING_NAME.length());
+    }
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * Next buffer in the pipeline.
+     */
+    protected OutputBuffer buffer;
+
+
+    /**
+     * Compression output stream.
+     */
+    protected GZIPOutputStream compressionStream = null;
+
+
+    /**
+     * Fake internal output stream.
+     */
+    protected OutputStream fakeOutputStream = new FakeOutputStream();
+
+
+    // --------------------------------------------------- OutputBuffer Methods
+
+
+    /**
+     * Write some bytes.
+     * 
+     * @return number of bytes written by the filter
+     */
+    public int doWrite(ByteChunk chunk, Response res)
+        throws IOException {
+        if (compressionStream == null) {
+            compressionStream = new GZIPOutputStream(fakeOutputStream);
+        }
+        compressionStream.write(chunk.getBytes(), chunk.getStart(), 
+                                chunk.getLength());
+        return chunk.getLength();
+    }
+
+
+    // --------------------------------------------------- OutputFilter Methods
+
+
+    /**
+     * Some filters need additional parameters from the response. All the 
+     * necessary reading can occur in that method, as this method is called
+     * after the response header processing is complete.
+     */
+    public void setResponse(Response response) {
+    }
+
+
+    /**
+     * Set the next buffer in the filter pipeline.
+     */
+    public void setBuffer(OutputBuffer buffer) {
+        this.buffer = buffer;
+    }
+
+
+    /**
+     * End the current request. It is acceptable to write extra bytes using
+     * buffer.doWrite during the execution of this method.
+     */
+    public long end()
+        throws IOException {
+        if (compressionStream == null) {
+            compressionStream = new GZIPOutputStream(fakeOutputStream);
+        }
+        compressionStream.finish();
+        compressionStream.close();
+        return ((OutputFilter) buffer).end();
+    }
+
+
+    /**
+     * Make the filter ready to process the next request.
+     */
+    public void recycle() {
+        // Set compression stream to null
+        compressionStream = null;
+    }
+
+
+    /**
+     * Return the name of the associated encoding; Here, the value is 
+     * "identity".
+     */
+    public ByteChunk getEncodingName() {
+        return ENCODING;
+    }
+
+
+    // ------------------------------------------- FakeOutputStream Inner Class
+
+
+    protected class FakeOutputStream
+        extends OutputStream {
+        protected ByteChunk outputChunk = new ByteChunk();
+        protected byte[] singleByteBuffer = new byte[1];
+        public void write(int b)
+            throws IOException {
+            // Shouldn't get used for good performance, but is needed for 
+            // compatibility with Sun JDK 1.4.0
+            singleByteBuffer[0] = (byte) (b & 0xff);
+            outputChunk.setBytes(singleByteBuffer, 0, 1);
+            buffer.doWrite(outputChunk, null);
+        }
+        public void write(byte[] b, int off, int len)
+            throws IOException {
+            outputChunk.setBytes(b, off, len);
+            buffer.doWrite(outputChunk, null);
+        }
+        public void flush() throws IOException {}
+        public void close() throws IOException {}
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/http11/src/java/org/apache/coyote/http11/filters/IdentityInputFilter.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/http11/src/java/org/apache/coyote/http11/filters/IdentityInputFilter.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/http11/src/java/org/apache/coyote/http11/filters/IdentityInputFilter.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,201 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.filters;
+
+import java.io.IOException;
+
+import org.apache.tomcat.util.buf.ByteChunk;
+
+import org.apache.coyote.InputBuffer;
+import org.apache.coyote.Request;
+import org.apache.coyote.http11.InputFilter;
+
+/**
+ * Identity input filter.
+ * 
+ * @author Remy Maucherat
+ */
+public class IdentityInputFilter implements InputFilter {
+
+
+    // -------------------------------------------------------------- Constants
+
+
+    protected static final String ENCODING_NAME = "identity";
+    protected static final ByteChunk ENCODING = new ByteChunk();
+
+
+    // ----------------------------------------------------- Static Initializer
+
+
+    static {
+        ENCODING.setBytes(ENCODING_NAME.getBytes(), 0, ENCODING_NAME.length());
+    }
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * Content length.
+     */
+    protected long contentLength = -1;
+
+
+    /**
+     * Remaining bytes.
+     */
+    protected long remaining = 0;
+
+
+    /**
+     * Next buffer in the pipeline.
+     */
+    protected InputBuffer buffer;
+
+
+    /**
+     * Chunk used to read leftover bytes.
+     */
+    protected ByteChunk endChunk = new ByteChunk();
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * Get content length.
+     */
+    public long getContentLength() {
+        return contentLength;
+    }
+
+
+    /**
+     * Get remaining bytes.
+     */
+    public long getRemaining() {
+        return remaining;
+    }
+
+
+    // ---------------------------------------------------- InputBuffer Methods
+
+
+    /**
+     * Read bytes.
+     * 
+     * @return If the filter does request length control, this value is
+     * significant; it should be the number of bytes consumed from the buffer,
+     * up until the end of the current request body, or the buffer length, 
+     * whichever is greater. If the filter does not do request body length
+     * control, the returned value should be -1.
+     */
+    public int doRead(ByteChunk chunk, Request req)
+        throws IOException {
+
+        int result = -1;
+
+        if (contentLength >= 0) {
+            if (remaining > 0) {
+                int nRead = buffer.doRead(chunk, req);
+                if (nRead > remaining) {
+                    // The chunk is longer than the number of bytes remaining
+                    // in the body; changing the chunk length to the number
+                    // of bytes remaining
+                    chunk.setBytes(chunk.getBytes(), chunk.getStart(), 
+                                   (int) remaining);
+                    result = (int) remaining;
+                } else {
+                    result = nRead;
+                }
+                remaining = remaining - nRead;
+            } else {
+                // No more bytes left to be read : return -1 and clear the 
+                // buffer
+                chunk.recycle();
+                result = -1;
+            }
+        }
+
+        return result;
+
+    }
+
+
+    // ---------------------------------------------------- InputFilter Methods
+
+
+    /**
+     * Read the content length from the request.
+     */
+    public void setRequest(Request request) {
+        contentLength = request.getContentLengthLong();
+        remaining = contentLength;
+    }
+
+
+    /**
+     * End the current request.
+     */
+    public long end()
+        throws IOException {
+
+        // Consume extra bytes.
+        while (remaining > 0) {
+            int nread = buffer.doRead(endChunk, null);
+            if (nread > 0 ) {
+                remaining = remaining - nread;
+            } else { // errors are handled higher up.
+                remaining = 0;
+            }
+        }
+
+        // If too many bytes were read, return the amount.
+        return -remaining;
+
+    }
+
+
+    /**
+     * Set the next buffer in the filter pipeline.
+     */
+    public void setBuffer(InputBuffer buffer) {
+        this.buffer = buffer;
+    }
+
+
+    /**
+     * Make the filter ready to process the next request.
+     */
+    public void recycle() {
+        contentLength = -1;
+        remaining = 0;
+        endChunk.recycle();
+    }
+
+
+    /**
+     * Return the name of the associated encoding; Here, the value is 
+     * "identity".
+     */
+    public ByteChunk getEncodingName() {
+        return ENCODING;
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/http11/src/java/org/apache/coyote/http11/filters/IdentityOutputFilter.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/http11/src/java/org/apache/coyote/http11/filters/IdentityOutputFilter.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/http11/src/java/org/apache/coyote/http11/filters/IdentityOutputFilter.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,189 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.filters;
+
+import java.io.IOException;
+
+import org.apache.tomcat.util.buf.ByteChunk;
+
+import org.apache.coyote.OutputBuffer;
+import org.apache.coyote.Response;
+import org.apache.coyote.http11.OutputFilter;
+
+/**
+ * Identity output filter.
+ * 
+ * @author Remy Maucherat
+ */
+public class IdentityOutputFilter implements OutputFilter {
+
+
+    // -------------------------------------------------------------- Constants
+
+
+    protected static final String ENCODING_NAME = "identity";
+    protected static final ByteChunk ENCODING = new ByteChunk();
+
+
+    // ----------------------------------------------------- Static Initializer
+
+
+    static {
+        ENCODING.setBytes(ENCODING_NAME.getBytes(), 0, ENCODING_NAME.length());
+    }
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * Content length.
+     */
+    protected long contentLength = -1;
+
+
+    /**
+     * Remaining bytes.
+     */
+    protected long remaining = 0;
+
+
+    /**
+     * Next buffer in the pipeline.
+     */
+    protected OutputBuffer buffer;
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * Get content length.
+     */
+    public long getContentLength() {
+        return contentLength;
+    }
+
+
+    /**
+     * Get remaining bytes.
+     */
+    public long getRemaining() {
+        return remaining;
+    }
+
+
+    // --------------------------------------------------- OutputBuffer Methods
+
+
+    /**
+     * Write some bytes.
+     * 
+     * @return number of bytes written by the filter
+     */
+    public int doWrite(ByteChunk chunk, Response res)
+        throws IOException {
+
+        int result = -1;
+
+        if (contentLength >= 0) {
+            if (remaining > 0) {
+                result = chunk.getLength();
+                if (result > remaining) {
+                    // The chunk is longer than the number of bytes remaining
+                    // in the body; changing the chunk length to the number
+                    // of bytes remaining
+                    chunk.setBytes(chunk.getBytes(), chunk.getStart(), 
+                                   (int) remaining);
+                    result = (int) remaining;
+                    remaining = 0;
+                } else {
+                    remaining = remaining - result;
+                }
+                buffer.doWrite(chunk, res);
+            } else {
+                // No more bytes left to be written : return -1 and clear the 
+                // buffer
+                chunk.recycle();
+                result = -1;
+            }
+        } else {
+            // If no content length was set, just write the bytes
+            buffer.doWrite(chunk, res);
+            result = chunk.getLength();
+        }
+
+        return result;
+
+    }
+
+
+    // --------------------------------------------------- OutputFilter Methods
+
+
+    /**
+     * Some filters need additional parameters from the response. All the 
+     * necessary reading can occur in that method, as this method is called
+     * after the response header processing is complete.
+     */
+    public void setResponse(Response response) {
+        contentLength = response.getContentLengthLong();
+        remaining = contentLength;
+    }
+
+
+    /**
+     * Set the next buffer in the filter pipeline.
+     */
+    public void setBuffer(OutputBuffer buffer) {
+        this.buffer = buffer;
+    }
+
+
+    /**
+     * End the current request. It is acceptable to write extra bytes using
+     * buffer.doWrite during the execution of this method.
+     */
+    public long end()
+        throws IOException {
+
+        if (remaining > 0)
+            return remaining;
+        return 0;
+
+    }
+
+
+    /**
+     * Make the filter ready to process the next request.
+     */
+    public void recycle() {
+        contentLength = -1;
+        remaining = 0;
+    }
+
+
+    /**
+     * Return the name of the associated encoding; Here, the value is 
+     * "identity".
+     */
+    public ByteChunk getEncodingName() {
+        return ENCODING;
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/http11/src/java/org/apache/coyote/http11/filters/SavedRequestInputFilter.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/http11/src/java/org/apache/coyote/http11/filters/SavedRequestInputFilter.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/http11/src/java/org/apache/coyote/http11/filters/SavedRequestInputFilter.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,99 @@
+/*
+ *  Copyright 1999-2005 The Apache Software Foundation
+ *
+ *  Licensed 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.filters;
+
+import java.io.IOException;
+
+import org.apache.coyote.InputBuffer;
+import org.apache.coyote.http11.InputFilter;
+import org.apache.tomcat.util.buf.ByteChunk;
+
+/**
+ * Input filter responsible for replaying the request body when restoring the
+ * saved request after FORM authentication.
+ */
+public class SavedRequestInputFilter implements InputFilter {
+
+	/**
+     * The original request body.
+	 */
+    protected ByteChunk input = null;
+
+    /**
+     * Create a new SavedRequestInputFilter.
+     * 
+     * @param input The saved request body to be replayed.
+     */
+    public SavedRequestInputFilter(ByteChunk input) {
+        this.input = input;
+    }
+
+    /**
+     * Read bytes.
+     */
+    public int doRead(ByteChunk chunk, org.apache.coyote.Request request)
+            throws IOException {
+        int writeLength = 0;
+        
+        if (chunk.getLimit() > 0 && chunk.getLimit() < input.getLength()) {
+            writeLength = chunk.getLimit();
+        } else {
+        	writeLength = input.getLength();
+        }
+        
+        input.substract(chunk.getBuffer(), 0, writeLength);
+        chunk.setOffset(0);
+        chunk.setEnd(writeLength);
+        
+        return writeLength;
+    }
+
+    /**
+     * Set the content length on the request.
+     */
+    public void setRequest(org.apache.coyote.Request request) {
+        request.setContentLength(input.getLength());
+    }
+
+    /**
+     * Make the filter ready to process the next request.
+     */
+    public void recycle() {
+        input = null;
+    }
+
+    /**
+     * Return the name of the associated encoding; here, the value is null.
+     */
+    public ByteChunk getEncodingName() {
+        return null;
+    }
+
+    /**
+     * Set the next buffer in the filter pipeline (has no effect).
+     */
+    public void setBuffer(InputBuffer buffer) {
+    }
+
+    /**
+     * End the current request (has no effect).
+     */
+    public long end() throws IOException {
+        return 0;
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/http11/src/java/org/apache/coyote/http11/filters/VoidInputFilter.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/http11/src/java/org/apache/coyote/http11/filters/VoidInputFilter.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/http11/src/java/org/apache/coyote/http11/filters/VoidInputFilter.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,118 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.filters;
+
+import java.io.IOException;
+
+import org.apache.tomcat.util.buf.ByteChunk;
+
+import org.apache.coyote.InputBuffer;
+import org.apache.coyote.Request;
+import org.apache.coyote.http11.InputFilter;
+
+/**
+ * Void input filter, which returns -1 when attempting a read. Used with a GET,
+ * HEAD, or a similar request.
+ * 
+ * @author Remy Maucherat
+ */
+public class VoidInputFilter implements InputFilter {
+
+
+    // -------------------------------------------------------------- Constants
+
+
+    protected static final String ENCODING_NAME = "void";
+    protected static final ByteChunk ENCODING = new ByteChunk();
+
+
+    // ----------------------------------------------------- Static Initializer
+
+
+    static {
+        ENCODING.setBytes(ENCODING_NAME.getBytes(), 0, ENCODING_NAME.length());
+    }
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    // --------------------------------------------------- OutputBuffer Methods
+
+
+    /**
+     * Write some bytes.
+     * 
+     * @return number of bytes written by the filter
+     */
+    public int doRead(ByteChunk chunk, Request req)
+        throws IOException {
+
+        return -1;
+
+    }
+
+
+    // --------------------------------------------------- OutputFilter Methods
+
+
+    /**
+     * Set the associated reauest.
+     */
+    public void setRequest(Request request) {
+    }
+
+
+    /**
+     * Set the next buffer in the filter pipeline.
+     */
+    public void setBuffer(InputBuffer buffer) {
+    }
+
+
+    /**
+     * Make the filter ready to process the next request.
+     */
+    public void recycle() {
+    }
+
+
+    /**
+     * Return the name of the associated encoding; Here, the value is 
+     * "void".
+     */
+    public ByteChunk getEncodingName() {
+        return ENCODING;
+    }
+
+
+    /**
+     * End the current request. It is acceptable to write extra bytes using
+     * buffer.doWrite during the execution of this method.
+     * 
+     * @return Should return 0 unless the filter does some content length 
+     * delimitation, in which case the number is the amount of extra bytes or
+     * missing bytes, which would indicate an error. 
+     * Note: It is recommended that extra bytes be swallowed by the filter.
+     */
+    public long end()
+        throws IOException {
+        return 0;
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/http11/src/java/org/apache/coyote/http11/filters/VoidOutputFilter.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/http11/src/java/org/apache/coyote/http11/filters/VoidOutputFilter.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/http11/src/java/org/apache/coyote/http11/filters/VoidOutputFilter.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,127 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.filters;
+
+import java.io.IOException;
+
+import org.apache.tomcat.util.buf.ByteChunk;
+
+import org.apache.coyote.OutputBuffer;
+import org.apache.coyote.Response;
+import org.apache.coyote.http11.OutputFilter;
+
+/**
+ * Void output filter, which silently swallows bytes written. Used with a 204
+ * status (no content) or a HEAD request.
+ * 
+ * @author Remy Maucherat
+ */
+public class VoidOutputFilter implements OutputFilter {
+
+
+    // -------------------------------------------------------------- Constants
+
+
+    protected static final String ENCODING_NAME = "void";
+    protected static final ByteChunk ENCODING = new ByteChunk();
+
+
+    // ----------------------------------------------------- Static Initializer
+
+
+    static {
+        ENCODING.setBytes(ENCODING_NAME.getBytes(), 0, ENCODING_NAME.length());
+    }
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * Next buffer in the pipeline.
+     */
+    protected OutputBuffer buffer;
+
+
+    // --------------------------------------------------- OutputBuffer Methods
+
+
+    /**
+     * Write some bytes.
+     * 
+     * @return number of bytes written by the filter
+     */
+    public int doWrite(ByteChunk chunk, Response res)
+        throws IOException {
+
+        return chunk.getLength();
+
+    }
+
+
+    // --------------------------------------------------- OutputFilter Methods
+
+
+    /**
+     * Some filters need additional parameters from the response. All the 
+     * necessary reading can occur in that method, as this method is called
+     * after the response header processing is complete.
+     */
+    public void setResponse(Response response) {
+    }
+
+
+    /**
+     * Set the next buffer in the filter pipeline.
+     */
+    public void setBuffer(OutputBuffer buffer) {
+        this.buffer = buffer;
+    }
+
+
+    /**
+     * Make the filter ready to process the next request.
+     */
+    public void recycle() {
+    }
+
+
+    /**
+     * Return the name of the associated encoding; Here, the value is 
+     * "identity".
+     */
+    public ByteChunk getEncodingName() {
+        return ENCODING;
+    }
+
+
+    /**
+     * End the current request. It is acceptable to write extra bytes using
+     * buffer.doWrite during the execution of this method.
+     * 
+     * @return Should return 0 unless the filter does some content length 
+     * delimitation, in which case the number is the amount of extra bytes or
+     * missing bytes, which would indicate an error. 
+     * Note: It is recommended that extra bytes be swallowed by the filter.
+     */
+    public long end()
+        throws IOException {
+        return 0;
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/http11/src/test/java/org/apache/coyote/http11/FileTester.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/http11/src/test/java/org/apache/coyote/http11/FileTester.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/http11/src/test/java/org/apache/coyote/http11/FileTester.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,151 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.net.Socket;
+import java.util.Locale;
+
+import org.apache.coyote.Adapter;
+import org.apache.coyote.ActionCode;
+import org.apache.coyote.Processor;
+
+/**
+ * File tester.
+ * <p>
+ * This tester is initialized with an adapter (it will use the HTTP/1.1 
+ * processor), and will then accept an input file (which will contain the 
+ * input data), and an output file, to which the result of the request(s)
+ * will be written.
+ *
+ * @author Remy Maucherat
+ */
+public class FileTester {
+
+
+    // -------------------------------------------------------------- Constants
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Construct a new file tester using the two files specified. The contents
+     * of the output file will be overwritten when the test is run.
+     * 
+     * @param adapter Coyote adapter to use for this test
+     * @param processor Coyote processor to use for this test
+     * @param inputFile File containing the HTTP requests in plain text
+     * @param outputFile File containing the HTTP responses
+     */
+    public FileTester(Adapter adapter, Processor processor,
+                      File inputFile, File outputFile) {
+
+        processor.setAdapter(adapter);
+
+        this.adapter = adapter;
+        this.processor = processor;
+        this.inputFile = inputFile;
+        this.outputFile = outputFile;
+
+    }
+
+
+    // --------------------------------------------------------- Static Methods
+
+
+    /**
+     * Utility main method, which will use the HTTP/1.1 processor with the 
+     * test adapter.
+     *
+     * @param args Command line arguments to be processed
+     */
+    public static void main(String args[])
+        throws Exception {
+
+        if (args.length < 2) {
+            System.out.println("Incorrect number of arguments");
+            return;
+        }
+
+        // The first argument is the input file
+        File inputFile = new File(args[0]);
+
+        // The second argument is the output file
+        File outputFile = new File(args[1]);
+
+        Adapter testAdapter = new RandomAdapter();
+        Http11Processor http11Processor = new Http11Processor();
+        http11Processor.setSocket(new Socket("127.0.0.1", 8080));
+        http11Processor.action(ActionCode.ACTION_START, null);
+
+        FileTester tester = new FileTester(testAdapter, http11Processor,
+                                           inputFile, outputFile);
+        tester.test();
+
+    }
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * File containing the input data.
+     */
+    protected File inputFile;
+
+
+    /**
+     * File containing the output data.
+     */
+    protected File outputFile;
+
+
+    /**
+     * Coyote adapter to use.
+     */
+    protected Adapter adapter;
+
+
+    /**
+     * Coyote processor to use.
+     */
+    protected Processor processor;
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Process the test.
+     */
+    public void test()
+        throws Exception {
+
+        InputStream is = new FileInputStream(inputFile);
+        OutputStream os = new FileOutputStream(outputFile);
+
+        processor.process(is, os);
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/http11/src/test/java/org/apache/coyote/http11/RandomAdapter.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/http11/src/test/java/org/apache/coyote/http11/RandomAdapter.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/http11/src/test/java/org/apache/coyote/http11/RandomAdapter.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,184 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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;
+
+import org.apache.tomcat.util.buf.MessageBytes;
+import org.apache.tomcat.util.buf.ByteChunk;
+import org.apache.tomcat.util.http.MimeHeaders;
+
+import org.apache.coyote.ActionCode;
+import org.apache.coyote.Adapter;
+import org.apache.coyote.Request;
+import org.apache.coyote.Response;
+
+/**
+ * Adapter which will return random responses using pipelining, which means it
+ * will never try to generate bogus responses.
+ *
+ * @author Remy Maucherat
+ */
+public class RandomAdapter
+    implements Adapter {
+
+    private static org.apache.commons.logging.Log log=
+        org.apache.commons.logging.LogFactory.getLog( RandomAdapter.class );
+
+    public static final String CRLF = "\r\n";
+    public static final byte[] b = "0123456789\r\n".getBytes();
+    public static final ByteChunk bc = new ByteChunk();
+
+
+    /** 
+     * Service method, which dumps the request to the console.
+     */
+    public void service(Request req, Response res)
+	throws Exception {
+
+        double rand = Math.random();
+        int n = (int) Math.round(10 * rand);
+
+        // Temp variables
+        byte[] buf = null;
+        int nRead = 0;
+        StringBuffer sbuf = new StringBuffer();
+        MimeHeaders headers = req.getMimeHeaders();
+        int size = headers.size();
+
+        switch (n) {
+
+        case 0:
+
+            // 0) Do nothing
+            if (log.isDebugEnabled())
+                log.debug("Response 0");
+            break;
+
+        case 1:
+
+            // 1) Set content length, and write the appropriate content
+            if (log.isDebugEnabled())
+                log.debug("Response 1");
+            res.setContentLength(b.length);
+            bc.setBytes(b, 0, b.length);
+            res.doWrite(bc);
+            break;
+
+        case 2:
+
+            // 2) Read the request data, and print out the number of bytes
+            // read
+            if (log.isDebugEnabled())
+                log.debug("Response 2");
+            while (nRead >= 0) {
+                nRead = req.doRead(bc);
+                buf = ("Read " + nRead + " bytes\r\n").getBytes();
+                bc.setBytes(buf, 0, buf.length);
+                res.doWrite(bc);
+            }
+            break;
+
+        case 3:
+
+            // 3) Return 204 (no content), while reading once on input
+            if (log.isDebugEnabled())
+                log.debug("Response 3");
+            res.setStatus(204);
+            nRead = req.doRead(bc);
+            res.setHeader("Info", "Read " + nRead + " bytes");
+            break;
+
+        case 4:
+
+            // 4) Do a request dump
+            if (log.isDebugEnabled())
+                log.debug("Response 4");
+            sbuf.append("Request dump:");
+            sbuf.append(CRLF);
+            sbuf.append(req.method());
+            sbuf.append(" ");
+            sbuf.append(req.unparsedURI());
+            sbuf.append(" ");
+            sbuf.append(req.protocol());
+            sbuf.append(CRLF);
+            for (int i = 0; i < size; i++) {
+                sbuf.append(headers.getName(i) + ": ");
+                sbuf.append(headers.getValue(i).toString());
+                sbuf.append(CRLF);
+            }
+            sbuf.append("Request body:");
+            sbuf.append(CRLF);
+            res.action(ActionCode.ACTION_ACK, null);
+            ByteChunk bc2 = new ByteChunk();
+            byte[] b2 = sbuf.toString().getBytes();
+            bc2.setBytes(b2, 0, b2.length);
+            res.doWrite(bc2);
+            while (nRead >= 0) {
+                nRead = req.doRead(bc2);
+                if (nRead > 0)
+                    res.doWrite(bc2);
+            }
+            break;
+
+        default:
+
+            // Response not implemented yet
+            if (log.isDebugEnabled())
+                log.debug("Response " + n + " is not implemented yet");
+
+        }
+
+/*
+        StringBuffer buf = new StringBuffer();
+        buf.append("Request dump:");
+        buf.append(CRLF);
+        buf.append(req.method());
+        buf.append(" ");
+        buf.append(req.unparsedURI());
+        buf.append(" ");
+        buf.append(req.protocol());
+        buf.append(CRLF);
+        
+        MimeHeaders headers = req.getMimeHeaders();
+        int size = headers.size();
+        for (int i = 0; i < size; i++) {
+            buf.append(headers.getName(i) + ": ");
+            buf.append(headers.getValue(i).toString());
+            buf.append(CRLF);
+        }
+
+        buf.append("Request body:");
+        buf.append(CRLF);
+
+        res.action(ActionCode.ACTION_ACK, null);
+
+        ByteChunk bc = new ByteChunk();
+        byte[] b = buf.toString().getBytes();
+        bc.setBytes(b, 0, b.length);
+        res.doWrite(bc);
+
+        int nRead = 0;
+
+        while (nRead >= 0) {
+            nRead = req.doRead(bc);
+            if (nRead > 0)
+                res.doWrite(bc);
+        }
+*/
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/http11/src/test/java/org/apache/coyote/http11/TestAdapter.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/http11/src/test/java/org/apache/coyote/http11/TestAdapter.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/http11/src/test/java/org/apache/coyote/http11/TestAdapter.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,84 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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;
+
+import org.apache.tomcat.util.buf.MessageBytes;
+import org.apache.tomcat.util.buf.ByteChunk;
+import org.apache.tomcat.util.http.MimeHeaders;
+
+import org.apache.coyote.ActionCode;
+import org.apache.coyote.Adapter;
+import org.apache.coyote.Request;
+import org.apache.coyote.Response;
+
+/**
+ * Adapter which will generate content.
+ *
+ * @author Remy Maucherat
+ */
+public class TestAdapter
+    implements Adapter {
+
+
+    public static final String CRLF = "\r\n";
+
+
+    /** 
+     * Service method, which dumps the request to the console.
+     */
+    public void service(Request req, Response res)
+	throws Exception {
+        
+        StringBuffer buf = new StringBuffer();
+        buf.append("Request dump:");
+        buf.append(CRLF);
+        buf.append(req.method());
+        buf.append(" ");
+        buf.append(req.unparsedURI());
+        buf.append(" ");
+        buf.append(req.protocol());
+        buf.append(CRLF);
+        
+        MimeHeaders headers = req.getMimeHeaders();
+        int size = headers.size();
+        for (int i = 0; i < size; i++) {
+            buf.append(headers.getName(i) + ": ");
+            buf.append(headers.getValue(i).toString());
+            buf.append(CRLF);
+        }
+
+        buf.append("Request body:");
+        buf.append(CRLF);
+
+        res.action(ActionCode.ACTION_ACK, null);
+
+        ByteChunk bc = new ByteChunk();
+        byte[] b = buf.toString().getBytes();
+        bc.setBytes(b, 0, b.length);
+        res.doWrite(bc);
+
+        int nRead = 0;
+
+        while (nRead >= 0) {
+            nRead = req.doRead(bc);
+            if (nRead > 0)
+                res.doWrite(bc);
+        }
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/http11/src/test/test.bat
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/http11/src/test/test.bat	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/http11/src/test/test.bat	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,4 @@
+
+
+java -cp .;../../../lib/commons-logging.jar;../lib/tomcat-util.jar;../lib/tomcat-coyote.jar;../lib/tomcat-http11.jar org.apache.coyote.http11.FileTester tests/test1.txt tests/test1.out
+

Added: branches/tomcat5.5/upstream/5.5.20/connectors/http11/src/test/tests/test1.txt
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/http11/src/test/tests/test1.txt	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/http11/src/test/tests/test1.txt	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,198 @@
+GET /foo HTTP/1.1
+Header1: simple header
+Host:     random_host     
+Header2:     this is a sample multiline header formatted 
+     using lots of extra spaces   
+Header3:    another     
+         multiline
+   header
+      which   
+    spans
+        six lines  
+Content-Length: 204
+
+01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789
+
+GET /bar HTTP/1.1
+Host:foobar
+Transfer-Encoding: chunked
+
+cc
+00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+
+
+cc
+11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111
+
+
+cc
+22222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222
+
+
+cc
+33333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333
+
+
+cc
+44444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444
+
+
+cc
+55555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555
+
+
+cc
+66666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666
+
+
+cc
+77777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777
+
+
+cc
+88888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888
+
+
+cc
+99999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999
+
+
+cc
+00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+
+
+cc
+11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111
+
+
+cc
+22222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222
+
+
+cc
+33333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333
+
+
+cc
+44444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444
+
+
+cc
+55555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555
+
+
+cc
+66666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666
+
+
+cc
+77777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777
+
+
+cc
+88888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888
+
+
+cc
+99999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999
+
+
+cc
+00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+
+
+cc
+11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111
+
+
+cc
+22222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222
+
+
+cc
+33333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333
+
+
+cc
+44444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444
+
+
+cc
+55555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555
+
+
+cc
+66666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666
+
+
+cc
+77777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777
+
+
+cc
+88888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888
+
+
+cc
+99999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999
+
+
+0
+
+GET /bar HTTP/1.1
+Host:foobar
+Transfer-Encoding: chunked
+
+1774
+000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111122222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333334444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444455555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666667777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777788888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999990000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222223333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333344444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555556666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666677777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888889999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111112222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222233333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444445555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555566666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777778888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888899999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999
+
+
+cc
+00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+
+
+1774
+000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111122222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333334444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444455555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666667777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777788888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999990000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222223333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333344444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555556666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666677777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888889999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111112222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222233333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444445555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555566666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777778888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888899999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999
+
+
+1774
+000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111122222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333334444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444455555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666667777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777788888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999990000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222223333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333344444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555556666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666677777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888889999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111112222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222233333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444445555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555566666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777778888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888899999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999
+
+
+cc
+11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111
+
+
+0
+
+GET /foo2 HTTP/1.1
+Host: localhost
+Header4:     this is a sample multiline header formatted 
+     using lots of extra spaces   
+Header5:    another     
+         multiline
+   header
+      which   
+    spans
+        six lines  
+Content-Length: 12
+
+0123456789
+HEAD /bar2 HTTP/1.1
+Header6:    another     
+         multiline
+   header
+      which   
+    spans
+        six lines  
+Host:foobar
+
+GET /bar2 HTTP/1.1
+Header6:    another     
+         multiline
+   header
+      which   
+    spans
+        six lines  
+Host:foobar
+

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/BUILD.txt
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/BUILD.txt	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/BUILD.txt	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,13 @@
+This is a source release of the mod_jk 1.2 web server connector for
+Tomcat. Only the web server connector source is included.  The Tomcat
+side of the connector is available with the normal Tomcat distribution.
+
+Documentation for how to build mod_jk 1.2 from source and configure
+it for your webserver is located in the native/BUILDING file in this
+source distribution.
+
+For the impatient Apache admins:
+$> cd native
+$> ./configure --with-apxs=/usr/sbin/apxs (or where ever the apxs/apxs2 is)
+$> make
+$> su -c 'make install'

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/HOWTO-RELEASE
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/HOWTO-RELEASE	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/HOWTO-RELEASE	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,239 @@
+		How to do a mod_jk 1.2 release
+
+Check out a clean copy of tomcat/connectors from subversion to
+make sure you don't have any lingering configure or build files.
+This will make sure that the source distribution created is clean.
+
+We assume, that you check out to a directory tomcat-connectors.
+
+If you haven't already, add your public PGP key to
+tomcat-connectors/KEYS.
+
+Update version numbers as needed
+--------------------------------
+
+Do a find for all the docs which include the previous version string
+and replace it with the new version.  These are the docs I found which
+had to be updated:
+
+xdocs/howto/apache.xml
+xdocs/howto/quick.xml
+xdocs/howto/workers.xml
+
+Update the version in jk/native/configure.in.
+
+Update the version in jk/native/common/jk_version.h, here is
+a svn diff that shows what I changed:
+
+Index: native/common/jk_version.h
+===================================================================
+--- native/common/jk_version.h  (revision 417260)
++++ native/common/jk_version.h  (working copy)
+@@ -32,7 +32,7 @@
+ #define JK_VERBETA      0
+ #define JK_BETASTRING   "0"
+ /* set JK_VERISRELEASE to 1 when release (do not forget to commit!) */
+-#define JK_VERISRELEASE 0
++#define JK_VERISRELEASE 1
+ #define JK_VERRC        0
+ #define JK_RCSTRING     "0"
+
+After updating revision numbers, commit your changes to subversion.
+
+Tag and branch tomcat-connectors in subversion
+----------------------------------------------
+
+Use the pattern below for branching and tagging the tomcat-connectors directory.
+
+TAG=JK_{MAJOR_REVISION}_{MINOR_REVISION}_{RELEASE}
+
+svn copy \
+   https://svn.apache.org/repos/asf/tomcat/connectors/trunk/ \
+   https://svn.apache.org/repos/asf/tomcat/connectors/tags/jk1.2.x/TAG/
+
+Here is an example for mod_jk 1.2.16
+
+svn copy \
+   https://svn.apache.org/repos/asf/tomcat/connectors/trunk/ \
+   https://svn.apache.org/repos/asf/tomcat/connectors/tags/jk1.2.x/JK_1_2_16/
+
+Build the mod_jk 1.2 documentation
+----------------------------------
+
+cd tomcat-connectors/jk/xdocs
+ant
+
+
+Check the documentation carefully (produced in tomcat-connectors/jk/build/docs)
+and copy it to people.apache.org:/x1/www/tomcat.apache.org/connectors-doc
+
+Create the new source distribution
+----------------------------------
+
+(A tool named jkrelease.sh in tomcat-connectors/jk/tools does the
+following steps).
+
+Create the directory
+tomcat-connectors-jk-{MAJOR_REVISION}-{MINOR_REVISION}-{RELEASE}-src
+
+For this example mkdir tomcat-connectors-jk-1.2.16-src
+
+Copy the files KEYS and LICENSE from tomcat-conectors to
+the source distribution directory.
+
+cp tomcat-connectors/KEYS tomcat-connectors-jk-1.2.16-src
+cp tomcat-connectors/LICENSE tomcat-connectors-jk-1.2.16-src
+
+Copy the directory tomcat-connectors/scandoc to the source
+distribution directory.
+
+cp -pr tomcat-connectors/scandoc tomcat-connectors-jk-1.2.16-src
+
+Copy the directory tomcat-connectors/common to the source
+distribution directory.
+
+cp -pr tomcat-connectors/common tomcat-connectors-jk-1.2.16-src
+
+Make the jk directory in the source distribution.
+
+mkdir tomcat-connectors-jk-1.2.16-src/jk
+
+Copy the file BUILD.txt from tomcat-conectors/jk to 
+the source distribution jk directory.
+
+cp -p tomcat-connectors/jk/BUILD.txt tomcat-connectors-jk-1.2.16-src/README.txt
+
+Copy the directory tomcat-connectors/build/docs to the source
+distribution directory.
+
+cp -pr tomcat-connectors/jk/build/docs tomcat-connectors-jk-1.2.16-src/jk
+
+Copy the directory tomcat-connectors/tools to the source
+distribution directory.
+
+cp -pr tomcat-connectors/jk/tools tomcat-connectors-jk-1.2.16-src/jk
+
+Make the jk conf directory in the source distribution.
+
+mkdir tomcat-connectors-jk-1.2.16-src/jk/conf
+
+Copy the worker.properties file to the jk/conf directory.
+
+cp -p tomcat-connectors/jk/conf/worker.properties tomcat-connectors-jk-1.2.16-src/jk/conf
+
+Copy the directory tomcat-connectors/support to the source
+distribution directory.
+
+cp -pr tomcat-connectors/jk/support tomcat-connectors-jk-1.2.16-src/jk
+
+Copy the directory tomcat-connectors/native to the source
+distribution directory.
+
+cp -pr tomcat-connectors/jk/native tomcat-connectors-jk-1.2.16-src/jk
+
+Remove all the CVS and .svn directories from the new source distribution.
+
+find tomcat-connectors-jk-1.2.16-src -type d -name CVS | xargs rm -rf
+find tomcat-connectors-jk-1.2.16-src -type d -name .svn | xargs rm -rf
+
+cd to tomcat-connectors-jk-1.2.16-src/jk/native and run buildconf.sh
+to create the configure script.
+
+Create a tar gzip'd archive
+
+tar zcf tomcat-connectors-jk-1.2.16-src.tar.gz tomcat-connectors-jk-1.2.16-src
+
+Create a zip archive
+
+zip -r tomcat-connectors-jk-1.2.16-src.zip tomcat-connectors-jk-1.2.16-src
+
+Sign the release using PGP. Here is an example using gpg:
+
+gpg -abs -o tomcat-connectors-jk-1.2.16-src.tar.gz.asc tomcat-connectors-jk-1.2.16-src.tar.gz
+
+Upload source distribution and documentation to www.apache.org
+-------------------------------------------------------------------
+First update the KEYS on the server if you have added a new pgp key.
+
+scp tomcat-connectors/KEYS to the
+/www/www.apache.org/dist/tomcat/tomcat-connectors
+directory on the www.apache.org server.
+
+scp tomcat-connectors-jk-1.2.16-src.tar.gz* to 
+/www/www.apache.org/dist/tomcat/tomcat-connectors/jk/source
+scp tomcat-connectors-jk-1.2.16-src.zip* to   
+/www/www.apache.org/dist/tomcat/tomcat-connectors/jk/source
+
+ssh to www.apache.org and cd to the
+/www/www.apache.org/dist/tomcat/tomcat-connectors/jk directory.
+
+Remove the symlinks for current and replace them with a soft link
+to the new source distribution files.
+
+ln -s source/tomcat-connectors-jk-1.2.16-src.tar.gz tomcat-connectors-jk-src-current.tar.gz
+ln -s source/tomcat-connectors-jk-1.2.16-src.tar.gz.asc tomcat-connectors-jk-src-current.tar.gz.asc
+ln -s source/tomcat-connectors-jk-1.2.16-src.tar.zip tomcat-connectors-jk-src-current.zip
+ln -s source/tomcat-connectors-jk-1.2.16-src.zip.asc tomcat-connectors-jk-src-current.zip.asc
+
+Make sure the group write bit is set on all files and directories
+in the jk directory.
+
+chmod -R g+w /www/www.apache.org/dist/tomcat/tomcat-connectors/jk/
+
+Build binaries and upload distributions to www.apache.org
+--------------------------------------------------------------
+
+Build mod_jk for a specific web server and OS.  Package it as appropriate for
+the OS and sign the archive using PGP. Please include the ASF License, the
+generated docs, and the tools.  Please name the distribuiton as follows:
+
+tomcat-connectors-jk-{version}-{os-version-cpu}-{web server-version}.(tar.gz|zip)
+
+scp the binary distribution and pgp signature file to the appropriate binaries/{os} directory.
+
+Make sure the group write bit is on for all files you upload.
+
+Update source for next version
+------------------------------
+
+Reset JK_VERISRELEASE to 0 and update JK_VERSTRING, JK_VERMAJOR,
+JK_VERMINOR, and JK_VERFIX as needed.  Commit your changes to subversion.
+
+Remove old release distributions from www.apache.org
+----------------------------------------------------
+
+Verify that the old versions of the source and binary distributions are
+available at /www/archive.apache.org/dist/tomcat/tomcat-connector/jk .
+Copy old source distributions and binaries as needed, then remove the
+old source and binary distributions.
+
+Arrange the downloads_tomcat-connectors.cgi
+-------------------------------------------
+
+Check tomcat-site out:
+svn co https://svn.apache.org/repos/asf/tomcat/site site-tomcat
+
+
+Arrange the file: xdocs/downloads/downloads.xml
+
+Use ant to regenerate the corresponding html file:
+docs/site/downloads/downloads_tomcat-connectors.html
+
+Commit it after checking carefully the changes.
+
+Connect to people.apache.org and update the tomcat.apache.org site image,
+the site tomcat.apache.org should reflect the change after a while.
+cd /x2/www/tomcat.apache.org/site/downloads
+svn update downloads_tomcat-connectors.html
+
+Announcements
+-------------
+
+The release distribution directories are mirrored so that the
+releases can be downloaded from multiple sites.  Please wait
+24 hours before sending out the announcement so that the mirrors
+get a chance to get the new release distributions.
+
+Send an email announcement to users at tomcat.apache.org,
+dev at tomcat.apache.org, and announce at apache.org.
+

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/README.txt
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/README.txt	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/README.txt	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,68 @@
+This directory contains both the native and java-side code for
+ajp connectors.
+
+Building
+========
+
+* Install tomcat(3.3, 4.0, 4.1). Install Apache(1.3, 2.0). Any
+combination is fine, but j-t-c developers should have them all.
+
+* Copy build.properties.sample to build.properties
+
+* Edit build.properties to taste. In particular it's important to set
+the paths to tomcat and apache.
+
+* Run "ant". It'll build modules for all the detected containers.
+
+* If your system have a current working version of libtool, run "ant native". 
+  This will build the native connectors for the detected servers ( both jk
+  and jk2).
+
+  Alternatively, you can build using configure/make/dsp/apxs.
+
+* Run "ant install". This will copy the files in the right location
+  in your server/container. Optional: on unix systems you can create
+  symlinks ( XXX script will be provided ) and avoid copying. 
+
+Setting tomcat 3.3
+==================
+
+Restart tomcat. 
+
+Setting tomcat 4.0
+==================
+
+To use the ajp13 connector for tomcat 4:
+
+XXX Can we automate this ?
+
+ 1) add the following to server.xml:
+
+     <Connector className="org.apache.ajp.tomcat4.Ajp13Connector"
+               port="8009" acceptCount="10" debug="0"/>
+
+Setting tomcat 4.1
+==================
+
+Restart tomcat. 
+
+( XXX this is not completely implemented. For now we'll use the same 
+mechanism as in 4.0 - i.e. add <Connector> in server.xml.  )
+
+Configuring JK1
+===============
+
+
+
+Configuring JK2
+===============
+
+
+Building the tests
+==================
+( probably not working - the best test is to run watchdog/tester/3.3 test webapp )
+( XXX is it ok to remove this ? )
+
+* Download junit from http://www.junit.org (version 3.7 or greater is required).
+
+* "ant test"

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/build.properties.autoconf
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/build.properties.autoconf	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/build.properties.autoconf	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,66 @@
+#
+# build.properties for jk2/ajp connector.
+# to be processed by configure
+#
+
+# Directory where tomcat5 is installed
+tomcat5.home=@TOMCAT5_HOME@ 
+
+# Directory where catalina is installed. It can 
+# be either 4.0 or 4.1
+tomcat40.home=@TOMCAT40_HOME@
+
+# If you want to build/install on  both 4.0 
+# and 4.1, set this to point to 4.0 and 'catalina.home'
+# to point to 4.0
+# ( most people need only the first, but developers should
+# have both )
+tomcat41.home=@TOMCAT41_HOME@
+
+# Directory where tomcat3.3 is installed
+tomcat33.home=@TOMCAT33_HOME@ 
+
+# Location of Apache2, Apache1.3, IIS and Netscape (iPlanet)
+apache2.home=@APACHE2_HOME@
+apache13.home=@APACHE_HOME@
+iis.home=@IIS_HOME@
+iplanet.home=@IPLANET_HOME@
+
+
+# APR location - by default the version included in Apache2 is used.
+# Don't edit unless you install 'standalone' apr.
+apr.home=@APR_HOME@
+
+apr.include=@APR_INCDIR@
+apr-util.include=@APR_UTIL_INCL@
+
+apr.lib=@APR_LIBDIR@
+apr-util.lib=@APR_UTIL_LIB@
+
+
+# Location of Apache2, Apache1.3 apxs build tool
+apxs=@APXS@
+apxs2=@APXS2@
+
+
+# Location of Apache2, Apache1.3, IIS and Netscape (iPlanet) 
+# includes directory
+apache2.include=@APACHE2_INCDIR@
+apache13.include=@APACHE_INCDIR@
+iis.include=@IIS_INCDIR@
+iplanet.include=@IPLANET_INCDIR@
+
+
+# Location of Apache2, Apache1.3, IIS and Netscape (iPlanet) 
+# lib directory
+apache2.lib=@APACHE2_LIBDIR@
+apache13.lib=@APACHE_LIBDIR@
+iis.lib=@IIS_LIBDIR@
+iplanet.lib=@IPLANET_LIBDIR@
+
+
+# Compile-time options for native code
+so.debug=true
+so.optimize=false
+so.profile=false
+

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/build.properties.sample
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/build.properties.sample	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/build.properties.sample	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,62 @@
+#
+# sample build.properties for ajp connector.
+# edit to taste...
+#
+
+# Directory where tomcat5 is installed
+tomcat5.home= ../../jakarta-tomcat-5/build
+
+# Directory where catalina is installed. It can 
+# be either 4.0 or 4.1
+tomcat40.home=../../jakarta-tomcat-4.0/build
+
+# If you want to build/install on  both 4.0 
+# and 4.1, set this to point to 4.0 and 'catalina.home'
+# to point to 4.0
+# ( most people need only the first, but developers should
+# have both )
+tomcat41.home=../../jakarta-tomcat-4.1/build
+
+# Directory where tomcat3.3 is installed
+tomcat33.home= ../../jakarta-tomcat/build/tomcat
+
+# Location of Apache2, Apache1.3, Netscape, IIS
+apache2.home=/opt/apache2
+apache13.home=/opt/apache13
+iplanet.home=/opt/iplanet6
+aolserver.home=/opt/aolserver-4.0
+# iplanet.home=d:/tools/sdk/netscape
+# iis.home=e:/
+
+# APR location - by default the version included in Apache2 is used.
+# Don't edit unless you install 'standalone' apr.
+apr.home=${apache2.home}
+
+apr.include=${apr.home}/include
+apr-util.include=${apr.home}/include
+
+apr.lib=${apr.home}/lib
+apr-util.lib=${apr.home}/lib
+apache2.lib=${apache2.home}/lib
+
+
+# Compile-time options for native code
+so.debug=true
+so.optimize=false
+so.profile=false
+
+# tools for other directories
+# Metrowerks and Novell ndk
+#mw.home=d:/tools/mw/6.0
+#novellndk.home=d:/tools/novell/ndk/nwsdk
+#novelllibc.home=d:/tools/novell/ndk/libc
+#build.compiler.base=${mw.home}
+#build.compiler.cc=${mw.home}/bin/mwccnlm
+#build.compiler.ld=${mw.home}/bin/mwldnlm
+#netscape.home=${iplanet.home}
+#option_no_reuse_worker=true
+
+# MSVC
+#mssdk.home=c:/Program Files/Microsoft Visual Studio/VC98
+
+

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/build.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/build.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/build.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,446 @@
+<project name="jk" default="build-main" basedir=".">
+  
+    <!-- We'll build jk for 3.3 or 4.0 ( depending on what you have installed ).
+    You need to set tomcat5.home, tomcat40.home, and/or tomcat33.home in
+    build.properties ( either the path to 'official' distribution or the
+    development dirs )
+    -->
+  
+    <!-- ===================== Initialize Property Values ================ -->
+    <property file="build.properties"/>
+    <property file="../build.properties"/>
+    <property file="../build.properties.default"/>
+    <property file="${user.home}/build.properties"/>
+    <property file="${user.home}/.build.properties"/>
+
+    <property name="jk.build" location="${basedir}/build"/>
+    <property name="build.docs" location="${basedir}/build/docs"/>
+    <property name="source.docs" location="./xdocs"/>
+    <property name="gen.dev.doc" value="false"/>
+
+    <!-- Compile options -->
+    <property name="optimize" value="off" />
+    <property name="compile.debug" value="true" />
+    <property name="compile.deprecation" value="false" />
+
+    <property name="tomcat-jk.jar" value="${jk.build}/lib/tomcat-jk.jar" />
+    <property name="tomcat-jkconfig.jar" value="${jk.build}/lib/jkconfig.jar" />
+    <property name="tomcat-jkshm.jar" value="${jk.build}/lib/jkshm.jar" />
+    <property name="tomcat-jk2.jar" value="${jk.build}/lib/tomcat-jk2.jar" />
+    <property name="tomcat-jni.jar" value="${jk.build}/lib/tomcat-jni.jar" />
+    <property name="tomcat-apr.jar" value="../jni/dist/tomcat-native-1.0.0.jar" />
+
+    <!-- default locations, overrident by properties -->
+    <property name="base.path" location="/usr/share/java"/>
+
+    <property name="tomcat33.home" 
+              location="../../jakarta-tomcat/build/tomcat/lib/common/tomcat_core.jar" />
+    <property name="tomcat40.home" 
+	      location="../../jakarta-tomcat-4.0/build" />
+    <property name="tomcat41.home" 
+	      location="../../jakarta-tomcat-4.1/build" />
+    <property name="tomcat5.home" 
+	      location="../../jakarta-tomcat-catalina/build" />
+    <property name="coyote.home" 
+	      location="../coyote/build" />
+    <property name="tomcat-util.home" location="../util/build" />
+    <property name="tomcat-coyote.jar" location="${coyote.home}/lib/tomcat-coyote.jar" />
+    <property name="servlet-api.jar" location="${tomcat5.home}/common/lib/servlet-api.jar" />
+    <property name="tomcat-util.jar" location="${tomcat-util.home}/lib/tomcat-util.jar" />
+
+    <property name="tc4-catalina.jar" location="${tomcat41.home}/server/lib/catalina.jar" />
+    <property name="tc5-catalina.jar" location="${tomcat5.home}/server/lib/catalina.jar" />
+    <property name="tc3-core.jar" location="${tomcat33.home}/lib/common/tomcat_core.jar" />
+    <property name="tc3-core_util.jar" location="${tomcat33.home}/lib/common/core_util.jar" />
+    <property name="tc3-util.jar" location="${tomcat33.home}/lib/container/tomcat_util.jar" />
+    <property name="tc3-modules.jar" location="${tomcat33.home}/lib/container/tomcat_modules.jar" />
+    <property name="commons-modeler.jar" location="../../jakarta-commons/modeler/dist/commons-modeler.jar" />
+
+    <!-- Fix build via ECLIPSE which didn't export ant's jars -->
+    <path id="xml-apis.classpath">
+        <pathelement path="${jaxp.home}/jaxp.jar"/>
+        <pathelement path="${jaxp.home}/crimson.jar"/>
+        <pathelement path="${xerces2.home}/xml-apis.jar"/>
+        <pathelement path="${xml-parser-apis.jar}"/>
+    </path>
+    
+    <path id="build-main.classpath">
+        <pathelement location="../util/build/classes"/>
+        <pathelement location="${servlet-api.jar}"/>
+        <pathelement location="${tomcat-util.jar}" />
+        <pathelement location="${commons-logging.jar}"/>
+        <pathelement location="${commons-modeler.jar}"/>
+        <pathelement location="${jmx.jar}"/>
+        <pathelement location="${tomcat-coyote.jar}"/>
+    </path>
+
+    <path id="build-tc4.classpath">
+        <pathelement location="${tc4-catalina.jar}" />
+        <pathelement location="${servlet-api.jar}" />
+    </path>    
+    <path id="build-tc5.classpath">
+        <pathelement location="${tc5-catalina.jar}" />
+        <pathelement location="${servlet-api.jar}" />
+    </path>    
+    <path id="build-tc3.classpath">
+       <pathelement location="${tc3-core.jar}" />
+       <pathelement location="${tc3-core_util.jar}" />
+       <pathelement location="${tc3-util.jar}" />
+       <pathelement location="${tc3-modules.jar}" />
+       <pathelement location="${servlet-api.jar}" />
+   </path>
+  <!-- ==================== Detection and reports ==================== -->
+
+    <target name="report"  >
+        <echo message="Tomcat33: ${tomcat33.detect} ${tomcat33.home}" />
+        <echo message="Tomcat40:  ${tomcat40.detect} ${tomcat40.home}" />
+        <echo message="Tomcat41: ${tomcat41.detect} ${tomcat41.home}" />
+        <echo message="Tomcat5:  ${tomcat5.detect} ${tomcat5.home}" />
+        <echo message="Apache13: ${apache13.detect} ${apache13.home}" />
+        <echo message="Apache2: ${apache2.detect} ${apache2.home}" />
+        <echo message="iPlanet:  ${iplanet.detect} ${iplanet.home}" />
+        <echo message="IIS:      ${iis.detect} ${iis.home}" />
+        <echo message="AOLserver: ${aolserver.detect} ${aolserver.home}" />
+        <echo message="jmx:      ${jmx.jar} ${jmx.detect} ${commons-modeler.jar} ${modeler.detect}" />
+    </target>
+
+    <target name="detect" >
+        <echo message="-------- tomcat-connectors --------" /> 
+        <available property="tomcat33.detect" 
+                   file="${tc3-core.jar}" />
+        <available property="tomcat40.detect" 
+                   file="${tc4-catalina.jar}" />
+        <available property="tomcat41.detect" 
+                   file="${tomcat41.home}/server/webapps" />
+        <condition property="tomcat5.detect">
+          <and>
+            <available
+              classname="javax.servlet.ServletRequestEvent"
+              classpath="${servlet-api.jar}" />
+            <available file="${tc5-catalina.jar}" />
+          </and>
+        </condition>
+        <available property="apache13.detect" 
+                   file="${apache13.home}" />
+        <available property="apache2.detect" 
+                   file="${apache2.home}" />
+        <available property="iis.detect" 
+                   file="${iis.home}" />
+        <available property="iplanet.detect" 
+                   file="${iplanet.home}" />
+        <available property="aolserver.detect" 
+                   file="${aolserver.home}" />
+        <available property="jmx.detect" 
+                   file="${jmx.jar}" />
+        <available property="jdk14.detect" 
+                   classname="java.nio.MappedByteBuffer" />
+        <available property="modeler.detect" 
+                   file="${commons-modeler.jar}" />
+        <!-- Check if we can find the XSLTProcessor class in the classpath -->
+        <available
+                   property="avail.xalan"
+                   classname="org.apache.xalan.xslt.Process">
+                   <!--
+                   <classpath refid="classpath"/>
+                    -->
+        </available>
+    </target>
+
+    <target name="prepare" depends="detect" >
+        <mkdir dir="${jk.build}"/>
+        <mkdir dir="${jk.build}"/>
+        <mkdir dir="${jk.build}/conf"/>
+	<mkdir dir="${jk.build}/classes"/>
+        <mkdir dir="${jk.build}/classes/META-INF" />
+	<mkdir dir="${jk.build}/lib"/>
+	<copy todir="${jk.build}/conf" >
+	    <fileset dir="conf" includes="*" />
+	</copy>
+
+        <!-- util and coyote must be build first -->
+        <copy  tofile="${jk.build}/lib/tomcat-coyote.jar"
+              file="${tomcat-coyote.jar}" />
+
+        <!-- Fix build via ECLIPSE which didn't export ant's jars -->
+        <path id="xml-apis.classpath">
+          <pathelement path="${jaxp.home}/jaxp.jar"/>
+          <pathelement path="${jaxp.home}/crimson.jar"/>
+          <pathelement path="${xerces2.home}/xml-apis.jar"/>
+          <pathelement path="${xml-parser-apis.jar}"/>
+        </path>
+
+    </target>
+     
+    <target name="build-main" 
+            depends="prepare,report,jkjava" />
+
+    <!-- build all the stuff -->
+    <target name="all" 
+            depends="prepare,report,coyote,jkjava,jkant" />
+
+    <!-- Build only jk, assume coyote and utils are built -->
+    <target name="build-jk" 
+            depends="prepare,report,jkjava" />
+
+    <!-- ==================== Building ==================== -->
+    <target name="jkjava-static" depends="prepare,report" >
+	<!-- Copy static resource files -->
+	<copy todir="${jk.build}/classes">
+	    <fileset dir="java">
+	    	<include name="**/*.properties"/>
+	    </fileset>
+        </copy>
+        <copy todir="${jk.build}/classes" >
+          <fileset dir="java" includes="**/*.xml" />
+        </copy>
+    </target>
+    <target name="jkjava-shared" depends="jkjava-static" 
+             description="Build shared java side of the connector" >
+        <javac srcdir="java"
+               destdir="${jk.build}/classes"
+               deprecation="${compile.deprecation}"
+               debug="${compile.debug}"
+               optimize="${optimize}"
+               verbose="off" >
+            <include name="org/apache/jk/**"/>
+            <include name="org/apache/coyote/ajp/**" />
+	    <exclude name="org/apache/jk/common/JkMX.java" unless="jmx.detect"/>
+	    <exclude name="org/apache/jk/common/ModJkMX.java" unless="jmx.detect"/>
+	    <exclude name="org/apache/jk/common/Shm14.java" unless="jdk14.detect"/>
+            <exclude name="org/apache/jk/config/*Config.java"  />
+            <exclude name="org/apache/jk/ant/**" />
+	    <classpath>
+	       <pathelement location="${tomcat-apr.jar}" />
+	       <path refid="xml-apis.classpath"/>
+	       <path refid="build-main.classpath"/>
+	    </classpath>
+	</javac>
+	<jar jarfile="${tomcat-jkconfig.jar}"
+             index="true"
+	     basedir="${jk.build}/classes" 
+             manifest="conf/jkconfig.manifest">
+            <include name="org/apache/jk/config/**" />
+        </jar>
+	<jar jarfile="${tomcat-jk2.jar}"
+             index="true"
+             manifest="conf/tomcat-jk2.manifest"
+	     basedir="${jk.build}/classes" >
+            <include name="org/apache/jk/**" />
+            <include name="org/apache/coyote/ajp/**" />
+            <exclude name="org/apache/jk/ant/**" />
+        </jar>
+	
+	<jar jarfile="${tomcat-jni.jar}"
+             index="true"
+	     basedir="${jk.build}/classes" 
+             manifest="conf/jk2.manifest" >
+            <include name="org/apache/jk/apr/**" />
+            <include name="org/apache/jk/core/**" />
+        </jar>
+	
+    </target>
+    <target name="jkjava-tc5" depends="jkjava-shared" if="tomcat5.detect"
+           description="Build TC5 java side of the connector" >
+        <javac srcdir="java"
+               destdir="${jk.build}/classes"
+               deprecation="${compile.deprecation}"
+               debug="${compile.debug}"
+               optimize="${optimize}"
+               verbose="off" >
+            <include name="org/apache/coyote/ajp/**"/>
+            <include name="org/apache/jk/config/**"/>
+	    <classpath>
+	       <path refid="xml-apis.classpath"/>
+	       <path refid="build-main.classpath"/>
+               <path refid="build-tc5.classpath"/>
+	    </classpath>
+	</javac>
+	<jar jarfile="${tomcat-jkconfig.jar}"
+             index="true"
+	     basedir="${jk.build}/classes" 
+             manifest="conf/jkconfig.manifest">
+            <include name="org/apache/jk/config/**" />
+        </jar>
+    </target>
+    <target name="jkjava-tc4" depends="jkjava-shared" if="tomcat40.detect"
+           description="Build the TC4 java side of the connector">
+        <javac srcdir="java"
+               destdir="${jk.build}/classes"
+               deprecation="${compile.deprecation}"
+               debug="${compile.debug}"
+               optimize="${optimize}"
+               verbose="off" >
+            <include name="org/apache/ajp/**" />
+            <exclude name="org/apache/ajp/tomcat33/**" />
+	    <classpath>
+	       <path refid="xml-apis.classpath"/>
+	       <path refid="build-main.classpath"/>
+               <path refid="build-tc4.classpath"/>
+	    </classpath>
+
+	</javac>
+
+	<jar jarfile="${tomcat-jk.jar}"
+             index="true"
+	     basedir="${jk.build}/classes">
+            <include name="org/apache/ajp/**" />
+        </jar>
+	
+	<jar jarfile="${tomcat-jkshm.jar}"
+             index="true"
+	     basedir="${jk.build}/classes" 
+             manifest="conf/shm.manifest">
+            <include name="org/apache/ajp/common/Shm.class" />
+        </jar>
+    </target>
+    <target name="jkjava-tc3" depends="jkjava-shared" if="tomcat33.detect"
+           description="Build the TC3 java side of the connector">
+        <javac srcdir="java"
+               destdir="${jk.build}/classes"
+               deprecation="${compile.deprecation}"
+               debug="${compile.debug}"
+               optimize="${optimize}"
+               verbose="off" >
+            <include name="org/apache/ajp/**" />
+            <exclude name="org/apache/ajp/tomcat4/**" />
+	    <classpath>
+	       <path refid="xml-apis.classpath"/>
+	       <path refid="build-main.classpath"/>
+               <path refid="build-tc3.classpath"/>
+	    </classpath>
+
+	</javac>
+
+	<jar jarfile="${tomcat-jk.jar}"
+             index="true"
+	     basedir="${jk.build}/classes">
+            <include name="org/apache/ajp/**" />
+        </jar>
+	
+    </target>
+    <target name="jkjava" depends="jkjava-tc3,jkjava-tc4,jkjava-tc5"
+            description="Build java side of the connector" >
+    </target>
+    
+    <target name="jkant" >
+        <mkdir dir="${jk.build}/classes"/>
+        <mkdir dir="${jk.build}/classes/META-INF" />
+        <mkdir dir="${jk.build}/lib"/>
+	<javac srcdir="jkant/java" 
+	       destdir="${jk.build}/classes" 
+	       debug="${compile.debug}"
+               deprecation="${compile.deprecation}"
+	       optimize="${optimize}"
+	       verbose="off" >
+	</javac>
+	<copy todir="${jk.build}/classes/META-INF" 
+              file="jkant/ant.tasks"/>
+	<jar jarfile="${jk.build}/lib/jkant.jar"
+             index="true"
+	     basedir="${jk.build}/classes" >
+            <include name="org/apache/jk/ant/**" />
+            <include name="META-INF/ant.tasks" />
+        </jar>
+    </target>
+    
+    <target name="coyote" 
+            description="Build utils" >
+        <ant dir="../util"  />
+        <ant dir="../coyote" />
+    </target>
+
+
+    <!-- ================ Experimental: Xdoclet =================== -->
+
+    <!-- Use Javadoc tags to generate auxiliary files.
+    -->
+    <target name="xdoclet" depends="prepare">
+        <path id="xdoclet.classpath">
+            <pathelement location="../lib/xdoclet.jar"/>
+            <pathelement location="../lib/log4j-core.jar"/>
+            <pathelement location="${ant.home}/lib/ant.jar"/>
+            <path refid="build-main.classpath" />
+        </path>
+        
+        
+        <taskdef name="webdoclet"
+                 classname="xdoclet.web.WebDocletTask" 
+                 classpathref="xdoclet.classpath" />
+        <taskdef name="document"
+                 classname="xdoclet.doc.DocumentDocletTask"
+                 classpathref="xdoclet.classpath" />
+        <taskdef name="jmxdoclet"
+                 classname="xdoclet.jmx.JMXDocletTask"
+                 classpathref="xdoclet.classpath" />
+            
+        <jmxdoclet sourcepath="java"
+                   destdir="${jk.build}/jmx-java"
+                   classpathref="xdoclet.classpath"
+                   force="${xdoclet.force}">
+            <fileset dir="java">
+               <include name="**/*.java" />
+            </fileset>
+
+            <!-- Create the {0}MBean interface for the MBean -->
+            <mbeaninterface mergedir="java"/>
+
+            <!-- Create the OpenJMX specific description adaptor class for the MBean -->
+            <openjmxDescription />
+
+            <!--create the jbossmx xml descriptor for the mbean-->
+            <jbossxmbean/>
+
+            <!--create the jboss xml service template for the mbean-->
+           <jbossXmlServiceTemplate/>
+        </jmxdoclet>
+
+            
+        <document sourcepath="java"
+                  destdir="${jk.build}/todo" 
+                  classpathref="xdoclet.classpath" >
+            <fileset dir="java">
+                <include name="**/*.java" />
+            </fileset>
+            <info header="Todo list"
+                  projectname="JK2"
+                  tag="todo" />
+         </document>
+
+    </target>
+
+    <!-- ================ javadocs =================== -->
+    <target name="javadoc" unless="docs-uptodate">
+        <delete dir="${jk.build}/javadoc"/>
+	<mkdir dir="${jk.build}/javadoc"/>
+	<javadoc packagenames="org.apache.ajp,org.apache.ajp.tomcat4,org.apache.ajp,org.apache.ajp.tomcat5"
+                 sourcepath="java"
+                 classpath="${tomcat5.home}/server/lib/catalina.jar:${tomcat5.home}/common/lib/servlet-api.jar:${tomcat41.home}/server/lib/catalina.jar:${tomcat41.home}/common/lib/servlet.jar:${tomcat40.home}/server/lib/catalina.jar:${tomcat40.home}/common/lib/servlet.jar:${tomcat-util.jar}"
+                 destdir="${jk.build}/javadoc"
+                 author="true"
+                 version="true"
+                 windowtitle="Jk Connector Documentation"
+                 doctitle="Jk Connector"
+                 bottom="Copyright &#169; 2001-2005 Apache Software Foundation.  All Rights Reserved."
+	/>
+    </target>
+
+    <target name="clean">
+        <delete dir="${jk.build}/classes"/>
+        <delete dir="${jk.build}/lib"/>
+        <delete dir="${jk.build}/javadoc"/>
+        <delete dir="${build.docs}"/>
+    </target>
+
+    <!-- It's better to call it directly with individual tags -->
+    <target name="native" depends="jkant,detect,report" >
+	<ant  dir="native" antfile="build.xml"  />
+	<ant  dir="native2" antfile="build.xml"  />
+    </target>
+
+    <target name="clean-native">
+        <ant  dir="native" antfile="build.xml" target="clean"  />
+        <ant  dir="native2" antfile="build.xml" target="clean"  />
+    </target>
+
+
+</project>

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/conf/jk2.manifest
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/conf/jk2.manifest	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/conf/jk2.manifest	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,2 @@
+Main-Class: org.apache.jk.apr.TomcatStarter
+Class-Path: ../lib/tomcat.jar log4j.jar log4j-core.jar ../lib/common/log4j.jar ../lib/common/log4j-core.jar ../lib/common/classes ../lib/common/commons-logging.jar bootstrap.jar ../server/lib/commons-logging.jar ../server/lib/jmx.jar jmx.jar commons-logging-api.jar

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/conf/jk2.properties
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/conf/jk2.properties	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/conf/jk2.properties	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,26 @@
+## THIS FILE MAY BE OVERRIDEN AT RUNTIME. MAKE SURE TOMCAT IS STOPED
+## WHEN YOU EDIT THE FILE.
+
+## COMMENTS WILL BE _LOST_
+
+## DOCUMENTATION OF THE FORMAT IN JkMain javadoc.
+
+# Set the desired handler list
+# handler.list=apr,request,channelJni
+#
+# Override the default port for the socketChannel
+# channelSocket.port=8019
+# Default: 
+# channelUnix.file=${jkHome}/work/jk2.socket
+# Just to check if the the config  is working
+# shm.file=${jkHome}/work/jk2.shm
+
+# In order to enable jni use any channelJni directive
+# channelJni.disabled = 0
+# And one of the following directives:
+
+# apr.jniModeSo=/opt/apache2/modules/mod_jk2.so
+
+# If set to inprocess the mod_jk2 will Register natives itself
+# This will enable the starting of the Tomcat from mod_jk2
+# apr.jniModeSo=inprocess

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/conf/jkconf.ant.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/conf/jkconf.ant.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/conf/jkconf.ant.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,51 @@
+<project name="jkconf" default="main" basedir=".">
+
+    <target name="init-3x" if="33.detect">
+        <taskdef name="jkconf" 
+                 classname="org.apache.jk.config.WebXml2Jk" >
+            <classpath>
+                <!-- 3.3 support -->
+                <pathelement location="/ws/jtc/jk/build/classes" />
+                <pathelement location="${tomcat.home}/lib/container/tomcat-jk2.jar" />
+                <pathelement location="${tomcat.home}/lib/container/crimson.jar"/>
+                <pathelement location="${tomcat.home}/lib/common/commons-logging.jar"/>
+            </classpath>
+        </taskdef>
+    </target>
+
+    <target name="init-4x" if="4x.detect" >
+        <path id="main.classpath">
+            <!-- 3.3 support -->
+            <fileset dir="${tomcat.home}/lib" includes="*.jar" />
+            <fileset dir="${tomcat.home}/server/lib" includes="*.jar" />
+            <fileset dir="${tomcat.home}/common/lib" includes="*.jar" />
+        </path>
+        
+        <taskdef name="jkconf" classpathref="main.classpath" 
+                 classname="org.apache.jk.config.WebXml2Jk" />
+    </target>
+
+    <target name="detect" >
+        <property file="build.properties"/>
+        <property file="${user.home}/build.properties"/>
+        <property file="${user.home}/.build.properties"/>
+            
+            <!-- default locations, overrident by properties.
+            This file must be installed in conf/  -->
+        <property name="tomcat.home" location=".." />
+            
+        <available property="33.detect" file="${tomcat.home}/lib/container" />
+        <available property="4x.detect" file="${tomcat.home}/server/lib" />
+    </target>
+
+    <target name="init" depends="detect,init-3x,init-4x" />
+
+    <!-- ==================== Detection and reports ==================== -->
+
+
+    <target name="main" depends="init">
+        <jkconf docBase="${tomcat.home}/webapps/examples" 
+                context="/examples" />
+    </target>
+
+</project>

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/conf/jkconfig.manifest
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/conf/jkconfig.manifest	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/conf/jkconfig.manifest	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,2 @@
+Main-Class: org.apache.jk.config.WebXml2Jk
+Class-Path: tomcat-jk2.jar commons-logging.jar crimson.jar xercesImpl.jar xmlApis.jar tomcat-util.jar log4j.jar log4j-core.jar

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/conf/shm.manifest
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/conf/shm.manifest	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/conf/shm.manifest	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,2 @@
+Main-Class: org.apache.jk.common.Shm
+Class-Path: tomcat-jk2.jar commons-logging.jar tomcat-util.jar log4j.jar log4j-core.jar

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/conf/tomcat-jk2.manifest
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/conf/tomcat-jk2.manifest	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/conf/tomcat-jk2.manifest	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,7 @@
+Manifest-version: 1.0
+Extension-Name: org.apache.jk
+Specification-Vendor: Apache Software Foundation
+Specification-Version: 2.0
+Implementation-Vendor-Id: org.apache
+Implementation-Vendor: Apache Software Foundation
+Implementation-Version: 2.1

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/conf/uriworkermap.properties
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/conf/uriworkermap.properties	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/conf/uriworkermap.properties	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,23 @@
+# uriworkermap.properties - IIS
+#
+# This file provides sample mappings for example wlb
+# worker defined in workermap.properties.minimal
+# The general syntax for this file is:
+# [URL]=[Worker name]
+
+/admin/*=wlb
+/manager/*=wlb
+/jsp-examples/*=wlb
+/servlets-examples/*=wlb
+
+# Optionally filter out all .jpeg files inside that context
+# For no mapping the url has to start with exclamation (!)
+
+!/servlets-examples/*.jpeg=wlb
+
+#
+# Mount jkstatus to /jkmanager
+# For production servers you will need to
+# secure the access to the /jkmanager url
+#
+/jkmanager=jkstatus

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/conf/workers.properties
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/conf/workers.properties	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/conf/workers.properties	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,206 @@
+# workers.properties -
+#
+# This file provides jk derived plugins with the needed information to
+# connect to the different tomcat workers.  Note that the distributed
+# version of this file requires modification before it is usable by a
+# plugin.
+#
+# As a general note, the characters $( and ) are used internally to define
+# macros. Do not use them in your own configuration!!!
+#
+# Whenever you see a set of lines such as:
+# x=value
+# y=$(x)\something
+#
+# the final value for y will be value\something
+#
+# Normaly all you will need to do is un-comment and modify the first three
+# properties, i.e. workers.tomcat_home, workers.java_home and ps.
+# Most of the configuration is derived from these.
+#
+# When you are done updating workers.tomcat_home, workers.java_home and ps
+# you should have 3 workers configured:
+#
+# - An ajp12 worker that connects to localhost:8007
+# - An ajp13 worker that connects to localhost:8009
+# - A jni inprocess worker.
+# - A load balancer worker
+#
+# However by default the plugins will only use the ajp12 worker. To have
+# the plugins use other workers you should modify the worker.list property.
+#
+#
+
+# OPTIONS ( very important for jni mode ) 
+
+#
+# workers.tomcat_home should point to the location where you
+# installed tomcat. This is where you have your conf, webapps and lib
+# directories.
+#
+workers.tomcat_home=/var/tomcat3
+
+#
+# workers.java_home should point to your Java installation. Normally
+# you should have a bin and lib directories beneath it.
+#
+workers.java_home=/opt/IBMJava2-13
+
+#
+# You should configure your environment slash... ps=\ on NT and / on UNIX
+# and maybe something different elsewhere.
+#
+ps=/
+
+#
+#------ ADVANCED MODE ------------------------------------------------
+#---------------------------------------------------------------------
+#
+
+#
+#------ DEFAULT worket list ------------------------------------------
+#---------------------------------------------------------------------
+#
+#
+# The workers that your plugins should create and work with
+#
+# Add 'inprocess' if you want JNI connector 
+worker.list=ajp12, ajp13
+# , inprocess
+
+
+#
+#------ DEFAULT ajp12 WORKER DEFINITION ------------------------------
+#---------------------------------------------------------------------
+#
+
+#
+# Defining a worker named ajp12 and of type ajp12
+# Note that the name and the type do not have to match.
+#
+worker.ajp12.port=8007
+worker.ajp12.host=localhost
+worker.ajp12.type=ajp12
+#
+# Specifies the load balance factor when used with
+# a load balancing worker.
+# Note:
+#  ----> lbfactor must be > 0
+#  ----> Low lbfactor means less work done by the worker.
+worker.ajp12.lbfactor=1
+
+#
+#------ DEFAULT ajp13 WORKER DEFINITION ------------------------------
+#---------------------------------------------------------------------
+#
+
+#
+# Defining a worker named ajp13 and of type ajp13
+# Note that the name and the type do not have to match.
+#
+worker.ajp13.port=8009
+worker.ajp13.host=localhost
+worker.ajp13.type=ajp13
+#
+# Specifies the load balance factor when used with
+# a load balancing worker.
+# Note:
+#  ----> lbfactor must be > 0
+#  ----> Low lbfactor means less work done by the worker.
+worker.ajp13.lbfactor=1
+
+#
+# Specify the size of the open connection pool.
+#worker.ajp13.connection_pool_size
+
+#
+#------ DEFAULT LOAD BALANCER WORKER DEFINITION ----------------------
+#---------------------------------------------------------------------
+#
+
+#
+# The loadbalancer (type lb) workers perform wighted round-robin
+# load balancing with sticky sessions.
+# Note:
+#  ----> If a worker dies, the load balancer will check its state
+#        once in a while. Until then all work is redirected to peer
+#        workers.
+worker.loadbalancer.type=lb
+worker.loadbalancer.balanced_workers=ajp12, ajp13
+
+
+#
+#------ DEFAULT JNI WORKER DEFINITION---------------------------------
+#---------------------------------------------------------------------
+#
+
+#
+# Defining a worker named inprocess and of type jni
+# Note that the name and the type do not have to match.
+#
+worker.inprocess.type=jni
+
+#
+#------ CLASSPATH DEFINITION -----------------------------------------
+#---------------------------------------------------------------------
+#
+
+#
+# Additional class path components.
+#
+worker.inprocess.class_path=$(workers.tomcat_home)$(ps)lib$(ps)tomcat.jar
+
+#
+# Setting the command line for tomcat. 
+# Note: The cmd_line string may not contain spaces.
+#
+worker.inprocess.cmd_line=start
+
+# Not needed, but can be customized.
+#worker.inprocess.cmd_line=-config
+#worker.inprocess.cmd_line=$(workers.tomcat_home)$(ps)conf$(ps)server.xml
+#worker.inprocess.cmd_line=-home
+#worker.inprocess.cmd_line=$(workers.tomcat_home)
+
+#
+# The JVM that we are about to use
+#
+# This is for Java2
+#
+# Windows
+worker.inprocess.jvm_lib=$(workers.java_home)$(ps)jre$(ps)bin$(ps)classic$(ps)jvm.dll
+# IBM JDK1.3 
+#worker.inprocess.jvm_lib=$(workers.java_home)$(ps)jre$(ps)bin$(ps)classic$(ps)libjvm.so
+# Unix - Sun VM or blackdown
+#worker.inprocess.jvm_lib=$(workers.java_home)$(ps)jre$(ps)lib$(ps)i386$(ps)classic$(ps)libjvm.so
+
+#
+# And this is for jdk1.1.X
+#
+#worker.inprocess.jvm_lib=$(workers.java_home)$(ps)bin$(ps)javai.dll
+
+
+#
+# Setting the place for the stdout and stderr of tomcat
+#
+worker.inprocess.stdout=$(workers.tomcat_home)$(ps)logs$(ps)inprocess.stdout
+worker.inprocess.stderr=$(workers.tomcat_home)$(ps)logs$(ps)inprocess.stderr
+
+#
+# Setting the tomcat.home Java property
+#
+#worker.inprocess.sysprops=tomcat.home=$(workers.tomcat_home)
+
+#
+# Java system properties
+#
+# worker.inprocess.sysprops=java.compiler=NONE
+# worker.inprocess.sysprops=myprop=mypropvalue
+
+#
+# Additional path components.
+#
+# worker.inprocess.ld_path=d:$(ps)SQLLIB$(ps)bin
+#
+
+

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/conf/workers.properties.minimal
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/conf/workers.properties.minimal	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/conf/workers.properties.minimal	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,30 @@
+# workers.properties.minimal -
+#
+# This file provides minimal jk configuration properties needed to
+# connect to Tomcat.
+#
+# The workers that jk should create and work with
+#
+
+worker.list=wlb,jkstatus
+
+#
+# Defining a worker named ajp13w and of type ajp13
+# Note that the name and the type do not have to match.
+#
+worker.ajp13w.type=ajp13
+worker.ajp13w.host=localhost
+worker.ajp13w.port=8009
+
+#
+# Defining a load balancer
+# 
+
+worker.wlb.type=lb
+worker.wlb.balance_workers=ajp13w
+
+#
+# Define status worker
+#
+
+worker.jkstatus.type=status

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/conf/workers2.properties
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/conf/workers2.properties	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/conf/workers2.properties	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,132 @@
+[logger]
+level=DEBUG
+
+[config:]
+file=${serverRoot}/conf/workers2.properties
+debug=0
+debugEnv=0
+
+[uriMap:]
+info=Maps the requests. Options: debug
+debug=0
+
+# Alternate file logger
+#[logger.file:0]
+#level=DEBUG
+#file=${serverRoot}/logs/jk2.log
+
+[shm:]
+info=Scoreboard. Required for reconfiguration and status with multiprocess servers
+file=${serverRoot}/logs/jk2.shm
+size=1000000
+debug=0
+disabled=0
+
+[workerEnv:]
+info=Global server options
+timing=1
+debug=0
+# Default Native Logger (apache2 or win32 ) 
+# can be overriden to a file logger, useful 
+# when tracing win32 related issues
+#logger=logger.file:0
+
+[lb:lb]
+info=Default load balancer.
+debug=0
+
+[lb:lb_1]
+info=A second load balancer.
+debug=0
+
+[channel.socket:localhost:8009]
+info=Ajp13 forwarding over socket
+debug=0
+tomcatId=localhost:8009
+
+[channel.socket:localhost:8019]
+info=A second tomcat instance. 
+debug=0
+tomcatId=localhost:8019
+lb_factor=1
+#group=lb
+group:lb:lb
+#group=lb_1
+group:lb:lb_1
+disabled=0
+
+[channel.un:/opt/33/work/jk2.socket]
+info=A second channel connecting to localhost:8019 via unix socket
+tomcatId=localhost:8019
+lb_factor=1
+debug=0
+
+[channel.jni:jni]
+info=The jni channel, used if tomcat is started inprocess
+
+[status:]
+info=Status worker, displays runtime informations
+
+[vm:]
+info=Parameters used to load a JVM in the server process
+#JVM=C:\jdk\jre\bin\hotspot\jvm.dll
+classpath=${TOMCAT_HOME}/bin/tomcat-jni.jar
+classpath=${TOMCAT_HOME}/server/lib/commons-logging.jar
+OPT=-Dtomcat.home=${TOMCAT_HOME}
+OPT=-Dcatalina.home=${TOMCAT_HOME}
+OPT=-Xmx128M
+#OPT=-Djava.compiler=NONE
+disabled=1
+
+[worker.jni:onStartup]
+info=Command to be executed by the VM on startup. This one will start tomcat.
+class=org/apache/jk/apr/TomcatStarter
+ARG=start
+# For Tomcat 5 use the 'stard' for startup argument
+# ARG=stard
+disabled=1
+stdout=${serverRoot}/logs/stdout.log
+stderr=${serverRoot}/logs/stderr.log
+
+[worker.jni:onShutdown]
+info=Command to be executed by the VM on shutdown. This one will stop tomcat.
+class=org/apache/jk/apr/TomcatStarter
+ARG=stop
+disabled=1
+
+[uri:/jkstatus/*]
+info=Display status information and checks the config file for changes.
+group=status:
+
+[uri:127.0.0.1:8003]
+info=Example virtual host. Make sure myVirtualHost is in /etc/hosts to test it
+alias=myVirtualHost:8003
+
+[uri:127.0.0.1:8003/ex]
+info=Example webapp in the virtual host. It'll go to lb_1 ( i.e. localhost:8019 )
+context=/ex
+group=lb_1
+
+[uri:/examples]
+info=Example webapp in the default context. 
+context=/examples
+debug=0
+
+[uri:/examples1/*]
+info=A second webapp, this time going to the second tomcat only.
+group=lb_1
+debug=0
+
+[uri:/examples/servlet/*]
+info=Prefix mapping
+
+[uri:/examples/*.jsp]
+info=Extension mapping
+
+[uri:/examples/*]
+info=Map the whole webapp
+
+[uri:/examples/servlet/HelloW]
+info=Example with debug enabled.
+debug=10
+

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/conf/workers2.properties.minimal
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/conf/workers2.properties.minimal	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/conf/workers2.properties.minimal	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,55 @@
+#
+# This is the minimal JK2 connector configuration file.
+# 
+
+[logger]
+info=Native logger
+level=ERROR
+
+[config:]
+file=${serverRoot}/conf/workers2.properties
+debug=0
+debugEnv=0
+
+[uriMap:]
+info=Maps the requests.
+debug=0
+
+[shm:]
+info=Scoreboard. Required for reconfiguration and status with multiprocess servers
+file=anonymous
+debug=0
+
+[workerEnv:]
+info=Global server options
+timing=0
+debug=0
+
+[lb:lb]
+info=Default load balancer.
+debug=0
+
+[channel.socket:localhost:8009]
+info=Ajp13 forwarding over socket
+debug=0
+tomcatId=localhost:8009
+
+[uri:/admin]
+info=Tomcat HTML based administration web application.
+debug=0
+
+[uri:/manager]
+info=A scriptable management web application for the Tomcat Web Server.
+debug=0
+
+[uri:/jsp-examples]
+info=JSP 2.0 Examples.
+debug=0
+
+[uri:/servlets-examples]
+info=Servlet 2.4 Examples.
+debug=0
+
+[uri:/*.jsp]
+info=JSP Extension mapping.
+debug=0

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/ajp/Ajp13.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/ajp/Ajp13.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/ajp/Ajp13.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,512 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.ajp;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.Socket;
+
+import org.apache.tomcat.util.http.BaseRequest;
+import org.apache.tomcat.util.http.HttpMessages;
+import org.apache.tomcat.util.http.MimeHeaders;
+
+/**
+ * Represents a single, persistent connection between the web server and
+ * the servlet container.  Uses the Apache JServ Protocol version 1.3 for
+ * communication.  Because this protocal does not multiplex requests, this
+ * connection can only be associated with a single request-handling cycle
+ * at a time.<P>
+ *
+ * This class contains knowledge about how an individual packet is laid out
+ * (via the <CODE>Ajp13Packet</CODE> class), and also about the
+ * stages of communicaton between the server and the servlet container.  It
+ * translates from Tomcat's internal servlet support methods
+ * (e.g. doWrite) to the correct packets to send to the web server.
+ *
+ * @author Dan Milstein [danmil at shore.net]
+ * @author Keith Wannamaker [Keith at Wannamaker.org]
+ * @author Kevin Seguin [seguin at apache.org]
+ * @author Henri Gomez [hgomez at apache.org]
+ * @author Costin Manolache
+ */
+public class Ajp13 {
+
+    public static final int MAX_PACKET_SIZE=8192;
+    public static final int H_SIZE=4;  // Size of basic packet header
+
+    public static final int  MAX_READ_SIZE = MAX_PACKET_SIZE - H_SIZE - 2;
+    public static final int  MAX_SEND_SIZE = MAX_PACKET_SIZE - H_SIZE - 4;
+
+    // Error code for Ajp13
+    public static final int  JK_AJP13_BAD_HEADER        = -100;
+    public static final int  JK_AJP13_NO_HEADER         = -101;
+    public static final int  JK_AJP13_COMM_CLOSED       = -102;
+    public static final int  JK_AJP13_COMM_BROKEN       = -103;
+    public static final int  JK_AJP13_BAD_BODY          = -104;
+    public static final int  JK_AJP13_INCOMPLETE_BODY   = -105;
+
+    // ============ Instance Properties ====================
+
+    OutputStream out;
+    InputStream in;
+
+    // Buffer used of output body and headers
+    public Ajp13Packet outBuf = new Ajp13Packet( MAX_PACKET_SIZE );
+    // Buffer used for input body
+    Ajp13Packet inBuf  = new Ajp13Packet( MAX_PACKET_SIZE );
+    // Buffer used for request head ( and headers )
+    Ajp13Packet hBuf=new Ajp13Packet( MAX_PACKET_SIZE );
+
+    // Holds incoming reads of request body data (*not* header data)
+    byte []bodyBuff = new byte[MAX_READ_SIZE];
+    
+    int blen;  // Length of current chunk of body data in buffer
+    int pos;   // Current read position within that buffer
+
+    boolean end_of_stream;  // true if we've received an empty packet
+    
+    // Required handler - essential request processing
+    public RequestHandler reqHandler;
+    // AJP14 - detect protocol,set communication parameters, login
+    // If no password is set, use only Ajp13 messaging
+    boolean backwardCompat=true;
+    boolean logged=false;
+    String secret=null;
+    
+    public Ajp13() {
+	super();
+	initBuf();
+        reqHandler=new RequestHandler();
+	reqHandler.init( this );
+    }
+
+    public Ajp13(RequestHandler reqHandler ) {
+	super();
+	initBuf();
+        this.reqHandler=reqHandler;
+	reqHandler.init( this );
+    }
+
+    /** Will be overriden
+     */
+    public void initBuf() {
+	outBuf = new Ajp13Packet( MAX_PACKET_SIZE );
+	inBuf  = new Ajp13Packet( MAX_PACKET_SIZE );
+	hBuf=new Ajp13Packet( MAX_PACKET_SIZE );
+    }
+    
+    public void recycle() {
+        if (debug > 0) {
+            logger.log("recycle()");
+        }
+
+        // This is a touch cargo-cultish, but I think wise.
+        blen = 0; 
+        pos = 0;
+        end_of_stream = false;
+        logged=false;
+    }
+    
+    /**
+     * Associate an open socket with this instance.
+     */
+    public void setSocket( Socket socket ) throws IOException {
+        if (debug > 0) {
+            logger.log("setSocket()");
+        }
+        
+	socket.setSoLinger( true, 100);
+	out = socket.getOutputStream();
+	in  = socket.getInputStream();
+	pos = 0;
+    }
+
+    /**
+     * Backward compat mode, no login  needed
+     */
+    public void setBackward(boolean b) 
+    {
+        backwardCompat=b;
+    }
+
+    public boolean isLogged() {
+	return logged;
+    }
+
+    void setLogged( boolean b ) {
+        logged=b;
+    }
+
+    public void setSecret( String s ) {
+        secret=s;
+    }
+
+    public String getSecret() {
+        return secret;
+    }
+    
+    // -------------------- Handlers registry --------------------
+
+    static final int MAX_HANDLERS=32;
+    static final int RESERVED=16;  // reserved names, backward compat
+
+    // Note that we don't make distinction between in and out
+    // messages ( i.e. one id is used only in one direction )
+    AjpHandler handlers[]=new AjpHandler[MAX_HANDLERS];
+    String handlerName[]=new String[MAX_HANDLERS];
+    int currentId=RESERVED;
+
+    public int registerMessageType( int id, String name, AjpHandler h,
+				    String sig[] )
+    {
+	if( id < 0 ) {
+	    // try to find it by name
+	    for( int i=0; i< handlerName.length; i++ )
+		if( name.equals( handlerName[i] ) ) return i;
+	    handlerName[currentId]=name;
+	    handlers[currentId]=h;
+	    currentId++;
+	    return currentId;
+	}
+	// fixed id
+	handlerName[id]=name;
+	handlers[id]=h;
+	return id;
+    }
+    
+    // -------------------- Main dispatch --------------------
+    
+    /**
+     * Read a new packet from the web server and decode it.  If it's a
+     * forwarded request, store its properties in the passed-in AjpRequest
+     * object.
+     *
+     * @param req An empty (newly-recycled) request object.
+     * 
+     * @return 200 in case of a successful read of a forwarded request, 500
+     * if there were errors in the reading of the request, and -2 if the
+     * server is asking the container to shut itself down.  
+     */
+    public int receiveNextRequest(BaseRequest req) throws IOException {
+        if (debug > 0) {
+            logger.log("receiveNextRequest()");
+        }
+        
+        // XXX The return values are awful.
+
+        int err = 0;
+
+        // if we receive an IOException here, it must be because
+        // the remote just closed the ajp13 connection, and it's not
+        // an error, we just need to close the AJP13 connection
+        try {
+            err = receive(hBuf);
+        } catch (IOException ioe) {
+            if(debug >0 ) logger.log( "IOException receiving message ");
+            return -1;  // Indicate it's a disconnection from the remote end
+        }
+        
+	if(err < 0) {
+	    if(debug >0 ) logger.log( "Error receiving message ");
+	    return 500;
+	}
+	
+	int type = (int)hBuf.getByte();
+        //        System.out.println("XXX " + this );
+        return handleMessage( type, hBuf, req );
+    }
+
+    /** Override for ajp14, temporary
+     */
+    public int handleMessage( int type, Ajp13Packet hBuf, BaseRequest req )
+        throws IOException
+    {
+        if( type > handlers.length ) {
+	    logger.log( "Invalid handler " + type );
+	    return 500;
+	}
+
+        if( debug > 0 )
+            logger.log( "Received " + type + " " + handlerName[type]);
+        
+        // Ajp14, unlogged
+	if( ! backwardCompat && ! isLogged() ) {
+	    if( type != NegociationHandler.JK_AJP14_LOGINIT_CMD &&
+		type != NegociationHandler.JK_AJP14_LOGCOMP_CMD ) {
+
+                logger.log( "Ajp14 error: not logged " +
+                            type + " " + handlerName[type]);
+
+		return 300;
+	    }
+	    // else continue
+	}
+
+        // Ajp13 messages
+	switch(type) {
+	case RequestHandler.JK_AJP13_FORWARD_REQUEST:
+	    return reqHandler.decodeRequest(this, hBuf, req);
+	    
+	case RequestHandler.JK_AJP13_CPING_REQUEST:
+		return reqHandler.sendCPong(this, outBuf);
+		
+	case RequestHandler.JK_AJP13_SHUTDOWN:
+	    return -2;
+	}
+
+	// logged || loging message
+	AjpHandler handler=handlers[type];
+	if( handler==null ) {
+	    logger.log( "Unknown message " + type + handlerName[type] );
+	    return 200;
+	}
+
+        if( debug > 0 )
+            logger.log( "Ajp14 handler " + handler );
+	return handler.handleAjpMessage( type, this, hBuf, req );
+    }
+
+    // ==================== Servlet Input Support =================
+
+    /** @deprecated -- Will use reqHandler, make sure nobody else
+     calls this */
+
+    
+    public int available() throws IOException {
+        return reqHandler.available(this);
+    }
+
+    public int doRead() throws IOException 
+    {
+        return reqHandler.doRead( this );
+    }
+    
+    public int doRead(byte[] b, int off, int len) throws IOException 
+    {
+        return reqHandler.doRead( this, b, off, len );
+    }
+    
+    private boolean refillReadBuffer() throws IOException 
+    {
+        return reqHandler.refillReadBuffer(this);
+    }    
+
+    public void beginSendHeaders(int status,
+                                 String statusMessage,
+                                 int numHeaders) throws IOException {
+        reqHandler.beginSendHeaders( this, outBuf,
+                                         status, statusMessage,
+                                         numHeaders);
+    }        
+
+	public void sendHeader(String name, String value) throws IOException {
+		reqHandler.sendHeader(  outBuf, name, value );
+	}
+
+
+    public void endSendHeaders() throws IOException {
+        reqHandler.endSendHeaders(this, outBuf);
+    }
+
+    public void sendHeaders(int status, MimeHeaders headers)
+        throws IOException
+    {
+        reqHandler.sendHeaders(this, outBuf, status,
+                                   HttpMessages.getMessage(status),
+                                   headers);
+    }
+
+    public void sendHeaders(int status, String statusMessage,
+                            MimeHeaders headers)
+        throws IOException
+    {
+        reqHandler.sendHeaders( this, outBuf, status,
+                                    statusMessage, headers );
+    }
+
+    public void finish() throws IOException {
+        reqHandler.finish(this, outBuf );
+    }
+
+    public void doWrite(byte b[], int off, int len) throws IOException {
+        reqHandler.doWrite( this, outBuf, b, off, len );
+    }
+    
+
+    // ========= Internal Packet-Handling Methods =================
+
+    /**
+     * Read N bytes from the InputStream, and ensure we got them all
+     * Under heavy load we could experience many fragmented packets
+     * just read Unix Network Programming to recall that a call to
+     * read didn't ensure you got all the data you want
+     *
+     * from read() Linux manual
+     *
+     * On success, the number of bytes read is returned (zero indicates end of file),
+     * and the file position is advanced by this number.
+     * It is not an error if this number is smaller than the number of bytes requested;
+     * this may happen for example because fewer bytes
+     * are actually available right now (maybe because we were close to end-of-file,
+     * or because we are reading from a pipe, or  from  a
+     * terminal),  or  because  read()  was interrupted by a signal.
+     * On error, -1 is returned, and errno is set appropriately. In this
+     * case it is left unspecified whether the file position (if any) changes.
+     *
+     **/
+    private int readN(InputStream in, byte[] b, int offset, int len) throws IOException {
+        int pos = 0;
+        int got;
+
+        while(pos < len) {
+            got = in.read(b, pos + offset, len - pos);
+
+            if (debug > 10) {
+                logger.log("read got # " + got);
+            }
+
+            // connection just closed by remote. 
+            if (got <= 0) {
+                // This happens periodically, as apache restarts
+                // periodically.
+                // It should be more gracefull ! - another feature for Ajp14 
+                return JK_AJP13_COMM_BROKEN;
+            }
+
+            pos += got;
+        }
+        return pos;
+     }
+
+    /**
+     * Read in a packet from the web server and store it in the passed-in
+     * <CODE>Ajp13Packet</CODE> object.
+     *
+     * @param msg The object into which to store the incoming packet -- any
+     * current contents will be overwritten.
+     *
+     * @return The number of bytes read on a successful read or -1 if there 
+     * was an error.
+     **/
+    public int receive(Ajp13Packet msg) throws IOException {
+        if (debug > 0) {
+            logger.log("receive()");
+        }
+
+	// XXX If the length in the packet header doesn't agree with the
+	// actual number of bytes read, it should probably return an error
+	// value.  Also, callers of this method never use the length
+	// returned -- should probably return true/false instead.
+	byte b[] = msg.getBuff();
+	
+        int rd = readN(in, b, 0, H_SIZE );
+        
+        // XXX - connection closed (JK_AJP13_COMM_CLOSED)
+        //     - connection broken (JK_AJP13_COMM_BROKEN)
+        //
+        if(rd < 0) {
+            // Most likely normal apache restart.
+            return rd;
+        }
+        
+	int len = msg.checkIn();
+	if( debug > 5 )
+            logger.log( "Received " + rd + " " + len + " " + b[0] );
+        
+	// XXX check if enough space - it's assert()-ed !!!
+        
+ 	int total_read = 0;
+        
+        total_read = readN(in, b, H_SIZE, len);
+
+        // it's ok to have read 0 bytes when len=0 -- this means
+        // the end of the stream has been reached.
+        if (total_read < 0) {
+            logger.log("can't read body, waited #" + len);
+            return JK_AJP13_BAD_BODY;
+        }
+        
+        if (total_read != len) {
+            logger.log( "incomplete read, waited #" + len +
+                        " got only " + total_read);
+            return JK_AJP13_INCOMPLETE_BODY;
+        }
+        
+        if (debug > 0)
+            logger.log("receive:  total read = " + total_read);
+	return total_read;
+    }
+    
+    /**
+     * Send a packet to the web server.  Works for any type of message.
+     *
+     * @param msg A packet with accumulated data to send to the server --
+     * this method will write out the length in the header.  
+     */
+    public void send( Ajp13Packet msg ) throws IOException {
+        if (debug > 0) {
+            logger.log("send()");
+        }
+
+	msg.end(); // Write the packet header
+	byte b[] = msg.getBuff();
+	int len  = msg.getLen();
+
+        if (debug > 5 )
+            logger.log("send() " + len + " " + b[0] );
+
+	out.write( b, 0, len );
+    }
+	
+    /**
+     * Close the socket connection to the web server.  In general, sockets
+     * are maintained across many requests, so this will not be called
+     * after finish().  
+     */
+    public void close() throws IOException {
+        if (debug > 0) {
+            logger.log("close()");
+        }
+
+	if(null != out) {        
+	    out.close();
+	}
+	if(null !=in) {
+	    in.close();
+	}
+        setLogged( false );	// no more logged now 
+    }
+
+    // -------------------- Debug --------------------
+    protected int debug = 0;
+    
+    public void setDebug(int debug) {
+        this.debug = debug;
+        this.reqHandler.setDebug(debug);
+    }
+
+    public void setLogger(Logger l) {
+        this.logger = l;
+        this.reqHandler.setLogger(l);
+    }
+
+    /**
+     * XXX place holder...
+     */
+    Logger logger = new Logger();
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/ajp/Ajp13Packet.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/ajp/Ajp13Packet.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/ajp/Ajp13Packet.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,520 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.ajp;
+
+import java.io.UnsupportedEncodingException;
+
+import org.apache.tomcat.util.buf.MessageBytes;
+import org.apache.tomcat.util.http.MimeHeaders;
+
+
+/**
+ * A single packet for communication between the web server and the
+ * container.  Designed to be reused many times with no creation of
+ * garbage.  Understands the format of data types for these packets.
+ * Can be used (somewhat confusingly) for both incoming and outgoing
+ * packets.  
+ *
+ * See Ajp14/Ajp13Packet.
+ *
+ * @author Henri Gomez [hgomez at apache.org]
+ * @author Dan Milstein [danmil at shore.net]
+ * @author Keith Wannamaker [Keith at Wannamaker.org]
+ * @author Kevin Seguin
+ * @author Costin Manolache
+ */
+public class Ajp13Packet {
+    
+    private static org.apache.commons.logging.Log log=
+        org.apache.commons.logging.LogFactory.getLog( Ajp13Packet.class );
+    
+    public static final String DEFAULT_CHAR_ENCODING = "8859_1";
+    public static final int    AJP13_WS_HEADER       = 0x1234;
+    public static final int    AJP13_SW_HEADER       = 0x4142;  // 'AB'
+
+    /**
+     * encoding to use when converting byte[] <-> string
+     */
+    String encoding = DEFAULT_CHAR_ENCODING;
+
+    /**
+     * Holds the bytes of the packet
+     */
+    byte buff[];
+
+    /**
+     * The current read or write position in the buffer
+     */
+    int pos;    
+
+    /**
+     * This actually means different things depending on whether the
+     * packet is read or write.  For read, it's the length of the
+     * payload (excluding the header).  For write, it's the length of
+     * the packet as a whole (counting the header).  Oh, well.
+     */
+    int len; 
+
+    /**
+     * Create a new packet with an internal buffer of given size.
+     * @param size packet size
+     */
+    public Ajp13Packet( int size ) {
+        buff = new byte[size];
+    }
+
+    /**
+     * Create a new packet with given bytes
+     * @param b this packet's bytes.
+     */
+    public Ajp13Packet( byte b[] ) {
+        buff = b;
+    }
+
+    /**
+     * Set the encoding to use for byte[] <-> string
+     * conversions.
+     * @param encoding the encoding to use.
+     */
+    public void setEncoding(String encoding) {
+        this.encoding = encoding;
+    }
+
+    /**
+     * Get the encoding used for byte[] <-> string
+     * conversions.
+     * @return the encoding used.
+     */
+    public String getEncoding() {
+        return encoding;
+    }
+
+    /**
+     * Get the internal buffer
+     * @return internal buffer
+     */
+    public byte[] getBuff() {
+        return buff;
+    }
+
+    /**
+     * Get length.
+     * @return length -- This actually means different things depending on whether the
+     *                   packet is read or write.  For read, it's the length of the
+     *                   payload (excluding the header).  For write, it's the length of
+     *                   the packet as a whole (counting the header).  Oh, well.
+     */
+    public int getLen() {
+        return len;
+    }
+
+    /**
+     * Get offset into internal buffer.
+     * @return offset
+     */
+    public int getByteOff() {
+        return pos;
+    }
+
+    /**
+     * Set offset into internal buffer.
+     * @param c new offset
+     */
+    public void setByteOff(int c) {
+        pos=c;
+    }
+
+    /** 
+     * Parse the packet header for a packet sent from the web server to
+     * the container.  Set the read position to immediately after
+     * the header.
+     *
+     * @return The length of the packet payload, as encoded in the
+     * header, or -1 if the packet doesn't have a valid header.  
+     */
+    public int checkIn() {
+        pos = 0;
+        int mark = getInt();
+        len      = getInt();
+	    
+        if( mark != AJP13_WS_HEADER ) {
+            if (log.isDebugEnabled())
+                log.debug("BAD packet " + mark);
+            dump( "In: " );
+            return -1;
+        }
+        return len;
+    }
+    
+    /**
+     * Prepare this packet for accumulating a message from the container to
+     * the web server.  Set the write position to just after the header
+     * (but leave the length unwritten, because it is as yet unknown).
+     */
+    public void reset() {
+        len = 4;
+        pos = 4;
+        buff[0] = (byte)(AJP13_SW_HEADER >> 8);
+        buff[1] = (byte)(AJP13_SW_HEADER & 0xFF);
+    }
+	
+    /**
+     * For a packet to be sent to the web server, finish the process of
+     * accumulating data and write the length of the data payload into
+     * the header.  
+     */
+    public void end() {
+        len = pos;
+        setInt( 2, len-4 );
+    }
+	
+    // ============ Data Writing Methods ===================
+
+    /**
+     * Write an 32 bit integer at an arbitrary position in the packet,but don't
+     * change the write position.
+     *
+     * @param bpos The 0-indexed position within the buffer at which to
+     * write the integer (where 0 is the beginning of the header).
+     * @param val The integer to write.
+     */
+    private void setInt( int bPos, int val ) {
+        buff[bPos]   = (byte) ((val >>>  8) & 0xFF);
+        buff[bPos+1] = (byte) (val & 0xFF);
+    }
+
+    public void appendInt( int val ) {
+        setInt( pos, val );
+        pos += 2;
+    }
+	
+    public void appendByte( byte val ) {
+        buff[pos++] = val;
+    }
+	
+    public void appendBool( boolean val) {
+        buff[pos++] = (byte) (val ? 1 : 0);
+    }
+
+    /**
+     * Write a String out at the current write position.  Strings are
+     * encoded with the length in two bytes first, then the string, and
+     * then a terminating \0 (which is <B>not</B> included in the
+     * encoded length).  The terminator is for the convenience of the C
+     * code, where it saves a round of copying.  A null string is
+     * encoded as a string with length 0.  
+     */
+    public void appendString(String str) throws UnsupportedEncodingException {
+        // Dual use of the buffer - as Ajp13Packet and as OutputBuffer
+        // The idea is simple - fewer buffers, smaller footprint and less
+        // memcpy. The code is a bit tricky, but only local to this
+        // function.
+        if(str == null) {
+            setInt( pos, 0);
+            buff[pos + 2] = 0;
+            pos += 3;
+            return;
+        }
+
+        //
+        // XXX i don't have OutputBuffer in tc4... ks.
+        // fix this later...
+        //
+        byte[] bytes = str.getBytes(encoding);
+        appendBytes(bytes, 0, bytes.length);
+        
+        /* XXX XXX XXX XXX Try to add it back.
+        int strStart=pos;
+
+        // This replaces the old ( buggy and slow ) str.length()
+        // and str.getBytes(). str.length() is chars, may be != bytes
+        // and getBytes is _very_ slow.
+        // XXX setEncoding !!!
+
+        ob.setByteOff( pos+2 ); 
+        try {
+            ob.write( str );
+            ob.flushChars();
+        } catch( IOException ex ) {
+            ex.printStackTrace();
+        }
+        int strEnd=ob.getByteOff();
+        
+        buff[strEnd]=0; // The \0 terminator
+        int strLen=strEnd-strStart;
+        setInt( pos, strEnd - strStart );
+        pos += strLen + 3; 
+        */
+    }
+
+    /** 
+     * Copy a chunk of bytes into the packet, starting at the current
+     * write position.  The chunk of bytes is encoded with the length
+     * in two bytes first, then the data itself, and finally a
+     * terminating \0 (which is <B>not</B> included in the encoded
+     * length).
+     *
+     * @param b The array from which to copy bytes.
+     * @param off The offset into the array at which to start copying
+     * @param numBytes The number of bytes to copy.  
+     */
+    public void appendBytes( byte b[], int off, int numBytes ) {
+        appendInt( numBytes );
+        if( pos + numBytes >= buff.length ) {
+            if (log.isDebugEnabled())
+                log.debug("Buffer overflow " + buff.length + " " + pos + " " + numBytes );
+        }
+        System.arraycopy( b, off, buff, pos, numBytes);
+        buff[pos + numBytes] = 0; // Terminating \0
+        pos += numBytes + 1;
+    }
+
+        /**
+     * Write a 32 bits integer at an arbitrary position in the packet, but don't
+     * change the write position.
+     *
+     * @param bpos The 0-indexed position within the buffer at which to
+     * write the integer (where 0 is the beginning of the header).
+     * @param val The integer to write.
+     */
+    private void setLongInt( int bPos, int val ) {
+        buff[bPos]   = (byte) ((val >>>  24) & 0xFF);
+        buff[bPos+1] = (byte) ((val >>>  16) & 0xFF);
+        buff[bPos+2] = (byte) ((val >>>   8) & 0xFF);
+        buff[bPos+3] = (byte) (val & 0xFF);
+    }
+
+    public void appendLongInt( int val ) {
+        setLongInt( pos, val );
+        pos += 4;
+    }
+
+    /**
+     * Copy a chunk of bytes into the packet, starting at the current
+     * write position.  The chunk of bytes IS NOT ENCODED with ANY length
+     * header.
+     *
+     * @param b The array from which to copy bytes.
+     * @param off The offset into the array at which to start copying
+     * @param numBytes The number of bytes to copy.
+     */
+    public void appendXBytes(byte[] b, int off, int numBytes) {
+        if( pos + numBytes > buff.length ) {
+            if (log.isDebugEnabled())
+                log.debug("appendXBytes - Buffer overflow " + buff.length + " " + pos + " " + numBytes );
+        }
+        System.arraycopy( b, off, buff, pos, numBytes);
+        pos += numBytes;
+    }
+	
+    
+    // ============ Data Reading Methods ===================
+
+    /**
+     * Read an integer from packet, and advance the read position past
+     * it.  Integers are encoded as two unsigned bytes with the
+     * high-order byte first, and, as far as I can tell, in
+     * little-endian order within each byte.  
+     */
+    public int getInt() {
+        int result = peekInt();
+        pos += 2;
+        return result;
+    }
+
+    /**
+     * Read an integer from the packet, but don't advance the read
+     * position past it.  
+     */
+    public int peekInt() {
+        int b1 = buff[pos] & 0xFF;  // No swap, Java order
+        int b2 = buff[pos + 1] & 0xFF;
+
+        return  (b1<<8) + b2;
+    }
+
+    public byte getByte() {
+        byte res = buff[pos];
+        pos++;
+        return res;
+    }
+
+    public byte peekByte() {
+        return buff[pos];
+    }
+
+    public boolean getBool() {
+        return (getByte() == (byte) 1);
+    }
+
+    public void getMessageBytes(MessageBytes mb) {
+        int length = getInt();
+        if( (length == 0xFFFF) || (length == -1) ) {
+            mb.setString( null );
+            return;
+        }
+        mb.setBytes( buff, pos, length );
+        pos += length;
+        pos++; // Skip the terminating \0
+    }
+    
+    public MessageBytes addHeader(MimeHeaders headers) {
+        int length = getInt();
+        if( (length == 0xFFFF) || (length == -1) ) {
+            return null;
+        }
+        MessageBytes vMB=headers.addValue( buff, pos, length );
+        pos += length;
+        pos++; // Skip the terminating \0
+	    
+        return vMB;
+    }
+	
+    /**
+     * Read a String from the packet, and advance the read position
+     * past it.  See appendString for details on string encoding.
+     **/
+    public String getString() throws java.io.UnsupportedEncodingException {
+        int length = getInt();
+        if( (length == 0xFFFF) || (length == -1) ) {
+            if (log.isDebugEnabled())
+                log.debug("null string " + length);
+            return null;
+        }
+        String s = new String(buff, pos, length, encoding);
+
+        pos += length;
+        pos++; // Skip the terminating \0
+        return s;
+    }
+
+    /**
+     * Copy a chunk of bytes from the packet into an array and advance
+     * the read position past the chunk.  See appendBytes() for details
+     * on the encoding.
+     *
+     * @return The number of bytes copied.
+     */
+    public int getBytes(byte dest[]) {
+        int length = getInt();
+        if( length > buff.length ) {
+            // XXX Should be if(pos + length > buff.legth)?
+            if (log.isDebugEnabled())
+                log.debug("XXX Assert failed, buff too small ");
+        }
+	
+        if( (length == 0xFFFF) || (length == -1) ) {
+            if (log.isDebugEnabled())
+                log.debug("null string " + length);
+            return 0;
+        }
+
+        System.arraycopy( buff, pos,  dest, 0, length );
+        pos += length;
+        pos++; // Skip terminating \0  XXX I believe this is wrong but harmless
+        return length;
+    }
+
+        /**
+     * Read a 32 bits integer from packet, and advance the read position past
+     * it.  Integers are encoded as four unsigned bytes with the
+     * high-order byte first, and, as far as I can tell, in
+     * little-endian order within each byte.
+     */
+    public int getLongInt() {
+        int result = peekLongInt();
+        pos += 4;
+        return result;
+    }
+
+    /**
+     * Copy a chunk of bytes from the packet into an array and advance
+     * the read position past the chunk.  See appendXBytes() for details
+     * on the encoding.
+     *
+     * @return The number of bytes copied.
+     */
+    public int getXBytes(byte[] dest, int length) {
+        if( length > buff.length ) {
+        // XXX Should be if(pos + length > buff.legth)?
+            if (log.isDebugEnabled())
+                log.debug("XXX Assert failed, buff too small ");
+        }
+
+        System.arraycopy( buff, pos,  dest, 0, length );
+        pos += length;
+        return length;
+    }
+
+    /**
+     * Read a 32 bits integer from the packet, but don't advance the read
+     * position past it.
+     */
+    public int peekLongInt() {
+        int b1 = buff[pos] & 0xFF;  // No swap, Java order
+        b1 <<= 8;
+        b1 |= (buff[pos + 1] & 0xFF);
+        b1 <<= 8;
+        b1 |= (buff[pos + 2] & 0xFF);
+        b1 <<=8;
+        b1 |= (buff[pos + 3] & 0xFF);
+        return  b1;
+    }
+
+    // ============== Debugging code =========================
+    private String hex( int x ) {
+        //	    if( x < 0) x=256 + x;
+        String h=Integer.toHexString( x );
+        if( h.length() == 1 ) h = "0" + h;
+        return h.substring( h.length() - 2 );
+    }
+
+    private void hexLine( int start ) {
+	int pkgEnd = len + 4;
+	if( pkgEnd > buff.length )
+	    pkgEnd = buff.length;
+        for( int i=start; i< start+16 ; i++ ) {
+            if( i < pkgEnd) {
+                if (log.isDebugEnabled())
+                    log.debug( hex( buff[i] ) + " ");
+            } else {
+                if (log.isDebugEnabled()) 
+                    log.debug( "   " );
+            }
+        }
+        if (log.isDebugEnabled()) 
+            log.debug(" | ");
+        for( int i=start; i < start+16 && i < pkgEnd; i++ ) {
+            if( Character.isLetterOrDigit( (char)buff[i] )) {
+                if (log.isDebugEnabled()) 
+                    log.debug( new Character((char)buff[i]) );
+            } else {
+                if (log.isDebugEnabled()) 
+                    log.debug( "." );
+            }
+        }
+    }
+    
+    public void dump(String msg) {
+        if (log.isDebugEnabled())
+            log.debug( msg + ": " + buff + " " + pos +"/" + (len + 4));
+
+        for( int j=0; j < len + 4; j+=16 )
+            hexLine( j );
+
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/ajp/AjpHandler.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/ajp/AjpHandler.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/ajp/AjpHandler.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,53 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.ajp;
+
+import java.io.IOException;
+
+import org.apache.tomcat.util.http.BaseRequest;
+
+/**
+ * Base class for handlers of Ajp messages. Jk provide a simple bidirectional 
+ * communication mechanism between the web server and a servlet container. It is
+ * based on messages that are passed between the 2 server, using a single
+ * thread on each side.
+ *
+ * The container side must be able to deal with at least the "REQUEST FORWARD",
+ * the server side must be able to deal with at least "HEADERS", "BODY",
+ * "END" messages.
+ *
+ * @author Henri Gomez
+ * @author Costin Manolache
+ */
+public class AjpHandler
+{
+    public static final int UNKNOWN=-1;
+    Ajp13 channel;
+    
+    public void init( Ajp13 channel ) {
+        this.channel=channel;
+    }
+    
+    /** Execute the callback 
+     */
+    public int handleAjpMessage( int type, Ajp13 channel,
+				 Ajp13Packet ajp, BaseRequest req )
+	throws IOException
+    {
+	return UNKNOWN;
+    }
+}    

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/ajp/Logger.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/ajp/Logger.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/ajp/Logger.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,51 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.ajp;
+
+/**
+ * A simple logger class used by classes in this package.
+ * The intention is for this class to be overridden so that
+ * log messages from classes in this package can be adapted
+ * to loggers used by the connector implementations for various
+ * servlet containers.
+ *
+ * @author Kevin Seguin [seguin at apache.org]
+ */
+public class Logger {
+    
+    private static org.apache.commons.logging.Log log=
+        org.apache.commons.logging.LogFactory.getLog(Logger.class );
+    
+    /**
+     * Log the given message.
+     * @param msg The message to log.
+     */
+    public void log(String msg) {
+        if (log.isDebugEnabled())
+            log.debug("[Ajp13] " + msg);
+    }
+    
+    /**
+     * Log the given message and error.
+     * @param msg The message to log.
+     * @param t The error to log.
+     */
+    public void log(String msg, Throwable t) {
+        if (log.isDebugEnabled())
+            log.debug("[Ajp13] " + msg, t);
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/ajp/NegociationHandler.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/ajp/NegociationHandler.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/ajp/NegociationHandler.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,533 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.ajp;
+
+import java.io.IOException;
+import java.security.MessageDigest;
+
+import org.apache.tomcat.util.buf.HexUtils;
+import org.apache.tomcat.util.http.BaseRequest;
+
+
+/**
+ * Handler for the protocol negotiation. It will authenticate and 
+ * exchange information about supported messages on each end.
+ * 
+ * 
+ * @author Henri Gomez [hgomez at apache.org]
+ * @author Dan Milstein [danmil at shore.net]
+ * @author Keith Wannamaker [Keith at Wannamaker.org]
+ * @author Costin Manolache
+ */
+public class NegociationHandler extends AjpHandler
+{
+    
+    private static org.apache.commons.logging.Log log=
+        org.apache.commons.logging.LogFactory.getLog(NegociationHandler.class );
+    
+    // Initial Login Phase (web server -> servlet engine)
+    public static final byte JK_AJP14_LOGINIT_CMD=0x10;
+    
+    // Second Login Phase (servlet engine -> web server), md5 seed is received
+    public static final byte JK_AJP14_LOGSEED_CMD=0x11;
+    
+    // Third Login Phase (web server -> servlet engine),
+    // md5 of seed + secret is sent
+    public static final byte JK_AJP14_LOGCOMP_CMD=0x12;
+    
+    // Login Accepted (servlet engine -> web server)
+    public static final byte JK_AJP14_LOGOK_CMD=0x13;
+
+    // Login Rejected (servlet engine -> web server), will be logged
+    public static final byte JK_AJP14_LOGNOK_CMD=0x14;
+    
+    // Context Query (web server -> servlet engine),
+    // which URI are handled by servlet engine ?
+    public static final byte JK_AJP14_CONTEXT_QRY_CMD=0x15;
+    
+    // Context Info (servlet engine -> web server), URI handled response
+    public static final byte JK_AJP14_CONTEXT_INFO_CMD= 0x16;
+    
+    // Context Update (servlet engine -> web server), status of context changed
+    public static final byte JK_AJP14_CONTEXT_UPDATE_CMD= 0x17;
+    
+    // Servlet Engine Status (web server -> servlet engine),
+    // what's the status of the servlet engine ?
+    public static final byte JK_AJP14_STATUS_CMD= 0x18;
+    
+    // Secure Shutdown command (web server -> servlet engine),
+    //please servlet stop yourself.
+    public static final byte JK_AJP14_SHUTDOWN_CMD= 0x19;
+    
+    // Secure Shutdown command Accepted (servlet engine -> web server)
+    public static final byte JK_AJP14_SHUTOK_CMD= 0x1A;
+    
+    // Secure Shutdown Rejected (servlet engine -> web server)
+    public static final byte JK_AJP14_SHUTNOK_CMD= 0x1B;
+    
+    // Context Status (web server -> servlet engine),
+    //what's the status of the context ?
+    public static final byte JK_AJP14_CONTEXT_STATE_CMD= 0x1C;
+    
+    // Context Status Reply (servlet engine -> web server), status of context
+    public static final byte JK_AJP14_CONTEXT_STATE_REP_CMD = 0x1D;
+    
+    // Unknown Packet Reply (web server <-> servlet engine),
+    //when a packet couldn't be decoded
+    public static final byte JK_AJP14_UNKNOW_PACKET_CMD = 0x1E;
+
+
+    // -------------------- Other constants -------------------- 
+
+    // Entropy Packet Size
+    public static final int AJP14_ENTROPY_SEED_LEN= 32;
+    public static final int AJP14_COMPUTED_KEY_LEN= 32;
+    
+    // web-server want context info after login
+    public static final int AJP14_CONTEXT_INFO_NEG= 0x80000000;
+    
+    // web-server want context updates
+    public static final int AJP14_CONTEXT_UPDATE_NEG= 0x40000000;
+    
+    // web-server want compressed stream
+    public static final int AJP14_GZIP_STREAM_NEG= 0x20000000;
+    
+    // web-server want crypted DES56 stream with secret key
+    public static final int AJP14_DES56_STREAM_NEG= 0x10000000;
+    
+    // Extended info on server SSL vars
+    public static final int AJP14_SSL_VSERVER_NEG= 0x08000000;
+    
+    // Extended info on client SSL vars
+    public static final int AJP14_SSL_VCLIENT_NEG= 0x04000000;
+    
+    // Extended info on crypto SSL vars
+    public static final int AJP14_SSL_VCRYPTO_NEG= 0x02000000;
+    
+    // Extended info on misc SSL vars
+    public static final int  AJP14_SSL_VMISC_NEG= 0x01000000;
+    
+    // mask of protocol supported
+    public static final int  AJP14_PROTO_SUPPORT_AJPXX_NEG=0x00FF0000;
+    
+    // communication could use AJP14
+    public static final int  AJP14_PROTO_SUPPORT_AJP14_NEG=0x00010000;
+    
+    // communication could use AJP15
+    public static final int  AJP14_PROTO_SUPPORT_AJP15_NEG=0x00020000;
+    
+    // communication could use AJP16
+    public static final int  AJP14_PROTO_SUPPORT_AJP16_NEG=0x00040000;
+    
+    // Some failure codes
+    public static final int AJP14_BAD_KEY_ERR= 0xFFFFFFFF;
+    public static final int AJP14_ENGINE_DOWN_ERR = 0xFFFFFFFE;
+    public static final int AJP14_RETRY_LATER_ERR = 0xFFFFFFFD;
+    public static final int AJP14_SHUT_AUTHOR_FAILED_ERR = 0xFFFFFFFC;
+    
+    // Some status codes
+    public static final byte AJP14_CONTEXT_DOWN= 0x01;
+    public static final byte AJP14_CONTEXT_UP= 0x02;
+    public static final byte AJP14_CONTEXT_OK= 0x03;
+
+
+    // -------------------- Parameters --------------------
+    String  containerSignature="Ajp14-based container";
+    String  seed="seed";// will use random
+    String  password;
+
+    int	webserverNegociation=0;
+    //    String  webserverName;
+    
+    public NegociationHandler() {
+        setSeed("myveryrandomentropy");
+	setPassword("myverysecretkey");
+    }
+
+    public void setContainerSignature( String s ) {
+	containerSignature=s;
+    }
+
+    // -------------------- State --------------------
+
+    //     public String getWebserverName() {
+    // 	return webserverName;
+    //     }
+    
+    // -------------------- Parameters --------------------
+    
+    /**
+     * Set the original entropy seed
+     */
+    public void setSeed(String pseed) 
+    {
+	String[] credentials = new String[1];
+	credentials[0] = pseed;
+	seed = digest(credentials, "md5");
+    }
+
+    /**
+     * Get the original entropy seed
+     */
+    public String getSeed()
+    {
+	return seed;
+    }
+
+    /**
+     * Set the secret password
+     */
+    public void setPassword(String ppwd) 
+    {
+	password = ppwd;
+    }
+    
+    /**
+     * Get the secret password
+     */
+    public String getPassword()
+    {
+	return password;
+    }
+
+    // -------------------- Initialization --------------------
+
+    public void init( Ajp13 ajp14 ) {
+        super.init(ajp14);
+	// register incoming message handlers
+	ajp14.registerMessageType( JK_AJP14_LOGINIT_CMD,"JK_AJP14_LOGINIT_CMD",
+				   this, null); //
+	ajp14.registerMessageType( JK_AJP14_LOGCOMP_CMD,"JK_AJP14_LOGCOMP_CMD",
+				   this, null); //
+	ajp14.registerMessageType( RequestHandler.JK_AJP13_SHUTDOWN,"JK_AJP13_SHUTDOWN",
+				   this, null); //
+	ajp14.registerMessageType( JK_AJP14_CONTEXT_QRY_CMD,
+				   "JK_AJP14_CONTEXT_QRY_CMD",
+				   this, null); //
+	ajp14.registerMessageType( JK_AJP14_STATUS_CMD,"JK_AJP14_STATUS_CMD",
+				   this, null); //
+	ajp14.registerMessageType( JK_AJP14_SHUTDOWN_CMD,
+                                   "JK_AJP14_SHUTDOWN_CMD",
+				   this, null); //
+	ajp14.registerMessageType( JK_AJP14_CONTEXT_STATE_CMD,
+				   "JK_AJP14_CONTEXT_STATE_CMD",
+				   this, null); //
+	ajp14.registerMessageType( JK_AJP14_UNKNOW_PACKET_CMD,
+				   "JK_AJP14_UNKNOW_PACKET_CMD",
+				   this, null); //
+	
+	// register outgoing messages handler
+	ajp14.registerMessageType( JK_AJP14_LOGNOK_CMD,"JK_AJP14_LOGNOK_CMD",
+				   this,null );
+	
+    }
+    
+
+    
+    // -------------------- Dispatch --------------------
+
+    public int handleAjpMessage( int type, Ajp13 ch, Ajp13Packet hBuf,
+				 BaseRequest req )
+	throws IOException
+    {
+        if (log.isDebugEnabled())
+            log.debug("handleAjpMessage: " + type );
+	Ajp13Packet outBuf=ch.outBuf;
+	// Valid requests when not logged:
+	switch( type ) {
+	case JK_AJP14_LOGINIT_CMD :
+	    return handleLogInit(ch, hBuf, outBuf);
+	case JK_AJP14_LOGCOMP_CMD :
+	    return handleLogComp(ch, hBuf, outBuf);
+	case RequestHandler.JK_AJP13_SHUTDOWN:
+	    return -2;
+	case JK_AJP14_CONTEXT_QRY_CMD :
+	    return handleContextQuery(ch, hBuf, outBuf);
+	case JK_AJP14_STATUS_CMD :
+	    return handleStatus(hBuf, outBuf);
+	case JK_AJP14_SHUTDOWN_CMD :
+	    return handleShutdown(hBuf, outBuf);
+	case JK_AJP14_CONTEXT_STATE_CMD :
+	    return handleContextState(hBuf, outBuf);
+	case JK_AJP14_UNKNOW_PACKET_CMD :
+	    return handleUnknowPacket(hBuf, outBuf);
+	default:
+	    log("unknown command " + type + " received");
+	    return 200; // XXX This is actually an error condition
+	}
+	//return UNKNOWN;
+    }
+    
+    //----------- Implementation for various protocol commands -----------
+
+    /**
+     * Handle the Initial Login Message from Web-Server
+     *
+     * Get the requested Negociation Flags
+     * Get also the Web-Server Name
+     * 
+     * Send Login Seed (MD5 of seed)
+     */
+    private int handleLogInit( Ajp13 ch, Ajp13Packet msg,
+			       Ajp13Packet outBuf )
+	throws IOException
+    {
+	webserverNegociation = msg.getLongInt();
+	String webserverName  = msg.getString();
+	log("in handleLogInit with nego " +
+	    decodeNegociation(webserverNegociation) +
+            " from webserver " + webserverName);
+	
+	outBuf.reset();
+        outBuf.appendByte(JK_AJP14_LOGSEED_CMD);
+	String[] credentials = new String[1];
+	credentials[0] = getSeed();
+        outBuf.appendXBytes(getSeed().getBytes(), 0, AJP14_ENTROPY_SEED_LEN);
+	log("in handleLogInit: sent entropy " + getSeed());
+        outBuf.end();
+        ch.send(outBuf);
+	return 304;
+    }
+    
+    /**
+     * Handle the Second Phase of Login (accreditation)
+     * 
+     * Get the MD5 digest of entropy + secret password
+     * If the authentification is valid send back LogOk
+     * If the authentification failed send back LogNok
+     */
+    private int handleLogComp( Ajp13 ch, Ajp13Packet msg,
+			       Ajp13Packet outBuf )
+	throws IOException
+    {
+	// log("in handleLogComp :");
+	
+	byte [] rdigest = new byte[AJP14_ENTROPY_SEED_LEN];
+	
+	if (msg.getXBytes(rdigest, AJP14_ENTROPY_SEED_LEN) < 0)
+	    return 200;
+	
+	String[] credentials = new String[2];
+	credentials[0] = getSeed();
+	credentials[1] = getPassword();
+	String computed = digest(credentials, "md5");
+	String received = new String(rdigest);
+	
+	// XXX temp workaround, to test the rest of the connector.
+	
+	if ( ! computed.equalsIgnoreCase(received)) {
+	    log("in handleLogComp : authentification failure received=" +
+		received + " awaited=" + computed);
+	}
+	
+	if (false ) { // ! computed.equalsIgnoreCase(received)) {
+	    log("in handleLogComp : authentification failure received=" +
+		received + " awaited=" + computed);
+	    
+	    // we should have here a security mecanism which could maintain
+	    // a list of remote IP which failed too many times
+	    // so we could reject them quickly at next connect
+	    outBuf.reset();
+	    outBuf.appendByte(JK_AJP14_LOGNOK_CMD);
+	    outBuf.appendLongInt(AJP14_BAD_KEY_ERR);
+	    outBuf.end();
+	    ch.send(outBuf);
+	    return 200;
+	} else {
+            // logged we can go process requests
+	    channel.setLogged(true);
+	    outBuf.reset();
+	    outBuf.appendByte(JK_AJP14_LOGOK_CMD);
+	    outBuf.appendLongInt(getProtocolFlags(webserverNegociation));
+	    outBuf.appendString( containerSignature );
+	    outBuf.end(); 
+	    ch.send(outBuf);
+	}
+	
+	return (304);
+    }
+
+    private int handleContextQuery( Ajp13 ch, Ajp13Packet msg,
+				    Ajp13Packet outBuf )
+	throws IOException
+    {
+	log("in handleContextQuery :");
+    String virtualHost = msg.getString();
+    log("in handleContextQuery for virtual" + virtualHost); 
+
+    outBuf.reset();
+    outBuf.appendByte(JK_AJP14_CONTEXT_INFO_CMD);
+    outBuf.appendString( virtualHost );
+
+    log("in handleContextQuery for virtual " + virtualHost +
+        "examples URI/MIMES");
+    outBuf.appendString("examples");    // first context - examples
+    outBuf.appendString("servlet/*");   // examples/servlet/*
+    outBuf.appendString("*.jsp");       // examples/*.jsp
+    outBuf.appendString("");            // no more URI/MIMES
+
+    log("in handleContextQuery for virtual " + virtualHost +
+        "send admin URI/MIMES"); 
+    outBuf.appendString("admin");       // second context - admin
+    outBuf.appendString("servlet/*");   // /admin//servlet/*
+    outBuf.appendString("*.jsp");       // /admin/*.jsp
+    outBuf.appendString("");            // no more URI/MIMES
+
+    outBuf.appendString("");            // no more contexts
+    outBuf.end();
+    ch.send(outBuf);
+    
+	return (304);
+    }
+    
+    private int handleStatus( Ajp13Packet msg, Ajp13Packet outBuf )
+        throws IOException
+    {
+	log("in handleStatus :");
+	return (304);
+    }
+
+    private int handleShutdown( Ajp13Packet msg, Ajp13Packet outBuf )
+        throws IOException
+    {
+	log("in handleShutdown :");
+	return (304);
+    }
+    
+    private int handleContextState( Ajp13Packet msg , Ajp13Packet outBuf)
+        throws IOException
+    {
+	log("in handleContextState :");
+	return (304);
+    }
+    
+    private int handleUnknowPacket( Ajp13Packet msg, Ajp13Packet outBuf )
+        throws IOException
+    {
+	log("in handleUnknowPacket :");
+	return (304);
+    }
+
+    // -------------------- Utils --------------------
+
+    /**
+     * Compute the Protocol Negociation Flags
+     * 
+     * Depending the protocol fatures implemented on servet-engine,
+     * we'll drop requested features which could be asked by web-server
+     *
+     * Hopefully this functions could be overrided by decendants
+     */
+    private int getProtocolFlags(int wanted)
+    {
+                    // no real-time context update
+	wanted &= ~(AJP14_CONTEXT_UPDATE_NEG |
+                    // no gzip compression yet
+		    AJP14_GZIP_STREAM_NEG    | 
+                     // no DES56 cyphering yet
+		    AJP14_DES56_STREAM_NEG   |
+                    // no Extended info on server SSL vars yet
+		    AJP14_SSL_VSERVER_NEG    |
+                    // no Extended info on client SSL vars yet
+		    AJP14_SSL_VCLIENT_NEG    |
+                    // no Extended info on crypto SSL vars yet
+		    AJP14_SSL_VCRYPTO_NEG    |
+                    // no Extended info on misc SSL vars yet
+		    AJP14_SSL_VMISC_NEG	     |
+                    // Reset AJP protocol mask
+		    AJP14_PROTO_SUPPORT_AJPXX_NEG);
+        
+	// Only strict AJP14 supported
+	return (wanted | AJP14_PROTO_SUPPORT_AJP14_NEG);	
+    }
+
+    /**
+     * Compute a digest (MD5 in AJP14) for an array of String
+     */
+    public final String digest(String[] credentials, String algorithm) {
+        try {
+            // Obtain a new message digest with MD5 encryption
+            MessageDigest md =
+                (MessageDigest)MessageDigest.getInstance(algorithm).clone();
+            // encode the credentials items
+	    for (int i = 0; i < credentials.length; i++) {
+		if( debug > 0 )
+                    log("Credentials : " + i + " " + credentials[i]);
+		if( credentials[i] != null  )
+		    md.update(credentials[i].getBytes());
+	    }
+            // obtain the byte array from the digest
+            byte[] dig = md.digest();
+	    return HexUtils.convert(dig);
+        } catch (Exception ex) {
+            ex.printStackTrace();
+            return null;
+        }
+    }
+
+    // -------------------- Debugging --------------------
+    // Very usefull for develoment
+
+    /**
+     * Display Negociation field in human form 
+     */
+    private String decodeNegociation(int nego)
+    {
+	StringBuffer buf = new StringBuffer(128);
+	
+	if ((nego & AJP14_CONTEXT_INFO_NEG) != 0) 
+	    buf.append(" CONTEXT-INFO");
+	
+	if ((nego & AJP14_CONTEXT_UPDATE_NEG) != 0)
+	    buf.append(" CONTEXT-UPDATE");
+	
+	if ((nego & AJP14_GZIP_STREAM_NEG) != 0)
+	    buf.append(" GZIP-STREAM");
+	
+	if ((nego & AJP14_DES56_STREAM_NEG) != 0)
+	    buf.append(" DES56-STREAM");
+	
+	if ((nego & AJP14_SSL_VSERVER_NEG) != 0)
+	    buf.append(" SSL-VSERVER");
+	
+	if ((nego & AJP14_SSL_VCLIENT_NEG) != 0)
+	    buf.append(" SSL-VCLIENT");
+	
+	if ((nego & AJP14_SSL_VCRYPTO_NEG) != 0)
+	    buf.append(" SSL-VCRYPTO");
+	
+	if ((nego & AJP14_SSL_VMISC_NEG) != 0)
+	    buf.append(" SSL-VMISC");
+	
+	if ((nego & AJP14_PROTO_SUPPORT_AJP14_NEG) != 0)
+	    buf.append(" AJP14");
+	
+	if ((nego & AJP14_PROTO_SUPPORT_AJP15_NEG) != 0)
+	    buf.append(" AJP15");
+	
+	if ((nego & AJP14_PROTO_SUPPORT_AJP16_NEG) != 0)
+	    buf.append(" AJP16");
+	
+	return (buf.toString());
+    }
+    
+    private static int debug=10;
+    void log(String s) {
+        if (log.isDebugEnabled())
+	    log.debug("Ajp14Negotiation: " + s );
+    }
+ }

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/ajp/RequestHandler.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/ajp/RequestHandler.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/ajp/RequestHandler.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,806 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.ajp;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+
+import org.apache.tomcat.util.buf.ByteChunk;
+import org.apache.tomcat.util.buf.MessageBytes;
+import org.apache.tomcat.util.http.BaseRequest;
+import org.apache.tomcat.util.http.HttpMessages;
+import org.apache.tomcat.util.http.MimeHeaders;
+
+
+/**
+ * Handle messages related with basic request information.
+ *
+ * This object can handle the following incoming messages:
+ * - "FORWARD_REQUEST" input message ( sent when a request is passed from the web server )
+ * - "PING REQUEST" input message (sent by the web server to determine if tomcat is not frozen,
+ *                                 a PONG REPLY will be sent back)
+ * - "RECEIVE_BODY_CHUNK" input ( sent by container to pass more body, in response to GET_BODY_CHUNK )
+ *
+ * It can handle the following outgoing messages:
+ * - SEND_HEADERS. Pass the status code and headers.
+ * - SEND_BODY_CHUNK. Send a chunk of body
+ * - GET_BODY_CHUNK. Request a chunk of body data
+ * - END_RESPONSE. Notify the end of a request processing.
+ *
+ * @author Henri Gomez [hgomez at apache.org]
+ * @author Dan Milstein [danmil at shore.net]
+ * @author Keith Wannamaker [Keith at Wannamaker.org]
+ * @author Costin Manolache
+ */
+public class RequestHandler extends AjpHandler
+{
+    // XXX Will move to a registry system.
+    
+    // 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_CPING_REQUEST     = 10;    
+
+    // Prefix codes for message types from container to server
+    public static final byte JK_AJP13_SEND_BODY_CHUNK   = 3;
+    public static final byte JK_AJP13_SEND_HEADERS      = 4;
+    public static final byte JK_AJP13_END_RESPONSE      = 5;
+	public static final byte JK_AJP13_GET_BODY_CHUNK    = 6;
+	public static final byte JK_AJP13_CPONG_REPLY       = 9;
+	
+    // Integer codes for common response header strings
+    public static final int SC_RESP_CONTENT_TYPE        = 0xA001;
+    public static final int SC_RESP_CONTENT_LANGUAGE    = 0xA002;
+    public static final int SC_RESP_CONTENT_LENGTH      = 0xA003;
+    public static final int SC_RESP_DATE                = 0xA004;
+    public static final int SC_RESP_LAST_MODIFIED       = 0xA005;
+    public static final int SC_RESP_LOCATION            = 0xA006;
+    public static final int SC_RESP_SET_COOKIE          = 0xA007;
+    public static final int SC_RESP_SET_COOKIE2         = 0xA008;
+    public static final int SC_RESP_SERVLET_ENGINE      = 0xA009;
+    public static final int SC_RESP_STATUS              = 0xA00A;
+    public static final int SC_RESP_WWW_AUTHENTICATE    = 0xA00B;
+	
+    // Integer codes for common (optional) request attribute names
+    public static final byte SC_A_CONTEXT       = 1;  // XXX Unused
+    public static final byte SC_A_SERVLET_PATH  = 2;  // XXX Unused
+    public static final byte SC_A_REMOTE_USER   = 3;
+    public static final byte SC_A_AUTH_TYPE     = 4;
+    public static final byte SC_A_QUERY_STRING  = 5;
+    public static final byte SC_A_JVM_ROUTE     = 6;
+    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;
+    public static final byte SC_A_SSL_KEY_SIZE  = 11; // ajp14 originally, now in ajp13 with jk 1.2/2.0
+    public static final byte SC_A_SECRET        = 12;
+    public static final byte SC_A_STORED_METHOD = 13;
+
+    // Used for attributes which are not in the list above
+    public static final byte SC_A_REQ_ATTRIBUTE = 10; 
+
+    // Terminates list of attributes
+    public static final byte SC_A_ARE_DONE      = (byte)0xFF;
+    
+    // Translates integer codes to names of HTTP methods
+    public static final String []methodTransArray = {
+        "OPTIONS",
+        "GET",
+        "HEAD",
+        "POST",
+        "PUT",
+        "DELETE",
+        "TRACE",
+        "PROPFIND",
+        "PROPPATCH",
+        "MKCOL",
+        "COPY",
+        "MOVE",
+        "LOCK",
+        "UNLOCK",
+        "ACL",
+        "REPORT",
+        "VERSION-CONTROL",
+        "CHECKIN",
+        "CHECKOUT",
+        "UNCHECKOUT",
+        "SEARCH",
+        "MKWORKSPACE",
+        "UPDATE",
+        "LABEL",
+        "MERGE",
+        "BASELINE-CONTROL",
+        "MKACTIVITY"
+    };
+    public static final int SC_M_JK_STORED = (byte) 0xFF;
+
+    
+    // id's for common request headers
+    public static final int SC_REQ_ACCEPT          = 1;
+    public static final int SC_REQ_ACCEPT_CHARSET  = 2;
+    public static final int SC_REQ_ACCEPT_ENCODING = 3;
+    public static final int SC_REQ_ACCEPT_LANGUAGE = 4;
+    public static final int SC_REQ_AUTHORIZATION   = 5;
+    public static final int SC_REQ_CONNECTION      = 6;
+    public static final int SC_REQ_CONTENT_TYPE    = 7;
+    public static final int SC_REQ_CONTENT_LENGTH  = 8;
+    public static final int SC_REQ_COOKIE          = 9;
+    public static final int SC_REQ_COOKIE2         = 10;
+    public static final int SC_REQ_HOST            = 11;
+    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;
+
+    // Translates integer codes to request header names    
+    public static final String []headerTransArray = {
+        "accept",
+        "accept-charset",
+        "accept-encoding",
+        "accept-language",
+        "authorization",
+        "connection",
+        "content-type",
+        "content-length",
+        "cookie",
+        "cookie2",
+        "host",
+        "pragma",
+        "referer",
+        "user-agent"
+    };
+
+    public RequestHandler() 
+    {
+    }
+
+    public void init( Ajp13 ajp14 ) {
+	// register incoming message handlers
+	ajp14.registerMessageType( JK_AJP13_FORWARD_REQUEST,
+				   "JK_AJP13_FORWARD_REQUEST",
+				   this, null); // 2
+	// register outgoing messages handler
+	ajp14.registerMessageType( JK_AJP13_SEND_BODY_CHUNK, // 3
+				   "JK_AJP13_SEND_BODY_CHUNK",
+				   this,null );
+	ajp14.registerMessageType( JK_AJP13_SEND_HEADERS,  // 4
+				   "JK_AJP13_SEND_HEADERS",
+				   this,null );
+	ajp14.registerMessageType( JK_AJP13_END_RESPONSE, // 5
+				   "JK_AJP13_END_RESPONSE",
+				   this,null );
+	ajp14.registerMessageType( JK_AJP13_GET_BODY_CHUNK, // 6
+				   "JK_AJP13_GET_BODY_CHUNK",
+				   this, null );
+	ajp14.registerMessageType( JK_AJP13_CPING_REQUEST,
+				   "JK_AJP13_PING_REQUEST",
+				   this, null); // 10
+	ajp14.registerMessageType( JK_AJP13_CPONG_REPLY,
+				   "JK_AJP13_PONG_REPLY",
+				   this, null); // 9
+    }
+    
+    /**
+     * Send a CPONG REPLY to web server to its CPING request
+     * 
+     * @param ch the Ajp13 channel
+     * @param outBuf the Ajp13Packet output packet to use
+     */
+    public int sendCPong(Ajp13 ch, Ajp13Packet outBuf)
+    {
+		outBuf.reset();
+		outBuf.appendByte(JK_AJP13_CPONG_REPLY);
+    	
+    	try
+    	{
+			ch.send(outBuf);
+    	}
+    	catch (IOException ioe)
+    	{
+    		log("can't send pong reply");
+    	}
+    	
+    	return (999);	// success but no need to process farther
+    }
+    
+    // -------------------- Incoming message --------------------
+    public int handleAjpMessage( int type, Ajp13 channel,
+				 Ajp13Packet ajp, BaseRequest req )
+	throws IOException
+    {
+	switch( type ) {
+	case RequestHandler.JK_AJP13_FORWARD_REQUEST:
+	    return decodeRequest(channel, channel.hBuf, req );
+		
+	default:
+	    return UNKNOWN;
+	}
+    }
+    
+    /**
+     * Parse a FORWARD_REQUEST packet from the web server and store its
+     * properties in the passed-in request object.
+     *
+     * @param req An empty (newly-recycled) request object.
+     * @param msg Holds the packet which has just been sent by the web
+     * server, with its read position just past the packet header (which in
+     * this case includes the prefix code for FORWARD_REQUEST).
+     *
+     * @return 200 in case of a successful decoduing, 500 in case of error.  
+     */
+    protected int decodeRequest(Ajp13 ch, Ajp13Packet msg, BaseRequest req)
+        throws IOException
+    {
+        
+        if (debug > 0) {
+            log("decodeRequest()");
+        }
+
+	// XXX Awful return values
+
+        boolean isSSL = false;
+
+        // Translate the HTTP method code to a String.
+        byte methodCode = msg.getByte();
+        if (methodCode != SC_M_JK_STORED)
+          req.method().setString(methodTransArray[(int)methodCode - 1]);
+
+        msg.getMessageBytes(req.protocol()); 
+        msg.getMessageBytes(req.requestURI());
+
+        msg.getMessageBytes(req.remoteAddr());
+        msg.getMessageBytes(req.remoteHost());
+        msg.getMessageBytes(req.serverName());
+        req.setServerPort(msg.getInt());
+
+	isSSL = msg.getBool();
+
+	// Decode headers
+	MimeHeaders headers = req.headers();
+	int hCount = msg.getInt();
+        for(int i = 0 ; i < hCount ; i++) {
+            String hName = null;
+
+	    // Header names are encoded as either an integer code starting
+	    // with 0xA0, or as a normal string (in which case the first
+	    // two bytes are the length).
+            int isc = msg.peekInt();
+            int hId = isc & 0xFF;
+
+	    MessageBytes vMB=null;
+            isc &= 0xFF00;
+            if(0xA000 == isc) {
+                //
+                // header name is encoded as an int
+                //
+                msg.getInt(); // To advance the read position
+                hName = headerTransArray[hId - 1];
+		vMB= headers.addValue(hName);
+                msg.getMessageBytes(vMB);
+
+                if (hId == SC_REQ_CONTENT_LENGTH) {
+                    // just read content-length header
+                    int contentLength = (vMB == null) ? -1 : vMB.getInt();
+                    req.setContentLength(contentLength);
+                } else if (hId == SC_REQ_CONTENT_TYPE) {
+                    // just read content-type header
+                    ByteChunk bchunk = vMB.getByteChunk();
+                    req.contentType().setBytes(bchunk.getBytes(),
+                                               bchunk.getOffset(),
+                                               bchunk.getLength());
+                } else if (hId == SC_REQ_AUTHORIZATION) {
+                    ByteChunk bchunk = vMB.getByteChunk();
+                    req.authorization().setBytes(bchunk.getBytes(),
+                                               bchunk.getOffset(),
+                                               bchunk.getLength());
+                }
+            } else {
+                //
+                // header name is a string
+                //
+		// XXX Not very elegant
+		vMB = msg.addHeader(headers);
+		if (vMB == null) {
+                    return 500; // wrong packet
+                }
+                msg.getMessageBytes(vMB);
+            }
+        }
+
+	byte attributeCode;
+        for(attributeCode = msg.getByte() ;
+            attributeCode != SC_A_ARE_DONE ;
+            attributeCode = msg.getByte()) {
+            switch(attributeCode) {
+	    case SC_A_CONTEXT      :
+                break;
+		
+	    case SC_A_SERVLET_PATH :
+                break;
+		
+	    case SC_A_REMOTE_USER  :
+                msg.getMessageBytes(req.remoteUser());
+                break;
+		
+	    case SC_A_AUTH_TYPE    :
+                msg.getMessageBytes(req.authType());
+                break;
+		
+	    case SC_A_QUERY_STRING :
+		msg.getMessageBytes(req.queryString());
+                break;
+		
+	    case SC_A_JVM_ROUTE    :
+                msg.getMessageBytes(req.jvmRoute());
+                break;
+		
+	    case SC_A_SSL_CERT     :
+		isSSL = true;
+                // Transform the string into certificate.
+                String certString = msg.getString();
+                byte[] certData = certString.getBytes();
+                ByteArrayInputStream bais = new ByteArrayInputStream(certData);
+ 
+                // Fill the first element.
+                X509Certificate jsseCerts[] = null;
+                try {
+                    CertificateFactory cf =
+                        CertificateFactory.getInstance("X.509");
+                    X509Certificate cert = (X509Certificate)
+                        cf.generateCertificate(bais);
+                    jsseCerts =  new X509Certificate[1];
+                    jsseCerts[0] = cert;
+                } catch(java.security.cert.CertificateException e) {
+                    log("Certificate convertion failed" + e );
+                }
+ 
+                req.setAttribute("javax.servlet.request.X509Certificate",
+                                 jsseCerts);
+                break;
+		
+	    case SC_A_SSL_CIPHER   :
+		isSSL = true;
+		req.setAttribute("javax.servlet.request.cipher_suite",
+				 msg.getString());
+                break;
+		
+	    case SC_A_SECRET   :
+                // If a request has a secret attribute, set it on
+                // channel - it'll be visible to the caller ( Interceptor,
+                // Connector ) and it can check it against its settings before
+                // trusting us.
+                String secret=msg.getString();
+                if(secret!=null) {
+                    ch.setSecret( secret );
+                }
+                break;
+		
+	    case SC_A_SSL_SESSION  :
+		isSSL = true;
+		req.setAttribute("javax.servlet.request.ssl_session",
+				  msg.getString());
+                break;
+		
+	    case SC_A_REQ_ATTRIBUTE :
+		req.setAttribute(msg.getString(), 
+				 msg.getString());
+                break;
+
+	    case SC_A_SSL_KEY_SIZE: // Ajp13 !
+                isSSL = true;
+		req.setAttribute("javax.servlet.request.key_size",
+				 Integer.toString(msg.getInt()));
+		break;
+    
+        case SC_A_STORED_METHOD:
+                req.method().setString(msg.getString());
+                break;
+    
+	    default:
+                // Ignore. Assume a single-string value - we shouldn't
+                // allow anything else.
+                msg.getString();
+                break;
+	    }
+        }
+
+        if(isSSL) {
+            req.setScheme(req.SCHEME_HTTPS);
+            req.setSecure(true);
+        }
+
+        // set cookies on request now that we have all headers
+        req.cookies().setHeaders(req.headers());
+
+	// Check to see if there should be a body packet coming along
+	// immediately after
+    	if(req.getContentLength() > 0) {
+
+	    /* Read present data */
+	    int err = ch.receive(ch.inBuf);
+            if(err < 0) {
+            	return 500;
+	    }
+	    
+	    ch.blen = ch.inBuf.peekInt();
+	    ch.pos = 0;
+	    ch.inBuf.getBytes(ch.bodyBuff);
+    	}
+    
+        if (debug > 5) {
+            log(req.toString());
+        }
+
+        return 200; // Success
+    }
+    
+
+    // -------------------- Messages from container to server ------------------
+    
+    /**
+     * Send the HTTP headers back to the web server and on to the browser.
+     *
+     * @param status The HTTP status code to send.
+     * @param statusMessage the HTTP status message to send.
+     * @param headers The set of all headers.
+     */
+    public void sendHeaders(Ajp13 ch, Ajp13Packet outBuf,
+			    int status, String statusMessage,
+                            MimeHeaders headers)
+        throws IOException
+    {
+	// XXX if more headers that MAX_SIZE, send 2 packets!
+	if( statusMessage==null ) statusMessage=HttpMessages.getMessage(status);
+	outBuf.reset();
+        outBuf.appendByte(JK_AJP13_SEND_HEADERS);
+        outBuf.appendInt(status);
+	
+	outBuf.appendString(statusMessage);
+        
+	int numHeaders = headers.size();
+        outBuf.appendInt(numHeaders);
+        
+	for( int i=0 ; i < numHeaders ; i++ ) {
+	    String headerName = headers.getName(i).toString();
+	    int sc = headerNameToSc(headerName);
+            if(-1 != sc) {
+                outBuf.appendInt(sc);
+            } else {
+                outBuf.appendString(headerName);
+            }
+            outBuf.appendString(headers.getValue(i).toString() );
+        }
+
+        outBuf.end();
+        ch.send(outBuf);
+    } 
+
+
+    /**
+     * Signal the web server that the servlet has finished handling this
+     * request, and that the connection can be reused.
+     */
+    public void finish(Ajp13 ch, Ajp13Packet outBuf) throws IOException {
+        if (debug > 0)  log("finish()");
+
+	outBuf.reset();
+        outBuf.appendByte(JK_AJP13_END_RESPONSE);
+        outBuf.appendBool(true); // Reuse this connection
+        outBuf.end();
+        ch.send(outBuf);
+    }
+
+    /**
+     * Send a chunk of response body data to the web server and on to the
+     * browser.
+     *
+     * @param b A huffer of bytes to send.
+     * @param off The offset into the buffer from which to start sending.
+     * @param len The number of bytes to send.
+     */    
+    public void doWrite(Ajp13 ch, Ajp13Packet outBuf,
+			byte b[], int off, int len)
+	throws IOException
+    {
+        if (debug > 0) log("doWrite(byte[], " + off + ", " + len + ")");
+
+	int sent = 0;
+	while(sent < len) {
+	    int to_send = len - sent;
+	    to_send = to_send > Ajp13.MAX_SEND_SIZE ? Ajp13.MAX_SEND_SIZE : to_send;
+
+	    outBuf.reset();
+	    outBuf.appendByte(JK_AJP13_SEND_BODY_CHUNK);	        	
+	    outBuf.appendBytes(b, off + sent, to_send);	        
+	    ch.send(outBuf);
+	    sent += to_send;
+	}
+    }
+
+    // -------------------- Utils -------------------- 
+
+    /**
+     * Translate an HTTP response header name to an integer code if
+     * possible.  Case is ignored.
+     * 
+     * @param name The name of the response header to translate.
+     *
+     * @return The code for that header name, or -1 if no code exists.
+     */
+    protected int headerNameToSc(String name)
+    {       
+        switch(name.charAt(0)) {
+	case 'c':
+	case 'C':
+	    if(name.equalsIgnoreCase("Content-Type")) {
+		return SC_RESP_CONTENT_TYPE;
+	    } else if(name.equalsIgnoreCase("Content-Language")) {
+		return SC_RESP_CONTENT_LANGUAGE;
+	    } else if(name.equalsIgnoreCase("Content-Length")) {
+		return SC_RESP_CONTENT_LENGTH;
+	    }
+            break;
+            
+	case 'd':
+	case 'D':
+	    if(name.equalsIgnoreCase("Date")) {
+                return SC_RESP_DATE;
+	    }
+            break;
+            
+	case 'l':
+	case 'L':
+	    if(name.equalsIgnoreCase("Last-Modified")) {
+		return SC_RESP_LAST_MODIFIED;
+	    } else if(name.equalsIgnoreCase("Location")) {
+		return SC_RESP_LOCATION;
+	    }
+            break;
+
+	case 's':
+	case 'S':
+	    if(name.equalsIgnoreCase("Set-Cookie")) {
+		return SC_RESP_SET_COOKIE;
+	    } else if(name.equalsIgnoreCase("Set-Cookie2")) {
+		return SC_RESP_SET_COOKIE2;
+	    }
+            break;
+            
+	case 'w':
+	case 'W':
+	    if(name.equalsIgnoreCase("WWW-Authenticate")) {
+		return SC_RESP_WWW_AUTHENTICATE;
+	    }
+            break;          
+        }
+        
+        return -1;
+    }
+   
+    private int debug=0;
+    private Logger logger = new Logger();
+    
+    public void setDebug(int debug) {
+        this.debug = debug;
+    }
+
+    public void setLogger(Logger l) {
+        this.logger = l;
+    }
+    
+    void log(String s) {
+        logger.log("[RequestHandler] " + s );
+    }
+
+    // ==================== Servlet Input Support =================
+    // XXX DEPRECATED
+    
+    public int available(Ajp13 ch) throws IOException {
+        if (debug > 0) {
+            log("available()");
+        }
+
+        if (ch.pos >= ch.blen) {
+            if( ! refillReadBuffer(ch)) {
+		return 0;
+	    }
+        }
+        return ch.blen - ch.pos;
+    }
+
+    /**
+     * Return the next byte of request body data (to a servlet).
+     */
+    public int doRead(Ajp13 ch) throws IOException 
+    {
+        if (debug > 0) {
+            log("doRead()");
+        }
+
+        if(ch.pos >= ch.blen) {
+            if( ! refillReadBuffer(ch)) {
+		return -1;
+	    }
+        }
+        return ch.bodyBuff[ch.pos++] & 0xFF;
+    }
+    
+    /**
+     * Store a chunk of request data into the passed-in byte buffer.
+     *
+     * @param b A buffer to fill with data from the request.
+     * @param off The offset in the buffer at which to start filling.
+     * @param len The number of bytes to copy into the buffer.
+     *
+     * @return The number of bytes actually copied into the buffer, or -1
+     * if the end of the stream has been reached.
+     */
+    public int doRead(Ajp13 ch, byte[] b, int off, int len) throws IOException 
+    {
+        if (debug > 0) {
+            log("doRead(byte[], int, int)");
+        }
+
+	if(ch.pos >= ch.blen) {
+	    if( ! refillReadBuffer(ch)) {
+		return -1;
+	    }
+	}
+
+	if(ch.pos + len <= ch.blen) { // Fear the off by one error
+	    // Sanity check b.length > off + len?
+	    System.arraycopy(ch.bodyBuff, ch.pos, b, off, len);
+	    ch.pos += len;
+	    return len;
+	}
+
+	// Not enough data (blen < pos + len)
+	int toCopy = len;
+	while(toCopy > 0) {
+	    int bytesRemaining = ch.blen - ch.pos;
+	    if(bytesRemaining < 0) 
+		bytesRemaining = 0;
+	    int c = bytesRemaining < toCopy ? bytesRemaining : toCopy;
+            
+	    System.arraycopy(ch.bodyBuff, ch.pos, b, off, c);
+
+	    toCopy    -= c;
+
+	    off       += c;
+	    ch.pos       += c; // In case we exactly consume the buffer
+
+	    if(toCopy > 0) 
+		if( ! refillReadBuffer(ch)) { // Resets blen and pos
+		    break;
+		}
+	}
+
+	return len - toCopy;
+    }
+    
+    /**
+     * Get more request body data from the web server and store it in the 
+     * internal buffer.
+     *
+     * @return true if there is more data, false if not.    
+     */
+    public boolean refillReadBuffer(Ajp13 ch) throws IOException 
+    {
+        if (debug > 0) {
+            log("refillReadBuffer()");
+        }
+
+	// If the server returns an empty packet, assume that that end of
+	// the stream has been reached (yuck -- fix protocol??).
+
+	// Why not use outBuf??
+	ch.inBuf.reset();
+	ch.inBuf.appendByte(JK_AJP13_GET_BODY_CHUNK);
+	ch.inBuf.appendInt(Ajp13.MAX_READ_SIZE);
+	ch.send(ch.inBuf);
+	
+	int err = ch.receive(ch.inBuf);
+        if(err < 0) {
+	    throw new IOException();
+	}
+	
+        // check for empty packet, which means end of stream
+        if (ch.inBuf.getLen() == 0) {
+            if (debug > 0) {
+                log("refillReadBuffer():  "
+                    + "received empty packet -> end of stream");
+            }
+            ch.blen = 0;
+            ch.pos = 0;
+            return false;
+        }
+
+    	ch.blen = ch.inBuf.peekInt();
+    	ch.pos = 0;
+    	ch.inBuf.getBytes(ch.bodyBuff);
+
+	return (ch.blen > 0);
+    }    
+
+    // ==================== Servlet Output Support =================
+    
+    /**
+     */
+    public void beginSendHeaders(Ajp13 ch, Ajp13Packet outBuf,
+				 int status,
+                                 String statusMessage,
+                                 int numHeaders) throws IOException {
+
+        if (debug > 0) {
+            log("sendHeaders()");
+        }
+
+	// XXX if more headers that MAX_SIZE, send 2 packets!
+
+	outBuf.reset();
+        outBuf.appendByte(JK_AJP13_SEND_HEADERS);
+
+        if (debug > 0) {
+            log("status is:  " + status +
+                       "(" + statusMessage + ")");
+        }
+
+        // set status code and message
+        outBuf.appendInt(status);
+        outBuf.appendString(statusMessage);
+
+        // write the number of headers...
+        outBuf.appendInt(numHeaders);
+    }
+
+    public void sendHeader(Ajp13Packet outBuf,
+			   String name, String value)
+	throws IOException
+    {
+        int sc = headerNameToSc(name);
+        if(-1 != sc) {
+            outBuf.appendInt(sc);
+        } else {
+            outBuf.appendString(name);
+        }
+        outBuf.appendString(value);
+    }
+
+    public void endSendHeaders(Ajp13 ch, Ajp13Packet outBuf)
+	throws IOException
+    {
+        outBuf.end();
+        ch.send(outBuf);
+    }
+
+    /**
+     * Send the HTTP headers back to the web server and on to the browser.
+     *
+     * @param status The HTTP status code to send.
+     * @param headers The set of all headers.
+     */
+    public void sendHeaders(Ajp13 ch, Ajp13Packet outBuf,
+			    int status, MimeHeaders headers)
+        throws IOException
+    {
+        sendHeaders(ch, outBuf, status, HttpMessages.getMessage(status),
+                    headers);
+    }
+    
+
+ }

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/ajp/tomcat33/Ajp14Interceptor.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/ajp/tomcat33/Ajp14Interceptor.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/ajp/tomcat33/Ajp14Interceptor.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,460 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.ajp.tomcat33;
+
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.Socket;
+
+import org.apache.ajp.Ajp13;
+import org.apache.ajp.NegociationHandler;
+import org.apache.ajp.RequestHandler;
+import org.apache.tomcat.core.Context;
+import org.apache.tomcat.core.ContextManager;
+import org.apache.tomcat.core.Request;
+import org.apache.tomcat.core.Response;
+import org.apache.tomcat.core.TomcatException;
+import org.apache.tomcat.modules.server.PoolTcpConnector;
+import org.apache.tomcat.util.buf.UDecoder;
+import org.apache.tomcat.util.http.BaseRequest;
+import org.apache.tomcat.util.http.Cookies;
+import org.apache.tomcat.util.http.HttpMessages;
+import org.apache.tomcat.util.net.TcpConnection;
+import org.apache.tomcat.util.net.TcpConnectionHandler;
+
+/** Note. PoolTcpConnector is a convenience base class used for
+    TCP-based connectors in tomcat33. It allows all those modules
+    to share the thread pool and listener code.
+
+    In future it's likely other optimizations will be implemented in
+    the PoolTcpConnector, so it's better to use it if you don't have
+    a good reason not to ( like a connector for J2ME, where you want
+    minimal footprint and don't care about high load )
+*/
+
+/** Tomcat 33 module implementing the Ajp14 protocol.
+ *
+ *  The actual protocol implementation is in Ajp14.java, this is just an
+ *  adapter to plug it into tomcat.
+ */
+public class Ajp14Interceptor extends PoolTcpConnector
+    implements  TcpConnectionHandler
+{
+    int ajp14_note=-1;
+    String password;
+    RequestHandler reqHandler=new RequestHandler();
+    NegociationHandler negHandler=new NegociationHandler();
+    
+    public Ajp14Interceptor()
+    {
+        super();
+ 	super.setSoLinger( 100 );
+	super.setTcpNoDelay( true );
+    }
+
+    // initialization
+    public void engineInit(ContextManager cm) throws TomcatException {
+	log("engineInit");
+    }
+
+    public void engineStart(ContextManager cm) throws TomcatException {
+	super.engineInit( cm );
+	ajp14_note=cm.getNoteId( ContextManager.REQUEST_NOTE, "ajp14" );
+	super.engineStart(cm);
+   }
+
+    
+    // -------------------- Ajp14 specific parameters --------------------
+
+    public void setPassword( String s ) {
+	this.password=s;
+    }
+
+    /**
+     * Set the original entropy seed
+     */
+    public void setSeed(String pseed) 
+    {
+	negHandler.setSeed( pseed );
+    }
+    
+    // -------------------- PoolTcpConnector --------------------
+
+    /** Called by PoolTcpConnector to allow childs to init.
+     */
+    protected void localInit() throws Exception {
+	ep.setConnectionHandler( this );
+    }
+
+    // -------------------- Handler implementation --------------------
+
+    /*  The TcpConnectionHandler interface is used by the PoolTcpConnector to
+     *  handle incoming connections.
+     */
+
+    /** Called by the thread pool when a new thread is added to the pool,
+	in order to create the (expensive) objects that will be stored
+	as thread data.
+	XXX we should use a single object, not array ( several reasons ),
+	XXX Ajp14 should be storead as a request note, to be available in
+	all modules
+    */
+    public Object[] init()
+    {
+	if( debug > 0 ) log("Init ");
+        Object thData[]=new Object[1];
+	thData[0]=initRequest( null );
+	return thData;
+    }
+
+    /** Construct the request object, with probably unnecesary
+	sanity tests ( should work without thread pool - but that is
+	not supported in PoolTcpConnector, maybe in future )
+    */
+    private Ajp14Request initRequest(Object thData[] ) {
+	if( ajp14_note < 0 ) throw new RuntimeException( "assert: ajp14_note>0" );
+	Ajp14Request req=null;
+	if( thData != null ) {
+	    req=(Ajp14Request)thData[0];
+	}
+	if( req != null ) {
+	    Response res=req.getResponse();
+	    req.recycle();
+	    res.recycle();
+	    // make the note available to other modules
+	    req.setNote( ajp14_note, req.ajp13);
+	    return req;
+	}
+	// either thData==null or broken ( req==null)
+       	Ajp13 ajp13=new Ajp13(reqHandler);
+        negHandler.init( ajp13 );
+
+	negHandler.setContainerSignature( ContextManager.TOMCAT_NAME +
+                                          " v" + ContextManager.TOMCAT_VERSION);
+	if( password!= null ) {
+            negHandler.setPassword( password );
+            ajp13.setBackward(false); 
+        }
+
+	BaseRequest ajpreq=new BaseRequest();
+
+	req=new Ajp14Request(ajp13, ajpreq);
+	Ajp14Response res=new Ajp14Response(ajp13);
+	cm.initRequest(req, res);
+	return  req;
+    }
+    
+    /** Called whenever a new TCP connection is received. The connection
+	is reused.
+     */
+    public void processConnection(TcpConnection connection, Object thData[])
+    {
+        try {
+	    if( debug>0)
+		log( "Received ajp14 connection ");
+            Socket socket = connection.getSocket();
+	    // assert: socket!=null, connection!=null ( checked by PoolTcpEndpoint )
+	    
+            socket.setSoLinger( true, 100);
+
+            Ajp14Request req=initRequest( thData );
+            Ajp14Response res= (Ajp14Response)req.getResponse();
+            Ajp13 ajp13=req.ajp13;
+	    BaseRequest ajpReq=req.ajpReq;
+
+            ajp13.setSocket(socket);
+
+	    // first request should be the loginit.
+	    int status=ajp13.receiveNextRequest( ajpReq );
+	    if( status != 304 )  { // XXX use better codes
+		log( "Failure in logInit ");
+		return;
+	    }
+
+	    status=ajp13.receiveNextRequest( ajpReq );
+	    if( status != 304 ) { // XXX use better codes
+		log( "Failure in login ");
+		return;
+	    }
+	    
+            boolean moreRequests = true;
+            while(moreRequests) {
+		status=ajp13.receiveNextRequest( ajpReq );
+
+		if( status==-2) {
+		    // special case - shutdown
+		    // XXX need better communication, refactor it
+		    if( !doShutdown(socket.getLocalAddress(),
+				    socket.getInetAddress())) {
+			moreRequests = false;
+			continue;
+		    }                        
+		}
+		
+		// 999 low level requests are just ignored (ie cping/cpong)
+		if( status  == 200)
+		    cm.service(req, res);
+		else if (status == 500) {
+		    log( "Invalid request received " + req );
+		    break;
+		}
+		
+		req.recycle();
+		res.recycle();
+            }
+            if( debug > 0 ) log("Closing ajp14 connection");
+            ajp13.close();
+	    socket.close();
+        } catch (Exception e) {
+	    log("Processing connection " + connection, e);
+        }
+    }
+
+    // We don't need to check isSameAddress if we authenticate !!!
+    protected boolean doShutdown(InetAddress serverAddr,
+                                 InetAddress clientAddr)
+    {
+        try {
+	    // close the socket connection before handling any signal
+	    // but get the addresses first so they are not corrupted			
+            if(isSameAddress(serverAddr, clientAddr)) {
+		cm.stop();
+		// same behavior as in past, because it seems that
+		// stopping everything doesn't work - need to figure
+		// out what happens with the threads ( XXX )
+
+		// XXX It should work now - but will fail if servlets create
+		// threads
+		System.exit(0);
+	    }
+	} catch(Exception ignored) {
+	    log("Ignored " + ignored);
+	}
+	log("Shutdown command ignored");
+	return false;
+    }
+
+    // legacy, should be removed 
+    public void setServer(Object contextM)
+    {
+        this.cm=(ContextManager)contextM;
+    }
+
+    public Object getInfo( Context ctx, Request request,
+			   int id, String key ) {
+	if( ! ( request instanceof Ajp14Request ) ) {
+	    return null;
+	}
+	Ajp14Request ajp14req = (Ajp14Request)request;
+	return ajp14req.ajpReq.getAttribute( key );
+    }
+    public int setInfo( Context ctx, Request request,
+			int id, String key, Object obj ) {
+	if( ! ( request instanceof Ajp14Request ) ) {
+	    return DECLINED;
+	}
+	Ajp14Request ajp14req = (Ajp14Request)request;
+	ajp14req.ajpReq.setAttribute(key, obj);
+	return OK;
+    }
+		
+
+
+}
+
+
+//-------------------- Glue code for request/response.
+// Probably not needed ( or can be simplified ), but it's
+// not that bad.
+
+class Ajp14Request extends Request 
+{
+    Ajp13 ajp13;
+    BaseRequest ajpReq;
+    
+    public Ajp14Request(Ajp13 ajp13, BaseRequest ajpReq) 
+    {
+	headers = ajpReq.headers();
+	methodMB=ajpReq.method();
+	protoMB=ajpReq.protocol();
+	uriMB = ajpReq.requestURI();
+	queryMB = ajpReq.queryString();
+	remoteAddrMB = ajpReq.remoteAddr();
+	remoteHostMB = ajpReq.remoteHost();
+	serverNameMB = ajpReq.serverName();
+
+	// XXX sync cookies 
+	scookies = new Cookies( headers );
+	urlDecoder=new UDecoder();
+
+	// XXX sync headers
+	
+	params.setQuery( queryMB );
+	params.setURLDecoder( urlDecoder );
+	params.setHeaders( headers );
+	initRequest(); 	
+
+        this.ajp13=ajp13;
+	this.ajpReq=ajpReq;
+    }
+
+    // -------------------- Wrappers for changed method names, and to use the buffers
+    // XXX Move BaseRequest into util !!! ( it's just a stuct with some MessageBytes )
+
+    public int getServerPort() {
+        return ajpReq.getServerPort();
+    }
+
+    public void setServerPort(int i ) {
+	ajpReq.setServerPort( i );
+    }
+
+    public  void setRemoteUser( String s ) {
+	super.setRemoteUser(s);
+	ajpReq.remoteUser().setString(s);
+    }
+
+    public String getRemoteUser() {
+	String s=ajpReq.remoteUser().toString();
+	if( s == null )
+	    s=super.getRemoteUser();
+	return s;
+    }
+
+    public String getAuthType() {
+	return ajpReq.authType().toString();
+    }
+    
+    public void setAuthType(String s ) {
+	ajpReq.authType().setString(s);
+    }
+
+    public String getJvmRoute() {
+	return ajpReq.jvmRoute().toString();
+    }
+    
+    public void setJvmRoute(String s ) {
+	ajpReq.jvmRoute().setString(s);
+    }
+
+    // XXX scheme
+    
+    public boolean isSecure() {
+	return ajpReq.getSecure();
+    }
+    
+    public int getContentLength() {
+        int i=ajpReq.getContentLength();
+	if( i >= 0 ) return i;
+	i= super.getContentLength();
+	return i;
+    }
+
+    public void setContentLength( int i ) {
+	super.setContentLength(i); // XXX sync
+    }
+
+    // XXX broken
+//     public Iterator getAttributeNames() {
+//         return attributes.keySet().iterator();
+//     }
+
+
+    // --------------------
+
+    public void recycle() {
+	super.recycle();
+	ajpReq.recycle();
+	if( ajp13!=null) ajp13.recycle();
+    }
+
+    public String dumpRequest() {
+	return ajpReq.toString();
+    }
+    
+    // -------------------- 
+    
+    // XXX This should go away if we introduce an InputBuffer.
+    // We almost have it as result of encoding fixes, but for now
+    // just keep this here, doesn't hurt too much.
+    public int doRead() throws IOException 
+    {
+	if( available <= 0 )
+	    return -1;
+	available--;
+	return ajp13.reqHandler.doRead(ajp13);
+    }
+    
+    public int doRead(byte[] b, int off, int len) throws IOException 
+    {
+	if( available <= 0 )
+	    return -1;
+	int rd=ajp13.reqHandler.doRead( ajp13, b,off, len );
+	available -= rd;
+	return rd;
+    }
+    
+}
+
+class Ajp14Response extends Response 
+{
+    Ajp13 ajp13;
+    boolean finished=false;
+    
+    public Ajp14Response(Ajp13 ajp13) 
+    {
+	super();
+	this.ajp13=ajp13;
+    }
+
+    public void recycle() {
+	super.recycle();
+	finished=false;
+    }
+
+    // XXX if more headers that MAX_SIZE, send 2 packets!
+    // XXX Can be implemented using module notification, no need to extend
+    public void endHeaders() throws IOException 
+    {
+        super.endHeaders();
+    
+        if (request.protocol().isNull()) {
+            return;
+        }
+
+	ajp13.reqHandler.sendHeaders(ajp13, ajp13.outBuf, getStatus(),
+				     HttpMessages.getMessage(status),
+				     getMimeHeaders());
+    } 
+
+    // XXX Can be implemented using module notification, no need to extend
+    public void finish() throws IOException 
+    {
+	if(!finished) {
+	    super.finish();
+		finished = true; // Avoid END_OF_RESPONSE sent 2 times
+	    ajp13.reqHandler.finish(ajp13, ajp13.outBuf);
+	}
+    }
+
+    // XXX Can be implemented using the buffers, no need to extend
+    public void doWrite(  byte b[], int off, int len) throws IOException 
+    {
+	ajp13.reqHandler.doWrite(ajp13, ajp13.outBuf, b, off, len );
+    }
+    
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/ajp/tomcat4/Ajp13Connector.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/ajp/tomcat4/Ajp13Connector.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/ajp/tomcat4/Ajp13Connector.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,1108 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.ajp.tomcat4;
+
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.security.AccessControlException;
+import java.util.Stack;
+import java.util.Vector;
+
+import org.apache.catalina.Connector;
+import org.apache.catalina.Container;
+import org.apache.catalina.Lifecycle;
+import org.apache.catalina.LifecycleException;
+import org.apache.catalina.LifecycleListener;
+import org.apache.catalina.Request;
+import org.apache.catalina.Response;
+import org.apache.catalina.Service;
+import org.apache.catalina.net.DefaultServerSocketFactory;
+import org.apache.catalina.net.ServerSocketFactory;
+import org.apache.catalina.util.LifecycleSupport;
+import org.apache.catalina.util.StringManager;
+
+/**
+ * Implementation of an Ajp13 connector.
+ *
+ * @author Kevin Seguin
+ * @version $Revision: 299218 $ $Date: 2004-02-24 02:48:44 -0600 (Tue, 24 Feb 2004) $
+ */
+
+
+public final class Ajp13Connector
+    implements Connector, Lifecycle, Runnable {
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The accept count for this Connector.
+     */
+    private int acceptCount = 10;
+
+
+    /**
+     * The IP address on which to bind, if any.  If <code>null</code>, all
+     * addresses on the server will be bound.
+     */
+    private String address = null;
+
+
+    /**
+     * The input buffer size we should create on input streams.
+     */
+    private int bufferSize = 2048;
+
+
+    /**
+     * The Container used for processing requests received by this Connector.
+     */
+    protected Container container = null;
+
+
+    /**
+     * The set of processors that have ever been created.
+     */
+    private Vector created = new Vector();
+
+
+    /**
+     * The current number of processors that have been created.
+     */
+    private int curProcessors = 0;
+
+
+    /**
+     * The debugging detail level for this component.
+     */
+    private int debug = 0;
+
+
+    /**
+     * The server socket factory for this component.
+     */
+    private ServerSocketFactory factory = null;
+
+
+    /**
+     * Descriptive information about this Connector implementation.
+     */
+    private static final String info =
+        "org.apache.catalina.connector.ajp.Ajp13Connector/1.0";
+
+
+    /**
+     * redirect port.
+     */
+    private int redirectPort = -1;
+
+    /**
+     * enable DNS lookups.
+     */
+    private boolean enableLookups = false;
+
+    /**
+     * The lifecycle event support for this component.
+     */
+    protected LifecycleSupport lifecycle = new LifecycleSupport(this);
+
+
+    /**
+     * The minimum number of processors to start at initialization time.
+     */
+    protected int minProcessors = 5;
+
+
+    /**
+     * The maximum number of processors allowed, or <0 for unlimited.
+     */
+    private int maxProcessors = 20;
+
+
+    /**
+     * Timeout value on the incoming connection.
+     * Note : a value of 0 means no timeout.
+     */
+    private int connectionTimeout = -1;
+
+
+    /**
+     * Linger value to be used on socket close.
+     * Note : a value of -1 means no linger used on close.
+     */
+    private int connectionLinger = -1;
+
+
+    /**
+     * The port number on which we listen for ajp13 requests.
+     */
+    private int port = 8009;
+
+
+    /**
+     * The set of processors that have been created but are not currently
+     * being used to process a request.
+     */
+    private Stack processors = new Stack();
+
+
+    /**
+     * The request scheme that will be set on all requests received
+     * through this connector.
+     */
+    private String scheme = "http";
+
+
+    /**
+     * The secure connection flag that will be set on all requests received
+     * through this connector.
+     */
+    private boolean secure = false;
+
+
+    /**
+     * The server socket through which we listen for incoming TCP connections.
+     */
+    private ServerSocket serverSocket = null;
+
+
+    /**
+     * The string manager for this package.
+     */
+    private StringManager sm =
+	StringManager.getManager(Constants.PACKAGE);
+
+
+    /**
+     * Has this component been started yet?
+     */
+    private boolean started = false;
+
+
+    /**
+     * The shutdown signal to our background thread
+     */
+    private boolean stopped = false;
+
+
+    /**
+     * The background thread.
+     */
+    private Thread thread = null;
+
+
+    /**
+     * This connector's thread group.
+     */
+    private ThreadGroup threadGroup = null;
+
+
+    /**
+     * The name to register for the background thread.
+     */
+    private String threadName = null;
+
+
+    /**
+     * A thread that periodically logs debug info if debug > 0.
+     */
+    private DebugThread debugThread = null;
+
+
+    /**
+     * The thread synchronization object.
+     */
+    private Object threadSync = new Object();
+
+    private Ajp13Logger logger = new Ajp13Logger();
+
+    /**
+     * The service which which the connector is associated
+     */
+    private Service service = null;
+
+    private String secret = null;
+
+
+    /**
+     * Tomcat authentication flag. If true, the authnetication is done by
+     * Tomcat, otherwise, it is done by the native webserver.
+     */
+    private boolean tomcatAuthentication = true;
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * Return the connection timeout for this Connector.
+     */
+    public int getConnectionTimeout() {
+
+	return (connectionTimeout);
+
+    }
+
+
+    /**
+     * Set the connection timeout for this Connector.
+     *
+     * @param connectionTimeout The new connection timeout
+     */
+    public void setConnectionTimeout(int connectionTimeout) {
+
+	this.connectionTimeout = connectionTimeout;
+
+    }
+
+    /**
+     * Return the connection linger settings for this Connector.
+     */
+    public int getConnectionLinger() {
+
+	return (connectionLinger);
+
+    }
+
+
+    /**
+     * Set the connection linger for this Connector.
+     *
+     * @param connectionLinger The new connection linger
+     */
+    public void setConnectionLinger(int connectionLinger) {
+
+	this.connectionLinger = connectionLinger;
+
+    }
+
+    public void setSecret( String s ) {
+        secret=s;
+    }
+
+    public String getSecret() {
+        return secret;
+    }
+    
+
+    /**
+     * Return the accept count for this Connector.
+     */
+    public int getAcceptCount() {
+
+	return (acceptCount);
+
+    }
+
+
+    /**
+     * Set the accept count for this Connector.
+     *
+     * @param count The new accept count
+     */
+    public void setAcceptCount(int count) {
+
+	this.acceptCount = count;
+
+    }
+
+
+
+    /**
+     * Return the bind IP address for this Connector.
+     */
+    public String getAddress() {
+
+	return (this.address);
+
+    }
+
+
+    /**
+     * Set the bind IP address for this Connector.
+     *
+     * @param address The bind IP address
+     */
+    public void setAddress(String address) {
+
+	this.address = address;
+
+    }
+
+
+    /**
+     * Is this connector available for processing requests?
+     */
+    public boolean isAvailable() {
+
+	return (started);
+
+    }
+
+
+    /**
+     * Return the input buffer size for this Connector.
+     */
+    public int getBufferSize() {
+
+	return (this.bufferSize);
+
+    }
+
+
+    /**
+     * Set the input buffer size for this Connector.
+     *
+     * @param bufferSize The new input buffer size.
+     */
+    public void setBufferSize(int bufferSize) {
+
+	this.bufferSize = bufferSize;
+
+    }
+
+
+    /**
+     * Return the Container used for processing requests received by this
+     * Connector.
+     */
+    public Container getContainer() {
+
+	return (container);
+
+    }
+
+
+    /**
+     * Set the Container used for processing requests received by this
+     * Connector.
+     *
+     * @param container The new Container to use
+     */
+    public void setContainer(Container container) {
+
+	this.container = container;
+
+    }
+
+
+    /**
+     * Return the current number of processors that have been created.
+     */
+    public int getCurProcessors() {
+
+	return (curProcessors);
+
+    }
+
+
+    /**
+     * Return the debugging detail level for this component.
+     */
+    public int getDebug() {
+
+        return (debug);
+
+    }
+
+
+    /**
+     * Set the debugging detail level for this component.
+     *
+     * @param debug The new debugging detail level
+     */
+    public void setDebug(int debug) {
+
+        this.debug = debug;
+
+    }
+
+    /**
+     * Return the "enable DNS lookups" flag.
+     */
+    public boolean getEnableLookups() {
+        return this.enableLookups;
+    }
+
+    /**
+     * Set the "enable DNS lookups" flag.
+     *
+     * @param enableLookups The new "enable DNS lookups" flag value
+     */
+    public void setEnableLookups(boolean enableLookups) {
+        this.enableLookups = enableLookups;
+    }
+
+    /**
+     * Return the port number to which a request should be redirected if
+     * it comes in on a non-SSL port and is subject to a security constraint
+     * with a transport guarantee that requires SSL.
+     */
+    public int getRedirectPort() {
+        return this.redirectPort;
+    }
+
+
+    /**
+     * Set the redirect port number.
+     *
+     * @param redirectPort The redirect port number (non-SSL to SSL)
+     */
+    public void setRedirectPort(int redirectPort) {
+        this.redirectPort = redirectPort;
+    }
+
+    /**
+     * Return the server socket factory used by this Container.
+     */
+    public ServerSocketFactory getFactory() {
+
+        if (this.factory == null) {
+            synchronized (this) {
+                this.factory = new DefaultServerSocketFactory();
+            }
+        }
+        return (this.factory);
+
+    }
+
+
+    /**
+     * Set the server socket factory used by this Container.
+     *
+     * @param factory The new server socket factory
+     */
+    public void setFactory(ServerSocketFactory factory) {
+
+        this.factory = factory;
+
+    }
+
+
+    /**
+     * Return descriptive information about this Connector implementation.
+     */
+    public String getInfo() {
+
+	return (info);
+
+    }
+
+
+    /**
+     * Return the minimum number of processors to start at initialization.
+     */
+    public int getMinProcessors() {
+
+	return (minProcessors);
+
+    }
+
+
+    /**
+     * Set the minimum number of processors to start at initialization.
+     *
+     * @param minProcessors The new minimum processors
+     */
+    public void setMinProcessors(int minProcessors) {
+
+	this.minProcessors = minProcessors;
+
+    }
+
+
+    /**
+     * Return the maximum number of processors allowed, or <0 for unlimited.
+     */
+    public int getMaxProcessors() {
+
+	return (maxProcessors);
+
+    }
+
+
+    /**
+     * Set the maximum number of processors allowed, or <0 for unlimited.
+     *
+     * @param maxProcessors The new maximum processors
+     */
+    public void setMaxProcessors(int maxProcessors) {
+
+	this.maxProcessors = maxProcessors;
+
+    }
+
+
+    /**
+     * Return the port number on which we listen for AJP13 requests.
+     */
+    public int getPort() {
+
+	return (this.port);
+
+    }
+
+
+    /**
+     * Set the port number on which we listen for AJP13 requests.
+     *
+     * @param port The new port number
+     */
+    public void setPort(int port) {
+
+	this.port = port;
+
+    }
+
+
+    /**
+     * Return the scheme that will be assigned to requests received
+     * through this connector.  Default value is "http".
+     */
+    public String getScheme() {
+
+	return (this.scheme);
+
+    }
+
+
+    /**
+     * Set the scheme that will be assigned to requests received through
+     * this connector.
+     *
+     * @param scheme The new scheme
+     */
+    public void setScheme(String scheme) {
+
+	this.scheme = scheme;
+
+    }
+
+
+    /**
+     * Return the secure connection flag that will be assigned to requests
+     * received through this connector.  Default value is "false".
+     */
+    public boolean getSecure() {
+
+	return (this.secure);
+
+    }
+
+
+    /**
+     * Set the secure connection flag that will be assigned to requests
+     * received through this connector.
+     *
+     * @param secure The new secure connection flag
+     */
+    public void setSecure(boolean secure) {
+
+	this.secure = secure;
+
+    }
+
+
+    /**
+     * Returns the <code>Service</code> with which we are associated.
+     */
+    public Service getService() {
+	return service;
+    }
+
+
+    /**
+     * Set the <code>Service</code> with which we are associated.
+     */
+    public void setService(Service service) {
+	this.service = service;
+    }
+
+
+    /**
+     * Get the value of the tomcatAuthentication flag.
+     */
+    public boolean getTomcatAuthentication() {
+        return tomcatAuthentication;
+    }
+
+
+    /**
+     * Set the value of the tomcatAuthentication flag.
+     */
+    public void setTomcatAuthentication(boolean tomcatAuthentication) {
+        this.tomcatAuthentication = tomcatAuthentication;
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Create (or allocate) and return a Request object suitable for
+     * specifying the contents of a Request to the responsible Container.
+     */
+    public Request createRequest() {
+
+	Ajp13Request request = new Ajp13Request(this);
+	request.setConnector(this);
+	return (request);
+
+    }
+
+
+    /**
+     * Create (or allocate) and return a Response object suitable for
+     * receiving the contents of a Response from the responsible Container.
+     */
+    public Response createResponse() {
+
+	Ajp13Response response = new Ajp13Response();
+	response.setConnector(this);
+	return (response);
+
+    }
+
+    /**
+     * Invoke a pre-startup initialization. This is used to allow connectors
+     * to bind to restricted ports under Unix operating environments.
+     * ServerSocket (we start as root and change user? or I miss something?).
+     */
+    public void initialize() throws LifecycleException {
+    }
+
+
+    // -------------------------------------------------------- Package Methods
+
+
+    /**
+     * Recycle the specified Processor so that it can be used again.
+     *
+     * @param processor The processor to be recycled
+     */
+    void recycle(Ajp13Processor processor) {
+
+        synchronized(processors) {
+            if (debug > 0) {
+                logger.log("added processor to available processors, available="
+                           + processors.size());
+            }
+            processors.push(processor);
+        }
+
+    }
+
+
+    // -------------------------------------------------------- Private Methods
+
+
+    /**
+     * Create (or allocate) and return an available processor for use in
+     * processing a specific AJP13 request, if possible.  If the maximum
+     * allowed processors have already been created and are in use, return
+     * <code>null</code> instead.
+     */
+    private Ajp13Processor createProcessor() {
+
+	synchronized (processors) {
+	    if (processors.size() > 0)
+		return ((Ajp13Processor) processors.pop());
+	    if ((maxProcessors > 0) && (curProcessors < maxProcessors))
+	        return (newProcessor());
+	    else
+	        return (null);
+	}
+
+    }
+
+
+    /**
+     * Create and return a new processor suitable for processing AJP13
+     * requests and returning the corresponding responses.
+     */
+    private Ajp13Processor newProcessor() {
+
+        Ajp13Processor processor = new Ajp13Processor(this, curProcessors++, threadGroup);
+	if (processor instanceof Lifecycle) {
+	    try {
+	        ((Lifecycle) processor).start();
+	    } catch (LifecycleException e) {
+	        logger.log("newProcessor", e);
+                curProcessors--;
+	        return (null);
+	    }
+	}
+	created.addElement(processor);
+	return (processor);
+
+    }
+
+
+    /**
+     * Open and return the server socket for this Connector.  If an IP
+     * address has been specified, the socket will be opened only on that
+     * address; otherwise it will be opened on all addresses.
+     *
+     * @exception IOException if an input/output error occurs
+     */
+    private ServerSocket open() throws IOException {
+
+        // Acquire the server socket factory for this Connector
+        ServerSocketFactory factory = getFactory();
+
+	// If no address is specified, open a connection on all addresses
+        if (address == null) {
+	    logger.log(sm.getString("ajp13Connector.allAddresses"));
+            try {
+		return (factory.createSocket(port, acceptCount));
+	    } catch(Exception ex ) {
+		ex.printStackTrace();
+		return null;
+	    }
+	}
+
+	// Open a server socket on the specified address
+        try {
+            InetAddress is = InetAddress.getByName(address);
+	    logger.log(sm.getString("ajp13Connector.anAddress", address));
+            return (factory.createSocket(port, acceptCount, is));
+	} catch (Exception e) {
+	    try {
+		logger.log(sm.getString("ajp13Connector.noAddress", address));
+		return (factory.createSocket(port, acceptCount));
+	    } catch( Exception e1 ) {
+		e1.printStackTrace();
+		return null;
+	    }
+	}
+
+    }
+
+
+    // ---------------------------------------------- Background Thread Methods
+
+
+    /**
+     * The background thread that listens for incoming TCP/IP connections and
+     * hands them off to an appropriate processor.
+     */
+    public void run() {
+
+        // Loop until we receive a shutdown command
+	while (!stopped) {
+
+	    // Accept the next incoming connection from the server socket
+	    Socket socket = null;
+	    try {
+                if (debug > 0) {
+                    logger.log("accepting socket...");
+                }
+                
+		socket = serverSocket.accept();
+
+                if (debug > 0) {
+                    logger.log("accepted socket, assigning to processor.");
+                }
+                
+                /* Warning :
+                 * 
+                 * To be able to close more quickly a connection, it's recommanded
+                 * to set linger to a small value.
+                 * 
+                 * AJP13 connection SHOULD be closed under webserver responsability and 
+                 * in such case it's safe to close socket on Tomcat side without delay,
+                 * which may be also the case for HTTP connectors.
+                 * 
+                 * I (henri) recommand to set Linger to 0, making socket closed immediatly
+                 * so the OS will free faster the underlying io descriptor and resources.
+                 * It's very important under heavy load !
+                 */
+                
+                if (connectionLinger < 0)
+                	socket.setSoLinger(false, 0);
+                else	
+                	socket.setSoLinger(true, connectionLinger);
+                	
+                /* We don't need it since it's the native side which 
+                 * will set the connection with keep alive
+                 * if specified in workers.properties.
+                 * 
+                 * socket.setKeepAlive(true); 
+                 */
+                
+                /* Warning :
+                 * 
+                 * AJP13 shouldn't use socket timeout on tomcat site since
+                 * when Tomcat close a connection after a timeout is reached
+                 * the socket stay in half-closed state until the webserver
+                 * try to send a request to tomcat and detect the socket close
+                 * when it will try to read the reply.
+                 * 
+                 * On many Unix platforms the write() call didn't told
+                 * webserver that the socket is closed.
+                 */
+                 
+                if (connectionTimeout >= 0) {
+                    socket.setSoTimeout(connectionTimeout);
+                }
+            } catch (AccessControlException ace) {
+                logger.log("socket accept security exception: "
+                           + ace.getMessage());
+                continue;
+	    } catch (IOException e) {
+		if (started && !stopped)
+		    logger.log("accept: ", e);
+		try {
+                    if (serverSocket != null) {
+                        serverSocket.close();
+                    }
+                    if (stopped) {
+                        if (debug > 0) {
+                            logger.log("run():  stopped, so breaking");
+                        }
+                        break;
+                    } else {
+                        if (debug > 0) {
+                            logger.log("run():  not stopped, " +
+                                       "so reopening server socket");
+                        }
+                        serverSocket = open();
+                    }
+                } catch (IOException ex) {
+                    // If reopening fails, exit
+                    logger.log("socket reopen: ", ex);
+                    break;
+                }
+                continue;
+	    }
+
+	    // Hand this socket off to an appropriate processor
+            if (debug > 0) {
+                synchronized(processors) {
+                    logger.log("about to create a processor, available="
+                               + processors.size() + ", created=" + created.size()
+                               + ", maxProcessors=" + maxProcessors);
+                }
+            }
+	    Ajp13Processor processor = createProcessor();
+	    if (processor == null) {
+		try {
+		    logger.log(sm.getString("ajp13Connector.noProcessor"));
+		    socket.close();
+		} catch (IOException e) {
+		    ;
+		}
+		continue;
+	    }
+	    processor.assign(socket);
+
+	    // The processor will recycle itself when it finishes
+
+	}
+
+	// Notify the threadStop() method that we have shut ourselves down
+	synchronized (threadSync) {
+	    threadSync.notifyAll();
+	}
+
+    }
+
+
+    /**
+     * Start the background processing thread.
+     */
+    private void threadStart() {
+
+	logger.log(sm.getString("ajp13Connector.starting"));
+
+	thread = new Thread(threadGroup, this, threadName);
+	thread.setDaemon(true);
+	thread.start();
+
+    }
+
+
+    /**
+     * Stop the background processing thread.
+     */
+    private void threadStop() {
+
+	logger.log(sm.getString("ajp13Connector.stopping"));
+
+	stopped = true;
+	synchronized (threadSync) {
+	    try {
+		threadSync.wait(5000);
+	    } catch (InterruptedException e) {
+		;
+	    }
+	}
+	thread = null;
+
+    }
+
+
+    // ------------------------------------------------------ Lifecycle Methods
+
+
+    /**
+     * Add a lifecycle event listener to this component.
+     *
+     * @param listener The listener to add
+     */
+    public void addLifecycleListener(LifecycleListener listener) {
+
+	lifecycle.addLifecycleListener(listener);
+
+    }
+
+    /**
+     * Get the lifecycle listeners associated with this lifecycle. If this
+     * Lifecycle has no listeners registered, a zero-length array is returned.
+     */
+    public LifecycleListener[] findLifecycleListeners() {
+        return null; // FIXME: lifecycle.findLifecycleListeners();
+    }
+
+
+    /**
+     * Remove a lifecycle event listener from this component.
+     *
+     * @param listener The listener to add
+     */
+    public void removeLifecycleListener(LifecycleListener listener) {
+
+	lifecycle.removeLifecycleListener(listener);
+
+    }
+
+
+    /**
+     * Begin processing requests via this Connector.
+     *
+     * @exception LifecycleException if a fatal startup error occurs
+     */
+    public void start() throws LifecycleException {
+
+	// Validate and update our current state
+	if (started)
+	    throw new LifecycleException
+		(sm.getString("ajp13Connector.alreadyStarted"));
+
+        if (debug > 0) {
+            debugThread = new DebugThread();
+            debugThread.setDaemon(true);
+            debugThread.start();
+        }
+
+        threadName = "Ajp13Connector[" + port + "]";
+        threadGroup = new ThreadGroup(threadName);
+        threadGroup.setDaemon(true);
+        logger.setConnector(this);
+        logger.setName(threadName);
+	lifecycle.fireLifecycleEvent(START_EVENT, null);
+	started = true;
+
+	// Establish a server socket on the specified port
+	try {
+	    serverSocket = open();
+	} catch (IOException e) {
+	    throw new LifecycleException(threadName + ".open", e);
+	}
+
+	// Start our background thread
+	threadStart();
+
+	// Create the specified minimum number of processors
+	while (curProcessors < minProcessors) {
+	    if ((maxProcessors > 0) && (curProcessors >= maxProcessors))
+		break;
+	    Ajp13Processor processor = newProcessor();
+	    recycle(processor);
+	}
+
+    }
+
+
+    /**
+     * Terminate processing requests via this Connector.
+     *
+     * @exception LifecycleException if a fatal shutdown error occurs
+     */
+    public void stop() throws LifecycleException {
+
+	// Validate and update our current state
+	if (!started)
+	    throw new LifecycleException
+		(sm.getString("ajp13Connector.notStarted"));
+	lifecycle.fireLifecycleEvent(STOP_EVENT, null);
+	started = false;
+
+	// Gracefully shut down all processors we have created
+	for (int i = created.size() - 1; i >= 0; i--) {
+	    Ajp13Processor processor = (Ajp13Processor) created.elementAt(i);
+	    if (processor instanceof Lifecycle) {
+		try {
+		    ((Lifecycle) processor).stop();
+		} catch (LifecycleException e) {
+		    logger.log("Ajp13Connector.stop", e);
+		}
+	    }
+	}
+
+	// Stop our background thread
+	threadStop();
+
+	// Close the server socket we were using
+	if (serverSocket != null) {
+	    try {
+		serverSocket.close();
+	    } catch (IOException e) {
+		;
+	    }
+	    serverSocket = null;
+	}
+
+    }
+
+    /**
+     * Debugging thread used to debug thread activity in this
+     * connector.
+     */
+    private class DebugThread extends Thread
+    {
+        public void run() {
+            while (true) {
+                try {
+                    sleep(60 * 1000);
+                } catch (InterruptedException e) {
+                    break;
+                }
+                logger.log("active threads=" + threadGroup.activeCount());
+                System.out.println("===================================");
+                System.out.println("Ajp13Connector active threads="
+                                   + threadGroup.activeCount());
+                threadGroup.list();
+                System.out.println("===================================");
+            }
+        }
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/ajp/tomcat4/Ajp13InputStream.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/ajp/tomcat4/Ajp13InputStream.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/ajp/tomcat4/Ajp13InputStream.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,66 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.ajp.tomcat4;
+
+import java.io.IOException;
+
+import javax.servlet.ServletInputStream;
+
+import org.apache.ajp.Ajp13;
+
+public class Ajp13InputStream extends ServletInputStream {
+
+    private Ajp13 ajp13;
+
+    Ajp13InputStream(Ajp13 ajp13) {
+        this.ajp13 = ajp13;
+    }
+
+    public int available() throws IOException {
+        return ajp13.available();
+    }
+
+    public void close() throws IOException {
+    }
+
+    public void mark(int readLimit) {
+    }
+
+    public boolean markSupported() {
+        return false;
+    }
+
+    public void reset() throws IOException {
+        throw new IOException("reset() not supported");
+    }
+
+    public int read() throws IOException {
+        return ajp13.doRead();
+    }
+
+    public int read(byte[] b, int off, int len) throws IOException {
+        return ajp13.doRead(b, off, len);
+    }
+
+    public long skip(long n) throws IOException {
+        if (n > Integer.MAX_VALUE) {
+            throw new IOException("can't skip than many:  " + n);
+        }
+        byte[] b = new byte[(int)n];
+        return ajp13.doRead(b, 0, b.length);
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/ajp/tomcat4/Ajp13Logger.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/ajp/tomcat4/Ajp13Logger.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/ajp/tomcat4/Ajp13Logger.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,87 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.ajp.tomcat4;
+
+import org.apache.catalina.Logger;
+
+class Ajp13Logger {
+
+    private String name = null;
+    private Ajp13Connector connector = null;
+    private boolean logStackTrace = false;
+    
+    Ajp13Logger() {
+        name = toString();
+    }
+
+    void setConnector(Ajp13Connector connector) {
+        this.connector = connector;
+    }
+
+    void setName(String name) {
+        this.name = name;
+    }
+
+    /**
+     * Log a message on the Logger associated with our Container (if any)
+     *
+     * @param message Message to be logged
+     */
+    void log(String message) {
+
+        if (logStackTrace) {
+            log(message, new Throwable());
+        } else {
+            Logger logger = getLogger();
+            
+            if (logger != null)
+                logger.log(name + " " + message);
+            else
+                System.out.println(name + " " + message);
+        }
+    }
+
+    /**
+     * Log a message on the Logger associated with our Container (if any)
+     *
+     * @param message Message to be logged
+     * @param throwable Associated exception
+     */
+    void log(String message, Throwable throwable) {
+
+        Logger logger = getLogger();
+
+	if (logger != null)
+	    logger.log(name + " " + message, throwable);
+	else {
+	    System.out.println(name + " " + message);
+	    throwable.printStackTrace(System.out);
+	}
+
+    }
+
+    private Logger getLogger() {
+
+        if (connector != null) {
+            return connector.getContainer().getLogger();
+        } else {
+            return null;
+        }
+
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/ajp/tomcat4/Ajp13OutputStream.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/ajp/tomcat4/Ajp13OutputStream.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/ajp/tomcat4/Ajp13OutputStream.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,46 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.ajp.tomcat4;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+import org.apache.ajp.Ajp13;
+
+public class Ajp13OutputStream extends OutputStream {
+
+    private Ajp13 ajp13;
+    
+    Ajp13OutputStream(Ajp13 ajp13) {
+        this.ajp13 = ajp13;
+    }
+
+    public void write(int b) throws IOException {
+        byte[] bb = new byte[]{(byte)b};
+        ajp13.doWrite(bb, 0, 1);
+    }
+
+    public void write(byte[] b, int off, int len) throws IOException {
+        ajp13.doWrite(b, off, len);
+    }
+
+    public void close() throws IOException {
+    }
+
+    public void flush() throws IOException {
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/ajp/tomcat4/Ajp13Processor.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/ajp/tomcat4/Ajp13Processor.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/ajp/tomcat4/Ajp13Processor.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,666 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.ajp.tomcat4;
+
+
+import java.io.IOException;
+import java.net.Socket;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.ajp.Ajp13;
+import org.apache.catalina.Lifecycle;
+import org.apache.catalina.LifecycleException;
+import org.apache.catalina.LifecycleListener;
+import org.apache.catalina.util.LifecycleSupport;
+import org.apache.catalina.util.StringManager;
+import org.apache.tomcat.util.http.BaseRequest;
+
+/**
+ * @author Kevin Seguin
+ * @version $Revision: 299218 $ $Date: 2004-02-24 02:48:44 -0600 (Tue, 24 Feb 2004) $
+ */
+
+final class Ajp13Processor
+    implements Lifecycle, Runnable {
+
+    /**
+     * A simple class to provide synchronized access
+     * to a boolean.
+     */
+    private class Bool {
+
+        private boolean b = false;
+
+        Bool() {
+        }
+        
+        Bool(boolean b) {
+            this.b = b;
+        }
+
+        synchronized boolean value() {
+            return b;
+        }
+
+        synchronized void set(boolean b) {
+            this.b = b;
+        }
+    }
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Construct a new Ajp13Processor associated with the specified connector.
+     *
+     * @param connector Ajp13Connector that owns this processor
+     * @param id Identifier of this Ajp13Processor (unique per connector)
+     * @param threadGroup The thread group any threads created by the processor
+     *        should be in.
+     */
+    public Ajp13Processor(Ajp13Connector connector,
+                          int id,
+                          ThreadGroup threadGroup) {
+
+	super();
+	this.connector = connector;
+	this.debug = connector.getDebug();
+	this.id = id;
+	this.request = (Ajp13Request) connector.createRequest();
+        this.request.setConnector(connector);
+        this.request.setConnector(connector);
+	this.response = (Ajp13Response) connector.createResponse();
+        this.response.setConnector(connector);
+	this.threadName =
+	  "Ajp13Processor[" + connector.getPort() + "][" + id + "]";
+        this.threadGroup = threadGroup;
+
+        this.logger.setConnector(connector);
+        this.logger.setName(this.threadName);
+    }
+
+
+    // ----------------------------------------------------- Instance Variables
+
+    private Ajp13Logger logger = new Ajp13Logger();
+    private BaseRequest ajpRequest = new BaseRequest();
+
+    /**
+     * Is there a new socket available?
+     */
+    private boolean available = false;
+
+
+    /**
+     * The Ajp13Connector with which this processor is associated.
+     */
+    private Ajp13Connector connector = null;
+
+
+    /**
+     * The debugging detail level for this component.
+     */
+    private int debug = 0;
+
+
+    /**
+     * The identifier of this processor, unique per connector.
+     */
+    private int id = 0;
+
+
+    /**
+     * The lifecycle event support for this component.
+     */
+    private LifecycleSupport lifecycle = new LifecycleSupport(this);
+
+
+    /**
+     * The AJP13 request object we will pass to our associated container.
+     */
+    private Ajp13Request request = null;
+
+
+    /**
+     * The AJP13 response object we will pass to our associated container.
+     */
+    private Ajp13Response response = null;
+
+
+    /**
+     * The string manager for this package.
+     */
+    protected StringManager sm =
+	StringManager.getManager(Constants.PACKAGE);
+
+
+    /**
+     * The socket we are currently processing a request for.  This object
+     * is used for inter-thread communication only.
+     */
+    private Socket socket = null;
+
+
+    /**
+     * Has this component been started yet?
+     */
+    private boolean started = false;
+
+
+    /**
+     * The shutdown signal to our background thread
+     */
+    private Bool stopped = new Bool(true);
+
+    /**
+     * Are we currently handling a request?
+     */
+    private Bool handlingRequest = new Bool(false);
+
+
+    /**
+     * The background thread.
+     */
+    private Thread thread = null;
+
+
+    /**
+     * The name to register for the background thread.
+     */
+    private String threadName = null;
+
+
+    /**
+     * This processor's thread group.
+     */
+    private ThreadGroup threadGroup = null;
+
+
+    /**
+     * The thread synchronization object.
+     */
+    private Object threadSync = new Object();
+
+
+
+    // -------------------------------------------------------- Package Methods
+
+
+    /**
+     * Process an incoming TCP/IP connection on the specified socket.  Any
+     * exception that occurs during processing must be logged and swallowed.
+     * <b>NOTE</b>:  This method is called from our Connector's thread.  We
+     * must assign it to our own thread so that multiple simultaneous
+     * requests can be handled.
+     *
+     * @param socket TCP socket to process
+     */
+    synchronized void assign(Socket socket) {
+
+        // Wait for the Processor to get the previous Socket
+        while (available) {
+	    try {
+	        wait();
+	    } catch (InterruptedException e) {
+	    }
+        }
+
+	// Store the newly available Socket and notify our thread
+	this.socket = socket;
+	available = true;
+	notifyAll();
+
+	if ((debug > 0) && (socket != null))
+	    logger.log(" An incoming request is being assigned");
+
+    }
+
+
+    // -------------------------------------------------------- Private Methods
+
+
+    /**
+     * Await a newly assigned Socket from our Connector, or <code>null</code>
+     * if we are supposed to shut down.
+     */
+    private synchronized Socket await() {
+
+        // Wait for the Connector to provide a new Socket
+        while (!available) {
+	    try {
+	        wait();
+	    } catch (InterruptedException e) {
+	    }
+        }
+
+	// Notify the Connector that we have received this Socket
+	Socket socket = this.socket;
+	available = false;
+	notifyAll();
+
+	if ((debug > 0) && (socket != null))
+	    logger.log("  The incoming request has been awaited");
+
+	return (socket);
+
+    }
+
+    /**
+     * Parse and record the connection parameters related to this request.
+     *
+     * @param socket The socket on which we are connected
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception ServletException if a parsing error occurs
+     */
+    private void parseConnection(Socket socket)
+        throws IOException, ServletException {
+
+	if (debug > 1)
+	    logger.log("  parseConnection: address=" + socket.getInetAddress() +
+		", port=" + connector.getPort());
+	request.setServerPort(connector.getPort());
+        request.setSocket(socket);
+
+    }
+
+    /**
+     * Process an incoming AJP13 request on the Socket that has been assigned
+     * to this Processor.  Any exceptions that occur during processing must be
+     * swallowed and dealt with.
+     *
+     * @param socket The socket on which we are connected to the client
+     */
+    private void process(Socket socket) {
+
+        Ajp13 ajp13 = new Ajp13();
+        ajp13.setDebug(debug);
+        ajp13.setLogger(new org.apache.ajp.Logger() {
+                public void log(String msg) {
+                    logger.log("[Ajp13] " + msg);
+                }
+                
+                public void log(String msg, Throwable t) {
+                    logger.log("[Ajp13] " + msg, t);
+                }
+            });
+
+        Ajp13InputStream input = new Ajp13InputStream(ajp13);
+        Ajp13OutputStream output = new Ajp13OutputStream(ajp13);
+        response.setAjp13(ajp13);
+
+        try {
+            ajp13.setSocket(socket);
+        } catch (IOException e) {
+            logger.log("process: ajp13.setSocket", e);
+        }
+
+        boolean moreRequests = true;
+        String expectedSecret=connector.getSecret();
+        
+        boolean needAuth= ( expectedSecret != null );
+        
+        while (moreRequests && !stopped.value()) {
+            
+            int status = 0;
+            try {
+                if (debug > 0) {
+                    logger.log("waiting on next request...");
+                }
+                
+                status = ajp13.receiveNextRequest(ajpRequest);
+                
+                if (debug > 0) {
+                    logger.log("received next request, status=" + status);
+                }
+            } catch (IOException e) {
+                logger.log("process: ajp13.receiveNextRequest", e);
+            }
+
+            if( needAuth ) {
+                String connSecret=ajp13.getSecret();
+                if( connSecret == null ) {
+                    logger.log( "Connection without password, " +
+                                "tomcat is configured to require one" );
+                    break;
+                }
+                if( ! connSecret.equals(expectedSecret) ) {
+                    logger.log( "Connection with wrong password" );
+                    break;
+                }
+                
+                needAuth=false;
+            }
+            
+            if (stopped.value()) {
+                if (debug > 0) {
+                    logger.log("process:  received request, but we're stopped");
+                }
+                break;
+            }
+            
+            if( status==-2) {
+                // special case - shutdown
+                // XXX need better communication, refactor it
+//                  if( !doShutdown(socket.getLocalAddress(),
+//                                  socket.getInetAddress())) {
+//                      moreRequests = false;
+//                      continue;
+//                  }
+                break;
+            }
+            
+			// Allready handled by low level proto, don't go farther
+			if( status == 999 )
+			{
+				ajpRequest.recycle();
+				request.recycle();
+
+				// recycle ajp13 object
+				ajp13.recycle();
+
+				continue;
+			}
+
+			if( status != 200 )
+				break;
+
+            try {
+                // set flag
+                handlingRequest.set(true);
+
+                boolean bad_request = false;
+
+                // set up request
+                try {
+                    request.setAjpRequest(ajpRequest);
+                } catch (IllegalArgumentException e) {
+                    bad_request = true;
+                }
+                request.setResponse(response);
+                request.setStream(input);
+                
+                // setup response
+                response.setRequest(request);
+                response.setStream(output);
+                
+                if (debug > 0) {
+                    logger.log("invoking...");
+                }
+
+                if (!bad_request) {
+                    try {
+                        connector.getContainer().invoke(request, response);
+                    } catch (IOException ioe) {
+                        // Pass the IOException through
+                        throw ioe;
+                    } catch (Throwable e) {
+                        // A throwable here could be caused by a Valve,
+                        // Filter, or other component in the chain.
+                        // Processing of the request failed, return an
+                        // Internal Server Error
+                        logger.log("process: invoke", e);
+                        response.sendError
+                            (HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
+                    }
+                } else {
+                    response.sendError
+                        (HttpServletResponse.SC_BAD_REQUEST);
+                }
+
+                if (debug > 0) {
+                    logger.log("done invoking, finishing request/response....");
+                }
+
+                response.finishResponse();
+                request.finishRequest();
+
+                if (debug > 0) {
+                    logger.log("finished handling request.");
+                }
+
+            } catch (IOException ioe) {
+                // Normally this catches a socket Broken Pipe caused by the
+                // remote client aborting the request. Don't print the stack
+                // trace in this case. Then let the Processor recycle.
+                logger.log("process: IOException " + ioe.getMessage());
+                moreRequests = false;
+            } catch (Throwable e) {
+                // Processing the request and sending the response failed.
+                // We don't know what the state of the Ajp Connector socket
+                // is in. Bail out and recycle the Processor.
+                logger.log("process: finish", e);
+                moreRequests = false;
+            }
+
+            // Recycling the request and the response objects
+            if (debug > 0) {
+                logger.log("recyling objects ...");
+            }
+            
+            ajpRequest.recycle();
+            request.recycle();
+            response.recycle();
+
+            // recycle ajp13 object
+            ajp13.recycle();
+
+            // reset flag
+            handlingRequest.set(false);
+        }
+        
+	try {
+            if (debug > 0) {
+                logger.log("closing ajp13 object...");
+            }
+
+            ajp13.close();
+
+            if (debug > 0) {
+                logger.log("ajp13 object closed.");
+            }
+	} catch (IOException e) {
+	    logger.log("process: ajp13.close", e);
+	}
+
+	try {
+            if (debug > 0) {
+                logger.log("closing socket...");
+            }
+
+            socket.close();
+
+            if (debug > 0) {
+                logger.log("socket closed.");
+            }
+	} catch (IOException e) {
+	    logger.log("process: socket.close", e);
+	}
+	socket = null;
+
+        if (debug > 0) {
+            logger.log("process:  done");
+        }
+    }
+
+
+    // ---------------------------------------------- Background Thread Methods
+
+
+    /**
+     * The background thread that listens for incoming TCP/IP connections and
+     * hands them off to an appropriate processor.
+     */
+    public void run() {
+
+        // Process requests until we receive a shutdown signal
+	while (!stopped.value()) {
+
+	    // Wait for the next socket to be assigned
+            if (debug > 0) {
+                logger.log("waiting for next socket to be assigned...");
+            }
+	    Socket socket = await();
+	    if (socket == null)
+		continue;
+
+            if (debug > 0) {
+                logger.log("socket assigned.");
+            }
+
+	    // Process the request from this socket
+	    process(socket);
+
+	    // Finish up this request
+            if (debug > 0) {
+                logger.log("recycling myself ...");
+            }
+	    connector.recycle(this);
+	}
+
+	// Tell threadStop() we have shut ourselves down successfully
+	synchronized (threadSync) {
+	    threadSync.notifyAll();
+	}
+
+    }
+
+
+    /**
+     * Start the background processing thread.
+     */
+    private void threadStart() {
+
+	logger.log(sm.getString("ajp13Processor.starting"));
+
+        stopped.set(false);
+	thread = new Thread(threadGroup, this, threadName);
+	thread.setDaemon(true);
+	thread.start();
+
+	if (debug > 0)
+	    logger.log(" Background thread has been started");
+
+    }
+
+
+    /**
+     * Stop the background processing thread.
+     */
+    private void threadStop() {
+
+	logger.log(sm.getString("ajp13Processor.stopping"));
+
+	stopped.set(true);
+        assign(null);
+	synchronized (threadSync) {
+	    try {
+                if (handlingRequest.value()) {
+                    if (debug > 0) {
+                        logger.log
+                            ("currentling handling a request, so waiting....");
+                    }
+                    threadSync.wait(5000);
+                } else {
+                    if (debug > 0) {
+                        logger.log
+                            ("not currently handling a request, not waiting.");
+                    }
+                }
+	    } catch (InterruptedException e) {
+		;
+	    }
+	}
+	thread = null;
+
+    }
+
+
+    // ------------------------------------------------------ Lifecycle Methods
+
+
+    /**
+     * Add a lifecycle event listener to this component.
+     *
+     * @param listener The listener to add
+     */
+    public void addLifecycleListener(LifecycleListener listener) {
+
+	lifecycle.addLifecycleListener(listener);
+
+    }
+
+    /**
+     * Get the lifecycle listeners associated with this lifecycle. If this
+     * Lifecycle has no listeners registered, a zero-length array is returned.
+     */
+    public LifecycleListener[] findLifecycleListeners() {
+        return null; // FIXME: lifecycle.findLifecycleListeners();
+    }
+
+
+    /**
+     * Remove a lifecycle event listener from this component.
+     *
+     * @param listener The listener to add
+     */
+    public void removeLifecycleListener(LifecycleListener listener) {
+
+	lifecycle.removeLifecycleListener(listener);
+
+    }
+
+
+    /**
+     * Start the background thread we will use for request processing.
+     *
+     * @exception LifecycleException if a fatal startup error occurs
+     */
+    public void start() throws LifecycleException {
+
+	if (started)
+	    throw new LifecycleException
+		(sm.getString("ajp13Processor.alreadyStarted"));
+	lifecycle.fireLifecycleEvent(START_EVENT, null);
+	started = true;
+
+	threadStart();
+
+    }
+
+
+    /**
+     * Stop the background thread we will use for request processing.
+     *
+     * @exception LifecycleException if a fatal shutdown error occurs
+     */
+    public void stop() throws LifecycleException {
+
+	if (!started)
+	    throw new LifecycleException
+		(sm.getString("ajp13Processor.notStarted"));
+	lifecycle.fireLifecycleEvent(STOP_EVENT, null);
+	started = false;
+
+	threadStop();
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/ajp/tomcat4/Ajp13Request.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/ajp/tomcat4/Ajp13Request.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/ajp/tomcat4/Ajp13Request.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,320 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.ajp.tomcat4;
+
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.Locale;
+import java.util.TreeMap;
+
+import javax.servlet.ServletInputStream;
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletRequest;
+
+import org.apache.catalina.Globals;
+import org.apache.catalina.connector.HttpRequestBase;
+import org.apache.catalina.util.StringParser;
+import org.apache.tomcat.util.buf.MessageBytes;
+import org.apache.tomcat.util.http.BaseRequest;
+import org.apache.tomcat.util.http.Cookies;
+import org.apache.tomcat.util.http.MimeHeaders;
+import org.apache.tomcat.util.http.ServerCookie;
+
+public class Ajp13Request extends HttpRequestBase {
+
+    private static final String match =
+	";" + Globals.SESSION_PARAMETER_NAME + "=";
+
+    private static int id = 1;
+
+    private Ajp13Logger logger = new Ajp13Logger();
+    private int debug;
+
+    public Ajp13Request(Ajp13Connector connector) {
+        super();
+        this.debug = connector.getDebug();
+        this.logger.setConnector(connector);
+        this.logger.setName("Ajp13Request[" + (id++) + "]");
+    }
+
+    public void recycle() {
+        super.recycle();        
+    }
+
+    void setAjpRequest(BaseRequest ajp) throws UnsupportedEncodingException {
+        // XXX make this guy wrap AjpRequest so
+        // we're more efficient (that's the whole point of
+        // all of the MessageBytes in AjpRequest)
+
+        setMethod(ajp.method().toString());
+        setProtocol(ajp.protocol().toString());
+        setRequestURI(ajp.requestURI().toString());
+        setRemoteAddr(ajp.remoteAddr().toString());
+        setRemoteHost(ajp.remoteHost().toString());
+        setServerName(ajp.serverName().toString());
+        setServerPort(ajp.getServerPort());
+
+        if ((!(((Ajp13Connector) connector).getTomcatAuthentication())) 
+            && (ajp.remoteUser() != null)) {
+            setUserPrincipal(new Ajp13Principal(ajp.remoteUser().toString()));
+        } else {
+            setUserPrincipal(null);
+        }
+
+        setAuthType(ajp.authType().toString());
+        setAuthorization(ajp.authorization().toString());
+        setQueryString(ajp.queryString().toString());
+        setScheme(ajp.getScheme());
+        setSecure(ajp.getSecure());
+        setContentLength(ajp.getContentLength());
+
+        String contentType = ajp.contentType().toString();
+        if (contentType != null) {
+            setContentType(contentType);
+        }
+
+        MimeHeaders mheaders = ajp.headers();
+        int nheaders = mheaders.size();
+        for (int i = 0; i < nheaders; ++i) {
+            MessageBytes name = mheaders.getName(i);
+            MessageBytes value = mheaders.getValue(i);
+            addHeader(name.toString(), value.toString());
+            if ("accept-language".equals(name.toString()))
+                parseLocalesHeader(value.toString());	
+        }
+
+        Iterator itr = ajp.getAttributeNames();
+        while (itr.hasNext()) {
+            String name = (String)itr.next();
+            setAttribute(name, ajp.getAttribute(name));
+        }
+
+        addCookies(ajp.cookies());
+    }
+
+//      public Object getAttribute(String name) {
+//          return ajp.getAttribute(name);
+//      }
+
+//      public Enumeration getAttributeNames() {
+//          return new Enumerator(ajp.getAttributeNames());
+//      }
+
+    public void setRequestURI(String uri) {
+	int semicolon = uri.indexOf(match);
+	if (semicolon >= 0) {
+	    String rest = uri.substring(semicolon + match.length());
+	    int semicolon2 = rest.indexOf(";");
+	    if (semicolon2 >= 0) {
+		setRequestedSessionId(rest.substring(0, semicolon2));
+		rest = rest.substring(semicolon2);
+	    } else {
+		setRequestedSessionId(rest);
+		rest = "";
+	    }
+	    setRequestedSessionURL(true);
+	    uri = uri.substring(0, semicolon) + rest;
+	    if (debug >= 1)
+	        logger.log(" Requested URL session id is " +
+                           ((HttpServletRequest) getRequest())
+                           .getRequestedSessionId());
+	} else {
+	    setRequestedSessionId(null);
+	    setRequestedSessionURL(false);
+	}
+
+        super.setRequestURI(uri);
+    }
+
+    private void addCookies(Cookies cookies) {
+        int ncookies = cookies.getCookieCount();
+        for (int j = 0; j < ncookies; j++) {
+            ServerCookie scookie = cookies.getCookie(j);
+            Cookie cookie = new Cookie(scookie.getName().toString(),
+                                       scookie.getValue().toString());
+            if (cookie.getName().equals(Globals.SESSION_COOKIE_NAME)) {
+                // Override anything requested in the URL
+                if (!isRequestedSessionIdFromCookie()) {
+                                // Accept only the first session id cookie
+                    setRequestedSessionId(cookie.getValue());
+                    setRequestedSessionCookie(true);
+                    setRequestedSessionURL(false);
+                    if (debug > 0) {
+                        logger.log(" Requested cookie session id is " +
+                                   ((HttpServletRequest) getRequest())
+                                   .getRequestedSessionId());
+                    }
+                }
+            }
+            if (debug > 0) {
+                logger.log(" Adding cookie " + cookie.getName() + "=" +
+                           cookie.getValue());
+            }
+            addCookie(cookie);                    
+        }        
+    }
+
+    public ServletInputStream createInputStream() throws IOException {
+        return (ServletInputStream)getStream();
+    }
+
+
+    /**
+     * Parse accept-language header value.
+     */
+    protected void parseLocalesHeader(String value) {
+
+        // Store the accumulated languages that have been requested in
+        // a local collection, sorted by the quality value (so we can
+        // add Locales in descending order).  The values will be ArrayLists
+        // containing the corresponding Locales to be added
+        TreeMap locales = new TreeMap();
+
+        // Preprocess the value to remove all whitespace
+        int white = value.indexOf(' ');
+        if (white < 0)
+            white = value.indexOf('\t');
+        if (white >= 0) {
+            StringBuffer sb = new StringBuffer();
+            int len = value.length();
+            for (int i = 0; i < len; i++) {
+                char ch = value.charAt(i);
+                if ((ch != ' ') && (ch != '\t'))
+                    sb.append(ch);
+            }
+            value = sb.toString();
+        }
+
+        // Process each comma-delimited language specification
+	StringParser parser = new StringParser();
+        parser.setString(value);        
+        int length = parser.getLength();
+        while (true) {
+
+            // Extract the next comma-delimited entry
+            int start = parser.getIndex();
+            if (start >= length)
+                break;
+            int end = parser.findChar(',');
+            String entry = parser.extract(start, end).trim();
+            parser.advance();   // For the following entry
+
+            // Extract the quality factor for this entry
+            double quality = 1.0;
+            int semi = entry.indexOf(";q=");
+            if (semi >= 0) {
+                try {
+                    quality = Double.parseDouble(entry.substring(semi + 3));
+                } catch (NumberFormatException e) {
+                    quality = 0.0;
+                }
+                entry = entry.substring(0, semi);
+            }
+
+            // Skip entries we are not going to keep track of
+            if (quality < 0.00005)
+                continue;       // Zero (or effectively zero) quality factors
+            if ("*".equals(entry))
+                continue;       // FIXME - "*" entries are not handled
+
+            // Extract the language and country for this entry
+            String language = null;
+            String country = null;
+            String variant = null;
+            int dash = entry.indexOf('-');
+            if (dash < 0) {
+                language = entry;
+                country = "";
+                variant = "";
+            } else {
+                language = entry.substring(0, dash);
+                country = entry.substring(dash + 1);
+                int vDash = country.indexOf('-');
+                if (vDash > 0) {
+                    String cTemp = country.substring(0, vDash);
+                    variant = country.substring(vDash + 1);
+                    country = cTemp;
+                } else {
+                    variant = "";
+                }
+            }
+
+            // Add a new Locale to the list of Locales for this quality level
+            Locale locale = new Locale(language, country, variant);
+            Double key = new Double(-quality);  // Reverse the order
+            ArrayList values = (ArrayList) locales.get(key);
+            if (values == null) {
+                values = new ArrayList();
+                locales.put(key, values);
+            }
+            values.add(locale);
+
+        }
+
+        // Process the quality values in highest->lowest order (due to
+        // negating the Double value when creating the key)
+        Iterator keys = locales.keySet().iterator();
+        while (keys.hasNext()) {
+            Double key = (Double) keys.next();
+            ArrayList list = (ArrayList) locales.get(key);
+            Iterator values = list.iterator();
+            while (values.hasNext()) {
+                Locale locale = (Locale) values.next();
+                addLocale(locale);
+            }
+        }
+
+    }
+}
+
+class Ajp13Principal implements java.security.Principal {
+    String user;
+    
+    Ajp13Principal(String user) {
+        this.user = user;
+    }
+    public boolean equals(Object o) {
+        if (o == null) {
+            return false;
+        } else if (!(o instanceof Ajp13Principal)) {
+            return false;
+        } else if (o == this) {
+            return true;
+        } else if (this.user == null && ((Ajp13Principal)o).user == null) {
+            return true;
+        } else if (user != null) {
+            return user.equals( ((Ajp13Principal)o).user);
+        } else {
+            return false;
+        }
+    }
+    
+    public String getName() {
+        return user;
+    }
+    
+    public int hashCode() {
+        if (user == null) return 0;
+        else return user.hashCode();
+    }
+    
+    public String toString() {
+        return getName();
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/ajp/tomcat4/Ajp13Response.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/ajp/tomcat4/Ajp13Response.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/ajp/tomcat4/Ajp13Response.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,165 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.ajp.tomcat4;
+
+import java.io.IOException;
+
+import java.util.Iterator;
+
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpSession;
+
+import org.apache.catalina.connector.HttpResponseBase;
+import org.apache.catalina.Globals;
+import org.apache.catalina.util.CookieTools;
+
+import org.apache.ajp.Ajp13;
+import org.apache.tomcat.util.http.MimeHeaders;
+
+public class Ajp13Response extends HttpResponseBase {
+
+    private Ajp13 ajp13;
+    private boolean finished = false;
+    private boolean headersSent = false;
+    private MimeHeaders headers = new MimeHeaders();
+    private StringBuffer cookieValue = new StringBuffer();
+
+    String getStatusMessage() {
+        return getStatusMessage(getStatus());
+    }
+
+    public void recycle() {
+        super.recycle();
+        this.finished = false;
+        this.headersSent = false;
+        this.headers.recycle();
+    }
+
+    protected void sendHeaders()  throws IOException {
+
+        if (headersSent) {
+            // don't send headers twice
+            return;
+        }
+        headersSent = true;
+
+        int numHeaders = 0;
+
+        if (getContentType() != null) {
+            numHeaders++;
+	}
+        
+	if (getContentLength() >= 0) {
+            numHeaders++;
+	}
+
+	// Add the session ID cookie if necessary
+	HttpServletRequest hreq = (HttpServletRequest) request.getRequest();
+	HttpSession session = hreq.getSession(false);
+
+	if ((session != null) && session.isNew() && (getContext() != null) 
+            && getContext().getCookies()) {
+	    Cookie cookie = new Cookie(Globals.SESSION_COOKIE_NAME,
+				       session.getId());
+	    cookie.setMaxAge(-1);
+	    String contextPath = null;
+            if (context != null)
+                contextPath = context.getPath();
+	    if ((contextPath != null) && (contextPath.length() > 0))
+		cookie.setPath(contextPath);
+	    else
+	        cookie.setPath("/");
+	    if (hreq.isSecure())
+		cookie.setSecure(true);
+	    addCookie(cookie);
+	}
+
+        // Send all specified cookies (if any)
+	synchronized (cookies) {
+	    Iterator items = cookies.iterator();
+	    while (items.hasNext()) {
+		Cookie cookie = (Cookie) items.next();
+
+                cookieValue.delete(0, cookieValue.length());
+                CookieTools.getCookieHeaderValue(cookie, cookieValue);
+                
+                addHeader(CookieTools.getCookieHeaderName(cookie),
+                          cookieValue.toString());
+	    }
+	}
+
+        // figure out how many headers...
+        // can have multiple headers of the same name...
+        // need to loop through headers once to get total
+        // count, once to add header to outBuf
+        String[] hnames = getHeaderNames();
+        Object[] hvalues = new Object[hnames.length];
+
+        int i;
+        for (i = 0; i < hnames.length; ++i) {
+            String[] tmp = getHeaderValues(hnames[i]);
+            numHeaders += tmp.length;
+            hvalues[i] = tmp;
+        }
+
+        ajp13.beginSendHeaders(getStatus(), getStatusMessage(getStatus()), numHeaders);
+
+        // send each header
+        if (getContentType() != null) {
+	    ajp13.sendHeader("Content-Type", getContentType());
+	}
+        
+	if (getContentLength() >= 0) {
+	    ajp13.sendHeader("Content-Length", String.valueOf(getContentLength()));
+	}
+
+        for (i = 0; i < hnames.length; ++i) {
+	    String name = hnames[i];
+            String[] values = (String[])hvalues[i];
+
+            for (int j = 0; j < values.length; ++j) {
+                ajp13.sendHeader(name, values[j]);
+            }
+        }
+
+        ajp13.endSendHeaders();
+
+        // The response is now committed
+        committed = true;
+    }
+
+    public void finishResponse() throws IOException {
+	if(!this.finished) {
+            try {
+                super.finishResponse();
+            } catch( Throwable t ) {
+                t.printStackTrace();
+            }
+            this.finished = true; // Avoid END_OF_RESPONSE sent 2 times
+	    ajp13.finish();
+	}        
+    }
+
+    void setAjp13(Ajp13 ajp13) {
+        this.ajp13 = ajp13;
+    }
+
+    Ajp13 getAjp13() {
+        return this.ajp13;
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/ajp/tomcat4/Constants.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/ajp/tomcat4/Constants.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/ajp/tomcat4/Constants.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,21 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.ajp.tomcat4;
+
+public interface Constants {
+    public static final String PACKAGE = "org.apache.ajp.tomcat4";
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/ajp/tomcat4/JkServlet.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/ajp/tomcat4/JkServlet.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/ajp/tomcat4/JkServlet.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,95 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.ajp.tomcat4;
+
+
+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.apache.catalina.Container;
+import org.apache.catalina.ContainerServlet;
+import org.apache.catalina.Context;
+import org.apache.catalina.Wrapper;
+
+
+/**
+ * Module loader for JkServlet
+ *
+ * @author Costin Manolache
+ */
+public class JkServlet
+    extends HttpServlet implements ContainerServlet
+{
+    // -------------------- ContainerServlet interface --------------------
+    Wrapper wrapper;
+    
+    public Wrapper getWrapper() {
+	if( dL > 0 ) d("getWrapper()");
+	return wrapper;
+    }
+
+    public void setWrapper(Wrapper wrapper) {
+	if( dL > 0 ) d("setWrapper() " + wrapper );
+	this.wrapper=wrapper;
+    }
+
+    Context ctx;
+    
+    /**
+     * Initialize this servlet.
+     */
+    public void init() throws ServletException {
+	super.init();
+        if(wrapper == null) {
+	    log("No wrapper available, make sure the app is trusted");
+	    //System.out.println("No wrapper available, make sure the app is trusted");
+	    return;
+	}
+
+	ctx=(Context) wrapper.getParent();
+
+	if( dL > 0 ) {
+	    d("Wrapper: " + wrapper.getClass().getName() + " " + wrapper );
+	    d("Ctx: " + ctx.getClass().getName() + " " + ctx );
+	    Object parent=ctx.getParent();
+	    d("P: " + parent.getClass().getName() + " " + parent );
+	    while( parent instanceof Container ) {
+		parent=((Container)parent).getParent();
+		d("P: " + parent.getClass().getName() + " " + parent );
+	    }
+	}
+	
+    }
+
+    public void service(HttpServletRequest request,
+                      HttpServletResponse response)
+        throws IOException, ServletException
+    {
+	throw new ServletException("Shouldn't be called direclty");
+    }
+    
+    private static final int dL=10;
+    private  void d(String s ) {
+        log( "JkServlet: " + s );
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/ajp/tomcat4/LocalStrings.properties
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/ajp/tomcat4/LocalStrings.properties	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/ajp/tomcat4/LocalStrings.properties	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,22 @@
+# $Id: LocalStrings.properties 295282 2001-05-12 05:52:38Z seguin $
+
+# language
+
+# package org.apache.jk.ajp.tomcat4;
+
+ajp13Connector.alreadyStarted=Ajp13 connector has already been started
+ajp13Connector.allAddresses=Opening server socket on all host IP addresses
+ajp13Connector.failedSocketFactoryLoading=Failed to load socket factory
+ajp13Connector.failedToCreateSocket=Socket factory failed to create socket
+ajp13Connector.anAddress=Opening server socket on host IP address {0}
+ajp13Connector.noAddress=No host IP address matching {0}, opening on all addresses
+ajp13Connector.noProcessor=No processor available, rejecting this connection
+ajp13Connector.notStarted=Ajp13 connector has not yet been started
+ajp13Connector.starting=Starting background thread
+ajp13Connector.stopping=Stopping background thread
+
+ajp13Processor.alreadyStarted=Ajp13 processor has already been started
+ajp13Processor.notStarted=Ajp13 processor has not yet been started
+ajp13Processor.start=Ajp13 processor has already been started
+ajp13Processor.starting=Starting background thread
+ajp13Processor.stopping=Stopping background thread

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/ajp/tomcat4/LocalStrings_es.properties
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/ajp/tomcat4/LocalStrings_es.properties	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/ajp/tomcat4/LocalStrings_es.properties	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,22 @@
+# $Id: LocalStrings_es.properties 299218 2004-02-24 08:48:44Z hgomez $
+
+# language es
+
+# package org.apache.jk.ajp.tomcat4;
+
+ajp13Connector.alreadyStarted=Ya ha sido arrancado el conector Ajp13
+ajp13Connector.allAddresses=Abriendo enchufe (socket) de servidor en todas la direcciones IP de máquinas
+ajp13Connector.failedSocketFactoryLoading=No pude cargar fábrica de echufes (sockets)
+ajp13Connector.failedToCreateSocket=La fábrica de enchufes (sockets) no pudo crear enchufe (socket)
+ajp13Connector.anAddress=Abriendo enchufe (socket) de servidor en dirección IP de máquina {0}
+ajp13Connector.noAddress=No hay dirección IP de máquina que coincida con {0}, abriendo en todas las direcciones
+ajp13Connector.noProcessor=El procesador no está disponible, rechazando esta conexión
+ajp13Connector.notStarted=Aún no ha sido arrancado el conector Ajp13
+ajp13Connector.starting=Arrancado hilo en segundo plano
+ajp13Connector.stopping=Parando hilo en segundo plano
+
+ajp13Processor.alreadyStarted=Ya ha sido arrancado el procesador Ajp13
+ajp13Processor.notStarted=Aún no ha sido arrancado el procesador Ajp13
+ajp13Processor.start=Ya ha sido arrancado el procesador Ajp13
+ajp13Processor.starting=Arrancando hilo en segundo plano
+ajp13Processor.stopping=Parando hilo en segundo plano

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/ajp/tomcat4/LocalStrings_fr.properties
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/ajp/tomcat4/LocalStrings_fr.properties	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/ajp/tomcat4/LocalStrings_fr.properties	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,22 @@
+# $Id: LocalStrings_fr.properties 299218 2004-02-24 08:48:44Z hgomez $
+
+# language fr
+
+# package org.apache.jk.ajp.tomcat4;
+
+ajp13Connector.alreadyStarted=le connecteur ajp13 a déjà été démarré
+ajp13Connector.allAddresses=Ouverture du serveur socket sur toutes les adresses IP
+ajp13Connector.failedSocketFactoryLoading=Impossible de charger le créateur de socket (socket factory)
+ajp13Connector.failedToCreateSocket=Le créateur de socket (socket factory) n'a pu créer un socket
+ajp13Connector.anAddress=Ouverture du serveur socket sur l''adresse IP {0}
+ajp13Connector.noAddress=Pas d''adresse IP correspondant à {0}, ouverture sur toutes les adresses
+ajp13Connector.noProcessor=Pas de processeur disponible, rejet de cette connexion
+ajp13Connector.notStarted=Le connecteur ajp13 n'a pas encore été démarré
+ajp13Connector.starting=Démarrage de la tache de fond (background thread)
+ajp13Connector.stopping=Arrêt de la tache de fond (background thread)
+
+ajp13Processor.alreadyStarted=Le processeur ajp13 a déjà été démarré
+ajp13Processor.notStarted=Le processeur ajp13 n'a pas encore été démarré
+ajp13Processor.start=Le processeur ajp13 a déjà été démarré
+ajp13Processor.starting=Démarrage de la tache de fond (background thread)
+ajp13Processor.stopping=Arrêt de la tache de fond (background thread)

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/ajp/tomcat4/LocalStrings_ja.properties
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/ajp/tomcat4/LocalStrings_ja.properties	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/ajp/tomcat4/LocalStrings_ja.properties	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,22 @@
+# $Id: LocalStrings_ja.properties 298858 2003-09-02 14:11:53Z remm $
+
+# language ja
+
+# package org.apache.jk.ajp.tomcat4;
+
+ajp13Connector.alreadyStarted=AJP13\u30b3\u30cd\u30af\u30bf\u306f\u65e2\u306b\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u3059
+ajp13Connector.allAddresses=\u3059\u3079\u3066\u306e\u30db\u30b9\u30c8IP\u30a2\u30c9\u30ec\u30b9\u306e\u30b5\u30fc\u30d0\u30bd\u30b1\u30c3\u30c8\u3092\u30aa\u30fc\u30d7\u30f3\u3057\u307e\u3059
+ajp13Connector.failedSocketFactoryLoading=\u30bd\u30b1\u30c3\u30c8\u30d5\u30a1\u30af\u30c8\u30ea\u306e\u30ed\u30fc\u30c9\u306b\u5931\u6557\u3057\u307e\u3057\u305f
+ajp13Connector.failedToCreateSocket=\u30bd\u30b1\u30c3\u30c8\u30d5\u30a1\u30af\u30c8\u30ea\u306f\u30bd\u30b1\u30c3\u30c8\u306e\u4f5c\u6210\u306b\u5931\u6557\u3057\u307e\u3057\u305f
+ajp13Connector.anAddress=\u30db\u30b9\u30c8IP\u30a2\u30c9\u30ec\u30b9 {0} \u306e\u30b5\u30fc\u30d0\u30bd\u30b1\u30c3\u30c8\u3092\u30aa\u30fc\u30d7\u30f3\u3057\u307e\u3059
+ajp13Connector.noAddress={0} \u306b\u4e00\u81f4\u3059\u308b\u30db\u30b9\u30c8IP\u30a2\u30c9\u30ec\u30b9\u306f\u5b58\u5728\u3057\u306a\u3044\u306e\u3067\u3001\u3059\u3079\u3066\u306e\u30a2\u30c9\u30ec\u30b9\u3092\u30aa\u30fc\u30d7\u30f3\u3057\u307e\u3059
+ajp13Connector.noProcessor=\u5229\u7528\u53ef\u80fd\u306a\u30d7\u30ed\u30bb\u30c3\u30b5\u304c\u306a\u3044\u306e\u3067\uff0c\u3053\u306e\u30b3\u30cd\u30af\u30b7\u30e7\u30f3\u3092\u62d2\u5426\u3057\u307e\u3059
+ajp13Connector.notStarted=AJP13\u30b3\u30cd\u30af\u30bf\u306f\u307e\u3060\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u305b\u3093
+ajp13Connector.starting=\u30d0\u30c3\u30af\u30b0\u30e9\u30a6\u30f3\u30c9\u30b9\u30ec\u30c3\u30c9\u3092\u8d77\u52d5\u3057\u307e\u3059
+ajp13Connector.stopping=\u30d0\u30c3\u30af\u30b0\u30e9\u30a6\u30f3\u30c9\u30b9\u30ec\u30c3\u30c9\u3092\u505c\u6b62\u3057\u307e\u3059
+
+ajp13Processor.alreadyStarted=AJP13\u30d7\u30ed\u30bb\u30c3\u30b5\u306f\u65e2\u306b\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u3059
+ajp13Processor.notStarted=AJP13\u30d7\u30ed\u30bb\u30c3\u30b5\u306f\u307e\u3060\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u305b\u3093
+ajp13Processor.start=AJP13\u30d7\u30ed\u30bb\u30c3\u30b5\u306f\u65e2\u306b\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u3059
+ajp13Processor.starting=\u30d0\u30c3\u30af\u30b0\u30e9\u30a6\u30f3\u30c9\u30b9\u30ec\u30c3\u30c9\u3092\u8d77\u52d5\u3057\u307e\u3059
+ajp13Processor.stopping=\u30d0\u30c3\u30af\u30b0\u30e9\u30a6\u30f3\u30c9\u30b9\u30ec\u30c3\u30c9\u3092\u505c\u6b62\u3057\u307e\u3059

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/ajp/tomcat4/config/ApacheConfig.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/ajp/tomcat4/config/ApacheConfig.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/ajp/tomcat4/config/ApacheConfig.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,570 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.ajp.tomcat4.config;
+
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.Date;
+import java.util.Hashtable;
+
+import org.apache.catalina.Context;
+import org.apache.catalina.Host;
+
+/* The idea is to keep all configuration in server.xml and
+   the normal apache config files. We don't want people to
+   touch apache ( or IIS, NES ) config files unless they
+   want to and know what they're doing ( better than we do :-).
+
+   One nice feature ( if someone sends it ) would be to
+   also edit httpd.conf to add the include.
+
+   We'll generate a number of configuration files - this one
+   is trying to generate a native apache config file.
+
+   Some web.xml mappings do not "map" to server configuration - in
+   this case we need to fallback to forward all requests to tomcat.
+
+   Ajp14 will add to that the posibility to have tomcat and
+   apache on different machines, and many other improvements -
+   but this should also work for Ajp12, Ajp13 and Jni.
+
+*/
+
+/**
+    Generates automatic apache mod_jk configurations based on
+    the Tomcat server.xml settings and the war contexts
+    initialized during startup.
+    <p>
+    This config interceptor is enabled by inserting an ApacheConfig
+    <code>Listener</code> in 
+    the server.xml file like so:
+    <pre>
+    * < Server ... >
+    *   ...
+    *   <Listener className=<b>org.apache.ajp.tomcat4.config.ApacheConfig</b> 
+    *       <i>options</i> />
+    *   ...
+    * < /Server >
+    </pre>
+    where <i>options</i> can include any of the following attributes:
+    <ul>
+     <li><b>configHome</b> - default parent directory for the following paths.
+                            If not set, this defaults to TOMCAT_HOME. Ignored
+                            whenever any of the following paths is absolute.
+                             </li>
+     <li><b>jkConfig</b> - path to use for writing Apache mod_jk conf file. If
+                            not set, defaults to
+                            "conf/auto/mod_jk.conf".</li>
+     <li><b>workersConfig</b> - path to workers.properties file used by 
+                            mod_jk. If not set, defaults to
+                            "conf/jk/workers.properties".</li>
+     <li><b>modJk</b> - path to Apache mod_jk plugin file.  If not set,
+                        defaults to "modules/mod_jk.dll" on windows,
+                        "modules/mod_jk.nlm" on netware, and
+                        "libexec/mod_jk.so" everywhere else.</li>
+     <li><b>jkLog</b> - path to log file to be used by mod_jk.</li>
+     <li><b>jkDebug</b> - JK Loglevel setting.  May be debug, info, error, or emerg.
+                          If not set, defaults to emerg.</li>
+     <li><b>jkWorker</b> The desired worker.  Must be set to one of the workers
+                         defined in the workers.properties file. "ajp12", "ajp13"
+                         or "inprocess" are the workers found in the default
+                         workers.properties file. If not specified, defaults
+                         to "ajp13" if an Ajp13Interceptor is in use, otherwise
+                         it defaults to "ajp12".</li>
+     <li><b>forwardAll</b> - If true, forward all requests to Tomcat. This helps
+                             insure that all the behavior configured in the web.xml
+                             file functions correctly.  If false, let Apache serve
+                             static resources. The default is true.
+                             Warning: When false, some configuration in
+                             the web.xml may not be duplicated in Apache.
+                             Review the mod_jk conf file to see what
+                             configuration is actually being set in Apache.</li>
+     <li><b>noRoot</b> - If true, the root context is not mapped to
+                         Tomcat.  If false and forwardAll is true, all requests
+                         to the root context are mapped to Tomcat. If false and
+                         forwardAll is false, only JSP and servlets requests to
+                         the root context are mapped to Tomcat. When false,
+                         to correctly serve Tomcat's root context you must also
+                         modify the DocumentRoot setting in Apache's httpd.conf
+                         file to point to Tomcat's root context directory.
+                         Otherwise some content, such as Apache's index.html,
+                         will be served by Apache before mod_jk gets a chance
+                         to claim the request and pass it to Tomcat.
+                         The default is true.</li>
+    </ul>
+    <p>
+    @author Costin Manolache
+    @author Larry Isaacs
+    @author Mel Martinez
+    @author Bill Barker
+ */
+public class ApacheConfig  extends BaseJkConfig { 
+    
+    /** default path to mod_jk .conf location */
+    public static final String MOD_JK_CONFIG = "conf/auto/mod_jk.conf";
+    /** default path to workers.properties file
+	This should be also auto-generated from server.xml.
+    */
+    public static final String WORKERS_CONFIG = "conf/jk/workers.properties";
+    /** default mod_jk log file location */
+    public static final String JK_LOG_LOCATION = "logs/mod_jk.log";
+    /** default location of mod_jk Apache plug-in. */
+    public static final String MOD_JK;
+    
+    //set up some defaults based on OS type
+    static{
+        String os = System.getProperty("os.name").toLowerCase();
+        if(os.indexOf("windows")>=0){ 
+           MOD_JK = "modules/mod_jk.dll";
+        }else if(os.indexOf("netware")>=0){
+           MOD_JK = "modules/mod_jk.nlm";
+        }else{
+           MOD_JK = "libexec/mod_jk.so";
+        }
+    }
+    
+    private File jkConfig = null;
+    private File modJk = null;
+
+    // ssl settings 
+    private boolean sslExtract=true;
+    private String sslHttpsIndicator="HTTPS";
+    private String sslSessionIndicator="SSL_SESSION_ID";
+    private String sslCipherIndicator="SSL_CIPHER";
+    private String sslCertsIndicator="SSL_CLIENT_CERT";
+
+    Hashtable NamedVirtualHosts=null;
+    
+    public ApacheConfig() {
+    }
+
+    //-------------------- Properties --------------------
+
+    /**
+        set the path to the output file for the auto-generated
+        mod_jk configuration file.  If this path is relative
+        then it will be resolved absolutely against
+        the getConfigHome() path.
+        <p>
+        @param path String path to a file
+    */
+    public void setJkConfig(String path){
+	jkConfig= (path==null)?null:new File(path);
+    }
+
+    /**
+        set the path to the mod_jk Apache Module
+        @param path String path to a file
+    */
+    public void setModJk(String path){
+        modJk=( path==null?null:new File(path));
+    }
+
+    /** By default mod_jk is configured to collect SSL information from
+	the apache environment and send it to the Tomcat workers. The
+	problem is that there are many SSL solutions for Apache and as
+	a result the environment variable names may change.
+
+	The following JK related SSL configureation
+	can be used to customize mod_jk's SSL behaviour.
+
+	Should mod_jk send SSL information to Tomact (default is On)
+    */
+    public void setExtractSSL( boolean sslMode ) {
+	this.sslExtract=sslMode;
+    }
+
+    /** What is the indicator for SSL (default is HTTPS)
+     */
+    public void setHttpsIndicator( String s ) {
+	sslHttpsIndicator=s;
+    }
+
+    /**What is the indicator for SSL session (default is SSL_SESSION_ID)
+     */
+    public void setSessionIndicator( String s ) {
+	sslSessionIndicator=s;
+    }
+    
+    /**What is the indicator for client SSL cipher suit (default is SSL_CIPHER)
+     */
+    public void setCipherIndicator( String s ) {
+	sslCipherIndicator=s;
+    }
+
+    /** What is the indicator for the client SSL certificated(default
+	is SSL_CLIENT_CERT
+     */
+    public void setCertsIndicator( String s ) {
+	sslCertsIndicator=s;
+    }
+
+    // -------------------- Initialize/guess defaults --------------------
+
+    /** Initialize defaults for properties that are not set
+	explicitely
+    */
+    protected void initProperties() {
+        super.initProperties();
+
+	jkConfig= getConfigFile( jkConfig, configHome, MOD_JK_CONFIG);
+	workersConfig=getConfigFile( workersConfig, configHome,
+				     WORKERS_CONFIG);
+	if( modJk == null )
+	    modJk=new File(MOD_JK);
+	else
+	    modJk=getConfigFile( modJk, configHome, MOD_JK );
+	jkLog=getConfigFile( jkLog, configHome, JK_LOG_LOCATION);
+    }
+    // -------------------- Generate config --------------------
+    
+    protected PrintWriter getWriter() throws IOException {
+	String abJkConfig = jkConfig.getAbsolutePath();
+	return new PrintWriter(new FileWriter(abJkConfig, append));
+    }
+			       
+
+    // -------------------- Config sections  --------------------
+
+    /** Generate the loadModule and general options
+     */
+    protected boolean generateJkHead(PrintWriter mod_jk)
+    {
+
+	mod_jk.println("########## Auto generated on " +  new Date() +
+		       "##########" );
+	mod_jk.println();
+
+	// Fail if mod_jk not found, let the user know the problem
+	// instead of running into problems later.
+	if( ! modJk.exists() ) {
+	    log( "mod_jk location: " + modJk );
+	    log( "Make sure it is installed corectly or " +
+		 " set the config location" );
+	    log( "Using <Listener className=\""+getClass().getName()+"\"  modJk=\"PATH_TO_MOD_JK.SO_OR_DLL\" />" );
+	}
+            
+	// Verify the file exists !!
+	mod_jk.println("<IfModule !mod_jk.c>");
+	mod_jk.println("  LoadModule jk_module \""+
+		       modJk.toString().replace('\\','/') +
+                       "\"");
+	mod_jk.println("</IfModule>");
+	mod_jk.println();                
+
+	
+	// Fail if workers file not found, let the user know the problem
+	// instead of running into problems later.
+	if( ! workersConfig.exists() ) {
+	    log( "Can't find workers.properties at " + workersConfig );
+	    log( "Please install it in the default location or " +
+		 " set the config location" );
+	    log( "Using <Listener className=\"" + getClass().getName() + "\"  workersConfig=\"FULL_PATH\" />" );
+	    return false;
+	}
+            
+	mod_jk.println("JkWorkersFile \"" 
+		       + workersConfig.toString().replace('\\', '/') 
+		       + "\"");
+
+	mod_jk.println("JkLogFile \"" 
+		       + jkLog.toString().replace('\\', '/') 
+		       + "\"");
+	mod_jk.println();
+
+	if( jkDebug != null ) {
+	    mod_jk.println("JkLogLevel " + jkDebug);
+	    mod_jk.println();
+	}
+	return true;
+    }
+
+    protected void generateVhostHead(Host host, PrintWriter mod_jk) {
+
+        mod_jk.println();
+        String vhostip = host.getName();
+	String vhost = vhostip;
+	int ppos = vhost.indexOf(":");
+	if(ppos >= 0)
+	    vhost = vhost.substring(0,ppos);
+
+        mod_jk.println("<VirtualHost "+ vhostip + ">");
+        mod_jk.println("    ServerName " + vhost );
+        String [] aliases=host.findAliases();
+        if( aliases.length > 0 ) {
+            mod_jk.print("    ServerAlias " );
+            for( int ii=0; ii < aliases.length ; ii++) {
+                mod_jk.print( aliases[ii] + " " );
+            }
+            mod_jk.println();
+        }
+        indent="    ";
+    }
+
+    protected void generateVhostTail(Host host, PrintWriter mod_jk) {
+        mod_jk.println("</VirtualHost>");
+        indent="";
+    }
+    
+    protected void generateSSLConfig(PrintWriter mod_jk) {
+	if( ! sslExtract ) {
+	    mod_jk.println("JkExtractSSL Off");        
+	}
+	if( ! "HTTPS".equalsIgnoreCase( sslHttpsIndicator ) ) {
+	    mod_jk.println("JkHTTPSIndicator " + sslHttpsIndicator);        
+	}
+	if( ! "SSL_SESSION_ID".equalsIgnoreCase( sslSessionIndicator )) {
+	    mod_jk.println("JkSESSIONIndicator " + sslSessionIndicator);
+	}
+	if( ! "SSL_CIPHER".equalsIgnoreCase( sslCipherIndicator )) {
+	    mod_jk.println("JkCIPHERIndicator " + sslCipherIndicator);
+	}
+	if( ! "SSL_CLIENT_CERT".equalsIgnoreCase( sslCertsIndicator )) {
+	    mod_jk.println("JkCERTSIndicator " + sslCertsIndicator);
+	}
+
+	mod_jk.println();
+    }
+
+    // -------------------- Forward all mode --------------------
+    String indent="";
+    
+    /** Forward all requests for a context to tomcat.
+	The default.
+     */
+    protected void generateStupidMappings(Context context,
+					   PrintWriter mod_jk )
+    {
+	String ctxPath  = context.getPath();
+	if(ctxPath == null)
+	    return;
+
+	String nPath=("".equals(ctxPath)) ? "/" : ctxPath;
+	
+        mod_jk.println();
+	mod_jk.println(indent + "JkMount " +  nPath + " " + jkWorker );
+	if( "".equals(ctxPath) ) {
+	    mod_jk.println(indent + "JkMount " +  nPath + "* " + jkWorker );
+            if ( context.getParent() instanceof Host ) {
+                mod_jk.println(indent + "DocumentRoot \"" +
+                            getApacheDocBase(context) + "\"");
+            } else {
+                mod_jk.println(indent +
+                        "# To avoid Apache serving root welcome files from htdocs, update DocumentRoot");
+                mod_jk.println(indent +
+                        "# to point to: \"" + getApacheDocBase(context) + "\"");
+            }
+
+	} else {
+	    mod_jk.println(indent + "JkMount " +  nPath + "/* " + jkWorker );
+	}
+    }    
+
+    
+    private void generateNameVirtualHost( PrintWriter mod_jk, String ip ) {
+        if( !NamedVirtualHosts.containsKey(ip) ) {
+            mod_jk.println("NameVirtualHost " + ip + "");
+            NamedVirtualHosts.put(ip,ip);
+        }
+    }
+    
+    // -------------------- Apache serves static mode --------------------
+    // This is not going to work for all apps. We fall back to stupid mode.
+    
+    protected void generateContextMappings(Context context, PrintWriter mod_jk )
+    {
+	String ctxPath  = context.getPath();
+	Host vhost = getHost(context);
+
+        if( noRoot &&  "".equals(ctxPath) ) {
+            log("Ignoring root context in non-forward-all mode  ");
+            return;
+        }
+
+	mod_jk.println();
+	mod_jk.println(indent + "#################### " +
+		       ((vhost!=null ) ? vhost.getName() + ":" : "" ) +
+		       (("".equals(ctxPath)) ? "/" : ctxPath ) +
+		       " ####################" );
+        mod_jk.println();
+	// Dynamic /servet pages go to Tomcat
+ 
+	generateStaticMappings( context, mod_jk );
+
+	// InvokerInterceptor - it doesn't have a container,
+	// but it's implemented using a special module.
+	
+	// XXX we need to better collect all mappings
+
+	if(context.getLoginConfig() != null) {
+	    String loginPage = context.getLoginConfig().getLoginPage();
+	    if(loginPage != null) {
+		int lpos = loginPage.lastIndexOf("/");
+		String jscurl = loginPage.substring(0,lpos+1) + "j_security_check";
+		addMapping( ctxPath, jscurl, mod_jk);
+	    }
+	}
+	String [] servletMaps = context.findServletMappings();
+	for(int ii=0; ii < servletMaps.length; ii++) {
+	      addMapping( ctxPath, servletMaps[ii] , mod_jk );
+	}
+    }
+
+    /** Add an Apache extension mapping.
+     */
+    protected boolean addExtensionMapping( String ctxPath, String ext,
+					 PrintWriter mod_jk )
+    {
+        if( debug > 0 )
+            log( "Adding extension map for " + ctxPath + "/*." + ext );
+	mod_jk.println(indent + "JkMount " + ctxPath + "/*." + ext
+		       + " " + jkWorker);
+	return true;
+    }
+    
+    
+    /** Add a fulling specified Appache mapping.
+     */
+    protected boolean addMapping( String fullPath, PrintWriter mod_jk ) {
+        if( debug > 0 )
+            log( "Adding map for " + fullPath );
+	mod_jk.println(indent + "JkMount " + fullPath + "  " + jkWorker );
+	return true;
+    }
+    /** Add a partially specified Appache mapping.
+     */
+    protected boolean addMapping( String ctxP, String ext, PrintWriter mod_jk ) {
+        if( debug > 0 )
+            log( "Adding map for " + ext );
+	if(! ext.startsWith("/") )
+	    ext = "/" + ext;
+	if(ext.length() > 1)
+	    mod_jk.println(indent + "JkMount " + ctxP + ext+ "  " + jkWorker );
+	return true;
+    }
+
+    private void generateWelcomeFiles(Context context, PrintWriter mod_jk ) {
+	String wf[]=context.findWelcomeFiles();
+	if( wf==null || wf.length == 0 )
+	    return;
+	mod_jk.print(indent + "    DirectoryIndex ");
+	for( int i=0; i<wf.length ; i++ ) {
+	    mod_jk.print( wf[i] + " " );
+	}
+	mod_jk.println();
+    }
+
+    /** Mappings for static content. XXX need to add welcome files,
+     *  mime mappings ( all will be handled by Mime and Static modules of
+     *  apache ).
+     */
+    private void generateStaticMappings(Context context, PrintWriter mod_jk ) {
+	String ctxPath  = context.getPath();
+
+	// Calculate the absolute path of the document base
+	String docBase = getApacheDocBase(context);
+
+        if( !"".equals(ctxPath) ) {
+            // Static files will be served by Apache
+            mod_jk.println(indent + "# Static files ");		    
+            mod_jk.println(indent + "Alias " + ctxPath + " \"" + docBase + "\"");
+            mod_jk.println();
+        } else {
+            if ( getHost(context) != null ) {
+                mod_jk.println(indent + "DocumentRoot \"" +
+                            getApacheDocBase(context) + "\"");
+            } else {
+                // For root context, ask user to update DocumentRoot setting.
+                // Using "Alias / " interferes with the Alias for other contexts.
+                mod_jk.println(indent +
+                        "# Be sure to update DocumentRoot");
+                mod_jk.println(indent +
+                        "# to point to: \"" + docBase + "\"");
+            }
+        }
+	mod_jk.println(indent + "<Directory \"" + docBase + "\">");
+	mod_jk.println(indent + "    Options Indexes FollowSymLinks");
+
+	generateWelcomeFiles(context, mod_jk);
+
+	// XXX XXX Here goes the Mime types and welcome files !!!!!!!!
+	mod_jk.println(indent + "</Directory>");
+	mod_jk.println();            
+	
+
+	// Deny serving any files from WEB-INF
+	mod_jk.println();            
+	mod_jk.println(indent +
+		       "# Deny direct access to WEB-INF and META-INF");
+	mod_jk.println(indent + "#");                        
+	mod_jk.println(indent + "<Location \"" + ctxPath + "/WEB-INF/*\">");
+	mod_jk.println(indent + "    AllowOverride None");
+	mod_jk.println(indent + "    deny from all");
+	mod_jk.println(indent + "</Location>");
+	// Deny serving any files from META-INF
+	mod_jk.println();            
+	mod_jk.println(indent + "<Location \"" + ctxPath + "/META-INF/*\">");
+	mod_jk.println(indent + "    AllowOverride None");
+	mod_jk.println(indent + "    deny from all");
+	mod_jk.println(indent + "</Location>");
+	if (File.separatorChar == '\\') {
+	    mod_jk.println(indent + "#");		    
+	    mod_jk.println(indent +
+			   "# Use Directory too. On Windows, Location doesn't"
+			   + " work unless case matches");
+	    mod_jk.println(indent + "#");                        
+	    mod_jk.println(indent +
+			   "<Directory \"" + docBase + "/WEB-INF/\">");
+	    mod_jk.println(indent + "    AllowOverride None");
+	    mod_jk.println(indent + "    deny from all");
+	    mod_jk.println(indent + "</Directory>");
+	    mod_jk.println();
+	    mod_jk.println(indent +
+			   "<Directory \"" + docBase + "/META-INF/\">");
+	    mod_jk.println(indent + "    AllowOverride None");
+	    mod_jk.println(indent + "    deny from all");
+	    mod_jk.println(indent + "</Directory>");
+	}
+	mod_jk.println();
+    }    
+
+    // -------------------- Utils --------------------
+
+    private String getApacheDocBase(Context context)
+    {
+	// Calculate the absolute path of the document base
+	String docBase = getAbsoluteDocBase(context);
+	if (File.separatorChar == '\\') {
+	    // use separator preferred by Apache
+	    docBase = docBase.replace('\\','/');
+	}
+        return docBase;
+    }
+
+    private String getVirtualHostAddress(String vhost, String vhostip) {
+        if( vhostip == null ) {
+            if ( vhost != null && vhost.length() > 0 && Character.isDigit(vhost.charAt(0)) )
+                vhostip=vhost;
+            else
+                vhostip="*";
+        }
+        return vhostip;
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/ajp/tomcat4/config/BaseJkConfig.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/ajp/tomcat4/config/BaseJkConfig.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/ajp/tomcat4/config/BaseJkConfig.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,490 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.ajp.tomcat4.config;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.PrintWriter;
+
+import org.apache.catalina.Container;
+import org.apache.catalina.Context;
+import org.apache.catalina.Engine;
+import org.apache.catalina.Host;
+import org.apache.catalina.Lifecycle;
+import org.apache.catalina.LifecycleEvent;
+import org.apache.catalina.LifecycleListener;
+import org.apache.catalina.Server;
+
+
+/**
+    Base class for automatic jk based configurations based on
+    the Tomcat server.xml settings and the war contexts
+    initialized during startup.
+    <p>
+    This config interceptor is enabled by inserting a Config
+    element in the <b>&lt;ContextManager&gt;</b> tag body inside
+    the server.xml file like so:
+    <pre>
+    * < ContextManager ... >
+    *   ...
+    *   <<b>???Config</b> <i>options</i> />
+    *   ...
+    * < /ContextManager >
+    </pre>
+    where <i>options</i> can include any of the following attributes:
+    <ul>
+     <li><b>configHome</b> - default parent directory for the following paths.
+                             If not set, this defaults to TOMCAT_HOME. Ignored
+                             whenever any of the following paths is absolute.
+                             </li>
+     <li><b>workersConfig</b> - path to workers.properties file used by 
+                                jk connector. If not set, defaults to
+                                "conf/jk/workers.properties".</li>
+     <li><b>jkLog</b> - path to log file to be used by jk connector.</li>
+     <li><b>jkDebug</b> - Loglevel setting.  May be debug, info, error, or emerg.
+                          If not set, defaults to emerg.</li>
+     <li><b>jkWorker</b> The desired worker.  Must be set to one of the workers
+                         defined in the workers.properties file. "ajp12", "ajp13"
+                         or "inprocess" are the workers found in the default
+                         workers.properties file. If not specified, defaults
+                         to "ajp13" if an Ajp13Interceptor is in use, otherwise
+                         it defaults to "ajp12".</li>
+     <li><b>forwardAll</b> - If true, forward all requests to Tomcat. This helps
+                             insure that all the behavior configured in the web.xml
+                             file functions correctly.  If false, let Apache serve
+                             static resources. The default is true.
+                             Warning: When false, some configuration in
+                             the web.xml may not be duplicated in Apache.
+                             Review the mod_jk conf file to see what
+                             configuration is actually being set in Apache.</li>
+     <li><b>noRoot</b> - If true, the root context is not mapped to
+                         Tomcat.  If false and forwardAll is true, all requests
+                         to the root context are mapped to Tomcat. If false and
+                         forwardAll is false, only JSP and servlets requests to
+                         the root context are mapped to Tomcat. When false,
+                         to correctly serve Tomcat's root context you may also
+                         need to modify the web server to point it's home
+                         directory to Tomcat's root context directory.
+                         Otherwise some content, such as the root index.html,
+                         may be served by the web server before the connector
+                         gets a chance to claim the request and pass it to Tomcat.
+                         The default is true.</li>
+    </ul>
+    <p>
+    @author Costin Manolache
+    @author Larry Isaacs
+    @author Bill Barker
+	@version $Revision: 299797 $
+ */
+public class BaseJkConfig  implements LifecycleListener {
+
+    private static org.apache.commons.logging.Log log=
+        org.apache.commons.logging.LogFactory.getLog( BaseJkConfig.class );
+    
+    protected int debug=0;
+    protected File configHome = null;
+    protected File workersConfig = null;
+
+    protected File jkLog = null;
+    protected String jkDebug="emerg";
+    protected String jkWorker = "ajp13";
+
+    protected boolean noRoot=true;
+    protected boolean forwardAll=true;
+
+    protected String tomcatHome;
+    protected boolean regenerate=false;
+    protected boolean append=false;
+
+    // -------------------- Tomcat callbacks --------------------
+
+
+    // Auto-config should be able to react to dynamic config changes,
+    // and regenerate the config.
+
+    /** Generate the configuration - only when the server is
+     *  completely initialized ( before starting )
+     */
+    public void lifecycleEvent(LifecycleEvent evt)
+    {
+	if(Lifecycle.START_EVENT.equals(evt.getType())) {
+	   execute( evt );
+	}
+    }
+
+    /** Generate configuration files.  Override with method to generate
+        web server specific configuration.
+     */
+    public void execute(LifecycleEvent evt)
+    {
+	initProperties();
+	PrintWriter mod_jk = null;
+	try {
+	    mod_jk = getWriter();
+	} catch(IOException iex) {
+	    log.warn("Unable to open config file", iex);
+	    return;
+	}
+	Lifecycle who = evt.getLifecycle();
+	if( who instanceof Server ) {
+	    executeServer((Server)who, mod_jk);
+	} else if ( who instanceof Host ) {
+	    executeHost((Host)who, mod_jk);
+	} else if( who instanceof Context ) {
+	    executeContext((Context)who, mod_jk);
+	}
+	mod_jk.close();
+    }
+    /** Generate configuration files.  Override with method to generate
+        web server specific configuration.
+     */
+    public void executeServer(Server svr, PrintWriter mod_jk) {
+	if(! append ) {
+	    if( ! generateJkHead(mod_jk) )
+		return;
+	    generateSSLConfig(mod_jk);
+	    generateJkTail(mod_jk);
+	}
+    }
+
+    /** Generate SSL options
+     */
+    protected void generateSSLConfig(PrintWriter mod_jk)
+    {
+    }
+    /** Generate general options
+     */
+    protected boolean generateJkHead(PrintWriter mod_jk)
+    {
+	return true;
+    }
+    /** Generate general options
+     */
+    protected void generateJkTail(PrintWriter mod_jk)
+    {
+    }
+    /** Generate Virtual Host start
+     */
+    protected void generateVhostHead(Host host, PrintWriter mod_jk) {
+    }
+    /** Generate Virtual Host end
+     */
+    protected void generateVhostTail(Host host, PrintWriter mod_jk) {
+    }
+    /** Generate configuration files.  Override with method to generate
+        web server specific configuration.
+     */
+    protected void executeEngine(Engine egn, PrintWriter mod_jk) {
+	Container [] children = egn.findChildren();
+	for(int ii=0; ii < children.length; ii++) {
+	    if( children[ii] instanceof Host ) {
+		executeHost((Host)children[ii], mod_jk);
+	    } else if( children[ii] instanceof Context ) {
+		executeContext((Context)children[ii], mod_jk);
+	    }
+	}
+    }
+    /** Generate configuration files.  Override with method to generate
+        web server specific configuration.
+     */
+    protected void executeHost(Host hst, PrintWriter mod_jk) {
+	generateVhostHead(hst, mod_jk);
+	Container [] children = hst.findChildren();
+	for(int ii=0; ii < children.length; ii++) {
+	    if(children[ii] instanceof Context) {
+		executeContext((Context)children[ii],mod_jk);
+	    }
+	}
+	generateVhostTail(hst, mod_jk);
+    }
+    /**
+        executes the ApacheConfig interceptor. This method generates apache
+        configuration files for use with  mod_jk.
+        <p>
+        @param context a Context object.
+	@param mod_jk Writer for output.
+    */
+    public void executeContext(Context context, PrintWriter mod_jk){
+
+	if(context.getPath().length() > 0 || ! noRoot ) {
+	    String docRoot = context.getServletContext().getRealPath("/");
+	    if( forwardAll || docRoot == null)
+		generateStupidMappings( context, mod_jk );
+	    else
+		generateContextMappings( context, mod_jk);
+	}
+    }
+    protected void generateStupidMappings(Context context, PrintWriter mod_jk){
+    }
+    protected void generateContextMappings(Context context, PrintWriter mod_jk){
+    }
+    /** Get the output Writer.  Override with method to generate
+        web server specific configuration.
+     */
+    protected PrintWriter getWriter() throws IOException {
+	return null;
+    }
+    /** Get the host associated with this Container (if any).
+     */
+    protected Host getHost(Container child) {
+	while(child != null && ! (child instanceof Host) ) {
+	    child = child.getParent();
+	}
+	return (Host)child;
+    }
+
+    //-------------------- Properties --------------------
+
+    /** Append to config file.
+     *  Set to <code>true</code> if the config information should be 
+     *  appended.
+     */
+    public void setAppend(boolean apnd) {
+	append = apnd;
+    }
+    /** If false, we'll try to generate a config that will
+     *  let apache serve static files.
+     *  The default is true, forward all requests in a context
+     *  to tomcat.
+     */
+    public void setForwardAll( boolean b ) {
+        forwardAll=b;
+    }
+
+    /** Special option - do not generate mappings for the ROOT
+        context. The default is true, and will not generate the mappings,
+        not redirecting all pages to tomcat (since /* matches everything).
+        This means that the web server's root remains intact but isn't
+        completely servlet/JSP enabled. If the ROOT webapp can be configured
+        with the web server serving static files, there's no problem setting
+        this option to false. If not, then setting it true means the web
+        server will be out of picture for all requests.
+    */
+    public void setNoRoot( boolean b ) {
+        noRoot=b;
+    }
+    
+    /**
+        set a path to the parent directory of the
+        conf folder.  That is, the parent directory
+        within which path setters would be resolved against,
+        if relative.  For example if ConfigHome is set to "/home/tomcat"
+        and regConfig is set to "conf/mod_jk.conf" then the resulting 
+        path used would be: 
+        "/home/tomcat/conf/mod_jk.conf".</p>
+        <p>
+        However, if the path is set to an absolute path,
+        this attribute is ignored.
+        <p>
+        If not set, execute() will set this to TOMCAT_HOME.
+        <p>
+        @param dir - path to a directory
+    */
+    public void setConfigHome(String dir){
+        if( dir==null ) return;
+        File f=new File(dir);
+        if(!f.isDirectory()){
+            throw new IllegalArgumentException(
+                "BaseConfig.setConfigHome(): "+
+                "Configuration Home must be a directory! : "+dir);
+        }
+        configHome = f;
+    }
+
+    /**
+        set a path to the workers.properties file.
+        @param path String path to workers.properties file
+    */
+    public void setWorkersConfig(String path){
+        workersConfig= (path==null?null:new File(path));
+    }
+
+    /**
+        set the path to the log file
+        @param path String path to a file
+    */
+    public void setJkLog(String path){
+        jkLog= ( path==null?null:new File(path));
+    }
+
+    /** Set the verbosity level
+        ( use debug, error, etc. ) If not set, no log is written.
+     */
+    public void setJkDebug( String level ) {
+        jkDebug=level;
+    }
+
+    /**
+        Set the AJP worker.
+        @param worker The worker name
+     */
+    public void setJkWorker(String worker){
+        jkWorker = worker;
+    }
+
+    // -------------------- Initialize/guess defaults --------------------
+
+    /** Initialize defaults for properties that are not set
+        explicitely
+    */
+    protected void initProperties() {
+        tomcatHome = System.getProperty("catalina.home");
+        File tomcatDir = new File(tomcatHome);
+        if(configHome==null){
+            configHome=tomcatDir;
+        }
+    }
+
+    // -------------------- Config Utils  --------------------
+
+
+    /** Add an extension mapping. Override with method to generate
+        web server specific configuration
+     */
+    protected boolean addExtensionMapping( String ctxPath, String ext,
+					 PrintWriter pw )
+    {
+	return true;
+    }
+    
+    
+    /** Add a fulling specified mapping.  Override with method to generate
+        web server specific configuration
+     */
+    protected boolean addMapping( String fullPath, PrintWriter pw ) {
+	return true;
+    }
+
+    // -------------------- General Utils --------------------
+
+    protected String getAbsoluteDocBase(Context context)
+    {
+	// Calculate the absolute path of the document base
+	String docBase = context.getServletContext().getRealPath("/");
+	docBase = docBase.substring(0,docBase.length()-1);
+	if (!isAbsolute(docBase)){
+	    docBase = tomcatHome + "/" + docBase;
+	}
+	docBase = patch(docBase);
+        return docBase;
+    }
+
+    // ------------------ Grabbed from FileUtil -----------------
+    public static File getConfigFile( File base, File configDir, String defaultF )
+    {
+        if( base==null )
+            base=new File( defaultF );
+        if( ! base.isAbsolute() ) {
+            if( configDir != null )
+                base=new File( configDir, base.getPath());
+            else
+                base=new File( base.getAbsolutePath()); //??
+        }
+        File parent=new File(base.getParent());
+        if(!parent.exists()){
+            if(!parent.mkdirs()){
+                throw new RuntimeException(
+                    "Unable to create path to config file :"+
+                    base.getAbsolutePath());
+            }
+        }
+        return base;
+    }
+    public static String patch(String path) {
+        String patchPath = path;
+
+        // Move drive spec to the front of the path
+        if (patchPath.length() >= 3 &&
+            patchPath.charAt(0) == '/'  &&
+            Character.isLetter(patchPath.charAt(1)) &&
+            patchPath.charAt(2) == ':') {
+            patchPath=patchPath.substring(1,3)+"/"+patchPath.substring(3);
+        }
+
+        // Eliminate consecutive slashes after the drive spec
+	if (patchPath.length() >= 2 &&
+            Character.isLetter(patchPath.charAt(0)) &&
+            patchPath.charAt(1) == ':') {
+            char[] ca = patchPath.replace('/', '\\').toCharArray();
+            char c;
+            StringBuffer sb = new StringBuffer();
+
+            for (int i = 0; i < ca.length; i++) {
+                if ((ca[i] != '\\') ||
+                    (ca[i] == '\\' &&
+                        i > 0 &&
+                        ca[i - 1] != '\\')) {
+                    if (i == 0 &&
+                        Character.isLetter(ca[i]) &&
+                        i < ca.length - 1 &&
+                        ca[i + 1] == ':') {
+                        c = Character.toUpperCase(ca[i]);
+                    } else {
+                        c = ca[i];
+                    }
+
+                    sb.append(c);
+                }
+            }
+
+            patchPath = sb.toString();
+        }
+
+	// fix path on NetWare - all '/' become '\\' and remove duplicate '\\'
+	if (System.getProperty("os.name").startsWith("NetWare") &&
+	    path.length() >=3 &&
+	    path.indexOf(':') > 0) {
+	    char[] ca = patchPath.replace('/', '\\').toCharArray();
+	    StringBuffer sb = new StringBuffer();
+
+	    for (int i = 0; i < ca.length; i++) {
+		if ((ca[i] != '\\') ||
+		    (ca[i] == '\\' && i > 0 && ca[i - 1] != '\\')) {
+		    sb.append(ca[i]);
+		}
+	    }
+	    patchPath = sb.toString();
+	}
+
+        return patchPath;
+    }
+
+    public static boolean isAbsolute( String path ) {
+	// normal file
+	if( path.startsWith("/" ) ) return true;
+
+	if( path.startsWith(File.separator ) ) return true;
+
+	// win c:
+	if (path.length() >= 3 &&
+            Character.isLetter(path.charAt(0)) &&
+            path.charAt(1) == ':')
+	    return true;
+
+	// NetWare volume:
+	if (System.getProperty("os.name").startsWith("NetWare") &&
+	    path.length() >=3 &&
+	    path.indexOf(':') > 0)
+	    return true;
+
+	return false;
+    }
+
+    protected void log(String msg) {
+        log.info(msg);
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/ajp/tomcat4/config/IISConfig.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/ajp/tomcat4/config/IISConfig.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/ajp/tomcat4/config/IISConfig.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,303 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.ajp.tomcat4.config;
+
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.Date;
+
+import org.apache.catalina.Context;
+
+
+/**
+    Generates automatic IIS isapi_redirect configurations based on
+    the Tomcat server.xml settings and the war contexts
+    initialized during startup.
+    <p>
+    This config interceptor is enabled by inserting an IISConfig
+    element in the <b>&lt;ContextManager&gt;</b> tag body inside
+    the server.xml file like so:
+    <pre>
+    * < ContextManager ... >
+    *   ...
+    *   <<b>IISConfig</b> <i>options</i> />
+    *   ...
+    * < /ContextManager >
+    </pre>
+    where <i>options</i> can include any of the following attributes:
+    <ul>
+     <li><b>configHome</b> - default parent directory for the following paths.
+                            If not set, this defaults to TOMCAT_HOME. Ignored
+                            whenever any of the following paths is absolute.
+                             </li>
+     <li><b>regConfig</b> - path to use for writing IIS isapi_redirect registry
+                            file. If not set, defaults to
+                            "conf/auto/iis_redirect.reg".</li>
+     <li><b>workersConfig</b> - path to workers.properties file used by 
+                                isapi_redirect. If not set, defaults to
+                                "conf/jk/workers.properties".</li>
+     <li><b>uriConfig</b> - path to use for writing IIS isapi_redirect uriworkermap
+                            file. If not set, defaults to
+                            "conf/auto/uriworkermap.properties".</li>
+     <li><b>jkLog</b> - path to log file to be used by isapi_redirect.</li>
+     <li><b>jkDebug</b> - Loglevel setting.  May be debug, info, error, or emerg.
+                          If not set, defaults to emerg.</li>
+     <li><b>jkWorker</b> The desired worker.  Must be set to one of the workers
+                         defined in the workers.properties file. "ajp12", "ajp13"
+                         or "inprocess" are the workers found in the default
+                         workers.properties file. If not specified, defaults
+                         to "ajp13" if an Ajp13Interceptor is in use, otherwise
+                         it defaults to "ajp12".</li>
+     <li><b>forwardAll</b> - If true, forward all requests to Tomcat. This helps
+                             insure that all the behavior configured in the web.xml
+                             file functions correctly.  If false, let IIS serve
+                             static resources assuming it has been configured
+                             to do so. The default is true.
+                             Warning: When false, some configuration in
+                             the web.xml may not be duplicated in IIS.
+                             Review the uriworkermap file to see what
+                             configuration is actually being set in IIS.</li>
+     <li><b>noRoot</b> - If true, the root context is not mapped to
+                         Tomcat.  If false and forwardAll is true, all requests
+                         to the root context are mapped to Tomcat. If false and
+                         forwardAll is false, only JSP and servlets requests to
+                         the root context are mapped to Tomcat. When false,
+                         to correctly serve Tomcat's root context you must also
+                         modify the Home Directory setting in IIS
+                         to point to Tomcat's root context directory.
+                         Otherwise some content, such as the root index.html,
+                         will be served by IIS before isapi_redirect gets a chance
+                         to claim the request and pass it to Tomcat.
+                         The default is true.</li>
+    </ul>
+  <p>
+    @author Costin Manolache
+    @author Larry Isaacs
+    @author Gal Shachor
+    @author Bill Barker
+ */
+public class IISConfig extends BaseJkConfig  { 
+
+    public static final String WORKERS_CONFIG = "/conf/jk/workers.properties";
+    public static final String URI_WORKERS_MAP_CONFIG = "/conf/auto/uriworkermap.properties";
+    public static final String ISAPI_LOG_LOCATION = "/logs/iis_redirect.log";
+    public static final String ISAPI_REG_FILE = "/conf/auto/iis_redirect.reg";    
+
+    private File regConfig = null;
+    private File uriConfig = null;
+
+    public IISConfig() 
+    {
+    }
+
+    //-------------------- Properties --------------------
+    
+    /**
+        set the path to the output file for the auto-generated
+        isapi_redirect registry file.  If this path is relative
+        then getRegConfig() will resolve it absolutely against
+        the getConfigHome() path.
+        <p>
+        @param path String path to a file
+    */
+    public void setRegConfig(String path){
+	regConfig= (path==null)?null:new File(path);
+    }
+
+    /**
+        set a path to the uriworkermap.properties file.
+        @param path String path to uriworkermap.properties file
+    */
+    public void setUriConfig(String path){
+        uriConfig= (path==null?null:new File(path));
+    }
+
+    // -------------------- Initialize/guess defaults --------------------
+
+    /** Initialize defaults for properties that are not set
+	explicitely
+    */
+    protected void initProperties() {
+        super.initProperties();
+
+	regConfig=getConfigFile( regConfig, configHome, ISAPI_REG_FILE);
+	workersConfig=getConfigFile( workersConfig, configHome, WORKERS_CONFIG);
+	uriConfig=getConfigFile( uriConfig, configHome, URI_WORKERS_MAP_CONFIG);
+	jkLog=getConfigFile( jkLog, configHome, ISAPI_LOG_LOCATION);
+    }
+
+    // -------------------- Generate config --------------------
+
+    protected PrintWriter getWriter() throws IOException {
+	String abUriConfig = uriConfig.getAbsolutePath();
+	return new PrintWriter(new FileWriter(abUriConfig,append));        
+    }
+    protected boolean generateJkHead(PrintWriter mod_jk) {
+	try {
+	    PrintWriter regfile = new PrintWriter(new FileWriter(regConfig));
+	    log("Generating IIS registry file = "+regConfig );
+	    generateRegistrySettings(regfile);
+	    regfile.close();
+	} catch(IOException iex) {
+	    log("Unable to generate registry file " +regConfig);
+	    return false;
+	}
+	log("Generating IIS URI worker map file = "+uriConfig );
+	generateUriWorkerHeader(mod_jk);            
+	return true;
+    }
+
+    // -------------------- Config sections  --------------------
+
+    /** Writes the registry settings required by the IIS connector
+     */
+    private void generateRegistrySettings(PrintWriter regfile)
+    {
+        regfile.println("REGEDIT4");
+        regfile.println();
+        regfile.println("[HKEY_LOCAL_MACHINE\\SOFTWARE\\Apache Software Foundation\\Jakarta Isapi Redirector\\1.0]");
+        regfile.println("\"extension_uri\"=\"/jakarta/isapi_redirect.dll\"");
+        regfile.println("\"log_file\"=\"" + dubleSlash(jkLog.toString()) +"\"");
+        regfile.println("\"log_level\"=\"" + jkDebug + "\"");
+        regfile.println("\"worker_file\"=\"" + dubleSlash(workersConfig.toString()) +"\"");
+        regfile.println("\"worker_mount_file\"=\"" + dubleSlash(uriConfig.toString()) +"\"");
+    }
+
+    /** Writes the header information to the uriworkermap file
+     */
+    private void generateUriWorkerHeader(PrintWriter uri_worker)
+    {
+        uri_worker.println("###################################################################");		    
+        uri_worker.println("# Auto generated configuration. Dated: " +  new Date());
+        uri_worker.println("###################################################################");		    
+        uri_worker.println();
+
+        uri_worker.println("#");        
+        uri_worker.println("# Default worker to be used through our mappings");
+        uri_worker.println("#");        
+        uri_worker.println("default.worker=" + jkWorker);        
+        uri_worker.println();
+    }
+
+    /** Forward all requests for a context to tomcat.
+	The default.
+     */
+    protected void generateStupidMappings(Context context, PrintWriter uri_worker )
+    {
+        String ctxPath  = context.getPath();
+	String nPath=("".equals(ctxPath)) ? "/" : ctxPath;
+
+        if( noRoot &&  "".equals(ctxPath) ) {
+            log("Ignoring root context in forward-all mode  ");
+            return;
+        } 
+
+        // map all requests for this context to Tomcat
+        uri_worker.println(nPath +"=$(default.worker)");
+        if( "".equals(ctxPath) ) {
+            uri_worker.println(nPath +"*=$(default.worker)");
+            uri_worker.println(
+                    "# Note: To correctly serve the Tomcat's root context, IIS's Home Directory must");
+            uri_worker.println(
+                    "# must be set to: \"" + getAbsoluteDocBase(context) + "\"");
+        }
+        else
+            uri_worker.println(nPath +"/*=$(default.worker)");
+    }
+
+    protected void generateContextMappings(Context context, PrintWriter uri_worker )
+    {
+        String ctxPath  = context.getPath();
+	String nPath=("".equals(ctxPath)) ? "/" : ctxPath;
+
+        if( noRoot &&  "".equals(ctxPath) ) {
+            log("Ignoring root context in forward-all mode  ");
+            return;
+        } 
+
+        // Static files will be served by IIS
+        uri_worker.println();
+        uri_worker.println("#########################################################");		    
+        uri_worker.println("# Auto configuration for the " + nPath + " context.");
+        uri_worker.println("#########################################################");		    
+        uri_worker.println();
+
+        // Static mappings are not set in uriworkermap, but must be set with IIS admin.
+
+	// InvokerInterceptor - it doesn't have a container,
+	// but it's implemented using a special module.
+
+	// XXX we need to better collect all mappings
+
+	if(context.getLoginConfig() != null) {
+	    String loginPage = context.getLoginConfig().getLoginPage();
+	    if(loginPage != null) {
+		int lpos = loginPage.lastIndexOf("/");
+		String jscurl = loginPage.substring(0,lpos+1) + "j_security_check";
+		addMapping( ctxPath, jscurl, uri_worker);
+	    }
+	}
+		String [] servletMaps=context.findServletMappings();
+	for( int ii=0; ii < servletMaps.length ; ii++) {
+	    addMapping( ctxPath , servletMaps[ii] , uri_worker );
+	}
+    }
+
+    /** Add an IIS extension mapping.
+     */
+    protected boolean addMapping( String ctxPath, String ext,
+					 PrintWriter uri_worker )
+    {
+        if( debug > 0 )
+            log( "Adding extension map for " + ctxPath + "/*." + ext );
+	if(! ext.startsWith("/") )
+	    ext = "/" + ext;
+	if(ext.length() > 1)
+	    uri_worker.println(ctxPath + "/*." + ext + "=$(default.worker)");
+        return true;
+    }
+
+    /** Add a fulling specified IIS mapping.
+     */
+    protected boolean addMapping( String fullPath, PrintWriter uri_worker ) {
+        if( debug > 0 )
+            log( "Adding map for " + fullPath );
+        uri_worker.println(fullPath + "=$(default.worker)" );
+        return true;
+    }
+
+    // -------------------- Utils --------------------
+
+    private String dubleSlash(String in) 
+    {
+        StringBuffer sb = new StringBuffer();
+        
+        for(int i = 0 ; i < in.length() ; i++) {
+            char ch = in.charAt(i);
+            if('\\' == ch) {
+                sb.append("\\\\");
+            } else {
+                sb.append(ch);
+            }
+        }
+        
+        return sb.toString();
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/ajp/tomcat4/config/NSConfig.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/ajp/tomcat4/config/NSConfig.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/ajp/tomcat4/config/NSConfig.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,326 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.ajp.tomcat4.config;
+
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.Date;
+
+import org.apache.catalina.Context;
+
+
+/**
+    Generates automatic Netscape nsapi_redirect configurations based on
+    the Tomcat server.xml settings and the war contexts
+    initialized during startup.
+    <p>
+    This config interceptor is enabled by inserting an NSConfig
+    element in the <b>&lt;ContextManager&gt;</b> tag body inside
+    the server.xml file like so:
+    <pre>
+    * < ContextManager ... >
+    *   ...
+    *   <<b>NSConfig</b> <i>options</i> />
+    *   ...
+    * < /ContextManager >
+    </pre>
+    where <i>options</i> can include any of the following attributes:
+    <ul>
+     <li><b>configHome</b> - default parent directory for the following paths.
+                            If not set, this defaults to TOMCAT_HOME. Ignored
+                            whenever any of the following paths is absolute.
+                             </li>
+     <li><b>objConfig</b> - path to use for writing Netscape obj.conf
+                            file. If not set, defaults to
+                            "conf/auto/obj.conf".</li>
+     <li><b>objectName</b> - Name of the Object to execute the requests.
+                             Defaults to "servlet".</li>
+     <li><b>workersConfig</b> - path to workers.properties file used by 
+                                nsapi_redirect. If not set, defaults to
+                                "conf/jk/workers.properties".</li>
+     <li><b>nsapiJk</b> - path to Netscape mod_jk plugin file.  If not set,
+                        defaults to "bin/nsapi_redirect.dll" on windows,
+                        "bin/nsapi_rd.nlm" on netware, and
+                        "bin/nsapi_redirector.so" everywhere else.</li>
+     <li><b>jkLog</b> - path to log file to be used by nsapi_redirect.</li>
+     <li><b>jkDebug</b> - Loglevel setting.  May be debug, info, error, or emerg.
+                          If not set, defaults to emerg.</li>
+     <li><b>jkWorker</b> The desired worker.  Must be set to one of the workers
+                         defined in the workers.properties file. "ajp12", "ajp13"
+                         or "inprocess" are the workers found in the default
+                         workers.properties file. If not specified, defaults
+                         to "ajp13" if an Ajp13Interceptor is in use, otherwise
+                         it defaults to "ajp12".</li>
+     <li><b>forwardAll</b> - If true, forward all requests to Tomcat. This helps
+                             insure that all the behavior configured in the web.xml
+                             file functions correctly.  If false, let Netscape serve
+                             static resources assuming it has been configured
+                             to do so. The default is true.
+                             Warning: When false, some configuration in
+                             the web.xml may not be duplicated in Netscape.
+                             Review the uriworkermap file to see what
+                             configuration is actually being set in Netscape.</li>
+     <li><b>noRoot</b> - If true, the root context is not mapped to
+                         Tomcat.  If false and forwardAll is true, all requests
+                         to the root context are mapped to Tomcat. If false and
+                         forwardAll is false, only JSP and servlets requests to
+                         the root context are mapped to Tomcat. When false,
+                         to correctly serve Tomcat's root context you must also
+                         modify the Home Directory setting in Netscape
+                         to point to Tomcat's root context directory.
+                         Otherwise some content, such as the root index.html,
+                         will be served by Netscape before nsapi_redirect gets a chance
+                         to claim the request and pass it to Tomcat.
+                         The default is true.</li>
+    </ul>
+  <p>
+    @author Costin Manolache
+    @author Larry Isaacs
+    @author Gal Shachor
+    @author Bill Barker
+ */
+public class NSConfig  extends BaseJkConfig { 
+
+    public static final String WORKERS_CONFIG = "/conf/jk/workers.properties";
+    public static final String NS_CONFIG = "/conf/auto/obj.conf";
+    public static final String NSAPI_LOG_LOCATION = "/logs/nsapi_redirect.log";
+    /** default location of nsapi plug-in. */
+    public static final String NSAPI_REDIRECTOR;
+    
+    //set up some defaults based on OS type
+    static{
+        String os = System.getProperty("os.name").toLowerCase();
+        if(os.indexOf("windows")>=0){
+           NSAPI_REDIRECTOR = "bin/nsapi_redirect.dll";
+        }else if(os.indexOf("netware")>=0){
+           NSAPI_REDIRECTOR = "bin/nsapi_rd.nlm";
+        }else{
+           NSAPI_REDIRECTOR = "bin/nsapi_redirector.so";
+        }
+    }
+
+    private File objConfig = null;
+    private File nsapiJk = null;
+    private String objectName = "servlet";
+
+    public NSConfig() 
+    {
+    }
+
+    //-------------------- Properties --------------------
+    
+    /**
+        set the path to the output file for the auto-generated
+        isapi_redirect registry file.  If this path is relative
+        then getRegConfig() will resolve it absolutely against
+        the getConfigHome() path.
+        <p>
+        @param path String path to a file
+    */
+    public void setObjConfig(String path) {
+	objConfig= (path==null)?null:new File(path);
+    }
+
+    /**
+        set the path to the nsapi plugin module
+        @param path String path to a file
+    */
+    public void setNsapiJk(String path) {
+        nsapiJk=( path==null?null:new File(path));
+    }
+
+    /**
+        Set the name for the Object that implements the
+        jk_service call.
+        @param name Name of the obj.conf Object
+    */
+    public void setObjectName(String name) {
+        objectName = name;
+    }
+
+    // -------------------- Initialize/guess defaults --------------------
+
+    /** Initialize defaults for properties that are not set
+	explicitely
+    */
+    protected void initProperties() {
+        super.initProperties();
+
+	objConfig=getConfigFile( objConfig, configHome, NS_CONFIG);
+	workersConfig=getConfigFile( workersConfig, configHome, WORKERS_CONFIG);
+
+	if( nsapiJk == null )
+	    nsapiJk=new File(NSAPI_REDIRECTOR);
+	else
+	    nsapiJk =getConfigFile( nsapiJk, configHome, NSAPI_REDIRECTOR );
+	jkLog=getConfigFile( jkLog, configHome, NSAPI_LOG_LOCATION);
+    }
+
+    // -------------------- Generate config --------------------
+    protected PrintWriter getWriter() throws IOException {
+	String abObjConfig = objConfig.getAbsolutePath();
+	return new PrintWriter(new FileWriter(abObjConfig,append));
+    }
+    protected boolean generateJkHead(PrintWriter mod_jk) {
+	log("Generating netscape web server config = "+objConfig );
+	
+	generateNsapiHead( mod_jk );
+	
+	mod_jk.println("<Object name=default>");
+	return true;
+    }
+
+    private void generateNsapiHead(PrintWriter objfile)
+    {
+        objfile.println("###################################################################");		    
+        objfile.println("# Auto generated configuration. Dated: " +  new Date());
+        objfile.println("###################################################################");		    
+        objfile.println();
+
+        objfile.println("#");        
+        objfile.println("# You will need to merge the content of this file with your ");
+        objfile.println("# regular obj.conf and then restart (=stop + start) your Netscape server. ");
+        objfile.println("#");        
+        objfile.println();
+            
+        objfile.println("#");                    
+        objfile.println("# Loading the redirector into your server");
+        objfile.println("#");        
+        objfile.println();            
+        objfile.println("Init fn=\"load-modules\" funcs=\"jk_init,jk_service\" shlib=\"<put full path to the redirector here>\"");
+        objfile.println("Init fn=\"jk_init\" worker_file=\"" + 
+                        workersConfig.toString().replace('\\', '/') +  
+                        "\" log_level=\"" + jkDebug + "\" log_file=\"" + 
+                        jkLog.toString().replace('\\', '/') + 
+                        "\"");
+        objfile.println();
+    }
+
+    protected void generateJkTail(PrintWriter objfile)
+    {
+        objfile.println();
+        objfile.println("#######################################################");		    
+        objfile.println("# Protecting the WEB-INF and META-INF directories.");
+        objfile.println("#######################################################");		    
+        objfile.println("PathCheck fn=\"deny-existence\" path=\"*/WEB-INF/*\""); 
+        objfile.println("PathCheck fn=\"deny-existence\" path=\"*/META-INF/*\""); 
+        objfile.println();
+
+        objfile.println("</Object>");            
+        objfile.println();
+
+        objfile.println("#######################################################");		    
+        objfile.println("# New object to execute your servlet requests.");
+        objfile.println("#######################################################");		    
+        objfile.println("<Object name=" + objectName + ">");
+        objfile.println("ObjectType fn=force-type type=text/html");
+        objfile.println("Service fn=\"jk_service\" worker=\""+ jkWorker + "\" path=\"/*\"");
+        objfile.println("</Object>");
+        objfile.println();
+    }
+
+    // -------------------- Forward all mode --------------------
+    
+    /** Forward all requests for a context to tomcat.
+	The default.
+     */
+    protected void generateStupidMappings(Context context, PrintWriter objfile )
+    {
+        String ctxPath  = context.getPath();
+	String nPath=("".equals(ctxPath)) ? "/" : ctxPath;
+
+        if( noRoot &&  "".equals(ctxPath) ) {
+            log("Ignoring root context in forward-all mode  ");
+            return;
+        } 
+	objfile.println("<Object name=" + context.getName() + ">");
+
+        objfile.println("NameTrans fn=\"assign-name\" from=\"" + ctxPath + "\" name=\"" + objectName + "\""); 
+        objfile.println("NameTrans fn=\"assign-name\" from=\"" + ctxPath + "/*\" name=\"" + objectName + "\""); 
+	objfile.println("</Object>");
+    }
+
+
+    // -------------------- Netscape serves static mode --------------------
+    // This is not going to work for all apps. We fall back to stupid mode.
+    
+    protected void generateContextMappings(Context context, PrintWriter objfile )
+    {
+        String ctxPath  = context.getPath();
+	String nPath=("".equals(ctxPath)) ? "/" : ctxPath;
+
+        if( noRoot &&  "".equals(ctxPath) ) {
+            log("Ignoring root context in non-forward-all mode  ");
+            return;
+        } 
+	objfile.println("<Object name=" + context.getName() + ">");
+        // Static files will be served by Netscape
+        objfile.println("#########################################################");		    
+        objfile.println("# Auto configuration for the " + nPath + " context starts.");
+        objfile.println("#########################################################");		    
+        objfile.println();
+
+        // XXX Need to determine what if/how static mappings are done
+
+	// InvokerInterceptor - it doesn't have a container,
+	// but it's implemented using a special module.
+	
+	// XXX we need to better collect all mappings
+	if(context.getLoginConfig() != null) {
+	    String loginPage = context.getLoginConfig().getLoginPage();
+	    if(loginPage != null) {
+		int lpos = loginPage.lastIndexOf("/");
+		String jscurl = loginPage.substring(0,lpos+1) + "j_security_check";
+		addMapping( ctxPath, jscurl, objfile);
+	    }
+	}
+	
+	String [] servletMaps=context.findServletMappings();
+	for(int ii=0; ii < servletMaps.length; ii++) {
+	    addMapping( ctxPath , servletMaps[ii] , objfile );
+	}
+	objfile.println("</Object>");
+    }
+
+    /** Add a Netscape extension mapping.
+     */
+    protected boolean addMapping( String ctxPath, String ext,
+					 PrintWriter objfile )
+    {
+        if( debug > 0 )
+            log( "Adding extension map for " + ctxPath + "/*." + ext );
+	if(! ext.startsWith("/") )
+	    ext = "/" + ext;
+	if(ext.length() > 1)
+	    objfile.println("NameTrans fn=\"assign-name\" from=\"" +
+                    ctxPath  + ext + "\" name=\"" + objectName + "\""); 
+	return true;
+    }
+
+    /** Add a fulling specified Netscape mapping.
+     */
+    protected boolean addMapping( String fullPath, PrintWriter objfile ) {
+        if( debug > 0 )
+            log( "Adding map for " + fullPath );
+        objfile.println("NameTrans fn=\"assign-name\" from=\"" +
+                        fullPath + "\" name=\"" + objectName + "\""); 
+	return true;
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/coyote/ajp/AjpAprProcessor.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/coyote/ajp/AjpAprProcessor.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/coyote/ajp/AjpAprProcessor.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,1279 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.ajp;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InterruptedIOException;
+import java.net.InetAddress;
+import java.nio.ByteBuffer;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+
+import org.apache.coyote.ActionCode;
+import org.apache.coyote.ActionHook;
+import org.apache.coyote.Adapter;
+import org.apache.coyote.InputBuffer;
+import org.apache.coyote.OutputBuffer;
+import org.apache.coyote.Request;
+import org.apache.coyote.RequestInfo;
+import org.apache.coyote.Response;
+import org.apache.tomcat.jni.Socket;
+import org.apache.tomcat.jni.Status;
+import org.apache.tomcat.util.buf.ByteChunk;
+import org.apache.tomcat.util.buf.HexUtils;
+import org.apache.tomcat.util.buf.MessageBytes;
+import org.apache.tomcat.util.http.HttpMessages;
+import org.apache.tomcat.util.http.MimeHeaders;
+import org.apache.tomcat.util.net.AprEndpoint;
+import org.apache.tomcat.util.res.StringManager;
+import org.apache.tomcat.util.threads.ThreadWithAttributes;
+
+
+/**
+ * Processes HTTP requests.
+ *
+ * @author Remy Maucherat
+ * @author Henri Gomez
+ * @author Dan Milstein
+ * @author Keith Wannamaker
+ * @author Kevin Seguin
+ * @author Costin Manolache
+ * @author Bill Barker
+ */
+public class AjpAprProcessor implements ActionHook {
+
+
+    /**
+     * Logger.
+     */
+    protected static org.apache.commons.logging.Log log
+        = org.apache.commons.logging.LogFactory.getLog(AjpAprProcessor.class);
+
+    /**
+     * The string manager for this package.
+     */
+    protected static StringManager sm =
+        StringManager.getManager(Constants.Package);
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    public AjpAprProcessor(AprEndpoint endpoint) {
+
+        this.endpoint = endpoint;
+
+        request = new Request();
+        request.setInputBuffer(new SocketInputBuffer());
+
+        response = new Response();
+        response.setHook(this);
+        response.setOutputBuffer(new SocketOutputBuffer());
+        request.setResponse(response);
+
+        if (endpoint.getFirstReadTimeout() > 0) {
+            readTimeout = endpoint.getFirstReadTimeout() * 1000;
+        } else {
+            readTimeout = 100 * 1000;
+        }
+
+        // Allocate input and output buffers
+        inputBuffer = ByteBuffer.allocateDirect(Constants.MAX_PACKET_SIZE * 2);
+        inputBuffer.limit(0);
+        outputBuffer = ByteBuffer.allocateDirect(Constants.MAX_PACKET_SIZE * 2);
+
+        // Cause loading of HexUtils
+        int foo = HexUtils.DEC[0];
+
+        // Cause loading of HttpMessages
+        HttpMessages.getMessage(200);
+
+    }
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * Associated adapter.
+     */
+    protected Adapter adapter = null;
+
+
+    /**
+     * Request object.
+     */
+    protected Request request = null;
+
+
+    /**
+     * Response object.
+     */
+    protected Response response = null;
+
+
+    /**
+     * Header message. Note that this header is merely the one used during the
+     * processing of the first message of a "request", so it might not be a request
+     * header. It will stay unchanged during the processing of the whole request.
+     */
+    protected AjpMessage requestHeaderMessage = new AjpMessage();
+
+
+    /**
+     * Message used for response header composition.
+     */
+    protected AjpMessage responseHeaderMessage = new AjpMessage();
+
+
+    /**
+     * Body message.
+     */
+    protected AjpMessage bodyMessage = new AjpMessage();
+
+
+    /**
+     * Body message.
+     */
+    protected MessageBytes bodyBytes = MessageBytes.newInstance();
+
+
+    /**
+     * State flag.
+     */
+    protected boolean started = false;
+
+
+    /**
+     * Error flag.
+     */
+    protected boolean error = false;
+
+
+    /**
+     * Socket associated with the current connection.
+     */
+    protected long socket;
+
+
+    /**
+     * Host name (used to avoid useless B2C conversion on the host name).
+     */
+    protected char[] hostNameC = new char[0];
+
+
+    /**
+     * Associated endpoint.
+     */
+    protected AprEndpoint endpoint;
+
+
+    /**
+     * The socket timeout used when reading the first block of the request
+     * header.
+     */
+    protected long readTimeout;
+
+
+    /**
+     * Temp message bytes used for processing.
+     */
+    protected MessageBytes tmpMB = MessageBytes.newInstance();
+
+
+    /**
+     * Byte chunk for certs.
+     */
+    protected MessageBytes certificates = MessageBytes.newInstance();
+
+
+    /**
+     * End of stream flag.
+     */
+    protected boolean endOfStream = false;
+
+
+    /**
+     * Body empty flag.
+     */
+    protected boolean empty = true;
+
+
+    /**
+     * First read.
+     */
+    protected boolean first = true;
+
+
+    /**
+     * Replay read.
+     */
+    protected boolean replay = false;
+
+
+    /**
+     * Finished response.
+     */
+    protected boolean finished = false;
+
+
+    /**
+     * Direct buffer used for output.
+     */
+    protected ByteBuffer outputBuffer = null;
+
+
+    /**
+     * Direct buffer used for input.
+     */
+    protected ByteBuffer inputBuffer = null;
+
+
+    /**
+     * Direct buffer used for sending right away a get body message.
+     */
+    protected static final ByteBuffer getBodyMessageBuffer;
+
+
+    /**
+     * Direct buffer used for sending right away a pong message.
+     */
+    protected static final ByteBuffer pongMessageBuffer;
+
+
+    /**
+     * End message array.
+     */
+    protected static final byte[] endMessageArray;
+
+
+    // ----------------------------------------------------- Static Initializer
+
+
+    static {
+
+        // Set the get body message buffer
+        AjpMessage getBodyMessage = new AjpMessage();
+        getBodyMessage.reset();
+        getBodyMessage.appendByte(Constants.JK_AJP13_GET_BODY_CHUNK);
+        getBodyMessage.appendInt(Constants.MAX_READ_SIZE);
+        getBodyMessage.end();
+        getBodyMessageBuffer =
+            ByteBuffer.allocateDirect(getBodyMessage.getLen());
+        getBodyMessageBuffer.put(getBodyMessage.getBuffer(), 0,
+                getBodyMessage.getLen());
+
+        // Set the read body message buffer
+        AjpMessage pongMessage = new AjpMessage();
+        pongMessage.reset();
+        pongMessage.appendByte(Constants.JK_AJP13_CPONG_REPLY);
+        pongMessage.end();
+        pongMessageBuffer = ByteBuffer.allocateDirect(pongMessage.getLen());
+        pongMessageBuffer.put(pongMessage.getBuffer(), 0,
+                pongMessage.getLen());
+
+        // Allocate the end message array
+        AjpMessage endMessage = new AjpMessage();
+        endMessage.reset();
+        endMessage.appendByte(Constants.JK_AJP13_END_RESPONSE);
+        endMessage.appendByte(1);
+        endMessage.end();
+        endMessageArray = new byte[endMessage.getLen()];
+        System.arraycopy(endMessage.getBuffer(), 0, endMessageArray, 0,
+                endMessage.getLen());
+
+    }
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * Use Tomcat authentication ?
+     */
+    protected boolean tomcatAuthentication = true;
+    public boolean getTomcatAuthentication() { return tomcatAuthentication; }
+    public void setTomcatAuthentication(boolean tomcatAuthentication) { this.tomcatAuthentication = tomcatAuthentication; }
+
+
+    /**
+     * Required secret.
+     */
+    protected String requiredSecret = null;
+    public void setRequiredSecret(String requiredSecret) { this.requiredSecret = requiredSecret; }
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /** Get the request associated with this processor.
+     *
+     * @return The request
+     */
+    public Request getRequest() {
+        return request;
+    }
+
+
+    /**
+     * Process pipelined HTTP requests using the specified input and output
+     * streams.
+     *
+     * @throws IOException error during an I/O operation
+     */
+    public boolean process(long socket)
+        throws IOException {
+        ThreadWithAttributes thrA=
+                (ThreadWithAttributes)Thread.currentThread();
+        RequestInfo rp = request.getRequestProcessor();
+        thrA.setCurrentStage(endpoint, "parsing http request");
+        rp.setStage(org.apache.coyote.Constants.STAGE_PARSE);
+
+        // Setting up the socket
+        this.socket = socket;
+        Socket.setrbb(this.socket, inputBuffer);
+        Socket.setsbb(this.socket, outputBuffer);
+
+        // Error flag
+        error = false;
+
+        long soTimeout = endpoint.getSoTimeout();
+
+        int limit = 0;
+        if (endpoint.getFirstReadTimeout() > 0) {
+            limit = endpoint.getMaxThreads() / 2;
+        }
+
+        boolean openSocket = true;
+        boolean keptAlive = false;
+
+        while (started && !error) {
+
+            // Parsing the request header
+            try {
+                // Get first message of the request
+                if (!readMessage(requestHeaderMessage, true,
+                        keptAlive && (endpoint.getCurrentThreadsBusy() > limit))) {
+                    // This means that no data is available right now
+                    // (long keepalive), so that the processor should be recycled
+                    // and the method should return true
+                    rp.setStage(org.apache.coyote.Constants.STAGE_ENDED);
+                    break;
+                }
+                // Check message type, process right away and break if
+                // not regular request processing
+                int type = requestHeaderMessage.getByte();
+                if (type == Constants.JK_AJP13_CPING_REQUEST) {
+                    if (Socket.sendb(socket, pongMessageBuffer, 0,
+                            pongMessageBuffer.position()) < 0) {
+                        error = true;
+                    }
+                    continue;
+                } else if(type != Constants.JK_AJP13_FORWARD_REQUEST) {
+                    // Usually the servlet didn't read the previous request body
+                    if(log.isDebugEnabled()) {
+                        log.debug("Unexpected message: "+type);
+                    }
+                    continue;
+                }
+
+                keptAlive = true;
+                request.setStartTime(System.currentTimeMillis());
+            } catch (IOException e) {
+                error = true;
+                break;
+            } catch (Throwable t) {
+                log.debug(sm.getString("ajpprocessor.header.error"), t);
+                // 400 - Bad Request
+                response.setStatus(400);
+                error = true;
+            }
+
+            // Setting up filters, and parse some request headers
+            thrA.setCurrentStage(endpoint, "prepareRequest");
+            rp.setStage(org.apache.coyote.Constants.STAGE_PREPARE);
+            try {
+                prepareRequest();
+                thrA.setParam(endpoint, request.requestURI());
+            } catch (Throwable t) {
+                log.debug(sm.getString("ajpprocessor.request.prepare"), t);
+                // 400 - Internal Server Error
+                response.setStatus(400);
+                error = true;
+            }
+
+            // Process the request in the adapter
+            if (!error) {
+                try {
+                    thrA.setCurrentStage(endpoint, "service");
+                    rp.setStage(org.apache.coyote.Constants.STAGE_SERVICE);
+                    adapter.service(request, response);
+                } catch (InterruptedIOException e) {
+                    error = true;
+                } catch (Throwable t) {
+                    log.error(sm.getString("ajpprocessor.request.process"), t);
+                    // 500 - Internal Server Error
+                    response.setStatus(500);
+                    error = true;
+                }
+            }
+
+            // Finish the response if not done yet
+            if (!finished) {
+                try {
+                    finish();
+                } catch (Throwable t) {
+                    error = true;
+                }
+            }
+
+            // If there was an error, make sure the request is counted as
+            // and error, and update the statistics counter
+            if (error) {
+                response.setStatus(500);
+            }
+            request.updateCounters();
+
+            thrA.setCurrentStage(endpoint, "ended");
+            rp.setStage(org.apache.coyote.Constants.STAGE_KEEPALIVE);
+            recycle();
+
+        }
+
+        // Add the socket to the poller
+        if (!error) {
+            endpoint.getPoller().add(socket);
+        } else {
+            openSocket = false;
+        }
+
+        rp.setStage(org.apache.coyote.Constants.STAGE_ENDED);
+        recycle();
+
+        return openSocket;
+
+    }
+
+
+    // ----------------------------------------------------- ActionHook Methods
+
+
+    /**
+     * Send an action to the connector.
+     *
+     * @param actionCode Type of the action
+     * @param param Action parameter
+     */
+    public void action(ActionCode actionCode, Object param) {
+
+        if (actionCode == ActionCode.ACTION_COMMIT) {
+
+            if (response.isCommitted())
+                return;
+
+            // Validate and write response headers
+            try {
+                prepareResponse();
+            } catch (IOException e) {
+                // Set error flag
+                error = true;
+            }
+
+        } else if (actionCode == ActionCode.ACTION_CLIENT_FLUSH) {
+
+            if (!response.isCommitted()) {
+                // Validate and write response headers
+                try {
+                    prepareResponse();
+                } catch (IOException e) {
+                    // Set error flag
+                    error = true;
+                    return;
+                }
+            }
+
+            try {
+                flush();
+            } catch (IOException e) {
+                // Set error flag
+                error = true;
+            }
+
+        } else if (actionCode == ActionCode.ACTION_CLOSE) {
+            // Close
+
+            // End the processing of the current request, and stop any further
+            // transactions with the client
+
+            try {
+                finish();
+            } catch (IOException e) {
+                // Set error flag
+                error = true;
+            }
+
+        } else if (actionCode == ActionCode.ACTION_START) {
+
+            started = true;
+
+        } else if (actionCode == ActionCode.ACTION_STOP) {
+
+            started = false;
+
+        } else if (actionCode == ActionCode.ACTION_REQ_SSL_ATTRIBUTE ) {
+
+            if (!certificates.isNull()) {
+                ByteChunk certData = certificates.getByteChunk();
+                X509Certificate jsseCerts[] = null;
+                ByteArrayInputStream bais =
+                    new ByteArrayInputStream(certData.getBytes(),
+                            certData.getStart(),
+                            certData.getLength());
+                // Fill the first element.
+                try {
+                    CertificateFactory cf =
+                        CertificateFactory.getInstance("X.509");
+                    X509Certificate cert = (X509Certificate)
+                    cf.generateCertificate(bais);
+                    jsseCerts = new X509Certificate[1];
+                    jsseCerts[0] = cert;
+                    request.setAttribute(AprEndpoint.CERTIFICATE_KEY, jsseCerts);
+                } catch (java.security.cert.CertificateException e) {
+                    log.error(sm.getString("ajpprocessor.certs.fail"), e);
+                    return;
+                }
+            }
+
+        } else if (actionCode == ActionCode.ACTION_REQ_HOST_ATTRIBUTE) {
+
+            // Get remote host name using a DNS resolution
+            if (request.remoteHost().isNull()) {
+                try {
+                    request.remoteHost().setString(InetAddress.getByName
+                            (request.remoteAddr().toString()).getHostName());
+                } catch (IOException iex) {
+                    // Ignore
+                }
+            }
+
+        } else if (actionCode == ActionCode.ACTION_REQ_LOCAL_ADDR_ATTRIBUTE) {
+
+            // Copy from local name for now, which should simply be an address
+            request.localAddr().setString(request.localName().toString());
+
+        } else if (actionCode == ActionCode.ACTION_REQ_SET_BODY_REPLAY) {
+
+            request.setContentLength(-1); // reset content length
+            // Set the given bytes as the content
+            ByteChunk bc = (ByteChunk) param;
+            bodyBytes.setBytes(bc.getBytes(), bc.getStart(), bc.getLength());
+            first = false;
+            empty = false;
+            replay = true;
+
+        }
+
+
+    }
+
+
+    // ------------------------------------------------------ Connector Methods
+
+
+    /**
+     * Set the associated adapter.
+     *
+     * @param adapter the new adapter
+     */
+    public void setAdapter(Adapter adapter) {
+        this.adapter = adapter;
+    }
+
+
+    /**
+     * Get the associated adapter.
+     *
+     * @return the associated adapter
+     */
+    public Adapter getAdapter() {
+        return adapter;
+    }
+
+
+    // ------------------------------------------------------ Protected Methods
+
+
+    /**
+     * After reading the request headers, we have to setup the request filters.
+     */
+    protected void prepareRequest() {
+
+        // Translate the HTTP method code to a String.
+        byte methodCode = requestHeaderMessage.getByte();
+        if (methodCode != Constants.SC_M_JK_STORED) {
+            String methodName = Constants.methodTransArray[(int)methodCode - 1];
+            request.method().setString(methodName);
+        }
+
+        requestHeaderMessage.getBytes(request.protocol());
+        requestHeaderMessage.getBytes(request.requestURI());
+
+        requestHeaderMessage.getBytes(request.remoteAddr());
+        requestHeaderMessage.getBytes(request.remoteHost());
+        requestHeaderMessage.getBytes(request.localName());
+        request.setLocalPort(requestHeaderMessage.getInt());
+
+        boolean isSSL = requestHeaderMessage.getByte() != 0;
+        if (isSSL) {
+            request.scheme().setString("https");
+        }
+
+        // Decode headers
+        MimeHeaders headers = request.getMimeHeaders();
+
+        int hCount = requestHeaderMessage.getInt();
+        for(int i = 0 ; i < hCount ; i++) {
+            String hName = null;
+
+            // Header names are encoded as either an integer code starting
+            // with 0xA0, or as a normal string (in which case the first
+            // two bytes are the length).
+            int isc = requestHeaderMessage.peekInt();
+            int hId = isc & 0xFF;
+
+            MessageBytes vMB = null;
+            isc &= 0xFF00;
+            if(0xA000 == isc) {
+                requestHeaderMessage.getInt(); // To advance the read position
+                hName = Constants.headerTransArray[hId - 1];
+                vMB = headers.addValue(hName);
+            } else {
+                // reset hId -- if the header currently being read
+                // happens to be 7 or 8 bytes long, the code below
+                // will think it's the content-type header or the
+                // content-length header - SC_REQ_CONTENT_TYPE=7,
+                // SC_REQ_CONTENT_LENGTH=8 - leading to unexpected
+                // behaviour.  see bug 5861 for more information.
+                hId = -1;
+                requestHeaderMessage.getBytes(tmpMB);
+                ByteChunk bc = tmpMB.getByteChunk();
+                vMB = headers.addValue(bc.getBuffer(),
+                        bc.getStart(), bc.getLength());
+            }
+
+            requestHeaderMessage.getBytes(vMB);
+
+            if (hId == Constants.SC_REQ_CONTENT_LENGTH ||
+                    (hId == -1 && tmpMB.equalsIgnoreCase("Content-Length"))) {
+                // just read the content-length header, so set it
+                request.setContentLength( vMB.getInt() );
+            } else if (hId == Constants.SC_REQ_CONTENT_TYPE ||
+                    (hId == -1 && tmpMB.equalsIgnoreCase("Content-Type"))) {
+                // just read the content-type header, so set it
+                ByteChunk bchunk = vMB.getByteChunk();
+                request.contentType().setBytes(bchunk.getBytes(),
+                        bchunk.getOffset(),
+                        bchunk.getLength());
+            }
+        }
+
+        // Decode extra attributes
+        boolean secret = false;
+        byte attributeCode;
+        while ((attributeCode = requestHeaderMessage.getByte())
+                != Constants.SC_A_ARE_DONE) {
+
+            switch (attributeCode) {
+
+            case Constants.SC_A_REQ_ATTRIBUTE :
+                requestHeaderMessage.getBytes(tmpMB);
+                String n = tmpMB.toString();
+                requestHeaderMessage.getBytes(tmpMB);
+                String v = tmpMB.toString();
+                request.setAttribute(n, v);
+                break;
+
+            case Constants.SC_A_CONTEXT :
+                requestHeaderMessage.getBytes(tmpMB);
+                // nothing
+                break;
+
+            case Constants.SC_A_SERVLET_PATH :
+                requestHeaderMessage.getBytes(tmpMB);
+                // nothing
+                break;
+
+            case Constants.SC_A_REMOTE_USER :
+                if (tomcatAuthentication) {
+                    // ignore server
+                    requestHeaderMessage.getBytes(tmpMB);
+                } else {
+                    requestHeaderMessage.getBytes(request.getRemoteUser());
+                }
+                break;
+
+            case Constants.SC_A_AUTH_TYPE :
+                if (tomcatAuthentication) {
+                    // ignore server
+                    requestHeaderMessage.getBytes(tmpMB);
+                } else {
+                    requestHeaderMessage.getBytes(request.getAuthType());
+                }
+                break;
+
+            case Constants.SC_A_QUERY_STRING :
+                requestHeaderMessage.getBytes(request.queryString());
+                break;
+
+            case Constants.SC_A_JVM_ROUTE :
+                requestHeaderMessage.getBytes(request.instanceId());
+                break;
+
+            case Constants.SC_A_SSL_CERT :
+                request.scheme().setString("https");
+                // SSL certificate extraction is lazy, moved to JkCoyoteHandler
+                requestHeaderMessage.getBytes(certificates);
+                break;
+
+            case Constants.SC_A_SSL_CIPHER :
+                request.scheme().setString("https");
+                requestHeaderMessage.getBytes(tmpMB);
+                request.setAttribute(AprEndpoint.CIPHER_SUITE_KEY,
+                                     tmpMB.toString());
+                break;
+
+            case Constants.SC_A_SSL_SESSION :
+                request.scheme().setString("https");
+                requestHeaderMessage.getBytes(tmpMB);
+                request.setAttribute(AprEndpoint.SESSION_ID_KEY,
+                                     tmpMB.toString());
+                break;
+
+            case Constants.SC_A_SSL_KEY_SIZE :
+                request.setAttribute(AprEndpoint.KEY_SIZE_KEY,
+                                     new Integer(requestHeaderMessage.getInt()));
+                break;
+
+            case Constants.SC_A_STORED_METHOD:
+                requestHeaderMessage.getBytes(request.method());
+                break;
+
+            case Constants.SC_A_SECRET:
+                requestHeaderMessage.getBytes(tmpMB);
+                if (requiredSecret != null) {
+                    secret = true;
+                    if (!tmpMB.equals(requiredSecret)) {
+                        response.setStatus(403);
+                        error = true;
+                    }
+                }
+                break;
+
+            default:
+                // Ignore unknown attribute for backward compatibility
+                break;
+
+            }
+
+        }
+
+        // Check if secret was submitted if required
+        if ((requiredSecret != null) && !secret) {
+            response.setStatus(403);
+            error = true;
+        }
+
+        // Check for a full URI (including protocol://host:port/)
+        ByteChunk uriBC = request.requestURI().getByteChunk();
+        if (uriBC.startsWithIgnoreCase("http", 0)) {
+
+            int pos = uriBC.indexOf("://", 0, 3, 4);
+            int uriBCStart = uriBC.getStart();
+            int slashPos = -1;
+            if (pos != -1) {
+                byte[] uriB = uriBC.getBytes();
+                slashPos = uriBC.indexOf('/', pos + 3);
+                if (slashPos == -1) {
+                    slashPos = uriBC.getLength();
+                    // Set URI as "/"
+                    request.requestURI().setBytes
+                        (uriB, uriBCStart + pos + 1, 1);
+                } else {
+                    request.requestURI().setBytes
+                        (uriB, uriBCStart + slashPos,
+                         uriBC.getLength() - slashPos);
+                }
+                MessageBytes hostMB = headers.setValue("host");
+                hostMB.setBytes(uriB, uriBCStart + pos + 3,
+                                slashPos - pos - 3);
+            }
+
+        }
+
+        MessageBytes valueMB = request.getMimeHeaders().getValue("host");
+        parseHost(valueMB);
+
+    }
+
+
+    /**
+     * Parse host.
+     */
+    public void parseHost(MessageBytes valueMB) {
+
+        if (valueMB == null || (valueMB != null && valueMB.isNull()) ) {
+            // HTTP/1.0
+            // Default is what the socket tells us. Overriden if a host is
+            // found/parsed
+            request.setServerPort(endpoint.getPort());
+            return;
+        }
+
+        ByteChunk valueBC = valueMB.getByteChunk();
+        byte[] valueB = valueBC.getBytes();
+        int valueL = valueBC.getLength();
+        int valueS = valueBC.getStart();
+        int colonPos = -1;
+        if (hostNameC.length < valueL) {
+            hostNameC = new char[valueL];
+        }
+
+        boolean ipv6 = (valueB[valueS] == '[');
+        boolean bracketClosed = false;
+        for (int i = 0; i < valueL; i++) {
+            char b = (char) valueB[i + valueS];
+            hostNameC[i] = b;
+            if (b == ']') {
+                bracketClosed = true;
+            } else if (b == ':') {
+                if (!ipv6 || bracketClosed) {
+                    colonPos = i;
+                    break;
+                }
+            }
+        }
+
+        if (colonPos < 0) {
+            if (request.scheme().equalsIgnoreCase("https")) {
+                // 443 - Default HTTPS port
+                request.setServerPort(443);
+            } else {
+                // 80 - Default HTTTP port
+                request.setServerPort(80);
+            }
+            request.serverName().setChars(hostNameC, 0, valueL);
+        } else {
+
+            request.serverName().setChars(hostNameC, 0, colonPos);
+
+            int port = 0;
+            int mult = 1;
+            for (int i = valueL - 1; i > colonPos; i--) {
+                int charValue = HexUtils.DEC[(int) valueB[i + valueS]];
+                if (charValue == -1) {
+                    // Invalid character
+                    error = true;
+                    // 400 - Bad request
+                    response.setStatus(400);
+                    break;
+                }
+                port = port + (charValue * mult);
+                mult = 10 * mult;
+            }
+            request.setServerPort(port);
+
+        }
+
+    }
+
+
+    /**
+     * When committing the response, we have to validate the set of headers, as
+     * well as setup the response filters.
+     */
+    protected void prepareResponse()
+        throws IOException {
+
+        response.setCommitted(true);
+
+        responseHeaderMessage.reset();
+        responseHeaderMessage.appendByte(Constants.JK_AJP13_SEND_HEADERS);
+
+        // HTTP header contents
+        responseHeaderMessage.appendInt(response.getStatus());
+        String message = response.getMessage();
+        if (message == null){
+            message = HttpMessages.getMessage(response.getStatus());
+        } else {
+            message = message.replace('\n', ' ').replace('\r', ' ');
+        }
+        tmpMB.setString(message);
+        responseHeaderMessage.appendBytes(tmpMB);
+
+        // Special headers
+        MimeHeaders headers = response.getMimeHeaders();
+        String contentType = response.getContentType();
+        if (contentType != null) {
+            headers.setValue("Content-Type").setString(contentType);
+        }
+        String contentLanguage = response.getContentLanguage();
+        if (contentLanguage != null) {
+            headers.setValue("Content-Language").setString(contentLanguage);
+        }
+        int contentLength = response.getContentLength();
+        if (contentLength >= 0) {
+            headers.setValue("Content-Length").setInt(contentLength);
+        }
+
+        // Other headers
+        int numHeaders = headers.size();
+        responseHeaderMessage.appendInt(numHeaders);
+        for (int i = 0; i < numHeaders; i++) {
+            MessageBytes hN = headers.getName(i);
+            responseHeaderMessage.appendBytes(hN);
+            MessageBytes hV=headers.getValue(i);
+            responseHeaderMessage.appendBytes(hV);
+        }
+
+        // Write to buffer
+        responseHeaderMessage.end();
+        outputBuffer.put(responseHeaderMessage.getBuffer(), 0, responseHeaderMessage.getLen());
+
+    }
+
+
+    /**
+     * Finish AJP response.
+     */
+    protected void finish()
+        throws IOException {
+
+        if (!response.isCommitted()) {
+            // Validate and write response headers
+            try {
+                prepareResponse();
+            } catch (IOException e) {
+                // Set error flag
+                error = true;
+            }
+        }
+
+        if (finished)
+            return;
+
+        finished = true;
+
+        // Add the end message
+        if (outputBuffer.position() + endMessageArray.length > outputBuffer.capacity()) {
+            flush();
+        }
+        outputBuffer.put(endMessageArray);
+        flush();
+
+    }
+
+
+    /**
+     * Read at least the specified amount of bytes, and place them
+     * in the input buffer.
+     */
+    protected boolean read(int n)
+        throws IOException {
+
+        if (inputBuffer.capacity() - inputBuffer.limit() <=
+                n - inputBuffer.remaining()) {
+            inputBuffer.compact();
+            inputBuffer.limit(inputBuffer.position());
+            inputBuffer.position(0);
+        }
+        while (inputBuffer.remaining() < n) {
+            int nRead = Socket.recvbb
+                (socket, inputBuffer.limit(),
+                        inputBuffer.capacity() - inputBuffer.limit());
+            if (nRead > 0) {
+                inputBuffer.limit(inputBuffer.limit() + nRead);
+            } else {
+                throw new IOException(sm.getString("ajpprotocol.failedread"));
+            }
+        }
+
+        return true;
+
+    }
+
+
+    /**
+     * Read at least the specified amount of bytes, and place them
+     * in the input buffer.
+     */
+    protected boolean readt(int n, boolean useAvailableData)
+        throws IOException {
+
+        if (useAvailableData && inputBuffer.remaining() == 0) {
+            return false;
+        }
+        if (inputBuffer.capacity() - inputBuffer.limit() <=
+                n - inputBuffer.remaining()) {
+            inputBuffer.compact();
+            inputBuffer.limit(inputBuffer.position());
+            inputBuffer.position(0);
+        }
+        while (inputBuffer.remaining() < n) {
+            int nRead = Socket.recvbbt
+                (socket, inputBuffer.limit(),
+                        inputBuffer.capacity() - inputBuffer.limit(), readTimeout);
+            if (nRead > 0) {
+                inputBuffer.limit(inputBuffer.limit() + nRead);
+            } else {
+                if ((-nRead) == Status.ETIMEDOUT || (-nRead) == Status.TIMEUP) {
+                    return false;
+                } else {
+                    throw new IOException(sm.getString("ajpprotocol.failedread"));
+                }
+            }
+        }
+
+        return true;
+
+    }
+
+
+    /** Receive a chunk of data. Called to implement the
+     *  'special' packet in ajp13 and to receive the data
+     *  after we send a GET_BODY packet
+     */
+    public boolean receive() throws IOException {
+
+        first = false;
+        bodyMessage.reset();
+        readMessage(bodyMessage, false, false);
+
+        // No data received.
+        if (bodyMessage.getLen() == 0) {
+            // just the header
+            // Don't mark 'end of stream' for the first chunk.
+            return false;
+        }
+        int blen = bodyMessage.peekInt();
+        if (blen == 0) {
+            return false;
+        }
+
+        bodyMessage.getBytes(bodyBytes);
+        empty = false;
+        return true;
+    }
+
+    /**
+     * Get more request body data from the web server and store it in the
+     * internal buffer.
+     *
+     * @return true if there is more data, false if not.
+     */
+    private boolean refillReadBuffer() throws IOException {
+        // If the server returns an empty packet, assume that that end of
+        // the stream has been reached (yuck -- fix protocol??).
+        // FORM support
+        if (replay) {
+            endOfStream = true; // we've read everything there is
+        }
+        if (endOfStream) {
+            return false;
+        }
+
+        // Request more data immediately
+        Socket.sendb(socket, getBodyMessageBuffer, 0,
+                getBodyMessageBuffer.position());
+
+        boolean moreData = receive();
+        if( !moreData ) {
+            endOfStream = true;
+        }
+        return moreData;
+    }
+
+
+    /**
+     * Read an AJP message.
+     *
+     * @param first is true if the message is the first in the request, which
+     *        will cause a short duration blocking read
+     * @return true if the message has been read, false if the short read
+     *         didn't return anything
+     * @throws IOException any other failure, including incomplete reads
+     */
+    protected boolean readMessage(AjpMessage message, boolean first,
+            boolean useAvailableData)
+        throws IOException {
+
+        byte[] buf = message.getBuffer();
+        int headerLength = message.getHeaderLength();
+
+        if (first) {
+            if (!readt(headerLength, useAvailableData)) {
+                return false;
+            }
+        } else {
+            read(headerLength);
+        }
+        inputBuffer.get(message.getBuffer(), 0, headerLength);
+        message.processHeader();
+        read(message.getLen());
+        inputBuffer.get(message.getBuffer(), headerLength, message.getLen());
+
+        return true;
+
+    }
+
+
+    /**
+     * Recycle the processor.
+     */
+    public void recycle() {
+
+        // Recycle Request object
+        first = true;
+        endOfStream = false;
+        empty = true;
+        replay = false;
+        finished = false;
+        request.recycle();
+        response.recycle();
+        certificates.recycle();
+
+        inputBuffer.clear();
+        inputBuffer.limit(0);
+        outputBuffer.clear();
+
+    }
+
+
+    /**
+     * Callback to write data from the buffer.
+     */
+    protected void flush()
+        throws IOException {
+        if (outputBuffer.position() > 0) {
+            if (Socket.sendbb(socket, 0, outputBuffer.position()) < 0) {
+                throw new IOException();
+            }
+            outputBuffer.clear();
+        }
+    }
+
+
+    // ------------------------------------- InputStreamInputBuffer Inner Class
+
+
+    /**
+     * This class is an input buffer which will read its data from an input
+     * stream.
+     */
+    protected class SocketInputBuffer
+        implements InputBuffer {
+
+
+        /**
+         * Read bytes into the specified chunk.
+         */
+        public int doRead(ByteChunk chunk, Request req )
+            throws IOException {
+
+            if (endOfStream) {
+                return -1;
+            }
+            if (first && req.getContentLength() > 0) {
+                // Handle special first-body-chunk
+                if (!receive()) {
+                    return 0;
+                }
+            } else if (empty) {
+                if (!refillReadBuffer()) {
+                    return -1;
+                }
+            }
+            ByteChunk bc = bodyBytes.getByteChunk();
+            chunk.setBytes(bc.getBuffer(), bc.getStart(), bc.getLength());
+            empty = true;
+            return chunk.getLength();
+
+        }
+
+    }
+
+
+    // ----------------------------------- OutputStreamOutputBuffer Inner Class
+
+
+    /**
+     * This class is an output buffer which will write data to an output
+     * stream.
+     */
+    protected class SocketOutputBuffer
+        implements OutputBuffer {
+
+
+        /**
+         * Write chunk.
+         */
+        public int doWrite(ByteChunk chunk, Response res)
+            throws IOException {
+
+            if (!response.isCommitted()) {
+                // Validate and write response headers
+                try {
+                    prepareResponse();
+                } catch (IOException e) {
+                    // Set error flag
+                    error = true;
+                }
+            }
+
+            int len = chunk.getLength();
+            // 4 - hardcoded, byte[] marshalling overhead
+            int chunkSize = Constants.MAX_SEND_SIZE;
+            int off = 0;
+            while (len > 0) {
+                int thisTime = len;
+                if (thisTime > chunkSize) {
+                    thisTime = chunkSize;
+                }
+                len -= thisTime;
+                if (outputBuffer.position() + thisTime +
+                    Constants.H_SIZE + 4 > outputBuffer.capacity()) {
+                    flush();
+                }
+                outputBuffer.put((byte) 0x41);
+                outputBuffer.put((byte) 0x42);
+                outputBuffer.putShort((short) (thisTime + 4));
+                outputBuffer.put(Constants.JK_AJP13_SEND_BODY_CHUNK);
+                outputBuffer.putShort((short) thisTime);
+                outputBuffer.put(chunk.getBytes(), chunk.getOffset() + off, thisTime);
+                outputBuffer.put((byte) 0x00);
+                off += thisTime;
+            }
+
+            return chunk.getLength();
+
+        }
+
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/coyote/ajp/AjpAprProtocol.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/coyote/ajp/AjpAprProtocol.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/coyote/ajp/AjpAprProtocol.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,517 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.ajp;
+
+import java.net.InetAddress;
+import java.net.URLEncoder;
+import java.util.Hashtable;
+import java.util.Iterator;
+
+import javax.management.MBeanRegistration;
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+
+import org.apache.commons.modeler.Registry;
+import org.apache.coyote.ActionCode;
+import org.apache.coyote.ActionHook;
+import org.apache.coyote.Adapter;
+import org.apache.coyote.ProtocolHandler;
+import org.apache.coyote.RequestGroupInfo;
+import org.apache.coyote.RequestInfo;
+import org.apache.tomcat.util.net.AprEndpoint;
+import org.apache.tomcat.util.net.AprEndpoint.Handler;
+import org.apache.tomcat.util.res.StringManager;
+
+
+/**
+ * Abstract the protocol implementation, including threading, etc.
+ * Processor is single threaded and specific to stream-based protocols,
+ * will not fit Jk protocols like JNI.
+ *
+ * @author Remy Maucherat
+ * @author Costin Manolache
+ */
+public class AjpAprProtocol 
+    implements ProtocolHandler, MBeanRegistration {
+    
+    
+    protected static org.apache.commons.logging.Log log =
+        org.apache.commons.logging.LogFactory.getLog(AjpAprProtocol.class);
+
+    /**
+     * The string manager for this package.
+     */
+    protected static StringManager sm =
+        StringManager.getManager(Constants.Package);
+
+
+    // ------------------------------------------------------------ Constructor
+
+
+    public AjpAprProtocol() {
+        cHandler = new AjpConnectionHandler(this);
+        setSoLinger(Constants.DEFAULT_CONNECTION_LINGER);
+        setSoTimeout(Constants.DEFAULT_CONNECTION_TIMEOUT);
+        //setServerSoTimeout(Constants.DEFAULT_SERVER_SOCKET_TIMEOUT);
+        setTcpNoDelay(Constants.DEFAULT_TCP_NO_DELAY);
+    }
+
+    
+    // ----------------------------------------------------- Instance Variables
+
+
+    protected ObjectName tpOname;
+    
+    
+    protected ObjectName rgOname;
+
+
+    /**
+     * Associated APR endpoint.
+     */
+    protected AprEndpoint ep = new AprEndpoint();
+
+
+    /**
+     * Configuration attributes.
+     */
+    protected Hashtable attributes = new Hashtable();
+
+
+    /**
+     * Should authentication be done in the native webserver layer, 
+     * or in the Servlet container ?
+     */
+    protected boolean tomcatAuthentication = true;
+
+
+    /**
+     * Required secret.
+     */
+    protected String requiredSecret = null;
+
+
+    /**
+     * Adapter which will process the requests recieved by this endpoint.
+     */
+    private Adapter adapter;
+    
+    
+    /**
+     * Connection handler for AJP.
+     */
+    private AjpConnectionHandler cHandler;
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /** 
+     * Pass config info
+     */
+    public void setAttribute(String name, Object value) {
+        if (log.isTraceEnabled()) {
+            log.trace(sm.getString("ajpprotocol.setattribute", name, value));
+        }
+        attributes.put(name, value);
+    }
+
+    public Object getAttribute(String key) {
+        if (log.isTraceEnabled()) {
+            log.trace(sm.getString("ajpprotocol.getattribute", key));
+        }
+        return attributes.get(key);
+    }
+
+
+    public Iterator getAttributeNames() {
+        return attributes.keySet().iterator();
+    }
+
+
+    /**
+     * Set a property.
+     */
+    public void setProperty(String name, String value) {
+        setAttribute(name, value);
+    }
+
+
+    /**
+     * Get a property
+     */
+    public String getProperty(String name) {
+        return (String) getAttribute(name);
+    }
+
+
+    /**
+     * The adapter, used to call the connector
+     */
+    public void setAdapter(Adapter adapter) {
+        this.adapter = adapter;
+    }
+
+
+    public Adapter getAdapter() {
+        return adapter;
+    }
+
+
+    /** Start the protocol
+     */
+    public void init() throws Exception {
+        ep.setName(getName());
+        ep.setHandler(cHandler);
+        ep.setUseSendfile(false);
+
+        try {
+            ep.init();
+        } catch (Exception ex) {
+            log.error(sm.getString("ajpprotocol.endpoint.initerror"), ex);
+            throw ex;
+        }
+        if (log.isInfoEnabled()) {
+            log.info(sm.getString("ajpprotocol.init", getName()));
+        }
+    }
+
+
+    public void start() throws Exception {
+        if (this.domain != null ) {
+            try {
+                tpOname = new ObjectName
+                    (domain + ":" + "type=ThreadPool,name=" + getName());
+                Registry.getRegistry(null, null)
+                    .registerComponent(ep, tpOname, null );
+            } catch (Exception e) {
+                log.error("Can't register threadpool" );
+            }
+            rgOname = new ObjectName
+                (domain + ":type=GlobalRequestProcessor,name=" + getName());
+            Registry.getRegistry(null, null).registerComponent
+                (cHandler.global, rgOname, null);
+        }
+
+        try {
+            ep.start();
+        } catch (Exception ex) {
+            log.error(sm.getString("ajpprotocol.endpoint.starterror"), ex);
+            throw ex;
+        }
+        if (log.isInfoEnabled())
+            log.info(sm.getString("ajpprotocol.start", getName()));
+    }
+
+    public void pause() throws Exception {
+        try {
+            ep.pause();
+        } catch (Exception ex) {
+            log.error(sm.getString("ajpprotocol.endpoint.pauseerror"), ex);
+            throw ex;
+        }
+        if (log.isInfoEnabled())
+            log.info(sm.getString("ajpprotocol.pause", getName()));
+    }
+
+    public void resume() throws Exception {
+        try {
+            ep.resume();
+        } catch (Exception ex) {
+            log.error(sm.getString("ajpprotocol.endpoint.resumeerror"), ex);
+            throw ex;
+        }
+        if (log.isInfoEnabled())
+            log.info(sm.getString("ajpprotocol.resume", getName()));
+    }
+
+    public void destroy() throws Exception {
+        if (log.isInfoEnabled())
+            log.info(sm.getString("ajpprotocol.stop", getName()));
+        ep.destroy();
+        if (tpOname!=null)
+            Registry.getRegistry(null, null).unregisterComponent(tpOname);
+        if (rgOname != null)
+            Registry.getRegistry(null, null).unregisterComponent(rgOname);
+    }
+
+
+    public int getMaxThreads() {
+        return ep.getMaxThreads();
+    }
+
+    public void setMaxThreads(int maxThreads) {
+        ep.setMaxThreads(maxThreads);
+        setAttribute("maxThreads", "" + maxThreads);
+    }
+
+    public void setThreadPriority(int threadPriority) {
+        ep.setThreadPriority(threadPriority);
+        setAttribute("threadPriority", "" + threadPriority);
+    }
+    
+    public int getThreadPriority() {
+        return ep.getThreadPriority();
+    }
+    
+
+    public int getBacklog() {
+        return ep.getBacklog();
+    }
+
+
+    public void setBacklog( int i ) {
+        ep.setBacklog(i);
+        setAttribute("backlog", "" + i);
+    }
+
+
+    public int getPort() {
+        return ep.getPort();
+    }
+
+
+    public void setPort( int port ) {
+        ep.setPort(port);
+        setAttribute("port", "" + port);
+    }
+
+
+    public boolean getUseSendfile() {
+        return ep.getUseSendfile();
+    }
+
+
+    public void setUseSendfile(boolean useSendfile) {
+        // No sendfile for AJP
+    }
+
+
+    public InetAddress getAddress() {
+        return ep.getAddress();
+    }
+
+
+    public void setAddress(InetAddress ia) {
+        ep.setAddress(ia);
+        setAttribute("address", "" + ia);
+    }
+
+
+    public String getName() {
+        String encodedAddr = "";
+        if (getAddress() != null) {
+            encodedAddr = "" + getAddress();
+            if (encodedAddr.startsWith("/"))
+                encodedAddr = encodedAddr.substring(1);
+            encodedAddr = URLEncoder.encode(encodedAddr) + "-";
+        }
+        return ("ajp-" + encodedAddr + ep.getPort());
+    }
+
+
+    public boolean getTcpNoDelay() {
+        return ep.getTcpNoDelay();
+    }
+
+
+    public void setTcpNoDelay(boolean b) {
+        ep.setTcpNoDelay(b);
+        setAttribute("tcpNoDelay", "" + b);
+    }
+
+
+    public boolean getTomcatAuthentication() {
+        return tomcatAuthentication;
+    }
+
+
+    public void setTomcatAuthentication(boolean tomcatAuthentication) {
+        this.tomcatAuthentication = tomcatAuthentication;
+    }
+
+
+    public int getFirstReadTimeout() {
+        return ep.getFirstReadTimeout();
+    }
+
+
+    public void setFirstReadTimeout(int i) {
+        ep.setFirstReadTimeout(i);
+        setAttribute("firstReadTimeout", "" + i);
+    }
+
+
+    public int getPollTime() {
+        return ep.getPollTime();
+    }
+
+
+    public void setPollTime(int i) {
+        ep.setPollTime(i);
+        setAttribute("pollTime", "" + i);
+    }
+
+
+    public void setPollerSize(int i) {
+        ep.setPollerSize(i); 
+        setAttribute("pollerSize", "" + i);
+    }
+
+
+    public int getPollerSize() {
+        return ep.getPollerSize();
+    }
+
+
+    public int getSoLinger() {
+        return ep.getSoLinger();
+    }
+
+
+    public void setSoLinger(int i) {
+        ep.setSoLinger(i);
+        setAttribute("soLinger", "" + i);
+    }
+
+
+    public int getSoTimeout() {
+        return ep.getSoTimeout();
+    }
+
+
+    public void setSoTimeout( int i ) {
+        ep.setSoTimeout(i);
+        setAttribute("soTimeout", "" + i);
+    }
+
+    
+    public void setRequiredSecret(String requiredSecret) {
+        this.requiredSecret = requiredSecret;
+    }
+    
+    
+    // --------------------------------------  AjpConnectionHandler Inner Class
+
+
+    protected static class AjpConnectionHandler implements Handler {
+        protected AjpAprProtocol proto;
+        protected static int count = 0;
+        protected RequestGroupInfo global=new RequestGroupInfo();
+        protected ThreadLocal localProcessor = new ThreadLocal();
+
+        public AjpConnectionHandler(AjpAprProtocol proto) {
+            this.proto = proto;
+        }
+
+        public boolean process(long socket) {
+            AjpAprProcessor processor = null;
+            try {
+                processor = (AjpAprProcessor) localProcessor.get();
+                if (processor == null) {
+                    processor = new AjpAprProcessor(proto.ep);
+                    processor.setAdapter(proto.adapter);
+                    processor.setTomcatAuthentication(proto.tomcatAuthentication);
+                    processor.setRequiredSecret(proto.requiredSecret);
+                    localProcessor.set(processor);
+                    if (proto.getDomain() != null) {
+                        synchronized (this) {
+                            try {
+                                RequestInfo rp = processor.getRequest().getRequestProcessor();
+                                rp.setGlobalProcessor(global);
+                                ObjectName rpName = new ObjectName
+                                    (proto.getDomain() + ":type=RequestProcessor,worker="
+                                        + proto.getName() + ",name=AjpRequest" + count++ );
+                                Registry.getRegistry(null, null)
+                                    .registerComponent(rp, rpName, null);
+                            } catch (Exception ex) {
+                                log.warn(sm.getString("ajpprotocol.request.register"));
+                            }
+                        }
+                    }
+                }
+
+                if (processor instanceof ActionHook) {
+                    ((ActionHook) processor).action(ActionCode.ACTION_START, null);
+                }
+
+                return processor.process(socket);
+
+            } catch(java.net.SocketException e) {
+                // SocketExceptions are normal
+                AjpAprProtocol.log.debug
+                    (sm.getString
+                     ("ajpprotocol.proto.socketexception.debug"), e);
+            } catch (java.io.IOException e) {
+                // IOExceptions are normal
+                AjpAprProtocol.log.debug
+                    (sm.getString
+                     ("ajpprotocol.proto.ioexception.debug"), e);
+            }
+            // Future developers: if you discover any other
+            // rare-but-nonfatal exceptions, catch them here, and log as
+            // above.
+            catch (Throwable e) {
+                // 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.
+                AjpAprProtocol.log.error
+                    (sm.getString("ajpprotocol.proto.error"), e);
+            } finally {
+                if (processor instanceof ActionHook) {
+                    ((ActionHook) processor).action(ActionCode.ACTION_STOP, null);
+                }
+            }
+            return false;
+        }
+    }
+
+
+    // -------------------- Various implementation classes --------------------
+
+
+    protected String domain;
+    protected ObjectName oname;
+    protected MBeanServer mserver;
+
+    public ObjectName getObjectName() {
+        return oname;
+    }
+
+    public String getDomain() {
+        return domain;
+    }
+
+    public ObjectName preRegister(MBeanServer server,
+                                  ObjectName name) throws Exception {
+        oname=name;
+        mserver=server;
+        domain=name.getDomain();
+        return name;
+    }
+
+    public void postRegister(Boolean registrationDone) {
+    }
+
+    public void preDeregister() throws Exception {
+    }
+
+    public void postDeregister() {
+    }
+    
+ 
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/coyote/ajp/AjpMessage.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/coyote/ajp/AjpMessage.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/coyote/ajp/AjpMessage.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,449 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.ajp;
+
+import org.apache.tomcat.util.buf.ByteChunk;
+import org.apache.tomcat.util.buf.CharChunk;
+import org.apache.tomcat.util.buf.MessageBytes;
+import org.apache.tomcat.util.res.StringManager;
+
+/**
+ * A single packet for communication between the web server and the
+ * container.  Designed to be reused many times with no creation of
+ * garbage.  Understands the format of data types for these packets.
+ * Can be used (somewhat confusingly) for both incoming and outgoing
+ * packets.  
+ *
+ * @author Henri Gomez
+ * @author Dan Milstein
+ * @author Keith Wannamaker
+ * @author Kevin Seguin
+ * @author Costin Manolache
+ */
+public class AjpMessage {
+
+
+    protected static org.apache.commons.logging.Log log =
+        org.apache.commons.logging.LogFactory.getLog(AjpMessage.class);
+
+    /**
+     * The string manager for this package.
+     */
+    protected static StringManager sm =
+        StringManager.getManager(Constants.Package);
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * Fixed size buffer.
+     */
+    protected byte buf[] = new byte[8 * 1024];
+
+
+    /**
+     * The current read or write position in the buffer.
+     */
+    protected int pos;
+
+
+    /**
+     * This actually means different things depending on whether the
+     * packet is read or write.  For read, it's the length of the
+     * payload (excluding the header).  For write, it's the length of
+     * the packet as a whole (counting the header).  Oh, well.
+     */
+    protected int len; 
+
+    
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Prepare this packet for accumulating a message from the container to
+     * the web server.  Set the write position to just after the header
+     * (but leave the length unwritten, because it is as yet unknown).
+     */
+    public void reset() {
+        len = 4;
+        pos = 4;
+    }
+
+
+    /**
+     * For a packet to be sent to the web server, finish the process of
+     * accumulating data and write the length of the data payload into
+     * the header.  
+     */
+    public void end() {
+        len = pos;
+        int dLen = len - 4;
+
+        buf[0] = (byte) 0x41;
+        buf[1] = (byte) 0x42;
+        buf[2] = (byte) ((dLen>>>8) & 0xFF);
+        buf[3] = (byte) (dLen & 0xFF);
+    }
+
+
+    /**
+     * Return the underlying byte buffer.
+     */
+    public byte[] getBuffer() {
+        return buf;
+    }
+
+
+    /**
+     * Return the current message length. For read, it's the length of the
+     * payload (excluding the header).  For write, it's the length of
+     * the packet as a whole (counting the header).
+     */
+    public int getLen() {
+        return len;
+    }
+    
+
+    /**
+     * Add a short integer (2 bytes) to the message.
+     */
+    public void appendInt(int val) {
+        buf[pos++] = (byte) ((val >>> 8) & 0xFF);
+        buf[pos++] = (byte) (val & 0xFF);
+    }
+
+
+    /**
+     * Append a byte (1 byte) to the message.
+     */
+    public void appendByte(int val) {
+        buf[pos++] = (byte) val;
+    }
+	
+    
+    /**
+     * Append an int (4 bytes) to the message.
+     */
+    public void appendLongInt(int val) {
+        buf[pos++] = (byte) ((val >>> 24) & 0xFF);
+        buf[pos++] = (byte) ((val >>> 16) & 0xFF);
+        buf[pos++] = (byte) ((val >>> 8) & 0xFF);
+        buf[pos++] = (byte) (val & 0xFF);
+    }
+
+    
+    /**
+     * Write a MessageBytes out at the current write position.
+     * A null MessageBytes is encoded as a string with length 0.  
+     */
+    public void appendBytes(MessageBytes mb) {
+        if (mb == null) {
+            log.error(sm.getString("ajpmessage.null"), 
+                    new NullPointerException());
+            appendInt(0);
+            appendByte(0);
+            return;
+        }
+        if (mb.getType() == MessageBytes.T_BYTES) {
+            ByteChunk bc = mb.getByteChunk();
+            appendByteChunk(bc);
+        } else if (mb.getType() == MessageBytes.T_CHARS) {
+            CharChunk cc = mb.getCharChunk();
+            appendCharChunk(cc);
+        } else {
+            appendString(mb.toString());
+        }
+    }
+
+    
+    /**
+     * Write a ByteChunk out at the current write position.
+     * A null ByteChunk is encoded as a string with length 0.  
+     */
+    public void appendByteChunk(ByteChunk bc) {
+        if (bc == null) {
+            log.error(sm.getString("ajpmessage.null"), 
+                    new NullPointerException());
+            appendInt(0);
+            appendByte(0);
+            return;
+        }
+        appendBytes(bc.getBytes(), bc.getStart(), bc.getLength());
+    }
+
+    
+    /**
+     * Write a CharChunk out at the current write position.
+     * A null CharChunk is encoded as a string with length 0.  
+     */
+    public void appendCharChunk(CharChunk cc) {
+        if (cc == null) {
+            log.error(sm.getString("ajpmessage.null"), 
+                    new NullPointerException());
+            appendInt(0);
+            appendByte(0);
+            return;
+        }
+        int start = cc.getStart();
+        int end = cc.getEnd();
+        appendInt(end - start);
+        char[] cbuf = cc.getBuffer();
+        for (int i = start; i < end; i++) {
+            char c = cbuf[i];
+            // Note:  This is clearly incorrect for many strings,
+            // but is the only consistent approach within the current
+            // servlet framework.  It must suffice until servlet output
+            // streams properly encode their output.
+            if ((c <= 31) && (c != 9)) {
+                c = ' ';
+            } else if (c == 127) {
+                c = ' ';
+            }
+            appendByte(c);
+        }
+        appendByte(0);
+    }
+
+    
+    /**
+     * Write a String out at the current write position.  Strings are
+     * encoded with the length in two bytes first, then the string, and
+     * then a terminating \0 (which is <B>not</B> included in the
+     * encoded length).  The terminator is for the convenience of the C
+     * code, where it saves a round of copying.  A null string is
+     * encoded as a string with length 0.  
+     */
+    public void appendString(String str) {
+        if (str == null) {
+            log.error(sm.getString("ajpmessage.null"), 
+                    new NullPointerException());
+            appendInt(0);
+            appendByte(0);
+            return;
+        }
+        int len = str.length();
+        appendInt(len);
+        for (int i = 0; i < len; i++) {
+            char c = str.charAt (i);
+            // Note:  This is clearly incorrect for many strings,
+            // but is the only consistent approach within the current
+            // servlet framework.  It must suffice until servlet output
+            // streams properly encode their output.
+            if ((c <= 31) && (c != 9)) {
+                c = ' ';
+            } else if (c == 127) {
+                c = ' ';
+            }
+            appendByte(c);
+        }
+        appendByte(0);
+    }
+
+    
+    /** 
+     * Copy a chunk of bytes into the packet, starting at the current
+     * write position.  The chunk of bytes is encoded with the length
+     * in two bytes first, then the data itself, and finally a
+     * terminating \0 (which is <B>not</B> included in the encoded
+     * length).
+     *
+     * @param b The array from which to copy bytes.
+     * @param off The offset into the array at which to start copying
+     * @param numBytes The number of bytes to copy.  
+     */
+    public void appendBytes(byte[] b, int off, int numBytes) {
+        if (pos + numBytes + 3 >= buf.length) {
+            log.error(sm.getString("ajpmessage.overflow", "" + numBytes, "" + pos),
+                    new ArrayIndexOutOfBoundsException());
+            if (log.isDebugEnabled()) {
+                dump("Overflow/coBytes");
+            }
+            return;
+        }
+        appendInt(numBytes);
+        System.arraycopy(b, off, buf, pos, numBytes);
+        pos += numBytes;
+        appendByte(0);
+    }
+
+    
+    /**
+     * Read an integer from packet, and advance the read position past
+     * it.  Integers are encoded as two unsigned bytes with the
+     * high-order byte first, and, as far as I can tell, in
+     * little-endian order within each byte.  
+     */
+    public int getInt() {
+        int b1 = buf[pos++] & 0xFF;
+        int b2 = buf[pos++] & 0xFF;
+        return (b1<<8) + b2;
+    }
+
+
+    public int peekInt() {
+        int b1 = buf[pos] & 0xFF;
+        int b2 = buf[pos+1] & 0xFF;
+        return (b1<<8) + b2;
+    }
+
+    
+    public byte getByte() {
+        byte res = buf[pos++];
+        return res;
+    }
+
+    
+    public byte peekByte() {
+        byte res = buf[pos];
+        return res;
+    }
+
+    
+    public void getBytes(MessageBytes mb) {
+        int length = getInt();
+        if ((length == 0xFFFF) || (length == -1)) {
+            mb.recycle();
+            return;
+        }
+        mb.setBytes(buf, pos, length);
+        pos += length;
+        pos++; // Skip the terminating \0
+    }
+    
+    
+    /**
+     * Copy a chunk of bytes from the packet into an array and advance
+     * the read position past the chunk.  See appendBytes() for details
+     * on the encoding.
+     *
+     * @return The number of bytes copied.
+     */
+    public int getBytes(byte[] dest) {
+        int length = getInt();
+        if (pos + length > buf.length) {
+            log.error(sm.getString("ajpmessage.read", "" + length));
+            return 0;
+        }
+	
+        if ((length == 0xFFFF) || (length == -1)) {
+            return 0;
+        }
+
+        System.arraycopy(buf, pos, dest, 0, length);
+        pos += length;
+        pos++; // Skip terminating \0
+        return length;
+    }
+
+    
+    /**
+     * Read a 32 bits integer from packet, and advance the read position past
+     * it.  Integers are encoded as four unsigned bytes with the
+     * high-order byte first, and, as far as I can tell, in
+     * little-endian order within each byte.
+     */
+    public int getLongInt() {
+        int b1 = buf[pos++] & 0xFF; // No swap, Java order
+        b1 <<= 8;
+        b1 |= (buf[pos++] & 0xFF);
+        b1 <<= 8;
+        b1 |= (buf[pos++] & 0xFF);
+        b1 <<=8;
+        b1 |= (buf[pos++] & 0xFF);
+        return  b1;
+    }
+
+
+    public int getHeaderLength() {
+        return 4;
+    }
+
+    
+    public int processHeader() {
+        pos = 0;
+        int mark = getInt();
+        len = getInt();
+        // Verify message signature
+        if ((mark != 0x1234) && (mark != 0x4142)) {
+            log.error(sm.getString("ajpmessage.invalid", "" + mark));
+            if (log.isDebugEnabled()) {
+                dump("In: ");
+            }
+            return -1;
+        }
+        if (log.isDebugEnabled())  {
+            log.debug("Received " + len + " " + buf[0]);
+        }
+        return len;
+    }
+    
+
+    /**
+     * Dump the contents of the message, prefixed with the given String.
+     */
+    public void dump(String msg) {
+        if (log.isDebugEnabled()) {
+            log.debug(msg + ": " + buf + " " + pos +"/" + (len + 4));
+        }
+        int max = pos;
+        if (len + 4 > pos)
+            max = len+4;
+        if (max > 1000)
+            max = 1000;
+        if (log.isDebugEnabled()) {
+            for (int j = 0; j < max; j += 16) { 
+                log.debug(hexLine(buf, j, len));
+            }
+        }
+    }
+
+
+    // ------------------------------------------------------ Protected Methods
+
+
+    protected static String hexLine(byte buf[], int start, int len) {
+        StringBuffer sb = new StringBuffer();
+        for (int i = start; i < start + 16 ; i++) {
+            if (i < len + 4) {
+                sb.append(hex(buf[i]) + " ");
+            } else { 
+                sb.append("   ");
+            }
+        }
+        sb.append(" | ");
+        for (int i = start; i < start + 16 && i < len + 4; i++) {
+            if (!Character.isISOControl((char) buf[i])) {
+                sb.append(new Character((char) buf[i]));
+            } else {
+                sb.append(".");
+            }
+        }
+        return sb.toString();
+    }
+
+
+    protected static String hex(int x) {
+        String h = Integer.toHexString(x);
+        if (h.length() == 1) {
+            h = "0" + h;
+        }
+        return h.substring(h.length() - 2);
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/coyote/ajp/Constants.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/coyote/ajp/Constants.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/coyote/ajp/Constants.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,337 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.ajp;
+
+import org.apache.tomcat.util.buf.ByteChunk;
+
+
+/**
+ * Constants.
+ *
+ * @author Remy Maucherat
+ */
+public final class Constants {
+
+
+    // -------------------------------------------------------------- Constants
+
+
+    /**
+     * Package name.
+     */
+    public static final String Package = "org.apache.coyote.ajp";
+
+    public static final int DEFAULT_CONNECTION_LINGER = -1;
+    public static final int DEFAULT_CONNECTION_TIMEOUT = -1;
+    public static final int DEFAULT_CONNECTION_UPLOAD_TIMEOUT = 300000;
+    public static final int DEFAULT_SERVER_SOCKET_TIMEOUT = 0;
+    public static final boolean DEFAULT_TCP_NO_DELAY = true;
+
+    // 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_CPING_REQUEST     = 10;
+
+    // Prefix codes for message types from container to server
+    public static final byte JK_AJP13_SEND_BODY_CHUNK   = 3;
+    public static final byte JK_AJP13_SEND_HEADERS      = 4;
+    public static final byte JK_AJP13_END_RESPONSE      = 5;
+    public static final byte JK_AJP13_GET_BODY_CHUNK    = 6;
+    public static final byte JK_AJP13_CPONG_REPLY       = 9;
+
+    // Integer codes for common response header strings
+    public static final int SC_RESP_CONTENT_TYPE        = 0xA001;
+    public static final int SC_RESP_CONTENT_LANGUAGE    = 0xA002;
+    public static final int SC_RESP_CONTENT_LENGTH      = 0xA003;
+    public static final int SC_RESP_DATE                = 0xA004;
+    public static final int SC_RESP_LAST_MODIFIED       = 0xA005;
+    public static final int SC_RESP_LOCATION            = 0xA006;
+    public static final int SC_RESP_SET_COOKIE          = 0xA007;
+    public static final int SC_RESP_SET_COOKIE2         = 0xA008;
+    public static final int SC_RESP_SERVLET_ENGINE      = 0xA009;
+    public static final int SC_RESP_STATUS              = 0xA00A;
+    public static final int SC_RESP_WWW_AUTHENTICATE    = 0xA00B;
+
+    // Integer codes for common (optional) request attribute names
+    public static final byte SC_A_CONTEXT       = 1;  // XXX Unused
+    public static final byte SC_A_SERVLET_PATH  = 2;  // XXX Unused
+    public static final byte SC_A_REMOTE_USER   = 3;
+    public static final byte SC_A_AUTH_TYPE     = 4;
+    public static final byte SC_A_QUERY_STRING  = 5;
+    public static final byte SC_A_JVM_ROUTE     = 6;
+    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;
+    public static final byte SC_A_SSL_KEYSIZE   = 11;
+    public static final byte SC_A_SECRET        = 12;
+    public static final byte SC_A_STORED_METHOD = 13;
+
+    // Used for attributes which are not in the list above
+    public static final byte SC_A_REQ_ATTRIBUTE = 10;
+
+    // Terminates list of attributes
+    public static final byte SC_A_ARE_DONE      = (byte)0xFF;
+
+    // Ajp13 specific -  needs refactoring for the new model
+    /**
+     * Maximum Total byte size for a AJP packet
+     */
+    public static final int MAX_PACKET_SIZE = 8192;
+    /**
+     * Size of basic packet header
+     */
+    public static final int H_SIZE = 4;
+    /**
+     * Maximum size of data that can be sent in one packet
+     */
+    public static final int  MAX_READ_SIZE = MAX_PACKET_SIZE - H_SIZE - 2;
+    public static final int  MAX_SEND_SIZE = MAX_PACKET_SIZE - H_SIZE - 4;
+
+    // Translates integer codes to names of HTTP methods
+    public static final String []methodTransArray = {
+            "OPTIONS",
+            "GET",
+            "HEAD",
+            "POST",
+            "PUT",
+            "DELETE",
+            "TRACE",
+            "PROPFIND",
+            "PROPPATCH",
+            "MKCOL",
+            "COPY",
+            "MOVE",
+            "LOCK",
+            "UNLOCK",
+            "ACL",
+            "REPORT",
+            "VERSION-CONTROL",
+            "CHECKIN",
+            "CHECKOUT",
+            "UNCHECKOUT",
+            "SEARCH",
+            "MKWORKSPACE",
+            "UPDATE",
+            "LABEL",
+            "MERGE",
+            "BASELINE-CONTROL",
+            "MKACTIVITY"
+    };
+    public static final int SC_M_JK_STORED = (byte) 0xFF;
+
+    // id's for common request headers
+    public static final int SC_REQ_ACCEPT          = 1;
+    public static final int SC_REQ_ACCEPT_CHARSET  = 2;
+    public static final int SC_REQ_ACCEPT_ENCODING = 3;
+    public static final int SC_REQ_ACCEPT_LANGUAGE = 4;
+    public static final int SC_REQ_AUTHORIZATION   = 5;
+    public static final int SC_REQ_CONNECTION      = 6;
+    public static final int SC_REQ_CONTENT_TYPE    = 7;
+    public static final int SC_REQ_CONTENT_LENGTH  = 8;
+    public static final int SC_REQ_COOKIE          = 9;
+    public static final int SC_REQ_COOKIE2         = 10;
+    public static final int SC_REQ_HOST            = 11;
+    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
+    public static final String []headerTransArray = {
+            "accept",
+            "accept-charset",
+            "accept-encoding",
+            "accept-language",
+            "authorization",
+            "connection",
+            "content-type",
+            "content-length",
+            "cookie",
+            "cookie2",
+            "host",
+            "pragma",
+            "referer",
+            "user-agent"
+    };
+
+
+    /**
+     * CRLF.
+     */
+    public static final String CRLF = "\r\n";
+
+
+    /**
+     * Server string.
+     */
+    public static final byte[] SERVER_BYTES =
+        ByteChunk.convertToBytes("Server: Apache-Coyote/1.1" + CRLF);
+
+
+    /**
+     * CR.
+     */
+    public static final byte CR = (byte) '\r';
+
+
+    /**
+     * LF.
+     */
+    public static final byte LF = (byte) '\n';
+
+
+    /**
+     * SP.
+     */
+    public static final byte SP = (byte) ' ';
+
+
+    /**
+     * HT.
+     */
+    public static final byte HT = (byte) '\t';
+
+
+    /**
+     * COLON.
+     */
+    public static final byte COLON = (byte) ':';
+
+
+    /**
+     * 'A'.
+     */
+    public static final byte A = (byte) 'A';
+
+
+    /**
+     * 'a'.
+     */
+    public static final byte a = (byte) 'a';
+
+
+    /**
+     * 'Z'.
+     */
+    public static final byte Z = (byte) 'Z';
+
+
+    /**
+     * '?'.
+     */
+    public static final byte QUESTION = (byte) '?';
+
+
+    /**
+     * Lower case offset.
+     */
+    public static final byte LC_OFFSET = A - a;
+
+
+    /**
+     * Default HTTP header buffer size.
+     */
+    public static final int DEFAULT_HTTP_HEADER_BUFFER_SIZE = 48 * 1024;
+
+
+    /* Various constant "strings" */
+    public static final byte[] CRLF_BYTES = ByteChunk.convertToBytes(CRLF);
+    public static final byte[] COLON_BYTES = ByteChunk.convertToBytes(": ");
+    public static final String CONNECTION = "Connection";
+    public static final String CLOSE = "close";
+    public static final byte[] CLOSE_BYTES =
+        ByteChunk.convertToBytes(CLOSE);
+    public static final String KEEPALIVE = "keep-alive";
+    public static final byte[] KEEPALIVE_BYTES =
+        ByteChunk.convertToBytes(KEEPALIVE);
+    public static final String CHUNKED = "chunked";
+    public static final byte[] ACK_BYTES =
+        ByteChunk.convertToBytes("HTTP/1.1 100 Continue" + CRLF + CRLF);
+    public static final String TRANSFERENCODING = "Transfer-Encoding";
+    public static final byte[] _200_BYTES =
+        ByteChunk.convertToBytes("200");
+    public static final byte[] _400_BYTES =
+        ByteChunk.convertToBytes("400");
+    public static final byte[] _404_BYTES =
+        ByteChunk.convertToBytes("404");
+
+
+    /**
+     * Identity filters (input and output).
+     */
+    public static final int IDENTITY_FILTER = 0;
+
+
+    /**
+     * Chunked filters (input and output).
+     */
+    public static final int CHUNKED_FILTER = 1;
+
+
+    /**
+     * Void filters (input and output).
+     */
+    public static final int VOID_FILTER = 2;
+
+
+    /**
+     * GZIP filter (output).
+     */
+    public static final int GZIP_FILTER = 3;
+
+
+    /**
+     * Buffered filter (input)
+     */
+    public static final int BUFFERED_FILTER = 3;
+
+
+    /**
+     * HTTP/1.0.
+     */
+    public static final String HTTP_10 = "HTTP/1.0";
+
+
+    /**
+     * HTTP/1.1.
+     */
+    public static final String HTTP_11 = "HTTP/1.1";
+    public static final byte[] HTTP_11_BYTES =
+        ByteChunk.convertToBytes(HTTP_11);
+
+
+    /**
+     * GET.
+     */
+    public static final String GET = "GET";
+
+
+    /**
+     * HEAD.
+     */
+    public static final String HEAD = "HEAD";
+
+
+    /**
+     * POST.
+     */
+    public static final String POST = "POST";
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/coyote/ajp/LocalStrings.properties
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/coyote/ajp/LocalStrings.properties	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/coyote/ajp/LocalStrings.properties	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,37 @@
+# $Id: LocalStrings.properties 301021 2005-08-01 10:00:59Z remm $
+
+# language 
+
+# package org.apache.coyote.ajp
+
+#
+# AjpAprProtocol
+#
+
+ajpprotocol.endpoint.initerror=Error initializing endpoint
+ajpprotocol.endpoint.starterror=Error starting endpoint
+ajpprotocol.init=Initializing Coyote AJP/1.3 on {0}
+ajpprotocol.proto.error=Error reading request, ignored
+ajpprotocol.getattribute=Attribute {0}
+ajpprotocol.setattribute=Attribute {0}: {1}
+ajpprotocol.start=Starting Coyote AJP/1.3 on {0}
+ajpprotocol.stop=Stopping Coyote AJP/1.3 on {0}
+ajpprotocol.pause=Pausing Coyote AJP/1.3 on {0}
+ajpprotocol.endpoint.pauseerror=Error pausing endpoint
+ajpprotocol.resume=Resuming Coyote AJP/1.3 on {0}
+ajpprotocol.endpoint.resumeerror=Error resuming endpoint
+ajpprotocol.failedread=Socket read failed
+ajpprotocol.failedwrite=Socket write failed
+ajpprotocol.request.register=Error registering request processor in JMX
+
+ajpprocessor.header.error=Header message parsing failed
+ajpprocessor.request.prepare=Error preparing request
+ajpprocessor.request.process=Error processing request
+ajpprocessor.certs.fail=Certificate convertion failed
+ajpprocessor.socket.info=Exception getting socket information
+
+ajpmessage.null=Cannot append null value
+ajpmessage.overflow=Overflow error for buffer adding {0} bytes at position {1}
+ajpmessage.read=Requested {0} bytes exceeds message available data
+ajpmessage.invalid=Invalid message recieved with signature {0}
+

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/apr/AprImpl.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/apr/AprImpl.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/apr/AprImpl.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,316 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.jk.apr;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.util.Hashtable;
+import org.apache.jk.core.JkHandler;
+import org.apache.jk.core.MsgContext;
+import org.apache.jk.core.JkChannel;
+
+/** Implements the interface with the APR library. This is for internal-use
+ *  only. The goal is to use 'natural' mappings for user code - for example
+ *  java.net.Socket for unix-domain sockets, etc. 
+ * 
+ */
+public class AprImpl extends JkHandler { // This will be o.a.t.util.handler.TcHandler - lifecycle and config
+    static AprImpl aprSingleton=null;
+
+    String baseDir;
+    String aprHome;
+    String soExt="so";
+
+    static boolean ok=true;
+    boolean initialized=false;
+    // Handlers for native callbacks
+    Hashtable jkHandlers=new Hashtable();
+
+    // Name of the so used in inprocess mode 
+    String jniModeSo="inprocess";
+    // name of the so used by java. If not set we'll loadLibrary("jkjni" ),
+    // if set we load( nativeSo )
+    String nativeSo;
+    
+    public AprImpl() {
+        aprSingleton=this;
+    }
+    
+    // -------------------- Properties --------------------
+    
+    /** Native libraries are located based on base dir.
+     *  XXX Add platform, version, etc
+     */
+    public void setBaseDir(String s) {
+        baseDir=s;
+    }
+    
+    public void setSoExt(String s ) {
+        soExt=s;
+    }
+    
+    // XXX maybe install the jni lib in apr-home ?
+    public void setAprHome( String s ) {
+        aprHome=s;
+    }
+
+    /** Add a Handler for jni callbacks.
+     */
+    public void addJkHandler(String type, JkHandler cb) {
+        jkHandlers.put( type, cb );
+    }
+    
+    /** Name of the so used in inprocess mode
+     */
+    public void setJniModeSo(String jniModeSo ) {
+        this.jniModeSo=jniModeSo;
+    }
+
+    /** name of the so used by java. If not set we'll loadLibrary("jkjni" ),
+        if set we load( nativeSo )
+    */
+    public void setNativeSo( String nativeSo ) {
+        this.nativeSo=nativeSo;
+    }
+
+    /** Sets the System.out stream */
+    
+    public static void setOut( String filename ) {
+        try{ 
+            if( filename !=null ){
+                System.setOut( new PrintStream(new FileOutputStream(filename )));
+            }
+        }catch (Throwable th){
+        }
+    }
+    /** Sets the System.err stream */
+    
+    public static void setErr( String filename ) {
+        try{ 
+            if( filename !=null ){
+                System.setErr( new PrintStream(new FileOutputStream(filename )));
+            }                                                 
+        }catch (Throwable th){
+        }
+    }
+
+    // -------------------- Apr generic utils --------------------
+    /** Initialize APR
+     */
+    public native int initialize();
+
+    public native int terminate();
+
+    /* -------------------- Access to the jk_env_t -------------------- */
+
+    /* The jk_env_t provide temporary storage ( pool ), logging, common services
+     */
+    
+    /* Return a jk_env_t, used to keep the execution context ( temp pool, etc )
+     */
+    public native long getJkEnv();
+
+    /** Clean the temp pool, put back the env in the pool
+     */
+    public native void releaseJkEnv(long xEnv);
+
+    /* -------------------- Interface to the jk_bean object -------------------- */
+    /* Each jk component is 'wrapped' as a bean, with a specified lifecycle
+     *
+     */
+    
+    /** Get a native component
+     *  @return 0 if the component is not found.
+     */
+    public native long getJkHandler(long xEnv, String compName );
+
+    public native long createJkHandler(long xEnv, String compName );
+
+    public native int jkSetAttribute( long xEnv, long componentP, String name, String val );
+
+    public native String jkGetAttribute( long xEnv, long componentP, String name );
+    
+    public native int jkInit( long xEnv, long componentP );
+
+    public native int jkDestroy( long xEnv, long componentP );
+    
+    /** Send the packet to the C side. On return it contains the response
+     *  or indication there is no response. Asymetrical because we can't
+     *  do things like continuations.
+     */
+    public static native int jkInvoke(long xEnv, long componentP, long endpointP,
+                                      int code, byte data[], int off, int len, int raw);
+
+    /** Recycle an endpoint after use.
+     */
+    public native void jkRecycle(long xEnv, long endpointP);
+
+    // -------------------- Called from C --------------------
+    // XXX Check security, add guard or other protection
+    // It's better to do it the other way - on init 'push' AprImpl into
+    // the native library, and have native code call instance methods.
+    
+    public static Object createJavaContext(String type, long cContext) {
+        // XXX will be an instance method, fields accessible directly
+        AprImpl apr=aprSingleton;
+        JkChannel jkH=(JkChannel)apr.jkHandlers.get( type );
+        if( jkH==null ) return null;
+
+        MsgContext ep=jkH.createMsgContext();
+
+        ep.setSource( jkH );
+        
+        ep.setJniContext( cContext );
+        return ep;
+    }
+
+    /** Return a buffer associated with the ctx.
+     */
+    public static byte[] getBuffer( Object ctx, int id ) {
+        return ((MsgContext)ctx).getBuffer(  id );
+    }
+
+    public static int jniInvoke( long jContext, Object ctx ) {
+        try {
+            MsgContext ep=(MsgContext)ctx;
+            ep.setJniEnv(  jContext );
+            ep.setType( 0 );
+            return ((MsgContext)ctx).execute();
+        } catch( Throwable ex ) {
+            ex.printStackTrace();
+            return -1;
+        }
+    }
+
+    // -------------------- Initialization -------------------- 
+
+    public void init() throws IOException {
+        try {
+            initialized=true;
+            loadNative();
+
+            initialize();
+            jkSetAttribute(0, 0, "channel:jni", "starting");
+            
+            log.info("JK: Initialized apr" );
+            
+        } catch( Throwable t ) {
+            throw new IOException( t.toString() );
+        }
+        ok=true;
+    }
+
+    public boolean isLoaded() {
+        if( ! initialized ) {
+            try {
+                init();
+            } catch( Throwable t ) {
+                log.info("Apr not loaded: " + t);
+            }
+        }
+        return ok;
+    }
+
+    static boolean jniMode=false;
+
+    
+    public static void jniMode() {
+        jniMode=true;
+    }
+
+    /** This method of loading the libs doesn't require setting
+     *   LD_LIBRARY_PATH. Assuming a 'right' binary distribution,
+     *   or a correct build all files will be in their right place.
+     *
+     *  The burden is on our code to deal with platform specific
+     *  extensions and to keep the paths consistent - not easy, but
+     *  worth it if it avoids one extra step for the user.
+     *
+     *  Of course, this can change to System.load() and putting the
+     *  libs in LD_LIBRARY_PATH.
+     */
+    public void loadNative() throws Throwable {
+        if( aprHome==null )
+            aprHome=baseDir;
+
+        // XXX Update for windows
+        if( jniMode ) {
+            /* In JNI mode we use mod_jk for the native functions.
+               This seems the cleanest solution that works with multiple
+               VMs.
+            */
+            if (jniModeSo.equals("inprocess")) {
+                ok=true;
+                return;                                
+            }
+            try {
+                log.info("Loading " + jniModeSo);
+                if( jniModeSo!= null ) System.load( jniModeSo );
+            } catch( Throwable ex ) {
+                // ignore
+                //ex.printStackTrace();
+                return;
+            }
+            ok=true;
+            return;
+        }
+        
+            /*
+              jkjni _must_ be linked with apr and crypt -
+              this seem the only ( decent ) way to support JDK1.4 and
+              JDK1.3 at the same time
+              try {
+                  System.loadLibrary( "crypt" );
+              } catch( Throwable ex ) {
+                  // ignore
+                  ex.printStackTrace();
+              }
+              try {
+                  System.loadLibrary( "apr" );
+              } catch( Throwable ex ) {
+                  System.out.println("can't load apr, that's fine");
+                  ex.printStackTrace();
+              }
+            */
+        try {
+            if( nativeSo == null ) {
+                // This will load libjkjni.so or jkjni.dll in LD_LIBRARY_PATH
+                log.debug("Loading jkjni from " + System.getProperty("java.library.path"));
+                System.loadLibrary( "jkjni" );
+            } else {
+                System.load( nativeSo );
+            }
+        } catch( Throwable ex ) {
+            ok=false;
+            //ex.printStackTrace();
+            throw ex;
+        }
+    } 
+
+    public void loadNative(String libPath) {
+        try {
+            System.load( libPath );
+        } catch( Throwable ex ) {
+            ok=false;
+            if( log.isDebugEnabled() ) 
+                log.debug( "Error loading native library ", ex);
+        }
+    }
+    private static org.apache.commons.logging.Log log=
+        org.apache.commons.logging.LogFactory.getLog( AprImpl.class );
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/apr/TomcatStarter.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/apr/TomcatStarter.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/apr/TomcatStarter.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,93 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.jk.apr;
+
+import java.lang.reflect.Method;
+
+// Hack for Catalina 4.1 who hungs the calling thread.
+// Also avoids delays in apache initialization ( tomcat can take a while )
+
+/** 
+ * Start some tomcat.
+ * 
+ */
+public class TomcatStarter implements Runnable {
+    Class c;
+    String args[];
+    AprImpl apr = new AprImpl();
+    
+    public static String mainClasses[]={ "org.apache.tomcat.startup.Main",
+                                         "org.apache.catalina.startup.BootstrapService",
+                                         "org.apache.catalina.startup.Bootstrap"};
+
+    // If someone has time - we can also guess the classpath and do other
+    // fancy guessings.
+    
+    public static void main( String args[] ) {
+        System.err.println("TomcatStarter: main()");
+        int nClasses = 0;
+        
+        try {
+            AprImpl.jniMode();            
+            // Find the class
+            Class c=null;
+            for( int i=0; i<mainClasses.length; i++ ) {
+                try {
+                    System.err.println("Try  " + mainClasses[i]);
+                    c=Class.forName( mainClasses[i] );
+                } catch( ClassNotFoundException ex  ) {
+                    continue;
+                }
+                if( c!= null ) {
+                    ++nClasses;
+                    Thread startThread=new Thread( new TomcatStarter(c, args));
+                    c=null;
+                    startThread.start();
+                    break;
+                }
+            }
+            if (nClasses==0)
+                System.err.println("No class found  ");
+
+        } catch (Throwable t ) {
+            t.printStackTrace(System.err);
+        }
+    }
+
+    public TomcatStarter( Class c, String args[] ) {
+        this.c=c;
+        this.args=args;
+    }
+    
+    public void run() {
+        System.err.println("Starting " + c.getName());
+        try {
+            Class argClass=args.getClass();
+            Method m=c.getMethod( "main", new Class[] {argClass} );
+            m.invoke( c, new Object[] { args } );
+            System.out.println("TomcatStarter: Done");
+            if (apr.isLoaded())
+                apr.jkSetAttribute(0, 0, "channel:jni", "done");
+            if (args[0].equals("stop")) {
+                  Thread.sleep(5000);
+                  Runtime.getRuntime().exit(0);
+            }
+        } catch( Throwable t ) {
+            t.printStackTrace(System.err);
+        }
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/common/AjpConstants.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/common/AjpConstants.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/common/AjpConstants.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,192 @@
+/*
+ *  Copyright 1999-2005 The Apache Software Foundation
+ *
+ *  Licensed 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.jk.common;
+
+
+/**
+ * Common class for the AJP Protocol values
+ */
+
+public class AjpConstants {
+    // Prefix codes for message types from server to container
+    /**
+     * Message code for initial Request packet
+     */
+    public static final byte JK_AJP13_FORWARD_REQUEST   = 2;
+    /**
+     * Message code for a request to shutdown Tomcat
+     */
+    public static final byte JK_AJP13_SHUTDOWN          = 7;
+    /**
+     * Message code for a Ping request (obsolete)
+     */
+    public static final byte JK_AJP13_PING_REQUEST      = 8;
+    /**
+     * Message code for a CPing request
+     */
+    public static final byte JK_AJP13_CPING_REQUEST     = 10;
+
+    // Prefix codes for message types from container to server
+    /**
+     * Response code that the package is part of the Response body
+     */
+    public static final byte JK_AJP13_SEND_BODY_CHUNK   = 3;
+    /**
+     * Response code that the package is the HTTP headers
+     */
+    public static final byte JK_AJP13_SEND_HEADERS      = 4;
+    /**
+     * Response code for EOT
+     */
+    public static final byte JK_AJP13_END_RESPONSE      = 5;
+    /**
+     * Response code to request the next Request body chunk
+     */
+    public static final byte JK_AJP13_GET_BODY_CHUNK    = 6;
+    /**
+     * Response code to reply to a CPing
+     */
+    public static final byte JK_AJP13_CPONG_REPLY       = 9;
+    
+    // Integer codes for common response header strings
+    public static final int SC_RESP_CONTENT_TYPE        = 0xA001;
+    public static final int SC_RESP_CONTENT_LANGUAGE    = 0xA002;
+    public static final int SC_RESP_CONTENT_LENGTH      = 0xA003;
+    public static final int SC_RESP_DATE                = 0xA004;
+    public static final int SC_RESP_LAST_MODIFIED       = 0xA005;
+    public static final int SC_RESP_LOCATION            = 0xA006;
+    public static final int SC_RESP_SET_COOKIE          = 0xA007;
+    public static final int SC_RESP_SET_COOKIE2         = 0xA008;
+    public static final int SC_RESP_SERVLET_ENGINE      = 0xA009;
+    public static final int SC_RESP_STATUS              = 0xA00A;
+    public static final int SC_RESP_WWW_AUTHENTICATE    = 0xA00B;
+        
+    // Integer codes for common (optional) request attribute names
+    public static final byte SC_A_CONTEXT       = 1;  // XXX Unused
+    public static final byte SC_A_SERVLET_PATH  = 2;  // XXX Unused
+    public static final byte SC_A_REMOTE_USER   = 3;
+    public static final byte SC_A_AUTH_TYPE     = 4;
+    public static final byte SC_A_QUERY_STRING  = 5;
+    public static final byte SC_A_JVM_ROUTE     = 6;
+    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;
+    public static final byte SC_A_SSL_KEYSIZE   = 11;
+    public static final byte SC_A_SECRET        = 12;
+    public static final byte SC_A_STORED_METHOD = 13;
+
+    // Used for attributes which are not in the list above
+    /**
+     * Request Attribute is passed as a String
+     */
+    public static final byte SC_A_REQ_ATTRIBUTE = 10; 
+
+    /**
+     * Terminates list of attributes
+     */
+    public static final byte SC_A_ARE_DONE      = (byte)0xFF;
+    
+    /**
+     * Translates integer codes to names of HTTP methods
+     */
+    public static final String []methodTransArray = {
+        "OPTIONS",
+        "GET",
+        "HEAD",
+        "POST",
+        "PUT",
+        "DELETE",
+        "TRACE",
+        "PROPFIND",
+        "PROPPATCH",
+        "MKCOL",
+        "COPY",
+        "MOVE",
+        "LOCK",
+        "UNLOCK",
+        "ACL",
+        "REPORT",
+        "VERSION-CONTROL",
+        "CHECKIN",
+        "CHECKOUT",
+        "UNCHECKOUT",
+        "SEARCH",
+        "MKWORKSPACE",
+        "UPDATE",
+        "LABEL",
+        "MERGE",
+        "BASELINE-CONTROL",
+        "MKACTIVITY"
+    };
+
+    /**
+     * Request Method is passed as a String
+     */
+    public static final int SC_M_JK_STORED = (byte) 0xFF;
+    
+    // id's for common request headers
+    public static final int SC_REQ_ACCEPT          = 1;
+    public static final int SC_REQ_ACCEPT_CHARSET  = 2;
+    public static final int SC_REQ_ACCEPT_ENCODING = 3;
+    public static final int SC_REQ_ACCEPT_LANGUAGE = 4;
+    public static final int SC_REQ_AUTHORIZATION   = 5;
+    public static final int SC_REQ_CONNECTION      = 6;
+    public static final int SC_REQ_CONTENT_TYPE    = 7;
+    public static final int SC_REQ_CONTENT_LENGTH  = 8;
+    public static final int SC_REQ_COOKIE          = 9;
+    public static final int SC_REQ_COOKIE2         = 10;
+    public static final int SC_REQ_HOST            = 11;
+    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    
+     */
+    public static final String []headerTransArray = {
+        "accept",
+        "accept-charset",
+        "accept-encoding",
+        "accept-language",
+        "authorization",
+        "connection",
+        "content-type",
+        "content-length",
+        "cookie",
+        "cookie2",
+        "host",
+        "pragma",
+        "referer",
+        "user-agent"
+    };
+    // Ajp13 specific -  needs refactoring for the new model
+    /**
+     * Maximum Total byte size for a AJP packet
+     */
+    public static final int MAX_PACKET_SIZE=8192;
+    /**
+     * Size of basic packet header
+     */
+    public static final int H_SIZE=4;  
+    /**
+     * Maximum size of data that can be sent in one packet
+     */
+    public static final int  MAX_READ_SIZE = MAX_PACKET_SIZE - H_SIZE - 2;
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/common/ChannelJni.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/common/ChannelJni.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/common/ChannelJni.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,191 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.jk.common;
+
+import java.io.IOException;
+
+import org.apache.jk.core.JkHandler;
+import org.apache.jk.core.Msg;
+import org.apache.jk.core.MsgContext;
+import org.apache.jk.core.JkChannel;
+
+import org.apache.coyote.Request;
+/** Pass messages using jni 
+ *
+ * @author Costin Manolache
+ */
+public class ChannelJni extends JniHandler implements JkChannel {
+    int receivedNote=1;
+
+    public ChannelJni() {
+        // we use static for now, it's easier on the C side.
+        // Easy to change after we get everything working
+    }
+
+    public void init() throws IOException {
+        super.initNative("channel.jni:jni");
+
+        if( apr==null ) return;
+        
+        // We'll be called from C. This deals with that.
+        apr.addJkHandler( "channelJni", this );        
+        log.info("JK: listening on channel.jni:jni" );
+        
+        if( next==null ) {
+            if( nextName!=null ) 
+                setNext( wEnv.getHandler( nextName ) );
+            if( next==null )
+                next=wEnv.getHandler( "dispatch" );
+            if( next==null )
+                next=wEnv.getHandler( "request" );
+            if( log.isDebugEnabled() )
+                log.debug("Setting default next " + next.getClass().getName());
+        }
+    }
+
+    /** Receives does nothing - send will put the response
+     *  in the same buffer
+     */
+    public int receive( Msg msg, MsgContext ep )
+        throws IOException
+    {
+        Msg sentResponse=(Msg)ep.getNote( receivedNote );
+        ep.setNote( receivedNote, null );
+
+        if( sentResponse == null ) {
+            if( log.isDebugEnabled() )
+                log.debug("No send() prior to receive(), no data buffer");
+            // No sent() was done prior to receive.
+            msg.reset();
+            msg.end();
+            sentResponse = msg;
+        }
+        
+        sentResponse.processHeader();
+
+        if( log.isTraceEnabled() )
+            sentResponse.dump("received response ");
+
+        if( msg != sentResponse ) {
+            log.error( "Error, in JNI mode the msg used for receive() must be identical with the one used for send()");
+        }
+        
+        return 0;
+    }
+
+    /** Send the packet. XXX This will modify msg !!!
+     *  We could use 2 packets, or sendAndReceive().
+     *    
+     */
+    public int send( Msg msg, MsgContext ep )
+        throws IOException
+    {
+        ep.setNote( receivedNote, null );
+        if( log.isDebugEnabled() ) log.debug("ChannelJni.send: "  +  msg );
+
+        int rc=super.nativeDispatch( msg, ep, JK_HANDLE_JNI_DISPATCH, 0);
+
+        // nativeDispatch will put the response in the same buffer.
+        // Next receive() will just get it from there. Very tricky to do
+        // things in one thread instead of 2.
+        ep.setNote( receivedNote, msg );
+        
+        return rc;
+    }
+
+    public int flush(Msg msg, MsgContext ep) throws IOException {
+        ep.setNote( receivedNote, null );
+        return OK;
+    }
+
+    public boolean isSameAddress(MsgContext ep) {
+        return true;
+    }
+
+    public void registerRequest(Request req, MsgContext ep, int count) {
+        // Not supported.
+    }
+
+    public String getChannelName() {
+        return getName();
+    }
+    /** Receive a packet from the C side. This is called from the C
+     *  code using invocation, but only for the first packet - to avoid
+     *  recursivity and thread problems.
+     *
+     *  This may look strange, but seems the best solution for the
+     *  problem ( the problem is that we don't have 'continuation' ).
+     *
+     *  sendPacket will move the thread execution on the C side, and
+     *  return when another packet is available. For packets that
+     *  are one way it'll return after it is processed too ( having
+     *  2 threads is far more expensive ).
+     *
+     *  Again, the goal is to be efficient and behave like all other
+     *  Channels ( so the rest of the code can be shared ). Playing with
+     *  java objects on C is extremely difficult to optimize and do
+     *  right ( IMHO ), so we'll try to keep it simple - byte[] passing,
+     *  the conversion done in java ( after we know the encoding and
+     *  if anyone asks for it - same lazy behavior as in 3.3 ).
+     */
+    public  int invoke(Msg msg, MsgContext ep )  throws IOException {
+        if( apr==null ) return -1;
+        
+        long xEnv=ep.getJniEnv();
+        long cEndpointP=ep.getJniContext();
+
+        int type=ep.getType();
+        if( log.isDebugEnabled() ) log.debug("ChannelJni.invoke: "  + ep + " " + type);
+
+        switch( type ) {
+        case JkHandler.HANDLE_RECEIVE_PACKET:
+            return receive( msg, ep );
+        case JkHandler.HANDLE_SEND_PACKET:
+            return send( msg, ep );
+        case JkHandler.HANDLE_FLUSH:
+            return flush(msg, ep);
+        }
+
+        // Reset receivedNote. It'll be visible only after a SEND and before a receive.
+        ep.setNote( receivedNote, null );
+
+        // Default is FORWARD - called from C 
+        try {
+            // first, we need to get an endpoint. It should be
+            // per/thread - and probably stored by the C side.
+            if( log.isDebugEnabled() ) log.debug("Received request " + xEnv);
+            
+            // The endpoint will store the message pt.
+            msg.processHeader();
+
+            if( log.isTraceEnabled() ) msg.dump("Incoming msg ");
+
+            int status= next.invoke(  msg, ep );
+            
+            if( log.isDebugEnabled() ) log.debug("after processCallbacks " + status);
+            
+            return status;
+        } catch( Exception ex ) {
+            ex.printStackTrace();
+        }
+        return 0;
+    }    
+
+    private static org.apache.commons.logging.Log log=
+        org.apache.commons.logging.LogFactory.getLog( ChannelJni.class );
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/common/ChannelNioSocket.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/common/ChannelNioSocket.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/common/ChannelNioSocket.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,1192 @@
+/*
+ *  Copyright 1999-2005 The Apache Software Foundation
+ *
+ *  Licensed 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.jk.common;
+
+import java.util.Set;
+import java.util.Iterator;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.nio.ByteBuffer;
+import java.nio.channels.Selector;
+import java.nio.channels.SelectionKey;
+import java.nio.channels.SocketChannel;
+import java.nio.channels.ClosedSelectorException;
+import java.nio.channels.ServerSocketChannel;
+import java.nio.channels.CancelledKeyException;
+import java.nio.channels.ClosedChannelException;
+import java.net.URLEncoder;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.net.SocketException;
+
+import javax.management.ListenerNotFoundException;
+import javax.management.MBeanNotificationInfo;
+import javax.management.Notification;
+import javax.management.NotificationBroadcaster;
+import javax.management.NotificationBroadcasterSupport;
+import javax.management.NotificationFilter;
+import javax.management.NotificationListener;
+import javax.management.ObjectName;
+
+import org.apache.commons.modeler.Registry;
+import org.apache.jk.core.JkHandler;
+import org.apache.jk.core.Msg;
+import org.apache.jk.core.MsgContext;
+import org.apache.jk.core.JkChannel;
+import org.apache.jk.core.WorkerEnv;
+import org.apache.coyote.Request;
+import org.apache.coyote.RequestGroupInfo;
+import org.apache.coyote.RequestInfo;
+import org.apache.tomcat.util.threads.ThreadPool;
+import org.apache.tomcat.util.threads.ThreadPoolRunnable;
+
+/** 
+ * Accept ( and send ) TCP messages.
+ *
+ * @author Costin Manolache
+ * @author Bill Barker
+ * jmx:mbean name="jk:service=ChannelNioSocket"
+ *            description="Accept socket connections"
+ * jmx:notification name="org.apache.coyote.INVOKE
+ * jmx:notification-handler name="org.apache.jk.JK_SEND_PACKET
+ * jmx:notification-handler name="org.apache.jk.JK_RECEIVE_PACKET
+ * jmx:notification-handler name="org.apache.jk.JK_FLUSH
+ *
+ * Jk can use multiple protocols/transports.
+ * Various container adapters should load this object ( as a bean ),
+ * set configurations and use it. Note that the connector will handle
+ * all incoming protocols - it's not specific to ajp1x. The protocol
+ * is abstracted by MsgContext/Message/Channel.
+ *
+ * A lot of the 'original' behavior is hardcoded - this uses Ajp13 wire protocol,
+ * TCP, Ajp14 API etc.
+ * As we add other protocols/transports/APIs this will change, the current goal
+ * is to get the same level of functionality as in the original jk connector.
+ *
+ * XXX Make the 'message type' pluggable
+ */
+public class ChannelNioSocket extends JkHandler
+    implements NotificationBroadcaster, JkChannel {
+    private static org.apache.commons.logging.Log log =
+        org.apache.commons.logging.LogFactory.getLog( ChannelNioSocket.class );
+
+    private int startPort=8009;
+    private int maxPort=8019; // 0 for backward compat.
+    private int port=startPort;
+    private InetAddress inet;
+    private int serverTimeout = 0;
+    private boolean tcpNoDelay=true; // nodelay to true by default
+    private int linger=100;
+    private int socketTimeout = 0;
+    private boolean nioIsBroken = false;
+    private Selector selector = null;
+    private int bufferSize = 8*1024;
+    private int packetSize = 8*1024;
+
+    private long requestCount=0;
+    
+    /* Turning this to true will reduce the latency with about 20%.
+       But it requires changes in tomcat to make sure client-requested
+       flush() is honored ( on my test, I got 367->433 RPS and
+       52->35ms average time with a simple servlet )
+    */
+    
+    ThreadPool tp=ThreadPool.createThreadPool(true);
+
+    /* ==================== Tcp socket options ==================== */
+
+    /**
+     * jmx:managed-constructor description="default constructor"
+     */
+    public ChannelNioSocket() {
+        // This should be integrated with the  domain setup
+    }
+    
+    public ThreadPool getThreadPool() {
+        return tp;
+    }
+
+    public long getRequestCount() {
+        return requestCount;
+    }
+    
+    /** Set the port for the ajp13 channel.
+     *  To support seemless load balancing and jni, we treat this
+     *  as the 'base' port - we'll try up until we find one that is not
+     *  used. We'll also provide the 'difference' to the main coyote
+     *  handler - that will be our 'sessionID' and the position in
+     *  the scoreboard and the suffix for the unix domain socket.
+     *
+     * jmx:managed-attribute description="Port to listen" access="READ_WRITE"
+     */
+    public void setPort( int port ) {
+        this.startPort=port;
+        this.port=port;
+        this.maxPort=port+10;
+    }
+
+    public int getPort() {
+        return port;
+    }
+
+    public void setAddress(InetAddress inet) {
+        this.inet=inet;
+    }
+
+    public void setBufferSize(int bs) {
+        if(bs > 8*1024) {
+            bufferSize = bs;
+        }
+    }
+
+    public int getBufferSize() {
+        return bufferSize;
+    }
+
+    public void setPacketSize(int ps) {
+        if(ps < 8*1024) {
+            ps = 8*1024;
+        }
+        packetSize = ps;
+    }
+
+    public int getPacketSize() {
+        return packetSize;
+    }
+
+    /**
+     * jmx:managed-attribute description="Bind on a specified address" access="READ_WRITE"
+     */
+    public void setAddress(String inet) {
+        try {
+            this.inet= InetAddress.getByName( inet );
+        } catch( Exception ex ) {
+            log.error("Error parsing "+inet,ex);
+        }
+    }
+
+    public String getAddress() {
+        if( inet!=null)
+            return inet.toString();
+        return "/0.0.0.0";
+    }
+
+    /**
+     * Sets the timeout in ms of the server sockets created by this
+     * server. This method allows the developer to make servers
+     * more or less responsive to having their server sockets
+     * shut down.
+     *
+     * <p>By default this value is 1000ms.
+     */
+    public void setServerTimeout(int timeout) {
+        this.serverTimeout = timeout;
+    }
+    public int getServerTimeout() {
+        return serverTimeout;
+    }
+
+    public void setTcpNoDelay( boolean b ) {
+        tcpNoDelay=b;
+    }
+
+    public boolean getTcpNoDelay() {
+        return tcpNoDelay;
+    }
+    
+    public void setSoLinger( int i ) {
+        linger=i;
+    }
+
+    public int getSoLinger() {
+        return linger;
+    }
+    
+    public void setSoTimeout( int i ) {
+        socketTimeout=i;
+    }
+
+    public int getSoTimeout() {
+        return socketTimeout;
+    }
+
+    public void setMaxPort( int i ) {
+        maxPort=i;
+    }
+
+    public int getMaxPort() {
+        return maxPort;
+    }
+
+    /** At startup we'll look for the first free port in the range.
+        The difference between this port and the beggining of the range
+        is the 'id'.
+        This is usefull for lb cases ( less config ).
+    */
+    public int getInstanceId() {
+        return port-startPort;
+    }
+
+    /** If set to false, the thread pool will be created in
+     *  non-daemon mode, and will prevent main from exiting
+     */
+    public void setDaemon( boolean b ) {
+        tp.setDaemon( b );
+    }
+
+    public boolean getDaemon() {
+        return tp.getDaemon();
+    }
+
+
+    public void setMaxThreads( int i ) {
+        if( log.isDebugEnabled()) log.debug("Setting maxThreads " + i);
+        tp.setMaxThreads(i);
+    }
+    
+    public void setMinSpareThreads( int i ) {
+        if( log.isDebugEnabled()) log.debug("Setting minSpareThreads " + i);
+        tp.setMinSpareThreads(i);
+    }
+
+    public void setMaxSpareThreads( int i ) {
+        if( log.isDebugEnabled()) log.debug("Setting maxSpareThreads " + i);
+        tp.setMaxSpareThreads(i);
+    }
+
+    public int getMaxThreads() {
+        return tp.getMaxThreads();   
+    }
+    
+    public int getMinSpareThreads() {
+        return tp.getMinSpareThreads();   
+    }
+
+    public int getMaxSpareThreads() {
+        return tp.getMaxSpareThreads();   
+    }
+
+    public void setBacklog(int i) {
+    }
+    
+    public void setNioIsBroken(boolean nib) {
+        nioIsBroken = nib;
+    }
+
+    public boolean getNioIsBroken() {
+        return nioIsBroken;
+    }
+    
+    /* ==================== ==================== */
+    ServerSocket sSocket;
+    final int socketNote=1;
+    final int isNote=2;
+    final int osNote=3;
+    final int notifNote=4;
+    boolean paused = false;
+
+    public void pause() throws Exception {
+        synchronized(this) {
+            paused = true;
+        }
+    }
+
+    public void resume()  {
+        synchronized(this) {
+            paused = false;
+            notify();
+        }
+    }
+
+
+    public void accept( MsgContext ep ) throws IOException {
+        if( sSocket==null ) return;
+        synchronized(this) {
+            while(paused) {
+                try{ 
+                    wait();
+                } catch(InterruptedException ie) {
+                    //Ignore, since can't happen
+                }
+            }
+        }
+        SocketChannel sc=sSocket.getChannel().accept();
+        Socket s = sc.socket();
+        ep.setNote( socketNote, s );
+        if(log.isDebugEnabled() )
+            log.debug("Accepted socket " + s +" channel "  + sc.isBlocking());
+
+        try {
+            setSocketOptions(s);
+        } catch(SocketException sex) {
+            log.debug("Error initializing Socket Options", sex);
+        }
+        
+        requestCount++;
+
+        sc.configureBlocking(false);
+        InputStream is=new SocketInputStream(sc);
+        OutputStream os = new SocketOutputStream(sc);
+        ep.setNote( isNote, is );
+        ep.setNote( osNote, os );
+        ep.setControl( tp );
+    }
+
+    private void setSocketOptions(Socket s) throws SocketException {
+        if( socketTimeout > 0 ) 
+            s.setSoTimeout( socketTimeout );
+        
+        s.setTcpNoDelay( tcpNoDelay ); // set socket tcpnodelay state
+
+        if( linger > 0 )
+            s.setSoLinger( true, linger);
+    }
+
+    public void resetCounters() {
+        requestCount=0;
+    }
+
+    /** Called after you change some fields at runtime using jmx.
+        Experimental for now.
+    */
+    public void reinit() throws IOException {
+        destroy();
+        init();
+    }
+
+    /**
+     * jmx:managed-operation
+     */
+    public void init() throws IOException {
+        // Find a port.
+        if (startPort == 0) {
+            port = 0;
+            if(log.isInfoEnabled())
+                log.info("JK: ajp13 disabling channelNioSocket");
+            running = true;
+            return;
+        }
+        if (maxPort < startPort)
+            maxPort = startPort;
+        ServerSocketChannel ssc = ServerSocketChannel.open();
+        ssc.configureBlocking(false);
+        for( int i=startPort; i<=maxPort; i++ ) {
+            try {
+                InetSocketAddress iddr = null;
+                if( inet == null ) {
+                    iddr = new InetSocketAddress( i);
+                } else {
+                    iddr=new InetSocketAddress( inet, i);
+                }
+                sSocket = ssc.socket();
+                sSocket.bind(iddr);
+                port=i;
+                break;
+            } catch( IOException ex ) {
+                if(log.isInfoEnabled())
+                    log.info("Port busy " + i + " " + ex.toString());
+                sSocket = null;
+            }
+        }
+
+        if( sSocket==null ) {
+            log.error("Can't find free port " + startPort + " " + maxPort );
+            return;
+        }
+        if(log.isInfoEnabled())
+            log.info("JK: ajp13 listening on " + getAddress() + ":" + port );
+
+        selector = Selector.open();
+        ssc.register(selector, SelectionKey.OP_ACCEPT);
+        // If this is not the base port and we are the 'main' channleSocket and
+        // SHM didn't already set the localId - we'll set the instance id
+        if( "channelNioSocket".equals( name ) &&
+            port != startPort &&
+            (wEnv.getLocalId()==0) ) {
+            wEnv.setLocalId(  port - startPort );
+        }
+
+        // XXX Reverse it -> this is a notification generator !!
+        if( next==null && wEnv!=null ) {
+            if( nextName!=null )
+                setNext( wEnv.getHandler( nextName ) );
+            if( next==null )
+                next=wEnv.getHandler( "dispatch" );
+            if( next==null )
+                next=wEnv.getHandler( "request" );
+        }
+        JMXRequestNote =wEnv.getNoteId( WorkerEnv.ENDPOINT_NOTE, "requestNote");
+        running = true;
+
+        // Run a thread that will accept connections.
+        // XXX Try to find a thread first - not sure how...
+        if( this.domain != null ) {
+            try {
+                tpOName=new ObjectName(domain + ":type=ThreadPool,name=" + 
+                                       getChannelName());
+
+                Registry.getRegistry(null, null)
+                    .registerComponent(tp, tpOName, null);
+
+                rgOName = new ObjectName
+                    (domain+":type=GlobalRequestProcessor,name=" + getChannelName());
+                Registry.getRegistry(null, null)
+                    .registerComponent(global, rgOName, null);
+            } catch (Exception e) {
+                log.error("Can't register threadpool" );
+            }
+        }
+
+        tp.start();
+        Poller pollAjp = new Poller();
+        tp.runIt(pollAjp);
+    }
+
+    ObjectName tpOName;
+    ObjectName rgOName;
+    RequestGroupInfo global=new RequestGroupInfo();
+    int JMXRequestNote;
+
+    public void start() throws IOException{
+        if( sSocket==null )
+            init();
+        resume();
+    }
+
+    public void stop() throws IOException {
+        destroy();
+    }
+
+    public void registerRequest(Request req, MsgContext ep, int count) {
+        if(this.domain != null) {
+            try {
+                RequestInfo rp=req.getRequestProcessor();
+                rp.setGlobalProcessor(global);
+                ObjectName roname = new ObjectName
+                    (getDomain() + ":type=RequestProcessor,worker="+
+                     getChannelName()+",name=JkRequest" +count);
+                ep.setNote(JMXRequestNote, roname);
+                        
+                Registry.getRegistry(null, null).registerComponent( rp, roname, null);
+            } catch( Exception ex ) {
+                log.warn("Error registering request");
+            }
+        }
+    }
+
+    public void open(MsgContext ep) throws IOException {
+    }
+
+    
+    public void close(MsgContext ep) throws IOException {
+        Socket s=(Socket)ep.getNote( socketNote );
+        SelectionKey key = s.getChannel().keyFor(selector);
+        if(key != null) {
+            key.cancel();
+        }
+        s.close();
+    }
+
+    public void destroy() throws IOException {
+        running = false;
+        try {
+            /* If we disabled the channel return */
+            if (port == 0)
+                return;
+            tp.shutdown();
+
+            selector.wakeup().close();
+            sSocket.close(); // XXX?
+            
+            if( tpOName != null )  {
+                Registry.getRegistry(null, null).unregisterComponent(tpOName);
+            }
+            if( rgOName != null ) {
+                Registry.getRegistry(null, null).unregisterComponent(rgOName);
+            }
+        } catch(Exception e) {
+            log.info("Error shutting down the channel " + port + " " +
+                    e.toString());
+            if( log.isDebugEnabled() ) log.debug("Trace", e);
+        }
+    }
+
+    public int send( Msg msg, MsgContext ep)
+        throws IOException    {
+        msg.end(); // Write the packet header
+        byte buf[]=msg.getBuffer();
+        int len=msg.getLen();
+        
+        if(log.isTraceEnabled() )
+            log.trace("send() " + len + " " + buf[4] );
+
+        OutputStream os=(OutputStream)ep.getNote( osNote );
+        os.write( buf, 0, len );
+        return len;
+    }
+
+    public int flush( Msg msg, MsgContext ep)
+        throws IOException    {
+        OutputStream os=(OutputStream)ep.getNote( osNote );
+        os.flush();
+        return 0;
+    }
+
+    public int receive( Msg msg, MsgContext ep )
+        throws IOException    {
+        if (log.isTraceEnabled()) {
+            log.trace("receive() ");
+        }
+
+        byte buf[]=msg.getBuffer();
+        int hlen=msg.getHeaderLength();
+        
+        // XXX If the length in the packet header doesn't agree with the
+        // actual number of bytes read, it should probably return an error
+        // value.  Also, callers of this method never use the length
+        // returned -- should probably return true/false instead.
+
+        int rd = this.read(ep, buf, 0, hlen );
+        
+        if(rd < 0) {
+            // Most likely normal apache restart.
+            // log.warn("Wrong message " + rd );
+            return rd;
+        }
+
+        msg.processHeader();
+
+        /* After processing the header we know the body
+           length
+        */
+        int blen=msg.getLen();
+        
+        // XXX check if enough space - it's assert()-ed !!!
+        
+        int total_read = 0;
+        
+        total_read = this.read(ep, buf, hlen, blen);
+        
+        if ((total_read <= 0) && (blen > 0)) {
+            log.warn("can't read body, waited #" + blen);
+            return  -1;
+        }
+        
+        if (total_read != blen) {
+             log.warn( "incomplete read, waited #" + blen +
+                        " got only " + total_read);
+            return -2;
+        }
+        
+        return total_read;
+    }
+    
+    /**
+     * Read N bytes from the InputStream, and ensure we got them all
+     * Under heavy load we could experience many fragmented packets
+     * just read Unix Network Programming to recall that a call to
+     * read didn't ensure you got all the data you want
+     *
+     * from read() Linux manual
+     *
+     * On success, the number of bytes read is returned (zero indicates end
+     * of file),and the file position is advanced by this number.
+     * It is not an error if this number is smaller than the number of bytes
+     * requested; this may happen for example because fewer bytes
+     * are actually available right now (maybe because we were close to
+     * end-of-file, or because we are reading from a pipe, or  from  a
+     * terminal),  or  because  read()  was interrupted by a signal.
+     * On error, -1 is returned, and errno is set appropriately. In this
+     * case it is left unspecified whether the file position (if any) changes.
+     *
+     **/
+    public int read( MsgContext ep, byte[] b, int offset, int len)
+        throws IOException
+    {
+        InputStream is=(InputStream)ep.getNote( isNote );
+        int pos = 0;
+        int got;
+
+        while(pos < len) {
+            try {
+                got = is.read(b, pos + offset, len - pos);
+            } catch(ClosedChannelException sex) {
+                if(pos > 0) {
+                    log.info("Error reading data after "+pos+"bytes",sex);
+                } else {
+                    log.debug("Error reading data", sex);
+                }
+                got = -1;
+            }
+            if (log.isTraceEnabled()) {
+                log.trace("read() " + b + " " + (b==null ? 0: b.length) + " " +
+                          offset + " " + len + " = " + got );
+            }
+
+            // connection just closed by remote. 
+            if (got <= 0) {
+                // This happens periodically, as apache restarts
+                // periodically.
+                // It should be more gracefull ! - another feature for Ajp14
+                // log.warn( "server has closed the current connection (-1)" );
+                return -3;
+            }
+
+            pos += got;
+        }
+        return pos;
+    }
+    
+    protected boolean running=true;
+    
+    /** Accept incoming connections, dispatch to the thread pool
+     */
+    void acceptConnections() {
+        if( running ) {
+            try{
+                MsgContext ep=createMsgContext();
+                ep.setSource(this);
+                ep.setWorkerEnv( wEnv );
+                this.accept(ep);
+
+                if( !running ) return;
+                
+                // Since this is a long-running connection, we don't care
+                // about the small GC
+                SocketConnection ajpConn=
+                    new SocketConnection( ep);
+                ajpConn.register(ep);
+            }catch(Exception ex) {
+                if (running)
+                    log.warn("Exception executing accept" ,ex);
+            }
+        }
+    }
+
+
+    // XXX This should become handleNotification
+    public int invoke( Msg msg, MsgContext ep ) throws IOException {
+        int type=ep.getType();
+
+        switch( type ) {
+        case JkHandler.HANDLE_RECEIVE_PACKET:
+            if( log.isDebugEnabled()) log.debug("RECEIVE_PACKET ?? ");
+            return receive( msg, ep );
+        case JkHandler.HANDLE_SEND_PACKET:
+            return send( msg, ep );
+        case JkHandler.HANDLE_FLUSH:
+            return flush( msg, ep );
+        }
+
+        if( log.isTraceEnabled() )
+            log.trace("Call next " + type + " " + next);
+
+        // Send notification
+        if( nSupport!=null ) {
+            Notification notif=(Notification)ep.getNote(notifNote);
+            if( notif==null ) {
+                notif=new Notification("channelNioSocket.message", ep, requestCount );
+                ep.setNote( notifNote, notif);
+            }
+            nSupport.sendNotification(notif);
+        }
+
+        if( next != null ) {
+            return next.invoke( msg, ep );
+        } else {
+            log.info("No next ");
+        }
+
+        return OK;
+    }
+    
+    public boolean isSameAddress(MsgContext ep) {
+        Socket s=(Socket)ep.getNote( socketNote );
+        return isSameAddress( s.getLocalAddress(), s.getInetAddress());
+    }
+    
+    public String getChannelName() {
+        String encodedAddr = "";
+        if (inet != null && !"0.0.0.0".equals(inet.getHostAddress())) {
+            encodedAddr = getAddress();
+            if (encodedAddr.startsWith("/"))
+                encodedAddr = encodedAddr.substring(1);
+            encodedAddr = URLEncoder.encode(encodedAddr) + "-";
+        }
+        return ("jk-" + encodedAddr + port);
+    }
+    
+    /**
+     * Return <code>true</code> if the specified client and server addresses
+     * are the same.  This method works around a bug in the IBM 1.1.8 JVM on
+     * Linux, where the address bytes are returned reversed in some
+     * circumstances.
+     *
+     * @param server The server's InetAddress
+     * @param client The client's InetAddress
+     */
+    public static boolean isSameAddress(InetAddress server, InetAddress client)
+    {
+        // Compare the byte array versions of the two addresses
+        byte serverAddr[] = server.getAddress();
+        byte clientAddr[] = client.getAddress();
+        if (serverAddr.length != clientAddr.length)
+            return (false);
+        boolean match = true;
+        for (int i = 0; i < serverAddr.length; i++) {
+            if (serverAddr[i] != clientAddr[i]) {
+                match = false;
+                break;
+            }
+        }
+        if (match)
+            return (true);
+
+        // Compare the reversed form of the two addresses
+        for (int i = 0; i < serverAddr.length; i++) {
+            if (serverAddr[i] != clientAddr[(serverAddr.length-1)-i])
+                return (false);
+        }
+        return (true);
+    }
+
+    public void sendNewMessageNotification(Notification notification) {
+        if( nSupport!= null )
+            nSupport.sendNotification(notification);
+    }
+
+    private NotificationBroadcasterSupport nSupport= null;
+
+    public void addNotificationListener(NotificationListener listener,
+                                        NotificationFilter filter,
+                                        Object handback)
+            throws IllegalArgumentException
+    {
+        if( nSupport==null ) nSupport=new NotificationBroadcasterSupport();
+        nSupport.addNotificationListener(listener, filter, handback);
+    }
+
+    public void removeNotificationListener(NotificationListener listener)
+            throws ListenerNotFoundException
+    {
+        if( nSupport!=null)
+            nSupport.removeNotificationListener(listener);
+    }
+
+    MBeanNotificationInfo notifInfo[]=new MBeanNotificationInfo[0];
+
+    public void setNotificationInfo( MBeanNotificationInfo info[]) {
+        this.notifInfo=info;
+    }
+
+    public MBeanNotificationInfo[] getNotificationInfo() {
+        return notifInfo;
+    }
+
+    protected class SocketConnection implements ThreadPoolRunnable {
+        MsgContext ep;
+        MsgAjp recv = new MsgAjp(packetSize);
+        boolean inProgress = false;
+
+        SocketConnection(MsgContext ep) {
+            this.ep=ep;
+        }
+
+        public Object[] getInitData() {
+            return null;
+        }
+    
+        public void runIt(Object perTh[]) {
+            if(!processConnection(ep)) {
+                unregister(ep);
+            }
+        }
+
+        public boolean isRunning() {
+            return inProgress;
+        }
+
+        public  void setFinished() {
+            inProgress = false;
+        }
+
+        /** Process a single ajp connection.
+         */
+        boolean processConnection(MsgContext ep) {
+            try {
+                InputStream sis = (InputStream)ep.getNote(isNote);
+                boolean haveInput = true;
+                while(haveInput) {
+                    if( !running || paused ) {
+                        return false;
+                    }
+                    int status= receive( recv, ep );
+                    if( status <= 0 ) {
+                        if( status==-3)
+                            log.debug( "server has been restarted or reset this connection" );
+                        else 
+                            log.warn("Closing ajp connection " + status );
+                        return false;
+                    }
+                    ep.setLong( MsgContext.TIMER_RECEIVED, System.currentTimeMillis());
+                    
+                    ep.setType( 0 );
+                    // Will call next
+                    status= invoke( recv, ep );
+                    if( status != JkHandler.OK ) {
+                        log.warn("processCallbacks status " + status );
+                        return false;
+                    }
+                    synchronized(this) {
+                        synchronized(sis) {
+                            haveInput = sis.available() > 0;
+                        }
+                        if(!haveInput) {
+                            setFinished();
+                        } else {
+                            if(log.isDebugEnabled())
+                                log.debug("KeepAlive: "+sis.available());
+                        }
+                    }
+                } 
+            } catch( Exception ex ) {
+                String msg = ex.getMessage();
+                if( msg != null && msg.indexOf( "Connection reset" ) >= 0)
+                    log.debug( "Server has been restarted or reset this connection");
+                else if (msg != null && msg.indexOf( "Read timed out" ) >=0 )
+                    log.debug( "connection timeout reached");            
+                else
+                    log.error( "Error, processing connection", ex);
+                return false;
+            } 
+            return true;
+        }
+
+        synchronized void  process(SelectionKey sk) {
+            if(!sk.isValid()) {
+                return;
+            }
+            if(sk.isReadable()) {
+                SocketInputStream sis = (SocketInputStream)ep.getNote(isNote);
+                boolean isok = sis.readAvailable();
+                if(!inProgress) {
+                    if(isok) {
+                        if(sis.available() > 0 || !nioIsBroken){
+                            inProgress = true;
+                            tp.runIt(this);
+                        }
+                    } else {
+                        unregister(ep);
+                        return;
+                    }
+                } 
+            }
+            if(sk.isWritable()) {
+                Object os = ep.getNote(osNote);
+                synchronized(os) {
+                    os.notify();
+                }
+            }
+        }
+
+        synchronized void unregister(MsgContext ep) {
+            try{
+                close(ep);
+            } catch(Exception e) {
+                log.error("Error closing connection", e);
+            }
+            try{
+                Request req = (Request)ep.getRequest();
+                if( req != null ) {
+                    ObjectName roname = (ObjectName)ep.getNote(JMXRequestNote);
+                    if( roname != null ) {
+                        Registry.getRegistry(null, null).unregisterComponent(roname);
+                    }
+                    req.getRequestProcessor().setGlobalProcessor(null);
+                }
+            } catch( Exception ee) {
+                log.error( "Error, releasing connection",ee);
+            }
+        }
+
+        void register(MsgContext ep) {
+            Socket s = (Socket)ep.getNote(socketNote);
+            try {
+                s.getChannel().register(selector, SelectionKey.OP_READ, this);
+            } catch(IOException iex) {
+                log.error("Unable to register connection",iex);
+                unregister(ep);
+            }
+        }
+
+    }
+
+    protected class Poller implements ThreadPoolRunnable {
+
+        Poller() {
+        }
+
+        public Object[] getInitData() {
+            return null;
+        }
+    
+        public void runIt(Object perTh[]) {
+            while(running) {
+                try {
+                    int ns = selector.select(serverTimeout);
+                    if(log.isDebugEnabled())
+                        log.debug("Selecting "+ns+" channels");
+                    if(ns > 0) {
+                        Set sels = selector.selectedKeys();
+                        Iterator it = sels.iterator();
+                        while(it.hasNext()) {
+                            SelectionKey sk = (SelectionKey)it.next();
+                            if(sk.isValid()) {
+                                if(sk.isAcceptable()) {
+                                    acceptConnections();
+                                } else {
+                                    SocketConnection sc = (SocketConnection)sk.attachment();
+                                    sc.process(sk);
+                                }
+                            } else {
+                                sk.cancel();
+                            }
+                            it.remove();
+                        }
+                    }
+                } catch(ClosedSelectorException cse) {
+                    log.debug("Selector is closed");
+                    return;
+                } catch(CancelledKeyException cke) {
+                    log.debug("Key Cancelled", cke);
+                } catch(IOException iex) {
+                    log.warn("IO Error in select",iex);
+                } catch(Exception ex) {
+                    log.warn("Error processing select",ex);
+                }
+            }
+        }
+    }
+
+    protected class SocketInputStream extends InputStream {
+        final int BUFFER_SIZE = 8200;
+        private ByteBuffer buffer = ByteBuffer.allocateDirect(BUFFER_SIZE);
+        private SocketChannel channel;
+        private boolean blocking = false;
+        private boolean isClosed = false;
+        private volatile boolean dataAvailable = false;
+
+        SocketInputStream(SocketChannel channel) {
+            this.channel = channel;
+            buffer.limit(0);
+        }
+
+        public int available() {
+            return buffer.remaining();
+        }
+
+        public void mark(int readlimit) {
+            buffer.mark();
+        }
+
+        public boolean markSupported() {
+            return true;
+        }
+
+        public void reset() {
+            buffer.reset();
+        }
+
+        public synchronized int read() throws IOException {
+            if(!checkAvailable(1)) {
+                block(1);
+            }
+            return buffer.get();
+        }
+
+        private boolean checkAvailable(int nbyte) throws IOException {
+            if(isClosed) {
+                throw new ClosedChannelException();
+            }
+            return buffer.remaining() >=  nbyte;
+        }
+
+        private int fill(int nbyte) throws IOException {
+            int rem = nbyte;
+            int read = 0;
+            boolean eof = false;
+            byte [] oldData = null;
+            if(buffer.remaining() > 0) {
+                // should rarely happen, so short-lived GC shouldn't hurt
+                // as much as allocating a long-lived buffer for this
+                if(log.isDebugEnabled())
+                    log.debug("Saving old buffer: "+buffer.remaining());
+                oldData = new byte[buffer.remaining()];
+                buffer.get(oldData);
+            }
+            buffer.clear();
+            if(oldData != null) {
+                buffer.put(oldData);
+            }
+            while(rem > 0) {
+                int count = channel.read(buffer);
+                if(count < 0) {
+                    eof = true;
+                    break;
+                } else if(count == 0) {
+                    log.debug("Failed to recieve signaled read: ");
+                    break;
+                }
+                read += count;
+                rem -= count;
+            }
+            buffer.flip();
+            return eof ? -1 : read;
+        }
+
+        synchronized boolean readAvailable() {
+            if(blocking) {
+                dataAvailable = true;
+                notify();
+            } else if(dataAvailable) {
+                log.debug("Race Condition");
+            } else {
+                int nr=0;
+
+                try {
+                    nr = fill(1);
+                } catch(ClosedChannelException cce) {
+                    log.debug("Channel is closed",cce);
+                    nr = -1;
+                } catch(IOException iex) {
+                    log.warn("Exception processing read",iex);
+                    nr = -1; // Can't handle this yet
+                }
+                if(nr < 0) {
+                    isClosed = true;
+                    notify();
+                    return false;
+                } else if(nr == 0) {
+                    if(!nioIsBroken) {
+                        dataAvailable = (buffer.remaining() <= 0);
+                    }
+                }
+            }
+            return true;
+        }
+
+        public int read(byte [] data) throws IOException {
+            return read(data, 0, data.length);
+        }
+
+        public synchronized int read(byte [] data, int offset, int len) throws IOException {
+            int olen = len;
+            while(!checkAvailable(len)) {
+                int avail = buffer.remaining();
+                if(avail > 0) {
+                    buffer.get(data, offset, avail);
+                }
+                len -= avail;
+                offset += avail;
+                block(len);
+            }
+            buffer.get(data, offset, len);
+            return olen;
+        }
+
+        private void block(int len) throws IOException {
+            if(len <= 0) {
+                return;
+            }
+            if(!dataAvailable) {
+                blocking = true;
+                if(log.isDebugEnabled())
+                    log.debug("Waiting for "+len+" bytes to be available");
+                try{
+                    wait(socketTimeout);
+                }catch(InterruptedException iex) {
+                    log.debug("Interrupted",iex);
+                }
+                blocking = false;
+            }
+            if(dataAvailable) {
+                dataAvailable = false;
+                if(fill(len) < 0) {
+                    isClosed = true;
+                } 
+            }
+        }
+    }
+
+    protected class SocketOutputStream extends OutputStream {
+        ByteBuffer buffer = ByteBuffer.allocateDirect(bufferSize);
+        SocketChannel channel;
+
+        SocketOutputStream(SocketChannel channel) {
+            this.channel = channel;
+        }
+
+        public void write(int b) throws IOException {
+            if(!checkAvailable(1)) {
+                flush();
+            }
+            buffer.put((byte)b);
+        }
+
+        public void write(byte [] data) throws IOException {
+            write(data, 0, data.length);
+        }
+
+        public void write(byte [] data, int offset, int len) throws IOException {
+            if(!checkAvailable(len)) {
+                flush();
+            }
+            buffer.put(data, offset, len);
+        }
+
+        public void flush() throws IOException {
+            buffer.flip();
+            while(buffer.hasRemaining()) {
+                int count = channel.write(buffer);
+                if(count == 0) {
+                    synchronized(this) {
+                        SelectionKey key = channel.keyFor(selector);
+                        key.interestOps(SelectionKey.OP_WRITE);
+                        if(log.isDebugEnabled())
+                            log.debug("Blocking for channel write: "+buffer.remaining());
+                        try {
+                            wait();
+                        } catch(InterruptedException iex) {
+                            // ignore, since can't happen
+                        }
+                        key.interestOps(SelectionKey.OP_READ);
+                    }
+                }
+            }
+            buffer.clear();
+        }
+
+        private boolean checkAvailable(int len) {
+            return buffer.remaining() >= len;
+        }
+    }
+
+}
+

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/common/ChannelShm.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/common/ChannelShm.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/common/ChannelShm.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,32 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.jk.common;
+
+import org.apache.jk.core.JkHandler;
+
+
+
+/** Channel using shm.
+ *
+ * @author Costin Manolache
+ */
+public class ChannelShm extends JkHandler {
+
+    // Not implemented yet.
+    
+    
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/common/ChannelSocket.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/common/ChannelSocket.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/common/ChannelSocket.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,895 @@
+/*
+ *  Copyright 1999-2005 The Apache Software Foundation
+ *
+ *  Licensed 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.jk.common;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.URLEncoder;
+import java.net.InetAddress;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.net.SocketException;
+
+import javax.management.ListenerNotFoundException;
+import javax.management.MBeanNotificationInfo;
+import javax.management.Notification;
+import javax.management.NotificationBroadcaster;
+import javax.management.NotificationBroadcasterSupport;
+import javax.management.NotificationFilter;
+import javax.management.NotificationListener;
+import javax.management.ObjectName;
+
+import org.apache.commons.modeler.Registry;
+import org.apache.jk.core.JkHandler;
+import org.apache.jk.core.Msg;
+import org.apache.jk.core.MsgContext;
+import org.apache.jk.core.JkChannel;
+import org.apache.jk.core.WorkerEnv;
+import org.apache.coyote.Request;
+import org.apache.coyote.RequestGroupInfo;
+import org.apache.coyote.RequestInfo;
+import org.apache.tomcat.util.threads.ThreadPool;
+import org.apache.tomcat.util.threads.ThreadPoolRunnable;
+
+/** 
+ * Accept ( and send ) TCP messages.
+ *
+ * @author Costin Manolache
+ * @author Bill Barker
+ * jmx:mbean name="jk:service=ChannelNioSocket"
+ *            description="Accept socket connections"
+ * jmx:notification name="org.apache.coyote.INVOKE
+ * jmx:notification-handler name="org.apache.jk.JK_SEND_PACKET
+ * jmx:notification-handler name="org.apache.jk.JK_RECEIVE_PACKET
+ * jmx:notification-handler name="org.apache.jk.JK_FLUSH
+ *
+ * Jk can use multiple protocols/transports.
+ * Various container adapters should load this object ( as a bean ),
+ * set configurations and use it. Note that the connector will handle
+ * all incoming protocols - it's not specific to ajp1x. The protocol
+ * is abstracted by MsgContext/Message/Channel.
+ *
+ * A lot of the 'original' behavior is hardcoded - this uses Ajp13 wire protocol,
+ * TCP, Ajp14 API etc.
+ * As we add other protocols/transports/APIs this will change, the current goal
+ * is to get the same level of functionality as in the original jk connector.
+ *
+ * XXX Make the 'message type' pluggable
+ */
+public class ChannelSocket extends JkHandler
+    implements NotificationBroadcaster, JkChannel {
+    private static org.apache.commons.logging.Log log =
+        org.apache.commons.logging.LogFactory.getLog( ChannelSocket.class );
+
+    private int startPort=8009;
+    private int maxPort=8019; // 0 for backward compat.
+    private int port=startPort;
+    private InetAddress inet;
+    private int serverTimeout;
+    private boolean tcpNoDelay=true; // nodelay to true by default
+    private int linger=100;
+    private int socketTimeout;
+    private int bufferSize = -1;
+    private int packetSize = 8*1024;
+
+
+    private long requestCount=0;
+    
+    ThreadPool tp=ThreadPool.createThreadPool(true);
+
+    /* ==================== Tcp socket options ==================== */
+
+    /**
+     * jmx:managed-constructor description="default constructor"
+     */
+    public ChannelSocket() {
+        // This should be integrated with the  domain setup
+    }
+    
+    public ThreadPool getThreadPool() {
+        return tp;
+    }
+
+    public long getRequestCount() {
+        return requestCount;
+    }
+    
+    /** Set the port for the ajp13 channel.
+     *  To support seemless load balancing and jni, we treat this
+     *  as the 'base' port - we'll try up until we find one that is not
+     *  used. We'll also provide the 'difference' to the main coyote
+     *  handler - that will be our 'sessionID' and the position in
+     *  the scoreboard and the suffix for the unix domain socket.
+     *
+     * jmx:managed-attribute description="Port to listen" access="READ_WRITE"
+     */
+    public void setPort( int port ) {
+        this.startPort=port;
+        this.port=port;
+        this.maxPort=port+10;
+    }
+
+    public int getPort() {
+        return port;
+    }
+
+    public void setAddress(InetAddress inet) {
+        this.inet=inet;
+    }
+
+    /**
+     * jmx:managed-attribute description="Bind on a specified address" access="READ_WRITE"
+     */
+    public void setAddress(String inet) {
+        try {
+            this.inet= InetAddress.getByName( inet );
+        } catch( Exception ex ) {
+            log.error("Error parsing "+inet,ex);
+        }
+    }
+
+    public String getAddress() {
+        if( inet!=null)
+            return inet.toString();
+        return "/0.0.0.0";
+    }
+
+    /**
+     * Sets the timeout in ms of the server sockets created by this
+     * server. This method allows the developer to make servers
+     * more or less responsive to having their server sockets
+     * shut down.
+     *
+     * <p>By default this value is 1000ms.
+     */
+    public void setServerTimeout(int timeout) {
+	this.serverTimeout = timeout;
+    }
+    public int getServerTimeout() {
+        return serverTimeout;
+    }
+
+    public void setTcpNoDelay( boolean b ) {
+	tcpNoDelay=b;
+    }
+
+    public boolean getTcpNoDelay() {
+        return tcpNoDelay;
+    }
+    
+    public void setSoLinger( int i ) {
+	linger=i;
+    }
+
+    public int getSoLinger() {
+        return linger;
+    }
+    
+    public void setSoTimeout( int i ) {
+	socketTimeout=i;
+    }
+
+    public int getSoTimeout() {
+	return socketTimeout;
+    }
+
+    public void setMaxPort( int i ) {
+        maxPort=i;
+    }
+
+    public int getMaxPort() {
+        return maxPort;
+    }
+
+    public void setBufferSize(int bs) {
+        bufferSize = bs;
+    }
+
+    public int getBufferSize() {
+        return bufferSize;
+    }
+
+    public void setPacketSize(int ps) {
+        if(ps < 8*1024) {
+            ps = 8*1024;
+        }
+        packetSize = ps;
+    }
+
+    public int getPacketSize() {
+        return packetSize;
+    }
+
+    /** At startup we'll look for the first free port in the range.
+        The difference between this port and the beggining of the range
+        is the 'id'.
+        This is usefull for lb cases ( less config ).
+    */
+    public int getInstanceId() {
+        return port-startPort;
+    }
+
+    /** If set to false, the thread pool will be created in
+     *  non-daemon mode, and will prevent main from exiting
+     */
+    public void setDaemon( boolean b ) {
+        tp.setDaemon( b );
+    }
+
+    public boolean getDaemon() {
+        return tp.getDaemon();
+    }
+
+
+    public void setMaxThreads( int i ) {
+        if( log.isDebugEnabled()) log.debug("Setting maxThreads " + i);
+        tp.setMaxThreads(i);
+    }
+    
+    public void setMinSpareThreads( int i ) {
+        if( log.isDebugEnabled()) log.debug("Setting minSpareThreads " + i);
+        tp.setMinSpareThreads(i);
+    }
+    
+    public void setMaxSpareThreads( int i ) {
+        if( log.isDebugEnabled()) log.debug("Setting maxSpareThreads " + i);
+        tp.setMaxSpareThreads(i);
+    }
+
+    public int getMaxThreads() {
+        return tp.getMaxThreads();   
+    }
+    
+    public int getMinSpareThreads() {
+        return tp.getMinSpareThreads();   
+    }
+
+    public int getMaxSpareThreads() {
+        return tp.getMaxSpareThreads();   
+    }
+
+    public void setBacklog(int i) {
+    }
+    
+    
+    /* ==================== ==================== */
+    ServerSocket sSocket;
+    final int socketNote=1;
+    final int isNote=2;
+    final int osNote=3;
+    final int notifNote=4;
+    boolean paused = false;
+
+    public void pause() throws Exception {
+        synchronized(this) {
+            paused = true;
+            unLockSocket();
+        }
+    }
+
+    public void resume() throws Exception {
+        synchronized(this) {
+            paused = false;
+            notify();
+        }
+    }
+
+
+    public void accept( MsgContext ep ) throws IOException {
+        if( sSocket==null ) return;
+        synchronized(this) {
+            while(paused) {
+                try{ 
+                    wait();
+                } catch(InterruptedException ie) {
+                    //Ignore, since can't happen
+                }
+            }
+        }
+        Socket s=sSocket.accept();
+        ep.setNote( socketNote, s );
+        if(log.isDebugEnabled() )
+            log.debug("Accepted socket " + s );
+
+        try {
+            setSocketOptions(s);
+        } catch(SocketException sex) {
+            log.debug("Error initializing Socket Options", sex);
+        }
+        
+        requestCount++;
+
+        InputStream is=new BufferedInputStream(s.getInputStream());
+        OutputStream os;
+        if( bufferSize > 0 )
+            os = new BufferedOutputStream( s.getOutputStream(), bufferSize);
+        else
+            os = s.getOutputStream();
+        ep.setNote( isNote, is );
+        ep.setNote( osNote, os );
+        ep.setControl( tp );
+    }
+
+    private void setSocketOptions(Socket s) throws SocketException {
+        if( socketTimeout > 0 ) 
+            s.setSoTimeout( socketTimeout );
+        
+        s.setTcpNoDelay( tcpNoDelay ); // set socket tcpnodelay state
+
+        if( linger > 0 )
+            s.setSoLinger( true, linger);
+    }
+
+    public void resetCounters() {
+        requestCount=0;
+    }
+
+    /** Called after you change some fields at runtime using jmx.
+        Experimental for now.
+    */
+    public void reinit() throws IOException {
+        destroy();
+        init();
+    }
+
+    /**
+     * jmx:managed-operation
+     */
+    public void init() throws IOException {
+        // Find a port.
+        if (startPort == 0) {
+            port = 0;
+            if(log.isInfoEnabled())
+                log.info("JK: ajp13 disabling channelSocket");
+            running = true;
+            return;
+        }
+        if (maxPort < startPort)
+            maxPort = startPort;
+        for( int i=startPort; i<=maxPort; i++ ) {
+            try {
+                if( inet == null ) {
+                    sSocket = new ServerSocket( i, 0 );
+                } else {
+                    sSocket=new ServerSocket( i, 0, inet );
+                }
+                port=i;
+                break;
+            } catch( IOException ex ) {
+                if(log.isInfoEnabled())
+                    log.info("Port busy " + i + " " + ex.toString());
+                continue;
+            }
+        }
+
+        if( sSocket==null ) {
+            log.error("Can't find free port " + startPort + " " + maxPort );
+            return;
+        }
+        if(log.isInfoEnabled())
+            log.info("JK: ajp13 listening on " + getAddress() + ":" + port );
+
+        // If this is not the base port and we are the 'main' channleSocket and
+        // SHM didn't already set the localId - we'll set the instance id
+        if( "channelSocket".equals( name ) &&
+            port != startPort &&
+            (wEnv.getLocalId()==0) ) {
+            wEnv.setLocalId(  port - startPort );
+        }
+        if( serverTimeout > 0 )
+            sSocket.setSoTimeout( serverTimeout );
+
+        // XXX Reverse it -> this is a notification generator !!
+        if( next==null && wEnv!=null ) {
+            if( nextName!=null )
+                setNext( wEnv.getHandler( nextName ) );
+            if( next==null )
+                next=wEnv.getHandler( "dispatch" );
+            if( next==null )
+                next=wEnv.getHandler( "request" );
+        }
+        JMXRequestNote =wEnv.getNoteId( WorkerEnv.ENDPOINT_NOTE, "requestNote");
+        running = true;
+
+        // Run a thread that will accept connections.
+        // XXX Try to find a thread first - not sure how...
+        if( this.domain != null ) {
+            try {
+                tpOName=new ObjectName(domain + ":type=ThreadPool,name=" + 
+                                       getChannelName());
+
+                Registry.getRegistry(null, null)
+                    .registerComponent(tp, tpOName, null);
+
+                rgOName = new ObjectName
+                    (domain+":type=GlobalRequestProcessor,name=" + getChannelName());
+                Registry.getRegistry(null, null)
+                    .registerComponent(global, rgOName, null);
+            } catch (Exception e) {
+                log.error("Can't register threadpool" );
+            }
+        }
+
+        tp.start();
+        SocketAcceptor acceptAjp=new SocketAcceptor(  this );
+        tp.runIt( acceptAjp);
+
+    }
+
+    ObjectName tpOName;
+    ObjectName rgOName;
+    RequestGroupInfo global=new RequestGroupInfo();
+    int JMXRequestNote;
+
+    public void start() throws IOException{
+        if( sSocket==null )
+            init();
+    }
+
+    public void stop() throws IOException {
+        destroy();
+    }
+
+    public void registerRequest(Request req, MsgContext ep, int count) {
+        if(this.domain != null) {
+            try {
+                RequestInfo rp=req.getRequestProcessor();
+                rp.setGlobalProcessor(global);
+                ObjectName roname = new ObjectName
+                    (getDomain() + ":type=RequestProcessor,worker="+
+                     getChannelName()+",name=JkRequest" +count);
+                ep.setNote(JMXRequestNote, roname);
+                        
+                Registry.getRegistry(null, null).registerComponent( rp, roname, null);
+            } catch( Exception ex ) {
+                log.warn("Error registering request");
+            }
+        }
+    }
+
+    public void open(MsgContext ep) throws IOException {
+    }
+
+    
+    public void close(MsgContext ep) throws IOException {
+        Socket s=(Socket)ep.getNote( socketNote );
+        s.close();
+    }
+
+    private void unLockSocket() throws IOException {
+        // Need to create a connection to unlock the accept();
+        Socket s;
+        InetAddress ladr = inet;
+
+        if(port == 0)
+            return;
+        if (ladr == null || "0.0.0.0".equals(ladr.getHostAddress())) {
+            ladr = InetAddress.getLocalHost();
+        }
+        s=new Socket(ladr, port );
+        // setting soLinger to a small value will help shutdown the
+        // connection quicker
+        s.setSoLinger(true, 0);
+
+	s.close();
+    }
+
+    public void destroy() throws IOException {
+        running = false;
+        try {
+            /* If we disabled the channel return */
+            if (port == 0)
+                return;
+            tp.shutdown();
+
+	    if(!paused) {
+		unLockSocket();
+	    }
+
+            sSocket.close(); // XXX?
+            
+            if( tpOName != null )  {
+                Registry.getRegistry(null, null).unregisterComponent(tpOName);
+            }
+            if( rgOName != null ) {
+                Registry.getRegistry(null, null).unregisterComponent(rgOName);
+            }
+        } catch(Exception e) {
+            log.info("Error shutting down the channel " + port + " " +
+                    e.toString());
+            if( log.isDebugEnabled() ) log.debug("Trace", e);
+        }
+    }
+
+    public int send( Msg msg, MsgContext ep)
+        throws IOException    {
+        msg.end(); // Write the packet header
+        byte buf[]=msg.getBuffer();
+        int len=msg.getLen();
+        
+        if(log.isTraceEnabled() )
+            log.trace("send() " + len + " " + buf[4] );
+
+        OutputStream os=(OutputStream)ep.getNote( osNote );
+        os.write( buf, 0, len );
+        return len;
+    }
+
+    public int flush( Msg msg, MsgContext ep)
+        throws IOException    {
+        if( bufferSize > 0 ) {
+            OutputStream os=(OutputStream)ep.getNote( osNote );
+            os.flush();
+        }
+        return 0;
+    }
+
+    public int receive( Msg msg, MsgContext ep )
+        throws IOException    {
+        if (log.isDebugEnabled()) {
+            log.debug("receive() ");
+        }
+
+        byte buf[]=msg.getBuffer();
+        int hlen=msg.getHeaderLength();
+        
+	// XXX If the length in the packet header doesn't agree with the
+	// actual number of bytes read, it should probably return an error
+	// value.  Also, callers of this method never use the length
+	// returned -- should probably return true/false instead.
+
+        int rd = this.read(ep, buf, 0, hlen );
+        
+        if(rd < 0) {
+            // Most likely normal apache restart.
+            // log.warn("Wrong message " + rd );
+            return rd;
+        }
+
+        msg.processHeader();
+
+        /* After processing the header we know the body
+           length
+        */
+        int blen=msg.getLen();
+        
+	// XXX check if enough space - it's assert()-ed !!!
+        
+ 	int total_read = 0;
+        
+        total_read = this.read(ep, buf, hlen, blen);
+        
+        if ((total_read <= 0) && (blen > 0)) {
+            log.warn("can't read body, waited #" + blen);
+            return  -1;
+        }
+        
+        if (total_read != blen) {
+             log.warn( "incomplete read, waited #" + blen +
+                        " got only " + total_read);
+            return -2;
+        }
+        
+	return total_read;
+    }
+    
+    /**
+     * Read N bytes from the InputStream, and ensure we got them all
+     * Under heavy load we could experience many fragmented packets
+     * just read Unix Network Programming to recall that a call to
+     * read didn't ensure you got all the data you want
+     *
+     * from read() Linux manual
+     *
+     * On success, the number of bytes read is returned (zero indicates end
+     * of file),and the file position is advanced by this number.
+     * It is not an error if this number is smaller than the number of bytes
+     * requested; this may happen for example because fewer bytes
+     * are actually available right now (maybe because we were close to
+     * end-of-file, or because we are reading from a pipe, or  from  a
+     * terminal),  or  because  read()  was interrupted by a signal.
+     * On error, -1 is returned, and errno is set appropriately. In this
+     * case it is left unspecified whether the file position (if any) changes.
+     *
+     **/
+    public int read( MsgContext ep, byte[] b, int offset, int len)
+        throws IOException    {
+        InputStream is=(InputStream)ep.getNote( isNote );
+        int pos = 0;
+        int got;
+
+        while(pos < len) {
+            try {
+                got = is.read(b, pos + offset, len - pos);
+            } catch(SocketException sex) {
+                if(pos > 0) {
+                    log.info("Error reading data after "+pos+"bytes",sex);
+                } else {
+                    log.debug("Error reading data", sex);
+                }
+                got = -1;
+            }
+            if (log.isTraceEnabled()) {
+                log.trace("read() " + b + " " + (b==null ? 0: b.length) + " " +
+                          offset + " " + len + " = " + got );
+            }
+
+            // connection just closed by remote. 
+            if (got <= 0) {
+                // This happens periodically, as apache restarts
+                // periodically.
+                // It should be more gracefull ! - another feature for Ajp14
+                // log.warn( "server has closed the current connection (-1)" );
+                return -3;
+            }
+
+            pos += got;
+        }
+        return pos;
+    }
+    
+    protected boolean running=true;
+    
+    /** Accept incoming connections, dispatch to the thread pool
+     */
+    void acceptConnections() {
+        if( log.isDebugEnabled() )
+            log.debug("Accepting ajp connections on " + port);
+        while( running ) {
+	    try{
+                MsgContext ep=createMsgContext();
+                ep.setSource(this);
+                ep.setWorkerEnv( wEnv );
+                this.accept(ep);
+
+                if( !running ) break;
+                
+                // Since this is a long-running connection, we don't care
+                // about the small GC
+                SocketConnection ajpConn=
+                    new SocketConnection(this, ep);
+                tp.runIt( ajpConn );
+	    }catch(Exception ex) {
+                if (running)
+                    log.warn("Exception executing accept" ,ex);
+	    }
+        }
+    }
+
+    /** Process a single ajp connection.
+     */
+    void processConnection(MsgContext ep) {
+        try {
+            MsgAjp recv=new MsgAjp(packetSize);
+            while( running ) {
+                if(paused) { // Drop the connection on pause
+                    break;
+                }
+                int status= this.receive( recv, ep );
+                if( status <= 0 ) {
+                    if( status==-3)
+                        log.debug( "server has been restarted or reset this connection" );
+                    else 
+                        log.warn("Closing ajp connection " + status );
+                    break;
+                }
+                ep.setLong( MsgContext.TIMER_RECEIVED, System.currentTimeMillis());
+                
+                ep.setType( 0 );
+                // Will call next
+                status= this.invoke( recv, ep );
+                if( status!= JkHandler.OK ) {
+                    log.warn("processCallbacks status " + status );
+                    break;
+                }
+            }
+        } catch( Exception ex ) {
+            String msg = ex.getMessage();
+            if( msg != null && msg.indexOf( "Connection reset" ) >= 0)
+                log.debug( "Server has been restarted or reset this connection");
+            else if (msg != null && msg.indexOf( "Read timed out" ) >=0 )
+                log.debug( "connection timeout reached");            
+            else
+                log.error( "Error, processing connection", ex);
+        } finally {
+	    	/*
+	    	 * Whatever happened to this connection (remote closed it, timeout, read error)
+	    	 * the socket SHOULD be closed, or we may be in situation where the webserver
+	    	 * will continue to think the socket is still open and will forward request
+	    	 * to tomcat without receiving ever a reply
+	    	 */
+            try {
+                this.close( ep );
+            }
+            catch( Exception e) {
+                log.error( "Error, closing connection", e);
+            }
+            try{
+                Request req = (Request)ep.getRequest();
+                if( req != null ) {
+                    ObjectName roname = (ObjectName)ep.getNote(JMXRequestNote);
+                    if( roname != null ) {
+                        Registry.getRegistry(null, null).unregisterComponent(roname);
+                    }
+                    req.getRequestProcessor().setGlobalProcessor(null);
+                }
+            } catch( Exception ee) {
+                log.error( "Error, releasing connection",ee);
+            }
+        }
+    }
+
+    // XXX This should become handleNotification
+    public int invoke( Msg msg, MsgContext ep ) throws IOException {
+        int type=ep.getType();
+
+        switch( type ) {
+        case JkHandler.HANDLE_RECEIVE_PACKET:
+            if( log.isDebugEnabled()) log.debug("RECEIVE_PACKET ?? ");
+            return receive( msg, ep );
+        case JkHandler.HANDLE_SEND_PACKET:
+            return send( msg, ep );
+        case JkHandler.HANDLE_FLUSH:
+            return flush( msg, ep );
+        }
+
+        if( log.isDebugEnabled() )
+            log.debug("Call next " + type + " " + next);
+
+        // Send notification
+        if( nSupport!=null ) {
+            Notification notif=(Notification)ep.getNote(notifNote);
+            if( notif==null ) {
+                notif=new Notification("channelSocket.message", ep, requestCount );
+                ep.setNote( notifNote, notif);
+            }
+            nSupport.sendNotification(notif);
+        }
+
+        if( next != null ) {
+            return next.invoke( msg, ep );
+        } else {
+            log.info("No next ");
+        }
+
+        return OK;
+    }
+    
+    public boolean isSameAddress(MsgContext ep) {
+        Socket s=(Socket)ep.getNote( socketNote );
+        return isSameAddress( s.getLocalAddress(), s.getInetAddress());
+    }
+    
+    public String getChannelName() {
+        String encodedAddr = "";
+        if (inet != null && !"0.0.0.0".equals(inet.getHostAddress())) {
+            encodedAddr = getAddress();
+            if (encodedAddr.startsWith("/"))
+                encodedAddr = encodedAddr.substring(1);
+	    encodedAddr = URLEncoder.encode(encodedAddr) + "-";
+        }
+        return ("jk-" + encodedAddr + port);
+    }
+    
+    /**
+     * Return <code>true</code> if the specified client and server addresses
+     * are the same.  This method works around a bug in the IBM 1.1.8 JVM on
+     * Linux, where the address bytes are returned reversed in some
+     * circumstances.
+     *
+     * @param server The server's InetAddress
+     * @param client The client's InetAddress
+     */
+    public static boolean isSameAddress(InetAddress server, InetAddress client)
+    {
+	// Compare the byte array versions of the two addresses
+	byte serverAddr[] = server.getAddress();
+	byte clientAddr[] = client.getAddress();
+	if (serverAddr.length != clientAddr.length)
+	    return (false);
+	boolean match = true;
+	for (int i = 0; i < serverAddr.length; i++) {
+	    if (serverAddr[i] != clientAddr[i]) {
+		match = false;
+		break;
+	    }
+	}
+	if (match)
+	    return (true);
+
+	// Compare the reversed form of the two addresses
+	for (int i = 0; i < serverAddr.length; i++) {
+	    if (serverAddr[i] != clientAddr[(serverAddr.length-1)-i])
+		return (false);
+	}
+	return (true);
+    }
+
+    public void sendNewMessageNotification(Notification notification) {
+        if( nSupport!= null )
+            nSupport.sendNotification(notification);
+    }
+
+    private NotificationBroadcasterSupport nSupport= null;
+
+    public void addNotificationListener(NotificationListener listener,
+                                        NotificationFilter filter,
+                                        Object handback)
+            throws IllegalArgumentException
+    {
+        if( nSupport==null ) nSupport=new NotificationBroadcasterSupport();
+        nSupport.addNotificationListener(listener, filter, handback);
+    }
+
+    public void removeNotificationListener(NotificationListener listener)
+            throws ListenerNotFoundException
+    {
+        if( nSupport!=null)
+            nSupport.removeNotificationListener(listener);
+    }
+
+    MBeanNotificationInfo notifInfo[]=new MBeanNotificationInfo[0];
+
+    public void setNotificationInfo( MBeanNotificationInfo info[]) {
+        this.notifInfo=info;
+    }
+
+    public MBeanNotificationInfo[] getNotificationInfo() {
+        return notifInfo;
+    }
+
+    static class SocketAcceptor implements ThreadPoolRunnable {
+	ChannelSocket wajp;
+    
+	SocketAcceptor(ChannelSocket wajp ) {
+	    this.wajp=wajp;
+	}
+	
+	public Object[] getInitData() {
+	    return null;
+	}
+	
+	public void runIt(Object thD[]) {
+	    wajp.acceptConnections();
+	}
+    }
+
+    static class SocketConnection implements ThreadPoolRunnable {
+	ChannelSocket wajp;
+	MsgContext ep;
+
+	SocketConnection(ChannelSocket wajp, MsgContext ep) {
+	    this.wajp=wajp;
+	    this.ep=ep;
+	}
+
+
+	public Object[] getInitData() {
+	    return null;
+	}
+	
+	public void runIt(Object perTh[]) {
+	    wajp.processConnection(ep);
+	    ep = null;
+	}
+    }
+
+}
+

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/common/ChannelUn.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/common/ChannelUn.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/common/ChannelUn.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,394 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.jk.common;
+
+import java.net.URLEncoder;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import javax.management.ObjectName;
+
+import org.apache.commons.modeler.Registry;
+import org.apache.jk.core.JkHandler;
+import org.apache.jk.core.Msg;
+import org.apache.jk.core.MsgContext;
+import org.apache.jk.core.JkChannel;
+import org.apache.jk.core.WorkerEnv;
+import org.apache.coyote.Request;
+import org.apache.coyote.RequestGroupInfo;
+import org.apache.coyote.RequestInfo;
+import org.apache.tomcat.util.threads.ThreadPool;
+import org.apache.tomcat.util.threads.ThreadPoolRunnable;
+
+
+/** Pass messages using unix domain sockets.
+ *
+ * @author Costin Manolache
+ */
+public class ChannelUn extends JniHandler implements JkChannel {
+    static final int CH_OPEN=4;
+    static final int CH_CLOSE=5;
+    static final int CH_READ=6;
+    static final int CH_WRITE=7;
+
+    String file;
+    ThreadPool tp = ThreadPool.createThreadPool(true);
+
+    /* ==================== Tcp socket options ==================== */
+
+    public ThreadPool getThreadPool() {
+        return tp;
+    }
+    
+    public void setFile( String f ) {
+        file=f;
+    }
+    
+    public String getFile() {
+        return file;
+    }
+    
+    /* ==================== ==================== */
+    int socketNote=1;
+    int isNote=2;
+    int osNote=3;
+    
+    int localId=0;
+    
+    public void init() throws IOException {
+        if( file==null ) {
+            log.debug("No file, disabling unix channel");
+            return;
+            //throw new IOException( "No file for the unix socket channel");
+        }
+        if( wEnv!=null && wEnv.getLocalId() != 0 ) {
+            localId=wEnv.getLocalId();
+        }
+
+        if( localId != 0 ) {
+            file=file+ localId;
+        }
+        File socketFile=new File( file );
+        if( !socketFile.isAbsolute() ) {
+            String home=wEnv.getJkHome();
+            if( home==null ) {
+                log.debug("No jkhome");
+            } else {
+                File homef=new File( home );
+                socketFile=new File( homef, file );
+                log.debug( "Making the file absolute " +socketFile);
+            }
+        }
+        
+        if( ! socketFile.exists() ) {
+            try {
+                FileOutputStream fos=new FileOutputStream(socketFile);
+                fos.write( 1 );
+                fos.close();
+            } catch( Throwable t ) {
+                log.error("Attempting to create the file failed, disabling channel" 
+                        + socketFile);
+                return;
+            }
+        }
+        // The socket file cannot be removed ...
+        if (!socketFile.delete()) {
+            log.error( "Can't remove socket file " + socketFile);
+            return;
+        }
+        
+
+        super.initNative( "channel.un:" + file );
+
+        if( apr==null || ! apr.isLoaded() ) {
+            log.debug("Apr is not available, disabling unix channel ");
+            apr=null;
+            return;
+        }
+        
+        // Set properties and call init.
+        setNativeAttribute( "file", file );
+        // unixListenSocket=apr.unSocketListen( file, 10 );
+
+        setNativeAttribute( "listen", "10" );
+        // setNativeAttribute( "debug", "10" );
+
+        // Initialize the thread pool and execution chain
+        if( next==null && wEnv!=null ) {
+            if( nextName!=null ) 
+                setNext( wEnv.getHandler( nextName ) );
+            if( next==null )
+                next=wEnv.getHandler( "dispatch" );
+            if( next==null )
+                next=wEnv.getHandler( "request" );
+        }
+
+        super.initJkComponent();
+        JMXRequestNote =wEnv.getNoteId( WorkerEnv.ENDPOINT_NOTE, "requestNote");        
+        // Run a thread that will accept connections.
+        if( this.domain != null ) {
+            try {
+                tpOName=new ObjectName(domain + ":type=ThreadPool,name=" + 
+				       getChannelName());
+
+                Registry.getRegistry(null, null)
+		    .registerComponent(tp, tpOName, null);
+
+		rgOName = new ObjectName
+		    (domain+":type=GlobalRequestProcessor,name=" + getChannelName());
+		Registry.getRegistry(null, null)
+		    .registerComponent(global, rgOName, null);
+            } catch (Exception e) {
+                log.error("Can't register threadpool" );
+            }
+        }
+        tp.start();
+        AprAcceptor acceptAjp=new AprAcceptor(  this );
+        tp.runIt( acceptAjp);
+        log.info("JK: listening on unix socket: " + file );
+        
+    }
+
+    ObjectName tpOName;
+    ObjectName rgOName;
+    RequestGroupInfo global=new RequestGroupInfo();
+    int count = 0;
+    int JMXRequestNote;
+
+    public void start() throws IOException {
+    }
+
+    public void destroy() throws IOException {
+        if( apr==null ) return;
+        try {
+            if( tp != null )
+                tp.shutdown();
+            
+            //apr.unSocketClose( unixListenSocket,3);
+            super.destroyJkComponent();
+
+            if(tpOName != null) {
+		Registry.getRegistry(null, null).unregisterComponent(tpOName);
+	    }
+	    if(rgOName != null) {
+		Registry.getRegistry(null, null).unregisterComponent(rgOName);
+	    }
+        } catch(Exception e) {
+            log.error("Error in destroy",e);
+        }
+    }
+
+    public void registerRequest(Request req, MsgContext ep, int count) {
+	if(this.domain != null) {
+	    try {
+
+		RequestInfo rp=req.getRequestProcessor();
+		rp.setGlobalProcessor(global);
+		ObjectName roname = new ObjectName
+		    (getDomain() + ":type=RequestProcessor,worker="+
+		     getChannelName()+",name=JkRequest" +count);
+		ep.setNote(JMXRequestNote, roname);
+                        
+		Registry.getRegistry(null, null).registerComponent( rp, roname, null);
+	    } catch( Exception ex ) {
+		log.warn("Error registering request");
+	    }
+	}
+    }
+
+
+    /** Open a connection - since we're listening that will block in
+        accept
+    */
+    public int open(MsgContext ep) throws IOException {
+        // Will associate a jk_endpoint with ep and call open() on it.
+        // jk_channel_un will accept a connection and set the socket info
+        // in the endpoint. MsgContext will represent an active connection.
+        return super.nativeDispatch( ep.getMsg(0), ep, CH_OPEN, 1 );
+    }
+    
+    public void close(MsgContext ep) throws IOException {
+        super.nativeDispatch( ep.getMsg(0), ep, CH_CLOSE, 1 );
+    }
+
+    public int send( Msg msg, MsgContext ep)
+        throws IOException
+    {
+        return super.nativeDispatch( msg, ep, CH_WRITE, 0 );
+    }
+
+    public int receive( Msg msg, MsgContext ep )
+        throws IOException
+    {
+        int rc=super.nativeDispatch( msg, ep, CH_READ, 1 );
+
+        if( rc!=0 ) {
+            log.error("receive error:   " + rc, new Throwable());
+            return -1;
+        }
+        
+        msg.processHeader();
+        
+        if (log.isDebugEnabled())
+             log.debug("receive:  total read = " + msg.getLen());
+
+	return msg.getLen();
+    }
+
+    public int flush( Msg msg, MsgContext ep) throws IOException {
+	return OK;
+    }
+
+    public boolean isSameAddress( MsgContext ep ) {
+	return false; // Not supporting shutdown on this channel.
+    }
+
+    boolean running=true;
+    
+    /** Accept incoming connections, dispatch to the thread pool
+     */
+    void acceptConnections() {
+        if( apr==null ) return;
+
+        if( log.isDebugEnabled() )
+            log.debug("Accepting ajp connections on " + file);
+        
+        while( running ) {
+            try {
+                MsgContext ep=this.createMsgContext();
+
+                // blocking - opening a server connection.
+                int status=this.open(ep);
+                if( status != 0 && status != 2 ) {
+                    log.error( "Error acceptin connection on " + file );
+                    break;
+                }
+
+                //    if( log.isDebugEnabled() )
+                //     log.debug("Accepted ajp connections ");
+        
+                AprConnection ajpConn= new AprConnection(this, ep);
+                tp.runIt( ajpConn );
+            } catch( Exception ex ) {
+                ex.printStackTrace();
+            }
+        }
+    }
+
+    /** Process a single ajp connection.
+     */
+    void processConnection(MsgContext ep) {
+        if( log.isDebugEnabled() )
+            log.debug( "New ajp connection ");
+        try {
+            MsgAjp recv=new MsgAjp();
+            while( running ) {
+                int res=this.receive( recv, ep );
+                if( res<0 ) {
+                    // EOS
+                    break;
+                }
+                ep.setType(0);
+                log.debug( "Process msg ");
+                int status=next.invoke( recv, ep );
+            }
+            if( log.isDebugEnabled() )
+                log.debug( "Closing un channel");
+            try{
+                Request req = (Request)ep.getRequest();
+                if( req != null ) {
+                    ObjectName roname = (ObjectName)ep.getNote(JMXRequestNote);
+                    if( roname != null ) {
+                        Registry.getRegistry(null, null).unregisterComponent(roname);
+                    }
+                    req.getRequestProcessor().setGlobalProcessor(null);
+                }
+            } catch( Exception ee) {
+                log.error( "Error, releasing connection",ee);
+            }
+            this.close( ep );
+        } catch( Exception ex ) {
+            ex.printStackTrace();
+        }
+    }
+
+    public int invoke( Msg msg, MsgContext ep ) throws IOException {
+        int type=ep.getType();
+
+        switch( type ) {
+        case JkHandler.HANDLE_RECEIVE_PACKET:
+            return receive( msg, ep );
+        case JkHandler.HANDLE_SEND_PACKET:
+            return send( msg, ep );
+        case JkHandler.HANDLE_FLUSH:
+            return flush( msg, ep );
+        }
+
+        // return next.invoke( msg, ep );
+        return OK;
+    }
+
+    public String getChannelName() {
+        String encodedAddr = "";
+        String address = file;
+        if (address != null) {
+            encodedAddr = "" + address;
+            if (encodedAddr.startsWith("/"))
+                encodedAddr = encodedAddr.substring(1);
+            encodedAddr = URLEncoder.encode(encodedAddr) ;
+        }
+        return ("jk-" + encodedAddr);
+    }
+
+    private static org.apache.commons.logging.Log log=
+        org.apache.commons.logging.LogFactory.getLog( ChannelUn.class );
+}
+
+class AprAcceptor implements ThreadPoolRunnable {
+    ChannelUn wajp;
+    
+    AprAcceptor(ChannelUn wajp ) {
+        this.wajp=wajp;
+    }
+
+    public Object[] getInitData() {
+        return null;
+    }
+
+    public void runIt(Object thD[]) {
+        wajp.acceptConnections();
+    }
+}
+
+class AprConnection implements ThreadPoolRunnable {
+    ChannelUn wajp;
+    MsgContext ep;
+
+    AprConnection(ChannelUn wajp, MsgContext ep) {
+        this.wajp=wajp;
+        this.ep=ep;
+    }
+
+
+    public Object[] getInitData() {
+        return null;
+    }
+    
+    public void runIt(Object perTh[]) {
+        wajp.processConnection(ep);
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/common/HandlerDispatch.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/common/HandlerDispatch.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/common/HandlerDispatch.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,100 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.jk.common;
+
+import java.io.IOException;
+
+import org.apache.jk.core.JkHandler;
+import org.apache.jk.core.Msg;
+import org.apache.jk.core.MsgContext;
+
+
+
+
+/**
+ * Dispatch based on the message type. ( XXX make it more generic,
+ * now it's specific to ajp13 ).
+ * 
+ * @author Costin Manolache
+ */
+public class HandlerDispatch extends JkHandler
+{
+    private static org.apache.commons.logging.Log log=
+        org.apache.commons.logging.LogFactory.getLog( HandlerDispatch.class );
+
+    public HandlerDispatch() 
+    {
+    }
+
+    public void init() {
+    }
+
+    JkHandler handlers[]=new JkHandler[MAX_HANDLERS];
+    String handlerNames[]=new String[MAX_HANDLERS];
+    
+    static final int MAX_HANDLERS=32;    
+    static final int RESERVED=16;  // reserved names, backward compat
+    int currentId=RESERVED;
+
+    public int registerMessageType( int id, String name, JkHandler h,
+                                    String sig[] )
+    {
+        if( log.isDebugEnabled() )
+            log.debug( "Register message " + id + " " + h.getName() +
+                 " " + h.getClass().getName());
+	if( id < 0 ) {
+	    // try to find it by name
+	    for( int i=0; i< handlerNames.length; i++ ) {
+                if( handlerNames[i]==null ) continue;
+                if( name.equals( handlerNames[i] ) )
+                    return i;
+            }
+	    handlers[currentId]=h;
+            handlerNames[currentId]=name;
+	    currentId++;
+	    return currentId;
+	}
+	handlers[id]=h;
+        handlerNames[currentId]=name;
+	return id;
+    }
+
+    
+    // -------------------- Incoming message --------------------
+
+    public int invoke(Msg msg, MsgContext ep ) 
+        throws IOException
+    {
+        int type=msg.peekByte();
+        ep.setType( type );
+        
+        if( type > handlers.length ||
+            handlers[type]==null ) {
+	    if( log.isDebugEnabled() )
+                log.debug( "Invalid handler " + type );
+	    return ERROR;
+	}
+
+        if( log.isDebugEnabled() )
+            log.debug( "Received " + type + " " + handlers[type].getName());
+        
+	JkHandler handler=handlers[type];
+        
+        return handler.invoke( msg, ep );
+    }
+
+ }

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/common/HandlerRequest.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/common/HandlerRequest.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/common/HandlerRequest.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,666 @@
+/*
+ *  Copyright 1999-2005 The Apache Software Foundation
+ *
+ *  Licensed 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.jk.common;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.CharConversionException;
+import java.net.InetAddress;
+import java.util.Properties;
+
+import org.apache.coyote.Request;
+import org.apache.coyote.RequestInfo;
+import org.apache.coyote.Response;
+import org.apache.coyote.Constants;
+import org.apache.jk.core.JkHandler;
+import org.apache.jk.core.Msg;
+import org.apache.jk.core.MsgContext;
+import org.apache.jk.core.WorkerEnv;
+import org.apache.jk.core.JkChannel;
+import org.apache.tomcat.util.buf.ByteChunk;
+import org.apache.tomcat.util.buf.CharChunk;
+import org.apache.tomcat.util.buf.HexUtils;
+import org.apache.tomcat.util.buf.MessageBytes;
+import org.apache.tomcat.util.http.MimeHeaders;
+import org.apache.tomcat.util.net.SSLSupport;
+import org.apache.tomcat.util.threads.ThreadWithAttributes;
+
+/**
+ * Handle messages related with basic request information.
+ *
+ * This object can handle the following incoming messages:
+ * - "FORWARD_REQUEST" input message ( sent when a request is passed from the
+ *   web server )
+ * - "RECEIVE_BODY_CHUNK" input ( sent by container to pass more body, in
+ *   response to GET_BODY_CHUNK )
+ *
+ * It can handle the following outgoing messages:
+ * - SEND_HEADERS. Pass the status code and headers.
+ * - SEND_BODY_CHUNK. Send a chunk of body
+ * - GET_BODY_CHUNK. Request a chunk of body data
+ * - END_RESPONSE. Notify the end of a request processing.
+ *
+ * @author Henri Gomez [hgomez at apache.org]
+ * @author Dan Milstein [danmil at shore.net]
+ * @author Keith Wannamaker [Keith at Wannamaker.org]
+ * @author Costin Manolache
+ */
+public class HandlerRequest extends JkHandler
+{
+    private static org.apache.commons.logging.Log log=
+        org.apache.commons.logging.LogFactory.getLog( HandlerRequest.class );
+
+    /*
+     * Note for Host parsing.
+     */
+    public static final int HOSTBUFFER = 10;
+
+    /**
+     * Thread lock.
+     */
+    private static Object lock = new Object();
+
+    private HandlerDispatch dispatch;
+    private String ajpidDir="conf";
+    
+
+    public HandlerRequest() {
+    }
+
+    public void init() {
+        dispatch=(HandlerDispatch)wEnv.getHandler( "dispatch" );
+        if( dispatch != null ) {
+            // register incoming message handlers
+            dispatch.registerMessageType( AjpConstants.JK_AJP13_FORWARD_REQUEST,
+                                          "JK_AJP13_FORWARD_REQUEST",
+                                          this, null); // 2
+            
+            dispatch.registerMessageType( AjpConstants.JK_AJP13_SHUTDOWN,
+                                          "JK_AJP13_SHUTDOWN",
+                                          this, null); // 7
+            
+            dispatch.registerMessageType( AjpConstants.JK_AJP13_CPING_REQUEST,
+                                          "JK_AJP13_CPING_REQUEST",
+                                           this, null); // 10
+            dispatch.registerMessageType( HANDLE_THREAD_END,
+                                         "HANDLE_THREAD_END",
+                                         this, null);
+            // register outgoing messages handler
+            dispatch.registerMessageType( AjpConstants.JK_AJP13_SEND_BODY_CHUNK, // 3
+                                          "JK_AJP13_SEND_BODY_CHUNK",
+                                          this,null );
+        }
+
+        tmpBufNote=wEnv.getNoteId( WorkerEnv.ENDPOINT_NOTE, "tmpBuf" );
+        secretNote=wEnv.getNoteId( WorkerEnv.ENDPOINT_NOTE, "secret" );
+        
+        if( next==null )
+            next=wEnv.getHandler( "container" );
+        if( log.isDebugEnabled() )
+            log.debug( "Container handler " + next + " " + next.getName() +
+                       " " + next.getClass().getName());
+
+        // should happen on start()
+        generateAjp13Id();
+    }
+
+    public void setSecret( String s ) {
+        requiredSecret=s;
+    }
+
+    public void setUseSecret( boolean b ) {
+        if(b) {
+            requiredSecret=Double.toString(Math.random());
+        }
+    }
+
+    public void setDecodedUri( boolean b ) {
+        decoded=b;
+    }
+
+    public boolean isTomcatAuthentication() {
+        return tomcatAuthentication;
+    }
+
+    public void setShutdownEnabled(boolean se) {
+        shutdownEnabled = se;
+    }
+
+    public boolean getShutdownEnabled() {
+        return shutdownEnabled;
+    }
+
+    public void setTomcatAuthentication(boolean newTomcatAuthentication) {
+        tomcatAuthentication = newTomcatAuthentication;
+    }
+    
+    public void setAjpidDir( String path ) {
+        if( "".equals( path ) ) path=null;
+        ajpidDir=path;
+    }
+
+    /**
+     * Set the flag to tell if we JMX register requests.
+     */
+    public void setRegisterRequests(boolean srr) {
+        registerRequests = srr;
+    }
+
+    /**
+     * Get the flag to tell if we JMX register requests.
+     */
+    public boolean getRegisterRequests() {
+        return registerRequests;
+    }
+
+    /**
+     * Set the flag to delay the initial body read
+     */
+    public void setDelayInitialRead(boolean dir) {
+	delayInitialRead = dir;
+    }
+
+    /**
+     * Get the flag to tell if we delay the initial body read
+     */
+    public boolean getDelayInitialRead() {
+	return delayInitialRead;
+    }
+
+    // -------------------- Ajp13.id --------------------
+
+    private void generateAjp13Id() {
+        int portInt=8009; // tcpCon.getPort();
+        InetAddress address=null; // tcpCon.getAddress();
+
+        if( requiredSecret == null || !shutdownEnabled )
+            return;
+        
+        File f1=new File( wEnv.getJkHome() );
+        File f2=new File( f1, "conf" );
+        
+        if( ! f2.exists() ) {
+            log.error( "No conf dir for ajp13.id " + f2 );
+            return;
+        }
+        
+        File sf=new File( f2, "ajp13.id");
+        
+        if( log.isDebugEnabled())
+            log.debug( "Using stop file: "+sf);
+
+        try {
+            Properties props=new Properties();
+
+            props.put( "port", Integer.toString( portInt ));
+            if( address!=null ) {
+                props.put( "address", address.getHostAddress() );
+            }
+            if( requiredSecret !=null ) {
+                props.put( "secret", requiredSecret );
+            }
+
+            FileOutputStream stopF=new FileOutputStream( sf );
+            props.store( stopF, "Automatically generated, don't edit" );
+        } catch( IOException ex ) {
+            if(log.isDebugEnabled())
+                log.debug( "Can't create stop file: "+sf,ex );
+        }
+    }
+    
+    // -------------------- Incoming message --------------------
+    private String requiredSecret=null;
+    private int secretNote;
+    private int tmpBufNote;
+
+    private boolean decoded=true;
+    private boolean tomcatAuthentication=true;
+    private boolean registerRequests=true;
+    private boolean shutdownEnabled=false;
+    private boolean delayInitialRead = true;
+    
+    public int invoke(Msg msg, MsgContext ep ) 
+        throws IOException    {
+        int type=msg.getByte();
+        ThreadWithAttributes twa = null;
+        if (Thread.currentThread() instanceof ThreadWithAttributes) {
+            twa = (ThreadWithAttributes) Thread.currentThread();
+        }
+        Object control=ep.getControl();
+        MessageBytes tmpMB=(MessageBytes)ep.getNote( tmpBufNote );
+        if( tmpMB==null ) {
+            tmpMB= MessageBytes.newInstance();
+            ep.setNote( tmpBufNote, tmpMB);
+        }
+
+        if( log.isDebugEnabled() )
+            log.debug( "Handling " + type );
+        
+        switch( type ) {
+        case AjpConstants.JK_AJP13_FORWARD_REQUEST:
+            try {
+                if (twa != null) {
+                    twa.setCurrentStage(control, "JkDecode");
+                }
+                decodeRequest( msg, ep, tmpMB );
+                if (twa != null) {
+                    twa.setCurrentStage(control, "JkService");
+                    twa.setParam(control,
+                                 ((Request)ep.getRequest()).unparsedURI());
+                }
+            } catch( Exception ex ) {
+                log.error( "Error decoding request ", ex );
+                msg.dump( "Incomming message");
+                return ERROR;
+            }
+
+            if( requiredSecret != null ) {
+                String epSecret=(String)ep.getNote( secretNote );
+                if( epSecret==null || ! requiredSecret.equals( epSecret ) )
+                    return ERROR;
+            }
+            /* XXX it should be computed from request, by workerEnv */
+            if(log.isDebugEnabled() )
+                log.debug("Calling next " + next.getName() + " " +
+                  next.getClass().getName());
+
+            int err= next.invoke( msg, ep );
+            if (twa != null) {
+                twa.setCurrentStage(control, "JkDone");
+            }
+
+            if( log.isDebugEnabled() )
+                log.debug( "Invoke returned " + err );
+            return err;
+        case AjpConstants.JK_AJP13_SHUTDOWN:
+            String epSecret=null;
+            if( msg.getLen() > 3 ) {
+                // we have a secret
+                msg.getBytes( tmpMB );
+                epSecret=tmpMB.toString();
+            }
+            
+            if( requiredSecret != null &&
+                requiredSecret.equals( epSecret ) ) {
+                if( log.isDebugEnabled() )
+                    log.debug("Received wrong secret, no shutdown ");
+                return ERROR;
+            }
+
+            // XXX add isSameAddress check
+            JkChannel ch=ep.getSource();
+            if( !ch.isSameAddress(ep) ) {
+                log.error("Shutdown request not from 'same address' ");
+                return ERROR;
+            }
+
+            if( !shutdownEnabled ) {
+                log.warn("Ignoring shutdown request: shutdown not enabled");
+                return ERROR;
+            }
+            // forward to the default handler - it'll do the shutdown
+            checkRequest(ep);
+            next.invoke( msg, ep );
+
+            if(log.isInfoEnabled())
+                log.info("Exiting");
+            System.exit(0);
+            
+            return OK;
+
+            // We got a PING REQUEST, quickly respond with a PONG
+        case AjpConstants.JK_AJP13_CPING_REQUEST:
+            msg.reset();
+            msg.appendByte(AjpConstants.JK_AJP13_CPONG_REPLY);
+            ep.getSource().send( msg, ep );
+            ep.getSource().flush( msg, ep ); // Server needs to get it
+            return OK;
+
+        case HANDLE_THREAD_END:
+            return OK;
+
+        default:
+            if(log.isInfoEnabled())
+                log.info("Unknown message " + type);
+        }
+
+        return OK;
+    }
+
+    static int count = 0;
+
+    private Request checkRequest(MsgContext ep) {
+        Request req=ep.getRequest();
+        if( req==null ) {
+            req=new Request();
+            Response res=new Response();
+            req.setResponse(res);
+            ep.setRequest( req );
+            if( registerRequests ) {
+                synchronized(lock) {
+                    ep.getSource().registerRequest(req, ep, count++);
+                }
+            }
+        }
+        return req;
+    }
+
+    private int decodeRequest( Msg msg, MsgContext ep, MessageBytes tmpMB )
+        throws IOException    {
+        // FORWARD_REQUEST handler
+        Request req = checkRequest(ep);
+
+        RequestInfo rp = req.getRequestProcessor();
+        rp.setStage(Constants.STAGE_PARSE);
+        MessageBytes tmpMB2 = (MessageBytes)req.getNote(WorkerEnv.SSL_CERT_NOTE);
+        if(tmpMB2 != null) {
+            tmpMB2.recycle();
+        }
+        req.setStartTime(System.currentTimeMillis());
+        
+        // Translate the HTTP method code to a String.
+        byte methodCode = msg.getByte();
+        if (methodCode != AjpConstants.SC_M_JK_STORED) {
+            String mName=AjpConstants.methodTransArray[(int)methodCode - 1];
+            req.method().setString(mName);
+        }
+
+        msg.getBytes(req.protocol()); 
+        msg.getBytes(req.requestURI());
+
+        msg.getBytes(req.remoteAddr());
+        msg.getBytes(req.remoteHost());
+        msg.getBytes(req.localName());
+        req.setLocalPort(msg.getInt());
+
+        boolean isSSL = msg.getByte() != 0;
+        if( isSSL ) {
+            // XXX req.setSecure( true );
+            req.scheme().setString("https");
+        }
+
+        decodeHeaders( ep, msg, req, tmpMB );
+
+        decodeAttributes( ep, msg, req, tmpMB );
+
+        rp.setStage(Constants.STAGE_PREPARE);
+        MessageBytes valueMB = req.getMimeHeaders().getValue("host");
+        parseHost(valueMB, req);
+        // set cookies on request now that we have all headers
+        req.getCookies().setHeaders(req.getMimeHeaders());
+
+        // Check to see if there should be a body packet coming along
+        // immediately after
+        int cl=req.getContentLength();
+        if(cl > 0) {
+            JkInputStream jkIS = ep.getInputStream();
+            jkIS.setIsReadRequired(true);
+            if(!delayInitialRead) {
+                jkIS.receive();
+            }
+        }
+    
+        if (log.isTraceEnabled()) {
+            log.trace(req.toString());
+         }
+
+        return OK;
+    }
+        
+    private int decodeAttributes( MsgContext ep, Msg msg, Request req,
+                                  MessageBytes tmpMB) {
+        boolean moreAttr=true;
+
+        while( moreAttr ) {
+            byte attributeCode=msg.getByte();
+            if( attributeCode == AjpConstants.SC_A_ARE_DONE )
+                return 200;
+
+            /* Special case ( XXX in future API make it separate type !)
+             */
+            if( attributeCode == AjpConstants.SC_A_SSL_KEY_SIZE ) {
+                // Bug 1326: it's an Integer.
+                req.setAttribute(SSLSupport.KEY_SIZE_KEY,
+                                 new Integer( msg.getInt()));
+               //Integer.toString(msg.getInt()));
+            }
+
+            if( attributeCode == AjpConstants.SC_A_REQ_ATTRIBUTE ) {
+                // 2 strings ???...
+                msg.getBytes( tmpMB );
+                String n=tmpMB.toString();
+                msg.getBytes( tmpMB );
+                String v=tmpMB.toString();
+                req.setAttribute(n, v );
+                if(log.isTraceEnabled())
+                    log.trace("jk Attribute set " + n + "=" + v);
+            }
+
+
+            // 1 string attributes
+            switch(attributeCode) {
+            case AjpConstants.SC_A_CONTEXT      :
+                msg.getBytes( tmpMB );
+                // nothing
+                break;
+                
+            case AjpConstants.SC_A_SERVLET_PATH :
+                msg.getBytes( tmpMB );
+                // nothing 
+                break;
+                
+            case AjpConstants.SC_A_REMOTE_USER  :
+                if( tomcatAuthentication ) {
+                    // ignore server
+                    msg.getBytes( tmpMB );
+                } else {
+                    msg.getBytes(req.getRemoteUser());
+                }
+                break;
+                
+            case AjpConstants.SC_A_AUTH_TYPE    :
+                if( tomcatAuthentication ) {
+                    // ignore server
+                    msg.getBytes( tmpMB );
+                } else {
+                    msg.getBytes(req.getAuthType());
+                }
+                break;
+                
+            case AjpConstants.SC_A_QUERY_STRING :
+                msg.getBytes(req.queryString());
+                break;
+                
+            case AjpConstants.SC_A_JVM_ROUTE    :
+                msg.getBytes(req.instanceId());
+                break;
+                
+            case AjpConstants.SC_A_SSL_CERT     :
+                req.scheme().setString( "https" );
+                // Transform the string into certificate.
+                MessageBytes tmpMB2 = (MessageBytes)req.getNote(WorkerEnv.SSL_CERT_NOTE);
+                if(tmpMB2 == null) {
+                    tmpMB2 = MessageBytes.newInstance();
+                    req.setNote(WorkerEnv.SSL_CERT_NOTE, tmpMB2);
+                }
+                // SSL certificate extraction is costy, moved to JkCoyoteHandler
+                msg.getBytes(tmpMB2);
+                break;
+                
+            case AjpConstants.SC_A_SSL_CIPHER   :
+                req.scheme().setString( "https" );
+                msg.getBytes(tmpMB);
+                req.setAttribute(SSLSupport.CIPHER_SUITE_KEY,
+                                 tmpMB.toString());
+                break;
+                
+            case AjpConstants.SC_A_SSL_SESSION  :
+                req.scheme().setString( "https" );
+                msg.getBytes(tmpMB);
+                req.setAttribute(SSLSupport.SESSION_ID_KEY, 
+                                  tmpMB.toString());
+                break;
+                
+            case AjpConstants.SC_A_SECRET  :
+                msg.getBytes(tmpMB);
+                String secret=tmpMB.toString();
+                if(log.isTraceEnabled())
+                    log.trace("Secret: " + secret );
+                // endpoint note
+                ep.setNote( secretNote, secret );
+                break;
+                
+            case AjpConstants.SC_A_STORED_METHOD:
+                msg.getBytes(req.method()); 
+                break;
+                
+            default:
+                break; // ignore, we don't know about it - backward compat
+            }
+        }
+        return 200;
+    }
+    
+    private void decodeHeaders( MsgContext ep, Msg msg, Request req,
+                                MessageBytes tmpMB ) {
+        // Decode headers
+        MimeHeaders headers = req.getMimeHeaders();
+
+        int hCount = msg.getInt();
+        for(int i = 0 ; i < hCount ; i++) {
+            String hName = null;
+
+            // Header names are encoded as either an integer code starting
+            // with 0xA0, or as a normal string (in which case the first
+            // two bytes are the length).
+            int isc = msg.peekInt();
+            int hId = isc & 0xFF;
+
+            MessageBytes vMB=null;
+            isc &= 0xFF00;
+            if(0xA000 == isc) {
+                msg.getInt(); // To advance the read position
+                hName = AjpConstants.headerTransArray[hId - 1];
+                vMB=headers.addValue( hName );
+            } else {
+                // reset hId -- if the header currently being read
+                // happens to be 7 or 8 bytes long, the code below
+                // will think it's the content-type header or the
+                // content-length header - SC_REQ_CONTENT_TYPE=7,
+                // SC_REQ_CONTENT_LENGTH=8 - leading to unexpected
+                // behaviour.  see bug 5861 for more information.
+                hId = -1;
+                msg.getBytes( tmpMB );
+                ByteChunk bc=tmpMB.getByteChunk();
+                vMB=headers.addValue( bc.getBuffer(),
+                                      bc.getStart(), bc.getLength() );
+            }
+
+            msg.getBytes(vMB);
+
+            if (hId == AjpConstants.SC_REQ_CONTENT_LENGTH ||
+                (hId == -1 && tmpMB.equalsIgnoreCase("Content-Length"))) {
+                // just read the content-length header, so set it
+                req.setContentLength( vMB.getInt() );
+            } else if (hId == AjpConstants.SC_REQ_CONTENT_TYPE ||
+                (hId == -1 && tmpMB.equalsIgnoreCase("Content-Type"))) {
+                // just read the content-type header, so set it
+                ByteChunk bchunk = vMB.getByteChunk();
+                req.contentType().setBytes(bchunk.getBytes(),
+                                           bchunk.getOffset(),
+                                           bchunk.getLength());
+            }
+        }
+    }
+
+    /**
+     * Parse host.
+     */
+    private void parseHost(MessageBytes valueMB, Request request) 
+        throws IOException {
+
+        if (valueMB == null || valueMB.isNull()) {
+            // HTTP/1.0
+            // Default is what the socket tells us. Overriden if a host is 
+            // found/parsed
+            request.setServerPort(request.getLocalPort());
+            request.serverName().duplicate(request.localName());
+            return;
+        }
+
+        ByteChunk valueBC = valueMB.getByteChunk();
+        byte[] valueB = valueBC.getBytes();
+        int valueL = valueBC.getLength();
+        int valueS = valueBC.getStart();
+        int colonPos = -1;
+        CharChunk hostNameC = (CharChunk)request.getNote(HOSTBUFFER);
+        if(hostNameC == null) {
+            hostNameC = new CharChunk(valueL);
+            request.setNote(HOSTBUFFER, hostNameC);
+        }
+        hostNameC.recycle();
+
+        boolean ipv6 = (valueB[valueS] == '[');
+        boolean bracketClosed = false;
+        for (int i = 0; i < valueL; i++) {
+            char b = (char) valueB[i + valueS];
+            hostNameC.append(b);
+            if (b == ']') {
+                bracketClosed = true;
+            } else if (b == ':') {
+                if (!ipv6 || bracketClosed) {
+                    colonPos = i;
+                    break;
+                }
+            }
+        }
+
+        if (colonPos < 0) {
+            if (request.scheme().equalsIgnoreCase("https")) {
+                // 80 - Default HTTTP port
+                request.setServerPort(443);
+            } else {
+                // 443 - Default HTTPS port
+                request.setServerPort(80);
+            }
+            request.serverName().setChars(hostNameC.getChars(), 
+                                          hostNameC.getStart(), 
+                                          hostNameC.getLength());
+        } else {
+
+            request.serverName().setChars(hostNameC.getChars(), 
+                                          hostNameC.getStart(), colonPos);
+
+            int port = 0;
+            int mult = 1;
+            for (int i = valueL - 1; i > colonPos; i--) {
+                int charValue = HexUtils.DEC[(int) valueB[i + valueS]];
+                if (charValue == -1) {
+                    // Invalid character
+                    throw new CharConversionException("Invalid char in port: " + valueB[i + valueS]); 
+                }
+                port = port + (charValue * mult);
+                mult = 10 * mult;
+            }
+            request.setServerPort(port);
+
+        }
+
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/common/JkInputStream.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/common/JkInputStream.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/common/JkInputStream.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,318 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.jk.common;
+
+import java.io.IOException;
+
+import org.apache.coyote.OutputBuffer;
+import org.apache.coyote.InputBuffer;
+import org.apache.coyote.Request;
+import org.apache.coyote.Response;
+
+import org.apache.jk.core.Msg;
+import org.apache.jk.core.MsgContext;
+
+import org.apache.tomcat.util.buf.ByteChunk;
+import org.apache.tomcat.util.buf.MessageBytes;
+import org.apache.tomcat.util.buf.C2BConverter;
+import org.apache.tomcat.util.http.HttpMessages;
+import org.apache.tomcat.util.http.MimeHeaders;
+
+/** Generic input stream impl on top of ajp
+ */
+public class JkInputStream implements InputBuffer, OutputBuffer {
+    private static org.apache.commons.logging.Log log=
+        org.apache.commons.logging.LogFactory.getLog( JkInputStream.class );
+
+    private Msg bodyMsg = new MsgAjp();
+    private Msg outputMsg = new MsgAjp();
+    private MsgContext mc;
+
+    
+    // Holds incoming chunks of request body data
+    private MessageBytes bodyBuff = MessageBytes.newInstance();
+    private MessageBytes tempMB = MessageBytes.newInstance();
+    private boolean end_of_stream=false; 
+    private boolean isEmpty = true;
+    private boolean isFirst = true;
+    private boolean isReplay = false;
+    private boolean isReadRequired = false;
+
+    static {
+        // Make certain HttpMessages is loaded for SecurityManager
+        try {
+            Class.forName("org.apache.tomcat.util.http.HttpMessages");
+        } catch(Exception ex) {
+            // ignore
+        }
+    }
+
+    public JkInputStream(MsgContext context) {
+        mc = context;
+    }
+
+    // -------------------- Jk specific methods --------------------
+
+
+    /**
+     * Set the flag saying that the server is sending a body
+     */
+    public void setIsReadRequired(boolean irr) {
+        isReadRequired = irr;
+    }
+
+    /**
+     * Return the flag saying that the server is sending a body
+     */
+    public boolean isReadRequired() {
+        return isReadRequired;
+    }
+
+    
+    /** Must be called before or after each request
+     */
+    public void recycle() {
+        if(isReadRequired && isFirst) {
+            // The Servlet never read the request body, so we need to junk it
+            try {
+              receive();
+            } catch(IOException iex) {
+              log.debug("Error consuming request body",iex);
+            }
+        }
+
+        end_of_stream = false;
+        isEmpty = true;
+        isFirst = true;
+        isReplay = false;
+        isReadRequired = false;
+        bodyBuff.recycle();
+        tempMB.recycle();
+    }
+
+
+    public void endMessage() throws IOException {
+        outputMsg.reset();
+        outputMsg.appendByte(AjpConstants.JK_AJP13_END_RESPONSE);
+        outputMsg.appendByte(1);
+        mc.getSource().send(outputMsg, mc);
+        mc.getSource().flush(outputMsg, mc);
+    }
+
+
+    // -------------------- OutputBuffer implementation --------------------
+
+        
+    public int doWrite(ByteChunk chunk, Response res) 
+        throws IOException    {
+        if (!res.isCommitted()) {
+            // Send the connector a request for commit. The connector should
+            // then validate the headers, send them (using sendHeader) and 
+            // set the filters accordingly.
+            res.sendHeaders();
+        }
+
+        int len=chunk.getLength();
+        byte buf[]=outputMsg.getBuffer();
+        // 4 - hardcoded, byte[] marshalling overhead 
+        int chunkSize=buf.length - outputMsg.getHeaderLength() - 4;
+        int off=0;
+        while( len > 0 ) {
+            int thisTime=len;
+            if( thisTime > chunkSize ) {
+                thisTime=chunkSize;
+            }
+            len-=thisTime;
+            
+            outputMsg.reset();
+            outputMsg.appendByte( AjpConstants.JK_AJP13_SEND_BODY_CHUNK);
+            if( log.isTraceEnabled() ) 
+                log.trace("doWrite " + off + " " + thisTime + " " + len );
+            outputMsg.appendBytes( chunk.getBytes(), chunk.getOffset() + off, thisTime );
+            off+=thisTime;
+            mc.getSource().send( outputMsg, mc );
+        }
+        return 0;
+    }
+
+    public int doRead(ByteChunk responseChunk, Request req) 
+        throws IOException {
+
+        if( log.isDebugEnabled())
+            log.debug( "doRead "  + end_of_stream+
+                       " " + responseChunk.getOffset()+ " " + responseChunk.getLength());
+        if( end_of_stream ) {
+            return -1;
+        }
+
+        if( isFirst && isReadRequired ) {
+            // Handle special first-body-chunk, but only if httpd expects it.
+            if( !receive() ) {
+                return 0;
+            }
+        } else if(isEmpty) {
+            if ( !refillReadBuffer() ){
+                return -1;
+            }
+        }
+        ByteChunk bc = bodyBuff.getByteChunk();
+        responseChunk.setBytes( bc.getBuffer(), bc.getStart(), bc.getLength() );
+        isEmpty = true;
+        return responseChunk.getLength();
+    }
+    
+    /** Receive a chunk of data. Called to implement the
+     *  'special' packet in ajp13 and to receive the data
+     *  after we send a GET_BODY packet
+     */
+    public boolean receive() throws IOException {
+        isFirst = false;
+        bodyMsg.reset();
+        int err = mc.getSource().receive(bodyMsg, mc);
+        if( log.isDebugEnabled() )
+            log.info( "Receiving: getting request body chunk " + err + " " + bodyMsg.getLen() );
+        
+        if(err < 0) {
+            throw new IOException();
+        }
+
+        // No data received.
+        if( bodyMsg.getLen() == 0 ) { // just the header
+            // Don't mark 'end of stream' for the first chunk.
+            // end_of_stream = true;
+            return false;
+        }
+        int blen = bodyMsg.peekInt();
+
+        if( blen == 0 ) {
+            return false;
+        }
+
+        if( log.isTraceEnabled() ) {
+            bodyMsg.dump("Body buffer");
+        }
+        
+        bodyMsg.getBytes(bodyBuff);
+        if( log.isTraceEnabled() )
+            log.trace( "Data:\n" + bodyBuff);
+        isEmpty = false;
+        return true;
+    }
+    
+    /**
+     * Get more request body data from the web server and store it in the 
+     * internal buffer.
+     *
+     * @return true if there is more data, false if not.    
+     */
+    private boolean refillReadBuffer() throws IOException 
+    {
+        // If the server returns an empty packet, assume that that end of
+        // the stream has been reached (yuck -- fix protocol??).
+        if(isReplay) {
+            end_of_stream = true; // we've read everything there is
+        }
+        if (end_of_stream) {
+            if( log.isDebugEnabled() ) 
+                log.debug("refillReadBuffer: end of stream " );
+            return false;
+        }
+
+        // Why not use outBuf??
+        bodyMsg.reset();
+        bodyMsg.appendByte(AjpConstants.JK_AJP13_GET_BODY_CHUNK);
+        bodyMsg.appendInt(AjpConstants.MAX_READ_SIZE);
+        
+        if( log.isDebugEnabled() )
+            log.debug("refillReadBuffer " + Thread.currentThread());
+
+        mc.getSource().send(bodyMsg, mc);
+        mc.getSource().flush(bodyMsg, mc); // Server needs to get it
+
+        // In JNI mode, response will be in bodyMsg. In TCP mode, response need to be
+        // read
+
+        boolean moreData=receive();
+        if( !moreData ) {
+            end_of_stream=true;
+        }
+        return moreData;
+    }
+
+    public void appendHead(Response res) throws IOException {
+        if( log.isDebugEnabled() )
+            log.debug("COMMIT sending headers " + res + " " + res.getMimeHeaders() );
+        
+        C2BConverter c2b=mc.getConverter();
+        
+        outputMsg.reset();
+        outputMsg.appendByte(AjpConstants.JK_AJP13_SEND_HEADERS);
+        outputMsg.appendInt( res.getStatus() );
+        
+        String message=res.getMessage();
+        if( message==null ){
+            message= HttpMessages.getMessage(res.getStatus());
+        } else {
+            message = message.replace('\n', ' ').replace('\r', ' ');
+        }
+        tempMB.setString( message );
+        c2b.convert( tempMB );
+        outputMsg.appendBytes(tempMB);
+
+        // XXX add headers
+        
+        MimeHeaders headers=res.getMimeHeaders();
+        String contentType = res.getContentType();
+        if( contentType != null ) {
+            headers.setValue("Content-Type").setString(contentType);
+        }
+        String contentLanguage = res.getContentLanguage();
+        if( contentLanguage != null ) {
+            headers.setValue("Content-Language").setString(contentLanguage);
+        }
+        int contentLength = res.getContentLength();
+        if( contentLength >= 0 ) {
+            headers.setValue("Content-Length").setInt(contentLength);
+        }
+        int numHeaders = headers.size();
+        outputMsg.appendInt(numHeaders);
+        for( int i=0; i<numHeaders; i++ ) {
+            MessageBytes hN=headers.getName(i);
+            // no header to sc conversion - there's little benefit
+            // on this direction
+            c2b.convert ( hN );
+            outputMsg.appendBytes( hN );
+                        
+            MessageBytes hV=headers.getValue(i);
+            c2b.convert( hV );
+            outputMsg.appendBytes( hV );
+        }
+        mc.getSource().send( outputMsg, mc );
+    }
+
+    /**
+     * Set the replay buffer for Form auth
+     */
+    public void setReplay(ByteChunk replay) {
+        isFirst = false;
+        isEmpty = false;
+        isReplay = true;
+        bodyBuff.setBytes(replay.getBytes(), replay.getStart(), replay.getLength());
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/common/JkMX.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/common/JkMX.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/common/JkMX.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,394 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.jk.common;
+
+
+import org.apache.jk.core.JkHandler;
+
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+import javax.management.Attribute;
+import javax.management.MBeanServerFactory;
+import java.io.IOException;
+
+/**
+ * Load the HTTP or RMI adapters for MX4J and JMXRI.
+ *
+ * Add "mx.enabled=true" in jk2.properties to enable it.
+ * You could also select http and/or jrmp protocol, 
+ * with mx.httpPort, mx.httpHost, mxjrmpPort and mx.jrmpPort.
+ * <p />
+ * If you run into an error message like
+ * "SystemId Unknown; Line #12; Column #81; Cannot add attribute name after
+ * child nodes or before an element is produced.  Attribute will be ignored."
+ * after setting mx.enabled to true, you probably need a newer version
+ * of Xalan.  See the RELEASE-NOTES document section on XML Parsers for
+ * more information.
+ *
+ */
+public class JkMX extends JkHandler
+{
+    MBeanServer mserver;
+    private boolean enabled=false;
+    private boolean log4jEnabled=true;
+    private int httpport=-1;
+    private String httphost="localhost";
+    private String authmode="none";
+    private String authuser=null;
+    private String authpassword=null;
+    private int jrmpport=-1;
+    private String jrmphost="localhost";
+    private boolean useXSLTProcessor = true;
+
+    public JkMX() {
+    }
+
+    /* -------------------- Public methods -------------------- */
+
+    /** Enable the MX4J adapters (new way)
+     */
+    public void setEnabled(boolean b) {
+        enabled=b;
+    }
+        
+    public boolean getEnabled() {
+        return enabled;
+    }
+        
+    /** Enable the Log4j MBean)
+     */
+    public void setLog4jEnabled(boolean b) {
+        log4jEnabled=b;
+    }
+        
+    public boolean getLog4jEnabled() {
+        return log4jEnabled;
+    }
+
+    /** Enable the MX4J adapters (old way, compatible)
+     */
+    public void setPort(int i) {
+        enabled=(i != -1);
+    }
+        
+    public int getPort() {
+        return ((httpport != -1) ? httpport : jrmpport);
+    }
+
+    /** Enable the MX4J HTTP internal adapter
+     */ 
+    public void setHttpPort( int i ) {
+        httpport=i;
+    }
+
+    public int getHttpPort() {
+        return httpport;
+    }
+
+    public void setHttpHost(String host ) {
+        this.httphost=host;
+    }
+
+    public String getHttpHost() {
+        return httphost;
+    }
+
+    public void setAuthMode(String mode) {
+        authmode=mode;
+    }
+
+    public String getAuthMode() {
+        return authmode;
+    }
+
+    public void setAuthUser(String user) {
+        authuser=user;
+    }
+
+    public String getAuthUser() {
+        return authuser;
+    }
+
+    public void setAuthPassword(String password) {
+        authpassword=password;
+    }
+
+    public String getAuthPassword() {
+        return authpassword;
+    }
+
+    /** Enable the MX4J JRMP internal adapter
+     */
+    public void setJrmpPort( int i ) {
+        jrmpport=i;
+    }
+
+    public int getJrmpPort() {
+        return jrmpport;
+    }
+
+    public void setJrmpHost(String host ) {
+        this.jrmphost=host;
+    }
+
+    public String getJrmpHost() {
+        return jrmphost;
+    }
+
+    public boolean getUseXSLTProcessor() {
+        return useXSLTProcessor;
+    }
+
+    public void setUseXSLTProcessor(boolean uxsltp) {
+        useXSLTProcessor = uxsltp;
+    }        
+
+    /* ==================== Start/stop ==================== */
+    ObjectName httpServerName=null;
+    ObjectName jrmpServerName=null;
+
+    /** Initialize the worker. After this call the worker will be
+     *  ready to accept new requests.
+     */
+    public void loadAdapter() throws IOException {
+        boolean httpAdapterLoaded = false;
+        boolean jrmpAdapterLoaded = false;
+        
+        if ((httpport != -1) && classExists("mx4j.adaptor.http.HttpAdaptor")) {
+            try {
+                httpServerName = registerObject("mx4j.adaptor.http.HttpAdaptor",
+                                                "Http:name=HttpAdaptor");
+
+                        
+                if( httphost!=null )
+                    mserver.setAttribute(httpServerName, new Attribute("Host", httphost));
+                mserver.setAttribute(httpServerName, new Attribute("Port", new Integer(httpport)));
+
+                if( "none".equals(authmode) || "basic".equals(authmode) || "digest".equals(authmode) )
+                    mserver.setAttribute(httpServerName, new Attribute("AuthenticationMethod", authmode));
+
+                if( authuser!=null && authpassword!=null )
+                    mserver.invoke(httpServerName, "addAuthorization",
+                        new Object[] {
+                            authuser,
+                            authpassword},
+                        new String[] { "java.lang.String", "java.lang.String" });
+
+                if(useXSLTProcessor) {
+                    ObjectName processorName = registerObject("mx4j.adaptor.http.XSLTProcessor",
+                                                          "Http:name=XSLTProcessor");
+                    mserver.setAttribute(httpServerName, new Attribute("ProcessorName", processorName));
+                }
+
+                // starts the server
+                mserver.invoke(httpServerName, "start", null, null);
+
+                log.info( "Started MX4J console on host " + httphost + " at port " + httpport);
+                
+                httpAdapterLoaded = true;
+
+            } catch( Throwable t ) {
+                httpServerName=null;
+                log.error( "Can't load the MX4J http adapter ", t );
+            }
+        }
+
+        if ((httpport != -1) && (!httpAdapterLoaded) && classExists("mx4j.tools.adaptor.http.HttpAdaptor")) {
+            try {
+                httpServerName = registerObject("mx4j.tools.adaptor.http.HttpAdaptor",
+                                                "Http:name=HttpAdaptor");
+
+                        
+                if( httphost!=null )
+                    mserver.setAttribute(httpServerName, new Attribute("Host", httphost));
+                mserver.setAttribute(httpServerName, new Attribute("Port", new Integer(httpport)));
+
+                if( "none".equals(authmode) || "basic".equals(authmode) || "digest".equals(authmode) )
+                    mserver.setAttribute(httpServerName, new Attribute("AuthenticationMethod", authmode));
+
+                if( authuser!=null && authpassword!=null )
+                    mserver.invoke(httpServerName, "addAuthorization",
+                        new Object[] {
+                            authuser,
+                            authpassword},
+                        new String[] { "java.lang.String", "java.lang.String" });
+
+               if(useXSLTProcessor) {
+                    ObjectName processorName = registerObject("mx4j.tools.adaptor.http.XSLTProcessor",
+                                                          "Http:name=XSLTProcessor");
+                    mserver.setAttribute(httpServerName, new Attribute("ProcessorName", processorName));
+		}
+                // starts the server
+                mserver.invoke(httpServerName, "start", null, null);
+                if(log.isInfoEnabled())
+                    log.info( "Started MX4J console on host " + httphost + " at port " + httpport);
+                
+                httpAdapterLoaded = true;
+
+            } catch( Throwable t ) {
+                httpServerName=null;
+                log.error( "Can't load the MX4J http adapter ", t );
+            }
+        }
+
+        if ((jrmpport != -1) && classExists("mx4j.tools.naming.NamingService")) {
+            try {
+                jrmpServerName = registerObject("mx4j.tools.naming.NamingService",
+                                                "Naming:name=rmiregistry");
+				mserver.setAttribute(jrmpServerName, new Attribute("Port", 
+				                                     new Integer(jrmpport)));
+                mserver.invoke(jrmpServerName, "start", null, null);
+                if(log.isInfoEnabled())
+                    log.info( "Creating " + jrmpServerName );
+
+                // Create the JRMP adaptor
+                ObjectName adaptor = registerObject("mx4j.adaptor.rmi.jrmp.JRMPAdaptor",
+                                                    "Adaptor:protocol=jrmp");
+
+
+                mserver.setAttribute(adaptor, new Attribute("JNDIName", "jrmp"));
+
+                mserver.invoke( adaptor, "putNamingProperty",
+                        new Object[] {
+                            javax.naming.Context.INITIAL_CONTEXT_FACTORY,
+                            "com.sun.jndi.rmi.registry.RegistryContextFactory"},
+                        new String[] { "java.lang.Object", "java.lang.Object" });
+
+                String jrpmurl = "rmi://" + jrmphost + ":" + Integer.toString(jrmpport) ;
+                                        
+                mserver.invoke( adaptor, "putNamingProperty",
+                        new Object[] {
+                            javax.naming.Context.PROVIDER_URL,
+                            jrpmurl},
+                        new String[] { "java.lang.Object", "java.lang.Object" });
+
+                // Registers the JRMP adaptor in JNDI and starts it
+                mserver.invoke(adaptor, "start", null, null);
+                if(log.isInfoEnabled())
+                    log.info( "Creating " + adaptor + " on host " + jrmphost + " at port " + jrmpport);
+
+                jrmpAdapterLoaded = true;
+
+            } catch( Exception ex ) {
+                jrmpServerName = null;
+                log.error( "MX4j RMI adapter not loaded: " + ex.toString());
+            }
+        }
+
+        if ((httpport != -1) && (! httpAdapterLoaded) && classExists("com.sun.jdmk.comm.HtmlAdaptorServer")) {
+            try {
+                httpServerName=registerObject("com.sun.jdmk.comm.HtmlAdaptorServer",
+                                              "Adaptor:name=html,port=" + httpport);
+                if(log.isInfoEnabled())
+                    log.info("Registering the JMX_RI html adapter " + httpServerName + " at port " + httpport);
+
+                mserver.setAttribute(httpServerName,
+                                     new Attribute("Port", new Integer(httpport)));
+
+                mserver.invoke(httpServerName, "start", null, null);
+
+                httpAdapterLoaded = true;
+            } catch( Throwable t ) {
+                httpServerName = null;
+                log.error( "Can't load the JMX_RI http adapter " + t.toString()  );
+            }
+        }
+
+        if ((!httpAdapterLoaded) && (!jrmpAdapterLoaded))
+            log.warn( "No adaptors were loaded but mx.enabled was defined.");
+
+    }
+
+    public void destroy() {
+        try {
+            if(log.isInfoEnabled())
+                log.info("Stoping JMX ");
+
+            if( httpServerName!=null ) {
+                mserver.invoke(httpServerName, "stop", null, null);
+            }
+            if( jrmpServerName!=null ) {
+                mserver.invoke(jrmpServerName, "stop", null, null);
+            }
+        } catch( Throwable t ) {
+            log.error( "Destroy error" + t );
+        }
+    }
+
+    public void init() throws IOException {
+        try {
+            mserver = getMBeanServer();
+
+            if( enabled ) {
+                loadAdapter();
+            }
+            if( log4jEnabled) {
+                try {
+                    registerObject("org.apache.log4j.jmx.HierarchyDynamicMBean" ,
+                                   "log4j:hierarchy=default");
+                    if(log.isInfoEnabled())
+                         log.info("Registering the JMX hierarchy for Log4J ");
+                } catch( Throwable t ) {
+                    if(log.isInfoEnabled())
+                        log.info("Can't enable log4j mx: ",t);
+                }
+            }
+        } catch( Throwable t ) {
+            log.error( "Init error", t );
+        }
+    }
+
+    public void addHandlerCallback( JkHandler w ) {
+    }
+
+    MBeanServer getMBeanServer() {
+        MBeanServer server;
+        if( MBeanServerFactory.findMBeanServer(null).size() > 0 ) {
+            server=(MBeanServer)MBeanServerFactory.findMBeanServer(null).get(0);
+        } else {
+            server=MBeanServerFactory.createMBeanServer();
+        }
+        return (server);
+    }
+
+
+    private static boolean classExists(String className) {
+        try {
+            Thread.currentThread().getContextClassLoader().loadClass(className);
+            return true;
+        } catch(Throwable e) {
+            if (log.isInfoEnabled())
+                log.info( "className [" + className + "] does not exist");
+            return false;
+        }
+    }
+
+    private ObjectName registerObject(String className, String oName) 
+        throws Exception {
+        Class c = Class.forName(className);
+        Object o = c.newInstance();
+        ObjectName objN = new ObjectName(oName);
+        mserver.registerMBean(o, objN);
+        return objN;
+    }
+
+    private static org.apache.commons.logging.Log log=
+        org.apache.commons.logging.LogFactory.getLog( JkMX.class );
+
+
+}
+

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/common/JniHandler.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/common/JniHandler.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/common/JniHandler.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,317 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.jk.common;
+
+import java.io.IOException;
+
+import javax.management.ObjectName;
+
+import org.apache.commons.modeler.Registry;
+import org.apache.jk.apr.AprImpl;
+import org.apache.jk.core.JkHandler;
+import org.apache.jk.core.Msg;
+import org.apache.jk.core.MsgContext;
+import org.apache.jk.core.JkChannel;
+import org.apache.tomcat.util.buf.ByteChunk;
+import org.apache.tomcat.util.buf.C2BConverter;
+import org.apache.tomcat.util.buf.MessageBytes;
+
+
+/**
+ * Base class for components using native code ( libjkjni.so ).
+ * It allows to access the jk_env and wrap ( 'box' ? ) a native
+ * jk component, and call it's methods.
+ *
+ * Note that get/setAttribute are expensive ( Strings, etc ),
+ * invoke() is were all optimizations are done. We do recycle
+ * all memory on both C and java sides ( the only exception is
+ * when we attempt pinning but the VM doesn't support it ). The
+ * low level optimizations from ByteBuffer, etc are used to
+ * reduce the overhead of passing strings.
+ *
+ * @author Costin Manolache
+ */
+public class JniHandler extends JkHandler {
+    protected AprImpl apr;
+
+    // The native side handler
+    protected long nativeJkHandlerP;
+
+    protected String jkHome;
+
+    // Dispatch table codes. Hardcoded for now, will change when we have more handlers.
+    public static final int JK_HANDLE_JNI_DISPATCH=0x15;
+    public static final int JK_HANDLE_SHM_DISPATCH=0x16;
+
+
+    public static final int MSG_NOTE=0;
+    public static final int MB_NOTE=2;
+    private boolean paused = false;
+
+
+    public JniHandler() {
+    }
+
+    /**
+     */
+    public void setJkHome( String s ) {
+        jkHome=s;
+    }
+
+    public String getJkHome() {
+        return jkHome;
+    }
+
+    /** You must call initNative() inside the component init()
+     */
+    public void init() throws IOException {
+        // static field init, temp
+    }
+
+    protected void initNative(String nativeComponentName) {
+        apr=(AprImpl)wEnv.getHandler("apr");
+        if( apr==null ) {
+            // In most cases we can just load it automatically.
+            // that requires all libs to be installed in standard places
+            // ( LD_LIBRARY_PATH, /usr/lib
+            try {
+                apr=new AprImpl();
+                wEnv.addHandler("apr", apr);
+                apr.init();
+                if( oname != null ) {
+                    ObjectName aprname=new ObjectName(oname.getDomain() +
+                            ":type=JkHandler, name=apr");
+                    Registry.getRegistry(null, null).registerComponent(apr, aprname, null);
+                }
+            } catch( Throwable t ) {
+                log.debug("Can't load apr", t);
+                apr=null;
+            }
+        }
+        if( apr==null || ! apr.isLoaded() ) {
+            if( log.isDebugEnabled() )
+                log.debug("No apr, disabling jni proxy ");
+            apr=null;
+            return;
+        }
+
+        try {
+            long xEnv=apr.getJkEnv();
+            nativeJkHandlerP=apr.getJkHandler(xEnv, nativeComponentName );
+            
+            if( nativeJkHandlerP==0 ) {
+                log.debug("Component not found, creating it " + nativeComponentName );
+                nativeJkHandlerP=apr.createJkHandler(xEnv, nativeComponentName);
+            }
+            log.debug("Native proxy " + nativeJkHandlerP );
+            apr.releaseJkEnv(xEnv);
+        } catch( Throwable t ) {
+            apr=null;
+            log.info("Error calling apr ", t);
+        }
+   }
+
+    public void appendString( Msg msg, String s, C2BConverter charsetDecoder)
+        throws IOException
+    {
+        ByteChunk bc=charsetDecoder.getByteChunk();
+        charsetDecoder.recycle();
+        charsetDecoder.convert( s );
+        charsetDecoder.flushBuffer();
+        msg.appendByteChunk( bc );
+    }
+
+    public void pause() throws Exception {
+        synchronized(this) {
+            paused = true;
+        }
+    }
+
+    public void resume() throws Exception {
+        synchronized(this) {
+            paused = false;
+            notifyAll();
+        }
+    }
+
+
+    /** Create a msg context to be used with the shm channel
+     */
+    public MsgContext createMsgContext() {
+        if( nativeJkHandlerP==0 || apr==null  )
+            return null;
+
+        synchronized(this) {
+            try{ 
+                while(paused) {
+                    wait();
+                }
+            }catch(InterruptedException ie) {
+                // Ignore, since it can't happen
+            }
+        }
+
+        try {
+            MsgContext msgCtx=new MsgContext();
+            MsgAjp msg=new MsgAjp();
+
+            msgCtx.setSource( (JkChannel)this );
+            msgCtx.setWorkerEnv( wEnv );
+
+            msgCtx.setNext( this );
+
+            msgCtx.setMsg( MSG_NOTE, msg); // XXX Use noteId
+
+            C2BConverter c2b=new C2BConverter(  "iso-8859-1" );
+            msgCtx.setConverter( c2b );
+
+            MessageBytes tmpMB= MessageBytes.newInstance();
+            msgCtx.setNote( MB_NOTE, tmpMB );
+            return msgCtx;
+        } catch( Exception ex ) {
+            log.error("Can't create endpoint", ex);
+            return null;
+        }
+    }
+
+    public void setNativeAttribute(String name, String val) throws IOException {
+        if( apr==null ) return;
+
+        if( nativeJkHandlerP == 0 ) {
+            log.error( "Unitialized component " + name+ " " + val );
+            return;
+        }
+
+        long xEnv=apr.getJkEnv();
+
+        apr.jkSetAttribute( xEnv, nativeJkHandlerP, name, val );
+
+        apr.releaseJkEnv( xEnv );
+    }
+
+    public void initJkComponent() throws IOException {
+        if( apr==null ) return;
+
+        if( nativeJkHandlerP == 0 ) {
+            log.error( "Unitialized component " );
+            return;
+        }
+
+        long xEnv=apr.getJkEnv();
+
+        apr.jkInit( xEnv, nativeJkHandlerP );
+
+        apr.releaseJkEnv( xEnv );
+    }
+
+    public void destroyJkComponent() throws IOException {
+        if( apr==null ) return;
+
+        if( nativeJkHandlerP == 0 ) {
+            log.error( "Unitialized component " );
+            return;
+        }
+
+        long xEnv=apr.getJkEnv();
+
+        apr.jkDestroy( xEnv, nativeJkHandlerP );
+
+        apr.releaseJkEnv( xEnv );
+    }
+
+
+
+    protected void setNativeEndpoint(MsgContext msgCtx) {
+        long xEnv=apr.getJkEnv();
+        msgCtx.setJniEnv( xEnv );
+
+        long epP=apr.createJkHandler(xEnv, "endpoint");
+        log.debug("create ep " + epP );
+        if( epP == 0 ) return;
+        apr.jkInit( xEnv, epP );
+        msgCtx.setJniContext( epP );
+
+    }
+
+    protected void recycleNative(MsgContext ep) {
+        apr.jkRecycle(ep.getJniEnv(), ep.getJniContext());
+    }
+
+    /** send and get the response in the same buffer. This calls the
+    * method on the wrapped jk_bean object.
+     */
+    protected int nativeDispatch( Msg msg, MsgContext ep, int code, int raw )
+        throws IOException
+    {
+        if( log.isDebugEnabled() )
+            log.debug( "Sending packet " + code + " " + raw);
+
+        if( raw == 0 ) {
+            msg.end();
+
+            if( log.isTraceEnabled() ) msg.dump("OUT:" );
+        }
+
+        // Create ( or reuse ) the jk_endpoint ( the native pair of
+        // MsgContext )
+        long xEnv=ep.getJniEnv();
+        long nativeContext=ep.getJniContext();
+        if( nativeContext==0 || xEnv==0 ) {
+            setNativeEndpoint( ep );
+            xEnv=ep.getJniEnv();
+            nativeContext=ep.getJniContext();
+        }
+
+        if( xEnv==0 || nativeContext==0 || nativeJkHandlerP==0 ) {
+            log.error("invokeNative: Null pointer ");
+            return -1;
+        }
+
+        // Will process the message in the current thread.
+        // No wait needed to receive the response, if any
+        int status=AprImpl.jkInvoke( xEnv,
+                                 nativeJkHandlerP,
+                                 nativeContext,
+                                 code, msg.getBuffer(), 0, msg.getLen(), raw );
+
+        if( status != 0 && status != 2 ) {
+            log.error( "nativeDispatch: error " + status, new Throwable() );
+        }
+
+        if( log.isDebugEnabled() ) log.debug( "Sending packet - done " + status);
+        return status;
+    }
+
+    /** Base implementation for invoke. Dispatch the action to the native
+    * code, where invoke() is called on the wrapped jk_bean.
+    */
+    public  int invoke(Msg msg, MsgContext ep )
+        throws IOException
+    {
+        long xEnv=ep.getJniEnv();
+        int type=ep.getType();
+
+        int status=nativeDispatch(msg, ep, type, 0 );
+
+        apr.jkRecycle(xEnv, ep.getJniContext());
+        apr.releaseJkEnv( xEnv );
+        return status;
+    }
+
+    private static org.apache.commons.logging.Log log=
+        org.apache.commons.logging.LogFactory.getLog( JniHandler.class );
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/common/ModJkMX.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/common/ModJkMX.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/common/ModJkMX.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,451 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.jk.common;
+
+import java.io.IOException;
+import java.io.BufferedReader;
+import java.io.InputStreamReader;
+import java.net.URLConnection;
+import java.net.URL;
+import java.util.List;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import javax.management.MBeanServer;
+import javax.management.AttributeNotFoundException;
+import javax.management.MBeanException;
+import javax.management.ReflectionException;
+import javax.management.Attribute;
+import javax.management.ObjectName;
+
+import org.apache.jk.core.JkHandler;
+import org.apache.commons.modeler.Registry;
+import org.apache.commons.modeler.BaseModelMBean;
+import org.apache.commons.modeler.ManagedBean;
+import org.apache.commons.modeler.AttributeInfo;
+import org.apache.commons.modeler.OperationInfo;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * A small mbean that will act as a proxy for mod_jk2.
+ *
+ * For efficiency, it'll get bulk results and cache them - you
+ * can force an update by calling the refreshAttributes and refreshMetadata
+ * operations on this mbean.
+ *
+ * TODO: implement the user/pass auth ( right now you must use IP based security )
+ * TODO: eventually support https
+ * TODO: support for metadata ( mbean-descriptors ) for description and type conversions
+ * TODO: filter out trivial components ( mutexes, etc )
+ *
+ * @author Costin Manolache
+ */
+public class ModJkMX extends JkHandler
+{
+    private static Log log = LogFactory.getLog(ModJkMX.class);
+
+    MBeanServer mserver;
+    String webServerHost="localhost";
+    int webServerPort=80;
+    String statusPath="/jkstatus";
+    String user;
+    String pass;
+    Registry reg;
+
+    HashMap mbeans=new HashMap();
+    long lastRefresh=0;
+    long updateInterval=5000; // 5 sec - it's min time between updates
+
+    public ModJkMX()
+    {
+    }
+
+    /* -------------------- Public methods -------------------- */
+
+    public String getWebServerHost() {
+        return webServerHost;
+    }
+
+    public void setWebServerHost(String webServerHost) {
+        this.webServerHost = webServerHost;
+    }
+
+    public int getWebServerPort() {
+        return webServerPort;
+    }
+
+    public void setWebServerPort(int webServerPort) {
+        this.webServerPort = webServerPort;
+    }
+
+    public long getUpdateInterval() {
+        return updateInterval;
+    }
+
+    public void setUpdateInterval(long updateInterval) {
+        this.updateInterval = updateInterval;
+    }
+
+    public String getUser() {
+        return user;
+    }
+
+    public void setUser(String user) {
+        this.user = user;
+    }
+
+    public String getPass() {
+        return pass;
+    }
+
+    public void setPass(String pass) {
+        this.pass = pass;
+    }
+
+    public String getStatusPath() {
+        return statusPath;
+    }
+
+    public void setStatusPath(String statusPath) {
+        this.statusPath = statusPath;
+    }
+    /* ==================== Start/stop ==================== */
+
+    public void destroy() {
+        try {
+            // We should keep track of loaded beans and call stop.
+            // Modeler should do it...
+            Iterator mbeansIt=mbeans.values().iterator();
+            MBeanServer mbserver = Registry.getRegistry(null, null).getMBeanServer();
+            while( mbeansIt.hasNext()) {
+                MBeanProxy proxy=(MBeanProxy)mbeansIt.next();
+                Object ooname = proxy.getObjectName();
+                if( ooname != null ) {
+                    ObjectName oname = null;
+                    if(ooname instanceof ObjectName) {
+                        oname = (ObjectName)ooname;
+                    } else if(ooname instanceof String) {
+                        oname = new ObjectName((String)ooname);
+                    }
+                    if( oname != null ) {
+                        mbserver.unregisterMBean(oname);
+                    }
+                }
+            }
+        } catch( Throwable t ) {
+            log.error( "Destroy error", t );
+        }
+    }
+
+    public void init() throws IOException {
+        try {
+            //if( log.isDebugEnabled() )
+            log.info("init " + webServerHost + " " + webServerPort);
+            reg=Registry.getRegistry(null, null);
+            refreshMetadata();
+            refreshAttributes();
+        } catch( Throwable t ) {
+            log.error( "Init error", t );
+        }
+    }
+
+    public void start() throws IOException {
+        if( reg==null)
+            init();
+    }
+
+    /** Refresh the proxies, if updateInterval passed
+     *
+     */
+    public void refresh()  {
+        long time=System.currentTimeMillis();
+        if( time - lastRefresh < updateInterval ) {
+            return;
+        }
+        lastRefresh=time;
+        refreshMetadata();
+        refreshAttributes();
+    }
+
+    public void refreshAttributes()  {
+        try {
+            int cnt=0;
+            // connect to apache, get a list of mbeans
+            BufferedReader is=getStream( "dmp=*");
+            if( is==null ) return;
+
+            String name=null;
+            String att=null;
+            String val=null;
+            while(true) {
+                String line=is.readLine();
+                if( line==null ) break;
+                line=line.trim();
+                if( "".equals(line) || line.startsWith("#") ) continue;
+
+                // for each mbean, create a proxy
+                if(log.isDebugEnabled())
+                    log.debug("Read " + line);
+
+                if(line.startsWith( "[")) {
+                    name=line.substring(1);
+                    if( name.endsWith("]")) {
+                        name=name.substring(0, name.length()-1);
+                    }
+                }
+                // Name/value pair
+                int idx=line.indexOf('=');
+                if( idx < 0 ) continue;
+                att=line.substring(0, idx );
+                val=line.substring(idx+1);
+
+                if( log.isDebugEnabled())
+                    log.debug("name: " + name + " att=" + att +
+                            " val=" + val);
+
+                MBeanProxy proxy=(MBeanProxy)mbeans.get(name);
+                if( proxy==null ) {
+                    log.info( "Unknown object " + name);
+                } else {
+                    proxy.update(att, val);
+                    cnt++;
+                }
+            }
+            log.info( "Refreshing attributes " + cnt);
+        } catch( Exception ex ) {
+            log.info("Error ", ex);
+        }
+    }
+
+    /** connect to apache, get a list of mbeans
+      */
+    BufferedReader getStream(String qry) throws Exception {
+        try {
+            String path=statusPath + "?" + qry;
+            URL url=new URL( "http", webServerHost, webServerPort, path);
+            URLConnection urlc=url.openConnection();
+            BufferedReader is=new BufferedReader(new InputStreamReader(urlc.getInputStream()));
+            return is;
+        } catch (IOException e) {
+            log.info( "Can't connect to jkstatus " + webServerHost + ":" + webServerPort
+            + " " + e.toString());
+            return null;
+        }
+    }
+
+    public void refreshMetadata() {
+        try {
+            int cnt=0;
+            int newCnt=0;
+            BufferedReader is=getStream("lst=*");
+            if( is==null ) return;
+            String name=null;
+            String type=null;
+            ArrayList getters=new ArrayList();
+            ArrayList setters=new ArrayList();
+            ArrayList methods=new ArrayList();
+            while(true) {
+                String line=is.readLine();
+                if( log.isDebugEnabled())
+                    log.debug("Read " + line);
+
+                // end of section
+                if( line == null || line.startsWith("[") ) {
+                    if( name != null ) {
+                        cnt++;
+                        if( mbeans.get( name ) ==null ) {
+                            // New component
+                            newCnt++;
+                            MBeanProxy mproxy=new MBeanProxy(this);
+                            mproxy.init( name, getters, setters, methods);
+                            mbeans.put( name, mproxy );
+                        }
+                        if( log.isDebugEnabled())
+                            log.debug("mbean name: " + name + " type=" + type);
+
+                        getters.clear();
+                        setters.clear();
+                        methods.clear();
+                    }
+                }
+                // end of data
+                if( line==null ) break;
+
+                line=line.trim();
+                if( "".equals( line ) || line.startsWith("#"))  continue;
+
+                // for each mbean, create a proxy
+
+                if(line.startsWith( "[") && line.endsWith("]")) {
+                    name=line.substring(1, line.length()-1);
+                }
+                if(line.startsWith( "T=")) {
+                    type=line.substring(2);
+                }
+                if( line.startsWith("G=")) {
+                    getters.add(line.substring(2));
+                }
+                if( line.startsWith("S=")) {
+                    setters.add(line.substring(2));
+                }
+                if( line.startsWith("M=")) {
+                    methods.add(line.substring(2));
+                }
+            }
+            log.info( "Refreshing metadata " + cnt + " " +  newCnt);
+        } catch( Exception ex ) {
+            log.info("Error ", ex);
+        }
+    }
+
+    /** Use the same metadata, except that we replace the attribute
+     * get/set methods.
+     */
+    static class MBeanProxy extends BaseModelMBean {
+        private static Log log = LogFactory.getLog(MBeanProxy.class);
+
+        String jkName;
+        List getAttNames;
+        List setAttNames;
+        HashMap atts=new HashMap();
+        ModJkMX jkmx;
+
+        public MBeanProxy(ModJkMX jkmx) throws Exception {
+            this.jkmx=jkmx;
+        }
+
+        void init( String name, List getters, List setters, List methods )
+            throws Exception
+        {
+            if(log.isDebugEnabled())
+                log.debug("Register " + name );
+            int col=name.indexOf( ':' );
+            this.jkName=name;
+            String type=name.substring(0, col );
+            String id=name.substring(col+1);
+            id=id.replace('*','%');
+            id=id.replace(':', '%');
+            if( id.length() == 0 ) {
+                id="default";
+            }
+            ManagedBean mbean= new ManagedBean();
+
+            AttributeInfo ai=new AttributeInfo();
+            ai.setName( "jkName" );
+            ai.setType( "java.lang.String");
+            ai.setWriteable(false);
+            mbean.addAttribute(ai);
+
+            for( int i=0; i<getters.size(); i++ ) {
+                String att=(String)getters.get(i);
+                // Register metadata
+                ai=new AttributeInfo();
+                ai.setName( att );
+                ai.setType( "java.lang.String");
+                if( ! setters.contains(att))
+                    ai.setWriteable(false);
+                mbean.addAttribute(ai);
+            }
+            for( int i=0; i<setters.size(); i++ ) {
+                String att=(String)setters.get(i);
+                if( getters.contains(att))
+                    continue;
+                // Register metadata
+                ai=new AttributeInfo();
+                ai.setName( att );
+                ai.setType( "java.lang.String");
+                ai.setReadable(false);
+                mbean.addAttribute(ai);
+            }
+            for( int i=0; i<methods.size(); i++ ) {
+                String att=(String)methods.get(i);
+                // Register metadata
+                OperationInfo oi=new OperationInfo();
+                oi.setName( att );
+                oi.setReturnType("void");
+                mbean.addOperation(oi);
+            }
+
+            this.setModelMBeanInfo(mbean.createMBeanInfo());
+
+            MBeanServer mserver=Registry.getRegistry(null, null).getMBeanServer();
+            oname=new ObjectName("apache:type=" + type + ",id=" + id);
+            mserver.registerMBean(this, oname);
+        }
+
+        private void update( String name, String val ) {
+            log.debug( "Updating " + jkName + " " + name + " " + val);
+            atts.put( name, val);
+        }
+
+        public Object getAttribute(String name)
+            throws AttributeNotFoundException, MBeanException,
+                ReflectionException {
+            if( "jkName".equals( name )) {
+                return jkName;
+            }
+            jkmx.refresh();
+            return atts.get(name);
+        }
+
+        public void setAttribute(Attribute attribute)
+            throws AttributeNotFoundException, MBeanException,
+            ReflectionException
+        {
+            try {
+                // we support only string values
+                String val=(String)attribute.getValue();
+                String name=attribute.getName();
+                BufferedReader is=jkmx.getStream("set=" + jkName + "|" +
+                        name + "|" + val);
+                if( is==null ) return;
+                String res=is.readLine();
+                if( log.isDebugEnabled())
+                    log.debug( "Setting " + jkName + " " + name + " result " + res);
+
+                jkmx.refreshMetadata();
+                jkmx.refreshAttributes();
+            } catch( Exception ex ) {
+                throw new MBeanException(ex);
+            }
+        }
+
+        public Object invoke(String name, Object params[], String signature[])
+            throws MBeanException, ReflectionException {
+            try {
+                // we support only string values
+                BufferedReader is=jkmx.getStream("inv=" + jkName + "|" +
+                        name );
+                if( is==null ) return null;
+                String res=is.readLine();
+                if( log.isDebugEnabled())
+                    log.debug( "Invoking " + jkName + " " + name + " result " + res);
+
+                jkmx.refreshMetadata();
+                jkmx.refreshAttributes();
+            } catch( Exception ex ) {
+                throw new MBeanException(ex);
+            }
+            return null;
+        }
+
+    }
+
+
+}
+

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/common/MsgAjp.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/common/MsgAjp.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/common/MsgAjp.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,351 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.jk.common;
+
+import java.io.IOException;
+
+import org.apache.jk.core.Msg;
+import org.apache.tomcat.util.buf.ByteChunk;
+import org.apache.tomcat.util.buf.MessageBytes;
+
+/**
+ * A single packet for communication between the web server and the
+ * container.  Designed to be reused many times with no creation of
+ * garbage.  Understands the format of data types for these packets.
+ * Can be used (somewhat confusingly) for both incoming and outgoing
+ * packets.  
+ *
+ * See Ajp14/Ajp13Packet.java.
+ *
+ * @author Henri Gomez [hgomez at apache.org]
+ * @author Dan Milstein [danmil at shore.net]
+ * @author Keith Wannamaker [Keith at Wannamaker.org]
+ * @author Kevin Seguin
+ * @author Costin Manolache
+ */
+public class MsgAjp extends Msg {
+    private static org.apache.commons.logging.Log log=
+        org.apache.commons.logging.LogFactory.getLog( MsgAjp.class );
+
+    // that's the original buffer size in ajp13 - otherwise we'll get interoperability problems.
+    private byte buf[];
+    // The current read or write position in the buffer
+    private int pos;    
+    /**
+     * This actually means different things depending on whether the
+     * packet is read or write.  For read, it's the length of the
+     * payload (excluding the header).  For write, it's the length of
+     * the packet as a whole (counting the header).  Oh, well.
+     */
+    private int len; 
+
+    /**
+     * The maximum packet size
+     */
+    private int bufsize;
+
+    /**
+     * Constructor that takes a buffer size
+     */
+    public MsgAjp(int bsize) {
+        if(bsize < 8*1024) {
+            bsize = 8*1024;
+        }
+        bufsize = bsize;
+        buf = new byte[bsize];
+    
+    }
+
+    /**
+     * No arg constructor.
+     * @deprecated Use the buffer size constructor.
+     */
+    public MsgAjp() {
+        this(8*1024);
+    }
+
+    /**
+     * Prepare this packet for accumulating a message from the container to
+     * the web server.  Set the write position to just after the header
+     * (but leave the length unwritten, because it is as yet unknown).
+     */
+    public void reset() {
+        len = 4;
+        pos = 4;
+    }
+	
+    /**
+     * For a packet to be sent to the web server, finish the process of
+     * accumulating data and write the length of the data payload into
+     * the header.  
+     */
+    public void end() {
+        len=pos;
+        int dLen=len-4;
+
+        buf[0] = (byte)0x41;
+        buf[1] = (byte)0x42;
+        buf[2]=  (byte)((dLen>>>8 ) & 0xFF );
+        buf[3] = (byte)(dLen & 0xFF);
+    }
+
+    public byte[] getBuffer() {
+        return buf;
+    }
+
+    public int getLen() {
+        return len;
+    }
+    
+    // ============ Data Writing Methods ===================
+
+    /**
+     * Add an int.
+     *
+     * @param val The integer to write.
+     */
+    public void appendInt( int val ) {
+        buf[pos++]   = (byte) ((val >>>  8) & 0xFF);
+        buf[pos++] = (byte) (val & 0xFF);
+    }
+
+    public void appendByte( int val ) {
+        buf[pos++] = (byte)val;
+    }
+	
+    public void appendLongInt( int val ) {
+        buf[pos++]   = (byte) ((val >>>  24) & 0xFF);
+        buf[pos++] = (byte) ((val >>>  16) & 0xFF);
+        buf[pos++] = (byte) ((val >>>   8) & 0xFF);
+        buf[pos++] = (byte) (val & 0xFF);
+    }
+
+    /**
+     * Write a String out at the current write position.  Strings are
+     * encoded with the length in two bytes first, then the string, and
+     * then a terminating \0 (which is <B>not</B> included in the
+     * encoded length).  The terminator is for the convenience of the C
+     * code, where it saves a round of copying.  A null string is
+     * encoded as a string with length 0.  
+     */
+    public void appendBytes(MessageBytes mb) throws IOException {
+        if(mb==null || mb.isNull() ) {
+            appendInt( 0);
+            appendByte(0);
+            return;
+        }
+
+        // XXX Convert !!
+        ByteChunk bc= mb.getByteChunk();
+        appendByteChunk(bc);
+    }
+
+    public void appendByteChunk(ByteChunk bc) throws IOException {
+        if(bc==null) {
+            log.error("appendByteChunk() null");
+            appendInt( 0);
+            appendByte(0);
+            return;
+        }
+
+        byte[] bytes = bc.getBytes();
+        int start=bc.getStart();
+        appendInt( bc.getLength() );
+        cpBytes(bytes, start, bc.getLength());
+        appendByte(0);
+    }
+
+    /** 
+     * Copy a chunk of bytes into the packet, starting at the current
+     * write position.  The chunk of bytes is encoded with the length
+     * in two bytes first, then the data itself, and finally a
+     * terminating \0 (which is <B>not</B> included in the encoded
+     * length).
+     *
+     * @param b The array from which to copy bytes.
+     * @param off The offset into the array at which to start copying
+     * @param numBytes The number of bytes to copy.  
+     */
+    public void appendBytes( byte b[], int off, int numBytes ) {
+        appendInt( numBytes );
+        cpBytes( b, off, numBytes );
+        appendByte(0);
+    }
+    
+    private void cpBytes( byte b[], int off, int numBytes ) {
+        if( pos + numBytes >= buf.length ) {
+            log.error("Buffer overflow: buffer.len=" + buf.length + " pos=" +
+                      pos + " data=" + numBytes );
+            dump("Overflow/coBytes");
+            log.error( "Overflow ", new Throwable());
+            return;
+        }
+        System.arraycopy( b, off, buf, pos, numBytes);
+        pos += numBytes;
+        // buf[pos + numBytes] = 0; // Terminating \0
+    }
+    
+
+    
+    // ============ Data Reading Methods ===================
+
+    /**
+     * Read an integer from packet, and advance the read position past
+     * it.  Integers are encoded as two unsigned bytes with the
+     * high-order byte first, and, as far as I can tell, in
+     * little-endian order within each byte.  
+     */
+    public int getInt() {
+        int b1 = buf[pos++] & 0xFF;  // No swap, Java order
+        int b2 = buf[pos++] & 0xFF;
+
+        return  (b1<<8) + b2;
+    }
+
+    public int peekInt() {
+        int b1 = buf[pos] & 0xFF;  // No swap, Java order
+        int b2 = buf[pos+1] & 0xFF;
+
+        return  (b1<<8) + b2;
+    }
+
+    public byte getByte() {
+        byte res = buf[pos++];
+        return res;
+    }
+
+    public byte peekByte() {
+        byte res = buf[pos];
+        return res;
+    }
+
+    public void getBytes(MessageBytes mb) {
+        int length = getInt();
+        if( (length == 0xFFFF) || (length == -1) ) {
+            mb.recycle();
+            return;
+        }
+        mb.setBytes( buf, pos, length );
+        pos += length;
+        pos++; // Skip the terminating \0
+    }
+    
+    /**
+     * Copy a chunk of bytes from the packet into an array and advance
+     * the read position past the chunk.  See appendBytes() for details
+     * on the encoding.
+     *
+     * @return The number of bytes copied.
+     */
+    public int getBytes(byte dest[]) {
+        int length = getInt();
+        if( length > buf.length ) {
+            // XXX Should be if(pos + length > buff.legth)?
+            log.error("getBytes() buffer overflow " + length + " " + buf.length );
+        }
+	
+        if( (length == 0xFFFF) || (length == -1) ) {
+            log.info("Null string " + length);
+            return 0;
+        }
+
+        System.arraycopy( buf, pos,  dest, 0, length );
+        pos += length;
+        pos++; // Skip terminating \0  XXX I believe this is wrong but harmless
+        return length;
+    }
+
+    /**
+     * Read a 32 bits integer from packet, and advance the read position past
+     * it.  Integers are encoded as four unsigned bytes with the
+     * high-order byte first, and, as far as I can tell, in
+     * little-endian order within each byte.
+     */
+    public int getLongInt() {
+        int b1 = buf[pos++] & 0xFF;  // No swap, Java order
+        b1 <<= 8;
+        b1 |= (buf[pos++] & 0xFF);
+        b1 <<= 8;
+        b1 |= (buf[pos++] & 0xFF);
+        b1 <<=8;
+        b1 |= (buf[pos++] & 0xFF);
+        return  b1;
+    }
+
+    public int getHeaderLength() {
+        return 4;
+    }
+
+    public int processHeader() {
+        pos = 0;
+        int mark = getInt();
+        len      = getInt();
+	    
+        if( mark != 0x1234 && mark != 0x4142 ) {
+            // XXX Logging
+            log.error("BAD packet signature " + mark);
+            dump( "In: " );
+            return -1;
+        }
+
+        if( log.isDebugEnabled() ) 
+            log.debug( "Received " + len + " " + buf[0] );
+        return len;
+    }
+    
+    public void dump(String msg) {
+        if( log.isDebugEnabled() ) 
+            log.debug( msg + ": " + buf + " " + pos +"/" + (len + 4));
+        int max=pos;
+        if( len + 4 > pos )
+            max=len+4;
+        if( max >1000 ) max=1000;
+        if( log.isDebugEnabled() ) 
+            for( int j=0; j < max; j+=16 ) 
+                log.debug( hexLine( buf, j, len ));
+	
+    }
+
+    /* -------------------- Utilities -------------------- */
+    // XXX Move to util package
+
+    public static String hexLine( byte buf[], int start, int len ) {
+        StringBuffer sb=new StringBuffer();
+        for( int i=start; i< start+16 ; i++ ) {
+            if( i < len + 4)
+                sb.append( hex( buf[i] ) + " ");
+            else 
+                sb.append( "   " );
+        }
+        sb.append(" | ");
+        for( int i=start; i < start+16 && i < len + 4; i++ ) {
+            if( ! Character.isISOControl( (char)buf[i] ))
+                sb.append( new Character((char)buf[i]) );
+            else
+                sb.append( "." );
+        }
+        return sb.toString();
+    }
+
+    private  static String hex( int x ) {
+        //	    if( x < 0) x=256 + x;
+        String h=Integer.toHexString( x );
+        if( h.length() == 1 ) h = "0" + h;
+        return h.substring( h.length() - 2 );
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/common/Shm.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/common/Shm.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/common/Shm.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,330 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.jk.common;
+
+import java.io.IOException;
+import java.util.Vector;
+
+import org.apache.jk.apr.AprImpl;
+import org.apache.jk.core.Msg;
+import org.apache.jk.core.MsgContext;
+import org.apache.jk.core.WorkerEnv;
+import org.apache.tomcat.util.IntrospectionUtils;
+import org.apache.tomcat.util.buf.C2BConverter;
+
+/* The code is a bit confusing at this moment - the class is used as
+   a Bean, or ant Task, or CLI - i.e. you set properties and call execute.
+
+   That's different from the rest of jk handlers wich are stateless ( but
+   similar with Coyote-http ).
+*/
+
+
+/** Handle the shared memory objects.
+ *
+ * @author Costin Manolache
+ */
+public class Shm extends JniHandler {
+    String file="/tmp/shm.file";
+    int size;
+    String host="localhost";
+    int port=8009;
+    String unixSocket;
+
+    boolean help=false;
+    boolean unregister=false;
+    boolean reset=false;
+    String dumpFile=null;
+
+    Vector groups=new Vector();
+    
+    // Will be dynamic ( getMethodId() ) after things are stable 
+    static final int SHM_WRITE_SLOT=2;
+    static final int SHM_RESET=5;
+    static final int SHM_DUMP=6;
+    
+    public Shm() {
+    }
+
+    /** Scoreboard location
+     */
+    public void setFile( String f ) {
+        file=f;
+    }
+
+    /** Copy the scoreboard in a file for debugging
+     *  Will also log a lot of information about what's in the scoreboard.
+     */
+    public void setDump( String dumpFile ) {
+        this.dumpFile=dumpFile;
+    }
+    
+    /** Size. Used only if the scoreboard is to be created.
+     */
+    public void setSize( int size ) {
+        this.size=size;
+    }
+
+    /** Set this to get the scoreboard reset.
+     *  The shm segment will be destroyed and a new one created,
+     *  with the provided size.
+     *
+     *  Requires "file" and "size".
+     */
+    public void setReset(boolean b) {
+        reset=true;
+    }
+
+    /** Ajp13 host
+     */
+    public void setHost( String host ) {
+        this.host=host;
+    }
+
+    /** Mark this instance as belonging to a group
+     */
+    public void setGroup( String grp ) {
+        groups.addElement( grp );
+    }
+
+    /** Ajp13 port
+     */
+    public void setPort( int port ) {
+        this.port=port;
+    }
+
+    /** Unix socket where tomcat is listening.
+     *  Use it only if tomcat is on the same host, of course
+     */
+    public void setUnixSocket( String unixSocket  ) {
+        this.unixSocket=unixSocket;
+    }
+
+    /** Set this option to mark the tomcat instance as
+        'down', so apache will no longer forward messages to it.
+        Note that requests with a session will still try this
+        host first.
+
+        This can be used to implement gracefull shutdown.
+
+        Host and port are still required, since they are used
+        to identify tomcat.
+    */
+    public void setUnregister( boolean unregister  ) {
+        this.unregister=true;
+    }
+    
+    public void init() throws IOException {
+        super.initNative( "shm" );
+        if( apr==null ) return;
+        if( file==null ) {
+            log.error("No shm file, disabling shared memory");
+            apr=null;
+            return;
+        }
+
+        // Set properties and call init.
+        setNativeAttribute( "file", file );
+        if( size > 0 )
+            setNativeAttribute( "size", Integer.toString( size ) );
+        
+        initJkComponent();
+    }
+
+    public void resetScoreboard() throws IOException {
+        if( apr==null ) return;
+        MsgContext mCtx=createMsgContext();
+        Msg msg=(Msg)mCtx.getMsg(0);
+        msg.reset();
+
+        msg.appendByte( SHM_RESET );
+        
+        this.invoke( msg, mCtx );
+    }
+
+    public void dumpScoreboard(String fname) throws IOException {
+        if( apr==null ) return;
+        MsgContext mCtx=createMsgContext();
+        Msg msg=(Msg)mCtx.getMsg(0);
+        C2BConverter c2b=mCtx.getConverter();
+        msg.reset();
+
+        msg.appendByte( SHM_DUMP );
+
+        appendString( msg, fname, c2b);
+        
+        this.invoke( msg, mCtx );
+    }
+
+    /** Register a tomcat instance
+     *  XXX make it more flexible
+     */
+    public void registerTomcat(String host, int port, String unixDomain)
+        throws IOException
+    {
+        String instanceId=host+":" + port;
+
+        String slotName="TOMCAT:" + instanceId;
+        MsgContext mCtx=createMsgContext();
+        Msg msg=(Msg)mCtx.getMsg(0);
+        msg.reset();
+        C2BConverter c2b=mCtx.getConverter();
+        
+        msg.appendByte( SHM_WRITE_SLOT );
+        appendString( msg, slotName, c2b );
+
+        int channelCnt=1;
+        if( unixDomain != null ) channelCnt++;
+
+        // number of groups. 0 means the default lb.
+        msg.appendInt( groups.size() );
+        for( int i=0; i<groups.size(); i++ ) {
+            appendString( msg, (String)groups.elementAt( i ), c2b);
+            appendString( msg, instanceId, c2b);
+        }
+        
+        // number of channels for this instance
+        msg.appendInt( channelCnt );
+        
+        // The body:
+        appendString(msg, "channel.socket:" + host + ":" + port, c2b );
+        msg.appendInt( 1 );
+        appendString(msg, "tomcatId", c2b);
+        appendString(msg, instanceId, c2b);
+
+        if( unixDomain != null ) {
+            appendString(msg, "channel.apr:" + unixDomain, c2b );
+            msg.appendInt(1);
+            appendString(msg, "tomcatId", c2b);
+            appendString(msg, instanceId, c2b);
+        }
+
+        if (log.isDebugEnabled())
+            log.debug("Register " + instanceId );
+        this.invoke( msg, mCtx );
+    }
+
+    public void unRegisterTomcat(String host, int port)
+        throws IOException
+    {
+        String slotName="TOMCAT:" + host + ":" + port;
+        MsgContext mCtx=createMsgContext();
+        Msg msg=(Msg)mCtx.getMsg(0);
+        msg.reset();
+        C2BConverter c2b=mCtx.getConverter();
+        
+        msg.appendByte( SHM_WRITE_SLOT );
+        appendString( msg, slotName, c2b );
+
+        // number of channels for this instance
+        msg.appendInt( 0 );
+        msg.appendInt( 0 );
+        
+        if (log.isDebugEnabled())
+            log.debug("UnRegister " + slotName );
+        this.invoke( msg, mCtx );
+    }
+
+    public void destroy() throws IOException {
+        destroyJkComponent();
+    }
+
+    
+    public  int invoke(Msg msg, MsgContext ep )
+        throws IOException
+    {
+        if( apr==null ) return 0;
+        log.debug("ChannelShm.invoke: "  + ep );
+        super.nativeDispatch( msg, ep, JK_HANDLE_SHM_DISPATCH, 0 );
+        return 0;
+    }    
+
+    private static org.apache.commons.logging.Log log=
+        org.apache.commons.logging.LogFactory.getLog( Shm.class );
+
+    
+    //-------------------- Main - use the shm functions from ant or CLI ------
+
+    /** Local initialization - for standalone use
+     */
+    public void initCli() throws IOException {
+        WorkerEnv wEnv=new WorkerEnv();
+        AprImpl apr=new AprImpl();
+        wEnv.addHandler( "apr", apr );
+        wEnv.addHandler( "shm", this );
+        apr.init();
+        if( ! apr.isLoaded() ) {
+            log.error( "No native support. " +
+                       "Make sure libapr.so and libjkjni.so are available in LD_LIBRARY_PATH");
+            return;
+        }
+    }
+    
+    public void execute() {
+        try {
+            if( help ) return;
+            initCli();
+            init();
+
+            if( reset ) {
+                resetScoreboard();
+            } else if( dumpFile!=null ) {
+                dumpScoreboard(dumpFile);
+            } else if( unregister ) {
+                unRegisterTomcat( host, port );
+            } else {
+                registerTomcat( host, port, unixSocket );
+            }
+        } catch (Exception ex ) {
+            log.error( "Error executing Shm", ex);
+        }
+    }
+
+    public void setHelp( boolean b ) {
+        if (log.isDebugEnabled()) {
+            log.debug("Usage: ");
+            log.debug("  Shm [OPTIONS]");
+            log.debug("");
+            log.debug("  -file SHM_FILE");
+            log.debug("  -group GROUP ( can be specified multiple times )");
+            log.debug("  -host HOST");
+            log.debug("  -port PORT");
+            log.debug("  -unixSocket UNIX_FILE");
+            //        log.debug("  -priority XXX");
+            //        log.debug("  -lbFactor XXX");
+        }
+        help=true;
+        return;
+    }
+    
+    public static void main( String args[] ) {
+        try {
+            Shm shm=new Shm();
+
+            if( args.length == 0 ||
+                ( "-?".equals(args[0]) ) ) {
+                shm.setHelp( true );
+                return;
+            }
+
+            IntrospectionUtils.processArgs( shm, args);
+            shm.execute();
+        } catch( Exception ex ) {
+            ex.printStackTrace();
+        }
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/common/Shm14.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/common/Shm14.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/common/Shm14.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,96 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.jk.common;
+
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.nio.MappedByteBuffer;
+import java.nio.channels.FileChannel;
+
+import org.apache.jk.core.Msg;
+import org.apache.jk.core.MsgContext;
+import org.apache.tomcat.util.IntrospectionUtils;
+
+/** Shm implementation using JDK1.4 nio.
+ *
+ *
+ * @author Costin Manolache
+ */
+public class Shm14 extends Shm {
+    
+    
+    // Not ready yet.
+    
+    private static org.apache.commons.logging.Log log=
+        org.apache.commons.logging.LogFactory.getLog( Shm14.class );
+    
+    MappedByteBuffer bb;
+
+    public void init() {
+        try {
+            RandomAccessFile f=new RandomAccessFile( file, "rw" );
+            FileChannel fc=f.getChannel();
+            
+            bb=fc.map( FileChannel.MapMode.READ_WRITE, 0, f.length());
+        } catch( IOException ex ) {
+            ex.printStackTrace();
+        }
+    }
+
+    public void dumpScoreboard(String file) {
+        // We can only sync with our backing store.
+        bb.force();
+        // XXX we should copy the content to the file
+    }
+
+    public void resetScoreboard() throws IOException {
+        // XXX Need to write the head
+    }
+
+
+    public  int invoke(Msg msg, MsgContext ep )
+        throws IOException
+    {
+        if (log.isDebugEnabled())
+            log.debug("ChannelShm14.invoke: "  + ep );
+
+        // 
+        
+        return 0;
+    }    
+
+    public void initCli() {
+    }
+
+    public static void main( String args[] ) {
+        try {
+            Shm14 shm=new Shm14();
+
+            if( args.length == 0 ||
+                ( "-?".equals(args[0]) ) ) {
+                shm.setHelp( true );
+                return;
+            }
+
+            IntrospectionUtils.processArgs( shm, args);
+            shm.execute();
+        } catch( Exception ex ) {
+            ex.printStackTrace();
+        }
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/common/WorkerDummy.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/common/WorkerDummy.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/common/WorkerDummy.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,90 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.jk.common;
+
+import java.io.IOException;
+
+import org.apache.jk.core.JkHandler;
+import org.apache.jk.core.Msg;
+import org.apache.jk.core.MsgContext;
+import org.apache.jk.core.WorkerEnv;
+import org.apache.tomcat.util.buf.MessageBytes;
+
+
+/** A dummy worker, will just send back a dummy response.
+ *  Used for testing and tunning.
+ */
+public class WorkerDummy extends JkHandler
+{
+    public WorkerDummy()
+    {
+        String msg="HelloWorld";
+        byte b[]=msg.getBytes();
+        body.setBytes(b, 0, b.length);
+    }
+
+    /* ==================== Start/stop ==================== */
+
+    /** Initialize the worker. After this call the worker will be
+     *  ready to accept new requests.
+     */
+    public void init() throws IOException {
+        headersMsgNote=wEnv.getNoteId( WorkerEnv.ENDPOINT_NOTE, "headerMsg" );
+    }
+ 
+    MessageBytes body=MessageBytes.newInstance();
+    private int headersMsgNote;
+    
+    public int invoke( Msg in, MsgContext ep ) 
+        throws IOException
+    {
+        MsgAjp msg=(MsgAjp)ep.getNote( headersMsgNote );
+        if( msg==null ) {
+            msg=new MsgAjp();
+            ep.setNote( headersMsgNote, msg );
+        }
+
+        msg.reset();
+        msg.appendByte(AjpConstants.JK_AJP13_SEND_HEADERS);
+        msg.appendInt(200);
+        msg.appendBytes(null);
+
+        msg.appendInt(0);
+
+        ep.setType( JkHandler.HANDLE_SEND_PACKET );
+        ep.getSource().invoke( msg, ep );
+        //         msg.dump("out:" );
+
+        msg.reset();
+        msg.appendByte( AjpConstants.JK_AJP13_SEND_BODY_CHUNK);
+        msg.appendInt( body.getLength() );
+        msg.appendBytes( body );
+
+        
+        ep.getSource().invoke(msg, ep);
+
+        msg.reset();
+        msg.appendByte( AjpConstants.JK_AJP13_END_RESPONSE );
+        msg.appendInt( 1 );
+        
+        ep.getSource().invoke(msg, ep );
+        return OK;
+    }
+    
+    private static final int dL=0;
+}
+

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/config/ApacheConfig.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/config/ApacheConfig.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/config/ApacheConfig.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,573 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.jk.config;
+
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.Date;
+import java.util.Hashtable;
+
+import org.apache.catalina.Context;
+import org.apache.catalina.Host;
+
+/* The idea is to keep all configuration in server.xml and
+   the normal apache config files. We don't want people to
+   touch apache ( or IIS, NES ) config files unless they
+   want to and know what they're doing ( better than we do :-).
+
+   One nice feature ( if someone sends it ) would be to
+   also edit httpd.conf to add the include.
+
+   We'll generate a number of configuration files - this one
+   is trying to generate a native apache config file.
+
+   Some web.xml mappings do not "map" to server configuration - in
+   this case we need to fallback to forward all requests to tomcat.
+
+   Ajp14 will add to that the posibility to have tomcat and
+   apache on different machines, and many other improvements -
+   but this should also work for Ajp12, Ajp13 and Jni.
+
+*/
+
+/**
+    Generates automatic apache mod_jk configurations based on
+    the Tomcat server.xml settings and the war contexts
+    initialized during startup.
+    <p>
+    This config interceptor is enabled by inserting an ApacheConfig
+    <code>Listener</code> in 
+    the server.xml file like so:
+    <pre>
+    * < Server ... >
+    *   ...
+    *   <Listener className=<b>org.apache.ajp.tomcat4.config.ApacheConfig</b> 
+    *       <i>options</i> />
+    *   ...
+    * < /Server >
+    </pre>
+    where <i>options</i> can include any of the following attributes:
+    <ul>
+     <li><b>configHome</b> - default parent directory for the following paths.
+                            If not set, this defaults to TOMCAT_HOME. Ignored
+                            whenever any of the following paths is absolute.
+                             </li>
+     <li><b>jkConfig</b> - path to use for writing Apache mod_jk conf file. If
+                            not set, defaults to
+                            "conf/auto/mod_jk.conf".</li>
+     <li><b>workersConfig</b> - path to workers.properties file used by 
+                            mod_jk. If not set, defaults to
+                            "conf/jk/workers.properties".</li>
+     <li><b>modJk</b> - path to Apache mod_jk plugin file.  If not set,
+                        defaults to "modules/mod_jk.dll" on windows,
+                        "modules/mod_jk.nlm" on netware, and
+                        "libexec/mod_jk.so" everywhere else.</li>
+     <li><b>jkLog</b> - path to log file to be used by mod_jk.</li>
+     <li><b>jkDebug</b> - JK Loglevel setting.  May be debug, info, error, or emerg.
+                          If not set, defaults to emerg.</li>
+     <li><b>jkWorker</b> The desired worker.  Must be set to one of the workers
+                         defined in the workers.properties file. "ajp12", "ajp13"
+                         or "inprocess" are the workers found in the default
+                         workers.properties file. If not specified, defaults
+                         to "ajp13" if an Ajp13Interceptor is in use, otherwise
+                         it defaults to "ajp12".</li>
+     <li><b>forwardAll</b> - If true, forward all requests to Tomcat. This helps
+                             insure that all the behavior configured in the web.xml
+                             file functions correctly.  If false, let Apache serve
+                             static resources. The default is true.
+                             Warning: When false, some configuration in
+                             the web.xml may not be duplicated in Apache.
+                             Review the mod_jk conf file to see what
+                             configuration is actually being set in Apache.</li>
+     <li><b>noRoot</b> - If true, the root context is not mapped to
+                         Tomcat.  If false and forwardAll is true, all requests
+                         to the root context are mapped to Tomcat. If false and
+                         forwardAll is false, only JSP and servlets requests to
+                         the root context are mapped to Tomcat. When false,
+                         to correctly serve Tomcat's root context you must also
+                         modify the DocumentRoot setting in Apache's httpd.conf
+                         file to point to Tomcat's root context directory.
+                         Otherwise some content, such as Apache's index.html,
+                         will be served by Apache before mod_jk gets a chance
+                         to claim the request and pass it to Tomcat.
+                         The default is true.</li>
+    </ul>
+    <p>
+    @author Costin Manolache
+    @author Larry Isaacs
+    @author Mel Martinez
+    @author Bill Barker
+ */
+public class ApacheConfig  extends BaseJkConfig { 
+
+    private static org.apache.commons.logging.Log log =
+        org.apache.commons.logging.LogFactory.getLog(ApacheConfig.class);
+
+    /** default path to mod_jk .conf location */
+    public static final String MOD_JK_CONFIG = "conf/auto/mod_jk.conf";
+    /** default path to workers.properties file
+	This should be also auto-generated from server.xml.
+    */
+    public static final String WORKERS_CONFIG = "conf/jk/workers.properties";
+    /** default mod_jk log file location */
+    public static final String JK_LOG_LOCATION = "logs/mod_jk.log";
+    /** default location of mod_jk Apache plug-in. */
+    public static final String MOD_JK;
+    
+    //set up some defaults based on OS type
+    static{
+        String os = System.getProperty("os.name").toLowerCase();
+        if(os.indexOf("windows")>=0){ 
+           MOD_JK = "modules/mod_jk.dll";
+        }else if(os.indexOf("netware")>=0){
+           MOD_JK = "modules/mod_jk.nlm";
+        }else{
+           MOD_JK = "libexec/mod_jk.so";
+        }
+    }
+    
+    private File jkConfig = null;
+    private File modJk = null;
+
+    // ssl settings 
+    private boolean sslExtract=true;
+    private String sslHttpsIndicator="HTTPS";
+    private String sslSessionIndicator="SSL_SESSION_ID";
+    private String sslCipherIndicator="SSL_CIPHER";
+    private String sslCertsIndicator="SSL_CLIENT_CERT";
+
+    Hashtable NamedVirtualHosts=null;
+    
+    public ApacheConfig() {
+    }
+
+    //-------------------- Properties --------------------
+
+    /**
+        set the path to the output file for the auto-generated
+        mod_jk configuration file.  If this path is relative
+        then it will be resolved absolutely against
+        the getConfigHome() path.
+        <p>
+        @param path String path to a file
+    */
+    public void setJkConfig(String path){
+	jkConfig= (path==null)?null:new File(path);
+    }
+
+    /**
+        set the path to the mod_jk Apache Module
+        @param path String path to a file
+    */
+    public void setModJk(String path){
+        modJk=( path==null?null:new File(path));
+    }
+
+    /** By default mod_jk is configured to collect SSL information from
+	the apache environment and send it to the Tomcat workers. The
+	problem is that there are many SSL solutions for Apache and as
+	a result the environment variable names may change.
+
+	The following JK related SSL configureation
+	can be used to customize mod_jk's SSL behaviour.
+
+	Should mod_jk send SSL information to Tomact (default is On)
+    */
+    public void setExtractSSL( boolean sslMode ) {
+	this.sslExtract=sslMode;
+    }
+
+    /** What is the indicator for SSL (default is HTTPS)
+     */
+    public void setHttpsIndicator( String s ) {
+	sslHttpsIndicator=s;
+    }
+
+    /**What is the indicator for SSL session (default is SSL_SESSION_ID)
+     */
+    public void setSessionIndicator( String s ) {
+	sslSessionIndicator=s;
+    }
+    
+    /**What is the indicator for client SSL cipher suit (default is SSL_CIPHER)
+     */
+    public void setCipherIndicator( String s ) {
+	sslCipherIndicator=s;
+    }
+
+    /** What is the indicator for the client SSL certificated(default
+	is SSL_CLIENT_CERT
+     */
+    public void setCertsIndicator( String s ) {
+	sslCertsIndicator=s;
+    }
+
+    // -------------------- Initialize/guess defaults --------------------
+
+    /** Initialize defaults for properties that are not set
+	explicitely
+    */
+    protected void initProperties() {
+        super.initProperties();
+
+	jkConfig= getConfigFile( jkConfig, configHome, MOD_JK_CONFIG);
+	workersConfig=getConfigFile( workersConfig, configHome,
+				     WORKERS_CONFIG);
+	if( modJk == null )
+	    modJk=new File(MOD_JK);
+	else
+	    modJk=getConfigFile( modJk, configHome, MOD_JK );
+	jkLog=getConfigFile( jkLog, configHome, JK_LOG_LOCATION);
+    }
+    // -------------------- Generate config --------------------
+    
+    protected PrintWriter getWriter() throws IOException {
+	String abJkConfig = jkConfig.getAbsolutePath();
+	return new PrintWriter(new FileWriter(abJkConfig, append));
+    }
+			       
+
+    // -------------------- Config sections  --------------------
+
+    /** Generate the loadModule and general options
+     */
+    protected boolean generateJkHead(PrintWriter mod_jk)
+    {
+
+	mod_jk.println("########## Auto generated on " +  new Date() +
+		       "##########" );
+	mod_jk.println();
+
+	// Fail if mod_jk not found, let the user know the problem
+	// instead of running into problems later.
+	if( ! modJk.exists() ) {
+	    log.info( "mod_jk location: " + modJk );
+	    log.info( "Make sure it is installed corectly or " +
+		 " set the config location" );
+	    log.info( "Using <Listener className=\""+getClass().getName()+"\"  modJk=\"PATH_TO_MOD_JK.SO_OR_DLL\" />" );
+	}
+            
+	// Verify the file exists !!
+	mod_jk.println("<IfModule !mod_jk.c>");
+	mod_jk.println("  LoadModule jk_module \""+
+		       modJk.toString().replace('\\','/') +
+                       "\"");
+	mod_jk.println("</IfModule>");
+	mod_jk.println();                
+
+	
+	// Fail if workers file not found, let the user know the problem
+	// instead of running into problems later.
+	if( ! workersConfig.exists() ) {
+	    log.warn( "Can't find workers.properties at " + workersConfig );
+	    log.warn( "Please install it in the default location or " +
+		 " set the config location" );
+	    log.warn( "Using <Listener className=\"" + getClass().getName() + "\"  workersConfig=\"FULL_PATH\" />" );
+	    return false;
+	}
+            
+	mod_jk.println("JkWorkersFile \"" 
+		       + workersConfig.toString().replace('\\', '/') 
+		       + "\"");
+
+	mod_jk.println("JkLogFile \"" 
+		       + jkLog.toString().replace('\\', '/') 
+		       + "\"");
+	mod_jk.println();
+
+	if( jkDebug != null ) {
+	    mod_jk.println("JkLogLevel " + jkDebug);
+	    mod_jk.println();
+	}
+	return true;
+    }
+
+    protected void generateVhostHead(Host host, PrintWriter mod_jk) {
+
+        mod_jk.println();
+        String vhostip = host.getName();
+	String vhost = vhostip;
+	int ppos = vhost.indexOf(":");
+	if(ppos >= 0)
+	    vhost = vhost.substring(0,ppos);
+
+        mod_jk.println("<VirtualHost "+ vhostip + ">");
+        mod_jk.println("    ServerName " + vhost );
+        String [] aliases=host.findAliases();
+        if( aliases.length > 0 ) {
+            mod_jk.print("    ServerAlias " );
+            for( int ii=0; ii < aliases.length ; ii++) {
+                mod_jk.print( aliases[ii] + " " );
+            }
+            mod_jk.println();
+        }
+        indent="    ";
+    }
+
+    protected void generateVhostTail(Host host, PrintWriter mod_jk) {
+        mod_jk.println("</VirtualHost>");
+        indent="";
+    }
+    
+    protected void generateSSLConfig(PrintWriter mod_jk) {
+	if( ! sslExtract ) {
+	    mod_jk.println("JkExtractSSL Off");        
+	}
+	if( ! "HTTPS".equalsIgnoreCase( sslHttpsIndicator ) ) {
+	    mod_jk.println("JkHTTPSIndicator " + sslHttpsIndicator);        
+	}
+	if( ! "SSL_SESSION_ID".equalsIgnoreCase( sslSessionIndicator )) {
+	    mod_jk.println("JkSESSIONIndicator " + sslSessionIndicator);
+	}
+	if( ! "SSL_CIPHER".equalsIgnoreCase( sslCipherIndicator )) {
+	    mod_jk.println("JkCIPHERIndicator " + sslCipherIndicator);
+	}
+	if( ! "SSL_CLIENT_CERT".equalsIgnoreCase( sslCertsIndicator )) {
+	    mod_jk.println("JkCERTSIndicator " + sslCertsIndicator);
+	}
+
+	mod_jk.println();
+    }
+
+    // -------------------- Forward all mode --------------------
+    String indent="";
+    
+    /** Forward all requests for a context to tomcat.
+	The default.
+     */
+    protected void generateStupidMappings(Context context,
+					   PrintWriter mod_jk )
+    {
+	String ctxPath  = context.getPath();
+	if(ctxPath == null)
+	    return;
+
+	String nPath=("".equals(ctxPath)) ? "/" : ctxPath;
+	
+        mod_jk.println();
+	mod_jk.println(indent + "JkMount " +  nPath + " " + jkWorker );
+	if( "".equals(ctxPath) ) {
+	    mod_jk.println(indent + "JkMount " +  nPath + "* " + jkWorker );
+            if ( context.getParent() instanceof Host ) {
+                mod_jk.println(indent + "DocumentRoot \"" +
+                            getApacheDocBase(context) + "\"");
+            } else {
+                mod_jk.println(indent +
+                        "# To avoid Apache serving root welcome files from htdocs, update DocumentRoot");
+                mod_jk.println(indent +
+                        "# to point to: \"" + getApacheDocBase(context) + "\"");
+            }
+
+	} else {
+	    mod_jk.println(indent + "JkMount " +  nPath + "/* " + jkWorker );
+	}
+    }    
+
+    
+    private void generateNameVirtualHost( PrintWriter mod_jk, String ip ) {
+        if( !NamedVirtualHosts.containsKey(ip) ) {
+            mod_jk.println("NameVirtualHost " + ip + "");
+            NamedVirtualHosts.put(ip,ip);
+        }
+    }
+    
+    // -------------------- Apache serves static mode --------------------
+    // This is not going to work for all apps. We fall back to stupid mode.
+    
+    protected void generateContextMappings(Context context, PrintWriter mod_jk )
+    {
+	String ctxPath  = context.getPath();
+	Host vhost = getHost(context);
+
+        if( noRoot &&  "".equals(ctxPath) ) {
+            log.debug("Ignoring root context in non-forward-all mode  ");
+            return;
+        }
+
+	mod_jk.println();
+	mod_jk.println(indent + "#################### " +
+		       ((vhost!=null ) ? vhost.getName() + ":" : "" ) +
+		       (("".equals(ctxPath)) ? "/" : ctxPath ) +
+		       " ####################" );
+        mod_jk.println();
+	// Dynamic /servet pages go to Tomcat
+ 
+	generateStaticMappings( context, mod_jk );
+
+	// InvokerInterceptor - it doesn't have a container,
+	// but it's implemented using a special module.
+	
+	// XXX we need to better collect all mappings
+
+	if(context.getLoginConfig() != null) {
+	    String loginPage = context.getLoginConfig().getLoginPage();
+	    if(loginPage != null) {
+		int lpos = loginPage.lastIndexOf("/");
+		String jscurl = loginPage.substring(0,lpos+1) + "j_security_check";
+		addMapping( ctxPath, jscurl, mod_jk);
+	    }
+	}
+	String [] servletMaps = context.findServletMappings();
+	for(int ii=0; ii < servletMaps.length; ii++) {
+	      addMapping( ctxPath, servletMaps[ii] , mod_jk );
+	}
+    }
+
+    /** Add an Apache extension mapping.
+     */
+    protected boolean addExtensionMapping( String ctxPath, String ext,
+					 PrintWriter mod_jk )
+    {
+        if( log.isDebugEnabled() )
+            log.debug( "Adding extension map for " + ctxPath + "/*." + ext );
+	mod_jk.println(indent + "JkMount " + ctxPath + "/*." + ext
+		       + " " + jkWorker);
+	return true;
+    }
+    
+    
+    /** Add a fulling specified Appache mapping.
+     */
+    protected boolean addMapping( String fullPath, PrintWriter mod_jk ) {
+        if( log.isDebugEnabled() )
+            log.debug( "Adding map for " + fullPath );
+	mod_jk.println(indent + "JkMount " + fullPath + "  " + jkWorker );
+	return true;
+    }
+    /** Add a partially specified Appache mapping.
+     */
+    protected boolean addMapping( String ctxP, String ext, PrintWriter mod_jk ) {
+        if( log.isDebugEnabled() )
+            log.debug( "Adding map for " + ext );
+	if(! ext.startsWith("/") )
+	    ext = "/" + ext;
+	if(ext.length() > 1)
+	    mod_jk.println(indent + "JkMount " + ctxP + ext+ "  " + jkWorker );
+	return true;
+    }
+
+    private void generateWelcomeFiles(Context context, PrintWriter mod_jk ) {
+	String wf[]=context.findWelcomeFiles();
+	if( wf==null || wf.length == 0 )
+	    return;
+	mod_jk.print(indent + "    DirectoryIndex ");
+	for( int i=0; i<wf.length ; i++ ) {
+	    mod_jk.print( wf[i] + " " );
+	}
+	mod_jk.println();
+    }
+
+    /** Mappings for static content. XXX need to add welcome files,
+     *  mime mappings ( all will be handled by Mime and Static modules of
+     *  apache ).
+     */
+    private void generateStaticMappings(Context context, PrintWriter mod_jk ) {
+	String ctxPath  = context.getPath();
+
+	// Calculate the absolute path of the document base
+	String docBase = getApacheDocBase(context);
+
+        if( !"".equals(ctxPath) ) {
+            // Static files will be served by Apache
+            mod_jk.println(indent + "# Static files ");		    
+            mod_jk.println(indent + "Alias " + ctxPath + " \"" + docBase + "\"");
+            mod_jk.println();
+        } else {
+            if ( getHost(context) != null ) {
+                mod_jk.println(indent + "DocumentRoot \"" +
+                            getApacheDocBase(context) + "\"");
+            } else {
+                // For root context, ask user to update DocumentRoot setting.
+                // Using "Alias / " interferes with the Alias for other contexts.
+                mod_jk.println(indent +
+                        "# Be sure to update DocumentRoot");
+                mod_jk.println(indent +
+                        "# to point to: \"" + docBase + "\"");
+            }
+        }
+	mod_jk.println(indent + "<Directory \"" + docBase + "\">");
+	mod_jk.println(indent + "    Options Indexes FollowSymLinks");
+
+	generateWelcomeFiles(context, mod_jk);
+
+	// XXX XXX Here goes the Mime types and welcome files !!!!!!!!
+	mod_jk.println(indent + "</Directory>");
+	mod_jk.println();            
+	
+
+	// Deny serving any files from WEB-INF
+	mod_jk.println();            
+	mod_jk.println(indent +
+		       "# Deny direct access to WEB-INF and META-INF");
+	mod_jk.println(indent + "#");                        
+	mod_jk.println(indent + "<Location \"" + ctxPath + "/WEB-INF/*\">");
+	mod_jk.println(indent + "    AllowOverride None");
+	mod_jk.println(indent + "    deny from all");
+	mod_jk.println(indent + "</Location>");
+	// Deny serving any files from META-INF
+	mod_jk.println();            
+	mod_jk.println(indent + "<Location \"" + ctxPath + "/META-INF/*\">");
+	mod_jk.println(indent + "    AllowOverride None");
+	mod_jk.println(indent + "    deny from all");
+	mod_jk.println(indent + "</Location>");
+	if (File.separatorChar == '\\') {
+	    mod_jk.println(indent + "#");		    
+	    mod_jk.println(indent +
+			   "# Use Directory too. On Windows, Location doesn't"
+			   + " work unless case matches");
+	    mod_jk.println(indent + "#");                        
+	    mod_jk.println(indent +
+			   "<Directory \"" + docBase + "/WEB-INF/\">");
+	    mod_jk.println(indent + "    AllowOverride None");
+	    mod_jk.println(indent + "    deny from all");
+	    mod_jk.println(indent + "</Directory>");
+	    mod_jk.println();
+	    mod_jk.println(indent +
+			   "<Directory \"" + docBase + "/META-INF/\">");
+	    mod_jk.println(indent + "    AllowOverride None");
+	    mod_jk.println(indent + "    deny from all");
+	    mod_jk.println(indent + "</Directory>");
+	}
+	mod_jk.println();
+    }    
+
+    // -------------------- Utils --------------------
+
+    private String getApacheDocBase(Context context)
+    {
+	// Calculate the absolute path of the document base
+	String docBase = getAbsoluteDocBase(context);
+	if (File.separatorChar == '\\') {
+	    // use separator preferred by Apache
+	    docBase = docBase.replace('\\','/');
+	}
+        return docBase;
+    }
+
+    private String getVirtualHostAddress(String vhost, String vhostip) {
+        if( vhostip == null ) {
+            if ( vhost != null && vhost.length() > 0 && Character.isDigit(vhost.charAt(0)) )
+                vhostip=vhost;
+            else
+                vhostip="*";
+        }
+        return vhostip;
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/config/BaseJkConfig.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/config/BaseJkConfig.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/config/BaseJkConfig.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,515 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.jk.config;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.PrintWriter;
+
+import org.apache.catalina.Container;
+import org.apache.catalina.Context;
+import org.apache.catalina.Engine;
+import org.apache.catalina.Host;
+import org.apache.catalina.Lifecycle;
+import org.apache.catalina.LifecycleEvent;
+import org.apache.catalina.LifecycleListener;
+import org.apache.catalina.Server;
+
+
+/**
+    Base class for automatic jk based configurations based on
+    the Tomcat server.xml settings and the war contexts
+    initialized during startup.
+    <p>
+    This config interceptor is enabled by inserting a Config
+    element in the <b>&lt;ContextManager&gt;</b> tag body inside
+    the server.xml file like so:
+    <pre>
+    * < ContextManager ... >
+    *   ...
+    *   <<b>???Config</b> <i>options</i> />
+    *   ...
+    * < /ContextManager >
+    </pre>
+    where <i>options</i> can include any of the following attributes:
+    <ul>
+     <li><b>configHome</b> - default parent directory for the following paths.
+                             If not set, this defaults to TOMCAT_HOME. Ignored
+                             whenever any of the following paths is absolute.
+                             </li>
+     <li><b>workersConfig</b> - path to workers.properties file used by 
+                                jk connector. If not set, defaults to
+                                "conf/jk/workers.properties".</li>
+     <li><b>jkLog</b> - path to log file to be used by jk connector.</li>
+     <li><b>jkDebug</b> - Loglevel setting.  May be debug, info, error, or emerg.
+                          If not set, defaults to emerg.</li>
+     <li><b>jkWorker</b> The desired worker.  Must be set to one of the workers
+                         defined in the workers.properties file. "ajp12", "ajp13"
+                         or "inprocess" are the workers found in the default
+                         workers.properties file. If not specified, defaults
+                         to "ajp13" if an Ajp13Interceptor is in use, otherwise
+                         it defaults to "ajp12".</li>
+     <li><b>forwardAll</b> - If true, forward all requests to Tomcat. This helps
+                             insure that all the behavior configured in the web.xml
+                             file functions correctly.  If false, let Apache serve
+                             static resources. The default is true.
+                             Warning: When false, some configuration in
+                             the web.xml may not be duplicated in Apache.
+                             Review the mod_jk conf file to see what
+                             configuration is actually being set in Apache.</li>
+     <li><b>noRoot</b> - If true, the root context is not mapped to
+                         Tomcat.  If false and forwardAll is true, all requests
+                         to the root context are mapped to Tomcat. If false and
+                         forwardAll is false, only JSP and servlets requests to
+                         the root context are mapped to Tomcat. When false,
+                         to correctly serve Tomcat's root context you may also
+                         need to modify the web server to point it's home
+                         directory to Tomcat's root context directory.
+                         Otherwise some content, such as the root index.html,
+                         may be served by the web server before the connector
+                         gets a chance to claim the request and pass it to Tomcat.
+                         The default is true.</li>
+    </ul>
+    <p>
+    @author Costin Manolache
+    @author Larry Isaacs
+    @author Bill Barker
+        @version $Revision: 299988 $
+ */
+public class BaseJkConfig  implements LifecycleListener {
+    private static org.apache.commons.logging.Log log =
+        org.apache.commons.logging.LogFactory.getLog(BaseJkConfig.class);
+
+    protected File configHome = null;
+    protected File workersConfig = null;
+
+    protected File jkLog = null;
+    protected String jkDebug="emerg";
+    protected String jkWorker = "ajp13";
+
+    protected boolean noRoot=true;
+    protected boolean forwardAll=true;
+
+    protected String tomcatHome;
+    protected boolean regenerate=false;
+    protected boolean append=false;
+    protected boolean legacy=true;
+
+    // -------------------- Tomcat callbacks --------------------
+
+
+    // Auto-config should be able to react to dynamic config changes,
+    // and regenerate the config.
+
+    /** 
+     *  Generate the configuration - only when the server is
+     *  completely initialized ( before starting )
+     */
+    public void lifecycleEvent(LifecycleEvent evt) {
+        if(Lifecycle.START_EVENT.equals(evt.getType())) {
+           execute( evt );
+        } 
+    }
+
+    /** 
+     *  Generate configuration files.  Override with method to generate
+     *  web server specific configuration.
+     */
+    public void execute(LifecycleEvent evt) {
+        initProperties();
+        PrintWriter mod_jk = null;
+        try {
+            mod_jk = getWriter();
+        } catch(IOException iex) {
+            log.warn("Unable to open config file");
+            return;
+        }
+        Lifecycle who = evt.getLifecycle();
+        if( who instanceof Server ) {
+            executeServer((Server)who, mod_jk);
+        } else if(who instanceof Engine) {
+            executeEngine((Engine)who, mod_jk);
+        } else if ( who instanceof Host ) {
+            executeHost((Host)who, mod_jk);
+        } else if( who instanceof Context ) {
+            executeContext((Context)who, mod_jk);
+        }
+        mod_jk.close();
+    }
+    /** 
+     *  Generate configuration files.  Override with method to generate
+     *  web server specific configuration.
+     */
+    public void executeServer(Server svr, PrintWriter mod_jk) {
+        if(! append ) {
+            if( ! generateJkHead(mod_jk) )
+                return;
+            generateSSLConfig(mod_jk);
+            generateJkTail(mod_jk);
+        }
+    }
+
+    /** 
+     * Generate SSL options
+     */
+    protected void generateSSLConfig(PrintWriter mod_jk) {
+    }
+
+    /** 
+     * Generate general options
+     */
+    protected boolean generateJkHead(PrintWriter mod_jk)  {
+        return true;
+    }
+
+    /** 
+     * Generate general options
+     */
+    protected void generateJkTail(PrintWriter mod_jk) {
+    }
+
+    /** 
+     * Generate Virtual Host start
+     */
+    protected void generateVhostHead(Host host, PrintWriter mod_jk) {
+    }
+
+    /** 
+     * Generate Virtual Host end
+     */
+    protected void generateVhostTail(Host host, PrintWriter mod_jk) {
+    }
+
+    /** 
+     *  Generate configuration files.  Override with method to generate
+     *  web server specific configuration.
+     */
+    protected void executeEngine(Engine egn, PrintWriter mod_jk) {
+        if(egn.getJvmRoute() != null) {
+            jkWorker = egn.getJvmRoute();
+        }
+        executeServer(egn.getService().getServer(), mod_jk);
+        Container [] children = egn.findChildren();
+        for(int ii=0; ii < children.length; ii++) {
+            if( children[ii] instanceof Host ) {
+                executeHost((Host)children[ii], mod_jk);
+            } else if( children[ii] instanceof Context ) {
+                executeContext((Context)children[ii], mod_jk);
+            }
+        }
+    }
+    /**
+     *  Generate configuration files.  Override with method to generate
+     *  web server specific configuration.
+     */
+    protected void executeHost(Host hst, PrintWriter mod_jk) {
+        generateVhostHead(hst, mod_jk);
+        Container [] children = hst.findChildren();
+        for(int ii=0; ii < children.length; ii++) {
+            if(children[ii] instanceof Context) {
+                executeContext((Context)children[ii],mod_jk);
+            }
+        }
+        generateVhostTail(hst, mod_jk);
+    }
+    /**
+     *   executes the ApacheConfig interceptor. This method generates apache
+     *   configuration files for use with  mod_jk.
+     *   @param context a Context object.
+     *   @param mod_jk Writer for output.
+    */
+    public void executeContext(Context context, PrintWriter mod_jk){
+
+        if(context.getPath().length() > 0 || ! noRoot ) {
+            String docRoot = context.getServletContext().getRealPath("/");
+            if( forwardAll || docRoot == null)
+                generateStupidMappings( context, mod_jk );
+            else
+                generateContextMappings( context, mod_jk);
+        }
+    }
+
+    protected void generateStupidMappings(Context context, PrintWriter mod_jk){
+    }
+    protected void generateContextMappings(Context context, PrintWriter mod_jk){
+    }
+
+    /** 
+     *  Get the output Writer.  Override with method to generate
+     *  web server specific configuration.
+     */
+    protected PrintWriter getWriter() throws IOException {
+        return null;
+    }
+
+    /** 
+     * Get the host associated with this Container (if any).
+     */
+    protected Host getHost(Container child) {
+        while(child != null && ! (child instanceof Host) ) {
+            child = child.getParent();
+        }
+        return (Host)child;
+    }
+
+    //-------------------- Properties --------------------
+
+    /** 
+     *  Append to config file.
+     *  Set to <code>true</code> if the config information should be 
+     *  appended.
+     */
+    public void setAppend(boolean apnd) {
+        append = apnd;
+    }
+
+    /** 
+     *  If false, we'll try to generate a config that will
+     *  let apache serve static files.
+     *  The default is true, forward all requests in a context
+     *  to tomcat.
+     */
+    public void setForwardAll( boolean b ) {
+        forwardAll=b;
+    }
+
+    /** 
+     *  Special option - do not generate mappings for the ROOT
+     *  context. The default is true, and will not generate the mappings,
+     *  not redirecting all pages to tomcat (since /* matches everything).
+     *  This means that the web server's root remains intact but isn't
+     *  completely servlet/JSP enabled. If the ROOT webapp can be configured
+     *  with the web server serving static files, there's no problem setting
+     *   this option to false. If not, then setting it true means the web
+     *   server will be out of picture for all requests.
+     */
+    public void setNoRoot( boolean b ) {
+        noRoot=b;
+    }
+    
+    /**
+     *  set a path to the parent directory of the
+     *  conf folder.  That is, the parent directory
+     *  within which path setters would be resolved against,
+     *  if relative.  For example if ConfigHome is set to "/home/tomcat"
+     *  and regConfig is set to "conf/mod_jk.conf" then the resulting 
+     *  path used would be: 
+     *  "/home/tomcat/conf/mod_jk.conf".</p>
+     *  <p>
+     *  However, if the path is set to an absolute path,
+     *  this attribute is ignored.
+     *  <p>
+     *  If not set, execute() will set this to TOMCAT_HOME.
+     *  @param dir - path to a directory
+     */
+    public void setConfigHome(String dir){
+        if( dir==null ) return;
+        File f=new File(dir);
+        if(!f.isDirectory()){
+            throw new IllegalArgumentException(
+                "BaseConfig.setConfigHome(): "+
+                "Configuration Home must be a directory! : "+dir);
+        }
+        configHome = f;
+    }
+
+    /**
+     *  set a path to the workers.properties file.
+     *  @param path String path to workers.properties file
+     */
+    public void setWorkersConfig(String path){
+        workersConfig= (path==null?null:new File(path));
+    }
+
+    /**
+     *  set the path to the log file
+     *   @param path String path to a file
+     */
+    public void setJkLog(String path){
+        jkLog = ( path==null ? null : new File(path));
+    }
+
+    /** 
+     *  Set the verbosity level
+     *  ( use debug, error, etc. ) If not set, no log is written.
+     */
+    public void setJkDebug( String level ) {
+        jkDebug=level;
+    }
+
+    /**
+     *   Sets the JK worker.
+     *   @param worker The worker
+     */
+    public void setJkWorker(String worker){
+        jkWorker = worker;
+    }
+
+    public void setLegacy(boolean legacy) {
+        this.legacy = legacy;
+    }
+
+    // -------------------- Initialize/guess defaults --------------------
+
+    /** 
+     *  Initialize defaults for properties that are not set
+     *   explicitely
+     */
+    protected void initProperties() {
+        tomcatHome = System.getProperty("catalina.home");
+        File tomcatDir = new File(tomcatHome);
+        if(configHome==null){
+            configHome=tomcatDir;
+        }
+    }
+
+    // -------------------- Config Utils  --------------------
+
+
+    /** 
+     * Add an extension mapping. Override with method to generate
+     *   web server specific configuration
+     */
+    protected boolean addExtensionMapping( String ctxPath, String ext,
+                                         PrintWriter pw ) {
+        return true;
+    }
+    
+    
+    /** 
+     * Add a fulling specified mapping.  Override with method to generate
+     * web server specific configuration
+     */
+    protected boolean addMapping( String fullPath, PrintWriter pw ) {
+        return true;
+    }
+
+    // -------------------- General Utils --------------------
+
+    protected String getAbsoluteDocBase(Context context) {
+        // Calculate the absolute path of the document base
+        String docBase = context.getServletContext().getRealPath("/");
+        docBase = docBase.substring(0,docBase.length()-1);
+        if (!isAbsolute(docBase)){
+            docBase = tomcatHome + "/" + docBase;
+        }
+        docBase = patch(docBase);
+        return docBase;
+    }
+
+    // ------------------ Grabbed from FileUtil -----------------
+    public static File getConfigFile( File base, File configDir, String defaultF )
+    {
+        if( base==null )
+            base=new File( defaultF );
+        if( ! base.isAbsolute() ) {
+            if( configDir != null )
+                base=new File( configDir, base.getPath());
+            else
+                base=new File( base.getAbsolutePath()); //??
+        }
+        File parent=new File(base.getParent());
+        if(!parent.exists()){
+            if(!parent.mkdirs()){
+                throw new RuntimeException(
+                    "Unable to create path to config file :"+
+                    base.getAbsolutePath());
+            }
+        }
+        return base;
+    }
+
+    public static String patch(String path) {
+        String patchPath = path;
+
+        // Move drive spec to the front of the path
+        if (patchPath.length() >= 3 &&
+            patchPath.charAt(0) == '/'  &&
+            Character.isLetter(patchPath.charAt(1)) &&
+            patchPath.charAt(2) == ':') {
+            patchPath=patchPath.substring(1,3)+"/"+patchPath.substring(3);
+        }
+
+        // Eliminate consecutive slashes after the drive spec
+        if (patchPath.length() >= 2 &&
+            Character.isLetter(patchPath.charAt(0)) &&
+            patchPath.charAt(1) == ':') {
+            char[] ca = patchPath.replace('/', '\\').toCharArray();
+            char c;
+            StringBuffer sb = new StringBuffer();
+
+            for (int i = 0; i < ca.length; i++) {
+                if ((ca[i] != '\\') ||
+                    (ca[i] == '\\' &&
+                        i > 0 &&
+                        ca[i - 1] != '\\')) {
+                    if (i == 0 &&
+                        Character.isLetter(ca[i]) &&
+                        i < ca.length - 1 &&
+                        ca[i + 1] == ':') {
+                        c = Character.toUpperCase(ca[i]);
+                    } else {
+                        c = ca[i];
+                    }
+
+                    sb.append(c);
+                }
+            }
+
+            patchPath = sb.toString();
+        }
+
+        // fix path on NetWare - all '/' become '\\' and remove duplicate '\\'
+        if (System.getProperty("os.name").startsWith("NetWare") &&
+            path.length() >=3 &&
+            path.indexOf(':') > 0) {
+            char[] ca = patchPath.replace('/', '\\').toCharArray();
+            StringBuffer sb = new StringBuffer();
+
+            for (int i = 0; i < ca.length; i++) {
+                if ((ca[i] != '\\') ||
+                    (ca[i] == '\\' && i > 0 && ca[i - 1] != '\\')) {
+                    sb.append(ca[i]);
+                }
+            }
+            patchPath = sb.toString();
+        }
+
+        return patchPath;
+    }
+
+    public static boolean isAbsolute( String path ) {
+        // normal file
+        if( path.startsWith("/" ) ) return true;
+
+        if( path.startsWith(File.separator ) ) return true;
+
+        // win c:
+        if (path.length() >= 3 &&
+            Character.isLetter(path.charAt(0)) &&
+            path.charAt(1) == ':')
+            return true;
+
+        // NetWare volume:
+        if (System.getProperty("os.name").startsWith("NetWare") &&
+            path.length() >=3 &&
+            path.indexOf(':') > 0)
+            return true;
+
+        return false;
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/config/GeneratorApache2.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/config/GeneratorApache2.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/config/GeneratorApache2.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,193 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.jk.config;
+
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.Vector;
+
+import org.w3c.dom.Node;
+
+
+/* Naming conventions:
+
+JK_CONF_DIR == serverRoot/work  ( XXX /jkConfig ? )
+
+- Each vhost has a sub-dir named after the canonycal name
+
+- For each webapp in a vhost, there is a separate WEBAPP_NAME.jkmap
+
+- In httpd.conf ( or equivalent servers ), in each virtual host you
+should "Include JK_CONF_DIR/VHOST/jk_apache.conf". The config
+file will contain the Alias declarations and other rules required
+for apache operation. Same for other servers. 
+
+- WebXml2Jk will be invoked by a config tool or automatically for each
+webapp - it'll generate the WEBAPP.jkmap files and config fragments.
+
+WebXml2Jk will _not_ generate anything else but mappings.
+It should _not_ try to guess locations or anything else - that's
+another components' job.
+
+*/
+
+/**
+ *
+ * @author Costin Manolache
+ */
+public class GeneratorApache2 implements WebXml2Jk.MappingGenerator {
+    WebXml2Jk wxml;
+    String vhost;
+    String cpath;
+    String worker;
+    PrintWriter out;
+    
+    public void setWebXmlReader(WebXml2Jk wxml ) {
+        this.wxml=wxml;
+        vhost=wxml.vhost;
+        cpath=wxml.cpath;
+        worker=wxml.worker;
+    }
+
+    public void generateStart() throws IOException {
+        File base=wxml.getJkDir();
+        File outF=new File(base, "jk2.conf");
+        out=new PrintWriter( new FileWriter( outF ));
+
+        out.println("# Must be included in a virtual host context for " + vhost );
+
+        out.println("Alias " + cpath + " \"" + wxml.docBase + "\"");
+        out.println("<Directory \"" + wxml.docBase + "\" >");
+        out.println("  Options Indexes FollowSymLinks");
+        generateMimeMapping( out );
+        generateWelcomeFiles( out);
+
+        // If we use this instead of extension mapping for jsp we can avoid most
+        // jsp security problems.
+        out.println("  AddHandler jakarta-servlet2 .jsp");
+        out.println("</Directory>");
+        out.println();
+        
+        out.println("<Location \"" + cpath + "/WEB-INF\" >");
+        out.println("  AllowOverride None");
+        out.println("  Deny from all");
+        out.println("</Location>");
+        out.println();
+        out.println("<Location \"" + cpath + "/META-INF\" >");
+        out.println("  AllowOverride None");
+        out.println("  Deny from all");
+        out.println("</Location>");
+        out.println();
+    }
+
+    private void generateWelcomeFiles( PrintWriter out ) {
+        Vector wf= wxml.getWellcomeFiles();
+        out.print("  DirectoryIndex ");
+        for( int i=0; i<wf.size(); i++ ) {
+            out.print( " " + (String)wf.elementAt(i));
+        }
+        out.println();
+    }
+    
+    private void generateMimeMapping( PrintWriter out ) {
+        Node webN=wxml.getWebXmlNode();
+        for( Node mapN=WebXml2Jk.getChild( webN, "mime-mapping" );
+             mapN != null; mapN = WebXml2Jk.getNext( mapN ) ) {
+            String ext=WebXml2Jk.getChildContent( mapN, "extension" );
+            String type=WebXml2Jk.getChildContent( mapN, "mime-type" );
+
+            out.println("  AddType " + type + " " + ext );
+        }
+        
+
+    }
+
+    public void generateEnd() {
+        out.close();
+    }
+    
+    public void generateServletMapping( String servlet, String url ) {
+        out.println( "<Location \"" + cpath + url + "\" >");
+        out.println( "  SetHandler jakarta-servlet2" );
+        out.println( "  JkUriSet group " + worker );
+        out.println( "  JkUriSet servlet " +  servlet);
+        out.println( "  JkUriSet host " +  vhost );
+        out.println( "  JkUriSet context " +  cpath );
+        out.println( "</Location>");
+        out.println();
+    }
+
+    public void generateFilterMapping( String servlet, String url ) {
+        out.println( "<Location \"" + cpath + url + "\" >");
+        out.println( "  SetHandler jakarta-servlet2" );
+        out.println( "  JkUriSet group " + worker );
+        out.println( "  JkUriSet servlet " +  servlet);
+        out.println( "  JkUriSet host " +  vhost );
+        out.println( "  JkUriSet context " +  cpath );
+        out.println( "</Location>");
+        out.println();
+    }
+
+    public void generateLoginConfig( String loginPage,
+                                     String errPage, String authM ) {
+        out.println( "<Location \"" + cpath + loginPage + "\" >");
+        out.println( "  SetHandler jakarta-servlet2" );
+        out.println( "  JkUriSet group " + worker );
+        out.println( "  JkUriSet host " +  vhost );
+        out.println( "  JkUriSet context " +  cpath );
+        out.println( "</Location>");
+        out.println();
+    }
+
+    public void generateErrorPage( int err, String location ) {
+        
+    }
+
+    // XXX Only if BASIC/DIGEST and 'integrated auth'
+    public void generateConstraints( Vector urls, Vector methods, Vector roles, boolean isSSL ) {
+        for( int i=0; i<urls.size(); i++ ) {
+            String url=(String)urls.elementAt(i);
+
+            out.println( "<Location \"" + cpath + url + "\" >");
+
+            if( methods.size() > 0 ) {
+                out.print("  <Limit ");
+                for( int j=0; j<methods.size(); j++ ) {
+                    String m=(String)methods.elementAt(j);
+                    out.print( " " +  m);
+                }
+                out.println(  " >" );
+            }
+
+            out.println( "    AuthType basic" );
+            out.print( "    Require group " );
+            for( int j=0; j<roles.size(); j++ ) {
+                String role=(String)roles.elementAt(j);
+                out.print( " " +  role);
+            }
+            out.println();
+
+            if( methods.size() > 0 ) {
+                out.println("  </Limit>");
+            }
+            
+            out.println( "</Location>");
+        }
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/config/GeneratorJk1.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/config/GeneratorJk1.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/config/GeneratorJk1.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,112 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.jk.config;
+
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.Vector;
+
+
+/* Naming conventions:
+
+JK_CONF_DIR == serverRoot/work  ( XXX /jkConfig ? )
+
+- Each vhost has a sub-dir named after the canonycal name
+
+- For each webapp in a vhost, there is a separate WEBAPP_NAME.jkmap
+
+- In httpd.conf ( or equivalent servers ), in each virtual host you
+should "Include JK_CONF_DIR/VHOST/jk_apache.conf". The config
+file will contain the Alias declarations and other rules required
+for apache operation. Same for other servers. 
+
+- WebXml2Jk will be invoked by a config tool or automatically for each
+webapp - it'll generate the WEBAPP.jkmap files and config fragments.
+
+WebXml2Jk will _not_ generate anything else but mappings.
+It should _not_ try to guess locations or anything else - that's
+another components' job.
+
+*/
+
+/**
+ *
+ * @author Costin Manolache
+ */
+public class GeneratorJk1 implements WebXml2Jk.MappingGenerator {
+    WebXml2Jk wxml;
+    String vhost;
+    String cpath;
+    String worker;
+    PrintWriter out;
+    
+    public void setWebXmlReader(WebXml2Jk wxml ) {
+        this.wxml=wxml;
+        vhost=wxml.vhost;
+        cpath=wxml.cpath;
+        worker=wxml.worker;
+    }
+
+    public void generateStart( ) throws IOException  {
+        File base=wxml.getJkDir();
+        File outF=new File(base, "jk.conf");
+        out=new PrintWriter( new FileWriter( outF ));
+        
+        out.println("# This must be included in the virtual host section for " + vhost );
+    }
+
+    public void generateEnd() {
+        out.close();
+    }
+
+    
+    public void generateServletMapping( String servlet, String url ) {
+        out.println( "JkMount " + cpath + url + " " + worker);
+    }
+
+    public void generateFilterMapping( String servlet, String url ) {
+        out.println( "JkMount " + cpath + url + " " + worker);
+    }
+
+    public void generateLoginConfig( String loginPage,
+                                        String errPage, String authM ) {
+        out.println( "JkMount " + cpath + loginPage + " " + worker);
+    }
+
+    public void generateErrorPage( int err, String location ) {
+
+    }
+
+    public void generateMimeMapping( String ext, String type ) {
+
+    }
+    
+    public void generateWelcomeFiles( Vector wf ) {
+
+    }
+                                            
+    
+    public void generateConstraints( Vector urls, Vector methods, Vector roles, boolean isSSL ) {
+        for( int i=0; i<urls.size(); i++ ) {
+            String url=(String)urls.elementAt(i);
+
+            out.println( "JkMount " + cpath + url + " " + worker);
+        }
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/config/GeneratorJk2.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/config/GeneratorJk2.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/config/GeneratorJk2.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,143 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.jk.config;
+
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.Vector;
+
+
+/* Naming conventions:
+
+JK_CONF_DIR == serverRoot/work  ( XXX /jkConfig ? )
+
+- Each vhost has a sub-dir named after the canonycal name
+
+- For each webapp in a vhost, there is a separate WEBAPP_NAME.jkmap
+
+- In httpd.conf ( or equivalent servers ), in each virtual host you
+should "Include JK_CONF_DIR/VHOST/jk_apache.conf". The config
+file will contain the Alias declarations and other rules required
+for apache operation. Same for other servers. 
+
+- WebXml2Jk will be invoked by a config tool or automatically for each
+webapp - it'll generate the WEBAPP.jkmap files and config fragments.
+
+WebXml2Jk will _not_ generate anything else but mappings.
+It should _not_ try to guess locations or anything else - that's
+another components' job.
+
+*/
+
+/**
+ *
+ * @author Costin Manolache
+ */
+public class GeneratorJk2 implements WebXml2Jk.MappingGenerator {
+    WebXml2Jk wxml;
+    String vhost;
+    String cpath;
+    String worker;
+    PrintWriter out;
+    
+    public void setWebXmlReader(WebXml2Jk wxml ) {
+        this.wxml=wxml;
+        vhost=wxml.vhost;
+        cpath=wxml.cpath;
+        worker=wxml.worker;
+    }
+
+    public void generateStart( ) throws IOException {
+        File base=wxml.getJkDir();
+        File outF=new File(base, "jk2map.properties");
+        out=new PrintWriter( new FileWriter( outF ));
+
+        out.println("# Autogenerated from web.xml" );
+    }
+
+    public void generateEnd() {
+        out.close();
+    }
+    
+    public void generateServletMapping( String servlet, String url ) {
+        out.println( "[uri:" + vhost + cpath + url + "]");
+        out.println( "group=" + worker );
+        out.println( "servlet=" +  servlet);
+        out.println( "host=" +  vhost); 
+        out.println( "context=" +  cpath);
+        out.println();
+    }
+
+    public void generateFilterMapping( String servlet, String url ) {
+        out.println( "[url:" + vhost + cpath + url + "]");
+        out.println( "group=" + worker );
+        out.println( "filter=" +  servlet);
+        out.println( "host=" +  vhost); 
+        out.println( "context=" +  cpath);
+        out.println();
+    }
+
+    public void generateLoginConfig( String loginPage,
+                                        String errPage, String authM ) {
+        out.println("[url:" + vhost + cpath + loginPage  + "]" );
+        out.println( "group=" + worker );
+        out.println( "host=" +  vhost); 
+        out.println( "context=" +  cpath);
+        out.println();
+        out.println("[url:" + vhost + cpath + errPage  + "]" );
+        out.println( "group=" + worker );
+        out.println( "host=" +  vhost); 
+        out.println( "context=" +  cpath);
+        out.println();
+    }
+
+    public void generateErrorPage( int err, String location ) {
+
+    }
+
+    public void generateMimeMapping( String ext, String type ) {
+
+    }
+    
+    public void generateWelcomeFiles( Vector wf ) {
+
+    }
+                                            
+    
+    public void generateConstraints( Vector urls, Vector methods, Vector roles, boolean isSSL ) {
+        for( int i=0; i<urls.size(); i++ ) {
+            String url=(String)urls.elementAt(i);
+
+            out.println("[url:" + vhost + cpath + url + "]");
+            out.println( "group=" + worker );
+            out.println( "host=" +  vhost); 
+            out.println( "context=" +  cpath);
+            for( int j=0; j<roles.size(); j++ ) {
+                String role=(String)roles.elementAt(j);
+                out.println( "role=" +  role);
+            }
+            for( int j=0; j<methods.size(); j++ ) {
+                String m=(String)methods.elementAt(j);
+                out.println( "method=" +  m);
+            }
+            if( isSSL )
+                out.println("ssl=true");
+        }
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/config/IISConfig.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/config/IISConfig.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/config/IISConfig.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,305 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.jk.config;
+
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.Date;
+
+import org.apache.catalina.Context;
+
+
+/**
+    Generates automatic IIS isapi_redirect configurations based on
+    the Tomcat server.xml settings and the war contexts
+    initialized during startup.
+    <p>
+    This config interceptor is enabled by inserting an IISConfig
+    element in the <b>&lt;ContextManager&gt;</b> tag body inside
+    the server.xml file like so:
+    <pre>
+    * < ContextManager ... >
+    *   ...
+    *   <<b>IISConfig</b> <i>options</i> />
+    *   ...
+    * < /ContextManager >
+    </pre>
+    where <i>options</i> can include any of the following attributes:
+    <ul>
+     <li><b>configHome</b> - default parent directory for the following paths.
+                            If not set, this defaults to TOMCAT_HOME. Ignored
+                            whenever any of the following paths is absolute.
+                             </li>
+     <li><b>regConfig</b> - path to use for writing IIS isapi_redirect registry
+                            file. If not set, defaults to
+                            "conf/auto/iis_redirect.reg".</li>
+     <li><b>workersConfig</b> - path to workers.properties file used by 
+                                isapi_redirect. If not set, defaults to
+                                "conf/jk/workers.properties".</li>
+     <li><b>uriConfig</b> - path to use for writing IIS isapi_redirect uriworkermap
+                            file. If not set, defaults to
+                            "conf/auto/uriworkermap.properties".</li>
+     <li><b>jkLog</b> - path to log file to be used by isapi_redirect.</li>
+     <li><b>jkDebug</b> - Loglevel setting.  May be debug, info, error, or emerg.
+                          If not set, defaults to emerg.</li>
+     <li><b>jkWorker</b> The desired worker.  Must be set to one of the workers
+                         defined in the workers.properties file. "ajp12", "ajp13"
+                         or "inprocess" are the workers found in the default
+                         workers.properties file. If not specified, defaults
+                         to "ajp13" if an Ajp13Interceptor is in use, otherwise
+                         it defaults to "ajp12".</li>
+     <li><b>forwardAll</b> - If true, forward all requests to Tomcat. This helps
+                             insure that all the behavior configured in the web.xml
+                             file functions correctly.  If false, let IIS serve
+                             static resources assuming it has been configured
+                             to do so. The default is true.
+                             Warning: When false, some configuration in
+                             the web.xml may not be duplicated in IIS.
+                             Review the uriworkermap file to see what
+                             configuration is actually being set in IIS.</li>
+     <li><b>noRoot</b> - If true, the root context is not mapped to
+                         Tomcat.  If false and forwardAll is true, all requests
+                         to the root context are mapped to Tomcat. If false and
+                         forwardAll is false, only JSP and servlets requests to
+                         the root context are mapped to Tomcat. When false,
+                         to correctly serve Tomcat's root context you must also
+                         modify the Home Directory setting in IIS
+                         to point to Tomcat's root context directory.
+                         Otherwise some content, such as the root index.html,
+                         will be served by IIS before isapi_redirect gets a chance
+                         to claim the request and pass it to Tomcat.
+                         The default is true.</li>
+    </ul>
+  <p>
+    @author Costin Manolache
+    @author Larry Isaacs
+    @author Gal Shachor
+    @author Bill Barker
+ */
+public class IISConfig extends BaseJkConfig  { 
+    private static org.apache.commons.logging.Log log =
+        org.apache.commons.logging.LogFactory.getLog(IISConfig.class);
+
+    public static final String WORKERS_CONFIG = "/conf/jk/workers.properties";
+    public static final String URI_WORKERS_MAP_CONFIG = "/conf/auto/uriworkermap.properties";
+    public static final String ISAPI_LOG_LOCATION = "/logs/iis_redirect.log";
+    public static final String ISAPI_REG_FILE = "/conf/auto/iis_redirect.reg";    
+
+    private File regConfig = null;
+    private File uriConfig = null;
+
+    public IISConfig() 
+    {
+    }
+
+    //-------------------- Properties --------------------
+    
+    /**
+        set the path to the output file for the auto-generated
+        isapi_redirect registry file.  If this path is relative
+        then getRegConfig() will resolve it absolutely against
+        the getConfigHome() path.
+        <p>
+        @param path String path to a file
+    */
+    public void setRegConfig(String path){
+	regConfig= (path==null)?null:new File(path);
+    }
+
+    /**
+        set a path to the uriworkermap.properties file.
+        @param path String path to uriworkermap.properties file
+    */
+    public void setUriConfig(String path){
+        uriConfig= (path==null?null:new File(path));
+    }
+
+    // -------------------- Initialize/guess defaults --------------------
+
+    /** Initialize defaults for properties that are not set
+	explicitely
+    */
+    protected void initProperties() {
+        super.initProperties();
+
+	regConfig=getConfigFile( regConfig, configHome, ISAPI_REG_FILE);
+	workersConfig=getConfigFile( workersConfig, configHome, WORKERS_CONFIG);
+	uriConfig=getConfigFile( uriConfig, configHome, URI_WORKERS_MAP_CONFIG);
+	jkLog=getConfigFile( jkLog, configHome, ISAPI_LOG_LOCATION);
+    }
+
+    // -------------------- Generate config --------------------
+
+    protected PrintWriter getWriter() throws IOException {
+	String abUriConfig = uriConfig.getAbsolutePath();
+	return new PrintWriter(new FileWriter(abUriConfig,append));        
+    }
+    protected boolean generateJkHead(PrintWriter mod_jk) {
+	try {
+	    PrintWriter regfile = new PrintWriter(new FileWriter(regConfig));
+	    log.info("Generating IIS registry file = "+regConfig );
+	    generateRegistrySettings(regfile);
+	    regfile.close();
+	} catch(IOException iex) {
+	    log.warn("Unable to generate registry file " +regConfig);
+	    return false;
+	}
+	log.info("Generating IIS URI worker map file = "+uriConfig );
+	generateUriWorkerHeader(mod_jk);            
+	return true;
+    }
+
+    // -------------------- Config sections  --------------------
+
+    /** Writes the registry settings required by the IIS connector
+     */
+    private void generateRegistrySettings(PrintWriter regfile)
+    {
+        regfile.println("REGEDIT4");
+        regfile.println();
+        regfile.println("[HKEY_LOCAL_MACHINE\\SOFTWARE\\Apache Software Foundation\\Jakarta Isapi Redirector\\1.0]");
+        regfile.println("\"extension_uri\"=\"/jakarta/isapi_redirect.dll\"");
+        regfile.println("\"log_file\"=\"" + dubleSlash(jkLog.toString()) +"\"");
+        regfile.println("\"log_level\"=\"" + jkDebug + "\"");
+        regfile.println("\"worker_file\"=\"" + dubleSlash(workersConfig.toString()) +"\"");
+        regfile.println("\"worker_mount_file\"=\"" + dubleSlash(uriConfig.toString()) +"\"");
+    }
+
+    /** Writes the header information to the uriworkermap file
+     */
+    private void generateUriWorkerHeader(PrintWriter uri_worker)
+    {
+        uri_worker.println("###################################################################");		    
+        uri_worker.println("# Auto generated configuration. Dated: " +  new Date());
+        uri_worker.println("###################################################################");		    
+        uri_worker.println();
+
+        uri_worker.println("#");        
+        uri_worker.println("# Default worker to be used through our mappings");
+        uri_worker.println("#");        
+        uri_worker.println("default.worker=" + jkWorker);        
+        uri_worker.println();
+    }
+
+    /** Forward all requests for a context to tomcat.
+	The default.
+     */
+    protected void generateStupidMappings(Context context, PrintWriter uri_worker )
+    {
+        String ctxPath  = context.getPath();
+	String nPath=("".equals(ctxPath)) ? "/" : ctxPath;
+
+        if( noRoot &&  "".equals(ctxPath) ) {
+            log.debug("Ignoring root context in forward-all mode  ");
+            return;
+        } 
+
+        // map all requests for this context to Tomcat
+        uri_worker.println(nPath +"=$(default.worker)");
+        if( "".equals(ctxPath) ) {
+            uri_worker.println(nPath +"*=$(default.worker)");
+            uri_worker.println(
+                    "# Note: To correctly serve the Tomcat's root context, IIS's Home Directory must");
+            uri_worker.println(
+                    "# must be set to: \"" + getAbsoluteDocBase(context) + "\"");
+        }
+        else
+            uri_worker.println(nPath +"/*=$(default.worker)");
+    }
+
+    protected void generateContextMappings(Context context, PrintWriter uri_worker )
+    {
+        String ctxPath  = context.getPath();
+	String nPath=("".equals(ctxPath)) ? "/" : ctxPath;
+
+        if( noRoot &&  "".equals(ctxPath) ) {
+            log.debug("Ignoring root context in forward-all mode  ");
+            return;
+        } 
+
+        // Static files will be served by IIS
+        uri_worker.println();
+        uri_worker.println("#########################################################");		    
+        uri_worker.println("# Auto configuration for the " + nPath + " context.");
+        uri_worker.println("#########################################################");		    
+        uri_worker.println();
+
+        // Static mappings are not set in uriworkermap, but must be set with IIS admin.
+
+	// InvokerInterceptor - it doesn't have a container,
+	// but it's implemented using a special module.
+
+	// XXX we need to better collect all mappings
+
+	if(context.getLoginConfig() != null) {
+	    String loginPage = context.getLoginConfig().getLoginPage();
+	    if(loginPage != null) {
+		int lpos = loginPage.lastIndexOf("/");
+		String jscurl = loginPage.substring(0,lpos+1) + "j_security_check";
+		addMapping( ctxPath, jscurl, uri_worker);
+	    }
+	}
+		String [] servletMaps=context.findServletMappings();
+	for( int ii=0; ii < servletMaps.length ; ii++) {
+	    addMapping( ctxPath , servletMaps[ii] , uri_worker );
+	}
+    }
+
+    /** Add an IIS extension mapping.
+     */
+    protected boolean addMapping( String ctxPath, String ext,
+					 PrintWriter uri_worker )
+    {
+        if( log.isDebugEnabled() )
+            log.debug( "Adding extension map for " + ctxPath + "/*." + ext );
+	if(! ext.startsWith("/") )
+	    ext = "/" + ext;
+	if(ext.length() > 1)
+	    uri_worker.println(ctxPath + "/*." + ext + "=$(default.worker)");
+        return true;
+    }
+
+    /** Add a fulling specified IIS mapping.
+     */
+    protected boolean addMapping( String fullPath, PrintWriter uri_worker ) {
+        if( log.isDebugEnabled() )
+            log.debug( "Adding map for " + fullPath );
+        uri_worker.println(fullPath + "=$(default.worker)" );
+        return true;
+    }
+
+    // -------------------- Utils --------------------
+
+    private String dubleSlash(String in) 
+    {
+        StringBuffer sb = new StringBuffer();
+        
+        for(int i = 0 ; i < in.length() ; i++) {
+            char ch = in.charAt(i);
+            if('\\' == ch) {
+                sb.append("\\\\");
+            } else {
+                sb.append(ch);
+            }
+        }
+        
+        return sb.toString();
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/config/NSConfig.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/config/NSConfig.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/config/NSConfig.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,328 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.jk.config;
+
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.Date;
+
+import org.apache.catalina.Context;
+
+
+/**
+    Generates automatic Netscape nsapi_redirect configurations based on
+    the Tomcat server.xml settings and the war contexts
+    initialized during startup.
+    <p>
+    This config interceptor is enabled by inserting an NSConfig
+    element in the <b>&lt;ContextManager&gt;</b> tag body inside
+    the server.xml file like so:
+    <pre>
+    * < ContextManager ... >
+    *   ...
+    *   <<b>NSConfig</b> <i>options</i> />
+    *   ...
+    * < /ContextManager >
+    </pre>
+    where <i>options</i> can include any of the following attributes:
+    <ul>
+     <li><b>configHome</b> - default parent directory for the following paths.
+                            If not set, this defaults to TOMCAT_HOME. Ignored
+                            whenever any of the following paths is absolute.
+                             </li>
+     <li><b>objConfig</b> - path to use for writing Netscape obj.conf
+                            file. If not set, defaults to
+                            "conf/auto/obj.conf".</li>
+     <li><b>objectName</b> - Name of the Object to execute the requests.
+                             Defaults to "servlet".</li>
+     <li><b>workersConfig</b> - path to workers.properties file used by 
+                                nsapi_redirect. If not set, defaults to
+                                "conf/jk/workers.properties".</li>
+     <li><b>nsapiJk</b> - path to Netscape mod_jk plugin file.  If not set,
+                        defaults to "bin/nsapi_redirect.dll" on windows,
+                        "bin/nsapi_rd.nlm" on netware, and
+                        "bin/nsapi_redirector.so" everywhere else.</li>
+     <li><b>jkLog</b> - path to log file to be used by nsapi_redirect.</li>
+     <li><b>jkDebug</b> - Loglevel setting.  May be debug, info, error, or emerg.
+                          If not set, defaults to emerg.</li>
+     <li><b>jkWorker</b> The desired worker.  Must be set to one of the workers
+                         defined in the workers.properties file. "ajp12", "ajp13"
+                         or "inprocess" are the workers found in the default
+                         workers.properties file. If not specified, defaults
+                         to "ajp13" if an Ajp13Interceptor is in use, otherwise
+                         it defaults to "ajp12".</li>
+     <li><b>forwardAll</b> - If true, forward all requests to Tomcat. This helps
+                             insure that all the behavior configured in the web.xml
+                             file functions correctly.  If false, let Netscape serve
+                             static resources assuming it has been configured
+                             to do so. The default is true.
+                             Warning: When false, some configuration in
+                             the web.xml may not be duplicated in Netscape.
+                             Review the uriworkermap file to see what
+                             configuration is actually being set in Netscape.</li>
+     <li><b>noRoot</b> - If true, the root context is not mapped to
+                         Tomcat.  If false and forwardAll is true, all requests
+                         to the root context are mapped to Tomcat. If false and
+                         forwardAll is false, only JSP and servlets requests to
+                         the root context are mapped to Tomcat. When false,
+                         to correctly serve Tomcat's root context you must also
+                         modify the Home Directory setting in Netscape
+                         to point to Tomcat's root context directory.
+                         Otherwise some content, such as the root index.html,
+                         will be served by Netscape before nsapi_redirect gets a chance
+                         to claim the request and pass it to Tomcat.
+                         The default is true.</li>
+    </ul>
+  <p>
+    @author Costin Manolache
+    @author Larry Isaacs
+    @author Gal Shachor
+    @author Bill Barker
+ */
+public class NSConfig  extends BaseJkConfig { 
+    private static org.apache.commons.logging.Log log =
+        org.apache.commons.logging.LogFactory.getLog(NSConfig.class);
+
+    public static final String WORKERS_CONFIG = "/conf/jk/workers.properties";
+    public static final String NS_CONFIG = "/conf/auto/obj.conf";
+    public static final String NSAPI_LOG_LOCATION = "/logs/nsapi_redirect.log";
+    /** default location of nsapi plug-in. */
+    public static final String NSAPI_REDIRECTOR;
+    
+    //set up some defaults based on OS type
+    static{
+        String os = System.getProperty("os.name").toLowerCase();
+        if(os.indexOf("windows")>=0){
+           NSAPI_REDIRECTOR = "bin/nsapi_redirect.dll";
+        }else if(os.indexOf("netware")>=0){
+           NSAPI_REDIRECTOR = "bin/nsapi_rd.nlm";
+        }else{
+           NSAPI_REDIRECTOR = "bin/nsapi_redirector.so";
+        }
+    }
+
+    private File objConfig = null;
+    private File nsapiJk = null;
+    private String objectName = "servlet";
+
+    public NSConfig() 
+    {
+    }
+
+    //-------------------- Properties --------------------
+    
+    /**
+        set the path to the output file for the auto-generated
+        isapi_redirect registry file.  If this path is relative
+        then getRegConfig() will resolve it absolutely against
+        the getConfigHome() path.
+        <p>
+        @param path String path to a file
+    */
+    public void setObjConfig(String path) {
+	objConfig= (path==null)?null:new File(path);
+    }
+
+    /**
+        set the path to the nsapi plugin module
+        @param path String path to a file
+    */
+    public void setNsapiJk(String path) {
+        nsapiJk=( path==null?null:new File(path));
+    }
+
+    /**
+        Set the name for the Object that implements the
+        jk_service call.
+        @param name Name of the obj.conf Object
+    */
+    public void setObjectName(String name) {
+        objectName = name;
+    }
+
+    // -------------------- Initialize/guess defaults --------------------
+
+    /** Initialize defaults for properties that are not set
+	explicitely
+    */
+    protected void initProperties() {
+        super.initProperties();
+
+	objConfig=getConfigFile( objConfig, configHome, NS_CONFIG);
+	workersConfig=getConfigFile( workersConfig, configHome, WORKERS_CONFIG);
+
+	if( nsapiJk == null )
+	    nsapiJk=new File(NSAPI_REDIRECTOR);
+	else
+	    nsapiJk =getConfigFile( nsapiJk, configHome, NSAPI_REDIRECTOR );
+	jkLog=getConfigFile( jkLog, configHome, NSAPI_LOG_LOCATION);
+    }
+
+    // -------------------- Generate config --------------------
+    protected PrintWriter getWriter() throws IOException {
+	String abObjConfig = objConfig.getAbsolutePath();
+	return new PrintWriter(new FileWriter(abObjConfig,append));
+    }
+    protected boolean generateJkHead(PrintWriter mod_jk) {
+	log.info("Generating netscape web server config = "+objConfig );
+	
+	generateNsapiHead( mod_jk );
+	
+	mod_jk.println("<Object name=default>");
+	return true;
+    }
+
+    private void generateNsapiHead(PrintWriter objfile)
+    {
+        objfile.println("###################################################################");		    
+        objfile.println("# Auto generated configuration. Dated: " +  new Date());
+        objfile.println("###################################################################");		    
+        objfile.println();
+
+        objfile.println("#");        
+        objfile.println("# You will need to merge the content of this file with your ");
+        objfile.println("# regular obj.conf and then restart (=stop + start) your Netscape server. ");
+        objfile.println("#");        
+        objfile.println();
+            
+        objfile.println("#");                    
+        objfile.println("# Loading the redirector into your server");
+        objfile.println("#");        
+        objfile.println();            
+        objfile.println("Init fn=\"load-modules\" funcs=\"jk_init,jk_service\" shlib=\"<put full path to the redirector here>\"");
+        objfile.println("Init fn=\"jk_init\" worker_file=\"" + 
+                        workersConfig.toString().replace('\\', '/') +  
+                        "\" log_level=\"" + jkDebug + "\" log_file=\"" + 
+                        jkLog.toString().replace('\\', '/') + 
+                        "\"");
+        objfile.println();
+    }
+
+    protected void generateJkTail(PrintWriter objfile)
+    {
+        objfile.println();
+        objfile.println("#######################################################");		    
+        objfile.println("# Protecting the WEB-INF and META-INF directories.");
+        objfile.println("#######################################################");		    
+        objfile.println("PathCheck fn=\"deny-existence\" path=\"*/WEB-INF/*\""); 
+        objfile.println("PathCheck fn=\"deny-existence\" path=\"*/META-INF/*\""); 
+        objfile.println();
+
+        objfile.println("</Object>");            
+        objfile.println();
+
+        objfile.println("#######################################################");		    
+        objfile.println("# New object to execute your servlet requests.");
+        objfile.println("#######################################################");		    
+        objfile.println("<Object name=" + objectName + ">");
+        objfile.println("ObjectType fn=force-type type=text/html");
+        objfile.println("Service fn=\"jk_service\" worker=\""+ jkWorker + "\" path=\"/*\"");
+        objfile.println("</Object>");
+        objfile.println();
+    }
+
+    // -------------------- Forward all mode --------------------
+    
+    /** Forward all requests for a context to tomcat.
+	The default.
+     */
+    protected void generateStupidMappings(Context context, PrintWriter objfile )
+    {
+        String ctxPath  = context.getPath();
+	String nPath=("".equals(ctxPath)) ? "/" : ctxPath;
+
+        if( noRoot &&  "".equals(ctxPath) ) {
+            log.debug("Ignoring root context in forward-all mode  ");
+            return;
+        } 
+	objfile.println("<Object name=" + context.getName() + ">");
+
+        objfile.println("NameTrans fn=\"assign-name\" from=\"" + ctxPath + "\" name=\"" + objectName + "\""); 
+        objfile.println("NameTrans fn=\"assign-name\" from=\"" + ctxPath + "/*\" name=\"" + objectName + "\""); 
+	objfile.println("</Object>");
+    }
+
+
+    // -------------------- Netscape serves static mode --------------------
+    // This is not going to work for all apps. We fall back to stupid mode.
+    
+    protected void generateContextMappings(Context context, PrintWriter objfile )
+    {
+        String ctxPath  = context.getPath();
+	String nPath=("".equals(ctxPath)) ? "/" : ctxPath;
+
+        if( noRoot &&  "".equals(ctxPath) ) {
+            log.debug("Ignoring root context in non-forward-all mode  ");
+            return;
+        } 
+	objfile.println("<Object name=" + context.getName() + ">");
+        // Static files will be served by Netscape
+        objfile.println("#########################################################");		    
+        objfile.println("# Auto configuration for the " + nPath + " context starts.");
+        objfile.println("#########################################################");		    
+        objfile.println();
+
+        // XXX Need to determine what if/how static mappings are done
+
+	// InvokerInterceptor - it doesn't have a container,
+	// but it's implemented using a special module.
+	
+	// XXX we need to better collect all mappings
+	if(context.getLoginConfig() != null) {
+	    String loginPage = context.getLoginConfig().getLoginPage();
+	    if(loginPage != null) {
+		int lpos = loginPage.lastIndexOf("/");
+		String jscurl = loginPage.substring(0,lpos+1) + "j_security_check";
+		addMapping( ctxPath, jscurl, objfile);
+	    }
+	}
+	
+	String [] servletMaps=context.findServletMappings();
+	for(int ii=0; ii < servletMaps.length; ii++) {
+	    addMapping( ctxPath , servletMaps[ii] , objfile );
+	}
+	objfile.println("</Object>");
+    }
+
+    /** Add a Netscape extension mapping.
+     */
+    protected boolean addMapping( String ctxPath, String ext,
+					 PrintWriter objfile )
+    {
+        if( log.isDebugEnabled() )
+            log.debug( "Adding extension map for " + ctxPath + "/*." + ext );
+	if(! ext.startsWith("/") )
+	    ext = "/" + ext;
+	if(ext.length() > 1)
+	    objfile.println("NameTrans fn=\"assign-name\" from=\"" +
+                    ctxPath  + ext + "\" name=\"" + objectName + "\""); 
+	return true;
+    }
+
+    /** Add a fulling specified Netscape mapping.
+     */
+    protected boolean addMapping( String fullPath, PrintWriter objfile ) {
+        if( log.isDebugEnabled() )
+            log.debug( "Adding map for " + fullPath );
+        objfile.println("NameTrans fn=\"assign-name\" from=\"" +
+                        fullPath + "\" name=\"" + objectName + "\""); 
+	return true;
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/config/WebXml2Jk.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/config/WebXml2Jk.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/config/WebXml2Jk.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,451 @@
+/*
+ *  Copyright 1999-2005 The Apache Software Foundation
+ *
+ *  Licensed 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.jk.config;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.StringReader;
+import java.util.Hashtable;
+import java.util.Vector;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+
+import org.apache.tomcat.util.IntrospectionUtils;
+import org.w3c.dom.Document;
+import org.w3c.dom.Node;
+import org.xml.sax.EntityResolver;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+
+
+/* Naming conventions:
+
+JK_CONF_DIR == serverRoot/work  ( XXX /jkConfig ? )
+
+- Each vhost has a sub-dir named after the canonycal name
+
+- For each webapp in a vhost, there is a separate WEBAPP_NAME.jkmap
+
+- In httpd.conf ( or equivalent servers ), in each virtual host you
+should "Include JK_CONF_DIR/VHOST/jk_apache.conf". The config
+file will contain the Alias declarations and other rules required
+for apache operation. Same for other servers. 
+
+- WebXml2Jk will be invoked by a config tool or automatically for each
+webapp - it'll generate the WEBAPP.jkmap files and config fragments.
+
+WebXml2Jk will _not_ generate anything else but mappings.
+It should _not_ try to guess locations or anything else - that's
+another components' job.
+
+*/
+
+/**
+ * Read a web.xml file and generate the mappings for jk2.
+ * It can be used from the command line or ant.
+ * 
+ * In order for the web server to serve static pages, all webapps
+ * must be deployed on the computer that runs Apache, IIS, etc.
+ *
+ * Dynamic pages can be executed on that computer or other servers
+ * in a pool, but even if the main server doesn't run tomcat,
+ * it must have all the static files and WEB-INF/web.xml.
+ * ( you could have a script remove everything else, including jsps - if
+ *  security paranoia is present ).
+ *
+ * XXX We could have this in WEB-INF/urimap.properties.
+ *
+ * @author Costin Manolache
+ */
+public class WebXml2Jk {
+    String vhost="";
+    String cpath="";
+    String docBase;
+    String file;
+    String worker="lb"; 
+
+    // -------------------- Settings -------------------- 
+
+    // XXX We can also generate location-independent mappings.
+    
+    /** Set the canonycal name of the virtual host.
+     */
+    public void setHost( String vhost ) {
+        this.vhost=vhost; 
+    }
+    
+    /** Set the canonical name of the virtual host.
+     */
+    public void setContext( String contextPath ) {
+        this.cpath=contextPath;
+    }
+
+    
+    /** Set the base directory where the application is
+     *  deployed ( on the web server ).
+     */
+    public void setDocBase(String docBase ) {
+        this.docBase=docBase;
+    }
+
+    // Automatically generated.
+//     /** The file where the jk2 mapping will be generated
+//      */
+//     public void setJk2Conf( String outFile ) {
+//         file=outFile;
+//         type=CONFIG_JK2_URIMAP;
+//     }
+
+//     /** Backward compat: generate JkMounts for mod_jk1
+//      */
+//     public void setJkmountFile( String outFile ) {
+//         file=outFile;
+//         type=CONFIG_JK_MOUNT;
+//     }
+
+    /* By default we map to the lb - in jk2 this is automatically
+     * created and includes all  tomcat instances.
+     *
+     * This is equivalent to the worker in jk1.
+     */
+    public void setGroup(String route ) {
+        worker=route;
+    }
+
+    // -------------------- Generators --------------------
+    public static interface MappingGenerator {
+        void setWebXmlReader(WebXml2Jk wxml );
+
+        /** Start section( vhost declarations, etc )
+         */
+        void generateStart() throws IOException ;
+
+        void generateEnd() throws IOException ;
+        
+        void generateServletMapping( String servlet, String url )throws IOException ;
+        void generateFilterMapping( String servlet, String url ) throws IOException ;
+
+        void generateLoginConfig( String loginPage,
+                                  String errPage, String authM ) throws IOException ;
+
+        void generateErrorPage( int err, String location ) throws IOException ;
+            
+        void generateConstraints( Vector urls, Vector methods, Vector roles, boolean isSSL ) throws IOException ;
+    }    
+    
+    // -------------------- Implementation --------------------
+    Node webN;
+    File jkDir;
+    
+    /** Return the top level node
+     */
+    public Node getWebXmlNode() {
+        return webN;
+    }
+
+    public File getJkDir() {
+        return jkDir;
+    }
+    
+    /** Extract the wellcome files from the web.xml
+     */
+    public Vector getWellcomeFiles() {
+        Node n0=getChild( webN, "welcome-file-list" );
+        Vector wF=new Vector();
+        if( n0!=null ) {
+            for( Node mapN=getChild( webN, "welcome-file" );
+                 mapN != null; mapN = getNext( mapN ) ) {
+                wF.addElement( getContent(mapN));
+            }
+        }
+        // XXX Add index.html, index.jsp
+        return wF;
+    }
+
+
+    void generate(MappingGenerator gen ) throws IOException {
+        gen.generateStart();
+        log.info("Generating mappings for servlets " );
+        for( Node mapN=getChild( webN, "servlet-mapping" );
+             mapN != null; mapN = getNext( mapN ) ) {
+            
+            String serv=getChildContent( mapN, "servlet-name");
+            String url=getChildContent( mapN, "url-pattern");
+            
+            gen.generateServletMapping( serv, url );
+        }
+
+        log.info("Generating mappings for filters " );
+        for( Node mapN=getChild( webN, "filter-mapping" );
+             mapN != null; mapN = getNext( mapN ) ) {
+            
+            String filter=getChildContent( mapN, "filter-name");
+            String url=getChildContent( mapN, "url-pattern");
+
+            gen.generateFilterMapping(  filter, url );
+        }
+
+
+        for( Node mapN=getChild( webN, "error-page" );
+             mapN != null; mapN = getNext( mapN ) ) {
+            String errorCode= getChildContent( mapN, "error-code" );
+            String location= getChildContent( mapN, "location" );
+
+            if( errorCode!=null && ! "".equals( errorCode ) ) {
+                try {
+                    int err=new Integer( errorCode ).intValue();
+                    gen.generateErrorPage(  err, location );
+                } catch( Exception ex ) {
+                    log.error( "Format error " + location, ex);
+                }
+            }
+        }
+
+        Node lcN=getChild( webN, "login-config" );
+        if( lcN!=null ) {
+            log.info("Generating mapping for login-config " );
+            
+            String authMeth=getContent( getChild( lcN, "auth-method"));
+            if( authMeth == null ) authMeth="BASIC";
+
+            Node n1=getChild( lcN, "form-login-config");
+            String loginPage= getChildContent( n1, "form-login-page");
+            String errPage= getChildContent( n1, "form-error-page");
+
+	    if(loginPage != null) {
+		int lpos = loginPage.lastIndexOf("/");
+		String jscurl = loginPage.substring(0,lpos+1) + "j_security_check";
+                gen.generateLoginConfig( jscurl, errPage, authMeth );
+	    }
+        }
+
+        log.info("Generating mappings for security constraints " );
+        for( Node mapN=getChild( webN, "security-constraint" );
+             mapN != null; mapN = getNext( mapN )) {
+
+            Vector methods=new Vector();
+            Vector urls=new Vector();
+            Vector roles=new Vector();
+            boolean isSSL=false;
+            
+            Node wrcN=getChild( mapN, "web-resource-collection");
+            for( Node uN=getChild(wrcN, "http-method");
+                 uN!=null; uN=getNext( uN )) {
+                methods.addElement( getContent( uN ));
+            }
+            for( Node uN=getChild(wrcN, "url-pattern");
+                 uN!=null; uN=getNext( uN )) {
+                urls.addElement( getContent( uN ));
+            }
+
+            // Not used at the moment
+            Node acN=getChild( mapN, "auth-constraint");
+            for( Node rN=getChild(acN, "role-name");
+                 rN!=null; rN=getNext( rN )) {
+                roles.addElement(getContent( rN ));
+            }
+
+            Node ucN=getChild( mapN, "user-data-constraint");
+            String transp=getContent(getChild( ucN, "transport-guarantee"));
+            if( transp!=null ) {
+                if( "INTEGRAL".equalsIgnoreCase( transp ) ||
+                    "CONFIDENTIAL".equalsIgnoreCase( transp ) ) {
+                    isSSL=true;
+                }
+            }
+
+            gen.generateConstraints( urls, methods, roles, isSSL );
+        }
+        gen.generateEnd();
+    }
+    
+    // -------------------- Main and ant wrapper --------------------
+    
+    public void execute() {
+        try {
+            if( docBase== null) {
+                log.error("No docbase - please specify the base directory of you web application ( -docBase PATH )");
+                return;
+            }
+            if( cpath== null) {
+                log.error("No context - please specify the mount ( -context PATH )");
+                return;
+            }
+            File docbF=new File(docBase);
+            File wXmlF=new File( docBase, "WEB-INF/web.xml");
+
+            Document wXmlN=readXml(wXmlF);
+            if( wXmlN == null ) return;
+
+            webN = wXmlN.getDocumentElement();
+            if( webN==null ) {
+                log.error("Can't find web-app");
+                return;
+            }
+
+            jkDir=new File( docbF, "WEB-INF/jk2" );
+            jkDir.mkdirs();
+            
+            MappingGenerator generator=new GeneratorJk2();
+            generator.setWebXmlReader( this );
+            generate( generator );
+
+            generator=new GeneratorJk1();
+            generator.setWebXmlReader( this );
+            generate( generator );
+
+            generator=new GeneratorApache2();
+            generator.setWebXmlReader( this );
+            generate( generator );
+
+        } catch( Exception ex ) {
+            ex.printStackTrace();
+        }
+    }
+
+
+    public static void main(String args[] ) {
+        try {
+            if( args.length == 1 &&
+                ( "-?".equals(args[0]) || "-h".equals( args[0])) ) {
+                System.out.println("Usage: ");
+                System.out.println("  WebXml2Jk [OPTIONS]");
+                System.out.println();
+                System.out.println("  -docBase DIR        The location of the webapp. Required");
+                System.out.println("  -group GROUP        Group, if you have multiple tomcats with diffrent content. " );
+                System.out.println("                      The default is 'lb', and should be used in most cases");
+                System.out.println("  -host HOSTNAME      Canonical hostname - for virtual hosts");
+                System.out.println("  -context /CPATH     Context path where the app will be mounted");
+                return;
+            }
+
+            WebXml2Jk w2jk=new WebXml2Jk();
+
+            /* do ant-style property setting */
+            IntrospectionUtils.processArgs( w2jk, args, new String[] {},
+                                            null, new Hashtable());
+            w2jk.execute();
+        } catch( Exception ex ) {
+            ex.printStackTrace();
+        }
+
+    }
+
+    private static org.apache.commons.logging.Log log=
+        org.apache.commons.logging.LogFactory.getLog( WebXml2Jk.class );
+
+    
+    // -------------------- DOM utils --------------------
+
+    /** Get the content of a node
+     */
+    public static String getContent(Node n ) {
+        if( n==null ) return null;
+        Node n1=n.getFirstChild();
+        // XXX Check if it's a text node
+
+        String s1=n1.getNodeValue();
+        return s1.trim();
+    }
+    
+    /** Get the first child
+     */
+    public static Node getChild( Node parent, String name ) {
+        if( parent==null ) return null;
+        Node first=parent.getFirstChild();
+        if( first==null ) return null;
+        for (Node node = first; node != null;
+             node = node.getNextSibling()) {
+            //System.out.println("getNode: " + name + " " + node.getNodeName());
+            if( name.equals( node.getNodeName() ) ) {
+                return node;
+            }
+        }
+        return null;
+    }
+
+    /** Get the first child's content ( i.e. it's included TEXT node )
+     */
+    public static String getChildContent( Node parent, String name ) {
+        Node first=parent.getFirstChild();
+        if( first==null ) return null;
+        for (Node node = first; node != null;
+             node = node.getNextSibling()) {
+            //System.out.println("getNode: " + name + " " + node.getNodeName());
+            if( name.equals( node.getNodeName() ) ) {
+                return getContent( node );
+            }
+        }
+        return null;
+    }
+
+    /** Get the node in the list of siblings
+     */
+    public static Node getNext( Node current ) {
+        Node first=current.getNextSibling();
+        String name=current.getNodeName();
+        if( first==null ) return null;
+        for (Node node = first; node != null;
+             node = node.getNextSibling()) {
+            //System.out.println("getNode: " + name + " " + node.getNodeName());
+            if( name.equals( node.getNodeName() ) ) {
+                return node;
+            }
+        }
+        return null;
+    }
+
+    public static class NullResolver implements EntityResolver {
+        public InputSource resolveEntity (String publicId,
+                                                   String systemId)
+            throws SAXException, IOException
+        {
+            if (log.isDebugEnabled())
+                log.debug("ResolveEntity: " + publicId + " " + systemId);
+            return new InputSource(new StringReader(""));
+        }
+    }
+    
+    public static Document readXml(File xmlF)
+        throws SAXException, IOException, ParserConfigurationException
+    {
+        if( ! xmlF.exists() ) {
+            log.error("No xml file " + xmlF );
+            return null;
+        }
+        DocumentBuilderFactory dbf =
+            DocumentBuilderFactory.newInstance();
+
+        dbf.setValidating(false);
+        dbf.setIgnoringComments(false);
+        dbf.setIgnoringElementContentWhitespace(true);
+        //dbf.setCoalescing(true);
+        //dbf.setExpandEntityReferences(true);
+
+        DocumentBuilder db = null;
+        db = dbf.newDocumentBuilder();
+        db.setEntityResolver( new NullResolver() );
+        
+        // db.setErrorHandler( new MyErrorHandler());
+
+        Document doc = db.parse(xmlF);
+        return doc;
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/core/JkChannel.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/core/JkChannel.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/core/JkChannel.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,76 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.jk.core;
+
+import java.io.IOException;
+
+import org.apache.coyote.Request;
+
+/**
+ * A Channel represents a connection point to the outside world.
+ *
+ * @author Bill Barker
+ */
+
+public interface JkChannel {
+
+
+    /**
+     * Return the identifying name of this Channel.
+     */
+    public String getChannelName();
+
+    /**
+     * Send a message back to the client.
+     * @param msg The message to send.
+     * @param ep The connection point for this request.
+     */
+    public int send(Msg msg, MsgContext ep) throws IOException;
+
+    /**
+     * Recieve a message from the client.
+     * @param msg The place to recieve the data into.
+     * @param ep The connection point for this request.
+     */
+    public  int receive(Msg msg, MsgContext ep) throws IOException;
+
+    /**
+     * Flush the data to the client.
+     */
+    public int flush(Msg msg, MsgContext ep) throws IOException;
+
+    /**
+     * Invoke the request chain.
+     */
+    public int invoke(Msg msg, MsgContext ep) throws IOException;
+
+    /**
+     * Confirm that a shutdown request was recieved form us.
+     */
+    public boolean isSameAddress(MsgContext ep);
+
+    /**
+     * Register a new Request in the Request pool.
+     */
+    public void registerRequest(Request req, MsgContext ep, int count);
+
+    /**
+     * Create a new request endpoint.
+     */
+    public MsgContext createMsgContext();
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/core/JkHandler.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/core/JkHandler.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/core/JkHandler.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,196 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.jk.core;
+
+import java.io.IOException;
+import java.util.Properties;
+
+import javax.management.MBeanRegistration;
+import javax.management.MBeanServer;
+import javax.management.Notification;
+import javax.management.NotificationListener;
+import javax.management.ObjectName;
+
+import org.apache.commons.modeler.Registry;
+
+/**
+ *
+ * @author Costin Manolache
+ */
+public class JkHandler implements MBeanRegistration, NotificationListener {
+    public static final int OK=0;
+    public static final int LAST=1;
+    public static final int ERROR=2;
+
+    protected Properties properties=new Properties();
+    protected WorkerEnv wEnv;
+    protected JkHandler next;
+    protected String nextName=null;
+    protected String name;
+    protected int id;
+
+    // XXX Will be replaced with notes and (configurable) ids
+    // Each represents a 'chain' - similar with ActionCode in Coyote ( the concepts
+    // will be merged ).    
+    public static final int HANDLE_RECEIVE_PACKET   = 10;
+    public static final int HANDLE_SEND_PACKET      = 11;
+    public static final int HANDLE_FLUSH            = 12;
+    public static final int HANDLE_THREAD_END       = 13;
+    
+    public void setWorkerEnv( WorkerEnv we ) {
+        this.wEnv=we;
+    }
+
+    /** Set the name of the handler. Will allways be called by
+     *  worker env after creating the worker.
+     */
+    public void setName(String s ) {
+        name=s;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    /** Set the id of the worker. We use an id for faster dispatch.
+     *  Since we expect a decent number of handler in system, the
+     *  id is unique - that means we may have to allocate bigger
+     *  dispatch tables. ( easy to fix if needed )
+     */
+    public void setId( int id ) {
+        this.id=id;
+    }
+
+    public int getId() {
+        return id;
+    }
+    
+    /** Catalina-style "recursive" invocation.
+     *  A chain is used for Apache/3.3 style iterative invocation.
+     */
+    public void setNext( JkHandler h ) {
+        next=h;
+    }
+
+    public void setNext( String s ) {
+        nextName=s;
+    }
+
+    public String getNext() {
+        if( nextName==null ) {
+            if( next!=null)
+                nextName=next.getName();
+        }
+        return nextName;
+    }
+
+    /** Should register the request types it can handle,
+     *   same style as apache2.
+     */
+    public void init() throws IOException {
+    }
+
+    /** Clean up and stop the handler
+     */
+    public void destroy() throws IOException {
+    }
+
+    public MsgContext createMsgContext() {
+        return new MsgContext();
+    }
+    
+    public int invoke(Msg msg, MsgContext mc )  throws IOException {
+        return OK;
+    }
+    
+    public void setProperty( String name, String value ) {
+        properties.put( name, value );
+    }
+
+    public String getProperty( String name ) {
+        return properties.getProperty(name) ;
+    }
+
+    /** Experimental, will be replaced. This allows handlers to be
+     *  notified when other handlers are added.
+     */
+    public void addHandlerCallback( JkHandler w ) {
+
+    }
+
+    public void handleNotification(Notification notification, Object handback)
+    {
+//        BaseNotification bNot=(BaseNotification)notification;
+//        int code=bNot.getCode();
+//
+//        MsgContext ctx=(MsgContext)bNot.getSource();
+
+
+    }
+
+    protected String domain;
+    protected ObjectName oname;
+    protected MBeanServer mserver;
+
+    public ObjectName getObjectName() {
+        return oname;
+    }
+
+    public String getDomain() {
+        return domain;
+    }
+
+    public ObjectName preRegister(MBeanServer server,
+                                  ObjectName oname) throws Exception {
+        this.oname=oname;
+        mserver=server;
+        domain=oname.getDomain();
+        if( name==null ) {
+            name=oname.getKeyProperty("name");
+        }
+        
+        // we need to create a workerEnv or set one.
+        ObjectName wEnvName=new ObjectName(domain + ":type=JkWorkerEnv");
+        if ( wEnv == null ) {
+            wEnv=new WorkerEnv();
+        }
+        if( ! mserver.isRegistered(wEnvName )) {
+            Registry.getRegistry(null, null).registerComponent(wEnv, wEnvName, null);
+        }
+        mserver.invoke( wEnvName, "addHandler", 
+                new Object[] {name, this}, 
+                new String[] {"java.lang.String", 
+                              "org.apache.jk.core.JkHandler"});
+        return oname;
+    }
+    
+    public void postRegister(Boolean registrationDone) {
+    }
+
+    public void preDeregister() throws Exception {
+    }
+
+    public void postDeregister() {
+    }
+
+    public void pause() throws Exception {
+    }
+
+    public void resume() throws Exception {
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/core/Msg.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/core/Msg.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/core/Msg.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,153 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.jk.core;
+
+import java.io.IOException;
+
+import org.apache.tomcat.util.buf.ByteChunk;
+import org.apache.tomcat.util.buf.MessageBytes;
+
+
+/**
+ * A single packet for communication between the web server and the
+ * container.
+ *
+ * In a more generic sense, it's the event that drives the processing chain.
+ * XXX Use Event, make Msg a particular case.
+ *
+ * @author Henri Gomez [hgomez at apache.org]
+ * @author Dan Milstein [danmil at shore.net]
+ * @author Keith Wannamaker [Keith at Wannamaker.org]
+ * @author Kevin Seguin
+ * @author Costin Manolache
+ */
+public abstract class Msg {
+
+    
+    
+    /**
+     * Prepare this packet for accumulating a message from the container to
+     * the web server.  Set the write position to just after the header
+     * (but leave the length unwritten, because it is as yet unknown).
+     */
+    public abstract void reset();
+
+    /**
+     * For a packet to be sent to the web server, finish the process of
+     * accumulating data and write the length of the data payload into
+     * the header.  
+     */
+    public abstract void end();
+
+    public abstract  void appendInt( int val );
+
+    public abstract void appendByte( int val );
+	
+    public abstract void appendLongInt( int val );
+
+    /**
+     */
+    public abstract void appendBytes(MessageBytes mb) throws IOException;
+
+    public abstract void appendByteChunk(ByteChunk bc) throws IOException;
+    
+    /** 
+     * Copy a chunk of bytes into the packet, starting at the current
+     * write position.  The chunk of bytes is encoded with the length
+     * in two bytes first, then the data itself, and finally a
+     * terminating \0 (which is <B>not</B> included in the encoded
+     * length).
+     *
+     * @param b The array from which to copy bytes.
+     * @param off The offset into the array at which to start copying
+     * @param numBytes The number of bytes to copy.  
+     */
+    public abstract void appendBytes( byte b[], int off, int numBytes );
+
+    /**
+     * Read an integer from packet, and advance the read position past
+     * it.  Integers are encoded as two unsigned bytes with the
+     * high-order byte first, and, as far as I can tell, in
+     * little-endian order within each byte.  
+     */
+    public abstract int getInt();
+
+    public abstract int peekInt();
+
+    public abstract byte getByte();
+
+    public abstract byte peekByte();
+
+    public abstract void getBytes(MessageBytes mb);
+    
+    /**
+     * Copy a chunk of bytes from the packet into an array and advance
+     * the read position past the chunk.  See appendBytes() for details
+     * on the encoding.
+     *
+     * @return The number of bytes copied.
+     */
+    public abstract int getBytes(byte dest[]);
+
+    /**
+     * Read a 32 bits integer from packet, and advance the read position past
+     * it.  Integers are encoded as four unsigned bytes with the
+     * high-order byte first, and, as far as I can tell, in
+     * little-endian order within each byte.
+     */
+    public abstract int getLongInt();
+
+    public abstract int getHeaderLength();
+
+    public abstract int processHeader();
+
+    public abstract byte[] getBuffer();
+
+    public abstract int getLen();
+    
+    public abstract void dump(String msg);
+
+    /* -------------------- Utilities -------------------- */
+    // XXX Move to util package
+
+    public static String hexLine( byte buf[], int start, int len ) {
+        StringBuffer sb=new StringBuffer();
+        for( int i=start; i< start+16 ; i++ ) {
+            if( i < len + 4)
+                sb.append( hex( buf[i] ) + " ");
+            else
+                sb.append( "   " );
+        }
+        sb.append(" | ");
+        for( int i=start; i < start+16 && i < len + 4; i++ ) {
+            if( ! Character.isISOControl( (char)buf[i] ))
+                sb.append( new Character((char)buf[i]) );
+            else
+                sb.append( "." );
+        }
+        return sb.toString();
+    }
+
+    private  static String hex( int x ) {
+        //	    if( x < 0) x=256 + x;
+        String h=Integer.toHexString( x );
+        if( h.length() == 1 ) h = "0" + h;
+        return h.substring( h.length() - 2 );
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/core/MsgContext.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/core/MsgContext.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/core/MsgContext.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,382 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.jk.core;
+
+import java.io.IOException;
+import java.io.ByteArrayInputStream;
+import java.net.InetAddress;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+
+import org.apache.coyote.ActionCode;
+import org.apache.coyote.ActionHook;
+import org.apache.coyote.Request;
+import org.apache.coyote.Response;
+
+import org.apache.tomcat.util.buf.C2BConverter;
+import org.apache.tomcat.util.buf.MessageBytes;
+import org.apache.tomcat.util.buf.ByteChunk;
+import org.apache.tomcat.util.net.SSLSupport;
+import org.apache.jk.common.JkInputStream;
+
+
+/**
+ *
+ * @author Henri Gomez [hgomez at apache.org]
+ * @author Dan Milstein [danmil at shore.net]
+ * @author Keith Wannamaker [Keith at Wannamaker.org]
+ * @author Kevin Seguin
+ * @author Costin Manolache
+ */
+public class MsgContext implements ActionHook {
+    private static org.apache.commons.logging.Log log =
+        org.apache.commons.logging.LogFactory.getLog(MsgContext.class);
+    private static org.apache.commons.logging.Log logTime=
+        org.apache.commons.logging.LogFactory.getLog( "org.apache.jk.REQ_TIME" );
+
+    private int type;
+    private Object notes[]=new Object[32];
+    private JkHandler next;
+    private JkChannel source;
+    private JkInputStream jkIS = new JkInputStream(this);
+    private C2BConverter c2b;
+    private Request req;
+    private WorkerEnv wEnv;
+    private Msg msgs[]=new Msg[10];
+    private int status=0;
+    // Control object
+    private Object control;
+
+    // Application managed, like notes
+    private long timers[]=new long[20];
+    
+    // The context can be used by JNI components as well
+    private long jkEndpointP;
+    private long xEnvP;
+
+    // Temp: use notes and dynamic strings
+    public static final int TIMER_RECEIVED=0;
+    public static final int TIMER_PRE_REQUEST=1;
+    public static final int TIMER_POST_REQUEST=2;
+
+    // Status codes
+    public static final int JK_STATUS_NEW=0;
+    public static final int JK_STATUS_HEAD=1;
+    public static final int JK_STATUS_CLOSED=2;
+    public static final int JK_STATUS_ERROR=3;
+
+    public MsgContext() {
+        try {
+            c2b = new C2BConverter("iso-8859-1");
+        } catch(IOException iex) {
+            log.warn("Can't happen", iex);
+        }
+    }
+    
+    public final Object getNote( int id ) {
+        return notes[id];
+    }
+
+    public final void setNote( int id, Object o ) {
+        notes[id]=o;
+    }
+
+    /** The id of the chain */
+    public final int getType() {
+        return type;
+    }
+
+    public final void setType(int i) {
+        type=i;
+    }
+
+    public final void setLong( int i, long l) {
+        timers[i]=l;
+    }
+    
+    public final long getLong( int i) {
+        return timers[i];
+    }
+    
+    // Common attributes ( XXX should be notes for flexibility ? )
+
+    public final WorkerEnv getWorkerEnv() {
+        return wEnv;
+    }
+
+    public final void setWorkerEnv( WorkerEnv we ) {
+        this.wEnv=we;
+    }
+    
+    public final JkChannel getSource() {
+        return source;
+    }
+    
+    public final void setSource(JkChannel ch) {
+        this.source=ch;
+    }
+
+    public final int getStatus() {
+        return status;
+    }
+
+    public final void setStatus( int s ) {
+        status=s;
+    }
+    
+    public final JkHandler getNext() {
+        return next;
+    }
+    
+    public final void setNext(JkHandler ch) {
+        this.next=ch;
+    }
+
+    /** The high level request object associated with this context
+     */
+    public final void setRequest( Request req ) {
+        this.req=req;
+        req.setInputBuffer(jkIS);
+        Response res = req.getResponse();
+        res.setOutputBuffer(jkIS);
+        res.setHook(this);
+    }
+
+    public final Request getRequest() {
+        return req;
+    }
+
+    /** The context may store a number of messages ( buffers + marshalling )
+     */
+    public final Msg getMsg(int i) {
+        return msgs[i];
+    }
+
+    public final void setMsg(int i, Msg msg) {
+        this.msgs[i]=msg;
+    }
+
+    public final C2BConverter getConverter() {
+        return c2b;
+    }
+
+    public final void setConverter(C2BConverter c2b) {
+        this.c2b = c2b;
+    }
+    
+    public final boolean isLogTimeEnabled() {
+        return logTime.isDebugEnabled();
+    }
+
+    public JkInputStream getInputStream() {
+        return jkIS;
+    }
+
+    /** Each context contains a number of byte[] buffers used for communication.
+     *  The C side will contain a char * equivalent - both buffers are long-lived
+     *  and recycled.
+     *
+     *  This will be called at init time. A long-lived global reference to the byte[]
+     *  will be stored in the C context.
+     */
+    public byte[] getBuffer( int id ) {
+        // We use a single buffer right now. 
+        if( msgs[id]==null ) {
+            return null;
+        }
+        return msgs[id].getBuffer();
+    }
+
+    /** Invoke a java hook. The xEnv is the representation of the current execution
+     *  environment ( the jni_env_t * )
+     */
+    public int execute() throws IOException {
+        int status=next.invoke(msgs[0], this);
+        return status;
+    }
+
+    // -------------------- Jni support --------------------
+    
+    /** Store native execution context data when this handler is called
+     *  from JNI. This will change on each call, represent temproary
+     *  call data.
+     */
+    public void setJniEnv( long xEnvP ) {
+            this.xEnvP=xEnvP;
+    }
+
+    public long getJniEnv() {
+        return xEnvP;
+    }
+    
+    /** The long-lived JNI context associated with this java context.
+     *  The 2 share pointers to buffers and cache data to avoid expensive
+     *  jni calls.
+     */
+    public void setJniContext( long cContext ) {
+        this.jkEndpointP=cContext;
+    }
+
+    public long getJniContext() {
+        return jkEndpointP;
+    }
+
+    public Object getControl() {
+        return control;
+    }
+
+    public void setControl(Object control) {
+        this.control = control;
+    }
+
+    // -------------------- Coyote Action implementation --------------------
+    
+    public void action(ActionCode actionCode, Object param) {
+        if( actionCode==ActionCode.ACTION_COMMIT ) {
+            if( log.isDebugEnabled() ) log.debug("COMMIT " );
+            Response res=(Response)param;
+
+            if(  res.isCommitted() ) {
+                if( log.isDebugEnabled() )
+                    log.debug("Response already committed " );
+            } else {
+                try {
+                    jkIS.appendHead( res );
+                } catch(IOException iex) {
+                    log.warn("Unable to send headers",iex);
+                    setStatus(JK_STATUS_ERROR);
+                }
+            }
+        } else if( actionCode==ActionCode.ACTION_RESET ) {
+            if( log.isDebugEnabled() )
+                log.debug("RESET " );
+            
+        } else if( actionCode==ActionCode.ACTION_CLIENT_FLUSH ) {
+            if( log.isDebugEnabled() ) log.debug("CLIENT_FLUSH " );
+            try {
+                source.flush( null, this );
+            } catch(IOException iex) {
+                // This is logged elsewhere, so debug only here
+                log.debug("Error during flush",iex);
+                Response res = (Response)param;
+                res.setErrorException(iex);
+                setStatus(JK_STATUS_ERROR);
+            }
+            
+        } else if( actionCode==ActionCode.ACTION_CLOSE ) {
+            if( log.isDebugEnabled() ) log.debug("CLOSE " );
+            
+            Response res=(Response)param;
+            if( getStatus()== JK_STATUS_CLOSED || getStatus() == JK_STATUS_ERROR) {
+                // Double close - it may happen with forward 
+                if( log.isDebugEnabled() ) log.debug("Double CLOSE - forward ? " + res.getRequest().requestURI() );
+                return;
+            }
+                 
+            if( !res.isCommitted() )
+                this.action( ActionCode.ACTION_COMMIT, param );
+            try {            
+                jkIS.endMessage();
+            } catch(IOException iex) {
+                log.warn("Error sending end packet",iex);
+                setStatus(JK_STATUS_ERROR);
+            }
+            if(getStatus() != JK_STATUS_ERROR) {
+                setStatus(JK_STATUS_CLOSED );
+            }
+
+            if( logTime.isDebugEnabled() ) 
+                logTime(res.getRequest(), res);
+        } else if( actionCode==ActionCode.ACTION_REQ_SSL_ATTRIBUTE ) {
+            Request req=(Request)param;
+
+            // Extract SSL certificate information (if requested)
+            MessageBytes certString = (MessageBytes)req.getNote(WorkerEnv.SSL_CERT_NOTE);
+            if( certString != null && !certString.isNull() ) {
+                ByteChunk certData = certString.getByteChunk();
+                ByteArrayInputStream bais = 
+                    new ByteArrayInputStream(certData.getBytes(),
+                                             certData.getStart(),
+                                             certData.getLength());
+ 
+                // Fill the first element.
+                X509Certificate jsseCerts[] = null;
+                try {
+                    CertificateFactory cf =
+                        CertificateFactory.getInstance("X.509");
+                    X509Certificate cert = (X509Certificate)
+                        cf.generateCertificate(bais);
+                    jsseCerts =  new X509Certificate[1];
+                    jsseCerts[0] = cert;
+                } catch(java.security.cert.CertificateException e) {
+                    log.error("Certificate convertion failed" , e );
+                    return;
+                }
+ 
+                req.setAttribute(SSLSupport.CERTIFICATE_KEY, 
+                                 jsseCerts);
+            }
+                
+        } else if( actionCode==ActionCode.ACTION_REQ_HOST_ATTRIBUTE ) {
+            Request req=(Request)param;
+
+            // If remoteHost not set by JK, get it's name from it's remoteAddr
+            if( req.remoteHost().isNull()) {
+                try {
+                    req.remoteHost().setString(InetAddress.getByName(
+                                               req.remoteAddr().toString()).
+                                               getHostName());
+                } catch(IOException iex) {
+                    if(log.isDebugEnabled())
+                        log.debug("Unable to resolve "+req.remoteAddr());
+                }
+            }
+        } else if( actionCode==ActionCode.ACTION_ACK ) {
+            if( log.isTraceEnabled() )
+                log.trace("ACK " );
+        } else if ( actionCode == ActionCode.ACTION_REQ_SET_BODY_REPLAY ) {
+            if( log.isTraceEnabled() )
+                log.trace("Replay ");
+            ByteChunk bc = (ByteChunk)param;
+            jkIS.setReplay(bc);
+            req.setContentLength(bc.getLength()); // reset so re-read
+        }
+    }
+    
+
+    private void logTime(Request req, Response res ) {
+        // called after the request
+        //            org.apache.coyote.Request req=(org.apache.coyote.Request)param;
+        //            Response res=req.getResponse();
+        String uri=req.requestURI().toString();
+        if( uri.indexOf( ".gif" ) >0 ) return;
+        
+        setLong( MsgContext.TIMER_POST_REQUEST, System.currentTimeMillis());
+        long t1= getLong( MsgContext.TIMER_PRE_REQUEST ) -
+            getLong( MsgContext.TIMER_RECEIVED );
+        long t2= getLong( MsgContext.TIMER_POST_REQUEST ) -
+            getLong( MsgContext.TIMER_PRE_REQUEST );
+        
+        logTime.debug("Time pre=" + t1 + "/ service=" + t2 + " " +
+                      res.getContentLength() + " " + 
+                      uri );
+    }
+
+    public void recycle() {
+        jkIS.recycle();
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/core/WorkerEnv.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/core/WorkerEnv.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/core/WorkerEnv.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,144 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.jk.core;
+
+import java.util.Hashtable;
+import javax.management.ObjectName;
+
+/**
+ * The controller object. It manages all other jk objects, acting as the root of
+ * the jk object model.
+ *
+ * @author Gal Shachor
+ * @author Henri Gomez [hgomez at apache.org]
+ * @author Dan Milstein [danmil at shore.net]
+ * @author Keith Wannamaker [Keith at Wannamaker.org]
+ * @author Kevin Seguin
+ * @author Costin Manolache
+ */
+public class WorkerEnv {
+
+    Hashtable properties;
+
+    public static final int ENDPOINT_NOTE=0;
+    public static final int REQUEST_NOTE=1;
+    public static final int SSL_CERT_NOTE=16;
+    int noteId[]=new int[4];
+    String noteName[][]=new String[4][];
+    private Object notes[]=new Object[32];
+
+    Hashtable handlersMap=new Hashtable();
+    JkHandler handlersTable[]=new JkHandler[20];
+    int handlerCount=0;
+    
+    // base dir for the jk webapp
+    String home;
+    int localId=0;
+    
+    public WorkerEnv() {
+        for( int i=0; i<noteId.length; i++ ) {
+            noteId[i]=7;
+            noteName[i]=new String[20];
+        }
+    }
+
+    public void setLocalId(int id) {
+        localId=id;
+    }
+    
+    public int getLocalId() {
+        return localId;
+    }
+    
+    public void setJkHome( String s ) {
+        home=s;
+    }
+
+    public String getJkHome() {
+        return home;
+    }
+    
+    public final Object getNote(int i ) {
+        return notes[i];
+    }
+
+    public final void setNote(int i, Object o ) {
+        notes[i]=o;
+    }
+
+    public int getNoteId( int type, String name ) {
+        for( int i=0; i<noteId[type]; i++ ) {
+            if( name.equals( noteName[type][i] ))
+                return i;
+        }
+        int id=noteId[type]++;
+        noteName[type][id]=name;
+        return id;
+    }
+
+    public void addHandler( String name, JkHandler w ) {
+        JkHandler oldH = getHandler(name);
+        if(oldH == w) {
+            // Already added
+            return;
+        }
+        w.setWorkerEnv( this );
+        w.setName( name );
+        handlersMap.put( name, w );
+        if( handlerCount > handlersTable.length ) {
+            JkHandler newT[]=new JkHandler[ 2 * handlersTable.length ];
+            System.arraycopy( handlersTable, 0, newT, 0, handlersTable.length );
+            handlersTable=newT;
+        }
+        if(oldH == null) {
+            handlersTable[handlerCount]=w;
+            w.setId( handlerCount );
+            handlerCount++;
+        } else {
+            handlersTable[oldH.getId()]=w;
+            w.setId(oldH.getId());
+        }
+
+        // Notify all other handlers of the new one
+        // XXX Could be a Coyote action ?
+        for( int i=0; i< handlerCount ; i++ ) {
+            handlersTable[i].addHandlerCallback( w );
+        }
+    }
+
+    public final JkHandler getHandler( String name ) {
+        return (JkHandler)handlersMap.get(name);
+    }
+
+    public final JkHandler getHandler( int id ) {
+        return handlersTable[id];
+    }
+
+    public final int getHandlerCount() {
+        return handlerCount;
+    }
+    
+    public ObjectName[] getHandlersObjectName() {
+        
+        ObjectName onames[]=new ObjectName[ handlerCount ];
+        for( int i=0; i<handlerCount; i++ ) {
+            onames[i]=handlersTable[i].getObjectName();
+        }
+        return onames;
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/core/package.html
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/core/package.html	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/core/package.html	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,16 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+  <title></title>
+</head>
+<body>
+<h2>Jk2 interfaces</h2>
+<p>Core interfaces for jk2, similar with the interfaces defined in the C
+side ( jk2/include ).<br>
+</p>
+<p>The implementations are in common/ and server/.<br>
+</p>
+<p><br>
+</p>
+</body>
+</html>

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/mbeans-descriptors.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/mbeans-descriptors.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/mbeans-descriptors.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,541 @@
+<?xml version="1.0"?>
+<!DOCTYPE mbeans-descriptors PUBLIC
+ "-//Apache Software Foundation//DTD Model MBeans Configuration File"
+ "http://jakarta.apache.org/commons/dtds/mbeans-descriptors.dtd">
+
+<!--
+     Descriptions of JMX MBeans for jk
+ -->
+
+<mbeans-descriptors>
+
+  <mbean name="ChannelSocket"
+         description="Socket channel"
+         domain="Catalina"
+         group="Jk"
+         type="org.apache.jk.common.ChannelSocket">
+
+    <attribute   name="port"
+          description="The port number on which we listen for ajp13 requests"
+                type="int"/>
+    <attribute   name="maxPort"
+          description="The max port number on which we listen for ajp13 requests"
+                type="int"/>
+    <attribute   name="address"
+          description="The IP address on which to bind"
+                 type="java.lang.String"/>
+    <attribute   name="maxSpareThreads"
+          description="The maximum number of unused request processing threads"
+                 type="int"/>
+    <attribute   name="maxThreads"
+          description="The maximum number of request processing threads to be created"
+                 type="int"/>
+    <attribute   name="minSpareThreads"
+          description="The number of request processing threads that will be created"
+                 type="int"/>
+    <attribute   name="tcpNoDelay"
+          description="Should we use TCP no delay?"
+                 type="boolean"/>
+    <attribute   name="soLinger"
+          description="Linger value on the incoming connection"
+                 type="int"/>
+    <attribute   name="soTimeout"
+          description="Socket timeout"
+                 type="int"/>
+    <attribute   name="requestCount"
+          description="current request count"
+                 type="int"
+            writeable="false"/>
+    <attribute   name="daemon"
+          description="are worker threads on daemon mode"
+                 type="boolean"
+            writeable="false"/>
+    <attribute name="packetSize"
+          description="The maximum AJP packet size"
+          type="int" />
+
+    <operation name="start"
+               description="Start, if server socket no create call init"
+               impact="ACTION"
+               returnType="void" />
+    <operation name="stop"
+               description="Stop"
+               impact="ACTION"
+               returnType="void" />
+    <operation name="pause"
+               description="Pause ajp socket, no new connection accepted"
+               impact="ACTION"
+               returnType="void"/>
+    <operation name="resume"
+               description="Resume socket for new connections"
+               impact="ACTION"
+               returnType="void"/>
+    <operation name="reinit"
+               description="Init and Destroy"
+               impact="ACTION"
+               returnType="void" />
+    <operation name="init"
+               description="Init"
+               impact="ACTION"
+               returnType="void" />
+    <operation name="destroy"
+               description="Destroy"
+               impact="ACTION"
+               returnType="void" />
+    <operation name="resetCounters"
+               description="reset request counter"
+               impact="ACTION"
+               returnType="void"/>
+
+
+  </mbean>
+
+  <mbean name="JkWorkerEnv"
+         description="Worker env for jk"
+         domain="Catalina"
+         group="Jk"
+         type="org.apache.jk.core.WorkerEnv">
+
+    <attribute name="localId"
+               description="If automatic port allocation is enabled, ChannelSocket will allocate ports sequentially. This is the sequence number"
+               type="java.lang.Integer"/>
+
+    <attribute name="jkHome"
+               description="Base directory for jk"
+               type="java.lang.String"/>
+
+    <attribute name="managedResource"
+               description="Access to the object"
+               type="java.lang.Object" writeable="false" />
+
+    <attribute name="handlersObjectName"
+               description="List of all jk handlers"
+               type="[Ljavax.management.ObjectName;"/>
+
+    <operation name="addHandler"
+               description="add a jk component"
+               returnType="void">
+      <parameter name="name"
+                 description="local name"
+                 type="java.lang.String"/>
+      <parameter name="handler"
+                 description="handler"
+                 type="org.apache.jk.core.JkHandler"/>
+    </operation>
+
+  </mbean>
+
+  <!-- Native connectors -->
+  <mbean name="JkAjp13"
+         description="native Ajp13 connector"
+         domain="Catalina"
+         group="Jk"
+         type="org.apache.jk.modjk.ajp13">
+
+    <attribute name="Id"
+               description="Internal id"
+               type="java.lang.String"/>
+
+    <attribute name="disabled"
+               description="State"
+               type="java.lang.Integer"/>
+
+    <attribute name="ver"
+               description="Generation"
+               type="java.lang.Integer"/>
+
+    <attribute name="debug"
+               description="Debug level"
+               type="java.lang.Integer"/>
+
+    <attribute name="lb_factor"
+               description=""
+               type="java.lang.Integer"/>
+    <attribute name="lb_value"
+               description=""
+               type="java.lang.Integer"/>
+    <attribute name="epCount"
+               description=""
+               type="java.lang.Integer"/>
+    <attribute name="graceful"
+               description=""
+               type="java.lang.Integer"/>
+
+    <attribute name="route"
+               description=""
+               type="java.lang.String"/>
+
+  </mbean>
+
+  <mbean name="JkChannelSocket"
+         description="native Ajp13 connector"
+         domain="Catalina"
+         group="Jk"
+         type="org.apache.jk.modjk.channel.socket">
+
+    <attribute name="Id"
+               description="Internal id"
+               type="java.lang.String"/>
+
+    <attribute name="disabled"
+               description="State"
+               type="java.lang.Integer"/>
+
+    <attribute name="ver"
+               description="Generation"
+               type="java.lang.Integer"/>
+
+    <attribute name="debug"
+               description="Debug level"
+               type="java.lang.Integer"/>
+
+  </mbean>
+
+  <mbean name="JkWorkerEnv" 
+         description=""
+         domain="Catalina"
+         group="Jk"
+         type="org.apache.jk.modjk.workerEnv">
+
+    <attribute name="Id"
+               description="Internal id"
+               type="java.lang.String"/>
+
+    <attribute name="disabled"
+               description="State"
+               type="java.lang.Integer"/>
+
+    <attribute name="ver"
+               description="Generation"
+               type="java.lang.Integer"/>
+
+    <attribute name="debug"
+               description="Debug level"
+               type="java.lang.Integer"/>
+
+  </mbean>
+
+  <mbean name="JkLoggerApache2" 
+         description=""
+         domain="Catalina"
+         group="Jk"
+         type="org.apache.jk.modjk.logger.apache2">
+    <attribute name="Id"
+               description="Internal id"
+               type="java.lang.String"/>
+
+    <attribute name="disabled"
+               description="State"
+               type="java.lang.Integer"/>
+
+    <attribute name="ver"
+               description="Generation"
+               type="java.lang.Integer"/>
+
+    <attribute name="debug"
+               description="Debug level"
+               type="java.lang.Integer"/>
+
+
+  </mbean>
+
+  <mbean name="JkUriMap" 
+         description=""
+         domain="Catalina"
+         group="Jk"
+         type="org.apache.jk.modjk.uriMap">
+    <attribute name="Id"
+               description="Internal id"
+               type="java.lang.String"/>
+
+    <attribute name="disabled"
+               description="State"
+               type="java.lang.Integer"/>
+
+    <attribute name="ver"
+               description="Generation"
+               type="java.lang.Integer"/>
+
+    <attribute name="debug"
+               description="Debug level"
+               type="java.lang.Integer"/>
+
+
+  </mbean>
+
+  <mbean name="JkConfig" 
+         description=""
+         domain="Catalina"
+         group="Jk"
+         type="org.apache.jk.modjk.config">
+    <attribute name="Id"
+               description="Internal id"
+               type="java.lang.String"/>
+
+    <attribute name="disabled"
+               description="State"
+               type="java.lang.Integer"/>
+
+    <attribute name="ver"
+               description="Generation"
+               type="java.lang.Integer"/>
+
+    <attribute name="debug"
+               description="Debug level"
+               type="java.lang.Integer"/>
+
+    <attribute name="file"
+               description="Config file"
+               type="java.lang.String"/>
+
+  </mbean>
+  <mbean name="JkShm" 
+         description=""
+         domain="Catalina"
+         group="Jk"
+         type="org.apache.jk.modjk.shm">
+    <attribute name="Id"
+               description="Internal id"
+               type="java.lang.String"/>
+
+    <attribute name="disabled"
+               description="State"
+               type="java.lang.Integer"/>
+
+    <attribute name="ver"
+               description="Generation"
+               type="java.lang.Integer"/>
+
+    <attribute name="debug"
+               description="Debug level"
+               type="java.lang.Integer"/>
+
+
+  </mbean>
+  <mbean name="JkUri" 
+         description=""
+         domain="Catalina"
+         group="Jk"
+         type="org.apache.jk.modjk.uri">
+
+    <attribute name="Id"
+               description="Internal id"
+               type="java.lang.String"/>
+
+    <attribute name="disabled"
+               description="State"
+               type="java.lang.Integer"/>
+
+    <attribute name="ver"
+               description="Generation"
+               type="java.lang.Integer"/>
+
+    <attribute name="debug"
+               description="Debug level"
+               type="java.lang.Integer"/>
+
+    <attribute name="host"
+               description="Uri components"
+               type="java.lang.String"/>
+    <attribute name="uri"
+               description="Uri"
+               type="java.lang.String"/>
+    <attribute name="path"
+               description="Uri"
+               type="java.lang.String"/>
+
+  </mbean>
+
+  <mbean name="JkVm" 
+         description=""
+         domain="Catalina"
+         group="Jk"
+         type="org.apache.jk.modjk.vm">
+    <attribute name="Id"
+               description="Internal id"
+               type="java.lang.String"/>
+
+    <attribute name="disabled"
+               description="State"
+               type="java.lang.Integer"/>
+
+    <attribute name="ver"
+               description="Generation"
+               type="java.lang.Integer"/>
+
+    <attribute name="debug"
+               description="Debug level"
+               type="java.lang.Integer"/>
+
+
+  </mbean>
+
+  <mbean name="JkChannelUn" 
+         description=""
+         domain="Catalina"
+         group="Jk"
+         type="org.apache.jk.modjk.channel.un">
+    <attribute name="Id"
+               description="Internal id"
+               type="java.lang.String"/>
+
+    <attribute name="disabled"
+               description="State"
+               type="java.lang.Integer"/>
+
+    <attribute name="ver"
+               description="Generation"
+               type="java.lang.Integer"/>
+
+    <attribute name="debug"
+               description="Debug level"
+               type="java.lang.Integer"/>
+
+
+  </mbean>
+
+  <mbean name="JkChannelJni" 
+         description=""
+         domain="Catalina"
+         group="Jk"
+         type="org.apache.jk.modjk.channel.jni">
+    <attribute name="Id"
+               description="Internal id"
+               type="java.lang.String"/>
+
+    <attribute name="disabled"
+               description="State"
+               type="java.lang.Integer"/>
+
+    <attribute name="ver"
+               description="Generation"
+               type="java.lang.Integer"/>
+
+    <attribute name="debug"
+               description="Debug level"
+               type="java.lang.Integer"/>
+
+
+  </mbean>
+
+  <mbean name="JkWorkerJni" 
+         description=""
+         domain="Catalina"
+         group="Jk"
+         type="org.apache.jk.modjk.worker.jni">
+    <attribute name="Id"
+               description="Internal id"
+               type="java.lang.String"/>
+
+    <attribute name="disabled"
+               description="State"
+               type="java.lang.Integer"/>
+
+    <attribute name="ver"
+               description="Generation"
+               type="java.lang.Integer"/>
+
+    <attribute name="debug"
+               description="Debug level"
+               type="java.lang.Integer"/>
+
+
+  </mbean>
+
+  <mbean name="JkStatus" 
+         description=""
+         domain="Catalina"
+         group="Jk"
+         type="org.apache.jk.modjk.status">
+    <attribute name="Id"
+               description="Internal id"
+               type="java.lang.String"/>
+
+    <attribute name="disabled"
+               description="State"
+               type="java.lang.Integer"/>
+
+    <attribute name="ver"
+               description="Generation"
+               type="java.lang.Integer"/>
+
+    <attribute name="debug"
+               description="Debug level"
+               type="java.lang.Integer"/>
+
+
+  </mbean>
+  <mbean name="JkHandlerResponse" 
+         description=""
+         domain="Catalina"
+         group="Jk"
+         type="org.apache.jk.modjk.handler.response">
+    <attribute name="Id"
+               description="Internal id"
+               type="java.lang.String"/>
+
+    <attribute name="disabled"
+               description="State"
+               type="java.lang.Integer"/>
+
+    <attribute name="ver"
+               description="Generation"
+               type="java.lang.Integer"/>
+
+    <attribute name="debug"
+               description="Debug level"
+               type="java.lang.Integer"/>
+
+
+  </mbean>
+  <mbean name="JkHandlerLogon" 
+         description=""
+         domain="Catalina"
+         group="Jk"
+         type="org.apache.jk.modjk.handler.logon">
+    <attribute name="Id"
+               description="Internal id"
+               type="java.lang.String"/>
+
+    <attribute name="disabled"
+               description="State"
+               type="java.lang.Integer"/>
+
+    <attribute name="ver"
+               description="Generation"
+               type="java.lang.Integer"/>
+
+    <attribute name="debug"
+               description="Debug level"
+               type="java.lang.Integer"/>
+
+
+  </mbean>
+
+  <mbean name="JkLb" 
+         description=""
+         domain="Catalina"
+         group="Jk"
+         type="org.apache.jk.modjk.lb">
+   
+    <attribute name="Id"
+               description="Internal id"
+               type="java.lang.String"/>
+
+    <attribute name="disabled"
+               description="State"
+               type="java.lang.Integer"/>
+
+    <attribute name="ver"
+               description="Generation"
+               type="java.lang.Integer"/>
+
+    <attribute name="debug"
+               description="Debug level"
+               type="java.lang.Integer"/>
+
+  </mbean>
+
+
+
+</mbeans-descriptors>

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/server/JkCoyoteHandler.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/server/JkCoyoteHandler.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/server/JkCoyoteHandler.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,227 @@
+/*
+ *  Copyright 1999-2005 The Apache Software Foundation
+ *
+ *  Licensed 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.jk.server;
+
+import java.io.IOException;
+import java.util.Iterator;
+
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+
+import org.apache.commons.modeler.Registry;
+import org.apache.coyote.Adapter;
+import org.apache.coyote.ProtocolHandler;
+import org.apache.coyote.Request;
+import org.apache.coyote.Response;
+import org.apache.coyote.RequestInfo;
+import org.apache.coyote.Constants;
+import org.apache.jk.common.HandlerRequest;
+import org.apache.jk.common.JkInputStream;
+import org.apache.jk.common.MsgAjp;
+import org.apache.jk.core.JkHandler;
+import org.apache.jk.core.Msg;
+import org.apache.jk.core.MsgContext;
+import org.apache.jk.core.WorkerEnv;
+import org.apache.tomcat.util.buf.ByteChunk;
+import org.apache.tomcat.util.buf.C2BConverter;
+import org.apache.tomcat.util.buf.MessageBytes;
+import org.apache.tomcat.util.http.HttpMessages;
+import org.apache.tomcat.util.http.MimeHeaders;
+import org.apache.tomcat.util.net.SSLSupport;
+
+/** Plugs Jk into Coyote. Must be named "type=JkHandler,name=container"
+ *
+ * jmx:notification-handler name="org.apache.jk.SEND_PACKET
+ * jmx:notification-handler name="org.apache.coyote.ACTION_COMMIT
+ */
+public class JkCoyoteHandler extends JkHandler implements ProtocolHandler {
+    protected static org.apache.commons.logging.Log log 
+        = org.apache.commons.logging.LogFactory.getLog(JkCoyoteHandler.class);
+    // Set debug on this logger to see the container request time
+
+    // ----------------------------------------------------------- DoPrivileged
+    private boolean paused = false;
+    int epNote;
+    Adapter adapter;
+    protected JkMain jkMain=null;
+
+    /** Set a property. Name is a "component.property". JMX should
+     * be used instead.
+     */
+    public void setProperty( String name, String value ) {
+        if( log.isTraceEnabled())
+            log.trace("setProperty " + name + " " + value );
+        getJkMain().setProperty( name, value );
+        properties.put( name, value );
+    }
+
+    public String getProperty( String name ) {
+        return properties.getProperty(name) ;
+    }
+
+    public Iterator getAttributeNames() {
+       return properties.keySet().iterator();
+    }
+
+    /** Pass config info
+     */
+    public void setAttribute( String name, Object value ) {
+        if( log.isDebugEnabled())
+            log.debug("setAttribute " + name + " " + value );
+        if( value instanceof String )
+            this.setProperty( name, (String)value );
+    }
+
+    /**
+     * Retrieve config info.
+     * Primarily for use with the admin webapp.
+     */   
+    public Object getAttribute( String name ) {
+        return getJkMain().getProperty(name);
+    }
+
+    /** The adapter, used to call the connector 
+     */
+    public void setAdapter(Adapter adapter) {
+        this.adapter=adapter;
+    }
+
+    public Adapter getAdapter() {
+        return adapter;
+    }
+
+    public JkMain getJkMain() {
+        if( jkMain == null ) {
+            jkMain=new JkMain();
+            jkMain.setWorkerEnv(wEnv);
+            
+        }
+        return jkMain;
+    }
+    
+    boolean started=false;
+    
+    /** Start the protocol
+     */
+    public void init() {
+        if( started ) return;
+
+        started=true;
+        
+        if( wEnv==null ) {
+            // we are probably not registered - not very good.
+            wEnv=getJkMain().getWorkerEnv();
+            wEnv.addHandler("container", this );
+        }
+
+        try {
+            // jkMain.setJkHome() XXX;
+            
+            getJkMain().init();
+
+        } catch( Exception ex ) {
+            log.error("Error during init",ex);
+        }
+    }
+
+    public void start() {
+        try {
+            if( oname != null && getJkMain().getDomain() == null) {
+                try {
+                    ObjectName jkmainOname = 
+                        new ObjectName(oname.getDomain() + ":type=JkMain");
+                    Registry.getRegistry(null, null)
+                        .registerComponent(getJkMain(), jkmainOname, "JkMain");
+                } catch (Exception e) {
+                    log.error( "Error registering jkmain " + e );
+                }
+            }
+            getJkMain().start();
+        } catch( Exception ex ) {
+            log.error("Error during startup",ex);
+        }
+    }
+
+    public void pause() throws Exception {
+        if(!paused) {
+            paused = true;
+            getJkMain().pause();
+        }
+    }
+
+    public void resume() throws Exception {
+        if(paused) {
+            paused = false;
+            getJkMain().resume();
+        }
+    }
+
+    public void destroy() {
+        if( !started ) return;
+
+        started = false;
+        getJkMain().stop();
+    }
+
+    
+    // -------------------- Jk handler implementation --------------------
+    // Jk Handler mehod
+    public int invoke( Msg msg, MsgContext ep ) 
+        throws IOException {
+        if( ep.isLogTimeEnabled() ) 
+            ep.setLong( MsgContext.TIMER_PRE_REQUEST, System.currentTimeMillis());
+        
+        Request req=ep.getRequest();
+        Response res=req.getResponse();
+
+        if( log.isDebugEnabled() )
+            log.debug( "Invoke " + req + " " + res + " " + req.requestURI().toString());
+        
+        res.setNote( epNote, ep );
+        ep.setStatus( MsgContext.JK_STATUS_HEAD );
+        RequestInfo rp = req.getRequestProcessor();
+        rp.setStage(Constants.STAGE_SERVICE);
+        try {
+            adapter.service( req, res );
+        } catch( Exception ex ) {
+            log.info("Error servicing request " + req,ex);
+        }
+        if(ep.getStatus() != MsgContext.JK_STATUS_CLOSED) {
+            res.finish();
+        }
+
+        req.recycle();
+        req.updateCounters();
+        res.recycle();
+        ep.recycle();
+        if( ep.getStatus() == MsgContext.JK_STATUS_ERROR ) {
+            return ERROR;
+        }
+        ep.setStatus( MsgContext.JK_STATUS_NEW );
+        rp.setStage(Constants.STAGE_KEEPALIVE);
+        return OK;
+    }
+
+
+    public ObjectName preRegister(MBeanServer server,
+                                  ObjectName oname) throws Exception
+    {
+        // override - we must be registered as "container"
+        this.name="container";        
+        return super.preRegister(server, oname);
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/server/JkMain.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/server/JkMain.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/java/org/apache/jk/server/JkMain.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,694 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.jk.server;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Properties;
+import java.util.StringTokenizer;
+import java.util.Vector;
+
+import javax.management.MBeanRegistration;
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+
+import org.apache.commons.modeler.Registry;
+import org.apache.jk.core.JkHandler;
+import org.apache.jk.core.WorkerEnv;
+import org.apache.tomcat.util.IntrospectionUtils;
+
+/** Main class used to startup and configure jk. It manages the conf/jk2.properties file
+ *  and is the target of JMX proxy.
+ *
+ *  It implements a policy of save-on-change - whenever a property is changed at
+ *  runtime the jk2.properties file will be overriden. 
+ *
+ *  You can edit the config file when tomcat is stoped ( or if you don't use JMX or
+ *  other admin tools ).
+ *
+ *  The format of jk2.properties:
+ *  <dl>
+ *   <dt>TYPE[.LOCALNAME].PROPERTY_NAME=VALUE
+ *   <dd>Set a property on the associated component. TYPE will be used to
+ *   find the class name and instantiate the component. LOCALNAME allows
+ *   multiple instances. In JMX mode, TYPE and LOCALNAME will form the
+ *   JMX name ( eventually combined with a 'jk2' component )
+ *
+ *   <dt>NAME=VALUE
+ *   <dd>Define global properties to be used in ${} substitutions
+ *
+ *   <dt>class.COMPONENT_TYPE=JAVA_CLASS_NAME
+ *   <dd>Adds a new 'type' of component. We predefine all known types.
+ * </dl>
+ *
+ * Instances are created the first time a component name is found. In addition,
+ * 'handler.list' property will override the list of 'default' components that are
+ * loaded automatically.
+ *
+ *  Note that the properties file is just one (simplistic) way to configure jk. We hope
+ *  to see configs based on registry, LDAP, db, etc. ( XML is not necesarily better )
+ * 
+ * @author Costin Manolache
+ */
+public class JkMain implements MBeanRegistration
+{
+    WorkerEnv wEnv;
+    String propFile;
+    Properties props=new Properties();
+
+    Properties modules=new Properties();
+    boolean modified=false;
+    boolean started=false;
+    boolean saveProperties=false;
+
+    public JkMain()
+    {
+        JkMain.jkMain=this;
+        modules.put("channelSocket", "org.apache.jk.common.ChannelSocket");
+        modules.put("channelNioSocket", "org.apache.jk.common.ChannelNioSocket");
+        modules.put("channelUnix", "org.apache.jk.common.ChannelUn");
+        modules.put("channelJni", "org.apache.jk.common.ChannelJni");
+        modules.put("apr", "org.apache.jk.apr.AprImpl");
+        modules.put("mx", "org.apache.jk.common.JkMX");
+        modules.put("modeler", "org.apache.jk.common.JkModeler");
+        modules.put("shm", "org.apache.jk.common.Shm");
+        modules.put("request","org.apache.jk.common.HandlerRequest");
+        modules.put("container","org.apache.jk.common.HandlerRequest");
+        modules.put("modjk","org.apache.jk.common.ModJkMX");
+
+    }
+
+    public static JkMain getJkMain() {
+        return jkMain;
+    }
+
+    private static String DEFAULT_HTTPS="com.sun.net.ssl.internal.www.protocol";
+    private void initHTTPSUrls() {
+        try {
+            // 11657: if only ajp is used, https: redirects need to work ( at least for 1.3+)
+            String value = System.getProperty("java.protocol.handler.pkgs");
+            if (value == null) {
+                value = DEFAULT_HTTPS;
+            } else if (value.indexOf(DEFAULT_HTTPS) >= 0  ) {
+                return; // already set
+            } else {
+                value += "|" + DEFAULT_HTTPS;
+            }
+            System.setProperty("java.protocol.handler.pkgs", value);
+        } catch(Exception ex ) {
+            log.info("Error adding SSL Protocol Handler",ex);
+        }
+    }
+
+    // -------------------- Setting --------------------
+    
+    /** Load a .properties file into and set the values
+     *  into jk2 configuration.
+     */
+    public void setPropertiesFile( String p  ) {
+        propFile=p;
+        if( started ) {
+            loadPropertiesFile();
+        }
+    }
+
+    public String getPropertiesFile() {
+        return propFile;
+    }
+
+    public void setSaveProperties( boolean b ) {
+        saveProperties=b;
+    }
+
+    /** Set a name/value as a jk2 property
+     */
+    public void setProperty( String n, String v ) {
+        if( "jkHome".equals( n ) ) {
+            setJkHome( v );
+        } 
+        if( "propertiesFile".equals( n ) ) {
+            setPropertiesFile( v );
+        }
+        props.put( n, v );
+        if( started ) {
+            processProperty( n, v );
+            saveProperties();
+        }
+    }
+    /**
+     * Retrieve a property.
+     */
+    public Object getProperty(String name) {
+        String alias = (String)replacements.get(name);
+        Object result = null;
+        if(alias != null) {
+            result = props.get(alias);
+        }
+        if(result == null) {
+            result = props.get(name);
+        }
+        return result;
+    }
+    /**
+     * Set the <code>channelClassName</code> that will used to connect to
+     * httpd.
+     */
+    public void setChannelClassName(String name) {
+        props.put( "handler.channel.className",name);
+    }
+
+    public String getChannelClassName() {
+        return (String)props.get( "handler.channel.className");
+    }
+
+    /**
+     * Set the <code>workerClassName</code> that will handle the request.
+     * ( sort of 'pivot' in axis :-)
+     */
+    public void setWorkerClassName(String name) {
+        props.put( "handler.container.className",name);
+    }
+
+    public String getWorkerClassName() {
+        return (String)props.get( "handler.container.className");
+    }
+
+    /** Set the base dir of jk2. ( including WEB-INF if in a webapp ).
+     *  We'll try to guess it from classpath if none is set ( for
+     *  example on command line ), but if in a servlet environment
+     *  you need to use Context.getRealPath or a system property or
+     *  set it expliciltey.
+     */
+    public void setJkHome( String s ) {
+        getWorkerEnv().setJkHome(s);
+    }
+
+    public String getJkHome() {
+        return getWorkerEnv().getJkHome();
+    }
+
+    String out;
+    String err;
+    File propsF;
+    
+    public void setOut( String s ) {
+        this.out=s;
+    }
+
+    public String getOut() {
+        return this.out;
+    }
+
+    public void setErr( String s ) {
+        this.err=s;
+    }
+    
+    public String getErr() {
+        return this.err;
+    }
+    
+    // -------------------- Initialization --------------------
+    
+    public void init() throws IOException
+    {
+        long t1=System.currentTimeMillis();
+        if(null != out) {
+            PrintStream outS=new PrintStream(new FileOutputStream(out));
+            System.setOut(outS);
+        }
+        if(null != err) {
+            PrintStream errS=new PrintStream(new FileOutputStream(err));
+            System.setErr(errS);
+        }
+
+        String home=getWorkerEnv().getJkHome();
+        if( home==null ) {
+            // XXX use IntrospectionUtil to find myself
+            this.guessHome();
+        }
+        home=getWorkerEnv().getJkHome();
+        if( home==null ) {
+            log.info( "Can't find home, jk2.properties not loaded");
+        }
+        if(log.isDebugEnabled())
+            log.debug("Starting Jk2, base dir= " + home  );
+        loadPropertiesFile();
+
+        String initHTTPS = (String)props.get("class.initHTTPS");
+        if("true".equalsIgnoreCase(initHTTPS)) {
+            initHTTPSUrls();
+        }
+
+        long t2=System.currentTimeMillis();
+        initTime=t2-t1;
+    }
+    
+    static String defaultHandlers[]= { "request",
+                                       "container",
+                                       "channelSocket"};
+    /*
+     static String defaultHandlers[]= { "apr",
+                                       "shm",
+                                       "request",
+                                       "container",
+                                       "channelSocket",
+                                       "channelJni",
+                                       "channelUnix"};
+    */
+    
+    public void stop() 
+    {
+        for( int i=0; i<wEnv.getHandlerCount(); i++ ) {
+            if( wEnv.getHandler(i) != null ) {
+                try {
+                    wEnv.getHandler(i).destroy();
+                } catch( IOException ex) {
+                    log.error("Error stoping " + wEnv.getHandler(i).getName(), ex);
+                }
+            }
+        }
+
+        started=false;
+    }
+    
+    public void start() throws IOException
+    {
+        long t1=System.currentTimeMillis();
+        // We must have at least 3 handlers:
+        // channel is the 'transport'
+        // request is the request processor or 'global' chain
+        // container is the 'provider'
+        // Additional handlers may exist and be used internally
+        // or be chained to create one of the standard handlers 
+
+        String handlers[]=defaultHandlers;
+        // backward compat
+        String workers=props.getProperty( "handler.list", null );
+        if( workers!=null ) {
+            handlers= split( workers, ",");
+        }
+
+        // Load additional component declarations
+        processModules();
+        
+        for( int i=0; i<handlers.length; i++ ) {
+            String name= handlers[i];
+            JkHandler w=getWorkerEnv().getHandler( name );
+            if( w==null ) {
+                newHandler( name, "", name );
+            }
+        }
+
+        // Process properties - and add aditional handlers.
+        processProperties();
+
+        for( int i=0; i<wEnv.getHandlerCount(); i++ ) {
+            if( wEnv.getHandler(i) != null ) {
+                try {
+                    wEnv.getHandler(i).init();
+                } catch( IOException ex) {
+                    if( "apr".equals(wEnv.getHandler(i).getName() )) {
+                        log.info( "APR not loaded, disabling jni components: " + ex.toString());
+                    } else {
+                        log.error( "error initializing " + wEnv.getHandler(i).getName(), ex );
+                    }
+                }
+            }
+        }
+
+        started=true;
+        long t2=System.currentTimeMillis();
+        startTime=t2-t1;
+
+        this.saveProperties();
+        log.info("Jk running ID=" + wEnv.getLocalId() + " time=" + initTime + "/" + startTime +
+                 "  config=" + propFile);
+    }
+
+    // -------------------- Usefull methods --------------------
+    
+    public WorkerEnv getWorkerEnv() {
+        if( wEnv==null ) { 
+            wEnv=new WorkerEnv();
+        }
+        return wEnv;
+    }
+
+    public void setWorkerEnv(WorkerEnv wEnv) {
+        this.wEnv = wEnv;
+    }
+
+    /* A bit of magic to support workers.properties without giving
+       up the clean get/set
+    */
+    public void setBeanProperty( Object target, String name, String val ) {
+        if( val!=null )
+            val=IntrospectionUtils.replaceProperties( val, props, null );
+        if( log.isDebugEnabled())
+            log.debug( "setProperty " + target + " " + name + "=" + val );
+        
+        IntrospectionUtils.setProperty( target, name, val );
+    }
+
+    /* 
+     * Set a handler property
+     */
+    public void setPropertyString( String handlerN, String name, String val ) {
+        if( log.isDebugEnabled() )
+            log.debug( "setProperty " + handlerN + " " + name + "=" + val );
+        Object target=getWorkerEnv().getHandler( handlerN );
+
+        setBeanProperty( target, name, val );
+        if( started ) {
+            saveProperties();
+        }
+
+    }
+
+    /** The time it took to initialize jk ( ms)
+     */
+    public long getInitTime() {
+        return initTime;
+    }
+
+    /** The time it took to start jk ( ms )
+     */
+    public long getStartTime() {
+        return startTime;
+    }
+    
+    // -------------------- Main --------------------
+
+    long initTime;
+    long startTime;
+    static JkMain jkMain=null;
+
+    public static void main(String args[]) {
+        try {
+            if( args.length == 1 &&
+                ( "-?".equals(args[0]) || "-h".equals( args[0])) ) {
+                System.out.println("Usage: ");
+                System.out.println("  JkMain [args]");
+                System.out.println();
+                System.out.println("  Each bean setter corresponds to an arg ( like -debug 10 )");
+                System.out.println("  System properties:");
+                System.out.println("    jk2.home    Base dir of jk2");
+                return;
+            }
+
+            jkMain=new JkMain();
+
+            IntrospectionUtils.processArgs( jkMain, args, new String[] {},
+                                            null, new Hashtable());
+
+            jkMain.init();
+            jkMain.start();
+        } catch( Exception ex ) {
+            log.warn("Error running",ex);
+        }
+    }
+
+    // -------------------- Private methods --------------------
+
+
+    private boolean checkPropertiesFile() {
+        if(propFile == null) {
+            return false;
+        }
+        propsF = new File(propFile);
+        if(!propsF.isAbsolute()) {
+            String home = getWorkerEnv().getJkHome();
+            if( home == null ) {
+                return false;
+            }
+            propsF = new File(home, propFile);
+        }
+        return propsF.exists();
+    }
+            
+    private void loadPropertiesFile() {
+        if(!checkPropertiesFile()) {
+            return;
+        }
+
+        try {
+            props.load( new FileInputStream(propsF) );
+        } catch(IOException ex ){
+            log.warn("Unable to load properties from "+propsF,ex);
+        }
+    }
+
+    public  void saveProperties() {
+        if( !saveProperties) return;
+        
+        if(propsF == null) {
+            log.warn("No properties file specified. Unable to save");
+            return;
+        }
+        // Temp - to check if it works
+        File outFile= new File(propsF.getParentFile(), propsF.getName()+".save");
+        log.debug("Saving properties " + outFile );
+        try {
+            props.store( new FileOutputStream(outFile), "AUTOMATICALLY GENERATED" );
+        } catch(IOException ex ){
+            log.warn("Unable to save to "+outFile,ex);
+        }
+    }
+
+    // translate top-level keys ( from coyote or generic ) into component keys
+    static Hashtable replacements=new Hashtable();
+    static {
+        replacements.put("port","channelSocket.port");
+        replacements.put("maxThreads", "channelSocket.maxThreads");   
+        replacements.put("minSpareThreads", "channelSocket.minSpareThreads");   
+        replacements.put("maxSpareThreads", "channelSocket.maxSpareThreads");   
+        replacements.put("backlog", "channelSocket.backlog");   
+        replacements.put("tcpNoDelay", "channelSocket.tcpNoDelay");
+        replacements.put("soTimeout", "channelSocket.soTimeout");
+        replacements.put("timeout", "channelSocket.timeout");
+        replacements.put("address", "channelSocket.address");            
+        replacements.put("bufferSize", "channelSocket.bufferSize");
+        replacements.put("tomcatAuthentication", "request.tomcatAuthentication");            
+        replacements.put("packetSize", "channelSocket.packetSize");
+    }
+
+    private void preProcessProperties() {
+        Enumeration keys=props.keys();
+        Vector v=new Vector();
+        
+        while( keys.hasMoreElements() ) {
+            String key=(String)keys.nextElement();          
+            Object newName=replacements.get(key);
+            if( newName !=null ) {
+                v.addElement(key);
+            }
+        }
+        keys=v.elements();
+        while( keys.hasMoreElements() ) {
+            String key=(String)keys.nextElement();
+            Object propValue=props.getProperty( key );
+            String replacement=(String)replacements.get(key);
+            props.put(replacement, propValue);
+            if( log.isDebugEnabled()) 
+                log.debug("Substituting " + key + " " + replacement + " " + 
+                    propValue);
+        }
+    }
+    
+    private void processProperties() {
+        preProcessProperties();
+        Enumeration keys=props.keys();
+
+        while( keys.hasMoreElements() ) {
+            String name=(String)keys.nextElement();
+            String propValue=props.getProperty( name );
+
+            processProperty( name, propValue );
+        }
+    }
+
+    private void processProperty(String name, String propValue) {
+        String type=name;
+        String fullName=name;
+        String localName="";
+        String propName="";
+        // ignore
+        if( name.startsWith("key.")) return;
+
+        int dot=name.indexOf(".");
+        int lastDot=name.lastIndexOf(".");
+        if( dot > 0 ) {
+            type=name.substring(0, dot );
+            if( dot != lastDot ) {
+                localName=name.substring( dot + 1, lastDot );
+                fullName=type + "." + localName;
+            } else {
+                fullName=type;
+            }
+            propName=name.substring( lastDot+1);
+        } else {
+            return;
+        }
+        
+        if( log.isDebugEnabled() )
+            log.debug( "Processing " + type + ":" + localName + ":" + fullName + " " + propName );
+        if( "class".equals( type ) || "handler".equals( type ) ) {
+            return;
+        }
+        
+        JkHandler comp=getWorkerEnv().getHandler( fullName );
+        if( comp==null ) {
+            comp=newHandler( type, localName, fullName );
+        }
+        if( comp==null )
+            return;
+        
+        if( log.isDebugEnabled() ) 
+            log.debug("Setting " + propName + " on " + fullName + " " + comp);
+        this.setBeanProperty( comp, propName, propValue );
+    }
+
+    private JkHandler newHandler( String type, String localName, String fullName )
+    {
+        JkHandler handler;
+        String classN=modules.getProperty(type);
+        if( classN == null ) {
+            log.error("No class name for " + fullName + " " + type );
+            return null;
+        }
+        try {
+            Class channelclass = Class.forName(classN);
+            handler=(JkHandler)channelclass.newInstance();
+        } catch (Throwable ex) {
+            handler=null;
+            log.error( "Can't create " + fullName, ex );
+            return null;
+        }
+        if( this.domain != null ) {
+            try {
+                ObjectName handlerOname = new ObjectName
+                    (this.domain + ":" + "type=JkHandler,name=" + fullName);
+                Registry.getRegistry(null, null).registerComponent(handler, handlerOname, classN);
+            } catch (Exception e) {
+                log.error( "Error registering " + fullName, e );
+            }
+
+        }
+        wEnv.addHandler( fullName, handler );
+        return handler;
+    }
+
+    private void processModules() {
+        Enumeration keys=props.keys();
+        int plen=6;
+        
+        while( keys.hasMoreElements() ) {
+            String k=(String)keys.nextElement();
+            if( ! k.startsWith( "class." ) )
+                continue;
+
+            String name= k.substring( plen );
+            String propValue=props.getProperty( k );
+
+            if( log.isDebugEnabled()) log.debug("Register " + name + " " + propValue );
+            modules.put( name, propValue );
+        }
+    }
+
+    private String[] split(String s, String delim ) {
+         Vector v=new Vector();
+        StringTokenizer st=new StringTokenizer(s, delim );
+        while( st.hasMoreTokens() ) {
+            v.addElement( st.nextToken());
+        }
+        String res[]=new String[ v.size() ];
+        for( int i=0; i<res.length; i++ ) {
+            res[i]=(String)v.elementAt(i);
+        }
+        return res;
+    }
+
+    // guessing home
+    private static String CNAME="org/apache/jk/server/JkMain.class";
+
+    private void guessHome() {
+        String home= wEnv.getJkHome();
+        if( home != null )
+            return;
+        home=IntrospectionUtils.guessInstall( "jk2.home","jk2.home",
+                                              "tomcat-jk2.jar", CNAME );
+        if( home != null ) {
+            log.info("Guessed home " + home );
+            wEnv.setJkHome( home );
+        }
+    }
+
+    static org.apache.commons.logging.Log log=
+        org.apache.commons.logging.LogFactory.getLog( JkMain.class );
+
+    protected String domain;
+    protected ObjectName oname;
+    protected MBeanServer mserver;
+
+    public ObjectName getObjectName() {
+        return oname;
+    }
+
+    public String getDomain() {
+        return domain;
+    }
+
+    public ObjectName preRegister(MBeanServer server,
+                                  ObjectName name) throws Exception {
+        oname=name;
+        mserver=server;
+        domain=name.getDomain();
+        return name;
+    }
+
+    public void postRegister(Boolean registrationDone) {
+    }
+
+    public void preDeregister() throws Exception {
+    }
+
+    public void postDeregister() {
+    }
+
+    public void pause() throws Exception {
+        for( int i=0; i<wEnv.getHandlerCount(); i++ ) {
+            if( wEnv.getHandler(i) != null ) {
+                wEnv.getHandler(i).pause();
+            }
+        }
+    }
+
+    public void resume() throws Exception {
+        for( int i=0; i<wEnv.getHandlerCount(); i++ ) {
+            if( wEnv.getHandler(i) != null ) {
+                wEnv.getHandler(i).resume();
+            }
+        }
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkant/ant.tasks
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkant/ant.tasks	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkant/ant.tasks	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,3 @@
+so=org.apache.jk.ant.SoTask
+libtoolCompile=org.apache.jk.ant.compilers.LibtoolCompiler
+ccCompile=org.apache.jk.ant.compilers.CcCompiler

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkant/buildJakarta.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkant/buildJakarta.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkant/buildJakarta.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,237 @@
+<?xml version="1.0" ?>
+<!-- EXPERIMENTAL - JUST AN EXAMPLE ON HOW TO USE GCJ TASK -->
+<!-- MAY REQUIRE SMALL/TRIVIAL MODIFICATION IN SOURCES -->
+<!-- REQUIRES GCJ FROM CVS - 3.0.1 DOESN'T WORK -->
+<project name="tomcat_gcj" default="main" basedir=".">
+
+  <description>Native build for tomcat</description>
+  
+  <property file="${user.home}/.ant.properties" />
+  <property file="${user.home}/build.properties" />
+  <property file="build.properties" />
+
+  <property name="LIB" value="/opt/java" />
+  <property name="tomcat.src" value="/ws/33" />
+  <property name="ant.src" value="/ws/jakarta/jakarta-ant" />
+  <property name="crimson.src" value="/ws/jakarta/xml-crimson" />
+  <property name="xmlcommons.src" value="/ws/jakarta/xml-commons" />
+  <property name="servletapi.src" value="/ws/jakarta/jakarta-servletapi" />
+  <path id="jkant" >
+    <pathelement location="build/jkant.jar"/>
+  </path>
+
+  <property name="native.dir" location="." />
+
+  <property name="so.debug" value="true" />
+  <property name="so.optimize" value="true" />
+  <property name="so.profile" value="false" />
+  
+  <!-- ==================== Targets ==================== -->
+
+  <target name="main" depends="all">
+  </target>
+  
+  <target name="init" >
+    <taskdef resource="META-INF/ant.tasks" 
+	     classpathref="jkant" />
+    <mkdir dir="build"/>
+    <mkdir dir="build/obj"/>
+  </target>
+
+  <target name="all" depends="init,org-apache-crimson,javax-servlet,javax-xml,org-apache-tomcat,examples,link" />  
+
+  <target name="link" >
+    <exec dir="build/obj" executable="gcj">
+      <arg value="--main=org.apache.tomcat.startup.EmbededTomcat"/>
+      <arg value="-Dtomcat.home=."/>
+      <arg value="-Djavax.xml.parsers.SAXParserFactory=org.apache.crimson.jaxp.SAXParserFactoryImpl" />
+      <arg value="-g"/>
+      <arg value="-o"/>
+      <arg value="tomcat"/>
+      <arg value="lib-org-apache-tomcat.so"/>
+      <arg value="lib-javax-servlet.so"/>
+      <arg value="lib-org-apache-crimson.so"/>
+      <arg value="lib-javax-xml.so"/>
+      <arg value="lib-examples.so"/>
+    </exec>
+  </target>
+
+  <target name="org-apache-tomcat" depends="init">
+    <property name="build.compiler.cc" value="gcj" />
+    <so sofile="lib-org-apache-tomcat" 
+	buildDir="build/obj" 
+	optimize="${so.optimize}"
+	debug="${so.debug}"
+	profile="${so.profile}"
+	taskDebug="0"
+	>
+      <src dir="${tomcat.src}/src/share">
+	<include name="**/*.java" />
+	<include name="**/*.properties" />
+	<include name="**/*.dtd" />
+	<exclude name="org/apache/tomcat/util/compat/JSSECertCompat.java" />
+	<exclude name="org/apache/tomcat/util/net/SSLSocketFactory.java" />
+	<exclude name="org/apache/tomcat/util/test/**/*.java" />
+	<exclude name="org/apache/tomcat/modules/server/JNI*.java" />
+	<exclude name="org/apache/jasper/**/*.java" /> 
+	<exclude name="org/apache/jasper/compiler/CommandLineCompiler.java" />
+	<exclude name="org/apache/jasper/compiler/SunJavaCompiler.java" />
+      </src>
+      <src dir="${tomcat.src}/src/facade22">
+	<include name="**/*.java" />
+	<exclude name="org/apache/tomcat/facade/JspInterceptor.java" />
+	<exclude name="org/apache/tomcat/facade/TagPoolManagerInterceptor.java" />
+      </src>
+      <includes>
+        <include name="${LIB}/crimson-1.1.3/crimson.jar" />
+        <include name="${tomcat.src}/src/share" />
+        <include name="${tomcat.src}/src/facade22" />
+        <include name="${LIB}/jakarta-servletapi-22/lib/servlet.jar" />
+      </includes>
+    </so>
+  </target>
+
+  <target name="ant" depends="init">
+    <property name="build.compiler.cc" value="gcj" />
+    <so sofile="lib-org-apache-tools-ant" 
+	buildDir="build/obj" 
+	optimize="${so.optimize}"
+	debug="${so.debug}"
+	profile="${so.profile}"
+	taskDebug="0"
+	>
+      <src dir="${ant.src}/src/main">
+	<include name="**/*.java" />
+	<include name="**/*.properties" />
+	<include name="**/*.txt" />
+	<include name="**/*.dtd" />
+	<exclude name="org/apache/tools/ant/taskdefs/optional/**" />
+	<exclude name="org/apache/tools/ant/types/optional/**" />
+	<exclude name="org/apache/tools/ant/util/depend/**" />
+	<exclude name="org/apache/tools/ant/util/regexp/JakartaOroMatcher.java" />
+	<exclude name="org/apache/tools/ant/util/regexp/JakartaRegexpMatcher.java" />
+	<exclude name="org/apache/tools/ant/util/regexp/Jdk14RegexpMatcher.java" />
+	<exclude name="org/apache/tools/ant/util/regexp/Jdk14RegexpRegexp.java" />
+	<exclude name="org/apache/tools/ant/util/regexp/JakartaOroRegexp.java" />
+	<exclude name="org/apache/tools/ant/util/regexp/JakartaRegexpRegexp.java" />
+	<exclude name="org/apache/tools/ant/listener/Log4jListener.java" />
+      </src>
+      <includes>
+        <include name="${LIB}/crimson-1.1.3/crimson.jar" />
+        <include name="${ant.src}/src/main" />
+      </includes>
+    </so>
+    <exec dir="build/obj" executable="gcj">
+      <arg value="--main=org.apache.tools.ant.Main"/>
+      <arg value="-Dant.home=."/>
+      <arg value="-Djavax.xml.parsers.SAXParserFactory=org.apache.crimson.jaxp.SAXParserFactoryImpl" />
+      <arg value="-g"/>
+      <arg value="-o"/>
+      <arg value="ant"/>
+      <arg value="lib-org-apache-tools-ant.so"/>
+      <arg value="lib-org-apache-crimson.so"/>
+      <arg value="lib-javax-xml.so"/>
+    </exec>
+  </target>
+
+  <target name="examples" depends="init">
+    <property name="build.compiler.cc" value="gcj" />
+    <so sofile="lib-examples" 
+	buildDir="build/obj" 
+	optimize="${so.optimize}"
+	debug="${so.debug}"
+	profile="${so.profile}"
+	taskDebug="0"
+	>
+      <src dir="${tomcat.src}/build/tomcat/webapps/examples/WEB-INF/classes">
+	<include name="**/*.java" />
+      </src>
+      <includes>
+        <include name="${LIB}/crimson-1.1.3/crimson.jar" />
+        <include name="${tomcat.src}/src/share" />
+        <include name="${tomcat.src}/src/facade22" />
+        <include name="${tomcat.src}/build/tomcat/webapps/examples/WEB-INF/classes" />
+        <include name="${LIB}/jakarta-servletapi-22/lib/servlet.jar" />
+      </includes>
+    </so>
+  </target>
+
+  <target name="javax-servlet" depends="init">
+    <property name="build.compiler.cc" value="gcj" />
+    <so sofile="lib-javax-servlet" 
+	buildDir="build/obj" 
+	optimize="${so.optimize}"
+	debug="${so.debug}"
+	profile="${so.profile}"
+	taskDebug="0"
+	>
+      <src dir="${servletapi.src}/src/share">
+	<include name="**/*.java" />
+	<include name="**/*.properties" />
+      </src>
+      <includes>
+        <include name="${servletapi.src}/src/share" />
+      </includes>
+    </so>
+  </target>
+
+  <target name="org-apache-crimson" depends="init">
+    <property name="build.compiler.cc" value="gcj" />
+    <so sofile="lib-org-apache-crimson" 
+	buildDir="build/obj" 
+	optimize="${so.optimize}"
+	debug="${so.debug}"
+	profile="${so.profile}"
+	taskDebug="0"
+	>
+      <src dir="${crimson.src}/src">
+	<include name="**/*.java" />
+	<include name="**/*.properties" />
+	<include name="META-INF/**" />
+	<exclude name="org/w3c/**" />
+	<exclude name="org/xml/**" />
+      </src>
+      <includes>
+        <include name="${crimson.src}/src" />
+        <include name="${xmlcommons.src}/java/external/src" />
+      </includes>
+    </so>
+  </target>
+
+  <target name="javax-xml" depends="init">
+    <property name="build.compiler.cc" value="gcj" />
+    <so sofile="lib-javax-xml" 
+	buildDir="build/obj" 
+	optimize="${so.optimize}"
+	debug="${so.debug}"
+	profile="${so.profile}"
+	taskDebug="0"
+	>
+      <src dir="${xmlcommons.src}/java/external/src">
+	<include name="javax/xml/**/*.java" />
+	<include name="**/*.properties" />
+	<exclude name="org/**" />
+      </src>
+      <includes>
+        <include name="${crimson.src}/src" />
+        <include name="${xmlcommons.src}/java/external/src" />
+      </includes>
+    </so>
+  </target>
+
+  <target name="clean" >
+    <delete >
+      <fileset dir=".">
+	<include name="**/*.o"/>
+	<include name="**/*.so"/>
+	<include name="**/*.lo"/>
+	<include name="**/*.la"/>
+	<include name="**/.libs"/>
+	<include name="**/*.nlm"/>
+	<include name="**/*.map"/>
+	<include name="**/*.sym"/>
+      </fileset>
+    </delete>
+  </target>
+
+</project>

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkant/java/org/apache/jk/ant/ApacheConfig.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkant/java/org/apache/jk/ant/ApacheConfig.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkant/java/org/apache/jk/ant/ApacheConfig.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,53 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.jk.ant;
+
+import org.apache.tools.ant.BuildException;
+
+/**
+ *  Set preferences for compiling Apache modules.
+ *  XXX will use apxs query to detect the flags.
+ * 
+ * @author Costin Manolache
+ */
+public class ApacheConfig {
+    
+    
+    public ApacheConfig() {
+    }
+
+    public void setApxs( String s ) {
+
+    }
+    
+    /** Return include path for Apache
+     */
+    public String[] getIncludes() {
+	return null;
+    }
+
+    /** Return extra C flags that are needed to compile
+     */
+    public String[] getCflags() {
+	return null;
+    }
+    
+    public void execute() throws BuildException {
+
+    }
+    
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkant/java/org/apache/jk/ant/Def.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkant/java/org/apache/jk/ant/Def.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkant/java/org/apache/jk/ant/Def.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,82 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.jk.ant;
+
+import org.apache.tools.ant.Project;
+
+/** Define name/value, value is optional
+ *  The define will take place if the condition
+ *  is met.
+ *
+ *  A <so> task should include all the defines it supports,
+ *  with the default value. This allows the builder to customize
+ *  without having to look at the source.
+ */
+public class Def {
+    String name;
+    String info;
+    String value;
+    String ifCond;
+    String unlessCond;
+    Project project;
+
+    public Def() {
+    }
+
+    public void setProject( Project p ) {
+	project=p;
+    }
+    
+    public void setName(String n) {
+	name=n;
+    }
+
+    public void setValue( String v ) {
+	value=v;
+    }
+
+    public void setIf( String ifCond ) {
+	this.ifCond=ifCond;
+    }
+
+    public void setUnless( String unlessCond ) {
+	this.unlessCond=unlessCond;
+    }
+
+    /** Informations about the option
+     */
+    public void setInfo(String n ) {
+	info=n;
+    }
+
+    // -------------------- Getters --------------------
+
+    /** Return the name of the define, or null if the define is not
+     *  valid ( if/unless conditions )
+     */
+    public String getName() {
+	if( ifCond!=null && project.getProperty(ifCond) == null )
+	    return null;
+	if (unlessCond != null && project.getProperty(unlessCond) != null) 
+	    return null;
+	return name;
+    }
+
+    public String getValue() {
+	return value;
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkant/java/org/apache/jk/ant/JkData.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkant/java/org/apache/jk/ant/JkData.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkant/java/org/apache/jk/ant/JkData.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,85 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.jk.ant;
+
+import org.apache.tools.ant.Project;
+
+/**
+ *  Set platform specific data.  Can be used to specify files (fileName="value")
+ *  symbols (symbol="value") or generic values (value="value").  A platform
+ *  can also be set on the object so that platform specific compilers can
+ *  determine if they want to use the values.
+ *  XXX will use apxs query to detect the flags.
+ * 
+ * @author Mike Anderson
+ */
+public class JkData {
+
+    private String value;
+    private boolean isfile = false;
+    private String ifCond;
+    String unlessCond;
+    Project project;
+    
+    
+    public JkData() {
+    }
+
+    public void setProject( Project p ) {
+        project=p;
+    }
+    
+    public void setFileName( String s ) {
+        value = s;
+        isfile = true;
+    }
+    
+    public void setSymbol( String s ) {
+        value = s;
+        isfile = false;
+    }
+
+    public void setValue( String s ) {
+        value = s;
+    }
+
+    public void setIsFile( boolean isf ) {
+        isfile = isf;
+    }
+
+    public void setIf( String s ) {
+        ifCond = s;
+    }
+
+    public void setUnless( String s ) {
+        unlessCond = s;
+    }
+
+    public String getValue()
+    {
+        if( ifCond!=null && project.getProperty(ifCond) == null )
+            return null;
+        if (unlessCond != null && project.getProperty(unlessCond) != null) 
+            return null;
+        return value;
+    }
+
+    public boolean isFile()
+    {
+        return isfile;
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkant/java/org/apache/jk/ant/JniConfig.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkant/java/org/apache/jk/ant/JniConfig.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkant/java/org/apache/jk/ant/JniConfig.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,59 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.jk.ant;
+
+import org.apache.tools.ant.BuildException;
+
+/*  Base task for 'config guessers'.
+ *  Each guesser will set properties based on OS, environment,
+ *  properties, well-known locations, other programs.
+ *  
+ *  Examples:
+ *   - set the required include files for JNI compilation
+ *   - use apxs to detect apache directories and flags
+ *
+ *  XXX Should be usable at top-level as well as in <so>
+ */
+
+/**
+ *  Set preferences for compiling Jni .so files.
+ * 
+ * @author Costin Manolache
+ */
+public class JniConfig  {
+    String includes[];
+    
+    public JniConfig() {
+    }
+
+    /** Return include path for JNI
+     */
+    public String[] getIncludes() {
+	return null;
+    }
+
+    /** Return extra C flags that are needed to compile
+     */
+    public String[] getCflags() {
+	return null;
+    }
+    
+    public void execute() throws BuildException {
+	
+    }
+    
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkant/java/org/apache/jk/ant/SoTask.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkant/java/org/apache/jk/ant/SoTask.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkant/java/org/apache/jk/ant/SoTask.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,539 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.jk.ant;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.util.Enumeration;
+import java.util.Vector;
+
+import org.apache.jk.ant.compilers.CcCompiler;
+import org.apache.jk.ant.compilers.CompilerAdapter;
+import org.apache.jk.ant.compilers.GcjCompiler;
+import org.apache.jk.ant.compilers.GcjLinker;
+import org.apache.jk.ant.compilers.LibtoolCompiler;
+import org.apache.jk.ant.compilers.LibtoolLinker;
+import org.apache.jk.ant.compilers.LinkerAdapter;
+import org.apache.jk.ant.compilers.MsvcCompiler;
+import org.apache.jk.ant.compilers.MsvcLinker;
+import org.apache.jk.ant.compilers.MwccCompiler;
+import org.apache.jk.ant.compilers.MwldLinker;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.DirectoryScanner;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.taskdefs.Execute;
+import org.apache.tools.ant.taskdefs.ExecuteStreamHandler;
+import org.apache.tools.ant.taskdefs.PumpStreamHandler;
+import org.apache.tools.ant.types.Commandline;
+import org.apache.tools.ant.types.FileSet;
+import org.apache.tools.ant.types.Path;
+import org.apache.tools.ant.types.PatternSet;
+
+/** Global properties
+
+    Same idea as in javac, some user .properties will set the local preferences,
+    including machine-specific. If one is not specified we'll guess it. The
+    build file will be clean.
+
+    TODO: can we get configure to generate such a file ? 
+
+    build.native.cc=gcc
+    # Path to libtool ( used as a backup )
+    build.native.libtool=
+    # Platform-specific flags for compilation.
+    build.native.extra_cflags=
+*/
+/* XXX add a optional "compiler" attribute 
+    to not guess the compiler based on the executable name 
+    present in a global property.
+
+*/
+
+
+/**
+ * Task to generate a .so file, similar with ( or using ) libtool.
+ * I hate libtool, so long term I would like to replace most of it
+ * with decent java code. Short term it'll just use libtool and
+ * hide some of the ugliness.
+ * 
+ * arguments:
+ * <ul>
+ * <li>source
+ * </ul>
+ *
+ * <p>
+ *
+ * @author Costin Manolache
+ * @author Mike Anderson
+ * @author Ignacio J. Ortega
+ */
+public class SoTask extends Task {
+    protected String apxs;
+    // or FileSet ?
+    protected Vector src; //[FileSet]
+    protected PatternSet includes;
+    protected Path depends;
+    protected Path libs;
+    protected String module;
+    protected String soFile;
+    protected String soExt = ".so";
+    protected String cflags;
+    protected File buildDir;
+    protected int debug;
+
+    protected boolean optG=true;
+    protected boolean optWgcc=true;
+    protected boolean optimize=false;
+    protected boolean profile=false;
+    protected Vector defines    = new Vector();
+    protected Vector imports    = new Vector();     // used by the NetWare, win32 linkers
+    protected Vector exports    = new Vector();     // used by the NetWare, win32 linkers
+    protected Vector modules    = new Vector();     // used by the NetWare linker
+    protected Vector linkOpts   = new Vector();     // used by the NetWare, win32 linkers
+    protected Vector altSoFiles = new Vector();     // used by the NetWare linker
+    protected Vector resources  = new Vector();     // used by the win32 linker
+
+    // Computed fields 
+    //    protected Vector compileList; // [Source]
+    protected Vector srcList=new Vector();
+    protected CompilerAdapter compiler;
+    //    protected GlobPatternMapper co_mapper;
+    
+    public SoTask() {};
+
+    // Hack to allow individual compilers/linkers to work
+    // as regular Tasks, independnetly.
+    public void duplicateTo(SoTask so) {
+        // This will act as a proxy for the child task 
+        so.project=project;
+        so.target=target;
+        so.location=location;
+        so.taskName=taskName;
+        so.taskType=taskType;
+        
+        so.apxs=apxs;
+        so.src=src;
+        so.includes=includes;
+        so.depends=depends;
+        so.libs=libs;
+        so.module=module;
+        so.soFile=soFile;
+        so.soExt=soExt;
+        so.cflags=cflags;
+        so.buildDir=buildDir;
+        so.debug=debug;
+        so.optG=optG;
+        so.optWgcc=optWgcc;
+        so.optimize=optimize;
+        so.profile=profile;
+        so.defines=defines;
+        so.imports=imports;
+        so.exports=exports;
+        so.resources=resources;
+        so.modules=modules;
+        so.linkOpts=linkOpts;
+        so.srcList=srcList;
+        //      so.compileList=compileList;
+        so.compiler=compiler;
+        //      so.co_mapper=co_mapper;
+        so.altSoFiles=altSoFiles;
+    }
+
+    /**  @deprecated use setTarget
+     */
+    public void setSoFile(String s ) {
+        soFile=s;
+    }
+
+    /** Add debug information
+     */
+    public void setDebug(boolean b) {
+        optG=b;
+    }
+
+    /** Add debug information
+     */
+    public void setOptimize(boolean b) {
+        optimize=b;
+    }
+
+    /** Add profiling information
+     */
+    public void setProfile(boolean b) {
+        profile=b;
+    }
+
+    /** Gcc warnings
+     */
+    public void setGccWarn(boolean b) {
+        optWgcc=b;
+    }
+
+    /** Debug the <so> task
+     */
+    public void setTaskDebug(int i) {
+        debug=i;
+    }
+
+    /** Add a -D option. Note that each define has
+     *  an if/unless attribute
+     */ 
+    public void addDef(Def var ) {
+        var.setProject( project );
+        defines.addElement(var);
+    }
+
+    /**
+     * Add an import file/symbol for NetWare or win32 platform
+     *
+     * 
+     */
+    public void addImport(JkData imp) {
+        imp.setProject( project );
+        imports.add(imp);
+    }
+
+    /**
+     * Add an export file/symbol for NetWare or win32 platform
+     *
+     * 
+     */
+    public void addExport(JkData exp) {
+        exp.setProject( project );
+        exports.add(exp);
+    }
+
+    /**
+     * Add an resource file on win32 platform
+     *
+     * 
+     */
+    public void addResource(JkData res) {
+        res.setProject( project );
+        resources.add(res);
+    }
+
+    /**
+     * Add a link option for NetWare or win32 platform
+     *
+     * 
+     */
+    public void addLinkOpt(JkData option) {
+        option.setProject( project );
+        linkOpts.add(option);
+    }
+
+    /**
+     * Add an NLMModule dependancy
+     *
+     * 
+     */
+    public void addNLMModule(JkData module) {
+        module.setProject( project );
+        modules.add(module);
+    }
+
+    /**
+     * Add an alternate target since some platforms (NetWare) have file name
+     * limitations.
+     * 
+     */
+    public void addAltSoFile(JkData altSo) {
+        altSo.setProject( project );
+        altSoFiles.add(altSo);
+    }
+
+    /** Set the target for this compilation. Don't include any
+     *  directory or suffix ( not sure about prefix - we may want
+     *  to add lib automatically for unix, and nothing on win/etc ?  ).
+     */
+    public void setTarget(String s ) {
+        soFile=s;
+    }
+
+    /** Set the extension for the target.  This will depend on the platform
+     *  we are compiling for.
+     */
+    public void setExtension(String s ) {
+        soExt=s;
+    }
+
+    /** Directory where intermediary objects will be
+     *  generated
+     */
+    public void setBuildDir( File s ) {
+        buildDir=s;
+    }
+
+    public void setCflags(String s ) {
+        cflags=s;
+    }
+    
+    /** Directory where the .so file will be generated
+     */
+    public void setSoDir( String s ) {
+        
+    }
+
+    public void addJniConfig( JniConfig jniCfg ) {
+
+    }
+
+    public void addApacheConfig( ApacheConfig apacheCfg ) {
+
+    }
+    
+    
+    /**
+     * Source files ( .c )
+     *
+     * @return a nested src element.
+     */
+    public void addSrc(FileSet fl) {
+        if( src==null ) src=new Vector();
+        src.addElement(fl);
+    }
+
+    /**
+     * Include files
+     */
+    public PatternSet createIncludes() {
+        includes=new PatternSet(); //Path(project);
+        return includes;
+    }
+
+    /**
+     * General dependencies. If any of the files is modified
+     * ( i.e. is newer than the oldest .o ) we'll recompile everything.
+     *
+     * This can be used for headers ( until we add support for makedepend)
+     * or any important file that could invalidate the build.
+     * Another example is checking httpd or apxs ( if a new version
+     * was installed, maybe some flags or symbols changed )
+     */
+    public Path createDepends() {
+        depends=new Path(project);
+        return depends;
+    }
+
+    /**
+     * Libraries ( .a, .so or .dll ) files to link to.
+     */
+    public Path createLibs() {
+        libs=new Path(project);
+        return libs;
+    }
+    
+    
+    /**
+     * The name of the target file.
+     * (XXX including extension - this should be automatically added )
+     */
+    public void setModule(String modName) {
+        this.module = modName;	// Should be this ?
+    }
+
+    // XXX Add specific code for Netware, Windows and platforms where libtool
+    // is problematic
+
+    // XXX Add specific code for Linux and platforms where things are
+    // clean, libtool should be just a fallback.
+    public void execute() throws BuildException {
+        compiler=findCompilerAdapter();
+        //      co_mapper=compiler.getOMapper();
+        LinkerAdapter linker=findLinkerAdapter();
+
+        if( soFile==null )
+            throw new BuildException("No target ( " + soExt + " file )");
+        if (src == null) 
+            throw new BuildException("No source files");
+
+        // XXX makedepend-type dependencies - how ??
+        // We could generate a dummy Makefile and parse the content...
+        findSourceFiles();
+
+        // Copy all settings into compiler
+        this.duplicateTo(compiler);
+        compiler.compile( srcList );
+
+        // XXX move this checking to linker
+        File soTarget=new File( buildDir, soFile + soExt );
+        if( compiler.getCompiledFiles().size() == 0 && soTarget.exists()) {
+            // No dependency, no need to relink
+            return;
+        }
+
+        this.duplicateTo(linker);
+        linker.link(srcList);
+    }
+
+    public CompilerAdapter findCompilerAdapter() {
+        CompilerAdapter compilerAdapter;
+        String cc;
+        cc=project.getProperty("build.compiler.cc");
+        if( cc!=null ) {
+            if( "cc".equals( cc ) ) {
+                compilerAdapter=new CcCompiler();
+                compilerAdapter.setSoTask( this );
+                return compilerAdapter;
+            }
+            if( "gcj".equals( cc ) ) {
+                compilerAdapter=new GcjCompiler();
+                compilerAdapter.setSoTask( this );
+                return compilerAdapter;
+            }
+            if( cc.indexOf("mwccnlm") != -1 ) {
+                compilerAdapter=new MwccCompiler();
+                compilerAdapter.setSoTask( this );
+                return compilerAdapter;
+            }
+            if( cc.indexOf("cl") != -1 ) {
+                compilerAdapter=new MsvcCompiler();
+                compilerAdapter.setSoTask( this );
+                return compilerAdapter;
+            }
+        }
+        
+        compilerAdapter=new LibtoolCompiler(); 
+        compilerAdapter.setSoTask( this );
+        return compilerAdapter;
+   }
+
+    public LinkerAdapter findLinkerAdapter() {
+        LinkerAdapter linkerAdapter;
+        String ld=project.getProperty("build.compiler.ld");
+        if( ld!=null ) {
+            if( ld.indexOf("mwldnlm") != -1 ) {
+                linkerAdapter=new MwldLinker();
+                linkerAdapter.setSoTask( this );
+                return linkerAdapter;
+            }
+            if( ld.indexOf("link") != -1 ) {
+                linkerAdapter=new MsvcLinker();
+                linkerAdapter.setSoTask( this );
+                return linkerAdapter;
+            }
+            //      if( "ld".equals( cc ) ) {
+            //          linkerAdapter=new LdLinker();
+            //          linkerAdapter.setSoTask( this );
+            //          return cc;
+            //      }
+        }
+
+        String cc=project.getProperty("build.compiler.cc");
+        if( "gcj".equals( cc ) ) {
+            linkerAdapter=new GcjLinker();
+            linkerAdapter.setSoTask( this );
+            return linkerAdapter;
+        }
+
+        
+        linkerAdapter=new LibtoolLinker(); 
+        linkerAdapter.setSoTask( this );
+        return linkerAdapter;
+   }
+
+    /** Find all source files declared with <src> elements
+     */
+    public void findSourceFiles() {
+        if (buildDir == null) buildDir = project.getBaseDir();
+
+        Enumeration e=src.elements();
+        while( e.hasMoreElements() ) {
+            FileSet fs=(FileSet)e.nextElement();
+            DirectoryScanner ds=fs.getDirectoryScanner( project );
+            String localList[]= ds.getIncludedFiles(); 
+            if (localList.length == 0) 
+                throw new BuildException("No source files ");
+            for( int i=0; i<localList.length; i++ ) {
+                srcList.addElement( new Source( fs.getDir(project), localList[i]));
+            }
+        }
+    }
+ 
+    /** If any file declared in <depend> element has changed, we'll do
+        a full rebuild.
+    */
+    public boolean checkDepend(long oldestO, File oldestOFile) {
+        if( depends==null )
+            return false;
+        String dependsA[]=depends.list(); 
+        for( int i=0; i< dependsA.length; i++ ) {
+            File f=new File( dependsA[i] );
+            if( ! f.exists() ) {
+                log("Depend not found " + f );
+                return true;
+            }
+            if( f.lastModified() > oldestO ) {
+                log( "Depend " + f + " newer than " + oldestOFile );
+                return true;
+            }
+        }
+        return false;
+    }
+    
+    // ==================== Execution utils ==================== 
+
+    protected ExecuteStreamHandler streamhandler = null;
+    protected ByteArrayOutputStream outputstream = null;
+    protected ByteArrayOutputStream errorstream = null;
+
+    public int execute( Commandline cmd ) throws BuildException
+    {
+        createStreamHandler();
+        Execute exe = new Execute(streamhandler, null);
+        exe.setAntRun(project);
+
+        exe.setWorkingDirectory(buildDir);
+
+        exe.setCommandline(cmd.getCommandline());
+        int result=0;
+        try {
+            result=exe.execute();
+        } catch (IOException e) {
+            throw new BuildException(e, location);
+        } 
+        return result;
+    }
+
+    public void createStreamHandler()  throws BuildException {
+        //      try {
+        outputstream= new ByteArrayOutputStream();
+        errorstream = new ByteArrayOutputStream();
+        
+        streamhandler =
+            new PumpStreamHandler(new PrintStream(outputstream),
+                                  new PrintStream(errorstream));
+        //      }  catch (IOException e) {
+        //          throw new BuildException(e,location);
+        //      }
+    }
+
+    public void closeStreamHandler() {
+        try {
+            if (outputstream != null) 
+                outputstream.close();
+            if (errorstream != null) 
+                errorstream.close();
+            outputstream=null;
+            errorstream=null;
+        } catch (IOException e) {}
+    }
+}
+

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkant/java/org/apache/jk/ant/Source.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkant/java/org/apache/jk/ant/Source.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkant/java/org/apache/jk/ant/Source.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,50 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.jk.ant;
+
+import java.io.File;
+
+import org.apache.tools.ant.util.GlobPatternMapper;
+
+public class Source {
+    File dir;
+    String localPart;
+    
+    public Source( File dir, String localPart ) {
+	this.dir=dir;
+	this.localPart=localPart;
+    }
+
+    public String getTargetFile( GlobPatternMapper mapper ) {
+	String targetNA[]=mapper.mapFileName( localPart );
+	if( targetNA==null )
+	    return null; // strange, probably different extension ?
+	String target=targetNA[0];
+	return target;
+    }
+
+    public File getFile() {
+	return  new File( dir, localPart );
+    }
+
+    public String getPackage() {
+	int lastSlash=localPart.lastIndexOf("/");
+	if( lastSlash==-1 )
+	    return "";
+	return localPart.substring( 0, lastSlash );
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkant/java/org/apache/jk/ant/compilers/CcCompiler.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkant/java/org/apache/jk/ant/compilers/CcCompiler.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkant/java/org/apache/jk/ant/compilers/CcCompiler.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,126 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.jk.ant.compilers;
+
+import java.io.File;
+
+import org.apache.jk.ant.Source;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.types.Commandline;
+import org.apache.tools.ant.util.GlobPatternMapper;
+
+/**
+ *  Compile using Gcc.
+ *
+ * @author Costin Manolache
+ */
+public class CcCompiler extends CompilerAdapter {
+    GlobPatternMapper co_mapper=new GlobPatternMapper();
+
+    public CcCompiler() {
+	super();
+	co_mapper.setFrom("*.c");
+	co_mapper.setTo("*.o");
+    }
+
+    public String[] getTargetFiles( Source src ) {
+        File srcFile = src.getFile();
+        String name=srcFile.getName();
+        
+        return co_mapper.mapFileName( name );
+    }
+    
+    String cc;
+    
+    /** Compile  using 'standard' gcc flags. This assume a 'current' gcc on
+     *  a 'normal' platform - no need for libtool
+     */
+    public void compileSingleFile(Source sourceObj) throws BuildException {
+	File f=sourceObj.getFile();
+	String source=f.toString();
+	Commandline cmd = new Commandline();
+
+	cc=project.getProperty("build.native.cc");
+	if(cc==null) cc="cc";
+	
+	cmd.setExecutable( cc );
+
+	cmd.createArgument().setValue( "-c" );
+
+	addIncludes(cmd);
+	addExtraFlags( cmd );
+	addDebug(cmd);
+	addDefines( cmd );
+	addOptimize( cmd );
+	addProfile( cmd );
+
+	cmd.createArgument().setValue( source );
+
+	project.log( "Compiling " + source);
+
+	int result=execute( cmd );
+        displayError( result, source, cmd );
+	closeStreamHandler();
+    }
+    protected void addDebug(Commandline cmd) {
+	if( optG ) {
+	    cmd.createArgument().setValue("-g" );
+        }
+
+        if( optWgcc ) {
+	    if( ! "HP-UX".equalsIgnoreCase( System.getProperty( "os.name" )) ) {
+                // HP-UX uses -W for some other things
+                cmd.createArgument().setValue("-W");
+            }
+
+            if( cc!= null && cc.indexOf( "gcc" ) >= 0 ) {
+                //cmd.createArgument().setValue("-Wall");
+                cmd.createArgument().setValue("-Wimplicit");
+                cmd.createArgument().setValue("-Wreturn-type");
+                cmd.createArgument().setValue("-Wcomment");
+                cmd.createArgument().setValue("-Wformat");
+                cmd.createArgument().setValue("-Wchar-subscripts");
+                cmd.createArgument().setValue("-O");
+                cmd.createArgument().setValue("-Wuninitialized");
+                
+                // Non -Wall
+                // 	    cmd.createArgument().setValue("-Wtraditional");
+                // 	    cmd.createArgument().setValue("-Wredundant-decls");
+                cmd.createArgument().setValue("-Wmissing-declarations");
+                cmd.createArgument().setValue("-Wmissing-prototypes");
+                //	    cmd.createArgument().setValue("-Wconversions");
+                cmd.createArgument().setValue("-Wcast-align");
+                // 	    cmd.createArgument().setValue("-pedantic" );
+            }
+	}
+    }
+    protected void addOptimize( Commandline cmd ) {
+	if( optimize )
+	    cmd.createArgument().setValue("-O3" );
+    }
+
+    protected void addProfile( Commandline cmd ) {
+	if( profile ) {
+	    cmd.createArgument().setValue("-pg" );
+	    // bb.in 
+	    // cmd.createArgument().setValue("-ax" );
+	}
+    }
+
+
+}
+

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkant/java/org/apache/jk/ant/compilers/CompilerAdapter.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkant/java/org/apache/jk/ant/compilers/CompilerAdapter.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkant/java/org/apache/jk/ant/compilers/CompilerAdapter.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,288 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.jk.ant.compilers;
+
+import java.io.File;
+import java.util.Enumeration;
+import java.util.Vector;
+
+import org.apache.jk.ant.Def;
+import org.apache.jk.ant.SoTask;
+import org.apache.jk.ant.Source;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.types.Commandline;
+
+/* Modeled after javac
+ */
+
+/**
+ * s/javac/C compiler/
+ *
+ * The interface that all compiler adapters must adher to.  
+ *
+ * <p>A compiler adapter is an adapter that interprets the javac's
+ * parameters in preperation to be passed off to the compier this
+ * adapter represents.  As all the necessary values are stored in the
+ * Javac task itself, the only thing all adapters need is the javac
+ * task, the execute command and a parameterless constructor (for
+ * reflection).</p>
+ *
+ * @author Jay Dickon Glanville <a href="mailto:jayglanville at home.com">jayglanville at home.com</a>
+ * @author Costin Manolache
+ */
+public abstract class CompilerAdapter extends SoTask {
+    SoTask so;
+    Vector compileList;
+
+    public CompilerAdapter() {
+	so=this;
+    };
+
+    public void setSoTask(SoTask so ) {
+	this.so=so;
+	so.duplicateTo( this );
+    }
+
+//     /** @deprecated
+//      */
+//     public GlobPatternMapper getOMapper() {
+//         return null;
+//     }
+
+    /** Return the files that depend on a src file.
+     *  The first item should be the .o file used for linking.
+     */
+    public abstract String[] getTargetFiles( Source src );
+
+    public void execute() throws BuildException {
+        super.findSourceFiles();
+        Vector compileList=findCompileList(srcList);
+	compile( compileList );
+    }
+
+    /** Verify if a .c file needs compilation.
+     *	As with javac, we assume a fixed build structure, where all .o
+     *	files are in a separate directory from the sources ( no mess ).
+     *
+     *  XXX Hack makedepend somehow into this.
+     */
+    public boolean needCompile( Source source ) {
+	// For each .c file we'll have a .o file in the build dir,
+	// with the same name.
+	File srcF = source.getFile();
+	if( !srcF.exists() ) {
+            if( debug > 0 )
+                log("No source file " + srcF ); 
+            return false;
+        }
+
+	String targetNames[]= getTargetFiles( source );
+	if( targetNames==null || targetNames.length==0 ) {
+            if( debug > 0 )
+                log("No target files " + srcF ); 
+	    return true; // strange, probably different extension ?
+        }
+        String targetName=targetNames[0];
+
+        String targetDir=source.getPackage();
+        File f1=new File( buildDir, targetDir );
+        File target=new File( f1, targetName );
+	//	System.out.println("XXX " + target );
+	if( ! target.exists() ) {
+            if( debug > 0 )
+                log("Target doesn't exist " + target ); 
+	    return true;
+        }
+	if( oldestO > target.lastModified() ) {
+	    oldestO=target.lastModified();
+	    oldestOFile=target;
+	}
+	if( srcF.lastModified() > target.lastModified() ) 
+	    return true;
+
+	if( debug > 0 )
+	    log("No need to compile " + srcF + " target " + target ); 
+	return false;
+    }
+
+    /** Remove all generated files, cleanup
+     */
+    public void removeOFiles( Vector srcList ) {
+        for (int i = 0; i < srcList.size(); i++) {
+            //            log( "Checking " + (Source)srcList.elementAt(i));
+            Source source=(Source)srcList.elementAt(i);
+	    String targetNA[]=getTargetFiles(source);
+	    if( targetNA==null )
+		continue;
+            String targetDir=source.getPackage();
+            File f1=new File( buildDir, targetDir );
+            for( int j=0; j<targetNA.length; j++ ) {
+                File target=new File( f1, targetNA[j] );
+                // Check the dependency
+                if( target.exists() ) {
+                    // Remove it - we'll do a full build
+                    target.delete();
+                    log("Removing " + target );
+                }
+            }
+        }
+    }
+
+    // XXX modified as side-effect of checking files with needCompile()
+    long oldestO=System.currentTimeMillis();
+    File oldestOFile=null;
+
+    /** Find the subset of the source list that needs compilation.
+     */
+    protected Vector findCompileList(Vector srcList) throws BuildException {
+        Vector compileList=new Vector();
+
+        for (int i = 0; i < srcList.size(); i++) {
+	    Source source=(Source)srcList.elementAt(i);
+	    File srcFile=source.getFile();
+	   
+            if (!srcFile.exists()) {
+                throw new BuildException("Source \"" + srcFile.getPath() +
+                                         "\" does not exist!", location);
+            }
+
+	    // Check the dependency
+	    if( needCompile( source ) ) 
+		compileList.addElement( source );
+	}
+
+	if( checkDepend(oldestO, oldestOFile) ) {
+	    log("Dependency expired, removing "
+                + srcList.size() + " .o files and doing a full build ");
+	    removeOFiles(srcList);
+            compileList=new Vector();
+	    for(int i=0; i<srcList.size(); i++ ) {
+		Source source=(Source)srcList.elementAt(i);
+		compileList.addElement( source );
+	    }
+            return compileList;
+	}
+
+
+        return compileList;
+    }
+    
+    /** Return the files that were actually compiled
+     */
+    public Vector getCompiledFiles() {
+        return compileList;
+    }
+
+    /** Compile the source files. The compiler adapter can override either this method
+     *  ( if it can compile multiple files at once ) or compileSingleFile().
+     *  Note that the list includes _all_ sources, findCompileList() can be used to
+     *  avoid compiling files that are up-to-date.
+     */
+    public void compile(Vector sourceFiles ) throws BuildException {
+        compileList=findCompileList(sourceFiles);
+
+        log("Compiling " + compileList.size() + " out of " + sourceFiles.size());
+	Enumeration en=compileList.elements();
+	while( en.hasMoreElements() ) {
+	    Source source=(Source)en.nextElement();
+	    compileSingleFile(source);
+	}
+    }
+    
+    /** Compile single file
+     */
+    public void compileSingleFile(Source sourceObj) throws BuildException {
+    }
+
+
+    protected void displayError( int result, String source, Commandline cmd )
+	throws BuildException
+    {
+        if( result == 0 ) {
+            String err=errorstream.toString();
+            if(err==null ) return;
+            if( err.indexOf( "warning" ) <= 0 )
+                return;
+            log("Warnings: ");
+            log( err );
+            return;
+        }
+        
+	log("Compile failed " + result + " " +  source );
+	log("Command:" + cmd.toString());
+	log("Output:" );
+	if( outputstream!=null ) 
+	    log( outputstream.toString());
+	log("StdErr:" );
+	if( errorstream!=null ) 
+	    log( errorstream.toString());
+	
+	throw new BuildException("Compile failed " + source);
+    }
+
+    protected void addIncludes(Commandline cmd) {
+	String [] includeList = ( includes==null ) ?
+	    new String[] {} : includes.getIncludePatterns(project); 
+	for( int i=0; i<includeList.length; i++ ) {
+	    cmd.createArgument().setValue("-I" + includeList[i] );
+	}
+    }
+
+    /** Common cc parameters
+     */
+    protected void addExtraFlags(Commandline cmd )  {
+	String extra_cflags=project.getProperty("build.native.extra_cflags");
+	String localCflags=cflags;
+	if( localCflags==null ) {
+	    localCflags=extra_cflags;
+	} else {
+	    if( extra_cflags!=null ) {
+		localCflags+=" " + extra_cflags;
+	    }
+ 	}
+	if( localCflags != null )
+	    cmd.createArgument().setLine( localCflags );
+    }
+
+    protected void addDefines( Commandline cmd ) {
+        // Define by default the OS ( as known to java )
+        String os=System.getProperty("java.os");
+
+        if( defines.size() > 0 ) {
+	    Enumeration defs=defines.elements();
+	    while( defs.hasMoreElements() ) {
+		Def d=(Def)defs.nextElement();
+		String name=d.getName();
+		String val=d.getValue();
+		if( name==null ) continue;
+		String arg="-D" + name;
+		if( val!=null )
+		    arg+= "=" + val;
+		cmd.createArgument().setValue( arg );
+            }
+        }
+    }
+
+    protected void addDebug(Commandline cmd) {
+    }
+
+    protected void addOptimize( Commandline cmd ) {
+    }
+
+    protected void addProfile( Commandline cmd ) {
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkant/java/org/apache/jk/ant/compilers/GcjCompiler.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkant/java/org/apache/jk/ant/compilers/GcjCompiler.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkant/java/org/apache/jk/ant/compilers/GcjCompiler.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,116 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.jk.ant.compilers;
+
+import java.io.File;
+
+import org.apache.jk.ant.Source;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.types.Commandline;
+
+/**
+ *  Compile using Gcj. This is ( even more ) experimental.
+ * 
+ * @author Costin Manolache
+ */
+public class GcjCompiler extends CcCompiler {
+    
+    public GcjCompiler() {
+	super();
+	co_mapper.setFrom("*.java");
+	co_mapper.setTo("*.o");
+    }
+
+    public String[] getTargetFiles( Source src ) {
+        File srcFile = src.getFile();
+        String name=srcFile.getName();
+        if( name.endsWith( ".java" ) ) {
+            return co_mapper.mapFileName( name );
+        } else {
+            return new String[]
+            { name + ".o" };
+        }
+    }
+
+    
+    /** Compile using libtool.
+     */
+    public void compileSingleFile(Source sourceObj) throws BuildException {
+	File f=sourceObj.getFile();
+	String source=f.toString();
+	Commandline cmd = new Commandline();
+
+	cmd.setExecutable( "gcj" );
+
+	cmd.createArgument().setValue("-c" );
+	
+	if( optG ) {
+            //	    cmd.createArgument().setValue("-g" );
+            cmd.createArgument().setValue("-ggdb3" );
+            //            cmd.createArgument().setValue("-save-temps" );
+	    //  cmd.createArgument().setValue("-Wall");
+	}
+	addOptimize( cmd );
+	addExtraFlags( cmd );
+	cmd.createArgument().setValue("-fPIC" );
+	addIncludes( cmd );
+        String targetDir=sourceObj.getPackage();
+	try {
+	    File f1=new File( buildDir, targetDir );
+	    f1.mkdirs();
+            cmd.createArgument().setValue( "-o" );
+            String targetO[]=getTargetFiles( sourceObj );
+            if( targetO==null ) {
+                log("no target for " + sourceObj.getFile() );
+                return;
+            }
+            File ff=new File( f1, targetO[0]);
+            cmd.createArgument().setValue( ff.toString() );
+	} catch( Exception ex ) {
+	    ex.printStackTrace();
+	}
+	
+        if( ! source.endsWith(".java") ) {
+            cmd.createArgument().setValue("-R" );
+            cmd.createArgument().setValue( targetDir + "/" + f.getName() );
+            //System.out.println("XXX resource " + targetDir + "/" + f.getName() );
+        } else {
+            //            cmd.createArgument().setValue("-fno-bounds-check" );
+        }
+        cmd.createArgument().setValue( source );
+	project.log( "Compiling " + source);
+
+	if( debug > 0 )
+	    project.log( "Command: " + cmd ); 
+	int result=execute( cmd );
+	if( result!=0 ) {
+	    displayError( result, source, cmd );
+	}
+	closeStreamHandler();
+    }
+
+    protected void addIncludes(Commandline cmd) {
+	String [] includeList = ( includes==null ) ?
+	    new String[] {} : includes.getIncludePatterns(project); 
+	for( int i=0; i<includeList.length; i++ ) {
+	    cmd.createArgument().setValue("-I" + includeList[i] );
+	}
+    }
+
+
+}
+

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkant/java/org/apache/jk/ant/compilers/GcjLinker.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkant/java/org/apache/jk/ant/compilers/GcjLinker.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkant/java/org/apache/jk/ant/compilers/GcjLinker.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,125 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.jk.ant.compilers;
+
+import java.io.File;
+import java.util.Enumeration;
+import java.util.Vector;
+
+import org.apache.jk.ant.JkData;
+import org.apache.jk.ant.SoTask;
+import org.apache.jk.ant.Source;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.types.Commandline;
+import org.apache.tools.ant.util.GlobPatternMapper;
+
+/**
+ * Link java using gcj.
+ * 
+ * @author Costin Manolache
+ */
+public class GcjLinker extends LinkerAdapter {
+    SoTask so;
+    protected static GlobPatternMapper co_mapper=new GlobPatternMapper();
+    static {
+	co_mapper.setFrom("*.java");
+	co_mapper.setTo("*.o");
+    }
+    public GcjLinker() {
+	so=this;
+    }
+
+    public String[] getTargetFiles( Source src ) {
+        File srcFile = src.getFile();
+        String name=srcFile.getName();
+        if( name.endsWith( ".java" ) )
+            return co_mapper.mapFileName( name );
+        else
+            return new String[]
+            { name + ".o" };
+    }
+
+
+    
+    public void setSoTask(SoTask so ) {
+	this.so=so;
+	so.duplicateTo( this );
+    }
+
+    public void execute() throws BuildException {
+	findSourceFiles();
+	link(this.srcList);
+    }
+
+    /** Link using libtool.
+     */
+    public boolean link(Vector srcList) throws BuildException {
+//         link( srcList, false );
+        link( srcList, true );
+	return true;
+    }
+    public boolean link(Vector srcList, boolean shared) throws BuildException {
+	Commandline cmd = new Commandline();
+
+	cmd.setExecutable( "gcj" );
+
+        if( shared )
+            cmd.createArgument().setValue( "--shared" );
+	cmd.createArgument().setValue( "-o" );
+        if( shared )
+            cmd.createArgument().setValue( soFile + ".so" );
+        else
+            cmd.createArgument().setValue( soFile + ".a" );
+
+	project.log( "Linking " + buildDir + "/" + soFile + ".so");
+
+        // write out any additional link options
+        Enumeration opts = linkOpts.elements();
+        while( opts.hasMoreElements() ) {
+            JkData opt = (JkData) opts.nextElement();
+            String option = opt.getValue();
+            if( option == null ) continue;
+
+            cmd.createArgument().setValue( option );
+        }
+
+	for( int i=0; i<srcList.size(); i++ ) {
+	    Source source=(Source)srcList.elementAt(i);
+	    File f1=new File(buildDir, source.getPackage());
+	    File srcF=new File(f1, getTargetFiles(source)[0]);
+	    cmd.createArgument().setValue( srcF.toString() );
+	}
+	
+	int result=execute( cmd );
+	if( result!=0 ) {
+	    log("Link failed " + result );
+	    log("Command:" + cmd.toString());
+	    log("Output:" );
+	    if( outputstream!=null ) 
+		log( outputstream.toString());
+	    log("StdErr:" );
+	    if( errorstream!=null ) 
+		log( errorstream.toString());
+	    
+	    throw new BuildException("Link failed " + soFile);
+	}
+	closeStreamHandler();
+
+	return true;
+    }
+}
+

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkant/java/org/apache/jk/ant/compilers/LibtoolCompiler.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkant/java/org/apache/jk/ant/compilers/LibtoolCompiler.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkant/java/org/apache/jk/ant/compilers/LibtoolCompiler.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,105 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.jk.ant.compilers;
+
+import java.io.File;
+import java.util.Enumeration;
+import java.util.Vector;
+
+import org.apache.jk.ant.Source;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.types.Commandline;
+
+/**
+ *  Compile using libtool.
+ * 
+ *  It extends SoTask so we can debug it or use it independently of <so>.
+ *  For normal use you should use the generic task, and system-specific
+ *  properties to choose the right compiler plugin ( like we select
+ *  jikes ).
+ *
+ * @author Costin Manolache
+ */
+public class LibtoolCompiler extends CcCompiler {
+
+    public LibtoolCompiler() {
+	super();
+    };
+
+    public void compile(Vector sourceFiles ) throws BuildException {
+        compileList=findCompileList(sourceFiles);
+        
+        log("Compiling " + compileList.size() + " out of " + sourceFiles.size());
+	Enumeration en=compileList.elements();
+	while( en.hasMoreElements() ) {
+	    Source source=(Source)en.nextElement();
+	    compileSingleFile(source);
+	}
+    }
+    
+
+    /** Compile using libtool.
+     */
+    public void compileSingleFile(Source sourceObj) throws BuildException {
+	File f=sourceObj.getFile();
+	String source=f.toString();
+	Commandline cmd = new Commandline();
+
+	String libtool=project.getProperty("build.native.libtool");
+	if(libtool==null) libtool="libtool";
+
+	cmd.setExecutable( libtool );
+	
+	cmd.createArgument().setValue("--mode=compile");
+
+	String cc=project.getProperty("build.native.cc");
+	if(cc==null) cc="cc";
+
+	cmd.createArgument().setValue( cc );
+
+	cmd.createArgument().setValue( "-c" );
+	
+	cmd.createArgument().setValue( "-o" );
+	
+	File ff=new File( buildDir, sourceObj.getTargetFile(co_mapper));
+	cmd.createArgument().setValue( ff.toString() );
+	try {
+	    String targetDir=sourceObj.getPackage();
+	    File f1=new File( buildDir, targetDir );
+	    f1.mkdirs();
+	    // System.out.println("mkdir " + f1 );
+	} catch( Exception ex ) {
+	    ex.printStackTrace();
+	}
+
+	addIncludes(cmd);
+	addExtraFlags( cmd );
+	addDebug(cmd);
+	addDefines( cmd );
+	addOptimize( cmd );
+	addProfile( cmd );
+
+	project.log( "Compiling " + source);
+	cmd.createArgument().setValue( source );
+
+        if( debug > 0 ) project.log(cmd.toString());
+	int result=execute( cmd );
+        displayError( result, source, cmd );
+	closeStreamHandler();
+    }
+}
+

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkant/java/org/apache/jk/ant/compilers/LibtoolLinker.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkant/java/org/apache/jk/ant/compilers/LibtoolLinker.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkant/java/org/apache/jk/ant/compilers/LibtoolLinker.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,157 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.jk.ant.compilers;
+
+import java.io.File;
+import java.util.Enumeration;
+import java.util.Vector;
+
+import org.apache.jk.ant.JkData;
+import org.apache.jk.ant.SoTask;
+import org.apache.jk.ant.Source;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.types.Commandline;
+import org.apache.tools.ant.util.GlobPatternMapper;
+
+/**
+ * Link using libtool.
+ * 
+ * @author Costin Manolache
+ */
+public class LibtoolLinker extends LinkerAdapter {
+    SoTask so;
+    GlobPatternMapper lo_mapper=new GlobPatternMapper();
+    public LibtoolLinker() {
+	so=this;
+	lo_mapper.setFrom("*.c");
+	lo_mapper.setTo("*.lo");
+    }
+
+    /** Link using libtool.
+     */
+    public boolean link(Vector srcList) throws BuildException {
+	so.duplicateTo( this );
+	Commandline cmd = new Commandline();
+
+	String libtool=project.getProperty("build.native.libtool");
+	if(libtool==null) libtool="libtool";
+
+	cmd.setExecutable( libtool );
+	
+	cmd.createArgument().setValue("--mode=link");
+
+	String cc=project.getProperty("build.native.cc");
+	if(cc==null) cc="cc";
+
+	cmd.createArgument().setValue( cc );
+	
+	cmd.createArgument().setValue("-module");
+	cmd.createArgument().setValue("-avoid-version");
+	cmd.createArgument().setValue("-rpath");
+	cmd.createArgument().setValue( buildDir.getAbsolutePath());
+
+	cmd.createArgument().setValue( "-o" );
+	cmd.createArgument().setValue( soFile + ".la" );
+
+	if( profile )
+	    cmd.createArgument().setValue("-pg" );
+
+        // write out any additional link options
+        Enumeration opts = linkOpts.elements();
+        while( opts.hasMoreElements() ) {
+            JkData opt = (JkData) opts.nextElement();
+            String option = opt.getValue();
+            if( option == null ) continue;
+
+            cmd.createArgument().setValue( option );
+        }
+        
+	// All .o files must be included
+	project.log( "Linking " + buildDir + "/" + soFile + ".so");
+
+        if( libs!=null ) {
+            String libsA[]=libs.list(); 
+            for( int i=0; i< libsA.length; i++ ) {
+                cmd.createArgument().setValue( "-l" + libsA[i] );
+                //XXX debug
+                project.log("XXX -l" + libsA[i] );
+            }
+        }
+	
+	for( int i=0; i<srcList.size(); i++ ) {
+	    Source sourceObj=(Source)srcList.elementAt(i);
+	    
+	    File ff=new File( buildDir, sourceObj.getTargetFile(lo_mapper));
+	    cmd.createArgument().setValue( ff.toString() );
+	}
+	
+	int result=execute( cmd );
+	if( result!=0 ) {
+	    log("Link failed " + result );
+	    log("Command:" + cmd.toString());
+	    log("Output:" );
+	    if( outputstream!=null ) 
+		log( outputstream.toString());
+	    log("StdErr:" );
+	    if( errorstream!=null ) 
+		log( errorstream.toString());
+	    
+	    throw new BuildException("Link failed " + soFile);
+	}
+	closeStreamHandler();
+
+	executeLibtoolInstall();
+	return true;
+    }
+
+    /** Final step using libtool.
+     */
+    private void executeLibtoolInstall() throws BuildException {
+	Commandline cmd = new Commandline();
+
+	String libtool=project.getProperty("build.native.libtool");
+	if(libtool==null) libtool="libtool";
+
+	cmd.setExecutable( libtool );
+	
+	cmd.createArgument().setValue("--mode=install");
+
+	cmd.createArgument().setValue( "cp" );
+
+	File laFile=new File( buildDir, soFile + ".la" );
+	cmd.createArgument().setValue( laFile.getAbsolutePath());
+	
+	File soFileF=new File( buildDir, soFile + ".so" );
+	cmd.createArgument().setValue( soFileF.getAbsolutePath());
+
+	int result=execute( cmd );
+	if( result!=0 ) {
+	    log("Link/install failed " + result );
+	    log("Command:" + cmd.toString());
+	    log("Output:" );
+	    if( outputstream!=null ) 
+		log( outputstream.toString());
+	    log("StdErr:" );
+	    if( errorstream!=null ) 
+		log( errorstream.toString());
+	    
+	    throw new BuildException("Link failed " + soFile);
+	}
+	closeStreamHandler();
+    }    
+}
+

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkant/java/org/apache/jk/ant/compilers/LinkerAdapter.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkant/java/org/apache/jk/ant/compilers/LinkerAdapter.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkant/java/org/apache/jk/ant/compilers/LinkerAdapter.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,64 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.jk.ant.compilers;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.jk.ant.*;
+
+import java.util.*;
+
+/* Modeled after javac
+ */
+
+/**
+ * s/javac/C linker/
+ *
+ * The interface that all compiler adapters must adher to.  
+ *
+ * <p>A compiler adapter is an adapter that interprets the javac's
+ * parameters in preperation to be passed off to the compier this
+ * adapter represents.  As all the necessary values are stored in the
+ * Javac task itself, the only thing all adapters need is the javac
+ * task, the execute command and a parameterless constructor (for
+ * reflection).</p>
+ *
+ * @author Jay Dickon Glanville <a href="mailto:jayglanville at home.com">jayglanville at home.com</a>
+ * @author Costin Manolache
+ */
+public abstract class LinkerAdapter extends SoTask {
+    protected SoTask so;
+
+    /**
+     * Sets the compiler attributes, which are stored in the Javac task.
+     */
+    public void setSoTask(SoTask so ) {
+	this.so=so;
+    }
+
+    public void execute() throws BuildException {
+	findSourceFiles();
+	link(this.srcList);
+    }
+
+
+    /**
+     * Executes the task.
+     *
+     * @return has the compilation been successful
+     */
+    public abstract boolean link(Vector srcFiles) throws BuildException;
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkant/java/org/apache/jk/ant/compilers/MsvcCompiler.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkant/java/org/apache/jk/ant/compilers/MsvcCompiler.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkant/java/org/apache/jk/ant/compilers/MsvcCompiler.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,169 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.jk.ant.compilers;
+
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.Enumeration;
+
+import org.apache.jk.ant.Def;
+import org.apache.jk.ant.SoTask;
+import org.apache.jk.ant.Source;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.types.Commandline;
+import org.apache.tools.ant.util.GlobPatternMapper;
+
+/**
+ *  Compile using Microsoft Visual C++ v6.0
+ * 
+ * @author Costin Manolache
+ * @author Ignacio J. Ortega
+ * @author Mike Anderson
+ * @author Larry Isaacs
+ */
+public class MsvcCompiler extends CompilerAdapter {
+    GlobPatternMapper co_mapperS=new GlobPatternMapper();
+    
+    public MsvcCompiler() {
+        super();
+	co_mapperS.setFrom("*.c");
+	co_mapperS.setTo("*.obj");
+    }
+
+    public String[] getTargetFiles( Source src ) {
+        File srcFile = src.getFile();
+        String name=srcFile.getName();
+        
+        return co_mapperS.mapFileName( name );
+    }
+
+    public void setSoTask(SoTask so ) {
+        this.so=so;
+        so.setExtension(".dll");
+        so.duplicateTo( this );
+        project.setProperty("win32", "true");
+        if (optG)
+            project.setProperty("win32.debug", "true");
+        else
+            project.setProperty("win32.release", "true");
+    }
+
+    /** Compile using msvc 
+     */
+    public void compileSingleFile(Source sourceObj) throws BuildException {
+	File f=sourceObj.getFile();
+	String source=f.toString();
+        String [] includeList = ( includes==null ) ?
+            new String[] {} : includes.getIncludePatterns(project);
+
+        Commandline cmd = new Commandline();
+
+        String cc=project.getProperty("build.compiler.cc");
+        if(cc==null) cc="cl";
+        
+        cmd.setExecutable( cc );
+        addCCArgs( cmd, source, includeList );
+
+        int result=execute( cmd );
+        if( result!=0 ) {
+            log("Compile failed " + result + " " +  source );
+            log("Output:" );
+            if( outputstream!=null ) 
+                log( outputstream.toString());
+            log("StdErr:" );
+            if( errorstream!=null ) 
+                log( errorstream.toString());
+            
+            throw new BuildException("Compile failed " + source);
+        }
+        File ccOpt = new File(buildDir, "cc.opt");
+        ccOpt.delete();
+        closeStreamHandler();
+
+    }
+
+    /** common compiler args
+     */
+    private void addCCArgs(Commandline cmd, String source, String includeList[]) {
+        String extra_cflags=project.getProperty("build.native.extra_cflags");
+        String localCflags=cflags;
+        File ccOpt = new File(buildDir, "cc.opt");
+        if( localCflags==null ) {
+            localCflags=new String("-nologo -W3 -GX -O2 -c");
+            if( extra_cflags!=null ) {
+                localCflags+=" " + extra_cflags;
+            }
+        }
+
+        if (optG)
+            localCflags += " -MTd -Zi";
+        else
+            localCflags += " -MT";
+
+        // create a cc.opt file 
+        PrintWriter ccpw = null;
+        try
+        {
+            ccpw = new PrintWriter(new FileWriter(ccOpt));
+            // write the compilation flags out
+            ccpw.println(localCflags);
+            for( int i=0; i<includeList.length; i++ ) {
+                ccpw.print("-I");
+                if (!includeList[i].startsWith("\"")) {
+                    ccpw.print("\"");
+                }
+                ccpw.print(includeList[i] );
+                if (!includeList[i].endsWith("\"")) {
+                    ccpw.print("\"");
+                }
+                ccpw.println();
+            }
+
+            if( defines.size() > 0 ) {
+                Enumeration defs=defines.elements();
+                while( defs.hasMoreElements() ) {
+                    Def d=(Def)defs.nextElement();
+                    String name=d.getName();
+                    String val=d.getValue();
+                    if( name==null ) continue;
+                    String arg="-D" + name;
+                    if( val!=null )
+                        arg+= "=" + val;
+                    ccpw.println(arg);
+                }
+            }
+        }
+        catch (IOException ioe)
+        {
+            log("Caught IOException");
+        }
+        finally
+        {
+            if (ccpw != null)
+            {
+                ccpw.close();
+            }
+        }
+
+        project.log( "Compiling " + source);
+        cmd.createArgument().setValue( source );
+        cmd.createArgument().setValue( "@cc.opt" );
+    }
+}
+

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkant/java/org/apache/jk/ant/compilers/MsvcLinker.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkant/java/org/apache/jk/ant/compilers/MsvcLinker.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkant/java/org/apache/jk/ant/compilers/MsvcLinker.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,194 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.jk.ant.compilers;
+
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.Enumeration;
+import java.util.Vector;
+
+import org.apache.jk.ant.JkData;
+import org.apache.jk.ant.SoTask;
+import org.apache.jk.ant.Source;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.types.Commandline;
+import org.apache.tools.ant.util.GlobPatternMapper;
+
+/**
+ * Link using MSVC Linker
+ *
+ * @author Costin Manolache
+ * @author Ignacio J. Ortega
+ * @author Mike Anderson
+ * @author Larry Isaacs
+ */
+public class MsvcLinker extends LinkerAdapter {
+    SoTask so;
+    GlobPatternMapper co_mapper=new GlobPatternMapper();
+    
+    public MsvcLinker() {
+        so=this;
+        co_mapper.setFrom("*.c");
+        co_mapper.setTo("*.obj");
+    }
+
+    public void setSoTask(SoTask so ) {
+        this.so=so;
+        so.setExtension(".dll");
+        so.duplicateTo( this );
+        project.setProperty("win32", "true");
+        if (optG)
+            project.setProperty("win32.debug", "true");
+        else
+            project.setProperty("win32.release", "true");
+    }
+
+    public void execute() throws BuildException {
+        findSourceFiles();
+        link(this.srcList);
+    }
+
+    public boolean link(Vector srcList) throws BuildException {
+        Commandline cmd = new Commandline();
+        File linkOpt = new File(buildDir, "link.opt");
+        File linkDef = new File(buildDir, "link.def");
+
+        String libtool=project.getProperty("build.compiler.ld");
+        if(libtool==null) libtool="link";
+
+        cmd.setExecutable( libtool );
+
+        // All .obj files must be included
+        project.log( "Linking " + buildDir + "/" + soFile + ".dll");
+
+        // create a .opt file and a .def file
+        PrintWriter linkOptPw = null;
+        PrintWriter linkDefPw = null;
+        try
+        {
+            linkOptPw = new PrintWriter(new FileWriter(linkOpt));
+            linkDefPw = new PrintWriter(new FileWriter(linkDef));
+
+            // write the imports to link with to the .opt file
+            linkOptPw.print("  ");
+            Enumeration imps = imports.elements();
+            while( imps.hasMoreElements() ) {
+                JkData imp = (JkData) imps.nextElement();
+                String name = imp.getValue();
+                if( name==null ) continue;
+                linkOptPw.print(name+" ");
+            }
+
+            // write the link flags out
+
+            linkOptPw.print("/machine:I386 ");
+            linkOptPw.print("/out:" + soFile + ".dll ");
+            linkOptPw.print("/nologo ");
+            linkOptPw.print("/dll ");
+            linkOptPw.print("/incremental:no ");
+
+            // write out any additional link options
+            Enumeration opts = linkOpts.elements();
+            while( opts.hasMoreElements() ) {
+                JkData opt = (JkData) opts.nextElement();
+                String option = opt.getValue();
+                if( option == null ) continue;
+                linkOptPw.println( option );
+            }
+
+            // add debug information in if requested
+            if (optG)
+            {
+                linkOptPw.print("/debug ");
+            }
+            // def file
+            linkOptPw.println("/def:link.def");
+            // write the objects to link with to the .opt file
+            for( int i=0; i<srcList.size(); i++ ) {
+                Source source=(Source)srcList.elementAt(i);
+                File srcF = source.getFile();
+                String name=srcF.getName();
+                String targetNA[]=co_mapper.mapFileName( name );
+                if( targetNA!=null )
+                    linkOptPw.println( targetNA[0] );
+            }
+            // Write the resources to link to .opt file
+            Enumeration ress = resources.elements();
+            while( ress.hasMoreElements() ) {
+                JkData res = (JkData) ress.nextElement();
+                String name = res.getValue();
+                if( name==null ) continue;
+                linkOptPw.println(name);
+            }
+            
+            // Write the library name to the def file
+            linkDefPw.println("LIBRARY\t\""+soFile+"\"");
+
+            // write the exported symbols to the .def file
+            Enumeration exps = exports.elements();
+            if ( exps.hasMoreElements() )
+            {
+                linkDefPw.println("EXPORTS");
+                while( exps.hasMoreElements() ) {
+                    JkData exp = (JkData) exps.nextElement();
+                    String name = exp.getValue();
+                    if( name==null ) continue;
+                    linkDefPw.println("\t" + name);
+                }
+            }
+        }
+        catch (IOException ioe)
+        {
+            log("Caught IOException");
+        }
+        finally
+        {
+            if (linkOptPw != null)
+            {
+                linkOptPw.close();
+            }
+
+            if (linkDefPw != null)
+            {
+                linkDefPw.close();
+            }
+        }
+
+
+        cmd.createArgument().setValue( "@link.opt" );
+        int result=execute( cmd );
+        if( result!=0 ) {
+            log("Link failed " + result );
+            log("Command:" + cmd.toString());
+            log("Output:" );
+            if( outputstream!=null )
+                log( outputstream.toString());
+            log("StdErr:" );
+            if( errorstream!=null )
+                log( errorstream.toString());
+
+            throw new BuildException("Link failed " + soFile);
+        }
+        //         linkOpt.delete();
+        //         linkDef.delete();
+        closeStreamHandler();
+        return true;
+    }
+}
+

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkant/java/org/apache/jk/ant/compilers/MwccCompiler.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkant/java/org/apache/jk/ant/compilers/MwccCompiler.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkant/java/org/apache/jk/ant/compilers/MwccCompiler.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,164 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.jk.ant.compilers;
+
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.Enumeration;
+
+import org.apache.jk.ant.Def;
+import org.apache.jk.ant.SoTask;
+import org.apache.jk.ant.Source;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.types.Commandline;
+
+/**
+ *  Compile using MetroWerks.
+ * 
+ *  It extends SoTask so we can debug it or use it independently of <so>.
+ *  For normal use you should use the generic task, and system-specific
+ *  properties to choose the right compiler plugin ( like we select
+ *  jikes ).
+ *
+ * @author Mike Anderson
+ */
+public class MwccCompiler extends CcCompiler {
+    
+    public MwccCompiler() {
+        super();
+    };
+
+    public void setSoTask(SoTask so ) {
+        this.so=so;
+        so.setExtension(".nlm");
+        so.duplicateTo( this );
+        project.setProperty("netware", "true");
+    }
+
+    /** Compile  using mwccnlm.
+     */
+    public void compileSingleFile(Source sourceObj) throws BuildException {
+	File f=sourceObj.getFile();
+	String source=f.toString();
+        String [] includeList = ( includes==null ) ?
+            new String[] {} : includes.getIncludePatterns(project);
+
+        Commandline cmd = new Commandline();
+
+        String cc=project.getProperty("build.compiler.cc");
+        if(cc==null) cc="mwccnlm";
+        
+        cmd.setExecutable( cc );
+        addCCArgs( cmd, source, includeList );
+
+        int result=execute( cmd );
+        if( result!=0 ) {
+            log("Compile failed " + result + " " +  source );
+            log("Output:" );
+            if( outputstream!=null ) 
+                log( outputstream.toString());
+            log("StdErr:" );
+            if( errorstream!=null ) 
+                log( errorstream.toString());
+            
+            throw new BuildException("Compile failed " + source);
+        }
+        if (null == project.getProperty("save.optionFiles"))
+        {
+            File ccOpt = new File(buildDir, "cc.opt");
+            ccOpt.delete();
+        }
+        closeStreamHandler();
+
+    }
+
+    /** common compiler args
+     */
+    private void addCCArgs(Commandline cmd, String source, String includeList[]) {
+        String extra_cflags=project.getProperty("build.native.extra_cflags");
+        String localCflags=cflags;
+        File ccOpt = new File(buildDir, "cc.opt");
+        boolean useLibC = false;
+
+        // create a cc.opt file 
+        PrintWriter ccpw = null;
+        try
+        {
+            ccpw = new PrintWriter(new FileWriter(ccOpt));
+
+            for( int i=0; i<includeList.length; i++ ) {
+                ccpw.print("-I");
+                ccpw.println(includeList[i] );
+            }
+
+            if( defines.size() > 0 ) {
+                Enumeration defs=defines.elements();
+                while( defs.hasMoreElements() ) {
+                    Def d=(Def)defs.nextElement();
+                    String name=d.getName();
+                    String val=d.getValue();
+                    if( name==null ) continue;
+                    
+                    String arg="-D" + name;
+                    if( val!=null )
+                        arg+= "=" + val;
+                    ccpw.println(arg);
+
+                    // check to see if we are building using LibC
+                    if (name.equals("__NOVELL_LIBC__"))
+                        useLibC = true;
+                }
+            }
+
+            // finalize the cflags
+            if( localCflags==null ) {
+                localCflags=new String("-nosyspath -c -w nocmdline -bool on");
+                if (useLibC)
+                    localCflags += " -align 4";
+                else
+                    localCflags += " -align 1";
+
+                if( extra_cflags!=null )
+                    localCflags+=" " + extra_cflags;
+            }
+
+            if (optG)
+                localCflags += " -g";
+
+            // write the compilation flags out
+            ccpw.println(localCflags);
+        }
+        catch (IOException ioe)
+        {
+            log("Caught IOException");
+        }
+        finally
+        {
+            if (ccpw != null)
+            {
+                ccpw.close();
+            }
+        }
+
+        project.log( "Compiling " + source);
+        cmd.createArgument().setValue( source );
+        cmd.createArgument().setValue( "@cc.opt" );
+    }
+}
+

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkant/java/org/apache/jk/ant/compilers/MwldLinker.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkant/java/org/apache/jk/ant/compilers/MwldLinker.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkant/java/org/apache/jk/ant/compilers/MwldLinker.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,222 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.jk.ant.compilers;
+
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.Enumeration;
+import java.util.Vector;
+
+import org.apache.jk.ant.JkData;
+import org.apache.jk.ant.SoTask;
+import org.apache.jk.ant.Source;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.types.Commandline;
+import org.apache.tools.ant.util.GlobPatternMapper;
+
+/**
+ * Link using libtool.
+ * 
+ * @author Costin Manolache
+ */
+public class MwldLinker extends LinkerAdapter {
+    GlobPatternMapper lo_mapper=new GlobPatternMapper();
+    
+    public MwldLinker() {
+        super();
+        lo_mapper.setFrom("*.c");
+	lo_mapper.setTo("*.o");
+    }
+
+    public void setSoTask(SoTask so ) {
+        this.so=so;
+        so.setExtension(".nlm");
+        so.duplicateTo( this );
+        project.setProperty("netware", "true");
+
+        Enumeration e=altSoFiles.elements();
+        while (e.hasMoreElements())
+        {
+            JkData data = (JkData) e.nextElement();
+            String altSo = data.getValue();
+            if (altSo == null) 
+                continue;
+            else
+            {
+                so.setTarget(altSo);    // set it on the master copy
+                setTarget(altSo);       // set it on ourself
+                break;
+            }
+        }
+    }
+
+    public void execute() throws BuildException {
+        findSourceFiles();
+        link(this.srcList);
+    }
+
+    /** Link using libtool.
+     */
+    public boolean link(Vector srcList) throws BuildException {
+        Commandline cmd = new Commandline();
+        File linkOpt = new File(buildDir, "link.opt");
+        File linkDef = new File(buildDir, "link.def");
+        boolean useLibC = false;
+
+        String libtool=project.getProperty("build.compiler.ld");
+        if(libtool==null) libtool="mwldnlm";
+
+        cmd.setExecutable( libtool );
+        
+        // All .obj files must be included
+        project.log( "Linking " + buildDir + "/" + soFile + ".nlm");
+
+        // create a .opt file and a .def file
+        PrintWriter linkOptPw = null;
+        PrintWriter linkDefPw = null;
+        try
+        {
+            String libBase = project.getProperty("build.compiler.base");
+            if (libBase == null) libBase = "\\tools\\mw\\5.3";
+            linkOptPw = new PrintWriter(new FileWriter(linkOpt));
+            linkDefPw = new PrintWriter(new FileWriter(linkDef));
+
+            // write the link flags out
+            linkOptPw.println("-warnings off");
+            linkOptPw.println("-zerobss");
+            linkOptPw.println("-o " + soFile + ".nlm");
+            linkOptPw.println("-map " + soFile + ".map");
+            linkOptPw.println("-nodefaults");
+
+            // add debug information in if requested
+            if (optG)
+            {
+                linkOptPw.println("-g");
+                linkOptPw.println("-sym internal");
+                linkOptPw.println("-sym codeview4");
+                linkOptPw.println("-osym " + soFile + ".NCV");
+            }
+
+            // write out any additional link options
+            Enumeration opts = linkOpts.elements();
+            while( opts.hasMoreElements() ) {
+                JkData opt = (JkData) opts.nextElement();
+                String option = opt.getValue();
+                if( option == null ) continue;
+
+                linkOptPw.println( option );
+                option = option.toLowerCase();
+
+                // check to see if we are building using LibC
+                if (option.indexOf("libc") > 0)
+                    useLibC = true;
+            }
+
+            // add the default startup code to the list of objects
+            if (useLibC)
+                linkOptPw.println("-llibcpre.o");
+            else
+                linkOptPw.println(libBase + "\\lib\\nwpre.obj");
+
+            // write the objects to link with to the .opt file
+            for( int i=0; i<srcList.size(); i++ ) {
+                Source source=(Source)srcList.elementAt(i);
+                File srcF = source.getFile();
+                String name=srcF.getName();
+                String targetNA[]=lo_mapper.mapFileName( name );
+                if( targetNA!=null )
+                    linkOptPw.println( targetNA[0] );
+            }
+            linkOptPw.println("-commandfile link.def");
+
+            // write the dependant modules to the .def file
+            Enumeration mods = modules.elements();
+            while( mods.hasMoreElements() ) {
+                JkData mod = (JkData) mods.nextElement();
+                String name = mod.getValue();
+                if( name==null ) continue;
+                linkDefPw.println("module " + name);
+            }
+
+            // write the imports to link with to the .def file
+            Enumeration imps = imports.elements();
+            while( imps.hasMoreElements() ) {
+                JkData imp = (JkData) imps.nextElement();
+                String name = imp.getValue();
+                if( name==null ) continue;
+                if (imp.isFile())
+                    linkDefPw.println("Import @" + name);
+                else
+                    linkDefPw.println("Import " + name);
+            }
+
+            // write the exports to link with to the .def file
+            Enumeration exps = exports.elements();
+            while( exps.hasMoreElements() ) {
+                JkData exp = (JkData) exps.nextElement();
+                String name = exp.getValue();
+                if( name==null ) continue;
+                if (exp.isFile())
+                    linkDefPw.println("Export @" + name);
+                else
+                    linkDefPw.println("Export " + name);
+            }
+        }
+        catch (IOException ioe)
+        {
+            log("Caught IOException");
+        }
+        finally
+        {
+            if (linkOptPw != null)
+            {
+                linkOptPw.close();
+            }
+
+            if (linkDefPw != null)
+            {
+                linkDefPw.close();
+            }
+        }
+
+
+        cmd.createArgument().setValue( "@link.opt" );
+        int result=execute( cmd );
+        if( result!=0 ) {
+            log("Link failed " + result );
+            log("Command:" + cmd.toString());
+            log("Output:" );
+            if( outputstream!=null ) 
+                log( outputstream.toString());
+            log("StdErr:" );
+            if( errorstream!=null ) 
+                log( errorstream.toString());
+            
+            throw new BuildException("Link failed " + soFile);
+        }
+        if (null == project.getProperty("save.optionFiles"))
+        {
+            linkOpt.delete();
+            linkDef.delete();
+        }
+        closeStreamHandler();
+        return true;
+    }
+}
+

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/build/classes/org/apache/jk/status/JkBalancer.class
===================================================================
(Binary files differ)


Property changes on: branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/build/classes/org/apache/jk/status/JkBalancer.class
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/build/classes/org/apache/jk/status/JkBalancerMapping.class
===================================================================
(Binary files differ)


Property changes on: branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/build/classes/org/apache/jk/status/JkBalancerMapping.class
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/build/classes/org/apache/jk/status/JkBalancerMember.class
===================================================================
(Binary files differ)


Property changes on: branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/build/classes/org/apache/jk/status/JkBalancerMember.class
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/build/classes/org/apache/jk/status/JkServer.class
===================================================================
(Binary files differ)


Property changes on: branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/build/classes/org/apache/jk/status/JkServer.class
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/build/classes/org/apache/jk/status/JkStatus.class
===================================================================
(Binary files differ)


Property changes on: branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/build/classes/org/apache/jk/status/JkStatus.class
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/build/classes/org/apache/jk/status/JkStatusAccessor.class
===================================================================
(Binary files differ)


Property changes on: branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/build/classes/org/apache/jk/status/JkStatusAccessor.class
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/build/classes/org/apache/jk/status/JkStatusParser.class
===================================================================
(Binary files differ)


Property changes on: branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/build/classes/org/apache/jk/status/JkStatusParser.class
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/build/classes/org/apache/jk/status/JkStatusResetTask.class
===================================================================
(Binary files differ)


Property changes on: branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/build/classes/org/apache/jk/status/JkStatusResetTask.class
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/build/classes/org/apache/jk/status/JkStatusTask.class
===================================================================
(Binary files differ)


Property changes on: branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/build/classes/org/apache/jk/status/JkStatusTask.class
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/build/classes/org/apache/jk/status/JkStatusUpdateTask.class
===================================================================
(Binary files differ)


Property changes on: branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/build/classes/org/apache/jk/status/JkStatusUpdateTask.class
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/build/classes/org/apache/jk/status/LocalStrings.properties
===================================================================

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/build/classes/org/apache/jk/status/antlib.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/build/classes/org/apache/jk/status/antlib.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/build/classes/org/apache/jk/status/antlib.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<antlib>
+  <typedef
+        name="update"
+        classname="org.apache.jk.status.JkStatusUpdateTask" />
+  <typedef
+        name="reset"
+        classname="org.apache.jk.status.JkStatusResetTask" />
+  <typedef
+        name="status"
+        classname="org.apache.jk.status.JkStatusTask" />
+</antlib>

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/build/classes/org/apache/jk/status/jkstatus.tasks
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/build/classes/org/apache/jk/status/jkstatus.tasks	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/build/classes/org/apache/jk/status/jkstatus.tasks	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,5 @@
+# Apache mod_jk jk status tasks
+jkUpdate=org.apache.jk.status.JkStatusUpdateTask
+jkReset=org.apache.jk.status.JkStatusResetTask
+jkStatus=org.apache.jk.status.JkStatusTask
+

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/build/classes/org/apache/jk/status/mbeans-descriptors.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/build/classes/org/apache/jk/status/mbeans-descriptors.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/build/classes/org/apache/jk/status/mbeans-descriptors.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,32 @@
+<?xml version="1.0"?>
+<mbeans-descriptors>
+
+<!--
+  <mbean name="JkStatus"
+         description="represent the apache mod_jk status"
+         domain="Jk"
+         group="Status"
+         type="org.apache.jk.status.JkStatusMbean">
+    
+    <attribute name="className"
+               description="Fully qualified class name of the managed object"
+               type="java.lang.String"
+               writeable="false"/>
+
+    <attribute name="info"
+               description="The base directory for Context configuration files"
+               type="java.lang.String"
+               writeable="false" />
+      
+    <operation name="check"
+               description="Check a web application name for updates"
+               impact="ACTION"
+               returnType="void">
+      <parameter name="name"
+                 description="Application name"
+                 type="java.lang.String"/>
+    </operation>
+
+  </mbean>
+-->
+</mbeans-descriptors>

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/build.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/build.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/build.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,141 @@
+<project name="JkStatus" default="dist" basedir=".">
+
+
+  <!-- ===================== Initialize Property Values =================== -->
+
+  <property file="../../../build/build.properties" />
+  <property file="../../../build/build.properties.default" />
+
+  <!-- Build Defaults -->
+  <property name="jtc.home"  location="../.."/>
+  <property name="catalina.build" location="../../../build/build"/>
+  <property name="jk.build"  value="${jtc.home}/jk/jkstatus/build"/>
+  <property name="jk.dist"   value="${jtc.home}/jk/jkstatus/dist"/>
+
+    <!-- Construct Catalina classpath -->
+  <path id="jtc.classpath">
+    <pathelement location="${catalina.build}/server/lib/catalina.jar"/>
+    <pathelement location="${catalina.build}/server/lib/catalina-ant.jar"/>
+    <pathelement location="${catalina.build}/server/lib/tomcat-util.jar"/>
+    <pathelement location="${commons-modeler.jar}"/>
+    <pathelement location="${commons-logging.jar}"/>
+    <pathelement location="${jmx.jar}"/>
+    <pathelement location="${catalina.build}/common/lib/servlet-api.jar"/>
+  </path>
+
+    <!-- Source path -->
+  <path id="javadoc.sourcepath">
+    <pathelement location="src/share"/>
+  </path>
+
+
+  <!-- =================== BUILD: Set compile flags ======================= -->
+  <target name="flags">
+    <!-- JDK flags -->
+    <available property="jdk.1.2.present" classname="java.util.HashMap" />
+    <available property="jdk.1.3.present" 
+     classname="java.lang.reflect.Proxy" />
+    <available property="jdk.1.4.present" classname="java.nio.Buffer" />
+  </target>
+
+
+  <!-- =================== BUILD: Set compile flags ======================= -->
+  <target name="flags.display" depends="flags" unless="flags.hide">
+
+    <echo message="--- Build environment for Catalina ---" />
+
+    <echo message="If ${property_name} is displayed, then the property is not set)" />
+
+    <echo message="--- Build options ---" />
+    <echo message="full.dist=${full.dist}" />
+    <echo message="build.sysclasspath=${build.sysclasspath}" />
+    <echo message="compile.debug=${compile.debug}" />
+    <echo message="compile.deprecation=${compile.deprecation}" />
+    <echo message="compile.optimize=${compile.optimize}" />
+
+    <echo message="--- Ant Flags ---" />
+    <echo message="&lt;style&gt; task available (required)=${style.available}" />
+
+    <echo message="--- JDK ---" />
+    <echo message="jdk.1.2.present=${jdk.1.2.present}" />
+    <echo message="jdk.1.3.present=${jdk.1.3.present}" />
+    <echo message="jdk.1.4.present=${jdk.1.4.present}" />
+
+  </target>
+
+  <!-- =================== BUILD: Create Directories ====================== -->
+  <target name="build-prepare">
+    <mkdir dir="${catalina.build}"/>
+    <mkdir dir="${catalina.build}/classes"/>
+    <mkdir dir="${jk.dist}"/>
+    <mkdir dir="${jk.build}"/>
+    <mkdir dir="${jk.build}/classes"/>
+  </target>
+
+  <!-- ================ BUILD: Compile Catalina Components ================ -->
+  
+  <target name="build-jk-status" depends="build-prepare">
+    <!-- Compile internal server components -->
+    <javac srcdir="${basedir}/src/share" destdir="${jk.build}/classes"
+           debug="${compile.debug}" deprecation="${compile.deprecation}"
+           optimize="${compile.optimize}"
+           excludes="**/.svn/**"  	   
+    	>
+        <classpath refid="jtc.classpath" />
+    </javac>
+    <copy file="${basedir}/src/share/org/apache/jk/status/LocalStrings.properties"
+    	  tofile="${jk.build}/classes/org/apache/jk/status/LocalStrings.properties"/>
+    <copy file="${basedir}/src/share/org/apache/jk/status/mbeans-descriptors.xml"
+    	  tofile="${jk.build}/classes/org/apache/jk/status/mbeans-descriptors.xml"/>
+    <copy file="${basedir}/src/share/org/apache/jk/status/antlib.xml"
+    	  tofile="${jk.build}/classes/org/apache/jk/status/antlib.xml"/>
+    <copy file="${basedir}/src/share/org/apache/jk/status/jkstatus.tasks"
+    	  tofile="${jk.build}/classes/org/apache/jk/status/jkstatus.tasks"/>
+   </target>
+
+
+  <!-- ================ BUILD: Create Catalina Javadocs =================== -->
+  <target name="javadoc">
+    <delete dir="${jk.build}/javadoc"/>
+    <mkdir dir="${jk.build}/javadoc"/>
+    <javadoc packagenames="org.apache.jk.status.*"
+      classpathref="jtc.classpath"
+      sourcepathref="javadoc.sourcepath"
+      destdir="${jk.build}/javadoc"
+      author="true"
+      version="true"
+      windowtitle="Jk Status Internal API Documentation"
+      doctitle="Jk Status API"
+      bottom="Copyright &#169; 2000-2005 Apache Software Foundation.  All Rights Reserved."
+    />
+  </target>
+
+  <!-- ======================= BUILD: Clean Directory ===================== -->
+  <target name="build-clean">
+    <delete dir="${jk.build}"/>
+  </target>
+
+  <!-- ==================== BUILD: Rebuild Everything ===================== -->
+
+
+  <!-- ================ DIST: Create Distribution ========================= -->
+  <target name="dist" depends="build-jk-status">
+    
+    <jar destfile="${jk.dist}/tomcat-jkstatus-ant.jar"
+         basedir="${jk.build}/classes">
+       <include name="org/apache/jk/status/**" />
+       <exclude name="**/package.html" />
+       <exclude name="**/LocalStrings_*" />
+    </jar>
+  </target>
+
+  <target name="copy" depends="dist" >
+     <copy file="${jk.dist}/tomcat-jkstatus-ant.jar" todir="${catalina.build}/server/lib" />
+     <copy file="conf/jkstatus-tasks.xml" todir="${catalina.build}/bin" />
+  </target>
+  
+  <!-- ======================== DIST: Clean Directory ===================== -->
+
+  <!-- ====================== Convenient Synonyms ========================= -->
+
+</project>

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/conf/jkstatus-tasks.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/conf/jkstatus-tasks.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/conf/jkstatus-tasks.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,22 @@
+<!--
+  XML file for importing apache jk status ant tasks.
+  <import file="${jkstatus.home}/lib/jkstatus-tasks.xml"/>
+-->
+
+<project name="jkstatus-tasks" >
+  <description>Apache mod_jk ant jkstatus Tasks</description>
+  <!-- set jkstatus.home if it's not already set -->
+  <dirname property="jkstatus.home.bin.dir" file="${ant.file.jkstatus-tasks}"/>
+  <property name="jkstatus.home" value="${jkstatus.home.bin.dir}/.."/>
+  <path id="jkstatus.path">
+      <pathelement location="${jkstatus.home}/bin/commons-logging-api.jar"/>
+      <pathelement location="${jkstatus.home}/lib/catalina-ant.jar"/>
+      <pathelement location="${jkstatus.home}/lib/tomcat-jkstatus-ant.jar"/>
+      <pathelement location="${jkstatus.home}/lib/tomcat-util.jar"/>
+  </path>
+
+  <taskdef resource="org/apache/jk/status/jkstatus.tasks">
+       <classpath refid="jkstatus.path"/>
+  </taskdef>
+
+</project>

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/dist/tomcat-jkstatus-ant.jar
===================================================================
(Binary files differ)


Property changes on: branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/dist/tomcat-jkstatus-ant.jar
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/example/jkstatus.properties.default
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/example/jkstatus.properties.default	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/example/jkstatus.properties.default	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,6 @@
+jkstatus.host=localhost
+jkstatus.port=80
+jkstatus.username=manager
+jkstatus.password=tomcat
+jkstatus.url=http://${jkstatus.host}:${jkstatus.port}/jkstatus
+

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/example/jkstatus.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/example/jkstatus.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/example/jkstatus.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,105 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!-- @author Peter Rossbach -->
+
+<project name="status" 
+         default="status" basedir=".">
+
+    <property name="profile" value=""/>
+    <property file="jkstatus${profile}.properties"/>
+    <property file="jkstatus${profile}.properties.default"/>
+    <property name="catalina.home" location="../../../../build/build"/>
+
+    <path id="jkstatus.path">
+      <pathelement location="${catalina.home}/bin/commons-logging-api.jar"/>
+      <pathelement location="${catalina.home}/server/lib/catalina-ant.jar"/>
+      <pathelement location="${catalina.home}/server/lib/tomcat-jkstatus-ant.jar"/>
+      <pathelement location="${catalina.home}/server/lib/tomcat-util.jar"/>
+    </path>
+
+    <taskdef resource="org/apache/jk/status/jkstatus.tasks">
+       <classpath refid="jkstatus.path"/>
+    </taskdef>
+
+    <!--
+       ########################################################################################################
+       public
+       ########################################################################################################
+    -->   
+    <target name="status"
+            depends="-status-modjk-access" 
+            description="got jk status" />
+
+    <target name="reset"
+            depends="-status-modjk-reset" 
+            description="reset jk status" />
+
+    <!--
+       ########################################################################################################
+       private
+       ########################################################################################################
+    -->   
+    
+   <target name="-status-modjk-access">
+      <jkStatus url="${jkstatus.url}" 
+                username="${jkstatus.username}"
+                password="${jkstatus.password}"
+                resultproperty="jkstatus"
+                failOnError="false"/>
+      <echoproperties prefix="jkstatus" />           
+      <jkStatus url="${jkstatus.url}" 
+                username="${jkstatus.username}"
+                password="${jkstatus.password}"
+                loadbalancer="loadbalancer"
+                resultproperty="lb"
+                failOnError="false"/>
+      <echoproperties prefix="lb" />           
+      <jkStatus url="${jkstatus.url}" 
+                username="${jkstatus.username}"
+                password="${jkstatus.password}"
+                worker="node01"
+                resultproperty="worker"
+                failOnError="false"/>
+     <echoproperties prefix="worker" />
+     <jkUpdate url="${jkstatus.url}" 
+               username="${jkstatus.username}"
+               password="${jkstatus.password}"
+               workerLoadFactor="${worker.node01.lbfactor}"
+               workerRedirect="${worker.node01.redirect}"
+               workerClusterDomain="d20"
+               workerDisabled="true"
+               workerStopped="false"
+               workerLb="${worker.node01.lb.name}"
+               worker = "node01"
+               workerType = "worker"/>
+      <jkStatus url="${jkstatus.url}" 
+                username="${jkstatus.username}"
+                password="${jkstatus.password}"
+                worker="node01"
+                resultproperty="workerafter"
+                failOnError="false"/>
+      <echoproperties prefix="workerafter" />
+   </target>     
+
+   <target name="-status-modjk-reset">
+      <jkStatus url="${jkstatus.url}" 
+                username="${jkstatus.username}"
+                password="${jkstatus.password}"
+                resultproperty="jkstatus.before"
+                failOnError="false"/>
+      <echoproperties prefix="jkstatus.before" />   
+        
+      <jkReset  url="${jkstatus.url}" 
+                username="${jkstatus.username}"
+                password="${jkstatus.password}"
+                workerLb="loadbalancer"
+       />
+
+       <jkStatus url="${jkstatus.url}" 
+                username="${jkstatus.username}"
+                password="${jkstatus.password}"
+                resultproperty="jkstatus.after"
+                failOnError="false"/>
+      <echoproperties prefix="jkstatus.after" />
+   </target>           
+
+</project>

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/src/share/org/apache/jk/status/JkBalancer.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/src/share/org/apache/jk/status/JkBalancer.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/src/share/org/apache/jk/status/JkBalancer.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,161 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.jk.status;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author Peter Rossbach
+ * @version $Revision:$ $Date:$
+ * @see org.apache.jk.status.JkStatusParser
+ */
+public class JkBalancer implements Serializable {
+
+    int id ;
+    String name ;
+    String type ;
+    boolean sticky ;
+    boolean stickyforce;
+    int retries ;
+    int recover ;
+        
+    List members = new ArrayList() ;
+    List mappings = new ArrayList() ;
+     
+    /**
+     * @return Returns the id.
+     */
+    public int getId() {
+        return id;
+    }
+    /**
+     * @param id The id to set.
+     */
+    public void setId(int id) {
+        this.id = id;
+    }
+    /**
+     * @return Returns the mappings.
+     */
+    public List getBalancerMappings() {
+        return mappings;
+    }
+    /**
+     * @param mappings The mappings to set.
+     */
+    public void setBalancerMappings(List mappings) {
+        this.mappings = mappings;
+    }
+    public void addBalancerMapping(JkBalancerMapping mapping) {
+        mappings.add(mapping);
+    }
+    public void removeBalancerMapping(JkBalancerMapping mapping) {
+        mappings.remove(mapping);
+    }
+    /**
+     * @return Returns the members.
+     */
+    public List getBalancerMembers() {
+        return members;
+    }
+    /**
+     * @param members The members to set.
+     */
+    public void setBalancerMembers(List members) {
+        this.members = members;
+    }
+    public void addBalancerMember(JkBalancerMember member) {
+        members.add(member);
+    }   
+    public void removeBalancerMember(JkBalancerMember member) {
+        members.remove(member);
+    }   
+    /**
+     * @return Returns the name.
+     */
+    public String getName() {
+        return name;
+    }
+    /**
+     * @param name The name to set.
+     */
+    public void setName(String name) {
+        this.name = name;
+    }
+    /**
+     * @return Returns the recover.
+     */
+    public int getRecover() {
+        return recover;
+    }
+    /**
+     * @param recover The recover to set.
+     */
+    public void setRecover(int recover) {
+        this.recover = recover;
+    }
+    /**
+     * @return Returns the retries.
+     */
+    public int getRetries() {
+        return retries;
+    }
+    /**
+     * @param retries The retries to set.
+     */
+    public void setRetries(int retries) {
+        this.retries = retries;
+    }
+    /**
+     * @return Returns the sticky.
+     */
+    public boolean isSticky() {
+        return sticky;
+    }
+    /**
+     * @param sticky The sticky to set.
+     */
+    public void setSticky(boolean sticky) {
+        this.sticky = sticky;
+    }
+    /**
+     * @return Returns the stickyforce.
+     */
+    public boolean isStickyforce() {
+        return stickyforce;
+    }
+    /**
+     * @param stickyforce The stickyforce to set.
+     */
+    public void setStickyforce(boolean stickyforce) {
+        this.stickyforce = stickyforce;
+    }
+    /**
+     * @return Returns the type.
+     */
+    public String getType() {
+        return type;
+    }
+    /**
+     * @param type The type to set.
+     */
+    public void setType(String type) {
+        this.type = type;
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/src/share/org/apache/jk/status/JkBalancerMapping.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/src/share/org/apache/jk/status/JkBalancerMapping.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/src/share/org/apache/jk/status/JkBalancerMapping.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,66 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.jk.status;
+
+import java.io.Serializable;
+
+/**
+ * @author Peter Rossbach
+ * @version $Revision:$ $Date:$
+ * @see org.apache.jk.status.JkStatusParser
+ */
+public class JkBalancerMapping implements Serializable {
+    String type ;
+    String uri;
+    String context ;
+    
+    /**
+     * @return Returns the context.
+     */
+    public String getContext() {
+        return context;
+    }
+    /**
+     * @param context The context to set.
+     */
+    public void setContext(String context) {
+        this.context = context;
+    }
+    /**
+     * @return Returns the type.
+     */
+    public String getType() {
+        return type;
+    }
+    /**
+     * @param type The type to set.
+     */
+    public void setType(String type) {
+        this.type = type;
+    }
+    /**
+     * @return Returns the uri.
+     */
+    public String getUri() {
+        return uri;
+    }
+    /**
+     * @param uri The uri to set.
+     */
+    public void setUri(String uri) {
+        this.uri = uri;
+    }
+ }

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/src/share/org/apache/jk/status/JkBalancerMember.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/src/share/org/apache/jk/status/JkBalancerMember.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/src/share/org/apache/jk/status/JkBalancerMember.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,438 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.jk.status;
+
+import java.io.Serializable;
+
+/**
+ * @author Peter Rossbach
+ * @version $Revision:$ $Date:$
+ * @see org.apache.jk.status.JkStatusParser
+ */
+/**
+ * @author peter
+ *
+ */
+public class JkBalancerMember implements Serializable {
+    
+    int id;
+
+    String name;
+
+    /* possible with > 1.2.16 */
+    String jvm_route;
+
+    String type;
+
+    String host;
+
+    int port;
+
+    String address;
+
+    /* deprecated with mod_jk 1.2.16*/
+    String status;
+    
+    /* possible with > 1.2.16 */
+    String activation; 
+
+    /* possible with > 1.2.16 */
+    String state; 
+        
+    int lbfactor;
+
+    long lbvalue;
+
+    /* possible with > 1.2.16 */
+    long lbmult = -1 ;
+    
+    int elected;
+
+    long readed;
+
+    long transferred;
+
+    long errors;
+
+    long clienterrors = -1;
+    
+    int busy;
+    
+    /* possible with > 1.2.16 */
+    int maxbusy = -1;
+    
+    String redirect;
+    
+    String domain;
+    
+    /* possible with > 1.2.16 */
+    int distance = -1;
+
+    /**
+     * @return Returns the jvm_route.
+     * @since mod_jk 1.2.19
+     */
+    public String getJvm_route() {
+        return jvm_route;
+    }
+
+    /**
+     * @param jvm_route The jvm_route to set.
+     * @since mod_jk 1.2.19
+     */
+    public void setJvm_route(String jvm_route) {
+        this.jvm_route = jvm_route;
+    }
+
+    /**
+     * @return Returns the address.
+     */
+    public String getAddress() {
+        return address;
+    }
+
+    /**
+     * @param address
+     *            The address to set.
+     */
+    public void setAddress(String address) {
+        this.address = address;
+    }
+
+    /**
+     * @return Returns the busy.
+     */
+    public int getBusy() {
+        return busy;
+    }
+
+    /**
+     * @param busy
+     *            The busy to set.
+     */
+    public void setBusy(int busy) {
+        this.busy = busy;
+    }
+
+
+    /**
+     * @return Returns the maxbusy.
+     * @since mod_jk 1.2.18
+     */
+    public int getMaxbusy() {
+        return maxbusy;
+    }
+
+    /**
+     * @param maxbusy The maxbusy to set.
+     * @since mod_jk 1.2.18
+     */
+    public void setMaxbusy(int maxbusy) {
+        this.maxbusy = maxbusy;
+    }
+
+    /**
+     * @return Returns the elected.
+     */
+    public int getElected() {
+        return elected;
+    }
+
+    /**
+     * @param elected
+     *            The elected to set.
+     */
+    public void setElected(int elected) {
+        this.elected = elected;
+    }
+
+    /**
+     * @return Returns the clienterrors.
+     * @since mod_jk 1.2.19
+     */
+    public long getClienterrors() {
+        return clienterrors;
+    }
+
+    /**
+     * @param clienterrors The clienterrors to set.
+     * @since mod_jk 1.2.19
+     */
+    public void setClienterrors(long clienterrors) {
+        this.clienterrors = clienterrors;
+    }
+
+    /**
+     * @return Returns the errors.
+     */
+    public long getErrors() {
+        return errors;
+    }
+
+    /**
+     * @param errors
+     *            The errors to set.
+     */
+    public void setErrors(long errors) {
+        this.errors = errors;
+    }
+
+    /**
+     * @return Returns the host.
+     */
+    public String getHost() {
+        return host;
+    }
+
+    /**
+     * @param host
+     *            The host to set.
+     */
+    public void setHost(String host) {
+        this.host = host;
+    }
+
+    /**
+     * @return Returns the id.
+     */
+    public int getId() {
+        return id;
+    }
+
+    /**
+     * @param id
+     *            The id to set.
+     */
+    public void setId(int id) {
+        this.id = id;
+    }
+
+    /**
+     * @return Returns the lbfactor.
+     */
+    public int getLbfactor() {
+        return lbfactor;
+    }
+
+    /**
+     * @param lbfactor
+     *            The lbfactor to set.
+     */
+    public void setLbfactor(int lbfactor) {
+        this.lbfactor = lbfactor;
+    }
+
+    /**
+     * @return Returns the lbvalue.
+     */
+    public long getLbvalue() {
+        return lbvalue;
+    }
+
+    /**
+     * @param lbvalue
+     *            The lbvalue to set.
+     */
+    public void setLbvalue(long lbvalue) {
+        this.lbvalue = lbvalue;
+    }
+    
+    /**
+     * @return Returns the lbmult.
+     * @since mod_jk 1.2.19
+     */
+    public long getLbmult() {
+        return lbmult;
+    }
+
+    /**
+     * @param lbmult The lbmult to set.
+     * @since mod_jk 1.2.19
+     */
+    public void setLbmult(long lbmult) {
+        this.lbmult = lbmult;
+    }
+
+    /**
+     * @return Returns the name.
+     */
+    public String getName() {
+        return name;
+    }
+
+    /**
+     * @param name
+     *            The name to set.
+     */
+    public void setName(String name) {
+        this.name = name;
+    }
+
+
+    /**
+     * @return Returns the port.
+     */
+    public int getPort() {
+        return port;
+    }
+
+    /**
+     * @param port
+     *            The port to set.
+     */
+    public void setPort(int port) {
+        this.port = port;
+    }
+
+    /**
+     * @return Returns the readed.
+     */
+    public long getReaded() {
+        return readed;
+    }
+
+    /**
+     * @param readed
+     *            The readed to set.
+     */
+    public void setReaded(long readed) {
+        this.readed = readed;
+    }
+
+    /**
+     * @return Returns the status.
+     * @deprecated since 1.2.16
+     */
+    public String getStatus() {
+        return status;
+    }
+
+    /**
+     * @param status
+     *            The status to set.
+     * @deprecated since 1.2.16
+     */
+    public void setStatus(String status) {
+        this.status = status;
+    }
+
+    /**
+     * @return Returns the activation.
+     * @since mod_jk 1.2.19
+     */
+    public String getActivation() {
+        return activation;
+    }
+
+    /**
+     * @param activation The activation to set.
+     * @since mod_jk 1.2.19
+     */
+    public void setActivation(String activation) {
+        this.activation = activation;
+    }
+
+    /**
+     * @return Returns the state.
+     * @since mod_jk 1.2.19
+     */
+    public String getState() {
+        return state;
+    }
+
+    /**
+     * @param state The state to set.
+     * @since mod_jk 1.2.19
+     */
+    public void setState(String state) {
+        this.state = state;
+    }
+
+    /**
+     * @return Returns the transferred.
+     */
+    public long getTransferred() {
+        return transferred;
+    }
+
+    /**
+     * @param transferred
+     *            The transferred to set.
+     */
+    public void setTransferred(long transferred) {
+        this.transferred = transferred;
+    }
+
+    /**
+     * @return Returns the type.
+     */
+    public String getType() {
+        return type;
+    }
+
+    /**
+     * @param type
+     *            The type to set.
+     */
+    public void setType(String type) {
+        this.type = type;
+    }
+    
+    
+    /**
+     * @return Returns the domain.
+     */
+    public String getDomain() {
+        return domain;
+    }
+    /**
+     * @param domain The domain to set.
+     */
+    public void setDomain(String domain) {
+        this.domain = domain;
+    }
+ 
+    /**
+     * @return Returns the redirect.
+     */
+    public String getRedirect() {
+        return redirect;
+    }
+    /**
+     * @param redirect The redirect to set.
+     */
+    public void setRedirect(String redirect) {
+        this.redirect = redirect;
+    }
+
+    /**
+     * @return Returns the distance.
+     * @since mod_jk 1.2.18
+     */
+    public int getDistance() {
+        return distance;
+    }
+
+    /**
+     * @param distance The distance to set.
+     * @since mod_jk 1.2.18
+     */
+    public void setDistance(int distance) {
+        this.distance = distance;
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/src/share/org/apache/jk/status/JkServer.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/src/share/org/apache/jk/status/JkServer.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/src/share/org/apache/jk/status/JkServer.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,79 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.jk.status;
+
+import java.io.Serializable;
+
+/**
+ * @author Peter Rossbach
+ * @version $Revision:$ $Date:$
+ * @see org.apache.jk.status.JkStatusParser
+ */
+public class JkServer implements Serializable {
+    String name ;
+    String port;  
+    String software;
+    String version ;
+    
+    /**
+     * @return Returns the name.
+     */
+    public String getName() {
+        return name;
+    }
+    /**
+     * @param name The name to set.
+     */
+    public void setName(String name) {
+        this.name = name;
+    }
+    /**
+     * @return Returns the port.
+     */
+    public String getPort() {
+        return port;
+    }
+    /**
+     * @param port The port to set.
+     */
+    public void setPort(String port) {
+        this.port = port;
+    }
+    /**
+     * @return Returns the software.
+     */
+    public String getSoftware() {
+        return software;
+    }
+    /**
+     * @param software The software to set.
+     */
+    public void setSoftware(String software) {
+        this.software = software;
+    }
+    /**
+     * @return Returns the version.
+     */
+    public String getVersion() {
+        return version;
+    }
+    /**
+     * @param version The version to set.
+     */
+    public void setVersion(String version) {
+        this.version = version;
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/src/share/org/apache/jk/status/JkStatus.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/src/share/org/apache/jk/status/JkStatus.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/src/share/org/apache/jk/status/JkStatus.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,63 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.jk.status;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author Peter Rossbach
+ * @version $Revision:$ $Date:$
+ * @see org.apache.jk.status.JkStatusParser
+ */
+public class JkStatus implements Serializable {
+
+    JkServer server ;
+    List balancers = new ArrayList() ;
+    
+    /**
+     * @return Returns the balancers.
+     */
+    public List getBalancers() {
+        return balancers;
+    }
+    /**
+     * @param balancers The balancers to set.
+     */
+    public void setBalancers(List balancers) {
+        this.balancers = balancers;
+    }
+    
+    public void addBalancer(JkBalancer balancer) {
+      balancers.add(balancer);
+    }
+    
+    public void removeBalancer(JkBalancer balancer) {
+      balancers.remove(balancer);
+    }
+
+    /**
+     * @return Returns the server.
+     */
+    public JkServer getServer() {
+        return server;
+    }
+    public void setServer(JkServer server) {
+       this.server = server ;
+    }
+    
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/src/share/org/apache/jk/status/JkStatusAccessor.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/src/share/org/apache/jk/status/JkStatusAccessor.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/src/share/org/apache/jk/status/JkStatusAccessor.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,129 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.jk.status;
+
+import java.io.IOException;
+import java.net.HttpURLConnection;
+import java.net.MalformedURLException;
+import java.net.ProtocolException;
+import java.net.URL;
+import java.net.URLConnection;
+
+import org.apache.catalina.util.Base64;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.tomcat.util.digester.Digester;
+
+/**
+ * @author Peter Rossbach
+ * @version $Revision:$ $Date:$
+ * @see org.apache.jk.status.JkStatusParser
+ * @since 5.5.10
+ */
+public class JkStatusAccessor {
+    
+    private static Log log = LogFactory.getLog(JkStatusAccessor.class);
+    /**
+     * The descriptive information about this implementation.
+     */
+    protected static final String info = "org.apache.jk.status.JkStatusAccessor/1.0";
+
+    /**
+     * Parse Apache mod_jk Status  from base url http://host:port/jkstatus)
+     * @param url
+     * @param username
+     * @param password
+     *  
+     */
+    public JkStatus status(String url, String username, String password)
+            throws Exception {
+
+        if(url == null || "".equals(url))
+            return null ;
+        HttpURLConnection hconn = null;
+        JkStatus status = null;
+
+        try {
+            hconn = openConnection(url + "?cmd=show&mime=xml", username, password);
+            Digester digester = JkStatusParser.getDigester();
+            synchronized (digester) {
+                status = (JkStatus) digester.parse(hconn.getInputStream());
+            }
+        } catch (Throwable t) {
+            throw new Exception(t);
+        } finally {
+            if (hconn != null) {
+                try {
+                    hconn.disconnect();
+                } catch (Throwable u) {
+                    ;
+                }
+                hconn = null;
+            }
+        }
+        return status;
+    }
+
+    /**
+     * Create a auth http connection for this url
+     * 
+     * @param url
+     * @param username
+     * @param password
+     * @return
+     * @throws IOException
+     * @throws MalformedURLException
+     * @throws ProtocolException
+     */
+    protected HttpURLConnection openConnection(String url, String username,
+            String password) throws IOException, MalformedURLException,
+            ProtocolException {
+        URLConnection conn;
+        conn = (new URL(url)).openConnection();
+        HttpURLConnection hconn = (HttpURLConnection) conn;
+
+        // Set up standard connection characteristics
+        hconn.setAllowUserInteraction(false);
+        hconn.setDoInput(true);
+        hconn.setUseCaches(false);
+        hconn.setDoOutput(false);
+        hconn.setRequestMethod("GET");
+        hconn.setRequestProperty("User-Agent", "JkStatus-Client/1.0");
+
+        if(username != null && password != null ) {
+             setAuthHeader(hconn, username, password);
+        }
+        // Establish the connection with the server
+        hconn.connect();
+        return hconn;
+    }
+
+    /**
+     * Set Basic Auth Header
+     * 
+     * @param hconn
+     * @param username
+     * @param password
+     */
+    protected void setAuthHeader(HttpURLConnection hconn, String username,
+            String password) {
+        // Set up an authorization header with our credentials
+        String input = username + ":" + password;
+        String output = new String(Base64.encode(input.getBytes()));
+        hconn.setRequestProperty("Authorization", "Basic " + output);
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/src/share/org/apache/jk/status/JkStatusParser.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/src/share/org/apache/jk/status/JkStatusParser.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/src/share/org/apache/jk/status/JkStatusParser.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,121 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.jk.status;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.tomcat.util.digester.Digester;
+
+/**
+ * <code>
+ *
+ *  &lt;?xml version="1.0" encoding="UTF-8" ?&gt;
+ *  &lt;jk:status xmlns:jk="http://tomcat.apache.org"&gt;
+ *    &lt;jk:server name="localhost" port="2010" software="Apache/2.0.58 (Unix) mod_jk/1.2.19-dev" version="1.2.19" /&gt;
+ *    &lt;jk:balancers&gt;
+ *    &lt;jk:balancer id="0" name="loadbalancer" type="lb" sticky="True" stickyforce="False" retries="2" recover="60" &gt;
+ *        &lt;jk:member id="0" name="node01" type="ajp13" host="localhost" port="20012" address="127.0.0.1:20012" activation="ACT" state="N/A" distance="0" lbfactor="1" lbmult="1" lbvalue="0" elected="0" errors="0" transferred="0" readed="0" busy="0" maxbusy="0" jvm_route="node01" /&gt;
+ *        &lt;jk:member id="1" name="node02" type="ajp13" host="localhost" port="20022" address="127.0.0.1:20022" activation="ACT" state="N/A" distance="0" lbfactor="1" lbmult="1" lbvalue="0" elected="0" errors="0" transferred="0" readed="0" busy="0" maxbusy="0" jvm_route="node02" /&gt;
+ *      &lt;jk:map type="Wildchar" uri="/ClusterSession*" context="/ClusterSession*" /&gt;
+ *      &lt;jk:map type="Wildchar" uri="/ClusterTest*" context="/ClusterTest*" /&gt;
+ *      &lt;jk:map type="Wildchar" uri="/test*" context="/test*" /&gt;
+ *    &lt;/jk:balancer&gt;
+ *    &lt;/jk:balancers&gt;
+ *  &lt;/jk:status&gt;
+ *
+ * </code>
+ * @author Peter Rossbach
+ * @version $Revision:$ $Date:$
+ * @since 5.5.10
+ */
+public class JkStatusParser {
+    private static Log log = LogFactory.getLog(JkStatusParser.class);
+
+    /**
+     * The descriptive information about this implementation.
+     */
+    private static final String info = "org.apache.jk.status.JkStatusParser/1.1";
+
+    /**
+     * Return descriptive information about this implementation and the
+     * corresponding version number, in the format
+     * <code>&lt;description&gt;/&lt;version&gt;</code>.
+     */
+    public String getInfo() {
+
+        return (info);
+
+    }
+
+    /**
+     * The <code>Digester</code> instance used to parse registry descriptors.
+     */
+    public static Digester digester = createDigester();
+
+    public static Digester getDigester() {
+        return digester;
+    }
+
+    /**
+     * Create and configure the Digester we will be using for setup mod_jk jk status page.
+     */
+    public static Digester createDigester() {
+        long t1 = System.currentTimeMillis();
+        // Initialize the digester
+        Digester digester = new Digester();
+        digester.setValidating(false);
+        digester.setClassLoader(JkStatus.class.getClassLoader());
+
+        // parse status
+        digester.addObjectCreate("jk:status", "org.apache.jk.status.JkStatus",
+                "className");
+        digester.addSetProperties("jk:status");
+
+        digester.addObjectCreate("jk:status/jk:server",
+                "org.apache.jk.status.JkServer", "className");
+        digester.addSetProperties("jk:status/jk:server");
+        digester.addSetNext("jk:status/jk:server", "setServer",
+                "org.apache.jk.status.JkServer");
+
+        digester.addObjectCreate("jk:status/jk:balancers/jk:balancer",
+                "org.apache.jk.status.JkBalancer", "className");
+        digester.addSetProperties("jk:status/jk:balancers/jk:balancer");
+        digester.addSetNext("jk:status/jk:balancers/jk:balancer",
+                "addBalancer", "org.apache.jk.status.JkBalancer");
+
+        digester.addObjectCreate(
+                "jk:status/jk:balancers/jk:balancer/jk:member",
+                "org.apache.jk.status.JkBalancerMember", "className");
+        digester
+                .addSetProperties("jk:status/jk:balancers/jk:balancer/jk:member");
+        digester.addSetNext("jk:status/jk:balancers/jk:balancer/jk:member",
+                "addBalancerMember", "org.apache.jk.status.JkBalancerMember");
+
+        digester.addObjectCreate("jk:status/jk:balancers/jk:balancer/jk:map",
+                "org.apache.jk.status.JkBalancerMapping", "className");
+        digester.addSetProperties("jk:status/jk:balancers/jk:balancer/jk:map");
+        digester.addSetNext("jk:status/jk:balancers/jk:balancer/jk:map",
+                "addBalancerMapping", "org.apache.jk.status.JkBalancerMapping");
+
+        long t2 = System.currentTimeMillis();
+        if (log.isDebugEnabled())
+            log.debug("Digester for apache mod_jk jkstatus page is created "
+                    + (t2 - t1));
+        return (digester);
+
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/src/share/org/apache/jk/status/JkStatusResetTask.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/src/share/org/apache/jk/status/JkStatusResetTask.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/src/share/org/apache/jk/status/JkStatusResetTask.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,108 @@
+/*
+ * Copyright 2002,2005 The Apache Software Foundation.
+ * 
+ * Licensed 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.jk.status;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URLEncoder;
+
+import org.apache.catalina.ant.AbstractCatalinaTask;
+import org.apache.tools.ant.BuildException;
+
+/**
+ * Ant task that implements the <code>/jkstatus?cmd=reset&amp;l=loadbalancer</code> command, supported by the
+ * mod_jk status (1.2.15) application.
+ * 
+ * @author Peter Rossbach
+ * @version $Revision: 1.3 $
+ * @since 5.5.13
+ */
+public class JkStatusResetTask extends AbstractCatalinaTask {
+
+    private String workerLb;
+
+    /**
+     *  
+     */
+    public JkStatusResetTask() {
+        super();
+        setUrl("http://localhost/jkstatus");
+    }
+
+    /**
+     * @return Returns the workerLb.
+     */
+    public String getWorkerLb() {
+        return workerLb;
+    }
+
+    /**
+     * @param workerLb
+     *            The workerLb to set.
+     */
+    public void setWorkerLb(String workerLb) {
+        this.workerLb = workerLb;
+    }
+
+    /**
+     * Execute the requested operation.
+     * 
+     * @exception BuildException
+     *                if an error occurs
+     */
+    public void execute() throws BuildException {
+
+        super.execute();
+        checkParameter();
+        StringBuffer sb = createLink();
+        execute(sb.toString(), null, null, -1);
+
+    }
+
+    /**
+     * Create jkstatus reset link
+     * <ul>
+     * <li><b>load balance example:
+     * </b>http://localhost/jkstatus?cmd=reset&w=loadbalancer&mime=txt</li>
+     * </ul>
+     * 
+     * @return create jkstatus link
+     */
+    private StringBuffer createLink() {
+        // Building URL
+        StringBuffer sb = new StringBuffer();
+        try {
+            sb.append("?cmd=reset");
+            sb.append("&w=");
+            sb.append(URLEncoder.encode(workerLb, getCharset()));
+            sb.append("&mime=txt");
+
+        } catch (UnsupportedEncodingException e) {
+            throw new BuildException("Invalid 'charset' attribute: "
+                    + getCharset());
+        }
+        return sb;
+    }
+
+    /**
+     * check correct lb and worker pararmeter
+     */
+    protected void checkParameter() {
+        if (workerLb == null) {
+            throw new BuildException("Must specify 'workerLb' attribute");
+        }
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/src/share/org/apache/jk/status/JkStatusTask.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/src/share/org/apache/jk/status/JkStatusTask.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/src/share/org/apache/jk/status/JkStatusTask.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,586 @@
+/*
+ * Copyright 2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.jk.status;
+
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.catalina.ant.BaseRedirectorHelperTask;
+import org.apache.tomcat.util.IntrospectionUtils;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+
+/**
+ * Ant task that implements the show <code>/jkstatus</code> command, supported
+ * by the mod_jk status (1.2.13) application.
+ * 
+ * @author Peter Rossbach
+ * @version $Revision:$
+ * @since 5.5.10
+ */
+public class JkStatusTask extends BaseRedirectorHelperTask {
+
+    /**
+     * The descriptive information about this implementation.
+     */
+    private static final String info = "org.apache.jk.status.JkStatusTask/1.1";
+
+    /**
+     * Store status as <code>resultProperty</code> prefix.
+     */
+    protected String resultproperty;
+
+    /**
+     * Echo status at ant console
+     */
+    protected boolean echo = false;
+
+    /**
+     * The login password for the <code>mod_jk status</code> page.
+     */
+    protected String password = null;
+
+    /**
+     * The URL of the <code>mod_jk status</code> page to be used.
+     */
+    protected String url = "http://localhost:80/jkstatus";
+
+    /**
+     * The login username for the <code>mod_jk status</code> page.
+     */
+    protected String username = null;
+
+    private String errorProperty;
+
+    private String worker;
+
+    private String loadbalancer;
+
+    /**
+     * Return descriptive information about this implementation and the
+     * corresponding version number, in the format
+     * <code>&lt;description&gt;/&lt;version&gt;</code>.
+     */
+    public String getInfo() {
+
+        return (info);
+
+    }
+
+    public String getPassword() {
+        return (this.password);
+    }
+
+    public void setPassword(String password) {
+        this.password = password;
+    }
+
+    public String getUrl() {
+        return (this.url);
+    }
+
+    public void setUrl(String url) {
+        this.url = url;
+    }
+
+    public String getUsername() {
+        return (this.username);
+    }
+
+    public void setUsername(String username) {
+        this.username = username;
+    }
+
+    /**
+     * @return Returns the echo.
+     */
+    public boolean isEcho() {
+        return echo;
+    }
+
+    /**
+     * @param echo
+     *            The echo to set.
+     */
+    public void setEcho(boolean echo) {
+        this.echo = echo;
+    }
+
+    /**
+     * @return Returns the resultproperty.
+     */
+    public String getResultproperty() {
+        return resultproperty;
+    }
+
+    /**
+     * @param resultproperty
+     *            The resultproperty to set.
+     */
+    public void setResultproperty(String resultproperty) {
+        this.resultproperty = resultproperty;
+    }
+
+    /**
+     * @return Returns the loadbalancer.
+     */
+    public String getLoadbalancer() {
+        return loadbalancer;
+    }
+    /**
+     * @param loadbalancer The loadbalancer to set.
+     */
+    public void setLoadbalancer(String loadbalancer) {
+        this.loadbalancer = loadbalancer;
+    }
+    /**
+     * @return Returns the worker.
+     */
+    public String getWorker() {
+        return worker;
+    }
+    /**
+     * @param worker The worker to set.
+     */
+    public void setWorker(String worker) {
+        this.worker = worker;
+    }
+    // --------------------------------------------------------- Public Methods
+
+    /**
+     * Get jkstatus from server.
+     * 
+     * @exception BuildException
+     *                if a validation error occurs
+     */
+    public void execute() throws BuildException {
+
+        if (url == null) {
+            throw new BuildException("Must specify an 'url'");
+        }
+        boolean isWorkerOnly = worker != null && !"".equals(worker);
+        boolean isLoadbalancerOnly = loadbalancer != null
+                && !"".equals(loadbalancer);
+
+        StringBuffer error = new StringBuffer();
+        try {
+            JkStatusAccessor accessor = new JkStatusAccessor();
+            JkStatus status = accessor.status(url, username, password);
+            if (!isWorkerOnly && !isLoadbalancerOnly) {
+                JkServer server = status.getServer();
+                if (resultproperty != null) {
+                    createProperty(server, "name");
+                    createProperty(server, "port");
+                    createProperty(server, "version");
+                    createProperty(server, "software");
+                }
+                if (isEcho()) {
+                    handleOutput("server name=" + server.getName() + "."
+                            + server.getPort() + " - " + server.getSoftware());
+                }
+            }
+            List balancers = status.getBalancers();
+            for (Iterator iter = balancers.iterator(); iter.hasNext();) {
+                JkBalancer balancer = (JkBalancer) iter.next();
+                String balancerIndex = null;
+                if (isLoadbalancerOnly) {
+                    if (loadbalancer.equals(balancer.getName())) {
+                        if (resultproperty != null) {
+                            setPropertyBalancerOnly(balancer);
+                        }
+                        echoBalancer(balancer);
+                        return;
+                    }
+                } else {
+                    if (!isWorkerOnly) {
+                        if (resultproperty != null) {
+                            balancerIndex = Integer.toString(balancer.getId());
+                            setPropertyBalancer(balancer,balancerIndex);
+                        }
+                        echoBalancer(balancer);
+                    }
+                    List members = balancer.getBalancerMembers();
+                    for (Iterator iterator = members.iterator(); iterator
+                            .hasNext();) {
+                        JkBalancerMember member = (JkBalancerMember) iterator
+                                .next();
+                        if (isWorkerOnly) {
+                            if (worker.equals(member.getName())) {
+                                if (resultproperty != null) {
+                                    setPropertyWorkerOnly(balancer, member);
+                                }
+                                echoWorker(member);
+                                return;
+                            }
+                        } else {
+                            if (resultproperty != null) {
+                                setPropertyWorker(balancerIndex, member);
+                            }
+                            echoWorker(member);
+                            if (member.getStatus() != null && !"OK".equals(member.getStatus())) {
+                                error.append(" worker name=" + member.getName()
+                                        + " status=" + member.getStatus()
+                                        + " host=" + member.getAddress());
+                            }
+                            if (member.getState() != null && !("OK".equals(member.getState()) || "N/A".equals(member.getState())) ){
+                                error.append(" worker name=" + member.getName()
+                                        + " state=" + member.getState()
+                                        + " host=" + member.getAddress());
+                            }
+                        }
+                    }
+                    if (!isWorkerOnly) {
+                        if (resultproperty != null && members.size() > 0) {
+                            getProject().setNewProperty(
+                                    resultproperty + ".balancer."
+                                            + balancerIndex + ".member.length",
+                                    Integer.toString(members.size()));
+                        }
+                        List mappings = balancer.getBalancerMappings();
+                        int j = 0;
+                        for (Iterator iterator = mappings.iterator(); iterator
+                                .hasNext(); j++) {
+                            JkBalancerMapping mapping = (JkBalancerMapping) iterator
+                                    .next();
+                            if (resultproperty != null) {
+                                String stringIndex2 = Integer.toString(j);
+                                createProperty(mapping, balancerIndex,
+                                        stringIndex2, "type");
+                                createProperty(mapping, balancerIndex,
+                                        stringIndex2, "uri");
+                                createProperty(mapping, balancerIndex,
+                                        stringIndex2, "context");
+                            }
+                            if (isEcho()) {
+                                handleOutput("balancer name="
+                                        + balancer.getName() + " mappingtype="
+                                        + mapping.getType() + " uri="
+                                        + mapping.getUri() + " context="
+                                        + mapping.getContext());
+                            }
+                        }
+                        if (resultproperty != null && mappings.size() > 0) {
+                            getProject().setNewProperty(
+                                    resultproperty + ".balancer."
+                                            + balancerIndex + ".map.length",
+                                    Integer.toString(mappings.size()));
+                        }
+                    }
+                }
+            }
+            if (!isWorkerOnly && !isLoadbalancerOnly) {
+                if (resultproperty != null && balancers.size() > 0) {
+                    getProject().setNewProperty(
+                            resultproperty + ".balancer.length",
+                            Integer.toString(balancers.size()));
+                }
+            }
+        } catch (Throwable t) {
+            error.append(t.getMessage());
+            if (getErrorProperty() != null) {
+                getProject().setNewProperty(errorProperty, error.toString());
+            }
+            if (isFailOnError()) {
+                throw new BuildException(t);
+            } else {
+                handleErrorOutput(t.getMessage());
+                return;
+            }
+        }
+        if (error.length() != 0) {
+            if (getErrorProperty() != null) {
+                getProject().setNewProperty(errorProperty, error.toString());
+            }
+            if (isFailOnError()) {
+                // exception should be thrown only if failOnError == true
+                // or error line will be logged twice
+                throw new BuildException(error.toString());
+            }
+        }
+
+    }
+
+    /**
+     * @param member
+     */
+    private void echoWorker(JkBalancerMember member) {
+        if (isEcho()) {
+            StringBuffer state = new StringBuffer("worker name=") ;
+            state.append( member.getName()) ;
+            if(member.getStatus() != null) {
+                state.append(" status=");
+                state.append(member.getStatus());
+            }
+            if(member.getState() != null) {
+                state.append(" state=");
+                state.append(member.getState())  ;
+            }
+            state.append(" host=");
+            state.append(member.getAddress());
+            handleOutput(state.toString());
+        }
+    }
+
+    /**
+     * @param balancer
+     */
+    private void echoBalancer(JkBalancer balancer) {
+        if (isEcho()) {
+            handleOutput("balancer name=" + balancer.getName() + " type="
+                    + balancer.getType());
+        }
+    }
+
+    /**
+     * @param balancer
+     */
+    private void setPropertyBalancerOnly(JkBalancer balancer) {
+        String prefix = resultproperty + "." + balancer.getName();
+        getProject().setNewProperty(prefix + ".id",
+                Integer.toString(balancer.getId()));
+        getProject().setNewProperty(prefix + ".type", balancer.getType());
+        getProject().setNewProperty(prefix + ".sticky",
+                Boolean.toString(balancer.isSticky()));
+        getProject().setNewProperty(prefix + ".stickyforce",
+                Boolean.toString(balancer.isStickyforce()));
+        getProject().setNewProperty(prefix + ".retries",
+                Integer.toString(balancer.getRetries()));
+        getProject().setNewProperty(prefix + ".recover",
+                Integer.toString(balancer.getRecover()));
+    }
+
+    /**
+     * @param balancer
+     * @return
+     */
+    private void setPropertyBalancer(JkBalancer balancer,String balancerIndex) {
+        createProperty(balancer, balancerIndex, "id");
+        createProperty(balancer, balancerIndex, "name");
+        createProperty(balancer, balancerIndex, "type");
+        createProperty(balancer, balancerIndex, "sticky");
+        createProperty(balancer, balancerIndex, "stickyforce");
+        createProperty(balancer, balancerIndex, "retries");
+        createProperty(balancer, balancerIndex, "recover");
+    }
+
+    /**
+     * @param balancerIndex
+     * @param member
+     */
+    private void setPropertyWorker(String balancerIndex, JkBalancerMember member) {
+        String workerIndex = Integer.toString(member.getId());
+        createProperty(member, balancerIndex, workerIndex, "id");
+        createProperty(member, balancerIndex, workerIndex, "name");
+        createProperty(member, balancerIndex, workerIndex, "type");
+        createProperty(member, balancerIndex, workerIndex, "host");
+        createProperty(member, balancerIndex, workerIndex, "port");
+        createProperty(member, balancerIndex, workerIndex, "address");
+        if(member.getJvm_route() != null) {
+            createProperty(member, balancerIndex, workerIndex, "jvm_route");
+        }
+        if(member.getStatus() != null) {
+            createProperty(member, balancerIndex, workerIndex, "status");
+        }
+        if(member.getActivation() != null) {
+            createProperty(member, balancerIndex, workerIndex, "activation");
+        }
+        if(member.getState() != null) {
+            createProperty(member, balancerIndex, workerIndex, "state");
+        }
+        createProperty(member, balancerIndex, workerIndex, "lbfactor");
+        createProperty(member, balancerIndex, workerIndex, "lbvalue");
+        if(member.getLbmult() > 0) {
+            createProperty(member, balancerIndex, workerIndex, "lbmult");
+        }
+        createProperty(member, balancerIndex, workerIndex, "elected");
+        createProperty(member, balancerIndex, workerIndex, "readed");
+        createProperty(member, balancerIndex, workerIndex, "busy");
+        if(member.getMaxbusy() > 0) {
+            createProperty(member, balancerIndex, workerIndex, "maxbusy");
+        }
+        createProperty(member, balancerIndex, workerIndex, "transferred");
+        createProperty(member, balancerIndex, workerIndex, "errors");
+        if(member.getClienterrors() > 0) {
+            createProperty(member, balancerIndex, workerIndex, "clienterrors");
+        }
+        if(member.getDistance() > 0) {
+            createProperty(member, balancerIndex, workerIndex, "distance");
+        }
+        if (member.getDomain() != null) {
+            createProperty(member, balancerIndex, workerIndex, "domain");
+        } else {
+            getProject().setNewProperty(resultproperty + ".balancer." + balancerIndex + ".member." + workerIndex +
+                    ".domain", "");          
+        }
+        if (member.getRedirect() != null) {
+            createProperty(member, balancerIndex, workerIndex, "redirect");
+        } else {
+            getProject().setNewProperty(resultproperty + ".balancer." + balancerIndex + ".member." + workerIndex +
+                    ".redirect", "");          
+        }
+    }
+
+    /**
+     * @param balancer
+     * @param member
+     */
+    private void setPropertyWorkerOnly(JkBalancer balancer,
+            JkBalancerMember member) {
+        String prefix = resultproperty + "." + member.getName();
+        Project currentProject = getProject();
+        
+        currentProject.setNewProperty(prefix + ".lb.id",
+                Integer.toString(balancer.getId()));
+        currentProject.setNewProperty(prefix + ".lb.name", balancer.getName());
+        currentProject.setNewProperty(prefix + ".id",
+                Integer.toString(member.getId()));
+        currentProject.setNewProperty(prefix + ".type", member.getType());
+        if(member.getJvm_route() != null) {
+            currentProject.setNewProperty(prefix + ".jvm_route", member.getJvm_route());
+        }
+        if(member.getStatus() != null) {
+            currentProject.setNewProperty(prefix + ".status", member.getStatus());
+        }
+        if(member.getActivation() != null) {
+            currentProject.setNewProperty(prefix + ".activation", member.getActivation());
+        }
+        if(member.getState() != null) {
+            currentProject.setNewProperty(prefix + ".state", member.getState());
+        }
+        currentProject.setNewProperty(prefix + ".host", member.getHost());
+        currentProject.setNewProperty(prefix + ".address", member.getAddress());
+        currentProject.setNewProperty(prefix + ".port",
+                Integer.toString(member.getPort()));
+        currentProject.setNewProperty(prefix + ".lbfactor",
+                Integer.toString(member.getLbfactor()));
+        currentProject.setNewProperty(prefix + ".lbvalue",
+                Long.toString(member.getLbvalue()));
+        if(member.getLbmult() > 0) {
+            currentProject.setNewProperty(prefix + ".lbmult",
+                    Long.toString(member.getLbmult()));
+        }
+        currentProject.setNewProperty(prefix + ".elected",
+                Long.toString(member.getElected()));
+        currentProject.setNewProperty(prefix + ".readed",
+                Long.toString(member.getReaded()));
+        currentProject.setNewProperty(prefix + ".transferred",
+                Long.toString(member.getTransferred()));
+        currentProject.setNewProperty(prefix + ".busy",
+                Integer.toString(member.getBusy()));
+        if(member.getMaxbusy() > 0) {
+            currentProject.setNewProperty(prefix + ".maxbusy",
+                    Long.toString(member.getMaxbusy()));
+        }
+        currentProject.setNewProperty(prefix + ".errors",
+                Long.toString(member.getErrors()));
+        if(member.getClienterrors() > 0) {
+            currentProject.setNewProperty(prefix + ".clienterrors",
+                    Long.toString(member.getClienterrors()));
+        }
+        if(member.getDistance() > 0) {
+            currentProject.setNewProperty(prefix + ".distance",
+                    Integer.toString(member.getDistance()));
+        }
+        if (member.getDomain() != null)
+            currentProject.setNewProperty(prefix + ".domain", member.getDomain());
+        else
+            currentProject.setNewProperty(prefix + ".domain", "");
+        if (member.getRedirect() != null)
+            currentProject.setNewProperty(prefix + ".redirect",
+                    member.getRedirect());
+        else
+            currentProject.setNewProperty(prefix + ".redirect", "");
+            
+    }
+
+    /*
+     * Set ant property for save error state
+     * 
+     * @see org.apache.catalina.ant.BaseRedirectorHelperTask#setErrorProperty(java.lang.String)
+     */
+    public void setErrorProperty(String arg0) {
+        errorProperty = arg0;
+        super.setErrorProperty(arg0);
+    }
+
+    /**
+     * @return Returns the errorProperty.
+     */
+    public String getErrorProperty() {
+        return errorProperty;
+    }
+
+    protected void createProperty(Object result, String attribute) {
+        createProperty(result, null, null, attribute);
+    }
+
+    protected void createProperty(Object result, String arraymark,
+            String attribute) {
+        createProperty(result, arraymark, null, attribute);
+    }
+
+    /**
+     * create result as property with name from attribute resultproperty
+     */
+    protected void createProperty(Object result, String arraymark,
+            String arraymark2, String attribute) {
+        if (resultproperty != null) {
+            Object value = IntrospectionUtils.getProperty(result, attribute);
+            if (value != null) {
+                StringBuffer propertyname = new StringBuffer(resultproperty);
+
+                if (result instanceof JkServer) {
+                    propertyname.append(".server");
+                } else if (result instanceof JkBalancer) {
+                    propertyname.append(".balancer");
+                    if (arraymark != null) {
+                        propertyname.append(".");
+                        propertyname.append(arraymark);
+                    }
+                } else if (result instanceof JkBalancerMember) {
+                    propertyname.append(".balancer");
+                    if (arraymark != null) {
+                        propertyname.append(".");
+                        propertyname.append(arraymark);
+                    }
+                    propertyname.append(".member");
+                    if (arraymark2 != null) {
+                        propertyname.append(".");
+                        propertyname.append(arraymark2);
+                    }
+
+                } else if (result instanceof JkBalancerMapping) {
+                    propertyname.append(".balancer");
+                    if (arraymark != null) {
+                        propertyname.append(".");
+                        propertyname.append(arraymark);
+                    }
+                    propertyname.append(".map");
+                    if (arraymark2 != null) {
+                        propertyname.append(".");
+                        propertyname.append(arraymark2);
+                    }
+                }
+                propertyname.append(".");
+                propertyname.append(attribute);
+                getProject().setNewProperty(propertyname.toString(),
+                        value.toString());
+            }
+        }
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/src/share/org/apache/jk/status/JkStatusUpdateTask.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/src/share/org/apache/jk/status/JkStatusUpdateTask.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/src/share/org/apache/jk/status/JkStatusUpdateTask.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,514 @@
+/*
+ * Copyright 2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.jk.status;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URLEncoder;
+
+import org.apache.catalina.ant.AbstractCatalinaTask;
+import org.apache.tools.ant.BuildException;
+
+/**
+ * Ant task that implements the <code>/status</code> command, supported by the
+ * mod_jk status (1.2.13) application.
+ * 
+ * 
+ * @author Peter Rossbach
+ * @version $Revision: 1.3 $
+ * @since 5.5.10
+ */
+public class JkStatusUpdateTask extends AbstractCatalinaTask {
+
+    /**
+     * The descriptive information about this implementation.
+     */
+    private static final String info = "org.apache.jk.status.JkStatusUpdateTask/1.1";
+
+    private String worker = "lb";
+
+    private String workerType = "lb";
+
+    private int internalid = 0;
+
+    private Integer lbRetries;
+
+    private Integer lbRecovertime;
+
+    private Boolean lbStickySession = Boolean.TRUE;
+
+    private Boolean lbForceSession = Boolean.FALSE;
+
+    private Integer workerLoadFactor;
+
+    private String workerJvmRoute ;
+    
+    private int workerDistance = -1;
+    
+    private String workerRedirect;
+
+    private String workerClusterDomain;
+
+    private Boolean workerDisabled ;
+
+    private Boolean workerStopped ;
+    
+    private int workerActivation = -1;
+      
+    private boolean isLBMode = true;
+    
+    
+
+    private String workerLb;
+
+    /**
+     * Return descriptive information about this implementation and the
+     * corresponding version number, in the format
+     * <code>&lt;description&gt;/&lt;version&gt;</code>.
+     */
+    public String getInfo() {
+
+        return (info);
+
+    }
+    
+    /**
+     *  
+     */
+    public JkStatusUpdateTask() {
+        super();
+        setUrl("http://localhost/jkstatus");
+    }
+
+    /**
+     * @return Returns the workerDistance.
+     */
+    public int getWorkerDistance() {
+        return workerDistance;
+    }
+
+    /**
+     * @param workerDistance The workerDistance to set.
+     */
+    public void setWorkerDistance(int workerDistance) {
+        this.workerDistance = workerDistance;
+    }
+
+    /**
+     * @return Returns the workerJvmRoute.
+     */
+    public String getWorkerJvmRoute() {
+        return workerJvmRoute;
+    }
+
+    /**
+     * @param workerJvmRoute The workerJvmRoute to set.
+     */
+    public void setWorkerJvmRoute(String workerJvmRoute) {
+        this.workerJvmRoute = workerJvmRoute;
+    }
+
+    /**
+     * @return Returns the internalid.
+     */
+    public int getInternalid() {
+        return internalid;
+    }
+
+    /**
+     * @param internalid
+     *            The internalid to set.
+     */
+    public void setInternalid(int internalid) {
+        this.internalid = internalid;
+    }
+
+    /**
+     * @return Returns the lbForceSession.
+     */
+    public Boolean getLbForceSession() {
+        return lbForceSession;
+    }
+
+    /**
+     * @param lbForceSession
+     *            The lbForceSession to set.
+     */
+    public void setLbForceSession(Boolean lbForceSession) {
+        this.lbForceSession = lbForceSession;
+    }
+
+    /**
+     * @return Returns the lbRecovertime.
+     */
+    public Integer getLbRecovertime() {
+        return lbRecovertime;
+    }
+
+    /**
+     * @param lbRecovertime
+     *            The lbRecovertime to set.
+     */
+    public void setLbRecovertime(Integer lbRecovertime) {
+        this.lbRecovertime = lbRecovertime;
+    }
+
+    /**
+     * @return Returns the lbRetries.
+     */
+    public Integer getLbRetries() {
+        return lbRetries;
+    }
+
+    /**
+     * @param lbRetries
+     *            The lbRetries to set.
+     */
+    public void setLbRetries(Integer lbRetries) {
+        this.lbRetries = lbRetries;
+    }
+
+    /**
+     * @return Returns the lbStickySession.
+     */
+    public Boolean getLbStickySession() {
+        return lbStickySession;
+    }
+
+    /**
+     * @param lbStickySession
+     *            The lbStickySession to set.
+     */
+    public void setLbStickySession(Boolean lbStickySession) {
+        this.lbStickySession = lbStickySession;
+    }
+
+    /**
+     * @return Returns the worker.
+     */
+    public String getWorker() {
+        return worker;
+    }
+
+    /**
+     * @param worker
+     *            The worker to set.
+     */
+    public void setWorker(String worker) {
+        this.worker = worker;
+    }
+
+    /**
+     * @return Returns the workerType.
+     */
+    public String getWorkerType() {
+        return workerType;
+    }
+
+    /**
+     * @param workerType
+     *            The workerType to set.
+     */
+    public void setWorkerType(String workerType) {
+        this.workerType = workerType;
+    }
+
+    /**
+     * @return Returns the workerLb.
+     */
+    public String getWorkerLb() {
+        return workerLb;
+    }
+
+    /**
+     * @param workerLb
+     *            The workerLb to set.
+     */
+    public void setWorkerLb(String workerLb) {
+        this.workerLb = workerLb;
+    }
+
+    /**
+     * @return Returns the workerClusterDomain.
+     */
+    public String getWorkerClusterDomain() {
+        return workerClusterDomain;
+    }
+
+    /**
+     * @param workerClusterDomain
+     *            The workerClusterDomain to set.
+     */
+    public void setWorkerClusterDomain(String workerClusterDomain) {
+        this.workerClusterDomain = workerClusterDomain;
+    }
+
+    /**
+     * @return Returns the workerDisabled.
+     */
+    public Boolean getWorkerDisabled() {
+        return workerDisabled;
+    }
+
+    /**
+     * @param workerDisabled
+     *            The workerDisabled to set.
+     */
+    public void setWorkerDisabled(Boolean workerDisabled) {
+        this.workerDisabled = workerDisabled;
+    }
+
+    /**
+     * @return Returns the workerActivation.
+     */
+    public int getWorkerActivation() {
+        return workerActivation;
+    }
+    
+    /**
+     * <ul>
+     * <li>1 active</li>
+     * <li>2 disabled</li>
+     * <li>3 stopped</li>
+     * </ul>
+     * @param workerActivation The workerActivation to set.
+     * 
+     */
+    public void setWorkerActivation(int workerActivation) {
+        this.workerActivation = workerActivation;
+    }
+    
+    /**
+     * @return Returns the workerStopped.
+     */
+    public Boolean getWorkerStopped() {
+        return workerStopped;
+    }
+    
+    /**
+     * @param workerStopped The workerStopped to set.
+     */
+    public void setWorkerStopped(Boolean workerStopped) {
+        this.workerStopped = workerStopped;
+    }
+    
+    /**
+     * @return Returns the workerLoadFactor.
+     */
+    public Integer getWorkerLoadFactor() {
+        return workerLoadFactor;
+    }
+
+    /**
+     * @param workerLoadFactor
+     *            The workerLoadFactor to set.
+     */
+    public void setWorkerLoadFactor(Integer workerLoadFactor) {
+        this.workerLoadFactor = workerLoadFactor;
+    }
+
+    /**
+     * @return Returns the workerRedirect.
+     */
+    public String getWorkerRedirect() {
+        return workerRedirect;
+    }
+
+    /**
+     * @param workerRedirect
+     *            The workerRedirect to set.
+     */
+    public void setWorkerRedirect(String workerRedirect) {
+        this.workerRedirect = workerRedirect;
+    }
+
+    /**
+     * Execute the requested operation.
+     * 
+     * @exception BuildException
+     *                if an error occurs
+     */
+    public void execute() throws BuildException {
+
+        super.execute();
+        checkParameter();
+        StringBuffer sb = createLink();
+        execute(sb.toString(), null, null, -1);
+
+    }
+
+    /**
+     * Create JkStatus link
+     * <ul>
+     * <li><b>load balance example:
+     * </b>http://localhost/jkstatus?cmd=update&mime=txt&w=lb&lf=false&ls=true</li>
+     * <li><b>worker example:
+     * </b>http://localhost/jkstatus?cmd=update&mime=txt&w=node1&wn=node01&l=lb&wf=1&wa=1&wx=0
+     * <br/
+     * <ul>
+     * <li>wa=1 activation</li>
+     * <li>wa=2 disabled</li>
+     * <li>wa=3 stopped</li>
+     * </ul>
+     * </li>
+     * </ul>
+     * 
+     * <ul>
+     * <li><b>w:<b/> name tcp worker node</li>
+     * <li><b>l:<b/> name loadbalancer</li>
+     * <li><b>wf:<b/> load factor</li>
+     * <li><b>wn:<b/> jvm route</li>
+     * <li><b>wx:<b/> distance</li>
+     * <li><b>wa:<b/> activation state</li>
+     * <li><b>wr:<b/> redirect route</li>
+     * <li><b>wd:<b/> cluster domain</li>
+     * <li><b>ws:<b/> stopped deprecated 1.2.16</li>
+     * <li><b>wd:<b/> disabled deprecated 1.2.16</li>
+     * </ul>
+     * 
+     * @return create jkstatus link
+     */
+    private StringBuffer createLink() {
+        // Building URL
+        StringBuffer sb = new StringBuffer();
+        try {
+            sb.append("?cmd=update&mime=txt");
+            sb.append("&w=");
+            sb.append(URLEncoder.encode(worker, getCharset()));
+
+            if (isLBMode) {
+                //http://localhost/jkstatus?cmd=update&mime=txt&w=lb&lf=false&ls=true
+                if ((lbRetries != null)) { // > 0
+                    sb.append("&lr=");
+                    sb.append(lbRetries);
+                }
+                if ((lbRecovertime != null)) { // > 59
+                    sb.append("&lt=");
+                    sb.append(lbRecovertime);
+                }
+                if ((lbStickySession != null)) {
+                    sb.append("&ls=");
+                    sb.append(lbStickySession);
+                }
+                if ((lbForceSession != null)) {
+                    sb.append("&lf=");
+                    sb.append(lbForceSession);
+                }
+            } else {
+                //http://localhost/status?cmd=update&mime=txt&w=node1&l=lb&wf=1&wd=false&ws=false
+                if (workerLb != null) { // must be configured
+                    sb.append("&l=");
+                    sb.append(URLEncoder.encode(workerLb, getCharset()));
+                }
+                if (workerLoadFactor != null) { // >= 1
+                    sb.append("&wf=");
+                    sb.append(workerLoadFactor);
+                }
+                if (workerJvmRoute != null) {
+                    sb.append("&wn=");
+                    sb.append(URLEncoder.encode(workerJvmRoute, getCharset()));
+                } 
+                if (workerDisabled != null) {
+                    sb.append("&wd=");
+                    sb.append(workerDisabled);
+                }
+                if (workerStopped != null) {
+                    sb.append("&ws=");
+                    sb.append(workerStopped);
+                }
+                if (workerActivation > 0 && workerActivation < 4) {
+                    sb.append("&wa=");
+                    sb.append(workerActivation);
+                } 
+                if (workerDistance >= 0) {
+                    sb.append("&wx=");
+                    sb.append(workerDistance);
+                }
+                if (workerRedirect != null) { // other worker conrecte lb's
+                    sb.append("&wr=");
+                    sb.append(URLEncoder.encode(workerRedirect,
+                            getCharset()));
+                }
+                if (workerClusterDomain != null) {
+                    sb.append("&wc=");
+                    sb.append(URLEncoder.encode(workerClusterDomain,
+                            getCharset()));
+                }
+            }
+
+        } catch (UnsupportedEncodingException e) {
+            throw new BuildException("Invalid 'charset' attribute: "
+                    + getCharset());
+        }
+        return sb;
+    }
+
+    /**
+     * check correct lb and worker pararmeter
+     */
+    protected void checkParameter() {
+        if (worker == null) {
+            throw new BuildException("Must specify 'worker' attribute");
+        }
+        if (workerType == null) {
+            throw new BuildException("Must specify 'workerType' attribute");
+        }
+        if ("lb".equals(workerType)) {
+            if (lbRecovertime == null && lbRetries == null) {
+                throw new BuildException(
+                        "Must specify at a lb worker either 'lbRecovertime' or"
+                                + "'lbRetries' attribute");
+            }
+            if (lbStickySession == null || lbForceSession == null) {
+                throw new BuildException("Must specify at a lb worker either"
+                        + "'lbStickySession' and 'lbForceSession' attribute");
+            }
+            if (null != lbRecovertime && 60 < lbRecovertime.intValue()) {
+                throw new BuildException(
+                        "The 'lbRecovertime' must be greater than 59");
+            }
+            if (null != lbRetries && 1 < lbRetries.intValue()) {
+                throw new BuildException(
+                        "The 'lbRetries' must be greater than 1");
+            }
+            isLBMode = true;
+        } else if ("worker".equals(workerType)) {
+            if (workerLoadFactor == null ) {
+                throw new BuildException(
+                        "Must specify at a node worker 'workerLoadFactor' attribute");
+            }
+            if (workerClusterDomain == null) {
+                throw new BuildException(
+                        "Must specify at a node worker 'workerClusterDomain' attribute");
+            }
+            if (workerRedirect == null) {
+                throw new BuildException(
+                        "Must specify at a node worker 'workerRedirect' attribute");
+            }
+            if (workerLb == null) {
+                throw new BuildException("Must specify 'workerLb' attribute");
+            }
+            if (workerLoadFactor.intValue() < 1) {
+                throw new BuildException(
+                        "The 'workerLoadFactor' must be greater or equal 1");
+            }
+            isLBMode = false;
+        } else {
+            throw new BuildException(
+                    "Only 'lb' and 'worker' supported as workerType attribute");
+        }
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/src/share/org/apache/jk/status/LocalStrings.properties
===================================================================

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/src/share/org/apache/jk/status/antlib.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/src/share/org/apache/jk/status/antlib.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/src/share/org/apache/jk/status/antlib.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<antlib>
+  <typedef
+        name="update"
+        classname="org.apache.jk.status.JkStatusUpdateTask" />
+  <typedef
+        name="reset"
+        classname="org.apache.jk.status.JkStatusResetTask" />
+  <typedef
+        name="status"
+        classname="org.apache.jk.status.JkStatusTask" />
+</antlib>

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/src/share/org/apache/jk/status/jkstatus.tasks
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/src/share/org/apache/jk/status/jkstatus.tasks	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/src/share/org/apache/jk/status/jkstatus.tasks	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,5 @@
+# Apache mod_jk jk status tasks
+jkUpdate=org.apache.jk.status.JkStatusUpdateTask
+jkReset=org.apache.jk.status.JkStatusResetTask
+jkStatus=org.apache.jk.status.JkStatusTask
+

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/src/share/org/apache/jk/status/mbeans-descriptors.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/src/share/org/apache/jk/status/mbeans-descriptors.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/src/share/org/apache/jk/status/mbeans-descriptors.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,32 @@
+<?xml version="1.0"?>
+<mbeans-descriptors>
+
+<!--
+  <mbean name="JkStatus"
+         description="represent the apache mod_jk status"
+         domain="Jk"
+         group="Status"
+         type="org.apache.jk.status.JkStatusMbean">
+    
+    <attribute name="className"
+               description="Fully qualified class name of the managed object"
+               type="java.lang.String"
+               writeable="false"/>
+
+    <attribute name="info"
+               description="The base directory for Context configuration files"
+               type="java.lang.String"
+               writeable="false" />
+      
+    <operation name="check"
+               description="Check a web application name for updates"
+               impact="ACTION"
+               returnType="void">
+      <parameter name="name"
+                 description="Application name"
+                 type="java.lang.String"/>
+    </operation>
+
+  </mbean>
+-->
+</mbeans-descriptors>

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/src/share/org/apache/jk/status/package.html
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/src/share/org/apache/jk/status/package.html	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/src/share/org/apache/jk/status/package.html	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,44 @@
+<body>
+
+<p>This package contains a set of <code>Task</code> implementations for
+<em>Ant (version 1.6.x or later)</em> that can be used to interact with the
+Apaache mod_jk status page to show, update, disable and stop mod_jk worker.
+For more information, see
+<a href="http://tomcat.apache.org/connectors-doc/index.html"><strong>JK Documenation</strong></a>.</p>
+
+<p>The attributes of each task element correspond
+exactly to the request parameters that are included with an HTTP request
+sent directly to jk status page.  They are summarized as follows:
+</p>
+
+<table>
+  <tr>
+    <th align="center" width="15%">Attribute</th>
+    <th align="center" width="85%">Description</th>
+  </tr>
+  <tr>
+    <td align="center">url</td>
+    <td>
+      The URL of the jk status page you will use to
+      perform the requested operations.  If not specified, defaults to
+      <code>http://localhost:80/jkstatus</code> (which corresponds
+      to a standard installation of Apache mod_jk).
+    </td>
+  </tr>
+  <tr>
+    <td align="center">username</td>
+    <td>
+      The username of a mod_jk status user that has been configured with the
+      <code>Allow user</code> Apache Location constraint.  This attribute is optional.
+    </td>
+  </tr>
+  <tr>
+    <td align="center">password</td>
+    <td>
+      The password of a mod_jk status user that has been configured with the
+      <code>Allow user</code> Apache Location constraint.  This attribute is optional.
+    </td>
+  </tr>
+</table>
+
+</body>

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/test/build.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/test/build.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/test/build.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,104 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!-- @author Peter Rossbach -->
+<project name="JkStatusTestcases" basedir="." default="test">
+	<property file="../../../../build/build.properties" />
+	<property file="../../../../build/build.properties.default" />
+	<property name="test.report.logs" value="logs/reports" />
+	<property name="test.results" value="logs/test-results" />
+
+	<property name="compile.optimize" value="true" />
+	<property name="compile.debug" value="true" />
+	<property name="compile.source" value="1.4" />
+	<property name="compile.deprecation" value="true" />
+	<property name="compile.nowarn" value="off" />
+	<property name="compile.encoding" value="ISO-8859-1" />
+	<property name="build.dir" value="build/test" />
+	<property name="src.dir" value="src/share" />
+	<property name="catalina.home" value="../../../../build/build" />
+
+	<!-- Build the classpath -->
+	<path id="project.classpath">
+		<pathelement location="../build/classes" />
+		<pathelement location="${jmx.jar}" />
+		<pathelement location="${commons-logging.jar}" />
+		<pathelement location="${log4j.jar}" />
+		<fileset dir="${catalina.home}/common/endorsed">
+			<include name="*.jar" />
+		</fileset>
+		<fileset dir="${catalina.home}/common/lib">
+			<include name="*.jar" />
+		</fileset>
+		<fileset dir="${catalina.home}/server/lib">
+			<include name="*.jar" />
+		</fileset>
+	</path>
+
+	<target name="build-prepare">
+		<mkdir dir="${build.dir}" />
+	</target>
+
+	<target name="info" description="Shows a information about this ant script">
+		<echo>
+			This ant script implements some testcases to verify the key functions of tomcat apache mod_jk jkstatus module.
+			You find this script at: ${ant.file}
+		</echo>
+	</target>
+
+	<!-- This target compiles all sources out of the 
+			projects source tree -->
+	<target name="compile" depends="build-prepare" description="This target compiles all sources out of the projects source tree">
+
+		<!-- Copies the static resources out of the src tree
+				to the build/classes dir -->
+		<copy todir="${build.dir}/classes">
+			<fileset dir="${src.dir}">
+				<include name="**" />
+				<exclude name="**/*.java" />
+			</fileset>
+		</copy>
+
+		<!-- Compiles all sources -->
+		<javac destdir="${build.dir}/classes" srcdir="${src.dir}" includes="**/*.java" excludes="**/.svn/**" deprecation="${compile.deprecation}" debug="${compile.debug}" source="${compile.source}" optimize="${compile.optimize}" nowarn="${compile.nowarn}" encoding="${compile.encoding}">
+			<classpath>
+				<path refid="project.classpath" />
+			</classpath>
+		</javac>
+	</target>
+
+	<target name="test" depends="compile" description="Run unit tests">
+		<delete dir="${test.results}" />
+		<mkdir dir="${test.results}" />
+		<junit fork="yes" failureProperty="test.failure">
+			<jvmarg value="-Dcatalina.base=${basedir}" />
+			<jvmarg value="-Dcatalina.home=${catalina.home}" />
+			<jvmarg value="-Dlog4j.configuration=file:conf/log4j.xml" />
+			<classpath>
+				<pathelement location="${build.dir}/classes" />
+				<path refid="project.classpath" />
+			</classpath>
+			<formatter type="plain" usefile="false" />
+			<formatter type="xml" />
+			<batchtest todir="${test.results}">
+				<fileset dir="${build.dir}/classes" includes="**/*Test.class" />
+			</batchtest>
+		</junit>
+		<mkdir dir="${test.report.logs}" />
+		<junitreport todir="${test.report.logs}">
+			<fileset dir="${test.results}" />
+			<report format="frames" todir="${test.report.logs}" />
+		</junitreport>
+		<antcall target="checktest" />
+	</target>
+
+	<target name="checktest" if="test.failure">
+		<fail message="some test failed" />
+	</target>
+
+	<target name="clean">
+		<delete dir="${build}/dir" />
+		<delete dir="build" />
+		<delete dir="${test.report.logs}" />
+		<delete dir="${test.results}" />
+		<delete dir="logs" />
+	</target>
+</project>

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/test/conf/jkstatus.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/test/conf/jkstatus.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/test/conf/jkstatus.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<jk:status xmlns:jk="http://jakarta.apache.org">
+  <jk:server name="localhost" port="80" software="Apache/2.0.54 (Win32) mod_ssl/2.0.54 OpenSSL/0.9.7g mod_jk/1.2.15" version="1.2.15" />
+  <jk:balancers>
+  <jk:balancer id="0" name="lb" type="lb" sticky="True" stickyforce="False" retries="3" recover="60" >
+      <jk:member id="0" name="node1" type="ajp13" host="localhost" port="9012" address="127.0.0.1:9012" status="OK" lbfactor="1" lbvalue="1" elected="0" readed="0" transferred="0" errors="0" busy="0" />
+      <jk:member id="1" name="node2" type="ajp13" host="localhost" port="9022" address="127.0.0.1:9022" status="OK" lbfactor="1" lbvalue="1" elected="0" readed="0" transferred="0" errors="0" busy="0" />
+    <jk:map type="Wildchar" uri="/ClusterTest/*" context="/ClusterTest/*" />
+    <jk:map type="Exact" uri="/ClusterTest" context="/ClusterTest" />
+    <jk:map type="Wildchar" uri="/myapps/*" context="/myapps/*" />
+    <jk:map type="Exact" uri="/myapps" context="/myapps" />
+  </jk:balancer>
+  </jk:balancers>
+</jk:status>
+

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/test/conf/log4j.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/test/conf/log4j.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/test/conf/log4j.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
+<!-- ===================================================================== -->
+<!-- -->
+<!-- Log4j Configuration -->
+<!-- -->
+<!-- ===================================================================== -->
+<!-- $Id:$ -->
+<!--
+| For more configuration infromation and examples see the Jakarta Log4j
+| owebsite: http://jakarta.apache.org/log4j
+-->
+<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/" debug="false">
+
+<!-- ============================== -->
+<!-- Append messages to the console -->
+<!-- ==============================-->
+
+<appender name="CONSOLE" class="org.apache.log4j.ConsoleAppender">
+<param name="Target" value="System.out"/>
+<layout class="org.apache.log4j.PatternLayout">
+<!--The default pattern: Date Priority [Category] Message\n-->
+<param name="ConversionPattern" value="%d{ABSOLUTE} %-5p [%c{1}] %m%n"/>
+</layout>
+</appender>
+
+
+<category name="org.apache.jk.status" 
+           additivity="false"> 
+   <priority value="info" />
+   <appender-ref ref="CONSOLE" />
+</category>
+
+<category name="org.apache.catalina" 
+           additivity="false"> 
+   <priority value="info" />
+   <appender-ref ref="CONSOLE" />
+</category>
+<category name="org.apache.tomcat" 
+           additivity="false"> 
+   <priority value="error" />
+   <appender-ref ref="CONSOLE" />
+</category>
+<category name="org.apache.naming" 
+           additivity="false"> 
+   <priority value="info" />
+   <appender-ref ref="CONSOLE" />
+</category>
+<category name="org.apache.commons" 
+           additivity="false"> 
+   <priority value="info" />
+   <appender-ref ref="CONSOLE" />
+</category>
+
+<!-- Setup the Root c  -->
+<root>
+<appender-ref ref="CONSOLE"/>
+</root>
+</log4j:configuration> 
+

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/test/src/share/org/apache/jk/status/JkStatusParserTest.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/test/src/share/org/apache/jk/status/JkStatusParserTest.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/jkstatus/test/src/share/org/apache/jk/status/JkStatusParserTest.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,46 @@
+package org.apache.jk.status;
+
+import java.io.IOException;
+import java.io.StringReader;
+
+import junit.framework.TestCase;
+
+import org.apache.tomcat.util.digester.Digester;
+import org.xml.sax.SAXException;
+
+/**
+ * @author Peter Rossbach
+ *  
+ */
+public class JkStatusParserTest extends TestCase {
+
+	public void testDigester() throws IOException, SAXException {
+		Digester digester = JkStatusParser.createDigester();
+        String example = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>"
+                       +  "<jk:status xmlns:jk=\"http://jakarta.apache.org\">"
+                       +  "<jk:server name=\"localhost\" port=\"80\" software=\"Apache/2.0.54 (Win32) mod_ssl/2.0.54 OpenSSL/0.9.7g mod_jk/1.2.13-dev\" version=\"1.2.12\" />"
+                       +  "<jk:balancers>"
+                       +  "<jk:balancer id=\"0\" name=\"lb\" type=\"lb\" sticky=\"True\" stickyforce=\"False\" retries=\"3\" recover=\"60\" >"
+                       +  "<jk:member id=\"0\" name=\"node1\" type=\"ajp13\" host=\"localhost\" port=\"9012\" address=\"127.0.0.1:9012\" status=\"OK\" lbfactor=\"1\" lbvalue=\"1\" elected=\"0\" readed=\"0\" transferred=\"0\" errors=\"0\" busy=\"0\" />"
+                       +  "<jk:member id=\"1\" name=\"node2\" type=\"ajp13\" host=\"localhost\" port=\"9022\" address=\"127.0.0.1:9022\" status=\"OK\" lbfactor=\"1\" lbvalue=\"1\" elected=\"0\" readed=\"0\" transferred=\"0\" errors=\"0\" busy=\"0\" />"
+                       +  "<jk:map type=\"Wildchar\" uri=\"/ClusterTest/*\" context=\"/ClusterTest/*\" />"
+                       +  "<jk:map type=\"Exact\" uri=\"/ClusterTest\" context=\"/ClusterTest\" />"
+                       +  "<jk:map type=\"Wildchar\" uri=\"/myapps/*\" context=\"/myapps/*\" />"
+                       +  "<jk:map type=\"Exact\" uri=\"/myapps\" context=\"/myapps\" />"
+                       +  "</jk:balancer>"
+                       +  "</jk:balancers>"
+                       +  "</jk:status>" ;
+		StringReader reader = new StringReader(example);
+		JkStatus status = (JkStatus) digester
+				.parse(reader);
+		assertNotNull(status);
+        assertNotNull(status.getServer());
+        assertEquals(1,status.getBalancers().size());
+        JkBalancer balancer = (JkBalancer)status.getBalancers().get(0);
+        assertEquals(2,balancer.getBalancerMembers().size());
+        assertEquals("node1",((JkBalancerMember)balancer.getBalancerMembers().get(0)).getName());
+        assertEquals("node2",((JkBalancerMember)balancer.getBalancerMembers().get(1)).getName());
+        assertEquals(4,balancer.getBalancerMappings().size());
+	}
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/BUILDING
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/BUILDING	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/BUILDING	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,143 @@
+ 
+  Building from the subversion tree: (for developers only).
+  -----------------------------------
+  When using a subversion tree buildconf.sh must be run before configure.
+  The today version of buildconf.sh build the following files:
+  libtool files in scripts/build/unix (should copy them?).
+  Makefile.in from Makefile.am
+  aclocal.m4 from different m4 files located in the local machine.
+  configure from configure.in and aclocal.m4.
+  If you see error message from automake, don't care about them.
+
+
+  Building using configure
+  ------------------------
+ 
+  It is possible to use autoconf for configuration and installation.
+  To create tomcat-connectors's autoconf script, you will need libtool
+  1.5.2 or higher, and autoconf 2.59 or newer.
+  Those tools will not be required if you are just
+  using a package downloaded from apache.org, they are only required for
+  developers.
+ 
+  To configure tomcat-connectors run the following commands.
+ 
+  ./buildconf.sh  (not required unless you are a developer)
+  ./configure [autoconf arguments] [tomcat-connectors arguments]
+  make
+
+  It is possible to set CFLAGS and LDFLAGS to add some platform specifics:
+  LDFLAGS=-lc \
+  ./configure -with-apxs=/home2/local/apache/bin/apxs
+
+  
+  Build for both Apache 1.3 and 2.0
+  ---------------------------------
+
+  If you want to build mod_jk for Apache 1.3 and 2.0, you should :
+
+  use configure and indicate Apache 1.3 apxs location (--with-apxs)
+  use make
+  copy the mod_jk binary to the apache modules location
+
+  make clean (to remove all previously compiled modules)
+  use configure and indicate Apache 2.0 apxs location,
+  then make.
+
+  ./configure --with-apxs=/usr/sbin/apxs
+  make
+  cp ./apache-1.3/mod_jk.so /usr/lib/apache
+  make clean
+  ./configure --with-apxs=/usr/sbin/apxs2
+  make 
+  cp ./apache-2.0/mod_jk.so /usr/lib/apache2
+   
+
+  Examples
+  --------
+
+  Apache2.0, JNI support:
+
+  ./configure --with-apxs=/opt/apache2/bin/apxs --with-java-home=${JAVA_HOME} --with-java-platform=2 -enable-jni
+
+  Apache 1.3, no JNI support:
+
+  ./configure --with-apxs=/usr/sbin/apxs 
+
+  tomcat-connectors arguments
+  -----------------------------------
+  JVM related parameters:
+  --with-java-home=DIR
+  DIR is the  patch to the JDK root directory. Something like: /opt/java/jdk12
+  --with-os-type[=SUBDIR] 
+  SUBDIR is the os-type subdirectory, normaly configure should guess it
+  correctly.
+  --with-arch-type[=SUBDIR]
+  SUBDIR is the arch subdirectory, normaly configure should guess it correctly. 
+  --with-java-platform=VAL
+  VAL is the Java platform 1 is 1.1.x and 2 is 1.2.x. It is guessed correctly.
+  
+  Apache related parameters:
+  --with-apxs[=FILE]
+  FILE is the location of the apxs tool. Default is finding apxs in PATH.
+  It builds a shared Apache module. It detects automaticly the Apache version.
+  (2.0 and 1.3)
+* --with-apache=DIR
+  DIR is the path where apache sources are located.
+  The apache sources should have been configured before configuring mod_jk.
+  DIR is something like: /home/apache/apache_1.3.19
+  It builds a static Apache module.
+  --enable-EAPI
+  This parameter is needed when using Apache-1.3 and mod_ssl, otherwise you
+  will get the error message: "this module might crash under EAPI!" when
+  loading libjk.so in httpd.
+
+  JNI support:
+  --enable-jni
+  Build the jni_connect.so and the JNI worker.
+
+* Static build need more tests, and we strongly recommand dynamic build
+  using DSO/APXS.
+
+
+  Installation
+  ------------
+
+  The mod_jk binary will be in :
+
+  ./apache-1.3/mod_jk.so if you select to build mod_jk for apache 1.3
+
+  ./apache-2.0/mod_jk.so if you select to build mod_jk for apache 2.0
+
+
+
+  Misc notes 
+  ----------
+
+  HP-UX build notes :
+
+  If you plan to use GCC on HP-UX to build mod_jk, be sure to 
+  have -DHPUX11GCC defined (usually by setting CLAGS before configure)
+
+  Reports are that the stripped down cc version that ships with
+  HP-UX won't be able to works, you should habe the HP add-on ANSI C 
+  Compiler package.
+
+  A good repository for HP-UX gnu tools is :
+
+  http://gatekeep.cs.utah.edu/
+
+
+  Solaris build notes :
+
+  the build should works with the GNU gcc compiler, on both
+  SPARC and x86 architecture systems.
+
+  A good repository for Solaris gnu tools is :
+
+  http://www.sunfreeware.com/
+
+  Be carefull when mixing native compiler and gnu compiler, and
+  ensure that apache and mod_jk will be compiled and linked with
+  the same tools (ie full Solaris or full GNU)
+

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/CHANGES.txt
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/CHANGES.txt	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/CHANGES.txt	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,132 @@
+TOMCAT CONNECTORS (JK) CHANGELOG:           -*-text-*-
+Last modified at [$Date: 2006-06-28 18:56:49 -0500 (Wed, 28 Jun 2006) $]
+PLEASE DON'T WRITE IN THIS FILE BUT IN ../xdocs/changelog.xml AND USE ../tools/jkrelease.sh
+TO BUILD THE TEXT VERSION.
+
+Changes in JK 1.2.11
+    * BUG 34358: Fix the load balance worker load balance method. It was not being
+      set from the worker.properties file
+    * BUG 34357: Fix a segfault in Apache 2 when using JKAutoAlias.
+    * Update tomcat_trend.pl for new error log string formatting.
+
+Changes in JK 1.2.10
+    * Do not mark the worker in error state if headers are larger then AJP13
+      limit.
+
+Changes in JK 1.2.9
+    * lbfactor is now relationship between members, so worker.a.lbfactor=1 and worker.b.lbfactor=1
+      will give 50-50% load.
+    * Use of shm for load balancer via JkShmFile. Be sure to define JkShmFile /path/to/smfile 
+      in your httpd.conf
+    * on Series you should use the latest PTF for Apache 2.0 (which is now 2.0.52) and ad minima
+      SI17402/SI17061 or cumulative including them.
+     
+Changes in JK 1.2.8
+    * cachesize has changed from unlimited to limited, so it's basically a pool of connections 
+      with recycle timeout like in mod_proxy for Apache 2.2.
+      
+Changes with JK 1.2.7
+    * Fix iis redirector that was figuring .properties
+      file on each request [mturk]
+    * Start fixing 64/32 bit compatibility issues [mturk]
+    * Indent all source files. [mturk]
+    
+Changes with JK 1.2.6
+    * Fix POST Recovery problems in LB mode [hgomez]
+    * Add CPING/CPONG support to avoid problems with hang tomcats [hgomez]
+    * Make POST recovery in LB configurable [hgomez]
+    * Update to Apache License 2.0 [hgomez]
+    * For Apache 2.0, when the env var no-jk is present, mod_jk didn't handle request (declined)
+      and as such dont forward requests to tomcats even if URL match.
+      To be used with SetEnvIf or BrowserMatch directives for example to exclude some URL/URI or
+      Browser [hgomez].
+    * Add a fix for iSeries (AS/400) which use XOPEN/Unix98 APIs and need sa_len to be set when
+      calling connect(), it will resolve the error EINVAL in jk_connect [hgomez].
+      
+Changes with JK 1.2.5
+    * Fix a thread safe bug when mapping URI's.
+      [billbarker]
+    * Fix a thread safe bug when resolving worker host name
+      when using mod_jk with Apache 2 and the worker MPM.
+      [hgomez]
+    * Remove an unnecessary error message when connections to
+      all load balanced workers fail.
+      [glenn]
+    * When mod_jk cannot connect to a worker include the name of
+      the worker in the error message.  This is especially helpful
+      when you are using load balanced workers.
+      [glenn]
+    * Fix problem with mod_jk.log getting opened multiple times for
+      Apache 2. Only one mod_jk.log can be configured.
+      [glenn]
+    * Fix Apache 2 connector so that DirectoryIndex works for an
+      index.jsp page if JkOptions ForwardDirectories was configured.
+      [hgomez]
+    * Fix exposure of JSP source if a //path/to.jsp URL was requested
+      in Apache 1.3 and Apache 2.0 connector.
+      [billbarker]
+
+Changes with JK 1.2.4
+    * Fix use of libtool for Apache mod_jk builds with more recent
+      versions of Apache 2.
+      [jfclere]
+    * Use reentrant version of strtok() for web server's which use
+      threads. This fixes a thread safe bug under Apache 2 and the
+      worker MPM.
+      [glenn]
+    * Fix the Apache 2 mod_jk hook priority so that mod_jk works
+      well with both mod_alias and mod_dir.
+      [glenn]
+
+Changes with JK 1.2.3:
+    * Add the ability to configure JkLog to pipe its log output to an
+      executable such as Apache rotatelogs or cronolog.  Apache 2.0 only.
+      [glenn]
+    * Add JkAutoAlias to Apache 2.0
+      [glenn]
+    * Apache 2/1.3, if Tomcat returns an error but not content,
+      let Apache handle processing the error returned by Tomcat.
+    * Added the load balancer sticky_session property. If set to 0
+      requests with servlet SESSION ID's can be routed to any Tomcat
+      worker. Default is 1, sessions are sticky.
+      [glenn]
+    * Cleaned up detection and reporting of aborted client connections.
+      This cleanup also makes sure that mod_jk does not pass any requests
+      on to Tomcat if the remote client aborted its connection.
+      [glenn]
+    * Fixed a bug in Apache 2.0 which caused a POST request forwarded to
+      Tomcat to fail if it generated SSI directives which were post
+      processed by mod_include.
+      [glenn]
+    * Fixed a bug in JkRequestLogFormat when printing the request URI that
+      could cause a URI with hex escapes sequences to be formatted wrong.
+      [glenn]
+      
+Changes with JK 1.2.2:
+    * tomcat_trend.pl updated script to support changed logging of 
+      aborted requests
+      [glenn]
+    * jk set correctly the content-type in Apache 2.0,
+      making it ready to works with mod_deflate and AddOutputFilterByType 
+      [hgomez]
+    * jk will check result of get_endpoint and handle a failure.
+      This call can fail if the allocation for the endpoint fails because of low memory conditions 
+      causing a dereference of NULL when we try and access the endpoint
+      [mmanders]
+      
+Changes with JK 1.2.1:
+    * Don't send initial chunk for chunked encoding, fix #14282
+      [costin]
+    * Add perl scripts for analyzing mod_jk logs and generating graphs/reports  
+      [glenn]
+    * Make JK honor the CanonicalHost directive.
+      [hgomez]
+    * Log cleanup
+      [costin]
+    * Fix typos in jk xdocs/docs
+      [hgomez]
+    * Add JkRequestLogFormat to Apache 2.0
+      [hgomez]
+    * Final patches to make JK iSeries compliant
+      [hgomez]
+      

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/Makefile.am
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/Makefile.am	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/Makefile.am	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,21 @@
+#
+# Tell automake what it should do
+AUTOMAKE_OPTIONS = foreign
+MAINTAINERCLEANFILES=config.cache config.status config.log \
+Makefile.in configure
+
+SUBDIRS = @WEBSERVER@
+
+all:
+	target="all"; \
+	list='$(SUBDIRS)'; \
+	for i in $$list; do \
+	    echo "Making $$target in $$i"; \
+	    if test "$$i" != "."; then \
+	       (cd $$i && $(MAKE) $$target) || exit 1; \
+	    fi; \
+	done;
+
+apidocs: common/*.h
+	../../scandoc/scandoc.pl -i ../../scandoc/template.pl -p \
+	./docs/api/ -dproject="mod_jk Library" common/*.h common/*.c

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/README
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/README	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/README	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,30 @@
+README for tomcat-connector
+
+$Id: README 417906 2006-06-28 23:56:49Z rjung $
+
+Please see doc/mod_jk-howto.html for more verbose instructions
+
+* What is tomcat-connector ?
+
+tomcat-connector is a new project to release web-servers connector
+for the Tomcat servlet engine.
+
+This project didn't start from null since it reuse the latest code from
+mod_jk for the native parts and tomcat 3.3 for the java side of the 
+force.
+
+From mod_jk we gain :
+
+* A connector (plugin) for many Web Server, including
+  Apache HTTP Server, Netscape/IPLanet NES and Microsoft IIS
+  It also support JNI (and seems to used at least by IBM under 
+  AS/400 for Apache/WebSphere connectivity).
+  
+* Fault-tolerance and load-balancing. mod_jk use the concept of 
+  workers which handle a particular request, and a special worker
+  , the lb worker, is a group (cluster ?) of physical workers.
+
+* Direct access to Tomcat 3.2/3.3/4.0/4.1 servlet engine via ajp13
+  protocol. 
+
+* OK, then how do I build web-connector ? Just take a look at BUILDING

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/STATUS.txt
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/STATUS.txt	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/STATUS.txt	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,39 @@
+TOMCAT CONNECTORS (JK) STATUS:			-*-text-*-
+Last modified at [$Date: 2006-07-20 18:03:34 -0500 (Thu, 20 Jul 2006) $]
+
+Release:
+
+    1.2.19  : in development
+    1.2.18  : released July, 2006
+    1.2.17  : not released
+    1.2.16  : not released
+    1.2.15  : released November 8, 2005
+    1.2.14  : released July 13, 2005
+    1.2.13  : released May 16, 2005
+    1.2.12  : released May 7, 2005
+    1.2.11  : released April 29, 2005
+    1.2.10  : released March 30, 2005
+    1.2.9   : not released
+    1.2.8   : released December 24, 2004
+    1.2.7   : not released
+    1.2.6   : released July 23, 2004
+    1.2.5   : released September 30, 2003 
+    1.2.4   : released May 27, 2003
+    1.2.3   : released May 16, 2003
+    1.2.2   : released December 17, 2002
+    
+
+
+RELEASE SHOWSTOPPERS:
+
+    
+    
+ 
+RELEASE NON-SHOWSTOPPERS BUT WOULD BE REAL NICE TO WRAP THESE UP:
+    
+
+
+
+STUFF FOR THE FUTURE:
+
+    * enter mature phase ... ?

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/TODO
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/TODO	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/TODO	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,221 @@
+TODO for tomcat-connectors
+
+$Id: TODO 417587 2006-06-27 21:05:40Z rjung $
+
+1) Optimize "distance"
+======================
+
+Sorting the list of balanced workers by distance would be nice, but:
+How to combine the sorting with the offset implementation (especially
+useful for strategy BUSYNESS under low load).
+
+2) Reduce number of string comparisons in most_suitable
+========================================================
+
+a) redirect/domains
+
+It would be easy to improve the redirect string b an integer, giving the
+index of the worker in the lb. Then lb would not need to search for the redirect worker.
+
+The same way, one could add a list with indizes to workers in the same domain.
+Whenever domain names are managed (init and status worker update) one would
+scan the worker list and update the index list.
+
+Finally one could have a list of workers, whose domain is the same as the redirect
+attribute of the worker, because that's also something we consider.
+
+What I'm not sure about, even in the existing code, is the locking between updates
+by the status worker and the process local information about the workers,
+especially in the case, when status updates a redirect or domain attribute.
+
+I would like to keep these attributes and the new index arrays process local,
+and the processes should find out about changes made by status to shm (redirect/domain)
+and then rebuild their data. No need to get these on every request from the shm,
+only the check for up-to-date should be made.
+
+b) exact matches for jvmRoutes
+
+Could we use hashes instead of string comparisons all the time?
+I'm not sure, if a good enough hash takes longer than a string comparison though.
+
+3) Optimization of JK_WORKER_USABLE
+====================================
+
+We use that one quite a lot. Since it is now a combination of four
+ANDs of negated values, we could also do
+
+#define JK_WORKER_USABLE(w)   (!((w)->in_error_state || ($w)->is_stopped || (w)->is_disabled || (w)->is_busy))
+
+I think it we should consider combining the flags into an additional
+is_usable (makes checks easier, but of course we would have to set it
+every time we change one of the four other flags). But in terms of
+performance that happens rarely.
+
+4) Code separation between factory, validate and init in lb
+============================================================
+
+The factory contains:
+
+        private_data->worker.retries = JK_RETRIES;
+        private_data->s->recover_wait_time = WAIT_BEFORE_RECOVER;
+
+I think, this should move to validate() or init().
+It might even be obsolete, because in init, we already have:
+
+    pThis->retries = jk_get_worker_retries(props, p->s->name,
+    p->s->retries = pThis->retries;
+    p->s->recover_wait_time = jk_get_worker_recover_timeout(props, p->s->name, WAIT_BEFORE_RECOVER);
+    if (p->s->recover_wait_time < WAIT_BEFORE_RECOVER)
+        p->s->recover_wait_time = WAIT_BEFORE_RECOVER;
+
+Then: In validate there is
+
+                p->lb_workers[i].s->error_time = 0;
+
+So shouldn't there also be
+
+                p->lb_workers[i].s->maintain_time = time(NULL);
+
+5) Refactor Logging
+====================
+
+a) Use the same code files for the request logging functions in Apache 1.3 and 2.0.
+
+b) Use the same code files for piped logging in Apache 1.3 and 2.0.
+
+6) ajpget
+==========
+
+Combine ajplib and Apache ab to an ajp13 commandline client ajpget.
+
+7) Manage lb method and locking via jk_status
+=============================================
+
+It's not yet contained in the shm.
+
+8) Parsing workers.properties
+=============================
+
+Parsing of workers.properties aditionally to just looking up attributes
+would help users to detect syntax errors in the file. At the moment
+no information will be logged, e.g. when attributes contain typos.
+
+9) Persisting workers.properties
+================================
+
+Make workers.properties persist from inside status worker.
+
+10) Reduce number of uses of time(NULL)
+=======================================
+
+We use time(NULL) a lot. Since it only has resolution of a second,
+I'm asking myself, if we could update the actual time in only a few
+places and get time out of some variables when needed. The same does
+not hold true for millisecond time, but in several cases we use the time,
+it's not very critical, that it is exact. These cases are related to:
+
+Some of this is already been done, the remaining parts are:
+
+- last_access for usage against timeout value that is ~minutes
+- error_time for usage against retry timeout that is ~minutes
+- uri_worker_map checked for usage against JK_URIMAP_RELOAD=1 minute
+
+So I think, it would suffice to set an actual time at the beginning of
+the request/response cycle (used by everything before the request is being
+sent over the socket) and maybe after the response shows up/ an error occurs
+(for everything else, if there is).
+
+For which cases would it be OK, to use the time before sending to TC:
+- uri_worker_map "checked" (uri map lookup starts early)
+- setting/testing last_access in
+  - jk_ajp_common.c:ajp_connect_to_endpoint()
+  - jk_ajp_common.c:ajp_get_endpoint()
+  - jk_ajp_common.c:ajp_maintain()
+
+What about the others:
+- setting last_access in init should use the actual time in
+  jk_ajp_common.c:ajp_create_endpoint_cache()
+
+- setting last_access again after the service could also use the 
+  actual time in jk_ajp_common.c:ajp_done()
+- setting error_time should better use the actual time
+  jk_lb_worker.c service(): rec->s->error_time = time(NULL);
+
+The last two cases could again use the same time, which then would be needed
+to be generated at the end or directly after service.
+
+11) Access/Modification Time in shm
+===================================
+
+a) [Discussion] What will this generally be used for? At the moment,
+only jk_status "uses" it, but it only sets the values, it never asks for them.
+
+b) [Improvement, minor] jk_shm_set_workers_time() implicitly calls
+jk_shm_sync_access_time(), but jk_status does:
+
+            jk_shm_set_workers_time(time(NULL));
+            /* Since we updated the config no need to reload
+             * on the next request
+             */
+            jk_shm_sync_access_time();
+
+two times. So depending on the idea of the functionality of these calls,
+either set_workers_time and sync_access_time should be independently,
+or the second call in jk_status coulkd be removed.
+
+12) "Destroy" functionality
+===========================
+
+[Hint] Destroy on a worker never seems to free shm,
+but I think that was already a flaw without shm.
+
+13) Locks against shm
+=====================
+
+It might be an intersting experiment to implement an improved locking structure.
+It looks like one would need in fact different types of locks.
+In shm we have as read/write information:
+
+Changed only by status worker:
+- redirect, domain, lb_factor, sticky_session, sticky_session_force,
+  recover_wait_time, retries, status (is_disabled, is_stopped).
+
+These changes need some kind of reconfiguration in the threads after
+change and before the next request/response. Since changes are rare,
+here we would be better of, with a simple detect change and copy from
+shm to process procedure. status updates the data in shm and after that
+the time stamp on the shh. Each process checks the time stamp before
+doing a request, and when the time stamp changed it does a writer CS
+lock and updates it's local copy. All threads always do a reader CS
+lock when doing a request/response cycle. Reader CS locks are concurrent,
+writers are exclusive. So readers are not allowed, when the config data is being updated.
+
+Changed by the threads themselves (and via reset by the status worker):
+- counters needed by routing decisions (lb_value, readed, transferred, busy)
+- timers needed by maintenance functions (error_time, servic_time/maintain_time)
+- status is_busy, in_error_state
+- uncritical data with no influence on routing decisions (max_busy, elected, errors,
+  in_recovering)
+
+Here again we could improve by using reader/writer locks. I have a
+tendency for the PESSIMISTIC side of locking, but I think we could
+shrink the code blocks that should be locked. At the monent they are
+pretty big (most of get_most_suitable_worker).
+
+Read-only: name and id.
+
+By the way: at several places we don't check for errors on getting the lock.
+
+14) What I didn't yet check
+===========================
+
+a) Correctness of is_busy handling
+
+b) Correctness of the reset values after reset by status worker
+
+c) What would be the exact behaviour, if shm does not work (memory case).
+   Will this be a critical failure, or will we only experience a
+   degradation in routing decisions.
+
+d) How complete is mod_proxy_ajp/mod_proxy_balancer.
+   Port changes from mod_jk to them.

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/apache-1.3/Makefile.apxs.in
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/apache-1.3/Makefile.apxs.in	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/apache-1.3/Makefile.apxs.in	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,25 @@
+## configure should make the Makefile out of this file.
+
+APXS=@APXS@
+OS=@OS@
+JAVA_HOME=@JAVA_HOME@
+APXSLDFLAGS=@APXSLDFLAGS@
+APXSCFLAGS=@APXSCFLAGS@
+
+JK=../common/
+JK_INCL=-DUSE_APACHE_MD5 -I ${JK}
+JAVA_INCL=-I ${JAVA_HOME}/include -I ${JAVA_HOME}/include/${OS}
+JAVA_LIB=-L ${JAVA_HOME}/jre/lib/${ARCH} -L ${JAVA_HOME}/lib/${ARCH}/native_threads
+
+## read the object (.c) from the list file.
+OEXT=.c
+include ../common/list.mk
+
+all: mod_jk.so
+
+mod_jk.so: 
+	$(APXS) -c -o $@ -Wc,"${APXSCFLAGS} ${JK_INCL}" ${JAVA_INCL} "${APXSLDFLAGS}" mod_jk.c ${APACHE_OBJECTS} 
+
+clean:
+	rm -f *.o *.lo *.a *.la *.so *.so.* *.slo
+	rm -rf .libs

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/apache-1.3/Makefile.in
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/apache-1.3/Makefile.in	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/apache-1.3/Makefile.in	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,97 @@
+
+## configure should make the Makefile out of this file.
+
+srcdir=@srcdir@
+top_srcdir=@top_srcdir@
+VPATH=@srcdir@
+APXS=@APXS@
+OS=@OS@
+JAVA_HOME=@JAVA_HOME@
+CP=@CP@
+APACHE_DIR=@APACHE_DIR@
+MKDIR=@MKDIR@
+DESTDIR=@APACHE_DIR@
+LIBTOOL=@LIBTOOL@
+CP=@CP@
+CC=@CC@
+
+top_builddir=..
+
+OEXT=.lo
+libexecdir=${APACHE_DIR}/libexec
+JK_DIR := ..
+BUILD_DIR = ${JK_DIR}/../build/jk/apache13
+
+APACHE_FILES = Makefile.tmpl Makefile.libdir libjk.module
+
+JK=../common/
+JK_INCL=-DUSE_APACHE_MD5 -I ${top_srcdir}/common
+JAVA_INCL=-I ${JAVA_HOME}/include -I ${JAVA_HOME}/include/${OS}
+JAVA_LIB=-L ${JAVA_HOME}/jre/lib/${ARCH} -L ${JAVA_HOME}/lib/${ARCH}/native_threads
+APACHE_CFLAGS=@apache_include@ @APXSCFLAGS@ @APXSCPPFLAGS@ -I${top_srcdir}/common
+
+# Compile commands
+JK_CFLAGS  = $(JK_INCL) $(JAVA_INCL) $(APACHE_CFLAGS)
+COMPILE    = $(CC)
+SH_COMPILE = $(LIBTOOL) --mode=compile $(COMPILE) $(JK_CFLAGS)
+MOD_LINK   = $(LIBTOOL) --mode=link $(CC)
+
+include ../common/list.mk
+
+all: @LIB_JK_TYPE@
+
+#
+# install part
+#
+install: @INSTALL_TYPE@
+
+install_static: mod_jk.a
+	@echo ""
+	@echo "Copying files to Apache Modules Directory..."
+	-${MKDIR} ${APACHE_DIR}/src/modules/jk
+	${LIBTOOL} --mode=install ${CP} $< ${APACHE_DIR}/src/modules/jk/mod_jk.a
+	-${CP} Makefile.tmpl ${APACHE_DIR}/src/modules/jk
+	-${CP} Makefile.libdir ${APACHE_DIR}/src/modules/jk
+	-${CP} mod_jk.c ${APACHE_DIR}/src/modules/jk
+	-${MKDIR} ${APACHE_DIR}/src/modules/jk/include
+	-${CP} ../common/*.h ${APACHE_DIR}/src/modules/jk/include
+	@echo ""
+	@echo "Please be sure to re-compile Apache..."
+	@echo ""
+	@echo "cd ${APACHE_DIR}"
+	@echo "./config.status --activate-module=src/modules/jk/libjk.a \\"
+	@echo "                --enable-module=dir \\"
+	@echo "                --disable-shared=dir"
+	@echo "make"
+	@echo ""
+install_dynamic: mod_jk.la
+	@echo ""
+	@echo "Copying files to Apache libexec Directory..."
+	${LIBTOOL} --mode=install ${CP} $< ${libexecdir}/mod_jk.so
+
+#
+# Clean part.
+#
+clean:
+	rm -f *.o *.lo *.a *.la *.so *.so.* *.slo
+	rm -rf .libs
+
+#
+# Compile part.
+#
+mod_jk.la: mod_jk.lo $(APACHE_OBJECTS)
+	 ${MOD_LINK} -o $@ -module -rpath ${libexecdir} $^
+mod_jk.a: mod_jk.lo $(APACHE_OBJECTS)
+	 ${MOD_LINK} -o $@ $^
+
+mod_jk.so: mod_jk.la
+	$(LIBTOOL) --mode=install cp mod_jk.la `pwd`/$@
+
+#
+# Common part.
+#
+mod_jk.lo: mod_jk.c
+	${SH_COMPILE} -c mod_jk.c -o $@
+
+.c.lo:
+	${SH_COMPILE} -c $< -o $@

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/apache-1.3/Makefile.libdir
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/apache-1.3/Makefile.libdir	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/apache-1.3/Makefile.libdir	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,4 @@
+This is a place-holder which indicates to Configure that it shouldn't
+provide the default targets when building the Makefile in this directory.
+Instead it'll just prepend all the important variable definitions, and
+copy the Makefile.tmpl onto the end.

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/apache-1.3/Makefile.netware
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/apache-1.3/Makefile.netware	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/apache-1.3/Makefile.netware	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,265 @@
+#
+# Makefile for mod_jk (NetWare version - gnu make)
+# created by Guenter Knauf <fuankg at apache.org>
+#
+
+# Edit the path below to point to the base of your Apache 1.3 includes.
+ifndef AP_HOME
+AP_HOME	= c:/projects/cw/apache_1.3.33
+endif
+# Edit the path below to point to the base of your NetWare Java SDK.
+ifndef JAVA_HOME
+JAVA_HOME	= c:/projects/sdks/java-nw
+endif
+# Edit the path below to point to the base of your Novell NDK.
+ifndef NDKBASE
+NDKBASE	= c:/novell
+endif
+INSTDIR	= s:/apache/modules
+
+# Edit the vars below to change NLM target settings.
+TARGET  = mod_jk
+VERSION	= $(JK_VERSION)
+COPYR	= Copyright (c) 2000-2004 The Apache Software Foundation. All rights reserved.
+DESCR	= Apache $(AP_VERSION_STR) plugin for Tomcat $(JK_VERSION_STR)
+MTSAFE	= NO
+STACK	= 49152
+#SCREEN	= NONE
+EXPORTS	= jk_module
+#AP_PRE	= YES
+
+# Edit the var below to point to your lib architecture.
+ifndef LIBARCH
+LIBARCH = CLIB
+# LIBARCH = LIBC
+endif
+
+# must be equal to DEBUG or NDEBUG
+DB	= NDEBUG
+# DB	= DEBUG
+# Optimization: -O<n> or debugging: -g
+ifeq ($(DB),NDEBUG)
+	OPT	= -O2
+	OBJDIR	= release
+else
+	OPT	= -g
+	OBJDIR	= debug
+endif
+
+# Include the version info retrieved from jk_version.h
+-include $(OBJDIR)/version.inc
+
+# The following line defines your compiler.
+ifdef METROWERKS
+	CC = mwccnlm
+else
+	CC = gcc
+endif
+# RM	= rm -f
+#CP	= cp -fv
+
+# Global flags for all compilers
+CFLAGS	= $(OPT) -D$(DB) -DNETWARE -nostdinc
+
+ifeq ($(CC),mwccnlm)
+LD	= mwldnlm
+LDFLAGS	= -nostdlib $(PRELUDE) $(OBJDIR)/*.o -o $(OBJDIR)/$(TARGET).nlm -commandfile
+CFLAGS	+= -gccinc -inline off -opt nointrinsics
+#CFLAGS	+= -w on
+ifeq ($(LIBARCH),LIBC)
+	PRELUDE = $(SDK_LIBC)/imports/libcpre.o
+	CFLAGS += -align 4 -inst mmx -proc 586
+#	CFLAGS += -D__ANSIC__
+else
+#	PRELUDE = $(SDK_CLIB)/imports/clibpre.obj
+	PRELUDE = "$(METROWERKS)/Novell Support/libraries/runtime/prelude.obj"
+#	CFLAGS += -include "$(METROWERKS)/Novell Support/headers/nlm_prefix.h"
+	CFLAGS += -align 1 -proc 586
+endif
+else
+LD	= nlmconv
+LDFLAGS	= -T
+CFLAGS	+= -fno-builtin -fpack-struct -fpcc-struct-return
+CFLAGS	+= -w
+#CFLAGS	+= -Wall -Wno-main # -pedantic
+ifeq ($(LIBARCH),LIBC)
+	PRELUDE = $(SDK_LIBC)/imports/libcpre.gcc.o
+#	CFLAGS += -D__ANSIC__
+else
+#	PRELUDE = $(SDK_CLIB)/imports/clibpre.gcc.o
+	CFLAGS += -include $(NDKBASE)/nlmconv/genlm.h
+endif
+endif
+CFLAGS	+= -include "precomp.h"
+
+ifeq ($(AP_PRE),YES)
+	PRELUDE	= $(OBJDIR)/libpre.o
+endif
+
+
+NDK_ROOT = $(NDKBASE)/ndk
+SDK_CLIB = $(NDK_ROOT)/nwsdk
+SDK_LIBC = $(NDK_ROOT)/libc
+JKCOMMON = ../common
+
+INCLUDES = -I$(AP_HOME)/src/include -I$(AP_HOME)/src/os/netware
+INCLUDES += -I$(JKCOMMON) -I$(JAVA_HOME)/include -I$(JAVA_HOME)/include/netware 
+
+ifeq ($(LIBARCH),LIBC)
+	INCLUDES += -I$(SDK_LIBC)/include -I$(SDK_LIBC)/include/nks
+	INCLUDES += -I$(SDK_LIBC)/include/winsock
+else
+	INCLUDES += -I$(SDK_CLIB)/include/nlm -I$(SDK_CLIB)/include
+	INCLUDES += -I$(NDKBASE)/ws295sdk/include
+	CFLAGS += -DNETDB_USE_INTERNET
+endif
+CFLAGS	+= $(INCLUDES)
+
+ifeq ($(MTSAFE),YES)
+	XDCDATA = $(AP_HOME)/src/os/netware/apache.xdc
+endif
+
+ifeq ($(OSTYPE),linux)
+DL	= '
+-include $(NDKBASE)/nlmconv/ncpfs.inc
+endif
+
+OBJS	= \
+	$(OBJDIR)/jk_nwmain.o \
+	$(OBJDIR)/jk_ajp12_worker.o \
+	$(OBJDIR)/jk_ajp13.o \
+	$(OBJDIR)/jk_ajp13_worker.o \
+	$(OBJDIR)/jk_ajp14.o \
+	$(OBJDIR)/jk_ajp14_worker.o \
+	$(OBJDIR)/jk_ajp_common.o \
+	$(OBJDIR)/jk_connect.o \
+	$(OBJDIR)/jk_context.o \
+	$(OBJDIR)/jk_jni_worker.o \
+	$(OBJDIR)/jk_lb_worker.o \
+	$(OBJDIR)/jk_map.o \
+	$(OBJDIR)/jk_md5.o \
+	$(OBJDIR)/jk_msg_buff.o \
+	$(OBJDIR)/jk_pool.o \
+	$(OBJDIR)/jk_shm.o \
+	$(OBJDIR)/jk_sockbuf.o \
+	$(OBJDIR)/jk_status.o \
+	$(OBJDIR)/jk_uri_worker_map.o \
+	$(OBJDIR)/jk_util.o \
+	$(OBJDIR)/jk_worker.o \
+	$(OBJDIR)/$(TARGET).o
+
+
+all: $(OBJDIR) $(OBJDIR)/version.inc $(OBJDIR)/$(TARGET).nlm 
+
+$(OBJDIR)/%.o: %.c
+	@echo Compiling $<
+	@$(CC) $(CFLAGS) -c $< -o $@
+
+$(OBJDIR)/%.o: $(JKCOMMON)/%.c
+	@echo Compiling $<
+	@$(CC) $(CFLAGS) -c $< -o $@
+
+$(OBJDIR)/%.o: $(AP_HOME)/src/os/netware/%.c
+	@echo Compiling $<
+	@$(CC) $(CFLAGS) -c $< -o $@
+
+$(OBJDIR)/version.inc: $(JKCOMMON)/jk_version.h $(AP_HOME)/src/include/httpd.h $(OBJDIR)
+	@echo Creating $@
+	@awk -f ../../support/get_ver.awk $< $(AP_HOME)/src/include/httpd.h > $@
+
+dist: all
+	-$(RM) $(OBJDIR)/*.o $(OBJDIR)/$(TARGET).map $(OBJDIR)/$(TARGET).ncv
+	-$(RM) $(OBJDIR)/$(TARGET).def $(OBJDIR)/version.inc
+#	-$(CP) ../changes.txt $(OBJDIR)/
+
+install: all
+	@[ -d $(INSTDIR) ] || mkdir $(INSTDIR)
+	@$(CP) $(TARGET).nlm $(INSTDIR)
+
+clean:
+	-$(RM) -r $(OBJDIR)
+
+$(OBJDIR):
+	@mkdir $(OBJDIR)
+
+$(OBJDIR)/$(TARGET).nlm: $(OBJS) $(OBJDIR)/$(TARGET).def $(XDCDATA)
+	@echo Linking $@
+	@-$(RM) $@
+	@$(LD) $(LDFLAGS) $(OBJDIR)/$(TARGET).def
+
+$(OBJDIR)/%.xdc: Makefile.netware
+	@echo Creating $@
+	@$(MPKXDC) $(XDCOPT) $@
+
+$(OBJDIR)/%.def: Makefile.netware
+	@echo $(DL)# DEF file for linking with $(LD)$(DL) > $@
+	@echo $(DL)# Do not edit this file - it is created by make!$(DL) >> $@
+	@echo $(DL)# All your changes will be lost!!$(DL) >> $@
+	@echo $(DL)#$(DL) >> $@
+	@echo $(DL)copyright "$(COPYR)"$(DL) >> $@
+	@echo $(DL)description "$(DESCR)"$(DL) >> $@
+	@echo $(DL)version $(VERSION)$(DL) >> $@
+ifdef NLMTYPE
+	@echo $(DL)type $(NLMTYPE)$(DL) >> $@
+endif
+ifdef STACK
+	@echo $(DL)stack $(STACK)$(DL) >> $@
+endif
+ifdef SCREEN
+	@echo $(DL)screenname "$(SCREEN)"$(DL) >> $@
+else
+	@echo $(DL)screenname "DEFAULT"$(DL) >> $@
+endif
+ifeq ($(DB),DEBUG)
+	@echo $(DL)debug$(DL) >> $@
+endif
+	@echo $(DL)threadname "$(TARGET)"$(DL) >> $@
+ifdef XDCDATA
+	@echo $(DL)xdcdata $(XDCDATA)$(DL) >> $@
+endif
+ifeq ($(LIBARCH),CLIB)
+ifeq ($(AP_PRE),YES)
+	@echo $(DL)start _lib_start$(DL) >> $@
+	@echo $(DL)exit _lib_stop$(DL) >> $@
+else
+	@echo $(DL)start _Prelude$(DL) >> $@
+	@echo $(DL)exit _Stop$(DL) >> $@
+endif
+	@echo $(DL)import @$(NDK_ROOT)/nwsdk/imports/clib.imp$(DL) >> $@
+	@echo $(DL)import @$(NDK_ROOT)/nwsdk/imports/threads.imp$(DL) >> $@
+	@echo $(DL)import @$(NDK_ROOT)/nwsdk/imports/nlmlib.imp$(DL) >> $@
+	@echo $(DL)import @$(NDK_ROOT)/nwsdk/imports/socklib.imp$(DL) >> $@
+#	@echo $(DL)import @$(NDK_ROOT)/nwsdk/imports/ws2nlm.imp$(DL) >> $@
+	@echo $(DL)import @$(AP_HOME)/src/os/netware/apachecore.imp$(DL) >> $@
+	@echo $(DL)module clib$(DL) >> $@
+else
+ifeq ($(LD),nlmconv)
+	@echo $(DL)flag_on 64$(DL) >> $@
+else
+	@echo $(DL)autounload$(DL) >> $@
+endif
+	@echo $(DL)pseudopreemption$(DL) >> $@
+	@echo $(DL)start _LibCPrelude$(DL) >> $@
+	@echo $(DL)exit _LibCPostlude$(DL) >> $@
+	@echo $(DL)check _LibCCheckUnload$(DL) >> $@
+	@echo $(DL)import @$(NDK_ROOT)/libc/imports/libc.imp$(DL) >> $@
+	@echo $(DL)import @$(NDK_ROOT)/libc/imports/netware.imp$(DL) >> $@
+#	@echo $(DL)import @$(NDK_ROOT)/libc/imports/ws2nlm.imp$(DL) >> $@
+	@echo $(DL)import @$(AP_HOME)/src/os/netware/apachecore.imp$(DL) >> $@
+	@echo $(DL)module libc$(DL) >> $@
+endif
+ifdef MODULES
+	@echo $(DL)module $(MODULES)$(DL) >> $@
+endif
+ifdef EXPORTS
+	@echo $(DL)export $(EXPORTS)$(DL) >> $@
+endif
+ifdef IMPORTS
+	@echo $(DL)import $(IMPORTS)$(DL) >> $@
+endif
+ifeq ($(LD),nlmconv)
+	@echo $(DL)input $(OBJS)$(DL) >> $@
+	@echo $(DL)input $(PRELUDE)$(DL) >> $@
+	@echo $(DL)output $(TARGET).nlm$(DL) >> $@
+endif
+

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/apache-1.3/Makefile.tmpl
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/apache-1.3/Makefile.tmpl	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/apache-1.3/Makefile.tmpl	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,38 @@
+##
+## Apache 1.3 Makefile template for mod_jk
+##
+LIB=libjk.$(LIBEXT)
+JK_INCLUDES=$(INCLUDES) -I./include
+
+OBJS=mod_jk.o
+OBJS_LIB=mod_jk.a
+
+SHLIB_OBJS=mod_jk.so-o
+SHLIB_OBJS_LIB=mod_jk.a
+
+all: ${LIB}
+
+#   build the static library by merging the object files
+libjk.a: $(OBJS) $(OBJS_LIB)
+	cp $(OBJS_LIB) $@
+	ar r $@ $(OBJS)
+	${RANLIB} $@
+#   build the shared object library by linking the object files
+libjk.so: $(SHLIB_OBJS) $(SHLIB_OBJS_LIB)
+	rm -f $@
+	$(LD_SHLIB) $(LDFLAGS_SHLIB) -o $@ $(SHLIB_OBJS) $(SHLIB_OBJS_LIB) $(LIBS)
+
+.SUFFIXES: .o .so-o
+.c.o:
+	$(CC) -c $(JK_INCLUDES) $(CFLAGS) $(CPPFLAGS) $(SPACER) $<
+.c.so-o:
+	$(CC) -c $(JK_INCLUDES) $(CFLAGS) $(CFLAGS_SHLIB) $(CPPFLAGS) $(SPACER) $< && mv $*.o $*.so-o
+
+clean:
+	-rm -f $(OBJS) $(SHLIB_OBJS) $(LIB)
+
+distclean: clean
+	-rm -f Makefile
+ 
+depend:
+	echo "No depend"

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/apache-1.3/Makefile.vc
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/apache-1.3/Makefile.vc	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/apache-1.3/Makefile.vc	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,276 @@
+# Microsoft Developer Studio Generated NMAKE File, Based on mod_jk.dsp
+!IF "$(CFG)" == ""
+CFG=mod_jk - Win32 Release
+!MESSAGE No configuration specified. Defaulting to mod_jk - Win32 Release.
+!ENDIF 
+
+!IF "$(CFG)" != "mod_jk - Win32 Release"
+!MESSAGE Invalid configuration "$(CFG)" specified.
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE 
+!MESSAGE NMAKE /f "Makefile.vc" CFG="mod_jk - Win32 Release"
+!MESSAGE 
+!MESSAGE Possible choices for configuration are:
+!MESSAGE 
+!MESSAGE "mod_jk - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE 
+!ERROR An invalid configuration is specified.
+!ENDIF 
+
+!IF "$(OS)" == "Windows_NT"
+NULL=
+!ELSE 
+NULL=nul
+!ENDIF 
+
+CPP=cl.exe
+MTL=midl.exe
+RSC=rc.exe
+OUTDIR=.\Release
+INTDIR=.\Release
+# Begin Custom Macros
+OutDir=.\Release
+# End Custom Macros
+
+ALL : "$(OUTDIR)\mod_jk.so"
+
+
+CLEAN :
+	- at erase "$(INTDIR)\jk_ajp12_worker.obj"
+	- at erase "$(INTDIR)\jk_ajp13.obj"
+	- at erase "$(INTDIR)\jk_ajp13_worker.obj"
+	- at erase "$(INTDIR)\jk_ajp14.obj"
+	- at erase "$(INTDIR)\jk_ajp14_worker.obj"
+	- at erase "$(INTDIR)\jk_ajp_common.obj"
+	- at erase "$(INTDIR)\jk_connect.obj"
+	- at erase "$(INTDIR)\jk_context.obj"
+	- at erase "$(INTDIR)\jk_jni_worker.obj"
+	- at erase "$(INTDIR)\jk_lb_worker.obj"
+	- at erase "$(INTDIR)\jk_map.obj"
+	- at erase "$(INTDIR)\jk_md5.obj"
+	- at erase "$(INTDIR)\jk_msg_buff.obj"
+	- at erase "$(INTDIR)\jk_pool.obj"
+	- at erase "$(INTDIR)\jk_shm.obj"
+	- at erase "$(INTDIR)\jk_sockbuf.obj"
+	- at erase "$(INTDIR)\jk_status.obj"
+	- at erase "$(INTDIR)\jk_uri_worker_map.obj"
+	- at erase "$(INTDIR)\jk_util.obj"
+	- at erase "$(INTDIR)\jk_worker.obj"
+	- at erase "$(INTDIR)\mod_jk.obj"
+	- at erase "$(INTDIR)\mod_jk_src.idb"
+	- at erase "$(INTDIR)\mod_jk_src.pdb"
+	- at erase "$(OUTDIR)\mod_jk.exp"
+	- at erase "$(OUTDIR)\mod_jk.lib"
+	- at erase "$(OUTDIR)\mod_jk.pdb"
+	- at erase "$(OUTDIR)\mod_jk.so"
+
+"$(OUTDIR)" :
+    if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+BSC32=bscmake.exe
+BSC32_FLAGS=/nologo /o"$(OUTDIR)\mod_jk.bsc" 
+BSC32_SBRS= \
+	
+LINK32=link.exe
+LINK32_FLAGS=ApacheCore.lib kernel32.lib user32.lib advapi32.lib ws2_32.lib mswsock.lib /nologo /base:"0x6A6B0000" /subsystem:windows /dll /incremental:no /pdb:"$(OUTDIR)\mod_jk.pdb" /debug /machine:I386 /out:"$(OUTDIR)\mod_jk.so" /implib:"$(OUTDIR)\mod_jk.lib" /libpath:"$(APACHE1_HOME)\lib" /libpath:"$(APACHE1_HOME)\libexec" /opt:ref 
+LINK32_OBJS= \
+	"$(INTDIR)\jk_ajp12_worker.obj" \
+	"$(INTDIR)\jk_ajp13.obj" \
+	"$(INTDIR)\jk_ajp13_worker.obj" \
+	"$(INTDIR)\jk_ajp14.obj" \
+	"$(INTDIR)\jk_ajp14_worker.obj" \
+	"$(INTDIR)\jk_ajp_common.obj" \
+	"$(INTDIR)\jk_connect.obj" \
+	"$(INTDIR)\jk_context.obj" \
+	"$(INTDIR)\jk_jni_worker.obj" \
+	"$(INTDIR)\jk_lb_worker.obj" \
+	"$(INTDIR)\jk_map.obj" \
+	"$(INTDIR)\jk_md5.obj" \
+	"$(INTDIR)\jk_msg_buff.obj" \
+	"$(INTDIR)\jk_pool.obj" \
+	"$(INTDIR)\jk_shm.obj" \
+	"$(INTDIR)\jk_sockbuf.obj" \
+	"$(INTDIR)\jk_status.obj" \
+	"$(INTDIR)\jk_uri_worker_map.obj" \
+	"$(INTDIR)\jk_util.obj" \
+	"$(INTDIR)\jk_worker.obj" \
+	"$(INTDIR)\mod_jk.obj"
+
+"$(OUTDIR)\mod_jk.so" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+    $(LINK32) @<<
+  $(LINK32_FLAGS) $(LINK32_OBJS)
+<<
+
+CPP_PROJ=/nologo /MD /W3 /Zi /O2 /I "..\common" /I "$(APACHE1_HOME)\include" /I "$(JAVA_HOME)\include" /I "$(JAVA_HOME)\include\win32" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "MOD_JK_EXPORTS" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\mod_jk_src" /FD /c 
+
+.c{$(INTDIR)}.obj::
+   $(CPP) @<<
+   $(CPP_PROJ) $< 
+<<
+
+.cpp{$(INTDIR)}.obj::
+   $(CPP) @<<
+   $(CPP_PROJ) $< 
+<<
+
+.cxx{$(INTDIR)}.obj::
+   $(CPP) @<<
+   $(CPP_PROJ) $< 
+<<
+
+.c{$(INTDIR)}.sbr::
+   $(CPP) @<<
+   $(CPP_PROJ) $< 
+<<
+
+.cpp{$(INTDIR)}.sbr::
+   $(CPP) @<<
+   $(CPP_PROJ) $< 
+<<
+
+.cxx{$(INTDIR)}.sbr::
+   $(CPP) @<<
+   $(CPP_PROJ) $< 
+<<
+
+MTL_PROJ=/nologo /D "NDEBUG" /mktyplib203 /win32 
+
+!IF "$(NO_EXTERNAL_DEPS)" != "1"
+!IF EXISTS("mod_jk.dep")
+!INCLUDE "mod_jk.dep"
+!ELSE 
+!MESSAGE Warning: cannot find "mod_jk.dep"
+!ENDIF 
+!ENDIF 
+
+
+!IF "$(CFG)" == "mod_jk - Win32 Release"
+SOURCE=..\common\jk_ajp12_worker.c
+
+"$(INTDIR)\jk_ajp12_worker.obj" : $(SOURCE) "$(INTDIR)"
+	$(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=..\common\jk_ajp13.c
+
+"$(INTDIR)\jk_ajp13.obj" : $(SOURCE) "$(INTDIR)"
+	$(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=..\common\jk_ajp13_worker.c
+
+"$(INTDIR)\jk_ajp13_worker.obj" : $(SOURCE) "$(INTDIR)"
+	$(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=..\common\jk_ajp14.c
+
+"$(INTDIR)\jk_ajp14.obj" : $(SOURCE) "$(INTDIR)"
+	$(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=..\common\jk_ajp14_worker.c
+
+"$(INTDIR)\jk_ajp14_worker.obj" : $(SOURCE) "$(INTDIR)"
+	$(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=..\common\jk_ajp_common.c
+
+"$(INTDIR)\jk_ajp_common.obj" : $(SOURCE) "$(INTDIR)"
+	$(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=..\common\jk_connect.c
+
+"$(INTDIR)\jk_connect.obj" : $(SOURCE) "$(INTDIR)"
+	$(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=..\common\jk_context.c
+
+"$(INTDIR)\jk_context.obj" : $(SOURCE) "$(INTDIR)"
+	$(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=..\common\jk_jni_worker.c
+
+"$(INTDIR)\jk_jni_worker.obj" : $(SOURCE) "$(INTDIR)"
+	$(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=..\common\jk_lb_worker.c
+
+"$(INTDIR)\jk_lb_worker.obj" : $(SOURCE) "$(INTDIR)"
+	$(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=..\common\jk_map.c
+
+"$(INTDIR)\jk_map.obj" : $(SOURCE) "$(INTDIR)"
+	$(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=..\common\jk_md5.c
+
+"$(INTDIR)\jk_md5.obj" : $(SOURCE) "$(INTDIR)"
+	$(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=..\common\jk_msg_buff.c
+
+"$(INTDIR)\jk_msg_buff.obj" : $(SOURCE) "$(INTDIR)"
+	$(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=..\common\jk_pool.c
+
+"$(INTDIR)\jk_pool.obj" : $(SOURCE) "$(INTDIR)"
+	$(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=..\common\jk_shm.c
+
+"$(INTDIR)\jk_shm.obj" : $(SOURCE) "$(INTDIR)"
+	$(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=..\common\jk_sockbuf.c
+
+"$(INTDIR)\jk_sockbuf.obj" : $(SOURCE) "$(INTDIR)"
+	$(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=..\common\jk_status.c
+
+"$(INTDIR)\jk_status.obj" : $(SOURCE) "$(INTDIR)"
+	$(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=..\common\jk_uri_worker_map.c
+
+"$(INTDIR)\jk_uri_worker_map.obj" : $(SOURCE) "$(INTDIR)"
+	$(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=..\common\jk_util.c
+
+"$(INTDIR)\jk_util.obj" : $(SOURCE) "$(INTDIR)"
+	$(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=..\common\jk_worker.c
+
+"$(INTDIR)\jk_worker.obj" : $(SOURCE) "$(INTDIR)"
+	$(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\mod_jk.c
+
+"$(INTDIR)\mod_jk.obj" : $(SOURCE) "$(INTDIR)"
+
+
+
+!ENDIF 
+

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/apache-1.3/NWGNUmakefile
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/apache-1.3/NWGNUmakefile	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/apache-1.3/NWGNUmakefile	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,27 @@
+#
+# Declare the sub-directories to be built here
+#
+
+SUBDIRS = \
+		$(EOLIST) 
+
+#
+# Get the 'head' of the build environment.  This includes default targets and
+# paths to tools
+#
+
+include $(AP_WORK)\NWGNUhead.inc
+
+#
+# build this level's files
+
+ifeq "$(wildcard NWGNUmakefile.mak)" "NWGNUmakefile.mak" 
+include NWGNUmakefile.mak
+endif
+
+#
+# You can use this target if all that is needed is to copy files to the
+# installation area
+#
+install :: nlms FORCE
+

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/apache-1.3/NWGNUmakefile.mak
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/apache-1.3/NWGNUmakefile.mak	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/apache-1.3/NWGNUmakefile.mak	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,287 @@
+#
+# Makefile for mod_jk (NetWare version - gnu make)
+# created by Guenter Knauf <fuankg at apache.org>
+#
+
+#
+# Make sure all needed macro's are defined
+#
+
+# Edit the path below to point to the base of your NetWare Java SDK.
+ifndef JAVA_HOME
+JAVA_HOME = c:/projects/sdks/java-nw
+endif
+
+JKCOMMON = ../common
+
+#
+# Get the 'head' of the build environment if necessary.  This includes default
+# targets and paths to tools
+#
+
+ifndef EnvironmentDefined
+include $(AP_WORK)\NWGNUhead.inc
+endif
+
+#
+# These directories will be at the beginning of the include list, followed by
+# INCDIRS
+#
+XINCDIRS	+= \
+			$(JKCOMMON) \
+			$(JAVA_HOME)/include \
+			$(JAVA_HOME)/include/netware \
+			$(SRC)\include \
+			$(NWOS) \
+			$(EOLIST)
+
+#
+# These flags will come after CFLAGS
+#
+XCFLAGS		+= \
+			$(EOLIST)
+
+#
+# These defines will come after DEFINES
+#
+XDEFINES	+= \
+			$(EOLIST)
+
+#
+# These flags will be added to the link.opt file
+#
+XLFLAGS		+= \
+			$(EOLIST)
+
+#
+# These values will be appended to the correct variables based on the value of
+# RELEASE
+#
+ifeq "$(RELEASE)" "debug"
+XINCDIRS	+= \
+			$(EOLIST)
+
+XCFLAGS		+= \
+			$(EOLIST)
+
+XDEFINES	+= \
+			$(EOLIST)
+
+XLFLAGS		+= \
+			$(EOLIST)
+endif
+
+ifeq "$(RELEASE)" "noopt"
+XINCDIRS	+= \
+			$(EOLIST)
+
+XCFLAGS		+= \
+			$(EOLIST)
+
+XDEFINES	+= \
+			$(EOLIST)
+
+XLFLAGS		+= \
+			$(EOLIST)
+endif
+
+ifeq "$(RELEASE)" "release"
+XINCDIRS	+= \
+			$(EOLIST)
+
+XCFLAGS		+= \
+			$(EOLIST)
+
+XDEFINES	+= \
+			$(EOLIST)
+
+XLFLAGS		+= \
+			$(EOLIST)
+endif
+
+#
+# These are used by the link target if an NLM is being generated
+# This is used by the link 'name' directive to name the nlm.  If left blank
+# TARGET_nlm (see below) will be used.
+#
+NLM_NAME	= mod_jk
+
+#
+# This is used by the link '-desc ' directive. 
+# If left blank, NLM_NAME will be used.
+#
+NLM_DESCRIPTION	= Apache $(AP_VERSION_STR) plugin for Tomcat $(JK_VERSION_STR)
+
+#
+# This is used by the '-threadname' directive.  If left blank,
+# NLM_NAME Thread will be used.
+#
+NLM_THREAD_NAME	= JK Module
+
+#
+# If this is specified, it will override VERSION value in 
+# $(AP_WORK)\NWGNUenvironment.inc
+#
+NLM_VERSION	= $(JK_VERSION)
+
+#
+# If this is specified, it will override the default of 64K
+#
+NLM_STACK_SIZE	= 49152
+
+#
+# If this is specified it will be used by the link '-entry' directive
+#
+NLM_ENTRY_SYM	= _lib_start
+#NLM_ENTRY_SYM	= _lib_start_ws
+
+#
+# If this is specified it will be used by the link '-exit' directive
+#
+NLM_EXIT_SYM	= _lib_stop
+#NLM_EXIT_SYM	= _lib_stop_ws
+
+#
+# If this is specified it will be used by the link '-flags' directive
+#
+NLM_FLAGS	=
+
+#
+# Declare all target files (you must add your files here)
+#
+
+#
+# If there is an NLM target, put it here
+#
+TARGET_nlm = \
+	$(OBJDIR)/$(NLM_NAME).nlm \
+	$(EOLIST)
+
+#
+# If there is an LIB target, put it here
+#
+TARGET_lib = \
+	$(EOLIST)
+
+#
+# These are the OBJ files needed to create the NLM target above.
+# Paths must all use the '/' character
+#
+FILES_nlm_objs = \
+	$(OBJDIR)/jk_nwmain.o \
+	$(OBJDIR)/jk_ajp12_worker.o \
+	$(OBJDIR)/jk_ajp13.o \
+	$(OBJDIR)/jk_ajp13_worker.o \
+	$(OBJDIR)/jk_ajp14.o \
+	$(OBJDIR)/jk_ajp14_worker.o \
+	$(OBJDIR)/jk_ajp_common.o \
+	$(OBJDIR)/jk_connect.o \
+	$(OBJDIR)/jk_context.o \
+	$(OBJDIR)/jk_jni_worker.o \
+	$(OBJDIR)/jk_lb_worker.o \
+	$(OBJDIR)/jk_map.o \
+	$(OBJDIR)/jk_md5.o \
+	$(OBJDIR)/jk_msg_buff.o \
+	$(OBJDIR)/jk_pool.o \
+	$(OBJDIR)/jk_shm.o \
+	$(OBJDIR)/jk_sockbuf.o \
+	$(OBJDIR)/jk_status.o \
+	$(OBJDIR)/jk_uri_worker_map.o \
+	$(OBJDIR)/jk_util.o \
+	$(OBJDIR)/jk_worker.o \
+	$(OBJDIR)/$(NLM_NAME).o \
+	$(EOLIST)
+
+#
+# These are the LIB files needed to create the NLM target above.
+# These will be added as a library command in the link.opt file.
+#
+FILES_nlm_libs = \
+	$(NWOS)/$(OBJDIR)/libpre.o \
+	$(EOLIST)
+
+#	$(NWOS)/$(OBJDIR)/libprews.o
+
+#
+# These are the modules that the above NLM target depends on to load.
+# These will be added as a module command in the link.opt file.
+#
+FILES_nlm_modules = \
+	$(EOLIST)
+
+#
+# If the nlm has a msg file, put it's path here
+#
+FILE_nlm_msg =
+ 
+#
+# If the nlm has a hlp file put it's path here
+#
+FILE_nlm_hlp =
+
+#
+# If this is specified, it will override $(NWOS)\copyright.txt.
+#
+#FILE_nlm_copyright = 'Copyright (c) 2000-2005 The Apache Software Foundation. All rights reserved.'
+FILE_nlm_copyright =
+
+
+#
+# Any additional imports go here
+#
+FILES_nlm_Ximports = \
+	@ApacheCore.imp \
+	@threads.imp \
+	@clib.imp \
+	@nlmlib.imp \
+	@socklib.imp \
+	$(EOLIST)
+ 
+#   
+# Any symbols exported to here
+#
+FILES_nlm_exports = \
+	jk_module \
+	$(EOLIST)
+
+#   
+# These are the OBJ files needed to create the LIB target above.
+# Paths must all use the '/' character
+#
+FILES_lib_objs = \
+	$(EOLIST)
+
+#
+# implement targets and dependancies (leave this section alone)
+#
+
+libs :: $(OBJDIR) $(TARGET_lib)
+
+nlms :: libs $(TARGET_nlm)
+
+#
+# Updated this target to create necessary directories and copy files to the 
+# correct place.  (See $(AP_WORK)\NWGNUhead.inc for examples)
+#
+install :: nlms FORCE
+	copy $(OBJDIR)\$(NLM_NAME).nlm $(INSTALL)\Apache\modules
+
+#
+# Any specialized rules here
+#
+vpath %.c . $(JKCOMMON)
+
+$(OBJDIR)/version.inc: $(JKCOMMON)/jk_version.h $(SRC)/include/httpd.h $(OBJDIR)
+	@echo Creating $@
+	@awk -f ../../support/get_ver.awk $<  $(SRC)/include/httpd.h > $@
+
+# Include the version info retrieved from jk_version.h
+-include $(OBJDIR)/version.inc
+
+#
+# Include the 'tail' makefile that has targets that depend on variables defined
+# in this makefile
+#
+
+include $(AP_WORK)/NWGNUtail.inc
+

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/apache-1.3/libjk.module
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/apache-1.3/libjk.module	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/apache-1.3/libjk.module	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,5 @@
+Name: jk_module
+ConfigStart
+	LIBS="-Lmodules/jk -L../modules/jk -L../../modules/jk -ljk $LIBS"
+	RULE_HIDE=yes
+ConfigEnd

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/apache-1.3/mod_jk.c
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/apache-1.3/mod_jk.c	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/apache-1.3/mod_jk.c	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,2484 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.
+ */
+
+/***************************************************************************
+ * Description: Apache 1.3 plugin for Tomcat                                *
+ *              See ../common/jk_service.h for general mod_jk info         *
+ * Author:      Gal Shachor <shachor at il.ibm.com>                           *
+ *              Dan Milstein <danmil at shore.net>                            *
+ *              Henri Gomez <hgomez at apache.org>                            *
+ * Version:     $Revision: 440636 $                                          *
+ ***************************************************************************/
+
+/*
+ * mod_jk: keeps all servlet related ramblings together.
+ */
+
+/* #include "ap_config.h" */
+#include "httpd.h"
+#include "http_config.h"
+#include "http_request.h"
+#include "http_core.h"
+#include "http_protocol.h"
+#include "http_main.h"
+#include "http_log.h"
+#include "util_script.h"
+#include "util_date.h"
+#include "http_conf_globals.h"
+
+/*
+ * jk_ include files
+ */
+#ifdef NETWARE
+#define _SYS_TYPES_H_
+#define _NETDB_H_INCLUDED
+#define _IN_
+#define _INET_
+#define _SYS_TIMEVAL_H_
+#define _SYS_SOCKET_H_
+#endif
+#include "jk_global.h"
+#include "jk_util.h"
+#include "jk_map.h"
+#include "jk_pool.h"
+#include "jk_service.h"
+#include "jk_worker.h"
+#include "jk_uri_worker_map.h"
+#include "jk_ajp13.h"
+#include "jk_shm.h"
+
+#define JK_NOTE_WORKER_NAME         ("JK_WORKER_NAME")
+#define JK_NOTE_WORKER_TYPE         ("JK_WORKER_TYPE")
+#define JK_NOTE_REQUEST_DURATION    ("JK_REQUEST_DURATION")
+#define JK_NOTE_WORKER_ROUTE        ("JK_WORKER_ROUTE")
+#define JK_HANDLER          ("jakarta-servlet")
+#define JK_MAGIC_TYPE       ("application/x-jakarta-servlet")
+#define NULL_FOR_EMPTY(x)   ((x && !strlen(x)) ? NULL : x)
+#define STRNULL_FOR_NULL(x) ((x) ? (x) : "(null)")
+
+/*
+ * If you are not using SSL, comment out the following line. It will make
+ * apache run faster.
+ *
+ * Personally, I (DM), think this may be a lie.
+ */
+#define ADD_SSL_INFO
+
+module MODULE_VAR_EXPORT jk_module;
+#ifdef WIN32
+extern __declspec(dllimport) module dir_module;
+#else
+extern module dir_module;
+#endif
+
+static int xfer_flags = (O_WRONLY | O_APPEND | O_CREAT);
+#if defined(OS2) || defined(WIN32) || defined(NETWARE)
+/* OS/2 dosen't support users and groups */
+static mode_t xfer_mode = (S_IREAD | S_IWRITE);
+#else
+static mode_t xfer_mode = (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+#endif
+
+/*
+ * Configuration object for the mod_jk module.
+ */
+typedef struct
+{
+
+    /*
+     * Log stuff
+     */
+    char *log_file;
+    int log_fd;
+    int log_level;
+    jk_logger_t *log;
+
+    /*
+     * Worker stuff
+     */
+    jk_map_t *worker_properties;
+    char *worker_file;
+    char *mount_file;
+    jk_map_t *uri_to_context;
+
+    int mountcopy;
+    char *secret_key;
+    jk_map_t *automount;
+
+    jk_uri_worker_map_t *uw_map;
+
+    /*
+     * Automatic context path apache alias
+     */
+    char *alias_dir;
+
+    /*
+     * Request Logging
+     */
+
+    char *format_string;
+    array_header *format;
+
+    /*
+     * SSL Support
+     */
+    int ssl_enable;
+    char *https_indicator;
+    char *certs_indicator;
+    char *cipher_indicator;
+    char *session_indicator;
+    char *key_size_indicator;
+
+    /*
+     * Jk Options
+     */
+    int options;
+
+    /*
+     * Environment variables support
+     */
+    int envvars_in_use;
+    table *envvars;
+
+    server_rec *s;
+} jk_server_conf_t;
+
+
+/*
+ * The "private", or subclass portion of the web server service class for
+ * Apache 1.3.  An instance of this class is created for each request
+ * handled.  See jk_service.h for details about the ws_service object in
+ * general.
+ */
+struct apache_private_data
+{
+    /*
+     * For memory management for this request.  Aliased to be identical to
+     * the pool in the superclass (jk_ws_service).
+     */
+    jk_pool_t p;
+
+    /* True iff response headers have been returned to client */
+    int response_started;
+
+    /* True iff request body data has been read from Apache */
+    int read_body_started;
+
+    /* Apache request structure */
+    request_rec *r;
+};
+typedef struct apache_private_data apache_private_data_t;
+
+typedef struct dir_config_struct
+{
+    array_header *index_names;
+} dir_config_rec;
+
+static jk_logger_t *main_log = NULL;
+static jk_worker_env_t worker_env;
+static char *jk_shm_file = NULL;
+static size_t jk_shm_size = JK_SHM_DEF_SIZE;
+
+static int JK_METHOD ws_start_response(jk_ws_service_t *s,
+                                       int status,
+                                       const char *reason,
+                                       const char *const *header_names,
+                                       const char *const *header_values,
+                                       unsigned num_of_headers);
+
+static int JK_METHOD ws_read(jk_ws_service_t *s,
+                             void *b, unsigned l, unsigned *a);
+
+static int JK_METHOD ws_write(jk_ws_service_t *s, const void *b, unsigned l);
+
+static void JK_METHOD ws_add_log_items(jk_ws_service_t *s,
+                                       const char *const *log_names,
+                                       const char *const *log_values,
+                                       unsigned num_of_log_items);
+
+/* srevilak - new function prototypes */
+static void jk_server_cleanup(void *data);
+static void jk_generic_cleanup(server_rec * s);
+
+
+
+/* ====================================================================== */
+/* JK Service step callbacks                                              */
+/* ====================================================================== */
+
+
+/*
+ * Send the HTTP response headers back to the browser.
+ *
+ * Think of this function as a method of the apache1.3-specific subclass of
+ * the jk_ws_service class.  Think of the *s param as a "this" or "self"
+ * pointer.
+ */
+static int JK_METHOD ws_start_response(jk_ws_service_t *s,
+                                       int status,
+                                       const char *reason,
+                                       const char *const *header_names,
+                                       const char *const *header_values,
+                                       unsigned num_of_headers)
+{
+    if (s && s->ws_private) {
+        unsigned h;
+
+        /* Obtain a subclass-specific "this" pointer */
+        apache_private_data_t *p = s->ws_private;
+        request_rec *r = p->r;
+
+        if (!reason) {
+            reason = "";
+        }
+        r->status = status;
+        r->status_line = ap_psprintf(r->pool, "%d %s", status, reason);
+
+        for (h = 0; h < num_of_headers; h++) {
+            if (!strcasecmp(header_names[h], "Content-type")) {
+                char *tmp = ap_pstrdup(r->pool, header_values[h]);
+                ap_content_type_tolower(tmp);
+                r->content_type = tmp;
+            }
+            else if (!strcasecmp(header_names[h], "Location")) {
+                ap_table_set(r->headers_out, header_names[h],
+                             header_values[h]);
+            }
+            else if (!strcasecmp(header_names[h], "Content-Length")) {
+                ap_table_set(r->headers_out, header_names[h],
+                             header_values[h]);
+            }
+            else if (!strcasecmp(header_names[h], "Transfer-Encoding")) {
+                ap_table_set(r->headers_out, header_names[h],
+                             header_values[h]);
+            }
+            else if (!strcasecmp(header_names[h], "Last-Modified")) {
+                /*
+                 * If the script gave us a Last-Modified header, we can't just
+                 * pass it on blindly because of restrictions on future values.
+                 */
+                ap_update_mtime(r, ap_parseHTTPdate(header_values[h]));
+                ap_set_last_modified(r);
+            }
+            else {
+                ap_table_add(r->headers_out, header_names[h],
+                             header_values[h]);
+            }
+        }
+
+        ap_send_http_header(r);
+        p->response_started = JK_TRUE;
+
+        return JK_TRUE;
+    }
+    return JK_FALSE;
+}
+
+/*
+ * Read a chunk of the request body into a buffer.  Attempt to read len
+ * bytes into the buffer.  Write the number of bytes actually read into
+ * actually_read.
+ *
+ * Think of this function as a method of the apache1.3-specific subclass of
+ * the jk_ws_service class.  Think of the *s param as a "this" or "self"
+ * pointer.
+ */
+static int JK_METHOD ws_read(jk_ws_service_t *s,
+                             void *b, unsigned len, unsigned *actually_read)
+{
+    if (s && s->ws_private && b && actually_read) {
+        apache_private_data_t *p = s->ws_private;
+        if (!p->read_body_started) {
+            if (ap_should_client_block(p->r)) {
+                p->read_body_started = JK_TRUE;
+            }
+        }
+
+        if (p->read_body_started) {
+            long rv;
+            if ((rv = ap_get_client_block(p->r, b, len)) < 0) {
+                *actually_read = 0;
+            }
+            else {
+                *actually_read = (unsigned)rv;
+            }
+            /* reset timeout after successful read */
+            ap_reset_timeout(p->r);
+            return JK_TRUE;
+        }
+    }
+    return JK_FALSE;
+}
+
+static void JK_METHOD ws_flush(jk_ws_service_t *s)
+{
+    if (s && s->ws_private) {
+        apache_private_data_t *p = s->ws_private;
+        BUFF *bf = p->r->connection->client;
+        ap_bflush(bf);
+    }
+}
+
+/*
+ * Write a chunk of response data back to the browser.  If the headers
+ * haven't yet been sent over, send over default header values (Status =
+ * 200, basically).
+ *
+ * Write len bytes from buffer b.
+ *
+ * Think of this function as a method of the apache1.3-specific subclass of
+ * the jk_ws_service class.  Think of the *s param as a "this" or "self"
+ * pointer.
+ */
+static int JK_METHOD ws_write(jk_ws_service_t *s, const void *b, unsigned len)
+{
+    if (s && s->ws_private && b) {
+        apache_private_data_t *p = s->ws_private;
+
+        if (len) {
+            char *buf = (char *)b;
+            int w = (int)len;
+            int r = 0;
+
+            if (!p->response_started) {
+                if (main_log)
+                    jk_log(main_log, JK_LOG_INFO,
+                           "Write without start, starting with defaults");
+                if (!s->start_response(s, 200, NULL, NULL, NULL, 0)) {
+                    return JK_FALSE;
+                }
+            }
+
+            if (p->r->header_only) {
+                BUFF *bf = p->r->connection->client;
+                ap_bflush(bf);
+                return JK_TRUE;
+            }
+
+            while (len && !p->r->connection->aborted) {
+                w = ap_bwrite(p->r->connection->client, &buf[r], len);
+                if (w > 0) {
+                    /* reset timeout after successful write */
+                    ap_reset_timeout(p->r);
+                    r += w;
+                    len -= w;
+                }
+                else if (w < 0) {
+                    /* Error writing data -- abort */
+                    if (!p->r->connection->aborted) {
+                        ap_bsetflag(p->r->connection->client, B_EOUT, 1);
+                        p->r->connection->aborted = 1;
+                    }
+                    return JK_FALSE;
+                }
+
+            }
+            if (p->r->connection->aborted)
+                return JK_FALSE;
+        }
+
+        return JK_TRUE;
+    }
+    return JK_FALSE;
+}
+
+static void JK_METHOD ws_add_log_items(jk_ws_service_t *s,
+                                       const char *const *log_names,
+                                       const char *const *log_values,
+                                       unsigned num_of_log_items)
+{
+    unsigned h;
+    apache_private_data_t *p = s->ws_private;
+    request_rec *r = p->r;
+
+    for (h = 0; h < num_of_log_items; h++) {
+        if (log_names[h] && log_values[h]) {
+            ap_table_setn(r->notes, log_names[h], log_values[h]);
+        }
+    }
+}
+
+/* ====================================================================== */
+/* Utility functions                                                      */
+/* ====================================================================== */
+
+/* Log something to JK log file then exit */
+static void jk_error_exit(const char *file,
+                          int line,
+                          int level,
+                          const server_rec * s,
+                          ap_pool * p, const char *fmt, ...)
+{
+    va_list ap;
+    char *res;
+
+    va_start(ap, fmt);
+    res = ap_pvsprintf(p, fmt, ap);
+    va_end(ap);
+
+    ap_log_error(file, line, level, s, res);
+
+    /* Exit process */
+    exit(1);
+}
+
+/* Return the content length associated with an Apache request structure */
+static int get_content_length(request_rec * r)
+{
+    if (r->clength > 0) {
+        return r->clength;
+    }
+    else {
+        char *lenp = (char *)ap_table_get(r->headers_in, "Content-Length");
+
+        if (lenp) {
+            int rc = atoi(lenp);
+            if (rc > 0) {
+                return rc;
+            }
+        }
+    }
+
+    return 0;
+}
+
+/*
+ * Set up an instance of a ws_service object for a single request.  This
+ * particular instance will be of the Apache 1.3-specific subclass.  Copies
+ * all of the important request information from the Apache request object
+ * into the jk_ws_service_t object.
+ *
+ * Params
+ *
+ * private_data: The subclass-specific data structure, already initialized
+ * (with a pointer to the Apache request_rec structure, among other things)
+ *
+ * s: The base class object.
+ *
+ * conf: Configuration information
+ *
+ * Called from jk_handler().  See jk_service.h for explanations of what most
+ * of these fields mean.
+ */
+static int init_ws_service(apache_private_data_t * private_data,
+                           jk_ws_service_t *s, jk_server_conf_t * conf)
+{
+    request_rec *r = private_data->r;
+    char *ssl_temp = NULL;
+    s->jvm_route = NULL;        /* Used for sticky session routing */
+
+    /* Copy in function pointers (which are really methods) */
+    s->start_response = ws_start_response;
+    s->read = ws_read;
+    s->write = ws_write;
+    s->flush = ws_flush;
+    s->add_log_items = ws_add_log_items;
+
+    /* Clear RECO status */
+    s->reco_status = RECO_NONE;
+
+    s->auth_type = NULL_FOR_EMPTY(r->connection->ap_auth_type);
+    s->remote_user = NULL_FOR_EMPTY(r->connection->user);
+
+    s->protocol = r->protocol;
+    s->remote_host =
+        (char *)ap_get_remote_host(r->connection, r->per_dir_config,
+                                   REMOTE_HOST);
+    s->remote_host = NULL_FOR_EMPTY(s->remote_host);
+
+    if (conf->options & JK_OPT_FWDLOCAL)
+        s->remote_addr = NULL_FOR_EMPTY(r->connection->local_ip);
+    else
+        s->remote_addr = NULL_FOR_EMPTY(r->connection->remote_ip);
+
+    if (conf->options & JK_OPT_FLUSHPACKETS)
+        s->flush_packets = 1;
+    else
+        s->flush_packets = 0;
+
+    if (conf->options & JK_OPT_DISABLEREUSE)
+        s->disable_reuse = 1;
+    else
+        s->disable_reuse = 0;
+
+    /* get server name */
+    /* s->server_name  = (char *)(r->hostname ? r->hostname : r->server->server_hostname); */
+    /* XXX : a la jk2 */
+    s->server_name = (char *)ap_get_server_name(r);
+
+    /* get the real port (otherwise redirect failed) */
+    /* s->server_port     = htons( r->connection->local_addr.sin_port ); */
+    /* XXX : a la jk2 */
+    s->server_port = ap_get_server_port(r);
+
+    s->server_software = (char *)ap_get_server_version();
+
+    s->method = (char *)r->method;
+    s->content_length = get_content_length(r);
+    s->is_chunked = r->read_chunked;
+    s->no_more_chunks = 0;
+    s->query_string = r->args;
+
+    /* Dump all connection param so we can trace what's going to
+     * the remote tomcat
+     */
+    if (JK_IS_DEBUG_LEVEL(conf->log)) {
+        jk_log(conf->log, JK_LOG_DEBUG,
+               "Service protocol=%s method=%s host=%s addr=%s name=%s port=%d auth=%s user=%s laddr=%s raddr=%s",
+               STRNULL_FOR_NULL(s->protocol),
+               STRNULL_FOR_NULL(s->method),
+               STRNULL_FOR_NULL(s->remote_host),
+               STRNULL_FOR_NULL(s->remote_addr),
+               STRNULL_FOR_NULL(s->server_name),
+               s->server_port,
+               STRNULL_FOR_NULL(s->auth_type),
+               STRNULL_FOR_NULL(s->remote_user),
+               STRNULL_FOR_NULL(r->connection->local_ip),
+               STRNULL_FOR_NULL(r->connection->remote_ip));
+    }
+
+    /*
+     * The 2.2 servlet spec errata says the uri from
+     * HttpServletRequest.getRequestURI() should remain encoded.
+     * [http://java.sun.com/products/servlet/errata_042700.html]
+     *
+     * We use JkOptions to determine which method to be used
+     *
+     * ap_escape_uri is the latest recommanded but require
+     *               some java decoding (in TC 3.3 rc2)
+     *
+     * unparsed_uri is used for strict compliance with spec and
+     *              old Tomcat (3.2.3 for example)
+     *
+     * uri is use for compatibilty with mod_rewrite with old Tomcats
+     */
+
+    switch (conf->options & JK_OPT_FWDURIMASK) {
+
+    case JK_OPT_FWDURICOMPATUNPARSED:
+        s->req_uri = r->unparsed_uri;
+        if (s->req_uri != NULL) {
+            char *query_str = strchr(s->req_uri, '?');
+            if (query_str != NULL) {
+                *query_str = 0;
+            }
+        }
+
+        break;
+
+    case JK_OPT_FWDURICOMPAT:
+        s->req_uri = r->uri;
+        break;
+
+    case JK_OPT_FWDURIESCAPED:
+        s->req_uri = ap_escape_uri(r->pool, r->uri);
+        break;
+
+    default:
+        return JK_FALSE;
+    }
+
+    s->is_ssl = JK_FALSE;
+    s->ssl_cert = NULL;
+    s->ssl_cert_len = 0;
+    s->ssl_cipher = NULL;       /* required by Servlet 2.3 Api, allready in original ajp13 */
+    s->ssl_session = NULL;
+    s->ssl_key_size = -1;       /* required by Servlet 2.3 Api, added in jtc */
+
+    if (conf->ssl_enable || conf->envvars_in_use) {
+        ap_add_common_vars(r);
+
+        if (conf->ssl_enable) {
+            ssl_temp =
+                (char *)ap_table_get(r->subprocess_env,
+                                     conf->https_indicator);
+            if (ssl_temp && !strcasecmp(ssl_temp, "on")) {
+                s->is_ssl = JK_TRUE;
+                s->ssl_cert =
+                    (char *)ap_table_get(r->subprocess_env,
+                                         conf->certs_indicator);
+                if (s->ssl_cert) {
+                    s->ssl_cert_len = strlen(s->ssl_cert);
+                }
+                /* Servlet 2.3 API */
+                s->ssl_cipher =
+                    (char *)ap_table_get(r->subprocess_env,
+                                         conf->cipher_indicator);
+                s->ssl_session =
+                    (char *)ap_table_get(r->subprocess_env,
+                                         conf->session_indicator);
+
+                if (conf->options & JK_OPT_FWDKEYSIZE) {
+                    /* Servlet 2.3 API */
+                    ssl_temp =
+                        (char *)ap_table_get(r->subprocess_env,
+                                             conf->key_size_indicator);
+                    if (ssl_temp)
+                        s->ssl_key_size = atoi(ssl_temp);
+                }
+            }
+        }
+
+        if (conf->envvars_in_use) {
+            array_header *t = ap_table_elts(conf->envvars);
+            if (t && t->nelts) {
+                int i;
+                table_entry *elts = (table_entry *) t->elts;
+                s->attributes_names =
+                    ap_palloc(r->pool, sizeof(char *) * t->nelts);
+                s->attributes_values =
+                    ap_palloc(r->pool, sizeof(char *) * t->nelts);
+
+                for (i = 0; i < t->nelts; i++) {
+                    s->attributes_names[i] = elts[i].key;
+                    s->attributes_values[i] =
+                        (char *)ap_table_get(r->subprocess_env, elts[i].key);
+                    if (!s->attributes_values[i]) {
+                        s->attributes_values[i] = elts[i].val;
+                    }
+                }
+
+                s->num_attributes = t->nelts;
+            }
+        }
+    }
+
+    s->headers_names = NULL;
+    s->headers_values = NULL;
+    s->num_headers = 0;
+    if (r->headers_in && ap_table_elts(r->headers_in)) {
+        int need_content_length_header = (!s->is_chunked
+                                          && s->content_length ==
+                                          0) ? JK_TRUE : JK_FALSE;
+        array_header *t = ap_table_elts(r->headers_in);
+        if (t && t->nelts) {
+            int i;
+            table_entry *elts = (table_entry *) t->elts;
+            s->num_headers = t->nelts;
+            /* allocate an extra header slot in case we need to add a content-length header */
+            s->headers_names =
+                ap_palloc(r->pool, sizeof(char *) * (t->nelts + 1));
+            s->headers_values =
+                ap_palloc(r->pool, sizeof(char *) * (t->nelts + 1));
+            if (!s->headers_names || !s->headers_values)
+                return JK_FALSE;
+            for (i = 0; i < t->nelts; i++) {
+                char *hname = ap_pstrdup(r->pool, elts[i].key);
+                s->headers_values[i] = ap_pstrdup(r->pool, elts[i].val);
+                s->headers_names[i] = hname;
+                if (need_content_length_header &&
+                    !strcasecmp(s->headers_values[i], "content-length")) {
+                    need_content_length_header = JK_FALSE;
+                }
+            }
+            /* Add a content-length = 0 header if needed.
+             * Ajp13 assumes an absent content-length header means an unknown,
+             * but non-zero length body.
+             */
+            if (need_content_length_header) {
+                s->headers_names[s->num_headers] = "content-length";
+                s->headers_values[s->num_headers] = "0";
+                s->num_headers++;
+            }
+        }
+        /* Add a content-length = 0 header if needed. */
+        else if (need_content_length_header) {
+            s->headers_names = ap_palloc(r->pool, sizeof(char *));
+            s->headers_values = ap_palloc(r->pool, sizeof(char *));
+            if (!s->headers_names || !s->headers_values)
+                return JK_FALSE;
+            s->headers_names[0] = "content-length";
+            s->headers_values[0] = "0";
+            s->num_headers++;
+        }
+    }
+    s->uw_map = conf->uw_map;
+    return JK_TRUE;
+}
+
+/*
+ * The JK module command processors
+ *
+ * The below are all installed so that Apache calls them while it is
+ * processing its config files.  This allows configuration info to be
+ * copied into a jk_server_conf_t object, which is then used for request
+ * filtering/processing.
+ *
+ * See jk_cmds definition below for explanations of these options.
+ */
+
+/*
+ * JkMountCopy directive handling
+ *
+ * JkMountCopy On/Off
+ */
+
+static const char *jk_set_mountcopy(cmd_parms * cmd, void *dummy, int flag)
+{
+    server_rec *s = cmd->server;
+    jk_server_conf_t *conf =
+        (jk_server_conf_t *) ap_get_module_config(s->module_config,
+                                                  &jk_module);
+
+    /* Set up our value */
+    conf->mountcopy = flag ? JK_TRUE : JK_FALSE;
+
+    return NULL;
+}
+
+/*
+ * JkMount directive handling
+ *
+ * JkMount URI(context) worker
+ */
+
+static const char *jk_mount_context(cmd_parms * cmd,
+                                    void *dummy,
+                                    char *context,
+                                    char *worker)
+{
+    server_rec *s = cmd->server;
+    jk_server_conf_t *conf =
+        (jk_server_conf_t *) ap_get_module_config(s->module_config,
+                                                  &jk_module);
+    const char *c, *w;
+
+    if (worker != NULL && cmd->path == NULL ) {
+        c = context;
+        w = worker;
+    }
+    else if (worker == NULL && cmd->path != NULL) {
+        c = cmd->path;
+        w = context;
+    }
+    else {
+        if (worker == NULL)
+            return "JkMount needs a path when not defined in a location";
+        else
+            return "JkMount can not have a path when defined in a location";
+    }
+
+    if (c[0] != '/')
+        return "JkMount context should start with /";
+
+    /*
+     * Add the new worker to the alias map.
+     */
+    jk_map_put(conf->uri_to_context, c, w, NULL);
+    return NULL;
+}
+
+/*
+ * JkUnMount directive handling
+ *
+ * JkUnMount URI(context) worker
+ */
+
+static const char *jk_unmount_context(cmd_parms * cmd,
+                                      void *dummy,
+                                      const char *context,
+                                      const char *worker)
+{
+    server_rec *s = cmd->server;
+    jk_server_conf_t *conf =
+        (jk_server_conf_t *) ap_get_module_config(s->module_config,
+                                                  &jk_module);
+    char *uri;
+    const char *c, *w;
+
+    if (worker != NULL && cmd->path == NULL ) {
+        c = context;
+        w = worker;
+    }
+    else if (worker == NULL && cmd->path != NULL) {
+        c = cmd->path;
+        w = context;
+    }
+    else {
+        if (worker == NULL)
+            return "JkUnMount needs a path when not defined in a location";
+        else
+            return "JkUnMount can not have a path when defined in a location";
+    }
+    if (c[0] != '/')
+        return "JkUnMount context should start with /";
+    uri = ap_pstrcat(cmd->temp_pool, "!", c, NULL);
+    /*
+     * Add the new worker to the alias map.
+     */
+    jk_map_put(conf->uri_to_context, uri, w, NULL);
+    return NULL;
+}
+
+/*
+ * JkAutoMount directive handling
+ *
+ * JkAutoMount worker [virtualhost]
+ */
+
+static const char *jk_automount_context(cmd_parms * cmd,
+                                        void *dummy,
+                                        char *worker, char *virtualhost)
+{
+    server_rec *s = cmd->server;
+    jk_server_conf_t *conf =
+        (jk_server_conf_t *) ap_get_module_config(s->module_config,
+                                                  &jk_module);
+
+    /*
+     * Add the new automount to the auto map.
+     */
+    jk_map_put(conf->automount, worker, virtualhost, NULL);
+    return NULL;
+}
+
+/*
+ * JkWorkersFile Directive Handling
+ *
+ * JkWorkersFile file
+ */
+
+static const char *jk_set_worker_file(cmd_parms * cmd,
+                                      void *dummy, char *worker_file)
+{
+    server_rec *s = cmd->server;
+    struct stat statbuf;
+
+    jk_server_conf_t *conf =
+        (jk_server_conf_t *) ap_get_module_config(s->module_config,
+                                                  &jk_module);
+
+    /* we need an absolut path */
+    conf->worker_file = ap_server_root_relative(cmd->pool, worker_file);
+
+#ifdef CHROOTED_APACHE
+    ap_server_strip_chroot(conf->worker_file, 0);
+#endif
+
+    if (conf->worker_file == worker_file)
+        conf->worker_file = ap_pstrdup(cmd->pool, worker_file);
+
+    if (conf->worker_file == NULL)
+        return "JkWorkersFile file_name invalid";
+
+    if (stat(conf->worker_file, &statbuf) == -1)
+        return "Can't find the workers file specified";
+
+    return NULL;
+}
+
+/*
+ * JkMountFile Directive Handling
+ *
+ * JkMountFile file
+ */
+
+static const char *jk_set_mount_file(cmd_parms * cmd,
+                                     void *dummy, char *mount_file)
+{
+    server_rec *s = cmd->server;
+    struct stat statbuf;
+
+    jk_server_conf_t *conf =
+        (jk_server_conf_t *) ap_get_module_config(s->module_config,
+                                                  &jk_module);
+
+    /* we need an absolut path (ap_server_root_relative does the ap_pstrdup) */
+    conf->mount_file = ap_server_root_relative(cmd->pool, mount_file);
+
+#ifdef CHROOTED_APACHE
+    ap_server_strip_chroot(conf->mount_file, 0);
+#endif
+
+    if (conf->mount_file == NULL)
+        return "JkMountFile file name invalid";
+
+    if (stat(conf->mount_file, &statbuf) == -1)
+        return "Can't find the mount file specified";
+
+    return NULL;
+}
+
+/*
+ * JkLogFile Directive Handling
+ *
+ * JkLogFile file
+ */
+
+static const char *jk_set_log_file(cmd_parms * cmd,
+                                   void *dummy, char *log_file)
+{
+    server_rec *s = cmd->server;
+    jk_server_conf_t *conf =
+        (jk_server_conf_t *) ap_get_module_config(s->module_config,
+                                                  &jk_module);
+
+    /* we need an absolut path */
+    conf->log_file = log_file;
+
+    return NULL;
+}
+
+/*
+ * JkShmFile Directive Handling
+ *
+ * JkShmFile file
+ */
+
+static const char *jk_set_shm_file(cmd_parms * cmd,
+                                   void *dummy, char *shm_file)
+{
+
+    /* we need an absolut path */
+    jk_shm_file = ap_server_root_relative(cmd->pool, shm_file);
+
+#ifdef CHROOTED_APACHE
+    ap_server_strip_chroot(jk_shm_file, 0);
+#endif
+
+    if (jk_shm_file == shm_file)
+        jk_shm_file = ap_pstrdup(cmd->pool, shm_file);
+
+    if (jk_shm_file == NULL)
+        return "JkShmFile file_name invalid";
+
+    return NULL;
+}
+
+/*
+ * JkShmSize Directive Handling
+ *
+ * JkShmSize size in kilobytes
+ */
+
+static const char *jk_set_shm_size(cmd_parms * cmd,
+                                   void *dummy, const char *shm_size)
+{
+    int sz = 0;
+    /* we need an absolute path */
+    sz = atoi(shm_size) * 1024;
+    if (sz < JK_SHM_DEF_SIZE)
+        sz = JK_SHM_DEF_SIZE;
+    else
+        sz = JK_SHM_ALIGN(sz);
+    jk_shm_size = (size_t)sz;
+    return NULL;
+}
+
+/*
+ * JkLogLevel Directive Handling
+ *
+ * JkLogLevel debug/info/request/error/emerg
+ */
+
+static const char *jk_set_log_level(cmd_parms * cmd,
+                                    void *dummy, char *log_level)
+{
+    server_rec *s = cmd->server;
+    jk_server_conf_t *conf =
+        (jk_server_conf_t *) ap_get_module_config(s->module_config,
+                                                  &jk_module);
+
+    conf->log_level = jk_parse_log_level(log_level);
+
+    return NULL;
+}
+
+/*
+ * JkLogStampFormat Directive Handling
+ *
+ * JkLogStampFormat "[%a %b %d %H:%M:%S %Y] "
+ */
+
+static const char *jk_set_log_fmt(cmd_parms * cmd,
+                                  void *dummy, char *log_format)
+{
+    jk_set_log_format(log_format);
+    return NULL;
+}
+
+/*
+ * JkAutoAlias Directive Handling
+ *
+ * JkAutoAlias application directory
+ */
+
+static const char *jk_set_auto_alias(cmd_parms * cmd,
+                                     void *dummy, char *directory)
+{
+    server_rec *s = cmd->server;
+    jk_server_conf_t *conf =
+        (jk_server_conf_t *) ap_get_module_config(s->module_config,
+                                                  &jk_module);
+
+    conf->alias_dir = directory;
+
+    if (conf->alias_dir == NULL)
+        return "JkAutoAlias directory invalid";
+
+    return NULL;
+}
+
+/*****************************************************************
+ *
+ * Actually logging.
+ */
+
+typedef const char *(*item_key_func) (request_rec *, char *);
+
+typedef struct
+{
+    item_key_func func;
+    char *arg;
+} request_log_format_item;
+
+static const char *process_item(request_rec * r,
+                                request_log_format_item * item)
+{
+    const char *cp;
+
+    cp = (*item->func) (r, item->arg);
+    return cp ? cp : "-";
+}
+
+static void request_log_transaction(request_rec * r, jk_server_conf_t * conf)
+{
+    request_log_format_item *items;
+    char *str, *s;
+    int i;
+    int len = 0;
+    const char **strs;
+    int *strl;
+    array_header *format = conf->format;
+
+    strs = ap_palloc(r->pool, sizeof(char *) * (format->nelts));
+    strl = ap_palloc(r->pool, sizeof(int) * (format->nelts));
+    items = (request_log_format_item *) format->elts;
+    for (i = 0; i < format->nelts; ++i) {
+        strs[i] = process_item(r, &items[i]);
+    }
+    for (i = 0; i < format->nelts; ++i) {
+        len += strl[i] = strlen(strs[i]);
+    }
+    str = ap_palloc(r->pool, len + 1);
+    for (i = 0, s = str; i < format->nelts; ++i) {
+        memcpy(s, strs[i], strl[i]);
+        s += strl[i];
+    }
+    *s = 0;
+    jk_log(conf->log ? conf->log : main_log, JK_LOG_REQUEST, "%s", str);
+}
+
+/*****************************************************************
+ *
+ * Parsing the log format string
+ */
+
+static char *format_integer(pool * p, int i)
+{
+    return ap_psprintf(p, "%d", i);
+}
+
+static char *pfmt(pool * p, int i)
+{
+    if (i <= 0) {
+        return "-";
+    }
+    else {
+        return format_integer(p, i);
+    }
+}
+
+static const char *constant_item(request_rec * dummy, char *stuff)
+{
+    return stuff;
+}
+
+static const char *log_worker_name(request_rec * r, char *a)
+{
+    return ap_table_get(r->notes, JK_NOTE_WORKER_NAME);
+}
+
+static const char *log_worker_route(request_rec * r, char *a)
+{
+    return ap_table_get(r->notes, JK_NOTE_WORKER_ROUTE);
+}
+
+static const char *log_request_duration(request_rec * r, char *a)
+{
+    return ap_table_get(r->notes, JK_NOTE_REQUEST_DURATION);
+}
+
+static const char *log_request_line(request_rec * r, char *a)
+{
+    /* NOTE: If the original request contained a password, we
+     * re-write the request line here to contain XXXXXX instead:
+     * (note the truncation before the protocol string for HTTP/0.9 requests)
+     * (note also that r->the_request contains the unmodified request)
+     */
+    return (r->parsed_uri.password) ? ap_pstrcat(r->pool, r->method, " ",
+                                                 ap_unparse_uri_components(r->
+                                                                           pool,
+                                                                           &r->
+                                                                           parsed_uri,
+                                                                           0),
+                                                 r->assbackwards ? NULL : " ",
+                                                 r->protocol, NULL)
+        : r->the_request;
+}
+
+/* These next two routines use the canonical name:port so that log
+ * parsers don't need to duplicate all the vhost parsing crud.
+ */
+static const char *log_virtual_host(request_rec * r, char *a)
+{
+    return r->server->server_hostname;
+}
+
+static const char *log_server_port(request_rec * r, char *a)
+{
+    return ap_psprintf(r->pool, "%u",
+                       r->server->port ? r->server->
+                       port : ap_default_port(r));
+}
+
+/* This respects the setting of UseCanonicalName so that
+ * the dynamic mass virtual hosting trick works better.
+ */
+static const char *log_server_name(request_rec * r, char *a)
+{
+    return ap_get_server_name(r);
+}
+
+static const char *log_request_uri(request_rec * r, char *a)
+{
+    return r->uri;
+}
+static const char *log_request_method(request_rec * r, char *a)
+{
+    return r->method;
+}
+
+static const char *log_request_protocol(request_rec * r, char *a)
+{
+    return r->protocol;
+}
+static const char *log_request_query(request_rec * r, char *a)
+{
+    return (r->args != NULL) ? ap_pstrcat(r->pool, "?", r->args, NULL)
+        : "";
+}
+static const char *log_status(request_rec * r, char *a)
+{
+    return pfmt(r->pool, r->status);
+}
+
+static const char *clf_log_bytes_sent(request_rec * r, char *a)
+{
+    if (!r->sent_bodyct) {
+        return "-";
+    }
+    else {
+        long int bs;
+        ap_bgetopt(r->connection->client, BO_BYTECT, &bs);
+        return ap_psprintf(r->pool, "%ld", bs);
+    }
+}
+
+static const char *log_bytes_sent(request_rec * r, char *a)
+{
+    if (!r->sent_bodyct) {
+        return "0";
+    }
+    else {
+        long int bs;
+        ap_bgetopt(r->connection->client, BO_BYTECT, &bs);
+        return ap_psprintf(r->pool, "%ld", bs);
+    }
+}
+
+static struct log_item_list
+{
+    char ch;
+    item_key_func func;
+} log_item_keys[] = {
+
+    {
+    'T', log_request_duration}, {
+    'r', log_request_line}, {
+    'U', log_request_uri}, {
+    's', log_status}, {
+    'b', clf_log_bytes_sent}, {
+    'B', log_bytes_sent}, {
+    'V', log_server_name}, {
+    'v', log_virtual_host}, {
+    'p', log_server_port}, {
+    'H', log_request_protocol}, {
+    'm', log_request_method}, {
+    'q', log_request_query}, {
+    'w', log_worker_name}, {
+    'R', log_worker_route}, {
+    '\0'}
+};
+
+static struct log_item_list *find_log_func(char k)
+{
+    int i;
+
+    for (i = 0; log_item_keys[i].ch; ++i)
+        if (k == log_item_keys[i].ch) {
+            return &log_item_keys[i];
+        }
+
+    return NULL;
+}
+
+static char *parse_request_log_misc_string(pool * p,
+                                           request_log_format_item * it,
+                                           const char **sa)
+{
+    const char *s;
+    char *d;
+
+    it->func = constant_item;
+
+    s = *sa;
+    while (*s && *s != '%') {
+        s++;
+    }
+    /*
+     * This might allocate a few chars extra if there's a backslash
+     * escape in the format string.
+     */
+    it->arg = ap_palloc(p, s - *sa + 1);
+
+    d = it->arg;
+    s = *sa;
+    while (*s && *s != '%') {
+        if (*s != '\\') {
+            *d++ = *s++;
+        }
+        else {
+            s++;
+            switch (*s) {
+            case '\\':
+                *d++ = '\\';
+                s++;
+                break;
+            case 'n':
+                *d++ = '\n';
+                s++;
+                break;
+            case 't':
+                *d++ = '\t';
+                s++;
+                break;
+            default:
+                /* copy verbatim */
+                *d++ = '\\';
+                /*
+                 * Allow the loop to deal with this *s in the normal
+                 * fashion so that it handles end of string etc.
+                 * properly.
+                 */
+                break;
+            }
+        }
+    }
+    *d = '\0';
+
+    *sa = s;
+    return NULL;
+}
+
+static char *parse_request_log_item(pool * p,
+                                    request_log_format_item * it,
+                                    const char **sa)
+{
+    const char *s = *sa;
+    struct log_item_list *l;
+
+    if (*s != '%') {
+        return parse_request_log_misc_string(p, it, sa);
+    }
+
+    ++s;
+    it->arg = "";               /* For safety's sake... */
+
+    l = find_log_func(*s++);
+    if (!l) {
+        char dummy[2];
+
+        dummy[0] = s[-1];
+        dummy[1] = '\0';
+        return ap_pstrcat(p, "Unrecognized JkRequestLogFormat directive %",
+                          dummy, NULL);
+    }
+    it->func = l->func;
+    *sa = s;
+    return NULL;
+}
+
+static array_header *parse_request_log_string(pool * p, const char *s,
+                                              const char **err)
+{
+    array_header *a = ap_make_array(p, 15, sizeof(request_log_format_item));
+    char *res;
+
+    while (*s) {
+        if ((res =
+             parse_request_log_item(p,
+                                    (request_log_format_item *)
+                                    ap_push_array(a), &s))) {
+            *err = res;
+            return NULL;
+        }
+    }
+
+    return a;
+}
+
+/*
+ * JkRequestLogFormat Directive Handling
+ *
+ * JkRequestLogFormat format string
+ *
+ * %b - Bytes sent, excluding HTTP headers. In CLF format
+ * %B - Bytes sent, excluding HTTP headers.
+ * %H - The request protocol
+ * %m - The request method
+ * %p - The canonical Port of the server serving the request
+ * %q - The query string (prepended with a ? if a query string exists,
+ *      otherwise an empty string)
+ * %r - First line of request
+ * %s - request HTTP status code
+ * %T - Requset duration, elapsed time to handle request in seconds '.' micro seconds
+ * %U - The URL path requested, not including any query string.
+ * %v - The canonical ServerName of the server serving the request.
+ * %V - The server name according to the UseCanonicalName setting.
+ * %w - Tomcat worker name
+ */
+
+static const char *jk_set_request_log_format(cmd_parms * cmd,
+                                             void *dummy, char *format)
+{
+    const char *err_string = NULL;
+    server_rec *s = cmd->server;
+    jk_server_conf_t *conf =
+        (jk_server_conf_t *) ap_get_module_config(s->module_config,
+                                                  &jk_module);
+
+    conf->format_string = ap_pstrdup(cmd->pool, format);
+    if (format != NULL) {
+        conf->format =
+            parse_request_log_string(cmd->pool, format, &err_string);
+    }
+    if (conf->format == NULL)
+        return "JkRequestLogFormat format array NULL";
+
+    return err_string;
+}
+
+/*
+ * JkExtractSSL Directive Handling
+ *
+ * JkExtractSSL On/Off
+ */
+
+static const char *jk_set_enable_ssl(cmd_parms * cmd, void *dummy, int flag)
+{
+    server_rec *s = cmd->server;
+    jk_server_conf_t *conf =
+        (jk_server_conf_t *) ap_get_module_config(s->module_config,
+                                                  &jk_module);
+
+    /* Set up our value */
+    conf->ssl_enable = flag ? JK_TRUE : JK_FALSE;
+    return NULL;
+}
+
+/*
+ * JkHTTPSIndicator Directive Handling
+ *
+ * JkHTTPSIndicator HTTPS
+ */
+
+static const char *jk_set_https_indicator(cmd_parms * cmd,
+                                          void *dummy, char *indicator)
+{
+    server_rec *s = cmd->server;
+    jk_server_conf_t *conf =
+        (jk_server_conf_t *) ap_get_module_config(s->module_config,
+                                                  &jk_module);
+
+    conf->https_indicator = ap_pstrdup(cmd->pool, indicator);
+    return NULL;
+}
+
+/*
+ * JkCERTSIndicator Directive Handling
+ *
+ * JkCERTSIndicator SSL_CLIENT_CERT
+ */
+
+static const char *jk_set_certs_indicator(cmd_parms * cmd,
+                                          void *dummy, char *indicator)
+{
+    server_rec *s = cmd->server;
+    jk_server_conf_t *conf =
+        (jk_server_conf_t *) ap_get_module_config(s->module_config,
+                                                  &jk_module);
+
+    conf->certs_indicator = ap_pstrdup(cmd->pool, indicator);
+    return NULL;
+}
+
+/*
+ * JkCIPHERIndicator Directive Handling
+ *
+ * JkCIPHERIndicator SSL_CIPHER
+ */
+
+static const char *jk_set_cipher_indicator(cmd_parms * cmd,
+                                           void *dummy, char *indicator)
+{
+    server_rec *s = cmd->server;
+    jk_server_conf_t *conf =
+        (jk_server_conf_t *) ap_get_module_config(s->module_config,
+                                                  &jk_module);
+
+    conf->cipher_indicator = ap_pstrdup(cmd->pool, indicator);
+    return NULL;
+}
+
+/*
+ * JkSESSIONIndicator Directive Handling
+ *
+ * JkSESSIONIndicator SSL_SESSION_ID
+ */
+
+static const char *jk_set_session_indicator(cmd_parms * cmd,
+                                            void *dummy, char *indicator)
+{
+    server_rec *s = cmd->server;
+    jk_server_conf_t *conf =
+        (jk_server_conf_t *) ap_get_module_config(s->module_config,
+                                                  &jk_module);
+
+    conf->session_indicator = ap_pstrdup(cmd->pool, indicator);
+    return NULL;
+}
+
+/*
+ * JkKEYSIZEIndicator Directive Handling
+ *
+ * JkKEYSIZEIndicator SSL_CIPHER_USEKEYSIZE
+ */
+
+static const char *jk_set_key_size_indicator(cmd_parms * cmd,
+                                             void *dummy, char *indicator)
+{
+    server_rec *s = cmd->server;
+    jk_server_conf_t *conf =
+        (jk_server_conf_t *) ap_get_module_config(s->module_config,
+                                                  &jk_module);
+
+    conf->key_size_indicator = ap_pstrdup(cmd->pool, indicator);
+    return NULL;
+}
+
+/*
+ * JkOptions Directive Handling
+ *
+ *
+ * +ForwardSSLKeySize        => Forward SSL Key Size, to follow 2.3 specs but may broke old TC 3.2
+ * -ForwardSSLKeySize        => Don't Forward SSL Key Size, will make mod_jk works with all TC release
+ *  ForwardURICompat         => Forward URI normally, less spec compliant but mod_rewrite compatible (old TC)
+ *  ForwardURICompatUnparsed => Forward URI as unparsed, spec compliant but broke mod_rewrite (old TC)
+ *  ForwardURIEscaped        => Forward URI escaped and Tomcat (3.3 rc2) stuff will do the decoding part
+ *  ForwardDirectories       => Forward all directory requests with no index files to Tomcat
+ */
+
+const char *jk_set_options(cmd_parms * cmd, void *dummy, const char *line)
+{
+    int opt = 0;
+    int mask = 0;
+    char action;
+    char *w;
+
+    server_rec *s = cmd->server;
+    jk_server_conf_t *conf =
+        (jk_server_conf_t *) ap_get_module_config(s->module_config,
+                                                  &jk_module);
+
+    while (line[0] != 0) {
+        w = ap_getword_conf(cmd->pool, &line);
+        action = 0;
+
+        if (*w == '+' || *w == '-') {
+            action = *(w++);
+        }
+
+        mask = 0;
+
+        if (!strcasecmp(w, "ForwardKeySize")) {
+            opt = JK_OPT_FWDKEYSIZE;
+        }
+        else if (!strcasecmp(w, "ForwardURICompat")) {
+            opt = JK_OPT_FWDURICOMPAT;
+            mask = JK_OPT_FWDURIMASK;
+        }
+        else if (!strcasecmp(w, "ForwardURICompatUnparsed")) {
+            opt = JK_OPT_FWDURICOMPATUNPARSED;
+            mask = JK_OPT_FWDURIMASK;
+        }
+        else if (!strcasecmp(w, "ForwardURIEscaped")) {
+            opt = JK_OPT_FWDURIESCAPED;
+            mask = JK_OPT_FWDURIMASK;
+        }
+        else if (!strcasecmp(w, "ForwardDirectories")) {
+            opt = JK_OPT_FWDDIRS;
+        }
+        else if (!strcasecmp(w, "ForwardLocalAddress")) {
+            opt = JK_OPT_FWDLOCAL;
+        }
+        else if (!strcasecmp(w, "FlushPackets")) {
+            opt = JK_OPT_FLUSHPACKETS;
+        }
+        else if (!strcasecmp(w, "DisableReuse")) {
+            opt = JK_OPT_DISABLEREUSE;
+        }
+        else
+            return ap_pstrcat(cmd->pool, "JkOptions: Illegal option '", w,
+                              "'", NULL);
+
+        conf->options &= ~mask;
+
+        if (action == '-') {
+            conf->options &= ~opt;
+        }
+        else if (action == '+') {
+            conf->options |= opt;
+        }
+        else {                  /* for now +Opt == Opt */
+            conf->options |= opt;
+        }
+    }
+    return NULL;
+}
+
+/*
+ * JkEnvVar Directive Handling
+ *
+ * JkEnvVar MYOWNDIR
+ */
+
+static const char *jk_add_env_var(cmd_parms * cmd,
+                                  void *dummy,
+                                  char *env_name, char *default_value)
+{
+    server_rec *s = cmd->server;
+    jk_server_conf_t *conf =
+        (jk_server_conf_t *) ap_get_module_config(s->module_config,
+                                                  &jk_module);
+
+    conf->envvars_in_use = JK_TRUE;
+
+    ap_table_add(conf->envvars, env_name, default_value);
+
+    return NULL;
+}
+
+/*
+ * JkWorkerProperty Directive Handling
+ *
+ * JkWorkerProperty name=value
+ */
+
+static const char *jk_set_worker_property(cmd_parms * cmd,
+                                          void *dummy,
+                                          const char *line)
+{
+    server_rec *s = cmd->server;
+    jk_server_conf_t *conf =
+        (jk_server_conf_t *) ap_get_module_config(s->module_config,
+                                                  &jk_module);
+
+    jk_logger_t *l = conf->log ? conf->log : main_log;
+    if (jk_map_read_property(conf->worker_properties, line, l) == JK_FALSE)
+        return ap_pstrcat(cmd->temp_pool, "Invalid JkWorkerProperty ", line);
+
+    return NULL;
+}
+
+static const command_rec jk_cmds[] = {
+    /*
+     * JkWorkersFile specifies a full path to the location of the worker
+     * properties file.
+     *
+     * This file defines the different workers used by apache to redirect
+     * servlet requests.
+     */
+    {"JkWorkersFile", jk_set_worker_file, NULL, RSRC_CONF, TAKE1,
+     "the name of a worker file for the Tomcat servlet containers"},
+
+    /*
+     * JkMountFile specifies a full path to the location of the
+     * uriworker properties file.
+     *
+     * This file defines the different mapping for workers used by apache
+     * to redirect servlet requests.
+     */
+    {"JkMountFile", jk_set_mount_file, NULL, RSRC_CONF, TAKE1,
+     "the name of a mount file for the Tomcat servlet uri mappings"},
+
+    /*
+     * JkAutoMount specifies that the list of handled URLs must be
+     * asked to the servlet engine (autoconf feature)
+     */
+    {"JkAutoMount", jk_automount_context, NULL, RSRC_CONF, TAKE12,
+     "automatic mount points to a servlet-engine worker"},
+
+    /*
+     * JkMount mounts a url prefix to a worker (the worker need to be
+     * defined in the worker properties file.
+     */
+    {"JkMount", jk_mount_context, NULL, RSRC_CONF|ACCESS_CONF, TAKE12,
+     "A mount point from a context to a servlet-engine worker"},
+
+    /*
+     * JkUnMount unmounts a url prefix to a worker (the worker need to be
+     * defined in the worker properties file.
+     */
+    {"JkUnMount", jk_unmount_context, NULL, RSRC_CONF|ACCESS_CONF, TAKE12,
+     "A no mount point from a context to a servlet-engine worker"},
+
+     /*
+     * JkMountCopy specifies if mod_jk should copy the mount points
+     * from the main server to the virtual servers.
+     */
+    {"JkMountCopy", jk_set_mountcopy, NULL, RSRC_CONF, FLAG,
+     "Should the base server mounts be copied to the virtual server"},
+
+    /*
+     * JkLogFile & JkLogLevel specifies to where should the plugin log
+     * its information and how much.
+     * JkLogStampFormat specify the time-stamp to be used on log
+     */
+    {"JkLogFile", jk_set_log_file, NULL, RSRC_CONF, TAKE1,
+     "Full path to the mod_jk module log file"},
+    {"JkShmFile", jk_set_shm_file, NULL, RSRC_CONF, TAKE1,
+     "Full path to the mod_jk module shared memory file"},
+    {"JkShmSize", jk_set_shm_size, NULL, RSRC_CONF, TAKE1,
+     "Size of the shared memory file in KBytes"},
+    {"JkLogLevel", jk_set_log_level, NULL, RSRC_CONF, TAKE1,
+     "The mod_jk module log level, can be debug, info, request, error, or emerg"},
+    {"JkLogStampFormat", jk_set_log_fmt, NULL, RSRC_CONF, TAKE1,
+     "The mod_jk module log format, follow strftime synthax"},
+    {"JkRequestLogFormat", jk_set_request_log_format, NULL, RSRC_CONF, TAKE1,
+     "The mod_jk module request log format string"},
+
+    /*
+     * Automatically Alias webapp context directories into the Apache
+     * document space.
+     */
+    {"JkAutoAlias", jk_set_auto_alias, NULL, RSRC_CONF, TAKE1,
+     "The mod_jk module automatic context apache alias directory"},
+
+    /*
+     * Apache has multiple SSL modules (for example apache_ssl, stronghold
+     * IHS ...). Each of these can have a different SSL environment names
+     * The following properties let the administrator specify the envoiroment
+     * variables names.
+     *
+     * HTTPS - indication for SSL
+     * CERTS - Base64-Der-encoded client certificates.
+     * CIPHER - A string specifing the ciphers suite in use.
+     * SESSION - A string specifing the current SSL session.
+     * KEYSIZE - Size of Key used in dialogue (#bits are secure)
+     */
+    {"JkHTTPSIndicator", jk_set_https_indicator, NULL, RSRC_CONF, TAKE1,
+     "Name of the Apache environment that contains SSL indication"},
+    {"JkCERTSIndicator", jk_set_certs_indicator, NULL, RSRC_CONF, TAKE1,
+     "Name of the Apache environment that contains SSL client certificates"},
+    {"JkCIPHERIndicator", jk_set_cipher_indicator, NULL, RSRC_CONF, TAKE1,
+     "Name of the Apache environment that contains SSL client cipher"},
+    {"JkSESSIONIndicator", jk_set_session_indicator, NULL, RSRC_CONF, TAKE1,
+     "Name of the Apache environment that contains SSL session"},
+    {"JkKEYSIZEIndicator", jk_set_key_size_indicator, NULL, RSRC_CONF, TAKE1,
+     "Name of the Apache environment that contains SSL key size in use"},
+    {"JkExtractSSL", jk_set_enable_ssl, NULL, RSRC_CONF, FLAG,
+     "Turns on SSL processing and information gathering by mod_jk"},
+
+    /*
+     * Options to tune mod_jk configuration
+     * for now we understand :
+     * +ForwardSSLKeySize        => Forward SSL Key Size, to follow 2.3 specs but may broke old TC 3.2
+     * -ForwardSSLKeySize        => Don't Forward SSL Key Size, will make mod_jk works with all TC release
+     *  ForwardURICompat         => Forward URI normally, less spec compliant but mod_rewrite compatible (old TC)
+     *  ForwardURICompatUnparsed => Forward URI as unparsed, spec compliant but broke mod_rewrite (old TC)
+     *  ForwardURIEscaped        => Forward URI escaped and Tomcat (3.3 rc2) stuff will do the decoding part
+     */
+    {"JkOptions", jk_set_options, NULL, RSRC_CONF, RAW_ARGS,
+     "Set one of more options to configure the mod_jk module"},
+
+    /*
+     * JkEnvVar let user defines envs var passed from WebServer to
+     * Servlet Engine
+     */
+    {"JkEnvVar", jk_add_env_var, NULL, RSRC_CONF, TAKE2,
+     "Adds a name of environment variable that should be sent to servlet-engine"},
+
+    {"JkWorkerProperty", jk_set_worker_property, NULL, RSRC_CONF, RAW_ARGS,
+     "Set workers.properties formated directive"},
+
+    {NULL}
+};
+
+/* ====================================================================== */
+/* The JK module handlers                                                 */
+/* ====================================================================== */
+
+/*
+ * Called to handle a single request.
+ */
+static int jk_handler(request_rec * r)
+{
+    /* Retrieve the worker name stored by jk_translate() */
+    const char *worker_name = ap_table_get(r->notes, JK_NOTE_WORKER_NAME);
+    int rc;
+
+    if (r->proxyreq) {
+        return HTTP_INTERNAL_SERVER_ERROR;
+    }
+
+    /* Set up r->read_chunked flags for chunked encoding, if present */
+    if ((rc = ap_setup_client_block(r, REQUEST_CHUNKED_DECHUNK))) {
+        return rc;
+    }
+
+    if (worker_name) {
+        jk_server_conf_t *conf =
+            (jk_server_conf_t *) ap_get_module_config(r->server->
+                                                      module_config,
+                                                      &jk_module);
+        jk_logger_t *l = conf->log ? conf->log : main_log;
+        jk_worker_t *worker;
+
+        JK_TRACE_ENTER(l);
+
+        worker = wc_get_worker_for_name(worker_name, l);
+
+        if (worker) {
+#ifndef NO_GETTIMEOFDAY
+            struct timeval tv_begin, tv_end;
+#endif
+            int rc = JK_FALSE;
+            int is_error = JK_HTTP_SERVER_ERROR;
+            apache_private_data_t private_data;
+            jk_ws_service_t s;
+            jk_pool_atom_t buf[SMALL_POOL_SIZE];
+            jk_open_pool(&private_data.p, buf, sizeof(buf));
+
+            private_data.response_started = JK_FALSE;
+            private_data.read_body_started = JK_FALSE;
+            private_data.r = r;
+
+            wc_maintain(l);
+            jk_init_ws_service(&s);
+
+            /* Update retries for this worker */
+            s.retries = worker->retries;
+            s.ws_private = &private_data;
+            s.pool = &private_data.p;
+            ap_table_setn(r->notes, JK_NOTE_WORKER_TYPE,
+                          wc_get_name_for_type(worker->type, l));
+#ifndef NO_GETTIMEOFDAY
+            if (conf->format != NULL) {
+                gettimeofday(&tv_begin, NULL);
+            }
+#endif
+
+            if (init_ws_service(&private_data, &s, conf)) {
+                jk_endpoint_t *end = NULL;
+                if (worker->get_endpoint(worker, &end, l)) {
+                    rc = end->service(end, &s, l, &is_error);
+                    end->done(&end, l);
+
+                    if (s.content_read < s.content_length ||
+                        (s.is_chunked && !s.no_more_chunks)) {
+                        /*
+                         * If the servlet engine didn't consume all of the
+                         * request data, consume and discard all further
+                         * characters left to read from client
+                         */
+                        char *buff = ap_palloc(r->pool, 2048);
+                        if (buff != NULL) {
+                            int rd;
+                            while ((rd =
+                                    ap_get_client_block(r, buff, 2048)) > 0) {
+                                s.content_read += rd;
+                            }
+                        }
+                    }
+                }
+                if (conf->format != NULL) {
+#ifndef NO_GETTIMEOFDAY
+                    long micro, seconds;
+                    char *duration = NULL;
+                    gettimeofday(&tv_end, NULL);
+                    if (tv_end.tv_usec < tv_begin.tv_usec) {
+                        tv_end.tv_usec += 1000000;
+                        tv_end.tv_sec--;
+                    }
+                    micro = tv_end.tv_usec - tv_begin.tv_usec;
+                    seconds = tv_end.tv_sec - tv_begin.tv_sec;
+                    duration =
+                        ap_psprintf(r->pool, "%.1ld.%.6ld", seconds, micro);
+                    ap_table_setn(r->notes, JK_NOTE_REQUEST_DURATION, duration);
+#endif
+                    if (s.jvm_route && *s.jvm_route)
+                        ap_table_setn(r->notes, JK_NOTE_WORKER_ROUTE, s.jvm_route);
+                    request_log_transaction(r, conf);
+                }
+            }
+            else {
+                jk_log(l, JK_LOG_ERROR, "Could not init service"
+                       " for worker=%s",
+                       worker_name);
+                jk_close_pool(&private_data.p);
+                JK_TRACE_EXIT(l);
+                return is_error;
+            }
+            jk_close_pool(&private_data.p);
+
+            if (rc > 0) {
+                /* If tomcat returned no body and the status is not OK,
+                   let apache handle the error code */
+                if (!r->sent_bodyct && r->status >= HTTP_BAD_REQUEST) {
+                    jk_log(l, JK_LOG_INFO, "No body with status=%d"
+                           " for worker=%s",
+                           r->status, worker_name);
+                    JK_TRACE_EXIT(l);
+                    return r->status;
+                }
+                if (JK_IS_DEBUG_LEVEL(l))
+                    jk_log(l, JK_LOG_DEBUG, "Service finished"
+                           " with status=%d for worker=%s",
+                           r->status, worker_name);
+                JK_TRACE_EXIT(l);
+                return OK;      /* NOT r->status, even if it has changed. */
+            }
+            else if (rc == JK_CLIENT_ERROR) {
+                if (is_error != HTTP_REQUEST_ENTITY_TOO_LARGE)
+                    r->connection->aborted = 1;
+                jk_log(l, JK_LOG_INFO, "Aborting connection"
+                       " for worker=%s",
+                       worker_name);
+                JK_TRACE_EXIT(l);
+                return is_error;
+            }
+            else {
+                jk_log(l, JK_LOG_INFO, "Service error=%d"
+                       " for worker=%s",
+                       rc, worker_name);
+                JK_TRACE_EXIT(l);
+                return is_error;
+            }
+        }
+        else {
+            jk_log(l, JK_LOG_ERROR, "Could not init service"
+                   " for worker=%s",
+                   worker_name);
+            JK_TRACE_EXIT(l);
+            return HTTP_INTERNAL_SERVER_ERROR;
+        }
+    }
+
+    return HTTP_INTERNAL_SERVER_ERROR;
+}
+
+/*
+ * Create a default config object.
+ */
+static void *create_jk_config(ap_pool * p, server_rec * s)
+{
+    jk_server_conf_t *c =
+        (jk_server_conf_t *) ap_pcalloc(p, sizeof(jk_server_conf_t));
+
+    c->worker_properties = NULL;
+    jk_map_alloc(&c->worker_properties);
+    c->worker_file = NULL;
+    c->mount_file = NULL;
+    c->log_file = NULL;
+    c->log_fd = -1;
+    c->log_level = JK_LOG_DEF_LEVEL;
+    c->log = NULL;
+    c->alias_dir = NULL;
+    c->format_string = NULL;
+    c->format = NULL;
+    c->mountcopy = JK_FALSE;
+    c->options = JK_OPT_FWDURIDEFAULT;
+
+    /*
+     * By default we will try to gather SSL info.
+     * Disable this functionality through JkExtractSSL
+     */
+    c->ssl_enable = JK_TRUE;
+    /*
+     * The defaults ssl indicators match those in mod_ssl (seems
+     * to be in more use).
+     */
+    c->https_indicator = "HTTPS";
+    c->certs_indicator = "SSL_CLIENT_CERT";
+
+    /*
+     * The following (comented out) environment variables match apache_ssl!
+     * If you are using apache_sslapache_ssl uncomment them (or use the
+     * configuration directives to set them.
+     *
+     c->cipher_indicator = "HTTPS_CIPHER";
+     c->session_indicator = NULL;
+     c->key_size_indicator = NULL;
+     */
+
+    /*
+     * The following environment variables match mod_ssl! If you
+     * are using another module (say apache_ssl) comment them out.
+     */
+    c->cipher_indicator = "SSL_CIPHER";
+    c->session_indicator = "SSL_SESSION_ID";
+    c->key_size_indicator = "SSL_CIPHER_USEKEYSIZE";
+
+    if (!jk_map_alloc(&(c->uri_to_context))) {
+        jk_error_exit(APLOG_MARK, APLOG_EMERG, s, p, "Memory error");
+    }
+    if (!jk_map_alloc(&(c->automount))) {
+        jk_error_exit(APLOG_MARK, APLOG_EMERG, s, p, "Memory error");
+    }
+    c->uw_map = NULL;
+    c->secret_key = NULL;
+
+    c->envvars_in_use = JK_FALSE;
+    c->envvars = ap_make_table(p, 0);
+
+    c->s = s;
+    jk_map_put(c->worker_properties, "ServerRoot", ap_server_root, NULL);
+
+    return c;
+}
+
+
+static void copy_jk_map(ap_pool * p, server_rec * s, jk_map_t *src,
+                        jk_map_t *dst)
+{
+    int sz = jk_map_size(src);
+    int i;
+    for (i = 0; i < sz; i++) {
+        const char *name = jk_map_name_at(src, i);
+        if (jk_map_get(src, name, NULL) == NULL) {
+            if (!jk_map_put (dst, name,
+                 ap_pstrdup(p, jk_map_get_string(src, name, NULL)),
+                            NULL)) {
+                jk_error_exit(APLOG_MARK, APLOG_EMERG, s, p, "Memory error");
+            }
+        }
+    }
+}
+
+static void *merge_jk_config(ap_pool * p, void *basev, void *overridesv)
+{
+    jk_server_conf_t *base = (jk_server_conf_t *) basev;
+    jk_server_conf_t *overrides = (jk_server_conf_t *) overridesv;
+
+    if (base->ssl_enable) {
+        overrides->ssl_enable = base->ssl_enable;
+        overrides->https_indicator = base->https_indicator;
+        overrides->certs_indicator = base->certs_indicator;
+        overrides->cipher_indicator = base->cipher_indicator;
+        overrides->session_indicator = base->session_indicator;
+        overrides->key_size_indicator = base->key_size_indicator;
+    }
+
+    overrides->options = base->options;
+
+    if (overrides->mountcopy) {
+        copy_jk_map(p, overrides->s, base->uri_to_context,
+                    overrides->uri_to_context);
+        copy_jk_map(p, overrides->s, base->automount, overrides->automount);
+        overrides->mount_file = base->mount_file;
+    }
+
+    if (base->envvars_in_use) {
+        overrides->envvars_in_use = JK_TRUE;
+        overrides->envvars =
+            ap_overlay_tables(p, overrides->envvars, base->envvars);
+    }
+
+    if (!uri_worker_map_alloc
+        (&(overrides->uw_map), overrides->uri_to_context, overrides->log)) {
+        jk_error_exit(APLOG_MARK, APLOG_EMERG, overrides->s, p,
+                      "Memory error");
+    }
+
+    if (base->secret_key)
+        overrides->secret_key = base->secret_key;
+
+    return overrides;
+}
+
+static int JK_METHOD jk_log_to_file(jk_logger_t *l,
+                                    int level, const char *what)
+{
+    if (l &&
+        (l->level <= level || level == JK_LOG_REQUEST_LEVEL) &&
+         l->logger_private && what) {
+        file_logger_t *flp = l->logger_private;
+        int log_fd = flp->log_fd;
+        size_t sz = strlen(what);
+        if (log_fd >= 0 && sz) {
+            if ( write(log_fd, what, sz) < 0 )
+            {
+                ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO,
+                             NULL,
+                             "mod_jk: jk_log_to_file %s failed",
+                             what);
+            }
+        }
+
+        return JK_TRUE;
+    }
+
+    return JK_FALSE;
+}
+
+static void open_jk_log(server_rec *s, pool *p)
+{
+    jk_logger_t *jkl;
+    file_logger_t *flp;
+    jk_server_conf_t *conf =
+        (jk_server_conf_t *) ap_get_module_config(s->module_config,
+                                                  &jk_module);
+
+    if (!conf->log_file || conf->log_fd >= 0)
+        return;               /* virtual log shared w/main server */
+
+    if (*conf->log_file == '|') {
+        piped_log *pl;
+
+        pl = ap_open_piped_log(p, conf->log_file + 1);
+        if (pl == NULL) {
+            ap_log_error(APLOG_MARK, APLOG_ERR, s,
+                         "mod_jk: could not open reliable pipe "
+                         "to jk log %s", conf->log_file + 1);
+            exit(1);
+        }
+        conf->log_fd = ap_piped_log_write_fd(pl);
+    }
+    else if (*conf->log_file != '\0') {
+        char *log_file = ap_server_root_relative(p, conf->log_file);
+#if AP_MODULE_MAGIC_AT_LEAST(19990320,14)
+        if ((conf->log_fd = ap_popenf_ex(p, log_file, xfer_flags, xfer_mode, 1))
+             < 0) {
+#else
+        if ((conf->log_fd = ap_popenf(p, log_file, xfer_flags, xfer_mode))
+             < 0) {
+#endif
+            ap_log_error(APLOG_MARK, APLOG_ERR, s,
+                         "mod_jk: could not open JkLog " "file %s", log_file);
+            exit(1);
+        }
+    }
+
+    jkl = (jk_logger_t *)ap_palloc(p, sizeof(jk_logger_t));
+    flp = (file_logger_t *)ap_palloc(p, sizeof(file_logger_t));
+    if (jkl && flp) {
+        jkl->log = jk_log_to_file;
+        jkl->level = conf->log_level;
+        jkl->logger_private = flp;
+        flp->log_fd = conf->log_fd;
+        conf->log = jkl;
+        if (main_log == NULL)
+            main_log = conf->log;
+        return;
+    }
+
+    return;
+}
+
+static void jk_init(server_rec * s, ap_pool * p)
+{
+    int rc;
+    server_rec *t;
+    jk_server_conf_t *conf =
+        (jk_server_conf_t *) ap_get_module_config(s->module_config,
+                                                  &jk_module);
+    jk_map_t *init_map = conf->worker_properties;
+
+    open_jk_log(s, p);
+    main_log = conf->log;
+    for (t=s; t; t = t->next)
+        open_jk_log(t, p);
+#if !defined(WIN32) && !defined(NETWARE)
+    if (!jk_shm_file) {
+        jk_shm_file = ap_server_root_relative(p, "logs/jk-runtime-status");
+        if (jk_shm_file)
+            ap_log_error(APLOG_MARK, APLOG_INFO | APLOG_NOERRNO, NULL,
+                         "No JkShmFile defined in httpd.conf. "
+                         "Using default %s", jk_shm_file);
+    }
+#endif
+
+    if ((rc = jk_shm_open(jk_shm_file, jk_shm_size, conf->log)) == 0) {
+        if (JK_IS_DEBUG_LEVEL(conf->log))
+            jk_log(conf->log, JK_LOG_DEBUG, "Initialized shm:%s",
+                   jk_shm_name(), rc);
+    }
+    else
+        jk_log(conf->log, JK_LOG_ERROR, "Initializing shm:%s errno=%d",
+               jk_shm_name(), rc);
+#if !defined(WIN32) && !defined(NETWARE)
+    if (!jk_shm_file)
+        ap_log_error(APLOG_MARK, APLOG_EMERG | APLOG_NOERRNO, NULL,
+                     "No JkShmFile defined in httpd.conf. "
+                     "LoadBalancer will not function properly!");
+#endif
+
+    /* SREVILAK -- register cleanup handler to clear resources on restart,
+     * to make sure log file gets closed in the parent process  */
+    ap_register_cleanup(p, s, jk_server_cleanup, ap_null_cleanup);
+
+/*
+{ int i;
+jk_log(conf->log, JK_LOG_DEBUG, "default secret key = %s", conf->secret_key);
+for (i = 0; i < jk_map_size(conf->automount); i++)
+{
+            char *name = jk_map_name_at(conf->automount, i);
+            jk_log(conf->log, JK_LOG_DEBUG, "worker = %s and virtualhost = %s", name, map_get_string(conf->automount, name, NULL));
+}
+}
+*/
+
+     /* Create mapping from uri's to workers, and start up all the workers */
+    if (!uri_worker_map_alloc
+        (&(conf->uw_map), conf->uri_to_context, conf->log)) {
+        jk_error_exit(APLOG_MARK, APLOG_EMERG, s, p, "Memory error");
+    }
+
+    /*if(map_alloc(&init_map)) { */
+
+    if (!jk_map_read_properties(init_map, conf->worker_file, NULL, conf->log)) {
+
+        if (jk_map_size(init_map) == 0) {
+            ap_log_error(APLOG_MARK, APLOG_EMERG, NULL,
+                         "No worker file and no worker options in httpd.conf "
+                         "use JkWorkerFile to set workers");
+            return;
+        }
+
+    }
+#if MODULE_MAGIC_NUMBER >= 19980527
+        /* Tell apache we're here */
+    ap_add_version_component(JK_EXPOSED_VERSION);
+#endif
+
+    if (jk_map_resolve_references(init_map, "worker.", 1, 1, conf->log) == JK_FALSE) {
+        jk_error_exit(APLOG_MARK, APLOG_EMERG, s, p, "Error in resolving configuration references");
+    }
+
+    /* we add the URI->WORKER MAP since workers using AJP14 will feed it */
+    worker_env.uri_to_worker = conf->uw_map;
+    worker_env.virtual = "*";       /* for now */
+    worker_env.server_name = (char *)ap_get_server_version();
+    if (wc_open(init_map, &worker_env, conf->log)) {
+        /* XXX: For each virtual host? */
+        if (conf && conf->mount_file) {
+            conf->uw_map->fname = conf->mount_file;
+            uri_worker_map_load(conf->uw_map, conf->log);
+        }
+        return;
+    }
+
+    ap_log_error(APLOG_MARK, APLOG_ERR, NULL,
+                 "Error while opening the workers, jk will not work");
+}
+
+/*
+ * Perform uri to worker mapping, and store the name of the relevant worker
+ * in the notes fields of the request_rec object passed in.  This will then
+ * get picked up in jk_handler().
+ */
+static int jk_translate(request_rec * r)
+{
+    if (!r->proxyreq) {
+        jk_server_conf_t *conf =
+            (jk_server_conf_t *) ap_get_module_config(r->server->
+                                                      module_config,
+                                                      &jk_module);
+
+        if (conf) {
+            jk_logger_t *l = conf->log ? conf->log : main_log;
+            char *clean_uri = ap_pstrdup(r->pool, r->uri);
+            const char *worker;
+
+            ap_no2slash(clean_uri);
+            worker = map_uri_to_worker(conf->uw_map, clean_uri, l);
+
+            /* Don't know the worker, ForwardDirectories is set, there is a
+             * previous request for which the handler is JK_HANDLER (as set by
+             * jk_fixups) and the request is for a directory:
+             * --> forward to Tomcat, via default worker */
+            if (!worker && (conf->options & JK_OPT_FWDDIRS) &&
+                r->prev && r->prev->handler &&
+                !strcmp(r->prev->handler, JK_HANDLER) && clean_uri &&
+                strlen(clean_uri) && clean_uri[strlen(clean_uri) - 1] == '/') {
+
+                if (worker_env.num_of_workers) {
+                    /* Nothing here to do but assign the first worker since we
+                     * already tried mapping and it didn't work out */
+                    worker = worker_env.worker_list[0];
+
+                    jk_log(l, JK_LOG_DEBUG, "Manual configuration for %s %s",
+                           clean_uri, worker_env.worker_list[0]);
+                }
+            }
+
+            if (worker) {
+                r->handler = ap_pstrdup(r->pool, JK_HANDLER);
+                ap_table_setn(r->notes, JK_NOTE_WORKER_NAME, worker);
+            }
+            else if (conf->alias_dir != NULL) {
+                /* Automatically map uri to a context static file */
+                jk_log(l, JK_LOG_DEBUG,
+                       "mod_jk::jk_translate, check alias_dir: %s",
+                       conf->alias_dir);
+                if (strlen(clean_uri) > 1) {
+                    /* Get the context directory name */
+                    char *context_dir = NULL;
+                    char *context_path = NULL;
+                    char *child_dir = NULL;
+                    char *index = clean_uri;
+                    char *suffix = strchr(index + 1, '/');
+                    if (suffix != NULL) {
+                        int size = suffix - index;
+                        context_dir = ap_pstrndup(r->pool, index, size);
+                        /* Get the context child directory name */
+                        index = index + size + 1;
+                        suffix = strchr(index, '/');
+                        if (suffix != NULL) {
+                            size = suffix - index;
+                            child_dir = ap_pstrndup(r->pool, index, size);
+                        }
+                        else {
+                            child_dir = index;
+                        }
+                        /* Deny access to WEB-INF and META-INF directories */
+                        if (child_dir != NULL) {
+                            jk_log(l, JK_LOG_DEBUG,
+                                   "mod_jk::jk_translate, AutoAlias child_dir: %s",
+                                   child_dir);
+                            if (!strcasecmp(child_dir, "WEB-INF") ||
+                                !strcasecmp(child_dir, "META-INF")) {
+                                jk_log(l, JK_LOG_DEBUG,
+                                       "mod_jk::jk_translate, AutoAlias HTTP_NOT_FOUND for URI: %s",
+                                       r->uri);
+                                return HTTP_NOT_FOUND;
+                            }
+                        }
+                    }
+                    else {
+                        context_dir = ap_pstrdup(r->pool, index);
+                    }
+
+                    context_path = ap_pstrcat(r->pool, conf->alias_dir,
+                                              ap_os_escape_path(r->pool,
+                                                                context_dir,
+                                                                1), NULL);
+                    if (context_path != NULL) {
+                        DIR *dir = ap_popendir(r->pool, context_path);
+                        if (dir != NULL) {
+                            char *escurl =
+                                ap_os_escape_path(r->pool, clean_uri, 1);
+                            char *ret =
+                                ap_pstrcat(r->pool, conf->alias_dir, escurl,
+                                           NULL);
+                            ap_pclosedir(r->pool, dir);
+                            /* Add code to verify real path ap_os_canonical_name */
+                            if (ret != NULL) {
+                                jk_log(l, JK_LOG_DEBUG,
+                                       "mod_jk::jk_translate, AutoAlias OK for file: %s",
+                                       ret);
+                                r->filename = ret;
+                                return OK;
+                            }
+                        }
+                        else {
+                            /* Deny access to war files in web app directory */
+                            int size = strlen(context_dir);
+                            if (size > 4
+                                && !strcasecmp(context_dir + (size - 4),
+                                               ".war")) {
+                                jk_log(l, JK_LOG_DEBUG,
+                                       "mod_jk::jk_translate, AutoAlias FORBIDDEN for URI: %s",
+                                       r->uri);
+                                return FORBIDDEN;
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    return DECLINED;
+}
+
+/* In case ForwardDirectories option is set, we need to know if all files
+ * mentioned in DirectoryIndex have been exhausted without success. If yes, we
+ * need to let mod_dir know that we want Tomcat to handle the directory
+ */
+static int jk_fixups(request_rec * r)
+{
+    /* This is a sub-request, probably from mod_dir */
+    if (r->main) {
+        jk_server_conf_t *conf = (jk_server_conf_t *)
+            ap_get_module_config(r->server->module_config, &jk_module);
+        char *worker = (char *)ap_table_get(r->notes, JK_NOTE_WORKER_NAME);
+
+        /* Only if we have no worker and ForwardDirectories is set */
+        if (!worker && (conf->options & JK_OPT_FWDDIRS)) {
+            char *dummy_ptr[1], **names_ptr, *idx;
+            int num_names;
+            dir_config_rec *d = (dir_config_rec *)
+                ap_get_module_config(r->per_dir_config, &dir_module);
+            jk_logger_t *l = conf->log ? conf->log : main_log;
+
+            /* Direct lift from mod_dir */
+            if (d->index_names) {
+                names_ptr = (char **)d->index_names->elts;
+                num_names = d->index_names->nelts;
+            }
+            else {
+                dummy_ptr[0] = DEFAULT_INDEX;
+                names_ptr = dummy_ptr;
+                num_names = 1;
+            }
+
+            /* Where the index file would start within the filename */
+            idx = r->filename + strlen(r->filename) -
+                strlen(names_ptr[num_names - 1]);
+
+            /* The requested filename has the last index file at the end */
+            if (idx >= r->filename && !strcmp(idx, names_ptr[num_names - 1])) {
+                r->uri = r->main->uri;  /* Trick mod_dir with URI */
+                r->finfo.st_mode = S_IFREG;     /* Trick mod_dir with file stat */
+
+                /* We'll be checking for handler in r->prev later on */
+                r->main->handler = ap_pstrdup(r->pool, JK_HANDLER);
+
+                jk_log(l, JK_LOG_DEBUG, "ForwardDirectories on: %s",
+                       r->uri);
+            }
+        }
+    }
+
+    return DECLINED;
+}
+
+static void exit_handler(server_rec * s, ap_pool * p)
+{
+    /* srevilak - refactor cleanup body to jk_generic_cleanup() */
+    jk_generic_cleanup(s);
+}
+
+
+/** srevilak -- registered as a cleanup handler in jk_init */
+static void jk_server_cleanup(void *data)
+{
+    jk_generic_cleanup((server_rec *) data);
+    jk_shm_close();
+}
+
+
+/** BEGIN SREVILAK
+ * body taken from exit_handler()
+ */
+static void jk_generic_cleanup(server_rec * s)
+{
+
+    server_rec *tmp = s;
+
+    /* loop through all available servers to clean up all configuration
+     * records we've created
+     */
+    while (NULL != tmp) {
+        jk_server_conf_t *conf =
+            (jk_server_conf_t *) ap_get_module_config(tmp->module_config,
+                                                      &jk_module);
+
+        if (conf) {
+            wc_close(NULL);
+            uri_worker_map_free(&(conf->uw_map), NULL);
+            jk_map_free(&(conf->uri_to_context));
+            jk_map_free(&(conf->worker_properties));
+            jk_map_free(&(conf->automount));
+        }
+        tmp = tmp->next;
+    }
+}
+
+/** END SREVILAK **/
+
+
+static const handler_rec jk_handlers[] = {
+    {JK_MAGIC_TYPE, jk_handler},
+    {JK_HANDLER, jk_handler},
+    {NULL}
+};
+
+module MODULE_VAR_EXPORT jk_module = {
+    STANDARD_MODULE_STUFF,
+    jk_init,                    /* module initializer */
+    NULL,                       /* per-directory config creator */
+    NULL,                       /* dir config merger */
+    create_jk_config,           /* server config creator */
+    merge_jk_config,            /* server config merger */
+    jk_cmds,                    /* command table */
+    jk_handlers,                /* [7] list of handlers */
+    jk_translate,               /* [2] filename-to-URI translation */
+    NULL,                       /* [5] check/validate user_id */
+    NULL,                       /* [6] check user_id is valid *here* */
+    NULL,                       /* [4] check access by host address */
+    NULL,                       /* XXX [7] MIME type checker/setter */
+    jk_fixups,                  /* [8] fixups */
+    NULL,                       /* [10] logger */
+    NULL,                       /* [3] header parser */
+    NULL,                       /* apache child process initializer */
+    exit_handler,               /* apache child process exit/cleanup */
+    NULL                        /* [1] post read_request handling */
+#ifdef EAPI
+        /*
+         * Extended module APIs, needed when using SSL.
+         * STDC say that we do not have to have them as NULL but
+         * why take a chance
+         */
+        , NULL,                 /* add_module */
+    NULL,                       /* remove_module */
+    NULL,                       /* rewrite_command */
+    NULL,                       /* new_connection */
+    NULL                        /* close_connection */
+#endif /* EAPI */
+};

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/apache-1.3/mod_jk.dsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/apache-1.3/mod_jk.dsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/apache-1.3/mod_jk.dsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,287 @@
+# Microsoft Developer Studio Project File - Name="mod_jk" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
+
+CFG=mod_jk - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE 
+!MESSAGE NMAKE /f "mod_jk.mak".
+!MESSAGE 
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE 
+!MESSAGE NMAKE /f "mod_jk.mak" CFG="mod_jk - Win32 Debug"
+!MESSAGE 
+!MESSAGE Possible choices for configuration are:
+!MESSAGE 
+!MESSAGE "mod_jk - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "mod_jk - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE 
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+MTL=midl.exe
+RSC=rc.exe
+
+!IF  "$(CFG)" == "mod_jk - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MD /W3 /O2 /Oy- /Zi /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "MOD_JK_EXPORTS" /FD /c
+# ADD CPP /nologo /MD /W3 /O2 /Oy- /Zi /I "..\common" /I "$(APACHE1_HOME)\include" /I "$(APACHE1_HOME)\src\include" /I "$(APACHE1_HOME)\src\os\win32" /I "$(JAVA_HOME)\include" /I "$(JAVA_HOME)\include\win32" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "MOD_JK_EXPORTS" /Fd"Release\mod_jk_src" /FD /c
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386
+# ADD LINK32 ApacheCore.lib kernel32.lib user32.lib advapi32.lib ws2_32.lib mswsock.lib /nologo /base:"0x6A6B0000" /subsystem:windows /dll /debug /machine:I386 /out:"Release/mod_jk.so" /libpath:"$(APACHE1_HOME)\libexec" /libpath:"$(APACHE1_HOME)\src\CoreR" /libpath:"$(APACHE1_HOME)\src\Release" /opt:ref
+
+!ELSEIF  "$(CFG)" == "mod_jk - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MDd /W3 /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "MOD_JK_EXPORTS" /FD /c
+# ADD CPP /nologo /MDd /W3 /GX /Zi /Od /I "..\common" /I "$(APACHE1_HOME)\include" /I "$(APACHE1_HOME)\src\include" /I "$(APACHE1_HOME)\src\os\win32" /I "$(JAVA_HOME)\include" /I "$(JAVA_HOME)\include\win32" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "MOD_JK_EXPORTS" /Fd"Debug\mod_jk_src" /FD /c
+# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 ApacheCore.lib kernel32.lib user32.lib advapi32.lib ws2_32.lib mswsock.lib /nologo /base:"0x6A6B0000" /subsystem:windows /dll /incremental:no /debug /machine:I386 /out:"Debug/mod_jk.so" /libpath:"$(APACHE1_HOME)\libexec" /libpath:"$(APACHE1_HOME)\src\CoreD" /libpath:"$(APACHE1_HOME)\src\Debug"
+
+!ENDIF 
+
+# Begin Target
+
+# Name "mod_jk - Win32 Release"
+# Name "mod_jk - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# Begin Source File
+
+SOURCE=..\common\jk_ajp12_worker.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_ajp13.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_ajp13_worker.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_ajp14.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_ajp14_worker.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_ajp_common.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_connect.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_context.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_jni_worker.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_lb_worker.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_map.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_md5.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_msg_buff.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_pool.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_shm.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_sockbuf.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_status.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_uri_worker_map.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_util.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_worker.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\mod_jk.c
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl"
+# Begin Source File
+
+SOURCE=..\common\jk_ajp12_worker.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_ajp13.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_ajp13_worker.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_ajp14.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_ajp14_worker.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_ajp_common.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_connect.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_context.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_global.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_jni_worker.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_lb_worker.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_logger.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_map.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_md5.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_msg_buff.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_mt.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_pool.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_service.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_shm.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_sockbuf.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_status.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_uri_worker_map.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_util.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_worker.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_worker_list.h
+# End Source File
+# End Group
+# Begin Group "Resource Files"
+
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
+# End Group
+# End Target
+# End Project

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/apache-1.3/mod_jk.exp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/apache-1.3/mod_jk.exp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/apache-1.3/mod_jk.exp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1 @@
+mod_jk.exp

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/apache-2.0/Makefile.apxs.in
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/apache-2.0/Makefile.apxs.in	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/apache-2.0/Makefile.apxs.in	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,28 @@
+## configure should make the Makefile out of this file.
+
+APXS=@APXS@
+OS=@OS@
+JAVA_HOME=@JAVA_HOME@
+APXSLDFLAGS=@APXSLDFLAGS@
+APXSCFLAGS=@APXSCFLAGS@
+
+JK=../common/
+JK_INCL=-DUSE_APACHE_MD5 -I ${JK}
+JAVA_INCL=-I ${JAVA_HOME}/include -I ${JAVA_HOME}/include/${OS}
+JAVA_LIB=-L ${JAVA_HOME}/jre/lib/${ARCH} -L ${JAVA_HOME}/lib/${ARCH}/native_threads
+
+## read the object (.c) from the list file.
+OEXT=.c
+include ../common/list.mk
+
+all: mod_jk.la
+
+mod_jk.la: 
+	$(APXS)  -c -o $@ -Wc,"${APXSCFLAGS} ${JK_INCL}" "${JAVA_INCL}" "${APXSLDFLAGS}" mod_jk.c ${APACHE_OBJECTS} 
+
+install: mod_jk.la
+	$(APXS) -i mod_jk.la
+ 
+clean:
+	rm -f *.o *.lo *.a *.la *.so *.so.* *.slo
+	rm -rf .libs

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/apache-2.0/Makefile.in
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/apache-2.0/Makefile.in	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/apache-2.0/Makefile.in	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,81 @@
+## 
+
+APXS=@APXS@
+OS=@OS@
+JAVA_HOME=@JAVA_HOME@
+CP=@CP@
+APACHE_DIR=@APACHE_DIR@
+MKDIR=@MKDIR@
+APXSCFLAGS=@APXSCFLAGS@
+APXSCPPFLAGS=@APXSCPPFLAGS@
+CC=@CC@
+
+# Defaults
+libexecdir=${APACHE_DIR}/modules
+
+JK=../common/
+# Defines APACHE_OBJECTS - the list of all common files
+include ../common/list.mk
+
+# Apache2 settings, values guessed by Apache config and used to build it
+# Will define libexecdir, LIBTOOL, etc
+include @APACHE_CONFIG_VARS@
+
+# Local settings ( overriding/appending to Apache's ) 
+COMMON=../common
+JK_INCL=-DUSE_APACHE_MD5 -I ${COMMON} 
+JAVA_INCL=-I ${JAVA_HOME}/include -I ${JAVA_HOME}/include/${OS}
+JAVA_LIB=-L ${JAVA_HOME}/jre/lib/${ARCH} -L ${JAVA_HOME}/lib/${ARCH}/native_threads
+CFLAGS=@apache_include@ @CFLAGS@ ${JK_INCL} ${JAVA_INCL} ${APXSCPPFLAGS} ${APXSCFLAGS} ${EXTRA_CFLAGS} ${EXTRA_CPPFLAGS}
+
+
+# Implicit rules
+include ../scripts/build/rules.mk
+
+OEXT=.lo
+
+all: Makefile @LIB_JK_TYPE@ 
+install: @INSTALL_TYPE@
+
+Makefile: Makefile.in
+	echo Regenerating Makefile
+	( cd ..; ./config.status )
+
+lib_jk.la: mod_jk.lo ${APACHE_OBJECTS}
+	$(LIBTOOL) --mode=link $(CC) -o lib_jk.la -static -rpath ${libexecdir}/jk mod_jk.lo $(APACHE_OBJECTS)
+
+install_static:
+	@echo ""
+	@echo "Copying files to Apache Modules Directory..."
+	-${MKDIR} ${APACHE_DIR}/modules/jk
+	${CP} config.m4 ${APACHE_DIR}/modules/jk
+	${LIBTOOL} --mode=install cp lib_jk.la ${APACHE_DIR}/modules/jk
+	@echo ""
+	@echo "Please be sure to re-compile Apache..."
+	@echo ""
+	@echo "cd ${APACHE_DIR}"
+	@echo "./buildconf"
+	@echo "./configure --with-mod_jk"
+	@echo "make"
+	@echo ""
+
+#################### Dynamic .so file ####################
+# APXS will compile every file, this is derived from apxs
+
+mod_jk.la: mod_jk.lo $(APACHE_OBJECTS)
+	$(LIBTOOL) --mode=link ${COMPILE} `${APXS} -q LDFLAGS` -o $@ -module -rpath ${libexecdir} -avoid-version mod_jk.lo $(APACHE_OBJECTS)
+
+mod_jk.so: mod_jk.la
+	$(LIBTOOL) --mode=install cp mod_jk.la `pwd`/$@
+
+install_dynamic:
+	@echo ""
+	@echo "Installing files to Apache Modules Directory..."
+	$(APXS) -i mod_jk.la
+	@echo ""
+	@echo "Please be sure to arrange ${APACHE_DIR}/conf/httpd.conf..."
+	@echo ""
+
+clean:
+	rm -f *.o *.lo *.a *.la *.so *.so.* *.slo
+	rm -rf .libs

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/apache-2.0/Makefile.vc
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/apache-2.0/Makefile.vc	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/apache-2.0/Makefile.vc	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,276 @@
+# Microsoft Developer Studio Generated NMAKE File, Based on mod_jk.dsp
+!IF "$(CFG)" == ""
+CFG=apache - Win32 Release
+!MESSAGE No configuration specified. Defaulting to apache - Win32 Release.
+!ENDIF 
+
+!IF "$(CFG)" != "apache - Win32 Release"
+!MESSAGE Invalid configuration "$(CFG)" specified.
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE 
+!MESSAGE NMAKE /f "Makefile.vc" CFG="apache - Win32 Release"
+!MESSAGE 
+!MESSAGE Possible choices for configuration are:
+!MESSAGE 
+!MESSAGE "apache - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE 
+!ERROR An invalid configuration is specified.
+!ENDIF 
+
+!IF "$(OS)" == "Windows_NT"
+NULL=
+!ELSE 
+NULL=nul
+!ENDIF 
+
+CPP=cl.exe
+MTL=midl.exe
+RSC=rc.exe
+OUTDIR=.\Release
+INTDIR=.\Release
+# Begin Custom Macros
+OutDir=.\Release
+# End Custom Macros
+
+ALL : "$(OUTDIR)\mod_jk.so"
+
+
+CLEAN :
+	- at erase "$(INTDIR)\jk_ajp12_worker.obj"
+	- at erase "$(INTDIR)\jk_ajp13.obj"
+	- at erase "$(INTDIR)\jk_ajp13_worker.obj"
+	- at erase "$(INTDIR)\jk_ajp14.obj"
+	- at erase "$(INTDIR)\jk_ajp14_worker.obj"
+	- at erase "$(INTDIR)\jk_ajp_common.obj"
+	- at erase "$(INTDIR)\jk_connect.obj"
+	- at erase "$(INTDIR)\jk_context.obj"
+	- at erase "$(INTDIR)\jk_jni_worker.obj"
+	- at erase "$(INTDIR)\jk_lb_worker.obj"
+	- at erase "$(INTDIR)\jk_map.obj"
+	- at erase "$(INTDIR)\jk_md5.obj"
+	- at erase "$(INTDIR)\jk_msg_buff.obj"
+	- at erase "$(INTDIR)\jk_pool.obj"
+	- at erase "$(INTDIR)\jk_shm.obj"
+	- at erase "$(INTDIR)\jk_sockbuf.obj"
+	- at erase "$(INTDIR)\jk_status.obj"
+	- at erase "$(INTDIR)\jk_uri_worker_map.obj"
+	- at erase "$(INTDIR)\jk_util.obj"
+	- at erase "$(INTDIR)\jk_worker.obj"
+	- at erase "$(INTDIR)\mod_jk.obj"
+	- at erase "$(INTDIR)\mod_jk_src.idb"
+	- at erase "$(INTDIR)\mod_jk_src.pdb"
+	- at erase "$(OUTDIR)\mod_jk.exp"
+	- at erase "$(OUTDIR)\mod_jk.lib"
+	- at erase "$(OUTDIR)\mod_jk.pdb"
+	- at erase "$(OUTDIR)\mod_jk.so"
+
+"$(OUTDIR)" :
+    if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+BSC32=bscmake.exe
+BSC32_FLAGS=/nologo /o"$(OUTDIR)\mod_jk.bsc" 
+BSC32_SBRS= \
+	
+LINK32=link.exe
+LINK32_FLAGS=libhttpd.lib libapr.lib libaprutil.lib kernel32.lib user32.lib advapi32.lib wsock32.lib /nologo /base:"0x6A6B0000" /subsystem:windows /dll /incremental:no /pdb:"$(OUTDIR)\mod_jk.pdb" /debug /machine:I386 /out:"$(OUTDIR)\mod_jk.so" /implib:"$(OUTDIR)\mod_jk.lib" /libpath:"$(APACHE2_HOME)\lib" /opt:ref 
+LINK32_OBJS= \
+	"$(INTDIR)\jk_ajp12_worker.obj" \
+	"$(INTDIR)\jk_ajp13.obj" \
+	"$(INTDIR)\jk_ajp13_worker.obj" \
+	"$(INTDIR)\jk_ajp14.obj" \
+	"$(INTDIR)\jk_ajp14_worker.obj" \
+	"$(INTDIR)\jk_ajp_common.obj" \
+	"$(INTDIR)\jk_connect.obj" \
+	"$(INTDIR)\jk_context.obj" \
+	"$(INTDIR)\jk_jni_worker.obj" \
+	"$(INTDIR)\jk_lb_worker.obj" \
+	"$(INTDIR)\jk_map.obj" \
+	"$(INTDIR)\jk_md5.obj" \
+	"$(INTDIR)\jk_msg_buff.obj" \
+	"$(INTDIR)\jk_pool.obj" \
+	"$(INTDIR)\jk_shm.obj" \
+	"$(INTDIR)\jk_sockbuf.obj" \
+	"$(INTDIR)\jk_status.obj" \
+	"$(INTDIR)\jk_uri_worker_map.obj" \
+	"$(INTDIR)\jk_util.obj" \
+	"$(INTDIR)\jk_worker.obj" \
+	"$(INTDIR)\mod_jk.obj"
+
+"$(OUTDIR)\mod_jk.so" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+    $(LINK32) @<<
+  $(LINK32_FLAGS) $(LINK32_OBJS)
+<<
+
+CPP_PROJ=/nologo /MD /W3 /Zi /O2 /I "..\common" /I "$(JAVA_HOME)\include" /I "$(JAVA_HOME)\include\win32" /I "$(APACHE2_HOME)\include" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\mod_jk_src" /FD /c 
+
+.c{$(INTDIR)}.obj::
+   $(CPP) @<<
+   $(CPP_PROJ) $< 
+<<
+
+.cpp{$(INTDIR)}.obj::
+   $(CPP) @<<
+   $(CPP_PROJ) $< 
+<<
+
+.cxx{$(INTDIR)}.obj::
+   $(CPP) @<<
+   $(CPP_PROJ) $< 
+<<
+
+.c{$(INTDIR)}.sbr::
+   $(CPP) @<<
+   $(CPP_PROJ) $< 
+<<
+
+.cpp{$(INTDIR)}.sbr::
+   $(CPP) @<<
+   $(CPP_PROJ) $< 
+<<
+
+.cxx{$(INTDIR)}.sbr::
+   $(CPP) @<<
+   $(CPP_PROJ) $< 
+<<
+
+MTL_PROJ=/nologo /D "NDEBUG" /mktyplib203 /win32 
+
+!IF "$(NO_EXTERNAL_DEPS)" != "1"
+!IF EXISTS("mod_jk.dep")
+!INCLUDE "mod_jk.dep"
+!ELSE 
+!MESSAGE Warning: cannot find "mod_jk.dep"
+!ENDIF 
+!ENDIF 
+
+
+!IF "$(CFG)" == "apache - Win32 Release"
+SOURCE=..\common\jk_ajp12_worker.c
+
+"$(INTDIR)\jk_ajp12_worker.obj" : $(SOURCE) "$(INTDIR)"
+	$(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=..\common\jk_ajp13.c
+
+"$(INTDIR)\jk_ajp13.obj" : $(SOURCE) "$(INTDIR)"
+	$(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=..\common\jk_ajp13_worker.c
+
+"$(INTDIR)\jk_ajp13_worker.obj" : $(SOURCE) "$(INTDIR)"
+	$(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=..\common\jk_ajp14.c
+
+"$(INTDIR)\jk_ajp14.obj" : $(SOURCE) "$(INTDIR)"
+	$(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=..\common\jk_ajp14_worker.c
+
+"$(INTDIR)\jk_ajp14_worker.obj" : $(SOURCE) "$(INTDIR)"
+	$(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=..\common\jk_ajp_common.c
+
+"$(INTDIR)\jk_ajp_common.obj" : $(SOURCE) "$(INTDIR)"
+	$(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=..\common\jk_connect.c
+
+"$(INTDIR)\jk_connect.obj" : $(SOURCE) "$(INTDIR)"
+	$(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=..\common\jk_context.c
+
+"$(INTDIR)\jk_context.obj" : $(SOURCE) "$(INTDIR)"
+	$(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=..\common\jk_jni_worker.c
+
+"$(INTDIR)\jk_jni_worker.obj" : $(SOURCE) "$(INTDIR)"
+	$(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=..\common\jk_lb_worker.c
+
+"$(INTDIR)\jk_lb_worker.obj" : $(SOURCE) "$(INTDIR)"
+	$(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=..\common\jk_map.c
+
+"$(INTDIR)\jk_map.obj" : $(SOURCE) "$(INTDIR)"
+	$(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=..\common\jk_md5.c
+
+"$(INTDIR)\jk_md5.obj" : $(SOURCE) "$(INTDIR)"
+	$(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=..\common\jk_msg_buff.c
+
+"$(INTDIR)\jk_msg_buff.obj" : $(SOURCE) "$(INTDIR)"
+	$(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=..\common\jk_pool.c
+
+"$(INTDIR)\jk_pool.obj" : $(SOURCE) "$(INTDIR)"
+	$(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=..\common\jk_shm.c
+
+"$(INTDIR)\jk_shm.obj" : $(SOURCE) "$(INTDIR)"
+	$(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=..\common\jk_sockbuf.c
+
+"$(INTDIR)\jk_sockbuf.obj" : $(SOURCE) "$(INTDIR)"
+	$(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=..\common\jk_status.c
+
+"$(INTDIR)\jk_status.obj" : $(SOURCE) "$(INTDIR)"
+	$(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=..\common\jk_uri_worker_map.c
+
+"$(INTDIR)\jk_uri_worker_map.obj" : $(SOURCE) "$(INTDIR)"
+	$(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=..\common\jk_util.c
+
+"$(INTDIR)\jk_util.obj" : $(SOURCE) "$(INTDIR)"
+	$(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=..\common\jk_worker.c
+
+"$(INTDIR)\jk_worker.obj" : $(SOURCE) "$(INTDIR)"
+	$(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\mod_jk.c
+
+"$(INTDIR)\mod_jk.obj" : $(SOURCE) "$(INTDIR)"
+
+
+
+!ENDIF 
+

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/apache-2.0/NWGNUmakefile
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/apache-2.0/NWGNUmakefile	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/apache-2.0/NWGNUmakefile	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,316 @@
+#
+# Makefile for mod_jk (uses the build system of Apache2 - gnu make)
+# created by Guenter Knauf <eflash at gmx.net>
+#
+
+#ifeq ($(strip $(JAVA_HOME)),)
+#@echo You must set the JAVA_HOME environment var pointing to the NetWare Java SDK!
+#endif
+
+#
+# Declare the sub-directories to be built here
+#
+
+SUBDIRS = \
+	$(EOLIST)
+
+#
+# Get the 'head' of the build environment.  This includes default targets and
+# paths to tools
+#
+
+include $(AP_WORK)\build\NWGNUhead.inc
+
+#
+# build this level's files
+
+#
+# Make sure all needed macro's are defined
+#
+
+JKCOMMON = ../common
+
+#
+# These directories will be at the beginning of the include list, followed by
+# INCDIRS
+#
+XINCDIRS	+= \
+			$(JKCOMMON) \
+			$(AP_WORK)/include \
+			$(NWOS) \
+			$(AP_WORK)/modules/arch/netware \
+			$(APR)/include \
+			$(APRUTIL)/include \
+			$(APR) \
+			$(JAVA_HOME)/include \
+			$(JAVA_HOME)/include/netware \
+			$(EOLIST)
+
+#
+# These flags will come after CFLAGS
+#
+XCFLAGS		+= \
+			$(EOLIST)
+
+#
+# These defines will come after DEFINES
+#
+XDEFINES	+= \
+			-D__NOVELL_LIBC__ \
+			-D_POSIX_SOURCE \
+			$(EOLIST)
+
+#
+# These flags will be added to the link.opt file
+#
+XLFLAGS		+= \
+			$(EOLIST)
+
+#
+# These values will be appended to the correct variables based on the value of
+# RELEASE
+#
+ifeq "$(RELEASE)" "debug"
+XINCDIRS	+= \
+			$(EOLIST)
+
+XCFLAGS		+= \
+			$(EOLIST)
+
+XDEFINES	+= \
+			$(EOLIST)
+
+XLFLAGS		+= \
+		   	$(EOLIST)
+endif
+
+ifeq "$(RELEASE)" "noopt"
+XINCDIRS	+= \
+			$(EOLIST)
+
+XCFLAGS		+= \
+			$(EOLIST)
+
+XDEFINES	+= \
+			$(EOLIST)
+
+XLFLAGS		+= \
+		   	$(EOLIST)
+endif
+
+ifeq "$(RELEASE)" "release"
+XINCDIRS	+= \
+			$(EOLIST)
+
+XCFLAGS		+= \
+			$(EOLIST)
+
+XDEFINES	+= \
+			$(EOLIST)
+
+XLFLAGS		+= \
+			$(EOLIST)
+endif
+
+#
+# These are used by the link target if an NLM is being generated
+# This is used by the link 'name' directive to name the nlm.  If left blank
+# TARGET_nlm (see below) will be used.
+#
+NLM_NAME		= mod_jk
+
+#
+# This is used by the link '-desc ' directive.
+# If left blank, NLM_NAME will be used.
+#
+NLM_DESCRIPTION	= Apache $(VERSION_STR) plugin for Tomcat $(JK_VERSION_STR)
+
+#
+# This is used by the link '-copy ' directive.
+# If left blank, the ASF copyright defined in NWGNUtail.inc will be used.
+#
+NLM_COPYRIGHT	=
+
+#
+# This is used by the '-threadname' directive.  If left blank,
+# NLM_NAME Thread will be used.
+#
+NLM_THREAD_NAME	= JK Module
+
+#
+# If this is specified, it will override VERSION value in
+# $(AP_WORK)\build\NWGNUenvironment.inc
+#
+NLM_VERSION	= $(JK_VERSION)
+
+#
+# If this is specified, it will override the default of 64K
+#
+NLM_STACK_SIZE	= 49152
+
+
+#
+# If this is specified it will be used by the link '-entry' directive
+#
+NLM_ENTRY_SYM	= _LibCPrelude
+
+#
+# If this is specified it will be used by the link '-exit' directive
+#
+NLM_EXIT_SYM	= _LibCPostlude
+
+#
+# If this is specified it will be used by the link '-check' directive
+#
+NLM_CHECK_SYM	=
+
+#
+# If these are specified it will be used by the link '-flags' directive
+#
+NLM_FLAGS		=  AUTOUNLOAD, PSEUDOPREEMPTION
+
+#
+# If this is specified it will be linked in with the XDCData option in the def
+# file instead of the default of $(NWOS)/apache.xdc.  XDCData can be disabled
+# by setting APACHE_UNIPROC in the environment
+#
+XDCDATA         =
+
+#
+# If there is an NLM target, put it here
+#
+TARGET_nlm = \
+	$(OBJDIR)/mod_jk.nlm \
+	$(EOLIST)
+
+#
+# If there is an LIB target, put it here
+#
+TARGET_lib = \
+	$(EOLIST)
+
+#
+# These are the OBJ files needed to create the NLM target above.
+# Paths must all use the '/' character
+#
+FILES_nlm_objs = \
+	$(OBJDIR)/jk_nwmain.o \
+	$(OBJDIR)/jk_ajp12_worker.o \
+	$(OBJDIR)/jk_ajp13.o \
+	$(OBJDIR)/jk_ajp13_worker.o \
+	$(OBJDIR)/jk_ajp14.o \
+	$(OBJDIR)/jk_ajp14_worker.o \
+	$(OBJDIR)/jk_ajp_common.o \
+	$(OBJDIR)/jk_connect.o \
+	$(OBJDIR)/jk_context.o \
+	$(OBJDIR)/jk_jni_worker.o \
+	$(OBJDIR)/jk_lb_worker.o \
+	$(OBJDIR)/jk_map.o \
+	$(OBJDIR)/jk_md5.o \
+	$(OBJDIR)/jk_msg_buff.o \
+	$(OBJDIR)/jk_pool.o \
+	$(OBJDIR)/jk_shm.o \
+	$(OBJDIR)/jk_sockbuf.o \
+	$(OBJDIR)/jk_status.o \
+	$(OBJDIR)/jk_uri_worker_map.o \
+	$(OBJDIR)/jk_util.o \
+	$(OBJDIR)/jk_worker.o \
+	$(OBJDIR)/mod_jk.o \
+	$(EOLIST)
+
+#
+# These are the LIB files needed to create the NLM target above.
+# These will be added as a library command in the link.opt file.
+#
+FILES_nlm_libs = \
+   	libcpre.o \
+	$(EOLIST)
+
+#
+# These are the modules that the above NLM target depends on to load.
+# These will be added as a module command in the link.opt file.
+#
+FILES_nlm_modules = \
+	aprlib \
+	libc \
+	$(EOLIST)
+
+#
+# If the nlm has a msg file, put it's path here
+#
+FILE_nlm_msg =
+
+#
+# If the nlm has a hlp file put it's path here
+#
+FILE_nlm_hlp =
+
+#
+# If this is specified, it will override $(NWOS)\copyright.txt.
+#
+FILE_nlm_copyright =
+
+#
+# Any additional imports go here
+#
+FILES_nlm_Ximports = \
+	@$(APR)/aprlib.imp \
+	@$(NWOS)/httpd.imp \
+	@libc.imp \
+	@ws2nlm.imp \
+	$(EOLIST)
+
+#
+# Any symbols exported to here
+#
+FILES_nlm_exports = \
+	jk_module \
+	$(EOLIST)
+
+#
+# These are the OBJ files needed to create the LIB target above.
+# Paths must all use the '/' character
+#
+FILES_lib_objs = \
+	$(EOLIST)
+
+#
+# implement targets and dependancies (leave this section alone)
+#
+
+libs :: $(OBJDIR) $(TARGET_lib)
+
+nlms :: libs $(TARGET_nlm)
+
+#
+# Updated this target to create necessary directories and copy files to the
+# correct place.  (See $(AP_WORK)\build\NWGNUhead.inc for examples)
+#
+install :: nlms FORCE
+	copy $(OBJDIR)\*.nlm $(INSTALL)\Apache2\modules\*.*
+
+#
+# Any specialized rules here
+#
+
+vpath %.c $(JKCOMMON)
+
+$(OBJDIR)/version.inc: $(JKCOMMON)/jk_version.h $(OBJDIR)
+	@echo Creating $@
+	@awk -f ../../support/get_ver.awk $< > $@
+
+
+#
+# Include the version info retrieved from jk_version.h
+#
+
+-include $(OBJDIR)/version.inc
+
+#
+# Include the 'tail' makefile that has targets that depend on variables defined
+# in this makefile
+#
+
+include $(AP_WORK)\build\NWGNUtail.inc
+
+

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/apache-2.0/bldjk.qclsrc
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/apache-2.0/bldjk.qclsrc	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/apache-2.0/bldjk.qclsrc	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,320 @@
+PGM
+CRTCMOD MODULE(MOD_JK/MOD_JK) +
+	SRCSTMF('/home/apache/jk/native/apache-2.0/mod_jk.c') +
+	DEFINE('AS400' 'HAVE_JNI' 'HAVE_APR' '_XOPEN_SOURCE=520' + 
+	       'USE_APACHE_MD5' '_REENTRANT') +
+	TEXT('mod_jk.c') +
+	OPTIMIZE(40) +
+	SYSIFCOPT(*IFSIO) +
+	TGTCCSID(*JOB) +
+	OPTION(*LOGMSG) +
+	TERASPACE(*YES *TSIFC) +
+	STGMDL(*INHERIT) +
+    INCDIR('/home/apache/jk/native/common' '/QIBM/ProdData/HTTPA/Include')
+
+CRTCMOD MODULE(MOD_JK/JK_AJP_COM) +
+    SRCSTMF('/home/apache/jk/native/common/jk_ajp_common.c') +
+    DEFINE('AS400' 'HAVE_JNI' 'HAVE_APR' '_XOPEN_SOURCE=520' +  
+           'USE_APACHE_MD5' '_REENTRANT') +
+    TEXT('jk_ajp_common.c') +
+    OPTIMIZE(40) +
+    SYSIFCOPT(*IFSIO) +
+    LANGLVL(*ANSI) +
+    TGTCCSID(*JOB) +
+    OPTION(*LOGMSG) +
+    TERASPACE(*YES *TSIFC) +
+    STGMDL(*INHERIT) +
+    INCDIR('/home/apache/jk/native/common' '/QIBM/ProdData/HTTPA/Include')
+
+CRTCMOD MODULE(MOD_JK/JK_AJP12_W) +
+    SRCSTMF('/home/apache/jk/native/common/jk_ajp12_worker.c') +
+    DEFINE('AS400' 'HAVE_JNI' 'HAVE_APR' '_XOPEN_SOURCE=520' +  
+           'USE_APACHE_MD5' '_REENTRANT') +
+    TEXT('jk_ajp12_worker.c') +
+    OPTIMIZE(40) +
+    SYSIFCOPT(*IFSIO) +
+    LANGLVL(*ANSI) +
+    TGTCCSID(*JOB) +
+    OPTION(*LOGMSG) +
+    TERASPACE(*YES *TSIFC) +
+    STGMDL(*INHERIT) +
+    INCDIR('/home/apache/jk/native/common' '/QIBM/ProdData/HTTPA/Include')
+
+CRTCMOD MODULE(MOD_JK/JK_AJP13) +
+    SRCSTMF('/home/apache/jk/native/common/jk_ajp13.c') +
+    DEFINE('AS400' 'HAVE_JNI' 'HAVE_APR' '_XOPEN_SOURCE=520' +   
+           'USE_APACHE_MD5' '_REENTRANT') +
+    TEXT('jk_ajp13.c') +
+    OPTIMIZE(40) +
+    SYSIFCOPT(*IFSIO) +
+    LANGLVL(*ANSI) +
+    TGTCCSID(*JOB) +
+    OPTION(*LOGMSG) +
+    TERASPACE(*YES *TSIFC) +
+    STGMDL(*INHERIT) +
+    INCDIR('/home/apache/jk/native/common' '/QIBM/ProdData/HTTPA/Include')
+
+CRTCMOD MODULE(MOD_JK/JK_AJP13_W) +
+    SRCSTMF('/home/apache/jk/native/common/jk_ajp13_worker.c') +
+    DEFINE('AS400' 'HAVE_JNI' 'HAVE_APR' '_XOPEN_SOURCE=520' +  
+           'USE_APACHE_MD5' '_REENTRANT') +
+    TEXT('jk_ajp13_worker.c') +
+    OPTIMIZE(40) +
+    SYSIFCOPT(*IFSIO) +
+    LANGLVL(*ANSI) +
+    TGTCCSID(*JOB) +
+    OPTION(*LOGMSG) +
+    TERASPACE(*YES *TSIFC) +
+    STGMDL(*INHERIT) +
+    INCDIR('/home/apache/jk/native/common' '/QIBM/ProdData/HTTPA/Include')
+
+CRTCMOD MODULE(MOD_JK/JK_AJP14) +
+    SRCSTMF('/home/apache/jk/native/common/jk_ajp14.c') +
+    DEFINE('AS400' 'HAVE_JNI' 'HAVE_APR' '_XOPEN_SOURCE=520' +  
+           'USE_APACHE_MD5' '_REENTRANT') +
+    TEXT('jk_ajp14.c') +
+    OPTIMIZE(40) +
+    SYSIFCOPT(*IFSIO) +
+    LANGLVL(*ANSI) +
+    TGTCCSID(*JOB) +
+    OPTION(*LOGMSG) +
+    TERASPACE(*YES *TSIFC) +
+    STGMDL(*INHERIT) +
+    INCDIR('/home/apache/jk/native/common' '/QIBM/ProdData/HTTPA/Include')
+
+CRTCMOD MODULE(MOD_JK/JK_AJP14_W) +
+    SRCSTMF('/home/apache/jk/native/common/jk_ajp14_worker.c') +
+    DEFINE('AS400' 'HAVE_JNI' 'HAVE_APR' '_XOPEN_SOURCE=520' +  
+           'USE_APACHE_MD5' '_REENTRANT') +
+    TEXT('jk_ajp14_worker.c') +
+    OPTIMIZE(40) +
+    SYSIFCOPT(*IFSIO) +
+    LANGLVL(*ANSI) +
+    TGTCCSID(*JOB) +
+    OPTION(*LOGMSG) +
+    TERASPACE(*YES *TSIFC) +
+    STGMDL(*INHERIT) +
+    INCDIR('/home/apache/jk/native/common' '/QIBM/ProdData/HTTPA/Include')
+
+CRTCMOD MODULE(MOD_JK/JK_CONNECT) +
+    SRCSTMF('/home/apache/jk/native/common/jk_connect.c') +
+    DEFINE('AS400' 'HAVE_JNI' 'HAVE_APR' '_XOPEN_SOURCE=520' +  
+           'USE_APACHE_MD5' '_REENTRANT' 'USE_SO_RCVTIMEO' +
+           'USE_SO_SNDTIMEO' ) +
+    TEXT('jk_connect.c') +
+    OPTIMIZE(40) +
+    SYSIFCOPT(*IFSIO) +
+    LANGLVL(*ANSI) +
+    TGTCCSID(*JOB) +
+    OPTION(*LOGMSG) +
+    TERASPACE(*YES *TSIFC) +
+    STGMDL(*INHERIT) +
+    INCDIR('/home/apache/jk/native/common' '/QIBM/ProdData/HTTPA/Include')
+
+CRTCMOD MODULE(MOD_JK/JK_CONTEXT) +
+    SRCSTMF('/home/apache/jk/native/common/jk_context.c') +
+    DEFINE('AS400' 'HAVE_JNI' 'HAVE_APR' '_XOPEN_SOURCE=520' +  
+           'USE_APACHE_MD5' '_REENTRANT') +
+    TEXT('jk_context.c') +
+    OPTIMIZE(40) +
+    SYSIFCOPT(*IFSIO) +
+    LANGLVL(*ANSI) +
+    TGTCCSID(*JOB) +
+    OPTION(*LOGMSG) +
+    TERASPACE(*YES *TSIFC) +
+    STGMDL(*INHERIT) +
+    INCDIR('/home/apache/jk/native/common' '/QIBM/ProdData/HTTPA/Include')
+
+CRTCMOD MODULE(MOD_JK/JK_JNI_WOR) +
+    SRCSTMF('/home/apache/jk/native/common/jk_jni_worker.c') +
+    DEFINE('AS400' 'HAVE_JNI' 'HAVE_APR' 'OS400_JVM_12' + 
+           '_XOPEN_SOURCE=520' +  'USE_APACHE_MD5' +
+    '_REENTRANT') +
+    TEXT('jk_jni_worker.c') +
+    OPTIMIZE(40) +
+    SYSIFCOPT(*IFSIO) +
+    LANGLVL(*ANSI) +
+    TGTCCSID(*JOB) +
+    OPTION(*LOGMSG ) +
+    TERASPACE(*YES *TSIFC) +
+    STGMDL(*INHERIT) +
+    INCDIR('/home/apache/jk/native/common' '/QIBM/ProdData/HTTPA/Include')
+
+CRTCMOD MODULE(MOD_JK/JK_LB_WORK) +
+    SRCSTMF('/home/apache/jk/native/common/jk_lb_worker.c') +
+    DEFINE('AS400' 'HAVE_JNI' 'HAVE_APR' '_XOPEN_SOURCE=520' +  
+           'USE_APACHE_MD5' '_REENTRANT') +
+    TEXT('jk_lb_worker.c') +
+    OPTIMIZE(40) +
+    SYSIFCOPT(*IFSIO) +
+    LANGLVL(*ANSI) +
+    TGTCCSID(*JOB) +
+    OPTION(*LOGMSG) +
+    TERASPACE(*YES *TSIFC) +
+    STGMDL(*INHERIT) +
+    INCDIR('/home/apache/jk/native/common' '/QIBM/ProdData/HTTPA/Include')
+
+CRTCMOD MODULE(MOD_JK/JK_MAP) +
+    SRCSTMF('/home/apache/jk/native/common/jk_map.c') +
+    DEFINE('AS400' 'HAVE_JNI' 'HAVE_APR' '_XOPEN_SOURCE=520' +  
+           'USE_APACHE_MD5' '_REENTRANT') +
+    TEXT('jk_map.c') +
+    OPTIMIZE(40) +
+    SYSIFCOPT(*IFSIO) +
+    LANGLVL(*ANSI) +
+    TGTCCSID(*JOB) +
+    OPTION(*LOGMSG) +
+    TERASPACE(*YES *TSIFC) +
+    STGMDL(*INHERIT) +
+    INCDIR('/home/apache/jk/native/common' '/QIBM/ProdData/HTTPA/Include')
+
+CRTCMOD MODULE(MOD_JK/JK_MD5) +
+    SRCSTMF('/home/apache/jk/native/common/jk_md5.c') +
+    DEFINE('AS400' 'HAVE_JNI' 'HAVE_APR' '_XOPEN_SOURCE=520' +  
+           'USE_APACHE_MD5' '_REENTRANT') +
+    TEXT('jk_md5.c') +
+    OPTIMIZE(40) +
+    SYSIFCOPT(*IFSIO) +
+    LANGLVL(*ANSI) +
+    TGTCCSID(*JOB) +
+    OPTION(*LOGMSG) +
+    TERASPACE(*YES *TSIFC) +
+    STGMDL(*INHERIT) +
+    INCDIR('/home/apache/jk/native/common' '/QIBM/ProdData/HTTPA/Include')
+
+CRTCMOD MODULE(MOD_JK/JK_MSG_BUF) +
+    SRCSTMF('/home/apache/jk/native/common/jk_msg_buff.c') +
+    DEFINE('AS400' 'HAVE_JNI' 'HAVE_APR' '_XOPEN_SOURCE=520' +  
+           'USE_APACHE_MD5' '_REENTRANT') +
+    TEXT('jk_msg_buff.c') +
+    OPTIMIZE(40) +
+    SYSIFCOPT(*IFSIO) +
+    LANGLVL(*ANSI) +
+    TGTCCSID(*JOB) +
+    OPTION(*LOGMSG) +
+    TERASPACE(*YES *TSIFC) +
+    STGMDL(*INHERIT) +
+    INCDIR('/home/apache/jk/native/common' '/QIBM/ProdData/HTTPA/Include')
+
+CRTCMOD MODULE(MOD_JK/JK_POOL) +
+    SRCSTMF('/home/apache/jk/native/common/jk_pool.c') +
+    DEFINE('AS400' 'HAVE_JNI' 'HAVE_APR' '_XOPEN_SOURCE=520' +  
+           'USE_APACHE_MD5' '_REENTRANT') +
+    TEXT('jk_pool.c') +
+    OPTIMIZE(40) +
+    SYSIFCOPT(*IFSIO) +
+    LANGLVL(*ANSI) +
+    TGTCCSID(*JOB) +
+    OPTION(*LOGMSG) +
+    TERASPACE(*YES *TSIFC) +
+    STGMDL(*INHERIT) +
+    INCDIR('/home/apache/jk/native/common' '/QIBM/ProdData/HTTPA/Include')
+
+CRTCMOD MODULE(MOD_JK/JK_SOCKBUF) +
+    SRCSTMF('/home/apache/jk/native/common/jk_sockbuf.c') +
+    DEFINE('AS400' 'HAVE_JNI' 'HAVE_APR' '_XOPEN_SOURCE=520' +  
+           'USE_APACHE_MD5' '_REENTRANT') +
+    TEXT('jk_sockbuf.c') +
+    OPTIMIZE(40) +
+    SYSIFCOPT(*IFSIO) +
+    LANGLVL(*ANSI) +
+    TGTCCSID(*JOB) +
+    OPTION(*LOGMSG) +
+    TERASPACE(*YES *TSIFC) +
+    STGMDL(*INHERIT) +
+    INCDIR('/home/apache/jk/native/common' '/QIBM/ProdData/HTTPA/Include')
+
+CRTCMOD MODULE(MOD_JK/JK_URI_W_M) +
+    SRCSTMF('/home/apache/jk/native/common/jk_uri_worker_map.c') +
+    DEFINE('AS400' 'HAVE_JNI' 'HAVE_APR' '_XOPEN_SOURCE=520' +  
+           'USE_APACHE_MD5' '_REENTRANT') +
+    TEXT('jk_uri_worker_map.c') +
+    OPTIMIZE(40) +
+    SYSIFCOPT(*IFSIO) +
+    LANGLVL(*ANSI) +
+    TGTCCSID(*JOB) +
+    OPTION(*LOGMSG) +
+    TERASPACE(*YES *TSIFC) +
+    STGMDL(*INHERIT) +
+    INCDIR('/home/apache/jk/native/common' '/QIBM/ProdData/HTTPA/Include')
+
+CRTCMOD MODULE(MOD_JK/JK_UTIL) +
+    SRCSTMF('/home/apache/jk/native/common/jk_util.c') +
+    DEFINE('AS400' 'HAVE_JNI' 'HAVE_APR' '_XOPEN_SOURCE=520' +  
+           'USE_APACHE_MD5' '_REENTRANT') +
+    TEXT('jk_util.c') +
+    OPTIMIZE(40) +
+    SYSIFCOPT(*IFSIO) +
+    LANGLVL(*ANSI) +
+    TGTCCSID(*JOB) +
+    OPTION(*LOGMSG) +
+    TERASPACE(*YES *TSIFC) +
+    STGMDL(*INHERIT) +
+    INCDIR('/home/apache/jk/native/common' '/QIBM/ProdData/HTTPA/Include')
+
+CRTCMOD MODULE(MOD_JK/JK_WORKER) +
+    SRCSTMF('/home/apache/jk/native/common/jk_worker.c') +
+    DEFINE('AS400' 'HAVE_JNI' 'HAVE_APR' '_XOPEN_SOURCE=520' +  
+           'USE_APACHE_MD5' '_REENTRANT') +
+    TEXT('jk_worker.c') +
+    OPTIMIZE(40) +
+    SYSIFCOPT(*IFSIO) +
+    LANGLVL(*ANSI) +
+    TGTCCSID(*JOB) +
+    OPTION(*LOGMSG) +
+    TERASPACE(*YES *TSIFC) +
+    STGMDL(*INHERIT) +
+    INCDIR('/home/apache/jk/native/common' '/QIBM/ProdData/HTTPA/Include')
+
+CRTCMOD MODULE(MOD_JK/JK_STATUS) +
+    SRCSTMF('/home/apache/jk/native/common/jk_status.c') +
+    DEFINE('AS400' 'HAVE_JNI' 'HAVE_APR' '_XOPEN_SOURCE=520' +
+           'USE_APACHE_MD5' '_REENTRANT') +
+    TEXT('jk_status.c') +
+    OPTIMIZE(40) +
+    SYSIFCOPT(*IFSIO) +
+    LANGLVL(*ANSI) +
+    TGTCCSID(*JOB) +
+    OPTION(*LOGMSG) +
+    TERASPACE(*YES *TSIFC) +
+    STGMDL(*INHERIT) +
+    INCDIR('/home/apache/jk/native/common' '/QIBM/ProdData/HTTPA/Include')
+
+CRTCMOD MODULE(MOD_JK/JK_SHM) +
+    SRCSTMF('/home/apache/jk/native/common/jk_shm.c') +
+    DEFINE('AS400' 'HAVE_JNI' 'HAVE_APR' '_XOPEN_SOURCE=520' +
+           'USE_APACHE_MD5' '_REENTRANT') +
+    TEXT('jk_shm.c') +
+    OPTIMIZE(40) +
+    SYSIFCOPT(*IFSIO) +
+    LANGLVL(*ANSI) +
+    TGTCCSID(*JOB) +
+    OPTION(*LOGMSG) +
+    TERASPACE(*YES *TSIFC) +
+    STGMDL(*INHERIT) +
+    INCDIR('/home/apache/jk/native/common' '/QIBM/ProdData/HTTPA/Include')
+
+CRTSRVPGM SRVPGM(MOD_JK/MOD_JK) +
+      MODULE(MOD_JK/MOD_JK +
+             MOD_JK/JK_AJP_COM MOD_JK/JK_AJP12_W +
+             MOD_JK/JK_AJP13 MOD_JK/JK_AJP13_W +
+             MOD_JK/JK_AJP14 MOD_JK/JK_AJP14_W +
+             MOD_JK/JK_CONNECT MOD_JK/JK_CONTEXT +
+             MOD_JK/JK_JNI_WOR MOD_JK/JK_LB_WORK +
+             MOD_JK/JK_MAP MOD_JK/JK_MD5 +
+             MOD_JK/JK_MSG_BUF MOD_JK/JK_POOL +
+             MOD_JK/JK_SOCKBUF MOD_JK/JK_URI_W_M +
+             MOD_JK/JK_UTIL MOD_JK/JK_WORKER +
+             MOD_JK/JK_STATUS MOD_JK/JK_SHM) +
+      EXPORT(*SRCFILE) +
+      BNDDIR() +
+      SRCFILE(MOD_JK/QSRVSRC) +
+      SRCMBR(MOD_JK) +
+      DETAIL(*BASIC) +
+      STGMDL(*INHERIT) +
+      ACTGRP(*CALLER) +
+      BNDSRVPGM(QHTTPSVR/QZSRAPR QHTTPSVR/QZSRCORE +
+                QHTTPSVR/QZSRXMLP QHTTPSVR/QZSRSDBM) +
+      TEXT('Apache mod_jk tomcat connector module')
+
+ENDPGM

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/apache-2.0/config.m4
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/apache-2.0/config.m4	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/apache-2.0/config.m4	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,18 @@
+AC_MSG_CHECKING(for mod_jk module)
+AC_ARG_WITH(mod_jk,
+  [  --with-mod_jk  Include the mod_jk (static).],
+  [
+    modpath_current=modules/jk
+    module=jk
+    libname=lib_jk.la
+    BUILTIN_LIBS="$BUILTIN_LIBS $modpath_current/$libname"
+    cat >>$modpath_current/modules.mk<<EOF
+DISTCLEAN_TARGETS = modules.mk
+static = $libname
+shared =
+EOF
+  MODLIST="$MODLIST $module"
+  AC_MSG_RESULT(added $withval)
+  ],
+  [ AC_MSG_RESULT(no mod_jk added) 
+  ])

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/apache-2.0/mod_jk.c
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/apache-2.0/mod_jk.c	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/apache-2.0/mod_jk.c	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,2782 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.
+ */
+
+/***************************************************************************
+ * Description: Apache 2 plugin for Tomcat                                 *
+ * Author:      Gal Shachor <shachor at il.ibm.com>                           *
+ *              Henri Gomez <hgomez at apache.org>                            *
+ * Version:     $Revision: 440636 $                                          *
+ ***************************************************************************/
+
+/*
+ * mod_jk: keeps all servlet related ramblings together.
+ */
+
+#include "ap_config.h"
+#include "apr_lib.h"
+#include "apr_date.h"
+#include "apr_file_info.h"
+#include "apr_file_io.h"
+#include "httpd.h"
+#include "http_config.h"
+#include "http_request.h"
+#include "http_core.h"
+#include "http_protocol.h"
+#include "http_main.h"
+#include "http_log.h"
+#include "util_script.h"
+#include "ap_mpm.h"
+
+#ifdef AS400
+#include "ap_charset.h"
+#include "util_charset.h"       /* ap_hdrs_from_ascii */
+#endif
+
+/* moved to apr since http-2.0.19-dev */
+#if (MODULE_MAGIC_NUMBER_MAJOR < 20010523)
+#define apr_date_parse_http ap_parseHTTPdate
+#include "util_date.h"
+#endif
+
+/* deprecated with apr 0.9.3 */
+
+/*
+   The latest Apache 2.0.47 for iSeries didn't export apr_filepath_name_get
+   but apr_filename_of_pathname, even if includes seems right and the APR
+   in use is 0.9.4
+*/
+
+#include "apr_version.h"
+#if (APR_MAJOR_VERSION == 0) && \
+    (APR_MINOR_VERSION <= 9) && \
+    (APR_PATCH_VERSION < 3) || defined(AS400)
+#define apr_filepath_name_get apr_filename_of_pathname
+#endif
+
+#include "apr_strings.h"
+
+/* Yes; sorta sucks - with luck we will clean this up before httpd-2.2
+ * ships, leaving AP_NEED_SET_MUTEX_PERMS def'd as 1 or 0 on all platforms.
+ */
+#ifdef AP_NEED_SET_MUTEX_PERMS
+# define JK_NEED_SET_MUTEX_PERMS AP_NEED_SET_MUTEX_PERMS
+#else
+  /* A special case for httpd-2.0 */
+# if !defined(OS2) && !defined(WIN32) && !defined(BEOS) && !defined(NETWARE) && !defined(AS400)
+#  define JK_NEED_SET_MUTEX_PERMS 1
+# else
+#  define JK_NEED_SET_MUTEX_PERMS 0
+# endif
+#endif
+
+#if JK_NEED_SET_MUTEX_PERMS
+#include "unixd.h"      /* for unixd_set_global_mutex_perms */
+#endif
+/*
+ * jk_ include files
+ */
+#ifdef NETWARE
+#define __sys_types_h__
+#define __sys_socket_h__
+#define __netdb_h__
+#define __netinet_in_h__
+#define __arpa_inet_h__
+#define __sys_timeval_h__
+#endif
+
+#include "jk_global.h"
+#include "jk_ajp13.h"
+#include "jk_logger.h"
+#include "jk_map.h"
+#include "jk_pool.h"
+#include "jk_service.h"
+#include "jk_uri_worker_map.h"
+#include "jk_util.h"
+#include "jk_worker.h"
+#include "jk_shm.h"
+
+#define JK_NOTE_WORKER_NAME         ("JK_WORKER_NAME")
+#define JK_NOTE_WORKER_TYPE         ("JK_WORKER_TYPE")
+#define JK_NOTE_REQUEST_DURATION    ("JK_REQUEST_DURATION")
+#define JK_NOTE_WORKER_ROUTE        ("JK_WORKER_ROUTE")
+#define JK_HANDLER          ("jakarta-servlet")
+#define JK_MAGIC_TYPE       ("application/x-jakarta-servlet")
+#define NULL_FOR_EMPTY(x)   ((x && !strlen(x)) ? NULL : x)
+#define STRNULL_FOR_NULL(x) ((x) ? (x) : "(null)")
+/*
+ * If you are not using SSL, comment out the following line. It will make
+ * apache run faster.
+ *
+ * Personally, I (DM), think this may be a lie.
+ */
+#define ADD_SSL_INFO
+
+/* module MODULE_VAR_EXPORT jk_module; */
+AP_MODULE_DECLARE_DATA module jk_module;
+
+typedef struct
+{
+
+    /*
+     * Log stuff
+     */
+    char *log_file;
+    int log_level;
+    jk_logger_t *log;
+    apr_file_t *jklogfp;
+
+    /*
+     * Worker stuff
+     */
+    jk_map_t *worker_properties;
+    char *worker_file;
+    char *mount_file;
+    jk_map_t *uri_to_context;
+
+    int mountcopy;
+    char *secret_key;
+    jk_map_t *automount;
+
+    jk_uri_worker_map_t *uw_map;
+
+    int was_initialized;
+
+    /*
+     * Automatic context path apache alias
+     */
+    char *alias_dir;
+
+    /*
+     * Request Logging
+     */
+
+    char *format_string;
+    apr_array_header_t *format;
+
+    /*
+     * SSL Support
+     */
+    int ssl_enable;
+    char *https_indicator;
+    char *certs_indicator;
+    char *cipher_indicator;
+    char *session_indicator;    /* Servlet API 2.3 requirement */
+    char *key_size_indicator;   /* Servlet API 2.3 requirement */
+
+    /*
+     * Jk Options
+     */
+    int options;
+
+    /*
+     * Environment variables support
+     */
+    int envvars_in_use;
+    apr_table_t *envvars;
+
+    server_rec *s;
+} jk_server_conf_t;
+
+struct apache_private_data
+{
+    jk_pool_t p;
+
+    int response_started;
+    int read_body_started;
+    request_rec *r;
+};
+typedef struct apache_private_data apache_private_data_t;
+
+static jk_logger_t *main_log = NULL;
+static jk_worker_env_t worker_env;
+static apr_global_mutex_t *jk_log_lock = NULL;
+static char *jk_shm_file = NULL;
+static size_t jk_shm_size = JK_SHM_DEF_SIZE;
+
+static int JK_METHOD ws_start_response(jk_ws_service_t *s,
+                                       int status,
+                                       const char *reason,
+                                       const char *const *header_names,
+                                       const char *const *header_values,
+                                       unsigned num_of_headers);
+
+static int JK_METHOD ws_read(jk_ws_service_t *s,
+                             void *b, unsigned len, unsigned *actually_read);
+
+static void init_jk(apr_pool_t * pconf, jk_server_conf_t * conf,
+                    server_rec * s);
+
+static int JK_METHOD ws_write(jk_ws_service_t *s, const void *b, unsigned l);
+
+static void JK_METHOD ws_add_log_items(jk_ws_service_t *s,
+                                       const char *const *log_names,
+                                       const char *const *log_values,
+                                       unsigned num_of_log_items);
+
+/* ========================================================================= */
+/* JK Service step callbacks                                                 */
+/* ========================================================================= */
+
+static int JK_METHOD ws_start_response(jk_ws_service_t *s,
+                                       int status,
+                                       const char *reason,
+                                       const char *const *header_names,
+                                       const char *const *header_values,
+                                       unsigned num_of_headers)
+{
+    unsigned h;
+    apache_private_data_t *p = s->ws_private;
+    request_rec *r = p->r;
+
+    if (!reason) {
+        reason = "";
+    }
+    r->status = status;
+    r->status_line = apr_psprintf(r->pool, "%d %s", status, reason);
+
+    for (h = 0; h < num_of_headers; h++) {
+        if (!strcasecmp(header_names[h], "Content-type")) {
+            char *tmp = apr_pstrdup(r->pool, header_values[h]);
+            ap_content_type_tolower(tmp);
+            /* It should be done like this in Apache 2.0 */
+            /* This way, Apache 2.0 will be able to set the output filter */
+            /* and it make jk useable with deflate using */
+            /* AddOutputFilterByType DEFLATE text/html */
+            ap_set_content_type(r, tmp);
+        }
+        else if (!strcasecmp(header_names[h], "Location")) {
+#ifdef AS400
+            /* Fix escapes in Location Header URL */
+            ap_fixup_escapes((char *)header_values[h],
+                             strlen(header_values[h]), ap_hdrs_from_ascii);
+#endif
+            apr_table_set(r->headers_out, header_names[h], header_values[h]);
+        }
+        else if (!strcasecmp(header_names[h], "Content-Length")) {
+            apr_table_set(r->headers_out, header_names[h], header_values[h]);
+        }
+        else if (!strcasecmp(header_names[h], "Transfer-Encoding")) {
+            apr_table_set(r->headers_out, header_names[h], header_values[h]);
+        }
+        else if (!strcasecmp(header_names[h], "Last-Modified")) {
+            /*
+             * If the script gave us a Last-Modified header, we can't just
+             * pass it on blindly because of restrictions on future values.
+             */
+            ap_update_mtime(r, apr_date_parse_http(header_values[h]));
+            ap_set_last_modified(r);
+        }
+        else {
+            apr_table_add(r->headers_out, header_names[h], header_values[h]);
+        }
+    }
+
+    /* this NOP function was removed in apache 2.0 alpha14 */
+    /* ap_send_http_header(r); */
+    p->response_started = JK_TRUE;
+
+    return JK_TRUE;
+}
+
+/*
+ * Read a chunk of the request body into a buffer.  Attempt to read len
+ * bytes into the buffer.  Write the number of bytes actually read into
+ * actually_read.
+ *
+ * Think of this function as a method of the apache1.3-specific subclass of
+ * the jk_ws_service class.  Think of the *s param as a "this" or "self"
+ * pointer.
+ */
+static int JK_METHOD ws_read(jk_ws_service_t *s,
+                             void *b, unsigned len, unsigned *actually_read)
+{
+    if (s && s->ws_private && b && actually_read) {
+        apache_private_data_t *p = s->ws_private;
+        if (!p->read_body_started) {
+            if (ap_should_client_block(p->r)) {
+                p->read_body_started = JK_TRUE;
+            }
+        }
+
+        if (p->read_body_started) {
+#ifdef AS400
+            int long rv = OK;
+            if (rv = ap_change_request_body_xlate(p->r, 65535, 65535)) {        /* turn off request body translation */
+                ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_CRIT, 0,
+                             NULL,
+                             "mod_jk: Error on ap_change_request_body_xlate, rc=%d",
+                             rv);
+                return JK_FALSE;
+            }
+#else
+            long rv;
+#endif
+
+            if ((rv = ap_get_client_block(p->r, b, len)) < 0) {
+                *actually_read = 0;
+            }
+            else {
+                *actually_read = (unsigned)rv;
+            }
+            return JK_TRUE;
+        }
+    }
+    return JK_FALSE;
+}
+
+static void JK_METHOD ws_flush(jk_ws_service_t *s)
+{
+#ifndef AS400
+    if (s && s->ws_private) {
+        apache_private_data_t *p = s->ws_private;
+        ap_rflush(p->r);
+    }
+#endif
+}
+
+/*
+ * Write a chunk of response data back to the browser.  If the headers
+ * haven't yet been sent over, send over default header values (Status =
+ * 200, basically).
+ *
+ * Write len bytes from buffer b.
+ *
+ * Think of this function as a method of the apache1.3-specific subclass of
+ * the jk_ws_service class.  Think of the *s param as a "this" or "self"
+ * pointer.
+ */
+/* Works with 4096, fails with 8192 */
+#ifndef CHUNK_SIZE
+#define CHUNK_SIZE 4096
+#endif
+
+static int JK_METHOD ws_write(jk_ws_service_t *s, const void *b, unsigned int l)
+{
+#ifdef AS400
+    int rc;
+#endif
+
+    if (s && s->ws_private && b) {
+        apache_private_data_t *p = s->ws_private;
+
+        if (l) {
+            /* BUFF *bf = p->r->connection->client; */
+            int r = 0;
+            int ll = l;
+            const char *bb = (const char *)b;
+
+            if (!p->response_started) {
+                if (main_log)
+                    jk_log(main_log, JK_LOG_INFO,
+                           "Write without start, starting with defaults");
+                if (!s->start_response(s, 200, NULL, NULL, NULL, 0)) {
+                    return JK_FALSE;
+                }
+            }
+            if (p->r->header_only) {
+#ifndef AS400
+                ap_rflush(p->r);
+#endif
+                return JK_TRUE;
+            }
+#ifdef AS400
+            /* turn off response body translation */
+            rc = ap_change_response_body_xlate(p->r, 65535, 65535);
+            if (rc) {
+                ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_CRIT, 0,
+                             NULL,
+                             "mod_jk: Error on ap_change_response_body_xlate, rc=%d",
+                             rc);
+                return JK_FALSE;
+            }
+#endif
+
+            while (ll > 0 && !p->r->connection->aborted) {
+#if 0
+                /* Apache 2 output filter does not write
+                 * directly to the wire.
+                 */
+                int toSend = (ll > CHUNK_SIZE) ? CHUNK_SIZE : ll;
+                r = ap_rwrite(bb, toSend, p->r);
+#else
+                r = ap_rwrite(bb, ll, p->r);
+#endif
+                if (JK_IS_DEBUG_LEVEL(main_log))
+                    jk_log(main_log, JK_LOG_DEBUG,
+                           "written %d out of %d", r, ll);
+
+                if (r < 0)
+                    return JK_FALSE;
+                ll -= r;
+                bb += r;
+            }
+            if (p->r->connection->aborted)
+                return JK_FALSE;
+        }
+
+        return JK_TRUE;
+    }
+    return JK_FALSE;
+}
+
+static void JK_METHOD ws_add_log_items(jk_ws_service_t *s,
+                                       const char *const *log_names,
+                                       const char *const *log_values,
+                                       unsigned num_of_log_items)
+{
+    unsigned h;
+    apache_private_data_t *p = s->ws_private;
+    request_rec *r = p->r;
+
+    for (h = 0; h < num_of_log_items; h++) {
+        if (log_names[h] && log_values[h]) {
+            apr_table_setn(r->notes, log_names[h], log_values[h]);
+        }
+    }
+}
+
+/* ========================================================================= */
+/* Utility functions                                                         */
+/* ========================================================================= */
+
+/* ========================================================================= */
+/* Log something to Jk log file then exit */
+static void jk_error_exit(const char *file,
+                          int line,
+                          int level,
+                          const server_rec * s,
+                          apr_pool_t * p, const char *fmt, ...)
+{
+    va_list ap;
+    char *res;
+
+    va_start(ap, fmt);
+    res = apr_pvsprintf(s->process->pool, fmt, ap);
+    va_end(ap);
+
+    ap_log_error(file, line, level, 0, s, res);
+
+    /* Exit process */
+    exit(1);
+}
+
+static int get_content_length(request_rec * r)
+{
+    if (r->clength > 0) {
+        return (int)r->clength;
+    }
+    else if (r->main == NULL || r->main == r) {
+        char *lenp = (char *)apr_table_get(r->headers_in, "Content-Length");
+
+        if (lenp) {
+            int rc = atoi(lenp);
+            if (rc > 0) {
+                return rc;
+            }
+        }
+    }
+
+    return 0;
+}
+
+static int init_ws_service(apache_private_data_t * private_data,
+                           jk_ws_service_t *s, jk_server_conf_t * conf)
+{
+    request_rec *r = private_data->r;
+
+    char *ssl_temp = NULL;
+    s->jvm_route = NULL;        /* Used for sticky session routing */
+
+    /* Copy in function pointers (which are really methods) */
+    s->start_response = ws_start_response;
+    s->read = ws_read;
+    s->write = ws_write;
+    s->flush = ws_flush;
+    s->add_log_items = ws_add_log_items;
+
+    /* Clear RECO status */
+    s->reco_status = RECO_NONE;
+
+    s->auth_type = NULL_FOR_EMPTY(r->ap_auth_type);
+    s->remote_user = NULL_FOR_EMPTY(r->user);
+
+    s->protocol = r->protocol;
+    s->remote_host = (char *)ap_get_remote_host(r->connection,
+                                                r->per_dir_config,
+                                                REMOTE_HOST, NULL);
+    s->remote_host = NULL_FOR_EMPTY(s->remote_host);
+    if (conf->options & JK_OPT_FWDLOCAL)
+        s->remote_addr = NULL_FOR_EMPTY(r->connection->local_ip);
+    else
+        s->remote_addr = NULL_FOR_EMPTY(r->connection->remote_ip);
+    if (conf->options & JK_OPT_FLUSHPACKETS)
+        s->flush_packets = 1;
+    else
+        s->flush_packets = 0;
+
+    if (conf->options & JK_OPT_DISABLEREUSE)
+        s->disable_reuse = 1;
+    else
+        s->disable_reuse = 0;
+
+    /* get server name */
+    s->server_name = (char *)ap_get_server_name(r);
+
+    /* get the real port (otherwise redirect failed) */
+    /* XXX: use apache API for getting server port
+     *
+     * Pre 1.2.7 versions used:
+     * s->server_port = r->connection->local_addr->port;
+     */
+    s->server_port  = ap_get_server_port(r);
+
+    s->server_software = (char *)ap_get_server_version();
+    s->method = (char *)r->method;
+    s->content_length = get_content_length(r);
+    s->is_chunked = r->read_chunked;
+    s->no_more_chunks = 0;
+#ifdef AS400
+    /* Get the query string that is not translated to EBCDIC  */
+    s->query_string = ap_get_original_query_string(r);
+#else
+    s->query_string = r->args;
+#endif
+
+    /* Dump all connection param so we can trace what's going to
+     * the remote tomcat
+     */
+    if (JK_IS_DEBUG_LEVEL(conf->log)) {
+        jk_log(conf->log, JK_LOG_DEBUG,
+               "Service protocol=%s method=%s host=%s addr=%s name=%s port=%d auth=%s user=%s laddr=%s raddr=%s",
+               STRNULL_FOR_NULL(s->protocol),
+               STRNULL_FOR_NULL(s->method),
+               STRNULL_FOR_NULL(s->remote_host),
+               STRNULL_FOR_NULL(s->remote_addr),
+               STRNULL_FOR_NULL(s->server_name),
+               s->server_port,
+               STRNULL_FOR_NULL(s->auth_type),
+               STRNULL_FOR_NULL(s->remote_user),
+               STRNULL_FOR_NULL(r->connection->local_ip),
+               STRNULL_FOR_NULL(r->connection->remote_ip));
+    }
+
+    /*
+     * The 2.2 servlet spec errata says the uri from
+     * HttpServletRequest.getRequestURI() should remain encoded.
+     * [http://java.sun.com/products/servlet/errata_042700.html]
+     *
+     * We use JkOptions to determine which method to be used
+     *
+     * ap_escape_uri is the latest recommanded but require
+     *               some java decoding (in TC 3.3 rc2)
+     *
+     * unparsed_uri is used for strict compliance with spec and
+     *              old Tomcat (3.2.3 for example)
+     *
+     * uri is use for compatibilty with mod_rewrite with old Tomcats
+     */
+
+    switch (conf->options & JK_OPT_FWDURIMASK) {
+
+    case JK_OPT_FWDURICOMPATUNPARSED:
+        s->req_uri = r->unparsed_uri;
+        if (s->req_uri != NULL) {
+            char *query_str = strchr(s->req_uri, '?');
+            if (query_str != NULL) {
+                *query_str = 0;
+            }
+        }
+
+        break;
+
+    case JK_OPT_FWDURICOMPAT:
+        s->req_uri = r->uri;
+        break;
+
+    case JK_OPT_FWDURIESCAPED:
+        s->req_uri = ap_escape_uri(r->pool, r->uri);
+        break;
+
+    default:
+        return JK_FALSE;
+    }
+
+    s->is_ssl = JK_FALSE;
+    s->ssl_cert = NULL;
+    s->ssl_cert_len = 0;
+    s->ssl_cipher = NULL;       /* required by Servlet 2.3 Api,
+                                   allready in original ajp13 */
+    s->ssl_session = NULL;
+    s->ssl_key_size = -1;       /* required by Servlet 2.3 Api, added in jtc */
+
+    if (conf->ssl_enable || conf->envvars_in_use) {
+        ap_add_common_vars(r);
+
+        if (conf->ssl_enable) {
+            ssl_temp =
+                (char *)apr_table_get(r->subprocess_env,
+                                      conf->https_indicator);
+            if (ssl_temp && !strcasecmp(ssl_temp, "on")) {
+                s->is_ssl = JK_TRUE;
+                s->ssl_cert =
+                    (char *)apr_table_get(r->subprocess_env,
+                                          conf->certs_indicator);
+                if (s->ssl_cert) {
+                    s->ssl_cert_len = strlen(s->ssl_cert);
+                }
+                /* Servlet 2.3 API */
+                s->ssl_cipher =
+                    (char *)apr_table_get(r->subprocess_env,
+                                          conf->cipher_indicator);
+                s->ssl_session =
+                    (char *)apr_table_get(r->subprocess_env,
+                                          conf->session_indicator);
+
+                if (conf->options & JK_OPT_FWDKEYSIZE) {
+                    /* Servlet 2.3 API */
+                    ssl_temp = (char *)apr_table_get(r->subprocess_env,
+                                                     conf->
+                                                     key_size_indicator);
+                    if (ssl_temp)
+                        s->ssl_key_size = atoi(ssl_temp);
+                }
+            }
+        }
+
+        if (conf->envvars_in_use) {
+            const apr_array_header_t *t = apr_table_elts(conf->envvars);
+            if (t && t->nelts) {
+                int i;
+                apr_table_entry_t *elts = (apr_table_entry_t *) t->elts;
+                s->attributes_names = apr_palloc(r->pool,
+                                                 sizeof(char *) * t->nelts);
+                s->attributes_values = apr_palloc(r->pool,
+                                                  sizeof(char *) * t->nelts);
+
+                for (i = 0; i < t->nelts; i++) {
+                    s->attributes_names[i] = elts[i].key;
+                    s->attributes_values[i] =
+                        (char *)apr_table_get(r->subprocess_env, elts[i].key);
+                    if (!s->attributes_values[i]) {
+                        s->attributes_values[i] = elts[i].val;
+                    }
+                }
+
+                s->num_attributes = t->nelts;
+            }
+        }
+    }
+
+    s->headers_names = NULL;
+    s->headers_values = NULL;
+    s->num_headers = 0;
+    if (r->headers_in && apr_table_elts(r->headers_in)) {
+        int need_content_length_header = (!s->is_chunked
+                                          && s->content_length ==
+                                          0) ? JK_TRUE : JK_FALSE;
+        const apr_array_header_t *t = apr_table_elts(r->headers_in);
+        if (t && t->nelts) {
+            int i;
+            apr_table_entry_t *elts = (apr_table_entry_t *) t->elts;
+            s->num_headers = t->nelts;
+            /* allocate an extra header slot in case we need to add a content-length header */
+            s->headers_names =
+                apr_palloc(r->pool, sizeof(char *) * (t->nelts + 1));
+            s->headers_values =
+                apr_palloc(r->pool, sizeof(char *) * (t->nelts + 1));
+            if (!s->headers_names || !s->headers_values)
+                return JK_FALSE;
+            for (i = 0; i < t->nelts; i++) {
+                char *hname = apr_pstrdup(r->pool, elts[i].key);
+                s->headers_values[i] = apr_pstrdup(r->pool, elts[i].val);
+                s->headers_names[i] = hname;
+                if (need_content_length_header &&
+                    !strcasecmp(s->headers_values[i], "content-length")) {
+                    need_content_length_header = JK_FALSE;
+                }
+            }
+            /* Add a content-length = 0 header if needed.
+             * Ajp13 assumes an absent content-length header means an unknown,
+             * but non-zero length body.
+             */
+            if (need_content_length_header) {
+                s->headers_names[s->num_headers] = "content-length";
+                s->headers_values[s->num_headers] = "0";
+                s->num_headers++;
+            }
+        }
+        /* Add a content-length = 0 header if needed. */
+        else if (need_content_length_header) {
+            s->headers_names = apr_palloc(r->pool, sizeof(char *));
+            s->headers_values = apr_palloc(r->pool, sizeof(char *));
+            if (!s->headers_names || !s->headers_values)
+                return JK_FALSE;
+            s->headers_names[0] = "content-length";
+            s->headers_values[0] = "0";
+            s->num_headers++;
+        }
+    }
+    s->uw_map = conf->uw_map;
+    return JK_TRUE;
+}
+
+/*
+ * The JK module command processors
+ *
+ * The below are all installed so that Apache calls them while it is
+ * processing its config files.  This allows configuration info to be
+ * copied into a jk_server_conf_t object, which is then used for request
+ * filtering/processing.
+ *
+ * See jk_cmds definition below for explanations of these options.
+ */
+
+/*
+ * JkMountCopy directive handling
+ *
+ * JkMountCopy On/Off
+ */
+
+static const char *jk_set_mountcopy(cmd_parms * cmd, void *dummy, int flag)
+{
+    server_rec *s = cmd->server;
+    jk_server_conf_t *conf =
+        (jk_server_conf_t *) ap_get_module_config(s->module_config,
+                                                  &jk_module);
+
+    /* Set up our value */
+    conf->mountcopy = flag ? JK_TRUE : JK_FALSE;
+
+    return NULL;
+}
+
+/*
+ * JkMount directive handling
+ *
+ * JkMount URI(context) worker
+ */
+
+static const char *jk_mount_context(cmd_parms * cmd,
+                                    void *dummy,
+                                    const char *context,
+                                    const char *worker)
+{
+    server_rec *s = cmd->server;
+    jk_server_conf_t *conf =
+        (jk_server_conf_t *) ap_get_module_config(s->module_config,
+                                                  &jk_module);
+    const char *c, *w;
+
+    if (worker != NULL && cmd->path == NULL ) {
+        c = context;
+        w = worker;
+    }
+    else if (worker == NULL && cmd->path != NULL) {
+        c = cmd->path;
+        w = context;
+    }
+    else {
+        if (worker == NULL)
+            return "JkMount needs a path when not defined in a location";
+        else
+            return "JkMount can not have a path when defined in a location";
+    }
+
+    if (c[0] != '/')
+        return "JkMount context should start with /";
+
+    /*
+     * Add the new worker to the alias map.
+     */
+    jk_map_put(conf->uri_to_context, c, w, NULL);
+    return NULL;
+}
+
+/*
+ * JkUnMount directive handling
+ *
+ * JkUnMount URI(context) worker
+ */
+
+static const char *jk_unmount_context(cmd_parms * cmd,
+                                      void *dummy,
+                                      const char *context,
+                                      const char *worker)
+{
+    server_rec *s = cmd->server;
+    jk_server_conf_t *conf =
+        (jk_server_conf_t *) ap_get_module_config(s->module_config,
+                                                  &jk_module);
+    char *uri;
+    const char *c, *w;
+
+    if (worker != NULL && cmd->path == NULL ) {
+        c = context;
+        w = worker;
+    }
+    else if (worker == NULL && cmd->path != NULL) {
+        c = cmd->path;
+        w = context;
+    }
+    else {
+        if (worker == NULL)
+            return "JkUnMount needs a path when not defined in a location";
+        else
+            return "JkUnMount can not have a path when defined in a location";
+    }
+
+    if (c[0] != '/')
+        return "JkUnMount context should start with /";
+
+    uri = apr_pstrcat(cmd->temp_pool, "!", c, NULL);
+    /*
+     * Add the new worker to the alias map.
+     */
+    jk_map_put(conf->uri_to_context, uri, w, NULL);
+    return NULL;
+}
+
+
+/*
+ * JkAutoMount directive handling
+ *
+ * JkAutoMount worker [virtualhost]
+ * This is an experimental and undocumented extension made in j-t-c/jk.
+ */
+static const char *jk_automount_context(cmd_parms * cmd,
+                                        void *dummy,
+                                        const char *worker,
+                                        const char *virtualhost)
+{
+    server_rec *s = cmd->server;
+    jk_server_conf_t *conf =
+        (jk_server_conf_t *) ap_get_module_config(s->module_config,
+                                                  &jk_module);
+
+    /*
+     * Add the new automount to the auto map.
+     */
+    jk_map_put(conf->automount, worker, virtualhost, NULL);
+    return NULL;
+}
+
+/*
+ * JkWorkersFile Directive Handling
+ *
+ * JkWorkersFile file
+ */
+
+static const char *jk_set_worker_file(cmd_parms * cmd,
+                                      void *dummy, const char *worker_file)
+{
+    server_rec *s = cmd->server;
+    struct stat statbuf;
+
+    jk_server_conf_t *conf =
+        (jk_server_conf_t *) ap_get_module_config(s->module_config,
+                                                  &jk_module);
+
+    /* we need an absolut path (ap_server_root_relative does the ap_pstrdup) */
+    conf->worker_file = ap_server_root_relative(cmd->pool, worker_file);
+
+    if (conf->worker_file == NULL)
+        return "JkWorkersFile file_name invalid";
+
+    if (stat(conf->worker_file, &statbuf) == -1)
+        return "Can't find the workers file specified";
+
+    return NULL;
+}
+
+/*
+ * JkMountFile Directive Handling
+ *
+ * JkMountFile file
+ */
+
+static const char *jk_set_mount_file(cmd_parms * cmd,
+                                     void *dummy, const char *mount_file)
+{
+    server_rec *s = cmd->server;
+    struct stat statbuf;
+
+    jk_server_conf_t *conf =
+        (jk_server_conf_t *) ap_get_module_config(s->module_config,
+                                                  &jk_module);
+
+    /* we need an absolut path (ap_server_root_relative does the ap_pstrdup) */
+    conf->mount_file = ap_server_root_relative(cmd->pool, mount_file);
+
+    if (conf->mount_file == NULL)
+        return "JkMountFile file name invalid";
+
+    if (stat(conf->mount_file, &statbuf) == -1)
+        return "Can't find the mount file specified";
+
+    return NULL;
+}
+
+/*
+ * JkLogFile Directive Handling
+ *
+ * JkLogFile file
+ */
+
+static const char *jk_set_log_file(cmd_parms * cmd,
+                                   void *dummy, const char *log_file)
+{
+    server_rec *s = cmd->server;
+    jk_server_conf_t *conf =
+        (jk_server_conf_t *) ap_get_module_config(s->module_config,
+                                                  &jk_module);
+
+    /* we need an absolute path */
+    if (*log_file != '|')
+        conf->log_file = ap_server_root_relative(cmd->pool, log_file);
+    else
+        conf->log_file = apr_pstrdup(cmd->pool, log_file);
+
+    if (conf->log_file == NULL)
+        return "JkLogFile file_name invalid";
+
+    return NULL;
+}
+
+/*
+ * JkShmFile Directive Handling
+ *
+ * JkShmFile file
+ */
+
+static const char *jk_set_shm_file(cmd_parms * cmd,
+                                   void *dummy, const char *shm_file)
+{
+    /* we need an absolute path */
+    jk_shm_file = ap_server_root_relative(cmd->pool, shm_file);
+    if (jk_shm_file == NULL)
+        return "JkShmFile file name invalid";
+
+    return NULL;
+}
+
+/*
+ * JkShmSize Directive Handling
+ *
+ * JkShmSize size in kilobytes
+ */
+
+static const char *jk_set_shm_size(cmd_parms * cmd,
+                                   void *dummy, const char *shm_size)
+{
+    int sz = 0;
+    /* we need an absolute path */
+    sz = atoi(shm_size) * 1024;
+    if (sz < JK_SHM_DEF_SIZE)
+        sz = JK_SHM_DEF_SIZE;
+    else
+        sz = JK_SHM_ALIGN(sz);
+    jk_shm_size = (size_t)sz;
+    return NULL;
+}
+
+/*
+ * JkLogLevel Directive Handling
+ *
+ * JkLogLevel debug/info/error/emerg
+ */
+
+static const char *jk_set_log_level(cmd_parms * cmd,
+                                    void *dummy, const char *log_level)
+{
+    server_rec *s = cmd->server;
+    jk_server_conf_t *conf =
+        (jk_server_conf_t *) ap_get_module_config(s->module_config,
+                                                  &jk_module);
+
+    conf->log_level = jk_parse_log_level(log_level);
+
+    return NULL;
+}
+
+/*
+ * JkLogStampFormat Directive Handling
+ *
+ * JkLogStampFormat "[%a %b %d %H:%M:%S %Y] "
+ */
+
+static const char *jk_set_log_fmt(cmd_parms * cmd,
+                                  void *dummy, const char *log_format)
+{
+    jk_set_log_format(log_format);
+    return NULL;
+}
+
+
+/*
+ * JkAutoAlias Directive Handling
+ *
+ * JkAutoAlias application directory
+ */
+
+static const char *jk_set_auto_alias(cmd_parms * cmd,
+                                     void *dummy, const char *directory)
+{
+    server_rec *s = cmd->server;
+    jk_server_conf_t *conf =
+        (jk_server_conf_t *) ap_get_module_config(s->module_config,
+                                                  &jk_module);
+
+    conf->alias_dir = apr_pstrdup(cmd->pool, directory);
+
+    if (conf->alias_dir == NULL)
+        return "JkAutoAlias directory invalid";
+
+    return NULL;
+}
+
+/*****************************************************************
+ *
+ * Actually logging.
+ */
+
+typedef const char *(*item_key_func) (request_rec *, char *);
+
+typedef struct
+{
+    item_key_func func;
+    char *arg;
+} request_log_format_item;
+
+static const char *process_item(request_rec * r,
+                                request_log_format_item * item)
+{
+    const char *cp;
+
+    cp = (*item->func) (r, item->arg);
+    return cp ? cp : "-";
+}
+
+static void request_log_transaction(request_rec * r, jk_server_conf_t * conf)
+{
+    request_log_format_item *items;
+    char *str, *s;
+    int i;
+    int len = 0;
+    const char **strs;
+    int *strl;
+    apr_array_header_t *format = conf->format;
+
+    strs = apr_palloc(r->pool, sizeof(char *) * (format->nelts));
+    strl = apr_palloc(r->pool, sizeof(int) * (format->nelts));
+    items = (request_log_format_item *) format->elts;
+    for (i = 0; i < format->nelts; ++i) {
+        strs[i] = process_item(r, &items[i]);
+    }
+    for (i = 0; i < format->nelts; ++i) {
+        len += strl[i] = strlen(strs[i]);
+    }
+    str = apr_palloc(r->pool, len + 1);
+    for (i = 0, s = str; i < format->nelts; ++i) {
+        memcpy(s, strs[i], strl[i]);
+        s += strl[i];
+    }
+    *s = 0;
+
+    jk_log(conf->log, JK_LOG_REQUEST, "%s", str);
+
+}
+
+/*****************************************************************
+ *
+ * Parsing the log format string
+ */
+
+static char *format_integer(apr_pool_t * p, int i)
+{
+    return apr_psprintf(p, "%d", i);
+}
+
+static char *pfmt(apr_pool_t * p, int i)
+{
+    if (i <= 0) {
+        return "-";
+    }
+    else {
+        return format_integer(p, i);
+    }
+}
+
+static const char *constant_item(request_rec * dummy, char *stuff)
+{
+    return stuff;
+}
+
+static const char *log_worker_name(request_rec * r, char *a)
+{
+    return apr_table_get(r->notes, JK_NOTE_WORKER_NAME);
+}
+
+static const char *log_worker_route(request_rec * r, char *a)
+{
+    return apr_table_get(r->notes, JK_NOTE_WORKER_ROUTE);
+}
+
+
+static const char *log_request_duration(request_rec * r, char *a)
+{
+    return apr_table_get(r->notes, JK_NOTE_REQUEST_DURATION);
+}
+
+static const char *log_request_line(request_rec * r, char *a)
+{
+    /* NOTE: If the original request contained a password, we
+     * re-write the request line here to contain XXXXXX instead:
+     * (note the truncation before the protocol string for HTTP/0.9 requests)
+     * (note also that r->the_request contains the unmodified request)
+     */
+    return (r->parsed_uri.password) ? apr_pstrcat(r->pool, r->method, " ",
+                                                  apr_uri_unparse(r->pool,
+                                                                  &r->
+                                                                  parsed_uri,
+                                                                  0),
+                                                  r->
+                                                  assbackwards ? NULL : " ",
+                                                  r->protocol, NULL)
+        : r->the_request;
+}
+
+/* These next two routines use the canonical name:port so that log
+ * parsers don't need to duplicate all the vhost parsing crud.
+ */
+static const char *log_virtual_host(request_rec * r, char *a)
+{
+    return r->server->server_hostname;
+}
+
+static const char *log_server_port(request_rec * r, char *a)
+{
+    return apr_psprintf(r->pool, "%u",
+                        r->server->port ? r->server->
+                        port : ap_default_port(r));
+}
+
+/* This respects the setting of UseCanonicalName so that
+ * the dynamic mass virtual hosting trick works better.
+ */
+static const char *log_server_name(request_rec * r, char *a)
+{
+    return ap_get_server_name(r);
+}
+
+static const char *log_request_uri(request_rec * r, char *a)
+{
+    return r->uri;
+}
+static const char *log_request_method(request_rec * r, char *a)
+{
+    return r->method;
+}
+
+static const char *log_request_protocol(request_rec * r, char *a)
+{
+    return r->protocol;
+}
+static const char *log_request_query(request_rec * r, char *a)
+{
+    return (r->args != NULL) ? apr_pstrcat(r->pool, "?", r->args, NULL)
+        : "";
+}
+static const char *log_status(request_rec * r, char *a)
+{
+    return pfmt(r->pool, r->status);
+}
+
+static const char *clf_log_bytes_sent(request_rec * r, char *a)
+{
+    if (!r->sent_bodyct) {
+        return "-";
+    }
+    else {
+        return apr_off_t_toa(r->pool, r->bytes_sent);
+    }
+}
+
+static const char *log_bytes_sent(request_rec * r, char *a)
+{
+    if (!r->sent_bodyct) {
+        return "0";
+    }
+    else {
+        return apr_psprintf(r->pool, "%" APR_OFF_T_FMT, r->bytes_sent);
+    }
+}
+
+static struct log_item_list
+{
+    char ch;
+    item_key_func func;
+} log_item_keys[] = {
+
+    {
+    'T', log_request_duration}, {
+    'r', log_request_line}, {
+    'U', log_request_uri}, {
+    's', log_status}, {
+    'b', clf_log_bytes_sent}, {
+    'B', log_bytes_sent}, {
+    'V', log_server_name}, {
+    'v', log_virtual_host}, {
+    'p', log_server_port}, {
+    'H', log_request_protocol}, {
+    'm', log_request_method}, {
+    'q', log_request_query}, {
+    'w', log_worker_name}, {
+    'R', log_worker_route}, {
+    '\0'}
+};
+
+static struct log_item_list *find_log_func(char k)
+{
+    int i;
+
+    for (i = 0; log_item_keys[i].ch; ++i)
+        if (k == log_item_keys[i].ch) {
+            return &log_item_keys[i];
+        }
+
+    return NULL;
+}
+
+static char *parse_request_log_misc_string(apr_pool_t * p,
+                                           request_log_format_item * it,
+                                           const char **sa)
+{
+    const char *s;
+    char *d;
+
+    it->func = constant_item;
+
+    s = *sa;
+    while (*s && *s != '%') {
+        s++;
+    }
+    /*
+     * This might allocate a few chars extra if there's a backslash
+     * escape in the format string.
+     */
+    it->arg = apr_palloc(p, s - *sa + 1);
+
+    d = it->arg;
+    s = *sa;
+    while (*s && *s != '%') {
+        if (*s != '\\') {
+            *d++ = *s++;
+        }
+        else {
+            s++;
+            switch (*s) {
+            case '\\':
+                *d++ = '\\';
+                s++;
+                break;
+            case 'n':
+                *d++ = '\n';
+                s++;
+                break;
+            case 't':
+                *d++ = '\t';
+                s++;
+                break;
+            default:
+                /* copy verbatim */
+                *d++ = '\\';
+                /*
+                 * Allow the loop to deal with this *s in the normal
+                 * fashion so that it handles end of string etc.
+                 * properly.
+                 */
+                break;
+            }
+        }
+    }
+    *d = '\0';
+
+    *sa = s;
+    return NULL;
+}
+
+static char *parse_request_log_item(apr_pool_t * p,
+                                    request_log_format_item * it,
+                                    const char **sa)
+{
+    const char *s = *sa;
+    struct log_item_list *l;
+
+    if (*s != '%') {
+        return parse_request_log_misc_string(p, it, sa);
+    }
+
+    ++s;
+    it->arg = "";               /* For safety's sake... */
+
+    l = find_log_func(*s++);
+    if (!l) {
+        char dummy[2];
+
+        dummy[0] = s[-1];
+        dummy[1] = '\0';
+        return apr_pstrcat(p, "Unrecognized JkRequestLogFormat directive %",
+                           dummy, NULL);
+    }
+    it->func = l->func;
+    *sa = s;
+    return NULL;
+}
+
+static apr_array_header_t *parse_request_log_string(apr_pool_t * p,
+                                                    const char *s,
+                                                    const char **err)
+{
+    apr_array_header_t *a =
+        apr_array_make(p, 15, sizeof(request_log_format_item));
+    char *res;
+
+    while (*s) {
+        if ((res =
+             parse_request_log_item(p,
+                                    (request_log_format_item *)
+                                    apr_array_push(a), &s))) {
+            *err = res;
+            return NULL;
+        }
+    }
+
+    return a;
+}
+
+/*
+ * JkRequestLogFormat Directive Handling
+ *
+ * JkRequestLogFormat format string
+ *
+ * %b - Bytes sent, excluding HTTP headers. In CLF format
+ * %B - Bytes sent, excluding HTTP headers.
+ * %H - The request protocol
+ * %m - The request method
+ * %p - The canonical Port of the server serving the request
+ * %q - The query string (prepended with a ? if a query string exists,
+ *      otherwise an empty string)
+ * %r - First line of request
+ * %s - request HTTP status code
+ * %T - Requset duration, elapsed time to handle request in seconds '.' micro seconds
+ * %U - The URL path requested, not including any query string.
+ * %v - The canonical ServerName of the server serving the request.
+ * %V - The server name according to the UseCanonicalName setting.
+ * %w - Tomcat worker name
+ */
+
+static const char *jk_set_request_log_format(cmd_parms * cmd,
+                                             void *dummy, const char *format)
+{
+    const char *err_string = NULL;
+    server_rec *s = cmd->server;
+    jk_server_conf_t *conf =
+        (jk_server_conf_t *) ap_get_module_config(s->module_config,
+                                                  &jk_module);
+
+    conf->format_string = apr_pstrdup(cmd->pool, format);
+    if (format != NULL) {
+        conf->format =
+            parse_request_log_string(cmd->pool, format, &err_string);
+    }
+    if (conf->format == NULL)
+        return "JkRequestLogFormat format array NULL";
+
+    return err_string;
+}
+
+
+/*
+ * JkExtractSSL Directive Handling
+ *
+ * JkExtractSSL On/Off
+ */
+
+static const char *jk_set_enable_ssl(cmd_parms * cmd, void *dummy, int flag)
+{
+    server_rec *s = cmd->server;
+    jk_server_conf_t *conf =
+        (jk_server_conf_t *) ap_get_module_config(s->module_config,
+                                                  &jk_module);
+
+    /* Set up our value */
+    conf->ssl_enable = flag ? JK_TRUE : JK_FALSE;
+
+    return NULL;
+}
+
+/*
+ * JkHTTPSIndicator Directive Handling
+ *
+ * JkHTTPSIndicator HTTPS
+ */
+
+static const char *jk_set_https_indicator(cmd_parms * cmd,
+                                          void *dummy, const char *indicator)
+{
+    server_rec *s = cmd->server;
+    jk_server_conf_t *conf =
+        (jk_server_conf_t *) ap_get_module_config(s->module_config,
+                                                  &jk_module);
+
+    conf->https_indicator = apr_pstrdup(cmd->pool, indicator);
+
+    return NULL;
+}
+
+/*
+ * JkCERTSIndicator Directive Handling
+ *
+ * JkCERTSIndicator SSL_CLIENT_CERT
+ */
+
+static const char *jk_set_certs_indicator(cmd_parms * cmd,
+                                          void *dummy, const char *indicator)
+{
+    server_rec *s = cmd->server;
+    jk_server_conf_t *conf =
+        (jk_server_conf_t *) ap_get_module_config(s->module_config,
+                                                  &jk_module);
+
+    conf->certs_indicator = apr_pstrdup(cmd->pool, indicator);
+
+    return NULL;
+}
+
+/*
+ * JkCIPHERIndicator Directive Handling
+ *
+ * JkCIPHERIndicator SSL_CIPHER
+ */
+
+static const char *jk_set_cipher_indicator(cmd_parms * cmd,
+                                           void *dummy, const char *indicator)
+{
+    server_rec *s = cmd->server;
+    jk_server_conf_t *conf =
+        (jk_server_conf_t *) ap_get_module_config(s->module_config,
+                                                  &jk_module);
+
+    conf->cipher_indicator = apr_pstrdup(cmd->pool, indicator);
+
+    return NULL;
+}
+
+/*
+ * JkSESSIONIndicator Directive Handling
+ *
+ * JkSESSIONIndicator SSL_SESSION_ID
+ */
+
+static const char *jk_set_session_indicator(cmd_parms * cmd,
+                                            void *dummy,
+                                            const char *indicator)
+{
+    server_rec *s = cmd->server;
+    jk_server_conf_t *conf =
+        (jk_server_conf_t *) ap_get_module_config(s->module_config,
+                                                  &jk_module);
+
+    conf->session_indicator = apr_pstrdup(cmd->pool, indicator);
+
+    return NULL;
+}
+
+/*
+ * JkKEYSIZEIndicator Directive Handling
+ *
+ * JkKEYSIZEIndicator SSL_CIPHER_USEKEYSIZE
+ */
+
+static const char *jk_set_key_size_indicator(cmd_parms * cmd,
+                                             void *dummy,
+                                             const char *indicator)
+{
+    server_rec *s = cmd->server;
+    jk_server_conf_t *conf =
+        (jk_server_conf_t *) ap_get_module_config(s->module_config,
+                                                  &jk_module);
+
+    conf->key_size_indicator = apr_pstrdup(cmd->pool, indicator);
+
+    return NULL;
+}
+
+/*
+ * JkOptions Directive Handling
+ *
+ *
+ * +ForwardSSLKeySize        => Forward SSL Key Size, to follow 2.3 specs but may broke old TC 3.2
+ * -ForwardSSLKeySize        => Don't Forward SSL Key Size, will make mod_jk works with all TC release
+ *  ForwardURICompat         => Forward URI normally, less spec compliant but mod_rewrite compatible (old TC)
+ *  ForwardURICompatUnparsed => Forward URI as unparsed, spec compliant but broke mod_rewrite (old TC)
+ *  ForwardURIEscaped        => Forward URI escaped and Tomcat (3.3 rc2) stuff will do the decoding part
+ *  ForwardDirectories       => Forward all directory requests with no index files to Tomcat
+ */
+
+static const char *jk_set_options(cmd_parms * cmd, void *dummy,
+                                  const char *line)
+{
+    int opt = 0;
+    int mask = 0;
+    char action;
+    char *w;
+
+    server_rec *s = cmd->server;
+    jk_server_conf_t *conf =
+        (jk_server_conf_t *) ap_get_module_config(s->module_config,
+                                                  &jk_module);
+
+    while (line[0] != 0) {
+        w = ap_getword_conf(cmd->pool, &line);
+        action = 0;
+
+        if (*w == '+' || *w == '-') {
+            action = *(w++);
+        }
+
+        mask = 0;
+
+        if (!strcasecmp(w, "ForwardKeySize")) {
+            opt = JK_OPT_FWDKEYSIZE;
+        }
+        else if (!strcasecmp(w, "ForwardURICompat")) {
+            opt = JK_OPT_FWDURICOMPAT;
+            mask = JK_OPT_FWDURIMASK;
+        }
+        else if (!strcasecmp(w, "ForwardURICompatUnparsed")) {
+            opt = JK_OPT_FWDURICOMPATUNPARSED;
+            mask = JK_OPT_FWDURIMASK;
+        }
+        else if (!strcasecmp(w, "ForwardURIEscaped")) {
+            opt = JK_OPT_FWDURIESCAPED;
+            mask = JK_OPT_FWDURIMASK;
+        }
+        else if (!strcasecmp(w, "ForwardDirectories")) {
+            opt = JK_OPT_FWDDIRS;
+        }
+        else if (!strcasecmp(w, "ForwardLocalAddress")) {
+            opt = JK_OPT_FWDLOCAL;
+        }
+        else if (!strcasecmp(w, "FlushPackets")) {
+            opt = JK_OPT_FLUSHPACKETS;
+        }
+        else if (!strcasecmp(w, "DisableReuse")) {
+            opt = JK_OPT_DISABLEREUSE;
+        }
+        else
+            return apr_pstrcat(cmd->pool, "JkOptions: Illegal option '", w,
+                               "'", NULL);
+
+        conf->options &= ~mask;
+
+        if (action == '-') {
+            conf->options &= ~opt;
+        }
+        else if (action == '+') {
+            conf->options |= opt;
+        }
+        else {                  /* for now +Opt == Opt */
+            conf->options |= opt;
+        }
+    }
+    return NULL;
+}
+
+/*
+ * JkEnvVar Directive Handling
+ *
+ * JkEnvVar MYOWNDIR
+ */
+
+static const char *jk_add_env_var(cmd_parms * cmd,
+                                  void *dummy,
+                                  const char *env_name,
+                                  const char *default_value)
+{
+    server_rec *s = cmd->server;
+    jk_server_conf_t *conf =
+        (jk_server_conf_t *) ap_get_module_config(s->module_config,
+                                                  &jk_module);
+
+    conf->envvars_in_use = JK_TRUE;
+
+    apr_table_add(conf->envvars, env_name, default_value);
+
+    return NULL;
+}
+
+/*
+ * JkWorkerProperty Directive Handling
+ *
+ * JkWorkerProperty name=value
+ */
+
+static const char *jk_set_worker_property(cmd_parms * cmd,
+                                          void *dummy,
+                                          const char *line)
+{
+    server_rec *s = cmd->server;
+    jk_server_conf_t *conf =
+        (jk_server_conf_t *) ap_get_module_config(s->module_config,
+                                                  &jk_module);
+
+    if (jk_map_read_property(conf->worker_properties, line, conf->log) == JK_FALSE)
+        return apr_pstrcat(cmd->temp_pool, "Invalid JkWorkerProperty ", line);
+
+    return NULL;
+}
+
+static const command_rec jk_cmds[] = {
+    /*
+     * JkWorkersFile specifies a full path to the location of the worker
+     * properties file.
+     *
+     * This file defines the different workers used by apache to redirect
+     * servlet requests.
+     */
+    AP_INIT_TAKE1("JkWorkersFile", jk_set_worker_file, NULL, RSRC_CONF,
+                  "the name of a worker file for the Tomcat servlet containers"),
+
+    /*
+     * JkMountFile specifies a full path to the location of the
+     * uriworker properties file.
+     *
+     * This file defines the different mapping for workers used by apache
+     * to redirect servlet requests.
+     */
+    AP_INIT_TAKE1("JkMountFile", jk_set_mount_file, NULL, RSRC_CONF,
+                  "the name of a mount file for the Tomcat servlet uri mapping"),
+
+    /*
+     * JkAutoMount specifies that the list of handled URLs must be
+     * asked to the servlet engine (autoconf feature)
+     */
+    AP_INIT_TAKE12("JkAutoMount", jk_automount_context, NULL, RSRC_CONF,
+                   "automatic mount points to a Tomcat worker"),
+
+    /*
+     * JkMount mounts a url prefix to a worker (the worker need to be
+     * defined in the worker properties file.
+     */
+    AP_INIT_TAKE12("JkMount", jk_mount_context, NULL, RSRC_CONF|ACCESS_CONF,
+                   "A mount point from a context to a Tomcat worker"),
+
+    /*
+     * JkUnMount unmounts a url prefix to a worker (the worker need to be
+     * defined in the worker properties file.
+     */
+    AP_INIT_TAKE12("JkUnMount", jk_unmount_context, NULL, RSRC_CONF|ACCESS_CONF,
+                   "A no mount point from a context to a Tomcat worker"),
+
+    /*
+     * JkMountCopy specifies if mod_jk should copy the mount points
+     * from the main server to the virtual servers.
+     */
+    AP_INIT_FLAG("JkMountCopy", jk_set_mountcopy, NULL, RSRC_CONF,
+                 "Should the base server mounts be copied to the virtual server"),
+
+    /*
+     * JkLogFile & JkLogLevel specifies to where should the plugin log
+     * its information and how much.
+     * JkLogStampFormat specify the time-stamp to be used on log
+     */
+    AP_INIT_TAKE1("JkLogFile", jk_set_log_file, NULL, RSRC_CONF,
+                  "Full path to the Tomcat module log file"),
+
+    AP_INIT_TAKE1("JkShmFile", jk_set_shm_file, NULL, RSRC_CONF,
+                  "Full path to the Tomcat module shared memory file"),
+
+    AP_INIT_TAKE1("JkShmSize", jk_set_shm_size, NULL, RSRC_CONF,
+                  "Size of the shared memory file in KBytes"),
+
+    AP_INIT_TAKE1("JkLogLevel", jk_set_log_level, NULL, RSRC_CONF,
+                  "The Tomcat module log level, can be debug, "
+                  "info, error or emerg"),
+    AP_INIT_TAKE1("JkLogStampFormat", jk_set_log_fmt, NULL, RSRC_CONF,
+                  "The Tomcat module log format, follow strftime synthax"),
+    AP_INIT_TAKE1("JkRequestLogFormat", jk_set_request_log_format, NULL,
+                  RSRC_CONF,
+                  "The mod_jk module request log format string"),
+
+    /*
+     * Automatically Alias webapp context directories into the Apache
+     * document space.
+     */
+    AP_INIT_TAKE1("JkAutoAlias", jk_set_auto_alias, NULL, RSRC_CONF,
+                  "The mod_jk module automatic context apache alias directory"),
+
+    /*
+     * Apache has multiple SSL modules (for example apache_ssl, stronghold
+     * IHS ...). Each of these can have a different SSL environment names
+     * The following properties let the administrator specify the envoiroment
+     * variables names.
+     *
+     * HTTPS - indication for SSL
+     * CERTS - Base64-Der-encoded client certificates.
+     * CIPHER - A string specifing the ciphers suite in use.
+     * KEYSIZE - Size of Key used in dialogue (#bits are secure)
+     * SESSION - A string specifing the current SSL session.
+     */
+    AP_INIT_TAKE1("JkHTTPSIndicator", jk_set_https_indicator, NULL, RSRC_CONF,
+                  "Name of the Apache environment that contains SSL indication"),
+    AP_INIT_TAKE1("JkCERTSIndicator", jk_set_certs_indicator, NULL, RSRC_CONF,
+                  "Name of the Apache environment that contains SSL client certificates"),
+    AP_INIT_TAKE1("JkCIPHERIndicator", jk_set_cipher_indicator, NULL,
+                  RSRC_CONF,
+                  "Name of the Apache environment that contains SSL client cipher"),
+    AP_INIT_TAKE1("JkSESSIONIndicator", jk_set_session_indicator, NULL,
+                  RSRC_CONF,
+                  "Name of the Apache environment that contains SSL session"),
+    AP_INIT_TAKE1("JkKEYSIZEIndicator", jk_set_key_size_indicator, NULL,
+                  RSRC_CONF,
+                  "Name of the Apache environment that contains SSL key size in use"),
+    AP_INIT_FLAG("JkExtractSSL", jk_set_enable_ssl, NULL, RSRC_CONF,
+                 "Turns on SSL processing and information gathering by mod_jk"),
+
+    /*
+     * Options to tune mod_jk configuration
+     * for now we understand :
+     * +ForwardSSLKeySize        => Forward SSL Key Size, to follow 2.3 specs but may broke old TC 3.2
+     * -ForwardSSLKeySize        => Don't Forward SSL Key Size, will make mod_jk works with all TC release
+     *  ForwardURICompat         => Forward URI normally, less spec compliant but mod_rewrite compatible (old TC)
+     *  ForwardURICompatUnparsed => Forward URI as unparsed, spec compliant but broke mod_rewrite (old TC)
+     *  ForwardURIEscaped        => Forward URI escaped and Tomcat (3.3 rc2) stuff will do the decoding part
+     */
+    AP_INIT_RAW_ARGS("JkOptions", jk_set_options, NULL, RSRC_CONF,
+                     "Set one of more options to configure the mod_jk module"),
+
+    /*
+     * JkEnvVar let user defines envs var passed from WebServer to
+     * Servlet Engine
+     */
+    AP_INIT_TAKE2("JkEnvVar", jk_add_env_var, NULL, RSRC_CONF,
+                  "Adds a name of environment variable that should be sent "
+                  "to servlet-engine"),
+
+    AP_INIT_RAW_ARGS("JkWorkerProperty", jk_set_worker_property,
+                     NULL, RSRC_CONF,
+                     "Set workers.properties formated directive"),
+
+    {NULL}
+};
+
+/* ========================================================================= */
+/* The JK module handlers                                                    */
+/* ========================================================================= */
+
+/** Util - cleanup shmem.
+ */
+static apr_status_t jk_cleanup_shmem(void *data)
+{
+    jk_shm_close();
+    return APR_SUCCESS;
+}
+
+/** Main service method, called to forward a request to tomcat
+ */
+static int jk_handler(request_rec * r)
+{
+    const char *worker_name;
+    jk_server_conf_t *xconf;
+    int rc, dmt = 1;
+
+    /* We do DIR_MAGIC_TYPE here to make sure TC gets all requests, even
+     * if they are directory requests, in case there are no static files
+     * visible to Apache and/or DirectoryIndex was not used. This is only
+     * used when JkOptions has ForwardDirectories set. */
+    /* Not for me, try next handler */
+    if (strcmp(r->handler, JK_HANDLER)
+        && (dmt = strcmp(r->handler, DIR_MAGIC_TYPE)))
+        return DECLINED;
+
+    xconf = (jk_server_conf_t *) ap_get_module_config(r->server->module_config,
+                                                      &jk_module);
+    JK_TRACE_ENTER(xconf->log);
+    if (apr_table_get(r->subprocess_env, "no-jk")) {
+        jk_log(xconf->log, JK_LOG_DEBUG,
+               "Into handler no-jk env var detected for uri=%s, declined",
+               r->uri);
+
+        JK_TRACE_EXIT(xconf->log);
+        return DECLINED;
+    }
+
+    /* Was the option to forward directories to Tomcat set? */
+    if (!dmt && !(xconf->options & JK_OPT_FWDDIRS)) {
+        JK_TRACE_EXIT(xconf->log);
+        return DECLINED;
+    }
+    worker_name = apr_table_get(r->notes, JK_NOTE_WORKER_NAME);
+
+    /* Set up r->read_chunked flags for chunked encoding, if present */
+    if ((rc = ap_setup_client_block(r, REQUEST_CHUNKED_DECHUNK)) != APR_SUCCESS) {
+        JK_TRACE_EXIT(xconf->log);
+        return rc;
+    }
+
+    if (worker_name == NULL) {
+        /* we may be here because of a manual directive ( that overrides
+           translate and
+           sets the handler directly ). We still need to know the worker.
+         */
+        if (worker_env.num_of_workers == 1) {
+          /** We have a single worker ( the common case ).
+              ( lb is a bit special, it should count as a single worker but
+              I'm not sure how ). We also have a manual config directive that
+              explicitely give control to us. */
+            worker_name = worker_env.worker_list[0];
+            if (JK_IS_DEBUG_LEVEL(xconf->log))
+                jk_log(xconf->log, JK_LOG_DEBUG,
+                       "Single worker (%s) configuration for %s",
+                       worker_name, r->uri);
+        }
+        else {
+            worker_name = map_uri_to_worker(xconf->uw_map, r->uri, xconf->log);
+            if (worker_name == NULL && worker_env.num_of_workers) {
+                worker_name = worker_env.worker_list[0];
+                if (JK_IS_DEBUG_LEVEL(xconf->log))
+                    jk_log(xconf->log, JK_LOG_DEBUG,
+                           "Using first worker (%s) from %d workers for %s",
+                           worker_name, worker_env.num_of_workers, r->uri);
+            }
+        }
+        if (worker_name)
+            apr_table_setn(r->notes, JK_NOTE_WORKER_NAME, worker_name);
+    }
+
+    if (JK_IS_DEBUG_LEVEL(xconf->log))
+       jk_log(xconf->log, JK_LOG_DEBUG, "Into handler %s worker=%s"
+              " r->proxyreq=%d",
+              r->handler, worker_name, r->proxyreq);
+
+    /* If this is a proxy request, we'll notify an error */
+    if (r->proxyreq) {
+        jk_log(xconf->log, JK_LOG_INFO, "Proxy request for worker=%s"
+              " is not allowed",
+              worker_name);
+        JK_TRACE_EXIT(xconf->log);
+        return HTTP_INTERNAL_SERVER_ERROR;
+    }
+
+    if (worker_name) {
+        jk_worker_t *worker = wc_get_worker_for_name(worker_name, xconf->log);
+
+        /* If the remote client has aborted, just ignore the request */
+        if (r->connection->aborted) {
+            jk_log(xconf->log, JK_LOG_INFO, "Client connection aborted for"
+                   " worker=%s",
+                   worker_name);
+            JK_TRACE_EXIT(xconf->log);
+            return OK;
+        }
+
+        if (worker) {
+            apr_time_t request_begin = 0;
+            int is_error = HTTP_INTERNAL_SERVER_ERROR;
+            int rc = JK_FALSE;
+            apache_private_data_t private_data;
+            jk_ws_service_t s;
+            jk_pool_atom_t buf[SMALL_POOL_SIZE];
+            jk_open_pool(&private_data.p, buf, sizeof(buf));
+
+            private_data.response_started = JK_FALSE;
+            private_data.read_body_started = JK_FALSE;
+            private_data.r = r;
+
+            wc_maintain(xconf->log);
+
+            jk_init_ws_service(&s);
+            /* Update retries for this worker */
+            s.retries = worker->retries;
+            s.ws_private = &private_data;
+            s.pool = &private_data.p;
+            apr_table_setn(r->notes, JK_NOTE_WORKER_TYPE,
+                           wc_get_name_for_type(worker->type, xconf->log));
+
+            if (xconf->format != NULL) {
+                request_begin = apr_time_now();
+            }
+
+            if (init_ws_service(&private_data, &s, xconf)) {
+                jk_endpoint_t *end = NULL;
+
+                /* Use per/thread pool ( or "context" ) to reuse the
+                   endpoint. It's a bit faster, but I don't know
+                   how to deal with load balancing - but it's usefull for JNI
+                 */
+
+                /* worker->get_endpoint might fail if we are out of memory so check */
+                /* and handle it */
+                if (worker->get_endpoint(worker, &end, xconf->log)) {
+                    rc = end->service(end, &s, xconf->log,
+                                      &is_error);
+                    end->done(&end, xconf->log);
+                    if (s.content_read < s.content_length ||
+                        (s.is_chunked && !s.no_more_chunks)) {
+
+                        /*
+                         * If the servlet engine didn't consume all of the
+                         * request data, consume and discard all further
+                         * characters left to read from client
+                         */
+                        char *buff = apr_palloc(r->pool, 2048);
+                        if (buff != NULL) {
+                            int rd;
+                            while ((rd =
+                                    ap_get_client_block(r, buff, 2048)) > 0) {
+                                s.content_read += rd;
+                            }
+                        }
+                    }
+                }
+                else {            /* this means we couldn't get an endpoint */
+                    jk_log(xconf->log, JK_LOG_ERROR, "Could not get endpoint"
+                           " for worker=%s",
+                           worker_name);
+                    rc = 0;       /* just to make sure that we know we've failed */
+                }
+            }
+            else {
+                jk_log(xconf->log, JK_LOG_ERROR, "Could not init service"
+                       " for worker=%s",
+                       worker_name);
+                jk_close_pool(&private_data.p);
+                JK_TRACE_EXIT(xconf->log);
+                return HTTP_INTERNAL_SERVER_ERROR;
+            }
+            if (xconf->format != NULL) {
+                long micro, seconds;
+                char *duration = NULL;
+                apr_time_t rd = apr_time_now() - request_begin;
+                seconds = (long)apr_time_sec(rd);
+                micro = (long)(rd - apr_time_from_sec(seconds));
+
+                duration = apr_psprintf(r->pool, "%.1ld.%.6ld", seconds, micro);
+                apr_table_setn(r->notes, JK_NOTE_REQUEST_DURATION, duration);
+                if (s.jvm_route && *s.jvm_route)
+                    apr_table_setn(r->notes, JK_NOTE_WORKER_ROUTE, s.jvm_route);
+
+                request_log_transaction(r, xconf);
+            }
+
+            jk_close_pool(&private_data.p);
+
+            if (rc > 0) {
+                /* If tomcat returned no body and the status is not OK,
+                   let apache handle the error code */
+                if (!r->sent_bodyct && r->status >= HTTP_BAD_REQUEST) {
+                    jk_log(xconf->log, JK_LOG_INFO, "No body with status=%d"
+                           " for worker=%s",
+                           r->status, worker_name);
+                    JK_TRACE_EXIT(xconf->log);
+                    return r->status;
+                }
+                if (JK_IS_DEBUG_LEVEL(xconf->log))
+                    jk_log(xconf->log, JK_LOG_DEBUG, "Service finished"
+                           " with status=%d for worker=%s",
+                           r->status, worker_name);
+                JK_TRACE_EXIT(xconf->log);
+                return OK;      /* NOT r->status, even if it has changed. */
+            }
+            else if (rc == JK_CLIENT_ERROR) {
+                if (is_error != HTTP_REQUEST_ENTITY_TOO_LARGE)
+                    r->connection->aborted = 1;
+                jk_log(xconf->log, JK_LOG_INFO, "Aborting connection"
+                       " for worker=%s",
+                       worker_name);
+                JK_TRACE_EXIT(xconf->log);
+                return is_error;
+            }
+            else {
+                jk_log(xconf->log, JK_LOG_INFO, "Service error=%d"
+                       " for worker=%s",
+                       rc, worker_name);
+                JK_TRACE_EXIT(xconf->log);
+                return is_error;
+            }
+        }
+        else {
+            jk_log(xconf->log, JK_LOG_INFO, "Could not find a worker"
+                   " for worker name=%s",
+                   worker_name);
+            JK_TRACE_EXIT(xconf->log);
+            return HTTP_INTERNAL_SERVER_ERROR;
+        }
+    }
+
+    JK_TRACE_EXIT(xconf->log);
+    return DECLINED;
+}
+
+/** Standard apache hook, cleanup jk
+ */
+static apr_status_t jk_apr_pool_cleanup(void *data)
+{
+    server_rec *s = data;
+
+    while (NULL != s) {
+        jk_server_conf_t *conf =
+            (jk_server_conf_t *) ap_get_module_config(s->module_config,
+                                                      &jk_module);
+
+        if (conf && conf->worker_properties) {
+            /* On pool cleanup pass NULL for the jk_logger to
+               prevent segmentation faults on Windows because
+               we can't guarantee what order pools get cleaned
+               up between APR implementations. */
+            if (conf->was_initialized)
+                wc_close(NULL);
+            if (conf->worker_properties)
+                jk_map_free(&conf->worker_properties);
+            if (conf->uri_to_context)
+                jk_map_free(&conf->uri_to_context);
+            if (conf->automount)
+                jk_map_free(&conf->automount);
+            if (conf->uw_map)
+                uri_worker_map_free(&conf->uw_map, NULL);
+            conf->was_initialized   = JK_FALSE;
+            conf->worker_properties = NULL;
+        }
+        s = s->next;
+    }
+    return APR_SUCCESS;
+}
+
+/** Create default jk_config. XXX This is mostly server-independent,
+    all servers are using something similar - should go to common.
+ */
+static void *create_jk_config(apr_pool_t * p, server_rec * s)
+{
+    jk_server_conf_t *c =
+        (jk_server_conf_t *) apr_pcalloc(p, sizeof(jk_server_conf_t));
+
+    c->worker_properties = NULL;
+    jk_map_alloc(&c->worker_properties);
+    c->worker_file = NULL;
+    c->mount_file = NULL;
+    c->log_file = NULL;
+    c->log_level = JK_LOG_DEF_LEVEL;
+    c->log = NULL;
+    c->alias_dir = NULL;
+    c->format_string = NULL;
+    c->format = NULL;
+    c->mountcopy = JK_FALSE;
+    c->was_initialized = JK_FALSE;
+    c->options = JK_OPT_FWDURIDEFAULT;
+
+    /*
+     * By default we will try to gather SSL info.
+     * Disable this functionality through JkExtractSSL
+     */
+    c->ssl_enable = JK_TRUE;
+    /*
+     * The defaults ssl indicators match those in mod_ssl (seems
+     * to be in more use).
+     */
+    c->https_indicator = "HTTPS";
+    c->certs_indicator = "SSL_CLIENT_CERT";
+
+    /*
+     * The following (comented out) environment variables match apache_ssl!
+     * If you are using apache_sslapache_ssl uncomment them (or use the
+     * configuration directives to set them.
+     *
+     c->cipher_indicator = "HTTPS_CIPHER";
+     c->session_indicator = NULL;
+     */
+
+    /*
+     * The following environment variables match mod_ssl! If you
+     * are using another module (say apache_ssl) comment them out.
+     */
+    c->cipher_indicator = "SSL_CIPHER";
+    c->session_indicator = "SSL_SESSION_ID";
+    c->key_size_indicator = "SSL_CIPHER_USEKEYSIZE";
+
+    if (!jk_map_alloc(&(c->uri_to_context))) {
+        jk_error_exit(APLOG_MARK, APLOG_EMERG, s, p, "Memory error");
+    }
+    if (!jk_map_alloc(&(c->automount))) {
+        jk_error_exit(APLOG_MARK, APLOG_EMERG, s, p, "Memory error");
+    }
+
+    c->uw_map = NULL;
+    c->secret_key = NULL;
+
+    c->envvars_in_use = JK_FALSE;
+    c->envvars = apr_table_make(p, 0);
+
+    c->s = s;
+    jk_map_put(c->worker_properties, "ServerRoot", ap_server_root, NULL);
+    apr_pool_cleanup_register(p, s, jk_apr_pool_cleanup, jk_apr_pool_cleanup);
+    return c;
+}
+
+
+/** Utility - copy a map . XXX Should move to jk_map, it's generic code.
+ */
+static void copy_jk_map(apr_pool_t * p, server_rec * s, jk_map_t *src,
+                        jk_map_t *dst)
+{
+    int sz = jk_map_size(src);
+    int i;
+    for (i = 0; i < sz; i++) {
+        const char *name = jk_map_name_at(src, i);
+        if (jk_map_get(dst, name, NULL) == NULL) {
+            if (!jk_map_put(dst, name,
+                            apr_pstrdup(p, jk_map_get_string(src, name, NULL)),
+                            NULL)) {
+                jk_error_exit(APLOG_MARK, APLOG_EMERG, s, p, "Memory error");
+            }
+        }
+    }
+}
+
+/** Standard apache callback, merge jk options specified in <Directory>
+    context or <Host>.
+ */
+static void *merge_jk_config(apr_pool_t * p, void *basev, void *overridesv)
+{
+    jk_server_conf_t *base = (jk_server_conf_t *) basev;
+    jk_server_conf_t *overrides = (jk_server_conf_t *) overridesv;
+
+    if (base->ssl_enable) {
+        overrides->ssl_enable = base->ssl_enable;
+        overrides->https_indicator = base->https_indicator;
+        overrides->certs_indicator = base->certs_indicator;
+        overrides->cipher_indicator = base->cipher_indicator;
+        overrides->session_indicator = base->session_indicator;
+    }
+
+    overrides->options = base->options;
+
+    if (overrides->mountcopy) {
+        copy_jk_map(p, overrides->s, base->uri_to_context,
+                    overrides->uri_to_context);
+        copy_jk_map(p, overrides->s, base->automount, overrides->automount);
+        overrides->mount_file = base->mount_file;
+    }
+
+    if (base->envvars_in_use) {
+        overrides->envvars_in_use = JK_TRUE;
+        overrides->envvars = apr_table_overlay(p, overrides->envvars,
+                                               base->envvars);
+    }
+
+    if (!uri_worker_map_alloc(&(overrides->uw_map),
+                              overrides->uri_to_context, overrides->log)) {
+        jk_error_exit(APLOG_MARK, APLOG_EMERG, overrides->s,
+                      overrides->s->process->pool, "Memory error");
+    }
+
+    if (base->secret_key)
+        overrides->secret_key = base->secret_key;
+
+    return overrides;
+}
+
+static int JK_METHOD jk_log_to_file(jk_logger_t *l,
+                                    int level, const char *what)
+{
+    if (l &&
+        (l->level <= level || level == JK_LOG_REQUEST_LEVEL) &&
+        l->logger_private && what) {
+        unsigned sz = strlen(what);
+        apr_size_t wrote = sz;
+        char error[256];
+        if (sz) {
+            apr_status_t status;
+            file_logger_t *p = l->logger_private;
+            if (p->jklogfp) {
+                apr_status_t rv;
+                rv = apr_global_mutex_lock(jk_log_lock);
+                if (rv != APR_SUCCESS) {
+                    ap_log_error(APLOG_MARK, APLOG_ERR, rv, NULL,
+                                 "apr_global_mutex_lock(jk_log_lock) failed");
+                    /* XXX: Maybe this should be fatal? */
+                }
+                status = apr_file_write(p->jklogfp, what, &wrote);
+                if (status != APR_SUCCESS) {
+                    apr_strerror(status, error, 254);
+                    ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0,
+                                 NULL,
+                                 "mod_jk: jk_log_to_file %s failed: %s",
+                                 what, error);
+                }
+                rv = apr_global_mutex_unlock(jk_log_lock);
+                if (rv != APR_SUCCESS) {
+                    ap_log_error(APLOG_MARK, APLOG_ERR, rv, NULL,
+                                 "apr_global_mutex_unlock(jk_log_lock) failed");
+                    /* XXX: Maybe this should be fatal? */
+                }
+            }
+        }
+
+        return JK_TRUE;
+    }
+
+    return JK_FALSE;
+}
+
+/*
+** +-------------------------------------------------------+
+** |                                                       |
+** |              jk logfile support                       |
+** |                                                       |
+** +-------------------------------------------------------+
+*/
+
+static apr_status_t jklog_cleanup(void *d)
+{
+    /* set the main_log to NULL */
+    main_log = NULL;
+    return APR_SUCCESS;
+}
+
+static int open_jklog(server_rec * s, apr_pool_t * p)
+{
+    jk_server_conf_t *conf;
+    const char *fname;
+    apr_status_t rc;
+    piped_log *pl;
+    jk_logger_t *jkl;
+    file_logger_t *flp;
+    int jklog_flags = (APR_WRITE | APR_APPEND | APR_CREATE);
+    apr_fileperms_t jklog_mode =
+        (APR_UREAD | APR_UWRITE | APR_GREAD | APR_WREAD);
+
+    conf = ap_get_module_config(s->module_config, &jk_module);
+
+    if (main_log != NULL) {
+        conf->log = main_log;
+        return 0;
+    }
+    if (conf->log_file == NULL) {
+        return 0;
+    }
+    if (*(conf->log_file) == '\0') {
+        return 0;
+    }
+
+    if (*conf->log_file == '|') {
+        if ((pl = ap_open_piped_log(p, conf->log_file + 1)) == NULL) {
+            ap_log_error(APLOG_MARK, APLOG_ERR, 0, s,
+                         "mod_jk: could not open reliable pipe "
+                         "to jk log %s", conf->log_file + 1);
+            return -1;
+        }
+        conf->jklogfp = (void *)ap_piped_log_write_fd(pl);
+    }
+    else {
+        fname = ap_server_root_relative(p, conf->log_file);
+        if (!fname) {
+            ap_log_error(APLOG_MARK, APLOG_ERR, APR_EBADPATH, s,
+                         "mod_jk: Invalid JkLog " "path %s", conf->log_file);
+            return -1;
+        }
+        if ((rc = apr_file_open(&conf->jklogfp, fname,
+                                jklog_flags, jklog_mode, p))
+            != APR_SUCCESS) {
+            ap_log_error(APLOG_MARK, APLOG_ERR, rc, s,
+                         "mod_jk: could not open JkLog " "file %s", fname);
+            return -1;
+        }
+        apr_file_inherit_set(conf->jklogfp);
+    }
+    jkl = (jk_logger_t *)apr_palloc(p, sizeof(jk_logger_t));
+    flp = (file_logger_t *) apr_palloc(p, sizeof(file_logger_t));
+    if (jkl && flp) {
+        jkl->log = jk_log_to_file;
+        jkl->level = conf->log_level;
+        jkl->logger_private = flp;
+        flp->jklogfp = conf->jklogfp;
+        conf->log = jkl;
+        if (main_log == NULL)
+            main_log = conf->log;
+        apr_pool_cleanup_register(p, main_log, jklog_cleanup, jklog_cleanup);
+        return 0;
+    }
+
+    return -1;
+}
+
+
+/** Standard apache callback, initialize jk.
+ */
+static void jk_child_init(apr_pool_t * pconf, server_rec * s)
+{
+    jk_server_conf_t *conf;
+    apr_status_t rv;
+    int rc;
+
+    conf = ap_get_module_config(s->module_config, &jk_module);
+
+    rv = apr_global_mutex_child_init(&jk_log_lock, NULL, pconf);
+    if (rv != APR_SUCCESS) {
+        ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s,
+                     "mod_jk: could not init JK log lock in child");
+    }
+
+    JK_TRACE_ENTER(conf->log);
+
+    if ((rc = jk_shm_attach(jk_shm_file, jk_shm_size, conf->log)) == 0) {
+        if (JK_IS_DEBUG_LEVEL(conf->log))
+            jk_log(conf->log, JK_LOG_DEBUG, "Attached shm:%s",
+                   jk_shm_name());
+            apr_pool_cleanup_register(pconf, conf->log, jk_cleanup_shmem,
+                                     jk_cleanup_shmem);
+    }
+    else
+        jk_log(conf->log, JK_LOG_ERROR, "Attachning shm:%s errno=%d",
+               jk_shm_name(), rc);
+
+    if (JK_IS_DEBUG_LEVEL(conf->log))
+        jk_log(conf->log, JK_LOG_DEBUG, "Initialized %s", JK_EXPOSED_VERSION);
+    JK_TRACE_EXIT(conf->log);
+}
+
+/** Initialize jk, using worker.properties.
+    We also use apache commands ( JkWorker, etc), but this use is
+    deprecated, as we'll try to concentrate all config in
+    workers.properties, urimap.properties, and ajp14 autoconf.
+
+    Apache config will only be used for manual override, using
+    SetHandler and normal apache directives ( but minimal jk-specific
+    stuff )
+*/
+static void init_jk(apr_pool_t * pconf, jk_server_conf_t * conf,
+                    server_rec * s)
+{
+    int rc;
+    int mpm_threads = 1;
+
+    /*     jk_map_t *init_map = NULL; */
+    jk_map_t *init_map = conf->worker_properties;
+
+#if !defined(WIN32) && !defined(NETWARE)
+    if (!jk_shm_file) {
+        jk_shm_file = ap_server_root_relative(pconf, "logs/jk-runtime-status");
+        if (jk_shm_file)
+            ap_log_error(APLOG_MARK, APLOG_INFO | APLOG_NOERRNO,
+                         0, NULL,
+                         "No JkShmFile defined in httpd.conf. "
+                         "Using default %s", jk_shm_file);
+    }
+#endif
+    if ((rc = jk_shm_open(jk_shm_file, jk_shm_size, conf->log)) == 0) {
+        if (JK_IS_DEBUG_LEVEL(conf->log))
+            jk_log(conf->log, JK_LOG_DEBUG, "Initialized shm:%s",
+                   jk_shm_name(), rc);
+            apr_pool_cleanup_register(pconf, conf->log, jk_cleanup_shmem,
+                                      jk_cleanup_shmem);
+    }
+    else
+        jk_log(conf->log, JK_LOG_ERROR, "Initializing shm:%s errno=%d",
+               jk_shm_name(), rc);
+#if !defined(WIN32) && !defined(NETWARE)
+    if (!jk_shm_file) {
+        ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_CRIT,
+                     0, NULL,
+                     "No JkShmFile defined in httpd.conf. "
+                     "LoadBalancer will not function properly!");
+        ap_log_error(APLOG_MARK, APLOG_EMERG | APLOG_NOERRNO,
+                     0, NULL,
+                     "No JkShmFile defined in httpd.conf. "
+                     "LoadBalancer will not function properly!");
+    }
+#endif
+
+    /* Set default connection cache size for worker mpm */
+#if APR_HAS_THREADS
+    if (ap_mpm_query(AP_MPMQ_MAX_THREADS, &mpm_threads) != APR_SUCCESS)
+        mpm_threads = 1;
+#endif
+     jk_set_worker_def_cache_size(mpm_threads);
+
+    if (!uri_worker_map_alloc(&(conf->uw_map),
+                              conf->uri_to_context,
+                              conf->log)) {
+        jk_error_exit(APLOG_MARK, APLOG_EMERG, s, pconf, "Memory error");
+    }
+
+    /*     if(map_alloc(&init_map)) { */
+    if (!jk_map_read_properties(init_map, conf->worker_file, NULL, conf->log)) {
+        if (jk_map_size(init_map) == 0) {
+            ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_CRIT,
+                         0, NULL,
+                         "No worker file and no worker options in httpd.conf"
+                         "use JkWorkerFile to set workers");
+            return;
+        }
+    }
+
+    if (jk_map_resolve_references(init_map, "worker.", 1, 1, conf->log) == JK_FALSE) {
+        jk_error_exit(APLOG_MARK, APLOG_EMERG, s, pconf, "Error in resolving configuration references");
+    }
+
+    /* we add the URI->WORKER MAP since workers using AJP14
+       will feed it */
+    worker_env.uri_to_worker = conf->uw_map;
+    worker_env.virtual = "*";   /* for now */
+    worker_env.server_name = (char *)ap_get_server_version();
+    if (wc_open(init_map, &worker_env, conf->log)) {
+        ap_add_version_component(pconf, JK_EXPOSED_VERSION);
+    }
+}
+
+static int jk_post_config(apr_pool_t * pconf,
+                          apr_pool_t * plog,
+                          apr_pool_t * ptemp, server_rec * s)
+{
+    apr_status_t rv;
+    jk_server_conf_t *conf;
+    server_rec *srv = s;
+
+    /* create the jk log lockfiles in the parent */
+    if ((rv = apr_global_mutex_create(&jk_log_lock, NULL,
+                                      APR_LOCK_DEFAULT,
+                                      pconf)) != APR_SUCCESS) {
+        ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s,
+                     "mod_jk: could not create jk_log_lock");
+        return HTTP_INTERNAL_SERVER_ERROR;
+    }
+
+#if JK_NEED_SET_MUTEX_PERMS
+    rv = unixd_set_global_mutex_perms(jk_log_lock);
+    if (rv != APR_SUCCESS) {
+        ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s,
+                     "mod_jk: Could not set permissions on "
+                     "jk_log_lock; check User and Group directives");
+        return HTTP_INTERNAL_SERVER_ERROR;
+    }
+#endif
+
+    if (!s->is_virtual) {
+        conf = (jk_server_conf_t *)ap_get_module_config(s->module_config,
+                                                        &jk_module);
+        if (!conf->was_initialized) {
+            conf->was_initialized = JK_TRUE;
+            /* step through the servers and open each jk logfile.
+             */
+            for (; srv; srv = srv->next) {
+                if (open_jklog(srv, pconf))
+                    return HTTP_INTERNAL_SERVER_ERROR;
+            }
+            init_jk(pconf, conf, s);
+        }
+    }
+    for (srv = s; srv; srv = srv->next) {
+        conf = (jk_server_conf_t *)ap_get_module_config(srv->module_config,
+                                                        &jk_module);
+        if (conf && conf->mount_file) {
+            conf->uw_map->fname = conf->mount_file;
+            uri_worker_map_load(conf->uw_map, conf->log);
+        }
+    }
+
+    return OK;
+}
+
+/** Use the internal mod_jk mappings to find if this is a request for
+ *    tomcat and what worker to use.
+ */
+static int jk_translate(request_rec * r)
+{
+    if (!r->proxyreq) {
+        jk_server_conf_t *conf =
+            (jk_server_conf_t *) ap_get_module_config(r->server->
+                                                      module_config,
+                                                      &jk_module);
+
+        if (conf) {
+            const char *worker;
+            if ((r->handler != NULL) && (!strcmp(r->handler, JK_HANDLER))) {
+                /* Somebody already set the handler, probably manual config
+                 * or "native" configuration, no need for extra overhead
+                 */
+                if (JK_IS_DEBUG_LEVEL(conf->log))
+                    jk_log(conf->log, JK_LOG_DEBUG,
+                           "Manually mapped, no need to call uri_to_worker");
+                return DECLINED;
+            }
+
+            if (apr_table_get(r->subprocess_env, "no-jk")) {
+                if (JK_IS_DEBUG_LEVEL(conf->log))
+                    jk_log(conf->log, JK_LOG_DEBUG,
+                           "Into translate no-jk env var detected for uri=%s, declined",
+                           r->uri);
+
+                return DECLINED;
+            }
+
+            /* Special case to make sure that apache can serve a directory
+               listing if there are no matches for the DirectoryIndex and
+               Tomcat webapps are mapped into apache using JkAutoAlias. */
+            if (r->main != NULL && r->main->handler != NULL &&
+                (conf->alias_dir != NULL) &&
+                !strcmp(r->main->handler, DIR_MAGIC_TYPE)) {
+
+                /* Append the request uri to the JkAutoAlias directory and
+                   determine if the file exists. */
+                char *clean_uri;
+                apr_finfo_t finfo;
+                finfo.filetype = APR_NOFILE;
+                clean_uri = apr_pstrdup(r->pool, r->uri);
+                ap_no2slash(clean_uri);
+                /* Map uri to a context static file */
+                if (strlen(clean_uri) > 1) {
+                    char *context_path = NULL;
+
+                    context_path = apr_pstrcat(r->pool, conf->alias_dir,
+                                               ap_os_escape_path(r->pool,
+                                                                 clean_uri,
+                                                                 1), NULL);
+                    if (context_path != NULL) {
+                        apr_stat(&finfo, context_path, APR_FINFO_TYPE,
+                                 r->pool);
+                    }
+                }
+                if (finfo.filetype != APR_REG) {
+                    if (JK_IS_DEBUG_LEVEL(conf->log))
+                        jk_log(conf->log, JK_LOG_DEBUG,
+                               "JkAutoAlias, no DirectoryIndex file for URI %s",
+                               r->uri);
+                    return DECLINED;
+                }
+            }
+
+            worker = map_uri_to_worker(conf->uw_map, r->uri, conf->log);
+
+            if (worker) {
+                r->handler = apr_pstrdup(r->pool, JK_HANDLER);
+                apr_table_setn(r->notes, JK_NOTE_WORKER_NAME, worker);
+
+                /* This could be a sub-request, possibly from mod_dir */
+                /* Also set the HANDLER and uri for subrequest */
+                if (r->main) {
+                    r->main->handler = apr_pstrdup(r->main->pool, JK_HANDLER);
+                    r->main->uri = apr_pstrdup(r->main->pool, r->uri);
+                    apr_table_setn(r->main->notes, JK_NOTE_WORKER_NAME, worker);
+                }
+
+                return OK;
+            }
+            else if (conf->alias_dir != NULL) {
+                char *clean_uri = apr_pstrdup(r->pool, r->uri);
+                ap_no2slash(clean_uri);
+                /* Automatically map uri to a context static file */
+                if (JK_IS_DEBUG_LEVEL(conf->log))
+                    jk_log(conf->log, JK_LOG_DEBUG,
+                           "mod_jk::jk_translate, check alias_dir: %s",
+                           conf->alias_dir);
+                if (strlen(clean_uri) > 1) {
+                    /* Get the context directory name */
+                    char *context_dir = NULL;
+                    char *context_path = NULL;
+                    char *child_dir = NULL;
+                    char *index = clean_uri;
+                    char *suffix = strchr(index + 1, '/');
+                    if (suffix != NULL) {
+                        int size = suffix - index;
+                        context_dir = apr_pstrndup(r->pool, index, size);
+                        /* Get the context child directory name */
+                        index = index + size + 1;
+                        suffix = strchr(index, '/');
+                        if (suffix != NULL) {
+                            size = suffix - index;
+                            child_dir = apr_pstrndup(r->pool, index, size);
+                        }
+                        else {
+                            child_dir = index;
+                        }
+                        /* Deny access to WEB-INF and META-INF directories */
+                        if (child_dir != NULL) {
+                            if (JK_IS_DEBUG_LEVEL(conf->log))
+                                jk_log(conf->log, JK_LOG_DEBUG,
+                                       "mod_jk::jk_translate, AutoAlias child_dir: %s",
+                                       child_dir);
+                            if (!strcasecmp(child_dir, "WEB-INF")
+                                || !strcasecmp(child_dir, "META-INF")) {
+                                if (JK_IS_DEBUG_LEVEL(conf->log))
+                                    jk_log(conf->log, JK_LOG_DEBUG,
+                                           "mod_jk::jk_translate, AutoAlias HTTP_NOT_FOUND for URI: %s",
+                                           r->uri);
+                                return HTTP_NOT_FOUND;
+                            }
+                        }
+                    }
+                    else {
+                        context_dir = apr_pstrdup(r->pool, index);
+                    }
+
+                    context_path = apr_pstrcat(r->pool, conf->alias_dir,
+                                               ap_os_escape_path(r->pool,
+                                                                 context_dir,
+                                                                 1), NULL);
+                    if (context_path != NULL) {
+                        apr_finfo_t finfo;
+                        finfo.filetype = APR_NOFILE;
+                        apr_stat(&finfo, context_path, APR_FINFO_TYPE,
+                                 r->pool);
+                        if (finfo.filetype == APR_DIR) {
+                            char *escurl =
+                                ap_os_escape_path(r->pool, clean_uri, 1);
+                            char *ret =
+                                apr_pstrcat(r->pool, conf->alias_dir, escurl,
+                                            NULL);
+                            /* Add code to verify real path ap_os_canonical_name */
+                            if (ret != NULL) {
+                                if (JK_IS_DEBUG_LEVEL(conf->log))
+                                    jk_log(conf->log, JK_LOG_DEBUG,
+                                           "mod_jk::jk_translate, AutoAlias OK for file: %s",
+                                           ret);
+                                r->filename = ret;
+                                return OK;
+                            }
+                        }
+                        else {
+                            /* Deny access to war files in web app directory */
+                            int size = strlen(context_dir);
+                            if (size > 4
+                                && !strcasecmp(context_dir + (size - 4),
+                                               ".war")) {
+                                if (JK_IS_DEBUG_LEVEL(conf->log))
+                                    jk_log(conf->log, JK_LOG_DEBUG,
+                                           "mod_jk::jk_translate, AutoAlias HTTP_FORBIDDEN for URI: %s",
+                                           r->uri);
+                                return HTTP_FORBIDDEN;
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    return DECLINED;
+}
+
+#if (MODULE_MAGIC_NUMBER_MAJOR > 20010808)
+/* bypass the directory_walk and file_walk for non-file requests */
+static int jk_map_to_storage(request_rec * r)
+{
+
+    if (!r->proxyreq && !apr_table_get(r->notes, JK_NOTE_WORKER_NAME)) {
+        jk_server_conf_t *conf =
+            (jk_server_conf_t *) ap_get_module_config(r->server->
+                                                      module_config,
+                                                      &jk_module);
+
+        if (conf) {
+            const char *worker;
+            if ((r->handler != NULL) && (!strcmp(r->handler, JK_HANDLER))) {
+                /* Somebody already set the handler, probably manual config
+                 * or "native" configuration, no need for extra overhead
+                 */
+                if (JK_IS_DEBUG_LEVEL(conf->log))
+                    jk_log(conf->log, JK_LOG_DEBUG,
+                           "Manually mapped, no need to call uri_to_worker");
+                return DECLINED;
+            }
+
+            if (apr_table_get(r->subprocess_env, "no-jk")) {
+                if (JK_IS_DEBUG_LEVEL(conf->log))
+                    jk_log(conf->log, JK_LOG_DEBUG,
+                           "Into map_to_storage no-jk env var detected for uri=%s, declined",
+                           r->uri);
+
+                return DECLINED;
+            }
+
+            worker = map_uri_to_worker(conf->uw_map, r->uri, conf->log);
+
+            if (worker) {
+                r->handler = apr_pstrdup(r->pool, JK_HANDLER);
+                apr_table_setn(r->notes, JK_NOTE_WORKER_NAME, worker);
+
+                /* This could be a sub-request, possibly from mod_dir */
+                if (r->main)
+                    apr_table_setn(r->main->notes, JK_NOTE_WORKER_NAME, worker);
+
+            }
+        }
+    }
+
+    if (apr_table_get(r->notes, JK_NOTE_WORKER_NAME)) {
+
+        /* First find just the name of the file, no directory */
+        r->filename = (char *)apr_filepath_name_get(r->uri);
+
+        /* Only if sub-request for a directory, most likely from mod_dir */
+        if (r->main && r->main->filename &&
+            (!apr_filepath_name_get(r->main->filename) ||
+             !strlen(apr_filepath_name_get(r->main->filename)))) {
+
+            /* The filename from the main request will be set to what should
+             * be picked up, aliases included. Tomcat will need to know about
+             * those aliases or things won't work for them. Normal files should
+             * be fine. */
+
+            /* Need absolute path to stat */
+            if (apr_filepath_merge(&r->filename,
+                                   r->main->filename, r->filename,
+                                   APR_FILEPATH_SECUREROOT |
+                                   APR_FILEPATH_TRUENAME, r->pool)
+                != APR_SUCCESS) {
+                return DECLINED;        /* We should never get here, very bad */
+            }
+
+            /* Stat the file so that mod_dir knows it's there */
+            apr_stat(&r->finfo, r->filename, APR_FINFO_TYPE, r->pool);
+        }
+
+        return OK;
+    }
+    return DECLINED;
+}
+#endif
+
+static void jk_register_hooks(apr_pool_t * p)
+{
+    ap_hook_handler(jk_handler, NULL, NULL, APR_HOOK_MIDDLE);
+    ap_hook_post_config(jk_post_config, NULL, NULL, APR_HOOK_MIDDLE);
+    ap_hook_child_init(jk_child_init, NULL, NULL, APR_HOOK_MIDDLE);
+    ap_hook_translate_name(jk_translate, NULL, NULL, APR_HOOK_MIDDLE);
+#if (MODULE_MAGIC_NUMBER_MAJOR > 20010808)
+    ap_hook_map_to_storage(jk_map_to_storage, NULL, NULL, APR_HOOK_MIDDLE);
+#endif
+}
+
+module AP_MODULE_DECLARE_DATA jk_module = {
+    STANDARD20_MODULE_STUFF,
+    NULL,                       /* dir config creater */
+    NULL,                       /* dir merger --- default is to override */
+    create_jk_config,           /* server config */
+    merge_jk_config,            /* merge server config */
+    jk_cmds,                    /* command ap_table_t */
+    jk_register_hooks           /* register hooks */
+};

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/apache-2.0/mod_jk.dsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/apache-2.0/mod_jk.dsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/apache-2.0/mod_jk.dsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,287 @@
+# Microsoft Developer Studio Project File - Name="apache" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
+
+CFG=apache - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE 
+!MESSAGE NMAKE /f "mod_jk.mak".
+!MESSAGE 
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE 
+!MESSAGE NMAKE /f "mod_jk.mak" CFG="apache - Win32 Debug"
+!MESSAGE 
+!MESSAGE Possible choices for configuration are:
+!MESSAGE 
+!MESSAGE "apache - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "apache - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE 
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+MTL=midl.exe
+RSC=rc.exe
+
+!IF  "$(CFG)" == "apache - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MD /W3 /O2 /Oy- /Zi /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /FD /c
+# ADD CPP /nologo /MD /W3 /O2 /Oy- /Zi /I "..\common" /I "$(JAVA_HOME)\include" /I "$(JAVA_HOME)\include\win32" /I "$(APACHE2_HOME)\include" /I "$(APACHE2_HOME)\srclib\apr\include" /I "$(APACHE2_HOME)\srclib\apr-util\include" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "HAVE_APR" /Fd"Release/mod_jk_src" /FD /c
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib advapi32.lib /nologo /dll /machine:I386
+# ADD LINK32 libhttpd.lib libapr.lib libaprutil.lib kernel32.lib user32.lib advapi32.lib ws2_32.lib mswsock.lib /nologo /base:"0x6A6B0000" /subsystem:windows /dll /debug /machine:I386 /out:"Release/mod_jk.so" /libpath:"$(APACHE2_HOME)\Release" /libpath:"$(APACHE2_HOME)\srclib\apr\Release" /libpath:"$(APACHE2_HOME)\srclib\apr-util\Release" /libpath:"$(APACHE2_HOME)\lib" /opt:ref
+
+!ELSEIF  "$(CFG)" == "apache - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MDd /W3 /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FD /c
+# ADD CPP /nologo /MDd /W3 /GX /Zi /Od /I "..\common" /I "$(JAVA_HOME)\include" /I "$(JAVA_HOME)\include\win32" /I "$(APACHE2_HOME)\include" /I "$(APACHE2_HOME)\srclib\apr\include" /I "$(APACHE2_HOME)\srclib\apr-util\include" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "HAVE_APR" /Fd"Debug/mod_jk_src" /FD /c
+# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 libhttpd.lib libapr.lib libaprutil.lib kernel32.lib user32.lib advapi32.lib ws2_32.lib mswsock.lib /nologo /base:"0x6A6B0000" /subsystem:windows /dll /incremental:no /debug /machine:I386 /out:"Debug/mod_jk.so" /libpath:"$(APACHE2_HOME)/Debug" /libpath:"$(APACHE2_HOME)\srclib\apr\Debug" /libpath:"$(APACHE2_HOME)\srclib\apr-util\Debug" /libpath:"$(APACHE2_HOME)\lib"
+
+!ENDIF 
+
+# Begin Target
+
+# Name "apache - Win32 Release"
+# Name "apache - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# Begin Source File
+
+SOURCE=..\common\jk_ajp12_worker.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_ajp13.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_ajp13_worker.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_ajp14.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_ajp14_worker.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_ajp_common.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_connect.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_context.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_jni_worker.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_lb_worker.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_map.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_md5.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_msg_buff.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_pool.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_shm.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_sockbuf.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_status.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_uri_worker_map.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_util.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_worker.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\mod_jk.c
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl"
+# Begin Source File
+
+SOURCE=..\common\jk_ajp12_worker.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_ajp13.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_ajp13_worker.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_ajp14.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_ajp14_worker.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_ajp23_worker.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_ajp_common.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_connect.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_context.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_global.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_jni_worker.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_lb_worker.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_logger.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_map.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_md5.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_msg_buff.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_mt.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_pool.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_service.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_shm.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_sockbuf.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_status.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_uri_worker_map.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_util.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_worker.h
+# End Source File
+# End Group
+# Begin Group "Resource Files"
+
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
+# End Group
+# End Target
+# End Project

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/build.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/build.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/build.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,456 @@
+<?xml version="1.0" ?>
+
+<project name="jk_native" default="main" basedir=".">
+
+  <description>Build the native component of jk.</description>
+  
+  <property file="${user.home}/.ant.properties" />
+  <property file="${user.home}/build.properties" />
+  <property file="../build.properties" />
+  <property file="build.properties" />
+
+  <!-- Overriden if called from the main -->
+  <property name="jk.build" location="../build" /> 
+
+  <path id="cp.jkant" >
+    <pathelement location="${jk.build}/lib/jkant.jar"/>
+  </path>
+
+  <property name="native.dir" location="." />
+  <property name="apxs13" value="/opt/apache13/bin/apxs" />
+  <property name="apxs20" value="/opt/apache2/bin/apxs" />
+  
+  <property name="iplanet.home" location="/opt/iplanet" />
+  <property name="apache2.home" location="/opt/apache2" />
+  <property name="apache13.home" location="/opt/apache13" />
+  
+  <property name="apache2.include" location="${apache2.home}/include" />
+  <property name="apache13.include" location="${apache13.home}/include" />
+
+  <property name="so.debug" value="true" />
+  <property name="so.optimize" value="false" />
+  <property name="so.profile" value="false" />
+
+  <!-- ==================== Targets ==================== -->
+
+  <target name="main" depends="init,apache20,apache13,iis,netscape,jni">
+  </target>
+
+  <target name="init" >
+    <echo message="${user.home}" />
+    <taskdef resource="META-INF/ant.tasks" 
+	     classpathref="cp.jkant" />
+    <available property="apache13.detect" 
+               file="${apache13.home}" />
+    <available property="apache2.detect" 
+               file="${apache2.home}" />
+    <available property="iis.detect" 
+               file="${iis.home}" />
+    <available property="iplanet.detect" 
+               file="${iplanet.home}" />
+    <available property="HAVE_APR" 
+               file="${apr.include}/apr.h" />
+    <mkdir dir="${jk.build}/jk" />
+    <condition property="linux">
+       <equals arg1="${os.name}" arg2="Linux"/>
+    </condition>
+    <condition property="solaris">
+       <equals arg1="${os.name}" arg2="SunOS"/>
+    </condition>
+    <condition property="win32">
+      <os family="windows"/>
+    </condition>
+    <condition property="hpux">
+      <equals arg1="${os.name}" arg2="HP-UX"/>
+    </condition>
+    <!-- I believe they are using cross-compilation, so checking the os.name
+         doesn't help. We'll check if the NDK is installed instead -->
+    <condition property="netware">
+      <available file="novellndk.home" />
+    </condition>
+    <echo message="linux=${linux} solaris=${solaris} win32=${win32} hpux=${hpux} netware=${netware}"/>
+
+  </target>
+
+  <target name="jni" depends="init">
+    <mkdir dir="${jk.build}/jk/jni" />
+    <so sofile="jni_connect" 
+	buildDir="${jk.build}/jk/jni" 
+	optimize="${so.optimize}"
+	debug="${so.debug}"
+	profile="${so.profile}"
+	>
+      <jniConfig />
+      <src dir="${native.dir}">
+	<include name="jni/*.c" />
+	<include name="common/jk_map.c" />
+	<include name="common/jk_util.c" />
+	<include name="common/jk_pool.c" />
+	<include name="common/jk_logger.c" />
+        <include name="common/jk_nwmain.c" if="netware" />
+        <include name="common/apr/*.c" unless="HAVE_APR" />
+      </src>
+      <includes>
+	<include name="${native.dir}/common" />
+	<include name="${native.dir}/jni" />
+	<include name="${java.home}/../include" />
+	<include name="${build.compiler.base}/include" />
+        
+        <!-- Platform specific includes -->
+	<include name="${novellndk.home}/include/nlm" if="netware" />
+	<include name="${novellndk.home}/include" if="netware" />
+        <include name="${java.home}/../include/netware" if="netware" />
+        <include name="${java.home}/../include/solaris" if="solaris" />
+        <include name="${java.home}/../include/hp-ux" if="hpux" />        
+        <include name="${java.home}/../include/linux"  if="linux"/>
+        <include name="${java.home}/../include/win32" if="win32" unless="netware" />
+      </includes>
+      <depends>
+	<fileset dir="${native.dir}/common" includes="*.h" />
+      </depends>
+      
+      <!-- Platform-specific tags -->
+      <altSoFile value="jni_conn" if="netware" />
+      
+      <def name="N_PLAT_NLM" if="netware"
+	   info="Building for NetWare platform" />
+      <def name="NETWARE" if="netware"
+	   info="Building for NetWare platform" />
+      <def name="XP_NETWARE" if="netware"
+	   info="Building for NetWare platform" />
+           
+      <import fileName="${novellndk.home}/imports/clib.imp" if="netware" />
+      <import fileName="${novellndk.home}/imports/lib0.imp" if="netware" />
+      <import fileName="${novellndk.home}/imports/nlmlib.imp" if="netware" />
+      <import fileName="${novellndk.home}/imports/threads.imp" if="netware" />
+      <import fileName="${novellndk.home}/imports/socklib.imp" if="netware" />
+      <export fileName="${native.dir}/jni/jk_jnicb.exp" if="netware" />
+      <linkOpt value="-desc &quot;JNI Natives for Tomcat&quot;" if="netware" />
+      <linkOpt value="-screenname &quot;System Console&quot;" if="netware" />
+      <linkOpt value="-nlmversion 1,2,6" if="netware" />
+      <linkOpt value="-threadname &quot;JK_JNI Thread&quot;" if="netware" />
+      <linkOpt value="-stacksize 64000" if="netware" />
+      
+      <def name="HPUX11" if="hpux" />
+
+      <def name="WIN32" if="win32" unless="netware" />
+      <def name="DEBUG" if="win32.debug" unless="netware"  />
+      <def name="NDEBUG" if="win32.release" unless="netware"  />
+      <def name="_WINDOWS" if="win32" unless="netware" />
+      <def name="_MBCS" if="win32" unless="netware" />
+      <def name="_USRDLL" if="win32" unless="netware" />
+      <def name="JNI_CONNECT_EXPORTS" if="win32" unless="netware" />
+      <linkOpt value="/libpath:&quot;${build.compiler.base}/lib&quot;" if="win32" unless="netware" />
+    </so>
+  </target>
+
+  <target name="apache20" depends="init" if="apache2.detect">
+    <mkdir dir="${jk.build}/jk/apache2" />
+    <so sofile="mod_jk" 
+	buildDir="${jk.build}/jk/apache2"
+	optimize="${so.optimize}"
+	debug="${so.debug}"
+	taskDebug="0"
+	profile="${so.profile}"	>
+      <def name="_REENTRANT" />
+      <def name="CHANNEL" if="use.channel"
+           info="Use the new (experimental) channel interface" />
+      <def name="AJP12" if="use.ajp12"
+           info="Build the deprecated ajp12 worker" />
+      <def name="CHUNK_SIZE" value="4096" 
+	   info="Read/Write buffer size" />
+      <def name="REUSE_WORKER" 
+	   unless="option_no_reuse_worker"
+	   info="Reuse the worker endpoint, using per thread data" />
+      <def name="USE_APACHE_MD5" unless="netware"
+	   info="Use the MD5 implementation that is part of apache2" />
+      <def name="HPUX11" if="hpux" />
+      <apacheConfig apxs="${apxs20}" />
+      <jniConfig />
+      <src dir=".">
+	<include name="apache-2.0/mod_jk.c" />
+	<include name="common/**/*.c" />
+        <exclude name="common/ajp12/*.c" unless="use.ajp12" />
+        <exclude name="common/jk_nwmain.c" unless="netware" />
+      </src>
+      <includes>
+	<include name="${native.dir}/common" />
+	<include name="${apache2.include}" />
+	<include name="${java.home}/../include" />
+        
+        <!-- Platform specific includes -->
+        <include name="${java.home}/../include/win32" if="win32" unless="netware" />
+        <include name="${java.home}/../include/hp-ux" if="hpux" />        
+        <include name="${java.home}/../include/netware" if="netware" />
+        <include name="${java.home}/../include/linux"  if="linux"/>
+        <include name="${java.home}/../include/solaris" if="solaris" />
+	<include name="${novelllibc.home}/include" if="netware" />
+	<include name="${novelllibc.home}/include/winsock" if="netware" />
+      </includes>
+      <depends>
+	<fileset dir="${native.dir}/common" includes="*.h" />
+      </depends>
+
+      <!-- Platform-specific tags -->
+      <def name="WIN32" if="win32" unless="netware" />
+      <def name="DEBUG" if="win32.debug" unless="netware"  />
+      <def name="NDEBUG" if="win32.release" unless="netware"  />
+      <def name="_WINDOWS" if="win32" unless="netware" />
+      <def name="_MBCS" if="win32" unless="netware" />
+      <def name="_USRDLL" if="win32" unless="netware" />
+
+      <import fileName="libapr.lib" if="win32" unless="netware" />
+      <import fileName="libaprutil.lib" if="win32" unless="netware" />
+      <import fileName="libhttpd.lib" if="win32" unless="netware" />
+      <import fileName="wsock32.lib" if="win32" unless="netware" />
+      <linkOpt value="/libpath:&quot;${build.compiler.base}/lib&quot;" if="win32" unless="netware" />
+      <linkOpt value="/libpath:&quot;${apache2.home}/lib&quot;" if="win32" unless="netware" />
+      
+      <def name="N_PLAT_NLM" if="netware"
+	   info="Building for NetWare platform" />
+      <def name="NETWARE" if="netware"
+	   info="Building for NetWare platform" />
+      <def name="__NETWARE__" if="netware"
+	   info="Building for NetWare platform" />
+      <def name="__NOVELL_LIBC__" if="netware"
+	   info="Building for NetWare platform with LibC libraries" />
+           
+      <nlmmodule value="Apache2" if="netware" />
+      <import fileName="${novelllibc.home}/imports/libc.imp" if="netware" />
+      <import fileName="${novelllibc.home}/imports/ws2nlm.imp" if="netware" />
+      <import fileName="${apache2.home}/lib/httpd.imp" if="netware" />
+      <import fileName="${apache2.home}/lib/aprlib.imp" if="netware" />
+      <export symbol="jk_module" if="netware" />
+      <linkOpt value="-desc &quot;Apache 2.0 plugin for Tomcat&quot;" if="netware" />
+      <linkOpt value="-nlmversion 1,2,6" if="netware" />
+      <linkOpt value="-threadname &quot;mod_jk Module&quot;" if="netware" />
+      <linkOpt value="-stacksize 8192" if="netware" />
+      <linkOpt value="-l ${novelllibc.home}/imports" if="netware" />
+      <linkOpt value="-flags AUTOUNLOAD, PSEUDOPREEMPTION" if="netware" />
+      <linkOpt value="-entry _LibCPrelude" if="netware" />
+      <linkOpt value="-exit _LibCPostlude" if="netware" />
+    </so>
+
+  </target>
+  
+
+  <target name="apache13" depends="init" if="apache13.detect">
+    <mkdir dir="${jk.build}/jk/apache13" />
+    <so sofile="mod_jk" 
+	buildDir="${jk.build}/jk/apache13"
+	optimize="${so.optimize}"
+	debug="${so.debug}"
+	profile="${so.profile}">
+      <apacheConfig apxs="${apxs13}" />
+
+      <src dir=".">
+	<include name="apache-1.3/mod_jk.c" />
+	<include name="common/*.c" />
+	<exclude name="common/jk_jni_worker.c" />
+        <exclude name="common/jk_nwmain.c" unless="netware" />
+        <include name="common/apr/*.c" unless="HAVE_APR" />
+      </src>
+      <includes>
+	<include name="${native.dir}/common" />
+	<include name="${build.compiler.base}/include" />
+	<include name="${apache13.include}" />
+	<include name="${java.home}/../include" />
+
+        <!-- Platform specific includes -->
+	<include name="${apache13.home}/include" if="netware" />
+	<include name="${apache13.home}/os/netware" if="netware" />
+	<include name="${novellndk.home}/include/nlm" if="netware" />
+	<include name="${novellndk.home}/include" if="netware" />
+	<include name="${novellndk.home}/include/winsock" if="netware" />
+        <include name="${java.home}/../include/netware" if="netware" />
+                 
+	<include name="${apache13.home}/os/win32" if="win32" unless="netware" />
+        <include name="${java.home}/../include/win32" if="win32" unless="netware" />
+        <include name="${java.home}/../include/hp-ux" if="hpux" />
+        <include name="${native.dir}/common" if="win32" unless="netware" />
+      </includes>
+      <depends>
+	<fileset dir="${native.dir}/common" includes="*.h" />
+      </depends>
+
+      <!-- Platform-specific tags -->
+      <def name="N_PLAT_NLM" if="netware"
+	   info="Building for NetWare platform" />
+      <def name="NETWARE" if="netware"
+	   info="Building for NetWare platform" />
+      <def name="XP_NETWARE" if="netware"
+	   info="Building for NetWare platform" />
+      <def name="USE_SPRINTF" if="netware"
+	   info="Use the sprintf function to build strings" />
+           
+      <def name="HPUX11" if="hpux" />
+
+      <def name="WIN32" if="win32" unless="netware" />
+      <def name="DEBUG" if="win32.debug" unless="netware"  />
+      <def name="NDEBUG" if="win32.release" unless="netware"  />
+      <def name="_WINDOWS" if="win32" unless="netware" />
+      <def name="_MBCS" if="win32" unless="netware" />
+      <def name="_USRDLL" if="win32" unless="netware" />
+      <def name="MOD_JK_EXPORTS" if="win32" unless="netware" />
+      
+      <nlmmodule value="apache" if="netware" />
+      <import fileName="${novellndk.home}/imports/clib.imp" if="netware" />
+      <import fileName="${novellndk.home}/imports/lib0.imp" if="netware" />
+      <import fileName="${novellndk.home}/imports/nlmlib.imp" if="netware" />
+      <import fileName="${novellndk.home}/imports/threads.imp" if="netware" />
+      <import fileName="${novellndk.home}/imports/socklib.imp" if="netware" />
+      <import fileName="${novellndk.home}/imports/ws2nlm.imp" if="netware" />
+      <import fileName="${apache13.home}/os/netware/ApacheCore.imp" if="netware" />
+      <export symbol="jk_module" if="netware" />
+      <linkOpt value="-desc &quot;Apache 1.3 plugin for Tomcat&quot;" if="netware" />
+      <linkOpt value="-screenname &quot;System Console&quot;" if="netware" />
+      <linkOpt value="-nlmversion 1,2,6" if="netware" />
+      <linkOpt value="-threadname &quot;mod_jk Thread&quot;" if="netware" />
+      <linkOpt value="-stacksize 64000" if="netware" />
+      
+      <import fileName="ApacheCore.lib" if="win32" unless="netware" />
+      <import fileName="wsock32.lib" if="win32" unless="netware" />
+      <linkOpt value="/libpath:&quot;${build.compiler.base}/lib&quot;" if="win32" unless="netware" />
+      <linkOpt value="/libpath:&quot;${apache13.home}/CoreR&quot;" if="win32" unless="netware" />
+      <linkOpt value="/libpath:&quot;${apache13.home}/Release&quot;" if="win32" unless="netware" />
+      <linkOpt value="/libpath:&quot;${apache13.home}/libexec&quot;" if="win32" unless="netware" />
+    </so>
+  </target>
+
+  <target name="iis" depends="init" if="iis.detect">
+    <mkdir dir="${jk.build}/jk/iis" />
+    <so sofile="isapi_redirector" 
+        buildDir="${jk.build}/jk/iis"
+        optimize="${so.optimize}"
+        debug="${so.debug}"
+        profile="${so.profile}">
+        
+      <src dir=".">
+        <include name="iis/jk_isapi_plugin.c" />
+        <include name="common/*.c" />
+        <exclude name="common/jk_nwmain.c" unless="netware" />
+        <include name="common/apr/*.c" unless="HAVE_APR" />
+      </src>
+      <includes>
+        <include name="${java.home}/../include" />
+        <include name="${java.home}/../include/win32" />
+        <include name="${native.dir}/common" />
+        <include name="${mssdk.include}" />
+        <include name="${build.compiler.base}/include" />
+      </includes>
+      <depends>
+        <fileset dir="${native.dir}/common" includes="*.h" />
+      </depends>
+        
+      <!-- Platform-specific tags -->
+      <def name="WIN32" />
+      <def name="DEBUG" if="win32.debug"  />
+      <def name="NDEBUG" if="win32.release"  />
+      <def name="_WINDOWS"  />
+      <def name="_MBCS" />
+      <def name="_USRDLL" />
+      <def name="ISAPI_EXPORTS" />
+      <import fileName="advapi32.lib" />
+      <import fileName="wsock32.lib" />
+      <export symbol="HttpFilterProc"/>
+      <export symbol="GetFilterVersion"/>
+      <export symbol="GetExtensionVersion"/>
+      <export symbol="HttpExtensionProc"/>
+      <export symbol="TerminateFilter"/>
+      <export symbol="TerminateExtension"/>
+      <linkOpt value="/libpath:&quot;${mssdk.lib}&quot;" />
+      <linkOpt value="/libpath:&quot;${build.compiler.base}/lib&quot;" />
+    </so>
+  </target>
+
+  <target name="netscape" depends="init" if="iplanet.detect">
+    <mkdir dir="${jk.build}/jk/netscape" />
+    <property name="netscape.home" value="${iplanet.home}/plugins" />
+    <available property="unix" file="/etc/passwd" />
+    <so sofile="nsapi_redirector" 
+	buildDir="${jk.build}/jk/netscape"
+	optimize="${so.optimize}"
+	debug="${so.debug}"
+	profile="${so.profile}">
+
+      <src dir=".">
+	<include name="netscape/jk_nsapi_plugin.c" />
+	<include name="common/*.c" />
+        <exclude name="common/jk_nwmain.c" unless="netware" />
+        <include name="common/apr/*.c" unless="HAVE_APR" />
+      </src>
+      <includes>
+	<include name="${native.dir}/common" />
+	<include name="${build.compiler.base}/include" />
+	<include name="${netscape.home}/include" />
+	<include name="${java.home}/../include" />
+
+        <!-- Platform specific includes -->
+        
+	<include name="${novellndk.home}/include/nlm" if="netware" />
+	<include name="${novellndk.home}/include" if="netware" />
+        <include name="${java.home}/../include/linux" if="linux" />
+        <include name="${java.home}/../include/netware" if="netware" />
+                 
+	<include name="${apache13.home}/os/win32" if="win32" unless="netware" />
+        <include name="${java.home}/../include/win32" if="win32" unless="netware" />
+        <include name="${native.dir}/common" if="win32" unless="netware" />
+      </includes>
+      <depends>
+	<fileset dir="${native.dir}/common" includes="*.h" />
+      </depends>
+
+      <!-- Platform-specific tags -->
+      <altSoFile value="nsapi_rd" if="netware" />
+
+      <def name="XP_UNIX" if="unix"
+	   info="Building for unix platform" />
+      
+      <def name="N_PLAT_NLM" if="netware"
+	   info="Building for NetWare platform" />
+      <def name="NETWARE" if="netware"
+	   info="Building for NetWare platform" />
+      <def name="XP_NETWARE" if="netware"
+	   info="Building for NetWare platform" />
+      <def name="USE_SPRINTF" if="netware"
+	   info="Use the sprintf function to build strings" />
+           
+      <def name="WIN32" if="win32" unless="netware" />
+      <def name="DEBUG" if="win32.debug" unless="netware"  />
+      <def name="NDEBUG" if="win32.release" unless="netware"  />
+      <def name="_WINDOWS" if="win32" unless="netware" />
+      <def name="_MBCS" if="win32" unless="netware" />
+      <def name="_USRDLL" if="win32" unless="netware" />
+      <def name="XP_WIN32" if="win32" unless="netware" />
+      <def name="NSAPI_EXPORTS" if="win32" unless="netware" />
+      
+      <def name="XP_UNIX" if="unix"
+	   info="Unix platform - needed for nsapi.h" />
+      
+      <nlmmodule value="nshttpd" if="netware" />
+      <import fileName="${novellndk.home}/imports/clib.imp" if="netware" />
+      <import fileName="${novellndk.home}/imports/lib0.imp" if="netware" />
+      <import fileName="${novellndk.home}/imports/nlmlib.imp" if="netware" />
+      <import fileName="${novellndk.home}/imports/threads.imp" if="netware" />
+      <import fileName="${novellndk.home}/imports/socklib.imp" if="netware" />
+      <import fileName="${netscape.home}/imports/nsapi.imp" if="netware" />
+      <export symbol="jk_init" if="netware" />
+      <export symbol="jk_service" if="netware" />
+      <linkOpt value="-desc &quot;Netscape Plugin for Tomcat&quot;" if="netware" />
+      <linkOpt value="-screenname &quot;System Console&quot;" if="netware" />
+      <linkOpt value="-nlmversion 1,2,6" if="netware" />
+      <linkOpt value="-threadname &quot;NSTomcat Thread&quot;" if="netware" />
+      <linkOpt value="-stacksize 64000" if="netware" />
+      
+      <import fileName="ns-httpd36.lib" if="win32" unless="netware" />
+      <import fileName="wsock32.lib" if="win32" unless="netware" />
+      <linkOpt value="/libpath:&quot;${build.compiler.base}/lib&quot;" if="win32" unless="netware" />
+      <linkOpt value="/libpath:&quot;${netscape.home}/lib&quot;" if="win32" unless="netware" />
+    </so>
+  </target>
+
+  <target name="clean" >
+    <delete dir="${jk.build}/jk"/>
+  </target>
+
+</project>

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/buildconf.sh
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/buildconf.sh	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/buildconf.sh	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,20 @@
+#!/bin/sh
+
+echo "rm autom4te.cache"
+rm -rf autom4te.cache
+
+echo "libtoolize --force --automake --copy"
+libtoolize --force --automake --copy
+echo "aclocal"
+#aclocal --acdir=`aclocal --print-ac-dir`
+#aclocal --acdir=/usr/local/share/aclocal
+aclocal
+echo "autoheader"
+autoheader
+echo "automake -a --foreign --copy"
+automake -a --foreign --copy
+echo "autoconf"
+autoconf
+
+echo "rm autom4te.cache"
+rm -rf autom4te.cache


Property changes on: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/buildconf.sh
___________________________________________________________________
Name: svn:executable
   + 

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/.indent.pro
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/.indent.pro	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/.indent.pro	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,18 @@
+-i4 -npsl -di0 -br -nce -d0 -cli0 -npcs -nfc1 -nut -ncs
+-Tjk_env_t
+-Tjk_worker_t
+-Tjk_worker_env_t
+-Tjk_endpoint_t
+-Tjk_channel_t
+-Tjk_sockbuf_t
+-Tjk_msg_t
+-Tjk_msg_buf_t
+-Tjk_map_t
+-Tjk_uri_worker_map_t
+-Tjk_pool_t
+-Tjk_pool_atom_t
+-Tjk_logger_t
+-Tjk_ws_service_t
+-Tjk_context_item_t
+-Tjk_context_t
+-Tjk_login_service_t

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/Makefile.in
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/Makefile.in	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/Makefile.in	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,32 @@
+#### XXXX DO we need this Makefile ????
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+APXSLDFLAGS=@APXSLDFLAGS@
+APXSCFLAGS=@APXSCFLAGS@
+APXSCPPFLAGS=@APXSCPPFLAGS@
+
+top_builddir = ..
+
+LIBTOOL = @LIBTOOL@
+CC = @CC@
+
+OEXT=.lo
+include list.mk
+
+JAVA_INCL=-I @JAVA_HOME@/include -I @JAVA_HOME@/include/@OS@
+CFLAGS=@apache_include@ @CFLAGS@ ${APXSCFLAGS} ${APXSCPPFLAGS} ${JAVA_INCL}
+
+include @top_srcdir@/scripts/build/rules.mk
+
+JK=./
+
+all: ${APACHE_OBJECTS}
+
+install:
+
+clean:
+	rm -f *.o *.lo *.a *.la *.so *.so.* *.slo
+	rm -rf .libs

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_ajp12_worker.c
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_ajp12_worker.c	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_ajp12_worker.c	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,660 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.
+ */
+
+/***************************************************************************
+ * Description: ajpv1.2 worker, used to call local or remote jserv hosts   *
+ *              This worker is deprecated                                  *
+ * Author:      Gal Shachor <shachor at il.ibm.com>                           *
+ * Based on:    jserv_ajpv12.c from Jserv                                  *
+ * Version:     $Revision: 434177 $                                          *
+ ***************************************************************************/
+
+#include "jk_ajp12_worker.h"
+#include "jk_pool.h"
+#include "jk_connect.h"
+#include "jk_util.h"
+#include "jk_sockbuf.h"
+#ifdef AS400
+#include "util_ebcdic.h"
+#include <string.h>
+#endif
+
+#define AJP_DEF_HOST            ("localhost")
+#define AJP_DEF_PORT            (8007)
+#define READ_BUF_SIZE           (8*1024)
+#define DEF_RETRY_ATTEMPTS      (1)
+
+struct ajp12_worker
+{
+    struct sockaddr_in worker_inet_addr;
+    unsigned connect_retry_attempts;
+    char *name;
+    jk_worker_t worker;
+};
+
+typedef struct ajp12_worker ajp12_worker_t;
+
+struct ajp12_endpoint
+{
+    ajp12_worker_t *worker;
+
+    jk_sock_t sd;
+    jk_sockbuf_t sb;
+
+    jk_endpoint_t endpoint;
+};
+typedef struct ajp12_endpoint ajp12_endpoint_t;
+
+static int ajpv12_mark(ajp12_endpoint_t * p, unsigned char type);
+
+#ifdef AS400
+static int ajpv12_sendasciistring(ajp12_endpoint_t * p, char *buffer);
+#endif
+
+#ifdef AS400
+static int ajpv12_sendstring(ajp12_endpoint_t * p, char *buffer);
+#else
+static int ajpv12_sendstring(ajp12_endpoint_t * p, const char *buffer);
+#endif
+
+static int ajpv12_sendint(ajp12_endpoint_t * p, int d);
+
+static int ajpv12_sendnbytes(ajp12_endpoint_t * p,
+                             const void *buffer, int bufferlen);
+
+static int ajpv12_flush(ajp12_endpoint_t * p);
+
+static int ajpv12_handle_response(ajp12_endpoint_t * p,
+                                  jk_ws_service_t *s, jk_logger_t *l);
+
+static int ajpv12_handle_request(ajp12_endpoint_t * p,
+                                 jk_ws_service_t *s, jk_logger_t *l);
+
+static int JK_METHOD service(jk_endpoint_t *e,
+                             jk_ws_service_t *s,
+                             jk_logger_t *l, int *is_error)
+{
+    ajp12_endpoint_t *p = e->endpoint_private;
+    unsigned int attempt;
+    int rc = -1;
+    /*
+     * AJP12 protocol is not recoverable.
+     */
+
+    JK_TRACE_ENTER(l);
+ 
+    if (is_error)
+        *is_error = JK_HTTP_SERVER_ERROR;
+    if (!e || !e->endpoint_private || !s || !is_error) {
+        JK_LOG_NULL_PARAMS(l);
+        JK_TRACE_EXIT(l);
+        return JK_FALSE;
+    }
+
+    for (attempt = 0; attempt < p->worker->connect_retry_attempts;
+         attempt++) {
+        p->sd =
+            jk_open_socket(&p->worker->worker_inet_addr,
+                           JK_FALSE, -1, 0, l);
+
+        jk_log(l, JK_LOG_DEBUG, "In jk_endpoint_t::service, sd = %d",
+               p->sd);
+        if (IS_VALID_SOCKET(p->sd)) {
+            break;
+        }
+    }
+    if (IS_VALID_SOCKET(p->sd)) {
+
+        jk_sb_open(&p->sb, p->sd);
+        if (ajpv12_handle_request(p, s, l)) {
+            jk_log(l, JK_LOG_DEBUG,
+                   "In jk_endpoint_t::service, sent request");
+            rc = ajpv12_handle_response(p, s, l);
+            JK_TRACE_EXIT(l);
+            return rc;
+        }
+    }
+    jk_log(l, JK_LOG_ERROR, "In jk_endpoint_t::service, Error sd = %d",
+           p->sd);
+
+    JK_TRACE_EXIT(l);
+    return JK_FALSE;
+}
+
+static int JK_METHOD done(jk_endpoint_t **e, jk_logger_t *l)
+{
+    jk_log(l, JK_LOG_DEBUG, "Into jk_endpoint_t::done");
+    if (e && *e && (*e)->endpoint_private) {
+        ajp12_endpoint_t *p = (*e)->endpoint_private;
+        if (IS_VALID_SOCKET(p->sd)) {
+            jk_close_socket(p->sd);
+        }
+        free(p);
+        *e = NULL;
+        return JK_TRUE;
+    }
+
+    jk_log(l, JK_LOG_ERROR, "In jk_endpoint_t::done, NULL parameters");
+    return JK_FALSE;
+}
+
+static int JK_METHOD validate(jk_worker_t *pThis,
+                              jk_map_t *props,
+                              jk_worker_env_t *we, jk_logger_t *l)
+{
+    jk_log(l, JK_LOG_DEBUG, "Into jk_worker_t::validate");
+
+    if (pThis && pThis->worker_private) {
+        ajp12_worker_t *p = pThis->worker_private;
+        int port = jk_get_worker_port(props,
+                                      p->name,
+                                      AJP_DEF_PORT);
+
+        const char *host = jk_get_worker_host(props,
+                                        p->name,
+                                        AJP_DEF_HOST);
+
+        jk_log(l, JK_LOG_DEBUG,
+               "In jk_worker_t::validate for worker %s contact is %s:%d",
+               p->name, host, port);
+
+        if (port > 1024 && host) {
+            if (jk_resolve(host, port, &p->worker_inet_addr)) {
+                return JK_TRUE;
+            }
+            jk_log(l, JK_LOG_ERROR,
+                   "In jk_worker_t::validate, resolve failed");
+        }
+        jk_log(l, JK_LOG_ERROR, "In jk_worker_t::validate, Error %s %d",
+               host, port);
+    }
+    else {
+        jk_log(l, JK_LOG_ERROR,
+               "In jk_worker_t::validate, NULL parameters");
+    }
+
+    return JK_FALSE;
+}
+
+static int JK_METHOD init(jk_worker_t *pThis,
+                          jk_map_t *props,
+                          jk_worker_env_t *we, jk_logger_t *log)
+{
+    /* Nothing to do for now */
+    return JK_TRUE;
+}
+
+static int JK_METHOD get_endpoint(jk_worker_t *pThis,
+                                  jk_endpoint_t **pend, jk_logger_t *l)
+{
+    jk_log(l, JK_LOG_DEBUG, "Into jk_worker_t::get_endpoint");
+
+    if (pThis && pThis->worker_private && pend) {
+        ajp12_endpoint_t *p =
+            (ajp12_endpoint_t *) malloc(sizeof(ajp12_endpoint_t));
+        if (p) {
+            p->sd = JK_INVALID_SOCKET;
+            p->worker = pThis->worker_private;
+            p->endpoint.endpoint_private = p;
+            p->endpoint.service = service;
+            p->endpoint.done = done;
+            *pend = &p->endpoint;
+            return JK_TRUE;
+        }
+        jk_log(l, JK_LOG_ERROR,
+               "In jk_worker_t::get_endpoint, malloc failed");
+    }
+    else {
+        jk_log(l, JK_LOG_ERROR,
+               "In jk_worker_t::get_endpoint, NULL parameters");
+    }
+
+    return JK_FALSE;
+}
+
+static int JK_METHOD destroy(jk_worker_t **pThis, jk_logger_t *l)
+{
+    jk_log(l, JK_LOG_DEBUG, "Into jk_worker_t::destroy");
+    if (pThis && *pThis && (*pThis)->worker_private) {
+        ajp12_worker_t *private_data = (*pThis)->worker_private;
+        free(private_data->name);
+        free(private_data);
+
+        return JK_TRUE;
+    }
+
+    jk_log(l, JK_LOG_ERROR, "In jk_worker_t::destroy, NULL parameters");
+    return JK_FALSE;
+}
+
+int JK_METHOD ajp12_worker_factory(jk_worker_t **w,
+                                   const char *name, jk_logger_t *l)
+{
+    jk_log(l, JK_LOG_DEBUG, "Into ajp12_worker_factory");
+    if (NULL != name && NULL != w) {
+        ajp12_worker_t *private_data =
+            (ajp12_worker_t *) malloc(sizeof(ajp12_worker_t));
+
+        if (private_data) {
+            private_data->name = strdup(name);
+
+            if (private_data->name) {
+                private_data->connect_retry_attempts = DEF_RETRY_ATTEMPTS;
+                private_data->worker.worker_private = private_data;
+
+                private_data->worker.validate = validate;
+                private_data->worker.init = init;
+                private_data->worker.get_endpoint = get_endpoint;
+                private_data->worker.destroy = destroy;
+                private_data->worker.maintain = NULL;
+                private_data->worker.retries = JK_RETRIES;
+
+                *w = &private_data->worker;
+                return JK_AJP12_WORKER_TYPE;
+            }
+
+            free(private_data);
+        }
+        jk_log(l, JK_LOG_ERROR, "In ajp12_worker_factory, malloc failed");
+    }
+    else {
+        jk_log(l, JK_LOG_ERROR, "In ajp12_worker_factory, NULL parameters");
+    }
+
+    return 0;
+}
+
+static int ajpv12_sendnbytes(ajp12_endpoint_t * p,
+                             const void *buffer, int bufferlen)
+{
+    unsigned char bytes[2];
+    static const unsigned char null_b[2] =
+        { (unsigned char)0xff, (unsigned char)0xff };
+
+    if (buffer) {
+        bytes[0] = (unsigned char)((bufferlen >> 8) & 0xff);
+        bytes[1] = (unsigned char)(bufferlen & 0xff);
+
+        if (jk_sb_write(&p->sb, bytes, 2)) {
+            return jk_sb_write(&p->sb, buffer, bufferlen);
+        }
+        else {
+            return JK_FALSE;
+        }
+    }
+    else {
+        return jk_sb_write(&p->sb, null_b, 2);
+    }
+}
+
+#ifdef AS400
+static int ajpv12_sendasciistring(ajp12_endpoint_t * p, const char *buffer)
+{
+    int bufferlen;
+
+    if (buffer && (bufferlen = strlen(buffer))) {
+        return ajpv12_sendnbytes(p, buffer, bufferlen);
+    }
+    else {
+        return ajpv12_sendnbytes(p, NULL, 0);
+    }
+}
+#endif
+
+static int ajpv12_sendstring(ajp12_endpoint_t * p, const char *buffer)
+{
+    int bufferlen;
+
+    if (buffer && (bufferlen = (int)strlen(buffer))) {
+#if defined(AS400) || defined(_OSD_POSIX)
+        char buf[2048];
+        if (bufferlen < 2048) {
+            memcpy(buf, buffer, bufferlen);
+            jk_xlate_to_ascii(buf, bufferlen);
+            return ajpv12_sendnbytes(p, buf, bufferlen);
+        }
+        else
+            return -1;
+#else
+        return ajpv12_sendnbytes(p, buffer, bufferlen);
+#endif
+    }
+    else {
+        return ajpv12_sendnbytes(p, NULL, 0);
+    }
+}
+
+static int ajpv12_mark(ajp12_endpoint_t * p, unsigned char type)
+{
+    if (jk_sb_write(&p->sb, &type, 1)) {
+        return JK_TRUE;
+    }
+    else {
+        return JK_FALSE;
+    }
+}
+
+static int ajpv12_sendint(ajp12_endpoint_t * p, int d)
+{
+    char buf[20];
+    sprintf(buf, "%d", d);
+    return ajpv12_sendstring(p, buf);
+}
+
+static int ajpv12_flush(ajp12_endpoint_t * p)
+{
+    return jk_sb_flush(&p->sb);
+}
+
+static int ajpv12_handle_request(ajp12_endpoint_t * p,
+                                 jk_ws_service_t *s, jk_logger_t *l)
+{
+    int ret;
+
+    jk_log(l, JK_LOG_DEBUG, "Into ajpv12_handle_request");
+    /*
+     * Start the ajp 12 service sequence
+     */
+    jk_log(l, JK_LOG_DEBUG,
+           "ajpv12_handle_request, sending the ajp12 start sequence");
+
+    ret = (ajpv12_mark(p, 1) && ajpv12_sendstring(p, s->method) && ajpv12_sendstring(p, 0) &&   /* zone */
+           ajpv12_sendstring(p, 0) &&   /* servlet */
+           ajpv12_sendstring(p, s->server_name) && ajpv12_sendstring(p, 0) &&   /* doc root */
+           ajpv12_sendstring(p, 0) &&   /* path info */
+           ajpv12_sendstring(p, 0) &&   /* path translated */
+#ifdef AS400
+           ajpv12_sendasciistring(p, s->query_string) &&
+#else
+           ajpv12_sendstring(p, s->query_string) &&
+#endif
+           ajpv12_sendstring(p, s->remote_addr) &&
+           ajpv12_sendstring(p, s->remote_host) &&
+           ajpv12_sendstring(p, s->remote_user) &&
+           ajpv12_sendstring(p, s->auth_type) &&
+           ajpv12_sendint(p, s->server_port) &&
+#ifdef AS400
+           ajpv12_sendasciistring(p, s->method) &&
+#else
+           ajpv12_sendstring(p, s->method) &&
+#endif
+           ajpv12_sendstring(p, s->req_uri) && ajpv12_sendstring(p, 0) &&       /* */
+           ajpv12_sendstring(p, 0) &&   /* SCRIPT_NAME */
+#ifdef AS400
+           ajpv12_sendasciistring(p, s->server_name) &&
+#else
+           ajpv12_sendstring(p, s->server_name) &&
+#endif
+           ajpv12_sendint(p, s->server_port) && ajpv12_sendstring(p, s->protocol) && ajpv12_sendstring(p, 0) && /* SERVER_SIGNATURE */
+           ajpv12_sendstring(p, s->server_software) && ajpv12_sendstring(p, s->jvm_route) &&    /* JSERV_ROUTE */
+           ajpv12_sendstring(p, "") &&  /* JSERV ajpv12 compatibility */
+           ajpv12_sendstring(p, ""));   /* JSERV ajpv12 compatibility */
+
+    if (!ret) {
+        jk_log(l, JK_LOG_ERROR,
+               "In ajpv12_handle_request, failed to send the ajp12 start sequence");
+        return JK_FALSE;
+    }
+
+    if (s->num_attributes > 0) {
+        unsigned i;
+        jk_log(l, JK_LOG_DEBUG,
+               "ajpv12_handle_request, sending the environment variables");
+
+        for (i = 0; i < s->num_attributes; i++) {
+            ret = (ajpv12_mark(p, 5) &&
+                   ajpv12_sendstring(p, s->attributes_names[i]) &&
+                   ajpv12_sendstring(p, s->attributes_values[i]));
+            if (!ret) {
+                jk_log(l, JK_LOG_ERROR,
+                       "In ajpv12_handle_request, failed to send environment");
+                return JK_FALSE;
+            }
+        }
+    }
+
+    jk_log(l, JK_LOG_DEBUG, "ajpv12_handle_request, sending the headers");
+
+    /* Send the request headers */
+    if (s->num_headers) {
+        unsigned i;
+        for (i = 0; i < s->num_headers; ++i) {
+            ret = (ajpv12_mark(p, 3) &&
+                   ajpv12_sendstring(p, s->headers_names[i]) &&
+                   ajpv12_sendstring(p, s->headers_values[i]));
+
+            if (!ret) {
+                jk_log(l, JK_LOG_ERROR,
+                       "In ajpv12_handle_request, failed to send headers");
+                return JK_FALSE;
+            }
+        }
+    }
+
+    jk_log(l, JK_LOG_DEBUG,
+           "ajpv12_handle_request, sending the terminating mark");
+
+    ret = (ajpv12_mark(p, 4) && ajpv12_flush(p));
+    if (!ret) {
+        jk_log(l, JK_LOG_ERROR,
+               "In ajpv12_handle_request, failed to send the terminating mark");
+        return JK_FALSE;
+    }
+
+    if (s->content_length) {
+        char buf[READ_BUF_SIZE];
+        unsigned so_far = 0;
+
+        jk_log(l, JK_LOG_DEBUG,
+               "ajpv12_handle_request, sending the request body");
+
+        while (so_far < s->content_length) {
+            unsigned this_time = 0;
+            unsigned to_read = s->content_length - so_far;
+            if (to_read > READ_BUF_SIZE) {
+                to_read = READ_BUF_SIZE;
+            }
+
+            if (!s->read(s, buf, to_read, &this_time)) {
+                jk_log(l, JK_LOG_ERROR,
+                       "In ajpv12_handle_request, failed to read from the web server");
+                return JK_FALSE;
+            }
+            jk_log(l, JK_LOG_DEBUG, "ajpv12_handle_request, read %d bytes",
+                   this_time);
+            if (this_time > 0) {
+                so_far += this_time;
+                if ((int)this_time != send(p->sd, buf, this_time, 0)) {
+                    jk_log(l, JK_LOG_ERROR,
+                           "In ajpv12_handle_request, failed to write to the container");
+                    return JK_FALSE;
+                }
+                jk_log(l, JK_LOG_DEBUG,
+                       "ajpv12_handle_request, sent %d bytes", this_time);
+            }
+            else if (this_time == 0) {
+                jk_log(l, JK_LOG_ERROR,
+                       "In ajpv12_handle_request, Error: short read. content length is %d, read %d",
+                       s->content_length, so_far);
+                return JK_FALSE;
+            }
+        }
+    }
+
+    jk_log(l, JK_LOG_DEBUG, "ajpv12_handle_request done");
+    return JK_TRUE;
+}
+
+static int ajpv12_handle_response(ajp12_endpoint_t * p,
+                                  jk_ws_service_t *s, jk_logger_t *l)
+{
+    int status = 200;
+    char *reason = NULL;
+    char **names = NULL;
+    char **values = NULL;
+    int headers_capacity = 0;
+    int headers_len = 0;
+    int write_to_ws;
+
+    jk_log(l, JK_LOG_DEBUG, "Into ajpv12_handle_response");
+    /*
+     * Read headers ...
+     */
+    while (1) {
+        char *line = NULL;
+        char *name = NULL;
+        char *value = NULL;
+#if defined(AS400) || defined(_REENTRANT)
+        char *lasts;
+#endif
+
+        if (!jk_sb_gets(&p->sb, &line)) {
+            jk_log(l, JK_LOG_ERROR,
+                   "ajpv12_handle_response, error reading header line");
+            return JK_FALSE;
+        }
+#if defined(AS400) || defined(_OSD_POSIX)
+        jk_xlate_from_ascii(line, strlen(line));
+#endif
+
+        jk_log(l, JK_LOG_DEBUG, "ajpv12_handle_response, read %s", line);
+        if (0 == strlen(line)) {
+            jk_log(l, JK_LOG_DEBUG,
+                   "ajpv12_handle_response, headers are done");
+            break;              /* Empty line -> end of headers */
+        }
+
+        name = line;
+        while (isspace(*name) && *name) {
+            name++;             /* Skip leading white chars */
+        }
+        if (!*name) {           /* Empty header name */
+            jk_log(l, JK_LOG_ERROR,
+                   "ajpv12_handle_response, empty header name");
+            return JK_FALSE;
+        }
+        if (!(value = strchr(name, ':'))) {
+            jk_log(l, JK_LOG_ERROR,
+                   "ajpv12_handle_response, no value supplied");
+            return JK_FALSE;    /* No value !!! */
+        }
+        *value = '\0';
+        value++;
+        while (isspace(*value) && *value) {
+            value++;            /* Skip leading white chars */
+        }
+        if (!*value) {          /* Empty header value */
+            jk_log(l, JK_LOG_ERROR,
+                   "ajpv12_handle_response, empty header value");
+            return JK_FALSE;
+        }
+
+        jk_log(l, JK_LOG_DEBUG, "ajpv12_handle_response, read %s=%s", name,
+               value);
+        if (0 == strcmp("Status", name)) {
+#if defined(AS400) || defined(_REENTRANT)
+            char *numeric = strtok_r(value, " \t", &lasts);
+#else
+            char *numeric = strtok(value, " \t");
+#endif
+
+            status = atoi(numeric);
+            if (status < 100 || status > 999) {
+                jk_log(l, JK_LOG_ERROR,
+                       "ajpv12_handle_response, invalid status code");
+                return JK_FALSE;
+            }
+#if defined(AS400) || defined(_REENTRANT)
+            reason = jk_pool_strdup(s->pool, strtok_r(NULL, " \t", &lasts));
+#else
+            reason = jk_pool_strdup(s->pool, strtok(NULL, " \t"));
+#endif
+        }
+        else {
+            if (headers_capacity == headers_len) {
+                jk_log(l, JK_LOG_DEBUG,
+                       "ajpv12_handle_response, allocating header arrays");
+                names =
+                    (char **)jk_pool_realloc(s->pool,
+                                             sizeof(char *) *
+                                             (headers_capacity + 5), names,
+                                             sizeof(char *) *
+                                             headers_capacity);
+                values =
+                    (char **)jk_pool_realloc(s->pool,
+                                             sizeof(char *) *
+                                             (headers_capacity + 5), values,
+                                             sizeof(char *) *
+                                             headers_capacity);
+                if (!values || !names) {
+                    jk_log(l, JK_LOG_ERROR,
+                           "ajpv12_handle_response, malloc error");
+                    return JK_FALSE;
+                }
+                headers_capacity = headers_capacity + 5;
+            }
+            names[headers_len] = jk_pool_strdup(s->pool, name);
+            values[headers_len] = jk_pool_strdup(s->pool, value);
+            headers_len++;
+        }
+    }
+
+    jk_log(l, JK_LOG_DEBUG, "ajpv12_handle_response, starting response");
+    if (!s->start_response(s,
+                           status,
+                           reason,
+                           (const char *const *)names,
+                           (const char *const *)values, headers_len)) {
+        jk_log(l, JK_LOG_ERROR,
+               "ajpv12_handle_response, error starting response");
+        return JK_FALSE;
+    }
+
+    jk_log(l, JK_LOG_DEBUG,
+           "ajpv12_handle_response, reading response body");
+    /*
+     * Read response body
+     */
+    write_to_ws = JK_TRUE;
+    while (1) {
+        unsigned to_read = READ_BUF_SIZE;
+        unsigned acc = 0;
+        char *buf = NULL;
+
+        if (!jk_sb_read(&p->sb, &buf, to_read, &acc)) {
+            jk_log(l, JK_LOG_ERROR,
+                   "ajpv12_handle_response, error reading from ");
+            return JK_FALSE;
+        }
+
+        if (!acc) {
+            jk_log(l, JK_LOG_DEBUG,
+                   "ajpv12_handle_response, response body is done");
+            break;
+        }
+
+        if (write_to_ws) {
+            if (!s->write(s, buf, acc)) {
+                jk_log(l, JK_LOG_ERROR,
+                       "ajpv12_handle_response, error writing back to server");
+                write_to_ws = JK_FALSE;
+            }
+        }
+    }
+
+    jk_log(l, JK_LOG_DEBUG, "ajpv12_handle_response done");
+    return JK_TRUE;
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_ajp12_worker.h
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_ajp12_worker.h	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_ajp12_worker.h	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,44 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.
+ */
+
+/***************************************************************************
+ * Description: ajpv1.2 worker header file                                 *
+ * Author:      Gal Shachor <shachor at il.ibm.com>                           *
+ * Version:     $Revision: 300224 $                                           *
+ ***************************************************************************/
+
+#ifndef JK_AJP12_WORKER_H
+#define JK_AJP12_WORKER_H
+
+#include "jk_logger.h"
+#include "jk_service.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif                          /* __cplusplus */
+
+#define JK_AJP12_WORKER_NAME ("ajp12")
+#define JK_AJP12_WORKER_TYPE (1)
+
+int JK_METHOD ajp12_worker_factory(jk_worker_t **w,
+                                   const char *name, jk_logger_t *l);
+
+#ifdef __cplusplus
+}
+#endif                          /* __cplusplus */
+
+#endif                          /* JK_AJP12_WORKER_H */

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_ajp13.c
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_ajp13.c	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_ajp13.c	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,49 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.
+ */
+
+/***************************************************************************
+ * Description: Experimental bi-directionl protocol handler.               *
+ * Author:      Gal Shachor <shachor at il.ibm.com>                           *
+ * Author:      Henri Gomez <hgomez at apache.org>                            *
+ * Version:     $Revision: 300145 $                                           *
+ ***************************************************************************/
+
+
+#include "jk_global.h"
+#include "jk_util.h"
+#include "jk_ajp_common.h"
+#include "jk_ajp13.h"
+
+int ajp13_marshal_shutdown_into_msgb(jk_msg_buf_t *msg,
+                                     jk_pool_t *p, jk_logger_t *l)
+{
+    JK_TRACE_ENTER(l);
+    /* To be on the safe side */
+    jk_b_reset(msg);
+
+    /*
+     * Just a single byte with s/d command.
+     */
+    if (jk_b_append_byte(msg, JK_AJP13_SHUTDOWN)) {
+        jk_log(l, JK_LOG_ERROR,
+               "failed appending shutdown message");
+        JK_TRACE_EXIT(l);
+        return JK_FALSE;
+    }
+
+    JK_TRACE_EXIT(l);
+    return JK_TRUE;
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_ajp13.h
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_ajp13.h	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_ajp13.h	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,121 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.
+ */
+
+/***************************************************************************
+ * Description: Experimental bi-directionl protocol handler.               *
+ * Author:      Gal Shachor <shachor at il.ibm.com>                           *
+ * Version:     $Revision: 440649 $                                           *
+ ***************************************************************************/
+#ifndef JK_AJP13_H
+#define JK_AJP13_H
+
+#include "jk_ajp_common.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif                          /* __cplusplus */
+
+#define AJP13_PROTO                 13
+#define AJP13_WS_HEADER             0x1234
+#define AJP13_SW_HEADER             0x4142      /* 'AB' */
+
+#define AJP13_DEF_HOST              ("localhost")
+#define AJP13_DEF_PORT              (8009)
+#define AJP13_READ_BUF_SIZE         (8*1024)
+#define AJP13_DEF_CACHE_SZ          (1)
+#define JK_INTERNAL_ERROR           (-2)
+#define JK_FATAL_ERROR              (-3)
+#define JK_CLIENT_ERROR             (-4)
+#define JK_SERVER_ERROR             (-5)
+#define JK_CLIENT_RD_ERROR          (-6)
+#define JK_CLIENT_WR_ERROR          (-7)
+
+#define AJP13_MAX_SEND_BODY_SZ      (DEF_BUFFER_SZ - 6)
+#define AJP13_DEF_TIMEOUT           (0) /* Idle timout for pooled connections */
+
+/*
+ * Message does not have a response (for example, JK_AJP13_END_RESPONSE)
+ */
+#define JK_AJP13_ERROR              -1
+/*
+ * Message does not have a response (for example, JK_AJP13_END_RESPONSE)
+ */
+#define JK_AJP13_NO_RESPONSE        0
+/*
+ * Message have a response.
+ */
+#define JK_AJP13_HAS_RESPONSE       1
+
+/*
+ * Forward a request from the web server to the servlet container.
+ */
+#define JK_AJP13_FORWARD_REQUEST    (unsigned char)2
+
+/*
+ * Write a body chunk from the servlet container to the web server
+ */
+#define JK_AJP13_SEND_BODY_CHUNK    (unsigned char)3
+
+/*
+ * Send response headers from the servlet container to the web server.
+ */
+#define JK_AJP13_SEND_HEADERS       (unsigned char)4
+
+/*
+ * Marks the end of response.
+ */
+#define JK_AJP13_END_RESPONSE       (unsigned char)5
+
+/*
+ * Marks the end of response.
+ */
+#define JK_AJP13_GET_BODY_CHUNK     (unsigned char)6
+
+/*
+ * Asks the container to shutdown
+ */
+#define JK_AJP13_SHUTDOWN           (unsigned char)7
+
+/*
+ * Told container to take control (secure login phase)
+ */
+#define AJP13_PING_REQUEST          (unsigned char)8
+
+/*
+ * Check if the container is alive
+ */
+#define AJP13_CPING_REQUEST          (unsigned char)10
+
+/*
+ * Reply from the container to alive request
+ */
+#define AJP13_CPONG_REPLY            (unsigned char)9
+
+
+
+/*
+ * Functions
+ */
+
+int ajp13_marshal_shutdown_into_msgb(jk_msg_buf_t *msg,
+                                     jk_pool_t *p, jk_logger_t *l);
+
+#ifdef __cplusplus
+}
+#endif                          /* __cplusplus */
+
+#endif                          /* JK_AJP13_H */

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_ajp13_worker.c
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_ajp13_worker.c	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_ajp13_worker.c	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,119 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.
+ */
+
+/***************************************************************************
+ * Description: Bi-directional protocol.                                   *
+ * Author:      Costin <costin at costin.dnt.ro>                              *
+ * Author:      Gal Shachor <shachor at il.ibm.com>                           *
+ * Author:      Henri Gomez <hgomez at apache.org>                            *
+ * Version:     $Revision: 300520 $                                          *
+ ***************************************************************************/
+
+#include "jk_ajp13_worker.h"
+
+
+/* -------------------- Method -------------------- */
+static int JK_METHOD validate(jk_worker_t *pThis,
+                              jk_map_t *props,
+                              jk_worker_env_t *we, jk_logger_t *l)
+{
+    int rc;
+    JK_TRACE_ENTER(l);
+    rc = ajp_validate(pThis, props, we, l, AJP13_PROTO);
+    JK_TRACE_EXIT(l);
+    return rc;
+}
+
+
+static int JK_METHOD init(jk_worker_t *pThis,
+                          jk_map_t *props,
+                          jk_worker_env_t *we, jk_logger_t *l)
+{
+    int rc;
+    ajp_worker_t *aw = ( ajp_worker_t *)pThis->worker_private;
+    JK_TRACE_ENTER(l);
+
+    pThis->retries = jk_get_worker_retries(props, aw->name,
+                                           JK_RETRIES);
+
+    rc = ajp_init(pThis, props, we, l, AJP13_PROTO);
+    JK_TRACE_EXIT(l);
+    return rc;
+}
+
+
+static int JK_METHOD destroy(jk_worker_t **pThis, jk_logger_t *l)
+{
+    int rc;
+    JK_TRACE_ENTER(l);
+    rc = ajp_destroy(pThis, l, AJP13_PROTO);
+    JK_TRACE_EXIT(l);
+    return rc;
+}
+
+
+static int JK_METHOD get_endpoint(jk_worker_t *pThis,
+                                  jk_endpoint_t **pend, jk_logger_t *l)
+{
+    int rc;
+    JK_TRACE_ENTER(l);
+    rc = ajp_get_endpoint(pThis, pend, l, AJP13_PROTO);
+    JK_TRACE_EXIT(l);
+    return rc;
+}
+
+int JK_METHOD ajp13_worker_factory(jk_worker_t **w,
+                                   const char *name, jk_logger_t *l)
+{
+    ajp_worker_t *aw;
+
+    JK_TRACE_ENTER(l);
+    if (name == NULL || w == NULL) {
+        JK_LOG_NULL_PARAMS(l);
+        JK_TRACE_EXIT(l);
+        return 0;
+    }
+
+    aw = (ajp_worker_t *) calloc(1, sizeof(ajp_worker_t));
+    if (!aw) {
+        jk_log(l, JK_LOG_ERROR,
+               "malloc of private_data failed");
+        JK_TRACE_EXIT(l);
+        return 0;
+    }
+
+    aw->name = name;
+    aw->proto = AJP13_PROTO;
+    aw->login = NULL;
+
+    aw->ep_cache_sz = 0;
+    aw->ep_cache = NULL;
+    aw->connect_retry_attempts = AJP_DEF_RETRY_ATTEMPTS;
+    aw->worker.worker_private = aw;
+
+    aw->worker.validate = validate;
+    aw->worker.init = init;
+    aw->worker.get_endpoint = get_endpoint;
+    aw->worker.destroy = destroy;
+    aw->worker.maintain = ajp_maintain;
+    aw->worker.retries = JK_RETRIES;
+
+    aw->logon = NULL;           /* No Logon on AJP13 */
+
+    *w = &aw->worker;
+    JK_TRACE_EXIT(l);
+    return JK_AJP13_WORKER_TYPE;
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_ajp13_worker.h
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_ajp13_worker.h	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_ajp13_worker.h	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,49 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.
+ */
+
+/***************************************************************************
+ * Description: ajpv1.3 worker header file                                 *
+ * Author:      Gal Shachor <shachor at il.ibm.com>                           *
+ * Version:     $Revision: 300224 $                                           *
+ ***************************************************************************/
+
+#ifndef JK_AJP13_WORKER_H
+#define JK_AJP13_WORKER_H
+
+#include "jk_pool.h"
+#include "jk_connect.h"
+#include "jk_util.h"
+#include "jk_msg_buff.h"
+#include "jk_ajp_common.h"
+#include "jk_ajp13.h"
+#include "jk_logger.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif                          /* __cplusplus */
+
+#define JK_AJP13_WORKER_NAME ("ajp13")
+#define JK_AJP13_WORKER_TYPE (2)
+
+int JK_METHOD ajp13_worker_factory(jk_worker_t **w,
+                                   const char *name, jk_logger_t *l);
+
+#ifdef __cplusplus
+}
+#endif                          /* __cplusplus */
+
+#endif                          /* JK_AJP13_WORKER_H */

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_ajp14.c
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_ajp14.c	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_ajp14.c	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,694 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.
+ */
+
+/***************************************************************************
+ * Description: Next generation bi-directional protocol handler.           *
+ * Author:      Henri Gomez <hgomez at apache.org>                            *
+ * Version:     $Revision: 300507 $                                          *
+ ***************************************************************************/
+
+
+#include "jk_global.h"
+#include "jk_util.h"
+#include "jk_map.h"
+#include "jk_ajp_common.h"
+#include "jk_ajp14.h"
+#include "jk_md5.h"
+
+/*
+ * Compute the MD5 with ENTROPY / SECRET KEY
+ */
+
+void ajp14_compute_md5(jk_login_service_t *s, jk_logger_t *l)
+{
+    JK_TRACE_ENTER(l);
+    jk_md5((const unsigned char *)s->entropy,
+           (const unsigned char *)s->secret_key, s->computed_key);
+
+    if (JK_IS_DEBUG_LEVEL(l))
+        jk_log(l, JK_LOG_DEBUG, "(%s/%s) -> (%s)",
+               s->entropy, s->secret_key, s->computed_key);
+    JK_TRACE_EXIT(l);
+}
+
+
+/*
+ * Build the Login Init Command
+ *
+ * +-------------------------+---------------------------+---------------------------+
+ * | LOGIN INIT CMD (1 byte) | NEGOCIATION DATA (32bits) | WEB SERVER INFO (CString) |
+ * +-------------------------+---------------------------+---------------------------+
+ *
+ */
+
+int ajp14_marshal_login_init_into_msgb(jk_msg_buf_t *msg,
+                                       jk_login_service_t *s, jk_logger_t *l)
+{
+    JK_TRACE_ENTER(l);
+    /* To be on the safe side */
+    jk_b_reset(msg);
+
+    /*
+     * LOGIN
+     */
+    if (jk_b_append_byte(msg, AJP14_LOGINIT_CMD)) {
+        JK_TRACE_EXIT(l);
+        return JK_FALSE;
+    }
+    /*
+     * NEGOCIATION FLAGS
+     */
+    if (jk_b_append_long(msg, s->negociation)) {
+        JK_TRACE_EXIT(l);
+        return JK_FALSE;
+    }
+    /*
+     * WEB-SERVER NAME
+     */
+    if (jk_b_append_string(msg, s->web_server_name)) {
+        jk_log(l, JK_LOG_ERROR,
+               "failed appending the web_server_name string");
+        JK_TRACE_EXIT(l);
+        return JK_FALSE;
+    }
+
+    JK_TRACE_EXIT(l);
+    return JK_TRUE;
+}
+
+
+/*
+ * Decode the Login Seed Command
+ *
+ * +-------------------------+---------------------------+
+ * | LOGIN SEED CMD (1 byte) | MD5 of entropy (32 chars) |
+ * +-------------------------+---------------------------+
+ *
+ */
+
+int ajp14_unmarshal_login_seed(jk_msg_buf_t *msg,
+                               jk_login_service_t *s, jk_logger_t *l)
+{
+    JK_TRACE_ENTER(l);
+
+    if (jk_b_get_bytes
+        (msg, (unsigned char *)s->entropy, AJP14_ENTROPY_SEED_LEN) < 0) {
+        jk_log(l, JK_LOG_ERROR,
+               "can't get seed");
+        JK_TRACE_EXIT(l);
+        return JK_FALSE;
+    }
+
+    s->entropy[AJP14_ENTROPY_SEED_LEN] = 0;     /* Just to have a CString */
+    JK_TRACE_EXIT(l);
+    return JK_TRUE;
+}
+
+/*
+ * Build the Login Computed Command
+ *
+ * +-------------------------+---------------------------------------+
+ * | LOGIN COMP CMD (1 byte) | MD5 of RANDOM + SECRET KEY (32 chars) |
+ * +-------------------------+---------------------------------------+
+ *
+ */
+
+int ajp14_marshal_login_comp_into_msgb(jk_msg_buf_t *msg,
+                                       jk_login_service_t *s, jk_logger_t *l)
+{
+    JK_TRACE_ENTER(l);
+
+    /* To be on the safe side */
+    jk_b_reset(msg);
+
+    /*
+     * LOGIN
+     */
+    if (jk_b_append_byte(msg, AJP14_LOGCOMP_CMD)) {
+        JK_TRACE_EXIT(l);
+        return JK_FALSE;
+    }
+    /*
+     * COMPUTED-SEED
+     */
+    if (jk_b_append_bytes
+        (msg, (const unsigned char *)s->computed_key,
+         AJP14_COMPUTED_KEY_LEN)) {
+        jk_log(l, JK_LOG_ERROR,
+               "failed appending the COMPUTED MD5 bytes");
+        JK_TRACE_EXIT(l);
+        return JK_FALSE;
+    }
+
+    JK_TRACE_EXIT(l);
+    return JK_TRUE;
+}
+
+
+/*
+ * Decode the LogOk Command
+ *
+ * +--------------------+------------------------+-------------------------------+
+ * | LOGOK CMD (1 byte) | NEGOCIED DATA (32bits) | SERVLET ENGINE INFO (CString) |
+ * +--------------------+------------------------+-------------------------------+
+ *
+ */
+
+int ajp14_unmarshal_log_ok(jk_msg_buf_t *msg,
+                           jk_login_service_t *s, jk_logger_t *l)
+{
+    unsigned long nego;
+    char *sname;
+
+    JK_TRACE_ENTER(l);
+
+    nego = jk_b_get_long(msg);
+
+    if (nego == 0xFFFFFFFF) {
+        jk_log(l, JK_LOG_ERROR,
+               "can't get negociated data");
+        JK_TRACE_EXIT(l);
+        return JK_FALSE;
+    }
+
+    sname = (char *)jk_b_get_string(msg);
+
+    if (!sname) {
+        jk_log(l, JK_LOG_ERROR,
+               "can't get servlet engine name");
+        JK_TRACE_EXIT(l);
+        return JK_FALSE;
+    }
+
+    if (s->servlet_engine_name) /* take care of removing previously allocated data */
+        free(s->servlet_engine_name);
+
+    s->servlet_engine_name = strdup(sname);
+
+    if (!s->servlet_engine_name) {
+        jk_log(l, JK_LOG_ERROR,
+               "can't malloc servlet engine name");
+        JK_TRACE_EXIT(l);
+        return JK_FALSE;
+    }
+
+    JK_TRACE_EXIT(l);
+    return JK_TRUE;
+}
+
+
+/*
+ * Decode the Log Nok Command 
+ *
+ * +---------------------+-----------------------+
+ * | LOGNOK CMD (1 byte) | FAILURE CODE (32bits) |
+ * +---------------------+-----------------------+
+ *
+ */
+
+int ajp14_unmarshal_log_nok(jk_msg_buf_t *msg, jk_logger_t *l)
+{
+    unsigned long status;
+
+    JK_TRACE_ENTER(l);
+
+    status = jk_b_get_long(msg);
+
+    if (status == 0xFFFFFFFF) {
+        jk_log(l, JK_LOG_ERROR,
+               "can't get failure code");
+        JK_TRACE_EXIT(l);
+        return JK_FALSE;
+    }
+
+    jk_log(l, JK_LOG_INFO, "Can't Log with servlet engine - code %08lx",
+           status);
+    JK_TRACE_EXIT(l);
+    return JK_TRUE;
+}
+
+
+/* 
+ * Build the Shutdown Cmd
+ *
+ * +-----------------------+---------------------------------------+
+ * | SHUTDOWN CMD (1 byte) | MD5 of RANDOM + SECRET KEY (32 chars) |
+ * +-----------------------+---------------------------------------+
+ *
+ */
+
+int ajp14_marshal_shutdown_into_msgb(jk_msg_buf_t *msg,
+                                     jk_login_service_t *s, jk_logger_t *l)
+{
+
+    JK_TRACE_ENTER(l);
+
+    /* To be on the safe side */
+    jk_b_reset(msg);
+
+    /*
+     * SHUTDOWN CMD
+     */
+    if (jk_b_append_byte(msg, AJP14_SHUTDOWN_CMD)) {
+        JK_TRACE_EXIT(l);
+        return JK_FALSE;
+    }
+    /*
+     * COMPUTED-SEED
+     */
+    if (jk_b_append_bytes
+        (msg, (const unsigned char *)s->computed_key,
+         AJP14_COMPUTED_KEY_LEN)) {
+        jk_log(l, JK_LOG_ERROR,
+               "failed appending the COMPUTED MD5 bytes");
+        JK_TRACE_EXIT(l);
+        return JK_FALSE;
+    }
+
+    JK_TRACE_EXIT(l);
+    return JK_TRUE;
+}
+
+/*
+ * Decode the Shutdown Nok Command
+ *
+ * +----------------------+-----------------------+
+ * | SHUTNOK CMD (1 byte) | FAILURE CODE (32bits) |
+ * +----------------------+-----------------------+
+ *
+ */
+int ajp14_unmarshal_shutdown_nok(jk_msg_buf_t *msg, jk_logger_t *l)
+{
+    unsigned long status;
+
+    JK_TRACE_ENTER(l);
+    status = jk_b_get_long(msg);
+
+    if (status == 0xFFFFFFFF) {
+        jk_log(l, JK_LOG_ERROR,
+               "can't get failure code");
+        JK_TRACE_EXIT(l);
+        return JK_FALSE;
+    }
+
+    jk_log(l, JK_LOG_INFO, "Can't shutdown servlet engine - code %08lx",
+           status);
+    JK_TRACE_EXIT(l);
+    return JK_TRUE;
+}
+
+/*
+ * Build the Unknown Packet
+ *
+ * +-----------------------------+---------------------------------+------------------------------+
+ * | UNKNOWN PACKET CMD (1 byte) | UNHANDLED MESSAGE SIZE (16bits) | UNHANDLED MESSAGE (bytes...) |
+ * +-----------------------------+---------------------------------+------------------------------+
+ *
+ */
+
+int ajp14_marshal_unknown_packet_into_msgb(jk_msg_buf_t *msg,
+                                           jk_msg_buf_t *unk, jk_logger_t *l)
+{
+    JK_TRACE_ENTER(l);
+
+    /* To be on the safe side */
+    jk_b_reset(msg);
+
+    /*
+     * UNKNOWN PACKET CMD
+     */
+    if (jk_b_append_byte(msg, AJP14_UNKNOW_PACKET_CMD)) {
+        JK_TRACE_EXIT(l);
+        return JK_FALSE;
+    }
+    /*
+     * UNHANDLED MESSAGE SIZE
+     */
+    if (jk_b_append_int(msg, (unsigned short)unk->len)) {
+        JK_TRACE_EXIT(l);
+        return JK_FALSE;
+    }
+    /*
+     * UNHANDLED MESSAGE (Question : Did we have to send all the message or only part of)
+     *                                       (           ie: only 1k max                                                                )
+     */
+    if (jk_b_append_bytes(msg, unk->buf, unk->len)) {
+        jk_log(l, JK_LOG_ERROR,
+               "failed appending the UNHANDLED MESSAGE");
+        JK_TRACE_EXIT(l);
+        return JK_FALSE;
+    }
+
+    JK_TRACE_EXIT(l);
+    return JK_TRUE;
+}
+
+/*
+ * Build the Context Query Cmd (autoconf)
+ *
+ * +--------------------------+---------------------------------+
+ * | CONTEXT QRY CMD (1 byte) | VIRTUAL HOST NAME (CString (*)) |
+ * +--------------------------+---------------------------------+
+ *
+ */
+
+int ajp14_marshal_context_query_into_msgb(jk_msg_buf_t *msg,
+                                          char *virtual, jk_logger_t *l)
+{
+    JK_TRACE_ENTER(l);
+
+    /* To be on the safe side */
+    jk_b_reset(msg);
+
+    /*
+     * CONTEXT QUERY CMD
+     */
+    if (jk_b_append_byte(msg, AJP14_CONTEXT_QRY_CMD)) {
+        JK_TRACE_EXIT(l);
+        return JK_FALSE;
+    }
+    /*
+     * VIRTUAL HOST CSTRING
+     */
+    if (jk_b_append_string(msg, virtual)) {
+        jk_log(l, JK_LOG_ERROR,
+               "failed appending the virtual host string");
+        JK_TRACE_EXIT(l);
+        return JK_FALSE;
+    }
+
+    JK_TRACE_EXIT(l);
+    return JK_TRUE;
+}
+
+
+/*
+ * Decode the Context Info Cmd (Autoconf)
+ *
+ * The Autoconf feature of AJP14, let us know which URL/URI could
+ * be handled by the servlet-engine
+ *
+ * +---------------------------+---------------------------------+----------------------------+-------------------------------+-----------+
+ * | CONTEXT INFO CMD (1 byte) | VIRTUAL HOST NAME (CString (*)) | CONTEXT NAME (CString (*)) | URL1 [\n] URL2 [\n] URL3 [\n] | NEXT CTX. |
+ * +---------------------------+---------------------------------+----------------------------+-------------------------------+-----------+
+ */
+
+int ajp14_unmarshal_context_info(jk_msg_buf_t *msg,
+                                 jk_context_t *c, jk_logger_t *l)
+{
+    char *vname;
+    char *cname;
+    char *uri;
+
+    vname = (char *)jk_b_get_string(msg);
+
+    JK_TRACE_ENTER(l);
+    jk_log(l, JK_LOG_DEBUG,
+           "get virtual %s for virtual %s",
+           vname, c->virt);
+
+    if (!vname) {
+        jk_log(l, JK_LOG_ERROR,
+               "can't get virtual hostname");
+        JK_TRACE_EXIT(l);
+        return JK_FALSE;
+    }
+
+    /* Check if we get the correct virtual host */
+    if (c->virt != NULL && vname != NULL && strcmp(c->virt, vname)) {
+        /* set the virtual name, better to add to a virtual list ? */
+
+        if (context_set_virtual(c, vname) == JK_FALSE) {
+            jk_log(l, JK_LOG_ERROR,
+                   "can't malloc virtual hostname");
+            JK_TRACE_EXIT(l);
+            return JK_FALSE;
+        }
+    }
+
+    for (;;) {
+
+        cname = (char *)jk_b_get_string(msg);
+
+        if (!cname) {
+            jk_log(l, JK_LOG_ERROR,
+                   "can't get context");
+            JK_TRACE_EXIT(l);
+            return JK_FALSE;
+        }
+
+        jk_log(l, JK_LOG_DEBUG,
+               "get context %s for virtual %s",
+               cname, vname);
+
+        /* grab all contexts up to empty one which indicate end of contexts */
+        if (!strlen(cname))
+            break;
+
+        /* create new context base (if needed) */
+
+        if (context_add_base(c, cname) == JK_FALSE) {
+            jk_log(l, JK_LOG_ERROR,
+                   "can't add/set context %s",
+                   cname);
+            JK_TRACE_EXIT(l);
+            return JK_FALSE;
+        }
+
+        for (;;) {
+
+            uri = (char *)jk_b_get_string(msg);
+
+            if (!uri) {
+                jk_log(l, JK_LOG_ERROR,
+                       "can't get URI");
+                JK_TRACE_EXIT(l);
+                return JK_FALSE;
+            }
+
+            if (!strlen(uri)) {
+                jk_log(l, JK_LOG_DEBUG, "No more URI for context %s", cname);
+                break;
+            }
+
+            jk_log(l, JK_LOG_INFO,
+                   "Got URI (%s) for virtualhost %s and context %s", uri,
+                   vname, cname);
+
+            if (context_add_uri(c, cname, uri) == JK_FALSE) {
+                jk_log(l, JK_LOG_ERROR,
+                       "can't add/set uri (%s) for context %s",
+                       uri, cname);
+                JK_TRACE_EXIT(l);
+                return JK_FALSE;
+            }
+        }
+    }
+
+    JK_TRACE_EXIT(l);
+    return JK_TRUE;
+}
+
+
+/*
+ * Build the Context State Query Cmd
+ *
+ * We send the list of contexts where we want to know state, empty string end context list*
+ * If cname is set, only ask about THIS context
+ *
+ * +----------------------------+----------------------------------+----------------------------+----+
+ * | CONTEXT STATE CMD (1 byte) |  VIRTUAL HOST NAME (CString (*)) | CONTEXT NAME (CString (*)) | .. |
+ * +----------------------------+----------------------------------+----------------------------+----+
+ *
+ */
+
+int ajp14_marshal_context_state_into_msgb(jk_msg_buf_t *msg,
+                                          jk_context_t *c,
+                                          char *cname, jk_logger_t *l)
+{
+    jk_context_item_t *ci;
+    int i;
+
+    JK_TRACE_ENTER(l);
+
+    /* To be on the safe side */
+    jk_b_reset(msg);
+
+    /*
+     * CONTEXT STATE CMD
+     */
+    if (jk_b_append_byte(msg, AJP14_CONTEXT_STATE_CMD)) {
+        JK_TRACE_EXIT(l);
+        return JK_FALSE;
+    }
+    /*
+     * VIRTUAL HOST CSTRING
+     */
+    if (jk_b_append_string(msg, c->virt)) {
+        jk_log(l, JK_LOG_ERROR,
+               "failed appending the virtual host string");
+        JK_TRACE_EXIT(l);
+        return JK_FALSE;
+    }
+
+    if (cname) {
+
+        ci = context_find_base(c, cname);
+
+        if (!ci) {
+            jk_log(l, JK_LOG_ERROR,
+                   "unknown context %s",
+                   cname);
+            JK_TRACE_EXIT(l);
+            return JK_FALSE;
+        }
+
+        /*
+         * CONTEXT CSTRING
+         */
+
+        if (jk_b_append_string(msg, cname)) {
+            jk_log(l, JK_LOG_ERROR,
+                   "failed appending the context string %s",
+                   cname);
+            JK_TRACE_EXIT(l);
+            return JK_FALSE;
+        }
+    }
+    else {                      /* Grab all contexts name */
+
+        for (i = 0; i < c->size; i++) {
+
+            /*
+             * CONTEXT CSTRING
+             */
+            if (jk_b_append_string(msg, c->contexts[i]->cbase)) {
+                jk_log(l, JK_LOG_ERROR,
+                       "failed appending the context string %s",
+                       c->contexts[i]->cbase);
+                JK_TRACE_EXIT(l);
+                return JK_FALSE;
+            }
+        }
+    }
+
+    /* End of context list, an empty string */
+
+    if (jk_b_append_string(msg, "")) {
+        jk_log(l, JK_LOG_ERROR,
+               "failed appending end of contexts");
+        JK_TRACE_EXIT(l);
+        return JK_FALSE;
+    }
+
+    JK_TRACE_EXIT(l);
+    return JK_TRUE;
+}
+
+
+/*
+ * Decode the Context State Reply Cmd
+ *
+ * We get update of contexts list, empty string end context list*
+ *
+ * +----------------------------------+---------------------------------+----------------------------+------------------+----+
+ * | CONTEXT STATE REPLY CMD (1 byte) | VIRTUAL HOST NAME (CString (*)) | CONTEXT NAME (CString (*)) | UP/DOWN (1 byte) | .. |
+ * +----------------------------------+---------------------------------+----------------------------+------------------+----+
+ *
+ */
+
+int ajp14_unmarshal_context_state_reply(jk_msg_buf_t *msg,
+                                        jk_context_t *c, jk_logger_t *l)
+{
+    char *vname;
+    char *cname;
+    jk_context_item_t *ci;
+
+    JK_TRACE_ENTER(l);
+    /* get virtual name */
+    vname = (char *)jk_b_get_string(msg);
+
+    if (!vname) {
+        jk_log(l, JK_LOG_ERROR,
+               "can't get virtual hostname");
+        JK_TRACE_EXIT(l);
+        return JK_FALSE;
+    }
+
+    /* Check if we speak about the correct virtual */
+    if (strcmp(c->virt, vname)) {
+        jk_log(l, JK_LOG_ERROR,
+               "incorrect virtual %s instead of %s",
+               vname, c->virt);
+        JK_TRACE_EXIT(l);
+        return JK_FALSE;
+    }
+
+    for (;;) {
+
+        /* get context name */
+        cname = (char *)jk_b_get_string(msg);
+
+        if (!cname) {
+            jk_log(l, JK_LOG_ERROR,
+                   "can't get context");
+            JK_TRACE_EXIT(l);
+            return JK_FALSE;
+        }
+
+        if (!strlen(cname))
+            break;
+
+        ci = context_find_base(c, cname);
+
+        if (!ci) {
+            jk_log(l, JK_LOG_ERROR,
+                   "unknow context %s for virtual %s",
+                   cname, vname);
+            JK_TRACE_EXIT(l);
+            return JK_FALSE;
+        }
+
+        ci->status = jk_b_get_int(msg);
+
+        if (JK_IS_DEBUG_LEVEL(l))
+            jk_log(l, JK_LOG_DEBUG,
+                   "updated context %s to state %d",
+                   cname, ci->status);
+    }
+
+    JK_TRACE_EXIT(l);
+    return JK_TRUE;
+}
+
+/*
+ * Decode the Context Update Cmd
+ * 
+ * +-----------------------------+---------------------------------+----------------------------+------------------+
+ * | CONTEXT UPDATE CMD (1 byte) | VIRTUAL HOST NAME (CString (*)) | CONTEXT NAME (CString (*)) | UP/DOWN (1 byte) |
+ * +-----------------------------+---------------------------------+----------------------------+------------------+
+ * 
+ */
+
+int ajp14_unmarshal_context_update_cmd(jk_msg_buf_t *msg,
+                                       jk_context_t *c, jk_logger_t *l)
+{
+    int rc;
+    JK_TRACE_ENTER(l);
+    rc = ajp14_unmarshal_context_state_reply(msg, c, l);
+    JK_TRACE_EXIT(l);
+    return rc;
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_ajp14.h
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_ajp14.h	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_ajp14.h	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,306 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.
+ */
+
+/***************************************************************************
+ * Description: Next generation bi-directional protocol handler.           *
+ * Author:      Henri Gomez <hgomez at apache.org>                            *
+ * Version:     $Revision: 300154 $                                           *
+ ***************************************************************************/
+#ifndef JK_AJP14_H
+#define JK_AJP14_H
+
+#include "jk_ajp_common.h"
+#include "jk_context.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif                          /* __cplusplus */
+
+#define AJP14_PROTO                 14
+
+#define AJP14_WS_HEADER             0x1235
+#define AJP14_SW_HEADER             0x1235      /* AJP14 use now the same header in both directions */
+
+#define AJP14_DEF_HOST              ("localhost")
+#define AJP14_DEF_PORT              (8011)
+#define AJP14_READ_BUF_SIZE         (8*1024)
+#define AJP14_DEF_RETRY_ATTEMPTS    (1)
+#define AJP14_DEF_CACHE_SZ          (1)
+#define AJP14_MAX_SEND_BODY_SZ      (DEF_BUFFER_SZ - 6)
+#define AJP14_HEADER_LEN            (4)
+#define AJP14_HEADER_SZ_LEN         (2)
+
+/*
+ * Initial Login Phase (web server -> servlet engine)
+ */
+#define AJP14_LOGINIT_CMD           (unsigned char)0x10
+
+/*
+ * Second Login Phase (servlet engine -> web server), md5 seed is received
+ */
+#define AJP14_LOGSEED_CMD           (unsigned char)0x11
+
+/*
+ * Third Login Phase (web server -> servlet engine), md5 of seed + secret is sent
+ */
+#define AJP14_LOGCOMP_CMD           (unsigned char)0x12
+
+/*
+ * Login Accepted (servlet engine -> web server)
+ */
+#define AJP14_LOGOK_CMD             (unsigned char)0x13
+
+/*
+ * Login Rejected (servlet engine -> web server), will be logged
+ */
+#define AJP14_LOGNOK_CMD            (unsigned char)0x14
+
+/*
+ * Context Query (web server -> servlet engine), which URI are handled by servlet engine ?
+ */
+#define AJP14_CONTEXT_QRY_CMD       (unsigned char)0x15
+
+/*
+ * Context Info (servlet engine -> web server), URI handled response
+ */
+#define AJP14_CONTEXT_INFO_CMD      (unsigned char)0x16
+
+/* 
+ * Context Update (servlet engine -> web server), status of context changed
+ */
+#define AJP14_CONTEXT_UPDATE_CMD    (unsigned char)0x17
+
+/*
+ * Servlet Engine Status (web server -> servlet engine), what's the status of the servlet engine ?
+ */
+#define AJP14_STATUS_CMD            (unsigned char)0x18
+
+/*
+ * Secure Shutdown command (web server -> servlet engine), please servlet stop yourself.
+ */
+#define AJP14_SHUTDOWN_CMD          (unsigned char)0x19
+
+/*
+ * Secure Shutdown command Accepted (servlet engine -> web server)
+ */
+#define AJP14_SHUTOK_CMD            (unsigned char)0x1A
+
+/*
+ * Secure Shutdown Rejected (servlet engine -> web server)
+ */
+#define AJP14_SHUTNOK_CMD           (unsigned char)0x1B
+
+/*
+ * Context Status (web server -> servlet engine), what's the status of the context ?
+ */
+#define AJP14_CONTEXT_STATE_CMD     (unsigned char)0x1C
+
+/*
+ * Context Status Reply (servlet engine -> web server), status of context
+ */
+#define AJP14_CONTEXT_STATE_REP_CMD (unsigned char)0x1D
+
+/*
+ * Unknown Packet Reply (web server <-> servlet engine), when a packet couldn't be decoded
+ */
+#define AJP14_UNKNOW_PACKET_CMD     (unsigned char)0x1E
+
+
+/*
+ * Negociation flags 
+ */
+
+/*
+ * web-server want context info after login
+ */
+#define AJP14_CONTEXT_INFO_NEG      0x80000000
+
+/*
+ * web-server want context updates
+ */
+#define AJP14_CONTEXT_UPDATE_NEG    0x40000000
+
+/*
+ * web-server want compressed stream 
+ */
+#define AJP14_GZIP_STREAM_NEG       0x20000000
+
+/*
+ * web-server want crypted DES56 stream with secret key
+ */
+#define AJP14_DES56_STREAM_NEG      0x10000000
+
+/*
+ * Extended info on server SSL vars
+ */
+#define AJP14_SSL_VSERVER_NEG       0x08000000
+
+/*
+ *Extended info on client SSL vars
+ */
+#define AJP14_SSL_VCLIENT_NEG       0x04000000
+
+/*
+ * Extended info on crypto SSL vars
+ */
+#define AJP14_SSL_VCRYPTO_NEG       0x02000000
+
+/*
+ * Extended info on misc SSL vars
+ */
+#define AJP14_SSL_VMISC_NEG         0x01000000
+
+/*
+ * mask of protocol supported 
+ */
+#define AJP14_PROTO_SUPPORT_AJPXX_NEG   0x00FF0000
+
+/* 
+ * communication could use AJP14 
+ */
+#define AJP14_PROTO_SUPPORT_AJP14_NEG   0x00010000
+
+/*
+ * communication could use AJP15 
+ */
+#define AJP14_PROTO_SUPPORT_AJP15_NEG   0x00020000
+
+/*
+ * communication could use AJP16
+ */
+#define AJP14_PROTO_SUPPORT_AJP16_NEG   0x00040000
+
+/*
+ * Some failure codes
+ */
+#define AJP14_BAD_KEY_ERR               0xFFFFFFFF
+#define AJP14_ENGINE_DOWN_ERR           0xFFFFFFFE
+#define AJP14_RETRY_LATER_ERR           0xFFFFFFFD
+#define AJP14_SHUT_AUTHOR_FAILED_ERR    0xFFFFFFFC
+
+/*
+ * Some status codes
+ */
+#define AJP14_CONTEXT_DOWN       0x01
+#define AJP14_CONTEXT_UP         0x02
+#define AJP14_CONTEXT_OK         0x03
+
+/* 
+ * Misc defines
+ */
+#define AJP14_ENTROPY_SEED_LEN      32      /* we're using MD5 => 32 chars */
+#define AJP14_COMPUTED_KEY_LEN      32      /* we're using MD5 also */
+
+/*
+ * The login structure
+ */
+typedef struct jk_login_service jk_login_service_t;
+
+struct jk_login_service
+{
+
+    /*
+     *  Pointer to web-server name
+     */
+    const char *web_server_name;
+
+    /*
+     * Pointer to servlet-engine name
+     */
+    char *servlet_engine_name;
+
+    /*
+     * Pointer to secret key
+     */
+    const char *secret_key;
+
+    /*
+     * Received entropy seed
+     */
+    char entropy[AJP14_ENTROPY_SEED_LEN + 1];
+
+    /*
+     * Computed key
+     */
+    char computed_key[AJP14_COMPUTED_KEY_LEN + 1];
+
+    /*
+     *  What we want to negociate
+     */
+    unsigned long negociation;
+
+    /*
+     * What we received from servlet engine 
+     */
+    unsigned long negociated;
+};
+
+/*
+ * functions defined here 
+ */
+
+void ajp14_compute_md5(jk_login_service_t *s, jk_logger_t *l);
+
+int ajp14_marshal_login_init_into_msgb(jk_msg_buf_t *msg,
+                                       jk_login_service_t *s,
+                                       jk_logger_t *l);
+
+int ajp14_unmarshal_login_seed(jk_msg_buf_t *msg,
+                               jk_login_service_t *s, jk_logger_t *l);
+
+int ajp14_marshal_login_comp_into_msgb(jk_msg_buf_t *msg,
+                                       jk_login_service_t *s,
+                                       jk_logger_t *l);
+
+int ajp14_unmarshal_log_ok(jk_msg_buf_t *msg,
+                           jk_login_service_t *s, jk_logger_t *l);
+
+int ajp14_unmarshal_log_nok(jk_msg_buf_t *msg, jk_logger_t *l);
+
+int ajp14_marshal_shutdown_into_msgb(jk_msg_buf_t *msg,
+                                     jk_login_service_t *s,
+                                     jk_logger_t *l);
+
+int ajp14_unmarshal_shutdown_nok(jk_msg_buf_t *msg, jk_logger_t *l);
+
+int ajp14_marshal_unknown_packet_into_msgb(jk_msg_buf_t *msg,
+                                           jk_msg_buf_t *unk,
+                                           jk_logger_t *l);
+
+int ajp14_marshal_context_query_into_msgb(jk_msg_buf_t *msg,
+                                          char *virtual, jk_logger_t *l);
+
+int ajp14_unmarshal_context_info(jk_msg_buf_t *msg,
+                                 jk_context_t *context, jk_logger_t *l);
+
+int ajp14_marshal_context_state_into_msgb(jk_msg_buf_t *msg,
+                                          jk_context_t *context,
+                                          char *cname, jk_logger_t *l);
+
+int ajp14_unmarshal_context_state_reply(jk_msg_buf_t *msg,
+                                        jk_context_t *context,
+                                        jk_logger_t *l);
+
+int ajp14_unmarshal_context_update_cmd(jk_msg_buf_t *msg,
+                                       jk_context_t *context,
+                                       jk_logger_t *l);
+
+#ifdef __cplusplus
+}
+#endif                          /* __cplusplus */
+
+#endif                          /* JK_AJP14_H */

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_ajp14_worker.c
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_ajp14_worker.c	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_ajp14_worker.c	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,434 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.
+ */
+
+/***************************************************************************
+ * Description: AJP14 next generation Bi-directional protocol.             *
+ * Author:      Henri Gomez <hgomez at apache.org>                            *
+ * Version:     $Revision: 300520 $                                          *
+ ***************************************************************************/
+
+#include "jk_context.h"
+#include "jk_ajp14_worker.h"
+
+
+/*
+ * AJP14 Autoconf Phase
+ *
+ * CONTEXT QUERY / REPLY
+ */
+
+#define MAX_URI_SIZE    512
+
+static int handle_discovery(ajp_endpoint_t * ae,
+                            jk_worker_env_t *we,
+                            jk_msg_buf_t *msg, jk_logger_t *l)
+{
+    int cmd;
+    int i, j;
+#if 0
+    /* Not used for now */
+    jk_login_service_t *jl = ae->worker->login;
+#endif
+    jk_context_item_t *ci;
+    jk_context_t *c;
+    char *buf;
+
+#ifndef TESTME
+    JK_TRACE_ENTER(l);
+
+    ajp14_marshal_context_query_into_msgb(msg, we->virtual, l);
+
+    jk_log(l, JK_LOG_DEBUG, "send query");
+
+    if (ajp_connection_tcp_send_message(ae, msg, l) != JK_TRUE) {
+        JK_TRACE_EXIT(l);
+        return JK_FALSE;
+    }
+    jk_log(l, JK_LOG_DEBUG, "wait context reply");
+
+    jk_b_reset(msg);
+
+    if (ajp_connection_tcp_get_message(ae, msg, l) != JK_TRUE) {
+        JK_TRACE_EXIT(l);
+        return JK_FALSE;
+    }
+    if ((cmd = jk_b_get_byte(msg)) != AJP14_CONTEXT_INFO_CMD) {
+        jk_log(l, JK_LOG_ERROR,
+               "awaited command %d, received %d",
+               AJP14_CONTEXT_INFO_CMD, cmd);
+        JK_TRACE_EXIT(l);
+        return JK_FALSE;
+    }
+
+    if (context_alloc(&c, we->virtual) != JK_TRUE) {
+        jk_log(l, JK_LOG_ERROR,
+               "can't allocate context room");
+        JK_TRACE_EXIT(l);
+        return JK_FALSE;
+    }
+
+    if (ajp14_unmarshal_context_info(msg, c, l) != JK_TRUE) {
+        jk_log(l, JK_LOG_ERROR,
+               "can't get context reply");
+        JK_TRACE_EXIT(l);
+        return JK_FALSE;
+    }
+
+    jk_log(l, JK_LOG_DEBUG, "received context");
+
+    buf = malloc(MAX_URI_SIZE); /* Really a very long URI */
+
+    if (!buf) {
+        jk_log(l, JK_LOG_ERROR, "can't malloc buf");
+        JK_TRACE_EXIT(l);
+        return JK_FALSE;
+    }
+
+    for (i = 0; i < c->size; i++) {
+        ci = c->contexts[i];
+        for (j = 0; j < ci->size; j++) {
+
+#ifndef USE_SPRINTF
+            snprintf(buf, MAX_URI_SIZE - 1, "/%s/%s", ci->cbase, ci->uris[j]);
+#else
+            sprintf(buf, "/%s/%s", ci->cbase, ci->uris[j]);
+#endif
+
+            jk_log(l, JK_LOG_INFO,
+                   "worker %s will handle uri %s in context %s [%s]",
+                   ae->worker->name, ci->uris[j], ci->cbase, buf);
+
+            uri_worker_map_add(we->uri_to_worker, buf, ae->worker->name, l);
+        }
+    }
+
+    free(buf);
+    context_free(&c);
+
+#else
+
+    uri_worker_map_add(we->uri_to_worker, "/examples/servlet/*",
+                       ae->worker->name, l);
+    uri_worker_map_add(we->uri_to_worker, "/examples/*.jsp", ae->worker->name,
+                       l);
+    uri_worker_map_add(we->uri_to_worker, "/examples/*.gif", ae->worker->name,
+                       l);
+
+#endif
+
+    JK_TRACE_EXIT(l);
+    return JK_TRUE;
+}
+
+/*
+ * AJP14 Logon Phase
+ *
+ * INIT + REPLY / NEGO + REPLY
+ */
+
+static int handle_logon(ajp_endpoint_t * ae,
+                        jk_msg_buf_t *msg, jk_logger_t *l)
+{
+    int cmd;
+
+    jk_login_service_t *jl = ae->worker->login;
+    JK_TRACE_ENTER(l);
+
+    ajp14_marshal_login_init_into_msgb(msg, jl, l);
+
+    jk_log(l, JK_LOG_DEBUG, "send init");
+
+    if (ajp_connection_tcp_send_message(ae, msg, l) != JK_TRUE) {
+        JK_TRACE_EXIT(l);
+        return JK_FALSE;
+    }
+    jk_log(l, JK_LOG_DEBUG, "wait init reply");
+
+    jk_b_reset(msg);
+
+    if (ajp_connection_tcp_get_message(ae, msg, l) != JK_TRUE) {
+        JK_TRACE_EXIT(l);
+        return JK_FALSE;
+    }
+    if ((cmd = jk_b_get_byte(msg)) != AJP14_LOGSEED_CMD) {
+        jk_log(l, JK_LOG_ERROR,
+               "awaited command %d, received %d",
+               AJP14_LOGSEED_CMD, cmd);
+        JK_TRACE_EXIT(l);
+        return JK_FALSE;
+    }
+
+    if (ajp14_unmarshal_login_seed(msg, jl, l) != JK_TRUE) {
+        JK_TRACE_EXIT(l);
+        return JK_FALSE;
+    }
+    jk_log(l, JK_LOG_DEBUG, "received entropy %s",
+           jl->entropy);
+
+    ajp14_compute_md5(jl, l);
+
+    if (ajp14_marshal_login_comp_into_msgb(msg, jl, l) != JK_TRUE) {
+        JK_TRACE_EXIT(l);
+        return JK_FALSE;
+    }
+    if (ajp_connection_tcp_send_message(ae, msg, l) != JK_TRUE) {
+        JK_TRACE_EXIT(l);
+        return JK_FALSE;
+    }
+    jk_b_reset(msg);
+
+    if (ajp_connection_tcp_get_message(ae, msg, l) != JK_TRUE) {
+        JK_TRACE_EXIT(l);
+        return JK_FALSE;
+    }
+    switch (jk_b_get_byte(msg)) {
+
+    case AJP14_LOGOK_CMD:
+        if (ajp14_unmarshal_log_ok(msg, jl, l) == JK_TRUE) {
+            jk_log(l, JK_LOG_DEBUG,
+                   "Successfully connected to servlet-engine %s",
+                   jl->servlet_engine_name);
+            JK_TRACE_EXIT(l);
+            return JK_TRUE;
+        }
+        break;
+
+    case AJP14_LOGNOK_CMD:
+        ajp14_unmarshal_log_nok(msg, l);
+        break;
+    }
+
+    JK_TRACE_EXIT(l);
+    return JK_FALSE;
+}
+
+static int logon(ajp_endpoint_t * ae, jk_logger_t *l)
+{
+    jk_pool_t *p = &ae->pool;
+    jk_msg_buf_t *msg;
+    int rc;
+
+    JK_TRACE_ENTER(l);
+
+    msg = jk_b_new(p);
+    jk_b_set_buffer_size(msg, DEF_BUFFER_SZ);
+
+    if ((rc = handle_logon(ae, msg, l)) == JK_FALSE)
+        ajp_close_endpoint(ae, l);
+
+    JK_TRACE_EXIT(l);
+    return rc;
+}
+
+static int discovery(ajp_endpoint_t * ae, jk_worker_env_t *we, jk_logger_t *l)
+{
+    jk_pool_t *p = &ae->pool;
+    jk_msg_buf_t *msg;
+    int rc;
+
+    JK_TRACE_ENTER(l);
+
+    msg = jk_b_new(p);
+    jk_b_set_buffer_size(msg, DEF_BUFFER_SZ);
+
+    if ((rc = handle_discovery(ae, we, msg, l)) == JK_FALSE)
+        ajp_close_endpoint(ae, l);
+
+    JK_TRACE_EXIT(l);
+    return rc;
+}
+
+/* -------------------- Method -------------------- */
+static int JK_METHOD validate(jk_worker_t *pThis,
+                              jk_map_t *props,
+                              jk_worker_env_t *we, jk_logger_t *l)
+{
+    ajp_worker_t *aw;
+    const char *secret_key;
+
+    JK_TRACE_ENTER(l);
+    if (ajp_validate(pThis, props, we, l, AJP14_PROTO) == JK_FALSE) {
+        JK_TRACE_EXIT(l);
+        return JK_FALSE;
+    }
+    aw = pThis->worker_private;
+
+    secret_key = jk_get_worker_secret_key(props, aw->name);
+
+    if ((!secret_key) || (!strlen(secret_key))) {
+        jk_log(l, JK_LOG_ERROR,
+               "validate error, empty or missing secretkey");
+        JK_TRACE_EXIT(l);
+        return JK_FALSE;
+    }
+
+    /* jk_log(l, JK_LOG_DEBUG, "Into ajp14:validate - secret_key=%s", secret_key); */
+    JK_TRACE_EXIT(l);
+    return JK_TRUE;
+}
+
+static int JK_METHOD get_endpoint(jk_worker_t *pThis,
+                                  jk_endpoint_t **pend, jk_logger_t *l)
+{
+    int rc;
+    JK_TRACE_ENTER(l);
+    rc = ajp_get_endpoint(pThis, pend, l, AJP14_PROTO);
+    JK_TRACE_EXIT(l);
+    return rc;
+}
+
+static int JK_METHOD init(jk_worker_t *pThis,
+                          jk_map_t *props,
+                          jk_worker_env_t *we, jk_logger_t *l)
+{
+    ajp_worker_t *aw;
+    ajp_endpoint_t *ae;
+    jk_endpoint_t *je;
+    int rc;
+
+    JK_TRACE_EXIT(l);
+
+    if (ajp_init(pThis, props, we, l, AJP14_PROTO) == JK_FALSE) {
+        JK_TRACE_EXIT(l);
+        return JK_FALSE;
+    }
+    aw = pThis->worker_private;
+    pThis->retries = jk_get_worker_retries(props, aw->name,
+                                           JK_RETRIES);
+
+    /* Set Secret Key (used at logon time) */
+    aw->login->secret_key = jk_get_worker_secret_key(props, aw->name);
+
+    if (aw->login->secret_key == NULL) {
+        jk_log(l, JK_LOG_ERROR, "can't malloc secret_key");
+        JK_TRACE_EXIT(l);
+        return JK_FALSE;
+    }
+
+    /* Set WebServerName (used at logon time) */
+    aw->login->web_server_name = strdup(we->server_name);
+
+    if (aw->login->web_server_name == NULL) {
+        jk_log(l, JK_LOG_ERROR, "can't malloc web_server_name");
+        JK_TRACE_EXIT(l);
+        return JK_FALSE;
+    }
+
+    if (get_endpoint(pThis, &je, l) == JK_FALSE) {
+        JK_TRACE_EXIT(l);
+        return JK_FALSE;
+    }
+    ae = je->endpoint_private;
+
+    if (ajp_connect_to_endpoint(ae, l) == JK_TRUE) {
+
+        /* connection stage passed - try to get context info
+         * this is the long awaited autoconf feature :)
+         */
+        rc = discovery(ae, we, l);
+        ajp_close_endpoint(ae, l);
+        JK_TRACE_EXIT(l);
+        return rc;
+    }
+
+    JK_TRACE_EXIT(l);
+    return JK_TRUE;
+}
+
+
+static int JK_METHOD destroy(jk_worker_t **pThis, jk_logger_t *l)
+{
+    int rc;
+    ajp_worker_t *aw = (*pThis)->worker_private;
+
+    JK_TRACE_ENTER(l);
+
+    if (aw->login) {
+        free(aw->login);
+        aw->login = NULL;
+    }
+
+    rc = ajp_destroy(pThis, l, AJP14_PROTO);
+    JK_TRACE_EXIT(l);
+    return rc;
+}
+
+int JK_METHOD ajp14_worker_factory(jk_worker_t **w,
+                                   const char *name, jk_logger_t *l)
+{
+    ajp_worker_t *aw;
+
+    JK_TRACE_ENTER(l);
+
+    if (name == NULL || w == NULL) {
+        JK_LOG_NULL_PARAMS(l);
+        JK_TRACE_EXIT(l);
+        return 0;
+    }
+
+    aw = (ajp_worker_t *) calloc(1, sizeof(ajp_worker_t));
+    if (!aw) {
+        jk_log(l, JK_LOG_ERROR,
+               "malloc of private data failed");
+       JK_TRACE_EXIT(l);
+       return 0;
+    }
+
+    aw->name = strdup(name);
+
+    if (!aw->name) {
+        free(aw);
+        jk_log(l, JK_LOG_ERROR,
+               "malloc failed for name");
+        JK_TRACE_EXIT(l);
+        return 0;
+    }
+
+    aw->proto = AJP14_PROTO;
+
+    aw->login = (jk_login_service_t *)malloc(sizeof(jk_login_service_t));
+
+    if (aw->login == NULL) {
+        jk_log(l, JK_LOG_ERROR,
+               "malloc failed for login area");
+        JK_TRACE_EXIT(l);
+        return 0;
+    }
+
+    memset(aw->login, 0, sizeof(jk_login_service_t));
+
+    aw->login->negociation =
+        (AJP14_CONTEXT_INFO_NEG | AJP14_PROTO_SUPPORT_AJP14_NEG);
+    aw->login->web_server_name = NULL;  /* must be set in init */
+
+    aw->ep_cache_sz = 0;
+    aw->ep_cache = NULL;
+    aw->connect_retry_attempts = AJP_DEF_RETRY_ATTEMPTS;
+    aw->worker.worker_private = aw;
+
+    aw->worker.validate = validate;
+    aw->worker.init = init;
+    aw->worker.get_endpoint = get_endpoint;
+    aw->worker.destroy = destroy;
+    aw->worker.maintain = ajp_maintain;
+    aw->worker.retries = JK_RETRIES;
+
+    aw->logon = logon;          /* LogOn Handler for AJP14 */
+    *w = &aw->worker;
+
+    JK_TRACE_EXIT(l);
+    return JK_AJP14_WORKER_TYPE;
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_ajp14_worker.h
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_ajp14_worker.h	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_ajp14_worker.h	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,51 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.
+ */
+
+/***************************************************************************
+ * Description: ajpv14 worker header file                                  *
+ * Author:      Henri Gomez <hgomez at apache.org>                            *
+ * Version:     $Revision: 300224 $                                           *
+ ***************************************************************************/
+
+#ifndef JK_AJP14_WORKER_H
+#define JK_AJP14_WORKER_H
+
+#include "jk_pool.h"
+#include "jk_connect.h"
+#include "jk_util.h"
+#include "jk_msg_buff.h"
+#include "jk_ajp13.h"
+#include "jk_ajp14.h"
+#include "jk_logger.h"
+#include "jk_service.h"
+#include "jk_ajp13_worker.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif                          /* __cplusplus */
+
+#define JK_AJP14_WORKER_NAME ("ajp14")
+#define JK_AJP14_WORKER_TYPE (3)
+
+int JK_METHOD ajp14_worker_factory(jk_worker_t **w,
+                                   const char *name, jk_logger_t *l);
+
+#ifdef __cplusplus
+}
+#endif                          /* __cplusplus */
+
+#endif                          /* JK_AJP14_WORKER_H */

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_ajp_common.c
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_ajp_common.c	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_ajp_common.c	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,2355 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.
+ */
+
+/***************************************************************************
+ * Description: common stuff for bi-directional protocols ajp13/ajp14.     *
+ * Author:      Gal Shachor <shachor at il.ibm.com>                           *
+ * Author:      Henri Gomez <hgomez at apache.org>                            *
+ * Version:     $Revision: 440790 $                                          *
+ ***************************************************************************/
+
+
+#include "jk_global.h"
+#include "jk_util.h"
+#include "jk_ajp13.h"
+#include "jk_ajp14.h"
+#include "jk_ajp_common.h"
+#include "jk_connect.h"
+#ifdef AS400
+#include "util_ebcdic.h"
+#endif
+#if defined(NETWARE) && defined(__NOVELL_LIBC__)
+#include "novsock2.h"
+#endif
+
+const char *response_trans_headers[] = {
+    "Content-Type",
+    "Content-Language",
+    "Content-Length",
+    "Date",
+    "Last-Modified",
+    "Location",
+    "Set-Cookie",
+    "Set-Cookie2",
+    "Servlet-Engine",
+    "Status",
+    "WWW-Authenticate"
+};
+
+static const char *long_res_header_for_sc(int sc)
+{
+    const char *rc = NULL;
+    sc = sc & 0X00FF;
+    if (sc <= SC_RES_HEADERS_NUM && sc > 0) {
+        rc = response_trans_headers[sc - 1];
+    }
+
+    return rc;
+}
+
+#define UNKNOWN_METHOD (-1)
+
+static int sc_for_req_method(const char *method, size_t len)
+{
+    /* Note: the following code was generated by the "shilka" tool from
+       the "cocom" parsing/compilation toolkit. It is an optimized lookup
+       based on analysis of the input keywords. Postprocessing was done
+       on the shilka output, but the basic structure and analysis is
+       from there. Should new HTTP methods be added, then manual insertion
+       into this code is fine, or simply re-running the shilka tool on
+       the appropriate input. */
+
+    /* Note: it is also quite reasonable to just use our method_registry,
+       but I'm assuming (probably incorrectly) we want more speed here
+       (based on the optimizations the previous code was doing). */
+
+    switch (len)
+    {
+    case 3:
+        switch (method[0])
+        {
+        case 'A':
+            return (method[1] == 'C'
+                    && method[2] == 'L'
+                    ? SC_M_ACL : UNKNOWN_METHOD);
+        case 'P':
+            return (method[1] == 'U'
+                    && method[2] == 'T'
+                    ? SC_M_PUT : UNKNOWN_METHOD);
+        case 'G':
+            return (method[1] == 'E'
+                    && method[2] == 'T'
+                    ? SC_M_GET : UNKNOWN_METHOD);
+        default:
+            return UNKNOWN_METHOD;
+        }
+
+    case 4:
+        switch (method[0])
+        {
+        case 'H':
+            return (method[1] == 'E'
+                    && method[2] == 'A'
+                    && method[3] == 'D'
+                    ? SC_M_HEAD : UNKNOWN_METHOD);
+        case 'P':
+            return (method[1] == 'O'
+                    && method[2] == 'S'
+                    && method[3] == 'T'
+                    ? SC_M_POST : UNKNOWN_METHOD);
+        case 'M':
+            return (method[1] == 'O'
+                    && method[2] == 'V'
+                    && method[3] == 'E'
+                    ? SC_M_MOVE : UNKNOWN_METHOD);
+        case 'L':
+            return (method[1] == 'O'
+                    && method[2] == 'C'
+                    && method[3] == 'K'
+                    ? SC_M_LOCK : UNKNOWN_METHOD);
+        case 'C':
+            return (method[1] == 'O'
+                    && method[2] == 'P'
+                    && method[3] == 'Y'
+                    ? SC_M_COPY : UNKNOWN_METHOD);
+        default:
+            return UNKNOWN_METHOD;
+        }
+
+    case 5:
+        switch (method[2])
+        {
+        case 'R':
+            return (memcmp(method, "MERGE", 5) == 0
+                    ? SC_M_MERGE : UNKNOWN_METHOD);
+        case 'C':
+            return (memcmp(method, "MKCOL", 5) == 0
+                    ? SC_M_MKCOL : UNKNOWN_METHOD);
+        case 'B':
+            return (memcmp(method, "LABEL", 5) == 0
+                    ? SC_M_LABEL : UNKNOWN_METHOD);
+        case 'A':
+            return (memcmp(method, "TRACE", 5) == 0
+                    ? SC_M_TRACE : UNKNOWN_METHOD);
+        default:
+            return UNKNOWN_METHOD;
+        }
+
+    case 6:
+        switch (method[0])
+        {
+        case 'U':
+            switch (method[5])
+            {
+            case 'K':
+                return (memcmp(method, "UNLOCK", 6) == 0
+                        ? SC_M_UNLOCK : UNKNOWN_METHOD);
+            case 'E':
+                return (memcmp(method, "UPDATE", 6) == 0
+                        ? SC_M_UPDATE : UNKNOWN_METHOD);
+            default:
+                return UNKNOWN_METHOD;
+            }
+        case 'R':
+            return (memcmp(method, "REPORT", 6) == 0
+                    ? SC_M_REPORT : UNKNOWN_METHOD);
+        case 'S':
+            return (memcmp(method, "SEARCH", 6) == 0
+                    ? SC_M_SEARCH : UNKNOWN_METHOD);
+        case 'D':
+            return (memcmp(method, "DELETE", 6) == 0
+                    ? SC_M_DELETE : UNKNOWN_METHOD);
+        default:
+            return UNKNOWN_METHOD;
+        }
+
+    case 7:
+        switch (method[1])
+        {
+        case 'P':
+            return (memcmp(method, "OPTIONS", 7) == 0
+                    ? SC_M_OPTIONS : UNKNOWN_METHOD);
+        case 'H':
+            return (memcmp(method, "CHECKIN", 7) == 0
+                    ? SC_M_CHECKIN : UNKNOWN_METHOD);
+        default:
+            return UNKNOWN_METHOD;
+        }
+
+    case 8:
+        switch (method[0])
+        {
+        case 'P':
+            return (memcmp(method, "PROPFIND", 8) == 0
+                    ? SC_M_PROPFIND : UNKNOWN_METHOD);
+        case 'C':
+            return (memcmp(method, "CHECKOUT", 8) == 0
+                    ? SC_M_CHECKOUT : UNKNOWN_METHOD);
+        default:
+            return UNKNOWN_METHOD;
+        }
+
+    case 9:
+        return (memcmp(method, "PROPPATCH", 9) == 0
+                ? SC_M_PROPPATCH : UNKNOWN_METHOD);
+
+    case 10:
+        switch (method[0])
+        {
+        case 'U':
+            return (memcmp(method, "UNCHECKOUT", 10) == 0
+                    ? SC_M_UNCHECKOUT : UNKNOWN_METHOD);
+        case 'M':
+            return (memcmp(method, "MKACTIVITY", 10) == 0
+                    ? SC_M_MKACTIVITY : UNKNOWN_METHOD);
+        default:
+            return UNKNOWN_METHOD;
+        }
+
+    case 11:
+        return (memcmp(method, "MKWORKSPACE", 11) == 0
+                ? SC_M_MKWORKSPACE : UNKNOWN_METHOD);
+
+    case 15:
+        return (memcmp(method, "VERSION-CONTROL", 15) == 0
+                ? SC_M_VERSION_CONTROL : UNKNOWN_METHOD);
+
+    case 16:
+        return (memcmp(method, "BASELINE-CONTROL", 16) == 0
+                ? SC_M_BASELINE_CONTROL : UNKNOWN_METHOD);
+
+    default:
+        return UNKNOWN_METHOD;
+    }
+
+    /* NOTREACHED */
+}
+
+static int sc_for_req_header(const char *header_name)
+{
+    char header[16];
+    size_t len = strlen(header_name);
+    const char *p = header_name;
+    int i = 0;
+
+    /* ACCEPT-LANGUAGE is the longest headeer
+     * that is of interest.
+     */
+    if (len < 4 || len > 15)
+        return UNKNOWN_METHOD;
+
+    while (*p)
+        header[i++] = toupper((unsigned char)*p++);
+    header[i] = '\0';
+    p = &header[1];
+
+    switch (header[0]) {
+        case 'A':
+            if (memcmp(p, "CCEPT", 5) == 0) {
+                if (!header[6])
+                    return SC_ACCEPT;
+                else if (header[6] == '-') {
+                    p += 6;
+                    if (memcmp(p, "CHARSET", 7) == 0)
+                        return SC_ACCEPT_CHARSET;
+                    else if (memcmp(p,  "ENCODING", 8) == 0)
+                        return SC_ACCEPT_ENCODING;
+                    else if (memcmp(p, "LANGUAGE", 8) == 0)
+                        return SC_ACCEPT_LANGUAGE;
+                    else
+                        return UNKNOWN_METHOD;
+                }
+                else
+                    return UNKNOWN_METHOD;
+            }
+            else if (memcmp(p, "UTHORIZATION", 12) == 0)
+                return SC_AUTHORIZATION;
+            else
+                return UNKNOWN_METHOD;
+        break;
+        case 'C':
+            if(memcmp(p, "OOKIE2", 6) == 0)
+                return SC_COOKIE2;
+            else if (memcmp(p, "OOKIE", 5) == 0)
+                return SC_COOKIE;
+            else if(memcmp(p, "ONNECTION", 9) == 0)
+                return SC_CONNECTION;
+            else if(memcmp(p, "ONTENT-TYPE", 11) == 0)
+                return SC_CONTENT_TYPE;
+            else if(memcmp(p, "ONTENT-LENGTH", 13) == 0)
+                return SC_CONTENT_LENGTH;
+            else
+                return UNKNOWN_METHOD;
+        break;
+        case 'H':
+            if(memcmp(p, "OST", 3) == 0)
+                return SC_HOST;
+            else
+                return UNKNOWN_METHOD;
+        break;
+        case 'P':
+            if(memcmp(p, "RAGMA", 5) == 0)
+                return SC_PRAGMA;
+            else
+                return UNKNOWN_METHOD;
+        break;
+        case 'R':
+            if(memcmp(p, "EFERER", 6) == 0)
+                return SC_REFERER;
+            else
+                return UNKNOWN_METHOD;
+        break;
+        case 'U':
+            if(memcmp(p, "SER-AGENT", 9) == 0)
+                return SC_USER_AGENT;
+            else
+                return UNKNOWN_METHOD;
+        break;
+        default:
+            return UNKNOWN_METHOD;
+    }
+    /* NOTREACHED */
+}
+
+
+/*
+ * Message structure
+ *
+ *
+AJPV13_REQUEST/AJPV14_REQUEST=
+    request_prefix (1) (byte)
+    method         (byte)
+    protocol       (string)
+    req_uri        (string)
+    remote_addr    (string)
+    remote_host    (string)
+    server_name    (string)
+    server_port    (short)
+    is_ssl         (boolean)
+    num_headers    (short)
+    num_headers*(req_header_name header_value)
+
+    ?context       (byte)(string)
+    ?servlet_path  (byte)(string)
+    ?remote_user   (byte)(string)
+    ?auth_type     (byte)(string)
+    ?query_string  (byte)(string)
+    ?jvm_route     (byte)(string)
+    ?ssl_cert      (byte)(string)
+    ?ssl_cipher    (byte)(string)
+    ?ssl_session   (byte)(string)
+    ?ssl_key_size  (byte)(int)      via JkOptions +ForwardKeySize
+    request_terminator (byte)
+    ?body          content_length*(var binary)
+
+ */
+
+static int ajp_marshal_into_msgb(jk_msg_buf_t *msg,
+                                 jk_ws_service_t *s,
+                                 jk_logger_t *l, ajp_endpoint_t * ae)
+{
+    int method;
+    unsigned int i;
+
+    JK_TRACE_ENTER(l);
+
+    if ((method = sc_for_req_method(s->method,
+                                    strlen(s->method))) == UNKNOWN_METHOD)
+        method = SC_M_JK_STORED;
+
+    if (jk_b_append_byte(msg, JK_AJP13_FORWARD_REQUEST) ||
+        jk_b_append_byte(msg, (unsigned char)method) ||
+        jk_b_append_string(msg, s->protocol) ||
+        jk_b_append_string(msg, s->req_uri) ||
+        jk_b_append_string(msg, s->remote_addr) ||
+        jk_b_append_string(msg, s->remote_host) ||
+        jk_b_append_string(msg, s->server_name) ||
+        jk_b_append_int(msg, (unsigned short)s->server_port) ||
+        jk_b_append_byte(msg, (unsigned char)(s->is_ssl)) ||
+        jk_b_append_int(msg, (unsigned short)(s->num_headers))) {
+
+        jk_log(l, JK_LOG_ERROR,
+               "failed appending the message begining");
+        JK_TRACE_EXIT(l);
+        return JK_FALSE;
+    }
+
+    for (i = 0; i < s->num_headers; i++) {
+        int sc;
+
+        if ((sc = sc_for_req_header(s->headers_names[i])) != UNKNOWN_METHOD) {
+            if (jk_b_append_int(msg, (unsigned short)sc)) {
+                jk_log(l, JK_LOG_ERROR,
+                       "failed appending the header name");
+                JK_TRACE_EXIT(l);
+                return JK_FALSE;
+            }
+        }
+        else {
+            if (jk_b_append_string(msg, s->headers_names[i])) {
+                jk_log(l, JK_LOG_ERROR,
+                       "failed appending the header name");
+                JK_TRACE_EXIT(l);
+                return JK_FALSE;
+            }
+        }
+
+        if (jk_b_append_string(msg, s->headers_values[i])) {
+            jk_log(l, JK_LOG_ERROR,
+                   "failed appending the header value");
+            JK_TRACE_EXIT(l);
+            return JK_FALSE;
+        }
+    }
+
+    if (s->secret) {
+        if (jk_b_append_byte(msg, SC_A_SECRET) ||
+            jk_b_append_string(msg, s->secret)) {
+            jk_log(l, JK_LOG_ERROR,
+                   "failed appending secret");
+            JK_TRACE_EXIT(l);
+            return JK_FALSE;
+        }
+    }
+
+    if (s->remote_user) {
+        if (jk_b_append_byte(msg, SC_A_REMOTE_USER) ||
+            jk_b_append_string(msg, s->remote_user)) {
+            jk_log(l, JK_LOG_ERROR,
+                   "failed appending the remote user");
+            JK_TRACE_EXIT(l);
+            return JK_FALSE;
+        }
+    }
+    if (s->auth_type) {
+        if (jk_b_append_byte(msg, SC_A_AUTH_TYPE) ||
+            jk_b_append_string(msg, s->auth_type)) {
+            jk_log(l, JK_LOG_ERROR,
+                   "failed appending the auth type");
+            JK_TRACE_EXIT(l);
+            return JK_FALSE;
+        }
+    }
+    if (s->query_string) {
+        if (jk_b_append_byte(msg, SC_A_QUERY_STRING) ||
+#ifdef AS400
+            jk_b_append_asciistring(msg, s->query_string)) {
+#else
+            jk_b_append_string(msg, s->query_string)) {
+#endif
+            jk_log(l, JK_LOG_ERROR,
+                   "failed appending the query string");
+            JK_TRACE_EXIT(l);
+            return JK_FALSE;
+        }
+    }
+    if (s->jvm_route) {
+        if (jk_b_append_byte(msg, SC_A_JVM_ROUTE) ||
+            jk_b_append_string(msg, s->jvm_route)) {
+            jk_log(l, JK_LOG_ERROR,
+                   "failed appending the jvm route");
+            JK_TRACE_EXIT(l);
+            return JK_FALSE;
+        }
+    }
+    if (s->ssl_cert_len) {
+        if (jk_b_append_byte(msg, SC_A_SSL_CERT) ||
+            jk_b_append_string(msg, s->ssl_cert)) {
+            jk_log(l, JK_LOG_ERROR,
+                   "failed appending the SSL certificates");
+            JK_TRACE_EXIT(l);
+            return JK_FALSE;
+        }
+    }
+
+    if (s->ssl_cipher) {
+        if (jk_b_append_byte(msg, SC_A_SSL_CIPHER) ||
+            jk_b_append_string(msg, s->ssl_cipher)) {
+            jk_log(l, JK_LOG_ERROR,
+                   "failed appending the SSL ciphers");
+            JK_TRACE_EXIT(l);
+            return JK_FALSE;
+        }
+    }
+    if (s->ssl_session) {
+        if (jk_b_append_byte(msg, SC_A_SSL_SESSION) ||
+            jk_b_append_string(msg, s->ssl_session)) {
+            jk_log(l, JK_LOG_ERROR,
+                   "failed appending the SSL session");
+            JK_TRACE_EXIT(l);
+            return JK_FALSE;
+        }
+    }
+
+    /*
+     * ssl_key_size is required by Servlet 2.3 API
+     * added support only in ajp14 mode
+     * JFC removed: ae->proto == AJP14_PROTO
+     */
+    if (s->ssl_key_size != -1) {
+        if (jk_b_append_byte(msg, SC_A_SSL_KEY_SIZE) ||
+            jk_b_append_int(msg, (unsigned short)s->ssl_key_size)) {
+            jk_log(l, JK_LOG_ERROR,
+                   "failed appending the SSL key size");
+            JK_TRACE_EXIT(l);
+            return JK_FALSE;
+        }
+    }
+
+    /* If the method was unrecognized, encode it as an attribute */
+    if (method == SC_M_JK_STORED) {
+        if (JK_IS_DEBUG_LEVEL(l))
+            jk_log(l, JK_LOG_DEBUG, "unknown method %s", s->method);
+        if (jk_b_append_byte(msg, SC_A_STORED_METHOD) ||
+            jk_b_append_string(msg, s->method)) {
+            jk_log(l, JK_LOG_ERROR,
+                   "failed appending the request method");
+            JK_TRACE_EXIT(l);
+            return JK_FALSE;
+        }
+    }
+
+    if (s->num_attributes > 0) {
+        for (i = 0; i < s->num_attributes; i++) {
+            if (jk_b_append_byte(msg, SC_A_REQ_ATTRIBUTE) ||
+                jk_b_append_string(msg, s->attributes_names[i]) ||
+                jk_b_append_string(msg, s->attributes_values[i])) {
+                jk_log(l, JK_LOG_ERROR,
+                       "failed appending attribute %s=%s",
+                       s->attributes_names[i], s->attributes_values[i]);
+                JK_TRACE_EXIT(l);
+                return JK_FALSE;
+            }
+        }
+    }
+
+    if (jk_b_append_byte(msg, SC_A_ARE_DONE)) {
+        jk_log(l, JK_LOG_ERROR,
+               "failed appending the message end");
+        JK_TRACE_EXIT(l);
+        return JK_FALSE;
+    }
+
+    if (JK_IS_DEBUG_LEVEL(l))
+        jk_log(l, JK_LOG_DEBUG, "ajp marshaling done");
+    JK_TRACE_EXIT(l);
+    return JK_TRUE;
+}
+
+/*
+AJPV13_RESPONSE/AJPV14_RESPONSE:=
+    response_prefix (2)
+    status          (short)
+    status_msg      (short)
+    num_headers     (short)
+    num_headers*(res_header_name header_value)
+    *body_chunk
+    terminator      boolean <! -- recycle connection or not  -->
+
+req_header_name :=
+    sc_req_header_name | (string)
+
+res_header_name :=
+    sc_res_header_name | (string)
+
+header_value :=
+    (string)
+
+body_chunk :=
+    length  (short)
+    body    length*(var binary)
+
+ */
+
+
+static int ajp_unmarshal_response(jk_msg_buf_t *msg,
+                                  jk_res_data_t * d,
+                                  ajp_endpoint_t * ae, jk_logger_t *l)
+{
+    jk_pool_t *p = &ae->pool;
+
+    d->status = jk_b_get_int(msg);
+    JK_TRACE_ENTER(l);
+
+    if (!d->status) {
+        jk_log(l, JK_LOG_ERROR,
+               "NULL status");
+        JK_TRACE_EXIT(l);
+        return JK_FALSE;
+    }
+
+    d->msg = (char *)jk_b_get_string(msg);
+    if (d->msg) {
+#if defined(AS400) || defined(_OSD_POSIX)
+        jk_xlate_from_ascii(d->msg, strlen(d->msg));
+#endif
+    }
+
+    if (JK_IS_DEBUG_LEVEL(l))
+        jk_log(l, JK_LOG_DEBUG,
+               "status = %d", d->status);
+
+    d->num_headers = jk_b_get_int(msg);
+    d->header_names = d->header_values = NULL;
+
+    if (JK_IS_DEBUG_LEVEL(l))
+        jk_log(l, JK_LOG_DEBUG,
+               "Number of headers is = %d",
+               d->num_headers);
+
+    if (d->num_headers) {
+        d->header_names = jk_pool_alloc(p, sizeof(char *) * d->num_headers);
+        d->header_values = jk_pool_alloc(p, sizeof(char *) * d->num_headers);
+
+        if (d->header_names && d->header_values) {
+            unsigned int i;
+            for (i = 0; i < d->num_headers; i++) {
+                unsigned short name = jk_b_pget_int(msg, msg->pos);
+
+                if ((name & 0XFF00) == 0XA000) {
+                    jk_b_get_int(msg);
+                    name = name & 0X00FF;
+                    if (name <= SC_RES_HEADERS_NUM) {
+                        d->header_names[i] =
+                            (char *)long_res_header_for_sc(name);
+                    }
+                    else {
+                        jk_log(l, JK_LOG_ERROR,
+                               "No such sc (%d)", name);
+                        JK_TRACE_EXIT(l);
+                        return JK_FALSE;
+                    }
+                }
+                else {
+                    d->header_names[i] = (char *)jk_b_get_string(msg);
+                    if (!d->header_names[i]) {
+                        jk_log(l, JK_LOG_ERROR,
+                               "NULL header name");
+                        JK_TRACE_EXIT(l);
+                        return JK_FALSE;
+                    }
+#if defined(AS400) || defined(_OSD_POSIX)
+                    jk_xlate_from_ascii(d->header_names[i],
+                                        strlen(d->header_names[i]));
+#endif
+
+                }
+
+                d->header_values[i] = (char *)jk_b_get_string(msg);
+                if (!d->header_values[i]) {
+                    jk_log(l, JK_LOG_ERROR,
+                           "NULL header value");
+                    JK_TRACE_EXIT(l);
+                    return JK_FALSE;
+                }
+
+#if defined(AS400) || defined(_OSD_POSIX)
+                jk_xlate_from_ascii(d->header_values[i],
+                                    strlen(d->header_values[i]));
+#endif
+
+                if (JK_IS_DEBUG_LEVEL(l))
+                    jk_log(l, JK_LOG_DEBUG,
+                           "Header[%d] [%s] = [%s]",
+                           i, d->header_names[i], d->header_values[i]);
+            }
+        }
+    }
+
+    JK_TRACE_EXIT(l);
+    return JK_TRUE;
+}
+
+/*
+ * Reset the endpoint (clean buf and close socket)
+ */
+
+static void ajp_reset_endpoint(ajp_endpoint_t * ae, jk_logger_t *l)
+{
+    if (ae->sd > 0 && !ae->reuse) {
+        jk_close_socket(ae->sd);
+        if (JK_IS_DEBUG_LEVEL(l))
+            jk_log(l, JK_LOG_DEBUG,
+                   "reset socket with sd = %d", ae->sd);
+        ae->sd = -1;
+    }
+    jk_reset_pool(&(ae->pool));
+}
+
+/*
+ * Close the endpoint (close pool and close socket)
+ */
+
+void ajp_close_endpoint(ajp_endpoint_t * ae, jk_logger_t *l)
+{
+    JK_TRACE_ENTER(l);
+
+    if (IS_VALID_SOCKET(ae->sd)) {
+        jk_shutdown_socket(ae->sd);
+        if (JK_IS_DEBUG_LEVEL(l))
+            jk_log(l, JK_LOG_DEBUG,
+                   "closed socket with sd = %d", ae->sd);
+        ae->sd = JK_INVALID_SOCKET;
+    }
+
+    jk_close_pool(&(ae->pool));
+    free(ae);
+    JK_TRACE_EXIT(l);
+}
+
+
+/*
+ * Try another connection from cache
+ */
+
+static void ajp_next_connection(ajp_endpoint_t *ae, jk_logger_t *l)
+{
+    int rc;
+    ajp_worker_t *aw = ae->worker;
+    jk_sock_t sock = ae->sd;
+
+    /* Mark existing endpoint socket as closed */
+    ae->sd = JK_INVALID_SOCKET;
+    JK_ENTER_CS(&aw->cs, rc);
+    if (rc) {
+        unsigned int i;
+        for (i = 0; i < aw->ep_cache_sz; i++) {
+            /* Find cache slot with usable socket */
+            if (aw->ep_cache[i] && IS_VALID_SOCKET(aw->ep_cache[i]->sd)) {
+                ae->sd = aw->ep_cache[i]->sd;
+                aw->ep_cache[i]->sd = JK_INVALID_SOCKET;
+                break;
+            }
+        }
+        JK_LEAVE_CS(&aw->cs, rc);
+    }
+    /* Close previous socket */
+    if (IS_VALID_SOCKET(sock))
+        jk_close_socket(sock);
+}
+
+/*
+ * Wait input event on ajp_endpoint for timeout ms
+ */
+static int ajp_is_input_event(ajp_endpoint_t * ae, int timeout, jk_logger_t *l)
+{
+    fd_set rset;
+    struct timeval tv;
+    int rc;
+
+    FD_ZERO(&rset);
+    FD_SET(ae->sd, &rset);
+    tv.tv_sec = timeout / 1000;
+    tv.tv_usec = (timeout % 1000) * 1000;
+
+    do {
+        rc = select((int)ae->sd + 1, &rset, NULL, NULL, &tv);
+    } while (rc < 0 && errno == EINTR);
+
+    if (rc == 0) {
+        /* Timeout. Set the errno to timeout */
+#if defined(WIN32) || (defined(NETWARE) && defined(__NOVELL_LIBC__))
+        errno = WSAETIMEDOUT - WSABASEERR;
+#else
+        errno = ETIMEDOUT;
+#endif
+        return JK_FALSE;
+    }
+    else if (rc < 0) {
+        jk_log(l, JK_LOG_WARNING,
+               "error during select err=%d", errno);
+        return JK_FALSE;
+    }
+    else
+        return JK_TRUE;
+}
+
+
+/*
+ * Handle the CPING/CPONG initial query
+ */
+static int ajp_handle_cping_cpong(ajp_endpoint_t * ae, int timeout, jk_logger_t *l)
+{
+    int cmd;
+    jk_msg_buf_t *msg;
+
+    JK_TRACE_ENTER(l);
+    msg = jk_b_new(&ae->pool);
+    jk_b_set_buffer_size(msg, 16);      /* 16 is way too large but I'm lazy :-) */
+    jk_b_reset(msg);
+    jk_b_append_byte(msg, AJP13_CPING_REQUEST);
+
+    /* Send CPing query */
+    if (ajp_connection_tcp_send_message(ae, msg, l) != JK_TRUE) {
+        jk_log(l, JK_LOG_INFO,
+               "can't send cping query");
+        JK_TRACE_EXIT(l);
+        return JK_FALSE;
+    }
+
+    /* wait for Pong reply for timeout milliseconds
+     */
+    if (ajp_is_input_event(ae, timeout, l) == JK_FALSE) {
+        jk_log(l, JK_LOG_INFO, "timeout in reply pong");
+        JK_TRACE_EXIT(l);
+        return JK_FALSE;
+    }
+
+    /* Read and check for Pong reply
+     */
+    if (ajp_connection_tcp_get_message(ae, msg, l) != JK_TRUE) {
+        jk_log(l, JK_LOG_INFO,
+               "awaited reply cpong, not received");
+        JK_TRACE_EXIT(l);
+        return JK_FALSE;
+    }
+
+    if ((cmd = jk_b_get_byte(msg)) != AJP13_CPONG_REPLY) {
+        jk_log(l, JK_LOG_INFO,
+               "awaited reply cpong, received %d instead",
+               cmd);
+        JK_TRACE_EXIT(l);
+        return JK_FALSE;
+    }
+
+    JK_TRACE_EXIT(l);
+    return JK_TRUE;
+}
+
+int ajp_connect_to_endpoint(ajp_endpoint_t * ae, jk_logger_t *l)
+{
+    char buf[32];
+    int rc = JK_TRUE;
+
+    JK_TRACE_ENTER(l);
+
+    ae->sd = jk_open_socket(&ae->worker->worker_inet_addr,
+                            ae->worker->keepalive,
+                            ae->worker->socket_timeout,
+                            ae->worker->socket_buf, l);
+    if (IS_VALID_SOCKET(ae->sd)) {
+        ae->last_errno = 0;
+        if (JK_IS_DEBUG_LEVEL(l)) {
+            jk_log(l, JK_LOG_DEBUG,
+                   "Connected socket %d to (%s)",
+                   ae->sd,
+                   jk_dump_hinfo(&ae->worker->worker_inet_addr, buf));
+        }
+        /* set last_access only if needed */
+        if (ae->worker->cache_timeout > 0)
+            ae->last_access = time(NULL);
+        /* Check if we must execute a logon after the physical connect */
+        if (ae->worker->logon != NULL) {
+            rc = ae->worker->logon(ae, l);
+            JK_TRACE_EXIT(l);
+            return rc;
+        }
+        /* should we send a CPING to validate connection ? */
+        if (ae->worker->connect_timeout > 0) {
+            rc = ajp_handle_cping_cpong (ae,
+                        ae->worker->connect_timeout, l);
+            JK_TRACE_EXIT(l);
+            return rc;
+        }
+        JK_TRACE_EXIT(l);
+        return JK_TRUE;
+    }
+    ae->last_errno = errno;
+
+    jk_log(l, JK_LOG_INFO,
+           "Failed opening socket to (%s) with (errno=%d)",
+           jk_dump_hinfo(&ae->worker->worker_inet_addr, buf), errno);
+    JK_TRACE_EXIT(l);
+    return JK_FALSE;
+}
+
+/*
+ * Send a message to endpoint, using corresponding PROTO HEADER
+ */
+
+int ajp_connection_tcp_send_message(ajp_endpoint_t * ae,
+                                    jk_msg_buf_t *msg, jk_logger_t *l)
+{
+    int rc;
+
+    JK_TRACE_ENTER(l);
+    if (ae->proto == AJP13_PROTO) {
+        jk_b_end(msg, AJP13_WS_HEADER);
+        if (JK_IS_DEBUG_LEVEL(l))
+            jk_dump_buff(l, JK_LOG_DEBUG, "sending to ajp13", msg);
+    }
+    else if (ae->proto == AJP14_PROTO) {
+        jk_b_end(msg, AJP14_WS_HEADER);
+        if (JK_IS_DEBUG_LEVEL(l))
+            jk_dump_buff(l, JK_LOG_DEBUG, "sending to ajp14", msg);
+    }
+    else {
+        jk_log(l, JK_LOG_ERROR,
+               "unknown protocol %d, supported are AJP13/AJP14", ae->proto);
+        JK_TRACE_EXIT(l);
+        return JK_FATAL_ERROR;
+    }
+
+    if ((rc = jk_tcp_socket_sendfull(ae->sd, msg->buf,
+                                     msg->len)) > 0) {
+        ae->endpoint.wr += msg->len;
+        JK_TRACE_EXIT(l);
+        ae->last_errno = 0;
+        return JK_TRUE;
+    }
+    ae->last_errno = errno;
+    jk_log(l, JK_LOG_ERROR,
+           "sendfull returned %d with errno=%d ", rc, ae->last_errno);
+
+    JK_TRACE_EXIT(l);
+    return JK_FALSE;
+}
+
+/*
+ * Receive a message from endpoint, checking PROTO HEADER
+ */
+
+int ajp_connection_tcp_get_message(ajp_endpoint_t * ae,
+                                   jk_msg_buf_t *msg, jk_logger_t *l)
+{
+    unsigned char head[AJP_HEADER_LEN];
+    int rc;
+    int msglen;
+    unsigned int header;
+    char buf[32];
+
+    JK_TRACE_ENTER(l);
+
+    rc = jk_tcp_socket_recvfull(ae->sd, head, AJP_HEADER_LEN);
+
+    if (rc < 0) {
+        ae->last_errno = errno;
+        if (rc == JK_SOCKET_EOF) {
+            jk_log(l, JK_LOG_INFO,
+                   "(%s) Tomcat has forced a connection close for socket %d",
+                   ae->worker->name, ae->sd);
+            JK_TRACE_EXIT(l);
+        }
+        else {
+            jk_log(l, JK_LOG_ERROR,
+                   "(%s) can't receive the response message from tomcat, "
+                   "network problems or tomcat is down (%s), err=%d",
+                   ae->worker->name, jk_dump_hinfo(&ae->worker->worker_inet_addr,
+                                                   buf), rc);
+             JK_TRACE_EXIT(l);
+        }
+        return JK_FALSE;
+    }
+    ae->last_errno = 0;
+    ae->endpoint.rd += rc;
+    header = ((unsigned int)head[0] << 8) | head[1];
+
+    if (ae->proto == AJP13_PROTO) {
+        if (header != AJP13_SW_HEADER) {
+
+            if (header == AJP14_SW_HEADER) {
+                jk_log(l, JK_LOG_ERROR,
+                       "received AJP14 reply on an AJP13 connection from %s",
+                       jk_dump_hinfo(&ae->worker->worker_inet_addr, buf));
+            }
+            else {
+                jk_log(l, JK_LOG_ERROR,
+                       "wrong message format 0x%04x from %s",
+                       header, jk_dump_hinfo(&ae->worker->worker_inet_addr,
+                                             buf));
+            }
+            JK_TRACE_EXIT(l);
+            return JK_FALSE;
+        }
+    }
+    else if (ae->proto == AJP14_PROTO) {
+        if (header != AJP14_SW_HEADER) {
+
+            if (header == AJP13_SW_HEADER) {
+                jk_log(l, JK_LOG_ERROR,
+                       "received AJP13 reply on an AJP14 connection from %s",
+                       jk_dump_hinfo(&ae->worker->worker_inet_addr, buf));
+            }
+            else {
+                jk_log(l, JK_LOG_ERROR,
+                       "wrong message format 0x%04x from %s",
+                       header, jk_dump_hinfo(&ae->worker->worker_inet_addr,
+                                             buf));
+            }
+            JK_TRACE_EXIT(l);
+            return JK_FALSE;
+        }
+    }
+
+    msglen = ((head[2] & 0xff) << 8);
+    msglen += (head[3] & 0xFF);
+
+    if (msglen > msg->maxlen) {
+        jk_log(l, JK_LOG_ERROR,
+               "wrong message size %d %d from %s",
+               msglen, msg->maxlen,
+               jk_dump_hinfo(&ae->worker->worker_inet_addr, buf));
+        JK_TRACE_EXIT(l);
+        return JK_FALSE;
+    }
+
+    msg->len = msglen;
+    msg->pos = 0;
+
+    rc = jk_tcp_socket_recvfull(ae->sd, msg->buf, msglen);
+    if (rc < 0) {
+        ae->last_errno = errno;
+        jk_log(l, JK_LOG_ERROR,
+               "(%s) can't receive the response message from tomcat, "
+               "network problems or tomcat (%s) is down %d",
+               ae->worker->name, jk_dump_hinfo(&ae->worker->worker_inet_addr, buf),
+                                               rc);
+        JK_TRACE_EXIT(l);
+        return JK_FALSE;
+    }
+    ae->last_errno = 0;
+    ae->endpoint.rd += rc;
+
+    if (ae->proto == AJP13_PROTO) {
+        if (JK_IS_DEBUG_LEVEL(l))
+            jk_dump_buff(l, JK_LOG_DEBUG, "received from ajp13", msg);
+    }
+    else if (ae->proto == AJP14_PROTO) {
+        if (JK_IS_DEBUG_LEVEL(l))
+            jk_dump_buff(l, JK_LOG_DEBUG, "received from ajp14", msg);
+    }
+    JK_TRACE_EXIT(l);
+    return JK_TRUE;
+}
+
+/*
+ * Read all the data from the socket.
+ *
+ * Socket API doesn't guaranty that all the data will be kept in a
+ * single read, so we must loop until all awaited data is received
+ */
+
+static int ajp_read_fully_from_server(jk_ws_service_t *s, jk_logger_t *l,
+                                      unsigned char *buf, unsigned int len)
+{
+    unsigned int rdlen = 0;
+    unsigned int padded_len = len;
+
+    JK_TRACE_ENTER(l);
+    if (s->is_chunked && s->no_more_chunks) {
+        JK_TRACE_EXIT(l);
+        return 0;
+    }
+    if (s->is_chunked) {
+        /* Corner case: buf must be large enough to hold next
+         * chunk size (if we're on or near a chunk border).
+         * Pad the length to a reasonable value, otherwise the
+         * read fails and the remaining chunks are tossed.
+         */
+        padded_len = (len < CHUNK_BUFFER_PAD) ? len : len - CHUNK_BUFFER_PAD;
+    }
+
+    while (rdlen < padded_len) {
+        unsigned int this_time = 0;
+        if (!s->read(s, buf + rdlen, len - rdlen, &this_time)) {
+            /* Remote Client read failed. */
+            JK_TRACE_EXIT(l);
+            return JK_CLIENT_RD_ERROR;
+        }
+
+        if (0 == this_time) {
+            if (s->is_chunked) {
+                s->no_more_chunks = 1;  /* read no more */
+            }
+            break;
+        }
+        rdlen += this_time;
+    }
+
+    return (int)rdlen;
+}
+
+
+/*
+ * Read data from AJP13/AJP14 protocol
+ * Returns -1 on error, else number of bytes read
+ */
+
+static int ajp_read_into_msg_buff(ajp_endpoint_t * ae,
+                                  jk_ws_service_t *r,
+                                  jk_msg_buf_t *msg, int len, jk_logger_t *l)
+{
+    unsigned char *read_buf = msg->buf;
+
+    JK_TRACE_ENTER(l);
+    jk_b_reset(msg);
+
+    read_buf += AJP_HEADER_LEN; /* leave some space for the buffer headers */
+    read_buf += AJP_HEADER_SZ_LEN;      /* leave some space for the read length */
+
+    /* Pick the max size since we don't know the content_length */
+    if (r->is_chunked && len == 0) {
+        len = AJP13_MAX_SEND_BODY_SZ;
+    }
+
+    if ((len = ajp_read_fully_from_server(r, l, read_buf, len)) < 0) {
+        jk_log(l, JK_LOG_INFO,
+               "(%) receiving data from client failed. "
+               "Connection aborted or network problems",
+               ae->worker->name);
+        JK_TRACE_EXIT(l);
+        return JK_CLIENT_RD_ERROR;
+    }
+
+    if (!r->is_chunked) {
+        ae->left_bytes_to_send -= len;
+    }
+
+    if (len > 0) {
+        /* Recipient recognizes empty packet as end of stream, not
+           an empty body packet */
+        if (0 != jk_b_append_int(msg, (unsigned short)len)) {
+            jk_log(l, JK_LOG_INFO,
+                   "Failed appending message length");
+            JK_TRACE_EXIT(l);
+            return JK_CLIENT_RD_ERROR;
+        }
+    }
+
+    msg->len += len;
+
+    JK_TRACE_EXIT(l);
+    return len;
+}
+
+
+/*
+ * send request to Tomcat via Ajp13
+ * - first try to find reuseable socket
+ * - if no one available, try to connect
+ * - send request, but send must be see as asynchronous,
+ *   since send() call will return noerror about 95% of time
+ *   Hopefully we'll get more information on next read.
+ *
+ * nb: reqmsg is the original request msg buffer
+ *     repmsg is the reply msg buffer which could be scratched
+ */
+static int ajp_send_request(jk_endpoint_t *e,
+                            jk_ws_service_t *s,
+                            jk_logger_t *l,
+                            ajp_endpoint_t * ae, ajp_operation_t * op)
+{
+    int err = 0;
+    int postlen;
+
+    JK_TRACE_ENTER(l);
+    /* Up to now, we can recover */
+    op->recoverable = JK_TRUE;
+
+    /*
+     * First try to reuse open connections...
+     */
+    while (IS_VALID_SOCKET(ae->sd)) {
+        int rc = 0;
+        err = 0;
+        if (ae->worker->socket_timeout) {
+            if (!jk_is_socket_connected(ae->sd)) {
+                jk_log(l, JK_LOG_INFO,
+                       "(%s) socket %d is not connected any more (errno=%d)",
+                       ae->worker->name, ae->sd, errno);
+                jk_close_socket(ae->sd);
+                ae->sd = JK_INVALID_SOCKET;
+                err++;
+            }
+        }
+        if (ae->worker->prepost_timeout != 0 && !err) {
+            /* handle cping/cpong if prepost_timeout is set
+             * If the socket is disconnected no need to handle
+             * the cping/cpong
+             */
+            if (ajp_handle_cping_cpong(ae, ae->worker->prepost_timeout, l) ==
+                JK_FALSE)
+                err++;
+        }
+
+        /* If we got an error or can't send data, then try to get a pooled
+         * connection and try again.  If we are succesful, break out of this
+         * loop. */
+        if (err ||
+            ((rc = ajp_connection_tcp_send_message(ae, op->request, l)) != JK_TRUE)) {
+            if (rc != JK_FATAL_ERROR) {
+                jk_log(l, JK_LOG_INFO,
+                       "(%s) error sending request. Will try another pooled connection",
+                       ae->worker->name);
+                ajp_next_connection(ae, l);
+            }
+            else {
+                op->recoverable = JK_FALSE;
+                jk_log(l, JK_LOG_INFO,
+                       "(%s) error sending request. Unrecoverable operation",
+                       ae->worker->name);
+                JK_TRACE_EXIT(l);
+                return JK_FALSE;
+            }
+        }
+        else
+            break;
+    }
+
+    /*
+     * If we failed to reuse a connection, try to reconnect.
+     */
+    if (!IS_VALID_SOCKET(ae->sd)) {
+        if (err) {
+            /* XXX: If err is set, the tomcat is either dead or disconnected */
+            jk_log(l, JK_LOG_INFO,
+                   "(%s) all endpoints are disconnected or dead",
+                   ae->worker->name);
+            JK_TRACE_EXIT(l);
+            return JK_FALSE;
+        }
+        /* Connect to the backend.
+         * This can be either uninitalized connection or a reconnect.
+         */
+        if (ajp_connect_to_endpoint(ae, l) == JK_TRUE) {
+            /*
+             * After we are connected, each error that we are going to
+             * have is probably unrecoverable
+             */
+            if (ajp_connection_tcp_send_message(ae, op->request, l) != JK_TRUE) {
+                /* Close the socket if unable to send request */
+                jk_close_socket(ae->sd);
+                ae->sd = -1;
+                jk_log(l, JK_LOG_INFO,
+                       "(%s) error sending request on a fresh connection (errno=%d)",
+                       ae->worker->name, ae->last_errno);
+                JK_TRACE_EXIT(l);
+                return JK_FALSE;
+            }
+        }
+        else {
+            /* Close the socket if unable to connect */
+            jk_close_socket(ae->sd);
+            ae->sd = JK_INVALID_SOCKET;
+            jk_log(l, JK_LOG_INFO,
+                   "(%s) error connecting to the backend server (errno=%d)",
+                   ae->worker->name, ae->last_errno);
+            JK_TRACE_EXIT(l);
+            return JK_FALSE;
+        }
+    }
+
+    /*
+     * From now on an error means that we have an internal server error
+     * or Tomcat crashed. In any case we cannot recover this.
+     */
+
+    if (JK_IS_DEBUG_LEVEL(l))
+        jk_log(l, JK_LOG_DEBUG,
+               "request body to send %d - request body to resend %d",
+               ae->left_bytes_to_send, op->reply->len - AJP_HEADER_LEN);
+
+    /*
+     * POST recovery job is done here and will work when data to
+     * POST are less than 8k, since it's the maximum size of op-post buffer.
+     * We send here the first part of data which was sent previously to the
+     * remote Tomcat
+     */
+
+    /* Did we have something to resend (ie the op-post has been feeded previously */
+
+    postlen = op->post->len;
+    if (postlen > AJP_HEADER_LEN) {
+        if (ajp_connection_tcp_send_message(ae, op->post, l) != JK_TRUE) {
+            /* Close the socket if unable to send request */
+            jk_close_socket(ae->sd);
+            ae->sd = JK_INVALID_SOCKET;
+            jk_log(l, JK_LOG_ERROR, "(%s) failed resending request body (%d)",
+                   ae->worker->name, postlen);
+            JK_TRACE_EXIT(l);
+            return JK_SERVER_ERROR;
+        }
+        else {
+            if (JK_IS_DEBUG_LEVEL(l))
+                jk_log(l, JK_LOG_DEBUG, "Resent the request body (%d)",
+                       postlen);
+        }
+    }
+    else if (s->reco_status == RECO_FILLED) {
+        /* Recovery in LB MODE */
+        postlen = s->reco_buf->len;
+
+        if (postlen > AJP_HEADER_LEN) {
+            if (ajp_connection_tcp_send_message(ae, s->reco_buf, l) != JK_TRUE) {
+                /* Close the socket if unable to send request */
+                jk_close_socket(ae->sd);
+                ae->sd = -1;
+                jk_log(l, JK_LOG_ERROR,
+                       "(%s) failed resending request body (lb mode) (%d)",
+                       ae->worker->name, postlen);
+                JK_TRACE_EXIT(l);
+                return JK_SERVER_ERROR;
+            }
+        }
+        else {
+            if (JK_IS_DEBUG_LEVEL(l))
+                jk_log(l, JK_LOG_DEBUG,
+                       "Resent the request body (lb mode) (%d)", postlen);
+        }
+    }
+    else {
+        /* We never sent any POST data and we check if we have to send at
+         * least one block of data (max 8k). These data will be kept in reply
+         * for resend if the remote Tomcat is down, a fact we will learn only
+         * doing a read (not yet)
+         */
+        /* || s->is_chunked - this can't be done here. The original protocol
+           sends the first chunk of post data ( based on Content-Length ),
+           and that's what the java side expects.
+           Sending this data for chunked would break other ajp13 servers.
+
+           Note that chunking will continue to work - using the normal read.
+         */
+
+        if (ae->left_bytes_to_send > 0) {
+            int len = ae->left_bytes_to_send;
+            if (len > AJP13_MAX_SEND_BODY_SZ) {
+                len = AJP13_MAX_SEND_BODY_SZ;
+            }
+            if ((len = ajp_read_into_msg_buff(ae, s, op->post, len, l)) < 0) {
+                /* the browser stop sending data, no need to recover */
+                op->recoverable = JK_FALSE;
+                JK_TRACE_EXIT(l);
+                return JK_CLIENT_RD_ERROR;
+            }
+
+            /* If a RECOVERY buffer is available in LB mode, fill it */
+            if (s->reco_status == RECO_INITED) {
+                jk_b_copy(op->post, s->reco_buf);
+                s->reco_status = RECO_FILLED;
+            }
+
+            s->content_read = len;
+            if (ajp_connection_tcp_send_message(ae, op->post, l) != JK_TRUE) {
+                /* Close the socket if unable to send request */
+                jk_close_socket(ae->sd);
+                ae->sd = -1;
+                jk_log(l, JK_LOG_ERROR, "(%s) error sending request body",
+                       ae->worker->name);
+                JK_TRACE_EXIT(l);
+                return JK_SERVER_ERROR;
+            }
+        }
+    }
+    JK_TRACE_EXIT(l);
+    return (JK_TRUE);
+}
+
+/*
+ * What to do with incoming data (dispatcher)
+ */
+
+static int ajp_process_callback(jk_msg_buf_t *msg,
+                                jk_msg_buf_t *pmsg,
+                                ajp_endpoint_t * ae,
+                                jk_ws_service_t *r, jk_logger_t *l)
+{
+    int code = (int)jk_b_get_byte(msg);
+
+    JK_TRACE_ENTER(l);
+    switch (code) {
+    case JK_AJP13_SEND_HEADERS:
+        {
+            jk_res_data_t res;
+            if (!ajp_unmarshal_response(msg, &res, ae, l)) {
+                jk_log(l, JK_LOG_ERROR,
+                       "ajp_unmarshal_response failed");
+                JK_TRACE_EXIT(l);
+                return JK_AJP13_ERROR;
+            }
+            r->start_response(r, res.status, res.msg,
+                              (const char *const *)res.header_names,
+                              (const char *const *)res.header_values,
+                              res.num_headers);
+        }
+        return JK_AJP13_SEND_HEADERS;
+
+    case JK_AJP13_SEND_BODY_CHUNK:
+        {
+            unsigned int len = (unsigned int)jk_b_get_int(msg);
+            /*
+             * Do a sanity check on len to prevent write reading beyond buffer
+             * boundaries and thus revealing possible sensitive memory
+             * contents to the client.
+             * len cannot be larger than msg->len - 3 because the ajp message
+             * contains the magic byte for JK_AJP13_SEND_BODY_CHUNK (1 byte)
+             * and the length of the chunk (2 bytes). The remaining part of
+             * the message is the chunk.
+             */
+            if (len > (unsigned int)(msg->len - 3)) {
+                jk_log(l, JK_LOG_ERROR,
+                       "Chunk length too large. Length of AJP message is %i,"
+                       " chunk length is %i.", msg->len, len);
+                JK_TRACE_EXIT(l);
+                return JK_INTERNAL_ERROR;
+            }
+            if (!r->write(r, msg->buf + msg->pos, len)) {
+                jk_log(l, JK_LOG_INFO,
+                       "Writing to client aborted or client network problems");
+                JK_TRACE_EXIT(l);
+                return JK_CLIENT_WR_ERROR;
+            }
+            if (r->flush && r->flush_packets)
+                r->flush(r);
+        }
+        break;
+
+    case JK_AJP13_GET_BODY_CHUNK:
+        {
+            int len = (int)jk_b_get_int(msg);
+
+            if (len < 0) {
+                len = 0;
+            }
+            if (len > AJP13_MAX_SEND_BODY_SZ) {
+                len = AJP13_MAX_SEND_BODY_SZ;
+            }
+            if ((unsigned int)len > ae->left_bytes_to_send) {
+                len = ae->left_bytes_to_send;
+            }
+
+            /* the right place to add file storage for upload */
+            if ((len = ajp_read_into_msg_buff(ae, r, pmsg, len, l)) >= 0) {
+                r->content_read += len;
+                JK_TRACE_EXIT(l);
+                return JK_AJP13_HAS_RESPONSE;
+            }
+
+            jk_log(l, JK_LOG_INFO,
+                   "Reding from client aborted or client network problems");
+
+            JK_TRACE_EXIT(l);
+            return JK_CLIENT_RD_ERROR;
+        }
+        break;
+
+    case JK_AJP13_END_RESPONSE:
+        ae->reuse = (int)jk_b_get_byte(msg);
+        if (!ae->reuse) {
+            /*
+             * AJP13 protocol reuse flag set to false.
+             * Tomcat will close its side of the connection.
+             */
+            jk_log(l, JK_LOG_WARNING, "AJP13 protocol: Reuse is set to false");
+        }
+        else if (r->disable_reuse) {
+            ae->reuse = JK_FALSE;
+        }
+        else {
+            /* Reuse in all cases */
+            ae->reuse = JK_TRUE;
+        }
+        /* Flush after the last write */
+        if (r->flush && !r->flush_packets)
+            r->flush(r);
+
+        JK_TRACE_EXIT(l);
+        return JK_AJP13_END_RESPONSE;
+        break;
+
+    default:
+        jk_log(l, JK_LOG_ERROR,
+               "Unknown AJP protocol code: %02X", code);
+        JK_TRACE_EXIT(l);
+        return JK_AJP13_ERROR;
+    }
+
+    JK_TRACE_EXIT(l);
+    return JK_AJP13_NO_RESPONSE;
+}
+
+/*
+ * get replies from Tomcat via Ajp13/Ajp14
+ * We will know only at read time if the remote host closed
+ * the connection (half-closed state - FIN-WAIT2). In that case
+ * we must close our side of the socket and abort emission.
+ * We will need another connection to send the request
+ * There is need of refactoring here since we mix
+ * reply reception (tomcat -> apache) and request send (apache -> tomcat)
+ * and everything using the same buffer (repmsg)
+ * ajp13/ajp14 is async but handling read/send this way prevent nice recovery
+ * In fact if tomcat link is broken during upload (browser -> apache -> tomcat)
+ * we'll loose data and we'll have to abort the whole request.
+ */
+static int ajp_get_reply(jk_endpoint_t *e,
+                         jk_ws_service_t *s,
+                         jk_logger_t *l,
+                         ajp_endpoint_t * p, ajp_operation_t * op)
+{
+    /* Don't get header from tomcat yet */
+    int headeratclient = JK_FALSE;
+
+    JK_TRACE_ENTER(l);
+
+    /* Start read all reply message */
+    while (1) {
+        int rc = 0;
+
+        /* If we set a reply timeout, check it something is available */
+        if (p->worker->reply_timeout != 0) {
+            if (ajp_is_input_event(p, p->worker->reply_timeout, l) ==
+                JK_FALSE) {
+                jk_log(l, JK_LOG_ERROR,
+                       "(%s) Timeout with waiting reply from tomcat. "
+                       "Tomcat is down, stopped or network problems.",
+                       p->worker->name);
+                if (headeratclient == JK_FALSE) {
+                    if (p->worker->recovery_opts & RECOVER_ABORT_IF_TCGETREQUEST)
+                        op->recoverable = JK_FALSE;
+                }
+                else {
+                    if (p->worker->recovery_opts & RECOVER_ABORT_IF_TCSENDHEADER)
+                        op->recoverable = JK_FALSE;
+                }
+
+                JK_TRACE_EXIT(l);
+                return JK_FALSE;
+            }
+        }
+
+        if (!ajp_connection_tcp_get_message(p, op->reply, l)) {
+            /* we just can't recover, unset recover flag */
+            if (headeratclient == JK_FALSE) {
+                jk_log(l, JK_LOG_ERROR,
+                       "(%s) Tomcat is down or refused connection. "
+                       "No response has been sent to the client (yet)",
+                       p->worker->name);
+                /*
+                 * communication with tomcat has been interrupted BEFORE
+                 * headers have been sent to the client.
+                 * DISCUSSION: As we suppose that tomcat has already started
+                 * to process the query we think it's unrecoverable (and we
+                 * should not retry or switch to another tomcat in the
+                 * cluster).
+                 */
+
+                /*
+                 * We mark it unrecoverable if recovery_opts set to RECOVER_ABORT_IF_TCGETREQUEST
+                 */
+                if (p->worker->recovery_opts & RECOVER_ABORT_IF_TCGETREQUEST)
+                    op->recoverable = JK_FALSE;
+                /*
+                 * we want to display the webservers error page, therefore
+                 * we return JK_FALSE
+                 */
+                JK_TRACE_EXIT(l);
+                return JK_FALSE;
+            }
+            else {
+                jk_log(l, JK_LOG_ERROR,
+                       "(%s) Tomcat is down or network problems. "
+                       "Part of the response has already been sent to the client",
+                       p->worker->name);
+
+                /* communication with tomcat has been interrupted AFTER
+                 * headers have been sent to the client.
+                 * headers (and maybe parts of the body) have already been
+                 * sent, therefore the response is "complete" in a sense
+                 * that nobody should append any data, especially no 500 error
+                 * page of the webserver!
+                 *
+                 * BUT if you retrun JK_TRUE you have a 200 (OK) code in your
+                 * in your apache access.log instead of a 500 (Error).
+                 * Therefore return FALSE/FALSE
+                 * return JK_TRUE;
+                 */
+
+                /*
+                 * We mark it unrecoverable if recovery_opts set to RECOVER_ABORT_IF_TCSENDHEADER
+                 */
+                if (p->worker->recovery_opts & RECOVER_ABORT_IF_TCSENDHEADER)
+                    op->recoverable = JK_FALSE;
+
+                JK_TRACE_EXIT(l);
+                return JK_FALSE;
+            }
+        }
+
+        rc = ajp_process_callback(op->reply, op->post, p, s, l);
+
+        /* no more data to be sent, fine we have finish here */
+        if (JK_AJP13_END_RESPONSE == rc) {
+            JK_TRACE_EXIT(l);
+            return JK_TRUE;
+        }
+        else if (JK_AJP13_SEND_HEADERS == rc) {
+            headeratclient = JK_TRUE;
+        }
+        else if (JK_AJP13_HAS_RESPONSE == rc) {
+            /*
+             * in upload-mode there is no second chance since
+             * we may have allready sent part of the uploaded data
+             * to Tomcat.
+             * In this case if Tomcat connection is broken we must
+             * abort request and indicate error.
+             * A possible work-around could be to store the uploaded
+             * data to file and replay for it
+             */
+            op->recoverable = JK_FALSE;
+            rc = ajp_connection_tcp_send_message(p, op->post, l);
+            if (rc < 0) {
+                jk_log(l, JK_LOG_ERROR,
+                       "(%s) Tomcat is down or network problems",
+                        p->worker->name);
+                JK_TRACE_EXIT(l);
+                return JK_FALSE;
+            }
+        }
+        else if (JK_AJP13_ERROR == rc) {
+            /*
+             * Tomcat has send invalid AJP message.
+             * Locadbalancer if present will decide if
+             * failover is possible.
+             */
+            JK_TRACE_EXIT(l);
+            return JK_SERVER_ERROR;
+        }
+        else if (JK_FATAL_ERROR == rc) {
+            /*
+             * we won't be able to gracefully recover from this so
+             * set recoverable to false and get out.
+             */
+            op->recoverable = JK_FALSE;
+            JK_TRACE_EXIT(l);
+            return JK_FALSE;
+        }
+        else if (JK_CLIENT_RD_ERROR == rc) {
+            /*
+             * Client has stop sending to us, so get out.
+             * We assume this isn't our fault, so just a normal exit.
+             */
+            JK_TRACE_EXIT(l);
+            return JK_CLIENT_RD_ERROR;
+        }
+        else if (JK_CLIENT_WR_ERROR == rc) {
+            /*
+             * Client has stop receiving to us, so get out.
+             * We assume this isn't our fault, so just a normal exit.
+             */
+            JK_TRACE_EXIT(l);
+            return JK_CLIENT_WR_ERROR;
+        }
+        else if (JK_SERVER_ERROR == rc) {
+            /*
+             * Tomcat has stop talking to us, so get out.
+             * Locadbalancer if present will decide if
+             * failover is possible.
+             */
+            JK_TRACE_EXIT(l);
+            return JK_SERVER_ERROR;
+        }
+        else if (rc < 0) {
+            JK_TRACE_EXIT(l);
+            return (JK_FALSE);  /* XXX error */
+        }
+    }
+    /* XXX: Not reached? */
+    JK_TRACE_EXIT(l);
+    return JK_FALSE;
+}
+
+/*
+ * service is now splitted in ajp_send_request and ajp_get_reply
+ * much more easier to do errors recovery
+ *
+ * We serve here the request, using AJP13/AJP14 (e->proto)
+ *
+ */
+static int JK_METHOD ajp_service(jk_endpoint_t *e,
+                                 jk_ws_service_t *s,
+                                 jk_logger_t *l, int *is_error)
+{
+    int i, err;
+    ajp_operation_t oper;
+    ajp_operation_t *op = &oper;
+    ajp_endpoint_t *p;
+
+    JK_TRACE_ENTER(l);
+
+    if (is_error)
+        *is_error = JK_HTTP_SERVER_ERROR;
+    if (!e || !e->endpoint_private || !s || !is_error) {
+        JK_LOG_NULL_PARAMS(l);
+        JK_TRACE_EXIT(l);
+        return JK_FALSE;
+    }
+
+    p = e->endpoint_private;
+    op->request = jk_b_new(&(p->pool));
+    jk_b_set_buffer_size(op->request, p->worker->max_packet_size);
+    jk_b_reset(op->request);
+
+    op->reply = jk_b_new(&(p->pool));
+    jk_b_set_buffer_size(op->reply, p->worker->max_packet_size);
+    jk_b_reset(op->reply);
+
+    op->post = jk_b_new(&(p->pool));
+    jk_b_set_buffer_size(op->post, p->worker->max_packet_size);
+    jk_b_reset(op->post);
+
+    op->recoverable = JK_TRUE;
+    op->uploadfd = -1;      /* not yet used, later ;) */
+
+    p->left_bytes_to_send = s->content_length;
+    p->reuse = JK_FALSE;
+
+    s->secret = p->worker->secret;
+
+    /*
+     * We get here initial request (in reqmsg)
+     */
+    if (!ajp_marshal_into_msgb(op->request, s, l, p)) {
+        *is_error = JK_REQUEST_TOO_LARGE;
+        jk_log(l, JK_LOG_INFO,
+                "Creating AJP message failed, "
+                "without recovery");
+        JK_TRACE_EXIT(l);
+        return JK_CLIENT_ERROR;
+    }
+
+    if (JK_IS_DEBUG_LEVEL(l)) {
+        jk_log(l, JK_LOG_DEBUG, "processing %s with %d retries",
+               p->worker->name, p->worker->worker.retries);
+    }
+    /*
+     * JK_RETRIES could be replaced by the number of workers in
+     * a load-balancing configuration
+     */
+    for (i = 0; i < p->worker->worker.retries; i++) {
+        /*
+         * We're using reqmsg which hold initial request
+         * if Tomcat is stopped or restarted, we will pass reqmsg
+         * to next valid tomcat.
+         */
+        err = ajp_send_request(e, s, l, p, op);
+        if (err == JK_TRUE) {
+
+            /* If we have the no recoverable error, it's probably because
+             * the sender (browser) stopped sending data before the end
+             * (certainly in a big post)
+             */
+            if (!op->recoverable) {
+                *is_error = JK_HTTP_SERVER_ERROR;
+                jk_log(l, JK_LOG_ERROR,
+                       "(%s) sending request to tomcat failed "
+                       "without recovery in send loop %d",
+                       p->worker->name, i);
+                JK_TRACE_EXIT(l);
+                return JK_FALSE;
+            }
+
+            /* Up to there we can recover */
+
+            err = ajp_get_reply(e, s, l, p, op);
+            if (err == JK_TRUE) {
+                *is_error = JK_HTTP_OK;
+                /* Done with the request */
+                JK_TRACE_EXIT(l);
+                return JK_TRUE;
+            }
+
+            if (err == JK_CLIENT_RD_ERROR) {
+                *is_error = JK_HTTP_BAD_REQUEST;
+                if (p->worker->recovery_opts & RECOVER_ABORT_IF_CLIENTERROR) {
+                    /* Mark the endpoint for shutdown */
+                    p->reuse = JK_FALSE;
+                }
+                jk_log(l, JK_LOG_INFO,
+                       "(%s) request failed, "
+                       "because of client read error "
+                       "without recovery in send loop attempt=%d",
+                       p->worker->name, i);
+                JK_TRACE_EXIT(l);
+                return JK_CLIENT_ERROR;
+            }
+            else if (err == JK_CLIENT_WR_ERROR) {
+                /* XXX: Is this correct to log this as 200? */
+                *is_error = JK_HTTP_OK;
+                if (p->worker->recovery_opts & RECOVER_ABORT_IF_CLIENTERROR) {
+                    /* Mark the endpoint for shutdown */
+                    p->reuse = JK_FALSE;
+                }
+                jk_log(l, JK_LOG_INFO,
+                       "(%s) request failed, "
+                       "because of client write error "
+                       "without recovery in send loop attempt=%d",
+                       p->worker->name, i);
+                JK_TRACE_EXIT(l);
+                return JK_CLIENT_ERROR;
+            }
+            else if (err == JK_SERVER_ERROR) {
+                *is_error = JK_HTTP_SERVER_ERROR;
+                jk_log(l, JK_LOG_INFO,
+                       "(%s) request failed, "
+                       "because of server error "
+                       "without recovery in send loop attempt=%d",
+                       p->worker->name, i);
+                JK_TRACE_EXIT(l);
+                return JK_SERVER_ERROR;
+            }
+            else {
+                /* if we can't get reply, check if no recover flag was set
+                 * if is_recoverable_error is cleared, we have started
+                 * receiving upload data and we must consider that
+                 * operation is no more recoverable
+                 */
+                if (!op->recoverable) {
+                    *is_error = JK_HTTP_BAD_GATEWAY;
+                    jk_log(l, JK_LOG_ERROR,
+                           "(%s) receiving reply from tomcat failed "
+                           "without recovery in send loop attempt=%d",
+                           p->worker->name, i);
+                    JK_TRACE_EXIT(l);
+                    return JK_FALSE;
+                }
+                jk_log(l, JK_LOG_INFO,
+                       "(%s) receiving from tomcat failed, "
+                       "recoverable operation attempt=%d",
+                       p->worker->name, i);
+                /* Check for custom retries */
+                if (i >= JK_RETRIES) {
+                    jk_sleep(JK_SLEEP_DEF);
+                }
+            }
+        }
+        if (err == JK_CLIENT_RD_ERROR) {
+            *is_error = JK_HTTP_BAD_REQUEST;
+            if (p->worker->recovery_opts & RECOVER_ABORT_IF_CLIENTERROR) {
+                /* Mark the endpoint for shutdown */
+                p->reuse = JK_FALSE;
+            }
+            jk_log(l, JK_LOG_INFO,
+                   "(%s) sending request to tomcat failed, "
+                   "because of client read error "
+                   "without recovery in send loop attempt=%d",
+                   p->worker->name, i);
+            JK_TRACE_EXIT(l);
+            return JK_CLIENT_ERROR;
+        }
+        else if (err == JK_CLIENT_WR_ERROR) {
+            *is_error = JK_HTTP_OK;
+            if (p->worker->recovery_opts & RECOVER_ABORT_IF_CLIENTERROR) {
+                /* Mark the endpoint for shutdown */
+                p->reuse = JK_FALSE;
+            }
+            jk_log(l, JK_LOG_INFO,
+                   "(%s) sending request to tomcat failed, "
+                   "because of client write error "
+                   "without recovery in send loop attempt=%d",
+                   p->worker->name, i);
+            JK_TRACE_EXIT(l);
+            return JK_CLIENT_ERROR;
+        }
+        else {
+            jk_log(l, JK_LOG_INFO,
+                   "(%s) sending request to tomcat failed,  "
+                   "recoverable operation attempt=%d",
+                   p->worker->name, i + 1);
+        }
+        /* Get another connection from the pool and try again.
+         * Note: All sockets are probably closed already.
+         */
+        ajp_next_connection(p, l);
+    }
+    *is_error = JK_HTTP_SERVER_BUSY;
+    /* Log the error only once per failed request. */
+    jk_log(l, JK_LOG_ERROR,
+           "(%s) Connecting to tomcat failed. Tomcat is probably not started "
+           "or is listening on the wrong port",
+           p->worker->name);
+
+    JK_TRACE_EXIT(l);
+    return JK_FALSE;
+}
+
+/*
+ * Validate the worker (ajp13/ajp14)
+ */
+
+int ajp_validate(jk_worker_t *pThis,
+                 jk_map_t *props,
+                 jk_worker_env_t *we, jk_logger_t *l, int proto)
+{
+    int port;
+    const char *host;
+
+    JK_TRACE_ENTER(l);
+
+    if (proto == AJP13_PROTO) {
+        port = AJP13_DEF_PORT;
+        host = AJP13_DEF_HOST;
+    }
+    else if (proto == AJP14_PROTO) {
+        port = AJP14_DEF_PORT;
+        host = AJP14_DEF_HOST;
+    }
+    else {
+        jk_log(l, JK_LOG_ERROR,
+               "unknown protocol %d", proto);
+        JK_TRACE_EXIT(l);
+        return JK_FALSE;
+    }
+
+    if (pThis && pThis->worker_private) {
+        ajp_worker_t *p = pThis->worker_private;
+        p->port = jk_get_worker_port(props, p->name, port);
+        p->host = jk_get_worker_host(props, p->name, host);
+
+        if (JK_IS_DEBUG_LEVEL(l))
+            jk_log(l, JK_LOG_DEBUG,
+                   "worker %s contact is '%s:%d'",
+                   p->name, p->host, p->port);
+
+        if (p->port > 1024) {
+            if (jk_resolve(p->host, p->port, &p->worker_inet_addr)) {
+                JK_TRACE_EXIT(l);
+                return JK_TRUE;
+            }
+            jk_log(l, JK_LOG_ERROR,
+                   "can't resolve tomcat address %s", host);
+        }
+        jk_log(l, JK_LOG_ERROR,
+               "invalid host and port %s %d",
+               ((p->host == NULL) ? "NULL" : p->host), p->port);
+    }
+    else {
+        JK_LOG_NULL_PARAMS(l);
+    }
+
+    JK_TRACE_EXIT(l);
+    return JK_FALSE;
+}
+
+static int ajp_create_endpoint_cache(ajp_worker_t *p, int proto, jk_logger_t *l)
+{
+    unsigned int i;
+    time_t now = time(NULL);
+
+    JK_TRACE_ENTER(l);
+    p->ep_cache = (ajp_endpoint_t **)calloc(1, sizeof(ajp_endpoint_t *) *
+                                            p->ep_cache_sz);
+    if (!p->ep_cache) {
+        JK_TRACE_EXIT(l);
+        return JK_FALSE;
+    }
+    if (JK_IS_DEBUG_LEVEL(l))
+        jk_log(l, JK_LOG_DEBUG,
+                "setting connection pool size to %u with min %u",
+                p->ep_cache_sz, p->ep_mincache_sz);
+        for (i = 0; i < p->ep_cache_sz; i++) {
+            p->ep_cache[i] = (ajp_endpoint_t *)calloc(1, sizeof(ajp_endpoint_t));
+            if (!p->ep_cache[i]) {
+                jk_log(l, JK_LOG_ERROR,
+                        "allocating endpoint slot %d errno=%d",
+                        i, errno);
+                JK_TRACE_EXIT(l);
+                return JK_FALSE;
+            }
+            p->ep_cache[i]->sd = JK_INVALID_SOCKET;
+            p->ep_cache[i]->reuse = JK_FALSE;
+            p->ep_cache[i]->last_access = now;
+            jk_open_pool(&(p->ep_cache[i]->pool), p->ep_cache[i]->buf,
+                         sizeof(p->ep_cache[i]->buf));
+            p->ep_cache[i]->worker = p;
+            p->ep_cache[i]->endpoint.endpoint_private = p->ep_cache[i];
+            p->ep_cache[i]->proto = proto;
+            p->ep_cache[i]->endpoint.service = ajp_service;
+            p->ep_cache[i]->endpoint.done    = ajp_done;
+        }
+
+    JK_TRACE_EXIT(l);
+    return JK_TRUE;
+}
+
+int ajp_init(jk_worker_t *pThis,
+             jk_map_t *props, jk_worker_env_t *we, jk_logger_t *l, int proto)
+{
+    int rc = JK_FALSE;
+    int cache;
+    /*
+     * start the connection cache
+     */
+    JK_TRACE_ENTER(l);
+
+    cache = jk_get_worker_def_cache_size(proto);
+
+    if (pThis && pThis->worker_private) {
+        ajp_worker_t *p = pThis->worker_private;
+        p->ep_cache_sz = jk_get_worker_cache_size(props, p->name, cache);
+        p->ep_mincache_sz = jk_get_worker_cache_size_min(props, p->name,
+                                                         cache / 2);
+        p->socket_timeout =
+            jk_get_worker_socket_timeout(props, p->name, AJP_DEF_SOCKET_TIMEOUT);
+
+        p->socket_buf =
+            jk_get_worker_socket_buffer(props, p->name, 8192);
+
+        p->keepalive =
+            jk_get_worker_socket_keepalive(props, p->name, JK_FALSE);
+
+        p->cache_timeout =
+            jk_get_worker_cache_timeout(props, p->name,
+                                        AJP_DEF_CACHE_TIMEOUT);
+
+        p->connect_timeout =
+            jk_get_worker_connect_timeout(props, p->name,
+                                          AJP_DEF_CONNECT_TIMEOUT);
+
+        p->reply_timeout =
+            jk_get_worker_reply_timeout(props, p->name,
+                                        AJP_DEF_REPLY_TIMEOUT);
+
+        p->prepost_timeout =
+            jk_get_worker_prepost_timeout(props, p->name,
+                                          AJP_DEF_PREPOST_TIMEOUT);
+
+        p->recovery_opts =
+            jk_get_worker_recovery_opts(props, p->name,
+                                        AJP_DEF_RECOVERY_OPTS);
+        p->max_packet_size =
+            jk_get_max_packet_size(props, p->name);
+
+        pThis->retries =
+            jk_get_worker_retries(props, p->name,
+                                  JK_RETRIES);
+        if (pThis->retries < 1) {
+            jk_log(l, JK_LOG_INFO,
+                   "number of retries must be grater then 1. Setting to default=%d",
+                   JK_RETRIES);
+            pThis->retries = JK_RETRIES;
+        }
+
+        if (JK_IS_DEBUG_LEVEL(l)) {
+
+            jk_log(l, JK_LOG_DEBUG,
+                   "setting endpoint options:",
+                   p->keepalive);
+            jk_log(l, JK_LOG_DEBUG,
+                   "keepalive:        %d",
+                   p->keepalive);
+
+            jk_log(l, JK_LOG_DEBUG,
+                   "timeout:          %d",
+                   p->socket_timeout);
+
+            jk_log(l, JK_LOG_DEBUG,
+                   "buffer size:      %d",
+                   p->socket_buf);
+
+            jk_log(l, JK_LOG_DEBUG,
+                   "pool timeout:     %d",
+                   p->cache_timeout);
+
+            jk_log(l, JK_LOG_DEBUG,
+                   "connect timeout:  %d",
+                   p->connect_timeout);
+
+            jk_log(l, JK_LOG_DEBUG,
+                   "reply timeout:    %d",
+                   p->reply_timeout);
+
+            jk_log(l, JK_LOG_DEBUG,
+                   "prepost timeout:  %d",
+                   p->prepost_timeout);
+
+            jk_log(l, JK_LOG_DEBUG,
+                   "recovery options: %d",
+                   p->recovery_opts);
+
+            jk_log(l, JK_LOG_DEBUG,
+                   "retries:          %d",
+                    pThis->retries);
+
+            jk_log(l, JK_LOG_DEBUG,
+                   "max packet size:  %d",
+                    p->max_packet_size);
+        }
+        /*
+         *  Need to initialize secret here since we could return from inside
+         *  of the following loop
+         */
+
+        p->secret = jk_get_worker_secret(props, p->name);
+        /* Initialize cache slots */
+        JK_INIT_CS(&(p->cs), rc);
+        if (!rc) {
+            jk_log(l, JK_LOG_ERROR,
+                   "creating thread lock errno=%d",
+                   errno);
+            JK_TRACE_EXIT(l);
+            return JK_FALSE;
+        }
+        if (!ajp_create_endpoint_cache(p, proto, l)) {
+            jk_log(l, JK_LOG_ERROR,
+                   "allocating connection pool of size %u",
+                   p->ep_cache_sz);
+            JK_TRACE_EXIT(l);
+            return JK_FALSE;
+        }
+        rc = JK_TRUE;
+    }
+    else {
+        JK_LOG_NULL_PARAMS(l);
+    }
+
+    JK_TRACE_EXIT(l);
+    return rc;
+}
+
+int ajp_destroy(jk_worker_t **pThis, jk_logger_t *l, int proto)
+{
+    JK_TRACE_ENTER(l);
+
+    if (pThis && *pThis && (*pThis)->worker_private) {
+        unsigned int i;
+        ajp_worker_t *aw = (*pThis)->worker_private;
+
+        if (JK_IS_DEBUG_LEVEL(l))
+            jk_log(l, JK_LOG_DEBUG,
+                   "up to %u endpoints to close",
+                   aw->ep_cache_sz);
+
+        for (i = 0; i < aw->ep_cache_sz; i++) {
+            if (aw->ep_cache[i])
+                ajp_close_endpoint(aw->ep_cache[i], l);
+        }
+        free(aw->ep_cache);
+        JK_DELETE_CS(&(aw->cs), i);
+
+        if (aw->login) {
+             /* take care of removing previously allocated data */
+            if (aw->login->servlet_engine_name)
+                free(aw->login->servlet_engine_name);
+
+            free(aw->login);
+            aw->login = NULL;
+        }
+
+        free(aw);
+        JK_TRACE_EXIT(l);
+        return JK_TRUE;
+    }
+
+    JK_LOG_NULL_PARAMS(l);
+    JK_TRACE_EXIT(l);
+    return JK_FALSE;
+}
+
+int JK_METHOD ajp_done(jk_endpoint_t **e, jk_logger_t *l)
+{
+    JK_TRACE_ENTER(l);
+    if (e && *e && (*e)->endpoint_private) {
+        ajp_endpoint_t *p = (*e)->endpoint_private;
+        int rc;
+        ajp_worker_t *w = p->worker;
+
+        JK_ENTER_CS(&w->cs, rc);
+        if (rc) {
+            int i;
+            jk_sock_t sock = JK_INVALID_SOCKET;
+
+            if (p->sd > 0 && !p->reuse) {
+                sock  = p->sd;
+                p->sd = JK_INVALID_SOCKET;
+            }
+            for(i = w->ep_cache_sz - 1; i >= 0; i--) {
+                if (w->ep_cache[i] == NULL) {
+                    w->ep_cache[i] = p;
+                    break;
+                }
+            }
+            ajp_reset_endpoint(p, l);
+            *e = NULL;
+            /* set last_access only if needed */
+            if (w->cache_timeout > 0)
+                p->last_access = time(NULL);
+            JK_LEAVE_CS(&w->cs, rc);
+            if (IS_VALID_SOCKET(sock))
+                jk_shutdown_socket(sock);
+            if (i >= 0) {
+                if (JK_IS_DEBUG_LEVEL(l))
+                    jk_log(l, JK_LOG_DEBUG,
+                            "recycling connection pool slot=%u for worker %s",
+                            i, p->worker->name);
+                JK_TRACE_EXIT(l);
+                return JK_TRUE;
+            }
+            /* XXX: This should never hapen because
+             * there is always free empty cache slot
+             */
+            jk_log(l, JK_LOG_ERROR,
+                    "could not find empty connection pool slot from %u for worker %s",
+                    w->ep_cache_sz, w->name);
+            JK_TRACE_EXIT(l);
+            return JK_FALSE;
+        }
+
+        jk_log(l, JK_LOG_ERROR,
+               "locking thread with errno=%d", errno);
+        JK_TRACE_EXIT(l);
+        return JK_FALSE;
+    }
+
+    JK_LOG_NULL_PARAMS(l);
+    JK_TRACE_EXIT(l);
+    return JK_FALSE;
+}
+
+int ajp_get_endpoint(jk_worker_t *pThis,
+                     jk_endpoint_t **je, jk_logger_t *l, int proto)
+{
+    JK_TRACE_ENTER(l);
+
+    if (pThis && pThis->worker_private && je) {
+        ajp_worker_t *aw = pThis->worker_private;
+        ajp_endpoint_t *ae = NULL;
+        time_t now = 0;
+        int rc;
+        /* Obtain current time only if needed */
+        if (aw->cache_timeout > 0)
+            now = time(NULL);
+        *je = NULL;
+
+        JK_ENTER_CS(&aw->cs, rc);
+        if (rc) {
+            unsigned int slot;
+            for (slot = 0; slot < aw->ep_cache_sz; slot++) {
+                if (aw->ep_cache[slot]) {
+                    ae = aw->ep_cache[slot];
+                    aw->ep_cache[slot] = NULL;
+                    break;
+                }
+            }
+            if (ae) {
+                ae->last_access = now;
+                *je = &ae->endpoint;
+                JK_LEAVE_CS(&aw->cs, rc);
+                if (JK_IS_DEBUG_LEVEL(l))
+                    jk_log(l, JK_LOG_DEBUG,
+                           "acquired connection pool slot=%u",
+                           slot);
+                JK_TRACE_EXIT(l);
+                return JK_TRUE;
+            }
+            else {
+                jk_log(l, JK_LOG_WARNING,
+                        "Unable to get the free endpoint for worker %s from %u slots",
+                        aw->name, aw->ep_cache_sz);
+            }
+            JK_LEAVE_CS(&aw->cs, rc);
+        }
+        else {
+           jk_log(l, JK_LOG_ERROR,
+                  "locking thread with errno=%d",
+                  errno);
+            JK_TRACE_EXIT(l);
+            return JK_FALSE;
+
+        }
+        jk_log(l, JK_LOG_INFO,
+               "can't find free endpoint");
+    }
+    else {
+        JK_LOG_NULL_PARAMS(l);
+    }
+
+    JK_TRACE_EXIT(l);
+    return JK_FALSE;
+}
+
+int JK_METHOD ajp_maintain(jk_worker_t *pThis, time_t now, jk_logger_t *l)
+{
+    JK_TRACE_ENTER(l);
+
+    if (pThis && pThis->worker_private) {
+        ajp_worker_t *aw = pThis->worker_private;
+        int rc;
+        /* Obtain current time only if needed */
+        if (aw->cache_timeout < 1) {
+            /* Nothing to do. */
+            JK_TRACE_EXIT(l);
+            return JK_TRUE;
+        }
+        JK_ENTER_CS(&aw->cs, rc);
+        if (rc) {
+            unsigned int i, n = 0, cnt = 0;
+            /* Count opended slots */
+            for (i = 0; i < aw->ep_cache_sz; i++) {
+                if (aw->ep_cache[i] && IS_VALID_SOCKET(aw->ep_cache[i]->sd))
+                    cnt++;
+            }
+            /* Handle worker cache and recycle timeouts */
+            for (i = 0; i < aw->ep_cache_sz; i++) {
+                /* Skip the closed sockets */
+                if (aw->ep_cache[i] && IS_VALID_SOCKET(aw->ep_cache[i]->sd)) {
+                    int elapsed = (int)difftime(now, aw->ep_cache[i]->last_access);
+                    if ((aw->cache_timeout > 0) && (elapsed > aw->cache_timeout)) {
+                        time_t rt = 0;
+                        n++;
+                        if (JK_IS_DEBUG_LEVEL(l))
+                            rt = time(NULL);
+                        aw->ep_cache[i]->reuse = JK_FALSE;
+                        ajp_reset_endpoint(aw->ep_cache[i], l);
+                        if (JK_IS_DEBUG_LEVEL(l))
+                            jk_log(l, JK_LOG_DEBUG,
+                                    "cleaning pool slot=%u elapsed %d in %d",
+                                    i, elapsed, (int)(difftime(time(NULL), rt)));
+                    }
+                }
+                if ((cnt - n) <= aw->ep_mincache_sz) {
+                    if (JK_IS_DEBUG_LEVEL(l)) {
+                        jk_log(l, JK_LOG_DEBUG,
+                        "reached pool min size %u from %u cache slots",
+                        aw->ep_mincache_sz, aw->ep_cache_sz);
+                    }
+                    break;
+                }
+            }
+            if (JK_IS_DEBUG_LEVEL(l))
+                jk_log(l, JK_LOG_DEBUG,
+                        "recycled %u sockets in %d seconds from %u pool slots",
+                        n, (int)(difftime(time(NULL), now)),
+                        aw->ep_cache_sz);
+            JK_LEAVE_CS(&aw->cs, rc);
+            JK_TRACE_EXIT(l);
+            return JK_TRUE;
+        }
+        else {
+           jk_log(l, JK_LOG_ERROR,
+                  "locking thread with errno=%d",
+                  errno);
+            JK_TRACE_EXIT(l);
+            return JK_FALSE;
+
+        }
+    }
+    else {
+        JK_LOG_NULL_PARAMS(l);
+    }
+
+    JK_TRACE_EXIT(l);
+    return JK_FALSE;
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_ajp_common.h
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_ajp_common.h	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_ajp_common.h	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,366 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.
+ */
+
+/***************************************************************************
+ * Description: common stuff for bi-directional protocol ajp13/ajp14.      *
+ * Author:      Gal Shachor <shachor at il.ibm.com>                           *
+ * Author:      Henri Gomez <hgomez at apache.org>                            *
+ * Version:     $Revision: 439553 $                                          *
+ ***************************************************************************/
+
+#ifndef JK_AJP_COMMON_H
+#define JK_AJP_COMMON_H
+
+#include "jk_service.h"
+#include "jk_msg_buff.h"
+#include "jk_mt.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif                          /* __cplusplus */
+
+/*
+ * Conditional request attributes
+ *
+ */
+#define SC_A_CONTEXT            (unsigned char)1
+#define SC_A_SERVLET_PATH       (unsigned char)2
+#define SC_A_REMOTE_USER        (unsigned char)3
+#define SC_A_AUTH_TYPE          (unsigned char)4
+#define SC_A_QUERY_STRING       (unsigned char)5
+#define SC_A_JVM_ROUTE          (unsigned char)6
+#define SC_A_SSL_CERT           (unsigned char)7
+#define SC_A_SSL_CIPHER         (unsigned char)8
+#define SC_A_SSL_SESSION        (unsigned char)9
+#define SC_A_REQ_ATTRIBUTE      (unsigned char)10
+#define SC_A_SSL_KEY_SIZE       (unsigned char)11       /* only in if JkOptions +ForwardKeySize */
+#define SC_A_SECRET             (unsigned char)12
+#define SC_A_STORED_METHOD      (unsigned char)13
+#define SC_A_ARE_DONE           (unsigned char)0xFF
+
+/*
+ * Request methods, coded as numbers instead of strings.
+ * The list of methods was taken from Section 5.1.1 of RFC 2616,
+ * RFC 2518, the ACL IETF draft, and the DeltaV IESG Proposed Standard.
+ *          Method        = "OPTIONS"
+ *                        | "GET"
+ *                        | "HEAD"
+ *                        | "POST"
+ *                        | "PUT"
+ *                        | "DELETE"
+ *                        | "TRACE"
+ *                        | "PROPFIND"
+ *                        | "PROPPATCH"
+ *                        | "MKCOL"
+ *                        | "COPY"
+ *                        | "MOVE"
+ *                        | "LOCK"
+ *                        | "UNLOCK"
+ *                        | "ACL"
+ *                        | "REPORT"
+ *                        | "VERSION-CONTROL"
+ *                        | "CHECKIN"
+ *                        | "CHECKOUT"
+ *                        | "UNCHECKOUT"
+ *                        | "SEARCH"
+ *                        | "MKWORKSPACE"
+ *                        | "UPDATE"
+ *                        | "LABEL"
+ *                        | "MERGE"
+ *                        | "BASELINE-CONTROL"
+ *                        | "MKACTIVITY"
+ *
+ */
+#define SC_M_OPTIONS            (unsigned char)1
+#define SC_M_GET                (unsigned char)2
+#define SC_M_HEAD               (unsigned char)3
+#define SC_M_POST               (unsigned char)4
+#define SC_M_PUT                (unsigned char)5
+#define SC_M_DELETE             (unsigned char)6
+#define SC_M_TRACE              (unsigned char)7
+#define SC_M_PROPFIND           (unsigned char)8
+#define SC_M_PROPPATCH          (unsigned char)9
+#define SC_M_MKCOL              (unsigned char)10
+#define SC_M_COPY               (unsigned char)11
+#define SC_M_MOVE               (unsigned char)12
+#define SC_M_LOCK               (unsigned char)13
+#define SC_M_UNLOCK             (unsigned char)14
+#define SC_M_ACL                (unsigned char)15
+#define SC_M_REPORT             (unsigned char)16
+#define SC_M_VERSION_CONTROL    (unsigned char)17
+#define SC_M_CHECKIN            (unsigned char)18
+#define SC_M_CHECKOUT           (unsigned char)19
+#define SC_M_UNCHECKOUT         (unsigned char)20
+#define SC_M_SEARCH             (unsigned char)21
+#define SC_M_MKWORKSPACE        (unsigned char)22
+#define SC_M_UPDATE             (unsigned char)23
+#define SC_M_LABEL              (unsigned char)24
+#define SC_M_MERGE              (unsigned char)25
+#define SC_M_BASELINE_CONTROL   (unsigned char)26
+#define SC_M_MKACTIVITY         (unsigned char)27
+#define SC_M_JK_STORED          (unsigned char)0xFF
+
+/*
+ * Frequent request headers, these headers are coded as numbers
+ * instead of strings.
+ *
+ * Accept
+ * Accept-Charset
+ * Accept-Encoding
+ * Accept-Language
+ * Authorization
+ * Connection
+ * Content-Type
+ * Content-Length
+ * Cookie
+ * Cookie2
+ * Host
+ * Pragma
+ * Referer
+ * User-Agent
+ *
+ */
+
+#define SC_ACCEPT               (unsigned short)0xA001
+#define SC_ACCEPT_CHARSET       (unsigned short)0xA002
+#define SC_ACCEPT_ENCODING      (unsigned short)0xA003
+#define SC_ACCEPT_LANGUAGE      (unsigned short)0xA004
+#define SC_AUTHORIZATION        (unsigned short)0xA005
+#define SC_CONNECTION           (unsigned short)0xA006
+#define SC_CONTENT_TYPE         (unsigned short)0xA007
+#define SC_CONTENT_LENGTH       (unsigned short)0xA008
+#define SC_COOKIE               (unsigned short)0xA009
+#define SC_COOKIE2              (unsigned short)0xA00A
+#define SC_HOST                 (unsigned short)0xA00B
+#define SC_PRAGMA               (unsigned short)0xA00C
+#define SC_REFERER              (unsigned short)0xA00D
+#define SC_USER_AGENT           (unsigned short)0xA00E
+
+/*
+ * Frequent response headers, these headers are coded as numbers
+ * instead of strings.
+ *
+ * Content-Type
+ * Content-Language
+ * Content-Length
+ * Date
+ * Last-Modified
+ * Location
+ * Set-Cookie
+ * Servlet-Engine
+ * Status
+ * WWW-Authenticate
+ *
+ */
+
+#define SC_RESP_CONTENT_TYPE        (unsigned short)0xA001
+#define SC_RESP_CONTENT_LANGUAGE    (unsigned short)0xA002
+#define SC_RESP_CONTENT_LENGTH      (unsigned short)0xA003
+#define SC_RESP_DATE                (unsigned short)0xA004
+#define SC_RESP_LAST_MODIFIED       (unsigned short)0xA005
+#define SC_RESP_LOCATION            (unsigned short)0xA006
+#define SC_RESP_SET_COOKIE          (unsigned short)0xA007
+#define SC_RESP_SET_COOKIE2         (unsigned short)0xA008
+#define SC_RESP_SERVLET_ENGINE      (unsigned short)0xA009
+#define SC_RESP_STATUS              (unsigned short)0xA00A
+#define SC_RESP_WWW_AUTHENTICATE    (unsigned short)0xA00B
+#define SC_RES_HEADERS_NUM          11
+
+/*
+ * AJP13/AJP14 use same message structure
+ */
+
+#define AJP_DEF_RETRY_ATTEMPTS    (1)
+
+#define AJP_HEADER_LEN            (4)
+#define AJP_HEADER_SZ_LEN         (2)
+#define CHUNK_BUFFER_PAD          (12)
+#define AJP_DEF_CACHE_TIMEOUT     (0)
+#define AJP_DEF_CONNECT_TIMEOUT   (0)   /* NO CONNECTION TIMEOUT => NO CPING/CPONG */
+#define AJP_DEF_REPLY_TIMEOUT     (0)   /* NO REPLY TIMEOUT                        */
+#define AJP_DEF_PREPOST_TIMEOUT   (0)   /* NO PREPOST TIMEOUT => NO CPING/CPONG    */
+#define AJP_DEF_RECOVERY_OPTS     (0)   /* NO RECOVERY / NO    */
+#define AJP_DEF_SOCKET_TIMEOUT    (-1)  /* No timeout */
+
+#define RECOVER_ABORT_IF_TCGETREQUEST    0x0001 /* DONT RECOVER IF TOMCAT FAIL AFTER RECEIVING REQUEST */
+#define RECOVER_ABORT_IF_TCSENDHEADER    0x0002 /* DONT RECOVER IF TOMCAT FAIL AFTER SENDING HEADERS */
+#define RECOVER_ABORT_IF_CLIENTERROR     0x0004 /* CLOSE THE SOCKET IN CASE OF CLIENT ERROR */
+
+
+
+struct jk_res_data
+{
+    int status;
+#ifdef AS400
+    char *msg;
+#else
+    const char *msg;
+#endif
+    unsigned num_headers;
+    char **header_names;
+    char **header_values;
+};
+typedef struct jk_res_data jk_res_data_t;
+
+#include "jk_ajp14.h"
+
+struct ajp_operation;
+typedef struct ajp_operation ajp_operation_t;
+
+struct ajp_endpoint;
+typedef struct ajp_endpoint ajp_endpoint_t;
+
+struct ajp_worker;
+typedef struct ajp_worker ajp_worker_t;
+
+struct ajp_worker
+{
+    struct sockaddr_in worker_inet_addr;    /* Contains host and port */
+    unsigned connect_retry_attempts;
+    const char *name;
+    const char *host;
+    int port;
+    /*
+     * Open connections cache...
+     *
+     * 1. Critical section object to protect the cache.
+     * 2. Cache size.
+     * 3. An array of "open" endpoints.
+     */
+    JK_CRIT_SEC cs;
+    unsigned int ep_cache_sz;
+    unsigned int ep_mincache_sz;
+    unsigned int ep_maxcache_sz;
+    ajp_endpoint_t **ep_cache;
+
+    int proto;              /* PROTOCOL USED AJP13/AJP14 */
+
+    jk_login_service_t *login;
+
+    /* Weak secret similar with ajp12, used in ajp13 */
+    const char *secret;
+
+    jk_worker_t worker;
+
+    /*
+     * Post physical connect handler.
+     * AJP14 will set here its login handler
+     */
+    int (*logon) (ajp_endpoint_t * ae, jk_logger_t *l);
+
+    /*
+     * Handle Socket Timeouts
+     */
+    int socket_timeout;
+    int keepalive;
+    int socket_buf;
+    /*
+     * Handle Cache Timeouts
+     */
+    int cache_timeout;
+
+    /*
+     * Handle Connection/Reply Timeouts
+     */
+    int connect_timeout;   /* connect cping/cpong delay in ms (0 means disabled)  */
+    int reply_timeout;     /* reply timeout delay in ms (0 means disabled) */
+    int prepost_timeout;   /* before sending a request cping/cpong timeout delay in ms (0 means disabled) */
+
+    /*
+     * Recovery option
+     */
+    unsigned int recovery_opts; /* Set the recovery option */
+    
+    unsigned int max_packet_size;  /*  Maximum AJP Packet size */
+};
+
+
+/*
+ * endpoint, the remote connector which does the work
+ */
+struct ajp_endpoint
+{
+    ajp_worker_t *worker;
+
+    jk_pool_t pool;
+    jk_pool_atom_t buf[BIG_POOL_SIZE];
+
+    int proto;              /* PROTOCOL USED AJP13/AJP14 */
+
+    jk_sock_t sd;
+    int reuse;
+
+    jk_endpoint_t endpoint;
+
+    unsigned int left_bytes_to_send;
+
+    /* time of the last request
+       handled by this endpoint */
+    time_t last_access;
+    int last_errno;
+};
+
+/*
+ * little struct to avoid multiples ptr passing
+ * this struct is ready to hold upload file fd
+ * to add upload persistant storage
+ */
+struct ajp_operation
+{
+    jk_msg_buf_t *request;  /* original request storage */
+    jk_msg_buf_t *reply;    /* reply storage (chuncked by ajp13 */
+    jk_msg_buf_t *post;     /* small post data storage area */
+    int uploadfd;           /* future persistant storage id */
+    int recoverable;        /* if exchange could be conducted on another TC */
+};
+
+/*
+ * Functions
+ */
+
+
+int ajp_validate(jk_worker_t *pThis,
+                 jk_map_t *props,
+                 jk_worker_env_t *we, jk_logger_t *l, int proto);
+
+int ajp_init(jk_worker_t *pThis,
+             jk_map_t *props,
+             jk_worker_env_t *we, jk_logger_t *l, int proto);
+
+int ajp_destroy(jk_worker_t **pThis, jk_logger_t *l, int proto);
+
+int JK_METHOD ajp_done(jk_endpoint_t **e, jk_logger_t *l);
+
+int ajp_get_endpoint(jk_worker_t *pThis,
+                     jk_endpoint_t **pend, jk_logger_t *l, int proto);
+
+int ajp_connect_to_endpoint(ajp_endpoint_t * ae, jk_logger_t *l);
+
+void ajp_close_endpoint(ajp_endpoint_t * ae, jk_logger_t *l);
+
+int ajp_connection_tcp_send_message(ajp_endpoint_t * ae,
+                                    jk_msg_buf_t *msg, jk_logger_t *l);
+
+int ajp_connection_tcp_get_message(ajp_endpoint_t * ae,
+                                   jk_msg_buf_t *msg, jk_logger_t *l);
+
+int JK_METHOD ajp_maintain(jk_worker_t *pThis, time_t now, jk_logger_t *l);
+
+#ifdef __cplusplus
+}
+#endif                          /* __cplusplus */
+#endif                          /* JK_AJP_COMMON_H */

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_connect.c
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_connect.c	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_connect.c	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,671 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.
+ */
+
+/*
+ * Description: Socket/Naming manipulation functions
+ * Based on:    Various Jserv files
+ */
+/**
+ * @package jk_connect
+ * @author      Gal Shachor <shachor at il.ibm.com>
+ * @author      Mladen Turk <mturk at apache.org>
+ * @version     $Revision: 440792 $
+ */
+
+
+#include "jk_connect.h"
+#include "jk_util.h"
+
+#ifdef HAVE_APR
+#include "apr_network_io.h"
+#include "apr_errno.h"
+#include "apr_general.h"
+#include "apr_pools.h"
+static apr_pool_t *jk_apr_pool = NULL;
+#endif
+
+#ifdef HAVE_SYS_FILIO_H
+/* FIONREAD on Solaris et al. */
+#include <sys/filio.h>
+#endif
+
+#if defined(WIN32) || (defined(NETWARE) && defined(__NOVELL_LIBC__))
+#define JK_IS_SOCKET_ERROR(x) ((x) == SOCKET_ERROR)
+#define JK_GET_SOCKET_ERRNO() errno = WSAGetLastError() - WSABASEERR
+#else
+#define JK_IS_SOCKET_ERROR(x) ((x) == -1)
+#define JK_GET_SOCKET_ERRNO() ((void)0)
+#endif /* WIN32 */
+
+/* our compiler cant deal with char* <-> const char* ... */
+#if defined(NETWARE) && !defined(__NOVELL_LIBC__)
+typedef char* SET_TYPE;
+#else
+typedef const char* SET_TYPE;
+#endif
+
+static int soblock(jk_sock_t sd)
+{
+/* BeOS uses setsockopt at present for non blocking... */
+#ifndef WIN32
+    int fd_flags;
+
+    fd_flags = fcntl(sd, F_GETFL, 0);
+#if defined(O_NONBLOCK)
+    fd_flags &= ~O_NONBLOCK;
+#elif defined(O_NDELAY)
+    fd_flags &= ~O_NDELAY;
+#elif defined(FNDELAY)
+    fd_flags &= ~FNDELAY;
+#else
+#error Please teach JK how to make sockets blocking on your platform.
+#endif
+    if (fcntl(sd, F_SETFL, fd_flags) == -1) {
+        return errno;
+    }
+#else
+    u_long on = 0;
+    if (ioctlsocket(sd, FIONBIO, &on) == SOCKET_ERROR) {
+        errno = WSAGetLastError() - WSABASEERR;
+        return errno;
+    }
+#endif /* WIN32 */
+    return 0;
+}
+
+static int sononblock(jk_sock_t sd)
+{
+#ifndef WIN32
+    int fd_flags;
+
+    fd_flags = fcntl(sd, F_GETFL, 0);
+#if defined(O_NONBLOCK)
+    fd_flags |= O_NONBLOCK;
+#elif defined(O_NDELAY)
+    fd_flags |= O_NDELAY;
+#elif defined(FNDELAY)
+    fd_flags |= FNDELAY;
+#else
+#error Please teach JK how to make sockets non-blocking on your platform.
+#endif
+    if (fcntl(sd, F_SETFL, fd_flags) == -1) {
+        return errno;
+    }
+#else
+    u_long on = 1;
+    if (ioctlsocket(sd, FIONBIO, &on) == SOCKET_ERROR) {
+        errno = WSAGetLastError() - WSABASEERR;
+        return errno;
+    }
+#endif /* WIN32 */
+    return 0;
+}
+
+#if defined (WIN32) || (defined(NETWARE) && defined(__NOVELL_LIBC__))
+/* WIN32 implementation */
+static int nb_connect(jk_sock_t sock, struct sockaddr *addr, int timeout)
+{
+    int rc;
+    if (timeout < 1)
+        return connect(sock, addr, sizeof(struct sockaddr_in));
+
+    if ((rc = sononblock(sock)))
+        return -1;
+    if (connect(sock, addr, sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
+        struct timeval tv;
+        fd_set wfdset, efdset;
+
+        if ((rc = WSAGetLastError()) != WSAEWOULDBLOCK) {
+            soblock(sock);
+            WSASetLastError(rc);
+            return -1;
+        }
+        /* wait for the connect to complete or timeout */
+        FD_ZERO(&wfdset);
+        FD_SET(sock, &wfdset);
+        FD_ZERO(&efdset);
+        FD_SET(sock, &efdset);
+
+        tv.tv_sec  = timeout;
+        tv.tv_usec = 0;
+        rc = select((int)sock + 1, NULL, &wfdset, &efdset, &tv);
+        if (rc == SOCKET_ERROR || rc == 0) {
+            rc = WSAGetLastError();
+            soblock(sock);
+            WSASetLastError(rc);
+            return -1;
+        }
+        /* Evaluate the efdset */
+        if (FD_ISSET(sock, &efdset)) {
+            /* The connect failed. */
+            int rclen = (int)sizeof(rc);
+            if (getsockopt(sock, SOL_SOCKET, SO_ERROR, (char*) &rc, &rclen))
+                rc = 0;
+            soblock(sock);
+            if (rc)
+                WSASetLastError(rc);
+            return -1;
+        }
+    }
+    soblock(sock);
+    return 0;
+}
+
+#elif !defined(NETWARE)
+/* POSIX implementation */
+static int nb_connect(jk_sock_t sock, struct sockaddr *addr, int timeout)
+{
+    int rc = 0;
+
+    if (timeout > 0) {
+        if (sononblock(sock))
+            return -1;
+    }
+    do {
+        rc = connect(sock, addr, sizeof(struct sockaddr_in));
+    } while (rc == -1 && errno == EINTR);
+
+    if ((rc == -1) && (errno == EINPROGRESS || errno == EALREADY)
+                   && (timeout > 0)) {
+        fd_set wfdset;
+        struct timeval tv;
+        socklen_t rclen = (socklen_t)sizeof(rc);
+
+        FD_ZERO(&wfdset);
+        FD_SET(sock, &wfdset);
+        tv.tv_sec  = timeout;
+        tv.tv_usec = 0;
+        rc = select(sock + 1, NULL, &wfdset, NULL, &tv);
+        if (rc <= 0) {
+            /* Save errno */
+            int err = errno;
+            soblock(sock);
+            errno = err;
+            return -1;
+        }
+        rc = 0;
+#ifdef SO_ERROR
+        if (!FD_ISSET(sock, &wfdset) ||
+            (getsockopt(sock, SOL_SOCKET, SO_ERROR,
+                        (char *)&rc, &rclen) < 0) || rc) {
+            if (rc)
+                errno = rc;
+            rc = -1;
+        }
+#endif /* SO_ERROR */
+    }
+    /* Not sure we can be already connected */
+    if (rc == -1 && errno == EISCONN)
+        rc = 0;
+    soblock(sock);
+    return rc;
+}
+#else
+/* NETWARE implementation - blocking for now */
+static int nb_connect(jk_sock_t sock, struct sockaddr *addr, int timeout)
+{
+    return connect(sock, addr, sizeof(struct sockaddr_in));
+}
+#endif
+
+/** resolve the host IP */
+
+int jk_resolve(const char *host, int port, struct sockaddr_in *rc)
+{
+    int x;
+    struct in_addr laddr;
+
+    memset(rc, 0, sizeof(struct sockaddr_in));
+
+    rc->sin_port = htons((short)port);
+    rc->sin_family = AF_INET;
+
+    /* Check if we only have digits in the string */
+    for (x = 0; host[x] != '\0'; x++) {
+        if (!isdigit(host[x]) && host[x] != '.') {
+            break;
+        }
+    }
+
+    /* If we found also characters we shoud make name to IP resolution */
+    if (host[x] != '\0') {
+
+#ifdef HAVE_APR
+        apr_sockaddr_t *remote_sa, *temp_sa;
+        char *remote_ipaddr;
+
+        if (!jk_apr_pool) {
+            if (apr_pool_create(&jk_apr_pool, NULL) != APR_SUCCESS)
+                return JK_FALSE;
+        }
+        if (apr_sockaddr_info_get
+            (&remote_sa, host, APR_UNSPEC, (apr_port_t) port, 0, jk_apr_pool)
+            != APR_SUCCESS)
+            return JK_FALSE;
+
+        /* Since we are only handling AF_INET (IPV4) address (in_addr_t) */
+        /* make sure we find one of those.                               */
+        temp_sa = remote_sa;
+        while ((NULL != temp_sa) && (AF_INET != temp_sa->family))
+            temp_sa = temp_sa->next;
+
+        /* if temp_sa is set, we have a valid address otherwise, just return */
+        if (NULL != temp_sa)
+            remote_sa = temp_sa;
+        else
+            return JK_FALSE;
+
+        apr_sockaddr_ip_get(&remote_ipaddr, remote_sa);
+        laddr.s_addr = inet_addr(remote_ipaddr);
+
+#else /* HAVE_APR */
+
+        /* XXX : WARNING : We should really use gethostbyname_r in multi-threaded env */
+        /* Fortunatly when APR is available, ie under Apache 2.0, we use it */
+#if defined(NETWARE) && !defined(__NOVELL_LIBC__)
+        struct hostent *hoste = gethostbyname((char*)host);
+#else
+        struct hostent *hoste = gethostbyname(host);
+#endif
+        if (!hoste) {
+            return JK_FALSE;
+        }
+
+        laddr = *((struct in_addr *)hoste->h_addr_list[0]);
+
+#endif /* HAVE_APR */
+    }
+    else {
+        /* If we found only digits we use inet_addr() */
+        laddr.s_addr = inet_addr(host);
+    }
+    memcpy(&(rc->sin_addr), &laddr, sizeof(laddr));
+
+    return JK_TRUE;
+}
+
+/** connect to Tomcat */
+
+jk_sock_t jk_open_socket(struct sockaddr_in *addr, int keepalive,
+                         int timeout, int sock_buf, jk_logger_t *l)
+{
+    char buf[32];
+    jk_sock_t sock;
+    int set = 1;
+    int ret = 0;
+#ifdef SO_LINGER
+    struct linger li;
+#endif
+
+    JK_TRACE_ENTER(l);
+
+    sock = socket(AF_INET, SOCK_STREAM, 0);
+    if (!IS_VALID_SOCKET(sock)) {
+        JK_GET_SOCKET_ERRNO();
+        jk_log(l, JK_LOG_ERROR,
+               "socket() failed with errno=%d", errno);
+        JK_TRACE_EXIT(l);
+        return JK_INVALID_SOCKET;
+;
+    }
+    /* Disable Nagle algorithm */
+    if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (SET_TYPE)&set,
+                   sizeof(set))) {
+        jk_log(l, JK_LOG_ERROR,
+                "failed setting TCP_NODELAY with errno=%d", errno);
+        jk_close_socket(sock);
+        JK_TRACE_EXIT(l);
+        return JK_INVALID_SOCKET;
+    }
+    if (JK_IS_DEBUG_LEVEL(l))
+        jk_log(l, JK_LOG_DEBUG,
+               "socket TCP_NODELAY set to On");
+    if (keepalive) {
+        set = 1;
+        if (setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (SET_TYPE)&set,
+                       sizeof(set))) {
+            jk_log(l, JK_LOG_ERROR,
+                   "failed setting SO_KEEPALIVE with errno=%d", errno);
+            jk_close_socket(sock);
+            JK_TRACE_EXIT(l);
+            return JK_INVALID_SOCKET;
+        }
+        if (JK_IS_DEBUG_LEVEL(l))
+            jk_log(l, JK_LOG_DEBUG,
+                   "socket SO_KEEPALIVE set to On");
+    }
+
+    if (sock_buf > 0) {
+        set = sock_buf;
+        /* Set socket send buffer size */
+        if (setsockopt(sock, SOL_SOCKET, SO_SNDBUF, (SET_TYPE)&set,
+                        sizeof(set))) {
+            JK_GET_SOCKET_ERRNO();
+            jk_log(l, JK_LOG_ERROR,
+                    "failed setting SO_SNDBUF with errno=%d", errno);
+            jk_close_socket(sock);
+            JK_TRACE_EXIT(l);
+            return JK_INVALID_SOCKET;
+        }
+        set = sock_buf;
+        /* Set socket receive buffer size */
+        if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF, (SET_TYPE)&set,
+                                sizeof(set))) {
+            JK_GET_SOCKET_ERRNO();
+            jk_log(l, JK_LOG_ERROR,
+                    "failed setting SO_RCVBUF with errno=%d", errno);
+            jk_close_socket(sock);
+            JK_TRACE_EXIT(l);
+            return JK_INVALID_SOCKET;
+        }
+        if (JK_IS_DEBUG_LEVEL(l))
+            jk_log(l, JK_LOG_DEBUG,
+                   "socket SO_SNDBUF and  SO_RCVBUF set to %d",
+                   sock_buf);
+    }
+
+    if (timeout > 0) {
+#if defined(WIN32) || (defined(NETWARE) && defined(__NOVELL_LIBC__))
+        int tmout = timeout * 1000;
+        setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO,
+                   (const char *) &tmout, sizeof(int));
+        setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO,
+                   (const char *) &tmout, sizeof(int));
+#elif defined(SO_RCVTIMEO) && defined(USE_SO_RCVTIMEO) && defined(SO_SNDTIMEO) && defined(USE_SO_SNDTIMEO)
+        struct timeval tv;
+        tv.tv_sec  = timeout;
+        tv.tv_usec = 0;
+        setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO,
+                   (const void *) &tv, sizeof(tv));
+        setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO,
+                   (const void *) &tv, sizeof(tv));
+#endif
+        if (JK_IS_DEBUG_LEVEL(l))
+            jk_log(l, JK_LOG_DEBUG,
+                   "timeout %d set for socket=%d",
+                   timeout, sock);
+    }
+#ifdef SO_NOSIGPIPE
+    /* The preferred method on Mac OS X (10.2 and later) to prevent SIGPIPEs when
+     * sending data to a dead peer. Possibly also existing and in use on other BSD
+     * systems?
+    */
+    set = 1;
+    if (setsockopt(sock, SOL_SOCKET, SO_NOSIGPIPE, (const char *)&set,
+                   sizeof(int))) {
+        JK_GET_SOCKET_ERRNO();
+        jk_log(l, JK_LOG_ERROR,
+                "failed setting SO_NOSIGPIPE with errno=%d", errno);
+        jk_close_socket(sock);
+        JK_TRACE_EXIT(l);
+        return JK_INVALID_SOCKET;
+    }
+#endif
+#ifdef SO_LINGER
+    /* Make hard closesocket by disabling lingering */
+    li.l_linger = li.l_onoff = 0;
+    if (setsockopt(sock, SOL_SOCKET, SO_LINGER, (SET_TYPE)&li,
+                   sizeof(li))) {
+        JK_GET_SOCKET_ERRNO();
+        jk_log(l, JK_LOG_ERROR,
+                "failed setting SO_LINGER with errno=%d", errno);
+        jk_close_socket(sock);
+        JK_TRACE_EXIT(l);
+        return JK_INVALID_SOCKET;
+    }
+#endif
+    /* Tries to connect to Tomcat (continues trying while error is EINTR) */
+    if (JK_IS_DEBUG_LEVEL(l))
+        jk_log(l, JK_LOG_DEBUG,
+                "trying to connect socket %d to %s", sock,
+                jk_dump_hinfo(addr, buf));
+
+/* Need more infos for BSD 4.4 and Unix 98 defines, for now only
+iSeries when Unix98 is required at compil time */
+#if (_XOPEN_SOURCE >= 520) && defined(AS400)
+    ((struct sockaddr *)addr)->sa_len = sizeof(struct sockaddr_in);
+#endif
+    ret = nb_connect(sock, (struct sockaddr *)addr, timeout);
+#if defined(WIN32) || (defined(NETWARE) && defined(__NOVELL_LIBC__))
+    if (ret == SOCKET_ERROR) {
+        errno = WSAGetLastError() - WSABASEERR;
+    }
+#endif /* WIN32 */
+
+    /* Check if we are connected */
+    if (ret) {
+        jk_log(l, JK_LOG_INFO,
+               "connect to %s failed with errno=%d",
+               jk_dump_hinfo(addr, buf), errno);
+        jk_close_socket(sock);
+        sock = JK_INVALID_SOCKET;
+    }
+    else {
+        if (JK_IS_DEBUG_LEVEL(l))
+            jk_log(l, JK_LOG_DEBUG, "socket %d connected to %s",
+                   sock, jk_dump_hinfo(addr, buf));
+    }
+    JK_TRACE_EXIT(l);
+    return sock;
+}
+
+/** close the socket */
+
+int jk_close_socket(jk_sock_t s)
+{
+#if defined(WIN32) || (defined(NETWARE) && defined(__NOVELL_LIBC__))
+    if (s != INVALID_SOCKET)
+        return closesocket(s) ? -1 : 0;
+#else
+    if (s != -1)
+        return close(s);
+#endif
+
+    return -1;
+}
+
+#ifndef MAX_SECS_TO_LINGER
+#define MAX_SECS_TO_LINGER 16
+#endif
+#define SECONDS_TO_LINGER  1
+
+#ifndef SHUT_WR
+#ifdef SD_SEND
+#define SHUT_WR SD_SEND
+#else
+#define SHUT_WR 0x01
+#endif
+#endif
+int jk_shutdown_socket(jk_sock_t s)
+{
+    unsigned char dummy[512];
+    int nbytes;
+    int ttl = 0;
+    int rc = 0;
+#if defined(WIN32) || (defined(NETWARE) && defined(__NOVELL_LIBC__))
+    int tmout = SECONDS_TO_LINGER * 1000;
+    if (s == INVALID_SOCKET)
+#else
+    struct timeval tv;
+    if (s < 0)
+#endif
+        return -1;
+
+    /* Shut down the socket for write, which will send a FIN
+     * to the peer.
+     */
+    if (shutdown(s, SHUT_WR)) {
+        return jk_close_socket(s);
+    }
+#if defined(WIN32)  || (defined(NETWARE) && defined(__NOVELL_LIBC__))
+    if (setsockopt(s, SOL_SOCKET, SO_RCVTIMEO,
+                   (const char *) &tmout, sizeof(int)) == 0)
+        rc = 1;
+#elif defined(SO_RCVTIMEO) && defined(USE_SO_RCVTIMEO)
+    tv.tv_sec  = SECONDS_TO_LINGER;
+    tv.tv_usec = 0;
+    if (setsockopt(s, SOL_SOCKET, SO_RCVTIMEO,
+                   (const void *) &tv, sizeof(tv)))
+        rc = 1;
+#endif
+    /* Read all data from the peer until we reach "end-of-file" (FIN
+     * from peer) or we've exceeded our overall timeout. If the client does
+     * not send us bytes within 12 second, close the connection.
+     */
+    while (rc) {
+        nbytes = jk_tcp_socket_recvfull(s, dummy, sizeof(dummy));
+        if (nbytes <= 0)
+            break;
+        ttl += SECONDS_TO_LINGER;
+        if (ttl > MAX_SECS_TO_LINGER)
+            break;
+    }
+    return jk_close_socket(s);
+}
+
+/** send a long message
+ * @param sd  opened socket.
+ * @param b   buffer containing the data.
+ * @param len length to send.
+ * @return    -2: send returned 0 ? what this that ?
+ *            -3: send failed.
+ *            >0: total size send.
+ * @bug       this fails on Unixes if len is too big for the underlying
+ *             protocol.
+ */
+int jk_tcp_socket_sendfull(jk_sock_t sd, const unsigned char *b, int len)
+{
+    int sent = 0;
+    int wr;
+
+    while (sent < len) {
+        do {
+#if defined(WIN32) || (defined(NETWARE) && defined(__NOVELL_LIBC__))
+            wr = send(sd, (const char*)(b + sent),
+                      len - sent, 0);
+            if (wr == SOCKET_ERROR)
+                errno = WSAGetLastError() - WSABASEERR;
+#else
+            wr = write(sd, b + sent, len - sent);
+#endif
+        } while (wr == -1 && (errno == EINTR || errno == EAGAIN));
+
+        if (wr == -1)
+            return (errno > 0) ? -errno : errno;
+        else if (wr == 0)
+            return JK_SOCKET_EOF;
+        sent += wr;
+    }
+
+    return sent;
+}
+
+/** receive len bytes. Used in ajp_common.
+ * @param sd  opened socket.
+ * @param b   buffer to store the data.
+ * @param len length to receive.
+ * @return    <0: receive failed or connection closed.
+ *            >0: length of the received data.
+ */
+int jk_tcp_socket_recvfull(jk_sock_t sd, unsigned char *b, int len)
+{
+    int rdlen = 0;
+    int rd;
+
+    while (rdlen < len) {
+        do {
+#if defined(WIN32) || (defined(NETWARE) && defined(__NOVELL_LIBC__))
+            rd = recv(sd, (char *)b + rdlen,
+                      len - rdlen, 0);
+            /* Assuming SOCKET_ERROR is -1 on NETWARE too */
+            if (rd == SOCKET_ERROR)
+                errno = WSAGetLastError() - WSABASEERR;
+#else
+            rd = read(sd, (char *)b + rdlen, len - rdlen);
+#endif
+        } while (rd == -1 && (errno == EINTR || errno == EAGAIN));
+
+        if (rd == -1)
+            return (errno > 0) ? -errno : errno;
+        else if (rd == 0)
+            return JK_SOCKET_EOF;
+        rdlen += rd;
+    }
+
+    return rdlen;
+}
+
+/**
+ * dump a sockaddr_in in A.B.C.D:P in ASCII buffer
+ *
+ */
+char *jk_dump_hinfo(struct sockaddr_in *saddr, char *buf)
+{
+    unsigned long laddr = (unsigned long)htonl(saddr->sin_addr.s_addr);
+    unsigned short lport = (unsigned short)htons(saddr->sin_port);
+
+    sprintf(buf, "%d.%d.%d.%d:%d",
+            (int)(laddr >> 24), (int)((laddr >> 16) & 0xff),
+            (int)((laddr >> 8) & 0xff), (int)(laddr & 0xff), (int)lport);
+
+    return buf;
+}
+
+int jk_is_socket_connected(jk_sock_t sock)
+{
+    fd_set fd;
+    struct timeval tv;
+    int rc;
+
+    FD_ZERO(&fd);
+    FD_SET(sock, &fd);
+
+    /* Wait one microsecond */
+    tv.tv_sec  = 0;
+    tv.tv_usec = 1;
+    
+    do {
+        rc = select((int)sock + 1, &fd, NULL, NULL, &tv);
+#if defined(WIN32) || (defined(NETWARE) && defined(__NOVELL_LIBC__))
+        errno = WSAGetLastError() - WSABASEERR;
+#endif        
+    } while (rc == -1 && errno == EINTR);
+
+    if (rc == 0) {
+        /* If we get a timeout, then we are still connected */
+        return 1;
+    }
+    else if (rc == 1) {
+#if defined(WIN32) || (defined(NETWARE) && defined(__NOVELL_LIBC__))
+        u_long nr;
+        if (ioctlsocket(sock, FIONREAD, &nr) == 0) {
+            if (WSAGetLastError() == 0)
+                errno = 0;
+            else
+                errno = WSAGetLastError() - WSABASEERR;
+            return nr == 0 ? 0 : 1;
+        }
+        errno = WSAGetLastError() - WSABASEERR;
+#else
+        int nr;
+        if (ioctl(sock, FIONREAD, (void*)&nr) == 0) {
+            return nr == 0 ? 0 : 1;
+        }
+#endif        
+    }
+
+    return 0;
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_connect.h
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_connect.h	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_connect.h	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,62 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.
+ */
+
+/***************************************************************************
+ * Description: Socket connections header file                             *
+ * Author:      Gal Shachor <shachor at il.ibm.com>                           *
+ * Version:     $Revision: 437450 $                                               *
+ ***************************************************************************/
+
+#ifndef JK_CONNECT_H
+#define JK_CONNECT_H
+
+#include "jk_logger.h"
+#include "jk_global.h"
+
+#if !defined(WIN32) && !(defined(NETWARE) && defined(__NOVELL_LIBC__))
+#define closesocket         close
+#endif
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif                          /* __cplusplus */
+
+#define JK_SOCKET_EOF      (-2)
+#define JK_SOCKET_ERROR    (-3)
+
+int jk_resolve(const char *host, int port, struct sockaddr_in *rc);
+
+jk_sock_t jk_open_socket(struct sockaddr_in *addr, int keepalive,
+                         int timeout, int sock_buf, jk_logger_t *l);
+
+int jk_close_socket(jk_sock_t s);
+
+int jk_shutdown_socket(jk_sock_t s);
+
+int jk_tcp_socket_sendfull(jk_sock_t sd, const unsigned char *b, int len);
+
+int jk_tcp_socket_recvfull(jk_sock_t sd, unsigned char *b, int len);
+
+char *jk_dump_hinfo(struct sockaddr_in *saddr, char *buf);
+
+int jk_is_socket_connected(jk_sock_t sd);
+
+#ifdef __cplusplus
+}
+#endif                          /* __cplusplus */
+
+#endif                          /* JK_CONNECT_H */

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_context.c
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_context.c	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_context.c	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,295 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.
+ */
+
+/***************************************************************************
+ * Description: Context handling (Autoconf)                                *
+ * Author:      Henri Gomez <hgomez at apache.org>                            *
+ * Version:     $Revision: 299951 $                                           *
+ ***************************************************************************/
+
+#include "jk_global.h"
+#include "jk_context.h"
+#include "jk_ajp_common.h"
+
+
+/*
+ * Set the virtual name of the context 
+ */
+
+int context_set_virtual(jk_context_t *c, char *virt)
+{
+    if (c) {
+
+        if (virt) {
+            c->virt = jk_pool_strdup(&c->p, virt);
+
+            if (!c->virt)
+                return JK_FALSE;
+        }
+
+        return JK_TRUE;
+    }
+
+    return JK_FALSE;
+}
+
+/*
+ * Init the context info struct
+ */
+
+int context_open(jk_context_t *c, char *virt)
+{
+    if (c) {
+        jk_open_pool(&c->p, c->buf, sizeof(jk_pool_atom_t) * SMALL_POOL_SIZE);
+        c->size = 0;
+        c->capacity = 0;
+        c->contexts = NULL;
+
+        return context_set_virtual(c, virt);
+    }
+
+    return JK_FALSE;
+}
+
+/*
+ * Close the context info struct
+ */
+
+int context_close(jk_context_t *c)
+{
+    if (c) {
+
+        jk_close_pool(&c->p);
+        return JK_TRUE;
+    }
+
+    return JK_FALSE;
+}
+
+/*
+ * Allocate and open context
+ */
+
+int context_alloc(jk_context_t **c, char *virt)
+{
+    if (c)
+        return context_open(*c =
+                            (jk_context_t *)calloc(1, sizeof(jk_context_t)),
+                            virt);
+
+    return JK_FALSE;
+}
+
+/*
+ * Close and destroy context
+ */
+
+int context_free(jk_context_t **c)
+{
+    if (c && *c) {
+        context_close(*c);
+        free(*c);
+        *c = NULL;
+        return JK_TRUE;
+    }
+
+    return JK_FALSE;
+}
+
+
+/*
+ * Ensure there will be memory in context info to store Context Bases
+ */
+
+static int context_realloc(jk_context_t *c)
+{
+    if (c->size == c->capacity) {
+        jk_context_item_t **contexts;
+        int capacity = c->capacity + CBASE_INC_SIZE;
+
+        contexts =
+            (jk_context_item_t **)jk_pool_alloc(&c->p,
+                                                sizeof(jk_context_item_t *) *
+                                                capacity);
+
+        if (!contexts)
+            return JK_FALSE;
+
+        if (c->capacity && c->contexts)
+            memcpy(contexts, c->contexts,
+                   sizeof(jk_context_item_t *) * c->capacity);
+
+        c->contexts = contexts;
+        c->capacity = capacity;
+    }
+
+    return JK_TRUE;
+}
+
+/*
+ * Ensure there will be memory in context info to URIS
+ */
+
+static int context_item_realloc(jk_context_t *c, jk_context_item_t *ci)
+{
+    if (ci->size == ci->capacity) {
+        char **uris;
+        int capacity = ci->capacity + URI_INC_SIZE;
+
+        uris = (char **)jk_pool_alloc(&c->p, sizeof(char *) * capacity);
+
+        if (!uris)
+            return JK_FALSE;
+
+        memcpy(uris, ci->uris, sizeof(char *) * ci->capacity);
+
+        ci->uris = uris;
+        ci->capacity = capacity;
+    }
+
+    return JK_TRUE;
+}
+
+
+/*
+ * Locate a context base in context list
+ */
+
+jk_context_item_t *context_find_base(jk_context_t *c, char *cbase)
+{
+    int i;
+    jk_context_item_t *ci;
+
+    if (!c || !cbase)
+        return NULL;
+
+    for (i = 0; i < c->size; i++) {
+
+        ci = c->contexts[i];
+
+        if (!ci)
+            continue;
+
+        if (!strcmp(ci->cbase, cbase))
+            return ci;
+    }
+
+    return NULL;
+}
+
+/*
+ * Locate an URI in a context item
+ */
+
+char *context_item_find_uri(jk_context_item_t *ci, char *uri)
+{
+    int i;
+
+    if (!ci || !uri)
+        return NULL;
+
+    for (i = 0; i < ci->size; i++) {
+        if (!strcmp(ci->uris[i], uri))
+            return ci->uris[i];
+    }
+
+    return NULL;
+}
+
+void context_dump_uris(jk_context_t *c, char *cbase, FILE * f)
+{
+    jk_context_item_t *ci;
+    int i;
+
+    ci = context_find_base(c, cbase);
+
+    if (!ci)
+        return;
+
+    for (i = 0; i < ci->size; i++)
+        fprintf(f, "/%s/%s\n", ci->cbase, ci->uris[i]);
+
+    fflush(f);
+}
+
+
+/*
+ * Add a new context item to context
+ */
+
+jk_context_item_t *context_add_base(jk_context_t *c, char *cbase)
+{
+    jk_context_item_t *ci;
+
+    if (!c || !cbase)
+        return NULL;
+
+    /* Check if the context base was not allready created */
+    ci = context_find_base(c, cbase);
+
+    if (ci)
+        return ci;
+
+    if (context_realloc(c) != JK_TRUE)
+        return NULL;
+
+    ci = (jk_context_item_t *)jk_pool_alloc(&c->p, sizeof(jk_context_item_t));
+
+    if (!ci)
+        return NULL;
+
+    c->contexts[c->size] = ci;
+    c->size++;
+    ci->cbase = jk_pool_strdup(&c->p, cbase);
+    ci->status = 0;
+    ci->size = 0;
+    ci->capacity = 0;
+    ci->uris = NULL;
+
+    return ci;
+}
+
+/*
+ * Add a new URI to a context item
+ */
+
+int context_add_uri(jk_context_t *c, char *cbase, char *uri)
+{
+    jk_context_item_t *ci;
+
+    if (!uri)
+        return JK_FALSE;
+
+    /* Get/Create the context base */
+    ci = context_add_base(c, cbase);
+
+    if (!ci)
+        return JK_FALSE;
+
+    if (context_item_find_uri(ci, uri) != NULL)
+        return JK_TRUE;
+
+    if (context_item_realloc(c, ci) == JK_FALSE)
+        return JK_FALSE;
+
+    ci->uris[ci->size] = jk_pool_strdup(&c->p, uri);
+
+    if (ci->uris[ci->size] == NULL)
+        return JK_FALSE;
+
+    ci->size++;
+    return JK_TRUE;
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_context.h
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_context.h	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_context.h	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,137 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.
+ */
+
+/***************************************************************************
+ * Description: Context Stuff (Autoconf)                                   *
+ * Author:      Henri Gomez <hgomez at apache.org>                            *
+ * Version:     $Revision: 299951 $                                           *
+ ***************************************************************************/
+#ifndef JK_CONTEXT_H
+#define JK_CONTEXT_H
+
+#include "jk_pool.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif                          /* __cplusplus */
+
+#define CBASE_INC_SIZE   (8)    /* Allocate memory by step of 8 URIs : ie 8 URI by context */
+#define URI_INC_SIZE (8)        /* Allocate memory by step of 8 CONTEXTs : ie 8 contexts by worker */
+
+typedef struct
+{
+
+    /*
+     * Context base (ie examples) 
+     */
+
+    char *cbase;
+
+    /*
+     * Status (Up/Down)
+     */
+
+    int status;
+
+    /*
+     * Num of URI handled 
+     */
+
+    int size;
+
+    /*
+     * Capacity
+     */
+
+    int capacity;
+
+    /*
+     * URL/URIs (autoconf)
+     */
+
+    char **uris;
+}
+jk_context_item_t;
+
+
+typedef struct
+{
+
+    /*
+     * Memory Pool
+     */
+
+    jk_pool_t p;
+    jk_pool_atom_t buf[SMALL_POOL_SIZE];
+
+    /*
+     * Virtual Server (if use)
+     */
+
+    char *virt;
+
+    /*
+     * Num of context handled (ie: examples, admin...)
+     */
+
+    int size;
+
+    /*
+     * Capacity
+     */
+
+    int capacity;
+
+    /*
+     * Context list, context / URIs
+     */
+
+    jk_context_item_t **contexts;
+}
+jk_context_t;
+
+
+/*
+ * functions defined here 
+ */
+
+int context_set_virtual(jk_context_t *c, char *virt);
+
+int context_open(jk_context_t *c, char *virt);
+
+int context_close(jk_context_t *c);
+
+int context_alloc(jk_context_t **c, char *virt);
+
+int context_free(jk_context_t **c);
+
+jk_context_item_t *context_find_base(jk_context_t *c, char *cbase);
+
+char *context_item_find_uri(jk_context_item_t *ci, char *uri);
+
+void context_dump_uris(jk_context_t *c, char *cbase, FILE * f);
+
+jk_context_item_t *context_add_base(jk_context_t *c, char *cbase);
+
+int context_add_uri(jk_context_t *c, char *cbase, char *uri);
+
+
+#ifdef __cplusplus
+}
+#endif                          /* __cplusplus */
+
+#endif                          /* JK_CONTEXT_H */

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_global.h
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_global.h	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_global.h	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,345 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.
+ */
+
+/***************************************************************************
+ * Description: Global definitions and include files that should exist     *
+ *              anywhere                                                   *
+ * Author:      Gal Shachor <shachor at il.ibm.com>                           *
+ * Version:     $Revision: 434345 $                                               *
+ ***************************************************************************/
+
+#ifndef JK_GLOBAL_H
+#define JK_GLOBAL_H
+
+#ifndef NETWARE
+#if !defined(WIN32) && !defined(AS400)
+#include "portable.h"
+#else
+#define HAVE_VSNPRINTF
+#define HAVE_SNPRINTF
+#endif
+#endif
+
+#if defined(WIN32)
+
+/* Ignore most warnings (back down to /W3) for poorly constructed headers
+ */
+#if defined(_MSC_VER) && _MSC_VER >= 1200
+#pragma warning(push, 3)
+#endif
+
+/* disable or reduce the frequency of...
+ *   C4057: indirection to slightly different base types
+ *   C4075: slight indirection changes (unsigned short* vs short[])
+ *   C4100: unreferenced formal parameter
+ *   C4127: conditional expression is constant
+ *   C4163: '_rotl64' : not available as an intrinsic function
+ *   C4201: nonstandard extension nameless struct/unions
+ *   C4244: int to char/short - precision loss
+ *   C4514: unreferenced inline function removed
+ */
+#pragma warning(disable: 4100 4127 4163 4201 4514; once: 4057 4075 4244)
+
+/* Ignore Microsoft's interpretation of secure development
+ * and the POSIX string handling API
+ */
+#if defined(_MSC_VER) && _MSC_VER >= 1400
+#ifndef _CRT_SECURE_NO_DEPRECATE
+#define _CRT_SECURE_NO_DEPRECATE
+#endif
+#pragma warning(disable: 4996)
+#endif
+#endif
+
+#include "jk_version.h"
+
+#ifdef HAVE_APR
+#include "apr_lib.h"
+#include "apr_strings.h"
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <time.h>
+#include <ctype.h>
+
+#ifdef _OSD_POSIX
+#include "ap_config.h"
+#endif
+
+#ifdef AS400
+#include "ap_config.h"
+extern char *strdup(const char *str);
+#endif
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#ifdef WIN32
+#ifndef _WINDOWS_
+#ifndef WIN32_LEAN_AND_MEAN
+#define WIN32_LEAN_AND_MEAN
+#endif
+#ifndef _WIN32_WINNT
+
+/* Restrict the server to a subset of Windows NT 4.0 header files by default
+ */
+#define _WIN32_WINNT 0x0400
+#endif
+#ifndef NOUSER
+#define NOUSER
+#endif
+#ifndef NOMCX
+#define NOMCX
+#endif
+#ifndef NOIME
+#define NOIME
+#endif
+#include <windows.h>
+/* 
+ * Add a _very_few_ declarations missing from the restricted set of headers
+ * (If this list becomes extensive, re-enable the required headers above!)
+ * winsock headers were excluded by WIN32_LEAN_AND_MEAN, so include them now
+ */
+#include <winsock2.h>
+#include <mswsock.h>
+#include <ws2tcpip.h>
+#endif
+#include <sys/timeb.h>
+#include <process.h>
+#else
+#include <unistd.h>
+#if defined(NETWARE) && defined(__NOVELL_LIBC__)
+#include "novsock2.h"
+#define __sys_socket_h__
+#define __netdb_h__
+#define __netinet_in_h__
+#define HAVE_VSNPRINTF
+#define HAVE_SNPRINTF
+#endif
+#include <netdb.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <fcntl.h>
+#ifndef NETWARE
+#include <netinet/tcp.h>
+#include <arpa/inet.h>
+#include <sys/un.h>
+#if !defined(_OSD_POSIX) && !defined(AS400) && !defined(CYGWIN)
+#include <sys/socketvar.h>
+#endif
+#if !defined(HPUX11) && !defined(AS400)
+#include <sys/select.h>
+#endif
+#endif
+
+#include <sys/time.h>
+#include <sys/ioctl.h>
+#endif
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif                          /* __cplusplus */
+
+#define JK_WORKER_FILE_TAG      ("worker_file")
+#define JK_MOUNT_FILE_TAG       ("worker_mount_file")
+#define JK_LOG_LEVEL_TAG        ("log_level")
+#define JK_LOG_FILE_TAG         ("log_file")
+#define JK_SHM_FILE_TAG         ("shm_file")
+#define JK_WORKER_NAME_TAG      ("worker")
+
+#define JK_WORKER_FILE_DEF  ("workers.properties")
+
+#define JK_TRUE  (1)
+#define JK_FALSE (0)
+
+#define JK_LF (10)
+#define JK_CR (13)
+
+#define JK_SESSION_IDENTIFIER "JSESSIONID"
+#define JK_PATH_SESSION_IDENTIFIER ";jsessionid"
+
+#if defined(WIN32) || defined(NETWARE)
+#define JK_METHOD __stdcall
+#define C_LEVEL_TRY_START       __try {
+#define C_LEVEL_TRY_END         }
+#define C_LEVEL_FINALLY_START   __finally {
+#define C_LEVEL_FINALLY_END     }
+#define PATH_SEPERATOR          (';')
+#define FILE_SEPERATOR          ('\\')
+#define PATH_ENV_VARIABLE       ("PATH")
+
+    /* incompatible names... */
+#ifndef strcasecmp
+#define strcasecmp stricmp
+#endif
+#else
+#define JK_METHOD
+#define C_LEVEL_TRY_START
+#define C_LEVEL_TRY_END
+#define C_LEVEL_FINALLY_START
+#define C_LEVEL_FINALLY_END
+#define PATH_SEPERATOR          (':')
+#define FILE_SEPERATOR          ('/')
+#define PATH_ENV_VARIABLE       ("LD_LIBRARY_PATH")
+#endif
+
+/* HTTP Error codes
+ */
+
+#define JK_HTTP_OK               200
+#define JK_HTTP_BAD_REQUEST      400
+#define JK_REQUEST_TOO_LARGE     413
+#define JK_HTTP_SERVER_ERROR     500
+#define JK_HTTP_NOT_IMPLEMENTED  501
+#define JK_HTTP_BAD_GATEWAY      502
+#define JK_HTTP_SERVER_BUSY      503
+#define JK_HTTP_GATEWAY_TIME_OUT 504
+
+
+/*
+ * RECO STATUS
+ */
+
+#define RECO_NONE   0x00
+#define RECO_INITED 0x01
+#define RECO_FILLED 0x02
+
+/*
+ * JK options
+ */
+
+#define JK_OPT_FWDURIMASK           0x0003
+
+#define JK_OPT_FWDURICOMPAT         0x0001
+#define JK_OPT_FWDURICOMPATUNPARSED 0x0002
+#define JK_OPT_FWDURIESCAPED        0x0003
+
+#define JK_OPT_FWDURIDEFAULT        JK_OPT_FWDURICOMPAT
+
+#define JK_OPT_FWDKEYSIZE           0x0004
+
+#define JK_OPT_FWDDIRS              0x0008
+/* Forward local instead remote address */
+#define JK_OPT_FWDLOCAL             0x0010
+#define JK_OPT_FLUSHPACKETS         0x0020
+#define JK_OPT_DISABLEREUSE         0x0040
+
+/* Check for EBCDIC systems */
+
+/* Check for Apache 2.0 running on an EBCDIC system */
+#if APR_CHARSET_EBCDIC
+
+#include <util_ebcdic.h>
+
+#define USE_CHARSET_EBCDIC
+#define jk_xlate_to_ascii(b, l) ap_xlate_proto_to_ascii(b, l)
+#define jk_xlate_from_ascii(b, l) ap_xlate_proto_from_ascii(b, l)
+
+#else                           /* APR_CHARSET_EBCDIC */
+
+/* Check for Apache 1.3 running on an EBCDIC system */
+#ifdef CHARSET_EBCDIC
+
+#define USE_CHARSET_EBCDIC
+#define jk_xlate_to_ascii(b, l) ebcdic2ascii(b, b, l)
+#define jk_xlate_from_ascii(b, l) ascii2ebcdic(b, b, l)
+
+#else                           /* CHARSET_EBCDIC */
+
+/* We're in on an ASCII system */
+
+#define jk_xlate_to_ascii(b, l) /* NOOP */
+#define jk_xlate_from_ascii(b, l)       /* NOOP */
+
+#endif                          /* CHARSET_EBCDIC */
+
+#endif                          /* APR_CHARSET_EBCDIC */
+
+/* jk_uint32_t defines a four byte word */
+/* jk_uint64_t defines a eight byte word */
+#if defined (WIN32)
+    typedef unsigned int jk_uint32_t;
+#define JK_UINT32_T_FMT "u"
+#define JK_UINT32_T_HEX_FMT "x"
+    typedef unsigned __int64 jk_uint64_t;
+#define JK_UINT64_T_FMT "I64u"
+#define JK_UINT64_T_HEX_FMT "I64x"
+#elif defined(AS400)
+    typedef unsigned int jk_uint32_t;
+#define JK_UINT32_T_FMT "u"
+#define JK_UINT32_T_HEX_FMT "x"
+    typedef unsigned long long jk_uint64_t;
+#define JK_UINT64_T_FMT "llu"
+#define JK_UINT64_T_HEX_FMT "llx"
+#else
+#include "jk_types.h"
+#endif
+
+#define JK_UINT32_T_FMT_LEN  (sizeof(JK_UINT32_T_FMT) - 1)
+#define JK_UINT32_T_HEX_FMT_LEN  (sizeof(JK_UINT32_T_HEX_FMT) - 1)
+#define JK_UINT64_T_FMT_LEN  (sizeof(JK_UINT64_T_FMT) - 1)
+#define JK_UINT64_T_HEX_FMT_LEN  (sizeof(JK_UINT64_T_HEX_FMT) - 1)
+
+#ifdef WIN32
+/* For WIN32, emulate gettimeofday() using _ftime() */
+#define gettimeofday(tv,tz) { struct _timeb tb; _ftime(&tb); (tv)->tv_sec = tb.time; (tv)->tv_usec = tb.millitm * 1000; }
+#ifdef HAVE_APR
+#define snprintf apr_snprintf
+#define vsnprintf apr_vsnprintf
+#else
+/* define snprint to match windows version */
+#define snprintf _snprintf
+#define vsnprintf _vsnprintf
+#endif
+#endif
+
+/* Use apr snprintf() and vsnprintf() when needed */
+#if defined(HAVE_APR)
+#if !defined(HAVE_SNPRINTF)
+#define snprintf apr_snprintf
+#endif
+#if !defined(HAVE_VSNPRINTF)
+#define vsnprintf apr_vsnprintf
+#endif
+#endif
+
+/* XXXX There is a snprintf() and vsnprintf() in jk_util.c */
+/* if those work remove the #define. */
+#if defined(NETWARE) || defined(AS400)
+#define USE_SPRINTF
+#define USE_VSPRINTF
+#endif
+
+#if defined(WIN32) || (defined(NETWARE) && defined(__NOVELL_LIBC__))
+typedef SOCKET jk_sock_t;
+#define IS_VALID_SOCKET(s) ((s) != INVALID_SOCKET)
+#define JK_INVALID_SOCKET  INVALID_SOCKET
+#else
+typedef int jk_sock_t;
+#define IS_VALID_SOCKET(s) ((s) > 0)
+#define JK_INVALID_SOCKET  (-1)
+#endif
+
+#ifdef __cplusplus
+}
+#endif                          /* __cplusplus */
+
+#endif                          /* JK_GLOBAL_H */

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_jni_worker.c
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_jni_worker.c	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_jni_worker.c	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,1237 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.
+ */
+
+/***************************************************************************
+ * Description: In process JNI worker                                      *
+ * Author:      Gal Shachor <shachor at il.ibm.com>                           *
+ * Based on:                                                               *
+ * Version:     $Revision: 434177 $                                           *
+ ***************************************************************************/
+
+#if !defined(WIN32) && !defined(NETWARE) && !defined(AS400)
+#include <dlfcn.h>
+#endif
+
+#include <jni.h>
+
+#include "jk_pool.h"
+#include "jk_jni_worker.h"
+#include "jk_util.h"
+
+#if defined LINUX && defined APACHE2_SIGHACK
+#include <pthread.h>
+#include <signal.h>
+#include <bits/signum.h>
+#endif
+
+#ifdef NETWARE
+#ifdef __NOVELL_LIBC__
+#include <dlfcn.h>
+#else
+#include <nwthread.h>
+#include <nwadv.h>
+#endif
+#endif
+
+#ifndef JNI_VERSION_1_1
+#define JNI_VERSION_1_1 0x00010001
+#endif
+
+/* probably on an older system that doesn't support RTLD_NOW or RTLD_LAZY.
+ * The below define is a lie since we are really doing RTLD_LAZY since the
+ * system doesn't support RTLD_NOW.
+ */
+#ifndef RTLD_NOW
+#define RTLD_NOW 1
+#endif
+
+#ifndef RTLD_GLOBAL
+#define RTLD_GLOBAL 0
+#endif
+
+#define null_check(e) if ((e) == 0) return JK_FALSE
+
+jint(JNICALL * jni_get_default_java_vm_init_args) (void *) = NULL;
+jint(JNICALL * jni_create_java_vm) (JavaVM **, JNIEnv **, void *) = NULL;
+#ifdef AS400
+jint(JNICALL * jni_get_created_java_vms) (JavaVM **, long, long *) = NULL;
+#else
+jint(JNICALL * jni_get_created_java_vms) (JavaVM **, int, int *) = NULL;
+#endif
+
+#define TC33_JAVA_BRIDGE_CLASS_NAME ("org/apache/tomcat/modules/server/JNIEndpoint")
+#define TC32_JAVA_BRIDGE_CLASS_NAME ("org/apache/tomcat/service/JNIEndpoint")
+
+static jk_worker_t *the_singleton_jni_worker = NULL;
+
+struct jni_worker
+{
+
+    int was_verified;
+    int was_initialized;
+
+    jk_pool_t p;
+    jk_pool_atom_t buf[TINY_POOL_SIZE];
+
+    /*
+     * JVM Object pointer.
+     */
+    JavaVM *jvm;
+
+    /*
+     * [V] JNIEnv used for boostraping from validate -> init w/o an attach
+     */
+    JNIEnv *tmp_env;
+
+    /*
+     * Web Server to Java bridge, instance and class.
+     */
+    jobject jk_java_bridge_object;
+    jclass jk_java_bridge_class;
+
+    /*
+     * Java methods ids, to jump into the JVM
+     */
+    jmethodID jk_startup_method;
+    jmethodID jk_service_method;
+    jmethodID jk_shutdown_method;
+
+    /*
+     * Command line for tomcat startup
+     */
+    char *tomcat_cmd_line;
+
+    /*
+     * Bridge Type, Tomcat 32/33/40/41/5
+     */
+    unsigned bridge_type;
+
+    /*
+     * Classpath
+     */
+    char *tomcat_classpath;
+
+    /*
+     * Full path to the jni javai/jvm dll
+     */
+    char *jvm_dll_path;
+
+    /*
+     * Initial Java heap size
+     */
+    unsigned tomcat_ms;
+
+    /*
+     * Max Java heap size
+     */
+    unsigned tomcat_mx;
+
+    /*
+     * Java system properties
+     */
+    char **sysprops;
+
+#ifdef JNI_VERSION_1_2
+    /*
+     * Java 2 initialization options (-X... , -verbose etc.)
+     */
+    char **java2opts;
+
+    /*
+     * Java 2 lax/strict option checking (bool)
+     */
+    int java2lax;
+#endif
+
+    /*
+     * stdout and stderr file names for Java
+     */
+    char *stdout_name;
+    char *stderr_name;
+
+    char *name;
+    jk_worker_t worker;
+};
+typedef struct jni_worker jni_worker_t;
+
+struct jni_endpoint
+{
+    int attached;
+    JNIEnv *env;
+    jni_worker_t *worker;
+
+    jk_endpoint_t endpoint;
+};
+typedef struct jni_endpoint jni_endpoint_t;
+
+
+static int load_jvm_dll(jni_worker_t * p, jk_logger_t *l);
+
+static int open_jvm(jni_worker_t * p, JNIEnv ** env, jk_logger_t *l);
+
+static int open_jvm1(jni_worker_t * p, JNIEnv ** env, jk_logger_t *l);
+
+#ifdef JNI_VERSION_1_2
+static int detect_jvm_version(jk_logger_t *l);
+
+static int open_jvm2(jni_worker_t * p, JNIEnv ** env, jk_logger_t *l);
+#endif
+
+
+static int get_bridge_object(jni_worker_t * p, JNIEnv * env, jk_logger_t *l);
+
+static int get_method_ids(jni_worker_t * p, JNIEnv * env, jk_logger_t *l);
+
+static JNIEnv *attach_to_jvm(jni_worker_t * p, jk_logger_t *l);
+
+static void detach_from_jvm(jni_worker_t * p, jk_logger_t *l);
+
+
+/*
+   Duplicate string and convert it to ASCII on EBDIC based systems
+   Needed for at least AS/400 and BS2000 but what about other EBDIC systems ?
+*/
+static void *strdup_ascii(jk_pool_t *p, char *s)
+{
+    char *rc;
+    rc = jk_pool_strdup(p, s);
+
+#if defined(AS400) || defined(_OSD_POSIX)
+    jk_xlate_to_ascii(rc, strlen(rc));
+#endif
+
+    return rc;
+}
+
+#if defined LINUX && defined APACHE2_SIGHACK
+static void linux_signal_hack()
+{
+    sigset_t newM;
+    sigset_t old;
+
+    sigemptyset(&newM);
+    pthread_sigmask(SIG_SETMASK, &newM, &old);
+
+    sigdelset(&old, SIGUSR1);
+    sigdelset(&old, SIGUSR2);
+    sigdelset(&old, SIGUNUSED);
+    sigdelset(&old, SIGRTMIN);
+    sigdelset(&old, SIGRTMIN + 1);
+    sigdelset(&old, SIGRTMIN + 2);
+    pthread_sigmask(SIG_SETMASK, &old, NULL);
+}
+
+static void print_signals(sigset_t * sset)
+{
+    int sig;
+    for (sig = 1; sig < 20; sig++) {
+        if (sigismember(sset, sig)) {
+            printf(" %d", sig);
+        }
+    }
+    printf("\n");
+}
+#endif
+
+static int JK_METHOD service(jk_endpoint_t *e,
+                             jk_ws_service_t *s,
+                             jk_logger_t *l, int *is_recoverable_error)
+{
+    jni_endpoint_t *p;
+    jint rc;
+
+    JK_TRACE_ENTER(l);
+
+    if (is_recoverable_error)
+        *is_recoverable_error = JK_FALSE;
+    if (!e || !e->endpoint_private || !s || !is_recoverable_error) {
+        JK_LOG_NULL_PARAMS(l);
+        JK_TRACE_EXIT(l);
+        return JK_FALSE;
+    }
+
+    p = e->endpoint_private;
+
+    if (!p->attached) {
+        /* Try to attach */
+        if (!(p->env = attach_to_jvm(p->worker, l))) {
+            jk_log(l, JK_LOG_EMERG, "Attach failed");
+            /*   Is it recoverable ?? */
+            *is_recoverable_error = JK_TRUE;
+            JK_TRACE_EXIT(l);
+            return JK_FALSE;
+        }
+        p->attached = JK_TRUE;
+    }
+
+    /* we are attached now */
+
+    /* 
+     * When we call the JVM we cannot know what happens
+     * So we can not recover !!!
+     */
+    jk_log(l, JK_LOG_DEBUG, "In service, calling Tomcat...");
+
+    rc = (*(p->env))->CallIntMethod(p->env,
+                                    p->worker->jk_java_bridge_object,
+                                    p->worker->jk_service_method,
+                                    /* [V] For some reason gcc likes this pointer -> int -> jlong conversion, */
+                                    /*     but not the direct pointer -> jlong conversion. I hope it's okay.  */
+#ifdef AS400
+                                    s, l
+#else
+                                    (jlong) (int)s, (jlong) (int)l
+#endif
+        );
+
+    /* [V] Righ now JNIEndpoint::service() only returns 1 or 0 */
+    if (rc) {
+        jk_log(l, JK_LOG_DEBUG, "Tomcat returned OK, done");
+        JK_TRACE_EXIT(l);
+        return JK_TRUE;
+    }
+    else {
+        jk_log(l, JK_LOG_ERROR, "Tomcat FAILED!");
+        JK_TRACE_EXIT(l);
+        return JK_FALSE;
+    }
+}
+
+static int JK_METHOD done(jk_endpoint_t **e, jk_logger_t *l)
+{
+    jni_endpoint_t *p;
+
+    JK_TRACE_ENTER(l);
+    if (!e || !*e || !(*e)->endpoint_private) {
+        JK_LOG_NULL_PARAMS(l);
+        JK_TRACE_EXIT(l);
+        return JK_FALSE;
+    }
+
+    p = (*e)->endpoint_private;
+
+    if (p->attached) {
+        detach_from_jvm(p->worker, l);
+    }
+
+    free(p);
+    *e = NULL;
+    JK_TRACE_EXIT(l);
+    return JK_TRUE;
+}
+
+static int JK_METHOD validate(jk_worker_t *pThis,
+                              jk_map_t *props,
+                              jk_worker_env_t *we, jk_logger_t *l)
+{
+    jni_worker_t *p;
+    int mem_config = 0;
+    int btype = 0;
+    const char *str_config = NULL;
+    JNIEnv *env;
+
+    JK_TRACE_ENTER(l);
+
+    if (!pThis || !pThis->worker_private) {
+        JK_LOG_NULL_PARAMS(l);
+        JK_TRACE_EXIT(l);
+        return JK_FALSE;
+    }
+
+    p = pThis->worker_private;
+
+    if (p->was_verified) {
+        jk_log(l, JK_LOG_DEBUG, "been here before, done");
+        JK_TRACE_EXIT(l);
+        return JK_TRUE;
+    }
+
+    if (jk_get_worker_mx(props, p->name, (unsigned int *)&mem_config)) {
+        p->tomcat_mx = mem_config;
+    }
+
+    if (jk_get_worker_ms(props, p->name, (unsigned int *)&mem_config)) {
+        p->tomcat_ms = mem_config;
+    }
+
+    if (jk_get_worker_classpath(props, p->name, &str_config)) {
+        p->tomcat_classpath = jk_pool_strdup(&p->p, str_config);
+    }
+
+    if (!p->tomcat_classpath) {
+        jk_log(l, JK_LOG_EMERG, "no classpath");
+        JK_TRACE_EXIT(l);
+        return JK_FALSE;
+    }
+
+    if (jk_get_worker_bridge_type(props, p->name, (unsigned int *)&btype)) {
+        p->bridge_type = btype;
+    }
+
+    if (jk_get_worker_jvm_path(props, p->name, &str_config)) {
+        p->jvm_dll_path = jk_pool_strdup(&p->p, str_config);
+    }
+
+    if (!p->jvm_dll_path || !jk_file_exists(p->jvm_dll_path)) {
+        jk_log(l, JK_LOG_EMERG, "no jvm_dll_path");
+        JK_TRACE_EXIT(l);
+        return JK_FALSE;
+    }
+
+    if (jk_get_worker_cmd_line(props, p->name, &str_config)) {
+        p->tomcat_cmd_line = jk_pool_strdup(&p->p, str_config);
+    }
+
+    if (jk_get_worker_stdout(props, p->name, &str_config)) {
+        p->stdout_name = jk_pool_strdup(&p->p, str_config);
+    }
+
+    if (jk_get_worker_stderr(props, p->name, &str_config)) {
+        p->stderr_name = jk_pool_strdup(&p->p, str_config);
+    }
+
+    if (jk_get_worker_sysprops(props, p->name, &str_config)) {
+        p->sysprops = jk_parse_sysprops(&p->p, str_config);
+    }
+
+#ifdef JNI_VERSION_1_2
+    if (jk_get_worker_str_prop(props, p->name, "java2opts", &str_config)) {
+        /* jk_log(l, JK_LOG_DEBUG, "Got opts: %s", str_config); */
+        p->java2opts = jk_parse_sysprops(&p->p, str_config);
+    }
+    if (jk_get_worker_int_prop(props, p->name, "java2lax", &mem_config)) {
+        p->java2lax = mem_config ? JK_TRUE : JK_FALSE;
+    }
+#endif
+
+    if (jk_get_worker_libpath(props, p->name, &str_config)) {
+        jk_append_libpath(&p->p, str_config);
+    }
+
+    if (!load_jvm_dll(p, l)) {
+        jk_log(l, JK_LOG_EMERG, "can't load jvm dll");
+        /* [V] no detach needed here */
+        JK_TRACE_EXIT(l);
+        return JK_FALSE;
+    }
+
+    if (!open_jvm(p, &env, l)) {
+        jk_log(l, JK_LOG_EMERG, "can't open jvm");
+        /* [V] no detach needed here */
+        JK_TRACE_EXIT(l);
+        return JK_FALSE;
+    }
+
+    if (!get_bridge_object(p, env, l)) {
+        jk_log(l, JK_LOG_EMERG, "can't get bridge object");
+        /* [V] the detach here may segfault on 1.1 JVM... */
+        detach_from_jvm(p, l);
+        JK_TRACE_EXIT(l);
+        return JK_FALSE;
+    }
+
+    if (!get_method_ids(p, env, l)) {
+        jk_log(l, JK_LOG_EMERG, "can't get method ids");
+        /* [V] the detach here may segfault on 1.1 JVM... */
+        detach_from_jvm(p, l);
+        JK_TRACE_EXIT(l);
+        return JK_FALSE;
+    }
+
+    p->was_verified = JK_TRUE;
+    p->tmp_env = env;
+
+    JK_TRACE_EXIT(l);
+    return JK_TRUE;
+}
+
+static int JK_METHOD init(jk_worker_t *pThis,
+                          jk_map_t *props,
+                          jk_worker_env_t *we, jk_logger_t *l)
+{
+    jni_worker_t *p;
+    JNIEnv *env;
+
+    JK_TRACE_ENTER(l);
+
+    if (!pThis || !pThis->worker_private) {
+        JK_LOG_NULL_PARAMS(l);
+        JK_TRACE_EXIT(l);
+        return JK_FALSE;
+    }
+
+    p = pThis->worker_private;
+
+    if (p->was_initialized) {
+        jk_log(l, JK_LOG_DEBUG, "done (been here!)");
+        JK_TRACE_EXIT(l);
+        return JK_TRUE;
+    }
+
+    if (!p->jvm ||
+        !p->jk_java_bridge_object ||
+        !p->jk_service_method ||
+        !p->jk_startup_method || !p->jk_shutdown_method) {
+        jk_log(l, JK_LOG_EMERG, "worker not set completely");
+        JK_TRACE_EXIT(l);
+        return JK_FALSE;
+    }
+
+    /* [V] init is called from the same thread that called validate */
+    /* there is no need to attach to the JVM, just get the env */
+
+    /* if(env = attach_to_jvm(p,l)) { */
+    if ((env = p->tmp_env)) {
+        jstring cmd_line = (jstring) NULL;
+        jstring stdout_name = (jstring) NULL;
+        jstring stderr_name = (jstring) NULL;
+        jint rc = 0;
+
+        /* AS400/BS2000 need EBCDIC to ASCII conversion for JNI */
+
+        if (p->tomcat_cmd_line) {
+            cmd_line =
+                (*env)->NewStringUTF(env,
+                                     strdup_ascii(&p->p, p->tomcat_cmd_line));
+        }
+        if (p->stdout_name) {
+            stdout_name =
+                (*env)->NewStringUTF(env,
+                                     strdup_ascii(&p->p, p->stdout_name));
+        }
+        if (p->stderr_name) {
+            stderr_name =
+                (*env)->NewStringUTF(env,
+                                     strdup_ascii(&p->p, p->stderr_name));
+        }
+
+        jk_log(l, JK_LOG_DEBUG,
+               "calling Tomcat to intialize itself...");
+        rc = (*env)->CallIntMethod(env, p->jk_java_bridge_object,
+                                   p->jk_startup_method, cmd_line,
+                                   stdout_name, stderr_name);
+
+        detach_from_jvm(p, l);
+
+        if (rc) {
+            p->was_initialized = JK_TRUE;
+            jk_log(l, JK_LOG_DEBUG, "Tomcat initialized OK, done");
+            JK_TRACE_EXIT(l);
+            return JK_TRUE;
+        }
+        else {
+            jk_log(l, JK_LOG_EMERG, "could not initialize Tomcat");
+            JK_TRACE_EXIT(l);
+            return JK_FALSE;
+        }
+    }
+    else {
+        jk_log(l, JK_LOG_ERROR,
+               "In init, FIXME: init didn't gen env from validate!");
+        JK_TRACE_EXIT(l);
+        return JK_FALSE;
+    }
+}
+
+static int JK_METHOD get_endpoint(jk_worker_t *pThis,
+                                  jk_endpoint_t **pend, jk_logger_t *l)
+{
+    /* [V] This slow, needs replacement */
+    jni_endpoint_t *p;
+
+    JK_TRACE_ENTER(l);
+
+    if (!pThis || !pThis->worker_private || !pend) {
+        JK_LOG_NULL_PARAMS(l);
+        JK_TRACE_EXIT(l);
+        return JK_FALSE;
+    }
+    
+    p = (jni_endpoint_t *) calloc(1, sizeof(jni_endpoint_t));
+    if (p) {
+        p->attached = JK_FALSE;
+        p->env = NULL;
+        p->worker = pThis->worker_private;
+        p->endpoint.endpoint_private = p;
+        p->endpoint.service = service;
+        p->endpoint.done = done;
+        *pend = &p->endpoint;
+
+        JK_TRACE_EXIT(l);
+        return JK_TRUE;
+    }
+    else {
+        jk_log(l, JK_LOG_ERROR,
+               "could not allocate endpoint");
+        JK_TRACE_EXIT(l);
+        return JK_FALSE;
+    }
+}
+
+static int JK_METHOD destroy(jk_worker_t **pThis, jk_logger_t *l)
+{
+    jni_worker_t *p;
+    JNIEnv *env;
+
+    JK_TRACE_ENTER(l);
+
+    if (!pThis || !*pThis || !(*pThis)->worker_private) {
+        JK_LOG_NULL_PARAMS(l);
+        JK_TRACE_EXIT(l);
+        return JK_FALSE;
+    }
+
+    p = (*pThis)->worker_private;
+
+    if (!p->jvm) {
+        jk_log(l, JK_LOG_DEBUG, "JVM not intantiated");
+        JK_TRACE_EXIT(l);
+        return JK_FALSE;
+    }
+
+    if (!p->jk_java_bridge_object || !p->jk_shutdown_method) {
+        jk_log(l, JK_LOG_DEBUG, "Tomcat not intantiated");
+        JK_TRACE_EXIT(l);
+        return JK_FALSE;
+    }
+
+    if ((env = attach_to_jvm(p, l))) {
+        jk_log(l, JK_LOG_DEBUG, "shutting down Tomcat...");
+        (*env)->CallVoidMethod(env,
+                               p->jk_java_bridge_object,
+                               p->jk_shutdown_method);
+        detach_from_jvm(p, l);
+    }
+
+    jk_close_pool(&p->p);
+    free(p);
+
+    jk_log(l, JK_LOG_DEBUG, "destroyed");
+
+    JK_TRACE_EXIT(l);
+    return JK_TRUE;
+}
+
+int JK_METHOD jni_worker_factory(jk_worker_t **w,
+                                 const char *name, jk_logger_t *l)
+{
+    jni_worker_t *private_data;
+
+    JK_TRACE_ENTER(l);
+
+    if (!name || !w) {
+        JK_LOG_NULL_PARAMS(l);
+        JK_TRACE_EXIT(l);
+        return 0;
+    }
+
+    if (the_singleton_jni_worker) {
+        jk_log(l, JK_LOG_DEBUG,
+               "instance already created");
+        *w = the_singleton_jni_worker;
+        JK_TRACE_EXIT(l);
+        return JK_JNI_WORKER_TYPE;
+    }
+
+    private_data = (jni_worker_t *) malloc(sizeof(jni_worker_t));
+
+    if (!private_data) {
+        jk_log(l, JK_LOG_ERROR,
+               "memory allocation error");
+        JK_TRACE_EXIT(l);
+        return 0;
+    }
+
+    jk_open_pool(&private_data->p,
+                 private_data->buf, sizeof(jk_pool_atom_t) * TINY_POOL_SIZE);
+
+    private_data->name = jk_pool_strdup(&private_data->p, name);
+
+    if (!private_data->name) {
+        jk_log(l, JK_LOG_ERROR,
+               "memory allocation error");
+        jk_close_pool(&private_data->p);
+        free(private_data);
+        JK_TRACE_EXIT(l);
+        return 0;
+    }
+
+    private_data->was_verified = JK_FALSE;
+    private_data->was_initialized = JK_FALSE;
+    private_data->jvm = NULL;
+    private_data->tmp_env = NULL;
+    private_data->jk_java_bridge_object = (jobject) NULL;
+    private_data->jk_java_bridge_class = (jclass) NULL;
+    private_data->jk_startup_method = (jmethodID) NULL;
+    private_data->jk_service_method = (jmethodID) NULL;
+    private_data->jk_shutdown_method = (jmethodID) NULL;
+    private_data->tomcat_cmd_line = NULL;
+    private_data->tomcat_classpath = NULL;
+    private_data->bridge_type = TC33_BRIDGE_TYPE;
+    private_data->jvm_dll_path = NULL;
+    private_data->tomcat_ms = 0;
+    private_data->tomcat_mx = 0;
+    private_data->sysprops = NULL;
+#ifdef JNI_VERSION_1_2
+    private_data->java2opts = NULL;
+    private_data->java2lax = JK_TRUE;
+#endif
+    private_data->stdout_name = NULL;
+    private_data->stderr_name = NULL;
+
+    private_data->worker.worker_private = private_data;
+    private_data->worker.validate = validate;
+    private_data->worker.init = init;
+    private_data->worker.get_endpoint = get_endpoint;
+    private_data->worker.destroy = destroy;
+    private_data->worker.retries = JK_RETRIES;
+
+    *w = &private_data->worker;
+    the_singleton_jni_worker = &private_data->worker;
+
+    JK_TRACE_EXIT(l);
+    return JK_JNI_WORKER_TYPE;
+}
+
+static int load_jvm_dll(jni_worker_t * p, jk_logger_t *l)
+{
+#ifdef WIN32
+    HINSTANCE hInst = LoadLibrary(p->jvm_dll_path);
+    if (hInst) {
+        (FARPROC) jni_create_java_vm =
+            GetProcAddress(hInst, "JNI_CreateJavaVM");
+
+        (FARPROC) jni_get_created_java_vms =
+            GetProcAddress(hInst, "JNI_GetCreatedJavaVMs");
+
+        (FARPROC) jni_get_default_java_vm_init_args =
+            GetProcAddress(hInst, "JNI_GetDefaultJavaVMInitArgs");
+
+        jk_log(l, JK_LOG_DEBUG, "Loaded all JNI procs");
+
+        if (jni_create_java_vm && jni_get_default_java_vm_init_args
+            && jni_get_created_java_vms) {
+            return JK_TRUE;
+        }
+
+        FreeLibrary(hInst);
+    }
+#elif defined(NETWARE) && !defined(__NOVELL_LIBC__)
+    int javaNlmHandle = FindNLMHandle("JVM");
+    if (0 == javaNlmHandle) {
+        /* if we didn't get a handle, try to load java and retry getting the */
+        /* handle */
+        spawnlp(P_NOWAIT, "JVM.NLM", NULL);
+        ThreadSwitchWithDelay();
+        javaNlmHandle = FindNLMHandle("JVM");
+        if (0 == javaNlmHandle)
+            printf("Error loading Java.");
+
+    }
+    if (0 != javaNlmHandle) {
+        jni_create_java_vm = ImportSymbol(GetNLMHandle(), "JNI_CreateJavaVM");
+        jni_get_created_java_vms =
+            ImportSymbol(GetNLMHandle(), "JNI_GetCreatedJavaVMs");
+        jni_get_default_java_vm_init_args =
+            ImportSymbol(GetNLMHandle(), "JNI_GetDefaultJavaVMInitArgs");
+    }
+    if (jni_create_java_vm && jni_get_default_java_vm_init_args
+        && jni_get_created_java_vms) {
+        return JK_TRUE;
+    }
+#elif defined(AS400)
+    jk_log(l, JK_LOG_DEBUG,
+           "Direct reference to JNI entry points (no SRVPGM)");
+    jni_create_java_vm = &JNI_CreateJavaVM;
+    jni_get_default_java_vm_init_args = &JNI_GetDefaultJavaVMInitArgs;
+    jni_get_created_java_vms = &JNI_GetCreatedJavaVMs;
+#else
+    void *handle;
+    jk_log(l, JK_LOG_DEBUG, "loading JVM %s", p->jvm_dll_path);
+
+    handle = dlopen(p->jvm_dll_path, RTLD_NOW | RTLD_GLOBAL);
+
+    if (!handle) {
+        jk_log(l, JK_LOG_EMERG,
+               "Can't load native library %s : %s", p->jvm_dll_path,
+               dlerror());
+    }
+    else {
+        jni_create_java_vm = dlsym(handle, "JNI_CreateJavaVM");
+        jni_get_default_java_vm_init_args =
+            dlsym(handle, "JNI_GetDefaultJavaVMInitArgs");
+        jni_get_created_java_vms = dlsym(handle, "JNI_GetCreatedJavaVMs");
+
+        if (jni_create_java_vm && jni_get_default_java_vm_init_args &&
+            jni_get_created_java_vms) {
+            jk_log(l, JK_LOG_DEBUG,
+                   "In load_jvm_dll, symbols resolved, done");
+            return JK_TRUE;
+        }
+        jk_log(l, JK_LOG_EMERG,
+               "Can't resolve JNI_CreateJavaVM or JNI_GetDefaultJavaVMInitArgs");
+        dlclose(handle);
+    }
+#endif
+    return JK_FALSE;
+}
+
+static int open_jvm(jni_worker_t * p, JNIEnv ** env, jk_logger_t *l)
+{
+#ifdef JNI_VERSION_1_2
+    int jvm_version = detect_jvm_version(l);
+
+    switch (jvm_version) {
+    case JNI_VERSION_1_1:
+        return open_jvm1(p, env, l);
+    case JNI_VERSION_1_2:
+        return open_jvm2(p, env, l);
+    default:
+        return JK_FALSE;
+    }
+#else
+    /* [V] Make sure this is _really_ visible */
+#warning -------------------------------------------------------
+#warning NO JAVA 2 HEADERS! SUPPORT FOR JAVA 2 FEATURES DISABLED
+#warning -------------------------------------------------------
+    return open_jvm1(p, env, l);
+#endif
+}
+
+static int open_jvm1(jni_worker_t * p, JNIEnv ** env, jk_logger_t *l)
+{
+    JDK1_1InitArgs vm_args;
+    JNIEnv *penv;
+    int err;
+    *env = NULL;
+
+    JK_TRACE_ENTER(l);
+
+    vm_args.version = JNI_VERSION_1_1;
+
+    if (0 != jni_get_default_java_vm_init_args(&vm_args)) {
+        jk_log(l, JK_LOG_EMERG, "can't get default vm init args");
+        JK_TRACE_EXIT(l);
+        return JK_FALSE;
+    }
+    jk_log(l, JK_LOG_DEBUG, "got default jvm args");
+
+    if (vm_args.classpath) {
+        size_t len = strlen(vm_args.classpath) +
+            strlen(p->tomcat_classpath) + 3;
+        char *tmp = jk_pool_alloc(&p->p, len);
+        if (tmp) {
+            sprintf(tmp, "%s%c%s",
+                    strdup_ascii(&p->p, p->tomcat_classpath),
+                    PATH_SEPERATOR, vm_args.classpath);
+            p->tomcat_classpath = tmp;
+        }
+        else {
+            jk_log(l, JK_LOG_EMERG,
+                   "allocation error for classpath");
+            JK_TRACE_EXIT(l);
+            return JK_FALSE;
+        }
+    }
+    vm_args.classpath = p->tomcat_classpath;
+
+    if (p->tomcat_mx) {
+        vm_args.maxHeapSize = p->tomcat_mx;
+    }
+
+    if (p->tomcat_ms) {
+        vm_args.minHeapSize = p->tomcat_ms;
+    }
+
+    if (p->sysprops) {
+        /* No EBCDIC to ASCII conversion here for AS/400 - later */
+        vm_args.properties = p->sysprops;
+    }
+
+    jk_log(l, JK_LOG_DEBUG, "In open_jvm1, about to create JVM...");
+    if ((err = jni_create_java_vm(&(p->jvm), &penv, &vm_args)) != 0) {
+        jk_log(l, JK_LOG_EMERG,
+               "could not create JVM, code: %d ", err);
+        JK_TRACE_EXIT(l);
+        return JK_FALSE;
+    }
+    jk_log(l, JK_LOG_DEBUG, "JVM created, done");
+
+    *env = penv;
+
+    JK_TRACE_EXIT(l);
+    return JK_TRUE;
+}
+
+#ifdef JNI_VERSION_1_2
+static int detect_jvm_version(jk_logger_t *l)
+{
+    JNIEnv *env = NULL;
+    JDK1_1InitArgs vm_args;
+
+    JK_TRACE_ENTER(l);
+
+    /* [V] Idea: ask for 1.2. If the JVM is 1.1 it will return 1.1 instead  */
+    /*     Note: asking for 1.1 won't work, 'cause 1.2 JVMs will return 1.1 */
+    vm_args.version = JNI_VERSION_1_2;
+
+    if (0 != jni_get_default_java_vm_init_args(&vm_args)) {
+        jk_log(l, JK_LOG_EMERG, "can't get default vm init args");
+        JK_TRACE_EXIT(l);
+        return JK_FALSE;
+    }
+    jk_log(l, JK_LOG_DEBUG,
+           "found version: %X, done", vm_args.version);
+
+    JK_TRACE_EXIT(l);
+    return vm_args.version;
+}
+
+static char *build_opt_str(jk_pool_t *p,
+                           char *opt_name, char *opt_value, jk_logger_t *l)
+{
+    size_t len = strlen(opt_name) + strlen(opt_value) + 2;
+
+    /* [V] IMHO, these should not be deallocated as long as the JVM runs */
+    char *tmp = jk_pool_alloc(p, len);
+
+    if (tmp) {
+        sprintf(tmp, "%s%s", opt_name, opt_value);
+        return tmp;
+    }
+    else {
+        jk_log(l, JK_LOG_EMERG,
+               "allocation error for %s", opt_name);
+        return NULL;
+    }
+}
+
+static char *build_opt_int(jk_pool_t *p,
+                           char *opt_name, int opt_value, jk_logger_t *l)
+{
+    /* [V] this should suffice even for 64-bit int */
+    size_t len = strlen(opt_name) + 20 + 2;
+    /* [V] IMHO, these should not be deallocated as long as the JVM runs */
+    char *tmp = jk_pool_alloc(p, len);
+
+    if (tmp) {
+        sprintf(tmp, "%s%d", opt_name, opt_value);
+        return tmp;
+    }
+    else {
+        jk_log(l, JK_LOG_EMERG,
+               "allocation error for %s", opt_name);
+        return NULL;
+    }
+}
+
+static int open_jvm2(jni_worker_t * p, JNIEnv ** env, jk_logger_t *l)
+{
+    JavaVMInitArgs vm_args;
+    JNIEnv *penv = NULL;
+    JavaVMOption options[100];
+    int optn = 0, err;
+    char *tmp;
+
+    *env = NULL;
+
+    JK_TRACE_ENTER(l);
+
+    vm_args.version = JNI_VERSION_1_2;
+    vm_args.options = options;
+
+/* AS/400 need EBCDIC to ASCII conversion to parameters passed to JNI */
+/* No conversion for ASCII based systems (what about BS2000 ?) */
+
+    if (p->tomcat_classpath) {
+        jk_log(l, JK_LOG_DEBUG, "setting classpath to %s",
+               p->tomcat_classpath);
+        tmp =
+            build_opt_str(&p->p, "-Djava.class.path=", p->tomcat_classpath,
+                          l);
+        null_check(tmp);
+        options[optn++].optionString = strdup_ascii(&p->p, tmp);
+    }
+
+    if (p->tomcat_mx) {
+        jk_log(l, JK_LOG_DEBUG, "setting max heap to %d",
+               p->tomcat_mx);
+        tmp = build_opt_int(&p->p, "-Xmx", p->tomcat_mx, l);
+        null_check(tmp);
+        options[optn++].optionString = strdup_ascii(&p->p, tmp);
+    }
+
+    if (p->tomcat_ms) {
+        jk_log(l, JK_LOG_DEBUG, "setting start heap to %d",
+               p->tomcat_ms);
+        tmp = build_opt_int(&p->p, "-Xms", p->tomcat_ms, l);
+        null_check(tmp);
+        options[optn++].optionString = strdup_ascii(&p->p, tmp);
+    }
+
+    if (p->sysprops) {
+        int i = 0;
+        while (p->sysprops[i]) {
+            jk_log(l, JK_LOG_DEBUG, "setting %s",
+                   p->sysprops[i]);
+            tmp = build_opt_str(&p->p, "-D", p->sysprops[i], l);
+            null_check(tmp);
+            options[optn++].optionString = strdup_ascii(&p->p, tmp);
+            i++;
+        }
+    }
+
+    if (p->java2opts) {
+        int i = 0;
+
+        while (p->java2opts[i]) {
+            jk_log(l, JK_LOG_DEBUG, "using option: %s",
+                   p->java2opts[i]);
+            /* Pass it "as is" */
+            options[optn++].optionString =
+                strdup_ascii(&p->p, p->java2opts[i++]);
+        }
+    }
+
+    vm_args.nOptions = optn;
+
+    if (p->java2lax) {
+        jk_log(l, JK_LOG_DEBUG,
+               "the JVM will ignore unknown options");
+        vm_args.ignoreUnrecognized = JNI_TRUE;
+    }
+    else {
+        jk_log(l, JK_LOG_DEBUG,
+               "the JVM will FAIL if it finds unknown options");
+        vm_args.ignoreUnrecognized = JNI_FALSE;
+    }
+
+    jk_log(l, JK_LOG_DEBUG, "about to create JVM...");
+
+    err = jni_create_java_vm(&(p->jvm), &penv, &vm_args);
+
+    if (JNI_EEXIST == err) {
+#ifdef AS400
+        long vmCount;
+#else
+        int vmCount;
+#endif
+        jk_log(l, JK_LOG_DEBUG, "JVM alread instantiated."
+               "Trying to attach instead.");
+
+        jni_get_created_java_vms(&(p->jvm), 1, &vmCount);
+        if (NULL != p->jvm)
+            penv = attach_to_jvm(p, l);
+
+        if (NULL != penv)
+            err = 0;
+    }
+
+    if (err != 0) {
+        jk_log(l, JK_LOG_EMERG, "Fail-> could not create JVM, code: %d ",
+               err);
+        JK_TRACE_EXIT(l);
+        return JK_FALSE;
+    }
+
+    *env = penv;
+    jk_log(l, JK_LOG_DEBUG, "JVM created");
+
+    JK_TRACE_EXIT(l);
+    return JK_TRUE;
+}
+#endif
+
+static int get_bridge_object(jni_worker_t * p, JNIEnv * env, jk_logger_t *l)
+{
+    char *btype;
+    char *ctype;
+
+    jmethodID constructor_method_id;
+
+    JK_TRACE_ENTER(l);
+
+    switch (p->bridge_type) {
+    case TC32_BRIDGE_TYPE:
+        btype = TC32_JAVA_BRIDGE_CLASS_NAME;
+        break;
+
+    case TC33_BRIDGE_TYPE:
+        btype = TC33_JAVA_BRIDGE_CLASS_NAME;
+        break;
+
+    case TC40_BRIDGE_TYPE:
+    case TC41_BRIDGE_TYPE:
+    case TC50_BRIDGE_TYPE:
+        jk_log(l, JK_LOG_EMERG, "Bridge type %d not supported",
+               p->bridge_type);
+        JK_TRACE_EXIT(l);
+        return JK_FALSE;
+    }
+
+/* AS400/BS2000 need conversion from EBCDIC to ASCII before passing to JNI */
+/* for others, strdup_ascii is just jk_pool_strdup */
+
+    ctype = strdup_ascii(&p->p, btype);
+
+    p->jk_java_bridge_class = (*env)->FindClass(env, ctype);
+
+    if (!p->jk_java_bridge_class) {
+        jk_log(l, JK_LOG_EMERG, "Can't find class %s", btype);
+        JK_TRACE_EXIT(l);
+        return JK_FALSE;
+    }
+    jk_log(l, JK_LOG_DEBUG,
+           "In get_bridge_object, loaded %s bridge class", btype);
+
+    constructor_method_id = (*env)->GetMethodID(env, p->jk_java_bridge_class, strdup_ascii(&p->p, "<init>"),    /* method name */
+                                                strdup_ascii(&p->p, "()V"));    /* method sign */
+
+    if (!constructor_method_id) {
+        p->jk_java_bridge_class = (jclass) NULL;
+        jk_log(l, JK_LOG_EMERG, "Can't find constructor");
+        JK_TRACE_EXIT(l);
+        return JK_FALSE;
+    }
+
+    p->jk_java_bridge_object = (*env)->NewObject(env,
+                                                 p->jk_java_bridge_class,
+                                                 constructor_method_id);
+    if (!p->jk_java_bridge_object) {
+        p->jk_java_bridge_class = (jclass) NULL;
+        jk_log(l, JK_LOG_EMERG, "Can't create new bridge object");
+        JK_TRACE_EXIT(l);
+        return JK_FALSE;
+    }
+
+    p->jk_java_bridge_object =
+        (jobject) (*env)->NewGlobalRef(env, p->jk_java_bridge_object);
+    if (!p->jk_java_bridge_object) {
+        jk_log(l, JK_LOG_EMERG, "Can't create global ref to bridge object");
+        p->jk_java_bridge_class = (jclass) NULL;
+        p->jk_java_bridge_object = (jobject) NULL;
+        JK_TRACE_EXIT(l);
+        return JK_FALSE;
+    }
+
+    JK_TRACE_EXIT(l);
+    return JK_TRUE;
+}
+
+static int get_method_ids(jni_worker_t * p, JNIEnv * env, jk_logger_t *l)
+{
+
+/* AS400/BS2000 need conversion from EBCDIC to ASCII before passing to JNI */
+
+    p->jk_startup_method = (*env)->GetMethodID(env,
+                                               p->jk_java_bridge_class,
+                                               strdup_ascii(&p->p, "startup"),
+                                               strdup_ascii(&p->p,
+                                                            "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)I"));
+
+    if (!p->jk_startup_method) {
+        jk_log(l, JK_LOG_EMERG, "Can't find startup()");
+        return JK_FALSE;
+    }
+
+    p->jk_service_method = (*env)->GetMethodID(env,
+                                               p->jk_java_bridge_class,
+                                               strdup_ascii(&p->p, "service"),
+                                               strdup_ascii(&p->p, "(JJ)I"));
+
+    if (!p->jk_service_method) {
+        jk_log(l, JK_LOG_EMERG, "Can't find service()");
+        return JK_FALSE;
+    }
+
+    p->jk_shutdown_method = (*env)->GetMethodID(env,
+                                                p->jk_java_bridge_class,
+                                                strdup_ascii(&p->p,
+                                                             "shutdown"),
+                                                strdup_ascii(&p->p, "()V"));
+
+    if (!p->jk_shutdown_method) {
+        jk_log(l, JK_LOG_EMERG, "Can't find shutdown()");
+        return JK_FALSE;
+    }
+
+    return JK_TRUE;
+}
+
+static JNIEnv *attach_to_jvm(jni_worker_t * p, jk_logger_t *l)
+{
+    JNIEnv *rc = NULL;
+    /* [V] This message is important. If there are signal mask issues,    *
+     *     the JVM usually hangs when a new thread tries to attach to it  */
+    JK_TRACE_ENTER(l);
+
+#if defined LINUX && defined APACHE2_SIGHACK
+    linux_signal_hack();
+#endif
+
+    if (0 == (*(p->jvm))->AttachCurrentThread(p->jvm,
+#ifdef JNI_VERSION_1_2
+                                              (void **)
+#endif
+                                              &rc, NULL)) {
+        jk_log(l, JK_LOG_DEBUG, "In attach_to_jvm, attached ok");
+        JK_TRACE_EXIT(l);
+        return rc;
+    }
+    jk_log(l, JK_LOG_ERROR,
+           "In attach_to_jvm, cannot attach thread to JVM.");
+    JK_TRACE_EXIT(l);
+    return NULL;
+}
+
+/*
+static JNIEnv *attach_to_jvm(jni_worker_t *p)
+{
+    JNIEnv *rc = NULL;
+
+#ifdef LINUX
+    linux_signal_hack();
+#endif    
+
+    if(0 == (*(p->jvm))->AttachCurrentThread(p->jvm, 
+#ifdef JNI_VERSION_1_2 
+           (void **)
+#endif
+                                             &rc, 
+                                             NULL)) {
+        return rc;
+    }
+
+    return NULL;
+}
+*/
+static void detach_from_jvm(jni_worker_t * p, jk_logger_t *l)
+{
+    JK_TRACE_ENTER(l);
+    if (!p->jvm || !(*(p->jvm))) {
+        jk_log(l, JK_LOG_ERROR,
+               "cannot detach from NULL JVM.");
+    }
+
+    if (0 == (*(p->jvm))->DetachCurrentThread(p->jvm)) {
+        jk_log(l, JK_LOG_DEBUG, "detached ok");
+    }
+    else {
+        jk_log(l, JK_LOG_ERROR,
+               "cannot detach from JVM.");
+    }
+    JK_TRACE_EXIT(l);
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_jni_worker.h
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_jni_worker.h	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_jni_worker.h	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,44 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.
+ */
+
+/***************************************************************************
+ * Description: jni worker header file                                 *
+ * Author:      Gal Shachor <shachor at il.ibm.com>                           *
+ * Version:     $Revision: 300224 $                                               *
+ ***************************************************************************/
+
+#ifndef JK_JNI_WORKER_H
+#define JK_JNI_WORKER_H
+
+#include "jk_logger.h"
+#include "jk_service.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif                          /* __cplusplus */
+
+#define JK_JNI_WORKER_NAME  ("jni")
+#define JK_JNI_WORKER_TYPE  (4)
+
+int JK_METHOD jni_worker_factory(jk_worker_t **w,
+                                 const char *name, jk_logger_t *l);
+
+#ifdef __cplusplus
+}
+#endif                          /* __cplusplus */
+
+#endif                          /* JK_JNI_WORKER_H */

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_lb_worker.c
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_lb_worker.c	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_lb_worker.c	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,1325 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.
+ */
+
+/***************************************************************************
+ * Description: Load balancer worker, knows how to load balance among      *
+ *              several workers.                                           *
+ * Author:      Gal Shachor <shachor at il.ibm.com>                           *
+ * Author:      Mladen Turk <mturk at apache.org>                             *
+ * Author:      Rainer Jung <rjung at apache.org>                             *
+ * Based on:                                                               *
+ * Version:     $Revision: 441433 $                                          *
+ ***************************************************************************/
+
+#include "jk_pool.h"
+#include "jk_service.h"
+#include "jk_util.h"
+#include "jk_worker.h"
+#include "jk_lb_worker.h"
+#include "jk_ajp13.h"
+#include "jk_ajp13_worker.h"
+#include "jk_ajp14_worker.h"
+#include "jk_mt.h"
+#include "jk_shm.h"
+
+/*
+ * The load balancing code in this
+ */
+
+#define JK_WORKER_USABLE(w)   ((w)->state != JK_LB_STATE_ERROR && (w)->state != JK_LB_STATE_BUSY && (w)->activation != JK_LB_ACTIVATION_STOPPED && (w)->activation != JK_LB_ACTIVATION_DISABLED)
+#define JK_WORKER_USABLE_STICKY(w)   ((w)->state != JK_LB_STATE_ERROR && (w)->activation != JK_LB_ACTIVATION_STOPPED)
+
+static const char *lb_locking_type[] = {
+    "unknown",
+    JK_LB_LOCK_TEXT_OPTIMISTIC,
+    JK_LB_LOCK_TEXT_PESSIMISTIC,
+    NULL
+};
+
+static const char *lb_method_type[] = {
+    "unknown",
+    JK_LB_METHOD_TEXT_REQUESTS,
+    JK_LB_METHOD_TEXT_TRAFFIC,
+    JK_LB_METHOD_TEXT_BUSYNESS,
+    NULL
+};
+
+static const char *lb_state_type[] = {
+    "unknown",
+    JK_LB_STATE_TEXT_NA,
+    JK_LB_STATE_TEXT_OK,
+    JK_LB_STATE_TEXT_RECOVER,
+    JK_LB_STATE_TEXT_BUSY,
+    JK_LB_STATE_TEXT_ERROR,
+    NULL
+};
+
+static const char *lb_activation_type[] = {
+    "unknown",
+    JK_LB_ACTIVATION_TEXT_ACTIVE,
+    JK_LB_ACTIVATION_TEXT_DISABLED,
+    JK_LB_ACTIVATION_TEXT_STOPPED,
+    NULL
+};
+
+struct lb_endpoint
+{
+    jk_endpoint_t *e;
+    lb_worker_t *worker;
+
+    jk_endpoint_t endpoint;
+};
+typedef struct lb_endpoint lb_endpoint_t;
+
+
+/* Calculate the greatest common divisor of two positive integers */
+static jk_uint64_t gcd(jk_uint64_t a, jk_uint64_t b)
+{
+    jk_uint64_t r;
+    if (b > a) {
+        r = a;
+        a = b;
+        b = r;
+    }
+    while (b > 0) {
+        r = a % b;
+        a = b;
+        b = r;
+    }
+    return a;
+}
+
+/* Calculate the smallest common multiple of two positive integers */
+static jk_uint64_t scm(jk_uint64_t a, jk_uint64_t b)
+{
+    return a * b / gcd(a, b);
+}
+
+/* Return the string representation of the lb lock type */
+const char *jk_lb_get_lock(lb_worker_t *p, jk_logger_t *l)
+{
+    return lb_locking_type[p->lblock];
+}
+
+/* Return the string representation of the lb method type */
+const char *jk_lb_get_method(lb_worker_t *p, jk_logger_t *l)
+{
+    return lb_method_type[p->lbmethod];
+}
+
+/* Return the string representation of the balance worker state */
+const char *jk_lb_get_state(worker_record_t *p, jk_logger_t *l)
+{
+    return lb_state_type[p->s->state];
+}
+
+/* Return the string representation of the balance worker activation */
+const char *jk_lb_get_activation(worker_record_t *p, jk_logger_t *l)
+{
+    return lb_activation_type[p->s->activation];
+}
+
+/* Update the load multipliers wrt. lb_factor */
+void update_mult(lb_worker_t *p, jk_logger_t *l)
+{
+    unsigned int i = 0;
+    jk_uint64_t s = 1;
+    JK_TRACE_ENTER(l);
+    for (i = 0; i < p->num_of_workers; i++) {
+        s = scm(s, p->lb_workers[i].s->lb_factor);
+    }
+    for (i = 0; i < p->num_of_workers; i++) {
+        p->lb_workers[i].s->lb_mult = s / p->lb_workers[i].s->lb_factor;
+        if (JK_IS_DEBUG_LEVEL(l))
+            jk_log(l, JK_LOG_DEBUG,
+                   "worker %s gets multiplicity %"
+                   JK_UINT64_T_FMT,
+                   p->lb_workers[i].s->name,
+                   p->lb_workers[i].s->lb_mult);
+    }
+    JK_TRACE_EXIT(l);
+}
+
+/* Reset all lb values.
+ */
+void reset_lb_values(lb_worker_t *p, jk_logger_t *l)
+{
+    unsigned int i = 0;
+    JK_TRACE_ENTER(l);
+    if (p->lbmethod != JK_LB_METHOD_BUSYNESS) {
+        for (i = 0; i < p->num_of_workers; i++) {
+            p->lb_workers[i].s->lb_value = 0;
+        }
+    }
+}
+
+/* Retrieve the parameter with the given name                                */
+static char *get_path_param(jk_ws_service_t *s, const char *name)
+{
+    char *id_start = NULL;
+    for (id_start = strstr(s->req_uri, name);
+         id_start; id_start = strstr(id_start + 1, name)) {
+        if (id_start[strlen(name)] == '=') {
+            /*
+             * Session path-cookie was found, get it's value
+             */
+            id_start += (1 + strlen(name));
+            if (strlen(id_start)) {
+                char *id_end;
+                id_start = jk_pool_strdup(s->pool, id_start);
+                /*
+                 * The query string is not part of req_uri, however
+                 * to be on the safe side lets remove the trailing query
+                 * string if appended...
+                 */
+                if ((id_end = strchr(id_start, '?')) != NULL) {
+                    *id_end = '\0';
+                }
+                /*
+                 * Remove any trailing path element.
+                 */
+                if ((id_end = strchr(id_start, ';')) != NULL) {
+                    *id_end = '\0';
+                }
+                return id_start;
+            }
+        }
+    }
+
+    return NULL;
+}
+
+/* Retrieve the cookie with the given name                                   */
+static char *get_cookie(jk_ws_service_t *s, const char *name)
+{
+    unsigned i;
+    char *result = NULL;
+
+    for (i = 0; i < s->num_headers; i++) {
+        if (strcasecmp(s->headers_names[i], "cookie") == 0) {
+
+            char *id_start;
+            for (id_start = strstr(s->headers_values[i], name);
+                 id_start; id_start = strstr(id_start + 1, name)) {
+                if (id_start == s->headers_values[i] ||
+                    id_start[-1] == ';' ||
+                    id_start[-1] == ',' || isspace(id_start[-1])) {
+                    id_start += strlen(name);
+                    while (*id_start && isspace(*id_start))
+                        ++id_start;
+                    if (*id_start == '=' && id_start[1]) {
+                        /*
+                         * Session cookie was found, get it's value
+                         */
+                        char *id_end;
+                        ++id_start;
+                        id_start = jk_pool_strdup(s->pool, id_start);
+                        if ((id_end = strchr(id_start, ';')) != NULL) {
+                            *id_end = '\0';
+                        }
+                        if ((id_end = strchr(id_start, ',')) != NULL) {
+                            *id_end = '\0';
+                        }
+                        if (result == NULL) {
+                            result = id_start;
+                        }
+                        else {
+                            size_t osz = strlen(result) + 1;
+                            size_t sz = osz + strlen(id_start) + 1;
+                            result =
+                                jk_pool_realloc(s->pool, sz, result, osz);
+                            strcat(result, ";");
+                            strcat(result, id_start);
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    return result;
+}
+
+
+/* Retrieve session id from the cookie or the parameter
+ * (parameter first)
+ */
+static char *get_sessionid(jk_ws_service_t *s)
+{
+    char *val;
+    val = get_path_param(s, JK_PATH_SESSION_IDENTIFIER);
+    if (!val) {
+        val = get_cookie(s, JK_SESSION_IDENTIFIER);
+    }
+    return val;
+}
+
+static void close_workers(lb_worker_t * p, int num_of_workers, jk_logger_t *l)
+{
+    int i = 0;
+    for (i = 0; i < num_of_workers; i++) {
+        p->lb_workers[i].w->destroy(&(p->lb_workers[i].w), l);
+    }
+}
+
+/* If the worker is in error state run
+ * retry on that worker. It will be marked as
+ * operational if the retry timeout is elapsed.
+ * The worker might still be unusable, but we try
+ * anyway.
+ * If the worker is in ok state and got no requests
+ * since the last global maintenance, we mark its
+ * state as not available.
+ */
+static void recover_workers(lb_worker_t *p,
+                            jk_uint64_t curmax,
+                            time_t now,
+                            jk_logger_t *l)
+{
+    unsigned int i;
+    int elapsed;
+    worker_record_t *w = NULL;
+    JK_TRACE_ENTER(l);
+
+    for (i = 0; i < p->num_of_workers; i++) {
+        w = &p->lb_workers[i];
+        if (w->s->state == JK_LB_STATE_ERROR) {
+            elapsed = (int)difftime(now, w->s->error_time);
+            if (elapsed <= p->s->recover_wait_time) {
+                if (JK_IS_DEBUG_LEVEL(l))
+                    jk_log(l, JK_LOG_DEBUG,
+                           "worker %s will recover in %d seconds",
+                           w->s->name, p->s->recover_wait_time - elapsed);
+            }
+            else {
+                if (JK_IS_DEBUG_LEVEL(l))
+                    jk_log(l, JK_LOG_DEBUG,
+                           "worker %s is marked for recovery",
+                           w->s->name);
+                w->s->lb_value = curmax;
+                w->s->state = JK_LB_STATE_RECOVER;
+            }
+        }
+        else {
+            if (w->s->state == JK_LB_STATE_OK &&
+                w->s->elected == w->s->elected_snapshot)
+                w->s->state = JK_LB_STATE_NA;
+        }
+        w->s->elected_snapshot = w->s->elected;
+    }
+
+    JK_TRACE_EXIT(l);
+}
+
+static int force_recovery(lb_worker_t *p,
+                          jk_logger_t *l)
+{
+    unsigned int i;
+    int forced = 0;
+    worker_record_t *w = NULL;
+    JK_TRACE_ENTER(l);
+
+    for (i = 0; i < p->num_of_workers; i++) {
+        w = &p->lb_workers[i];
+        if (w->s->state == JK_LB_STATE_ERROR) {
+            if (JK_IS_DEBUG_LEVEL(l))
+                jk_log(l, JK_LOG_INFO,
+                       "worker %s is marked for recovery",
+                       w->s->name);
+            w->s->state = JK_LB_STATE_RECOVER;
+            forced++;
+        }
+    }
+
+    JK_TRACE_EXIT(l);
+    return forced;
+}
+
+/* Divide old load values by the decay factor,
+ * such that older values get less important
+ * for the routing decisions.
+ */
+static jk_uint64_t decay_load(lb_worker_t *p,
+                              time_t exponent,
+                              jk_logger_t *l)
+{
+    unsigned int i;
+    jk_uint64_t curmax = 0;
+
+    JK_TRACE_ENTER(l);
+    if (p->lbmethod != JK_LB_METHOD_BUSYNESS) {
+        for (i = 0; i < p->num_of_workers; i++) {
+            p->lb_workers[i].s->lb_value >>= exponent;
+            if (p->lb_workers[i].s->lb_value > curmax) {
+                curmax = p->lb_workers[i].s->lb_value;
+            }
+        }
+    }
+    JK_TRACE_EXIT(l);
+    return curmax;
+}
+
+static int JK_METHOD maintain_workers(jk_worker_t *p, time_t now, jk_logger_t *l)
+{
+    unsigned int i = 0;
+    jk_uint64_t curmax = 0;
+    long delta;
+
+    JK_TRACE_ENTER(l);
+    if (p && p->worker_private) {
+        unsigned int n = 0;
+        lb_worker_t *lb = (lb_worker_t *)p->worker_private;
+
+        for (i = 0; i < lb->num_of_workers; i++) {
+            if (lb->lb_workers[i].w->maintain) {
+                lb->lb_workers[i].w->maintain(lb->lb_workers[i].w, now, l);
+            }
+        }
+
+        jk_shm_lock();
+
+        /* Now we check for global maintenance (once for all processes).
+         * Checking workers for recovery and applying decay to the
+         * load values should not be done by each process individually.
+         * Therefore we globally sync and we use a global timestamp.
+         * Since it's possible that we come here a few milliseconds
+         * before the interval has passed, we allow a little tolerance.
+         */
+        delta = (long)difftime(now, lb->s->last_maintain_time) + JK_LB_MAINTAIN_TOLERANCE;
+        if (delta >= lb->maintain_time) {
+            lb->s->last_maintain_time = now;
+            if (JK_IS_DEBUG_LEVEL(l))
+                jk_log(l, JK_LOG_DEBUG,
+                       "decay with 2^%d",
+                       JK_LB_DECAY_MULT * delta / lb->maintain_time);
+            curmax = decay_load(lb, JK_LB_DECAY_MULT * delta / lb->maintain_time, l);
+            recover_workers(lb, curmax, now, l);
+        }
+
+        for (i = 0; i < lb->num_of_workers; i++) {
+            if (lb->lb_workers[i].s->state != JK_LB_STATE_ERROR) {
+                ++n;
+            }
+        }
+        if (!n) {
+            force_recovery(lb, l);    
+        }
+        jk_shm_unlock();
+
+    }
+    else {
+        JK_LOG_NULL_PARAMS(l);
+    }
+
+    JK_TRACE_EXIT(l);
+    return JK_TRUE;
+}
+
+static worker_record_t *find_by_session(lb_worker_t *p,
+                                        const char *name,
+                                        jk_logger_t *l)
+{
+
+    worker_record_t *rc = NULL;
+    unsigned int i;
+
+    for (i = 0; i < p->num_of_workers; i++) {
+        if (strcmp(p->lb_workers[i].s->jvm_route, name) == 0) {
+            rc = &p->lb_workers[i];
+            rc->r = &(rc->s->jvm_route[0]);
+            break;
+        }
+    }
+    return rc;
+}
+
+static worker_record_t *find_best_bydomain(lb_worker_t *p,
+                                           const char *domain,
+                                           jk_logger_t *l)
+{
+    unsigned int i;
+    int d = 0;
+    jk_uint64_t curmin = 0;
+
+    worker_record_t *candidate = NULL;
+
+    /* First try to see if we have available candidate */
+    for (i = 0; i < p->num_of_workers; i++) {
+        /* Skip all workers that are not member of domain */
+        if (strlen(p->lb_workers[i].s->domain) == 0 ||
+            strcmp(p->lb_workers[i].s->domain, domain))
+            continue;
+        /* Take into calculation only the workers that are
+         * not in error state, stopped, disabled or busy.
+         */
+        if (JK_WORKER_USABLE(p->lb_workers[i].s)) {
+            if (!candidate || p->lb_workers[i].s->distance < d ||
+                (p->lb_workers[i].s->lb_value < curmin &&
+                p->lb_workers[i].s->distance == d)) {
+                candidate = &p->lb_workers[i];
+                curmin = p->lb_workers[i].s->lb_value;
+                d = p->lb_workers[i].s->distance;
+            }
+        }
+    }
+
+    if (candidate) {
+        candidate->r = &(candidate->s->domain[0]);
+    }
+
+    return candidate;
+}
+
+
+static worker_record_t *find_best_byvalue(lb_worker_t *p,
+                                          jk_logger_t *l)
+{
+    static unsigned int next_offset = 0;
+    unsigned int i;
+    unsigned int j;
+    unsigned int offset;
+    int d = 0;
+    jk_uint64_t curmin = 0;
+
+    /* find the least busy worker */
+    worker_record_t *candidate = NULL;
+
+    offset = next_offset;
+
+    /* First try to see if we have available candidate */
+    for (j = offset; j < p->num_of_workers + offset; j++) {
+        i = j % p->num_of_workers;
+
+        /* Take into calculation only the workers that are
+         * not in error state, stopped, disabled or busy.
+         */
+        if (JK_WORKER_USABLE(p->lb_workers[i].s)) {
+            if (!candidate || p->lb_workers[i].s->distance < d ||
+                (p->lb_workers[i].s->lb_value < curmin &&
+                p->lb_workers[i].s->distance == d)) {
+                candidate = &p->lb_workers[i];
+                curmin = p->lb_workers[i].s->lb_value;
+                d = p->lb_workers[i].s->distance;
+                next_offset = i + 1;
+            }
+        }
+    }
+    return candidate;
+}
+
+static worker_record_t *find_bysession_route(lb_worker_t *p,
+                                             const char *name,
+                                             jk_logger_t *l)
+{
+    int uses_domain  = 0;
+    worker_record_t *candidate = NULL;
+
+    candidate = find_by_session(p, name, l);
+    if (!candidate) {
+        uses_domain = 1;
+        candidate = find_best_bydomain(p, name, l);
+    }
+    if (candidate) {
+        if (!JK_WORKER_USABLE_STICKY(candidate->s)) {
+            /* We have a worker that is error state or stopped.
+             * If it has a redirection set use that redirection worker.
+             * This enables to safely remove the member from the
+             * balancer. Of course you will need a some kind of
+             * session replication between those two remote.
+             */
+            if (p->s->sticky_session_force)
+                candidate = NULL;
+            else if (*candidate->s->redirect)
+                candidate = find_by_session(p, candidate->s->redirect, l);
+            else if (*candidate->s->domain && !uses_domain) {
+                uses_domain = 1;
+                candidate = find_best_bydomain(p, candidate->s->domain, l);
+            }
+            if (candidate && !JK_WORKER_USABLE_STICKY(candidate->s))
+                candidate = NULL;
+        }
+    }
+    return candidate;
+}
+
+static worker_record_t *find_failover_worker(lb_worker_t * p,
+                                             jk_logger_t *l)
+{
+    worker_record_t *rc = NULL;
+    unsigned int i;
+    const char *redirect = NULL;
+
+    for (i = 0; i < p->num_of_workers; i++) {
+        if (strlen(p->lb_workers[i].s->redirect)) {
+            redirect = &(p->lb_workers[i].s->redirect[0]);
+            break;
+        }
+    }
+    if (redirect)
+        rc = find_bysession_route(p, redirect, l);
+    return rc;
+}
+
+static worker_record_t *find_best_worker(lb_worker_t * p,
+                                         jk_logger_t *l)
+{
+    worker_record_t *rc = NULL;
+
+    rc = find_best_byvalue(p, l);
+    /* By default use worker jvm route as session route */
+    if (rc)
+        rc->r = &(rc->s->jvm_route[0]);
+    else
+        rc = find_failover_worker(p, l);
+    return rc;
+}
+
+static worker_record_t *get_most_suitable_worker(lb_worker_t * p,
+                                                 char *sessionid,
+                                                 jk_ws_service_t *s,
+                                                 jk_logger_t *l)
+{
+    worker_record_t *rc = NULL;
+    int r;
+
+    JK_TRACE_ENTER(l);
+    if (p->num_of_workers == 1) {
+        /* No need to find the best worker
+         * if there is a single one
+         */
+        if (JK_WORKER_USABLE_STICKY(p->lb_workers[0].s)) {
+            p->lb_workers[0].r = &(p->lb_workers[0].s->jvm_route[0]);
+            JK_TRACE_EXIT(l);
+            return &p->lb_workers[0];
+        }
+        else {
+            JK_TRACE_EXIT(l);
+            return NULL;
+        }
+    }
+    if (p->lblock == JK_LB_LOCK_PESSIMISTIC)
+        r = jk_shm_lock();
+    else {
+        JK_ENTER_CS(&(p->cs), r);
+    }
+    if (!r) {
+       jk_log(l, JK_LOG_ERROR,
+              "locking failed with errno=%d",
+              errno);
+        JK_TRACE_EXIT(l);
+        return NULL;
+    }
+    if (sessionid) {
+        char *session = sessionid;
+        while (sessionid) {
+            char *next = strchr(sessionid, ';');
+            char *session_route = NULL;
+            if (next)
+               *next++ = '\0';
+            if (JK_IS_DEBUG_LEVEL(l))
+                jk_log(l, JK_LOG_DEBUG,
+                       "searching worker for partial sessionid %s",
+                       sessionid);
+            session_route = strchr(sessionid, '.');
+            if (session_route) {
+                ++session_route;
+
+                if (JK_IS_DEBUG_LEVEL(l))
+                    jk_log(l, JK_LOG_DEBUG,
+                           "searching worker for session route %s",
+                           session_route);
+
+                /* We have a session route. Whow! */
+                rc = find_bysession_route(p, session_route, l);
+                if (rc) {
+                    if (p->lblock == JK_LB_LOCK_PESSIMISTIC)
+                        jk_shm_unlock();
+                    else {
+                        JK_LEAVE_CS(&(p->cs), r);
+                    }
+                    if (JK_IS_DEBUG_LEVEL(l))
+                        jk_log(l, JK_LOG_DEBUG,
+                               "found worker %s (%s) for route %s and partial sessionid %s",
+                               rc->s->name, rc->s->jvm_route, session_route, sessionid);
+                        JK_TRACE_EXIT(l);
+                    return rc;
+                }
+            }
+            /* Try next partial sessionid if present */
+            sessionid = next;
+            rc = NULL;
+        }
+        if (!rc && p->s->sticky_session_force) {
+            if (p->lblock == JK_LB_LOCK_PESSIMISTIC)
+                jk_shm_unlock();
+            else {
+                JK_LEAVE_CS(&(p->cs), r);
+            }
+            jk_log(l, JK_LOG_INFO,
+                   "all workers are in error state for session %s",
+                   session);
+            JK_TRACE_EXIT(l);
+            return NULL;
+        }
+    }
+    rc = find_best_worker(p, l);
+    if (p->lblock == JK_LB_LOCK_PESSIMISTIC)
+        jk_shm_unlock();
+    else {
+        JK_LEAVE_CS(&(p->cs), r);
+    }
+    if (rc && JK_IS_DEBUG_LEVEL(l)) {
+        jk_log(l, JK_LOG_DEBUG,
+               "found best worker %s (%s) using method '%s'",
+               rc->s->name, rc->s->jvm_route, jk_lb_get_method(p, l));
+    }
+    JK_TRACE_EXIT(l);
+    return rc;
+}
+
+static int JK_METHOD service(jk_endpoint_t *e,
+                             jk_ws_service_t *s,
+                             jk_logger_t *l, int *is_error)
+{
+    lb_endpoint_t *p;
+    int attempt = 1;
+    worker_record_t *prec = NULL;
+    int num_of_workers;
+    int first = 1;
+    int was_forced = 0;
+    int rc = -1;
+    char *sessionid = NULL;
+
+    JK_TRACE_ENTER(l);
+
+    if (is_error)
+        *is_error = JK_HTTP_SERVER_ERROR;
+    if (!e || !e->endpoint_private || !s || !is_error) {
+        JK_LOG_NULL_PARAMS(l);
+        JK_TRACE_EXIT(l);
+        return JK_FALSE;
+    }
+
+    p = e->endpoint_private;
+    num_of_workers = p->worker->num_of_workers;
+
+    /* Set returned error to OK */
+    *is_error = JK_HTTP_OK;
+
+    /* set the recovery post, for LB mode */
+    s->reco_buf = jk_b_new(s->pool);
+    jk_b_set_buffer_size(s->reco_buf, p->worker->max_packet_size);
+    jk_b_reset(s->reco_buf);
+    s->reco_status = RECO_INITED;
+    if (p->worker->s->sticky_session) {
+        /* Use sessionid only if sticky_session is
+         * defined for this load balancer
+         */
+        sessionid = get_sessionid(s);
+    }
+    if (JK_IS_DEBUG_LEVEL(l))
+        jk_log(l, JK_LOG_DEBUG,
+               "service sticky_session=%d id='%s'",
+               p->worker->s->sticky_session, sessionid ? sessionid : "empty");
+
+    while (attempt <= num_of_workers && rc == -1) {
+        worker_record_t *rec =
+            get_most_suitable_worker(p->worker, sessionid, s, l);
+        /* Do not reuse previous worker, because
+         * that worker already failed.
+         */
+        if (rec) {
+            int r;
+            int is_service_error = JK_HTTP_OK;
+            jk_endpoint_t *end = NULL;
+            int retry = 0;
+            int retry_wait = JK_LB_MIN_RETRY_WAIT;
+            s->jvm_route = rec->r;
+            prec = rec;
+
+            if (JK_IS_DEBUG_LEVEL(l))
+                jk_log(l, JK_LOG_DEBUG,
+                       "service worker=%s jvm_route=%s",
+                       rec->s->name, s->jvm_route);
+            while ((!(r=rec->w->get_endpoint(rec->w, &end, l)) || !end) && (retry < p->worker->s->retries)) {
+                retry++;
+                retry_wait *=2;
+                if (retry_wait > JK_LB_MAX_RETRY_WAIT)
+                    retry_wait = JK_LB_MAX_RETRY_WAIT;
+                if (JK_IS_DEBUG_LEVEL(l))
+                    jk_log(l, JK_LOG_DEBUG,
+                           "could not get free endpoint for worker"
+                           " (retry %d, sleeping for %d ms)",
+                           retry, retry_wait);
+                jk_sleep(retry_wait);
+            }
+            if (!r || !end) {
+                /* If we can not get the endpoint
+                 * mark the worker as busy rather then
+                 * as in error if the retry number is
+                 * greater then the number of retries.
+                 */
+                if (rec->s->state != JK_LB_STATE_ERROR)
+                    rec->s->state = JK_LB_STATE_BUSY;
+                jk_log(l, JK_LOG_INFO,
+                       "could not get free endpoint for worker %s (%d retries)",
+                       rec->s->name, retry);
+            }
+            else {
+                int service_stat = -1;
+                size_t rd = 0;
+                size_t wr = 0;
+                /* Reset endpoint read and write sizes for
+                 * this request.
+                 */
+                end->rd = end->wr = 0;
+                if (p->worker->lblock == JK_LB_LOCK_PESSIMISTIC)
+                    jk_shm_lock();
+
+                rec->s->elected++;
+                /* Increment the number of workers serving request */
+                p->worker->s->busy++;
+                if (p->worker->s->busy > p->worker->s->max_busy)
+                    p->worker->s->max_busy = p->worker->s->busy;
+                rec->s->busy++;
+                if (p->worker->lbmethod == JK_LB_METHOD_REQUESTS)
+                    rec->s->lb_value += rec->s->lb_mult;
+                else if (p->worker->lbmethod == JK_LB_METHOD_BUSYNESS)
+                    rec->s->lb_value += rec->s->lb_mult;
+                if (rec->s->busy > rec->s->max_busy)
+                    rec->s->max_busy = rec->s->busy;
+                if (p->worker->lblock == JK_LB_LOCK_PESSIMISTIC)
+                    jk_shm_unlock();
+
+                service_stat = end->service(end, s, l, &is_service_error);
+                rd = end->rd;
+                wr = end->wr;
+                end->done(&end, l);
+
+                if (p->worker->lblock == JK_LB_LOCK_PESSIMISTIC)
+                    jk_shm_lock();
+
+                /* Update partial reads and writes if any */
+                rec->s->readed += rd;
+                rec->s->transferred += wr;
+                if (p->worker->lbmethod == JK_LB_METHOD_TRAFFIC) {
+                    rec->s->lb_value += (rd+wr)*rec->s->lb_mult;
+                }
+                else if (p->worker->lbmethod == JK_LB_METHOD_BUSYNESS) {
+                    if (rec->s->lb_value >= rec->s->lb_mult) {
+                        rec->s->lb_value -= rec->s->lb_mult;
+                    }
+                    else {
+                        rec->s->lb_value = 0;
+                        if (JK_IS_DEBUG_LEVEL(l)) {
+                            jk_log(l, JK_LOG_DEBUG,
+                                   "worker %s has load value to low (%"
+                                   JK_UINT64_T_FMT
+                                   " < %"
+                                   JK_UINT64_T_FMT
+                                   ") ",
+                                   "- correcting to 0",
+                                   rec->s->name,
+                                   rec->s->lb_value,
+                                   rec->s->lb_mult);
+                        }
+                    }
+                }
+
+                /* When returning the endpoint mark the worker as not busy.
+                 * We have at least one endpoint free
+                 */
+                if (rec->s->state == JK_LB_STATE_BUSY)
+                    rec->s->state = JK_LB_STATE_OK;
+                /* Decrement the busy worker count.
+                 * Check if the busy was reset to zero by graceful
+                 * restart of the server.
+                 */
+                if (rec->s->busy)
+                    rec->s->busy--;
+                if (p->worker->s->busy)
+                    p->worker->s->busy--;
+                if (service_stat == JK_TRUE) {
+                    rec->s->state = JK_LB_STATE_OK;
+                    rec->s->error_time = 0;
+                    if (p->worker->lblock == JK_LB_LOCK_PESSIMISTIC)
+                        jk_shm_unlock();
+                    rc = JK_TRUE;
+                }
+                else if (service_stat == JK_CLIENT_ERROR) {
+                    /*
+                    * Client error !!!
+                    * Since this is bad request do not fail over.
+                    */
+                    rec->s->client_errors++;
+                    rec->s->state = JK_LB_STATE_OK;
+                    rec->s->error_time = 0;
+                    if (p->worker->lblock == JK_LB_LOCK_PESSIMISTIC)
+                        jk_shm_unlock();
+                    jk_log(l, JK_LOG_INFO,
+                           "unrecoverable error %d, request failed."
+                           " Client failed in the middle of request,"
+                           " we can't recover to another instance.",
+                           is_service_error);
+                    *is_error = is_service_error;
+                    rc = JK_CLIENT_ERROR;
+                }
+                else {
+                    /*
+                    * Service failed !!!
+                    * Time for fault tolerance (if possible)...
+                    */
+
+                    rec->s->errors++;
+                    rec->s->state = JK_LB_STATE_ERROR;
+                    rec->s->error_time = time(NULL);
+                    if (p->worker->lblock == JK_LB_LOCK_PESSIMISTIC)
+                        jk_shm_unlock();
+
+                    if (is_service_error != JK_HTTP_SERVER_BUSY) {
+                        /*
+                        * Error is not recoverable - break with an error.
+                        */
+                        jk_log(l, JK_LOG_ERROR,
+                            "unrecoverable error %d, request failed."
+                            " Tomcat failed in the middle of request,"
+                            " we can't recover to another instance.",
+                            is_service_error);
+                        *is_error = is_service_error;
+                        rc = JK_FALSE;
+                    }
+                    else
+                        jk_log(l, JK_LOG_INFO,
+                               "service failed, worker %s is in error state",
+                               rec->s->name);
+                }
+            }
+            if ( rc == -1 ) {
+                /*
+                 * Error is recoverable by submitting the request to
+                 * another worker... Lets try to do that.
+                 */
+                if (JK_IS_DEBUG_LEVEL(l))
+                    jk_log(l, JK_LOG_DEBUG,
+                           "recoverable error... will try to recover on other worker");
+            }
+            if (first == 1 && s->add_log_items) {
+                const char **log_names = jk_pool_alloc(s->pool, sizeof(char *) * JK_LB_NOTES_COUNT);
+                const char **log_values = jk_pool_alloc(s->pool, sizeof(char *) * JK_LB_NOTES_COUNT);
+                char *buf = jk_pool_alloc(s->pool, sizeof(char *) * JK_LB_NOTES_COUNT * JK_LB_UINT64_STR_SZ);;
+                first = 0;
+                if (log_names && log_values && buf) {
+                    log_names[0] = JK_NOTE_LB_FIRST_NAME;
+                    log_values[0] = prec->s->name;
+                    snprintf(buf, JK_LB_UINT64_STR_SZ, "%" JK_UINT64_T_FMT, prec->s->lb_value);
+                    log_names[1] = JK_NOTE_LB_FIRST_VALUE;
+                    log_values[1] = buf;
+                    buf += JK_LB_UINT64_STR_SZ;
+                    snprintf(buf, JK_LB_UINT64_STR_SZ, "%" JK_UINT64_T_FMT, prec->s->elected);
+                    log_names[2] = JK_NOTE_LB_FIRST_ACCESSED;
+                    log_values[2] = buf;
+                    buf += JK_LB_UINT64_STR_SZ;
+                    snprintf(buf, JK_LB_UINT64_STR_SZ, "%" JK_UINT64_T_FMT, prec->s->readed);
+                    log_names[3] = JK_NOTE_LB_FIRST_READ;
+                    log_values[3] = buf;
+                    buf += JK_LB_UINT64_STR_SZ;
+                    snprintf(buf, JK_LB_UINT64_STR_SZ, "%" JK_UINT64_T_FMT, prec->s->transferred);
+                    log_names[4] = JK_NOTE_LB_FIRST_TRANSFERRED;
+                    log_values[4] = buf;
+                    buf += JK_LB_UINT64_STR_SZ;
+                    snprintf(buf, JK_LB_UINT64_STR_SZ, "%" JK_UINT32_T_FMT, prec->s->errors);
+                    log_names[5] = JK_NOTE_LB_FIRST_ERRORS;
+                    log_values[5] = buf;
+                    buf += JK_LB_UINT64_STR_SZ;
+                    snprintf(buf, JK_LB_UINT64_STR_SZ, "%d", prec->s->busy);
+                    log_names[6] = JK_NOTE_LB_FIRST_BUSY;
+                    log_values[6] = buf;
+                    log_names[7] = JK_NOTE_LB_FIRST_ACTIVATION;
+                    log_values[7] = jk_lb_get_activation(rec, l);
+                    log_names[8] = JK_NOTE_LB_FIRST_STATE;
+                    log_values[8] = jk_lb_get_state(rec, l);
+                    s->add_log_items(s, log_names, log_values, JK_LB_NOTES_COUNT);
+                }
+            }
+        }
+        else {
+            /* NULL record, no more workers left ... */
+            if (attempt == 0 && !was_forced) {
+                int nf;
+                /* Force recovery only on first attempt.
+                 * If the second fails, Tomcat is still disconnected.
+                 */
+                jk_shm_lock();
+                nf = force_recovery(p->worker, l);
+                jk_shm_unlock();
+                was_forced = 1;
+                if (nf) {
+                    /* We have forced recovery.
+                     * Reset the service loop and go again
+                     */
+                    prec = NULL;
+                    rc   = -1;
+                    jk_log(l, JK_LOG_INFO,
+                           "Forcing recovery on first attempt for %d workers", nf);
+                    continue;
+                }
+                else {
+                    /* No workers in error state.
+                     * Somebody set them all to disabled?
+                     */    
+                    jk_log(l, JK_LOG_ERROR,
+                           "All tomcat instances failed, no more workers left for recovery");
+                    *is_error = JK_HTTP_SERVER_BUSY;
+                    rc = JK_FALSE;
+                }
+            }
+            else {
+                jk_log(l, JK_LOG_ERROR,
+                       "All tomcat instances failed, no more workers left");
+                *is_error = JK_HTTP_SERVER_BUSY;
+                rc = JK_FALSE;
+            }
+        }
+        attempt++;
+    }
+    if ( rc == -1 ) {
+        jk_log(l, JK_LOG_INFO,
+               "All tomcat instances are busy or in error state");
+        /* Set error to Timeout */
+        *is_error = JK_HTTP_SERVER_BUSY;
+        rc = JK_FALSE;
+    }
+    if (prec && s->add_log_items) {
+        const char **log_names = jk_pool_alloc(s->pool, sizeof(char *) * JK_LB_NOTES_COUNT);
+        const char **log_values = jk_pool_alloc(s->pool, sizeof(char *) * JK_LB_NOTES_COUNT);
+        char *buf = jk_pool_alloc(s->pool, sizeof(char *) * JK_LB_NOTES_COUNT * JK_LB_UINT64_STR_SZ);;
+        if (log_names && log_values && buf) {
+            log_names[0] = JK_NOTE_LB_LAST_NAME;
+            log_values[0] = prec->s->name;
+            snprintf(buf, JK_LB_UINT64_STR_SZ, "%" JK_UINT64_T_FMT, prec->s->lb_value);
+            log_names[1] = JK_NOTE_LB_LAST_VALUE;
+            log_values[1] = buf;
+            buf += JK_LB_UINT64_STR_SZ;
+            snprintf(buf, JK_LB_UINT64_STR_SZ, "%" JK_UINT64_T_FMT, prec->s->elected);
+            log_names[2] = JK_NOTE_LB_LAST_ACCESSED;
+            log_values[2] = buf;
+            buf += JK_LB_UINT64_STR_SZ;
+            snprintf(buf, JK_LB_UINT64_STR_SZ, "%" JK_UINT64_T_FMT, prec->s->readed);
+            log_names[3] = JK_NOTE_LB_LAST_READ;
+            log_values[3] = buf;
+            buf += JK_LB_UINT64_STR_SZ;
+            snprintf(buf, JK_LB_UINT64_STR_SZ, "%" JK_UINT64_T_FMT, prec->s->transferred);
+            log_names[4] = JK_NOTE_LB_LAST_TRANSFERRED;
+            log_values[4] = buf;
+            buf += JK_LB_UINT64_STR_SZ;
+            snprintf(buf, JK_LB_UINT64_STR_SZ, "%" JK_UINT32_T_FMT, prec->s->errors);
+            log_names[5] = JK_NOTE_LB_LAST_ERRORS;
+            log_values[5] = buf;
+            buf += JK_LB_UINT64_STR_SZ;
+            snprintf(buf, JK_LB_UINT64_STR_SZ, "%d", prec->s->busy);
+            log_names[6] = JK_NOTE_LB_LAST_BUSY;
+            log_values[6] = buf;
+            log_names[7] = JK_NOTE_LB_LAST_ACTIVATION;
+            log_values[7] = jk_lb_get_activation(prec, l);
+            log_names[8] = JK_NOTE_LB_LAST_STATE;
+            log_values[8] = jk_lb_get_state(prec, l);
+            s->add_log_items(s, log_names, log_values, JK_LB_NOTES_COUNT);
+        }
+    }
+
+    JK_TRACE_EXIT(l);
+    return rc;
+}
+
+static int JK_METHOD done(jk_endpoint_t **e, jk_logger_t *l)
+{
+    JK_TRACE_ENTER(l);
+
+    if (e && *e && (*e)->endpoint_private) {
+        lb_endpoint_t *p = (*e)->endpoint_private;
+
+        if (p->e) {
+            p->e->done(&p->e, l);
+        }
+
+        free(p);
+        *e = NULL;
+        JK_TRACE_EXIT(l);
+        return JK_TRUE;
+    }
+
+    JK_LOG_NULL_PARAMS(l);
+    JK_TRACE_EXIT(l);
+    return JK_FALSE;
+}
+
+static int JK_METHOD validate(jk_worker_t *pThis,
+                              jk_map_t *props,
+                              jk_worker_env_t *we, jk_logger_t *l)
+{
+    JK_TRACE_ENTER(l);
+
+    if (pThis && pThis->worker_private) {
+        lb_worker_t *p = pThis->worker_private;
+        char **worker_names;
+        unsigned int num_of_workers;
+        const char *secret;
+
+        p->s->sticky_session = jk_get_is_sticky_session(props, p->s->name);
+        p->s->sticky_session_force = jk_get_is_sticky_session_force(props, p->s->name);
+        secret = jk_get_worker_secret(props, p->s->name);
+
+        if (jk_get_lb_worker_list(props,
+                                  p->s->name,
+                                  &worker_names,
+                                  &num_of_workers) && num_of_workers) {
+            unsigned int i = 0;
+            unsigned int j = 0;
+            p->max_packet_size = DEF_BUFFER_SZ;
+            p->lb_workers = jk_pool_alloc(&p->p,
+                                          num_of_workers *
+                                          sizeof(worker_record_t));
+            if (!p->lb_workers) {
+                JK_TRACE_EXIT(l);
+                return JK_FALSE;
+            }
+
+            for (i = 0; i < num_of_workers; i++) {
+                p->lb_workers[i].s = jk_shm_alloc_worker(&p->p);
+                if (p->lb_workers[i].s == NULL) {
+                    jk_log(l, JK_LOG_ERROR,
+                           "allocating worker record from shared memory");
+                    JK_TRACE_EXIT(l);
+                    return JK_FALSE;
+                }
+            }
+
+            /* Calculate the maximum packet size from all workers
+             * for the recovery buffer.
+             */
+            for (i = 0; i < num_of_workers; i++) {
+                unsigned int ms = jk_get_max_packet_size(props, worker_names[i]);
+                if (ms > p->max_packet_size)
+                    p->max_packet_size = ms;
+            }
+            for (i = 0; i < num_of_workers; i++) {
+                const char *s;
+                strncpy(p->lb_workers[i].s->name, worker_names[i],
+                        JK_SHM_STR_SIZ);
+                p->lb_workers[i].s->lb_factor =
+                    jk_get_lb_factor(props, worker_names[i]);
+                if (p->lb_workers[i].s->lb_factor < 1) {
+                    p->lb_workers[i].s->lb_factor = 1;
+                }
+                p->lb_workers[i].s->distance =
+                    jk_get_distance(props, worker_names[i]);
+                if ((s = jk_get_worker_jvm_route(props, worker_names[i], NULL)))
+                    strncpy(p->lb_workers[i].s->jvm_route, s, JK_SHM_STR_SIZ);
+                else
+                    strncpy(p->lb_workers[i].s->jvm_route, worker_names[i], JK_SHM_STR_SIZ);
+                if ((s = jk_get_worker_domain(props, worker_names[i], NULL)))
+                    strncpy(p->lb_workers[i].s->domain, s, JK_SHM_STR_SIZ);
+                if ((s = jk_get_worker_redirect(props, worker_names[i], NULL)))
+                    strncpy(p->lb_workers[i].s->redirect, s, JK_SHM_STR_SIZ);
+
+                p->lb_workers[i].s->lb_value = 0;
+                p->lb_workers[i].s->state = JK_LB_STATE_NA;
+                p->lb_workers[i].s->error_time = 0;
+                p->lb_workers[i].s->activation = 
+                    jk_get_worker_activation(props, worker_names[i]);
+                if (!wc_create_worker(p->lb_workers[i].s->name, 0,
+                                      props,
+                                      &(p->lb_workers[i].w),
+                                      we, l) || !p->lb_workers[i].w) {
+                    break;
+                }
+                if (secret && (p->lb_workers[i].w->type == JK_AJP13_WORKER_TYPE ||
+                    p->lb_workers[i].w->type == JK_AJP14_WORKER_TYPE)) {
+                    ajp_worker_t *aw = (ajp_worker_t *)p->lb_workers[i].w->worker_private;
+                    if (!aw->secret)
+                        aw->secret = secret;
+                }
+            }
+
+            if (i != num_of_workers) {
+                jk_log(l, JK_LOG_ERROR,
+                       "Failed creating worker %s",
+                       p->lb_workers[i].s->name);
+                close_workers(p, i, l);
+            }
+            else {
+                for (i = 0; i < num_of_workers; i++) {
+                    if (JK_IS_DEBUG_LEVEL(l)) {
+                        jk_log(l, JK_LOG_DEBUG,
+                               "Balanced worker %i has name %s and jvm_route %s in domain %s",
+                               i,
+                               p->lb_workers[i].s->name,
+                               p->lb_workers[i].s->jvm_route,
+                               p->lb_workers[i].s->domain);
+                    }
+                }
+                p->num_of_workers = num_of_workers;
+                update_mult(p, l);
+                for (i = 0; i < num_of_workers; i++) {
+                    for (j = 0; j < i; j++) {
+                        if (strcmp(p->lb_workers[i].s->jvm_route, p->lb_workers[j].s->jvm_route) == 0) {
+                            jk_log(l, JK_LOG_ERROR,
+                                   "Balanced workers number %i (%s) and %i (%s) share the same jvm_route %s - aborting configuration!",
+                                   i,
+                                   p->lb_workers[i].s->name,
+                                   j,
+                                   p->lb_workers[j].s->name,
+                                   p->lb_workers[i].s->jvm_route);
+                            JK_TRACE_EXIT(l);
+                            return JK_FALSE;
+                        }
+                    }
+                }
+                JK_TRACE_EXIT(l);
+                return JK_TRUE;
+            }
+        }
+    }
+
+    JK_LOG_NULL_PARAMS(l);
+    JK_TRACE_EXIT(l);
+    return JK_FALSE;
+}
+
+static int JK_METHOD init(jk_worker_t *pThis,
+                          jk_map_t *props,
+                          jk_worker_env_t *we, jk_logger_t *log)
+{
+    int i;
+
+    lb_worker_t *p = (lb_worker_t *)pThis->worker_private;
+    JK_TRACE_ENTER(log);
+
+    pThis->retries = jk_get_worker_retries(props, p->s->name,
+                                           JK_RETRIES);
+    p->s->retries = pThis->retries;
+    p->s->recover_wait_time = jk_get_worker_recover_timeout(props, p->s->name,
+                                                            WAIT_BEFORE_RECOVER);
+    if (p->s->recover_wait_time < 1)
+        p->s->recover_wait_time = 1;
+    p->maintain_time = jk_get_worker_maintain_time(props);
+    p->s->last_maintain_time = time(NULL);
+
+    p->lbmethod = jk_get_lb_method(props, p->s->name);
+    p->lblock   = jk_get_lb_lock(props, p->s->name);
+
+    JK_INIT_CS(&(p->cs), i);
+    if (i == JK_FALSE) {
+        jk_log(log, JK_LOG_ERROR,
+               "creating thread lock errno=%d",
+               errno);
+        JK_TRACE_EXIT(log);
+        return JK_FALSE;
+    }
+
+    JK_TRACE_EXIT(log);
+    return JK_TRUE;
+}
+
+static int JK_METHOD get_endpoint(jk_worker_t *pThis,
+                                  jk_endpoint_t **pend, jk_logger_t *l)
+{
+    JK_TRACE_ENTER(l);
+
+    if (pThis && pThis->worker_private && pend) {
+        lb_endpoint_t *p = (lb_endpoint_t *) malloc(sizeof(lb_endpoint_t));
+        p->e = NULL;
+        p->worker = pThis->worker_private;
+        p->endpoint.endpoint_private = p;
+        p->endpoint.service = service;
+        p->endpoint.done = done;
+        *pend = &p->endpoint;
+
+        JK_TRACE_EXIT(l);
+        return JK_TRUE;
+    }
+    else {
+        JK_LOG_NULL_PARAMS(l);
+    }
+
+    JK_TRACE_EXIT(l);
+    return JK_FALSE;
+}
+
+static int JK_METHOD destroy(jk_worker_t **pThis, jk_logger_t *l)
+{
+    JK_TRACE_ENTER(l);
+
+    if (pThis && *pThis && (*pThis)->worker_private) {
+        unsigned int i;
+        lb_worker_t *private_data = (*pThis)->worker_private;
+
+        close_workers(private_data, private_data->num_of_workers, l);
+        JK_DELETE_CS(&(private_data->cs), i);
+        jk_close_pool(&private_data->p);
+        free(private_data);
+
+        JK_TRACE_EXIT(l);
+        return JK_TRUE;
+    }
+
+    JK_LOG_NULL_PARAMS(l);
+    JK_TRACE_EXIT(l);
+    return JK_FALSE;
+}
+
+int JK_METHOD lb_worker_factory(jk_worker_t **w,
+                                const char *name, jk_logger_t *l)
+{
+    JK_TRACE_ENTER(l);
+
+    if (NULL != name && NULL != w) {
+        lb_worker_t *private_data =
+            (lb_worker_t *) calloc(1, sizeof(lb_worker_t));
+
+
+        jk_open_pool(&private_data->p,
+                        private_data->buf,
+                        sizeof(jk_pool_atom_t) * TINY_POOL_SIZE);
+
+        private_data->s = jk_shm_alloc_worker(&private_data->p);
+        if (!private_data->s) {
+            free(private_data);
+            JK_TRACE_EXIT(l);
+            return 0;
+        }
+        strncpy(private_data->s->name, name, JK_SHM_STR_SIZ);
+        private_data->lb_workers = NULL;
+        private_data->num_of_workers = 0;
+        private_data->worker.worker_private = private_data;
+        private_data->worker.validate = validate;
+        private_data->worker.init = init;
+        private_data->worker.get_endpoint = get_endpoint;
+        private_data->worker.destroy = destroy;
+        private_data->worker.maintain = maintain_workers;
+        private_data->worker.retries = JK_RETRIES;
+        private_data->s->recover_wait_time = WAIT_BEFORE_RECOVER;
+        *w = &private_data->worker;
+        JK_TRACE_EXIT(l);
+        return JK_LB_WORKER_TYPE;
+    }
+    else {
+        JK_LOG_NULL_PARAMS(l);
+    }
+
+    JK_TRACE_EXIT(l);
+    return 0;
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_lb_worker.h
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_lb_worker.h	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_lb_worker.h	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,149 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.
+ */
+
+/***************************************************************************
+ * Description: load balance worker header file                            *
+ * Author:      Gal Shachor <shachor at il.ibm.com>                           *
+ * Author:      Rainer Jung <rjung at apache.org>                             *
+ * Version:     $Revision: 439810 $                                           *
+ ***************************************************************************/
+
+#ifndef JK_LB_WORKER_H
+#define JK_LB_WORKER_H
+
+#include "jk_logger.h"
+#include "jk_service.h"
+#include "jk_mt.h"
+#include "jk_shm.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif                          /* __cplusplus */
+
+#define JK_LB_WORKER_NAME     ("lb")
+#define JK_LB_WORKER_TYPE     (5)
+#define JK_LB_DEF_DOMAIN_NAME ("unknown")
+
+#define JK_LB_METHOD_REQUESTS          (1)
+#define JK_LB_METHOD_TRAFFIC           (2)
+#define JK_LB_METHOD_BUSYNESS          (3)
+#define JK_LB_METHOD_DEF               (JK_LB_METHOD_REQUESTS)
+#define JK_LB_METHOD_TEXT_REQUESTS     ("Request")
+#define JK_LB_METHOD_TEXT_TRAFFIC      ("Traffic")
+#define JK_LB_METHOD_TEXT_BUSYNESS     ("Busyness")
+#define JK_LB_METHOD_TEXT_DEF          (JK_LB_METHOD_TEXT_REQUESTS)
+#define JK_LB_LOCK_OPTIMISTIC          (1)
+#define JK_LB_LOCK_PESSIMISTIC         (2)
+#define JK_LB_LOCK_DEF                 (JK_LB_LOCK_OPTIMISTIC)
+#define JK_LB_LOCK_TEXT_OPTIMISTIC     ("Optimistic")
+#define JK_LB_LOCK_TEXT_PESSIMISTIC    ("Pessimistic")
+#define JK_LB_LOCK_TEXT_DEF            (JK_LB_LOCK_TEXT_OPTIMISTIC)
+#define JK_LB_STATE_NA                 (1)
+#define JK_LB_STATE_OK                 (2)
+#define JK_LB_STATE_RECOVER            (3)
+#define JK_LB_STATE_BUSY               (4)
+#define JK_LB_STATE_ERROR              (5)
+#define JK_LB_STATE_TEXT_NA            ("N/A")
+#define JK_LB_STATE_TEXT_OK            ("OK")
+#define JK_LB_STATE_TEXT_RECOVER       ("REC")
+#define JK_LB_STATE_TEXT_BUSY          ("BSY")
+#define JK_LB_STATE_TEXT_ERROR         ("ERR")
+#define JK_LB_ACTIVATION_ACTIVE        (1)
+#define JK_LB_ACTIVATION_DISABLED      (2)
+#define JK_LB_ACTIVATION_STOPPED       (3)
+#define JK_LB_ACTIVATION_TEXT_ACTIVE   ("ACT")
+#define JK_LB_ACTIVATION_TEXT_DISABLED ("DIS")
+#define JK_LB_ACTIVATION_TEXT_STOPPED  ("STP")
+
+#define JK_LB_UINT64_STR_SZ          (21)
+#define JK_LB_NOTES_COUNT            (9)
+#define JK_NOTE_LB_FIRST_NAME        ("JK_LB_FIRST_NAME")
+#define JK_NOTE_LB_FIRST_VALUE       ("JK_LB_FIRST_VALUE")
+#define JK_NOTE_LB_FIRST_ACCESSED    ("JK_LB_FIRST_ACCESSED")
+#define JK_NOTE_LB_FIRST_READ        ("JK_LB_FIRST_READ")
+#define JK_NOTE_LB_FIRST_TRANSFERRED ("JK_LB_FIRST_TRANSFERRED")
+#define JK_NOTE_LB_FIRST_ERRORS      ("JK_LB_FIRST_ERRORS")
+#define JK_NOTE_LB_FIRST_BUSY        ("JK_LB_FIRST_BUSY")
+#define JK_NOTE_LB_FIRST_ACTIVATION  ("JK_LB_FIRST_ACTIVATION")
+#define JK_NOTE_LB_FIRST_STATE       ("JK_LB_FIRST_STATE")
+#define JK_NOTE_LB_LAST_NAME         ("JK_LB_LAST_NAME")
+#define JK_NOTE_LB_LAST_VALUE        ("JK_LB_LAST_VALUE")
+#define JK_NOTE_LB_LAST_ACCESSED     ("JK_LB_LAST_ACCESSED")
+#define JK_NOTE_LB_LAST_READ         ("JK_LB_LAST_READ")
+#define JK_NOTE_LB_LAST_TRANSFERRED  ("JK_LB_LAST_TRANSFERRED")
+#define JK_NOTE_LB_LAST_ERRORS       ("JK_LB_LAST_ERRORS")
+#define JK_NOTE_LB_LAST_BUSY         ("JK_LB_LAST_BUSY")
+#define JK_NOTE_LB_LAST_ACTIVATION   ("JK_LB_LAST_ACTIVATION")
+#define JK_NOTE_LB_LAST_STATE        ("JK_LB_LAST_STATE")
+
+/* Minimal time in ms to wait between get_endpoint retries for balanced workers */
+#define JK_LB_MIN_RETRY_WAIT  (25)
+/* Maximal time in ms to wait between get_endpoint retries for balanced workers */
+#define JK_LB_MAX_RETRY_WAIT  (100)
+/* Time to wait before retry. */
+#define WAIT_BEFORE_RECOVER   (60)
+/* We accept doing global maintenance if we are */
+/* JK_LB_MAINTAIN_TOLERANCE seconds early. */
+#define JK_LB_MAINTAIN_TOLERANCE (2)
+/* We divide load values by 2^x during global maintenance. */
+/* The exponent x is JK_LB_DECAY_MULT*#MAINT_INTV_SINCE_LAST_MAINT */
+#define JK_LB_DECAY_MULT         (1)
+
+struct worker_record
+{
+    jk_worker_t      *w;
+    /* Shared memory worker data */
+    jk_shm_worker_t  *s;
+    /* Current jvmRoute. Can be name or domain */
+    const char       *r;
+};
+typedef struct worker_record worker_record_t;
+
+struct lb_worker
+{
+    worker_record_t *lb_workers;
+    unsigned int num_of_workers;
+    int          lbmethod;
+    int          lblock;
+    time_t       maintain_time;
+    unsigned int max_packet_size;
+
+    jk_pool_t p;
+    jk_pool_atom_t buf[TINY_POOL_SIZE];
+
+    jk_worker_t worker;
+    JK_CRIT_SEC cs;
+
+    /* Shared memory worker data */
+    jk_shm_worker_t  *s;
+};
+typedef struct lb_worker lb_worker_t;
+
+int JK_METHOD lb_worker_factory(jk_worker_t **w,
+                                const char *name, jk_logger_t *l);
+
+const char *jk_lb_get_lock(lb_worker_t *p, jk_logger_t *l);
+const char *jk_lb_get_method(lb_worker_t *p, jk_logger_t *l);
+const char *jk_lb_get_state(worker_record_t *p, jk_logger_t *l);
+const char *jk_lb_get_activation(worker_record_t *p, jk_logger_t *l);
+void reset_lb_values(lb_worker_t *p, jk_logger_t *l);
+void update_mult(lb_worker_t * p, jk_logger_t *l);
+
+#ifdef __cplusplus
+}
+#endif                          /* __cplusplus */
+#endif                          /* JK_LB_WORKER_H */

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_logger.h
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_logger.h	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_logger.h	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,126 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.
+ */
+
+/***************************************************************************
+ * Description: Logger object definitions                                  *
+ * Author:      Gal Shachor <shachor at il.ibm.com>                           *
+ * Version:     $Revision: 434087 $                                           *
+ ***************************************************************************/
+
+#ifndef JK_LOGGER_H
+#define JK_LOGGER_H
+
+#include "jk_global.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+typedef struct jk_logger jk_logger_t;
+struct jk_logger
+{
+    void *logger_private;
+    int level;
+
+    int (JK_METHOD * log) (jk_logger_t *l, int level, const char *what);
+
+};
+
+typedef struct file_logger_t file_logger_t;
+struct file_logger_t
+{
+    FILE *logfile;
+    /* For Apache 2 APR piped logging */
+    void *jklogfp;
+    /* For Apache 1.3 piped logging */
+    int log_fd;
+};
+
+/* Level like Java tracing, but available only
+   at compile time on DEBUG preproc define.
+ */
+#define JK_LOG_TRACE_LEVEL   0
+#define JK_LOG_DEBUG_LEVEL   1
+#define JK_LOG_INFO_LEVEL    2
+#define JK_LOG_WARNING_LEVEL 3
+#define JK_LOG_ERROR_LEVEL   4
+#define JK_LOG_EMERG_LEVEL   5
+#define JK_LOG_REQUEST_LEVEL 6
+#define JK_LOG_DEF_LEVEL     JK_LOG_INFO_LEVEL
+
+#define JK_LOG_TRACE_VERB   "trace"
+#define JK_LOG_DEBUG_VERB   "debug"
+#define JK_LOG_INFO_VERB    "info"
+#define JK_LOG_WARN_VERB    "warn"
+#define JK_LOG_ERROR_VERB   "error"
+#define JK_LOG_EMERG_VERB   "emerg"
+#define JK_LOG_DEF_VERB     JK_LOG_INFO_VERB
+
+#if defined(__GNUC__) || (defined(_MSC_VER) && (_MSC_VER > 1200))
+#define JK_LOG_TRACE   __FILE__,__LINE__,__FUNCTION__,JK_LOG_TRACE_LEVEL
+#define JK_LOG_DEBUG   __FILE__,__LINE__,__FUNCTION__,JK_LOG_DEBUG_LEVEL
+#define JK_LOG_ERROR   __FILE__,__LINE__,__FUNCTION__,JK_LOG_ERROR_LEVEL
+#define JK_LOG_EMERG   __FILE__,__LINE__,__FUNCTION__,JK_LOG_EMERG_LEVEL
+#define JK_LOG_INFO    __FILE__,__LINE__,__FUNCTION__,JK_LOG_INFO_LEVEL
+#define JK_LOG_WARNING __FILE__,__LINE__,__FUNCTION__,JK_LOG_WARNING_LEVEL
+#else
+#define JK_LOG_TRACE   __FILE__,__LINE__,NULL,JK_LOG_TRACE_LEVEL
+#define JK_LOG_DEBUG   __FILE__,__LINE__,NULL,JK_LOG_DEBUG_LEVEL
+#define JK_LOG_ERROR   __FILE__,__LINE__,NULL,JK_LOG_ERROR_LEVEL
+#define JK_LOG_EMERG   __FILE__,__LINE__,NULL,JK_LOG_EMERG_LEVEL
+#define JK_LOG_INFO    __FILE__,__LINE__,NULL,JK_LOG_INFO_LEVEL
+#define JK_LOG_WARNING __FILE__,__LINE__,NULL,JK_LOG_WARNING_LEVEL
+#endif
+
+#define JK_LOG_REQUEST __FILE__,0,NULL,JK_LOG_REQUEST_LEVEL
+
+#if defined(JK_PRODUCTION)
+/* TODO: all DEBUG messages should be compiled out
+ * when this define is in place.
+ */
+#define JK_IS_PRODUCTION    1
+#define JK_TRACE_ENTER(l)
+#define JK_TRACE_EXIT(l)
+#else
+#define JK_IS_PRODUCTION    0
+#define JK_TRACE_ENTER(l)                               \
+    do {                                                \
+        if ((l) && (l)->level == JK_LOG_TRACE_LEVEL) {  \
+            jk_log((l), JK_LOG_TRACE, "enter");         \
+    } } while (0)
+
+#define JK_TRACE_EXIT(l)                                \
+    do {                                                \
+        if ((l) && (l)->level == JK_LOG_TRACE_LEVEL) {  \
+            jk_log((l), JK_LOG_TRACE, "exit");          \
+    } } while (0)
+
+#endif  /* JK_PRODUCTION */
+
+#define JK_LOG_NULL_PARAMS(l) jk_log((l), JK_LOG_ERROR, "NULL parameters")
+
+/* Debug level macro
+ * It is more efficient to check the level prior
+ * calling function that will not execute anyhow because of level
+ */
+#define JK_IS_DEBUG_LEVEL(l)  ((l) && (l)->level <  JK_LOG_INFO_LEVEL)
+
+
+#ifdef __cplusplus
+}
+#endif      /* __cplusplus */
+#endif      /* JK_LOGGER_H */

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_map.c
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_map.c	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_map.c	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,719 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.
+ */
+
+/***************************************************************************
+ * Description: General purpose map object                                 *
+ * Author:      Gal Shachor <shachor at il.ibm.com>                           *
+ * Author:      Mladen Turk <mturk at apache.org>                             *
+ * Version:     $Revision: 439824 $                                          *
+ ***************************************************************************/
+#ifdef AS400
+#include "apr_xlate.h"
+#endif
+
+#include "jk_global.h"
+#include "jk_pool.h"
+#include "jk_util.h"
+#include "jk_map.h"
+
+#define CAPACITY_INC_SIZE   (50)
+#define LENGTH_OF_LINE      (8192)
+#define JK_MAP_RECURSION    (20)
+#define JK_MAP_REFERENCE    (".reference")
+#define JK_MAP_REFERENCE_SZ (strlen(JK_MAP_REFERENCE))
+
+#ifdef AS400
+#define CASE_MASK 0xbfbfbfbf
+#else
+#define CASE_MASK 0xdfdfdfdf
+#endif
+
+/* Compute the "checksum" for a key, consisting of the first
+ * 4 bytes, normalized for case-insensitivity and packed into
+ * an int...this checksum allows us to do a single integer
+ * comparison as a fast check to determine whether we can
+ * skip a strcasecmp
+ */
+#define COMPUTE_KEY_CHECKSUM(key, checksum)    \
+{                                              \
+    const char *k = (key);                     \
+    unsigned int c = (unsigned int)*k;         \
+    (checksum) = c;                            \
+    (checksum) <<= 8;                          \
+    if (c) {                                   \
+        c = (unsigned int)*++k;                \
+        checksum |= c;                         \
+    }                                          \
+    (checksum) <<= 8;                          \
+    if (c) {                                   \
+        c = (unsigned int)*++k;                \
+        checksum |= c;                         \
+    }                                          \
+    (checksum) <<= 8;                          \
+    if (c) {                                   \
+        c = (unsigned int)*++k;                \
+        checksum |= c;                         \
+    }                                          \
+    checksum &= CASE_MASK;                     \
+}
+
+struct jk_map
+{
+    jk_pool_t p;
+    jk_pool_atom_t buf[SMALL_POOL_SIZE];
+
+    const char **names;
+    const void **values;
+    unsigned int *keys;
+
+    unsigned int capacity;
+    unsigned int size;
+};
+
+static void trim_prp_comment(char *prp);
+static size_t trim(char *s);
+static int map_realloc(jk_map_t *m);
+
+int jk_map_alloc(jk_map_t **m)
+{
+    if (m) {
+        return jk_map_open(*m = (jk_map_t *)malloc(sizeof(jk_map_t)));
+    }
+
+    return JK_FALSE;
+}
+
+int jk_map_free(jk_map_t **m)
+{
+    int rc = JK_FALSE;
+
+    if (m && *m) {
+        jk_map_close(*m);
+        free(*m);
+        *m = NULL;
+    }
+
+    return rc;
+}
+
+int jk_map_open(jk_map_t *m)
+{
+    int rc = JK_FALSE;
+
+    if (m) {
+        jk_open_pool(&m->p, m->buf, sizeof(jk_pool_atom_t) * SMALL_POOL_SIZE);
+        m->capacity = 0;
+        m->size = 0;
+        m->keys  = NULL;
+        m->names = NULL;
+        m->values = NULL;
+        rc = JK_TRUE;
+    }
+
+    return rc;
+}
+
+int jk_map_close(jk_map_t *m)
+{
+    int rc = JK_FALSE;
+
+    if (m) {
+        jk_close_pool(&m->p);
+        rc = JK_TRUE;
+    }
+
+    return rc;
+}
+
+void *jk_map_get(jk_map_t *m, const char *name, const void *def)
+{
+    const void *rc = (void *)def;
+
+    if (m && name) {
+        unsigned int i;
+        unsigned int key;
+        COMPUTE_KEY_CHECKSUM(name, key)
+        for (i = 0; i < m->size; i++) {
+            if (m->keys[i] == key && strcmp(m->names[i], name) == 0) {
+                rc = m->values[i];
+                break;
+            }
+        }
+    }
+
+    return (void *)rc;          /* DIRTY */
+}
+
+int jk_map_get_id(jk_map_t *m, const char *name)
+{
+    int rc = -1;
+    if (m && name) {
+        unsigned int i;
+        unsigned int key;
+        COMPUTE_KEY_CHECKSUM(name, key)
+        for (i = 0; i < m->size; i++) {
+            if (m->keys[i] == key && strcmp(m->names[i], name) == 0) {
+                rc = i;
+                break;
+            }
+        }
+    }
+
+    return rc;
+}
+
+const char *jk_map_get_string(jk_map_t *m, const char *name, const char *def)
+{
+    const char *rc = def;
+
+    if (m && name) {
+        unsigned int i;
+        unsigned int key;
+        COMPUTE_KEY_CHECKSUM(name, key)
+        for (i = 0; i < m->size; i++) {
+            if (m->keys[i] == key && strcmp(m->names[i], name) == 0) {
+                rc = m->values[i];
+                break;
+            }
+        }
+    }
+
+    return rc;
+}
+
+
+int jk_map_get_int(jk_map_t *m, const char *name, int def)
+{
+    char buf[100];
+    const char *rc;
+    size_t len;
+    int int_res;
+    int multit = 1;
+
+    sprintf(buf, "%d", def);
+    rc = jk_map_get_string(m, name, buf);
+
+    len = strlen(rc);
+    if (len) {
+        char *lastchar = &buf[0] + len - 1;
+        strcpy(buf, rc);
+        if ('m' == *lastchar || 'M' == *lastchar) {
+            *lastchar = '\0';
+            multit = 1024 * 1024;
+        }
+        else if ('k' == *lastchar || 'K' == *lastchar) {
+            *lastchar = '\0';
+            multit = 1024;
+        }
+        int_res = atoi(buf);
+    }
+    else
+        int_res = def;
+
+    return int_res * multit;
+}
+
+double jk_map_get_double(jk_map_t *m, const char *name, double def)
+{
+    char buf[100];
+    const char *rc;
+
+    sprintf(buf, "%f", def);
+    rc = jk_map_get_string(m, name, buf);
+
+    return atof(rc);
+}
+
+int jk_map_get_bool(jk_map_t *m, const char *name, int def)
+{
+    char buf[100];
+    size_t len;
+    const char *rc;
+    int rv = 0;
+
+    sprintf(buf, "%d", def);
+    rc = jk_map_get_string(m, name, buf);
+
+    len = strlen(rc);
+    if (len) {
+        if (strcasecmp(rc, "true") == 0 ||
+            *rc == 'Y' || *rc == 'y' || *rc == '1') {
+            rv = 1;
+        }
+    }
+    return rv;
+}
+
+char **jk_map_get_string_list(jk_map_t *m,
+                              const char *name,
+                              unsigned *list_len, const char *def)
+{
+    const char *l = jk_map_get_string(m, name, def);
+    char **ar = NULL;
+
+#if defined(AS400) || defined(_REENTRANT)
+    char *lasts;
+#endif
+
+    *list_len = 0;
+
+    if (l) {
+        unsigned capacity = 0;
+        unsigned idex = 0;
+        char *p;
+        char *v = jk_pool_strdup(&m->p, l);
+
+        if (!v) {
+            return NULL;
+        }
+
+        /*
+         * GS, in addition to VG's patch, we now need to
+         * strtok also by a "*"
+         */
+#if defined(AS400) || defined(_REENTRANT)
+        for (p = strtok_r(v, " \t,", &lasts);
+             p; p = strtok_r(NULL, " \t,", &lasts))
+#else
+        for (p = strtok(v, " \t,"); p; p = strtok(NULL, " \t,"))
+#endif
+
+        {
+
+            if (idex == capacity) {
+                ar = jk_pool_realloc(&m->p,
+                                     sizeof(char *) * (capacity + 5),
+                                     ar, sizeof(char *) * capacity);
+                if (!ar) {
+                    return JK_FALSE;
+                }
+                capacity += 5;
+            }
+            ar[idex] = jk_pool_strdup(&m->p, p);
+            idex++;
+        }
+
+        *list_len = idex;
+    }
+
+    return ar;
+}
+
+int jk_map_add(jk_map_t *m, const char *name, const void *value)
+{
+    int rc = JK_FALSE;
+
+    if (m && name) {
+        unsigned int key;
+        COMPUTE_KEY_CHECKSUM(name, key)
+        map_realloc(m);
+
+        if (m->size < m->capacity) {
+            m->values[m->size] = value;
+            m->names[m->size] = jk_pool_strdup(&m->p, name);
+            m->keys[m->size] = key;
+            m->size++;
+            rc = JK_TRUE;
+        }
+    }
+
+    return rc;
+}
+
+int jk_map_put(jk_map_t *m, const char *name, const void *value, void **old)
+{
+    int rc = JK_FALSE;
+
+    if (m && name) {
+        unsigned int i;
+        unsigned int key;
+        COMPUTE_KEY_CHECKSUM(name, key)
+        for (i = 0; i < m->size; i++) {
+            if (m->keys[i] == key && strcasecmp(m->names[i], name) == 0) {
+                break;
+            }
+        }
+
+        if (i < m->size) {
+            if (old)
+                *old = (void *)m->values[i];        /* DIRTY */
+            m->values[i] = value;
+            rc = JK_TRUE;
+        }
+        else {
+            rc = jk_map_add(m, name, value);
+        }
+    }
+
+    return rc;
+}
+
+int jk_map_read_property(jk_map_t *m, const char *str, jk_logger_t *l)
+{
+    int rc = JK_TRUE;
+    char buf[LENGTH_OF_LINE + 1];
+    char *prp = &buf[0];
+
+    if (strlen(str) > LENGTH_OF_LINE)
+        return JK_FALSE;
+
+    strcpy(prp, str);
+    if (trim(prp)) {
+        char *v = strchr(prp, '=');
+        if (v) {
+            *v = '\0';
+            v++;
+            trim(prp);
+            trim(v);
+            if (strlen(v) && strlen(prp)) {
+                const char *oldv = jk_map_get_string(m, prp, NULL);
+                v = jk_map_replace_properties(m, v);
+                if (oldv && jk_is_unique_property(prp) == JK_FALSE) {
+                    char *tmpv = jk_pool_alloc(&m->p,
+                                       strlen(v) + strlen(oldv) + 3);
+                    if (tmpv) {
+                        char sep = '*';
+                        if (jk_is_path_property(prp))
+                            sep = PATH_SEPERATOR;
+                        else if (jk_is_cmd_line_property(prp))
+                            sep = ' ';
+                        else if (jk_is_list_property(prp))
+                            sep = ',';
+                        sprintf(tmpv, "%s%c%s", oldv, sep, v);
+                    }
+                    v = tmpv;
+                }
+                else {
+                    if (jk_is_deprecated_property(prp)) {
+                        jk_log(l, JK_LOG_WARNING,
+                               "The attribute %s is deprecated - please check"
+                               " the documentation for the correct replacement.",
+                               prp);
+                    }
+                    v = jk_pool_strdup(&m->p, v);
+                }
+                if (v) {
+                    jk_map_put(m, prp, v, NULL);
+                }
+                else {
+                    rc = JK_FALSE;
+                }
+            }
+        }
+    }
+    return rc;
+}
+
+
+int jk_map_read_properties(jk_map_t *m, const char *f, time_t *modified, jk_logger_t *l)
+{
+    int rc = JK_FALSE;
+
+    if (m && f) {
+        struct stat statbuf;
+        FILE *fp;
+        if ((rc = stat(f, &statbuf)) == -1)
+            return JK_FALSE;
+#ifdef AS400
+        fp = fopen(f, "r, o_ccsid=0");
+#else
+        fp = fopen(f, "r");
+#endif
+
+        if (fp) {
+            char buf[LENGTH_OF_LINE + 1];
+            char *prp;
+
+            rc = JK_TRUE;
+
+            while (NULL != (prp = fgets(buf, LENGTH_OF_LINE, fp))) {
+                trim_prp_comment(prp);
+                if (*prp) {
+                    if ((rc = jk_map_read_property(m, prp, l)) == JK_FALSE)
+                        break;
+                }
+            }
+            fclose(fp);
+            if (modified)
+                *modified = statbuf.st_mtime;
+        }
+    }
+
+    return rc;
+}
+
+
+int jk_map_size(jk_map_t *m)
+{
+    if (m) {
+        return m->size;
+    }
+
+    return -1;
+}
+
+const char *jk_map_name_at(jk_map_t *m, int idex)
+{
+    if (m && idex >= 0) {
+        return m->names[idex];  /* DIRTY */
+    }
+
+    return NULL;
+}
+
+void *jk_map_value_at(jk_map_t *m, int idex)
+{
+    if (m && idex >= 0) {
+        return (void *)m->values[idex]; /* DIRTY */
+    }
+
+    return NULL;
+}
+
+static void trim_prp_comment(char *prp)
+{
+#ifdef AS400
+    char *comment;
+    /* lots of lines that translate a '#' realtime deleted   */
+    comment = strchr(prp, *APR_NUMBERSIGN);
+#else
+    char *comment = strchr(prp, '#');
+#endif
+    if (comment) {
+        *comment = '\0';
+    }
+}
+
+static size_t trim(char *s)
+{
+    size_t i;
+
+    /* check for empty strings */
+    if (!(i = strlen(s)))
+        return 0;
+    for (i = i - 1; (i >= 0) &&
+         isspace((int)((unsigned char)s[i])); i--);
+
+    s[i + 1] = '\0';
+
+    for (i = 0; ('\0' != s[i]) &&
+         isspace((int)((unsigned char)s[i])); i++);
+
+    if (i > 0) {
+        strcpy(s, &s[i]);
+    }
+
+    return strlen(s);
+}
+
+static int map_realloc(jk_map_t *m)
+{
+    if (m->size == m->capacity) {
+        char **names;
+        void **values;
+        unsigned int *keys;
+        int capacity = m->capacity + CAPACITY_INC_SIZE;
+
+        names = (char **)jk_pool_alloc(&m->p, sizeof(char *) * capacity);
+        values = (void **)jk_pool_alloc(&m->p, sizeof(void *) * capacity);
+        keys = (unsigned int *)jk_pool_alloc(&m->p, sizeof(unsigned int) * capacity);
+
+        if (values && names) {
+            if (m->capacity && m->names)
+                memcpy(names, m->names, sizeof(char *) * m->capacity);
+
+            if (m->capacity && m->values)
+                memcpy(values, m->values, sizeof(void *) * m->capacity);
+
+            if (m->capacity && m->keys)
+                memcpy(keys, m->keys, sizeof(unsigned int) * m->capacity);
+
+            m->names = (const char **)names;
+            m->values = (const void **)values;
+            m->keys = keys;
+            m->capacity = capacity;
+
+            return JK_TRUE;
+        }
+    }
+
+    return JK_FALSE;
+}
+
+/**
+ *  Replace $(property) in value.
+ *
+ */
+char *jk_map_replace_properties(jk_map_t *m, const char *value)
+{
+    char *rc = (char *)value;
+    char *env_start = rc;
+    int rec = 0;
+
+    while ((env_start = strstr(env_start, "$(")) != NULL) {
+        char *env_end = strstr(env_start, ")");
+        if (rec++ > 20)
+            return rc;
+        if (env_end) {
+            char env_name[LENGTH_OF_LINE + 1] = "";
+            const char *env_value;
+#if defined(WIN32)
+            char env_buf[LENGTH_OF_LINE + 1];
+#endif
+            *env_end = '\0';
+            strcpy(env_name, env_start + 2);
+            *env_end = ')';
+
+            env_value = jk_map_get_string(m, env_name, NULL);
+            if (!env_value) {
+                env_value = getenv(env_name);
+            }
+#if defined(WIN32)
+            if (!env_value) {
+                /* Try the env block from calling process */
+                if (GetEnvironmentVariable(env_name, env_buf,
+                                           sizeof(env_buf)))
+                    env_value = &env_buf[0];
+            }
+#endif
+            if (env_value) {
+                size_t offset = 0;
+                char *new_value = jk_pool_alloc(&m->p,
+                                                (sizeof(char) *
+                                                (strlen(rc) +
+                                                strlen(env_value))));
+                if (!new_value) {
+                    break;
+                }
+                *env_start = '\0';
+                strcpy(new_value, rc);
+                strcat(new_value, env_value);
+                strcat(new_value, env_end + 1);
+                offset = env_start - rc + strlen(env_value);
+                rc = new_value;
+                /* Avoid recursive subst */
+                env_start = rc + offset;
+            }
+            else {
+                env_start = env_end;
+            }
+        }
+        else {
+            break;
+        }
+    }
+
+    return rc;
+}
+
+/**
+ *  Resolve references
+ *
+ */
+int jk_map_resolve_references(jk_map_t *m, const char *prefix,
+                              int wildcard, int depth, jk_logger_t *l)
+{
+    int rc = JK_FALSE;
+
+    JK_TRACE_ENTER(l);
+
+    if (m && prefix && depth <= JK_MAP_RECURSION) {
+        size_t prelen = strlen(prefix);
+        unsigned int i;
+        rc = JK_TRUE;
+        if (JK_IS_DEBUG_LEVEL(l))
+            jk_log(l, JK_LOG_DEBUG,
+                   "Checking for references with prefix %s with%s wildcard (recursion %d)",
+                   prefix, wildcard? "" : "out", depth);
+        for (i = 0; i < m->size; i++) {
+            if (m->values[i] && !strncmp(m->names[i], prefix, prelen)) {
+                size_t remain = strlen(m->names[i]) - prelen;
+                if ((remain == JK_MAP_REFERENCE_SZ ) || (wildcard && remain > JK_MAP_REFERENCE_SZ)) {
+                    remain = strlen(m->names[i]) - JK_MAP_REFERENCE_SZ;
+                    if (!strncmp(m->names[i] + remain, JK_MAP_REFERENCE, JK_MAP_REFERENCE_SZ)) {
+                        char *from = jk_pool_alloc(&m->p,
+                                                   (sizeof(char) *
+                                                   (strlen(m->values[i]) + 2)));
+                        char *to = jk_pool_alloc(&m->p,
+                                                 (sizeof(char) *
+                                                 (remain + 2)));
+                        if (!from || !to) {
+                            rc = JK_FALSE;
+                            break;
+                        }
+                        strcpy(from, m->values[i]);
+                        *(from+strlen(m->values[i]))   = '.';
+                        *(from+strlen(m->values[i])+1) = '\0';
+                        strncpy(to, m->names[i], remain);
+                        *(to+remain)   = '.';
+                        *(to+remain+1) = '\0';
+
+                        rc = jk_map_resolve_references(m, m->values[i], 0, ++depth, l);
+                        if (rc == JK_FALSE) {
+                            break;
+                        }
+                        if (JK_IS_DEBUG_LEVEL(l))
+                            jk_log(l, JK_LOG_DEBUG,
+                                   "Copying values from %s to %s",
+                                   from, to);
+                        rc = jk_map_inherit_properties(m, from, to);
+                        if (rc == JK_FALSE) {
+                            break;
+                        }
+                        m->values[i] = NULL;
+                    }
+                }
+            }
+        }
+    }
+    JK_TRACE_EXIT(l);
+    return rc;
+}
+
+/**
+ *  Inherit properties
+ *
+ */
+int jk_map_inherit_properties(jk_map_t *m, const char *from, const char *to)
+{
+    int rc = JK_FALSE;
+
+    if (m && from && to) {
+        unsigned int i;
+        rc = JK_TRUE;
+        for (i = 0; i < m->size; i++) {
+            if (!strncmp(m->names[i], from, strlen(from))) {
+                const char *prp = m->names[i] + strlen(from);
+                char *to_prp = jk_pool_alloc(&m->p,
+                                             (sizeof(char) *
+                                             (strlen(to) +
+                                             strlen(prp) + 1)));
+                if (!to_prp) {
+                    break;
+                }
+                strcpy(to_prp, to);
+                strcat(to_prp, prp);
+                if (jk_map_get_id(m, to_prp) < 0 ) {
+                    rc = jk_map_add(m, to_prp, m->values[i]);
+                    if (rc == JK_FALSE) {
+                        break;
+                    }
+                }
+            }
+        }
+    }
+    return rc;
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_map.h
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_map.h	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_map.h	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,88 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.
+ */
+
+/***************************************************************************
+ * Description: Map object header file                                     *
+ * Author:      Gal Shachor <shachor at il.ibm.com>                           *
+ * Version:     $Revision: 437381 $                                           *
+ ***************************************************************************/
+
+#ifndef JK_MAP_H
+#define JK_MAP_H
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif                          /* __cplusplus */
+
+
+struct jk_map;
+typedef struct jk_map jk_map_t;
+
+int jk_map_alloc(jk_map_t **m);
+
+int jk_map_free(jk_map_t **m);
+
+int jk_map_open(jk_map_t *m);
+
+int jk_map_close(jk_map_t *m);
+
+void *jk_map_get(jk_map_t *m, const char *name, const void *def);
+
+int jk_map_get_id(jk_map_t *m, const char *name);
+
+int jk_map_get_int(jk_map_t *m, const char *name, int def);
+
+double jk_map_get_double(jk_map_t *m, const char *name, double def);
+
+int jk_map_get_bool(jk_map_t *m, const char *name, int def);
+
+const char *jk_map_get_string(jk_map_t *m, const char *name, const char *def);
+
+char **jk_map_get_string_list(jk_map_t *m,
+                           const char *name,
+                           unsigned *list_len, const char *def);
+
+int jk_map_add(jk_map_t *m, const char *name, const void *value);
+
+int jk_map_put(jk_map_t *m, const char *name, const void *value, void **old);
+
+int jk_map_read_property(jk_map_t *m, const char *str, jk_logger_t *l);
+
+int jk_map_read_properties(jk_map_t *m, const char *f, time_t *modified, jk_logger_t *l);
+
+int jk_map_size(jk_map_t *m);
+
+const char *jk_map_name_at(jk_map_t *m, int idex);
+
+void *jk_map_value_at(jk_map_t *m, int idex);
+
+/**
+ *  Replace $(property) in value.
+ * 
+ */
+char *jk_map_replace_properties(jk_map_t *m, const char *value);
+
+int jk_map_resolve_references(jk_map_t *m, const char *prefix, int wildcard, int depth, jk_logger_t *l);
+
+int jk_map_inherit_properties(jk_map_t *m, const char *from, const char *to);
+
+#ifdef __cplusplus
+}
+#endif                          /* __cplusplus */
+
+#endif                          /* JK_MAP_H */

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_md5.c
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_md5.c	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_md5.c	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,474 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.
+ */
+
+/*
+ * This is work is derived from material Copyright RSA Data Security, Inc.
+ *
+ * The RSA copyright statement and Licence for that original material is
+ * included below. This is followed by the Apache copyright statement and
+ * licence for the modifications made to that material.
+ */
+
+/* MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm
+ */
+
+/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
+   rights reserved.
+
+   License to copy and use this software is granted provided that it
+   is identified as the "RSA Data Security, Inc. MD5 Message-Digest
+   Algorithm" in all material mentioning or referencing this software
+   or this function.
+
+   License is also granted to make and use derivative works provided
+   that such works are identified as "derived from the RSA Data
+   Security, Inc. MD5 Message-Digest Algorithm" in all material
+   mentioning or referencing the derived work.
+
+   RSA Data Security, Inc. makes no representations concerning either
+   the merchantability of this software or the suitability of this
+   software for any particular purpose. It is provided "as is"
+   without express or implied warranty of any kind.
+
+   These notices must be retained in any copies of any part of this
+   documentation and/or software.
+ */
+
+/*
+ * The ap_MD5Encode() routine uses much code obtained from the FreeBSD 3.0
+ * MD5 crypt() function, which is licenced as follows:
+ * ----------------------------------------------------------------------------
+ * "THE BEER-WARE LICENSE" (Revision 42):
+ * <phk at login.dknet.dk> wrote this file.  As long as you retain this notice you
+ * can do whatever you want with this stuff. If we meet some day, and you think
+ * this stuff is worth it, you can buy me a beer in return.   Poul-Henning Kamp
+ * ----------------------------------------------------------------------------
+ */
+
+/***************************************************************************
+ * Description: MD5 encoding wrapper                                       *
+ * Author:      Henri Gomez <hgomez at apache.org>                            *
+ * Version:     $Revision: 406380 $                                           *
+ ***************************************************************************/
+
+/*
+ * JK MD5 Encoding function (jk_MD5Encode)
+ *
+ * Jk delegate MD5 encoding to ap_MD5Encode when used in Apache Web-Server.
+ * When another web-server is used like NES/IIS, we should use corresponding calls.
+ * NES/IIS specialists will add the necessary code but until that, I reused the code
+ * from Apache HTTP server.
+ * 
+ * Nota: If you use an EBCDIC system without Apache, you'll have to use MD5 encoding
+ * corresponding call or have a ebcdic2ascii() functions somewhere.
+ * For example current AS/400 have MD5 encoding support APIs but olders not....
+ */
+
+#include "jk_global.h"
+#include "jk_md5.h"
+
+char *JK_METHOD jk_hextocstr(unsigned char *org, char *dst, int n)
+{
+    char *os = dst;
+    unsigned char v;
+    static unsigned char zitohex[] = "0123456789ABCDEF";
+
+    while (--n >= 0) {
+        v = *org++;
+        *dst++ = zitohex[v >> 4];
+        *dst++ = zitohex[v & 0x0f];
+    }
+    *dst = 0;
+
+    return (os);
+}
+
+#ifndef USE_APACHE_MD5
+
+/* Constants for MD5Transform routine.
+ */
+
+#define S11 7
+#define S12 12
+#define S13 17
+#define S14 22
+#define S21 5
+#define S22 9
+#define S23 14
+#define S24 20
+#define S31 4
+#define S32 11
+#define S33 16
+#define S34 23
+#define S41 6
+#define S42 10
+#define S43 15
+#define S44 21
+
+static void MD5Transform(jk_uint32_t state[4], const unsigned char block[64]);
+static void Encode(unsigned char *output, const jk_uint32_t * input, size_t len);
+static void Decode(jk_uint32_t * output, const unsigned char *input, size_t len);
+static void jk_MD5Init(JK_MD5_CTX * context);
+static void jk_MD5Update(JK_MD5_CTX * context, const unsigned char *input,
+                         size_t inputLen);
+/*static void jk_MD5Final(unsigned char digest[JK_MD5_DIGESTSIZE], JK_MD5_CTX *context);*/
+
+static unsigned char PADDING[64] = {
+    0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+/* F, G, H and I are basic MD5 functions.
+ */
+#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
+#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
+#define H(x, y, z) ((x) ^ (y) ^ (z))
+#define I(x, y, z) ((y) ^ ((x) | (~z)))
+
+/* ROTATE_LEFT rotates x left n bits.
+ */
+#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
+
+/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
+   Rotation is separate from addition to prevent recomputation.
+ */
+#define FF(a, b, c, d, x, s, ac) { \
+ (a) += F ((b), (c), (d)) + (x) + (jk_uint32_t)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+  }
+#define GG(a, b, c, d, x, s, ac) { \
+ (a) += G ((b), (c), (d)) + (x) + (jk_uint32_t)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+  }
+#define HH(a, b, c, d, x, s, ac) { \
+ (a) += H ((b), (c), (d)) + (x) + (jk_uint32_t)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+  }
+#define II(a, b, c, d, x, s, ac) { \
+ (a) += I ((b), (c), (d)) + (x) + (jk_uint32_t)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+  }
+
+/* MD5 initialization. Begins an MD5 operation, writing a new context.
+ */
+static void jk_MD5Init(JK_MD5_CTX * context)
+{
+    context->count[0] = context->count[1] = 0;
+    /* Load magic initialization constants. */
+    context->state[0] = 0x67452301;
+    context->state[1] = 0xefcdab89;
+    context->state[2] = 0x98badcfe;
+    context->state[3] = 0x10325476;
+}
+
+/* MD5 block update operation. Continues an MD5 message-digest
+   operation, processing another message block, and updating the
+   context.
+ */
+static void jk_MD5Update(JK_MD5_CTX * context, const unsigned char *input,
+                         size_t inputLen)
+{
+    size_t i, idx, partLen;
+
+    /* Compute number of bytes mod 64 */
+    idx = (size_t) ((context->count[0] >> 3) & 0x3F);
+
+    /* Update number of bits */
+    if ((context->count[0] += ((jk_uint32_t) inputLen << 3))
+        < ((jk_uint32_t) inputLen << 3)) {
+        context->count[1]++;
+    }
+    context->count[1] += (jk_uint32_t) inputLen >> 29;
+
+    partLen = 64 - idx;
+
+    /* Transform as many times as possible. */
+#ifndef CHARSET_EBCDIC
+    if (inputLen >= partLen) {
+        memcpy(&context->buffer[idx], input, partLen);
+        MD5Transform(context->state, context->buffer);
+
+        for (i = partLen; i + 63 < inputLen; i += 64) {
+            MD5Transform(context->state, &input[i]);
+        }
+
+        idx = 0;
+    }
+    else {
+        i = 0;
+    }
+
+    /* Buffer remaining input */
+    memcpy(&context->buffer[idx], &input[i], inputLen - i);
+#else /*CHARSET_EBCDIC */
+    if (inputLen >= partLen) {
+        ebcdic2ascii(&context->buffer[idx], input, partLen);
+        MD5Transform(context->state, context->buffer);
+
+        for (i = partLen; i + 63 < inputLen; i += 64) {
+            unsigned char inp_tmp[64];
+            ebcdic2ascii(inp_tmp, &input[i], 64);
+            MD5Transform(context->state, inp_tmp);
+        }
+
+        idx = 0;
+    }
+    else {
+        i = 0;
+    }
+
+    /* Buffer remaining input */
+    ebcdic2ascii(&context->buffer[idx], &input[i], inputLen - i);
+#endif /*CHARSET_EBCDIC */
+}
+
+/* MD5 finalization. Ends an MD5 message-digest operation, writing the
+   the message digest and zeroizing the context.
+ */
+static void JK_METHOD jk_MD5Final(unsigned char digest[16], JK_MD5_CTX * context)
+{
+    unsigned char bits[8];
+    size_t idx, padLen;
+
+
+    /* Save number of bits */
+    Encode(bits, context->count, 8);
+
+#ifdef CHARSET_EBCDIC
+    /* XXX: @@@: In order to make this no more complex than necessary,
+     * this kludge converts the bits[] array using the ascii-to-ebcdic
+     * table, because the following jk_MD5Update() re-translates
+     * its input (ebcdic-to-ascii).
+     * Otherwise, we would have to pass a "conversion" flag to jk_MD5Update()
+     */
+    ascii2ebcdic(bits, bits, 8);
+
+    /* Since everything is converted to ascii within jk_MD5Update(), 
+     * the initial 0x80 (PADDING[0]) must be stored as 0x20 
+     */
+    ascii2ebcdic(PADDING, PADDING, 1);
+#endif /*CHARSET_EBCDIC */
+
+    /* Pad out to 56 mod 64. */
+    idx = (size_t) ((context->count[0] >> 3) & 0x3f);
+    padLen = (idx < 56) ? (56 - idx) : (120 - idx);
+    jk_MD5Update(context, (const unsigned char *)PADDING, padLen);
+
+    /* Append length (before padding) */
+    jk_MD5Update(context, (const unsigned char *)bits, 8);
+
+    /* Store state in digest */
+    Encode(digest, context->state, 16);
+
+    /* Zeroize sensitive information. */
+    memset(context, 0, sizeof(*context));
+}
+
+/* MD5 basic transformation. Transforms state based on block. */
+static void MD5Transform(jk_uint32_t state[4], const unsigned char block[64])
+{
+    jk_uint32_t a = state[0], b = state[1], c = state[2], d = state[3], x[16];
+
+    Decode(x, block, 64);
+
+    /* Round 1 */
+    FF(a, b, c, d, x[0], S11, 0xd76aa478);      /* 1 */
+    FF(d, a, b, c, x[1], S12, 0xe8c7b756);      /* 2 */
+    FF(c, d, a, b, x[2], S13, 0x242070db);      /* 3 */
+    FF(b, c, d, a, x[3], S14, 0xc1bdceee);      /* 4 */
+    FF(a, b, c, d, x[4], S11, 0xf57c0faf);      /* 5 */
+    FF(d, a, b, c, x[5], S12, 0x4787c62a);      /* 6 */
+    FF(c, d, a, b, x[6], S13, 0xa8304613);      /* 7 */
+    FF(b, c, d, a, x[7], S14, 0xfd469501);      /* 8 */
+    FF(a, b, c, d, x[8], S11, 0x698098d8);      /* 9 */
+    FF(d, a, b, c, x[9], S12, 0x8b44f7af);      /* 10 */
+    FF(c, d, a, b, x[10], S13, 0xffff5bb1);     /* 11 */
+    FF(b, c, d, a, x[11], S14, 0x895cd7be);     /* 12 */
+    FF(a, b, c, d, x[12], S11, 0x6b901122);     /* 13 */
+    FF(d, a, b, c, x[13], S12, 0xfd987193);     /* 14 */
+    FF(c, d, a, b, x[14], S13, 0xa679438e);     /* 15 */
+    FF(b, c, d, a, x[15], S14, 0x49b40821);     /* 16 */
+
+    /* Round 2 */
+    GG(a, b, c, d, x[1], S21, 0xf61e2562);      /* 17 */
+    GG(d, a, b, c, x[6], S22, 0xc040b340);      /* 18 */
+    GG(c, d, a, b, x[11], S23, 0x265e5a51);     /* 19 */
+    GG(b, c, d, a, x[0], S24, 0xe9b6c7aa);      /* 20 */
+    GG(a, b, c, d, x[5], S21, 0xd62f105d);      /* 21 */
+    GG(d, a, b, c, x[10], S22, 0x2441453);      /* 22 */
+    GG(c, d, a, b, x[15], S23, 0xd8a1e681);     /* 23 */
+    GG(b, c, d, a, x[4], S24, 0xe7d3fbc8);      /* 24 */
+    GG(a, b, c, d, x[9], S21, 0x21e1cde6);      /* 25 */
+    GG(d, a, b, c, x[14], S22, 0xc33707d6);     /* 26 */
+    GG(c, d, a, b, x[3], S23, 0xf4d50d87);      /* 27 */
+    GG(b, c, d, a, x[8], S24, 0x455a14ed);      /* 28 */
+    GG(a, b, c, d, x[13], S21, 0xa9e3e905);     /* 29 */
+    GG(d, a, b, c, x[2], S22, 0xfcefa3f8);      /* 30 */
+    GG(c, d, a, b, x[7], S23, 0x676f02d9);      /* 31 */
+    GG(b, c, d, a, x[12], S24, 0x8d2a4c8a);     /* 32 */
+
+    /* Round 3 */
+    HH(a, b, c, d, x[5], S31, 0xfffa3942);      /* 33 */
+    HH(d, a, b, c, x[8], S32, 0x8771f681);      /* 34 */
+    HH(c, d, a, b, x[11], S33, 0x6d9d6122);     /* 35 */
+    HH(b, c, d, a, x[14], S34, 0xfde5380c);     /* 36 */
+    HH(a, b, c, d, x[1], S31, 0xa4beea44);      /* 37 */
+    HH(d, a, b, c, x[4], S32, 0x4bdecfa9);      /* 38 */
+    HH(c, d, a, b, x[7], S33, 0xf6bb4b60);      /* 39 */
+    HH(b, c, d, a, x[10], S34, 0xbebfbc70);     /* 40 */
+    HH(a, b, c, d, x[13], S31, 0x289b7ec6);     /* 41 */
+    HH(d, a, b, c, x[0], S32, 0xeaa127fa);      /* 42 */
+    HH(c, d, a, b, x[3], S33, 0xd4ef3085);      /* 43 */
+    HH(b, c, d, a, x[6], S34, 0x4881d05);       /* 44 */
+    HH(a, b, c, d, x[9], S31, 0xd9d4d039);      /* 45 */
+    HH(d, a, b, c, x[12], S32, 0xe6db99e5);     /* 46 */
+    HH(c, d, a, b, x[15], S33, 0x1fa27cf8);     /* 47 */
+    HH(b, c, d, a, x[2], S34, 0xc4ac5665);      /* 48 */
+
+    /* Round 4 */
+    II(a, b, c, d, x[0], S41, 0xf4292244);      /* 49 */
+    II(d, a, b, c, x[7], S42, 0x432aff97);      /* 50 */
+    II(c, d, a, b, x[14], S43, 0xab9423a7);     /* 51 */
+    II(b, c, d, a, x[5], S44, 0xfc93a039);      /* 52 */
+    II(a, b, c, d, x[12], S41, 0x655b59c3);     /* 53 */
+    II(d, a, b, c, x[3], S42, 0x8f0ccc92);      /* 54 */
+    II(c, d, a, b, x[10], S43, 0xffeff47d);     /* 55 */
+    II(b, c, d, a, x[1], S44, 0x85845dd1);      /* 56 */
+    II(a, b, c, d, x[8], S41, 0x6fa87e4f);      /* 57 */
+    II(d, a, b, c, x[15], S42, 0xfe2ce6e0);     /* 58 */
+    II(c, d, a, b, x[6], S43, 0xa3014314);      /* 59 */
+    II(b, c, d, a, x[13], S44, 0x4e0811a1);     /* 60 */
+    II(a, b, c, d, x[4], S41, 0xf7537e82);      /* 61 */
+    II(d, a, b, c, x[11], S42, 0xbd3af235);     /* 62 */
+    II(c, d, a, b, x[2], S43, 0x2ad7d2bb);      /* 63 */
+    II(b, c, d, a, x[9], S44, 0xeb86d391);      /* 64 */
+
+    state[0] += a;
+    state[1] += b;
+    state[2] += c;
+    state[3] += d;
+
+    /* Zeroize sensitive information. */
+    memset(x, 0, sizeof(x));
+}
+
+/* Encodes input (jk_uint32_t) into output (unsigned char). Assumes len is
+   a multiple of 4.
+ */
+static void Encode(unsigned char *output, const jk_uint32_t * input, size_t len)
+{
+    size_t i, j;
+    jk_uint32_t k;
+
+    for (i = 0, j = 0; j < len; i++, j += 4) {
+        k = input[i];
+        output[j] = (unsigned char)(k & 0xff);
+        output[j + 1] = (unsigned char)((k >> 8) & 0xff);
+        output[j + 2] = (unsigned char)((k >> 16) & 0xff);
+        output[j + 3] = (unsigned char)((k >> 24) & 0xff);
+    }
+}
+
+/* Decodes input (unsigned char) into output (jk_uint32_t). Assumes len is
+ * a multiple of 4.
+ */
+static void Decode(jk_uint32_t * output, const unsigned char *input, size_t len)
+{
+    size_t i, j;
+
+    for (i = 0, j = 0; j < len; i++, j += 4)
+        output[i] = ((jk_uint32_t) input[j]) | (((jk_uint32_t) input[j + 1]) << 8) |
+            (((jk_uint32_t) input[j + 2]) << 16) | (((jk_uint32_t) input[j + 3]) <<
+                                                 24);
+}
+
+char *JK_METHOD jk_md5(const unsigned char *org, const unsigned char *org2,
+                       char *dst)
+{
+    JK_MD5_CTX ctx;
+    char buf[JK_MD5_DIGESTSIZE + 1];
+
+    jk_MD5Init(&ctx);
+    jk_MD5Update(&ctx, org, strlen((const char *)org));
+
+    if (org2 != NULL)
+        jk_MD5Update(&ctx, org2, strlen((const char *)org2));
+
+    jk_MD5Final((unsigned char *)buf, &ctx);
+    return (jk_hextocstr((unsigned char *)buf, dst, JK_MD5_DIGESTSIZE));
+}
+
+#else /* USE_APACHE_MD5 */
+
+#include "httpd.h"
+#include "http_config.h"
+
+#ifdef STANDARD20_MODULE_STUFF
+
+#include "apr_md5.h"
+#define  AP_MD5_CTX     apr_md5_ctx_t
+#define  ap_MD5Init     apr_md5_init
+#define  ap_MD5Update   apr_md5_update
+#define  ap_MD5Final    apr_md5_final
+
+#else /* STANDARD20_MODULE_STUFF */
+
+#include "ap_md5.h"
+
+#endif /* STANDARD20_MODULE_STUFF */
+
+char *JK_METHOD jk_md5(const unsigned char *org, const unsigned char *org2,
+                       char *dst)
+{
+    AP_MD5_CTX ctx;
+    char buf[JK_MD5_DIGESTSIZE + 1];
+
+    ap_MD5Init(&ctx);
+    ap_MD5Update(&ctx, org, strlen((const char *)org));
+
+    if (org2 != NULL)
+        ap_MD5Update(&ctx, org2, strlen((const char *)org2));
+
+    ap_MD5Final((unsigned char *)buf, &ctx);
+    return (jk_hextocstr((unsigned char *)buf, dst, JK_MD5_DIGESTSIZE));
+}
+
+#endif /* USE_APACHE_MD5 */
+
+/* Test values:
+ * ""                  D4 1D 8C D9 8F 00 B2 04  E9 80 09 98 EC F8 42 7E
+ * "a"                 0C C1 75 B9 C0 F1 B6 A8  31 C3 99 E2 69 77 26 61
+ * "abc                90 01 50 98 3C D2 4F B0  D6 96 3F 7D 28 E1 7F 72
+ * "message digest"    F9 6B 69 7D 7C B7 93 8D  52 5A 2F 31 AA F1 61 D0
+ *
+ */
+
+#ifdef TEST_JKMD5
+
+main(int argc, char **argv)
+{
+    char xxx[(2 * JK_MD5_DIGESTSIZE) + 1];
+
+    if (argc > 1)
+        printf("%s => %s\n", argv[1], jk_md5(argv[1], NULL, xxx));
+}
+
+#endif

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_md5.h
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_md5.h	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_md5.h	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,83 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.
+ */
+
+/*
+ * This is work is derived from material Copyright RSA Data Security, Inc.
+ *
+ * The RSA copyright statement and Licence for that original material is
+ * included below. This is followed by the Apache copyright statement and
+ * licence for the modifications made to that material.
+ */
+
+/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
+   rights reserved.
+
+   License to copy and use this software is granted provided that it
+   is identified as the "RSA Data Security, Inc. MD5 Message-Digest
+   Algorithm" in all material mentioning or referencing this software
+   or this function.
+
+   License is also granted to make and use derivative works provided
+   that such works are identified as "derived from the RSA Data
+   Security, Inc. MD5 Message-Digest Algorithm" in all material
+   mentioning or referencing the derived work.
+
+   RSA Data Security, Inc. makes no representations concerning either
+   the merchantability of this software or the suitability of this
+   software for any particular purpose. It is provided "as is"
+   without express or implied warranty of any kind.
+
+   These notices must be retained in any copies of any part of this
+   documentation and/or software.
+*/
+
+#ifndef JK_APACHE_MD5_H
+#define JK_APACHE_MD5_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/* MD5.H - header file for MD5.C */
+
+#define JK_MD5_DIGESTSIZE 16
+
+/* MD5 context. */
+typedef struct
+{
+    jk_uint32_t state[4];      /* state (ABCD) */
+    jk_uint32_t count[2];      /* number of bits, modulo 2^64 (lsb first) */
+    unsigned char buffer[64];       /* input buffer */
+} JK_MD5_CTX;
+
+/*
+ * Define the Magic String prefix that identifies a password as being
+ * hashed using our algorithm.
+ */
+#define JK_MD5PW_ID "$apr1$"
+#define JK_MD5PW_IDLEN 6
+
+char *JK_METHOD jk_hextocstr(unsigned char *org, char *dst, int n);
+char *JK_METHOD jk_md5(const unsigned char *org,
+                       const unsigned char *org2, char *dst);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif                          /* !JK_APACHE_MD5_H */

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_msg_buff.c
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_msg_buff.c	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_msg_buff.c	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,368 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.
+ */
+
+/***************************************************************************
+ * Description: Data marshaling. XDR like                                  *
+ * Author:      Costin <costin at costin.dnt.ro>                              *
+ * Author:      Gal Shachor <shachor at il.ibm.com>                           *
+ * Author:      Henri Gomez <hgomez at apache.org>                            *
+ * Version:     $Revision: 300508 $                                          *
+ ***************************************************************************/
+
+#include "jk_pool.h"
+#include "jk_connect.h"
+#include "jk_util.h"
+#include "jk_sockbuf.h"
+#include "jk_msg_buff.h"
+#include "jk_logger.h"
+
+static char *jk_HEX = "0123456789ABCDEFX";
+
+/*
+ * Simple marshaling code.
+ */
+
+void jk_b_reset(jk_msg_buf_t *msg)
+{
+    msg->len = 4;
+    msg->pos = 4;
+}
+
+int jk_b_append_long(jk_msg_buf_t *msg, unsigned long val)
+{
+    if (msg->len + 4 > msg->maxlen) {
+        return -1;
+    }
+
+    msg->buf[msg->len++] = (unsigned char)((val >> 24) & 0xFF);
+    msg->buf[msg->len++] = (unsigned char)((val >> 16) & 0xFF);
+    msg->buf[msg->len++] = (unsigned char)((val >> 8) & 0xFF);
+    msg->buf[msg->len++] = (unsigned char)((val) & 0xFF);
+
+    return 0;
+}
+
+
+int jk_b_append_int(jk_msg_buf_t *msg, unsigned short val)
+{
+    if (msg->len + 2 > msg->maxlen) {
+        return -1;
+    }
+
+    msg->buf[msg->len++] = (unsigned char)((val >> 8) & 0xFF);
+    msg->buf[msg->len++] = (unsigned char)((val) & 0xFF);
+
+    return 0;
+}
+
+
+int jk_b_append_byte(jk_msg_buf_t *msg, unsigned char val)
+{
+    if (msg->len + 1 > msg->maxlen) {
+        return -1;
+    }
+
+    msg->buf[msg->len++] = val;
+
+    return 0;
+}
+
+
+void jk_b_end(jk_msg_buf_t *msg, int protoh)
+{
+    /* 
+     * Ugly way to set the size in the right position 
+     */
+    int hlen = msg->len - 4;
+
+    msg->buf[0] = (unsigned char)((protoh >> 8) & 0xFF);
+    msg->buf[1] = (unsigned char)((protoh) & 0xFF);
+    msg->buf[2] = (unsigned char)((hlen >> 8) & 0xFF);
+    msg->buf[3] = (unsigned char)((hlen) & 0xFF);
+
+}
+
+
+jk_msg_buf_t *jk_b_new(jk_pool_t *p)
+{
+    jk_msg_buf_t *msg =
+        (jk_msg_buf_t *)jk_pool_alloc(p, sizeof(jk_msg_buf_t));
+
+    if (!msg) {
+        return NULL;
+    }
+
+    msg->pool = p;
+
+    return msg;
+}
+
+int jk_b_set_buffer(jk_msg_buf_t *msg, unsigned char *data, int buffSize)
+{
+    if (!msg) {
+        return -1;
+    }
+
+    msg->len = 0;
+    msg->buf = data;
+    msg->maxlen = buffSize;
+
+    return 0;
+}
+
+
+int jk_b_set_buffer_size(jk_msg_buf_t *msg, int buffSize)
+{
+    unsigned char *data = (unsigned char *)jk_pool_alloc(msg->pool, buffSize);
+
+    if (!data) {
+        return -1;
+    }
+
+    jk_b_set_buffer(msg, data, buffSize);
+    return 0;
+}
+
+#ifdef AS400
+int jk_b_append_asciistring(jk_msg_buf_t *msg, const char *param)
+{
+    int len;
+
+    if (!param) {
+        jk_b_append_int(msg, 0xFFFF);
+        return 0;
+    }
+
+    len = strlen(param);
+    if (msg->len + len + 2 > msg->maxlen) {
+        return -1;
+    }
+
+    /* ignore error - we checked once */
+    jk_b_append_int(msg, (unsigned short)len);
+
+    /* We checked for space !!  */
+    strncpy((char *)msg->buf + msg->len, param, len + 1);       /* including \0 */
+    msg->len += len + 1;
+
+    return 0;
+}
+#endif
+
+int jk_b_append_string(jk_msg_buf_t *msg, const char *param)
+{
+    unsigned short len;
+
+    if (!param) {
+        jk_b_append_int(msg, 0xFFFF);
+        return 0;
+    }
+
+    len = (unsigned short)strlen(param);
+    if (msg->len + len + 2 > msg->maxlen) {
+        return -1;
+    }
+
+    /* ignore error - we checked once */
+    jk_b_append_int(msg, len);
+
+    /* We checked for space !!  */
+    strncpy((char *)msg->buf + msg->len, param, len + 1);       /* including \0 */
+#if defined(AS400) || defined(_OSD_POSIX)
+    /* convert from EBCDIC if needed */
+    jk_xlate_to_ascii((char *)msg->buf + msg->len, len + 1);
+#endif
+    msg->len += len + 1;
+
+    return 0;
+}
+
+
+int jk_b_append_bytes(jk_msg_buf_t *msg, const unsigned char *param, int len)
+{
+    if (!len) {
+        return 0;
+    }
+
+    if (msg->len + len > msg->maxlen) {
+        return -1;
+    }
+
+    /* We checked for space !!  */
+    memcpy((char *)msg->buf + msg->len, param, len);
+    msg->len += len;
+
+    return 0;
+}
+
+unsigned long jk_b_get_long(jk_msg_buf_t *msg)
+{
+    unsigned long i;
+    if (msg->pos + 3 > msg->len) {
+        return 0xFFFFFFFF;
+    }
+    i = ((msg->buf[(msg->pos++)] & 0xFF) << 24);
+    i |= ((msg->buf[(msg->pos++)] & 0xFF) << 16);
+    i |= ((msg->buf[(msg->pos++)] & 0xFF) << 8);
+    i |= ((msg->buf[(msg->pos++)] & 0xFF));
+    return i;
+}
+
+unsigned long jk_b_pget_long(jk_msg_buf_t *msg, int pos)
+{
+    unsigned long i;
+    i = ((msg->buf[(pos++)] & 0xFF) << 24);
+    i |= ((msg->buf[(pos++)] & 0xFF) << 16);
+    i |= ((msg->buf[(pos++)] & 0xFF) << 8);
+    i |= ((msg->buf[(pos)] & 0xFF));
+    return i;
+}
+
+
+unsigned short jk_b_get_int(jk_msg_buf_t *msg)
+{
+    unsigned short i;
+    if (msg->pos + 1 > msg->len) {
+        return 0xFFFF;
+    }
+    i = ((msg->buf[(msg->pos++)] & 0xFF) << 8);
+    i += ((msg->buf[(msg->pos++)] & 0xFF));
+    return i;
+}
+
+unsigned short jk_b_pget_int(jk_msg_buf_t *msg, int pos)
+{
+    unsigned short i;
+    i = ((msg->buf[pos++] & 0xFF) << 8);
+    i += ((msg->buf[pos] & 0xFF));
+    return i;
+}
+
+unsigned char jk_b_get_byte(jk_msg_buf_t *msg)
+{
+    unsigned char rc;
+    if (msg->pos > msg->len) {
+        return 0xFF;
+    }
+    rc = msg->buf[msg->pos++];
+
+    return rc;
+}
+
+unsigned char jk_b_pget_byte(jk_msg_buf_t *msg, int pos)
+{
+    return msg->buf[pos];
+}
+
+
+unsigned char *jk_b_get_string(jk_msg_buf_t *msg)
+{
+    unsigned short size = jk_b_get_int(msg);
+    int start = msg->pos;
+
+    if ((size == 0xFFFF) || (size + start > msg->maxlen)) {
+        /* TODO: return NULL and deal with that in the code */
+        return (unsigned char *)"ERROR";
+    }
+
+    msg->pos += size;
+    msg->pos++;                 /* terminating NULL */
+
+    return (unsigned char *)(msg->buf + start);
+}
+
+int jk_b_get_bytes(jk_msg_buf_t *msg, unsigned char *buf, int len)
+{
+    int start = msg->pos;
+
+    if ((len < 0) || (len + start > msg->maxlen)) {
+        return (-1);
+    }
+
+    memcpy(buf, msg->buf + start, len);
+    msg->pos += len;
+    return (len);
+}
+
+
+
+/** Helpie dump function 
+ */
+void jk_dump_buff(jk_logger_t *l,
+                  const char *file,
+                  int line, const char *funcname,
+                  int level, char *what, jk_msg_buf_t *msg)
+{
+    int i = 0;
+    char lb[80];
+    char *current;
+    int j;
+    int len = msg->len;
+    
+    if (l == NULL)
+        return;
+    if (l->level != JK_LOG_TRACE_LEVEL && len > 1024)
+        len = 1024;
+
+    jk_log(l, file, line, funcname, level,
+           "%s pos=%d len=%d max=%d",
+           what, msg->pos, msg->len, msg->maxlen);
+
+    for (i = 0; i < len; i += 16) {
+        current = &lb[0];
+
+        for (j = 0; j < 16; j++) {
+            unsigned char x = (msg->buf[i + j]);
+            if ((i + j) >= len)
+                x = 0;
+            *current++ = jk_HEX[x >> 4];
+            *current++ = jk_HEX[x & 0x0f];
+            *current++ = ' ';
+        }
+        *current++ = ' ';
+        *current++ = '-';
+        *current++ = ' ';
+        for (j = 0; j < 16; j++) {
+            unsigned char x = msg->buf[i + j];
+            if ((i + j) >= len)
+                x = 0;
+            if (x > 0x20 && x < 0x7F) {
+                *current++ = x;
+            }
+            else {
+                *current++ = '.';
+            }
+        }
+        *current++ = '\0';
+            jk_log(l, file, line, funcname, level,
+                   "%.4x    %s", i, lb);
+    }
+}
+
+
+int jk_b_copy(jk_msg_buf_t *smsg, jk_msg_buf_t *dmsg)
+{
+    if (smsg == NULL || dmsg == NULL)
+        return (-1);
+
+    if (dmsg->maxlen < smsg->len)
+        return (-2);
+
+    memcpy(dmsg->buf, smsg->buf, smsg->len);
+    dmsg->len = smsg->len;
+
+    return (smsg->len);
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_msg_buff.h
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_msg_buff.h	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_msg_buff.h	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,153 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.
+ */
+
+/***************************************************************************
+ * Description: Data marshaling. XDR like                                  *
+ * Author:      Costin <costin at costin.dnt.ro>                              *
+ * Author:      Gal Shachor <shachor at il.ibm.com>                           *
+ * Version:     $Revision: 300507 $                                           *
+ ***************************************************************************/
+
+#ifndef JK_MSG_BUF_H
+#define JK_MSG_BUF_H
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif                          /* __cplusplus */
+
+#define DEF_BUFFER_SZ (8 * 1024)
+
+/* XXX replace all return values with error codes */
+#define ERR_BAD_PACKET -5
+
+/*
+RPC details:
+
+  - one parameter  - use a structure for more. The method
+    is encoded as part of the request
+  - one or no result
+  - 
+
+
+
+ */
+
+typedef struct jk_msg_buf_t jk_msg_buf_t;
+struct jk_msg_buf_t
+{
+    jk_pool_t *pool;
+    unsigned char *buf;
+    int pos;
+    int len;
+    int maxlen;
+};
+
+
+/* -------------------- Setup routines -------------------- */
+
+/** Allocate a buffer.
+ */
+jk_msg_buf_t *jk_b_new(jk_pool_t *p);
+
+/** Set up a buffer with an existing buffer
+ */
+int jk_b_set_buffer(jk_msg_buf_t *msg, unsigned char *data, int buffSize);
+
+/*
+ * Set up a buffer with a new buffer of buffSize
+ */
+int jk_b_set_buffer_size(jk_msg_buf_t *msg, int buffSize);
+
+/*
+ * Finalize the buffer before sending - set length fields, etc
+ */
+void jk_b_end(jk_msg_buf_t *msg, int protoh);
+
+/*
+ * Recycle the buffer - z for a new invocation 
+ */
+void jk_b_reset(jk_msg_buf_t *msg);
+
+/* -------------------- Real encoding -------------------- */
+
+int jk_b_append_byte(jk_msg_buf_t *msg, unsigned char val);
+
+int jk_b_append_bytes(jk_msg_buf_t *msg,
+                      const unsigned char *param, int len);
+
+int jk_b_append_int(jk_msg_buf_t *msg, unsigned short val);
+
+int jk_b_append_long(jk_msg_buf_t *msg, unsigned long val);
+
+int jk_b_append_string(jk_msg_buf_t *msg, const char *param);
+
+#ifdef AS400
+int jk_b_append_asciistring(jk_msg_buf_t *msg, const char *param);
+#endif
+
+int jk_b_append_bytes(jk_msg_buf_t *msg,
+                      const unsigned char *param, int len);
+
+/* -------------------- Decoding -------------------- */
+
+/** Get a byte from the current position 
+ */
+unsigned char jk_b_get_byte(jk_msg_buf_t *msg);
+
+/** Get an int from the current position
+ */
+unsigned short jk_b_get_int(jk_msg_buf_t *msg);
+
+/** Get a long from the current position
+ */
+unsigned long jk_b_get_long(jk_msg_buf_t *msg);
+
+/** Get a String from the current position
+ */
+unsigned char *jk_b_get_string(jk_msg_buf_t *msg);
+
+/** Get Bytes from the current position
+ */
+int jk_b_get_bytes(jk_msg_buf_t *msg, unsigned char *buf, int len);
+
+/** Get a byte from an arbitrary position
+ */
+unsigned char jk_b_pget_byte(jk_msg_buf_t *msg, int pos);
+
+/** Get an int from an arbitrary position 
+ */
+unsigned short jk_b_pget_int(jk_msg_buf_t *msg, int pos);
+
+/** Get a long from an arbitrary position 
+ */
+unsigned long jk_b_pget_long(jk_msg_buf_t *msg, int pos);
+
+/* --------------------- Help ------------------------ */
+void jk_dump_buff(jk_logger_t *l,
+                  const char *file,
+                  int line, const char *funcname,
+                  int level, char *what, jk_msg_buf_t *msg);
+
+/** Copy a msg buf into another one
+  */
+int jk_b_copy(jk_msg_buf_t *smsg, jk_msg_buf_t *dmsg);
+
+#ifdef __cplusplus
+}
+#endif    /* __cplusplus */
+#endif    /* JK_MSG_BUF_H */

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_mt.h
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_mt.h	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_mt.h	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,145 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.
+ */
+
+/***************************************************************************
+ * Description: Multi thread portability code for JK                       *
+ * Author:      Gal Shachor <shachor at il.ibm.com>                           *
+ * Version:     $Revision: 300467 $                                           *
+ ***************************************************************************/
+
+#ifndef _JK_MT_H
+#define _JK_MT_H
+
+#include "jk_global.h"
+
+
+#if defined(WIN32)
+#define jk_gettid()    ((int)GetCurrentThreadId())
+#elif defined(NETWARE) && !defined(__NOVELL_LIBC__)
+#define getpid()       ((int)GetThreadGroupID())
+#endif
+
+/*
+ * All WIN32 code is MT, UNIX code that uses pthreads is marked by the POSIX
+ * _REENTRANT define.
+ */
+#if defined (WIN32) || defined(_REENTRANT) || (defined(NETWARE) && defined(__NOVELL_LIBC__))
+#ifdef JK_PREFORK 
+#define _MT_CODE 0
+#else
+#define _MT_CODE 1
+#endif
+#else
+#define _MT_CODE 0
+#endif
+
+/*
+ * Marks execution under MT compilation
+ */
+#if _MT_CODE
+#ifdef WIN32
+#include <windows.h>
+
+typedef CRITICAL_SECTION JK_CRIT_SEC;
+#define JK_INIT_CS(x, rc) InitializeCriticalSection(x); rc = JK_TRUE
+#define JK_DELETE_CS(x, rc) DeleteCriticalSection(x);   rc = JK_TRUE
+#define JK_ENTER_CS(x, rc) EnterCriticalSection(x);     rc = JK_TRUE
+#define JK_LEAVE_CS(x, rc) LeaveCriticalSection(x);     rc = JK_TRUE
+
+#else /* !WIN32 */
+#define _MT_CODE_PTHREAD
+#include <pthread.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+typedef pthread_mutex_t JK_CRIT_SEC;
+#define JK_INIT_CS(x, rc)\
+            if(pthread_mutex_init(x, NULL)) rc = JK_FALSE; else rc = JK_TRUE
+
+#define JK_DELETE_CS(x, rc)\
+            if(pthread_mutex_destroy(x))    rc = JK_FALSE; else rc = JK_TRUE
+
+#define JK_ENTER_CS(x, rc)\
+            if(pthread_mutex_lock(x))       rc = JK_FALSE; else rc = JK_TRUE
+
+#define JK_LEAVE_CS(x, rc)\
+            if(pthread_mutex_unlock(x))     rc = JK_FALSE; else rc = JK_TRUE
+
+int jk_gettid(void);
+#endif /* WIN32 */
+
+#else /* !_MT_CODE */
+
+typedef void *JK_CRIT_SEC;
+#define JK_INIT_CS(x, rc)   rc = JK_TRUE
+#define JK_DELETE_CS(x, rc) rc = JK_TRUE
+#define JK_ENTER_CS(x, rc)  rc = JK_TRUE
+#define JK_LEAVE_CS(x, rc)  rc = JK_TRUE
+#define jk_gettid()         0
+#endif /* MT_CODE */
+
+#if !defined(WIN32) && !defined(NETWARE)
+#include <unistd.h>
+#include <fcntl.h>
+
+#if HAVE_FLOCK
+#include <sys/file.h>
+
+#define JK_ENTER_LOCK(x, rc)        \
+    do {                            \
+      while ((rc = flock((x), LOCK_EX) < 0) && (errno == EINTR)); \
+      rc = rc == 0 ? JK_TRUE : JK_FALSE; \
+    } while (0)
+
+#define JK_LEAVE_LOCK(x, rc)        \
+    do {                            \
+      while ((rc = flock((x), LOCK_UN) < 0) && (errno == EINTR)); \
+      rc = rc == 0 ? JK_TRUE : JK_FALSE; \
+    } while (0)
+
+#else
+
+#define JK_ENTER_LOCK(x, rc)        \
+    do {                            \
+      struct flock _fl;             \
+      _fl.l_type   = F_WRLCK;       \
+      _fl.l_whence = SEEK_SET;      \
+      _fl.l_start  = 0;             \
+      _fl.l_len    = 1L;            \
+      _fl.l_pid    = 0;             \
+      while ((rc = fcntl((x), F_SETLKW, &_fl) < 0) && (errno == EINTR)); \
+      rc = rc == 0 ? JK_TRUE : JK_FALSE; \
+    } while (0)
+
+#define JK_LEAVE_LOCK(x, rc)        \
+    do {                            \
+      struct flock _fl;             \
+      _fl.l_type   = F_UNLCK;       \
+      _fl.l_whence = SEEK_SET;      \
+      _fl.l_start  = 0;             \
+      _fl.l_len    = 1L;            \
+      _fl.l_pid    = 0;             \
+      while ((rc = fcntl((x), F_SETLKW, &_fl) < 0) && (errno == EINTR)); \
+      rc = rc == 0 ? JK_TRUE : JK_FALSE; \
+    } while (0)
+#endif /* HAVE_FLOCK */
+
+#else  /* WIN32 || NETWARE */
+#define JK_ENTER_LOCK(x, rc) rc = JK_TRUE
+#define JK_LEAVE_LOCK(x, rc) rc = JK_TRUE
+#endif
+
+#endif /* _JK_MT_H */

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_nwmain.c
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_nwmain.c	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_nwmain.c	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,102 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.
+ */
+
+/***************************************************************************
+ * Description: Netware Wrapper                                            *
+ * Author:      Mike Anderson <mmander at novell.com>                         *
+ * Version:     $Revision: 299829 $                                           *
+ ***************************************************************************/
+
+#ifdef NETWARE
+/*
+ * NATIVE_MAIN
+ */
+
+/*
+ * INCLUDES
+ */
+
+#include <stdio.h>
+
+/* Apache 2/APR uses NOVELL_LIBC which has a different way of handling
+ * "library" nlms.  If we aren't on LIBC, use the old method
+ */
+
+#ifndef __NOVELL_LIBC__
+#include <nwthread.h>
+#include <netdb.h>
+
+NETDB_DEFINE_CONTEXT
+/*
+ * main ()
+ *
+ * Main entry point -- don't do much more than I've provided
+ *
+ * Entry:
+ *
+ * Exit:
+ *    Nothing
+ */
+void main()
+{
+    ExitThread(TSR_THREAD, 0);
+}
+#else /* __NOVELL_LIBC__ */
+
+/* Since we are on LibC, we need to handle our own startup and shutdown */
+
+#include <netware.h>
+#include "novsock2.h"
+
+int _NonAppStart
+    (void *NLMHandle,
+     void *errorScreen,
+     const char *cmdLine,
+     const char *loadDirPath,
+     size_t uninitializedDataLength,
+     void *NLMFileHandle,
+     int (*readRoutineP) (int conn, void *fileHandle, size_t offset,
+                          size_t nbytes, size_t * bytesRead, void *buffer),
+     size_t customDataOffset,
+     size_t customDataSize, int messageCount, const char **messages)
+{
+#pragma unused(cmdLine)
+#pragma unused(loadDirPath)
+#pragma unused(uninitializedDataLength)
+#pragma unused(NLMFileHandle)
+#pragma unused(readRoutineP)
+#pragma unused(customDataOffset)
+#pragma unused(customDataSize)
+#pragma unused(messageCount)
+#pragma unused(messages)
+
+    WSADATA wsaData;
+
+    return WSAStartup((WORD) MAKEWORD(2, 0), &wsaData);
+}
+
+void _NonAppStop(void)
+{
+    WSACleanup();
+}
+
+int _NonAppCheckUnload(void)
+{
+    return 0;
+}
+#endif /* __NOVELL_LIBC__ */
+
+#endif

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_pool.c
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_pool.c	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_pool.c	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,164 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.
+ */
+
+/***************************************************************************
+ * Description: Simple memory pool                                         *
+ * Author:      Gal Shachor <shachor at il.ibm.com>                           *
+ * Version:     $Revision: 300548 $                                           *
+ ***************************************************************************/
+
+#include "jk_pool.h"
+
+#define DEFAULT_DYNAMIC 10
+
+
+static void *jk_pool_dyn_alloc(jk_pool_t *p, size_t size);
+
+
+void jk_open_pool(jk_pool_t *p, jk_pool_atom_t *buf, size_t size)
+{
+    p->pos = 0;
+    p->size = size;
+    p->buf = (char *)buf;
+
+    p->dyn_pos = 0;
+    p->dynamic = NULL;
+    p->dyn_size = 0;
+}
+
+void jk_close_pool(jk_pool_t *p)
+{
+    jk_reset_pool(p);
+    if (p->dynamic) {
+        free(p->dynamic);
+    }
+}
+
+void jk_reset_pool(jk_pool_t *p)
+{
+    if (p->dyn_pos && p->dynamic) {
+        size_t i;
+        for (i = 0; i < p->dyn_pos; i++) {
+            if (p->dynamic[i]) {
+                free(p->dynamic[i]);
+            }
+        }
+    }
+
+    p->dyn_pos = 0;
+    p->pos = 0;
+}
+
+void *jk_pool_alloc(jk_pool_t *p, size_t size)
+{
+    void *rc = NULL;
+
+    size = JK_ALIGN_DEFAULT(size);
+    if ((p->size - p->pos) >= size) {
+        rc = &(p->buf[p->pos]);
+        p->pos += size;
+    }
+    else {
+        rc = jk_pool_dyn_alloc(p, size);
+    }
+
+    return rc;
+}
+
+void *jk_pool_realloc(jk_pool_t *p, size_t sz, const void *old, size_t old_sz)
+{
+    void *rc;
+
+    if (!p || (!old && old_sz)) {
+        return NULL;
+    }
+
+    rc = jk_pool_alloc(p, sz);
+    if (rc) {
+        memcpy(rc, old, old_sz);
+    }
+
+    return rc;
+}
+
+void *jk_pool_strdup(jk_pool_t *p, const char *s)
+{
+    void *rc = NULL;
+    if (s && p) {
+        size_t size = strlen(s);
+
+        if (!size) {
+            return "";
+        }
+
+        size++;
+        rc = jk_pool_alloc(p, size);
+        if (rc) {
+            memcpy(rc, s, size);
+        }
+    }
+
+    return rc;
+}
+
+#if defined (DEBUG) || defined(_DEBUG)
+static void jk_dump_pool(jk_pool_t *p, FILE * f)
+{
+    fprintf(f, "Dumping for pool [%p]\n",  p);
+    fprintf(f, "size             [%ld]\n", p->size);
+    fprintf(f, "pos              [%ld]\n", p->pos);
+    fprintf(f, "buf              [%p]\n",  p->buf);
+    fprintf(f, "dyn_size         [%ld]\n", p->dyn_size);
+    fprintf(f, "dyn_pos          [%ld]\n", p->dyn_pos);
+    fprintf(f, "dynamic          [%p]\n",  p->dynamic);
+
+    fflush(f);
+}
+#endif
+
+static void *jk_pool_dyn_alloc(jk_pool_t *p, size_t size)
+{
+    void *rc;
+
+    if (p->dyn_size == p->dyn_pos) {
+        size_t new_dyn_size = p->dyn_size * 2 + DEFAULT_DYNAMIC;
+        void **new_dynamic = (void **)malloc(new_dyn_size * sizeof(void *));
+        if (new_dynamic) {
+            if (p->dynamic) {
+                /* Copy old dynamic slots */
+                memcpy(new_dynamic, p->dynamic, p->dyn_size * sizeof(void *));
+
+                free(p->dynamic);
+            }
+
+            p->dynamic = new_dynamic;
+            p->dyn_size = new_dyn_size;
+        }
+        else {
+#if defined (DEBUG) || defined(_DEBUG)
+            jk_dump_pool(p, stderr);
+#endif            
+            return NULL;
+        }
+    }
+
+    rc = p->dynamic[p->dyn_pos] = malloc(size);
+    if (p->dynamic[p->dyn_pos]) {
+        p->dyn_pos++;
+    }
+
+    return rc;
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_pool.h
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_pool.h	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_pool.h	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,125 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.
+ */
+
+/***************************************************************************
+ * Description: Memory Pool object header file                             *
+ * Author:      Gal Shachor <shachor at il.ibm.com>                           *
+ * Version:     $Revision: 300079 $                                           *
+ ***************************************************************************/
+#ifndef _JK_POOL_H
+#define _JK_POOL_H
+
+#include "jk_global.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif                          /* __cplusplus */
+
+/**
+ * @file jk_pool.h
+ * @brief Jk memory allocation
+ *
+ * Similar with apr_pools, but completely unsynchronized.
+ * XXX use same names
+ * 
+ */
+
+/*
+ * The pool atom (basic pool alocation unit) is an 8 byte long. 
+ * Each allocation (even for 1 byte) will return a round up to the 
+ * number of atoms. 
+ * 
+ * This is to help in alignment of 32/64 bit machines ...
+ * G.S
+ */
+#ifdef WIN32
+    typedef __int64 jk_pool_atom_t;
+#elif defined(AIX)
+    typedef long long jk_pool_atom_t;
+#elif defined(SOLARIS)
+    typedef long long jk_pool_atom_t;
+#elif defined(LINUX)
+    typedef long long jk_pool_atom_t;
+#elif defined(FREEBSD)
+    typedef long long jk_pool_atom_t;
+#elif defined(OS2)
+    typedef long long jk_pool_atom_t;
+#elif defined(NETWARE)
+    typedef long long jk_pool_atom_t;
+#elif defined(HPUX11)
+    typedef long long jk_pool_atom_t;
+#elif defined(IRIX)
+    typedef long long jk_pool_atom_t;
+#elif defined(AS400)
+    typedef void *jk_pool_atom_t;
+#else
+    typedef long long jk_pool_atom_t;
+#endif
+
+/**
+ * Alignment macros
+ */
+
+/* JK_ALIGN() is only to be used to align on a power of 2 boundary */
+#define JK_ALIGN(size, boundary) \
+    (((size) + ((boundary) - 1)) & ~((boundary) - 1))
+
+/** Default alignment */
+#ifdef AS400
+#define JK_ALIGN_DEFAULT(size) JK_ALIGN(size, 16)
+#else
+#define JK_ALIGN_DEFAULT(size) JK_ALIGN(size, 8)
+#endif
+
+/* 
+ * Pool size in number of pool atoms.
+ */
+#define TINY_POOL_SIZE 256      /* Tiny 1/4K atom pool. */
+#define SMALL_POOL_SIZE 512     /* Small 1/2K atom pool. */
+#define BIG_POOL_SIZE   2*SMALL_POOL_SIZE       /* Bigger 1K atom pool. */
+#define HUGE_POOL_SIZE  2*BIG_POOL_SIZE /* Huge 2K atom pool. */
+
+/** jk pool structure */
+struct jk_pool
+{
+    size_t size;
+    size_t pos;
+    char *buf;
+    size_t dyn_size;
+    size_t dyn_pos;
+    void **dynamic;
+};
+
+typedef struct jk_pool jk_pool_t;
+
+void jk_open_pool(jk_pool_t *p, jk_pool_atom_t *buf, size_t size);
+
+void jk_close_pool(jk_pool_t *p);
+
+void jk_reset_pool(jk_pool_t *p);
+
+void *jk_pool_alloc(jk_pool_t *p, size_t sz);
+
+void *jk_pool_realloc(jk_pool_t *p,
+                      size_t sz, const void *old, size_t old_sz);
+
+void *jk_pool_strdup(jk_pool_t *p, const char *s);
+
+#ifdef __cplusplus
+}
+#endif                          /* __cplusplus */
+#endif                          /* _JK_POOL_H */

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_service.h
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_service.h	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_service.h	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,469 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.
+ */
+
+/***************************************************************************
+ * Description: Definitions of the objects used during the service step.   *
+ *              These are the web server (ws) the worker and the connection*
+ *              JVM connection point                                       *
+ * Author:      Gal Shachor <shachor at il.ibm.com>                           *
+ * Author:      Dan Milstein <danmil at shore.net>                            *
+ * Author:      Henri Gomez <hgomez at apache.org>                            *
+ * Version:     $Revision: 434345 $                                          *
+ ***************************************************************************/
+
+#ifndef JK_SERVICE_H
+#define JK_SERVICE_H
+
+#include "jk_global.h"
+#include "jk_logger.h"
+#include "jk_pool.h"
+#include "jk_map.h"
+#include "jk_uri_worker_map.h"
+#include "jk_msg_buff.h"
+
+#define JK_RETRIES 2
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif                          /* __cplusplus */
+
+/*
+ * Env Information to be provided to worker at init time
+ * With AJP14 support we need to have access to many informations
+ * about web-server, uri to worker map....
+ */
+
+struct jk_worker_env
+{
+
+    /* The URI to WORKER map, will be feeded by AJP14 autoconf feature */
+    jk_uri_worker_map_t *uri_to_worker;
+
+    unsigned int num_of_workers;
+    char **worker_list;
+
+    /* Web-Server we're running on (Apache/IIS/NES) */
+    char *server_name;
+
+    /* Virtual server handled - "*" is all virtual */
+    char *virtual;
+};
+typedef struct jk_worker_env jk_worker_env_t;
+
+struct jk_ws_service;
+struct jk_endpoint;
+struct jk_worker;
+typedef struct jk_ws_service jk_ws_service_t;
+typedef struct jk_endpoint jk_endpoint_t;
+typedef struct jk_worker jk_worker_t;
+
+/*
+ * The web server service 'class'.  An instance of this class is created
+ * for each request which is forwarded from the web server to the servlet
+ * container.  Contains the basic information about the request
+ * (e.g. protocol, req_uri, etc), and also contains a series of methods
+ * which provide access to core web server functionality (start_response,
+ * read, write).  This class might be more accurately called ws_request.
+ *
+ * As with all the core jk classes, this is essentially an abstract base
+ * class which is implemented/extended by classes which are specific to a
+ * particular web server.  By using an abstract base class in this manner,
+ * workers can be written for different protocols (e.g. ajp12, ajp13, ajp14)
+ * without the workers having to worry about which web server they are
+ * talking to.
+ *
+ * This particular OO-in-C system uses a 'ws_private' pointer to point to
+ * the platform-specific data.  So in the subclasses, the methods do most
+ * of their work by getting their hands on the ws_private pointer and then
+ * using that to get at the correctly formatted data and functions for
+ * their platform.
+ *
+ * Try imagining this as a 'public abstract class', and the ws_private
+ * pointer as a sort of extra 'this' reference.  Or imagine that you are
+ * seeing the internal vtables of your favorite OO language.  Whatever
+ * works for you.
+ *
+ * See apache1.3/mod_jk.c and iis/jk_isapi_plugin.c for examples.
+ */
+struct jk_ws_service
+{
+
+    /*
+     * A 'this' pointer which is used by the subclasses of this class to
+     * point to data which is specific to a given web server platform
+     * (e.g. Apache or IIS).
+     */
+    void *ws_private;
+
+    /*
+     * Provides memory management.  All data specific to this request is
+     * allocated within this pool, which can then be reclaimed at the end
+     * of the request handling cycle.
+     *
+     * Alive as long as the request is alive.
+     */
+    jk_pool_t *pool;
+
+    /*
+     * CGI Environment needed by servlets
+     */
+    const char *method;
+    const char *protocol;
+    char *req_uri;
+    const char *remote_addr;
+    const char *remote_host;
+    const char *remote_user;
+    const char *auth_type;
+    const char *query_string;
+    const char *server_name;
+    unsigned server_port;
+    char *server_software;
+    unsigned content_length;        /* integer that represents the content  */
+    /* length should be 0 if unknown.        */
+    unsigned is_chunked;    /* 1 if content length is unknown (chunked rq) */
+    unsigned no_more_chunks;        /* 1 if last chunk has been read */
+    unsigned content_read;  /* number of bytes read */
+
+    /*
+     * SSL information
+     *
+     * is_ssl       - True if request is in ssl connection
+     * ssl_cert     - If available, base64 ASN.1 encoded client certificates.
+     * ssl_cert_len - Length of ssl_cert, 0 if certificates are not available.
+     * ssl_cipher   - The ssl cipher suite in use.
+     * ssl_session  - The ssl session string
+     *
+     * In some servers it is impossible to extract all this information, in this
+     * case, we are passing NULL.
+     */
+    int is_ssl;
+    char *ssl_cert;
+    unsigned ssl_cert_len;
+    char *ssl_cipher;
+    char *ssl_session;
+
+    /*
+     * SSL extra information for Servlet 2.3 API
+     *
+     * ssl_key_size - ssl key size in use
+     */
+    int ssl_key_size;
+
+    /*
+     * Headers, names and values.
+     */
+    char **headers_names;   /* Names of the request headers  */
+    char **headers_values;  /* Values of the request headers */
+    unsigned num_headers;   /* Number of request headers     */
+
+
+    /*
+     * Request attributes.
+     *
+     * These attributes that were extracted from the web server and are
+     * sent to Tomcat.
+     *
+     * The developer should be able to read them from the ServletRequest
+     * attributes. Tomcat is required to append org.apache.tomcat. to
+     * these attrinbute names.
+     */
+    char **attributes_names;        /* Names of the request attributes  */
+    char **attributes_values;       /* Values of the request attributes */
+    unsigned num_attributes;        /* Number of request attributes     */
+
+    /*
+     * The jvm route is in use when the adapter load balance among
+     * several JVMs. It is the ID of a specific JVM in the load balance
+     * group. We are using this variable to implement JVM session
+     * affinity
+     */
+    const char *jvm_route;
+
+    /* Temp solution for auth. For native1 it'll be sent on each request,
+       if an option is present. For native2 it'll be sent with the first
+       request. On java side, both cases will work. For tomcat3.2 or
+       a version that doesn't support secret - don't set the secret,
+       and it'll work.
+     */
+    const char *secret;
+
+    /*
+     * Area to get POST data for fail-over recovery in POST
+     */
+    jk_msg_buf_t *reco_buf;
+    int reco_status;
+
+    /* Number of retries. Defaults to JK_RETRIES
+     */
+    int retries;
+
+    /*
+     * If set call flush after each write
+     */
+    int flush_packets;
+
+    /* Uri worker map. Added for virtual host support
+     */
+    jk_uri_worker_map_t *uw_map;
+
+    /*
+     * Callbacks into the web server.  For each, the first argument is
+     * essentially a 'this' pointer.  All return JK_TRUE on success
+     * and JK_FALSE on failure.
+     */
+    /*
+     * Send the response headers to the browser.
+     */
+    int (JK_METHOD * start_response) (jk_ws_service_t *s,
+                                      int status,
+                                      const char *reason,
+                                      const char *const *header_names,
+                                      const char *const *header_values,
+                                      unsigned num_of_headers);
+
+    /*
+     * Read a chunk of the request body into a buffer.  Attempt to read len
+     * bytes into the buffer.  Write the number of bytes actually read into
+     * actually_read.
+     */
+    int (JK_METHOD * read) (jk_ws_service_t *s,
+                            void *buffer,
+                            unsigned len, unsigned *actually_read);
+
+    /*
+     * Write a chunk of response data back to the browser.
+     */
+    int (JK_METHOD * write) (jk_ws_service_t *s,
+                             const void *buffer, unsigned len);
+
+    /*
+     * Flush a chunk of response data back to the browser.
+     */
+    void (JK_METHOD * flush) (jk_ws_service_t *s);
+
+    /*
+     * If set do not reuse socket after each full response
+     */
+    int disable_reuse;
+
+    /*
+     * Add more data to log facilities.
+     */
+    void (JK_METHOD * add_log_items) (jk_ws_service_t *s,
+                                      const char *const *log_names,
+                                      const char *const *log_values,
+                                      unsigned num_of_items);
+};
+
+/*
+ * The endpoint 'class', which represents one end of a connection to the
+ * servlet engine.  Basically, supports nothing other than forwarding the
+ * request to the servlet engine.  Endpoints can be persistent (as with
+ * ajp13/ajp14, where a single connection is reused many times), or can last for a
+ * single request (as with ajp12, where a new connection is created for
+ * every request).
+ *
+ * An endpoint for a given protocol is obtained by the web server plugin
+ * from a worker object for that protocol.  See below for details.
+ *
+ * As with all the core jk classes, this is essentially an abstract base
+ * class which is implemented/extended by classes which are specific to a
+ * particular protocol.  By using an abstract base class in this manner,
+ * plugins can be written for different servers (e.g. IIS, Apache) without
+ * the plugins having to worry about which protocol they are talking.
+ *
+ * This particular OO-in-C system uses a 'endpoint_private' pointer to
+ * point to the protocol-specific data/functions.  So in the subclasses, the
+ * methods do most of their work by getting their hands on the
+ * endpoint_private pointer and then using that to get at the functions for
+ * their protocol.
+ *
+ * Try imagining this as a 'public abstract class', and the
+ * endpoint_private pointer as a sort of extra 'this' reference.  Or
+ * imagine that you are seeing the internal vtables of your favorite OO
+ * language.  Whatever works for you.
+ *
+ * See jk_ajp13_worker.c/jk_ajp14_worker.c and jk_ajp12_worker.c for examples.
+ */
+struct jk_endpoint
+{
+    size_t rd;
+    size_t wr;
+
+    /*
+     * A 'this' pointer which is used by the subclasses of this class to
+     * point to data/functions which are specific to a given protocol
+     * (e.g. ajp12 or ajp13 or ajp14).
+     */
+    void *endpoint_private;
+
+    /*
+     * Forward a request to the servlet engine.  The request is described
+     * by the jk_ws_service_t object.
+     * is_error is either 0 meaning recoverable or set to
+     * the HTTP error code.
+     */
+    int (JK_METHOD * service) (jk_endpoint_t *e,
+                               jk_ws_service_t *s,
+                               jk_logger_t *l, int *is_error);
+
+    /*
+     * Called when this particular endpoint has finished processing a
+     * request.  For some protocols (e.g. ajp12), this frees the memory
+     * associated with the endpoint.  For others (e.g. ajp13/ajp14), this can
+     * return the endpoint to a cache of already opened endpoints.
+     *
+     * Note that the first argument is *not* a 'this' pointer, but is
+     * rather a pointer to a 'this' pointer.  This is necessary, because
+     * we may need to free this object.
+     */
+    int (JK_METHOD * done) (jk_endpoint_t **p, jk_logger_t *l);
+};
+
+/*
+ * The worker 'class', which represents something to which the web server
+ * can delegate requests.
+ *
+ * This can mean communicating with a particular servlet engine instance,
+ * using a particular protocol.  A single web server instance may have
+ * multiple workers communicating with a single servlet engine (it could be
+ * using ajp12 for some requests and ajp13/ajp14 for others).  Or, a single web
+ * server instance could have multiple workers communicating with different
+ * servlet engines using the same protocol (it could be load balancing
+ * among many engines, using ajp13/ajp14 for all communication).
+ *
+ * There is also a load balancing worker (jk_lb_worker.c), which itself
+ * manages a group of workers.
+ *
+ * Web servers are configured to forward requests to a given worker.  To
+ * handle those requests, the worker's get_endpoint method is called, and
+ * then the service() method of that endpoint is called.
+ *
+ * As with all the core jk classes, this is essentially an abstract base
+ * class which is implemented/extended by classes which are specific to a
+ * particular protocol (or request-handling system).  By using an abstract
+ * base class in this manner, plugins can be written for different servers
+ * (e.g. IIS, Apache) without the plugins having to worry about which
+ * protocol they are talking.
+ *
+ * This particular OO-in-C system uses a 'worker_private' pointer to
+ * point to the protocol-specific data/functions.  So in the subclasses, the
+ * methods do most of their work by getting their hands on the
+ * worker_private pointer and then using that to get at the functions for
+ * their protocol.
+ *
+ * Try imagining this as a 'public abstract class', and the
+ * worker_private pointer as a sort of extra 'this' reference.  Or
+ * imagine that you are seeing the internal vtables of your favorite OO
+ * language.  Whatever works for you.
+ *
+ * See jk_ajp14_worker.c, jk_ajp13_worker.c and jk_ajp12_worker.c for examples.
+ */
+struct jk_worker
+{
+
+    /*
+     * Public property to enable the number of retry attempts
+     * on this worker.
+     */
+    int retries;
+    /*
+     * A 'this' pointer which is used by the subclasses of this class to
+     * point to data/functions which are specific to a given protocol
+     * (e.g. ajp12 or ajp13 or ajp14).
+     */
+    void *worker_private;
+
+    int   type;
+    /*
+     * For all of the below (except destroy), the first argument is
+     * essentially a 'this' pointer.
+     */
+
+    /*
+     * Given a worker which is in the process of being created, and a list
+     * of configuration options (or 'properties'), check to see if it the
+     * options are.  This will always be called before the init() method.
+     * The init/validate distinction is a bit hazy to me.
+     * See jk_ajp13_worker.c/jk_ajp14_worker.c and jk_worker.c->wc_create_worker()
+     */
+    int (JK_METHOD * validate) (jk_worker_t *w,
+                                jk_map_t *props,
+                                jk_worker_env_t *we, jk_logger_t *l);
+
+    /*
+     * Update worker either from jk_status or reloading from workers.properties
+     */
+    int (JK_METHOD * update) (jk_worker_t *w,
+                              jk_map_t *props,
+                              jk_worker_env_t *we, jk_logger_t *l);
+
+    /*
+     * Do whatever initialization needs to be done to start this worker up.
+     * Configuration options are passed in via the props parameter.
+     */
+    int (JK_METHOD * init) (jk_worker_t *w,
+                            jk_map_t *props,
+                            jk_worker_env_t *we, jk_logger_t *l);
+
+
+    /*
+     * Obtain an endpoint to service a particular request.  A pointer to
+     * the endpoint is stored in pend.
+     */
+    int (JK_METHOD * get_endpoint) (jk_worker_t *w,
+                                    jk_endpoint_t **pend, jk_logger_t *l);
+
+    /*
+     * Shutdown this worker.  The first argument is not a 'this' pointer,
+     * but rather a pointer to 'this', so that the object can be free'd (I
+     * think -- though that doesn't seem to be happening.  Hmmm).
+     */
+    int (JK_METHOD * destroy) (jk_worker_t **w, jk_logger_t *l);
+
+    /*
+     * Maintain this worker.
+     */
+    int (JK_METHOD * maintain) (jk_worker_t *w, time_t now, jk_logger_t *l);
+
+};
+
+/*
+ * Essentially, an abstract base class (or factory class) with a single
+ * method -- think of it as createWorker() or the Factory Method Design
+ * Pattern.  There is a different worker_factory function for each of the
+ * different types of workers.  The set of all these functions is created
+ * at startup from the list in jk_worker_list.h, and then the correct one
+ * is chosen in jk_worker.c->wc_create_worker().  See jk_worker.c and
+ * jk_ajp13_worker.c/jk_ajp14_worker.c for examples.
+ *
+ * This allows new workers to be written without modifing the plugin code
+ * for the various web servers (since the only link is through
+ * jk_worker_list.h).
+ */
+typedef int (JK_METHOD * worker_factory) (jk_worker_t **w,
+                                          const char *name,
+                                          jk_logger_t *l);
+
+void jk_init_ws_service(jk_ws_service_t *s);
+
+
+#ifdef __cplusplus
+}
+#endif                          /* __cplusplus */
+
+#endif                          /* JK_SERVICE_H */

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_shm.c
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_shm.c	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_shm.c	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,485 @@
+/*
+ *  Copyright 1999-2005 The Apache Software Foundation
+ *
+ *  Licensed 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.
+ */
+
+/***************************************************************************
+ * Description: Shared Memory support                                      *
+ * Author:      Mladen Turk <mturk at jboss.com>                              *
+ * Author:      Rainer Jung <rjung at apache.org>                             *
+ * Version:     $Revision: 424266 $                                          *
+ ***************************************************************************/
+
+#include "jk_global.h"
+#include "jk_pool.h"
+#include "jk_util.h"
+#include "jk_mt.h"
+#include "jk_shm.h"
+
+/** jk shm header core data structure */
+struct jk_shm_header_data
+{
+    /* Shared memory magic JK_SHM_MAGIC */
+    char   magic[JK_SHM_MAGIC_SIZ];
+    size_t size;
+    size_t pos;
+    unsigned int childs;
+    unsigned int workers;
+    time_t modified;
+};
+
+typedef struct jk_shm_header_data jk_shm_header_data_t;
+
+/** jk shm header record structure */
+struct jk_shm_header
+{
+    union {
+        jk_shm_header_data_t data;
+        char alignbuf[JK_SHM_ALIGN(sizeof(jk_shm_header_data_t))];
+    } h;
+    char   buf[1];
+};
+
+typedef struct jk_shm_header jk_shm_header_t;
+
+/** jk shm structure */
+struct jk_shm
+{
+    size_t     size;
+    const char *filename;
+    int        fd;
+    int        fd_lock;
+    int        attached;
+    jk_shm_header_t  *hdr;
+    JK_CRIT_SEC       cs;
+};
+
+typedef struct jk_shm jk_shm_t;
+
+static const char shm_signature[] = { JK_SHM_MAGIC };
+static jk_shm_t jk_shmem = { 0, NULL, -1, -1, 0, NULL};
+static time_t jk_workers_modified_time = 0;
+static time_t jk_workers_access_time = 0;
+#if defined (WIN32)
+static HANDLE jk_shm_map = NULL;
+#endif
+
+#if defined (WIN32) || defined(NETWARE)
+
+/* Use plain memory */
+int jk_shm_open(const char *fname, size_t sz, jk_logger_t *l)
+{
+    int rc;
+    JK_TRACE_ENTER(l);
+    if (jk_shmem.hdr) {
+        if (JK_IS_DEBUG_LEVEL(l))
+            jk_log(l, JK_LOG_DEBUG, "Shared memory is already opened");
+        JK_TRACE_EXIT(l);
+        return 0;
+    }
+
+    jk_shmem.size =  JK_SHM_ALIGN(sizeof(jk_shm_header_t) + sz);
+
+#if defined (WIN32)
+    if (fname) {
+        jk_shm_map = CreateFileMapping(INVALID_HANDLE_VALUE,
+                                       NULL,
+                                       PAGE_READWRITE,
+                                       0,
+                                       (DWORD)(sizeof(jk_shm_header_t) + sz),
+                                       fname);
+        if (jk_shm_map == NULL || jk_shm_map == INVALID_HANDLE_VALUE &&
+            GetLastError() == ERROR_ALREADY_EXISTS)
+            jk_shm_map = OpenFileMapping(PAGE_READWRITE, FALSE, fname);
+        if (jk_shm_map == NULL || jk_shm_map == INVALID_HANDLE_VALUE) {
+            JK_TRACE_EXIT(l);
+            return -1;
+        }
+        jk_shmem.hdr = (jk_shm_header_t *)MapViewOfFile(jk_shm_map,
+                                                        FILE_MAP_ALL_ACCESS,
+                                                        0,
+                                                        0,
+                                                        0);
+    }
+    else
+#endif
+    jk_shmem.hdr = (jk_shm_header_t *)calloc(1, jk_shmem.size);
+    if (!jk_shmem.hdr) {
+#if defined (WIN32)
+        if (jk_shm_map) {
+            CloseHandle(jk_shm_map);
+            jk_shm_map = NULL;
+        }
+#endif
+        JK_TRACE_EXIT(l);
+        return -1;
+    }
+    jk_shmem.filename = "memory";
+    jk_shmem.fd       = 0;
+    jk_shmem.attached = 0;
+    memcpy(jk_shmem.hdr->h.data.magic, shm_signature, JK_SHM_MAGIC_SIZ);
+    jk_shmem.hdr->h.data.size = sz;
+    JK_INIT_CS(&(jk_shmem.cs), rc);
+    if (JK_IS_DEBUG_LEVEL(l))
+        jk_log(l, JK_LOG_DEBUG,
+               "Initialized shared memory size=%u free=%u addr=%#lx",
+               jk_shmem.size, jk_shmem.hdr->h.data.size, jk_shmem.hdr);
+    JK_TRACE_EXIT(l);
+    return 0;
+}
+
+int jk_shm_attach(const char *fname, size_t sz, jk_logger_t *l)
+{
+    JK_TRACE_ENTER(l);
+    if (!jk_shm_open(fname, sz, l)) {
+        jk_shmem.attached = 1;
+        jk_shmem.hdr->h.data.childs++;
+        if (JK_IS_DEBUG_LEVEL(l))
+            jk_log(l, JK_LOG_DEBUG,
+                   "Attached shared memory [%d] size=%u free=%u addr=%#lx",
+                   jk_shmem.hdr->h.data.childs, jk_shmem.hdr->h.data.size,
+                   jk_shmem.hdr->h.data.size - jk_shmem.hdr->h.data.pos,
+                   jk_shmem.hdr);
+        JK_TRACE_EXIT(l);
+        return 0;
+    }
+    else {
+        JK_TRACE_EXIT(l);
+        return -1;
+    }
+}
+
+void jk_shm_close()
+{
+    if (jk_shmem.hdr) {
+        int rc;
+#if defined (WIN32)
+        if (jk_shm_map) {
+            UnmapViewOfFile(jk_shmem.hdr);
+            CloseHandle(jk_shm_map);
+            jk_shm_map = NULL;
+        }
+        else
+#endif
+        free(jk_shmem.hdr);
+        JK_DELETE_CS(&(jk_shmem.cs), rc);
+    }
+    jk_shmem.hdr = NULL;
+}
+
+#else
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <sys/uio.h>
+
+#ifndef MAP_FAILED
+#define MAP_FAILED  (-1)
+#endif
+
+#ifndef MAP_FILE
+#define MAP_FILE    (0)
+#endif
+
+static int do_shm_open_lock(const char *fname, int attached, jk_logger_t *l)
+{
+    int rc;
+    int fd;
+    int flags = O_RDWR;
+    char flkname[256];
+    JK_TRACE_ENTER(l);
+
+    jk_shmem.fd_lock = -1;
+    strcpy(flkname, fname);
+    strcat(flkname, ".lock");
+    if (!attached)
+        flags |= (O_CREAT|O_TRUNC);
+    fd = open(flkname, flags, 0666);
+    if (fd == -1) {
+        JK_TRACE_EXIT(l);
+        return errno;
+    }
+
+    if (!attached) {
+        if (ftruncate(fd, 1)) {
+            rc = errno;
+            close(fd);
+            JK_TRACE_EXIT(l);
+            return rc;
+         }
+    }
+    if (lseek(fd, 0, SEEK_SET) != 0) {
+        rc = errno;
+        close(fd);
+        JK_TRACE_EXIT(l);
+        return rc;
+    }
+    jk_shmem.fd_lock = fd;
+
+    if (JK_IS_DEBUG_LEVEL(l))
+        jk_log(l, JK_LOG_DEBUG,
+               "Opened shared memory lock %s", flkname);
+    JK_TRACE_EXIT(l);
+    return 0;
+}
+
+static int do_shm_open(const char *fname, int attached,
+                       size_t sz, jk_logger_t *l)
+{
+    int rc;
+    int fd;
+    int flags = O_RDWR;
+    void *base;
+
+    JK_TRACE_ENTER(l);
+    if (jk_shmem.hdr) {
+        /* Probably a call from vhost */
+        if (JK_IS_DEBUG_LEVEL(l))
+            jk_log(l, JK_LOG_DEBUG,
+                    "Shared memory is already open");
+        return 0;
+    }
+    jk_shmem.filename = fname;
+    if (attached)
+        jk_shmem.attached = (int)getpid();
+    else
+        jk_shmem.attached = 0;
+
+    jk_shmem.size = JK_SHM_ALIGN(sizeof(jk_shm_header_t) + sz);
+
+    /* Use plain memory in case there is no file name */
+    if (!fname) {
+        jk_shmem.filename  = "memory";
+        if (JK_IS_DEBUG_LEVEL(l))
+            jk_log(l, JK_LOG_DEBUG,
+                   "Using process memory as shared memory");
+        JK_TRACE_EXIT(l);
+        return 0;
+    }
+
+    if (!attached)
+        flags |= (O_CREAT|O_TRUNC);
+    fd = open(fname, flags, 0666);
+    if (fd == -1) {
+        jk_shmem.size = 0;
+        JK_TRACE_EXIT(l);
+        return errno;
+    }
+
+    if (!attached) {
+        size_t size = lseek(fd, 0, SEEK_END);
+        if (size < jk_shmem.size) {
+            size = jk_shmem.size;
+            if (ftruncate(fd, jk_shmem.size)) {
+                rc = errno;
+                close(fd);
+                jk_shmem.size = 0;
+                JK_TRACE_EXIT(l);
+                return rc;
+            }
+            if (JK_IS_DEBUG_LEVEL(l))
+                jk_log(l, JK_LOG_DEBUG,
+                       "Truncated shared memory to %u", size);
+        }
+    }
+    if (lseek(fd, 0, SEEK_SET) != 0) {
+        rc = errno;
+        close(fd);
+        jk_shmem.size = 0;
+        JK_TRACE_EXIT(l);
+        return rc;
+    }
+
+    base = mmap((caddr_t)0, jk_shmem.size,
+                PROT_READ | PROT_WRITE,
+                MAP_FILE | MAP_SHARED,
+                fd, 0);
+    if (base == (caddr_t)MAP_FAILED || base == (caddr_t)0) {
+        rc = errno;
+        close(fd);
+        jk_shmem.size = 0;
+        JK_TRACE_EXIT(l);
+        return rc;
+    }
+    jk_shmem.hdr = base;
+    jk_shmem.fd  = fd;
+
+    /* Clear shared memory */
+    if (!attached) {
+        memset(jk_shmem.hdr, 0, jk_shmem.size);
+        memcpy(jk_shmem.hdr->h.data.magic, shm_signature, JK_SHM_MAGIC_SIZ);
+        jk_shmem.hdr->h.data.size = sz;
+        if (JK_IS_DEBUG_LEVEL(l))
+            jk_log(l, JK_LOG_DEBUG,
+                   "Initialized shared memory size=%u free=%u addr=%#lx",
+                   jk_shmem.size, jk_shmem.hdr->h.data.size, jk_shmem.hdr);
+    }
+    else {
+        jk_shmem.hdr->h.data.childs++;
+        if (JK_IS_DEBUG_LEVEL(l))
+            jk_log(l, JK_LOG_INFO,
+                   "Attached shared memory [%d] size=%u free=%u addr=%#lx",
+                   jk_shmem.hdr->h.data.childs, jk_shmem.hdr->h.data.size,
+                   jk_shmem.hdr->h.data.size - jk_shmem.hdr->h.data.pos,
+                   jk_shmem.hdr);
+        /* TODO: check header magic */
+    }
+    JK_INIT_CS(&(jk_shmem.cs), rc);
+    if ((rc = do_shm_open_lock(fname, attached, l))) {
+        munmap((void *)jk_shmem.hdr, jk_shmem.size);
+        close(jk_shmem.fd);
+        jk_shmem.hdr = NULL;
+        jk_shmem.fd  = -1;
+        JK_TRACE_EXIT(l);
+        return rc;
+    }
+    JK_TRACE_EXIT(l);
+    return 0;
+}
+
+int jk_shm_open(const char *fname, size_t sz, jk_logger_t *l)
+{
+    return do_shm_open(fname, 0, sz, l);
+}
+
+int jk_shm_attach(const char *fname, size_t sz, jk_logger_t *l)
+{
+    return do_shm_open(fname, 1, sz, l);
+}
+
+void jk_shm_close()
+{
+    int rc;
+    if (jk_shmem.hdr) {
+        if (jk_shmem.attached) {
+            int p = (int)getpid();
+            if (p != jk_shmem.attached) {
+                /* In case this is a forked child
+                 * do not close the shared memory.
+                 * It will be closed by the parent.
+                 */
+                 return;
+            }
+        }
+        if (jk_shmem.fd_lock >= 0) {
+            close(jk_shmem.fd_lock);
+        }
+        if (jk_shmem.fd >= 0) {
+            munmap((void *)jk_shmem.hdr, jk_shmem.size);
+            close(jk_shmem.fd);
+        }
+        jk_shmem.fd_lock = -1;
+    }
+    if (jk_shmem.size) {
+        JK_DELETE_CS(&(jk_shmem.cs), rc);
+    }
+    jk_shmem.size = 0;
+    jk_shmem.hdr  = NULL;
+    jk_shmem.fd   = -1;
+}
+
+
+#endif
+
+void *jk_shm_alloc(jk_pool_t *p, size_t size)
+{
+    void *rc = NULL;
+
+    if (jk_shmem.hdr) {
+        size = JK_ALIGN_DEFAULT(size);
+        if ((jk_shmem.hdr->h.data.size - jk_shmem.hdr->h.data.pos) >= size) {
+            rc = &(jk_shmem.hdr->buf[jk_shmem.hdr->h.data.pos]);
+            jk_shmem.hdr->h.data.pos += size;
+        }
+    }
+    else if (p)
+        rc = jk_pool_alloc(p, size);
+
+    return rc;
+}
+
+const char *jk_shm_name()
+{
+    return jk_shmem.filename;
+}
+
+
+time_t jk_shm_get_workers_time()
+{
+    if (jk_shmem.hdr)
+        return jk_shmem.hdr->h.data.modified;
+    else
+        return jk_workers_modified_time;
+}
+
+void jk_shm_set_workers_time(time_t t)
+{
+    if (jk_shmem.hdr)
+        jk_shmem.hdr->h.data.modified = t;
+    else
+        jk_workers_modified_time = t;
+    jk_workers_access_time = t;
+}
+
+int jk_shm_is_modified()
+{
+    time_t m = jk_shm_get_workers_time();
+    if (m != jk_workers_access_time)
+        return 1;
+    else
+        return 0;
+}
+
+void jk_shm_sync_access_time()
+{
+    jk_workers_access_time = jk_shm_get_workers_time();
+}
+
+int jk_shm_lock()
+{
+    int rc;
+    JK_ENTER_CS(&(jk_shmem.cs), rc);
+    if (rc == JK_TRUE && jk_shmem.fd_lock != -1) {
+        JK_ENTER_LOCK(jk_shmem.fd_lock, rc);
+    }
+    return rc;
+}
+
+int jk_shm_unlock()
+{
+    int rc;
+    JK_LEAVE_CS(&(jk_shmem.cs), rc);
+    if (rc == JK_TRUE && jk_shmem.fd_lock != -1) {
+        JK_LEAVE_LOCK(jk_shmem.fd_lock, rc);
+    }
+    return rc;
+}
+
+jk_shm_worker_t *jk_shm_alloc_worker(jk_pool_t *p)
+{
+    jk_shm_worker_t *w = (jk_shm_worker_t *)jk_shm_alloc(p, sizeof(jk_shm_worker_t));
+    if (w) {
+        memset(w, 0, sizeof(jk_shm_worker_t));
+        if (jk_shmem.hdr) {
+            jk_shmem.hdr->h.data.workers++;
+            w->id = jk_shmem.hdr->h.data.workers;
+        }
+        else
+            w->id = -1;
+    }
+    return w;
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_shm.h
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_shm.h	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_shm.h	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,170 @@
+/*
+ *  Copyright 1999-2005 The Apache Software Foundation
+ *
+ *  Licensed 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.
+ */
+
+/***************************************************************************
+ * Description: Shared Memory object header file                           *
+ * Author:      Mladen Turk <mturk at jboss.com>                              *
+ * Author:      Rainer Jung <rjung at apache.org>                             *
+ * Version:     $Revision: 441427 $                                           *
+ ***************************************************************************/
+#ifndef _JK_SHM_H
+#define _JK_SHM_H
+
+#include "jk_global.h"
+#include "jk_pool.h"
+#include "jk_util.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif                          /* __cplusplus */
+
+/**
+ * @file jk_shm.h
+ * @brief Jk shared memory management
+ *
+ *
+ */
+
+#define JK_SHM_MAJOR    '1'
+#define JK_SHM_MINOR    '2'
+#define JK_SHM_STR_SIZ  63
+#define JK_SHM_URI_SIZ  127
+#define JK_SHM_DYNAMIC  16
+#define JK_SHM_MAGIC    '!', 'J', 'K', 'S', 'H', 'M', JK_SHM_MAJOR, JK_SHM_MINOR
+#define JK_SHM_MAGIC_SIZ  8
+
+/* Really huge numbers, but 64 workers should be enough */
+#define JK_SHM_MAX_WORKERS  64
+#define JK_SHM_WORKER_SIZE  JK_SHM_ALIGN(sizeof(jk_shm_worker_t))
+#define JK_SHM_DEF_SIZE     (JK_SHM_MAX_WORKERS * JK_SHM_WORKER_SIZE)
+#define JK_SHM_ALIGNMENT    64
+#define JK_SHM_ALIGN(x)     JK_ALIGN(x, JK_SHM_ALIGNMENT)
+
+/** jk shm worker record structure */
+struct jk_shm_worker
+{
+    int     id;
+    /* Number of currently busy channels */
+    volatile int busy;
+    /* Maximum number of busy channels */
+    volatile int max_busy;
+    /* Number of currently connected channels */
+    volatile int connected;
+    /* worker name */
+    char    name[JK_SHM_STR_SIZ+1];
+    /* jvm route */
+    char    jvm_route[JK_SHM_STR_SIZ+1];
+    /* worker domain */
+    char    domain[JK_SHM_STR_SIZ+1];
+    /* worker redirect route */
+    char    redirect[JK_SHM_STR_SIZ+1];
+    /* worker distance */
+    volatile int distance;
+    /* current activation state (config) of the worker */
+    volatile int activation;
+    /* current error state (runtime) of the worker */
+    volatile int state;
+    /* Current lb factor */
+    volatile int lb_factor;
+    /* Current lb reciprocal factor */
+    volatile jk_uint64_t lb_mult;
+    /* Current lb value  */
+    volatile jk_uint64_t lb_value;
+    int     sticky_session;
+    int     sticky_session_force;
+    int     recover_wait_time;
+    int     retries;
+    /* Statistical data */
+    volatile time_t  error_time;
+    /* Service transfer rate time */
+    volatile time_t  last_maintain_time;
+    /* Number of bytes read from remote */
+    volatile jk_uint64_t readed;
+    /* Number of bytes transferred to remote */
+    volatile jk_uint64_t transferred;
+    /* Number of times the worker was elected */
+    volatile jk_uint64_t  elected;
+    /* Number of times the worker was elected - snapshot during maintenance */
+    volatile jk_uint64_t  elected_snapshot;
+    /* Number of non 200 responses */
+    volatile jk_uint32_t  errors;
+    /* Number of recovery attempts */
+    volatile jk_uint32_t  recoveries;
+    /* Number of recovery failures */
+    volatile jk_uint32_t  recovery_errors;
+    /* Number of client errors */
+    volatile jk_uint32_t  client_errors;
+};
+typedef struct jk_shm_worker jk_shm_worker_t;
+
+const char *jk_shm_name(void);
+
+/* Open the shared memory creating file if needed
+ */
+int jk_shm_open(const char *fname, size_t sz, jk_logger_t *l);
+
+/* Close the shared memory
+ */
+void jk_shm_close(void);
+
+/* Attach the shared memory in child process.
+ * File has to be opened in parent.
+ */
+int jk_shm_attach(const char *fname, size_t sz, jk_logger_t *l);
+
+/* allocate shm memory
+ * If there is no shm present the pool will be used instead
+ */
+void *jk_shm_alloc(jk_pool_t *p, size_t size);
+
+/* allocate shm worker record
+ * If there is no shm present the pool will be used instead
+ */
+jk_shm_worker_t *jk_shm_alloc_worker(jk_pool_t *p);
+
+/* Return workers.properties last modified time
+ */
+time_t jk_shm_get_workers_time(void);
+
+/* Set workers.properties last modified time
+ */
+void jk_shm_set_workers_time(time_t t);
+
+/* Check if the shared memory has been modified
+ * by some other process.
+ */
+int jk_shm_is_modified(void);
+
+/* Synchronize access and modification time.
+ * This function should be called when the shared memory
+ * is modified and after we update the config acording
+ * to the current shared memory data.
+ */
+void jk_shm_sync_access_time(void);
+
+
+/* Lock shared memory for thread safe access */
+int jk_shm_lock(void);
+
+/* Unlock shared memory for thread safe access */
+int jk_shm_unlock(void);
+
+
+#ifdef __cplusplus
+}
+#endif  /* __cplusplus */
+#endif  /* _JK_SHM_H */

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_sockbuf.c
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_sockbuf.c	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_sockbuf.c	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,194 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.
+ */
+
+/***************************************************************************
+ * Description: Simple buffer object to handle buffered socket IO          *
+ * Author:      Gal Shachor <shachor at il.ibm.com>                           *
+ * Version:     $Revision: 424266 $                                           *
+ ***************************************************************************/
+
+#include "jk_global.h"
+#include "jk_sockbuf.h"
+
+static int fill_buffer(jk_sockbuf_t *sb);
+
+int jk_sb_open(jk_sockbuf_t *sb, jk_sock_t sd)
+{
+    if (sb && sd >= 0) {
+        sb->end = 0;
+        sb->start = 0;
+        sb->sd = sd;
+        return JK_TRUE;
+    }
+
+    return JK_FALSE;
+}
+
+int jk_sb_write(jk_sockbuf_t *sb, const void *buf, unsigned sz)
+{
+    if (sb && buf && sz) {
+        if ((SOCKBUF_SIZE - sb->end) >= sz) {
+            memcpy(sb->buf + sb->end, buf, sz);
+            sb->end += sz;
+        }
+        else {
+            if (!jk_sb_flush(sb)) {
+                return JK_FALSE;
+            }
+            if (sz > SOCKBUF_SIZE) {
+                return (send(sb->sd, (char *)buf, sz, 0) == (int)sz);
+            }
+
+            memcpy(sb->buf + sb->end, buf, sz);
+            sb->end += sz;
+        }
+
+        return JK_TRUE;
+    }
+
+    return JK_FALSE;
+}
+
+int jk_sb_flush(jk_sockbuf_t *sb)
+{
+    if (sb) {
+        int save_out = sb->end;
+        sb->end = sb->start = 0;
+        if (save_out) {
+            return send(sb->sd, sb->buf, save_out, 0) == save_out;
+        }
+        return JK_TRUE;
+    }
+
+    return JK_FALSE;
+}
+
+
+int jk_sb_read(jk_sockbuf_t *sb, char **buf, unsigned sz, unsigned *ac)
+{
+    if (sb && buf && ac) {
+        unsigned avail;
+
+        *ac = 0;
+        *buf = NULL;
+
+        if (sb->end == sb->start) {
+            sb->end = sb->start = 0;
+            if (fill_buffer(sb) < 0) {
+                return JK_FALSE;
+            }
+        }
+
+        *buf = sb->buf + sb->start;
+        avail = sb->end - sb->start;
+        if (avail > sz) {
+            *ac = sz;
+        }
+        else {
+            *ac = avail;
+        }
+        sb->start += *ac;
+
+        return JK_TRUE;
+    }
+
+    return JK_FALSE;
+}
+
+int jk_sb_gets(jk_sockbuf_t *sb, char **ps)
+{
+    int ret;
+    if (sb) {
+        while (1) {
+            unsigned i;
+            for (i = sb->start; i < sb->end; i++) {
+                if (JK_LF == sb->buf[i]) {
+                    if (i > sb->start && JK_CR == sb->buf[i - 1]) {
+                        sb->buf[i - 1] = '\0';
+                    }
+                    else {
+                        sb->buf[i] = '\0';
+                    }
+                    *ps = sb->buf + sb->start;
+                    sb->start = (i + 1);
+                    return JK_TRUE;
+                }
+            }
+            if ((ret = fill_buffer(sb)) < 0) {
+                return JK_FALSE;
+            }
+            else if (ret == 0) {
+                *ps = sb->buf + sb->start;
+                if ((SOCKBUF_SIZE - sb->end) > 0) {
+                    sb->buf[sb->end] = '\0';
+                }
+                else {
+                    sb->buf[sb->end - 1] = '\0';
+                }
+                return JK_TRUE;
+            }
+        }
+    }
+
+    return JK_FALSE;
+}
+
+/*
+ * Read data from the socket into the associated buffer, and update the
+ * start and end indices.  May move the data currently in the buffer.  If
+ * new data is read into the buffer (or if it is already full), returns 1.
+ * If EOF is received on the socket, returns 0.  In case of error returns
+ * -1.  
+ */
+static int fill_buffer(jk_sockbuf_t *sb)
+{
+    int ret;
+
+    /*
+     * First move the current data to the beginning of the buffer
+     */
+    if (sb->start < sb->end) {
+        if (sb->start > 0) {
+            unsigned to_copy = sb->end - sb->start;
+            memmove(sb->buf, sb->buf + sb->start, to_copy);
+            sb->start = 0;
+            sb->end = to_copy;
+        }
+    }
+    else {
+        sb->start = sb->end = 0;
+    }
+
+    /*
+     * In the unlikely case where the buffer is already full, we won't be
+     * reading anything and we'd be calling recv with a 0 count.  
+     */
+    if ((SOCKBUF_SIZE - sb->end) > 0) {
+        /*
+         * Now, read more data
+         */
+        ret = recv(sb->sd, sb->buf + sb->end, SOCKBUF_SIZE - sb->end, 0);
+
+        /* 0 is EOF/SHUTDOWN, -1 is SOCK_ERROR */
+        if (ret <= 0) {
+            return ret;
+        }
+
+        sb->end += ret;
+    }
+
+    return 1;
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_sockbuf.h
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_sockbuf.h	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_sockbuf.h	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,44 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.
+ */
+
+/***************************************************************************
+ * Description: Socket buffer header file                                  *
+ * Author:      Gal Shachor <shachor at il.ibm.com>                           *
+ * Version:     $Revision: 424266 $                                           *
+ ***************************************************************************/
+
+#include "jk_global.h"
+
+#define SOCKBUF_SIZE (8*1024)
+
+struct jk_sockbuf
+{
+    char buf[SOCKBUF_SIZE];
+    unsigned int start;
+    unsigned int end;
+    jk_sock_t sd;
+};
+typedef struct jk_sockbuf jk_sockbuf_t;
+
+int jk_sb_open(jk_sockbuf_t *sb, jk_sock_t sd);
+
+int jk_sb_write(jk_sockbuf_t *sb, const void *buf, unsigned sz);
+
+int jk_sb_read(jk_sockbuf_t *sb, char **buf, unsigned sz, unsigned *ac);
+
+int jk_sb_flush(jk_sockbuf_t *sb);
+
+int jk_sb_gets(jk_sockbuf_t *sb, char **ps);

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_status.c
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_status.c	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_status.c	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,1118 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.
+ */
+
+/***************************************************************************
+ * Description: Status worker, display and manages JK workers              *
+ * Author:      Mladen Turk <mturk at jboss.com>                              *
+ * Author:      Rainer Jung <rjung at apache.org>                             *
+ * Version:     $Revision: 441427 $                                           *
+ ***************************************************************************/
+
+#include "jk_pool.h"
+#include "jk_service.h"
+#include "jk_util.h"
+#include "jk_worker.h"
+#include "jk_status.h"
+#include "jk_mt.h"
+#include "jk_shm.h"
+#include "jk_ajp_common.h"
+#include "jk_lb_worker.h"
+#include "jk_ajp13_worker.h"
+#include "jk_ajp14_worker.h"
+#include "jk_connect.h"
+#include "jk_uri_worker_map.h"
+
+#define HUGE_BUFFER_SIZE (8*1024)
+
+#define JK_STATUS_HEAD "<!DOCTYPE HTML PUBLIC \"-//W3C//" \
+                       "DTD HTML 3.2 Final//EN\">\n"      \
+                       "<html><head><title>JK Status Manager</title>"
+
+#define JK_STATUS_HEND "</head>\n<body>\n"
+#define JK_STATUS_BEND "</body>\n</html>\n"
+
+#define JK_STATUS_XMLH "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n"          \
+                       "<jk:status xmlns:jk=\"http://tomcat.apache.org\">\n"
+
+#define JK_STATUS_XMLE "</jk:status>\n"
+
+#define JK_STATUS_TEXTUPDATE_RESPONCE "OK - jk status worker updated\n"
+
+typedef struct status_worker status_worker_t;
+
+struct status_endpoint
+{
+    jk_endpoint_t   *e;
+    status_worker_t *s_worker;
+    jk_endpoint_t   endpoint;
+};
+
+typedef struct status_endpoint status_endpoint_t;
+
+struct status_worker
+{
+    jk_pool_t         p;
+    jk_pool_atom_t    buf[TINY_POOL_SIZE];
+    const char        *name;
+    const char        *css;
+    jk_worker_t       worker;
+    status_endpoint_t ep;
+    jk_worker_env_t   *we;
+};
+
+static const char *worker_type[] = {
+    "unknown",
+    "ajp12",
+    "ajp13",
+    "ajp14",
+    "jni",
+    "lb",
+    "status",
+    NULL
+};
+
+static const char *headers_names[] = {
+    "Content-Type",
+    "Cache-Control",
+    "Pragma",
+    NULL
+};
+
+#define HEADERS_NO_CACHE "no-cache", "no-cache", NULL
+
+static const char *headers_vhtml[] = {
+    "text/html",
+    HEADERS_NO_CACHE
+};
+
+static const char *headers_vxml[] = {
+    "text/xml",
+    HEADERS_NO_CACHE
+};
+
+static const char *headers_vtxt[] = {
+    "text/plain",
+    HEADERS_NO_CACHE
+};
+
+#if !defined(HAVE_VSNPRINTF) && !defined(HAVE_APR)
+static FILE *f = NULL;
+static int vsnprintf(char *str, size_t n, const char *fmt, va_list ap)
+{
+    int res;
+
+    if (f == NULL)
+        f = fopen("/dev/null", "w");
+    if (f == NULL)
+        return -1;
+
+    setvbuf(f, str, _IOFBF, n);
+
+    res = vfprintf(f, fmt, ap);
+
+    if (res > 0 && res < n) {
+        res = vsprintf(str, fmt, ap);
+    }
+    return res;
+}
+#endif
+
+static int jk_printf(jk_ws_service_t *s, const char *fmt, ...)
+{
+    int rc = 0;
+    va_list args;
+#ifdef NETWARE
+/* On NetWare, this can get called on a thread that has a limited stack so */
+/* we will allocate and free the temporary buffer in this function         */
+        char *buf;
+#else
+        char buf[HUGE_BUFFER_SIZE];
+#endif
+
+    if (!s || !fmt) {
+        return -1;
+    }
+    va_start(args, fmt);
+
+#ifdef NETWARE
+        buf = (char *)malloc(HUGE_BUFFER_SIZE);
+        if (NULL == buf)
+            return -1;
+#endif
+#ifdef USE_VSPRINTF             /* until we get a vsnprintf function */
+    rc = vsprintf(buf, fmt, args);
+#else
+    rc = vsnprintf(buf, HUGE_BUFFER_SIZE, fmt, args);
+#endif
+    va_end(args);
+    if (rc > 0)
+        s->write(s, buf, rc);
+#ifdef NETWARE
+        free(buf);
+#endif
+    return rc;
+}
+
+/* Actually APR's apr_strfsize */
+static char *status_strfsize(jk_uint64_t size, char *buf)
+{
+    const char ord[] = "KMGTPE";
+    const char *o = ord;
+    unsigned int remain, siz;
+
+    if (size < 973) {
+        if (sprintf(buf, "%3d ", (int) size) < 0)
+            return strcpy(buf, "****");
+        return buf;
+    }
+    do {
+        remain = (unsigned int)(size & 0x03FF);
+        size >>= 10;
+        if (size >= 973) {
+            ++o;
+            continue;
+        }
+        siz = (unsigned int)(size & 0xFFFF);
+        if (siz < 9 || (siz == 9 && remain < 973)) {
+            if ((remain = ((remain * 5) + 256) / 512) >= 10)
+                ++siz, remain = 0;
+            if (sprintf(buf, "%d.%d%c", siz, remain, *o) < 0)
+                return strcpy(buf, "****");
+            return buf;
+        }
+        if (remain >= 512)
+            ++siz;
+        if (sprintf(buf, "%3d%c", siz, *o) < 0)
+            return strcpy(buf, "****");
+        return buf;
+    } while (1);
+}
+
+static const char *status_worker_type(int t)
+{
+    if (t < 0 || t > 6)
+        t = 0;
+    return worker_type[t];
+}
+
+
+static const char *status_val_bool(int v)
+{
+    if (v == 0)
+        return "False";
+    else
+        return "True";
+}
+
+static const char *status_val_match(unsigned int match)
+{
+    if (match & MATCH_TYPE_STOPPED)
+        return "Stopped";
+    else if (match & MATCH_TYPE_DISABLED)
+        return "Disabled";
+    else if (match & MATCH_TYPE_NO_MATCH)
+        return "Unmount";
+    else if (match & MATCH_TYPE_EXACT)
+        return "Exact";
+    else if (match & MATCH_TYPE_CONTEXT)
+        return "Context";
+    else if (match & MATCH_TYPE_CONTEXT_PATH)
+        return "Context Path";
+    else if (match & MATCH_TYPE_SUFFIX)
+        return "Suffix";
+    else if (match & MATCH_TYPE_GENERAL_SUFFIX)
+        return "General Suffix";
+    else if (match & MATCH_TYPE_WILDCHAR_PATH)
+        return "Wildchar";
+    else
+        return "Error";
+}
+
+static void jk_puts(jk_ws_service_t *s, const char *str)
+{
+    if (str)
+        s->write(s, str, (unsigned int)strlen(str));
+    else
+        s->write(s, "(null)", 6);
+}
+
+static void jk_putv(jk_ws_service_t *s, ...)
+{
+    va_list va;
+    const char *str;
+
+    va_start(va, s);
+    while (1) {
+        str = va_arg(va, const char *);
+        if (str == NULL)
+            break;
+        s->write(s, str, (unsigned int)strlen(str));
+    }
+    va_end(va);
+}
+
+static const char *status_cmd(const char *param, const char *req, char *buf, size_t len)
+{
+    char ps[32];
+    char *p;
+    size_t l = 0;
+
+    *buf = '\0';
+    if (!req)
+        return NULL;
+    if (!param)
+        return NULL;
+    sprintf(ps, "&%s=", param);
+    p = strstr(req, ps);
+    if (!p) {
+        sprintf(ps, "%s=", param);
+        if (!strncmp(req, ps, strlen(ps)))
+            p = (char *)req;
+    }
+    if (p) {
+        p += strlen(ps);
+        while (*p) {
+            if (*p != '&')
+                buf[l++] = *p;
+            else
+                break;
+            if (l + 2 > len)
+                break;
+            p++;
+        }
+        buf[l] = '\0';
+        if (l)
+            return buf;
+        else
+            return NULL;
+    }
+    else
+        return NULL;
+}
+
+static int status_int(const char *param, const char *req, int def)
+{
+    const char *v;
+    char buf[32];
+    int rv = def;
+
+    if ((v = status_cmd(param, req, buf, sizeof(buf) -1))) {
+        rv = atoi(v);
+    }
+    return rv;
+}
+
+static int status_bool(const char *param, const char *req)
+{
+    const char *v;
+    char buf[32];
+    int rv = 0;
+
+    if ((v = status_cmd(param, req, buf, sizeof(buf)))) {
+        if (strcasecmp(v, "on") == 0 ||
+            strcasecmp(v, "true") == 0)
+            rv = 1;
+    }
+    return rv;
+}
+
+static void display_maps(jk_ws_service_t *s, status_worker_t *sw,
+                         jk_uri_worker_map_t *uwmap,
+                         const char *worker, jk_logger_t *l)
+{
+    unsigned int i;
+
+    jk_puts(s, "<br/>Uri Mappings:\n");
+    jk_puts(s, "<table>\n<tr><th>Match Type</th><th>Uri</th>"
+               "<th>Context</th></tr>\n");
+    for (i = 0; i < uwmap->size; i++) {
+        uri_worker_record_t *uwr = uwmap->maps[i];
+        if (strcmp(uwr->worker_name, worker)) {
+            continue;
+        }
+        jk_putv(s, "<tr><td>",
+                status_val_match(uwr->match_type),
+                "</td><td>", NULL);
+        jk_puts(s, uwr->uri);
+        jk_putv(s, "</td><td>", uwr->context, NULL);
+
+        jk_puts(s, "</td></tr>\n");
+    }
+    jk_puts(s, "</table>\n");
+}
+
+static void dump_maps(jk_ws_service_t *s, status_worker_t *sw,
+                      jk_uri_worker_map_t *uwmap,
+                      const char *worker, jk_logger_t *l)
+{
+    unsigned int i;
+
+    for (i = 0; i < uwmap->size; i++) {
+        uri_worker_record_t *uwr = uwmap->maps[i];
+        if (strcmp(uwr->worker_name, worker)) {
+            continue;
+        }
+        jk_printf(s, "    <jk:map type=\"%s\" uri=\"%s\" context=\"%s\" />\n",
+              status_val_match(uwr->match_type),
+              uwr->uri,
+              uwr->context) ;
+    }
+}
+
+
+/**
+ * Command line reference:
+ * cmd=list (default) display configuration
+ * cmd=show display detailed configuration
+ * cmd=update update configuration
+ * cmd=add  add new uri map.
+ * w=worker display detailed configuration for worker
+ *
+ * Worker parameters:
+ * r=string redirect route name
+ *
+ */
+
+
+static void display_workers(jk_ws_service_t *s, status_worker_t *sw,
+                            const char *dworker, jk_logger_t *l)
+{
+    unsigned int i;
+    char buf[32];
+    time_t now = time(NULL);
+
+    for (i = 0; i < sw->we->num_of_workers; i++) {
+        jk_worker_t *w = wc_get_worker_for_name(sw->we->worker_list[i], l);
+        ajp_worker_t *aw = NULL;
+        lb_worker_t *lb = NULL;
+        if (w == NULL)
+            continue;
+        if (w->type == JK_LB_WORKER_TYPE) {
+            lb = (lb_worker_t *)w->worker_private;
+        }
+        else if (w->type == JK_AJP13_WORKER_TYPE ||
+                 w->type == JK_AJP14_WORKER_TYPE) {
+            aw = (ajp_worker_t *)w->worker_private;
+        }
+        else {
+            /* Skip status, jni and ajp12 worker */
+            continue;
+        }
+        jk_puts(s, "<hr/>\n<h3>Worker Status for ");
+        if (dworker && strcmp(dworker, sw->we->worker_list[i]) == 0) {
+            /* Next click will colapse the editor */
+            jk_putv(s, "<a href=\"", s->req_uri, "?cmd=show\">", NULL);
+        }
+        else
+            jk_putv(s, "<a href=\"", s->req_uri, "?cmd=show&w=",
+                    sw->we->worker_list[i], "\">", NULL);
+        jk_putv(s, sw->we->worker_list[i], "</a></h3>\n", NULL);
+        if (lb != NULL) {
+            unsigned int j;
+            int selected = -1;
+            jk_puts(s, "<table><tr>"
+                    "<th>Type</th><th>Sticky session</th>"
+                    "<th>Force Sticky session</th>"
+                    "<th>Retries</th>"
+                    "<th>Method</th>"
+                    "<th>Lock</th>"
+                    "<th>Recovery timeout</th>"
+                    "</tr>\n<tr>");
+            jk_putv(s, "<td>", status_worker_type(w->type), "</td>", NULL);
+            jk_putv(s, "<td>", status_val_bool(lb->s->sticky_session),
+                    "</td>", NULL);
+            jk_putv(s, "<td>", status_val_bool(lb->s->sticky_session_force),
+                    "</td>", NULL);
+            jk_printf(s, "<td>%d</td>", lb->s->retries);
+            jk_printf(s, "<td>%s</td>", jk_lb_get_method(lb, l));
+            jk_printf(s, "<td>%s</td>", jk_lb_get_lock(lb, l));
+            jk_printf(s, "<td>%d</td>", lb->s->recover_wait_time);
+            jk_puts(s, "</tr>\n</table>\n<br/>\n");
+            jk_puts(s, "<table><tr>"
+                    "<th>Name</th><th>Type</th><th>jvmRoute</th><th>Host</th><th>Addr</th>"
+                    "<th>Act</th><th>Stat</th><th>D</th><th>F</th><th>M</th><th>V</th><th>Acc</th><th>Err</th><th>CE</th>"
+                    "<th>Wr</th><th>Rd</th><th>Busy</th><th>Max</th><th>RR</th><th>Cd</th><th>Rs</th></tr>\n");
+            for (j = 0; j < lb->num_of_workers; j++) {
+                worker_record_t *wr = &(lb->lb_workers[j]);
+                ajp_worker_t *a = (ajp_worker_t *)wr->w->worker_private;
+                jk_putv(s, "<tr>\n<td><a href=\"", s->req_uri,
+                        "?cmd=show&w=",
+                        wr->s->name, "\">",
+                        wr->s->name, "</a></td>", NULL);
+                if (dworker && strcmp(dworker, wr->s->name) == 0)
+                    selected = j;
+                jk_putv(s, "<td>", status_worker_type(wr->w->type), "</td>", NULL);
+                jk_putv(s, "<td>", wr->s->jvm_route, "</td>", NULL);
+                jk_printf(s, "<td>%s:%d</td>", a->host, a->port);
+                jk_putv(s, "<td>", jk_dump_hinfo(&a->worker_inet_addr, buf),
+                        "</td>", NULL);
+                /* TODO: descriptive status */
+                jk_putv(s, "<td>", jk_lb_get_activation(wr, l), "</td>", NULL);
+                jk_putv(s, "<td>", jk_lb_get_state(wr, l), "</td>", NULL);
+                jk_printf(s, "<td>%d</td>", wr->s->distance);
+                jk_printf(s, "<td>%d</td>", wr->s->lb_factor);
+                jk_printf(s, "<td>%" JK_UINT64_T_FMT "</td>", wr->s->lb_mult);
+                jk_printf(s, "<td>%" JK_UINT64_T_FMT "</td>", wr->s->lb_value);
+                jk_printf(s, "<td>%" JK_UINT64_T_FMT "</td>", wr->s->elected);
+                jk_printf(s, "<td>%" JK_UINT32_T_FMT "</td>", wr->s->errors);
+                jk_printf(s, "<td>%" JK_UINT32_T_FMT "</td>", wr->s->client_errors);
+                jk_putv(s, "<td>", status_strfsize(wr->s->transferred, buf),
+                        "</td>", NULL);
+                jk_putv(s, "<td>", status_strfsize(wr->s->readed, buf),
+                        "</td>", NULL);
+                jk_printf(s, "<td>%u</td>", wr->s->busy);
+                jk_printf(s, "<td>%u</td>\n<td>", wr->s->max_busy);
+                if (wr->s->redirect && *wr->s->redirect)
+                    jk_puts(s, wr->s->redirect);
+                else
+                    jk_puts(s,"&nbsp;");
+                jk_puts(s, "</td>\n<td>");
+                if (wr->s->domain && *wr->s->domain)
+                    jk_puts(s, wr->s->domain);
+                else
+                    jk_puts(s,"&nbsp;");
+                jk_puts(s, "</td>\n<td>");
+                if (wr->s->state == JK_LB_STATE_ERROR) {
+                    int rs = lb->maintain_time - (int)difftime(now, lb->s->last_maintain_time);
+                    if (rs < lb->s->recover_wait_time - (int)difftime(now, wr->s->error_time))
+                        rs += lb->maintain_time;
+                    jk_printf(s, "%u", rs < 0 ? 0 : rs);
+                }
+                else
+                    jk_puts(s, "-");
+                jk_puts(s, "</td>\n</tr>\n");
+            }
+            jk_puts(s, "</table><br/>\n");
+            if (selected >= 0) {
+                worker_record_t *wr = &(lb->lb_workers[selected]);
+                jk_putv(s, "<hr/><h3>Edit worker settings for ",
+                        wr->s->name, NULL);
+                jk_putv(s, "<form method=\"GET\" action=\"",
+                        s->req_uri, "\">\n", NULL);
+                jk_puts(s, "<input type=\"hidden\" name=\"cmd\" ");
+                jk_puts(s, "value=\"update\">\n");
+                jk_puts(s, "<input type=\"hidden\" name=\"w\" ");
+                jk_putv(s, "value=\"", wr->s->name, "\">\n", NULL);
+                jk_puts(s, "<input type=\"hidden\" name=\"id\" ");
+                jk_printf(s, "value=\"%u\">\n", selected);
+                jk_puts(s, "<input type=\"hidden\" name=\"lb\" ");
+                jk_printf(s, "value=\"%u\">\n", i);
+
+                jk_puts(s, "<table>\n<tr><td>Route:</td><td><input name=\"wn\" type=\"text\" ");
+                jk_printf(s, "value=\"%s\"/></td></tr>\n", wr->s->jvm_route);
+
+                jk_puts(s, "<tr><td>Distance:</td><td><input name=\"wx\" type=\"text\" ");
+                jk_printf(s, "value=\"%d\"/></td></tr>\n", wr->s->distance);
+
+                jk_puts(s, "<tr><td>Load factor:</td><td><input name=\"wf\" type=\"text\" ");
+                jk_printf(s, "value=\"%d\"/></td></tr>\n", wr->s->lb_factor);
+                jk_puts(s, "<tr><td>Route Redirect:</td><td><input name=\"wr\" type=\"text\" ");
+                jk_putv(s, "value=\"", wr->s->redirect, NULL);
+                jk_puts(s, "\"/></td></tr>\n");
+                jk_puts(s, "<tr><td>Cluster Domain:</td><td><input name=\"wc\" type=\"text\" ");
+                jk_putv(s, "value=\"", wr->s->domain, NULL);
+                jk_puts(s, "\"/></td></tr>\n");
+                jk_puts(s, "<tr><td>Activation:</td><td></td></tr>\n");
+                jk_puts(s, "<tr><td>&nbsp;&nbsp;Active</td><td><input name=\"wa\" type=\"radio\"");
+                jk_printf(s, " value=\"%d\"", JK_LB_ACTIVATION_ACTIVE);
+                if (wr->s->activation == JK_LB_ACTIVATION_ACTIVE)
+                    jk_puts(s, " checked=\"checked\"");
+                jk_puts(s, "/></td></tr>\n");
+                jk_puts(s, "<tr><td>&nbsp;&nbsp;Disabled</td><td><input name=\"wa\" type=\"radio\"");
+                jk_printf(s, " value=\"%d\"", JK_LB_ACTIVATION_DISABLED);
+                if (wr->s->activation == JK_LB_ACTIVATION_DISABLED)
+                    jk_puts(s, " checked=\"checked\"");
+                jk_puts(s, "/></td></tr>\n");
+                jk_puts(s, "<tr><td>&nbsp;&nbsp;Stopped</td><td><input name=\"wa\" type=\"radio\"");
+                jk_printf(s, " value=\"%d\"", JK_LB_ACTIVATION_STOPPED);
+                if (wr->s->activation == JK_LB_ACTIVATION_STOPPED)
+                    jk_puts(s, " checked=\"checked\"");
+                jk_puts(s, "/></td></tr>\n");
+                jk_puts(s, "</table>\n");
+                jk_puts(s, "<br/><input type=\"submit\" value=\"Update Worker\"/>\n</form>\n");
+
+            }
+            else if (dworker && strcmp(dworker, sw->we->worker_list[i]) == 0) {
+                /* Edit Load balancer settings */
+                jk_putv(s, "<hr/><h3>Edit Load balancer settings for ",
+                        dworker, "</h3>\n", NULL);
+                jk_putv(s, "<form method=\"GET\" action=\"",
+                        s->req_uri, "\">\n", NULL);
+                jk_puts(s, "<input type=\"hidden\" name=\"cmd\" ");
+                jk_puts(s, "value=\"update\"/>\n");
+                jk_puts(s, "<input type=\"hidden\" name=\"w\" ");
+                jk_putv(s, "value=\"", dworker, "\"/>\n", NULL);
+                jk_puts(s, "<input type=\"hidden\" name=\"id\" ");
+                jk_printf(s, "value=\"%u\"/>\n", i);
+
+                jk_puts(s, "<table>\n<tr><td>Retries:</td><td><input name=\"lr\" type=\"text\" ");
+                jk_printf(s, "value=\"%d\"/></td></tr>\n", lb->s->retries);
+                jk_puts(s, "<tr><td>Recover time:</td><td><input name=\"lt\" type=\"text\" ");
+                jk_printf(s, "value=\"%d\"/></td></tr>\n", lb->s->recover_wait_time);
+                jk_puts(s, "<tr><td>Sticky session:</td><td><input name=\"ls\" type=\"checkbox\"");
+                if (lb->s->sticky_session)
+                    jk_puts(s, " checked=\"checked\"");
+                jk_puts(s, "/></td></tr>\n");
+                jk_puts(s, "<tr><td>Force Sticky session:</td><td><input name=\"lf\" type=\"checkbox\"");
+                if (lb->s->sticky_session_force)
+                    jk_puts(s, " checked=\"checked\"");
+                jk_puts(s, "/></td></tr>\n");
+                jk_puts(s, "</table>\n");
+
+                display_maps(s, sw, s->uw_map, dworker, l);
+                jk_puts(s, "<br/><input type=\"submit\" value=\"Update Balancer\"/></form>\n");
+            }
+        }
+        else {
+            jk_puts(s, "\n\n<table><tr>"
+                    "<th>Type</th><th>Host</th><th>Addr</th>"
+                    "</tr>\n<tr>");
+            jk_putv(s, "<td>", status_worker_type(w->type), "</td>", NULL);
+            jk_printf(s, "<td>%s:%d</td>", aw->host, aw->port);
+            jk_putv(s, "<td>", jk_dump_hinfo(&aw->worker_inet_addr, buf),
+                    "</td>\n</tr>\n", NULL);
+            jk_puts(s, "</table>\n");
+
+        }
+    }
+    /* Display legend */
+    jk_puts(s, "<hr/><table>\n"
+            "<tr><th>Name</th><td>Worker name</td></tr>\n"
+            "<tr><th>Type</th><td>Worker type</td></tr>\n"
+            "<tr><th>jvmRoute</th><td>Worker JVM route</td></tr>\n"
+            "<tr><th>Addr</th><td>Backend Address info</td></tr>\n"
+            "<tr><th>Act</th><td>Worker activation configuration</td></tr>\n"
+            "<tr><th>Stat</th><td>Worker error status</td></tr>\n"
+            "<tr><th>D</th><td>Worker distance</td></tr>\n"
+            "<tr><th>F</th><td>Load Balancer factor</td></tr>\n"
+            "<tr><th>M</th><td>Load Balancer multiplicity</td></tr>\n"
+            "<tr><th>V</th><td>Load Balancer value</td></tr>\n"
+            "<tr><th>Acc</th><td>Number of requests</td></tr>\n"
+            "<tr><th>Err</th><td>Number of failed requests</td></tr>\n"
+            "<tr><th>CE</th><td>Number of client errors</td></tr>\n"
+            "<tr><th>Wr</th><td>Number of bytes transferred/min</td></tr>\n"
+            "<tr><th>Rd</th><td>Number of bytes read/min</td></tr>\n"
+            "<tr><th>Busy</th><td>Current number of busy connections</td></tr>\n"
+            "<tr><th>Max</th><td>Maximum number of busy connections</td></tr>\n"
+            "<tr><th>RR</th><td>Route redirect</td></tr>\n"
+            "<tr><th>Cd</th><td>Cluster domain</td></tr>\n"
+            "<tr><th>Rs</th><td>Recovery scheduled</td></tr>\n"
+            "</table>");
+}
+
+static void dump_config(jk_ws_service_t *s, status_worker_t *sw,
+                        jk_logger_t *l)
+{
+    unsigned int i;
+    char buf[32];
+    int has_lb = 0;
+
+    for (i = 0; i < sw->we->num_of_workers; i++) {
+        jk_worker_t *w = wc_get_worker_for_name(sw->we->worker_list[i], l);
+        if (w == NULL)
+            continue;
+        if (w->type == JK_LB_WORKER_TYPE) {
+            has_lb = 1;
+            break;
+        }
+    }
+
+    jk_printf(s, "  <jk:server name=\"%s\" port=\"%d\" software=\"%s\" version=\"%s\" />\n",
+              s->server_name, s->server_port, s->server_software,  JK_VERSTRING);
+    if (has_lb)
+        jk_puts(s, "  <jk:balancers>\n");
+    for (i = 0; i < sw->we->num_of_workers; i++) {
+        jk_worker_t *w = wc_get_worker_for_name(sw->we->worker_list[i], l);
+        lb_worker_t *lb = NULL;
+        unsigned int j;
+
+        if (w == NULL)
+            continue;
+        if (w->type == JK_LB_WORKER_TYPE) {
+            lb = (lb_worker_t *)w->worker_private;
+        }
+        else {
+            /* Skip non lb workers */
+            continue;
+        }
+        jk_printf(s, "  <jk:balancer id=\"%d\" name=\"%s\" type=\"%s\" sticky=\"%s\" stickyforce=\"%s\" retries=\"%d\" recover=\"%d\" >\n",
+             i,
+             lb->s->name,
+             status_worker_type(w->type),
+             status_val_bool(lb->s->sticky_session),
+             status_val_bool(lb->s->sticky_session_force),
+             lb->s->retries,
+             lb->s->recover_wait_time);
+        for (j = 0; j < lb->num_of_workers; j++) {
+            worker_record_t *wr = &(lb->lb_workers[j]);
+            ajp_worker_t *a = (ajp_worker_t *)wr->w->worker_private;
+            /* TODO: descriptive status */
+            jk_printf(s, "      <jk:member id=\"%d\" name=\"%s\" type=\"%s\" host=\"%s\" port=\"%d\" address=\"%s\" activation=\"%s\" state=\"%s\"",
+                j,
+                wr->s->name,
+                status_worker_type(wr->w->type),
+                a->host,
+                a->port,
+                jk_dump_hinfo(&a->worker_inet_addr, buf),
+                jk_lb_get_activation(wr, l),
+                jk_lb_get_state(wr, l));
+
+            jk_printf(s, " distance=\"%d\"", wr->s->distance);
+            jk_printf(s, " lbfactor=\"%d\"", wr->s->lb_factor);
+            jk_printf(s, " lbmult=\"%" JK_UINT64_T_FMT "\"", wr->s->lb_mult);
+            jk_printf(s, " lbvalue=\"%" JK_UINT64_T_FMT "\"", wr->s->lb_value);
+            jk_printf(s, " elected=\"%" JK_UINT64_T_FMT "\"", wr->s->elected);
+            jk_printf(s, " errors=\"%" JK_UINT32_T_FMT "\"", wr->s->errors);
+            jk_printf(s, " clienterrors=\"%" JK_UINT32_T_FMT "\"", wr->s->client_errors);
+            jk_printf(s, " transferred=\"%" JK_UINT64_T_FMT "\"", wr->s->transferred);
+            jk_printf(s, " readed=\"%" JK_UINT64_T_FMT "\"", wr->s->readed);
+            jk_printf(s, " busy=\"%u\"", wr->s->busy);
+            jk_printf(s, " maxbusy=\"%u\"", wr->s->max_busy);
+            if (wr->s->jvm_route && *wr->s->jvm_route)
+                jk_printf(s, " jvm_route=\"%s\"", wr->s->jvm_route);
+            if (wr->s->redirect && *wr->s->redirect)
+                jk_printf(s, " redirect=\"%s\"", wr->s->redirect);
+            if (wr->s->domain && *wr->s->domain)
+                jk_printf(s, " domain=\"%s\"", wr->s->domain);
+            jk_puts(s, " />\n");
+        }
+        dump_maps(s, sw, s->uw_map, lb->s->name, l);
+        jk_puts(s, "  </jk:balancer>\n");
+
+    }
+    if (has_lb)
+        jk_puts(s, "  </jk:balancers>\n");
+
+}
+
+static void update_worker(jk_ws_service_t *s, status_worker_t *sw,
+                          const char *dworker, jk_logger_t *l)
+{
+    int i;
+    char buf[1024];
+    const char *b;
+    lb_worker_t *lb;
+    jk_worker_t *w = wc_get_worker_for_name(dworker, l);
+
+    if (w && w->type == JK_LB_WORKER_TYPE) {
+        lb = (lb_worker_t *)w->worker_private;
+        i = status_int("lr", s->query_string, lb->s->retries);
+        if (i > 0)
+            lb->s->retries = i;
+        i = status_int("lt", s->query_string, lb->s->recover_wait_time);
+        if (i < 1)
+            i = 1;
+        lb->s->recover_wait_time = i;
+        lb->s->sticky_session = status_bool("ls", s->query_string);
+        lb->s->sticky_session_force = status_bool("lf", s->query_string);
+    }
+    else  {
+        int n = status_int("lb", s->query_string, -1);
+        worker_record_t *wr = NULL;
+        ajp_worker_t *a;
+        if (n >= 0 && n < (int)sw->we->num_of_workers)
+            w = wc_get_worker_for_name(sw->we->worker_list[n], l);
+        else {
+            if (!(b = status_cmd("l", s->query_string, buf, sizeof(buf))))
+                return;
+            w = wc_get_worker_for_name(b, l);
+        }
+        if (!w || w->type != JK_LB_WORKER_TYPE)
+            return;
+        lb = (lb_worker_t *)w->worker_private;
+        i = status_int("id", s->query_string, -1);
+        if (i >= 0 && i < (int)lb->num_of_workers)
+            wr = &(lb->lb_workers[i]);
+        else {
+            for (i = 0; i < (int)lb->num_of_workers; i++) {
+                if (strcmp(dworker, lb->lb_workers[i].s->name) == 0) {
+                    wr = &(lb->lb_workers[i]);
+                    break;
+                }
+            }
+        }
+        if (!wr)
+            return;
+        a  = (ajp_worker_t *)wr->w->worker_private;
+
+        if ((b = status_cmd("wr", s->query_string, buf, sizeof(buf))))
+            strncpy(wr->s->redirect, b, JK_SHM_STR_SIZ);
+        else
+            memset(wr->s->redirect, 0, JK_SHM_STR_SIZ);
+        if ((b = status_cmd("wc", s->query_string, buf, sizeof(buf))))
+            strncpy(wr->s->domain, b, JK_SHM_STR_SIZ);
+        else
+            memset(wr->s->domain, 0, JK_SHM_STR_SIZ);
+        if ((b = status_cmd("wn", s->query_string, buf, sizeof(buf)))) {
+            if (strlen(b) > 0)
+                strncpy(wr->s->jvm_route, b, JK_SHM_STR_SIZ);
+        }
+        i = status_int("wa", s->query_string, wr->s->activation);
+        if (wr->s->activation != i && i>0 && i<= JK_LB_ACTIVATION_STOPPED) {
+            wr->s->activation = i;
+            reset_lb_values(lb, l);
+            jk_log(l, JK_LOG_INFO,
+                   "worker '%s' activation changed to '%s' via status worker",
+                   wr->s->name,
+                   jk_lb_get_activation(wr, l));
+        }
+        i = status_int("wx", s->query_string, wr->s->distance);
+        if (wr->s->distance != i) {
+            wr->s->distance = i;
+            reset_lb_values(lb, l);
+        }
+        i = status_int("wf", s->query_string, wr->s->lb_factor);
+        if (i > 0 && wr->s->lb_factor != i) {
+            wr->s->lb_factor = i;
+            /* Recalculate the load multiplicators wrt. lb_factor */
+            update_mult(lb, l);
+        }
+    }
+}
+
+static void reset_worker(jk_ws_service_t *s, status_worker_t *sw,
+                         const char *dworker, jk_logger_t *l)
+{
+    unsigned int i;
+    lb_worker_t *lb;
+    jk_worker_t *w = wc_get_worker_for_name(dworker, l);
+
+    if (w && w->type == JK_LB_WORKER_TYPE) {
+        lb = (lb_worker_t *)w->worker_private;
+        for (i = 0; i < lb->num_of_workers; i++) {
+            worker_record_t *wr = &(lb->lb_workers[i]);
+            wr->s->busy             = 0;
+            wr->s->elected          = 0;
+            wr->s->error_time       = 0;
+            wr->s->errors           = 0;
+            wr->s->lb_value         = 0;
+            wr->s->max_busy         = 0;
+            wr->s->readed           = 0;
+            wr->s->transferred      = 0;
+            wr->s->state            = JK_LB_STATE_NA;
+        }
+    }
+}
+
+static int status_cmd_type(const char *req)
+{
+    if (!req)
+        return 0;
+    else if (!strncmp(req, "cmd=list", 8))
+        return 0;
+    else if (!strncmp(req, "cmd=show", 8))
+        return 1;
+    else if (!strncmp(req, "cmd=update", 10))
+        return 2;
+    else if (!strncmp(req, "cmd=reset", 9))
+        return 3;
+    else
+        return 0;
+}
+
+static int status_mime_type(const char *req)
+{
+    int ret = 0 ;
+    if (req) {
+        char mimetype[32];
+        if (status_cmd("mime", req, mimetype, sizeof(mimetype)) != NULL) {
+            if (!strcmp(mimetype, "xml"))
+                ret = 1;
+            else if (!strcmp(mimetype, "txt"))
+                ret = 2;
+        }
+    }
+    return ret ;
+}
+
+static int JK_METHOD service(jk_endpoint_t *e,
+                             jk_ws_service_t *s,
+                             jk_logger_t *l, int *is_recoverable_error)
+{
+    char buf[128];
+    char *worker = NULL;
+    int cmd;
+    int mime;
+    status_endpoint_t *p;
+
+    JK_TRACE_ENTER(l);
+
+    if (is_recoverable_error)
+        *is_recoverable_error = JK_FALSE;
+    if (!e || !e->endpoint_private || !s || !is_recoverable_error) {
+        JK_LOG_NULL_PARAMS(l);
+        JK_TRACE_EXIT(l);
+        return JK_FALSE;
+    }
+
+    p = e->endpoint_private;
+
+    /* Step 1: Process GET params and update configuration */
+    cmd = status_cmd_type(s->query_string);
+    mime = status_mime_type(s->query_string);
+    if (cmd > 0 && (status_cmd("w", s->query_string, buf, sizeof(buf)) != NULL))
+        worker = strdup(buf);
+    if ((cmd == 2) && worker) {
+        /* lock shared memory */
+        jk_shm_lock();
+        update_worker(s, p->s_worker, worker, l);
+        /* update modification time to reflect the current config */
+        jk_shm_set_workers_time(time(NULL));
+        /* Since we updated the config no need to reload
+         * on the next request
+         */
+        jk_shm_sync_access_time();
+        /* unlock the shared memory */
+        jk_shm_unlock();
+    }
+    else if ((cmd == 3) && worker) {
+        /* lock shared memory */
+        jk_shm_lock();
+        reset_worker(s, p->s_worker, worker, l);
+        /* update modification time to reflect the current config */
+        jk_shm_set_workers_time(time(NULL));
+        /* Since we updated the config no need to reload
+         * on the next request
+         */
+        jk_shm_sync_access_time();
+        /* unlock the shared memory */
+        jk_shm_unlock();
+    }
+    if (mime == 0) {
+        int refresh = status_int("refresh", s->query_string, -1);
+        s->start_response(s, 200, "OK", headers_names, headers_vhtml, 3);
+        s->write(s, JK_STATUS_HEAD, sizeof(JK_STATUS_HEAD) - 1);
+        if (cmd > 1) {
+            jk_putv(s, "\n<meta http-equiv=\"Refresh\" content=\"0;url=",
+                      s->req_uri, "\">", NULL);
+        }
+        else if (cmd == 0 && refresh >= 0) {
+            jk_printf(s, "\n<meta http-equiv=\"Refresh\" content=\"%d;url=%s?%s\">",
+                      refresh, s->req_uri, s->query_string);
+        }
+        if (p->s_worker->css) {
+            jk_putv(s, "\n<link rel=\"stylesheet\" type=\"text/css\" href=\"",
+                    p->s_worker->css, "\" />\n", NULL);
+        }
+        s->write(s, JK_STATUS_HEND, sizeof(JK_STATUS_HEND) - 1);
+        jk_printf(s, "<!-- TOMCAT_CONNECTOR_VER_%02d%02d%02d -->\n", JK_VERMAJOR, JK_VERMINOR, JK_VERFIX);
+        jk_printf(s, "<!-- TOMCAT_CONNECTOR_STR_%s -->\n", JK_EXPOSED_VERSION);
+        if ( cmd <= 1 ) {
+            jk_puts(s, "<h1>JK Status Manager for ");
+            jk_puts(s, s->server_name);
+            jk_puts(s, "</h1>\n\n");
+            jk_putv(s, "<dl><dt>Server Version:</dt><dd>",
+                    s->server_software, "</dd>\n", NULL);
+            jk_putv(s, "<dt>JK Version:</dt><dd>",
+                    JK_VERSTRING, "\n</dd></dl>\n", NULL);
+        }
+        if ( cmd == 0 ) {
+            if (refresh >= 0) {
+                const char *str = s->query_string;
+                char *buf = jk_pool_alloc(s->pool, sizeof(char *) * (strlen(str)+1));
+                int result = 0;
+                int scan = 0;
+
+                while (str[scan] != 0) {
+                    if (strncmp(&str[scan], "refresh=", strlen("refresh=")) == 0) {
+                        scan += strlen("refresh=");
+                        while (str[scan] != 0 && str[scan] != '&')
+                            scan++;
+                        if (str[scan] == '&')
+                            scan++;
+                    }
+                    else {
+                        if (result > 0 && str[scan] != 0 && str[scan] != '&') {
+                            buf[result] = '&';
+                            result++;
+                        }
+                        while (str[scan] != 0 && str[scan] != '&') {
+                            buf[result] = str[scan];
+                            result++;
+                            scan++;
+                        }
+                        if (str[scan] == '&')
+                            scan++;
+                    }
+                }
+                buf[result] = '\0';
+
+                jk_putv(s, "[<a href=\"", s->req_uri, NULL);
+                if (buf && buf[0])
+                    jk_putv(s, "?", buf, NULL);
+                jk_puts(s, "\">Stop auto refresh</a>]");
+            }
+            else {
+                jk_putv(s, "<form method=\"GET\" action=\"",
+                        s->req_uri, NULL);
+                if (s->query_string && s->query_string[0])
+                    jk_putv(s, "?", s->query_string, NULL);
+                jk_puts(s, "\">\n");
+                jk_puts(s, "<input type=\"submit\" value=\"Start auto refresh\"/>\n");
+                jk_puts(s, "(interval "
+                        "<input name=\"refresh\" type=\"text\" size=\"3\" value=\"10\"/> "
+                        "seconds)\n");
+                jk_puts(s, "</form>\n");
+            }
+        }
+        if ( cmd <= 1 ) {
+            /* Step 2: Display configuration */
+            display_workers(s, p->s_worker, worker, l);
+        }
+
+        s->write(s, JK_STATUS_BEND, sizeof(JK_STATUS_BEND) - 1);
+
+    }
+    else if (mime == 1) {
+        s->start_response(s, 200, "OK", headers_names, headers_vxml, 3);
+        s->write(s, JK_STATUS_XMLH, sizeof(JK_STATUS_XMLH) - 1);
+        dump_config(s, p->s_worker, l);
+        s->write(s, JK_STATUS_XMLE, sizeof(JK_STATUS_XMLE) - 1);
+    }
+    else {
+        s->start_response(s, 200, "OK", headers_names, headers_vtxt, 3);
+        s->write(s,  JK_STATUS_TEXTUPDATE_RESPONCE,
+                 sizeof(JK_STATUS_TEXTUPDATE_RESPONCE) - 1);
+    }
+    if (worker)
+        free(worker);
+    JK_TRACE_EXIT(l);
+    return JK_TRUE;
+}
+
+static int JK_METHOD done(jk_endpoint_t **e, jk_logger_t *l)
+{
+    JK_TRACE_ENTER(l);
+
+    if (e && *e && (*e)->endpoint_private) {
+        *e = NULL;
+        JK_TRACE_EXIT(l);
+        return JK_TRUE;
+    }
+
+    JK_LOG_NULL_PARAMS(l);
+    JK_TRACE_EXIT(l);
+    return JK_FALSE;
+}
+
+static int JK_METHOD validate(jk_worker_t *pThis,
+                              jk_map_t *props,
+                              jk_worker_env_t *we, jk_logger_t *l)
+{
+    JK_TRACE_ENTER(l);
+
+    if (pThis && pThis->worker_private) {
+        JK_TRACE_EXIT(l);
+        return JK_TRUE;
+    }
+
+    JK_LOG_NULL_PARAMS(l);
+    JK_TRACE_EXIT(l);
+    return JK_FALSE;
+}
+
+static int JK_METHOD init(jk_worker_t *pThis,
+                          jk_map_t *props,
+                          jk_worker_env_t *we, jk_logger_t *log)
+{
+    JK_TRACE_ENTER(log);
+    if (pThis && pThis->worker_private) {
+        status_worker_t *p = pThis->worker_private;
+        p->we = we;
+        if (!jk_get_worker_str_prop(props, p->name, "css", &(p->css)))
+            p->css = NULL;
+    }
+    JK_TRACE_EXIT(log);
+    return JK_TRUE;
+}
+
+static int JK_METHOD get_endpoint(jk_worker_t *pThis,
+                                  jk_endpoint_t **pend, jk_logger_t *l)
+{
+    JK_TRACE_ENTER(l);
+
+    if (pThis && pThis->worker_private && pend) {
+        status_worker_t *p = (status_worker_t *)pThis->worker_private;
+        *pend = p->ep.e;
+        JK_TRACE_EXIT(l);
+        return JK_TRUE;
+    }
+    else {
+        JK_LOG_NULL_PARAMS(l);
+    }
+
+    JK_TRACE_EXIT(l);
+    return JK_FALSE;
+}
+
+static int JK_METHOD destroy(jk_worker_t **pThis, jk_logger_t *l)
+{
+    JK_TRACE_ENTER(l);
+
+    if (pThis && *pThis && (*pThis)->worker_private) {
+        status_worker_t *private_data = (*pThis)->worker_private;
+
+        jk_close_pool(&private_data->p);
+        free(private_data);
+
+        JK_TRACE_EXIT(l);
+        return JK_TRUE;
+    }
+
+    JK_LOG_NULL_PARAMS(l);
+    JK_TRACE_EXIT(l);
+    return JK_FALSE;
+}
+
+int JK_METHOD status_worker_factory(jk_worker_t **w,
+                                    const char *name, jk_logger_t *l)
+{
+    JK_TRACE_ENTER(l);
+
+    if (NULL != name && NULL != w) {
+        status_worker_t *private_data =
+            (status_worker_t *) calloc(1, sizeof(status_worker_t));
+
+        jk_open_pool(&private_data->p,
+                        private_data->buf,
+                        sizeof(jk_pool_atom_t) * TINY_POOL_SIZE);
+
+        private_data->name = name;
+
+        private_data->worker.worker_private = private_data;
+        private_data->worker.validate = validate;
+        private_data->worker.init = init;
+        private_data->worker.get_endpoint = get_endpoint;
+        private_data->worker.destroy = destroy;
+        private_data->worker.retries = 1;
+
+        /* Status worker has single static endpoint. */
+        private_data->ep.endpoint.done = done;
+        private_data->ep.endpoint.service = service;
+        private_data->ep.endpoint.endpoint_private = &private_data->ep;
+        private_data->ep.e = &(private_data->ep.endpoint);
+        private_data->ep.s_worker = private_data;
+        *w = &private_data->worker;
+        JK_TRACE_EXIT(l);
+        return JK_STATUS_WORKER_TYPE;
+    }
+    else {
+        JK_LOG_NULL_PARAMS(l);
+    }
+
+    JK_TRACE_EXIT(l);
+    return 0;
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_status.h
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_status.h	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_status.h	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,43 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.
+ */
+
+/***************************************************************************
+ * Description: Status worker header file                                  *
+ * Author:      Mladen Turk <mturk at jboss.com>                              * 
+ * Version:     $Revision: 300224 $                                           *
+ ***************************************************************************/
+
+#ifndef JK_STATUS_H
+#define JK_STATUS_H
+
+#include "jk_logger.h"
+#include "jk_service.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif                          /* __cplusplus */
+
+#define JK_STATUS_WORKER_NAME     ("status")
+#define JK_STATUS_WORKER_TYPE     (6)
+
+int JK_METHOD status_worker_factory(jk_worker_t **w,
+                                    const char *name, jk_logger_t *l);
+
+#ifdef __cplusplus
+}
+#endif                          /* __cplusplus */
+#endif                          /* JK_STATUS_H */

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_types.h.in
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_types.h.in	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_types.h.in	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,59 @@
+/*
+ *  Copyright 2006 The Apache Software Foundation
+ *
+ *  Licensed 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.
+ */
+
+/***************************************************************************
+ * Description: Platform specific, auto-detected types.                    *
+ * Author:      Rainer Jung <rjung at apache.org>                             *
+ * Version:     $Revision: 408166 $                                           *
+ ***************************************************************************/
+
+#ifndef JK_TYPES_H
+#define JK_TYPES_H
+
+/* GENERATED FILE WARNING!  DO NOT EDIT jk_types.h
+ *
+ * You must modify jk_types.h.in instead.
+ *
+ */
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif                          /* __cplusplus */
+
+/* jk_uint32_t defines a four byte word */
+typedef unsigned @int32_value@ jk_uint32_t;
+
+/* And JK_UINT32_T_FMT */
+ at uint32_t_fmt@
+
+/* And JK_UINT32_T_HEX_FMT */
+ at uint32_t_hex_fmt@
+
+/* jk_uint64_t defines a eight byte word */
+typedef unsigned @int64_value@ jk_uint64_t;
+
+/* And JK_UINT64_T_FMT */
+ at uint64_t_fmt@
+
+/* And JK_UINT64_T_HEX_FMT */
+ at uint64_t_hex_fmt@
+
+#ifdef __cplusplus
+}
+#endif                          /* __cplusplus */
+
+#endif                          /* JK_TYPES_H */

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_uri_worker_map.c
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_uri_worker_map.c	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_uri_worker_map.c	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,653 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.
+ */
+
+/***************************************************************************
+ * Description: URI to worker map object.                                  *
+ *                                                                         *
+ * Author:      Gal Shachor <shachor at il.ibm.com>                           *
+ * Author:      Mladen Turk <mturk at apache.org>                             *
+ * Version:     $Revision: 437379 $                                          *
+ ***************************************************************************/
+
+#include "jk_pool.h"
+#include "jk_util.h"
+#include "jk_map.h"
+#include "jk_mt.h"
+#include "jk_uri_worker_map.h"
+
+#ifdef WIN32
+#define JK_STRCMP   strcasecmp
+#define JK_STRNCMP  strnicmp
+#else
+#define JK_STRCMP   strcmp
+#define JK_STRNCMP  strncmp
+#endif
+
+
+/*
+ * Given context uri, count the number of path tokens.
+ *
+ * Servlet specification 2.4, SRV.11.1 says
+
+ *   The container will recursively try tomatch the longest
+ *   path-prefix. This is done by stepping down the path tree a
+ *   directory at a time, using the / character as a path
+ *   separator. The longest match determines the servlet selected.
+ *
+ * The implication seems to be `most uri path elements is most exact'.
+ * This is a little helper function to count uri tokens, so we can
+ * keep the worker map sorted with most specific first.
+ */
+static int worker_count_context_uri_tokens(const char * context)
+{
+    const char * c = context;
+    int count = 0;
+    while (c && *c) {
+        if ('/' == *c++)
+            count++;
+    }
+    return count;
+}
+
+static int worker_compare(const void *elem1, const void *elem2)
+{
+    uri_worker_record_t *e1 = *(uri_worker_record_t **)elem1;
+    uri_worker_record_t *e2 = *(uri_worker_record_t **)elem2;
+    int e1_tokens = 0;
+    int e2_tokens = 0;
+
+    e1_tokens = worker_count_context_uri_tokens(e1->context);
+    e2_tokens = worker_count_context_uri_tokens(e2->context);
+
+    if (e1_tokens != e2_tokens) {
+        return (e2_tokens - e1_tokens);
+    }
+    /* given the same number of URI tokens, use character
+     * length as a tie breaker
+     */
+    return ((int)e2->context_len - (int)e1->context_len);
+}
+
+static void worker_qsort(jk_uri_worker_map_t *uw_map)
+{
+
+   /* Sort remaining args using Quicksort algorithm: */
+   qsort((void *)uw_map->maps, uw_map->size,
+         sizeof(uri_worker_record_t *), worker_compare );
+
+}
+
+/* Match = 0, NoMatch = 1, Abort = -1
+ * Based loosely on sections of wildmat.c by Rich Salz
+ */
+static int wildchar_match(const char *str, const char *exp, int icase)
+{
+    int x, y;
+
+    for (x = 0, y = 0; exp[y]; ++y, ++x) {
+        if (!str[x] && exp[y] != '*')
+            return -1;
+        if (exp[y] == '*') {
+            while (exp[++y] == '*');
+            if (!exp[y])
+                return 0;
+            while (str[x]) {
+                int ret;
+                if ((ret = wildchar_match(&str[x++], &exp[y], icase)) != 1)
+                    return ret;
+            }
+            return -1;
+        }
+        else if (exp[y] != '?') {
+            if (icase && (tolower(str[x]) != tolower(exp[y])))
+                return 1;
+            else if (!icase && str[x] != exp[y])
+                return 1;
+        }
+    }
+    return (str[x] != '\0');
+}
+
+int uri_worker_map_alloc(jk_uri_worker_map_t **uw_map,
+                         jk_map_t *init_data, jk_logger_t *l)
+{
+    JK_TRACE_ENTER(l);
+
+    if (uw_map) {
+        int rc;
+        *uw_map = (jk_uri_worker_map_t *)calloc(1, sizeof(jk_uri_worker_map_t));
+
+        JK_INIT_CS(&((*uw_map)->cs), rc);
+        if (rc == JK_FALSE) {
+            jk_log(l, JK_LOG_ERROR,
+                   "creating thread lock errno=%d",
+                   errno);
+            JK_TRACE_EXIT(l);
+            return JK_FALSE;
+        }
+        if (init_data)
+            rc = uri_worker_map_open(*uw_map, init_data, l);
+        JK_TRACE_EXIT(l);
+        return rc;
+    }
+
+    JK_LOG_NULL_PARAMS(l);
+    JK_TRACE_EXIT(l);
+
+    return JK_FALSE;
+}
+
+static int uri_worker_map_close(jk_uri_worker_map_t *uw_map, jk_logger_t *l)
+{
+    JK_TRACE_ENTER(l);
+
+    if (uw_map) {
+        int i;
+        JK_DELETE_CS(&(uw_map->cs), i);
+        jk_close_pool(&uw_map->p);
+        JK_TRACE_EXIT(l);
+        return JK_TRUE;
+    }
+
+    JK_LOG_NULL_PARAMS(l);
+    JK_TRACE_EXIT(l);
+    return JK_FALSE;
+}
+
+int uri_worker_map_free(jk_uri_worker_map_t **uw_map, jk_logger_t *l)
+{
+    JK_TRACE_ENTER(l);
+
+    if (uw_map && *uw_map) {
+        uri_worker_map_close(*uw_map, l);
+        free(*uw_map);
+        *uw_map = NULL;
+        JK_TRACE_EXIT(l);
+        return JK_TRUE;
+    }
+    else
+        JK_LOG_NULL_PARAMS(l);
+
+    JK_TRACE_EXIT(l);
+    return JK_FALSE;
+}
+
+/*
+ * Ensure there will be memory in context info to store Context Bases
+ */
+
+#define UW_INC_SIZE 4           /* 4 URI->WORKER STEP */
+
+static int uri_worker_map_realloc(jk_uri_worker_map_t *uw_map)
+{
+    if (uw_map->size == uw_map->capacity) {
+        uri_worker_record_t **uwr;
+        int capacity = uw_map->capacity + UW_INC_SIZE;
+
+        uwr =
+            (uri_worker_record_t **) jk_pool_alloc(&uw_map->p,
+                                                   sizeof(uri_worker_record_t
+                                                          *) * capacity);
+
+        if (!uwr)
+            return JK_FALSE;
+
+        if (uw_map->capacity && uw_map->maps)
+            memcpy(uwr, uw_map->maps,
+                   sizeof(uri_worker_record_t *) * uw_map->capacity);
+
+        uw_map->maps = uwr;
+        uw_map->capacity = capacity;
+    }
+
+    return JK_TRUE;
+}
+
+
+int uri_worker_map_add(jk_uri_worker_map_t *uw_map,
+                       const char *puri, const char *worker, jk_logger_t *l)
+{
+    uri_worker_record_t *uwr = NULL;
+    char *uri;
+    unsigned int match_type = 0;
+    unsigned int i;
+
+    JK_TRACE_ENTER(l);
+
+    if (*puri == '-') {
+        /* Disable urimap.
+         * This way you can disable already mounted
+         * context.
+         */
+        match_type = MATCH_TYPE_DISABLED;
+        puri++;
+    }
+    if (*puri == '!') {
+        match_type |= MATCH_TYPE_NO_MATCH;
+        puri++;
+    }
+
+    /* Find if duplicate entry */
+    for (i = 0; i < uw_map->size; i++) {
+        uwr = uw_map->maps[i];
+        if (strcmp(uwr->uri, puri) == 0) {
+            /* Update disabled flag */
+            if (match_type & MATCH_TYPE_DISABLED)
+                uwr->match_type |= MATCH_TYPE_DISABLED;
+            else
+                uwr->match_type &= ~MATCH_TYPE_DISABLED;
+            if (strcmp(uwr->worker_name, worker) == 0) {
+                jk_log(l, JK_LOG_DEBUG,
+                       "map rule %s=%s already exists",
+                       puri, worker);
+                JK_TRACE_EXIT(l);
+                return JK_TRUE;
+            }
+            else {
+                jk_log(l, JK_LOG_DEBUG,
+                       "changing map rule %s=%s ",
+                       puri, worker);
+                uwr->worker_name = jk_pool_strdup(&uw_map->p, worker);
+                JK_TRACE_EXIT(l);
+                return JK_TRUE;
+            }
+        }
+    }
+    if (uri_worker_map_realloc(uw_map) == JK_FALSE) {
+        JK_TRACE_EXIT(l);
+        return JK_FALSE;
+    }
+    uwr = (uri_worker_record_t *)jk_pool_alloc(&uw_map->p,
+                                    sizeof(uri_worker_record_t));
+    if (!uwr) {
+        jk_log(l, JK_LOG_ERROR,
+               "can't alloc map entry");
+        JK_TRACE_EXIT(l);
+        return JK_FALSE;
+    }
+
+    uri = jk_pool_strdup(&uw_map->p, puri);
+    if (!uri || !worker) {
+        jk_log(l, JK_LOG_ERROR,
+               "can't alloc uri/worker strings");
+        JK_TRACE_EXIT(l);
+        return JK_FALSE;
+    }
+
+    if (*uri == '/') {
+        if (strchr(uri, '*') ||
+            strchr(uri, '?')) {
+            /* Something like
+             * /context/ * /user/ *
+             * /context/ *.suffix
+             */
+            match_type |= MATCH_TYPE_WILDCHAR_PATH;
+            jk_log(l, JK_LOG_DEBUG,
+                    "wildchar rule %s=%s was added",
+                    uri, worker);
+
+        }
+        else {
+            /* Something like:  JkMount /login/j_security_check ajp13 */
+            match_type |= MATCH_TYPE_EXACT;
+            jk_log(l, JK_LOG_DEBUG,
+                   "exact rule %s=%s was added",
+                   uri, worker);
+        }
+        uwr->uri = uri;
+        uwr->context = uri;
+        uwr->worker_name = jk_pool_strdup(&uw_map->p, worker);
+        uwr->context_len = strlen(uwr->context);
+    }
+    else {
+        /*
+         * JFC: please check...
+         * Not sure what to do, but I try to prevent problems.
+         * I have fixed jk_mount_context() in apaches/mod_jk.c so we should
+         * not arrive here when using Apache.
+         */
+        jk_log(l, JK_LOG_ERROR,
+               "invalid context %s",
+               uri);
+        JK_TRACE_EXIT(l);
+        return JK_FALSE;
+    }
+    uwr->match_type = match_type;
+    uw_map->maps[uw_map->size] = uwr;
+    uw_map->size++;
+    if (match_type & MATCH_TYPE_NO_MATCH) {
+        /* If we split the mappings this one will be calculated */
+        uw_map->nosize++;
+    }
+    worker_qsort(uw_map);
+    JK_TRACE_EXIT(l);
+    return JK_TRUE;
+}
+
+int uri_worker_map_open(jk_uri_worker_map_t *uw_map,
+                        jk_map_t *init_data, jk_logger_t *l)
+{
+    int rc = JK_TRUE;
+
+    JK_TRACE_ENTER(l);
+
+    uw_map->size = 0;
+    uw_map->capacity = 0;
+
+    if (uw_map) {
+        int sz;
+
+        rc = JK_TRUE;
+        jk_open_pool(&uw_map->p,
+                     uw_map->buf, sizeof(jk_pool_atom_t) * SMALL_POOL_SIZE);
+        uw_map->size = 0;
+        uw_map->maps = NULL;
+
+        sz = jk_map_size(init_data);
+
+        jk_log(l, JK_LOG_DEBUG,
+               "rule map size is %d",
+               sz);
+
+        if (sz > 0) {
+            int i;
+            for (i = 0; i < sz; i++) {
+                const char *u = jk_map_name_at(init_data, i);
+                const char *w = jk_map_value_at(init_data, i);
+                /* Multiple mappings like :
+                 * /servlets-examples|/ *
+                 * will create two mappings:
+                 * /servlets-examples
+                 * and:
+                 * /servlets-examples/ *
+                 */
+                if (strchr(u, '|')) {
+                    char *s, *r = strdup(u);
+                    s = strchr(r, '|');
+                    *(s++) = '\0';
+                    /* Add first mapping */
+                    if (!uri_worker_map_add(uw_map, r, w, l)) {
+                        jk_log(l, JK_LOG_ERROR,
+                        "invalid mapping rule %s->%s", r, w);
+                        rc = JK_FALSE;
+                    }
+                    for (; *s; s++)
+                        *(s - 1) = *s;
+                    *(s - 1) = '\0';
+                    /* add second mapping */
+                    if (!uri_worker_map_add(uw_map, r, w, l)) {
+                        jk_log(l, JK_LOG_ERROR,
+                               "invalid mapping rule %s->%s", r, w);
+                        rc = JK_FALSE;
+                    }
+                    free(r);
+                }
+                else if (!uri_worker_map_add(uw_map, u, w, l)) {
+                    jk_log(l, JK_LOG_ERROR,
+                           "invalid mapping rule %s->%s",
+                           u, w);
+                    rc = JK_FALSE;
+                    break;
+                }
+                if (rc == JK_FALSE)
+                    break;
+            }
+        }
+
+        if (rc == JK_FALSE) {
+            jk_log(l, JK_LOG_ERROR,
+                   "there was an error, freing buf");
+            jk_close_pool(&uw_map->p);
+        }
+    }
+
+    JK_TRACE_EXIT(l);
+    return rc;
+}
+
+static int is_nomap_match(jk_uri_worker_map_t *uw_map,
+                          const char *uri, const char* worker,
+                          jk_logger_t *l)
+{
+    unsigned int i;
+
+    JK_TRACE_ENTER(l);
+
+    for (i = 0; i < uw_map->size; i++) {
+        uri_worker_record_t *uwr = uw_map->maps[i];
+
+        /* Check only nomatch mappings */
+        if (!(uwr->match_type & MATCH_TYPE_NO_MATCH) ||
+            (uwr->match_type & MATCH_TYPE_DISABLED))
+            continue;
+        /* Check only mathing workers */
+        if (strcmp(uwr->worker_name, worker))
+            continue;
+        if (uwr->match_type & MATCH_TYPE_WILDCHAR_PATH) {
+            /* Map is already sorted by context_len */
+            if (wildchar_match(uri, uwr->context,
+#ifdef WIN32
+                               0
+#else
+                               0
+#endif
+                               ) == 0) {
+                    jk_log(l, JK_LOG_DEBUG,
+                           "Found a no match %s -> %s",
+                           uwr->worker_name, uwr->context);
+                    JK_TRACE_EXIT(l);
+                    return JK_TRUE;
+             }
+        }
+        else if (JK_STRNCMP(uwr->context, uri, uwr->context_len) == 0) {
+            if (strlen(uri) == uwr->context_len) {
+                if (JK_IS_DEBUG_LEVEL(l))
+                    jk_log(l, JK_LOG_DEBUG,
+                            "Found an exact no match %s -> %s",
+                            uwr->worker_name, uwr->context);
+                JK_TRACE_EXIT(l);
+                return JK_TRUE;
+            }
+        }
+    }
+
+    JK_TRACE_EXIT(l);
+    return JK_FALSE;
+}
+
+
+const char *map_uri_to_worker(jk_uri_worker_map_t *uw_map,
+                              const char *uri, jk_logger_t *l)
+{
+    unsigned int i;
+    char *url_rewrite;
+    const char *rv = NULL;
+    char  url[JK_MAX_URI_LEN+1];
+
+    JK_TRACE_ENTER(l);
+
+    if (!uw_map || !uri) {
+        JK_LOG_NULL_PARAMS(l);
+        JK_TRACE_EXIT(l);
+        return NULL;
+    }
+    if (*uri != '/') {
+        jk_log(l, JK_LOG_WARNING,
+                "Uri %s is invalid. Uri must start with /", uri);
+        JK_TRACE_EXIT(l);
+        return NULL;
+    }
+    for (i = 0; i < strlen(uri); i++) 
+        if (uri[i] == ';')
+            break;
+        else
+            url[i] = uri[i];
+    url[i] = '\0';
+    
+    url_rewrite = strstr(uri, JK_PATH_SESSION_IDENTIFIER);
+    if (url_rewrite) {
+        size_t len = url_rewrite - url;
+        if (len > JK_MAX_URI_LEN)
+            len = JK_MAX_URI_LEN;
+        url[len] = '\0';
+        if (JK_IS_DEBUG_LEVEL(l))
+            jk_log(l, JK_LOG_DEBUG, "Removing Session path '%s' URI '%s'",
+                   url_rewrite, url);
+    }
+    if (uw_map->fname)
+        uri_worker_map_update(uw_map, l);
+    if (JK_IS_DEBUG_LEVEL(l))
+        jk_log(l, JK_LOG_DEBUG, "Attempting to map URI '%s' from %d maps",
+               uri, uw_map->size);
+
+    for (i = 0; i < uw_map->size; i++) {
+        uri_worker_record_t *uwr = uw_map->maps[i];
+
+        /* Check for match types */
+        if ((uwr->match_type & MATCH_TYPE_DISABLED) ||
+            (uwr->match_type & MATCH_TYPE_NO_MATCH))
+            continue;
+
+        if (JK_IS_DEBUG_LEVEL(l))
+            jk_log(l, JK_LOG_DEBUG, "Attempting to map context URI '%s'", uwr->uri);
+
+        if (uwr->match_type & MATCH_TYPE_WILDCHAR_PATH) {
+            const char *wname;
+            /* Map is already sorted by context_len */
+            if (wildchar_match(url, uwr->context,
+#ifdef WIN32
+                               0
+#else
+                               0
+#endif
+                               ) == 0) {
+                    wname = uwr->worker_name;
+                    if (JK_IS_DEBUG_LEVEL(l))
+                        jk_log(l, JK_LOG_DEBUG,
+                               "Found a wildchar match %s -> %s",
+                               uwr->worker_name, uwr->context);
+                    JK_TRACE_EXIT(l);
+                    rv = wname;
+                    goto cleanup;
+             }
+        }
+        else if (JK_STRNCMP(uwr->context, url, uwr->context_len) == 0) {
+            if (strlen(url) == uwr->context_len) {
+                if (JK_IS_DEBUG_LEVEL(l))
+                    jk_log(l, JK_LOG_DEBUG,
+                           "Found an exact match %s -> %s",
+                           uwr->worker_name, uwr->context);
+                JK_TRACE_EXIT(l);
+                rv = uwr->worker_name;
+                goto cleanup;
+            }
+        }
+    }
+    /* No matches found */
+    JK_TRACE_EXIT(l);
+
+cleanup:
+    if (rv && uw_map->nosize) {
+        if (is_nomap_match(uw_map, url, rv, l)) {
+            if (JK_IS_DEBUG_LEVEL(l))
+                jk_log(l, JK_LOG_DEBUG,
+                       "Denying matching for worker %s by nomatch rule",
+                       rv);
+            rv = NULL;
+        }
+    }
+    return rv;
+}
+
+int uri_worker_map_load(jk_uri_worker_map_t *uw_map,
+                        jk_logger_t *l)
+{
+    int rc = JK_FALSE;
+    jk_map_t *map;
+
+    jk_map_alloc(&map);
+    if (jk_map_read_properties(map, uw_map->fname,
+                               &uw_map->modified, l)) {
+        int i;
+        for (i = 0; i < jk_map_size(map); i++) {
+            const char *u = jk_map_name_at(map, i);
+            const char *w = jk_map_value_at(map, i);
+            /* Multiple mappings like :
+             * /servlets-examples|/ *
+             * will create two mappings:
+             * /servlets-examples
+             * and:
+             * /servlets-examples/ *
+             */
+            if (strchr(u, '|')) {
+                char *s, *r = strdup(u);
+                s = strchr(r, '|');
+                *(s++) = '\0';
+                /* Add first mapping */
+                if (!uri_worker_map_add(uw_map, r, w, l)) {
+                    jk_log(l, JK_LOG_ERROR,
+                    "invalid mapping rule %s->%s", r, w);
+                }
+                for (; *s; s++)
+                   *(s - 1) = *s;
+                *(s - 1) = '\0';
+                /* add second mapping */
+                if (!uri_worker_map_add(uw_map, r, w, l)) {
+                    jk_log(l, JK_LOG_ERROR,
+                    "invalid mapping rule %s->%s", r, w);
+                }
+                free(r);
+            }
+            else if (!uri_worker_map_add(uw_map, u, w, l)) {
+                jk_log(l, JK_LOG_ERROR,
+                       "invalid mapping rule %s->%s",
+                       u, w);
+            }
+        }
+        uw_map->checked = time(NULL);
+        rc = JK_TRUE;
+    }
+    jk_map_free(&map);
+    return rc;
+}
+
+int uri_worker_map_update(jk_uri_worker_map_t *uw_map,
+                          jk_logger_t *l)
+{
+    int rc = JK_TRUE;
+    time_t now = time(NULL);
+
+    if ((now - uw_map->checked) > JK_URIMAP_RELOAD) {
+        struct stat statbuf;
+        uw_map->checked = now;
+        if ((rc = stat(uw_map->fname, &statbuf)) == -1)
+            return JK_FALSE;
+        if (statbuf.st_mtime == uw_map->modified)
+            return JK_TRUE;
+        JK_ENTER_CS(&(uw_map->cs), rc);
+        /* Check if some other thread updated status */
+        if (statbuf.st_mtime == uw_map->modified) {
+            JK_LEAVE_CS(&(uw_map->cs), rc);
+            return JK_TRUE;
+        }
+        rc = uri_worker_map_load(uw_map, l);
+        JK_LEAVE_CS(&(uw_map->cs), rc);
+        jk_log(l, JK_LOG_INFO,
+               "Reloaded urimaps from %s", uw_map->fname);
+    }
+    return rc;
+}
+

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_uri_worker_map.h
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_uri_worker_map.h	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_uri_worker_map.h	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,127 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.
+ */
+
+/***************************************************************************
+ * Description: URI to worker mapper header file                           *
+ * Author:      Gal Shachor <shachor at il.ibm.com>                           *
+ * Version:     $Revision: 405672 $                                           *
+ ***************************************************************************/
+
+#ifndef JK_URI_WORKER_MAP_H
+#define JK_URI_WORKER_MAP_H
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif                          /* __cplusplus */
+
+#include "jk_global.h"
+#include "jk_map.h"
+#include "jk_logger.h"
+#include "jk_mt.h"
+
+/* Urimap reload time. Use 60 seconds by default.
+ */
+#define JK_URIMAP_RELOAD            60
+
+#define MATCH_TYPE_EXACT            0x0001
+#define MATCH_TYPE_CONTEXT          0x0002
+/* match all context path URIs with a path component suffix */
+#define MATCH_TYPE_CONTEXT_PATH     0x0004
+#define MATCH_TYPE_SUFFIX           0x0010
+/* match all URIs of the form *ext */
+#define MATCH_TYPE_GENERAL_SUFFIX   0x0020
+/* match multiple wild characters (*) and (?) */
+#define MATCH_TYPE_WILDCHAR_PATH    0x0040
+#define MATCH_TYPE_NO_MATCH         0x1000
+#define MATCH_TYPE_DISABLED         0x2000
+#define MATCH_TYPE_STOPPED          0x4000
+
+#define JK_MAX_URI_LEN              4095
+struct uri_worker_record
+{
+    /* Original uri for logging */
+    char *uri;
+
+    /* Name of worker mapped */
+    const char *worker_name;
+
+    /* Base context */
+    const char *context;
+
+    /* Match type */
+    unsigned int match_type;
+
+    /* char length of the context */
+    size_t context_len;
+};
+typedef struct uri_worker_record uri_worker_record_t;
+
+struct jk_uri_worker_map
+{
+    /* Memory Pool */
+    jk_pool_t p;
+    jk_pool_atom_t buf[BIG_POOL_SIZE];
+
+    /* map URI->WORKER */
+    uri_worker_record_t **maps;
+    
+    /* Map Number */
+    unsigned int size;
+
+    /* Map Capacity */
+    unsigned int capacity;
+
+    /* NoMap Number */
+    unsigned int nosize;
+
+    /* Dynamic config support */
+
+    JK_CRIT_SEC cs;
+    /* uriworkermap filename */
+    const char *fname;    
+    /* Last modified time */
+    time_t  modified;
+    /* Last checked time */
+    time_t  checked;
+};
+typedef struct jk_uri_worker_map jk_uri_worker_map_t;
+
+int uri_worker_map_alloc(jk_uri_worker_map_t **uw_map,
+                         jk_map_t *init_data, jk_logger_t *l);
+
+int uri_worker_map_free(jk_uri_worker_map_t **uw_map, jk_logger_t *l);
+
+int uri_worker_map_open(jk_uri_worker_map_t *uw_map,
+                        jk_map_t *init_data, jk_logger_t *l);
+
+int uri_worker_map_add(jk_uri_worker_map_t *uw_map,
+                       const char *puri, const char *pworker, jk_logger_t *l);
+
+const char *map_uri_to_worker(jk_uri_worker_map_t *uw_map,
+                              const char *uri, jk_logger_t *l);
+
+int uri_worker_map_load(jk_uri_worker_map_t *uw_map,
+                        jk_logger_t *l);
+
+int uri_worker_map_update(jk_uri_worker_map_t *uw_map,
+                          jk_logger_t *l);
+
+#ifdef __cplusplus
+}
+#endif    /* __cplusplus */
+#endif    /* JK_URI_WORKER_MAP_H */

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_util.c
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_util.c	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_util.c	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,1429 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.
+ */
+
+/***************************************************************************
+ * Description: Utility functions (mainly configuration)                   *
+ * Author:      Gal Shachor <shachor at il.ibm.com>                           *
+ * Author:      Henri Gomez <hgomez at apache.org>                            *
+ * Author:      Rainer Jung <rjung at apache.org>                             *
+ * Version:     $Revision: 440635 $                                          *
+ ***************************************************************************/
+
+
+#include "jk_util.h"
+#include "jk_ajp12_worker.h"
+#include "jk_ajp13_worker.h"
+#include "jk_ajp14_worker.h"
+#include "jk_lb_worker.h"
+#include "jk_mt.h"
+
+#define SYSPROPS_OF_WORKER          ("sysprops")
+#define STDERR_OF_WORKER            ("stderr")
+#define STDOUT_OF_WORKER            ("stdout")
+#define SECRET_OF_WORKER            ("secret")
+#define MX_OF_WORKER                ("mx")
+#define MS_OF_WORKER                ("ms")
+#define CP_OF_WORKER                ("class_path")
+#define BRIDGE_OF_WORKER            ("bridge")
+#define JVM_OF_WORKER               ("jvm_lib")
+#define LIBPATH_OF_WORKER           ("ld_path")
+#define CMD_LINE_OF_WORKER          ("cmd_line")
+#define NATIVE_LIB_OF_WORKER        ("native_lib")
+#define HOST_OF_WORKER              ("host")
+#define PORT_OF_WORKER              ("port")
+#define TYPE_OF_WORKER              ("type")
+#define CACHE_OF_WORKER_DEPRECATED  ("cachesize")
+#define CACHE_OF_WORKER             ("connection_pool_size")
+#define CACHE_OF_WORKER_MIN         ("connection_pool_minsize")
+#define CACHE_TIMEOUT_DEPRECATED    ("cache_timeout")
+#define CACHE_TIMEOUT_OF_WORKER     ("connection_pool_timeout")
+#define RECOVERY_OPTS_OF_WORKER     ("recovery_options")
+#define CONNECT_TIMEOUT_OF_WORKER   ("connect_timeout")
+#define PREPOST_TIMEOUT_OF_WORKER   ("prepost_timeout")
+#define REPLY_TIMEOUT_OF_WORKER     ("reply_timeout")
+#define SOCKET_TIMEOUT_OF_WORKER    ("socket_timeout")
+#define SOCKET_BUFFER_OF_WORKER     ("socket_buffer")
+#define SOCKET_KEEPALIVE_OF_WORKER  ("socket_keepalive")
+#define RECYCLE_TIMEOUT_DEPRECATED  ("recycle_timeout")
+#define LOAD_FACTOR_OF_WORKER       ("lbfactor")
+#define DISTANCE_OF_WORKER          ("distance")
+#define BALANCED_WORKERS_DEPRECATED ("balanced_workers")
+#define BALANCE_WORKERS             ("balance_workers")
+#define STICKY_SESSION              ("sticky_session")
+#define STICKY_SESSION_FORCE        ("sticky_session_force")
+#define JVM_ROUTE_OF_WORKER         ("jvm_route")
+#define DOMAIN_OF_WORKER            ("domain")
+#define REDIRECT_OF_WORKER          ("redirect")
+#define MOUNT_OF_WORKER             ("mount")
+#define METHOD_OF_WORKER            ("method")
+#define LOCK_OF_WORKER              ("lock")
+#define IS_WORKER_DISABLED_DEPRECATED ("disabled")
+#define IS_WORKER_STOPPED_DEPRECATED  ("stopped")
+#define ACTIVATION_OF_WORKER        ("activation")
+#define WORKER_RECOVER_TIME         ("recover_time")
+#define WORKER_MAX_PACKET_SIZE      ("max_packet_size")
+
+
+#define DEFAULT_WORKER_TYPE         JK_AJP13_WORKER_NAME
+#define SECRET_KEY_OF_WORKER        ("secretkey")
+#define RETRIES_OF_WORKER           ("retries")
+
+#define DEFAULT_WORKER              JK_AJP13_WORKER_NAME
+#define WORKER_LIST_PROPERTY_NAME     ("worker.list")
+#define WORKER_MAINTAIN_PROPERTY_NAME ("worker.maintain")
+#define DEFAULT_MAINTAIN_TIME       (60)
+#define DEFAULT_LB_FACTOR           (1)
+#define DEFAULT_DISTANCE            (0)
+
+#define TOMCAT32_BRIDGE_NAME        ("tomcat32")
+#define TOMCAT33_BRIDGE_NAME        ("tomcat33")
+#define TOMCAT40_BRIDGE_NAME        ("tomcat40")
+#define TOMCAT41_BRIDGE_NAME        ("tomcat41")
+#define TOMCAT50_BRIDGE_NAME        ("tomcat5")
+
+#define HUGE_BUFFER_SIZE (8*1024)
+#define LOG_LINE_SIZE    (1024)
+
+#define MAKE_WORKER_PARAM(P)     \
+        strcpy(buf, "worker.");  \
+        strcat(buf, wname);      \
+        strcat(buf, ".");        \
+        strcat(buf, P)
+
+/*
+ * define the log format, we're using by default the one from error.log
+ *
+ * [Mon Mar 26 19:44:48 2001] [jk_uri_worker_map.c (155)]: Into jk_uri_worker_map_t::uri_worker_map_alloc
+ * log format used by apache in error.log
+ */
+#ifndef JK_TIME_FORMAT
+#define JK_TIME_FORMAT "[%a %b %d %H:%M:%S %Y] "
+#endif
+
+/* Visual C++ Toolkit 2003 support */
+#if defined (_MSC_VER) && (_MSC_VER == 1310)
+    extern long _ftol(double); /* defined by VC6 C libs */
+    extern long _ftol2(double dblSource) { return _ftol(dblSource); }
+#endif
+
+static const char *list_properties[] = {
+    BALANCE_WORKERS,
+    MOUNT_OF_WORKER,
+    "list",
+    NULL
+};
+
+static const char *unique_properties[] = {
+    SECRET_OF_WORKER,
+    HOST_OF_WORKER,
+    PORT_OF_WORKER,
+    TYPE_OF_WORKER,
+    CACHE_OF_WORKER_DEPRECATED,
+    CACHE_OF_WORKER,
+    CACHE_OF_WORKER_MIN,
+    CACHE_TIMEOUT_DEPRECATED,
+    CACHE_TIMEOUT_OF_WORKER,
+    RECOVERY_OPTS_OF_WORKER,
+    CONNECT_TIMEOUT_OF_WORKER,
+    PREPOST_TIMEOUT_OF_WORKER,
+    REPLY_TIMEOUT_OF_WORKER,
+    SOCKET_TIMEOUT_OF_WORKER,
+    SOCKET_BUFFER_OF_WORKER,
+    SOCKET_KEEPALIVE_OF_WORKER,
+    RECYCLE_TIMEOUT_DEPRECATED,
+    LOAD_FACTOR_OF_WORKER,
+    STICKY_SESSION,
+    STICKY_SESSION_FORCE,
+    JVM_ROUTE_OF_WORKER,
+    DOMAIN_OF_WORKER,
+    REDIRECT_OF_WORKER,
+    METHOD_OF_WORKER,
+    LOCK_OF_WORKER,
+    IS_WORKER_DISABLED_DEPRECATED,
+    IS_WORKER_STOPPED_DEPRECATED,
+    ACTIVATION_OF_WORKER,
+    WORKER_RECOVER_TIME,
+    WORKER_MAX_PACKET_SIZE,
+    RETRIES_OF_WORKER,
+    WORKER_MAINTAIN_PROPERTY_NAME,
+    NULL
+};
+
+static const char *deprecated_properties[] = {
+    SYSPROPS_OF_WORKER,
+    STDERR_OF_WORKER,
+    STDOUT_OF_WORKER,
+    MX_OF_WORKER,
+    MS_OF_WORKER,
+    CP_OF_WORKER,
+    BRIDGE_OF_WORKER,
+    JVM_OF_WORKER,
+    LIBPATH_OF_WORKER,
+    CMD_LINE_OF_WORKER,
+    NATIVE_LIB_OF_WORKER,
+    CACHE_OF_WORKER_DEPRECATED,
+    CACHE_TIMEOUT_DEPRECATED,
+    RECYCLE_TIMEOUT_DEPRECATED,
+    BALANCED_WORKERS_DEPRECATED,
+    IS_WORKER_DISABLED_DEPRECATED,
+    IS_WORKER_STOPPED_DEPRECATED,
+    NULL
+};
+
+/* All entries need to have fixed length 8 chars! */
+static const char *jk_level_verbs[] = {
+    "[" JK_LOG_TRACE_VERB "] ",
+    "[" JK_LOG_DEBUG_VERB "] ",
+    "[" JK_LOG_INFO_VERB "]  ",
+    "[" JK_LOG_WARN_VERB "]  ",
+    "[" JK_LOG_ERROR_VERB "] ",
+    "[" JK_LOG_EMERG_VERB "] ",
+    NULL
+};
+
+const char *jk_log_fmt = JK_TIME_FORMAT;
+
+/* Sleep for 100ms */
+void jk_sleep(int ms)
+{
+#ifdef OS2
+    DosSleep(ms);
+#elif defined(BEOS)
+    snooze(ms * 1000);
+#elif defined(NETWARE)
+    delay(ms);
+#elif defined(WIN32)
+    Sleep(ms);
+#else
+    struct timeval tv;
+    tv.tv_usec = ms * 1000;
+    tv.tv_sec = 0;
+    select(0, NULL, NULL, NULL, &tv);
+#endif
+}
+
+static int set_time_str(char *str, int len)
+{
+    time_t t = time(NULL);
+    struct tm *tms;
+
+    tms = localtime(&t);
+    return (int)strftime(str, len, jk_log_fmt, tms);
+}
+
+/* Write at most n characters to the buffer in str, return the
+ * number of chars written or -1 if the buffer would have been
+ * overflowed.
+ *
+ * This is portable to any POSIX-compliant system that has /dev/null
+ */
+#if !defined(HAVE_VSNPRINTF) && !defined(HAVE_APR)
+static FILE *f = NULL;
+static int vsnprintf(char *str, size_t n, const char *fmt, va_list ap)
+{
+    int res;
+
+    if (f == NULL)
+        f = fopen("/dev/null", "w");
+    if (f == NULL)
+        return -1;
+
+    setvbuf(f, str, _IOFBF, n);
+
+    res = vfprintf(f, fmt, ap);
+
+    if (res > 0 && res < n) {
+        res = vsprintf(str, fmt, ap);
+    }
+    return res;
+}
+#endif
+#if !defined(HAVE_SNPRINTF) && !defined(HAVE_APR)
+static int snprintf(char *str, size_t n, const char *fmt, ...)
+{
+    va_list ap;
+    int res;
+
+    va_start(ap, fmt);
+    res = vsnprintf(str, n, fmt, ap);
+    va_end(ap);
+    return res;
+}
+#endif
+
+static int JK_METHOD log_to_file(jk_logger_t *l, int level, const char *what)
+{
+    if (l &&
+        (l->level <= level || level == JK_LOG_REQUEST_LEVEL) &&
+        l->logger_private && what) {
+        size_t sz = strlen(what);
+        if (sz) {
+            file_logger_t *p = l->logger_private;
+            if (fwrite(what, 1, sz, p->logfile)) {
+                /* [V] Flush the dam' thing! */
+                fflush(p->logfile);
+            }
+        }
+
+        return JK_TRUE;
+    }
+
+    return JK_FALSE;
+}
+
+int jk_parse_log_level(const char *level)
+{
+    if (0 == strcasecmp(level, JK_LOG_TRACE_VERB)) {
+        return JK_LOG_TRACE_LEVEL;
+    }
+
+    if (0 == strcasecmp(level, JK_LOG_DEBUG_VERB)) {
+        return JK_LOG_DEBUG_LEVEL;
+    }
+
+    if (0 == strcasecmp(level, JK_LOG_INFO_VERB)) {
+        return JK_LOG_INFO_LEVEL;
+    }
+
+    if (0 == strcasecmp(level, JK_LOG_WARN_VERB)) {
+        return JK_LOG_WARNING_LEVEL;
+    }
+
+    if (0 == strcasecmp(level, JK_LOG_ERROR_VERB)) {
+        return JK_LOG_ERROR_LEVEL;
+    }
+
+    if (0 == strcasecmp(level, JK_LOG_EMERG_VERB)) {
+        return JK_LOG_EMERG_LEVEL;
+    }
+
+    return JK_LOG_DEF_LEVEL;
+}
+
+int jk_open_file_logger(jk_logger_t **l, const char *file, int level)
+{
+    if (l && file) {
+        jk_logger_t *rc = (jk_logger_t *)malloc(sizeof(jk_logger_t));
+        file_logger_t *p = (file_logger_t *) malloc(sizeof(file_logger_t));
+        if (rc && p) {
+            rc->log = log_to_file;
+            rc->level = level;
+            rc->logger_private = p;
+#ifdef AS400
+            p->logfile = fopen(file, "a+, o_ccsid=0");
+#else
+            p->logfile = fopen(file, "a+");
+#endif
+            if (p->logfile) {
+                *l = rc;
+                return JK_TRUE;
+            }
+        }
+        if (rc) {
+            free(rc);
+        }
+        if (p) {
+            free(p);
+        }
+
+        *l = NULL;
+    }
+    return JK_FALSE;
+}
+
+int jk_close_file_logger(jk_logger_t **l)
+{
+    if (l && *l) {
+        file_logger_t *p = (*l)->logger_private;
+        if (p) {
+            fflush(p->logfile);
+            fclose(p->logfile);
+            free(p);
+        }
+        free(*l);
+        *l = NULL;
+
+        return JK_TRUE;
+    }
+    return JK_FALSE;
+}
+
+int jk_log(jk_logger_t *l,
+           const char *file, int line, const char *funcname, int level,
+           const char *fmt, ...)
+{
+    int rc = 0;
+    /* Need to reserve space for newline and terminating zero byte. */
+    static int usable_size = HUGE_BUFFER_SIZE-2;
+    if (!l || !file || !fmt) {
+        return -1;
+    }
+
+    if ((l->level <= level) || (level == JK_LOG_REQUEST_LEVEL)) {
+#ifdef NETWARE
+        /* On NetWare, this can get called on a thread that has a limited stack so */
+        /* we will allocate and free the temporary buffer in this function         */
+        char *buf;
+#else
+        char buf[HUGE_BUFFER_SIZE];
+#endif
+        char *f = (char *)(file + strlen(file) - 1);
+        va_list args;
+        int used = 0;
+
+        while (f != file && '\\' != *f && '/' != *f) {
+            f--;
+        }
+        if (f != file) {
+            f++;
+        }
+
+#ifdef NETWARE
+        buf = (char *)malloc(HUGE_BUFFER_SIZE);
+        if (NULL == buf)
+            return -1;
+#endif
+        used = set_time_str(buf, usable_size);
+
+        if (line) {
+            /* Log [pid:threadid] for all levels except REQUEST. */
+            /* This information helps to correlate lines from different logs. */
+            /* Performance is no issue, because with production log levels */
+            /* we only call it often, if we have a lot of errors */
+#ifdef USE_SPRINTF              /* until we get a snprintf function */
+            rc = sprintf(&buf[used], "[%04d:%04d] ", getpid(),
+                            jk_gettid());
+#else
+            rc = snprintf(&buf[used], usable_size - used,
+                             "[%04d:%04d] ", getpid(), jk_gettid());
+#endif
+            used += rc;
+            if (rc < 0 || usable_size - used < 8) {
+                return 0;
+            }
+            strcat(buf, jk_level_verbs[level]);
+            used += 8;
+
+            if (funcname) {
+                rc = (int)strlen(funcname) + 2;
+                if (usable_size - used >= rc) {
+                    strcat(buf, funcname);
+                    strcat(buf, "::");
+                    used += rc;
+                }
+            }
+
+#ifdef USE_SPRINTF              /* until we get a snprintf function */
+            rc = sprintf(&buf[used], "%s (%d): ", f, line);
+#else
+            rc = snprintf(&buf[used], usable_size - used,
+                             "%s (%d): ", f, line);
+#endif
+            used += rc;
+            if (rc < 0 || usable_size - used < 0) {
+                return 0;           /* [V] not sure what to return... */
+            }
+        }
+
+        va_start(args, fmt);
+#ifdef USE_VSPRINTF             /* until we get a vsnprintf function */
+        rc = vsprintf(buf + used, fmt, args);
+#else
+        rc = vsnprintf(buf + used, usable_size - used, fmt, args);
+#endif
+        if ( rc <= usable_size - used ) {
+            used += rc;
+        } else {
+            used = usable_size;
+        }
+        buf[used] = '\n';
+        buf[used+1] = 0;
+        va_end(args);
+        l->log(l, level, buf);
+#ifdef NETWARE
+        free(buf);
+#endif
+    }
+
+    return rc;
+}
+
+const char *jk_get_worker_type(jk_map_t *m, const char *wname)
+{
+    char buf[1024];
+
+    if (!m || !wname) {
+        return NULL;
+    }
+    MAKE_WORKER_PARAM(TYPE_OF_WORKER);
+    return jk_map_get_string(m, buf, DEFAULT_WORKER_TYPE);
+}
+
+const char *jk_get_worker_jvm_route(jk_map_t *m, const char *wname, const char *def)
+{
+    char buf[1024];
+    if (!m || !wname) {
+        return NULL;
+    }
+    MAKE_WORKER_PARAM(JVM_ROUTE_OF_WORKER);
+    return jk_map_get_string(m, buf, def);
+}
+
+const char *jk_get_worker_domain(jk_map_t *m, const char *wname, const char *def)
+{
+    char buf[1024];
+    if (!m || !wname) {
+        return NULL;
+    }
+    MAKE_WORKER_PARAM(DOMAIN_OF_WORKER);
+    return jk_map_get_string(m, buf, def);
+}
+
+const char *jk_get_worker_redirect(jk_map_t *m, const char *wname, const char *def)
+{
+    char buf[1024];
+    if (!m || !wname) {
+        return NULL;
+    }
+   MAKE_WORKER_PARAM(REDIRECT_OF_WORKER);
+    return jk_map_get_string(m, buf, def);
+}
+
+const char *jk_get_worker_secret(jk_map_t *m, const char *wname)
+{
+    char buf[1024];
+
+    if (!m || !wname) {
+        return NULL;
+    }
+
+    MAKE_WORKER_PARAM(SECRET_OF_WORKER);
+
+    return jk_map_get_string(m, buf, NULL);
+}
+
+/* [V] I suggest that the following general purpose functions be used.       */
+/*     More should be added (double etc.), but now these were enough for me. */
+/*     Functions that can be simulated with these should be "deprecated".    */
+
+int jk_get_worker_str_prop(jk_map_t *m,
+                           const char *wname, const char *pname, const char **prop)
+{
+    char buf[1024];
+
+    if (m && prop && wname && pname) {
+        MAKE_WORKER_PARAM(pname);
+        *prop = jk_map_get_string(m, buf, NULL);
+        if (*prop) {
+            return JK_TRUE;
+        }
+    }
+    return JK_FALSE;
+}
+
+int jk_get_worker_int_prop(jk_map_t *m,
+                           const char *wname, const char *pname, int *prop)
+{
+    char buf[1024];
+
+    if (m && prop && wname && pname) {
+        int i;
+        MAKE_WORKER_PARAM(pname);
+        i = jk_map_get_int(m, buf, -1);
+        if (-1 != i) {
+            *prop = i;
+            return JK_TRUE;
+        }
+    }
+    return JK_FALSE;
+}
+
+const char *jk_get_worker_host(jk_map_t *m, const char *wname, const char *def)
+{
+    char buf[1024];
+
+    if (!m || !wname) {
+        return NULL;
+    }
+
+    MAKE_WORKER_PARAM(HOST_OF_WORKER);
+
+    return jk_map_get_string(m, buf, def);
+}
+
+int jk_get_worker_port(jk_map_t *m, const char *wname, int def)
+{
+    char buf[1024];
+
+    if (!m || !wname) {
+        return -1;
+    }
+
+    MAKE_WORKER_PARAM(PORT_OF_WORKER);
+
+    return jk_map_get_int(m, buf, def);
+}
+
+static int def_cache_size = -1;
+int jk_get_worker_def_cache_size(int protocol)
+{
+    if (def_cache_size < 1) {
+        if (protocol == AJP14_PROTO)
+            def_cache_size = AJP14_DEF_CACHE_SZ;
+        else
+            def_cache_size = AJP13_DEF_CACHE_SZ;
+    }
+    return def_cache_size;
+}
+
+void jk_set_worker_def_cache_size(int sz)
+{
+    def_cache_size = sz;
+}
+
+int jk_get_worker_cache_size(jk_map_t *m, const char *wname, int def)
+{
+    char buf[1024];
+    int rv;
+
+    if (!m || !wname) {
+        return -1;
+    }
+
+    MAKE_WORKER_PARAM(CACHE_OF_WORKER);
+    if ((rv = jk_map_get_int(m, buf, -1)) >= 0)
+        return rv;
+    MAKE_WORKER_PARAM(CACHE_OF_WORKER_DEPRECATED);
+    return jk_map_get_int(m, buf, def);
+}
+
+int jk_get_worker_cache_size_min(jk_map_t *m, const char *wname, int def)
+{
+    char buf[1024];
+
+    if (!m || !wname) {
+        return -1;
+    }
+
+    MAKE_WORKER_PARAM(CACHE_OF_WORKER_MIN);
+    return jk_map_get_int(m, buf, def);
+}
+
+int jk_get_worker_socket_timeout(jk_map_t *m, const char *wname, int def)
+{
+    char buf[1024];
+
+    if (!m || !wname) {
+        return -1;
+    }
+
+    MAKE_WORKER_PARAM(SOCKET_TIMEOUT_OF_WORKER);
+
+    return jk_map_get_int(m, buf, def);
+}
+
+int jk_get_worker_recover_timeout(jk_map_t *m, const char *wname, int def)
+{
+    char buf[1024];
+
+    if (!m || !wname) {
+        return -1;
+    }
+
+    MAKE_WORKER_PARAM(WORKER_RECOVER_TIME);
+
+    return jk_map_get_int(m, buf, def);
+}
+
+int jk_get_worker_socket_buffer(jk_map_t *m, const char *wname, int def)
+{
+    char buf[1024];
+    int i;
+    if (!m || !wname) {
+        return -1;
+    }
+
+    MAKE_WORKER_PARAM(SOCKET_BUFFER_OF_WORKER);
+
+    i = jk_map_get_int(m, buf, 0);
+    if (i > 0 && i < def)
+        i = def;
+    return i;
+}
+
+int jk_get_worker_socket_keepalive(jk_map_t *m, const char *wname, int def)
+{
+    char buf[1024];
+
+    if (!m || !wname) {
+        return -1;
+    }
+
+    MAKE_WORKER_PARAM(SOCKET_KEEPALIVE_OF_WORKER);
+
+    return jk_map_get_bool(m, buf, def);
+}
+
+int jk_get_worker_cache_timeout(jk_map_t *m, const char *wname, int def)
+{
+    char buf[1024];
+    int rv;
+
+    if (!m || !wname) {
+        return -1;
+    }
+
+    MAKE_WORKER_PARAM(CACHE_TIMEOUT_OF_WORKER);
+    if ((rv = jk_map_get_int(m, buf, -1)) >= 0)
+        return rv;
+    MAKE_WORKER_PARAM(CACHE_TIMEOUT_DEPRECATED);
+
+    return jk_map_get_int(m, buf, def);
+}
+
+int jk_get_worker_connect_timeout(jk_map_t *m, const char *wname, int def)
+{
+    char buf[1024];
+
+    if (!m || !wname) {
+        return -1;
+    }
+
+    MAKE_WORKER_PARAM(CONNECT_TIMEOUT_OF_WORKER);
+
+    return jk_map_get_int(m, buf, def);
+}
+
+int jk_get_worker_prepost_timeout(jk_map_t *m, const char *wname, int def)
+{
+    char buf[1024];
+
+    if (!m || !wname) {
+        return -1;
+    }
+
+    MAKE_WORKER_PARAM(PREPOST_TIMEOUT_OF_WORKER);
+
+    return jk_map_get_int(m, buf, def);
+}
+
+int jk_get_worker_reply_timeout(jk_map_t *m, const char *wname, int def)
+{
+    char buf[1024];
+
+    if (!m || !wname) {
+        return -1;
+    }
+
+    MAKE_WORKER_PARAM(REPLY_TIMEOUT_OF_WORKER);
+
+    return jk_map_get_int(m, buf, def);
+}
+
+int jk_get_worker_recycle_timeout(jk_map_t *m, const char *wname, int def)
+{
+    return def;
+}
+
+int jk_get_worker_retries(jk_map_t *m, const char *wname, int def)
+{
+    char buf[1024];
+    int rv;
+    if (!m || !wname) {
+        return -1;
+    }
+
+    MAKE_WORKER_PARAM(RETRIES_OF_WORKER);
+
+    rv = jk_map_get_int(m, buf, def);
+    if (rv < 1)
+        rv = 1;
+
+    return rv;
+}
+
+int jk_get_worker_recovery_opts(jk_map_t *m, const char *wname, int def)
+{
+    char buf[1024];
+
+    if (!m || !wname) {
+        return -1;
+    }
+
+    MAKE_WORKER_PARAM(RECOVERY_OPTS_OF_WORKER);
+
+    return jk_map_get_int(m, buf, def);
+}
+
+const char *jk_get_worker_secret_key(jk_map_t *m, const char *wname)
+{
+    char buf[1024];
+
+    if (!m || !wname) {
+        return NULL;
+    }
+
+    MAKE_WORKER_PARAM(SECRET_KEY_OF_WORKER);
+    return jk_map_get_string(m, buf, NULL);
+}
+
+int jk_get_worker_list(jk_map_t *m, char ***list, unsigned *num_of_wokers)
+{
+    if (m && list && num_of_wokers) {
+        char **ar = jk_map_get_string_list(m,
+                                        WORKER_LIST_PROPERTY_NAME,
+                                        num_of_wokers,
+                                        DEFAULT_WORKER);
+        if (ar) {
+            *list = ar;
+            return JK_TRUE;
+        }
+        *list = NULL;
+        *num_of_wokers = 0;
+    }
+
+    return JK_FALSE;
+}
+
+int jk_get_is_worker_disabled(jk_map_t *m, const char *wname)
+{
+    int rc = JK_TRUE;
+    char buf[1024];
+    if (m && wname) {
+        int value;
+        MAKE_WORKER_PARAM(IS_WORKER_DISABLED_DEPRECATED);
+        value = jk_map_get_bool(m, buf, 0);
+        if (!value)
+            rc = JK_FALSE;
+    }
+    return rc;
+}
+
+int jk_get_is_worker_stopped(jk_map_t *m, const char *wname)
+{
+    int rc = JK_TRUE;
+    char buf[1024];
+    if (m && wname) {
+        int value;
+        MAKE_WORKER_PARAM(IS_WORKER_STOPPED_DEPRECATED);
+        value = jk_map_get_bool(m, buf, 0);
+        if (!value)
+            rc = JK_FALSE;
+    }
+    return rc;
+}
+
+int jk_get_worker_activation(jk_map_t *m, const char *wname)
+{
+    char buf[1024];
+    const char *v;
+    if (!m || !wname) {
+        return JK_LB_ACTIVATION_ACTIVE;
+    }
+
+    MAKE_WORKER_PARAM(ACTIVATION_OF_WORKER);
+    v = jk_map_get_string(m, buf, NULL);
+    if (v) {
+        if (*v == 'a' || *v == 'A')
+            return JK_LB_ACTIVATION_ACTIVE;
+        else if (*v == 's' || *v == 'S')
+            return JK_LB_ACTIVATION_STOPPED;
+        else if (*v == 'd' || *v == 'D')
+            return JK_LB_ACTIVATION_DISABLED;
+        else
+            return JK_LB_ACTIVATION_ACTIVE;
+    }
+    else if (jk_get_is_worker_stopped(m, wname))
+        return JK_LB_ACTIVATION_STOPPED;
+    else if (jk_get_is_worker_disabled(m, wname))
+        return JK_LB_ACTIVATION_DISABLED;
+    else
+        return JK_LB_ACTIVATION_ACTIVE;
+}
+
+void jk_set_log_format(const char *logformat)
+{
+    jk_log_fmt = (logformat) ? logformat : JK_TIME_FORMAT;
+}
+
+int jk_get_lb_factor(jk_map_t *m, const char *wname)
+{
+    char buf[1024];
+
+    if (!m || !wname) {
+        return DEFAULT_LB_FACTOR;
+    }
+
+    MAKE_WORKER_PARAM(LOAD_FACTOR_OF_WORKER);
+
+    return jk_map_get_int(m, buf, DEFAULT_LB_FACTOR);
+}
+
+int jk_get_distance(jk_map_t *m, const char *wname)
+{
+    char buf[1024];
+
+    if (!m || !wname) {
+        return DEFAULT_DISTANCE;
+    }
+
+    MAKE_WORKER_PARAM(DISTANCE_OF_WORKER);
+
+    return jk_map_get_int(m, buf, DEFAULT_DISTANCE);
+}
+
+int jk_get_is_sticky_session(jk_map_t *m, const char *wname)
+{
+    int rc = JK_TRUE;
+    char buf[1024];
+    if (m && wname) {
+        int value;
+        MAKE_WORKER_PARAM(STICKY_SESSION);
+        value = jk_map_get_bool(m, buf, 1);
+        if (!value)
+            rc = JK_FALSE;
+    }
+    return rc;
+}
+
+int jk_get_is_sticky_session_force(jk_map_t *m, const char *wname)
+{
+    int rc = JK_FALSE;
+    char buf[1024];
+    if (m && wname) {
+        int value;
+        MAKE_WORKER_PARAM(STICKY_SESSION_FORCE);
+        value = jk_map_get_bool(m, buf, 0);
+        if (value)
+            rc = JK_TRUE;
+    }
+    return rc;
+}
+
+int jk_get_lb_method(jk_map_t *m, const char *wname)
+{
+    char buf[1024];
+    const char *v;
+    if (!m || !wname) {
+        return JK_LB_METHOD_DEF;
+    }
+
+    MAKE_WORKER_PARAM(METHOD_OF_WORKER);
+    v = jk_map_get_string(m, buf, NULL);
+    if (!v)
+        return JK_LB_METHOD_DEF;
+    else if  (*v == 't' || *v == 'T' || *v == '1')
+        return JK_LB_METHOD_TRAFFIC;
+    else if  (*v == 'r' || *v == 'R' || *v == '0')
+        return JK_LB_METHOD_REQUESTS;
+    else if  (*v == 'b' || *v == 'B' || *v == '2')
+        return JK_LB_METHOD_BUSYNESS;
+    else
+        return JK_LB_METHOD_DEF;
+}
+
+int jk_get_lb_lock(jk_map_t *m, const char *wname)
+{
+    char buf[1024];
+    const char *v;
+    if (!m || !wname) {
+        return JK_LB_LOCK_DEF;
+    }
+
+    MAKE_WORKER_PARAM(LOCK_OF_WORKER);
+    v = jk_map_get_string(m, buf, NULL);
+    if (!v)
+        return JK_LB_LOCK_DEF;
+    else if  (*v == 'o' || *v == 'O' || *v == '0')
+        return JK_LB_LOCK_OPTIMISTIC;
+    else if  (*v == 'p' || *v == 'P' || *v == '1')
+        return JK_LB_LOCK_PESSIMISTIC;
+    else
+        return JK_LB_LOCK_DEF;
+}
+
+int jk_get_max_packet_size(jk_map_t *m, const char *wname)
+{
+    char buf[1024];
+    int sz;
+
+    if (!m || !wname) {
+        return DEF_BUFFER_SZ;
+    }
+
+    MAKE_WORKER_PARAM(DISTANCE_OF_WORKER);
+    sz = jk_map_get_int(m, buf, DEF_BUFFER_SZ);
+    sz = JK_ALIGN(sz, 1024);
+    if (sz < DEF_BUFFER_SZ)
+        sz = DEF_BUFFER_SZ;
+    else if (sz > 64*1024)
+        sz = 64*1024;
+    
+    return sz;
+}
+
+int jk_get_lb_worker_list(jk_map_t *m,
+                          const char *wname,
+                          char ***list, unsigned int *num_of_wokers)
+{
+    char buf[1024];
+
+    if (m && list && num_of_wokers && wname) {
+        char **ar = NULL;
+
+        MAKE_WORKER_PARAM(BALANCE_WORKERS);
+        ar = jk_map_get_string_list(m, buf, num_of_wokers, NULL);
+        if (ar) {
+            *list = ar;
+            return JK_TRUE;
+        }
+        /* Try old balanced_workers directive */
+        MAKE_WORKER_PARAM(BALANCED_WORKERS_DEPRECATED);
+        ar = jk_map_get_string_list(m, buf, num_of_wokers, NULL);
+        if (ar) {
+            *list = ar;
+            return JK_TRUE;
+        }
+        *list = NULL;
+        *num_of_wokers = 0;
+    }
+
+    return JK_FALSE;
+}
+
+int jk_get_worker_mount_list(jk_map_t *m,
+                             const char *wname,
+                             char ***list, unsigned int *num_of_maps)
+{
+    char buf[1024];
+
+    if (m && list && num_of_maps && wname) {
+        char **ar = NULL;
+
+        MAKE_WORKER_PARAM(MOUNT_OF_WORKER);
+        ar = jk_map_get_string_list(m, buf, num_of_maps, NULL);
+        if (ar) {
+            *list = ar;
+            return JK_TRUE;
+        }
+        *list = NULL;
+        *num_of_maps = 0;
+    }
+
+    return JK_FALSE;
+}
+
+int jk_get_worker_maintain_time(jk_map_t *m)
+{
+    return jk_map_get_int(m, WORKER_MAINTAIN_PROPERTY_NAME,
+                          DEFAULT_MAINTAIN_TIME);
+}
+
+int jk_get_worker_mx(jk_map_t *m, const char *wname, unsigned *mx)
+{
+    char buf[1024];
+
+    if (m && mx && wname) {
+        int i;
+        MAKE_WORKER_PARAM(MX_OF_WORKER);
+
+        i = jk_map_get_int(m, buf, -1);
+        if (-1 != i) {
+            *mx = (unsigned)i;
+            return JK_TRUE;
+        }
+    }
+
+    return JK_FALSE;
+}
+
+int jk_get_worker_ms(jk_map_t *m, const char *wname, unsigned *ms)
+{
+    char buf[1024];
+
+    if (m && ms && wname) {
+        int i;
+        MAKE_WORKER_PARAM(MS_OF_WORKER);
+
+        i = jk_map_get_int(m, buf, -1);
+        if (-1 != i) {
+            *ms = (unsigned)i;
+            return JK_TRUE;
+        }
+    }
+
+    return JK_FALSE;
+}
+
+int jk_get_worker_classpath(jk_map_t *m, const char *wname, const char **cp)
+{
+    char buf[1024];
+
+    if (m && cp && wname) {
+        MAKE_WORKER_PARAM(CP_OF_WORKER);
+
+        *cp = jk_map_get_string(m, buf, NULL);
+        if (*cp) {
+            return JK_TRUE;
+        }
+    }
+
+    return JK_FALSE;
+}
+
+int jk_get_worker_bridge_type(jk_map_t *m, const char *wname, unsigned *bt)
+{
+    char buf[1024];
+    const char *type;
+
+    if (m && bt && wname) {
+        MAKE_WORKER_PARAM(BRIDGE_OF_WORKER);
+
+        type = jk_map_get_string(m, buf, NULL);
+
+        if (type) {
+            if (!strcasecmp(type, TOMCAT32_BRIDGE_NAME))
+                *bt = TC32_BRIDGE_TYPE;
+            else if (!strcasecmp(type, TOMCAT33_BRIDGE_NAME))
+                *bt = TC33_BRIDGE_TYPE;
+            else if (!strcasecmp(type, TOMCAT40_BRIDGE_NAME))
+                *bt = TC40_BRIDGE_TYPE;
+            else if (!strcasecmp(type, TOMCAT41_BRIDGE_NAME))
+                *bt = TC41_BRIDGE_TYPE;
+            else if (!strcasecmp(type, TOMCAT50_BRIDGE_NAME))
+                *bt = TC50_BRIDGE_TYPE;
+
+            return JK_TRUE;
+        }
+    }
+
+    return JK_FALSE;
+}
+
+int jk_get_worker_jvm_path(jk_map_t *m, const char *wname, const char **vm_path)
+{
+    char buf[1024];
+
+    if (m && vm_path && wname) {
+        MAKE_WORKER_PARAM(JVM_OF_WORKER);
+
+        *vm_path = jk_map_get_string(m, buf, NULL);
+        if (*vm_path) {
+            return JK_TRUE;
+        }
+    }
+
+    return JK_FALSE;
+}
+
+/* [V] This is unused. currently. */
+int jk_get_worker_callback_dll(jk_map_t *m, const char *wname, const char **cb_path)
+{
+    char buf[1024];
+
+    if (m && cb_path && wname) {
+        MAKE_WORKER_PARAM(NATIVE_LIB_OF_WORKER);
+
+        *cb_path = jk_map_get_string(m, buf, NULL);
+        if (*cb_path) {
+            return JK_TRUE;
+        }
+    }
+
+    return JK_FALSE;
+}
+
+int jk_get_worker_cmd_line(jk_map_t *m, const char *wname, const char **cmd_line)
+{
+    char buf[1024];
+
+    if (m && cmd_line && wname) {
+        MAKE_WORKER_PARAM(CMD_LINE_OF_WORKER);
+
+        *cmd_line = jk_map_get_string(m, buf, NULL);
+        if (*cmd_line) {
+            return JK_TRUE;
+        }
+    }
+
+    return JK_FALSE;
+}
+
+
+int jk_file_exists(const char *f)
+{
+    if (f) {
+        struct stat st;
+#ifdef AS400
+        if ((0 == stat(f, &st)) && (st.st_mode & _S_IFREG)) {
+#else
+        if ((0 == stat(f, &st)) && (st.st_mode & S_IFREG)) {
+#endif
+            return JK_TRUE;
+        }
+    }
+    return JK_FALSE;
+}
+
+static int jk_is_some_property(const char *prp_name, const char *suffix, const char *sep)
+{
+    char buf[1024];
+
+    if (prp_name && suffix) {
+        size_t prp_name_len;
+        size_t suffix_len;
+        strcpy(buf, sep);
+        strcat(buf, suffix);
+        prp_name_len = strlen(prp_name);
+        suffix_len = strlen(buf);
+        if (prp_name_len >= suffix_len) {
+            const char *prp_suffix = prp_name + prp_name_len - suffix_len;
+            if (0 == strcmp(buf, prp_suffix)) {
+                return JK_TRUE;
+            }
+        }
+    }
+
+    return JK_FALSE;
+}
+
+int jk_is_path_property(const char *prp_name)
+{
+    return jk_is_some_property(prp_name, "path", "_");
+}
+
+int jk_is_cmd_line_property(const char *prp_name)
+{
+    return jk_is_some_property(prp_name, CMD_LINE_OF_WORKER, ".");
+}
+
+int jk_is_list_property(const char *prp_name)
+{
+    const char **props = &list_properties[0];
+    while (*props) {
+        if (jk_is_some_property(prp_name, *props, "."))
+            return JK_TRUE;
+        props++;
+    }
+    return JK_FALSE;
+}
+
+int jk_is_unique_property(const char *prp_name)
+{
+    const char **props = &unique_properties[0];
+    while (*props) {
+        if (jk_is_some_property(prp_name, *props, "."))
+            return JK_TRUE;
+        props++;
+    }
+    return JK_FALSE;
+}
+
+int jk_is_deprecated_property(const char *prp_name)
+{
+    const char **props = &deprecated_properties[0];
+    while (*props) {
+        if (jk_is_some_property(prp_name, *props, "."))
+            return JK_TRUE;
+        props++;
+    }
+    return JK_FALSE;
+}
+
+int jk_get_worker_stdout(jk_map_t *m, const char *wname, const char **stdout_name)
+{
+    char buf[1024];
+
+    if (m && stdout_name && wname) {
+        MAKE_WORKER_PARAM(STDOUT_OF_WORKER);
+
+        *stdout_name = jk_map_get_string(m, buf, NULL);
+        if (*stdout_name) {
+            return JK_TRUE;
+        }
+    }
+
+    return JK_FALSE;
+}
+
+int jk_get_worker_stderr(jk_map_t *m, const char *wname, const char **stderr_name)
+{
+    char buf[1024];
+
+    if (m && stderr_name && wname) {
+        MAKE_WORKER_PARAM(STDERR_OF_WORKER);
+
+        *stderr_name = jk_map_get_string(m, buf, NULL);
+        if (*stderr_name) {
+            return JK_TRUE;
+        }
+    }
+
+    return JK_FALSE;
+}
+
+int jk_get_worker_sysprops(jk_map_t *m, const char *wname, const char **sysprops)
+{
+    char buf[1024];
+
+    if (m && sysprops && wname) {
+        MAKE_WORKER_PARAM(SYSPROPS_OF_WORKER);
+
+        *sysprops = jk_map_get_string(m, buf, NULL);
+        if (*sysprops) {
+            return JK_TRUE;
+        }
+    }
+
+    return JK_FALSE;
+}
+
+int jk_get_worker_libpath(jk_map_t *m, const char *wname, const char **libpath)
+{
+    char buf[1024];
+
+    if (m && libpath && wname) {
+        MAKE_WORKER_PARAM(LIBPATH_OF_WORKER);
+
+        *libpath = jk_map_get_string(m, buf, NULL);
+        if (*libpath) {
+            return JK_TRUE;
+        }
+    }
+
+    return JK_FALSE;
+}
+
+char **jk_parse_sysprops(jk_pool_t *p, const char *sysprops)
+{
+    char **rc = NULL;
+#if defined(AS400) || defined(_REENTRANT)
+    char *lasts;
+#endif
+
+    if (p && sysprops) {
+        char *prps = jk_pool_strdup(p, sysprops);
+        if (prps && strlen(prps)) {
+            unsigned num_of_prps;
+
+            for (num_of_prps = 1; *sysprops; sysprops++) {
+                if ('*' == *sysprops) {
+                    num_of_prps++;
+                }
+            }
+
+            rc = jk_pool_alloc(p, (num_of_prps + 1) * sizeof(char *));
+            if (rc) {
+                unsigned i = 0;
+#if defined(AS400) || defined(_REENTRANT)
+                char *tmp = strtok_r(prps, "*", &lasts);
+#else
+                char *tmp = strtok(prps, "*");
+#endif
+
+                while (tmp && i < num_of_prps) {
+                    rc[i] = tmp;
+#if defined(AS400) || defined(_REENTRANT)
+                    tmp = strtok_r(NULL, "*", &lasts);
+#else
+                    tmp = strtok(NULL, "*");
+#endif
+                    i++;
+                }
+                rc[i] = NULL;
+            }
+        }
+    }
+
+    return rc;
+}
+
+void jk_append_libpath(jk_pool_t *p, const char *libpath)
+{
+    char *env = NULL;
+    char *current = getenv(PATH_ENV_VARIABLE);
+
+    if (current) {
+        env = jk_pool_alloc(p, strlen(PATH_ENV_VARIABLE) +
+                            strlen(current) + strlen(libpath) + 5);
+        if (env) {
+            sprintf(env, "%s=%s%c%s",
+                    PATH_ENV_VARIABLE, libpath, PATH_SEPERATOR, current);
+        }
+    }
+    else {
+        env = jk_pool_alloc(p, strlen(PATH_ENV_VARIABLE) +
+                            strlen(libpath) + 5);
+        if (env) {
+            sprintf(env, "%s=%s", PATH_ENV_VARIABLE, libpath);
+        }
+    }
+
+    if (env) {
+        putenv(env);
+    }
+}
+
+void jk_init_ws_service(jk_ws_service_t *s)
+{
+    s->ws_private = NULL;
+    s->pool = NULL;
+    s->method = NULL;
+    s->protocol = NULL;
+    s->req_uri = NULL;
+    s->remote_addr = NULL;
+    s->remote_host = NULL;
+    s->remote_user = NULL;
+    s->auth_type = NULL;
+    s->query_string = NULL;
+    s->server_name = NULL;
+    s->server_port = 80;
+    s->server_software = NULL;
+    s->content_length = 0;
+    s->is_chunked = 0;
+    s->no_more_chunks = 0;
+    s->content_read = 0;
+    s->is_ssl = JK_FALSE;
+    s->ssl_cert = NULL;
+    s->ssl_cert_len = 0;
+    s->ssl_cipher = NULL;
+    s->ssl_session = NULL;
+    s->headers_names = NULL;
+    s->headers_values = NULL;
+    s->num_headers = 0;
+    s->attributes_names = NULL;
+    s->attributes_values = NULL;
+    s->num_attributes = 0;
+    s->jvm_route = NULL;
+    s->retries = JK_RETRIES;
+    s->add_log_items = NULL;
+}
+
+#ifdef _MT_CODE_PTHREAD
+int jk_gettid()
+{
+    pthread_t t = pthread_self();
+#ifdef AS400
+    /* OS400 use 64 bits ThreadId, get only low 32 bits for now */
+    pthread_id_np_t       tid;
+    pthread_getunique_np(&t, &tid);
+    return ((int)(tid.intId.lo & 0xFFFFFFFF));
+#else
+    int tid = (int)(t & 0xFFFF);
+    return tid;
+#endif /* AS400 */
+}
+#endif

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_util.h
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_util.h	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_util.h	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,188 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.
+ */
+
+/***************************************************************************
+ * Description: Various utility functions                                  *
+ * Author:      Gal Shachor <shachor at il.ibm.com>                           *
+ * Author:      Henri Gomez <hgomez at apache.org>                            *
+ * Author:      Rainer Jung <rjung at apache.org>                             *
+ * Version:     $Revision: 439824 $                                          *
+ ***************************************************************************/
+#ifndef _JK_UTIL_H
+#define _JK_UTIL_H
+
+#include "jk_global.h"
+#include "jk_logger.h"
+#include "jk_map.h"
+#include "jk_pool.h"
+#include "jk_service.h"
+
+#define JK_SLEEP_DEF     (100)
+
+void jk_sleep(int ms);
+
+int jk_parse_log_level(const char *level);
+
+int jk_open_file_logger(jk_logger_t **l, const char *file, int level);
+
+int jk_close_file_logger(jk_logger_t **l);
+
+int jk_log(jk_logger_t *l,
+           const char *file, int line, const char *funcname, int level,
+           const char *fmt, ...);
+
+/* [V] Two general purpose functions. Should ease the function bloat. */
+int jk_get_worker_str_prop(jk_map_t *m,
+                           const char *wname, const char *pname, const char **prop);
+
+int jk_get_worker_int_prop(jk_map_t *m,
+                           const char *wname, const char *pname, int *prop);
+
+const char *jk_get_worker_host(jk_map_t *m, const char *wname, const char *def);
+
+const char *jk_get_worker_type(jk_map_t *m, const char *wname);
+
+int jk_get_worker_port(jk_map_t *m, const char *wname, int def);
+
+int jk_get_worker_cache_size(jk_map_t *m, const char *wname, int def);
+
+int jk_get_worker_cache_size_min(jk_map_t *m, const char *wname, int def);
+
+int jk_get_worker_socket_timeout(jk_map_t *m, const char *wname, int def);
+
+int jk_get_worker_socket_buffer(jk_map_t *m, const char *wname, int def);
+
+int jk_get_worker_socket_keepalive(jk_map_t *m, const char *wname, int def);
+
+int jk_get_worker_cache_timeout(jk_map_t *m, const char *wname, int def);
+
+int jk_get_worker_recovery_opts(jk_map_t *m, const char *wname, int def);
+
+int jk_get_worker_connect_timeout(jk_map_t *m, const char *wname, int def);
+
+int jk_get_worker_reply_timeout(jk_map_t *m, const char *wname, int def);
+
+int jk_get_worker_prepost_timeout(jk_map_t *m, const char *wname, int def);
+
+int jk_get_worker_recycle_timeout(jk_map_t *m, const char *wname, int def);
+
+int jk_get_worker_recover_timeout(jk_map_t *m, const char *wname, int def);
+
+const char *jk_get_worker_jvm_route(jk_map_t *m, const char *wname, const char *def);
+
+const char *jk_get_worker_domain(jk_map_t *m, const char *wname, const char *def);
+
+const char *jk_get_worker_redirect(jk_map_t *m, const char *wname, const char *def);
+
+const char *jk_get_worker_secret_key(jk_map_t *m, const char *wname);
+
+int jk_get_worker_retries(jk_map_t *m, const char *wname, int def);
+
+int jk_get_is_worker_disabled(jk_map_t *m, const char *wname);
+
+int jk_get_is_worker_stopped(jk_map_t *m, const char *wname);
+
+int jk_get_worker_activation(jk_map_t *m, const char *wname);
+
+void jk_set_log_format(const char *logformat);
+
+int jk_get_worker_list(jk_map_t *m, char ***list, unsigned *num_of_wokers);
+
+int jk_get_lb_factor(jk_map_t *m, const char *wname);
+
+int jk_get_distance(jk_map_t *m, const char *wname);
+
+int jk_get_is_sticky_session(jk_map_t *m, const char *wname);
+
+int jk_get_is_sticky_session_force(jk_map_t *m, const char *wname);
+
+int jk_get_lb_method(jk_map_t *m, const char *wname);
+
+int jk_get_lb_lock(jk_map_t *m, const char *wname);
+
+int jk_get_lb_worker_list(jk_map_t *m,
+                          const char *lb_wname,
+                          char ***list, unsigned int *num_of_wokers);
+int jk_get_worker_mount_list(jk_map_t *m,
+                             const char *wname,
+                             char ***list, unsigned int *num_of_maps);
+const char *jk_get_worker_secret(jk_map_t *m, const char *wname);
+
+int jk_get_worker_mx(jk_map_t *m, const char *wname, unsigned *mx);
+
+int jk_get_worker_ms(jk_map_t *m, const char *wname, unsigned *ms);
+
+int jk_get_worker_classpath(jk_map_t *m, const char *wname, const char **cp);
+
+
+int jk_get_worker_bridge_type(jk_map_t *m, const char *wname, unsigned *bt);
+
+int jk_get_worker_jvm_path(jk_map_t *m, const char *wname, const char **vm_path);
+
+int jk_get_worker_callback_dll(jk_map_t *m,
+                               const char *wname, const char **cb_path);
+
+int jk_get_worker_cmd_line(jk_map_t *m, const char *wname, const char **cmd_line);
+
+int jk_file_exists(const char *f);
+
+int jk_is_list_property(const char *prp_name);
+
+int jk_is_path_property(const char *prp_name);
+
+int jk_is_cmd_line_property(const char *prp_name);
+
+int jk_is_unique_property(const char *prp_name);
+
+int jk_is_deprecated_property(const char *prp_name);
+
+int jk_get_worker_stdout(jk_map_t *m, const char *wname, const char **stdout_name);
+
+int jk_get_worker_stderr(jk_map_t *m, const char *wname, const char **stderr_name);
+
+int jk_get_worker_sysprops(jk_map_t *m, const char *wname, const char **sysprops);
+
+int jk_get_worker_libpath(jk_map_t *m, const char *wname, const char **libpath);
+
+char **jk_parse_sysprops(jk_pool_t *p, const char *sysprops);
+
+
+void jk_append_libpath(jk_pool_t *p, const char *libpath);
+
+void jk_set_worker_def_cache_size(int sz);
+
+int jk_get_worker_def_cache_size(int protocol);
+
+int jk_get_worker_maintain_time(jk_map_t *m);
+
+int jk_get_max_packet_size(jk_map_t *m, const char *wname);
+
+#define TC32_BRIDGE_TYPE    32
+#define TC33_BRIDGE_TYPE    33
+#define TC40_BRIDGE_TYPE    40
+#define TC41_BRIDGE_TYPE    41
+#define TC50_BRIDGE_TYPE    50
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif                          /* __cplusplus */
+
+
+#ifdef __cplusplus
+}
+#endif                          /* __cplusplus */
+#endif                          /* _JK_UTIL_H */

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_version.h
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_version.h	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_version.h	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,71 @@
+/*
+ *  Copyright 1999-2005 The Apache Software Foundation
+ *
+ *  Licensed 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.
+ */
+
+/***************************************************************************
+ * Description: JK version header file                                     *
+ * Version:     $Revision: 424104 $                                           *
+ ***************************************************************************/
+
+#ifndef __JK_VERSION_H
+#define __JK_VERSION_H
+
+/************** START OF AREA TO MODIFY BEFORE RELEASING *************/
+#define JK_VERMAJOR     1
+#define JK_VERMINOR     2
+#define JK_VERFIX       19
+#define JK_VERSTRING    "1.2.19"
+
+/* Beta number */
+#define JK_VERBETA      0
+#define JK_BETASTRING   "0"
+/* set JK_VERISRELEASE to 1 when release (do not forget to commit!) */
+#define JK_VERISRELEASE 0
+#define JK_VERRC        0
+#define JK_RCSTRING     "0"
+
+/************** END OF AREA TO MODIFY BEFORE RELEASING *************/
+
+#if !defined(PACKAGE)
+#define PACKAGE "mod_jk"
+#endif
+
+/* Build JK_EXPOSED_VERSION and JK_VERSION */
+#define JK_EXPOSED_VERSION_INT PACKAGE "/" JK_VERSTRING
+
+#if ( JK_VERISRELEASE == 1 )
+#define JK_RELEASE_STR  JK_EXPOSED_VERSION_INT
+#else
+#define JK_RELEASE_STR  JK_EXPOSED_VERSION_INT "-dev"
+#endif
+
+#if ( JK_VERBETA == 0 )
+#define JK_EXPOSED_VERSION JK_RELEASE_STR
+#undef JK_VERBETA
+#define JK_VERBETA 255
+#else
+#define JK_EXPOSED_VERSION JK_RELEASE_STR "-beta-" JK_BETASTRING
+#endif
+
+#if (JK_VERRC != 0)
+#undef JK_EXPOSED_VERSION
+#define JK_EXPOSED_VERSION JK_RELEASE_STR "-rc-" JK_RCSTRING
+#endif
+
+#define JK_MAKEVERSION(major, minor, fix, beta) (((major) << 24) + ((minor) << 16) + ((fix) << 8) + (beta))
+
+#define JK_VERSION JK_MAKEVERSION(JK_VERMAJOR, JK_VERMINOR, JK_VERFIX, JK_VERBETA)
+
+#endif /* __JK_VERSION_H */

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_worker.c
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_worker.c	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_worker.c	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,330 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.
+ */
+
+/***************************************************************************
+ * Description: Workers controller                                         *
+ * Author:      Gal Shachor <shachor at il.ibm.com>                           *
+ * Author:      Henri Gomez <hgomez at apache.org>                            *
+ * Version:     $Revision: 434119 $                                          *
+ ***************************************************************************/
+
+#define _PLACE_WORKER_LIST_HERE
+#include "jk_worker_list.h"
+#include "jk_worker.h"
+#include "jk_util.h"
+#include "jk_mt.h"
+
+static void close_workers(jk_logger_t *l);
+
+static worker_factory get_factory_for(const char *type);
+
+static int build_worker_map(jk_map_t *init_data,
+                            char **worker_list,
+                            unsigned num_of_workers,
+                            jk_worker_env_t *we, jk_logger_t *l);
+
+/* Global worker list */
+static jk_map_t *worker_map;
+#if _MT_CODE
+static JK_CRIT_SEC worker_lock;
+#endif
+static int worker_maintain_time = 0;
+
+int wc_open(jk_map_t *init_data, jk_worker_env_t *we, jk_logger_t *l)
+{
+    int rc;
+    JK_TRACE_ENTER(l);
+
+    if (!jk_map_alloc(&worker_map)) {
+        JK_TRACE_EXIT(l);
+        return JK_FALSE;
+    }
+    JK_INIT_CS(&worker_lock, rc);
+    if (rc == JK_FALSE) {
+        jk_log(l, JK_LOG_ERROR,
+                "creating thread lock errno=%d",
+                errno);
+        JK_TRACE_EXIT(l);
+        return JK_FALSE;
+    }
+
+    if (!jk_get_worker_list(init_data, &(we->worker_list),
+                            &we->num_of_workers)) {
+        JK_TRACE_EXIT(l);
+        we->num_of_workers = 0;
+        we->worker_list = NULL;
+        return JK_FALSE;
+    }
+
+    worker_maintain_time = jk_get_worker_maintain_time(init_data);
+
+    if (!build_worker_map(init_data, we->worker_list,
+                          we->num_of_workers, we, l)) {
+        close_workers(l);
+        we->num_of_workers = 0;
+        we->worker_list = NULL;
+        JK_TRACE_EXIT(l);
+        return JK_FALSE;
+    }
+
+    JK_TRACE_EXIT(l);
+    return JK_TRUE;
+}
+
+
+void wc_close(jk_logger_t *l)
+{
+    int rc;
+    JK_TRACE_ENTER(l);
+    JK_DELETE_CS(&worker_lock, rc);
+    close_workers(l);
+    JK_TRACE_EXIT(l);
+}
+
+jk_worker_t *wc_get_worker_for_name(const char *name, jk_logger_t *l)
+{
+    jk_worker_t *rc;
+
+    JK_TRACE_ENTER(l);
+    if (!name) {
+        JK_LOG_NULL_PARAMS(l);
+        JK_TRACE_EXIT(l);
+        return NULL;
+    }
+
+    rc = jk_map_get(worker_map, name, NULL);
+
+    if (JK_IS_DEBUG_LEVEL(l))
+        jk_log(l, JK_LOG_DEBUG, "%s a worker %s",
+               rc ? "found" : "did not find", name);
+    JK_TRACE_EXIT(l);
+    return rc;
+}
+
+int wc_create_worker(const char *name, int use_map,
+                     jk_map_t *init_data,
+                     jk_worker_t **rc, jk_worker_env_t *we, jk_logger_t *l)
+{
+    JK_TRACE_ENTER(l);
+
+    if (rc) {
+        const char *type = jk_get_worker_type(init_data, name);
+        worker_factory fac = get_factory_for(type);
+        jk_worker_t *w = NULL;
+        unsigned int i, num_of_maps;
+        char **map_names;
+        int wtype;
+
+        *rc = NULL;
+
+        if (!fac) {
+            jk_log(l, JK_LOG_ERROR, "Unknown worker type %s for worker %s",
+                   type, name);
+            JK_TRACE_EXIT(l);
+            return JK_FALSE;
+        }
+
+        if (JK_IS_DEBUG_LEVEL(l))
+            jk_log(l, JK_LOG_DEBUG,
+                   "about to create instance %s of %s", name,
+                   type);
+
+        if (((wtype = fac(&w, name, l)) == 0) || !w) {
+            jk_log(l, JK_LOG_ERROR,
+                   "factory for %s failed for %s", type,
+                   name);
+            JK_TRACE_EXIT(l);
+            return JK_FALSE;
+        }
+
+        if (JK_IS_DEBUG_LEVEL(l))
+            jk_log(l, JK_LOG_DEBUG,
+                   "about to validate and init %s", name);
+        if (!w->validate(w, init_data, we, l)) {
+            w->destroy(&w, l);
+            jk_log(l, JK_LOG_ERROR,
+                   "validate failed for %s", name);
+            JK_TRACE_EXIT(l);
+            return JK_FALSE;
+        }
+
+        if (!w->init(w, init_data, we, l)) {
+            w->destroy(&w, l);
+            jk_log(l, JK_LOG_ERROR, "init failed for %s",
+                   name);
+            JK_TRACE_EXIT(l);
+            return JK_FALSE;
+        }
+        if (use_map &&
+            jk_get_worker_mount_list(init_data, name,
+                                     &map_names,
+                                     &num_of_maps) && num_of_maps) {
+            for (i = 0; i < num_of_maps; i++) {
+                if (JK_IS_DEBUG_LEVEL(l))
+                    jk_log(l, JK_LOG_DEBUG,
+                            "mounting %s to worker %s",
+                            map_names[i], name);
+                if (uri_worker_map_add(we->uri_to_worker, map_names[i],
+                                       name, l) == JK_FALSE) {
+                    w->destroy(&w, l);
+                    jk_log(l, JK_LOG_ERROR,
+                           "validate failed for %s", name);
+                    JK_TRACE_EXIT(l);
+                    return JK_FALSE;
+                }
+            }
+        }
+        w->type = wtype;
+        *rc = w;
+        JK_TRACE_EXIT(l);
+        return JK_TRUE;
+    }
+
+    JK_LOG_NULL_PARAMS(l);
+    return JK_FALSE;
+}
+
+static void close_workers(jk_logger_t *l)
+{
+    int sz = jk_map_size(worker_map);
+
+    JK_TRACE_ENTER(l);
+
+    if (sz > 0) {
+        int i;
+        for (i = 0; i < sz; i++) {
+            jk_worker_t *w = jk_map_value_at(worker_map, i);
+            if (w) {
+                if (JK_IS_DEBUG_LEVEL(l))
+                    jk_log(l, JK_LOG_DEBUG,
+                           "close_workers will destroy worker %s",
+                           jk_map_name_at(worker_map, i));
+                w->destroy(&w, l);
+            }
+        }
+    }
+    jk_map_free(&worker_map);
+    JK_TRACE_EXIT(l);
+}
+
+static int build_worker_map(jk_map_t *init_data,
+                            char **worker_list,
+                            unsigned num_of_workers,
+                            jk_worker_env_t *we, jk_logger_t *l)
+{
+    unsigned i;
+
+    JK_TRACE_ENTER(l);
+
+    for (i = 0; i < num_of_workers; i++) {
+        jk_worker_t *w = NULL;
+
+        if (JK_IS_DEBUG_LEVEL(l))
+            jk_log(l, JK_LOG_DEBUG,
+                   "creating worker %s", worker_list[i]);
+
+        if (wc_create_worker(worker_list[i], 1, init_data, &w, we, l)) {
+            jk_worker_t *oldw = NULL;
+            if (!jk_map_put(worker_map, worker_list[i], w, (void *)&oldw)) {
+                w->destroy(&w, l);
+                JK_TRACE_EXIT(l);
+                return JK_FALSE;
+            }
+
+            if (oldw) {
+                if (JK_IS_DEBUG_LEVEL(l))
+                    jk_log(l, JK_LOG_DEBUG,
+                           "removing old %s worker",
+                           worker_list[i]);
+                oldw->destroy(&oldw, l);
+            }
+        }
+        else {
+            jk_log(l, JK_LOG_ERROR,
+                   "failed to create worker %s",
+                   worker_list[i]);
+            JK_TRACE_EXIT(l);
+            return JK_FALSE;
+        }
+    }
+
+    JK_TRACE_EXIT(l);
+    return JK_TRUE;
+}
+
+static worker_factory get_factory_for(const char *type)
+{
+    worker_factory_record_t *factory = &worker_factories[0];
+    while (factory->name) {
+        if (0 == strcmp(factory->name, type)) {
+            return factory->fac;
+        }
+
+        factory++;
+    }
+
+    return NULL;
+}
+
+const char *wc_get_name_for_type(int type, jk_logger_t *l)
+{
+    worker_factory_record_t *factory = &worker_factories[0];
+    while (factory->name) {
+        if (type == factory->type) {
+            jk_log(l, JK_LOG_DEBUG,
+                   "Found worker type '%s'",
+                   factory->name);
+            return factory->name;
+        }
+
+        factory++;
+    }
+
+    return NULL;
+}
+
+void wc_maintain(jk_logger_t *l)
+{
+    static time_t last_maintain = 0;
+    int sz = jk_map_size(worker_map);
+
+    JK_TRACE_ENTER(l);
+
+    if (sz > 0 && worker_maintain_time > 0) {
+        int i;
+        time_t now;
+        JK_ENTER_CS(&worker_lock, i);
+        now = time(NULL);
+        if (difftime(now, last_maintain) >= worker_maintain_time) {
+            last_maintain = now;
+            JK_LEAVE_CS(&worker_lock, i);
+            for (i = 0; i < sz; i++) {
+                jk_worker_t *w = jk_map_value_at(worker_map, i);
+                if (w && w->maintain) {
+                    if (JK_IS_DEBUG_LEVEL(l))
+                        jk_log(l, JK_LOG_DEBUG,
+                               "Maintaining worker %s",
+                               jk_map_name_at(worker_map, i));
+                    w->maintain(w, now, l);
+                }
+            }
+        }
+        else {
+            JK_LEAVE_CS(&worker_lock, i);
+        }
+    }
+    JK_TRACE_EXIT(l);
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_worker.h
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_worker.h	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_worker.h	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,54 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.
+ */
+
+/***************************************************************************
+ * Description: Workers controller header file                             *
+ * Author:      Gal Shachor <shachor at il.ibm.com>                           *
+ * Version:     $Revision: 434119 $                                           *
+ ***************************************************************************/
+
+#ifndef JK_WORKER_H
+#define JK_WORKER_H
+
+#include "jk_logger.h"
+#include "jk_service.h"
+#include "jk_map.h"
+#include "jk_uri_worker_map.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif                          /* __cplusplus */
+
+int wc_open(jk_map_t *init_data, jk_worker_env_t *we, jk_logger_t *l);
+
+void wc_close(jk_logger_t *l);
+
+jk_worker_t *wc_get_worker_for_name(const char *name, jk_logger_t *l);
+
+const char *wc_get_name_for_type(int type, jk_logger_t *l);
+
+int wc_create_worker(const char *name, int use_map,
+                     jk_map_t *init_data,
+                     jk_worker_t **rc,
+                     jk_worker_env_t *we, jk_logger_t *l);
+
+void wc_maintain(jk_logger_t *l);
+
+#ifdef __cplusplus
+}
+#endif                          /* __cplusplus */
+#endif                          /* JK_WORKER_H */

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_worker_list.h
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_worker_list.h	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/jk_worker_list.h	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,97 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.
+ */
+
+/***************************************************************************
+ * Description: Worker list                                                *
+ * Author:      Gal Shachor <shachor at il.ibm.com>                           *
+ * Author:      Henri Gomez <hgomez at apache.org>                            *
+ * Version:     $Revision: 300224 $                                           *
+ ***************************************************************************/
+
+/*
+ * This file includes a list of all the possible workers in the jk library
+ * plus their factories. 
+ *
+ * If you want to add a worker just place it in the worker_factories array
+ * with its unique name and factory.
+ *
+ * If you want to remove a worker, hjust comment out its line in the 
+ * worker_factories array as well as its header file. For example, look
+ * at what we have done to the ajp23 worker.
+ *
+ * Note: This file should be included only in the jk_worker controller.
+ * Currently the jk_worker controller is located in jk_worker.c
+ */
+#ifdef _PLACE_WORKER_LIST_HERE
+#ifndef _JK_WORKER_LIST_H
+#define _JK_WORKER_LIST_H
+
+#include "jk_ajp12_worker.h"
+#include "jk_ajp13_worker.h"
+#include "jk_ajp14_worker.h"
+#ifdef HAVE_JNI
+#include "jk_jni_worker.h"
+#endif
+#include "jk_lb_worker.h"
+#include "jk_status.h"
+
+struct worker_factory_record
+{
+    const char *name;
+    int        type;
+    worker_factory fac;
+};
+typedef struct worker_factory_record worker_factory_record_t;
+
+static worker_factory_record_t worker_factories[] = {
+    /*
+     * AJPv12 worker, this is the stable worker.
+     */
+    {JK_AJP12_WORKER_NAME, JK_AJP12_WORKER_TYPE, ajp12_worker_factory},
+    /*
+     * AJPv13 worker, fast bi-directional worker.
+     */
+    {JK_AJP13_WORKER_NAME, JK_AJP13_WORKER_TYPE, ajp13_worker_factory},
+    /*
+     * AJPv14 worker, next generation fast bi-directional worker.
+     */
+    {JK_AJP14_WORKER_NAME, JK_AJP14_WORKER_TYPE, ajp14_worker_factory},
+    /*
+     * In process JNI based worker. Requires the server to be 
+     * multithreaded and to use native threads.
+     */
+#ifdef HAVE_JNI
+    {JK_JNI_WORKER_NAME, JK_JNI_WORKER_TYPE, jni_worker_factory},
+#endif
+    /*
+     * Load balancing worker. Performs round robin with sticky 
+     * session load balancing.
+     */
+    {JK_LB_WORKER_NAME, JK_LB_WORKER_TYPE, lb_worker_factory},
+
+    /*
+     * Status worker. Performs display display and
+     * worker management.
+     */
+    {JK_STATUS_WORKER_NAME, JK_STATUS_WORKER_TYPE, status_worker_factory},
+
+    /*
+     * Marks the end of the worker factory list.
+     */
+    {NULL, 0, NULL}
+};
+#endif /* _JK_WORKER_LIST_H */
+#endif /* _PLACE_WORKER_LIST_HERE */

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/list.mk.in
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/list.mk.in	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/list.mk.in	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,11 @@
+## Object needed for mod_jk for Apache-1.3
+APACHE_OBJECTS= ${JK}jk_ajp12_worker${OEXT} ${JK}jk_connect${OEXT} \
+                ${JK}jk_msg_buff${OEXT} ${JK}jk_util${OEXT} \
+                ${JK}jk_ajp13${OEXT} ${JK}jk_pool${OEXT} \
+                ${JK}jk_worker${OEXT} ${JK}jk_ajp13_worker${OEXT} \
+                ${JK}jk_lb_worker${OEXT} ${JK}jk_sockbuf${OEXT} \
+                ${JK}jk_map${OEXT} ${JK}jk_uri_worker_map${OEXT} \
+                ${JK}jk_ajp14${OEXT} ${JK}jk_ajp14_worker${OEXT} \
+                ${JK}jk_md5${OEXT} ${JK}jk_shm${OEXT} @JK_JNI_WORKER@ \
+                ${JK}jk_ajp_common${OEXT} ${JK}jk_context${OEXT} \
+                ${JK}jk_status${OEXT}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/portable.h
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/portable.h	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/portable.h	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,2 @@
+/* On most platform this file is overwritten when doing configure */
+/* DON'T COMMIT THE FILE IT BREAKS windoze and Netware, commit the sample file */

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/portable.h.sample
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/portable.h.sample	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/common/portable.h.sample	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,93 @@
+/* On most platform this file is overwritten when doing configure */
+/* common/portable.h.  Generated by configure.  */
+/* common/portable.h.in.  Generated from configure.in by autoheader.  */
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#define HAVE_DLFCN_H 1
+
+/* Have flock() */
+#define HAVE_FLOCK 1
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define HAVE_MEMORY_H 1
+
+/* Have snprintf() */
+#define HAVE_SNPRINTF 1
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#define HAVE_STDINT_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the <strings.h> header file. */
+#define HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* Have vsnprintf() */
+#define HAVE_VSNPRINTF 1
+
+/* Name of package */
+#define PACKAGE "mod_jk"
+
+/* Define to the address where bug reports for this package should be sent. */
+#define PACKAGE_BUGREPORT ""
+
+/* Define to the full name of this package. */
+#define PACKAGE_NAME ""
+
+/* Define to the full name and version of this package. */
+#define PACKAGE_STRING ""
+
+/* Define to the one symbol short name of this package. */
+#define PACKAGE_TARNAME ""
+
+/* Define to the version of this package. */
+#define PACKAGE_VERSION ""
+
+/* The size of a `char', as computed by sizeof. */
+#define SIZEOF_CHAR 1
+
+/* The size of a `int', as computed by sizeof. */
+#define SIZEOF_INT 4
+
+/* The size of a `long', as computed by sizeof. */
+#define SIZEOF_LONG 4
+
+/* The size of a `longlong', as computed by sizeof. */
+#define SIZEOF_LONGLONG 0
+
+/* The size of a `long double', as computed by sizeof. */
+#define SIZEOF_LONG_DOUBLE 16
+
+/* The size of a `long long', as computed by sizeof. */
+#define SIZEOF_LONG_LONG 8
+
+/* The size of a `short', as computed by sizeof. */
+#define SIZEOF_SHORT 2
+
+/* Define to 1 if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Define to use SO_RCVTIMEO with setsockopt() */
+#define USE_SO_RCVTIMEO 1
+
+/* Define to use SO_SNDTIMEO with setsockopt() */
+#define USE_SO_SNDTIMEO 1
+
+/* Version number of package */
+#define VERSION "1.2.19"

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/configure.in
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/configure.in	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/configure.in	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,626 @@
+dnl
+dnl Process this file with autoconf to produce a configure script
+dnl
+AC_REVISION($Id: configure.in 439843 2006-09-03 21:04:47Z rjung $)dnl
+
+AC_PREREQ(2.13)
+AC_INIT(common/jk_worker.h)
+AC_CONFIG_HEADER(common/portable.h)
+AC_CONFIG_AUX_DIR(scripts/build/unix)
+AC_CANONICAL_SYSTEM
+
+dnl package and version. (synchronization with common/jk_version.h ?)
+PACKAGE=mod_jk
+VERSION=1.2.19
+
+AM_INIT_AUTOMAKE(${PACKAGE}, ${VERSION})
+
+AC_PROG_CC
+AC_PROG_LD
+
+dnl Not sure what it does, but the libtool manual seems to require this
+dnl It should use the native platform dlopen ( if available )
+AC_LIBTOOL_DLOPEN
+
+dnl AM_PROG_LIBTOOL often causes problems.
+dnl I have solved them once using aclocal --acdir=/usr/local/share/aclocal/
+AM_PROG_LIBTOOL
+
+AC_PATH_PROG(TEST,test,$PATH)dnl
+AC_SUBST(TEST)
+
+AC_PATH_PROG(RM,rm,$PATH)dnl
+AC_SUBST(RM)
+
+AC_PATH_PROG(GREP,grep,$PATH)dnl
+AC_SUBST(GREP)
+
+AC_PATH_PROG(ECHO,echo,echo,$PATH)dnl
+AC_SUBST(ECHO)
+
+AC_PATH_PROG(SED,sed,$PATH)dnl
+AC_SUBST(SED)
+
+AC_PATH_PROG(CP,cp,$PATH)dnl
+AC_SUBST(CP)
+
+AC_PATH_PROG(MKDIR,mkdir,$PATH)dnl
+AC_SUBST(MKDIR)
+
+dnl AC_PATH_PROG(LIBTOOL,libtool,$PATH)dnl
+AC_SUBST(LIBTOOL)
+
+dnl ----------------------------- Checks for standard typedefs
+
+dnl Checks for integer size
+AC_CHECK_SIZEOF(char, 1)
+AC_CHECK_SIZEOF(int, 4)
+AC_CHECK_SIZEOF(long, 4)
+AC_CHECK_SIZEOF(short, 2)
+AC_CHECK_SIZEOF(long double, 12)
+AC_CHECK_SIZEOF(long long, 8)
+AC_CHECK_SIZEOF(longlong, 8)
+
+# Now we need to find what jk_uint32_t (sizeof == 4) will be.
+# The first match is our preference.
+if test "$ac_cv_sizeof_int" = "4"; then
+    int32_t_fmt='#define JK_INT32_T_FMT "d"'
+    uint32_t_fmt='#define JK_UINT32_T_FMT "u"'
+    uint32_t_hex_fmt='#define JK_UINT32_T_HEX_FMT "x"'
+    int32_value="int"
+elif test "$ac_cv_sizeof_long" = "4"; then
+    int32_t_fmt='#define JK_INT32_T_FMT "ld"'
+    uint32_t_fmt='#define JK_UINT32_T_FMT "lu"'
+    uint32_t_hex_fmt='#define JK_UINT32_T_HEX_FMT "lx"'
+    int32_value="long"
+else
+    int32_t_fmt='#error could not detect a 32-bit integer type'
+    uint32_t_fmt='#error could not detect a 32-bit integer type'
+    uint32_t_hex_fmt='#error could not detect a 32-bit integer type'
+    AC_ERROR([could not detect a 32-bit integer type])
+fi
+
+# Now we need to find what jk_uint64_t (sizeof == 8) will be.
+# The first match is our preference.
+if test "$ac_cv_sizeof_int" = "8"; then
+    int64_t_fmt='#define JK_INT64_T_FMT "d"'
+    uint64_t_fmt='#define JK_UINT64_T_FMT "u"'
+    uint64_t_hex_fmt='#define JK_UINT64_T_HEX_FMT "x"'
+    int64_value="int"
+elif test "$ac_cv_sizeof_long" = "8"; then
+    int64_t_fmt='#define JK_INT64_T_FMT "ld"'
+    uint64_t_fmt='#define JK_UINT64_T_FMT "lu"'
+    uint64_t_hex_fmt='#define JK_UINT64_T_HEX_FMT "lx"'
+    int64_value="long"
+elif test "$ac_cv_sizeof_long_long" = "8"; then
+    # Linux, Solaris, FreeBSD all support ll with printf.
+    # BSD 4.4 originated 'q'.  Solaris is more popular and 
+    # doesn't support 'q'.  Solaris wins.  Exceptions can
+    # go to the OS-dependent section.
+    int64_t_fmt='#define JK_INT64_T_FMT "lld"'
+    uint64_t_fmt='#define JK_UINT64_T_FMT "llu"'
+    uint64_t_hex_fmt='#define JK_UINT64_T_HEX_FMT "llx"'
+    int64_value="long long"
+elif test "$ac_cv_sizeof_long_double" = "8"; then
+    int64_t_fmt='#define JK_INT64_T_FMT "Ld"'
+    uint64_t_fmt='#define JK_UINT64_T_FMT "Lu"'
+    uint64_t_hex_fmt='#define JK_UINT64_T_HEX_FMT "Lx"'
+    int64_value="long double"
+elif test "$ac_cv_sizeof_longlong" = "8"; then
+    int64_t_fmt='#define JK_INT64_T_FMT "qd"'
+    uint64_t_fmt='#define JK_UINT64_T_FMT "qu"'
+    uint64_t_hex_fmt='#define JK_UINT64_T_HEX_FMT "qx"'
+    int64_value="__int64"
+else
+    int64_t_fmt='#error could not detect a 64-bit integer type'
+    uint64_t_fmt='#error could not detect a 64-bit integer type'
+    uint64_t_hex_fmt='#error could not detect a 64-bit integer type'
+    AC_ERROR([could not detect a 64-bit integer type])
+fi
+
+AC_SUBST(int32_value)
+AC_SUBST(int32_t_fmt) 
+AC_SUBST(uint32_t_fmt) 
+AC_SUBST(uint32_t_hex_fmt) 
+AC_SUBST(int64_value)
+AC_SUBST(int64_t_fmt) 
+AC_SUBST(uint64_t_fmt) 
+AC_SUBST(uint64_t_hex_fmt) 
+
+dnl check for snprintf and vsnprintf.
+AC_CHECK_FUNC(snprintf, AC_DEFINE(HAVE_SNPRINTF,1,[Have snprintf()]))
+AC_CHECK_FUNC(vsnprintf, AC_DEFINE(HAVE_VSNPRINTF,1,[Have vsnprintf()]))
+dnl check for flock function.
+AC_CHECK_FUNC(flock, AC_DEFINE(HAVE_FLOCK,1,[Have flock()]))
+
+dnl check for -lsocket library
+AC_CHECK_LIB(socket, setsockopt, [LIBS="$LIBS -lsocket"])
+
+dnl check for filio.h used on Solaris to define FIONREAD ioctl.
+AC_CHECK_HEADERS(sys/filio.h)
+
+AC_DEFUN([JK_CHECK_SETSOCKOPT], [
+AC_MSG_CHECKING(whether to use $1 with setsockopt())
+AC_TRY_RUN([
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+
+int main(void)
+{
+    int s;
+    struct timeval tv;
+    tv.tv_sec  = 3;
+    tv.tv_usec = 0;
+
+#ifndef $1
+    exit(3);
+#else
+    if ((s = socket(AF_INET, SOCK_STREAM, 0)) == -1)
+        exit(2);
+
+    /* fails on Solaris 2.6,8,9,10 and some Linuxes because
+       SO_RCVTIMEO|SO_SNDTIMEO are defined but not implemented */
+    if (setsockopt(s, SOL_SOCKET, $1, (const void *)&tv, sizeof(tv)) == -1)
+        exit(1);
+
+    exit(0);
+#endif
+}
+]
+, [ AC_MSG_RESULT([yes]) AC_DEFINE(USE_$1, 1, [Define to use $1 with setsockopt()]) ]
+, [ AC_MSG_RESULT([no]) ]
+)
+])dnl
+
+dnl check for SO_RCVTIMEO and SO_SNDTIMEO
+JK_CHECK_SETSOCKOPT(SO_RCVTIMEO)
+JK_CHECK_SETSOCKOPT(SO_SNDTIMEO)
+
+APACHE_CONFIG_VARS=`pwd`/scripts/build/config_vars.mk
+WEBSERVER=""
+apache_dir=""
+apache_include=""
+APXS="apxs"
+AC_ARG_WITH(apxs,
+[  --with-apxs[=FILE]      Build shared Apache module. FILE is the optional
+                        pathname to the apxs tool; defaults to finding
+			apxs in your PATH.],
+[
+    case "${withval}" in
+        y | yes | true) find_apxs=true ;;
+        n | no | false) find_apxs=false ;;
+        *) find_apxs=false ;;
+    esac
+
+    if ${TEST} ${find_apxs} ; then
+        AC_MSG_RESULT([need to check for Perl first, apxs depends on it...])
+        AC_PATH_PROG(PERL,perl,$PATH)dnl
+
+        if ${TEST} ${find_apxs} ; then
+            APXS=${withval}
+        else
+            AC_PATH_PROG(APXS,apxs,$PATH)dnl
+        fi
+
+        if ${TEST} -n "${APXS}" ; then
+            dnl Seems that we have it, but have to check if it is OK first
+            if ${TEST} ! -x "${APXS}" ; then
+                AC_MSG_ERROR(Invalid location for apxs: '${APXS}')
+            fi
+
+            ${APXS} -q PREFIX >/dev/null 2>/dev/null || apxs_support=false
+
+            if ${TEST} "${apxs_support}" = "false" ; then
+                AC_MSG_RESULT(could not find ${APXS})
+                AC_MSG_ERROR(You must specify a valid --with-apxs path)
+            fi
+
+            dnl apache_dir and apache_include are also needed.
+            apache_dir=`$APXS -q PREFIX`
+            apache_include="-I`$APXS -q INCLUDEDIR`"
+
+            dnl test apache version
+            APA=`${GREP} STANDARD20 ${APXS}`
+            if ${TEST} -z "$APA" ; then
+                WEBSERVER="apache-1.3"
+		APXSCFLAGS="`$APXS -q CFLAGS` -DJK_PREFORK"
+		APXS_CPPFLAGS=""
+            else
+                WEBSERVER="apache-2.0"
+              	APRINCLUDEDIR=""
+              	INCTEMP="`$APXS -q APR_INCLUDEDIR` `$APXS -q APU_INCLUDEDIR`"
+              	for INC in ${INCTEMP}; do
+              	    APRINCLUDEDIR="${APRINCLUDEDIR} -I${INC}"
+              	done
+                AC_MSG_RESULT([APRINCLUDEDIR is $APRINCLUDEDIR])
+              	APXSCFLAGS="`${APXS} -q CFLAGS` `${APXS} -q EXTRA_CFLAGS` -DHAVE_APR ${APRINCLUDEDIR}"
+              	APXSCPPFLAGS="`${APXS} -q EXTRA_CPPFLAGS`"
+                APACHE_CONFIG_VARS="`${APXS} -q exp_installbuilddir`/config_vars.mk"
+                LIBTOOL=`$APXS -q LIBTOOL`
+            fi
+            AC_MSG_RESULT([building connector for \"$WEBSERVER\"])
+
+            AC_SUBST(APXS)
+        fi
+    fi
+],
+[
+	AC_MSG_RESULT(no apxs given)
+])
+AC_SUBST(APACHE_CONFIG_VARS)
+
+dnl Apache-2.0 needs the os subdirectory to include os.h
+dnl this include is copy from os/config.m4
+sinclude(../support/os_apache.m4)
+
+dnl it is copied from the configure of JServ ;=)
+dnl and adapted.
+
+apache_dir_is_src="false"
+AC_ARG_WITH(apache,
+[  --with-apache=DIR      Build static Apache module. DIR is the pathname
+                        to the Apache source directory.],
+[
+    if ${TEST} ! -z "$WEBSERVER" ; then
+        AC_MSG_ERROR([Sorry cannot use --with-apxs=${APXS} and --with-apache=${withval} togother, please choose one of both])
+    fi
+
+    AC_MSG_CHECKING([for Apache source directory (assume static build)])
+
+    if ${TEST} -n "${withval}" && ${TEST} -d "${withval}" ; then
+        if ${TEST} -d "${withval}/src" ; then
+           # handle the case where people use relative paths to
+           # the apache source directory by pre-pending the current
+           # build directory to the path. there are probably
+           # errors with this if configure is run while in a
+           # different directory than what you are in at the time
+           if ${TEST} -n "`${ECHO} ${withval}|${GREP} \"^\.\.\"`" ; then
+               withval=`pwd`/${withval}
+           fi
+
+           apache_dir=${withval}
+           apache_dir_is_src="true"
+           AC_MSG_RESULT(${apache_dir})
+
+           AC_MSG_CHECKING(for Apache include directory)
+
+           if ${TEST} -d "${withval}/src/include" ; then
+               # read osdir from the existing apache.
+               osdir=`${GREP} '^OSDIR=' ${withval}/src/Makefile.config | ${SED} -e 's:^OSDIR=.*/os:os:'`
+               if ${TEST} -z "${osdir}" ; then
+                   osdir=os/unix
+               fi
+               apache_include="-I${withval}/src/include \
+                   -I${withval}/src/${osdir}"
+               WEBSERVER="apache-1.3"
+               LIB_JK_TYPE=mod_jk.a
+               CFLAGS="${CFLAGS} -DJK_PREFORK"
+               AC_MSG_RESULT([${apache_include}, version 1.3])
+           else
+               AC_MSG_ERROR([Sorry Apache 1.2.x is no longer supported.])
+           fi
+        else
+           if ${TEST} -d "${withval}/include" ; then
+              # osdir for Apache20.
+              WEBSERVER="apache-2.0"
+              apache_dir=${withval}
+              apache_dir_is_src="true"
+              LIB_JK_TYPE=lib_jk.la
+              apache_include="-I${withval}/include -I${withval}/srclib/apr/include -I${withval}/os/${OS_APACHE_DIR} -I${withval}/srclib/apr-util/include"
+              AC_MSG_RESULT(${apache_dir})
+           fi
+        fi
+    fi
+
+    dnl Make sure we have a result.
+    if ${TEST} -z "$WEBSERVER" ; then
+        AC_MSG_ERROR([Directory $apache_dir is not a valid Apache source distribution])
+    fi
+
+# VT: Now, which one I'm supposed to use? Let's figure it out later
+
+    configure_apache=true
+    configure_src=true
+
+    AC_MSG_RESULT([building connector for \"$WEBSERVER\"])
+],
+[
+	AC_MSG_RESULT(no apache given)
+])
+AC_SUBST(apache_include)
+APACHE_DIR=${apache_dir}
+AC_SUBST(APACHE_DIR)
+
+dnl Check for enable-jni
+JK_JNI_WORKER=""
+AC_ARG_ENABLE(jni,
+[  --enable-jni     Build jni_connect.so and enable jni_worker.],
+[
+    AC_MSG_RESULT(jni enable (need JDK))
+    CFLAGS="${CFLAGS} -DHAVE_JNI"
+    JK_JNI_WORKER="\${JK}jk_jni_worker\${OEXT}"
+])dnl
+AC_SUBST(JK_JNI_WORKER)
+
+dnl CFLAGS for EAPI mod_ssl (Apache 1.3)
+dnl it also allows the CFLAGS environment variable.
+CFLAGS="${CFLAGS}"
+AC_ARG_ENABLE(
+EAPI,
+[  --enable-EAPI     Enable EAPI support (mod_ssl, Apache 1.3)],
+[
+case "${enableval}" in
+    y | Y | YES | yes | TRUE | true )
+        CFLAGS="${CFLAGS} -DEAPI"
+        AC_MSG_RESULT([...Enabling EAPI Support...])
+        ;;
+esac
+])
+AC_SUBST(CFLAGS)
+
+dnl CFLAGS for maintainer mode
+dnl it also allows the CFLAGS environment variable.
+CFLAGS="${CFLAGS}"
+AC_ARG_ENABLE(
+maintainer-mode,
+[  --enable-maintainer-mode   Turn on debugging and compile time warnings],
+[
+case "${enableval}" in
+    y | Y | YES | yes | TRUE | true )
+        CFLAGS="${CFLAGS} -DDEBUG -Wall"
+        AC_MSG_RESULT([...Enabling Maintainer mode...])
+        ;;
+esac
+])
+AC_SUBST(CFLAGS)
+
+dnl CFLAGS for preforks mode
+dnl it also allows the CFLAGS environment variable.
+CFLAGS="${CFLAGS}"
+AC_ARG_ENABLE(
+prefork,
+[  --enable-prefork   Turn on prefork web server mode],
+[
+case "${enableval}" in
+    y | Y | YES | yes | TRUE | true )
+        CFLAGS="${CFLAGS} -DJK_PREFORK"
+        AC_MSG_RESULT([...Enabling Prefork mode...])
+        ;;
+esac
+])
+AC_SUBST(CFLAGS)
+
+dnl the APXSCFLAGS is given by apxs to the C compiler
+dnl the APXSLDFLAGS is given to the linker (for APRVARS).
+dnl APXSLDFLAGS=""
+dnl APXSCFLAGS=""
+if ${TEST} -n "${CFLAGS}" ; then
+	APXSCFLAGS="${APXSCFLAGS} ${CFLAGS}"
+fi
+dnl the APXSLDFLAGS is normaly empty but APXSCFLAGS is not.
+if ${TEST} -n "${LDFLAGS}" ; then
+	APXSLDFLAGS="-Wl,${LDFLAGS}"
+fi
+AC_SUBST(APXSCFLAGS)
+AC_SUBST(APXSCPPFLAGS)
+AC_SUBST(APXSLDFLAGS)
+
+if ${TEST} -n "${JK_JNI_WORKER}" ; then
+
+WEBSERVER="jni ${WEBSERVER}"
+
+dnl Find the JDK
+dnl Results go in JAVA_HOME
+dnl Also sets JAVA_PLATFORM to 1 for 1.1 and to 2 for 1.2
+
+AC_MSG_CHECKING([for JDK location (please wait)])
+
+dnl The order is: --with-java-home first, environment second, guessed value third.
+
+dnl This is a safe default. Could screw up on the security features, but
+dnl oh well, this is what --with-java2 is for.
+
+if ${TEST} -n "${JAVA_HOME}" ; then
+	JAVA_HOME_ENV="${JAVA_HOME}"
+else
+	JAVA_HOME_ENV=""
+fi
+JAVA_HOME=""
+JAVA_PLATFORM="1"
+
+AC_ARG_WITH(java-home,
+[  --with-java-home=DIR     Where is your JDK root directory.],
+[
+
+    # This stuff works if the command line parameter --with-java-home was
+    # specified, so it takes priority rightfully.
+
+    JAVA_HOME=${withval}
+
+    if ${TEST} ! -d "${JAVA_HOME}" ; then
+        AC_MSG_ERROR(Not a directory: ${JAVA_HOME})
+    fi
+
+    AC_MSG_RESULT(${JAVA_HOME})
+
+],
+[
+    # This works if the parameter was NOT specified, so it's a good time
+    # to see what the enviroment says.
+
+    # Since Sun uses JAVA_HOME a lot, we check it first and ignore the
+    # JAVA_HOME, otherwise just use whatever JAVA_HOME was specified.
+
+    if ${TEST} -n "${JAVA_HOME_ENV}" ; then
+
+        JAVA_HOME=${JAVA_HOME_ENV}
+        AC_MSG_RESULT(${JAVA_HOME_ENV} from environment)
+    fi
+])
+
+if ${TEST} -z "${JAVA_HOME}" ; then
+
+    # Oh well, nobody set neither JAVA_HOME nor JAVA_HOME, have to guess
+
+    # The following code is based on the code submitted by Henner Zeller
+    # for ${srcdir}/src/scripts/package/rpm/ApacheJServ.spec
+
+    # Two variables will be set as a result:
+    #
+    # JAVA_HOME
+    # JAVA_PLATFORM
+    AC_MSG_CHECKING([Try to guess JDK location])
+
+
+    for JAVA_PREFIX in \
+	    /usr/local \
+	    /usr/local/lib \
+    	    /usr \
+    	    /usr/lib \
+            /opt  \
+    	    /
+    do
+        for JAVA_PLATFORM in 3 2 1 ;
+        do
+
+            for subversion in .9 .8 .7 .6 .5 .4 .3 .2 .1 "" ;
+                do
+                    for VARIANT in IBMJava2- java java- jdk jdk-;
+                    do
+                        GUESS="${JAVA_PREFIX}/${VARIANT}1.${JAVA_PLATFORM}${subversion}"
+dnl                        AC_MSG_CHECKING([${GUESS}])
+                        if ${TEST} -d "${GUESS}/bin" \
+                        && ${TEST} -d "${GUESS}/include" ; then
+
+                            JAVA_HOME="${GUESS}"
+                            AC_MSG_RESULT([${GUESS}])
+                            break
+                        fi
+
+                    done
+
+                    if ${TEST} -n "${JAVA_HOME}" ; then
+                        break;
+                    fi
+
+                done
+
+                if ${TEST} -n "${JAVA_HOME}" ; then
+                    break;
+                fi
+
+            done
+
+            if ${TEST} -n "${JAVA_HOME}" ; then
+                break;
+            fi
+
+        done
+
+        if ${TEST} -n "${JAVA_HOME}" ; then
+
+            dnl Just to have the messages looking uniformly
+
+            AC_MSG_CHECKING(Java platform)
+            AC_MSG_RESULT([guess ${JAVA_PLATFORM}])
+        fi
+
+
+else
+
+        AC_MSG_CHECKING(Java platform)
+
+        AC_ARG_WITH(java-platform,
+        [  --with-java-platform=VAL Force the Java platorm
+                          (value is 1 for 1.1.x or 2 for 1.2.x or greater)],
+        [
+            dnl This requires a bit of tweaking to be handled properly, but
+            dnl the default is good enough
+
+            JAVA_PLATFORM="2"
+        ])
+
+        AC_MSG_RESULT(forced Java ${JAVA_PLATFORM})
+
+fi
+dnl end of JServ ;=)
+
+dnl test if --enable-jni give but not valid JAVA_HOME
+if ${TEST} -z "${JAVA_HOME}" ; then
+    AC_MSG_ERROR([JDK home not found, please specify one with --with-java-home option (run ./configure --help for more options)])
+fi
+
+dnl guess OS = OS_TYPE for jni_md.h
+OS=""
+AC_ARG_WITH(os-type,
+[  --with-os-type[=SUBDIR]     Where is your JDK os-type subdirectory.],
+[
+    OS=${withval}
+
+    if ${TEST} ! -d "${JAVA_HOME}/${OS}" ; then
+        AC_MSG_ERROR(Not a directory: ${JAVA_HOME}/${OS})
+    fi
+],
+[
+    AC_MSG_CHECKING(os_type directory)
+    if ${TEST} -f ${JAVA_HOME}/include/jni_md.h; then
+    	OS=""
+    else
+        for f in ${JAVA_HOME}/include/*/jni_md.h; do
+            if ${TEST} -f $f; then
+                OS=`dirname ${f}`
+                OS=`basename ${OS}`
+                echo " ${OS}"
+            fi
+        done
+        if ${TEST} -z "${OS}"; then
+            AC_MSG_RESULT(Cannot find jni_md.h in ${JAVA_HOME}/${OS})
+            AC_MSG_ERROR(You should retry --with-os-type=SUBDIR)
+        fi
+    fi
+])
+fi
+AC_SUBST(JAVA_HOME)
+AC_SUBST(OS)
+
+
+dnl Check that  a WEBSERVER has been given
+if ${TEST} -z "$WEBSERVER" ; then
+	AC_MSG_ERROR(Cannot find the WebServer)
+fi
+
+dnl Add common to subdir list
+WEBSERVER="common ${WEBSERVER}"
+
+AC_SUBST(WEBSERVER)
+
+AM_CONDITIONAL(MAKE_DYNAMIC_APACHE, ${TEST} "${apache_dir_is_src}" = "false")
+
+if ${TEST} "${apache_dir_is_src}" = "false" ; then
+dnl normal apxs handling
+	APACHE20_OEXT=.c
+	LIB_JK_TYPE=mod_jk.so
+	INSTALL_TYPE=install_dynamic
+else
+dnl install static library in apache sources.
+	APACHE20_OEXT=.lo
+	INSTALL_TYPE=install_static
+fi
+AC_SUBST(APACHE20_OEXT)
+AC_SUBST(LIB_JK_TYPE)
+AC_SUBST(INSTALL_TYPE)
+
+dnl automake needs the path it does not work with $WEBSERVER
+dnl that why useless Makefiles are build.
+AC_OUTPUT([
+	Makefile
+	apache-1.3/Makefile
+	apache-1.3/Makefile.apxs
+	apache-2.0/Makefile
+	apache-2.0/Makefile.apxs
+	common/Makefile
+	common/list.mk
+	common/jk_types.h
+	jni/Makefile
+	])

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/docs/api/README.txt
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/docs/api/README.txt	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/docs/api/README.txt	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,3 @@
+To generate the API documentation for the mod_jk library, simply invoke
+  make apidocs
+from the mod_jk Library root source path. (tomcat-connectors/jk/native)

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/Makefile.vc
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/Makefile.vc	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/Makefile.vc	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,286 @@
+# Microsoft Developer Studio Generated NMAKE File, Based on isapi.dsp
+!IF "$(CFG)" == ""
+CFG=isapi - Win32 Release
+!MESSAGE No configuration specified. Defaulting to isapi - Win32 Release.
+!ENDIF 
+
+!IF "$(CFG)" != "isapi - Win32 Release"
+!MESSAGE Invalid configuration "$(CFG)" specified.
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE 
+!MESSAGE NMAKE /f "Makefile.vc" CFG="isapi - Win32 Release"
+!MESSAGE 
+!MESSAGE Possible choices for configuration are:
+!MESSAGE 
+!MESSAGE "isapi - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE 
+!ERROR An invalid configuration is specified.
+!ENDIF 
+
+!IF "$(OS)" == "Windows_NT"
+NULL=
+!ELSE 
+NULL=nul
+!ENDIF 
+
+CPP=cl.exe
+MTL=midl.exe
+RSC=rc.exe
+OUTDIR=.\Release
+INTDIR=.\Release
+# Begin Custom Macros
+OutDir=.\Release
+# End Custom Macros
+
+ALL : "$(OUTDIR)\isapi_redirect.dll"
+
+
+CLEAN :
+	- at erase "$(INTDIR)\isapi_redirector_src.idb"
+	- at erase "$(INTDIR)\isapi_redirector_src.pdb"
+	- at erase "$(INTDIR)\jk_ajp12_worker.obj"
+	- at erase "$(INTDIR)\jk_ajp13.obj"
+	- at erase "$(INTDIR)\jk_ajp13_worker.obj"
+	- at erase "$(INTDIR)\jk_ajp14.obj"
+	- at erase "$(INTDIR)\jk_ajp14_worker.obj"
+	- at erase "$(INTDIR)\jk_ajp_common.obj"
+	- at erase "$(INTDIR)\jk_connect.obj"
+	- at erase "$(INTDIR)\jk_context.obj"
+	- at erase "$(INTDIR)\jk_isapi_plugin.obj"
+	- at erase "$(INTDIR)\jk_jni_worker.obj"
+	- at erase "$(INTDIR)\jk_lb_worker.obj"
+	- at erase "$(INTDIR)\jk_map.obj"
+	- at erase "$(INTDIR)\jk_md5.obj"
+	- at erase "$(INTDIR)\jk_msg_buff.obj"
+	- at erase "$(INTDIR)\jk_nwmain.obj"
+	- at erase "$(INTDIR)\jk_pool.obj"
+	- at erase "$(INTDIR)\jk_shm.obj"
+	- at erase "$(INTDIR)\jk_sockbuf.obj"
+	- at erase "$(INTDIR)\jk_status.obj"
+	- at erase "$(INTDIR)\jk_uri_worker_map.obj"
+	- at erase "$(INTDIR)\jk_util.obj"
+	- at erase "$(INTDIR)\jk_worker.obj"
+	- at erase "$(OUTDIR)\isapi_redirect.dll"
+	- at erase "$(OUTDIR)\isapi_redirect.exp"
+	- at erase "$(OUTDIR)\isapi_redirect.lib"
+	- at erase "$(OUTDIR)\isapi_redirect.pdb"
+
+"$(OUTDIR)" :
+    if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+BSC32=bscmake.exe
+BSC32_FLAGS=/nologo /o"$(OUTDIR)\isapi.bsc" 
+BSC32_SBRS= \
+	
+LINK32=link.exe
+LINK32_FLAGS=kernel32.lib user32.lib advapi32.lib ws2_32.lib mswsock.lib /nologo /base:"0x6A6B0000" /dll /incremental:no /pdb:"$(OUTDIR)\isapi_redirect.pdb" /debug /machine:I386 /def:".\isapi.def" /out:"$(OUTDIR)\isapi_redirect.dll" /implib:"$(OUTDIR)\isapi_redirect.lib" 
+DEF_FILE= \
+	".\isapi.def"
+LINK32_OBJS= \
+	"$(INTDIR)\jk_ajp12_worker.obj" \
+	"$(INTDIR)\jk_ajp13.obj" \
+	"$(INTDIR)\jk_ajp13_worker.obj" \
+	"$(INTDIR)\jk_ajp14.obj" \
+	"$(INTDIR)\jk_ajp14_worker.obj" \
+	"$(INTDIR)\jk_ajp_common.obj" \
+	"$(INTDIR)\jk_connect.obj" \
+	"$(INTDIR)\jk_context.obj" \
+	"$(INTDIR)\jk_isapi_plugin.obj" \
+	"$(INTDIR)\jk_jni_worker.obj" \
+	"$(INTDIR)\jk_lb_worker.obj" \
+	"$(INTDIR)\jk_map.obj" \
+	"$(INTDIR)\jk_md5.obj" \
+	"$(INTDIR)\jk_msg_buff.obj" \
+	"$(INTDIR)\jk_nwmain.obj" \
+	"$(INTDIR)\jk_pool.obj" \
+	"$(INTDIR)\jk_shm.obj" \
+	"$(INTDIR)\jk_sockbuf.obj" \
+	"$(INTDIR)\jk_status.obj" \
+	"$(INTDIR)\jk_uri_worker_map.obj" \
+	"$(INTDIR)\jk_util.obj" \
+	"$(INTDIR)\jk_worker.obj"
+
+"$(OUTDIR)\isapi_redirect.dll" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+    $(LINK32) @<<
+  $(LINK32_FLAGS) $(LINK32_OBJS)
+<<
+
+CPP_PROJ=/nologo /MD /W3 /Zi /O2 /I "..\common" /I "$(JAVA_HOME)\include" /I "$(JAVA_HOME)\include\win32" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "ISAPI_EXPORTS" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\isapi_redirector_src" /FD /c 
+
+.c{$(INTDIR)}.obj::
+   $(CPP) @<<
+   $(CPP_PROJ) $< 
+<<
+
+.cpp{$(INTDIR)}.obj::
+   $(CPP) @<<
+   $(CPP_PROJ) $< 
+<<
+
+.cxx{$(INTDIR)}.obj::
+   $(CPP) @<<
+   $(CPP_PROJ) $< 
+<<
+
+.c{$(INTDIR)}.sbr::
+   $(CPP) @<<
+   $(CPP_PROJ) $< 
+<<
+
+.cpp{$(INTDIR)}.sbr::
+   $(CPP) @<<
+   $(CPP_PROJ) $< 
+<<
+
+.cxx{$(INTDIR)}.sbr::
+   $(CPP) @<<
+   $(CPP_PROJ) $< 
+<<
+
+MTL_PROJ=/nologo /D "NDEBUG" /mktyplib203 /win32 
+
+!IF "$(NO_EXTERNAL_DEPS)" != "1"
+!IF EXISTS("isapi.dep")
+!INCLUDE "isapi.dep"
+!ELSE 
+!MESSAGE Warning: cannot find "isapi.dep"
+!ENDIF 
+!ENDIF 
+
+
+!IF "$(CFG)" == "isapi - Win32 Release"
+SOURCE=..\common\jk_ajp12_worker.c
+
+"$(INTDIR)\jk_ajp12_worker.obj" : $(SOURCE) "$(INTDIR)"
+	$(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=..\common\jk_ajp13.c
+
+"$(INTDIR)\jk_ajp13.obj" : $(SOURCE) "$(INTDIR)"
+	$(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=..\common\jk_ajp13_worker.c
+
+"$(INTDIR)\jk_ajp13_worker.obj" : $(SOURCE) "$(INTDIR)"
+	$(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=..\common\jk_ajp14.c
+
+"$(INTDIR)\jk_ajp14.obj" : $(SOURCE) "$(INTDIR)"
+	$(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=..\common\jk_ajp14_worker.c
+
+"$(INTDIR)\jk_ajp14_worker.obj" : $(SOURCE) "$(INTDIR)"
+	$(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=..\common\jk_ajp_common.c
+
+"$(INTDIR)\jk_ajp_common.obj" : $(SOURCE) "$(INTDIR)"
+	$(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=..\common\jk_connect.c
+
+"$(INTDIR)\jk_connect.obj" : $(SOURCE) "$(INTDIR)"
+	$(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=..\common\jk_context.c
+
+"$(INTDIR)\jk_context.obj" : $(SOURCE) "$(INTDIR)"
+	$(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\jk_isapi_plugin.c
+
+"$(INTDIR)\jk_isapi_plugin.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=..\common\jk_jni_worker.c
+
+"$(INTDIR)\jk_jni_worker.obj" : $(SOURCE) "$(INTDIR)"
+	$(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=..\common\jk_lb_worker.c
+
+"$(INTDIR)\jk_lb_worker.obj" : $(SOURCE) "$(INTDIR)"
+	$(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=..\common\jk_map.c
+
+"$(INTDIR)\jk_map.obj" : $(SOURCE) "$(INTDIR)"
+	$(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=..\common\jk_md5.c
+
+"$(INTDIR)\jk_md5.obj" : $(SOURCE) "$(INTDIR)"
+	$(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=..\common\jk_msg_buff.c
+
+"$(INTDIR)\jk_msg_buff.obj" : $(SOURCE) "$(INTDIR)"
+	$(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=..\common\jk_nwmain.c
+
+"$(INTDIR)\jk_nwmain.obj" : $(SOURCE) "$(INTDIR)"
+	$(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=..\common\jk_pool.c
+
+"$(INTDIR)\jk_pool.obj" : $(SOURCE) "$(INTDIR)"
+	$(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=..\common\jk_shm.c
+
+"$(INTDIR)\jk_shm.obj" : $(SOURCE) "$(INTDIR)"
+	$(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=..\common\jk_sockbuf.c
+
+"$(INTDIR)\jk_sockbuf.obj" : $(SOURCE) "$(INTDIR)"
+	$(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=..\common\jk_status.c
+
+"$(INTDIR)\jk_status.obj" : $(SOURCE) "$(INTDIR)"
+	$(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=..\common\jk_uri_worker_map.c
+
+"$(INTDIR)\jk_uri_worker_map.obj" : $(SOURCE) "$(INTDIR)"
+	$(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=..\common\jk_util.c
+
+"$(INTDIR)\jk_util.obj" : $(SOURCE) "$(INTDIR)"
+	$(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=..\common\jk_worker.c
+
+"$(INTDIR)\jk_worker.obj" : $(SOURCE) "$(INTDIR)"
+	$(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+
+!ENDIF 
+

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/README
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/README	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/README	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,46 @@
+ABOUT
+-----
+
+The Tomcat redirector was developed using Visual C++ Ver.6.0, 
+so having this environment is a prerequisite if you want to perform 
+a custom build.
+
+REQUIREMENT
+-----------
+
+* MS VC 6.0 (+ update, latest service pack is sp5)
+  isapi_redirector.dll can be built using the command line tools, or 
+  from within the Visual Studio IDE Workbench. The command line build 
+  requires the environment to reflect the PATH, INCLUDE, LIB and other 
+  variables that can be configured with the vcvars32 batch file: 
+  
+  "c:\Program Files\DevStudio\VC\Bin\vcvars32.bat"
+
+* MS PLATFORM SDK
+  Visual C++ 6.0 builds require an updated Microsoft Windows Platform SDK 
+  (http://www.microsoft.com/msdownload/platformsdk/sdkupdate/) to enable 
+  some isapi_redirector.dll features. For command line builds,
+  the Platform SDK environment is prepared by the setenv batch file:
+  
+  "c:\Program Files\Microsoft Platform SDK\setenv.bat"
+
+  Note that the Windows Platform SDK is only needed if you want authenticate 
+  using IIS to compile a isapi_redirector.dll.. 
+
+
+
+BUILDING
+--------
+ 
+The steps that you need to take are:
+
+   1. Change directory to the isapi redirector plugins source directory.
+   
+   2. Execute the following command:
+      MSDEV isapi.dsp /MAKE ALL
+      If msdev is not in your path, enter the full path to msdev.exe
+
+This will build both release and debug versions of the redirector plugin.
+
+An alternative will be to open the isapi workspace file (isapi.dsw) in msdev and 
+build it using the build menu.

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/installer/LICENSE.TXT
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/installer/LICENSE.TXT	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/installer/LICENSE.TXT	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,201 @@
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed 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.

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/installer/License.rtf
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/installer/License.rtf	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/installer/License.rtf	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,72 @@
+{\rtf1\ansi\ansicpg1252\deff0{\fonttbl{\f0\fswiss\fprq2\fcharset0 Arial;}}
+\viewkind4\uc1\pard\qc\lang1033\b\f0\fs18 Apache License\par
+Version 2.0, January 2004\par
+http://www.apache.org/licenses/\par
+\b0\par
+\pard TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\par
+\par
+\pard\fi-180\li180 1. Definitions.\par
+\par
+\pard\li180 "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document.\par
+\par
+"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License.\par
+\par
+"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity.\par
+\par
+"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License.\par
+\par
+"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files.\par
+\par
+"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types.\par
+\par
+"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below).\par
+\par
+"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof.\par
+\par
+"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution."\par
+\par
+"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work.\par
+\pard\par
+\pard\fi-180\li180 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form.\par
+\par
+3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed.\par
+\par
+4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions:\par
+\pard\par
+\pard\fi-270\li450 (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and\par
+\par
+(b) You must cause any modified files to carry prominent notices stating that You changed the files; and\par
+\par
+(c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and\par
+\par
+(d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License.\par
+\pard\par
+\pard\li180 You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or  for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License.\par
+\pard\par
+\pard\fi-180\li180 5. Submission of Contributions. Unless You explicitly state otherwise,  any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions.\par
+\par
+6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file.\par
+\par
+7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License.\par
+\par
+8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages.\par
+\par
+9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability.\par
+\pard\par
+END OF TERMS AND CONDITIONS\par
+\par
+APPENDIX: How to apply the Apache License to your work.\par
+\par
+To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!)  The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives.\par
+\par
+\pard\li180 Copyright [yyyy] [name of copyright owner]\par
+\par
+Licensed 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\par
+\par
+\pard\li360 http://www.apache.org/licenses/LICENSE-2.0\par
+\pard\li180\par
+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.\par
+\pard\par
+\b\par
+}
+ 

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/installer/bin/README
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/installer/bin/README	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/installer/bin/README	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1 @@
+Jakarta Isapi Redirector

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/installer/conf/uriworkermap.properties
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/installer/conf/uriworkermap.properties	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/installer/conf/uriworkermap.properties	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,23 @@
+# uriworkermap.properties - IIS
+#
+# This file provides sample mappings for example wlb
+# worker defined in workermap.properties.minimal
+# The general syntax for this file is:
+# [URL]=[Worker name]
+
+/admin/*=wlb
+/manager/*=wlb
+/jsp-examples/*=wlb
+/servlets-examples/*=wlb
+
+# Optionally filter out all .jpeg files inside that context
+# For no mapping the url has to start with exclamation (!)
+
+!/servlets-examples/*.jpeg=wlb
+
+#
+# Mount jkstatus to /jkmanager
+# For production servers you will need to
+# secure the access to the /jkmanager url
+#
+/jkmanager=jkstatus

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/installer/conf/workers.properties.minimal
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/installer/conf/workers.properties.minimal	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/installer/conf/workers.properties.minimal	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,30 @@
+# workers.properties.minimal -
+#
+# This file provides minimal jk configuration properties needed to
+# connect to Tomcat.
+#
+# The workers that jk should create and work with
+#
+
+worker.list=wlb,jkstatus
+
+#
+# Defining a worker named ajp13w and of type ajp13
+# Note that the name and the type do not have to match.
+#
+worker.ajp13w.type=ajp13
+worker.ajp13w.host=localhost
+worker.ajp13w.port=8009
+
+#
+# Defining a load balancer
+# 
+
+worker.wlb.type=lb
+worker.wlb.balance_workers=ajp13w
+
+#
+# Define status worker
+#
+
+worker.jkstatus.type=status

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/installer/iisfilter.vbs
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/installer/iisfilter.vbs	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/installer/iisfilter.vbs	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,119 @@
+'
+' Copyright 1999-2004 The Apache Software Foundation
+'
+' Licensed 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.
+'
+
+' =========================================================================
+' Description: Install script for Tomcat ISAPI redirector                              
+' Author:      Mladen Turk <mturk at apache.org>                           
+' Version:     $Revision: 300364 $                                           
+' =========================================================================
+
+'
+' Get a handle to the filters for the server - we process all errors
+'
+On Error Resume Next
+
+filterName = "jakarta"
+filterLib = "bin\isapi_redirect.dll"
+  
+Function IISInstallFilter(filterDir, filterObject)
+
+    Dim filters
+    Set filters = GetObject(filterObject)
+    If err Then err.clear
+    info "Got Filters " + filters.FilterLoadOrder
+    
+    '
+    ' Create the filter - if it fails then delete it and try again
+    '
+    name = filterName
+    info "Creating Filter  - " + filterName
+    Dim filter
+    Set filter = filters.Create( "IISFilter", filterName )
+    If err Then
+    	err.clear
+    	info "Filter exists - deleting"
+    	filters.delete "IISFilter", filterName
+    	If err Then
+    	    info "Error Deleting Filter"
+    	    IISInstallFilter = 0
+    	    Exit Function
+    	End If
+    	Set filter = filters.Create( "IISFilter", filterName )
+    	If Err Then
+    	    info "Error Creating Filter"
+    	    IISInstallFilter = 0
+    	    Exit Function
+    	End If
+    End If
+    
+    '
+    ' Set the filter info and save it
+    '
+    filter.FilterPath = filterDir + filterLib
+'    filter.FilterEnabled = true
+    filter.FilterDescription = "Jakarta Isapi Redirector"
+    filter.NotifyOrderHigh = true
+    filter.SetInfo
+    info "Created Filter " + filterDir + filterLib
+    
+    '
+    ' Set the load order - only if it's not in the list already
+    '
+    On Error goto 0
+    loadOrders = filters.FilterLoadOrder
+    list = Split( loadOrders, "," )
+    found = false
+    For each item in list
+    	If Trim( item ) = filterName Then found = true
+    Next
+    
+    If found = false Then 
+    	info "Filter is not in load order - adding now."
+    	If Len(loadOrders) <> 0  Then loadOrders = loadOrders + ","
+    	filters.FilterLoadOrder = loadOrders + filterName
+    	filters.SetInfo
+    	info "Added Filter " + filterName 
+    Else
+    	info "Filter already exists in load order - no update required."
+    End If
+    IISInstallFilter = 1
+End Function
+
+' 
+' Helper function for snafus
+'
+Function fail(message)
+'	MsgBox " " + message
+	WScript.Quit(1)
+End function
+
+'
+' Helper function for info
+'
+Function info(message)
+'	MsgBox " " + message
+End Function 
+
+info "Installing IIS Filter " + Session.Property("INSTALLDIR")
+Dim rv
+rv = 0
+rv = IISInstallFilter(Session.Property("INSTALLDIR"), "IIS://LocalHost/W3SVC/1/Filters")
+If rv = 0 Then    
+    rv = IISInstallFilter(Session.Property("INSTALLDIR"), "/LM/W3SVC/Filters")
+End If
+If rv = 0 Then
+    rv = IISInstallFilter(Session.Property("INSTALLDIR"), "/LM/W3SVC/1/Filters")
+End If

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/installer/isapi-redirector-win32-msi.ism
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/installer/isapi-redirector-win32-msi.ism	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/installer/isapi-redirector-win32-msi.ism	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,4595 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<?xml-stylesheet type="text/xsl" href="is.xsl" ?>
+<!DOCTYPE msi [
+   <!ELEMENT msi   (summary,table*)>
+   <!ATTLIST msi version    CDATA #REQUIRED>
+   <!ATTLIST msi xmlns:dt   CDATA #IMPLIED
+                 codepage   CDATA #IMPLIED
+                 compression (MSZIP|LZX|none) "LZX">
+   
+   <!ELEMENT summary       (codepage?,title?,subject?,author?,keywords?,comments?,
+                            template,lastauthor?,revnumber,lastprinted?,
+                            createdtm?,lastsavedtm?,pagecount,wordcount,
+                            charcount?,appname?,security?)>
+                            
+   <!ELEMENT codepage      (#PCDATA)>
+   <!ELEMENT title         (#PCDATA)>
+   <!ELEMENT subject       (#PCDATA)>
+   <!ELEMENT author        (#PCDATA)>
+   <!ELEMENT keywords      (#PCDATA)>
+   <!ELEMENT comments      (#PCDATA)>
+   <!ELEMENT template      (#PCDATA)>
+   <!ELEMENT lastauthor    (#PCDATA)>
+   <!ELEMENT revnumber     (#PCDATA)>
+   <!ELEMENT lastprinted   (#PCDATA)>
+   <!ELEMENT createdtm     (#PCDATA)>
+   <!ELEMENT lastsavedtm   (#PCDATA)>
+   <!ELEMENT pagecount     (#PCDATA)>
+   <!ELEMENT wordcount     (#PCDATA)>
+   <!ELEMENT charcount     (#PCDATA)>
+   <!ELEMENT appname       (#PCDATA)>
+   <!ELEMENT security      (#PCDATA)>                            
+                                
+   <!ELEMENT table         (col+,row*)>
+   <!ATTLIST table
+                name        CDATA #REQUIRED>
+
+   <!ELEMENT col           (#PCDATA)>
+   <!ATTLIST col
+                 key       (yes|no) #IMPLIED
+                 def       CDATA #IMPLIED>
+                 
+   <!ELEMENT row            (td+)>
+   
+   <!ELEMENT td             (#PCDATA)>
+   <!ATTLIST td
+                 href       CDATA #IMPLIED
+                 dt:dt     (string|bin.base64) #IMPLIED
+                 md5        CDATA #IMPLIED>
+]>
+<msi version="2.0" xmlns:dt="urn:schemas-microsoft-com:datatypes">
+	
+	<summary>
+		<codepage>1252</codepage>
+		<title>Installation Database</title>
+		<subject>Jakarta Isapi Redirector</subject>
+		<author>##COMPANY_NAME##</author>
+		<keywords>Installer,MSI,Database</keywords>
+		<comments>Contact:  Your local administrator</comments>
+		<template>Intel;1033</template>
+		<lastauthor>Administrator</lastauthor>
+		<revnumber>{C3AC9A0C-8E2C-4998-8FD3-894123CF9D37}</revnumber>
+		<lastprinted/>
+		<createdtm>06/21/1999 09:00</createdtm>
+		<lastsavedtm>07/14/2000 12:50</lastsavedtm>
+		<pagecount>200</pagecount>
+		<wordcount>0</wordcount>
+		<charcount/>
+		<appname>InstallShield Developer</appname>
+		<security>1</security>
+	</summary>
+	
+	<table name="ActionText">
+		<col key="yes" def="s72">Action</col>
+		<col def="L64">Description</col>
+		<col def="L128">Template</col>
+		<row><td>Advertise</td><td>##IDS_ACTIONTEXT_Advertising##</td><td/></row>
+		<row><td>AllocateRegistrySpace</td><td>##IDS_ACTIONTEXT_AllocatingRegistry##</td><td>##IDS_ACTIONTEXT_FreeSpace##</td></row>
+		<row><td>AppSearch</td><td>##IDS_ACTIONTEXT_SearchInstalled##</td><td>##IDS_ACTIONTEXT_PropertySignature##</td></row>
+		<row><td>BindImage</td><td>##IDS_ACTIONTEXT_BindingExes##</td><td>##IDS_ACTIONTEXT_File##</td></row>
+		<row><td>CCPSearch</td><td>##IDS_ACTIONTEXT_UnregisterModules##</td><td/></row>
+		<row><td>CostFinalize</td><td>##IDS_ACTIONTEXT_ComputingSpace3##</td><td/></row>
+		<row><td>CostInitialize</td><td>##IDS_ACTIONTEXT_ComputingSpace##</td><td/></row>
+		<row><td>CreateFolders</td><td>##IDS_ACTIONTEXT_CreatingFolders##</td><td>##IDS_ACTIONTEXT_Folder##</td></row>
+		<row><td>CreateShortcuts</td><td>##IDS_ACTIONTEXT_CreatingShortcuts##</td><td>##IDS_ACTIONTEXT_Shortcut##</td></row>
+		<row><td>DeleteServices</td><td>##IDS_ACTIONTEXT_DeletingServices##</td><td>##IDS_ACTIONTEXT_Service##</td></row>
+		<row><td>DuplicateFiles</td><td>##IDS_ACTIONTEXT_CreatingDuplicate##</td><td>##IDS_ACTIONTEXT_FileDirectorySize##</td></row>
+		<row><td>FileCost</td><td>##IDS_ACTIONTEXT_ComputingSpace2##</td><td/></row>
+		<row><td>FindRelatedProducts</td><td>##IDS_ACTIONTEXT_SearchForRelated##</td><td>##IDS_ACTIONTEXT_FoundApp##</td></row>
+		<row><td>GenerateScript</td><td>##IDS_ACTIONTEXT_GeneratingScript##</td><td>##IDS_ACTIONTEXT_1##</td></row>
+		<row><td>InstallAdminPackage</td><td>##IDS_ACTIONTEXT_CopyingNetworkFiles##</td><td>##IDS_ACTIONTEXT_FileDirSize##</td></row>
+		<row><td>InstallFiles</td><td>##IDS_ACTIONTEXT_CopyingNewFiles##</td><td>##IDS_ACTIONTEXT_FileDirSize2##</td></row>
+		<row><td>InstallODBC</td><td>##IDS_ACTIONTEXT_InstallODBC##</td><td/></row>
+		<row><td>InstallSFPCatalogFile</td><td>##IDS_ACTIONTEXT_InstallingSystemCatalog##</td><td>##IDS_ACTIONTEXT_FileDependencies##</td></row>
+		<row><td>InstallServices</td><td>##IDS_ACTIONTEXT_InstallServices##</td><td>##IDS_ACTIONTEXT_Service2##</td></row>
+		<row><td>InstallValidate</td><td>##IDS_ACTIONTEXT_Validating##</td><td/></row>
+		<row><td>LaunchConditions</td><td>##IDS_ACTIONTEXT_EvaluateLaunchConditions##</td><td/></row>
+		<row><td>MigrateFeatureStates</td><td>##IDS_ACTIONTEXT_MigratingFeatureStates##</td><td>##IDS_ACTIONTEXT_Application##</td></row>
+		<row><td>MoveFiles</td><td>##IDS_ACTIONTEXT_MovingFiles##</td><td>##IDS_ACTIONTEXT_FileDirSize3##</td></row>
+		<row><td>PatchFiles</td><td>##IDS_ACTIONTEXT_PatchingFiles##</td><td>##IDS_ACTIONTEXT_FileDirSize4##</td></row>
+		<row><td>ProcessComponents</td><td>##IDS_ACTIONTEXT_UpdateComponentRegistration##</td><td/></row>
+		<row><td>PublishComponents</td><td>##IDS_ACTIONTEXT_PublishingQualifiedComponents##</td><td>##IDS_ACTIONTEXT_ComponentIDQualifier##</td></row>
+		<row><td>PublishFeatures</td><td>##IDS_ACTIONTEXT_PublishProductFeatures##</td><td>##IDS_ACTIONTEXT_FeatureColon##</td></row>
+		<row><td>PublishProduct</td><td>##IDS_ACTIONTEXT_PublishProductInfo##</td><td/></row>
+		<row><td>RMCCPSearch</td><td>##IDS_ACTIONTEXT_SearchingQualifyingProducts##</td><td/></row>
+		<row><td>RegisterClassInfo</td><td>##IDS_ACTIONTEXT_RegisterClassServer##</td><td>##IDS_ACTIONTEXT_ClassId##</td></row>
+		<row><td>RegisterComPlus</td><td>##IDS_ACTIONTEXT_RegisteringComPlus##</td><td>##IDS_ACTIONTEXT_AppIdAppTypeRSN##</td></row>
+		<row><td>RegisterExtensionInfo</td><td>##IDS_ACTIONTEXT_RegisterExtensionServers##</td><td>##IDS_ACTIONTEXT_Extension2##</td></row>
+		<row><td>RegisterFonts</td><td>##IDS_ACTIONTEXT_RegisterFonts##</td><td>##IDS_ACTIONTEXT_Font##</td></row>
+		<row><td>RegisterMIMEInfo</td><td>##IDS_ACTIONTEXT_RegisterMimeInfo##</td><td>##IDS_ACTIONTEXT_ContentTypeExtension##</td></row>
+		<row><td>RegisterProduct</td><td>##IDS_ACTIONTEXT_RegisteringProduct##</td><td>##IDS_ACTIONTEXT_1b##</td></row>
+		<row><td>RegisterProgIdInfo</td><td>##IDS_ACTIONTEXT_RegisteringProgIdentifiers##</td><td>##IDS_ACTIONTEXT_ProgID2##</td></row>
+		<row><td>RegisterTypeLibraries</td><td>##IDS_ACTIONTEXT_RegisterTypeLibs##</td><td>##IDS_ACTIONTEXT_LibId##</td></row>
+		<row><td>RegisterUser</td><td>##IDS_ACTIONTEXT_RegUser##</td><td>##IDS_ACTIONTEXT_1c##</td></row>
+		<row><td>RemoveDuplicateFiles</td><td>##IDS_ACTIONTEXT_RemovingDuplicates##</td><td>##IDS_ACTIONTEXT_FileDir##</td></row>
+		<row><td>RemoveEnvironmentStrings</td><td>##IDS_ACTIONTEXT_UpdateEnvironmentStrings##</td><td>##IDS_ACTIONTEXT_NameValueAction2##</td></row>
+		<row><td>RemoveExistingProducts</td><td>##IDS_ACTIONTEXT_RemoveApps##</td><td>##IDS_ACTIONTEXT_AppCommandLine##</td></row>
+		<row><td>RemoveFiles</td><td>##IDS_ACTIONTEXT_RemovingFiles##</td><td>##IDS_ACTIONTEXT_FileDir2##</td></row>
+		<row><td>RemoveFolders</td><td>##IDS_ACTIONTEXT_RemovingFolders##</td><td>##IDS_ACTIONTEXT_Folder1##</td></row>
+		<row><td>RemoveIniValues</td><td>##IDS_ACTIONTEXT_RemovingIni##</td><td>##IDS_ACTIONTEXT_FileSectionKeyValue##</td></row>
+		<row><td>RemoveODBC</td><td>##IDS_ACTIONTEXT_RemovingODBC##</td><td/></row>
+		<row><td>RemoveRegistryValues</td><td>##IDS_ACTIONTEXT_RemovingRegistry##</td><td>##IDS_ACTIONTEXT_KeyName##</td></row>
+		<row><td>RemoveShortcuts</td><td>##IDS_ACTIONTEXT_RemovingShortcuts##</td><td>##IDS_ACTIONTEXT_Shortcut1##</td></row>
+		<row><td>Rollback</td><td>##IDS_ACTIONTEXT_RollingBack##</td><td>##IDS_ACTIONTEXT_1d##</td></row>
+		<row><td>RollbackCleanup</td><td>##IDS_ACTIONTEXT_RemovingBackup##</td><td>##IDS_ACTIONTEXT_File2##</td></row>
+		<row><td>SelfRegModules</td><td>##IDS_ACTIONTEXT_RegisteringModules##</td><td>##IDS_ACTIONTEXT_FileFolder##</td></row>
+		<row><td>SelfUnregModules</td><td>##IDS_ACTIONTEXT_UnregisterModules##</td><td>##IDS_ACTIONTEXT_FileFolder2##</td></row>
+		<row><td>SetODBCFolders</td><td>##IDS_ACTIONTEXT_InitializeODBCDirs##</td><td/></row>
+		<row><td>StartServices</td><td>##IDS_ACTIONTEXT_StartingServices##</td><td>##IDS_ACTIONTEXT_Service3##</td></row>
+		<row><td>StopServices</td><td>##IDS_ACTIONTEXT_StoppingServices##</td><td>##IDS_ACTIONTEXT_Service4##</td></row>
+		<row><td>UnmoveFiles</td><td>##IDS_ACTIONTEXT_RemovingMoved##</td><td>##IDS_ACTIONTEXT_FileDir3##</td></row>
+		<row><td>UnpublishComponents</td><td>##IDS_ACTIONTEXT_UnpublishQualified##</td><td>##IDS_ACTIONTEXT_ComponentIdQualifier2##</td></row>
+		<row><td>UnpublishFeatures</td><td>##IDS_ACTIONTEXT_UnpublishProductFeatures##</td><td>##IDS_ACTIONTEXT_Feature##</td></row>
+		<row><td>UnpublishProduct</td><td>##IDS_ACTIONTEXT_UnpublishingProductInfo##</td><td/></row>
+		<row><td>UnregisterClassInfo</td><td>##IDS_ACTIONTEXT_UnregisterClassServers##</td><td>##IDS_ACTIONTEXT_ClsID##</td></row>
+		<row><td>UnregisterComPlus</td><td>##IDS_ACTIONTEXT_UnregisteringComPlus##</td><td>##IDS_ACTIONTEXT_AppId##</td></row>
+		<row><td>UnregisterExtensionInfo</td><td>##IDS_ACTIONTEXT_UnregisterExtensionServers##</td><td>##IDS_ACTIONTEXT_Extension##</td></row>
+		<row><td>UnregisterFonts</td><td>##IDS_ACTIONTEXT_UnregisteringFonts##</td><td>##IDS_ACTIONTEXT_Font2##</td></row>
+		<row><td>UnregisterMIMEInfo</td><td>##IDS_ACTIONTEXT_UnregisteringMimeInfo##</td><td>##IDS_ACTIONTEXT_ContentTypeExtension2##</td></row>
+		<row><td>UnregisterProgIdInfo</td><td>##IDS_ACTIONTEXT_UnregisteringProgramIds##</td><td>##IDS_ACTIONTEXT_ProgID##</td></row>
+		<row><td>UnregisterTypeLibraries</td><td>##IDS_ACTIONTEXT_UnregTypeLibs##</td><td>##IDS_ACTIONTEXT_Libid2##</td></row>
+		<row><td>WriteEnvironmentStrings</td><td>##IDS_ACTIONTEXT_EnvironmentStrings##</td><td>##IDS_ACTIONTEXT_NameValueAction##</td></row>
+		<row><td>WriteIniValues</td><td>##IDS_ACTIONTEXT_WritingINI##</td><td>##IDS_ACTIONTEXT_FileSectionKeyValue2##</td></row>
+		<row><td>WriteRegistryValues</td><td>##IDS_ACTIONTEXT_WritingRegistry##</td><td>##IDS_ACTIONTEXT_KeyNameValue##</td></row>
+		<row><td>caCreateVRoots</td><td>##IDS_ACTIONTEXT_CreatingIISRoots##</td><td/></row>
+		<row><td>caRemoveVRoots</td><td>##IDS_ACTIONTEXT_RemovingIISRoots##</td><td/></row>
+	</table>
+
+	<table name="AdminExecuteSequence">
+		<col key="yes" def="s72">Action</col>
+		<col def="S255">Condition</col>
+		<col def="I2">Sequence</col>
+		<col def="S255">ISComments</col>
+		<col def="I4">ISAttributes</col>
+		<row><td>CostFinalize</td><td/><td>1000</td><td>CostFinalize</td><td/></row>
+		<row><td>CostInitialize</td><td/><td>800</td><td>CostInitialize</td><td/></row>
+		<row><td>FileCost</td><td/><td>900</td><td>FileCost</td><td/></row>
+		<row><td>InstallAdminPackage</td><td/><td>3900</td><td>InstallAdminPackage</td><td/></row>
+		<row><td>InstallFiles</td><td/><td>4000</td><td>InstallFiles</td><td/></row>
+		<row><td>InstallFinalize</td><td/><td>6600</td><td>InstallFinalize</td><td/></row>
+		<row><td>InstallInitialize</td><td/><td>1500</td><td>InstallInitialize</td><td/></row>
+		<row><td>InstallValidate</td><td/><td>1400</td><td>InstallValidate</td><td/></row>
+		<row><td>ScheduleReboot</td><td>ISSCHEDULEREBOOT</td><td>4010</td><td>ScheduleReboot</td><td/></row>
+	</table>
+
+	<table name="AdminUISequence">
+		<col key="yes" def="s72">Action</col>
+		<col def="S255">Condition</col>
+		<col def="I2">Sequence</col>
+		<col def="S255">ISComments</col>
+		<col def="I4">ISAttributes</col>
+		<row><td>AdminWelcome</td><td/><td>1010</td><td>AdminWelcome</td><td/></row>
+		<row><td>CostFinalize</td><td/><td>1000</td><td>CostFinalize</td><td/></row>
+		<row><td>CostInitialize</td><td/><td>800</td><td>CostInitialize</td><td/></row>
+		<row><td>ExecuteAction</td><td/><td>1300</td><td>ExecuteAction</td><td/></row>
+		<row><td>FileCost</td><td/><td>900</td><td>FileCost</td><td/></row>
+		<row><td>SetupCompleteError</td><td/><td>-3</td><td>SetupCompleteError</td><td/></row>
+		<row><td>SetupCompleteSuccess</td><td/><td>-1</td><td>SetupCompleteSuccess</td><td/></row>
+		<row><td>SetupInitialization</td><td/><td>50</td><td>SetupInitialization</td><td/></row>
+		<row><td>SetupInterrupted</td><td/><td>-2</td><td>SetupInterrupted</td><td/></row>
+		<row><td>SetupProgress</td><td/><td>1020</td><td>SetupProgress</td><td/></row>
+	</table>
+
+	<table name="AdvtExecuteSequence">
+		<col key="yes" def="s72">Action</col>
+		<col def="S255">Condition</col>
+		<col def="I2">Sequence</col>
+		<col def="S255">ISComments</col>
+		<col def="I4">ISAttributes</col>
+		<row><td>CostFinalize</td><td/><td>1000</td><td>CostFinalize</td><td/></row>
+		<row><td>CostInitialize</td><td/><td>800</td><td>CostInitialize</td><td/></row>
+		<row><td>CreateShortcuts</td><td/><td>4500</td><td>CreateShortcuts</td><td/></row>
+		<row><td>InstallFinalize</td><td/><td>6600</td><td>InstallFinalize</td><td/></row>
+		<row><td>InstallInitialize</td><td/><td>1500</td><td>InstallInitialize</td><td/></row>
+		<row><td>InstallValidate</td><td/><td>1400</td><td>InstallValidate</td><td/></row>
+		<row><td>MsiPublishAssemblies</td><td/><td>6250</td><td>MsiPublishAssemblies</td><td/></row>
+		<row><td>PublishComponents</td><td/><td>6200</td><td>PublishComponents</td><td/></row>
+		<row><td>PublishFeatures</td><td/><td>6300</td><td>PublishFeatures</td><td/></row>
+		<row><td>PublishProduct</td><td/><td>6400</td><td>PublishProduct</td><td/></row>
+		<row><td>RegisterClassInfo</td><td/><td>4600</td><td>RegisterClassInfo</td><td/></row>
+		<row><td>RegisterExtensionInfo</td><td/><td>4700</td><td>RegisterExtensionInfo</td><td/></row>
+		<row><td>RegisterMIMEInfo</td><td/><td>4900</td><td>RegisterMIMEInfo</td><td/></row>
+		<row><td>RegisterProgIdInfo</td><td/><td>4800</td><td>RegisterProgIdInfo</td><td/></row>
+		<row><td>RegisterTypeLibraries</td><td/><td>4910</td><td>RegisterTypeLibraries</td><td/></row>
+		<row><td>ScheduleReboot</td><td>ISSCHEDULEREBOOT</td><td>6410</td><td>ScheduleReboot</td><td/></row>
+	</table>
+
+	<table name="AdvtUISequence">
+		<col key="yes" def="s72">Action</col>
+		<col def="S255">Condition</col>
+		<col def="I2">Sequence</col>
+		<col def="S255">ISComments</col>
+		<col def="I4">ISAttributes</col>
+	</table>
+
+	<table name="AppId">
+		<col key="yes" def="s38">AppId</col>
+		<col def="S255">RemoteServerName</col>
+		<col def="S255">LocalService</col>
+		<col def="S255">ServiceParameters</col>
+		<col def="S255">DllSurrogate</col>
+		<col def="I2">ActivateAtStorage</col>
+		<col def="I2">RunAsInteractiveUser</col>
+	</table>
+
+	<table name="AppSearch">
+		<col key="yes" def="s72">Property</col>
+		<col key="yes" def="s72">Signature_</col>
+		<row><td>IISROOTFOLDER</td><td>_IISROOTFOLDER</td></row>
+		<row><td>IIS_VERSION</td><td>_IIS_VERSION</td></row>
+	</table>
+
+	<table name="BBControl">
+		<col key="yes" def="s50">Billboard_</col>
+		<col key="yes" def="s50">BBControl</col>
+		<col def="s50">Type</col>
+		<col def="i2">X</col>
+		<col def="i2">Y</col>
+		<col def="i2">Width</col>
+		<col def="i2">Height</col>
+		<col def="I4">Attributes</col>
+		<col def="L50">Text</col>
+	</table>
+
+	<table name="Billboard">
+		<col key="yes" def="s50">Billboard</col>
+		<col def="s38">Feature_</col>
+		<col def="S50">Action</col>
+		<col def="I2">Ordering</col>
+	</table>
+
+	<table name="Binary">
+		<col key="yes" def="s72">Name</col>
+		<col def="V0">Data</col>
+		<col def="S255">ISBuildSourcePath</col>
+		<row><td>ISSELFREG.DLL</td><td/><td>&lt;ISProductFolder&gt;\redist\language independent\i386\isregsvr.dll</td></row>
+		<row><td>NewBinary1</td><td/><td>&lt;ISProductFolder&gt;\Redist\Language Independent\OS Independent\IsDialogBanner.ibd</td></row>
+		<row><td>NewBinary10</td><td/><td>&lt;ISProductFolder&gt;\Redist\Language Independent\OS Independent\CompleteSetupIco.ibd</td></row>
+		<row><td>NewBinary11</td><td/><td>&lt;ISProductFolder&gt;\Redist\Language Independent\OS Independent\CustomSetupIco.ibd</td></row>
+		<row><td>NewBinary12</td><td/><td>&lt;ISProductFolder&gt;\Redist\Language Independent\OS Independent\DestIcon.ibd</td></row>
+		<row><td>NewBinary13</td><td/><td>&lt;ISProductFolder&gt;\Redist\Language Independent\OS Independent\NetworkInstall.ico</td></row>
+		<row><td>NewBinary14</td><td/><td>&lt;ISProductFolder&gt;\Redist\Language Independent\OS Independent\DontInstall.ico</td></row>
+		<row><td>NewBinary15</td><td/><td>&lt;ISProductFolder&gt;\Redist\Language Independent\OS Independent\Install.ico</td></row>
+		<row><td>NewBinary16</td><td/><td>&lt;ISProductFolder&gt;\Redist\Language Independent\OS Independent\InstallFirstUse.ico</td></row>
+		<row><td>NewBinary17</td><td/><td>&lt;ISProductFolder&gt;\Redist\Language Independent\OS Independent\InstallPartial.ico</td></row>
+		<row><td>NewBinary18</td><td/><td>&lt;ISProductFolder&gt;\Redist\Language Independent\OS Independent\InstallStateMenu.ico</td></row>
+		<row><td>NewBinary19</td><td/><td>&lt;ISProjectFolder&gt;\iisfilter.vbs</td></row>
+		<row><td>NewBinary2</td><td/><td>&lt;ISProductFolder&gt;\Redist\Language Independent\OS Independent\New.ibd</td></row>
+		<row><td>NewBinary3</td><td/><td>&lt;ISProductFolder&gt;\Redist\Language Independent\OS Independent\Up.ibd</td></row>
+		<row><td>NewBinary4</td><td/><td>&lt;ISProductFolder&gt;\Redist\Language Independent\OS Independent\WarningIcon.ibd</td></row>
+		<row><td>NewBinary5</td><td/><td>&lt;ISProductFolder&gt;\Redist\Language Independent\OS Independent\IsDialogBitmap.ibd</td></row>
+		<row><td>NewBinary6</td><td/><td>&lt;ISProductFolder&gt;\Redist\Language Independent\OS Independent\CustomSetupIco.ibd</td></row>
+		<row><td>NewBinary7</td><td/><td>&lt;ISProductFolder&gt;\Redist\Language Independent\OS Independent\ReinstIco.ibd</td></row>
+		<row><td>NewBinary8</td><td/><td>&lt;ISProductFolder&gt;\Redist\Language Independent\OS Independent\RemoveIco.ibd</td></row>
+		<row><td>NewBinary9</td><td/><td>&lt;ISProductFolder&gt;\Redist\Language Independent\OS Independent\SetupIcon.ibd</td></row>
+		<row><td>SetAllUsers.dll</td><td/><td>&lt;ISProductFolder&gt;\redist\language independent\i386\SetAllUsers.dll</td></row>
+		<row><td>binIISHelper</td><td/><td>&lt;ISProductFolder&gt;\Support\IISHelper.dll</td></row>
+	</table>
+
+	<table name="BindImage">
+		<col key="yes" def="s72">File_</col>
+		<col def="S255">Path</col>
+	</table>
+
+	<table name="CCPSearch">
+		<col key="yes" def="s72">Signature_</col>
+	</table>
+
+	<table name="CheckBox">
+		<col key="yes" def="s72">Property</col>
+		<col def="S64">Value</col>
+		<row><td>ISCHECKFORPRODUCTUPDATES</td><td>1</td></row>
+		<row><td>LAUNCHPROGRAM</td><td>1</td></row>
+	</table>
+
+	<table name="Class">
+		<col key="yes" def="s38">CLSID</col>
+		<col key="yes" def="s32">Context</col>
+		<col key="yes" def="s72">Component_</col>
+		<col def="S255">ProgId_Default</col>
+		<col def="L255">Description</col>
+		<col def="S38">AppId_</col>
+		<col def="S255">FileTypeMask</col>
+		<col def="S72">Icon_</col>
+		<col def="I2">IconIndex</col>
+		<col def="S32">DefInprocHandler</col>
+		<col def="S255">Argument</col>
+		<col def="s38">Feature_</col>
+		<col def="I2">Attributes</col>
+	</table>
+
+	<table name="ComboBox">
+		<col key="yes" def="s72">Property</col>
+		<col key="yes" def="i2">Order</col>
+		<col def="s64">Value</col>
+		<col def="L64">Text</col>
+	</table>
+
+	<table name="CompLocator">
+		<col key="yes" def="s72">Signature_</col>
+		<col def="s38">ComponentId</col>
+		<col def="I2">Type</col>
+	</table>
+
+	<table name="Complus">
+		<col key="yes" def="s72">Component_</col>
+		<col key="yes" def="I2">ExpType</col>
+	</table>
+
+	<table name="Component">
+		<col key="yes" def="s72">Component</col>
+		<col def="S38">ComponentId</col>
+		<col def="s72">Directory_</col>
+		<col def="i2">Attributes</col>
+		<col def="S255">Condition</col>
+		<col def="S72">KeyPath</col>
+		<col def="I4">ISAttributes</col>
+		<col def="S255">ISComments</col>
+		<col def="S255">ISScanAtBuildFile</col>
+		<col def="S255">ISRegFileToMergeAtBuild</col>
+		<col def="S0">ISDotNetInstallerArgsInstall</col>
+		<col def="S0">ISDotNetInstallerArgsCommit</col>
+		<col def="S0">ISDotNetInstallerArgsUninstall</col>
+		<col def="S0">ISDotNetInstallerArgsRollback</col>
+		<row><td>AllOtherFiles</td><td>{01621138-5B6F-47D3-B183-8F6107690955}</td><td>BIN</td><td>8</td><td/><td/><td>17</td><td/><td/><td/><td>/LogFile=</td><td>/LogFile=</td><td>/LogFile=</td><td>/LogFile=</td></row>
+		<row><td>AllOtherFiles1</td><td>{918FECBF-6B1D-4648-A0C9-BAE694AB1DF3}</td><td>CONF</td><td>8</td><td/><td/><td>17</td><td/><td/><td/><td>/LogFile=</td><td>/LogFile=</td><td>/LogFile=</td><td>/LogFile=</td></row>
+		<row><td>AllOtherFiles10</td><td>{E461BDCC-5045-469B-96DF-CDB381D7413E}</td><td>BIN</td><td>8</td><td/><td/><td>17</td><td/><td/><td/><td>/LogFile=</td><td>/LogFile=</td><td>/LogFile=</td><td>/LogFile=</td></row>
+		<row><td>AllOtherFiles11</td><td>{BE301E37-3373-4655-B6E0-B39ACCEC85DB}</td><td>BIN</td><td>8</td><td/><td/><td>17</td><td/><td/><td/><td>/LogFile=</td><td>/LogFile=</td><td>/LogFile=</td><td>/LogFile=</td></row>
+		<row><td>AllOtherFiles12</td><td>{CEBD938A-39BA-4ACD-94F4-E87FF5D65383}</td><td>LOG</td><td>8</td><td/><td/><td>17</td><td/><td/><td/><td>/LogFile=</td><td>/LogFile=</td><td>/LogFile=</td><td>/LogFile=</td></row>
+		<row><td>AllOtherFiles2</td><td>{BC4C5E05-7E81-40D6-A477-29D1658190F8}</td><td>LOG</td><td>8</td><td/><td/><td>17</td><td/><td/><td/><td>/LogFile=</td><td>/LogFile=</td><td>/LogFile=</td><td>/LogFile=</td></row>
+		<row><td>AllOtherFiles3</td><td>{66FFA73A-17D7-46D7-911F-3E515C813FFC}</td><td>INSTALLDIR</td><td>8</td><td/><td/><td>17</td><td/><td/><td/><td>/LogFile=</td><td>/LogFile=</td><td>/LogFile=</td><td>/LogFile=</td></row>
+		<row><td>AllOtherFiles4</td><td>{F7546761-05DF-4ED7-9F6D-854F42CE2333}</td><td>INSTALLDIR</td><td>8</td><td/><td/><td>145</td><td/><td/><td/><td>/LogFile=</td><td>/LogFile=</td><td>/LogFile=</td><td>/LogFile=</td></row>
+		<row><td>AllOtherFiles5</td><td>{56403C1F-20CA-423C-A296-D95AB3E1E7FF}</td><td>CONF</td><td>8</td><td/><td/><td>17</td><td/><td/><td/><td>/LogFile=</td><td>/LogFile=</td><td>/LogFile=</td><td>/LogFile=</td></row>
+		<row><td>AllOtherFiles6</td><td>{2D786CD4-E0CB-47FF-9981-F3F1FC266B1A}</td><td>INSTALLDIR</td><td>8</td><td/><td/><td>17</td><td/><td/><td/><td>/LogFile=</td><td>/LogFile=</td><td>/LogFile=</td><td>/LogFile=</td></row>
+		<row><td>AllOtherFiles7</td><td>{990D5874-56BB-457E-A316-C048C7AF214A}</td><td>INSTALLDIR</td><td>8</td><td/><td/><td>17</td><td/><td/><td/><td>/LogFile=</td><td>/LogFile=</td><td>/LogFile=</td><td>/LogFile=</td></row>
+		<row><td>AllOtherFiles8</td><td>{C8EC2CC3-13A1-4EED-B195-D44739A00048}</td><td>BIN</td><td>8</td><td/><td/><td>145</td><td/><td/><td/><td>/LogFile=</td><td>/LogFile=</td><td>/LogFile=</td><td>/LogFile=</td></row>
+		<row><td>AllOtherFiles9</td><td>{80382F22-06B4-4290-B60B-908D38ECBA4D}</td><td>CONF</td><td>8</td><td/><td/><td>17</td><td/><td/><td/><td>/LogFile=</td><td>/LogFile=</td><td>/LogFile=</td><td>/LogFile=</td></row>
+		<row><td>ISRegistryComponent</td><td>{60AC5270-5430-4CC4-AF22-BE198804A039}</td><td>INSTALLDIR</td><td>8</td><td/><td/><td>17</td><td/><td/><td/><td>/LogFile=</td><td>/LogFile=</td><td>/LogFile=</td><td>/LogFile=</td></row>
+		<row><td>ISRegistryComponent1</td><td>{695FA56F-E422-429B-AA91-884E5F5DEDCF}</td><td>INSTALLDIR</td><td>8</td><td/><td/><td>17</td><td/><td/><td/><td>/LogFile=</td><td>/LogFile=</td><td>/LogFile=</td><td>/LogFile=</td></row>
+		<row><td>VirtualDirComponent</td><td>{F2BD5AC6-AB0C-4ED5-889E-148870C25009}</td><td>INSTALLDIR</td><td>8</td><td/><td/><td>17</td><td/><td/><td/><td>/LogFile=</td><td>/LogFile=</td><td>/LogFile=</td><td>/LogFile=</td></row>
+	</table>
+
+	<table name="Condition">
+		<col key="yes" def="s38">Feature_</col>
+		<col key="yes" def="i2">Level</col>
+		<col def="S255">Condition</col>
+	</table>
+
+	<table name="Control">
+		<col key="yes" def="s72">Dialog_</col>
+		<col key="yes" def="s50">Control</col>
+		<col def="s20">Type</col>
+		<col def="i2">X</col>
+		<col def="i2">Y</col>
+		<col def="i2">Width</col>
+		<col def="i2">Height</col>
+		<col def="I4">Attributes</col>
+		<col def="S72">Property</col>
+		<col def="L0">Text</col>
+		<col def="S50">Control_Next</col>
+		<col def="L50">Help</col>
+		<col def="I4">ISWindowStyle</col>
+		<col def="I4">ISControlId</col>
+		<col def="S255">ISBuildSourcePath</col>
+		<col def="S72">Binary_</col>
+		<row><td>AdminChangeFolder</td><td>Banner</td><td>Bitmap</td><td>0</td><td>0</td><td>374</td><td>44</td><td>1</td><td/><td/><td/><td/><td>0</td><td/><td/><td>NewBinary1</td></row>
+		<row><td>AdminChangeFolder</td><td>BannerLine</td><td>Line</td><td>0</td><td>44</td><td>374</td><td>0</td><td>1</td><td/><td/><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>AdminChangeFolder</td><td>Branding1</td><td>Text</td><td>4</td><td>229</td><td>50</td><td>13</td><td>3</td><td/><td>##IDS_INSTALLSHIELD_FORMATTED##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>AdminChangeFolder</td><td>Branding2</td><td>Text</td><td>3</td><td>228</td><td>50</td><td>13</td><td>65537</td><td/><td>##IDS_INSTALLSHIELD##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>AdminChangeFolder</td><td>Cancel</td><td>PushButton</td><td>301</td><td>243</td><td>66</td><td>17</td><td>3</td><td/><td>##IDS_CANCEL##</td><td>ComboText</td><td/><td>0</td><td/><td/><td/></row>
+		<row><td>AdminChangeFolder</td><td>Combo</td><td>DirectoryCombo</td><td>21</td><td>64</td><td>277</td><td>80</td><td>458755</td><td>TARGETDIR</td><td>##IDS__IsAdminInstallBrowse_4##</td><td>Up</td><td/><td>0</td><td/><td/><td/></row>
+		<row><td>AdminChangeFolder</td><td>ComboText</td><td>Text</td><td>21</td><td>50</td><td>99</td><td>14</td><td>3</td><td/><td>##IDS__IsAdminInstallBrowse_LookIn##</td><td>Combo</td><td/><td>0</td><td/><td/><td/></row>
+		<row><td>AdminChangeFolder</td><td>DlgDesc</td><td>Text</td><td>21</td><td>23</td><td>292</td><td>25</td><td>65539</td><td/><td>##IDS__IsAdminInstallBrowse_BrowseDestination##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>AdminChangeFolder</td><td>DlgLine</td><td>Line</td><td>48</td><td>234</td><td>326</td><td>0</td><td>1</td><td/><td/><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>AdminChangeFolder</td><td>DlgTitle</td><td>Text</td><td>13</td><td>6</td><td>292</td><td>25</td><td>65539</td><td/><td>##IDS__IsAdminInstallBrowse_ChangeDestination##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>AdminChangeFolder</td><td>List</td><td>DirectoryList</td><td>21</td><td>90</td><td>332</td><td>97</td><td>7</td><td>TARGETDIR</td><td>##IDS__IsAdminInstallBrowse_8##</td><td>TailText</td><td/><td>0</td><td/><td/><td/></row>
+		<row><td>AdminChangeFolder</td><td>NewFolder</td><td>PushButton</td><td>335</td><td>66</td><td>19</td><td>19</td><td>3670019</td><td/><td/><td>List</td><td>##IDS__IsAdminInstallBrowse_CreateFolder##</td><td>0</td><td/><td/><td>NewBinary2</td></row>
+		<row><td>AdminChangeFolder</td><td>OK</td><td>PushButton</td><td>230</td><td>243</td><td>66</td><td>17</td><td>3</td><td/><td>##IDS_OK##</td><td>Cancel</td><td/><td>0</td><td/><td/><td/></row>
+		<row><td>AdminChangeFolder</td><td>Tail</td><td>PathEdit</td><td>21</td><td>207</td><td>332</td><td>17</td><td>3</td><td>TARGETDIR</td><td>##IDS__IsAdminInstallBrowse_11##</td><td>OK</td><td/><td>0</td><td/><td/><td/></row>
+		<row><td>AdminChangeFolder</td><td>TailText</td><td>Text</td><td>21</td><td>193</td><td>99</td><td>13</td><td>3</td><td/><td>##IDS__IsAdminInstallBrowse_FolderName##</td><td>Tail</td><td/><td>0</td><td/><td/><td/></row>
+		<row><td>AdminChangeFolder</td><td>Up</td><td>PushButton</td><td>310</td><td>66</td><td>19</td><td>19</td><td>3670019</td><td/><td/><td>NewFolder</td><td>##IDS__IsAdminInstallBrowse_UpOneLevel##</td><td>0</td><td/><td/><td>NewBinary3</td></row>
+		<row><td>AdminNetworkLocation</td><td>Back</td><td>PushButton</td><td>164</td><td>243</td><td>66</td><td>17</td><td>3</td><td/><td>##IDS_BACK##</td><td>InstallNow</td><td/><td>0</td><td/><td/><td/></row>
+		<row><td>AdminNetworkLocation</td><td>Banner</td><td>Bitmap</td><td>0</td><td>0</td><td>374</td><td>44</td><td>1</td><td/><td/><td/><td/><td>0</td><td/><td/><td>NewBinary1</td></row>
+		<row><td>AdminNetworkLocation</td><td>BannerLine</td><td>Line</td><td>0</td><td>44</td><td>374</td><td>0</td><td>1</td><td/><td/><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>AdminNetworkLocation</td><td>Branding1</td><td>Text</td><td>4</td><td>229</td><td>50</td><td>13</td><td>3</td><td/><td>##IDS_INSTALLSHIELD_FORMATTED##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>AdminNetworkLocation</td><td>Branding2</td><td>Text</td><td>3</td><td>228</td><td>50</td><td>13</td><td>65537</td><td/><td>##IDS_INSTALLSHIELD##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>AdminNetworkLocation</td><td>Browse</td><td>PushButton</td><td>286</td><td>124</td><td>66</td><td>17</td><td>3</td><td/><td>##IDS__IsAdminInstallPoint_Change##</td><td>Back</td><td/><td>0</td><td/><td/><td/></row>
+		<row><td>AdminNetworkLocation</td><td>Cancel</td><td>PushButton</td><td>301</td><td>243</td><td>66</td><td>17</td><td>3</td><td/><td>##IDS_CANCEL##</td><td>SetupPathEdit</td><td/><td>0</td><td/><td/><td/></row>
+		<row><td>AdminNetworkLocation</td><td>DlgDesc</td><td>Text</td><td>21</td><td>23</td><td>292</td><td>25</td><td>65539</td><td/><td>##IDS__IsAdminInstallPoint_SpecifyNetworkLocation##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>AdminNetworkLocation</td><td>DlgLine</td><td>Line</td><td>48</td><td>234</td><td>326</td><td>0</td><td>1</td><td/><td/><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>AdminNetworkLocation</td><td>DlgText</td><td>Text</td><td>21</td><td>51</td><td>326</td><td>40</td><td>3</td><td/><td>##IDS__IsAdminInstallPoint_EnterNetworkLocation##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>AdminNetworkLocation</td><td>DlgTitle</td><td>Text</td><td>13</td><td>6</td><td>292</td><td>25</td><td>65539</td><td/><td>##IDS__IsAdminInstallPoint_NetworkLocationFormatted##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>AdminNetworkLocation</td><td>InstallNow</td><td>PushButton</td><td>230</td><td>243</td><td>66</td><td>17</td><td>3</td><td/><td>##IDS__IsAdminInstallPoint_Install##</td><td>Cancel</td><td/><td>0</td><td/><td/><td/></row>
+		<row><td>AdminNetworkLocation</td><td>LBBrowse</td><td>Text</td><td>21</td><td>90</td><td>100</td><td>10</td><td>3</td><td/><td>##IDS__IsAdminInstallPoint_NetworkLocation##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>AdminNetworkLocation</td><td>SetupPathEdit</td><td>PathEdit</td><td>21</td><td>102</td><td>330</td><td>17</td><td>3</td><td>TARGETDIR</td><td/><td>Browse</td><td/><td>0</td><td/><td/><td/></row>
+		<row><td>AdminWelcome</td><td>Back</td><td>PushButton</td><td>164</td><td>243</td><td>66</td><td>17</td><td>1</td><td/><td>##IDS_BACK##</td><td>Next</td><td/><td>0</td><td/><td/><td/></row>
+		<row><td>AdminWelcome</td><td>Cancel</td><td>PushButton</td><td>301</td><td>243</td><td>66</td><td>17</td><td>3</td><td/><td>##IDS_CANCEL##</td><td>Back</td><td/><td>0</td><td/><td/><td/></row>
+		<row><td>AdminWelcome</td><td>DlgLine</td><td>Line</td><td>0</td><td>234</td><td>326</td><td>0</td><td>1</td><td/><td/><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>AdminWelcome</td><td>Image</td><td>Bitmap</td><td>0</td><td>0</td><td>374</td><td>234</td><td>1</td><td/><td/><td/><td/><td>0</td><td/><td/><td>NewBinary5</td></row>
+		<row><td>AdminWelcome</td><td>Next</td><td>PushButton</td><td>230</td><td>243</td><td>66</td><td>17</td><td>3</td><td/><td>##IDS_NEXT##</td><td>Cancel</td><td/><td>0</td><td/><td/><td/></row>
+		<row><td>AdminWelcome</td><td>TextLine1</td><td>Text</td><td>135</td><td>8</td><td>225</td><td>45</td><td>65539</td><td/><td>##IDS__IsAdminInstallPointWelcome_Wizard##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>AdminWelcome</td><td>TextLine2</td><td>Text</td><td>135</td><td>55</td><td>228</td><td>45</td><td>65539</td><td/><td>##IDS__IsAdminInstallPointWelcome_ServerImage##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>CancelSetup</td><td>Icon</td><td>Icon</td><td>15</td><td>15</td><td>24</td><td>24</td><td>5242881</td><td/><td/><td/><td/><td>0</td><td/><td/><td>NewBinary4</td></row>
+		<row><td>CancelSetup</td><td>No</td><td>PushButton</td><td>135</td><td>57</td><td>66</td><td>17</td><td>3</td><td/><td>##IDS__IsCancelDlg_No##</td><td>Yes</td><td/><td>0</td><td/><td/><td/></row>
+		<row><td>CancelSetup</td><td>Text</td><td>Text</td><td>48</td><td>15</td><td>194</td><td>30</td><td>3</td><td/><td>##IDS__IsCancelDlg_ConfirmCancel##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>CancelSetup</td><td>Yes</td><td>PushButton</td><td>62</td><td>57</td><td>66</td><td>17</td><td>3</td><td/><td>##IDS__IsCancelDlg_Yes##</td><td>No</td><td/><td>0</td><td/><td/><td/></row>
+		<row><td>CustomSetup</td><td>Back</td><td>PushButton</td><td>164</td><td>243</td><td>66</td><td>17</td><td>3</td><td/><td>##IDS_BACK##</td><td>Next</td><td/><td>0</td><td/><td/><td/></row>
+		<row><td>CustomSetup</td><td>Banner</td><td>Bitmap</td><td>0</td><td>0</td><td>374</td><td>44</td><td>1</td><td/><td/><td/><td/><td>0</td><td/><td/><td>NewBinary1</td></row>
+		<row><td>CustomSetup</td><td>BannerLine</td><td>Line</td><td>0</td><td>44</td><td>374</td><td>0</td><td>1</td><td/><td/><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>CustomSetup</td><td>Branding1</td><td>Text</td><td>4</td><td>229</td><td>50</td><td>13</td><td>3</td><td/><td>##IDS_INSTALLSHIELD_FORMATTED##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>CustomSetup</td><td>Branding2</td><td>Text</td><td>3</td><td>228</td><td>50</td><td>13</td><td>65537</td><td/><td>##IDS_INSTALLSHIELD##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>CustomSetup</td><td>Cancel</td><td>PushButton</td><td>301</td><td>243</td><td>66</td><td>17</td><td>3</td><td/><td>##IDS_CANCEL##</td><td>Tree</td><td/><td>0</td><td/><td/><td/></row>
+		<row><td>CustomSetup</td><td>ChangeFolder</td><td>PushButton</td><td>301</td><td>203</td><td>66</td><td>17</td><td>3</td><td/><td>##IDS__IsCustomSelectionDlg_Change##</td><td>Help</td><td/><td>0</td><td/><td/><td/></row>
+		<row><td>CustomSetup</td><td>Details</td><td>PushButton</td><td>93</td><td>243</td><td>66</td><td>17</td><td>3</td><td/><td>##IDS__IsCustomSelectionDlg_Space##</td><td>Back</td><td/><td>0</td><td/><td/><td/></row>
+		<row><td>CustomSetup</td><td>DlgDesc</td><td>Text</td><td>17</td><td>23</td><td>292</td><td>25</td><td>65539</td><td/><td>##IDS__IsCustomSelectionDlg_SelectFeatures##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>CustomSetup</td><td>DlgLine</td><td>Line</td><td>48</td><td>234</td><td>326</td><td>0</td><td>1</td><td/><td/><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>CustomSetup</td><td>DlgText</td><td>Text</td><td>9</td><td>51</td><td>360</td><td>10</td><td>3</td><td/><td>##IDS__IsCustomSelectionDlg_ClickFeatureIcon##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>CustomSetup</td><td>DlgTitle</td><td>Text</td><td>9</td><td>6</td><td>292</td><td>25</td><td>65539</td><td/><td>##IDS__IsCustomSelectionDlg_CustomSetup##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>CustomSetup</td><td>FeatureGroup</td><td>GroupBox</td><td>235</td><td>67</td><td>131</td><td>120</td><td>1</td><td/><td>##IDS__IsCustomSelectionDlg_FeatureDescription##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>CustomSetup</td><td>Help</td><td>PushButton</td><td>22</td><td>243</td><td>66</td><td>17</td><td>3</td><td/><td>##IDS__IsCustomSelectionDlg_Help##</td><td>Details</td><td/><td>0</td><td/><td/><td/></row>
+		<row><td>CustomSetup</td><td>InstallLabel</td><td>Text</td><td>8</td><td>190</td><td>360</td><td>10</td><td>3</td><td/><td>##IDS__IsCustomSelectionDlg_InstallTo##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>CustomSetup</td><td>ItemDescription</td><td>Text</td><td>241</td><td>80</td><td>120</td><td>50</td><td>3</td><td/><td>##IDS__IsCustomSelectionDlg_MultilineDescription##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>CustomSetup</td><td>Location</td><td>Text</td><td>8</td><td>203</td><td>291</td><td>20</td><td>3</td><td/><td>##IDS__IsCustomSelectionDlg_FeaturePath##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>CustomSetup</td><td>Next</td><td>PushButton</td><td>230</td><td>243</td><td>66</td><td>17</td><td>3</td><td/><td>##IDS_NEXT##</td><td>Cancel</td><td/><td>0</td><td/><td/><td/></row>
+		<row><td>CustomSetup</td><td>Size</td><td>Text</td><td>241</td><td>133</td><td>120</td><td>50</td><td>3</td><td/><td>##IDS__IsCustomSelectionDlg_FeatureSize##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>CustomSetup</td><td>Tree</td><td>SelectionTree</td><td>8</td><td>70</td><td>220</td><td>118</td><td>7</td><td>_BrowseProperty</td><td/><td>ChangeFolder</td><td/><td>0</td><td/><td/><td/></row>
+		<row><td>CustomSetupTips</td><td>Banner</td><td>Bitmap</td><td>0</td><td>0</td><td>374</td><td>44</td><td>1</td><td/><td/><td/><td/><td>0</td><td/><td/><td>NewBinary1</td></row>
+		<row><td>CustomSetupTips</td><td>BannerLine</td><td>Line</td><td>0</td><td>44</td><td>374</td><td>0</td><td>1</td><td/><td/><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>CustomSetupTips</td><td>Branding1</td><td>Text</td><td>4</td><td>229</td><td>50</td><td>13</td><td>3</td><td/><td>##IDS_INSTALLSHIELD_FORMATTED##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>CustomSetupTips</td><td>Branding2</td><td>Text</td><td>3</td><td>228</td><td>50</td><td>13</td><td>65537</td><td/><td>##IDS_INSTALLSHIELD##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>CustomSetupTips</td><td>DlgDesc</td><td>Text</td><td>21</td><td>23</td><td>292</td><td>25</td><td>65539</td><td/><td>##IDS_SetupTips_CustomSetupDescription##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>CustomSetupTips</td><td>DlgLine</td><td>Line</td><td>48</td><td>234</td><td>326</td><td>0</td><td>1</td><td/><td/><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>CustomSetupTips</td><td>DlgTitle</td><td>Text</td><td>13</td><td>6</td><td>292</td><td>25</td><td>65539</td><td/><td>##IDS_SetupTips_CustomSetup##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>CustomSetupTips</td><td>DontInstall</td><td>Icon</td><td>21</td><td>155</td><td>24</td><td>24</td><td>5242881</td><td/><td/><td/><td/><td>0</td><td/><td/><td>NewBinary14</td></row>
+		<row><td>CustomSetupTips</td><td>DontInstallText</td><td>Text</td><td>60</td><td>155</td><td>300</td><td>20</td><td>3</td><td/><td>##IDS_SetupTips_WillNotBeInstalled##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>CustomSetupTips</td><td>FirstInstallText</td><td>Text</td><td>60</td><td>180</td><td>300</td><td>20</td><td>3</td><td/><td>##IDS_SetupTips_Advertise##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>CustomSetupTips</td><td>Install</td><td>Icon</td><td>21</td><td>105</td><td>24</td><td>24</td><td>5242881</td><td/><td/><td/><td/><td>0</td><td/><td/><td>NewBinary15</td></row>
+		<row><td>CustomSetupTips</td><td>InstallFirstUse</td><td>Icon</td><td>21</td><td>180</td><td>24</td><td>24</td><td>5242881</td><td/><td/><td/><td/><td>0</td><td/><td/><td>NewBinary16</td></row>
+		<row><td>CustomSetupTips</td><td>InstallPartial</td><td>Icon</td><td>21</td><td>130</td><td>24</td><td>24</td><td>5242881</td><td/><td/><td/><td/><td>0</td><td/><td/><td>NewBinary17</td></row>
+		<row><td>CustomSetupTips</td><td>InstallStateMenu</td><td>Icon</td><td>21</td><td>52</td><td>24</td><td>24</td><td>5242881</td><td/><td/><td/><td/><td>0</td><td/><td/><td>NewBinary18</td></row>
+		<row><td>CustomSetupTips</td><td>InstallStateText</td><td>Text</td><td>21</td><td>91</td><td>300</td><td>10</td><td>3</td><td/><td>##IDS_SetupTips_InstallState##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>CustomSetupTips</td><td>InstallText</td><td>Text</td><td>60</td><td>105</td><td>300</td><td>20</td><td>3</td><td/><td>##IDS_SetupTips_AllInstalledLocal##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>CustomSetupTips</td><td>MenuText</td><td>Text</td><td>50</td><td>52</td><td>300</td><td>36</td><td>3</td><td/><td>##IDS_SetupTips_IconInstallState##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>CustomSetupTips</td><td>NetworkInstall</td><td>Icon</td><td>21</td><td>205</td><td>24</td><td>24</td><td>5242881</td><td/><td/><td/><td/><td>0</td><td/><td/><td>NewBinary13</td></row>
+		<row><td>CustomSetupTips</td><td>NetworkInstallText</td><td>Text</td><td>60</td><td>205</td><td>300</td><td>20</td><td>3</td><td/><td>##IDS_SetupTips_Network##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>CustomSetupTips</td><td>OK</td><td>PushButton</td><td>301</td><td>243</td><td>66</td><td>17</td><td>3</td><td/><td>##IDS_SetupTips_OK##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>CustomSetupTips</td><td>PartialText</td><td>Text</td><td>60</td><td>130</td><td>300</td><td>20</td><td>3</td><td/><td>##IDS_SetupTips_SubFeaturesInstalledLocal##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>CustomerInformation</td><td>Back</td><td>PushButton</td><td>164</td><td>243</td><td>66</td><td>17</td><td>3</td><td/><td>##IDS_BACK##</td><td>Next</td><td/><td>0</td><td/><td/><td/></row>
+		<row><td>CustomerInformation</td><td>Banner</td><td>Bitmap</td><td>0</td><td>0</td><td>374</td><td>44</td><td>1</td><td/><td/><td/><td/><td>0</td><td/><td/><td>NewBinary1</td></row>
+		<row><td>CustomerInformation</td><td>BannerLine</td><td>Line</td><td>0</td><td>44</td><td>374</td><td>0</td><td>1</td><td/><td/><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>CustomerInformation</td><td>Branding1</td><td>Text</td><td>4</td><td>229</td><td>50</td><td>13</td><td>3</td><td/><td>##IDS_INSTALLSHIELD_FORMATTED##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>CustomerInformation</td><td>Branding2</td><td>Text</td><td>3</td><td>228</td><td>50</td><td>13</td><td>65537</td><td/><td>##IDS_INSTALLSHIELD##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>CustomerInformation</td><td>Cancel</td><td>PushButton</td><td>301</td><td>243</td><td>66</td><td>17</td><td>3</td><td/><td>##IDS_CANCEL##</td><td>NameLabel</td><td/><td>0</td><td/><td/><td/></row>
+		<row><td>CustomerInformation</td><td>CompanyEdit</td><td>Edit</td><td>21</td><td>100</td><td>237</td><td>17</td><td>3</td><td>COMPANYNAME</td><td>##IDS__IsRegisterUserDlg_Tahoma80##</td><td>SerialLabel</td><td/><td>0</td><td/><td/><td/></row>
+		<row><td>CustomerInformation</td><td>CompanyLabel</td><td>Text</td><td>21</td><td>89</td><td>75</td><td>10</td><td>3</td><td/><td>##IDS__IsRegisterUserDlg_Organization##</td><td>CompanyEdit</td><td/><td>0</td><td/><td/><td/></row>
+		<row><td>CustomerInformation</td><td>DlgDesc</td><td>Text</td><td>21</td><td>23</td><td>292</td><td>25</td><td>65539</td><td/><td>##IDS__IsRegisterUserDlg_PleaseEnterInfo##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>CustomerInformation</td><td>DlgLine</td><td>Line</td><td>48</td><td>234</td><td>326</td><td>0</td><td>1</td><td/><td/><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>CustomerInformation</td><td>DlgRadioGroupText</td><td>Text</td><td>21</td><td>161</td><td>300</td><td>14</td><td>3</td><td/><td>##IDS__IsRegisterUserDlg_InstallFor##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>CustomerInformation</td><td>DlgTitle</td><td>Text</td><td>13</td><td>6</td><td>292</td><td>25</td><td>65539</td><td/><td>##IDS__IsRegisterUserDlg_CustomerInformation##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>CustomerInformation</td><td>NameEdit</td><td>Edit</td><td>21</td><td>63</td><td>237</td><td>17</td><td>3</td><td>USERNAME</td><td>##IDS__IsRegisterUserDlg_Tahoma50##</td><td>CompanyLabel</td><td/><td>0</td><td/><td/><td/></row>
+		<row><td>CustomerInformation</td><td>NameLabel</td><td>Text</td><td>21</td><td>52</td><td>75</td><td>10</td><td>3</td><td/><td>##IDS__IsRegisterUserDlg_UserName##</td><td>NameEdit</td><td/><td>0</td><td/><td/><td/></row>
+		<row><td>CustomerInformation</td><td>Next</td><td>PushButton</td><td>230</td><td>243</td><td>66</td><td>17</td><td>3</td><td/><td>##IDS_NEXT##</td><td>Cancel</td><td/><td>0</td><td/><td/><td/></row>
+		<row><td>CustomerInformation</td><td>RadioGroup</td><td>RadioButtonGroup</td><td>63</td><td>170</td><td>300</td><td>50</td><td>3</td><td>ApplicationUsers</td><td>##IDS__IsRegisterUserDlg_16##</td><td>Back</td><td/><td>0</td><td/><td/><td/></row>
+		<row><td>CustomerInformation</td><td>SerialLabel</td><td>Text</td><td>21</td><td>127</td><td>109</td><td>10</td><td>2</td><td/><td>##IDS__IsRegisterUserDlg_SerialNumber##</td><td>SerialNumber</td><td/><td>0</td><td/><td/><td/></row>
+		<row><td>CustomerInformation</td><td>SerialNumber</td><td>MaskedEdit</td><td>21</td><td>138</td><td>237</td><td>17</td><td>2</td><td>ISX_SERIALNUM</td><td/><td>RadioGroup</td><td/><td>0</td><td/><td/><td/></row>
+		<row><td>DatabaseFolder</td><td>Back</td><td>PushButton</td><td>164</td><td>243</td><td>66</td><td>17</td><td>3</td><td/><td>##IDS_BACK##</td><td>Next</td><td/><td>0</td><td/><td/><td/></row>
+		<row><td>DatabaseFolder</td><td>Banner</td><td>Bitmap</td><td>0</td><td>0</td><td>374</td><td>44</td><td>1</td><td/><td/><td/><td/><td>0</td><td/><td/><td>NewBinary1</td></row>
+		<row><td>DatabaseFolder</td><td>BannerLine</td><td>Line</td><td>0</td><td>44</td><td>374</td><td>0</td><td>1</td><td/><td/><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>DatabaseFolder</td><td>Branding1</td><td>Text</td><td>4</td><td>229</td><td>50</td><td>13</td><td>3</td><td/><td>##IDS_INSTALLSHIELD_FORMATTED##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>DatabaseFolder</td><td>Branding2</td><td>Text</td><td>3</td><td>228</td><td>50</td><td>13</td><td>65537</td><td/><td>##IDS_INSTALLSHIELD##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>DatabaseFolder</td><td>Cancel</td><td>PushButton</td><td>301</td><td>243</td><td>66</td><td>17</td><td>3</td><td/><td>##IDS_CANCEL##</td><td>ChangeFolder</td><td/><td>0</td><td/><td/><td/></row>
+		<row><td>DatabaseFolder</td><td>ChangeFolder</td><td>PushButton</td><td>301</td><td>65</td><td>66</td><td>17</td><td>3</td><td/><td>##IDS_CHANGE##</td><td>Back</td><td/><td>0</td><td/><td/><td/></row>
+		<row><td>DatabaseFolder</td><td>DatabaseFolder</td><td>Icon</td><td>21</td><td>52</td><td>24</td><td>24</td><td>5242881</td><td/><td/><td/><td/><td>0</td><td/><td/><td>NewBinary12</td></row>
+		<row><td>DatabaseFolder</td><td>DlgDesc</td><td>Text</td><td>21</td><td>23</td><td>292</td><td>25</td><td>65539</td><td/><td>##IDS__DatabaseFolder_ChangeFolder##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>DatabaseFolder</td><td>DlgLine</td><td>Line</td><td>48</td><td>234</td><td>326</td><td>0</td><td>1</td><td/><td/><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>DatabaseFolder</td><td>DlgTitle</td><td>Text</td><td>13</td><td>6</td><td>292</td><td>25</td><td>65539</td><td/><td>##IDS__DatabaseFolder_DatabaseFolder##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>DatabaseFolder</td><td>LocLabel</td><td>Text</td><td>57</td><td>52</td><td>290</td><td>10</td><td>3</td><td/><td>##IDS_DatabaseFolder_InstallDatabaseTo##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>DatabaseFolder</td><td>Location</td><td>Text</td><td>57</td><td>65</td><td>240</td><td>40</td><td>3</td><td>_BrowseProperty</td><td>##IDS__DatabaseFolder_DatabaseDir##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>DatabaseFolder</td><td>Next</td><td>PushButton</td><td>230</td><td>243</td><td>66</td><td>17</td><td>3</td><td/><td>##IDS_NEXT##</td><td>Cancel</td><td/><td>0</td><td/><td/><td/></row>
+		<row><td>DestinationFolder</td><td>Back</td><td>PushButton</td><td>164</td><td>243</td><td>66</td><td>17</td><td>3</td><td/><td>##IDS_BACK##</td><td>Next</td><td/><td>0</td><td/><td/><td/></row>
+		<row><td>DestinationFolder</td><td>Banner</td><td>Bitmap</td><td>0</td><td>0</td><td>374</td><td>44</td><td>1</td><td/><td/><td/><td/><td>0</td><td/><td/><td>NewBinary1</td></row>
+		<row><td>DestinationFolder</td><td>BannerLine</td><td>Line</td><td>0</td><td>44</td><td>374</td><td>0</td><td>1</td><td/><td/><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>DestinationFolder</td><td>Branding1</td><td>Text</td><td>4</td><td>229</td><td>50</td><td>13</td><td>3</td><td/><td>##IDS_INSTALLSHIELD_FORMATTED##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>DestinationFolder</td><td>Branding2</td><td>Text</td><td>3</td><td>228</td><td>50</td><td>13</td><td>65537</td><td/><td>##IDS_INSTALLSHIELD##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>DestinationFolder</td><td>Cancel</td><td>PushButton</td><td>301</td><td>243</td><td>66</td><td>17</td><td>3</td><td/><td>##IDS_CANCEL##</td><td>ChangeFolder</td><td/><td>0</td><td/><td/><td/></row>
+		<row><td>DestinationFolder</td><td>ChangeFolder</td><td>PushButton</td><td>301</td><td>65</td><td>66</td><td>17</td><td>3</td><td/><td>##IDS__DestinationFolder_Change##</td><td>Back</td><td/><td>0</td><td/><td/><td/></row>
+		<row><td>DestinationFolder</td><td>DestFolder</td><td>Icon</td><td>21</td><td>52</td><td>24</td><td>24</td><td>5242881</td><td/><td/><td/><td/><td>0</td><td/><td/><td>NewBinary12</td></row>
+		<row><td>DestinationFolder</td><td>DlgDesc</td><td>Text</td><td>21</td><td>23</td><td>292</td><td>25</td><td>65539</td><td/><td>##IDS__DestinationFolder_ChangeFolder##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>DestinationFolder</td><td>DlgLine</td><td>Line</td><td>48</td><td>234</td><td>326</td><td>0</td><td>1</td><td/><td/><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>DestinationFolder</td><td>DlgTitle</td><td>Text</td><td>13</td><td>6</td><td>292</td><td>25</td><td>65539</td><td/><td>##IDS__DestinationFolder_DestinationFolder##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>DestinationFolder</td><td>LocLabel</td><td>Text</td><td>57</td><td>52</td><td>290</td><td>10</td><td>3</td><td/><td>##IDS__DestinationFolder_InstallTo##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>DestinationFolder</td><td>Location</td><td>Text</td><td>57</td><td>65</td><td>240</td><td>40</td><td>3</td><td>_BrowseProperty</td><td>##IDS_INSTALLDIR##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>DestinationFolder</td><td>Next</td><td>PushButton</td><td>230</td><td>243</td><td>66</td><td>17</td><td>3</td><td/><td>##IDS_NEXT##</td><td>Cancel</td><td/><td>0</td><td/><td/><td/></row>
+		<row><td>DiskSpaceRequirements</td><td>Banner</td><td>Bitmap</td><td>0</td><td>0</td><td>374</td><td>44</td><td>1</td><td/><td/><td/><td/><td>0</td><td/><td/><td>NewBinary1</td></row>
+		<row><td>DiskSpaceRequirements</td><td>BannerLine</td><td>Line</td><td>0</td><td>44</td><td>374</td><td>0</td><td>1</td><td/><td/><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>DiskSpaceRequirements</td><td>Branding1</td><td>Text</td><td>4</td><td>229</td><td>50</td><td>13</td><td>3</td><td/><td>##IDS_INSTALLSHIELD_FORMATTED##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>DiskSpaceRequirements</td><td>Branding2</td><td>Text</td><td>3</td><td>228</td><td>50</td><td>13</td><td>65537</td><td/><td>##IDS_INSTALLSHIELD##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>DiskSpaceRequirements</td><td>DlgDesc</td><td>Text</td><td>17</td><td>23</td><td>292</td><td>25</td><td>65539</td><td/><td>##IDS__IsFeatureDetailsDlg_SpaceRequired##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>DiskSpaceRequirements</td><td>DlgLine</td><td>Line</td><td>48</td><td>234</td><td>326</td><td>0</td><td>1</td><td/><td/><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>DiskSpaceRequirements</td><td>DlgText</td><td>Text</td><td>10</td><td>185</td><td>358</td><td>41</td><td>3</td><td/><td>##IDS__IsFeatureDetailsDlg_VolumesTooSmall##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>DiskSpaceRequirements</td><td>DlgTitle</td><td>Text</td><td>9</td><td>6</td><td>292</td><td>25</td><td>65539</td><td/><td>##IDS__IsFeatureDetailsDlg_DiskSpaceRequirements##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>DiskSpaceRequirements</td><td>List</td><td>VolumeCostList</td><td>8</td><td>55</td><td>358</td><td>125</td><td>393223</td><td/><td>##IDS__IsFeatureDetailsDlg_Numbers##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>DiskSpaceRequirements</td><td>OK</td><td>PushButton</td><td>301</td><td>243</td><td>66</td><td>17</td><td>3</td><td/><td>##IDS__IsFeatureDetailsDlg_OK##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>FilesInUse</td><td>Banner</td><td>Bitmap</td><td>0</td><td>0</td><td>374</td><td>44</td><td>1</td><td/><td/><td/><td/><td>0</td><td/><td/><td>NewBinary1</td></row>
+		<row><td>FilesInUse</td><td>BannerLine</td><td>Line</td><td>0</td><td>44</td><td>374</td><td>0</td><td>1</td><td/><td/><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>FilesInUse</td><td>Branding1</td><td>Text</td><td>4</td><td>229</td><td>50</td><td>13</td><td>3</td><td/><td>##IDS_INSTALLSHIELD_FORMATTED##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>FilesInUse</td><td>Branding2</td><td>Text</td><td>3</td><td>228</td><td>50</td><td>13</td><td>65537</td><td/><td>##IDS_INSTALLSHIELD##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>FilesInUse</td><td>DlgDesc</td><td>Text</td><td>21</td><td>23</td><td>292</td><td>25</td><td>65539</td><td/><td>##IDS__IsFilesInUse_FilesInUseMessage##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>FilesInUse</td><td>DlgLine</td><td>Line</td><td>48</td><td>234</td><td>326</td><td>0</td><td>1</td><td/><td/><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>FilesInUse</td><td>DlgText</td><td>Text</td><td>21</td><td>51</td><td>348</td><td>29</td><td>3</td><td/><td>##IDS__IsFilesInUse_ApplicationsUsingFiles##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>FilesInUse</td><td>DlgTitle</td><td>Text</td><td>13</td><td>6</td><td>292</td><td>25</td><td>65539</td><td/><td>##IDS__IsFilesInUse_FilesInUse##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>FilesInUse</td><td>Exit</td><td>PushButton</td><td>301</td><td>243</td><td>66</td><td>17</td><td>3</td><td/><td>##IDS__IsFilesInUse_Exit##</td><td>List</td><td/><td>0</td><td/><td/><td/></row>
+		<row><td>FilesInUse</td><td>Ignore</td><td>PushButton</td><td>230</td><td>243</td><td>66</td><td>17</td><td>3</td><td/><td>##IDS__IsFilesInUse_Ignore##</td><td>Exit</td><td/><td>0</td><td/><td/><td/></row>
+		<row><td>FilesInUse</td><td>List</td><td>ListBox</td><td>21</td><td>87</td><td>331</td><td>135</td><td>7</td><td>FileInUseProcess</td><td/><td>Retry</td><td/><td>0</td><td/><td/><td/></row>
+		<row><td>FilesInUse</td><td>Retry</td><td>PushButton</td><td>164</td><td>243</td><td>66</td><td>17</td><td>3</td><td/><td>##IDS__IsFilesInUse_Retry##</td><td>Ignore</td><td/><td>0</td><td/><td/><td/></row>
+		<row><td>InstallChangeFolder</td><td>Banner</td><td>Bitmap</td><td>0</td><td>0</td><td>374</td><td>44</td><td>1</td><td/><td/><td/><td/><td>0</td><td/><td/><td>NewBinary1</td></row>
+		<row><td>InstallChangeFolder</td><td>BannerLine</td><td>Line</td><td>0</td><td>44</td><td>374</td><td>0</td><td>1</td><td/><td/><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>InstallChangeFolder</td><td>Branding1</td><td>Text</td><td>4</td><td>229</td><td>50</td><td>13</td><td>3</td><td/><td>##IDS_INSTALLSHIELD_FORMATTED##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>InstallChangeFolder</td><td>Branding2</td><td>Text</td><td>3</td><td>228</td><td>50</td><td>13</td><td>65537</td><td/><td>##IDS_INSTALLSHIELD##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>InstallChangeFolder</td><td>Cancel</td><td>PushButton</td><td>301</td><td>243</td><td>66</td><td>17</td><td>3</td><td/><td>##IDS_CANCEL##</td><td>ComboText</td><td/><td>0</td><td/><td/><td/></row>
+		<row><td>InstallChangeFolder</td><td>Combo</td><td>DirectoryCombo</td><td>21</td><td>64</td><td>277</td><td>80</td><td>4128779</td><td>_BrowseProperty</td><td>##IDS__IsBrowseFolderDlg_4##</td><td>Up</td><td/><td>0</td><td/><td/><td/></row>
+		<row><td>InstallChangeFolder</td><td>ComboText</td><td>Text</td><td>21</td><td>50</td><td>99</td><td>14</td><td>3</td><td/><td>##IDS__IsBrowseFolderDlg_LookIn##</td><td>Combo</td><td/><td>0</td><td/><td/><td/></row>
+		<row><td>InstallChangeFolder</td><td>DlgDesc</td><td>Text</td><td>21</td><td>23</td><td>292</td><td>25</td><td>65539</td><td/><td>##IDS__IsBrowseFolderDlg_BrowseDestFolder##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>InstallChangeFolder</td><td>DlgLine</td><td>Line</td><td>48</td><td>234</td><td>326</td><td>0</td><td>1</td><td/><td/><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>InstallChangeFolder</td><td>DlgTitle</td><td>Text</td><td>13</td><td>6</td><td>292</td><td>25</td><td>65539</td><td/><td>##IDS__IsBrowseFolderDlg_ChangeCurrentFolder##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>InstallChangeFolder</td><td>List</td><td>DirectoryList</td><td>21</td><td>90</td><td>332</td><td>97</td><td>15</td><td>_BrowseProperty</td><td>##IDS__IsBrowseFolderDlg_8##</td><td>TailText</td><td/><td>0</td><td/><td/><td/></row>
+		<row><td>InstallChangeFolder</td><td>NewFolder</td><td>PushButton</td><td>335</td><td>66</td><td>19</td><td>19</td><td>3670019</td><td/><td/><td>List</td><td>##IDS__IsBrowseFolderDlg_CreateFolder##</td><td>0</td><td/><td/><td>NewBinary2</td></row>
+		<row><td>InstallChangeFolder</td><td>OK</td><td>PushButton</td><td>230</td><td>243</td><td>66</td><td>17</td><td>3</td><td/><td>##IDS__IsBrowseFolderDlg_OK##</td><td>Cancel</td><td/><td>0</td><td/><td/><td/></row>
+		<row><td>InstallChangeFolder</td><td>Tail</td><td>PathEdit</td><td>21</td><td>207</td><td>332</td><td>17</td><td>15</td><td>_BrowseProperty</td><td>##IDS__IsBrowseFolderDlg_11##</td><td>OK</td><td/><td>0</td><td/><td/><td/></row>
+		<row><td>InstallChangeFolder</td><td>TailText</td><td>Text</td><td>21</td><td>193</td><td>99</td><td>13</td><td>3</td><td/><td>##IDS__IsBrowseFolderDlg_FolderName##</td><td>Tail</td><td/><td>0</td><td/><td/><td/></row>
+		<row><td>InstallChangeFolder</td><td>Up</td><td>PushButton</td><td>310</td><td>66</td><td>19</td><td>19</td><td>3670019</td><td/><td/><td>NewFolder</td><td>##IDS__IsBrowseFolderDlg_UpOneLevel##</td><td>0</td><td/><td/><td>NewBinary3</td></row>
+		<row><td>InstallWelcome</td><td>Back</td><td>PushButton</td><td>164</td><td>243</td><td>66</td><td>17</td><td>1</td><td/><td>##IDS_BACK##</td><td>Copyright</td><td/><td>0</td><td/><td/><td/></row>
+		<row><td>InstallWelcome</td><td>Cancel</td><td>PushButton</td><td>301</td><td>243</td><td>66</td><td>17</td><td>3</td><td/><td>##IDS_CANCEL##</td><td>Back</td><td/><td>0</td><td/><td/><td/></row>
+		<row><td>InstallWelcome</td><td>Copyright</td><td>Text</td><td>135</td><td>144</td><td>228</td><td>73</td><td>65539</td><td/><td>##IDS__IsWelcomeDlg_WarningCopyright##</td><td>Next</td><td/><td>0</td><td/><td/><td/></row>
+		<row><td>InstallWelcome</td><td>DlgLine</td><td>Line</td><td>0</td><td>234</td><td>374</td><td>0</td><td>1</td><td/><td/><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>InstallWelcome</td><td>Image</td><td>Bitmap</td><td>0</td><td>0</td><td>374</td><td>234</td><td>1</td><td/><td/><td/><td/><td>0</td><td/><td/><td>NewBinary5</td></row>
+		<row><td>InstallWelcome</td><td>Next</td><td>PushButton</td><td>230</td><td>243</td><td>66</td><td>17</td><td>3</td><td/><td>##IDS_NEXT##</td><td>Cancel</td><td/><td>0</td><td/><td/><td/></row>
+		<row><td>InstallWelcome</td><td>TextLine1</td><td>Text</td><td>135</td><td>8</td><td>225</td><td>45</td><td>65539</td><td/><td>##IDS__IsWelcomeDlg_WelcomeProductName##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>InstallWelcome</td><td>TextLine2</td><td>Text</td><td>135</td><td>55</td><td>228</td><td>45</td><td>65539</td><td/><td>##IDS__IsWelcomeDlg_InstallProductName##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>LicenseAgreement</td><td>Agree</td><td>RadioButtonGroup</td><td>8</td><td>190</td><td>291</td><td>40</td><td>3</td><td>AgreeToLicense</td><td/><td>Back</td><td/><td>0</td><td/><td/><td/></row>
+		<row><td>LicenseAgreement</td><td>Back</td><td>PushButton</td><td>164</td><td>243</td><td>66</td><td>17</td><td>3</td><td/><td>##IDS_BACK##</td><td>Next</td><td/><td>0</td><td/><td/><td/></row>
+		<row><td>LicenseAgreement</td><td>Banner</td><td>Bitmap</td><td>0</td><td>0</td><td>374</td><td>44</td><td>1</td><td/><td/><td/><td/><td>0</td><td/><td/><td>NewBinary1</td></row>
+		<row><td>LicenseAgreement</td><td>BannerLine</td><td>Line</td><td>0</td><td>44</td><td>374</td><td>0</td><td>1</td><td/><td/><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>LicenseAgreement</td><td>Branding1</td><td>Text</td><td>4</td><td>229</td><td>50</td><td>13</td><td>3</td><td/><td>##IDS_INSTALLSHIELD_FORMATTED##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>LicenseAgreement</td><td>Branding2</td><td>Text</td><td>3</td><td>228</td><td>50</td><td>13</td><td>65537</td><td/><td>##IDS_INSTALLSHIELD##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>LicenseAgreement</td><td>Cancel</td><td>PushButton</td><td>301</td><td>243</td><td>66</td><td>17</td><td>3</td><td/><td>##IDS_CANCEL##</td><td>ISPrintButton</td><td/><td>0</td><td/><td/><td/></row>
+		<row><td>LicenseAgreement</td><td>DlgDesc</td><td>Text</td><td>21</td><td>23</td><td>292</td><td>25</td><td>65539</td><td/><td>##IDS__IsLicenseDlg_ReadLicenseAgreement##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>LicenseAgreement</td><td>DlgLine</td><td>Line</td><td>48</td><td>234</td><td>326</td><td>0</td><td>1</td><td/><td/><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>LicenseAgreement</td><td>DlgTitle</td><td>Text</td><td>13</td><td>6</td><td>292</td><td>25</td><td>65539</td><td/><td>##IDS__IsLicenseDlg_LicenseAgreement##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>LicenseAgreement</td><td>ISPrintButton</td><td>PushButton</td><td>301</td><td>188</td><td>65</td><td>17</td><td>3</td><td/><td>##IDS_PRINT_BUTTON##</td><td>Agree</td><td/><td>0</td><td/><td/><td/></row>
+		<row><td>LicenseAgreement</td><td>Memo</td><td>ScrollableText</td><td>8</td><td>55</td><td>358</td><td>130</td><td>7</td><td/><td/><td/><td/><td>0</td><td/><td>&lt;ISProjectFolder&gt;\License.rtf</td><td/></row>
+		<row><td>LicenseAgreement</td><td>Next</td><td>PushButton</td><td>230</td><td>243</td><td>66</td><td>17</td><td>3</td><td/><td>##IDS_NEXT##</td><td>Cancel</td><td/><td>0</td><td/><td/><td/></row>
+		<row><td>MaintenanceType</td><td>Back</td><td>PushButton</td><td>164</td><td>243</td><td>66</td><td>17</td><td>3</td><td/><td>##IDS_BACK##</td><td>Next</td><td/><td>0</td><td/><td/><td/></row>
+		<row><td>MaintenanceType</td><td>Banner</td><td>Bitmap</td><td>0</td><td>0</td><td>374</td><td>44</td><td>1</td><td/><td/><td/><td/><td>0</td><td/><td/><td>NewBinary1</td></row>
+		<row><td>MaintenanceType</td><td>BannerLine</td><td>Line</td><td>0</td><td>44</td><td>374</td><td>0</td><td>1</td><td/><td/><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>MaintenanceType</td><td>Branding1</td><td>Text</td><td>4</td><td>229</td><td>50</td><td>13</td><td>3</td><td/><td>##IDS_INSTALLSHIELD_FORMATTED##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>MaintenanceType</td><td>Branding2</td><td>Text</td><td>3</td><td>228</td><td>50</td><td>13</td><td>65537</td><td/><td>##IDS_INSTALLSHIELD##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>MaintenanceType</td><td>Cancel</td><td>PushButton</td><td>301</td><td>243</td><td>66</td><td>17</td><td>3</td><td/><td>##IDS_CANCEL##</td><td>RadioGroup</td><td/><td>0</td><td/><td/><td/></row>
+		<row><td>MaintenanceType</td><td>DlgDesc</td><td>Text</td><td>21</td><td>23</td><td>292</td><td>25</td><td>65539</td><td/><td>##IDS__IsMaintenanceDlg_MaitenanceOptions##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>MaintenanceType</td><td>DlgLine</td><td>Line</td><td>48</td><td>234</td><td>326</td><td>0</td><td>1</td><td/><td/><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>MaintenanceType</td><td>DlgTitle</td><td>Text</td><td>13</td><td>6</td><td>292</td><td>25</td><td>65539</td><td/><td>##IDS__IsMaintenanceDlg_ProgramMaintenance##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>MaintenanceType</td><td>Ico1</td><td>Icon</td><td>35</td><td>75</td><td>24</td><td>24</td><td>5242881</td><td/><td/><td/><td/><td>0</td><td/><td/><td>NewBinary6</td></row>
+		<row><td>MaintenanceType</td><td>Ico2</td><td>Icon</td><td>35</td><td>135</td><td>24</td><td>24</td><td>5242881</td><td/><td/><td/><td/><td>0</td><td/><td/><td>NewBinary7</td></row>
+		<row><td>MaintenanceType</td><td>Ico3</td><td>Icon</td><td>35</td><td>195</td><td>24</td><td>24</td><td>5242881</td><td/><td/><td/><td/><td>0</td><td/><td/><td>NewBinary8</td></row>
+		<row><td>MaintenanceType</td><td>Next</td><td>PushButton</td><td>230</td><td>243</td><td>66</td><td>17</td><td>3</td><td/><td>##IDS_NEXT##</td><td>Cancel</td><td/><td>0</td><td/><td/><td/></row>
+		<row><td>MaintenanceType</td><td>RadioGroup</td><td>RadioButtonGroup</td><td>21</td><td>55</td><td>290</td><td>170</td><td>3</td><td>_IsMaintenance</td><td>##IDS__IsMaintenanceDlg_11##</td><td>Back</td><td/><td>0</td><td/><td/><td/></row>
+		<row><td>MaintenanceType</td><td>Text1</td><td>Text</td><td>80</td><td>72</td><td>260</td><td>35</td><td>3</td><td/><td>##IDS__IsMaintenanceDlg_ChangeFeatures##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>MaintenanceType</td><td>Text2</td><td>Text</td><td>80</td><td>135</td><td>260</td><td>35</td><td>3</td><td/><td>##IDS__IsMaintenanceDlg_RepairMessage##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>MaintenanceType</td><td>Text3</td><td>Text</td><td>80</td><td>192</td><td>260</td><td>35</td><td>3</td><td/><td>##IDS__IsMaintenanceDlg_RemoveProductName##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>MaintenanceWelcome</td><td>Back</td><td>PushButton</td><td>164</td><td>243</td><td>66</td><td>17</td><td>1</td><td/><td>##IDS_BACK##</td><td>Next</td><td/><td>0</td><td/><td/><td/></row>
+		<row><td>MaintenanceWelcome</td><td>Cancel</td><td>PushButton</td><td>301</td><td>243</td><td>66</td><td>17</td><td>3</td><td/><td>##IDS_CANCEL##</td><td>Back</td><td/><td>0</td><td/><td/><td/></row>
+		<row><td>MaintenanceWelcome</td><td>DlgLine</td><td>Line</td><td>0</td><td>234</td><td>374</td><td>0</td><td>1</td><td/><td/><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>MaintenanceWelcome</td><td>Image</td><td>Bitmap</td><td>0</td><td>0</td><td>374</td><td>234</td><td>1</td><td/><td/><td/><td/><td>0</td><td/><td/><td>NewBinary5</td></row>
+		<row><td>MaintenanceWelcome</td><td>Next</td><td>PushButton</td><td>230</td><td>243</td><td>66</td><td>17</td><td>3</td><td/><td>##IDS_NEXT##</td><td>Cancel</td><td/><td>0</td><td/><td/><td/></row>
+		<row><td>MaintenanceWelcome</td><td>TextLine1</td><td>Text</td><td>135</td><td>8</td><td>225</td><td>45</td><td>65539</td><td/><td>##IDS__IsMaintenanceWelcome_WizardWelcome##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>MaintenanceWelcome</td><td>TextLine2</td><td>Text</td><td>135</td><td>55</td><td>228</td><td>50</td><td>65539</td><td/><td>##IDS__IsMaintenanceWelcome_MaintenanceOptionsDescription##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>OutOfSpace</td><td>Banner</td><td>Bitmap</td><td>0</td><td>0</td><td>374</td><td>44</td><td>1</td><td/><td/><td/><td/><td>0</td><td/><td/><td>NewBinary1</td></row>
+		<row><td>OutOfSpace</td><td>BannerLine</td><td>Line</td><td>0</td><td>44</td><td>374</td><td>0</td><td>1</td><td/><td/><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>OutOfSpace</td><td>Branding1</td><td>Text</td><td>4</td><td>229</td><td>50</td><td>13</td><td>3</td><td/><td>##IDS_INSTALLSHIELD_FORMATTED##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>OutOfSpace</td><td>Branding2</td><td>Text</td><td>3</td><td>228</td><td>50</td><td>13</td><td>65537</td><td/><td>##IDS_INSTALLSHIELD##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>OutOfSpace</td><td>DlgDesc</td><td>Text</td><td>21</td><td>23</td><td>292</td><td>25</td><td>65539</td><td/><td>##IDS__IsDiskSpaceDlg_DiskSpace##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>OutOfSpace</td><td>DlgLine</td><td>Line</td><td>48</td><td>234</td><td>326</td><td>0</td><td>1</td><td/><td/><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>OutOfSpace</td><td>DlgText</td><td>Text</td><td>21</td><td>51</td><td>326</td><td>43</td><td>3</td><td/><td>##IDS__IsDiskSpaceDlg_HighlightedVolumes##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>OutOfSpace</td><td>DlgTitle</td><td>Text</td><td>13</td><td>6</td><td>292</td><td>25</td><td>65539</td><td/><td>##IDS__IsDiskSpaceDlg_OutOfDiskSpace##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>OutOfSpace</td><td>List</td><td>VolumeCostList</td><td>21</td><td>95</td><td>332</td><td>120</td><td>393223</td><td/><td>##IDS__IsDiskSpaceDlg_Numbers##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>OutOfSpace</td><td>Resume</td><td>PushButton</td><td>301</td><td>243</td><td>66</td><td>17</td><td>3</td><td/><td>##IDS__IsDiskSpaceDlg_OK##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>PatchWelcome</td><td>Back</td><td>PushButton</td><td>164</td><td>243</td><td>66</td><td>17</td><td>1</td><td/><td>##IDS_BACK##</td><td>Next</td><td/><td>0</td><td/><td/><td/></row>
+		<row><td>PatchWelcome</td><td>Cancel</td><td>PushButton</td><td>301</td><td>243</td><td>66</td><td>17</td><td>3</td><td/><td>##IDS_CANCEL##</td><td>Back</td><td/><td>0</td><td/><td/><td/></row>
+		<row><td>PatchWelcome</td><td>DlgLine</td><td>Line</td><td>0</td><td>234</td><td>374</td><td>0</td><td>1</td><td/><td/><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>PatchWelcome</td><td>Image</td><td>Bitmap</td><td>0</td><td>0</td><td>374</td><td>234</td><td>1</td><td/><td/><td/><td/><td>0</td><td/><td/><td>NewBinary5</td></row>
+		<row><td>PatchWelcome</td><td>Next</td><td>PushButton</td><td>230</td><td>243</td><td>66</td><td>17</td><td>3</td><td/><td>##IDS__IsPatchDlg_Update##</td><td>Cancel</td><td/><td>0</td><td/><td/><td/></row>
+		<row><td>PatchWelcome</td><td>TextLine1</td><td>Text</td><td>135</td><td>8</td><td>225</td><td>45</td><td>65539</td><td/><td>##IDS__IsPatchDlg_WelcomePatchWizard##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>PatchWelcome</td><td>TextLine2</td><td>Text</td><td>135</td><td>54</td><td>228</td><td>45</td><td>65539</td><td/><td>##IDS__IsPatchDlg_PatchClickUpdate##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>ReadyToInstall</td><td>Back</td><td>PushButton</td><td>164</td><td>243</td><td>66</td><td>17</td><td>3</td><td/><td>##IDS_BACK##</td><td>InstallNow</td><td/><td>0</td><td/><td/><td/></row>
+		<row><td>ReadyToInstall</td><td>Banner</td><td>Bitmap</td><td>0</td><td>0</td><td>374</td><td>44</td><td>1</td><td/><td/><td/><td/><td>0</td><td/><td/><td>NewBinary1</td></row>
+		<row><td>ReadyToInstall</td><td>BannerLine</td><td>Line</td><td>0</td><td>44</td><td>374</td><td>0</td><td>1</td><td/><td/><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>ReadyToInstall</td><td>Branding1</td><td>Text</td><td>4</td><td>229</td><td>50</td><td>13</td><td>3</td><td/><td>##IDS_INSTALLSHIELD_FORMATTED##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>ReadyToInstall</td><td>Branding2</td><td>Text</td><td>3</td><td>228</td><td>50</td><td>13</td><td>65537</td><td/><td>##IDS_INSTALLSHIELD##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>ReadyToInstall</td><td>Cancel</td><td>PushButton</td><td>301</td><td>243</td><td>66</td><td>17</td><td>3</td><td/><td>##IDS_CANCEL##</td><td>Back</td><td/><td>0</td><td/><td/><td/></row>
+		<row><td>ReadyToInstall</td><td>DlgDesc</td><td>Text</td><td>21</td><td>23</td><td>292</td><td>25</td><td>65539</td><td/><td>##IDS__IsVerifyReadyDlg_WizardReady##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>ReadyToInstall</td><td>DlgLine</td><td>Line</td><td>48</td><td>234</td><td>374</td><td>0</td><td>1</td><td/><td/><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>ReadyToInstall</td><td>DlgText</td><td>Text</td><td>21</td><td>51</td><td>326</td><td>20</td><td>3</td><td/><td>##IDS__IsVerifyReadyDlg_ClickInstall##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>ReadyToInstall</td><td>DlgText1</td><td>Text</td><td>21</td><td>70</td><td>330</td><td>24</td><td>3</td><td/><td>##IDS__IsVerifyReadyDlg_BackOrCancel##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>ReadyToInstall</td><td>DlgTitle</td><td>Text</td><td>13</td><td>6</td><td>292</td><td>25</td><td>65538</td><td/><td>##IDS__IsVerifyReadyDlg_ModifyReady##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>ReadyToInstall</td><td>DlgTitle2</td><td>Text</td><td>13</td><td>6</td><td>292</td><td>25</td><td>65538</td><td/><td>##IDS__IsVerifyReadyDlg_ReadyRepair##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>ReadyToInstall</td><td>DlgTitle3</td><td>Text</td><td>13</td><td>6</td><td>292</td><td>25</td><td>65538</td><td/><td>##IDS__IsVerifyReadyDlg_ReadyInstall##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>ReadyToInstall</td><td>InstallNow</td><td>PushButton</td><td>230</td><td>243</td><td>66</td><td>17</td><td>3</td><td/><td>##IDS__IsVerifyReadyDlg_Install##</td><td>Cancel</td><td/><td>0</td><td/><td/><td/></row>
+		<row><td>ReadyToRemove</td><td>Back</td><td>PushButton</td><td>164</td><td>243</td><td>66</td><td>17</td><td>3</td><td/><td>##IDS_BACK##</td><td>RemoveNow</td><td/><td>0</td><td/><td/><td/></row>
+		<row><td>ReadyToRemove</td><td>Banner</td><td>Bitmap</td><td>0</td><td>0</td><td>374</td><td>44</td><td>1</td><td/><td/><td/><td/><td>0</td><td/><td/><td>NewBinary1</td></row>
+		<row><td>ReadyToRemove</td><td>BannerLine</td><td>Line</td><td>0</td><td>44</td><td>374</td><td>0</td><td>1</td><td/><td/><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>ReadyToRemove</td><td>Branding1</td><td>Text</td><td>4</td><td>229</td><td>50</td><td>13</td><td>3</td><td/><td>##IDS_INSTALLSHIELD_FORMATTED##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>ReadyToRemove</td><td>Branding2</td><td>Text</td><td>3</td><td>228</td><td>50</td><td>13</td><td>65537</td><td/><td>##IDS_INSTALLSHIELD##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>ReadyToRemove</td><td>Cancel</td><td>PushButton</td><td>301</td><td>243</td><td>66</td><td>17</td><td>3</td><td/><td>##IDS_CANCEL##</td><td>Back</td><td/><td>0</td><td/><td/><td/></row>
+		<row><td>ReadyToRemove</td><td>DlgDesc</td><td>Text</td><td>21</td><td>23</td><td>292</td><td>25</td><td>65539</td><td/><td>##IDS__IsVerifyRemoveAllDlg_ChoseRemoveProgram##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>ReadyToRemove</td><td>DlgLine</td><td>Line</td><td>48</td><td>234</td><td>326</td><td>0</td><td>1</td><td/><td/><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>ReadyToRemove</td><td>DlgText</td><td>Text</td><td>21</td><td>51</td><td>326</td><td>24</td><td>3</td><td/><td>##IDS__IsVerifyRemoveAllDlg_ClickRemove##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>ReadyToRemove</td><td>DlgText1</td><td>Text</td><td>21</td><td>79</td><td>330</td><td>23</td><td>3</td><td/><td>##IDS__IsVerifyRemoveAllDlg_ClickBack##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>ReadyToRemove</td><td>DlgText2</td><td>Text</td><td>21</td><td>102</td><td>330</td><td>24</td><td>3</td><td/><td/><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>ReadyToRemove</td><td>DlgTitle</td><td>Text</td><td>13</td><td>6</td><td>292</td><td>25</td><td>65539</td><td/><td>##IDS__IsVerifyRemoveAllDlg_RemoveProgram##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>ReadyToRemove</td><td>RemoveNow</td><td>PushButton</td><td>230</td><td>243</td><td>66</td><td>17</td><td>3</td><td/><td>##IDS__IsVerifyRemoveAllDlg_Remove##</td><td>Cancel</td><td/><td>0</td><td/><td/><td/></row>
+		<row><td>SQLBrowse</td><td>Branding1</td><td>Text</td><td>4</td><td>227</td><td>50</td><td>13</td><td>3</td><td/><td>##IDS_INSTALLSHIELD_FORMATTED##</td><td/><td/><td>0</td><td>0</td><td/><td/></row>
+		<row><td>SQLBrowse</td><td>Branding2</td><td>Text</td><td>3</td><td>226</td><td>50</td><td>13</td><td>65537</td><td/><td>##IDS_INSTALLSHIELD##</td><td/><td/><td>0</td><td>0</td><td/><td/></row>
+		<row><td>SQLBrowse</td><td>Cancel</td><td>PushButton</td><td>194</td><td>241</td><td>66</td><td>17</td><td>3</td><td/><td>##IDS_CANCEL##</td><td>TxtSQLBrowse</td><td/><td>0</td><td/><td/><td/></row>
+		<row><td>SQLBrowse</td><td>DlgLine</td><td>Line</td><td>48</td><td>232</td><td>224</td><td>0</td><td>1</td><td/><td/><td/><td/><td>0</td><td>0</td><td/><td/></row>
+		<row><td>SQLBrowse</td><td>OK</td><td>PushButton</td><td>125</td><td>241</td><td>66</td><td>17</td><td>3</td><td/><td>##IDS_OK##</td><td>lstSQLServer</td><td/><td>0</td><td/><td/><td/></row>
+		<row><td>SQLBrowse</td><td>TxtSQLBrowse</td><td>Text</td><td>13</td><td>8</td><td>245</td><td>31</td><td>65539</td><td/><td>##IDS_SQLBROWSE_INTRO##</td><td>OK</td><td/><td>0</td><td/><td/><td/></row>
+		<row><td>SQLBrowse</td><td>lstSQLServer</td><td>ListBox</td><td>14</td><td>45</td><td>245</td><td>165</td><td>7</td><td>IS_SQLSERVER_LIST</td><td/><td>Cancel</td><td/><td>0</td><td/><td/><td/></row>
+		<row><td>SQLLogin</td><td>Back</td><td>PushButton</td><td>164</td><td>243</td><td>66</td><td>17</td><td>3</td><td/><td>##IDS_BACK##</td><td>Next</td><td/><td>0</td><td/><td/><td/></row>
+		<row><td>SQLLogin</td><td>Banner</td><td>Bitmap</td><td>0</td><td>0</td><td>374</td><td>44</td><td>1</td><td/><td/><td/><td/><td>0</td><td/><td/><td>NewBinary1</td></row>
+		<row><td>SQLLogin</td><td>BannerLine</td><td>Line</td><td>0</td><td>44</td><td>374</td><td>0</td><td>1</td><td/><td/><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>SQLLogin</td><td>Branding1</td><td>Text</td><td>4</td><td>229</td><td>50</td><td>13</td><td>3</td><td/><td>##IDS_INSTALLSHIELD_FORMATTED##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>SQLLogin</td><td>Branding2</td><td>Text</td><td>3</td><td>228</td><td>50</td><td>13</td><td>65537</td><td/><td>##IDS_INSTALLSHIELD##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>SQLLogin</td><td>BtnSQLBrowse</td><td>PushButton</td><td>301</td><td>106</td><td>66</td><td>17</td><td>3</td><td/><td>##IDS_SQLLOGIN_BROWSE##</td><td>lblAuthentication</td><td/><td>0</td><td/><td/><td/></row>
+		<row><td>SQLLogin</td><td>Cancel</td><td>PushButton</td><td>301</td><td>243</td><td>66</td><td>17</td><td>3</td><td/><td>##IDS_CANCEL##</td><td>lblServer</td><td/><td>0</td><td/><td/><td/></row>
+		<row><td>SQLLogin</td><td>DlgDesc</td><td>Text</td><td>21</td><td>23</td><td>292</td><td>25</td><td>65539</td><td/><td>##IDS_SQLLOGIN_DESC##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>SQLLogin</td><td>DlgLine</td><td>Line</td><td>48</td><td>234</td><td>326</td><td>0</td><td>1</td><td/><td/><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>SQLLogin</td><td>DlgTitle</td><td>Text</td><td>13</td><td>7</td><td>292</td><td>25</td><td>65539</td><td/><td>##IDS_SQLLOGIN_TITLE##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>SQLLogin</td><td>EdtLogin</td><td>Edit</td><td>92</td><td>184</td><td>218</td><td>16</td><td>3</td><td>IS_SQLSERVER_USERNAME</td><td/><td>lblPswd</td><td/><td>0</td><td/><td/><td/></row>
+		<row><td>SQLLogin</td><td>EdtPswd</td><td>Edit</td><td>92</td><td>208</td><td>218</td><td>16</td><td>2097155</td><td>IS_SQLSERVER_PASSWORD</td><td/><td>Back</td><td/><td>0</td><td/><td/><td/></row>
+		<row><td>SQLLogin</td><td>Next</td><td>PushButton</td><td>229</td><td>243</td><td>66</td><td>17</td><td>3</td><td/><td>##IDS_NEXT##</td><td>Cancel</td><td/><td>0</td><td/><td/><td/></row>
+		<row><td>SQLLogin</td><td>RadioButtonGroup1</td><td>RadioButtonGroup</td><td>25</td><td>145</td><td>343</td><td>34</td><td>3</td><td>IS_SQLSERVER_AUTHENTICATION</td><td/><td>lblLoginID</td><td/><td>0</td><td/><td/><td/></row>
+		<row><td>SQLLogin</td><td>cboServers</td><td>ComboBox</td><td>18</td><td>106</td><td>278</td><td>80</td><td>65539</td><td>IS_SQLSERVER_SERVER</td><td/><td>BtnSQLBrowse</td><td/><td>0</td><td/><td/><td/></row>
+		<row><td>SQLLogin</td><td>lblAuthentication</td><td>Text</td><td>18</td><td>129</td><td>334</td><td>14</td><td>131075</td><td/><td>##IDS_SQLLOGIN_CONNECT##</td><td>RadioButtonGroup1</td><td/><td>0</td><td/><td/><td/></row>
+		<row><td>SQLLogin</td><td>lblLoginID</td><td>Text</td><td>43</td><td>186</td><td>48</td><td>13</td><td>3</td><td/><td>##IDS_SQLLOGIN_ID##</td><td>EdtLogin</td><td/><td>0</td><td/><td/><td/></row>
+		<row><td>SQLLogin</td><td>lblPswd</td><td>Text</td><td>43</td><td>208</td><td>47</td><td>13</td><td>3</td><td/><td>##IDS_SQLLOGIN_PSWD##</td><td>EdtPswd</td><td/><td>0</td><td/><td/><td/></row>
+		<row><td>SQLLogin</td><td>lblSQLLoginIntro</td><td>Text</td><td>17</td><td>50</td><td>345</td><td>40</td><td>65539</td><td/><td>##IDS_SQLLOGIN_INTRO##</td><td>cboServers</td><td/><td>0</td><td/><td/><td/></row>
+		<row><td>SQLLogin</td><td>lblServer</td><td>Text</td><td>18</td><td>92</td><td>88</td><td>14</td><td>3</td><td/><td>##IDS_SQLLOGIN_SERVER##</td><td>lblSQLLoginIntro</td><td/><td>0</td><td/><td/><td/></row>
+		<row><td>SetupCompleteError</td><td>Back</td><td>PushButton</td><td>164</td><td>243</td><td>66</td><td>17</td><td>1</td><td/><td>##IDS_BACK##</td><td>Finish</td><td/><td>0</td><td/><td/><td/></row>
+		<row><td>SetupCompleteError</td><td>Cancel</td><td>PushButton</td><td>301</td><td>243</td><td>66</td><td>17</td><td>1</td><td/><td>##IDS_CANCEL##</td><td>Back</td><td/><td>0</td><td/><td/><td/></row>
+		<row><td>SetupCompleteError</td><td>DlgLine</td><td>Line</td><td>0</td><td>234</td><td>374</td><td>0</td><td>1</td><td/><td/><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>SetupCompleteError</td><td>Finish</td><td>PushButton</td><td>230</td><td>243</td><td>66</td><td>17</td><td>3</td><td/><td>##IDS__IsFatalError_Finish##</td><td>Cancel</td><td/><td>0</td><td/><td/><td/></row>
+		<row><td>SetupCompleteError</td><td>FinishText1</td><td>Text</td><td>135</td><td>80</td><td>228</td><td>50</td><td>65539</td><td/><td>##IDS__IsFatalError_NotModified##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>SetupCompleteError</td><td>FinishText2</td><td>Text</td><td>135</td><td>135</td><td>228</td><td>25</td><td>65539</td><td/><td>##IDS__IsFatalError_ClickFinish##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>SetupCompleteError</td><td>Image</td><td>Bitmap</td><td>0</td><td>0</td><td>374</td><td>234</td><td>1</td><td/><td/><td/><td/><td>0</td><td/><td/><td>NewBinary5</td></row>
+		<row><td>SetupCompleteError</td><td>RestContText1</td><td>Text</td><td>135</td><td>80</td><td>228</td><td>50</td><td>65539</td><td/><td>##IDS__IsFatalError_KeepOrRestore##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>SetupCompleteError</td><td>RestContText2</td><td>Text</td><td>135</td><td>135</td><td>228</td><td>25</td><td>65539</td><td/><td>##IDS__IsFatalError_RestoreOrContinueLater##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>SetupCompleteError</td><td>TextLine1</td><td>Text</td><td>135</td><td>8</td><td>225</td><td>45</td><td>65539</td><td/><td>##IDS__IsFatalError_WizardCompleted##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>SetupCompleteError</td><td>TextLine2</td><td>Text</td><td>135</td><td>55</td><td>228</td><td>25</td><td>65539</td><td/><td>##IDS__IsFatalError_WizardInterrupted##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>SetupCompleteSuccess</td><td>Back</td><td>PushButton</td><td>164</td><td>243</td><td>66</td><td>17</td><td>1</td><td/><td>##IDS_BACK##</td><td>OK</td><td/><td>0</td><td/><td/><td/></row>
+		<row><td>SetupCompleteSuccess</td><td>Cancel</td><td>PushButton</td><td>301</td><td>243</td><td>66</td><td>17</td><td>1</td><td/><td>##IDS_CANCEL##</td><td>Image</td><td/><td>0</td><td/><td/><td/></row>
+		<row><td>SetupCompleteSuccess</td><td>CheckBoxUpdates</td><td>CheckBox</td><td>135</td><td>164</td><td>10</td><td>9</td><td>2</td><td>ISCHECKFORPRODUCTUPDATES</td><td>CheckBox1</td><td>Back</td><td/><td>0</td><td/><td/><td/></row>
+		<row><td>SetupCompleteSuccess</td><td>CheckForUpdatesText</td><td>Text</td><td>152</td><td>162</td><td>190</td><td>30</td><td>65538</td><td/><td>##IDS__IsExitDialog_Update_YesCheckForUpdates##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>SetupCompleteSuccess</td><td>CheckLaunchProgram</td><td>CheckBox</td><td>151</td><td>114</td><td>10</td><td>9</td><td>2</td><td>LAUNCHPROGRAM</td><td/><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>SetupCompleteSuccess</td><td>CheckLaunchReadme</td><td>CheckBox</td><td>151</td><td>148</td><td>10</td><td>9</td><td>2</td><td>LAUNCHREADME</td><td/><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>SetupCompleteSuccess</td><td>DlgLine</td><td>Line</td><td>0</td><td>234</td><td>374</td><td>0</td><td>1</td><td/><td/><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>SetupCompleteSuccess</td><td>Image</td><td>Bitmap</td><td>0</td><td>0</td><td>374</td><td>234</td><td>1</td><td/><td/><td>CheckBoxUpdates</td><td/><td>0</td><td/><td/><td>NewBinary5</td></row>
+		<row><td>SetupCompleteSuccess</td><td>LaunchProgramText</td><td>Text</td><td>164</td><td>112</td><td>198</td><td>15</td><td>65538</td><td/><td>Launch [ProductName]</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>SetupCompleteSuccess</td><td>LaunchReadmeText</td><td>Text</td><td>164</td><td>148</td><td>198</td><td>13</td><td>65538</td><td/><td>##IDS__IsExitDialog_ShowReadMe##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>SetupCompleteSuccess</td><td>OK</td><td>PushButton</td><td>230</td><td>243</td><td>66</td><td>17</td><td>3</td><td/><td>##IDS__IsExitDialog_Finish##</td><td>Cancel</td><td/><td>0</td><td/><td/><td/></row>
+		<row><td>SetupCompleteSuccess</td><td>TextLine1</td><td>Text</td><td>135</td><td>8</td><td>225</td><td>45</td><td>65539</td><td/><td>##IDS__IsExitDialog_WizardCompleted##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>SetupCompleteSuccess</td><td>TextLine2</td><td>Text</td><td>135</td><td>55</td><td>228</td><td>45</td><td>65538</td><td/><td>##IDS__IsExitDialog_InstallSuccess##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>SetupCompleteSuccess</td><td>TextLine3</td><td>Text</td><td>135</td><td>55</td><td>228</td><td>45</td><td>65538</td><td/><td>##IDS__IsExitDialog_UninstallSuccess##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>SetupCompleteSuccess</td><td>UpdateTextLine1</td><td>Text</td><td>135</td><td>30</td><td>228</td><td>45</td><td>65538</td><td/><td>##IDS__IsExitDialog_Update_SetupFinished##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>SetupCompleteSuccess</td><td>UpdateTextLine2</td><td>Text</td><td>135</td><td>80</td><td>228</td><td>45</td><td>65538</td><td/><td>##IDS__IsExitDialog_Update_PossibleUpdates##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>SetupCompleteSuccess</td><td>UpdateTextLine3</td><td>Text</td><td>135</td><td>120</td><td>228</td><td>45</td><td>65538</td><td/><td>##IDS__IsExitDialog_Update_InternetConnection##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>SetupError</td><td>A</td><td>PushButton</td><td>192</td><td>80</td><td>66</td><td>17</td><td>3</td><td/><td>##IDS__IsErrorDlg_Abort##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>SetupError</td><td>C</td><td>PushButton</td><td>192</td><td>80</td><td>66</td><td>17</td><td>3</td><td/><td>##IDS_CANCEL2##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>SetupError</td><td>ErrorIcon</td><td>Icon</td><td>15</td><td>15</td><td>24</td><td>24</td><td>5242881</td><td/><td/><td/><td/><td>0</td><td/><td/><td>NewBinary4</td></row>
+		<row><td>SetupError</td><td>ErrorText</td><td>Text</td><td>50</td><td>15</td><td>200</td><td>50</td><td>3</td><td/><td>##IDS__IsErrorDlg_ErrorText##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>SetupError</td><td>I</td><td>PushButton</td><td>192</td><td>80</td><td>66</td><td>17</td><td>3</td><td/><td>##IDS__IsErrorDlg_Ignore##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>SetupError</td><td>N</td><td>PushButton</td><td>192</td><td>80</td><td>66</td><td>17</td><td>3</td><td/><td>##IDS__IsErrorDlg_NO##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>SetupError</td><td>O</td><td>PushButton</td><td>192</td><td>80</td><td>66</td><td>17</td><td>3</td><td/><td>##IDS__IsErrorDlg_OK##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>SetupError</td><td>R</td><td>PushButton</td><td>192</td><td>80</td><td>66</td><td>17</td><td>3</td><td/><td>##IDS__IsErrorDlg_Retry##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>SetupError</td><td>Y</td><td>PushButton</td><td>192</td><td>80</td><td>66</td><td>17</td><td>3</td><td/><td>##IDS__IsErrorDlg_Yes##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>SetupInitialization</td><td>ActionData</td><td>Text</td><td>135</td><td>125</td><td>228</td><td>12</td><td>65539</td><td/><td>##IDS__IsInitDlg_1##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>SetupInitialization</td><td>ActionText</td><td>Text</td><td>135</td><td>109</td><td>220</td><td>36</td><td>65539</td><td/><td>##IDS__IsInitDlg_2##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>SetupInitialization</td><td>Back</td><td>PushButton</td><td>164</td><td>243</td><td>66</td><td>17</td><td>1</td><td/><td>##IDS_BACK##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>SetupInitialization</td><td>Cancel</td><td>PushButton</td><td>301</td><td>243</td><td>66</td><td>17</td><td>3</td><td/><td>##IDS_CANCEL##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>SetupInitialization</td><td>DlgLine</td><td>Line</td><td>0</td><td>234</td><td>374</td><td>0</td><td>1</td><td/><td/><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>SetupInitialization</td><td>Image</td><td>Bitmap</td><td>0</td><td>0</td><td>374</td><td>234</td><td>1</td><td/><td/><td/><td/><td>0</td><td/><td/><td>NewBinary5</td></row>
+		<row><td>SetupInitialization</td><td>Next</td><td>PushButton</td><td>230</td><td>243</td><td>66</td><td>17</td><td>1</td><td/><td>##IDS_NEXT##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>SetupInitialization</td><td>TextLine1</td><td>Text</td><td>135</td><td>8</td><td>225</td><td>45</td><td>65539</td><td/><td>##IDS__IsInitDlg_WelcomeWizard##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>SetupInitialization</td><td>TextLine2</td><td>Text</td><td>135</td><td>55</td><td>228</td><td>30</td><td>65539</td><td/><td>##IDS__IsInitDlg_PreparingWizard##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>SetupInterrupted</td><td>Back</td><td>PushButton</td><td>164</td><td>243</td><td>66</td><td>17</td><td>1</td><td/><td>##IDS_BACK##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>SetupInterrupted</td><td>Cancel</td><td>PushButton</td><td>301</td><td>243</td><td>66</td><td>17</td><td>1</td><td/><td>##IDS_CANCEL##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>SetupInterrupted</td><td>DlgLine</td><td>Line</td><td>0</td><td>234</td><td>374</td><td>0</td><td>1</td><td/><td/><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>SetupInterrupted</td><td>Finish</td><td>PushButton</td><td>230</td><td>243</td><td>66</td><td>17</td><td>3</td><td/><td>##IDS__IsUserExit_Finish##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>SetupInterrupted</td><td>FinishText1</td><td>Text</td><td>135</td><td>80</td><td>228</td><td>50</td><td>65539</td><td/><td>##IDS__IsUserExit_NotModified##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>SetupInterrupted</td><td>FinishText2</td><td>Text</td><td>135</td><td>135</td><td>228</td><td>25</td><td>65539</td><td/><td>##IDS__IsUserExit_ClickFinish##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>SetupInterrupted</td><td>Image</td><td>Bitmap</td><td>0</td><td>0</td><td>374</td><td>234</td><td>1</td><td/><td/><td/><td/><td>0</td><td/><td/><td>NewBinary5</td></row>
+		<row><td>SetupInterrupted</td><td>RestContText1</td><td>Text</td><td>135</td><td>80</td><td>228</td><td>50</td><td>65539</td><td/><td>##IDS__IsUserExit_KeepOrRestore##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>SetupInterrupted</td><td>RestContText2</td><td>Text</td><td>135</td><td>135</td><td>228</td><td>25</td><td>65539</td><td/><td>##IDS__IsUserExit_RestoreOrContinue##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>SetupInterrupted</td><td>TextLine1</td><td>Text</td><td>135</td><td>8</td><td>225</td><td>45</td><td>65539</td><td/><td>##IDS__IsUserExit_WizardCompleted##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>SetupInterrupted</td><td>TextLine2</td><td>Text</td><td>135</td><td>55</td><td>228</td><td>25</td><td>65539</td><td/><td>##IDS__IsUserExit_WizardInterrupted##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>SetupProgress</td><td>ActionProgress95</td><td>ProgressBar</td><td>59</td><td>113</td><td>275</td><td>12</td><td>65537</td><td/><td>##IDS__IsProgressDlg_ProgressDone##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>SetupProgress</td><td>ActionText</td><td>Text</td><td>59</td><td>100</td><td>275</td><td>12</td><td>3</td><td/><td>##IDS__IsProgressDlg_2##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>SetupProgress</td><td>Back</td><td>PushButton</td><td>164</td><td>243</td><td>66</td><td>17</td><td>1</td><td/><td>##IDS_BACK##</td><td>Next</td><td/><td>0</td><td/><td/><td/></row>
+		<row><td>SetupProgress</td><td>Banner</td><td>Bitmap</td><td>0</td><td>0</td><td>374</td><td>44</td><td>1</td><td/><td/><td/><td/><td>0</td><td/><td/><td>NewBinary1</td></row>
+		<row><td>SetupProgress</td><td>BannerLine</td><td>Line</td><td>0</td><td>44</td><td>374</td><td>0</td><td>1</td><td/><td/><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>SetupProgress</td><td>Branding1</td><td>Text</td><td>4</td><td>229</td><td>50</td><td>13</td><td>3</td><td/><td>##IDS_INSTALLSHIELD_FORMATTED##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>SetupProgress</td><td>Branding2</td><td>Text</td><td>3</td><td>228</td><td>50</td><td>13</td><td>65537</td><td/><td>##IDS_INSTALLSHIELD##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>SetupProgress</td><td>Cancel</td><td>PushButton</td><td>301</td><td>243</td><td>66</td><td>17</td><td>3</td><td/><td>##IDS_CANCEL##</td><td>Back</td><td/><td>0</td><td/><td/><td/></row>
+		<row><td>SetupProgress</td><td>DlgDesc</td><td>Text</td><td>21</td><td>23</td><td>292</td><td>25</td><td>65538</td><td/><td>##IDS__IsProgressDlg_UninstallingFeatures2##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>SetupProgress</td><td>DlgDesc2</td><td>Text</td><td>21</td><td>23</td><td>292</td><td>25</td><td>65538</td><td/><td>##IDS__IsProgressDlg_UninstallingFeatures##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>SetupProgress</td><td>DlgLine</td><td>Line</td><td>48</td><td>234</td><td>326</td><td>0</td><td>1</td><td/><td/><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>SetupProgress</td><td>DlgText</td><td>Text</td><td>59</td><td>51</td><td>275</td><td>30</td><td>65538</td><td/><td>##IDS__IsProgressDlg_WaitUninstall2##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>SetupProgress</td><td>DlgText2</td><td>Text</td><td>59</td><td>51</td><td>275</td><td>30</td><td>65538</td><td/><td>##IDS__IsProgressDlg_WaitUninstall##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>SetupProgress</td><td>DlgTitle</td><td>Text</td><td>13</td><td>6</td><td>292</td><td>25</td><td>65538</td><td/><td>##IDS__IsProgressDlg_InstallingProductName##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>SetupProgress</td><td>DlgTitle2</td><td>Text</td><td>13</td><td>6</td><td>292</td><td>25</td><td>65538</td><td/><td>##IDS__IsProgressDlg_Uninstalling##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>SetupProgress</td><td>LbSec</td><td>Text</td><td>172</td><td>139</td><td>32</td><td>12</td><td>2</td><td/><td>##IDS__IsProgressDlg_SecHidden##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>SetupProgress</td><td>LbStatus</td><td>Text</td><td>59</td><td>85</td><td>70</td><td>12</td><td>3</td><td/><td>##IDS__IsProgressDlg_Status##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>SetupProgress</td><td>Next</td><td>PushButton</td><td>230</td><td>243</td><td>66</td><td>17</td><td>1</td><td/><td>##IDS_NEXT##</td><td>Cancel</td><td/><td>0</td><td/><td/><td/></row>
+		<row><td>SetupProgress</td><td>SetupIcon</td><td>Icon</td><td>21</td><td>51</td><td>24</td><td>24</td><td>5242881</td><td/><td/><td/><td/><td>0</td><td/><td/><td>NewBinary9</td></row>
+		<row><td>SetupProgress</td><td>ShowTime</td><td>Text</td><td>155</td><td>139</td><td>17</td><td>12</td><td>2</td><td/><td>##IDS__IsProgressDlg_Hidden##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>SetupProgress</td><td>TextTime</td><td>Text</td><td>59</td><td>139</td><td>96</td><td>12</td><td>2</td><td/><td>##IDS__IsProgressDlg_HiddenTimeRemaining##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>SetupResume</td><td>Back</td><td>PushButton</td><td>164</td><td>243</td><td>66</td><td>17</td><td>1</td><td/><td>##IDS_BACK##</td><td>Next</td><td/><td>0</td><td/><td/><td/></row>
+		<row><td>SetupResume</td><td>Cancel</td><td>PushButton</td><td>301</td><td>243</td><td>66</td><td>17</td><td>3</td><td/><td>##IDS_CANCEL##</td><td>Back</td><td/><td>0</td><td/><td/><td/></row>
+		<row><td>SetupResume</td><td>DlgLine</td><td>Line</td><td>0</td><td>234</td><td>374</td><td>0</td><td>1</td><td/><td/><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>SetupResume</td><td>Image</td><td>Bitmap</td><td>0</td><td>0</td><td>374</td><td>234</td><td>1</td><td/><td/><td/><td/><td>0</td><td/><td/><td>NewBinary5</td></row>
+		<row><td>SetupResume</td><td>Next</td><td>PushButton</td><td>230</td><td>243</td><td>66</td><td>17</td><td>3</td><td/><td>##IDS_NEXT##</td><td>Cancel</td><td/><td>0</td><td/><td/><td/></row>
+		<row><td>SetupResume</td><td>PreselectedText</td><td>Text</td><td>135</td><td>55</td><td>228</td><td>45</td><td>65539</td><td/><td>##IDS__IsResumeDlg_WizardResume##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>SetupResume</td><td>ResumeText</td><td>Text</td><td>135</td><td>46</td><td>228</td><td>45</td><td>65539</td><td/><td>##IDS__IsResumeDlg_ResumeSuspended##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>SetupResume</td><td>TextLine1</td><td>Text</td><td>135</td><td>8</td><td>225</td><td>45</td><td>65539</td><td/><td>##IDS__IsResumeDlg_Resuming##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>SetupType</td><td>Back</td><td>PushButton</td><td>164</td><td>243</td><td>66</td><td>17</td><td>3</td><td/><td>##IDS_BACK##</td><td>Next</td><td/><td>0</td><td/><td/><td/></row>
+		<row><td>SetupType</td><td>Banner</td><td>Bitmap</td><td>0</td><td>0</td><td>374</td><td>44</td><td>1</td><td/><td/><td/><td/><td>0</td><td/><td/><td>NewBinary1</td></row>
+		<row><td>SetupType</td><td>BannerLine</td><td>Line</td><td>0</td><td>44</td><td>374</td><td>0</td><td>1</td><td/><td/><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>SetupType</td><td>Branding1</td><td>Text</td><td>4</td><td>229</td><td>50</td><td>13</td><td>3</td><td/><td>##IDS_INSTALLSHIELD_FORMATTED##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>SetupType</td><td>Branding2</td><td>Text</td><td>3</td><td>228</td><td>50</td><td>13</td><td>65537</td><td/><td>##IDS_INSTALLSHIELD##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>SetupType</td><td>Cancel</td><td>PushButton</td><td>301</td><td>243</td><td>66</td><td>17</td><td>3</td><td/><td>##IDS_CANCEL##</td><td>RadioGroup</td><td/><td>0</td><td/><td/><td/></row>
+		<row><td>SetupType</td><td>CompText</td><td>Text</td><td>80</td><td>94</td><td>246</td><td>35</td><td>3</td><td/><td>##IDS__IsSetupTypeMinDlg_AllFeatures##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>SetupType</td><td>CompleteIco</td><td>Icon</td><td>34</td><td>94</td><td>24</td><td>24</td><td>5242881</td><td/><td/><td/><td/><td>0</td><td/><td/><td>NewBinary10</td></row>
+		<row><td>SetupType</td><td>CustText</td><td>Text</td><td>80</td><td>154</td><td>246</td><td>35</td><td>3</td><td/><td>##IDS__IsSetupTypeMinDlg_ChooseFeatures##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>SetupType</td><td>CustomIco</td><td>Icon</td><td>34</td><td>154</td><td>24</td><td>24</td><td>5242881</td><td/><td/><td/><td/><td>0</td><td/><td/><td>NewBinary6</td></row>
+		<row><td>SetupType</td><td>DlgDesc</td><td>Text</td><td>21</td><td>23</td><td>292</td><td>25</td><td>65539</td><td/><td>##IDS__IsSetupTypeMinDlg_ChooseSetupType##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>SetupType</td><td>DlgLine</td><td>Line</td><td>48</td><td>234</td><td>326</td><td>0</td><td>1</td><td/><td/><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>SetupType</td><td>DlgText</td><td>Text</td><td>21</td><td>51</td><td>326</td><td>10</td><td>3</td><td/><td>##IDS__IsSetupTypeMinDlg_SelectSetupType##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>SetupType</td><td>DlgTitle</td><td>Text</td><td>13</td><td>6</td><td>292</td><td>25</td><td>65539</td><td/><td>##IDS__IsSetupTypeMinDlg_SetupType##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>SetupType</td><td>Next</td><td>PushButton</td><td>230</td><td>243</td><td>66</td><td>17</td><td>3</td><td/><td>##IDS_NEXT##</td><td>Cancel</td><td/><td>0</td><td/><td/><td/></row>
+		<row><td>SetupType</td><td>RadioGroup</td><td>RadioButtonGroup</td><td>21</td><td>79</td><td>264</td><td>120</td><td>3</td><td>_IsSetupTypeMin</td><td>##IDS__IsSetupTypeMinDlg_13##</td><td>Back</td><td/><td>0</td><td/><td/><td/></row>
+		<row><td>SplashBitmap</td><td>Back</td><td>PushButton</td><td>164</td><td>243</td><td>66</td><td>17</td><td>1</td><td/><td>##IDS_BACK##</td><td>Next</td><td/><td>0</td><td/><td/><td/></row>
+		<row><td>SplashBitmap</td><td>Branding1</td><td>Text</td><td>4</td><td>229</td><td>50</td><td>13</td><td>3</td><td/><td>##IDS_INSTALLSHIELD_FORMATTED##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>SplashBitmap</td><td>Branding2</td><td>Text</td><td>3</td><td>228</td><td>50</td><td>13</td><td>65537</td><td/><td>##IDS_INSTALLSHIELD##</td><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>SplashBitmap</td><td>Cancel</td><td>PushButton</td><td>301</td><td>243</td><td>66</td><td>17</td><td>3</td><td/><td>##IDS_CANCEL##</td><td>Back</td><td/><td>0</td><td/><td/><td/></row>
+		<row><td>SplashBitmap</td><td>DlgLine</td><td>Line</td><td>48</td><td>234</td><td>374</td><td>0</td><td>1</td><td/><td/><td/><td/><td>0</td><td/><td/><td/></row>
+		<row><td>SplashBitmap</td><td>Image</td><td>Bitmap</td><td>13</td><td>12</td><td>349</td><td>211</td><td>1</td><td/><td/><td/><td/><td>0</td><td/><td/><td>NewBinary5</td></row>
+		<row><td>SplashBitmap</td><td>Next</td><td>PushButton</td><td>230</td><td>243</td><td>66</td><td>17</td><td>3</td><td/><td>##IDS_NEXT##</td><td>Cancel</td><td/><td>0</td><td/><td/><td/></row>
+	</table>
+
+	<table name="ControlCondition">
+		<col key="yes" def="s72">Dialog_</col>
+		<col key="yes" def="s50">Control_</col>
+		<col key="yes" def="s50">Action</col>
+		<col key="yes" def="s255">Condition</col>
+		<row><td>CustomSetup</td><td>ChangeFolder</td><td>Hide</td><td>Installed</td></row>
+		<row><td>CustomSetup</td><td>Details</td><td>Hide</td><td>Installed</td></row>
+		<row><td>CustomSetup</td><td>InstallLabel</td><td>Hide</td><td>Installed</td></row>
+		<row><td>CustomerInformation</td><td>DlgRadioGroupText</td><td>Hide</td><td>NOT Privileged</td></row>
+		<row><td>CustomerInformation</td><td>DlgRadioGroupText</td><td>Hide</td><td>ProductState &gt; 0</td></row>
+		<row><td>CustomerInformation</td><td>DlgRadioGroupText</td><td>Hide</td><td>Version9X</td></row>
+		<row><td>CustomerInformation</td><td>RadioGroup</td><td>Hide</td><td>NOT Privileged</td></row>
+		<row><td>CustomerInformation</td><td>RadioGroup</td><td>Hide</td><td>ProductState &gt; 0</td></row>
+		<row><td>CustomerInformation</td><td>RadioGroup</td><td>Hide</td><td>Version9X</td></row>
+		<row><td>CustomerInformation</td><td>SerialLabel</td><td>Show</td><td>SERIALNUMSHOW</td></row>
+		<row><td>CustomerInformation</td><td>SerialNumber</td><td>Show</td><td>SERIALNUMSHOW</td></row>
+		<row><td>InstallWelcome</td><td>Copyright</td><td>Hide</td><td>SHOWCOPYRIGHT="No"</td></row>
+		<row><td>InstallWelcome</td><td>Copyright</td><td>Show</td><td>SHOWCOPYRIGHT="Yes"</td></row>
+		<row><td>LicenseAgreement</td><td>Next</td><td>Disable</td><td>AgreeToLicense &lt;&gt; "Yes"</td></row>
+		<row><td>LicenseAgreement</td><td>Next</td><td>Enable</td><td>AgreeToLicense = "Yes"</td></row>
+		<row><td>ReadyToInstall</td><td>DlgTitle</td><td>Show</td><td>ProgressType0="Modify"</td></row>
+		<row><td>ReadyToInstall</td><td>DlgTitle2</td><td>Show</td><td>ProgressType0="Repair"</td></row>
+		<row><td>ReadyToInstall</td><td>DlgTitle3</td><td>Show</td><td>ProgressType0="install"</td></row>
+		<row><td>SQLLogin</td><td>EdtLogin</td><td>Disable</td><td>IS_SQLSERVER_AUTHENTICATION=0</td></row>
+		<row><td>SQLLogin</td><td>EdtLogin</td><td>Enable</td><td>IS_SQLSERVER_AUTHENTICATION=1</td></row>
+		<row><td>SQLLogin</td><td>EdtPswd</td><td>Disable</td><td>IS_SQLSERVER_AUTHENTICATION=0</td></row>
+		<row><td>SQLLogin</td><td>EdtPswd</td><td>Enable</td><td>IS_SQLSERVER_AUTHENTICATION=1</td></row>
+		<row><td>SQLLogin</td><td>lblLoginID</td><td>Disable</td><td>IS_SQLSERVER_AUTHENTICATION=0</td></row>
+		<row><td>SQLLogin</td><td>lblLoginID</td><td>Enable</td><td>IS_SQLSERVER_AUTHENTICATION=1</td></row>
+		<row><td>SQLLogin</td><td>lblPswd</td><td>Disable</td><td>IS_SQLSERVER_AUTHENTICATION=0</td></row>
+		<row><td>SQLLogin</td><td>lblPswd</td><td>Enable</td><td>IS_SQLSERVER_AUTHENTICATION=1</td></row>
+		<row><td>SetupCompleteError</td><td>Back</td><td>Default</td><td>UpdateStarted</td></row>
+		<row><td>SetupCompleteError</td><td>Back</td><td>Disable</td><td>NOT UpdateStarted</td></row>
+		<row><td>SetupCompleteError</td><td>Back</td><td>Enable</td><td>UpdateStarted</td></row>
+		<row><td>SetupCompleteError</td><td>Cancel</td><td>Disable</td><td>NOT UpdateStarted</td></row>
+		<row><td>SetupCompleteError</td><td>Cancel</td><td>Enable</td><td>UpdateStarted</td></row>
+		<row><td>SetupCompleteError</td><td>Finish</td><td>Default</td><td>NOT UpdateStarted</td></row>
+		<row><td>SetupCompleteError</td><td>FinishText1</td><td>Hide</td><td>UpdateStarted</td></row>
+		<row><td>SetupCompleteError</td><td>FinishText1</td><td>Show</td><td>NOT UpdateStarted</td></row>
+		<row><td>SetupCompleteError</td><td>FinishText2</td><td>Hide</td><td>UpdateStarted</td></row>
+		<row><td>SetupCompleteError</td><td>FinishText2</td><td>Show</td><td>NOT UpdateStarted</td></row>
+		<row><td>SetupCompleteError</td><td>RestContText1</td><td>Hide</td><td>NOT UpdateStarted</td></row>
+		<row><td>SetupCompleteError</td><td>RestContText1</td><td>Show</td><td>UpdateStarted</td></row>
+		<row><td>SetupCompleteError</td><td>RestContText2</td><td>Hide</td><td>NOT UpdateStarted</td></row>
+		<row><td>SetupCompleteError</td><td>RestContText2</td><td>Show</td><td>UpdateStarted</td></row>
+		<row><td>SetupCompleteSuccess</td><td>CheckBoxUpdates</td><td>Show</td><td>ISENABLEDWUSFINISHDIALOG And NOT Installed And ACTION="INSTALL"</td></row>
+		<row><td>SetupCompleteSuccess</td><td>CheckForUpdatesText</td><td>Show</td><td>ISENABLEDWUSFINISHDIALOG And NOT Installed And ACTION="INSTALL"</td></row>
+		<row><td>SetupCompleteSuccess</td><td>CheckLaunchProgram</td><td>Show</td><td>SHOWLAUNCHPROGRAM="-1" And PROGRAMFILETOLAUNCHATEND &lt;&gt; "" And NOT Installed And NOT ISENABLEDWUSFINISHDIALOG</td></row>
+		<row><td>SetupCompleteSuccess</td><td>CheckLaunchReadme</td><td>Show</td><td>SHOWLAUNCHREADME="-1"  And READMEFILETOLAUNCHATEND &lt;&gt; "" And NOT Installed And NOT ISENABLEDWUSFINISHDIALOG</td></row>
+		<row><td>SetupCompleteSuccess</td><td>LaunchProgramText</td><td>Show</td><td>SHOWLAUNCHPROGRAM="-1" And PROGRAMFILETOLAUNCHATEND &lt;&gt; "" And NOT Installed And NOT ISENABLEDWUSFINISHDIALOG</td></row>
+		<row><td>SetupCompleteSuccess</td><td>LaunchReadmeText</td><td>Show</td><td>SHOWLAUNCHREADME="-1"  And READMEFILETOLAUNCHATEND &lt;&gt; "" And NOT Installed And NOT ISENABLEDWUSFINISHDIALOG</td></row>
+		<row><td>SetupCompleteSuccess</td><td>TextLine2</td><td>Show</td><td>ProgressType2="installed" And ((ACTION&lt;&gt;"INSTALL") OR (NOT ISENABLEDWUSFINISHDIALOG) OR (ISENABLEDWUSFINISHDIALOG And Installed))</td></row>
+		<row><td>SetupCompleteSuccess</td><td>TextLine3</td><td>Show</td><td>ProgressType2="uninstalled" And ((ACTION&lt;&gt;"INSTALL") OR (NOT ISENABLEDWUSFINISHDIALOG) OR (ISENABLEDWUSFINISHDIALOG And Installed))</td></row>
+		<row><td>SetupCompleteSuccess</td><td>UpdateTextLine1</td><td>Show</td><td>ISENABLEDWUSFINISHDIALOG And NOT Installed And ACTION="INSTALL"</td></row>
+		<row><td>SetupCompleteSuccess</td><td>UpdateTextLine2</td><td>Show</td><td>ISENABLEDWUSFINISHDIALOG And NOT Installed And ACTION="INSTALL"</td></row>
+		<row><td>SetupCompleteSuccess</td><td>UpdateTextLine3</td><td>Show</td><td>ISENABLEDWUSFINISHDIALOG And NOT Installed And ACTION="INSTALL"</td></row>
+		<row><td>SetupInterrupted</td><td>Back</td><td>Default</td><td>UpdateStarted</td></row>
+		<row><td>SetupInterrupted</td><td>Back</td><td>Disable</td><td>NOT UpdateStarted</td></row>
+		<row><td>SetupInterrupted</td><td>Back</td><td>Enable</td><td>UpdateStarted</td></row>
+		<row><td>SetupInterrupted</td><td>Cancel</td><td>Disable</td><td>NOT UpdateStarted</td></row>
+		<row><td>SetupInterrupted</td><td>Cancel</td><td>Enable</td><td>UpdateStarted</td></row>
+		<row><td>SetupInterrupted</td><td>Finish</td><td>Default</td><td>NOT UpdateStarted</td></row>
+		<row><td>SetupInterrupted</td><td>FinishText1</td><td>Hide</td><td>UpdateStarted</td></row>
+		<row><td>SetupInterrupted</td><td>FinishText1</td><td>Show</td><td>NOT UpdateStarted</td></row>
+		<row><td>SetupInterrupted</td><td>FinishText2</td><td>Hide</td><td>UpdateStarted</td></row>
+		<row><td>SetupInterrupted</td><td>FinishText2</td><td>Show</td><td>NOT UpdateStarted</td></row>
+		<row><td>SetupInterrupted</td><td>RestContText1</td><td>Hide</td><td>NOT UpdateStarted</td></row>
+		<row><td>SetupInterrupted</td><td>RestContText1</td><td>Show</td><td>UpdateStarted</td></row>
+		<row><td>SetupInterrupted</td><td>RestContText2</td><td>Hide</td><td>NOT UpdateStarted</td></row>
+		<row><td>SetupInterrupted</td><td>RestContText2</td><td>Show</td><td>UpdateStarted</td></row>
+		<row><td>SetupProgress</td><td>DlgDesc</td><td>Show</td><td>ProgressType2="installed"</td></row>
+		<row><td>SetupProgress</td><td>DlgDesc2</td><td>Show</td><td>ProgressType2="uninstalled"</td></row>
+		<row><td>SetupProgress</td><td>DlgText</td><td>Show</td><td>ProgressType3="installs"</td></row>
+		<row><td>SetupProgress</td><td>DlgText2</td><td>Show</td><td>ProgressType3="uninstalls"</td></row>
+		<row><td>SetupProgress</td><td>DlgTitle</td><td>Show</td><td>ProgressType1="Installing"</td></row>
+		<row><td>SetupProgress</td><td>DlgTitle2</td><td>Show</td><td>ProgressType1="Uninstalling"</td></row>
+		<row><td>SetupResume</td><td>PreselectedText</td><td>Hide</td><td>RESUME</td></row>
+		<row><td>SetupResume</td><td>PreselectedText</td><td>Show</td><td>NOT RESUME</td></row>
+		<row><td>SetupResume</td><td>ResumeText</td><td>Hide</td><td>NOT RESUME</td></row>
+		<row><td>SetupResume</td><td>ResumeText</td><td>Show</td><td>RESUME</td></row>
+	</table>
+
+	<table name="ControlEvent">
+		<col key="yes" def="s72">Dialog_</col>
+		<col key="yes" def="s50">Control_</col>
+		<col key="yes" def="s50">Event</col>
+		<col key="yes" def="s255">Argument</col>
+		<col key="yes" def="S255">Condition</col>
+		<col def="I2">Ordering</col>
+		<row><td>AdminChangeFolder</td><td>Cancel</td><td>EndDialog</td><td>Return</td><td>1</td><td>2</td></row>
+		<row><td>AdminChangeFolder</td><td>Cancel</td><td>Reset</td><td>0</td><td>1</td><td>1</td></row>
+		<row><td>AdminChangeFolder</td><td>NewFolder</td><td>DirectoryListNew</td><td>0</td><td>1</td><td>0</td></row>
+		<row><td>AdminChangeFolder</td><td>OK</td><td>EndDialog</td><td>Return</td><td>1</td><td>0</td></row>
+		<row><td>AdminChangeFolder</td><td>OK</td><td>SetTargetPath</td><td>TARGETDIR</td><td>1</td><td>1</td></row>
+		<row><td>AdminChangeFolder</td><td>Up</td><td>DirectoryListUp</td><td>0</td><td>1</td><td>0</td></row>
+		<row><td>AdminNetworkLocation</td><td>Back</td><td>NewDialog</td><td>AdminWelcome</td><td>1</td><td>0</td></row>
+		<row><td>AdminNetworkLocation</td><td>Browse</td><td>SpawnDialog</td><td>AdminChangeFolder</td><td>1</td><td>0</td></row>
+		<row><td>AdminNetworkLocation</td><td>Cancel</td><td>SpawnDialog</td><td>CancelSetup</td><td>1</td><td>0</td></row>
+		<row><td>AdminNetworkLocation</td><td>InstallNow</td><td>EndDialog</td><td>Return</td><td>OutOfNoRbDiskSpace &lt;&gt; 1</td><td>3</td></row>
+		<row><td>AdminNetworkLocation</td><td>InstallNow</td><td>NewDialog</td><td>OutOfSpace</td><td>OutOfNoRbDiskSpace = 1</td><td>2</td></row>
+		<row><td>AdminNetworkLocation</td><td>InstallNow</td><td>SetTargetPath</td><td>TARGETDIR</td><td>1</td><td>1</td></row>
+		<row><td>AdminWelcome</td><td>Cancel</td><td>SpawnDialog</td><td>CancelSetup</td><td>1</td><td>0</td></row>
+		<row><td>AdminWelcome</td><td>Next</td><td>NewDialog</td><td>AdminNetworkLocation</td><td>1</td><td>0</td></row>
+		<row><td>CancelSetup</td><td>No</td><td>EndDialog</td><td>Return</td><td>1</td><td>0</td></row>
+		<row><td>CancelSetup</td><td>Yes</td><td>EndDialog</td><td>Exit</td><td>1</td><td>2</td></row>
+		<row><td>CustomSetup</td><td>Back</td><td>NewDialog</td><td>DestinationFolder</td><td>Installed</td><td>0</td></row>
+		<row><td>CustomSetup</td><td>Back</td><td>NewDialog</td><td>SetupType</td><td>NOT Installed</td><td>0</td></row>
+		<row><td>CustomSetup</td><td>Cancel</td><td>SpawnDialog</td><td>CancelSetup</td><td>1</td><td>0</td></row>
+		<row><td>CustomSetup</td><td>ChangeFolder</td><td>SelectionBrowse</td><td>InstallChangeFolder</td><td>1</td><td>0</td></row>
+		<row><td>CustomSetup</td><td>Details</td><td>SelectionBrowse</td><td>DiskSpaceRequirements</td><td>1</td><td>1</td></row>
+		<row><td>CustomSetup</td><td>Help</td><td>SpawnDialog</td><td>CustomSetupTips</td><td>1</td><td>1</td></row>
+		<row><td>CustomSetup</td><td>Next</td><td>NewDialog</td><td>OutOfSpace</td><td>OutOfNoRbDiskSpace = 1</td><td>0</td></row>
+		<row><td>CustomSetup</td><td>Next</td><td>NewDialog</td><td>ReadyToInstall</td><td>OutOfNoRbDiskSpace &lt;&gt; 1</td><td>0</td></row>
+		<row><td>CustomSetup</td><td>Next</td><td>[_IsSetupTypeMin]</td><td>Custom</td><td>1</td><td>0</td></row>
+		<row><td>CustomSetupTips</td><td>OK</td><td>EndDialog</td><td>Return</td><td>1</td><td>1</td></row>
+		<row><td>CustomerInformation</td><td>Back</td><td>NewDialog</td><td>LicenseAgreement</td><td>1</td><td>1</td></row>
+		<row><td>CustomerInformation</td><td>Cancel</td><td>SpawnDialog</td><td>CancelSetup</td><td>1</td><td>0</td></row>
+		<row><td>CustomerInformation</td><td>Next</td><td>EndDialog</td><td>Exit</td><td>(SERIALNUMVALRETRYLIMIT) And (SERIALNUMVALRETRYLIMIT&lt;0) And (SERIALNUMVALRETURN&lt;&gt;SERIALNUMVALSUCCESSRETVAL)</td><td>3</td></row>
+		<row><td>CustomerInformation</td><td>Next</td><td>NewDialog</td><td>SetupType</td><td>(Not SERIALNUMVALRETURN) OR (SERIALNUMVALRETURN=SERIALNUMVALSUCCESSRETVAL)</td><td>4</td></row>
+		<row><td>CustomerInformation</td><td>Next</td><td>[ALLUSERS]</td><td>1</td><td>ApplicationUsers = "AllUsers" And Privileged</td><td>1</td></row>
+		<row><td>CustomerInformation</td><td>Next</td><td>[ALLUSERS]</td><td>{}</td><td>ApplicationUsers = "OnlyCurrentUser" And Privileged</td><td>2</td></row>
+		<row><td>DatabaseFolder</td><td>Back</td><td>NewDialog</td><td>CustomerInformation</td><td>1</td><td>1</td></row>
+		<row><td>DatabaseFolder</td><td>Cancel</td><td>SpawnDialog</td><td>CancelSetup</td><td>1</td><td>1</td></row>
+		<row><td>DatabaseFolder</td><td>ChangeFolder</td><td>SpawnDialog</td><td>InstallChangeFolder</td><td>1</td><td>1</td></row>
+		<row><td>DatabaseFolder</td><td>ChangeFolder</td><td>[_BrowseProperty]</td><td>DATABASEDIR</td><td>1</td><td>2</td></row>
+		<row><td>DatabaseFolder</td><td>Next</td><td>NewDialog</td><td>SetupType</td><td>1</td><td>1</td></row>
+		<row><td>DestinationFolder</td><td>Back</td><td>NewDialog</td><td>LicenseAgreement</td><td>1</td><td>0</td></row>
+		<row><td>DestinationFolder</td><td>Cancel</td><td>SpawnDialog</td><td>CancelSetup</td><td>1</td><td>1</td></row>
+		<row><td>DestinationFolder</td><td>ChangeFolder</td><td>SpawnDialog</td><td>InstallChangeFolder</td><td>1</td><td>1</td></row>
+		<row><td>DestinationFolder</td><td>ChangeFolder</td><td>[_BrowseProperty]</td><td>INSTALLDIR</td><td>1</td><td>2</td></row>
+		<row><td>DestinationFolder</td><td>Next</td><td>NewDialog</td><td>ReadyToInstall</td><td>1</td><td>0</td></row>
+		<row><td>DiskSpaceRequirements</td><td>OK</td><td>EndDialog</td><td>Return</td><td>1</td><td>0</td></row>
+		<row><td>FilesInUse</td><td>Exit</td><td>EndDialog</td><td>Exit</td><td>1</td><td>0</td></row>
+		<row><td>FilesInUse</td><td>Ignore</td><td>EndDialog</td><td>Ignore</td><td>1</td><td>0</td></row>
+		<row><td>FilesInUse</td><td>Retry</td><td>EndDialog</td><td>Retry</td><td>1</td><td>0</td></row>
+		<row><td>InstallChangeFolder</td><td>Cancel</td><td>EndDialog</td><td>Return</td><td>1</td><td>2</td></row>
+		<row><td>InstallChangeFolder</td><td>Cancel</td><td>Reset</td><td>0</td><td>1</td><td>1</td></row>
+		<row><td>InstallChangeFolder</td><td>NewFolder</td><td>DirectoryListNew</td><td>0</td><td>1</td><td>0</td></row>
+		<row><td>InstallChangeFolder</td><td>OK</td><td>EndDialog</td><td>Return</td><td>1</td><td>3</td></row>
+		<row><td>InstallChangeFolder</td><td>OK</td><td>SetTargetPath</td><td>[_BrowseProperty]</td><td>1</td><td>2</td></row>
+		<row><td>InstallChangeFolder</td><td>Up</td><td>DirectoryListUp</td><td>0</td><td>1</td><td>0</td></row>
+		<row><td>InstallWelcome</td><td>Back</td><td>NewDialog</td><td>SplashBitmap</td><td>Display_IsBitmapDlg</td><td>0</td></row>
+		<row><td>InstallWelcome</td><td>Cancel</td><td>SpawnDialog</td><td>CancelSetup</td><td>1</td><td>0</td></row>
+		<row><td>InstallWelcome</td><td>Next</td><td>NewDialog</td><td>LicenseAgreement</td><td>1</td><td>0</td></row>
+		<row><td>LicenseAgreement</td><td>Back</td><td>NewDialog</td><td>InstallWelcome</td><td>1</td><td>0</td></row>
+		<row><td>LicenseAgreement</td><td>Cancel</td><td>SpawnDialog</td><td>CancelSetup</td><td>1</td><td>0</td></row>
+		<row><td>LicenseAgreement</td><td>ISPrintButton</td><td>DoAction</td><td>ISPrint</td><td>1</td><td>0</td></row>
+		<row><td>LicenseAgreement</td><td>Next</td><td>NewDialog</td><td>DestinationFolder</td><td>AgreeToLicense = "Yes"</td><td>0</td></row>
+		<row><td>MaintenanceType</td><td>Back</td><td>NewDialog</td><td>MaintenanceWelcome</td><td>1</td><td>0</td></row>
+		<row><td>MaintenanceType</td><td>Cancel</td><td>SpawnDialog</td><td>CancelSetup</td><td>1</td><td>0</td></row>
+		<row><td>MaintenanceType</td><td>Next</td><td>NewDialog</td><td>CustomSetup</td><td>_IsMaintenance = "Change"</td><td>12</td></row>
+		<row><td>MaintenanceType</td><td>Next</td><td>NewDialog</td><td>ReadyToInstall</td><td>_IsMaintenance = "Reinstall"</td><td>13</td></row>
+		<row><td>MaintenanceType</td><td>Next</td><td>NewDialog</td><td>ReadyToRemove</td><td>_IsMaintenance = "Remove"</td><td>11</td></row>
+		<row><td>MaintenanceType</td><td>Next</td><td>Reinstall</td><td>ALL</td><td>_IsMaintenance = "Reinstall"</td><td>10</td></row>
+		<row><td>MaintenanceType</td><td>Next</td><td>ReinstallMode</td><td>[ReinstallModeText]</td><td>_IsMaintenance = "Reinstall"</td><td>9</td></row>
+		<row><td>MaintenanceType</td><td>Next</td><td>[ProgressType0]</td><td>Modify</td><td>_IsMaintenance = "Change"</td><td>2</td></row>
+		<row><td>MaintenanceType</td><td>Next</td><td>[ProgressType0]</td><td>Repair</td><td>_IsMaintenance = "Reinstall"</td><td>1</td></row>
+		<row><td>MaintenanceType</td><td>Next</td><td>[ProgressType1]</td><td>Modifying</td><td>_IsMaintenance = "Change"</td><td>3</td></row>
+		<row><td>MaintenanceType</td><td>Next</td><td>[ProgressType1]</td><td>Repairing</td><td>_IsMaintenance = "Reinstall"</td><td>4</td></row>
+		<row><td>MaintenanceType</td><td>Next</td><td>[ProgressType2]</td><td>modified</td><td>_IsMaintenance = "Change"</td><td>6</td></row>
+		<row><td>MaintenanceType</td><td>Next</td><td>[ProgressType2]</td><td>repairs</td><td>_IsMaintenance = "Reinstall"</td><td>5</td></row>
+		<row><td>MaintenanceType</td><td>Next</td><td>[ProgressType3]</td><td>modifies</td><td>_IsMaintenance = "Change"</td><td>7</td></row>
+		<row><td>MaintenanceType</td><td>Next</td><td>[ProgressType3]</td><td>repairs</td><td>_IsMaintenance = "Reinstall"</td><td>8</td></row>
+		<row><td>MaintenanceWelcome</td><td>Cancel</td><td>SpawnDialog</td><td>CancelSetup</td><td>1</td><td>0</td></row>
+		<row><td>MaintenanceWelcome</td><td>Next</td><td>NewDialog</td><td>MaintenanceType</td><td>1</td><td>0</td></row>
+		<row><td>OutOfSpace</td><td>Resume</td><td>NewDialog</td><td>AdminNetworkLocation</td><td>ACTION = "ADMIN"</td><td>0</td></row>
+		<row><td>OutOfSpace</td><td>Resume</td><td>NewDialog</td><td>CustomSetup</td><td>ACTION &lt;&gt; "ADMIN"</td><td>0</td></row>
+		<row><td>PatchWelcome</td><td>Back</td><td>NewDialog</td><td>SplashBitmap</td><td>Display_IsBitmapDlg</td><td>0</td></row>
+		<row><td>PatchWelcome</td><td>Cancel</td><td>SpawnDialog</td><td>CancelSetup</td><td>1</td><td>1</td></row>
+		<row><td>PatchWelcome</td><td>Next</td><td>EndDialog</td><td>Return</td><td>1</td><td>3</td></row>
+		<row><td>PatchWelcome</td><td>Next</td><td>Reinstall</td><td>ALL</td><td>PATCH And REINSTALL=""</td><td>1</td></row>
+		<row><td>PatchWelcome</td><td>Next</td><td>ReinstallMode</td><td>omus</td><td>PATCH And REINSTALLMODE=""</td><td>2</td></row>
+		<row><td>ReadyToInstall</td><td>Back</td><td>NewDialog</td><td>CustomSetup</td><td>Installed OR _IsSetupTypeMin = "Custom"</td><td>2</td></row>
+		<row><td>ReadyToInstall</td><td>Back</td><td>NewDialog</td><td>DestinationFolder</td><td>NOT Installed AND _IsSetupTypeMin &lt;&gt; "Custom"</td><td>1</td></row>
+		<row><td>ReadyToInstall</td><td>Back</td><td>NewDialog</td><td>MaintenanceType</td><td>Installed AND _IsMaintenance = "Reinstall"</td><td>3</td></row>
+		<row><td>ReadyToInstall</td><td>Cancel</td><td>SpawnDialog</td><td>CancelSetup</td><td>1</td><td>0</td></row>
+		<row><td>ReadyToInstall</td><td>InstallNow</td><td>EndDialog</td><td>Return</td><td>OutOfNoRbDiskSpace &lt;&gt; 1</td><td>0</td></row>
+		<row><td>ReadyToInstall</td><td>InstallNow</td><td>NewDialog</td><td>OutOfSpace</td><td>OutOfNoRbDiskSpace = 1</td><td>0</td></row>
+		<row><td>ReadyToInstall</td><td>InstallNow</td><td>[ProgressType1]</td><td>Installing</td><td>1</td><td>0</td></row>
+		<row><td>ReadyToInstall</td><td>InstallNow</td><td>[ProgressType2]</td><td>installed</td><td>1</td><td>0</td></row>
+		<row><td>ReadyToInstall</td><td>InstallNow</td><td>[ProgressType3]</td><td>installs</td><td>1</td><td>0</td></row>
+		<row><td>ReadyToRemove</td><td>Back</td><td>NewDialog</td><td>MaintenanceType</td><td>1</td><td>0</td></row>
+		<row><td>ReadyToRemove</td><td>Cancel</td><td>SpawnDialog</td><td>CancelSetup</td><td>1</td><td>0</td></row>
+		<row><td>ReadyToRemove</td><td>RemoveNow</td><td>EndDialog</td><td>Return</td><td>OutOfNoRbDiskSpace &lt;&gt; 1</td><td>2</td></row>
+		<row><td>ReadyToRemove</td><td>RemoveNow</td><td>NewDialog</td><td>OutOfSpace</td><td>OutOfNoRbDiskSpace = 1</td><td>2</td></row>
+		<row><td>ReadyToRemove</td><td>RemoveNow</td><td>Remove</td><td>ALL</td><td>1</td><td>1</td></row>
+		<row><td>ReadyToRemove</td><td>RemoveNow</td><td>[ProgressType1]</td><td>Uninstalling</td><td>1</td><td>0</td></row>
+		<row><td>ReadyToRemove</td><td>RemoveNow</td><td>[ProgressType2]</td><td>uninstalled</td><td>1</td><td>0</td></row>
+		<row><td>ReadyToRemove</td><td>RemoveNow</td><td>[ProgressType3]</td><td>uninstalls</td><td>1</td><td>0</td></row>
+		<row><td>SQLBrowse</td><td>Cancel</td><td>EndDialog</td><td>Return</td><td>1</td><td>1</td></row>
+		<row><td>SQLBrowse</td><td>OK</td><td>EndDialog</td><td>Return</td><td>1</td><td>2</td></row>
+		<row><td>SQLBrowse</td><td>OK</td><td>[IS_SQLSERVER_SERVER]</td><td>[IS_SQLSERVER_LIST]</td><td>1</td><td>1</td></row>
+		<row><td>SQLLogin</td><td>Back</td><td>NewDialog</td><td>CustomerInformation</td><td>1</td><td>1</td></row>
+		<row><td>SQLLogin</td><td>BtnSQLBrowse</td><td>DoAction</td><td>ISSQLServerList</td><td>1</td><td>2</td></row>
+		<row><td>SQLLogin</td><td>BtnSQLBrowse</td><td>SpawnDialog</td><td>SQLBrowse</td><td>1</td><td>3</td></row>
+		<row><td>SQLLogin</td><td>BtnSQLBrowse</td><td>[IS_SQLSERVER_LIST]</td><td>[IS_SQLSERVER_SERVER]</td><td>1</td><td>1</td></row>
+		<row><td>SQLLogin</td><td>Cancel</td><td>SpawnDialog</td><td>CancelSetup</td><td>1</td><td>1</td></row>
+		<row><td>SQLLogin</td><td>Next</td><td>DoAction</td><td>ISSQLServerValidate</td><td>1</td><td>3</td></row>
+		<row><td>SQLLogin</td><td>Next</td><td>NewDialog</td><td>SetupType</td><td>IS_SQLSERVER_STATUS=0</td><td>4</td></row>
+		<row><td>SetupCompleteError</td><td>Back</td><td>EndDialog</td><td>Return</td><td>1</td><td>2</td></row>
+		<row><td>SetupCompleteError</td><td>Back</td><td>[Suspend]</td><td>{}</td><td>1</td><td>1</td></row>
+		<row><td>SetupCompleteError</td><td>Cancel</td><td>EndDialog</td><td>Return</td><td>1</td><td>2</td></row>
+		<row><td>SetupCompleteError</td><td>Cancel</td><td>[Suspend]</td><td>1</td><td>1</td><td>1</td></row>
+		<row><td>SetupCompleteError</td><td>Finish</td><td>EndDialog</td><td>Exit</td><td>1</td><td>2</td></row>
+		<row><td>SetupCompleteSuccess</td><td>OK</td><td>DoAction</td><td>CheckForProductUpdates</td><td>ISCHECKFORPRODUCTUPDATES="1" And ISENABLEDWUSFINISHDIALOG And NOT ISREBOOTREQUIRED And NOT Installed And ACTION="INSTALL"</td><td>4</td></row>
+		<row><td>SetupCompleteSuccess</td><td>OK</td><td>DoAction</td><td>CheckForProductUpdatesOnReboot</td><td>ISCHECKFORPRODUCTUPDATES="1" And ISENABLEDWUSFINISHDIALOG And ISREBOOTREQUIRED And NOT Installed And ACTION="INSTALL"</td><td>5</td></row>
+		<row><td>SetupCompleteSuccess</td><td>OK</td><td>DoAction</td><td>IS_LAUNCH_MY_PROGRAM_PLEASE</td><td>LAUNCHPROGRAM</td><td/></row>
+		<row><td>SetupCompleteSuccess</td><td>OK</td><td>EndDialog</td><td>Exit</td><td>1</td><td>2</td></row>
+		<row><td>SetupError</td><td>A</td><td>EndDialog</td><td>ErrorAbort</td><td>1</td><td>0</td></row>
+		<row><td>SetupError</td><td>C</td><td>EndDialog</td><td>ErrorCancel</td><td>1</td><td>0</td></row>
+		<row><td>SetupError</td><td>I</td><td>EndDialog</td><td>ErrorIgnore</td><td>1</td><td>0</td></row>
+		<row><td>SetupError</td><td>N</td><td>EndDialog</td><td>ErrorNo</td><td>1</td><td>0</td></row>
+		<row><td>SetupError</td><td>O</td><td>EndDialog</td><td>ErrorOk</td><td>1</td><td>0</td></row>
+		<row><td>SetupError</td><td>R</td><td>EndDialog</td><td>ErrorRetry</td><td>1</td><td>0</td></row>
+		<row><td>SetupError</td><td>Y</td><td>EndDialog</td><td>ErrorYes</td><td>1</td><td>0</td></row>
+		<row><td>SetupInitialization</td><td>Cancel</td><td>SpawnDialog</td><td>CancelSetup</td><td>1</td><td>0</td></row>
+		<row><td>SetupInterrupted</td><td>Back</td><td>EndDialog</td><td>Exit</td><td>1</td><td>2</td></row>
+		<row><td>SetupInterrupted</td><td>Back</td><td>[Suspend]</td><td>{}</td><td>1</td><td>1</td></row>
+		<row><td>SetupInterrupted</td><td>Cancel</td><td>EndDialog</td><td>Exit</td><td>1</td><td>2</td></row>
+		<row><td>SetupInterrupted</td><td>Cancel</td><td>[Suspend]</td><td>1</td><td>1</td><td>1</td></row>
+		<row><td>SetupInterrupted</td><td>Finish</td><td>EndDialog</td><td>Exit</td><td>1</td><td>2</td></row>
+		<row><td>SetupProgress</td><td>Cancel</td><td>SpawnDialog</td><td>CancelSetup</td><td>1</td><td>0</td></row>
+		<row><td>SetupResume</td><td>Cancel</td><td>SpawnDialog</td><td>CancelSetup</td><td>1</td><td>0</td></row>
+		<row><td>SetupResume</td><td>Next</td><td>EndDialog</td><td>Return</td><td>OutOfNoRbDiskSpace &lt;&gt; 1</td><td>0</td></row>
+		<row><td>SetupResume</td><td>Next</td><td>NewDialog</td><td>OutOfSpace</td><td>OutOfNoRbDiskSpace = 1</td><td>0</td></row>
+		<row><td>SetupType</td><td>Back</td><td>NewDialog</td><td>DestinationFolder</td><td>1</td><td>0</td></row>
+		<row><td>SetupType</td><td>Cancel</td><td>SpawnDialog</td><td>CancelSetup</td><td>1</td><td>0</td></row>
+		<row><td>SetupType</td><td>Next</td><td>AddLocal</td><td>ALL</td><td>_IsSetupTypeMin = "Typical"</td><td>0</td></row>
+		<row><td>SetupType</td><td>Next</td><td>NewDialog</td><td>CustomSetup</td><td>_IsSetupTypeMin = "Custom"</td><td>0</td></row>
+		<row><td>SetupType</td><td>Next</td><td>NewDialog</td><td>ReadyToInstall</td><td>_IsSetupTypeMin &lt;&gt; "Custom"</td><td>0</td></row>
+		<row><td>SplashBitmap</td><td>Cancel</td><td>SpawnDialog</td><td>CancelSetup</td><td>1</td><td>0</td></row>
+		<row><td>SplashBitmap</td><td>Next</td><td>NewDialog</td><td>InstallWelcome</td><td>1</td><td>0</td></row>
+	</table>
+
+	<table name="CreateFolder">
+		<col key="yes" def="s72">Directory_</col>
+		<col key="yes" def="s72">Component_</col>
+		<row><td>BIN</td><td>AllOtherFiles10</td></row>
+		<row><td>BIN</td><td>AllOtherFiles11</td></row>
+		<row><td>BIN</td><td>AllOtherFiles8</td></row>
+		<row><td>CONF</td><td>AllOtherFiles5</td></row>
+		<row><td>CONF</td><td>AllOtherFiles9</td></row>
+		<row><td>INSTALLDIR</td><td>AllOtherFiles4</td></row>
+		<row><td>INSTALLDIR</td><td>AllOtherFiles5</td></row>
+		<row><td>INSTALLDIR</td><td>AllOtherFiles6</td></row>
+		<row><td>INSTALLDIR</td><td>AllOtherFiles7</td></row>
+		<row><td>INSTALLDIR</td><td>ISRegistryComponent</td></row>
+		<row><td>INSTALLDIR</td><td>ISRegistryComponent1</td></row>
+		<row><td>INSTALLDIR</td><td>VirtualDirComponent</td></row>
+		<row><td>LOG</td><td>AllOtherFiles12</td></row>
+	</table>
+
+	<table name="CustomAction">
+		<col key="yes" def="s72">Action</col>
+		<col def="i2">Type</col>
+		<col def="S64">Source</col>
+		<col def="S0">Target</col>
+		<col def="S255">ISComments</col>
+		<row><td>CheckForProductUpdates</td><td>226</td><td>ISUpdateServiceFolder</td><td>[ISUpdateServiceFolder]agent.exe "/au[ProductCode] /EndOfInstall"</td><td>Checks for product updates</td></row>
+		<row><td>CheckForProductUpdatesOnReboot</td><td>226</td><td>ISUpdateServiceFolder</td><td>[ISUpdateServiceFolder]agent.exe "/au[ProductCode] /EndOfInstall /Reboot"</td><td>Checks for product updates on reboot</td></row>
+		<row><td>ISPrint</td><td>1</td><td>SetAllUsers.dll</td><td>PrintScrollableText</td><td>Prints the contents of a ScrollableText control on a dialog.</td></row>
+		<row><td>ISSelfRegisterCosting</td><td>1</td><td>ISSELFREG.DLL</td><td>ISSelfRegisterCosting</td><td/></row>
+		<row><td>ISSelfRegisterFiles</td><td>1025</td><td>ISSELFREG.DLL</td><td>ISSelfRegisterFiles</td><td/></row>
+		<row><td>ISSelfRegisterFinalize</td><td>1</td><td>ISSELFREG.DLL</td><td>ISSelfRegisterFinalize</td><td/></row>
+		<row><td>ISUnSelfRegisterFiles</td><td>1025</td><td>ISSELFREG.DLL</td><td>ISUnSelfRegisterFiles</td><td/></row>
+		<row><td>InstallFilter</td><td>70</td><td>NewBinary19</td><td/><td/></row>
+		<row><td>SetARPINSTALLLOCATION</td><td>51</td><td>ARPINSTALLLOCATION</td><td>[INSTALLDIR]</td><td/></row>
+		<row><td>SetAllUsersProfileNT</td><td>51</td><td>ALLUSERSPROFILE</td><td>[%SystemRoot]\Profiles\All Users</td><td/></row>
+		<row><td>caCreateVRoots</td><td>1025</td><td>binIISHelper</td><td>CreateIISVRoots</td><td/></row>
+		<row><td>caExtractIISSuppFiles</td><td>1</td><td>binIISHelper</td><td>ExtractIISTables</td><td/></row>
+		<row><td>caIISCleanup</td><td>1</td><td>binIISHelper</td><td>CleanupVRoots</td><td/></row>
+		<row><td>caRemoveVRoots</td><td>1025</td><td>binIISHelper</td><td>RemoveIISVRoots</td><td/></row>
+		<row><td>caRlbackVRoots</td><td>1281</td><td>binIISHelper</td><td>RlBackRemoveIISVRoots</td><td/></row>
+		<row><td>setAllUsersProfile2K</td><td>51</td><td>ALLUSERSPROFILE</td><td>[%ALLUSERSPROFILE]</td><td/></row>
+		<row><td>setUserProfileNT</td><td>51</td><td>USERPROFILE</td><td>[%USERPROFILE]</td><td/></row>
+	</table>
+
+	<table name="Dialog">
+		<col key="yes" def="s72">Dialog</col>
+		<col def="i2">HCentering</col>
+		<col def="i2">VCentering</col>
+		<col def="i2">Width</col>
+		<col def="i2">Height</col>
+		<col def="I4">Attributes</col>
+		<col def="L128">Title</col>
+		<col def="s50">Control_First</col>
+		<col def="S50">Control_Default</col>
+		<col def="S50">Control_Cancel</col>
+		<col def="S255">ISComments</col>
+		<col def="S72">TextStyle_</col>
+		<col def="I4">ISWindowStyle</col>
+		<col def="I4">ISResourceId</col>
+		<row><td>AdminChangeFolder</td><td>50</td><td>50</td><td>374</td><td>266</td><td>3</td><td>##IDS_PRODUCTNAME_INSTALLSHIELD##</td><td>Tail</td><td>OK</td><td>Cancel</td><td>Install Point Browse</td><td/><td>0</td><td/></row>
+		<row><td>AdminNetworkLocation</td><td>50</td><td>50</td><td>374</td><td>266</td><td>3</td><td>##IDS_PRODUCTNAME_INSTALLSHIELD##</td><td>InstallNow</td><td>InstallNow</td><td>Cancel</td><td>Network Location</td><td/><td>0</td><td/></row>
+		<row><td>AdminWelcome</td><td>50</td><td>50</td><td>374</td><td>266</td><td>3</td><td>##IDS_PRODUCTNAME_INSTALLSHIELD##</td><td>Next</td><td>Next</td><td>Cancel</td><td>Administration Welcome</td><td/><td>0</td><td/></row>
+		<row><td>CancelSetup</td><td>50</td><td>50</td><td>260</td><td>85</td><td>3</td><td>##IDS_PRODUCTNAME_INSTALLSHIELD##</td><td>No</td><td>No</td><td>No</td><td>Cancel</td><td/><td>0</td><td/></row>
+		<row><td>CustomSetup</td><td>50</td><td>50</td><td>374</td><td>266</td><td>35</td><td>##IDS_PRODUCTNAME_INSTALLSHIELD##</td><td>Tree</td><td>Next</td><td>Cancel</td><td>Custom Selection</td><td/><td>0</td><td/></row>
+		<row><td>CustomSetupTips</td><td>50</td><td>50</td><td>374</td><td>266</td><td>3</td><td>##IDS_PRODUCTNAME_INSTALLSHIELD##</td><td>OK</td><td>OK</td><td>OK</td><td>Custom Setup Tips</td><td/><td>0</td><td/></row>
+		<row><td>CustomerInformation</td><td>50</td><td>50</td><td>374</td><td>266</td><td>3</td><td>##IDS_PRODUCTNAME_INSTALLSHIELD##</td><td>NameEdit</td><td>Next</td><td>Cancel</td><td>Identification</td><td/><td>0</td><td/></row>
+		<row><td>DatabaseFolder</td><td>50</td><td>50</td><td>374</td><td>266</td><td>3</td><td>##IDS_PRODUCTNAME_INSTALLSHIELD##</td><td>Next</td><td>Next</td><td>Cancel</td><td>Database Folder</td><td/><td>0</td><td/></row>
+		<row><td>DestinationFolder</td><td>50</td><td>50</td><td>374</td><td>266</td><td>3</td><td>##IDS_PRODUCTNAME_INSTALLSHIELD##</td><td>Next</td><td>Next</td><td>Cancel</td><td>Destination Folder</td><td/><td>0</td><td/></row>
+		<row><td>DiskSpaceRequirements</td><td>50</td><td>50</td><td>374</td><td>266</td><td>3</td><td>##IDS_PRODUCTNAME_INSTALLSHIELD##</td><td>OK</td><td>OK</td><td>OK</td><td>Feature Details</td><td/><td>0</td><td/></row>
+		<row><td>FilesInUse</td><td>50</td><td>50</td><td>374</td><td>266</td><td>19</td><td>##IDS_PRODUCTNAME_INSTALLSHIELD##</td><td>Retry</td><td>Retry</td><td>Exit</td><td>Files in Use</td><td/><td>0</td><td/></row>
+		<row><td>InstallChangeFolder</td><td>50</td><td>50</td><td>374</td><td>266</td><td>3</td><td>##IDS_PRODUCTNAME_INSTALLSHIELD##</td><td>Tail</td><td>OK</td><td>Cancel</td><td>Browse</td><td/><td>0</td><td/></row>
+		<row><td>InstallWelcome</td><td>50</td><td>50</td><td>374</td><td>266</td><td>3</td><td>##IDS_PRODUCTNAME_INSTALLSHIELD##</td><td>Next</td><td>Next</td><td>Cancel</td><td>Welcome Panel</td><td/><td>0</td><td/></row>
+		<row><td>LicenseAgreement</td><td>50</td><td>50</td><td>374</td><td>266</td><td>2</td><td>##IDS_PRODUCTNAME_INSTALLSHIELD##</td><td>Agree</td><td>Next</td><td>Cancel</td><td>License Agreement</td><td/><td>0</td><td/></row>
+		<row><td>MaintenanceType</td><td>50</td><td>50</td><td>374</td><td>266</td><td>3</td><td>##IDS_PRODUCTNAME_INSTALLSHIELD##</td><td>RadioGroup</td><td>Next</td><td>Cancel</td><td>Change, Reinstall, Remove</td><td/><td>0</td><td/></row>
+		<row><td>MaintenanceWelcome</td><td>50</td><td>50</td><td>374</td><td>266</td><td>3</td><td>##IDS_PRODUCTNAME_INSTALLSHIELD##</td><td>Next</td><td>Next</td><td>Cancel</td><td>Maintenance Welcome</td><td/><td>0</td><td/></row>
+		<row><td>OutOfSpace</td><td>50</td><td>50</td><td>374</td><td>266</td><td>3</td><td>##IDS_PRODUCTNAME_INSTALLSHIELD##</td><td>Resume</td><td>Resume</td><td>Resume</td><td>Out Of Disk Space</td><td/><td>0</td><td/></row>
+		<row><td>PatchWelcome</td><td>50</td><td>50</td><td>374</td><td>266</td><td>3</td><td>##IDS__IsPatchDlg_PatchWizard##</td><td>Next</td><td>Next</td><td>Cancel</td><td>Patch Panel</td><td/><td>0</td><td/></row>
+		<row><td>ReadyToInstall</td><td>50</td><td>50</td><td>374</td><td>266</td><td>35</td><td>##IDS_PRODUCTNAME_INSTALLSHIELD##</td><td>InstallNow</td><td>InstallNow</td><td>Cancel</td><td>Ready to Install</td><td/><td>0</td><td/></row>
+		<row><td>ReadyToRemove</td><td>50</td><td>50</td><td>374</td><td>266</td><td>3</td><td>##IDS_PRODUCTNAME_INSTALLSHIELD##</td><td>RemoveNow</td><td>RemoveNow</td><td>Cancel</td><td>Verify Remove</td><td/><td>0</td><td/></row>
+		<row><td>SQLBrowse</td><td>50</td><td>50</td><td>272</td><td>265</td><td>3</td><td>##IDS_PRODUCTNAME_INSTALLSHIELD##</td><td>lstSQLServer</td><td>OK</td><td>Cancel</td><td>SQL Server List Browse</td><td/><td>0</td><td/></row>
+		<row><td>SQLLogin</td><td>50</td><td>50</td><td>374</td><td>266</td><td>3</td><td>##IDS_PRODUCTNAME_INSTALLSHIELD##</td><td>cboServers</td><td>Next</td><td>Cancel</td><td>SQL Server Login</td><td/><td>0</td><td/></row>
+		<row><td>SetupCompleteError</td><td>50</td><td>50</td><td>374</td><td>266</td><td>3</td><td>##IDS_PRODUCTNAME_INSTALLSHIELD##</td><td>Finish</td><td>Finish</td><td>Finish</td><td>Fatal Error</td><td/><td>0</td><td/></row>
+		<row><td>SetupCompleteSuccess</td><td>50</td><td>50</td><td>374</td><td>266</td><td>3</td><td>##IDS_PRODUCTNAME_INSTALLSHIELD##</td><td>OK</td><td>OK</td><td>OK</td><td>Exit</td><td/><td>0</td><td/></row>
+		<row><td>SetupError</td><td>50</td><td>50</td><td>270</td><td>110</td><td>65543</td><td>##IDS__IsErrorDlg_InstallerInfo##</td><td>ErrorText</td><td>O</td><td>C</td><td>Error</td><td/><td>0</td><td/></row>
+		<row><td>SetupInitialization</td><td>50</td><td>50</td><td>374</td><td>266</td><td>5</td><td>##IDS_PRODUCTNAME_INSTALLSHIELD##</td><td>Cancel</td><td>Cancel</td><td>Cancel</td><td>Setup Initialization</td><td/><td>0</td><td/></row>
+		<row><td>SetupInterrupted</td><td>50</td><td>50</td><td>374</td><td>266</td><td>3</td><td>##IDS_PRODUCTNAME_INSTALLSHIELD##</td><td>Finish</td><td>Finish</td><td>Finish</td><td>User Exit</td><td/><td>0</td><td/></row>
+		<row><td>SetupProgress</td><td>50</td><td>50</td><td>374</td><td>266</td><td>5</td><td>##IDS_PRODUCTNAME_INSTALLSHIELD##</td><td>Cancel</td><td>Cancel</td><td>Cancel</td><td>Progress</td><td/><td>0</td><td/></row>
+		<row><td>SetupResume</td><td>50</td><td>50</td><td>374</td><td>266</td><td>3</td><td>##IDS_PRODUCTNAME_INSTALLSHIELD##</td><td>Next</td><td>Next</td><td>Cancel</td><td>Resume</td><td/><td>0</td><td/></row>
+		<row><td>SetupType</td><td>50</td><td>50</td><td>374</td><td>266</td><td>3</td><td>##IDS_PRODUCTNAME_INSTALLSHIELD##</td><td>RadioGroup</td><td>Next</td><td>Cancel</td><td>Setup Type</td><td/><td>0</td><td/></row>
+		<row><td>SplashBitmap</td><td>50</td><td>50</td><td>374</td><td>266</td><td>3</td><td>##IDS_PRODUCTNAME_INSTALLSHIELD##</td><td>Next</td><td>Next</td><td>Cancel</td><td>Welcome Bitmap</td><td/><td>0</td><td/></row>
+	</table>
+
+	<table name="Directory">
+		<col key="yes" def="s72">Directory</col>
+		<col def="S72">Directory_Parent</col>
+		<col def="l255">DefaultDir</col>
+		<col def="S255">ISDescription</col>
+		<col def="I4">ISAttributes</col>
+		<col def="S255">ISFolderName</col>
+		<row><td>ALLUSERSPROFILE</td><td>TARGETDIR</td><td>.:ALLUSE~1|All Users</td><td/><td>0</td><td/></row>
+		<row><td>APACHE_SOFTWARE_FOUNDATION</td><td>ProgramFilesFolder</td><td>APACHE~1|Apache Software Foundation</td><td/><td>0</td><td/></row>
+		<row><td>AdminToolsFolder</td><td>TARGETDIR</td><td>.:Admint~1|AdminTools</td><td/><td>0</td><td/></row>
+		<row><td>AppDataFolder</td><td>TARGETDIR</td><td>.:APPLIC~1|Application Data</td><td/><td>0</td><td/></row>
+		<row><td>BIN</td><td>INSTALLDIR</td><td>bin</td><td/><td>0</td><td/></row>
+		<row><td>CONF</td><td>INSTALLDIR</td><td>conf</td><td/><td>0</td><td/></row>
+		<row><td>CommonAppDataFolder</td><td>TARGETDIR</td><td>.:Common~1|CommonAppData</td><td/><td>0</td><td/></row>
+		<row><td>CommonFiles64Folder</td><td>TARGETDIR</td><td>.:Common64</td><td/><td>0</td><td/></row>
+		<row><td>CommonFilesFolder</td><td>TARGETDIR</td><td>.:Common</td><td/><td>0</td><td/></row>
+		<row><td>DATABASEDIR</td><td>ISYourDataBaseDir</td><td>.</td><td/><td>0</td><td/></row>
+		<row><td>DesktopFolder</td><td>TARGETDIR</td><td>.:Desktop</td><td/><td>3</td><td/></row>
+		<row><td>FavoritesFolder</td><td>TARGETDIR</td><td>.:FAVORI~1|Favorites</td><td/><td>0</td><td/></row>
+		<row><td>FontsFolder</td><td>TARGETDIR</td><td>.:Fonts</td><td/><td>0</td><td/></row>
+		<row><td>GlobalAssemblyCache</td><td>TARGETDIR</td><td>.:Global~1|GlobalAssemblyCache</td><td/><td>0</td><td/></row>
+		<row><td>IISROOTFOLDER</td><td>TARGETDIR</td><td>.:IISRoo~1|IISRootFolder</td><td/><td>0</td><td/></row>
+		<row><td>INSTALLDIR</td><td>JAKARTA_ISAPI_REDIRECTOR</td><td>.</td><td/><td>0</td><td/></row>
+		<row><td>ISCommonFilesFolder</td><td>CommonFilesFolder</td><td>Instal~1|InstallShield</td><td/><td>0</td><td/></row>
+		<row><td>ISMyCompanyDir</td><td>ProgramFilesFolder</td><td>MYCOMP~1|My Company Name</td><td/><td>0</td><td/></row>
+		<row><td>ISMyProductDir</td><td>ISMyCompanyDir</td><td>MYPROD~1|My Product Name</td><td/><td>0</td><td/></row>
+		<row><td>ISUpdateServiceFolder</td><td>ISCommonFilesFolder</td><td>UPDATE~1|UpdateService</td><td/><td>0</td><td/></row>
+		<row><td>ISYourDataBaseDir</td><td>INSTALLDIR</td><td>Database</td><td/><td>0</td><td/></row>
+		<row><td>JAKARTA_ISAPI_REDIRECTOR</td><td>APACHE_SOFTWARE_FOUNDATION</td><td>JAKART~1|Jakarta Isapi Redirector</td><td/><td>0</td><td/></row>
+		<row><td>JAKARTA_ISAPU_REDIRECTOR</td><td>APACHE_SOFTWARE_FOUNDATION</td><td>JAKART~1|Jakarta Isapu Redirector</td><td/><td>0</td><td/></row>
+		<row><td>JBOSS_EUROPE_SARL</td><td>ProgramFilesFolder</td><td>JBOSSE~1|JBoss Europe SaRL</td><td/><td>0</td><td/></row>
+		<row><td>LOG</td><td>INSTALLDIR</td><td>log</td><td/><td>0</td><td/></row>
+		<row><td>LocalAppDataFolder</td><td>TARGETDIR</td><td>.:LocalA~1|LocalAppData</td><td/><td>0</td><td/></row>
+		<row><td>MY_PRODUCT_NAME</td><td>JBOSS_EUROPE_SARL</td><td>MYPROD~1|My Product Name</td><td/><td>0</td><td/></row>
+		<row><td>MY_PRODUCT_NAME1</td><td>APACHE_SOFTWARE_FOUNDATION</td><td>MYPROD~1|My Product Name</td><td/><td>0</td><td/></row>
+		<row><td>MyPicturesFolder</td><td>TARGETDIR</td><td>.:MyPict~1|MyPictures</td><td/><td>0</td><td/></row>
+		<row><td>PersonalFolder</td><td>TARGETDIR</td><td>.:Personal</td><td/><td>0</td><td/></row>
+		<row><td>PrimaryVolumePath</td><td>TARGETDIR</td><td>.:Primar~1|PrimaryVolumePath</td><td/><td>0</td><td/></row>
+		<row><td>ProgramFiles64Folder</td><td>TARGETDIR</td><td>.:Prog64~1|Program Files 64</td><td/><td>0</td><td/></row>
+		<row><td>ProgramFilesFolder</td><td>TARGETDIR</td><td>.:PROGRA~1|program files</td><td/><td>0</td><td/></row>
+		<row><td>ProgramMenuFolder</td><td>TARGETDIR</td><td>.:Programs</td><td/><td>3</td><td/></row>
+		<row><td>SendToFolder</td><td>TARGETDIR</td><td>.:SendTo</td><td/><td>3</td><td/></row>
+		<row><td>StartMenuFolder</td><td>TARGETDIR</td><td>.:STARTM~1|Start Menu</td><td/><td>3</td><td/></row>
+		<row><td>StartupFolder</td><td>TARGETDIR</td><td>.:StartUp</td><td/><td>3</td><td/></row>
+		<row><td>System16Folder</td><td>TARGETDIR</td><td>.:System</td><td/><td>0</td><td/></row>
+		<row><td>System64Folder</td><td>TARGETDIR</td><td>.:System64</td><td/><td>0</td><td/></row>
+		<row><td>SystemFolder</td><td>TARGETDIR</td><td>.:System32</td><td/><td>0</td><td/></row>
+		<row><td>TARGETDIR</td><td/><td>SourceDir</td><td/><td>0</td><td/></row>
+		<row><td>TempFolder</td><td>TARGETDIR</td><td>.:Temp</td><td/><td>0</td><td/></row>
+		<row><td>TemplateFolder</td><td>TARGETDIR</td><td>.:ShellNew</td><td/><td>0</td><td/></row>
+		<row><td>USERPROFILE</td><td>TARGETDIR</td><td>.:USERPR~1|UserProfile</td><td/><td>0</td><td/></row>
+		<row><td>WindowsFolder</td><td>TARGETDIR</td><td>.:Windows</td><td/><td>0</td><td/></row>
+		<row><td>WindowsVolume</td><td>TARGETDIR</td><td>.:WinRoot</td><td/><td>0</td><td/></row>
+	</table>
+
+	<table name="DrLocator">
+		<col key="yes" def="s72">Signature_</col>
+		<col key="yes" def="S72">Parent</col>
+		<col key="yes" def="S255">Path</col>
+		<col def="I2">Depth</col>
+	</table>
+
+	<table name="DuplicateFile">
+		<col key="yes" def="s72">FileKey</col>
+		<col def="s72">Component_</col>
+		<col def="s72">File_</col>
+		<col def="L255">DestName</col>
+		<col def="S72">DestFolder</col>
+	</table>
+
+	<table name="Environment">
+		<col key="yes" def="s72">Environment</col>
+		<col def="l255">Name</col>
+		<col def="L255">Value</col>
+		<col def="s72">Component_</col>
+	</table>
+
+	<table name="Error">
+		<col key="yes" def="i2">Error</col>
+		<col def="L255">Message</col>
+		<row><td>0</td><td>##IDS_ERROR_0##</td></row>
+		<row><td>1</td><td>##IDS_ERROR_1##</td></row>
+		<row><td>10</td><td>##IDS_ERROR_8##</td></row>
+		<row><td>11</td><td>##IDS_ERROR_9##</td></row>
+		<row><td>1101</td><td>##IDS_ERROR_22##</td></row>
+		<row><td>12</td><td>##IDS_ERROR_10##</td></row>
+		<row><td>13</td><td>##IDS_ERROR_11##</td></row>
+		<row><td>1301</td><td>##IDS_ERROR_23##</td></row>
+		<row><td>1302</td><td>##IDS_ERROR_24##</td></row>
+		<row><td>1303</td><td>##IDS_ERROR_25##</td></row>
+		<row><td>1304</td><td>##IDS_ERROR_26##</td></row>
+		<row><td>1305</td><td>##IDS_ERROR_27##</td></row>
+		<row><td>1306</td><td>##IDS_ERROR_28##</td></row>
+		<row><td>1307</td><td>##IDS_ERROR_29##</td></row>
+		<row><td>1308</td><td>##IDS_ERROR_30##</td></row>
+		<row><td>1309</td><td>##IDS_ERROR_31##</td></row>
+		<row><td>1310</td><td>##IDS_ERROR_32##</td></row>
+		<row><td>1311</td><td>##IDS_ERROR_33##</td></row>
+		<row><td>1312</td><td>##IDS_ERROR_34##</td></row>
+		<row><td>1313</td><td>##IDS_ERROR_35##</td></row>
+		<row><td>1314</td><td>##IDS_ERROR_36##</td></row>
+		<row><td>1315</td><td>##IDS_ERROR_37##</td></row>
+		<row><td>1316</td><td>##IDS_ERROR_38##</td></row>
+		<row><td>1317</td><td>##IDS_ERROR_39##</td></row>
+		<row><td>1318</td><td>##IDS_ERROR_40##</td></row>
+		<row><td>1319</td><td>##IDS_ERROR_41##</td></row>
+		<row><td>1320</td><td>##IDS_ERROR_42##</td></row>
+		<row><td>1321</td><td>##IDS_ERROR_43##</td></row>
+		<row><td>1322</td><td>##IDS_ERROR_44##</td></row>
+		<row><td>1323</td><td>##IDS_ERROR_45##</td></row>
+		<row><td>1324</td><td>##IDS_ERROR_46##</td></row>
+		<row><td>1325</td><td>##IDS_ERROR_47##</td></row>
+		<row><td>1326</td><td>##IDS_ERROR_48##</td></row>
+		<row><td>1327</td><td>##IDS_ERROR_49##</td></row>
+		<row><td>1328</td><td>##IDS_ERROR_122##</td></row>
+		<row><td>14</td><td>##IDS_ERROR_12##</td></row>
+		<row><td>1401</td><td>##IDS_ERROR_50##</td></row>
+		<row><td>1402</td><td>##IDS_ERROR_51##</td></row>
+		<row><td>1403</td><td>##IDS_ERROR_52##</td></row>
+		<row><td>1404</td><td>##IDS_ERROR_53##</td></row>
+		<row><td>1405</td><td>##IDS_ERROR_54##</td></row>
+		<row><td>1406</td><td>##IDS_ERROR_55##</td></row>
+		<row><td>1407</td><td>##IDS_ERROR_56##</td></row>
+		<row><td>1408</td><td>##IDS_ERROR_57##</td></row>
+		<row><td>1409</td><td>##IDS_ERROR_58##</td></row>
+		<row><td>1410</td><td>##IDS_ERROR_59##</td></row>
+		<row><td>15</td><td>##IDS_ERROR_13##</td></row>
+		<row><td>1500</td><td>##IDS_ERROR_60##</td></row>
+		<row><td>1501</td><td>##IDS_ERROR_61##</td></row>
+		<row><td>1502</td><td>##IDS_ERROR_62##</td></row>
+		<row><td>1503</td><td>##IDS_ERROR_63##</td></row>
+		<row><td>16</td><td>##IDS_ERROR_14##</td></row>
+		<row><td>1601</td><td>##IDS_ERROR_64##</td></row>
+		<row><td>1602</td><td>##IDS_ERROR_65##</td></row>
+		<row><td>1603</td><td>##IDS_ERROR_66##</td></row>
+		<row><td>1604</td><td>##IDS_ERROR_67##</td></row>
+		<row><td>1605</td><td>##IDS_ERROR_68##</td></row>
+		<row><td>1606</td><td>##IDS_ERROR_69##</td></row>
+		<row><td>1607</td><td>##IDS_ERROR_70##</td></row>
+		<row><td>1608</td><td>##IDS_ERROR_71##</td></row>
+		<row><td>17</td><td>##IDS_ERROR_15##</td></row>
+		<row><td>1701</td><td>##IDS_ERROR_72##</td></row>
+		<row><td>1702</td><td>##IDS_ERROR_73##</td></row>
+		<row><td>1703</td><td>##IDS_ERROR_74##</td></row>
+		<row><td>1704</td><td>##IDS_ERROR_75##</td></row>
+		<row><td>1705</td><td>##IDS_ERROR_76##</td></row>
+		<row><td>1706</td><td>##IDS_ERROR_77##</td></row>
+		<row><td>1707</td><td>##IDS_ERROR_78##</td></row>
+		<row><td>1708</td><td>##IDS_ERROR_79##</td></row>
+		<row><td>1709</td><td>##IDS_ERROR_80##</td></row>
+		<row><td>1710</td><td>##IDS_ERROR_81##</td></row>
+		<row><td>1711</td><td>##IDS_ERROR_82##</td></row>
+		<row><td>1712</td><td>##IDS_ERROR_83##</td></row>
+		<row><td>1713</td><td>##IDS_ERROR_123##</td></row>
+		<row><td>1714</td><td>##IDS_ERROR_124##</td></row>
+		<row><td>18</td><td>##IDS_ERROR_16##</td></row>
+		<row><td>1801</td><td>##IDS_ERROR_84##</td></row>
+		<row><td>1802</td><td>##IDS_ERROR_85##</td></row>
+		<row><td>1803</td><td>##IDS_ERROR_86##</td></row>
+		<row><td>1804</td><td>##IDS_ERROR_87##</td></row>
+		<row><td>1805</td><td>##IDS_ERROR_88##</td></row>
+		<row><td>1806</td><td>##IDS_ERROR_89##</td></row>
+		<row><td>1807</td><td>##IDS_ERROR_90##</td></row>
+		<row><td>19</td><td>##IDS_ERROR_17##</td></row>
+		<row><td>1901</td><td>##IDS_ERROR_91##</td></row>
+		<row><td>1902</td><td>##IDS_ERROR_92##</td></row>
+		<row><td>1903</td><td>##IDS_ERROR_93##</td></row>
+		<row><td>1904</td><td>##IDS_ERROR_94##</td></row>
+		<row><td>1905</td><td>##IDS_ERROR_95##</td></row>
+		<row><td>1906</td><td>##IDS_ERROR_96##</td></row>
+		<row><td>1907</td><td>##IDS_ERROR_97##</td></row>
+		<row><td>1908</td><td>##IDS_ERROR_98##</td></row>
+		<row><td>1909</td><td>##IDS_ERROR_99##</td></row>
+		<row><td>1910</td><td>##IDS_ERROR_100##</td></row>
+		<row><td>1911</td><td>##IDS_ERROR_101##</td></row>
+		<row><td>1912</td><td>##IDS_ERROR_102##</td></row>
+		<row><td>1913</td><td>##IDS_ERROR_103##</td></row>
+		<row><td>1914</td><td>##IDS_ERROR_104##</td></row>
+		<row><td>1915</td><td>##IDS_ERROR_105##</td></row>
+		<row><td>1916</td><td>##IDS_ERROR_106##</td></row>
+		<row><td>1917</td><td>##IDS_ERROR_107##</td></row>
+		<row><td>1918</td><td>##IDS_ERROR_108##</td></row>
+		<row><td>1919</td><td>##IDS_ERROR_109##</td></row>
+		<row><td>1920</td><td>##IDS_ERROR_110##</td></row>
+		<row><td>1921</td><td>##IDS_ERROR_111##</td></row>
+		<row><td>1922</td><td>##IDS_ERROR_112##</td></row>
+		<row><td>1923</td><td>##IDS_ERROR_113##</td></row>
+		<row><td>1924</td><td>##IDS_ERROR_114##</td></row>
+		<row><td>1925</td><td>##IDS_ERROR_115##</td></row>
+		<row><td>1926</td><td>##IDS_ERROR_116##</td></row>
+		<row><td>1927</td><td>##IDS_ERROR_117##</td></row>
+		<row><td>1928</td><td>##IDS_ERROR_118##</td></row>
+		<row><td>1929</td><td>##IDS_ERROR_119##</td></row>
+		<row><td>1930</td><td>##IDS_ERROR_125##</td></row>
+		<row><td>1931</td><td>##IDS_ERROR_126##</td></row>
+		<row><td>1932</td><td>##IDS_ERROR_127##</td></row>
+		<row><td>1933</td><td>##IDS_ERROR_128##</td></row>
+		<row><td>1934</td><td>##IDS_ERROR_129##</td></row>
+		<row><td>2</td><td>##IDS_ERROR_2##</td></row>
+		<row><td>20</td><td>##IDS_ERROR_18##</td></row>
+		<row><td>21</td><td>##IDS_ERROR_19##</td></row>
+		<row><td>22</td><td>##IDS_ERROR_120##</td></row>
+		<row><td>23</td><td>##IDS_ERROR_121##</td></row>
+		<row><td>2331</td><td>##IDS_ERROR_2331##</td></row>
+		<row><td>27500</td><td>##IDS_ERROR_130##</td></row>
+		<row><td>27501</td><td>##IDS_ERROR_131##</td></row>
+		<row><td>27502</td><td>##IDS_ERROR_27502##</td></row>
+		<row><td>27503</td><td>##IDS_ERROR_27503##</td></row>
+		<row><td>27504</td><td>##IDS_ERROR_27504##</td></row>
+		<row><td>27505</td><td>##IDS_ERROR_27505##</td></row>
+		<row><td>27506</td><td>##IDS_ERROR_27506##</td></row>
+		<row><td>27507</td><td>##IDS_ERROR_27507##</td></row>
+		<row><td>27508</td><td>##IDS_ERROR_27508##</td></row>
+		<row><td>27509</td><td>##IDS_ERROR_27509##</td></row>
+		<row><td>27510</td><td>##IDS_ERROR_27510##</td></row>
+		<row><td>27511</td><td>##IDS_ERROR_27511##</td></row>
+		<row><td>27512</td><td>##IDS_ERROR_27512##</td></row>
+		<row><td>27513</td><td>##IDS_ERROR_27513##</td></row>
+		<row><td>27514</td><td>##IDS_ERROR_27514##</td></row>
+		<row><td>27515</td><td>##IDS_ERROR_27515##</td></row>
+		<row><td>27516</td><td>##IDS_ERROR_27516##</td></row>
+		<row><td>27517</td><td>##IDS_ERROR_27517##</td></row>
+		<row><td>27518</td><td>##IDS_ERROR_27518##</td></row>
+		<row><td>27519</td><td>##IDS_ERROR_27519##</td></row>
+		<row><td>27520</td><td>##IDS_ERROR_27520##</td></row>
+		<row><td>27521</td><td>##IDS_ERROR_27521##</td></row>
+		<row><td>27522</td><td>##IDS_ERROR_27522##</td></row>
+		<row><td>27523</td><td>##IDS_ERROR_27523##</td></row>
+		<row><td>27524</td><td>##IDS_ERROR_27524##</td></row>
+		<row><td>27525</td><td>##IDS_ERROR_27525##</td></row>
+		<row><td>27526</td><td>##IDS_ERROR_27526##</td></row>
+		<row><td>27527</td><td>##IDS_ERROR_27527##</td></row>
+		<row><td>27528</td><td>##IDS_ERROR_27528##</td></row>
+		<row><td>27529</td><td>##IDS_ERROR_27529##</td></row>
+		<row><td>27530</td><td>##IDS_ERROR_27530##</td></row>
+		<row><td>27531</td><td>##IDS_ERROR_27531##</td></row>
+		<row><td>27532</td><td>##IDS_ERROR_27532##</td></row>
+		<row><td>27533</td><td>##IDS_ERROR_27533##</td></row>
+		<row><td>27534</td><td>##IDS_ERROR_27534##</td></row>
+		<row><td>27535</td><td>##IDS_ERROR_27535##</td></row>
+		<row><td>27536</td><td>##IDS_ERROR_27536##</td></row>
+		<row><td>27537</td><td>##IDS_ERROR_27537##</td></row>
+		<row><td>27538</td><td>##IDS_ERROR_27538##</td></row>
+		<row><td>27539</td><td>##IDS_ERROR_27539##</td></row>
+		<row><td>27540</td><td>##IDS_ERROR_27540##</td></row>
+		<row><td>27541</td><td>##IDS_ERROR_27541##</td></row>
+		<row><td>27542</td><td>##IDS_ERROR_27542##</td></row>
+		<row><td>27543</td><td>##IDS_ERROR_27543##</td></row>
+		<row><td>27544</td><td>##IDS_ERROR_27544##</td></row>
+		<row><td>27545</td><td>##IDS_ERROR_27545##</td></row>
+		<row><td>27546</td><td>##IDS_ERROR_27546##</td></row>
+		<row><td>27547</td><td>##IDS_ERROR_27547##</td></row>
+		<row><td>27548</td><td>##IDS_ERROR_27548##</td></row>
+		<row><td>27549</td><td>##IDS_ERROR_27549##</td></row>
+		<row><td>27550</td><td>##IDS_ERROR_27550##</td></row>
+		<row><td>27551</td><td>##IDS_ERROR_27551##</td></row>
+		<row><td>32</td><td>##IDS_ERROR_20##</td></row>
+		<row><td>33</td><td>##IDS_ERROR_21##</td></row>
+		<row><td>4</td><td>##IDS_ERROR_3##</td></row>
+		<row><td>5</td><td>##IDS_ERROR_4##</td></row>
+		<row><td>7</td><td>##IDS_ERROR_5##</td></row>
+		<row><td>8</td><td>##IDS_ERROR_6##</td></row>
+		<row><td>9</td><td>##IDS_ERROR_7##</td></row>
+	</table>
+
+	<table name="EventMapping">
+		<col key="yes" def="s72">Dialog_</col>
+		<col key="yes" def="s50">Control_</col>
+		<col key="yes" def="s50">Event</col>
+		<col def="s50">Attribute</col>
+		<row><td>CustomSetup</td><td>ItemDescription</td><td>SelectionDescription</td><td>Text</td></row>
+		<row><td>CustomSetup</td><td>Location</td><td>SelectionPath</td><td>Text</td></row>
+		<row><td>CustomSetup</td><td>Size</td><td>SelectionSize</td><td>Text</td></row>
+		<row><td>SetupInitialization</td><td>ActionData</td><td>ActionData</td><td>Text</td></row>
+		<row><td>SetupInitialization</td><td>ActionText</td><td>ActionText</td><td>Text</td></row>
+		<row><td>SetupProgress</td><td>ActionProgress95</td><td>AdminInstallFinalize</td><td>Progress</td></row>
+		<row><td>SetupProgress</td><td>ActionProgress95</td><td>InstallFiles</td><td>Progress</td></row>
+		<row><td>SetupProgress</td><td>ActionProgress95</td><td>MoveFiles</td><td>Progress</td></row>
+		<row><td>SetupProgress</td><td>ActionProgress95</td><td>RemoveFiles</td><td>Progress</td></row>
+		<row><td>SetupProgress</td><td>ActionProgress95</td><td>RemoveRegistryValues</td><td>Progress</td></row>
+		<row><td>SetupProgress</td><td>ActionProgress95</td><td>SetProgress</td><td>Progress</td></row>
+		<row><td>SetupProgress</td><td>ActionProgress95</td><td>UnmoveFiles</td><td>Progress</td></row>
+		<row><td>SetupProgress</td><td>ActionProgress95</td><td>WriteIniValues</td><td>Progress</td></row>
+		<row><td>SetupProgress</td><td>ActionProgress95</td><td>WriteRegistryValues</td><td>Progress</td></row>
+		<row><td>SetupProgress</td><td>ActionText</td><td>ActionText</td><td>Text</td></row>
+	</table>
+
+	<table name="Extension">
+		<col key="yes" def="s255">Extension</col>
+		<col key="yes" def="s72">Component_</col>
+		<col def="S255">ProgId_</col>
+		<col def="S64">MIME_</col>
+		<col def="s38">Feature_</col>
+	</table>
+
+	<table name="Feature">
+		<col key="yes" def="s38">Feature</col>
+		<col def="S38">Feature_Parent</col>
+		<col def="L64">Title</col>
+		<col def="L255">Description</col>
+		<col def="I2">Display</col>
+		<col def="i2">Level</col>
+		<col def="S72">Directory_</col>
+		<col def="i2">Attributes</col>
+		<col def="S255">ISReleaseFlags</col>
+		<col def="S255">ISComments</col>
+		<col def="S255">ISFeatureCabName</col>
+		<col def="S255">ISProFeatureName</col>
+		<row><td>MainFeature</td><td/><td>##ID_STRING4##</td><td/><td>2</td><td>1</td><td>INSTALLDIR</td><td>0</td><td/><td/><td/><td/></row>
+	</table>
+
+	<table name="FeatureComponents">
+		<col key="yes" def="s38">Feature_</col>
+		<col key="yes" def="s72">Component_</col>
+		<row><td>MainFeature</td><td>AllOtherFiles</td></row>
+		<row><td>MainFeature</td><td>AllOtherFiles1</td></row>
+		<row><td>MainFeature</td><td>AllOtherFiles2</td></row>
+		<row><td>MainFeature</td><td>AllOtherFiles3</td></row>
+		<row><td>MainFeature</td><td>ISRegistryComponent</td></row>
+		<row><td>MainFeature</td><td>ISRegistryComponent1</td></row>
+		<row><td>MainFeature</td><td>VirtualDirComponent</td></row>
+	</table>
+
+	<table name="File">
+		<col key="yes" def="s72">File</col>
+		<col def="s72">Component_</col>
+		<col def="s255">FileName</col>
+		<col def="i4">FileSize</col>
+		<col def="S72">Version</col>
+		<col def="S20">Language</col>
+		<col def="I2">Attributes</col>
+		<col def="i2">Sequence</col>
+		<col def="S255">ISBuildSourcePath</col>
+		<col def="I4">ISAttributes</col>
+		<col def="S72">ISComponentSubFolder_</col>
+		<row><td>license.txt</td><td>AllOtherFiles3</td><td>LICENSE.TXT</td><td>0</td><td/><td/><td/><td>1</td><td>&lt;ISProjectFolder&gt;\LICENSE.TXT</td><td>1</td><td/></row>
+	</table>
+
+	<table name="FileSFPCatalog">
+		<col key="yes" def="s72">File_</col>
+		<col key="yes" def="s255">SFPCatalog_</col>
+	</table>
+
+	<table name="Font">
+		<col key="yes" def="s72">File_</col>
+		<col def="S128">FontTitle</col>
+	</table>
+
+	<table name="ISAssistantTag">
+		<col key="yes" def="s72">Tag</col>
+		<col def="S255">Data</col>
+		<row><td>BiildCDROMEnabled</td><td/></row>
+		<row><td>BiildInternetEnabled</td><td/></row>
+		<row><td>BiildSingleExeEnabled</td><td/></row>
+		<row><td>BiildSingleMSIEnabled</td><td/></row>
+		<row><td>PROJECT_ASSISTANT_DEFAULT_FEATURE</td><td>NewFeature1</td></row>
+		<row><td>PROJECT_ASSISTANT_FEATURES</td><td>NonSelectable</td></row>
+		<row><td>RegistryPageEnabled</td><td>Yes</td></row>
+	</table>
+
+	<table name="ISCEApp">
+		<col key="yes" def="s50">AppKey</col>
+		<col def="s50">AppName</col>
+		<col def="s200">CompanyName</col>
+		<col def="s50">DefDir</col>
+		<col def="S255">IconPath</col>
+		<col def="I4">IconIndex</col>
+		<col def="S255">DeviceFile</col>
+		<col def="s50">DesktopTargetDir</col>
+		<col def="S255">Description</col>
+		<col def="i2">DeleteMedia</col>
+		<col def="I4">InstallNetCF</col>
+		<col def="I4">InstallSQLServer</col>
+		<col def="I4">InstallSQLClient</col>
+		<col def="I4">InstallSQLDev</col>
+		<col def="S255">PreXML</col>
+		<col def="S255">PostXML</col>
+		<col def="I2">NoUninstall</col>
+		<col def="S255">SPCFile</col>
+		<col def="S255">PVKFile</col>
+		<col def="I4">Attributes</col>
+		<col def="S255">RawDeviceFile</col>
+		<col def="S72">Component_</col>
+	</table>
+
+	<table name="ISCEDir">
+		<col key="yes" def="s50">AppKey</col>
+		<col key="yes" def="s50">DirKey</col>
+		<col def="s50">DirParent</col>
+		<col def="s255">DirValue</col>
+	</table>
+
+	<table name="ISCEFile">
+		<col key="yes" def="s50">AppKey</col>
+		<col key="yes" def="s50">FileKey</col>
+		<col def="s255">Name</col>
+		<col def="s50">Destination</col>
+		<col def="s255">Source</col>
+		<col def="i4">Processor</col>
+		<col def="i4">Platform</col>
+		<col def="i4">CopyOption</col>
+		<col def="i4">FileOption</col>
+		<col def="I4">AdvancedOptions</col>
+	</table>
+
+	<table name="ISCEFileExt">
+		<col key="yes" def="s50">AppKey</col>
+		<col key="yes" def="s50">ExtKey</col>
+		<col def="s50">FileKey</col>
+		<col def="S255">Description</col>
+		<col def="s50">Extension</col>
+		<col def="i4">IconIndex</col>
+	</table>
+
+	<table name="ISCEInstall">
+		<col key="yes" def="s255">CEInstallKey</col>
+		<col def="s255">CEAppName</col>
+		<col def="s255">CEDesktopDir</col>
+		<col def="s255">CEIniFileKey</col>
+		<col def="s0">CECabs</col>
+		<col def="s0">CEIcoFile</col>
+		<col def="i2">DeleteMedia</col>
+		<col def="S38">Component_</col>
+	</table>
+
+	<table name="ISCEOtherAppCABs">
+		<col key="yes" def="s50">AppKey</col>
+		<col key="yes" def="s50">FileKey</col>
+		<col def="s255">BuildSourcePath</col>
+	</table>
+
+	<table name="ISCERegistry">
+		<col key="yes" def="s50">AppKey</col>
+		<col key="yes" def="s50">RegKey</col>
+		<col def="i4">Root</col>
+		<col def="s255">Key</col>
+		<col def="S255">Name</col>
+		<col def="S255">Value</col>
+		<col def="i4">Processor</col>
+		<col def="i4">Platform</col>
+		<col def="i4">Overwrite</col>
+	</table>
+
+	<table name="ISCESetupFile">
+		<col key="yes" def="s50">AppKey</col>
+		<col key="yes" def="s50">SetupFileKey</col>
+		<col def="s255">Name</col>
+		<col def="s255">Source</col>
+		<col def="i4">Processor</col>
+		<col def="i4">Platform</col>
+	</table>
+
+	<table name="ISCEShtCut">
+		<col key="yes" def="s50">AppKey</col>
+		<col key="yes" def="s50">ShtCutKey</col>
+		<col def="s255">DisplayName</col>
+		<col def="s255">Destination</col>
+		<col def="s50">Target</col>
+		<col def="i4">Platform</col>
+	</table>
+
+	<table name="ISComCatalogAttribute">
+		<col key="yes" def="s72">ISComCatalogObject_</col>
+		<col key="yes" def="s255">ItemName</col>
+		<col def="S0">ItemValue</col>
+	</table>
+
+	<table name="ISComCatalogCollection">
+		<col key="yes" def="s72">ISComCatalogCollection</col>
+		<col def="s72">ISComCatalogObject_</col>
+		<col def="s255">CollectionName</col>
+	</table>
+
+	<table name="ISComCatalogCollectionObjects">
+		<col key="yes" def="s72">ISComCatalogCollection_</col>
+		<col key="yes" def="s72">ISComCatalogObject_</col>
+	</table>
+
+	<table name="ISComCatalogObject">
+		<col key="yes" def="s72">ISComCatalogObject</col>
+		<col def="s255">DisplayName</col>
+	</table>
+
+	<table name="ISComPlusApplication">
+		<col key="yes" def="s72">ISComCatalogObject_</col>
+		<col def="S255">ComputerName</col>
+		<col def="s72">Component_</col>
+		<col def="I2">ISAttributes</col>
+		<col def="S0">DepFiles</col>
+	</table>
+
+	<table name="ISComPlusProxy">
+		<col key="yes" def="s72">ISComPlusProxy</col>
+		<col def="s72">ISComPlusApplication_</col>
+		<col def="S72">Component_</col>
+		<col def="I2">ISAttributes</col>
+		<col def="S0">DepFiles</col>
+	</table>
+
+	<table name="ISComponentExtended">
+		<col key="yes" def="s72">Component_</col>
+		<col def="I4">OS</col>
+		<col def="S0">Language</col>
+		<col def="s72">FilterProperty</col>
+		<col def="I4">Platforms</col>
+		<col def="S0">FTPLocation</col>
+		<col def="S0">HTTPLocation</col>
+		<col def="S0">Miscellaneous</col>
+		<row><td>AllOtherFiles</td><td/><td/><td>_74B17E30_4D29_487A_8CD4_7B95B8D56A83_FILTER</td><td/><td/><td/><td/></row>
+		<row><td>AllOtherFiles1</td><td/><td/><td>_7B0061CE_6436_4507_9459_93572D569FC1_FILTER</td><td/><td/><td/><td/></row>
+		<row><td>AllOtherFiles10</td><td/><td/><td>_E157B509_E34A_4875_AB50_BA85BE3F5DD2_FILTER</td><td/><td/><td/><td/></row>
+		<row><td>AllOtherFiles11</td><td/><td/><td>_3B6FD6F4_F250_47A8_834C_D7EFD14C3BEF_FILTER</td><td/><td/><td/><td/></row>
+		<row><td>AllOtherFiles12</td><td/><td/><td>_D98A783F_15B1_4E2D_B444_2AFE9178F6F0_FILTER</td><td/><td/><td/><td/></row>
+		<row><td>AllOtherFiles2</td><td/><td/><td>_7322BDD9_A833_41E8_B75C_D99037B19E78_FILTER</td><td/><td/><td/><td/></row>
+		<row><td>AllOtherFiles3</td><td/><td/><td>_C7E1E3F1_ABC8_4A0D_929F_A385EDF1E1F7_FILTER</td><td/><td/><td/><td/></row>
+		<row><td>AllOtherFiles4</td><td/><td/><td>_D740564E_80EF_41ED_958F_95C1F4062224_FILTER</td><td/><td/><td/><td/></row>
+		<row><td>AllOtherFiles5</td><td/><td/><td>_D918C9FE_F0EE_4F2B_870A_095BCA8C2C2F_FILTER</td><td/><td/><td/><td/></row>
+		<row><td>AllOtherFiles6</td><td/><td/><td>_228CD380_C643_4C2C_8ECB_4E7429660108_FILTER</td><td/><td/><td/><td/></row>
+		<row><td>AllOtherFiles7</td><td/><td/><td>_0C21B08E_04C8_4326_8560_DDA770F7D93E_FILTER</td><td/><td/><td/><td/></row>
+		<row><td>AllOtherFiles8</td><td/><td/><td>_845468E3_C693_4547_A32F_F231781A4C8A_FILTER</td><td/><td/><td/><td/></row>
+		<row><td>AllOtherFiles9</td><td/><td/><td>_5F1CCD3B_FD30_4D31_ACEE_707E99BE0281_FILTER</td><td/><td/><td/><td/></row>
+		<row><td>ISRegistryComponent</td><td/><td/><td>_1DEB35F2_294C_4ED0_B0A2_78FB6F4E2EFF_FILTER</td><td/><td/><td/><td/></row>
+		<row><td>ISRegistryComponent1</td><td/><td/><td>_2E54C60F_AF93_4D31_8E1B_F381B381FC92_FILTER</td><td/><td/><td/><td/></row>
+		<row><td>VirtualDirComponent</td><td/><td/><td>_5ACAD922_2F71_4963_BCF2_D05C97252574_FILTER</td><td/><td/><td/><td/></row>
+	</table>
+
+	<table name="ISDLLWrapper">
+		<col key="yes" def="s72">EntryPoint</col>
+		<col def="I4">Type</col>
+		<col def="s0">Source</col>
+		<col def="s255">Target</col>
+	</table>
+
+	<table name="ISDRMFile">
+		<col key="yes" def="s72">ISDRMFile</col>
+		<col def="S72">File_</col>
+		<col def="S72">ISDRMLicense_</col>
+		<col def="s255">Shell</col>
+	</table>
+
+	<table name="ISDRMFileAttribute">
+		<col key="yes" def="s72">ISDRMFile_</col>
+		<col key="yes" def="s72">Property</col>
+		<col def="S0">Value</col>
+	</table>
+
+	<table name="ISDRMLicense">
+		<col key="yes" def="s72">ISDRMLicense</col>
+		<col def="S255">Description</col>
+		<col def="S50">ProjectVersion</col>
+		<col def="I4">Attributes</col>
+		<col def="S255">LicenseNumber</col>
+		<col def="S255">RequestCode</col>
+		<col def="S255">ResponseCode</col>
+	</table>
+
+	<table name="ISDependency">
+		<col key="yes" def="S50">ISDependency</col>
+		<col def="I2">Exclude</col>
+	</table>
+
+	<table name="ISDisk1File">
+		<col key="yes" def="s72">ISDisk1File</col>
+		<col def="s255">ISBuildSourcePath</col>
+		<col def="I4">Disk</col>
+	</table>
+
+	<table name="ISDynamicFile">
+		<col key="yes" def="s72">Component_</col>
+		<col key="yes" def="s255">SourceFolder</col>
+		<col def="I2">IncludeFlags</col>
+		<col def="S0">IncludeFiles</col>
+		<col def="S0">ExcludeFiles</col>
+		<col def="I4">ISAttributes</col>
+		<row><td>AllOtherFiles</td><td>&lt;ISProjectFolder&gt;\bin</td><td>4</td><td/><td/><td>0</td></row>
+		<row><td>AllOtherFiles1</td><td>&lt;ISProjectFolder&gt;\conf</td><td>4</td><td/><td/><td>0</td></row>
+		<row><td>AllOtherFiles2</td><td>&lt;ISProjectFolder&gt;\log</td><td>4</td><td/><td/><td>0</td></row>
+	</table>
+
+	<table name="ISFeatureMergeModuleExcludes">
+		<col key="yes" def="s38">Feature_</col>
+		<col key="yes" def="s255">ModuleID</col>
+		<col key="yes" def="i2">Language</col>
+	</table>
+
+	<table name="ISFeatureMergeModules">
+		<col key="yes" def="s38">Feature_</col>
+		<col key="yes" def="s255">ISMergeModule_</col>
+		<col key="yes" def="i2">Language_</col>
+	</table>
+
+	<table name="ISIISCommon">
+		<col key="yes" def="s50">ISIISCommon</col>
+		<col def="S50">ISIISCommon_Parent</col>
+		<col def="L255">DisplayName</col>
+		<col def="s50">RootDir</col>
+		<col def="i4">Attributes</col>
+		<col def="L255">DefDoc</col>
+		<col def="I4">SessionTimeout</col>
+		<col def="I4">ScriptTimeout</col>
+		<col def="S255">AnonyUserName</col>
+		<col def="S255">AnonyPasswrd</col>
+		<col def="S0">CustomErrors</col>
+		<col def="L255">AppName</col>
+		<col def="S72">SSLCert</col>
+		<row><td>ISIISCommonVRoot</td><td>ISIISCommonWebsite1</td><td>##ID_STRING3##</td><td>BIN</td><td>28069</td><td>Default.asp</td><td>20</td><td>90</td><td/><td/><td/><td/><td/></row>
+		<row><td>ISIISCommonWebsite1</td><td/><td>Default Web Site</td><td>IISROOTFOLDER</td><td>28113</td><td/><td>20</td><td>90</td><td/><td/><td/><td/><td/></row>
+	</table>
+
+	<table name="ISIISMetaData">
+		<col key="yes" def="s72">ISIISCommon_</col>
+		<col key="yes" def="I4">MetaDataProp</col>
+		<col def="I4">MetaDataType</col>
+		<col def="i4">MetaDataUserType</col>
+		<col def="i4">MetaDataAttributes</col>
+		<col def="i4">Order</col>
+		<col def="s0">MetaDataValue</col>
+	</table>
+
+	<table name="ISInstallScriptAction">
+		<col key="yes" def="s72">EntryPoint</col>
+		<col def="I4">Type</col>
+		<col def="s72">Source</col>
+		<col def="S255">Target</col>
+	</table>
+
+	<table name="ISLanguage">
+		<col key="yes" def="s50">ISLanguage</col>
+		<col def="I2">Included</col>
+		<row><td>1033</td><td>1</td></row>
+	</table>
+
+	<table name="ISLinkerLibrary">
+		<col key="yes" def="s72">ISLinkerLibrary</col>
+		<col def="s255">Library</col>
+		<col def="i4">Order</col>
+		<row><td>Isrt.obl</td><td>&lt;ISProductFolder&gt;\Script\ISRT\Lib\isrt.obl</td><td>2</td></row>
+		<row><td>Iswi.obl</td><td>&lt;ISProductFolder&gt;\Script\ISWi\Lib\iswi.obl</td><td>1</td></row>
+	</table>
+
+	<table name="ISLocalControl">
+		<col key="yes" def="s72">Dialog_</col>
+		<col key="yes" def="s50">Control_</col>
+		<col key="yes" def="s50">ISLanguage_</col>
+		<col def="I4">Attributes</col>
+		<col def="I2">X</col>
+		<col def="I2">Y</col>
+		<col def="I2">Width</col>
+		<col def="I2">Height</col>
+		<col def="S72">Binary_</col>
+		<col def="S255">ISBuildSourcePath</col>
+	</table>
+
+	<table name="ISLocalDialog">
+		<col key="yes" def="S50">Dialog_</col>
+		<col key="yes" def="S50">ISLanguage_</col>
+		<col def="I4">Attributes</col>
+		<col def="S72">TextStyle_</col>
+		<col def="i2">Width</col>
+		<col def="i2">Height</col>
+	</table>
+
+	<table name="ISLocalRadioButton">
+		<col key="yes" def="s72">Property</col>
+		<col key="yes" def="i2">Order</col>
+		<col key="yes" def="s50">ISLanguage_</col>
+		<col def="i2">X</col>
+		<col def="i2">Y</col>
+		<col def="i2">Width</col>
+		<col def="i2">Height</col>
+	</table>
+
+	<table name="ISLogicalDisk">
+		<col key="yes" def="i2">DiskId</col>
+		<col key="yes" def="s255">ISProductConfiguration_</col>
+		<col key="yes" def="s255">ISRelease_</col>
+		<col def="i2">LastSequence</col>
+		<col def="L64">DiskPrompt</col>
+		<col def="S255">Cabinet</col>
+		<col def="S32">VolumeLabel</col>
+		<col def="S32">Source</col>
+		<row><td>1</td><td>Release</td><td>Bin</td><td>0</td><td/><td/><td/><td/></row>
+		<row><td>1</td><td>Release</td><td>Msi</td><td>0</td><td/><td/><td/><td/></row>
+	</table>
+
+	<table name="ISLogicalDiskFeatures">
+		<col key="yes" def="i2">ISLogicalDisk_</col>
+		<col key="yes" def="s255">ISProductConfiguration_</col>
+		<col key="yes" def="s255">ISRelease_</col>
+		<col key="yes" def="S38">Feature_</col>
+		<col def="i2">Sequence</col>
+		<col def="I4">ISAttributes</col>
+	</table>
+
+	<table name="ISMergeModule">
+		<col key="yes" def="s255">ISMergeModule</col>
+		<col key="yes" def="i2">Language</col>
+		<col def="s255">Name</col>
+		<col def="S255">Destination</col>
+		<col def="I4">ISAttributes</col>
+	</table>
+
+	<table name="ISMergeModuleCfgValues">
+		<col key="yes" def="s255">ISMergeModule_</col>
+		<col key="yes" def="i2">Language_</col>
+		<col key="yes" def="s72">ModuleConfiguration_</col>
+		<col def="L0">Value</col>
+		<col def="i2">Format</col>
+		<col def="L255">Type</col>
+		<col def="L255">ContextData</col>
+		<col def="L255">DefaultValue</col>
+		<col def="I2">Attributes</col>
+		<col def="L255">DisplayName</col>
+		<col def="L255">Description</col>
+		<col def="L255">HelpLocation</col>
+		<col def="L255">HelpKeyword</col>
+	</table>
+
+	<table name="ISObject">
+		<col key="yes" def="s50">ObjectName</col>
+		<col def="s15">Language</col>
+	</table>
+
+	<table name="ISObjectProperty">
+		<col key="yes" def="S50">ObjectName</col>
+		<col key="yes" def="S50">Property</col>
+		<col def="S0">Value</col>
+		<col def="I2">IncludeInBuild</col>
+	</table>
+
+	<table name="ISPalmApp">
+		<col key="yes" def="s72">PalmApp</col>
+		<col key="yes" def="s72">Component</col>
+	</table>
+
+	<table name="ISPalmAppFile">
+		<col key="yes" def="s72">PalmApp</col>
+		<col key="yes" def="s72">FileKey</col>
+		<col def="i4">Destination</col>
+	</table>
+
+	<table name="ISPatchConfigImage">
+		<col key="yes" def="S72">PatchConfiguration_</col>
+		<col key="yes" def="s72">UpgradedImage_</col>
+	</table>
+
+	<table name="ISPatchConfiguration">
+		<col key="yes" def="s72">Name</col>
+		<col def="i2">CanPCDiffer</col>
+		<col def="i2">CanPVDiffer</col>
+		<col def="i2">IncludeWholeFiles</col>
+		<col def="i2">LeaveDecompressed</col>
+		<col def="i2">OptimizeForSize</col>
+		<col def="i2">EnablePatchCache</col>
+		<col def="S0">PatchCacheDir</col>
+		<col def="i4">Flags</col>
+		<col def="S0">PatchGuidsToReplace</col>
+		<col def="s0">TargetProductCodes</col>
+		<col def="s50">PatchGuid</col>
+		<col def="s0">OutputPath</col>
+		<col def="i2">MinMsiVersion</col>
+		<col def="I4">Attributes</col>
+	</table>
+
+	<table name="ISPatchConfigurationProperty">
+		<col key="yes" def="S72">ISPatchConfiguration_</col>
+		<col key="yes" def="S50">Property</col>
+		<col def="S50">Value</col>
+	</table>
+
+	<table name="ISPatchExternalFile">
+		<col key="yes" def="s50">Name</col>
+		<col key="yes" def="s13">ISUpgradedImage_</col>
+		<col def="s72">FileKey</col>
+		<col def="s255">FilePath</col>
+	</table>
+
+	<table name="ISPatchWholeFile">
+		<col key="yes" def="s50">UpgradedImage</col>
+		<col key="yes" def="s72">FileKey</col>
+		<col def="S72">Component</col>
+	</table>
+
+	<table name="ISPathVariable">
+		<col key="yes" def="s32">ISPathVariable</col>
+		<col def="S255">Value</col>
+		<col def="S255">TestValue</col>
+		<col def="i4">Type</col>
+		<row><td>CommonFilesFolder</td><td/><td/><td>1</td></row>
+		<row><td>ISPROJECTDIR</td><td/><td/><td>1</td></row>
+		<row><td>ISProductFolder</td><td/><td/><td>1</td></row>
+		<row><td>ISProjectDataFolder</td><td/><td/><td>1</td></row>
+		<row><td>ISProjectFolder</td><td/><td/><td>1</td></row>
+		<row><td>PATH_TO_IIS_FILES</td><td>C:\W\jakarta\jtc\jk\native\iis</td><td/><td>2</td></row>
+		<row><td>ProgramFilesFolder</td><td/><td/><td>1</td></row>
+		<row><td>SystemFolder</td><td/><td/><td>1</td></row>
+		<row><td>WindowsFolder</td><td/><td/><td>1</td></row>
+	</table>
+
+	<table name="ISProductConfiguration">
+		<col key="yes" def="s72">ISProductConfiguration</col>
+		<col def="S255">ProductConfigurationFlags</col>
+		<col def="I4">GeneratePackageCode</col>
+		<row><td>Release</td><td/><td>1</td></row>
+	</table>
+
+	<table name="ISProductConfigurationInstance">
+		<col key="yes" def="s72">ISProductConfiguration_</col>
+		<col key="yes" def="i2">InstanceId</col>
+		<col key="yes" def="s72">Property</col>
+		<col def="s255">Value</col>
+	</table>
+
+	<table name="ISProductConfigurationProperty">
+		<col key="yes" def="s72">ISProductConfiguration_</col>
+		<col key="yes" def="s72">Property</col>
+		<col def="L255">Value</col>
+		<row><td>Release</td><td>SetupFileName</td><td>setup</td></row>
+	</table>
+
+	<table name="ISRelease">
+		<col key="yes" def="s72">ISRelease</col>
+		<col key="yes" def="s72">ISProductConfiguration_</col>
+		<col def="s255">BuildLocation</col>
+		<col def="s255">PackageName</col>
+		<col def="i4">Type</col>
+		<col def="s255">SupportedLanguagesUI</col>
+		<col def="i4">MsiSourceType</col>
+		<col def="i4">ReleaseType</col>
+		<col def="s72">Platforms</col>
+		<col def="S255">SupportedLanguagesData</col>
+		<col def="s6">DefaultLanguage</col>
+		<col def="i4">SupportedOSs</col>
+		<col def="s50">DiskSize</col>
+		<col def="i4">DiskSizeUnit</col>
+		<col def="i4">DiskClusterSize</col>
+		<col def="S255">ReleaseFlags</col>
+		<col def="i4">DiskSpanning</col>
+		<col def="S255">SynchMsi</col>
+		<col def="s255">MediaLocation</col>
+		<col def="S255">URLLocation</col>
+		<col def="S255">DigitalURL</col>
+		<col def="S255">DigitalPVK</col>
+		<col def="S255">DigitalSPC</col>
+		<col def="S255">Password</col>
+		<col def="S255">VersionCopyright</col>
+		<col def="i4">Attributes</col>
+		<col def="S255">CDBrowser</col>
+		<col def="S255">DotNetBuildConfiguration</col>
+		<col def="S255">MsiCommandLine</col>
+		<col def="I4">ISSetupPrerequisiteLocation</col>
+		<row><td>Bin</td><td>Release</td><td>&lt;ISProjectDataFolder&gt;</td><td>PackageName</td><td>4</td><td>1033</td><td>2</td><td>1</td><td>Intel</td><td/><td>1033</td><td>3</td><td>0</td><td>1</td><td>0</td><td/><td>0</td><td/><td>MediaLocation</td><td/><td>http://</td><td/><td/><td/><td/><td>8988685</td><td/><td/><td/><td/></row>
+		<row><td>Msi</td><td>Release</td><td>&lt;ISProjectDataFolder&gt;</td><td>PackageName</td><td>0</td><td>1033</td><td>2</td><td>1</td><td>Intel</td><td/><td>1033</td><td>3</td><td>650</td><td>0</td><td>2048</td><td/><td>0</td><td/><td>MediaLocation</td><td/><td>http://</td><td/><td/><td/><td/><td>8464397</td><td/><td/><td/><td/></row>
+	</table>
+
+	<table name="ISReleaseExtended">
+		<col key="yes" def="s72">ISRelease_</col>
+		<col key="yes" def="s72">ISProductConfiguration_</col>
+		<col def="I4">WebType</col>
+		<col def="S255">WebURL</col>
+		<col def="I4">WebCabSize</col>
+		<col def="S255">OneClickCabName</col>
+		<col def="S255">OneClickHtmlName</col>
+		<col def="S255">WebLocalCachePath</col>
+		<col def="I4">EngineLocation</col>
+		<col def="S255">Win9xMsiUrl</col>
+		<col def="S255">WinNTMsiUrl</col>
+		<col def="I4">ISEngineLocation</col>
+		<col def="S255">ISEngineURL</col>
+		<col def="I4">OneClickTargetBrowser</col>
+		<col def="S255">DigitalCertificateIdNS</col>
+		<col def="S255">DigitalCertificateDBaseNS</col>
+		<col def="S255">DigitalCertificatePasswordNS</col>
+		<col def="I4">DotNetRedistLocation</col>
+		<col def="S255">DotNetRedistURL</col>
+		<col def="I4">DotNetVersion</col>
+		<col def="S255">DotNetBaseLanguage</col>
+		<col def="S0">DotNetLangaugePacks</col>
+		<col def="S255">DotNetFxCmdLine</col>
+		<col def="S255">DotNetLangPackCmdLine</col>
+		<col def="S50">JSharpCmdLine</col>
+		<col def="I4">Attributes</col>
+		<col def="I4">JSharpRedistLocation</col>
+		<col def="I4">MsiEngineVersion</col>
+		<col def="S255">WinMsi30Url</col>
+		<col def="S255">CertPassword</col>
+		<row><td>Bin</td><td>Release</td><td>0</td><td>http://</td><td>0</td><td>install</td><td>install</td><td>[WindowsFolder]Downloaded Installations</td><td>1</td><td>http://www.installengine.com/Msiengine20</td><td>http://www.installengine.com/Msiengine20</td><td>2</td><td>http://www.installengine.com/cert03/isengine</td><td>2</td><td/><td/><td/><td>3</td><td>http://www.installengine.com/cert03/dotnetfx</td><td>0</td><td>1033</td><td/><td/><td/><td/><td>16</td><td>3</td><td>4</td><td>http://www.installengine.com/Msiengine30</td><td/></row>
+		<row><td>Msi</td><td>Release</td><td>0</td><td>http://</td><td>0</td><td>install</td><td>install</td><td>[WindowsFolder]Downloaded Installations</td><td>2</td><td>http://www.installengine.com/Msiengine20</td><td>http://www.installengine.com/Msiengine20</td><td>2</td><td>http://www.installengine.com/cert03/isengine</td><td/><td/><td/><td/><td>3</td><td>http://www.installengine.com/cert03/dotnetfx</td><td>0</td><td>1033</td><td/><td/><td/><td/><td>16</td><td>3</td><td>4</td><td>http://www.installengine.com/Msiengine30</td><td/></row>
+		<row><td>Release 1</td><td>Release</td><td/><td/><td/><td/><td/><td/><td/><td/><td/><td/><td/><td/><td/><td/><td/><td/><td/><td/><td/><td/><td/><td/><td/><td/><td/><td/><td/><td/></row>
+	</table>
+
+	<table name="ISReleasePublishInfo">
+		<col key="yes" def="s72">ISRelease_</col>
+		<col def="s72">ISProductConfiguration_</col>
+		<col def="S255">Repository</col>
+		<col def="S255">DisplayName</col>
+		<col def="S255">Publisher</col>
+		<col def="S255">Description</col>
+		<col def="I4">ISAttributes</col>
+	</table>
+
+	<table name="ISSQLConnection">
+		<col key="yes" def="s72">ISSQLConnection</col>
+		<col def="s255">Server</col>
+		<col def="s255">Database</col>
+		<col def="s255">UserName</col>
+		<col def="s255">Password</col>
+		<col def="s255">Authentication</col>
+		<col def="i2">Attributes</col>
+		<col def="i2">Order</col>
+		<col def="S0">Comments</col>
+		<col def="I4">CmdTimeout</col>
+	</table>
+
+	<table name="ISSQLConnectionDBServer">
+		<col key="yes" def="s72">ISSQLConnectionDBServer</col>
+		<col key="yes" def="s72">ISSQLConnection_</col>
+		<col key="yes" def="s72">ISSQLDBMetaData_</col>
+		<col def="i2">Order</col>
+	</table>
+
+	<table name="ISSQLConnectionScript">
+		<col key="yes" def="s72">ISSQLConnection_</col>
+		<col key="yes" def="s72">ISSQLScriptFile_</col>
+		<col def="i2">Order</col>
+	</table>
+
+	<table name="ISSQLDBMetaData">
+		<col key="yes" def="s72">ISSQLDBMetaData</col>
+		<col def="S0">DisplayName</col>
+		<col def="S0">AdoDriverName</col>
+		<col def="S0">AdoCxnDriver</col>
+		<col def="S0">AdoCxnServer</col>
+		<col def="S0">AdoCxnDatabase</col>
+		<col def="S0">AdoCxnUserID</col>
+		<col def="S0">AdoCxnPassword</col>
+		<col def="S0">AdoCxnWindowsSecurity</col>
+		<col def="S0">AdoCxnNetLibrary</col>
+		<col def="S0">TestDatabaseCmd</col>
+		<col def="S0">TestTableCmd</col>
+		<col def="S0">VersionInfoCmd</col>
+		<col def="S0">VersionBeginToken</col>
+		<col def="S0">VersionEndToken</col>
+		<col def="S0">LocalInstanceNames</col>
+	</table>
+
+	<table name="ISSQLRequirement">
+		<col key="yes" def="s72">ISSQLRequirement</col>
+		<col key="yes" def="s72">ISSQLConnection_</col>
+		<col def="S15">MajorVersion</col>
+		<col def="S25">ServicePackLevel</col>
+		<col def="i4">Attributes</col>
+		<col def="S72">ISSQLConnectionDBServer_</col>
+	</table>
+
+	<table name="ISSQLScriptError">
+		<col key="yes" def="i4">ErrNumber</col>
+		<col key="yes" def="S72">ISSQLScriptFile_</col>
+		<col def="i2">ErrHandling</col>
+		<col def="L255">Message</col>
+		<col def="i2">Attributes</col>
+	</table>
+
+	<table name="ISSQLScriptFile">
+		<col key="yes" def="s72">ISSQLScriptFile</col>
+		<col def="s72">Component_</col>
+		<col def="i2">Scheduling</col>
+		<col def="L255">InstallText</col>
+		<col def="L255">UninstallText</col>
+		<col def="S0">ISBuildSourcePath</col>
+		<col def="S0">Comments</col>
+		<col def="i2">ErrorHandling</col>
+		<col def="i2">Attributes</col>
+		<col def="S15">Version</col>
+	</table>
+
+	<table name="ISSQLScriptImport">
+		<col key="yes" def="s72">ISSQLScriptFile_</col>
+		<col def="S255">Server</col>
+		<col def="S255">Database</col>
+		<col def="S255">UserName</col>
+		<col def="S255">Password</col>
+		<col def="i4">Authentication</col>
+		<col def="S0">IncludeTables</col>
+		<col def="S0">ExcludeTables</col>
+		<col def="i4">Attributes</col>
+	</table>
+
+	<table name="ISSQLScriptReplace">
+		<col key="yes" def="s72">ISSQLScriptReplace</col>
+		<col key="yes" def="s72">ISSQLScriptFile_</col>
+		<col def="S0">Search</col>
+		<col def="S0">Replace</col>
+		<col def="i4">Attributes</col>
+	</table>
+
+	<table name="ISScriptFile">
+		<col key="yes" def="s255">ISScriptFile</col>
+	</table>
+
+	<table name="ISSelfReg">
+		<col key="yes" def="s72">FileKey</col>
+		<col def="I2">Cost</col>
+		<col def="I2">Order</col>
+		<col def="S50">CmdLine</col>
+	</table>
+
+	<table name="ISSetupFile">
+		<col key="yes" def="s72">ISSetupFile</col>
+		<col def="S255">FileName</col>
+		<col def="V0">Stream</col>
+		<col def="S50">Language</col>
+		<col def="I2">Splash</col>
+		<col def="S0">Path</col>
+	</table>
+
+	<table name="ISSetupPrerequisites">
+		<col key="yes" def="s72">ISSetupPrerequisites</col>
+		<col def="S255">ISBuildSourcePath</col>
+		<col def="I2">Order</col>
+	</table>
+
+	<table name="ISStorages">
+		<col key="yes" def="s72">Name</col>
+		<col def="S0">ISBuildSourcePath</col>
+	</table>
+
+	<table name="ISString">
+		<col key="yes" def="s255">ISString</col>
+		<col key="yes" def="s50">ISLanguage_</col>
+		<col def="S0">Value</col>
+		<col def="I2">Encoded</col>
+		<col def="S0">Comment</col>
+		<col def="I4">TimeStamp</col>
+		<row><td>COMPANY_NAME</td><td>1033</td><td>Apache Software Foundation</td><td>0</td><td/><td>2115503849</td></row>
+		<row><td>DN_AlwaysInstall</td><td>1033</td><td>Always Install</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDPROP_EXPRESS_LAUNCH_CONDITION_COLOR</td><td>1033</td><td>The color settings of your system are not adequate for running [ProductName].</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDPROP_EXPRESS_LAUNCH_CONDITION_OS</td><td>1033</td><td>[ProductName] requires that your computer is running Windows NT 4.0 or Windows 2000 or Windows XP or Windows 2003 Server</td><td>0</td><td/><td>2115550953</td></row>
+		<row><td>IDPROP_EXPRESS_LAUNCH_CONDITION_PROCESSOR</td><td>1033</td><td>The processor is not adequate for running [ProductName].</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDPROP_EXPRESS_LAUNCH_CONDITION_RAM</td><td>1033</td><td>The amount of RAM is not adequate for running [ProductName].</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDPROP_EXPRESS_LAUNCH_CONDITION_SCREEN</td><td>1033</td><td>The screen resolution is not adequate for running [ProductName].</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDPROP_SETUPTYPE_COMPACT</td><td>1033</td><td>Compact</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDPROP_SETUPTYPE_COMPACT_DESC</td><td>1033</td><td>Compact Description</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDPROP_SETUPTYPE_COMPLETE</td><td>1033</td><td>Complete</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDPROP_SETUPTYPE_COMPLETE_DESC</td><td>1033</td><td>Complete</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDPROP_SETUPTYPE_CUSTOM</td><td>1033</td><td>Custom</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDPROP_SETUPTYPE_CUSTOM_DESC</td><td>1033</td><td>Custom Description</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDPROP_SETUPTYPE_CUSTOM_DESC_PRO</td><td>1033</td><td>Custom</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDPROP_SETUPTYPE_TYPICAL</td><td>1033</td><td>Typical</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDPROP_SETUPTYPE_TYPICAL_DESC</td><td>1033</td><td>Typical Description</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ACTIONTEXT_1</td><td>1033</td><td>[1]</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ACTIONTEXT_1b</td><td>1033</td><td>[1]</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ACTIONTEXT_1c</td><td>1033</td><td>[1]</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ACTIONTEXT_1d</td><td>1033</td><td>[1]</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ACTIONTEXT_Advertising</td><td>1033</td><td>Advertising application</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ACTIONTEXT_AllocatingRegistry</td><td>1033</td><td>Allocating registry space</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ACTIONTEXT_AppCommandLine</td><td>1033</td><td>Application: [1], Command line: [2]</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ACTIONTEXT_AppId</td><td>1033</td><td>AppId: [1]{{, AppType: [2]}}</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ACTIONTEXT_AppIdAppTypeRSN</td><td>1033</td><td>AppId: [1]{{, AppType: [2], Users: [3], RSN: [4]}}</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ACTIONTEXT_Application</td><td>1033</td><td>Application: [1]</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ACTIONTEXT_BindingExes</td><td>1033</td><td>Binding executables</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ACTIONTEXT_ClassId</td><td>1033</td><td>Class ID: [1]</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ACTIONTEXT_ClsID</td><td>1033</td><td>Class ID: [1]</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ACTIONTEXT_ComponentIDQualifier</td><td>1033</td><td>Component ID: [1], Qualifier: [2]</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ACTIONTEXT_ComponentIdQualifier2</td><td>1033</td><td>Component ID: [1], Qualifier: [2]</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ACTIONTEXT_ComputingSpace</td><td>1033</td><td>Computing space requirements</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ACTIONTEXT_ComputingSpace2</td><td>1033</td><td>Computing space requirements</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ACTIONTEXT_ComputingSpace3</td><td>1033</td><td>Computing space requirements</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ACTIONTEXT_ContentTypeExtension</td><td>1033</td><td>MIME Content Type: [1], Extension: [2]</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ACTIONTEXT_ContentTypeExtension2</td><td>1033</td><td>MIME Content Type: [1], Extension: [2]</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ACTIONTEXT_CopyingNetworkFiles</td><td>1033</td><td>Copying files to the network</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ACTIONTEXT_CopyingNewFiles</td><td>1033</td><td>Copying new files</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ACTIONTEXT_CreatingDuplicate</td><td>1033</td><td>Creating duplicate files</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ACTIONTEXT_CreatingFolders</td><td>1033</td><td>Creating folders</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ACTIONTEXT_CreatingIISRoots</td><td>1033</td><td>Creating IIS Virtual Roots...</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ACTIONTEXT_CreatingShortcuts</td><td>1033</td><td>Creating shortcuts</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ACTIONTEXT_DeletingServices</td><td>1033</td><td>Deleting services</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ACTIONTEXT_EnvironmentStrings</td><td>1033</td><td>Updating environment strings</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ACTIONTEXT_EvaluateLaunchConditions</td><td>1033</td><td>Evaluating launch conditions</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ACTIONTEXT_Extension</td><td>1033</td><td>Extension: [1]</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ACTIONTEXT_Extension2</td><td>1033</td><td>Extension: [1]</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ACTIONTEXT_Feature</td><td>1033</td><td>Feature: [1]</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ACTIONTEXT_FeatureColon</td><td>1033</td><td>Feature: [1]</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ACTIONTEXT_File</td><td>1033</td><td>File: [1]</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ACTIONTEXT_File2</td><td>1033</td><td>File: [1]</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ACTIONTEXT_FileDependencies</td><td>1033</td><td>File: [1],  Dependencies: [2]</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ACTIONTEXT_FileDir</td><td>1033</td><td>File: [1], Directory: [9]</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ACTIONTEXT_FileDir2</td><td>1033</td><td>File: [1], Directory: [9]</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ACTIONTEXT_FileDir3</td><td>1033</td><td>File: [1], Directory: [9]</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ACTIONTEXT_FileDirSize</td><td>1033</td><td>File: [1], Directory: [9], Size: [6]</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ACTIONTEXT_FileDirSize2</td><td>1033</td><td>File: [1],  Directory: [9],  Size: [6]</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ACTIONTEXT_FileDirSize3</td><td>1033</td><td>File: [1],  Directory: [9],  Size: [6]</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ACTIONTEXT_FileDirSize4</td><td>1033</td><td>File: [1],  Directory: [2],  Size: [3]</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ACTIONTEXT_FileDirectorySize</td><td>1033</td><td>File: [1],  Directory: [9],  Size: [6]</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ACTIONTEXT_FileFolder</td><td>1033</td><td>File: [1], Folder: [2]</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ACTIONTEXT_FileFolder2</td><td>1033</td><td>File: [1], Folder: [2]</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ACTIONTEXT_FileSectionKeyValue</td><td>1033</td><td>File: [1],  Section: [2],  Key: [3], Value: [4]</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ACTIONTEXT_FileSectionKeyValue2</td><td>1033</td><td>File: [1],  Section: [2],  Key: [3], Value: [4]</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ACTIONTEXT_Folder</td><td>1033</td><td>Folder: [1]</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ACTIONTEXT_Folder1</td><td>1033</td><td>Folder: [1]</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ACTIONTEXT_Font</td><td>1033</td><td>Font: [1]</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ACTIONTEXT_Font2</td><td>1033</td><td>Font: [1]</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ACTIONTEXT_FoundApp</td><td>1033</td><td>Found application: [1]</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ACTIONTEXT_FreeSpace</td><td>1033</td><td>Free space: [1]</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ACTIONTEXT_GeneratingScript</td><td>1033</td><td>Generating script operations for action:</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ACTIONTEXT_InitializeODBCDirs</td><td>1033</td><td>Initializing ODBC directories</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ACTIONTEXT_InstallODBC</td><td>1033</td><td>Installing ODBC components</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ACTIONTEXT_InstallServices</td><td>1033</td><td>Installing new services</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ACTIONTEXT_InstallingSystemCatalog</td><td>1033</td><td>Installing system catalog</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ACTIONTEXT_KeyName</td><td>1033</td><td>Key: [1], Name: [2]</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ACTIONTEXT_KeyNameValue</td><td>1033</td><td>Key: [1], Name: [2], Value: [3]</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ACTIONTEXT_LibId</td><td>1033</td><td>LibID: [1]</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ACTIONTEXT_Libid2</td><td>1033</td><td>LibID: [1]</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ACTIONTEXT_MigratingFeatureStates</td><td>1033</td><td>Migrating feature states from related applications</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ACTIONTEXT_MovingFiles</td><td>1033</td><td>Moving files</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ACTIONTEXT_NameValueAction</td><td>1033</td><td>Name: [1], Value: [2], Action [3]</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ACTIONTEXT_NameValueAction2</td><td>1033</td><td>Name: [1], Value: [2], Action [3]</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ACTIONTEXT_PatchingFiles</td><td>1033</td><td>Patching files</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ACTIONTEXT_ProgID</td><td>1033</td><td>ProgID: [1]</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ACTIONTEXT_ProgID2</td><td>1033</td><td>ProgID: [1]</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ACTIONTEXT_PropertySignature</td><td>1033</td><td>Property: [1], Signature: [2]</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ACTIONTEXT_PublishProductFeatures</td><td>1033</td><td>Publishing product features</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ACTIONTEXT_PublishProductInfo</td><td>1033</td><td>Publishing product information</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ACTIONTEXT_PublishingQualifiedComponents</td><td>1033</td><td>Publishing qualified components</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ACTIONTEXT_RegUser</td><td>1033</td><td>Registering user</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ACTIONTEXT_RegisterClassServer</td><td>1033</td><td>Registering class servers</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ACTIONTEXT_RegisterExtensionServers</td><td>1033</td><td>Registering extension servers</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ACTIONTEXT_RegisterFonts</td><td>1033</td><td>Registering fonts</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ACTIONTEXT_RegisterMimeInfo</td><td>1033</td><td>Registering MIME info</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ACTIONTEXT_RegisterTypeLibs</td><td>1033</td><td>Registering type libraries</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ACTIONTEXT_RegisteringComPlus</td><td>1033</td><td>Registering COM+ Applications and Components</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ACTIONTEXT_RegisteringModules</td><td>1033</td><td>Registering modules</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ACTIONTEXT_RegisteringProduct</td><td>1033</td><td>Registering product</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ACTIONTEXT_RegisteringProgIdentifiers</td><td>1033</td><td>Registering program identifiers</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ACTIONTEXT_RemoveApps</td><td>1033</td><td>Removing applications</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ACTIONTEXT_RemovingBackup</td><td>1033</td><td>Removing backup files</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ACTIONTEXT_RemovingDuplicates</td><td>1033</td><td>Removing duplicated files</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ACTIONTEXT_RemovingFiles</td><td>1033</td><td>Removing files</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ACTIONTEXT_RemovingFolders</td><td>1033</td><td>Removing folders</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ACTIONTEXT_RemovingIISRoots</td><td>1033</td><td>Removing IIS Virtual Roots...</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ACTIONTEXT_RemovingIni</td><td>1033</td><td>Removing INI file entries</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ACTIONTEXT_RemovingMoved</td><td>1033</td><td>Removing moved files</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ACTIONTEXT_RemovingODBC</td><td>1033</td><td>Removing ODBC components</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ACTIONTEXT_RemovingRegistry</td><td>1033</td><td>Removing system registry values</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ACTIONTEXT_RemovingShortcuts</td><td>1033</td><td>Removing shortcuts</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ACTIONTEXT_RollingBack</td><td>1033</td><td>Rolling back action:</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ACTIONTEXT_SearchForRelated</td><td>1033</td><td>Searching for related applications</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ACTIONTEXT_SearchInstalled</td><td>1033</td><td>Searching for installed applications</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ACTIONTEXT_SearchingQualifyingProducts</td><td>1033</td><td>Searching for qualifying products</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ACTIONTEXT_SearchingQualifyingProducts2</td><td>1033</td><td>Searching for qualifying products</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ACTIONTEXT_Service</td><td>1033</td><td>Service: [1]</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ACTIONTEXT_Service2</td><td>1033</td><td>Service: [2]</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ACTIONTEXT_Service3</td><td>1033</td><td>Service: [1]</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ACTIONTEXT_Service4</td><td>1033</td><td>Service: [1]</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ACTIONTEXT_Shortcut</td><td>1033</td><td>Shortcut: [1]</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ACTIONTEXT_Shortcut1</td><td>1033</td><td>Shortcut: [1]</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ACTIONTEXT_StartingServices</td><td>1033</td><td>Starting services</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ACTIONTEXT_StoppingServices</td><td>1033</td><td>Stopping services</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ACTIONTEXT_UnpublishProductFeatures</td><td>1033</td><td>Unpublishing product features</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ACTIONTEXT_UnpublishQualified</td><td>1033</td><td>Unpublishing Qualified Components</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ACTIONTEXT_UnpublishingProductInfo</td><td>1033</td><td>Unpublishing product information</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ACTIONTEXT_UnregTypeLibs</td><td>1033</td><td>Unregistering type libraries</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ACTIONTEXT_UnregisterClassServers</td><td>1033</td><td>Unregister class servers</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ACTIONTEXT_UnregisterExtensionServers</td><td>1033</td><td>Unregistering extension servers</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ACTIONTEXT_UnregisterModules</td><td>1033</td><td>Unregistering modules</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ACTIONTEXT_UnregisteringComPlus</td><td>1033</td><td>Unregistering COM+ Applications and Components</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ACTIONTEXT_UnregisteringFonts</td><td>1033</td><td>Unregistering fonts</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ACTIONTEXT_UnregisteringMimeInfo</td><td>1033</td><td>Unregistering MIME info</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ACTIONTEXT_UnregisteringProgramIds</td><td>1033</td><td>Unregistering program identifiers</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ACTIONTEXT_UpdateComponentRegistration</td><td>1033</td><td>Updating component registration</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ACTIONTEXT_UpdateEnvironmentStrings</td><td>1033</td><td>Updating environment strings</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ACTIONTEXT_Validating</td><td>1033</td><td>Validating install</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ACTIONTEXT_WritingINI</td><td>1033</td><td>Writing INI file values</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ACTIONTEXT_WritingRegistry</td><td>1033</td><td>Writing system registry values</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_BACK</td><td>1033</td><td>&lt; &amp;Back</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_CANCEL</td><td>1033</td><td>Cancel</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_CANCEL2</td><td>1033</td><td>&amp;Cancel</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_CHANGE</td><td>1033</td><td>&amp;Change...</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_COMPLUS_PROGRESSTEXT_COST</td><td>1033</td><td>Costing COM+ application: [1]</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_COMPLUS_PROGRESSTEXT_INSTALL</td><td>1033</td><td>Installing COM+ application: [1]</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_COMPLUS_PROGRESSTEXT_UNINSTALL</td><td>1033</td><td>Uninstalling COM+ application: [1]</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_DatabaseFolder_InstallDatabaseTo</td><td>1033</td><td>Install [ProductName] database to:</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_0</td><td>1033</td><td>{{Fatal error: }}</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_1</td><td>1033</td><td>Error [1].</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_10</td><td>1033</td><td>=== Logging started: [Date]  [Time] ===</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_100</td><td>1033</td><td>Could not remove shortcut [2]. Verify that the shortcut file exists and that you can access it.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_101</td><td>1033</td><td>Could not register type library for file [2].  Contact your support personnel.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_102</td><td>1033</td><td>Could not unregister type library for file [2].  Contact your support personnel.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_103</td><td>1033</td><td>Could not update the INI file [2][3].  Verify that the file exists and that you can access it.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_104</td><td>1033</td><td>Could not schedule file [2] to replace file [3] on reboot.  Verify that you have write permissions to file [3].</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_105</td><td>1033</td><td>Error removing ODBC driver manager, ODBC error [2]: [3]. Contact your support personnel.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_106</td><td>1033</td><td>Error installing ODBC driver manager, ODBC error [2]: [3]. Contact your support personnel.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_107</td><td>1033</td><td>Error removing ODBC driver [4], ODBC error [2]: [3]. Verify that you have sufficient privileges to remove ODBC drivers.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_108</td><td>1033</td><td>Error installing ODBC driver [4], ODBC error [2]: [3]. Verify that the file [4] exists and that you can access it.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_109</td><td>1033</td><td>Error configuring ODBC data source [4], ODBC error [2]: [3]. Verify that the file [4] exists and that you can access it.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_11</td><td>1033</td><td>=== Logging stopped: [Date]  [Time] ===</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_110</td><td>1033</td><td>Service [2] ([3]) failed to start.  Verify that you have sufficient privileges to start system services.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_111</td><td>1033</td><td>Service [2] ([3]) could not be stopped.  Verify that you have sufficient privileges to stop system services.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_112</td><td>1033</td><td>Service [2] ([3]) could not be deleted.  Verify that you have sufficient privileges to remove system services.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_113</td><td>1033</td><td>Service [2] ([3]) could not be installed.  Verify that you have sufficient privileges to install system services.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_114</td><td>1033</td><td>Could not update environment variable [2].  Verify that you have sufficient privileges to modify environment variables.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_115</td><td>1033</td><td>You do not have sufficient privileges to complete this installation for all users of the machine.  Log on as an administrator and then retry this installation.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_116</td><td>1033</td><td>Could not set file security for file [3]. Error: [2].  Verify that you have sufficient privileges to modify the security permissions for this file.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_117</td><td>1033</td><td>Component Services (COM+ 1.0) are not installed on this computer.  This installation requires Component Services in order to complete successfully.  Component Services are available on Windows 2000.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_118</td><td>1033</td><td>Error registering COM+ application.  Contact your support personnel for more information.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_119</td><td>1033</td><td>Error unregistering COM+ application.  Contact your support personnel for more information.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_12</td><td>1033</td><td>Action start [Time]: [1].</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_120</td><td>1033</td><td>Removing older versions of this application</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_121</td><td>1033</td><td>Preparing to remove older versions of this application</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_122</td><td>1033</td><td>Error applying patch to file [2].  It has probably been updated by other means, and can no longer be modified by this patch.  For more information contact your patch vendor.  {{System Error: [3]}}</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_123</td><td>1033</td><td>[2] cannot install one of its required products. Contact your technical support group.  {{System Error: [3].}}</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_124</td><td>1033</td><td>The older version of [2] cannot be removed.  Contact your technical support group.  {{System Error [3].}}</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_125</td><td>1033</td><td>The description for service '[2]' ([3]) could not be changed.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_126</td><td>1033</td><td>The Windows Installer service cannot update the system file [2] because the file is protected by Windows.  You may need to update your operating system for this program to work correctly. {{Package version: [3], OS Protected version: [4]}}</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_127</td><td>1033</td><td>The Windows Installer service cannot update the protected Windows file [2]. {{Package version: [3], OS Protected version: [4], SFP Error: [5]}}</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_128</td><td>1033</td><td>The Windows Installer service cannot update one or more protected Windows files. SFP Error: [2]. List of protected files: [3]</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_129</td><td>1033</td><td>User installations are disabled via policy on the machine.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_13</td><td>1033</td><td>Action ended [Time]: [1]. Return value [2].</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_130</td><td>1033</td><td>This setup requires Internet Information Server 4.0 or higher for configuring IIS Virtual Roots. Please make sure that you have IIS 4.0 or higher.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_131</td><td>1033</td><td>This setup requires Administrator privileges for configuring IIS Virtual Roots.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_14</td><td>1033</td><td>Time remaining: {[1] minutes }{[2] seconds}</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_15</td><td>1033</td><td>Out of memory. Shut down other applications before retrying.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_16</td><td>1033</td><td>Installer is no longer responding.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_17</td><td>1033</td><td>Installer terminated prematurely.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_18</td><td>1033</td><td>Please wait while Windows configures [ProductName]</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_19</td><td>1033</td><td>Gathering required information...</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_2</td><td>1033</td><td>Warning [1].</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_20</td><td>1033</td><td>{[ProductName] }Setup completed successfully.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_21</td><td>1033</td><td>{[ProductName] }Setup failed.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_22</td><td>1033</td><td>Error reading from file: [2]. {{ System error [3].}}  Verify that the file exists and that you can access it.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_23</td><td>1033</td><td>Cannot create the file [3].  A directory with this name already exists.  Cancel the installation and try installing to a different location.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_2331</td><td>1033</td><td>Error loading library [2] or finding entry point [3].</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_24</td><td>1033</td><td>Please insert the disk: [2]</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_25</td><td>1033</td><td>The installer has insufficient privileges to access this directory: [2].  The installation cannot continue.  Log on as an administrator or contact your system administrator.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_26</td><td>1033</td><td>Error writing to file [2].  Verify that you have access to that directory.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_27</td><td>1033</td><td>Error reading from file [2].  Verify that the file exists and that you can access it.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_27502</td><td>1033</td><td>Could not connect to [2] '[3]'. [4]</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_27503</td><td>1033</td><td>Error retrieving version string from [2] '[3]'. [4]</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_27504</td><td>1033</td><td>SQL version requirements not met: [3]. This installation requires [4]</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_27505</td><td>1033</td><td>Could not open SQL script file [2].</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_27506</td><td>1033</td><td>Error executing SQL script [2]. Line [3]. [4]</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_27507</td><td>1033</td><td>Connection or browsing for database servers requires that MDAC be installed.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_27508</td><td>1033</td><td>Error installing COM+ application [2]. [3]</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_27509</td><td>1033</td><td>Error uninstalling COM+ application [2]. [3]</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_27510</td><td>1033</td><td>Error installing COM+ application [2].  Could not load Microsoft(R) .NET class libraries. Registering .NET serviced components requires that Microsoft(R) .NET Framework be installed.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_27511</td><td>1033</td><td>Could not execute SQL script file [2]. Connection not open: [3]</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_27512</td><td>1033</td><td>Error beginning transactions for [2] '[3]'. Database [4]. [5]</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_27513</td><td>1033</td><td>Error committing transactions for [2] '[3]'. Database [4]. [5]</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_27514</td><td>1033</td><td>This installation requires a Microsoft SQL Server. The specified server '[3]' is a Microsoft SQL Server Desktop Engine (MSDE).</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_27515</td><td>1033</td><td>Error retrieving schema version from [2] '[3]'. Database: '[4]'. [5]</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_27516</td><td>1033</td><td>Error writing schema version to [2] '[3]'. Database: '[4]'. [5]</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_27517</td><td>1033</td><td>This installation requires Administrator privileges for installing COM+ applications. Log on as an administrator and then retry this installation.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_27518</td><td>1033</td><td>The COM+ application "[2]" is configured to run as an NT service; this requires COM+ 1.5 or later on the system. Since your system has COM+ 1.0, this application will not be installed.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_27519</td><td>1033</td><td>Error updating XML file [2]. [3]</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_27520</td><td>1033</td><td>Error opening XML file [2]. [3]</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_27521</td><td>1033</td><td>This setup requires MSXML 3.0 or higher for configuring XML files. Please make sure that you have version 3.0 or higher.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_27522</td><td>1033</td><td>Error creating XML file [2]. [3]</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_27523</td><td>1033</td><td>Error loading servers.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_27524</td><td>1033</td><td>Error loading NetApi32.DLL. The ISNetApi.dll needs to have NetApi32.DLL properly loaded and requires an NT based operating system.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_27525</td><td>1033</td><td>Server not found. Verify that the specified server exists. The server name can not be empty.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_27526</td><td>1033</td><td>Unspecified error from ISNetApi.dll.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_27527</td><td>1033</td><td>The buffer is too small.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_27528</td><td>1033</td><td>Access denied. Check administrative rights.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_27529</td><td>1033</td><td>Invalid computer.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_27530</td><td>1033</td><td>Undefined switch case.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_27531</td><td>1033</td><td>Unhandled exception.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_27532</td><td>1033</td><td>Invalid user name for this server or domain.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_27533</td><td>1033</td><td>The case-sensitive passwords do not match.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_27534</td><td>1033</td><td>The list is empty.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_27535</td><td>1033</td><td>Access violation.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_27536</td><td>1033</td><td>Error getting group.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_27537</td><td>1033</td><td>Error adding user to group. Verify that the group exists for this domain or server.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_27538</td><td>1033</td><td>Error creating user.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_27539</td><td>1033</td><td>ERROR_NETAPI_ERROR_NOT_PRIMARY returned from NetAPI.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_27540</td><td>1033</td><td>The specified user already exists.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_27541</td><td>1033</td><td>The specified group already exists.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_27542</td><td>1033</td><td>Invalid password. Verify that the password is in accordance with your network password policy.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_27543</td><td>1033</td><td>Invalid name.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_27544</td><td>1033</td><td>Invalid group.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_27545</td><td>1033</td><td>The user name can not be empty and must be in the format DOMAIN\Username.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_27546</td><td>1033</td><td>Error loading or creating INI file in the user TEMP directory.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_27547</td><td>1033</td><td>ISNetAPI.dll is not loaded or there was an error loading the dll. This dll needs to be loaded for this operation. Verify that the dll is in the SUPPORTDIR directory.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_27548</td><td>1033</td><td>Error deleting INI file containing new user information from the user's TEMP directory.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_27549</td><td>1033</td><td>Error getting the primary domain controller (PDC).</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_27550</td><td>1033</td><td>Every field must have a value in order to create a user.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_27551</td><td>1033</td><td>ODBC driver for [2] not found. This is required to connect to [2] database servers.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_28</td><td>1033</td><td>Another application has exclusive access to the file [2].  Please shut down all other applications, then click Retry.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_29</td><td>1033</td><td>There is not enough disk space to install the file [2].  Free some disk space and click Retry, or click Cancel to exit.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_3</td><td>1033</td><td>Info [1].</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_30</td><td>1033</td><td>Source file not found: [2].  Verify that the file exists and that you can access it.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_31</td><td>1033</td><td>Error reading from file: [3]. {{ System error [2].}}  Verify that the file exists and that you can access it.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_32</td><td>1033</td><td>Error writing to file: [3]. {{ System error [2].}}  Verify that you have access to that directory.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_33</td><td>1033</td><td>Source file not found{{(cabinet)}}: [2].  Verify that the file exists and that you can access it.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_34</td><td>1033</td><td>Cannot create the directory [2].  A file with this name already exists.  Please rename or remove the file and click Retry, or click Cancel to exit.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_35</td><td>1033</td><td>The volume [2] is currently unavailable.  Please select another.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_36</td><td>1033</td><td>The specified path [2] is unavailable.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_37</td><td>1033</td><td>Unable to write to the specified folder [2].</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_38</td><td>1033</td><td>A network error occurred while attempting to read from the file [2]</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_39</td><td>1033</td><td>An error occurred while attempting to create the directory [2]</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_4</td><td>1033</td><td>Internal Error [1]. [2]{, [3]}{, [4]}</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_40</td><td>1033</td><td>A network error occurred while attempting to create the directory [2]</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_41</td><td>1033</td><td>A network error occurred while attempting to open the source file cabinet [2].</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_42</td><td>1033</td><td>The specified path is too long [2].</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_43</td><td>1033</td><td>The Installer has insufficient privileges to modify the file [2].</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_44</td><td>1033</td><td>A portion of the path [2] exceeds the length allowed by the system.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_45</td><td>1033</td><td>The path [2] contains words that are not valid in folders.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_46</td><td>1033</td><td>The path [2] contains an invalid character.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_47</td><td>1033</td><td>[2] is not a valid short file name.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_48</td><td>1033</td><td>Error getting file security: [3] GetLastError: [2]</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_49</td><td>1033</td><td>Invalid Drive: [2]</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_5</td><td>1033</td><td>{{Disk full: }}</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_50</td><td>1033</td><td>Could not create key [2]. {{ System error [3].}}  Verify that you have sufficient access to that key, or contact your support personnel.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_51</td><td>1033</td><td>Could not open key: [2]. {{ System error [3].}}  Verify that you have sufficient access to that key, or contact your support personnel.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_52</td><td>1033</td><td>Could not delete value [2] from key [3]. {{ System error [4].}}  Verify that you have sufficient access to that key, or contact your support personnel.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_53</td><td>1033</td><td>Could not delete key [2]. {{ System error [3].}}  Verify that you have sufficient access to that key, or contact your support personnel.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_54</td><td>1033</td><td>Could not read value [2] from key [3]. {{ System error [4].}}  Verify that you have sufficient access to that key, or contact your support personnel.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_55</td><td>1033</td><td>Could not write value [2] to key [3]. {{ System error [4].}}  Verify that you have sufficient access to that key, or contact your support personnel.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_56</td><td>1033</td><td>Could not get value names for key [2]. {{ System error [3].}}  Verify that you have sufficient access to that key, or contact your support personnel.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_57</td><td>1033</td><td>Could not get sub key names for key [2]. {{ System error [3].}}  Verify that you have sufficient access to that key, or contact your support personnel.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_58</td><td>1033</td><td>Could not read security information for key [2]. {{ System error [3].}}  Verify that you have sufficient access to that key, or contact your support personnel.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_59</td><td>1033</td><td>Could not increase the available registry space. [2] KB of free registry space is required for the installation of this application.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_6</td><td>1033</td><td>Action [Time]: [1]. [2]</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_60</td><td>1033</td><td>Another installation is in progress. You must complete that installation before continuing this one.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_61</td><td>1033</td><td>Error accessing secured data. Please make sure the Windows Installer is configured properly and try the installation again.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_62</td><td>1033</td><td>User [2] has previously initiated an installation for product [3].  That user will need to run that installation again before using that product.  Your current installation will now continue.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_63</td><td>1033</td><td>User [2] has previously initiated an installation for product [3].  That user will need to run that installation again before using that product.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_64</td><td>1033</td><td>Out of disk space -- Volume: '[2]'; required space: [3] KB; available space: [4] KB.  Free some disk space and retry.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_65</td><td>1033</td><td>Are you sure you want to cancel?</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_66</td><td>1033</td><td>The file [2][3] is being held in use{ by the following process: Name: [4], ID: [5], Window Title: [6]}.  Close that application and retry.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_67</td><td>1033</td><td>The product [2] is already installed, preventing the installation of this product.  The two products are incompatible.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_68</td><td>1033</td><td>Out of disk space -- Volume: [2]; required space: [3] KB; available space: [4] KB.  If rollback is disabled, enough space is available. Click Cancel to quit, Retry to check available disk space again, or Ignore to continue without rollback.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_69</td><td>1033</td><td>Could not access network location [2].</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_7</td><td>1033</td><td>[ProductName]</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_70</td><td>1033</td><td>The following applications should be closed before continuing the installation:</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_71</td><td>1033</td><td>Could not find any previously installed compliant products on the machine for installing this product.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_72</td><td>1033</td><td>The key [2] is not valid.  Verify that you entered the correct key.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_73</td><td>1033</td><td>The installer must restart your system before configuration of [2] can continue.  Click Yes to restart now or No if you plan to restart later.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_74</td><td>1033</td><td>You must restart your system for the configuration changes made to [2] to take effect. Click Yes to restart now or No if you plan to restart later.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_75</td><td>1033</td><td>An installation for [2] is currently suspended.  You must undo the changes made by that installation to continue.  Do you want to undo those changes?</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_76</td><td>1033</td><td>A previous installation for this product is in progress.  You must undo the changes made by that installation to continue.  Do you want to undo those changes?</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_77</td><td>1033</td><td>No valid source could be found for product [2].  The Windows Installer cannot continue.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_78</td><td>1033</td><td>Installation operation completed successfully.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_79</td><td>1033</td><td>Installation operation failed.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_8</td><td>1033</td><td>{[2]}{, [3]}{, [4]}</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_80</td><td>1033</td><td>Product: [2] -- [3]</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_81</td><td>1033</td><td>You may either restore your computer to its previous state or continue the installation later. Would you like to restore?</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_82</td><td>1033</td><td>An error occurred while writing installation information to disk.  Check to make sure enough disk space is available, and click Retry, or Cancel to end the installation.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_83</td><td>1033</td><td>One or more of the files required to restore your computer to its previous state could not be found.  Restoration will not be possible.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_84</td><td>1033</td><td>The path [2] is not valid.  Please specify a valid path.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_85</td><td>1033</td><td>Out of memory. Shut down other applications before retrying.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_86</td><td>1033</td><td>There is no disk in drive [2]. Please insert one and click Retry, or click Cancel to go back to the previously selected volume.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_87</td><td>1033</td><td>There is no disk in drive [2]. Please insert one and click Retry, or click Cancel to return to the browse dialog and select a different volume.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_88</td><td>1033</td><td>The folder [2] does not exist.  Please enter a path to an existing folder.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_89</td><td>1033</td><td>You have insufficient privileges to read this folder.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_9</td><td>1033</td><td>Message type: [1], Argument: [2]</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_90</td><td>1033</td><td>A valid destination folder for the installation could not be determined.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_91</td><td>1033</td><td>Error attempting to read from the source installation database: [2].</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_92</td><td>1033</td><td>Scheduling reboot operation: Renaming file [2] to [3]. Must reboot to complete operation.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_93</td><td>1033</td><td>Scheduling reboot operation: Deleting file [2]. Must reboot to complete operation.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_94</td><td>1033</td><td>Module [2] failed to register.  HRESULT [3].  Contact your support personnel.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_95</td><td>1033</td><td>Module [2] failed to unregister.  HRESULT [3].  Contact your support personnel.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_96</td><td>1033</td><td>Failed to cache package [2]. Error: [3]. Contact your support personnel.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_97</td><td>1033</td><td>Could not register font [2].  Verify that you have sufficient permissions to install fonts, and that the system supports this font.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_98</td><td>1033</td><td>Could not unregister font [2]. Verify that you have sufficient permissions to remove fonts.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ERROR_99</td><td>1033</td><td>Could not create shortcut [2]. Verify that the destination folder exists and that you can access it.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_INSTALLDIR</td><td>1033</td><td>[INSTALLDIR]</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_INSTALLSHIELD</td><td>1033</td><td>InstallShield</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_INSTALLSHIELD_FORMATTED</td><td>1033</td><td>{&amp;MSSWhiteSerif8}InstallShield</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ISSCRIPT_VERSION_MISSING</td><td>1033</td><td>The InstallScript engine is missing from this machine.  If available, please run ISScript.msi, or contact your support personnel for further assistance.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_ISSCRIPT_VERSION_OLD</td><td>1033</td><td>The InstallScript engine on this machine is older than the version required to run this setup.  If available, please install the latest version of ISScript.msi, or contact your support personnel for further assistance.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_NEXT</td><td>1033</td><td>&amp;Next &gt;</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_OK</td><td>1033</td><td>OK</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_PRINT_BUTTON</td><td>1033</td><td>&amp;Print</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_PRODUCTNAME_INSTALLSHIELD</td><td>1033</td><td>[ProductName] - InstallShield Wizard</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_PROGMSG_IIS_CREATEVROOT</td><td>1033</td><td>Creating IIS virtual directory %s</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_PROGMSG_IIS_CREATEVROOTS</td><td>1033</td><td>Creating IIS virtual directories...</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_PROGMSG_IIS_EXTRACT</td><td>1033</td><td>Extracting information for IIS virtual directories...</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_PROGMSG_IIS_EXTRACTDONE</td><td>1033</td><td>Extracted information for IIS virtual directories...</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_PROGMSG_IIS_REMOVESITE</td><td>1033</td><td>Removing web site at port %d</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_PROGMSG_IIS_REMOVEVROOT</td><td>1033</td><td>Removing IIS virtual directory %s</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_PROGMSG_IIS_REMOVEVROOTS</td><td>1033</td><td>Removing IIS virtual directories...</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_PROGMSG_IIS_ROLLBACKVROOTS</td><td>1033</td><td>Rolling back virtual directory and web site changes...</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_PROGMSG_XML_COSTING</td><td>1033</td><td>Costing XML files...</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_PROGMSG_XML_CREATE_FILE</td><td>1033</td><td>Creating XML file %s...</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_PROGMSG_XML_FILES</td><td>1033</td><td>Performing XML file changes...</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_PROGMSG_XML_REMOVE_FILE</td><td>1033</td><td>Removing XML file %s...</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_PROGMSG_XML_ROLLBACK_FILES</td><td>1033</td><td>Rolling back XML file changes...</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_PROGMSG_XML_UPDATE_FILE</td><td>1033</td><td>Updating XML file %s...</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_SQLBROWSE_INTRO</td><td>1033</td><td>From the list of servers below, select the database server you would like to target.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_SQLLOGIN_BROWSE</td><td>1033</td><td>B&amp;rowse...</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_SQLLOGIN_CONNECT</td><td>1033</td><td>Connect using:</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_SQLLOGIN_DESC</td><td>1033</td><td>Select database server and authentication method</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_SQLLOGIN_ID</td><td>1033</td><td>&amp;Login ID:</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_SQLLOGIN_INTRO</td><td>1033</td><td>Select the database server to install to from the list below or click Browse to see a list of all database servers. You can also specify the way to authenticate your login using your current credentials or a SQL Login ID and Password.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_SQLLOGIN_PSWD</td><td>1033</td><td>&amp;Password:</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_SQLLOGIN_SERVER</td><td>1033</td><td>&amp;Database Server:</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_SQLLOGIN_SQL</td><td>1033</td><td>S&amp;erver authentication using the Login ID and password below</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_SQLLOGIN_TITLE</td><td>1033</td><td>{&amp;MSSansBold8}Database Server</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_SQLLOGIN_WIN</td><td>1033</td><td>&amp;Windows authentication credentials of current user</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_SQLSCRIPT_INSTALLING</td><td>1033</td><td>Executing SQL Install Script...</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_SQLSCRIPT_UNINSTALLING</td><td>1033</td><td>Executing SQL Uninstall Script...</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_STANDARD_USE_SETUPEXE</td><td>1033</td><td>This installation cannot be run by directly launching the MSI package. You must run setup.exe.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_SetupTips_Advertise</td><td>1033</td><td>Will be installed on first use. (Available only if the feature supports this option.)</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_SetupTips_AllInstalledLocal</td><td>1033</td><td>Will be completely installed to the local hard drive.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_SetupTips_CustomSetup</td><td>1033</td><td>{&amp;MSSansBold8}Custom Setup Tips</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_SetupTips_CustomSetupDescription</td><td>1033</td><td>Custom Setup allows you to selectively install program features.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_SetupTips_IconInstallState</td><td>1033</td><td>The icon next to the feature name indicates the install state of the feature. Click the icon to drop down the install state menu for each feature.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_SetupTips_InstallState</td><td>1033</td><td>This install state means the feature...</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_SetupTips_Network</td><td>1033</td><td>Will be installed to run from the network. (Available only if the feature supports this option.)</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_SetupTips_OK</td><td>1033</td><td>OK</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_SetupTips_SubFeaturesInstalledLocal</td><td>1033</td><td>Will have some subfeatures installed to the local hard drive. (Available only if the feature has subfeatures.)</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_SetupTips_WillNotBeInstalled</td><td>1033</td><td>Will not be installed.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_UITEXT_Available</td><td>1033</td><td>Available</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_UITEXT_Bytes</td><td>1033</td><td>bytes</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_UITEXT_CompilingFeaturesCost</td><td>1033</td><td>Compiling cost for this feature...</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_UITEXT_Differences</td><td>1033</td><td>Differences</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_UITEXT_DiskSize</td><td>1033</td><td>Disk Size</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_UITEXT_FeatureCompletelyRemoved</td><td>1033</td><td>This feature will be completely removed.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_UITEXT_FeatureContinueNetwork</td><td>1033</td><td>This feature will continue to be run from the network</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_UITEXT_FeatureFreeSpace</td><td>1033</td><td>This feature frees up [1] on your hard drive.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_UITEXT_FeatureInstalledCD</td><td>1033</td><td>This feature, and all subfeatures, will be installed to run from the CD.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_UITEXT_FeatureInstalledCD2</td><td>1033</td><td>This feature will be installed to run from CD.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_UITEXT_FeatureInstalledLocal</td><td>1033</td><td>This feature, and all subfeatures, will be installed on local hard drive.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_UITEXT_FeatureInstalledLocal2</td><td>1033</td><td>This feature will be installed on local hard drive.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_UITEXT_FeatureInstalledNetwork</td><td>1033</td><td>This feature, and all subfeatures, will be installed to run from the network.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_UITEXT_FeatureInstalledNetwork2</td><td>1033</td><td>This feature will be installed to run from network.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_UITEXT_FeatureInstalledRequired</td><td>1033</td><td>Will be installed when required.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_UITEXT_FeatureInstalledWhenRequired</td><td>1033</td><td>This feature will be set to be installed when required.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_UITEXT_FeatureInstalledWhenRequired2</td><td>1033</td><td>This feature will be installed when required.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_UITEXT_FeatureLocal</td><td>1033</td><td>This feature will be installed on the local hard drive.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_UITEXT_FeatureLocal2</td><td>1033</td><td>This feature will be installed on your local hard drive.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_UITEXT_FeatureNetwork</td><td>1033</td><td>This feature will be installed to run from the network.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_UITEXT_FeatureNetwork2</td><td>1033</td><td>This feature will be available to run from the network.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_UITEXT_FeatureNotAvailable</td><td>1033</td><td>This feature will not be available.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_UITEXT_FeatureOnCD</td><td>1033</td><td>This feature will be installed to run from CD.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_UITEXT_FeatureOnCD2</td><td>1033</td><td>This feature will be available to run from CD.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_UITEXT_FeatureRemainLocal</td><td>1033</td><td>This feature will remain on your local hard drive.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_UITEXT_FeatureRemoveNetwork</td><td>1033</td><td>This feature will be removed from your local hard drive, but will be still available to run from the network.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_UITEXT_FeatureRemovedCD</td><td>1033</td><td>This feature will be removed from your local hard drive but will still be available to run from CD.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_UITEXT_FeatureRemovedUnlessRequired</td><td>1033</td><td>This feature will be removed from your local hard drive but will be set to be installed when required.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_UITEXT_FeatureRequiredSpace</td><td>1033</td><td>This feature requires [1] on your hard drive.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_UITEXT_FeatureRunFromCD</td><td>1033</td><td>This feature will continue to be run from the CD</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_UITEXT_FeatureSpaceFree</td><td>1033</td><td>This feature frees up [1] on your hard drive. It has [2] of [3] subfeatures selected. The subfeatures free up [4] on your hard drive.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_UITEXT_FeatureSpaceFree2</td><td>1033</td><td>This feature frees up [1] on your hard drive. It has [2] of [3] subfeatures selected. The subfeatures require [4] on your hard drive.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_UITEXT_FeatureSpaceFree3</td><td>1033</td><td>This feature requires [1] on your hard drive. It has [2] of [3] subfeatures selected. The subfeatures free up [4] on your hard drive.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_UITEXT_FeatureSpaceFree4</td><td>1033</td><td>This feature requires [1] on your hard drive. It has [2] of [3] subfeatures selected. The subfeatures require [4] on your hard drive.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_UITEXT_FeatureUnavailable</td><td>1033</td><td>This feature will become unavailable.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_UITEXT_FeatureUninstallNoNetwork</td><td>1033</td><td>This feature will be uninstalled completely, and you won't be able to run it from the network.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_UITEXT_FeatureWasCD</td><td>1033</td><td>This feature was run from the CD but will be set to be installed when required.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_UITEXT_FeatureWasCDLocal</td><td>1033</td><td>This feature was run from the CD but will be installed on the local hard drive.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_UITEXT_FeatureWasOnNetworkInstalled</td><td>1033</td><td>This feature was run from the network but will be installed when required.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_UITEXT_FeatureWasOnNetworkLocal</td><td>1033</td><td>This feature was run from the network but will be installed on the local hard drive.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_UITEXT_FeatureWillBeUninstalled</td><td>1033</td><td>This feature will be uninstalled completely, and you won't be able to run it from CD.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_UITEXT_Folder</td><td>1033</td><td>Fldr|New Folder</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_UITEXT_GB</td><td>1033</td><td>GB</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_UITEXT_KB</td><td>1033</td><td>KB</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_UITEXT_MB</td><td>1033</td><td>MB</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_UITEXT_Required</td><td>1033</td><td>Required</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_UITEXT_TimeRemaining</td><td>1033</td><td>Time remaining: {[1] min }[2] sec</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS_UITEXT_Volume</td><td>1033</td><td>Volume</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__AgreeToLicense_0</td><td>1033</td><td>I &amp;do not accept the terms in the license agreement</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__AgreeToLicense_1</td><td>1033</td><td>I &amp;accept the terms in the license agreement</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__DatabaseFolder_ChangeFolder</td><td>1033</td><td>Click Next to install to this folder, or click Change to install to a different folder.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__DatabaseFolder_DatabaseDir</td><td>1033</td><td>[DATABASEDIR]</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__DatabaseFolder_DatabaseFolder</td><td>1033</td><td>{&amp;MSSansBold8}Database Folder</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__DestinationFolder_Change</td><td>1033</td><td>&amp;Change...</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__DestinationFolder_ChangeFolder</td><td>1033</td><td>Click Next to install to this folder, or click Change to install to a different folder.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__DestinationFolder_DestinationFolder</td><td>1033</td><td>{&amp;MSSansBold8}Destination Folder</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__DestinationFolder_InstallTo</td><td>1033</td><td>Install [ProductName] to:</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__DisplayName_Custom</td><td>1033</td><td>Custom</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__DisplayName_Minimal</td><td>1033</td><td>Minimal</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__DisplayName_Typical</td><td>1033</td><td>Typical</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsAdminInstallBrowse_11</td><td>1033</td><td/><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsAdminInstallBrowse_4</td><td>1033</td><td/><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsAdminInstallBrowse_8</td><td>1033</td><td/><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsAdminInstallBrowse_BrowseDestination</td><td>1033</td><td>Browse to the destination folder.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsAdminInstallBrowse_ChangeDestination</td><td>1033</td><td>{&amp;MSSansBold8}Change Current Destination Folder</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsAdminInstallBrowse_CreateFolder</td><td>1033</td><td>Create new folder|</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsAdminInstallBrowse_FolderName</td><td>1033</td><td>&amp;Folder name:</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsAdminInstallBrowse_LookIn</td><td>1033</td><td>&amp;Look in:</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsAdminInstallBrowse_UpOneLevel</td><td>1033</td><td>Up one level|</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsAdminInstallPointWelcome_ServerImage</td><td>1033</td><td>The InstallShield(R) Wizard will create a server image of [ProductName] at a specified network location. To continue, click Next.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsAdminInstallPointWelcome_Wizard</td><td>1033</td><td>{&amp;TahomaBold10}Welcome to the InstallShield Wizard for [ProductName]</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsAdminInstallPoint_Change</td><td>1033</td><td>&amp;Change...</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsAdminInstallPoint_EnterNetworkLocation</td><td>1033</td><td>Enter the network location or click Change to browse to a location.  Click Install to create a server image of [ProductName] at the specified network location or click Cancel to exit the wizard.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsAdminInstallPoint_Install</td><td>1033</td><td>&amp;Install</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsAdminInstallPoint_NetworkLocation</td><td>1033</td><td>&amp;Network location:</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsAdminInstallPoint_NetworkLocationFormatted</td><td>1033</td><td>{&amp;MSSansBold8}Network Location</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsAdminInstallPoint_SpecifyNetworkLocation</td><td>1033</td><td>Specify a network location for the server image of the product.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsBrowseButton</td><td>1033</td><td>&amp;Browse...</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsBrowseFolderDlg_11</td><td>1033</td><td/><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsBrowseFolderDlg_4</td><td>1033</td><td/><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsBrowseFolderDlg_8</td><td>1033</td><td/><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsBrowseFolderDlg_BrowseDestFolder</td><td>1033</td><td>Browse to the destination folder.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsBrowseFolderDlg_ChangeCurrentFolder</td><td>1033</td><td>{&amp;MSSansBold8}Change Current Destination Folder</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsBrowseFolderDlg_CreateFolder</td><td>1033</td><td>Create New Folder|</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsBrowseFolderDlg_FolderName</td><td>1033</td><td>&amp;Folder name:</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsBrowseFolderDlg_LookIn</td><td>1033</td><td>&amp;Look in:</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsBrowseFolderDlg_OK</td><td>1033</td><td>OK</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsBrowseFolderDlg_UpOneLevel</td><td>1033</td><td>Up One Level|</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsBrowseForAccount</td><td>1033</td><td>Browse for a User Account</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsBrowseGroup</td><td>1033</td><td>Select a Group</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsBrowseUsernameTitle</td><td>1033</td><td>Select a User Name</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsCancelDlg_ConfirmCancel</td><td>1033</td><td>Are you sure you want to cancel [ProductName] installation?</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsCancelDlg_No</td><td>1033</td><td>&amp;No</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsCancelDlg_Yes</td><td>1033</td><td>&amp;Yes</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsConfirmPassword</td><td>1033</td><td>Con&amp;firm password:</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsCreateNewUserTitle</td><td>1033</td><td>New User Information</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsCreateUserBrowse</td><td>1033</td><td>N&amp;ew User Information...</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsCustomSelectionDlg_Change</td><td>1033</td><td>&amp;Change...</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsCustomSelectionDlg_ClickFeatureIcon</td><td>1033</td><td>Click on an icon in the list below to change how a feature is installed.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsCustomSelectionDlg_CustomSetup</td><td>1033</td><td>{&amp;MSSansBold8}Custom Setup</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsCustomSelectionDlg_FeatureDescription</td><td>1033</td><td>Feature Description</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsCustomSelectionDlg_FeaturePath</td><td>1033</td><td>&lt;selected feature path&gt;</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsCustomSelectionDlg_FeatureSize</td><td>1033</td><td>Feature size</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsCustomSelectionDlg_Help</td><td>1033</td><td>&amp;Help</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsCustomSelectionDlg_InstallTo</td><td>1033</td><td>Install to:</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsCustomSelectionDlg_MultilineDescription</td><td>1033</td><td>Multiline description of the currently selected item</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsCustomSelectionDlg_SelectFeatures</td><td>1033</td><td>Select the program features you want installed.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsCustomSelectionDlg_Space</td><td>1033</td><td>&amp;Space</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsDiskSpaceDlg_DiskSpace</td><td>1033</td><td>Disk space required for the installation exceeds available disk space.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsDiskSpaceDlg_HighlightedVolumes</td><td>1033</td><td>The highlighted volumes do not have enough disk space available for the currently selected features. You can remove files from the highlighted volumes, choose to install fewer features onto local drives, or select different destination drives.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsDiskSpaceDlg_Numbers</td><td>1033</td><td>{120}{70}{70}{70}{70}</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsDiskSpaceDlg_OK</td><td>1033</td><td>OK</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsDiskSpaceDlg_OutOfDiskSpace</td><td>1033</td><td>{&amp;MSSansBold8}Out of Disk Space</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsDomainOrServer</td><td>1033</td><td>&amp;Domain or server:</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsErrorDlg_Abort</td><td>1033</td><td>&amp;Abort</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsErrorDlg_ErrorText</td><td>1033</td><td>&lt;error text goes here&gt;&lt;error text goes here&gt;&lt;error text goes here&gt;&lt;error text goes here&gt;&lt;error text goes here&gt;&lt;error text goes here&gt;&lt;error text goes here&gt;&lt;error text goes here&gt;&lt;error text goes here&gt;&lt;error text goes here&gt;&lt;error text goes here&gt;</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsErrorDlg_Ignore</td><td>1033</td><td>&amp;Ignore</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsErrorDlg_InstallerInfo</td><td>1033</td><td>[ProductName] Installer Information</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsErrorDlg_NO</td><td>1033</td><td>&amp;No</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsErrorDlg_OK</td><td>1033</td><td>&amp;OK</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsErrorDlg_Retry</td><td>1033</td><td>&amp;Retry</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsErrorDlg_Yes</td><td>1033</td><td>&amp;Yes</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsExitDialog_Finish</td><td>1033</td><td>&amp;Finish</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsExitDialog_InstallSuccess</td><td>1033</td><td>The InstallShield Wizard has successfully installed [ProductName]. Click Finish to exit the wizard.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsExitDialog_LaunchProgram</td><td>1033</td><td>Launch the program</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsExitDialog_ShowReadMe</td><td>1033</td><td>Show the readme file</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsExitDialog_UninstallSuccess</td><td>1033</td><td>The InstallShield Wizard has successfully uninstalled [ProductName]. Click Finish to exit the wizard.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsExitDialog_Update_InternetConnection</td><td>1033</td><td>Your Internet connection can be used to make sure that you have the latest updates.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsExitDialog_Update_PossibleUpdates</td><td>1033</td><td>Some program files might have been updated since you purchased your copy of [ProductName].</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsExitDialog_Update_SetupFinished</td><td>1033</td><td>Setup has finished installing [ProductName].</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsExitDialog_Update_YesCheckForUpdates</td><td>1033</td><td>&amp;Yes, check for program updates (Recommended) after the setup completes.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsExitDialog_WizardCompleted</td><td>1033</td><td>{&amp;TahomaBold10}InstallShield Wizard Completed</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsFatalError_ClickFinish</td><td>1033</td><td>Click Finish to exit the wizard.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsFatalError_Finish</td><td>1033</td><td>&amp;Finish</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsFatalError_KeepOrRestore</td><td>1033</td><td>You can either keep any existing installed elements on your system to continue this installation at a later time or you can restore your system to its original state prior to the installation.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsFatalError_NotModified</td><td>1033</td><td>Your system has not been modified. To complete installation at another time, please run setup again.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsFatalError_RestoreOrContinueLater</td><td>1033</td><td>Click Restore or Continue Later to exit the wizard.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsFatalError_WizardCompleted</td><td>1033</td><td>{&amp;TahomaBold10}InstallShield Wizard Completed</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsFatalError_WizardInterrupted</td><td>1033</td><td>The wizard was interrupted before [ProductName] could be completely installed.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsFeatureDetailsDlg_DiskSpaceRequirements</td><td>1033</td><td>{&amp;MSSansBold8}Disk Space Requirements</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsFeatureDetailsDlg_Numbers</td><td>1033</td><td>{120}{70}{70}{70}{70}</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsFeatureDetailsDlg_OK</td><td>1033</td><td>OK</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsFeatureDetailsDlg_SpaceRequired</td><td>1033</td><td>The disk space required for the installation of the selected features.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsFeatureDetailsDlg_VolumesTooSmall</td><td>1033</td><td>The highlighted volumes do not have enough disk space available for the currently selected features. You can remove files from the highlighted volumes, choose to install fewer features onto local drives, or select different destination drives.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsFilesInUse_ApplicationsUsingFiles</td><td>1033</td><td>The following applications are using files that need to be updated by this setup. Close these applications and click Retry to continue.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsFilesInUse_Exit</td><td>1033</td><td>&amp;Exit</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsFilesInUse_FilesInUse</td><td>1033</td><td>{&amp;MSSansBold8}Files in Use</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsFilesInUse_FilesInUseMessage</td><td>1033</td><td>Some files that need to be updated are currently in use.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsFilesInUse_Ignore</td><td>1033</td><td>&amp;Ignore</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsFilesInUse_Retry</td><td>1033</td><td>&amp;Retry</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsGroup</td><td>1033</td><td>&amp;Group:</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsGroupLabel</td><td>1033</td><td>Gr&amp;oup:</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsInitDlg_1</td><td>1033</td><td/><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsInitDlg_2</td><td>1033</td><td/><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsInitDlg_PreparingWizard</td><td>1033</td><td>[ProductName] Setup is preparing the InstallShield Wizard which will guide you through the program setup process.  Please wait.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsInitDlg_WelcomeWizard</td><td>1033</td><td>{&amp;TahomaBold10}Welcome to the InstallShield Wizard for [ProductName]</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsLicenseDlg_LicenseAgreement</td><td>1033</td><td>{&amp;MSSansBold8}License Agreement</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsLicenseDlg_ReadLicenseAgreement</td><td>1033</td><td>Please read the following license agreement carefully.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsLogonInfoDescription</td><td>1033</td><td>Specify the user name and password of the user account that will logon to use this application. The user account must be in the form DOMAIN\Username.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsLogonInfoTitle</td><td>1033</td><td>{&amp;MSSansBold8}Logon Information</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsLogonInfoTitleDescription</td><td>1033</td><td>Specify a user name and password</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsLogonNewUserDescription</td><td>1033</td><td>Select the button below to specify information about a new user that will be created during the installation.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsMaintenanceDlg_11</td><td>1033</td><td/><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsMaintenanceDlg_ChangeFeatures</td><td>1033</td><td>Change which program features are installed. This option displays the Custom Selection dialog in which you can change the way features are installed.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsMaintenanceDlg_MaitenanceOptions</td><td>1033</td><td>Modify, repair, or remove the program.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsMaintenanceDlg_Modify</td><td>1033</td><td>{&amp;MSSansBold8}&amp;Modify</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsMaintenanceDlg_ProgramMaintenance</td><td>1033</td><td>{&amp;MSSansBold8}Program Maintenance</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsMaintenanceDlg_Remove</td><td>1033</td><td>{&amp;MSSansBold8}&amp;Remove</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsMaintenanceDlg_RemoveProductName</td><td>1033</td><td>Remove [ProductName] from your computer.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsMaintenanceDlg_Repair</td><td>1033</td><td>{&amp;MSSansBold8}Re&amp;pair</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsMaintenanceDlg_RepairMessage</td><td>1033</td><td>Repair installation errors in the program. This option fixes missing or corrupt files, shortcuts, and registry entries.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsMaintenanceWelcome_MaintenanceOptionsDescription</td><td>1033</td><td>The InstallShield(R) Wizard will allow you to modify, repair, or remove [ProductName]. To continue, click Next.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsMaintenanceWelcome_WizardWelcome</td><td>1033</td><td>{&amp;TahomaBold10}Welcome to the InstallShield Wizard for [ProductName]</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsPatchDlg_PatchClickUpdate</td><td>1033</td><td>The InstallShield(R) Wizard will install the Patch for [ProductName] on your computer.  To continue, click Update.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsPatchDlg_PatchWizard</td><td>1033</td><td>[ProductName] Patch - InstallShield Wizard</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsPatchDlg_Update</td><td>1033</td><td>&amp;Update &gt;</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsPatchDlg_WelcomePatchWizard</td><td>1033</td><td>{&amp;TahomaBold10}Welcome to the Patch for [ProductName]</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsProgressDlg_2</td><td>1033</td><td/><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsProgressDlg_Hidden</td><td>1033</td><td>(Hidden for now)</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsProgressDlg_HiddenTimeRemaining</td><td>1033</td><td>)Hidden for now)Estimated time remaining:</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsProgressDlg_InstallingProductName</td><td>1033</td><td>{&amp;MSSansBold8}Installing [ProductName]</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsProgressDlg_ProgressDone</td><td>1033</td><td>Progress done</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsProgressDlg_SecHidden</td><td>1033</td><td>(Hidden for now)Sec.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsProgressDlg_Status</td><td>1033</td><td>Status:</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsProgressDlg_Uninstalling</td><td>1033</td><td>{&amp;MSSansBold8}Uninstalling [ProductName]</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsProgressDlg_UninstallingFeatures</td><td>1033</td><td>The program features you selected are being uninstalled.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsProgressDlg_UninstallingFeatures2</td><td>1033</td><td>The program features you selected are being installed.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsProgressDlg_WaitUninstall</td><td>1033</td><td>Please wait while the InstallShield Wizard uninstalls [ProductName]. This may take several minutes.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsProgressDlg_WaitUninstall2</td><td>1033</td><td>Please wait while the InstallShield Wizard installs [ProductName]. This may take several minutes.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsReadmeDlg_Cancel</td><td>1033</td><td>&amp;Cancel</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsReadmeDlg_PleaseReadInfo</td><td>1033</td><td>Please read the following readme information carefully.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsReadmeDlg_ReadMeInfo</td><td>1033</td><td>{&amp;MSSansBold8}Readme Information</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsRegisterUserDlg_16</td><td>1033</td><td/><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsRegisterUserDlg_Anyone</td><td>1033</td><td>&amp;Anyone who uses this computer (all users)</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsRegisterUserDlg_CustomerInformation</td><td>1033</td><td>{&amp;MSSansBold8}Customer Information</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsRegisterUserDlg_InstallFor</td><td>1033</td><td>Install this application for:</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsRegisterUserDlg_OnlyMe</td><td>1033</td><td>Only for &amp;me ([USERNAME])</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsRegisterUserDlg_Organization</td><td>1033</td><td>&amp;Organization:</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsRegisterUserDlg_PleaseEnterInfo</td><td>1033</td><td>Please enter your information.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsRegisterUserDlg_SerialNumber</td><td>1033</td><td>&amp;Serial Number:</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsRegisterUserDlg_Tahoma50</td><td>1033</td><td>{\Tahoma8}{50}</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsRegisterUserDlg_Tahoma80</td><td>1033</td><td>{\Tahoma8}{80}</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsRegisterUserDlg_UserName</td><td>1033</td><td>&amp;User Name:</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsResumeDlg_ResumeSuspended</td><td>1033</td><td>The InstallShield(R) Wizard will complete the suspended installation of [ProductName] on your computer. To continue, click Next.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsResumeDlg_Resuming</td><td>1033</td><td>{&amp;TahomaBold10}Resuming the InstallShield Wizard for [ProductName]</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsResumeDlg_WizardResume</td><td>1033</td><td>The InstallShield(R) Wizard will complete the installation of [ProductName] on your computer. To continue, click Next.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsSelectDomainOrServer</td><td>1033</td><td>Select a Domain or Server</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsSelectDomainUserInstructions</td><td>1033</td><td>Use the browse buttons to select a domain\server and a user name.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsSetupTypeMinDlg_13</td><td>1033</td><td/><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsSetupTypeMinDlg_AllFeatures</td><td>1033</td><td>All program features will be installed. (Requires the most disk space.)</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsSetupTypeMinDlg_ChooseFeatures</td><td>1033</td><td>Choose which program features you want installed and where they will be installed. Recommended for advanced users.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsSetupTypeMinDlg_ChooseSetupType</td><td>1033</td><td>Choose the setup type that best suits your needs.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsSetupTypeMinDlg_Complete</td><td>1033</td><td>{&amp;MSSansBold8}&amp;Complete</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsSetupTypeMinDlg_Custom</td><td>1033</td><td>{&amp;MSSansBold8}Cu&amp;stom</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsSetupTypeMinDlg_Minimal</td><td>1033</td><td>{&amp;MSSansBold8}&amp;Minimal</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsSetupTypeMinDlg_MinimumFeatures</td><td>1033</td><td>Minimum required features will be installed.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsSetupTypeMinDlg_SelectSetupType</td><td>1033</td><td>Please select a setup type.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsSetupTypeMinDlg_SetupType</td><td>1033</td><td>{&amp;MSSansBold8}Setup Type</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsSetupTypeMinDlg_Typical</td><td>1033</td><td>{&amp;MSSansBold8}&amp;Typical</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsUserExit_ClickFinish</td><td>1033</td><td>Click Finish to exit the wizard.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsUserExit_Finish</td><td>1033</td><td>&amp;Finish</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsUserExit_KeepOrRestore</td><td>1033</td><td>You can either keep any existing installed elements on your system to continue this installation at a later time or you can restore your system to its original state prior to the installation.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsUserExit_NotModified</td><td>1033</td><td>Your system has not been modified. To install this program at a later time, please run the installation again.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsUserExit_RestoreOrContinue</td><td>1033</td><td>Click Restore or Continue Later to exit the wizard.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsUserExit_WizardCompleted</td><td>1033</td><td>{&amp;TahomaBold10}InstallShield Wizard Completed</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsUserExit_WizardInterrupted</td><td>1033</td><td>The wizard was interrupted before [ProductName] could be completely installed.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsUserNameLabel</td><td>1033</td><td>&amp;User name:</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsVerifyReadyDlg_BackOrCancel</td><td>1033</td><td>If you want to review or change any of your installation settings, click Back. Click Cancel to exit the wizard.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsVerifyReadyDlg_ClickInstall</td><td>1033</td><td>Click Install to begin the installation.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsVerifyReadyDlg_Company</td><td>1033</td><td>Company: [COMPANYNAME]</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsVerifyReadyDlg_CurrentSettings</td><td>1033</td><td>Current Settings:</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsVerifyReadyDlg_DestFolder</td><td>1033</td><td>Destination Folder:</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsVerifyReadyDlg_Install</td><td>1033</td><td>&amp;Install</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsVerifyReadyDlg_Installdir</td><td>1033</td><td>[INSTALLDIR]</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsVerifyReadyDlg_ModifyReady</td><td>1033</td><td>{&amp;MSSansBold8}Ready to Modify the Program</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsVerifyReadyDlg_ReadyInstall</td><td>1033</td><td>{&amp;MSSansBold8}Ready to Install the Program</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsVerifyReadyDlg_ReadyRepair</td><td>1033</td><td>{&amp;MSSansBold8}Ready to Repair the Program</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsVerifyReadyDlg_SelectedSetupType</td><td>1033</td><td>[SelectedSetupType]</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsVerifyReadyDlg_Serial</td><td>1033</td><td>Serial: [ISX_SERIALNUM]</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsVerifyReadyDlg_SetupType</td><td>1033</td><td>Setup Type:</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsVerifyReadyDlg_UserInfo</td><td>1033</td><td>User Information:</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsVerifyReadyDlg_UserName</td><td>1033</td><td>Name: [USERNAME]</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsVerifyReadyDlg_WizardReady</td><td>1033</td><td>The wizard is ready to begin installation.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsVerifyRemoveAllDlg_ChoseRemoveProgram</td><td>1033</td><td>You have chosen to remove the program from your system.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsVerifyRemoveAllDlg_ClickBack</td><td>1033</td><td>If you want to review or change any settings, click Back.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsVerifyRemoveAllDlg_ClickRemove</td><td>1033</td><td>Click Remove to remove [ProductName] from your computer. After removal, this program will no longer be available for use.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsVerifyRemoveAllDlg_Remove</td><td>1033</td><td>&amp;Remove</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsVerifyRemoveAllDlg_RemoveProgram</td><td>1033</td><td>{&amp;MSSansBold8}Remove the Program</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsWelcomeDlg_InstallProductName</td><td>1033</td><td>The InstallShield(R) Wizard will install [ProductName] on your computer. To continue, click Next.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsWelcomeDlg_WarningCopyright</td><td>1033</td><td>WARNING: This program is protected by copyright law and international treaties.</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__IsWelcomeDlg_WelcomeProductName</td><td>1033</td><td>{&amp;TahomaBold10}Welcome to the InstallShield Wizard for [ProductName]</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__TargetReq_DESC_COLOR</td><td>1033</td><td>The color settings of your system are not adequate for running [ProductName].</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__TargetReq_DESC_OS</td><td>1033</td><td>The operating system is not adequate for running [ProductName].</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__TargetReq_DESC_PROCESSOR</td><td>1033</td><td>The processor is not adequate for running [ProductName].</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__TargetReq_DESC_RAM</td><td>1033</td><td>The amount of RAM is not adequate for running [ProductName].</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>IDS__TargetReq_DESC_RESOLUTION</td><td>1033</td><td>The screen resolution is not adequate for running [ProductName].</td><td>0</td><td/><td>-1256677244</td></row>
+		<row><td>ID_STRING1</td><td>1033</td><td>http://jakarta.apache.org</td><td>0</td><td/><td>2115538665</td></row>
+		<row><td>ID_STRING2</td><td>1033</td><td>DisplayName1</td><td>0</td><td/><td>2115549418</td></row>
+		<row><td>ID_STRING3</td><td>1033</td><td>jakarta</td><td>0</td><td/><td>2115510538</td></row>
+		<row><td>ID_STRING4</td><td>1033</td><td>CoreFiles</td><td>0</td><td/><td>2115544011</td></row>
+		<row><td>IIDS_UITEXT_FeatureUninstalled</td><td>1033</td><td>This feature will remain uninstalled.</td><td>0</td><td/><td>-1256677244</td></row>
+	</table>
+
+	<table name="ISTargetImage">
+		<col key="yes" def="s13">UpgradedImage_</col>
+		<col key="yes" def="s13">Name</col>
+		<col def="s0">MsiPath</col>
+		<col def="i2">Order</col>
+		<col def="I4">Flags</col>
+		<col def="i2">IgnoreMissingFiles</col>
+	</table>
+
+	<table name="ISUpgradeMsiItem">
+		<col key="yes" def="s72">UpgradeItem</col>
+		<col def="s0">ObjectSetupPath</col>
+		<col def="S255">ISReleaseFlags</col>
+		<col def="i2">ISAttributes</col>
+	</table>
+
+	<table name="ISUpgradedImage">
+		<col key="yes" def="s13">Name</col>
+		<col def="s0">MsiPath</col>
+		<col def="s8">Family</col>
+	</table>
+
+	<table name="ISVRoot">
+		<col key="yes" def="s50">VRootKey</col>
+		<col def="l255">VRootName</col>
+		<col def="s50">VRootDir</col>
+		<col def="i4">VRootProps</col>
+		<col def="S255">VRootAppName</col>
+		<col def="S255">VRootDefDoc</col>
+		<col def="S255">Condition</col>
+		<col def="I4">SessionTimeout</col>
+		<col def="I4">ScriptTimeout</col>
+		<col def="S255">AnonyUserName</col>
+		<col def="S255">AnonyPasswrd</col>
+		<col def="s72">Component_</col>
+		<row><td>ISIISCommonVRoot</td><td>Obsolete</td><td>Obsolete</td><td>0</td><td/><td/><td/><td/><td/><td/><td/><td>VirtualDirComponent</td></row>
+	</table>
+
+	<table name="ISVRootAppMaps">
+		<col key="yes" def="s255">VRootKey</col>
+		<col key="yes" def="s255">VRootAppMapKey</col>
+		<col def="l50">Extension</col>
+		<col def="l255">ExecPath</col>
+		<col def="l255">Verb</col>
+		<col def="i4">AppMapProps</col>
+	</table>
+
+	<table name="ISWebSite">
+		<col key="yes" def="s50">ISIISCommon_</col>
+		<col def="s50">Port</col>
+		<col def="S50">IP</col>
+		<col def="s50">SiteNumber</col>
+		<col def="I4">WebSiteProps</col>
+		<row><td>ISIISCommonWebsite1</td><td>80</td><td/><td>1</td><td>0</td></row>
+	</table>
+
+	<table name="ISXmlElement">
+		<col key="yes" def="s72">ISXmlElement</col>
+		<col def="s72">ISXmlFile_</col>
+		<col def="S72">ISXmlElement_Parent</col>
+		<col def="L255">XPath</col>
+		<col def="L255">Content</col>
+		<col def="I4">ISAttributes</col>
+	</table>
+
+	<table name="ISXmlElementAttrib">
+		<col key="yes" def="s72">ISXmlElementAttrib</col>
+		<col key="yes" def="s72">ISXmlElement_</col>
+		<col def="L255">Name</col>
+		<col def="L255">Value</col>
+		<col def="I4">ISAttributes</col>
+	</table>
+
+	<table name="ISXmlFile">
+		<col key="yes" def="s72">ISXmlFile</col>
+		<col def="l255">FileName</col>
+		<col def="s72">Component_</col>
+		<col def="s50">Directory</col>
+		<col def="I4">ISAttributes</col>
+	</table>
+
+	<table name="ISXmlLocator">
+		<col key="yes" def="s72">Signature_</col>
+		<col key="yes" def="S72">Parent</col>
+		<col def="S255">Element</col>
+		<col def="S255">Attribute</col>
+		<col def="I2">ISAttributes</col>
+	</table>
+
+	<table name="Icon">
+		<col key="yes" def="s72">Name</col>
+		<col def="V0">Data</col>
+		<col def="S255">ISBuildSourcePath</col>
+		<col def="I2">ISIconIndex</col>
+		<row><td>ARPPRODUCTICON.exe</td><td/><td>&lt;ISProjectFolder&gt;\tomcat.ico</td><td>0</td></row>
+	</table>
+
+	<table name="IniFile">
+		<col key="yes" def="s72">IniFile</col>
+		<col def="l255">FileName</col>
+		<col def="S72">DirProperty</col>
+		<col def="l255">Section</col>
+		<col def="l128">Key</col>
+		<col def="s255">Value</col>
+		<col def="i2">Action</col>
+		<col def="s72">Component_</col>
+	</table>
+
+	<table name="IniLocator">
+		<col key="yes" def="s72">Signature_</col>
+		<col def="s255">FileName</col>
+		<col def="s96">Section</col>
+		<col def="s128">Key</col>
+		<col def="I2">Field</col>
+		<col def="I2">Type</col>
+	</table>
+
+	<table name="InstallExecuteSequence">
+		<col key="yes" def="s72">Action</col>
+		<col def="S255">Condition</col>
+		<col def="I2">Sequence</col>
+		<col def="S255">ISComments</col>
+		<col def="I4">ISAttributes</col>
+		<row><td>AllocateRegistrySpace</td><td>NOT Installed</td><td>1550</td><td>AllocateRegistrySpace</td><td/></row>
+		<row><td>AppSearch</td><td/><td>400</td><td>AppSearch</td><td/></row>
+		<row><td>BindImage</td><td/><td>4300</td><td>BindImage</td><td/></row>
+		<row><td>CCPSearch</td><td>CCP_TEST</td><td>500</td><td>CCPSearch</td><td/></row>
+		<row><td>CostFinalize</td><td/><td>1000</td><td>CostFinalize</td><td/></row>
+		<row><td>CostInitialize</td><td/><td>800</td><td>CostInitialize</td><td/></row>
+		<row><td>CreateFolders</td><td/><td>3700</td><td>CreateFolders</td><td/></row>
+		<row><td>CreateShortcuts</td><td/><td>4500</td><td>CreateShortcuts</td><td/></row>
+		<row><td>DeleteServices</td><td>VersionNT</td><td>2000</td><td>DeleteServices</td><td/></row>
+		<row><td>DuplicateFiles</td><td/><td>4210</td><td>DuplicateFiles</td><td/></row>
+		<row><td>FileCost</td><td/><td>900</td><td>FileCost</td><td/></row>
+		<row><td>FindRelatedProducts</td><td>NOT ISSETUPDRIVEN</td><td>420</td><td>FindRelatedProducts</td><td/></row>
+		<row><td>ISSelfRegisterCosting</td><td/><td>2201</td><td/><td/></row>
+		<row><td>ISSelfRegisterFiles</td><td/><td>5601</td><td/><td/></row>
+		<row><td>ISSelfRegisterFinalize</td><td/><td>6601</td><td/><td/></row>
+		<row><td>ISUnSelfRegisterFiles</td><td/><td>2202</td><td/><td/></row>
+		<row><td>InstallFiles</td><td/><td>4000</td><td>InstallFiles</td><td/></row>
+		<row><td>InstallFilter</td><td/><td>4001</td><td/><td/></row>
+		<row><td>InstallFinalize</td><td/><td>6600</td><td>InstallFinalize</td><td/></row>
+		<row><td>InstallInitialize</td><td/><td>1501</td><td>InstallInitialize</td><td/></row>
+		<row><td>InstallODBC</td><td/><td>5400</td><td>InstallODBC</td><td/></row>
+		<row><td>InstallServices</td><td>VersionNT</td><td>5800</td><td>InstallServices</td><td/></row>
+		<row><td>InstallValidate</td><td/><td>1400</td><td>InstallValidate</td><td/></row>
+		<row><td>IsolateComponents</td><td/><td>950</td><td>IsolateComponents</td><td/></row>
+		<row><td>LaunchConditions</td><td>Not Installed</td><td>410</td><td>LaunchConditions</td><td/></row>
+		<row><td>MigrateFeatureStates</td><td/><td>1200</td><td>MigrateFeatureStates</td><td/></row>
+		<row><td>MoveFiles</td><td/><td>3800</td><td>MoveFiles</td><td/></row>
+		<row><td>MsiPublishAssemblies</td><td/><td>6250</td><td>MsiPublishAssemblies</td><td/></row>
+		<row><td>MsiUnpublishAssemblies</td><td/><td>1750</td><td>MsiUnpublishAssemblies</td><td/></row>
+		<row><td>PatchFiles</td><td/><td>4090</td><td>PatchFiles</td><td/></row>
+		<row><td>ProcessComponents</td><td/><td>1600</td><td>ProcessComponents</td><td/></row>
+		<row><td>PublishComponents</td><td/><td>6200</td><td>PublishComponents</td><td/></row>
+		<row><td>PublishFeatures</td><td/><td>6300</td><td>PublishFeatures</td><td/></row>
+		<row><td>PublishProduct</td><td/><td>6400</td><td>PublishProduct</td><td/></row>
+		<row><td>RMCCPSearch</td><td>Not CCP_SUCCESS And CCP_TEST</td><td>600</td><td>RMCCPSearch</td><td/></row>
+		<row><td>RegisterClassInfo</td><td/><td>4600</td><td>RegisterClassInfo</td><td/></row>
+		<row><td>RegisterComPlus</td><td/><td>5700</td><td>RegisterComPlus</td><td/></row>
+		<row><td>RegisterExtensionInfo</td><td/><td>4700</td><td>RegisterExtensionInfo</td><td/></row>
+		<row><td>RegisterFonts</td><td/><td>5300</td><td>RegisterFonts</td><td/></row>
+		<row><td>RegisterMIMEInfo</td><td/><td>4900</td><td>RegisterMIMEInfo</td><td/></row>
+		<row><td>RegisterProduct</td><td/><td>6100</td><td>RegisterProduct</td><td/></row>
+		<row><td>RegisterProgIdInfo</td><td/><td>4800</td><td>RegisterProgIdInfo</td><td/></row>
+		<row><td>RegisterTypeLibraries</td><td/><td>5500</td><td>RegisterTypeLibraries</td><td/></row>
+		<row><td>RegisterUser</td><td/><td>6000</td><td>RegisterUser</td><td/></row>
+		<row><td>RemoveDuplicateFiles</td><td/><td>3400</td><td>RemoveDuplicateFiles</td><td/></row>
+		<row><td>RemoveEnvironmentStrings</td><td/><td>3300</td><td>RemoveEnvironmentStrings</td><td/></row>
+		<row><td>RemoveExistingProducts</td><td/><td>1410</td><td>RemoveExistingProducts</td><td/></row>
+		<row><td>RemoveFiles</td><td/><td>3500</td><td>RemoveFiles</td><td/></row>
+		<row><td>RemoveFolders</td><td/><td>3600</td><td>RemoveFolders</td><td/></row>
+		<row><td>RemoveIniValues</td><td/><td>3100</td><td>RemoveIniValues</td><td/></row>
+		<row><td>RemoveODBC</td><td/><td>2400</td><td>RemoveODBC</td><td/></row>
+		<row><td>RemoveRegistryValues</td><td/><td>2600</td><td>RemoveRegistryValues</td><td/></row>
+		<row><td>RemoveShortcuts</td><td/><td>3200</td><td>RemoveShortcuts</td><td/></row>
+		<row><td>ScheduleReboot</td><td>ISSCHEDULEREBOOT</td><td>6410</td><td>ScheduleReboot</td><td/></row>
+		<row><td>SelfRegModules</td><td/><td>5600</td><td>SelfRegModules</td><td/></row>
+		<row><td>SelfUnregModules</td><td/><td>2200</td><td>SelfUnregModules</td><td/></row>
+		<row><td>SetARPINSTALLLOCATION</td><td>Not Installed</td><td>1010</td><td>SetARPINSTALLLOCATION</td><td/></row>
+		<row><td>SetODBCFolders</td><td/><td>1100</td><td>SetODBCFolders</td><td/></row>
+		<row><td>StartServices</td><td>VersionNT</td><td>5900</td><td>StartServices</td><td/></row>
+		<row><td>StopServices</td><td>VersionNT</td><td>1900</td><td>StopServices</td><td/></row>
+		<row><td>UnpublishComponents</td><td/><td>1700</td><td>UnpublishComponents</td><td/></row>
+		<row><td>UnpublishFeatures</td><td/><td>1800</td><td>UnpublishFeatures</td><td/></row>
+		<row><td>UnregisterClassInfo</td><td/><td>2700</td><td>UnregisterClassInfo</td><td/></row>
+		<row><td>UnregisterComPlus</td><td/><td>2100</td><td>UnregisterComPlus</td><td/></row>
+		<row><td>UnregisterExtensionInfo</td><td/><td>2800</td><td>UnregisterExtensionInfo</td><td/></row>
+		<row><td>UnregisterFonts</td><td/><td>2500</td><td>UnregisterFonts</td><td/></row>
+		<row><td>UnregisterMIMEInfo</td><td/><td>3000</td><td>UnregisterMIMEInfo</td><td/></row>
+		<row><td>UnregisterProgIdInfo</td><td/><td>2900</td><td>UnregisterProgIdInfo</td><td/></row>
+		<row><td>UnregisterTypeLibraries</td><td/><td>2300</td><td>UnregisterTypeLibraries</td><td/></row>
+		<row><td>ValidateProductID</td><td/><td>700</td><td>ValidateProductID</td><td/></row>
+		<row><td>WriteEnvironmentStrings</td><td/><td>5200</td><td>WriteEnvironmentStrings</td><td/></row>
+		<row><td>WriteIniValues</td><td/><td>5100</td><td>WriteIniValues</td><td/></row>
+		<row><td>WriteRegistryValues</td><td/><td>5000</td><td>WriteRegistryValues</td><td/></row>
+		<row><td>caCreateVRoots</td><td/><td>4002</td><td/><td/></row>
+		<row><td>caExtractIISSuppFiles</td><td/><td>1500</td><td/><td/></row>
+		<row><td>caIISCleanup</td><td/><td>6602</td><td/><td/></row>
+		<row><td>caRemoveVRoots</td><td/><td>3503</td><td/><td/></row>
+		<row><td>caRlbackVRoots</td><td/><td>3502</td><td/><td/></row>
+	</table>
+
+	<table name="InstallShield">
+		<col key="yes" def="s72">Property</col>
+		<col def="S0">Value</col>
+		<row><td>ActiveLanguage</td><td>1033</td></row>
+		<row><td>Comments</td><td/></row>
+		<row><td>CurrentMedia</td><td dt:dt="bin.base64" md5="fc57cd997448222cf865e8f31ac4d902">
+QgBpAG4AAQBSAGUAbABlAGEAcwBlAA==
+			</td></row>
+		<row><td>ISCompilerOption_CompileBeforeBuild</td><td>1</td></row>
+		<row><td>ISCompilerOption_Debug</td><td>0</td></row>
+		<row><td>ISCompilerOption_IncludePath</td><td/></row>
+		<row><td>ISCompilerOption_MaxErrors</td><td>50</td></row>
+		<row><td>ISCompilerOption_MaxWarnings</td><td>50</td></row>
+		<row><td>ISCompilerOption_OutputPath</td><td>&lt;ISProjectDataFolder&gt;\Script Files</td></row>
+		<row><td>ISCompilerOption_PreProcessor</td><td/></row>
+		<row><td>ISCompilerOption_WarningLevel</td><td>3</td></row>
+		<row><td>ISCompilerOption_WarningsAsErrors</td><td>1</td></row>
+		<row><td>ISDialogLangID</td><td/></row>
+		<row><td>ISUSLock</td><td>{3872C0E8-6909-4854-B023-A63C791DEF8B}</td></row>
+		<row><td>ISUSSignature</td><td>{33FEE5F9-7895-4F44-87E1-D98785707659}</td></row>
+		<row><td>IsProjectFileText</td><td>1</td></row>
+		<row><td>MsiExecCmdLineOptions</td><td/></row>
+		<row><td>MsiLogFile</td><td/></row>
+		<row><td>OnUpgrade</td><td>1</td></row>
+		<row><td>Owner</td><td>Mladen Turk</td></row>
+		<row><td>PatchFamily</td><td>MyPatchFamily1</td></row>
+		<row><td>PatchSequence</td><td>1.0.0</td></row>
+		<row><td>SaveAsSchema</td><td/></row>
+		<row><td>SccEnabled</td><td>0</td></row>
+		<row><td>SccPath</td><td/></row>
+		<row><td>SchemaVersion</td><td>759</td></row>
+		<row><td>Type</td><td>MSI</td></row>
+	</table>
+
+	<table name="InstallUISequence">
+		<col key="yes" def="s72">Action</col>
+		<col def="S255">Condition</col>
+		<col def="I2">Sequence</col>
+		<col def="S255">ISComments</col>
+		<col def="I4">ISAttributes</col>
+		<row><td>AppSearch</td><td/><td>400</td><td>AppSearch</td><td/></row>
+		<row><td>CCPSearch</td><td>CCP_TEST</td><td>500</td><td>CCPSearch</td><td/></row>
+		<row><td>CostFinalize</td><td/><td>1000</td><td>CostFinalize</td><td/></row>
+		<row><td>CostInitialize</td><td/><td>800</td><td>CostInitialize</td><td/></row>
+		<row><td>ExecuteAction</td><td/><td>1300</td><td>ExecuteAction</td><td/></row>
+		<row><td>FileCost</td><td/><td>900</td><td>FileCost</td><td/></row>
+		<row><td>FindRelatedProducts</td><td/><td>430</td><td>FindRelatedProducts</td><td/></row>
+		<row><td>InstallWelcome</td><td>Not Installed And (Not PATCH Or IS_MAJOR_UPGRADE)</td><td>1210</td><td>InstallWelcome</td><td/></row>
+		<row><td>IsolateComponents</td><td/><td>950</td><td>IsolateComponents</td><td/></row>
+		<row><td>LaunchConditions</td><td>Not Installed</td><td>410</td><td>LaunchConditions</td><td/></row>
+		<row><td>MaintenanceWelcome</td><td>Installed And Not RESUME And Not Preselected And Not PATCH</td><td>1230</td><td>MaintenanceWelcome</td><td/></row>
+		<row><td>MigrateFeatureStates</td><td/><td>1200</td><td>MigrateFeatureStates</td><td/></row>
+		<row><td>PatchWelcome</td><td>PATCH And Not IS_MAJOR_UPGRADE</td><td>1205</td><td>Patch Panel</td><td/></row>
+		<row><td>RMCCPSearch</td><td>Not CCP_SUCCESS And CCP_TEST</td><td>600</td><td>RMCCPSearch</td><td/></row>
+		<row><td>ResolveSource</td><td>Not Installed And Not PATCH</td><td>990</td><td>ResolveSource</td><td/></row>
+		<row><td>SetAllUsersProfileNT</td><td>VersionNT = 400</td><td>970</td><td/><td/></row>
+		<row><td>SetupCompleteError</td><td/><td>-3</td><td>SetupCompleteError</td><td/></row>
+		<row><td>SetupCompleteSuccess</td><td/><td>-1</td><td>SetupCompleteSuccess</td><td/></row>
+		<row><td>SetupInitialization</td><td/><td>420</td><td>SetupInitialization</td><td/></row>
+		<row><td>SetupInterrupted</td><td/><td>-2</td><td>SetupInterrupted</td><td/></row>
+		<row><td>SetupProgress</td><td/><td>1240</td><td>SetupProgress</td><td/></row>
+		<row><td>SetupResume</td><td>Installed And (RESUME Or Preselected) And Not PATCH</td><td>1220</td><td>SetupResume</td><td/></row>
+		<row><td>ValidateProductID</td><td/><td>700</td><td>ValidateProductID</td><td/></row>
+		<row><td>setAllUsersProfile2K</td><td>VersionNT &gt;= 500</td><td>980</td><td/><td/></row>
+		<row><td>setUserProfileNT</td><td>VersionNT</td><td>960</td><td/><td/></row>
+	</table>
+
+	<table name="IsolatedComponent">
+		<col key="yes" def="s72">Component_Shared</col>
+		<col key="yes" def="s72">Component_Application</col>
+	</table>
+
+	<table name="LaunchCondition">
+		<col key="yes" def="s255">Condition</col>
+		<col def="l255">Description</col>
+		<row><td>(Not Version9X)</td><td>##IDPROP_EXPRESS_LAUNCH_CONDITION_OS##</td></row>
+	</table>
+
+	<table name="ListBox">
+		<col key="yes" def="s72">Property</col>
+		<col key="yes" def="i2">Order</col>
+		<col def="s64">Value</col>
+		<col def="L64">Text</col>
+	</table>
+
+	<table name="ListView">
+		<col key="yes" def="s72">Property</col>
+		<col key="yes" def="i2">Order</col>
+		<col def="s64">Value</col>
+		<col def="L64">Text</col>
+		<col def="S72">Binary_</col>
+	</table>
+
+	<table name="LockPermissions">
+		<col key="yes" def="s72">LockObject</col>
+		<col key="yes" def="s32">Table</col>
+		<col key="yes" def="S255">Domain</col>
+		<col key="yes" def="s255">User</col>
+		<col def="I4">Permission</col>
+	</table>
+
+	<table name="MIME">
+		<col key="yes" def="s64">ContentType</col>
+		<col def="s255">Extension_</col>
+		<col def="S38">CLSID</col>
+	</table>
+
+	<table name="Media">
+		<col key="yes" def="i2">DiskId</col>
+		<col def="i2">LastSequence</col>
+		<col def="L64">DiskPrompt</col>
+		<col def="S255">Cabinet</col>
+		<col def="S32">VolumeLabel</col>
+		<col def="S32">Source</col>
+	</table>
+
+	<table name="MoveFile">
+		<col key="yes" def="s72">FileKey</col>
+		<col def="s72">Component_</col>
+		<col def="L255">SourceName</col>
+		<col def="L255">DestName</col>
+		<col def="S72">SourceFolder</col>
+		<col def="s72">DestFolder</col>
+		<col def="i2">Options</col>
+	</table>
+
+	<table name="MsiAssembly">
+		<col key="yes" def="s72">Component_</col>
+		<col def="s38">Feature_</col>
+		<col def="S72">File_Manifest</col>
+		<col def="S72">File_Application</col>
+		<col def="I2">Attributes</col>
+	</table>
+
+	<table name="MsiAssemblyName">
+		<col key="yes" def="s72">Component_</col>
+		<col key="yes" def="s255">Name</col>
+		<col def="s255">Value</col>
+	</table>
+
+	<table name="MsiDigitalCertificate">
+		<col key="yes" def="s72">DigitalCertificate</col>
+		<col def="v0">CertData</col>
+	</table>
+
+	<table name="MsiDigitalSignature">
+		<col key="yes" def="s32">Table</col>
+		<col key="yes" def="s72">SignObject</col>
+		<col def="s72">DigitalCertificate_</col>
+		<col def="V0">Hash</col>
+	</table>
+
+	<table name="MsiDriverPackages">
+		<col key="yes" def="s72">Component</col>
+		<col def="i4">Flags</col>
+		<col def="I4">Sequence</col>
+		<col def="S0">ReferenceComponents</col>
+	</table>
+
+	<table name="MsiFileHash">
+		<col key="yes" def="s72">File_</col>
+		<col def="i2">Options</col>
+		<col def="i4">HashPart1</col>
+		<col def="i4">HashPart2</col>
+		<col def="i4">HashPart3</col>
+		<col def="i4">HashPart4</col>
+	</table>
+
+	<table name="MsiPatchCertificate">
+		<col key="yes" def="S72">PatchCertificate</col>
+		<col def="s72">DigitalCertificate_</col>
+	</table>
+
+	<table name="MsiPatchMetadata">
+		<col key="yes" def="s72">PatchConfiguration_</col>
+		<col key="yes" def="S72">Company</col>
+		<col key="yes" def="s72">Property</col>
+		<col def="S0">Value</col>
+	</table>
+
+	<table name="MsiPatchOldAssemblyFile">
+		<col key="yes" def="s72">File_</col>
+		<col key="yes" def="S72">Assembly_</col>
+	</table>
+
+	<table name="MsiPatchOldAssemblyName">
+		<col key="yes" def="s72">Assembly_</col>
+		<col key="yes" def="s255">Name</col>
+		<col def="S255">Value</col>
+	</table>
+
+	<table name="MsiPatchSequence">
+		<col key="yes" def="s72">PatchConfiguration_</col>
+		<col key="yes" def="s0">PatchFamily</col>
+		<col key="yes" def="S0">Target</col>
+		<col def="s0">Sequence</col>
+		<col def="i2">Supersede</col>
+	</table>
+
+	<table name="ODBCAttribute">
+		<col key="yes" def="s72">Driver_</col>
+		<col key="yes" def="s40">Attribute</col>
+		<col def="S255">Value</col>
+	</table>
+
+	<table name="ODBCDataSource">
+		<col key="yes" def="s72">DataSource</col>
+		<col def="s72">Component_</col>
+		<col def="s255">Description</col>
+		<col def="s255">DriverDescription</col>
+		<col def="i2">Registration</col>
+	</table>
+
+	<table name="ODBCDriver">
+		<col key="yes" def="s72">Driver</col>
+		<col def="s72">Component_</col>
+		<col def="s255">Description</col>
+		<col def="s72">File_</col>
+		<col def="S72">File_Setup</col>
+	</table>
+
+	<table name="ODBCSourceAttribute">
+		<col key="yes" def="s72">DataSource_</col>
+		<col key="yes" def="s32">Attribute</col>
+		<col def="S255">Value</col>
+	</table>
+
+	<table name="ODBCTranslator">
+		<col key="yes" def="s72">Translator</col>
+		<col def="s72">Component_</col>
+		<col def="s255">Description</col>
+		<col def="s72">File_</col>
+		<col def="S72">File_Setup</col>
+	</table>
+
+	<table name="Patch">
+		<col key="yes" def="s72">File_</col>
+		<col key="yes" def="i2">Sequence</col>
+		<col def="i4">PatchSize</col>
+		<col def="i2">Attributes</col>
+		<col def="V0">Header</col>
+		<col def="S255">ISBuildSourcePath</col>
+	</table>
+
+	<table name="PatchPackage">
+		<col key="yes" def="s38">PatchId</col>
+		<col def="i2">Media_</col>
+	</table>
+
+	<table name="ProgId">
+		<col key="yes" def="s255">ProgId</col>
+		<col def="S255">ProgId_Parent</col>
+		<col def="S38">Class_</col>
+		<col def="L255">Description</col>
+		<col def="S72">Icon_</col>
+		<col def="I2">IconIndex</col>
+		<col def="I4">ISAttributes</col>
+	</table>
+
+	<table name="Property">
+		<col key="yes" def="s72">Property</col>
+		<col def="L0">Value</col>
+		<col def="S255">ISComments</col>
+		<row><td>ARPPRODUCTICON</td><td>ARPPRODUCTICON.exe</td><td/></row>
+		<row><td>ARPURLINFOABOUT</td><td>##ID_STRING1##</td><td/></row>
+		<row><td>AgreeToLicense</td><td>No</td><td/></row>
+		<row><td>ApplicationUsers</td><td>AllUsers</td><td/></row>
+		<row><td>DWUSINTERVAL</td><td>30</td><td/></row>
+		<row><td>DWUSLINK</td><td>CEAC2798B9CCC7BFDEAC879F5E6C978F29BC978F69DCE0AFCEFC673F895C57EF898B905F79AC</td><td/></row>
+		<row><td>DefaultUIFont</td><td>Tahoma8</td><td/></row>
+		<row><td>DialogCaption</td><td>InstallShield for Windows Installer</td><td/></row>
+		<row><td>DiskPrompt</td><td>[1]</td><td/></row>
+		<row><td>DisplayNameCustom</td><td>##IDS__DisplayName_Custom##</td><td/></row>
+		<row><td>DisplayNameMinimal</td><td>##IDS__DisplayName_Minimal##</td><td/></row>
+		<row><td>DisplayNameTypical</td><td>##IDS__DisplayName_Typical##</td><td/></row>
+		<row><td>Display_IsBitmapDlg</td><td>1</td><td/></row>
+		<row><td>ErrorDialog</td><td>SetupError</td><td/></row>
+		<row><td>INSTALLLEVEL</td><td>100</td><td/></row>
+		<row><td>ISCHECKFORPRODUCTUPDATES</td><td>1</td><td/></row>
+		<row><td>ISENABLEDWUSFINISHDIALOG</td><td/><td/></row>
+		<row><td>ISVROOT_PORT_NO</td><td>0</td><td/></row>
+		<row><td>IS_COMPLUS_PROGRESSTEXT_COST</td><td>##IDS_COMPLUS_PROGRESSTEXT_COST##</td><td/></row>
+		<row><td>IS_COMPLUS_PROGRESSTEXT_INSTALL</td><td>##IDS_COMPLUS_PROGRESSTEXT_INSTALL##</td><td/></row>
+		<row><td>IS_COMPLUS_PROGRESSTEXT_UNINSTALL</td><td>##IDS_COMPLUS_PROGRESSTEXT_UNINSTALL##</td><td/></row>
+		<row><td>IS_PROGMSG_XML_COSTING</td><td>##IDS_PROGMSG_XML_COSTING##</td><td/></row>
+		<row><td>IS_PROGMSG_XML_CREATE_FILE</td><td>##IDS_PROGMSG_XML_CREATE_FILE##</td><td/></row>
+		<row><td>IS_PROGMSG_XML_FILES</td><td>##IDS_PROGMSG_XML_FILES##</td><td/></row>
+		<row><td>IS_PROGMSG_XML_REMOVE_FILE</td><td>##IDS_PROGMSG_XML_REMOVE_FILE##</td><td/></row>
+		<row><td>IS_PROGMSG_XML_ROLLBACK_FILES</td><td>##IDS_PROGMSG_XML_ROLLBACK_FILES##</td><td/></row>
+		<row><td>IS_PROGMSG_XML_UPDATE_FILE</td><td>##IDS_PROGMSG_XML_UPDATE_FILE##</td><td/></row>
+		<row><td>IS_SQLSERVER_AUTHENTICATION</td><td>0</td><td/></row>
+		<row><td>IS_SQLSERVER_DATABASE</td><td/><td/></row>
+		<row><td>IS_SQLSERVER_PASSWORD</td><td/><td/></row>
+		<row><td>IS_SQLSERVER_SERVER</td><td/><td/></row>
+		<row><td>IS_SQLSERVER_USERNAME</td><td>sa</td><td/></row>
+		<row><td>InstallChoice</td><td>AR</td><td/></row>
+		<row><td>Manufacturer</td><td>##COMPANY_NAME##</td><td/></row>
+		<row><td>PIDTemplate</td><td>12345&lt;###-%%%%%%%&gt;@@@@@</td><td/></row>
+		<row><td>PROGMSG_IIS_CREATEVROOT</td><td>##IDS_PROGMSG_IIS_CREATEVROOT##</td><td/></row>
+		<row><td>PROGMSG_IIS_CREATEVROOTS</td><td>##IDS_PROGMSG_IIS_CREATEVROOTS##</td><td/></row>
+		<row><td>PROGMSG_IIS_EXTRACT</td><td>##IDS_PROGMSG_IIS_EXTRACT##</td><td/></row>
+		<row><td>PROGMSG_IIS_EXTRACTDONE</td><td>##IDS_PROGMSG_IIS_EXTRACTDONE##</td><td/></row>
+		<row><td>PROGMSG_IIS_REMOVESITE</td><td>##IDS_PROGMSG_IIS_REMOVESITE##</td><td/></row>
+		<row><td>PROGMSG_IIS_REMOVEVROOT</td><td>##IDS_PROGMSG_IIS_REMOVEVROOT##</td><td/></row>
+		<row><td>PROGMSG_IIS_REMOVEVROOTS</td><td>##IDS_PROGMSG_IIS_REMOVEVROOTS##</td><td/></row>
+		<row><td>PROGMSG_IIS_ROLLBACKVROOTS</td><td>##IDS_PROGMSG_IIS_ROLLBACKVROOTS##</td><td/></row>
+		<row><td>ProductCode</td><td>{8B799ADD-7E5C-41B9-936B-942F3CAE42A0}</td><td/></row>
+		<row><td>ProductID</td><td>none</td><td/></row>
+		<row><td>ProductLanguage</td><td>1033</td><td/></row>
+		<row><td>ProductName</td><td>Jakarta Isapi Redirector</td><td/></row>
+		<row><td>ProductVersion</td><td>1.2.19</td><td/></row>
+		<row><td>ProgressType0</td><td>install</td><td/></row>
+		<row><td>ProgressType1</td><td>Installing</td><td/></row>
+		<row><td>ProgressType2</td><td>installed</td><td/></row>
+		<row><td>ProgressType3</td><td>installs</td><td/></row>
+		<row><td>RebootYesNo</td><td>Yes</td><td/></row>
+		<row><td>ReinstallModeText</td><td>omus</td><td/></row>
+		<row><td>SHOWLAUNCHPROGRAM</td><td>0</td><td/></row>
+		<row><td>SetupType</td><td>Typical</td><td/></row>
+		<row><td>UpgradeCode</td><td>{0BE8FA4C-503F-4209-A3DA-79B605E542E0}</td><td/></row>
+		<row><td>_IsMaintenance</td><td>Change</td><td/></row>
+		<row><td>_IsSetupTypeMin</td><td>Typical</td><td/></row>
+	</table>
+
+	<table name="PublishComponent">
+		<col key="yes" def="s38">ComponentId</col>
+		<col key="yes" def="s255">Qualifier</col>
+		<col key="yes" def="s72">Component_</col>
+		<col def="L255">AppData</col>
+		<col def="s38">Feature_</col>
+	</table>
+
+	<table name="RadioButton">
+		<col key="yes" def="s72">Property</col>
+		<col key="yes" def="i2">Order</col>
+		<col def="s64">Value</col>
+		<col def="i2">X</col>
+		<col def="i2">Y</col>
+		<col def="i2">Width</col>
+		<col def="i2">Height</col>
+		<col def="L64">Text</col>
+		<col def="L50">Help</col>
+		<col def="I4">ISControlId</col>
+		<row><td>AgreeToLicense</td><td>1</td><td>No</td><td>0</td><td>15</td><td>291</td><td>15</td><td>##IDS__AgreeToLicense_0##</td><td/><td/></row>
+		<row><td>AgreeToLicense</td><td>2</td><td>Yes</td><td>0</td><td>0</td><td>291</td><td>15</td><td>##IDS__AgreeToLicense_1##</td><td/><td/></row>
+		<row><td>ApplicationUsers</td><td>1</td><td>AllUsers</td><td>1</td><td>7</td><td>290</td><td>14</td><td>##IDS__IsRegisterUserDlg_Anyone##</td><td/><td/></row>
+		<row><td>ApplicationUsers</td><td>2</td><td>OnlyCurrentUser</td><td>1</td><td>23</td><td>290</td><td>14</td><td>##IDS__IsRegisterUserDlg_OnlyMe##</td><td/><td/></row>
+		<row><td>IS_SQLSERVER_AUTHENTICATION</td><td>1</td><td>0</td><td>0</td><td>0</td><td>327</td><td>14</td><td>##IDS_SQLLOGIN_WIN##</td><td/><td>0</td></row>
+		<row><td>IS_SQLSERVER_AUTHENTICATION</td><td>2</td><td>1</td><td>0</td><td>14</td><td>327</td><td>19</td><td>##IDS_SQLLOGIN_SQL##</td><td/><td>0</td></row>
+		<row><td>_IsMaintenance</td><td>1</td><td>Change</td><td>0</td><td>0</td><td>290</td><td>14</td><td>##IDS__IsMaintenanceDlg_Modify##</td><td/><td/></row>
+		<row><td>_IsMaintenance</td><td>2</td><td>Reinstall</td><td>0</td><td>60</td><td>290</td><td>14</td><td>##IDS__IsMaintenanceDlg_Repair##</td><td/><td/></row>
+		<row><td>_IsMaintenance</td><td>3</td><td>Remove</td><td>0</td><td>120</td><td>290</td><td>14</td><td>##IDS__IsMaintenanceDlg_Remove##</td><td/><td/></row>
+		<row><td>_IsSetupTypeMin</td><td>1</td><td>Typical</td><td>0</td><td>0</td><td>264</td><td>14</td><td>##IDS__IsSetupTypeMinDlg_Complete##</td><td/><td/></row>
+		<row><td>_IsSetupTypeMin</td><td>2</td><td>Custom</td><td>0</td><td>60</td><td>264</td><td>14</td><td>##IDS__IsSetupTypeMinDlg_Custom##</td><td/><td/></row>
+	</table>
+
+	<table name="RegLocator">
+		<col key="yes" def="s72">Signature_</col>
+		<col def="i2">Root</col>
+		<col def="s255">Key</col>
+		<col def="S255">Name</col>
+		<col def="I2">Type</col>
+		<row><td>_IISROOTFOLDER</td><td>2</td><td>Software\Microsoft\InetStp</td><td>PathWWWRoot</td><td>0</td></row>
+		<row><td>_IIS_VERSION</td><td>2</td><td>SYSTEM\CurrentControlSet\Services\W3SVC\Parameters</td><td>MajorVersion</td><td>2</td></row>
+	</table>
+
+	<table name="Registry">
+		<col key="yes" def="s72">Registry</col>
+		<col def="i2">Root</col>
+		<col def="s255">Key</col>
+		<col def="S255">Name</col>
+		<col def="S0">Value</col>
+		<col def="s72">Component_</col>
+		<col def="I4">ISAttributes</col>
+		<row><td>Registry10</td><td>2</td><td>SOFTWARE\Apache Software Foundation</td><td/><td/><td>ISRegistryComponent1</td><td>0</td></row>
+		<row><td>Registry11</td><td>2</td><td>SOFTWARE\Apache Software Foundation\Jakarta Isapi Redirector</td><td/><td/><td>ISRegistryComponent1</td><td>0</td></row>
+		<row><td>Registry12</td><td>2</td><td>SOFTWARE\Apache Software Foundation\Jakarta Isapi Redirector\1.0</td><td/><td/><td>ISRegistryComponent1</td><td>0</td></row>
+		<row><td>Registry13</td><td>2</td><td>SOFTWARE\Apache Software Foundation\Jakarta Isapi Redirector\1.0</td><td>extension_uri</td><td>/jakarta/isapi_redirect.dll</td><td>ISRegistryComponent1</td><td>0</td></row>
+		<row><td>Registry14</td><td>2</td><td>SOFTWARE\Apache Software Foundation\Jakarta Isapi Redirector\1.0</td><td>log_file</td><td>[INSTALLDIR]log\isapi_redirect.log</td><td>ISRegistryComponent1</td><td>0</td></row>
+		<row><td>Registry15</td><td>2</td><td>SOFTWARE\Apache Software Foundation\Jakarta Isapi Redirector\1.0</td><td>log_level</td><td>info</td><td>ISRegistryComponent1</td><td>0</td></row>
+		<row><td>Registry16</td><td>2</td><td>SOFTWARE\Apache Software Foundation\Jakarta Isapi Redirector\1.0</td><td>worker_file</td><td>[INSTALLDIR]conf\workers.properties.minimal</td><td>ISRegistryComponent1</td><td>0</td></row>
+		<row><td>Registry17</td><td>2</td><td>SOFTWARE\Apache Software Foundation\Jakarta Isapi Redirector\1.0</td><td>worker_mount_file</td><td>[INSTALLDIR]conf\uriworkermap.properties</td><td>ISRegistryComponent1</td><td>0</td></row>
+	</table>
+
+	<table name="RemoveFile">
+		<col key="yes" def="s72">FileKey</col>
+		<col def="s72">Component_</col>
+		<col def="L255">FileName</col>
+		<col def="s72">DirProperty</col>
+		<col def="i2">InstallMode</col>
+	</table>
+
+	<table name="RemoveIniFile">
+		<col key="yes" def="s72">RemoveIniFile</col>
+		<col def="l255">FileName</col>
+		<col def="S72">DirProperty</col>
+		<col def="l96">Section</col>
+		<col def="l128">Key</col>
+		<col def="L255">Value</col>
+		<col def="i2">Action</col>
+		<col def="s72">Component_</col>
+	</table>
+
+	<table name="RemoveRegistry">
+		<col key="yes" def="s72">RemoveRegistry</col>
+		<col def="i2">Root</col>
+		<col def="l255">Key</col>
+		<col def="L255">Name</col>
+		<col def="s72">Component_</col>
+	</table>
+
+	<table name="ReserveCost">
+		<col key="yes" def="s72">ReserveKey</col>
+		<col def="s72">Component_</col>
+		<col def="S72">ReserveFolder</col>
+		<col def="i4">ReserveLocal</col>
+		<col def="i4">ReserveSource</col>
+	</table>
+
+	<table name="SFPCatalog">
+		<col key="yes" def="s255">SFPCatalog</col>
+		<col def="V0">Catalog</col>
+		<col def="S0">Dependency</col>
+	</table>
+
+	<table name="SelfReg">
+		<col key="yes" def="s72">File_</col>
+		<col def="I2">Cost</col>
+	</table>
+
+	<table name="ServiceControl">
+		<col key="yes" def="s72">ServiceControl</col>
+		<col def="s255">Name</col>
+		<col def="i2">Event</col>
+		<col def="S255">Arguments</col>
+		<col def="I2">Wait</col>
+		<col def="s72">Component_</col>
+	</table>
+
+	<table name="ServiceInstall">
+		<col key="yes" def="s72">ServiceInstall</col>
+		<col def="s255">Name</col>
+		<col def="L255">DisplayName</col>
+		<col def="i4">ServiceType</col>
+		<col def="i4">StartType</col>
+		<col def="i4">ErrorControl</col>
+		<col def="S255">LoadOrderGroup</col>
+		<col def="S255">Dependencies</col>
+		<col def="S255">StartName</col>
+		<col def="S255">Password</col>
+		<col def="S255">Arguments</col>
+		<col def="s72">Component_</col>
+		<col def="L255">Description</col>
+	</table>
+
+	<table name="Shortcut">
+		<col key="yes" def="s72">Shortcut</col>
+		<col def="s72">Directory_</col>
+		<col def="l128">Name</col>
+		<col def="s72">Component_</col>
+		<col def="s255">Target</col>
+		<col def="S255">Arguments</col>
+		<col def="L255">Description</col>
+		<col def="I2">Hotkey</col>
+		<col def="S72">Icon_</col>
+		<col def="I2">IconIndex</col>
+		<col def="I2">ShowCmd</col>
+		<col def="S72">WkDir</col>
+		<col def="S255">ISComments</col>
+		<col def="S255">ISShortcutName</col>
+		<col def="I4">ISAttributes</col>
+	</table>
+
+	<table name="Signature">
+		<col key="yes" def="s72">Signature</col>
+		<col def="s255">FileName</col>
+		<col def="S20">MinVersion</col>
+		<col def="S20">MaxVersion</col>
+		<col def="I4">MinSize</col>
+		<col def="I4">MaxSize</col>
+		<col def="I4">MinDate</col>
+		<col def="I4">MaxDate</col>
+		<col def="S255">Languages</col>
+	</table>
+
+	<table name="TextStyle">
+		<col key="yes" def="s72">TextStyle</col>
+		<col def="s32">FaceName</col>
+		<col def="i2">Size</col>
+		<col def="I4">Color</col>
+		<col def="I2">StyleBits</col>
+		<row><td>Arial8</td><td>Arial</td><td>8</td><td/><td/></row>
+		<row><td>Arial9</td><td>Arial</td><td>9</td><td/><td/></row>
+		<row><td>ArialBlue10</td><td>Arial</td><td>10</td><td>16711680</td><td/></row>
+		<row><td>ArialBlueStrike10</td><td>Arial</td><td>10</td><td>16711680</td><td>8</td></row>
+		<row><td>CourierNew8</td><td>Courier New</td><td>8</td><td/><td/></row>
+		<row><td>CourierNew9</td><td>Courier New</td><td>9</td><td/><td/></row>
+		<row><td>MSGothic9</td><td>MS Gothic</td><td>9</td><td/><td/></row>
+		<row><td>MSSGreySerif8</td><td>MS Sans Serif</td><td>8</td><td>8421504</td><td/></row>
+		<row><td>MSSWhiteSerif8</td><td>Tahoma</td><td>8</td><td>16777215</td><td/></row>
+		<row><td>MSSansBold8</td><td>Tahoma</td><td>8</td><td/><td>1</td></row>
+		<row><td>MSSansSerif8</td><td>MS Sans Serif</td><td>8</td><td/><td/></row>
+		<row><td>MSSansSerif9</td><td>MS Sans Serif</td><td>9</td><td/><td/></row>
+		<row><td>Tahoma10</td><td>Tahoma</td><td>10</td><td/><td/></row>
+		<row><td>Tahoma8</td><td>Tahoma</td><td>8</td><td/><td/></row>
+		<row><td>Tahoma9</td><td>Tahoma</td><td>9</td><td/><td/></row>
+		<row><td>TahomaBold10</td><td>Tahoma</td><td>10</td><td/><td>1</td></row>
+		<row><td>TahomaBold8</td><td>Tahoma</td><td>8</td><td/><td>1</td></row>
+		<row><td>Times8</td><td>Times New Roman</td><td>8</td><td/><td/></row>
+		<row><td>Times9</td><td>Times New Roman</td><td>9</td><td/><td/></row>
+		<row><td>TimesItalic12</td><td>Times New Roman</td><td>12</td><td/><td>2</td></row>
+		<row><td>TimesItalicBlue10</td><td>Times New Roman</td><td>10</td><td>16711680</td><td>2</td></row>
+		<row><td>TimesRed16</td><td>Times New Roman</td><td>16</td><td>255</td><td/></row>
+	</table>
+
+	<table name="TypeLib">
+		<col key="yes" def="s38">LibID</col>
+		<col key="yes" def="i2">Language</col>
+		<col key="yes" def="s72">Component_</col>
+		<col def="I4">Version</col>
+		<col def="L128">Description</col>
+		<col def="S72">Directory_</col>
+		<col def="s38">Feature_</col>
+		<col def="I4">Cost</col>
+	</table>
+
+	<table name="UIText">
+		<col key="yes" def="s72">Key</col>
+		<col def="L255">Text</col>
+		<row><td>AbsentPath</td><td/></row>
+		<row><td>GB</td><td>##IDS_UITEXT_GB##</td></row>
+		<row><td>KB</td><td>##IDS_UITEXT_KB##</td></row>
+		<row><td>MB</td><td>##IDS_UITEXT_MB##</td></row>
+		<row><td>MenuAbsent</td><td>##IDS_UITEXT_FeatureNotAvailable##</td></row>
+		<row><td>MenuAdvertise</td><td>##IDS_UITEXT_FeatureInstalledWhenRequired2##</td></row>
+		<row><td>MenuAllCD</td><td>##IDS_UITEXT_FeatureInstalledCD##</td></row>
+		<row><td>MenuAllLocal</td><td>##IDS_UITEXT_FeatureInstalledLocal##</td></row>
+		<row><td>MenuAllNetwork</td><td>##IDS_UITEXT_FeatureInstalledNetwork##</td></row>
+		<row><td>MenuCD</td><td>##IDS_UITEXT_FeatureInstalledCD2##</td></row>
+		<row><td>MenuLocal</td><td>##IDS_UITEXT_FeatureInstalledLocal2##</td></row>
+		<row><td>MenuNetwork</td><td>##IDS_UITEXT_FeatureInstalledNetwork2##</td></row>
+		<row><td>NewFolder</td><td>##IDS_UITEXT_Folder##</td></row>
+		<row><td>SelAbsentAbsent</td><td>##IDS_UITEXT_GB##</td></row>
+		<row><td>SelAbsentAdvertise</td><td>##IDS_UITEXT_FeatureInstalledWhenRequired##</td></row>
+		<row><td>SelAbsentCD</td><td>##IDS_UITEXT_FeatureOnCD##</td></row>
+		<row><td>SelAbsentLocal</td><td>##IDS_UITEXT_FeatureLocal##</td></row>
+		<row><td>SelAbsentNetwork</td><td>##IDS_UITEXT_FeatureNetwork##</td></row>
+		<row><td>SelAdvertiseAbsent</td><td>##IDS_UITEXT_FeatureUnavailable##</td></row>
+		<row><td>SelAdvertiseAdvertise</td><td>##IDS_UITEXT_FeatureInstalledRequired##</td></row>
+		<row><td>SelAdvertiseCD</td><td>##IDS_UITEXT_FeatureOnCD2##</td></row>
+		<row><td>SelAdvertiseLocal</td><td>##IDS_UITEXT_FeatureLocal2##</td></row>
+		<row><td>SelAdvertiseNetwork</td><td>##IDS_UITEXT_FeatureNetwork2##</td></row>
+		<row><td>SelCDAbsent</td><td>##IDS_UITEXT_FeatureWillBeUninstalled##</td></row>
+		<row><td>SelCDAdvertise</td><td>##IDS_UITEXT_FeatureWasCD##</td></row>
+		<row><td>SelCDCD</td><td>##IDS_UITEXT_FeatureRunFromCD##</td></row>
+		<row><td>SelCDLocal</td><td>##IDS_UITEXT_FeatureWasCDLocal##</td></row>
+		<row><td>SelChildCostNeg</td><td>##IDS_UITEXT_FeatureFreeSpace##</td></row>
+		<row><td>SelChildCostPos</td><td>##IDS_UITEXT_FeatureRequiredSpace##</td></row>
+		<row><td>SelCostPending</td><td>##IDS_UITEXT_CompilingFeaturesCost##</td></row>
+		<row><td>SelLocalAbsent</td><td>##IDS_UITEXT_FeatureCompletelyRemoved##</td></row>
+		<row><td>SelLocalAdvertise</td><td>##IDS_UITEXT_FeatureRemovedUnlessRequired##</td></row>
+		<row><td>SelLocalCD</td><td>##IDS_UITEXT_FeatureRemovedCD##</td></row>
+		<row><td>SelLocalLocal</td><td>##IDS_UITEXT_FeatureRemainLocal##</td></row>
+		<row><td>SelLocalNetwork</td><td>##IDS_UITEXT_FeatureRemoveNetwork##</td></row>
+		<row><td>SelNetworkAbsent</td><td>##IDS_UITEXT_FeatureUninstallNoNetwork##</td></row>
+		<row><td>SelNetworkAdvertise</td><td>##IDS_UITEXT_FeatureWasOnNetworkInstalled##</td></row>
+		<row><td>SelNetworkLocal</td><td>##IDS_UITEXT_FeatureWasOnNetworkLocal##</td></row>
+		<row><td>SelNetworkNetwork</td><td>##IDS_UITEXT_FeatureContinueNetwork##</td></row>
+		<row><td>SelParentCostNegNeg</td><td>##IDS_UITEXT_FeatureSpaceFree##</td></row>
+		<row><td>SelParentCostNegPos</td><td>##IDS_UITEXT_FeatureSpaceFree2##</td></row>
+		<row><td>SelParentCostPosNeg</td><td>##IDS_UITEXT_FeatureSpaceFree3##</td></row>
+		<row><td>SelParentCostPosPos</td><td>##IDS_UITEXT_FeatureSpaceFree4##</td></row>
+		<row><td>TimeRemaining</td><td>##IDS_UITEXT_TimeRemaining##</td></row>
+		<row><td>VolumeCostAvailable</td><td>##IDS_UITEXT_Available##</td></row>
+		<row><td>VolumeCostDifference</td><td>##IDS_UITEXT_Differences##</td></row>
+		<row><td>VolumeCostRequired</td><td>##IDS_UITEXT_Required##</td></row>
+		<row><td>VolumeCostSize</td><td>##IDS_UITEXT_DiskSize##</td></row>
+		<row><td>VolumeCostVolume</td><td>##IDS_UITEXT_Volume##</td></row>
+		<row><td>bytes</td><td>##IDS_UITEXT_Bytes##</td></row>
+	</table>
+
+	<table name="Upgrade">
+		<col key="yes" def="s38">UpgradeCode</col>
+		<col key="yes" def="S20">VersionMin</col>
+		<col key="yes" def="S20">VersionMax</col>
+		<col key="yes" def="S255">Language</col>
+		<col key="yes" def="i4">Attributes</col>
+		<col def="S255">Remove</col>
+		<col def="s72">ActionProperty</col>
+		<col def="S72">ISDisplayName</col>
+	</table>
+
+	<table name="Verb">
+		<col key="yes" def="s255">Extension_</col>
+		<col key="yes" def="s32">Verb</col>
+		<col def="I2">Sequence</col>
+		<col def="L255">Command</col>
+		<col def="L255">Argument</col>
+	</table>
+
+	<table name="_Validation">
+		<col key="yes" def="s32">Table</col>
+		<col key="yes" def="s32">Column</col>
+		<col def="s4">Nullable</col>
+		<col def="I4">MinValue</col>
+		<col def="I4">MaxValue</col>
+		<col def="S255">KeyTable</col>
+		<col def="I2">KeyColumn</col>
+		<col def="S32">Category</col>
+		<col def="S255">Set</col>
+		<col def="S255">Description</col>
+		<row><td>ActionText</td><td>Action</td><td>N</td><td/><td/><td/><td/><td>Identifier</td><td/><td>Name of action to be described.</td></row>
+		<row><td>ActionText</td><td>Description</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>Localized description displayed in progress dialog and log when action is executing.</td></row>
+		<row><td>ActionText</td><td>Template</td><td>Y</td><td/><td/><td/><td/><td>Template</td><td/><td>Optional localized format template used to format action data records for display during action execution.</td></row>
+		<row><td>AdminExecuteSequence</td><td>Action</td><td>N</td><td/><td/><td/><td/><td>Identifier</td><td/><td>Name of action to invoke, either in the engine or the handler DLL.</td></row>
+		<row><td>AdminExecuteSequence</td><td>Condition</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>Optional expression which skips the action if evaluates to expFalse.If the expression syntax is invalid, the engine will terminate, returning iesBadActionData.</td></row>
+		<row><td>AdminExecuteSequence</td><td>ISAttributes</td><td>Y</td><td/><td/><td/><td/><td/><td/><td>This is used to store MM Custom Action Types</td></row>
+		<row><td>AdminExecuteSequence</td><td>ISComments</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td dt:dt="bin.base64" md5="ee654261ffce9c7f08d4789d0f5b202c">
+QQB1AHQAaABvAHIAGSBzACAAYwBvAG0AbQBlAG4AdABzACAAbwBuACAAdABoAGkAcwAgAFMAZQBxAHUAZQBuAGMAZQAuAA==
+			</td></row>
+		<row><td>AdminExecuteSequence</td><td>Sequence</td><td>Y</td><td>-4</td><td>32767</td><td/><td/><td/><td/><td>Number that determines the sort order in which the actions are to be executed.  Leave blank to suppress action.</td></row>
+		<row><td>AdminUISequence</td><td>Action</td><td>N</td><td/><td/><td/><td/><td>Identifier</td><td/><td>Name of action to invoke, either in the engine or the handler DLL.</td></row>
+		<row><td>AdminUISequence</td><td>Condition</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>Optional expression which skips the action if evaluates to expFalse.If the expression syntax is invalid, the engine will terminate, returning iesBadActionData.</td></row>
+		<row><td>AdminUISequence</td><td>ISAttributes</td><td>Y</td><td/><td/><td/><td/><td/><td/><td>This is used to store MM Custom Action Types</td></row>
+		<row><td>AdminUISequence</td><td>ISComments</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td dt:dt="bin.base64" md5="ee654261ffce9c7f08d4789d0f5b202c">
+QQB1AHQAaABvAHIAGSBzACAAYwBvAG0AbQBlAG4AdABzACAAbwBuACAAdABoAGkAcwAgAFMAZQBxAHUAZQBuAGMAZQAuAA==
+			</td></row>
+		<row><td>AdminUISequence</td><td>Sequence</td><td>Y</td><td>-4</td><td>32767</td><td/><td/><td/><td/><td>Number that determines the sort order in which the actions are to be executed.  Leave blank to suppress action.</td></row>
+		<row><td>AdvtExecuteSequence</td><td>Action</td><td>N</td><td/><td/><td/><td/><td>Identifier</td><td/><td>Name of action to invoke, either in the engine or the handler DLL.</td></row>
+		<row><td>AdvtExecuteSequence</td><td>Condition</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>Optional expression which skips the action if evaluates to expFalse.If the expression syntax is invalid, the engine will terminate, returning iesBadActionData.</td></row>
+		<row><td>AdvtExecuteSequence</td><td>ISAttributes</td><td>Y</td><td/><td/><td/><td/><td/><td/><td>This is used to store MM Custom Action Types</td></row>
+		<row><td>AdvtExecuteSequence</td><td>ISComments</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td dt:dt="bin.base64" md5="ee654261ffce9c7f08d4789d0f5b202c">
+QQB1AHQAaABvAHIAGSBzACAAYwBvAG0AbQBlAG4AdABzACAAbwBuACAAdABoAGkAcwAgAFMAZQBxAHUAZQBuAGMAZQAuAA==
+			</td></row>
+		<row><td>AdvtExecuteSequence</td><td>Sequence</td><td>Y</td><td>-4</td><td>32767</td><td/><td/><td/><td/><td>Number that determines the sort order in which the actions are to be executed.  Leave blank to suppress action.</td></row>
+		<row><td>AdvtUISequence</td><td>Action</td><td>N</td><td/><td/><td/><td/><td>Identifier</td><td/><td>Name of action to invoke, either in the engine or the handler DLL.</td></row>
+		<row><td>AdvtUISequence</td><td>Condition</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>Optional expression which skips the action if evaluates to expFalse.If the expression syntax is invalid, the engine will terminate, returning iesBadActionData.</td></row>
+		<row><td>AdvtUISequence</td><td>ISAttributes</td><td>Y</td><td/><td/><td/><td/><td/><td/><td>This is used to store MM Custom Action Types</td></row>
+		<row><td>AdvtUISequence</td><td>ISComments</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td dt:dt="bin.base64" md5="ee654261ffce9c7f08d4789d0f5b202c">
+QQB1AHQAaABvAHIAGSBzACAAYwBvAG0AbQBlAG4AdABzACAAbwBuACAAdABoAGkAcwAgAFMAZQBxAHUAZQBuAGMAZQAuAA==
+			</td></row>
+		<row><td>AdvtUISequence</td><td>Sequence</td><td>Y</td><td>-4</td><td>32767</td><td/><td/><td/><td/><td>Number that determines the sort order in which the actions are to be executed.  Leave blank to suppress action.</td></row>
+		<row><td>AppId</td><td>ActivateAtStorage</td><td>Y</td><td>0</td><td>1</td><td/><td/><td/><td/><td/></row>
+		<row><td>AppId</td><td>AppId</td><td>N</td><td/><td/><td/><td/><td>Guid</td><td/><td/></row>
+		<row><td>AppId</td><td>DllSurrogate</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td/></row>
+		<row><td>AppId</td><td>LocalService</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td/></row>
+		<row><td>AppId</td><td>RemoteServerName</td><td>Y</td><td/><td/><td/><td/><td>Formatted</td><td/><td/></row>
+		<row><td>AppId</td><td>RunAsInteractiveUser</td><td>Y</td><td>0</td><td>1</td><td/><td/><td/><td/><td/></row>
+		<row><td>AppId</td><td>ServiceParameters</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td/></row>
+		<row><td>AppSearch</td><td>Property</td><td>N</td><td/><td/><td/><td/><td>Identifier</td><td/><td>The property associated with a Signature</td></row>
+		<row><td>AppSearch</td><td>Signature_</td><td>N</td><td/><td/><td>ISXmlLocator;Signature</td><td>1</td><td>Identifier</td><td/><td>The Signature_ represents a unique file signature and is also the foreign key in the Signature,  RegLocator, IniLocator, CompLocator and the DrLocator tables.</td></row>
+		<row><td>BBControl</td><td>Attributes</td><td>Y</td><td>0</td><td>2147483647</td><td/><td/><td/><td/><td>A 32-bit word that specifies the attribute flags to be applied to this control.</td></row>
+		<row><td>BBControl</td><td>BBControl</td><td>N</td><td/><td/><td/><td/><td>Identifier</td><td/><td>Name of the control. This name must be unique within a billboard, but can repeat on different billboard.</td></row>
+		<row><td>BBControl</td><td>Billboard_</td><td>N</td><td/><td/><td>Billboard</td><td>1</td><td>Identifier</td><td/><td>External key to the Billboard table, name of the billboard.</td></row>
+		<row><td>BBControl</td><td>Height</td><td>N</td><td>0</td><td>32767</td><td/><td/><td/><td/><td>Height of the bounding rectangle of the control.</td></row>
+		<row><td>BBControl</td><td>Text</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>A string used to set the initial text contained within a control (if appropriate).</td></row>
+		<row><td>BBControl</td><td>Type</td><td>N</td><td/><td/><td/><td/><td>Identifier</td><td/><td>The type of the control.</td></row>
+		<row><td>BBControl</td><td>Width</td><td>N</td><td>0</td><td>32767</td><td/><td/><td/><td/><td>Width of the bounding rectangle of the control.</td></row>
+		<row><td>BBControl</td><td>X</td><td>N</td><td>0</td><td>32767</td><td/><td/><td/><td/><td>Horizontal coordinate of the upper left corner of the bounding rectangle of the control.</td></row>
+		<row><td>BBControl</td><td>Y</td><td>N</td><td>0</td><td>32767</td><td/><td/><td/><td/><td>Vertical coordinate of the upper left corner of the bounding rectangle of the control.</td></row>
+		<row><td>Billboard</td><td>Action</td><td>Y</td><td/><td/><td/><td/><td>Identifier</td><td/><td>The name of an action. The billboard is displayed during the progress messages received from this action.</td></row>
+		<row><td>Billboard</td><td>Billboard</td><td>N</td><td/><td/><td/><td/><td>Identifier</td><td/><td>Name of the billboard.</td></row>
+		<row><td>Billboard</td><td>Feature_</td><td>N</td><td/><td/><td>Feature</td><td>1</td><td>Identifier</td><td/><td>An external key to the Feature Table. The billboard is shown only if this feature is being installed.</td></row>
+		<row><td>Billboard</td><td>Ordering</td><td>Y</td><td>0</td><td>32767</td><td/><td/><td/><td/><td>A positive integer. If there is more than one billboard corresponding to an action they will be shown in the order defined by this column.</td></row>
+		<row><td>Binary</td><td>Data</td><td>Y</td><td/><td/><td/><td/><td>Binary</td><td/><td>Binary stream. The binary icon data in PE (.DLL or .EXE) or icon (.ICO) format.</td></row>
+		<row><td>Binary</td><td>ISBuildSourcePath</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>Full path to the ICO or EXE file.</td></row>
+		<row><td>Binary</td><td>Name</td><td>N</td><td/><td/><td/><td/><td>Identifier</td><td/><td>Unique key identifying the binary data.</td></row>
+		<row><td>BindImage</td><td>File_</td><td>N</td><td/><td/><td>File</td><td>1</td><td>Identifier</td><td/><td>The index into the File table. This must be an executable file.</td></row>
+		<row><td>BindImage</td><td>Path</td><td>Y</td><td/><td/><td/><td/><td>Paths</td><td/><td>A list of ;  delimited paths that represent the paths to be searched for the import DLLS. The list is usually a list of properties each enclosed within square brackets [] .</td></row>
+		<row><td>CCPSearch</td><td>Signature_</td><td>N</td><td/><td/><td>Signature</td><td>1</td><td>Identifier</td><td/><td>The Signature_ represents a unique file signature and is also the foreign key in the Signature,  RegLocator, IniLocator, CompLocator and the DrLocator tables.</td></row>
+		<row><td>CheckBox</td><td>Property</td><td>N</td><td/><td/><td/><td/><td>Identifier</td><td/><td>A named property to be tied to the item.</td></row>
+		<row><td>CheckBox</td><td>Value</td><td>Y</td><td/><td/><td/><td/><td>Formatted</td><td/><td>The value string associated with the item.</td></row>
+		<row><td>Class</td><td>AppId_</td><td>Y</td><td/><td/><td>AppId</td><td>1</td><td>Guid</td><td/><td>Optional AppID containing DCOM information for associated application (string GUID).</td></row>
+		<row><td>Class</td><td>Argument</td><td>Y</td><td/><td/><td/><td/><td>Formatted</td><td/><td>optional argument for LocalServers.</td></row>
+		<row><td>Class</td><td>Attributes</td><td>Y</td><td/><td>32767</td><td/><td/><td/><td/><td>Class registration attributes.</td></row>
+		<row><td>Class</td><td>CLSID</td><td>N</td><td/><td/><td/><td/><td>Guid</td><td/><td>The CLSID of an OLE factory.</td></row>
+		<row><td>Class</td><td>Component_</td><td>N</td><td/><td/><td>Component</td><td>1</td><td>Identifier</td><td/><td>Required foreign key into the Component Table, specifying the component for which to return a path when called through LocateComponent.</td></row>
+		<row><td>Class</td><td>Context</td><td>N</td><td/><td/><td/><td/><td>Identifier</td><td/><td>The numeric server context for this server. CLSCTX_xxxx</td></row>
+		<row><td>Class</td><td>DefInprocHandler</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td>1;2;3</td><td>Optional default inproc handler.  Only optionally provided if Context=CLSCTX_LOCAL_SERVER.  Typically "ole32.dll" or "mapi32.dll"</td></row>
+		<row><td>Class</td><td>Description</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>Localized description for the Class.</td></row>
+		<row><td>Class</td><td>Feature_</td><td>N</td><td/><td/><td>Feature</td><td>1</td><td>Identifier</td><td/><td>Required foreign key into the Feature Table, specifying the feature to validate or install in order for the CLSID factory to be operational.</td></row>
+		<row><td>Class</td><td>FileTypeMask</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>Optional string containing information for the HKCRthis CLSID) key. If multiple patterns exist, they must be delimited by a semicolon, and numeric subkeys will be generated: 0,1,2...</td></row>
+		<row><td>Class</td><td>IconIndex</td><td>Y</td><td>-32767</td><td>32767</td><td/><td/><td/><td/><td>Optional icon index.</td></row>
+		<row><td>Class</td><td>Icon_</td><td>Y</td><td/><td/><td>Icon</td><td>1</td><td>Identifier</td><td/><td>Optional foreign key into the Icon Table, specifying the icon file associated with this CLSID. Will be written under the DefaultIcon key.</td></row>
+		<row><td>Class</td><td>ProgId_Default</td><td>Y</td><td/><td/><td>ProgId</td><td>1</td><td>Text</td><td/><td>Optional ProgId associated with this CLSID.</td></row>
+		<row><td>ComboBox</td><td>Order</td><td>N</td><td>1</td><td>32767</td><td/><td/><td/><td/><td>A positive integer used to determine the ordering of the items within one list.	The integers do not have to be consecutive.</td></row>
+		<row><td>ComboBox</td><td>Property</td><td>N</td><td/><td/><td/><td/><td>Identifier</td><td/><td>A named property to be tied to this item. All the items tied to the same property become part of the same combobox.</td></row>
+		<row><td>ComboBox</td><td>Text</td><td>Y</td><td/><td/><td/><td/><td>Formatted</td><td/><td>The visible text to be assigned to the item. Optional. If this entry or the entire column is missing, the text is the same as the value.</td></row>
+		<row><td>ComboBox</td><td>Value</td><td>N</td><td/><td/><td/><td/><td>Formatted</td><td/><td>The value string associated with this item. Selecting the line will set the associated property to this value.</td></row>
+		<row><td>CompLocator</td><td>ComponentId</td><td>N</td><td/><td/><td/><td/><td>Guid</td><td/><td>A string GUID unique to this component, version, and language.</td></row>
+		<row><td>CompLocator</td><td>Signature_</td><td>N</td><td/><td/><td>Signature</td><td>1</td><td>Identifier</td><td/><td>The table key. The Signature_ represents a unique file signature and is also the foreign key in the Signature table.</td></row>
+		<row><td>CompLocator</td><td>Type</td><td>Y</td><td>0</td><td>1</td><td/><td/><td/><td/><td>A boolean value that determines if the registry value is a filename or a directory location.</td></row>
+		<row><td>Complus</td><td>Component_</td><td>N</td><td/><td/><td>Component</td><td>1</td><td>Identifier</td><td/><td>Foreign key referencing Component that controls the ComPlus component.</td></row>
+		<row><td>Complus</td><td>ExpType</td><td>Y</td><td>0</td><td>32767</td><td/><td/><td/><td/><td>ComPlus component attributes.</td></row>
+		<row><td>Component</td><td>Attributes</td><td>N</td><td/><td/><td/><td/><td/><td/><td>Remote execution option, one of irsEnum</td></row>
+		<row><td>Component</td><td>Component</td><td>N</td><td/><td/><td/><td/><td>Identifier</td><td/><td>Primary key used to identify a particular component record.</td></row>
+		<row><td>Component</td><td>ComponentId</td><td>Y</td><td/><td/><td/><td/><td>Guid</td><td/><td>A string GUID unique to this component, version, and language.</td></row>
+		<row><td>Component</td><td>Condition</td><td>Y</td><td/><td/><td/><td/><td>Condition</td><td/><td>A conditional statement that will disable this component if the specified condition evaluates to the 'True' state. If a component is disabled, it will not be installed, regardless of the 'Action' state associated with the component.</td></row>
+		<row><td>Component</td><td>Directory_</td><td>N</td><td/><td/><td>Directory</td><td>1</td><td>Identifier</td><td/><td>Required key of a Directory table record. This is actually a property name whose value contains the actual path, set either by the AppSearch action or with the default setting obtained from the Directory table.</td></row>
+		<row><td>Component</td><td>ISAttributes</td><td>Y</td><td/><td/><td/><td/><td/><td/><td>This is used to store Installshield custom properties of a component.</td></row>
+		<row><td>Component</td><td>ISComments</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>User Comments.</td></row>
+		<row><td>Component</td><td>ISDotNetInstallerArgsCommit</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>Arguments passed to the key file of the component if if implements the .NET Installer class</td></row>
+		<row><td>Component</td><td>ISDotNetInstallerArgsInstall</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>Arguments passed to the key file of the component if if implements the .NET Installer class</td></row>
+		<row><td>Component</td><td>ISDotNetInstallerArgsRollback</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>Arguments passed to the key file of the component if if implements the .NET Installer class</td></row>
+		<row><td>Component</td><td>ISDotNetInstallerArgsUninstall</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>Arguments passed to the key file of the component if if implements the .NET Installer class</td></row>
+		<row><td>Component</td><td>ISRegFileToMergeAtBuild</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>Path and File name of a .REG file to merge into the component at build time.</td></row>
+		<row><td>Component</td><td>ISScanAtBuildFile</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>File used by the Dot Net scanner to populate dependant assemblies' File_Application field.</td></row>
+		<row><td>Component</td><td>KeyPath</td><td>Y</td><td/><td/><td>File;ODBCDataSource;Registry</td><td>1</td><td>Identifier</td><td/><td>Either the primary key into the File table, Registry table, or ODBCDataSource table. This extract path is stored when the component is installed, and is used to detect the presence of the component and to return the path to it.</td></row>
+		<row><td>Condition</td><td>Condition</td><td>Y</td><td/><td/><td/><td/><td>Condition</td><td/><td>Expression evaluated to determine if Level in the Feature table is to change.</td></row>
+		<row><td>Condition</td><td>Feature_</td><td>N</td><td/><td/><td>Feature</td><td>1</td><td>Identifier</td><td/><td>Reference to a Feature entry in Feature table.</td></row>
+		<row><td>Condition</td><td>Level</td><td>N</td><td>0</td><td>32767</td><td/><td/><td/><td/><td>New selection Level to set in Feature table if Condition evaluates to TRUE.</td></row>
+		<row><td>Control</td><td>Attributes</td><td>Y</td><td>0</td><td>2147483647</td><td/><td/><td/><td/><td>A 32-bit word that specifies the attribute flags to be applied to this control.</td></row>
+		<row><td>Control</td><td>Binary_</td><td>Y</td><td/><td/><td>Binary</td><td>1</td><td>Identifier</td><td/><td>External key to the Binary table.</td></row>
+		<row><td>Control</td><td>Control</td><td>N</td><td/><td/><td/><td/><td>Identifier</td><td/><td>Name of the control. This name must be unique within a dialog, but can repeat on different dialogs. </td></row>
+		<row><td>Control</td><td>Control_Next</td><td>Y</td><td/><td/><td>Control</td><td>2</td><td>Identifier</td><td/><td>The name of an other control on the same dialog. This link defines the tab order of the controls. The links have to form one or more cycles!</td></row>
+		<row><td>Control</td><td>Dialog_</td><td>N</td><td/><td/><td>Dialog</td><td>1</td><td>Identifier</td><td/><td>External key to the Dialog table, name of the dialog.</td></row>
+		<row><td>Control</td><td>Height</td><td>N</td><td>0</td><td>32767</td><td/><td/><td/><td/><td>Height of the bounding rectangle of the control.</td></row>
+		<row><td>Control</td><td>Help</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>The help strings used with the button. The text is optional. </td></row>
+		<row><td>Control</td><td>ISBuildSourcePath</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>Full path to .rtf file for scrollable text control</td></row>
+		<row><td>Control</td><td>ISControlId</td><td>Y</td><td/><td/><td/><td/><td/><td/><td>A number used to represent the control ID of the Control, Used in Dialog export</td></row>
+		<row><td>Control</td><td>ISWindowStyle</td><td>Y</td><td>0</td><td>2147483647</td><td/><td/><td/><td/><td>A 32-bit word that specifies non-MSI window styles to be applied to this control.</td></row>
+		<row><td>Control</td><td>Property</td><td>Y</td><td/><td/><td/><td/><td>Identifier</td><td/><td>The name of a defined property to be linked to this control. </td></row>
+		<row><td>Control</td><td>Text</td><td>Y</td><td/><td/><td/><td/><td>Formatted</td><td/><td>A string used to set the initial text contained within a control (if appropriate).</td></row>
+		<row><td>Control</td><td>Type</td><td>N</td><td/><td/><td/><td/><td>Identifier</td><td/><td>The type of the control.</td></row>
+		<row><td>Control</td><td>Width</td><td>N</td><td>0</td><td>32767</td><td/><td/><td/><td/><td>Width of the bounding rectangle of the control.</td></row>
+		<row><td>Control</td><td>X</td><td>N</td><td>0</td><td>32767</td><td/><td/><td/><td/><td>Horizontal coordinate of the upper left corner of the bounding rectangle of the control.</td></row>
+		<row><td>Control</td><td>Y</td><td>N</td><td>0</td><td>32767</td><td/><td/><td/><td/><td>Vertical coordinate of the upper left corner of the bounding rectangle of the control.</td></row>
+		<row><td>ControlCondition</td><td>Action</td><td>N</td><td/><td/><td/><td/><td/><td>Default;Disable;Enable;Hide;Show</td><td>The desired action to be taken on the specified control.</td></row>
+		<row><td>ControlCondition</td><td>Condition</td><td>N</td><td/><td/><td/><td/><td>Condition</td><td/><td>A standard conditional statement that specifies under which conditions the action should be triggered.</td></row>
+		<row><td>ControlCondition</td><td>Control_</td><td>N</td><td/><td/><td>Control</td><td>2</td><td>Identifier</td><td/><td>A foreign key to the Control table, name of the control.</td></row>
+		<row><td>ControlCondition</td><td>Dialog_</td><td>N</td><td/><td/><td>Dialog</td><td>1</td><td>Identifier</td><td/><td>A foreign key to the Dialog table, name of the dialog.</td></row>
+		<row><td>ControlEvent</td><td>Argument</td><td>N</td><td/><td/><td/><td/><td>Formatted</td><td/><td>A value to be used as a modifier when triggering a particular event.</td></row>
+		<row><td>ControlEvent</td><td>Condition</td><td>Y</td><td/><td/><td/><td/><td>Condition</td><td/><td>A standard conditional statement that specifies under which conditions an event should be triggered.</td></row>
+		<row><td>ControlEvent</td><td>Control_</td><td>N</td><td/><td/><td>Control</td><td>2</td><td>Identifier</td><td/><td>A foreign key to the Control table, name of the control</td></row>
+		<row><td>ControlEvent</td><td>Dialog_</td><td>N</td><td/><td/><td>Dialog</td><td>1</td><td>Identifier</td><td/><td>A foreign key to the Dialog table, name of the dialog.</td></row>
+		<row><td>ControlEvent</td><td>Event</td><td>N</td><td/><td/><td/><td/><td>Formatted</td><td/><td>An identifier that specifies the type of the event that should take place when the user interacts with control specified by the first two entries.</td></row>
+		<row><td>ControlEvent</td><td>Ordering</td><td>Y</td><td>0</td><td>2147483647</td><td/><td/><td/><td/><td>An integer used to order several events tied to the same control. Can be left blank.</td></row>
+		<row><td>CreateFolder</td><td>Component_</td><td>N</td><td/><td/><td>Component</td><td>1</td><td>Identifier</td><td/><td>Foreign key into the Component table.</td></row>
+		<row><td>CreateFolder</td><td>Directory_</td><td>N</td><td/><td/><td>Directory</td><td>1</td><td>Identifier</td><td/><td>Primary key, could be foreign key into the Directory table.</td></row>
+		<row><td>CustomAction</td><td>Action</td><td>N</td><td/><td/><td/><td/><td>Identifier</td><td/><td>Primary key, name of action, normally appears in sequence table unless private use.</td></row>
+		<row><td>CustomAction</td><td>ISComments</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td dt:dt="bin.base64" md5="32618cf58258b38e853f7a99b6c3518e">
+QQB1AHQAaABvAHIAGSBzACAAYwBvAG0AbQBlAG4AdABzACAAZgBvAHIAIAB0AGgAaQBzACAAYwB1AHMAdABvAG0AIABhAGMAdABpAG8AbgAuAA==
+			</td></row>
+		<row><td>CustomAction</td><td>Source</td><td>Y</td><td/><td/><td/><td/><td>CustomSource</td><td/><td>The table reference of the source of the code.</td></row>
+		<row><td>CustomAction</td><td>Target</td><td>Y</td><td/><td/><td>ISDLLWrapper;ISInstallScriptAction</td><td>1</td><td>Formatted</td><td/><td>Excecution parameter, depends on the type of custom action</td></row>
+		<row><td>CustomAction</td><td>Type</td><td>N</td><td>1</td><td>32767</td><td/><td/><td/><td/><td>The numeric custom action type, consisting of source location, code type, entry, option flags.</td></row>
+		<row><td>Dialog</td><td>Attributes</td><td>Y</td><td>0</td><td>2147483647</td><td/><td/><td/><td/><td>A 32-bit word that specifies the attribute flags to be applied to this dialog.</td></row>
+		<row><td>Dialog</td><td>Control_Cancel</td><td>Y</td><td/><td/><td>Control</td><td>2</td><td>Identifier</td><td/><td>Defines the cancel control. Hitting escape or clicking on the close icon on the dialog is equivalent to pushing this button.</td></row>
+		<row><td>Dialog</td><td>Control_Default</td><td>Y</td><td/><td/><td>Control</td><td>2</td><td>Identifier</td><td/><td>Defines the default control. Hitting return is equivalent to pushing this button.</td></row>
+		<row><td>Dialog</td><td>Control_First</td><td>N</td><td/><td/><td>Control</td><td>2</td><td>Identifier</td><td/><td>Defines the control that has the focus when the dialog is created.</td></row>
+		<row><td>Dialog</td><td>Dialog</td><td>N</td><td/><td/><td/><td/><td>Identifier</td><td/><td>Name of the dialog.</td></row>
+		<row><td>Dialog</td><td>HCentering</td><td>N</td><td>0</td><td>100</td><td/><td/><td/><td/><td>Horizontal position of the dialog on a 0-100 scale. 0 means left end, 100 means right end of the screen, 50 center.</td></row>
+		<row><td>Dialog</td><td>Height</td><td>N</td><td>0</td><td>32767</td><td/><td/><td/><td/><td>Height of the bounding rectangle of the dialog.</td></row>
+		<row><td>Dialog</td><td>ISComments</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td dt:dt="bin.base64" md5="99783de6d158fd3d49a9424b04aa1fc1">
+QQB1AHQAaABvAHIAGSBzACAAYwBvAG0AbQBlAG4AdABzACAAZgBvAHIAIAB0AGgAaQBzACAAZABpAGEAbABvAGcALgA=
+			</td></row>
+		<row><td>Dialog</td><td>ISResourceId</td><td>Y</td><td/><td/><td/><td/><td/><td/><td>A Number the Specifies the Dialog ID to be used in Dialog Export</td></row>
+		<row><td>Dialog</td><td>ISWindowStyle</td><td>Y</td><td/><td/><td/><td/><td/><td/><td>A 32-bit word that specifies non-MSI window styles to be applied to this control. This is only used in Script Based Setups.</td></row>
+		<row><td>Dialog</td><td>TextStyle_</td><td>Y</td><td/><td/><td/><td/><td>Identifier</td><td/><td>Foreign Key into TextStyle table, only used in Script Based Projects.</td></row>
+		<row><td>Dialog</td><td>Title</td><td>Y</td><td/><td/><td/><td/><td>Formatted</td><td/><td>A text string specifying the title to be displayed in the title bar of the dialog's window.</td></row>
+		<row><td>Dialog</td><td>VCentering</td><td>N</td><td>0</td><td>100</td><td/><td/><td/><td/><td>Vertical position of the dialog on a 0-100 scale. 0 means top end, 100 means bottom end of the screen, 50 center.</td></row>
+		<row><td>Dialog</td><td>Width</td><td>N</td><td>0</td><td>32767</td><td/><td/><td/><td/><td>Width of the bounding rectangle of the dialog.</td></row>
+		<row><td>Directory</td><td>DefaultDir</td><td>N</td><td/><td/><td/><td/><td>Text</td><td/><td>The default sub-path under parent's path.</td></row>
+		<row><td>Directory</td><td>Directory</td><td>N</td><td/><td/><td/><td/><td>Identifier</td><td/><td>Unique identifier for directory entry, primary key. If a property by this name is defined, it contains the full path to the directory.</td></row>
+		<row><td>Directory</td><td>Directory_Parent</td><td>Y</td><td/><td/><td>Directory</td><td>1</td><td>Identifier</td><td/><td>Reference to the entry in this table specifying the default parent directory. A record parented to itself or with a Null parent represents a root of the install tree.</td></row>
+		<row><td>Directory</td><td>ISAttributes</td><td>Y</td><td/><td/><td/><td/><td/><td>0;1;2;3;4;5;6;7</td><td>This is used to store Installshield custom properties of a directory.  Currently the only one is Shortcut.</td></row>
+		<row><td>Directory</td><td>ISDescription</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>Description of folder</td></row>
+		<row><td>Directory</td><td>ISFolderName</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>This is used in Pro projects because the pro identifier used in the tree wasn't necessarily unique.</td></row>
+		<row><td>DrLocator</td><td>Depth</td><td>Y</td><td>0</td><td>32767</td><td/><td/><td/><td/><td>The depth below the path to which the Signature_ is recursively searched. If absent, the depth is assumed to be 0.</td></row>
+		<row><td>DrLocator</td><td>Parent</td><td>Y</td><td/><td/><td/><td/><td>Identifier</td><td/><td>The parent file signature. It is also a foreign key in the Signature table. If null and the Path column does not expand to a full path, then all the fixed drives of the user system are searched using the Path.</td></row>
+		<row><td>DrLocator</td><td>Path</td><td>Y</td><td/><td/><td/><td/><td>AnyPath</td><td/><td>The path on the user system. This is a either a subpath below the value of the Parent or a full path. The path may contain properties enclosed within [ ] that will be expanded.</td></row>
+		<row><td>DrLocator</td><td>Signature_</td><td>N</td><td/><td/><td>Signature</td><td>1</td><td>Identifier</td><td/><td>The Signature_ represents a unique file signature and is also the foreign key in the Signature table.</td></row>
+		<row><td>DuplicateFile</td><td>Component_</td><td>N</td><td/><td/><td>Component</td><td>1</td><td>Identifier</td><td/><td>Foreign key referencing Component that controls the duplicate file.</td></row>
+		<row><td>DuplicateFile</td><td>DestFolder</td><td>Y</td><td/><td/><td/><td/><td>Identifier</td><td/><td>Name of a property whose value is assumed to resolve to the full pathname to a destination folder.</td></row>
+		<row><td>DuplicateFile</td><td>DestName</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>Filename to be given to the duplicate file.</td></row>
+		<row><td>DuplicateFile</td><td>FileKey</td><td>N</td><td/><td/><td/><td/><td>Identifier</td><td/><td>Primary key used to identify a particular file entry</td></row>
+		<row><td>DuplicateFile</td><td>File_</td><td>N</td><td/><td/><td>File</td><td>1</td><td>Identifier</td><td/><td>Foreign key referencing the source file to be duplicated.</td></row>
+		<row><td>Environment</td><td>Component_</td><td>N</td><td/><td/><td>Component</td><td>1</td><td>Identifier</td><td/><td>Foreign key into the Component table referencing component that controls the installing of the environmental value.</td></row>
+		<row><td>Environment</td><td>Environment</td><td>N</td><td/><td/><td/><td/><td>Identifier</td><td/><td>Unique identifier for the environmental variable setting</td></row>
+		<row><td>Environment</td><td>Name</td><td>N</td><td/><td/><td/><td/><td>Text</td><td/><td>The name of the environmental value.</td></row>
+		<row><td>Environment</td><td>Value</td><td>Y</td><td/><td/><td/><td/><td>Formatted</td><td/><td>The value to set in the environmental settings.</td></row>
+		<row><td>Error</td><td>Error</td><td>N</td><td>0</td><td>32767</td><td/><td/><td/><td/><td>Integer error number, obtained from header file IError(...) macros.</td></row>
+		<row><td>Error</td><td>Message</td><td>Y</td><td/><td/><td/><td/><td>Template</td><td/><td>Error formatting template, obtained from user ed. or localizers.</td></row>
+		<row><td>EventMapping</td><td>Attribute</td><td>N</td><td/><td/><td/><td/><td>Identifier</td><td/><td>The name of the control attribute, that is set when this event is received.</td></row>
+		<row><td>EventMapping</td><td>Control_</td><td>N</td><td/><td/><td>Control</td><td>2</td><td>Identifier</td><td/><td>A foreign key to the Control table, name of the control.</td></row>
+		<row><td>EventMapping</td><td>Dialog_</td><td>N</td><td/><td/><td>Dialog</td><td>1</td><td>Identifier</td><td/><td>A foreign key to the Dialog table, name of the Dialog.</td></row>
+		<row><td>EventMapping</td><td>Event</td><td>N</td><td/><td/><td/><td/><td>Identifier</td><td/><td>An identifier that specifies the type of the event that the control subscribes to.</td></row>
+		<row><td>Extension</td><td>Component_</td><td>N</td><td/><td/><td>Component</td><td>1</td><td>Identifier</td><td/><td>Required foreign key into the Component Table, specifying the component for which to return a path when called through LocateComponent.</td></row>
+		<row><td>Extension</td><td>Extension</td><td>N</td><td/><td/><td/><td/><td>Text</td><td/><td>The extension associated with the table row.</td></row>
+		<row><td>Extension</td><td>Feature_</td><td>N</td><td/><td/><td>Feature</td><td>1</td><td>Identifier</td><td/><td>Required foreign key into the Feature Table, specifying the feature to validate or install in order for the CLSID factory to be operational.</td></row>
+		<row><td>Extension</td><td>MIME_</td><td>Y</td><td/><td/><td>MIME</td><td>1</td><td>Text</td><td/><td>Optional Context identifier, typically "type/format" associated with the extension</td></row>
+		<row><td>Extension</td><td>ProgId_</td><td>Y</td><td/><td/><td>ProgId</td><td>1</td><td>Text</td><td/><td>Optional ProgId associated with this extension.</td></row>
+		<row><td>Feature</td><td>Attributes</td><td>N</td><td/><td/><td/><td/><td/><td>0;1;2;4;5;6;8;9;10;16;17;18;20;21;22;24;25;26;32;33;34;36;37;38;48;49;50;52;53;54</td><td>Feature attributes</td></row>
+		<row><td>Feature</td><td>Description</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>Longer descriptive text describing a visible feature item.</td></row>
+		<row><td>Feature</td><td>Directory_</td><td>Y</td><td/><td/><td>Directory</td><td>1</td><td>UpperCase</td><td/><td>The name of the Directory that can be configured by the UI. A non-null value will enable the browse button.</td></row>
+		<row><td>Feature</td><td>Display</td><td>Y</td><td>0</td><td>32767</td><td/><td/><td/><td/><td>Numeric sort order, used to force a specific display ordering.</td></row>
+		<row><td>Feature</td><td>Feature</td><td>N</td><td/><td/><td/><td/><td>Identifier</td><td/><td>Primary key used to identify a particular feature record.</td></row>
+		<row><td>Feature</td><td>Feature_Parent</td><td>Y</td><td/><td/><td>Feature</td><td>1</td><td>Identifier</td><td/><td>Optional key of a parent record in the same table. If the parent is not selected, then the record will not be installed. Null indicates a root item.</td></row>
+		<row><td>Feature</td><td>ISComments</td><td>Y</td><td/><td/><td/><td/><td/><td/><td>Comments</td></row>
+		<row><td>Feature</td><td>ISFeatureCabName</td><td>Y</td><td/><td/><td/><td/><td/><td/><td>Name of CAB used when compressing CABs by Feature. Used to override build generated name for CAB file.</td></row>
+		<row><td>Feature</td><td>ISProFeatureName</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>The name of the feature used by pro projects.  This doesn't have to be unique.</td></row>
+		<row><td>Feature</td><td>ISReleaseFlags</td><td>Y</td><td/><td/><td/><td/><td/><td/><td>Release Flags that specify whether this  feature will be built in a particular release.</td></row>
+		<row><td>Feature</td><td>Level</td><td>N</td><td>0</td><td>32767</td><td/><td/><td/><td/><td>The install level at which record will be initially selected. An install level of 0 will disable an item and prevent its display.</td></row>
+		<row><td>Feature</td><td>Title</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>Short text identifying a visible feature item.</td></row>
+		<row><td>FeatureComponents</td><td>Component_</td><td>N</td><td/><td/><td>Component</td><td>1</td><td>Identifier</td><td/><td>Foreign key into Component table.</td></row>
+		<row><td>FeatureComponents</td><td>Feature_</td><td>N</td><td/><td/><td>Feature</td><td>1</td><td>Identifier</td><td/><td>Foreign key into Feature table.</td></row>
+		<row><td>File</td><td>Attributes</td><td>Y</td><td>0</td><td>32767</td><td/><td/><td/><td/><td>Integer containing bit flags representing file attributes (with the decimal value of each bit position in parentheses)</td></row>
+		<row><td>File</td><td>Component_</td><td>N</td><td/><td/><td>Component</td><td>1</td><td>Identifier</td><td/><td>Foreign key referencing Component that controls the file.</td></row>
+		<row><td>File</td><td>File</td><td>N</td><td/><td/><td/><td/><td>Identifier</td><td/><td>Primary key, non-localized token, must match identifier in cabinet.  For uncompressed files, this field is ignored.</td></row>
+		<row><td>File</td><td>FileName</td><td>N</td><td/><td/><td/><td/><td>Text</td><td/><td>File name used for installation.  This may contain a "short name|long name" pair.  It may be just a long name, hence it cannot be of the Filename data type.</td></row>
+		<row><td>File</td><td>FileSize</td><td>N</td><td>0</td><td>2147483647</td><td/><td/><td/><td/><td>Size of file in bytes (long integer).</td></row>
+		<row><td>File</td><td>ISAttributes</td><td>Y</td><td>0</td><td>2147483647</td><td/><td/><td/><td/><td>This field contains the following attributes: UseSystemSettings(0x1)</td></row>
+		<row><td>File</td><td>ISBuildSourcePath</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>Full path, the category is of Text instead of Path because of potential use of path variables.</td></row>
+		<row><td>File</td><td>ISComponentSubFolder_</td><td>Y</td><td/><td/><td/><td/><td>Identifier</td><td/><td>Foreign key referencing component subfolder containing this file.  Only for Pro.</td></row>
+		<row><td>File</td><td>Language</td><td>Y</td><td/><td/><td/><td/><td>Language</td><td/><td>List of decimal language Ids, comma-separated if more than one.</td></row>
+		<row><td>File</td><td>Sequence</td><td>N</td><td>1</td><td>32767</td><td/><td/><td/><td/><td>Sequence with respect to the media images; order must track cabinet order.</td></row>
+		<row><td>File</td><td>Version</td><td>Y</td><td/><td/><td>File</td><td>1</td><td>Version</td><td/><td>Version string for versioned files;  Blank for unversioned files.</td></row>
+		<row><td>FileSFPCatalog</td><td>File_</td><td>N</td><td/><td/><td>File</td><td>1</td><td>Identifier</td><td/><td>File associated with the catalog</td></row>
+		<row><td>FileSFPCatalog</td><td>SFPCatalog_</td><td>N</td><td/><td/><td>SFPCatalog</td><td>1</td><td>Text</td><td/><td>Catalog associated with the file</td></row>
+		<row><td>Font</td><td>File_</td><td>N</td><td/><td/><td>File</td><td>1</td><td>Identifier</td><td/><td>Primary key, foreign key into File table referencing font file.</td></row>
+		<row><td>Font</td><td>FontTitle</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>Font name.</td></row>
+		<row><td>ISAssistantTag</td><td>Data</td><td>Y</td><td/><td/><td/><td/><td/><td/><td/></row>
+		<row><td>ISAssistantTag</td><td>Tag</td><td>N</td><td/><td/><td/><td/><td/><td/><td/></row>
+		<row><td>ISCEApp</td><td>AppKey</td><td>N</td><td/><td/><td/><td/><td/><td/><td/></row>
+		<row><td>ISCEApp</td><td>AppName</td><td>N</td><td/><td/><td/><td/><td/><td/><td/></row>
+		<row><td>ISCEApp</td><td>Attributes</td><td>Y</td><td/><td/><td/><td/><td/><td/><td/></row>
+		<row><td>ISCEApp</td><td>CompanyName</td><td>N</td><td/><td/><td/><td/><td/><td/><td/></row>
+		<row><td>ISCEApp</td><td>Component_</td><td>Y</td><td/><td/><td>Component</td><td>1</td><td/><td/><td/></row>
+		<row><td>ISCEApp</td><td>DefDir</td><td>N</td><td/><td/><td/><td/><td/><td/><td/></row>
+		<row><td>ISCEApp</td><td>DeleteMedia</td><td>N</td><td/><td/><td/><td/><td/><td/><td/></row>
+		<row><td>ISCEApp</td><td>Description</td><td>Y</td><td/><td/><td/><td/><td/><td/><td/></row>
+		<row><td>ISCEApp</td><td>DesktopTargetDir</td><td>N</td><td/><td/><td/><td/><td/><td/><td/></row>
+		<row><td>ISCEApp</td><td>DeviceFile</td><td>Y</td><td/><td/><td/><td/><td/><td/><td/></row>
+		<row><td>ISCEApp</td><td>IconIndex</td><td>Y</td><td/><td/><td/><td/><td/><td/><td/></row>
+		<row><td>ISCEApp</td><td>IconPath</td><td>Y</td><td/><td/><td/><td/><td/><td/><td/></row>
+		<row><td>ISCEApp</td><td>InstallNetCF</td><td>Y</td><td/><td/><td/><td/><td/><td/><td/></row>
+		<row><td>ISCEApp</td><td>InstallSQLClient</td><td>Y</td><td/><td/><td/><td/><td/><td/><td/></row>
+		<row><td>ISCEApp</td><td>InstallSQLDev</td><td>Y</td><td/><td/><td/><td/><td/><td/><td/></row>
+		<row><td>ISCEApp</td><td>InstallSQLServer</td><td>Y</td><td/><td/><td/><td/><td/><td/><td/></row>
+		<row><td>ISCEApp</td><td>NoUninstall</td><td>Y</td><td/><td/><td/><td/><td/><td/><td/></row>
+		<row><td>ISCEApp</td><td>PVKFile</td><td>Y</td><td/><td/><td/><td/><td/><td/><td/></row>
+		<row><td>ISCEApp</td><td>PostXML</td><td>Y</td><td/><td/><td/><td/><td/><td/><td/></row>
+		<row><td>ISCEApp</td><td>PreXML</td><td>Y</td><td/><td/><td/><td/><td/><td/><td/></row>
+		<row><td>ISCEApp</td><td>RawDeviceFile</td><td>Y</td><td/><td/><td/><td/><td/><td/><td/></row>
+		<row><td>ISCEApp</td><td>SPCFile</td><td>Y</td><td/><td/><td/><td/><td/><td/><td/></row>
+		<row><td>ISCEDir</td><td>AppKey</td><td>N</td><td/><td/><td/><td/><td/><td/><td/></row>
+		<row><td>ISCEDir</td><td>DirKey</td><td>N</td><td/><td/><td/><td/><td/><td/><td/></row>
+		<row><td>ISCEDir</td><td>DirParent</td><td>N</td><td/><td/><td/><td/><td/><td/><td/></row>
+		<row><td>ISCEDir</td><td>DirValue</td><td>N</td><td/><td/><td/><td/><td/><td/><td/></row>
+		<row><td>ISCEFile</td><td>AdvancedOptions</td><td>Y</td><td/><td/><td/><td/><td/><td/><td/></row>
+		<row><td>ISCEFile</td><td>AppKey</td><td>N</td><td/><td/><td/><td/><td/><td/><td/></row>
+		<row><td>ISCEFile</td><td>CopyOption</td><td>N</td><td/><td/><td/><td/><td/><td/><td/></row>
+		<row><td>ISCEFile</td><td>Destination</td><td>N</td><td/><td/><td/><td/><td/><td/><td/></row>
+		<row><td>ISCEFile</td><td>FileKey</td><td>N</td><td/><td/><td/><td/><td/><td/><td/></row>
+		<row><td>ISCEFile</td><td>FileOption</td><td>N</td><td/><td/><td/><td/><td/><td/><td/></row>
+		<row><td>ISCEFile</td><td>Name</td><td>N</td><td/><td/><td/><td/><td/><td/><td/></row>
+		<row><td>ISCEFile</td><td>Platform</td><td>N</td><td/><td/><td/><td/><td/><td/><td/></row>
+		<row><td>ISCEFile</td><td>Processor</td><td>N</td><td/><td/><td/><td/><td/><td/><td/></row>
+		<row><td>ISCEFile</td><td>Source</td><td>N</td><td/><td/><td/><td/><td/><td/><td/></row>
+		<row><td>ISCEFileExt</td><td>AppKey</td><td>N</td><td/><td/><td/><td/><td/><td/><td/></row>
+		<row><td>ISCEFileExt</td><td>Description</td><td>Y</td><td/><td/><td/><td/><td/><td/><td/></row>
+		<row><td>ISCEFileExt</td><td>ExtKey</td><td>N</td><td/><td/><td/><td/><td/><td/><td/></row>
+		<row><td>ISCEFileExt</td><td>Extension</td><td>N</td><td/><td/><td/><td/><td/><td/><td/></row>
+		<row><td>ISCEFileExt</td><td>FileKey</td><td>N</td><td/><td/><td/><td/><td/><td/><td/></row>
+		<row><td>ISCEFileExt</td><td>IconIndex</td><td>N</td><td/><td/><td/><td/><td/><td/><td/></row>
+		<row><td>ISCEInstall</td><td>CEAppName</td><td>N</td><td/><td/><td/><td/><td/><td/><td/></row>
+		<row><td>ISCEInstall</td><td>CECabs</td><td>N</td><td/><td/><td/><td/><td/><td/><td/></row>
+		<row><td>ISCEInstall</td><td>CEDesktopDir</td><td>N</td><td/><td/><td/><td/><td/><td/><td/></row>
+		<row><td>ISCEInstall</td><td>CEIcoFile</td><td>N</td><td/><td/><td/><td/><td/><td/><td/></row>
+		<row><td>ISCEInstall</td><td>CEIniFileKey</td><td>N</td><td/><td/><td/><td/><td/><td/><td/></row>
+		<row><td>ISCEInstall</td><td>CEInstallKey</td><td>N</td><td/><td/><td/><td/><td/><td/><td/></row>
+		<row><td>ISCEInstall</td><td>Component_</td><td>Y</td><td/><td/><td/><td/><td/><td/><td/></row>
+		<row><td>ISCEInstall</td><td>DeleteMedia</td><td>N</td><td/><td/><td/><td/><td/><td/><td/></row>
+		<row><td>ISCEOtherAppCABs</td><td>AppKey</td><td>N</td><td/><td/><td/><td/><td/><td/><td/></row>
+		<row><td>ISCEOtherAppCABs</td><td>BuildSourcePath</td><td>N</td><td/><td/><td/><td/><td/><td/><td/></row>
+		<row><td>ISCEOtherAppCABs</td><td>FileKey</td><td>N</td><td/><td/><td/><td/><td/><td/><td/></row>
+		<row><td>ISCERegistry</td><td>AppKey</td><td>N</td><td/><td/><td/><td/><td/><td/><td/></row>
+		<row><td>ISCERegistry</td><td>Key</td><td>N</td><td/><td/><td/><td/><td/><td/><td/></row>
+		<row><td>ISCERegistry</td><td>Name</td><td>Y</td><td/><td/><td/><td/><td/><td/><td/></row>
+		<row><td>ISCERegistry</td><td>Overwrite</td><td>N</td><td/><td/><td/><td/><td/><td/><td/></row>
+		<row><td>ISCERegistry</td><td>Platform</td><td>N</td><td/><td/><td/><td/><td/><td/><td/></row>
+		<row><td>ISCERegistry</td><td>Processor</td><td>N</td><td/><td/><td/><td/><td/><td/><td/></row>
+		<row><td>ISCERegistry</td><td>RegKey</td><td>N</td><td/><td/><td/><td/><td/><td/><td/></row>
+		<row><td>ISCERegistry</td><td>Root</td><td>N</td><td/><td/><td/><td/><td/><td/><td/></row>
+		<row><td>ISCERegistry</td><td>Value</td><td>Y</td><td/><td/><td/><td/><td/><td/><td/></row>
+		<row><td>ISCESetupFile</td><td>AppKey</td><td>N</td><td/><td/><td/><td/><td/><td/><td/></row>
+		<row><td>ISCESetupFile</td><td>Name</td><td>N</td><td/><td/><td/><td/><td/><td/><td/></row>
+		<row><td>ISCESetupFile</td><td>Platform</td><td>N</td><td/><td/><td/><td/><td/><td/><td/></row>
+		<row><td>ISCESetupFile</td><td>Processor</td><td>N</td><td/><td/><td/><td/><td/><td/><td/></row>
+		<row><td>ISCESetupFile</td><td>SetupFileKey</td><td>N</td><td/><td/><td/><td/><td/><td/><td/></row>
+		<row><td>ISCESetupFile</td><td>Source</td><td>N</td><td/><td/><td/><td/><td/><td/><td/></row>
+		<row><td>ISCEShtCut</td><td>AppKey</td><td>N</td><td/><td/><td/><td/><td/><td/><td/></row>
+		<row><td>ISCEShtCut</td><td>Destination</td><td>N</td><td/><td/><td/><td/><td/><td/><td/></row>
+		<row><td>ISCEShtCut</td><td>DisplayName</td><td>N</td><td/><td/><td/><td/><td/><td/><td/></row>
+		<row><td>ISCEShtCut</td><td>Platform</td><td>N</td><td/><td/><td/><td/><td/><td/><td/></row>
+		<row><td>ISCEShtCut</td><td>ShtCutKey</td><td>N</td><td/><td/><td/><td/><td/><td/><td/></row>
+		<row><td>ISCEShtCut</td><td>Target</td><td>N</td><td/><td/><td/><td/><td/><td/><td/></row>
+		<row><td>ISComCatalogAttribute</td><td>ISComCatalogObject_</td><td>N</td><td/><td/><td>ISComCatalogObject</td><td>1</td><td>Identifier</td><td/><td>Foreign key into the ISComCatalogObject table.</td></row>
+		<row><td>ISComCatalogAttribute</td><td>ItemName</td><td>N</td><td/><td/><td/><td/><td>Text</td><td/><td>The named attribute for a catalog object.</td></row>
+		<row><td>ISComCatalogAttribute</td><td>ItemValue</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>A value associated with the attribute defined in the ItemName column.</td></row>
+		<row><td>ISComCatalogCollection</td><td>CollectionName</td><td>N</td><td/><td/><td/><td/><td>Text</td><td/><td>A catalog collection name.</td></row>
+		<row><td>ISComCatalogCollection</td><td>ISComCatalogCollection</td><td>N</td><td/><td/><td/><td/><td>Identifier</td><td/><td>A unique key for the ISComCatalogCollection table.</td></row>
+		<row><td>ISComCatalogCollection</td><td>ISComCatalogObject_</td><td>N</td><td/><td/><td>ISComCatalogObject</td><td>1</td><td>Identifier</td><td/><td>Foreign key into the ISComCatalogObject table.</td></row>
+		<row><td>ISComCatalogCollectionObjects</td><td>ISComCatalogCollection_</td><td>N</td><td/><td/><td>ISComCatalogCollection</td><td>1</td><td>Identifier</td><td/><td>A unique key for the ISComCatalogCollection table.</td></row>
+		<row><td>ISComCatalogCollectionObjects</td><td>ISComCatalogObject_</td><td>N</td><td/><td/><td>ISComCatalogObject</td><td>1</td><td>Identifier</td><td/><td>Foreign key into the ISComCatalogObject table.</td></row>
+		<row><td>ISComCatalogObject</td><td>DisplayName</td><td>N</td><td/><td/><td/><td/><td/><td/><td>The display name of a catalog object.</td></row>
+		<row><td>ISComCatalogObject</td><td>ISComCatalogObject</td><td>N</td><td/><td/><td/><td/><td>Identifier</td><td/><td>A unique key for the ISComCatalogObject table.</td></row>
+		<row><td>ISComPlusApplication</td><td>Component_</td><td>N</td><td/><td/><td>Component</td><td>1</td><td>Identifier</td><td/><td>Foreign key into the Component table that a COM+ application belongs to.</td></row>
+		<row><td>ISComPlusApplication</td><td>ComputerName</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>Computer name that a COM+ application belongs to.</td></row>
+		<row><td>ISComPlusApplication</td><td>DepFiles</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>List of the dependent files.</td></row>
+		<row><td>ISComPlusApplication</td><td>ISAttributes</td><td>Y</td><td/><td/><td/><td/><td/><td/><td>InstallShield custom attributes associated with a COM+ application.</td></row>
+		<row><td>ISComPlusApplication</td><td>ISComCatalogObject_</td><td>N</td><td/><td/><td>ISComCatalogObject</td><td>1</td><td>Identifier</td><td/><td>Foreign key into the ISComCatalogObject table.</td></row>
+		<row><td>ISComPlusProxy</td><td>Component_</td><td>Y</td><td/><td/><td>Component</td><td>1</td><td>Identifier</td><td/><td>Foreign key into the Component table that a COM+ application proxy belongs to.</td></row>
+		<row><td>ISComPlusProxy</td><td>DepFiles</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>List of the dependent files.</td></row>
+		<row><td>ISComPlusProxy</td><td>ISAttributes</td><td>Y</td><td/><td/><td/><td/><td/><td/><td>InstallShield custom attributes associated with a COM+ application proxy.</td></row>
+		<row><td>ISComPlusProxy</td><td>ISComPlusApplication_</td><td>N</td><td/><td/><td>ISComPlusApplication</td><td>1</td><td>Identifier</td><td/><td>Foreign key into the ISComPlusApplication table that a COM+ application proxy belongs to.</td></row>
+		<row><td>ISComPlusProxy</td><td>ISComPlusProxy</td><td>N</td><td/><td/><td/><td/><td>Identifier</td><td/><td>A unique key for the ISComPlusProxy table.</td></row>
+		<row><td>ISComponentExtended</td><td>Component_</td><td>N</td><td/><td/><td>Component</td><td>1</td><td>Identifier</td><td/><td>Primary key used to identify a particular component record.</td></row>
+		<row><td>ISComponentExtended</td><td>FTPLocation</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>FTP Location</td></row>
+		<row><td>ISComponentExtended</td><td>FilterProperty</td><td>N</td><td/><td/><td/><td/><td>Identifier</td><td/><td>Property to set if you want to filter a component</td></row>
+		<row><td>ISComponentExtended</td><td>HTTPLocation</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>HTTP Location</td></row>
+		<row><td>ISComponentExtended</td><td>Language</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>Language</td></row>
+		<row><td>ISComponentExtended</td><td>Miscellaneous</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>Miscellaneous</td></row>
+		<row><td>ISComponentExtended</td><td>OS</td><td>Y</td><td/><td/><td/><td/><td/><td/><td>bitwise addition of OSs</td></row>
+		<row><td>ISComponentExtended</td><td>Platforms</td><td>Y</td><td/><td/><td/><td/><td/><td/><td>bitwise addition of Platforms.</td></row>
+		<row><td>ISDLLWrapper</td><td>EntryPoint</td><td>N</td><td/><td/><td/><td/><td>Text</td><td/><td>This is a foreign key to the target column in the CustomAction table</td></row>
+		<row><td>ISDLLWrapper</td><td>Source</td><td>N</td><td/><td/><td/><td/><td>Formatted</td><td/><td>This is column points to the source file for the DLLWrapper Custom Action</td></row>
+		<row><td>ISDLLWrapper</td><td>Target</td><td>N</td><td/><td/><td/><td/><td>Text</td><td/><td>The function signature</td></row>
+		<row><td>ISDLLWrapper</td><td>Type</td><td>Y</td><td/><td/><td/><td/><td/><td/><td>Type</td></row>
+		<row><td>ISDRMFile</td><td>File_</td><td>Y</td><td/><td/><td>File</td><td>1</td><td>Identifier</td><td/><td>Foreign key into File table.  A null value will cause a build warning.</td></row>
+		<row><td>ISDRMFile</td><td>ISDRMFile</td><td>N</td><td/><td/><td/><td/><td>Identifier</td><td/><td>Unique identifier for this item.</td></row>
+		<row><td>ISDRMFile</td><td>ISDRMLicense_</td><td>Y</td><td/><td/><td>ISDRMLicense</td><td>1</td><td>Identifier</td><td/><td>Foreign key referencing License that packages this file.</td></row>
+		<row><td>ISDRMFile</td><td>Shell</td><td>N</td><td/><td/><td/><td/><td>Text</td><td/><td>Text indicating the activation shell used at runtime.</td></row>
+		<row><td>ISDRMFileAttribute</td><td>ISDRMFile_</td><td>N</td><td/><td/><td>ISDRMFile</td><td>1</td><td>Identifier</td><td/><td>Primary foreign key into ISDRMFile table.</td></row>
+		<row><td>ISDRMFileAttribute</td><td>Property</td><td>N</td><td/><td/><td/><td/><td>Text</td><td/><td>The name of the attribute</td></row>
+		<row><td>ISDRMFileAttribute</td><td>Value</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>The value of the attribute</td></row>
+		<row><td>ISDRMLicense</td><td>Attributes</td><td>Y</td><td/><td/><td/><td/><td>Number</td><td/><td>Bitwise field used to specify binary attributes of this license.</td></row>
+		<row><td>ISDRMLicense</td><td>Description</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>An internal description of this license.</td></row>
+		<row><td>ISDRMLicense</td><td>ISDRMLicense</td><td>N</td><td/><td/><td/><td/><td>Identifier</td><td/><td>Unique key identifying the license record.</td></row>
+		<row><td>ISDRMLicense</td><td>LicenseNumber</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>The license number.</td></row>
+		<row><td>ISDRMLicense</td><td>ProjectVersion</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>The version of the project that this license is tied to.</td></row>
+		<row><td>ISDRMLicense</td><td>RequestCode</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>The request code.</td></row>
+		<row><td>ISDRMLicense</td><td>ResponseCode</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>The response code.</td></row>
+		<row><td>ISDependency</td><td>Exclude</td><td>Y</td><td/><td/><td/><td/><td/><td/><td/></row>
+		<row><td>ISDependency</td><td>ISDependency</td><td>Y</td><td/><td/><td/><td/><td/><td/><td/></row>
+		<row><td>ISDisk1File</td><td>Disk</td><td>Y</td><td/><td/><td/><td/><td/><td>-1;0;1</td><td>Used to differentiate between disk1(1), last disk(-1), and other(0).</td></row>
+		<row><td>ISDisk1File</td><td>ISBuildSourcePath</td><td>N</td><td/><td/><td/><td/><td>Text</td><td/><td>Full path of file to be copied to Disk1 folder</td></row>
+		<row><td>ISDisk1File</td><td>ISDisk1File</td><td>N</td><td/><td/><td/><td/><td>Identifier</td><td/><td>Primary key for ISDisk1File table</td></row>
+		<row><td>ISDynamicFile</td><td>Component_</td><td>N</td><td/><td/><td>Component</td><td>1</td><td>Identifier</td><td/><td>Foreign key referencing Component that controls the file.</td></row>
+		<row><td>ISDynamicFile</td><td>ExcludeFiles</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>Wildcards for excluded files.</td></row>
+		<row><td>ISDynamicFile</td><td>ISAttributes</td><td>Y</td><td/><td/><td/><td/><td/><td>0;1;2;3</td><td>This is used to store Installshield custom properties of a dynamic filet.  Currently the only one is SelfRegister.</td></row>
+		<row><td>ISDynamicFile</td><td>IncludeFiles</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>Wildcards for included files.</td></row>
+		<row><td>ISDynamicFile</td><td>IncludeFlags</td><td>Y</td><td/><td/><td/><td/><td/><td/><td>Include flags.</td></row>
+		<row><td>ISDynamicFile</td><td>SourceFolder</td><td>N</td><td/><td/><td/><td/><td>Text</td><td/><td>Full path, the category is of Text instead of Path because of potential use of path variables.</td></row>
+		<row><td>ISFeatureMergeModuleExcludes</td><td>Feature_</td><td>N</td><td/><td/><td/><td/><td>Identifier</td><td/><td>Foreign key into Feature table.</td></row>
+		<row><td>ISFeatureMergeModuleExcludes</td><td>Language</td><td>N</td><td/><td/><td/><td/><td/><td/><td>Foreign key into ISMergeModule table.</td></row>
+		<row><td>ISFeatureMergeModuleExcludes</td><td>ModuleID</td><td>N</td><td/><td/><td/><td/><td>Identifier</td><td/><td>Foreign key into ISMergeModule table.
+</td></row>
+		<row><td>ISFeatureMergeModules</td><td>Feature_</td><td>N</td><td/><td/><td>Feature</td><td>1</td><td>Identifier</td><td/><td>Foreign key into Feature table.</td></row>
+		<row><td>ISFeatureMergeModules</td><td>ISMergeModule_</td><td>N</td><td/><td/><td>ISMergeModule</td><td>1</td><td>Text</td><td/><td>Foreign key into ISMergeModule table.
+</td></row>
+		<row><td>ISFeatureMergeModules</td><td>Language_</td><td>N</td><td/><td/><td>ISMergeModule</td><td>2</td><td/><td/><td>Foreign key into ISMergeModule table.</td></row>
+		<row><td>ISIISCommon</td><td>AnonyPasswrd</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>Password for anonymous access</td></row>
+		<row><td>ISIISCommon</td><td>AnonyUserName</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>User name for anonymous access</td></row>
+		<row><td>ISIISCommon</td><td>AppName</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>AppName of this VRoot</td></row>
+		<row><td>ISIISCommon</td><td>Attributes</td><td>N</td><td/><td/><td/><td/><td>Number</td><td/><td>Attributes for this IIS node</td></row>
+		<row><td>ISIISCommon</td><td>CustomErrors</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>Delimited list of custom errors</td></row>
+		<row><td>ISIISCommon</td><td>DefDoc</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>Localizable Defeault Doc</td></row>
+		<row><td>ISIISCommon</td><td>DisplayName</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>Localizable Virtual Root Name</td></row>
+		<row><td>ISIISCommon</td><td>ISIISCommon</td><td>N</td><td/><td/><td/><td/><td>Identifier</td><td/><td>Primary key used to identify a particular  record.</td></row>
+		<row><td>ISIISCommon</td><td>ISIISCommon_Parent</td><td>Y</td><td/><td/><td>ISIISCommon</td><td>1</td><td>Identifier</td><td/><td>This record's parent record.</td></row>
+		<row><td>ISIISCommon</td><td>RootDir</td><td>N</td><td/><td/><td/><td/><td>Text</td><td/><td>Root directory for this IIS Node</td></row>
+		<row><td>ISIISCommon</td><td>SSLCert</td><td>Y</td><td/><td/><td>Binary</td><td>1</td><td>Identifier</td><td/><td>Foreign key into the binary table.</td></row>
+		<row><td>ISIISCommon</td><td>ScriptTimeout</td><td>Y</td><td/><td/><td/><td/><td>Number</td><td/><td>ASP Script Timeout</td></row>
+		<row><td>ISIISCommon</td><td>SessionTimeout</td><td>Y</td><td/><td/><td/><td/><td>Number</td><td/><td>Session Timeout</td></row>
+		<row><td>ISIISMetaData</td><td>ISIISCommon_</td><td>N</td><td/><td/><td>ISIISCommon</td><td>1</td><td>Identifier</td><td/><td>Foreign key into ISIISCommon table</td></row>
+		<row><td>ISIISMetaData</td><td>MetaDataAttributes</td><td>N</td><td/><td/><td/><td/><td/><td/><td>This is the dwMDAttributes item in the METADATA_RECORD structure</td></row>
+		<row><td>ISIISMetaData</td><td>MetaDataProp</td><td>Y</td><td/><td/><td/><td/><td/><td/><td>This is the dwMDIdentifier item in the METADATA_RECORD structure</td></row>
+		<row><td>ISIISMetaData</td><td>MetaDataType</td><td>Y</td><td/><td/><td/><td/><td/><td/><td>This is the dwMDDataType item in the METADATA_RECORD structure</td></row>
+		<row><td>ISIISMetaData</td><td>MetaDataUserType</td><td>N</td><td/><td/><td/><td/><td/><td/><td>This is the dwMDUserType item in the METADATA_RECORD structure</td></row>
+		<row><td>ISIISMetaData</td><td>MetaDataValue</td><td>N</td><td/><td/><td/><td/><td>Text</td><td/><td>This is the pbMDData  item in the METADATA_RECORD structure</td></row>
+		<row><td>ISIISMetaData</td><td>Order</td><td>N</td><td/><td/><td/><td/><td/><td/><td>Use this column to order the meta data properties.</td></row>
+		<row><td>ISInstallScriptAction</td><td>EntryPoint</td><td>N</td><td/><td/><td/><td/><td>Text</td><td/><td>This is a foreign key to the target column in the CustomAction table</td></row>
+		<row><td>ISInstallScriptAction</td><td>Source</td><td>N</td><td/><td/><td/><td/><td>Formatted</td><td/><td>This is column points to the source file for the DLLWrapper Custom Action</td></row>
+		<row><td>ISInstallScriptAction</td><td>Target</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>The function signature</td></row>
+		<row><td>ISInstallScriptAction</td><td>Type</td><td>Y</td><td/><td/><td/><td/><td/><td/><td>Type</td></row>
+		<row><td>ISLanguage</td><td>ISLanguage</td><td>N</td><td/><td/><td/><td/><td>Language</td><td/><td>This is the language ID.</td></row>
+		<row><td>ISLanguage</td><td>Included</td><td>Y</td><td/><td/><td/><td/><td/><td>0;1</td><td>Specify whether this language should be included.</td></row>
+		<row><td>ISLinkerLibrary</td><td>ISLinkerLibrary</td><td>N</td><td/><td/><td/><td/><td>Identifier</td><td/><td>Unique identifier for the link library.
+</td></row>
+		<row><td>ISLinkerLibrary</td><td>Library</td><td>N</td><td/><td/><td/><td/><td>Text</td><td/><td>Full path of the object library (.obl file).
+</td></row>
+		<row><td>ISLinkerLibrary</td><td>Order</td><td>N</td><td/><td/><td/><td/><td/><td/><td>Order of the Library</td></row>
+		<row><td>ISLocalControl</td><td>Attributes</td><td>Y</td><td/><td/><td/><td/><td/><td/><td>A 32-bit word that specifies the attribute flags to be applied to this control.</td></row>
+		<row><td>ISLocalControl</td><td>Binary_</td><td>Y</td><td/><td/><td>Binary</td><td>1</td><td>Identifier</td><td/><td>External key to the Binary table.</td></row>
+		<row><td>ISLocalControl</td><td>Control_</td><td>N</td><td/><td/><td>Control</td><td>2</td><td>Identifier</td><td/><td>Name of the control. This name must be unique within a dialog, but can repeat on different dialogs.</td></row>
+		<row><td>ISLocalControl</td><td>Dialog_</td><td>N</td><td/><td/><td>Dialog</td><td>1</td><td>Identifier</td><td/><td>External key to the Dialog table, name of the dialog.</td></row>
+		<row><td>ISLocalControl</td><td>Height</td><td>Y</td><td/><td/><td/><td/><td/><td/><td>Height of the bounding rectangle of the control.</td></row>
+		<row><td>ISLocalControl</td><td>ISBuildSourcePath</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>Full path to .rtf file for scrollable text control</td></row>
+		<row><td>ISLocalControl</td><td>ISLanguage_</td><td>N</td><td/><td/><td>ISLanguage</td><td>1</td><td>Language</td><td/><td>This is a foreign key to the ISLanguage table.</td></row>
+		<row><td>ISLocalControl</td><td>Width</td><td>Y</td><td/><td/><td/><td/><td/><td/><td>Width of the bounding rectangle of the control.</td></row>
+		<row><td>ISLocalControl</td><td>X</td><td>Y</td><td/><td/><td/><td/><td/><td/><td>Horizontal coordinate of the upper left corner of the bounding rectangle of the control.</td></row>
+		<row><td>ISLocalControl</td><td>Y</td><td>Y</td><td/><td/><td/><td/><td/><td/><td>Vertical coordinate of the upper left corner of the bounding rectangle of the control.</td></row>
+		<row><td>ISLocalDialog</td><td>Attributes</td><td>Y</td><td/><td/><td/><td/><td/><td/><td>A 32-bit word that specifies the attribute flags to be applied to this dialog.</td></row>
+		<row><td>ISLocalDialog</td><td>Dialog_</td><td>Y</td><td/><td/><td>Dialog</td><td>1</td><td>Identifier</td><td/><td>Name of the dialog.</td></row>
+		<row><td>ISLocalDialog</td><td>Height</td><td>N</td><td>0</td><td>32767</td><td/><td/><td/><td/><td>Height of the bounding rectangle of the dialog.</td></row>
+		<row><td>ISLocalDialog</td><td>ISLanguage_</td><td>Y</td><td/><td/><td>ISLanguage</td><td>1</td><td>Language</td><td/><td>This is a foreign key to the ISLanguage table.</td></row>
+		<row><td>ISLocalDialog</td><td>TextStyle_</td><td>Y</td><td/><td/><td/><td/><td>Identifier</td><td/><td>Foreign Key into TextStyle table, only used in Script Based Projects.</td></row>
+		<row><td>ISLocalDialog</td><td>Width</td><td>N</td><td>0</td><td>32767</td><td/><td/><td/><td/><td>Width of the bounding rectangle of the dialog.</td></row>
+		<row><td>ISLocalRadioButton</td><td>Height</td><td>N</td><td>0</td><td>32767</td><td/><td/><td/><td/><td>The height of the button.</td></row>
+		<row><td>ISLocalRadioButton</td><td>ISLanguage_</td><td>N</td><td/><td/><td>ISLanguage</td><td>1</td><td>Language</td><td/><td>This is a foreign key to the ISLanguage table.</td></row>
+		<row><td>ISLocalRadioButton</td><td>Order</td><td>N</td><td>1</td><td>32767</td><td>RadioButton</td><td>2</td><td/><td/><td>A positive integer used to determine the ordering of the items within one list..The integers do not have to be consecutive.</td></row>
+		<row><td>ISLocalRadioButton</td><td>Property</td><td>N</td><td/><td/><td>RadioButton</td><td>1</td><td>Identifier</td><td/><td>A named property to be tied to this radio button. All the buttons tied to the same property become part of the same group.</td></row>
+		<row><td>ISLocalRadioButton</td><td>Width</td><td>N</td><td>0</td><td>32767</td><td/><td/><td/><td/><td>The width of the button.</td></row>
+		<row><td>ISLocalRadioButton</td><td>X</td><td>N</td><td>0</td><td>32767</td><td/><td/><td/><td/><td>The horizontal coordinate of the upper left corner of the bounding rectangle of the radio button.</td></row>
+		<row><td>ISLocalRadioButton</td><td>Y</td><td>N</td><td>0</td><td>32767</td><td/><td/><td/><td/><td>The vertical coordinate of the upper left corner of the bounding rectangle of the radio button.</td></row>
+		<row><td>ISLogicalDisk</td><td>Cabinet</td><td>Y</td><td/><td/><td/><td/><td>Cabinet</td><td/><td>If some or all of the files stored on the media are compressed in a cabinet, the name of that cabinet.</td></row>
+		<row><td>ISLogicalDisk</td><td>DiskId</td><td>N</td><td>1</td><td>32767</td><td/><td/><td/><td/><td>Primary key, integer to determine sort order for table.</td></row>
+		<row><td>ISLogicalDisk</td><td>DiskPrompt</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>Disk name: the visible text actually printed on the disk.  This will be used to prompt the user when this disk needs to be inserted.</td></row>
+		<row><td>ISLogicalDisk</td><td>ISProductConfiguration_</td><td>N</td><td/><td/><td>ISProductConfiguration</td><td>1</td><td>Text</td><td/><td>Foreign key into the ISProductConfiguration table.</td></row>
+		<row><td>ISLogicalDisk</td><td>ISRelease_</td><td>N</td><td/><td/><td>ISRelease</td><td>1</td><td>Text</td><td/><td>Foreign key into the ISRelease table.</td></row>
+		<row><td>ISLogicalDisk</td><td>LastSequence</td><td>N</td><td>0</td><td>32767</td><td/><td/><td/><td/><td>File sequence number for the last file for this media.</td></row>
+		<row><td>ISLogicalDisk</td><td>Source</td><td>Y</td><td/><td/><td/><td/><td>Property</td><td/><td>The property defining the location of the cabinet file.</td></row>
+		<row><td>ISLogicalDisk</td><td>VolumeLabel</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>The label attributed to the volume.</td></row>
+		<row><td>ISLogicalDiskFeatures</td><td>Feature_</td><td>Y</td><td/><td/><td>Feature</td><td>1</td><td>Identifier</td><td/><td>Required foreign key into the Feature Table,</td></row>
+		<row><td>ISLogicalDiskFeatures</td><td>ISAttributes</td><td>Y</td><td/><td/><td/><td/><td/><td/><td>This is used to store Installshield custom properties, like Compressed, etc.</td></row>
+		<row><td>ISLogicalDiskFeatures</td><td>ISLogicalDisk_</td><td>N</td><td>1</td><td>32767</td><td>ISLogicalDisk</td><td>1</td><td>Identifier</td><td/><td>Foreign key into the ISLogicalDisk table.</td></row>
+		<row><td>ISLogicalDiskFeatures</td><td>ISProductConfiguration_</td><td>N</td><td/><td/><td>ISProductConfiguration</td><td>1</td><td>Text</td><td/><td>Foreign key into the ISProductConfiguration table.</td></row>
+		<row><td>ISLogicalDiskFeatures</td><td>ISRelease_</td><td>N</td><td/><td/><td>ISRelease</td><td>1</td><td>Text</td><td/><td>Foreign key into the ISRelease table.</td></row>
+		<row><td>ISLogicalDiskFeatures</td><td>Sequence</td><td>N</td><td>0</td><td>32767</td><td/><td/><td/><td/><td>File sequence number for the file for this media.</td></row>
+		<row><td>ISMergeModule</td><td>Destination</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>Destination.
+</td></row>
+		<row><td>ISMergeModule</td><td>ISAttributes</td><td>Y</td><td/><td/><td/><td/><td/><td/><td>This is used to store Installshield custom properties of a merge module.</td></row>
+		<row><td>ISMergeModule</td><td>ISMergeModule</td><td>N</td><td/><td/><td/><td/><td>Text</td><td/><td>The GUID identifying the merge module.
+</td></row>
+		<row><td>ISMergeModule</td><td>Language</td><td>N</td><td/><td/><td/><td/><td/><td/><td>Default decimal language of module.</td></row>
+		<row><td>ISMergeModule</td><td>Name</td><td>N</td><td/><td/><td/><td/><td>Text</td><td/><td>Name of the merge module.
+</td></row>
+		<row><td>ISMergeModuleCfgValues</td><td>Attributes</td><td>Y</td><td/><td/><td/><td/><td/><td/><td>Attributes (from configurable merge module)</td></row>
+		<row><td>ISMergeModuleCfgValues</td><td>ContextData</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>ContextData  (from configurable merge module)</td></row>
+		<row><td>ISMergeModuleCfgValues</td><td>DefaultValue</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>DefaultValue  (from configurable merge module)</td></row>
+		<row><td>ISMergeModuleCfgValues</td><td>Description</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>Description (from configurable merge module)</td></row>
+		<row><td>ISMergeModuleCfgValues</td><td>DisplayName</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>DisplayName (from configurable merge module)</td></row>
+		<row><td>ISMergeModuleCfgValues</td><td>Format</td><td>N</td><td/><td/><td/><td/><td/><td/><td>Format (from configurable merge module)</td></row>
+		<row><td>ISMergeModuleCfgValues</td><td>HelpKeyword</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>HelpKeyword (from configurable merge module)</td></row>
+		<row><td>ISMergeModuleCfgValues</td><td>HelpLocation</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>HelpLocation (from configurable merge module)</td></row>
+		<row><td>ISMergeModuleCfgValues</td><td>ISMergeModule_</td><td>N</td><td/><td/><td>ISMergeModule</td><td>1</td><td>Text</td><td/><td>The module signature, a foreign key into the ISMergeModule table</td></row>
+		<row><td>ISMergeModuleCfgValues</td><td>Language_</td><td>N</td><td/><td/><td>ISMergeModule</td><td>2</td><td/><td/><td>Default decimal language of module.</td></row>
+		<row><td>ISMergeModuleCfgValues</td><td>ModuleConfiguration_</td><td>N</td><td/><td/><td/><td/><td>Identifier</td><td/><td>Identifier, foreign key into ModuleConfiguration table (ModuleConfiguration.Name)</td></row>
+		<row><td>ISMergeModuleCfgValues</td><td>Type</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>Type (from configurable merge module)</td></row>
+		<row><td>ISMergeModuleCfgValues</td><td>Value</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>Value for this item.</td></row>
+		<row><td>ISObject</td><td>Language</td><td>N</td><td/><td/><td/><td/><td>Text</td><td/><td/></row>
+		<row><td>ISObject</td><td>ObjectName</td><td>N</td><td/><td/><td/><td/><td>Text</td><td/><td/></row>
+		<row><td>ISObjectProperty</td><td>IncludeInBuild</td><td>Y</td><td/><td/><td/><td/><td/><td/><td>Boolean, 0 for false non 0 for true</td></row>
+		<row><td>ISObjectProperty</td><td>ObjectName</td><td>Y</td><td/><td/><td>ISObject</td><td>1</td><td>Text</td><td/><td/></row>
+		<row><td>ISObjectProperty</td><td>Property</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td/></row>
+		<row><td>ISObjectProperty</td><td>Value</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td/></row>
+		<row><td>ISPalmApp</td><td>Component</td><td>N</td><td/><td/><td>Component</td><td>1</td><td/><td/><td/></row>
+		<row><td>ISPalmApp</td><td>PalmApp</td><td>N</td><td/><td/><td/><td/><td/><td/><td/></row>
+		<row><td>ISPalmAppFile</td><td>Destination</td><td>N</td><td/><td/><td/><td/><td/><td/><td/></row>
+		<row><td>ISPalmAppFile</td><td>FileKey</td><td>N</td><td/><td/><td>File</td><td>1</td><td/><td/><td/></row>
+		<row><td>ISPalmAppFile</td><td>PalmApp</td><td>N</td><td/><td/><td>ISPalmApp</td><td>1</td><td/><td/><td/></row>
+		<row><td>ISPatchConfigImage</td><td>PatchConfiguration_</td><td>Y</td><td/><td/><td>ISPatchConfiguration</td><td>1</td><td>Text</td><td/><td>Foreign key to the ISPatchConfigurationTable</td></row>
+		<row><td>ISPatchConfigImage</td><td>UpgradedImage_</td><td>N</td><td/><td/><td>ISUpgradedImage</td><td>1</td><td>Text</td><td/><td>Foreign key to the ISUpgradedImageTable</td></row>
+		<row><td>ISPatchConfiguration</td><td>Attributes</td><td>Y</td><td/><td/><td/><td/><td/><td/><td>PatchConfiguration attributes</td></row>
+		<row><td>ISPatchConfiguration</td><td>CanPCDiffer</td><td>N</td><td/><td/><td/><td/><td/><td/><td>This is determine whether Product Codes may differ</td></row>
+		<row><td>ISPatchConfiguration</td><td>CanPVDiffer</td><td>N</td><td/><td/><td/><td/><td/><td/><td>This is determine whether the Major Product Version may differ</td></row>
+		<row><td>ISPatchConfiguration</td><td>EnablePatchCache</td><td>N</td><td/><td/><td/><td/><td/><td/><td>This is determine whether to Enable Patch cacheing</td></row>
+		<row><td>ISPatchConfiguration</td><td>Flags</td><td>N</td><td/><td/><td/><td/><td/><td/><td>Patching API Flags</td></row>
+		<row><td>ISPatchConfiguration</td><td>IncludeWholeFiles</td><td>N</td><td/><td/><td/><td/><td/><td/><td>This is determine whether to build a binary level patch</td></row>
+		<row><td>ISPatchConfiguration</td><td>LeaveDecompressed</td><td>N</td><td/><td/><td/><td/><td/><td/><td>This is determine whether to leave intermediate files devcompressed when finished</td></row>
+		<row><td>ISPatchConfiguration</td><td>MinMsiVersion</td><td>N</td><td/><td/><td/><td/><td/><td/><td>Minimum Required MSI Version</td></row>
+		<row><td>ISPatchConfiguration</td><td>Name</td><td>N</td><td/><td/><td/><td/><td>Text</td><td/><td>Name of the Patch Configuration</td></row>
+		<row><td>ISPatchConfiguration</td><td>OptimizeForSize</td><td>N</td><td/><td/><td/><td/><td/><td/><td>This is determine whether to Optimize for large files</td></row>
+		<row><td>ISPatchConfiguration</td><td>OutputPath</td><td>N</td><td/><td/><td/><td/><td>Text</td><td/><td>Build Location</td></row>
+		<row><td>ISPatchConfiguration</td><td>PatchCacheDir</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>Directory to recieve the Patch Cache information</td></row>
+		<row><td>ISPatchConfiguration</td><td>PatchGuid</td><td>N</td><td/><td/><td/><td/><td>Text</td><td/><td>Unique Patch Identifier</td></row>
+		<row><td>ISPatchConfiguration</td><td>PatchGuidsToReplace</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>List Of Patch Guids to unregister</td></row>
+		<row><td>ISPatchConfiguration</td><td>TargetProductCodes</td><td>N</td><td/><td/><td/><td/><td>Text</td><td/><td>List Of target Product Codes</td></row>
+		<row><td>ISPatchConfigurationProperty</td><td>ISPatchConfiguration_</td><td>Y</td><td/><td/><td>ISPatchConfiguration</td><td>1</td><td>Text</td><td/><td>Name of the Patch Configuration</td></row>
+		<row><td>ISPatchConfigurationProperty</td><td>Property</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>Name of the Patch Configuration Property value</td></row>
+		<row><td>ISPatchConfigurationProperty</td><td>Value</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>Value of the Patch Configuration Property</td></row>
+		<row><td>ISPatchExternalFile</td><td>FileKey</td><td>N</td><td/><td/><td/><td/><td>Text</td><td/><td>Filekey</td></row>
+		<row><td>ISPatchExternalFile</td><td>FilePath</td><td>N</td><td/><td/><td/><td/><td>Text</td><td/><td>Filepath</td></row>
+		<row><td>ISPatchExternalFile</td><td>ISUpgradedImage_</td><td>N</td><td/><td/><td>ISUpgradedImage</td><td>1</td><td>Text</td><td/><td>Foreign key to the isupgraded image table</td></row>
+		<row><td>ISPatchExternalFile</td><td>Name</td><td>N</td><td/><td/><td/><td/><td>Text</td><td/><td>Uniqu name to identify this record.</td></row>
+		<row><td>ISPatchWholeFile</td><td>Component</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>Component containing file key</td></row>
+		<row><td>ISPatchWholeFile</td><td>FileKey</td><td>N</td><td/><td/><td/><td/><td>Text</td><td/><td>Key of file to be included as whole</td></row>
+		<row><td>ISPatchWholeFile</td><td>UpgradedImage</td><td>N</td><td/><td/><td>ISUpgradedImage</td><td>1</td><td>Text</td><td/><td>Foreign key to ISUpgradedImage Table</td></row>
+		<row><td>ISPathVariable</td><td>ISPathVariable</td><td>N</td><td/><td/><td/><td/><td/><td/><td>The name of the path variable.</td></row>
+		<row><td>ISPathVariable</td><td>TestValue</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>The test value of the path variable.</td></row>
+		<row><td>ISPathVariable</td><td>Type</td><td>N</td><td/><td/><td/><td/><td/><td>1;2;4;8</td><td>The type of the path variable.</td></row>
+		<row><td>ISPathVariable</td><td>Value</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>The value of the path variable.</td></row>
+		<row><td>ISProductConfiguration</td><td>GeneratePackageCode</td><td>Y</td><td/><td/><td/><td/><td>Number</td><td>0;1</td><td>Indicates whether or not to generate a package code.
+</td></row>
+		<row><td>ISProductConfiguration</td><td>ISProductConfiguration</td><td>N</td><td/><td/><td/><td/><td>Text</td><td/><td>The name of the product configuration.
+</td></row>
+		<row><td>ISProductConfiguration</td><td>ProductConfigurationFlags</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>Product configuration (release) flags.
+</td></row>
+		<row><td>ISProductConfigurationInstance</td><td>ISProductConfiguration_</td><td>N</td><td/><td/><td>ISProductConfiguration</td><td>1</td><td>Text</td><td/><td>Foreign key into the ISProductConfiguration table.
+</td></row>
+		<row><td>ISProductConfigurationInstance</td><td>InstanceId</td><td>N</td><td>0</td><td>32767</td><td/><td/><td/><td/><td>Identifies the instance number of this instance. This value is stored in the Property InstanceId.</td></row>
+		<row><td>ISProductConfigurationInstance</td><td>Property</td><td>N</td><td/><td/><td/><td/><td>Text</td><td/><td>Product Congiuration property name</td></row>
+		<row><td>ISProductConfigurationInstance</td><td>Value</td><td>N</td><td/><td/><td/><td/><td>Text</td><td/><td>String value for property.</td></row>
+		<row><td>ISProductConfigurationProperty</td><td>ISProductConfiguration_</td><td>N</td><td/><td/><td>ISProductConfiguration</td><td>1</td><td>Text</td><td/><td>Foreign key into the ISProductConfiguration table.
+</td></row>
+		<row><td>ISProductConfigurationProperty</td><td>Property</td><td>N</td><td/><td/><td>Property</td><td>1</td><td>Text</td><td/><td>Product Congiuration property name</td></row>
+		<row><td>ISProductConfigurationProperty</td><td>Value</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>String value for property. Never null or empty.
+
+
+
+</td></row>
+		<row><td>ISRelease</td><td>Attributes</td><td>N</td><td/><td/><td/><td/><td/><td/><td>Bitfield holding boolean values for various release attributes.</td></row>
+		<row><td>ISRelease</td><td>BuildLocation</td><td>N</td><td/><td/><td/><td/><td>Text</td><td/><td>Build location.</td></row>
+		<row><td>ISRelease</td><td>CDBrowser</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>Demoshield browser location.</td></row>
+		<row><td>ISRelease</td><td>DefaultLanguage</td><td>N</td><td/><td/><td/><td/><td>Language</td><td/><td>Default language for setup.</td></row>
+		<row><td>ISRelease</td><td>DigitalPVK</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>Digital signing private key (.pvk) file.</td></row>
+		<row><td>ISRelease</td><td>DigitalSPC</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>Digital signing Software Publisher Certificate (.spc) file.</td></row>
+		<row><td>ISRelease</td><td>DigitalURL</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>Digital signing URL.</td></row>
+		<row><td>ISRelease</td><td>DiskClusterSize</td><td>N</td><td/><td/><td/><td/><td/><td/><td>Disk cluster size.</td></row>
+		<row><td>ISRelease</td><td>DiskSize</td><td>N</td><td/><td/><td/><td/><td>Text</td><td/><td>Disk size.</td></row>
+		<row><td>ISRelease</td><td>DiskSizeUnit</td><td>N</td><td/><td/><td/><td/><td/><td>0;1;2</td><td>Disk size units (KB or MB).</td></row>
+		<row><td>ISRelease</td><td>DiskSpanning</td><td>N</td><td/><td/><td/><td/><td/><td>0;1;2</td><td>Disk spanning (automatic, enforce size, etc.).</td></row>
+		<row><td>ISRelease</td><td>DotNetBuildConfiguration</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>Build Configuration for .NET solutions.</td></row>
+		<row><td>ISRelease</td><td>ISProductConfiguration_</td><td>N</td><td/><td/><td>ISProductConfiguration</td><td>1</td><td>Text</td><td/><td>Foreign key into the ISProductConfiguration table.</td></row>
+		<row><td>ISRelease</td><td>ISRelease</td><td>N</td><td/><td/><td/><td/><td>Text</td><td/><td>The name of the release.
+</td></row>
+		<row><td>ISRelease</td><td>ISSetupPrerequisiteLocation</td><td>Y</td><td/><td/><td/><td/><td/><td>0;1;2</td><td>Location the Setup Prerequisites will be placed in</td></row>
+		<row><td>ISRelease</td><td>MediaLocation</td><td>N</td><td/><td/><td/><td/><td>Text</td><td/><td>Media location on disk.</td></row>
+		<row><td>ISRelease</td><td>MsiCommandLine</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>Command line passed to the msi package from setup.exe</td></row>
+		<row><td>ISRelease</td><td>MsiSourceType</td><td>N</td><td>-1</td><td>4</td><td/><td/><td/><td/><td>MSI media source type.</td></row>
+		<row><td>ISRelease</td><td>PackageName</td><td>N</td><td/><td/><td/><td/><td>Text</td><td/><td>Package name.</td></row>
+		<row><td>ISRelease</td><td>Password</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>Password.</td></row>
+		<row><td>ISRelease</td><td>Platforms</td><td>N</td><td/><td/><td/><td/><td>Text</td><td/><td>Platforms supported (Intel, Alpha, etc.).</td></row>
+		<row><td>ISRelease</td><td>ReleaseFlags</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>Release flags.</td></row>
+		<row><td>ISRelease</td><td>ReleaseType</td><td>N</td><td/><td/><td/><td/><td/><td>1;2;4</td><td>Release type (single, uncompressed, etc.).</td></row>
+		<row><td>ISRelease</td><td>SupportedLanguagesData</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>Languages supported (for component filtering).</td></row>
+		<row><td>ISRelease</td><td>SupportedLanguagesUI</td><td>N</td><td/><td/><td/><td/><td>Text</td><td/><td>UI languages supported.</td></row>
+		<row><td>ISRelease</td><td>SupportedOSs</td><td>N</td><td/><td/><td/><td/><td/><td/><td>Indicate which operating systmes are supported.</td></row>
+		<row><td>ISRelease</td><td>SynchMsi</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>MSI file to synchronize file keys and other data with (patch-like functionality).</td></row>
+		<row><td>ISRelease</td><td>Type</td><td>N</td><td>0</td><td>6</td><td/><td/><td/><td/><td>Release type (CDROM, Network, etc.).</td></row>
+		<row><td>ISRelease</td><td>URLLocation</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>Media location via URL.</td></row>
+		<row><td>ISRelease</td><td>VersionCopyright</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>Version stamp information.</td></row>
+		<row><td>ISReleaseExtended</td><td>Attributes</td><td>Y</td><td/><td/><td/><td/><td/><td/><td>Bitfield holding boolean values for various release attributes.</td></row>
+		<row><td>ISReleaseExtended</td><td>CertPassword</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>Digital certificate password</td></row>
+		<row><td>ISReleaseExtended</td><td>DigitalCertificateDBaseNS</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>Path to cerificate database for Netscape digital  signature</td></row>
+		<row><td>ISReleaseExtended</td><td>DigitalCertificateIdNS</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>Path to cerificate ID for Netscape digital  signature</td></row>
+		<row><td>ISReleaseExtended</td><td>DigitalCertificatePasswordNS</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>Password for Netscape digital  signature</td></row>
+		<row><td>ISReleaseExtended</td><td>DotNetBaseLanguage</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>Base Languge of .NET Redist</td></row>
+		<row><td>ISReleaseExtended</td><td>DotNetFxCmdLine</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>Command Line to pass to DotNetFx.exe</td></row>
+		<row><td>ISReleaseExtended</td><td>DotNetLangPackCmdLine</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>Command Line to pass to LangPack.exe</td></row>
+		<row><td>ISReleaseExtended</td><td>DotNetLangaugePacks</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>.NET Redist language packs to include</td></row>
+		<row><td>ISReleaseExtended</td><td>DotNetRedistLocation</td><td>Y</td><td>0</td><td>3</td><td/><td/><td/><td/><td>Location of .NET framework Redist (Web, SetupExe, Source, None)</td></row>
+		<row><td>ISReleaseExtended</td><td>DotNetRedistURL</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>URL to .NET framework Redist</td></row>
+		<row><td>ISReleaseExtended</td><td>DotNetVersion</td><td>Y</td><td>0</td><td>1</td><td/><td/><td/><td/><td>Version of .NET framework Redist (1.0, 1.1)</td></row>
+		<row><td>ISReleaseExtended</td><td>EngineLocation</td><td>Y</td><td>0</td><td>2</td><td/><td/><td/><td/><td>Location of msi engine (Web, SetupExe...)</td></row>
+		<row><td>ISReleaseExtended</td><td>ISEngineLocation</td><td>Y</td><td>0</td><td>2</td><td/><td/><td/><td/><td>Location of ISScript  engine (Web, SetupExe...)</td></row>
+		<row><td>ISReleaseExtended</td><td>ISEngineURL</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>URL to InstallShield scripting engine</td></row>
+		<row><td>ISReleaseExtended</td><td>ISProductConfiguration_</td><td>N</td><td/><td/><td/><td/><td>Text</td><td/><td>Foreign key into the ISProductConfiguration table.</td></row>
+		<row><td>ISReleaseExtended</td><td>ISRelease_</td><td>N</td><td/><td/><td/><td/><td>Text</td><td/><td>The name of the release.</td></row>
+		<row><td>ISReleaseExtended</td><td>JSharpCmdLine</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>Command Line to pass to vjredist.exe</td></row>
+		<row><td>ISReleaseExtended</td><td>JSharpRedistLocation</td><td>Y</td><td>0</td><td>3</td><td/><td/><td/><td/><td>Location of J# framework Redist (Web, SetupExe, Source, None)</td></row>
+		<row><td>ISReleaseExtended</td><td>MsiEngineVersion</td><td>Y</td><td/><td/><td/><td/><td/><td/><td>Bitfield holding selected MSI engine versions included in this release</td></row>
+		<row><td>ISReleaseExtended</td><td>OneClickCabName</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>File name of generated cabfile</td></row>
+		<row><td>ISReleaseExtended</td><td>OneClickHtmlName</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>File name of generated html page</td></row>
+		<row><td>ISReleaseExtended</td><td>OneClickTargetBrowser</td><td>Y</td><td>0</td><td>2</td><td/><td/><td/><td/><td>Target browser (IE, Netscape, both...)</td></row>
+		<row><td>ISReleaseExtended</td><td>WebCabSize</td><td>Y</td><td>0</td><td>2147483647</td><td/><td/><td/><td/><td>Size of the cabfile</td></row>
+		<row><td>ISReleaseExtended</td><td>WebLocalCachePath</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>Directory to cache downloaded package</td></row>
+		<row><td>ISReleaseExtended</td><td>WebType</td><td>Y</td><td>0</td><td>2</td><td/><td/><td/><td/><td>Type of web install (One Executable, Downloader...)</td></row>
+		<row><td>ISReleaseExtended</td><td>WebURL</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>URL to .msi package</td></row>
+		<row><td>ISReleaseExtended</td><td>Win9xMsiUrl</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>URL to Ansi MSI engine</td></row>
+		<row><td>ISReleaseExtended</td><td>WinMsi30Url</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>URL to MSI 3.0 engine</td></row>
+		<row><td>ISReleaseExtended</td><td>WinNTMsiUrl</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>URL to Unicode MSI engine</td></row>
+		<row><td>ISReleasePublishInfo</td><td>Description</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>Repository item description</td></row>
+		<row><td>ISReleasePublishInfo</td><td>DisplayName</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>Repository item display name</td></row>
+		<row><td>ISReleasePublishInfo</td><td>ISAttributes</td><td>Y</td><td/><td/><td/><td/><td/><td/><td>Bitfield holding various attributes</td></row>
+		<row><td>ISReleasePublishInfo</td><td>ISProductConfiguration_</td><td>N</td><td/><td/><td>ISProductConfiguration</td><td>1</td><td>Text</td><td/><td>Foreign key into the ISProductConfiguration table.</td></row>
+		<row><td>ISReleasePublishInfo</td><td>ISRelease_</td><td>N</td><td/><td/><td>ISRelease</td><td>1</td><td>Text</td><td/><td>The name of the release.</td></row>
+		<row><td>ISReleasePublishInfo</td><td>Publisher</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>Repository item publisher</td></row>
+		<row><td>ISReleasePublishInfo</td><td>Repository</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>Repository which to  publish the built merge module</td></row>
+		<row><td>ISSQLConnection</td><td>Attributes</td><td>N</td><td/><td/><td/><td/><td/><td/><td/></row>
+		<row><td>ISSQLConnection</td><td>Authentication</td><td>N</td><td/><td/><td/><td/><td/><td/><td/></row>
+		<row><td>ISSQLConnection</td><td>CmdTimeout</td><td>Y</td><td/><td/><td/><td/><td/><td/><td/></row>
+		<row><td>ISSQLConnection</td><td>Comments</td><td>Y</td><td/><td/><td/><td/><td/><td/><td/></row>
+		<row><td>ISSQLConnection</td><td>Database</td><td>N</td><td/><td/><td/><td/><td/><td/><td/></row>
+		<row><td>ISSQLConnection</td><td>ISSQLConnection</td><td>N</td><td/><td/><td/><td/><td/><td/><td/></row>
+		<row><td>ISSQLConnection</td><td>Order</td><td>N</td><td/><td/><td/><td/><td/><td/><td/></row>
+		<row><td>ISSQLConnection</td><td>Password</td><td>N</td><td/><td/><td/><td/><td/><td/><td/></row>
+		<row><td>ISSQLConnection</td><td>Server</td><td>N</td><td/><td/><td/><td/><td/><td/><td/></row>
+		<row><td>ISSQLConnection</td><td>UserName</td><td>N</td><td/><td/><td/><td/><td/><td/><td/></row>
+		<row><td>ISSQLConnectionDBServer</td><td>ISSQLConnectionDBServer</td><td>N</td><td/><td/><td/><td/><td/><td/><td/></row>
+		<row><td>ISSQLConnectionDBServer</td><td>ISSQLConnection_</td><td>N</td><td/><td/><td>ISSQLConnection</td><td>1</td><td/><td/><td/></row>
+		<row><td>ISSQLConnectionDBServer</td><td>ISSQLDBMetaData_</td><td>N</td><td/><td/><td>ISSQLDBMetaData</td><td>1</td><td/><td/><td/></row>
+		<row><td>ISSQLConnectionDBServer</td><td>Order</td><td>N</td><td/><td/><td/><td/><td/><td/><td/></row>
+		<row><td>ISSQLConnectionScript</td><td>ISSQLConnection_</td><td>N</td><td/><td/><td>ISSQLConnection</td><td>1</td><td/><td/><td/></row>
+		<row><td>ISSQLConnectionScript</td><td>ISSQLScriptFile_</td><td>N</td><td/><td/><td>ISSQLScriptFile</td><td>1</td><td/><td/><td/></row>
+		<row><td>ISSQLConnectionScript</td><td>Order</td><td>N</td><td/><td/><td/><td/><td/><td/><td/></row>
+		<row><td>ISSQLDBMetaData</td><td>AdoCxnDatabase</td><td>Y</td><td/><td/><td/><td/><td/><td/><td/></row>
+		<row><td>ISSQLDBMetaData</td><td>AdoCxnDriver</td><td>Y</td><td/><td/><td/><td/><td/><td/><td/></row>
+		<row><td>ISSQLDBMetaData</td><td>AdoCxnNetLibrary</td><td>Y</td><td/><td/><td/><td/><td/><td/><td/></row>
+		<row><td>ISSQLDBMetaData</td><td>AdoCxnPassword</td><td>Y</td><td/><td/><td/><td/><td/><td/><td/></row>
+		<row><td>ISSQLDBMetaData</td><td>AdoCxnServer</td><td>Y</td><td/><td/><td/><td/><td/><td/><td/></row>
+		<row><td>ISSQLDBMetaData</td><td>AdoCxnUserID</td><td>Y</td><td/><td/><td/><td/><td/><td/><td/></row>
+		<row><td>ISSQLDBMetaData</td><td>AdoCxnWindowsSecurity</td><td>Y</td><td/><td/><td/><td/><td/><td/><td/></row>
+		<row><td>ISSQLDBMetaData</td><td>AdoDriverName</td><td>Y</td><td/><td/><td/><td/><td/><td/><td/></row>
+		<row><td>ISSQLDBMetaData</td><td>DisplayName</td><td>Y</td><td/><td/><td/><td/><td/><td/><td/></row>
+		<row><td>ISSQLDBMetaData</td><td>ISSQLDBMetaData</td><td>N</td><td/><td/><td/><td/><td/><td/><td/></row>
+		<row><td>ISSQLDBMetaData</td><td>LocalInstanceNames</td><td>Y</td><td/><td/><td/><td/><td/><td/><td/></row>
+		<row><td>ISSQLDBMetaData</td><td>TestDatabaseCmd</td><td>Y</td><td/><td/><td/><td/><td/><td/><td/></row>
+		<row><td>ISSQLDBMetaData</td><td>TestTableCmd</td><td>Y</td><td/><td/><td/><td/><td/><td/><td/></row>
+		<row><td>ISSQLDBMetaData</td><td>VersionBeginToken</td><td>Y</td><td/><td/><td/><td/><td/><td/><td/></row>
+		<row><td>ISSQLDBMetaData</td><td>VersionEndToken</td><td>Y</td><td/><td/><td/><td/><td/><td/><td/></row>
+		<row><td>ISSQLDBMetaData</td><td>VersionInfoCmd</td><td>Y</td><td/><td/><td/><td/><td/><td/><td/></row>
+		<row><td>ISSQLRequirement</td><td>Attributes</td><td>N</td><td/><td/><td/><td/><td/><td/><td/></row>
+		<row><td>ISSQLRequirement</td><td>ISSQLConnectionDBServer_</td><td>Y</td><td/><td/><td>ISSQLConnectionDBServer</td><td>1</td><td/><td/><td/></row>
+		<row><td>ISSQLRequirement</td><td>ISSQLConnection_</td><td>N</td><td/><td/><td>ISSQLConnection</td><td>1</td><td/><td/><td/></row>
+		<row><td>ISSQLRequirement</td><td>ISSQLRequirement</td><td>N</td><td/><td/><td/><td/><td/><td/><td/></row>
+		<row><td>ISSQLRequirement</td><td>MajorVersion</td><td>Y</td><td/><td/><td/><td/><td/><td/><td/></row>
+		<row><td>ISSQLRequirement</td><td>ServicePackLevel</td><td>Y</td><td/><td/><td/><td/><td/><td/><td/></row>
+		<row><td>ISSQLScriptError</td><td>Attributes</td><td>N</td><td/><td/><td/><td/><td/><td/><td/></row>
+		<row><td>ISSQLScriptError</td><td>ErrHandling</td><td>N</td><td/><td/><td/><td/><td/><td/><td/></row>
+		<row><td>ISSQLScriptError</td><td>ErrNumber</td><td>N</td><td/><td/><td/><td/><td/><td/><td/></row>
+		<row><td>ISSQLScriptError</td><td>ISSQLScriptFile_</td><td>Y</td><td/><td/><td>ISSQLScriptFile</td><td>1</td><td>Identifier</td><td/><td>Foreign key referencing ISSQLScriptFile</td></row>
+		<row><td>ISSQLScriptError</td><td>Message</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>Custom end-user message. Reserved for future use.</td></row>
+		<row><td>ISSQLScriptFile</td><td>Attributes</td><td>N</td><td/><td/><td/><td/><td/><td/><td/></row>
+		<row><td>ISSQLScriptFile</td><td>Comments</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>Comments</td></row>
+		<row><td>ISSQLScriptFile</td><td>Component_</td><td>N</td><td/><td/><td>Component</td><td>1</td><td>Identifier</td><td/><td>Foreign key referencing Component that controls the SQL script.</td></row>
+		<row><td>ISSQLScriptFile</td><td>ErrorHandling</td><td>N</td><td/><td/><td/><td/><td/><td/><td/></row>
+		<row><td>ISSQLScriptFile</td><td>ISBuildSourcePath</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>Full path, the category is of Text instead of Path because of potential use of path variables.</td></row>
+		<row><td>ISSQLScriptFile</td><td>ISSQLScriptFile</td><td>N</td><td/><td/><td/><td/><td>Identifier</td><td/><td>This is the primary key to the ISSQLScriptFile table</td></row>
+		<row><td>ISSQLScriptFile</td><td>InstallText</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>Feedback end-user text at install</td></row>
+		<row><td>ISSQLScriptFile</td><td>Scheduling</td><td>N</td><td/><td/><td/><td/><td/><td/><td/></row>
+		<row><td>ISSQLScriptFile</td><td>UninstallText</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>Feedback end-user text at Uninstall</td></row>
+		<row><td>ISSQLScriptFile</td><td>Version</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>Schema Version (####.#####.####)</td></row>
+		<row><td>ISSQLScriptImport</td><td>Attributes</td><td>N</td><td/><td/><td/><td/><td/><td/><td/></row>
+		<row><td>ISSQLScriptImport</td><td>Authentication</td><td>N</td><td/><td/><td/><td/><td/><td/><td/></row>
+		<row><td>ISSQLScriptImport</td><td>Database</td><td>Y</td><td/><td/><td/><td/><td/><td/><td/></row>
+		<row><td>ISSQLScriptImport</td><td>ExcludeTables</td><td>Y</td><td/><td/><td/><td/><td/><td/><td/></row>
+		<row><td>ISSQLScriptImport</td><td>ISSQLScriptFile_</td><td>N</td><td/><td/><td>ISSQLScriptFile</td><td>1</td><td/><td/><td/></row>
+		<row><td>ISSQLScriptImport</td><td>IncludeTables</td><td>Y</td><td/><td/><td/><td/><td/><td/><td/></row>
+		<row><td>ISSQLScriptImport</td><td>Password</td><td>Y</td><td/><td/><td/><td/><td/><td/><td/></row>
+		<row><td>ISSQLScriptImport</td><td>Server</td><td>Y</td><td/><td/><td/><td/><td/><td/><td/></row>
+		<row><td>ISSQLScriptImport</td><td>UserName</td><td>Y</td><td/><td/><td/><td/><td/><td/><td/></row>
+		<row><td>ISSQLScriptReplace</td><td>Attributes</td><td>N</td><td/><td/><td/><td/><td/><td/><td/></row>
+		<row><td>ISSQLScriptReplace</td><td>ISSQLScriptFile_</td><td>N</td><td/><td/><td>ISSQLScriptFile</td><td>1</td><td/><td/><td/></row>
+		<row><td>ISSQLScriptReplace</td><td>ISSQLScriptReplace</td><td>N</td><td/><td/><td/><td/><td/><td/><td/></row>
+		<row><td>ISSQLScriptReplace</td><td>Replace</td><td>Y</td><td/><td/><td/><td/><td/><td/><td/></row>
+		<row><td>ISSQLScriptReplace</td><td>Search</td><td>Y</td><td/><td/><td/><td/><td/><td/><td/></row>
+		<row><td>ISScriptFile</td><td>ISScriptFile</td><td>N</td><td/><td/><td/><td/><td>Text</td><td/><td>This is the full path of the script file. The path portion may be expressed in path variable form.
+</td></row>
+		<row><td>ISSelfReg</td><td>CmdLine</td><td>Y</td><td/><td/><td/><td/><td/><td/><td/></row>
+		<row><td>ISSelfReg</td><td>Cost</td><td>Y</td><td/><td/><td/><td/><td/><td/><td/></row>
+		<row><td>ISSelfReg</td><td>FileKey</td><td>N</td><td/><td/><td>File</td><td>1</td><td>Identifier</td><td/><td>Foreign key to the file table</td></row>
+		<row><td>ISSelfReg</td><td>Order</td><td>Y</td><td/><td/><td/><td/><td/><td/><td/></row>
+		<row><td>ISSetupFile</td><td>FileName</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>This is the file name to use when streaming the file to the support files location</td></row>
+		<row><td>ISSetupFile</td><td>ISSetupFile</td><td>N</td><td/><td/><td/><td/><td>Identifier</td><td/><td>This is the primary key to the ISSetupFile table</td></row>
+		<row><td>ISSetupFile</td><td>Language</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>Four digit language identifier.  0 for Language Neutral</td></row>
+		<row><td>ISSetupFile</td><td>Path</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>Link to the source file on the build machine</td></row>
+		<row><td>ISSetupFile</td><td>Splash</td><td>Y</td><td/><td/><td/><td/><td>Short</td><td/><td>Boolean value indication whether his setup file entry belongs in the Splasc Screen section</td></row>
+		<row><td>ISSetupFile</td><td>Stream</td><td>Y</td><td/><td/><td/><td/><td>Binary</td><td/><td>Binary stream. The bits to stream to the support location</td></row>
+		<row><td>ISSetupPrerequisites</td><td>ISBuildSourcePath</td><td>Y</td><td/><td/><td/><td/><td/><td/><td/></row>
+		<row><td>ISSetupPrerequisites</td><td>ISSetupPrerequisites</td><td>N</td><td/><td/><td/><td/><td/><td/><td/></row>
+		<row><td>ISSetupPrerequisites</td><td>Order</td><td>Y</td><td/><td/><td/><td/><td/><td/><td/></row>
+		<row><td>ISStorages</td><td>ISBuildSourcePath</td><td>Y</td><td/><td/><td/><td/><td/><td/><td>Path to the file to stream into sub-storage</td></row>
+		<row><td>ISStorages</td><td>Name</td><td>N</td><td/><td/><td/><td/><td/><td/><td>Name of the sub-storage key</td></row>
+		<row><td>ISString</td><td>Comment</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>Comment</td></row>
+		<row><td>ISString</td><td>Encoded</td><td>Y</td><td/><td/><td/><td/><td/><td/><td>Encoding for multi-byte strings.</td></row>
+		<row><td>ISString</td><td>ISLanguage_</td><td>N</td><td/><td/><td/><td/><td>Language</td><td/><td>This is a foreign key to the ISLanguage table.</td></row>
+		<row><td>ISString</td><td>ISString</td><td>N</td><td/><td/><td/><td/><td>Text</td><td/><td>String id.</td></row>
+		<row><td>ISString</td><td>TimeStamp</td><td>Y</td><td/><td/><td/><td/><td>Time/Date</td><td/><td>Time Stamp. MSI's Time/Date column type is just an int, with bits packed in a certain order.</td></row>
+		<row><td>ISString</td><td>Value</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>real string value.</td></row>
+		<row><td>ISTargetImage</td><td>Flags</td><td>Y</td><td/><td/><td/><td/><td/><td/><td>relative order of the target image</td></row>
+		<row><td>ISTargetImage</td><td>IgnoreMissingFiles</td><td>N</td><td/><td/><td/><td/><td/><td/><td>If true, ignore missing source files when creating patch</td></row>
+		<row><td>ISTargetImage</td><td>MsiPath</td><td>N</td><td/><td/><td/><td/><td>Text</td><td/><td>Path to the target image</td></row>
+		<row><td>ISTargetImage</td><td>Name</td><td>N</td><td/><td/><td/><td/><td>Identifier</td><td/><td>Name of the TargetImage</td></row>
+		<row><td>ISTargetImage</td><td>Order</td><td>N</td><td/><td/><td/><td/><td/><td/><td>relative order of the target image</td></row>
+		<row><td>ISTargetImage</td><td>UpgradedImage_</td><td>N</td><td/><td/><td>ISUpgradedImage</td><td>1</td><td>Text</td><td/><td>foreign key to the upgraded Image table</td></row>
+		<row><td>ISUpgradeMsiItem</td><td>ISAttributes</td><td>N</td><td/><td/><td/><td/><td/><td>0;1</td><td/></row>
+		<row><td>ISUpgradeMsiItem</td><td>ISReleaseFlags</td><td>Y</td><td/><td/><td/><td/><td/><td/><td/></row>
+		<row><td>ISUpgradeMsiItem</td><td>ObjectSetupPath</td><td>N</td><td/><td/><td/><td/><td>Text</td><td/><td>The path to the setup you want to upgrade.</td></row>
+		<row><td>ISUpgradeMsiItem</td><td>UpgradeItem</td><td>N</td><td/><td/><td/><td/><td>Text</td><td/><td>The name of the Upgrade Item.</td></row>
+		<row><td>ISUpgradedImage</td><td>Family</td><td>N</td><td/><td/><td/><td/><td>Text</td><td/><td>Name of the image family</td></row>
+		<row><td>ISUpgradedImage</td><td>MsiPath</td><td>N</td><td/><td/><td/><td/><td>Text</td><td/><td>Path to the upgraded image</td></row>
+		<row><td>ISUpgradedImage</td><td>Name</td><td>N</td><td/><td/><td/><td/><td>Identifier</td><td/><td>Name of the UpgradedImage</td></row>
+		<row><td>ISVRoot</td><td>AnonyPasswrd</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>Obsolete column.  Moved to IISCommon</td></row>
+		<row><td>ISVRoot</td><td>AnonyUserName</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>Obsolete column.  Moved to IISCommon</td></row>
+		<row><td>ISVRoot</td><td>Component_</td><td>N</td><td/><td/><td>Component</td><td>1</td><td>Text</td><td/><td>Foreign key into Component table</td></row>
+		<row><td>ISVRoot</td><td>Condition</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>Obsolete column.  Moved to Component</td></row>
+		<row><td>ISVRoot</td><td>ScriptTimeout</td><td>Y</td><td/><td/><td/><td/><td/><td/><td>Obsolete column.  Moved to IISCommon</td></row>
+		<row><td>ISVRoot</td><td>SessionTimeout</td><td>Y</td><td/><td/><td/><td/><td/><td/><td>Obsolete column.  Moved to IISCommon</td></row>
+		<row><td>ISVRoot</td><td>VRootAppName</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>AppName of this VRoot</td></row>
+		<row><td>ISVRoot</td><td>VRootDefDoc</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>Obsolete column.  Moved to IISCommon</td></row>
+		<row><td>ISVRoot</td><td>VRootDir</td><td>N</td><td/><td/><td/><td/><td>Text</td><td/><td>Obsolete column.  Moved to IISCommon</td></row>
+		<row><td>ISVRoot</td><td>VRootKey</td><td>N</td><td/><td/><td/><td/><td>Text</td><td/><td>Foreign key into ISIISCommon table</td></row>
+		<row><td>ISVRoot</td><td>VRootName</td><td>N</td><td/><td/><td/><td/><td>Text</td><td/><td>Obsolete column.  Moved to IISCommon</td></row>
+		<row><td>ISVRoot</td><td>VRootProps</td><td>N</td><td/><td/><td/><td/><td/><td/><td>Properties of this VRoot</td></row>
+		<row><td>ISVRootAppMaps</td><td>AppMapProps</td><td>N</td><td/><td/><td/><td/><td/><td/><td/></row>
+		<row><td>ISVRootAppMaps</td><td>ExecPath</td><td>N</td><td/><td/><td/><td/><td>Text</td><td/><td>Localizable Exec Path</td></row>
+		<row><td>ISVRootAppMaps</td><td>Extension</td><td>N</td><td/><td/><td/><td/><td>Text</td><td/><td>Localizable Extension</td></row>
+		<row><td>ISVRootAppMaps</td><td>VRootAppMapKey</td><td>N</td><td/><td/><td/><td/><td/><td/><td/></row>
+		<row><td>ISVRootAppMaps</td><td>VRootKey</td><td>N</td><td/><td/><td>ISIISCommon</td><td>1</td><td/><td/><td/></row>
+		<row><td>ISVRootAppMaps</td><td>Verb</td><td>N</td><td/><td/><td/><td/><td>Text</td><td/><td>Localizable Verb</td></row>
+		<row><td>ISWebSite</td><td>IP</td><td>Y</td><td/><td/><td/><td/><td/><td/><td/></row>
+		<row><td>ISWebSite</td><td>ISIISCommon_</td><td>N</td><td/><td/><td>ISIISCommon</td><td>1</td><td>Text</td><td/><td>Foreign key into ISIISCommon table</td></row>
+		<row><td>ISWebSite</td><td>Port</td><td>N</td><td/><td/><td/><td/><td/><td/><td/></row>
+		<row><td>ISWebSite</td><td>SiteNumber</td><td>N</td><td/><td/><td/><td/><td/><td/><td/></row>
+		<row><td>ISWebSite</td><td>WebSiteProps</td><td>Y</td><td/><td/><td/><td/><td/><td/><td/></row>
+		<row><td>ISXmlElement</td><td>Content</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>Element contents</td></row>
+		<row><td>ISXmlElement</td><td>ISAttributes</td><td>Y</td><td/><td/><td/><td/><td>Number</td><td/><td>Internal XML element attributes</td></row>
+		<row><td>ISXmlElement</td><td>ISXmlElement</td><td>N</td><td/><td/><td/><td/><td>Identifier</td><td/><td>Primary key, non-localized, internal token for Xml element</td></row>
+		<row><td>ISXmlElement</td><td>ISXmlElement_Parent</td><td>Y</td><td/><td/><td>ISXmlElement</td><td>1</td><td>Identifier</td><td/><td>Foreign key into ISXMLElement table.</td></row>
+		<row><td>ISXmlElement</td><td>ISXmlFile_</td><td>N</td><td/><td/><td>ISXmlFile</td><td>1</td><td>Identifier</td><td/><td>Foreign key into XmlFile table.</td></row>
+		<row><td>ISXmlElement</td><td>XPath</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>XPath fragment including any operators</td></row>
+		<row><td>ISXmlElementAttrib</td><td>ISAttributes</td><td>Y</td><td/><td/><td/><td/><td>Number</td><td/><td>Internal XML elementattib attributes</td></row>
+		<row><td>ISXmlElementAttrib</td><td>ISXmlElementAttrib</td><td>N</td><td/><td/><td/><td/><td>Identifier</td><td/><td>Primary key, non-localized, internal token for Xml element attribute</td></row>
+		<row><td>ISXmlElementAttrib</td><td>ISXmlElement_</td><td>N</td><td/><td/><td>ISXmlElement</td><td>1</td><td>Identifier</td><td/><td>Foreign key into ISXMLElement table.</td></row>
+		<row><td>ISXmlElementAttrib</td><td>Name</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>Localized attribute name</td></row>
+		<row><td>ISXmlElementAttrib</td><td>Value</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>Localized attribute value</td></row>
+		<row><td>ISXmlFile</td><td>Component_</td><td>N</td><td/><td/><td>Component</td><td>1</td><td>Identifier</td><td/><td>Foreign key into Component table.</td></row>
+		<row><td>ISXmlFile</td><td>Directory</td><td>N</td><td/><td/><td/><td/><td>Identifier</td><td/><td>Foreign key into Directory table.</td></row>
+		<row><td>ISXmlFile</td><td>FileName</td><td>N</td><td/><td/><td/><td/><td>Text</td><td/><td>Localized XML file name</td></row>
+		<row><td>ISXmlFile</td><td>ISAttributes</td><td>Y</td><td/><td/><td/><td/><td>Number</td><td/><td>Internal XML file attributes</td></row>
+		<row><td>ISXmlFile</td><td>ISXmlFile</td><td>N</td><td/><td/><td/><td/><td>Identifier</td><td/><td>Primary key, non-localized,internal token for Xml file</td></row>
+		<row><td>ISXmlLocator</td><td>Attribute</td><td>Y</td><td/><td/><td/><td/><td/><td/><td>The name of an attribute within the XML element.</td></row>
+		<row><td>ISXmlLocator</td><td>Element</td><td>Y</td><td/><td/><td/><td/><td/><td/><td>XPath query that will locate an element in an XML file.</td></row>
+		<row><td>ISXmlLocator</td><td>ISAttributes</td><td>Y</td><td/><td/><td/><td/><td/><td>0;1;2</td><td/></row>
+		<row><td>ISXmlLocator</td><td>Parent</td><td>Y</td><td/><td/><td/><td/><td>Identifier</td><td/><td>The parent file signature. It is also a foreign key in the Signature table.</td></row>
+		<row><td>ISXmlLocator</td><td>Signature_</td><td>N</td><td/><td/><td/><td/><td>Identifier</td><td/><td>The Signature_ represents a unique file signature and is also the foreign key in the Signature,  RegLocator, IniLocator, ISXmlLocator, CompLocator and the DrLocator tables.</td></row>
+		<row><td>Icon</td><td>Data</td><td>Y</td><td/><td/><td/><td/><td>Binary</td><td/><td>Binary stream. The binary icon data in PE (.DLL or .EXE) or icon (.ICO) format.</td></row>
+		<row><td>Icon</td><td>ISBuildSourcePath</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>Full path to the ICO or EXE file.</td></row>
+		<row><td>Icon</td><td>ISIconIndex</td><td>Y</td><td>-32767</td><td>32767</td><td/><td/><td/><td/><td>Optional icon index to be extracted.</td></row>
+		<row><td>Icon</td><td>Name</td><td>N</td><td/><td/><td/><td/><td>Identifier</td><td/><td>Primary key. Name of the icon file.</td></row>
+		<row><td>IniFile</td><td>Action</td><td>N</td><td/><td/><td/><td/><td/><td>0;1;3</td><td>The type of modification to be made, one of iifEnum</td></row>
+		<row><td>IniFile</td><td>Component_</td><td>N</td><td/><td/><td>Component</td><td>1</td><td>Identifier</td><td/><td>Foreign key into the Component table referencing component that controls the installing of the .INI value.</td></row>
+		<row><td>IniFile</td><td>DirProperty</td><td>Y</td><td/><td/><td/><td/><td>Identifier</td><td/><td>Foreign key into the Directory table denoting the directory where the .INI file is.</td></row>
+		<row><td>IniFile</td><td>FileName</td><td>N</td><td/><td/><td/><td/><td>Text</td><td/><td>The .INI file name in which to write the information</td></row>
+		<row><td>IniFile</td><td>IniFile</td><td>N</td><td/><td/><td/><td/><td>Identifier</td><td/><td>Primary key, non-localized token.</td></row>
+		<row><td>IniFile</td><td>Key</td><td>N</td><td/><td/><td/><td/><td>Formatted</td><td/><td>The .INI file key below Section.</td></row>
+		<row><td>IniFile</td><td>Section</td><td>N</td><td/><td/><td/><td/><td>Formatted</td><td/><td>The .INI file Section.</td></row>
+		<row><td>IniFile</td><td>Value</td><td>N</td><td/><td/><td/><td/><td>Formatted</td><td/><td>The value to be written.</td></row>
+		<row><td>IniLocator</td><td>Field</td><td>Y</td><td>0</td><td>32767</td><td/><td/><td/><td/><td>The field in the .INI line. If Field is null or 0 the entire line is read.</td></row>
+		<row><td>IniLocator</td><td>FileName</td><td>N</td><td/><td/><td/><td/><td>Text</td><td/><td>The .INI file name.</td></row>
+		<row><td>IniLocator</td><td>Key</td><td>N</td><td/><td/><td/><td/><td>Text</td><td/><td>Key value (followed by an equals sign in INI file).</td></row>
+		<row><td>IniLocator</td><td>Section</td><td>N</td><td/><td/><td/><td/><td>Text</td><td/><td>Section name within in file (within square brackets in INI file).</td></row>
+		<row><td>IniLocator</td><td>Signature_</td><td>N</td><td/><td/><td>Signature</td><td>1</td><td>Identifier</td><td/><td>The table key. The Signature_ represents a unique file signature and is also the foreign key in the Signature table.</td></row>
+		<row><td>IniLocator</td><td>Type</td><td>Y</td><td>0</td><td>2</td><td/><td/><td/><td/><td>An integer value that determines if the .INI value read is a filename or a directory location or to be used as is w/o interpretation.</td></row>
+		<row><td>InstallExecuteSequence</td><td>Action</td><td>N</td><td/><td/><td/><td/><td>Identifier</td><td/><td>Name of action to invoke, either in the engine or the handler DLL.</td></row>
+		<row><td>InstallExecuteSequence</td><td>Condition</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>Optional expression which skips the action if evaluates to expFalse.If the expression syntax is invalid, the engine will terminate, returning iesBadActionData.</td></row>
+		<row><td>InstallExecuteSequence</td><td>ISAttributes</td><td>Y</td><td/><td/><td/><td/><td/><td/><td>This is used to store MM Custom Action Types</td></row>
+		<row><td>InstallExecuteSequence</td><td>ISComments</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td dt:dt="bin.base64" md5="ee654261ffce9c7f08d4789d0f5b202c">
+QQB1AHQAaABvAHIAGSBzACAAYwBvAG0AbQBlAG4AdABzACAAbwBuACAAdABoAGkAcwAgAFMAZQBxAHUAZQBuAGMAZQAuAA==
+			</td></row>
+		<row><td>InstallExecuteSequence</td><td>Sequence</td><td>Y</td><td>-4</td><td>32767</td><td/><td/><td/><td/><td>Number that determines the sort order in which the actions are to be executed.  Leave blank to suppress action.</td></row>
+		<row><td>InstallShield</td><td>Property</td><td>N</td><td/><td/><td/><td/><td>Identifier</td><td/><td>Name of property, uppercase if settable by launcher or loader.</td></row>
+		<row><td>InstallShield</td><td>Value</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>String value for property.</td></row>
+		<row><td>InstallUISequence</td><td>Action</td><td>N</td><td/><td/><td/><td/><td>Identifier</td><td/><td>Name of action to invoke, either in the engine or the handler DLL.</td></row>
+		<row><td>InstallUISequence</td><td>Condition</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>Optional expression which skips the action if evaluates to expFalse.If the expression syntax is invalid, the engine will terminate, returning iesBadActionData.</td></row>
+		<row><td>InstallUISequence</td><td>ISAttributes</td><td>Y</td><td/><td/><td/><td/><td/><td/><td>This is used to store MM Custom Action Types</td></row>
+		<row><td>InstallUISequence</td><td>ISComments</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td dt:dt="bin.base64" md5="ee654261ffce9c7f08d4789d0f5b202c">
+QQB1AHQAaABvAHIAGSBzACAAYwBvAG0AbQBlAG4AdABzACAAbwBuACAAdABoAGkAcwAgAFMAZQBxAHUAZQBuAGMAZQAuAA==
+			</td></row>
+		<row><td>InstallUISequence</td><td>Sequence</td><td>Y</td><td>-4</td><td>32767</td><td/><td/><td/><td/><td>Number that determines the sort order in which the actions are to be executed.  Leave blank to suppress action.</td></row>
+		<row><td>IsolatedComponent</td><td>Component_Application</td><td>N</td><td/><td/><td>Component</td><td>1</td><td>Identifier</td><td/><td>Key to Component table item for application</td></row>
+		<row><td>IsolatedComponent</td><td>Component_Shared</td><td>N</td><td/><td/><td>Component</td><td>1</td><td>Identifier</td><td/><td>Key to Component table item to be isolated</td></row>
+		<row><td>LaunchCondition</td><td>Condition</td><td>N</td><td/><td/><td/><td/><td>Condition</td><td/><td>Expression which must evaluate to TRUE in order for install to commence.</td></row>
+		<row><td>LaunchCondition</td><td>Description</td><td>N</td><td/><td/><td/><td/><td>Text</td><td/><td>Localizable text to display when condition fails and install must abort.</td></row>
+		<row><td>ListBox</td><td>Order</td><td>N</td><td>1</td><td>32767</td><td/><td/><td/><td/><td>A positive integer used to determine the ordering of the items within one list..The integers do not have to be consecutive.</td></row>
+		<row><td>ListBox</td><td>Property</td><td>N</td><td/><td/><td/><td/><td>Identifier</td><td/><td>A named property to be tied to this item. All the items tied to the same property become part of the same listbox.</td></row>
+		<row><td>ListBox</td><td>Text</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>The visible text to be assigned to the item. Optional. If this entry or the entire column is missing, the text is the same as the value.</td></row>
+		<row><td>ListBox</td><td>Value</td><td>N</td><td/><td/><td/><td/><td>Formatted</td><td/><td>The value string associated with this item. Selecting the line will set the associated property to this value.</td></row>
+		<row><td>ListView</td><td>Binary_</td><td>Y</td><td/><td/><td>Binary</td><td>1</td><td>Identifier</td><td/><td>The name of the icon to be displayed with the icon. The binary information is looked up from the Binary Table.</td></row>
+		<row><td>ListView</td><td>Order</td><td>N</td><td>1</td><td>32767</td><td/><td/><td/><td/><td>A positive integer used to determine the ordering of the items within one list..The integers do not have to be consecutive.</td></row>
+		<row><td>ListView</td><td>Property</td><td>N</td><td/><td/><td/><td/><td>Identifier</td><td/><td>A named property to be tied to this item. All the items tied to the same property become part of the same listview.</td></row>
+		<row><td>ListView</td><td>Text</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>The visible text to be assigned to the item. Optional. If this entry or the entire column is missing, the text is the same as the value.</td></row>
+		<row><td>ListView</td><td>Value</td><td>N</td><td/><td/><td/><td/><td>Text</td><td/><td>The value string associated with this item. Selecting the line will set the associated property to this value.</td></row>
+		<row><td>LockPermissions</td><td>Domain</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>Domain name for user whose permissions are being set. (usually a property)</td></row>
+		<row><td>LockPermissions</td><td>LockObject</td><td>N</td><td/><td/><td/><td/><td>Identifier</td><td/><td>Foreign key into Registry or File table</td></row>
+		<row><td>LockPermissions</td><td>Permission</td><td>Y</td><td>-2147483647</td><td>2147483647</td><td/><td/><td/><td/><td>Permission Access mask.  Full Control = 268435456 (GENERIC_ALL = 0x10000000)</td></row>
+		<row><td>LockPermissions</td><td>Table</td><td>N</td><td/><td/><td/><td/><td>Identifier</td><td>Directory;File;Registry</td><td>Reference to another table name</td></row>
+		<row><td>LockPermissions</td><td>User</td><td>N</td><td/><td/><td/><td/><td>Text</td><td/><td>User for permissions to be set.  (usually a property)</td></row>
+		<row><td>MIME</td><td>CLSID</td><td>Y</td><td/><td/><td>Class</td><td>1</td><td>Guid</td><td/><td>Optional associated CLSID.</td></row>
+		<row><td>MIME</td><td>ContentType</td><td>N</td><td/><td/><td/><td/><td>Text</td><td/><td>Primary key. Context identifier, typically "type/format".</td></row>
+		<row><td>MIME</td><td>Extension_</td><td>N</td><td/><td/><td>Extension</td><td>1</td><td>Text</td><td/><td>Optional associated extension (without dot)</td></row>
+		<row><td>Media</td><td>Cabinet</td><td>Y</td><td/><td/><td/><td/><td>Cabinet</td><td/><td>If some or all of the files stored on the media are compressed in a cabinet, the name of that cabinet.</td></row>
+		<row><td>Media</td><td>DiskId</td><td>N</td><td>1</td><td>32767</td><td/><td/><td/><td/><td>Primary key, integer to determine sort order for table.</td></row>
+		<row><td>Media</td><td>DiskPrompt</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>Disk name: the visible text actually printed on the disk.  This will be used to prompt the user when this disk needs to be inserted.</td></row>
+		<row><td>Media</td><td>LastSequence</td><td>N</td><td>0</td><td>32767</td><td/><td/><td/><td/><td>File sequence number for the last file for this media.</td></row>
+		<row><td>Media</td><td>Source</td><td>Y</td><td/><td/><td/><td/><td>Property</td><td/><td>The property defining the location of the cabinet file.</td></row>
+		<row><td>Media</td><td>VolumeLabel</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>The label attributed to the volume.</td></row>
+		<row><td>MoveFile</td><td>Component_</td><td>N</td><td/><td/><td>Component</td><td>1</td><td>Identifier</td><td/><td>If this component is not "selected" for installation or removal, no action will be taken on the associated MoveFile entry</td></row>
+		<row><td>MoveFile</td><td>DestFolder</td><td>N</td><td/><td/><td/><td/><td>Identifier</td><td/><td>Name of a property whose value is assumed to resolve to the full path to the destination directory</td></row>
+		<row><td>MoveFile</td><td>DestName</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>Name to be given to the original file after it is moved or copied.  If blank, the destination file will be given the same name as the source file</td></row>
+		<row><td>MoveFile</td><td>FileKey</td><td>N</td><td/><td/><td/><td/><td>Identifier</td><td/><td>Primary key that uniquely identifies a particular MoveFile record</td></row>
+		<row><td>MoveFile</td><td>Options</td><td>N</td><td>0</td><td>1</td><td/><td/><td/><td/><td>Integer value specifying the MoveFile operating mode, one of imfoEnum</td></row>
+		<row><td>MoveFile</td><td>SourceFolder</td><td>Y</td><td/><td/><td/><td/><td>Identifier</td><td/><td>Name of a property whose value is assumed to resolve to the full path to the source directory</td></row>
+		<row><td>MoveFile</td><td>SourceName</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>Name of the source file(s) to be moved or copied.  Can contain the '*' or '?' wildcards.</td></row>
+		<row><td>MsiAssembly</td><td>Attributes</td><td>Y</td><td/><td/><td/><td/><td/><td/><td>Assembly attributes</td></row>
+		<row><td>MsiAssembly</td><td>Component_</td><td>N</td><td/><td/><td>Component</td><td>1</td><td>Identifier</td><td/><td>Foreign key into Component table.</td></row>
+		<row><td>MsiAssembly</td><td>Feature_</td><td>N</td><td/><td/><td>Feature</td><td>1</td><td>Identifier</td><td/><td>Foreign key into Feature table.</td></row>
+		<row><td>MsiAssembly</td><td>File_Application</td><td>Y</td><td/><td/><td>File</td><td>1</td><td>Identifier</td><td/><td>Foreign key into File table, denoting the application context for private assemblies. Null for global assemblies.</td></row>
+		<row><td>MsiAssembly</td><td>File_Manifest</td><td>Y</td><td/><td/><td>File</td><td>1</td><td>Identifier</td><td/><td>Foreign key into the File table denoting the manifest file for the assembly.</td></row>
+		<row><td>MsiAssemblyName</td><td>Component_</td><td>N</td><td/><td/><td>Component</td><td>1</td><td>Identifier</td><td/><td>Foreign key into Component table.</td></row>
+		<row><td>MsiAssemblyName</td><td>Name</td><td>N</td><td/><td/><td/><td/><td>Text</td><td/><td>The name part of the name-value pairs for the assembly name.</td></row>
+		<row><td>MsiAssemblyName</td><td>Value</td><td>N</td><td/><td/><td/><td/><td>Text</td><td/><td>The value part of the name-value pairs for the assembly name.</td></row>
+		<row><td>MsiDigitalCertificate</td><td>CertData</td><td>N</td><td/><td/><td/><td/><td>Binary</td><td/><td>A certificate context blob for a signer certificate</td></row>
+		<row><td>MsiDigitalCertificate</td><td>DigitalCertificate</td><td>N</td><td/><td/><td/><td/><td>Identifier</td><td/><td>A unique identifier for the row</td></row>
+		<row><td>MsiDigitalSignature</td><td>DigitalCertificate_</td><td>N</td><td/><td/><td>MsiDigitalCertificate</td><td>1</td><td>Identifier</td><td/><td>Foreign key to MsiDigitalCertificate table identifying the signer certificate</td></row>
+		<row><td>MsiDigitalSignature</td><td>Hash</td><td>Y</td><td/><td/><td/><td/><td>Binary</td><td/><td>The encoded hash blob from the digital signature</td></row>
+		<row><td>MsiDigitalSignature</td><td>SignObject</td><td>N</td><td/><td/><td/><td/><td>Text</td><td/><td>Foreign key to Media table</td></row>
+		<row><td>MsiDigitalSignature</td><td>Table</td><td>N</td><td/><td/><td/><td/><td>Identifier</td><td/><td>Reference to another table name (only Media table is supported)</td></row>
+		<row><td>MsiDriverPackages</td><td>Component</td><td>N</td><td/><td/><td/><td/><td>Identifier</td><td/><td>Primary key used to identify a particular component record.</td></row>
+		<row><td>MsiDriverPackages</td><td>Flags</td><td>N</td><td/><td/><td/><td/><td/><td/><td>Driver package flags</td></row>
+		<row><td>MsiDriverPackages</td><td>ReferenceComponents</td><td>Y</td><td/><td/><td/><td/><td/><td/><td/></row>
+		<row><td>MsiDriverPackages</td><td>Sequence</td><td>Y</td><td/><td/><td/><td/><td/><td/><td>Installation sequence number</td></row>
+		<row><td>MsiFileHash</td><td>File_</td><td>N</td><td/><td/><td>File</td><td>1</td><td>Identifier</td><td/><td>Primary key, foreign key into File table referencing file with this hash</td></row>
+		<row><td>MsiFileHash</td><td>HashPart1</td><td>N</td><td/><td/><td/><td/><td/><td/><td>Size of file in bytes (long integer).</td></row>
+		<row><td>MsiFileHash</td><td>HashPart2</td><td>N</td><td/><td/><td/><td/><td/><td/><td>Size of file in bytes (long integer).</td></row>
+		<row><td>MsiFileHash</td><td>HashPart3</td><td>N</td><td/><td/><td/><td/><td/><td/><td>Size of file in bytes (long integer).</td></row>
+		<row><td>MsiFileHash</td><td>HashPart4</td><td>N</td><td/><td/><td/><td/><td/><td/><td>Size of file in bytes (long integer).</td></row>
+		<row><td>MsiFileHash</td><td>Options</td><td>N</td><td>0</td><td>32767</td><td/><td/><td/><td/><td>Various options and attributes for this hash.</td></row>
+		<row><td>MsiPatchCertificate</td><td>DigitalCertificate_</td><td>N</td><td/><td/><td>MsiDigitalCertificate</td><td>1</td><td>Identifier</td><td/><td>A foreign key to the digital certificate table</td></row>
+		<row><td>MsiPatchCertificate</td><td>PatchCertificate</td><td>Y</td><td/><td/><td/><td/><td>Identifier</td><td/><td>A unique identifier for the row</td></row>
+		<row><td>MsiPatchMetadata</td><td>Company</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>Optional company name</td></row>
+		<row><td>MsiPatchMetadata</td><td>PatchConfiguration_</td><td>N</td><td/><td/><td>ISPatchConfiguration</td><td>1</td><td>Text</td><td/><td>Foreign key to the ISPatchConfiguration table</td></row>
+		<row><td>MsiPatchMetadata</td><td>Property</td><td>N</td><td/><td/><td/><td/><td>Text</td><td/><td>Name of the metadata</td></row>
+		<row><td>MsiPatchMetadata</td><td>Value</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>Value of the metadata</td></row>
+		<row><td>MsiPatchOldAssemblyFile</td><td>Assembly_</td><td>Y</td><td/><td/><td>MsiPatchOldAssemblyName</td><td>1</td><td/><td/><td/></row>
+		<row><td>MsiPatchOldAssemblyFile</td><td>File_</td><td>N</td><td/><td/><td>File</td><td>1</td><td/><td/><td/></row>
+		<row><td>MsiPatchOldAssemblyName</td><td>Assembly_</td><td>N</td><td/><td/><td/><td/><td/><td/><td/></row>
+		<row><td>MsiPatchOldAssemblyName</td><td>Name</td><td>N</td><td/><td/><td/><td/><td/><td/><td/></row>
+		<row><td>MsiPatchOldAssemblyName</td><td>Value</td><td>Y</td><td/><td/><td/><td/><td/><td/><td/></row>
+		<row><td>MsiPatchSequence</td><td>PatchConfiguration_</td><td>N</td><td/><td/><td>ISPatchConfiguration</td><td>1</td><td>Text</td><td/><td>Foreign key to the patch configuration table</td></row>
+		<row><td>MsiPatchSequence</td><td>PatchFamily</td><td>N</td><td/><td/><td/><td/><td>Text</td><td/><td>Name of the family to which this patch belongs</td></row>
+		<row><td>MsiPatchSequence</td><td>Sequence</td><td>N</td><td/><td/><td/><td/><td>Version</td><td/><td>The version of this patch in this family</td></row>
+		<row><td>MsiPatchSequence</td><td>Supersede</td><td>N</td><td/><td/><td/><td/><td>Integer</td><td/><td>Supersede</td></row>
+		<row><td>MsiPatchSequence</td><td>Target</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>Target product codes for this patch family</td></row>
+		<row><td>ODBCAttribute</td><td>Attribute</td><td>N</td><td/><td/><td/><td/><td>Text</td><td/><td>Name of ODBC driver attribute</td></row>
+		<row><td>ODBCAttribute</td><td>Driver_</td><td>N</td><td/><td/><td>ODBCDriver</td><td>1</td><td>Identifier</td><td/><td>Reference to ODBC driver in ODBCDriver table</td></row>
+		<row><td>ODBCAttribute</td><td>Value</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>Value for ODBC driver attribute</td></row>
+		<row><td>ODBCDataSource</td><td>Component_</td><td>N</td><td/><td/><td>Component</td><td>1</td><td>Identifier</td><td/><td>Reference to associated component</td></row>
+		<row><td>ODBCDataSource</td><td>DataSource</td><td>N</td><td/><td/><td/><td/><td>Identifier</td><td/><td>Primary key, non-localized.internal token for data source</td></row>
+		<row><td>ODBCDataSource</td><td>Description</td><td>N</td><td/><td/><td/><td/><td>Text</td><td/><td>Text used as registered name for data source</td></row>
+		<row><td>ODBCDataSource</td><td>DriverDescription</td><td>N</td><td/><td/><td/><td/><td>Text</td><td/><td>Reference to driver description, may be existing driver</td></row>
+		<row><td>ODBCDataSource</td><td>Registration</td><td>N</td><td>0</td><td>1</td><td/><td/><td/><td/><td>Registration option: 0=machine, 1=user, others t.b.d.</td></row>
+		<row><td>ODBCDriver</td><td>Component_</td><td>N</td><td/><td/><td>Component</td><td>1</td><td>Identifier</td><td/><td>Reference to associated component</td></row>
+		<row><td>ODBCDriver</td><td>Description</td><td>N</td><td/><td/><td/><td/><td>Text</td><td/><td>Text used as registered name for driver, non-localized</td></row>
+		<row><td>ODBCDriver</td><td>Driver</td><td>N</td><td/><td/><td/><td/><td>Identifier</td><td/><td>Primary key, non-localized.internal token for driver</td></row>
+		<row><td>ODBCDriver</td><td>File_</td><td>N</td><td/><td/><td>File</td><td>1</td><td>Identifier</td><td/><td>Reference to key driver file</td></row>
+		<row><td>ODBCDriver</td><td>File_Setup</td><td>Y</td><td/><td/><td>File</td><td>1</td><td>Identifier</td><td/><td>Optional reference to key driver setup DLL</td></row>
+		<row><td>ODBCSourceAttribute</td><td>Attribute</td><td>N</td><td/><td/><td/><td/><td>Text</td><td/><td>Name of ODBC data source attribute</td></row>
+		<row><td>ODBCSourceAttribute</td><td>DataSource_</td><td>N</td><td/><td/><td>ODBCDataSource</td><td>1</td><td>Identifier</td><td/><td>Reference to ODBC data source in ODBCDataSource table</td></row>
+		<row><td>ODBCSourceAttribute</td><td>Value</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>Value for ODBC data source attribute</td></row>
+		<row><td>ODBCTranslator</td><td>Component_</td><td>N</td><td/><td/><td>Component</td><td>1</td><td>Identifier</td><td/><td>Reference to associated component</td></row>
+		<row><td>ODBCTranslator</td><td>Description</td><td>N</td><td/><td/><td/><td/><td>Text</td><td/><td>Text used as registered name for translator</td></row>
+		<row><td>ODBCTranslator</td><td>File_</td><td>N</td><td/><td/><td>File</td><td>1</td><td>Identifier</td><td/><td>Reference to key translator file</td></row>
+		<row><td>ODBCTranslator</td><td>File_Setup</td><td>Y</td><td/><td/><td>File</td><td>1</td><td>Identifier</td><td/><td>Optional reference to key translator setup DLL</td></row>
+		<row><td>ODBCTranslator</td><td>Translator</td><td>N</td><td/><td/><td/><td/><td>Identifier</td><td/><td>Primary key, non-localized.internal token for translator</td></row>
+		<row><td>Patch</td><td>Attributes</td><td>N</td><td>0</td><td>32767</td><td/><td/><td/><td/><td>Integer containing bit flags representing patch attributes</td></row>
+		<row><td>Patch</td><td>File_</td><td>N</td><td/><td/><td>File</td><td>1</td><td>Identifier</td><td/><td>Primary key, non-localized token, foreign key to File table, must match identifier in cabinet.</td></row>
+		<row><td>Patch</td><td>Header</td><td>Y</td><td/><td/><td/><td/><td>Binary</td><td/><td>Binary stream. The patch header, used for patch validation.</td></row>
+		<row><td>Patch</td><td>ISBuildSourcePath</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>Full path to patch header.</td></row>
+		<row><td>Patch</td><td>PatchSize</td><td>N</td><td>0</td><td>2147483647</td><td/><td/><td/><td/><td>Size of patch in bytes (long integer).</td></row>
+		<row><td>Patch</td><td>Sequence</td><td>N</td><td>0</td><td>32767</td><td/><td/><td/><td/><td>Primary key, sequence with respect to the media images; order must track cabinet order.</td></row>
+		<row><td>PatchPackage</td><td>Media_</td><td>N</td><td>0</td><td>32767</td><td/><td/><td/><td/><td>Foreign key to DiskId column of Media table. Indicates the disk containing the patch package.</td></row>
+		<row><td>PatchPackage</td><td>PatchId</td><td>N</td><td/><td/><td/><td/><td>Guid</td><td/><td>A unique string GUID representing this patch.</td></row>
+		<row><td>ProgId</td><td>Class_</td><td>Y</td><td/><td/><td>Class</td><td>1</td><td>Guid</td><td/><td>The CLSID of an OLE factory corresponding to the ProgId.</td></row>
+		<row><td>ProgId</td><td>Description</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>Localized description for the Program identifier.</td></row>
+		<row><td>ProgId</td><td>ISAttributes</td><td>Y</td><td/><td/><td/><td/><td/><td/><td>This is used to store Installshield custom properties of a component, like ExtractIcon, etc.</td></row>
+		<row><td>ProgId</td><td>IconIndex</td><td>Y</td><td>-32767</td><td>32767</td><td/><td/><td/><td/><td>Optional icon index.</td></row>
+		<row><td>ProgId</td><td>Icon_</td><td>Y</td><td/><td/><td>Icon</td><td>1</td><td>Identifier</td><td/><td>Optional foreign key into the Icon Table, specifying the icon file associated with this ProgId. Will be written under the DefaultIcon key.</td></row>
+		<row><td>ProgId</td><td>ProgId</td><td>N</td><td/><td/><td/><td/><td>Text</td><td/><td>The Program Identifier. Primary key.</td></row>
+		<row><td>ProgId</td><td>ProgId_Parent</td><td>Y</td><td/><td/><td>ProgId</td><td>1</td><td>Text</td><td/><td>The Parent Program Identifier. If specified, the ProgId column becomes a version independent prog id.</td></row>
+		<row><td>Property</td><td>ISComments</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>User Comments.</td></row>
+		<row><td>Property</td><td>Property</td><td>N</td><td/><td/><td/><td/><td>Identifier</td><td/><td>Name of property, uppercase if settable by launcher or loader.</td></row>
+		<row><td>Property</td><td>Value</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>String value for property.</td></row>
+		<row><td>PublishComponent</td><td>AppData</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>This is localisable Application specific data that can be associated with a Qualified Component.</td></row>
+		<row><td>PublishComponent</td><td>ComponentId</td><td>N</td><td/><td/><td/><td/><td>Guid</td><td/><td>A string GUID that represents the component id that will be requested by the alien product.</td></row>
+		<row><td>PublishComponent</td><td>Component_</td><td>N</td><td/><td/><td>Component</td><td>1</td><td>Identifier</td><td/><td>Foreign key into the Component table.</td></row>
+		<row><td>PublishComponent</td><td>Feature_</td><td>N</td><td/><td/><td>Feature</td><td>1</td><td>Identifier</td><td/><td>Foreign key into the Feature table.</td></row>
+		<row><td>PublishComponent</td><td>Qualifier</td><td>N</td><td/><td/><td/><td/><td>Text</td><td/><td>This is defined only when the ComponentId column is an Qualified Component Id. This is the Qualifier for ProvideComponentIndirect.</td></row>
+		<row><td>RadioButton</td><td>Height</td><td>N</td><td>0</td><td>32767</td><td/><td/><td/><td/><td>The height of the button.</td></row>
+		<row><td>RadioButton</td><td>Help</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>The help strings used with the button. The text is optional.</td></row>
+		<row><td>RadioButton</td><td>ISControlId</td><td>Y</td><td/><td/><td/><td/><td/><td/><td>A number used to represent the control ID of the Control, Used in Dialog export</td></row>
+		<row><td>RadioButton</td><td>Order</td><td>N</td><td>1</td><td>32767</td><td/><td/><td/><td/><td>A positive integer used to determine the ordering of the items within one list..The integers do not have to be consecutive.</td></row>
+		<row><td>RadioButton</td><td>Property</td><td>N</td><td/><td/><td/><td/><td>Identifier</td><td/><td>A named property to be tied to this radio button. All the buttons tied to the same property become part of the same group.</td></row>
+		<row><td>RadioButton</td><td>Text</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>The visible title to be assigned to the radio button.</td></row>
+		<row><td>RadioButton</td><td>Value</td><td>N</td><td/><td/><td/><td/><td>Formatted</td><td/><td>The value string associated with this button. Selecting the button will set the associated property to this value.</td></row>
+		<row><td>RadioButton</td><td>Width</td><td>N</td><td>0</td><td>32767</td><td/><td/><td/><td/><td>The width of the button.</td></row>
+		<row><td>RadioButton</td><td>X</td><td>N</td><td>0</td><td>32767</td><td/><td/><td/><td/><td>The horizontal coordinate of the upper left corner of the bounding rectangle of the radio button.</td></row>
+		<row><td>RadioButton</td><td>Y</td><td>N</td><td>0</td><td>32767</td><td/><td/><td/><td/><td>The vertical coordinate of the upper left corner of the bounding rectangle of the radio button.</td></row>
+		<row><td>RegLocator</td><td>Key</td><td>N</td><td/><td/><td/><td/><td>RegPath</td><td/><td>The key for the registry value.</td></row>
+		<row><td>RegLocator</td><td>Name</td><td>Y</td><td/><td/><td/><td/><td>Formatted</td><td/><td>The registry value name.</td></row>
+		<row><td>RegLocator</td><td>Root</td><td>N</td><td>0</td><td>3</td><td/><td/><td/><td/><td>The predefined root key for the registry value, one of rrkEnum.</td></row>
+		<row><td>RegLocator</td><td>Signature_</td><td>N</td><td/><td/><td>Signature</td><td>1</td><td>Identifier</td><td/><td>The table key. The Signature_ represents a unique file signature and is also the foreign key in the Signature table. If the type is 0, the registry values refers a directory, and _Signature is not a foreign key.</td></row>
+		<row><td>RegLocator</td><td>Type</td><td>Y</td><td>0</td><td>18</td><td/><td/><td/><td/><td>An integer value that determines if the registry value is a filename or a directory location or to be used as is w/o interpretation.</td></row>
+		<row><td>Registry</td><td>Component_</td><td>N</td><td/><td/><td>Component</td><td>1</td><td>Identifier</td><td/><td>Foreign key into the Component table referencing component that controls the installing of the registry value.</td></row>
+		<row><td>Registry</td><td>ISAttributes</td><td>Y</td><td/><td/><td/><td/><td/><td/><td>This is used to store Installshield custom properties of a registry item.  Currently the only one is Automatic.</td></row>
+		<row><td>Registry</td><td>Key</td><td>N</td><td/><td/><td/><td/><td>RegPath</td><td/><td>The key for the registry value.</td></row>
+		<row><td>Registry</td><td>Name</td><td>Y</td><td/><td/><td/><td/><td>Formatted</td><td/><td>The registry value name.</td></row>
+		<row><td>Registry</td><td>Registry</td><td>N</td><td/><td/><td/><td/><td>Identifier</td><td/><td>Primary key, non-localized token.</td></row>
+		<row><td>Registry</td><td>Root</td><td>N</td><td>-1</td><td>3</td><td/><td/><td/><td/><td>The predefined root key for the registry value, one of rrkEnum.</td></row>
+		<row><td>Registry</td><td>Value</td><td>Y</td><td/><td/><td/><td/><td>Formatted</td><td/><td>The registry value.</td></row>
+		<row><td>RemoveFile</td><td>Component_</td><td>N</td><td/><td/><td>Component</td><td>1</td><td>Identifier</td><td/><td>Foreign key referencing Component that controls the file to be removed.</td></row>
+		<row><td>RemoveFile</td><td>DirProperty</td><td>N</td><td/><td/><td/><td/><td>Identifier</td><td/><td>Name of a property whose value is assumed to resolve to the full pathname to the folder of the file to be removed.</td></row>
+		<row><td>RemoveFile</td><td>FileKey</td><td>N</td><td/><td/><td/><td/><td>Identifier</td><td/><td>Primary key used to identify a particular file entry</td></row>
+		<row><td>RemoveFile</td><td>FileName</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>Name of the file to be removed.</td></row>
+		<row><td>RemoveFile</td><td>InstallMode</td><td>N</td><td/><td/><td/><td/><td/><td>1;2;3</td><td>Installation option, one of iimEnum.</td></row>
+		<row><td>RemoveIniFile</td><td>Action</td><td>N</td><td/><td/><td/><td/><td/><td>2;4</td><td>The type of modification to be made, one of iifEnum.</td></row>
+		<row><td>RemoveIniFile</td><td>Component_</td><td>N</td><td/><td/><td>Component</td><td>1</td><td>Identifier</td><td/><td>Foreign key into the Component table referencing component that controls the deletion of the .INI value.</td></row>
+		<row><td>RemoveIniFile</td><td>DirProperty</td><td>Y</td><td/><td/><td/><td/><td>Identifier</td><td/><td>Foreign key into the Directory table denoting the directory where the .INI file is.</td></row>
+		<row><td>RemoveIniFile</td><td>FileName</td><td>N</td><td/><td/><td/><td/><td>Text</td><td/><td>The .INI file name in which to delete the information</td></row>
+		<row><td>RemoveIniFile</td><td>Key</td><td>N</td><td/><td/><td/><td/><td>Formatted</td><td/><td>The .INI file key below Section.</td></row>
+		<row><td>RemoveIniFile</td><td>RemoveIniFile</td><td>N</td><td/><td/><td/><td/><td>Identifier</td><td/><td>Primary key, non-localized token.</td></row>
+		<row><td>RemoveIniFile</td><td>Section</td><td>N</td><td/><td/><td/><td/><td>Formatted</td><td/><td>The .INI file Section.</td></row>
+		<row><td>RemoveIniFile</td><td>Value</td><td>Y</td><td/><td/><td/><td/><td>Formatted</td><td/><td>The value to be deleted. The value is required when Action is iifIniRemoveTag</td></row>
+		<row><td>RemoveRegistry</td><td>Component_</td><td>N</td><td/><td/><td>Component</td><td>1</td><td>Identifier</td><td/><td>Foreign key into the Component table referencing component that controls the deletion of the registry value.</td></row>
+		<row><td>RemoveRegistry</td><td>Key</td><td>N</td><td/><td/><td/><td/><td>RegPath</td><td/><td>The key for the registry value.</td></row>
+		<row><td>RemoveRegistry</td><td>Name</td><td>Y</td><td/><td/><td/><td/><td>Formatted</td><td/><td>The registry value name.</td></row>
+		<row><td>RemoveRegistry</td><td>RemoveRegistry</td><td>N</td><td/><td/><td/><td/><td>Identifier</td><td/><td>Primary key, non-localized token.</td></row>
+		<row><td>RemoveRegistry</td><td>Root</td><td>N</td><td>-1</td><td>3</td><td/><td/><td/><td/><td>The predefined root key for the registry value, one of rrkEnum</td></row>
+		<row><td>ReserveCost</td><td>Component_</td><td>N</td><td/><td/><td>Component</td><td>1</td><td>Identifier</td><td/><td>Reserve a specified amount of space if this component is to be installed.</td></row>
+		<row><td>ReserveCost</td><td>ReserveFolder</td><td>Y</td><td/><td/><td/><td/><td>Identifier</td><td/><td>Name of a property whose value is assumed to resolve to the full path to the destination directory</td></row>
+		<row><td>ReserveCost</td><td>ReserveKey</td><td>N</td><td/><td/><td/><td/><td>Identifier</td><td/><td>Primary key that uniquely identifies a particular ReserveCost record</td></row>
+		<row><td>ReserveCost</td><td>ReserveLocal</td><td>N</td><td>0</td><td>2147483647</td><td/><td/><td/><td/><td>Disk space to reserve if linked component is installed locally.</td></row>
+		<row><td>ReserveCost</td><td>ReserveSource</td><td>N</td><td>0</td><td>2147483647</td><td/><td/><td/><td/><td>Disk space to reserve if linked component is installed to run from the source location.</td></row>
+		<row><td>SFPCatalog</td><td>Catalog</td><td>Y</td><td/><td/><td/><td/><td>Binary</td><td/><td>SFP Catalog</td></row>
+		<row><td>SFPCatalog</td><td>Dependency</td><td>Y</td><td/><td/><td/><td/><td>Formatted</td><td/><td>Parent catalog - only used by SFP</td></row>
+		<row><td>SFPCatalog</td><td>SFPCatalog</td><td>N</td><td/><td/><td/><td/><td>Filename</td><td/><td>File name for the catalog.</td></row>
+		<row><td>SelfReg</td><td>Cost</td><td>Y</td><td>0</td><td>32767</td><td/><td/><td/><td/><td>The cost of registering the module.</td></row>
+		<row><td>SelfReg</td><td>File_</td><td>N</td><td/><td/><td>File</td><td>1</td><td>Identifier</td><td/><td>Foreign key into the File table denoting the module that needs to be registered.</td></row>
+		<row><td>ServiceControl</td><td>Arguments</td><td>Y</td><td/><td/><td/><td/><td>Formatted</td><td/><td>Arguments for the service.  Separate by [~].</td></row>
+		<row><td>ServiceControl</td><td>Component_</td><td>N</td><td/><td/><td>Component</td><td>1</td><td>Identifier</td><td/><td>Required foreign key into the Component Table that controls the startup of the service</td></row>
+		<row><td>ServiceControl</td><td>Event</td><td>N</td><td>0</td><td>187</td><td/><td/><td/><td/><td>Bit field:  Install:  0x1 = Start, 0x2 = Stop, 0x8 = Delete, Uninstall: 0x10 = Start, 0x20 = Stop, 0x80 = Delete</td></row>
+		<row><td>ServiceControl</td><td>Name</td><td>N</td><td/><td/><td/><td/><td>Formatted</td><td/><td>Name of a service. /, \, comma and space are invalid</td></row>
+		<row><td>ServiceControl</td><td>ServiceControl</td><td>N</td><td/><td/><td/><td/><td>Identifier</td><td/><td>Primary key, non-localized token.</td></row>
+		<row><td>ServiceControl</td><td>Wait</td><td>Y</td><td>0</td><td>1</td><td/><td/><td/><td/><td>Boolean for whether to wait for the service to fully start</td></row>
+		<row><td>ServiceInstall</td><td>Arguments</td><td>Y</td><td/><td/><td/><td/><td>Formatted</td><td/><td>Arguments to include in every start of the service, passed to WinMain</td></row>
+		<row><td>ServiceInstall</td><td>Component_</td><td>N</td><td/><td/><td>Component</td><td>1</td><td>Identifier</td><td/><td>Required foreign key into the Component Table that controls the startup of the service</td></row>
+		<row><td>ServiceInstall</td><td>Dependencies</td><td>Y</td><td/><td/><td/><td/><td>Formatted</td><td/><td>Other services this depends on to start.  Separate by [~], and end with [~][~]</td></row>
+		<row><td>ServiceInstall</td><td>Description</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>Description of service.</td></row>
+		<row><td>ServiceInstall</td><td>DisplayName</td><td>Y</td><td/><td/><td/><td/><td>Formatted</td><td/><td>External Name of the Service</td></row>
+		<row><td>ServiceInstall</td><td>ErrorControl</td><td>N</td><td>-2147483647</td><td>2147483647</td><td/><td/><td/><td/><td>Severity of error if service fails to start</td></row>
+		<row><td>ServiceInstall</td><td>LoadOrderGroup</td><td>Y</td><td/><td/><td/><td/><td>Formatted</td><td/><td>LoadOrderGroup</td></row>
+		<row><td>ServiceInstall</td><td>Name</td><td>N</td><td/><td/><td/><td/><td>Formatted</td><td/><td>Internal Name of the Service</td></row>
+		<row><td>ServiceInstall</td><td>Password</td><td>Y</td><td/><td/><td/><td/><td>Formatted</td><td/><td>password to run service with.  (with StartName)</td></row>
+		<row><td>ServiceInstall</td><td>ServiceInstall</td><td>N</td><td/><td/><td/><td/><td>Identifier</td><td/><td>Primary key, non-localized token.</td></row>
+		<row><td>ServiceInstall</td><td>ServiceType</td><td>N</td><td>-2147483647</td><td>2147483647</td><td/><td/><td/><td/><td>Type of the service</td></row>
+		<row><td>ServiceInstall</td><td>StartName</td><td>Y</td><td/><td/><td/><td/><td>Formatted</td><td/><td>User or object name to run service as</td></row>
+		<row><td>ServiceInstall</td><td>StartType</td><td>N</td><td>0</td><td>4</td><td/><td/><td/><td/><td>Type of the service</td></row>
+		<row><td>Shortcut</td><td>Arguments</td><td>Y</td><td/><td/><td/><td/><td>Formatted</td><td/><td>The command-line arguments for the shortcut.</td></row>
+		<row><td>Shortcut</td><td>Component_</td><td>N</td><td/><td/><td>Component</td><td>1</td><td>Identifier</td><td/><td>Foreign key into the Component table denoting the component whose selection gates the the shortcut creation/deletion.</td></row>
+		<row><td>Shortcut</td><td>Description</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>The description for the shortcut.</td></row>
+		<row><td>Shortcut</td><td>Directory_</td><td>N</td><td/><td/><td>Directory</td><td>1</td><td>Identifier</td><td/><td>Foreign key into the Directory table denoting the directory where the shortcut file is created.</td></row>
+		<row><td>Shortcut</td><td>Hotkey</td><td>Y</td><td>0</td><td>32767</td><td/><td/><td/><td/><td>The hotkey for the shortcut. It has the virtual-key code for the key in the low-order byte, and the modifier flags in the high-order byte. </td></row>
+		<row><td>Shortcut</td><td>ISAttributes</td><td>Y</td><td/><td/><td/><td/><td/><td/><td>This is used to store Installshield custom properties of a shortcut.  Mainly used in pro project types.</td></row>
+		<row><td>Shortcut</td><td>ISComments</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td dt:dt="bin.base64" md5="cb9acc27950b903a6080754a56990866">
+QQB1AHQAaABvAHIAGSBzACAAYwBvAG0AbQBlAG4AdABzACAAbwBuACAAdABoAGkAcwAgAFMAaABvAHIAdABjAHUAdAAuAA==
+			</td></row>
+		<row><td>Shortcut</td><td>ISShortcutName</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>A non-unique name for the shortcut.  Mainly used by pro pro project types.</td></row>
+		<row><td>Shortcut</td><td>IconIndex</td><td>Y</td><td>-32767</td><td>32767</td><td/><td/><td/><td/><td>The icon index for the shortcut.</td></row>
+		<row><td>Shortcut</td><td>Icon_</td><td>Y</td><td/><td/><td>Icon</td><td>1</td><td>Identifier</td><td/><td>Foreign key into the File table denoting the external icon file for the shortcut.</td></row>
+		<row><td>Shortcut</td><td>Name</td><td>N</td><td/><td/><td/><td/><td>Text</td><td/><td>The name of the shortcut to be created.</td></row>
+		<row><td>Shortcut</td><td>Shortcut</td><td>N</td><td/><td/><td/><td/><td>Identifier</td><td/><td>Primary key, non-localized token.</td></row>
+		<row><td>Shortcut</td><td>ShowCmd</td><td>Y</td><td/><td/><td/><td/><td/><td>1;3;7</td><td>The show command for the application window.The following values may be used.</td></row>
+		<row><td>Shortcut</td><td>Target</td><td>N</td><td/><td/><td/><td/><td>Shortcut</td><td/><td>The shortcut target. This is usually a property that is expanded to a file or a folder that the shortcut points to.</td></row>
+		<row><td>Shortcut</td><td>WkDir</td><td>Y</td><td/><td/><td/><td/><td>Identifier</td><td/><td>Name of property defining location of working directory.</td></row>
+		<row><td>Signature</td><td>FileName</td><td>N</td><td/><td/><td/><td/><td>Text</td><td/><td>The name of the file. This may contain a "short name|long name" pair.</td></row>
+		<row><td>Signature</td><td>Languages</td><td>Y</td><td/><td/><td/><td/><td>Language</td><td/><td>The languages supported by the file.</td></row>
+		<row><td>Signature</td><td>MaxDate</td><td>Y</td><td>0</td><td>2147483647</td><td/><td/><td/><td/><td>The maximum creation date of the file.</td></row>
+		<row><td>Signature</td><td>MaxSize</td><td>Y</td><td>0</td><td>2147483647</td><td/><td/><td/><td/><td>The maximum size of the file. </td></row>
+		<row><td>Signature</td><td>MaxVersion</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>The maximum version of the file.</td></row>
+		<row><td>Signature</td><td>MinDate</td><td>Y</td><td>0</td><td>2147483647</td><td/><td/><td/><td/><td>The minimum creation date of the file.</td></row>
+		<row><td>Signature</td><td>MinSize</td><td>Y</td><td>0</td><td>2147483647</td><td/><td/><td/><td/><td>The minimum size of the file.</td></row>
+		<row><td>Signature</td><td>MinVersion</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>The minimum version of the file.</td></row>
+		<row><td>Signature</td><td>Signature</td><td>N</td><td/><td/><td/><td/><td>Identifier</td><td/><td>The table key. The Signature represents a unique file signature.</td></row>
+		<row><td>TextStyle</td><td>Color</td><td>Y</td><td>0</td><td>16777215</td><td/><td/><td/><td/><td>A long integer indicating the color of the string in the RGB format (Red, Green, Blue each 0-255, RGB = R + 256*G + 256^2*B).</td></row>
+		<row><td>TextStyle</td><td>FaceName</td><td>N</td><td/><td/><td/><td/><td>Text</td><td/><td>A string indicating the name of the font used. Required. The string must be at most 31 characters long.</td></row>
+		<row><td>TextStyle</td><td>Size</td><td>N</td><td>0</td><td>32767</td><td/><td/><td/><td/><td>The size of the font used. This size is given in our units (1/12 of the system font height). Assuming that the system font is set to 12 point size, this is equivalent to the point size.</td></row>
+		<row><td>TextStyle</td><td>StyleBits</td><td>Y</td><td>0</td><td>15</td><td/><td/><td/><td/><td>A combination of style bits.</td></row>
+		<row><td>TextStyle</td><td>TextStyle</td><td>N</td><td/><td/><td/><td/><td>Identifier</td><td/><td>Name of the style. The primary key of this table. This name is embedded in the texts to indicate a style change.</td></row>
+		<row><td>TypeLib</td><td>Component_</td><td>N</td><td/><td/><td>Component</td><td>1</td><td>Identifier</td><td/><td>Required foreign key into the Component Table, specifying the component for which to return a path when called through LocateComponent.</td></row>
+		<row><td>TypeLib</td><td>Cost</td><td>Y</td><td>0</td><td>2147483647</td><td/><td/><td/><td/><td>The cost associated with the registration of the typelib. This column is currently optional.</td></row>
+		<row><td>TypeLib</td><td>Description</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td/></row>
+		<row><td>TypeLib</td><td>Directory_</td><td>Y</td><td/><td/><td>Directory</td><td>1</td><td>Identifier</td><td/><td>Optional. The foreign key into the Directory table denoting the path to the help file for the type library.</td></row>
+		<row><td>TypeLib</td><td>Feature_</td><td>N</td><td/><td/><td>Feature</td><td>1</td><td>Identifier</td><td/><td>Required foreign key into the Feature Table, specifying the feature to validate or install in order for the type library to be operational.</td></row>
+		<row><td>TypeLib</td><td>Language</td><td>N</td><td>0</td><td>32767</td><td/><td/><td/><td/><td>The language of the library.</td></row>
+		<row><td>TypeLib</td><td>LibID</td><td>N</td><td/><td/><td/><td/><td>Guid</td><td/><td>The GUID that represents the library.</td></row>
+		<row><td>TypeLib</td><td>Version</td><td>Y</td><td>0</td><td>2147483647</td><td/><td/><td/><td/><td>The version of the library. The major version is in the upper 8 bits of the short integer. The minor version is in the lower 8 bits.</td></row>
+		<row><td>UIText</td><td>Key</td><td>N</td><td/><td/><td/><td/><td>Identifier</td><td/><td>A unique key that identifies the particular string.</td></row>
+		<row><td>UIText</td><td>Text</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>The localized version of the string.</td></row>
+		<row><td>Upgrade</td><td>ActionProperty</td><td>N</td><td/><td/><td/><td/><td>UpperCase</td><td/><td>The property to set when a product in this set is found.</td></row>
+		<row><td>Upgrade</td><td>Attributes</td><td>N</td><td>0</td><td>2147483647</td><td/><td/><td/><td/><td>The attributes of this product set.</td></row>
+		<row><td>Upgrade</td><td>ISDisplayName</td><td>Y</td><td/><td/><td>ISUpgradeMsiItem</td><td>1</td><td/><td/><td/></row>
+		<row><td>Upgrade</td><td>Language</td><td>Y</td><td/><td/><td/><td/><td>Language</td><td/><td>A comma-separated list of languages for either products in this set or products not in this set.</td></row>
+		<row><td>Upgrade</td><td>Remove</td><td>Y</td><td/><td/><td/><td/><td>Formatted</td><td/><td>The list of features to remove when uninstalling a product from this set.  The default is "ALL".</td></row>
+		<row><td>Upgrade</td><td>UpgradeCode</td><td>N</td><td/><td/><td/><td/><td>Guid</td><td/><td>The UpgradeCode GUID belonging to the products in this set.</td></row>
+		<row><td>Upgrade</td><td>VersionMax</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>The maximum ProductVersion of the products in this set.  The set may or may not include products with this particular version.</td></row>
+		<row><td>Upgrade</td><td>VersionMin</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>The minimum ProductVersion of the products in this set.  The set may or may not include products with this particular version.</td></row>
+		<row><td>Verb</td><td>Argument</td><td>Y</td><td/><td/><td/><td/><td>Formatted</td><td/><td>Optional value for the command arguments.</td></row>
+		<row><td>Verb</td><td>Command</td><td>Y</td><td/><td/><td/><td/><td>Formatted</td><td/><td>The command text.</td></row>
+		<row><td>Verb</td><td>Extension_</td><td>N</td><td/><td/><td>Extension</td><td>1</td><td>Text</td><td/><td>The extension associated with the table row.</td></row>
+		<row><td>Verb</td><td>Sequence</td><td>Y</td><td>0</td><td>32767</td><td/><td/><td/><td/><td>Order within the verbs for a particular extension. Also used simply to specify the default verb.</td></row>
+		<row><td>Verb</td><td>Verb</td><td>N</td><td/><td/><td/><td/><td>Text</td><td/><td>The verb for the command.</td></row>
+		<row><td>_Validation</td><td>Category</td><td>Y</td><td/><td/><td/><td/><td/><td>"Text";"Formatted";"Template";"Condition";"Guid";"Path";"Version";"Language";"Identifier";"Binary";"UpperCase";"LowerCase";"Filename";"Paths";"AnyPath";"WildCardFilename";"RegPath";"KeyFormatted";"CustomSource";"Property";"Cabinet";"Shortcut";"URL";"DefaultDir"</td><td>String category</td></row>
+		<row><td>_Validation</td><td>Column</td><td>N</td><td/><td/><td/><td/><td>Identifier</td><td/><td>Name of column</td></row>
+		<row><td>_Validation</td><td>Description</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>Description of column</td></row>
+		<row><td>_Validation</td><td>KeyColumn</td><td>Y</td><td>1</td><td>32</td><td/><td/><td/><td/><td>Column to which foreign key connects</td></row>
+		<row><td>_Validation</td><td>KeyTable</td><td>Y</td><td/><td/><td/><td/><td>Identifier</td><td/><td>For foreign key, Name of table to which data must link</td></row>
+		<row><td>_Validation</td><td>MaxValue</td><td>Y</td><td>-2147483647</td><td>2147483647</td><td/><td/><td/><td/><td>Maximum value allowed</td></row>
+		<row><td>_Validation</td><td>MinValue</td><td>Y</td><td>-2147483647</td><td>2147483647</td><td/><td/><td/><td/><td>Minimum value allowed</td></row>
+		<row><td>_Validation</td><td>Nullable</td><td>N</td><td/><td/><td/><td/><td/><td>Y;N;@</td><td>Whether the column is nullable</td></row>
+		<row><td>_Validation</td><td>Set</td><td>Y</td><td/><td/><td/><td/><td>Text</td><td/><td>Set of values that are permitted</td></row>
+		<row><td>_Validation</td><td>Table</td><td>N</td><td/><td/><td/><td/><td>Identifier</td><td/><td>Name of table</td></row>
+	</table>
+</msi>

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/installer/log/README
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/installer/log/README	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/installer/log/README	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1 @@
+Jakarta Isapi Redirector log files

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/installer/tomcat.ico
===================================================================
(Binary files differ)


Property changes on: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/installer/tomcat.ico
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/isapi.def
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/isapi.def	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/isapi.def	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,9 @@
+LIBRARY	     "isapi_redirect"
+
+EXPORTS
+	HttpFilterProc
+	GetFilterVersion
+	GetExtensionVersion
+	HttpExtensionProc	
+	TerminateFilter
+	TerminateExtension

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/isapi.dsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/isapi.dsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/isapi.dsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,299 @@
+# Microsoft Developer Studio Project File - Name="isapi" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
+
+CFG=isapi - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE 
+!MESSAGE NMAKE /f "isapi.mak".
+!MESSAGE 
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE 
+!MESSAGE NMAKE /f "isapi.mak" CFG="isapi - Win32 Debug"
+!MESSAGE 
+!MESSAGE Possible choices for configuration are:
+!MESSAGE 
+!MESSAGE "isapi - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "isapi - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE 
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+MTL=midl.exe
+RSC=rc.exe
+
+!IF  "$(CFG)" == "isapi - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "ISAPI_EXPORTS" /YX /FD /c
+# ADD CPP /nologo /MD /W3 /Zi /O2 /I "..\common" /I "pcre" /I "$(JAVA_HOME)\include" /I "$(JAVA_HOME)\include\win32" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "ISAPI_EXPORTS" /D "HAS_PCRE" /Fd"Release/isapi_redirector_src" /FD /c
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x809 /d "NDEBUG"
+# ADD RSC /l 0x809 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386
+# ADD LINK32 kernel32.lib user32.lib advapi32.lib ws2_32.lib mswsock.lib /nologo /base:"0x6A6B0000" /dll /debug /machine:I386 /out:"Release\isapi_redirect.dll"
+
+!ELSEIF  "$(CFG)" == "isapi - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "ISAPI_EXPORTS" /YX /FD /GZ /c
+# ADD CPP /nologo /MDd /W3 /GX /Zi /Od /I "..\common" /I "pcre" /I "$(JAVA_HOME)\include" /I "$(JAVA_HOME)\include\win32" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "ISAPI_EXPORTS" /D "HAS_PCRE" /Fd"Debug/isapi_redirector_src" /FD /c
+# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x809 /d "_DEBUG"
+# ADD RSC /l 0x809 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib advapi32.lib ws2_32.lib mswsock.lib /nologo /base:"0x6A6B0000" /dll /incremental:no /debug /machine:I386 /out:"Debug\isapi_redirect.dll"
+
+!ENDIF 
+
+# Begin Target
+
+# Name "isapi - Win32 Release"
+# Name "isapi - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# Begin Source File
+
+SOURCE=.\isapi_redirect.rc
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_ajp12_worker.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_ajp13.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_ajp13_worker.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_ajp14.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_ajp14_worker.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_ajp_common.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_connect.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_context.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\jk_isapi_plugin.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_jni_worker.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_lb_worker.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_map.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_md5.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_msg_buff.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_nwmain.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_pool.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_shm.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_sockbuf.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_status.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_uri_worker_map.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_util.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_worker.c
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl"
+# Begin Source File
+
+SOURCE=..\common\jk_ajp13.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_ajp13_worker.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_ajp14.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_ajp14_worker.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_ajp_common.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_channel.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_connect.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_context.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_env.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_global.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_jni_worker.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_lb_worker.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_logger.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_map.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_md5.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_msg_buff.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_mt.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_pool.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_service.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_shm.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_status.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_uri_worker_map.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_util.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_version.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_worker.h
+# End Source File
+# End Group
+# Begin Group "Resource Files"
+
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
+# Begin Source File
+
+SOURCE=.\isapi.def
+# End Source File
+# End Group
+# End Target
+# End Project

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/isapi.dsw
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/isapi.dsw	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/isapi.dsw	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,59 @@
+Microsoft Developer Studio Workspace File, Format Version 6.00
+# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
+
+###############################################################################
+
+Project: "dftables"=".\pcre\dftables.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Project: "isapi"=".\isapi.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+    Begin Project Dependency
+    Project_Dep_Name pcre
+    End Project Dependency
+}}}
+
+###############################################################################
+
+Project: "pcre"=".\pcre\pcre.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+    Begin Project Dependency
+    Project_Dep_Name dftables
+    End Project Dependency
+}}}
+
+###############################################################################
+
+Global:
+
+Package=<5>
+{{{
+}}}
+
+Package=<3>
+{{{
+}}}
+
+###############################################################################
+

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/isapi_install.vbs
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/isapi_install.vbs	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/isapi_install.vbs	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,223 @@
+'
+' Copyright 1999-2004 The Apache Software Foundation
+'
+' Licensed 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.
+'
+
+' =========================================================================
+' Description: Install script for Tomcat ISAPI redirector                              
+' Author:      Peter S. Horne <horneps at yahoo.com.au>                           
+' Version:     $Revision: 299505 $                                           
+' =========================================================================
+'
+' This script automatically installs the tomcat isapi_redirector for use in
+' both out-of and in-process installations on IIS/Win2K. See the command line
+' usage section for usage instructions.
+
+'
+'  Check the command line
+'
+set args = wscript.arguments
+if args.count <> 6 then 
+	info ""
+	info "Tomcat ISAPI Redirector Installation Utility"
+	info "usage: isapi_install <server> <fdir> <worker> <mount> <log> <level>"
+	info "	server:	The Web Server Name (for example 'Default Web Site')"
+	info "	fdir:	the full path to the directory that contains the isapi filter"
+	info "	worker:	Full path and file name of the worker properties file"
+	info "	mount:	Full path and file name of the worker mount properties file"
+	info "	log:	Full path and file name of the log file"
+	info "	level:	The log level emerg | info"
+	info "(Re-runs are ok and will change/reset settings)"
+	info ""
+	fail "Incorrect Arguments"
+end if
+
+' Setup the args
+serverName = args(0)
+filterDir = args(1)
+filterName = "jakarta"
+filterLib = "\isapi_redirect.dll"
+workerFile = args(2)
+mountFile = args(3)
+logFile = args(4)
+logLevel = args(5)
+
+'
+' Get a shell
+'
+dim shell
+set shell = WScript.CreateObject("WScript.Shell")
+
+'
+' Find the indicated server from all the servers in the service 
+' Note: they aren't all Web!
+'
+set service = GetObject("IIS://LocalHost/W3SVC" )
+serverId = ""
+for each thing in service
+	 if thing.Class = "IIsWebServer" then
+		if thing.ServerComment = serverName then 
+			set server = thing
+			serverId = thing.name
+			exit for
+		end if
+	end if
+next
+if serverId = "" then fail "Server " + serverName + " not found."
+info "Found Server <" + serverName + "> at index [" + serverId + "]."
+
+'
+' Stop everything to release any dlls - needed for a re-install
+'
+' info "Stopping server <" + serverName + ">..."
+' server.stop
+' info "Done"
+
+'
+' Get a handle to the filters for the server - we process all errors
+'
+On Error Resume Next
+dim filters
+set filters = GetObject("IIS://LocalHost/W3SVC/" + serverId + "/Filters")
+if err then 
+	err.clear
+	info "Filters not found for server - creating"
+	set filters = server.create( "IIsFilters", "Filters" )
+	filters.setInfo
+	if err then fail "Error Creating Filters"
+end if
+info "Got Filters"
+
+'
+' Create the filter - if it fails then delete it and try again
+'
+name = filterName
+info "Creating Filter  - " + filterName
+dim filter
+set filter = filters.Create( "IISFilter", filterName )
+if err then
+	err.clear
+	info "Filter exists - deleting"
+	filters.delete "IISFilter", filterName
+	if err then fail "Error Deleting Filter"
+	set filter = filters.Create( "IISFilter", filterName )
+	if err then fail "Error Creating Filter"
+end if
+info "Created Filter"
+
+'
+' Set the filter info and save it
+'
+filter.FilterPath = filterDir + filterLib  
+filter.FilterEnabled=true
+filter.description = filterName
+filter.notifyOrderHigh = true
+filter.setInfo
+
+'
+' Set the load order - only if it's not in the list already
+'
+on error goto 0
+loadOrders = filters.FilterLoadOrder
+list = Split( loadOrders, "," )
+found = false
+for each item in list
+	if Trim( item ) = filterName then found = true
+next
+
+if found = false then 
+	info "Filter is not in load order - adding now."
+	if len(loadOrders) <> 0  then loadOrders = loadOrders + ","
+	filters.FilterLoadOrder = loadOrders + filterName
+	filters.setInfo
+	info "Filter added."
+else
+	info "Filter already exists in load order - no update required."
+end if
+
+'
+' Set the registry up
+' 
+regRoot = "HKEY_LOCAL_MACHINE\SOFTWARE\Apache Software Foundation\Jakarta Isapi Redirector\1.0\"
+err.clear
+on error resume next
+shell.RegDelete( regRoot )
+if err then 
+	info "Entering Registry Information for the first time"
+else 
+	info "Deleted existing Registry Setting"
+end if
+
+on error goto 0
+info "Updating Registry"
+shell.RegWrite regRoot + "extension_uri", "/jakarta/isapi_redirect.dll"
+shell.RegWrite regRoot + "log_file", logFile
+shell.RegWrite regRoot + "log_level", logLevel
+shell.RegWrite regRoot + "worker_file", workerFile
+shell.RegWrite regRoot + "worker_mount_file", mountFile
+info "Registry Settings Created"
+
+'
+' Finally, create the virtual directory matching th extension uri
+' 
+on error goto 0
+set root = GetObject( "IIS://LocalHost/W3SVC/" + serverID + "/ROOT" )
+on error resume next
+set vdir = root.Create("IISWebVirtualDir", filterName )
+if err then
+	info "Directory exists - deleting"
+	on error resume next
+	root.delete "IISWebVirtualDir", filterName
+	root.setInfo
+	if err then fail "Error Deleting Directory"
+	set vdir = root.create("IISWebVirtualDir", filterName )
+	if err then fail "Error Creating Directory"
+end if
+info "Directory Created"
+
+' Set the directory information - make it an application directory
+info "Setting Directory Information"
+vdir.AppCreate2 1
+vdir.AccessExecute = TRUE
+vdir.AppFriendlyName = filterName
+vdir.AccessRead = false
+vdir.ContentIndexed = false
+vdir.Path = filterDir
+vdir.setInfo
+if err then fail "Error saving new directory"
+info "Directory Saved"
+'
+' Re Start 
+'
+' info "Starting server <" + serverName + ">..."
+' server.start
+' info "Done"
+
+info "All done... Bye."
+wscript.quit(0)
+
+' 
+' Helper function for snafus
+'
+function fail( message )
+	wscript.echo "E: " + message
+	wscript.quit(1)
+end function
+
+'
+' Helper function for info
+'
+function info( message )
+	wscript.echo " " + message
+end function 

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/isapi_redirect.rc
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/isapi_redirect.rc	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/isapi_redirect.rc	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,53 @@
+#define JK_COPYRIGHT "Copyright 2000-2006 The Apache Software " \
+                     "Foundation or its licensors, as applicable."
+
+#define JK_LICENSE "Licensed 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\r\n\r\n" \
+                    "http://www.apache.org/licenses/LICENSE-2.0\r\n\r\n" \
+                    "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."
+
+#define JK_VERSION_STR  "1.2.19"
+#define JK_DLL_BASENAME "isapi_redirect-" JK_VERSION_STR
+
+
+1 VERSIONINFO
+ FILEVERSION 1,2,19,0
+ PRODUCTVERSION 1,2,19,0
+ FILEFLAGSMASK 0x3fL
+#if defined(_DEBUG)
+ FILEFLAGS 0x01L
+#else
+ FILEFLAGS 0x00L
+#endif
+ FILEOS 0x40004L
+ FILETYPE 0x1L
+ FILESUBTYPE 0x0L
+BEGIN
+  BLOCK "StringFileInfo"
+  BEGIN
+    BLOCK "040904b0"
+    BEGIN
+    VALUE "Comments", JK_LICENSE "\0"
+      VALUE "CompanyName", "Apache Software Foundation\0"
+      VALUE "FileDescription", "Apache Tomcat IIS Redirector\0"
+      VALUE "FileVersion", JK_VERSION_STR "\0"
+      VALUE "InternalName", JK_DLL_BASENAME "\0"
+      VALUE "LegalCopyright", JK_COPYRIGHT "\0"
+      VALUE "OriginalFilename", JK_DLL_BASENAME ".dll\0"
+      VALUE "ProductName", "Apache Tomcat Connectors project\0"
+      VALUE "ProductVersion", JK_VERSION_STR "\0"
+    END
+  END
+  BLOCK "VarFileInfo"
+  BEGIN
+    VALUE "Translation", 0x409, 1200
+  END
+END

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/isapi_redirect.reg
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/isapi_redirect.reg	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/isapi_redirect.reg	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,9 @@
+REGEDIT4
+
+[HKEY_LOCAL_MACHINE\SOFTWARE\Apache Software Foundation\Jakarta Isapi Redirector\1.0]
+"log_file"="C:\\tomcat\\logs\\isapi.log"
+"log_level"="debug"
+"worker_file"="C:\\tomcat\\conf\\workers.properties"
+"worker_mount_file"="C:\\tomcat\\conf\\uriworkermap.properties"
+"tomcat_start"="C:\\tomcat\\bin\\tomcat.bat start"
+"tomcat_stop"="C:\\tomcat\\bin\\tomcat.bat stop"

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/jk_isapi_plugin.c
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/jk_isapi_plugin.c	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/jk_isapi_plugin.c	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,1787 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.
+ */
+
+/***************************************************************************
+ * Description: ISAPI plugin for IIS/PWS                                   *
+ * Author:      Gal Shachor <shachor at il.ibm.com>                           *
+ * Author:      Larry Isaacs <larryi at apache.org>                           *
+ * Author:      Ignacio J. Ortega <nacho at apache.org>                       *
+ * Author:      Mladen Turk <mturk at apache.org>                             *
+ * Version:     $Revision: 438903 $                                          *
+ ***************************************************************************/
+
+// This define is needed to include wincrypt,h, needed to get client certificates
+#define _WIN32_WINNT 0x0400
+
+#include <httpext.h>
+#include <httpfilt.h>
+#include <wininet.h>
+
+#include "jk_global.h"
+#include "jk_util.h"
+#include "jk_map.h"
+#include "jk_pool.h"
+#include "jk_service.h"
+#include "jk_worker.h"
+#include "jk_uri_worker_map.h"
+#include "jk_shm.h"
+
+#define VERSION_STRING "Jakarta/ISAPI/" JK_VERSTRING
+#define SHM_DEF_NAME   "JKISAPISHMEM"
+#define DEFAULT_WORKER_NAME ("ajp13")
+/*
+ * We use special headers to pass values from the filter to the
+ * extension. These values are:
+ *
+ * 1. The real URI before redirection took place
+ * 2. The name of the worker to be used.
+ * 3. The contents of the Translate header, if any
+ *
+ */
+#define URI_HEADER_NAME_BASE              ("TOMCATURI")
+#define QUERY_HEADER_NAME_BASE            ("TOMCATQUERY")
+#define WORKER_HEADER_NAME_BASE           ("TOMCATWORKER")
+#define TOMCAT_TRANSLATE_HEADER_NAME_BASE ("TOMCATTRANSLATE")
+#define CONTENT_LENGTH                    ("CONTENT_LENGTH:")
+/* The template used to construct our unique headers
+ * from the base name and module instance
+ */
+#define HEADER_TEMPLATE      ("%s%p:")
+#define HTTP_HEADER_TEMPLATE ("HTTP_%s%p")
+
+static char URI_HEADER_NAME[_MAX_FNAME];
+static char QUERY_HEADER_NAME[_MAX_FNAME];
+static char WORKER_HEADER_NAME[_MAX_FNAME];
+static char TOMCAT_TRANSLATE_HEADER_NAME[_MAX_FNAME];
+
+static char HTTP_URI_HEADER_NAME[_MAX_FNAME];
+static char HTTP_QUERY_HEADER_NAME[_MAX_FNAME];
+static char HTTP_WORKER_HEADER_NAME[_MAX_FNAME];
+
+#define REGISTRY_LOCATION       ("Software\\Apache Software Foundation\\Jakarta Isapi Redirector\\1.0")
+#define EXTENSION_URI_TAG       ("extension_uri")
+
+#define URI_SELECT_TAG              ("uri_select")
+#define URI_SELECT_PARSED_VERB      ("parsed")
+#define URI_SELECT_UNPARSED_VERB    ("unparsed")
+#define URI_SELECT_ESCAPED_VERB     ("escaped")
+#define URI_REWRITE_VERB            ("rewrite_rule_file")
+
+#define TRANSLATE_HEADER                              ("Translate:")
+#define TRANSLATE_HEADER_NAME                         ("Translate")
+#define TRANSLATE_HEADER_NAME_LC                      ("translate")
+
+#define BAD_REQUEST     -1
+#define BAD_PATH        -2
+#define MAX_SERVERNAME  128
+
+#define HTML_ERROR_400          "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\">"  \
+                                "<HTML><HEAD><TITLE>Bad request!</TITLE></HEAD>"                    \
+                                "<BODY><H1>Bad request!</H1><DL><DD>\n"                             \
+                                "Your browser (or proxy) sent a request that "                      \
+                                "this server could not understand.</DL></DD></BODY></HTML>"
+
+#define HTML_ERROR_404          "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\">"  \
+                                "<HTML><HEAD><TITLE>Object not found!</TITLE></HEAD>"               \
+                                "<BODY><H1>The requested URL was not found on this server"          \
+                                "</H1><DL><DD>\nIf you entered the URL manually please check your"  \
+                                "spelling and try again.</DL></DD></BODY></HTML>"
+
+
+#define JK_TOLOWER(x)   ((char)tolower((BYTE)(x)))
+
+#define GET_SERVER_VARIABLE_VALUE(name, place)          \
+  do {                                                  \
+    (place) = NULL;                                     \
+    huge_buf_sz = sizeof(huge_buf);                     \
+    if (get_server_value(private_data->lpEcb,           \
+                        (name),                         \
+                        huge_buf,                       \
+                        huge_buf_sz)) {                 \
+        (place) = jk_pool_strdup(&private_data->p,      \
+                                 huge_buf);             \
+  } } while(0)
+
+#define GET_SERVER_VARIABLE_VALUE_INT(name, place, def)     \
+  do {                                                      \
+    huge_buf_sz = sizeof(huge_buf);                         \
+    if (get_server_value(private_data->lpEcb,               \
+                        (name),                             \
+                        huge_buf,                           \
+                        huge_buf_sz)) {                     \
+        (place) = atoi(huge_buf);                           \
+        if (0 == (place)) {                                 \
+            (place) = def;                                  \
+        }                                                   \
+    } else {                                                \
+        (place) = def;                                      \
+  } } while(0)
+
+static char ini_file_name[MAX_PATH];
+static int using_ini_file = JK_FALSE;
+static int is_inited = JK_FALSE;
+static int is_mapread = JK_FALSE;
+static int iis5 = -1;
+
+static jk_uri_worker_map_t *uw_map = NULL;
+static jk_map_t *workers_map = NULL;
+static jk_map_t *rewrite_map = NULL;
+
+static jk_logger_t *logger = NULL;
+static char *SERVER_NAME = "SERVER_NAME";
+static char *SERVER_SOFTWARE = "SERVER_SOFTWARE";
+static char *CONTENT_TYPE = "Content-Type:text/html\r\n\r\n";
+
+static char extension_uri[INTERNET_MAX_URL_LENGTH] =
+    "/jakarta/isapi_redirect.dll";
+static char log_file[MAX_PATH * 2];
+static int log_level = JK_LOG_DEF_LEVEL;
+static char worker_file[MAX_PATH * 2];
+static char worker_mount_file[MAX_PATH * 2] = {0};
+static char rewrite_rule_file[MAX_PATH * 2] = {0};
+
+#define URI_SELECT_OPT_PARSED       0
+#define URI_SELECT_OPT_UNPARSED     1
+#define URI_SELECT_OPT_ESCAPED      2
+
+static int uri_select_option = URI_SELECT_OPT_PARSED;
+
+static jk_worker_env_t worker_env;
+
+typedef struct isapi_private_data_t isapi_private_data_t;
+struct isapi_private_data_t
+{
+    jk_pool_t p;
+
+    int request_started;
+    unsigned int bytes_read_so_far;
+    LPEXTENSION_CONTROL_BLOCK lpEcb;
+};
+
+typedef struct isapi_log_data_t isapi_log_data_t;
+struct isapi_log_data_t {
+    char uri[INTERNET_MAX_URL_LENGTH];
+    char query[INTERNET_MAX_URL_LENGTH];
+};
+
+static int JK_METHOD start_response(jk_ws_service_t *s,
+                                    int status,
+                                    const char *reason,
+                                    const char *const *header_names,
+                                    const char *const *header_values,
+                                    unsigned int num_of_headers);
+
+static int JK_METHOD read(jk_ws_service_t *s,
+                          void *b, unsigned int l, unsigned int *a);
+
+static int JK_METHOD write(jk_ws_service_t *s, const void *b, unsigned int l);
+
+static int init_ws_service(isapi_private_data_t * private_data,
+                           jk_ws_service_t *s, char **worker_name);
+
+static int init_jk(char *serverName);
+
+static int initialize_extension(void);
+
+static int read_registry_init_data(void);
+
+static int get_registry_config_parameter(HKEY hkey,
+                                         const char *tag, char *b, DWORD sz);
+
+
+static int get_server_value(LPEXTENSION_CONTROL_BLOCK lpEcb,
+                            char *name,
+                            char *buf, DWORD bufsz);
+
+static int base64_encode_cert_len(int len);
+
+static int base64_encode_cert(char *encoded,
+                              const char *string, int len);
+
+
+static char x2c(const char *what)
+{
+    register char digit;
+
+    digit =
+        ((what[0] >= 'A') ? ((what[0] & 0xdf) - 'A') + 10 : (what[0] - '0'));
+    digit *= 16;
+    digit +=
+        (what[1] >= 'A' ? ((what[1] & 0xdf) - 'A') + 10 : (what[1] - '0'));
+    return (digit);
+}
+
+static int unescape_url(char *url)
+{
+    register int x, y, badesc, badpath;
+
+    badesc = 0;
+    badpath = 0;
+    for (x = 0, y = 0; url[y]; ++x, ++y) {
+        if (url[y] != '%')
+            url[x] = url[y];
+        else {
+            if (!isxdigit(url[y + 1]) || !isxdigit(url[y + 2])) {
+                badesc = 1;
+                url[x] = '%';
+            }
+            else {
+                url[x] = x2c(&url[y + 1]);
+                y += 2;
+                if (url[x] == '/' || url[x] == '\0')
+                    badpath = 1;
+            }
+        }
+    }
+    url[x] = '\0';
+    if (badesc)
+        return BAD_REQUEST;
+    else if (badpath)
+        return BAD_PATH;
+    else
+        return 0;
+}
+
+static void getparents(char *name)
+{
+    int l, w;
+
+    /* Four paseses, as per RFC 1808 */
+    /* a) remove ./ path segments */
+
+    for (l = 0, w = 0; name[l] != '\0';) {
+        if (name[l] == '.' && name[l + 1] == '/'
+            && (l == 0 || name[l - 1] == '/'))
+            l += 2;
+        else
+            name[w++] = name[l++];
+    }
+
+    /* b) remove trailing . path, segment */
+    if (w == 1 && name[0] == '.')
+        w--;
+    else if (w > 1 && name[w - 1] == '.' && name[w - 2] == '/')
+        w--;
+    name[w] = '\0';
+
+    /* c) remove all xx/../ segments. (including leading ../ and /../) */
+    l = 0;
+
+    while (name[l] != '\0') {
+        if (name[l] == '.' && name[l + 1] == '.' && name[l + 2] == '/' &&
+            (l == 0 || name[l - 1] == '/')) {
+            register int m = l + 3, n;
+
+            l = l - 2;
+            if (l >= 0) {
+                while (l >= 0 && name[l] != '/')
+                    l--;
+                l++;
+            }
+            else
+                l = 0;
+            n = l;
+            while ((name[n] = name[m]) != '\0') {
+                n++;
+                m++;
+            }
+        }
+        else
+            ++l;
+    }
+
+    /* d) remove trailing xx/.. segment. */
+    if (l == 2 && name[0] == '.' && name[1] == '.')
+        name[0] = '\0';
+    else if (l > 2 && name[l - 1] == '.' && name[l - 2] == '.'
+             && name[l - 3] == '/') {
+        l = l - 4;
+        if (l >= 0) {
+            while (l >= 0 && name[l] != '/')
+                l--;
+            l++;
+        }
+        else
+            l = 0;
+        name[l] = '\0';
+    }
+}
+
+/* Apache code to escape a URL */
+
+#define T_OS_ESCAPE_PATH    (4)
+
+static const BYTE test_char_table[256] = {
+     0, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 14, 14, 14, 14, 14,
+    14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+    14,  0,  7,  6,  1,  6,  1,  1,  9,  9,  1,  0,  8,  0,  0, 10,
+     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  8, 15, 15,  8, 15, 15,
+     8,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 15, 15, 15,  7,  0,
+     7,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 15,  7, 15,  1, 14,
+     6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,
+     6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,
+     6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,
+     6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,
+     6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,
+     6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,
+     6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,
+     6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6
+};
+
+#define TEST_CHAR(c, f) (test_char_table[(unsigned int)(c)] & (f))
+
+static const char c2x_table[] = "0123456789abcdef";
+
+static BYTE *c2x(unsigned int what, BYTE *where)
+{
+    *where++ = '%';
+    *where++ = c2x_table[what >> 4];
+    *where++ = c2x_table[what & 0xf];
+    return where;
+}
+
+static char *status_reason(int status)
+{
+    static struct reasons {
+        int status;
+        char *reason;
+    } *r, reasons[] = {
+        { 100, "Continue" },
+        { 101, "Switching Protocols" },
+        { 200, "OK" },
+        { 201, "Created" },
+        { 202, "Accepted" },
+        { 203, "Non-Authoritative Information" },
+        { 204, "No Content" },
+        { 205, "Reset Content" },
+        { 206, "Partial Content" },
+        { 300, "Multiple Choices" },
+        { 301, "Moved Permanently" },
+        { 302, "Moved Temporarily" },
+        { 303, "See Other" },
+        { 304, "Not Modified" },
+        { 305, "Use Proxy" },
+        { 400, "Bad Request" },
+        { 401, "Unauthorized" },
+        { 402, "Payment Required" },
+        { 403, "Forbidden" },
+        { 404, "Not Found" },
+        { 405, "Method Not Allowed" },
+        { 406, "Not Acceptable" },
+        { 407, "Proxy Authentication Required" },
+        { 408, "Request Timeout" },
+        { 409, "Conflict" },
+        { 410, "Gone" },
+        { 411, "Length Required" },
+        { 412, "Precondition Failed" },
+        { 413, "Request Entity Too Large" },
+        { 414, "Request-URI Too Long" },
+        { 415, "Unsupported Media Type" },
+        { 500, "Internal Server Error" },
+        { 501, "Not Implemented" },
+        { 502, "Bad Gateway" },
+        { 503, "Service Unavailable" },
+        { 504, "Gateway Timeout" },
+        { 505, "HTTP Version Not Supported" },
+        { 000, NULL}
+    };
+
+    r = reasons;
+    while (r->status <= status)
+        if (r->status == status)
+            return r->reason;
+        else
+            r++;
+    return "No Reason";
+}
+
+static int escape_url(const char *path, char *dest, int destsize)
+{
+    const BYTE *s = (const BYTE *)path;
+    BYTE *d = (BYTE *)dest;
+    BYTE *e = d + destsize - 1;
+    BYTE *ee = d + destsize - 3;
+
+    while (*s) {
+        if (TEST_CHAR(*s, T_OS_ESCAPE_PATH)) {
+            if (d >= ee)
+                return JK_FALSE;
+            d = c2x(*s, d);
+        }
+        else {
+            if (d >= e)
+                return JK_FALSE;
+            *d++ = *s;
+        }
+        ++s;
+    }
+    *d = '\0';
+    return JK_TRUE;
+}
+
+/*
+ * Find the first occurrence of find in s.
+ */
+static char *stristr(const char *s, const char *find)
+{
+    char c, sc;
+    size_t len;
+
+    if ((c = tolower((unsigned char)(*find++))) != 0) {
+        len = strlen(find);
+        do {
+            do {
+                if ((sc = tolower((unsigned char)(*s++))) == 0)
+                    return (NULL);
+            } while (sc != c);
+        } while (strnicmp(s, find, len) != 0);
+        s--;
+    }
+    return ((char *)s);
+}
+
+static int uri_is_web_inf(const char *uri)
+{
+    if (stristr(uri, "web-inf")) {
+        return JK_TRUE;
+    }
+    if (stristr(uri, "meta-inf")) {
+        return JK_TRUE;
+    }
+
+    return JK_FALSE;
+}
+
+static void write_error_response(PHTTP_FILTER_CONTEXT pfc, char *status,
+                                 char *msg)
+{
+    DWORD len = (DWORD)strlen(msg);
+
+    /* reject !!! */
+    pfc->AddResponseHeaders(pfc, CONTENT_TYPE, 0);
+    pfc->ServerSupportFunction(pfc,
+                               SF_REQ_SEND_RESPONSE_HEADER,
+                               status, 0, 0);
+    pfc->WriteClient(pfc, msg, &len, 0);
+}
+
+
+static int JK_METHOD start_response(jk_ws_service_t *s,
+                                    int status,
+                                    const char *reason,
+                                    const char *const *header_names,
+                                    const char *const *header_values,
+                                    unsigned int num_of_headers)
+{
+    static char crlf[3] = { (char)13, (char)10, '\0' };
+
+    JK_TRACE_ENTER(logger);
+    if (status < 100 || status > 1000) {
+        jk_log(logger, JK_LOG_ERROR,
+               "invalid status %d",
+               status);
+        JK_TRACE_EXIT(logger);
+        return JK_FALSE;
+    }
+
+    if (s && s->ws_private) {
+        isapi_private_data_t *p = s->ws_private;
+        if (!p->request_started) {
+            size_t len_of_status;
+            char *status_str;
+            char *headers_str;
+
+            p->request_started = JK_TRUE;
+
+            /*
+             * Create the status line
+             */
+            if (!reason) {
+                reason = status_reason(status);
+            }
+            status_str = (char *)_alloca((6 + strlen(reason)) * sizeof(char));
+            sprintf(status_str, "%d %s", status, reason);
+            len_of_status = strlen(status_str);
+
+            /*
+             * Create response headers string
+             */
+            if (num_of_headers) {
+                size_t i, len_of_headers;
+                for (i = 0, len_of_headers = 0; i < num_of_headers; i++) {
+                    len_of_headers += strlen(header_names[i]);
+                    len_of_headers += strlen(header_values[i]);
+                    len_of_headers += 4;        /* extra for colon, space and crlf */
+                }
+
+                len_of_headers += 3;    /* crlf and terminating null char */
+                headers_str = (char *)_alloca(len_of_headers * sizeof(char));
+                headers_str[0] = '\0';
+
+                for (i = 0; i < num_of_headers; i++) {
+                    strcat(headers_str, header_names[i]);
+                    strcat(headers_str, ": ");
+                    strcat(headers_str, header_values[i]);
+                    strcat(headers_str, crlf);
+                }
+                strcat(headers_str, crlf);
+            }
+            else {
+                headers_str = crlf;
+            }
+
+            if (!p->lpEcb->ServerSupportFunction(p->lpEcb->ConnID,
+                                                 HSE_REQ_SEND_RESPONSE_HEADER,
+                                                 status_str,
+                                                 (LPDWORD) &len_of_status,
+                                                 (LPDWORD) headers_str)) {
+                jk_log(logger, JK_LOG_ERROR,
+                       "HSE_REQ_SEND_RESPONSE_HEADER failed");
+                JK_TRACE_EXIT(logger);
+                return JK_FALSE;
+            }
+        }
+        JK_TRACE_EXIT(logger);
+        return JK_TRUE;
+
+    }
+
+    JK_LOG_NULL_PARAMS(logger);
+    JK_TRACE_EXIT(logger);
+    return JK_FALSE;
+}
+
+static int JK_METHOD read(jk_ws_service_t *s,
+                          void *b, unsigned int l, unsigned int *a)
+{
+    JK_TRACE_ENTER(logger);
+
+    if (s && s->ws_private && b && a) {
+        isapi_private_data_t *p = s->ws_private;
+
+        *a = 0;
+        if (l) {
+            char *buf = b;
+            DWORD already_read = p->lpEcb->cbAvailable - p->bytes_read_so_far;
+
+            if (already_read >= l) {
+                memcpy(buf, p->lpEcb->lpbData + p->bytes_read_so_far, l);
+                p->bytes_read_so_far += l;
+                *a = l;
+            }
+            else {
+                /*
+                 * Try to copy what we already have
+                 */
+                if (already_read > 0) {
+                    memcpy(buf, p->lpEcb->lpbData + p->bytes_read_so_far,
+                           already_read);
+                    buf += already_read;
+                    l -= already_read;
+                    p->bytes_read_so_far = p->lpEcb->cbAvailable;
+
+                    *a = already_read;
+                }
+
+                /*
+                 * Now try to read from the client ...
+                 */
+                if (p->lpEcb->ReadClient(p->lpEcb->ConnID, buf, (LPDWORD)&l)) {
+                    *a += l;
+                }
+                else {
+                    jk_log(logger, JK_LOG_ERROR,
+                           "ReadClient failed with %08x", GetLastError());
+                    JK_TRACE_EXIT(logger);
+                    return JK_FALSE;
+                }
+            }
+        }
+        JK_TRACE_EXIT(logger);
+        return JK_TRUE;
+    }
+
+    JK_LOG_NULL_PARAMS(logger);
+    JK_TRACE_EXIT(logger);
+    return JK_FALSE;
+}
+
+static int JK_METHOD write(jk_ws_service_t *s, const void *b, unsigned int l)
+{
+    JK_TRACE_ENTER(logger);
+
+    if (s && s->ws_private && b) {
+        isapi_private_data_t *p = s->ws_private;
+
+        if (l) {
+            unsigned int written = 0;
+            char *buf = (char *)b;
+
+            if (!p->request_started) {
+                start_response(s, 200, NULL, NULL, NULL, 0);
+            }
+
+            while (written < l) {
+                DWORD try_to_write = l - written;
+                if (!p->lpEcb->WriteClient(p->lpEcb->ConnID,
+                                           buf + written, &try_to_write, 0)) {
+                    jk_log(logger, JK_LOG_ERROR,
+                           "WriteClient failed with %08x", GetLastError());
+                    JK_TRACE_EXIT(logger);
+                    return JK_FALSE;
+                }
+                written += try_to_write;
+            }
+        }
+
+        JK_TRACE_EXIT(logger);
+        return JK_TRUE;
+
+    }
+
+    JK_LOG_NULL_PARAMS(logger);
+    JK_TRACE_EXIT(logger);
+    return JK_FALSE;
+}
+
+BOOL WINAPI GetFilterVersion(PHTTP_FILTER_VERSION pVer)
+{
+    ULONG http_filter_revision = HTTP_FILTER_REVISION;
+
+    pVer->dwFilterVersion = pVer->dwServerFilterVersion;
+
+    if (pVer->dwFilterVersion > http_filter_revision) {
+        pVer->dwFilterVersion = http_filter_revision;
+    }
+
+    pVer->dwFlags = SF_NOTIFY_ORDER_HIGH |
+                    SF_NOTIFY_SECURE_PORT |
+                    SF_NOTIFY_NONSECURE_PORT |
+                    SF_NOTIFY_PREPROC_HEADERS |
+                    SF_NOTIFY_LOG |
+                    SF_NOTIFY_AUTH_COMPLETE;
+
+    strcpy(pVer->lpszFilterDesc, VERSION_STRING);
+
+    if (!is_inited) {
+        return initialize_extension();
+    }
+
+    return TRUE;
+}
+
+static int simple_rewrite(char *uri)
+{
+    if (rewrite_map) {
+        int i;
+        char buf[INTERNET_MAX_URL_LENGTH];
+        for (i = 0; i < jk_map_size(rewrite_map); i++) {
+            const char *src = jk_map_name_at(rewrite_map, i);
+            if (strncmp(uri, src, strlen(src)) == 0) {
+                strcpy(buf, jk_map_value_at(rewrite_map, i));
+                strcat(buf, uri + strlen(src));
+                strcpy(uri, buf);
+                return 1;
+            }
+        }
+    }
+    return 0;
+}
+
+DWORD WINAPI HttpFilterProc(PHTTP_FILTER_CONTEXT pfc,
+                            DWORD dwNotificationType, LPVOID pvNotification)
+{
+    /* Initialise jk */
+    if (is_inited && !is_mapread) {
+        char serverName[MAX_SERVERNAME];
+        DWORD dwLen = sizeof(serverName);
+
+        if (pfc->GetServerVariable(pfc, SERVER_NAME, serverName, &dwLen)) {
+            if (dwLen > 0)
+                serverName[dwLen - 1] = '\0';
+            if (init_jk(serverName))
+                is_mapread = JK_TRUE;
+        }
+        /* If we can't read the map we become dormant */
+        if (!is_mapread)
+            is_inited = JK_FALSE;
+    }
+
+    if (is_inited && (iis5 < 0)) {
+        char serverSoftware[256];
+        DWORD dwLen = sizeof(serverSoftware);
+        iis5 = 0;
+        if (pfc->
+            GetServerVariable(pfc, SERVER_SOFTWARE, serverSoftware, &dwLen)) {
+            iis5 = (atof(serverSoftware + 14) >= 5.0);
+            if (iis5) {
+                jk_log(logger, JK_LOG_DEBUG, "Detected IIS >= 5.0");
+            }
+            else {
+                jk_log(logger, JK_LOG_DEBUG, "Detected IIS < 5.0");
+            }
+        }
+    }
+
+    if (is_inited &&
+        (((SF_NOTIFY_PREPROC_HEADERS == dwNotificationType) && !iis5) ||
+         ((SF_NOTIFY_AUTH_COMPLETE == dwNotificationType) && iis5)
+        )
+        ) {
+        char uri[INTERNET_MAX_URL_LENGTH];
+        char snuri[INTERNET_MAX_URL_LENGTH] = "/";
+        char Host[INTERNET_MAX_URL_LENGTH] = "";
+        char Port[INTERNET_MAX_URL_LENGTH] = "";
+        char Translate[INTERNET_MAX_URL_LENGTH];
+        char squery[INTERNET_MAX_URL_LENGTH] = "";
+        BOOL(WINAPI * GetHeader)
+            (struct _HTTP_FILTER_CONTEXT * pfc, LPSTR lpszName,
+             LPVOID lpvBuffer, LPDWORD lpdwSize);
+        BOOL(WINAPI * SetHeader)
+            (struct _HTTP_FILTER_CONTEXT * pfc, LPSTR lpszName,
+             LPSTR lpszValue);
+        BOOL(WINAPI * AddHeader)
+            (struct _HTTP_FILTER_CONTEXT * pfc, LPSTR lpszName,
+             LPSTR lpszValue);
+        char *query;
+        DWORD sz = sizeof(uri);
+        DWORD szHost = sizeof(Host);
+        DWORD szPort = sizeof(Port);
+        DWORD szTranslate = sizeof(Translate);
+
+        if (iis5) {
+            GetHeader =
+                ((PHTTP_FILTER_AUTH_COMPLETE_INFO) pvNotification)->GetHeader;
+            SetHeader =
+                ((PHTTP_FILTER_AUTH_COMPLETE_INFO) pvNotification)->SetHeader;
+            AddHeader =
+                ((PHTTP_FILTER_AUTH_COMPLETE_INFO) pvNotification)->AddHeader;
+        }
+        else {
+            GetHeader =
+                ((PHTTP_FILTER_PREPROC_HEADERS) pvNotification)->GetHeader;
+            SetHeader =
+                ((PHTTP_FILTER_PREPROC_HEADERS) pvNotification)->SetHeader;
+            AddHeader =
+                ((PHTTP_FILTER_PREPROC_HEADERS) pvNotification)->AddHeader;
+        }
+
+        if (JK_IS_DEBUG_LEVEL(logger))
+            jk_log(logger, JK_LOG_DEBUG, "Filter started");
+
+        /*
+         * Just in case somebody set these headers in the request!
+         */
+        SetHeader(pfc, URI_HEADER_NAME, NULL);
+        SetHeader(pfc, QUERY_HEADER_NAME, NULL);
+        SetHeader(pfc, WORKER_HEADER_NAME, NULL);
+        SetHeader(pfc, TOMCAT_TRANSLATE_HEADER_NAME, NULL);
+
+        if (!GetHeader(pfc, "url", (LPVOID) uri, (LPDWORD) & sz)) {
+            jk_log(logger, JK_LOG_ERROR,
+                   "error while getting the url");
+            return SF_STATUS_REQ_ERROR;
+        }
+
+        if (strlen(uri)) {
+            int rc;
+            const char *worker = NULL;
+            query = strchr(uri, '?');
+            if (query) {
+                *query++ = '\0';
+                strcpy(squery, query);
+            }
+
+            rc = unescape_url(uri);
+            if (rc == BAD_REQUEST) {
+                jk_log(logger, JK_LOG_ERROR,
+                       "[%s] contains one or more invalid escape sequences.",
+                       uri);
+                write_error_response(pfc, "400 Bad Request",
+                                     HTML_ERROR_400);
+                return SF_STATUS_REQ_FINISHED;
+            }
+            else if (rc == BAD_PATH) {
+                jk_log(logger, JK_LOG_EMERG,
+                       "[%s] contains forbidden escape sequences.",
+                       uri);
+                write_error_response(pfc, "404 Not Found",
+                                     HTML_ERROR_404);
+                return SF_STATUS_REQ_FINISHED;
+            }
+            getparents(uri);
+            if (pfc->
+                GetServerVariable(pfc, SERVER_NAME, (LPVOID) Host,
+                                  (LPDWORD) & szHost)) {
+                if (szHost > 0) {
+                    Host[szHost - 1] = '\0';
+                }
+            }
+            Port[0] = '\0';
+            if (pfc->
+                GetServerVariable(pfc, "SERVER_PORT", (LPVOID) Port,
+                                  (LPDWORD) & szPort)) {
+                if (szPort > 0) {
+                    Port[szPort - 1] = '\0';
+                }
+            }
+            szPort = atoi(Port);
+            if (szPort != 80 && szPort != 443 && szHost > 0) {
+                strcat(Host, ":");
+                strcat(Host, Port);
+            }
+            if (szHost > 0) {
+                strcat(snuri, Host);
+                strcat(snuri, uri);
+                if (JK_IS_DEBUG_LEVEL(logger))
+                    jk_log(logger, JK_LOG_DEBUG,
+                           "Virtual Host redirection of %s",
+                           snuri);
+                worker = map_uri_to_worker(uw_map, snuri, logger);
+            }
+            if (!worker) {
+                if (JK_IS_DEBUG_LEVEL(logger))
+                    jk_log(logger, JK_LOG_DEBUG,
+                           "Default redirection of %s",
+                           uri);
+                worker = map_uri_to_worker(uw_map, uri, logger);
+            }
+            /*
+             * Check if somebody is feading us with his own TOMCAT data headers.
+             * We reject such postings !
+             */
+            if (JK_IS_DEBUG_LEVEL(logger))
+                jk_log(logger, JK_LOG_DEBUG,
+                       "check if [%s] is points to the web-inf directory",
+                       uri);
+
+            if (uri_is_web_inf(uri)) {
+                jk_log(logger, JK_LOG_EMERG,
+                       "[%s] points to the web-inf or meta-inf directory.\nSomebody try to hack into the site!!!",
+                       uri);
+
+                write_error_response(pfc, "404 Not Found",
+                                     HTML_ERROR_404);
+                return SF_STATUS_REQ_FINISHED;
+            }
+
+            if (worker) {
+                char *forwardURI;
+
+                /* This is a servlet, should redirect ... */
+                jk_log(logger, JK_LOG_DEBUG,
+                       "[%s] is a servlet url - should redirect to %s",
+                       uri, worker);
+
+                /* get URI we should forward */
+                if (uri_select_option == URI_SELECT_OPT_UNPARSED) {
+                    /* get original unparsed URI */
+                    GetHeader(pfc, "url", (LPVOID) uri, (LPDWORD) & sz);
+                    /* restore terminator for uri portion */
+                    if (query)
+                        *(query - 1) = '\0';
+                    if (JK_IS_DEBUG_LEVEL(logger))
+                        jk_log(logger, JK_LOG_DEBUG,
+                               "fowarding original URI [%s]",
+                               uri);
+                    forwardURI = uri;
+                }
+                else if (uri_select_option == URI_SELECT_OPT_ESCAPED) {
+                    if (!escape_url(uri, snuri, INTERNET_MAX_URL_LENGTH)) {
+                        jk_log(logger, JK_LOG_ERROR,
+                               "[%s] re-encoding request exceeds maximum buffer size.",
+                               uri);
+                        write_error_response(pfc, "400 Bad Request",
+                                             HTML_ERROR_400);
+                        return SF_STATUS_REQ_FINISHED;
+                    }
+                    if (JK_IS_DEBUG_LEVEL(logger))
+                        jk_log(logger, JK_LOG_DEBUG,
+                               "fowarding escaped URI [%s]",
+                               snuri);
+                    forwardURI = snuri;
+                }
+                else {
+                    forwardURI = uri;
+                }
+                /* Do a simple rewrite .
+                 * Note that URI can be escaped, so thus the rule has
+                 * to be in that case.
+                 *
+                 * TODO: Add more advanced regexp rewrite.
+                 */
+                if (JK_IS_DEBUG_LEVEL(logger)) {
+                    char duri[INTERNET_MAX_URL_LENGTH];
+                    strcpy(duri, forwardURI);
+                    if (simple_rewrite(forwardURI)) {
+                        jk_log(logger, JK_LOG_DEBUG,
+                               "rewriten URI [%s]->[%s]",
+                               duri, forwardURI);
+                    }
+                }
+                else {
+                    simple_rewrite(forwardURI);
+                }
+
+                if (!AddHeader(pfc, URI_HEADER_NAME, forwardURI) ||
+                    ((strlen(squery) > 0)
+                     ? !AddHeader(pfc, QUERY_HEADER_NAME, squery) : FALSE) ||
+                    !AddHeader(pfc, WORKER_HEADER_NAME, (LPSTR)worker) ||
+                    !SetHeader(pfc, "url", extension_uri)) {
+                    jk_log(logger, JK_LOG_ERROR,
+                           "error while adding request headers");
+                    return SF_STATUS_REQ_ERROR;
+                }
+
+                /* Move Translate: header to a temporary header so
+                 * that the extension proc will be called.
+                 * This allows the servlet to handle 'Translate: f'.
+                 */
+                if (GetHeader
+                    (pfc, TRANSLATE_HEADER, (LPVOID) Translate,
+                     (LPDWORD) & szTranslate) && Translate != NULL
+                    && szTranslate > 0) {
+                    if (!AddHeader
+                        (pfc, TOMCAT_TRANSLATE_HEADER_NAME, Translate)) {
+                        jk_log(logger, JK_LOG_ERROR,
+                               "error while adding Tomcat-Translate headers");
+                        return SF_STATUS_REQ_ERROR;
+                    }
+                    SetHeader(pfc, "Translate:", NULL);
+                }
+                if (!pfc->pFilterContext) {
+                    isapi_log_data_t *ld = (isapi_log_data_t *)pfc->AllocMem(pfc, sizeof(isapi_log_data_t), 0);
+                    if (!ld) {
+                        jk_log(logger, JK_LOG_ERROR,
+                               "error while allocating memory");
+                        SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+                        return SF_STATUS_REQ_ERROR;
+                    }
+                    memset(ld, 0, sizeof(isapi_log_data_t));
+                    strcpy(ld->uri, forwardURI);
+                    strcpy(ld->query, squery);
+                    pfc->pFilterContext = ld;
+                } else {
+                    isapi_log_data_t *ld = (isapi_log_data_t *)pfc->pFilterContext;
+                    memset(ld, 0, sizeof(isapi_log_data_t));
+                    strcpy(ld->uri, forwardURI);
+                    strcpy(ld->query, squery);
+                }
+            }
+            else {
+                if (JK_IS_DEBUG_LEVEL(logger))
+                    jk_log(logger, JK_LOG_DEBUG,
+                           "[%s] is not a servlet url", uri);
+            }
+        }
+    }
+    else if (is_inited && (dwNotificationType == SF_NOTIFY_LOG)) {
+        if (pfc->pFilterContext) {
+            isapi_log_data_t *ld = (isapi_log_data_t *)pfc->pFilterContext;
+            HTTP_FILTER_LOG  *pl = (HTTP_FILTER_LOG *)pvNotification;
+            pl->pszTarget = ld->uri;
+            pl->pszParameters = ld->query;
+        }
+    }
+    return SF_STATUS_REQ_NEXT_NOTIFICATION;
+}
+
+
+BOOL WINAPI GetExtensionVersion(HSE_VERSION_INFO * pVer)
+{
+    pVer->dwExtensionVersion = MAKELONG(HSE_VERSION_MINOR, HSE_VERSION_MAJOR);
+
+    strcpy(pVer->lpszExtensionDesc, VERSION_STRING);
+
+
+    if (!is_inited) {
+        return initialize_extension();
+    }
+
+    return TRUE;
+}
+
+DWORD WINAPI HttpExtensionProc(LPEXTENSION_CONTROL_BLOCK lpEcb)
+{
+    DWORD rc = HSE_STATUS_ERROR;
+
+    lpEcb->dwHttpStatusCode = HTTP_STATUS_SERVER_ERROR;
+
+    JK_TRACE_ENTER(logger);
+
+    /* Initialise jk */
+    if (is_inited && !is_mapread) {
+        char serverName[MAX_SERVERNAME];
+        DWORD dwLen = sizeof(serverName);
+        if (lpEcb->
+            GetServerVariable(lpEcb->ConnID, SERVER_NAME, serverName,
+                              &dwLen)) {
+            if (dwLen > 0)
+                serverName[dwLen - 1] = '\0';
+            if (init_jk(serverName))
+                is_mapread = JK_TRUE;
+        }
+        if (!is_mapread)
+            is_inited = JK_FALSE;
+    }
+
+    if (is_inited) {
+        isapi_private_data_t private_data;
+        jk_ws_service_t s;
+        jk_pool_atom_t buf[SMALL_POOL_SIZE];
+        char *worker_name;
+
+        wc_maintain(logger);
+        jk_init_ws_service(&s);
+        jk_open_pool(&private_data.p, buf, sizeof(buf));
+
+        private_data.request_started = JK_FALSE;
+        private_data.bytes_read_so_far = 0;
+        private_data.lpEcb = lpEcb;
+
+        s.ws_private = &private_data;
+        s.pool = &private_data.p;
+
+        if (init_ws_service(&private_data, &s, &worker_name)) {
+            jk_worker_t *worker = wc_get_worker_for_name(worker_name, logger);
+
+            if (JK_IS_DEBUG_LEVEL(logger))
+                jk_log(logger, JK_LOG_DEBUG,
+                       "%s a worker for name %s",
+                       worker ? "got" : "could not get", worker_name);
+
+            if (worker) {
+                jk_endpoint_t *e = NULL;
+                /* Update retries for this worker */
+                s.retries = worker->retries;
+                if (worker->get_endpoint(worker, &e, logger)) {
+                    int is_error = JK_HTTP_SERVER_ERROR;
+                    if (e->service(e, &s, logger, &is_error)) {
+                        rc = HSE_STATUS_SUCCESS;
+                        lpEcb->dwHttpStatusCode = HTTP_STATUS_OK;
+                        jk_log(logger, JK_LOG_DEBUG,
+                               "service() returned OK");
+                    }
+                    else {
+                        lpEcb->dwHttpStatusCode = is_error;
+                        jk_log(logger, JK_LOG_ERROR,
+                               "service() failed");
+                    }
+                    e->done(&e, logger);
+                }
+            }
+            else {
+                jk_log(logger, JK_LOG_ERROR,
+                       "could not get a worker for name %s",
+                       worker_name);
+            }
+        }
+        jk_close_pool(&private_data.p);
+    }
+    else {
+        jk_log(logger, JK_LOG_ERROR,
+               "not initialized");
+    }
+
+    JK_TRACE_EXIT(logger);
+    return rc;
+}
+
+
+
+BOOL WINAPI TerminateExtension(DWORD dwFlags)
+{
+    return TerminateFilter(dwFlags);
+}
+
+BOOL WINAPI TerminateFilter(DWORD dwFlags)
+{
+    UNREFERENCED_PARAMETER(dwFlags);
+
+    if (is_inited) {
+        is_inited = JK_FALSE;
+
+        if (is_mapread) {
+            uri_worker_map_free(&uw_map, logger);
+            is_mapread = JK_FALSE;
+        }
+        if (workers_map) {
+            jk_map_free(&workers_map);
+            workers_map = NULL;
+        }
+        wc_close(logger);
+        if (logger) {
+            jk_close_file_logger(&logger);
+        }
+    }
+
+    return TRUE;
+}
+
+
+BOOL WINAPI DllMain(HINSTANCE hInst,    // Instance Handle of the DLL
+                    ULONG ulReason,     // Reason why NT called this DLL
+                    LPVOID lpReserved)  // Reserved parameter for future use
+{
+    BOOL fReturn = TRUE;
+    char drive[_MAX_DRIVE];
+    char dir[_MAX_DIR];
+    char fname[_MAX_FNAME];
+    char file_name[_MAX_PATH];
+
+    UNREFERENCED_PARAMETER(lpReserved);
+
+    switch (ulReason) {
+    case DLL_PROCESS_ATTACH:
+        if (GetModuleFileName(hInst, file_name, sizeof(file_name))) {
+            _splitpath(file_name, drive, dir, fname, NULL);
+            _makepath(ini_file_name, drive, dir, fname, ".properties");
+        }
+        else {
+            fReturn = JK_FALSE;
+        }
+        /* Construct redirector headers to use for this redirector instance */
+        sprintf(URI_HEADER_NAME, HEADER_TEMPLATE, URI_HEADER_NAME_BASE, hInst);
+        sprintf(QUERY_HEADER_NAME, HEADER_TEMPLATE, QUERY_HEADER_NAME_BASE, hInst);
+        sprintf(WORKER_HEADER_NAME, HEADER_TEMPLATE, WORKER_HEADER_NAME_BASE, hInst);
+        sprintf(TOMCAT_TRANSLATE_HEADER_NAME, HEADER_TEMPLATE, TOMCAT_TRANSLATE_HEADER_NAME_BASE, hInst);
+
+        sprintf(HTTP_URI_HEADER_NAME, HTTP_HEADER_TEMPLATE, URI_HEADER_NAME_BASE, hInst);
+        sprintf(HTTP_QUERY_HEADER_NAME, HTTP_HEADER_TEMPLATE, QUERY_HEADER_NAME_BASE, hInst);
+        sprintf(HTTP_WORKER_HEADER_NAME, HTTP_HEADER_TEMPLATE, WORKER_HEADER_NAME_BASE, hInst);
+
+    break;
+    case DLL_PROCESS_DETACH:
+        __try {
+            TerminateFilter(HSE_TERM_MUST_UNLOAD);
+        }
+        __except(1) {
+        }
+        break;
+
+    default:
+        break;
+    }
+
+    return fReturn;
+}
+
+static int init_jk(char *serverName)
+{
+    int rc = JK_FALSE;
+
+    if (!jk_open_file_logger(&logger, log_file, log_level)) {
+        logger = NULL;
+    }
+     /* Simulate shared memory
+      * For now use fixed size.
+      */
+     jk_shm_open(SHM_DEF_NAME, JK_SHM_DEF_SIZE, logger);
+
+     /* 10 is minimum supported on WINXP */
+     jk_set_worker_def_cache_size(10);
+
+    /* Logging the initialization type: registry or properties file in virtual dir
+     */
+    if (JK_IS_DEBUG_LEVEL(logger)) {
+        if (using_ini_file) {
+            jk_log(logger, JK_LOG_DEBUG, "Using ini file %s.", ini_file_name);
+        }
+        else {
+            jk_log(logger, JK_LOG_DEBUG, "Using registry.");
+        }
+
+        jk_log(logger, JK_LOG_DEBUG, "Using log file %s.", log_file);
+        jk_log(logger, JK_LOG_DEBUG, "Using log level %d.", log_level);
+        jk_log(logger, JK_LOG_DEBUG, "Using extension uri %s.", extension_uri);
+        jk_log(logger, JK_LOG_DEBUG, "Using worker file %s.", worker_file);
+        jk_log(logger, JK_LOG_DEBUG, "Using worker mount file %s.",
+               worker_mount_file);
+        jk_log(logger, JK_LOG_DEBUG, "Using rewrite rule file %s.",
+               rewrite_rule_file);
+        jk_log(logger, JK_LOG_DEBUG, "Using uri select %d.", uri_select_option);
+    }
+
+    if (rewrite_rule_file[0] && jk_map_alloc(&rewrite_map)) {
+        if (jk_map_read_properties(rewrite_map, rewrite_rule_file, NULL, logger)) {
+            if (JK_IS_DEBUG_LEVEL(logger)) {
+                jk_log(logger, JK_LOG_DEBUG, "Loaded rewrite rule file %s.",
+                       rewrite_rule_file);
+
+            }
+            else {
+                jk_map_free(&rewrite_map);
+            }
+        }
+    }
+
+    if (uri_worker_map_alloc(&uw_map, NULL, logger)) {
+        rc = JK_FALSE;
+        uw_map->fname = worker_mount_file;
+        if (worker_mount_file[0])
+            rc = uri_worker_map_load(uw_map, logger);
+    }
+    if (rc) {
+        rc = JK_FALSE;
+        if (jk_map_alloc(&workers_map)) {
+            if (jk_map_read_properties(workers_map, worker_file, NULL, logger)) {
+                /* we add the URI->WORKER MAP since workers using AJP14 will feed it */
+
+                worker_env.uri_to_worker = uw_map;
+                worker_env.server_name = serverName;
+
+                if (wc_open(workers_map, &worker_env, logger)) {
+                    rc = JK_TRUE;
+                }
+            }
+            else {
+                jk_log(logger, JK_LOG_EMERG,
+                       "Unable to read worker file %s.", worker_file);
+            }
+            if (rc != JK_TRUE) {
+                jk_map_free(&workers_map);
+                workers_map = NULL;
+            }
+        }
+    }
+
+    return rc;
+}
+
+static int initialize_extension(void)
+{
+
+    if (read_registry_init_data()) {
+        is_inited = JK_TRUE;
+    }
+    return is_inited;
+}
+
+int parse_uri_select(const char *uri_select)
+{
+    if (0 == strcasecmp(uri_select, URI_SELECT_PARSED_VERB)) {
+        return URI_SELECT_OPT_PARSED;
+    }
+
+    if (0 == strcasecmp(uri_select, URI_SELECT_UNPARSED_VERB)) {
+        return URI_SELECT_OPT_UNPARSED;
+    }
+
+    if (0 == strcasecmp(uri_select, URI_SELECT_ESCAPED_VERB)) {
+        return URI_SELECT_OPT_ESCAPED;
+    }
+
+    return -1;
+}
+
+static int read_registry_init_data(void)
+{
+    char tmpbuf[INTERNET_MAX_URL_LENGTH];
+    HKEY hkey;
+    long rc;
+    int ok = JK_TRUE;
+    const char *tmp;
+    jk_map_t *map;
+
+    if (jk_map_alloc(&map)) {
+        if (jk_map_read_properties(map, ini_file_name, NULL, logger)) {
+            using_ini_file = JK_TRUE;
+        }
+    }
+    if (using_ini_file) {
+        tmp = jk_map_get_string(map, JK_LOG_FILE_TAG, NULL);
+        if (tmp) {
+            strcpy(log_file, tmp);
+        }
+        else {
+            ok = JK_FALSE;
+        }
+        tmp = jk_map_get_string(map, JK_LOG_LEVEL_TAG, NULL);
+        if (tmp) {
+            log_level = jk_parse_log_level(tmp);
+        }
+        tmp = jk_map_get_string(map, EXTENSION_URI_TAG, NULL);
+        if (tmp) {
+            strcpy(extension_uri, tmp);
+        }
+        else {
+            ok = JK_FALSE;
+        }
+        tmp = jk_map_get_string(map, JK_WORKER_FILE_TAG, NULL);
+        if (tmp) {
+            strcpy(worker_file, tmp);
+        }
+        else {
+            ok = JK_FALSE;
+        }
+        tmp = jk_map_get_string(map, JK_MOUNT_FILE_TAG, NULL);
+        if (tmp) {
+            strcpy(worker_mount_file, tmp);
+        }
+        else {
+            ok = JK_FALSE;
+        }
+        tmp = jk_map_get_string(map, URI_REWRITE_VERB, NULL);
+        if (tmp) {
+            strcpy(rewrite_rule_file, tmp);
+        }
+        tmp = jk_map_get_string(map, URI_SELECT_TAG, NULL);
+        if (tmp) {
+            int opt = parse_uri_select(tmp);
+            if (opt >= 0) {
+                uri_select_option = opt;
+            }
+            else {
+                ok = JK_FALSE;
+            }
+        }
+
+    }
+    else {
+        rc = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
+                          REGISTRY_LOCATION, (DWORD) 0, KEY_READ, &hkey);
+        if (ERROR_SUCCESS != rc) {
+            return JK_FALSE;
+        }
+
+        if (get_registry_config_parameter(hkey,
+                                          JK_LOG_FILE_TAG,
+                                          tmpbuf, sizeof(log_file))) {
+            strcpy(log_file, tmpbuf);
+        }
+        else {
+            ok = JK_FALSE;
+        }
+
+        if (get_registry_config_parameter(hkey,
+                                          JK_LOG_LEVEL_TAG,
+                                          tmpbuf, sizeof(tmpbuf))) {
+            log_level = jk_parse_log_level(tmpbuf);
+        }
+
+        if (get_registry_config_parameter(hkey,
+                                          EXTENSION_URI_TAG,
+                                          tmpbuf, sizeof(extension_uri))) {
+            strcpy(extension_uri, tmpbuf);
+        }
+        else {
+            ok = JK_FALSE;
+        }
+
+        if (get_registry_config_parameter(hkey,
+                                          JK_WORKER_FILE_TAG,
+                                          tmpbuf, sizeof(worker_file))) {
+            strcpy(worker_file, tmpbuf);
+        }
+        else {
+            ok = JK_FALSE;
+        }
+
+        if (get_registry_config_parameter(hkey,
+                                          JK_MOUNT_FILE_TAG,
+                                          tmpbuf,
+                                          sizeof(worker_mount_file))) {
+            strcpy(worker_mount_file, tmpbuf);
+        }
+        else {
+            ok = JK_FALSE;
+        }
+
+        if (get_registry_config_parameter(hkey,
+                                          URI_REWRITE_VERB,
+                                          tmpbuf,
+                                          sizeof(rewrite_rule_file))) {
+            strcpy(rewrite_rule_file, tmpbuf);
+        }
+
+        if (get_registry_config_parameter(hkey,
+                                          URI_SELECT_TAG,
+                                          tmpbuf, sizeof(tmpbuf))) {
+            int opt = parse_uri_select(tmpbuf);
+            if (opt >= 0) {
+                uri_select_option = opt;
+            }
+            else {
+                ok = JK_FALSE;
+            }
+        }
+
+        RegCloseKey(hkey);
+    }
+    return ok;
+}
+
+static int get_registry_config_parameter(HKEY hkey,
+                                         const char *tag, char *b, DWORD sz)
+{
+    DWORD type = 0;
+    LONG lrc;
+
+    lrc = RegQueryValueEx(hkey, tag, (LPDWORD) 0, &type, (LPBYTE) b, &sz);
+    if ((ERROR_SUCCESS != lrc) || (type != REG_SZ)) {
+        return JK_FALSE;
+    }
+
+    b[sz] = '\0';
+
+    return JK_TRUE;
+}
+
+static int init_ws_service(isapi_private_data_t * private_data,
+                           jk_ws_service_t *s, char **worker_name)
+{
+    char huge_buf[16 * 1024];   /* should be enough for all */
+
+    DWORD huge_buf_sz;
+
+    s->jvm_route = NULL;
+
+    s->start_response = start_response;
+    s->read = read;
+    s->write = write;
+    s->flush = NULL;
+
+    /* Clear RECO status */
+    s->reco_status = RECO_NONE;
+
+    GET_SERVER_VARIABLE_VALUE(HTTP_WORKER_HEADER_NAME, (*worker_name));
+    GET_SERVER_VARIABLE_VALUE(HTTP_URI_HEADER_NAME, s->req_uri);
+    GET_SERVER_VARIABLE_VALUE(HTTP_QUERY_HEADER_NAME, s->query_string);
+
+    if (s->req_uri == NULL) {
+        s->query_string = private_data->lpEcb->lpszQueryString;
+        *worker_name = DEFAULT_WORKER_NAME;
+        GET_SERVER_VARIABLE_VALUE("URL", s->req_uri);
+        if (unescape_url(s->req_uri) < 0)
+            return JK_FALSE;
+        getparents(s->req_uri);
+    }
+
+    GET_SERVER_VARIABLE_VALUE("AUTH_TYPE", s->auth_type);
+    GET_SERVER_VARIABLE_VALUE("REMOTE_USER", s->remote_user);
+    GET_SERVER_VARIABLE_VALUE("SERVER_PROTOCOL", s->protocol);
+    GET_SERVER_VARIABLE_VALUE("REMOTE_HOST", s->remote_host);
+    GET_SERVER_VARIABLE_VALUE("REMOTE_ADDR", s->remote_addr);
+    GET_SERVER_VARIABLE_VALUE(SERVER_NAME, s->server_name);
+    GET_SERVER_VARIABLE_VALUE_INT("SERVER_PORT", s->server_port, 80);
+    GET_SERVER_VARIABLE_VALUE(SERVER_SOFTWARE, s->server_software);
+    GET_SERVER_VARIABLE_VALUE_INT("SERVER_PORT_SECURE", s->is_ssl, 0);
+
+    s->method = private_data->lpEcb->lpszMethod;
+    s->content_length = private_data->lpEcb->cbTotalBytes;
+
+    s->ssl_cert = NULL;
+    s->ssl_cert_len = 0;
+    s->ssl_cipher = NULL;
+    s->ssl_session = NULL;
+    s->ssl_key_size = -1;
+
+    s->headers_names = NULL;
+    s->headers_values = NULL;
+    s->num_headers = 0;
+    s->uw_map = uw_map;
+    /*
+     * Add SSL IIS environment
+     */
+    if (s->is_ssl) {
+        char *ssl_env_names[9] = {
+            "CERT_ISSUER",
+            "CERT_SUBJECT",
+            "CERT_COOKIE",
+            "HTTPS_SERVER_SUBJECT",
+            "CERT_FLAGS",
+            "HTTPS_SECRETKEYSIZE",
+            "CERT_SERIALNUMBER",
+            "HTTPS_SERVER_ISSUER",
+            "HTTPS_KEYSIZE"
+        };
+        char *ssl_env_values[9] = {
+            NULL,
+            NULL,
+            NULL,
+            NULL,
+            NULL,
+            NULL,
+            NULL,
+            NULL,
+            NULL
+        };
+        unsigned int i;
+        unsigned int num_of_vars = 0;
+
+        for (i = 0; i < 9; i++) {
+            GET_SERVER_VARIABLE_VALUE(ssl_env_names[i], ssl_env_values[i]);
+            if (ssl_env_values[i]) {
+                num_of_vars++;
+            }
+        }
+        if (num_of_vars) {
+            unsigned int j;
+
+            s->attributes_names =
+                jk_pool_alloc(&private_data->p, num_of_vars * sizeof(char *));
+            s->attributes_values =
+                jk_pool_alloc(&private_data->p, num_of_vars * sizeof(char *));
+
+            j = 0;
+            for (i = 0; i < 9; i++) {
+                if (ssl_env_values[i]) {
+                    s->attributes_names[j] = ssl_env_names[i];
+                    s->attributes_values[j] = ssl_env_values[i];
+                    j++;
+                }
+            }
+            s->num_attributes = num_of_vars;
+            if (ssl_env_values[4] && ssl_env_values[4][0] == '1') {
+                CERT_CONTEXT_EX cc;
+                cc.cbAllocated = sizeof(huge_buf);
+                cc.CertContext.pbCertEncoded = (BYTE *) huge_buf;
+                cc.CertContext.cbCertEncoded = 0;
+
+                if (private_data->lpEcb->
+                    ServerSupportFunction(private_data->lpEcb->ConnID,
+                                          (DWORD) HSE_REQ_GET_CERT_INFO_EX,
+                                          (LPVOID) & cc, NULL,
+                                          NULL) != FALSE) {
+                    jk_log(logger, JK_LOG_DEBUG,
+                           "Client Certificate encoding:%d sz:%d flags:%ld",
+                           cc.CertContext.
+                           dwCertEncodingType & X509_ASN_ENCODING,
+                           cc.CertContext.cbCertEncoded,
+                           cc.dwCertificateFlags);
+                    s->ssl_cert =
+                        jk_pool_alloc(&private_data->p,
+                                      base64_encode_cert_len(cc.CertContext.
+                                                             cbCertEncoded));
+
+                    s->ssl_cert_len = base64_encode_cert(s->ssl_cert,
+                                                         huge_buf,
+                                                         cc.CertContext.
+                                                         cbCertEncoded) - 1;
+                }
+            }
+        }
+    }
+
+    huge_buf_sz = sizeof(huge_buf);
+    if (get_server_value(private_data->lpEcb,
+                         "ALL_HTTP", huge_buf, huge_buf_sz)) {
+        unsigned int cnt = 0;
+        char *tmp;
+
+        for (tmp = huge_buf; *tmp; tmp++) {
+            if (*tmp == '\n') {
+                cnt++;
+            }
+        }
+
+        if (cnt) {
+            char *headers_buf = jk_pool_strdup(&private_data->p, huge_buf);
+            unsigned int i;
+            size_t len_of_http_prefix = strlen("HTTP_");
+            BOOL need_content_length_header = (s->content_length == 0);
+
+            cnt -= 2;           /* For our two special headers:
+                                 * HTTP_TOMCATURI_XXXXXXXX
+                                 * HTTP_TOMCATWORKER_XXXXXXXX
+                                 */
+            /* allocate an extra header slot in case we need to add a content-length header */
+            s->headers_names =
+                jk_pool_alloc(&private_data->p, (cnt + 1) * sizeof(char *));
+            s->headers_values =
+                jk_pool_alloc(&private_data->p, (cnt + 1) * sizeof(char *));
+
+            if (!s->headers_names || !s->headers_values || !headers_buf) {
+                return JK_FALSE;
+            }
+
+            for (i = 0, tmp = headers_buf; *tmp && i < cnt;) {
+                int real_header = JK_TRUE;
+
+                /* Skipp the HTTP_ prefix to the beginning of th header name */
+                tmp += len_of_http_prefix;
+
+                if (!strnicmp(tmp, URI_HEADER_NAME, strlen(URI_HEADER_NAME))
+                    || !strnicmp(tmp, WORKER_HEADER_NAME,
+                                 strlen(WORKER_HEADER_NAME))) {
+                    real_header = JK_FALSE;
+                }
+                else if (!strnicmp(tmp, QUERY_HEADER_NAME,
+                                   strlen(QUERY_HEADER_NAME))) {
+                    /* HTTP_TOMCATQUERY_XXXXXXXX was supplied,
+                     * remove it from the count and skip
+                     */
+                    cnt--;
+                    real_header = JK_FALSE;
+                }
+                else if (need_content_length_header &&
+                         !strnicmp(tmp, CONTENT_LENGTH,
+                                   strlen(CONTENT_LENGTH))) {
+                    need_content_length_header = FALSE;
+                    s->headers_names[i] = tmp;
+                }
+                else if (!strnicmp(tmp, TOMCAT_TRANSLATE_HEADER_NAME,
+                                   strlen(TOMCAT_TRANSLATE_HEADER_NAME))) {
+                    s->headers_names[i] = TRANSLATE_HEADER_NAME_LC;
+                }
+                else {
+                    s->headers_names[i] = tmp;
+                }
+
+                while (':' != *tmp && *tmp) {
+                    if ('_' == *tmp) {
+                        *tmp = '-';
+                    }
+                    else {
+                        *tmp = JK_TOLOWER(*tmp);
+                    }
+                    tmp++;
+                }
+                *tmp = '\0';
+                tmp++;
+
+                /* Skip all the WS chars after the ':' to the beginning of th header value */
+                while (' ' == *tmp || '\t' == *tmp || '\v' == *tmp) {
+                    tmp++;
+                }
+
+                if (real_header) {
+                    s->headers_values[i] = tmp;
+                }
+
+                while (*tmp != '\n' && *tmp != '\r') {
+                    tmp++;
+                }
+                *tmp = '\0';
+                tmp++;
+
+                /* skipp CR LF */
+                while (*tmp == '\n' || *tmp == '\r') {
+                    tmp++;
+                }
+
+                if (real_header) {
+                    i++;
+                }
+            }
+            /* Add a content-length = 0 header if needed.
+             * Ajp13 assumes an absent content-length header means an unknown,
+             * but non-zero length body.
+             */
+            if (need_content_length_header) {
+                s->headers_names[cnt] = "Content-Length";
+                s->headers_values[cnt] = "0";
+                cnt++;
+            }
+            s->num_headers = cnt;
+        }
+        else {
+            /* We must have our two headers */
+            return JK_FALSE;
+        }
+    }
+    else {
+        return JK_FALSE;
+    }
+
+    return JK_TRUE;
+}
+
+static int get_server_value(LPEXTENSION_CONTROL_BLOCK lpEcb,
+                            char *name, char *buf, DWORD bufsz)
+{
+    DWORD sz = bufsz;
+    buf[0]   = '\0';
+    if (!lpEcb->GetServerVariable(lpEcb->ConnID, name,
+                                  buf, (LPDWORD) &sz))
+        return JK_FALSE;
+
+    if (sz <= bufsz)
+        buf[sz-1] = '\0';
+    return JK_TRUE;
+}
+
+static const char begin_cert[] = "-----BEGIN CERTIFICATE-----\r\n";
+
+static const char end_cert[] = "-----END CERTIFICATE-----\r\n";
+
+static const char basis_64[] =
+    "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+static int base64_encode_cert_len(int len)
+{
+    int n = ((len + 2) / 3 * 4) + 1;    /* base64 encoded size */
+    n += (n + 63 / 64) * 2;             /* add CRLF's */
+    n += sizeof(begin_cert) + sizeof(end_cert) - 2;  /* add enclosing strings. */
+    return n;
+}
+
+static int base64_encode_cert(char *encoded,
+                              const char *string, int len)
+{
+    int i, c;
+    char *p;
+    const char *t;
+
+    p = encoded;
+
+    t = begin_cert;
+    while (*t != '\0')
+        *p++ = *t++;
+
+    c = 0;
+    for (i = 0; i < len - 2; i += 3) {
+        *p++ = basis_64[(string[i] >> 2) & 0x3F];
+        *p++ = basis_64[((string[i] & 0x3) << 4) |
+                        ((int)(string[i + 1] & 0xF0) >> 4)];
+        *p++ = basis_64[((string[i + 1] & 0xF) << 2) |
+                        ((int)(string[i + 2] & 0xC0) >> 6)];
+        *p++ = basis_64[string[i + 2] & 0x3F];
+        c += 4;
+        if (c >= 64) {
+            *p++ = '\r';
+            *p++ = '\n';
+            c = 0;
+        }
+    }
+    if (i < len) {
+        *p++ = basis_64[(string[i] >> 2) & 0x3F];
+        if (i == (len - 1)) {
+            *p++ = basis_64[((string[i] & 0x3) << 4)];
+            *p++ = '=';
+        }
+        else {
+            *p++ = basis_64[((string[i] & 0x3) << 4) |
+                            ((int)(string[i + 1] & 0xF0) >> 4)];
+            *p++ = basis_64[((string[i + 1] & 0xF) << 2)];
+        }
+        *p++ = '=';
+        c++;
+    }
+    if (c != 0) {
+        *p++ = '\r';
+        *p++ = '\n';
+    }
+
+    t = end_cert;
+    while (*t != '\0')
+        *p++ = *t++;
+
+    *p++ = '\0';
+    return (int)(p - encoded);
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/AUTHORS
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/AUTHORS	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/AUTHORS	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,6 @@
+Written by: Philip Hazel <ph10 at cam.ac.uk>
+
+University of Cambridge Computing Service,
+Cambridge, England. Phone: +44 1223 334714.
+
+Copyright (c) 1997-2004 University of Cambridge

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/COPYING
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/COPYING	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/COPYING	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,45 @@
+PCRE LICENCE
+------------
+
+PCRE is a library of functions to support regular expressions whose syntax
+and semantics are as close as possible to those of the Perl 5 language.
+
+Release 5 of PCRE is distributed under the terms of the "BSD" licence, as
+specified below. The documentation for PCRE, supplied in the "doc"
+directory, is distributed under the same terms as the software itself.
+
+Written by: Philip Hazel <ph10 at cam.ac.uk>
+
+University of Cambridge Computing Service,
+Cambridge, England. Phone: +44 1223 334714.
+
+Copyright (c) 1997-2004 University of Cambridge
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice,
+      this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+
+    * Neither the name of the University of Cambridge nor the names of its
+      contributors may be used to endorse or promote products derived from
+      this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+End

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/ChangeLog
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/ChangeLog	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/ChangeLog	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,1650 @@
+ChangeLog for PCRE
+------------------
+
+Version 5.0 13-Sep-04
+---------------------
+
+ 1. Internal change: literal characters are no longer packed up into items
+    containing multiple characters in a single byte-string. Each character
+    is now matched using a separate opcode. However, there may be more than one
+    byte in the character in UTF-8 mode.
+
+ 2. The pcre_callout_block structure has two new fields: pattern_position and
+    next_item_length. These contain the offset in the pattern to the next match
+    item, and its length, respectively.
+
+ 3. The PCRE_AUTO_CALLOUT option for pcre_compile() requests the automatic
+    insertion of callouts before each pattern item. Added the /C option to
+    pcretest to make use of this.
+
+ 4. On the advice of a Windows user, the lines
+
+      #if defined(_WIN32) || defined(WIN32)
+      _setmode( _fileno( stdout ), 0x8000 );
+      #endif  /* defined(_WIN32) || defined(WIN32) */
+
+    have been added to the source of pcretest. This apparently does useful
+    magic in relation to line terminators.
+
+ 5. Changed "r" and "w" in the calls to fopen() in pcretest to "rb" and "wb"
+    for the benefit of those environments where the "b" makes a difference.
+
+ 6. The icc compiler has the same options as gcc, but "configure" doesn't seem
+    to know about it. I have put a hack into configure.in that adds in code
+    to set GCC=yes if CC=icc. This seems to end up at a point in the
+    generated configure script that is early enough to affect the setting of
+    compiler options, which is what is needed, but I have no means of testing
+    whether it really works. (The user who reported this had patched the
+    generated configure script, which of course I cannot do.)
+
+    LATER: After change 22 below (new libtool files), the configure script
+    seems to know about icc (and also ecc). Therefore, I have commented out
+    this hack in configure.in.
+
+ 7. Added support for pkg-config (2 patches were sent in).
+
+ 8. Negated POSIX character classes that used a combination of internal tables
+    were completely broken. These were [[:^alpha:]], [[:^alnum:]], and
+    [[:^ascii]]. Typically, they would match almost any characters. The other
+    POSIX classes were not broken in this way.
+
+ 9. Matching the pattern "\b.*?" against "ab cd", starting at offset 1, failed
+    to find the match, as PCRE was deluded into thinking that the match had to
+    start at the start point or following a newline. The same bug applied to
+    patterns with negative forward assertions or any backward assertions
+    preceding ".*" at the start, unless the pattern required a fixed first
+    character. This was a failing pattern: "(?!.bcd).*". The bug is now fixed.
+
+10. In UTF-8 mode, when moving forwards in the subject after a failed match
+    starting at the last subject character, bytes beyond the end of the subject
+    string were read.
+
+11. Renamed the variable "class" as "classbits" to make life easier for C++
+    users. (Previously there was a macro definition, but it apparently wasn't
+    enough.)
+
+12. Added the new field "tables" to the extra data so that tables can be passed
+    in at exec time, or the internal tables can be re-selected. This allows
+    a compiled regex to be saved and re-used at a later time by a different
+    program that might have everything at different addresses.
+
+13. Modified the pcre-config script so that, when run on Solaris, it shows a
+    -R library as well as a -L library.
+
+14. The debugging options of pcretest (-d on the command line or D on a
+    pattern) showed incorrect output for anything following an extended class
+    that contained multibyte characters and which was followed by a quantifier.
+
+15. Added optional support for general category Unicode character properties
+    via the \p, \P, and \X escapes. Unicode property support implies UTF-8
+    support. It adds about 90K to the size of the library. The meanings of the
+    inbuilt class escapes such as \d and \s have NOT been changed.
+
+16. Updated pcredemo.c to include calls to free() to release the memory for the
+    compiled pattern.
+
+17. The generated file chartables.c was being created in the source directory
+    instead of in the building directory. This caused the build to fail if the
+    source directory was different from the building directory, and was
+    read-only.
+
+18. Added some sample Win commands from Mark Tetrode into the NON-UNIX-USE
+    file. No doubt somebody will tell me if they don't make sense... Also added
+    Dan Mooney's comments about building on OpenVMS.
+
+19. Added support for partial matching via the PCRE_PARTIAL option for
+    pcre_exec() and the \P data escape in pcretest.
+
+20. Extended pcretest with 3 new pattern features:
+
+    (i)   A pattern option of the form ">rest-of-line" causes pcretest to
+          write the compiled pattern to the file whose name is "rest-of-line".
+          This is a straight binary dump of the data, with the saved pointer to
+          the character tables forced to be NULL. The study data, if any, is
+          written too. After writing, pcretest reads a new pattern.
+
+    (ii)  If, instead of a pattern, "<rest-of-line" is given, pcretest reads a
+          compiled pattern from the given file. There must not be any
+          occurrences of "<" in the file name (pretty unlikely); if there are,
+          pcretest will instead treat the initial "<" as a pattern delimiter.
+          After reading in the pattern, pcretest goes on to read data lines as
+          usual.
+
+    (iii) The F pattern option causes pcretest to flip the bytes in the 32-bit
+          and 16-bit fields in a compiled pattern, to simulate a pattern that
+          was compiled on a host of opposite endianness.
+
+21. The pcre-exec() function can now cope with patterns that were compiled on
+    hosts of opposite endianness, with this restriction:
+
+      As for any compiled expression that is saved and used later, the tables
+      pointer field cannot be preserved; the extra_data field in the arguments
+      to pcre_exec() should be used to pass in a tables address if a value
+      other than the default internal tables were used at compile time.
+
+22. Calling pcre_exec() with a negative value of the "ovecsize" parameter is
+    now diagnosed as an error. Previously, most of the time, a negative number
+    would have been treated as zero, but if in addition "ovector" was passed as
+    NULL, a crash could occur.
+
+23. Updated the files ltmain.sh, config.sub, config.guess, and aclocal.m4 with
+    new versions from the libtool 1.5 distribution (the last one is a copy of
+    a file called libtool.m4). This seems to have fixed the need to patch
+    "configure" to support Darwin 1.3 (which I used to do). However, I still
+    had to patch ltmain.sh to ensure that ${SED} is set (it isn't on my
+    workstation).
+
+24. Changed the PCRE licence to be the more standard "BSD" licence.
+
+
+Version 4.5 01-Dec-03
+---------------------
+
+ 1. There has been some re-arrangement of the code for the match() function so
+    that it can be compiled in a version that does not call itself recursively.
+    Instead, it keeps those local variables that need separate instances for
+    each "recursion" in a frame on the heap, and gets/frees frames whenever it
+    needs to "recurse". Keeping track of where control must go is done by means
+    of setjmp/longjmp. The whole thing is implemented by a set of macros that
+    hide most of the details from the main code, and operates only if
+    NO_RECURSE is defined while compiling pcre.c. If PCRE is built using the
+    "configure" mechanism, "--disable-stack-for-recursion" turns on this way of
+    operating.
+
+    To make it easier for callers to provide specially tailored get/free
+    functions for this usage, two new functions, pcre_stack_malloc, and
+    pcre_stack_free, are used. They are always called in strict stacking order,
+    and the size of block requested is always the same.
+
+    The PCRE_CONFIG_STACKRECURSE info parameter can be used to find out whether
+    PCRE has been compiled to use the stack or the heap for recursion. The
+    -C option of pcretest uses this to show which version is compiled.
+
+    A new data escape \S, is added to pcretest; it causes the amounts of store
+    obtained and freed by both kinds of malloc/free at match time to be added
+    to the output.
+
+ 2. Changed the locale test to use "fr_FR" instead of "fr" because that's
+    what's available on my current Linux desktop machine.
+
+ 3. When matching a UTF-8 string, the test for a valid string at the start has
+    been extended. If start_offset is not zero, PCRE now checks that it points
+    to a byte that is the start of a UTF-8 character. If not, it returns
+    PCRE_ERROR_BADUTF8_OFFSET (-11). Note: the whole string is still checked;
+    this is necessary because there may be backward assertions in the pattern.
+    When matching the same subject several times, it may save resources to use
+    PCRE_NO_UTF8_CHECK on all but the first call if the string is long.
+
+ 4. The code for checking the validity of UTF-8 strings has been tightened so
+    that it rejects (a) strings containing 0xfe or 0xff bytes and (b) strings
+    containing "overlong sequences".
+
+ 5. Fixed a bug (appearing twice) that I could not find any way of exploiting!
+    I had written "if ((digitab[*p++] && chtab_digit) == 0)" where the "&&"
+    should have been "&", but it just so happened that all the cases this let
+    through by mistake were picked up later in the function.
+
+ 6. I had used a variable called "isblank" - this is a C99 function, causing
+    some compilers to warn. To avoid this, I renamed it (as "blankclass").
+
+ 7. Cosmetic: (a) only output another newline at the end of pcretest if it is
+    prompting; (b) run "./pcretest /dev/null" at the start of the test script
+    so the version is shown; (c) stop "make test" echoing "./RunTest".
+
+ 8. Added patches from David Burgess to enable PCRE to run on EBCDIC systems.
+
+ 9. The prototype for memmove() for systems that don't have it was using
+    size_t, but the inclusion of the header that defines size_t was later. I've
+    moved the #includes for the C headers earlier to avoid this.
+
+10. Added some adjustments to the code to make it easier to compiler on certain
+    special systems:
+
+      (a) Some "const" qualifiers were missing.
+      (b) Added the macro EXPORT before all exported functions; by default this
+          is defined to be empty.
+      (c) Changed the dftables auxiliary program (that builds chartables.c) so
+          that it reads its output file name as an argument instead of writing
+          to the standard output and assuming this can be redirected.
+
+11. In UTF-8 mode, if a recursive reference (e.g. (?1)) followed a character
+    class containing characters with values greater than 255, PCRE compilation
+    went into a loop.
+
+12. A recursive reference to a subpattern that was within another subpattern
+    that had a minimum quantifier of zero caused PCRE to crash. For example,
+    (x(y(?2))z)? provoked this bug with a subject that got as far as the
+    recursion. If the recursively-called subpattern itself had a zero repeat,
+    that was OK.
+
+13. In pcretest, the buffer for reading a data line was set at 30K, but the
+    buffer into which it was copied (for escape processing) was still set at
+    1024, so long lines caused crashes.
+
+14. A pattern such as /[ab]{1,3}+/ failed to compile, giving the error
+    "internal error: code overflow...". This applied to any character class
+    that was followed by a possessive quantifier.
+
+15. Modified the Makefile to add libpcre.la as a prerequisite for
+    libpcreposix.la because I was told this is needed for a parallel build to
+    work.
+
+16. If a pattern that contained .* following optional items at the start was
+    studied, the wrong optimizing data was generated, leading to matching
+    errors. For example, studying /[ab]*.*c/ concluded, erroneously, that any
+    matching string must start with a or b or c. The correct conclusion for
+    this pattern is that a match can start with any character.
+
+
+Version 4.4 13-Aug-03
+---------------------
+
+ 1. In UTF-8 mode, a character class containing characters with values between
+    127 and 255 was not handled correctly if the compiled pattern was studied.
+    In fixing this, I have also improved the studying algorithm for such
+    classes (slightly).
+
+ 2. Three internal functions had redundant arguments passed to them. Removal
+    might give a very teeny performance improvement.
+
+ 3. Documentation bug: the value of the capture_top field in a callout is *one
+    more than* the number of the hightest numbered captured substring.
+
+ 4. The Makefile linked pcretest and pcregrep with -lpcre, which could result
+    in incorrectly linking with a previously installed version. They now link
+    explicitly with libpcre.la.
+
+ 5. configure.in no longer needs to recognize Cygwin specially.
+
+ 6. A problem in pcre.in for Windows platforms is fixed.
+
+ 7. If a pattern was successfully studied, and the -d (or /D) flag was given to
+    pcretest, it used to include the size of the study block as part of its
+    output. Unfortunately, the structure contains a field that has a different
+    size on different hardware architectures. This meant that the tests that
+    showed this size failed. As the block is currently always of a fixed size,
+    this information isn't actually particularly useful in pcretest output, so
+    I have just removed it.
+
+ 8. Three pre-processor statements accidentally did not start in column 1.
+    Sadly, there are *still* compilers around that complain, even though
+    standard C has not required this for well over a decade. Sigh.
+
+ 9. In pcretest, the code for checking callouts passed small integers in the
+    callout_data field, which is a void * field. However, some picky compilers
+    complained about the casts involved for this on 64-bit systems. Now
+    pcretest passes the address of the small integer instead, which should get
+    rid of the warnings.
+
+10. By default, when in UTF-8 mode, PCRE now checks for valid UTF-8 strings at
+    both compile and run time, and gives an error if an invalid UTF-8 sequence
+    is found. There is a option for disabling this check in cases where the
+    string is known to be correct and/or the maximum performance is wanted.
+
+11. In response to a bug report, I changed one line in Makefile.in from
+
+        -Wl,--out-implib,.libs/lib at WIN_PREFIX@pcreposix.dll.a \
+    to
+        -Wl,--out-implib,.libs/@WIN_PREFIX at libpcreposix.dll.a \
+
+    to look similar to other lines, but I have no way of telling whether this
+    is the right thing to do, as I do not use Windows. No doubt I'll get told
+    if it's wrong...
+
+
+Version 4.3 21-May-03
+---------------------
+
+1. Two instances of @WIN_PREFIX@ omitted from the Windows targets in the
+   Makefile.
+
+2. Some refactoring to improve the quality of the code:
+
+   (i)   The utf8_table... variables are now declared "const".
+
+   (ii)  The code for \cx, which used the "case flipping" table to upper case
+         lower case letters, now just substracts 32. This is ASCII-specific,
+         but the whole concept of \cx is ASCII-specific, so it seems
+         reasonable.
+
+   (iii) PCRE was using its character types table to recognize decimal and
+         hexadecimal digits in the pattern. This is silly, because it handles
+         only 0-9, a-f, and A-F, but the character types table is locale-
+         specific, which means strange things might happen. A private
+         table is now used for this - though it costs 256 bytes, a table is
+         much faster than multiple explicit tests. Of course, the standard
+         character types table is still used for matching digits in subject
+         strings against \d.
+
+   (iv)  Strictly, the identifier ESC_t is reserved by POSIX (all identifiers
+         ending in _t are). So I've renamed it as ESC_tee.
+
+3. The first argument for regexec() in the POSIX wrapper should have been
+   defined as "const".
+
+4. Changed pcretest to use malloc() for its buffers so that they can be
+   Electric Fenced for debugging.
+
+5. There were several places in the code where, in UTF-8 mode, PCRE would try
+   to read one or more bytes before the start of the subject string. Often this
+   had no effect on PCRE's behaviour, but in some circumstances it could
+   provoke a segmentation fault.
+
+6. A lookbehind at the start of a pattern in UTF-8 mode could also cause PCRE
+   to try to read one or more bytes before the start of the subject string.
+
+7. A lookbehind in a pattern matched in non-UTF-8 mode on a PCRE compiled with
+   UTF-8 support could misbehave in various ways if the subject string
+   contained bytes with the 0x80 bit set and the 0x40 bit unset in a lookbehind
+   area. (PCRE was not checking for the UTF-8 mode flag, and trying to move
+   back over UTF-8 characters.)
+
+
+Version 4.2 14-Apr-03
+---------------------
+
+1. Typo "#if SUPPORT_UTF8" instead of "#ifdef SUPPORT_UTF8" fixed.
+
+2. Changes to the building process, supplied by Ronald Landheer-Cieslak
+     [ON_WINDOWS]: new variable, "#" on non-Windows platforms
+     [NOT_ON_WINDOWS]: new variable, "#" on Windows platforms
+     [WIN_PREFIX]: new variable, "cyg" for Cygwin
+     * Makefile.in: use autoconf substitution for OBJEXT, EXEEXT, BUILD_OBJEXT
+       and BUILD_EXEEXT
+     Note: automatic setting of the BUILD variables is not yet working
+     set CPPFLAGS and BUILD_CPPFLAGS (but don't use yet) - should be used at
+       compile-time but not at link-time
+     [LINK]: use for linking executables only
+     make different versions for Windows and non-Windows
+     [LINKLIB]: new variable, copy of UNIX-style LINK, used for linking
+       libraries
+     [LINK_FOR_BUILD]: new variable
+     [OBJEXT]: use throughout
+     [EXEEXT]: use throughout
+     <winshared>: new target
+     <wininstall>: new target
+     <dftables.o>: use native compiler
+     <dftables>: use native linker
+     <install>: handle Windows platform correctly
+     <clean>: ditto
+     <check>: ditto
+     copy DLL to top builddir before testing
+
+   As part of these changes, -no-undefined was removed again. This was reported
+   to give trouble on HP-UX 11.0, so getting rid of it seems like a good idea
+   in any case.
+
+3. Some tidies to get rid of compiler warnings:
+
+   . In the match_data structure, match_limit was an unsigned long int, whereas
+     match_call_count was an int. I've made them both unsigned long ints.
+
+   . In pcretest the fact that a const uschar * doesn't automatically cast to
+     a void * provoked a warning.
+
+   . Turning on some more compiler warnings threw up some "shadow" variables
+     and a few more missing casts.
+
+4. If PCRE was complied with UTF-8 support, but called without the PCRE_UTF8
+   option, a class that contained a single character with a value between 128
+   and 255 (e.g. /[\xFF]/) caused PCRE to crash.
+
+5. If PCRE was compiled with UTF-8 support, but called without the PCRE_UTF8
+   option, a class that contained several characters, but with at least one
+   whose value was between 128 and 255 caused PCRE to crash.
+
+
+Version 4.1 12-Mar-03
+---------------------
+
+1. Compiling with gcc -pedantic found a couple of places where casts were
+needed, and a string in dftables.c that was longer than standard compilers are
+required to support.
+
+2. Compiling with Sun's compiler found a few more places where the code could
+be tidied up in order to avoid warnings.
+
+3. The variables for cross-compiling were called HOST_CC and HOST_CFLAGS; the
+first of these names is deprecated in the latest Autoconf in favour of the name
+CC_FOR_BUILD, because "host" is typically used to mean the system on which the
+compiled code will be run. I can't find a reference for HOST_CFLAGS, but by
+analogy I have changed it to CFLAGS_FOR_BUILD.
+
+4. Added -no-undefined to the linking command in the Makefile, because this is
+apparently helpful for Windows. To make it work, also added "-L. -lpcre" to the
+linking step for the pcreposix library.
+
+5. PCRE was failing to diagnose the case of two named groups with the same
+name.
+
+6. A problem with one of PCRE's optimizations was discovered. PCRE remembers a
+literal character that is needed in the subject for a match, and scans along to
+ensure that it is present before embarking on the full matching process. This
+saves time in cases of nested unlimited repeats that are never going to match.
+Problem: the scan can take a lot of time if the subject is very long (e.g.
+megabytes), thus penalizing straightforward matches. It is now done only if the
+amount of subject to be scanned is less than 1000 bytes.
+
+7. A lesser problem with the same optimization is that it was recording the
+first character of an anchored pattern as "needed", thus provoking a search
+right along the subject, even when the first match of the pattern was going to
+fail. The "needed" character is now not set for anchored patterns, unless it
+follows something in the pattern that is of non-fixed length. Thus, it still
+fulfils its original purpose of finding quick non-matches in cases of nested
+unlimited repeats, but isn't used for simple anchored patterns such as /^abc/.
+
+
+Version 4.0 17-Feb-03
+---------------------
+
+1. If a comment in an extended regex that started immediately after a meta-item
+extended to the end of string, PCRE compiled incorrect data. This could lead to
+all kinds of weird effects. Example: /#/ was bad; /()#/ was bad; /a#/ was not.
+
+2. Moved to autoconf 2.53 and libtool 1.4.2.
+
+3. Perl 5.8 no longer needs "use utf8" for doing UTF-8 things. Consequently,
+the special perltest8 script is no longer needed - all the tests can be run
+from a single perltest script.
+
+4. From 5.004, Perl has not included the VT character (0x0b) in the set defined
+by \s. It has now been removed in PCRE. This means it isn't recognized as
+whitespace in /x regexes too, which is the same as Perl. Note that the POSIX
+class [:space:] *does* include VT, thereby creating a mess.
+
+5. Added the class [:blank:] (a GNU extension from Perl 5.8) to match only
+space and tab.
+
+6. Perl 5.005 was a long time ago. It's time to amalgamate the tests that use
+its new features into the main test script, reducing the number of scripts.
+
+7. Perl 5.8 has changed the meaning of patterns like /a(?i)b/. Earlier versions
+were backward compatible, and made the (?i) apply to the whole pattern, as if
+/i were given. Now it behaves more logically, and applies the option setting
+only to what follows. PCRE has been changed to follow suit. However, if it
+finds options settings right at the start of the pattern, it extracts them into
+the global options, as before. Thus, they show up in the info data.
+
+8. Added support for the \Q...\E escape sequence. Characters in between are
+treated as literals. This is slightly different from Perl in that $ and @ are
+also handled as literals inside the quotes. In Perl, they will cause variable
+interpolation. Note the following examples:
+
+    Pattern            PCRE matches      Perl matches
+
+    \Qabc$xyz\E        abc$xyz           abc followed by the contents of $xyz
+    \Qabc\$xyz\E       abc\$xyz          abc\$xyz
+    \Qabc\E\$\Qxyz\E   abc$xyz           abc$xyz
+
+For compatibility with Perl, \Q...\E sequences are recognized inside character
+classes as well as outside them.
+
+9. Re-organized 3 code statements in pcretest to avoid "overflow in
+floating-point constant arithmetic" warnings from a Microsoft compiler. Added a
+(size_t) cast to one statement in pcretest and one in pcreposix to avoid
+signed/unsigned warnings.
+
+10. SunOS4 doesn't have strtoul(). This was used only for unpicking the -o
+option for pcretest, so I've replaced it by a simple function that does just
+that job.
+
+11. pcregrep was ending with code 0 instead of 2 for the commands "pcregrep" or
+"pcregrep -".
+
+12. Added "possessive quantifiers" ?+, *+, ++, and {,}+ which come from Sun's
+Java package. This provides some syntactic sugar for simple cases of what my
+documentation calls "once-only subpatterns". A pattern such as x*+ is the same
+as (?>x*). In other words, if what is inside (?>...) is just a single repeated
+item, you can use this simplified notation. Note that only makes sense with
+greedy quantifiers. Consequently, the use of the possessive quantifier forces
+greediness, whatever the setting of the PCRE_UNGREEDY option.
+
+13. A change of greediness default within a pattern was not taking effect at
+the current level for patterns like /(b+(?U)a+)/. It did apply to parenthesized
+subpatterns that followed. Patterns like /b+(?U)a+/ worked because the option
+was abstracted outside.
+
+14. PCRE now supports the \G assertion. It is true when the current matching
+position is at the start point of the match. This differs from \A when the
+starting offset is non-zero. Used with the /g option of pcretest (or similar
+code), it works in the same way as it does for Perl's /g option. If all
+alternatives of a regex begin with \G, the expression is anchored to the start
+match position, and the "anchored" flag is set in the compiled expression.
+
+15. Some bugs concerning the handling of certain option changes within patterns
+have been fixed. These applied to options other than (?ims). For example,
+"a(?x: b c )d" did not match "XabcdY" but did match "Xa b c dY". It should have
+been the other way round. Some of this was related to change 7 above.
+
+16. PCRE now gives errors for /[.x.]/ and /[=x=]/ as unsupported POSIX
+features, as Perl does. Previously, PCRE gave the warnings only for /[[.x.]]/
+and /[[=x=]]/. PCRE now also gives an error for /[:name:]/ because it supports
+POSIX classes only within a class (e.g. /[[:alpha:]]/).
+
+17. Added support for Perl's \C escape. This matches one byte, even in UTF8
+mode. Unlike ".", it always matches newline, whatever the setting of
+PCRE_DOTALL. However, PCRE does not permit \C to appear in lookbehind
+assertions. Perl allows it, but it doesn't (in general) work because it can't
+calculate the length of the lookbehind. At least, that's the case for Perl
+5.8.0 - I've been told they are going to document that it doesn't work in
+future.
+
+18. Added an error diagnosis for escapes that PCRE does not support: these are
+\L, \l, \N, \P, \p, \U, \u, and \X.
+
+19. Although correctly diagnosing a missing ']' in a character class, PCRE was
+reading past the end of the pattern in cases such as /[abcd/.
+
+20. PCRE was getting more memory than necessary for patterns with classes that
+contained both POSIX named classes and other characters, e.g. /[[:space:]abc/.
+
+21. Added some code, conditional on #ifdef VPCOMPAT, to make life easier for
+compiling PCRE for use with Virtual Pascal.
+
+22. Small fix to the Makefile to make it work properly if the build is done
+outside the source tree.
+
+23. Added a new extension: a condition to go with recursion. If a conditional
+subpattern starts with (?(R) the "true" branch is used if recursion has
+happened, whereas the "false" branch is used only at the top level.
+
+24. When there was a very long string of literal characters (over 255 bytes
+without UTF support, over 250 bytes with UTF support), the computation of how
+much memory was required could be incorrect, leading to segfaults or other
+strange effects.
+
+25. PCRE was incorrectly assuming anchoring (either to start of subject or to
+start of line for a non-DOTALL pattern) when a pattern started with (.*) and
+there was a subsequent back reference to those brackets. This meant that, for
+example, /(.*)\d+\1/ failed to match "abc123bc". Unfortunately, it isn't
+possible to check for precisely this case. All we can do is abandon the
+optimization if .* occurs inside capturing brackets when there are any back
+references whatsoever. (See below for a better fix that came later.)
+
+26. The handling of the optimization for finding the first character of a
+non-anchored pattern, and for finding a character that is required later in the
+match were failing in some cases. This didn't break the matching; it just
+failed to optimize when it could. The way this is done has been re-implemented.
+
+27. Fixed typo in error message for invalid (?R item (it said "(?p").
+
+28. Added a new feature that provides some of the functionality that Perl
+provides with (?{...}). The facility is termed a "callout". The way it is done
+in PCRE is for the caller to provide an optional function, by setting
+pcre_callout to its entry point. Like pcre_malloc and pcre_free, this is a
+global variable. By default it is unset, which disables all calling out. To get
+the function called, the regex must include (?C) at appropriate points. This
+is, in fact, equivalent to (?C0), and any number <= 255 may be given with (?C).
+This provides a means of identifying different callout points. When PCRE
+reaches such a point in the regex, if pcre_callout has been set, the external
+function is called. It is provided with data in a structure called
+pcre_callout_block, which is defined in pcre.h. If the function returns 0,
+matching continues; if it returns a non-zero value, the match at the current
+point fails. However, backtracking will occur if possible. [This was changed
+later and other features added - see item 49 below.]
+
+29. pcretest is upgraded to test the callout functionality. It provides a
+callout function that displays information. By default, it shows the start of
+the match and the current position in the text. There are some new data escapes
+to vary what happens:
+
+    \C+         in addition, show current contents of captured substrings
+    \C-         do not supply a callout function
+    \C!n        return 1 when callout number n is reached
+    \C!n!m      return 1 when callout number n is reached for the mth time
+
+30. If pcregrep was called with the -l option and just a single file name, it
+output "<stdin>" if a match was found, instead of the file name.
+
+31. Improve the efficiency of the POSIX API to PCRE. If the number of capturing
+slots is less than POSIX_MALLOC_THRESHOLD, use a block on the stack to pass to
+pcre_exec(). This saves a malloc/free per call. The default value of
+POSIX_MALLOC_THRESHOLD is 10; it can be changed by --with-posix-malloc-threshold
+when configuring.
+
+32. The default maximum size of a compiled pattern is 64K. There have been a
+few cases of people hitting this limit. The code now uses macros to handle the
+storing of links as offsets within the compiled pattern. It defaults to 2-byte
+links, but this can be changed to 3 or 4 bytes by --with-link-size when
+configuring. Tests 2 and 5 work only with 2-byte links because they output
+debugging information about compiled patterns.
+
+33. Internal code re-arrangements:
+
+(a) Moved the debugging function for printing out a compiled regex into
+    its own source file (printint.c) and used #include to pull it into
+    pcretest.c and, when DEBUG is defined, into pcre.c, instead of having two
+    separate copies.
+
+(b) Defined the list of op-code names for debugging as a macro in
+    internal.h so that it is next to the definition of the opcodes.
+
+(c) Defined a table of op-code lengths for simpler skipping along compiled
+    code. This is again a macro in internal.h so that it is next to the
+    definition of the opcodes.
+
+34. Added support for recursive calls to individual subpatterns, along the
+lines of Robin Houston's patch (but implemented somewhat differently).
+
+35. Further mods to the Makefile to help Win32. Also, added code to pcregrep to
+allow it to read and process whole directories in Win32. This code was
+contributed by Lionel Fourquaux; it has not been tested by me.
+
+36. Added support for named subpatterns. The Python syntax (?P<name>...) is
+used to name a group. Names consist of alphanumerics and underscores, and must
+be unique. Back references use the syntax (?P=name) and recursive calls use
+(?P>name) which is a PCRE extension to the Python extension. Groups still have
+numbers. The function pcre_fullinfo() can be used after compilation to extract
+a name/number map. There are three relevant calls:
+
+  PCRE_INFO_NAMEENTRYSIZE        yields the size of each entry in the map
+  PCRE_INFO_NAMECOUNT            yields the number of entries
+  PCRE_INFO_NAMETABLE            yields a pointer to the map.
+
+The map is a vector of fixed-size entries. The size of each entry depends on
+the length of the longest name used. The first two bytes of each entry are the
+group number, most significant byte first. There follows the corresponding
+name, zero terminated. The names are in alphabetical order.
+
+37. Make the maximum literal string in the compiled code 250 for the non-UTF-8
+case instead of 255. Making it the same both with and without UTF-8 support
+means that the same test output works with both.
+
+38. There was a case of malloc(0) in the POSIX testing code in pcretest. Avoid
+calling malloc() with a zero argument.
+
+39. Change 25 above had to resort to a heavy-handed test for the .* anchoring
+optimization. I've improved things by keeping a bitmap of backreferences with
+numbers 1-31 so that if .* occurs inside capturing brackets that are not in
+fact referenced, the optimization can be applied. It is unlikely that a
+relevant occurrence of .* (i.e. one which might indicate anchoring or forcing
+the match to follow \n) will appear inside brackets with a number greater than
+31, but if it does, any back reference > 31 suppresses the optimization.
+
+40. Added a new compile-time option PCRE_NO_AUTO_CAPTURE. This has the effect
+of disabling numbered capturing parentheses. Any opening parenthesis that is
+not followed by ? behaves as if it were followed by ?: but named parentheses
+can still be used for capturing (and they will acquire numbers in the usual
+way).
+
+41. Redesigned the return codes from the match() function into yes/no/error so
+that errors can be passed back from deep inside the nested calls. A malloc
+failure while inside a recursive subpattern call now causes the
+PCRE_ERROR_NOMEMORY return instead of quietly going wrong.
+
+42. It is now possible to set a limit on the number of times the match()
+function is called in a call to pcre_exec(). This facility makes it possible to
+limit the amount of recursion and backtracking, though not in a directly
+obvious way, because the match() function is used in a number of different
+circumstances. The count starts from zero for each position in the subject
+string (for non-anchored patterns). The default limit is, for compatibility, a
+large number, namely 10 000 000. You can change this in two ways:
+
+(a) When configuring PCRE before making, you can use --with-match-limit=n
+    to set a default value for the compiled library.
+
+(b) For each call to pcre_exec(), you can pass a pcre_extra block in which
+    a different value is set. See 45 below.
+
+If the limit is exceeded, pcre_exec() returns PCRE_ERROR_MATCHLIMIT.
+
+43. Added a new function pcre_config(int, void *) to enable run-time extraction
+of things that can be changed at compile time. The first argument specifies
+what is wanted and the second points to where the information is to be placed.
+The current list of available information is:
+
+  PCRE_CONFIG_UTF8
+
+The output is an integer that is set to one if UTF-8 support is available;
+otherwise it is set to zero.
+
+  PCRE_CONFIG_NEWLINE
+
+The output is an integer that it set to the value of the code that is used for
+newline. It is either LF (10) or CR (13).
+
+  PCRE_CONFIG_LINK_SIZE
+
+The output is an integer that contains the number of bytes used for internal
+linkage in compiled expressions. The value is 2, 3, or 4. See item 32 above.
+
+  PCRE_CONFIG_POSIX_MALLOC_THRESHOLD
+
+The output is an integer that contains the threshold above which the POSIX
+interface uses malloc() for output vectors. See item 31 above.
+
+  PCRE_CONFIG_MATCH_LIMIT
+
+The output is an unsigned integer that contains the default limit of the number
+of match() calls in a pcre_exec() execution. See 42 above.
+
+44. pcretest has been upgraded by the addition of the -C option. This causes it
+to extract all the available output from the new pcre_config() function, and to
+output it. The program then exits immediately.
+
+45. A need has arisen to pass over additional data with calls to pcre_exec() in
+order to support additional features. One way would have been to define
+pcre_exec2() (for example) with extra arguments, but this would not have been
+extensible, and would also have required all calls to the original function to
+be mapped to the new one. Instead, I have chosen to extend the mechanism that
+is used for passing in "extra" data from pcre_study().
+
+The pcre_extra structure is now exposed and defined in pcre.h. It currently
+contains the following fields:
+
+  flags         a bitmap indicating which of the following fields are set
+  study_data    opaque data from pcre_study()
+  match_limit   a way of specifying a limit on match() calls for a specific
+                  call to pcre_exec()
+  callout_data  data for callouts (see 49 below)
+
+The flag bits are also defined in pcre.h, and are
+
+  PCRE_EXTRA_STUDY_DATA
+  PCRE_EXTRA_MATCH_LIMIT
+  PCRE_EXTRA_CALLOUT_DATA
+
+The pcre_study() function now returns one of these new pcre_extra blocks, with
+the actual study data pointed to by the study_data field, and the
+PCRE_EXTRA_STUDY_DATA flag set. This can be passed directly to pcre_exec() as
+before. That is, this change is entirely upwards-compatible and requires no
+change to existing code.
+
+If you want to pass in additional data to pcre_exec(), you can either place it
+in a pcre_extra block provided by pcre_study(), or create your own pcre_extra
+block.
+
+46. pcretest has been extended to test the PCRE_EXTRA_MATCH_LIMIT feature. If a
+data string contains the escape sequence \M, pcretest calls pcre_exec() several
+times with different match limits, until it finds the minimum value needed for
+pcre_exec() to complete. The value is then output. This can be instructive; for
+most simple matches the number is quite small, but for pathological cases it
+gets very large very quickly.
+
+47. There's a new option for pcre_fullinfo() called PCRE_INFO_STUDYSIZE. It
+returns the size of the data block pointed to by the study_data field in a
+pcre_extra block, that is, the value that was passed as the argument to
+pcre_malloc() when PCRE was getting memory in which to place the information
+created by pcre_study(). The fourth argument should point to a size_t variable.
+pcretest has been extended so that this information is shown after a successful
+pcre_study() call when information about the compiled regex is being displayed.
+
+48. Cosmetic change to Makefile: there's no need to have / after $(DESTDIR)
+because what follows is always an absolute path. (Later: it turns out that this
+is more than cosmetic for MinGW, because it doesn't like empty path
+components.)
+
+49. Some changes have been made to the callout feature (see 28 above):
+
+(i)  A callout function now has three choices for what it returns:
+
+       0  =>  success, carry on matching
+     > 0  =>  failure at this point, but backtrack if possible
+     < 0  =>  serious error, return this value from pcre_exec()
+
+     Negative values should normally be chosen from the set of PCRE_ERROR_xxx
+     values. In particular, returning PCRE_ERROR_NOMATCH forces a standard
+     "match failed" error. The error number PCRE_ERROR_CALLOUT is reserved for
+     use by callout functions. It will never be used by PCRE itself.
+
+(ii) The pcre_extra structure (see 45 above) has a void * field called
+     callout_data, with corresponding flag bit PCRE_EXTRA_CALLOUT_DATA. The
+     pcre_callout_block structure has a field of the same name. The contents of
+     the field passed in the pcre_extra structure are passed to the callout
+     function in the corresponding field in the callout block. This makes it
+     easier to use the same callout-containing regex from multiple threads. For
+     testing, the pcretest program has a new data escape
+
+       \C*n        pass the number n (may be negative) as callout_data
+
+     If the callout function in pcretest receives a non-zero value as
+     callout_data, it returns that value.
+
+50. Makefile wasn't handling CFLAGS properly when compiling dftables. Also,
+there were some redundant $(CFLAGS) in commands that are now specified as
+$(LINK), which already includes $(CFLAGS).
+
+51. Extensions to UTF-8 support are listed below. These all apply when (a) PCRE
+has been compiled with UTF-8 support *and* pcre_compile() has been compiled
+with the PCRE_UTF8 flag. Patterns that are compiled without that flag assume
+one-byte characters throughout. Note that case-insensitive matching applies
+only to characters whose values are less than 256. PCRE doesn't support the
+notion of cases for higher-valued characters.
+
+(i)   A character class whose characters are all within 0-255 is handled as
+      a bit map, and the map is inverted for negative classes. Previously, a
+      character > 255 always failed to match such a class; however it should
+      match if the class was a negative one (e.g. [^ab]). This has been fixed.
+
+(ii)  A negated character class with a single character < 255 is coded as
+      "not this character" (OP_NOT). This wasn't working properly when the test
+      character was multibyte, either singly or repeated.
+
+(iii) Repeats of multibyte characters are now handled correctly in UTF-8
+      mode, for example: \x{100}{2,3}.
+
+(iv)  The character escapes \b, \B, \d, \D, \s, \S, \w, and \W (either
+      singly or repeated) now correctly test multibyte characters. However,
+      PCRE doesn't recognize any characters with values greater than 255 as
+      digits, spaces, or word characters. Such characters always match \D, \S,
+      and \W, and never match \d, \s, or \w.
+
+(v)   Classes may now contain characters and character ranges with values
+      greater than 255. For example: [ab\x{100}-\x{400}].
+
+(vi)  pcregrep now has a --utf-8 option (synonym -u) which makes it call
+      PCRE in UTF-8 mode.
+
+52. The info request value PCRE_INFO_FIRSTCHAR has been renamed
+PCRE_INFO_FIRSTBYTE because it is a byte value. However, the old name is
+retained for backwards compatibility. (Note that LASTLITERAL is also a byte
+value.)
+
+53. The single man page has become too large. I have therefore split it up into
+a number of separate man pages. These also give rise to individual HTML pages;
+these are now put in a separate directory, and there is an index.html page that
+lists them all. Some hyperlinking between the pages has been installed.
+
+54. Added convenience functions for handling named capturing parentheses.
+
+55. Unknown escapes inside character classes (e.g. [\M]) and escapes that
+aren't interpreted therein (e.g. [\C]) are literals in Perl. This is now also
+true in PCRE, except when the PCRE_EXTENDED option is set, in which case they
+are faulted.
+
+56. Introduced HOST_CC and HOST_CFLAGS which can be set in the environment when
+calling configure. These values are used when compiling the dftables.c program
+which is run to generate the source of the default character tables. They
+default to the values of CC and CFLAGS. If you are cross-compiling PCRE,
+you will need to set these values.
+
+57. Updated the building process for Windows DLL, as provided by Fred Cox.
+
+
+Version 3.9 02-Jan-02
+---------------------
+
+1. A bit of extraneous text had somehow crept into the pcregrep documentation.
+
+2. If --disable-static was given, the building process failed when trying to
+build pcretest and pcregrep. (For some reason it was using libtool to compile
+them, which is not right, as they aren't part of the library.)
+
+
+Version 3.8 18-Dec-01
+---------------------
+
+1. The experimental UTF-8 code was completely screwed up. It was packing the
+bytes in the wrong order. How dumb can you get?
+
+
+Version 3.7 29-Oct-01
+---------------------
+
+1. In updating pcretest to check change 1 of version 3.6, I screwed up.
+This caused pcretest, when used on the test data, to segfault. Unfortunately,
+this didn't happen under Solaris 8, where I normally test things.
+
+2. The Makefile had to be changed to make it work on BSD systems, where 'make'
+doesn't seem to recognize that ./xxx and xxx are the same file. (This entry
+isn't in ChangeLog distributed with 3.7 because I forgot when I hastily made
+this fix an hour or so after the initial 3.7 release.)
+
+
+Version 3.6 23-Oct-01
+---------------------
+
+1. Crashed with /(sens|respons)e and \1ibility/ and "sense and sensibility" if
+offsets passed as NULL with zero offset count.
+
+2. The config.guess and config.sub files had not been updated when I moved to
+the latest autoconf.
+
+
+Version 3.5 15-Aug-01
+---------------------
+
+1. Added some missing #if !defined NOPOSIX conditionals in pcretest.c that
+had been forgotten.
+
+2. By using declared but undefined structures, we can avoid using "void"
+definitions in pcre.h while keeping the internal definitions of the structures
+private.
+
+3. The distribution is now built using autoconf 2.50 and libtool 1.4. From a
+user point of view, this means that both static and shared libraries are built
+by default, but this can be individually controlled. More of the work of
+handling this static/shared cases is now inside libtool instead of PCRE's make
+file.
+
+4. The pcretest utility is now installed along with pcregrep because it is
+useful for users (to test regexs) and by doing this, it automatically gets
+relinked by libtool. The documentation has been turned into a man page, so
+there are now .1, .txt, and .html versions in /doc.
+
+5. Upgrades to pcregrep:
+   (i)   Added long-form option names like gnu grep.
+   (ii)  Added --help to list all options with an explanatory phrase.
+   (iii) Added -r, --recursive to recurse into sub-directories.
+   (iv)  Added -f, --file to read patterns from a file.
+
+6. pcre_exec() was referring to its "code" argument before testing that
+argument for NULL (and giving an error if it was NULL).
+
+7. Upgraded Makefile.in to allow for compiling in a different directory from
+the source directory.
+
+8. Tiny buglet in pcretest: when pcre_fullinfo() was called to retrieve the
+options bits, the pointer it was passed was to an int instead of to an unsigned
+long int. This mattered only on 64-bit systems.
+
+9. Fixed typo (3.4/1) in pcre.h again. Sigh. I had changed pcre.h (which is
+generated) instead of pcre.in, which it its source. Also made the same change
+in several of the .c files.
+
+10. A new release of gcc defines printf() as a macro, which broke pcretest
+because it had an ifdef in the middle of a string argument for printf(). Fixed
+by using separate calls to printf().
+
+11. Added --enable-newline-is-cr and --enable-newline-is-lf to the configure
+script, to force use of CR or LF instead of \n in the source. On non-Unix
+systems, the value can be set in config.h.
+
+12. The limit of 200 on non-capturing parentheses is a _nesting_ limit, not an
+absolute limit. Changed the text of the error message to make this clear, and
+likewise updated the man page.
+
+13. The limit of 99 on the number of capturing subpatterns has been removed.
+The new limit is 65535, which I hope will not be a "real" limit.
+
+
+Version 3.4 22-Aug-00
+---------------------
+
+1. Fixed typo in pcre.h: unsigned const char * changed to const unsigned char *.
+
+2. Diagnose condition (?(0) as an error instead of crashing on matching.
+
+
+Version 3.3 01-Aug-00
+---------------------
+
+1. If an octal character was given, but the value was greater than \377, it
+was not getting masked to the least significant bits, as documented. This could
+lead to crashes in some systems.
+
+2. Perl 5.6 (if not earlier versions) accepts classes like [a-\d] and treats
+the hyphen as a literal. PCRE used to give an error; it now behaves like Perl.
+
+3. Added the functions pcre_free_substring() and pcre_free_substring_list().
+These just pass their arguments on to (pcre_free)(), but they are provided
+because some uses of PCRE bind it to non-C systems that can call its functions,
+but cannot call free() or pcre_free() directly.
+
+4. Add "make test" as a synonym for "make check". Corrected some comments in
+the Makefile.
+
+5. Add $(DESTDIR)/ in front of all the paths in the "install" target in the
+Makefile.
+
+6. Changed the name of pgrep to pcregrep, because Solaris has introduced a
+command called pgrep for grepping around the active processes.
+
+7. Added the beginnings of support for UTF-8 character strings.
+
+8. Arranged for the Makefile to pass over the settings of CC, CFLAGS, and
+RANLIB to ./ltconfig so that they are used by libtool. I think these are all
+the relevant ones. (AR is not passed because ./ltconfig does its own figuring
+out for the ar command.)
+
+
+Version 3.2 12-May-00
+---------------------
+
+This is purely a bug fixing release.
+
+1. If the pattern /((Z)+|A)*/ was matched agained ZABCDEFG it matched Z instead
+of ZA. This was just one example of several cases that could provoke this bug,
+which was introduced by change 9 of version 2.00. The code for breaking
+infinite loops after an iteration that matches an empty string was't working
+correctly.
+
+2. The pcretest program was not imitating Perl correctly for the pattern /a*/g
+when matched against abbab (for example). After matching an empty string, it
+wasn't forcing anchoring when setting PCRE_NOTEMPTY for the next attempt; this
+caused it to match further down the string than it should.
+
+3. The code contained an inclusion of sys/types.h. It isn't clear why this
+was there because it doesn't seem to be needed, and it causes trouble on some
+systems, as it is not a Standard C header. It has been removed.
+
+4. Made 4 silly changes to the source to avoid stupid compiler warnings that
+were reported on the Macintosh. The changes were from
+
+  while ((c = *(++ptr)) != 0 && c != '\n');
+to
+  while ((c = *(++ptr)) != 0 && c != '\n') ;
+
+Totally extraordinary, but if that's what it takes...
+
+5. PCRE is being used in one environment where neither memmove() nor bcopy() is
+available. Added HAVE_BCOPY and an autoconf test for it; if neither
+HAVE_MEMMOVE nor HAVE_BCOPY is set, use a built-in emulation function which
+assumes the way PCRE uses memmove() (always moving upwards).
+
+6. PCRE is being used in one environment where strchr() is not available. There
+was only one use in pcre.c, and writing it out to avoid strchr() probably gives
+faster code anyway.
+
+
+Version 3.2 12-May-00
+---------------------
+
+This is purely a bug fixing release.
+
+1. If the pattern /((Z)+|A)*/ was matched agained ZABCDEFG it matched Z instead
+of ZA. This was just one example of several cases that could provoke this bug,
+which was introduced by change 9 of version 2.00. The code for breaking
+infinite loops after an iteration that matches an empty string was't working
+correctly.
+
+2. The pcretest program was not imitating Perl correctly for the pattern /a*/g
+when matched against abbab (for example). After matching an empty string, it
+wasn't forcing anchoring when setting PCRE_NOTEMPTY for the next attempt; this
+caused it to match further down the string than it should.
+
+3. The code contained an inclusion of sys/types.h. It isn't clear why this
+was there because it doesn't seem to be needed, and it causes trouble on some
+systems, as it is not a Standard C header. It has been removed.
+
+4. Made 4 silly changes to the source to avoid stupid compiler warnings that
+were reported on the Macintosh. The changes were from
+
+  while ((c = *(++ptr)) != 0 && c != '\n');
+to
+  while ((c = *(++ptr)) != 0 && c != '\n') ;
+
+Totally extraordinary, but if that's what it takes...
+
+5. PCRE is being used in one environment where neither memmove() nor bcopy() is
+available. Added HAVE_BCOPY and an autoconf test for it; if neither
+HAVE_MEMMOVE nor HAVE_BCOPY is set, use a built-in emulation function which
+assumes the way PCRE uses memmove() (always moving upwards).
+
+6. PCRE is being used in one environment where strchr() is not available. There
+was only one use in pcre.c, and writing it out to avoid strchr() probably gives
+faster code anyway.
+
+
+Version 3.1 09-Feb-00
+---------------------
+
+The only change in this release is the fixing of some bugs in Makefile.in for
+the "install" target:
+
+(1) It was failing to install pcreposix.h.
+
+(2) It was overwriting the pcre.3 man page with the pcreposix.3 man page.
+
+
+Version 3.0 01-Feb-00
+---------------------
+
+1. Add support for the /+ modifier to perltest (to output $` like it does in
+pcretest).
+
+2. Add support for the /g modifier to perltest.
+
+3. Fix pcretest so that it behaves even more like Perl for /g when the pattern
+matches null strings.
+
+4. Fix perltest so that it doesn't do unwanted things when fed an empty
+pattern. Perl treats empty patterns specially - it reuses the most recent
+pattern, which is not what we want. Replace // by /(?#)/ in order to avoid this
+effect.
+
+5. The POSIX interface was broken in that it was just handing over the POSIX
+captured string vector to pcre_exec(), but (since release 2.00) PCRE has
+required a bigger vector, with some working space on the end. This means that
+the POSIX wrapper now has to get and free some memory, and copy the results.
+
+6. Added some simple autoconf support, placing the test data and the
+documentation in separate directories, re-organizing some of the
+information files, and making it build pcre-config (a GNU standard). Also added
+libtool support for building PCRE as a shared library, which is now the
+default.
+
+7. Got rid of the leading zero in the definition of PCRE_MINOR because 08 and
+09 are not valid octal constants. Single digits will be used for minor values
+less than 10.
+
+8. Defined REG_EXTENDED and REG_NOSUB as zero in the POSIX header, so that
+existing programs that set these in the POSIX interface can use PCRE without
+modification.
+
+9. Added a new function, pcre_fullinfo() with an extensible interface. It can
+return all that pcre_info() returns, plus additional data. The pcre_info()
+function is retained for compatibility, but is considered to be obsolete.
+
+10. Added experimental recursion feature (?R) to handle one common case that
+Perl 5.6 will be able to do with (?p{...}).
+
+11. Added support for POSIX character classes like [:alpha:], which Perl is
+adopting.
+
+
+Version 2.08 31-Aug-99
+----------------------
+
+1. When startoffset was not zero and the pattern began with ".*", PCRE was not
+trying to match at the startoffset position, but instead was moving forward to
+the next newline as if a previous match had failed.
+
+2. pcretest was not making use of PCRE_NOTEMPTY when repeating for /g and /G,
+and could get into a loop if a null string was matched other than at the start
+of the subject.
+
+3. Added definitions of PCRE_MAJOR and PCRE_MINOR to pcre.h so the version can
+be distinguished at compile time, and for completeness also added PCRE_DATE.
+
+5. Added Paul Sokolovsky's minor changes to make it easy to compile a Win32 DLL
+in GnuWin32 environments.
+
+
+Version 2.07 29-Jul-99
+----------------------
+
+1. The documentation is now supplied in plain text form and HTML as well as in
+the form of man page sources.
+
+2. C++ compilers don't like assigning (void *) values to other pointer types.
+In particular this affects malloc(). Although there is no problem in Standard
+C, I've put in casts to keep C++ compilers happy.
+
+3. Typo on pcretest.c; a cast of (unsigned char *) in the POSIX regexec() call
+should be (const char *).
+
+4. If NOPOSIX is defined, pcretest.c compiles without POSIX support. This may
+be useful for non-Unix systems who don't want to bother with the POSIX stuff.
+However, I haven't made this a standard facility. The documentation doesn't
+mention it, and the Makefile doesn't support it.
+
+5. The Makefile now contains an "install" target, with editable destinations at
+the top of the file. The pcretest program is not installed.
+
+6. pgrep -V now gives the PCRE version number and date.
+
+7. Fixed bug: a zero repetition after a literal string (e.g. /abcde{0}/) was
+causing the entire string to be ignored, instead of just the last character.
+
+8. If a pattern like /"([^\\"]+|\\.)*"/ is applied in the normal way to a
+non-matching string, it can take a very, very long time, even for strings of
+quite modest length, because of the nested recursion. PCRE now does better in
+some of these cases. It does this by remembering the last required literal
+character in the pattern, and pre-searching the subject to ensure it is present
+before running the real match. In other words, it applies a heuristic to detect
+some types of certain failure quickly, and in the above example, if presented
+with a string that has no trailing " it gives "no match" very quickly.
+
+9. A new runtime option PCRE_NOTEMPTY causes null string matches to be ignored;
+other alternatives are tried instead.
+
+
+Version 2.06 09-Jun-99
+----------------------
+
+1. Change pcretest's output for amount of store used to show just the code
+space, because the remainder (the data block) varies in size between 32-bit and
+64-bit systems.
+
+2. Added an extra argument to pcre_exec() to supply an offset in the subject to
+start matching at. This allows lookbehinds to work when searching for multiple
+occurrences in a string.
+
+3. Added additional options to pcretest for testing multiple occurrences:
+
+   /+   outputs the rest of the string that follows a match
+   /g   loops for multiple occurrences, using the new startoffset argument
+   /G   loops for multiple occurrences by passing an incremented pointer
+
+4. PCRE wasn't doing the "first character" optimization for patterns starting
+with \b or \B, though it was doing it for other lookbehind assertions. That is,
+it wasn't noticing that a match for a pattern such as /\bxyz/ has to start with
+the letter 'x'. On long subject strings, this gives a significant speed-up.
+
+
+Version 2.05 21-Apr-99
+----------------------
+
+1. Changed the type of magic_number from int to long int so that it works
+properly on 16-bit systems.
+
+2. Fixed a bug which caused patterns starting with .* not to work correctly
+when the subject string contained newline characters. PCRE was assuming
+anchoring for such patterns in all cases, which is not correct because .* will
+not pass a newline unless PCRE_DOTALL is set. It now assumes anchoring only if
+DOTALL is set at top level; otherwise it knows that patterns starting with .*
+must be retried after every newline in the subject.
+
+
+Version 2.04 18-Feb-99
+----------------------
+
+1. For parenthesized subpatterns with repeats whose minimum was zero, the
+computation of the store needed to hold the pattern was incorrect (too large).
+If such patterns were nested a few deep, this could multiply and become a real
+problem.
+
+2. Added /M option to pcretest to show the memory requirement of a specific
+pattern. Made -m a synonym of -s (which does this globally) for compatibility.
+
+3. Subpatterns of the form (regex){n,m} (i.e. limited maximum) were being
+compiled in such a way that the backtracking after subsequent failure was
+pessimal. Something like (a){0,3} was compiled as (a)?(a)?(a)? instead of
+((a)((a)(a)?)?)? with disastrous performance if the maximum was of any size.
+
+
+Version 2.03 02-Feb-99
+----------------------
+
+1. Fixed typo and small mistake in man page.
+
+2. Added 4th condition (GPL supersedes if conflict) and created separate
+LICENCE file containing the conditions.
+
+3. Updated pcretest so that patterns such as /abc\/def/ work like they do in
+Perl, that is the internal \ allows the delimiter to be included in the
+pattern. Locked out the use of \ as a delimiter. If \ immediately follows
+the final delimiter, add \ to the end of the pattern (to test the error).
+
+4. Added the convenience functions for extracting substrings after a successful
+match. Updated pcretest to make it able to test these functions.
+
+
+Version 2.02 14-Jan-99
+----------------------
+
+1. Initialized the working variables associated with each extraction so that
+their saving and restoring doesn't refer to uninitialized store.
+
+2. Put dummy code into study.c in order to trick the optimizer of the IBM C
+compiler for OS/2 into generating correct code. Apparently IBM isn't going to
+fix the problem.
+
+3. Pcretest: the timing code wasn't using LOOPREPEAT for timing execution
+calls, and wasn't printing the correct value for compiling calls. Increased the
+default value of LOOPREPEAT, and the number of significant figures in the
+times.
+
+4. Changed "/bin/rm" in the Makefile to "-rm" so it works on Windows NT.
+
+5. Renamed "deftables" as "dftables" to get it down to 8 characters, to avoid
+a building problem on Windows NT with a FAT file system.
+
+
+Version 2.01 21-Oct-98
+----------------------
+
+1. Changed the API for pcre_compile() to allow for the provision of a pointer
+to character tables built by pcre_maketables() in the current locale. If NULL
+is passed, the default tables are used.
+
+
+Version 2.00 24-Sep-98
+----------------------
+
+1. Since the (>?) facility is in Perl 5.005, don't require PCRE_EXTRA to enable
+it any more.
+
+2. Allow quantification of (?>) groups, and make it work correctly.
+
+3. The first character computation wasn't working for (?>) groups.
+
+4. Correct the implementation of \Z (it is permitted to match on the \n at the
+end of the subject) and add 5.005's \z, which really does match only at the
+very end of the subject.
+
+5. Remove the \X "cut" facility; Perl doesn't have it, and (?> is neater.
+
+6. Remove the ability to specify CASELESS, MULTILINE, DOTALL, and
+DOLLAR_END_ONLY at runtime, to make it possible to implement the Perl 5.005
+localized options. All options to pcre_study() were also removed.
+
+7. Add other new features from 5.005:
+
+   $(?<=           positive lookbehind
+   $(?<!           negative lookbehind
+   (?imsx-imsx)    added the unsetting capability
+                   such a setting is global if at outer level; local otherwise
+   (?imsx-imsx:)   non-capturing groups with option setting
+   (?(cond)re|re)  conditional pattern matching
+
+   A backreference to itself in a repeated group matches the previous
+   captured string.
+
+8. General tidying up of studying (both automatic and via "study")
+consequential on the addition of new assertions.
+
+9. As in 5.005, unlimited repeated groups that could match an empty substring
+are no longer faulted at compile time. Instead, the loop is forcibly broken at
+runtime if any iteration does actually match an empty substring.
+
+10. Include the RunTest script in the distribution.
+
+11. Added tests from the Perl 5.005_02 distribution. This showed up a few
+discrepancies, some of which were old and were also with respect to 5.004. They
+have now been fixed.
+
+
+Version 1.09 28-Apr-98
+----------------------
+
+1. A negated single character class followed by a quantifier with a minimum
+value of one (e.g.  [^x]{1,6}  ) was not compiled correctly. This could lead to
+program crashes, or just wrong answers. This did not apply to negated classes
+containing more than one character, or to minima other than one.
+
+
+Version 1.08 27-Mar-98
+----------------------
+
+1. Add PCRE_UNGREEDY to invert the greediness of quantifiers.
+
+2. Add (?U) and (?X) to set PCRE_UNGREEDY and PCRE_EXTRA respectively. The
+latter must appear before anything that relies on it in the pattern.
+
+
+Version 1.07 16-Feb-98
+----------------------
+
+1. A pattern such as /((a)*)*/ was not being diagnosed as in error (unlimited
+repeat of a potentially empty string).
+
+
+Version 1.06 23-Jan-98
+----------------------
+
+1. Added Markus Oberhumer's little patches for C++.
+
+2. Literal strings longer than 255 characters were broken.
+
+
+Version 1.05 23-Dec-97
+----------------------
+
+1. Negated character classes containing more than one character were failing if
+PCRE_CASELESS was set at run time.
+
+
+Version 1.04 19-Dec-97
+----------------------
+
+1. Corrected the man page, where some "const" qualifiers had been omitted.
+
+2. Made debugging output print "{0,xxx}" instead of just "{,xxx}" to agree with
+input syntax.
+
+3. Fixed memory leak which occurred when a regex with back references was
+matched with an offsets vector that wasn't big enough. The temporary memory
+that is used in this case wasn't being freed if the match failed.
+
+4. Tidied pcretest to ensure it frees memory that it gets.
+
+5. Temporary memory was being obtained in the case where the passed offsets
+vector was exactly big enough.
+
+6. Corrected definition of offsetof() from change 5 below.
+
+7. I had screwed up change 6 below and broken the rules for the use of
+setjmp(). Now fixed.
+
+
+Version 1.03 18-Dec-97
+----------------------
+
+1. A erroneous regex with a missing opening parenthesis was correctly
+diagnosed, but PCRE attempted to access brastack[-1], which could cause crashes
+on some systems.
+
+2. Replaced offsetof(real_pcre, code) by offsetof(real_pcre, code[0]) because
+it was reported that one broken compiler failed on the former because "code" is
+also an independent variable.
+
+3. The erroneous regex a[]b caused an array overrun reference.
+
+4. A regex ending with a one-character negative class (e.g. /[^k]$/) did not
+fail on data ending with that character. (It was going on too far, and checking
+the next character, typically a binary zero.) This was specific to the
+optimized code for single-character negative classes.
+
+5. Added a contributed patch from the TIN world which does the following:
+
+  + Add an undef for memmove, in case the the system defines a macro for it.
+
+  + Add a definition of offsetof(), in case there isn't one. (I don't know
+    the reason behind this - offsetof() is part of the ANSI standard - but
+    it does no harm).
+
+  + Reduce the ifdef's in pcre.c using macro DPRINTF, thereby eliminating
+    most of the places where whitespace preceded '#'. I have given up and
+    allowed the remaining 2 cases to be at the margin.
+
+  + Rename some variables in pcre to eliminate shadowing. This seems very
+    pedantic, but does no harm, of course.
+
+6. Moved the call to setjmp() into its own function, to get rid of warnings
+from gcc -Wall, and avoided calling it at all unless PCRE_EXTRA is used.
+
+7. Constructs such as \d{8,} were compiling into the equivalent of
+\d{8}\d{0,65527} instead of \d{8}\d* which didn't make much difference to the
+outcome, but in this particular case used more store than had been allocated,
+which caused the bug to be discovered because it threw up an internal error.
+
+8. The debugging code in both pcre and pcretest for outputting the compiled
+form of a regex was going wrong in the case of back references followed by
+curly-bracketed repeats.
+
+
+Version 1.02 12-Dec-97
+----------------------
+
+1. Typos in pcre.3 and comments in the source fixed.
+
+2. Applied a contributed patch to get rid of places where it used to remove
+'const' from variables, and fixed some signed/unsigned and uninitialized
+variable warnings.
+
+3. Added the "runtest" target to Makefile.
+
+4. Set default compiler flag to -O2 rather than just -O.
+
+
+Version 1.01 19-Nov-97
+----------------------
+
+1. PCRE was failing to diagnose unlimited repeat of empty string for patterns
+like /([ab]*)*/, that is, for classes with more than one character in them.
+
+2. Likewise, it wasn't diagnosing patterns with "once-only" subpatterns, such
+as /((?>a*))*/ (a PCRE_EXTRA facility).
+
+
+Version 1.00 18-Nov-97
+----------------------
+
+1. Added compile-time macros to support systems such as SunOS4 which don't have
+memmove() or strerror() but have other things that can be used instead.
+
+2. Arranged that "make clean" removes the executables.
+
+
+Version 0.99 27-Oct-97
+----------------------
+
+1. Fixed bug in code for optimizing classes with only one character. It was
+initializing a 32-byte map regardless, which could cause it to run off the end
+of the memory it had got.
+
+2. Added, conditional on PCRE_EXTRA, the proposed (?>REGEX) construction.
+
+
+Version 0.98 22-Oct-97
+----------------------
+
+1. Fixed bug in code for handling temporary memory usage when there are more
+back references than supplied space in the ovector. This could cause segfaults.
+
+
+Version 0.97 21-Oct-97
+----------------------
+
+1. Added the \X "cut" facility, conditional on PCRE_EXTRA.
+
+2. Optimized negated single characters not to use a bit map.
+
+3. Brought error texts together as macro definitions; clarified some of them;
+fixed one that was wrong - it said "range out of order" when it meant "invalid
+escape sequence".
+
+4. Changed some char * arguments to const char *.
+
+5. Added PCRE_NOTBOL and PCRE_NOTEOL (from POSIX).
+
+6. Added the POSIX-style API wrapper in pcreposix.a and testing facilities in
+pcretest.
+
+
+Version 0.96 16-Oct-97
+----------------------
+
+1. Added a simple "pgrep" utility to the distribution.
+
+2. Fixed an incompatibility with Perl: "{" is now treated as a normal character
+unless it appears in one of the precise forms "{ddd}", "{ddd,}", or "{ddd,ddd}"
+where "ddd" means "one or more decimal digits".
+
+3. Fixed serious bug. If a pattern had a back reference, but the call to
+pcre_exec() didn't supply a large enough ovector to record the related
+identifying subpattern, the match always failed. PCRE now remembers the number
+of the largest back reference, and gets some temporary memory in which to save
+the offsets during matching if necessary, in order to ensure that
+backreferences always work.
+
+4. Increased the compatibility with Perl in a number of ways:
+
+  (a) . no longer matches \n by default; an option PCRE_DOTALL is provided
+      to request this handling. The option can be set at compile or exec time.
+
+  (b) $ matches before a terminating newline by default; an option
+      PCRE_DOLLAR_ENDONLY is provided to override this (but not in multiline
+      mode). The option can be set at compile or exec time.
+
+  (c) The handling of \ followed by a digit other than 0 is now supposed to be
+      the same as Perl's. If the decimal number it represents is less than 10
+      or there aren't that many previous left capturing parentheses, an octal
+      escape is read. Inside a character class, it's always an octal escape,
+      even if it is a single digit.
+
+  (d) An escaped but undefined alphabetic character is taken as a literal,
+      unless PCRE_EXTRA is set. Currently this just reserves the remaining
+      escapes.
+
+  (e) {0} is now permitted. (The previous item is removed from the compiled
+      pattern).
+
+5. Changed all the names of code files so that the basic parts are no longer
+than 10 characters, and abolished the teeny "globals.c" file.
+
+6. Changed the handling of character classes; they are now done with a 32-byte
+bit map always.
+
+7. Added the -d and /D options to pcretest to make it possible to look at the
+internals of compilation without having to recompile pcre.
+
+
+Version 0.95 23-Sep-97
+----------------------
+
+1. Fixed bug in pre-pass concerning escaped "normal" characters such as \x5c or
+\x20 at the start of a run of normal characters. These were being treated as
+real characters, instead of the source characters being re-checked.
+
+
+Version 0.94 18-Sep-97
+----------------------
+
+1. The functions are now thread-safe, with the caveat that the global variables
+containing pointers to malloc() and free() or alternative functions are the
+same for all threads.
+
+2. Get pcre_study() to generate a bitmap of initial characters for non-
+anchored patterns when this is possible, and use it if passed to pcre_exec().
+
+
+Version 0.93 15-Sep-97
+----------------------
+
+1. /(b)|(:+)/ was computing an incorrect first character.
+
+2. Add pcre_study() to the API and the passing of pcre_extra to pcre_exec(),
+but not actually doing anything yet.
+
+3. Treat "-" characters in classes that cannot be part of ranges as literals,
+as Perl does (e.g. [-az] or [az-]).
+
+4. Set the anchored flag if a branch starts with .* or .*? because that tests
+all possible positions.
+
+5. Split up into different modules to avoid including unneeded functions in a
+compiled binary. However, compile and exec are still in one module. The "study"
+function is split off.
+
+6. The character tables are now in a separate module whose source is generated
+by an auxiliary program - but can then be edited by hand if required. There are
+now no calls to isalnum(), isspace(), isdigit(), isxdigit(), tolower() or
+toupper() in the code.
+
+7. Turn the malloc/free funtions variables into pcre_malloc and pcre_free and
+make them global. Abolish the function for setting them, as the caller can now
+set them directly.
+
+
+Version 0.92 11-Sep-97
+----------------------
+
+1. A repeat with a fixed maximum and a minimum of 1 for an ordinary character
+(e.g. /a{1,3}/) was broken (I mis-optimized it).
+
+2. Caseless matching was not working in character classes if the characters in
+the pattern were in upper case.
+
+3. Make ranges like [W-c] work in the same way as Perl for caseless matching.
+
+4. Make PCRE_ANCHORED public and accept as a compile option.
+
+5. Add an options word to pcre_exec() and accept PCRE_ANCHORED and
+PCRE_CASELESS at run time. Add escapes \A and \I to pcretest to cause it to
+pass them.
+
+6. Give an error if bad option bits passed at compile or run time.
+
+7. Add PCRE_MULTILINE at compile and exec time, and (?m) as well. Add \M to
+pcretest to cause it to pass that flag.
+
+8. Add pcre_info(), to get the number of identifying subpatterns, the stored
+options, and the first character, if set.
+
+9. Recognize C+ or C{n,m} where n >= 1 as providing a fixed starting character.
+
+
+Version 0.91 10-Sep-97
+----------------------
+
+1. PCRE was failing to diagnose unlimited repeats of subpatterns that could
+match the empty string as in /(a*)*/. It was looping and ultimately crashing.
+
+2. PCRE was looping on encountering an indefinitely repeated back reference to
+a subpattern that had matched an empty string, e.g. /(a|)\1*/. It now does what
+Perl does - treats the match as successful.
+
+****

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/INSTALL
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/INSTALL	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/INSTALL	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,185 @@
+Basic Installation
+==================
+
+   These are generic installation instructions that apply to systems that
+can run the `configure' shell script - Unix systems and any that imitate
+it. They are not specific to PCRE. There are PCRE-specific instructions
+for non-Unix systems in the file NON-UNIX-USE.
+
+   The `configure' shell script attempts to guess correct values for
+various system-dependent variables used during compilation.  It uses
+those values to create a `Makefile' in each directory of the package.
+It may also create one or more `.h' files containing system-dependent
+definitions.  Finally, it creates a shell script `config.status' that
+you can run in the future to recreate the current configuration, a file
+`config.cache' that saves the results of its tests to speed up
+reconfiguring, and a file `config.log' containing compiler output
+(useful mainly for debugging `configure').
+
+   If you need to do unusual things to compile the package, please try
+to figure out how `configure' could check whether to do them, and mail
+diffs or instructions to the address given in the `README' so they can
+be considered for the next release.  If at some point `config.cache'
+contains results you don't want to keep, you may remove or edit it.
+
+   The file `configure.in' is used to create `configure' by a program
+called `autoconf'.  You only need `configure.in' if you want to change
+it or regenerate `configure' using a newer version of `autoconf'.
+
+The simplest way to compile this package is:
+
+  1. `cd' to the directory containing the package's source code and type
+     `./configure' to configure the package for your system.  If you're
+     using `csh' on an old version of System V, you might need to type
+     `sh ./configure' instead to prevent `csh' from trying to execute
+     `configure' itself.
+
+     Running `configure' takes awhile.  While running, it prints some
+     messages telling which features it is checking for.
+
+  2. Type `make' to compile the package.
+
+  3. Optionally, type `make check' to run any self-tests that come with
+     the package.
+
+  4. Type `make install' to install the programs and any data files and
+     documentation.
+
+  5. You can remove the program binaries and object files from the
+     source code directory by typing `make clean'.  To also remove the
+     files that `configure' created (so you can compile the package for
+     a different kind of computer), type `make distclean'.  There is
+     also a `make maintainer-clean' target, but that is intended mainly
+     for the package's developers.  If you use it, you may have to get
+     all sorts of other programs in order to regenerate files that came
+     with the distribution.
+
+Compilers and Options
+=====================
+
+   Some systems require unusual options for compilation or linking that
+the `configure' script does not know about.  You can give `configure'
+initial values for variables by setting them in the environment.  Using
+a Bourne-compatible shell, you can do that on the command line like
+this:
+     CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure
+
+Or on systems that have the `env' program, you can do it like this:
+     env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure
+
+Compiling For Multiple Architectures
+====================================
+
+   You can compile the package for more than one kind of computer at the
+same time, by placing the object files for each architecture in their
+own directory.  To do this, you must use a version of `make' that
+supports the `VPATH' variable, such as GNU `make'.  `cd' to the
+directory where you want the object files and executables to go and run
+the `configure' script.  `configure' automatically checks for the
+source code in the directory that `configure' is in and in `..'.
+
+   If you have to use a `make' that does not supports the `VPATH'
+variable, you have to compile the package for one architecture at a time
+in the source code directory.  After you have installed the package for
+one architecture, use `make distclean' before reconfiguring for another
+architecture.
+
+Installation Names
+==================
+
+   By default, `make install' will install the package's files in
+`/usr/local/bin', `/usr/local/man', etc.  You can specify an
+installation prefix other than `/usr/local' by giving `configure' the
+option `--prefix=PATH'.
+
+   You can specify separate installation prefixes for
+architecture-specific files and architecture-independent files.  If you
+give `configure' the option `--exec-prefix=PATH', the package will use
+PATH as the prefix for installing programs and libraries.
+Documentation and other data files will still use the regular prefix.
+
+   In addition, if you use an unusual directory layout you can give
+options like `--bindir=PATH' to specify different values for particular
+kinds of files.  Run `configure --help' for a list of the directories
+you can set and what kinds of files go in them.
+
+   If the package supports it, you can cause programs to be installed
+with an extra prefix or suffix on their names by giving `configure' the
+option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
+
+Optional Features
+=================
+
+   Some packages pay attention to `--enable-FEATURE' options to
+`configure', where FEATURE indicates an optional part of the package.
+They may also pay attention to `--with-PACKAGE' options, where PACKAGE
+is something like `gnu-as' or `x' (for the X Window System).  The
+`README' should mention any `--enable-' and `--with-' options that the
+package recognizes.
+
+   For packages that use the X Window System, `configure' can usually
+find the X include and library files automatically, but if it doesn't,
+you can use the `configure' options `--x-includes=DIR' and
+`--x-libraries=DIR' to specify their locations.
+
+Specifying the System Type
+==========================
+
+   There may be some features `configure' can not figure out
+automatically, but needs to determine by the type of host the package
+will run on.  Usually `configure' can figure that out, but if it prints
+a message saying it can not guess the host type, give it the
+`--host=TYPE' option.  TYPE can either be a short name for the system
+type, such as `sun4', or a canonical name with three fields:
+     CPU-COMPANY-SYSTEM
+
+See the file `config.sub' for the possible values of each field.  If
+`config.sub' isn't included in this package, then this package doesn't
+need to know the host type.
+
+   If you are building compiler tools for cross-compiling, you can also
+use the `--target=TYPE' option to select the type of system they will
+produce code for and the `--build=TYPE' option to select the type of
+system on which you are compiling the package.
+
+Sharing Defaults
+================
+
+   If you want to set default values for `configure' scripts to share,
+you can create a site shell script called `config.site' that gives
+default values for variables like `CC', `cache_file', and `prefix'.
+`configure' looks for `PREFIX/share/config.site' if it exists, then
+`PREFIX/etc/config.site' if it exists.  Or, you can set the
+`CONFIG_SITE' environment variable to the location of the site script.
+A warning: not all `configure' scripts look for a site script.
+
+Operation Controls
+==================
+
+   `configure' recognizes the following options to control how it
+operates.
+
+`--cache-file=FILE'
+     Use and save the results of the tests in FILE instead of
+     `./config.cache'.  Set FILE to `/dev/null' to disable caching, for
+     debugging `configure'.
+
+`--help'
+     Print a summary of the options to `configure', and exit.
+
+`--quiet'
+`--silent'
+`-q'
+     Do not print messages saying which checks are being made.  To
+     suppress all normal output, redirect it to `/dev/null' (any error
+     messages will still be shown).
+
+`--srcdir=DIR'
+     Look for the package's source code in directory DIR.  Usually
+     `configure' can determine that directory automatically.
+
+`--version'
+     Print the version of Autoconf used to generate the `configure'
+     script, and exit.
+
+`configure' also accepts some other, not widely useful, options.

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/LICENCE
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/LICENCE	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/LICENCE	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,45 @@
+PCRE LICENCE
+------------
+
+PCRE is a library of functions to support regular expressions whose syntax
+and semantics are as close as possible to those of the Perl 5 language.
+
+Release 5 of PCRE is distributed under the terms of the "BSD" licence, as
+specified below. The documentation for PCRE, supplied in the "doc"
+directory, is distributed under the same terms as the software itself.
+
+Written by: Philip Hazel <ph10 at cam.ac.uk>
+
+University of Cambridge Computing Service,
+Cambridge, England. Phone: +44 1223 334714.
+
+Copyright (c) 1997-2004 University of Cambridge
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice,
+      this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+
+    * Neither the name of the University of Cambridge nor the names of its
+      contributors may be used to endorse or promote products derived from
+      this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+End

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/Makefile.in
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/Makefile.in	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/Makefile.in	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,20 @@
+LTLIBRARY_NAME = libpcre.la
+LTLIBRARY_SOURCES = maketables.c get.c study.c pcre.c
+
+CLEAN_TARGETS = dftables chartables.c
+DISTCLEAN_TARGETS = pcre.h pcre-config config.h config.log config.status $(CLEAN_TARGETS)
+
+include $(top_srcdir)/build/ltlib.mk
+
+config.h:
+	touch $@
+
+$(LTLIBRARY_OBJECTS) dftables.lo: config.h
+
+dftables: dftables.lo
+	$(LINK) $(EXTRA_LDFLAGS) dftables.lo $(EXTRA_LIBS)
+
+$(srcdir)/chartables.c: dftables
+	./dftables $@
+
+pcre.lo: $(srcdir)/chartables.c

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/NEWS
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/NEWS	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/NEWS	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,201 @@
+News about PCRE releases
+------------------------
+
+Release 5.0 13-Sep-04
+---------------------
+
+The licence under which PCRE is released has been changed to the more
+conventional "BSD" licence.
+
+In the code, some bugs have been fixed, and there are also some major changes
+in this release (which is why I've increased the number to 5.0). Some changes
+are internal rearrangements, and some provide a number of new facilities. The
+new features are:
+
+1. There's an "automatic callout" feature that inserts callouts before every
+   item in the regex, and there's a new callout field that gives the position
+   in the pattern - useful for debugging and tracing.
+
+2. The extra_data structure can now be used to pass in a set of character
+   tables at exec time. This is useful if compiled regex are saved and re-used
+   at a later time when the tables may not be at the same address. If the
+   default internal tables are used, the pointer saved with the compiled
+   pattern is now set to NULL, which means that you don't need to do anything
+   special unless you are using custom tables.
+
+3. It is possible, with some restrictions on the content of the regex, to
+   request "partial" matching. A special return code is given if all of the
+   subject string matched part of the regex. This could be useful for testing
+   an input field as it is being typed.
+
+4. There is now some optional support for Unicode character properties, which
+   means that the patterns items such as \p{Lu} and \X can now be used. Only
+   the general category properties are supported. If PCRE is compiled with this
+   support, an additional 90K data structure is include, which increases the
+   size of the library dramatically.
+
+5. There is support for saving compiled patterns and re-using them later.
+
+6. There is support for running regular expressions that were compiled on a
+   different host with the opposite endianness.
+
+7. The pcretest program has been extended to accommodate the new features.
+
+The main internal rearrangement is that sequences of literal characters are no
+longer handled as strings. Instead, each character is handled on its own. This
+makes some UTF-8 handling easier, and makes the support of partial matching
+possible. Compiled patterns containing long literal strings will be larger as a
+result of this change; I hope that performance will not be much affected.
+
+
+Release 4.5 01-Dec-03
+---------------------
+
+Again mainly a bug-fix and tidying release, with only a couple of new features:
+
+1. It's possible now to compile PCRE so that it does not use recursive
+function calls when matching. Instead it gets memory from the heap. This slows
+things down, but may be necessary on systems with limited stacks.
+
+2. UTF-8 string checking has been tightened to reject overlong sequences and to
+check that a starting offset points to the start of a character. Failure of the
+latter returns a new error code: PCRE_ERROR_BADUTF8_OFFSET.
+
+3. PCRE can now be compiled for systems that use EBCDIC code.
+
+
+Release 4.4 21-Aug-03
+---------------------
+
+This is mainly a bug-fix and tidying release. The only new feature is that PCRE
+checks UTF-8 strings for validity by default. There is an option to suppress
+this, just in case anybody wants that teeny extra bit of performance.
+
+
+Releases 4.1 - 4.3
+------------------
+
+Sorry, I forgot about updating the NEWS file for these releases. Please take a
+look at ChangeLog.
+
+
+Release 4.0 17-Feb-03
+---------------------
+
+There have been a lot of changes for the 4.0 release, adding additional
+functionality and mending bugs. Below is a list of the highlights of the new
+functionality. For full details of these features, please consult the
+documentation. For a complete list of changes, see the ChangeLog file.
+
+1. Support for Perl's \Q...\E escapes.
+
+2. "Possessive quantifiers" ?+, *+, ++, and {,}+ which come from Sun's Java
+package. They provide some syntactic sugar for simple cases of "atomic
+grouping".
+
+3. Support for the \G assertion. It is true when the current matching position
+is at the start point of the match.
+
+4. A new feature that provides some of the functionality that Perl provides
+with (?{...}). The facility is termed a "callout". The way it is done in PCRE
+is for the caller to provide an optional function, by setting pcre_callout to
+its entry point. To get the function called, the regex must include (?C) at
+appropriate points.
+
+5. Support for recursive calls to individual subpatterns. This makes it really
+easy to get totally confused.
+
+6. Support for named subpatterns. The Python syntax (?P<name>...) is used to
+name a group.
+
+7. Several extensions to UTF-8 support; it is now fairly complete. There is an
+option for pcregrep to make it operate in UTF-8 mode.
+
+8. The single man page has been split into a number of separate man pages.
+These also give rise to individual HTML pages which are put in a separate
+directory. There is an index.html page that lists them all. Some hyperlinking
+between the pages has been installed.
+
+
+Release 3.5 15-Aug-01
+---------------------
+
+1. The configuring system has been upgraded to use later versions of autoconf
+and libtool. By default it builds both a shared and a static library if the OS
+supports it. You can use --disable-shared or --disable-static on the configure
+command if you want only one of them.
+
+2. The pcretest utility is now installed along with pcregrep because it is
+useful for users (to test regexs) and by doing this, it automatically gets
+relinked by libtool. The documentation has been turned into a man page, so
+there are now .1, .txt, and .html versions in /doc.
+
+3. Upgrades to pcregrep:
+   (i)   Added long-form option names like gnu grep.
+   (ii)  Added --help to list all options with an explanatory phrase.
+   (iii) Added -r, --recursive to recurse into sub-directories.
+   (iv)  Added -f, --file to read patterns from a file.
+
+4. Added --enable-newline-is-cr and --enable-newline-is-lf to the configure
+script, to force use of CR or LF instead of \n in the source. On non-Unix
+systems, the value can be set in config.h.
+
+5. The limit of 200 on non-capturing parentheses is a _nesting_ limit, not an
+absolute limit. Changed the text of the error message to make this clear, and
+likewise updated the man page.
+
+6. The limit of 99 on the number of capturing subpatterns has been removed.
+The new limit is 65535, which I hope will not be a "real" limit.
+
+
+Release 3.3 01-Aug-00
+---------------------
+
+There is some support for UTF-8 character strings. This is incomplete and
+experimental. The documentation describes what is and what is not implemented.
+Otherwise, this is just a bug-fixing release.
+
+
+Release 3.0 01-Feb-00
+---------------------
+
+1. A "configure" script is now used to configure PCRE for Unix systems. It
+builds a Makefile, a config.h file, and the pcre-config script.
+
+2. PCRE is built as a shared library by default.
+
+3. There is support for POSIX classes such as [:alpha:].
+
+5. There is an experimental recursion feature.
+
+----------------------------------------------------------------------------
+          IMPORTANT FOR THOSE UPGRADING FROM VERSIONS BEFORE 2.00
+
+Please note that there has been a change in the API such that a larger
+ovector is required at matching time, to provide some additional workspace.
+The new man page has details. This change was necessary in order to support
+some of the new functionality in Perl 5.005.
+
+          IMPORTANT FOR THOSE UPGRADING FROM VERSION 2.00
+
+Another (I hope this is the last!) change has been made to the API for the
+pcre_compile() function. An additional argument has been added to make it
+possible to pass over a pointer to character tables built in the current
+locale by pcre_maketables(). To use the default tables, this new arguement
+should be passed as NULL.
+
+          IMPORTANT FOR THOSE UPGRADING FROM VERSION 2.05
+
+Yet another (and again I hope this really is the last) change has been made
+to the API for the pcre_exec() function. An additional argument has been
+added to make it possible to start the match other than at the start of the
+subject string. This is important if there are lookbehinds. The new man
+page has the details, but you just want to convert existing programs, all
+you need to do is to stick in a new fifth argument to pcre_exec(), with a
+value of zero. For example, change
+
+  pcre_exec(pattern, extra, subject, length, options, ovec, ovecsize)
+to
+  pcre_exec(pattern, extra, subject, length, 0, options, ovec, ovecsize)
+
+****

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/NON-UNIX-USE
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/NON-UNIX-USE	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/NON-UNIX-USE	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,244 @@
+Compiling PCRE on non-Unix systems
+----------------------------------
+
+See below for comments on Cygwin or MinGW and OpenVMS usage. I (Philip Hazel)
+have no knowledge of Windows or VMS sytems and how their libraries work. The
+items in the PCRE Makefile that relate to anything other than Unix-like systems
+have been contributed by PCRE users. There are some other comments and files in
+the Contrib directory on the ftp site that you may find useful. See
+
+  ftp://ftp.csx.cam.ac.uk/pub/software/programming/pcre/Contrib
+
+If you want to compile PCRE for a non-Unix system (or perhaps, more strictly,
+for a system that does not support "configure" and "make" files), note that
+PCRE consists entirely of code written in Standard C, and so should compile
+successfully on any system that has a Standard C compiler and library.
+
+
+GENERIC INSTRUCTIONS
+
+The following are generic comments about building PCRE. The interspersed
+indented commands are suggestions from Mark Tetrode as to which commands you
+might use on a Windows system to build a static library.
+
+(1) Copy or rename the file config.in as config.h, and change the macros that
+define HAVE_STRERROR and HAVE_MEMMOVE to define them as 1 rather than 0.
+Unfortunately, because of the way Unix autoconf works, the default setting has
+to be 0. You may also want to make changes to other macros in config.h. In
+particular, if you want to force a specific value for newline, you can define
+the NEWLINE macro. The default is to use '\n', thereby using whatever value
+your compiler gives to '\n'.
+
+  rem Mark Tetrode's commands
+  copy config.in config.h
+  rem Use write, because notepad cannot handle UNIX files. Change values.
+  write config.h
+
+(2) Copy or rename the file pcre.in as pcre.h, and change the macro definitions
+for PCRE_MAJOR, PCRE_MINOR, and PCRE_DATE near its start to the values set in
+configure.in.
+
+  rem Mark Tetrode's commands
+  copy pcre.in pcre.h
+  rem Read values from configure.in
+  write configure.in
+  rem Change values
+  write pcre.h
+
+(3) Compile dftables.c as a stand-alone program, and then run it with
+the single argument "chartables.c". This generates a set of standard
+character tables and writes them to that file.
+
+  rem Mark Tetrode's commands
+  rem Compile & run
+  cl -DSUPPORT_UTF8 dftables.c
+  dftables.exe > chartables.c
+
+(4) Compile maketables.c, get.c, study.c and pcre.c and link them all
+together into an object library in whichever form your system keeps such
+libraries. This is the pcre library (chartables.c is included by means of an
+#include directive). If your system has static and shared libraries, you may
+have to do this once for each type.
+
+  rem Mark Tetrode's commands, for a static library
+  rem Compile & lib
+  cl -DSUPPORT_UTF8 -DPOSIX_MALLOC_THRESHOLD=10 /c maketables.c get.c study.c pcre.c
+  lib /OUT:pcre.lib maketables.obj get.obj study.obj pcre.obj
+
+(5) Similarly, compile pcreposix.c and link it (on its own) as the pcreposix
+library.
+
+  rem Mark Tetrode's commands, for a static library
+  rem Compile & lib
+  cl -DSUPPORT_UTF8 -DPOSIX_MALLOC_THRESHOLD=10 /c pcreposix.c
+  lib /OUT:pcreposix.lib pcreposix.obj
+
+(6) Compile the test program pcretest.c. This needs the functions in the
+pcre and pcreposix libraries when linking.
+
+  rem Mark Tetrode's commands
+  rem compile & link
+  cl pcretest.c pcre.lib pcreposix.lib
+
+(7) Run pcretest on the testinput files in the testdata directory, and check
+that the output matches the corresponding testoutput files. You must use the
+-i option when checking testinput2. Note that the supplied files are in Unix
+format, with just LF characters as line terminators. You may need to edit them
+to change this if your system uses a different convention.
+
+  rem Mark Tetrode's commands
+  rem Make a change, i.e. space, backspace, and save again - do this for all
+  rem to change UNIX to Win, \n to \n\r
+  write testoutput1
+  write testoutput2
+  write testoutput3
+  write testoutput4
+  write testoutput5
+  pcretest testdata\testinput1 testdata\myoutput1
+  windiff testdata\testoutput1 testdata\myoutput1
+  pcretest -i testdata\testinput2 testdata\myoutput2
+  windiff testdata\testoutput2 testdata\myoutput2
+  pcretest testdata\testinput3 testdata\myoutput3
+  windiff testdata\testoutput3 testdata\myoutput3
+  pcretest testdata\testinput4 testdata\myoutput4
+  windiff testdata\testoutput4 testdata\myoutput4
+  pcretest testdata\testinput5 testdata\myoutput5
+  windiff testdata\testoutput5 testdata\myoutput5
+
+
+FURTHER REMARKS
+
+If you have a system without "configure" but where you can use a Makefile, edit
+Makefile.in to create Makefile, substituting suitable values for the variables
+at the head of the file.
+
+Some help in building a Win32 DLL of PCRE in GnuWin32 environments was
+contributed by Paul Sokolovsky. These environments are Mingw32
+(http://www.xraylith.wisc.edu/~khan/software/gnu-win32/) and CygWin
+(http://sourceware.cygnus.com/cygwin/). Paul comments:
+
+  For CygWin, set CFLAGS=-mno-cygwin, and do 'make dll'. You'll get
+  pcre.dll (containing pcreposix also), libpcre.dll.a, and dynamically
+  linked pgrep and pcretest. If you have /bin/sh, run RunTest (three
+  main test go ok, locale not supported).
+
+Changes to do MinGW with autoconf 2.50 were supplied by Fred Cox
+<sailorFred at yahoo.com>, who comments as follows:
+
+  If you are using the PCRE DLL, the normal Unix style configure && make &&
+  make check && make install should just work[*]. If you want to statically
+  link against the .a file, you must define PCRE_STATIC before including
+  pcre.h, otherwise the pcre_malloc and pcre_free exported functions will be
+  declared __declspec(dllimport), with hilarious results.  See the configure.in
+  and pcretest.c for how it is done for the static test.
+
+  Also, there will only be a libpcre.la, not a libpcreposix.la, as you
+  would expect from the Unix version. The single DLL includes the pcreposix
+  interface.
+
+[*] But note that the supplied test files are in Unix format, with just LF
+characters as line terminators. You will have to edit them to change to CR LF
+terminators.
+
+A script for building PCRE using Borland's C++ compiler for use with VPASCAL
+was contributed by Alexander Tokarev. It is called makevp.bat.
+
+These are some further comments about Win32 builds from Mark Evans. They
+were contributed before Fred Cox's changes were made, so it is possible that
+they may no longer be relevant.
+
+"The documentation for Win32 builds is a bit shy.  Under MSVC6 I
+followed their instructions to the letter, but there were still
+some things missing.
+
+(1) Must #define STATIC for entire project if linking statically.
+    (I see no reason to use DLLs for code this compact.)  This of
+    course is a project setting in MSVC under Preprocessor.
+
+(2) Missing some #ifdefs relating to the function pointers
+    pcre_malloc and pcre_free.  See my solution below.  (The stubs
+    may not be mandatory but they made me feel better.)"
+
+=========================
+#ifdef _WIN32
+#include <malloc.h>
+
+void* malloc_stub(size_t N)
+{ return malloc(N); }
+void free_stub(void* p)
+{ free(p); }
+void *(*pcre_malloc)(size_t) = &malloc_stub;
+void  (*pcre_free)(void *) = &free_stub;
+
+#else
+
+void *(*pcre_malloc)(size_t) = malloc;
+void  (*pcre_free)(void *) = free;
+
+#endif
+=========================
+
+
+BUILDING PCRE ON OPENVMS
+
+Dan Mooney sent the following comments about building PCRE on OpenVMS:
+
+"It was quite easy to compile and link the library. I don't have a formal
+make file but the attached file [reproduced below] contains the OpenVMS DCL
+commands I used to build the library. I had to add #define
+POSIX_MALLOC_THRESHOLD 10 to pcre.h since it was not defined anywhere.
+
+The library was built on:
+O/S: HP OpenVMS v7.3-1
+Compiler: Compaq C v6.5-001-48BCD
+Linker: vA13-01
+
+The test results did not match 100% due to the issues you mention in your
+documentation regarding isprint(), iscntrl(), isgraph() and ispunct(). I
+modified some of the character tables temporarily and was able to get the
+results to match. Tests using the fr locale did not match since I don't have
+that locale loaded. The study size was always reported to be 3 less than the
+value in the standard test output files."
+
+=========================
+$! This DCL procedure builds PCRE on OpenVMS
+$!
+$! I followed the instructions in the non-unix-use file in the distribution.
+$!
+$ COMPILE == "CC/LIST/NOMEMBER_ALIGNMENT/PREFIX_LIBRARY_ENTRIES=ALL_ENTRIES
+$ COMPILE DFTABLES.C
+$ LINK/EXE=DFTABLES.EXE DFTABLES.OBJ
+$ RUN DFTABLES.EXE/OUTPUT=CHARTABLES.C
+$ COMPILE MAKETABLES.C
+$ COMPILE GET.C
+$ COMPILE STUDY.C
+$! I had to set POSIX_MALLOC_THRESHOLD to 10 in PCRE.H since the symbol
+$! did not seem to be defined anywhere.
+$! I edited pcre.h and added #DEFINE SUPPORT_UTF8 to enable UTF8 support.
+$ COMPILE PCRE.C
+$ LIB/CREATE PCRE MAKETABLES.OBJ, GET.OBJ, STUDY.OBJ, PCRE.OBJ
+$! I had to set POSIX_MALLOC_THRESHOLD to 10 in PCRE.H since the symbol
+$! did not seem to be defined anywhere.
+$ COMPILE PCREPOSIX.C
+$ LIB/CREATE PCREPOSIX PCREPOSIX.OBJ
+$ COMPILE PCRETEST.C
+$ LINK/EXE=PCRETEST.EXE PCRETEST.OBJ, PCRE/LIB, PCREPOSIX/LIB
+$! C programs that want access to command line arguments must be
+$! defined as a symbol
+$ PCRETEST :== "$ SYS$ROADSUSERS:[DMOONEY.REGEXP]PCRETEST.EXE"
+$! Arguments must be enclosed in quotes.
+$ PCRETEST "-C"
+$! Test results:
+$!
+$!   The test results did not match 100%. The functions isprint(), iscntrl(),
+$!   isgraph() and ispunct() on OpenVMS must not produce the same results
+$!   as the system that built the test output files provided with the
+$!   distribution.
+$!
+$!   The study size did not match and was always 3 less on OpenVMS.
+$!
+$!   Locale could not be set to fr
+$!
+=========================
+
+****

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/NWGNUmakefile
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/NWGNUmakefile	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/NWGNUmakefile	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,267 @@
+#
+# NWGNUmakefile for DfTables.nlm (Apache2)
+# Declare the sub-directories to be built here
+#
+
+SUBDIRS = \
+		$(EOLIST) 
+
+#
+# Get the 'head' of the build environment.  This includes default targets and
+# paths to tools
+#
+
+include $(APR_WORK)\build\NWGNUhead.inc
+
+PCRE		= $(AP_WORK)/srclib/pcre
+
+#
+# build this level's files
+
+FILES_prebuild_headers = \
+	$(PCRE)/config.h \
+	$(PCRE)/pcre.h \
+	$(EOLIST) 
+	
+$(PCRE)/%.h: $(subst /,\,$(PCRE))\%.hw
+	@echo Creating $(subst /,\,$@)
+	copy $< $(subst /,\,$(PCRE))\$(@F)
+
+#
+# Make sure all needed macro's are defined
+#
+
+#
+# These directories will be at the beginning of the include list, followed by
+# INCDIRS
+#
+XINCDIRS	+= \
+			$(AP_WORK)/os/netware \
+			$(APR)/include/arch/netware \
+			$(EOLIST)
+
+#
+# These flags will come after CFLAGS
+#
+XCFLAGS		+= \
+			$(EOLIST)
+
+#
+# These defines will come after DEFINES
+#
+XDEFINES	+= \
+			$(EOLIST)
+
+#
+# These flags will be added to the link.opt file
+#
+XLFLAGS		+= \
+			$(EOLIST)
+
+#
+# These values will be appended to the correct variables based on the value of
+# RELEASE
+#
+ifeq "$(RELEASE)" "debug"
+XINCDIRS	+= \
+			$(EOLIST)
+
+XCFLAGS		+= \
+			$(EOLIST)
+
+XDEFINES	+= \
+			$(EOLIST)
+
+XLFLAGS		+= \
+			$(EOLIST)
+endif
+
+ifeq "$(RELEASE)" "noopt"
+XINCDIRS	+= \
+			$(EOLIST)
+
+XCFLAGS		+= \
+			$(EOLIST)
+
+XDEFINES	+= \
+			$(EOLIST)
+
+XLFLAGS		+= \
+			$(EOLIST)
+endif
+
+ifeq "$(RELEASE)" "release"
+XINCDIRS	+= \
+			$(EOLIST)
+
+XCFLAGS		+= \
+			$(EOLIST)
+
+XDEFINES	+= \
+			$(EOLIST)
+
+XLFLAGS		+= \
+			$(EOLIST)
+endif
+
+#
+# These are used by the link target if an NLM is being generated
+# This is used by the link 'name' directive to name the nlm.  If left blank
+# TARGET_nlm (see below) will be used.
+#
+NLM_NAME		= dftables
+
+#
+# This is used by the link '-desc ' directive. 
+# If left blank, NLM_NAME will be used.
+#
+NLM_DESCRIPTION	= Generate character tables
+
+#$(FILES_prebuild_headers)
+# This is used by the '-threadname' directive.  If left blank,
+# NLM_NAME Thread will be used.
+#
+NLM_THREAD_NAME	= dftables
+
+#
+# If this is specified, it will override VERSION value in 
+# $(APR_WORK)\build\NWGNUenvironment.inc
+#
+NLM_VERSION		= 1,0,0
+
+#
+# If this is specified, it will override the default of 64K
+#
+NLM_STACK_SIZE	= 8192
+
+#
+# If this is specified it will be used by the link '-entry' directive
+#
+NLM_ENTRY_SYM	=_LibCPrelude 
+
+#
+# If this is specified it will be used by the link '-exit' directive
+#
+NLM_EXIT_SYM	=_LibCPostlude 
+
+#
+# If this is specified it will be used by the link '-check' directive
+#
+NLM_CHECK_SYM	=
+
+#
+# If this is specified it will be used by the link '-flags' directive
+#
+NLM_FLAGS		= PSEUDOPREEMPTION
+ 
+#
+# If this is specified it will be linked in with the XDCData option in the def 
+# file instead of the default of $(APR)/misc/netware/apr.xdc.  XDCData can 
+# be disabled by setting APACHE_UNIPROC in the environment
+#
+XDCDATA         = 
+
+#
+# Declare all target files (you must add your files here)
+#
+
+#
+# If there is an NLM target, put it here
+#
+TARGET_nlm = \
+$(OBJDIR)/dftables.nlm \
+	$(EOLIST)
+
+#
+# If there is an LIB target, put it here
+#
+TARGET_lib = \
+	$(EOLIST)
+
+#
+# These are the OBJ files needed to create the NLM target above.
+# Paths must all use the '/' character
+#
+FILES_nlm_objs = \
+	$(FILES_prebuild_headers) \
+	$(OBJDIR)/dftables.o \
+	$(EOLIST)
+
+#
+# These are the LIB files needed to create the NLM target above.
+# These will be added as a library command in the link.opt file.
+#
+FILES_nlm_libs = \
+	libcpre.o \
+	$(EOLIST)
+
+#
+# These are the modules that the above NLM target depends on to load.
+# These will be added as a module command in the link.opt file.
+#
+FILES_nlm_modules = \
+	Libc \
+	$(EOLIST)
+
+#
+# If the nlm has a msg file, put it's path here
+#
+FILE_nlm_msg =
+ 
+#
+# If the nlm has a hlp file put it's path here
+#
+FILE_nlm_hlp =
+
+#
+# If this is specified, it will override $(NWOS)\copyright.txt.
+#
+FILE_nlm_copyright =
+
+#
+# Any additional imports go here
+#
+FILES_nlm_Ximports = \
+	@libc.imp \
+	$(EOLIST)
+ 
+#   
+# Any symbols exported to here
+#
+FILES_nlm_exports = \
+	$(EOLIST)
+	
+#   
+# These are the OBJ files needed to create the LIB target above.
+# Paths must all use the '/' character
+#
+FILES_lib_objs = \
+	$(EOLIST)
+
+#
+# implement targets and dependancies (leave this section alone)
+#
+
+libs :: $(OBJDIR) $(TARGET_lib)
+
+nlms :: libs $(TARGET_nlm)
+
+#
+# Updated this target to create necessary directories and copy files to the 
+# correct place.  (See $(APR_WORK)\build\NWGNUhead.inc for examples)
+#
+install :: nlms FORCE
+
+#
+# Any specialized rules here
+#
+
+
+#
+# Include the 'tail' makefile that has targets that depend on variables defined
+# in this makefile
+#
+
+include $(APR_WORK)\build\NWGNUtail.inc
+
+# End of NWGNUmakefile for DfTables.nlm (Apache2)

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/README
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/README	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/README	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,427 @@
+README file for PCRE (Perl-compatible regular expression library)
+-----------------------------------------------------------------
+
+The latest release of PCRE is always available from
+
+  ftp://ftp.csx.cam.ac.uk/pub/software/programming/pcre/pcre-xxx.tar.gz
+
+Please read the NEWS file if you are upgrading from a previous release.
+
+PCRE has its own native API, but a set of "wrapper" functions that are based on
+the POSIX API are also supplied in the library libpcreposix. Note that this
+just provides a POSIX calling interface to PCRE: the regular expressions
+themselves still follow Perl syntax and semantics. The header file
+for the POSIX-style functions is called pcreposix.h. The official POSIX name is
+regex.h, but I didn't want to risk possible problems with existing files of
+that name by distributing it that way. To use it with an existing program that
+uses the POSIX API, it will have to be renamed or pointed at by a link.
+
+If you are using the POSIX interface to PCRE and there is already a POSIX regex
+library installed on your system, you must take care when linking programs to
+ensure that they link with PCRE's libpcreposix library. Otherwise they may pick
+up the "real" POSIX functions of the same name.
+
+
+Documentation for PCRE
+----------------------
+
+If you install PCRE in the normal way, you will end up with an installed set of
+man pages whose names all start with "pcre". The one that is called "pcre"
+lists all the others. In addition to these man pages, the PCRE documentation is
+supplied in two other forms; however, as there is no standard place to install
+them, they are left in the doc directory of the unpacked source distribution.
+These forms are:
+
+  1. Files called doc/pcre.txt, doc/pcregrep.txt, and doc/pcretest.txt. The
+     first of these is a concatenation of the text forms of all the section 3
+     man pages except those that summarize individual functions. The other two
+     are the text forms of the section 1 man pages for the pcregrep and
+     pcretest commands. Text forms are provided for ease of scanning with text
+     editors or similar tools.
+
+  2. A subdirectory called doc/html contains all the documentation in HTML
+     form, hyperlinked in various ways, and rooted in a file called
+     doc/index.html.
+
+
+Contributions by users of PCRE
+------------------------------
+
+You can find contributions from PCRE users in the directory
+
+  ftp://ftp.csx.cam.ac.uk/pub/software/programming/pcre/Contrib
+
+where there is also a README file giving brief descriptions of what they are.
+Several of them provide support for compiling PCRE on various flavours of
+Windows systems (I myself do not use Windows). Some are complete in themselves;
+others are pointers to URLs containing relevant files.
+
+
+Building PCRE on a Unix-like system
+-----------------------------------
+
+To build PCRE on a Unix-like system, first run the "configure" command from the
+PCRE distribution directory, with your current directory set to the directory
+where you want the files to be created. This command is a standard GNU
+"autoconf" configuration script, for which generic instructions are supplied in
+INSTALL.
+
+Most commonly, people build PCRE within its own distribution directory, and in
+this case, on many systems, just running "./configure" is sufficient, but the
+usual methods of changing standard defaults are available. For example:
+
+CFLAGS='-O2 -Wall' ./configure --prefix=/opt/local
+
+specifies that the C compiler should be run with the flags '-O2 -Wall' instead
+of the default, and that "make install" should install PCRE under /opt/local
+instead of the default /usr/local.
+
+If you want to build in a different directory, just run "configure" with that
+directory as current. For example, suppose you have unpacked the PCRE source
+into /source/pcre/pcre-xxx, but you want to build it in /build/pcre/pcre-xxx:
+
+cd /build/pcre/pcre-xxx
+/source/pcre/pcre-xxx/configure
+
+There are some optional features that can be included or omitted from the PCRE
+library. You can read more about them in the pcrebuild man page.
+
+. If you want to make use of the support for UTF-8 character strings in PCRE,
+  you must add --enable-utf8 to the "configure" command. Without it, the code
+  for handling UTF-8 is not included in the library. (Even when included, it
+  still has to be enabled by an option at run time.)
+
+. If, in addition to support for UTF-8 character strings, you want to include
+  support for the \P, \p, and \X sequences that recognize Unicode character
+  properties, you must add --enable-unicode-properties to the "configure"
+  command. This adds about 90K to the size of the library (in the form of a
+  property table); only the basic two-letter properties such as Lu are
+  supported.
+
+. You can build PCRE to recognized CR or NL as the newline character, instead
+  of whatever your compiler uses for "\n", by adding --newline-is-cr or
+  --newline-is-nl to the "configure" command, respectively. Only do this if you
+  really understand what you are doing. On traditional Unix-like systems, the
+  newline character is NL.
+
+. When called via the POSIX interface, PCRE uses malloc() to get additional
+  storage for processing capturing parentheses if there are more than 10 of
+  them. You can increase this threshold by setting, for example,
+
+  --with-posix-malloc-threshold=20
+
+  on the "configure" command.
+
+. PCRE has a counter which can be set to limit the amount of resources it uses.
+  If the limit is exceeded during a match, the match fails. The default is ten
+  million. You can change the default by setting, for example,
+
+  --with-match-limit=500000
+
+  on the "configure" command. This is just the default; individual calls to
+  pcre_exec() can supply their own value. There is discussion on the pcreapi
+  man page.
+
+. The default maximum compiled pattern size is around 64K. You can increase
+  this by adding --with-link-size=3 to the "configure" command. You can
+  increase it even more by setting --with-link-size=4, but this is unlikely
+  ever to be necessary. If you build PCRE with an increased link size, test 2
+  (and 5 if you are using UTF-8) will fail. Part of the output of these tests
+  is a representation of the compiled pattern, and this changes with the link
+  size.
+
+. You can build PCRE so that its match() function does not call itself
+  recursively. Instead, it uses blocks of data from the heap via special
+  functions pcre_stack_malloc() and pcre_stack_free() to save data that would
+  otherwise be saved on the stack. To build PCRE like this, use
+
+  --disable-stack-for-recursion
+
+  on the "configure" command. PCRE runs more slowly in this mode, but it may be
+  necessary in environments with limited stack sizes.
+
+The "configure" script builds seven files:
+
+. pcre.h is build by copying pcre.in and making substitutions
+. Makefile is built by copying Makefile.in and making substitutions.
+. config.h is built by copying config.in and making substitutions.
+. pcre-config is built by copying pcre-config.in and making substitutions.
+. libpcre.pc is data for the pkg-config command, built from libpcre.pc.in
+. libtool is a script that builds shared and/or static libraries
+. RunTest is a script for running tests
+
+Once "configure" has run, you can run "make". It builds two libraries called
+libpcre and libpcreposix, a test program called pcretest, and the pcregrep
+command. You can use "make install" to copy these, the public header files
+pcre.h and pcreposix.h, and the man pages to appropriate live directories on
+your system, in the normal way.
+
+
+Retrieving configuration information on Unix-like systems
+---------------------------------------------------------
+
+Running "make install" also installs the command pcre-config, which can be used
+to recall information about the PCRE configuration and installation. For
+example:
+
+  pcre-config --version
+
+prints the version number, and
+
+  pcre-config --libs
+
+outputs information about where the library is installed. This command can be
+included in makefiles for programs that use PCRE, saving the programmer from
+having to remember too many details.
+
+The pkg-config command is another system for saving and retrieving information
+about installed libraries. Instead of separate commands for each library, a
+single command is used. For example:
+
+  pkg-config --cflags pcre
+
+The data is held in *.pc files that are installed in a directory called
+pkgconfig.
+
+
+Shared libraries on Unix-like systems
+-------------------------------------
+
+The default distribution builds PCRE as two shared libraries and two static
+libraries, as long as the operating system supports shared libraries. Shared
+library support relies on the "libtool" script which is built as part of the
+"configure" process.
+
+The libtool script is used to compile and link both shared and static
+libraries. They are placed in a subdirectory called .libs when they are newly
+built. The programs pcretest and pcregrep are built to use these uninstalled
+libraries (by means of wrapper scripts in the case of shared libraries). When
+you use "make install" to install shared libraries, pcregrep and pcretest are
+automatically re-built to use the newly installed shared libraries before being
+installed themselves. However, the versions left in the source directory still
+use the uninstalled libraries.
+
+To build PCRE using static libraries only you must use --disable-shared when
+configuring it. For example:
+
+./configure --prefix=/usr/gnu --disable-shared
+
+Then run "make" in the usual way. Similarly, you can use --disable-static to
+build only shared libraries.
+
+
+Cross-compiling on a Unix-like system
+-------------------------------------
+
+You can specify CC and CFLAGS in the normal way to the "configure" command, in
+order to cross-compile PCRE for some other host. However, during the building
+process, the dftables.c source file is compiled *and run* on the local host, in
+order to generate the default character tables (the chartables.c file). It
+therefore needs to be compiled with the local compiler, not the cross compiler.
+You can do this by specifying CC_FOR_BUILD (and if necessary CFLAGS_FOR_BUILD)
+when calling the "configure" command. If they are not specified, they default
+to the values of CC and CFLAGS.
+
+
+Building on non-Unix systems
+----------------------------
+
+For a non-Unix system, read the comments in the file NON-UNIX-USE, though if
+the system supports the use of "configure" and "make" you may be able to build
+PCRE in the same way as for Unix systems.
+
+PCRE has been compiled on Windows systems and on Macintoshes, but I don't know
+the details because I don't use those systems. It should be straightforward to
+build PCRE on any system that has a Standard C compiler, because it uses only
+Standard C functions.
+
+
+Testing PCRE
+------------
+
+To test PCRE on a Unix system, run the RunTest script that is created by the
+configuring process. (This can also be run by "make runtest", "make check", or
+"make test".) For other systems, see the instructions in NON-UNIX-USE.
+
+The script runs the pcretest test program (which is documented in its own man
+page) on each of the testinput files (in the testdata directory) in turn,
+and compares the output with the contents of the corresponding testoutput file.
+A file called testtry is used to hold the main output from pcretest
+(testsavedregex is also used as a working file). To run pcretest on just one of
+the test files, give its number as an argument to RunTest, for example:
+
+  RunTest 2
+
+The first file can also be fed directly into the perltest script to check that
+Perl gives the same results. The only difference you should see is in the first
+few lines, where the Perl version is given instead of the PCRE version.
+
+The second set of tests check pcre_fullinfo(), pcre_info(), pcre_study(),
+pcre_copy_substring(), pcre_get_substring(), pcre_get_substring_list(), error
+detection, and run-time flags that are specific to PCRE, as well as the POSIX
+wrapper API. It also uses the debugging flag to check some of the internals of
+pcre_compile().
+
+If you build PCRE with a locale setting that is not the standard C locale, the
+character tables may be different (see next paragraph). In some cases, this may
+cause failures in the second set of tests. For example, in a locale where the
+isprint() function yields TRUE for characters in the range 128-255, the use of
+[:isascii:] inside a character class defines a different set of characters, and
+this shows up in this test as a difference in the compiled code, which is being
+listed for checking. Where the comparison test output contains [\x00-\x7f] the
+test will contain [\x00-\xff], and similarly in some other cases. This is not a
+bug in PCRE.
+
+The third set of tests checks pcre_maketables(), the facility for building a
+set of character tables for a specific locale and using them instead of the
+default tables. The tests make use of the "fr_FR" (French) locale. Before
+running the test, the script checks for the presence of this locale by running
+the "locale" command. If that command fails, or if it doesn't include "fr_FR"
+in the list of available locales, the third test cannot be run, and a comment
+is output to say why. If running this test produces instances of the error
+
+  ** Failed to set locale "fr_FR"
+
+in the comparison output, it means that locale is not available on your system,
+despite being listed by "locale". This does not mean that PCRE is broken.
+
+The fourth test checks the UTF-8 support. It is not run automatically unless
+PCRE is built with UTF-8 support. To do this you must set --enable-utf8 when
+running "configure". This file can be also fed directly to the perltest script,
+provided you are running Perl 5.8 or higher. (For Perl 5.6, a small patch,
+commented in the script, can be be used.)
+
+The fifth test checks error handling with UTF-8 encoding, and internal UTF-8
+features of PCRE that are not relevant to Perl.
+
+The sixth and final test checks the support for Unicode character properties.
+It it not run automatically unless PCRE is built with Unicode property support.
+To to this you must set --enable-unicode-properties when running "configure".
+
+
+Character tables
+----------------
+
+PCRE uses four tables for manipulating and identifying characters whose values
+are less than 256. The final argument of the pcre_compile() function is a
+pointer to a block of memory containing the concatenated tables. A call to
+pcre_maketables() can be used to generate a set of tables in the current
+locale. If the final argument for pcre_compile() is passed as NULL, a set of
+default tables that is built into the binary is used.
+
+The source file called chartables.c contains the default set of tables. This is
+not supplied in the distribution, but is built by the program dftables
+(compiled from dftables.c), which uses the ANSI C character handling functions
+such as isalnum(), isalpha(), isupper(), islower(), etc. to build the table
+sources. This means that the default C locale which is set for your system will
+control the contents of these default tables. You can change the default tables
+by editing chartables.c and then re-building PCRE. If you do this, you should
+probably also edit Makefile to ensure that the file doesn't ever get
+re-generated.
+
+The first two 256-byte tables provide lower casing and case flipping functions,
+respectively. The next table consists of three 32-byte bit maps which identify
+digits, "word" characters, and white space, respectively. These are used when
+building 32-byte bit maps that represent character classes.
+
+The final 256-byte table has bits indicating various character types, as
+follows:
+
+    1   white space character
+    2   letter
+    4   decimal digit
+    8   hexadecimal digit
+   16   alphanumeric or '_'
+  128   regular expression metacharacter or binary zero
+
+You should not alter the set of characters that contain the 128 bit, as that
+will cause PCRE to malfunction.
+
+
+Manifest
+--------
+
+The distribution should contain the following files:
+
+(A) The actual source files of the PCRE library functions and their
+    headers:
+
+  dftables.c            auxiliary program for building chartables.c
+
+  get.c                 )
+  maketables.c          )
+  study.c               ) source of the functions
+  pcre.c                )   in the library
+  pcreposix.c           )
+  printint.c            )
+
+  ucp.c                 )
+  ucp.h                 ) source for the code that is used for
+  ucpinternal.h         )   Unicode property handling
+  ucptable.c            )
+  ucptypetable.c        )
+
+  pcre.in               "source" for the header for the external API; pcre.h
+                          is built from this by "configure"
+  pcreposix.h           header for the external POSIX wrapper API
+  internal.h            header for internal use
+  config.in             template for config.h, which is built by configure
+
+(B) Auxiliary files:
+
+  AUTHORS               information about the author of PCRE
+  ChangeLog             log of changes to the code
+  INSTALL               generic installation instructions
+  LICENCE               conditions for the use of PCRE
+  COPYING               the same, using GNU's standard name
+  Makefile.in           template for Unix Makefile, which is built by configure
+  NEWS                  important changes in this release
+  NON-UNIX-USE          notes on building PCRE on non-Unix systems
+  README                this file
+  RunTest.in            template for a Unix shell script for running tests
+  config.guess          ) files used by libtool,
+  config.sub            )   used only when building a shared library
+  configure             a configuring shell script (built by autoconf)
+  configure.in          the autoconf input used to build configure
+  doc/Tech.Notes        notes on the encoding
+  doc/*.3               man page sources for the PCRE functions
+  doc/*.1               man page sources for pcregrep and pcretest
+  doc/html/*            HTML documentation
+  doc/pcre.txt          plain text version of the man pages
+  doc/pcretest.txt      plain text documentation of test program
+  doc/perltest.txt      plain text documentation of Perl test program
+  install-sh            a shell script for installing files
+  libpcre.pc.in         "source" for libpcre.pc for pkg-config
+  ltmain.sh             file used to build a libtool script
+  mkinstalldirs         script for making install directories
+  pcretest.c            comprehensive test program
+  pcredemo.c            simple demonstration of coding calls to PCRE
+  perltest              Perl test program
+  pcregrep.c            source of a grep utility that uses PCRE
+  pcre-config.in        source of script which retains PCRE information
+  testdata/testinput1   test data, compatible with Perl
+  testdata/testinput2   test data for error messages and non-Perl things
+  testdata/testinput3   test data for locale-specific tests
+  testdata/testinput4   test data for UTF-8 tests compatible with Perl
+  testdata/testinput5   test data for other UTF-8 tests
+  testdata/testinput6   test data for Unicode property support tests
+  testdata/testoutput1  test results corresponding to testinput1
+  testdata/testoutput2  test results corresponding to testinput2
+  testdata/testoutput3  test results corresponding to testinput3
+  testdata/testoutput4  test results corresponding to testinput4
+  testdata/testoutput5  test results corresponding to testinput5
+  testdata/testoutput6  test results corresponding to testinput6
+
+(C) Auxiliary files for Win32 DLL
+
+  dll.mk
+  libpcre.def
+  libpcreposix.def
+  pcre.def
+
+(D) Auxiliary file for VPASCAL
+
+  makevp.bat
+
+Philip Hazel <ph10 at cam.ac.uk>
+September 2004

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/RunTest.in
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/RunTest.in	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/RunTest.in	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,192 @@
+#! /bin/sh
+
+# This file is generated by configure from RunTest.in. Make any changes
+# to that file.
+
+# Run PCRE tests
+
+cf=diff
+testdata=@top_srcdir@/testdata
+
+# Select which tests to run; if no selection, run all
+
+do1=no
+do2=no
+do3=no
+do4=no
+do5=no
+do6=no
+
+while [ $# -gt 0 ] ; do
+  case $1 in
+    1) do1=yes;;
+    2) do2=yes;;
+    3) do3=yes;;
+    4) do4=yes;;
+    5) do5=yes;; 
+    6) do6=yes;; 
+    *) echo "Unknown test number $1"; exit 1;;
+  esac
+  shift
+done
+
+if [ "@LINK_SIZE@" != "" -a "@LINK_SIZE@" != "-DLINK_SIZE=2" ] ; then
+  if [ $do2 = yes ] ; then
+    echo "Can't run test 2 with an internal link size other than 2"
+    exit 1  
+  fi   
+  if [ $do5 = yes ] ; then
+    echo "Can't run test 5 with an internal link size other than 2"
+    exit 1  
+  fi   
+  if [ $do6 = yes ] ; then
+    echo "Can't run test 6 with an internal link size other than 2"
+    exit 1  
+  fi   
+fi
+
+if [ "@UTF8@" = "" ] ; then
+  if [ $do4 = yes ] ; then
+    echo "Can't run test 4 because UTF-8 support is not configured"
+    exit 1
+  fi   
+  if [ $do5 = yes ] ; then
+    echo "Can't run test 5 because UTF-8 support is not configured"
+    exit 1
+  fi   
+  if [ $do6 = yes ] ; then
+    echo "Can't run test 6 because UTF-8 support is not configured"
+    exit 1
+  fi   
+fi    
+
+if [ "@UCP@" = "" ] ; then
+  if [ $do6 = yes ] ; then
+    echo "Can't run test 6 because Unicode property support is not configured"
+    exit 1
+  fi
+fi      
+
+if [ $do1 = no -a $do2 = no -a $do3 = no -a $do4 = no -a \
+     $do5 = no -a $do6 = no ] ; then
+  do1=yes
+  do2=yes 
+  do3=yes
+  if [ "@UTF8@" != "" ] ; then do4=yes; fi
+  if [ "@UTF8@" != "" ] ; then do5=yes; fi
+  if [ "@UTF8@" != "" -a "@UCP@" != "" ] ; then do6=yes; fi
+fi
+
+# Show which release
+
+./pcretest /dev/null
+
+# Primary test, Perl-compatible
+
+if [ $do1 = yes ] ; then
+  echo "Test 1: main functionality (Perl compatible)"
+  ./pcretest $testdata/testinput1 testtry
+  if [ $? = 0 ] ; then
+    $cf testtry $testdata/testoutput1
+    if [ $? != 0 ] ; then exit 1; fi
+    echo " " 
+  else exit 1
+  fi
+fi
+
+# PCRE tests that are not Perl-compatible - API & error tests, mostly
+
+if [ $do2 = yes ] ; then
+  if [ "@LINK_SIZE@" = "" -o "@LINK_SIZE@" = "-DLINK_SIZE=2" ] ; then   
+    echo "Test 2: API and error handling (not Perl compatible)"
+    ./pcretest -i $testdata/testinput2 testtry
+    if [ $? = 0 ] ; then
+      $cf testtry $testdata/testoutput2
+      if [ $? != 0 ] ; then exit 1; fi
+    else exit 1
+    fi
+  else
+    echo Test 2 skipped for link size other than 2 \(@LINK_SIZE@\)    
+  fi   
+fi
+
+if [ $do1 = yes -a $do2 = yes ] ; then
+  echo " " 
+  echo "The two main tests ran OK"
+  echo " " 
+fi
+
+# Locale-specific tests, provided the "fr_FR" locale is available
+
+if [ $do3 = yes ] ; then
+  locale -a | grep '^fr_FR$' >/dev/null
+  if [ $? -eq 0 ] ; then
+    echo "Test 3: locale-specific features (using 'fr_FR' locale)"
+    ./pcretest $testdata/testinput3 testtry
+    if [ $? = 0 ] ; then
+      $cf testtry $testdata/testoutput3
+      if [ $? != 0 ] ; then 
+        echo " "
+        echo "Locale test did not run entirely successfully."
+        echo "This usually means that there is a problem with the locale"
+        echo "settings rather than a bug in PCRE."    
+      else
+      echo "Locale test ran OK" 
+      fi 
+      echo " " 
+    else exit 1
+    fi
+  else
+    echo "Cannot test locale-specific features - 'fr_FR' locale not found,"
+    echo "or the \"locale\" command is not available to check for it."
+    echo " " 
+  fi
+fi
+
+# Additional tests for UTF8 support
+
+if [ $do4 = yes ] ; then
+  echo "Test 4: UTF-8 support (Perl compatible)"
+  ./pcretest $testdata/testinput4 testtry 
+  if [ $? = 0 ] ; then
+    $cf testtry $testdata/testoutput4
+    if [ $? != 0 ] ; then exit 1; fi
+  else exit 1
+  fi
+  echo "UTF8 test ran OK"
+  echo " "
+fi
+
+if [ $do5 = yes ] ; then
+  if [ "@LINK_SIZE@" = "" -o "@LINK_SIZE@" = "-DLINK_SIZE=2" ] ; then   
+    echo "Test 5: API and internals for UTF-8 support (not Perl compatible)"
+    ./pcretest $testdata/testinput5 testtry 
+    if [ $? = 0 ] ; then
+      $cf testtry $testdata/testoutput5
+      if [ $? != 0 ] ; then exit 1; fi
+    else exit 1
+    fi
+    echo "UTF8 internals test ran OK"
+    echo " "
+  else
+    echo Test 5 skipped for link size other than 2 \(@LINK_SIZE@\)    
+  fi   
+fi
+
+if [ $do6 = yes ] ; then
+  if [ "@LINK_SIZE@" = "" -o "@LINK_SIZE@" = "-DLINK_SIZE=2" ] ; then   
+    echo "Test 6: Unicode property support"
+    ./pcretest $testdata/testinput6 testtry 
+    if [ $? = 0 ] ; then
+      $cf testtry $testdata/testoutput6
+      if [ $? != 0 ] ; then exit 1; fi
+    else exit 1
+    fi
+    echo "Unicode properties test ran OK"
+    echo " "
+  else   
+    echo Test 6 skipped for link size other than 2 \(@LINK_SIZE@\)    
+  fi   
+fi
+
+# End

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/config.hw
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/config.hw	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/config.hw	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,107 @@
+
+/* On Unix systems config.in is converted by configure into config.h. PCRE is
+written in Standard C, but there are a few non-standard things it can cope
+with, allowing it to run on SunOS4 and other "close to standard" systems.
+
+On a non-Unix system you should just copy this file into config.h, and set up
+the macros the way you need them. You should normally change the definitions of
+HAVE_STRERROR and HAVE_MEMMOVE to 1. Unfortunately, because of the way autoconf
+works, these cannot be made the defaults. If your system has bcopy() and not
+memmove(), change the definition of HAVE_BCOPY instead of HAVE_MEMMOVE. If your
+system has neither bcopy() nor memmove(), leave them both as 0; an emulation
+function will be used. */
+
+/* If you are compiling for a system that uses EBCDIC instead of ASCII
+character codes, define this macro as 1. On systems that can use "configure",
+this can be done via --enable-ebcdic. */
+
+#ifndef EBCDIC
+#define EBCDIC 0
+#endif
+
+/* If you are compiling for a system that needs some magic to be inserted
+before the definition of an exported function, define this macro to contain the
+relevant magic. It apears at the start of every exported function. */
+
+#define EXPORT
+
+/* Define to empty if the "const" keyword does not work. */
+
+#undef const
+
+/* Define to "unsigned" if <stddef.h> doesn't define size_t. */
+
+#undef size_t
+
+/* The following two definitions are mainly for the benefit of SunOS4, which
+doesn't have the strerror() or memmove() functions that should be present in
+all Standard C libraries. The macros HAVE_STRERROR and HAVE_MEMMOVE should
+normally be defined with the value 1 for other systems, but unfortunately we
+can't make this the default because "configure" files generated by autoconf
+will only change 0 to 1; they won't change 1 to 0 if the functions are not
+found. */
+
+#define HAVE_STRERROR 1
+#define HAVE_MEMMOVE  1
+
+/* There are some non-Unix systems that don't even have bcopy(). If this macro
+is false, an emulation is used. If HAVE_MEMMOVE is set to 1, the value of
+HAVE_BCOPY is not relevant. */
+
+#define HAVE_BCOPY 0
+
+/* The value of NEWLINE determines the newline character. The default is to
+leave it up to the compiler, but some sites want to force a particular value.
+On Unix systems, "configure" can be used to override this default. */
+
+#ifndef NEWLINE
+#define NEWLINE '\n'
+#endif
+
+/* The value of LINK_SIZE determines the number of bytes used to store
+links as offsets within the compiled regex. The default is 2, which allows for
+compiled patterns up to 64K long. This covers the vast majority of cases.
+However, PCRE can also be compiled to use 3 or 4 bytes instead. This allows for
+longer patterns in extreme cases. On Unix systems, "configure" can be used to
+override this default. */
+
+#ifndef LINK_SIZE
+#define LINK_SIZE   2
+#endif
+
+/* The value of MATCH_LIMIT determines the default number of times the match()
+function can be called during a single execution of pcre_exec(). (There is a
+runtime method of setting a different limit.) The limit exists in order to
+catch runaway regular expressions that take for ever to determine that they do
+not match. The default is set very large so that it does not accidentally catch
+legitimate cases. On Unix systems, "configure" can be used to override this
+default default. */
+
+#ifndef MATCH_LIMIT
+#define MATCH_LIMIT 10000000
+#endif
+
+/* When calling PCRE via the POSIX interface, additional working storage is
+required for holding the pointers to capturing substrings because PCRE requires
+three integers per substring, whereas the POSIX interface provides only two. If
+the number of expected substrings is small, the wrapper function uses space on
+the stack, because this is faster than using malloc() for each call. The
+threshold above which the stack is no longer use is defined by POSIX_MALLOC_
+THRESHOLD. On Unix systems, "configure" can be used to override this default.
+*/
+
+#ifndef POSIX_MALLOC_THRESHOLD
+#define POSIX_MALLOC_THRESHOLD 10
+#endif
+
+/* PCRE uses recursive function calls to handle backtracking while matching.
+This can sometimes be a problem on systems that have stacks of limited size.
+Define NO_RECURSE to get a version that doesn't use recursion in the match()
+function; instead it creates its own stack by steam using pcre_recurse_malloc
+to get memory. For more detail, see comments and other stuff just above the
+match() function. On Unix systems, "configure" can be used to set this in the
+Makefile (use --disable-stack-for-recursion). */
+
+/* #define NO_RECURSE */
+
+/* End */

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/config.in
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/config.in	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/config.in	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,107 @@
+
+/* On Unix systems config.in is converted by configure into config.h. PCRE is
+written in Standard C, but there are a few non-standard things it can cope
+with, allowing it to run on SunOS4 and other "close to standard" systems.
+
+On a non-Unix system you should just copy this file into config.h, and set up
+the macros the way you need them. You should normally change the definitions of
+HAVE_STRERROR and HAVE_MEMMOVE to 1. Unfortunately, because of the way autoconf
+works, these cannot be made the defaults. If your system has bcopy() and not
+memmove(), change the definition of HAVE_BCOPY instead of HAVE_MEMMOVE. If your
+system has neither bcopy() nor memmove(), leave them both as 0; an emulation
+function will be used. */
+
+/* If you are compiling for a system that uses EBCDIC instead of ASCII
+character codes, define this macro as 1. On systems that can use "configure",
+this can be done via --enable-ebcdic. */
+
+#ifndef EBCDIC
+#define EBCDIC 0
+#endif
+
+/* If you are compiling for a system that needs some magic to be inserted
+before the definition of an exported function, define this macro to contain the
+relevant magic. It apears at the start of every exported function. */
+
+#define EXPORT
+
+/* Define to empty if the "const" keyword does not work. */
+
+#undef const
+
+/* Define to "unsigned" if <stddef.h> doesn't define size_t. */
+
+#undef size_t
+
+/* The following two definitions are mainly for the benefit of SunOS4, which
+doesn't have the strerror() or memmove() functions that should be present in
+all Standard C libraries. The macros HAVE_STRERROR and HAVE_MEMMOVE should
+normally be defined with the value 1 for other systems, but unfortunately we
+can't make this the default because "configure" files generated by autoconf
+will only change 0 to 1; they won't change 1 to 0 if the functions are not
+found. */
+
+#define HAVE_STRERROR 0
+#define HAVE_MEMMOVE  0
+
+/* There are some non-Unix systems that don't even have bcopy(). If this macro
+is false, an emulation is used. If HAVE_MEMMOVE is set to 1, the value of
+HAVE_BCOPY is not relevant. */
+
+#define HAVE_BCOPY    0
+
+/* The value of NEWLINE determines the newline character. The default is to
+leave it up to the compiler, but some sites want to force a particular value.
+On Unix systems, "configure" can be used to override this default. */
+
+#ifndef NEWLINE
+#define NEWLINE '\n'
+#endif
+
+/* The value of LINK_SIZE determines the number of bytes used to store
+links as offsets within the compiled regex. The default is 2, which allows for
+compiled patterns up to 64K long. This covers the vast majority of cases.
+However, PCRE can also be compiled to use 3 or 4 bytes instead. This allows for
+longer patterns in extreme cases. On Unix systems, "configure" can be used to
+override this default. */
+
+#ifndef LINK_SIZE
+#define LINK_SIZE   2
+#endif
+
+/* The value of MATCH_LIMIT determines the default number of times the match()
+function can be called during a single execution of pcre_exec(). (There is a
+runtime method of setting a different limit.) The limit exists in order to
+catch runaway regular expressions that take for ever to determine that they do
+not match. The default is set very large so that it does not accidentally catch
+legitimate cases. On Unix systems, "configure" can be used to override this
+default default. */
+
+#ifndef MATCH_LIMIT
+#define MATCH_LIMIT 10000000
+#endif
+
+/* When calling PCRE via the POSIX interface, additional working storage is
+required for holding the pointers to capturing substrings because PCRE requires
+three integers per substring, whereas the POSIX interface provides only two. If
+the number of expected substrings is small, the wrapper function uses space on
+the stack, because this is faster than using malloc() for each call. The
+threshold above which the stack is no longer use is defined by POSIX_MALLOC_
+THRESHOLD. On Unix systems, "configure" can be used to override this default.
+*/
+
+#ifndef POSIX_MALLOC_THRESHOLD
+#define POSIX_MALLOC_THRESHOLD 10
+#endif
+
+/* PCRE uses recursive function calls to handle backtracking while matching.
+This can sometimes be a problem on systems that have stacks of limited size.
+Define NO_RECURSE to get a version that doesn't use recursion in the match()
+function; instead it creates its own stack by steam using pcre_recurse_malloc
+to get memory. For more detail, see comments and other stuff just above the
+match() function. On Unix systems, "configure" can be used to set this in the
+Makefile (use --disable-stack-for-recursion). */
+
+/* #define NO_RECURSE */
+
+/* End */

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/configure.in
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/configure.in	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/configure.in	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,185 @@
+dnl Process this file with autoconf to produce a configure script.
+
+dnl This is required at the start; the name is the name of a file
+dnl it should be seeing, to verify it is in the same directory.
+
+AC_INIT(dftables.c)
+
+dnl A safety precaution
+
+AC_PREREQ(2.57)
+
+dnl Arrange to build config.h from config.in. Note that pcre.h is
+dnl built differently, as it is just a "substitution" file.
+dnl Manual says this macro should come right after AC_INIT.
+AC_CONFIG_HEADER(config.h:config.in)
+
+dnl Provide the current PCRE version information. Do not use numbers
+dnl with leading zeros for the minor version, as they end up in a C
+dnl macro, and may be treated as octal constants. Stick to single
+dnl digits for minor numbers less than 10. There are unlikely to be
+dnl that many releases anyway.
+
+PCRE_MAJOR=5
+PCRE_MINOR=0
+PCRE_DATE=13-Sep-2004
+PCRE_VERSION=${PCRE_MAJOR}.${PCRE_MINOR}
+
+dnl Default values for miscellaneous macros
+
+POSIX_MALLOC_THRESHOLD=-DPOSIX_MALLOC_THRESHOLD=10
+
+dnl Provide versioning information for libtool shared libraries that
+dnl are built by default on Unix systems.
+
+PCRE_LIB_VERSION=0:1:0
+PCRE_POSIXLIB_VERSION=0:0:0
+
+dnl Checks for programs.
+
+AC_PROG_CC
+
+dnl Checks for header files.
+
+AC_HEADER_STDC
+AC_CHECK_HEADERS(limits.h)
+
+dnl Checks for typedefs, structures, and compiler characteristics.
+
+AC_C_CONST
+AC_TYPE_SIZE_T
+
+dnl Checks for library functions.
+
+AC_CHECK_FUNCS(bcopy memmove strerror)
+
+dnl Handle --enable-shared-libraries
+
+LIBTOOL=./libtool
+LIBSUFFIX=la
+AC_ARG_ENABLE(shared,
+[  --disable-shared        build PCRE as a static library],
+if test "$enableval" = "no"; then
+  LIBTOOL=
+  LIBSUFFIX=a
+fi
+)
+
+dnl Handle --enable-utf8
+
+AC_ARG_ENABLE(utf8,
+[  --enable-utf8           enable UTF8 support],
+if test "$enableval" = "yes"; then
+  UTF8=-DSUPPORT_UTF8
+fi
+)
+
+dnl Handle --enable-unicode-properties
+
+AC_ARG_ENABLE(unicode-properties,
+[  --enable-unicode-properties  enable Unicode properties support],
+if test "$enableval" = "yes"; then
+  UCP=-DSUPPORT_UCP
+fi
+)
+
+dnl Handle --enable-newline-is-cr
+
+AC_ARG_ENABLE(newline-is-cr,
+[  --enable-newline-is-cr  use CR as the newline character],
+if test "$enableval" = "yes"; then
+  NEWLINE=-DNEWLINE=13
+fi
+)
+
+dnl Handle --enable-newline-is-lf
+
+AC_ARG_ENABLE(newline-is-lf,
+[  --enable-newline-is-lf  use LF as the newline character],
+if test "$enableval" = "yes"; then
+  NEWLINE=-DNEWLINE=10
+fi
+)
+
+dnl Handle --enable-ebcdic
+
+AC_ARG_ENABLE(ebcdic,
+[  --enable-ebcdic         assume EBCDIC coding rather than ASCII],
+if test "$enableval" == "yes"; then
+  EBCDIC=-DEBCDIC=1
+fi
+)
+
+dnl Handle --disable-stack-for-recursion
+
+AC_ARG_ENABLE(stack-for-recursion,
+[  --disable-stack-for-recursion  disable use of stack recursion when matching],
+if test "$enableval" = "no"; then
+  NO_RECURSE=-DNO_RECURSE
+fi
+)
+
+dnl There doesn't seem to be a straightforward way of having parameters
+dnl that set values, other than fudging the --with thing. So that's what
+dnl I've done.
+
+dnl Handle --with-posix-malloc-threshold=n
+
+AC_ARG_WITH(posix-malloc-threshold,
+[  --with-posix-malloc-threshold=5  threshold for POSIX malloc usage],
+  POSIX_MALLOC_THRESHOLD=-DPOSIX_MALLOC_THRESHOLD=$withval
+)
+
+dnl Handle --with-link-size=n
+
+AC_ARG_WITH(link-size,
+[  --with-link-size=2    internal link size (2, 3, or 4 allowed)],
+  LINK_SIZE=-DLINK_SIZE=$withval
+)
+
+dnl Handle --with-match_limit=n
+
+AC_ARG_WITH(match-limit,
+[  --with-match-limit=10000000      default limit on internal looping)],
+  MATCH_LIMIT=-DMATCH_LIMIT=$withval
+)
+
+dnl Unicode character property support implies UTF-8 support
+
+if test "$UCP" != "" ; then
+  UTF8=-DSUPPORT_UTF8
+fi
+
+dnl "Export" these variables
+
+AC_SUBST(BUILD_EXEEXT)
+AC_SUBST(BUILD_OBJEXT)
+AC_SUBST(CC_FOR_BUILD)
+AC_SUBST(CFLAGS_FOR_BUILD)
+AC_SUBST(EBCDIC)
+AC_SUBST(HAVE_MEMMOVE)
+AC_SUBST(HAVE_STRERROR)
+AC_SUBST(LIBTOOL)
+AC_SUBST(LIBSUFFIX)
+AC_SUBST(LINK_SIZE)
+AC_SUBST(MATCH_LIMIT)
+AC_SUBST(NEWLINE)
+AC_SUBST(NO_RECURSE)
+AC_SUBST(PCRE_MAJOR)
+AC_SUBST(PCRE_MINOR)
+AC_SUBST(PCRE_DATE)
+AC_SUBST(PCRE_VERSION)
+AC_SUBST(PCRE_LIB_VERSION)
+AC_SUBST(PCRE_POSIXLIB_VERSION)
+AC_SUBST(POSIX_MALLOC_THRESHOLD)
+AC_SUBST(UCP)
+AC_SUBST(UTF8)
+
+
+if test "x$enable_shared" = "xno" ; then
+    AC_DEFINE([PCRE_STATIC],[1],[to link statically])
+fi
+
+dnl This must be last; it determines what files are written as well as config.h
+AC_OUTPUT(Makefile pcre.h:pcre.in pcre-config,[chmod a+x pcre-config])
+

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/dftables.c
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/dftables.c	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/dftables.c	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,173 @@
+/*************************************************
+*      Perl-Compatible Regular Expressions       *
+*************************************************/
+
+/*
+PCRE is a library of functions to support regular expressions whose syntax
+and semantics are as close as possible to those of the Perl 5 language.
+
+Written by: Philip Hazel <ph10 at cam.ac.uk>
+
+           Copyright (c) 1997-2004 University of Cambridge
+
+-----------------------------------------------------------------------------
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice,
+      this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+
+    * Neither the name of the University of Cambridge nor the names of its
+      contributors may be used to endorse or promote products derived from
+      this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+-----------------------------------------------------------------------------
+*/
+
+
+/* This is a support program to generate the file chartables.c, containing
+character tables of various kinds. They are built according to the default C
+locale and used as the default tables by PCRE. Now that pcre_maketables is
+a function visible to the outside world, we make use of its code from here in
+order to be consistent. */
+
+#include <ctype.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "internal.h"
+
+#define DFTABLES          /* maketables.c notices this */
+#include "maketables.c"
+
+
+int main(int argc, char **argv)
+{
+int i;
+FILE *f;
+const unsigned char *tables = pcre_maketables();
+
+if (argc != 2)
+  {
+  fprintf(stderr, "dftables: one filename argument is required\n");
+  return 1;
+  }
+
+f = fopen(argv[1], "w");
+if (f == NULL)
+  {
+  fprintf(stderr, "dftables: failed to open %s for writing\n", argv[1]);
+  return 1;
+  }
+
+/* There are two fprintf() calls here, because gcc in pedantic mode complains
+about the very long string otherwise. */
+
+fprintf(f,
+  "/*************************************************\n"
+  "*      Perl-Compatible Regular Expressions       *\n"
+  "*************************************************/\n\n"
+  "/* This file is automatically written by the dftables auxiliary \n"
+  "program. If you edit it by hand, you might like to edit the Makefile to \n"
+  "prevent its ever being regenerated.\n\n");
+fprintf(f,
+  "This file is #included in the compilation of pcre.c to build the default\n"
+  "character tables which are used when no tables are passed to the compile\n"
+  "function. */\n\n"
+  "static unsigned char pcre_default_tables[] = {\n\n"
+  "/* This table is a lower casing table. */\n\n");
+
+fprintf(f, "  ");
+for (i = 0; i < 256; i++)
+  {
+  if ((i & 7) == 0 && i != 0) fprintf(f, "\n  ");
+  fprintf(f, "%3d", *tables++);
+  if (i != 255) fprintf(f, ",");
+  }
+fprintf(f, ",\n\n");
+
+fprintf(f, "/* This table is a case flipping table. */\n\n");
+
+fprintf(f, "  ");
+for (i = 0; i < 256; i++)
+  {
+  if ((i & 7) == 0 && i != 0) fprintf(f, "\n  ");
+  fprintf(f, "%3d", *tables++);
+  if (i != 255) fprintf(f, ",");
+  }
+fprintf(f, ",\n\n");
+
+fprintf(f,
+  "/* This table contains bit maps for various character classes.\n"
+  "Each map is 32 bytes long and the bits run from the least\n"
+  "significant end of each byte. The classes that have their own\n"
+  "maps are: space, xdigit, digit, upper, lower, word, graph\n"
+  "print, punct, and cntrl. Other classes are built from combinations. */\n\n");
+
+fprintf(f, "  ");
+for (i = 0; i < cbit_length; i++)
+  {
+  if ((i & 7) == 0 && i != 0)
+    {
+    if ((i & 31) == 0) fprintf(f, "\n");
+    fprintf(f, "\n  ");
+    }
+  fprintf(f, "0x%02x", *tables++);
+  if (i != cbit_length - 1) fprintf(f, ",");
+  }
+fprintf(f, ",\n\n");
+
+fprintf(f,
+  "/* This table identifies various classes of character by individual bits:\n"
+  "  0x%02x   white space character\n"
+  "  0x%02x   letter\n"
+  "  0x%02x   decimal digit\n"
+  "  0x%02x   hexadecimal digit\n"
+  "  0x%02x   alphanumeric or '_'\n"
+  "  0x%02x   regular expression metacharacter or binary zero\n*/\n\n",
+  ctype_space, ctype_letter, ctype_digit, ctype_xdigit, ctype_word,
+  ctype_meta);
+
+fprintf(f, "  ");
+for (i = 0; i < 256; i++)
+  {
+  if ((i & 7) == 0 && i != 0)
+    {
+    fprintf(f, " /* ");
+    if (isprint(i-8)) fprintf(f, " %c -", i-8);
+      else fprintf(f, "%3d-", i-8);
+    if (isprint(i-1)) fprintf(f, " %c ", i-1);
+      else fprintf(f, "%3d", i-1);
+    fprintf(f, " */\n  ");
+    }
+  fprintf(f, "0x%02x", *tables++);
+  if (i != 255) fprintf(f, ",");
+  }
+
+fprintf(f, "};/* ");
+if (isprint(i-8)) fprintf(f, " %c -", i-8);
+  else fprintf(f, "%3d-", i-8);
+if (isprint(i-1)) fprintf(f, " %c ", i-1);
+  else fprintf(f, "%3d", i-1);
+fprintf(f, " */\n\n/* End of chartables.c */\n");
+
+fclose(f);
+return 0;
+}
+
+/* End of dftables.c */

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/dftables.dsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/dftables.dsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/dftables.dsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,165 @@
+# Microsoft Developer Studio Project File - Name="dftables" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=dftables - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE 
+!MESSAGE NMAKE /f "dftables.mak".
+!MESSAGE 
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE 
+!MESSAGE NMAKE /f "dftables.mak" CFG="dftables - Win32 Debug"
+!MESSAGE 
+!MESSAGE Possible choices for configuration are:
+!MESSAGE 
+!MESSAGE "dftables - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "dftables - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE 
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF  "$(CFG)" == "dftables - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir ""
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir ""
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MD /W3 /O2 /D "_WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /Fd"Release\dftables" /FD /c
+# ADD CPP /nologo /MD /W3 /wd:4996 /O2 /D "_WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /Fd"Release\dftables" /FD /c
+# ADD BASE RSC /l 0x809 /d "NDEBUG"
+# ADD RSC /l 0x809 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib /nologo /subsystem:console /pdb:"Release\dftables.pdb"
+# SUBTRACT BASE LINK32 /pdb:none
+# ADD LINK32 kernel32.lib /nologo /subsystem:console /pdb:"Release\dftables.pdb" /opt:ref
+# SUBTRACT LINK32 /pdb:none
+
+!ELSEIF  "$(CFG)" == "dftables - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir ""
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir ""
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MDd /W3 /EHsc /Zi /Od /D "_WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /Fd"Debug\dftables" /FD /c
+# ADD CPP /nologo /MDd /W3 /wd:4996 /EHsc /Zi /Od /D "_WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /Fd"Debug\dftables" /FD /c
+# ADD BASE RSC /l 0x809 /d "_DEBUG"
+# ADD RSC /l 0x809 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib /nologo /subsystem:console /incremental:no /pdb:"Debug\dftables.pdb" /debug /pdbtype:sept
+# SUBTRACT BASE LINK32 /pdb:none
+# ADD LINK32 kernel32.lib /nologo /subsystem:console /incremental:no /pdb:"Debug\dftables.pdb" /debug
+# SUBTRACT LINK32 /pdb:none
+
+!ENDIF 
+
+# Begin Target
+
+# Name "dftables - Win32 Release"
+# Name "dftables - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=.\dftables.c
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hw"
+# Begin Source File
+
+SOURCE=.\config.hw
+
+!IF  "$(CFG)" == "dftables - Win32 Release"
+
+# Begin Custom Build - Creating pcre config.h from config.hw 
+InputPath=.\config.hw
+
+".\config.h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+	type .\config.hw > .\config.h
+	
+# End Custom Build
+
+!ELSEIF  "$(CFG)" == "dftables - Win32 Debug"
+
+# Begin Custom Build - Creating pcre config.h from config.hw 
+InputPath=.\config.hw
+
+".\config.h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+	type .\config.hw > .\config.h
+	
+# End Custom Build
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\internal.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\maketables.c
+# PROP Exclude_From_Build 1
+# End Source File
+# Begin Source File
+
+SOURCE=.\pcre.hw
+
+!IF  "$(CFG)" == "dftables - Win32 Release"
+
+# Begin Custom Build - Creating pcre.h from pcre.hw 
+InputPath=.\pcre.hw
+
+".\pcre.h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+	type .\pcre.hw > .\pcre.h
+	
+# End Custom Build
+
+!ELSEIF  "$(CFG)" == "dftables - Win32 Debug"
+
+# Begin Custom Build - Creating pcre.h from pcre.hw 
+InputPath=.\pcre.hw
+
+".\pcre.h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+	type .\pcre.hw > .\pcre.h
+	
+# End Custom Build
+
+!ENDIF 
+
+# End Source File
+# End Group
+# End Target
+# End Project

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/dll.mk
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/dll.mk	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/dll.mk	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,60 @@
+# dll.mk - auxilary Makefile to easy build dll's for mingw32 target
+# ver. 0.6 of 1999-03-25
+#
+# Homepage of this makefile - http://www.is.lg.ua/~paul/devel/
+# Homepage of original mingw32 project -
+#		      http://www.fu.is.saga-u.ac.jp/~colin/gcc.html
+#
+# How to use:
+# This makefile can:
+# 1. Create automatical .def file from list of objects
+# 2. Create .dll from objects and .def file, either automatical, or your
+#    hand-written (maybe) file, which must have same basename as dll
+# WARNING! There MUST be object, which name match dll's name. Make sux.
+# 3. Create import library from .def (as for .dll, only its name required,
+#    not dll itself)
+#    By convention implibs for dll have .dll.a suffix, e.g. libstuff.dll.a
+#    Why not just libstuff.a? 'Cos that's name for static lib, ok?
+# Process divided into 3 phases because:
+# 1. Pre-existent .def possible
+# 2. Generating implib is enough time-consuming
+#
+# Variables:
+#   DLL_LDLIBS  - libs for linking dll
+#   DLL_LDFLAGS - flags for linking dll
+#
+# By using $(DLL_SUFFIX) instead of 'dll', e.g. stuff.$(DLL_SUFFIX)
+# you may help porting makefiles to other platforms
+#
+# Put this file in your make's include path (e.g. main include dir, for
+# more information see include section in make doc). Put in the beginning
+# of your own Makefile line "include dll.mk". Specify dependences, e.g.:
+#
+# Do all stuff in one step
+# libstuff.dll.a: $(OBJECTS) stuff.def
+# stuff.def: $(OBJECTS)
+#
+# Steps separated, pre-provided .def, link with user32
+#
+# DLL_LDLIBS=-luser32
+# stuff.dll: $(OBJECTS)
+# libstuff.dll.a: $(OBJECTS)
+
+
+DLLWRAP=dllwrap
+DLLTOOL=dlltool
+
+DLL_SUFFIX=dll
+
+.SUFFIXES: .o .$(DLL_SUFFIX)
+
+_%.def: %.o
+      $(DLLTOOL) --export-all --output-def $@ $^
+
+%.$(DLL_SUFFIX): %.o
+      $(DLLWRAP) --dllname $(notdir $@) --driver-name $(CC) --def $*.def -o $@ $(filter %.o,$^) $(DLL_LDFLAGS) $(DLL_LDLIBS)
+
+lib%.$(DLL_SUFFIX).a:%.def
+      $(DLLTOOL) --dllname $(notdir $*.dll) --def $< --output-lib $@
+
+# End

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/doc/README_httpd
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/doc/README_httpd	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/doc/README_httpd	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,6 @@
+The documentation directory has been omitted from this copy of PCRE
+inside the httpd codebase because it's huge--over a megabyte of PCRE docs.
+
+The PCRE documentation directory is available in unmodified form in the
+vendor branch.  You can access it via web browser or Subversion checkout at
+http://svn.apache.org/repos/asf/httpd/httpd/vendor/pcre/current/doc/

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/get.c
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/get.c	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/get.c	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,357 @@
+/*************************************************
+*      Perl-Compatible Regular Expressions       *
+*************************************************/
+
+/*
+This is a library of functions to support regular expressions whose syntax
+and semantics are as close as possible to those of the Perl 5 language. See
+the file Tech.Notes for some information on the internals.
+
+Written by: Philip Hazel <ph10 at cam.ac.uk>
+
+           Copyright (c) 1997-2003 University of Cambridge
+
+-----------------------------------------------------------------------------
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice,
+      this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+
+    * Neither the name of the University of Cambridge nor the names of its
+      contributors may be used to endorse or promote products derived from
+      this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+-----------------------------------------------------------------------------
+*/
+
+/* This module contains some convenience functions for extracting substrings
+from the subject string after a regex match has succeeded. The original idea
+for these functions came from Scott Wimer. */
+
+
+/* Include the internals header, which itself includes Standard C headers plus
+the external pcre header. */
+
+#include "internal.h"
+
+
+/*************************************************
+*           Find number for named string         *
+*************************************************/
+
+/* This function is used by the two extraction functions below, as well
+as being generally available.
+
+Arguments:
+  code        the compiled regex
+  stringname  the name whose number is required
+
+Returns:      the number of the named parentheses, or a negative number
+                (PCRE_ERROR_NOSUBSTRING) if not found
+*/
+
+int
+pcre_get_stringnumber(const pcre *code, const char *stringname)
+{
+int rc;
+int entrysize;
+int top, bot;
+uschar *nametable;
+
+if ((rc = pcre_fullinfo(code, NULL, PCRE_INFO_NAMECOUNT, &top)) != 0)
+  return rc;
+if (top <= 0) return PCRE_ERROR_NOSUBSTRING;
+
+if ((rc = pcre_fullinfo(code, NULL, PCRE_INFO_NAMEENTRYSIZE, &entrysize)) != 0)
+  return rc;
+if ((rc = pcre_fullinfo(code, NULL, PCRE_INFO_NAMETABLE, &nametable)) != 0)
+  return rc;
+
+bot = 0;
+while (top > bot)
+  {
+  int mid = (top + bot) / 2;
+  uschar *entry = nametable + entrysize*mid;
+  int c = strcmp(stringname, (char *)(entry + 2));
+  if (c == 0) return (entry[0] << 8) + entry[1];
+  if (c > 0) bot = mid + 1; else top = mid;
+  }
+
+return PCRE_ERROR_NOSUBSTRING;
+}
+
+
+
+/*************************************************
+*      Copy captured string to given buffer      *
+*************************************************/
+
+/* This function copies a single captured substring into a given buffer.
+Note that we use memcpy() rather than strncpy() in case there are binary zeros
+in the string.
+
+Arguments:
+  subject        the subject string that was matched
+  ovector        pointer to the offsets table
+  stringcount    the number of substrings that were captured
+                   (i.e. the yield of the pcre_exec call, unless
+                   that was zero, in which case it should be 1/3
+                   of the offset table size)
+  stringnumber   the number of the required substring
+  buffer         where to put the substring
+  size           the size of the buffer
+
+Returns:         if successful:
+                   the length of the copied string, not including the zero
+                   that is put on the end; can be zero
+                 if not successful:
+                   PCRE_ERROR_NOMEMORY (-6) buffer too small
+                   PCRE_ERROR_NOSUBSTRING (-7) no such captured substring
+*/
+
+int
+pcre_copy_substring(const char *subject, int *ovector, int stringcount,
+  int stringnumber, char *buffer, int size)
+{
+int yield;
+if (stringnumber < 0 || stringnumber >= stringcount)
+  return PCRE_ERROR_NOSUBSTRING;
+stringnumber *= 2;
+yield = ovector[stringnumber+1] - ovector[stringnumber];
+if (size < yield + 1) return PCRE_ERROR_NOMEMORY;
+memcpy(buffer, subject + ovector[stringnumber], yield);
+buffer[yield] = 0;
+return yield;
+}
+
+
+
+/*************************************************
+*   Copy named captured string to given buffer   *
+*************************************************/
+
+/* This function copies a single captured substring into a given buffer,
+identifying it by name.
+
+Arguments:
+  code           the compiled regex
+  subject        the subject string that was matched
+  ovector        pointer to the offsets table
+  stringcount    the number of substrings that were captured
+                   (i.e. the yield of the pcre_exec call, unless
+                   that was zero, in which case it should be 1/3
+                   of the offset table size)
+  stringname     the name of the required substring
+  buffer         where to put the substring
+  size           the size of the buffer
+
+Returns:         if successful:
+                   the length of the copied string, not including the zero
+                   that is put on the end; can be zero
+                 if not successful:
+                   PCRE_ERROR_NOMEMORY (-6) buffer too small
+                   PCRE_ERROR_NOSUBSTRING (-7) no such captured substring
+*/
+
+int
+pcre_copy_named_substring(const pcre *code, const char *subject, int *ovector,
+  int stringcount, const char *stringname, char *buffer, int size)
+{
+int n = pcre_get_stringnumber(code, stringname);
+if (n <= 0) return n;
+return pcre_copy_substring(subject, ovector, stringcount, n, buffer, size);
+}
+
+
+
+/*************************************************
+*      Copy all captured strings to new store    *
+*************************************************/
+
+/* This function gets one chunk of store and builds a list of pointers and all
+of the captured substrings in it. A NULL pointer is put on the end of the list.
+
+Arguments:
+  subject        the subject string that was matched
+  ovector        pointer to the offsets table
+  stringcount    the number of substrings that were captured
+                   (i.e. the yield of the pcre_exec call, unless
+                   that was zero, in which case it should be 1/3
+                   of the offset table size)
+  listptr        set to point to the list of pointers
+
+Returns:         if successful: 0
+                 if not successful:
+                   PCRE_ERROR_NOMEMORY (-6) failed to get store
+*/
+
+int
+pcre_get_substring_list(const char *subject, int *ovector, int stringcount,
+  const char ***listptr)
+{
+int i;
+int size = sizeof(char *);
+int double_count = stringcount * 2;
+char **stringlist;
+char *p;
+
+for (i = 0; i < double_count; i += 2)
+  size += sizeof(char *) + ovector[i+1] - ovector[i] + 1;
+
+stringlist = (char **)(pcre_malloc)(size);
+if (stringlist == NULL) return PCRE_ERROR_NOMEMORY;
+
+*listptr = (const char **)stringlist;
+p = (char *)(stringlist + stringcount + 1);
+
+for (i = 0; i < double_count; i += 2)
+  {
+  int len = ovector[i+1] - ovector[i];
+  memcpy(p, subject + ovector[i], len);
+  *stringlist++ = p;
+  p += len;
+  *p++ = 0;
+  }
+
+*stringlist = NULL;
+return 0;
+}
+
+
+
+/*************************************************
+*   Free store obtained by get_substring_list    *
+*************************************************/
+
+/* This function exists for the benefit of people calling PCRE from non-C
+programs that can call its functions, but not free() or (pcre_free)() directly.
+
+Argument:   the result of a previous pcre_get_substring_list()
+Returns:    nothing
+*/
+
+void
+pcre_free_substring_list(const char **pointer)
+{
+(pcre_free)((void *)pointer);
+}
+
+
+
+/*************************************************
+*      Copy captured string to new store         *
+*************************************************/
+
+/* This function copies a single captured substring into a piece of new
+store
+
+Arguments:
+  subject        the subject string that was matched
+  ovector        pointer to the offsets table
+  stringcount    the number of substrings that were captured
+                   (i.e. the yield of the pcre_exec call, unless
+                   that was zero, in which case it should be 1/3
+                   of the offset table size)
+  stringnumber   the number of the required substring
+  stringptr      where to put a pointer to the substring
+
+Returns:         if successful:
+                   the length of the string, not including the zero that
+                   is put on the end; can be zero
+                 if not successful:
+                   PCRE_ERROR_NOMEMORY (-6) failed to get store
+                   PCRE_ERROR_NOSUBSTRING (-7) substring not present
+*/
+
+int
+pcre_get_substring(const char *subject, int *ovector, int stringcount,
+  int stringnumber, const char **stringptr)
+{
+int yield;
+char *substring;
+if (stringnumber < 0 || stringnumber >= stringcount)
+  return PCRE_ERROR_NOSUBSTRING;
+stringnumber *= 2;
+yield = ovector[stringnumber+1] - ovector[stringnumber];
+substring = (char *)(pcre_malloc)(yield + 1);
+if (substring == NULL) return PCRE_ERROR_NOMEMORY;
+memcpy(substring, subject + ovector[stringnumber], yield);
+substring[yield] = 0;
+*stringptr = substring;
+return yield;
+}
+
+
+
+/*************************************************
+*   Copy named captured string to new store      *
+*************************************************/
+
+/* This function copies a single captured substring, identified by name, into
+new store.
+
+Arguments:
+  code           the compiled regex
+  subject        the subject string that was matched
+  ovector        pointer to the offsets table
+  stringcount    the number of substrings that were captured
+                   (i.e. the yield of the pcre_exec call, unless
+                   that was zero, in which case it should be 1/3
+                   of the offset table size)
+  stringname     the name of the required substring
+  stringptr      where to put the pointer
+
+Returns:         if successful:
+                   the length of the copied string, not including the zero
+                   that is put on the end; can be zero
+                 if not successful:
+                   PCRE_ERROR_NOMEMORY (-6) couldn't get memory
+                   PCRE_ERROR_NOSUBSTRING (-7) no such captured substring
+*/
+
+int
+pcre_get_named_substring(const pcre *code, const char *subject, int *ovector,
+  int stringcount, const char *stringname, const char **stringptr)
+{
+int n = pcre_get_stringnumber(code, stringname);
+if (n <= 0) return n;
+return pcre_get_substring(subject, ovector, stringcount, n, stringptr);
+}
+
+
+
+
+/*************************************************
+*       Free store obtained by get_substring     *
+*************************************************/
+
+/* This function exists for the benefit of people calling PCRE from non-C
+programs that can call its functions, but not free() or (pcre_free)() directly.
+
+Argument:   the result of a previous pcre_get_substring()
+Returns:    nothing
+*/
+
+void
+pcre_free_substring(const char *pointer)
+{
+(pcre_free)((void *)pointer);
+}
+
+/* End of get.c */

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/install-sh
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/install-sh	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/install-sh	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,251 @@
+#!/bin/sh
+#
+# install - install a program, script, or datafile
+# This comes from X11R5 (mit/util/scripts/install.sh).
+#
+# Copyright 1991 by the Massachusetts Institute of Technology
+#
+# Permission to use, copy, modify, distribute, and sell this software and its
+# documentation for any purpose is hereby granted without fee, provided that
+# the above copyright notice appear in all copies and that both that
+# copyright notice and this permission notice appear in supporting
+# documentation, and that the name of M.I.T. not be used in advertising or
+# publicity pertaining to distribution of the software without specific,
+# written prior permission.  M.I.T. makes no representations about the
+# suitability of this software for any purpose.  It is provided "as is"
+# without express or implied warranty.
+#
+# Calling this script install-sh is preferred over install.sh, to prevent
+# `make' implicit rules from creating a file called install from it
+# when there is no Makefile.
+#
+# This script is compatible with the BSD install script, but was written
+# from scratch.  It can only install one file at a time, a restriction
+# shared with many OS's install programs.
+
+
+# set DOITPROG to echo to test this script
+
+# Don't use :- since 4.3BSD and earlier shells don't like it.
+doit="${DOITPROG-}"
+
+
+# put in absolute paths if you don't have them in your path; or use env. vars.
+
+mvprog="${MVPROG-mv}"
+cpprog="${CPPROG-cp}"
+chmodprog="${CHMODPROG-chmod}"
+chownprog="${CHOWNPROG-chown}"
+chgrpprog="${CHGRPPROG-chgrp}"
+stripprog="${STRIPPROG-strip}"
+rmprog="${RMPROG-rm}"
+mkdirprog="${MKDIRPROG-mkdir}"
+
+transformbasename=""
+transform_arg=""
+instcmd="$mvprog"
+chmodcmd="$chmodprog 0755"
+chowncmd=""
+chgrpcmd=""
+stripcmd=""
+rmcmd="$rmprog -f"
+mvcmd="$mvprog"
+src=""
+dst=""
+dir_arg=""
+
+while [ x"$1" != x ]; do
+    case $1 in
+	-c) instcmd="$cpprog"
+	    shift
+	    continue;;
+
+	-d) dir_arg=true
+	    shift
+	    continue;;
+
+	-m) chmodcmd="$chmodprog $2"
+	    shift
+	    shift
+	    continue;;
+
+	-o) chowncmd="$chownprog $2"
+	    shift
+	    shift
+	    continue;;
+
+	-g) chgrpcmd="$chgrpprog $2"
+	    shift
+	    shift
+	    continue;;
+
+	-s) stripcmd="$stripprog"
+	    shift
+	    continue;;
+
+	-t=*) transformarg=`echo $1 | sed 's/-t=//'`
+	    shift
+	    continue;;
+
+	-b=*) transformbasename=`echo $1 | sed 's/-b=//'`
+	    shift
+	    continue;;
+
+	*)  if [ x"$src" = x ]
+	    then
+		src=$1
+	    else
+		# this colon is to work around a 386BSD /bin/sh bug
+		:
+		dst=$1
+	    fi
+	    shift
+	    continue;;
+    esac
+done
+
+if [ x"$src" = x ]
+then
+	echo "install:	no input file specified"
+	exit 1
+else
+	true
+fi
+
+if [ x"$dir_arg" != x ]; then
+	dst=$src
+	src=""
+	
+	if [ -d $dst ]; then
+		instcmd=:
+		chmodcmd=""
+	else
+		instcmd=mkdir
+	fi
+else
+
+# Waiting for this to be detected by the "$instcmd $src $dsttmp" command
+# might cause directories to be created, which would be especially bad 
+# if $src (and thus $dsttmp) contains '*'.
+
+	if [ -f $src -o -d $src ]
+	then
+		true
+	else
+		echo "install:  $src does not exist"
+		exit 1
+	fi
+	
+	if [ x"$dst" = x ]
+	then
+		echo "install:	no destination specified"
+		exit 1
+	else
+		true
+	fi
+
+# If destination is a directory, append the input filename; if your system
+# does not like double slashes in filenames, you may need to add some logic
+
+	if [ -d $dst ]
+	then
+		dst="$dst"/`basename $src`
+	else
+		true
+	fi
+fi
+
+## this sed command emulates the dirname command
+dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'`
+
+# Make sure that the destination directory exists.
+#  this part is taken from Noah Friedman's mkinstalldirs script
+
+# Skip lots of stat calls in the usual case.
+if [ ! -d "$dstdir" ]; then
+defaultIFS='	
+'
+IFS="${IFS-${defaultIFS}}"
+
+oIFS="${IFS}"
+# Some sh's can't handle IFS=/ for some reason.
+IFS='%'
+set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'`
+IFS="${oIFS}"
+
+pathcomp=''
+
+while [ $# -ne 0 ] ; do
+	pathcomp="${pathcomp}${1}"
+	shift
+
+	if [ ! -d "${pathcomp}" ] ;
+        then
+		$mkdirprog "${pathcomp}"
+	else
+		true
+	fi
+
+	pathcomp="${pathcomp}/"
+done
+fi
+
+if [ x"$dir_arg" != x ]
+then
+	$doit $instcmd $dst &&
+
+	if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi &&
+	if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi &&
+	if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi &&
+	if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi
+else
+
+# If we're going to rename the final executable, determine the name now.
+
+	if [ x"$transformarg" = x ] 
+	then
+		dstfile=`basename $dst`
+	else
+		dstfile=`basename $dst $transformbasename | 
+			sed $transformarg`$transformbasename
+	fi
+
+# don't allow the sed command to completely eliminate the filename
+
+	if [ x"$dstfile" = x ] 
+	then
+		dstfile=`basename $dst`
+	else
+		true
+	fi
+
+# Make a temp file name in the proper directory.
+
+	dsttmp=$dstdir/#inst.$$#
+
+# Move or copy the file name to the temp name
+
+	$doit $instcmd $src $dsttmp &&
+
+	trap "rm -f ${dsttmp}" 0 &&
+
+# and set any options; do chmod last to preserve setuid bits
+
+# If any of these fail, we abort the whole thing.  If we want to
+# ignore errors from any of these, just make sure not to ignore
+# errors from the above "$doit $instcmd $src $dsttmp" command.
+
+	if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi &&
+	if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi &&
+	if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi &&
+	if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi &&
+
+# Now rename the file to the real destination.
+
+	$doit $rmcmd -f $dstdir/$dstfile &&
+	$doit $mvcmd $dsttmp $dstdir/$dstfile 
+
+fi &&
+
+
+exit 0

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/internal.h
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/internal.h	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/internal.h	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,752 @@
+/*************************************************
+*      Perl-Compatible Regular Expressions       *
+*************************************************/
+
+
+/* This is a library of functions to support regular expressions whose syntax
+and semantics are as close as possible to those of the Perl 5 language. See
+the file doc/Tech.Notes for some information on the internals.
+
+Written by: Philip Hazel <ph10 at cam.ac.uk>
+
+           Copyright (c) 1997-2004 University of Cambridge
+
+-----------------------------------------------------------------------------
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice,
+      this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+
+    * Neither the name of the University of Cambridge nor the names of its
+      contributors may be used to endorse or promote products derived from
+      this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+-----------------------------------------------------------------------------
+*/
+
+/* This header contains definitions that are shared between the different
+modules, but which are not relevant to the outside. */
+
+/* Get the definitions provided by running "configure" */
+
+#include "config.h"
+
+/* Standard C headers plus the external interface definition. The only time
+setjmp and stdarg are used is when NO_RECURSE is set. */
+
+#include <ctype.h>
+#include <limits.h>
+#include <setjmp.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifndef PCRE_SPY
+#define PCRE_DEFINITION       /* Win32 __declspec(export) trigger for .dll */
+#endif
+
+/* We need to have types that specify unsigned 16-bit and 32-bit integers. We
+cannot determine these outside the compilation (e.g. by running a program as
+part of "configure") because PCRE is often cross-compiled for use on other
+systems. Instead we make use of the maximum sizes that are available at
+preprocessor time in standard C environments. */
+
+#if USHRT_MAX == 65535
+  typedef unsigned short pcre_uint16;
+#elif UINT_MAX == 65535
+  typedef unsigned int pcre_uint16;
+#else
+  #error Cannot determine a type for 16-bit unsigned integers
+#endif
+
+#if UINT_MAX == 4294967295
+  typedef unsigned int pcre_uint32;
+#elif ULONG_MAX == 4294967295
+  typedef unsigned long int pcre_uint32;
+#else
+  #error Cannot determine a type for 32-bit unsigned integers
+#endif
+
+/* All character handling must be done as unsigned characters. Otherwise there
+are problems with top-bit-set characters and functions such as isspace().
+However, we leave the interface to the outside world as char *, because that
+should make things easier for callers. We define a short type for unsigned char
+to save lots of typing. I tried "uchar", but it causes problems on Digital
+Unix, where it is defined in sys/types, so use "uschar" instead. */
+
+typedef unsigned char uschar;
+
+/* Include the public PCRE header */
+
+#include "pcre.h"
+
+/* When compiling for use with the Virtual Pascal compiler, these functions
+need to have their names changed. PCRE must be compiled with the -DVPCOMPAT
+option on the command line. */
+
+#ifdef VPCOMPAT
+#define strncmp(s1,s2,m) _strncmp(s1,s2,m)
+#define memcpy(d,s,n)    _memcpy(d,s,n)
+#define memmove(d,s,n)   _memmove(d,s,n)
+#define memset(s,c,n)    _memset(s,c,n)
+#else  /* VPCOMPAT */
+
+/* To cope with SunOS4 and other systems that lack memmove() but have bcopy(),
+define a macro for memmove() if HAVE_MEMMOVE is false, provided that HAVE_BCOPY
+is set. Otherwise, include an emulating function for those systems that have
+neither (there some non-Unix environments where this is the case). This assumes
+that all calls to memmove are moving strings upwards in store, which is the
+case in PCRE. */
+
+#if ! HAVE_MEMMOVE
+#undef  memmove        /* some systems may have a macro */
+#if HAVE_BCOPY
+#define memmove(a, b, c) bcopy(b, a, c)
+#else  /* HAVE_BCOPY */
+void *
+pcre_memmove(unsigned char *dest, const unsigned char *src, size_t n)
+{
+int i;
+dest += n;
+src += n;
+for (i = 0; i < n; ++i) *(--dest) =  *(--src);
+}
+#define memmove(a, b, c) pcre_memmove(a, b, c)
+#endif   /* not HAVE_BCOPY */
+#endif   /* not HAVE_MEMMOVE */
+#endif   /* not VPCOMPAT */
+
+
+/* PCRE keeps offsets in its compiled code as 2-byte quantities (always stored
+in big-endian order) by default. These are used, for example, to link from the
+start of a subpattern to its alternatives and its end. The use of 2 bytes per
+offset limits the size of the compiled regex to around 64K, which is big enough
+for almost everybody. However, I received a request for an even bigger limit.
+For this reason, and also to make the code easier to maintain, the storing and
+loading of offsets from the byte string is now handled by the macros that are
+defined here.
+
+The macros are controlled by the value of LINK_SIZE. This defaults to 2 in
+the config.h file, but can be overridden by using -D on the command line. This
+is automated on Unix systems via the "configure" command. */
+
+#if LINK_SIZE == 2
+
+#define PUT(a,n,d)   \
+  (a[n] = (d) >> 8), \
+  (a[(n)+1] = (d) & 255)
+
+#define GET(a,n) \
+  (((a)[n] << 8) | (a)[(n)+1])
+
+#define MAX_PATTERN_SIZE (1 << 16)
+
+
+#elif LINK_SIZE == 3
+
+#define PUT(a,n,d)       \
+  (a[n] = (d) >> 16),    \
+  (a[(n)+1] = (d) >> 8), \
+  (a[(n)+2] = (d) & 255)
+
+#define GET(a,n) \
+  (((a)[n] << 16) | ((a)[(n)+1] << 8) | (a)[(n)+2])
+
+#define MAX_PATTERN_SIZE (1 << 24)
+
+
+#elif LINK_SIZE == 4
+
+#define PUT(a,n,d)        \
+  (a[n] = (d) >> 24),     \
+  (a[(n)+1] = (d) >> 16), \
+  (a[(n)+2] = (d) >> 8),  \
+  (a[(n)+3] = (d) & 255)
+
+#define GET(a,n) \
+  (((a)[n] << 24) | ((a)[(n)+1] << 16) | ((a)[(n)+2] << 8) | (a)[(n)+3])
+
+#define MAX_PATTERN_SIZE (1 << 30)   /* Keep it positive */
+
+
+#else
+#error LINK_SIZE must be either 2, 3, or 4
+#endif
+
+
+/* Convenience macro defined in terms of the others */
+
+#define PUTINC(a,n,d)   PUT(a,n,d), a += LINK_SIZE
+
+
+/* PCRE uses some other 2-byte quantities that do not change when the size of
+offsets changes. There are used for repeat counts and for other things such as
+capturing parenthesis numbers in back references. */
+
+#define PUT2(a,n,d)   \
+  a[n] = (d) >> 8; \
+  a[(n)+1] = (d) & 255
+
+#define GET2(a,n) \
+  (((a)[n] << 8) | (a)[(n)+1])
+
+#define PUT2INC(a,n,d)  PUT2(a,n,d), a += 2
+
+
+/* In case there is no definition of offsetof() provided - though any proper
+Standard C system should have one. */
+
+#ifndef offsetof
+#define offsetof(p_type,field) ((size_t)&(((p_type *)0)->field))
+#endif
+
+
+/* These are the public options that can change during matching. */
+
+#define PCRE_IMS (PCRE_CASELESS|PCRE_MULTILINE|PCRE_DOTALL)
+
+/* Private options flags start at the most significant end of the four bytes,
+but skip the top bit so we can use ints for convenience without getting tangled
+with negative values. The public options defined in pcre.h start at the least
+significant end. Make sure they don't overlap, though now that we have expanded
+to four bytes, there is plenty of space. */
+
+#define PCRE_FIRSTSET      0x40000000  /* first_byte is set */
+#define PCRE_REQCHSET      0x20000000  /* req_byte is set */
+#define PCRE_STARTLINE     0x10000000  /* start after \n for multiline */
+#define PCRE_ICHANGED      0x08000000  /* i option changes within regex */
+#define PCRE_NOPARTIAL     0x04000000  /* can't use partial with this regex */
+
+/* Options for the "extra" block produced by pcre_study(). */
+
+#define PCRE_STUDY_MAPPED   0x01     /* a map of starting chars exists */
+
+/* Masks for identifying the public options which are permitted at compile
+time, run time or study time, respectively. */
+
+#define PUBLIC_OPTIONS \
+  (PCRE_CASELESS|PCRE_EXTENDED|PCRE_ANCHORED|PCRE_MULTILINE| \
+   PCRE_DOTALL|PCRE_DOLLAR_ENDONLY|PCRE_EXTRA|PCRE_UNGREEDY|PCRE_UTF8| \
+   PCRE_NO_AUTO_CAPTURE|PCRE_NO_UTF8_CHECK|PCRE_AUTO_CALLOUT)
+
+#define PUBLIC_EXEC_OPTIONS \
+  (PCRE_ANCHORED|PCRE_NOTBOL|PCRE_NOTEOL|PCRE_NOTEMPTY|PCRE_NO_UTF8_CHECK| \
+   PCRE_PARTIAL)
+
+#define PUBLIC_STUDY_OPTIONS 0   /* None defined */
+
+/* Magic number to provide a small check against being handed junk. */
+
+#define MAGIC_NUMBER  0x50435245UL   /* 'PCRE' */
+
+/* Negative values for the firstchar and reqchar variables */
+
+#define REQ_UNSET (-2)
+#define REQ_NONE  (-1)
+
+/* Flags added to firstbyte or reqbyte; a "non-literal" item is either a
+variable-length repeat, or a anything other than literal characters. */
+
+#define REQ_CASELESS 0x0100    /* indicates caselessness */
+#define REQ_VARY     0x0200    /* reqbyte followed non-literal item */
+
+/* Miscellaneous definitions */
+
+typedef int BOOL;
+
+#define FALSE   0
+#define TRUE    1
+
+/* Escape items that are just an encoding of a particular data value. Note that
+ESC_n is defined as yet another macro, which is set in config.h to either \n
+(the default) or \r (which some people want). */
+
+#ifndef ESC_e
+#define ESC_e 27
+#endif
+
+#ifndef ESC_f
+#define ESC_f '\f'
+#endif
+
+#ifndef ESC_n
+#define ESC_n NEWLINE
+#endif
+
+#ifndef ESC_r
+#define ESC_r '\r'
+#endif
+
+/* We can't officially use ESC_t because it is a POSIX reserved identifier
+(presumably because of all the others like size_t). */
+
+#ifndef ESC_tee
+#define ESC_tee '\t'
+#endif
+
+/* These are escaped items that aren't just an encoding of a particular data
+value such as \n. They must have non-zero values, as check_escape() returns
+their negation. Also, they must appear in the same order as in the opcode
+definitions below, up to ESC_z. There's a dummy for OP_ANY because it
+corresponds to "." rather than an escape sequence. The final one must be
+ESC_REF as subsequent values are used for \1, \2, \3, etc. There is are two
+tests in the code for an escape greater than ESC_b and less than ESC_Z to
+detect the types that may be repeated. These are the types that consume
+characters. If any new escapes are put in between that don't consume a
+character, that code will have to change. */
+
+enum { ESC_A = 1, ESC_G, ESC_B, ESC_b, ESC_D, ESC_d, ESC_S, ESC_s, ESC_W,
+       ESC_w, ESC_dum1, ESC_C, ESC_P, ESC_p, ESC_X, ESC_Z, ESC_z, ESC_E,
+       ESC_Q, ESC_REF };
+
+/* Flag bits and data types for the extended class (OP_XCLASS) for classes that
+contain UTF-8 characters with values greater than 255. */
+
+#define XCL_NOT    0x01    /* Flag: this is a negative class */
+#define XCL_MAP    0x02    /* Flag: a 32-byte map is present */
+
+#define XCL_END       0    /* Marks end of individual items */
+#define XCL_SINGLE    1    /* Single item (one multibyte char) follows */
+#define XCL_RANGE     2    /* A range (two multibyte chars) follows */
+#define XCL_PROP      3    /* Unicode property (one property code) follows */
+#define XCL_NOTPROP   4    /* Unicode inverted property (ditto) */
+
+
+/* Opcode table: OP_BRA must be last, as all values >= it are used for brackets
+that extract substrings. Starting from 1 (i.e. after OP_END), the values up to
+OP_EOD must correspond in order to the list of escapes immediately above.
+Note that whenever this list is updated, the two macro definitions that follow
+must also be updated to match. */
+
+enum {
+  OP_END,            /* 0 End of pattern */
+
+  /* Values corresponding to backslashed metacharacters */
+
+  OP_SOD,            /* 1 Start of data: \A */
+  OP_SOM,            /* 2 Start of match (subject + offset): \G */
+  OP_NOT_WORD_BOUNDARY,  /*  3 \B */
+  OP_WORD_BOUNDARY,      /*  4 \b */
+  OP_NOT_DIGIT,          /*  5 \D */
+  OP_DIGIT,              /*  6 \d */
+  OP_NOT_WHITESPACE,     /*  7 \S */
+  OP_WHITESPACE,         /*  8 \s */
+  OP_NOT_WORDCHAR,       /*  9 \W */
+  OP_WORDCHAR,           /* 10 \w */
+  OP_ANY,            /* 11 Match any character */
+  OP_ANYBYTE,        /* 12 Match any byte (\C); different to OP_ANY for UTF-8 */
+  OP_NOTPROP,        /* 13 \P (not Unicode property) */
+  OP_PROP,           /* 14 \p (Unicode property) */
+  OP_EXTUNI,         /* 15 \X (extended Unicode sequence */
+  OP_EODN,           /* 16 End of data or \n at end of data: \Z. */
+  OP_EOD,            /* 17 End of data: \z */
+
+  OP_OPT,            /* 18 Set runtime options */
+  OP_CIRC,           /* 19 Start of line - varies with multiline switch */
+  OP_DOLL,           /* 20 End of line - varies with multiline switch */
+  OP_CHAR,           /* 21 Match one character, casefully */
+  OP_CHARNC,         /* 22 Match one character, caselessly */
+  OP_NOT,            /* 23 Match anything but the following char */
+
+  OP_STAR,           /* 24 The maximizing and minimizing versions of */
+  OP_MINSTAR,        /* 25 all these opcodes must come in pairs, with */
+  OP_PLUS,           /* 26 the minimizing one second. */
+  OP_MINPLUS,        /* 27 This first set applies to single characters */
+  OP_QUERY,          /* 28 */
+  OP_MINQUERY,       /* 29 */
+  OP_UPTO,           /* 30 From 0 to n matches */
+  OP_MINUPTO,        /* 31 */
+  OP_EXACT,          /* 32 Exactly n matches */
+
+  OP_NOTSTAR,        /* 33 The maximizing and minimizing versions of */
+  OP_NOTMINSTAR,     /* 34 all these opcodes must come in pairs, with */
+  OP_NOTPLUS,        /* 35 the minimizing one second. */
+  OP_NOTMINPLUS,     /* 36 This set applies to "not" single characters */
+  OP_NOTQUERY,       /* 37 */
+  OP_NOTMINQUERY,    /* 38 */
+  OP_NOTUPTO,        /* 39 From 0 to n matches */
+  OP_NOTMINUPTO,     /* 40 */
+  OP_NOTEXACT,       /* 41 Exactly n matches */
+
+  OP_TYPESTAR,       /* 42 The maximizing and minimizing versions of */
+  OP_TYPEMINSTAR,    /* 43 all these opcodes must come in pairs, with */
+  OP_TYPEPLUS,       /* 44 the minimizing one second. These codes must */
+  OP_TYPEMINPLUS,    /* 45 be in exactly the same order as those above. */
+  OP_TYPEQUERY,      /* 46 This set applies to character types such as \d */
+  OP_TYPEMINQUERY,   /* 47 */
+  OP_TYPEUPTO,       /* 48 From 0 to n matches */
+  OP_TYPEMINUPTO,    /* 49 */
+  OP_TYPEEXACT,      /* 50 Exactly n matches */
+
+  OP_CRSTAR,         /* 51 The maximizing and minimizing versions of */
+  OP_CRMINSTAR,      /* 52 all these opcodes must come in pairs, with */
+  OP_CRPLUS,         /* 53 the minimizing one second. These codes must */
+  OP_CRMINPLUS,      /* 54 be in exactly the same order as those above. */
+  OP_CRQUERY,        /* 55 These are for character classes and back refs */
+  OP_CRMINQUERY,     /* 56 */
+  OP_CRRANGE,        /* 57 These are different to the three sets above. */
+  OP_CRMINRANGE,     /* 58 */
+
+  OP_CLASS,          /* 59 Match a character class, chars < 256 only */
+  OP_NCLASS,         /* 60 Same, but the bitmap was created from a negative
+                           class - the difference is relevant only when a UTF-8
+                           character > 255 is encountered. */
+
+  OP_XCLASS,         /* 61 Extended class for handling UTF-8 chars within the
+                           class. This does both positive and negative. */
+
+  OP_REF,            /* 62 Match a back reference */
+  OP_RECURSE,        /* 63 Match a numbered subpattern (possibly recursive) */
+  OP_CALLOUT,        /* 64 Call out to external function if provided */
+
+  OP_ALT,            /* 65 Start of alternation */
+  OP_KET,            /* 66 End of group that doesn't have an unbounded repeat */
+  OP_KETRMAX,        /* 67 These two must remain together and in this */
+  OP_KETRMIN,        /* 68 order. They are for groups the repeat for ever. */
+
+  /* The assertions must come before ONCE and COND */
+
+  OP_ASSERT,         /* 69 Positive lookahead */
+  OP_ASSERT_NOT,     /* 70 Negative lookahead */
+  OP_ASSERTBACK,     /* 71 Positive lookbehind */
+  OP_ASSERTBACK_NOT, /* 72 Negative lookbehind */
+  OP_REVERSE,        /* 73 Move pointer back - used in lookbehind assertions */
+
+  /* ONCE and COND must come after the assertions, with ONCE first, as there's
+  a test for >= ONCE for a subpattern that isn't an assertion. */
+
+  OP_ONCE,           /* 74 Once matched, don't back up into the subpattern */
+  OP_COND,           /* 75 Conditional group */
+  OP_CREF,           /* 76 Used to hold an extraction string number (cond ref) */
+
+  OP_BRAZERO,        /* 77 These two must remain together and in this */
+  OP_BRAMINZERO,     /* 78 order. */
+
+  OP_BRANUMBER,      /* 79 Used for extracting brackets whose number is greater
+                           than can fit into an opcode. */
+
+  OP_BRA             /* 80 This and greater values are used for brackets that
+                           extract substrings up to EXTRACT_BASIC_MAX. After
+                           that, use is made of OP_BRANUMBER. */
+};
+
+/* WARNING WARNING WARNING: There is an implicit assumption in pcre.c and
+study.c that all opcodes are less than 128 in value. This makes handling UTF-8
+character sequences easier. */
+
+/* The highest extraction number before we have to start using additional
+bytes. (Originally PCRE didn't have support for extraction counts highter than
+this number.) The value is limited by the number of opcodes left after OP_BRA,
+i.e. 255 - OP_BRA. We actually set it a bit lower to leave room for additional
+opcodes. */
+
+#define EXTRACT_BASIC_MAX  100
+
+
+/* This macro defines textual names for all the opcodes. There are used only
+for debugging, in pcre.c when DEBUG is defined, and also in pcretest.c. The
+macro is referenced only in printint.c. */
+
+#define OP_NAME_LIST \
+  "End", "\\A", "\\G", "\\B", "\\b", "\\D", "\\d",                \
+  "\\S", "\\s", "\\W", "\\w", "Any", "Anybyte",                   \
+  "notprop", "prop", "extuni",                                    \
+  "\\Z", "\\z",                                                   \
+  "Opt", "^", "$", "char", "charnc", "not",                       \
+  "*", "*?", "+", "+?", "?", "??", "{", "{", "{",                 \
+  "*", "*?", "+", "+?", "?", "??", "{", "{", "{",                 \
+  "*", "*?", "+", "+?", "?", "??", "{", "{", "{",                 \
+  "*", "*?", "+", "+?", "?", "??", "{", "{",                      \
+  "class", "nclass", "xclass", "Ref", "Recurse", "Callout",       \
+  "Alt", "Ket", "KetRmax", "KetRmin", "Assert", "Assert not",     \
+  "AssertB", "AssertB not", "Reverse", "Once", "Cond", "Cond ref",\
+  "Brazero", "Braminzero", "Branumber", "Bra"
+
+
+/* This macro defines the length of fixed length operations in the compiled
+regex. The lengths are used when searching for specific things, and also in the
+debugging printing of a compiled regex. We use a macro so that it can be
+incorporated both into pcre.c and pcretest.c without being publicly exposed.
+
+As things have been extended, some of these are no longer fixed lenths, but are
+minima instead. For example, the length of a single-character repeat may vary
+in UTF-8 mode. The code that uses this table must know about such things. */
+
+#define OP_LENGTHS \
+  1,                             /* End                                    */ \
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /* \A, \G, \B, \B, \D, \d, \S, \s, \W, \w */ \
+  1, 1,                          /* Any, Anybyte                           */ \
+  2, 2, 1,                       /* NOTPROP, PROP, EXTUNI                  */ \
+  1, 1, 2, 1, 1,                 /* \Z, \z, Opt, ^, $                      */ \
+  2,                             /* Char  - the minimum length             */ \
+  2,                             /* Charnc  - the minimum length           */ \
+  2,                             /* not                                    */ \
+  /* Positive single-char repeats                            ** These are  */ \
+  2, 2, 2, 2, 2, 2,              /* *, *?, +, +?, ?, ??      ** minima in  */ \
+  4, 4, 4,                       /* upto, minupto, exact     ** UTF-8 mode */ \
+  /* Negative single-char repeats - only for chars < 256                   */ \
+  2, 2, 2, 2, 2, 2,              /* NOT *, *?, +, +?, ?, ??                */ \
+  4, 4, 4,                       /* NOT upto, minupto, exact               */ \
+  /* Positive type repeats                                                 */ \
+  2, 2, 2, 2, 2, 2,              /* Type *, *?, +, +?, ?, ??               */ \
+  4, 4, 4,                       /* Type upto, minupto, exact              */ \
+  /* Character class & ref repeats                                         */ \
+  1, 1, 1, 1, 1, 1,              /* *, *?, +, +?, ?, ??                    */ \
+  5, 5,                          /* CRRANGE, CRMINRANGE                    */ \
+ 33,                             /* CLASS                                  */ \
+ 33,                             /* NCLASS                                 */ \
+  0,                             /* XCLASS - variable length               */ \
+  3,                             /* REF                                    */ \
+  1+LINK_SIZE,                   /* RECURSE                                */ \
+  2+2*LINK_SIZE,                 /* CALLOUT                                */ \
+  1+LINK_SIZE,                   /* Alt                                    */ \
+  1+LINK_SIZE,                   /* Ket                                    */ \
+  1+LINK_SIZE,                   /* KetRmax                                */ \
+  1+LINK_SIZE,                   /* KetRmin                                */ \
+  1+LINK_SIZE,                   /* Assert                                 */ \
+  1+LINK_SIZE,                   /* Assert not                             */ \
+  1+LINK_SIZE,                   /* Assert behind                          */ \
+  1+LINK_SIZE,                   /* Assert behind not                      */ \
+  1+LINK_SIZE,                   /* Reverse                                */ \
+  1+LINK_SIZE,                   /* Once                                   */ \
+  1+LINK_SIZE,                   /* COND                                   */ \
+  3,                             /* CREF                                   */ \
+  1, 1,                          /* BRAZERO, BRAMINZERO                    */ \
+  3,                             /* BRANUMBER                              */ \
+  1+LINK_SIZE                    /* BRA                                    */ \
+
+
+/* A magic value for OP_CREF to indicate the "in recursion" condition. */
+
+#define CREF_RECURSE  0xffff
+
+/* The texts of compile-time error messages are defined as macros here so that
+they can be accessed by the POSIX wrapper and converted into error codes.  Yes,
+I could have used error codes in the first place, but didn't feel like changing
+just to accommodate the POSIX wrapper. */
+
+#define ERR1  "\\ at end of pattern"
+#define ERR2  "\\c at end of pattern"
+#define ERR3  "unrecognized character follows \\"
+#define ERR4  "numbers out of order in {} quantifier"
+#define ERR5  "number too big in {} quantifier"
+#define ERR6  "missing terminating ] for character class"
+#define ERR7  "invalid escape sequence in character class"
+#define ERR8  "range out of order in character class"
+#define ERR9  "nothing to repeat"
+#define ERR10 "operand of unlimited repeat could match the empty string"
+#define ERR11 "internal error: unexpected repeat"
+#define ERR12 "unrecognized character after (?"
+#define ERR13 "POSIX named classes are supported only within a class"
+#define ERR14 "missing )"
+#define ERR15 "reference to non-existent subpattern"
+#define ERR16 "erroffset passed as NULL"
+#define ERR17 "unknown option bit(s) set"
+#define ERR18 "missing ) after comment"
+#define ERR19 "parentheses nested too deeply"
+#define ERR20 "regular expression too large"
+#define ERR21 "failed to get memory"
+#define ERR22 "unmatched parentheses"
+#define ERR23 "internal error: code overflow"
+#define ERR24 "unrecognized character after (?<"
+#define ERR25 "lookbehind assertion is not fixed length"
+#define ERR26 "malformed number after (?("
+#define ERR27 "conditional group contains more than two branches"
+#define ERR28 "assertion expected after (?("
+#define ERR29 "(?R or (?digits must be followed by )"
+#define ERR30 "unknown POSIX class name"
+#define ERR31 "POSIX collating elements are not supported"
+#define ERR32 "this version of PCRE is not compiled with PCRE_UTF8 support"
+#define ERR33 "spare error"
+#define ERR34 "character value in \\x{...} sequence is too large"
+#define ERR35 "invalid condition (?(0)"
+#define ERR36 "\\C not allowed in lookbehind assertion"
+#define ERR37 "PCRE does not support \\L, \\l, \\N, \\U, or \\u"
+#define ERR38 "number after (?C is > 255"
+#define ERR39 "closing ) for (?C expected"
+#define ERR40 "recursive call could loop indefinitely"
+#define ERR41 "unrecognized character after (?P"
+#define ERR42 "syntax error after (?P"
+#define ERR43 "two named groups have the same name"
+#define ERR44 "invalid UTF-8 string"
+#define ERR45 "support for \\P, \\p, and \\X has not been compiled"
+#define ERR46 "malformed \\P or \\p sequence"
+#define ERR47 "unknown property name after \\P or \\p"
+
+/* The real format of the start of the pcre block; the index of names and the
+code vector run on as long as necessary after the end. We store an explicit
+offset to the name table so that if a regex is compiled on one host, saved, and
+then run on another where the size of pointers is different, all might still
+be well. For the case of compiled-on-4 and run-on-8, we include an extra
+pointer that is always NULL. For future-proofing, we also include a few dummy
+fields - even though you can never get this planning right!
+
+NOTE NOTE NOTE:
+Because people can now save and re-use compiled patterns, any additions to this
+structure should be made at the end, and something earlier (e.g. a new
+flag in the options or one of the dummy fields) should indicate that the new
+fields are present. Currently PCRE always sets the dummy fields to zero.
+NOTE NOTE NOTE:
+*/
+
+typedef struct real_pcre {
+  pcre_uint32 magic_number;
+  pcre_uint32 size;               /* Total that was malloced */
+  pcre_uint32 options;
+  pcre_uint32 dummy1;             /* For future use, maybe */
+
+  pcre_uint16 top_bracket;
+  pcre_uint16 top_backref;
+  pcre_uint16 first_byte;
+  pcre_uint16 req_byte;
+  pcre_uint16 name_table_offset;  /* Offset to name table that follows */
+  pcre_uint16 name_entry_size;    /* Size of any name items */
+  pcre_uint16 name_count;         /* Number of name items */
+  pcre_uint16 dummy2;             /* For future use, maybe */
+
+  const unsigned char *tables;    /* Pointer to tables or NULL for std */
+  const unsigned char *nullpad;   /* NULL padding */
+} real_pcre;
+
+/* The format of the block used to store data from pcre_study(). The same
+remark (see NOTE above) about extending this structure applies. */
+
+typedef struct pcre_study_data {
+  pcre_uint32 size;               /* Total that was malloced */
+  pcre_uint32 options;
+  uschar start_bits[32];
+} pcre_study_data;
+
+/* Structure for passing "static" information around between the functions
+doing the compiling, so that they are thread-safe. */
+
+typedef struct compile_data {
+  const uschar *lcc;            /* Points to lower casing table */
+  const uschar *fcc;            /* Points to case-flipping table */
+  const uschar *cbits;          /* Points to character type table */
+  const uschar *ctypes;         /* Points to table of type maps */
+  const uschar *start_code;     /* The start of the compiled code */
+  const uschar *start_pattern;  /* The start of the pattern */
+  uschar *name_table;           /* The name/number table */
+  int  names_found;             /* Number of entries so far */
+  int  name_entry_size;         /* Size of each entry */
+  int  top_backref;             /* Maximum back reference */
+  unsigned int backref_map;     /* Bitmap of low back refs */
+  int  req_varyopt;             /* "After variable item" flag for reqbyte */
+  BOOL nopartial;               /* Set TRUE if partial won't work */
+} compile_data;
+
+/* Structure for maintaining a chain of pointers to the currently incomplete
+branches, for testing for left recursion. */
+
+typedef struct branch_chain {
+  struct branch_chain *outer;
+  uschar *current;
+} branch_chain;
+
+/* Structure for items in a linked list that represents an explicit recursive
+call within the pattern. */
+
+typedef struct recursion_info {
+  struct recursion_info *prevrec; /* Previous recursion record (or NULL) */
+  int group_num;                /* Number of group that was called */
+  const uschar *after_call;     /* "Return value": points after the call in the expr */
+  const uschar *save_start;     /* Old value of md->start_match */
+  int *offset_save;             /* Pointer to start of saved offsets */
+  int saved_max;                /* Number of saved offsets */
+} recursion_info;
+
+/* When compiling in a mode that doesn't use recursive calls to match(),
+a structure is used to remember local variables on the heap. It is defined in
+pcre.c, close to the match() function, so that it is easy to keep it in step
+with any changes of local variable. However, the pointer to the current frame
+must be saved in some "static" place over a longjmp(). We declare the
+structure here so that we can put a pointer in the match_data structure.
+NOTE: This isn't used for a "normal" compilation of pcre. */
+
+struct heapframe;
+
+/* Structure for passing "static" information around between the functions
+doing the matching, so that they are thread-safe. */
+
+typedef struct match_data {
+  unsigned long int match_call_count; /* As it says */
+  unsigned long int match_limit;/* As it says */
+  int   *offset_vector;         /* Offset vector */
+  int    offset_end;            /* One past the end */
+  int    offset_max;            /* The maximum usable for return data */
+  const uschar *lcc;            /* Points to lower casing table */
+  const uschar *ctypes;         /* Points to table of type maps */
+  BOOL   offset_overflow;       /* Set if too many extractions */
+  BOOL   notbol;                /* NOTBOL flag */
+  BOOL   noteol;                /* NOTEOL flag */
+  BOOL   utf8;                  /* UTF8 flag */
+  BOOL   endonly;               /* Dollar not before final \n */
+  BOOL   notempty;              /* Empty string match not wanted */
+  BOOL   partial;               /* PARTIAL flag */
+  BOOL   hitend;                /* Hit the end of the subject at some point */
+  const uschar *start_code;     /* For use when recursing */
+  const uschar *start_subject;  /* Start of the subject string */
+  const uschar *end_subject;    /* End of the subject string */
+  const uschar *start_match;    /* Start of this match attempt */
+  const uschar *end_match_ptr;  /* Subject position at end match */
+  int    end_offset_top;        /* Highwater mark at end of match */
+  int    capture_last;          /* Most recent capture number */
+  int    start_offset;          /* The start offset value */
+  recursion_info *recursive;    /* Linked list of recursion data */
+  void  *callout_data;          /* To pass back to callouts */
+  struct heapframe *thisframe;  /* Used only when compiling for no recursion */
+} match_data;
+
+/* Bit definitions for entries in the pcre_ctypes table. */
+
+#define ctype_space   0x01
+#define ctype_letter  0x02
+#define ctype_digit   0x04
+#define ctype_xdigit  0x08
+#define ctype_word    0x10   /* alphameric or '_' */
+#define ctype_meta    0x80   /* regexp meta char or zero (end pattern) */
+
+/* Offsets for the bitmap tables in pcre_cbits. Each table contains a set
+of bits for a class map. Some classes are built by combining these tables. */
+
+#define cbit_space     0      /* [:space:] or \s */
+#define cbit_xdigit   32      /* [:xdigit:] */
+#define cbit_digit    64      /* [:digit:] or \d */
+#define cbit_upper    96      /* [:upper:] */
+#define cbit_lower   128      /* [:lower:] */
+#define cbit_word    160      /* [:word:] or \w */
+#define cbit_graph   192      /* [:graph:] */
+#define cbit_print   224      /* [:print:] */
+#define cbit_punct   256      /* [:punct:] */
+#define cbit_cntrl   288      /* [:cntrl:] */
+#define cbit_length  320      /* Length of the cbits table */
+
+/* Offsets of the various tables from the base tables pointer, and
+total length. */
+
+#define lcc_offset      0
+#define fcc_offset    256
+#define cbits_offset  512
+#define ctypes_offset (cbits_offset + cbit_length)
+#define tables_length (ctypes_offset + 256)
+
+/* End of internal.h */

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/libpcre.def
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/libpcre.def	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/libpcre.def	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,19 @@
+LIBRARY libpcre
+EXPORTS
+pcre_malloc
+pcre_free
+pcre_config
+pcre_callout
+pcre_compile
+pcre_copy_substring
+pcre_exec
+pcre_get_substring
+pcre_get_stringnumber
+pcre_get_substring_list
+pcre_free_substring
+pcre_free_substring_list
+pcre_info
+pcre_fullinfo
+pcre_maketables
+pcre_study
+pcre_version

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/libpcre.pc.in
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/libpcre.pc.in	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/libpcre.pc.in	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,12 @@
+# Package Information for pkg-config
+
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: libpcre
+Description: PCRE - Perl compatible regular expressions C library
+Version: @PCRE_VERSION@
+Libs: -L${libdir} -lpcre
+Cflags: -I${includedir}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/libpcreposix.def
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/libpcreposix.def	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/libpcreposix.def	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,24 @@
+LIBRARY libpcreposix
+EXPORTS
+pcre_malloc
+pcre_free
+pcre_config
+pcre_callout
+pcre_compile
+pcre_copy_substring
+pcre_exec
+pcre_get_substring
+pcre_get_stringnumber
+pcre_get_substring_list
+pcre_free_substring
+pcre_free_substring_list
+pcre_info
+pcre_fullinfo
+pcre_maketables
+pcre_study
+pcre_version
+
+regcomp
+regexec
+regerror
+regfree

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/maketables.c
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/maketables.c	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/maketables.c	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,146 @@
+/*************************************************
+*      Perl-Compatible Regular Expressions       *
+*************************************************/
+
+/*
+PCRE is a library of functions to support regular expressions whose syntax
+and semantics are as close as possible to those of the Perl 5 language.
+
+Written by: Philip Hazel <ph10 at cam.ac.uk>
+
+           Copyright (c) 1997-2003 University of Cambridge
+
+-----------------------------------------------------------------------------
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice,
+      this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+
+    * Neither the name of the University of Cambridge nor the names of its
+      contributors may be used to endorse or promote products derived from
+      this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+-----------------------------------------------------------------------------
+*/
+
+
+/* This file is compiled on its own as part of the PCRE library. However,
+it is also included in the compilation of dftables.c, in which case the macro
+DFTABLES is defined. */
+
+#ifndef DFTABLES
+#include "internal.h"
+#endif
+
+
+
+/*************************************************
+*           Create PCRE character tables         *
+*************************************************/
+
+/* This function builds a set of character tables for use by PCRE and returns
+a pointer to them. They are build using the ctype functions, and consequently
+their contents will depend upon the current locale setting. When compiled as
+part of the library, the store is obtained via pcre_malloc(), but when compiled
+inside dftables, use malloc().
+
+Arguments:   none
+Returns:     pointer to the contiguous block of data
+*/
+
+const unsigned char *
+pcre_maketables(void)
+{
+unsigned char *yield, *p;
+int i;
+
+#ifndef DFTABLES
+yield = (unsigned char*)(pcre_malloc)(tables_length);
+#else
+yield = (unsigned char*)malloc(tables_length);
+#endif
+
+if (yield == NULL) return NULL;
+p = yield;
+
+/* First comes the lower casing table */
+
+for (i = 0; i < 256; i++) *p++ = tolower(i);
+
+/* Next the case-flipping table */
+
+for (i = 0; i < 256; i++) *p++ = islower(i)? toupper(i) : tolower(i);
+
+/* Then the character class tables. Don't try to be clever and save effort
+on exclusive ones - in some locales things may be different. Note that the
+table for "space" includes everything "isspace" gives, including VT in the
+default locale. This makes it work for the POSIX class [:space:]. */
+
+memset(p, 0, cbit_length);
+for (i = 0; i < 256; i++)
+  {
+  if (isdigit(i))
+    {
+    p[cbit_digit  + i/8] |= 1 << (i&7);
+    p[cbit_word   + i/8] |= 1 << (i&7);
+    }
+  if (isupper(i))
+    {
+    p[cbit_upper  + i/8] |= 1 << (i&7);
+    p[cbit_word   + i/8] |= 1 << (i&7);
+    }
+  if (islower(i))
+    {
+    p[cbit_lower  + i/8] |= 1 << (i&7);
+    p[cbit_word   + i/8] |= 1 << (i&7);
+    }
+  if (i == '_')   p[cbit_word   + i/8] |= 1 << (i&7);
+  if (isspace(i)) p[cbit_space  + i/8] |= 1 << (i&7);
+  if (isxdigit(i))p[cbit_xdigit + i/8] |= 1 << (i&7);
+  if (isgraph(i)) p[cbit_graph  + i/8] |= 1 << (i&7);
+  if (isprint(i)) p[cbit_print  + i/8] |= 1 << (i&7);
+  if (ispunct(i)) p[cbit_punct  + i/8] |= 1 << (i&7);
+  if (iscntrl(i)) p[cbit_cntrl  + i/8] |= 1 << (i&7);
+  }
+p += cbit_length;
+
+/* Finally, the character type table. In this, we exclude VT from the white
+space chars, because Perl doesn't recognize it as such for \s and for comments
+within regexes. */
+
+for (i = 0; i < 256; i++)
+  {
+  int x = 0;
+  if (i != 0x0b && isspace(i)) x += ctype_space;
+  if (isalpha(i)) x += ctype_letter;
+  if (isdigit(i)) x += ctype_digit;
+  if (isxdigit(i)) x += ctype_xdigit;
+  if (isalnum(i) || i == '_') x += ctype_word;
+
+  /* Note: strchr includes the terminating zero in the characters it considers.
+  In this instance, that is ok because we want binary zero to be flagged as a
+  meta-character, which in this sense is any character that terminates a run
+  of data characters. */
+
+  if (strchr("*+?{^.$|()[", i) != 0) x += ctype_meta; *p++ = x; }
+
+return yield;
+}
+
+/* End of maketables.c */

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/makevp.bat
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/makevp.bat	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/makevp.bat	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,25 @@
+ at echo off
+
+REM This file was contributed by Alexander Tokarev for building PCRE for use
+REM with Virtual Pascal. It has not been tested with the latest PCRE release.
+
+REM CHANGE THIS FOR YOUR BORLAND C++ COMPILER PATH
+
+SET BORLAND=c:\usr\apps\bcc55
+
+sh configure
+
+bcc32 -DDFTABLES -DSTATIC -DVPCOMPAT -I%BORLAND%\include -L%BORLAND%\lib dftables.c
+
+dftables > chartables.c
+
+bcc32 -c -RT- -y- -v- -u- -P- -O2 -5 -DSTATIC -DVPCOMPAT -UDFTABLES -I%BORLAND%\include get.c maketables.c pcre.c study.c
+
+tlib %BORLAND%\lib\cw32.lib *calloc *del *strncmp *memcpy *memmove *memset
+tlib pcre.lib +get.obj +maketables.obj +pcre.obj +study.obj +calloc.obj +del.obj +strncmp.obj +memcpy.obj +memmove.obj +memset.obj
+
+del *.obj *.exe *.tds *.bak >nul 2>nul
+
+echo ---
+echo Now the library should be complete. Please check all messages above.
+echo Don't care for warnings, it's OK.

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/mkinstalldirs
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/mkinstalldirs	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/mkinstalldirs	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,40 @@
+#! /bin/sh
+# mkinstalldirs --- make directory hierarchy
+# Author: Noah Friedman <friedman at prep.ai.mit.edu>
+# Created: 1993-05-16
+# Public domain
+
+# $Id: mkinstalldirs 106103 2004-11-21 18:50:36Z nd $
+
+errstatus=0
+
+for file
+do
+   set fnord `echo ":$file" | sed -ne 's/^:\//#/;s/^://;s/\// /g;s/^#/\//;p'`
+   shift
+
+   pathcomp=
+   for d
+   do
+     pathcomp="$pathcomp$d"
+     case "$pathcomp" in
+       -* ) pathcomp=./$pathcomp ;;
+     esac
+
+     if test ! -d "$pathcomp"; then
+        echo "mkdir $pathcomp"
+
+        mkdir "$pathcomp" || lasterr=$?
+
+        if test ! -d "$pathcomp"; then
+  	  errstatus=$lasterr
+        fi
+     fi
+
+     pathcomp="$pathcomp/"
+   done
+done
+
+exit $errstatus
+
+# mkinstalldirs ends here

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/pcre-config.in
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/pcre-config.in	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/pcre-config.in	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,66 @@
+#!/bin/sh
+
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+exec_prefix_set=no
+
+usage="\
+Usage: pcre-config [--prefix] [--exec-prefix] [--version] [--libs] [--libs-posix] [--cflags] [--cflags-posix]"
+
+if test $# -eq 0; then
+      echo "${usage}" 1>&2
+      exit 1
+fi
+
+libR=
+case `uname -s` in
+  *SunOS*)
+  libR=" -R at libdir@"
+  ;;
+esac
+
+while test $# -gt 0; do
+  case "$1" in
+  -*=*) optarg=`echo "$1" | sed 's/[-_a-zA-Z0-9]*=//'` ;;
+  *) optarg= ;;
+  esac
+
+  case $1 in
+    --prefix=*)
+      prefix=$optarg
+      if test $exec_prefix_set = no ; then
+        exec_prefix=$optarg
+      fi
+      ;;
+    --prefix)
+      echo $prefix
+      ;;
+    --exec-prefix=*)
+      exec_prefix=$optarg
+      exec_prefix_set=yes
+      ;;
+    --exec-prefix)
+      echo $exec_prefix
+      ;;
+    --version)
+      echo @PCRE_VERSION@
+      ;;
+    --cflags | --cflags-posix)
+      if test @includedir@ != /usr/include ; then
+        includes=-I at includedir@
+      fi
+      echo $includes
+      ;;
+    --libs-posix)
+      echo -L at libdir@$libR -lpcreposix -lpcre
+      ;;
+    --libs)
+      echo -L at libdir@$libR -lpcre
+      ;;
+    *)
+      echo "${usage}" 1>&2
+      exit 1
+      ;;
+  esac
+  shift
+done

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/pcre.c
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/pcre.c	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/pcre.c	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,9207 @@
+/*************************************************
+*      Perl-Compatible Regular Expressions       *
+*************************************************/
+
+/*
+This is a library of functions to support regular expressions whose syntax
+and semantics are as close as possible to those of the Perl 5 language. See
+the file Tech.Notes for some information on the internals.
+
+Written by: Philip Hazel <ph10 at cam.ac.uk>
+
+           Copyright (c) 1997-2004 University of Cambridge
+
+-----------------------------------------------------------------------------
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice,
+      this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+
+    * Neither the name of the University of Cambridge nor the names of its
+      contributors may be used to endorse or promote products derived from
+      this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+-----------------------------------------------------------------------------
+*/
+
+
+/* Define DEBUG to get debugging output on stdout. */
+/* #define DEBUG */
+
+/* Use a macro for debugging printing, 'cause that eliminates the use of #ifdef
+inline, and there are *still* stupid compilers about that don't like indented
+pre-processor statements. I suppose it's only been 10 years... */
+
+#ifdef DEBUG
+#define DPRINTF(p) printf p
+#else
+#define DPRINTF(p) /*nothing*/
+#endif
+
+/* Include the internals header, which itself includes "config.h", the Standard
+C headers, and the external pcre header. */
+
+#include "internal.h"
+
+/* If Unicode Property support is wanted, include a private copy of the
+function that does it, and the table that translates names to numbers. */
+
+#ifdef SUPPORT_UCP
+#include "ucp.c"
+#include "ucptypetable.c"
+#endif
+
+/* Maximum number of items on the nested bracket stacks at compile time. This
+applies to the nesting of all kinds of parentheses. It does not limit
+un-nested, non-capturing parentheses. This number can be made bigger if
+necessary - it is used to dimension one int and one unsigned char vector at
+compile time. */
+
+#define BRASTACK_SIZE 200
+
+
+/* Maximum number of ints of offset to save on the stack for recursive calls.
+If the offset vector is bigger, malloc is used. This should be a multiple of 3,
+because the offset vector is always a multiple of 3 long. */
+
+#define REC_STACK_SAVE_MAX 30
+
+
+/* The maximum remaining length of subject we are prepared to search for a
+req_byte match. */
+
+#define REQ_BYTE_MAX 1000
+
+
+/* Table of sizes for the fixed-length opcodes. It's defined in a macro so that
+the definition is next to the definition of the opcodes in internal.h. */
+
+static const uschar OP_lengths[] = { OP_LENGTHS };
+
+/* Min and max values for the common repeats; for the maxima, 0 => infinity */
+
+static const char rep_min[] = { 0, 0, 1, 1, 0, 0 };
+static const char rep_max[] = { 0, 0, 0, 0, 1, 1 };
+
+/* Table for handling escaped characters in the range '0'-'z'. Positive returns
+are simple data values; negative values are for special things like \d and so
+on. Zero means further processing is needed (for things like \x), or the escape
+is invalid. */
+
+#if !EBCDIC   /* This is the "normal" table for ASCII systems */
+static const short int escapes[] = {
+     0,      0,      0,      0,      0,      0,      0,      0,   /* 0 - 7 */
+     0,      0,    ':',    ';',    '<',    '=',    '>',    '?',   /* 8 - ? */
+   '@', -ESC_A, -ESC_B, -ESC_C, -ESC_D, -ESC_E,      0, -ESC_G,   /* @ - G */
+     0,      0,      0,      0,      0,      0,      0,      0,   /* H - O */
+-ESC_P, -ESC_Q,      0, -ESC_S,      0,      0,      0, -ESC_W,   /* P - W */
+-ESC_X,      0, -ESC_Z,    '[',   '\\',    ']',    '^',    '_',   /* X - _ */
+   '`',      7, -ESC_b,      0, -ESC_d,  ESC_e,  ESC_f,      0,   /* ` - g */
+     0,      0,      0,      0,      0,      0,  ESC_n,      0,   /* h - o */
+-ESC_p,      0,  ESC_r, -ESC_s,  ESC_tee,    0,      0, -ESC_w,   /* p - w */
+     0,      0, -ESC_z                                            /* x - z */
+};
+
+#else         /* This is the "abnormal" table for EBCDIC systems */
+static const short int escapes[] = {
+/*  48 */     0,     0,      0,     '.',    '<',   '(',    '+',    '|',
+/*  50 */   '&',     0,      0,       0,      0,     0,      0,      0,
+/*  58 */     0,     0,    '!',     '$',    '*',   ')',    ';',    '~',
+/*  60 */   '-',   '/',      0,       0,      0,     0,      0,      0,
+/*  68 */     0,     0,    '|',     ',',    '%',   '_',    '>',    '?',
+/*  70 */     0,     0,      0,       0,      0,     0,      0,      0,
+/*  78 */     0,   '`',    ':',     '#',    '@',  '\'',    '=',    '"',
+/*  80 */     0,     7, -ESC_b,       0, -ESC_d, ESC_e,  ESC_f,      0,
+/*  88 */     0,     0,      0,     '{',      0,     0,      0,      0,
+/*  90 */     0,     0,      0,     'l',      0, ESC_n,      0, -ESC_p,
+/*  98 */     0, ESC_r,      0,     '}',      0,     0,      0,      0,
+/*  A0 */     0,   '~', -ESC_s, ESC_tee,      0,     0, -ESC_w,      0,
+/*  A8 */     0,-ESC_z,      0,       0,      0,   '[',      0,      0,
+/*  B0 */     0,     0,      0,       0,      0,     0,      0,      0,
+/*  B8 */     0,     0,      0,       0,      0,   ']',    '=',    '-',
+/*  C0 */   '{',-ESC_A, -ESC_B,  -ESC_C, -ESC_D,-ESC_E,      0, -ESC_G,
+/*  C8 */     0,     0,      0,       0,      0,     0,      0,      0,
+/*  D0 */   '}',     0,      0,       0,      0,     0,      0, -ESC_P,
+/*  D8 */-ESC_Q,     0,      0,       0,      0,     0,      0,      0,
+/*  E0 */  '\\',     0, -ESC_S,       0,      0,     0, -ESC_W, -ESC_X,
+/*  E8 */     0,-ESC_Z,      0,       0,      0,     0,      0,      0,
+/*  F0 */     0,     0,      0,       0,      0,     0,      0,      0,
+/*  F8 */     0,     0,      0,       0,      0,     0,      0,      0
+};
+#endif
+
+
+/* Tables of names of POSIX character classes and their lengths. The list is
+terminated by a zero length entry. The first three must be alpha, upper, lower,
+as this is assumed for handling case independence. */
+
+static const char *const posix_names[] = {
+  "alpha", "lower", "upper",
+  "alnum", "ascii", "blank", "cntrl", "digit", "graph",
+  "print", "punct", "space", "word",  "xdigit" };
+
+static const uschar posix_name_lengths[] = {
+  5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 4, 6, 0 };
+
+/* Table of class bit maps for each POSIX class; up to three may be combined
+to form the class. The table for [:blank:] is dynamically modified to remove
+the vertical space characters. */
+
+static const int posix_class_maps[] = {
+  cbit_lower, cbit_upper, -1,             /* alpha */
+  cbit_lower, -1,         -1,             /* lower */
+  cbit_upper, -1,         -1,             /* upper */
+  cbit_digit, cbit_lower, cbit_upper,     /* alnum */
+  cbit_print, cbit_cntrl, -1,             /* ascii */
+  cbit_space, -1,         -1,             /* blank - a GNU extension */
+  cbit_cntrl, -1,         -1,             /* cntrl */
+  cbit_digit, -1,         -1,             /* digit */
+  cbit_graph, -1,         -1,             /* graph */
+  cbit_print, -1,         -1,             /* print */
+  cbit_punct, -1,         -1,             /* punct */
+  cbit_space, -1,         -1,             /* space */
+  cbit_word,  -1,         -1,             /* word - a Perl extension */
+  cbit_xdigit,-1,         -1              /* xdigit */
+};
+
+/* Table to identify digits and hex digits. This is used when compiling
+patterns. Note that the tables in chartables are dependent on the locale, and
+may mark arbitrary characters as digits - but the PCRE compiling code expects
+to handle only 0-9, a-z, and A-Z as digits when compiling. That is why we have
+a private table here. It costs 256 bytes, but it is a lot faster than doing
+character value tests (at least in some simple cases I timed), and in some
+applications one wants PCRE to compile efficiently as well as match
+efficiently.
+
+For convenience, we use the same bit definitions as in chartables:
+
+  0x04   decimal digit
+  0x08   hexadecimal digit
+
+Then we can use ctype_digit and ctype_xdigit in the code. */
+
+#if !EBCDIC    /* This is the "normal" case, for ASCII systems */
+static const unsigned char digitab[] =
+  {
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /*   0-  7 */
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /*   8- 15 */
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /*  16- 23 */
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /*  24- 31 */
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /*    - '  */
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /*  ( - /  */
+  0x0c,0x0c,0x0c,0x0c,0x0c,0x0c,0x0c,0x0c, /*  0 - 7  */
+  0x0c,0x0c,0x00,0x00,0x00,0x00,0x00,0x00, /*  8 - ?  */
+  0x00,0x08,0x08,0x08,0x08,0x08,0x08,0x00, /*  @ - G  */
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /*  H - O  */
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /*  P - W  */
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /*  X - _  */
+  0x00,0x08,0x08,0x08,0x08,0x08,0x08,0x00, /*  ` - g  */
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /*  h - o  */
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /*  p - w  */
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /*  x -127 */
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 128-135 */
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 136-143 */
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 144-151 */
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 152-159 */
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 160-167 */
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 168-175 */
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 176-183 */
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 184-191 */
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 192-199 */
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 200-207 */
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 208-215 */
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 216-223 */
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 224-231 */
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 232-239 */
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 240-247 */
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};/* 248-255 */
+
+#else          /* This is the "abnormal" case, for EBCDIC systems */
+static const unsigned char digitab[] =
+  {
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /*   0-  7  0 */
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /*   8- 15    */
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /*  16- 23 10 */
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /*  24- 31    */
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /*  32- 39 20 */
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /*  40- 47    */
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /*  48- 55 30 */
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /*  56- 63    */
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /*    - 71 40 */
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /*  72- |     */
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /*  & - 87 50 */
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /*  88- ¬     */
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /*  - -103 60 */
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 104- ?     */
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 112-119 70 */
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 120- "     */
+  0x00,0x08,0x08,0x08,0x08,0x08,0x08,0x00, /* 128- g  80 */
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /*  h -143    */
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 144- p  90 */
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /*  q -159    */
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 160- x  A0 */
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /*  y -175    */
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /*  ^ -183 B0 */
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 184-191    */
+  0x00,0x08,0x08,0x08,0x08,0x08,0x08,0x00, /*  { - G  C0 */
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /*  H -207    */
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /*  } - P  D0 */
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /*  Q -223    */
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /*  \ - X  E0 */
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /*  Y -239    */
+  0x0c,0x0c,0x0c,0x0c,0x0c,0x0c,0x0c,0x0c, /*  0 - 7  F0 */
+  0x0c,0x0c,0x00,0x00,0x00,0x00,0x00,0x00};/*  8 -255    */
+
+static const unsigned char ebcdic_chartab[] = { /* chartable partial dup */
+  0x80,0x00,0x00,0x00,0x00,0x01,0x00,0x00, /*   0-  7 */
+  0x00,0x00,0x00,0x00,0x01,0x01,0x00,0x00, /*   8- 15 */
+  0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00, /*  16- 23 */
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /*  24- 31 */
+  0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00, /*  32- 39 */
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /*  40- 47 */
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /*  48- 55 */
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /*  56- 63 */
+  0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /*    - 71 */
+  0x00,0x00,0x00,0x80,0x00,0x80,0x80,0x80, /*  72- |  */
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /*  & - 87 */
+  0x00,0x00,0x00,0x80,0x80,0x80,0x00,0x00, /*  88- ¬  */
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /*  - -103 */
+  0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x80, /* 104- ?  */
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 112-119 */
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 120- "  */
+  0x00,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x12, /* 128- g  */
+  0x12,0x12,0x00,0x00,0x00,0x00,0x00,0x00, /*  h -143 */
+  0x00,0x12,0x12,0x12,0x12,0x12,0x12,0x12, /* 144- p  */
+  0x12,0x12,0x00,0x00,0x00,0x00,0x00,0x00, /*  q -159 */
+  0x00,0x00,0x12,0x12,0x12,0x12,0x12,0x12, /* 160- x  */
+  0x12,0x12,0x00,0x00,0x00,0x00,0x00,0x00, /*  y -175 */
+  0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /*  ^ -183 */
+  0x00,0x00,0x80,0x00,0x00,0x00,0x00,0x00, /* 184-191 */
+  0x80,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x12, /*  { - G  */
+  0x12,0x12,0x00,0x00,0x00,0x00,0x00,0x00, /*  H -207 */
+  0x00,0x12,0x12,0x12,0x12,0x12,0x12,0x12, /*  } - P  */
+  0x12,0x12,0x00,0x00,0x00,0x00,0x00,0x00, /*  Q -223 */
+  0x00,0x00,0x12,0x12,0x12,0x12,0x12,0x12, /*  \ - X  */
+  0x12,0x12,0x00,0x00,0x00,0x00,0x00,0x00, /*  Y -239 */
+  0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c, /*  0 - 7  */
+  0x1c,0x1c,0x00,0x00,0x00,0x00,0x00,0x00};/*  8 -255 */
+#endif
+
+
+/* Definition to allow mutual recursion */
+
+static BOOL
+  compile_regex(int, int, int *, uschar **, const uschar **, const char **,
+    BOOL, int, int *, int *, branch_chain *, compile_data *);
+
+/* Structure for building a chain of data that actually lives on the
+stack, for holding the values of the subject pointer at the start of each
+subpattern, so as to detect when an empty string has been matched by a
+subpattern - to break infinite loops. When NO_RECURSE is set, these blocks
+are on the heap, not on the stack. */
+
+typedef struct eptrblock {
+  struct eptrblock *epb_prev;
+  const uschar *epb_saved_eptr;
+} eptrblock;
+
+/* Flag bits for the match() function */
+
+#define match_condassert   0x01    /* Called to check a condition assertion */
+#define match_isgroup      0x02    /* Set if start of bracketed group */
+
+/* Non-error returns from the match() function. Error returns are externally
+defined PCRE_ERROR_xxx codes, which are all negative. */
+
+#define MATCH_MATCH        1
+#define MATCH_NOMATCH      0
+
+
+
+/*************************************************
+*               Global variables                 *
+*************************************************/
+
+/* PCRE is thread-clean and doesn't use any global variables in the normal
+sense. However, it calls memory allocation and free functions via the four
+indirections below, and it can optionally do callouts. These values can be
+changed by the caller, but are shared between all threads. However, when
+compiling for Virtual Pascal, things are done differently (see pcre.in). */
+
+#ifndef VPCOMPAT
+#ifdef __cplusplus
+extern "C" void *(*pcre_malloc)(size_t) = malloc;
+extern "C" void  (*pcre_free)(void *) = free;
+extern "C" void *(*pcre_stack_malloc)(size_t) = malloc;
+extern "C" void  (*pcre_stack_free)(void *) = free;
+extern "C" int   (*pcre_callout)(pcre_callout_block *) = NULL;
+#else
+void *(*pcre_malloc)(size_t) = malloc;
+void  (*pcre_free)(void *) = free;
+void *(*pcre_stack_malloc)(size_t) = malloc;
+void  (*pcre_stack_free)(void *) = free;
+int   (*pcre_callout)(pcre_callout_block *) = NULL;
+#endif
+#endif
+
+
+/*************************************************
+*    Macros and tables for character handling    *
+*************************************************/
+
+/* When UTF-8 encoding is being used, a character is no longer just a single
+byte. The macros for character handling generate simple sequences when used in
+byte-mode, and more complicated ones for UTF-8 characters. */
+
+#ifndef SUPPORT_UTF8
+#define GETCHAR(c, eptr) c = *eptr;
+#define GETCHARINC(c, eptr) c = *eptr++;
+#define GETCHARINCTEST(c, eptr) c = *eptr++;
+#define GETCHARLEN(c, eptr, len) c = *eptr;
+#define BACKCHAR(eptr)
+
+#else   /* SUPPORT_UTF8 */
+
+/* Get the next UTF-8 character, not advancing the pointer. This is called when
+we know we are in UTF-8 mode. */
+
+#define GETCHAR(c, eptr) \
+  c = *eptr; \
+  if ((c & 0xc0) == 0xc0) \
+    { \
+    int gcii; \
+    int gcaa = utf8_table4[c & 0x3f];  /* Number of additional bytes */ \
+    int gcss = 6*gcaa; \
+    c = (c & utf8_table3[gcaa]) << gcss; \
+    for (gcii = 1; gcii <= gcaa; gcii++) \
+      { \
+      gcss -= 6; \
+      c |= (eptr[gcii] & 0x3f) << gcss; \
+      } \
+    }
+
+/* Get the next UTF-8 character, advancing the pointer. This is called when we
+know we are in UTF-8 mode. */
+
+#define GETCHARINC(c, eptr) \
+  c = *eptr++; \
+  if ((c & 0xc0) == 0xc0) \
+    { \
+    int gcaa = utf8_table4[c & 0x3f];  /* Number of additional bytes */ \
+    int gcss = 6*gcaa; \
+    c = (c & utf8_table3[gcaa]) << gcss; \
+    while (gcaa-- > 0) \
+      { \
+      gcss -= 6; \
+      c |= (*eptr++ & 0x3f) << gcss; \
+      } \
+    }
+
+/* Get the next character, testing for UTF-8 mode, and advancing the pointer */
+
+#define GETCHARINCTEST(c, eptr) \
+  c = *eptr++; \
+  if (md->utf8 && (c & 0xc0) == 0xc0) \
+    { \
+    int gcaa = utf8_table4[c & 0x3f];  /* Number of additional bytes */ \
+    int gcss = 6*gcaa; \
+    c = (c & utf8_table3[gcaa]) << gcss; \
+    while (gcaa-- > 0) \
+      { \
+      gcss -= 6; \
+      c |= (*eptr++ & 0x3f) << gcss; \
+      } \
+    }
+
+/* Get the next UTF-8 character, not advancing the pointer, incrementing length
+if there are extra bytes. This is called when we know we are in UTF-8 mode. */
+
+#define GETCHARLEN(c, eptr, len) \
+  c = *eptr; \
+  if ((c & 0xc0) == 0xc0) \
+    { \
+    int gcii; \
+    int gcaa = utf8_table4[c & 0x3f];  /* Number of additional bytes */ \
+    int gcss = 6*gcaa; \
+    c = (c & utf8_table3[gcaa]) << gcss; \
+    for (gcii = 1; gcii <= gcaa; gcii++) \
+      { \
+      gcss -= 6; \
+      c |= (eptr[gcii] & 0x3f) << gcss; \
+      } \
+    len += gcaa; \
+    }
+
+/* If the pointer is not at the start of a character, move it back until
+it is. Called only in UTF-8 mode. */
+
+#define BACKCHAR(eptr) while((*eptr & 0xc0) == 0x80) eptr--;
+
+#endif
+
+
+
+/*************************************************
+*             Default character tables           *
+*************************************************/
+
+/* A default set of character tables is included in the PCRE binary. Its source
+is built by the maketables auxiliary program, which uses the default C ctypes
+functions, and put in the file chartables.c. These tables are used by PCRE
+whenever the caller of pcre_compile() does not provide an alternate set of
+tables. */
+
+#include "chartables.c"
+
+
+
+#ifdef SUPPORT_UTF8
+/*************************************************
+*           Tables for UTF-8 support             *
+*************************************************/
+
+/* These are the breakpoints for different numbers of bytes in a UTF-8
+character. */
+
+static const int utf8_table1[] =
+  { 0x7f, 0x7ff, 0xffff, 0x1fffff, 0x3ffffff, 0x7fffffff};
+
+/* These are the indicator bits and the mask for the data bits to set in the
+first byte of a character, indexed by the number of additional bytes. */
+
+static const int utf8_table2[] = { 0,    0xc0, 0xe0, 0xf0, 0xf8, 0xfc};
+static const int utf8_table3[] = { 0xff, 0x1f, 0x0f, 0x07, 0x03, 0x01};
+
+/* Table of the number of extra characters, indexed by the first character
+masked with 0x3f. The highest number for a valid UTF-8 character is in fact
+0x3d. */
+
+static const uschar utf8_table4[] = {
+  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,
+  2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+  3,3,3,3,3,3,3,3,4,4,4,4,5,5,5,5 };
+
+
+/*************************************************
+*       Convert character value to UTF-8         *
+*************************************************/
+
+/* This function takes an integer value in the range 0 - 0x7fffffff
+and encodes it as a UTF-8 character in 0 to 6 bytes.
+
+Arguments:
+  cvalue     the character value
+  buffer     pointer to buffer for result - at least 6 bytes long
+
+Returns:     number of characters placed in the buffer
+*/
+
+static int
+ord2utf8(int cvalue, uschar *buffer)
+{
+register int i, j;
+for (i = 0; i < sizeof(utf8_table1)/sizeof(int); i++)
+  if (cvalue <= utf8_table1[i]) break;
+buffer += i;
+for (j = i; j > 0; j--)
+ {
+ *buffer-- = 0x80 | (cvalue & 0x3f);
+ cvalue >>= 6;
+ }
+*buffer = utf8_table2[i] | cvalue;
+return i + 1;
+}
+#endif
+
+
+
+/*************************************************
+*         Print compiled regex                   *
+*************************************************/
+
+/* The code for doing this is held in a separate file that is also included in
+pcretest.c. It defines a function called print_internals(). */
+
+#ifdef DEBUG
+#include "printint.c"
+#endif
+
+
+
+/*************************************************
+*          Return version string                 *
+*************************************************/
+
+#define STRING(a)  # a
+#define XSTRING(s) STRING(s)
+
+EXPORT const char *
+pcre_version(void)
+{
+return XSTRING(PCRE_MAJOR) "." XSTRING(PCRE_MINOR) " " XSTRING(PCRE_DATE);
+}
+
+
+
+
+/*************************************************
+*         Flip bytes in an integer               *
+*************************************************/
+
+/* This function is called when the magic number in a regex doesn't match in
+order to flip its bytes to see if we are dealing with a pattern that was
+compiled on a host of different endianness. If so, this function is used to
+flip other byte values.
+
+Arguments:
+  value        the number to flip
+  n            the number of bytes to flip (assumed to be 2 or 4)
+
+Returns:       the flipped value
+*/
+
+static pcre_uint16
+byteflip2(pcre_uint16 value)
+{
+return ((value & 0x00ff) << 8) |
+       ((value & 0xff00) >> 8);
+}
+
+static pcre_uint32
+byteflip4(pcre_uint32 value)
+{
+return ((value & 0x000000ff) << 24) |
+       ((value & 0x0000ff00) <<  8) |
+       ((value & 0x00ff0000) >>  8) |
+       ((value & 0xff000000) >> 24);
+}
+
+/*************************************************
+*       Test for a byte-flipped compiled regex   *
+*************************************************/
+
+/* This function is called from pce_exec() and also from pcre_fullinfo(). Its
+job is to test whether the regex is byte-flipped - that is, it was compiled on
+a system of opposite endianness. The function is called only when the native
+MAGIC_NUMBER test fails. If the regex is indeed flipped, we flip all the
+relevant values into a different data block, and return it.
+
+Arguments:
+  re               points to the regex
+  study            points to study data, or NULL
+  internal_re      points to a new regex block
+  internal_study   points to a new study block
+
+Returns:           the new block if is is indeed a byte-flipped regex
+                   NULL if it is not
+*/
+
+static real_pcre *
+try_flipped(const real_pcre *re, real_pcre *internal_re,
+  const pcre_study_data *study, pcre_study_data *internal_study)
+{
+if (byteflip4(re->magic_number) != MAGIC_NUMBER)
+  return NULL;
+
+*internal_re = *re;           /* To copy other fields */
+internal_re->size = byteflip4(re->size);
+internal_re->options = byteflip4(re->options);
+internal_re->top_bracket = byteflip2(re->top_bracket);
+internal_re->top_backref = byteflip2(re->top_backref);
+internal_re->first_byte = byteflip2(re->first_byte);
+internal_re->req_byte = byteflip2(re->req_byte);
+internal_re->name_table_offset = byteflip2(re->name_table_offset);
+internal_re->name_entry_size = byteflip2(re->name_entry_size);
+internal_re->name_count = byteflip2(re->name_count);
+
+if (study != NULL)
+  {
+  *internal_study = *study;   /* To copy other fields */
+  internal_study->size = byteflip4(study->size);
+  internal_study->options = byteflip4(study->options);
+  }
+
+return internal_re;
+}
+
+
+
+/*************************************************
+* (Obsolete) Return info about compiled pattern  *
+*************************************************/
+
+/* This is the original "info" function. It picks potentially useful data out
+of the private structure, but its interface was too rigid. It remains for
+backwards compatibility. The public options are passed back in an int - though
+the re->options field has been expanded to a long int, all the public options
+at the low end of it, and so even on 16-bit systems this will still be OK.
+Therefore, I haven't changed the API for pcre_info().
+
+Arguments:
+  argument_re   points to compiled code
+  optptr        where to pass back the options
+  first_byte    where to pass back the first character,
+                or -1 if multiline and all branches start ^,
+                or -2 otherwise
+
+Returns:        number of capturing subpatterns
+                or negative values on error
+*/
+
+EXPORT int
+pcre_info(const pcre *argument_re, int *optptr, int *first_byte)
+{
+real_pcre internal_re;
+const real_pcre *re = (const real_pcre *)argument_re;
+if (re == NULL) return PCRE_ERROR_NULL;
+if (re->magic_number != MAGIC_NUMBER)
+  {
+  re = try_flipped(re, &internal_re, NULL, NULL);
+  if (re == NULL) return PCRE_ERROR_BADMAGIC;
+  }
+if (optptr != NULL) *optptr = (int)(re->options & PUBLIC_OPTIONS);
+if (first_byte != NULL)
+  *first_byte = ((re->options & PCRE_FIRSTSET) != 0)? re->first_byte :
+     ((re->options & PCRE_STARTLINE) != 0)? -1 : -2;
+return re->top_bracket;
+}
+
+
+
+/*************************************************
+*        Return info about compiled pattern      *
+*************************************************/
+
+/* This is a newer "info" function which has an extensible interface so
+that additional items can be added compatibly.
+
+Arguments:
+  argument_re      points to compiled code
+  extra_data       points extra data, or NULL
+  what             what information is required
+  where            where to put the information
+
+Returns:           0 if data returned, negative on error
+*/
+
+EXPORT int
+pcre_fullinfo(const pcre *argument_re, const pcre_extra *extra_data, int what,
+  void *where)
+{
+real_pcre internal_re;
+pcre_study_data internal_study;
+const real_pcre *re = (const real_pcre *)argument_re;
+const pcre_study_data *study = NULL;
+
+if (re == NULL || where == NULL) return PCRE_ERROR_NULL;
+
+if (extra_data != NULL && (extra_data->flags & PCRE_EXTRA_STUDY_DATA) != 0)
+  study = (const pcre_study_data *)extra_data->study_data;
+
+if (re->magic_number != MAGIC_NUMBER)
+  {
+  re = try_flipped(re, &internal_re, study, &internal_study);
+  if (re == NULL) return PCRE_ERROR_BADMAGIC;
+  if (study != NULL) study = &internal_study;
+  }
+
+switch (what)
+  {
+  case PCRE_INFO_OPTIONS:
+  *((unsigned long int *)where) = re->options & PUBLIC_OPTIONS;
+  break;
+
+  case PCRE_INFO_SIZE:
+  *((size_t *)where) = re->size;
+  break;
+
+  case PCRE_INFO_STUDYSIZE:
+  *((size_t *)where) = (study == NULL)? 0 : study->size;
+  break;
+
+  case PCRE_INFO_CAPTURECOUNT:
+  *((int *)where) = re->top_bracket;
+  break;
+
+  case PCRE_INFO_BACKREFMAX:
+  *((int *)where) = re->top_backref;
+  break;
+
+  case PCRE_INFO_FIRSTBYTE:
+  *((int *)where) =
+    ((re->options & PCRE_FIRSTSET) != 0)? re->first_byte :
+    ((re->options & PCRE_STARTLINE) != 0)? -1 : -2;
+  break;
+
+  /* Make sure we pass back the pointer to the bit vector in the external
+  block, not the internal copy (with flipped integer fields). */
+
+  case PCRE_INFO_FIRSTTABLE:
+  *((const uschar **)where) =
+    (study != NULL && (study->options & PCRE_STUDY_MAPPED) != 0)?
+      ((const pcre_study_data *)extra_data->study_data)->start_bits : NULL;
+  break;
+
+  case PCRE_INFO_LASTLITERAL:
+  *((int *)where) =
+    ((re->options & PCRE_REQCHSET) != 0)? re->req_byte : -1;
+  break;
+
+  case PCRE_INFO_NAMEENTRYSIZE:
+  *((int *)where) = re->name_entry_size;
+  break;
+
+  case PCRE_INFO_NAMECOUNT:
+  *((int *)where) = re->name_count;
+  break;
+
+  case PCRE_INFO_NAMETABLE:
+  *((const uschar **)where) = (const uschar *)re + re->name_table_offset;
+  break;
+
+  case PCRE_INFO_DEFAULT_TABLES:
+  *((const uschar **)where) = (const uschar *)pcre_default_tables;
+  break;
+
+  default: return PCRE_ERROR_BADOPTION;
+  }
+
+return 0;
+}
+
+
+
+/*************************************************
+* Return info about what features are configured *
+*************************************************/
+
+/* This is function which has an extensible interface so that additional items
+can be added compatibly.
+
+Arguments:
+  what             what information is required
+  where            where to put the information
+
+Returns:           0 if data returned, negative on error
+*/
+
+EXPORT int
+pcre_config(int what, void *where)
+{
+switch (what)
+  {
+  case PCRE_CONFIG_UTF8:
+#ifdef SUPPORT_UTF8
+  *((int *)where) = 1;
+#else
+  *((int *)where) = 0;
+#endif
+  break;
+
+  case PCRE_CONFIG_UNICODE_PROPERTIES:
+#ifdef SUPPORT_UCP
+  *((int *)where) = 1;
+#else
+  *((int *)where) = 0;
+#endif
+  break;
+
+  case PCRE_CONFIG_NEWLINE:
+  *((int *)where) = NEWLINE;
+  break;
+
+  case PCRE_CONFIG_LINK_SIZE:
+  *((int *)where) = LINK_SIZE;
+  break;
+
+  case PCRE_CONFIG_POSIX_MALLOC_THRESHOLD:
+  *((int *)where) = POSIX_MALLOC_THRESHOLD;
+  break;
+
+  case PCRE_CONFIG_MATCH_LIMIT:
+  *((unsigned int *)where) = MATCH_LIMIT;
+  break;
+
+  case PCRE_CONFIG_STACKRECURSE:
+#ifdef NO_RECURSE
+  *((int *)where) = 0;
+#else
+  *((int *)where) = 1;
+#endif
+  break;
+
+  default: return PCRE_ERROR_BADOPTION;
+  }
+
+return 0;
+}
+
+
+
+#ifdef DEBUG
+/*************************************************
+*        Debugging function to print chars       *
+*************************************************/
+
+/* Print a sequence of chars in printable format, stopping at the end of the
+subject if the requested.
+
+Arguments:
+  p           points to characters
+  length      number to print
+  is_subject  TRUE if printing from within md->start_subject
+  md          pointer to matching data block, if is_subject is TRUE
+
+Returns:     nothing
+*/
+
+static void
+pchars(const uschar *p, int length, BOOL is_subject, match_data *md)
+{
+int c;
+if (is_subject && length > md->end_subject - p) length = md->end_subject - p;
+while (length-- > 0)
+  if (isprint(c = *(p++))) printf("%c", c); else printf("\\x%02x", c);
+}
+#endif
+
+
+
+
+/*************************************************
+*            Handle escapes                      *
+*************************************************/
+
+/* This function is called when a \ has been encountered. It either returns a
+positive value for a simple escape such as \n, or a negative value which
+encodes one of the more complicated things such as \d. When UTF-8 is enabled,
+a positive value greater than 255 may be returned. On entry, ptr is pointing at
+the \. On exit, it is on the final character of the escape sequence.
+
+Arguments:
+  ptrptr     points to the pattern position pointer
+  errorptr   points to the pointer to the error message
+  bracount   number of previous extracting brackets
+  options    the options bits
+  isclass    TRUE if inside a character class
+
+Returns:     zero or positive => a data character
+             negative => a special escape sequence
+             on error, errorptr is set
+*/
+
+static int
+check_escape(const uschar **ptrptr, const char **errorptr, int bracount,
+  int options, BOOL isclass)
+{
+const uschar *ptr = *ptrptr;
+int c, i;
+
+/* If backslash is at the end of the pattern, it's an error. */
+
+c = *(++ptr);
+if (c == 0) *errorptr = ERR1;
+
+/* Non-alphamerics are literals. For digits or letters, do an initial lookup in
+a table. A non-zero result is something that can be returned immediately.
+Otherwise further processing may be required. */
+
+#if !EBCDIC    /* ASCII coding */
+else if (c < '0' || c > 'z') {}                           /* Not alphameric */
+else if ((i = escapes[c - '0']) != 0) c = i;
+
+#else          /* EBCDIC coding */
+else if (c < 'a' || (ebcdic_chartab[c] & 0x0E) == 0) {}   /* Not alphameric */
+else if ((i = escapes[c - 0x48]) != 0)  c = i;
+#endif
+
+/* Escapes that need further processing, or are illegal. */
+
+else
+  {
+  const uschar *oldptr;
+  switch (c)
+    {
+    /* A number of Perl escapes are not handled by PCRE. We give an explicit
+    error. */
+
+    case 'l':
+    case 'L':
+    case 'N':
+    case 'u':
+    case 'U':
+    *errorptr = ERR37;
+    break;
+
+    /* The handling of escape sequences consisting of a string of digits
+    starting with one that is not zero is not straightforward. By experiment,
+    the way Perl works seems to be as follows:
+
+    Outside a character class, the digits are read as a decimal number. If the
+    number is less than 10, or if there are that many previous extracting
+    left brackets, then it is a back reference. Otherwise, up to three octal
+    digits are read to form an escaped byte. Thus \123 is likely to be octal
+    123 (cf \0123, which is octal 012 followed by the literal 3). If the octal
+    value is greater than 377, the least significant 8 bits are taken. Inside a
+    character class, \ followed by a digit is always an octal number. */
+
+    case '1': case '2': case '3': case '4': case '5':
+    case '6': case '7': case '8': case '9':
+
+    if (!isclass)
+      {
+      oldptr = ptr;
+      c -= '0';
+      while ((digitab[ptr[1]] & ctype_digit) != 0)
+        c = c * 10 + *(++ptr) - '0';
+      if (c < 10 || c <= bracount)
+        {
+        c = -(ESC_REF + c);
+        break;
+        }
+      ptr = oldptr;      /* Put the pointer back and fall through */
+      }
+
+    /* Handle an octal number following \. If the first digit is 8 or 9, Perl
+    generates a binary zero byte and treats the digit as a following literal.
+    Thus we have to pull back the pointer by one. */
+
+    if ((c = *ptr) >= '8')
+      {
+      ptr--;
+      c = 0;
+      break;
+      }
+
+    /* \0 always starts an octal number, but we may drop through to here with a
+    larger first octal digit. */
+
+    case '0':
+    c -= '0';
+    while(i++ < 2 && ptr[1] >= '0' && ptr[1] <= '7')
+        c = c * 8 + *(++ptr) - '0';
+    c &= 255;     /* Take least significant 8 bits */
+    break;
+
+    /* \x is complicated when UTF-8 is enabled. \x{ddd} is a character number
+    which can be greater than 0xff, but only if the ddd are hex digits. */
+
+    case 'x':
+#ifdef SUPPORT_UTF8
+    if (ptr[1] == '{' && (options & PCRE_UTF8) != 0)
+      {
+      const uschar *pt = ptr + 2;
+      register int count = 0;
+      c = 0;
+      while ((digitab[*pt] & ctype_xdigit) != 0)
+        {
+        int cc = *pt++;
+        count++;
+#if !EBCDIC    /* ASCII coding */
+        if (cc >= 'a') cc -= 32;               /* Convert to upper case */
+        c = c * 16 + cc - ((cc < 'A')? '0' : ('A' - 10));
+#else          /* EBCDIC coding */
+        if (cc >= 'a' && cc <= 'z') cc += 64;  /* Convert to upper case */
+        c = c * 16 + cc - ((cc >= '0')? '0' : ('A' - 10));
+#endif
+        }
+      if (*pt == '}')
+        {
+        if (c < 0 || count > 8) *errorptr = ERR34;
+        ptr = pt;
+        break;
+        }
+      /* If the sequence of hex digits does not end with '}', then we don't
+      recognize this construct; fall through to the normal \x handling. */
+      }
+#endif
+
+    /* Read just a single hex char */
+
+    c = 0;
+    while (i++ < 2 && (digitab[ptr[1]] & ctype_xdigit) != 0)
+      {
+      int cc;                               /* Some compilers don't like ++ */
+      cc = *(++ptr);                        /* in initializers */
+#if !EBCDIC    /* ASCII coding */
+      if (cc >= 'a') cc -= 32;              /* Convert to upper case */
+      c = c * 16 + cc - ((cc < 'A')? '0' : ('A' - 10));
+#else          /* EBCDIC coding */
+      if (cc <= 'z') cc += 64;              /* Convert to upper case */
+      c = c * 16 + cc - ((cc >= '0')? '0' : ('A' - 10));
+#endif
+      }
+    break;
+
+    /* Other special escapes not starting with a digit are straightforward */
+
+    case 'c':
+    c = *(++ptr);
+    if (c == 0)
+      {
+      *errorptr = ERR2;
+      return 0;
+      }
+
+    /* A letter is upper-cased; then the 0x40 bit is flipped. This coding
+    is ASCII-specific, but then the whole concept of \cx is ASCII-specific.
+    (However, an EBCDIC equivalent has now been added.) */
+
+#if !EBCDIC    /* ASCII coding */
+    if (c >= 'a' && c <= 'z') c -= 32;
+    c ^= 0x40;
+#else          /* EBCDIC coding */
+    if (c >= 'a' && c <= 'z') c += 64;
+    c ^= 0xC0;
+#endif
+    break;
+
+    /* PCRE_EXTRA enables extensions to Perl in the matter of escapes. Any
+    other alphameric following \ is an error if PCRE_EXTRA was set; otherwise,
+    for Perl compatibility, it is a literal. This code looks a bit odd, but
+    there used to be some cases other than the default, and there may be again
+    in future, so I haven't "optimized" it. */
+
+    default:
+    if ((options & PCRE_EXTRA) != 0) switch(c)
+      {
+      default:
+      *errorptr = ERR3;
+      break;
+      }
+    break;
+    }
+  }
+
+*ptrptr = ptr;
+return c;
+}
+
+
+
+#ifdef SUPPORT_UCP
+/*************************************************
+*               Handle \P and \p                 *
+*************************************************/
+
+/* This function is called after \P or \p has been encountered, provided that
+PCRE is compiled with support for Unicode properties. On entry, ptrptr is
+pointing at the P or p. On exit, it is pointing at the final character of the
+escape sequence.
+
+Argument:
+  ptrptr     points to the pattern position pointer
+  negptr     points to a boolean that is set TRUE for negation else FALSE
+  errorptr   points to the pointer to the error message
+
+Returns:     value from ucp_type_table, or -1 for an invalid type
+*/
+
+static int
+get_ucp(const uschar **ptrptr, BOOL *negptr, const char **errorptr)
+{
+int c, i, bot, top;
+const uschar *ptr = *ptrptr;
+char name[4];
+
+c = *(++ptr);
+if (c == 0) goto ERROR_RETURN;
+
+*negptr = FALSE;
+
+/* \P or \p can be followed by a one- or two-character name in {}, optionally
+preceded by ^ for negation. */
+
+if (c == '{')
+  {
+  if (ptr[1] == '^')
+    {
+    *negptr = TRUE;
+    ptr++;
+    }
+  for (i = 0; i <= 2; i++)
+    {
+    c = *(++ptr);
+    if (c == 0) goto ERROR_RETURN;
+    if (c == '}') break;
+    name[i] = c;
+    }
+  if (c !='}')   /* Try to distinguish error cases */
+    {
+    while (*(++ptr) != 0 && *ptr != '}');
+    if (*ptr == '}') goto UNKNOWN_RETURN; else goto ERROR_RETURN;
+    }
+  name[i] = 0;
+  }
+
+/* Otherwise there is just one following character */
+
+else
+  {
+  name[0] = c;
+  name[1] = 0;
+  }
+
+*ptrptr = ptr;
+
+/* Search for a recognized property name using binary chop */
+
+bot = 0;
+top = sizeof(utt)/sizeof(ucp_type_table);
+
+while (bot < top)
+  {
+  i = (bot + top)/2;
+  c = strcmp(name, utt[i].name);
+  if (c == 0) return utt[i].value;
+  if (c > 0) bot = i + 1; else top = i;
+  }
+
+UNKNOWN_RETURN:
+*errorptr = ERR47;
+*ptrptr = ptr;
+return -1;
+
+ERROR_RETURN:
+*errorptr = ERR46;
+*ptrptr = ptr;
+return -1;
+}
+#endif
+
+
+
+
+/*************************************************
+*            Check for counted repeat            *
+*************************************************/
+
+/* This function is called when a '{' is encountered in a place where it might
+start a quantifier. It looks ahead to see if it really is a quantifier or not.
+It is only a quantifier if it is one of the forms {ddd} {ddd,} or {ddd,ddd}
+where the ddds are digits.
+
+Arguments:
+  p         pointer to the first char after '{'
+
+Returns:    TRUE or FALSE
+*/
+
+static BOOL
+is_counted_repeat(const uschar *p)
+{
+if ((digitab[*p++] & ctype_digit) == 0) return FALSE;
+while ((digitab[*p] & ctype_digit) != 0) p++;
+if (*p == '}') return TRUE;
+
+if (*p++ != ',') return FALSE;
+if (*p == '}') return TRUE;
+
+if ((digitab[*p++] & ctype_digit) == 0) return FALSE;
+while ((digitab[*p] & ctype_digit) != 0) p++;
+
+return (*p == '}');
+}
+
+
+
+/*************************************************
+*         Read repeat counts                     *
+*************************************************/
+
+/* Read an item of the form {n,m} and return the values. This is called only
+after is_counted_repeat() has confirmed that a repeat-count quantifier exists,
+so the syntax is guaranteed to be correct, but we need to check the values.
+
+Arguments:
+  p          pointer to first char after '{'
+  minp       pointer to int for min
+  maxp       pointer to int for max
+             returned as -1 if no max
+  errorptr   points to pointer to error message
+
+Returns:     pointer to '}' on success;
+             current ptr on error, with errorptr set
+*/
+
+static const uschar *
+read_repeat_counts(const uschar *p, int *minp, int *maxp, const char **errorptr)
+{
+int min = 0;
+int max = -1;
+
+/* Read the minimum value and do a paranoid check: a negative value indicates
+an integer overflow. */
+
+while ((digitab[*p] & ctype_digit) != 0) min = min * 10 + *p++ - '0';
+if (min < 0 || min > 65535)
+  {
+  *errorptr = ERR5;
+  return p;
+  }
+
+/* Read the maximum value if there is one, and again do a paranoid on its size.
+Also, max must not be less than min. */
+
+if (*p == '}') max = min; else
+  {
+  if (*(++p) != '}')
+    {
+    max = 0;
+    while((digitab[*p] & ctype_digit) != 0) max = max * 10 + *p++ - '0';
+    if (max < 0 || max > 65535)
+      {
+      *errorptr = ERR5;
+      return p;
+      }
+    if (max < min)
+      {
+      *errorptr = ERR4;
+      return p;
+      }
+    }
+  }
+
+/* Fill in the required variables, and pass back the pointer to the terminating
+'}'. */
+
+*minp = min;
+*maxp = max;
+return p;
+}
+
+
+
+/*************************************************
+*      Find first significant op code            *
+*************************************************/
+
+/* This is called by several functions that scan a compiled expression looking
+for a fixed first character, or an anchoring op code etc. It skips over things
+that do not influence this. For some calls, a change of option is important.
+For some calls, it makes sense to skip negative forward and all backward
+assertions, and also the \b assertion; for others it does not.
+
+Arguments:
+  code         pointer to the start of the group
+  options      pointer to external options
+  optbit       the option bit whose changing is significant, or
+                 zero if none are
+  skipassert   TRUE if certain assertions are to be skipped
+
+Returns:       pointer to the first significant opcode
+*/
+
+static const uschar*
+first_significant_code(const uschar *code, int *options, int optbit,
+  BOOL skipassert)
+{
+for (;;)
+  {
+  switch ((int)*code)
+    {
+    case OP_OPT:
+    if (optbit > 0 && ((int)code[1] & optbit) != (*options & optbit))
+      *options = (int)code[1];
+    code += 2;
+    break;
+
+    case OP_ASSERT_NOT:
+    case OP_ASSERTBACK:
+    case OP_ASSERTBACK_NOT:
+    if (!skipassert) return code;
+    do code += GET(code, 1); while (*code == OP_ALT);
+    code += OP_lengths[*code];
+    break;
+
+    case OP_WORD_BOUNDARY:
+    case OP_NOT_WORD_BOUNDARY:
+    if (!skipassert) return code;
+    /* Fall through */
+
+    case OP_CALLOUT:
+    case OP_CREF:
+    case OP_BRANUMBER:
+    code += OP_lengths[*code];
+    break;
+
+    default:
+    return code;
+    }
+  }
+/* Control never reaches here */
+}
+
+
+
+
+/*************************************************
+*        Find the fixed length of a pattern      *
+*************************************************/
+
+/* Scan a pattern and compute the fixed length of subject that will match it,
+if the length is fixed. This is needed for dealing with backward assertions.
+In UTF8 mode, the result is in characters rather than bytes.
+
+Arguments:
+  code     points to the start of the pattern (the bracket)
+  options  the compiling options
+
+Returns:   the fixed length, or -1 if there is no fixed length,
+             or -2 if \C was encountered
+*/
+
+static int
+find_fixedlength(uschar *code, int options)
+{
+int length = -1;
+
+register int branchlength = 0;
+register uschar *cc = code + 1 + LINK_SIZE;
+
+/* Scan along the opcodes for this branch. If we get to the end of the
+branch, check the length against that of the other branches. */
+
+for (;;)
+  {
+  int d;
+  register int op = *cc;
+  if (op >= OP_BRA) op = OP_BRA;
+
+  switch (op)
+    {
+    case OP_BRA:
+    case OP_ONCE:
+    case OP_COND:
+    d = find_fixedlength(cc, options);
+    if (d < 0) return d;
+    branchlength += d;
+    do cc += GET(cc, 1); while (*cc == OP_ALT);
+    cc += 1 + LINK_SIZE;
+    break;
+
+    /* Reached end of a branch; if it's a ket it is the end of a nested
+    call. If it's ALT it is an alternation in a nested call. If it is
+    END it's the end of the outer call. All can be handled by the same code. */
+
+    case OP_ALT:
+    case OP_KET:
+    case OP_KETRMAX:
+    case OP_KETRMIN:
+    case OP_END:
+    if (length < 0) length = branchlength;
+      else if (length != branchlength) return -1;
+    if (*cc != OP_ALT) return length;
+    cc += 1 + LINK_SIZE;
+    branchlength = 0;
+    break;
+
+    /* Skip over assertive subpatterns */
+
+    case OP_ASSERT:
+    case OP_ASSERT_NOT:
+    case OP_ASSERTBACK:
+    case OP_ASSERTBACK_NOT:
+    do cc += GET(cc, 1); while (*cc == OP_ALT);
+    /* Fall through */
+
+    /* Skip over things that don't match chars */
+
+    case OP_REVERSE:
+    case OP_BRANUMBER:
+    case OP_CREF:
+    case OP_OPT:
+    case OP_CALLOUT:
+    case OP_SOD:
+    case OP_SOM:
+    case OP_EOD:
+    case OP_EODN:
+    case OP_CIRC:
+    case OP_DOLL:
+    case OP_NOT_WORD_BOUNDARY:
+    case OP_WORD_BOUNDARY:
+    cc += OP_lengths[*cc];
+    break;
+
+    /* Handle literal characters */
+
+    case OP_CHAR:
+    case OP_CHARNC:
+    branchlength++;
+    cc += 2;
+#ifdef SUPPORT_UTF8
+    if ((options & PCRE_UTF8) != 0)
+      {
+      while ((*cc & 0xc0) == 0x80) cc++;
+      }
+#endif
+    break;
+
+    /* Handle exact repetitions. The count is already in characters, but we
+    need to skip over a multibyte character in UTF8 mode.  */
+
+    case OP_EXACT:
+    branchlength += GET2(cc,1);
+    cc += 4;
+#ifdef SUPPORT_UTF8
+    if ((options & PCRE_UTF8) != 0)
+      {
+      while((*cc & 0x80) == 0x80) cc++;
+      }
+#endif
+    break;
+
+    case OP_TYPEEXACT:
+    branchlength += GET2(cc,1);
+    cc += 4;
+    break;
+
+    /* Handle single-char matchers */
+
+    case OP_PROP:
+    case OP_NOTPROP:
+    cc++;
+    /* Fall through */
+
+    case OP_NOT_DIGIT:
+    case OP_DIGIT:
+    case OP_NOT_WHITESPACE:
+    case OP_WHITESPACE:
+    case OP_NOT_WORDCHAR:
+    case OP_WORDCHAR:
+    case OP_ANY:
+    branchlength++;
+    cc++;
+    break;
+
+    /* The single-byte matcher isn't allowed */
+
+    case OP_ANYBYTE:
+    return -2;
+
+    /* Check a class for variable quantification */
+
+#ifdef SUPPORT_UTF8
+    case OP_XCLASS:
+    cc += GET(cc, 1) - 33;
+    /* Fall through */
+#endif
+
+    case OP_CLASS:
+    case OP_NCLASS:
+    cc += 33;
+
+    switch (*cc)
+      {
+      case OP_CRSTAR:
+      case OP_CRMINSTAR:
+      case OP_CRQUERY:
+      case OP_CRMINQUERY:
+      return -1;
+
+      case OP_CRRANGE:
+      case OP_CRMINRANGE:
+      if (GET2(cc,1) != GET2(cc,3)) return -1;
+      branchlength += GET2(cc,1);
+      cc += 5;
+      break;
+
+      default:
+      branchlength++;
+      }
+    break;
+
+    /* Anything else is variable length */
+
+    default:
+    return -1;
+    }
+  }
+/* Control never gets here */
+}
+
+
+
+
+/*************************************************
+*    Scan compiled regex for numbered bracket    *
+*************************************************/
+
+/* This little function scans through a compiled pattern until it finds a
+capturing bracket with the given number.
+
+Arguments:
+  code        points to start of expression
+  utf8        TRUE in UTF-8 mode
+  number      the required bracket number
+
+Returns:      pointer to the opcode for the bracket, or NULL if not found
+*/
+
+static const uschar *
+find_bracket(const uschar *code, BOOL utf8, int number)
+{
+#ifndef SUPPORT_UTF8
+utf8 = utf8;               /* Stop pedantic compilers complaining */
+#endif
+
+for (;;)
+  {
+  register int c = *code;
+  if (c == OP_END) return NULL;
+  else if (c > OP_BRA)
+    {
+    int n = c - OP_BRA;
+    if (n > EXTRACT_BASIC_MAX) n = GET2(code, 2+LINK_SIZE);
+    if (n == number) return (uschar *)code;
+    code += OP_lengths[OP_BRA];
+    }
+  else
+    {
+    code += OP_lengths[c];
+
+#ifdef SUPPORT_UTF8
+
+    /* In UTF-8 mode, opcodes that are followed by a character may be followed
+    by a multi-byte character. The length in the table is a minimum, so we have
+    to scan along to skip the extra bytes. All opcodes are less than 128, so we
+    can use relatively efficient code. */
+
+    if (utf8) switch(c)
+      {
+      case OP_CHAR:
+      case OP_CHARNC:
+      case OP_EXACT:
+      case OP_UPTO:
+      case OP_MINUPTO:
+      case OP_STAR:
+      case OP_MINSTAR:
+      case OP_PLUS:
+      case OP_MINPLUS:
+      case OP_QUERY:
+      case OP_MINQUERY:
+      while ((*code & 0xc0) == 0x80) code++;
+      break;
+
+      /* XCLASS is used for classes that cannot be represented just by a bit
+      map. This includes negated single high-valued characters. The length in
+      the table is zero; the actual length is stored in the compiled code. */
+
+      case OP_XCLASS:
+      code += GET(code, 1) + 1;
+      break;
+      }
+#endif
+    }
+  }
+}
+
+
+
+/*************************************************
+*   Scan compiled regex for recursion reference  *
+*************************************************/
+
+/* This little function scans through a compiled pattern until it finds an
+instance of OP_RECURSE.
+
+Arguments:
+  code        points to start of expression
+  utf8        TRUE in UTF-8 mode
+
+Returns:      pointer to the opcode for OP_RECURSE, or NULL if not found
+*/
+
+static const uschar *
+find_recurse(const uschar *code, BOOL utf8)
+{
+#ifndef SUPPORT_UTF8
+utf8 = utf8;               /* Stop pedantic compilers complaining */
+#endif
+
+for (;;)
+  {
+  register int c = *code;
+  if (c == OP_END) return NULL;
+  else if (c == OP_RECURSE) return code;
+  else if (c > OP_BRA)
+    {
+    code += OP_lengths[OP_BRA];
+    }
+  else
+    {
+    code += OP_lengths[c];
+
+#ifdef SUPPORT_UTF8
+
+    /* In UTF-8 mode, opcodes that are followed by a character may be followed
+    by a multi-byte character. The length in the table is a minimum, so we have
+    to scan along to skip the extra bytes. All opcodes are less than 128, so we
+    can use relatively efficient code. */
+
+    if (utf8) switch(c)
+      {
+      case OP_CHAR:
+      case OP_CHARNC:
+      case OP_EXACT:
+      case OP_UPTO:
+      case OP_MINUPTO:
+      case OP_STAR:
+      case OP_MINSTAR:
+      case OP_PLUS:
+      case OP_MINPLUS:
+      case OP_QUERY:
+      case OP_MINQUERY:
+      while ((*code & 0xc0) == 0x80) code++;
+      break;
+
+      /* XCLASS is used for classes that cannot be represented just by a bit
+      map. This includes negated single high-valued characters. The length in
+      the table is zero; the actual length is stored in the compiled code. */
+
+      case OP_XCLASS:
+      code += GET(code, 1) + 1;
+      break;
+      }
+#endif
+    }
+  }
+}
+
+
+
+/*************************************************
+*    Scan compiled branch for non-emptiness      *
+*************************************************/
+
+/* This function scans through a branch of a compiled pattern to see whether it
+can match the empty string or not. It is called only from could_be_empty()
+below. Note that first_significant_code() skips over assertions. If we hit an
+unclosed bracket, we return "empty" - this means we've struck an inner bracket
+whose current branch will already have been scanned.
+
+Arguments:
+  code        points to start of search
+  endcode     points to where to stop
+  utf8        TRUE if in UTF8 mode
+
+Returns:      TRUE if what is matched could be empty
+*/
+
+static BOOL
+could_be_empty_branch(const uschar *code, const uschar *endcode, BOOL utf8)
+{
+register int c;
+for (code = first_significant_code(code + 1 + LINK_SIZE, NULL, 0, TRUE);
+     code < endcode;
+     code = first_significant_code(code + OP_lengths[c], NULL, 0, TRUE))
+  {
+  const uschar *ccode;
+
+  c = *code;
+
+  if (c >= OP_BRA)
+    {
+    BOOL empty_branch;
+    if (GET(code, 1) == 0) return TRUE;    /* Hit unclosed bracket */
+
+    /* Scan a closed bracket */
+
+    empty_branch = FALSE;
+    do
+      {
+      if (!empty_branch && could_be_empty_branch(code, endcode, utf8))
+        empty_branch = TRUE;
+      code += GET(code, 1);
+      }
+    while (*code == OP_ALT);
+    if (!empty_branch) return FALSE;   /* All branches are non-empty */
+    code += 1 + LINK_SIZE;
+    c = *code;
+    }
+
+  else switch (c)
+    {
+    /* Check for quantifiers after a class */
+
+#ifdef SUPPORT_UTF8
+    case OP_XCLASS:
+    ccode = code + GET(code, 1);
+    goto CHECK_CLASS_REPEAT;
+#endif
+
+    case OP_CLASS:
+    case OP_NCLASS:
+    ccode = code + 33;
+
+#ifdef SUPPORT_UTF8
+    CHECK_CLASS_REPEAT:
+#endif
+
+    switch (*ccode)
+      {
+      case OP_CRSTAR:            /* These could be empty; continue */
+      case OP_CRMINSTAR:
+      case OP_CRQUERY:
+      case OP_CRMINQUERY:
+      break;
+
+      default:                   /* Non-repeat => class must match */
+      case OP_CRPLUS:            /* These repeats aren't empty */
+      case OP_CRMINPLUS:
+      return FALSE;
+
+      case OP_CRRANGE:
+      case OP_CRMINRANGE:
+      if (GET2(ccode, 1) > 0) return FALSE;  /* Minimum > 0 */
+      break;
+      }
+    break;
+
+    /* Opcodes that must match a character */
+
+    case OP_PROP:
+    case OP_NOTPROP:
+    case OP_EXTUNI:
+    case OP_NOT_DIGIT:
+    case OP_DIGIT:
+    case OP_NOT_WHITESPACE:
+    case OP_WHITESPACE:
+    case OP_NOT_WORDCHAR:
+    case OP_WORDCHAR:
+    case OP_ANY:
+    case OP_ANYBYTE:
+    case OP_CHAR:
+    case OP_CHARNC:
+    case OP_NOT:
+    case OP_PLUS:
+    case OP_MINPLUS:
+    case OP_EXACT:
+    case OP_NOTPLUS:
+    case OP_NOTMINPLUS:
+    case OP_NOTEXACT:
+    case OP_TYPEPLUS:
+    case OP_TYPEMINPLUS:
+    case OP_TYPEEXACT:
+    return FALSE;
+
+    /* End of branch */
+
+    case OP_KET:
+    case OP_KETRMAX:
+    case OP_KETRMIN:
+    case OP_ALT:
+    return TRUE;
+
+    /* In UTF-8 mode, STAR, MINSTAR, QUERY, MINQUERY, UPTO, and MINUPTO  may be
+    followed by a multibyte character */
+
+#ifdef SUPPORT_UTF8
+    case OP_STAR:
+    case OP_MINSTAR:
+    case OP_QUERY:
+    case OP_MINQUERY:
+    case OP_UPTO:
+    case OP_MINUPTO:
+    if (utf8) while ((code[2] & 0xc0) == 0x80) code++;
+    break;
+#endif
+    }
+  }
+
+return TRUE;
+}
+
+
+
+/*************************************************
+*    Scan compiled regex for non-emptiness       *
+*************************************************/
+
+/* This function is called to check for left recursive calls. We want to check
+the current branch of the current pattern to see if it could match the empty
+string. If it could, we must look outwards for branches at other levels,
+stopping when we pass beyond the bracket which is the subject of the recursion.
+
+Arguments:
+  code        points to start of the recursion
+  endcode     points to where to stop (current RECURSE item)
+  bcptr       points to the chain of current (unclosed) branch starts
+  utf8        TRUE if in UTF-8 mode
+
+Returns:      TRUE if what is matched could be empty
+*/
+
+static BOOL
+could_be_empty(const uschar *code, const uschar *endcode, branch_chain *bcptr,
+  BOOL utf8)
+{
+while (bcptr != NULL && bcptr->current >= code)
+  {
+  if (!could_be_empty_branch(bcptr->current, endcode, utf8)) return FALSE;
+  bcptr = bcptr->outer;
+  }
+return TRUE;
+}
+
+
+
+/*************************************************
+*           Check for POSIX class syntax         *
+*************************************************/
+
+/* This function is called when the sequence "[:" or "[." or "[=" is
+encountered in a character class. It checks whether this is followed by an
+optional ^ and then a sequence of letters, terminated by a matching ":]" or
+".]" or "=]".
+
+Argument:
+  ptr      pointer to the initial [
+  endptr   where to return the end pointer
+  cd       pointer to compile data
+
+Returns:   TRUE or FALSE
+*/
+
+static BOOL
+check_posix_syntax(const uschar *ptr, const uschar **endptr, compile_data *cd)
+{
+int terminator;          /* Don't combine these lines; the Solaris cc */
+terminator = *(++ptr);   /* compiler warns about "non-constant" initializer. */
+if (*(++ptr) == '^') ptr++;
+while ((cd->ctypes[*ptr] & ctype_letter) != 0) ptr++;
+if (*ptr == terminator && ptr[1] == ']')
+  {
+  *endptr = ptr;
+  return TRUE;
+  }
+return FALSE;
+}
+
+
+
+
+/*************************************************
+*          Check POSIX class name                *
+*************************************************/
+
+/* This function is called to check the name given in a POSIX-style class entry
+such as [:alnum:].
+
+Arguments:
+  ptr        points to the first letter
+  len        the length of the name
+
+Returns:     a value representing the name, or -1 if unknown
+*/
+
+static int
+check_posix_name(const uschar *ptr, int len)
+{
+register int yield = 0;
+while (posix_name_lengths[yield] != 0)
+  {
+  if (len == posix_name_lengths[yield] &&
+    strncmp((const char *)ptr, posix_names[yield], len) == 0) return yield;
+  yield++;
+  }
+return -1;
+}
+
+
+/*************************************************
+*    Adjust OP_RECURSE items in repeated group   *
+*************************************************/
+
+/* OP_RECURSE items contain an offset from the start of the regex to the group
+that is referenced. This means that groups can be replicated for fixed
+repetition simply by copying (because the recursion is allowed to refer to
+earlier groups that are outside the current group). However, when a group is
+optional (i.e. the minimum quantifier is zero), OP_BRAZERO is inserted before
+it, after it has been compiled. This means that any OP_RECURSE items within it
+that refer to the group itself or any contained groups have to have their
+offsets adjusted. That is the job of this function. Before it is called, the
+partially compiled regex must be temporarily terminated with OP_END.
+
+Arguments:
+  group      points to the start of the group
+  adjust     the amount by which the group is to be moved
+  utf8       TRUE in UTF-8 mode
+  cd         contains pointers to tables etc.
+
+Returns:     nothing
+*/
+
+static void
+adjust_recurse(uschar *group, int adjust, BOOL utf8, compile_data *cd)
+{
+uschar *ptr = group;
+while ((ptr = (uschar *)find_recurse(ptr, utf8)) != NULL)
+  {
+  int offset = GET(ptr, 1);
+  if (cd->start_code + offset >= group) PUT(ptr, 1, offset + adjust);
+  ptr += 1 + LINK_SIZE;
+  }
+}
+
+
+
+/*************************************************
+*        Insert an automatic callout point       *
+*************************************************/
+
+/* This function is called when the PCRE_AUTO_CALLOUT option is set, to insert
+callout points before each pattern item.
+
+Arguments:
+  code           current code pointer
+  ptr            current pattern pointer
+  cd             pointers to tables etc
+
+Returns:         new code pointer
+*/
+
+static uschar *
+auto_callout(uschar *code, const uschar *ptr, compile_data *cd)
+{
+*code++ = OP_CALLOUT;
+*code++ = 255;
+PUT(code, 0, ptr - cd->start_pattern);  /* Pattern offset */
+PUT(code, LINK_SIZE, 0);                /* Default length */
+return code + 2*LINK_SIZE;
+}
+
+
+
+/*************************************************
+*         Complete a callout item                *
+*************************************************/
+
+/* A callout item contains the length of the next item in the pattern, which
+we can't fill in till after we have reached the relevant point. This is used
+for both automatic and manual callouts.
+
+Arguments:
+  previous_callout   points to previous callout item
+  ptr                current pattern pointer
+  cd                 pointers to tables etc
+
+Returns:             nothing
+*/
+
+static void
+complete_callout(uschar *previous_callout, const uschar *ptr, compile_data *cd)
+{
+int length = ptr - cd->start_pattern - GET(previous_callout, 2);
+PUT(previous_callout, 2 + LINK_SIZE, length);
+}
+
+
+
+#ifdef SUPPORT_UCP
+/*************************************************
+*           Get othercase range                  *
+*************************************************/
+
+/* This function is passed the start and end of a class range, in UTF-8 mode
+with UCP support. It searches up the characters, looking for internal ranges of
+characters in the "other" case. Each call returns the next one, updating the
+start address.
+
+Arguments:
+  cptr        points to starting character value; updated
+  d           end value
+  ocptr       where to put start of othercase range
+  odptr       where to put end of othercase range
+
+Yield:        TRUE when range returned; FALSE when no more
+*/
+
+static BOOL
+get_othercase_range(int *cptr, int d, int *ocptr, int *odptr)
+{
+int c, chartype, othercase, next;
+
+for (c = *cptr; c <= d; c++)
+  {
+  if (ucp_findchar(c, &chartype, &othercase) == ucp_L && othercase != 0) break;
+  }
+
+if (c > d) return FALSE;
+
+*ocptr = othercase;
+next = othercase + 1;
+
+for (++c; c <= d; c++)
+  {
+  if (ucp_findchar(c, &chartype, &othercase) != ucp_L || othercase != next)
+    break;
+  next++;
+  }
+
+*odptr = next - 1;
+*cptr = c;
+
+return TRUE;
+}
+#endif  /* SUPPORT_UCP */
+
+
+/*************************************************
+*           Compile one branch                   *
+*************************************************/
+
+/* Scan the pattern, compiling it into the code vector. If the options are
+changed during the branch, the pointer is used to change the external options
+bits.
+
+Arguments:
+  optionsptr     pointer to the option bits
+  brackets       points to number of extracting brackets used
+  codeptr        points to the pointer to the current code point
+  ptrptr         points to the current pattern pointer
+  errorptr       points to pointer to error message
+  firstbyteptr   set to initial literal character, or < 0 (REQ_UNSET, REQ_NONE)
+  reqbyteptr     set to the last literal character required, else < 0
+  bcptr          points to current branch chain
+  cd             contains pointers to tables etc.
+
+Returns:         TRUE on success
+                 FALSE, with *errorptr set on error
+*/
+
+static BOOL
+compile_branch(int *optionsptr, int *brackets, uschar **codeptr,
+  const uschar **ptrptr, const char **errorptr, int *firstbyteptr,
+  int *reqbyteptr, branch_chain *bcptr, compile_data *cd)
+{
+int repeat_type, op_type;
+int repeat_min = 0, repeat_max = 0;      /* To please picky compilers */
+int bravalue = 0;
+int greedy_default, greedy_non_default;
+int firstbyte, reqbyte;
+int zeroreqbyte, zerofirstbyte;
+int req_caseopt, reqvary, tempreqvary;
+int condcount = 0;
+int options = *optionsptr;
+int after_manual_callout = 0;
+register int c;
+register uschar *code = *codeptr;
+uschar *tempcode;
+BOOL inescq = FALSE;
+BOOL groupsetfirstbyte = FALSE;
+const uschar *ptr = *ptrptr;
+const uschar *tempptr;
+uschar *previous = NULL;
+uschar *previous_callout = NULL;
+uschar classbits[32];
+
+#ifdef SUPPORT_UTF8
+BOOL class_utf8;
+BOOL utf8 = (options & PCRE_UTF8) != 0;
+uschar *class_utf8data;
+uschar utf8_char[6];
+#else
+BOOL utf8 = FALSE;
+#endif
+
+/* Set up the default and non-default settings for greediness */
+
+greedy_default = ((options & PCRE_UNGREEDY) != 0);
+greedy_non_default = greedy_default ^ 1;
+
+/* Initialize no first byte, no required byte. REQ_UNSET means "no char
+matching encountered yet". It gets changed to REQ_NONE if we hit something that
+matches a non-fixed char first char; reqbyte just remains unset if we never
+find one.
+
+When we hit a repeat whose minimum is zero, we may have to adjust these values
+to take the zero repeat into account. This is implemented by setting them to
+zerofirstbyte and zeroreqbyte when such a repeat is encountered. The individual
+item types that can be repeated set these backoff variables appropriately. */
+
+firstbyte = reqbyte = zerofirstbyte = zeroreqbyte = REQ_UNSET;
+
+/* The variable req_caseopt contains either the REQ_CASELESS value or zero,
+according to the current setting of the caseless flag. REQ_CASELESS is a bit
+value > 255. It is added into the firstbyte or reqbyte variables to record the
+case status of the value. This is used only for ASCII characters. */
+
+req_caseopt = ((options & PCRE_CASELESS) != 0)? REQ_CASELESS : 0;
+
+/* Switch on next character until the end of the branch */
+
+for (;; ptr++)
+  {
+  BOOL negate_class;
+  BOOL possessive_quantifier;
+  BOOL is_quantifier;
+  int class_charcount;
+  int class_lastchar;
+  int newoptions;
+  int recno;
+  int skipbytes;
+  int subreqbyte;
+  int subfirstbyte;
+  int mclength;
+  uschar mcbuffer[8];
+
+  /* Next byte in the pattern */
+
+  c = *ptr;
+
+  /* If in \Q...\E, check for the end; if not, we have a literal */
+
+  if (inescq && c != 0)
+    {
+    if (c == '\\' && ptr[1] == 'E')
+      {
+      inescq = FALSE;
+      ptr++;
+      continue;
+      }
+    else
+      {
+      if (previous_callout != NULL)
+        {
+        complete_callout(previous_callout, ptr, cd);
+        previous_callout = NULL;
+        }
+      if ((options & PCRE_AUTO_CALLOUT) != 0)
+        {
+        previous_callout = code;
+        code = auto_callout(code, ptr, cd);
+        }
+      goto NORMAL_CHAR;
+      }
+    }
+
+  /* Fill in length of a previous callout, except when the next thing is
+  a quantifier. */
+
+  is_quantifier = c == '*' || c == '+' || c == '?' ||
+    (c == '{' && is_counted_repeat(ptr+1));
+
+  if (!is_quantifier && previous_callout != NULL &&
+       after_manual_callout-- <= 0)
+    {
+    complete_callout(previous_callout, ptr, cd);
+    previous_callout = NULL;
+    }
+
+  /* In extended mode, skip white space and comments */
+
+  if ((options & PCRE_EXTENDED) != 0)
+    {
+    if ((cd->ctypes[c] & ctype_space) != 0) continue;
+    if (c == '#')
+      {
+      /* The space before the ; is to avoid a warning on a silly compiler
+      on the Macintosh. */
+      while ((c = *(++ptr)) != 0 && c != NEWLINE) ;
+      if (c != 0) continue;   /* Else fall through to handle end of string */
+      }
+    }
+
+  /* No auto callout for quantifiers. */
+
+  if ((options & PCRE_AUTO_CALLOUT) != 0 && !is_quantifier)
+    {
+    previous_callout = code;
+    code = auto_callout(code, ptr, cd);
+    }
+
+  switch(c)
+    {
+    /* The branch terminates at end of string, |, or ). */
+
+    case 0:
+    case '|':
+    case ')':
+    *firstbyteptr = firstbyte;
+    *reqbyteptr = reqbyte;
+    *codeptr = code;
+    *ptrptr = ptr;
+    return TRUE;
+
+    /* Handle single-character metacharacters. In multiline mode, ^ disables
+    the setting of any following char as a first character. */
+
+    case '^':
+    if ((options & PCRE_MULTILINE) != 0)
+      {
+      if (firstbyte == REQ_UNSET) firstbyte = REQ_NONE;
+      }
+    previous = NULL;
+    *code++ = OP_CIRC;
+    break;
+
+    case '$':
+    previous = NULL;
+    *code++ = OP_DOLL;
+    break;
+
+    /* There can never be a first char if '.' is first, whatever happens about
+    repeats. The value of reqbyte doesn't change either. */
+
+    case '.':
+    if (firstbyte == REQ_UNSET) firstbyte = REQ_NONE;
+    zerofirstbyte = firstbyte;
+    zeroreqbyte = reqbyte;
+    previous = code;
+    *code++ = OP_ANY;
+    break;
+
+    /* Character classes. If the included characters are all < 255 in value, we
+    build a 32-byte bitmap of the permitted characters, except in the special
+    case where there is only one such character. For negated classes, we build
+    the map as usual, then invert it at the end. However, we use a different
+    opcode so that data characters > 255 can be handled correctly.
+
+    If the class contains characters outside the 0-255 range, a different
+    opcode is compiled. It may optionally have a bit map for characters < 256,
+    but those above are are explicitly listed afterwards. A flag byte tells
+    whether the bitmap is present, and whether this is a negated class or not.
+    */
+
+    case '[':
+    previous = code;
+
+    /* PCRE supports POSIX class stuff inside a class. Perl gives an error if
+    they are encountered at the top level, so we'll do that too. */
+
+    if ((ptr[1] == ':' || ptr[1] == '.' || ptr[1] == '=') &&
+        check_posix_syntax(ptr, &tempptr, cd))
+      {
+      *errorptr = (ptr[1] == ':')? ERR13 : ERR31;
+      goto FAILED;
+      }
+
+    /* If the first character is '^', set the negation flag and skip it. */
+
+    if ((c = *(++ptr)) == '^')
+      {
+      negate_class = TRUE;
+      c = *(++ptr);
+      }
+    else
+      {
+      negate_class = FALSE;
+      }
+
+    /* Keep a count of chars with values < 256 so that we can optimize the case
+    of just a single character (as long as it's < 256). For higher valued UTF-8
+    characters, we don't yet do any optimization. */
+
+    class_charcount = 0;
+    class_lastchar = -1;
+
+#ifdef SUPPORT_UTF8
+    class_utf8 = FALSE;                       /* No chars >= 256 */
+    class_utf8data = code + LINK_SIZE + 34;   /* For UTF-8 items */
+#endif
+
+    /* Initialize the 32-char bit map to all zeros. We have to build the
+    map in a temporary bit of store, in case the class contains only 1
+    character (< 256), because in that case the compiled code doesn't use the
+    bit map. */
+
+    memset(classbits, 0, 32 * sizeof(uschar));
+
+    /* Process characters until ] is reached. By writing this as a "do" it
+    means that an initial ] is taken as a data character. The first pass
+    through the regex checked the overall syntax, so we don't need to be very
+    strict here. At the start of the loop, c contains the first byte of the
+    character. */
+
+    do
+      {
+#ifdef SUPPORT_UTF8
+      if (utf8 && c > 127)
+        {                           /* Braces are required because the */
+        GETCHARLEN(c, ptr, ptr);    /* macro generates multiple statements */
+        }
+#endif
+
+      /* Inside \Q...\E everything is literal except \E */
+
+      if (inescq)
+        {
+        if (c == '\\' && ptr[1] == 'E')
+          {
+          inescq = FALSE;
+          ptr++;
+          continue;
+          }
+        else goto LONE_SINGLE_CHARACTER;
+        }
+
+      /* Handle POSIX class names. Perl allows a negation extension of the
+      form [:^name:]. A square bracket that doesn't match the syntax is
+      treated as a literal. We also recognize the POSIX constructions
+      [.ch.] and [=ch=] ("collating elements") and fault them, as Perl
+      5.6 and 5.8 do. */
+
+      if (c == '[' &&
+          (ptr[1] == ':' || ptr[1] == '.' || ptr[1] == '=') &&
+          check_posix_syntax(ptr, &tempptr, cd))
+        {
+        BOOL local_negate = FALSE;
+        int posix_class, i;
+        register const uschar *cbits = cd->cbits;
+
+        if (ptr[1] != ':')
+          {
+          *errorptr = ERR31;
+          goto FAILED;
+          }
+
+        ptr += 2;
+        if (*ptr == '^')
+          {
+          local_negate = TRUE;
+          ptr++;
+          }
+
+        posix_class = check_posix_name(ptr, tempptr - ptr);
+        if (posix_class < 0)
+          {
+          *errorptr = ERR30;
+          goto FAILED;
+          }
+
+        /* If matching is caseless, upper and lower are converted to
+        alpha. This relies on the fact that the class table starts with
+        alpha, lower, upper as the first 3 entries. */
+
+        if ((options & PCRE_CASELESS) != 0 && posix_class <= 2)
+          posix_class = 0;
+
+        /* Or into the map we are building up to 3 of the static class
+        tables, or their negations. The [:blank:] class sets up the same
+        chars as the [:space:] class (all white space). We remove the vertical
+        white space chars afterwards. */
+
+        posix_class *= 3;
+        for (i = 0; i < 3; i++)
+          {
+          BOOL blankclass = strncmp((char *)ptr, "blank", 5) == 0;
+          int taboffset = posix_class_maps[posix_class + i];
+          if (taboffset < 0) break;
+          if (local_negate)
+            {
+            if (i == 0)
+              for (c = 0; c < 32; c++) classbits[c] |= ~cbits[c+taboffset];
+            else
+              for (c = 0; c < 32; c++) classbits[c] &= ~cbits[c+taboffset];
+            if (blankclass) classbits[1] |= 0x3c;
+            }
+          else
+            {
+            for (c = 0; c < 32; c++) classbits[c] |= cbits[c+taboffset];
+            if (blankclass) classbits[1] &= ~0x3c;
+            }
+          }
+
+        ptr = tempptr + 1;
+        class_charcount = 10;  /* Set > 1; assumes more than 1 per class */
+        continue;    /* End of POSIX syntax handling */
+        }
+
+      /* Backslash may introduce a single character, or it may introduce one
+      of the specials, which just set a flag. Escaped items are checked for
+      validity in the pre-compiling pass. The sequence \b is a special case.
+      Inside a class (and only there) it is treated as backspace. Elsewhere
+      it marks a word boundary. Other escapes have preset maps ready to
+      or into the one we are building. We assume they have more than one
+      character in them, so set class_charcount bigger than one. */
+
+      if (c == '\\')
+        {
+        c = check_escape(&ptr, errorptr, *brackets, options, TRUE);
+
+        if (-c == ESC_b) c = '\b';       /* \b is backslash in a class */
+        else if (-c == ESC_X) c = 'X';   /* \X is literal X in a class */
+        else if (-c == ESC_Q)            /* Handle start of quoted string */
+          {
+          if (ptr[1] == '\\' && ptr[2] == 'E')
+            {
+            ptr += 2; /* avoid empty string */
+            }
+          else inescq = TRUE;
+          continue;
+          }
+
+        if (c < 0)
+          {
+          register const uschar *cbits = cd->cbits;
+          class_charcount += 2;     /* Greater than 1 is what matters */
+          switch (-c)
+            {
+            case ESC_d:
+            for (c = 0; c < 32; c++) classbits[c] |= cbits[c+cbit_digit];
+            continue;
+
+            case ESC_D:
+            for (c = 0; c < 32; c++) classbits[c] |= ~cbits[c+cbit_digit];
+            continue;
+
+            case ESC_w:
+            for (c = 0; c < 32; c++) classbits[c] |= cbits[c+cbit_word];
+            continue;
+
+            case ESC_W:
+            for (c = 0; c < 32; c++) classbits[c] |= ~cbits[c+cbit_word];
+            continue;
+
+            case ESC_s:
+            for (c = 0; c < 32; c++) classbits[c] |= cbits[c+cbit_space];
+            classbits[1] &= ~0x08;   /* Perl 5.004 onwards omits VT from \s */
+            continue;
+
+            case ESC_S:
+            for (c = 0; c < 32; c++) classbits[c] |= ~cbits[c+cbit_space];
+            classbits[1] |= 0x08;    /* Perl 5.004 onwards omits VT from \s */
+            continue;
+
+#ifdef SUPPORT_UCP
+            case ESC_p:
+            case ESC_P:
+              {
+              BOOL negated;
+              int property = get_ucp(&ptr, &negated, errorptr);
+              if (property < 0) goto FAILED;
+              class_utf8 = TRUE;
+              *class_utf8data++ = ((-c == ESC_p) != negated)?
+                XCL_PROP : XCL_NOTPROP;
+              *class_utf8data++ = property;
+              class_charcount -= 2;   /* Not a < 256 character */
+              }
+            continue;
+#endif
+
+            /* Unrecognized escapes are faulted if PCRE is running in its
+            strict mode. By default, for compatibility with Perl, they are
+            treated as literals. */
+
+            default:
+            if ((options & PCRE_EXTRA) != 0)
+              {
+              *errorptr = ERR7;
+              goto FAILED;
+              }
+            c = *ptr;              /* The final character */
+            class_charcount -= 2;  /* Undo the default count from above */
+            }
+          }
+
+        /* Fall through if we have a single character (c >= 0). This may be
+        > 256 in UTF-8 mode. */
+
+        }   /* End of backslash handling */
+
+      /* A single character may be followed by '-' to form a range. However,
+      Perl does not permit ']' to be the end of the range. A '-' character
+      here is treated as a literal. */
+
+      if (ptr[1] == '-' && ptr[2] != ']')
+        {
+        int d;
+        ptr += 2;
+
+#ifdef SUPPORT_UTF8
+        if (utf8)
+          {                           /* Braces are required because the */
+          GETCHARLEN(d, ptr, ptr);    /* macro generates multiple statements */
+          }
+        else
+#endif
+        d = *ptr;  /* Not UTF-8 mode */
+
+        /* The second part of a range can be a single-character escape, but
+        not any of the other escapes. Perl 5.6 treats a hyphen as a literal
+        in such circumstances. */
+
+        if (d == '\\')
+          {
+          const uschar *oldptr = ptr;
+          d = check_escape(&ptr, errorptr, *brackets, options, TRUE);
+
+          /* \b is backslash; \X is literal X; any other special means the '-'
+          was literal */
+
+          if (d < 0)
+            {
+            if (d == -ESC_b) d = '\b';
+            else if (d == -ESC_X) d = 'X'; else
+              {
+              ptr = oldptr - 2;
+              goto LONE_SINGLE_CHARACTER;  /* A few lines below */
+              }
+            }
+          }
+
+        /* The check that the two values are in the correct order happens in
+        the pre-pass. Optimize one-character ranges */
+
+        if (d == c) goto LONE_SINGLE_CHARACTER;  /* A few lines below */
+
+        /* In UTF-8 mode, if the upper limit is > 255, or > 127 for caseless
+        matching, we have to use an XCLASS with extra data items. Caseless
+        matching for characters > 127 is available only if UCP support is
+        available. */
+
+#ifdef SUPPORT_UTF8
+        if (utf8 && (d > 255 || ((options & PCRE_CASELESS) != 0 && d > 127)))
+          {
+          class_utf8 = TRUE;
+
+          /* With UCP support, we can find the other case equivalents of
+          the relevant characters. There may be several ranges. Optimize how
+          they fit with the basic range. */
+
+#ifdef SUPPORT_UCP
+          if ((options & PCRE_CASELESS) != 0)
+            {
+            int occ, ocd;
+            int cc = c;
+            int origd = d;
+            while (get_othercase_range(&cc, origd, &occ, &ocd))
+              {
+              if (occ >= c && ocd <= d) continue;  /* Skip embedded ranges */
+
+              if (occ < c  && ocd >= c - 1)        /* Extend the basic range */
+                {                                  /* if there is overlap,   */
+                c = occ;                           /* noting that if occ < c */
+                continue;                          /* we can't have ocd > d  */
+                }                                  /* because a subrange is  */
+              if (ocd > d && occ <= d + 1)         /* always shorter than    */
+                {                                  /* the basic range.       */
+                d = ocd;
+                continue;
+                }
+
+              if (occ == ocd)
+                {
+                *class_utf8data++ = XCL_SINGLE;
+                }
+              else
+                {
+                *class_utf8data++ = XCL_RANGE;
+                class_utf8data += ord2utf8(occ, class_utf8data);
+                }
+              class_utf8data += ord2utf8(ocd, class_utf8data);
+              }
+            }
+#endif  /* SUPPORT_UCP */
+
+          /* Now record the original range, possibly modified for UCP caseless
+          overlapping ranges. */
+
+          *class_utf8data++ = XCL_RANGE;
+          class_utf8data += ord2utf8(c, class_utf8data);
+          class_utf8data += ord2utf8(d, class_utf8data);
+
+          /* With UCP support, we are done. Without UCP support, there is no
+          caseless matching for UTF-8 characters > 127; we can use the bit map
+          for the smaller ones. */
+
+#ifdef SUPPORT_UCP
+          continue;    /* With next character in the class */
+#else
+          if ((options & PCRE_CASELESS) == 0 || c > 127) continue;
+
+          /* Adjust upper limit and fall through to set up the map */
+
+          d = 127;
+
+#endif  /* SUPPORT_UCP */
+          }
+#endif  /* SUPPORT_UTF8 */
+
+        /* We use the bit map for all cases when not in UTF-8 mode; else
+        ranges that lie entirely within 0-127 when there is UCP support; else
+        for partial ranges without UCP support. */
+
+        for (; c <= d; c++)
+          {
+          classbits[c/8] |= (1 << (c&7));
+          if ((options & PCRE_CASELESS) != 0)
+            {
+            int uc = cd->fcc[c];           /* flip case */
+            classbits[uc/8] |= (1 << (uc&7));
+            }
+          class_charcount++;                /* in case a one-char range */
+          class_lastchar = c;
+          }
+
+        continue;   /* Go get the next char in the class */
+        }
+
+      /* Handle a lone single character - we can get here for a normal
+      non-escape char, or after \ that introduces a single character or for an
+      apparent range that isn't. */
+
+      LONE_SINGLE_CHARACTER:
+
+      /* Handle a character that cannot go in the bit map */
+
+#ifdef SUPPORT_UTF8
+      if (utf8 && (c > 255 || ((options & PCRE_CASELESS) != 0 && c > 127)))
+        {
+        class_utf8 = TRUE;
+        *class_utf8data++ = XCL_SINGLE;
+        class_utf8data += ord2utf8(c, class_utf8data);
+
+#ifdef SUPPORT_UCP
+        if ((options & PCRE_CASELESS) != 0)
+          {
+          int chartype;
+          int othercase;
+          if (ucp_findchar(c, &chartype, &othercase) >= 0 && othercase > 0)
+            {
+            *class_utf8data++ = XCL_SINGLE;
+            class_utf8data += ord2utf8(othercase, class_utf8data);
+            }
+          }
+#endif  /* SUPPORT_UCP */
+
+        }
+      else
+#endif  /* SUPPORT_UTF8 */
+
+      /* Handle a single-byte character */
+        {
+        classbits[c/8] |= (1 << (c&7));
+        if ((options & PCRE_CASELESS) != 0)
+          {
+          c = cd->fcc[c];   /* flip case */
+          classbits[c/8] |= (1 << (c&7));
+          }
+        class_charcount++;
+        class_lastchar = c;
+        }
+      }
+
+    /* Loop until ']' reached; the check for end of string happens inside the
+    loop. This "while" is the end of the "do" above. */
+
+    while ((c = *(++ptr)) != ']' || inescq);
+
+    /* If class_charcount is 1, we saw precisely one character whose value is
+    less than 256. In non-UTF-8 mode we can always optimize. In UTF-8 mode, we
+    can optimize the negative case only if there were no characters >= 128
+    because OP_NOT and the related opcodes like OP_NOTSTAR operate on
+    single-bytes only. This is an historical hangover. Maybe one day we can
+    tidy these opcodes to handle multi-byte characters.
+
+    The optimization throws away the bit map. We turn the item into a
+    1-character OP_CHAR[NC] if it's positive, or OP_NOT if it's negative. Note
+    that OP_NOT does not support multibyte characters. In the positive case, it
+    can cause firstbyte to be set. Otherwise, there can be no first char if
+    this item is first, whatever repeat count may follow. In the case of
+    reqbyte, save the previous value for reinstating. */
+
+#ifdef SUPPORT_UTF8
+    if (class_charcount == 1 &&
+          (!utf8 ||
+          (!class_utf8 && (!negate_class || class_lastchar < 128))))
+
+#else
+    if (class_charcount == 1)
+#endif
+      {
+      zeroreqbyte = reqbyte;
+
+      /* The OP_NOT opcode works on one-byte characters only. */
+
+      if (negate_class)
+        {
+        if (firstbyte == REQ_UNSET) firstbyte = REQ_NONE;
+        zerofirstbyte = firstbyte;
+        *code++ = OP_NOT;
+        *code++ = class_lastchar;
+        break;
+        }
+
+      /* For a single, positive character, get the value into mcbuffer, and
+      then we can handle this with the normal one-character code. */
+
+#ifdef SUPPORT_UTF8
+      if (utf8 && class_lastchar > 127)
+        mclength = ord2utf8(class_lastchar, mcbuffer);
+      else
+#endif
+        {
+        mcbuffer[0] = class_lastchar;
+        mclength = 1;
+        }
+      goto ONE_CHAR;
+      }       /* End of 1-char optimization */
+
+    /* The general case - not the one-char optimization. If this is the first
+    thing in the branch, there can be no first char setting, whatever the
+    repeat count. Any reqbyte setting must remain unchanged after any kind of
+    repeat. */
+
+    if (firstbyte == REQ_UNSET) firstbyte = REQ_NONE;
+    zerofirstbyte = firstbyte;
+    zeroreqbyte = reqbyte;
+
+    /* If there are characters with values > 255, we have to compile an
+    extended class, with its own opcode. If there are no characters < 256,
+    we can omit the bitmap. */
+
+#ifdef SUPPORT_UTF8
+    if (class_utf8)
+      {
+      *class_utf8data++ = XCL_END;    /* Marks the end of extra data */
+      *code++ = OP_XCLASS;
+      code += LINK_SIZE;
+      *code = negate_class? XCL_NOT : 0;
+
+      /* If the map is required, install it, and move on to the end of
+      the extra data */
+
+      if (class_charcount > 0)
+        {
+        *code++ |= XCL_MAP;
+        memcpy(code, classbits, 32);
+        code = class_utf8data;
+        }
+
+      /* If the map is not required, slide down the extra data. */
+
+      else
+        {
+        int len = class_utf8data - (code + 33);
+        memmove(code + 1, code + 33, len);
+        code += len + 1;
+        }
+
+      /* Now fill in the complete length of the item */
+
+      PUT(previous, 1, code - previous);
+      break;   /* End of class handling */
+      }
+#endif
+
+    /* If there are no characters > 255, negate the 32-byte map if necessary,
+    and copy it into the code vector. If this is the first thing in the branch,
+    there can be no first char setting, whatever the repeat count. Any reqbyte
+    setting must remain unchanged after any kind of repeat. */
+
+    if (negate_class)
+      {
+      *code++ = OP_NCLASS;
+      for (c = 0; c < 32; c++) code[c] = ~classbits[c];
+      }
+    else
+      {
+      *code++ = OP_CLASS;
+      memcpy(code, classbits, 32);
+      }
+    code += 32;
+    break;
+
+    /* Various kinds of repeat; '{' is not necessarily a quantifier, but this
+    has been tested above. */
+
+    case '{':
+    if (!is_quantifier) goto NORMAL_CHAR;
+    ptr = read_repeat_counts(ptr+1, &repeat_min, &repeat_max, errorptr);
+    if (*errorptr != NULL) goto FAILED;
+    goto REPEAT;
+
+    case '*':
+    repeat_min = 0;
+    repeat_max = -1;
+    goto REPEAT;
+
+    case '+':
+    repeat_min = 1;
+    repeat_max = -1;
+    goto REPEAT;
+
+    case '?':
+    repeat_min = 0;
+    repeat_max = 1;
+
+    REPEAT:
+    if (previous == NULL)
+      {
+      *errorptr = ERR9;
+      goto FAILED;
+      }
+
+    if (repeat_min == 0)
+      {
+      firstbyte = zerofirstbyte;    /* Adjust for zero repeat */
+      reqbyte = zeroreqbyte;        /* Ditto */
+      }
+
+    /* Remember whether this is a variable length repeat */
+
+    reqvary = (repeat_min == repeat_max)? 0 : REQ_VARY;
+
+    op_type = 0;                    /* Default single-char op codes */
+    possessive_quantifier = FALSE;  /* Default not possessive quantifier */
+
+    /* Save start of previous item, in case we have to move it up to make space
+    for an inserted OP_ONCE for the additional '+' extension. */
+
+    tempcode = previous;
+
+    /* If the next character is '+', we have a possessive quantifier. This
+    implies greediness, whatever the setting of the PCRE_UNGREEDY option.
+    If the next character is '?' this is a minimizing repeat, by default,
+    but if PCRE_UNGREEDY is set, it works the other way round. We change the
+    repeat type to the non-default. */
+
+    if (ptr[1] == '+')
+      {
+      repeat_type = 0;                  /* Force greedy */
+      possessive_quantifier = TRUE;
+      ptr++;
+      }
+    else if (ptr[1] == '?')
+      {
+      repeat_type = greedy_non_default;
+      ptr++;
+      }
+    else repeat_type = greedy_default;
+
+    /* If previous was a recursion, we need to wrap it inside brackets so that
+    it can be replicated if necessary. */
+
+    if (*previous == OP_RECURSE)
+      {
+      memmove(previous + 1 + LINK_SIZE, previous, 1 + LINK_SIZE);
+      code += 1 + LINK_SIZE;
+      *previous = OP_BRA;
+      PUT(previous, 1, code - previous);
+      *code = OP_KET;
+      PUT(code, 1, code - previous);
+      code += 1 + LINK_SIZE;
+      }
+
+    /* If previous was a character match, abolish the item and generate a
+    repeat item instead. If a char item has a minumum of more than one, ensure
+    that it is set in reqbyte - it might not be if a sequence such as x{3} is
+    the first thing in a branch because the x will have gone into firstbyte
+    instead.  */
+
+    if (*previous == OP_CHAR || *previous == OP_CHARNC)
+      {
+      /* Deal with UTF-8 characters that take up more than one byte. It's
+      easier to write this out separately than try to macrify it. Use c to
+      hold the length of the character in bytes, plus 0x80 to flag that it's a
+      length rather than a small character. */
+
+#ifdef SUPPORT_UTF8
+      if (utf8 && (code[-1] & 0x80) != 0)
+        {
+        uschar *lastchar = code - 1;
+        while((*lastchar & 0xc0) == 0x80) lastchar--;
+        c = code - lastchar;            /* Length of UTF-8 character */
+        memcpy(utf8_char, lastchar, c); /* Save the char */
+        c |= 0x80;                      /* Flag c as a length */
+        }
+      else
+#endif
+
+      /* Handle the case of a single byte - either with no UTF8 support, or
+      with UTF-8 disabled, or for a UTF-8 character < 128. */
+
+        {
+        c = code[-1];
+        if (repeat_min > 1) reqbyte = c | req_caseopt | cd->req_varyopt;
+        }
+
+      goto OUTPUT_SINGLE_REPEAT;   /* Code shared with single character types */
+      }
+
+    /* If previous was a single negated character ([^a] or similar), we use
+    one of the special opcodes, replacing it. The code is shared with single-
+    character repeats by setting opt_type to add a suitable offset into
+    repeat_type. OP_NOT is currently used only for single-byte chars. */
+
+    else if (*previous == OP_NOT)
+      {
+      op_type = OP_NOTSTAR - OP_STAR;  /* Use "not" opcodes */
+      c = previous[1];
+      goto OUTPUT_SINGLE_REPEAT;
+      }
+
+    /* If previous was a character type match (\d or similar), abolish it and
+    create a suitable repeat item. The code is shared with single-character
+    repeats by setting op_type to add a suitable offset into repeat_type. Note
+    the the Unicode property types will be present only when SUPPORT_UCP is
+    defined, but we don't wrap the little bits of code here because it just
+    makes it horribly messy. */
+
+    else if (*previous < OP_EODN)
+      {
+      uschar *oldcode;
+      int prop_type;
+      op_type = OP_TYPESTAR - OP_STAR;  /* Use type opcodes */
+      c = *previous;
+
+      OUTPUT_SINGLE_REPEAT:
+      prop_type = (*previous == OP_PROP || *previous == OP_NOTPROP)?
+        previous[1] : -1;
+
+      oldcode = code;
+      code = previous;                  /* Usually overwrite previous item */
+
+      /* If the maximum is zero then the minimum must also be zero; Perl allows
+      this case, so we do too - by simply omitting the item altogether. */
+
+      if (repeat_max == 0) goto END_REPEAT;
+
+      /* All real repeats make it impossible to handle partial matching (maybe
+      one day we will be able to remove this restriction). */
+
+      if (repeat_max != 1) cd->nopartial = TRUE;
+
+      /* Combine the op_type with the repeat_type */
+
+      repeat_type += op_type;
+
+      /* A minimum of zero is handled either as the special case * or ?, or as
+      an UPTO, with the maximum given. */
+
+      if (repeat_min == 0)
+        {
+        if (repeat_max == -1) *code++ = OP_STAR + repeat_type;
+          else if (repeat_max == 1) *code++ = OP_QUERY + repeat_type;
+        else
+          {
+          *code++ = OP_UPTO + repeat_type;
+          PUT2INC(code, 0, repeat_max);
+          }
+        }
+
+      /* A repeat minimum of 1 is optimized into some special cases. If the
+      maximum is unlimited, we use OP_PLUS. Otherwise, the original item it
+      left in place and, if the maximum is greater than 1, we use OP_UPTO with
+      one less than the maximum. */
+
+      else if (repeat_min == 1)
+        {
+        if (repeat_max == -1)
+          *code++ = OP_PLUS + repeat_type;
+        else
+          {
+          code = oldcode;                 /* leave previous item in place */
+          if (repeat_max == 1) goto END_REPEAT;
+          *code++ = OP_UPTO + repeat_type;
+          PUT2INC(code, 0, repeat_max - 1);
+          }
+        }
+
+      /* The case {n,n} is just an EXACT, while the general case {n,m} is
+      handled as an EXACT followed by an UPTO. */
+
+      else
+        {
+        *code++ = OP_EXACT + op_type;  /* NB EXACT doesn't have repeat_type */
+        PUT2INC(code, 0, repeat_min);
+
+        /* If the maximum is unlimited, insert an OP_STAR. Before doing so,
+        we have to insert the character for the previous code. For a repeated
+        Unicode property match, there is an extra byte that defines the
+        required property. In UTF-8 mode, long characters have their length in
+        c, with the 0x80 bit as a flag. */
+
+        if (repeat_max < 0)
+          {
+#ifdef SUPPORT_UTF8
+          if (utf8 && c >= 128)
+            {
+            memcpy(code, utf8_char, c & 7);
+            code += c & 7;
+            }
+          else
+#endif
+            {
+            *code++ = c;
+            if (prop_type >= 0) *code++ = prop_type;
+            }
+          *code++ = OP_STAR + repeat_type;
+          }
+
+        /* Else insert an UPTO if the max is greater than the min, again
+        preceded by the character, for the previously inserted code. */
+
+        else if (repeat_max != repeat_min)
+          {
+#ifdef SUPPORT_UTF8
+          if (utf8 && c >= 128)
+            {
+            memcpy(code, utf8_char, c & 7);
+            code += c & 7;
+            }
+          else
+#endif
+          *code++ = c;
+          if (prop_type >= 0) *code++ = prop_type;
+          repeat_max -= repeat_min;
+          *code++ = OP_UPTO + repeat_type;
+          PUT2INC(code, 0, repeat_max);
+          }
+        }
+
+      /* The character or character type itself comes last in all cases. */
+
+#ifdef SUPPORT_UTF8
+      if (utf8 && c >= 128)
+        {
+        memcpy(code, utf8_char, c & 7);
+        code += c & 7;
+        }
+      else
+#endif
+      *code++ = c;
+
+      /* For a repeated Unicode property match, there is an extra byte that
+      defines the required property. */
+
+#ifdef SUPPORT_UCP
+      if (prop_type >= 0) *code++ = prop_type;
+#endif
+      }
+
+    /* If previous was a character class or a back reference, we put the repeat
+    stuff after it, but just skip the item if the repeat was {0,0}. */
+
+    else if (*previous == OP_CLASS ||
+             *previous == OP_NCLASS ||
+#ifdef SUPPORT_UTF8
+             *previous == OP_XCLASS ||
+#endif
+             *previous == OP_REF)
+      {
+      if (repeat_max == 0)
+        {
+        code = previous;
+        goto END_REPEAT;
+        }
+
+      /* All real repeats make it impossible to handle partial matching (maybe
+      one day we will be able to remove this restriction). */
+
+      if (repeat_max != 1) cd->nopartial = TRUE;
+
+      if (repeat_min == 0 && repeat_max == -1)
+        *code++ = OP_CRSTAR + repeat_type;
+      else if (repeat_min == 1 && repeat_max == -1)
+        *code++ = OP_CRPLUS + repeat_type;
+      else if (repeat_min == 0 && repeat_max == 1)
+        *code++ = OP_CRQUERY + repeat_type;
+      else
+        {
+        *code++ = OP_CRRANGE + repeat_type;
+        PUT2INC(code, 0, repeat_min);
+        if (repeat_max == -1) repeat_max = 0;  /* 2-byte encoding for max */
+        PUT2INC(code, 0, repeat_max);
+        }
+      }
+
+    /* If previous was a bracket group, we may have to replicate it in certain
+    cases. */
+
+    else if (*previous >= OP_BRA || *previous == OP_ONCE ||
+             *previous == OP_COND)
+      {
+      register int i;
+      int ketoffset = 0;
+      int len = code - previous;
+      uschar *bralink = NULL;
+
+      /* If the maximum repeat count is unlimited, find the end of the bracket
+      by scanning through from the start, and compute the offset back to it
+      from the current code pointer. There may be an OP_OPT setting following
+      the final KET, so we can't find the end just by going back from the code
+      pointer. */
+
+      if (repeat_max == -1)
+        {
+        register uschar *ket = previous;
+        do ket += GET(ket, 1); while (*ket != OP_KET);
+        ketoffset = code - ket;
+        }
+
+      /* The case of a zero minimum is special because of the need to stick
+      OP_BRAZERO in front of it, and because the group appears once in the
+      data, whereas in other cases it appears the minimum number of times. For
+      this reason, it is simplest to treat this case separately, as otherwise
+      the code gets far too messy. There are several special subcases when the
+      minimum is zero. */
+
+      if (repeat_min == 0)
+        {
+        /* If the maximum is also zero, we just omit the group from the output
+        altogether. */
+
+        if (repeat_max == 0)
+          {
+          code = previous;
+          goto END_REPEAT;
+          }
+
+        /* If the maximum is 1 or unlimited, we just have to stick in the
+        BRAZERO and do no more at this point. However, we do need to adjust
+        any OP_RECURSE calls inside the group that refer to the group itself or
+        any internal group, because the offset is from the start of the whole
+        regex. Temporarily terminate the pattern while doing this. */
+
+        if (repeat_max <= 1)
+          {
+          *code = OP_END;
+          adjust_recurse(previous, 1, utf8, cd);
+          memmove(previous+1, previous, len);
+          code++;
+          *previous++ = OP_BRAZERO + repeat_type;
+          }
+
+        /* If the maximum is greater than 1 and limited, we have to replicate
+        in a nested fashion, sticking OP_BRAZERO before each set of brackets.
+        The first one has to be handled carefully because it's the original
+        copy, which has to be moved up. The remainder can be handled by code
+        that is common with the non-zero minimum case below. We have to
+        adjust the value or repeat_max, since one less copy is required. Once
+        again, we may have to adjust any OP_RECURSE calls inside the group. */
+
+        else
+          {
+          int offset;
+          *code = OP_END;
+          adjust_recurse(previous, 2 + LINK_SIZE, utf8, cd);
+          memmove(previous + 2 + LINK_SIZE, previous, len);
+          code += 2 + LINK_SIZE;
+          *previous++ = OP_BRAZERO + repeat_type;
+          *previous++ = OP_BRA;
+
+          /* We chain together the bracket offset fields that have to be
+          filled in later when the ends of the brackets are reached. */
+
+          offset = (bralink == NULL)? 0 : previous - bralink;
+          bralink = previous;
+          PUTINC(previous, 0, offset);
+          }
+
+        repeat_max--;
+        }
+
+      /* If the minimum is greater than zero, replicate the group as many
+      times as necessary, and adjust the maximum to the number of subsequent
+      copies that we need. If we set a first char from the group, and didn't
+      set a required char, copy the latter from the former. */
+
+      else
+        {
+        if (repeat_min > 1)
+          {
+          if (groupsetfirstbyte && reqbyte < 0) reqbyte = firstbyte;
+          for (i = 1; i < repeat_min; i++)
+            {
+            memcpy(code, previous, len);
+            code += len;
+            }
+          }
+        if (repeat_max > 0) repeat_max -= repeat_min;
+        }
+
+      /* This code is common to both the zero and non-zero minimum cases. If
+      the maximum is limited, it replicates the group in a nested fashion,
+      remembering the bracket starts on a stack. In the case of a zero minimum,
+      the first one was set up above. In all cases the repeat_max now specifies
+      the number of additional copies needed. */
+
+      if (repeat_max >= 0)
+        {
+        for (i = repeat_max - 1; i >= 0; i--)
+          {
+          *code++ = OP_BRAZERO + repeat_type;
+
+          /* All but the final copy start a new nesting, maintaining the
+          chain of brackets outstanding. */
+
+          if (i != 0)
+            {
+            int offset;
+            *code++ = OP_BRA;
+            offset = (bralink == NULL)? 0 : code - bralink;
+            bralink = code;
+            PUTINC(code, 0, offset);
+            }
+
+          memcpy(code, previous, len);
+          code += len;
+          }
+
+        /* Now chain through the pending brackets, and fill in their length
+        fields (which are holding the chain links pro tem). */
+
+        while (bralink != NULL)
+          {
+          int oldlinkoffset;
+          int offset = code - bralink + 1;
+          uschar *bra = code - offset;
+          oldlinkoffset = GET(bra, 1);
+          bralink = (oldlinkoffset == 0)? NULL : bralink - oldlinkoffset;
+          *code++ = OP_KET;
+          PUTINC(code, 0, offset);
+          PUT(bra, 1, offset);
+          }
+        }
+
+      /* If the maximum is unlimited, set a repeater in the final copy. We
+      can't just offset backwards from the current code point, because we
+      don't know if there's been an options resetting after the ket. The
+      correct offset was computed above. */
+
+      else code[-ketoffset] = OP_KETRMAX + repeat_type;
+      }
+
+    /* Else there's some kind of shambles */
+
+    else
+      {
+      *errorptr = ERR11;
+      goto FAILED;
+      }
+
+    /* If the character following a repeat is '+', we wrap the entire repeated
+    item inside OP_ONCE brackets. This is just syntactic sugar, taken from
+    Sun's Java package. The repeated item starts at tempcode, not at previous,
+    which might be the first part of a string whose (former) last char we
+    repeated. However, we don't support '+' after a greediness '?'. */
+
+    if (possessive_quantifier)
+      {
+      int len = code - tempcode;
+      memmove(tempcode + 1+LINK_SIZE, tempcode, len);
+      code += 1 + LINK_SIZE;
+      len += 1 + LINK_SIZE;
+      tempcode[0] = OP_ONCE;
+      *code++ = OP_KET;
+      PUTINC(code, 0, len);
+      PUT(tempcode, 1, len);
+      }
+
+    /* In all case we no longer have a previous item. We also set the
+    "follows varying string" flag for subsequently encountered reqbytes if
+    it isn't already set and we have just passed a varying length item. */
+
+    END_REPEAT:
+    previous = NULL;
+    cd->req_varyopt |= reqvary;
+    break;
+
+
+    /* Start of nested bracket sub-expression, or comment or lookahead or
+    lookbehind or option setting or condition. First deal with special things
+    that can come after a bracket; all are introduced by ?, and the appearance
+    of any of them means that this is not a referencing group. They were
+    checked for validity in the first pass over the string, so we don't have to
+    check for syntax errors here.  */
+
+    case '(':
+    newoptions = options;
+    skipbytes = 0;
+
+    if (*(++ptr) == '?')
+      {
+      int set, unset;
+      int *optset;
+
+      switch (*(++ptr))
+        {
+        case '#':                 /* Comment; skip to ket */
+        ptr++;
+        while (*ptr != ')') ptr++;
+        continue;
+
+        case ':':                 /* Non-extracting bracket */
+        bravalue = OP_BRA;
+        ptr++;
+        break;
+
+        case '(':
+        bravalue = OP_COND;       /* Conditional group */
+
+        /* Condition to test for recursion */
+
+        if (ptr[1] == 'R')
+          {
+          code[1+LINK_SIZE] = OP_CREF;
+          PUT2(code, 2+LINK_SIZE, CREF_RECURSE);
+          skipbytes = 3;
+          ptr += 3;
+          }
+
+        /* Condition to test for a numbered subpattern match. We know that
+        if a digit follows ( then there will just be digits until ) because
+        the syntax was checked in the first pass. */
+
+        else if ((digitab[ptr[1]] && ctype_digit) != 0)
+          {
+          int condref;                 /* Don't amalgamate; some compilers */
+          condref = *(++ptr) - '0';    /* grumble at autoincrement in declaration */
+          while (*(++ptr) != ')') condref = condref*10 + *ptr - '0';
+          if (condref == 0)
+            {
+            *errorptr = ERR35;
+            goto FAILED;
+            }
+          ptr++;
+          code[1+LINK_SIZE] = OP_CREF;
+          PUT2(code, 2+LINK_SIZE, condref);
+          skipbytes = 3;
+          }
+        /* For conditions that are assertions, we just fall through, having
+        set bravalue above. */
+        break;
+
+        case '=':                 /* Positive lookahead */
+        bravalue = OP_ASSERT;
+        ptr++;
+        break;
+
+        case '!':                 /* Negative lookahead */
+        bravalue = OP_ASSERT_NOT;
+        ptr++;
+        break;
+
+        case '<':                 /* Lookbehinds */
+        switch (*(++ptr))
+          {
+          case '=':               /* Positive lookbehind */
+          bravalue = OP_ASSERTBACK;
+          ptr++;
+          break;
+
+          case '!':               /* Negative lookbehind */
+          bravalue = OP_ASSERTBACK_NOT;
+          ptr++;
+          break;
+          }
+        break;
+
+        case '>':                 /* One-time brackets */
+        bravalue = OP_ONCE;
+        ptr++;
+        break;
+
+        case 'C':                 /* Callout - may be followed by digits; */
+        previous_callout = code;  /* Save for later completion */
+        after_manual_callout = 1; /* Skip one item before completing */
+        *code++ = OP_CALLOUT;     /* Already checked that the terminating */
+          {                       /* closing parenthesis is present. */
+          int n = 0;
+          while ((digitab[*(++ptr)] & ctype_digit) != 0)
+            n = n * 10 + *ptr - '0';
+          if (n > 255)
+            {
+            *errorptr = ERR38;
+            goto FAILED;
+            }
+          *code++ = n;
+          PUT(code, 0, ptr - cd->start_pattern + 1);  /* Pattern offset */
+          PUT(code, LINK_SIZE, 0);                    /* Default length */
+          code += 2 * LINK_SIZE;
+          }
+        previous = NULL;
+        continue;
+
+        case 'P':                 /* Named subpattern handling */
+        if (*(++ptr) == '<')      /* Definition */
+          {
+          int i, namelen;
+          uschar *slot = cd->name_table;
+          const uschar *name;     /* Don't amalgamate; some compilers */
+          name = ++ptr;           /* grumble at autoincrement in declaration */
+
+          while (*ptr++ != '>');
+          namelen = ptr - name - 1;
+
+          for (i = 0; i < cd->names_found; i++)
+            {
+            int crc = memcmp(name, slot+2, namelen);
+            if (crc == 0)
+              {
+              if (slot[2+namelen] == 0)
+                {
+                *errorptr = ERR43;
+                goto FAILED;
+                }
+              crc = -1;             /* Current name is substring */
+              }
+            if (crc < 0)
+              {
+              memmove(slot + cd->name_entry_size, slot,
+                (cd->names_found - i) * cd->name_entry_size);
+              break;
+              }
+            slot += cd->name_entry_size;
+            }
+
+          PUT2(slot, 0, *brackets + 1);
+          memcpy(slot + 2, name, namelen);
+          slot[2+namelen] = 0;
+          cd->names_found++;
+          goto NUMBERED_GROUP;
+          }
+
+        if (*ptr == '=' || *ptr == '>')  /* Reference or recursion */
+          {
+          int i, namelen;
+          int type = *ptr++;
+          const uschar *name = ptr;
+          uschar *slot = cd->name_table;
+
+          while (*ptr != ')') ptr++;
+          namelen = ptr - name;
+
+          for (i = 0; i < cd->names_found; i++)
+            {
+            if (strncmp((char *)name, (char *)slot+2, namelen) == 0) break;
+            slot += cd->name_entry_size;
+            }
+          if (i >= cd->names_found)
+            {
+            *errorptr = ERR15;
+            goto FAILED;
+            }
+
+          recno = GET2(slot, 0);
+
+          if (type == '>') goto HANDLE_RECURSION;  /* A few lines below */
+
+          /* Back reference */
+
+          previous = code;
+          *code++ = OP_REF;
+          PUT2INC(code, 0, recno);
+          cd->backref_map |= (recno < 32)? (1 << recno) : 1;
+          if (recno > cd->top_backref) cd->top_backref = recno;
+          continue;
+          }
+
+        /* Should never happen */
+        break;
+
+        case 'R':                 /* Pattern recursion */
+        ptr++;                    /* Same as (?0)      */
+        /* Fall through */
+
+        /* Recursion or "subroutine" call */
+
+        case '0': case '1': case '2': case '3': case '4':
+        case '5': case '6': case '7': case '8': case '9':
+          {
+          const uschar *called;
+          recno = 0;
+          while((digitab[*ptr] & ctype_digit) != 0)
+            recno = recno * 10 + *ptr++ - '0';
+
+          /* Come here from code above that handles a named recursion */
+
+          HANDLE_RECURSION:
+
+          previous = code;
+
+          /* Find the bracket that is being referenced. Temporarily end the
+          regex in case it doesn't exist. */
+
+          *code = OP_END;
+          called = (recno == 0)?
+            cd->start_code : find_bracket(cd->start_code, utf8, recno);
+
+          if (called == NULL)
+            {
+            *errorptr = ERR15;
+            goto FAILED;
+            }
+
+          /* If the subpattern is still open, this is a recursive call. We
+          check to see if this is a left recursion that could loop for ever,
+          and diagnose that case. */
+
+          if (GET(called, 1) == 0 && could_be_empty(called, code, bcptr, utf8))
+            {
+            *errorptr = ERR40;
+            goto FAILED;
+            }
+
+          /* Insert the recursion/subroutine item */
+
+          *code = OP_RECURSE;
+          PUT(code, 1, called - cd->start_code);
+          code += 1 + LINK_SIZE;
+          }
+        continue;
+
+        /* Character after (? not specially recognized */
+
+        default:                  /* Option setting */
+        set = unset = 0;
+        optset = &set;
+
+        while (*ptr != ')' && *ptr != ':')
+          {
+          switch (*ptr++)
+            {
+            case '-': optset = &unset; break;
+
+            case 'i': *optset |= PCRE_CASELESS; break;
+            case 'm': *optset |= PCRE_MULTILINE; break;
+            case 's': *optset |= PCRE_DOTALL; break;
+            case 'x': *optset |= PCRE_EXTENDED; break;
+            case 'U': *optset |= PCRE_UNGREEDY; break;
+            case 'X': *optset |= PCRE_EXTRA; break;
+            }
+          }
+
+        /* Set up the changed option bits, but don't change anything yet. */
+
+        newoptions = (options | set) & (~unset);
+
+        /* If the options ended with ')' this is not the start of a nested
+        group with option changes, so the options change at this level. Compile
+        code to change the ims options if this setting actually changes any of
+        them. We also pass the new setting back so that it can be put at the
+        start of any following branches, and when this group ends (if we are in
+        a group), a resetting item can be compiled.
+
+        Note that if this item is right at the start of the pattern, the
+        options will have been abstracted and made global, so there will be no
+        change to compile. */
+
+        if (*ptr == ')')
+          {
+          if ((options & PCRE_IMS) != (newoptions & PCRE_IMS))
+            {
+            *code++ = OP_OPT;
+            *code++ = newoptions & PCRE_IMS;
+            }
+
+          /* Change options at this level, and pass them back for use
+          in subsequent branches. Reset the greedy defaults and the case
+          value for firstbyte and reqbyte. */
+
+          *optionsptr = options = newoptions;
+          greedy_default = ((newoptions & PCRE_UNGREEDY) != 0);
+          greedy_non_default = greedy_default ^ 1;
+          req_caseopt = ((options & PCRE_CASELESS) != 0)? REQ_CASELESS : 0;
+
+          previous = NULL;       /* This item can't be repeated */
+          continue;              /* It is complete */
+          }
+
+        /* If the options ended with ':' we are heading into a nested group
+        with possible change of options. Such groups are non-capturing and are
+        not assertions of any kind. All we need to do is skip over the ':';
+        the newoptions value is handled below. */
+
+        bravalue = OP_BRA;
+        ptr++;
+        }
+      }
+
+    /* If PCRE_NO_AUTO_CAPTURE is set, all unadorned brackets become
+    non-capturing and behave like (?:...) brackets */
+
+    else if ((options & PCRE_NO_AUTO_CAPTURE) != 0)
+      {
+      bravalue = OP_BRA;
+      }
+
+    /* Else we have a referencing group; adjust the opcode. If the bracket
+    number is greater than EXTRACT_BASIC_MAX, we set the opcode one higher, and
+    arrange for the true number to follow later, in an OP_BRANUMBER item. */
+
+    else
+      {
+      NUMBERED_GROUP:
+      if (++(*brackets) > EXTRACT_BASIC_MAX)
+        {
+        bravalue = OP_BRA + EXTRACT_BASIC_MAX + 1;
+        code[1+LINK_SIZE] = OP_BRANUMBER;
+        PUT2(code, 2+LINK_SIZE, *brackets);
+        skipbytes = 3;
+        }
+      else bravalue = OP_BRA + *brackets;
+      }
+
+    /* Process nested bracketed re. Assertions may not be repeated, but other
+    kinds can be. We copy code into a non-register variable in order to be able
+    to pass its address because some compilers complain otherwise. Pass in a
+    new setting for the ims options if they have changed. */
+
+    previous = (bravalue >= OP_ONCE)? code : NULL;
+    *code = bravalue;
+    tempcode = code;
+    tempreqvary = cd->req_varyopt;     /* Save value before bracket */
+
+    if (!compile_regex(
+         newoptions,                   /* The complete new option state */
+         options & PCRE_IMS,           /* The previous ims option state */
+         brackets,                     /* Extracting bracket count */
+         &tempcode,                    /* Where to put code (updated) */
+         &ptr,                         /* Input pointer (updated) */
+         errorptr,                     /* Where to put an error message */
+         (bravalue == OP_ASSERTBACK ||
+          bravalue == OP_ASSERTBACK_NOT), /* TRUE if back assert */
+         skipbytes,                    /* Skip over OP_COND/OP_BRANUMBER */
+         &subfirstbyte,                /* For possible first char */
+         &subreqbyte,                  /* For possible last char */
+         bcptr,                        /* Current branch chain */
+         cd))                          /* Tables block */
+      goto FAILED;
+
+    /* At the end of compiling, code is still pointing to the start of the
+    group, while tempcode has been updated to point past the end of the group
+    and any option resetting that may follow it. The pattern pointer (ptr)
+    is on the bracket. */
+
+    /* If this is a conditional bracket, check that there are no more than
+    two branches in the group. */
+
+    else if (bravalue == OP_COND)
+      {
+      uschar *tc = code;
+      condcount = 0;
+
+      do {
+         condcount++;
+         tc += GET(tc,1);
+         }
+      while (*tc != OP_KET);
+
+      if (condcount > 2)
+        {
+        *errorptr = ERR27;
+        goto FAILED;
+        }
+
+      /* If there is just one branch, we must not make use of its firstbyte or
+      reqbyte, because this is equivalent to an empty second branch. */
+
+      if (condcount == 1) subfirstbyte = subreqbyte = REQ_NONE;
+      }
+
+    /* Handle updating of the required and first characters. Update for normal
+    brackets of all kinds, and conditions with two branches (see code above).
+    If the bracket is followed by a quantifier with zero repeat, we have to
+    back off. Hence the definition of zeroreqbyte and zerofirstbyte outside the
+    main loop so that they can be accessed for the back off. */
+
+    zeroreqbyte = reqbyte;
+    zerofirstbyte = firstbyte;
+    groupsetfirstbyte = FALSE;
+
+    if (bravalue >= OP_BRA || bravalue == OP_ONCE || bravalue == OP_COND)
+      {
+      /* If we have not yet set a firstbyte in this branch, take it from the
+      subpattern, remembering that it was set here so that a repeat of more
+      than one can replicate it as reqbyte if necessary. If the subpattern has
+      no firstbyte, set "none" for the whole branch. In both cases, a zero
+      repeat forces firstbyte to "none". */
+
+      if (firstbyte == REQ_UNSET)
+        {
+        if (subfirstbyte >= 0)
+          {
+          firstbyte = subfirstbyte;
+          groupsetfirstbyte = TRUE;
+          }
+        else firstbyte = REQ_NONE;
+        zerofirstbyte = REQ_NONE;
+        }
+
+      /* If firstbyte was previously set, convert the subpattern's firstbyte
+      into reqbyte if there wasn't one, using the vary flag that was in
+      existence beforehand. */
+
+      else if (subfirstbyte >= 0 && subreqbyte < 0)
+        subreqbyte = subfirstbyte | tempreqvary;
+
+      /* If the subpattern set a required byte (or set a first byte that isn't
+      really the first byte - see above), set it. */
+
+      if (subreqbyte >= 0) reqbyte = subreqbyte;
+      }
+
+    /* For a forward assertion, we take the reqbyte, if set. This can be
+    helpful if the pattern that follows the assertion doesn't set a different
+    char. For example, it's useful for /(?=abcde).+/. We can't set firstbyte
+    for an assertion, however because it leads to incorrect effect for patterns
+    such as /(?=a)a.+/ when the "real" "a" would then become a reqbyte instead
+    of a firstbyte. This is overcome by a scan at the end if there's no
+    firstbyte, looking for an asserted first char. */
+
+    else if (bravalue == OP_ASSERT && subreqbyte >= 0) reqbyte = subreqbyte;
+
+    /* Now update the main code pointer to the end of the group. */
+
+    code = tempcode;
+
+    /* Error if hit end of pattern */
+
+    if (*ptr != ')')
+      {
+      *errorptr = ERR14;
+      goto FAILED;
+      }
+    break;
+
+    /* Check \ for being a real metacharacter; if not, fall through and handle
+    it as a data character at the start of a string. Escape items are checked
+    for validity in the pre-compiling pass. */
+
+    case '\\':
+    tempptr = ptr;
+    c = check_escape(&ptr, errorptr, *brackets, options, FALSE);
+
+    /* Handle metacharacters introduced by \. For ones like \d, the ESC_ values
+    are arranged to be the negation of the corresponding OP_values. For the
+    back references, the values are ESC_REF plus the reference number. Only
+    back references and those types that consume a character may be repeated.
+    We can test for values between ESC_b and ESC_Z for the latter; this may
+    have to change if any new ones are ever created. */
+
+    if (c < 0)
+      {
+      if (-c == ESC_Q)            /* Handle start of quoted string */
+        {
+        if (ptr[1] == '\\' && ptr[2] == 'E') ptr += 2; /* avoid empty string */
+          else inescq = TRUE;
+        continue;
+        }
+
+      /* For metasequences that actually match a character, we disable the
+      setting of a first character if it hasn't already been set. */
+
+      if (firstbyte == REQ_UNSET && -c > ESC_b && -c < ESC_Z)
+        firstbyte = REQ_NONE;
+
+      /* Set values to reset to if this is followed by a zero repeat. */
+
+      zerofirstbyte = firstbyte;
+      zeroreqbyte = reqbyte;
+
+      /* Back references are handled specially */
+
+      if (-c >= ESC_REF)
+        {
+        int number = -c - ESC_REF;
+        previous = code;
+        *code++ = OP_REF;
+        PUT2INC(code, 0, number);
+        }
+
+      /* So are Unicode property matches, if supported. We know that get_ucp
+      won't fail because it was tested in the pre-pass. */
+
+#ifdef SUPPORT_UCP
+      else if (-c == ESC_P || -c == ESC_p)
+        {
+        BOOL negated;
+        int value = get_ucp(&ptr, &negated, errorptr);
+        previous = code;
+        *code++ = ((-c == ESC_p) != negated)? OP_PROP : OP_NOTPROP;
+        *code++ = value;
+        }
+#endif
+
+      /* For the rest, we can obtain the OP value by negating the escape
+      value */
+
+      else
+        {
+        previous = (-c > ESC_b && -c < ESC_Z)? code : NULL;
+        *code++ = -c;
+        }
+      continue;
+      }
+
+    /* We have a data character whose value is in c. In UTF-8 mode it may have
+    a value > 127. We set its representation in the length/buffer, and then
+    handle it as a data character. */
+
+#ifdef SUPPORT_UTF8
+    if (utf8 && c > 127)
+      mclength = ord2utf8(c, mcbuffer);
+    else
+#endif
+
+     {
+     mcbuffer[0] = c;
+     mclength = 1;
+     }
+
+    goto ONE_CHAR;
+
+    /* Handle a literal character. It is guaranteed not to be whitespace or #
+    when the extended flag is set. If we are in UTF-8 mode, it may be a
+    multi-byte literal character. */
+
+    default:
+    NORMAL_CHAR:
+    mclength = 1;
+    mcbuffer[0] = c;
+
+#ifdef SUPPORT_UTF8
+    if (utf8 && (c & 0xc0) == 0xc0)
+      {
+      while ((ptr[1] & 0xc0) == 0x80)
+        mcbuffer[mclength++] = *(++ptr);
+      }
+#endif
+
+    /* At this point we have the character's bytes in mcbuffer, and the length
+    in mclength. When not in UTF-8 mode, the length is always 1. */
+
+    ONE_CHAR:
+    previous = code;
+    *code++ = ((options & PCRE_CASELESS) != 0)? OP_CHARNC : OP_CHAR;
+    for (c = 0; c < mclength; c++) *code++ = mcbuffer[c];
+
+    /* Set the first and required bytes appropriately. If no previous first
+    byte, set it from this character, but revert to none on a zero repeat.
+    Otherwise, leave the firstbyte value alone, and don't change it on a zero
+    repeat. */
+
+    if (firstbyte == REQ_UNSET)
+      {
+      zerofirstbyte = REQ_NONE;
+      zeroreqbyte = reqbyte;
+
+      /* If the character is more than one byte long, we can set firstbyte
+      only if it is not to be matched caselessly. */
+
+      if (mclength == 1 || req_caseopt == 0)
+        {
+        firstbyte = mcbuffer[0] | req_caseopt;
+        if (mclength != 1) reqbyte = code[-1] | cd->req_varyopt;
+        }
+      else firstbyte = reqbyte = REQ_NONE;
+      }
+
+    /* firstbyte was previously set; we can set reqbyte only the length is
+    1 or the matching is caseful. */
+
+    else
+      {
+      zerofirstbyte = firstbyte;
+      zeroreqbyte = reqbyte;
+      if (mclength == 1 || req_caseopt == 0)
+        reqbyte = code[-1] | req_caseopt | cd->req_varyopt;
+      }
+
+    break;            /* End of literal character handling */
+    }
+  }                   /* end of big loop */
+
+/* Control never reaches here by falling through, only by a goto for all the
+error states. Pass back the position in the pattern so that it can be displayed
+to the user for diagnosing the error. */
+
+FAILED:
+*ptrptr = ptr;
+return FALSE;
+}
+
+
+
+
+/*************************************************
+*     Compile sequence of alternatives           *
+*************************************************/
+
+/* On entry, ptr is pointing past the bracket character, but on return
+it points to the closing bracket, or vertical bar, or end of string.
+The code variable is pointing at the byte into which the BRA operator has been
+stored. If the ims options are changed at the start (for a (?ims: group) or
+during any branch, we need to insert an OP_OPT item at the start of every
+following branch to ensure they get set correctly at run time, and also pass
+the new options into every subsequent branch compile.
+
+Argument:
+  options        option bits, including any changes for this subpattern
+  oldims         previous settings of ims option bits
+  brackets       -> int containing the number of extracting brackets used
+  codeptr        -> the address of the current code pointer
+  ptrptr         -> the address of the current pattern pointer
+  errorptr       -> pointer to error message
+  lookbehind     TRUE if this is a lookbehind assertion
+  skipbytes      skip this many bytes at start (for OP_COND, OP_BRANUMBER)
+  firstbyteptr   place to put the first required character, or a negative number
+  reqbyteptr     place to put the last required character, or a negative number
+  bcptr          pointer to the chain of currently open branches
+  cd             points to the data block with tables pointers etc.
+
+Returns:      TRUE on success
+*/
+
+static BOOL
+compile_regex(int options, int oldims, int *brackets, uschar **codeptr,
+  const uschar **ptrptr, const char **errorptr, BOOL lookbehind, int skipbytes,
+  int *firstbyteptr, int *reqbyteptr, branch_chain *bcptr, compile_data *cd)
+{
+const uschar *ptr = *ptrptr;
+uschar *code = *codeptr;
+uschar *last_branch = code;
+uschar *start_bracket = code;
+uschar *reverse_count = NULL;
+int firstbyte, reqbyte;
+int branchfirstbyte, branchreqbyte;
+branch_chain bc;
+
+bc.outer = bcptr;
+bc.current = code;
+
+firstbyte = reqbyte = REQ_UNSET;
+
+/* Offset is set zero to mark that this bracket is still open */
+
+PUT(code, 1, 0);
+code += 1 + LINK_SIZE + skipbytes;
+
+/* Loop for each alternative branch */
+
+for (;;)
+  {
+  /* Handle a change of ims options at the start of the branch */
+
+  if ((options & PCRE_IMS) != oldims)
+    {
+    *code++ = OP_OPT;
+    *code++ = options & PCRE_IMS;
+    }
+
+  /* Set up dummy OP_REVERSE if lookbehind assertion */
+
+  if (lookbehind)
+    {
+    *code++ = OP_REVERSE;
+    reverse_count = code;
+    PUTINC(code, 0, 0);
+    }
+
+  /* Now compile the branch */
+
+  if (!compile_branch(&options, brackets, &code, &ptr, errorptr,
+        &branchfirstbyte, &branchreqbyte, &bc, cd))
+    {
+    *ptrptr = ptr;
+    return FALSE;
+    }
+
+  /* If this is the first branch, the firstbyte and reqbyte values for the
+  branch become the values for the regex. */
+
+  if (*last_branch != OP_ALT)
+    {
+    firstbyte = branchfirstbyte;
+    reqbyte = branchreqbyte;
+    }
+
+  /* If this is not the first branch, the first char and reqbyte have to
+  match the values from all the previous branches, except that if the previous
+  value for reqbyte didn't have REQ_VARY set, it can still match, and we set
+  REQ_VARY for the regex. */
+
+  else
+    {
+    /* If we previously had a firstbyte, but it doesn't match the new branch,
+    we have to abandon the firstbyte for the regex, but if there was previously
+    no reqbyte, it takes on the value of the old firstbyte. */
+
+    if (firstbyte >= 0 && firstbyte != branchfirstbyte)
+      {
+      if (reqbyte < 0) reqbyte = firstbyte;
+      firstbyte = REQ_NONE;
+      }
+
+    /* If we (now or from before) have no firstbyte, a firstbyte from the
+    branch becomes a reqbyte if there isn't a branch reqbyte. */
+
+    if (firstbyte < 0 && branchfirstbyte >= 0 && branchreqbyte < 0)
+        branchreqbyte = branchfirstbyte;
+
+    /* Now ensure that the reqbytes match */
+
+    if ((reqbyte & ~REQ_VARY) != (branchreqbyte & ~REQ_VARY))
+      reqbyte = REQ_NONE;
+    else reqbyte |= branchreqbyte;   /* To "or" REQ_VARY */
+    }
+
+  /* If lookbehind, check that this branch matches a fixed-length string,
+  and put the length into the OP_REVERSE item. Temporarily mark the end of
+  the branch with OP_END. */
+
+  if (lookbehind)
+    {
+    int length;
+    *code = OP_END;
+    length = find_fixedlength(last_branch, options);
+    DPRINTF(("fixed length = %d\n", length));
+    if (length < 0)
+      {
+      *errorptr = (length == -2)? ERR36 : ERR25;
+      *ptrptr = ptr;
+      return FALSE;
+      }
+    PUT(reverse_count, 0, length);
+    }
+
+  /* Reached end of expression, either ')' or end of pattern. Go back through
+  the alternative branches and reverse the chain of offsets, with the field in
+  the BRA item now becoming an offset to the first alternative. If there are
+  no alternatives, it points to the end of the group. The length in the
+  terminating ket is always the length of the whole bracketed item. If any of
+  the ims options were changed inside the group, compile a resetting op-code
+  following, except at the very end of the pattern. Return leaving the pointer
+  at the terminating char. */
+
+  if (*ptr != '|')
+    {
+    int length = code - last_branch;
+    do
+      {
+      int prev_length = GET(last_branch, 1);
+      PUT(last_branch, 1, length);
+      length = prev_length;
+      last_branch -= length;
+      }
+    while (length > 0);
+
+    /* Fill in the ket */
+
+    *code = OP_KET;
+    PUT(code, 1, code - start_bracket);
+    code += 1 + LINK_SIZE;
+
+    /* Resetting option if needed */
+
+    if ((options & PCRE_IMS) != oldims && *ptr == ')')
+      {
+      *code++ = OP_OPT;
+      *code++ = oldims;
+      }
+
+    /* Set values to pass back */
+
+    *codeptr = code;
+    *ptrptr = ptr;
+    *firstbyteptr = firstbyte;
+    *reqbyteptr = reqbyte;
+    return TRUE;
+    }
+
+  /* Another branch follows; insert an "or" node. Its length field points back
+  to the previous branch while the bracket remains open. At the end the chain
+  is reversed. It's done like this so that the start of the bracket has a
+  zero offset until it is closed, making it possible to detect recursion. */
+
+  *code = OP_ALT;
+  PUT(code, 1, code - last_branch);
+  bc.current = last_branch = code;
+  code += 1 + LINK_SIZE;
+  ptr++;
+  }
+/* Control never reaches here */
+}
+
+
+
+
+/*************************************************
+*          Check for anchored expression         *
+*************************************************/
+
+/* Try to find out if this is an anchored regular expression. Consider each
+alternative branch. If they all start with OP_SOD or OP_CIRC, or with a bracket
+all of whose alternatives start with OP_SOD or OP_CIRC (recurse ad lib), then
+it's anchored. However, if this is a multiline pattern, then only OP_SOD
+counts, since OP_CIRC can match in the middle.
+
+We can also consider a regex to be anchored if OP_SOM starts all its branches.
+This is the code for \G, which means "match at start of match position, taking
+into account the match offset".
+
+A branch is also implicitly anchored if it starts with .* and DOTALL is set,
+because that will try the rest of the pattern at all possible matching points,
+so there is no point trying again.... er ....
+
+.... except when the .* appears inside capturing parentheses, and there is a
+subsequent back reference to those parentheses. We haven't enough information
+to catch that case precisely.
+
+At first, the best we could do was to detect when .* was in capturing brackets
+and the highest back reference was greater than or equal to that level.
+However, by keeping a bitmap of the first 31 back references, we can catch some
+of the more common cases more precisely.
+
+Arguments:
+  code           points to start of expression (the bracket)
+  options        points to the options setting
+  bracket_map    a bitmap of which brackets we are inside while testing; this
+                  handles up to substring 31; after that we just have to take
+                  the less precise approach
+  backref_map    the back reference bitmap
+
+Returns:     TRUE or FALSE
+*/
+
+static BOOL
+is_anchored(register const uschar *code, int *options, unsigned int bracket_map,
+  unsigned int backref_map)
+{
+do {
+   const uschar *scode =
+     first_significant_code(code + 1+LINK_SIZE, options, PCRE_MULTILINE, FALSE);
+   register int op = *scode;
+
+   /* Capturing brackets */
+
+   if (op > OP_BRA)
+     {
+     int new_map;
+     op -= OP_BRA;
+     if (op > EXTRACT_BASIC_MAX) op = GET2(scode, 2+LINK_SIZE);
+     new_map = bracket_map | ((op < 32)? (1 << op) : 1);
+     if (!is_anchored(scode, options, new_map, backref_map)) return FALSE;
+     }
+
+   /* Other brackets */
+
+   else if (op == OP_BRA || op == OP_ASSERT || op == OP_ONCE || op == OP_COND)
+     {
+     if (!is_anchored(scode, options, bracket_map, backref_map)) return FALSE;
+     }
+
+   /* .* is not anchored unless DOTALL is set and it isn't in brackets that
+   are or may be referenced. */
+
+   else if ((op == OP_TYPESTAR || op == OP_TYPEMINSTAR) &&
+            (*options & PCRE_DOTALL) != 0)
+     {
+     if (scode[1] != OP_ANY || (bracket_map & backref_map) != 0) return FALSE;
+     }
+
+   /* Check for explicit anchoring */
+
+   else if (op != OP_SOD && op != OP_SOM &&
+           ((*options & PCRE_MULTILINE) != 0 || op != OP_CIRC))
+     return FALSE;
+   code += GET(code, 1);
+   }
+while (*code == OP_ALT);   /* Loop for each alternative */
+return TRUE;
+}
+
+
+
+/*************************************************
+*         Check for starting with ^ or .*        *
+*************************************************/
+
+/* This is called to find out if every branch starts with ^ or .* so that
+"first char" processing can be done to speed things up in multiline
+matching and for non-DOTALL patterns that start with .* (which must start at
+the beginning or after \n). As in the case of is_anchored() (see above), we
+have to take account of back references to capturing brackets that contain .*
+because in that case we can't make the assumption.
+
+Arguments:
+  code           points to start of expression (the bracket)
+  bracket_map    a bitmap of which brackets we are inside while testing; this
+                  handles up to substring 31; after that we just have to take
+                  the less precise approach
+  backref_map    the back reference bitmap
+
+Returns:         TRUE or FALSE
+*/
+
+static BOOL
+is_startline(const uschar *code, unsigned int bracket_map,
+  unsigned int backref_map)
+{
+do {
+   const uschar *scode = first_significant_code(code + 1+LINK_SIZE, NULL, 0,
+     FALSE);
+   register int op = *scode;
+
+   /* Capturing brackets */
+
+   if (op > OP_BRA)
+     {
+     int new_map;
+     op -= OP_BRA;
+     if (op > EXTRACT_BASIC_MAX) op = GET2(scode, 2+LINK_SIZE);
+     new_map = bracket_map | ((op < 32)? (1 << op) : 1);
+     if (!is_startline(scode, new_map, backref_map)) return FALSE;
+     }
+
+   /* Other brackets */
+
+   else if (op == OP_BRA || op == OP_ASSERT || op == OP_ONCE || op == OP_COND)
+     { if (!is_startline(scode, bracket_map, backref_map)) return FALSE; }
+
+   /* .* means "start at start or after \n" if it isn't in brackets that
+   may be referenced. */
+
+   else if (op == OP_TYPESTAR || op == OP_TYPEMINSTAR)
+     {
+     if (scode[1] != OP_ANY || (bracket_map & backref_map) != 0) return FALSE;
+     }
+
+   /* Check for explicit circumflex */
+
+   else if (op != OP_CIRC) return FALSE;
+
+   /* Move on to the next alternative */
+
+   code += GET(code, 1);
+   }
+while (*code == OP_ALT);  /* Loop for each alternative */
+return TRUE;
+}
+
+
+
+/*************************************************
+*       Check for asserted fixed first char      *
+*************************************************/
+
+/* During compilation, the "first char" settings from forward assertions are
+discarded, because they can cause conflicts with actual literals that follow.
+However, if we end up without a first char setting for an unanchored pattern,
+it is worth scanning the regex to see if there is an initial asserted first
+char. If all branches start with the same asserted char, or with a bracket all
+of whose alternatives start with the same asserted char (recurse ad lib), then
+we return that char, otherwise -1.
+
+Arguments:
+  code       points to start of expression (the bracket)
+  options    pointer to the options (used to check casing changes)
+  inassert   TRUE if in an assertion
+
+Returns:     -1 or the fixed first char
+*/
+
+static int
+find_firstassertedchar(const uschar *code, int *options, BOOL inassert)
+{
+register int c = -1;
+do {
+   int d;
+   const uschar *scode =
+     first_significant_code(code + 1+LINK_SIZE, options, PCRE_CASELESS, TRUE);
+   register int op = *scode;
+
+   if (op >= OP_BRA) op = OP_BRA;
+
+   switch(op)
+     {
+     default:
+     return -1;
+
+     case OP_BRA:
+     case OP_ASSERT:
+     case OP_ONCE:
+     case OP_COND:
+     if ((d = find_firstassertedchar(scode, options, op == OP_ASSERT)) < 0)
+       return -1;
+     if (c < 0) c = d; else if (c != d) return -1;
+     break;
+
+     case OP_EXACT:       /* Fall through */
+     scode += 2;
+
+     case OP_CHAR:
+     case OP_CHARNC:
+     case OP_PLUS:
+     case OP_MINPLUS:
+     if (!inassert) return -1;
+     if (c < 0)
+       {
+       c = scode[1];
+       if ((*options & PCRE_CASELESS) != 0) c |= REQ_CASELESS;
+       }
+     else if (c != scode[1]) return -1;
+     break;
+     }
+
+   code += GET(code, 1);
+   }
+while (*code == OP_ALT);
+return c;
+}
+
+
+
+
+#ifdef SUPPORT_UTF8
+/*************************************************
+*         Validate a UTF-8 string                *
+*************************************************/
+
+/* This function is called (optionally) at the start of compile or match, to
+validate that a supposed UTF-8 string is actually valid. The early check means
+that subsequent code can assume it is dealing with a valid string. The check
+can be turned off for maximum performance, but then consequences of supplying
+an invalid string are then undefined.
+
+Arguments:
+  string       points to the string
+  length       length of string, or -1 if the string is zero-terminated
+
+Returns:       < 0    if the string is a valid UTF-8 string
+               >= 0   otherwise; the value is the offset of the bad byte
+*/
+
+static int
+valid_utf8(const uschar *string, int length)
+{
+register const uschar *p;
+
+if (length < 0)
+  {
+  for (p = string; *p != 0; p++);
+  length = p - string;
+  }
+
+for (p = string; length-- > 0; p++)
+  {
+  register int ab;
+  register int c = *p;
+  if (c < 128) continue;
+  if ((c & 0xc0) != 0xc0) return p - string;
+  ab = utf8_table4[c & 0x3f];  /* Number of additional bytes */
+  if (length < ab) return p - string;
+  length -= ab;
+
+  /* Check top bits in the second byte */
+  if ((*(++p) & 0xc0) != 0x80) return p - string;
+
+  /* Check for overlong sequences for each different length */
+  switch (ab)
+    {
+    /* Check for xx00 000x */
+    case 1:
+    if ((c & 0x3e) == 0) return p - string;
+    continue;   /* We know there aren't any more bytes to check */
+
+    /* Check for 1110 0000, xx0x xxxx */
+    case 2:
+    if (c == 0xe0 && (*p & 0x20) == 0) return p - string;
+    break;
+
+    /* Check for 1111 0000, xx00 xxxx */
+    case 3:
+    if (c == 0xf0 && (*p & 0x30) == 0) return p - string;
+    break;
+
+    /* Check for 1111 1000, xx00 0xxx */
+    case 4:
+    if (c == 0xf8 && (*p & 0x38) == 0) return p - string;
+    break;
+
+    /* Check for leading 0xfe or 0xff, and then for 1111 1100, xx00 00xx */
+    case 5:
+    if (c == 0xfe || c == 0xff ||
+       (c == 0xfc && (*p & 0x3c) == 0)) return p - string;
+    break;
+    }
+
+  /* Check for valid bytes after the 2nd, if any; all must start 10 */
+  while (--ab > 0)
+    {
+    if ((*(++p) & 0xc0) != 0x80) return p - string;
+    }
+  }
+
+return -1;
+}
+#endif
+
+
+
+/*************************************************
+*        Compile a Regular Expression            *
+*************************************************/
+
+/* This function takes a string and returns a pointer to a block of store
+holding a compiled version of the expression.
+
+Arguments:
+  pattern      the regular expression
+  options      various option bits
+  errorptr     pointer to pointer to error text
+  erroroffset  ptr offset in pattern where error was detected
+  tables       pointer to character tables or NULL
+
+Returns:       pointer to compiled data block, or NULL on error,
+               with errorptr and erroroffset set
+*/
+
+EXPORT pcre *
+pcre_compile(const char *pattern, int options, const char **errorptr,
+  int *erroroffset, const unsigned char *tables)
+{
+real_pcre *re;
+int length = 1 + LINK_SIZE;      /* For initial BRA plus length */
+int c, firstbyte, reqbyte;
+int bracount = 0;
+int branch_extra = 0;
+int branch_newextra;
+int item_count = -1;
+int name_count = 0;
+int max_name_size = 0;
+int lastitemlength = 0;
+#ifdef SUPPORT_UTF8
+BOOL utf8;
+BOOL class_utf8;
+#endif
+BOOL inescq = FALSE;
+unsigned int brastackptr = 0;
+size_t size;
+uschar *code;
+const uschar *codestart;
+const uschar *ptr;
+compile_data compile_block;
+int brastack[BRASTACK_SIZE];
+uschar bralenstack[BRASTACK_SIZE];
+
+/* We can't pass back an error message if errorptr is NULL; I guess the best we
+can do is just return NULL. */
+
+if (errorptr == NULL) return NULL;
+*errorptr = NULL;
+
+/* However, we can give a message for this error */
+
+if (erroroffset == NULL)
+  {
+  *errorptr = ERR16;
+  return NULL;
+  }
+*erroroffset = 0;
+
+/* Can't support UTF8 unless PCRE has been compiled to include the code. */
+
+#ifdef SUPPORT_UTF8
+utf8 = (options & PCRE_UTF8) != 0;
+if (utf8 && (options & PCRE_NO_UTF8_CHECK) == 0 &&
+     (*erroroffset = valid_utf8((uschar *)pattern, -1)) >= 0)
+  {
+  *errorptr = ERR44;
+  return NULL;
+  }
+#else
+if ((options & PCRE_UTF8) != 0)
+  {
+  *errorptr = ERR32;
+  return NULL;
+  }
+#endif
+
+if ((options & ~PUBLIC_OPTIONS) != 0)
+  {
+  *errorptr = ERR17;
+  return NULL;
+  }
+
+/* Set up pointers to the individual character tables */
+
+if (tables == NULL) tables = pcre_default_tables;
+compile_block.lcc = tables + lcc_offset;
+compile_block.fcc = tables + fcc_offset;
+compile_block.cbits = tables + cbits_offset;
+compile_block.ctypes = tables + ctypes_offset;
+
+/* Maximum back reference and backref bitmap. This is updated for numeric
+references during the first pass, but for named references during the actual
+compile pass. The bitmap records up to 31 back references to help in deciding
+whether (.*) can be treated as anchored or not. */
+
+compile_block.top_backref = 0;
+compile_block.backref_map = 0;
+
+/* Reflect pattern for debugging output */
+
+DPRINTF(("------------------------------------------------------------------\n"));
+DPRINTF(("%s\n", pattern));
+
+/* The first thing to do is to make a pass over the pattern to compute the
+amount of store required to hold the compiled code. This does not have to be
+perfect as long as errors are overestimates. At the same time we can detect any
+flag settings right at the start, and extract them. Make an attempt to correct
+for any counted white space if an "extended" flag setting appears late in the
+pattern. We can't be so clever for #-comments. */
+
+ptr = (const uschar *)(pattern - 1);
+while ((c = *(++ptr)) != 0)
+  {
+  int min, max;
+  int class_optcount;
+  int bracket_length;
+  int duplength;
+
+  /* If we are inside a \Q...\E sequence, all chars are literal */
+
+  if (inescq)
+    {
+    if ((options & PCRE_AUTO_CALLOUT) != 0) length += 2 + 2*LINK_SIZE;
+    goto NORMAL_CHAR;
+    }
+
+  /* Otherwise, first check for ignored whitespace and comments */
+
+  if ((options & PCRE_EXTENDED) != 0)
+    {
+    if ((compile_block.ctypes[c] & ctype_space) != 0) continue;
+    if (c == '#')
+      {
+      /* The space before the ; is to avoid a warning on a silly compiler
+      on the Macintosh. */
+      while ((c = *(++ptr)) != 0 && c != NEWLINE) ;
+      if (c == 0) break;
+      continue;
+      }
+    }
+
+  item_count++;    /* Is zero for the first non-comment item */
+
+  /* Allow space for auto callout before every item except quantifiers. */
+
+  if ((options & PCRE_AUTO_CALLOUT) != 0 &&
+       c != '*' && c != '+' && c != '?' &&
+       (c != '{' || !is_counted_repeat(ptr + 1)))
+    length += 2 + 2*LINK_SIZE;
+
+  switch(c)
+    {
+    /* A backslashed item may be an escaped data character or it may be a
+    character type. */
+
+    case '\\':
+    c = check_escape(&ptr, errorptr, bracount, options, FALSE);
+    if (*errorptr != NULL) goto PCRE_ERROR_RETURN;
+
+    lastitemlength = 1;     /* Default length of last item for repeats */
+
+    if (c >= 0)             /* Data character */
+      {
+      length += 2;          /* For a one-byte character */
+
+#ifdef SUPPORT_UTF8
+      if (utf8 && c > 127)
+        {
+        int i;
+        for (i = 0; i < sizeof(utf8_table1)/sizeof(int); i++)
+          if (c <= utf8_table1[i]) break;
+        length += i;
+        lastitemlength += i;
+        }
+#endif
+
+      continue;
+      }
+
+    /* If \Q, enter "literal" mode */
+
+    if (-c == ESC_Q)
+      {
+      inescq = TRUE;
+      continue;
+      }
+
+    /* \X is supported only if Unicode property support is compiled */
+
+#ifndef SUPPORT_UCP
+    if (-c == ESC_X)
+      {
+      *errorptr = ERR45;
+      goto PCRE_ERROR_RETURN;
+      }
+#endif
+
+    /* \P and \p are for Unicode properties, but only when the support has
+    been compiled. Each item needs 2 bytes. */
+
+    else if (-c == ESC_P || -c == ESC_p)
+      {
+#ifdef SUPPORT_UCP
+      BOOL negated;
+      length += 2;
+      lastitemlength = 2;
+      if (get_ucp(&ptr, &negated, errorptr) < 0) goto PCRE_ERROR_RETURN;
+      continue;
+#else
+      *errorptr = ERR45;
+      goto PCRE_ERROR_RETURN;
+#endif
+      }
+
+    /* Other escapes need one byte */
+
+    length++;
+
+    /* A back reference needs an additional 2 bytes, plus either one or 5
+    bytes for a repeat. We also need to keep the value of the highest
+    back reference. */
+
+    if (c <= -ESC_REF)
+      {
+      int refnum = -c - ESC_REF;
+      compile_block.backref_map |= (refnum < 32)? (1 << refnum) : 1;
+      if (refnum > compile_block.top_backref)
+        compile_block.top_backref = refnum;
+      length += 2;   /* For single back reference */
+      if (ptr[1] == '{' && is_counted_repeat(ptr+2))
+        {
+        ptr = read_repeat_counts(ptr+2, &min, &max, errorptr);
+        if (*errorptr != NULL) goto PCRE_ERROR_RETURN;
+        if ((min == 0 && (max == 1 || max == -1)) ||
+          (min == 1 && max == -1))
+            length++;
+        else length += 5;
+        if (ptr[1] == '?') ptr++;
+        }
+      }
+    continue;
+
+    case '^':     /* Single-byte metacharacters */
+    case '.':
+    case '$':
+    length++;
+    lastitemlength = 1;
+    continue;
+
+    case '*':            /* These repeats won't be after brackets; */
+    case '+':            /* those are handled separately */
+    case '?':
+    length++;
+    goto POSESSIVE;      /* A few lines below */
+
+    /* This covers the cases of braced repeats after a single char, metachar,
+    class, or back reference. */
+
+    case '{':
+    if (!is_counted_repeat(ptr+1)) goto NORMAL_CHAR;
+    ptr = read_repeat_counts(ptr+1, &min, &max, errorptr);
+    if (*errorptr != NULL) goto PCRE_ERROR_RETURN;
+
+    /* These special cases just insert one extra opcode */
+
+    if ((min == 0 && (max == 1 || max == -1)) ||
+      (min == 1 && max == -1))
+        length++;
+
+    /* These cases might insert additional copies of a preceding character. */
+
+    else
+      {
+      if (min != 1)
+        {
+        length -= lastitemlength;   /* Uncount the original char or metachar */
+        if (min > 0) length += 3 + lastitemlength;
+        }
+      length += lastitemlength + ((max > 0)? 3 : 1);
+      }
+
+    if (ptr[1] == '?') ptr++;      /* Needs no extra length */
+
+    POSESSIVE:                     /* Test for possessive quantifier */
+    if (ptr[1] == '+')
+      {
+      ptr++;
+      length += 2 + 2*LINK_SIZE;   /* Allow for atomic brackets */
+      }
+    continue;
+
+    /* An alternation contains an offset to the next branch or ket. If any ims
+    options changed in the previous branch(es), and/or if we are in a
+    lookbehind assertion, extra space will be needed at the start of the
+    branch. This is handled by branch_extra. */
+
+    case '|':
+    length += 1 + LINK_SIZE + branch_extra;
+    continue;
+
+    /* A character class uses 33 characters provided that all the character
+    values are less than 256. Otherwise, it uses a bit map for low valued
+    characters, and individual items for others. Don't worry about character
+    types that aren't allowed in classes - they'll get picked up during the
+    compile. A character class that contains only one single-byte character
+    uses 2 or 3 bytes, depending on whether it is negated or not. Notice this
+    where we can. (In UTF-8 mode we can do this only for chars < 128.) */
+
+    case '[':
+    if (*(++ptr) == '^')
+      {
+      class_optcount = 10;  /* Greater than one */
+      ptr++;
+      }
+    else class_optcount = 0;
+
+#ifdef SUPPORT_UTF8
+    class_utf8 = FALSE;
+#endif
+
+    /* Written as a "do" so that an initial ']' is taken as data */
+
+    if (*ptr != 0) do
+      {
+      /* Inside \Q...\E everything is literal except \E */
+
+      if (inescq)
+        {
+        if (*ptr != '\\' || ptr[1] != 'E') goto GET_ONE_CHARACTER;
+        inescq = FALSE;
+        ptr += 1;
+        continue;
+        }
+
+      /* Outside \Q...\E, check for escapes */
+
+      if (*ptr == '\\')
+        {
+        c = check_escape(&ptr, errorptr, bracount, options, TRUE);
+        if (*errorptr != NULL) goto PCRE_ERROR_RETURN;
+
+        /* \b is backspace inside a class; \X is literal */
+
+        if (-c == ESC_b) c = '\b';
+        else if (-c == ESC_X) c = 'X';
+
+        /* \Q enters quoting mode */
+
+        else if (-c == ESC_Q)
+          {
+          inescq = TRUE;
+          continue;
+          }
+
+        /* Handle escapes that turn into characters */
+
+        if (c >= 0) goto NON_SPECIAL_CHARACTER;
+
+        /* Escapes that are meta-things. The normal ones just affect the
+        bit map, but Unicode properties require an XCLASS extended item. */
+
+        else
+          {
+          class_optcount = 10;         /* \d, \s etc; make sure > 1 */
+#ifdef SUPPORT_UTF8
+          if (-c == ESC_p || -c == ESC_P)
+            {
+            if (!class_utf8)
+              {
+              class_utf8 = TRUE;
+              length += LINK_SIZE + 2;
+              }
+            length += 2;
+            }
+#endif
+          }
+        }
+
+      /* Check the syntax for POSIX stuff. The bits we actually handle are
+      checked during the real compile phase. */
+
+      else if (*ptr == '[' && check_posix_syntax(ptr, &ptr, &compile_block))
+        {
+        ptr++;
+        class_optcount = 10;    /* Make sure > 1 */
+        }
+
+      /* Anything else increments the possible optimization count. We have to
+      detect ranges here so that we can compute the number of extra ranges for
+      caseless wide characters when UCP support is available. If there are wide
+      characters, we are going to have to use an XCLASS, even for single
+      characters. */
+
+      else
+        {
+        int d;
+
+        GET_ONE_CHARACTER:
+
+#ifdef SUPPORT_UTF8
+        if (utf8)
+          {
+          int extra = 0;
+          GETCHARLEN(c, ptr, extra);
+          ptr += extra;
+          }
+        else c = *ptr;
+#else
+        c = *ptr;
+#endif
+
+        /* Come here from handling \ above when it escapes to a char value */
+
+        NON_SPECIAL_CHARACTER:
+        class_optcount++;
+
+        d = -1;
+        if (ptr[1] == '-')
+          {
+          uschar const *hyptr = ptr++;
+          if (ptr[1] == '\\')
+            {
+            ptr++;
+            d = check_escape(&ptr, errorptr, bracount, options, TRUE);
+            if (*errorptr != NULL) goto PCRE_ERROR_RETURN;
+            if (-d == ESC_b) d = '\b';        /* backspace */
+            else if (-d == ESC_X) d = 'X';    /* literal X in a class */
+            }
+          else if (ptr[1] != 0 && ptr[1] != ']')
+            {
+            ptr++;
+#ifdef SUPPORT_UTF8
+            if (utf8)
+              {
+              int extra = 0;
+              GETCHARLEN(d, ptr, extra);
+              ptr += extra;
+              }
+            else
+#endif
+            d = *ptr;
+            }
+          if (d < 0) ptr = hyptr;      /* go back to hyphen as data */
+          }
+
+        /* If d >= 0 we have a range. In UTF-8 mode, if the end is > 255, or >
+        127 for caseless matching, we will need to use an XCLASS. */
+
+        if (d >= 0)
+          {
+          class_optcount = 10;     /* Ensure > 1 */
+          if (d < c)
+            {
+            *errorptr = ERR8;
+            goto PCRE_ERROR_RETURN;
+            }
+
+#ifdef SUPPORT_UTF8
+          if (utf8 && (d > 255 || ((options & PCRE_CASELESS) != 0 && d > 127)))
+            {
+            uschar buffer[6];
+            if (!class_utf8)         /* Allow for XCLASS overhead */
+              {
+              class_utf8 = TRUE;
+              length += LINK_SIZE + 2;
+              }
+
+#ifdef SUPPORT_UCP
+            /* If we have UCP support, find out how many extra ranges are
+            needed to map the other case of characters within this range. We
+            have to mimic the range optimization here, because extending the
+            range upwards might push d over a boundary that makes is use
+            another byte in the UTF-8 representation. */
+
+            if ((options & PCRE_CASELESS) != 0)
+              {
+              int occ, ocd;
+              int cc = c;
+              int origd = d;
+              while (get_othercase_range(&cc, origd, &occ, &ocd))
+                {
+                if (occ >= c && ocd <= d) continue;   /* Skip embedded */
+
+                if (occ < c  && ocd >= c - 1)  /* Extend the basic range */
+                  {                            /* if there is overlap,   */
+                  c = occ;                     /* noting that if occ < c */
+                  continue;                    /* we can't have ocd > d  */
+                  }                            /* because a subrange is  */
+                if (ocd > d && occ <= d + 1)   /* always shorter than    */
+                  {                            /* the basic range.       */
+                  d = ocd;
+                  continue;
+                  }
+
+                /* An extra item is needed */
+
+                length += 1 + ord2utf8(occ, buffer) +
+                  ((occ == ocd)? 0 : ord2utf8(ocd, buffer));
+                }
+              }
+#endif  /* SUPPORT_UCP */
+
+            /* The length of the (possibly extended) range */
+
+            length += 1 + ord2utf8(c, buffer) + ord2utf8(d, buffer);
+            }
+#endif  /* SUPPORT_UTF8 */
+
+          }
+
+        /* We have a single character. There is nothing to be done unless we
+        are in UTF-8 mode. If the char is > 255, or 127 when caseless, we must
+        allow for an XCL_SINGLE item, doubled for caselessness if there is UCP
+        support. */
+
+        else
+          {
+#ifdef SUPPORT_UTF8
+          if (utf8 && (c > 255 || ((options & PCRE_CASELESS) != 0 && c > 127)))
+            {
+            uschar buffer[6];
+            class_optcount = 10;     /* Ensure > 1 */
+            if (!class_utf8)         /* Allow for XCLASS overhead */
+              {
+              class_utf8 = TRUE;
+              length += LINK_SIZE + 2;
+              }
+#ifdef SUPPORT_UCP
+            length += (((options & PCRE_CASELESS) != 0)? 2 : 1) *
+              (1 + ord2utf8(c, buffer));
+#else   /* SUPPORT_UCP */
+            length += 1 + ord2utf8(c, buffer);
+#endif  /* SUPPORT_UCP */
+            }
+#endif  /* SUPPORT_UTF8 */
+          }
+        }
+      }
+    while (*(++ptr) != 0 && (inescq || *ptr != ']')); /* Concludes "do" above */
+
+    if (*ptr == 0)                          /* Missing terminating ']' */
+      {
+      *errorptr = ERR6;
+      goto PCRE_ERROR_RETURN;
+      }
+
+    /* We can optimize when there was only one optimizable character. Repeats
+    for positive and negated single one-byte chars are handled by the general
+    code. Here, we handle repeats for the class opcodes. */
+
+    if (class_optcount == 1) length += 3; else
+      {
+      length += 33;
+
+      /* A repeat needs either 1 or 5 bytes. If it is a possessive quantifier,
+      we also need extra for wrapping the whole thing in a sub-pattern. */
+
+      if (*ptr != 0 && ptr[1] == '{' && is_counted_repeat(ptr+2))
+        {
+        ptr = read_repeat_counts(ptr+2, &min, &max, errorptr);
+        if (*errorptr != NULL) goto PCRE_ERROR_RETURN;
+        if ((min == 0 && (max == 1 || max == -1)) ||
+          (min == 1 && max == -1))
+            length++;
+        else length += 5;
+        if (ptr[1] == '+')
+          {
+          ptr++;
+          length += 2 + 2*LINK_SIZE;
+          }
+        else if (ptr[1] == '?') ptr++;
+        }
+      }
+    continue;
+
+    /* Brackets may be genuine groups or special things */
+
+    case '(':
+    branch_newextra = 0;
+    bracket_length = 1 + LINK_SIZE;
+
+    /* Handle special forms of bracket, which all start (? */
+
+    if (ptr[1] == '?')
+      {
+      int set, unset;
+      int *optset;
+
+      switch (c = ptr[2])
+        {
+        /* Skip over comments entirely */
+        case '#':
+        ptr += 3;
+        while (*ptr != 0 && *ptr != ')') ptr++;
+        if (*ptr == 0)
+          {
+          *errorptr = ERR18;
+          goto PCRE_ERROR_RETURN;
+          }
+        continue;
+
+        /* Non-referencing groups and lookaheads just move the pointer on, and
+        then behave like a non-special bracket, except that they don't increment
+        the count of extracting brackets. Ditto for the "once only" bracket,
+        which is in Perl from version 5.005. */
+
+        case ':':
+        case '=':
+        case '!':
+        case '>':
+        ptr += 2;
+        break;
+
+        /* (?R) specifies a recursive call to the regex, which is an extension
+        to provide the facility which can be obtained by (?p{perl-code}) in
+        Perl 5.6. In Perl 5.8 this has become (??{perl-code}).
+
+        From PCRE 4.00, items such as (?3) specify subroutine-like "calls" to
+        the appropriate numbered brackets. This includes both recursive and
+        non-recursive calls. (?R) is now synonymous with (?0). */
+
+        case 'R':
+        ptr++;
+
+        case '0': case '1': case '2': case '3': case '4':
+        case '5': case '6': case '7': case '8': case '9':
+        ptr += 2;
+        if (c != 'R')
+          while ((digitab[*(++ptr)] & ctype_digit) != 0);
+        if (*ptr != ')')
+          {
+          *errorptr = ERR29;
+          goto PCRE_ERROR_RETURN;
+          }
+        length += 1 + LINK_SIZE;
+
+        /* If this item is quantified, it will get wrapped inside brackets so
+        as to use the code for quantified brackets. We jump down and use the
+        code that handles this for real brackets. */
+
+        if (ptr[1] == '+' || ptr[1] == '*' || ptr[1] == '?' || ptr[1] == '{')
+          {
+          length += 2 + 2 * LINK_SIZE;       /* to make bracketed */
+          duplength = 5 + 3 * LINK_SIZE;
+          goto HANDLE_QUANTIFIED_BRACKETS;
+          }
+        continue;
+
+        /* (?C) is an extension which provides "callout" - to provide a bit of
+        the functionality of the Perl (?{...}) feature. An optional number may
+        follow (default is zero). */
+
+        case 'C':
+        ptr += 2;
+        while ((digitab[*(++ptr)] & ctype_digit) != 0);
+        if (*ptr != ')')
+          {
+          *errorptr = ERR39;
+          goto PCRE_ERROR_RETURN;
+          }
+        length += 2 + 2*LINK_SIZE;
+        continue;
+
+        /* Named subpatterns are an extension copied from Python */
+
+        case 'P':
+        ptr += 3;
+        if (*ptr == '<')
+          {
+          const uschar *p;    /* Don't amalgamate; some compilers */
+          p = ++ptr;          /* grumble at autoincrement in declaration */
+          while ((compile_block.ctypes[*ptr] & ctype_word) != 0) ptr++;
+          if (*ptr != '>')
+            {
+            *errorptr = ERR42;
+            goto PCRE_ERROR_RETURN;
+            }
+          name_count++;
+          if (ptr - p > max_name_size) max_name_size = (ptr - p);
+          break;
+          }
+
+        if (*ptr == '=' || *ptr == '>')
+          {
+          while ((compile_block.ctypes[*(++ptr)] & ctype_word) != 0);
+          if (*ptr != ')')
+            {
+            *errorptr = ERR42;
+            goto PCRE_ERROR_RETURN;
+            }
+          break;
+          }
+
+        /* Unknown character after (?P */
+
+        *errorptr = ERR41;
+        goto PCRE_ERROR_RETURN;
+
+        /* Lookbehinds are in Perl from version 5.005 */
+
+        case '<':
+        ptr += 3;
+        if (*ptr == '=' || *ptr == '!')
+          {
+          branch_newextra = 1 + LINK_SIZE;
+          length += 1 + LINK_SIZE;         /* For the first branch */
+          break;
+          }
+        *errorptr = ERR24;
+        goto PCRE_ERROR_RETURN;
+
+        /* Conditionals are in Perl from version 5.005. The bracket must either
+        be followed by a number (for bracket reference) or by an assertion
+        group, or (a PCRE extension) by 'R' for a recursion test. */
+
+        case '(':
+        if (ptr[3] == 'R' && ptr[4] == ')')
+          {
+          ptr += 4;
+          length += 3;
+          }
+        else if ((digitab[ptr[3]] & ctype_digit) != 0)
+          {
+          ptr += 4;
+          length += 3;
+          while ((digitab[*ptr] & ctype_digit) != 0) ptr++;
+          if (*ptr != ')')
+            {
+            *errorptr = ERR26;
+            goto PCRE_ERROR_RETURN;
+            }
+          }
+        else   /* An assertion must follow */
+          {
+          ptr++;   /* Can treat like ':' as far as spacing is concerned */
+          if (ptr[2] != '?' ||
+             (ptr[3] != '=' && ptr[3] != '!' && ptr[3] != '<') )
+            {
+            ptr += 2;    /* To get right offset in message */
+            *errorptr = ERR28;
+            goto PCRE_ERROR_RETURN;
+            }
+          }
+        break;
+
+        /* Else loop checking valid options until ) is met. Anything else is an
+        error. If we are without any brackets, i.e. at top level, the settings
+        act as if specified in the options, so massage the options immediately.
+        This is for backward compatibility with Perl 5.004. */
+
+        default:
+        set = unset = 0;
+        optset = &set;
+        ptr += 2;
+
+        for (;; ptr++)
+          {
+          c = *ptr;
+          switch (c)
+            {
+            case 'i':
+            *optset |= PCRE_CASELESS;
+            continue;
+
+            case 'm':
+            *optset |= PCRE_MULTILINE;
+            continue;
+
+            case 's':
+            *optset |= PCRE_DOTALL;
+            continue;
+
+            case 'x':
+            *optset |= PCRE_EXTENDED;
+            continue;
+
+            case 'X':
+            *optset |= PCRE_EXTRA;
+            continue;
+
+            case 'U':
+            *optset |= PCRE_UNGREEDY;
+            continue;
+
+            case '-':
+            optset = &unset;
+            continue;
+
+            /* A termination by ')' indicates an options-setting-only item; if
+            this is at the very start of the pattern (indicated by item_count
+            being zero), we use it to set the global options. This is helpful
+            when analyzing the pattern for first characters, etc. Otherwise
+            nothing is done here and it is handled during the compiling
+            process.
+
+            [Historical note: Up to Perl 5.8, options settings at top level
+            were always global settings, wherever they appeared in the pattern.
+            That is, they were equivalent to an external setting. From 5.8
+            onwards, they apply only to what follows (which is what you might
+            expect).] */
+
+            case ')':
+            if (item_count == 0)
+              {
+              options = (options | set) & (~unset);
+              set = unset = 0;     /* To save length */
+              item_count--;        /* To allow for several */
+              }
+
+            /* Fall through */
+
+            /* A termination by ':' indicates the start of a nested group with
+            the given options set. This is again handled at compile time, but
+            we must allow for compiled space if any of the ims options are
+            set. We also have to allow for resetting space at the end of
+            the group, which is why 4 is added to the length and not just 2.
+            If there are several changes of options within the same group, this
+            will lead to an over-estimate on the length, but this shouldn't
+            matter very much. We also have to allow for resetting options at
+            the start of any alternations, which we do by setting
+            branch_newextra to 2. Finally, we record whether the case-dependent
+            flag ever changes within the regex. This is used by the "required
+            character" code. */
+
+            case ':':
+            if (((set|unset) & PCRE_IMS) != 0)
+              {
+              length += 4;
+              branch_newextra = 2;
+              if (((set|unset) & PCRE_CASELESS) != 0) options |= PCRE_ICHANGED;
+              }
+            goto END_OPTIONS;
+
+            /* Unrecognized option character */
+
+            default:
+            *errorptr = ERR12;
+            goto PCRE_ERROR_RETURN;
+            }
+          }
+
+        /* If we hit a closing bracket, that's it - this is a freestanding
+        option-setting. We need to ensure that branch_extra is updated if
+        necessary. The only values branch_newextra can have here are 0 or 2.
+        If the value is 2, then branch_extra must either be 2 or 5, depending
+        on whether this is a lookbehind group or not. */
+
+        END_OPTIONS:
+        if (c == ')')
+          {
+          if (branch_newextra == 2 &&
+              (branch_extra == 0 || branch_extra == 1+LINK_SIZE))
+            branch_extra += branch_newextra;
+          continue;
+          }
+
+        /* If options were terminated by ':' control comes here. Fall through
+        to handle the group below. */
+        }
+      }
+
+    /* Extracting brackets must be counted so we can process escapes in a
+    Perlish way. If the number exceeds EXTRACT_BASIC_MAX we are going to
+    need an additional 3 bytes of store per extracting bracket. However, if
+    PCRE_NO_AUTO)CAPTURE is set, unadorned brackets become non-capturing, so we
+    must leave the count alone (it will aways be zero). */
+
+    else if ((options & PCRE_NO_AUTO_CAPTURE) == 0)
+      {
+      bracount++;
+      if (bracount > EXTRACT_BASIC_MAX) bracket_length += 3;
+      }
+
+    /* Save length for computing whole length at end if there's a repeat that
+    requires duplication of the group. Also save the current value of
+    branch_extra, and start the new group with the new value. If non-zero, this
+    will either be 2 for a (?imsx: group, or 3 for a lookbehind assertion. */
+
+    if (brastackptr >= sizeof(brastack)/sizeof(int))
+      {
+      *errorptr = ERR19;
+      goto PCRE_ERROR_RETURN;
+      }
+
+    bralenstack[brastackptr] = branch_extra;
+    branch_extra = branch_newextra;
+
+    brastack[brastackptr++] = length;
+    length += bracket_length;
+    continue;
+
+    /* Handle ket. Look for subsequent max/min; for certain sets of values we
+    have to replicate this bracket up to that many times. If brastackptr is
+    0 this is an unmatched bracket which will generate an error, but take care
+    not to try to access brastack[-1] when computing the length and restoring
+    the branch_extra value. */
+
+    case ')':
+    length += 1 + LINK_SIZE;
+    if (brastackptr > 0)
+      {
+      duplength = length - brastack[--brastackptr];
+      branch_extra = bralenstack[brastackptr];
+      }
+    else duplength = 0;
+
+    /* The following code is also used when a recursion such as (?3) is
+    followed by a quantifier, because in that case, it has to be wrapped inside
+    brackets so that the quantifier works. The value of duplength must be
+    set before arrival. */
+
+    HANDLE_QUANTIFIED_BRACKETS:
+
+    /* Leave ptr at the final char; for read_repeat_counts this happens
+    automatically; for the others we need an increment. */
+
+    if ((c = ptr[1]) == '{' && is_counted_repeat(ptr+2))
+      {
+      ptr = read_repeat_counts(ptr+2, &min, &max, errorptr);
+      if (*errorptr != NULL) goto PCRE_ERROR_RETURN;
+      }
+    else if (c == '*') { min = 0; max = -1; ptr++; }
+    else if (c == '+') { min = 1; max = -1; ptr++; }
+    else if (c == '?') { min = 0; max = 1;  ptr++; }
+    else { min = 1; max = 1; }
+
+    /* If the minimum is zero, we have to allow for an OP_BRAZERO before the
+    group, and if the maximum is greater than zero, we have to replicate
+    maxval-1 times; each replication acquires an OP_BRAZERO plus a nesting
+    bracket set. */
+
+    if (min == 0)
+      {
+      length++;
+      if (max > 0) length += (max - 1) * (duplength + 3 + 2*LINK_SIZE);
+      }
+
+    /* When the minimum is greater than zero, we have to replicate up to
+    minval-1 times, with no additions required in the copies. Then, if there
+    is a limited maximum we have to replicate up to maxval-1 times allowing
+    for a BRAZERO item before each optional copy and nesting brackets for all
+    but one of the optional copies. */
+
+    else
+      {
+      length += (min - 1) * duplength;
+      if (max > min)   /* Need this test as max=-1 means no limit */
+        length += (max - min) * (duplength + 3 + 2*LINK_SIZE)
+          - (2 + 2*LINK_SIZE);
+      }
+
+    /* Allow space for once brackets for "possessive quantifier" */
+
+    if (ptr[1] == '+')
+      {
+      ptr++;
+      length += 2 + 2*LINK_SIZE;
+      }
+    continue;
+
+    /* Non-special character. It won't be space or # in extended mode, so it is
+    always a genuine character. If we are in a \Q...\E sequence, check for the
+    end; if not, we have a literal. */
+
+    default:
+    NORMAL_CHAR:
+
+    if (inescq && c == '\\' && ptr[1] == 'E')
+      {
+      inescq = FALSE;
+      ptr++;
+      continue;
+      }
+
+    length += 2;          /* For a one-byte character */
+    lastitemlength = 1;   /* Default length of last item for repeats */
+
+    /* In UTF-8 mode, check for additional bytes. */
+
+#ifdef SUPPORT_UTF8
+    if (utf8 && (c & 0xc0) == 0xc0)
+      {
+      while ((ptr[1] & 0xc0) == 0x80)         /* Can't flow over the end */
+        {                                     /* because the end is marked */
+        lastitemlength++;                     /* by a zero byte. */
+        length++;
+        ptr++;
+        }
+      }
+#endif
+
+    continue;
+    }
+  }
+
+length += 2 + LINK_SIZE;    /* For final KET and END */
+
+if ((options & PCRE_AUTO_CALLOUT) != 0)
+  length += 2 + 2*LINK_SIZE;  /* For final callout */
+
+if (length > MAX_PATTERN_SIZE)
+  {
+  *errorptr = ERR20;
+  return NULL;
+  }
+
+/* Compute the size of data block needed and get it, either from malloc or
+externally provided function. */
+
+size = length + sizeof(real_pcre) + name_count * (max_name_size + 3);
+re = (real_pcre *)(pcre_malloc)(size);
+
+if (re == NULL)
+  {
+  *errorptr = ERR21;
+  return NULL;
+  }
+
+/* Put in the magic number, and save the sizes, options, and character table
+pointer. NULL is used for the default character tables. The nullpad field is at
+the end; it's there to help in the case when a regex compiled on a system with
+4-byte pointers is run on another with 8-byte pointers. */
+
+re->magic_number = MAGIC_NUMBER;
+re->size = size;
+re->options = options;
+re->dummy1 = re->dummy2 = 0;
+re->name_table_offset = sizeof(real_pcre);
+re->name_entry_size = max_name_size + 3;
+re->name_count = name_count;
+re->tables = (tables == pcre_default_tables)? NULL : tables;
+re->nullpad = NULL;
+
+/* The starting points of the name/number translation table and of the code are
+passed around in the compile data block. */
+
+compile_block.names_found = 0;
+compile_block.name_entry_size = max_name_size + 3;
+compile_block.name_table = (uschar *)re + re->name_table_offset;
+codestart = compile_block.name_table + re->name_entry_size * re->name_count;
+compile_block.start_code = codestart;
+compile_block.start_pattern = (const uschar *)pattern;
+compile_block.req_varyopt = 0;
+compile_block.nopartial = FALSE;
+
+/* Set up a starting, non-extracting bracket, then compile the expression. On
+error, *errorptr will be set non-NULL, so we don't need to look at the result
+of the function here. */
+
+ptr = (const uschar *)pattern;
+code = (uschar *)codestart;
+*code = OP_BRA;
+bracount = 0;
+(void)compile_regex(options, options & PCRE_IMS, &bracount, &code, &ptr,
+  errorptr, FALSE, 0, &firstbyte, &reqbyte, NULL, &compile_block);
+re->top_bracket = bracount;
+re->top_backref = compile_block.top_backref;
+
+if (compile_block.nopartial) re->options |= PCRE_NOPARTIAL;
+
+/* If not reached end of pattern on success, there's an excess bracket. */
+
+if (*errorptr == NULL && *ptr != 0) *errorptr = ERR22;
+
+/* Fill in the terminating state and check for disastrous overflow, but
+if debugging, leave the test till after things are printed out. */
+
+*code++ = OP_END;
+
+#ifndef DEBUG
+if (code - codestart > length) *errorptr = ERR23;
+#endif
+
+/* Give an error if there's back reference to a non-existent capturing
+subpattern. */
+
+if (re->top_backref > re->top_bracket) *errorptr = ERR15;
+
+/* Failed to compile, or error while post-processing */
+
+if (*errorptr != NULL)
+  {
+  (pcre_free)(re);
+  PCRE_ERROR_RETURN:
+  *erroroffset = ptr - (const uschar *)pattern;
+  return NULL;
+  }
+
+/* If the anchored option was not passed, set the flag if we can determine that
+the pattern is anchored by virtue of ^ characters or \A or anything else (such
+as starting with .* when DOTALL is set).
+
+Otherwise, if we know what the first character has to be, save it, because that
+speeds up unanchored matches no end. If not, see if we can set the
+PCRE_STARTLINE flag. This is helpful for multiline matches when all branches
+start with ^. and also when all branches start with .* for non-DOTALL matches.
+*/
+
+if ((options & PCRE_ANCHORED) == 0)
+  {
+  int temp_options = options;
+  if (is_anchored(codestart, &temp_options, 0, compile_block.backref_map))
+    re->options |= PCRE_ANCHORED;
+  else
+    {
+    if (firstbyte < 0)
+      firstbyte = find_firstassertedchar(codestart, &temp_options, FALSE);
+    if (firstbyte >= 0)   /* Remove caseless flag for non-caseable chars */
+      {
+      int ch = firstbyte & 255;
+      re->first_byte = ((firstbyte & REQ_CASELESS) != 0 &&
+         compile_block.fcc[ch] == ch)? ch : firstbyte;
+      re->options |= PCRE_FIRSTSET;
+      }
+    else if (is_startline(codestart, 0, compile_block.backref_map))
+      re->options |= PCRE_STARTLINE;
+    }
+  }
+
+/* For an anchored pattern, we use the "required byte" only if it follows a
+variable length item in the regex. Remove the caseless flag for non-caseable
+bytes. */
+
+if (reqbyte >= 0 &&
+     ((re->options & PCRE_ANCHORED) == 0 || (reqbyte & REQ_VARY) != 0))
+  {
+  int ch = reqbyte & 255;
+  re->req_byte = ((reqbyte & REQ_CASELESS) != 0 &&
+    compile_block.fcc[ch] == ch)? (reqbyte & ~REQ_CASELESS) : reqbyte;
+  re->options |= PCRE_REQCHSET;
+  }
+
+/* Print out the compiled data for debugging */
+
+#ifdef DEBUG
+
+printf("Length = %d top_bracket = %d top_backref = %d\n",
+  length, re->top_bracket, re->top_backref);
+
+if (re->options != 0)
+  {
+  printf("%s%s%s%s%s%s%s%s%s%s\n",
+    ((re->options & PCRE_NOPARTIAL) != 0)? "nopartial " : "",
+    ((re->options & PCRE_ANCHORED) != 0)? "anchored " : "",
+    ((re->options & PCRE_CASELESS) != 0)? "caseless " : "",
+    ((re->options & PCRE_ICHANGED) != 0)? "case state changed " : "",
+    ((re->options & PCRE_EXTENDED) != 0)? "extended " : "",
+    ((re->options & PCRE_MULTILINE) != 0)? "multiline " : "",
+    ((re->options & PCRE_DOTALL) != 0)? "dotall " : "",
+    ((re->options & PCRE_DOLLAR_ENDONLY) != 0)? "endonly " : "",
+    ((re->options & PCRE_EXTRA) != 0)? "extra " : "",
+    ((re->options & PCRE_UNGREEDY) != 0)? "ungreedy " : "");
+  }
+
+if ((re->options & PCRE_FIRSTSET) != 0)
+  {
+  int ch = re->first_byte & 255;
+  const char *caseless = ((re->first_byte & REQ_CASELESS) == 0)? "" : " (caseless)";
+  if (isprint(ch)) printf("First char = %c%s\n", ch, caseless);
+    else printf("First char = \\x%02x%s\n", ch, caseless);
+  }
+
+if ((re->options & PCRE_REQCHSET) != 0)
+  {
+  int ch = re->req_byte & 255;
+  const char *caseless = ((re->req_byte & REQ_CASELESS) == 0)? "" : " (caseless)";
+  if (isprint(ch)) printf("Req char = %c%s\n", ch, caseless);
+    else printf("Req char = \\x%02x%s\n", ch, caseless);
+  }
+
+print_internals(re, stdout);
+
+/* This check is done here in the debugging case so that the code that
+was compiled can be seen. */
+
+if (code - codestart > length)
+  {
+  *errorptr = ERR23;
+  (pcre_free)(re);
+  *erroroffset = ptr - (uschar *)pattern;
+  return NULL;
+  }
+#endif
+
+return (pcre *)re;
+}
+
+
+
+/*************************************************
+*          Match a back-reference                *
+*************************************************/
+
+/* If a back reference hasn't been set, the length that is passed is greater
+than the number of characters left in the string, so the match fails.
+
+Arguments:
+  offset      index into the offset vector
+  eptr        points into the subject
+  length      length to be matched
+  md          points to match data block
+  ims         the ims flags
+
+Returns:      TRUE if matched
+*/
+
+static BOOL
+match_ref(int offset, register const uschar *eptr, int length, match_data *md,
+  unsigned long int ims)
+{
+const uschar *p = md->start_subject + md->offset_vector[offset];
+
+#ifdef DEBUG
+if (eptr >= md->end_subject)
+  printf("matching subject <null>");
+else
+  {
+  printf("matching subject ");
+  pchars(eptr, length, TRUE, md);
+  }
+printf(" against backref ");
+pchars(p, length, FALSE, md);
+printf("\n");
+#endif
+
+/* Always fail if not enough characters left */
+
+if (length > md->end_subject - eptr) return FALSE;
+
+/* Separate the caselesss case for speed */
+
+if ((ims & PCRE_CASELESS) != 0)
+  {
+  while (length-- > 0)
+    if (md->lcc[*p++] != md->lcc[*eptr++]) return FALSE;
+  }
+else
+  { while (length-- > 0) if (*p++ != *eptr++) return FALSE; }
+
+return TRUE;
+}
+
+
+#ifdef SUPPORT_UTF8
+/*************************************************
+*       Match character against an XCLASS        *
+*************************************************/
+
+/* This function is called from within the XCLASS code below, to match a
+character against an extended class which might match values > 255.
+
+Arguments:
+  c           the character
+  data        points to the flag byte of the XCLASS data
+
+Returns:      TRUE if character matches, else FALSE
+*/
+
+static BOOL
+match_xclass(int c, const uschar *data)
+{
+int t;
+BOOL negated = (*data & XCL_NOT) != 0;
+
+/* Character values < 256 are matched against a bitmap, if one is present. If
+not, we still carry on, because there may be ranges that start below 256 in the
+additional data. */
+
+if (c < 256)
+  {
+  if ((*data & XCL_MAP) != 0 && (data[1 + c/8] & (1 << (c&7))) != 0)
+    return !negated;   /* char found */
+  }
+
+/* First skip the bit map if present. Then match against the list of Unicode
+properties or large chars or ranges that end with a large char. We won't ever
+encounter XCL_PROP or XCL_NOTPROP when UCP support is not compiled. */
+
+if ((*data++ & XCL_MAP) != 0) data += 32;
+
+while ((t = *data++) != XCL_END)
+  {
+  int x, y;
+  if (t == XCL_SINGLE)
+    {
+    GETCHARINC(x, data);
+    if (c == x) return !negated;
+    }
+  else if (t == XCL_RANGE)
+    {
+    GETCHARINC(x, data);
+    GETCHARINC(y, data);
+    if (c >= x && c <= y) return !negated;
+    }
+
+#ifdef SUPPORT_UCP
+  else  /* XCL_PROP & XCL_NOTPROP */
+    {
+    int chartype, othercase;
+    int rqdtype = *data++;
+    int category = ucp_findchar(c, &chartype, &othercase);
+    if (rqdtype >= 128)
+      {
+      if ((rqdtype - 128 == category) == (t == XCL_PROP)) return !negated;
+      }
+    else
+      {
+      if ((rqdtype == chartype) == (t == XCL_PROP)) return !negated;
+      }
+    }
+#endif  /* SUPPORT_UCP */
+  }
+
+return negated;   /* char did not match */
+}
+#endif
+
+
+/***************************************************************************
+****************************************************************************
+                   RECURSION IN THE match() FUNCTION
+
+The match() function is highly recursive. Some regular expressions can cause
+it to recurse thousands of times. I was writing for Unix, so I just let it
+call itself recursively. This uses the stack for saving everything that has
+to be saved for a recursive call. On Unix, the stack can be large, and this
+works fine.
+
+It turns out that on non-Unix systems there are problems with programs that
+use a lot of stack. (This despite the fact that every last chip has oodles
+of memory these days, and techniques for extending the stack have been known
+for decades.) So....
+
+There is a fudge, triggered by defining NO_RECURSE, which avoids recursive
+calls by keeping local variables that need to be preserved in blocks of memory
+obtained from malloc instead instead of on the stack. Macros are used to
+achieve this so that the actual code doesn't look very different to what it
+always used to.
+****************************************************************************
+***************************************************************************/
+
+
+/* These versions of the macros use the stack, as normal */
+
+#ifndef NO_RECURSE
+#define REGISTER register
+#define RMATCH(rx,ra,rb,rc,rd,re,rf,rg) rx = match(ra,rb,rc,rd,re,rf,rg)
+#define RRETURN(ra) return ra
+#else
+
+
+/* These versions of the macros manage a private stack on the heap. Note
+that the rd argument of RMATCH isn't actually used. It's the md argument of
+match(), which never changes. */
+
+#define REGISTER
+
+#define RMATCH(rx,ra,rb,rc,rd,re,rf,rg)\
+  {\
+  heapframe *newframe = (pcre_stack_malloc)(sizeof(heapframe));\
+  if (setjmp(frame->Xwhere) == 0)\
+    {\
+    newframe->Xeptr = ra;\
+    newframe->Xecode = rb;\
+    newframe->Xoffset_top = rc;\
+    newframe->Xims = re;\
+    newframe->Xeptrb = rf;\
+    newframe->Xflags = rg;\
+    newframe->Xprevframe = frame;\
+    frame = newframe;\
+    DPRINTF(("restarting from line %d\n", __LINE__));\
+    goto HEAP_RECURSE;\
+    }\
+  else\
+    {\
+    DPRINTF(("longjumped back to line %d\n", __LINE__));\
+    frame = md->thisframe;\
+    rx = frame->Xresult;\
+    }\
+  }
+
+#define RRETURN(ra)\
+  {\
+  heapframe *newframe = frame;\
+  frame = newframe->Xprevframe;\
+  (pcre_stack_free)(newframe);\
+  if (frame != NULL)\
+    {\
+    frame->Xresult = ra;\
+    md->thisframe = frame;\
+    longjmp(frame->Xwhere, 1);\
+    }\
+  return ra;\
+  }
+
+
+/* Structure for remembering the local variables in a private frame */
+
+typedef struct heapframe {
+  struct heapframe *Xprevframe;
+
+  /* Function arguments that may change */
+
+  const uschar *Xeptr;
+  const uschar *Xecode;
+  int Xoffset_top;
+  long int Xims;
+  eptrblock *Xeptrb;
+  int Xflags;
+
+  /* Function local variables */
+
+  const uschar *Xcallpat;
+  const uschar *Xcharptr;
+  const uschar *Xdata;
+  const uschar *Xnext;
+  const uschar *Xpp;
+  const uschar *Xprev;
+  const uschar *Xsaved_eptr;
+
+  recursion_info Xnew_recursive;
+
+  BOOL Xcur_is_word;
+  BOOL Xcondition;
+  BOOL Xminimize;
+  BOOL Xprev_is_word;
+
+  unsigned long int Xoriginal_ims;
+
+#ifdef SUPPORT_UCP
+  int Xprop_type;
+  int Xprop_fail_result;
+  int Xprop_category;
+  int Xprop_chartype;
+  int Xprop_othercase;
+  int Xprop_test_against;
+  int *Xprop_test_variable;
+#endif
+
+  int Xctype;
+  int Xfc;
+  int Xfi;
+  int Xlength;
+  int Xmax;
+  int Xmin;
+  int Xnumber;
+  int Xoffset;
+  int Xop;
+  int Xsave_capture_last;
+  int Xsave_offset1, Xsave_offset2, Xsave_offset3;
+  int Xstacksave[REC_STACK_SAVE_MAX];
+
+  eptrblock Xnewptrb;
+
+  /* Place to pass back result, and where to jump back to */
+
+  int  Xresult;
+  jmp_buf Xwhere;
+
+} heapframe;
+
+#endif
+
+
+/***************************************************************************
+***************************************************************************/
+
+
+
+/*************************************************
+*         Match from current position            *
+*************************************************/
+
+/* On entry ecode points to the first opcode, and eptr to the first character
+in the subject string, while eptrb holds the value of eptr at the start of the
+last bracketed group - used for breaking infinite loops matching zero-length
+strings. This function is called recursively in many circumstances. Whenever it
+returns a negative (error) response, the outer incarnation must also return the
+same response.
+
+Performance note: It might be tempting to extract commonly used fields from the
+md structure (e.g. utf8, end_subject) into individual variables to improve
+performance. Tests using gcc on a SPARC disproved this; in the first case, it
+made performance worse.
+
+Arguments:
+   eptr        pointer in subject
+   ecode       position in code
+   offset_top  current top pointer
+   md          pointer to "static" info for the match
+   ims         current /i, /m, and /s options
+   eptrb       pointer to chain of blocks containing eptr at start of
+                 brackets - for testing for empty matches
+   flags       can contain
+                 match_condassert - this is an assertion condition
+                 match_isgroup - this is the start of a bracketed group
+
+Returns:       MATCH_MATCH if matched            )  these values are >= 0
+               MATCH_NOMATCH if failed to match  )
+               a negative PCRE_ERROR_xxx value if aborted by an error condition
+                 (e.g. stopped by recursion limit)
+*/
+
+static int
+match(REGISTER const uschar *eptr, REGISTER const uschar *ecode,
+  int offset_top, match_data *md, unsigned long int ims, eptrblock *eptrb,
+  int flags)
+{
+/* These variables do not need to be preserved over recursion in this function,
+so they can be ordinary variables in all cases. Mark them with "register"
+because they are used a lot in loops. */
+
+register int rrc;    /* Returns from recursive calls */
+register int i;      /* Used for loops not involving calls to RMATCH() */
+register int c;      /* Character values not kept over RMATCH() calls */
+
+/* When recursion is not being used, all "local" variables that have to be
+preserved over calls to RMATCH() are part of a "frame" which is obtained from
+heap storage. Set up the top-level frame here; others are obtained from the
+heap whenever RMATCH() does a "recursion". See the macro definitions above. */
+
+#ifdef NO_RECURSE
+heapframe *frame = (pcre_stack_malloc)(sizeof(heapframe));
+frame->Xprevframe = NULL;            /* Marks the top level */
+
+/* Copy in the original argument variables */
+
+frame->Xeptr = eptr;
+frame->Xecode = ecode;
+frame->Xoffset_top = offset_top;
+frame->Xims = ims;
+frame->Xeptrb = eptrb;
+frame->Xflags = flags;
+
+/* This is where control jumps back to to effect "recursion" */
+
+HEAP_RECURSE:
+
+/* Macros make the argument variables come from the current frame */
+
+#define eptr               frame->Xeptr
+#define ecode              frame->Xecode
+#define offset_top         frame->Xoffset_top
+#define ims                frame->Xims
+#define eptrb              frame->Xeptrb
+#define flags              frame->Xflags
+
+/* Ditto for the local variables */
+
+#ifdef SUPPORT_UTF8
+#define charptr            frame->Xcharptr
+#endif
+#define callpat            frame->Xcallpat
+#define data               frame->Xdata
+#define next               frame->Xnext
+#define pp                 frame->Xpp
+#define prev               frame->Xprev
+#define saved_eptr         frame->Xsaved_eptr
+
+#define new_recursive      frame->Xnew_recursive
+
+#define cur_is_word        frame->Xcur_is_word
+#define condition          frame->Xcondition
+#define minimize           frame->Xminimize
+#define prev_is_word       frame->Xprev_is_word
+
+#define original_ims       frame->Xoriginal_ims
+
+#ifdef SUPPORT_UCP
+#define prop_type          frame->Xprop_type
+#define prop_fail_result   frame->Xprop_fail_result
+#define prop_category      frame->Xprop_category
+#define prop_chartype      frame->Xprop_chartype
+#define prop_othercase     frame->Xprop_othercase
+#define prop_test_against  frame->Xprop_test_against
+#define prop_test_variable frame->Xprop_test_variable
+#endif
+
+#define ctype              frame->Xctype
+#define fc                 frame->Xfc
+#define fi                 frame->Xfi
+#define length             frame->Xlength
+#define max                frame->Xmax
+#define min                frame->Xmin
+#define number             frame->Xnumber
+#define offset             frame->Xoffset
+#define op                 frame->Xop
+#define save_capture_last  frame->Xsave_capture_last
+#define save_offset1       frame->Xsave_offset1
+#define save_offset2       frame->Xsave_offset2
+#define save_offset3       frame->Xsave_offset3
+#define stacksave          frame->Xstacksave
+
+#define newptrb            frame->Xnewptrb
+
+/* When recursion is being used, local variables are allocated on the stack and
+get preserved during recursion in the normal way. In this environment, fi and
+i, and fc and c, can be the same variables. */
+
+#else
+#define fi i
+#define fc c
+
+
+#ifdef SUPPORT_UTF8                /* Many of these variables are used ony */
+const uschar *charptr;             /* small blocks of the code. My normal  */
+#endif                             /* style of coding would have declared  */
+const uschar *callpat;             /* them within each of those blocks.    */
+const uschar *data;                /* However, in order to accommodate the */
+const uschar *next;                /* version of this code that uses an    */
+const uschar *pp;                  /* external "stack" implemented on the  */
+const uschar *prev;                /* heap, it is easier to declare them   */
+const uschar *saved_eptr;          /* all here, so the declarations can    */
+                                   /* be cut out in a block. The only      */
+recursion_info new_recursive;      /* declarations within blocks below are */
+                                   /* for variables that do not have to    */
+BOOL cur_is_word;                  /* be preserved over a recursive call   */
+BOOL condition;                    /* to RMATCH().                         */
+BOOL minimize;
+BOOL prev_is_word;
+
+unsigned long int original_ims;
+
+#ifdef SUPPORT_UCP
+int prop_type;
+int prop_fail_result;
+int prop_category;
+int prop_chartype;
+int prop_othercase;
+int prop_test_against;
+int *prop_test_variable;
+#endif
+
+int ctype;
+int length;
+int max;
+int min;
+int number;
+int offset;
+int op;
+int save_capture_last;
+int save_offset1, save_offset2, save_offset3;
+int stacksave[REC_STACK_SAVE_MAX];
+
+eptrblock newptrb;
+#endif
+
+/* These statements are here to stop the compiler complaining about unitialized
+variables. */
+
+#ifdef SUPPORT_UCP
+prop_fail_result = 0;
+prop_test_against = 0;
+prop_test_variable = NULL;
+#endif
+
+/* OK, now we can get on with the real code of the function. Recursion is
+specified by the macros RMATCH and RRETURN. When NO_RECURSE is *not* defined,
+these just turn into a recursive call to match() and a "return", respectively.
+However, RMATCH isn't like a function call because it's quite a complicated
+macro. It has to be used in one particular way. This shouldn't, however, impact
+performance when true recursion is being used. */
+
+if (md->match_call_count++ >= md->match_limit) RRETURN(PCRE_ERROR_MATCHLIMIT);
+
+original_ims = ims;    /* Save for resetting on ')' */
+
+/* At the start of a bracketed group, add the current subject pointer to the
+stack of such pointers, to be re-instated at the end of the group when we hit
+the closing ket. When match() is called in other circumstances, we don't add to
+this stack. */
+
+if ((flags & match_isgroup) != 0)
+  {
+  newptrb.epb_prev = eptrb;
+  newptrb.epb_saved_eptr = eptr;
+  eptrb = &newptrb;
+  }
+
+/* Now start processing the operations. */
+
+for (;;)
+  {
+  op = *ecode;
+  minimize = FALSE;
+
+  /* For partial matching, remember if we ever hit the end of the subject after
+  matching at least one subject character. */
+
+  if (md->partial &&
+      eptr >= md->end_subject &&
+      eptr > md->start_match)
+    md->hitend = TRUE;
+
+  /* Opening capturing bracket. If there is space in the offset vector, save
+  the current subject position in the working slot at the top of the vector. We
+  mustn't change the current values of the data slot, because they may be set
+  from a previous iteration of this group, and be referred to by a reference
+  inside the group.
+
+  If the bracket fails to match, we need to restore this value and also the
+  values of the final offsets, in case they were set by a previous iteration of
+  the same bracket.
+
+  If there isn't enough space in the offset vector, treat this as if it were a
+  non-capturing bracket. Don't worry about setting the flag for the error case
+  here; that is handled in the code for KET. */
+
+  if (op > OP_BRA)
+    {
+    number = op - OP_BRA;
+
+    /* For extended extraction brackets (large number), we have to fish out the
+    number from a dummy opcode at the start. */
+
+    if (number > EXTRACT_BASIC_MAX)
+      number = GET2(ecode, 2+LINK_SIZE);
+    offset = number << 1;
+
+#ifdef DEBUG
+    printf("start bracket %d subject=", number);
+    pchars(eptr, 16, TRUE, md);
+    printf("\n");
+#endif
+
+    if (offset < md->offset_max)
+      {
+      save_offset1 = md->offset_vector[offset];
+      save_offset2 = md->offset_vector[offset+1];
+      save_offset3 = md->offset_vector[md->offset_end - number];
+      save_capture_last = md->capture_last;
+
+      DPRINTF(("saving %d %d %d\n", save_offset1, save_offset2, save_offset3));
+      md->offset_vector[md->offset_end - number] = eptr - md->start_subject;
+
+      do
+        {
+        RMATCH(rrc, eptr, ecode + 1 + LINK_SIZE, offset_top, md, ims, eptrb,
+          match_isgroup);
+        if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+        md->capture_last = save_capture_last;
+        ecode += GET(ecode, 1);
+        }
+      while (*ecode == OP_ALT);
+
+      DPRINTF(("bracket %d failed\n", number));
+
+      md->offset_vector[offset] = save_offset1;
+      md->offset_vector[offset+1] = save_offset2;
+      md->offset_vector[md->offset_end - number] = save_offset3;
+
+      RRETURN(MATCH_NOMATCH);
+      }
+
+    /* Insufficient room for saving captured contents */
+
+    else op = OP_BRA;
+    }
+
+  /* Other types of node can be handled by a switch */
+
+  switch(op)
+    {
+    case OP_BRA:     /* Non-capturing bracket: optimized */
+    DPRINTF(("start bracket 0\n"));
+    do
+      {
+      RMATCH(rrc, eptr, ecode + 1 + LINK_SIZE, offset_top, md, ims, eptrb,
+        match_isgroup);
+      if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+      ecode += GET(ecode, 1);
+      }
+    while (*ecode == OP_ALT);
+    DPRINTF(("bracket 0 failed\n"));
+    RRETURN(MATCH_NOMATCH);
+
+    /* Conditional group: compilation checked that there are no more than
+    two branches. If the condition is false, skipping the first branch takes us
+    past the end if there is only one branch, but that's OK because that is
+    exactly what going to the ket would do. */
+
+    case OP_COND:
+    if (ecode[LINK_SIZE+1] == OP_CREF) /* Condition extract or recurse test */
+      {
+      offset = GET2(ecode, LINK_SIZE+2) << 1;  /* Doubled ref number */
+      condition = (offset == CREF_RECURSE * 2)?
+        (md->recursive != NULL) :
+        (offset < offset_top && md->offset_vector[offset] >= 0);
+      RMATCH(rrc, eptr, ecode + (condition?
+        (LINK_SIZE + 4) : (LINK_SIZE + 1 + GET(ecode, 1))),
+        offset_top, md, ims, eptrb, match_isgroup);
+      RRETURN(rrc);
+      }
+
+    /* The condition is an assertion. Call match() to evaluate it - setting
+    the final argument TRUE causes it to stop at the end of an assertion. */
+
+    else
+      {
+      RMATCH(rrc, eptr, ecode + 1 + LINK_SIZE, offset_top, md, ims, NULL,
+          match_condassert | match_isgroup);
+      if (rrc == MATCH_MATCH)
+        {
+        ecode += 1 + LINK_SIZE + GET(ecode, LINK_SIZE+2);
+        while (*ecode == OP_ALT) ecode += GET(ecode, 1);
+        }
+      else if (rrc != MATCH_NOMATCH)
+        {
+        RRETURN(rrc);         /* Need braces because of following else */
+        }
+      else ecode += GET(ecode, 1);
+      RMATCH(rrc, eptr, ecode + 1 + LINK_SIZE, offset_top, md, ims, eptrb,
+        match_isgroup);
+      RRETURN(rrc);
+      }
+    /* Control never reaches here */
+
+    /* Skip over conditional reference or large extraction number data if
+    encountered. */
+
+    case OP_CREF:
+    case OP_BRANUMBER:
+    ecode += 3;
+    break;
+
+    /* End of the pattern. If we are in a recursion, we should restore the
+    offsets appropriately and continue from after the call. */
+
+    case OP_END:
+    if (md->recursive != NULL && md->recursive->group_num == 0)
+      {
+      recursion_info *rec = md->recursive;
+      DPRINTF(("Hit the end in a (?0) recursion\n"));
+      md->recursive = rec->prevrec;
+      memmove(md->offset_vector, rec->offset_save,
+        rec->saved_max * sizeof(int));
+      md->start_match = rec->save_start;
+      ims = original_ims;
+      ecode = rec->after_call;
+      break;
+      }
+
+    /* Otherwise, if PCRE_NOTEMPTY is set, fail if we have matched an empty
+    string - backtracking will then try other alternatives, if any. */
+
+    if (md->notempty && eptr == md->start_match) RRETURN(MATCH_NOMATCH);
+    md->end_match_ptr = eptr;          /* Record where we ended */
+    md->end_offset_top = offset_top;   /* and how many extracts were taken */
+    RRETURN(MATCH_MATCH);
+
+    /* Change option settings */
+
+    case OP_OPT:
+    ims = ecode[1];
+    ecode += 2;
+    DPRINTF(("ims set to %02lx\n", ims));
+    break;
+
+    /* Assertion brackets. Check the alternative branches in turn - the
+    matching won't pass the KET for an assertion. If any one branch matches,
+    the assertion is true. Lookbehind assertions have an OP_REVERSE item at the
+    start of each branch to move the current point backwards, so the code at
+    this level is identical to the lookahead case. */
+
+    case OP_ASSERT:
+    case OP_ASSERTBACK:
+    do
+      {
+      RMATCH(rrc, eptr, ecode + 1 + LINK_SIZE, offset_top, md, ims, NULL,
+        match_isgroup);
+      if (rrc == MATCH_MATCH) break;
+      if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+      ecode += GET(ecode, 1);
+      }
+    while (*ecode == OP_ALT);
+    if (*ecode == OP_KET) RRETURN(MATCH_NOMATCH);
+
+    /* If checking an assertion for a condition, return MATCH_MATCH. */
+
+    if ((flags & match_condassert) != 0) RRETURN(MATCH_MATCH);
+
+    /* Continue from after the assertion, updating the offsets high water
+    mark, since extracts may have been taken during the assertion. */
+
+    do ecode += GET(ecode,1); while (*ecode == OP_ALT);
+    ecode += 1 + LINK_SIZE;
+    offset_top = md->end_offset_top;
+    continue;
+
+    /* Negative assertion: all branches must fail to match */
+
+    case OP_ASSERT_NOT:
+    case OP_ASSERTBACK_NOT:
+    do
+      {
+      RMATCH(rrc, eptr, ecode + 1 + LINK_SIZE, offset_top, md, ims, NULL,
+        match_isgroup);
+      if (rrc == MATCH_MATCH) RRETURN(MATCH_NOMATCH);
+      if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+      ecode += GET(ecode,1);
+      }
+    while (*ecode == OP_ALT);
+
+    if ((flags & match_condassert) != 0) RRETURN(MATCH_MATCH);
+
+    ecode += 1 + LINK_SIZE;
+    continue;
+
+    /* Move the subject pointer back. This occurs only at the start of
+    each branch of a lookbehind assertion. If we are too close to the start to
+    move back, this match function fails. When working with UTF-8 we move
+    back a number of characters, not bytes. */
+
+    case OP_REVERSE:
+#ifdef SUPPORT_UTF8
+    if (md->utf8)
+      {
+      c = GET(ecode,1);
+      for (i = 0; i < c; i++)
+        {
+        eptr--;
+        if (eptr < md->start_subject) RRETURN(MATCH_NOMATCH);
+        BACKCHAR(eptr)
+        }
+      }
+    else
+#endif
+
+    /* No UTF-8 support, or not in UTF-8 mode: count is byte count */
+
+      {
+      eptr -= GET(ecode,1);
+      if (eptr < md->start_subject) RRETURN(MATCH_NOMATCH);
+      }
+
+    /* Skip to next op code */
+
+    ecode += 1 + LINK_SIZE;
+    break;
+
+    /* The callout item calls an external function, if one is provided, passing
+    details of the match so far. This is mainly for debugging, though the
+    function is able to force a failure. */
+
+    case OP_CALLOUT:
+    if (pcre_callout != NULL)
+      {
+      pcre_callout_block cb;
+      cb.version          = 1;   /* Version 1 of the callout block */
+      cb.callout_number   = ecode[1];
+      cb.offset_vector    = md->offset_vector;
+      cb.subject          = (const char *)md->start_subject;
+      cb.subject_length   = md->end_subject - md->start_subject;
+      cb.start_match      = md->start_match - md->start_subject;
+      cb.current_position = eptr - md->start_subject;
+      cb.pattern_position = GET(ecode, 2);
+      cb.next_item_length = GET(ecode, 2 + LINK_SIZE);
+      cb.capture_top      = offset_top/2;
+      cb.capture_last     = md->capture_last;
+      cb.callout_data     = md->callout_data;
+      if ((rrc = (*pcre_callout)(&cb)) > 0) RRETURN(MATCH_NOMATCH);
+      if (rrc < 0) RRETURN(rrc);
+      }
+    ecode += 2 + 2*LINK_SIZE;
+    break;
+
+    /* Recursion either matches the current regex, or some subexpression. The
+    offset data is the offset to the starting bracket from the start of the
+    whole pattern. (This is so that it works from duplicated subpatterns.)
+
+    If there are any capturing brackets started but not finished, we have to
+    save their starting points and reinstate them after the recursion. However,
+    we don't know how many such there are (offset_top records the completed
+    total) so we just have to save all the potential data. There may be up to
+    65535 such values, which is too large to put on the stack, but using malloc
+    for small numbers seems expensive. As a compromise, the stack is used when
+    there are no more than REC_STACK_SAVE_MAX values to store; otherwise malloc
+    is used. A problem is what to do if the malloc fails ... there is no way of
+    returning to the top level with an error. Save the top REC_STACK_SAVE_MAX
+    values on the stack, and accept that the rest may be wrong.
+
+    There are also other values that have to be saved. We use a chained
+    sequence of blocks that actually live on the stack. Thanks to Robin Houston
+    for the original version of this logic. */
+
+    case OP_RECURSE:
+      {
+      callpat = md->start_code + GET(ecode, 1);
+      new_recursive.group_num = *callpat - OP_BRA;
+
+      /* For extended extraction brackets (large number), we have to fish out
+      the number from a dummy opcode at the start. */
+
+      if (new_recursive.group_num > EXTRACT_BASIC_MAX)
+        new_recursive.group_num = GET2(callpat, 2+LINK_SIZE);
+
+      /* Add to "recursing stack" */
+
+      new_recursive.prevrec = md->recursive;
+      md->recursive = &new_recursive;
+
+      /* Find where to continue from afterwards */
+
+      ecode += 1 + LINK_SIZE;
+      new_recursive.after_call = ecode;
+
+      /* Now save the offset data. */
+
+      new_recursive.saved_max = md->offset_end;
+      if (new_recursive.saved_max <= REC_STACK_SAVE_MAX)
+        new_recursive.offset_save = stacksave;
+      else
+        {
+        new_recursive.offset_save =
+          (int *)(pcre_malloc)(new_recursive.saved_max * sizeof(int));
+        if (new_recursive.offset_save == NULL) RRETURN(PCRE_ERROR_NOMEMORY);
+        }
+
+      memcpy(new_recursive.offset_save, md->offset_vector,
+            new_recursive.saved_max * sizeof(int));
+      new_recursive.save_start = md->start_match;
+      md->start_match = eptr;
+
+      /* OK, now we can do the recursion. For each top-level alternative we
+      restore the offset and recursion data. */
+
+      DPRINTF(("Recursing into group %d\n", new_recursive.group_num));
+      do
+        {
+        RMATCH(rrc, eptr, callpat + 1 + LINK_SIZE, offset_top, md, ims,
+            eptrb, match_isgroup);
+        if (rrc == MATCH_MATCH)
+          {
+          md->recursive = new_recursive.prevrec;
+          if (new_recursive.offset_save != stacksave)
+            (pcre_free)(new_recursive.offset_save);
+          RRETURN(MATCH_MATCH);
+          }
+        else if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+
+        md->recursive = &new_recursive;
+        memcpy(md->offset_vector, new_recursive.offset_save,
+            new_recursive.saved_max * sizeof(int));
+        callpat += GET(callpat, 1);
+        }
+      while (*callpat == OP_ALT);
+
+      DPRINTF(("Recursion didn't match\n"));
+      md->recursive = new_recursive.prevrec;
+      if (new_recursive.offset_save != stacksave)
+        (pcre_free)(new_recursive.offset_save);
+      RRETURN(MATCH_NOMATCH);
+      }
+    /* Control never reaches here */
+
+    /* "Once" brackets are like assertion brackets except that after a match,
+    the point in the subject string is not moved back. Thus there can never be
+    a move back into the brackets. Friedl calls these "atomic" subpatterns.
+    Check the alternative branches in turn - the matching won't pass the KET
+    for this kind of subpattern. If any one branch matches, we carry on as at
+    the end of a normal bracket, leaving the subject pointer. */
+
+    case OP_ONCE:
+      {
+      prev = ecode;
+      saved_eptr = eptr;
+
+      do
+        {
+        RMATCH(rrc, eptr, ecode + 1 + LINK_SIZE, offset_top, md, ims,
+          eptrb, match_isgroup);
+        if (rrc == MATCH_MATCH) break;
+        if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+        ecode += GET(ecode,1);
+        }
+      while (*ecode == OP_ALT);
+
+      /* If hit the end of the group (which could be repeated), fail */
+
+      if (*ecode != OP_ONCE && *ecode != OP_ALT) RRETURN(MATCH_NOMATCH);
+
+      /* Continue as from after the assertion, updating the offsets high water
+      mark, since extracts may have been taken. */
+
+      do ecode += GET(ecode,1); while (*ecode == OP_ALT);
+
+      offset_top = md->end_offset_top;
+      eptr = md->end_match_ptr;
+
+      /* For a non-repeating ket, just continue at this level. This also
+      happens for a repeating ket if no characters were matched in the group.
+      This is the forcible breaking of infinite loops as implemented in Perl
+      5.005. If there is an options reset, it will get obeyed in the normal
+      course of events. */
+
+      if (*ecode == OP_KET || eptr == saved_eptr)
+        {
+        ecode += 1+LINK_SIZE;
+        break;
+        }
+
+      /* The repeating kets try the rest of the pattern or restart from the
+      preceding bracket, in the appropriate order. We need to reset any options
+      that changed within the bracket before re-running it, so check the next
+      opcode. */
+
+      if (ecode[1+LINK_SIZE] == OP_OPT)
+        {
+        ims = (ims & ~PCRE_IMS) | ecode[4];
+        DPRINTF(("ims set to %02lx at group repeat\n", ims));
+        }
+
+      if (*ecode == OP_KETRMIN)
+        {
+        RMATCH(rrc, eptr, ecode + 1 + LINK_SIZE, offset_top, md, ims, eptrb, 0);
+        if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+        RMATCH(rrc, eptr, prev, offset_top, md, ims, eptrb, match_isgroup);
+        if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+        }
+      else  /* OP_KETRMAX */
+        {
+        RMATCH(rrc, eptr, prev, offset_top, md, ims, eptrb, match_isgroup);
+        if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+        RMATCH(rrc, eptr, ecode + 1+LINK_SIZE, offset_top, md, ims, eptrb, 0);
+        if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+        }
+      }
+    RRETURN(MATCH_NOMATCH);
+
+    /* An alternation is the end of a branch; scan along to find the end of the
+    bracketed group and go to there. */
+
+    case OP_ALT:
+    do ecode += GET(ecode,1); while (*ecode == OP_ALT);
+    break;
+
+    /* BRAZERO and BRAMINZERO occur just before a bracket group, indicating
+    that it may occur zero times. It may repeat infinitely, or not at all -
+    i.e. it could be ()* or ()? in the pattern. Brackets with fixed upper
+    repeat limits are compiled as a number of copies, with the optional ones
+    preceded by BRAZERO or BRAMINZERO. */
+
+    case OP_BRAZERO:
+      {
+      next = ecode+1;
+      RMATCH(rrc, eptr, next, offset_top, md, ims, eptrb, match_isgroup);
+      if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+      do next += GET(next,1); while (*next == OP_ALT);
+      ecode = next + 1+LINK_SIZE;
+      }
+    break;
+
+    case OP_BRAMINZERO:
+      {
+      next = ecode+1;
+      do next += GET(next,1); while (*next == OP_ALT);
+      RMATCH(rrc, eptr, next + 1+LINK_SIZE, offset_top, md, ims, eptrb,
+        match_isgroup);
+      if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+      ecode++;
+      }
+    break;
+
+    /* End of a group, repeated or non-repeating. If we are at the end of
+    an assertion "group", stop matching and return MATCH_MATCH, but record the
+    current high water mark for use by positive assertions. Do this also
+    for the "once" (not-backup up) groups. */
+
+    case OP_KET:
+    case OP_KETRMIN:
+    case OP_KETRMAX:
+      {
+      prev = ecode - GET(ecode, 1);
+      saved_eptr = eptrb->epb_saved_eptr;
+
+      /* Back up the stack of bracket start pointers. */
+
+      eptrb = eptrb->epb_prev;
+
+      if (*prev == OP_ASSERT || *prev == OP_ASSERT_NOT ||
+          *prev == OP_ASSERTBACK || *prev == OP_ASSERTBACK_NOT ||
+          *prev == OP_ONCE)
+        {
+        md->end_match_ptr = eptr;      /* For ONCE */
+        md->end_offset_top = offset_top;
+        RRETURN(MATCH_MATCH);
+        }
+
+      /* In all other cases except a conditional group we have to check the
+      group number back at the start and if necessary complete handling an
+      extraction by setting the offsets and bumping the high water mark. */
+
+      if (*prev != OP_COND)
+        {
+        number = *prev - OP_BRA;
+
+        /* For extended extraction brackets (large number), we have to fish out
+        the number from a dummy opcode at the start. */
+
+        if (number > EXTRACT_BASIC_MAX) number = GET2(prev, 2+LINK_SIZE);
+        offset = number << 1;
+
+#ifdef DEBUG
+        printf("end bracket %d", number);
+        printf("\n");
+#endif
+
+        /* Test for a numbered group. This includes groups called as a result
+        of recursion. Note that whole-pattern recursion is coded as a recurse
+        into group 0, so it won't be picked up here. Instead, we catch it when
+        the OP_END is reached. */
+
+        if (number > 0)
+          {
+          md->capture_last = number;
+          if (offset >= md->offset_max) md->offset_overflow = TRUE; else
+            {
+            md->offset_vector[offset] =
+              md->offset_vector[md->offset_end - number];
+            md->offset_vector[offset+1] = eptr - md->start_subject;
+            if (offset_top <= offset) offset_top = offset + 2;
+            }
+
+          /* Handle a recursively called group. Restore the offsets
+          appropriately and continue from after the call. */
+
+          if (md->recursive != NULL && md->recursive->group_num == number)
+            {
+            recursion_info *rec = md->recursive;
+            DPRINTF(("Recursion (%d) succeeded - continuing\n", number));
+            md->recursive = rec->prevrec;
+            md->start_match = rec->save_start;
+            memcpy(md->offset_vector, rec->offset_save,
+              rec->saved_max * sizeof(int));
+            ecode = rec->after_call;
+            ims = original_ims;
+            break;
+            }
+          }
+        }
+
+      /* Reset the value of the ims flags, in case they got changed during
+      the group. */
+
+      ims = original_ims;
+      DPRINTF(("ims reset to %02lx\n", ims));
+
+      /* For a non-repeating ket, just continue at this level. This also
+      happens for a repeating ket if no characters were matched in the group.
+      This is the forcible breaking of infinite loops as implemented in Perl
+      5.005. If there is an options reset, it will get obeyed in the normal
+      course of events. */
+
+      if (*ecode == OP_KET || eptr == saved_eptr)
+        {
+        ecode += 1 + LINK_SIZE;
+        break;
+        }
+
+      /* The repeating kets try the rest of the pattern or restart from the
+      preceding bracket, in the appropriate order. */
+
+      if (*ecode == OP_KETRMIN)
+        {
+        RMATCH(rrc, eptr, ecode + 1+LINK_SIZE, offset_top, md, ims, eptrb, 0);
+        if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+        RMATCH(rrc, eptr, prev, offset_top, md, ims, eptrb, match_isgroup);
+        if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+        }
+      else  /* OP_KETRMAX */
+        {
+        RMATCH(rrc, eptr, prev, offset_top, md, ims, eptrb, match_isgroup);
+        if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+        RMATCH(rrc, eptr, ecode + 1+LINK_SIZE, offset_top, md, ims, eptrb, 0);
+        if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+        }
+      }
+
+    RRETURN(MATCH_NOMATCH);
+
+    /* Start of subject unless notbol, or after internal newline if multiline */
+
+    case OP_CIRC:
+    if (md->notbol && eptr == md->start_subject) RRETURN(MATCH_NOMATCH);
+    if ((ims & PCRE_MULTILINE) != 0)
+      {
+      if (eptr != md->start_subject && eptr[-1] != NEWLINE)
+        RRETURN(MATCH_NOMATCH);
+      ecode++;
+      break;
+      }
+    /* ... else fall through */
+
+    /* Start of subject assertion */
+
+    case OP_SOD:
+    if (eptr != md->start_subject) RRETURN(MATCH_NOMATCH);
+    ecode++;
+    break;
+
+    /* Start of match assertion */
+
+    case OP_SOM:
+    if (eptr != md->start_subject + md->start_offset) RRETURN(MATCH_NOMATCH);
+    ecode++;
+    break;
+
+    /* Assert before internal newline if multiline, or before a terminating
+    newline unless endonly is set, else end of subject unless noteol is set. */
+
+    case OP_DOLL:
+    if ((ims & PCRE_MULTILINE) != 0)
+      {
+      if (eptr < md->end_subject)
+        { if (*eptr != NEWLINE) RRETURN(MATCH_NOMATCH); }
+      else
+        { if (md->noteol) RRETURN(MATCH_NOMATCH); }
+      ecode++;
+      break;
+      }
+    else
+      {
+      if (md->noteol) RRETURN(MATCH_NOMATCH);
+      if (!md->endonly)
+        {
+        if (eptr < md->end_subject - 1 ||
+           (eptr == md->end_subject - 1 && *eptr != NEWLINE))
+          RRETURN(MATCH_NOMATCH);
+        ecode++;
+        break;
+        }
+      }
+    /* ... else fall through */
+
+    /* End of subject assertion (\z) */
+
+    case OP_EOD:
+    if (eptr < md->end_subject) RRETURN(MATCH_NOMATCH);
+    ecode++;
+    break;
+
+    /* End of subject or ending \n assertion (\Z) */
+
+    case OP_EODN:
+    if (eptr < md->end_subject - 1 ||
+       (eptr == md->end_subject - 1 && *eptr != NEWLINE)) RRETURN(MATCH_NOMATCH);
+    ecode++;
+    break;
+
+    /* Word boundary assertions */
+
+    case OP_NOT_WORD_BOUNDARY:
+    case OP_WORD_BOUNDARY:
+      {
+
+      /* Find out if the previous and current characters are "word" characters.
+      It takes a bit more work in UTF-8 mode. Characters > 255 are assumed to
+      be "non-word" characters. */
+
+#ifdef SUPPORT_UTF8
+      if (md->utf8)
+        {
+        if (eptr == md->start_subject) prev_is_word = FALSE; else
+          {
+          const uschar *lastptr = eptr - 1;
+          while((*lastptr & 0xc0) == 0x80) lastptr--;
+          GETCHAR(c, lastptr);
+          prev_is_word = c < 256 && (md->ctypes[c] & ctype_word) != 0;
+          }
+        if (eptr >= md->end_subject) cur_is_word = FALSE; else
+          {
+          GETCHAR(c, eptr);
+          cur_is_word = c < 256 && (md->ctypes[c] & ctype_word) != 0;
+          }
+        }
+      else
+#endif
+
+      /* More streamlined when not in UTF-8 mode */
+
+        {
+        prev_is_word = (eptr != md->start_subject) &&
+          ((md->ctypes[eptr[-1]] & ctype_word) != 0);
+        cur_is_word = (eptr < md->end_subject) &&
+          ((md->ctypes[*eptr] & ctype_word) != 0);
+        }
+
+      /* Now see if the situation is what we want */
+
+      if ((*ecode++ == OP_WORD_BOUNDARY)?
+           cur_is_word == prev_is_word : cur_is_word != prev_is_word)
+        RRETURN(MATCH_NOMATCH);
+      }
+    break;
+
+    /* Match a single character type; inline for speed */
+
+    case OP_ANY:
+    if ((ims & PCRE_DOTALL) == 0 && eptr < md->end_subject && *eptr == NEWLINE)
+      RRETURN(MATCH_NOMATCH);
+    if (eptr++ >= md->end_subject) RRETURN(MATCH_NOMATCH);
+#ifdef SUPPORT_UTF8
+    if (md->utf8)
+      while (eptr < md->end_subject && (*eptr & 0xc0) == 0x80) eptr++;
+#endif
+    ecode++;
+    break;
+
+    /* Match a single byte, even in UTF-8 mode. This opcode really does match
+    any byte, even newline, independent of the setting of PCRE_DOTALL. */
+
+    case OP_ANYBYTE:
+    if (eptr++ >= md->end_subject) RRETURN(MATCH_NOMATCH);
+    ecode++;
+    break;
+
+    case OP_NOT_DIGIT:
+    if (eptr >= md->end_subject) RRETURN(MATCH_NOMATCH);
+    GETCHARINCTEST(c, eptr);
+    if (
+#ifdef SUPPORT_UTF8
+       c < 256 &&
+#endif
+       (md->ctypes[c] & ctype_digit) != 0
+       )
+      RRETURN(MATCH_NOMATCH);
+    ecode++;
+    break;
+
+    case OP_DIGIT:
+    if (eptr >= md->end_subject) RRETURN(MATCH_NOMATCH);
+    GETCHARINCTEST(c, eptr);
+    if (
+#ifdef SUPPORT_UTF8
+       c >= 256 ||
+#endif
+       (md->ctypes[c] & ctype_digit) == 0
+       )
+      RRETURN(MATCH_NOMATCH);
+    ecode++;
+    break;
+
+    case OP_NOT_WHITESPACE:
+    if (eptr >= md->end_subject) RRETURN(MATCH_NOMATCH);
+    GETCHARINCTEST(c, eptr);
+    if (
+#ifdef SUPPORT_UTF8
+       c < 256 &&
+#endif
+       (md->ctypes[c] & ctype_space) != 0
+       )
+      RRETURN(MATCH_NOMATCH);
+    ecode++;
+    break;
+
+    case OP_WHITESPACE:
+    if (eptr >= md->end_subject) RRETURN(MATCH_NOMATCH);
+    GETCHARINCTEST(c, eptr);
+    if (
+#ifdef SUPPORT_UTF8
+       c >= 256 ||
+#endif
+       (md->ctypes[c] & ctype_space) == 0
+       )
+      RRETURN(MATCH_NOMATCH);
+    ecode++;
+    break;
+
+    case OP_NOT_WORDCHAR:
+    if (eptr >= md->end_subject) RRETURN(MATCH_NOMATCH);
+    GETCHARINCTEST(c, eptr);
+    if (
+#ifdef SUPPORT_UTF8
+       c < 256 &&
+#endif
+       (md->ctypes[c] & ctype_word) != 0
+       )
+      RRETURN(MATCH_NOMATCH);
+    ecode++;
+    break;
+
+    case OP_WORDCHAR:
+    if (eptr >= md->end_subject) RRETURN(MATCH_NOMATCH);
+    GETCHARINCTEST(c, eptr);
+    if (
+#ifdef SUPPORT_UTF8
+       c >= 256 ||
+#endif
+       (md->ctypes[c] & ctype_word) == 0
+       )
+      RRETURN(MATCH_NOMATCH);
+    ecode++;
+    break;
+
+#ifdef SUPPORT_UCP
+    /* Check the next character by Unicode property. We will get here only
+    if the support is in the binary; otherwise a compile-time error occurs. */
+
+    case OP_PROP:
+    case OP_NOTPROP:
+    if (eptr >= md->end_subject) RRETURN(MATCH_NOMATCH);
+    GETCHARINCTEST(c, eptr);
+      {
+      int chartype, rqdtype;
+      int othercase;
+      int category = ucp_findchar(c, &chartype, &othercase);
+
+      rqdtype = *(++ecode);
+      ecode++;
+
+      if (rqdtype >= 128)
+        {
+        if ((rqdtype - 128 != category) == (op == OP_PROP))
+          RRETURN(MATCH_NOMATCH);
+        }
+      else
+        {
+        if ((rqdtype != chartype) == (op == OP_PROP))
+          RRETURN(MATCH_NOMATCH);
+        }
+      }
+    break;
+
+    /* Match an extended Unicode sequence. We will get here only if the support
+    is in the binary; otherwise a compile-time error occurs. */
+
+    case OP_EXTUNI:
+    if (eptr >= md->end_subject) RRETURN(MATCH_NOMATCH);
+    GETCHARINCTEST(c, eptr);
+      {
+      int chartype;
+      int othercase;
+      int category = ucp_findchar(c, &chartype, &othercase);
+      if (category == ucp_M) RRETURN(MATCH_NOMATCH);
+      while (eptr < md->end_subject)
+        {
+        int len = 1;
+        if (!md->utf8) c = *eptr; else
+          {
+          GETCHARLEN(c, eptr, len);
+          }
+        category = ucp_findchar(c, &chartype, &othercase);
+        if (category != ucp_M) break;
+        eptr += len;
+        }
+      }
+    ecode++;
+    break;
+#endif
+
+
+    /* Match a back reference, possibly repeatedly. Look past the end of the
+    item to see if there is repeat information following. The code is similar
+    to that for character classes, but repeated for efficiency. Then obey
+    similar code to character type repeats - written out again for speed.
+    However, if the referenced string is the empty string, always treat
+    it as matched, any number of times (otherwise there could be infinite
+    loops). */
+
+    case OP_REF:
+      {
+      offset = GET2(ecode, 1) << 1;               /* Doubled ref number */
+      ecode += 3;                                 /* Advance past item */
+
+      /* If the reference is unset, set the length to be longer than the amount
+      of subject left; this ensures that every attempt at a match fails. We
+      can't just fail here, because of the possibility of quantifiers with zero
+      minima. */
+
+      length = (offset >= offset_top || md->offset_vector[offset] < 0)?
+        md->end_subject - eptr + 1 :
+        md->offset_vector[offset+1] - md->offset_vector[offset];
+
+      /* Set up for repetition, or handle the non-repeated case */
+
+      switch (*ecode)
+        {
+        case OP_CRSTAR:
+        case OP_CRMINSTAR:
+        case OP_CRPLUS:
+        case OP_CRMINPLUS:
+        case OP_CRQUERY:
+        case OP_CRMINQUERY:
+        c = *ecode++ - OP_CRSTAR;
+        minimize = (c & 1) != 0;
+        min = rep_min[c];                 /* Pick up values from tables; */
+        max = rep_max[c];                 /* zero for max => infinity */
+        if (max == 0) max = INT_MAX;
+        break;
+
+        case OP_CRRANGE:
+        case OP_CRMINRANGE:
+        minimize = (*ecode == OP_CRMINRANGE);
+        min = GET2(ecode, 1);
+        max = GET2(ecode, 3);
+        if (max == 0) max = INT_MAX;
+        ecode += 5;
+        break;
+
+        default:               /* No repeat follows */
+        if (!match_ref(offset, eptr, length, md, ims)) RRETURN(MATCH_NOMATCH);
+        eptr += length;
+        continue;              /* With the main loop */
+        }
+
+      /* If the length of the reference is zero, just continue with the
+      main loop. */
+
+      if (length == 0) continue;
+
+      /* First, ensure the minimum number of matches are present. We get back
+      the length of the reference string explicitly rather than passing the
+      address of eptr, so that eptr can be a register variable. */
+
+      for (i = 1; i <= min; i++)
+        {
+        if (!match_ref(offset, eptr, length, md, ims)) RRETURN(MATCH_NOMATCH);
+        eptr += length;
+        }
+
+      /* If min = max, continue at the same level without recursion.
+      They are not both allowed to be zero. */
+
+      if (min == max) continue;
+
+      /* If minimizing, keep trying and advancing the pointer */
+
+      if (minimize)
+        {
+        for (fi = min;; fi++)
+          {
+          RMATCH(rrc, eptr, ecode, offset_top, md, ims, eptrb, 0);
+          if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+          if (fi >= max || !match_ref(offset, eptr, length, md, ims))
+            RRETURN(MATCH_NOMATCH);
+          eptr += length;
+          }
+        /* Control never gets here */
+        }
+
+      /* If maximizing, find the longest string and work backwards */
+
+      else
+        {
+        pp = eptr;
+        for (i = min; i < max; i++)
+          {
+          if (!match_ref(offset, eptr, length, md, ims)) break;
+          eptr += length;
+          }
+        while (eptr >= pp)
+          {
+          RMATCH(rrc, eptr, ecode, offset_top, md, ims, eptrb, 0);
+          if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+          eptr -= length;
+          }
+        RRETURN(MATCH_NOMATCH);
+        }
+      }
+    /* Control never gets here */
+
+
+
+    /* Match a bit-mapped character class, possibly repeatedly. This op code is
+    used when all the characters in the class have values in the range 0-255,
+    and either the matching is caseful, or the characters are in the range
+    0-127 when UTF-8 processing is enabled. The only difference between
+    OP_CLASS and OP_NCLASS occurs when a data character outside the range is
+    encountered.
+
+    First, look past the end of the item to see if there is repeat information
+    following. Then obey similar code to character type repeats - written out
+    again for speed. */
+
+    case OP_NCLASS:
+    case OP_CLASS:
+      {
+      data = ecode + 1;                /* Save for matching */
+      ecode += 33;                     /* Advance past the item */
+
+      switch (*ecode)
+        {
+        case OP_CRSTAR:
+        case OP_CRMINSTAR:
+        case OP_CRPLUS:
+        case OP_CRMINPLUS:
+        case OP_CRQUERY:
+        case OP_CRMINQUERY:
+        c = *ecode++ - OP_CRSTAR;
+        minimize = (c & 1) != 0;
+        min = rep_min[c];                 /* Pick up values from tables; */
+        max = rep_max[c];                 /* zero for max => infinity */
+        if (max == 0) max = INT_MAX;
+        break;
+
+        case OP_CRRANGE:
+        case OP_CRMINRANGE:
+        minimize = (*ecode == OP_CRMINRANGE);
+        min = GET2(ecode, 1);
+        max = GET2(ecode, 3);
+        if (max == 0) max = INT_MAX;
+        ecode += 5;
+        break;
+
+        default:               /* No repeat follows */
+        min = max = 1;
+        break;
+        }
+
+      /* First, ensure the minimum number of matches are present. */
+
+#ifdef SUPPORT_UTF8
+      /* UTF-8 mode */
+      if (md->utf8)
+        {
+        for (i = 1; i <= min; i++)
+          {
+          if (eptr >= md->end_subject) RRETURN(MATCH_NOMATCH);
+          GETCHARINC(c, eptr);
+          if (c > 255)
+            {
+            if (op == OP_CLASS) RRETURN(MATCH_NOMATCH);
+            }
+          else
+            {
+            if ((data[c/8] & (1 << (c&7))) == 0) RRETURN(MATCH_NOMATCH);
+            }
+          }
+        }
+      else
+#endif
+      /* Not UTF-8 mode */
+        {
+        for (i = 1; i <= min; i++)
+          {
+          if (eptr >= md->end_subject) RRETURN(MATCH_NOMATCH);
+          c = *eptr++;
+          if ((data[c/8] & (1 << (c&7))) == 0) RRETURN(MATCH_NOMATCH);
+          }
+        }
+
+      /* If max == min we can continue with the main loop without the
+      need to recurse. */
+
+      if (min == max) continue;
+
+      /* If minimizing, keep testing the rest of the expression and advancing
+      the pointer while it matches the class. */
+
+      if (minimize)
+        {
+#ifdef SUPPORT_UTF8
+        /* UTF-8 mode */
+        if (md->utf8)
+          {
+          for (fi = min;; fi++)
+            {
+            RMATCH(rrc, eptr, ecode, offset_top, md, ims, eptrb, 0);
+            if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+            if (fi >= max || eptr >= md->end_subject) RRETURN(MATCH_NOMATCH);
+            GETCHARINC(c, eptr);
+            if (c > 255)
+              {
+              if (op == OP_CLASS) RRETURN(MATCH_NOMATCH);
+              }
+            else
+              {
+              if ((data[c/8] & (1 << (c&7))) == 0) RRETURN(MATCH_NOMATCH);
+              }
+            }
+          }
+        else
+#endif
+        /* Not UTF-8 mode */
+          {
+          for (fi = min;; fi++)
+            {
+            RMATCH(rrc, eptr, ecode, offset_top, md, ims, eptrb, 0);
+            if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+            if (fi >= max || eptr >= md->end_subject) RRETURN(MATCH_NOMATCH);
+            c = *eptr++;
+            if ((data[c/8] & (1 << (c&7))) == 0) RRETURN(MATCH_NOMATCH);
+            }
+          }
+        /* Control never gets here */
+        }
+
+      /* If maximizing, find the longest possible run, then work backwards. */
+
+      else
+        {
+        pp = eptr;
+
+#ifdef SUPPORT_UTF8
+        /* UTF-8 mode */
+        if (md->utf8)
+          {
+          for (i = min; i < max; i++)
+            {
+            int len = 1;
+            if (eptr >= md->end_subject) break;
+            GETCHARLEN(c, eptr, len);
+            if (c > 255)
+              {
+              if (op == OP_CLASS) break;
+              }
+            else
+              {
+              if ((data[c/8] & (1 << (c&7))) == 0) break;
+              }
+            eptr += len;
+            }
+          for (;;)
+            {
+            RMATCH(rrc, eptr, ecode, offset_top, md, ims, eptrb, 0);
+            if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+            if (eptr-- == pp) break;        /* Stop if tried at original pos */
+            BACKCHAR(eptr);
+            }
+          }
+        else
+#endif
+          /* Not UTF-8 mode */
+          {
+          for (i = min; i < max; i++)
+            {
+            if (eptr >= md->end_subject) break;
+            c = *eptr;
+            if ((data[c/8] & (1 << (c&7))) == 0) break;
+            eptr++;
+            }
+          while (eptr >= pp)
+            {
+            RMATCH(rrc, eptr, ecode, offset_top, md, ims, eptrb, 0);
+            eptr--;
+            if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+            }
+          }
+
+        RRETURN(MATCH_NOMATCH);
+        }
+      }
+    /* Control never gets here */
+
+
+    /* Match an extended character class. This opcode is encountered only
+    in UTF-8 mode, because that's the only time it is compiled. */
+
+#ifdef SUPPORT_UTF8
+    case OP_XCLASS:
+      {
+      data = ecode + 1 + LINK_SIZE;                /* Save for matching */
+      ecode += GET(ecode, 1);                      /* Advance past the item */
+
+      switch (*ecode)
+        {
+        case OP_CRSTAR:
+        case OP_CRMINSTAR:
+        case OP_CRPLUS:
+        case OP_CRMINPLUS:
+        case OP_CRQUERY:
+        case OP_CRMINQUERY:
+        c = *ecode++ - OP_CRSTAR;
+        minimize = (c & 1) != 0;
+        min = rep_min[c];                 /* Pick up values from tables; */
+        max = rep_max[c];                 /* zero for max => infinity */
+        if (max == 0) max = INT_MAX;
+        break;
+
+        case OP_CRRANGE:
+        case OP_CRMINRANGE:
+        minimize = (*ecode == OP_CRMINRANGE);
+        min = GET2(ecode, 1);
+        max = GET2(ecode, 3);
+        if (max == 0) max = INT_MAX;
+        ecode += 5;
+        break;
+
+        default:               /* No repeat follows */
+        min = max = 1;
+        break;
+        }
+
+      /* First, ensure the minimum number of matches are present. */
+
+      for (i = 1; i <= min; i++)
+        {
+        if (eptr >= md->end_subject) RRETURN(MATCH_NOMATCH);
+        GETCHARINC(c, eptr);
+        if (!match_xclass(c, data)) RRETURN(MATCH_NOMATCH);
+        }
+
+      /* If max == min we can continue with the main loop without the
+      need to recurse. */
+
+      if (min == max) continue;
+
+      /* If minimizing, keep testing the rest of the expression and advancing
+      the pointer while it matches the class. */
+
+      if (minimize)
+        {
+        for (fi = min;; fi++)
+          {
+          RMATCH(rrc, eptr, ecode, offset_top, md, ims, eptrb, 0);
+          if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+          if (fi >= max || eptr >= md->end_subject) RRETURN(MATCH_NOMATCH);
+          GETCHARINC(c, eptr);
+          if (!match_xclass(c, data)) RRETURN(MATCH_NOMATCH);
+          }
+        /* Control never gets here */
+        }
+
+      /* If maximizing, find the longest possible run, then work backwards. */
+
+      else
+        {
+        pp = eptr;
+        for (i = min; i < max; i++)
+          {
+          int len = 1;
+          if (eptr >= md->end_subject) break;
+          GETCHARLEN(c, eptr, len);
+          if (!match_xclass(c, data)) break;
+          eptr += len;
+          }
+        for(;;)
+          {
+          RMATCH(rrc, eptr, ecode, offset_top, md, ims, eptrb, 0);
+          if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+          if (eptr-- == pp) break;        /* Stop if tried at original pos */
+          BACKCHAR(eptr)
+          }
+        RRETURN(MATCH_NOMATCH);
+        }
+
+      /* Control never gets here */
+      }
+#endif    /* End of XCLASS */
+
+    /* Match a single character, casefully */
+
+    case OP_CHAR:
+#ifdef SUPPORT_UTF8
+    if (md->utf8)
+      {
+      length = 1;
+      ecode++;
+      GETCHARLEN(fc, ecode, length);
+      if (length > md->end_subject - eptr) RRETURN(MATCH_NOMATCH);
+      while (length-- > 0) if (*ecode++ != *eptr++) RRETURN(MATCH_NOMATCH);
+      }
+    else
+#endif
+
+    /* Non-UTF-8 mode */
+      {
+      if (md->end_subject - eptr < 1) RRETURN(MATCH_NOMATCH);
+      if (ecode[1] != *eptr++) RRETURN(MATCH_NOMATCH);
+      ecode += 2;
+      }
+    break;
+
+    /* Match a single character, caselessly */
+
+    case OP_CHARNC:
+#ifdef SUPPORT_UTF8
+    if (md->utf8)
+      {
+      length = 1;
+      ecode++;
+      GETCHARLEN(fc, ecode, length);
+
+      if (length > md->end_subject - eptr) RRETURN(MATCH_NOMATCH);
+
+      /* If the pattern character's value is < 128, we have only one byte, and
+      can use the fast lookup table. */
+
+      if (fc < 128)
+        {
+        if (md->lcc[*ecode++] != md->lcc[*eptr++]) RRETURN(MATCH_NOMATCH);
+        }
+
+      /* Otherwise we must pick up the subject character */
+
+      else
+        {
+        int dc;
+        GETCHARINC(dc, eptr);
+        ecode += length;
+
+        /* If we have Unicode property support, we can use it to test the other
+        case of the character, if there is one. The result of ucp_findchar() is
+        < 0 if the char isn't found, and othercase is returned as zero if there
+        isn't one. */
+
+        if (fc != dc)
+          {
+#ifdef SUPPORT_UCP
+          int chartype;
+          int othercase;
+          if (ucp_findchar(fc, &chartype, &othercase) < 0 || dc != othercase)
+#endif
+            RRETURN(MATCH_NOMATCH);
+          }
+        }
+      }
+    else
+#endif   /* SUPPORT_UTF8 */
+
+    /* Non-UTF-8 mode */
+      {
+      if (md->end_subject - eptr < 1) RRETURN(MATCH_NOMATCH);
+      if (md->lcc[ecode[1]] != md->lcc[*eptr++]) RRETURN(MATCH_NOMATCH);
+      ecode += 2;
+      }
+    break;
+
+    /* Match a single character repeatedly; different opcodes share code. */
+
+    case OP_EXACT:
+    min = max = GET2(ecode, 1);
+    ecode += 3;
+    goto REPEATCHAR;
+
+    case OP_UPTO:
+    case OP_MINUPTO:
+    min = 0;
+    max = GET2(ecode, 1);
+    minimize = *ecode == OP_MINUPTO;
+    ecode += 3;
+    goto REPEATCHAR;
+
+    case OP_STAR:
+    case OP_MINSTAR:
+    case OP_PLUS:
+    case OP_MINPLUS:
+    case OP_QUERY:
+    case OP_MINQUERY:
+    c = *ecode++ - OP_STAR;
+    minimize = (c & 1) != 0;
+    min = rep_min[c];                 /* Pick up values from tables; */
+    max = rep_max[c];                 /* zero for max => infinity */
+    if (max == 0) max = INT_MAX;
+
+    /* Common code for all repeated single-character matches. We can give
+    up quickly if there are fewer than the minimum number of characters left in
+    the subject. */
+
+    REPEATCHAR:
+#ifdef SUPPORT_UTF8
+    if (md->utf8)
+      {
+      length = 1;
+      charptr = ecode;
+      GETCHARLEN(fc, ecode, length);
+      if (min * length > md->end_subject - eptr) RRETURN(MATCH_NOMATCH);
+      ecode += length;
+
+      /* Handle multibyte character matching specially here. There is
+      support for caseless matching if UCP support is present. */
+
+      if (length > 1)
+        {
+        int oclength = 0;
+        uschar occhars[8];
+
+#ifdef SUPPORT_UCP
+        int othercase;
+        int chartype;
+        if ((ims & PCRE_CASELESS) != 0 &&
+             ucp_findchar(fc, &chartype, &othercase) >= 0 &&
+             othercase > 0)
+          oclength = ord2utf8(othercase, occhars);
+#endif  /* SUPPORT_UCP */
+
+        for (i = 1; i <= min; i++)
+          {
+          if (memcmp(eptr, charptr, length) == 0) eptr += length;
+          /* Need braces because of following else */
+          else if (oclength == 0) { RRETURN(MATCH_NOMATCH); }
+          else
+            {
+            if (memcmp(eptr, occhars, oclength) != 0) RRETURN(MATCH_NOMATCH);
+            eptr += oclength;
+            }
+          }
+
+        if (min == max) continue;
+
+        if (minimize)
+          {
+          for (fi = min;; fi++)
+            {
+            RMATCH(rrc, eptr, ecode, offset_top, md, ims, eptrb, 0);
+            if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+            if (fi >= max || eptr >= md->end_subject) RRETURN(MATCH_NOMATCH);
+            if (memcmp(eptr, charptr, length) == 0) eptr += length;
+            /* Need braces because of following else */
+            else if (oclength == 0) { RRETURN(MATCH_NOMATCH); }
+            else
+              {
+              if (memcmp(eptr, occhars, oclength) != 0) RRETURN(MATCH_NOMATCH);
+              eptr += oclength;
+              }
+            }
+          /* Control never gets here */
+          }
+        else
+          {
+          pp = eptr;
+          for (i = min; i < max; i++)
+            {
+            if (eptr > md->end_subject - length) break;
+            if (memcmp(eptr, charptr, length) == 0) eptr += length;
+            else if (oclength == 0) break;
+            else
+              {
+              if (memcmp(eptr, occhars, oclength) != 0) break;
+              eptr += oclength;
+              }
+            }
+          while (eptr >= pp)
+           {
+           RMATCH(rrc, eptr, ecode, offset_top, md, ims, eptrb, 0);
+           if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+           eptr -= length;
+           }
+          RRETURN(MATCH_NOMATCH);
+          }
+        /* Control never gets here */
+        }
+
+      /* If the length of a UTF-8 character is 1, we fall through here, and
+      obey the code as for non-UTF-8 characters below, though in this case the
+      value of fc will always be < 128. */
+      }
+    else
+#endif  /* SUPPORT_UTF8 */
+
+    /* When not in UTF-8 mode, load a single-byte character. */
+      {
+      if (min > md->end_subject - eptr) RRETURN(MATCH_NOMATCH);
+      fc = *ecode++;
+      }
+
+    /* The value of fc at this point is always less than 256, though we may or
+    may not be in UTF-8 mode. The code is duplicated for the caseless and
+    caseful cases, for speed, since matching characters is likely to be quite
+    common. First, ensure the minimum number of matches are present. If min =
+    max, continue at the same level without recursing. Otherwise, if
+    minimizing, keep trying the rest of the expression and advancing one
+    matching character if failing, up to the maximum. Alternatively, if
+    maximizing, find the maximum number of characters and work backwards. */
+
+    DPRINTF(("matching %c{%d,%d} against subject %.*s\n", fc, min, max,
+      max, eptr));
+
+    if ((ims & PCRE_CASELESS) != 0)
+      {
+      fc = md->lcc[fc];
+      for (i = 1; i <= min; i++)
+        if (fc != md->lcc[*eptr++]) RRETURN(MATCH_NOMATCH);
+      if (min == max) continue;
+      if (minimize)
+        {
+        for (fi = min;; fi++)
+          {
+          RMATCH(rrc, eptr, ecode, offset_top, md, ims, eptrb, 0);
+          if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+          if (fi >= max || eptr >= md->end_subject ||
+              fc != md->lcc[*eptr++])
+            RRETURN(MATCH_NOMATCH);
+          }
+        /* Control never gets here */
+        }
+      else
+        {
+        pp = eptr;
+        for (i = min; i < max; i++)
+          {
+          if (eptr >= md->end_subject || fc != md->lcc[*eptr]) break;
+          eptr++;
+          }
+        while (eptr >= pp)
+          {
+          RMATCH(rrc, eptr, ecode, offset_top, md, ims, eptrb, 0);
+          eptr--;
+          if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+          }
+        RRETURN(MATCH_NOMATCH);
+        }
+      /* Control never gets here */
+      }
+
+    /* Caseful comparisons (includes all multi-byte characters) */
+
+    else
+      {
+      for (i = 1; i <= min; i++) if (fc != *eptr++) RRETURN(MATCH_NOMATCH);
+      if (min == max) continue;
+      if (minimize)
+        {
+        for (fi = min;; fi++)
+          {
+          RMATCH(rrc, eptr, ecode, offset_top, md, ims, eptrb, 0);
+          if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+          if (fi >= max || eptr >= md->end_subject || fc != *eptr++)
+            RRETURN(MATCH_NOMATCH);
+          }
+        /* Control never gets here */
+        }
+      else
+        {
+        pp = eptr;
+        for (i = min; i < max; i++)
+          {
+          if (eptr >= md->end_subject || fc != *eptr) break;
+          eptr++;
+          }
+        while (eptr >= pp)
+          {
+          RMATCH(rrc, eptr, ecode, offset_top, md, ims, eptrb, 0);
+          eptr--;
+          if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+          }
+        RRETURN(MATCH_NOMATCH);
+        }
+      }
+    /* Control never gets here */
+
+    /* Match a negated single one-byte character. The character we are
+    checking can be multibyte. */
+
+    case OP_NOT:
+    if (eptr >= md->end_subject) RRETURN(MATCH_NOMATCH);
+    ecode++;
+    GETCHARINCTEST(c, eptr);
+    if ((ims & PCRE_CASELESS) != 0)
+      {
+#ifdef SUPPORT_UTF8
+      if (c < 256)
+#endif
+      c = md->lcc[c];
+      if (md->lcc[*ecode++] == c) RRETURN(MATCH_NOMATCH);
+      }
+    else
+      {
+      if (*ecode++ == c) RRETURN(MATCH_NOMATCH);
+      }
+    break;
+
+    /* Match a negated single one-byte character repeatedly. This is almost a
+    repeat of the code for a repeated single character, but I haven't found a
+    nice way of commoning these up that doesn't require a test of the
+    positive/negative option for each character match. Maybe that wouldn't add
+    very much to the time taken, but character matching *is* what this is all
+    about... */
+
+    case OP_NOTEXACT:
+    min = max = GET2(ecode, 1);
+    ecode += 3;
+    goto REPEATNOTCHAR;
+
+    case OP_NOTUPTO:
+    case OP_NOTMINUPTO:
+    min = 0;
+    max = GET2(ecode, 1);
+    minimize = *ecode == OP_NOTMINUPTO;
+    ecode += 3;
+    goto REPEATNOTCHAR;
+
+    case OP_NOTSTAR:
+    case OP_NOTMINSTAR:
+    case OP_NOTPLUS:
+    case OP_NOTMINPLUS:
+    case OP_NOTQUERY:
+    case OP_NOTMINQUERY:
+    c = *ecode++ - OP_NOTSTAR;
+    minimize = (c & 1) != 0;
+    min = rep_min[c];                 /* Pick up values from tables; */
+    max = rep_max[c];                 /* zero for max => infinity */
+    if (max == 0) max = INT_MAX;
+
+    /* Common code for all repeated single-byte matches. We can give up quickly
+    if there are fewer than the minimum number of bytes left in the
+    subject. */
+
+    REPEATNOTCHAR:
+    if (min > md->end_subject - eptr) RRETURN(MATCH_NOMATCH);
+    fc = *ecode++;
+
+    /* The code is duplicated for the caseless and caseful cases, for speed,
+    since matching characters is likely to be quite common. First, ensure the
+    minimum number of matches are present. If min = max, continue at the same
+    level without recursing. Otherwise, if minimizing, keep trying the rest of
+    the expression and advancing one matching character if failing, up to the
+    maximum. Alternatively, if maximizing, find the maximum number of
+    characters and work backwards. */
+
+    DPRINTF(("negative matching %c{%d,%d} against subject %.*s\n", fc, min, max,
+      max, eptr));
+
+    if ((ims & PCRE_CASELESS) != 0)
+      {
+      fc = md->lcc[fc];
+
+#ifdef SUPPORT_UTF8
+      /* UTF-8 mode */
+      if (md->utf8)
+        {
+        register int d;
+        for (i = 1; i <= min; i++)
+          {
+          GETCHARINC(d, eptr);
+          if (d < 256) d = md->lcc[d];
+          if (fc == d) RRETURN(MATCH_NOMATCH);
+          }
+        }
+      else
+#endif
+
+      /* Not UTF-8 mode */
+        {
+        for (i = 1; i <= min; i++)
+          if (fc == md->lcc[*eptr++]) RRETURN(MATCH_NOMATCH);
+        }
+
+      if (min == max) continue;
+
+      if (minimize)
+        {
+#ifdef SUPPORT_UTF8
+        /* UTF-8 mode */
+        if (md->utf8)
+          {
+          register int d;
+          for (fi = min;; fi++)
+            {
+            RMATCH(rrc, eptr, ecode, offset_top, md, ims, eptrb, 0);
+            if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+            GETCHARINC(d, eptr);
+            if (d < 256) d = md->lcc[d];
+            if (fi >= max || eptr >= md->end_subject || fc == d)
+              RRETURN(MATCH_NOMATCH);
+            }
+          }
+        else
+#endif
+        /* Not UTF-8 mode */
+          {
+          for (fi = min;; fi++)
+            {
+            RMATCH(rrc, eptr, ecode, offset_top, md, ims, eptrb, 0);
+            if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+            if (fi >= max || eptr >= md->end_subject || fc == md->lcc[*eptr++])
+              RRETURN(MATCH_NOMATCH);
+            }
+          }
+        /* Control never gets here */
+        }
+
+      /* Maximize case */
+
+      else
+        {
+        pp = eptr;
+
+#ifdef SUPPORT_UTF8
+        /* UTF-8 mode */
+        if (md->utf8)
+          {
+          register int d;
+          for (i = min; i < max; i++)
+            {
+            int len = 1;
+            if (eptr >= md->end_subject) break;
+            GETCHARLEN(d, eptr, len);
+            if (d < 256) d = md->lcc[d];
+            if (fc == d) break;
+            eptr += len;
+            }
+          for(;;)
+            {
+            RMATCH(rrc, eptr, ecode, offset_top, md, ims, eptrb, 0);
+            if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+            if (eptr-- == pp) break;        /* Stop if tried at original pos */
+            BACKCHAR(eptr);
+            }
+          }
+        else
+#endif
+        /* Not UTF-8 mode */
+          {
+          for (i = min; i < max; i++)
+            {
+            if (eptr >= md->end_subject || fc == md->lcc[*eptr]) break;
+            eptr++;
+            }
+          while (eptr >= pp)
+            {
+            RMATCH(rrc, eptr, ecode, offset_top, md, ims, eptrb, 0);
+            if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+            eptr--;
+            }
+          }
+
+        RRETURN(MATCH_NOMATCH);
+        }
+      /* Control never gets here */
+      }
+
+    /* Caseful comparisons */
+
+    else
+      {
+#ifdef SUPPORT_UTF8
+      /* UTF-8 mode */
+      if (md->utf8)
+        {
+        register int d;
+        for (i = 1; i <= min; i++)
+          {
+          GETCHARINC(d, eptr);
+          if (fc == d) RRETURN(MATCH_NOMATCH);
+          }
+        }
+      else
+#endif
+      /* Not UTF-8 mode */
+        {
+        for (i = 1; i <= min; i++)
+          if (fc == *eptr++) RRETURN(MATCH_NOMATCH);
+        }
+
+      if (min == max) continue;
+
+      if (minimize)
+        {
+#ifdef SUPPORT_UTF8
+        /* UTF-8 mode */
+        if (md->utf8)
+          {
+          register int d;
+          for (fi = min;; fi++)
+            {
+            RMATCH(rrc, eptr, ecode, offset_top, md, ims, eptrb, 0);
+            if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+            GETCHARINC(d, eptr);
+            if (fi >= max || eptr >= md->end_subject || fc == d)
+              RRETURN(MATCH_NOMATCH);
+            }
+          }
+        else
+#endif
+        /* Not UTF-8 mode */
+          {
+          for (fi = min;; fi++)
+            {
+            RMATCH(rrc, eptr, ecode, offset_top, md, ims, eptrb, 0);
+            if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+            if (fi >= max || eptr >= md->end_subject || fc == *eptr++)
+              RRETURN(MATCH_NOMATCH);
+            }
+          }
+        /* Control never gets here */
+        }
+
+      /* Maximize case */
+
+      else
+        {
+        pp = eptr;
+
+#ifdef SUPPORT_UTF8
+        /* UTF-8 mode */
+        if (md->utf8)
+          {
+          register int d;
+          for (i = min; i < max; i++)
+            {
+            int len = 1;
+            if (eptr >= md->end_subject) break;
+            GETCHARLEN(d, eptr, len);
+            if (fc == d) break;
+            eptr += len;
+            }
+          for(;;)
+            {
+            RMATCH(rrc, eptr, ecode, offset_top, md, ims, eptrb, 0);
+            if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+            if (eptr-- == pp) break;        /* Stop if tried at original pos */
+            BACKCHAR(eptr);
+            }
+          }
+        else
+#endif
+        /* Not UTF-8 mode */
+          {
+          for (i = min; i < max; i++)
+            {
+            if (eptr >= md->end_subject || fc == *eptr) break;
+            eptr++;
+            }
+          while (eptr >= pp)
+            {
+            RMATCH(rrc, eptr, ecode, offset_top, md, ims, eptrb, 0);
+            if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+            eptr--;
+            }
+          }
+
+        RRETURN(MATCH_NOMATCH);
+        }
+      }
+    /* Control never gets here */
+
+    /* Match a single character type repeatedly; several different opcodes
+    share code. This is very similar to the code for single characters, but we
+    repeat it in the interests of efficiency. */
+
+    case OP_TYPEEXACT:
+    min = max = GET2(ecode, 1);
+    minimize = TRUE;
+    ecode += 3;
+    goto REPEATTYPE;
+
+    case OP_TYPEUPTO:
+    case OP_TYPEMINUPTO:
+    min = 0;
+    max = GET2(ecode, 1);
+    minimize = *ecode == OP_TYPEMINUPTO;
+    ecode += 3;
+    goto REPEATTYPE;
+
+    case OP_TYPESTAR:
+    case OP_TYPEMINSTAR:
+    case OP_TYPEPLUS:
+    case OP_TYPEMINPLUS:
+    case OP_TYPEQUERY:
+    case OP_TYPEMINQUERY:
+    c = *ecode++ - OP_TYPESTAR;
+    minimize = (c & 1) != 0;
+    min = rep_min[c];                 /* Pick up values from tables; */
+    max = rep_max[c];                 /* zero for max => infinity */
+    if (max == 0) max = INT_MAX;
+
+    /* Common code for all repeated single character type matches. Note that
+    in UTF-8 mode, '.' matches a character of any length, but for the other
+    character types, the valid characters are all one-byte long. */
+
+    REPEATTYPE:
+    ctype = *ecode++;      /* Code for the character type */
+
+#ifdef SUPPORT_UCP
+    if (ctype == OP_PROP || ctype == OP_NOTPROP)
+      {
+      prop_fail_result = ctype == OP_NOTPROP;
+      prop_type = *ecode++;
+      if (prop_type >= 128)
+        {
+        prop_test_against = prop_type - 128;
+        prop_test_variable = &prop_category;
+        }
+      else
+        {
+        prop_test_against = prop_type;
+        prop_test_variable = &prop_chartype;
+        }
+      }
+    else prop_type = -1;
+#endif
+
+    /* First, ensure the minimum number of matches are present. Use inline
+    code for maximizing the speed, and do the type test once at the start
+    (i.e. keep it out of the loop). Also we can test that there are at least
+    the minimum number of bytes before we start. This isn't as effective in
+    UTF-8 mode, but it does no harm. Separate the UTF-8 code completely as that
+    is tidier. Also separate the UCP code, which can be the same for both UTF-8
+    and single-bytes. */
+
+    if (min > md->end_subject - eptr) RRETURN(MATCH_NOMATCH);
+    if (min > 0)
+      {
+#ifdef SUPPORT_UCP
+      if (prop_type > 0)
+        {
+        for (i = 1; i <= min; i++)
+          {
+          GETCHARINC(c, eptr);
+          prop_category = ucp_findchar(c, &prop_chartype, &prop_othercase);
+          if ((*prop_test_variable == prop_test_against) == prop_fail_result)
+            RRETURN(MATCH_NOMATCH);
+          }
+        }
+
+      /* Match extended Unicode sequences. We will get here only if the
+      support is in the binary; otherwise a compile-time error occurs. */
+
+      else if (ctype == OP_EXTUNI)
+        {
+        for (i = 1; i <= min; i++)
+          {
+          GETCHARINCTEST(c, eptr);
+          prop_category = ucp_findchar(c, &prop_chartype, &prop_othercase);
+          if (prop_category == ucp_M) RRETURN(MATCH_NOMATCH);
+          while (eptr < md->end_subject)
+            {
+            int len = 1;
+            if (!md->utf8) c = *eptr; else
+              {
+              GETCHARLEN(c, eptr, len);
+              }
+            prop_category = ucp_findchar(c, &prop_chartype, &prop_othercase);
+            if (prop_category != ucp_M) break;
+            eptr += len;
+            }
+          }
+        }
+
+      else
+#endif     /* SUPPORT_UCP */
+
+/* Handle all other cases when the coding is UTF-8 */
+
+#ifdef SUPPORT_UTF8
+      if (md->utf8) switch(ctype)
+        {
+        case OP_ANY:
+        for (i = 1; i <= min; i++)
+          {
+          if (eptr >= md->end_subject ||
+             (*eptr++ == NEWLINE && (ims & PCRE_DOTALL) == 0))
+            RRETURN(MATCH_NOMATCH);
+          while (eptr < md->end_subject && (*eptr & 0xc0) == 0x80) eptr++;
+          }
+        break;
+
+        case OP_ANYBYTE:
+        eptr += min;
+        break;
+
+        case OP_NOT_DIGIT:
+        for (i = 1; i <= min; i++)
+          {
+          if (eptr >= md->end_subject) RRETURN(MATCH_NOMATCH);
+          GETCHARINC(c, eptr);
+          if (c < 128 && (md->ctypes[c] & ctype_digit) != 0)
+            RRETURN(MATCH_NOMATCH);
+          }
+        break;
+
+        case OP_DIGIT:
+        for (i = 1; i <= min; i++)
+          {
+          if (eptr >= md->end_subject ||
+             *eptr >= 128 || (md->ctypes[*eptr++] & ctype_digit) == 0)
+            RRETURN(MATCH_NOMATCH);
+          /* No need to skip more bytes - we know it's a 1-byte character */
+          }
+        break;
+
+        case OP_NOT_WHITESPACE:
+        for (i = 1; i <= min; i++)
+          {
+          if (eptr >= md->end_subject ||
+             (*eptr < 128 && (md->ctypes[*eptr++] & ctype_space) != 0))
+            RRETURN(MATCH_NOMATCH);
+          while (eptr < md->end_subject && (*eptr & 0xc0) == 0x80) eptr++;
+          }
+        break;
+
+        case OP_WHITESPACE:
+        for (i = 1; i <= min; i++)
+          {
+          if (eptr >= md->end_subject ||
+             *eptr >= 128 || (md->ctypes[*eptr++] & ctype_space) == 0)
+            RRETURN(MATCH_NOMATCH);
+          /* No need to skip more bytes - we know it's a 1-byte character */
+          }
+        break;
+
+        case OP_NOT_WORDCHAR:
+        for (i = 1; i <= min; i++)
+          {
+          if (eptr >= md->end_subject ||
+             (*eptr < 128 && (md->ctypes[*eptr++] & ctype_word) != 0))
+            RRETURN(MATCH_NOMATCH);
+          while (eptr < md->end_subject && (*eptr & 0xc0) == 0x80) eptr++;
+          }
+        break;
+
+        case OP_WORDCHAR:
+        for (i = 1; i <= min; i++)
+          {
+          if (eptr >= md->end_subject ||
+             *eptr >= 128 || (md->ctypes[*eptr++] & ctype_word) == 0)
+            RRETURN(MATCH_NOMATCH);
+          /* No need to skip more bytes - we know it's a 1-byte character */
+          }
+        break;
+
+        default:
+        RRETURN(PCRE_ERROR_INTERNAL);
+        }  /* End switch(ctype) */
+
+      else
+#endif     /* SUPPORT_UTF8 */
+
+      /* Code for the non-UTF-8 case for minimum matching of operators other
+      than OP_PROP and OP_NOTPROP. */
+
+      switch(ctype)
+        {
+        case OP_ANY:
+        if ((ims & PCRE_DOTALL) == 0)
+          {
+          for (i = 1; i <= min; i++)
+            if (*eptr++ == NEWLINE) RRETURN(MATCH_NOMATCH);
+          }
+        else eptr += min;
+        break;
+
+        case OP_ANYBYTE:
+        eptr += min;
+        break;
+
+        case OP_NOT_DIGIT:
+        for (i = 1; i <= min; i++)
+          if ((md->ctypes[*eptr++] & ctype_digit) != 0) RRETURN(MATCH_NOMATCH);
+        break;
+
+        case OP_DIGIT:
+        for (i = 1; i <= min; i++)
+          if ((md->ctypes[*eptr++] & ctype_digit) == 0) RRETURN(MATCH_NOMATCH);
+        break;
+
+        case OP_NOT_WHITESPACE:
+        for (i = 1; i <= min; i++)
+          if ((md->ctypes[*eptr++] & ctype_space) != 0) RRETURN(MATCH_NOMATCH);
+        break;
+
+        case OP_WHITESPACE:
+        for (i = 1; i <= min; i++)
+          if ((md->ctypes[*eptr++] & ctype_space) == 0) RRETURN(MATCH_NOMATCH);
+        break;
+
+        case OP_NOT_WORDCHAR:
+        for (i = 1; i <= min; i++)
+          if ((md->ctypes[*eptr++] & ctype_word) != 0)
+            RRETURN(MATCH_NOMATCH);
+        break;
+
+        case OP_WORDCHAR:
+        for (i = 1; i <= min; i++)
+          if ((md->ctypes[*eptr++] & ctype_word) == 0)
+            RRETURN(MATCH_NOMATCH);
+        break;
+
+        default:
+        RRETURN(PCRE_ERROR_INTERNAL);
+        }
+      }
+
+    /* If min = max, continue at the same level without recursing */
+
+    if (min == max) continue;
+
+    /* If minimizing, we have to test the rest of the pattern before each
+    subsequent match. Again, separate the UTF-8 case for speed, and also
+    separate the UCP cases. */
+
+    if (minimize)
+      {
+#ifdef SUPPORT_UCP
+      if (prop_type > 0)
+        {
+        for (fi = min;; fi++)
+          {
+          RMATCH(rrc, eptr, ecode, offset_top, md, ims, eptrb, 0);
+          if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+          if (fi >= max || eptr >= md->end_subject) RRETURN(MATCH_NOMATCH);
+          GETCHARINC(c, eptr);
+          prop_category = ucp_findchar(c, &prop_chartype, &prop_othercase);
+          if ((*prop_test_variable == prop_test_against) == prop_fail_result)
+            RRETURN(MATCH_NOMATCH);
+          }
+        }
+
+      /* Match extended Unicode sequences. We will get here only if the
+      support is in the binary; otherwise a compile-time error occurs. */
+
+      else if (ctype == OP_EXTUNI)
+        {
+        for (fi = min;; fi++)
+          {
+          RMATCH(rrc, eptr, ecode, offset_top, md, ims, eptrb, 0);
+          if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+          if (fi >= max || eptr >= md->end_subject) RRETURN(MATCH_NOMATCH);
+          GETCHARINCTEST(c, eptr);
+          prop_category = ucp_findchar(c, &prop_chartype, &prop_othercase);
+          if (prop_category == ucp_M) RRETURN(MATCH_NOMATCH);
+          while (eptr < md->end_subject)
+            {
+            int len = 1;
+            if (!md->utf8) c = *eptr; else
+              {
+              GETCHARLEN(c, eptr, len);
+              }
+            prop_category = ucp_findchar(c, &prop_chartype, &prop_othercase);
+            if (prop_category != ucp_M) break;
+            eptr += len;
+            }
+          }
+        }
+
+      else
+#endif     /* SUPPORT_UCP */
+
+#ifdef SUPPORT_UTF8
+      /* UTF-8 mode */
+      if (md->utf8)
+        {
+        for (fi = min;; fi++)
+          {
+          RMATCH(rrc, eptr, ecode, offset_top, md, ims, eptrb, 0);
+          if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+          if (fi >= max || eptr >= md->end_subject) RRETURN(MATCH_NOMATCH);
+
+          GETCHARINC(c, eptr);
+          switch(ctype)
+            {
+            case OP_ANY:
+            if ((ims & PCRE_DOTALL) == 0 && c == NEWLINE) RRETURN(MATCH_NOMATCH);
+            break;
+
+            case OP_ANYBYTE:
+            break;
+
+            case OP_NOT_DIGIT:
+            if (c < 256 && (md->ctypes[c] & ctype_digit) != 0)
+              RRETURN(MATCH_NOMATCH);
+            break;
+
+            case OP_DIGIT:
+            if (c >= 256 || (md->ctypes[c] & ctype_digit) == 0)
+              RRETURN(MATCH_NOMATCH);
+            break;
+
+            case OP_NOT_WHITESPACE:
+            if (c < 256 && (md->ctypes[c] & ctype_space) != 0)
+              RRETURN(MATCH_NOMATCH);
+            break;
+
+            case OP_WHITESPACE:
+            if  (c >= 256 || (md->ctypes[c] & ctype_space) == 0)
+              RRETURN(MATCH_NOMATCH);
+            break;
+
+            case OP_NOT_WORDCHAR:
+            if (c < 256 && (md->ctypes[c] & ctype_word) != 0)
+              RRETURN(MATCH_NOMATCH);
+            break;
+
+            case OP_WORDCHAR:
+            if (c >= 256 && (md->ctypes[c] & ctype_word) == 0)
+              RRETURN(MATCH_NOMATCH);
+            break;
+
+            default:
+            RRETURN(PCRE_ERROR_INTERNAL);
+            }
+          }
+        }
+      else
+#endif
+      /* Not UTF-8 mode */
+        {
+        for (fi = min;; fi++)
+          {
+          RMATCH(rrc, eptr, ecode, offset_top, md, ims, eptrb, 0);
+          if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+          if (fi >= max || eptr >= md->end_subject) RRETURN(MATCH_NOMATCH);
+          c = *eptr++;
+          switch(ctype)
+            {
+            case OP_ANY:
+            if ((ims & PCRE_DOTALL) == 0 && c == NEWLINE) RRETURN(MATCH_NOMATCH);
+            break;
+
+            case OP_ANYBYTE:
+            break;
+
+            case OP_NOT_DIGIT:
+            if ((md->ctypes[c] & ctype_digit) != 0) RRETURN(MATCH_NOMATCH);
+            break;
+
+            case OP_DIGIT:
+            if ((md->ctypes[c] & ctype_digit) == 0) RRETURN(MATCH_NOMATCH);
+            break;
+
+            case OP_NOT_WHITESPACE:
+            if ((md->ctypes[c] & ctype_space) != 0) RRETURN(MATCH_NOMATCH);
+            break;
+
+            case OP_WHITESPACE:
+            if  ((md->ctypes[c] & ctype_space) == 0) RRETURN(MATCH_NOMATCH);
+            break;
+
+            case OP_NOT_WORDCHAR:
+            if ((md->ctypes[c] & ctype_word) != 0) RRETURN(MATCH_NOMATCH);
+            break;
+
+            case OP_WORDCHAR:
+            if ((md->ctypes[c] & ctype_word) == 0) RRETURN(MATCH_NOMATCH);
+            break;
+
+            default:
+            RRETURN(PCRE_ERROR_INTERNAL);
+            }
+          }
+        }
+      /* Control never gets here */
+      }
+
+    /* If maximizing it is worth using inline code for speed, doing the type
+    test once at the start (i.e. keep it out of the loop). Again, keep the
+    UTF-8 and UCP stuff separate. */
+
+    else
+      {
+      pp = eptr;  /* Remember where we started */
+
+#ifdef SUPPORT_UCP
+      if (prop_type > 0)
+        {
+        for (i = min; i < max; i++)
+          {
+          int len = 1;
+          if (eptr >= md->end_subject) break;
+          GETCHARLEN(c, eptr, len);
+          prop_category = ucp_findchar(c, &prop_chartype, &prop_othercase);
+          if ((*prop_test_variable == prop_test_against) == prop_fail_result)
+            break;
+          eptr+= len;
+          }
+
+        /* eptr is now past the end of the maximum run */
+
+        for(;;)
+          {
+          RMATCH(rrc, eptr, ecode, offset_top, md, ims, eptrb, 0);
+          if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+          if (eptr-- == pp) break;        /* Stop if tried at original pos */
+          BACKCHAR(eptr);
+          }
+        }
+
+      /* Match extended Unicode sequences. We will get here only if the
+      support is in the binary; otherwise a compile-time error occurs. */
+
+      else if (ctype == OP_EXTUNI)
+        {
+        for (i = min; i < max; i++)
+          {
+          if (eptr >= md->end_subject) break;
+          GETCHARINCTEST(c, eptr);
+          prop_category = ucp_findchar(c, &prop_chartype, &prop_othercase);
+          if (prop_category == ucp_M) break;
+          while (eptr < md->end_subject)
+            {
+            int len = 1;
+            if (!md->utf8) c = *eptr; else
+              {
+              GETCHARLEN(c, eptr, len);
+              }
+            prop_category = ucp_findchar(c, &prop_chartype, &prop_othercase);
+            if (prop_category != ucp_M) break;
+            eptr += len;
+            }
+          }
+
+        /* eptr is now past the end of the maximum run */
+
+        for(;;)
+          {
+          RMATCH(rrc, eptr, ecode, offset_top, md, ims, eptrb, 0);
+          if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+          if (eptr-- == pp) break;        /* Stop if tried at original pos */
+          for (;;)                        /* Move back over one extended */
+            {
+            int len = 1;
+            BACKCHAR(eptr);
+            if (!md->utf8) c = *eptr; else
+              {
+              GETCHARLEN(c, eptr, len);
+              }
+            prop_category = ucp_findchar(c, &prop_chartype, &prop_othercase);
+            if (prop_category != ucp_M) break;
+            eptr--;
+            }
+          }
+        }
+
+      else
+#endif   /* SUPPORT_UCP */
+
+#ifdef SUPPORT_UTF8
+      /* UTF-8 mode */
+
+      if (md->utf8)
+        {
+        switch(ctype)
+          {
+          case OP_ANY:
+
+          /* Special code is required for UTF8, but when the maximum is unlimited
+          we don't need it, so we repeat the non-UTF8 code. This is probably
+          worth it, because .* is quite a common idiom. */
+
+          if (max < INT_MAX)
+            {
+            if ((ims & PCRE_DOTALL) == 0)
+              {
+              for (i = min; i < max; i++)
+                {
+                if (eptr >= md->end_subject || *eptr == NEWLINE) break;
+                eptr++;
+                while (eptr < md->end_subject && (*eptr & 0xc0) == 0x80) eptr++;
+                }
+              }
+            else
+              {
+              for (i = min; i < max; i++)
+                {
+                eptr++;
+                while (eptr < md->end_subject && (*eptr & 0xc0) == 0x80) eptr++;
+                }
+              }
+            }
+
+          /* Handle unlimited UTF-8 repeat */
+
+          else
+            {
+            if ((ims & PCRE_DOTALL) == 0)
+              {
+              for (i = min; i < max; i++)
+                {
+                if (eptr >= md->end_subject || *eptr == NEWLINE) break;
+                eptr++;
+                }
+              break;
+              }
+            else
+              {
+              c = max - min;
+              if (c > md->end_subject - eptr) c = md->end_subject - eptr;
+              eptr += c;
+              }
+            }
+          break;
+
+          /* The byte case is the same as non-UTF8 */
+
+          case OP_ANYBYTE:
+          c = max - min;
+          if (c > md->end_subject - eptr) c = md->end_subject - eptr;
+          eptr += c;
+          break;
+
+          case OP_NOT_DIGIT:
+          for (i = min; i < max; i++)
+            {
+            int len = 1;
+            if (eptr >= md->end_subject) break;
+            GETCHARLEN(c, eptr, len);
+            if (c < 256 && (md->ctypes[c] & ctype_digit) != 0) break;
+            eptr+= len;
+            }
+          break;
+
+          case OP_DIGIT:
+          for (i = min; i < max; i++)
+            {
+            int len = 1;
+            if (eptr >= md->end_subject) break;
+            GETCHARLEN(c, eptr, len);
+            if (c >= 256 ||(md->ctypes[c] & ctype_digit) == 0) break;
+            eptr+= len;
+            }
+          break;
+
+          case OP_NOT_WHITESPACE:
+          for (i = min; i < max; i++)
+            {
+            int len = 1;
+            if (eptr >= md->end_subject) break;
+            GETCHARLEN(c, eptr, len);
+            if (c < 256 && (md->ctypes[c] & ctype_space) != 0) break;
+            eptr+= len;
+            }
+          break;
+
+          case OP_WHITESPACE:
+          for (i = min; i < max; i++)
+            {
+            int len = 1;
+            if (eptr >= md->end_subject) break;
+            GETCHARLEN(c, eptr, len);
+            if (c >= 256 ||(md->ctypes[c] & ctype_space) == 0) break;
+            eptr+= len;
+            }
+          break;
+
+          case OP_NOT_WORDCHAR:
+          for (i = min; i < max; i++)
+            {
+            int len = 1;
+            if (eptr >= md->end_subject) break;
+            GETCHARLEN(c, eptr, len);
+            if (c < 256 && (md->ctypes[c] & ctype_word) != 0) break;
+            eptr+= len;
+            }
+          break;
+
+          case OP_WORDCHAR:
+          for (i = min; i < max; i++)
+            {
+            int len = 1;
+            if (eptr >= md->end_subject) break;
+            GETCHARLEN(c, eptr, len);
+            if (c >= 256 || (md->ctypes[c] & ctype_word) == 0) break;
+            eptr+= len;
+            }
+          break;
+
+          default:
+          RRETURN(PCRE_ERROR_INTERNAL);
+          }
+
+        /* eptr is now past the end of the maximum run */
+
+        for(;;)
+          {
+          RMATCH(rrc, eptr, ecode, offset_top, md, ims, eptrb, 0);
+          if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+          if (eptr-- == pp) break;        /* Stop if tried at original pos */
+          BACKCHAR(eptr);
+          }
+        }
+      else
+#endif
+
+      /* Not UTF-8 mode */
+        {
+        switch(ctype)
+          {
+          case OP_ANY:
+          if ((ims & PCRE_DOTALL) == 0)
+            {
+            for (i = min; i < max; i++)
+              {
+              if (eptr >= md->end_subject || *eptr == NEWLINE) break;
+              eptr++;
+              }
+            break;
+            }
+          /* For DOTALL case, fall through and treat as \C */
+
+          case OP_ANYBYTE:
+          c = max - min;
+          if (c > md->end_subject - eptr) c = md->end_subject - eptr;
+          eptr += c;
+          break;
+
+          case OP_NOT_DIGIT:
+          for (i = min; i < max; i++)
+            {
+            if (eptr >= md->end_subject || (md->ctypes[*eptr] & ctype_digit) != 0)
+              break;
+            eptr++;
+            }
+          break;
+
+          case OP_DIGIT:
+          for (i = min; i < max; i++)
+            {
+            if (eptr >= md->end_subject || (md->ctypes[*eptr] & ctype_digit) == 0)
+              break;
+            eptr++;
+            }
+          break;
+
+          case OP_NOT_WHITESPACE:
+          for (i = min; i < max; i++)
+            {
+            if (eptr >= md->end_subject || (md->ctypes[*eptr] & ctype_space) != 0)
+              break;
+            eptr++;
+            }
+          break;
+
+          case OP_WHITESPACE:
+          for (i = min; i < max; i++)
+            {
+            if (eptr >= md->end_subject || (md->ctypes[*eptr] & ctype_space) == 0)
+              break;
+            eptr++;
+            }
+          break;
+
+          case OP_NOT_WORDCHAR:
+          for (i = min; i < max; i++)
+            {
+            if (eptr >= md->end_subject || (md->ctypes[*eptr] & ctype_word) != 0)
+              break;
+            eptr++;
+            }
+          break;
+
+          case OP_WORDCHAR:
+          for (i = min; i < max; i++)
+            {
+            if (eptr >= md->end_subject || (md->ctypes[*eptr] & ctype_word) == 0)
+              break;
+            eptr++;
+            }
+          break;
+
+          default:
+          RRETURN(PCRE_ERROR_INTERNAL);
+          }
+
+        /* eptr is now past the end of the maximum run */
+
+        while (eptr >= pp)
+          {
+          RMATCH(rrc, eptr, ecode, offset_top, md, ims, eptrb, 0);
+          eptr--;
+          if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+          }
+        }
+
+      /* Get here if we can't make it match with any permitted repetitions */
+
+      RRETURN(MATCH_NOMATCH);
+      }
+    /* Control never gets here */
+
+    /* There's been some horrible disaster. Since all codes > OP_BRA are
+    for capturing brackets, and there shouldn't be any gaps between 0 and
+    OP_BRA, arrival here can only mean there is something seriously wrong
+    in the code above or the OP_xxx definitions. */
+
+    default:
+    DPRINTF(("Unknown opcode %d\n", *ecode));
+    RRETURN(PCRE_ERROR_UNKNOWN_NODE);
+    }
+
+  /* Do not stick any code in here without much thought; it is assumed
+  that "continue" in the code above comes out to here to repeat the main
+  loop. */
+
+  }             /* End of main loop */
+/* Control never reaches here */
+}
+
+
+/***************************************************************************
+****************************************************************************
+                   RECURSION IN THE match() FUNCTION
+
+Undefine all the macros that were defined above to handle this. */
+
+#ifdef NO_RECURSE
+#undef eptr
+#undef ecode
+#undef offset_top
+#undef ims
+#undef eptrb
+#undef flags
+
+#undef callpat
+#undef charptr
+#undef data
+#undef next
+#undef pp
+#undef prev
+#undef saved_eptr
+
+#undef new_recursive
+
+#undef cur_is_word
+#undef condition
+#undef minimize
+#undef prev_is_word
+
+#undef original_ims
+
+#undef ctype
+#undef length
+#undef max
+#undef min
+#undef number
+#undef offset
+#undef op
+#undef save_capture_last
+#undef save_offset1
+#undef save_offset2
+#undef save_offset3
+#undef stacksave
+
+#undef newptrb
+
+#endif
+
+/* These two are defined as macros in both cases */
+
+#undef fc
+#undef fi
+
+/***************************************************************************
+***************************************************************************/
+
+
+
+/*************************************************
+*         Execute a Regular Expression           *
+*************************************************/
+
+/* This function applies a compiled re to a subject string and picks out
+portions of the string if it matches. Two elements in the vector are set for
+each substring: the offsets to the start and end of the substring.
+
+Arguments:
+  argument_re     points to the compiled expression
+  extra_data      points to extra data or is NULL
+  subject         points to the subject string
+  length          length of subject string (may contain binary zeros)
+  start_offset    where to start in the subject string
+  options         option bits
+  offsets         points to a vector of ints to be filled in with offsets
+  offsetcount     the number of elements in the vector
+
+Returns:          > 0 => success; value is the number of elements filled in
+                  = 0 => success, but offsets is not big enough
+                   -1 => failed to match
+                 < -1 => some kind of unexpected problem
+*/
+
+EXPORT int
+pcre_exec(const pcre *argument_re, const pcre_extra *extra_data,
+  const char *subject, int length, int start_offset, int options, int *offsets,
+  int offsetcount)
+{
+int rc, resetcount, ocount;
+int first_byte = -1;
+int req_byte = -1;
+int req_byte2 = -1;
+unsigned long int ims = 0;
+BOOL using_temporary_offsets = FALSE;
+BOOL anchored;
+BOOL startline;
+BOOL first_byte_caseless = FALSE;
+BOOL req_byte_caseless = FALSE;
+match_data match_block;
+const uschar *tables;
+const uschar *start_bits = NULL;
+const uschar *start_match = (const uschar *)subject + start_offset;
+const uschar *end_subject;
+const uschar *req_byte_ptr = start_match - 1;
+
+pcre_study_data internal_study;
+const pcre_study_data *study;
+
+real_pcre internal_re;
+const real_pcre *external_re = (const real_pcre *)argument_re;
+const real_pcre *re = external_re;
+
+/* Plausibility checks */
+
+if ((options & ~PUBLIC_EXEC_OPTIONS) != 0) return PCRE_ERROR_BADOPTION;
+if (re == NULL || subject == NULL ||
+   (offsets == NULL && offsetcount > 0)) return PCRE_ERROR_NULL;
+if (offsetcount < 0) return PCRE_ERROR_BADCOUNT;
+
+/* Fish out the optional data from the extra_data structure, first setting
+the default values. */
+
+study = NULL;
+match_block.match_limit = MATCH_LIMIT;
+match_block.callout_data = NULL;
+
+/* The table pointer is always in native byte order. */
+
+tables = external_re->tables;
+
+if (extra_data != NULL)
+  {
+  register unsigned int flags = extra_data->flags;
+  if ((flags & PCRE_EXTRA_STUDY_DATA) != 0)
+    study = (const pcre_study_data *)extra_data->study_data;
+  if ((flags & PCRE_EXTRA_MATCH_LIMIT) != 0)
+    match_block.match_limit = extra_data->match_limit;
+  if ((flags & PCRE_EXTRA_CALLOUT_DATA) != 0)
+    match_block.callout_data = extra_data->callout_data;
+  if ((flags & PCRE_EXTRA_TABLES) != 0) tables = extra_data->tables;
+  }
+
+/* If the exec call supplied NULL for tables, use the inbuilt ones. This
+is a feature that makes it possible to save compiled regex and re-use them
+in other programs later. */
+
+if (tables == NULL) tables = pcre_default_tables;
+
+/* Check that the first field in the block is the magic number. If it is not,
+test for a regex that was compiled on a host of opposite endianness. If this is
+the case, flipped values are put in internal_re and internal_study if there was
+study data too. */
+
+if (re->magic_number != MAGIC_NUMBER)
+  {
+  re = try_flipped(re, &internal_re, study, &internal_study);
+  if (re == NULL) return PCRE_ERROR_BADMAGIC;
+  if (study != NULL) study = &internal_study;
+  }
+
+/* Set up other data */
+
+anchored = ((re->options | options) & PCRE_ANCHORED) != 0;
+startline = (re->options & PCRE_STARTLINE) != 0;
+
+/* The code starts after the real_pcre block and the capture name table. */
+
+match_block.start_code = (const uschar *)external_re + re->name_table_offset +
+  re->name_count * re->name_entry_size;
+
+match_block.start_subject = (const uschar *)subject;
+match_block.start_offset = start_offset;
+match_block.end_subject = match_block.start_subject + length;
+end_subject = match_block.end_subject;
+
+match_block.endonly = (re->options & PCRE_DOLLAR_ENDONLY) != 0;
+match_block.utf8 = (re->options & PCRE_UTF8) != 0;
+
+match_block.notbol = (options & PCRE_NOTBOL) != 0;
+match_block.noteol = (options & PCRE_NOTEOL) != 0;
+match_block.notempty = (options & PCRE_NOTEMPTY) != 0;
+match_block.partial = (options & PCRE_PARTIAL) != 0;
+match_block.hitend = FALSE;
+
+match_block.recursive = NULL;                   /* No recursion at top level */
+
+match_block.lcc = tables + lcc_offset;
+match_block.ctypes = tables + ctypes_offset;
+
+/* Partial matching is supported only for a restricted set of regexes at the
+moment. */
+
+if (match_block.partial && (re->options & PCRE_NOPARTIAL) != 0)
+  return PCRE_ERROR_BADPARTIAL;
+
+/* Check a UTF-8 string if required. Unfortunately there's no way of passing
+back the character offset. */
+
+#ifdef SUPPORT_UTF8
+if (match_block.utf8 && (options & PCRE_NO_UTF8_CHECK) == 0)
+  {
+  if (valid_utf8((uschar *)subject, length) >= 0)
+    return PCRE_ERROR_BADUTF8;
+  if (start_offset > 0 && start_offset < length)
+    {
+    int tb = ((uschar *)subject)[start_offset];
+    if (tb > 127)
+      {
+      tb &= 0xc0;
+      if (tb != 0 && tb != 0xc0) return PCRE_ERROR_BADUTF8_OFFSET;
+      }
+    }
+  }
+#endif
+
+/* The ims options can vary during the matching as a result of the presence
+of (?ims) items in the pattern. They are kept in a local variable so that
+restoring at the exit of a group is easy. */
+
+ims = re->options & (PCRE_CASELESS|PCRE_MULTILINE|PCRE_DOTALL);
+
+/* If the expression has got more back references than the offsets supplied can
+hold, we get a temporary chunk of working store to use during the matching.
+Otherwise, we can use the vector supplied, rounding down its size to a multiple
+of 3. */
+
+ocount = offsetcount - (offsetcount % 3);
+
+if (re->top_backref > 0 && re->top_backref >= ocount/3)
+  {
+  ocount = re->top_backref * 3 + 3;
+  match_block.offset_vector = (int *)(pcre_malloc)(ocount * sizeof(int));
+  if (match_block.offset_vector == NULL) return PCRE_ERROR_NOMEMORY;
+  using_temporary_offsets = TRUE;
+  DPRINTF(("Got memory to hold back references\n"));
+  }
+else match_block.offset_vector = offsets;
+
+match_block.offset_end = ocount;
+match_block.offset_max = (2*ocount)/3;
+match_block.offset_overflow = FALSE;
+match_block.capture_last = -1;
+
+/* Compute the minimum number of offsets that we need to reset each time. Doing
+this makes a huge difference to execution time when there aren't many brackets
+in the pattern. */
+
+resetcount = 2 + re->top_bracket * 2;
+if (resetcount > offsetcount) resetcount = ocount;
+
+/* Reset the working variable associated with each extraction. These should
+never be used unless previously set, but they get saved and restored, and so we
+initialize them to avoid reading uninitialized locations. */
+
+if (match_block.offset_vector != NULL)
+  {
+  register int *iptr = match_block.offset_vector + ocount;
+  register int *iend = iptr - resetcount/2 + 1;
+  while (--iptr >= iend) *iptr = -1;
+  }
+
+/* Set up the first character to match, if available. The first_byte value is
+never set for an anchored regular expression, but the anchoring may be forced
+at run time, so we have to test for anchoring. The first char may be unset for
+an unanchored pattern, of course. If there's no first char and the pattern was
+studied, there may be a bitmap of possible first characters. */
+
+if (!anchored)
+  {
+  if ((re->options & PCRE_FIRSTSET) != 0)
+    {
+    first_byte = re->first_byte & 255;
+    if ((first_byte_caseless = ((re->first_byte & REQ_CASELESS) != 0)) == TRUE)
+      first_byte = match_block.lcc[first_byte];
+    }
+  else
+    if (!startline && study != NULL &&
+      (study->options & PCRE_STUDY_MAPPED) != 0)
+        start_bits = study->start_bits;
+  }
+
+/* For anchored or unanchored matches, there may be a "last known required
+character" set. */
+
+if ((re->options & PCRE_REQCHSET) != 0)
+  {
+  req_byte = re->req_byte & 255;
+  req_byte_caseless = (re->req_byte & REQ_CASELESS) != 0;
+  req_byte2 = (tables + fcc_offset)[req_byte];  /* case flipped */
+  }
+
+/* Loop for handling unanchored repeated matching attempts; for anchored regexs
+the loop runs just once. */
+
+do
+  {
+  /* Reset the maximum number of extractions we might see. */
+
+  if (match_block.offset_vector != NULL)
+    {
+    register int *iptr = match_block.offset_vector;
+    register int *iend = iptr + resetcount;
+    while (iptr < iend) *iptr++ = -1;
+    }
+
+  /* Advance to a unique first char if possible */
+
+  if (first_byte >= 0)
+    {
+    if (first_byte_caseless)
+      while (start_match < end_subject &&
+             match_block.lcc[*start_match] != first_byte)
+        start_match++;
+    else
+      while (start_match < end_subject && *start_match != first_byte)
+        start_match++;
+    }
+
+  /* Or to just after \n for a multiline match if possible */
+
+  else if (startline)
+    {
+    if (start_match > match_block.start_subject + start_offset)
+      {
+      while (start_match < end_subject && start_match[-1] != NEWLINE)
+        start_match++;
+      }
+    }
+
+  /* Or to a non-unique first char after study */
+
+  else if (start_bits != NULL)
+    {
+    while (start_match < end_subject)
+      {
+      register unsigned int c = *start_match;
+      if ((start_bits[c/8] & (1 << (c&7))) == 0) start_match++; else break;
+      }
+    }
+
+#ifdef DEBUG  /* Sigh. Some compilers never learn. */
+  printf(">>>> Match against: ");
+  pchars(start_match, end_subject - start_match, TRUE, &match_block);
+  printf("\n");
+#endif
+
+  /* If req_byte is set, we know that that character must appear in the subject
+  for the match to succeed. If the first character is set, req_byte must be
+  later in the subject; otherwise the test starts at the match point. This
+  optimization can save a huge amount of backtracking in patterns with nested
+  unlimited repeats that aren't going to match. Writing separate code for
+  cased/caseless versions makes it go faster, as does using an autoincrement
+  and backing off on a match.
+
+  HOWEVER: when the subject string is very, very long, searching to its end can
+  take a long time, and give bad performance on quite ordinary patterns. This
+  showed up when somebody was matching /^C/ on a 32-megabyte string... so we
+  don't do this when the string is sufficiently long.
+
+  ALSO: this processing is disabled when partial matching is requested.
+  */
+
+  if (req_byte >= 0 &&
+      end_subject - start_match < REQ_BYTE_MAX &&
+      !match_block.partial)
+    {
+    register const uschar *p = start_match + ((first_byte >= 0)? 1 : 0);
+
+    /* We don't need to repeat the search if we haven't yet reached the
+    place we found it at last time. */
+
+    if (p > req_byte_ptr)
+      {
+      if (req_byte_caseless)
+        {
+        while (p < end_subject)
+          {
+          register int pp = *p++;
+          if (pp == req_byte || pp == req_byte2) { p--; break; }
+          }
+        }
+      else
+        {
+        while (p < end_subject)
+          {
+          if (*p++ == req_byte) { p--; break; }
+          }
+        }
+
+      /* If we can't find the required character, break the matching loop */
+
+      if (p >= end_subject) break;
+
+      /* If we have found the required character, save the point where we
+      found it, so that we don't search again next time round the loop if
+      the start hasn't passed this character yet. */
+
+      req_byte_ptr = p;
+      }
+    }
+
+  /* When a match occurs, substrings will be set for all internal extractions;
+  we just need to set up the whole thing as substring 0 before returning. If
+  there were too many extractions, set the return code to zero. In the case
+  where we had to get some local store to hold offsets for backreferences, copy
+  those back references that we can. In this case there need not be overflow
+  if certain parts of the pattern were not used. */
+
+  match_block.start_match = start_match;
+  match_block.match_call_count = 0;
+
+  rc = match(start_match, match_block.start_code, 2, &match_block, ims, NULL,
+    match_isgroup);
+
+  if (rc == MATCH_NOMATCH)
+    {
+    start_match++;
+#ifdef SUPPORT_UTF8
+    if (match_block.utf8)
+      while(start_match < end_subject && (*start_match & 0xc0) == 0x80)
+        start_match++;
+#endif
+    continue;
+    }
+
+  if (rc != MATCH_MATCH)
+    {
+    DPRINTF((">>>> error: returning %d\n", rc));
+    return rc;
+    }
+
+  /* We have a match! Copy the offset information from temporary store if
+  necessary */
+
+  if (using_temporary_offsets)
+    {
+    if (offsetcount >= 4)
+      {
+      memcpy(offsets + 2, match_block.offset_vector + 2,
+        (offsetcount - 2) * sizeof(int));
+      DPRINTF(("Copied offsets from temporary memory\n"));
+      }
+    if (match_block.end_offset_top > offsetcount)
+      match_block.offset_overflow = TRUE;
+
+    DPRINTF(("Freeing temporary memory\n"));
+    (pcre_free)(match_block.offset_vector);
+    }
+
+  rc = match_block.offset_overflow? 0 : match_block.end_offset_top/2;
+
+  if (offsetcount < 2) rc = 0; else
+    {
+    offsets[0] = start_match - match_block.start_subject;
+    offsets[1] = match_block.end_match_ptr - match_block.start_subject;
+    }
+
+  DPRINTF((">>>> returning %d\n", rc));
+  return rc;
+  }
+
+/* This "while" is the end of the "do" above */
+
+while (!anchored && start_match <= end_subject);
+
+if (using_temporary_offsets)
+  {
+  DPRINTF(("Freeing temporary memory\n"));
+  (pcre_free)(match_block.offset_vector);
+  }
+
+if (match_block.partial && match_block.hitend)
+  {
+  DPRINTF((">>>> returning PCRE_ERROR_PARTIAL\n"));
+  return PCRE_ERROR_PARTIAL;
+  }
+else
+  {
+  DPRINTF((">>>> returning PCRE_ERROR_NOMATCH\n"));
+  return PCRE_ERROR_NOMATCH;
+  }
+}
+
+/* End of pcre.c */

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/pcre.def
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/pcre.def	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/pcre.def	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,22 @@
+EXPORTS
+
+pcre_malloc DATA
+pcre_free DATA
+
+pcre_compile
+pcre_copy_substring
+pcre_exec
+pcre_get_substring
+pcre_get_substring_list
+pcre_free_substring
+pcre_free_substring_list
+pcre_info
+pcre_fullinfo
+pcre_maketables
+pcre_study
+pcre_version
+
+regcomp
+regexec
+regerror
+regfree

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/pcre.dsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/pcre.dsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/pcre.dsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,193 @@
+# Microsoft Developer Studio Project File - Name="pcre" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Static Library" 0x0104
+
+CFG=pcre - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE 
+!MESSAGE NMAKE /f "pcre.mak".
+!MESSAGE 
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE 
+!MESSAGE NMAKE /f "pcre.mak" CFG="pcre - Win32 Debug"
+!MESSAGE 
+!MESSAGE Possible choices for configuration are:
+!MESSAGE 
+!MESSAGE "pcre - Win32 Release" (based on "Win32 (x86) Static Library")
+!MESSAGE "pcre - Win32 Debug" (based on "Win32 (x86) Static Library")
+!MESSAGE 
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF  "$(CFG)" == "pcre - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "LibR"
+# PROP Intermediate_Dir "LibR"
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MD /W3 /O2 /D "_WIN32" /D "NDEBUG" /D "_WINDOWS" /D "PCRE_STATIC" /FD /c
+# ADD CPP /nologo /MD /W3 /Zi /O2 /D "_WIN32" /D "NDEBUG" /D "_WINDOWS" /D "PCRE_STATIC" /Fd"LibR/pcre_src" /FD /c
+# ADD BASE RSC /l 0x409
+# ADD RSC /l 0x409
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LIB32=link.exe -lib
+# ADD BASE LIB32 /nologo
+# ADD LIB32 /nologo
+
+!ELSEIF  "$(CFG)" == "pcre - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "LibD"
+# PROP Intermediate_Dir "LibD"
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MDd /W3 /EHsc /Zi /Od /D "_WIN32" /D "_DEBUG" /D "_WINDOWS" /D "PCRE_STATIC" /FD /c
+# ADD CPP /nologo /MDd /W3 /EHsc /Zi /Od /D "_WIN32" /D "_DEBUG" /D "_WINDOWS" /D "PCRE_STATIC" /Fd"LibD/pcre_src" /FD /c
+# ADD BASE RSC /l 0x409
+# ADD RSC /l 0x409
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LIB32=link.exe -lib
+# ADD BASE LIB32 /nologo
+# ADD LIB32 /nologo
+
+!ENDIF 
+
+# Begin Target
+
+# Name "pcre - Win32 Release"
+# Name "pcre - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "*.c"
+# Begin Source File
+
+SOURCE=.\dftables.exe
+
+!IF  "$(CFG)" == "pcre - Win32 Release"
+
+# Begin Custom Build - Creating pcre chartables.c from dftables 
+InputPath=.\dftables.exe
+
+".\chartables.c" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+	.\dftables.exe chartables.c 
+	
+# End Custom Build
+
+!ELSEIF  "$(CFG)" == "pcre - Win32 Debug"
+
+# Begin Custom Build - Creating pcre chartables.c from dftables 
+InputPath=.\dftables.exe
+
+".\chartables.c" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+	.\dftables.exe chartables.c 
+	
+# End Custom Build
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\get.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\maketables.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\pcre.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\study.c
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "*.h"
+# Begin Source File
+
+SOURCE=.\config.hw
+
+!IF  "$(CFG)" == "pcre - Win32 Release"
+
+# Begin Custom Build - Creating pcre config.h from config.hw 
+InputPath=.\config.hw
+
+".\config.h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+	type .\config.hw > .\config.h
+	
+# End Custom Build
+
+!ELSEIF  "$(CFG)" == "pcre - Win32 Debug"
+
+# Begin Custom Build - Creating pcre config.h from config.hw 
+InputPath=.\config.hw
+
+".\config.h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+	type .\config.hw > .\config.h
+	
+# End Custom Build
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\internal.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\pcre.hw
+
+!IF  "$(CFG)" == "pcre - Win32 Release"
+
+# Begin Custom Build - Creating pcre.h from pcre.hw 
+InputPath=.\pcre.hw
+
+".\pcre.h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+	type .\pcre.hw > .\pcre.h
+	
+# End Custom Build
+
+!ELSEIF  "$(CFG)" == "pcre - Win32 Debug"
+
+# Begin Custom Build - Creating pcre.h from pcre.hw 
+InputPath=.\pcre.hw
+
+".\pcre.h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+	type .\pcre.hw > .\pcre.h
+	
+# End Custom Build
+
+!ENDIF 
+
+# End Source File
+# End Group
+# End Target
+# End Project

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/pcre.hw
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/pcre.hw	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/pcre.hw	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,239 @@
+/*************************************************
+*       Perl-Compatible Regular Expressions      *
+*************************************************/
+
+/* In its original form, this is the .in file that is transformed by
+"configure" into pcre.h.
+
+           Copyright (c) 1997-2004 University of Cambridge
+
+-----------------------------------------------------------------------------
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice,
+      this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+
+    * Neither the name of the University of Cambridge nor the names of its
+      contributors may be used to endorse or promote products derived from
+      this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+-----------------------------------------------------------------------------
+*/
+
+#ifndef _PCRE_H
+#define _PCRE_H
+
+/* The file pcre.h is build by "configure" or copied from pcre.hw
+Do not edit it; instead make changes to pcre.in and/or pcre.hw */
+
+#define PCRE_MAJOR          5
+#define PCRE_MINOR          0
+#define PCRE_DATE           13-Sep-2004
+
+/* Win32 uses DLL by default */
+
+#ifdef _WIN32
+#  ifdef PCRE_DEFINITION
+#    ifdef DLL_EXPORT
+#      define PCRE_DATA_SCOPE __declspec(dllexport)
+#    endif
+#  else
+#    ifndef PCRE_STATIC
+#      define PCRE_DATA_SCOPE extern __declspec(dllimport)
+#    endif
+#  endif
+#endif
+#ifndef PCRE_DATA_SCOPE
+#  define PCRE_DATA_SCOPE     extern
+#endif
+
+/* Have to include stdlib.h in order to ensure that size_t is defined;
+it is needed here for malloc. */
+
+#include <stdlib.h>
+
+/* Allow for C++ users */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Options */
+
+#define PCRE_CASELESS           0x0001
+#define PCRE_MULTILINE          0x0002
+#define PCRE_DOTALL             0x0004
+#define PCRE_EXTENDED           0x0008
+#define PCRE_ANCHORED           0x0010
+#define PCRE_DOLLAR_ENDONLY     0x0020
+#define PCRE_EXTRA              0x0040
+#define PCRE_NOTBOL             0x0080
+#define PCRE_NOTEOL             0x0100
+#define PCRE_UNGREEDY           0x0200
+#define PCRE_NOTEMPTY           0x0400
+#define PCRE_UTF8               0x0800
+#define PCRE_NO_AUTO_CAPTURE    0x1000
+#define PCRE_NO_UTF8_CHECK      0x2000
+#define PCRE_AUTO_CALLOUT       0x4000
+#define PCRE_PARTIAL            0x8000
+
+/* Exec-time and get/set-time error codes */
+
+#define PCRE_ERROR_NOMATCH         (-1)
+#define PCRE_ERROR_NULL            (-2)
+#define PCRE_ERROR_BADOPTION       (-3)
+#define PCRE_ERROR_BADMAGIC        (-4)
+#define PCRE_ERROR_UNKNOWN_NODE    (-5)
+#define PCRE_ERROR_NOMEMORY        (-6)
+#define PCRE_ERROR_NOSUBSTRING     (-7)
+#define PCRE_ERROR_MATCHLIMIT      (-8)
+#define PCRE_ERROR_CALLOUT         (-9)  /* Never used by PCRE itself */
+#define PCRE_ERROR_BADUTF8        (-10)
+#define PCRE_ERROR_BADUTF8_OFFSET (-11)
+#define PCRE_ERROR_PARTIAL        (-12)
+#define PCRE_ERROR_BADPARTIAL     (-13)
+#define PCRE_ERROR_INTERNAL       (-14)
+#define PCRE_ERROR_BADCOUNT       (-15)
+
+/* Request types for pcre_fullinfo() */
+
+#define PCRE_INFO_OPTIONS            0
+#define PCRE_INFO_SIZE               1
+#define PCRE_INFO_CAPTURECOUNT       2
+#define PCRE_INFO_BACKREFMAX         3
+#define PCRE_INFO_FIRSTBYTE          4
+#define PCRE_INFO_FIRSTCHAR          4  /* For backwards compatibility */
+#define PCRE_INFO_FIRSTTABLE         5
+#define PCRE_INFO_LASTLITERAL        6
+#define PCRE_INFO_NAMEENTRYSIZE      7
+#define PCRE_INFO_NAMECOUNT          8
+#define PCRE_INFO_NAMETABLE          9
+#define PCRE_INFO_STUDYSIZE         10
+#define PCRE_INFO_DEFAULT_TABLES    11
+
+/* Request types for pcre_config() */
+
+#define PCRE_CONFIG_UTF8                    0
+#define PCRE_CONFIG_NEWLINE                 1
+#define PCRE_CONFIG_LINK_SIZE               2
+#define PCRE_CONFIG_POSIX_MALLOC_THRESHOLD  3
+#define PCRE_CONFIG_MATCH_LIMIT             4
+#define PCRE_CONFIG_STACKRECURSE            5
+#define PCRE_CONFIG_UNICODE_PROPERTIES      6
+
+/* Bit flags for the pcre_extra structure */
+
+#define PCRE_EXTRA_STUDY_DATA          0x0001
+#define PCRE_EXTRA_MATCH_LIMIT         0x0002
+#define PCRE_EXTRA_CALLOUT_DATA        0x0004
+#define PCRE_EXTRA_TABLES              0x0008
+
+/* Types */
+
+struct real_pcre;                 /* declaration; the definition is private  */
+typedef struct real_pcre pcre;
+
+/* The structure for passing additional data to pcre_exec(). This is defined in
+such as way as to be extensible. Always add new fields at the end, in order to
+remain compatible. */
+
+typedef struct pcre_extra {
+  unsigned long int flags;        /* Bits for which fields are set */
+  void *study_data;               /* Opaque data from pcre_study() */
+  unsigned long int match_limit;  /* Maximum number of calls to match() */
+  void *callout_data;             /* Data passed back in callouts */
+  const unsigned char *tables;    /* Pointer to character tables */
+} pcre_extra;
+
+/* The structure for passing out data via the pcre_callout_function. We use a
+structure so that new fields can be added on the end in future versions,
+without changing the API of the function, thereby allowing old clients to work
+without modification. */
+
+typedef struct pcre_callout_block {
+  int          version;           /* Identifies version of block */
+  /* ------------------------ Version 0 ------------------------------- */
+  int          callout_number;    /* Number compiled into pattern */
+  int         *offset_vector;     /* The offset vector */
+  const char  *subject;           /* The subject being matched */
+  int          subject_length;    /* The length of the subject */
+  int          start_match;       /* Offset to start of this match attempt */
+  int          current_position;  /* Where we currently are in the subject */
+  int          capture_top;       /* Max current capture */
+  int          capture_last;      /* Most recently closed capture */
+  void        *callout_data;      /* Data passed in with the call */
+  /* ------------------- Added for Version 1 -------------------------- */
+  int          pattern_position;  /* Offset to next item in the pattern */
+  int          next_item_length;  /* Length of next item in the pattern */
+  /* ------------------------------------------------------------------ */
+} pcre_callout_block;
+
+/* Indirection for store get and free functions. These can be set to
+alternative malloc/free functions if required. Special ones are used in the
+non-recursive case for "frames". There is also an optional callout function
+that is triggered by the (?) regex item. Some magic is required for Win32 DLL;
+it is null on other OS. For Virtual Pascal, these have to be different again.
+*/
+
+#ifndef VPCOMPAT
+PCRE_DATA_SCOPE void *(*pcre_malloc)(size_t);
+PCRE_DATA_SCOPE void  (*pcre_free)(void *);
+PCRE_DATA_SCOPE void *(*pcre_stack_malloc)(size_t);
+PCRE_DATA_SCOPE void  (*pcre_stack_free)(void *);
+PCRE_DATA_SCOPE int   (*pcre_callout)(pcre_callout_block *);
+#else   /* VPCOMPAT */
+extern void *pcre_malloc(size_t);
+extern void  pcre_free(void *);
+extern void *pcre_stack_malloc(size_t);
+extern void  pcre_stack_free(void *);
+extern int   pcre_callout(pcre_callout_block *);
+#endif  /* VPCOMPAT */
+
+/* Exported PCRE functions */
+
+extern pcre *pcre_compile(const char *, int, const char **,
+              int *, const unsigned char *);
+extern int  pcre_config(int, void *);
+extern int  pcre_copy_named_substring(const pcre *, const char *,
+              int *, int, const char *, char *, int);
+extern int  pcre_copy_substring(const char *, int *, int, int,
+              char *, int);
+extern int  pcre_exec(const pcre *, const pcre_extra *,
+              const char *, int, int, int, int *, int);
+extern void pcre_free_substring(const char *);
+extern void pcre_free_substring_list(const char **);
+extern int  pcre_fullinfo(const pcre *, const pcre_extra *, int,
+              void *);
+extern int  pcre_get_named_substring(const pcre *, const char *,
+              int *, int,  const char *, const char **);
+extern int  pcre_get_stringnumber(const pcre *, const char *);
+extern int  pcre_get_substring(const char *, int *, int, int,
+              const char **);
+extern int  pcre_get_substring_list(const char *, int *, int,
+              const char ***);
+extern int  pcre_info(const pcre *, int *, int *);
+extern const unsigned char *pcre_maketables(void);
+extern pcre_extra *pcre_study(const pcre *, int, const char **);
+extern const char *pcre_version(void);
+
+#ifdef __cplusplus
+}  /* extern "C" */
+#endif
+
+#endif /* End of pcre.h */

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/pcre.in
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/pcre.in	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/pcre.in	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,239 @@
+/*************************************************
+*       Perl-Compatible Regular Expressions      *
+*************************************************/
+
+/* In its original form, this is the .in file that is transformed by
+"configure" into pcre.h.
+
+           Copyright (c) 1997-2004 University of Cambridge
+
+-----------------------------------------------------------------------------
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice,
+      this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+
+    * Neither the name of the University of Cambridge nor the names of its
+      contributors may be used to endorse or promote products derived from
+      this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+-----------------------------------------------------------------------------
+*/
+
+#ifndef _PCRE_H
+#define _PCRE_H
+
+/* The file pcre.h is build by "configure". Do not edit it; instead
+make changes to pcre.in. */
+
+#define PCRE_MAJOR          @PCRE_MAJOR@
+#define PCRE_MINOR          @PCRE_MINOR@
+#define PCRE_DATE           @PCRE_DATE@
+
+/* Win32 uses DLL by default */
+
+#ifdef _WIN32
+#  ifdef PCRE_DEFINITION
+#    ifdef DLL_EXPORT
+#      define PCRE_DATA_SCOPE __declspec(dllexport)
+#    endif
+#  else
+#    ifndef PCRE_STATIC
+#      define PCRE_DATA_SCOPE extern __declspec(dllimport)
+#    endif
+#  endif
+#endif
+#ifndef PCRE_DATA_SCOPE
+#  define PCRE_DATA_SCOPE     extern
+#endif
+
+/* Have to include stdlib.h in order to ensure that size_t is defined;
+it is needed here for malloc. */
+
+#include <stdlib.h>
+
+/* Allow for C++ users */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Options */
+
+#define PCRE_CASELESS           0x0001
+#define PCRE_MULTILINE          0x0002
+#define PCRE_DOTALL             0x0004
+#define PCRE_EXTENDED           0x0008
+#define PCRE_ANCHORED           0x0010
+#define PCRE_DOLLAR_ENDONLY     0x0020
+#define PCRE_EXTRA              0x0040
+#define PCRE_NOTBOL             0x0080
+#define PCRE_NOTEOL             0x0100
+#define PCRE_UNGREEDY           0x0200
+#define PCRE_NOTEMPTY           0x0400
+#define PCRE_UTF8               0x0800
+#define PCRE_NO_AUTO_CAPTURE    0x1000
+#define PCRE_NO_UTF8_CHECK      0x2000
+#define PCRE_AUTO_CALLOUT       0x4000
+#define PCRE_PARTIAL            0x8000
+
+/* Exec-time and get/set-time error codes */
+
+#define PCRE_ERROR_NOMATCH         (-1)
+#define PCRE_ERROR_NULL            (-2)
+#define PCRE_ERROR_BADOPTION       (-3)
+#define PCRE_ERROR_BADMAGIC        (-4)
+#define PCRE_ERROR_UNKNOWN_NODE    (-5)
+#define PCRE_ERROR_NOMEMORY        (-6)
+#define PCRE_ERROR_NOSUBSTRING     (-7)
+#define PCRE_ERROR_MATCHLIMIT      (-8)
+#define PCRE_ERROR_CALLOUT         (-9)  /* Never used by PCRE itself */
+#define PCRE_ERROR_BADUTF8        (-10)
+#define PCRE_ERROR_BADUTF8_OFFSET (-11)
+#define PCRE_ERROR_PARTIAL        (-12)
+#define PCRE_ERROR_BADPARTIAL     (-13)
+#define PCRE_ERROR_INTERNAL       (-14)
+#define PCRE_ERROR_BADCOUNT       (-15)
+
+/* Request types for pcre_fullinfo() */
+
+#define PCRE_INFO_OPTIONS            0
+#define PCRE_INFO_SIZE               1
+#define PCRE_INFO_CAPTURECOUNT       2
+#define PCRE_INFO_BACKREFMAX         3
+#define PCRE_INFO_FIRSTBYTE          4
+#define PCRE_INFO_FIRSTCHAR          4  /* For backwards compatibility */
+#define PCRE_INFO_FIRSTTABLE         5
+#define PCRE_INFO_LASTLITERAL        6
+#define PCRE_INFO_NAMEENTRYSIZE      7
+#define PCRE_INFO_NAMECOUNT          8
+#define PCRE_INFO_NAMETABLE          9
+#define PCRE_INFO_STUDYSIZE         10
+#define PCRE_INFO_DEFAULT_TABLES    11
+
+/* Request types for pcre_config() */
+
+#define PCRE_CONFIG_UTF8                    0
+#define PCRE_CONFIG_NEWLINE                 1
+#define PCRE_CONFIG_LINK_SIZE               2
+#define PCRE_CONFIG_POSIX_MALLOC_THRESHOLD  3
+#define PCRE_CONFIG_MATCH_LIMIT             4
+#define PCRE_CONFIG_STACKRECURSE            5
+#define PCRE_CONFIG_UNICODE_PROPERTIES      6
+
+/* Bit flags for the pcre_extra structure */
+
+#define PCRE_EXTRA_STUDY_DATA          0x0001
+#define PCRE_EXTRA_MATCH_LIMIT         0x0002
+#define PCRE_EXTRA_CALLOUT_DATA        0x0004
+#define PCRE_EXTRA_TABLES              0x0008
+
+/* Types */
+
+struct real_pcre;                 /* declaration; the definition is private  */
+typedef struct real_pcre pcre;
+
+/* The structure for passing additional data to pcre_exec(). This is defined in
+such as way as to be extensible. Always add new fields at the end, in order to
+remain compatible. */
+
+typedef struct pcre_extra {
+  unsigned long int flags;        /* Bits for which fields are set */
+  void *study_data;               /* Opaque data from pcre_study() */
+  unsigned long int match_limit;  /* Maximum number of calls to match() */
+  void *callout_data;             /* Data passed back in callouts */
+  const unsigned char *tables;    /* Pointer to character tables */
+} pcre_extra;
+
+/* The structure for passing out data via the pcre_callout_function. We use a
+structure so that new fields can be added on the end in future versions,
+without changing the API of the function, thereby allowing old clients to work
+without modification. */
+
+typedef struct pcre_callout_block {
+  int          version;           /* Identifies version of block */
+  /* ------------------------ Version 0 ------------------------------- */
+  int          callout_number;    /* Number compiled into pattern */
+  int         *offset_vector;     /* The offset vector */
+  const char  *subject;           /* The subject being matched */
+  int          subject_length;    /* The length of the subject */
+  int          start_match;       /* Offset to start of this match attempt */
+  int          current_position;  /* Where we currently are in the subject */
+  int          capture_top;       /* Max current capture */
+  int          capture_last;      /* Most recently closed capture */
+  void        *callout_data;      /* Data passed in with the call */
+  /* ------------------- Added for Version 1 -------------------------- */
+  int          pattern_position;  /* Offset to next item in the pattern */
+  int          next_item_length;  /* Length of next item in the pattern */
+  /* ------------------------------------------------------------------ */
+} pcre_callout_block;
+
+/* Indirection for store get and free functions. These can be set to
+alternative malloc/free functions if required. Special ones are used in the
+non-recursive case for "frames". There is also an optional callout function
+that is triggered by the (?) regex item. Some magic is required for Win32 DLL;
+it is null on other OS. For Virtual Pascal, these have to be different again.
+*/
+
+#ifndef VPCOMPAT
+PCRE_DATA_SCOPE void *(*pcre_malloc)(size_t);
+PCRE_DATA_SCOPE void  (*pcre_free)(void *);
+PCRE_DATA_SCOPE void *(*pcre_stack_malloc)(size_t);
+PCRE_DATA_SCOPE void  (*pcre_stack_free)(void *);
+PCRE_DATA_SCOPE int   (*pcre_callout)(pcre_callout_block *);
+#else   /* VPCOMPAT */
+extern void *pcre_malloc(size_t);
+extern void  pcre_free(void *);
+extern void *pcre_stack_malloc(size_t);
+extern void  pcre_stack_free(void *);
+extern int   pcre_callout(pcre_callout_block *);
+#endif  /* VPCOMPAT */
+
+/* Exported PCRE functions */
+
+extern pcre *pcre_compile(const char *, int, const char **,
+              int *, const unsigned char *);
+extern int  pcre_config(int, void *);
+extern int  pcre_copy_named_substring(const pcre *, const char *,
+              int *, int, const char *, char *, int);
+extern int  pcre_copy_substring(const char *, int *, int, int,
+              char *, int);
+extern int  pcre_exec(const pcre *, const pcre_extra *,
+              const char *, int, int, int, int *, int);
+extern void pcre_free_substring(const char *);
+extern void pcre_free_substring_list(const char **);
+extern int  pcre_fullinfo(const pcre *, const pcre_extra *, int,
+              void *);
+extern int  pcre_get_named_substring(const pcre *, const char *,
+              int *, int,  const char *, const char **);
+extern int  pcre_get_stringnumber(const pcre *, const char *);
+extern int  pcre_get_substring(const char *, int *, int, int,
+              const char **);
+extern int  pcre_get_substring_list(const char *, int *, int,
+              const char ***);
+extern int  pcre_info(const pcre *, int *, int *);
+extern const unsigned char *pcre_maketables(void);
+extern pcre_extra *pcre_study(const pcre *, int, const char **);
+extern const char *pcre_version(void);
+
+#ifdef __cplusplus
+}  /* extern "C" */
+#endif
+
+#endif /* End of pcre.h */

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/pcredemo.c
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/pcredemo.c	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/pcredemo.c	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,324 @@
+/*************************************************
+*           PCRE DEMONSTRATION PROGRAM           *
+*************************************************/
+
+/* This is a demonstration program to illustrate the most straightforward ways
+of calling the PCRE regular expression library from a C program. See the
+pcresample documentation for a short discussion.
+
+Compile thuswise:
+  gcc -Wall pcredemo.c -I/usr/local/include -L/usr/local/lib \
+    -R/usr/local/lib -lpcre
+
+Replace "/usr/local/include" and "/usr/local/lib" with wherever the include and
+library files for PCRE are installed on your system. Only some operating
+systems (e.g. Solaris) use the -R option.
+*/
+
+
+#include <stdio.h>
+#include <string.h>
+#include <pcre.h>
+
+#define OVECCOUNT 30    /* should be a multiple of 3 */
+
+
+int main(int argc, char **argv)
+{
+pcre *re;
+const char *error;
+char *pattern;
+char *subject;
+unsigned char *name_table;
+int erroffset;
+int find_all;
+int namecount;
+int name_entry_size;
+int ovector[OVECCOUNT];
+int subject_length;
+int rc, i;
+
+
+/**************************************************************************
+* First, sort out the command line. There is only one possible option at  *
+* the moment, "-g" to request repeated matching to find all occurrences,  *
+* like Perl's /g option. We set the variable find_all to a non-zero value *
+* if the -g option is present. Apart from that, there must be exactly two *
+* arguments.                                                              *
+**************************************************************************/
+
+find_all = 0;
+for (i = 1; i < argc; i++)
+  {
+  if (strcmp(argv[i], "-g") == 0) find_all = 1;
+    else break;
+  }
+
+/* After the options, we require exactly two arguments, which are the pattern,
+and the subject string. */
+
+if (argc - i != 2)
+  {
+  printf("Two arguments required: a regex and a subject string\n");
+  return 1;
+  }
+
+pattern = argv[i];
+subject = argv[i+1];
+subject_length = (int)strlen(subject);
+
+
+/*************************************************************************
+* Now we are going to compile the regular expression pattern, and handle *
+* and errors that are detected.                                          *
+*************************************************************************/
+
+re = pcre_compile(
+  pattern,              /* the pattern */
+  0,                    /* default options */
+  &error,               /* for error message */
+  &erroffset,           /* for error offset */
+  NULL);                /* use default character tables */
+
+/* Compilation failed: print the error message and exit */
+
+if (re == NULL)
+  {
+  printf("PCRE compilation failed at offset %d: %s\n", erroffset, error);
+  return 1;
+  }
+
+
+/*************************************************************************
+* If the compilation succeeded, we call PCRE again, in order to do a     *
+* pattern match against the subject string. This does just ONE match. If *
+* further matching is needed, it will be done below.                     *
+*************************************************************************/
+
+rc = pcre_exec(
+  re,                   /* the compiled pattern */
+  NULL,                 /* no extra data - we didn't study the pattern */
+  subject,              /* the subject string */
+  subject_length,       /* the length of the subject */
+  0,                    /* start at offset 0 in the subject */
+  0,                    /* default options */
+  ovector,              /* output vector for substring information */
+  OVECCOUNT);           /* number of elements in the output vector */
+
+/* Matching failed: handle error cases */
+
+if (rc < 0)
+  {
+  switch(rc)
+    {
+    case PCRE_ERROR_NOMATCH: printf("No match\n"); break;
+    /*
+    Handle other special cases if you like
+    */
+    default: printf("Matching error %d\n", rc); break;
+    }
+  free(re);     /* Release memory used for the compiled pattern */
+  return 1;
+  }
+
+/* Match succeded */
+
+printf("\nMatch succeeded at offset %d\n", ovector[0]);
+
+
+/*************************************************************************
+* We have found the first match within the subject string. If the output *
+* vector wasn't big enough, set its size to the maximum. Then output any *
+* substrings that were captured.                                         *
+*************************************************************************/
+
+/* The output vector wasn't big enough */
+
+if (rc == 0)
+  {
+  rc = OVECCOUNT/3;
+  printf("ovector only has room for %d captured substrings\n", rc - 1);
+  }
+
+/* Show substrings stored in the output vector by number. Obviously, in a real
+application you might want to do things other than print them. */
+
+for (i = 0; i < rc; i++)
+  {
+  char *substring_start = subject + ovector[2*i];
+  int substring_length = ovector[2*i+1] - ovector[2*i];
+  printf("%2d: %.*s\n", i, substring_length, substring_start);
+  }
+
+
+/**************************************************************************
+* That concludes the basic part of this demonstration program. We have    *
+* compiled a pattern, and performed a single match. The code that follows *
+* first shows how to access named substrings, and then how to code for    *
+* repeated matches on the same subject.                                   *
+**************************************************************************/
+
+/* See if there are any named substrings, and if so, show them by name. First
+we have to extract the count of named parentheses from the pattern. */
+
+(void)pcre_fullinfo(
+  re,                   /* the compiled pattern */
+  NULL,                 /* no extra data - we didn't study the pattern */
+  PCRE_INFO_NAMECOUNT,  /* number of named substrings */
+  &namecount);          /* where to put the answer */
+
+if (namecount <= 0) printf("No named substrings\n"); else
+  {
+  unsigned char *tabptr;
+  printf("Named substrings\n");
+
+  /* Before we can access the substrings, we must extract the table for
+  translating names to numbers, and the size of each entry in the table. */
+
+  (void)pcre_fullinfo(
+    re,                       /* the compiled pattern */
+    NULL,                     /* no extra data - we didn't study the pattern */
+    PCRE_INFO_NAMETABLE,      /* address of the table */
+    &name_table);             /* where to put the answer */
+
+  (void)pcre_fullinfo(
+    re,                       /* the compiled pattern */
+    NULL,                     /* no extra data - we didn't study the pattern */
+    PCRE_INFO_NAMEENTRYSIZE,  /* size of each entry in the table */
+    &name_entry_size);        /* where to put the answer */
+
+  /* Now we can scan the table and, for each entry, print the number, the name,
+  and the substring itself. */
+
+  tabptr = name_table;
+  for (i = 0; i < namecount; i++)
+    {
+    int n = (tabptr[0] << 8) | tabptr[1];
+    printf("(%d) %*s: %.*s\n", n, name_entry_size - 3, tabptr + 2,
+      ovector[2*n+1] - ovector[2*n], subject + ovector[2*n]);
+    tabptr += name_entry_size;
+    }
+  }
+
+
+/*************************************************************************
+* If the "-g" option was given on the command line, we want to continue  *
+* to search for additional matches in the subject string, in a similar   *
+* way to the /g option in Perl. This turns out to be trickier than you   *
+* might think because of the possibility of matching an empty string.    *
+* What happens is as follows:                                            *
+*                                                                        *
+* If the previous match was NOT for an empty string, we can just start   *
+* the next match at the end of the previous one.                         *
+*                                                                        *
+* If the previous match WAS for an empty string, we can't do that, as it *
+* would lead to an infinite loop. Instead, a special call of pcre_exec() *
+* is made with the PCRE_NOTEMPTY and PCRE_ANCHORED flags set. The first  *
+* of these tells PCRE that an empty string is not a valid match; other   *
+* possibilities must be tried. The second flag restricts PCRE to one     *
+* match attempt at the initial string position. If this match succeeds,  *
+* an alternative to the empty string match has been found, and we can    *
+* proceed round the loop.                                                *
+*************************************************************************/
+
+if (!find_all)
+  {
+  free(re);   /* Release the memory used for the compiled pattern */
+  return 0;   /* Finish unless -g was given */
+  }
+
+/* Loop for second and subsequent matches */
+
+for (;;)
+  {
+  int options = 0;                 /* Normally no options */
+  int start_offset = ovector[1];   /* Start at end of previous match */
+
+  /* If the previous match was for an empty string, we are finished if we are
+  at the end of the subject. Otherwise, arrange to run another match at the
+  same point to see if a non-empty match can be found. */
+
+  if (ovector[0] == ovector[1])
+    {
+    if (ovector[0] == subject_length) break;
+    options = PCRE_NOTEMPTY | PCRE_ANCHORED;
+    }
+
+  /* Run the next matching operation */
+
+  rc = pcre_exec(
+    re,                   /* the compiled pattern */
+    NULL,                 /* no extra data - we didn't study the pattern */
+    subject,              /* the subject string */
+    subject_length,       /* the length of the subject */
+    start_offset,         /* starting offset in the subject */
+    options,              /* options */
+    ovector,              /* output vector for substring information */
+    OVECCOUNT);           /* number of elements in the output vector */
+
+  /* This time, a result of NOMATCH isn't an error. If the value in "options"
+  is zero, it just means we have found all possible matches, so the loop ends.
+  Otherwise, it means we have failed to find a non-empty-string match at a
+  point where there was a previous empty-string match. In this case, we do what
+  Perl does: advance the matching position by one, and continue. We do this by
+  setting the "end of previous match" offset, because that is picked up at the
+  top of the loop as the point at which to start again. */
+
+  if (rc == PCRE_ERROR_NOMATCH)
+    {
+    if (options == 0) break;
+    ovector[1] = start_offset + 1;
+    continue;    /* Go round the loop again */
+    }
+
+  /* Other matching errors are not recoverable. */
+
+  if (rc < 0)
+    {
+    printf("Matching error %d\n", rc);
+    free(re);    /* Release memory used for the compiled pattern */
+    return 1;
+    }
+
+  /* Match succeded */
+
+  printf("\nMatch succeeded again at offset %d\n", ovector[0]);
+
+  /* The match succeeded, but the output vector wasn't big enough. */
+
+  if (rc == 0)
+    {
+    rc = OVECCOUNT/3;
+    printf("ovector only has room for %d captured substrings\n", rc - 1);
+    }
+
+  /* As before, show substrings stored in the output vector by number, and then
+  also any named substrings. */
+
+  for (i = 0; i < rc; i++)
+    {
+    char *substring_start = subject + ovector[2*i];
+    int substring_length = ovector[2*i+1] - ovector[2*i];
+    printf("%2d: %.*s\n", i, substring_length, substring_start);
+    }
+
+  if (namecount <= 0) printf("No named substrings\n"); else
+    {
+    unsigned char *tabptr = name_table;
+    printf("Named substrings\n");
+    for (i = 0; i < namecount; i++)
+      {
+      int n = (tabptr[0] << 8) | tabptr[1];
+      printf("(%d) %*s: %.*s\n", n, name_entry_size - 3, tabptr + 2,
+        ovector[2*n+1] - ovector[2*n], subject + ovector[2*n]);
+      tabptr += name_entry_size;
+      }
+    }
+  }      /* End of loop to find second and subsequent matches */
+
+printf("\n");
+free(re);       /* Release memory used for the compiled pattern */
+return 0;
+}
+
+/* End of pcredemo.c */

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/pcregrep.c
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/pcregrep.c	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/pcregrep.c	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,673 @@
+/*************************************************
+*               pcregrep program                 *
+*************************************************/
+
+/* This is a grep program that uses the PCRE regular expression library to do
+its pattern matching. On a Unix or Win32 system it can recurse into
+directories.
+
+           Copyright (c) 1997-2004 University of Cambridge
+
+-----------------------------------------------------------------------------
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice,
+      this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+
+    * Neither the name of the University of Cambridge nor the names of its
+      contributors may be used to endorse or promote products derived from
+      this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+-----------------------------------------------------------------------------
+*/
+
+#include <ctype.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include "config.h"
+#include "pcre.h"
+
+#define FALSE 0
+#define TRUE 1
+
+typedef int BOOL;
+
+#define VERSION "3.0 14-Jan-2003"
+#define MAX_PATTERN_COUNT 100
+
+
+/*************************************************
+*               Global variables                 *
+*************************************************/
+
+static char *pattern_filename = NULL;
+static int  pattern_count = 0;
+static pcre **pattern_list;
+static pcre_extra **hints_list;
+
+static BOOL count_only = FALSE;
+static BOOL filenames = TRUE;
+static BOOL filenames_only = FALSE;
+static BOOL invert = FALSE;
+static BOOL number = FALSE;
+static BOOL recurse = FALSE;
+static BOOL silent = FALSE;
+static BOOL whole_lines = FALSE;
+
+/* Structure for options and list of them */
+
+typedef struct option_item {
+  int one_char;
+  const char *long_name;
+  const char *help_text;
+} option_item;
+
+static option_item optionlist[] = {
+  { -1,  "help",         "display this help and exit" },
+  { 'c', "count",        "print only a count of matching lines per FILE" },
+  { 'h', "no-filename",  "suppress the prefixing filename on output" },
+  { 'i', "ignore-case",  "ignore case distinctions" },
+  { 'l', "files-with-matches", "print only FILE names containing matches" },
+  { 'n', "line-number",  "print line number with output lines" },
+  { 'r', "recursive",    "recursively scan sub-directories" },
+  { 's', "no-messages",  "suppress error messages" },
+  { 'u', "utf-8",        "use UTF-8 mode" },
+  { 'V', "version",      "print version information and exit" },
+  { 'v', "invert-match", "select non-matching lines" },
+  { 'x', "line-regex",   "force PATTERN to match only whole lines" },
+  { 'x', "line-regexp",  "force PATTERN to match only whole lines" },
+  { 0,    NULL,           NULL }
+};
+
+
+/*************************************************
+*       Functions for directory scanning         *
+*************************************************/
+
+/* These functions are defined so that they can be made system specific,
+although at present the only ones are for Unix, Win32, and for "no directory
+recursion support". */
+
+
+/************* Directory scanning in Unix ***********/
+
+#if IS_UNIX
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <dirent.h>
+
+typedef DIR directory_type;
+
+static int
+isdirectory(char *filename)
+{
+struct stat statbuf;
+if (stat(filename, &statbuf) < 0)
+  return 0;        /* In the expectation that opening as a file will fail */
+return ((statbuf.st_mode & S_IFMT) == S_IFDIR)? '/' : 0;
+}
+
+static directory_type *
+opendirectory(char *filename)
+{
+return opendir(filename);
+}
+
+static char *
+readdirectory(directory_type *dir)
+{
+for (;;)
+  {
+  struct dirent *dent = readdir(dir);
+  if (dent == NULL) return NULL;
+  if (strcmp(dent->d_name, ".") != 0 && strcmp(dent->d_name, "..") != 0)
+    return dent->d_name;
+  }
+return NULL;   /* Keep compiler happy; never executed */
+}
+
+static void
+closedirectory(directory_type *dir)
+{
+closedir(dir);
+}
+
+
+/************* Directory scanning in Win32 ***********/
+
+/* I (Philip Hazel) have no means of testing this code. It was contributed by
+Lionel Fourquaux. */
+
+
+#elif HAVE_WIN32API
+
+#ifndef STRICT
+# define STRICT
+#endif
+#ifndef WIN32_LEAN_AND_MEAN
+# define WIN32_LEAN_AND_MEAN
+#endif
+#include <windows.h>
+
+typedef struct directory_type
+{
+HANDLE handle;
+BOOL first;
+WIN32_FIND_DATA data;
+} directory_type;
+
+int
+isdirectory(char *filename)
+{
+DWORD attr = GetFileAttributes(filename);
+if (attr == INVALID_FILE_ATTRIBUTES)
+  return 0;
+return ((attr & FILE_ATTRIBUTE_DIRECTORY) != 0) ? '/' : 0;
+}
+
+directory_type *
+opendirectory(char *filename)
+{
+size_t len;
+char *pattern;
+directory_type *dir;
+DWORD err;
+len = strlen(filename);
+pattern = (char *) malloc(len + 3);
+dir = (directory_type *) malloc(sizeof(*dir));
+if ((pattern == NULL) || (dir == NULL))
+  {
+  fprintf(stderr, "pcregrep: malloc failed\n");
+  exit(2);
+  }
+memcpy(pattern, filename, len);
+memcpy(&(pattern[len]), "\\*", 3);
+dir->handle = FindFirstFile(pattern, &(dir->data));
+if (dir->handle != INVALID_HANDLE_VALUE)
+  {
+  free(pattern);
+  dir->first = TRUE;
+  return dir;
+  }
+err = GetLastError();
+free(pattern);
+free(dir);
+errno = (err == ERROR_ACCESS_DENIED) ? EACCES : ENOENT;
+return NULL;
+}
+
+char *
+readdirectory(directory_type *dir)
+{
+for (;;)
+  {
+  if (!dir->first)
+    {
+    if (!FindNextFile(dir->handle, &(dir->data)))
+      return NULL;
+    }
+  else
+    {
+    dir->first = FALSE;
+    }
+  if (strcmp(dir->data.cFileName, ".") != 0 && strcmp(dir->data.cFileName, "..") != 0)
+    return dir->data.cFileName;
+  }
+#ifndef _MSC_VER
+return NULL;   /* Keep compiler happy; never executed */
+#endif
+}
+
+void
+closedirectory(directory_type *dir)
+{
+FindClose(dir->handle);
+free(dir);
+}
+
+
+/************* Directory scanning when we can't do it ***********/
+
+/* The type is void, and apart from isdirectory(), the functions do nothing. */
+
+#else
+
+typedef void directory_type;
+
+int isdirectory(char *filename) { return FALSE; }
+directory_type * opendirectory(char *filename) {}
+char *readdirectory(directory_type *dir) {}
+void closedirectory(directory_type *dir) {}
+
+#endif
+
+
+
+#if ! HAVE_STRERROR
+/*************************************************
+*     Provide strerror() for non-ANSI libraries  *
+*************************************************/
+
+/* Some old-fashioned systems still around (e.g. SunOS4) don't have strerror()
+in their libraries, but can provide the same facility by this simple
+alternative function. */
+
+extern int   sys_nerr;
+extern char *sys_errlist[];
+
+char *
+strerror(int n)
+{
+if (n < 0 || n >= sys_nerr) return "unknown error number";
+return sys_errlist[n];
+}
+#endif /* HAVE_STRERROR */
+
+
+
+/*************************************************
+*              Grep an individual file           *
+*************************************************/
+
+static int
+pcregrep(FILE *in, char *name)
+{
+int rc = 1;
+int linenumber = 0;
+int count = 0;
+int offsets[99];
+char buffer[BUFSIZ];
+
+while (fgets(buffer, sizeof(buffer), in) != NULL)
+  {
+  BOOL match = FALSE;
+  int i;
+  int length = (int)strlen(buffer);
+  if (length > 0 && buffer[length-1] == '\n') buffer[--length] = 0;
+  linenumber++;
+
+  for (i = 0; !match && i < pattern_count; i++)
+    {
+    match = pcre_exec(pattern_list[i], hints_list[i], buffer, length, 0, 0,
+      offsets, 99) >= 0;
+    if (match && whole_lines && offsets[1] != length) match = FALSE;
+    }
+
+  if (match != invert)
+    {
+    if (count_only) count++;
+
+    else if (filenames_only)
+      {
+      fprintf(stdout, "%s\n", (name == NULL)? "<stdin>" : name);
+      return 0;
+      }
+
+    else if (silent) return 0;
+
+    else
+      {
+      if (name != NULL) fprintf(stdout, "%s:", name);
+      if (number) fprintf(stdout, "%d:", linenumber);
+      fprintf(stdout, "%s\n", buffer);
+      }
+
+    rc = 0;
+    }
+  }
+
+if (count_only)
+  {
+  if (name != NULL) fprintf(stdout, "%s:", name);
+  fprintf(stdout, "%d\n", count);
+  }
+
+return rc;
+}
+
+
+
+
+/*************************************************
+*     Grep a file or recurse into a directory    *
+*************************************************/
+
+static int
+grep_or_recurse(char *filename, BOOL dir_recurse, BOOL show_filenames,
+  BOOL only_one_at_top)
+{
+int rc = 1;
+int sep;
+FILE *in;
+
+/* If the file is a directory and we are recursing, scan each file within it.
+The scanning code is localized so it can be made system-specific. */
+
+if ((sep = isdirectory(filename)) != 0 && dir_recurse)
+  {
+  char buffer[1024];
+  char *nextfile;
+  directory_type *dir = opendirectory(filename);
+
+  if (dir == NULL)
+    {
+    fprintf(stderr, "pcregrep: Failed to open directory %s: %s\n", filename,
+      strerror(errno));
+    return 2;
+    }
+
+  while ((nextfile = readdirectory(dir)) != NULL)
+    {
+    int frc;
+    sprintf(buffer, "%.512s%c%.128s", filename, sep, nextfile);
+    frc = grep_or_recurse(buffer, dir_recurse, TRUE, FALSE);
+    if (frc == 0 && rc == 1) rc = 0;
+    }
+
+  closedirectory(dir);
+  return rc;
+  }
+
+/* If the file is not a directory, or we are not recursing, scan it. If this is
+the first and only argument at top level, we don't show the file name (unless
+we are only showing the file name). Otherwise, control is via the
+show_filenames variable. */
+
+in = fopen(filename, "r");
+if (in == NULL)
+  {
+  fprintf(stderr, "pcregrep: Failed to open %s: %s\n", filename, strerror(errno));
+  return 2;
+  }
+
+rc = pcregrep(in, (filenames_only || (show_filenames && !only_one_at_top))?
+  filename : NULL);
+fclose(in);
+return rc;
+}
+
+
+
+
+/*************************************************
+*                Usage function                  *
+*************************************************/
+
+static int
+usage(int rc)
+{
+fprintf(stderr, "Usage: pcregrep [-Vcfhilnrsvx] [long-options] [pattern] [file1 file2 ...]\n");
+fprintf(stderr, "Type `pcregrep --help' for more information.\n");
+return rc;
+}
+
+
+
+
+/*************************************************
+*                Help function                   *
+*************************************************/
+
+static void
+help(void)
+{
+option_item *op;
+
+printf("Usage: pcregrep [OPTION]... [PATTERN] [FILE1 FILE2 ...]\n");
+printf("Search for PATTERN in each FILE or standard input.\n");
+printf("PATTERN must be present if -f is not used.\n");
+printf("Example: pcregrep -i 'hello.*world' menu.h main.c\n\n");
+
+printf("Options:\n");
+
+for (op = optionlist; op->one_char != 0; op++)
+  {
+  int n;
+  char s[4];
+  if (op->one_char > 0) sprintf(s, "-%c,", op->one_char); else strcpy(s, "   ");
+  printf("  %s --%s%n", s, op->long_name, &n);
+  n = 30 - n;
+  if (n < 1) n = 1;
+  printf("%.*s%s\n", n, "                    ", op->help_text);
+  }
+
+printf("\n  -f<filename>  or  --file=<filename>\n");
+printf("    Read patterns from <filename> instead of using a command line option.\n");
+printf("    Trailing white space is removed; blanks lines are ignored.\n");
+printf("    There is a maximum of %d patterns.\n", MAX_PATTERN_COUNT);
+
+printf("\nWith no FILE, read standard input. If fewer than two FILEs given, assume -h.\n");
+printf("Exit status is 0 if any matches, 1 if no matches, and 2 if trouble.\n");
+}
+
+
+
+
+/*************************************************
+*                Handle an option                *
+*************************************************/
+
+static int
+handle_option(int letter, int options)
+{
+switch(letter)
+  {
+  case -1:  help(); exit(0);
+  case 'c': count_only = TRUE; break;
+  case 'h': filenames = FALSE; break;
+  case 'i': options |= PCRE_CASELESS; break;
+  case 'l': filenames_only = TRUE;
+  case 'n': number = TRUE; break;
+  case 'r': recurse = TRUE; break;
+  case 's': silent = TRUE; break;
+  case 'u': options |= PCRE_UTF8; break;
+  case 'v': invert = TRUE; break;
+  case 'x': whole_lines = TRUE; options |= PCRE_ANCHORED; break;
+
+  case 'V':
+  fprintf(stderr, "pcregrep version %s using ", VERSION);
+  fprintf(stderr, "PCRE version %s\n", pcre_version());
+  exit(0);
+  break;
+
+  default:
+  fprintf(stderr, "pcregrep: Unknown option -%c\n", letter);
+  exit(usage(2));
+  }
+
+return options;
+}
+
+
+
+
+/*************************************************
+*                Main program                    *
+*************************************************/
+
+int
+main(int argc, char **argv)
+{
+int i, j;
+int rc = 1;
+int options = 0;
+int errptr;
+const char *error;
+BOOL only_one_at_top;
+
+/* Process the options */
+
+for (i = 1; i < argc; i++)
+  {
+  if (argv[i][0] != '-') break;
+
+  /* Missing options */
+
+  if (argv[i][1] == 0) exit(usage(2));
+
+  /* Long name options */
+
+  if (argv[i][1] == '-')
+    {
+    option_item *op;
+
+    if (strncmp(argv[i]+2, "file=", 5) == 0)
+      {
+      pattern_filename = argv[i] + 7;
+      continue;
+      }
+
+    for (op = optionlist; op->one_char != 0; op++)
+      {
+      if (strcmp(argv[i]+2, op->long_name) == 0)
+        {
+        options = handle_option(op->one_char, options);
+        break;
+        }
+      }
+    if (op->one_char == 0)
+      {
+      fprintf(stderr, "pcregrep: Unknown option %s\n", argv[i]);
+      exit(usage(2));
+      }
+    }
+
+  /* One-char options */
+
+  else
+    {
+    char *s = argv[i] + 1;
+    while (*s != 0)
+      {
+      if (*s == 'f')
+        {
+        pattern_filename = s + 1;
+        if (pattern_filename[0] == 0)
+          {
+          if (i >= argc - 1)
+            {
+            fprintf(stderr, "pcregrep: File name missing after -f\n");
+            exit(usage(2));
+            }
+          pattern_filename = argv[++i];
+          }
+        break;
+        }
+      else options = handle_option(*s++, options);
+      }
+    }
+  }
+
+pattern_list = (pcre **)malloc(MAX_PATTERN_COUNT * sizeof(pcre *));
+hints_list = (pcre_extra **)malloc(MAX_PATTERN_COUNT * sizeof(pcre_extra *));
+
+if (pattern_list == NULL || hints_list == NULL)
+  {
+  fprintf(stderr, "pcregrep: malloc failed\n");
+  return 2;
+  }
+
+/* Compile the regular expression(s). */
+
+if (pattern_filename != NULL)
+  {
+  FILE *f = fopen(pattern_filename, "r");
+  char buffer[BUFSIZ];
+  if (f == NULL)
+    {
+    fprintf(stderr, "pcregrep: Failed to open %s: %s\n", pattern_filename,
+      strerror(errno));
+    return 2;
+    }
+  while (fgets(buffer, sizeof(buffer), f) != NULL)
+    {
+    char *s = buffer + (int)strlen(buffer);
+    if (pattern_count >= MAX_PATTERN_COUNT)
+      {
+      fprintf(stderr, "pcregrep: Too many patterns in file (max %d)\n",
+        MAX_PATTERN_COUNT);
+      return 2;
+      }
+    while (s > buffer && isspace((unsigned char)(s[-1]))) s--;
+    if (s == buffer) continue;
+    *s = 0;
+    pattern_list[pattern_count] = pcre_compile(buffer, options, &error,
+      &errptr, NULL);
+    if (pattern_list[pattern_count++] == NULL)
+      {
+      fprintf(stderr, "pcregrep: Error in regex number %d at offset %d: %s\n",
+        pattern_count, errptr, error);
+      return 2;
+      }
+    }
+  fclose(f);
+  }
+
+/* If no file name, a single regex must be given inline */
+
+else
+  {
+  if (i >= argc) return usage(2);
+  pattern_list[0] = pcre_compile(argv[i++], options, &error, &errptr, NULL);
+  if (pattern_list[0] == NULL)
+    {
+    fprintf(stderr, "pcregrep: Error in regex at offset %d: %s\n", errptr,
+      error);
+    return 2;
+    }
+  pattern_count++;
+  }
+
+/* Study the regular expressions, as we will be running them may times */
+
+for (j = 0; j < pattern_count; j++)
+  {
+  hints_list[j] = pcre_study(pattern_list[j], 0, &error);
+  if (error != NULL)
+    {
+    char s[16];
+    if (pattern_count == 1) s[0] = 0; else sprintf(s, " number %d", j);
+    fprintf(stderr, "pcregrep: Error while studying regex%s: %s\n", s, error);
+    return 2;
+    }
+  }
+
+/* If there are no further arguments, do the business on stdin and exit */
+
+if (i >= argc) return pcregrep(stdin, NULL);
+
+/* Otherwise, work through the remaining arguments as files or directories.
+Pass in the fact that there is only one argument at top level - this suppresses
+the file name if the argument is not a directory. */
+
+only_one_at_top = (i == argc - 1);
+if (filenames_only) filenames = TRUE;
+
+for (; i < argc; i++)
+  {
+  int frc = grep_or_recurse(argv[i], recurse, filenames, only_one_at_top);
+  if (frc == 0 && rc == 1) rc = 0;
+  }
+
+return rc;
+}
+
+/* End */

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/pcreposix.c
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/pcreposix.c	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/pcreposix.c	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,316 @@
+/*************************************************
+*      Perl-Compatible Regular Expressions       *
+*************************************************/
+
+/*
+This is a library of functions to support regular expressions whose syntax
+and semantics are as close as possible to those of the Perl 5 language. See
+the file Tech.Notes for some information on the internals.
+
+This module is a wrapper that provides a POSIX API to the underlying PCRE
+functions.
+
+Written by: Philip Hazel <ph10 at cam.ac.uk>
+
+           Copyright (c) 1997-2004 University of Cambridge
+
+-----------------------------------------------------------------------------
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice,
+      this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+
+    * Neither the name of the University of Cambridge nor the names of its
+      contributors may be used to endorse or promote products derived from
+      this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+-----------------------------------------------------------------------------
+*/
+
+#include "internal.h"
+#include "pcreposix.h"
+#include "stdlib.h"
+
+
+
+/* Corresponding tables of PCRE error messages and POSIX error codes. */
+
+static const char *const estring[] = {
+  ERR1,  ERR2,  ERR3,  ERR4,  ERR5,  ERR6,  ERR7,  ERR8,  ERR9,  ERR10,
+  ERR11, ERR12, ERR13, ERR14, ERR15, ERR16, ERR17, ERR18, ERR19, ERR20,
+  ERR21, ERR22, ERR23, ERR24, ERR25, ERR26, ERR27, ERR29, ERR29, ERR30,
+  ERR31, ERR32, ERR33, ERR34, ERR35, ERR36, ERR37, ERR38, ERR39, ERR40,
+  ERR41, ERR42, ERR43, ERR44, ERR45, ERR46, ERR47 };
+
+static const int eint[] = {
+  REG_EESCAPE, /* "\\ at end of pattern" */
+  REG_EESCAPE, /* "\\c at end of pattern" */
+  REG_EESCAPE, /* "unrecognized character follows \\" */
+  REG_BADBR,   /* "numbers out of order in {} quantifier" */
+  REG_BADBR,   /* "number too big in {} quantifier" */
+  REG_EBRACK,  /* "missing terminating ] for character class" */
+  REG_ECTYPE,  /* "invalid escape sequence in character class" */
+  REG_ERANGE,  /* "range out of order in character class" */
+  REG_BADRPT,  /* "nothing to repeat" */
+  REG_BADRPT,  /* "operand of unlimited repeat could match the empty string" */
+  REG_ASSERT,  /* "internal error: unexpected repeat" */
+  REG_BADPAT,  /* "unrecognized character after (?" */
+  REG_BADPAT,  /* "POSIX named classes are supported only within a class" */
+  REG_EPAREN,  /* "missing )" */
+  REG_ESUBREG, /* "reference to non-existent subpattern" */
+  REG_INVARG,  /* "erroffset passed as NULL" */
+  REG_INVARG,  /* "unknown option bit(s) set" */
+  REG_EPAREN,  /* "missing ) after comment" */
+  REG_ESIZE,   /* "parentheses nested too deeply" */
+  REG_ESIZE,   /* "regular expression too large" */
+  REG_ESPACE,  /* "failed to get memory" */
+  REG_EPAREN,  /* "unmatched brackets" */
+  REG_ASSERT,  /* "internal error: code overflow" */
+  REG_BADPAT,  /* "unrecognized character after (?<" */
+  REG_BADPAT,  /* "lookbehind assertion is not fixed length" */
+  REG_BADPAT,  /* "malformed number after (?(" */
+  REG_BADPAT,  /* "conditional group containe more than two branches" */
+  REG_BADPAT,  /* "assertion expected after (?(" */
+  REG_BADPAT,  /* "(?R or (?digits must be followed by )" */
+  REG_ECTYPE,  /* "unknown POSIX class name" */
+  REG_BADPAT,  /* "POSIX collating elements are not supported" */
+  REG_INVARG,  /* "this version of PCRE is not compiled with PCRE_UTF8 support" */
+  REG_BADPAT,  /* "spare error" */
+  REG_BADPAT,  /* "character value in \x{...} sequence is too large" */
+  REG_BADPAT,  /* "invalid condition (?(0)" */
+  REG_BADPAT,  /* "\\C not allowed in lookbehind assertion" */
+  REG_EESCAPE, /* "PCRE does not support \\L, \\l, \\N, \\U, or \\u" */
+  REG_BADPAT,  /* "number after (?C is > 255" */
+  REG_BADPAT,  /* "closing ) for (?C expected" */
+  REG_BADPAT,  /* "recursive call could loop indefinitely" */
+  REG_BADPAT,  /* "unrecognized character after (?P" */
+  REG_BADPAT,  /* "syntax error after (?P" */
+  REG_BADPAT,  /* "two named groups have the same name" */
+  REG_BADPAT,  /* "invalid UTF-8 string" */
+  REG_BADPAT,  /* "support for \\P, \\p, and \\X has not been compiled" */
+  REG_BADPAT,  /* "malformed \\P or \\p sequence" */
+  REG_BADPAT   /* "unknown property name after \\P or \\p" */
+};
+
+/* Table of texts corresponding to POSIX error codes */
+
+static const char *const pstring[] = {
+  "",                                /* Dummy for value 0 */
+  "internal error",                  /* REG_ASSERT */
+  "invalid repeat counts in {}",     /* BADBR      */
+  "pattern error",                   /* BADPAT     */
+  "? * + invalid",                   /* BADRPT     */
+  "unbalanced {}",                   /* EBRACE     */
+  "unbalanced []",                   /* EBRACK     */
+  "collation error - not relevant",  /* ECOLLATE   */
+  "bad class",                       /* ECTYPE     */
+  "bad escape sequence",             /* EESCAPE    */
+  "empty expression",                /* EMPTY      */
+  "unbalanced ()",                   /* EPAREN     */
+  "bad range inside []",             /* ERANGE     */
+  "expression too big",              /* ESIZE      */
+  "failed to get memory",            /* ESPACE     */
+  "bad back reference",              /* ESUBREG    */
+  "bad argument",                    /* INVARG     */
+  "match failed"                     /* NOMATCH    */
+};
+
+
+
+
+/*************************************************
+*          Translate PCRE text code to int       *
+*************************************************/
+
+/* PCRE compile-time errors are given as strings defined as macros. We can just
+look them up in a table to turn them into POSIX-style error codes. */
+
+static int
+pcre_posix_error_code(const char *s)
+{
+size_t i;
+for (i = 0; i < sizeof(estring)/sizeof(char *); i++)
+  if (strcmp(s, estring[i]) == 0) return eint[i];
+return REG_ASSERT;
+}
+
+
+
+/*************************************************
+*          Translate error code to string        *
+*************************************************/
+
+EXPORT size_t
+regerror(int errcode, const regex_t *preg, char *errbuf, size_t errbuf_size)
+{
+const char *message, *addmessage;
+size_t length, addlength;
+
+message = (errcode >= (int)(sizeof(pstring)/sizeof(char *)))?
+  "unknown error code" : pstring[errcode];
+length = strlen(message) + 1;
+
+addmessage = " at offset ";
+addlength = (preg != NULL && (int)preg->re_erroffset != -1)?
+  strlen(addmessage) + 6 : 0;
+
+if (errbuf_size > 0)
+  {
+  if (addlength > 0 && errbuf_size >= length + addlength)
+    sprintf(errbuf, "%s%s%-6d", message, addmessage, (int)preg->re_erroffset);
+  else
+    {
+    strncpy(errbuf, message, errbuf_size - 1);
+    errbuf[errbuf_size-1] = 0;
+    }
+  }
+
+return length + addlength;
+}
+
+
+
+
+/*************************************************
+*           Free store held by a regex           *
+*************************************************/
+
+EXPORT void
+regfree(regex_t *preg)
+{
+(pcre_free)(preg->re_pcre);
+}
+
+
+
+
+/*************************************************
+*            Compile a regular expression        *
+*************************************************/
+
+/*
+Arguments:
+  preg        points to a structure for recording the compiled expression
+  pattern     the pattern to compile
+  cflags      compilation flags
+
+Returns:      0 on success
+              various non-zero codes on failure
+*/
+
+EXPORT int
+regcomp(regex_t *preg, const char *pattern, int cflags)
+{
+const char *errorptr;
+int erroffset;
+int options = 0;
+
+if ((cflags & REG_ICASE) != 0) options |= PCRE_CASELESS;
+if ((cflags & REG_NEWLINE) != 0) options |= PCRE_MULTILINE;
+
+preg->re_pcre = pcre_compile(pattern, options, &errorptr, &erroffset, NULL);
+preg->re_erroffset = erroffset;
+
+if (preg->re_pcre == NULL) return pcre_posix_error_code(errorptr);
+
+preg->re_nsub = pcre_info((const pcre *)preg->re_pcre, NULL, NULL);
+return 0;
+}
+
+
+
+
+/*************************************************
+*              Match a regular expression        *
+*************************************************/
+
+/* Unfortunately, PCRE requires 3 ints of working space for each captured
+substring, so we have to get and release working store instead of just using
+the POSIX structures as was done in earlier releases when PCRE needed only 2
+ints. However, if the number of possible capturing brackets is small, use a
+block of store on the stack, to reduce the use of malloc/free. The threshold is
+in a macro that can be changed at configure time. */
+
+EXPORT int
+regexec(const regex_t *preg, const char *string, size_t nmatch,
+  regmatch_t pmatch[], int eflags)
+{
+int rc;
+int options = 0;
+int *ovector = NULL;
+int small_ovector[POSIX_MALLOC_THRESHOLD * 3];
+BOOL allocated_ovector = FALSE;
+
+if ((eflags & REG_NOTBOL) != 0) options |= PCRE_NOTBOL;
+if ((eflags & REG_NOTEOL) != 0) options |= PCRE_NOTEOL;
+
+((regex_t *)preg)->re_erroffset = (size_t)(-1);  /* Only has meaning after compile */
+
+if (nmatch > 0)
+  {
+  if (nmatch <= POSIX_MALLOC_THRESHOLD)
+    {
+    ovector = &(small_ovector[0]);
+    }
+  else
+    {
+    ovector = (int *)malloc(sizeof(int) * nmatch * 3);
+    if (ovector == NULL) return REG_ESPACE;
+    allocated_ovector = TRUE;
+    }
+  }
+
+rc = pcre_exec((const pcre *)preg->re_pcre, NULL, string, (int)strlen(string),
+  0, options, ovector, nmatch * 3);
+
+if (rc == 0) rc = nmatch;    /* All captured slots were filled in */
+
+if (rc >= 0)
+  {
+  size_t i;
+  for (i = 0; i < (size_t)rc; i++)
+    {
+    pmatch[i].rm_so = ovector[i*2];
+    pmatch[i].rm_eo = ovector[i*2+1];
+    }
+  if (allocated_ovector) free(ovector);
+  for (; i < nmatch; i++) pmatch[i].rm_so = pmatch[i].rm_eo = -1;
+  return 0;
+  }
+
+else
+  {
+  if (allocated_ovector) free(ovector);
+  switch(rc)
+    {
+    case PCRE_ERROR_NOMATCH: return REG_NOMATCH;
+    case PCRE_ERROR_NULL: return REG_INVARG;
+    case PCRE_ERROR_BADOPTION: return REG_INVARG;
+    case PCRE_ERROR_BADMAGIC: return REG_INVARG;
+    case PCRE_ERROR_UNKNOWN_NODE: return REG_ASSERT;
+    case PCRE_ERROR_NOMEMORY: return REG_ESPACE;
+    case PCRE_ERROR_MATCHLIMIT: return REG_ESPACE;
+    case PCRE_ERROR_BADUTF8: return REG_INVARG;
+    case PCRE_ERROR_BADUTF8_OFFSET: return REG_INVARG;
+    default: return REG_ASSERT;
+    }
+  }
+}
+
+/* End of pcreposix.c */

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/pcreposix.dsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/pcreposix.dsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/pcreposix.dsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,154 @@
+# Microsoft Developer Studio Project File - Name="pcreposix" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Static Library" 0x0104
+
+CFG=pcreposix - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE 
+!MESSAGE NMAKE /f "pcreposix.mak".
+!MESSAGE 
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE 
+!MESSAGE NMAKE /f "pcreposix.mak" CFG="pcreposix - Win32 Debug"
+!MESSAGE 
+!MESSAGE Possible choices for configuration are:
+!MESSAGE 
+!MESSAGE "pcreposix - Win32 Release" (based on "Win32 (x86) Static Library")
+!MESSAGE "pcreposix - Win32 Debug" (based on "Win32 (x86) Static Library")
+!MESSAGE 
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF  "$(CFG)" == "pcreposix - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "LibR"
+# PROP Intermediate_Dir "LibR"
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MD /W3 /O2 /D "_WIN32" /D "NDEBUG" /D "_WINDOWS" /D "PCRE_STATIC" /FD /c
+# ADD CPP /nologo /MD /W3 /Zi /O2 /Oy- /D "_WIN32" /D "NDEBUG" /D "_WINDOWS" /D "PCRE_STATIC" /Fd"LibR/pcreposix_src" /FD /c
+# ADD BASE RSC /l 0x409
+# ADD RSC /l 0x409
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LIB32=link.exe -lib
+# ADD BASE LIB32 /nologo
+# ADD LIB32 /nologo
+
+!ELSEIF  "$(CFG)" == "pcreposix - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "LibD"
+# PROP Intermediate_Dir "LibD"
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MDd /W3 /Zi /Od /D "_WIN32" /D "_DEBUG" /D "_WINDOWS" /D "PCRE_STATIC" /FD /EHsc /c
+# ADD CPP /nologo /MDd /W3 /Zi /Od /I "..\..\include" /D "_WIN32" /D "_DEBUG" /D "_WINDOWS" /D "PCRE_STATIC" /Fd"LibD/pcreposix_src" /FD /EHsc /c
+# ADD BASE RSC /l 0x409
+# ADD RSC /l 0x409
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LIB32=link.exe -lib
+# ADD BASE LIB32 /nologo
+# ADD LIB32 /nologo
+
+!ENDIF 
+
+# Begin Target
+
+# Name "pcreposix - Win32 Release"
+# Name "pcreposix - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "*.c"
+# Begin Source File
+
+SOURCE=.\pcreposix.c
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "*.h"
+# Begin Source File
+
+SOURCE=.\config.hw
+
+!IF  "$(CFG)" == "pcreposix - Win32 Release"
+
+# Begin Custom Build - Creating pcre config.h from config.hw
+InputPath=.\config.hw
+
+".\config.h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+	type .\config.hw > .\config.h
+
+# End Custom Build
+
+!ELSEIF  "$(CFG)" == "pcreposix - Win32 Debug"
+
+# Begin Custom Build - Creating pcre config.h from config.hw
+InputPath=.\config.hw
+
+".\config.h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+	type .\config.hw > .\config.h
+
+# End Custom Build
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\pcre.hw
+
+!IF  "$(CFG)" == "pcreposix - Win32 Release"
+
+# Begin Custom Build - Creating pcre.h from pcre.hw
+InputPath=.\pcre.hw
+
+".\pcre.h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+	type .\pcre.hw > .\pcre.h
+
+# End Custom Build
+
+!ELSEIF  "$(CFG)" == "pcreposix - Win32 Debug"
+
+# Begin Custom Build - Creating pcre.h from pcre.hw
+InputPath=.\pcre.hw
+
+".\pcre.h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+	type .\pcre.hw > .\pcre.h
+
+# End Custom Build
+
+!ENDIF 
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\include\pcreposix.h
+# End Source File
+# End Group
+# End Target
+# End Project

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/pcreposix.h
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/pcreposix.h	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/pcreposix.h	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,99 @@
+/*************************************************
+*       Perl-Compatible Regular Expressions      *
+*************************************************/
+
+/* Copyright (c) 1997-2000 University of Cambridge */
+
+/**
+ * @file include/pcreposix.h
+ * @brief PCRE definitions
+ */
+
+#ifndef _PCREPOSIX_H
+#define _PCREPOSIX_H
+
+/* This is the header for the POSIX wrapper interface to the PCRE Perl-
+Compatible Regular Expression library. It defines the things POSIX says should
+be there. I hope. */
+
+/* Have to include stdlib.h in order to ensure that size_t is defined. */
+
+#include <stdlib.h>
+
+/* Allow for C++ users */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Options defined by POSIX. */
+
+  /** Ignore case */
+#define REG_ICASE     0x01
+  /** Don't match newlines with wildcards */
+#define REG_NEWLINE   0x02
+  /** Don't match BOL */
+#define REG_NOTBOL    0x04
+  /** Don't match EOL */
+#define REG_NOTEOL    0x08
+
+/* These are not used by PCRE, but by defining them we make it easier
+to slot PCRE into existing programs that make POSIX calls. */
+
+  /** UNUSED! */
+#define REG_EXTENDED  0
+  /** UNUSED! */
+#define REG_NOSUB     0
+
+/* Error values. Not all these are relevant or used by the wrapper. */
+
+enum {
+  REG_ASSERT = 1,  /* internal error ? */
+  REG_BADBR,       /* invalid repeat counts in {} */
+  REG_BADPAT,      /* pattern error */
+  REG_BADRPT,      /* ? * + invalid */
+  REG_EBRACE,      /* unbalanced {} */
+  REG_EBRACK,      /* unbalanced [] */
+  REG_ECOLLATE,    /* collation error - not relevant */
+  REG_ECTYPE,      /* bad class */
+  REG_EESCAPE,     /* bad escape sequence */
+  REG_EMPTY,       /* empty expression */
+  REG_EPAREN,      /* unbalanced () */
+  REG_ERANGE,      /* bad range inside [] */
+  REG_ESIZE,       /* expression too big */
+  REG_ESPACE,      /* failed to get memory */
+  REG_ESUBREG,     /* bad back reference */
+  REG_INVARG,      /* bad argument */
+  REG_NOMATCH      /* match failed */
+};
+
+
+/* The structure representing a compiled regular expression. */
+
+typedef struct {
+  void *re_pcre;
+  size_t re_nsub;
+  size_t re_erroffset;
+} regex_t;
+
+/* The structure in which a captured offset is returned. */
+
+typedef int regoff_t;
+
+typedef struct {
+  regoff_t rm_so;
+  regoff_t rm_eo;
+} regmatch_t;
+
+/* The functions */
+
+extern int regcomp(regex_t *, const char *, int);
+extern int regexec(const regex_t *, const char *, size_t, regmatch_t *, int);
+extern size_t regerror(int, const regex_t *, char *, size_t);
+extern void regfree(regex_t *);
+
+#ifdef __cplusplus
+}   /* extern "C" */
+#endif
+
+#endif /* End of pcreposix.h */

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/pcretest.c
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/pcretest.c	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/pcretest.c	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,1786 @@
+/*************************************************
+*             PCRE testing program               *
+*************************************************/
+
+/* This program was hacked up as a tester for PCRE. I really should have
+written it more tidily in the first place. Will I ever learn? It has grown and
+been extended and consequently is now rather untidy in places.
+
+-----------------------------------------------------------------------------
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice,
+      this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+
+    * Neither the name of the University of Cambridge nor the names of its
+      contributors may be used to endorse or promote products derived from
+      this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+-----------------------------------------------------------------------------
+*/
+
+
+#include <ctype.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <time.h>
+#include <locale.h>
+#include <errno.h>
+
+/* We need the internal info for displaying the results of pcre_study(). Also
+for getting the opcodes for showing compiled code. */
+
+#define PCRE_SPY        /* For Win32 build, import data, not export */
+#include "internal.h"
+
+/* It is possible to compile this test program without including support for
+testing the POSIX interface, though this is not available via the standard
+Makefile. */
+
+#if !defined NOPOSIX
+#include "pcreposix.h"
+#endif
+
+#ifndef CLOCKS_PER_SEC
+#ifdef CLK_TCK
+#define CLOCKS_PER_SEC CLK_TCK
+#else
+#define CLOCKS_PER_SEC 100
+#endif
+#endif
+
+#define LOOPREPEAT 500000
+
+#define BUFFER_SIZE 30000
+#define PBUFFER_SIZE BUFFER_SIZE
+#define DBUFFER_SIZE BUFFER_SIZE
+
+
+static FILE *outfile;
+static int log_store = 0;
+static int callout_count;
+static int callout_extra;
+static int callout_fail_count;
+static int callout_fail_id;
+static int first_callout;
+static int show_malloc;
+static int use_utf8;
+static size_t gotten_store;
+
+static uschar *pbuffer = NULL;
+
+
+static const int utf8_table1[] = {
+  0x0000007f, 0x000007ff, 0x0000ffff, 0x001fffff, 0x03ffffff, 0x7fffffff};
+
+static const int utf8_table2[] = {
+  0, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc};
+
+static const int utf8_table3[] = {
+  0xff, 0x1f, 0x0f, 0x07, 0x03, 0x01};
+
+
+
+/*************************************************
+*         Print compiled regex                   *
+*************************************************/
+
+/* The code for doing this is held in a separate file that is also included in
+pcre.c when it is compiled with the debug switch. It defines a function called
+print_internals(), which uses a table of opcode lengths defined by the macro
+OP_LENGTHS, whose name must be OP_lengths. It also uses a table that translates
+Unicode property names to numbers; this is kept in a separate file. */
+
+static uschar OP_lengths[] = { OP_LENGTHS };
+
+#include "ucp.h"
+#include "ucptypetable.c"
+#include "printint.c"
+
+
+
+/*************************************************
+*          Read number from string               *
+*************************************************/
+
+/* We don't use strtoul() because SunOS4 doesn't have it. Rather than mess
+around with conditional compilation, just do the job by hand. It is only used
+for unpicking the -o argument, so just keep it simple.
+
+Arguments:
+  str           string to be converted
+  endptr        where to put the end pointer
+
+Returns:        the unsigned long
+*/
+
+static int
+get_value(unsigned char *str, unsigned char **endptr)
+{
+int result = 0;
+while(*str != 0 && isspace(*str)) str++;
+while (isdigit(*str)) result = result * 10 + (int)(*str++ - '0');
+*endptr = str;
+return(result);
+}
+
+
+
+/*************************************************
+*       Convert character value to UTF-8         *
+*************************************************/
+
+/* This function takes an integer value in the range 0 - 0x7fffffff
+and encodes it as a UTF-8 character in 0 to 6 bytes.
+
+Arguments:
+  cvalue     the character value
+  buffer     pointer to buffer for result - at least 6 bytes long
+
+Returns:     number of characters placed in the buffer
+             -1 if input character is negative
+             0 if input character is positive but too big (only when
+             int is longer than 32 bits)
+*/
+
+static int
+ord2utf8(int cvalue, unsigned char *buffer)
+{
+register int i, j;
+for (i = 0; i < sizeof(utf8_table1)/sizeof(int); i++)
+  if (cvalue <= utf8_table1[i]) break;
+if (i >= sizeof(utf8_table1)/sizeof(int)) return 0;
+if (cvalue < 0) return -1;
+
+buffer += i;
+for (j = i; j > 0; j--)
+ {
+ *buffer-- = 0x80 | (cvalue & 0x3f);
+ cvalue >>= 6;
+ }
+*buffer = utf8_table2[i] | cvalue;
+return i + 1;
+}
+
+
+/*************************************************
+*            Convert UTF-8 string to value       *
+*************************************************/
+
+/* This function takes one or more bytes that represents a UTF-8 character,
+and returns the value of the character.
+
+Argument:
+  buffer   a pointer to the byte vector
+  vptr     a pointer to an int to receive the value
+
+Returns:   >  0 => the number of bytes consumed
+           -6 to 0 => malformed UTF-8 character at offset = (-return)
+*/
+
+static int
+utf82ord(unsigned char *buffer, int *vptr)
+{
+int c = *buffer++;
+int d = c;
+int i, j, s;
+
+for (i = -1; i < 6; i++)               /* i is number of additional bytes */
+  {
+  if ((d & 0x80) == 0) break;
+  d <<= 1;
+  }
+
+if (i == -1) { *vptr = c; return 1; }  /* ascii character */
+if (i == 0 || i == 6) return 0;        /* invalid UTF-8 */
+
+/* i now has a value in the range 1-5 */
+
+s = 6*i;
+d = (c & utf8_table3[i]) << s;
+
+for (j = 0; j < i; j++)
+  {
+  c = *buffer++;
+  if ((c & 0xc0) != 0x80) return -(j+1);
+  s -= 6;
+  d |= (c & 0x3f) << s;
+  }
+
+/* Check that encoding was the correct unique one */
+
+for (j = 0; j < sizeof(utf8_table1)/sizeof(int); j++)
+  if (d <= utf8_table1[j]) break;
+if (j != i) return -(i+1);
+
+/* Valid value */
+
+*vptr = d;
+return i+1;
+}
+
+
+
+/*************************************************
+*             Print character string             *
+*************************************************/
+
+/* Character string printing function. Must handle UTF-8 strings in utf8
+mode. Yields number of characters printed. If handed a NULL file, just counts
+chars without printing. */
+
+static int pchars(unsigned char *p, int length, FILE *f)
+{
+int c;
+int yield = 0;
+
+while (length-- > 0)
+  {
+  if (use_utf8)
+    {
+    int rc = utf82ord(p, &c);
+
+    if (rc > 0 && rc <= length + 1)   /* Mustn't run over the end */
+      {
+      length -= rc - 1;
+      p += rc;
+      if (c < 256 && isprint(c))
+        {
+        if (f != NULL) fprintf(f, "%c", c);
+        yield++;
+        }
+      else
+        {
+        int n;
+        if (f != NULL) fprintf(f, "\\x{%02x}%n", c, &n);
+        yield += n;
+        }
+      continue;
+      }
+    }
+
+   /* Not UTF-8, or malformed UTF-8  */
+
+  if (isprint(c = *(p++)))
+    {
+    if (f != NULL) fprintf(f, "%c", c);
+    yield++;
+    }
+  else
+    {
+    if (f != NULL) fprintf(f, "\\x%02x", c);
+    yield += 4;
+    }
+  }
+
+return yield;
+}
+
+
+
+/*************************************************
+*              Callout function                  *
+*************************************************/
+
+/* Called from PCRE as a result of the (?C) item. We print out where we are in
+the match. Yield zero unless more callouts than the fail count, or the callout
+data is not zero. */
+
+static int callout(pcre_callout_block *cb)
+{
+FILE *f = (first_callout | callout_extra)? outfile : NULL;
+int i, pre_start, post_start, subject_length;
+
+if (callout_extra)
+  {
+  fprintf(f, "Callout %d: last capture = %d\n",
+    cb->callout_number, cb->capture_last);
+
+  for (i = 0; i < cb->capture_top * 2; i += 2)
+    {
+    if (cb->offset_vector[i] < 0)
+      fprintf(f, "%2d: <unset>\n", i/2);
+    else
+      {
+      fprintf(f, "%2d: ", i/2);
+      (void)pchars((unsigned char *)cb->subject + cb->offset_vector[i],
+        cb->offset_vector[i+1] - cb->offset_vector[i], f);
+      fprintf(f, "\n");
+      }
+    }
+  }
+
+/* Re-print the subject in canonical form, the first time or if giving full
+datails. On subsequent calls in the same match, we use pchars just to find the
+printed lengths of the substrings. */
+
+if (f != NULL) fprintf(f, "--->");
+
+pre_start = pchars((unsigned char *)cb->subject, cb->start_match, f);
+post_start = pchars((unsigned char *)(cb->subject + cb->start_match),
+  cb->current_position - cb->start_match, f);
+
+subject_length = pchars((unsigned char *)cb->subject, cb->subject_length, NULL);
+
+(void)pchars((unsigned char *)(cb->subject + cb->current_position),
+  cb->subject_length - cb->current_position, f);
+
+if (f != NULL) fprintf(f, "\n");
+
+/* Always print appropriate indicators, with callout number if not already
+shown. For automatic callouts, show the pattern offset. */
+
+if (cb->callout_number == 255)
+  {
+  fprintf(outfile, "%+3d ", cb->pattern_position);
+  if (cb->pattern_position > 99) fprintf(outfile, "\n    ");
+  }
+else
+  {
+  if (callout_extra) fprintf(outfile, "    ");
+    else fprintf(outfile, "%3d ", cb->callout_number);
+  }
+
+for (i = 0; i < pre_start; i++) fprintf(outfile, " ");
+fprintf(outfile, "^");
+
+if (post_start > 0)
+  {
+  for (i = 0; i < post_start - 1; i++) fprintf(outfile, " ");
+  fprintf(outfile, "^");
+  }
+
+for (i = 0; i < subject_length - pre_start - post_start + 4; i++)
+  fprintf(outfile, " ");
+
+fprintf(outfile, "%.*s", (cb->next_item_length == 0)? 1 : cb->next_item_length,
+  pbuffer + cb->pattern_position);
+
+fprintf(outfile, "\n");
+first_callout = 0;
+
+if (cb->callout_data != NULL)
+  {
+  int callout_data = *((int *)(cb->callout_data));
+  if (callout_data != 0)
+    {
+    fprintf(outfile, "Callout data = %d\n", callout_data);
+    return callout_data;
+    }
+  }
+
+return (cb->callout_number != callout_fail_id)? 0 :
+       (++callout_count >= callout_fail_count)? 1 : 0;
+}
+
+
+/*************************************************
+*            Local malloc functions              *
+*************************************************/
+
+/* Alternative malloc function, to test functionality and show the size of the
+compiled re. */
+
+static void *new_malloc(size_t size)
+{
+void *block = malloc(size);
+gotten_store = size;
+if (show_malloc)
+  fprintf(outfile, "malloc       %3d %p\n", size, block);
+return block;
+}
+
+static void new_free(void *block)
+{
+if (show_malloc)
+  fprintf(outfile, "free             %p\n", block);
+free(block);
+}
+
+
+/* For recursion malloc/free, to test stacking calls */
+
+static void *stack_malloc(size_t size)
+{
+void *block = malloc(size);
+if (show_malloc)
+  fprintf(outfile, "stack_malloc %3d %p\n", size, block);
+return block;
+}
+
+static void stack_free(void *block)
+{
+if (show_malloc)
+  fprintf(outfile, "stack_free       %p\n", block);
+free(block);
+}
+
+
+/*************************************************
+*          Call pcre_fullinfo()                  *
+*************************************************/
+
+/* Get one piece of information from the pcre_fullinfo() function */
+
+static void new_info(pcre *re, pcre_extra *study, int option, void *ptr)
+{
+int rc;
+if ((rc = pcre_fullinfo(re, study, option, ptr)) < 0)
+  fprintf(outfile, "Error %d from pcre_fullinfo(%d)\n", rc, option);
+}
+
+
+
+/*************************************************
+*         Byte flipping function                 *
+*************************************************/
+
+static long int
+byteflip(long int value, int n)
+{
+if (n == 2) return ((value & 0x00ff) << 8) | ((value & 0xff00) >> 8);
+return ((value & 0x000000ff) << 24) |
+       ((value & 0x0000ff00) <<  8) |
+       ((value & 0x00ff0000) >>  8) |
+       ((value & 0xff000000) >> 24);
+}
+
+
+
+
+/*************************************************
+*                Main Program                    *
+*************************************************/
+
+/* Read lines from named file or stdin and write to named file or stdout; lines
+consist of a regular expression, in delimiters and optionally followed by
+options, followed by a set of test data, terminated by an empty line. */
+
+int main(int argc, char **argv)
+{
+FILE *infile = stdin;
+int options = 0;
+int study_options = 0;
+int op = 1;
+int timeit = 0;
+int showinfo = 0;
+int showstore = 0;
+int size_offsets = 45;
+int size_offsets_max;
+int *offsets;
+#if !defined NOPOSIX
+int posix = 0;
+#endif
+int debug = 0;
+int done = 0;
+
+unsigned char *buffer;
+unsigned char *dbuffer;
+
+/* Get buffers from malloc() so that Electric Fence will check their misuse
+when I am debugging. */
+
+buffer = (unsigned char *)malloc(BUFFER_SIZE);
+dbuffer = (unsigned char *)malloc(DBUFFER_SIZE);
+pbuffer = (unsigned char *)malloc(PBUFFER_SIZE);
+
+/* The outfile variable is static so that new_malloc can use it. The _setmode()
+stuff is some magic that I don't understand, but which apparently does good
+things in Windows. It's related to line terminations.  */
+
+#if defined(_WIN32) || defined(WIN32)
+_setmode( _fileno( stdout ), 0x8000 );
+#endif  /* defined(_WIN32) || defined(WIN32) */
+
+outfile = stdout;
+
+/* Scan options */
+
+while (argc > 1 && argv[op][0] == '-')
+  {
+  unsigned char *endptr;
+
+  if (strcmp(argv[op], "-s") == 0 || strcmp(argv[op], "-m") == 0)
+    showstore = 1;
+  else if (strcmp(argv[op], "-t") == 0) timeit = 1;
+  else if (strcmp(argv[op], "-i") == 0) showinfo = 1;
+  else if (strcmp(argv[op], "-d") == 0) showinfo = debug = 1;
+  else if (strcmp(argv[op], "-o") == 0 && argc > 2 &&
+      ((size_offsets = get_value((unsigned char *)argv[op+1], &endptr)),
+        *endptr == 0))
+    {
+    op++;
+    argc--;
+    }
+#if !defined NOPOSIX
+  else if (strcmp(argv[op], "-p") == 0) posix = 1;
+#endif
+  else if (strcmp(argv[op], "-C") == 0)
+    {
+    int rc;
+    printf("PCRE version %s\n", pcre_version());
+    printf("Compiled with\n");
+    (void)pcre_config(PCRE_CONFIG_UTF8, &rc);
+    printf("  %sUTF-8 support\n", rc? "" : "No ");
+    (void)pcre_config(PCRE_CONFIG_UNICODE_PROPERTIES, &rc);
+    printf("  %sUnicode properties support\n", rc? "" : "No ");
+    (void)pcre_config(PCRE_CONFIG_NEWLINE, &rc);
+    printf("  Newline character is %s\n", (rc == '\r')? "CR" : "LF");
+    (void)pcre_config(PCRE_CONFIG_LINK_SIZE, &rc);
+    printf("  Internal link size = %d\n", rc);
+    (void)pcre_config(PCRE_CONFIG_POSIX_MALLOC_THRESHOLD, &rc);
+    printf("  POSIX malloc threshold = %d\n", rc);
+    (void)pcre_config(PCRE_CONFIG_MATCH_LIMIT, &rc);
+    printf("  Default match limit = %d\n", rc);
+    (void)pcre_config(PCRE_CONFIG_STACKRECURSE, &rc);
+    printf("  Match recursion uses %s\n", rc? "stack" : "heap");
+    exit(0);
+    }
+  else
+    {
+    printf("** Unknown or malformed option %s\n", argv[op]);
+    printf("Usage:   pcretest [-d] [-i] [-o <n>] [-p] [-s] [-t] [<input> [<output>]]\n");
+    printf("  -C     show PCRE compile-time options and exit\n");
+    printf("  -d     debug: show compiled code; implies -i\n"
+           "  -i     show information about compiled pattern\n"
+           "  -m     output memory used information\n"
+           "  -o <n> set size of offsets vector to <n>\n");
+#if !defined NOPOSIX
+    printf("  -p     use POSIX interface\n");
+#endif
+    printf("  -s     output store (memory) used information\n"
+           "  -t     time compilation and execution\n");
+    return 1;
+    }
+  op++;
+  argc--;
+  }
+
+/* Get the store for the offsets vector, and remember what it was */
+
+size_offsets_max = size_offsets;
+offsets = (int *)malloc(size_offsets_max * sizeof(int));
+if (offsets == NULL)
+  {
+  printf("** Failed to get %d bytes of memory for offsets vector\n",
+    size_offsets_max * sizeof(int));
+  return 1;
+  }
+
+/* Sort out the input and output files */
+
+if (argc > 1)
+  {
+  infile = fopen(argv[op], "rb");
+  if (infile == NULL)
+    {
+    printf("** Failed to open %s\n", argv[op]);
+    return 1;
+    }
+  }
+
+if (argc > 2)
+  {
+  outfile = fopen(argv[op+1], "wb");
+  if (outfile == NULL)
+    {
+    printf("** Failed to open %s\n", argv[op+1]);
+    return 1;
+    }
+  }
+
+/* Set alternative malloc function */
+
+pcre_malloc = new_malloc;
+pcre_free = new_free;
+pcre_stack_malloc = stack_malloc;
+pcre_stack_free = stack_free;
+
+/* Heading line, then prompt for first regex if stdin */
+
+fprintf(outfile, "PCRE version %s\n\n", pcre_version());
+
+/* Main loop */
+
+while (!done)
+  {
+  pcre *re = NULL;
+  pcre_extra *extra = NULL;
+
+#if !defined NOPOSIX  /* There are still compilers that require no indent */
+  regex_t preg;
+  int do_posix = 0;
+#endif
+
+  const char *error;
+  unsigned char *p, *pp, *ppp;
+  unsigned char *to_file = NULL;
+  const unsigned char *tables = NULL;
+  unsigned long int true_size, true_study_size = 0;
+  size_t size, regex_gotten_store;
+  int do_study = 0;
+  int do_debug = debug;
+  int do_G = 0;
+  int do_g = 0;
+  int do_showinfo = showinfo;
+  int do_showrest = 0;
+  int do_flip = 0;
+  int erroroffset, len, delimiter;
+
+  use_utf8 = 0;
+
+  if (infile == stdin) printf("  re> ");
+  if (fgets((char *)buffer, BUFFER_SIZE, infile) == NULL) break;
+  if (infile != stdin) fprintf(outfile, "%s", (char *)buffer);
+  fflush(outfile);
+
+  p = buffer;
+  while (isspace(*p)) p++;
+  if (*p == 0) continue;
+
+  /* See if the pattern is to be loaded pre-compiled from a file. */
+
+  if (*p == '<' && strchr((char *)(p+1), '<') == NULL)
+    {
+    unsigned long int magic;
+    uschar sbuf[8];
+    FILE *f;
+
+    p++;
+    pp = p + (int)strlen((char *)p);
+    while (isspace(pp[-1])) pp--;
+    *pp = 0;
+
+    f = fopen((char *)p, "rb");
+    if (f == NULL)
+      {
+      fprintf(outfile, "Failed to open %s: %s\n", p, strerror(errno));
+      continue;
+      }
+
+    if (fread(sbuf, 1, 8, f) != 8) goto FAIL_READ;
+
+    true_size =
+      (sbuf[0] << 24) | (sbuf[1] << 16) | (sbuf[2] << 8) | sbuf[3];
+    true_study_size =
+      (sbuf[4] << 24) | (sbuf[5] << 16) | (sbuf[6] << 8) | sbuf[7];
+
+    re = (real_pcre *)new_malloc(true_size);
+    regex_gotten_store = gotten_store;
+
+    if (fread(re, 1, true_size, f) != true_size) goto FAIL_READ;
+
+    magic = ((real_pcre *)re)->magic_number;
+    if (magic != MAGIC_NUMBER)
+      {
+      if (byteflip(magic, sizeof(magic)) == MAGIC_NUMBER)
+        {
+        do_flip = 1;
+        }
+      else
+        {
+        fprintf(outfile, "Data in %s is not a compiled PCRE regex\n", p);
+        fclose(f);
+        continue;
+        }
+      }
+
+    fprintf(outfile, "Compiled regex%s loaded from %s\n",
+      do_flip? " (byte-inverted)" : "", p);
+
+    /* Need to know if UTF-8 for printing data strings */
+
+    new_info(re, NULL, PCRE_INFO_OPTIONS, &options);
+    use_utf8 = (options & PCRE_UTF8) != 0;
+
+    /* Now see if there is any following study data */
+
+    if (true_study_size != 0)
+      {
+      pcre_study_data *psd;
+
+      extra = (pcre_extra *)new_malloc(sizeof(pcre_extra) + true_study_size);
+      extra->flags = PCRE_EXTRA_STUDY_DATA;
+
+      psd = (pcre_study_data *)(((char *)extra) + sizeof(pcre_extra));
+      extra->study_data = psd;
+
+      if (fread(psd, 1, true_study_size, f) != true_study_size)
+        {
+        FAIL_READ:
+        fprintf(outfile, "Failed to read data from %s\n", p);
+        if (extra != NULL) new_free(extra);
+        if (re != NULL) new_free(re);
+        fclose(f);
+        continue;
+        }
+      fprintf(outfile, "Study data loaded from %s\n", p);
+      do_study = 1;     /* To get the data output if requested */
+      }
+    else fprintf(outfile, "No study data\n");
+
+    fclose(f);
+    goto SHOW_INFO;
+    }
+
+  /* In-line pattern (the usual case). Get the delimiter and seek the end of
+  the pattern; if is isn't complete, read more. */
+
+  delimiter = *p++;
+
+  if (isalnum(delimiter) || delimiter == '\\')
+    {
+    fprintf(outfile, "** Delimiter must not be alphameric or \\\n");
+    goto SKIP_DATA;
+    }
+
+  pp = p;
+
+  for(;;)
+    {
+    while (*pp != 0)
+      {
+      if (*pp == '\\' && pp[1] != 0) pp++;
+        else if (*pp == delimiter) break;
+      pp++;
+      }
+    if (*pp != 0) break;
+
+    len = BUFFER_SIZE - (pp - buffer);
+    if (len < 256)
+      {
+      fprintf(outfile, "** Expression too long - missing delimiter?\n");
+      goto SKIP_DATA;
+      }
+
+    if (infile == stdin) printf("    > ");
+    if (fgets((char *)pp, len, infile) == NULL)
+      {
+      fprintf(outfile, "** Unexpected EOF\n");
+      done = 1;
+      goto CONTINUE;
+      }
+    if (infile != stdin) fprintf(outfile, "%s", (char *)pp);
+    }
+
+  /* If the first character after the delimiter is backslash, make
+  the pattern end with backslash. This is purely to provide a way
+  of testing for the error message when a pattern ends with backslash. */
+
+  if (pp[1] == '\\') *pp++ = '\\';
+
+  /* Terminate the pattern at the delimiter, and save a copy of the pattern
+  for callouts. */
+
+  *pp++ = 0;
+  strcpy((char *)pbuffer, (char *)p);
+
+  /* Look for options after final delimiter */
+
+  options = 0;
+  study_options = 0;
+  log_store = showstore;  /* default from command line */
+
+  while (*pp != 0)
+    {
+    switch (*pp++)
+      {
+      case 'g': do_g = 1; break;
+      case 'i': options |= PCRE_CASELESS; break;
+      case 'm': options |= PCRE_MULTILINE; break;
+      case 's': options |= PCRE_DOTALL; break;
+      case 'x': options |= PCRE_EXTENDED; break;
+
+      case '+': do_showrest = 1; break;
+      case 'A': options |= PCRE_ANCHORED; break;
+      case 'C': options |= PCRE_AUTO_CALLOUT; break;
+      case 'D': do_debug = do_showinfo = 1; break;
+      case 'E': options |= PCRE_DOLLAR_ENDONLY; break;
+      case 'F': do_flip = 1; break;
+      case 'G': do_G = 1; break;
+      case 'I': do_showinfo = 1; break;
+      case 'M': log_store = 1; break;
+      case 'N': options |= PCRE_NO_AUTO_CAPTURE; break;
+
+#if !defined NOPOSIX
+      case 'P': do_posix = 1; break;
+#endif
+
+      case 'S': do_study = 1; break;
+      case 'U': options |= PCRE_UNGREEDY; break;
+      case 'X': options |= PCRE_EXTRA; break;
+      case '8': options |= PCRE_UTF8; use_utf8 = 1; break;
+      case '?': options |= PCRE_NO_UTF8_CHECK; break;
+
+      case 'L':
+      ppp = pp;
+      while (*ppp != '\n' && *ppp != ' ') ppp++;
+      *ppp = 0;
+      if (setlocale(LC_CTYPE, (const char *)pp) == NULL)
+        {
+        fprintf(outfile, "** Failed to set locale \"%s\"\n", pp);
+        goto SKIP_DATA;
+        }
+      tables = pcre_maketables();
+      pp = ppp;
+      break;
+
+      case '>':
+      to_file = pp;
+      while (*pp != 0) pp++;
+      while (isspace(pp[-1])) pp--;
+      *pp = 0;
+      break;
+
+      case '\n': case ' ': break;
+
+      default:
+      fprintf(outfile, "** Unknown option '%c'\n", pp[-1]);
+      goto SKIP_DATA;
+      }
+    }
+
+  /* Handle compiling via the POSIX interface, which doesn't support the
+  timing, showing, or debugging options, nor the ability to pass over
+  local character tables. */
+
+#if !defined NOPOSIX
+  if (posix || do_posix)
+    {
+    int rc;
+    int cflags = 0;
+
+    if ((options & PCRE_CASELESS) != 0) cflags |= REG_ICASE;
+    if ((options & PCRE_MULTILINE) != 0) cflags |= REG_NEWLINE;
+    rc = regcomp(&preg, (char *)p, cflags);
+
+    /* Compilation failed; go back for another re, skipping to blank line
+    if non-interactive. */
+
+    if (rc != 0)
+      {
+      (void)regerror(rc, &preg, (char *)buffer, BUFFER_SIZE);
+      fprintf(outfile, "Failed: POSIX code %d: %s\n", rc, buffer);
+      goto SKIP_DATA;
+      }
+    }
+
+  /* Handle compiling via the native interface */
+
+  else
+#endif  /* !defined NOPOSIX */
+
+    {
+    if (timeit)
+      {
+      register int i;
+      clock_t time_taken;
+      clock_t start_time = clock();
+      for (i = 0; i < LOOPREPEAT; i++)
+        {
+        re = pcre_compile((char *)p, options, &error, &erroroffset, tables);
+        if (re != NULL) free(re);
+        }
+      time_taken = clock() - start_time;
+      fprintf(outfile, "Compile time %.3f milliseconds\n",
+        (((double)time_taken * 1000.0) / (double)LOOPREPEAT) /
+          (double)CLOCKS_PER_SEC);
+      }
+
+    re = pcre_compile((char *)p, options, &error, &erroroffset, tables);
+
+    /* Compilation failed; go back for another re, skipping to blank line
+    if non-interactive. */
+
+    if (re == NULL)
+      {
+      fprintf(outfile, "Failed: %s at offset %d\n", error, erroroffset);
+      SKIP_DATA:
+      if (infile != stdin)
+        {
+        for (;;)
+          {
+          if (fgets((char *)buffer, BUFFER_SIZE, infile) == NULL)
+            {
+            done = 1;
+            goto CONTINUE;
+            }
+          len = (int)strlen((char *)buffer);
+          while (len > 0 && isspace(buffer[len-1])) len--;
+          if (len == 0) break;
+          }
+        fprintf(outfile, "\n");
+        }
+      goto CONTINUE;
+      }
+
+    /* Compilation succeeded; print data if required. There are now two
+    info-returning functions. The old one has a limited interface and
+    returns only limited data. Check that it agrees with the newer one. */
+
+    if (log_store)
+      fprintf(outfile, "Memory allocation (code space): %d\n",
+        (int)(gotten_store -
+              sizeof(real_pcre) -
+              ((real_pcre *)re)->name_count * ((real_pcre *)re)->name_entry_size));
+
+    /* Extract the size for possible writing before possibly flipping it,
+    and remember the store that was got. */
+
+    true_size = ((real_pcre *)re)->size;
+    regex_gotten_store = gotten_store;
+
+    /* If /S was present, study the regexp to generate additional info to
+    help with the matching. */
+
+    if (do_study)
+      {
+      if (timeit)
+        {
+        register int i;
+        clock_t time_taken;
+        clock_t start_time = clock();
+        for (i = 0; i < LOOPREPEAT; i++)
+          extra = pcre_study(re, study_options, &error);
+        time_taken = clock() - start_time;
+        if (extra != NULL) free(extra);
+        fprintf(outfile, "  Study time %.3f milliseconds\n",
+          (((double)time_taken * 1000.0) / (double)LOOPREPEAT) /
+            (double)CLOCKS_PER_SEC);
+        }
+      extra = pcre_study(re, study_options, &error);
+      if (error != NULL)
+        fprintf(outfile, "Failed to study: %s\n", error);
+      else if (extra != NULL)
+        true_study_size = ((pcre_study_data *)(extra->study_data))->size;
+      }
+
+    /* If the 'F' option was present, we flip the bytes of all the integer
+    fields in the regex data block and the study block. This is to make it
+    possible to test PCRE's handling of byte-flipped patterns, e.g. those
+    compiled on a different architecture. */
+
+    if (do_flip)
+      {
+      real_pcre *rre = (real_pcre *)re;
+      rre->magic_number = byteflip(rre->magic_number, sizeof(rre->magic_number));
+      rre->size = byteflip(rre->size, sizeof(rre->size));
+      rre->options = byteflip(rre->options, sizeof(rre->options));
+      rre->top_bracket = byteflip(rre->top_bracket, sizeof(rre->top_bracket));
+      rre->top_backref = byteflip(rre->top_backref, sizeof(rre->top_backref));
+      rre->first_byte = byteflip(rre->first_byte, sizeof(rre->first_byte));
+      rre->req_byte = byteflip(rre->req_byte, sizeof(rre->req_byte));
+      rre->name_table_offset = byteflip(rre->name_table_offset,
+        sizeof(rre->name_table_offset));
+      rre->name_entry_size = byteflip(rre->name_entry_size,
+        sizeof(rre->name_entry_size));
+      rre->name_count = byteflip(rre->name_count, sizeof(rre->name_count));
+
+      if (extra != NULL)
+        {
+        pcre_study_data *rsd = (pcre_study_data *)(extra->study_data);
+        rsd->size = byteflip(rsd->size, sizeof(rsd->size));
+        rsd->options = byteflip(rsd->options, sizeof(rsd->options));
+        }
+      }
+
+    /* Extract information from the compiled data if required */
+
+    SHOW_INFO:
+
+    if (do_showinfo)
+      {
+      unsigned long int get_options, all_options;
+      int old_first_char, old_options, old_count;
+      int count, backrefmax, first_char, need_char;
+      int nameentrysize, namecount;
+      const uschar *nametable;
+
+      if (do_debug)
+        {
+        fprintf(outfile, "------------------------------------------------------------------\n");
+        print_internals(re, outfile);
+        }
+
+      new_info(re, NULL, PCRE_INFO_OPTIONS, &get_options);
+      new_info(re, NULL, PCRE_INFO_SIZE, &size);
+      new_info(re, NULL, PCRE_INFO_CAPTURECOUNT, &count);
+      new_info(re, NULL, PCRE_INFO_BACKREFMAX, &backrefmax);
+      new_info(re, NULL, PCRE_INFO_FIRSTBYTE, &first_char);
+      new_info(re, NULL, PCRE_INFO_LASTLITERAL, &need_char);
+      new_info(re, NULL, PCRE_INFO_NAMEENTRYSIZE, &nameentrysize);
+      new_info(re, NULL, PCRE_INFO_NAMECOUNT, &namecount);
+      new_info(re, NULL, PCRE_INFO_NAMETABLE, (void *)&nametable);
+
+      old_count = pcre_info(re, &old_options, &old_first_char);
+      if (count < 0) fprintf(outfile,
+        "Error %d from pcre_info()\n", count);
+      else
+        {
+        if (old_count != count) fprintf(outfile,
+          "Count disagreement: pcre_fullinfo=%d pcre_info=%d\n", count,
+            old_count);
+
+        if (old_first_char != first_char) fprintf(outfile,
+          "First char disagreement: pcre_fullinfo=%d pcre_info=%d\n",
+            first_char, old_first_char);
+
+        if (old_options != (int)get_options) fprintf(outfile,
+          "Options disagreement: pcre_fullinfo=%ld pcre_info=%d\n",
+            get_options, old_options);
+        }
+
+      if (size != regex_gotten_store) fprintf(outfile,
+        "Size disagreement: pcre_fullinfo=%d call to malloc for %d\n",
+        size, regex_gotten_store);
+
+      fprintf(outfile, "Capturing subpattern count = %d\n", count);
+      if (backrefmax > 0)
+        fprintf(outfile, "Max back reference = %d\n", backrefmax);
+
+      if (namecount > 0)
+        {
+        fprintf(outfile, "Named capturing subpatterns:\n");
+        while (namecount-- > 0)
+          {
+          fprintf(outfile, "  %s %*s%3d\n", nametable + 2,
+            nameentrysize - 3 - (int)strlen((char *)nametable + 2), "",
+            GET2(nametable, 0));
+          nametable += nameentrysize;
+          }
+        }
+
+      /* The NOPARTIAL bit is a private bit in the options, so we have
+      to fish it out via out back door */
+
+      all_options = ((real_pcre *)re)->options;
+      if (do_flip)
+        {
+        all_options = byteflip(all_options, sizeof(all_options));
+        }
+
+      if ((all_options & PCRE_NOPARTIAL) != 0)
+        fprintf(outfile, "Partial matching not supported\n");
+
+      if (get_options == 0) fprintf(outfile, "No options\n");
+        else fprintf(outfile, "Options:%s%s%s%s%s%s%s%s%s%s\n",
+          ((get_options & PCRE_ANCHORED) != 0)? " anchored" : "",
+          ((get_options & PCRE_CASELESS) != 0)? " caseless" : "",
+          ((get_options & PCRE_EXTENDED) != 0)? " extended" : "",
+          ((get_options & PCRE_MULTILINE) != 0)? " multiline" : "",
+          ((get_options & PCRE_DOTALL) != 0)? " dotall" : "",
+          ((get_options & PCRE_DOLLAR_ENDONLY) != 0)? " dollar_endonly" : "",
+          ((get_options & PCRE_EXTRA) != 0)? " extra" : "",
+          ((get_options & PCRE_UNGREEDY) != 0)? " ungreedy" : "",
+          ((get_options & PCRE_UTF8) != 0)? " utf8" : "",
+          ((get_options & PCRE_NO_UTF8_CHECK) != 0)? " no_utf8_check" : "");
+
+      if (((((real_pcre *)re)->options) & PCRE_ICHANGED) != 0)
+        fprintf(outfile, "Case state changes\n");
+
+      if (first_char == -1)
+        {
+        fprintf(outfile, "First char at start or follows \\n\n");
+        }
+      else if (first_char < 0)
+        {
+        fprintf(outfile, "No first char\n");
+        }
+      else
+        {
+        int ch = first_char & 255;
+        const char *caseless = ((first_char & REQ_CASELESS) == 0)?
+          "" : " (caseless)";
+        if (isprint(ch))
+          fprintf(outfile, "First char = \'%c\'%s\n", ch, caseless);
+        else
+          fprintf(outfile, "First char = %d%s\n", ch, caseless);
+        }
+
+      if (need_char < 0)
+        {
+        fprintf(outfile, "No need char\n");
+        }
+      else
+        {
+        int ch = need_char & 255;
+        const char *caseless = ((need_char & REQ_CASELESS) == 0)?
+          "" : " (caseless)";
+        if (isprint(ch))
+          fprintf(outfile, "Need char = \'%c\'%s\n", ch, caseless);
+        else
+          fprintf(outfile, "Need char = %d%s\n", ch, caseless);
+        }
+
+      /* Don't output study size; at present it is in any case a fixed
+      value, but it varies, depending on the computer architecture, and
+      so messes up the test suite. (And with the /F option, it might be
+      flipped.) */
+
+      if (do_study)
+        {
+        if (extra == NULL)
+          fprintf(outfile, "Study returned NULL\n");
+        else
+          {
+          uschar *start_bits = NULL;
+          new_info(re, extra, PCRE_INFO_FIRSTTABLE, &start_bits);
+
+          if (start_bits == NULL)
+            fprintf(outfile, "No starting byte set\n");
+          else
+            {
+            int i;
+            int c = 24;
+            fprintf(outfile, "Starting byte set: ");
+            for (i = 0; i < 256; i++)
+              {
+              if ((start_bits[i/8] & (1<<(i&7))) != 0)
+                {
+                if (c > 75)
+                  {
+                  fprintf(outfile, "\n  ");
+                  c = 2;
+                  }
+                if (isprint(i) && i != ' ')
+                  {
+                  fprintf(outfile, "%c ", i);
+                  c += 2;
+                  }
+                else
+                  {
+                  fprintf(outfile, "\\x%02x ", i);
+                  c += 5;
+                  }
+                }
+              }
+            fprintf(outfile, "\n");
+            }
+          }
+        }
+      }
+
+    /* If the '>' option was present, we write out the regex to a file, and
+    that is all. The first 8 bytes of the file are the regex length and then
+    the study length, in big-endian order. */
+
+    if (to_file != NULL)
+      {
+      FILE *f = fopen((char *)to_file, "wb");
+      if (f == NULL)
+        {
+        fprintf(outfile, "Unable to open %s: %s\n", to_file, strerror(errno));
+        }
+      else
+        {
+        uschar sbuf[8];
+        sbuf[0] = (true_size >> 24)  & 255;
+        sbuf[1] = (true_size >> 16)  & 255;
+        sbuf[2] = (true_size >>  8)  & 255;
+        sbuf[3] = (true_size)  & 255;
+
+        sbuf[4] = (true_study_size >> 24)  & 255;
+        sbuf[5] = (true_study_size >> 16)  & 255;
+        sbuf[6] = (true_study_size >>  8)  & 255;
+        sbuf[7] = (true_study_size)  & 255;
+
+        if (fwrite(sbuf, 1, 8, f) < 8 ||
+            fwrite(re, 1, true_size, f) < true_size)
+          {
+          fprintf(outfile, "Write error on %s: %s\n", to_file, strerror(errno));
+          }
+        else
+          {
+          fprintf(outfile, "Compiled regex written to %s\n", to_file);
+          if (extra != NULL)
+            {
+            if (fwrite(extra->study_data, 1, true_study_size, f) <
+                true_study_size)
+              {
+              fprintf(outfile, "Write error on %s: %s\n", to_file,
+                strerror(errno));
+              }
+            else fprintf(outfile, "Study data written to %s\n", to_file);
+            }
+          }
+        fclose(f);
+        }
+      continue;  /* With next regex */
+      }
+    }        /* End of non-POSIX compile */
+
+  /* Read data lines and test them */
+
+  for (;;)
+    {
+    unsigned char *q;
+    unsigned char *bptr = dbuffer;
+    int *use_offsets = offsets;
+    int use_size_offsets = size_offsets;
+    int callout_data = 0;
+    int callout_data_set = 0;
+    int count, c;
+    int copystrings = 0;
+    int find_match_limit = 0;
+    int getstrings = 0;
+    int getlist = 0;
+    int gmatched = 0;
+    int start_offset = 0;
+    int g_notempty = 0;
+
+    options = 0;
+
+    pcre_callout = callout;
+    first_callout = 1;
+    callout_extra = 0;
+    callout_count = 0;
+    callout_fail_count = 999999;
+    callout_fail_id = -1;
+    show_malloc = 0;
+
+    if (infile == stdin) printf("data> ");
+    if (fgets((char *)buffer, BUFFER_SIZE, infile) == NULL)
+      {
+      done = 1;
+      goto CONTINUE;
+      }
+    if (infile != stdin) fprintf(outfile, "%s", (char *)buffer);
+
+    len = (int)strlen((char *)buffer);
+    while (len > 0 && isspace(buffer[len-1])) len--;
+    buffer[len] = 0;
+    if (len == 0) break;
+
+    p = buffer;
+    while (isspace(*p)) p++;
+
+    q = dbuffer;
+    while ((c = *p++) != 0)
+      {
+      int i = 0;
+      int n = 0;
+
+      if (c == '\\') switch ((c = *p++))
+        {
+        case 'a': c =    7; break;
+        case 'b': c = '\b'; break;
+        case 'e': c =   27; break;
+        case 'f': c = '\f'; break;
+        case 'n': c = '\n'; break;
+        case 'r': c = '\r'; break;
+        case 't': c = '\t'; break;
+        case 'v': c = '\v'; break;
+
+        case '0': case '1': case '2': case '3':
+        case '4': case '5': case '6': case '7':
+        c -= '0';
+        while (i++ < 2 && isdigit(*p) && *p != '8' && *p != '9')
+          c = c * 8 + *p++ - '0';
+        break;
+
+        case 'x':
+
+        /* Handle \x{..} specially - new Perl thing for utf8 */
+
+        if (*p == '{')
+          {
+          unsigned char *pt = p;
+          c = 0;
+          while (isxdigit(*(++pt)))
+            c = c * 16 + tolower(*pt) - ((isdigit(*pt))? '0' : 'W');
+          if (*pt == '}')
+            {
+            unsigned char buff8[8];
+            int ii, utn;
+            utn = ord2utf8(c, buff8);
+            for (ii = 0; ii < utn - 1; ii++) *q++ = buff8[ii];
+            c = buff8[ii];   /* Last byte */
+            p = pt + 1;
+            break;
+            }
+          /* Not correct form; fall through */
+          }
+
+        /* Ordinary \x */
+
+        c = 0;
+        while (i++ < 2 && isxdigit(*p))
+          {
+          c = c * 16 + tolower(*p) - ((isdigit(*p))? '0' : 'W');
+          p++;
+          }
+        break;
+
+        case 0:   /* \ followed by EOF allows for an empty line */
+        p--;
+        continue;
+
+        case '>':
+        while(isdigit(*p)) start_offset = start_offset * 10 + *p++ - '0';
+        continue;
+
+        case 'A':  /* Option setting */
+        options |= PCRE_ANCHORED;
+        continue;
+
+        case 'B':
+        options |= PCRE_NOTBOL;
+        continue;
+
+        case 'C':
+        if (isdigit(*p))    /* Set copy string */
+          {
+          while(isdigit(*p)) n = n * 10 + *p++ - '0';
+          copystrings |= 1 << n;
+          }
+        else if (isalnum(*p))
+          {
+          uschar name[256];
+          uschar *npp = name;
+          while (isalnum(*p)) *npp++ = *p++;
+          *npp = 0;
+          n = pcre_get_stringnumber(re, (char *)name);
+          if (n < 0)
+            fprintf(outfile, "no parentheses with name \"%s\"\n", name);
+          else copystrings |= 1 << n;
+          }
+        else if (*p == '+')
+          {
+          callout_extra = 1;
+          p++;
+          }
+        else if (*p == '-')
+          {
+          pcre_callout = NULL;
+          p++;
+          }
+        else if (*p == '!')
+          {
+          callout_fail_id = 0;
+          p++;
+          while(isdigit(*p))
+            callout_fail_id = callout_fail_id * 10 + *p++ - '0';
+          callout_fail_count = 0;
+          if (*p == '!')
+            {
+            p++;
+            while(isdigit(*p))
+              callout_fail_count = callout_fail_count * 10 + *p++ - '0';
+            }
+          }
+        else if (*p == '*')
+          {
+          int sign = 1;
+          callout_data = 0;
+          if (*(++p) == '-') { sign = -1; p++; }
+          while(isdigit(*p))
+            callout_data = callout_data * 10 + *p++ - '0';
+          callout_data *= sign;
+          callout_data_set = 1;
+          }
+        continue;
+
+        case 'G':
+        if (isdigit(*p))
+          {
+          while(isdigit(*p)) n = n * 10 + *p++ - '0';
+          getstrings |= 1 << n;
+          }
+        else if (isalnum(*p))
+          {
+          uschar name[256];
+          uschar *npp = name;
+          while (isalnum(*p)) *npp++ = *p++;
+          *npp = 0;
+          n = pcre_get_stringnumber(re, (char *)name);
+          if (n < 0)
+            fprintf(outfile, "no parentheses with name \"%s\"\n", name);
+          else getstrings |= 1 << n;
+          }
+        continue;
+
+        case 'L':
+        getlist = 1;
+        continue;
+
+        case 'M':
+        find_match_limit = 1;
+        continue;
+
+        case 'N':
+        options |= PCRE_NOTEMPTY;
+        continue;
+
+        case 'O':
+        while(isdigit(*p)) n = n * 10 + *p++ - '0';
+        if (n > size_offsets_max)
+          {
+          size_offsets_max = n;
+          free(offsets);
+          use_offsets = offsets = (int *)malloc(size_offsets_max * sizeof(int));
+          if (offsets == NULL)
+            {
+            printf("** Failed to get %d bytes of memory for offsets vector\n",
+              size_offsets_max * sizeof(int));
+            return 1;
+            }
+          }
+        use_size_offsets = n;
+        if (n == 0) use_offsets = NULL;   /* Ensures it can't write to it */
+        continue;
+
+        case 'P':
+        options |= PCRE_PARTIAL;
+        continue;
+
+        case 'S':
+        show_malloc = 1;
+        continue;
+
+        case 'Z':
+        options |= PCRE_NOTEOL;
+        continue;
+
+        case '?':
+        options |= PCRE_NO_UTF8_CHECK;
+        continue;
+        }
+      *q++ = c;
+      }
+    *q = 0;
+    len = q - dbuffer;
+
+    /* Handle matching via the POSIX interface, which does not
+    support timing or playing with the match limit or callout data. */
+
+#if !defined NOPOSIX
+    if (posix || do_posix)
+      {
+      int rc;
+      int eflags = 0;
+      regmatch_t *pmatch = NULL;
+      if (use_size_offsets > 0)
+        pmatch = (regmatch_t *)malloc(sizeof(regmatch_t) * use_size_offsets);
+      if ((options & PCRE_NOTBOL) != 0) eflags |= REG_NOTBOL;
+      if ((options & PCRE_NOTEOL) != 0) eflags |= REG_NOTEOL;
+
+      rc = regexec(&preg, (const char *)bptr, use_size_offsets, pmatch, eflags);
+
+      if (rc != 0)
+        {
+        (void)regerror(rc, &preg, (char *)buffer, BUFFER_SIZE);
+        fprintf(outfile, "No match: POSIX code %d: %s\n", rc, buffer);
+        }
+      else
+        {
+        size_t i;
+        for (i = 0; i < (size_t)use_size_offsets; i++)
+          {
+          if (pmatch[i].rm_so >= 0)
+            {
+            fprintf(outfile, "%2d: ", (int)i);
+            (void)pchars(dbuffer + pmatch[i].rm_so,
+              pmatch[i].rm_eo - pmatch[i].rm_so, outfile);
+            fprintf(outfile, "\n");
+            if (i == 0 && do_showrest)
+              {
+              fprintf(outfile, " 0+ ");
+              (void)pchars(dbuffer + pmatch[i].rm_eo, len - pmatch[i].rm_eo,
+                outfile);
+              fprintf(outfile, "\n");
+              }
+            }
+          }
+        }
+      free(pmatch);
+      }
+
+    /* Handle matching via the native interface - repeats for /g and /G */
+
+    else
+#endif  /* !defined NOPOSIX */
+
+    for (;; gmatched++)    /* Loop for /g or /G */
+      {
+      if (timeit)
+        {
+        register int i;
+        clock_t time_taken;
+        clock_t start_time = clock();
+        for (i = 0; i < LOOPREPEAT; i++)
+          count = pcre_exec(re, extra, (char *)bptr, len,
+            start_offset, options | g_notempty, use_offsets, use_size_offsets);
+        time_taken = clock() - start_time;
+        fprintf(outfile, "Execute time %.3f milliseconds\n",
+          (((double)time_taken * 1000.0) / (double)LOOPREPEAT) /
+            (double)CLOCKS_PER_SEC);
+        }
+
+      /* If find_match_limit is set, we want to do repeated matches with
+      varying limits in order to find the minimum value. */
+
+      if (find_match_limit)
+        {
+        int min = 0;
+        int mid = 64;
+        int max = -1;
+
+        if (extra == NULL)
+          {
+          extra = (pcre_extra *)malloc(sizeof(pcre_extra));
+          extra->flags = 0;
+          }
+        extra->flags |= PCRE_EXTRA_MATCH_LIMIT;
+
+        for (;;)
+          {
+          extra->match_limit = mid;
+          count = pcre_exec(re, extra, (char *)bptr, len, start_offset,
+            options | g_notempty, use_offsets, use_size_offsets);
+          if (count == PCRE_ERROR_MATCHLIMIT)
+            {
+            /* fprintf(outfile, "Testing match limit = %d\n", mid); */
+            min = mid;
+            mid = (mid == max - 1)? max : (max > 0)? (min + max)/2 : mid*2;
+            }
+          else if (count >= 0 || count == PCRE_ERROR_NOMATCH ||
+                                 count == PCRE_ERROR_PARTIAL)
+            {
+            if (mid == min + 1)
+              {
+              fprintf(outfile, "Minimum match limit = %d\n", mid);
+              break;
+              }
+            /* fprintf(outfile, "Testing match limit = %d\n", mid); */
+            max = mid;
+            mid = (min + mid)/2;
+            }
+          else break;    /* Some other error */
+          }
+
+        extra->flags &= ~PCRE_EXTRA_MATCH_LIMIT;
+        }
+
+      /* If callout_data is set, use the interface with additional data */
+
+      else if (callout_data_set)
+        {
+        if (extra == NULL)
+          {
+          extra = (pcre_extra *)malloc(sizeof(pcre_extra));
+          extra->flags = 0;
+          }
+        extra->flags |= PCRE_EXTRA_CALLOUT_DATA;
+        extra->callout_data = &callout_data;
+        count = pcre_exec(re, extra, (char *)bptr, len, start_offset,
+          options | g_notempty, use_offsets, use_size_offsets);
+        extra->flags &= ~PCRE_EXTRA_CALLOUT_DATA;
+        }
+
+      /* The normal case is just to do the match once, with the default
+      value of match_limit. */
+
+      else
+        {
+        count = pcre_exec(re, extra, (char *)bptr, len,
+          start_offset, options | g_notempty, use_offsets, use_size_offsets);
+        }
+
+      if (count == 0)
+        {
+        fprintf(outfile, "Matched, but too many substrings\n");
+        count = use_size_offsets/3;
+        }
+
+      /* Matched */
+
+      if (count >= 0)
+        {
+        int i;
+        for (i = 0; i < count * 2; i += 2)
+          {
+          if (use_offsets[i] < 0)
+            fprintf(outfile, "%2d: <unset>\n", i/2);
+          else
+            {
+            fprintf(outfile, "%2d: ", i/2);
+            (void)pchars(bptr + use_offsets[i],
+              use_offsets[i+1] - use_offsets[i], outfile);
+            fprintf(outfile, "\n");
+            if (i == 0)
+              {
+              if (do_showrest)
+                {
+                fprintf(outfile, " 0+ ");
+                (void)pchars(bptr + use_offsets[i+1], len - use_offsets[i+1],
+                  outfile);
+                fprintf(outfile, "\n");
+                }
+              }
+            }
+          }
+
+        for (i = 0; i < 32; i++)
+          {
+          if ((copystrings & (1 << i)) != 0)
+            {
+            char copybuffer[16];
+            int rc = pcre_copy_substring((char *)bptr, use_offsets, count,
+              i, copybuffer, sizeof(copybuffer));
+            if (rc < 0)
+              fprintf(outfile, "copy substring %d failed %d\n", i, rc);
+            else
+              fprintf(outfile, "%2dC %s (%d)\n", i, copybuffer, rc);
+            }
+          }
+
+        for (i = 0; i < 32; i++)
+          {
+          if ((getstrings & (1 << i)) != 0)
+            {
+            const char *substring;
+            int rc = pcre_get_substring((char *)bptr, use_offsets, count,
+              i, &substring);
+            if (rc < 0)
+              fprintf(outfile, "get substring %d failed %d\n", i, rc);
+            else
+              {
+              fprintf(outfile, "%2dG %s (%d)\n", i, substring, rc);
+              /* free((void *)substring); */
+              pcre_free_substring(substring);
+              }
+            }
+          }
+
+        if (getlist)
+          {
+          const char **stringlist;
+          int rc = pcre_get_substring_list((char *)bptr, use_offsets, count,
+            &stringlist);
+          if (rc < 0)
+            fprintf(outfile, "get substring list failed %d\n", rc);
+          else
+            {
+            for (i = 0; i < count; i++)
+              fprintf(outfile, "%2dL %s\n", i, stringlist[i]);
+            if (stringlist[i] != NULL)
+              fprintf(outfile, "string list not terminated by NULL\n");
+            /* free((void *)stringlist); */
+            pcre_free_substring_list(stringlist);
+            }
+          }
+        }
+
+      /* There was a partial match */
+
+      else if (count == PCRE_ERROR_PARTIAL)
+        {
+        fprintf(outfile, "Partial match\n");
+        break;  /* Out of the /g loop */
+        }
+
+      /* Failed to match. If this is a /g or /G loop and we previously set
+      g_notempty after a null match, this is not necessarily the end.
+      We want to advance the start offset, and continue. In the case of UTF-8
+      matching, the advance must be one character, not one byte. Fudge the
+      offset values to achieve this. We won't be at the end of the string -
+      that was checked before setting g_notempty. */
+
+      else
+        {
+        if (g_notempty != 0)
+          {
+          int onechar = 1;
+          use_offsets[0] = start_offset;
+          if (use_utf8)
+            {
+            while (start_offset + onechar < len)
+              {
+              int tb = bptr[start_offset+onechar];
+              if (tb <= 127) break;
+              tb &= 0xc0;
+              if (tb != 0 && tb != 0xc0) onechar++;
+              }
+            }
+          use_offsets[1] = start_offset + onechar;
+          }
+        else
+          {
+          if (count == PCRE_ERROR_NOMATCH)
+            {
+            if (gmatched == 0) fprintf(outfile, "No match\n");
+            }
+          else fprintf(outfile, "Error %d\n", count);
+          break;  /* Out of the /g loop */
+          }
+        }
+
+      /* If not /g or /G we are done */
+
+      if (!do_g && !do_G) break;
+
+      /* If we have matched an empty string, first check to see if we are at
+      the end of the subject. If so, the /g loop is over. Otherwise, mimic
+      what Perl's /g options does. This turns out to be rather cunning. First
+      we set PCRE_NOTEMPTY and PCRE_ANCHORED and try the match again at the
+      same point. If this fails (picked up above) we advance to the next
+      character. */
+
+      g_notempty = 0;
+      if (use_offsets[0] == use_offsets[1])
+        {
+        if (use_offsets[0] == len) break;
+        g_notempty = PCRE_NOTEMPTY | PCRE_ANCHORED;
+        }
+
+      /* For /g, update the start offset, leaving the rest alone */
+
+      if (do_g) start_offset = use_offsets[1];
+
+      /* For /G, update the pointer and length */
+
+      else
+        {
+        bptr += use_offsets[1];
+        len -= use_offsets[1];
+        }
+      }  /* End of loop for /g and /G */
+    }    /* End of loop for data lines */
+
+  CONTINUE:
+
+#if !defined NOPOSIX
+  if (posix || do_posix) regfree(&preg);
+#endif
+
+  if (re != NULL) free(re);
+  if (extra != NULL) free(extra);
+  if (tables != NULL)
+    {
+    free((void *)tables);
+    setlocale(LC_CTYPE, "C");
+    }
+  }
+
+if (infile == stdin) fprintf(outfile, "\n");
+return 0;
+}
+
+/* End */

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/perltest
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/perltest	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/perltest	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,211 @@
+#! /usr/bin/perl
+
+# Program for testing regular expressions with perl to check that PCRE handles
+# them the same. This is the version that supports /8 for UTF-8 testing. As it
+# stands, it requires at least Perl 5.8 for UTF-8 support. For Perl 5.6, it
+# can be used as is for non-UTF-8 testing, but you have to uncomment the
+# "use utf8" lines in order to to UTF-8 stuff (and you mustn't uncomment them
+# for non-UTF-8 use).
+
+
+# Function for turning a string into a string of printing chars. There are
+# currently problems with UTF-8 strings; this fudges round them.
+
+sub pchars {
+my($t) = "";
+
+if ($utf8)
+  {
+#  use utf8;                    <=============== For UTF-8 in Perl 5.6
+  @p = unpack('U*', $_[0]);
+  foreach $c (@p)
+    {
+    if ($c >= 32 && $c < 127) { $t .= chr $c; }
+      else { $t .= sprintf("\\x{%02x}", $c); }
+    }
+  }
+
+else
+  {
+  foreach $c (split(//, $_[0]))
+    {
+    if (ord $c >= 32 && ord $c < 127) { $t .= $c; }
+      else { $t .= sprintf("\\x%02x", ord $c); }
+    }
+  }
+
+$t;
+}
+
+
+
+# Read lines from named file or stdin and write to named file or stdout; lines
+# consist of a regular expression, in delimiters and optionally followed by
+# options, followed by a set of test data, terminated by an empty line.
+
+# Sort out the input and output files
+
+if (@ARGV > 0)
+  {
+  open(INFILE, "<$ARGV[0]") || die "Failed to open $ARGV[0]\n";
+  $infile = "INFILE";
+  }
+else { $infile = "STDIN"; }
+
+if (@ARGV > 1)
+  {
+  open(OUTFILE, ">$ARGV[1]") || die "Failed to open $ARGV[1]\n";
+  $outfile = "OUTFILE";
+  }
+else { $outfile = "STDOUT"; }
+
+printf($outfile "Perl $] Regular Expressions\n\n");
+
+# Main loop
+
+NEXT_RE:
+for (;;)
+  {
+  printf "  re> " if $infile eq "STDIN";
+  last if ! ($_ = <$infile>);
+  printf $outfile "$_" if $infile ne "STDIN";
+  next if ($_ eq "");
+
+  $pattern = $_;
+
+  while ($pattern !~ /^\s*(.).*\1/s)
+    {
+    printf "    > " if $infile eq "STDIN";
+    last if ! ($_ = <$infile>);
+    printf $outfile "$_" if $infile ne "STDIN";
+    $pattern .= $_;
+    }
+
+   chomp($pattern);
+   $pattern =~ s/\s+$//;
+
+  # The private /+ modifier means "print $' afterwards".
+
+  $showrest = ($pattern =~ s/\+(?=[a-z]*$)//);
+
+  # The private /8 modifier means "operate in UTF-8". Currently, Perl
+  # has bugs that we try to work around using this flag.
+
+  $utf8 = ($pattern =~ s/8(?=[a-z]*$)//);
+
+  # Check that the pattern is valid
+
+  if ($utf8)
+    {
+#    use utf8;                    <=============== For UTF-8 in Perl 5.6
+    eval "\$_ =~ ${pattern}";
+    }
+  else
+    {
+    eval "\$_ =~ ${pattern}";
+    }
+
+  if ($@)
+    {
+    printf $outfile "Error: $@";
+    next NEXT_RE;
+    }
+
+  # If the /g modifier is present, we want to put a loop round the matching;
+  # otherwise just a single "if".
+
+  $cmd = ($pattern =~ /g[a-z]*$/)? "while" : "if";
+
+  # If the pattern is actually the null string, Perl uses the most recently
+  # executed (and successfully compiled) regex is used instead. This is a
+  # nasty trap for the unwary! The PCRE test suite does contain null strings
+  # in places - if they are allowed through here all sorts of weird and
+  # unexpected effects happen. To avoid this, we replace such patterns with
+  # a non-null pattern that has the same effect.
+
+  $pattern = "/(?#)/$2" if ($pattern =~ /^(.)\1(.*)$/);
+
+  # Read data lines and test them
+
+  for (;;)
+    {
+    printf "data> " if $infile eq "STDIN";
+    last NEXT_RE if ! ($_ = <$infile>);
+    chomp;
+    printf $outfile "$_\n" if $infile ne "STDIN";
+
+    s/\s+$//;
+    s/^\s+//;
+
+    last if ($_ eq "");
+
+    $x = eval "\"$_\"";   # To get escapes processed
+
+    # Empty array for holding results, then do the matching.
+
+    @subs = ();
+
+    $pushes = "push \@subs,\$&;" .
+         "push \@subs,\$1;" .
+         "push \@subs,\$2;" .
+         "push \@subs,\$3;" .
+         "push \@subs,\$4;" .
+         "push \@subs,\$5;" .
+         "push \@subs,\$6;" .
+         "push \@subs,\$7;" .
+         "push \@subs,\$8;" .
+         "push \@subs,\$9;" .
+         "push \@subs,\$10;" .
+         "push \@subs,\$11;" .
+         "push \@subs,\$12;" .
+         "push \@subs,\$13;" .
+         "push \@subs,\$14;" .
+         "push \@subs,\$15;" .
+         "push \@subs,\$16;" .
+         "push \@subs,\$'; }";
+
+    if ($utf8)
+      {
+#      use utf8;                    <=============== For UTF-8 in Perl 5.6
+      eval "${cmd} (\$x =~ ${pattern}) {" . $pushes;
+      }
+    else
+      {
+      eval "${cmd} (\$x =~ ${pattern}) {" . $pushes;
+      }
+
+    if ($@)
+      {
+      printf $outfile "Error: $@\n";
+      next NEXT_RE;
+      }
+    elsif (scalar(@subs) == 0)
+      {
+      printf $outfile "No match\n";
+      }
+    else
+      {
+      while (scalar(@subs) != 0)
+        {
+        printf $outfile (" 0: %s\n", &pchars($subs[0]));
+        printf $outfile (" 0+ %s\n", &pchars($subs[17])) if $showrest;
+        $last_printed = 0;
+        for ($i = 1; $i <= 16; $i++)
+          {
+          if (defined $subs[$i])
+            {
+            while ($last_printed++ < $i-1)
+              { printf $outfile ("%2d: <unset>\n", $last_printed); }
+            printf $outfile ("%2d: %s\n", $i, &pchars($subs[$i]));
+            $last_printed = $i;
+            }
+          }
+        splice(@subs, 0, 18);
+        }
+      }
+    }
+  }
+
+# printf $outfile "\n";
+
+# End

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/perltest8
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/perltest8	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/perltest8	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,208 @@
+#! /usr/bin/perl
+
+# Program for testing regular expressions with perl to check that PCRE handles
+# them the same. This is the version that supports /8 for UTF-8 testing. It
+# requires at least Perl 5.6.
+
+
+# Function for turning a string into a string of printing chars. There are
+# currently problems with UTF-8 strings; this fudges round them.
+
+sub pchars {
+my($t) = "";
+
+if ($utf8)
+  {
+  use utf8;
+  @p = unpack('U*', $_[0]);
+  foreach $c (@p)
+    {
+    if ($c >= 32 && $c < 127) { $t .= chr $c; }
+      else { $t .= sprintf("\\x{%02x}", $c); }
+    }
+  }
+
+else
+  {
+  foreach $c (split(//, $_[0]))
+    {
+    if (ord $c >= 32 && ord $c < 127) { $t .= $c; }
+      else { $t .= sprintf("\\x%02x", ord $c); }
+    }
+  }
+
+$t;
+}
+
+
+
+# Read lines from named file or stdin and write to named file or stdout; lines
+# consist of a regular expression, in delimiters and optionally followed by
+# options, followed by a set of test data, terminated by an empty line.
+
+# Sort out the input and output files
+
+if (@ARGV > 0)
+  {
+  open(INFILE, "<$ARGV[0]") || die "Failed to open $ARGV[0]\n";
+  $infile = "INFILE";
+  }
+else { $infile = "STDIN"; }
+
+if (@ARGV > 1)
+  {
+  open(OUTFILE, ">$ARGV[1]") || die "Failed to open $ARGV[1]\n";
+  $outfile = "OUTFILE";
+  }
+else { $outfile = "STDOUT"; }
+
+printf($outfile "Perl $] Regular Expressions\n\n");
+
+# Main loop
+
+NEXT_RE:
+for (;;)
+  {
+  printf "  re> " if $infile eq "STDIN";
+  last if ! ($_ = <$infile>);
+  printf $outfile "$_" if $infile ne "STDIN";
+  next if ($_ eq "");
+
+  $pattern = $_;
+
+  while ($pattern !~ /^\s*(.).*\1/s)
+    {
+    printf "    > " if $infile eq "STDIN";
+    last if ! ($_ = <$infile>);
+    printf $outfile "$_" if $infile ne "STDIN";
+    $pattern .= $_;
+    }
+
+   chomp($pattern);
+   $pattern =~ s/\s+$//;
+
+  # The private /+ modifier means "print $' afterwards".
+
+  $showrest = ($pattern =~ s/\+(?=[a-z]*$)//);
+
+  # The private /8 modifier means "operate in UTF-8". Currently, Perl
+  # has bugs that we try to work around using this flag.
+
+  $utf8 = ($pattern =~ s/8(?=[a-z]*$)//);
+
+  # Check that the pattern is valid
+
+  if ($utf8)
+    {
+    use utf8;
+    eval "\$_ =~ ${pattern}";
+    }
+  else
+    {
+    eval "\$_ =~ ${pattern}";
+    }
+
+  if ($@)
+    {
+    printf $outfile "Error: $@";
+    next NEXT_RE;
+    }
+
+  # If the /g modifier is present, we want to put a loop round the matching;
+  # otherwise just a single "if".
+
+  $cmd = ($pattern =~ /g[a-z]*$/)? "while" : "if";
+
+  # If the pattern is actually the null string, Perl uses the most recently
+  # executed (and successfully compiled) regex is used instead. This is a
+  # nasty trap for the unwary! The PCRE test suite does contain null strings
+  # in places - if they are allowed through here all sorts of weird and
+  # unexpected effects happen. To avoid this, we replace such patterns with
+  # a non-null pattern that has the same effect.
+
+  $pattern = "/(?#)/$2" if ($pattern =~ /^(.)\1(.*)$/);
+
+  # Read data lines and test them
+
+  for (;;)
+    {
+    printf "data> " if $infile eq "STDIN";
+    last NEXT_RE if ! ($_ = <$infile>);
+    chomp;
+    printf $outfile "$_\n" if $infile ne "STDIN";
+
+    s/\s+$//;
+    s/^\s+//;
+
+    last if ($_ eq "");
+
+    $x = eval "\"$_\"";   # To get escapes processed
+
+    # Empty array for holding results, then do the matching.
+
+    @subs = ();
+
+    $pushes = "push \@subs,\$&;" .
+         "push \@subs,\$1;" .
+         "push \@subs,\$2;" .
+         "push \@subs,\$3;" .
+         "push \@subs,\$4;" .
+         "push \@subs,\$5;" .
+         "push \@subs,\$6;" .
+         "push \@subs,\$7;" .
+         "push \@subs,\$8;" .
+         "push \@subs,\$9;" .
+         "push \@subs,\$10;" .
+         "push \@subs,\$11;" .
+         "push \@subs,\$12;" .
+         "push \@subs,\$13;" .
+         "push \@subs,\$14;" .
+         "push \@subs,\$15;" .
+         "push \@subs,\$16;" .
+         "push \@subs,\$'; }";
+
+    if ($utf8)
+      {
+      use utf8;
+      eval "${cmd} (\$x =~ ${pattern}) {" . $pushes;
+      }
+    else
+      {
+      eval "${cmd} (\$x =~ ${pattern}) {" . $pushes;
+      }
+
+    if ($@)
+      {
+      printf $outfile "Error: $@\n";
+      next NEXT_RE;
+      }
+    elsif (scalar(@subs) == 0)
+      {
+      printf $outfile "No match\n";
+      }
+    else
+      {
+      while (scalar(@subs) != 0)
+        {
+        printf $outfile (" 0: %s\n", &pchars($subs[0]));
+        printf $outfile (" 0+ %s\n", &pchars($subs[17])) if $showrest;
+        $last_printed = 0;
+        for ($i = 1; $i <= 16; $i++)
+          {
+          if (defined $subs[$i])
+            {
+            while ($last_printed++ < $i-1)
+              { printf $outfile ("%2d: <unset>\n", $last_printed); }
+            printf $outfile ("%2d: %s\n", $i, &pchars($subs[$i]));
+            $last_printed = $i;
+            }
+          }
+        splice(@subs, 0, 18);
+        }
+      }
+    }
+  }
+
+printf $outfile "\n";
+
+# End

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/pgrep.c
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/pgrep.c	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/pgrep.c	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,225 @@
+/*************************************************
+*               PCRE grep program                *
+*************************************************/
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include "config.h"
+#include "pcre.h"
+
+#define FALSE 0
+#define TRUE 1
+
+typedef int BOOL;
+
+
+
+/*************************************************
+*               Global variables                 *
+*************************************************/
+
+static pcre *pattern;
+static pcre_extra *hints;
+
+static BOOL count_only = FALSE;
+static BOOL filenames_only = FALSE;
+static BOOL invert = FALSE;
+static BOOL number = FALSE;
+static BOOL silent = FALSE;
+static BOOL whole_lines = FALSE;
+
+
+
+#if ! HAVE_STRERROR
+/*************************************************
+*     Provide strerror() for non-ANSI libraries  *
+*************************************************/
+
+/* Some old-fashioned systems still around (e.g. SunOS4) don't have strerror()
+in their libraries, but can provide the same facility by this simple
+alternative function. */
+
+extern int   sys_nerr;
+extern char *sys_errlist[];
+
+char *
+strerror(int n)
+{
+if (n < 0 || n >= sys_nerr) return "unknown error number";
+return sys_errlist[n];
+}
+#endif /* HAVE_STRERROR */
+
+
+
+/*************************************************
+*              Grep an individual file           *
+*************************************************/
+
+static int
+pgrep(FILE *in, char *name)
+{
+int rc = 1;
+int linenumber = 0;
+int count = 0;
+int offsets[99];
+char buffer[BUFSIZ];
+
+while (fgets(buffer, sizeof(buffer), in) != NULL)
+  {
+  BOOL match;
+  int length = (int)strlen(buffer);
+  if (length > 0 && buffer[length-1] == '\n') buffer[--length] = 0;
+  linenumber++;
+
+  match = pcre_exec(pattern, hints, buffer, length, 0, 0, offsets, 99) >= 0;
+  if (match && whole_lines && offsets[1] != length) match = FALSE;
+
+  if (match != invert)
+    {
+    if (count_only) count++;
+
+    else if (filenames_only)
+      {
+      fprintf(stdout, "%s\n", (name == NULL)? "<stdin>" : name);
+      return 0;
+      }
+
+    else if (silent) return 0;
+
+    else
+      {
+      if (name != NULL) fprintf(stdout, "%s:", name);
+      if (number) fprintf(stdout, "%d:", linenumber);
+      fprintf(stdout, "%s\n", buffer);
+      }
+
+    rc = 0;
+    }
+  }
+
+if (count_only)
+  {
+  if (name != NULL) fprintf(stdout, "%s:", name);
+  fprintf(stdout, "%d\n", count);
+  }
+
+return rc;
+}
+
+
+
+
+/*************************************************
+*                Usage function                  *
+*************************************************/
+
+static int
+usage(int rc)
+{
+fprintf(stderr, "Usage: pgrep [-Vchilnsvx] pattern [file] ...\n");
+return rc;
+}
+
+
+
+
+/*************************************************
+*                Main program                    *
+*************************************************/
+
+int
+main(int argc, char **argv)
+{
+int i;
+int rc = 1;
+int options = 0;
+int errptr;
+const char *error;
+BOOL filenames = TRUE;
+
+/* Process the options */
+
+for (i = 1; i < argc; i++)
+  {
+  char *s;
+  if (argv[i][0] != '-') break;
+  s = argv[i] + 1;
+  while (*s != 0)
+    {
+    switch (*s++)
+      {
+      case 'c': count_only = TRUE; break;
+      case 'h': filenames = FALSE; break;
+      case 'i': options |= PCRE_CASELESS; break;
+      case 'l': filenames_only = TRUE;
+      case 'n': number = TRUE; break;
+      case 's': silent = TRUE; break;
+      case 'v': invert = TRUE; break;
+      case 'x': whole_lines = TRUE; options |= PCRE_ANCHORED; break;
+
+      case 'V':
+      fprintf(stderr, "PCRE version %s\n", pcre_version());
+      break;
+
+      default:
+      fprintf(stderr, "pgrep: unknown option %c\n", s[-1]);
+      return usage(2);
+      }
+    }
+  }
+
+/* There must be at least a regexp argument */
+
+if (i >= argc) return usage(0);
+
+/* Compile the regular expression. */
+
+pattern = pcre_compile(argv[i++], options, &error, &errptr, NULL);
+if (pattern == NULL)
+  {
+  fprintf(stderr, "pgrep: error in regex at offset %d: %s\n", errptr, error);
+  return 2;
+  }
+
+/* Study the regular expression, as we will be running it may times */
+
+hints = pcre_study(pattern, 0, &error);
+if (error != NULL)
+  {
+  fprintf(stderr, "pgrep: error while studing regex: %s\n", error);
+  return 2;
+  }
+
+/* If there are no further arguments, do the business on stdin and exit */
+
+if (i >= argc) return pgrep(stdin, NULL);
+
+/* Otherwise, work through the remaining arguments as files. If there is only
+one, don't give its name on the output. */
+
+if (i == argc - 1) filenames = FALSE;
+if (filenames_only) filenames = TRUE;
+
+for (; i < argc; i++)
+  {
+  FILE *in = fopen(argv[i], "r");
+  if (in == NULL)
+    {
+    fprintf(stderr, "%s: failed to open: %s\n", argv[i], strerror(errno));
+    rc = 2;
+    }
+  else
+    {
+    int frc = pgrep(in, filenames? argv[i] : NULL);
+    if (frc == 0 && rc == 1) rc = 0;
+    fclose(in);
+    }
+  }
+
+return rc;
+}
+
+/* End */

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/printint.c
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/printint.c	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/printint.c	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,471 @@
+/*************************************************
+*      Perl-Compatible Regular Expressions       *
+*************************************************/
+
+/*
+This is a library of functions to support regular expressions whose syntax
+and semantics are as close as possible to those of the Perl 5 language. See
+the file Tech.Notes for some information on the internals.
+
+Written by: Philip Hazel <ph10 at cam.ac.uk>
+
+           Copyright (c) 1997-2004 University of Cambridge
+
+-----------------------------------------------------------------------------
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice,
+      this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+
+    * Neither the name of the University of Cambridge nor the names of its
+      contributors may be used to endorse or promote products derived from
+      this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+-----------------------------------------------------------------------------
+*/
+
+
+/* This module contains a debugging function for printing out the internal form
+of a compiled regular expression. It is kept in a separate file so that it can
+be #included both in the pcretest program, and in the library itself when
+compiled with the debugging switch. */
+
+
+static const char *OP_names[] = { OP_NAME_LIST };
+
+
+/*************************************************
+*       Print single- or multi-byte character    *
+*************************************************/
+
+/* These tables are actually copies of ones in pcre.c. If we compile the
+library with debugging, they are included twice, but that isn't really a
+problem - compiling with debugging is pretty rare and these are very small. */
+
+static const int utf8_t3[] = { 0xff, 0x1f, 0x0f, 0x07, 0x03, 0x01};
+
+static const uschar utf8_t4[] = {
+  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,
+  2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+  3,3,3,3,3,3,3,3,4,4,4,4,5,5,5,5 };
+
+static int
+print_char(FILE *f, uschar *ptr, BOOL utf8)
+{
+int c = *ptr;
+
+if (!utf8 || (c & 0xc0) != 0xc0)
+  {
+  if (isprint(c)) fprintf(f, "%c", c); else fprintf(f, "\\x%02x", c);
+  return 0;
+  }
+else
+  {
+  int i;
+  int a = utf8_t4[c & 0x3f];  /* Number of additional bytes */
+  int s = 6*a;
+  c = (c & utf8_t3[a]) << s;
+  for (i = 1; i <= a; i++)
+    {
+    /* This is a check for malformed UTF-8; it should only occur if the sanity
+    check has been turned off. Rather than swallow random bytes, just stop if
+    we hit a bad one. Print it with \X instead of \x as an indication. */
+
+    if ((ptr[i] & 0xc0) != 0x80)
+      {
+      fprintf(f, "\\X{%x}", c);
+      return i - 1;
+      }
+
+    /* The byte is OK */
+
+    s -= 6;
+    c |= (ptr[i] & 0x3f) << s;
+    }
+  if (c < 128) fprintf(f, "\\x%02x", c); else fprintf(f, "\\x{%x}", c);
+  return a;
+  }
+}
+
+
+
+
+#ifdef SUPPORT_UCP
+/*************************************************
+*          Find Unicode property name            *
+*************************************************/
+
+static const char *
+get_ucpname(int property)
+{
+int i;
+for (i = sizeof(utt)/sizeof(ucp_type_table); i >= 0; i--)
+  {
+  if (property == utt[i].value) break;
+  }
+return (i >= 0)? utt[i].name : "??";
+}
+#endif /* SUPPORT_UCP */
+
+
+
+/*************************************************
+*         Print compiled regex                   *
+*************************************************/
+
+/* Make this function work for a regex with integers either byte order.
+However, we assume that what we are passed is a compiled regex. */
+
+static void
+print_internals(pcre *external_re, FILE *f)
+{
+real_pcre *re = (real_pcre *)external_re;
+uschar *codestart, *code;
+BOOL utf8;
+
+unsigned int options = re->options;
+int offset = re->name_table_offset;
+int count = re->name_count;
+int size = re->name_entry_size;
+
+if (re->magic_number != MAGIC_NUMBER)
+  {
+  offset = ((offset << 8) & 0xff00) | ((offset >> 8) & 0xff);
+  count = ((count << 8) & 0xff00) | ((count >> 8) & 0xff);
+  size = ((size << 8) & 0xff00) | ((size >> 8) & 0xff);
+  options = ((options << 24) & 0xff000000) |
+            ((options <<  8) & 0x00ff0000) |
+            ((options >>  8) & 0x0000ff00) |
+            ((options >> 24) & 0x000000ff);
+  }
+
+code = codestart = (uschar *)re + offset + count * size;
+utf8 = (options & PCRE_UTF8) != 0;
+
+for(;;)
+  {
+  uschar *ccode;
+  int c;
+  int extra = 0;
+
+  fprintf(f, "%3d ", code - codestart);
+
+  if (*code >= OP_BRA)
+    {
+    if (*code - OP_BRA > EXTRACT_BASIC_MAX)
+      fprintf(f, "%3d Bra extra\n", GET(code, 1));
+    else
+      fprintf(f, "%3d Bra %d\n", GET(code, 1), *code - OP_BRA);
+    code += OP_lengths[OP_BRA];
+    continue;
+    }
+
+  switch(*code)
+    {
+    case OP_END:
+    fprintf(f, "    %s\n", OP_names[*code]);
+    fprintf(f, "------------------------------------------------------------------\n");
+    return;
+
+    case OP_OPT:
+    fprintf(f, " %.2x %s", code[1], OP_names[*code]);
+    break;
+
+    case OP_CHAR:
+      {
+      fprintf(f, "    ");
+      do
+        {
+        code++;
+        code += 1 + print_char(f, code, utf8);
+        }
+      while (*code == OP_CHAR);
+      fprintf(f, "\n");
+      continue;
+      }
+    break;
+
+    case OP_CHARNC:
+      {
+      fprintf(f, " NC ");
+      do
+        {
+        code++;
+        code += 1 + print_char(f, code, utf8);
+        }
+      while (*code == OP_CHARNC);
+      fprintf(f, "\n");
+      continue;
+      }
+    break;
+
+    case OP_KETRMAX:
+    case OP_KETRMIN:
+    case OP_ALT:
+    case OP_KET:
+    case OP_ASSERT:
+    case OP_ASSERT_NOT:
+    case OP_ASSERTBACK:
+    case OP_ASSERTBACK_NOT:
+    case OP_ONCE:
+    case OP_COND:
+    case OP_REVERSE:
+    fprintf(f, "%3d %s", GET(code, 1), OP_names[*code]);
+    break;
+
+    case OP_BRANUMBER:
+    printf("%3d %s", GET2(code, 1), OP_names[*code]);
+    break;
+
+    case OP_CREF:
+    if (GET2(code, 1) == CREF_RECURSE)
+      fprintf(f, "    Cond recurse");
+    else
+      fprintf(f, "%3d %s", GET2(code,1), OP_names[*code]);
+    break;
+
+    case OP_STAR:
+    case OP_MINSTAR:
+    case OP_PLUS:
+    case OP_MINPLUS:
+    case OP_QUERY:
+    case OP_MINQUERY:
+    case OP_TYPESTAR:
+    case OP_TYPEMINSTAR:
+    case OP_TYPEPLUS:
+    case OP_TYPEMINPLUS:
+    case OP_TYPEQUERY:
+    case OP_TYPEMINQUERY:
+    fprintf(f, "    ");
+    if (*code >= OP_TYPESTAR)
+      {
+      fprintf(f, "%s", OP_names[code[1]]);
+#ifdef SUPPORT_UCP
+      if (code[1] == OP_PROP || code[1] == OP_NOTPROP)
+        {
+        fprintf(f, " %s ", get_ucpname(code[2]));
+        extra = 1;
+        }
+#endif
+      }
+    else extra = print_char(f, code+1, utf8);
+    fprintf(f, "%s", OP_names[*code]);
+    break;
+
+    case OP_EXACT:
+    case OP_UPTO:
+    case OP_MINUPTO:
+    fprintf(f, "    ");
+    extra = print_char(f, code+3, utf8);
+    fprintf(f, "{");
+    if (*code != OP_EXACT) fprintf(f, ",");
+    fprintf(f, "%d}", GET2(code,1));
+    if (*code == OP_MINUPTO) fprintf(f, "?");
+    break;
+
+    case OP_TYPEEXACT:
+    case OP_TYPEUPTO:
+    case OP_TYPEMINUPTO:
+    fprintf(f, "    %s", OP_names[code[3]]);
+#ifdef SUPPORT_UCP
+    if (code[3] == OP_PROP || code[3] == OP_NOTPROP)
+      {
+      fprintf(f, " %s ", get_ucpname(code[4]));
+      extra = 1;
+      }
+#endif
+    fprintf(f, "{");
+    if (*code != OP_TYPEEXACT) fprintf(f, "0,");
+    fprintf(f, "%d}", GET2(code,1));
+    if (*code == OP_TYPEMINUPTO) fprintf(f, "?");
+    break;
+
+    case OP_NOT:
+    if (isprint(c = code[1])) fprintf(f, "    [^%c]", c);
+      else fprintf(f, "    [^\\x%02x]", c);
+    break;
+
+    case OP_NOTSTAR:
+    case OP_NOTMINSTAR:
+    case OP_NOTPLUS:
+    case OP_NOTMINPLUS:
+    case OP_NOTQUERY:
+    case OP_NOTMINQUERY:
+    if (isprint(c = code[1])) fprintf(f, "    [^%c]", c);
+      else fprintf(f, "    [^\\x%02x]", c);
+    fprintf(f, "%s", OP_names[*code]);
+    break;
+
+    case OP_NOTEXACT:
+    case OP_NOTUPTO:
+    case OP_NOTMINUPTO:
+    if (isprint(c = code[3])) fprintf(f, "    [^%c]{", c);
+      else fprintf(f, "    [^\\x%02x]{", c);
+    if (*code != OP_NOTEXACT) fprintf(f, ",");
+    fprintf(f, "%d}", GET2(code,1));
+    if (*code == OP_NOTMINUPTO) fprintf(f, "?");
+    break;
+
+    case OP_RECURSE:
+    fprintf(f, "%3d %s", GET(code, 1), OP_names[*code]);
+    break;
+
+    case OP_REF:
+    fprintf(f, "    \\%d", GET2(code,1));
+    ccode = code + OP_lengths[*code];
+    goto CLASS_REF_REPEAT;
+
+    case OP_CALLOUT:
+    fprintf(f, "    %s %d %d %d", OP_names[*code], code[1], GET(code,2),
+      GET(code, 2 + LINK_SIZE));
+    break;
+
+#ifdef SUPPORT_UCP
+    case OP_PROP:
+    case OP_NOTPROP:
+    fprintf(f, "    %s %s", OP_names[*code], get_ucpname(code[1]));
+    break;
+#endif
+
+    /* OP_XCLASS can only occur in UTF-8 mode. However, there's no harm in
+    having this code always here, and it makes it less messy without all those
+    #ifdefs. */
+
+    case OP_CLASS:
+    case OP_NCLASS:
+    case OP_XCLASS:
+      {
+      int i, min, max;
+      BOOL printmap;
+
+      fprintf(f, "    [");
+
+      if (*code == OP_XCLASS)
+        {
+        extra = GET(code, 1);
+        ccode = code + LINK_SIZE + 1;
+        printmap = (*ccode & XCL_MAP) != 0;
+        if ((*ccode++ & XCL_NOT) != 0) fprintf(f, "^");
+        }
+      else
+        {
+        printmap = TRUE;
+        ccode = code + 1;
+        }
+
+      /* Print a bit map */
+
+      if (printmap)
+        {
+        for (i = 0; i < 256; i++)
+          {
+          if ((ccode[i/8] & (1 << (i&7))) != 0)
+            {
+            int j;
+            for (j = i+1; j < 256; j++)
+              if ((ccode[j/8] & (1 << (j&7))) == 0) break;
+            if (i == '-' || i == ']') fprintf(f, "\\");
+            if (isprint(i)) fprintf(f, "%c", i); else fprintf(f, "\\x%02x", i);
+            if (--j > i)
+              {
+              if (j != i + 1) fprintf(f, "-");
+              if (j == '-' || j == ']') fprintf(f, "\\");
+              if (isprint(j)) fprintf(f, "%c", j); else fprintf(f, "\\x%02x", j);
+              }
+            i = j;
+            }
+          }
+        ccode += 32;
+        }
+
+      /* For an XCLASS there is always some additional data */
+
+      if (*code == OP_XCLASS)
+        {
+        int ch;
+        while ((ch = *ccode++) != XCL_END)
+          {
+#ifdef SUPPORT_UCP
+          if (ch == XCL_PROP)
+            {
+            fprintf(f, "\\p{%s}", get_ucpname(*ccode++));
+            }
+          else if (ch == XCL_NOTPROP)
+            {
+            fprintf(f, "\\P{%s}", get_ucpname(*ccode++));
+            }
+          else
+#endif
+            {
+            ccode += 1 + print_char(f, ccode, TRUE);
+            if (ch == XCL_RANGE)
+              {
+              fprintf(f, "-");
+              ccode += 1 + print_char(f, ccode, TRUE);
+              }
+            }
+          }
+        }
+
+      /* Indicate a non-UTF8 class which was created by negation */
+
+      fprintf(f, "]%s", (*code == OP_NCLASS)? " (neg)" : "");
+
+      /* Handle repeats after a class or a back reference */
+
+      CLASS_REF_REPEAT:
+      switch(*ccode)
+        {
+        case OP_CRSTAR:
+        case OP_CRMINSTAR:
+        case OP_CRPLUS:
+        case OP_CRMINPLUS:
+        case OP_CRQUERY:
+        case OP_CRMINQUERY:
+        fprintf(f, "%s", OP_names[*ccode]);
+        extra += OP_lengths[*ccode];
+        break;
+
+        case OP_CRRANGE:
+        case OP_CRMINRANGE:
+        min = GET2(ccode,1);
+        max = GET2(ccode,3);
+        if (max == 0) fprintf(f, "{%d,}", min);
+        else fprintf(f, "{%d,%d}", min, max);
+        if (*ccode == OP_CRMINRANGE) fprintf(f, "?");
+        extra += OP_lengths[*ccode];
+        break;
+        }
+      }
+    break;
+
+    /* Anything else is just an item with no data*/
+
+    default:
+    fprintf(f, "    %s", OP_names[*code]);
+    break;
+    }
+
+  code += OP_lengths[*code] + extra;
+  fprintf(f, "\n");
+  }
+}
+
+/* End of printint.c */

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/study.c
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/study.c	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/study.c	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,484 @@
+/*************************************************
+*      Perl-Compatible Regular Expressions       *
+*************************************************/
+
+/*
+This is a library of functions to support regular expressions whose syntax
+and semantics are as close as possible to those of the Perl 5 language. See
+the file Tech.Notes for some information on the internals.
+
+Written by: Philip Hazel <ph10 at cam.ac.uk>
+
+           Copyright (c) 1997-2004 University of Cambridge
+
+-----------------------------------------------------------------------------
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice,
+      this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+
+    * Neither the name of the University of Cambridge nor the names of its
+      contributors may be used to endorse or promote products derived from
+      this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+-----------------------------------------------------------------------------
+*/
+
+
+/* Include the internals header, which itself includes Standard C headers plus
+the external pcre header. */
+
+#include "internal.h"
+
+
+
+/*************************************************
+*      Set a bit and maybe its alternate case    *
+*************************************************/
+
+/* Given a character, set its bit in the table, and also the bit for the other
+version of a letter if we are caseless.
+
+Arguments:
+  start_bits    points to the bit map
+  c             is the character
+  caseless      the caseless flag
+  cd            the block with char table pointers
+
+Returns:        nothing
+*/
+
+static void
+set_bit(uschar *start_bits, unsigned int c, BOOL caseless, compile_data *cd)
+{
+start_bits[c/8] |= (1 << (c&7));
+if (caseless && (cd->ctypes[c] & ctype_letter) != 0)
+  start_bits[cd->fcc[c]/8] |= (1 << (cd->fcc[c]&7));
+}
+
+
+
+/*************************************************
+*          Create bitmap of starting chars       *
+*************************************************/
+
+/* This function scans a compiled unanchored expression and attempts to build a
+bitmap of the set of initial characters. If it can't, it returns FALSE. As time
+goes by, we may be able to get more clever at doing this.
+
+Arguments:
+  code         points to an expression
+  start_bits   points to a 32-byte table, initialized to 0
+  caseless     the current state of the caseless flag
+  utf8         TRUE if in UTF-8 mode
+  cd           the block with char table pointers
+
+Returns:       TRUE if table built, FALSE otherwise
+*/
+
+static BOOL
+set_start_bits(const uschar *code, uschar *start_bits, BOOL caseless,
+  BOOL utf8, compile_data *cd)
+{
+register int c;
+
+/* This next statement and the later reference to dummy are here in order to
+trick the optimizer of the IBM C compiler for OS/2 into generating correct
+code. Apparently IBM isn't going to fix the problem, and we would rather not
+disable optimization (in this module it actually makes a big difference, and
+the pcre module can use all the optimization it can get). */
+
+volatile int dummy;
+
+do
+  {
+  const uschar *tcode = code + 1 + LINK_SIZE;
+  BOOL try_next = TRUE;
+
+  while (try_next)
+    {
+    /* If a branch starts with a bracket or a positive lookahead assertion,
+    recurse to set bits from within them. That's all for this branch. */
+
+    if ((int)*tcode >= OP_BRA || *tcode == OP_ASSERT)
+      {
+      if (!set_start_bits(tcode, start_bits, caseless, utf8, cd))
+        return FALSE;
+      try_next = FALSE;
+      }
+
+    else switch(*tcode)
+      {
+      default:
+      return FALSE;
+
+      /* Skip over callout */
+
+      case OP_CALLOUT:
+      tcode += 2 + 2*LINK_SIZE;
+      break;
+
+      /* Skip over extended extraction bracket number */
+
+      case OP_BRANUMBER:
+      tcode += 3;
+      break;
+
+      /* Skip over lookbehind and negative lookahead assertions */
+
+      case OP_ASSERT_NOT:
+      case OP_ASSERTBACK:
+      case OP_ASSERTBACK_NOT:
+      do tcode += GET(tcode, 1); while (*tcode == OP_ALT);
+      tcode += 1+LINK_SIZE;
+      break;
+
+      /* Skip over an option setting, changing the caseless flag */
+
+      case OP_OPT:
+      caseless = (tcode[1] & PCRE_CASELESS) != 0;
+      tcode += 2;
+      break;
+
+      /* BRAZERO does the bracket, but carries on. */
+
+      case OP_BRAZERO:
+      case OP_BRAMINZERO:
+      if (!set_start_bits(++tcode, start_bits, caseless, utf8, cd))
+        return FALSE;
+      dummy = 1;
+      do tcode += GET(tcode,1); while (*tcode == OP_ALT);
+      tcode += 1+LINK_SIZE;
+      break;
+
+      /* Single-char * or ? sets the bit and tries the next item */
+
+      case OP_STAR:
+      case OP_MINSTAR:
+      case OP_QUERY:
+      case OP_MINQUERY:
+      set_bit(start_bits, tcode[1], caseless, cd);
+      tcode += 2;
+#ifdef SUPPORT_UTF8
+      if (utf8) while ((*tcode & 0xc0) == 0x80) tcode++;
+#endif
+      break;
+
+      /* Single-char upto sets the bit and tries the next */
+
+      case OP_UPTO:
+      case OP_MINUPTO:
+      set_bit(start_bits, tcode[3], caseless, cd);
+      tcode += 4;
+#ifdef SUPPORT_UTF8
+      if (utf8) while ((*tcode & 0xc0) == 0x80) tcode++;
+#endif
+      break;
+
+      /* At least one single char sets the bit and stops */
+
+      case OP_EXACT:       /* Fall through */
+      tcode += 2;
+
+      case OP_CHAR:
+      case OP_CHARNC:
+      case OP_PLUS:
+      case OP_MINPLUS:
+      set_bit(start_bits, tcode[1], caseless, cd);
+      try_next = FALSE;
+      break;
+
+      /* Single character type sets the bits and stops */
+
+      case OP_NOT_DIGIT:
+      for (c = 0; c < 32; c++)
+        start_bits[c] |= ~cd->cbits[c+cbit_digit];
+      try_next = FALSE;
+      break;
+
+      case OP_DIGIT:
+      for (c = 0; c < 32; c++)
+        start_bits[c] |= cd->cbits[c+cbit_digit];
+      try_next = FALSE;
+      break;
+
+      case OP_NOT_WHITESPACE:
+      for (c = 0; c < 32; c++)
+        start_bits[c] |= ~cd->cbits[c+cbit_space];
+      try_next = FALSE;
+      break;
+
+      case OP_WHITESPACE:
+      for (c = 0; c < 32; c++)
+        start_bits[c] |= cd->cbits[c+cbit_space];
+      try_next = FALSE;
+      break;
+
+      case OP_NOT_WORDCHAR:
+      for (c = 0; c < 32; c++)
+        start_bits[c] |= ~cd->cbits[c+cbit_word];
+      try_next = FALSE;
+      break;
+
+      case OP_WORDCHAR:
+      for (c = 0; c < 32; c++)
+        start_bits[c] |= cd->cbits[c+cbit_word];
+      try_next = FALSE;
+      break;
+
+      /* One or more character type fudges the pointer and restarts, knowing
+      it will hit a single character type and stop there. */
+
+      case OP_TYPEPLUS:
+      case OP_TYPEMINPLUS:
+      tcode++;
+      break;
+
+      case OP_TYPEEXACT:
+      tcode += 3;
+      break;
+
+      /* Zero or more repeats of character types set the bits and then
+      try again. */
+
+      case OP_TYPEUPTO:
+      case OP_TYPEMINUPTO:
+      tcode += 2;               /* Fall through */
+
+      case OP_TYPESTAR:
+      case OP_TYPEMINSTAR:
+      case OP_TYPEQUERY:
+      case OP_TYPEMINQUERY:
+      switch(tcode[1])
+        {
+        case OP_ANY:
+        return FALSE;
+
+        case OP_NOT_DIGIT:
+        for (c = 0; c < 32; c++)
+          start_bits[c] |= ~cd->cbits[c+cbit_digit];
+        break;
+
+        case OP_DIGIT:
+        for (c = 0; c < 32; c++)
+          start_bits[c] |= cd->cbits[c+cbit_digit];
+        break;
+
+        case OP_NOT_WHITESPACE:
+        for (c = 0; c < 32; c++)
+          start_bits[c] |= ~cd->cbits[c+cbit_space];
+        break;
+
+        case OP_WHITESPACE:
+        for (c = 0; c < 32; c++)
+          start_bits[c] |= cd->cbits[c+cbit_space];
+        break;
+
+        case OP_NOT_WORDCHAR:
+        for (c = 0; c < 32; c++)
+          start_bits[c] |= ~cd->cbits[c+cbit_word];
+        break;
+
+        case OP_WORDCHAR:
+        for (c = 0; c < 32; c++)
+          start_bits[c] |= cd->cbits[c+cbit_word];
+        break;
+        }
+
+      tcode += 2;
+      break;
+
+      /* Character class where all the information is in a bit map: set the
+      bits and either carry on or not, according to the repeat count. If it was
+      a negative class, and we are operating with UTF-8 characters, any byte
+      with a value >= 0xc4 is a potentially valid starter because it starts a
+      character with a value > 255. */
+
+      case OP_NCLASS:
+      if (utf8)
+        {
+        start_bits[24] |= 0xf0;              /* Bits for 0xc4 - 0xc8 */
+        memset(start_bits+25, 0xff, 7);      /* Bits for 0xc9 - 0xff */
+        }
+      /* Fall through */
+
+      case OP_CLASS:
+        {
+        tcode++;
+
+        /* In UTF-8 mode, the bits in a bit map correspond to character
+        values, not to byte values. However, the bit map we are constructing is
+        for byte values. So we have to do a conversion for characters whose
+        value is > 127. In fact, there are only two possible starting bytes for
+        characters in the range 128 - 255. */
+
+        if (utf8)
+          {
+          for (c = 0; c < 16; c++) start_bits[c] |= tcode[c];
+          for (c = 128; c < 256; c++)
+            {
+            if ((tcode[c/8] && (1 << (c&7))) != 0)
+              {
+              int d = (c >> 6) | 0xc0;            /* Set bit for this starter */
+              start_bits[d/8] |= (1 << (d&7));    /* and then skip on to the */
+              c = (c & 0xc0) + 0x40 - 1;          /* next relevant character. */
+              }
+            }
+          }
+
+        /* In non-UTF-8 mode, the two bit maps are completely compatible. */
+
+        else
+          {
+          for (c = 0; c < 32; c++) start_bits[c] |= tcode[c];
+          }
+
+        /* Advance past the bit map, and act on what follows */
+
+        tcode += 32;
+        switch (*tcode)
+          {
+          case OP_CRSTAR:
+          case OP_CRMINSTAR:
+          case OP_CRQUERY:
+          case OP_CRMINQUERY:
+          tcode++;
+          break;
+
+          case OP_CRRANGE:
+          case OP_CRMINRANGE:
+          if (((tcode[1] << 8) + tcode[2]) == 0) tcode += 5;
+            else try_next = FALSE;
+          break;
+
+          default:
+          try_next = FALSE;
+          break;
+          }
+        }
+      break; /* End of bitmap class handling */
+
+      }      /* End of switch */
+    }        /* End of try_next loop */
+
+  code += GET(code, 1);   /* Advance to next branch */
+  }
+while (*code == OP_ALT);
+return TRUE;
+}
+
+
+
+/*************************************************
+*          Study a compiled expression           *
+*************************************************/
+
+/* This function is handed a compiled expression that it must study to produce
+information that will speed up the matching. It returns a pcre_extra block
+which then gets handed back to pcre_exec().
+
+Arguments:
+  re        points to the compiled expression
+  options   contains option bits
+  errorptr  points to where to place error messages;
+            set NULL unless error
+
+Returns:    pointer to a pcre_extra block, with study_data filled in and the
+              appropriate flag set;
+            NULL on error or if no optimization possible
+*/
+
+EXPORT pcre_extra *
+pcre_study(const pcre *external_re, int options, const char **errorptr)
+{
+uschar start_bits[32];
+pcre_extra *extra;
+pcre_study_data *study;
+const uschar *tables;
+const real_pcre *re = (const real_pcre *)external_re;
+uschar *code = (uschar *)re + re->name_table_offset +
+  (re->name_count * re->name_entry_size);
+compile_data compile_block;
+
+*errorptr = NULL;
+
+if (re == NULL || re->magic_number != MAGIC_NUMBER)
+  {
+  *errorptr = "argument is not a compiled regular expression";
+  return NULL;
+  }
+
+if ((options & ~PUBLIC_STUDY_OPTIONS) != 0)
+  {
+  *errorptr = "unknown or incorrect option bit(s) set";
+  return NULL;
+  }
+
+/* For an anchored pattern, or an unanchored pattern that has a first char, or
+a multiline pattern that matches only at "line starts", no further processing
+at present. */
+
+if ((re->options & (PCRE_ANCHORED|PCRE_FIRSTSET|PCRE_STARTLINE)) != 0)
+  return NULL;
+
+/* Set the character tables in the block that is passed around */
+
+tables = re->tables;
+if (tables == NULL)
+  (void)pcre_fullinfo(external_re, NULL, PCRE_INFO_DEFAULT_TABLES, (void*)&tables);
+
+compile_block.lcc = tables + lcc_offset;
+compile_block.fcc = tables + fcc_offset;
+compile_block.cbits = tables + cbits_offset;
+compile_block.ctypes = tables + ctypes_offset;
+
+/* See if we can find a fixed set of initial characters for the pattern. */
+
+memset(start_bits, 0, 32 * sizeof(uschar));
+if (!set_start_bits(code, start_bits, (re->options & PCRE_CASELESS) != 0,
+  (re->options & PCRE_UTF8) != 0, &compile_block)) return NULL;
+
+/* Get a pcre_extra block and a pcre_study_data block. The study data is put in
+the latter, which is pointed to by the former, which may also get additional
+data set later by the calling program. At the moment, the size of
+pcre_study_data is fixed. We nevertheless save it in a field for returning via
+the pcre_fullinfo() function so that if it becomes variable in the future, we
+don't have to change that code. */
+
+extra = (pcre_extra *)(pcre_malloc)
+  (sizeof(pcre_extra) + sizeof(pcre_study_data));
+
+if (extra == NULL)
+  {
+  *errorptr = "failed to get memory";
+  return NULL;
+  }
+
+study = (pcre_study_data *)((char *)extra + sizeof(pcre_extra));
+extra->flags = PCRE_EXTRA_STUDY_DATA;
+extra->study_data = study;
+
+study->size = sizeof(pcre_study_data);
+study->options = PCRE_STUDY_MAPPED;
+memcpy(study->start_bits, start_bits, sizeof(start_bits));
+
+return extra;
+}
+
+/* End of study.c */

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/testdata/testinput1
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/testdata/testinput1	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/testdata/testinput1	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,3842 @@
+/the quick brown fox/
+    the quick brown fox
+    The quick brown FOX
+    What do you know about the quick brown fox?
+    What do you know about THE QUICK BROWN FOX?
+
+/The quick brown fox/i
+    the quick brown fox
+    The quick brown FOX
+    What do you know about the quick brown fox?
+    What do you know about THE QUICK BROWN FOX?
+
+/abcd\t\n\r\f\a\e\071\x3b\$\\\?caxyz/
+    abcd\t\n\r\f\a\e9;\$\\?caxyz
+
+/a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz/
+    abxyzpqrrrabbxyyyypqAzz
+    abxyzpqrrrabbxyyyypqAzz
+    aabxyzpqrrrabbxyyyypqAzz
+    aaabxyzpqrrrabbxyyyypqAzz
+    aaaabxyzpqrrrabbxyyyypqAzz
+    abcxyzpqrrrabbxyyyypqAzz
+    aabcxyzpqrrrabbxyyyypqAzz
+    aaabcxyzpqrrrabbxyyyypAzz
+    aaabcxyzpqrrrabbxyyyypqAzz
+    aaabcxyzpqrrrabbxyyyypqqAzz
+    aaabcxyzpqrrrabbxyyyypqqqAzz
+    aaabcxyzpqrrrabbxyyyypqqqqAzz
+    aaabcxyzpqrrrabbxyyyypqqqqqAzz
+    aaabcxyzpqrrrabbxyyyypqqqqqqAzz
+    aaaabcxyzpqrrrabbxyyyypqAzz
+    abxyzzpqrrrabbxyyyypqAzz
+    aabxyzzzpqrrrabbxyyyypqAzz
+    aaabxyzzzzpqrrrabbxyyyypqAzz
+    aaaabxyzzzzpqrrrabbxyyyypqAzz
+    abcxyzzpqrrrabbxyyyypqAzz
+    aabcxyzzzpqrrrabbxyyyypqAzz
+    aaabcxyzzzzpqrrrabbxyyyypqAzz
+    aaaabcxyzzzzpqrrrabbxyyyypqAzz
+    aaaabcxyzzzzpqrrrabbbxyyyypqAzz
+    aaaabcxyzzzzpqrrrabbbxyyyyypqAzz
+    aaabcxyzpqrrrabbxyyyypABzz
+    aaabcxyzpqrrrabbxyyyypABBzz
+    >>>aaabxyzpqrrrabbxyyyypqAzz
+    >aaaabxyzpqrrrabbxyyyypqAzz
+    >>>>abcxyzpqrrrabbxyyyypqAzz
+    *** Failers
+    abxyzpqrrabbxyyyypqAzz
+    abxyzpqrrrrabbxyyyypqAzz
+    abxyzpqrrrabxyyyypqAzz
+    aaaabcxyzzzzpqrrrabbbxyyyyyypqAzz
+    aaaabcxyzzzzpqrrrabbbxyyypqAzz
+    aaabcxyzpqrrrabbxyyyypqqqqqqqAzz
+
+/^(abc){1,2}zz/
+    abczz
+    abcabczz
+    *** Failers
+    zz
+    abcabcabczz
+    >>abczz
+
+/^(b+?|a){1,2}?c/
+    bc
+    bbc
+    bbbc
+    bac
+    bbac
+    aac
+    abbbbbbbbbbbc
+    bbbbbbbbbbbac
+    *** Failers
+    aaac
+    abbbbbbbbbbbac
+
+/^(b+|a){1,2}c/
+    bc
+    bbc
+    bbbc
+    bac
+    bbac
+    aac
+    abbbbbbbbbbbc
+    bbbbbbbbbbbac
+    *** Failers
+    aaac
+    abbbbbbbbbbbac
+
+/^(b+|a){1,2}?bc/
+    bbc
+
+/^(b*|ba){1,2}?bc/
+    babc
+    bbabc
+    bababc
+    *** Failers
+    bababbc
+    babababc
+
+/^(ba|b*){1,2}?bc/
+    babc
+    bbabc
+    bababc
+    *** Failers
+    bababbc
+    babababc
+
+/^\ca\cA\c[\c{\c:/
+    \x01\x01\e;z
+
+/^[ab\]cde]/
+    athing
+    bthing
+    ]thing
+    cthing
+    dthing
+    ething
+    *** Failers
+    fthing
+    [thing
+    \\thing
+
+/^[]cde]/
+    ]thing
+    cthing
+    dthing
+    ething
+    *** Failers
+    athing
+    fthing
+
+/^[^ab\]cde]/
+    fthing
+    [thing
+    \\thing
+    *** Failers
+    athing
+    bthing
+    ]thing
+    cthing
+    dthing
+    ething
+
+/^[^]cde]/
+    athing
+    fthing
+    *** Failers
+    ]thing
+    cthing
+    dthing
+    ething
+
+/^\?/
+    ?
+
+/^ÿ/
+    ÿ
+
+/^[0-9]+$/
+    0
+    1
+    2
+    3
+    4
+    5
+    6
+    7
+    8
+    9
+    10
+    100
+    *** Failers
+    abc
+
+/^.*nter/
+    enter
+    inter
+    uponter
+
+/^xxx[0-9]+$/
+    xxx0
+    xxx1234
+    *** Failers
+    xxx
+
+/^.+[0-9][0-9][0-9]$/
+    x123
+    xx123
+    123456
+    *** Failers
+    123
+    x1234
+
+/^.+?[0-9][0-9][0-9]$/
+    x123
+    xx123
+    123456
+    *** Failers
+    123
+    x1234
+
+/^([^!]+)!(.+)=apquxz\.ixr\.zzz\.ac\.uk$/
+    abc!pqr=apquxz.ixr.zzz.ac.uk
+    *** Failers
+    !pqr=apquxz.ixr.zzz.ac.uk
+    abc!=apquxz.ixr.zzz.ac.uk
+    abc!pqr=apquxz:ixr.zzz.ac.uk
+    abc!pqr=apquxz.ixr.zzz.ac.ukk
+
+/:/
+    Well, we need a colon: somewhere
+    *** Fail if we don't
+
+/([\da-f:]+)$/i
+    0abc
+    abc
+    fed
+    E
+    ::
+    5f03:12C0::932e
+    fed def
+    Any old stuff
+    *** Failers
+    0zzz
+    gzzz
+    fed\x20
+    Any old rubbish
+
+/^.*\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/
+    .1.2.3
+    A.12.123.0
+    *** Failers
+    .1.2.3333
+    1.2.3
+    1234.2.3
+
+/^(\d+)\s+IN\s+SOA\s+(\S+)\s+(\S+)\s*\(\s*$/
+    1 IN SOA non-sp1 non-sp2(
+    1    IN    SOA    non-sp1    non-sp2   (
+    *** Failers
+    1IN SOA non-sp1 non-sp2(
+
+/^[a-zA-Z\d][a-zA-Z\d\-]*(\.[a-zA-Z\d][a-zA-z\d\-]*)*\.$/
+    a.
+    Z.
+    2.
+    ab-c.pq-r.
+    sxk.zzz.ac.uk.
+    x-.y-.
+    *** Failers
+    -abc.peq.
+
+/^\*\.[a-z]([a-z\-\d]*[a-z\d]+)?(\.[a-z]([a-z\-\d]*[a-z\d]+)?)*$/
+    *.a
+    *.b0-a
+    *.c3-b.c
+    *.c-a.b-c
+    *** Failers
+    *.0
+    *.a-
+    *.a-b.c-
+    *.c-a.0-c
+
+/^(?=ab(de))(abd)(e)/
+    abde
+
+/^(?!(ab)de|x)(abd)(f)/
+    abdf
+
+/^(?=(ab(cd)))(ab)/
+    abcd
+
+/^[\da-f](\.[\da-f])*$/i
+    a.b.c.d
+    A.B.C.D
+    a.b.c.1.2.3.C
+
+/^\".*\"\s*(;.*)?$/
+    \"1234\"
+    \"abcd\" ;
+    \"\" ; rhubarb
+    *** Failers
+    \"1234\" : things
+
+/^$/
+    \
+    *** Failers
+
+/   ^    a   (?# begins with a)  b\sc (?# then b c) $ (?# then end)/x
+    ab c
+    *** Failers
+    abc
+    ab cde
+
+/(?x)   ^    a   (?# begins with a)  b\sc (?# then b c) $ (?# then end)/
+    ab c
+    *** Failers
+    abc
+    ab cde
+
+/^   a\ b[c ]d       $/x
+    a bcd
+    a b d
+    *** Failers
+    abcd
+    ab d
+
+/^(a(b(c)))(d(e(f)))(h(i(j)))(k(l(m)))$/
+    abcdefhijklm
+
+/^(?:a(b(c)))(?:d(e(f)))(?:h(i(j)))(?:k(l(m)))$/
+    abcdefhijklm
+
+/^[\w][\W][\s][\S][\d][\D][\b][\n][\c]][\022]/
+    a+ Z0+\x08\n\x1d\x12
+
+/^[.^$|()*+?{,}]+/
+    .^\$(*+)|{?,?}
+
+/^a*\w/
+    z
+    az
+    aaaz
+    a
+    aa
+    aaaa
+    a+
+    aa+
+
+/^a*?\w/
+    z
+    az
+    aaaz
+    a
+    aa
+    aaaa
+    a+
+    aa+
+
+/^a+\w/
+    az
+    aaaz
+    aa
+    aaaa
+    aa+
+
+/^a+?\w/
+    az
+    aaaz
+    aa
+    aaaa
+    aa+
+
+/^\d{8}\w{2,}/
+    1234567890
+    12345678ab
+    12345678__
+    *** Failers
+    1234567
+
+/^[aeiou\d]{4,5}$/
+    uoie
+    1234
+    12345
+    aaaaa
+    *** Failers
+    123456
+
+/^[aeiou\d]{4,5}?/
+    uoie
+    1234
+    12345
+    aaaaa
+    123456
+
+/\A(abc|def)=(\1){2,3}\Z/
+    abc=abcabc
+    def=defdefdef
+    *** Failers
+    abc=defdef
+
+/^(a)(b)(c)(d)(e)(f)(g)(h)(i)(j)(k)\11*(\3\4)\1(?#)2$/
+    abcdefghijkcda2
+    abcdefghijkkkkcda2
+
+/(cat(a(ract|tonic)|erpillar)) \1()2(3)/
+    cataract cataract23
+    catatonic catatonic23
+    caterpillar caterpillar23
+
+
+/^From +([^ ]+) +[a-zA-Z][a-zA-Z][a-zA-Z] +[a-zA-Z][a-zA-Z][a-zA-Z] +[0-9]?[0-9] +[0-9][0-9]:[0-9][0-9]/
+    From abcd  Mon Sep 01 12:33:02 1997
+
+/^From\s+\S+\s+([a-zA-Z]{3}\s+){2}\d{1,2}\s+\d\d:\d\d/
+    From abcd  Mon Sep 01 12:33:02 1997
+    From abcd  Mon Sep  1 12:33:02 1997
+    *** Failers
+    From abcd  Sep 01 12:33:02 1997
+
+/^12.34/s
+    12\n34
+    12\r34
+
+/\w+(?=\t)/
+    the quick brown\t fox
+
+/foo(?!bar)(.*)/
+    foobar is foolish see?
+
+/(?:(?!foo)...|^.{0,2})bar(.*)/
+    foobar crowbar etc
+    barrel
+    2barrel
+    A barrel
+
+/^(\D*)(?=\d)(?!123)/
+    abc456
+    *** Failers
+    abc123
+
+/^1234(?# test newlines
+  inside)/
+    1234
+
+/^1234 #comment in extended re
+  /x
+    1234
+
+/#rhubarb
+  abcd/x
+    abcd
+
+/^abcd#rhubarb/x
+    abcd
+
+/^(a)\1{2,3}(.)/
+    aaab
+    aaaab
+    aaaaab
+    aaaaaab
+
+/(?!^)abc/
+    the abc
+    *** Failers
+    abc
+
+/(?=^)abc/
+    abc
+    *** Failers
+    the abc
+
+/^[ab]{1,3}(ab*|b)/
+    aabbbbb
+
+/^[ab]{1,3}?(ab*|b)/
+    aabbbbb
+
+/^[ab]{1,3}?(ab*?|b)/
+    aabbbbb
+
+/^[ab]{1,3}(ab*?|b)/
+    aabbbbb
+
+/  (?: [\040\t] |  \(
+(?:  [^\\\x80-\xff\n\015()]  |  \\ [^\x80-\xff]  |  \( (?:  [^\\\x80-\xff\n\015()]  |  \\ [^\x80-\xff]  )* \)  )*
+\)  )*                          # optional leading comment
+(?:    (?:
+[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+    # some number of atom characters...
+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom
+|
+" (?:                      # opening quote...
+[^\\\x80-\xff\n\015"]                #   Anything except backslash and quote
+|                     #    or
+\\ [^\x80-\xff]           #   Escaped something (something != CR)
+)* "  # closing quote
+)                    # initial word
+(?:  (?: [\040\t] |  \(
+(?:  [^\\\x80-\xff\n\015()]  |  \\ [^\x80-\xff]  |  \( (?:  [^\\\x80-\xff\n\015()]  |  \\ [^\x80-\xff]  )* \)  )*
+\)  )*  \.  (?: [\040\t] |  \(
+(?:  [^\\\x80-\xff\n\015()]  |  \\ [^\x80-\xff]  |  \( (?:  [^\\\x80-\xff\n\015()]  |  \\ [^\x80-\xff]  )* \)  )*
+\)  )*   (?:
+[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+    # some number of atom characters...
+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom
+|
+" (?:                      # opening quote...
+[^\\\x80-\xff\n\015"]                #   Anything except backslash and quote
+|                     #    or
+\\ [^\x80-\xff]           #   Escaped something (something != CR)
+)* "  # closing quote
+)  )* # further okay, if led by a period
+(?: [\040\t] |  \(
+(?:  [^\\\x80-\xff\n\015()]  |  \\ [^\x80-\xff]  |  \( (?:  [^\\\x80-\xff\n\015()]  |  \\ [^\x80-\xff]  )* \)  )*
+\)  )*  @  (?: [\040\t] |  \(
+(?:  [^\\\x80-\xff\n\015()]  |  \\ [^\x80-\xff]  |  \( (?:  [^\\\x80-\xff\n\015()]  |  \\ [^\x80-\xff]  )* \)  )*
+\)  )*    (?:
+[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+    # some number of atom characters...
+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom
+|   \[                         # [
+(?: [^\\\x80-\xff\n\015\[\]] |  \\ [^\x80-\xff]  )*    #    stuff
+\]                        #           ]
+)                           # initial subdomain
+(?:                                  #
+(?: [\040\t] |  \(
+(?:  [^\\\x80-\xff\n\015()]  |  \\ [^\x80-\xff]  |  \( (?:  [^\\\x80-\xff\n\015()]  |  \\ [^\x80-\xff]  )* \)  )*
+\)  )*  \.                        # if led by a period...
+(?: [\040\t] |  \(
+(?:  [^\\\x80-\xff\n\015()]  |  \\ [^\x80-\xff]  |  \( (?:  [^\\\x80-\xff\n\015()]  |  \\ [^\x80-\xff]  )* \)  )*
+\)  )*   (?:
+[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+    # some number of atom characters...
+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom
+|   \[                         # [
+(?: [^\\\x80-\xff\n\015\[\]] |  \\ [^\x80-\xff]  )*    #    stuff
+\]                        #           ]
+)                     #   ...further okay
+)*
+# address
+|                     #  or
+(?:
+[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+    # some number of atom characters...
+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom
+|
+" (?:                      # opening quote...
+[^\\\x80-\xff\n\015"]                #   Anything except backslash and quote
+|                     #    or
+\\ [^\x80-\xff]           #   Escaped something (something != CR)
+)* "  # closing quote
+)             # one word, optionally followed by....
+(?:
+[^()<>@,;:".\\\[\]\x80-\xff\000-\010\012-\037]  |  # atom and space parts, or...
+\(
+(?:  [^\\\x80-\xff\n\015()]  |  \\ [^\x80-\xff]  |  \( (?:  [^\\\x80-\xff\n\015()]  |  \\ [^\x80-\xff]  )* \)  )*
+\)       |  # comments, or...
+
+" (?:                      # opening quote...
+[^\\\x80-\xff\n\015"]                #   Anything except backslash and quote
+|                     #    or
+\\ [^\x80-\xff]           #   Escaped something (something != CR)
+)* "  # closing quote
+# quoted strings
+)*
+<  (?: [\040\t] |  \(
+(?:  [^\\\x80-\xff\n\015()]  |  \\ [^\x80-\xff]  |  \( (?:  [^\\\x80-\xff\n\015()]  |  \\ [^\x80-\xff]  )* \)  )*
+\)  )*                     # leading <
+(?:  @  (?: [\040\t] |  \(
+(?:  [^\\\x80-\xff\n\015()]  |  \\ [^\x80-\xff]  |  \( (?:  [^\\\x80-\xff\n\015()]  |  \\ [^\x80-\xff]  )* \)  )*
+\)  )*    (?:
+[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+    # some number of atom characters...
+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom
+|   \[                         # [
+(?: [^\\\x80-\xff\n\015\[\]] |  \\ [^\x80-\xff]  )*    #    stuff
+\]                        #           ]
+)                           # initial subdomain
+(?:                                  #
+(?: [\040\t] |  \(
+(?:  [^\\\x80-\xff\n\015()]  |  \\ [^\x80-\xff]  |  \( (?:  [^\\\x80-\xff\n\015()]  |  \\ [^\x80-\xff]  )* \)  )*
+\)  )*  \.                        # if led by a period...
+(?: [\040\t] |  \(
+(?:  [^\\\x80-\xff\n\015()]  |  \\ [^\x80-\xff]  |  \( (?:  [^\\\x80-\xff\n\015()]  |  \\ [^\x80-\xff]  )* \)  )*
+\)  )*   (?:
+[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+    # some number of atom characters...
+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom
+|   \[                         # [
+(?: [^\\\x80-\xff\n\015\[\]] |  \\ [^\x80-\xff]  )*    #    stuff
+\]                        #           ]
+)                     #   ...further okay
+)*
+
+(?:  (?: [\040\t] |  \(
+(?:  [^\\\x80-\xff\n\015()]  |  \\ [^\x80-\xff]  |  \( (?:  [^\\\x80-\xff\n\015()]  |  \\ [^\x80-\xff]  )* \)  )*
+\)  )*  ,  (?: [\040\t] |  \(
+(?:  [^\\\x80-\xff\n\015()]  |  \\ [^\x80-\xff]  |  \( (?:  [^\\\x80-\xff\n\015()]  |  \\ [^\x80-\xff]  )* \)  )*
+\)  )*  @  (?: [\040\t] |  \(
+(?:  [^\\\x80-\xff\n\015()]  |  \\ [^\x80-\xff]  |  \( (?:  [^\\\x80-\xff\n\015()]  |  \\ [^\x80-\xff]  )* \)  )*
+\)  )*    (?:
+[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+    # some number of atom characters...
+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom
+|   \[                         # [
+(?: [^\\\x80-\xff\n\015\[\]] |  \\ [^\x80-\xff]  )*    #    stuff
+\]                        #           ]
+)                           # initial subdomain
+(?:                                  #
+(?: [\040\t] |  \(
+(?:  [^\\\x80-\xff\n\015()]  |  \\ [^\x80-\xff]  |  \( (?:  [^\\\x80-\xff\n\015()]  |  \\ [^\x80-\xff]  )* \)  )*
+\)  )*  \.                        # if led by a period...
+(?: [\040\t] |  \(
+(?:  [^\\\x80-\xff\n\015()]  |  \\ [^\x80-\xff]  |  \( (?:  [^\\\x80-\xff\n\015()]  |  \\ [^\x80-\xff]  )* \)  )*
+\)  )*   (?:
+[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+    # some number of atom characters...
+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom
+|   \[                         # [
+(?: [^\\\x80-\xff\n\015\[\]] |  \\ [^\x80-\xff]  )*    #    stuff
+\]                        #           ]
+)                     #   ...further okay
+)*
+)* # further okay, if led by comma
+:                                # closing colon
+(?: [\040\t] |  \(
+(?:  [^\\\x80-\xff\n\015()]  |  \\ [^\x80-\xff]  |  \( (?:  [^\\\x80-\xff\n\015()]  |  \\ [^\x80-\xff]  )* \)  )*
+\)  )*  )? #       optional route
+(?:
+[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+    # some number of atom characters...
+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom
+|
+" (?:                      # opening quote...
+[^\\\x80-\xff\n\015"]                #   Anything except backslash and quote
+|                     #    or
+\\ [^\x80-\xff]           #   Escaped something (something != CR)
+)* "  # closing quote
+)                    # initial word
+(?:  (?: [\040\t] |  \(
+(?:  [^\\\x80-\xff\n\015()]  |  \\ [^\x80-\xff]  |  \( (?:  [^\\\x80-\xff\n\015()]  |  \\ [^\x80-\xff]  )* \)  )*
+\)  )*  \.  (?: [\040\t] |  \(
+(?:  [^\\\x80-\xff\n\015()]  |  \\ [^\x80-\xff]  |  \( (?:  [^\\\x80-\xff\n\015()]  |  \\ [^\x80-\xff]  )* \)  )*
+\)  )*   (?:
+[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+    # some number of atom characters...
+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom
+|
+" (?:                      # opening quote...
+[^\\\x80-\xff\n\015"]                #   Anything except backslash and quote
+|                     #    or
+\\ [^\x80-\xff]           #   Escaped something (something != CR)
+)* "  # closing quote
+)  )* # further okay, if led by a period
+(?: [\040\t] |  \(
+(?:  [^\\\x80-\xff\n\015()]  |  \\ [^\x80-\xff]  |  \( (?:  [^\\\x80-\xff\n\015()]  |  \\ [^\x80-\xff]  )* \)  )*
+\)  )*  @  (?: [\040\t] |  \(
+(?:  [^\\\x80-\xff\n\015()]  |  \\ [^\x80-\xff]  |  \( (?:  [^\\\x80-\xff\n\015()]  |  \\ [^\x80-\xff]  )* \)  )*
+\)  )*    (?:
+[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+    # some number of atom characters...
+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom
+|   \[                         # [
+(?: [^\\\x80-\xff\n\015\[\]] |  \\ [^\x80-\xff]  )*    #    stuff
+\]                        #           ]
+)                           # initial subdomain
+(?:                                  #
+(?: [\040\t] |  \(
+(?:  [^\\\x80-\xff\n\015()]  |  \\ [^\x80-\xff]  |  \( (?:  [^\\\x80-\xff\n\015()]  |  \\ [^\x80-\xff]  )* \)  )*
+\)  )*  \.                        # if led by a period...
+(?: [\040\t] |  \(
+(?:  [^\\\x80-\xff\n\015()]  |  \\ [^\x80-\xff]  |  \( (?:  [^\\\x80-\xff\n\015()]  |  \\ [^\x80-\xff]  )* \)  )*
+\)  )*   (?:
+[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+    # some number of atom characters...
+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom
+|   \[                         # [
+(?: [^\\\x80-\xff\n\015\[\]] |  \\ [^\x80-\xff]  )*    #    stuff
+\]                        #           ]
+)                     #   ...further okay
+)*
+#       address spec
+(?: [\040\t] |  \(
+(?:  [^\\\x80-\xff\n\015()]  |  \\ [^\x80-\xff]  |  \( (?:  [^\\\x80-\xff\n\015()]  |  \\ [^\x80-\xff]  )* \)  )*
+\)  )*  > #                  trailing >
+# name and address
+)  (?: [\040\t] |  \(
+(?:  [^\\\x80-\xff\n\015()]  |  \\ [^\x80-\xff]  |  \( (?:  [^\\\x80-\xff\n\015()]  |  \\ [^\x80-\xff]  )* \)  )*
+\)  )*                       # optional trailing comment
+/x
+    Alan Other <user\@dom.ain>
+    <user\@dom.ain>
+    user\@dom.ain
+    \"A. Other\" <user.1234\@dom.ain> (a comment)
+    A. Other <user.1234\@dom.ain> (a comment)
+    \"/s=user/ou=host/o=place/prmd=uu.yy/admd= /c=gb/\"\@x400-re.lay
+    A missing angle <user\@some.where
+    *** Failers
+    The quick brown fox
+
+/[\040\t]*                    # Nab whitespace.
+(?:
+\(                              #  (
+[^\\\x80-\xff\n\015()] *                             #     normal*
+(?:                                 #       (
+(?:  \\ [^\x80-\xff]  |
+\(                            #  (
+[^\\\x80-\xff\n\015()] *                            #     normal*
+(?:  \\ [^\x80-\xff]   [^\\\x80-\xff\n\015()] * )*        #     (special normal*)*
+\)                           #                       )
+)    #         special
+[^\\\x80-\xff\n\015()] *                         #         normal*
+)*                                  #            )*
+\)                             #                )
+[\040\t]* )*    # If comment found, allow more spaces.
+# optional leading comment
+(?:
+(?:
+[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+    # some number of atom characters...
+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom
+# Atom
+|                       #  or
+"                                     # "
+[^\\\x80-\xff\n\015"] *                            #   normal
+(?:  \\ [^\x80-\xff]  [^\\\x80-\xff\n\015"] * )*        #   ( special normal* )*
+"                                     #        "
+# Quoted string
+)
+[\040\t]*                    # Nab whitespace.
+(?:
+\(                              #  (
+[^\\\x80-\xff\n\015()] *                             #     normal*
+(?:                                 #       (
+(?:  \\ [^\x80-\xff]  |
+\(                            #  (
+[^\\\x80-\xff\n\015()] *                            #     normal*
+(?:  \\ [^\x80-\xff]   [^\\\x80-\xff\n\015()] * )*        #     (special normal*)*
+\)                           #                       )
+)    #         special
+[^\\\x80-\xff\n\015()] *                         #         normal*
+)*                                  #            )*
+\)                             #                )
+[\040\t]* )*    # If comment found, allow more spaces.
+(?:
+\.
+[\040\t]*                    # Nab whitespace.
+(?:
+\(                              #  (
+[^\\\x80-\xff\n\015()] *                             #     normal*
+(?:                                 #       (
+(?:  \\ [^\x80-\xff]  |
+\(                            #  (
+[^\\\x80-\xff\n\015()] *                            #     normal*
+(?:  \\ [^\x80-\xff]   [^\\\x80-\xff\n\015()] * )*        #     (special normal*)*
+\)                           #                       )
+)    #         special
+[^\\\x80-\xff\n\015()] *                         #         normal*
+)*                                  #            )*
+\)                             #                )
+[\040\t]* )*    # If comment found, allow more spaces.
+(?:
+[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+    # some number of atom characters...
+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom
+# Atom
+|                       #  or
+"                                     # "
+[^\\\x80-\xff\n\015"] *                            #   normal
+(?:  \\ [^\x80-\xff]  [^\\\x80-\xff\n\015"] * )*        #   ( special normal* )*
+"                                     #        "
+# Quoted string
+)
+[\040\t]*                    # Nab whitespace.
+(?:
+\(                              #  (
+[^\\\x80-\xff\n\015()] *                             #     normal*
+(?:                                 #       (
+(?:  \\ [^\x80-\xff]  |
+\(                            #  (
+[^\\\x80-\xff\n\015()] *                            #     normal*
+(?:  \\ [^\x80-\xff]   [^\\\x80-\xff\n\015()] * )*        #     (special normal*)*
+\)                           #                       )
+)    #         special
+[^\\\x80-\xff\n\015()] *                         #         normal*
+)*                                  #            )*
+\)                             #                )
+[\040\t]* )*    # If comment found, allow more spaces.
+# additional words
+)*
+@
+[\040\t]*                    # Nab whitespace.
+(?:
+\(                              #  (
+[^\\\x80-\xff\n\015()] *                             #     normal*
+(?:                                 #       (
+(?:  \\ [^\x80-\xff]  |
+\(                            #  (
+[^\\\x80-\xff\n\015()] *                            #     normal*
+(?:  \\ [^\x80-\xff]   [^\\\x80-\xff\n\015()] * )*        #     (special normal*)*
+\)                           #                       )
+)    #         special
+[^\\\x80-\xff\n\015()] *                         #         normal*
+)*                                  #            )*
+\)                             #                )
+[\040\t]* )*    # If comment found, allow more spaces.
+(?:
+[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+    # some number of atom characters...
+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom
+|
+\[                            # [
+(?: [^\\\x80-\xff\n\015\[\]] |  \\ [^\x80-\xff]  )*     #    stuff
+\]                           #           ]
+)
+[\040\t]*                    # Nab whitespace.
+(?:
+\(                              #  (
+[^\\\x80-\xff\n\015()] *                             #     normal*
+(?:                                 #       (
+(?:  \\ [^\x80-\xff]  |
+\(                            #  (
+[^\\\x80-\xff\n\015()] *                            #     normal*
+(?:  \\ [^\x80-\xff]   [^\\\x80-\xff\n\015()] * )*        #     (special normal*)*
+\)                           #                       )
+)    #         special
+[^\\\x80-\xff\n\015()] *                         #         normal*
+)*                                  #            )*
+\)                             #                )
+[\040\t]* )*    # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\.
+[\040\t]*                    # Nab whitespace.
+(?:
+\(                              #  (
+[^\\\x80-\xff\n\015()] *                             #     normal*
+(?:                                 #       (
+(?:  \\ [^\x80-\xff]  |
+\(                            #  (
+[^\\\x80-\xff\n\015()] *                            #     normal*
+(?:  \\ [^\x80-\xff]   [^\\\x80-\xff\n\015()] * )*        #     (special normal*)*
+\)                           #                       )
+)    #         special
+[^\\\x80-\xff\n\015()] *                         #         normal*
+)*                                  #            )*
+\)                             #                )
+[\040\t]* )*    # If comment found, allow more spaces.
+(?:
+[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+    # some number of atom characters...
+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom
+|
+\[                            # [
+(?: [^\\\x80-\xff\n\015\[\]] |  \\ [^\x80-\xff]  )*     #    stuff
+\]                           #           ]
+)
+[\040\t]*                    # Nab whitespace.
+(?:
+\(                              #  (
+[^\\\x80-\xff\n\015()] *                             #     normal*
+(?:                                 #       (
+(?:  \\ [^\x80-\xff]  |
+\(                            #  (
+[^\\\x80-\xff\n\015()] *                            #     normal*
+(?:  \\ [^\x80-\xff]   [^\\\x80-\xff\n\015()] * )*        #     (special normal*)*
+\)                           #                       )
+)    #         special
+[^\\\x80-\xff\n\015()] *                         #         normal*
+)*                                  #            )*
+\)                             #                )
+[\040\t]* )*    # If comment found, allow more spaces.
+# optional trailing comments
+)*
+# address
+|                             #  or
+(?:
+[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+    # some number of atom characters...
+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom
+# Atom
+|                       #  or
+"                                     # "
+[^\\\x80-\xff\n\015"] *                            #   normal
+(?:  \\ [^\x80-\xff]  [^\\\x80-\xff\n\015"] * )*        #   ( special normal* )*
+"                                     #        "
+# Quoted string
+)
+# leading word
+[^()<>@,;:".\\\[\]\x80-\xff\000-\010\012-\037] *               # "normal" atoms and or spaces
+(?:
+(?:
+\(                              #  (
+[^\\\x80-\xff\n\015()] *                             #     normal*
+(?:                                 #       (
+(?:  \\ [^\x80-\xff]  |
+\(                            #  (
+[^\\\x80-\xff\n\015()] *                            #     normal*
+(?:  \\ [^\x80-\xff]   [^\\\x80-\xff\n\015()] * )*        #     (special normal*)*
+\)                           #                       )
+)    #         special
+[^\\\x80-\xff\n\015()] *                         #         normal*
+)*                                  #            )*
+\)                             #                )
+|
+"                                     # "
+[^\\\x80-\xff\n\015"] *                            #   normal
+(?:  \\ [^\x80-\xff]  [^\\\x80-\xff\n\015"] * )*        #   ( special normal* )*
+"                                     #        "
+) # "special" comment or quoted string
+[^()<>@,;:".\\\[\]\x80-\xff\000-\010\012-\037] *            #  more "normal"
+)*
+<
+[\040\t]*                    # Nab whitespace.
+(?:
+\(                              #  (
+[^\\\x80-\xff\n\015()] *                             #     normal*
+(?:                                 #       (
+(?:  \\ [^\x80-\xff]  |
+\(                            #  (
+[^\\\x80-\xff\n\015()] *                            #     normal*
+(?:  \\ [^\x80-\xff]   [^\\\x80-\xff\n\015()] * )*        #     (special normal*)*
+\)                           #                       )
+)    #         special
+[^\\\x80-\xff\n\015()] *                         #         normal*
+)*                                  #            )*
+\)                             #                )
+[\040\t]* )*    # If comment found, allow more spaces.
+# <
+(?:
+@
+[\040\t]*                    # Nab whitespace.
+(?:
+\(                              #  (
+[^\\\x80-\xff\n\015()] *                             #     normal*
+(?:                                 #       (
+(?:  \\ [^\x80-\xff]  |
+\(                            #  (
+[^\\\x80-\xff\n\015()] *                            #     normal*
+(?:  \\ [^\x80-\xff]   [^\\\x80-\xff\n\015()] * )*        #     (special normal*)*
+\)                           #                       )
+)    #         special
+[^\\\x80-\xff\n\015()] *                         #         normal*
+)*                                  #            )*
+\)                             #                )
+[\040\t]* )*    # If comment found, allow more spaces.
+(?:
+[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+    # some number of atom characters...
+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom
+|
+\[                            # [
+(?: [^\\\x80-\xff\n\015\[\]] |  \\ [^\x80-\xff]  )*     #    stuff
+\]                           #           ]
+)
+[\040\t]*                    # Nab whitespace.
+(?:
+\(                              #  (
+[^\\\x80-\xff\n\015()] *                             #     normal*
+(?:                                 #       (
+(?:  \\ [^\x80-\xff]  |
+\(                            #  (
+[^\\\x80-\xff\n\015()] *                            #     normal*
+(?:  \\ [^\x80-\xff]   [^\\\x80-\xff\n\015()] * )*        #     (special normal*)*
+\)                           #                       )
+)    #         special
+[^\\\x80-\xff\n\015()] *                         #         normal*
+)*                                  #            )*
+\)                             #                )
+[\040\t]* )*    # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\.
+[\040\t]*                    # Nab whitespace.
+(?:
+\(                              #  (
+[^\\\x80-\xff\n\015()] *                             #     normal*
+(?:                                 #       (
+(?:  \\ [^\x80-\xff]  |
+\(                            #  (
+[^\\\x80-\xff\n\015()] *                            #     normal*
+(?:  \\ [^\x80-\xff]   [^\\\x80-\xff\n\015()] * )*        #     (special normal*)*
+\)                           #                       )
+)    #         special
+[^\\\x80-\xff\n\015()] *                         #         normal*
+)*                                  #            )*
+\)                             #                )
+[\040\t]* )*    # If comment found, allow more spaces.
+(?:
+[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+    # some number of atom characters...
+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom
+|
+\[                            # [
+(?: [^\\\x80-\xff\n\015\[\]] |  \\ [^\x80-\xff]  )*     #    stuff
+\]                           #           ]
+)
+[\040\t]*                    # Nab whitespace.
+(?:
+\(                              #  (
+[^\\\x80-\xff\n\015()] *                             #     normal*
+(?:                                 #       (
+(?:  \\ [^\x80-\xff]  |
+\(                            #  (
+[^\\\x80-\xff\n\015()] *                            #     normal*
+(?:  \\ [^\x80-\xff]   [^\\\x80-\xff\n\015()] * )*        #     (special normal*)*
+\)                           #                       )
+)    #         special
+[^\\\x80-\xff\n\015()] *                         #         normal*
+)*                                  #            )*
+\)                             #                )
+[\040\t]* )*    # If comment found, allow more spaces.
+# optional trailing comments
+)*
+(?: ,
+[\040\t]*                    # Nab whitespace.
+(?:
+\(                              #  (
+[^\\\x80-\xff\n\015()] *                             #     normal*
+(?:                                 #       (
+(?:  \\ [^\x80-\xff]  |
+\(                            #  (
+[^\\\x80-\xff\n\015()] *                            #     normal*
+(?:  \\ [^\x80-\xff]   [^\\\x80-\xff\n\015()] * )*        #     (special normal*)*
+\)                           #                       )
+)    #         special
+[^\\\x80-\xff\n\015()] *                         #         normal*
+)*                                  #            )*
+\)                             #                )
+[\040\t]* )*    # If comment found, allow more spaces.
+@
+[\040\t]*                    # Nab whitespace.
+(?:
+\(                              #  (
+[^\\\x80-\xff\n\015()] *                             #     normal*
+(?:                                 #       (
+(?:  \\ [^\x80-\xff]  |
+\(                            #  (
+[^\\\x80-\xff\n\015()] *                            #     normal*
+(?:  \\ [^\x80-\xff]   [^\\\x80-\xff\n\015()] * )*        #     (special normal*)*
+\)                           #                       )
+)    #         special
+[^\\\x80-\xff\n\015()] *                         #         normal*
+)*                                  #            )*
+\)                             #                )
+[\040\t]* )*    # If comment found, allow more spaces.
+(?:
+[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+    # some number of atom characters...
+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom
+|
+\[                            # [
+(?: [^\\\x80-\xff\n\015\[\]] |  \\ [^\x80-\xff]  )*     #    stuff
+\]                           #           ]
+)
+[\040\t]*                    # Nab whitespace.
+(?:
+\(                              #  (
+[^\\\x80-\xff\n\015()] *                             #     normal*
+(?:                                 #       (
+(?:  \\ [^\x80-\xff]  |
+\(                            #  (
+[^\\\x80-\xff\n\015()] *                            #     normal*
+(?:  \\ [^\x80-\xff]   [^\\\x80-\xff\n\015()] * )*        #     (special normal*)*
+\)                           #                       )
+)    #         special
+[^\\\x80-\xff\n\015()] *                         #         normal*
+)*                                  #            )*
+\)                             #                )
+[\040\t]* )*    # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\.
+[\040\t]*                    # Nab whitespace.
+(?:
+\(                              #  (
+[^\\\x80-\xff\n\015()] *                             #     normal*
+(?:                                 #       (
+(?:  \\ [^\x80-\xff]  |
+\(                            #  (
+[^\\\x80-\xff\n\015()] *                            #     normal*
+(?:  \\ [^\x80-\xff]   [^\\\x80-\xff\n\015()] * )*        #     (special normal*)*
+\)                           #                       )
+)    #         special
+[^\\\x80-\xff\n\015()] *                         #         normal*
+)*                                  #            )*
+\)                             #                )
+[\040\t]* )*    # If comment found, allow more spaces.
+(?:
+[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+    # some number of atom characters...
+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom
+|
+\[                            # [
+(?: [^\\\x80-\xff\n\015\[\]] |  \\ [^\x80-\xff]  )*     #    stuff
+\]                           #           ]
+)
+[\040\t]*                    # Nab whitespace.
+(?:
+\(                              #  (
+[^\\\x80-\xff\n\015()] *                             #     normal*
+(?:                                 #       (
+(?:  \\ [^\x80-\xff]  |
+\(                            #  (
+[^\\\x80-\xff\n\015()] *                            #     normal*
+(?:  \\ [^\x80-\xff]   [^\\\x80-\xff\n\015()] * )*        #     (special normal*)*
+\)                           #                       )
+)    #         special
+[^\\\x80-\xff\n\015()] *                         #         normal*
+)*                                  #            )*
+\)                             #                )
+[\040\t]* )*    # If comment found, allow more spaces.
+# optional trailing comments
+)*
+)*  # additional domains
+:
+[\040\t]*                    # Nab whitespace.
+(?:
+\(                              #  (
+[^\\\x80-\xff\n\015()] *                             #     normal*
+(?:                                 #       (
+(?:  \\ [^\x80-\xff]  |
+\(                            #  (
+[^\\\x80-\xff\n\015()] *                            #     normal*
+(?:  \\ [^\x80-\xff]   [^\\\x80-\xff\n\015()] * )*        #     (special normal*)*
+\)                           #                       )
+)    #         special
+[^\\\x80-\xff\n\015()] *                         #         normal*
+)*                                  #            )*
+\)                             #                )
+[\040\t]* )*    # If comment found, allow more spaces.
+# optional trailing comments
+)?     #       optional route
+(?:
+[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+    # some number of atom characters...
+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom
+# Atom
+|                       #  or
+"                                     # "
+[^\\\x80-\xff\n\015"] *                            #   normal
+(?:  \\ [^\x80-\xff]  [^\\\x80-\xff\n\015"] * )*        #   ( special normal* )*
+"                                     #        "
+# Quoted string
+)
+[\040\t]*                    # Nab whitespace.
+(?:
+\(                              #  (
+[^\\\x80-\xff\n\015()] *                             #     normal*
+(?:                                 #       (
+(?:  \\ [^\x80-\xff]  |
+\(                            #  (
+[^\\\x80-\xff\n\015()] *                            #     normal*
+(?:  \\ [^\x80-\xff]   [^\\\x80-\xff\n\015()] * )*        #     (special normal*)*
+\)                           #                       )
+)    #         special
+[^\\\x80-\xff\n\015()] *                         #         normal*
+)*                                  #            )*
+\)                             #                )
+[\040\t]* )*    # If comment found, allow more spaces.
+(?:
+\.
+[\040\t]*                    # Nab whitespace.
+(?:
+\(                              #  (
+[^\\\x80-\xff\n\015()] *                             #     normal*
+(?:                                 #       (
+(?:  \\ [^\x80-\xff]  |
+\(                            #  (
+[^\\\x80-\xff\n\015()] *                            #     normal*
+(?:  \\ [^\x80-\xff]   [^\\\x80-\xff\n\015()] * )*        #     (special normal*)*
+\)                           #                       )
+)    #         special
+[^\\\x80-\xff\n\015()] *                         #         normal*
+)*                                  #            )*
+\)                             #                )
+[\040\t]* )*    # If comment found, allow more spaces.
+(?:
+[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+    # some number of atom characters...
+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom
+# Atom
+|                       #  or
+"                                     # "
+[^\\\x80-\xff\n\015"] *                            #   normal
+(?:  \\ [^\x80-\xff]  [^\\\x80-\xff\n\015"] * )*        #   ( special normal* )*
+"                                     #        "
+# Quoted string
+)
+[\040\t]*                    # Nab whitespace.
+(?:
+\(                              #  (
+[^\\\x80-\xff\n\015()] *                             #     normal*
+(?:                                 #       (
+(?:  \\ [^\x80-\xff]  |
+\(                            #  (
+[^\\\x80-\xff\n\015()] *                            #     normal*
+(?:  \\ [^\x80-\xff]   [^\\\x80-\xff\n\015()] * )*        #     (special normal*)*
+\)                           #                       )
+)    #         special
+[^\\\x80-\xff\n\015()] *                         #         normal*
+)*                                  #            )*
+\)                             #                )
+[\040\t]* )*    # If comment found, allow more spaces.
+# additional words
+)*
+@
+[\040\t]*                    # Nab whitespace.
+(?:
+\(                              #  (
+[^\\\x80-\xff\n\015()] *                             #     normal*
+(?:                                 #       (
+(?:  \\ [^\x80-\xff]  |
+\(                            #  (
+[^\\\x80-\xff\n\015()] *                            #     normal*
+(?:  \\ [^\x80-\xff]   [^\\\x80-\xff\n\015()] * )*        #     (special normal*)*
+\)                           #                       )
+)    #         special
+[^\\\x80-\xff\n\015()] *                         #         normal*
+)*                                  #            )*
+\)                             #                )
+[\040\t]* )*    # If comment found, allow more spaces.
+(?:
+[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+    # some number of atom characters...
+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom
+|
+\[                            # [
+(?: [^\\\x80-\xff\n\015\[\]] |  \\ [^\x80-\xff]  )*     #    stuff
+\]                           #           ]
+)
+[\040\t]*                    # Nab whitespace.
+(?:
+\(                              #  (
+[^\\\x80-\xff\n\015()] *                             #     normal*
+(?:                                 #       (
+(?:  \\ [^\x80-\xff]  |
+\(                            #  (
+[^\\\x80-\xff\n\015()] *                            #     normal*
+(?:  \\ [^\x80-\xff]   [^\\\x80-\xff\n\015()] * )*        #     (special normal*)*
+\)                           #                       )
+)    #         special
+[^\\\x80-\xff\n\015()] *                         #         normal*
+)*                                  #            )*
+\)                             #                )
+[\040\t]* )*    # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\.
+[\040\t]*                    # Nab whitespace.
+(?:
+\(                              #  (
+[^\\\x80-\xff\n\015()] *                             #     normal*
+(?:                                 #       (
+(?:  \\ [^\x80-\xff]  |
+\(                            #  (
+[^\\\x80-\xff\n\015()] *                            #     normal*
+(?:  \\ [^\x80-\xff]   [^\\\x80-\xff\n\015()] * )*        #     (special normal*)*
+\)                           #                       )
+)    #         special
+[^\\\x80-\xff\n\015()] *                         #         normal*
+)*                                  #            )*
+\)                             #                )
+[\040\t]* )*    # If comment found, allow more spaces.
+(?:
+[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+    # some number of atom characters...
+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom
+|
+\[                            # [
+(?: [^\\\x80-\xff\n\015\[\]] |  \\ [^\x80-\xff]  )*     #    stuff
+\]                           #           ]
+)
+[\040\t]*                    # Nab whitespace.
+(?:
+\(                              #  (
+[^\\\x80-\xff\n\015()] *                             #     normal*
+(?:                                 #       (
+(?:  \\ [^\x80-\xff]  |
+\(                            #  (
+[^\\\x80-\xff\n\015()] *                            #     normal*
+(?:  \\ [^\x80-\xff]   [^\\\x80-\xff\n\015()] * )*        #     (special normal*)*
+\)                           #                       )
+)    #         special
+[^\\\x80-\xff\n\015()] *                         #         normal*
+)*                                  #            )*
+\)                             #                )
+[\040\t]* )*    # If comment found, allow more spaces.
+# optional trailing comments
+)*
+#       address spec
+>                    #                 >
+# name and address
+)
+/x
+    Alan Other <user\@dom.ain>
+    <user\@dom.ain>
+    user\@dom.ain
+    \"A. Other\" <user.1234\@dom.ain> (a comment)
+    A. Other <user.1234\@dom.ain> (a comment)
+    \"/s=user/ou=host/o=place/prmd=uu.yy/admd= /c=gb/\"\@x400-re.lay
+    A missing angle <user\@some.where
+    *** Failers
+    The quick brown fox
+
+/abc\0def\00pqr\000xyz\0000AB/
+    abc\0def\00pqr\000xyz\0000AB
+    abc456 abc\0def\00pqr\000xyz\0000ABCDE
+
+/abc\x0def\x00pqr\x000xyz\x0000AB/
+    abc\x0def\x00pqr\x000xyz\x0000AB
+    abc456 abc\x0def\x00pqr\x000xyz\x0000ABCDE
+
+/^[\000-\037]/
+    \0A
+    \01B
+    \037C
+
+/\0*/
+    \0\0\0\0
+
+/A\x0{2,3}Z/
+    The A\x0\x0Z
+    An A\0\x0\0Z
+    *** Failers
+    A\0Z
+    A\0\x0\0\x0Z
+
+/^(cow|)\1(bell)/
+    cowcowbell
+    bell
+    *** Failers
+    cowbell
+
+/^\s/
+    \040abc
+    \x0cabc
+    \nabc
+    \rabc
+    \tabc
+    *** Failers
+    abc
+
+/^a	b
+  
+    c/x
+    abc
+
+/^(a|)\1*b/
+    ab
+    aaaab
+    b
+    *** Failers
+    acb
+
+/^(a|)\1+b/
+    aab
+    aaaab
+    b
+    *** Failers
+    ab
+
+/^(a|)\1?b/
+    ab
+    aab
+    b
+    *** Failers
+    acb
+
+/^(a|)\1{2}b/
+    aaab
+    b
+    *** Failers
+    ab
+    aab
+    aaaab
+
+/^(a|)\1{2,3}b/
+    aaab
+    aaaab
+    b
+    *** Failers
+    ab
+    aab
+    aaaaab
+
+/ab{1,3}bc/
+    abbbbc
+    abbbc
+    abbc
+    *** Failers
+    abc
+    abbbbbc
+
+/([^.]*)\.([^:]*):[T ]+(.*)/
+    track1.title:TBlah blah blah
+
+/([^.]*)\.([^:]*):[T ]+(.*)/i
+    track1.title:TBlah blah blah
+
+/([^.]*)\.([^:]*):[t ]+(.*)/i
+    track1.title:TBlah blah blah
+
+/^[W-c]+$/
+    WXY_^abc
+    *** Failers
+    wxy
+
+/^[W-c]+$/i
+    WXY_^abc
+    wxy_^ABC
+
+/^[\x3f-\x5F]+$/i
+    WXY_^abc
+    wxy_^ABC
+
+/^abc$/m
+    abc
+    qqq\nabc
+    abc\nzzz
+    qqq\nabc\nzzz
+
+/^abc$/
+    abc
+    *** Failers
+    qqq\nabc
+    abc\nzzz
+    qqq\nabc\nzzz
+
+/\Aabc\Z/m
+    abc
+    abc\n 
+    *** Failers
+    qqq\nabc
+    abc\nzzz
+    qqq\nabc\nzzz
+    
+/\A(.)*\Z/s
+    abc\ndef
+
+/\A(.)*\Z/m
+    *** Failers
+    abc\ndef
+
+/(?:b)|(?::+)/
+    b::c
+    c::b
+
+/[-az]+/
+    az-
+    *** Failers
+    b
+
+/[az-]+/
+    za-
+    *** Failers
+    b
+
+/[a\-z]+/
+    a-z
+    *** Failers
+    b
+
+/[a-z]+/
+    abcdxyz
+
+/[\d-]+/
+    12-34
+    *** Failers
+    aaa
+
+/[\d-z]+/
+    12-34z
+    *** Failers
+    aaa
+
+/\x5c/
+    \\
+
+/\x20Z/
+    the Zoo
+    *** Failers
+    Zulu
+
+/(abc)\1/i
+    abcabc
+    ABCabc
+    abcABC
+
+/ab{3cd/
+    ab{3cd
+
+/ab{3,cd/
+    ab{3,cd
+
+/ab{3,4a}cd/
+    ab{3,4a}cd
+
+/{4,5a}bc/
+    {4,5a}bc
+
+/^a.b/
+    a\rb
+    *** Failers
+    a\nb
+
+/abc$/
+    abc
+    abc\n
+    *** Failers
+    abc\ndef
+
+/(abc)\123/
+    abc\x53
+
+/(abc)\223/
+    abc\x93
+
+/(abc)\323/
+    abc\xd3
+
+/(abc)\500/
+    abc\x40
+    abc\100
+
+/(abc)\5000/
+    abc\x400
+    abc\x40\x30
+    abc\1000
+    abc\100\x30
+    abc\100\060
+    abc\100\60
+
+/abc\81/
+    abc\081
+    abc\0\x38\x31
+
+/abc\91/
+    abc\091
+    abc\0\x39\x31
+
+/(a)(b)(c)(d)(e)(f)(g)(h)(i)(j)(k)(l)\12\123/
+    abcdefghijkllS
+
+/(a)(b)(c)(d)(e)(f)(g)(h)(i)(j)(k)\12\123/
+    abcdefghijk\12S
+
+/ab\gdef/
+    abgdef
+
+/a{0}bc/
+    bc
+
+/(a|(bc)){0,0}?xyz/
+    xyz
+
+/abc[\10]de/
+    abc\010de
+
+/abc[\1]de/
+    abc\1de
+
+/(abc)[\1]de/
+    abc\1de
+
+/(?s)a.b/
+    a\nb
+
+/^([^a])([^\b])([^c]*)([^d]{3,4})/
+    baNOTccccd
+    baNOTcccd
+    baNOTccd
+    bacccd
+    *** Failers
+    anything
+    b\bc   
+    baccd
+
+/[^a]/
+    Abc
+  
+/[^a]/i
+    Abc 
+
+/[^a]+/
+    AAAaAbc
+  
+/[^a]+/i
+    AAAaAbc 
+
+/[^a]+/
+    bbb\nccc
+   
+/[^k]$/
+    abc
+    *** Failers
+    abk   
+   
+/[^k]{2,3}$/
+    abc
+    kbc
+    kabc 
+    *** Failers
+    abk
+    akb
+    akk 
+
+/^\d{8,}\@.+[^k]$/
+    12345678\@a.b.c.d
+    123456789\@x.y.z
+    *** Failers
+    12345678\@x.y.uk
+    1234567\@a.b.c.d       
+
+/(a)\1{8,}/
+    aaaaaaaaa
+    aaaaaaaaaa
+    *** Failers
+    aaaaaaa   
+
+/[^a]/
+    aaaabcd
+    aaAabcd 
+
+/[^a]/i
+    aaaabcd
+    aaAabcd 
+
+/[^az]/
+    aaaabcd
+    aaAabcd 
+
+/[^az]/i
+    aaaabcd
+    aaAabcd 
+
+/\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327\330\331\332\333\334\335\336\337\340\341\342\343\344\345\346\347\350\351\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373\374\375\376\377/
+ \000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327\330\331\332\333\334\335\336\337\340\341\342\343\344\345\346\347\350\351\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373\374\375\376\377
+
+/P[^*]TAIRE[^*]{1,6}?LL/
+    xxxxxxxxxxxPSTAIREISLLxxxxxxxxx
+
+/P[^*]TAIRE[^*]{1,}?LL/
+    xxxxxxxxxxxPSTAIREISLLxxxxxxxxx
+
+/(\.\d\d[1-9]?)\d+/
+    1.230003938
+    1.875000282   
+    1.235  
+                  
+/(\.\d\d((?=0)|\d(?=\d)))/
+    1.230003938      
+    1.875000282
+    *** Failers 
+    1.235 
+    
+/a(?)b/
+    ab 
+ 
+/\b(foo)\s+(\w+)/i
+    Food is on the foo table
+    
+/foo(.*)bar/
+    The food is under the bar in the barn.
+    
+/foo(.*?)bar/  
+    The food is under the bar in the barn.
+
+/(.*)(\d*)/
+    I have 2 numbers: 53147
+    
+/(.*)(\d+)/
+    I have 2 numbers: 53147
+ 
+/(.*?)(\d*)/
+    I have 2 numbers: 53147
+
+/(.*?)(\d+)/
+    I have 2 numbers: 53147
+
+/(.*)(\d+)$/
+    I have 2 numbers: 53147
+
+/(.*?)(\d+)$/
+    I have 2 numbers: 53147
+
+/(.*)\b(\d+)$/
+    I have 2 numbers: 53147
+
+/(.*\D)(\d+)$/
+    I have 2 numbers: 53147
+
+/^\D*(?!123)/
+    ABC123
+     
+/^(\D*)(?=\d)(?!123)/
+    ABC445
+    *** Failers
+    ABC123
+    
+/^[W-]46]/
+    W46]789 
+    -46]789
+    *** Failers
+    Wall
+    Zebra
+    42
+    [abcd] 
+    ]abcd[
+       
+/^[W-\]46]/
+    W46]789 
+    Wall
+    Zebra
+    Xylophone  
+    42
+    [abcd] 
+    ]abcd[
+    \\backslash 
+    *** Failers
+    -46]789
+    well
+    
+/\d\d\/\d\d\/\d\d\d\d/
+    01/01/2000
+
+/word (?:[a-zA-Z0-9]+ ){0,10}otherword/
+  word cat dog elephant mussel cow horse canary baboon snake shark otherword
+  word cat dog elephant mussel cow horse canary baboon snake shark
+
+/word (?:[a-zA-Z0-9]+ ){0,300}otherword/
+  word cat dog elephant mussel cow horse canary baboon snake shark the quick brown fox and the lazy dog and several other words getting close to thirty by now I hope
+
+/^(a){0,0}/
+    bcd
+    abc
+    aab     
+
+/^(a){0,1}/
+    bcd
+    abc
+    aab  
+
+/^(a){0,2}/
+    bcd
+    abc
+    aab  
+
+/^(a){0,3}/
+    bcd
+    abc
+    aab
+    aaa   
+
+/^(a){0,}/
+    bcd
+    abc
+    aab
+    aaa
+    aaaaaaaa    
+
+/^(a){1,1}/
+    bcd
+    abc
+    aab  
+
+/^(a){1,2}/
+    bcd
+    abc
+    aab  
+
+/^(a){1,3}/
+    bcd
+    abc
+    aab
+    aaa   
+
+/^(a){1,}/
+    bcd
+    abc
+    aab
+    aaa
+    aaaaaaaa    
+
+/.*\.gif/
+    borfle\nbib.gif\nno
+
+/.{0,}\.gif/
+    borfle\nbib.gif\nno
+
+/.*\.gif/m
+    borfle\nbib.gif\nno
+
+/.*\.gif/s
+    borfle\nbib.gif\nno
+
+/.*\.gif/ms
+    borfle\nbib.gif\nno
+    
+/.*$/
+    borfle\nbib.gif\nno
+
+/.*$/m
+    borfle\nbib.gif\nno
+
+/.*$/s
+    borfle\nbib.gif\nno
+
+/.*$/ms
+    borfle\nbib.gif\nno
+    
+/.*$/
+    borfle\nbib.gif\nno\n
+
+/.*$/m
+    borfle\nbib.gif\nno\n
+
+/.*$/s
+    borfle\nbib.gif\nno\n
+
+/.*$/ms
+    borfle\nbib.gif\nno\n
+    
+/(.*X|^B)/
+    abcde\n1234Xyz
+    BarFoo 
+    *** Failers
+    abcde\nBar  
+
+/(.*X|^B)/m
+    abcde\n1234Xyz
+    BarFoo 
+    abcde\nBar  
+
+/(.*X|^B)/s
+    abcde\n1234Xyz
+    BarFoo 
+    *** Failers
+    abcde\nBar  
+
+/(.*X|^B)/ms
+    abcde\n1234Xyz
+    BarFoo 
+    abcde\nBar  
+
+/(?s)(.*X|^B)/
+    abcde\n1234Xyz
+    BarFoo 
+    *** Failers 
+    abcde\nBar  
+
+/(?s:.*X|^B)/
+    abcde\n1234Xyz
+    BarFoo 
+    *** Failers 
+    abcde\nBar  
+
+/^.*B/
+    **** Failers
+    abc\nB
+     
+/(?s)^.*B/
+    abc\nB
+
+/(?m)^.*B/
+    abc\nB
+     
+/(?ms)^.*B/
+    abc\nB
+
+/(?ms)^B/
+    abc\nB
+
+/(?s)B$/
+    B\n
+
+/^[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]/
+    123456654321
+  
+/^\d\d\d\d\d\d\d\d\d\d\d\d/
+    123456654321 
+
+/^[\d][\d][\d][\d][\d][\d][\d][\d][\d][\d][\d][\d]/
+    123456654321
+  
+/^[abc]{12}/
+    abcabcabcabc
+    
+/^[a-c]{12}/
+    abcabcabcabc
+    
+/^(a|b|c){12}/
+    abcabcabcabc 
+
+/^[abcdefghijklmnopqrstuvwxy0123456789]/
+    n
+    *** Failers 
+    z 
+
+/abcde{0,0}/
+    abcd
+    *** Failers
+    abce  
+
+/ab[cd]{0,0}e/
+    abe
+    *** Failers
+    abcde 
+    
+/ab(c){0,0}d/
+    abd
+    *** Failers
+    abcd   
+
+/a(b*)/
+    a
+    ab
+    abbbb
+    *** Failers
+    bbbbb    
+    
+/ab\d{0}e/
+    abe
+    *** Failers
+    ab1e   
+    
+/"([^\\"]+|\\.)*"/
+    the \"quick\" brown fox
+    \"the \\\"quick\\\" brown fox\" 
+
+/.*?/g+
+    abc
+  
+/\b/g+
+    abc 
+
+/\b/+g
+    abc 
+
+//g
+    abc
+
+/<tr([\w\W\s\d][^<>]{0,})><TD([\w\W\s\d][^<>]{0,})>([\d]{0,}\.)(.*)((<BR>([\w\W\s\d][^<>]{0,})|[\s]{0,}))<\/a><\/TD><TD([\w\W\s\d][^<>]{0,})>([\w\W\s\d][^<>]{0,})<\/TD><TD([\w\W\s\d][^<>]{0,})>([\w\W\s\d][^<>]{0,})<\/TD><\/TR>/is
+  <TR BGCOLOR='#DBE9E9'><TD align=left valign=top>43.<a href='joblist.cfm?JobID=94 6735&Keyword='>Word Processor<BR>(N-1286)</a></TD><TD align=left valign=top>Lega lstaff.com</TD><TD align=left valign=top>CA - Statewide</TD></TR>
+
+/a[^a]b/
+    acb
+    a\nb
+    
+/a.b/
+    acb
+    *** Failers 
+    a\nb   
+    
+/a[^a]b/s
+    acb
+    a\nb  
+    
+/a.b/s
+    acb
+    a\nb  
+
+/^(b+?|a){1,2}?c/
+    bac
+    bbac
+    bbbac
+    bbbbac
+    bbbbbac 
+
+/^(b+|a){1,2}?c/
+    bac
+    bbac
+    bbbac
+    bbbbac
+    bbbbbac 
+    
+/(?!\A)x/m
+    x\nb\n
+    a\bx\n  
+    
+/\x0{ab}/
+    \0{ab} 
+
+/(A|B)*?CD/
+    CD 
+    
+/(A|B)*CD/
+    CD 
+
+/(AB)*?\1/
+    ABABAB
+
+/(AB)*\1/
+    ABABAB
+    
+/(?<!bar)foo/
+    foo
+    catfood
+    arfootle
+    rfoosh
+    *** Failers
+    barfoo
+    towbarfoo
+
+/\w{3}(?<!bar)foo/
+    catfood
+    *** Failers
+    foo
+    barfoo
+    towbarfoo
+
+/(?<=(foo)a)bar/
+    fooabar
+    *** Failers
+    bar
+    foobbar
+      
+/\Aabc\z/m
+    abc
+    *** Failers
+    abc\n   
+    qqq\nabc
+    abc\nzzz
+    qqq\nabc\nzzz
+
+"(?>.*/)foo"
+    /this/is/a/very/long/line/in/deed/with/very/many/slashes/in/it/you/see/
+
+"(?>.*/)foo"
+    /this/is/a/very/long/line/in/deed/with/very/many/slashes/in/and/foo
+
+/(?>(\.\d\d[1-9]?))\d+/
+    1.230003938
+    1.875000282
+    *** Failers 
+    1.235 
+
+/^((?>\w+)|(?>\s+))*$/
+    now is the time for all good men to come to the aid of the party
+    *** Failers
+    this is not a line with only words and spaces!
+    
+/(\d+)(\w)/
+    12345a
+    12345+ 
+
+/((?>\d+))(\w)/
+    12345a
+    *** Failers
+    12345+ 
+
+/(?>a+)b/
+    aaab
+
+/((?>a+)b)/
+    aaab
+
+/(?>(a+))b/
+    aaab
+
+/(?>b)+/
+    aaabbbccc
+
+/(?>a+|b+|c+)*c/
+    aaabbbbccccd
+
+/((?>[^()]+)|\([^()]*\))+/
+    ((abc(ade)ufh()()x
+    
+/\(((?>[^()]+)|\([^()]+\))+\)/ 
+    (abc)
+    (abc(def)xyz)
+    *** Failers
+    ((()aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa   
+
+/a(?-i)b/i
+    ab
+    Ab
+    *** Failers 
+    aB
+    AB
+        
+/(a (?x)b c)d e/
+    a bcd e
+    *** Failers
+    a b cd e
+    abcd e   
+    a bcde 
+ 
+/(a b(?x)c d (?-x)e f)/
+    a bcde f
+    *** Failers
+    abcdef  
+
+/(a(?i)b)c/
+    abc
+    aBc
+    *** Failers
+    abC
+    aBC  
+    Abc
+    ABc
+    ABC
+    AbC
+    
+/a(?i:b)c/
+    abc
+    aBc
+    *** Failers 
+    ABC
+    abC
+    aBC
+    
+/a(?i:b)*c/
+    aBc
+    aBBc
+    *** Failers 
+    aBC
+    aBBC
+    
+/a(?=b(?i)c)\w\wd/
+    abcd
+    abCd
+    *** Failers
+    aBCd
+    abcD     
+    
+/(?s-i:more.*than).*million/i
+    more than million
+    more than MILLION
+    more \n than Million 
+    *** Failers
+    MORE THAN MILLION    
+    more \n than \n million 
+
+/(?:(?s-i)more.*than).*million/i
+    more than million
+    more than MILLION
+    more \n than Million 
+    *** Failers
+    MORE THAN MILLION    
+    more \n than \n million 
+    
+/(?>a(?i)b+)+c/ 
+    abc
+    aBbc
+    aBBc 
+    *** Failers
+    Abc
+    abAb    
+    abbC 
+    
+/(?=a(?i)b)\w\wc/
+    abc
+    aBc
+    *** Failers
+    Ab 
+    abC
+    aBC     
+    
+/(?<=a(?i)b)(\w\w)c/
+    abxxc
+    aBxxc
+    *** Failers
+    Abxxc
+    ABxxc
+    abxxC      
+
+/(?:(a)|b)(?(1)A|B)/
+    aA
+    bB
+    *** Failers
+    aB
+    bA    
+
+/^(a)?(?(1)a|b)+$/
+    aa
+    b
+    bb  
+    *** Failers
+    ab   
+
+/^(?(?=abc)\w{3}:|\d\d)$/
+    abc:
+    12
+    *** Failers
+    123
+    xyz    
+
+/^(?(?!abc)\d\d|\w{3}:)$/
+    abc:
+    12
+    *** Failers
+    123
+    xyz    
+    
+/(?(?<=foo)bar|cat)/
+    foobar
+    cat
+    fcat
+    focat   
+    *** Failers
+    foocat  
+
+/(?(?<!foo)cat|bar)/
+    foobar
+    cat
+    fcat
+    focat   
+    *** Failers
+    foocat  
+
+/( \( )? [^()]+ (?(1) \) |) /x
+    abcd
+    (abcd)
+    the quick (abcd) fox
+    (abcd   
+
+/( \( )? [^()]+ (?(1) \) ) /x
+    abcd
+    (abcd)
+    the quick (abcd) fox
+    (abcd   
+
+/^(?(2)a|(1)(2))+$/
+    12
+    12a
+    12aa
+    *** Failers
+    1234    
+
+/((?i)blah)\s+\1/
+    blah blah
+    BLAH BLAH
+    Blah Blah
+    blaH blaH
+    *** Failers
+    blah BLAH
+    Blah blah      
+    blaH blah 
+
+/((?i)blah)\s+(?i:\1)/
+    blah blah
+    BLAH BLAH
+    Blah Blah
+    blaH blaH
+    blah BLAH
+    Blah blah      
+    blaH blah 
+
+/(?>a*)*/
+    a
+    aa
+    aaaa
+    
+/(abc|)+/
+    abc
+    abcabc
+    abcabcabc
+    xyz      
+
+/([a]*)*/
+    a
+    aaaaa 
+ 
+/([ab]*)*/
+    a
+    b
+    ababab
+    aaaabcde
+    bbbb    
+ 
+/([^a]*)*/
+    b
+    bbbb
+    aaa   
+ 
+/([^ab]*)*/
+    cccc
+    abab  
+ 
+/([a]*?)*/
+    a
+    aaaa 
+ 
+/([ab]*?)*/
+    a
+    b
+    abab
+    baba   
+ 
+/([^a]*?)*/
+    b
+    bbbb
+    aaa   
+ 
+/([^ab]*?)*/
+    c
+    cccc
+    baba   
+ 
+/(?>a*)*/
+    a
+    aaabcde 
+ 
+/((?>a*))*/
+    aaaaa
+    aabbaa 
+ 
+/((?>a*?))*/
+    aaaaa
+    aabbaa 
+
+/(?(?=[^a-z]+[a-z])  \d{2}-[a-z]{3}-\d{2}  |  \d{2}-\d{2}-\d{2} ) /x
+    12-sep-98
+    12-09-98
+    *** Failers
+    sep-12-98
+        
+/(?<=(foo))bar\1/
+    foobarfoo
+    foobarfootling 
+    *** Failers
+    foobar
+    barfoo   
+
+/(?i:saturday|sunday)/
+    saturday
+    sunday
+    Saturday
+    Sunday
+    SATURDAY
+    SUNDAY
+    SunDay
+    
+/(a(?i)bc|BB)x/
+    abcx
+    aBCx
+    bbx
+    BBx
+    *** Failers
+    abcX
+    aBCX
+    bbX
+    BBX               
+
+/^([ab](?i)[cd]|[ef])/
+    ac
+    aC
+    bD
+    elephant
+    Europe 
+    frog
+    France
+    *** Failers
+    Africa     
+
+/^(ab|a(?i)[b-c](?m-i)d|x(?i)y|z)/
+    ab
+    aBd
+    xy
+    xY
+    zebra
+    Zambesi
+    *** Failers
+    aCD  
+    XY  
+
+/(?<=foo\n)^bar/m
+    foo\nbar
+    *** Failers
+    bar
+    baz\nbar   
+
+/(?<=(?<!foo)bar)baz/
+    barbaz
+    barbarbaz 
+    koobarbaz 
+    *** Failers
+    baz
+    foobarbaz 
+
+/The case of aaaaaa is missed out below because I think Perl 5.005_02 gets/
+/it wrong; it sets $1 to aaa rather than aa. Compare the following test,/
+/where it does set $1 to aa when matching aaaaaa./
+
+/^(a\1?){4}$/
+    a
+    aa
+    aaa
+    aaaa
+    aaaaa
+    aaaaaaa
+    aaaaaaaa
+    aaaaaaaaa
+    aaaaaaaaaa
+    aaaaaaaaaaa
+    aaaaaaaaaaaa
+    aaaaaaaaaaaaa
+    aaaaaaaaaaaaaa
+    aaaaaaaaaaaaaaa
+    aaaaaaaaaaaaaaaa               
+
+/^(a\1?)(a\1?)(a\2?)(a\3?)$/
+    a
+    aa
+    aaa
+    aaaa
+    aaaaa
+    aaaaaa
+    aaaaaaa
+    aaaaaaaa
+    aaaaaaaaa
+    aaaaaaaaaa
+    aaaaaaaaaaa
+    aaaaaaaaaaaa
+    aaaaaaaaaaaaa
+    aaaaaaaaaaaaaa
+    aaaaaaaaaaaaaaa
+    aaaaaaaaaaaaaaaa               
+
+/The following tests are taken from the Perl 5.005 test suite; some of them/
+/are compatible with 5.004, but I'd rather not have to sort them out./
+
+/abc/
+    abc
+    xabcy
+    ababc
+    *** Failers
+    xbc
+    axc
+    abx
+
+/ab*c/
+    abc
+
+/ab*bc/
+    abc
+    abbc
+    abbbbc
+
+/.{1}/
+    abbbbc
+
+/.{3,4}/
+    abbbbc
+
+/ab{0,}bc/
+    abbbbc
+
+/ab+bc/
+    abbc
+    *** Failers
+    abc
+    abq
+
+/ab{1,}bc/
+
+/ab+bc/
+    abbbbc
+
+/ab{1,}bc/
+    abbbbc
+
+/ab{1,3}bc/
+    abbbbc
+
+/ab{3,4}bc/
+    abbbbc
+
+/ab{4,5}bc/
+    *** Failers
+    abq
+    abbbbc
+
+/ab?bc/
+    abbc
+    abc
+
+/ab{0,1}bc/
+    abc
+
+/ab?bc/
+
+/ab?c/
+    abc
+
+/ab{0,1}c/
+    abc
+
+/^abc$/
+    abc
+    *** Failers
+    abbbbc
+    abcc
+
+/^abc/
+    abcc
+
+/^abc$/
+
+/abc$/
+    aabc
+    *** Failers
+    aabc
+    aabcd
+
+/^/
+    abc
+
+/$/
+    abc
+
+/a.c/
+    abc
+    axc
+
+/a.*c/
+    axyzc
+
+/a[bc]d/
+    abd
+    *** Failers
+    axyzd
+    abc
+
+/a[b-d]e/
+    ace
+
+/a[b-d]/
+    aac
+
+/a[-b]/
+    a-
+
+/a[b-]/
+    a-
+
+/a]/
+    a]
+
+/a[]]b/
+    a]b
+
+/a[^bc]d/
+    aed
+    *** Failers
+    abd
+    abd
+
+/a[^-b]c/
+    adc
+
+/a[^]b]c/
+    adc
+    *** Failers
+    a-c
+    a]c
+
+/\ba\b/
+    a-
+    -a
+    -a-
+
+/\by\b/
+    *** Failers
+    xy
+    yz
+    xyz
+
+/\Ba\B/
+    *** Failers
+    a-
+    -a
+    -a-
+
+/\By\b/
+    xy
+
+/\by\B/
+    yz
+
+/\By\B/
+    xyz
+
+/\w/
+    a
+
+/\W/
+    -
+    *** Failers
+    -
+    a
+
+/a\sb/
+    a b
+
+/a\Sb/
+    a-b
+    *** Failers
+    a-b
+    a b
+
+/\d/
+    1
+
+/\D/
+    -
+    *** Failers
+    -
+    1
+
+/[\w]/
+    a
+
+/[\W]/
+    -
+    *** Failers
+    -
+    a
+
+/a[\s]b/
+    a b
+
+/a[\S]b/
+    a-b
+    *** Failers
+    a-b
+    a b
+
+/[\d]/
+    1
+
+/[\D]/
+    -
+    *** Failers
+    -
+    1
+
+/ab|cd/
+    abc
+    abcd
+
+/()ef/
+    def
+
+/$b/
+
+/a\(b/
+    a(b
+
+/a\(*b/
+    ab
+    a((b
+
+/a\\b/
+    a\b
+
+/((a))/
+    abc
+
+/(a)b(c)/
+    abc
+
+/a+b+c/
+    aabbabc
+
+/a{1,}b{1,}c/
+    aabbabc
+
+/a.+?c/
+    abcabc
+
+/(a+|b)*/
+    ab
+
+/(a+|b){0,}/
+    ab
+
+/(a+|b)+/
+    ab
+
+/(a+|b){1,}/
+    ab
+
+/(a+|b)?/
+    ab
+
+/(a+|b){0,1}/
+    ab
+
+/[^ab]*/
+    cde
+
+/abc/
+    *** Failers
+    b
+    
+
+/a*/
+    
+
+/([abc])*d/
+    abbbcd
+
+/([abc])*bcd/
+    abcd
+
+/a|b|c|d|e/
+    e
+
+/(a|b|c|d|e)f/
+    ef
+
+/abcd*efg/
+    abcdefg
+
+/ab*/
+    xabyabbbz
+    xayabbbz
+
+/(ab|cd)e/
+    abcde
+
+/[abhgefdc]ij/
+    hij
+
+/^(ab|cd)e/
+
+/(abc|)ef/
+    abcdef
+
+/(a|b)c*d/
+    abcd
+
+/(ab|ab*)bc/
+    abc
+
+/a([bc]*)c*/
+    abc
+
+/a([bc]*)(c*d)/
+    abcd
+
+/a([bc]+)(c*d)/
+    abcd
+
+/a([bc]*)(c+d)/
+    abcd
+
+/a[bcd]*dcdcde/
+    adcdcde
+
+/a[bcd]+dcdcde/
+    *** Failers
+    abcde
+    adcdcde
+
+/(ab|a)b*c/
+    abc
+
+/((a)(b)c)(d)/
+    abcd
+
+/[a-zA-Z_][a-zA-Z0-9_]*/
+    alpha
+
+/^a(bc+|b[eh])g|.h$/
+    abh
+
+/(bc+d$|ef*g.|h?i(j|k))/
+    effgz
+    ij
+    reffgz
+    *** Failers
+    effg
+    bcdd
+
+/((((((((((a))))))))))/
+    a
+
+/((((((((((a))))))))))\10/
+    aa
+
+/(((((((((a)))))))))/
+    a
+
+/multiple words of text/
+    *** Failers
+    aa
+    uh-uh
+
+/multiple words/
+    multiple words, yeah
+
+/(.*)c(.*)/
+    abcde
+
+/\((.*), (.*)\)/
+    (a, b)
+
+/[k]/
+
+/abcd/
+    abcd
+
+/a(bc)d/
+    abcd
+
+/a[-]?c/
+    ac
+
+/(abc)\1/
+    abcabc
+
+/([a-c]*)\1/
+    abcabc
+
+/(a)|\1/
+    a
+    *** Failers
+    ab
+    x
+
+/(([a-c])b*?\2)*/
+    ababbbcbc
+
+/(([a-c])b*?\2){3}/
+    ababbbcbc
+
+/((\3|b)\2(a)x)+/
+    aaaxabaxbaaxbbax
+
+/((\3|b)\2(a)){2,}/
+    bbaababbabaaaaabbaaaabba
+
+/abc/i
+    ABC
+    XABCY
+    ABABC
+    *** Failers
+    aaxabxbaxbbx
+    XBC
+    AXC
+    ABX
+
+/ab*c/i
+    ABC
+
+/ab*bc/i
+    ABC
+    ABBC
+
+/ab*?bc/i
+    ABBBBC
+
+/ab{0,}?bc/i
+    ABBBBC
+
+/ab+?bc/i
+    ABBC
+
+/ab+bc/i
+    *** Failers
+    ABC
+    ABQ
+
+/ab{1,}bc/i
+
+/ab+bc/i
+    ABBBBC
+
+/ab{1,}?bc/i
+    ABBBBC
+
+/ab{1,3}?bc/i
+    ABBBBC
+
+/ab{3,4}?bc/i
+    ABBBBC
+
+/ab{4,5}?bc/i
+    *** Failers
+    ABQ
+    ABBBBC
+
+/ab??bc/i
+    ABBC
+    ABC
+
+/ab{0,1}?bc/i
+    ABC
+
+/ab??bc/i
+
+/ab??c/i
+    ABC
+
+/ab{0,1}?c/i
+    ABC
+
+/^abc$/i
+    ABC
+    *** Failers
+    ABBBBC
+    ABCC
+
+/^abc/i
+    ABCC
+
+/^abc$/i
+
+/abc$/i
+    AABC
+
+/^/i
+    ABC
+
+/$/i
+    ABC
+
+/a.c/i
+    ABC
+    AXC
+
+/a.*?c/i
+    AXYZC
+
+/a.*c/i
+    *** Failers
+    AABC
+    AXYZD
+
+/a[bc]d/i
+    ABD
+
+/a[b-d]e/i
+    ACE
+    *** Failers
+    ABC
+    ABD
+
+/a[b-d]/i
+    AAC
+
+/a[-b]/i
+    A-
+
+/a[b-]/i
+    A-
+
+/a]/i
+    A]
+
+/a[]]b/i
+    A]B
+
+/a[^bc]d/i
+    AED
+
+/a[^-b]c/i
+    ADC
+    *** Failers
+    ABD
+    A-C
+
+/a[^]b]c/i
+    ADC
+
+/ab|cd/i
+    ABC
+    ABCD
+
+/()ef/i
+    DEF
+
+/$b/i
+    *** Failers
+    A]C
+    B
+
+/a\(b/i
+    A(B
+
+/a\(*b/i
+    AB
+    A((B
+
+/a\\b/i
+    A\B
+
+/((a))/i
+    ABC
+
+/(a)b(c)/i
+    ABC
+
+/a+b+c/i
+    AABBABC
+
+/a{1,}b{1,}c/i
+    AABBABC
+
+/a.+?c/i
+    ABCABC
+
+/a.*?c/i
+    ABCABC
+
+/a.{0,5}?c/i
+    ABCABC
+
+/(a+|b)*/i
+    AB
+
+/(a+|b){0,}/i
+    AB
+
+/(a+|b)+/i
+    AB
+
+/(a+|b){1,}/i
+    AB
+
+/(a+|b)?/i
+    AB
+
+/(a+|b){0,1}/i
+    AB
+
+/(a+|b){0,1}?/i
+    AB
+
+/[^ab]*/i
+    CDE
+
+/abc/i
+
+/a*/i
+    
+
+/([abc])*d/i
+    ABBBCD
+
+/([abc])*bcd/i
+    ABCD
+
+/a|b|c|d|e/i
+    E
+
+/(a|b|c|d|e)f/i
+    EF
+
+/abcd*efg/i
+    ABCDEFG
+
+/ab*/i
+    XABYABBBZ
+    XAYABBBZ
+
+/(ab|cd)e/i
+    ABCDE
+
+/[abhgefdc]ij/i
+    HIJ
+
+/^(ab|cd)e/i
+    ABCDE
+
+/(abc|)ef/i
+    ABCDEF
+
+/(a|b)c*d/i
+    ABCD
+
+/(ab|ab*)bc/i
+    ABC
+
+/a([bc]*)c*/i
+    ABC
+
+/a([bc]*)(c*d)/i
+    ABCD
+
+/a([bc]+)(c*d)/i
+    ABCD
+
+/a([bc]*)(c+d)/i
+    ABCD
+
+/a[bcd]*dcdcde/i
+    ADCDCDE
+
+/a[bcd]+dcdcde/i
+
+/(ab|a)b*c/i
+    ABC
+
+/((a)(b)c)(d)/i
+    ABCD
+
+/[a-zA-Z_][a-zA-Z0-9_]*/i
+    ALPHA
+
+/^a(bc+|b[eh])g|.h$/i
+    ABH
+
+/(bc+d$|ef*g.|h?i(j|k))/i
+    EFFGZ
+    IJ
+    REFFGZ
+    *** Failers
+    ADCDCDE
+    EFFG
+    BCDD
+
+/((((((((((a))))))))))/i
+    A
+
+/((((((((((a))))))))))\10/i
+    AA
+
+/(((((((((a)))))))))/i
+    A
+
+/(?:(?:(?:(?:(?:(?:(?:(?:(?:(a))))))))))/i
+    A
+
+/(?:(?:(?:(?:(?:(?:(?:(?:(?:(a|b|c))))))))))/i
+    C
+
+/multiple words of text/i
+    *** Failers
+    AA
+    UH-UH
+
+/multiple words/i
+    MULTIPLE WORDS, YEAH
+
+/(.*)c(.*)/i
+    ABCDE
+
+/\((.*), (.*)\)/i
+    (A, B)
+
+/[k]/i
+
+/abcd/i
+    ABCD
+
+/a(bc)d/i
+    ABCD
+
+/a[-]?c/i
+    AC
+
+/(abc)\1/i
+    ABCABC
+
+/([a-c]*)\1/i
+    ABCABC
+
+/a(?!b)./
+    abad
+
+/a(?=d)./
+    abad
+
+/a(?=c|d)./
+    abad
+
+/a(?:b|c|d)(.)/
+    ace
+
+/a(?:b|c|d)*(.)/
+    ace
+
+/a(?:b|c|d)+?(.)/
+    ace
+    acdbcdbe
+
+/a(?:b|c|d)+(.)/
+    acdbcdbe
+
+/a(?:b|c|d){2}(.)/
+    acdbcdbe
+
+/a(?:b|c|d){4,5}(.)/
+    acdbcdbe
+
+/a(?:b|c|d){4,5}?(.)/
+    acdbcdbe
+
+/((foo)|(bar))*/
+    foobar
+
+/a(?:b|c|d){6,7}(.)/
+    acdbcdbe
+
+/a(?:b|c|d){6,7}?(.)/
+    acdbcdbe
+
+/a(?:b|c|d){5,6}(.)/
+    acdbcdbe
+
+/a(?:b|c|d){5,6}?(.)/
+    acdbcdbe
+
+/a(?:b|c|d){5,7}(.)/
+    acdbcdbe
+
+/a(?:b|c|d){5,7}?(.)/
+    acdbcdbe
+
+/a(?:b|(c|e){1,2}?|d)+?(.)/
+    ace
+
+/^(.+)?B/
+    AB
+
+/^([^a-z])|(\^)$/
+    .
+
+/^[<>]&/
+    <&OUT
+
+/^(a\1?){4}$/
+    aaaaaaaaaa
+    *** Failers
+    AB
+    aaaaaaaaa
+    aaaaaaaaaaa
+
+/^(a(?(1)\1)){4}$/
+    aaaaaaaaaa
+    *** Failers
+    aaaaaaaaa
+    aaaaaaaaaaa
+
+/(?:(f)(o)(o)|(b)(a)(r))*/
+    foobar
+
+/(?<=a)b/
+    ab
+    *** Failers
+    cb
+    b
+
+/(?<!c)b/
+    ab
+    b
+    b
+
+/(?:..)*a/
+    aba
+
+/(?:..)*?a/
+    aba
+
+/^(?:b|a(?=(.)))*\1/
+    abc
+
+/^(){3,5}/
+    abc
+
+/^(a+)*ax/
+    aax
+
+/^((a|b)+)*ax/
+    aax
+
+/^((a|bc)+)*ax/
+    aax
+
+/(a|x)*ab/
+    cab
+
+/(a)*ab/
+    cab
+
+/(?:(?i)a)b/
+    ab
+
+/((?i)a)b/
+    ab
+
+/(?:(?i)a)b/
+    Ab
+
+/((?i)a)b/
+    Ab
+
+/(?:(?i)a)b/
+    *** Failers
+    cb
+    aB
+
+/((?i)a)b/
+
+/(?i:a)b/
+    ab
+
+/((?i:a))b/
+    ab
+
+/(?i:a)b/
+    Ab
+
+/((?i:a))b/
+    Ab
+
+/(?i:a)b/
+    *** Failers
+    aB
+    aB
+
+/((?i:a))b/
+
+/(?:(?-i)a)b/i
+    ab
+
+/((?-i)a)b/i
+    ab
+
+/(?:(?-i)a)b/i
+    aB
+
+/((?-i)a)b/i
+    aB
+
+/(?:(?-i)a)b/i
+    *** Failers
+    aB
+    Ab
+
+/((?-i)a)b/i
+
+/(?:(?-i)a)b/i
+    aB
+
+/((?-i)a)b/i
+    aB
+
+/(?:(?-i)a)b/i
+    *** Failers
+    Ab
+    AB
+
+/((?-i)a)b/i
+
+/(?-i:a)b/i
+    ab
+
+/((?-i:a))b/i
+    ab
+
+/(?-i:a)b/i
+    aB
+
+/((?-i:a))b/i
+    aB
+
+/(?-i:a)b/i
+    *** Failers
+    AB
+    Ab
+
+/((?-i:a))b/i
+
+/(?-i:a)b/i
+    aB
+
+/((?-i:a))b/i
+    aB
+
+/(?-i:a)b/i
+    *** Failers
+    Ab
+    AB
+
+/((?-i:a))b/i
+
+/((?-i:a.))b/i
+    *** Failers
+    AB
+    a\nB
+
+/((?s-i:a.))b/i
+    a\nB
+
+/(?:c|d)(?:)(?:a(?:)(?:b)(?:b(?:))(?:b(?:)(?:b)))/
+    cabbbb
+
+/(?:c|d)(?:)(?:aaaaaaaa(?:)(?:bbbbbbbb)(?:bbbbbbbb(?:))(?:bbbbbbbb(?:)(?:bbbbbbbb)))/
+    caaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
+
+/(ab)\d\1/i
+    Ab4ab
+    ab4Ab
+
+/foo\w*\d{4}baz/
+    foobar1234baz
+
+/x(~~)*(?:(?:F)?)?/
+    x~~
+
+/^a(?#xxx){3}c/
+    aaac
+
+/^a (?#xxx) (?#yyy) {3}c/x
+    aaac
+
+/(?<![cd])b/
+    *** Failers
+    B\nB
+    dbcb
+
+/(?<![cd])[ab]/
+    dbaacb
+
+/(?<!(c|d))b/
+
+/(?<!(c|d))[ab]/
+    dbaacb
+
+/(?<!cd)[ab]/
+    cdaccb
+
+/^(?:a?b?)*$/
+    *** Failers
+    dbcb
+    a--
+
+/((?s)^a(.))((?m)^b$)/
+    a\nb\nc\n
+
+/((?m)^b$)/
+    a\nb\nc\n
+
+/(?m)^b/
+    a\nb\n
+
+/(?m)^(b)/
+    a\nb\n
+
+/((?m)^b)/
+    a\nb\n
+
+/\n((?m)^b)/
+    a\nb\n
+
+/((?s).)c(?!.)/
+    a\nb\nc\n
+    a\nb\nc\n
+
+/((?s)b.)c(?!.)/
+    a\nb\nc\n
+    a\nb\nc\n
+
+/^b/
+
+/()^b/
+    *** Failers
+    a\nb\nc\n
+    a\nb\nc\n
+
+/((?m)^b)/
+    a\nb\nc\n
+
+/(?(1)a|b)/
+
+/(?(1)b|a)/
+    a
+
+/(x)?(?(1)a|b)/
+    *** Failers
+    a
+    a
+
+/(x)?(?(1)b|a)/
+    a
+
+/()?(?(1)b|a)/
+    a
+
+/()(?(1)b|a)/
+
+/()?(?(1)a|b)/
+    a
+
+/^(\()?blah(?(1)(\)))$/
+    (blah)
+    blah
+    *** Failers
+    a
+    blah)
+    (blah
+
+/^(\(+)?blah(?(1)(\)))$/
+    (blah)
+    blah
+    *** Failers
+    blah)
+    (blah
+
+/(?(?!a)a|b)/
+
+/(?(?!a)b|a)/
+    a
+
+/(?(?=a)b|a)/
+    *** Failers
+    a
+    a
+
+/(?(?=a)a|b)/
+    a
+
+/(?=(a+?))(\1ab)/
+    aaab
+
+/^(?=(a+?))\1ab/
+
+/(\w+:)+/
+    one:
+
+/$(?<=^(a))/
+    a
+
+/(?=(a+?))(\1ab)/
+    aaab
+
+/^(?=(a+?))\1ab/
+    *** Failers
+    aaab
+    aaab
+
+/([\w:]+::)?(\w+)$/
+    abcd
+    xy:z:::abcd
+
+/^[^bcd]*(c+)/
+    aexycd
+
+/(a*)b+/
+    caab
+
+/([\w:]+::)?(\w+)$/
+    abcd
+    xy:z:::abcd
+    *** Failers
+    abcd:
+    abcd:
+
+/^[^bcd]*(c+)/
+    aexycd
+
+/(>a+)ab/
+
+/(?>a+)b/
+    aaab
+
+/([[:]+)/
+    a:[b]:
+
+/([[=]+)/
+    a=[b]=
+
+/([[.]+)/
+    a.[b].
+
+/((?>a+)b)/
+    aaab
+
+/(?>(a+))b/
+    aaab
+
+/((?>[^()]+)|\([^()]*\))+/
+    ((abc(ade)ufh()()x
+
+/a\Z/
+    *** Failers
+    aaab
+    a\nb\n
+
+/b\Z/
+    a\nb\n
+
+/b\z/
+
+/b\Z/
+    a\nb
+
+/b\z/
+    a\nb
+    *** Failers
+    
+/^(?>(?(1)\.|())[^\W_](?>[a-z0-9-]*[^\W_])?)+$/
+    a
+    abc
+    a-b
+    0-9 
+    a.b
+    5.6.7  
+    the.quick.brown.fox
+    a100.b200.300c  
+    12-ab.1245 
+    *** Failers
+    \
+    .a
+    -a
+    a-
+    a.  
+    a_b 
+    a.-
+    a..  
+    ab..bc 
+    the.quick.brown.fox-
+    the.quick.brown.fox.
+    the.quick.brown.fox_
+    the.quick.brown.fox+       
+
+/(?>.*)(?<=(abcd|wxyz))/
+    alphabetabcd
+    endingwxyz
+    *** Failers
+    a rather long string that doesn't end with one of them
+
+/word (?>(?:(?!otherword)[a-zA-Z0-9]+ ){0,30})otherword/
+    word cat dog elephant mussel cow horse canary baboon snake shark otherword
+    word cat dog elephant mussel cow horse canary baboon snake shark
+  
+/word (?>[a-zA-Z0-9]+ ){0,30}otherword/
+    word cat dog elephant mussel cow horse canary baboon snake shark the quick brown fox and the lazy dog and several other words getting close to thirty by now I hope
+
+/(?<=\d{3}(?!999))foo/
+    999foo
+    123999foo 
+    *** Failers
+    123abcfoo
+    
+/(?<=(?!...999)\d{3})foo/
+    999foo
+    123999foo 
+    *** Failers
+    123abcfoo
+
+/(?<=\d{3}(?!999)...)foo/
+    123abcfoo
+    123456foo 
+    *** Failers
+    123999foo  
+    
+/(?<=\d{3}...)(?<!999)foo/
+    123abcfoo   
+    123456foo 
+    *** Failers
+    123999foo  
+
+/<a[\s]+href[\s]*=[\s]*          # find <a href=
+ ([\"\'])?                       # find single or double quote
+ (?(1) (.*?)\1 | ([^\s]+))       # if quote found, match up to next matching
+                                 # quote, otherwise match up to next space
+/isx
+    <a href=abcd xyz
+    <a href=\"abcd xyz pqr\" cats
+    <a href=\'abcd xyz pqr\' cats
+
+/<a\s+href\s*=\s*                # find <a href=
+ (["'])?                         # find single or double quote
+ (?(1) (.*?)\1 | (\S+))          # if quote found, match up to next matching
+                                 # quote, otherwise match up to next space
+/isx
+    <a href=abcd xyz
+    <a href=\"abcd xyz pqr\" cats
+    <a href       =       \'abcd xyz pqr\' cats
+
+/<a\s+href(?>\s*)=(?>\s*)        # find <a href=
+ (["'])?                         # find single or double quote
+ (?(1) (.*?)\1 | (\S+))          # if quote found, match up to next matching
+                                 # quote, otherwise match up to next space
+/isx
+    <a href=abcd xyz
+    <a href=\"abcd xyz pqr\" cats
+    <a href       =       \'abcd xyz pqr\' cats
+
+/((Z)+|A)*/
+    ZABCDEFG
+
+/(Z()|A)*/
+    ZABCDEFG
+
+/(Z(())|A)*/
+    ZABCDEFG
+
+/((?>Z)+|A)*/
+    ZABCDEFG
+
+/((?>)+|A)*/
+    ZABCDEFG
+
+/a*/g
+    abbab
+
+/^[a-\d]/
+    abcde
+    -things
+    0digit
+    *** Failers
+    bcdef    
+
+/^[\d-a]/
+    abcde
+    -things
+    0digit
+    *** Failers
+    bcdef    
+    
+/[[:space:]]+/
+    > \x09\x0a\x0c\x0d\x0b<
+     
+/[[:blank:]]+/
+    > \x09\x0a\x0c\x0d\x0b<
+     
+/[\s]+/
+    > \x09\x0a\x0c\x0d\x0b<
+     
+/\s+/
+    > \x09\x0a\x0c\x0d\x0b<
+     
+/ab/x
+    ab
+
+/(?!\A)x/m
+  a\nxb\n
+
+/(?!^)x/m
+  a\nxb\n
+
+/abc\Qabc\Eabc/
+    abcabcabc
+    
+/abc\Q(*+|\Eabc/
+    abc(*+|abc 
+
+/   abc\Q abc\Eabc/x
+    abc abcabc
+    *** Failers
+    abcabcabc  
+    
+/abc#comment
+    \Q#not comment
+    literal\E/x
+    abc#not comment\n    literal     
+
+/abc#comment
+    \Q#not comment
+    literal/x
+    abc#not comment\n    literal     
+
+/abc#comment
+    \Q#not comment
+    literal\E #more comment
+    /x
+    abc#not comment\n    literal     
+
+/abc#comment
+    \Q#not comment
+    literal\E #more comment/x
+    abc#not comment\n    literal     
+
+/\Qabc\$xyz\E/
+    abc\\\$xyz
+
+/\Qabc\E\$\Qxyz\E/
+    abc\$xyz
+
+/\Gabc/
+    abc
+    *** Failers
+    xyzabc  
+
+/\Gabc./g
+    abc1abc2xyzabc3
+
+/abc./g
+    abc1abc2xyzabc3 
+
+/a(?x: b c )d/
+    XabcdY
+    *** Failers 
+    Xa b c d Y 
+
+/((?x)x y z | a b c)/
+    XabcY
+    AxyzB 
+
+/(?i)AB(?-i)C/
+    XabCY
+    *** Failers
+    XabcY  
+
+/((?i)AB(?-i)C|D)E/
+    abCE
+    DE
+    *** Failers
+    abcE
+    abCe  
+    dE
+    De    
+
+/(.*)\d+\1/
+    abc123abc
+    abc123bc 
+
+/(.*)\d+\1/s
+    abc123abc
+    abc123bc 
+    
+/((.*))\d+\1/
+    abc123abc
+    abc123bc  
+
+/-- This tests for an IPv6 address in the form where it can have up to --/
+/-- eight components, one and only one of which is empty. This must be --/
+/-- an internal component. --/
+
+/^(?!:)                       # colon disallowed at start
+  (?:                         # start of item
+    (?: [0-9a-f]{1,4} |       # 1-4 hex digits or
+    (?(1)0 | () ) )           # if null previously matched, fail; else null
+    :                         # followed by colon
+  ){1,7}                      # end item; 1-7 of them required               
+  [0-9a-f]{1,4} $             # final hex number at end of string
+  (?(1)|.)                    # check that there was an empty component
+  /xi
+    a123::a123
+    a123:b342::abcd
+    a123:b342::324e:abcd
+    a123:ddde:b342::324e:abcd
+    a123:ddde:b342::324e:dcba:abcd
+    a123:ddde:9999:b342::324e:dcba:abcd
+    *** Failers
+    1:2:3:4:5:6:7:8
+    a123:bce:ddde:9999:b342::324e:dcba:abcd
+    a123::9999:b342::324e:dcba:abcd
+    abcde:2:3:4:5:6:7:8
+    ::1
+    abcd:fee0:123::   
+    :1
+    1:  
+
+/[z\Qa-d]\E]/
+    z
+    a
+    -
+    d
+    ] 
+    *** Failers
+    b     
+
+/[\z\C]/
+    z
+    C 
+    
+/\M/
+    M 
+    
+/(a+)*b/
+    aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 
+    
+/(?i)reg(?:ul(?:[aä]|ae)r|ex)/
+    REGular
+    regulaer
+    Regex  
+    regulär 
+
+/Åæåä[à-ÿÀ-ß]+/
+    Åæåäà
+    Åæåäÿ
+    ÅæåäÀ
+    Åæåäß
+
+/(?<=Z)X./
+  \x84XAZXB
+
+/ End of testinput1 /

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/testdata/testinput2
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/testdata/testinput2	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/testdata/testinput2	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,1396 @@
+/(a)b|/
+
+/abc/
+    abc
+    defabc
+    \Aabc
+    *** Failers
+    \Adefabc
+    ABC
+
+/^abc/
+    abc
+    \Aabc
+    *** Failers
+    defabc
+    \Adefabc
+
+/a+bc/
+
+/a*bc/
+
+/a{3}bc/
+
+/(abc|a+z)/
+
+/^abc$/
+    abc
+    *** Failers
+    def\nabc
+
+/ab\gdef/X
+
+/(?X)ab\gdef/X
+
+/x{5,4}/
+
+/z{65536}/
+
+/[abcd/
+
+/(?X)[\B]/
+
+/[z-a]/
+
+/^*/
+
+/(abc/
+
+/(?# abc/
+
+/(?z)abc/
+
+/.*b/
+
+/.*?b/
+
+/cat|dog|elephant/
+    this sentence eventually mentions a cat
+    this sentences rambles on and on for a while and then reaches elephant
+
+/cat|dog|elephant/S
+    this sentence eventually mentions a cat
+    this sentences rambles on and on for a while and then reaches elephant
+
+/cat|dog|elephant/iS
+    this sentence eventually mentions a CAT cat
+    this sentences rambles on and on for a while to elephant ElePhant
+
+/a|[bcd]/S
+
+/(a|[^\dZ])/S
+
+/(a|b)*[\s]/S
+
+/(ab\2)/
+
+/{4,5}abc/
+
+/(a)(b)(c)\2/
+    abcb
+    \O0abcb
+    \O3abcb
+    \O6abcb
+    \O9abcb
+    \O12abcb 
+
+/(a)bc|(a)(b)\2/
+    abc
+    \O0abc
+    \O3abc
+    \O6abc
+    aba
+    \O0aba
+    \O3aba
+    \O6aba
+    \O9aba
+    \O12aba
+
+/abc$/E
+    abc
+    *** Failers
+    abc\n
+    abc\ndef
+
+/(a)(b)(c)(d)(e)\6/
+
+/the quick brown fox/
+    the quick brown fox
+    this is a line with the quick brown fox
+
+/the quick brown fox/A
+    the quick brown fox
+    *** Failers
+    this is a line with the quick brown fox
+
+/ab(?z)cd/
+
+/^abc|def/
+    abcdef
+    abcdef\B
+
+/.*((abc)$|(def))/
+    defabc
+    \Zdefabc
+
+/abc/P
+    abc
+    *** Failers
+    
+/^abc|def/P
+    abcdef
+    abcdef\B
+
+/.*((abc)$|(def))/P
+    defabc
+    \Zdefabc
+  
+/the quick brown fox/P
+    the quick brown fox
+    *** Failers 
+    The Quick Brown Fox 
+
+/the quick brown fox/Pi
+    the quick brown fox
+    The Quick Brown Fox 
+
+/abc.def/P
+    *** Failers
+    abc\ndef
+    
+/abc$/P
+    abc
+    abc\n 
+
+/(abc)\2/P
+
+/(abc\1)/P
+    abc
+
+/)/
+
+/a[]b/
+
+/[^aeiou ]{3,}/
+    co-processors, and for 
+    
+/<.*>/
+    abc<def>ghi<klm>nop
+
+/<.*?>/
+    abc<def>ghi<klm>nop
+
+/<.*>/U
+    abc<def>ghi<klm>nop
+    
+/(?U)<.*>/
+    abc<def>ghi<klm>nop
+
+/<.*?>/U
+    abc<def>ghi<klm>nop
+    
+/={3,}/U
+    abc========def
+    
+/(?U)={3,}?/
+    abc========def
+    
+/(?<!bar|cattle)foo/
+    foo
+    catfoo 
+    *** Failers
+    the barfoo
+    and cattlefoo   
+
+/(?<=a+)b/
+
+/(?<=aaa|b{0,3})b/
+
+/(?<!(foo)a\1)bar/
+
+/(?i)abc/
+
+/(a|(?m)a)/
+
+/(?i)^1234/
+
+/(^b|(?i)^d)/
+
+/(?s).*/
+
+/[abcd]/S
+
+/(?i)[abcd]/S
+
+/(?m)[xy]|(b|c)/S
+
+/(^a|^b)/m
+
+/(?i)(^a|^b)/m
+
+/(a)(?(1)a|b|c)/
+
+/(?(?=a)a|b|c)/
+
+/(?(1a)/
+
+/(?(?i))/
+
+/(?(abc))/
+
+/(?(?<ab))/
+
+/((?s)blah)\s+\1/
+
+/((?i)blah)\s+\1/
+
+/((?i)b)/DS
+
+/(a*b|(?i:c*(?-i)d))/S
+
+/a$/
+    a
+    a\n
+    *** Failers 
+    \Za
+    \Za\n   
+
+/a$/m
+    a
+    a\n
+    \Za\n   
+    *** Failers 
+    \Za
+    
+/\Aabc/m
+
+/^abc/m 
+
+/^((a+)(?U)([ab]+)(?-U)([bc]+)(\w*))/
+  aaaaabbbbbcccccdef
+
+/(?<=foo)[ab]/S
+
+/(?<!foo)(alpha|omega)/S
+
+/(?!alphabet)[ab]/S
+
+/(?<=foo\n)^bar/m
+    foo\nbarbar 
+    ***Failers
+    rhubarb 
+    barbell
+    abc\nbarton 
+
+/^(?<=foo\n)bar/m
+    foo\nbarbar 
+    ***Failers
+    rhubarb 
+    barbell
+    abc\nbarton 
+
+/(?>^abc)/m
+    abc
+    def\nabc
+    *** Failers
+    defabc   
+
+/(?<=ab(c+)d)ef/
+
+/(?<=ab(?<=c+)d)ef/
+
+/(?<=ab(c|de)f)g/
+
+/The next three are in testinput2 because they have variable length branches/
+
+/(?<=bullock|donkey)-cart/
+    the bullock-cart
+    a donkey-cart race
+    *** Failers
+    cart
+    horse-and-cart    
+      
+/(?<=ab(?i)x|y|z)/
+
+/(?>.*)(?<=(abcd)|(xyz))/
+    alphabetabcd
+    endingxyz
+
+/(?<=ab(?i)x(?-i)y|(?i)z|b)ZZ/
+    abxyZZ
+    abXyZZ
+    ZZZ
+    zZZ
+    bZZ
+    BZZ     
+    *** Failers
+    ZZ 
+    abXYZZ 
+    zzz
+    bzz  
+
+/(?<!(foo)a)bar/
+    bar
+    foobbar 
+    *** Failers
+    fooabar  
+
+/This one is here because Perl 5.005_02 doesn't fail it/
+
+/^(a)?(?(1)a|b)+$/
+    *** Failers
+    a 
+
+/This one is here because I think Perl 5.005_02 gets the setting of $1 wrong/
+
+/^(a\1?){4}$/
+    aaaaaa
+    
+/These are syntax tests from Perl 5.005/
+
+/a[b-a]/
+
+/a[]b/
+
+/a[/
+
+/*a/
+
+/(*)b/
+
+/abc)/
+
+/(abc/
+
+/a**/
+
+/)(/
+
+/\1/
+
+/\2/
+
+/(a)|\2/
+
+/a[b-a]/i
+
+/a[]b/i
+
+/a[/i
+
+/*a/i
+
+/(*)b/i
+
+/abc)/i
+
+/(abc/i
+
+/a**/i
+
+/)(/i
+
+/:(?:/
+
+/(?<%)b/
+
+/a(?{)b/
+
+/a(?{{})b/
+
+/a(?{}})b/
+
+/a(?{"{"})b/
+
+/a(?{"{"}})b/
+
+/(?(1?)a|b)/
+
+/(?(1)a|b|c)/
+
+/[a[:xyz:/
+
+/(?<=x+)y/
+
+/a{37,17}/
+
+/abc/\
+
+/abc/\P
+
+/abc/\i
+
+/(a)bc(d)/
+    abcd
+    abcd\C2
+    abcd\C5
+     
+/(.{20})/
+    abcdefghijklmnopqrstuvwxyz
+    abcdefghijklmnopqrstuvwxyz\C1
+    abcdefghijklmnopqrstuvwxyz\G1
+     
+/(.{15})/
+    abcdefghijklmnopqrstuvwxyz
+    abcdefghijklmnopqrstuvwxyz\C1\G1
+
+/(.{16})/
+    abcdefghijklmnopqrstuvwxyz
+    abcdefghijklmnopqrstuvwxyz\C1\G1\L
+    
+/^(a|(bc))de(f)/
+    adef\G1\G2\G3\G4\L 
+    bcdef\G1\G2\G3\G4\L 
+    adefghijk\C0 
+    
+/^abc\00def/
+    abc\00def\L\C0 
+    
+/word ((?:[a-zA-Z0-9]+ )((?:[a-zA-Z0-9]+ )((?:[a-zA-Z0-9]+ )((?:[a-zA-Z0-9]+ 
+)((?:[a-zA-Z0-9]+ )((?:[a-zA-Z0-9]+ )((?:[a-zA-Z0-9]+ )((?:[a-zA-Z0-9]+ 
+)?)?)?)?)?)?)?)?)?otherword/M
+
+/.*X/D
+
+/.*X/Ds
+
+/(.*X|^B)/D
+
+/(.*X|^B)/Ds
+    
+/(?s)(.*X|^B)/D
+
+/(?s:.*X|^B)/D
+
+/\Biss\B/+
+    Mississippi
+
+/\Biss\B/+P
+    Mississippi
+
+/iss/G+
+    Mississippi
+
+/\Biss\B/G+
+    Mississippi
+
+/\Biss\B/g+
+    Mississippi
+    *** Failers
+    Mississippi\A
+
+/(?<=[Ms])iss/g+
+    Mississippi
+
+/(?<=[Ms])iss/G+
+    Mississippi
+
+/^iss/g+
+    ississippi
+    
+/.*iss/g+
+    abciss\nxyzisspqr 
+
+/.i./+g
+    Mississippi
+    Mississippi\A
+    Missouri river
+    Missouri river\A  
+
+/^.is/+g
+    Mississippi
+
+/^ab\n/g+
+    ab\nab\ncd
+
+/^ab\n/mg+
+    ab\nab\ncd
+
+/abc/
+
+/abc|bac/
+
+/(abc|bac)/
+
+/(abc|(c|dc))/
+
+/(abc|(d|de)c)/
+
+/a*/
+
+/a+/
+
+/(baa|a+)/
+
+/a{0,3}/
+
+/baa{3,}/
+
+/"([^\\"]+|\\.)*"/
+
+/(abc|ab[cd])/
+
+/(a|.)/
+
+/a|ba|\w/
+
+/abc(?=pqr)/
+
+/...(?<=abc)/
+
+/abc(?!pqr)/
+
+/ab./
+
+/ab[xyz]/
+
+/abc*/
+
+/ab.c*/
+
+/a.c*/
+
+/.c*/
+
+/ac*/
+
+/(a.c*|b.c*)/
+
+/a.c*|aba/
+
+/.+a/
+
+/(?=abcda)a.*/
+
+/(?=a)a.*/
+
+/a(b)*/
+
+/a\d*/
+
+/ab\d*/
+
+/a(\d)*/
+
+/abcde{0,0}/
+
+/ab\d+/
+
+/a(?(1)b)/
+
+/a(?(1)bag|big)/
+
+/a(?(1)bag|big)*/
+
+/a(?(1)bag|big)+/
+
+/a(?(1)b..|b..)/
+
+/ab\d{0}e/
+
+/a?b?/
+    a
+    b
+    ab
+    \
+    *** Failers
+    \N     
+    
+/|-/
+    abcd
+    -abc
+    \Nab-c
+    *** Failers
+    \Nabc     
+
+/a*(b+)(z)(z)/P
+    aaaabbbbzzzz
+    aaaabbbbzzzz\O0
+    aaaabbbbzzzz\O1
+    aaaabbbbzzzz\O2
+    aaaabbbbzzzz\O3
+    aaaabbbbzzzz\O4
+    aaaabbbbzzzz\O5
+    
+/^.?abcd/S 
+
+/\(             # ( at start
+  (?:           # Non-capturing bracket
+  (?>[^()]+)    # Either a sequence of non-brackets (no backtracking)
+  |             # Or
+  (?R)          # Recurse - i.e. nested bracketed string
+  )*            # Zero or more contents
+  \)            # Closing )
+  /x
+    (abcd)
+    (abcd)xyz
+    xyz(abcd)
+    (ab(xy)cd)pqr 
+    (ab(xycd)pqr 
+    () abc () 
+    12(abcde(fsh)xyz(foo(bar))lmno)89
+    *** Failers
+    abcd 
+    abcd)
+    (abcd  
+
+/\(  ( (?>[^()]+) | (?R) )* \) /xg
+    (ab(xy)cd)pqr 
+    1(abcd)(x(y)z)pqr
+
+/\(  (?: (?>[^()]+) | (?R) ) \) /x
+    (abcd)
+    (ab(xy)cd)
+    (a(b(c)d)e) 
+    ((ab)) 
+    *** Failers
+    ()   
+
+/\(  (?: (?>[^()]+) | (?R) )? \) /x
+    ()
+    12(abcde(fsh)xyz(foo(bar))lmno)89
+
+/\(  ( (?>[^()]+) | (?R) )* \) /x
+    (ab(xy)cd)
+
+/\( ( ( (?>[^()]+) | (?R) )* ) \) /x
+    (ab(xy)cd)
+
+/\( (123)? ( ( (?>[^()]+) | (?R) )* ) \) /x
+    (ab(xy)cd)
+    (123ab(xy)cd)
+
+/\( ( (123)? ( (?>[^()]+) | (?R) )* ) \) /x
+    (ab(xy)cd)
+    (123ab(xy)cd)
+
+/\( (((((((((( ( (?>[^()]+) | (?R) )* )))))))))) \) /x
+    (ab(xy)cd)
+
+/\( ( ( (?>[^()<>]+) | ((?>[^()]+)) | (?R) )* ) \) /x
+    (abcd(xyz<p>qrs)123)
+
+/\( ( ( (?>[^()]+) | ((?R)) )* ) \) /x
+    (ab(cd)ef)
+    (ab(cd(ef)gh)ij)
+
+/^[[:alnum:]]/D
+
+/^[[:^alnum:]]/D
+
+/^[[:alpha:]]/D
+
+/^[[:^alpha:]]/D
+             
+/^[[:ascii:]]/D
+
+/^[[:^ascii:]]/D
+
+/^[[:blank:]]/D
+
+/^[[:cntrl:]]/D
+
+/^[[:digit:]]/D
+
+/^[[:graph:]]/D
+
+/^[[:lower:]]/D
+
+/^[[:print:]]/D
+
+/^[[:punct:]]/D
+
+/^[[:space:]]/D
+
+/^[[:upper:]]/D
+
+/^[[:xdigit:]]/D
+
+/^[[:word:]]/D
+
+/^[[:^cntrl:]]/D
+
+/^[12[:^digit:]]/D
+
+/^[[:^blank:]]/D
+
+/[01[:alpha:]%]/D
+
+/[[.ch.]]/
+
+/[[=ch=]]/
+
+/[[:rhubarb:]]/
+
+/[[:upper:]]/i
+    A
+    a 
+    
+/[[:lower:]]/i
+    A
+    a 
+
+/((?-i)[[:lower:]])[[:lower:]]/i
+    ab
+    aB
+    *** Failers
+    Ab
+    AB        
+
+/[\200-\410]/
+
+/^(?(0)f|b)oo/
+
+/This one's here because of the large output vector needed/
+
+/(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\w+)\s+(\270)/
+    \O900 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 ABC ABC
+
+/This one's here because Perl does this differently and PCRE can't at present/
+
+/(main(O)?)+/
+    mainmain
+    mainOmain
+    
+/These are all cases where Perl does it differently (nested captures)/
+
+/^(a(b)?)+$/
+    aba
+   
+/^(aa(bb)?)+$/
+    aabbaa    
+    
+/^(aa|aa(bb))+$/
+    aabbaa 
+    
+/^(aa(bb)??)+$/
+    aabbaa    
+    
+/^(?:aa(bb)?)+$/
+    aabbaa    
+    
+/^(aa(b(b))?)+$/
+    aabbaa    
+
+/^(?:aa(b(b))?)+$/
+    aabbaa    
+
+/^(?:aa(b(?:b))?)+$/
+    aabbaa    
+
+/^(?:aa(bb(?:b))?)+$/
+    aabbbaa    
+    
+/^(?:aa(b(?:bb))?)+$/
+    aabbbaa    
+
+/^(?:aa(?:b(b))?)+$/
+    aabbaa    
+
+/^(?:aa(?:b(bb))?)+$/
+    aabbbaa    
+
+/^(aa(b(bb))?)+$/
+    aabbbaa    
+
+/^(aa(bb(bb))?)+$/
+    aabbbbaa    
+
+/--------------------------------------------------------------------/ 
+    
+/#/xMD
+
+/a#/xMD
+
+/[\s]/D
+
+/[\S]/D
+
+/a(?i)b/D
+    ab
+    aB
+    *** Failers 
+    AB  
+
+/(a(?i)b)/D
+    ab
+    aB
+    *** Failers 
+    AB  
+    
+/   (?i)abc/xD
+
+/#this is a comment
+  (?i)abc/xD
+
+/123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890/D
+
+/\Q123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890/D
+
+/\Q\E/D
+    \
+
+/\Q\Ex/D
+
+/ \Q\E/D
+
+/a\Q\E/D
+  abc
+  bca
+  bac  
+
+/a\Q\Eb/D
+  abc
+
+/\Q\Eabc/D
+
+/x*+\w/D
+    *** Failers
+    xxxxx
+    
+/x?+/D
+
+/x++/D
+
+/x{1,3}+/D 
+
+/(x)*+/D
+
+/^(\w++|\s++)*$/
+    now is the time for all good men to come to the aid of the party
+    *** Failers
+    this is not a line with only words and spaces!
+    
+/(\d++)(\w)/
+    12345a
+    *** Failers
+    12345+ 
+
+/a++b/
+    aaab
+
+/(a++b)/
+    aaab
+
+/(a++)b/
+    aaab
+
+/([^()]++|\([^()]*\))+/
+    ((abc(ade)ufh()()x
+    
+/\(([^()]++|\([^()]+\))+\)/ 
+    (abc)
+    (abc(def)xyz)
+    *** Failers
+    ((()aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa   
+
+/(abc){1,3}+/D
+
+/a+?+/
+
+/a{2,3}?+b/
+
+/(?U)a+?+/
+
+/a{2,3}?+b/U
+
+/x(?U)a++b/D
+    xaaaab
+
+/(?U)xa++b/D
+    xaaaab
+
+/^((a+)(?U)([ab]+)(?-U)([bc]+)(\w*))/D
+
+/^x(?U)a+b/D
+
+/^x(?U)(a+)b/D
+
+/[.x.]/
+
+/[=x=]/
+
+/[:x:]/
+
+/\l/
+
+/\L/
+
+/\N{name}/
+
+/\u/
+
+/\U/
+
+/[/
+
+/[a-/
+
+/[[:space:]/
+
+/[\s]/DM
+
+/[[:space:]]/DM
+
+/[[:space:]abcde]/DM
+
+/< (?: (?(R) \d++  | [^<>]*+) | (?R)) * >/x
+    <>
+    <abcd>
+    <abc <123> hij>
+    <abc <def> hij>
+    <abc<>def> 
+    <abc<>      
+    *** Failers
+    <abc
+
+|8J\$WE\<\.rX\+ix\[d1b\!H\#\?vV0vrK\:ZH1\=2M\>iV\;\?aPhFB\<\*vW\@QW\@sO9\}cfZA\-i\'w\%hKd6gt1UJP\,15_\#QY\$M\^Mss_U\/\]\&LK9\[5vQub\^w\[KDD\<EjmhUZ\?\.akp2dF\>qmj\;2\}YWFdYx\.Ap\]hjCPTP\(n28k\+3\;o\&WXqs\/gOXdr\$\:r\'do0\;b4c\(f_Gr\=\"\\4\)\[01T7ajQJvL\$W\~mL_sS\/4h\:x\*\[ZN\=KLs\&L5zX\/\/\>it\,o\:aU\(\;Z\>pW\&T7oP\'2K\^E\:x9\'c\[\%z\-\,64JQ5AeH_G\#KijUKghQw\^\\vea3a\?kka_G\$8\#\`\*kynsxzBLru\'\]k_\[7FrVx\}\^\=\$blx\>s\-N\%j\;D\*aZDnsw\:YKZ\%Q\.Kne9\#hP\?\+b3\(SOvL\,\^\;\&u5\@\?5C5Bhb\=m\-vEh_L15Jl\]U\)0RP6\{q\%L\^_z5E\'Dw6X\b|DM
+
+|\$\<\.X\+ix\[d1b\!H\#\?vV0vrK\:ZH1\=2M\>iV\;\?aPhFB\<\*vW\@QW\@sO9\}cfZA\-i\'w\%hKd6gt1UJP\,15_\#QY\$M\^Mss_U\/\]\&LK9\[5vQub\^w\[KDD\<EjmhUZ\?\.akp2dF\>qmj\;2\}YWFdYx\.Ap\]hjCPTP\(n28k\+3\;o\&WXqs\/gOXdr\$\:r\'do0\;b4c\(f_Gr\=\"\\4\)\[01T7ajQJvL\$W\~mL_sS\/4h\:x\*\[ZN\=KLs\&L5zX\/\/\>it\,o\:aU\(\;Z\>pW\&T7oP\'2K\^E\:x9\'c\[\%z\-\,64JQ5AeH_G\#KijUKghQw\^\\vea3a\?kka_G\$8\#\`\*kynsxzBLru\'\]k_\[7FrVx\}\^\=\$blx\>s\-N\%j\;D\*aZDnsw\:YKZ\%Q\.Kne9\#hP\?\+b3\(SOvL\,\^\;\&u5\@\?5C5Bhb\=m\-vEh_L15Jl\]U\)0RP6\{q\%L\^_z5E\'Dw6X\b|DM
+
+/(.*)\d+\1/I
+
+/(.*)\d+/I
+    
+/(.*)\d+\1/Is
+
+/(.*)\d+/Is
+
+/(.*(xyz))\d+\2/I
+
+/((.*))\d+\1/I
+    abc123bc
+    
+/a[b]/I
+
+/(?=a).*/I
+
+/(?=abc).xyz/iI
+
+/(?=abc)(?i).xyz/I
+
+/(?=a)(?=b)/I
+
+/(?=.)a/I
+
+/((?=abcda)a)/I
+
+/((?=abcda)ab)/I
+
+/()a/I
+
+/(?(1)ab|ac)/I
+
+/(?(1)abz|acz)/I
+
+/(?(1)abz)/I
+
+/(?(1)abz)123/I
+
+/(a)+/I
+
+/(a){2,3}/I
+
+/(a)*/I
+
+/[a]/I
+
+/[ab]/I
+
+/[ab]/IS
+
+/[^a]/I
+
+/\d456/I
+
+/\d456/IS
+
+/a^b/I
+
+/^a/mI
+  abcde
+  xy\nabc 
+  *** Failers 
+  xyabc 
+
+/c|abc/I
+
+/(?i)[ab]/IS
+
+/[ab](?i)cd/IS
+
+/abc(?C)def/
+    abcdef
+    1234abcdef 
+    *** Failers
+    abcxyz
+    abcxyzf   
+
+/abc(?C)de(?C1)f/
+    123abcdef
+    
+/(?C1)\dabc(?C2)def/ 
+    1234abcdef
+    *** Failers
+    abcdef 
+    
+/(?C255)ab/
+
+/(?C256)ab/
+
+/(?Cab)xx/ 
+
+/(?C12vr)x/
+
+/abc(?C)def/
+    *** Failers
+    \x83\x0\x61bcdef
+
+/(abc)(?C)de(?C1)f/
+    123abcdef
+    123abcdef\C+ 
+    123abcdef\C- 
+    *** Failers
+    123abcdef\C!1 
+    
+/(?C0)(abc(?C1))*/
+    abcabcabc
+    abcabc\C!1!3   
+    *** Failers
+    abcabcabc\C!1!3   
+
+/(\d{3}(?C))*/
+    123\C+
+    123456\C+
+    123456789\C+  
+
+/((xyz)(?C)p|(?C1)xyzabc)/
+    xyzabc\C+
+
+/(X)((xyz)(?C)p|(?C1)xyzabc)/
+    Xxyzabc\C+
+
+/(?=(abc))(?C)abcdef/
+    abcdef\C+
+    
+/(?!(abc)(?C1)d)(?C2)abcxyz/
+    abcxyz\C+ 
+
+/(?<=(abc)(?C))xyz/
+   abcxyz\C+
+   
+/(?C)abc/ 
+
+/(?C)^abc/
+
+/(?C)a|b/S
+
+/(?R)/
+
+/(a|(?R))/
+
+/(ab|(bc|(de|(?R))))/
+
+/x(ab|(bc|(de|(?R))))/
+    xab
+    xbc
+    xde
+    xxab
+    xxxab
+    *** Failers
+    xyab   
+
+/(ab|(bc|(de|(?1))))/
+
+/x(ab|(bc|(de|(?1)x)x)x)/
+
+/^([^()]|\((?1)*\))*$/
+    abc
+    a(b)c
+    a(b(c))d  
+    *** Failers)
+    a(b(c)d  
+
+/^>abc>([^()]|\((?1)*\))*<xyz<$/
+   >abc>123<xyz<
+   >abc>1(2)3<xyz<
+   >abc>(1(2)3)<xyz<
+
+/(a(?1)b)/D
+
+/(a(?1)+b)/D
+
+/^\W*(?:((.)\W*(?1)\W*\2|)|((.)\W*(?3)\W*\4|\W*.\W*))\W*$/i
+    1221
+    Satan, oscillate my metallic sonatas!
+    A man, a plan, a canal: Panama!
+    Able was I ere I saw Elba. 
+    *** Failers
+    The quick brown fox  
+    
+/^(\d+|\((?1)([+*-])(?1)\)|-(?1))$/
+    12
+    (((2+2)*-3)-7)
+    -12
+    *** Failers
+    ((2+2)*-3)-7)
+         
+/^(x(y|(?1){2})z)/
+    xyz
+    xxyzxyzz 
+    *** Failers
+    xxyzz
+    xxyzxyzxyzz   
+
+/((< (?: (?(R) \d++  | [^<>]*+) | (?2)) * >))/x
+    <>
+    <abcd>
+    <abc <123> hij>
+    <abc <def> hij>
+    <abc<>def> 
+    <abc<>      
+    *** Failers
+    <abc
+
+/(?1)/
+
+/((?2)(abc)/
+
+/^(abc)def(?1)/
+    abcdefabc
+
+/^(a|b|c)=(?1)+/
+    a=a
+    a=b
+    a=bc  
+
+/^(a|b|c)=((?1))+/
+    a=a
+    a=b
+    a=bc  
+
+/a(?P<name1>b|c)d(?P<longername2>e)/D
+    abde
+    acde 
+
+/(?:a(?P<c>c(?P<d>d)))(?P<a>a)/D
+
+/(?P<a>a)...(?P=a)bbb(?P>a)d/D
+
+/^\W*(?:(?P<one>(?P<two>.)\W*(?P>one)\W*(?P=two)|)|(?P<three>(?P<four>.)\W*(?P>three)\W*(?P=four)|\W*.\W*))\W*$/i
+    1221
+    Satan, oscillate my metallic sonatas!
+    A man, a plan, a canal: Panama!
+    Able was I ere I saw Elba. 
+    *** Failers
+    The quick brown fox  
+    
+/((?(R)a|b))\1(?1)?/
+  bb
+  bbaa 
+
+/(.*)a/sI
+
+/(.*)a\1/sI
+
+/(.*)a(b)\2/sI
+
+/((.*)a|(.*)b)z/sI
+
+/((.*)a|(.*)b)z\1/sI
+
+/((.*)a|(.*)b)z\2/sI
+
+/((.*)a|(.*)b)z\3/sI
+
+/((.*)a|^(.*)b)z\3/sI
+
+/(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)a/sI
+
+/(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)a\31/sI
+
+/(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)a\32/sI
+
+/(a)(bc)/ND
+  abc
+
+/(?P<one>a)(bc)/ND
+  abc
+
+/(a)(?P<named>bc)/ND
+
+/(a+)*zz/
+  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaazzbbbbbb\M
+  aaaaaaaaaaaaaz\M
+
+/(aaa(?C1)bbb|ab)/
+   aaabbb
+   aaabbb\C*0
+   aaabbb\C*1
+   aaabbb\C*-1
+
+/ab(?P<one>cd)ef(?P<two>gh)/
+    abcdefgh
+    abcdefgh\C1\Gtwo
+    abcdefgh\Cone\Ctwo
+    abcdefgh\Cthree  
+
+/(?P<Tes>)(?P<Test>)/D
+
+/(?P<Test>)(?P<Tes>)/D
+
+/(?P<Z>zz)(?P<A>aa)/
+    zzaa\CZ
+    zzaa\CA
+
+/(?P<x>eks)(?P<x>eccs)/
+
+/(?P<abc>abc(?P<def>def)(?P<abc>xyz))/
+
+"\[((?P<elem>\d+)(,(?P>elem))*)\]"
+    [10,20,30,5,5,4,4,2,43,23,4234]
+    *** Failers
+    []  
+
+"\[((?P<elem>\d+)(,(?P>elem))*)?\]"
+    [10,20,30,5,5,4,4,2,43,23,4234]
+    [] 
+
+/(a(b(?2)c))?/D
+
+/(a(b(?2)c))*/D
+
+/(a(b(?2)c)){0,2}/D
+
+/[ab]{1}+/D
+
+/((w\/|-|with)*(free|immediate)*.*?shipping\s*[!.-]*)/i
+     Baby Bjorn Active Carrier - With free SHIPPING!!
+
+/((w\/|-|with)*(free|immediate)*.*?shipping\s*[!.-]*)/iS
+     Baby Bjorn Active Carrier - With free SHIPPING!!
+     
+/a*.*b/SD
+
+/(a|b)*.?c/SD 
+
+/abc(?C255)de(?C)f/D
+
+/abcde/CD
+  abcde
+  abcdfe 
+  
+/a*b/CD
+  ab
+  aaaab
+  aaaacb   
+
+/a+b/CD
+  ab
+  aaaab
+  aaaacb   
+
+/(abc|def)x/CD
+  abcx
+  defx
+  abcdefzx
+
+/(ab|cd){3,4}/C
+  ababab
+  abcdabcd
+  abcdcdcdcdcd  
+
+/([ab]{,4}c|xy)/CD
+    Note: that { does NOT introduce a quantifier
+
+/([ab]{1,4}c|xy){4,5}?123/CD
+    aacaacaacaacaac123
+
+/\b.*/I
+  ab cd\>1
+  
+/\b.*/Is 
+  ab cd\>1
+  
+/(?!.bcd).*/I
+  Xbcd12345 
+
+/abcde/
+    ab\P
+    abc\P
+    abcd\P
+    abcde\P   
+    the quick brown abc\P
+    ** Failers\P
+    the quick brown abxyz fox\P
+    
+"^(0?[1-9]|[12][0-9]|3[01])/(0?[1-9]|1[012])/(20)?\d\d$"
+    13/05/04\P
+    13/5/2004\P
+    02/05/09\P 
+    1\P
+    1/2\P
+    1/2/0\P
+    1/2/04\P    
+    0\P
+    02/\P
+    02/0\P   
+    02/1\P
+    ** Failers\P
+    \P
+    123\P
+    33/4/04\P
+    3/13/04\P
+    0/1/2003\P
+    0/\P 
+    02/0/\P 
+    02/13\P  
+
+/0{0,2}ABC/I
+    
+/\d{3,}ABC/I
+    
+/\d*ABC/I
+
+/[abc]+DE/I
+
+/[abc]?123/
+    123\P
+    a\P
+    b\P
+    c\P
+    c12\P
+    c123\P      
+
+/^(?:\d){3,5}X/
+    1\P
+    123\P
+    123X
+    1234\P
+    1234X
+    12345\P
+    12345X      
+    *** Failers 
+    1X 
+    123456\P 
+
+/abc/>testsavedregex
+<testsavedregex
+    abc
+    ** Failers
+    bca
+    
+/abc/F>testsavedregex
+<testsavedregex
+    abc
+    ** Failers
+    bca
+
+/(a|b)/S>testsavedregex
+<testsavedregex
+    abc
+    ** Failers
+    def  
+    
+/(a|b)/SF>testsavedregex
+<testsavedregex
+    abc
+    ** Failers
+    def  
+    
+~<(\w+)/?>(.)*</(\1)>~smg
+    <!DOCTYPE seite SYSTEM "http://www.lco.lineas.de/xmlCms.dtd">\n<seite>\n<dokumenteninformation>\n<seitentitel>Partner der LCO</seitentitel>\n<sprache>de</sprache>\n<seitenbeschreibung>Partner der LINEAS Consulting\nGmbH</seitenbeschreibung>\n<schluesselworte>LINEAS Consulting GmbH Hamburg\nPartnerfirmen</schluesselworte>\n<revisit>30 days</revisit>\n<robots>index,follow</robots>\n<menueinformation>\n<aktiv>ja</aktiv>\n<menueposition>3</menueposition>\n<menuetext>Partner</menuetext>\n</menueinformation>\n<lastedited>\n<autor>LCO</autor>\n<firma>LINEAS Consulting</firma>\n<datum>15.10.2003</datum>\n</lastedited>\n</dokumenteninformation>\n<inhalt>\n\n<absatzueberschrift>Die Partnerfirmen der LINEAS Consulting\nGmbH</absatzueberschrift>\n\n<absatz><link ziel="http://www.ca.com/" zielfenster="_blank">\n<bild name="logo_ca.gif" rahmen="no"/></link> <link\nziel="http://www.ey.com/" zielfenster="_blank"><bild\nname="logo_euy.gif" rahmen="no"/></link>\n</absatz>\n\n<absatz><link ziel="http://www.cisco.de/" zielfenster="_blank">\n<bild name="logo_cisco.gif" rahmen="ja"/></link></absatz>\n\n<absatz><link ziel="http://www.atelion.de/"\nzielfenster="_blank"><bild\nname="logo_atelion.gif" rahmen="no"/></link>\n</absatz>\n\n<absatz><link ziel="http://www.line-information.de/"\nzielfenster="_blank">\n<bild name="logo_line_information.gif" rahmen="no"/></link>\n</absatz>\n\n<absatz><bild name="logo_aw.gif" rahmen="no"/></absatz>\n\n<absatz><link ziel="http://www.incognis.de/"\nzielfenster="_blank"><bild\nname="logo_incognis.gif" rahmen="no"/></link></absatz>\n\n<absatz><link ziel="http://www.addcraft.com/"\nzielfenster="_blank"><bild\nname="logo_addcraft.gif" rahmen="no"/></link></absatz>\n\n<absatz><link ziel="http://www.comendo.com/"\nzielfenster="_blank"><bild\nname="logo_comendo.gif" rahmen="no"/></link></absatz>\n\n</inhalt>\n</seite>
+
+/^a/IF
+
+/ End of testinput2 /

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/testdata/testinput3
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/testdata/testinput3	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/testdata/testinput3	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,65 @@
+/^[\w]+/
+    *** Failers
+    École
+
+/^[\w]+/Lfr_FR
+    École
+
+/^[\w]+/
+    *** Failers
+    École
+
+/^[\W]+/
+    École
+
+/^[\W]+/Lfr_FR
+    *** Failers
+    École
+
+/[\b]/
+    \b
+    *** Failers
+    a
+
+/[\b]/Lfr_FR
+    \b
+    *** Failers
+    a
+
+/^\w+/
+    *** Failers
+    École
+
+/^\w+/Lfr_FR
+    École
+
+/(.+)\b(.+)/
+    École
+
+/(.+)\b(.+)/Lfr_FR
+    *** Failers
+    École
+
+/École/i
+    École
+    *** Failers
+    école
+
+/École/iLfr_FR
+    École
+    école
+
+/\w/IS
+
+/\w/ISLfr_FR
+
+/^[\xc8-\xc9]/iLfr_FR
+    École
+    école
+
+/^[\xc8-\xc9]/Lfr_FR
+    École
+    *** Failers 
+    école
+
+/ End of testinput3 /

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/testdata/testinput4
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/testdata/testinput4	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/testdata/testinput4	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,513 @@
+/-- Do not use the \x{} construct except with patterns that have the --/
+/-- /8 option set, because PCRE doesn't recognize them as UTF-8 unless --/
+/-- that option is set. However, the latest Perls recognize them always. --/
+
+/a.b/8
+    acb
+    a\x7fb
+    a\x{100}b 
+    *** Failers
+    a\nb  
+
+/a(.{3})b/8
+    a\x{4000}xyb 
+    a\x{4000}\x7fyb 
+    a\x{4000}\x{100}yb 
+    *** Failers
+    a\x{4000}b 
+    ac\ncb 
+
+/a(.*?)(.)/
+    a\xc0\x88b
+
+/a(.*?)(.)/8
+    a\x{100}b
+
+/a(.*)(.)/
+    a\xc0\x88b
+
+/a(.*)(.)/8
+    a\x{100}b
+
+/a(.)(.)/
+    a\xc0\x92bcd
+
+/a(.)(.)/8
+    a\x{240}bcd
+
+/a(.?)(.)/
+    a\xc0\x92bcd
+
+/a(.?)(.)/8
+    a\x{240}bcd
+
+/a(.??)(.)/
+    a\xc0\x92bcd
+
+/a(.??)(.)/8
+    a\x{240}bcd
+
+/a(.{3})b/8
+    a\x{1234}xyb 
+    a\x{1234}\x{4321}yb 
+    a\x{1234}\x{4321}\x{3412}b 
+    *** Failers
+    a\x{1234}b 
+    ac\ncb 
+
+/a(.{3,})b/8
+    a\x{1234}xyb 
+    a\x{1234}\x{4321}yb 
+    a\x{1234}\x{4321}\x{3412}b 
+    axxxxbcdefghijb 
+    a\x{1234}\x{4321}\x{3412}\x{3421}b 
+    *** Failers
+    a\x{1234}b 
+
+/a(.{3,}?)b/8
+    a\x{1234}xyb 
+    a\x{1234}\x{4321}yb 
+    a\x{1234}\x{4321}\x{3412}b 
+    axxxxbcdefghijb 
+    a\x{1234}\x{4321}\x{3412}\x{3421}b 
+    *** Failers
+    a\x{1234}b 
+
+/a(.{3,5})b/8
+    a\x{1234}xyb 
+    a\x{1234}\x{4321}yb 
+    a\x{1234}\x{4321}\x{3412}b 
+    axxxxbcdefghijb 
+    a\x{1234}\x{4321}\x{3412}\x{3421}b 
+    axbxxbcdefghijb 
+    axxxxxbcdefghijb 
+    *** Failers
+    a\x{1234}b 
+    axxxxxxbcdefghijb 
+
+/a(.{3,5}?)b/8
+    a\x{1234}xyb 
+    a\x{1234}\x{4321}yb 
+    a\x{1234}\x{4321}\x{3412}b 
+    axxxxbcdefghijb 
+    a\x{1234}\x{4321}\x{3412}\x{3421}b 
+    axbxxbcdefghijb 
+    axxxxxbcdefghijb 
+    *** Failers
+    a\x{1234}b 
+    axxxxxxbcdefghijb 
+
+/^[a\x{c0}]/8
+    *** Failers
+    \x{100}
+
+/(?<=aXb)cd/8
+    aXbcd
+
+/(?<=a\x{100}b)cd/8
+    a\x{100}bcd
+
+/(?<=a\x{100000}b)cd/8
+    a\x{100000}bcd
+    
+/(?:\x{100}){3}b/8
+    \x{100}\x{100}\x{100}b
+    *** Failers 
+    \x{100}\x{100}b
+
+/\x{ab}/8
+    \x{ab} 
+    \xc2\xab
+    *** Failers 
+    \x00{ab}
+
+/(?<=(.))X/8
+    WXYZ
+    \x{256}XYZ 
+    *** Failers
+    XYZ 
+
+/X(\C{3})/8
+    X\x{1234}
+
+/X(\C{4})/8
+    X\x{1234}YZ
+    
+/X\C*/8
+    XYZabcdce
+    
+/X\C*?/8
+    XYZabcde
+    
+/X\C{3,5}/8
+    Xabcdefg   
+    X\x{1234} 
+    X\x{1234}YZ
+    X\x{1234}\x{512}  
+    X\x{1234}\x{512}YZ
+
+/X\C{3,5}?/8
+    Xabcdefg   
+    X\x{1234} 
+    X\x{1234}YZ
+    X\x{1234}\x{512}  
+
+/[^a]+/8g
+    bcd
+    \x{100}aY\x{256}Z 
+    
+/^[^a]{2}/8
+    \x{100}bc
+ 
+/^[^a]{2,}/8
+    \x{100}bcAa
+
+/^[^a]{2,}?/8
+    \x{100}bca
+
+/[^a]+/8ig
+    bcd
+    \x{100}aY\x{256}Z 
+    
+/^[^a]{2}/8i
+    \x{100}bc
+ 
+/^[^a]{2,}/8i
+    \x{100}bcAa
+
+/^[^a]{2,}?/8i
+    \x{100}bca
+
+/\x{100}{0,0}/8
+    abcd
+ 
+/\x{100}?/8
+    abcd
+    \x{100}\x{100} 
+
+/\x{100}{0,3}/8 
+    \x{100}\x{100} 
+    \x{100}\x{100}\x{100}\x{100} 
+    
+/\x{100}*/8
+    abce
+    \x{100}\x{100}\x{100}\x{100} 
+
+/\x{100}{1,1}/8
+    abcd\x{100}\x{100}\x{100}\x{100} 
+
+/\x{100}{1,3}/8
+    abcd\x{100}\x{100}\x{100}\x{100} 
+
+/\x{100}+/8
+    abcd\x{100}\x{100}\x{100}\x{100} 
+
+/\x{100}{3}/8
+    abcd\x{100}\x{100}\x{100}XX
+
+/\x{100}{3,5}/8
+    abcd\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}XX
+
+/\x{100}{3,}/8
+    abcd\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}XX
+
+/(?<=a\x{100}{2}b)X/8+
+    Xyyya\x{100}\x{100}bXzzz
+
+/\D*/8
+  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+
+/\D*/8
+  \x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}
+
+/\D/8
+    1X2
+    1\x{100}2 
+  
+/>\S/8
+    > >X Y
+    > >\x{100} Y
+  
+/\d/8
+    \x{100}3
+    
+/\s/8
+    \x{100} X
+    
+/\D+/8
+    12abcd34
+    *** Failers
+    1234  
+
+/\D{2,3}/8
+    12abcd34
+    12ab34
+    *** Failers  
+    1234
+    12a34  
+
+/\D{2,3}?/8
+    12abcd34
+    12ab34
+    *** Failers  
+    1234
+    12a34  
+
+/\d+/8
+    12abcd34
+    *** Failers
+
+/\d{2,3}/8
+    12abcd34
+    1234abcd
+    *** Failers  
+    1.4 
+
+/\d{2,3}?/8
+    12abcd34
+    1234abcd
+    *** Failers  
+    1.4 
+
+/\S+/8
+    12abcd34
+    *** Failers
+    \    \ 
+
+/\S{2,3}/8
+    12abcd34
+    1234abcd
+    *** Failers
+    \     \  
+
+/\S{2,3}?/8
+    12abcd34
+    1234abcd
+    *** Failers
+    \     \  
+
+/>\s+</8+
+    12>      <34
+    *** Failers
+
+/>\s{2,3}</8+
+    ab>  <cd
+    ab>   <ce
+    *** Failers
+    ab>    <cd 
+
+/>\s{2,3}?</8+
+    ab>  <cd
+    ab>   <ce
+    *** Failers
+    ab>    <cd 
+
+/\w+/8
+    12      34
+    *** Failers
+    +++=*! 
+
+/\w{2,3}/8
+    ab  cd
+    abcd ce
+    *** Failers
+    a.b.c
+
+/\w{2,3}?/8
+    ab  cd
+    abcd ce
+    *** Failers
+    a.b.c
+
+/\W+/8
+    12====34
+    *** Failers
+    abcd 
+
+/\W{2,3}/8
+    ab====cd
+    ab==cd
+    *** Failers
+    a.b.c
+
+/\W{2,3}?/8
+    ab====cd
+    ab==cd
+    *** Failers
+    a.b.c
+
+/[\x{100}]/8
+    \x{100}
+    Z\x{100}
+    \x{100}Z
+    *** Failers 
+
+/[Z\x{100}]/8
+    Z\x{100}
+    \x{100}
+    \x{100}Z
+    *** Failers 
+
+/[\x{100}\x{200}]/8
+   ab\x{100}cd
+   ab\x{200}cd
+   *** Failers  
+
+/[\x{100}-\x{200}]/8
+   ab\x{100}cd
+   ab\x{200}cd
+   ab\x{111}cd 
+   *** Failers  
+
+/[z-\x{200}]/8
+   ab\x{100}cd
+   ab\x{200}cd
+   ab\x{111}cd 
+   abzcd
+   ab|cd  
+   *** Failers  
+
+/[Q\x{100}\x{200}]/8
+   ab\x{100}cd
+   ab\x{200}cd
+   Q? 
+   *** Failers  
+
+/[Q\x{100}-\x{200}]/8
+   ab\x{100}cd
+   ab\x{200}cd
+   ab\x{111}cd 
+   Q? 
+   *** Failers  
+
+/[Qz-\x{200}]/8
+   ab\x{100}cd
+   ab\x{200}cd
+   ab\x{111}cd 
+   abzcd
+   ab|cd  
+   Q? 
+   *** Failers  
+
+/[\x{100}\x{200}]{1,3}/8
+   ab\x{100}cd
+   ab\x{200}cd
+   ab\x{200}\x{100}\x{200}\x{100}cd
+   *** Failers  
+
+/[\x{100}\x{200}]{1,3}?/8
+   ab\x{100}cd
+   ab\x{200}cd
+   ab\x{200}\x{100}\x{200}\x{100}cd
+   *** Failers  
+
+/[Q\x{100}\x{200}]{1,3}/8
+   ab\x{100}cd
+   ab\x{200}cd
+   ab\x{200}\x{100}\x{200}\x{100}cd
+   *** Failers  
+
+/[Q\x{100}\x{200}]{1,3}?/8
+   ab\x{100}cd
+   ab\x{200}cd
+   ab\x{200}\x{100}\x{200}\x{100}cd
+   *** Failers  
+
+/(?<=[\x{100}\x{200}])X/8
+    abc\x{200}X
+    abc\x{100}X 
+    *** Failers
+    X  
+
+/(?<=[Q\x{100}\x{200}])X/8
+    abc\x{200}X
+    abc\x{100}X 
+    abQX 
+    *** Failers
+    X  
+
+/(?<=[\x{100}\x{200}]{3})X/8
+    abc\x{100}\x{200}\x{100}X
+    *** Failers
+    abc\x{200}X
+    X  
+
+/[^\x{100}\x{200}]X/8
+    AX
+    \x{150}X
+    \x{500}X 
+    *** Failers
+    \x{100}X
+    \x{200}X   
+
+/[^Q\x{100}\x{200}]X/8
+    AX
+    \x{150}X
+    \x{500}X 
+    *** Failers
+    \x{100}X
+    \x{200}X   
+    QX 
+
+/[^\x{100}-\x{200}]X/8
+    AX
+    \x{500}X 
+    *** Failers
+    \x{100}X
+    \x{150}X
+    \x{200}X   
+
+/a\Cb/
+    aXb
+    a\nb
+  
+/a\Cb/8
+    aXb
+    a\nb
+    *** Failers 
+    a\x{100}b 
+
+/[z-\x{100}]/8i
+    z
+    Z 
+    \x{100}
+    *** Failers
+    \x{102}
+    y    
+
+/[\xFF]/
+    >\xff<
+
+/[\xff]/8
+    >\x{ff}<
+
+/[^\xFF]/
+    XYZ
+
+/[^\xff]/8
+    XYZ
+    \x{123} 
+
+/^[ac]*b/8
+  xb
+
+/^[ac\x{100}]*b/8
+  xb
+
+/^[^x]*b/8i
+  xb
+
+/^[^x]*b/8
+  xb
+  
+/^\d*b/8
+  xb 
+
+/(|a)/g8
+    catac
+    a\x{256}a 
+
+/^\x{85}$/8i
+    \x{85}
+
+/ End of testinput4 /

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/testdata/testinput5
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/testdata/testinput5	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/testdata/testinput5	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,263 @@
+/\x{100}/8DM
+
+/\x{1000}/8DM
+
+/\x{10000}/8DM
+
+/\x{100000}/8DM
+
+/\x{1000000}/8DM
+
+/\x{4000000}/8DM
+
+/\x{7fffFFFF}/8DM
+
+/[\x{ff}]/8DM
+
+/[\x{100}]/8DM
+
+/\x{ffffffff}/8
+
+/\x{100000000}/8
+
+/^\x{100}a\x{1234}/8
+    \x{100}a\x{1234}bcd
+
+/\x80/8D
+
+/\xff/8D
+
+/\x{0041}\x{2262}\x{0391}\x{002e}/D8
+    \x{0041}\x{2262}\x{0391}\x{002e}
+    
+/\x{D55c}\x{ad6d}\x{C5B4}/D8 
+    \x{D55c}\x{ad6d}\x{C5B4} 
+
+/\x{65e5}\x{672c}\x{8a9e}/D8
+    \x{65e5}\x{672c}\x{8a9e}
+
+/\x{80}/D8
+
+/\x{084}/D8
+
+/\x{104}/D8
+
+/\x{861}/D8
+
+/\x{212ab}/D8
+
+/.{3,5}X/D8
+    \x{212ab}\x{212ab}\x{212ab}\x{861}X
+
+
+/.{3,5}?/D8
+    \x{212ab}\x{212ab}\x{212ab}\x{861}
+
+/-- These tests are here rather than in testinput4 because Perl 5.6 has --/
+/-- some problems with UTF-8 support, in the area of \x{..} where the   --/
+/-- value is < 255. It grumbles about invalid UTF-8 strings.            --/
+
+/^[a\x{c0}]b/8
+    \x{c0}b
+    
+/^([a\x{c0}]*?)aa/8
+    a\x{c0}aaaa/ 
+
+/^([a\x{c0}]*?)aa/8
+    a\x{c0}aaaa/ 
+    a\x{c0}a\x{c0}aaa/ 
+
+/^([a\x{c0}]*)aa/8
+    a\x{c0}aaaa/ 
+    a\x{c0}a\x{c0}aaa/ 
+
+/^([a\x{c0}]*)a\x{c0}/8
+    a\x{c0}aaaa/ 
+    a\x{c0}a\x{c0}aaa/ 
+    
+/-- --/ 
+    
+/(?<=\C)X/8
+    Should produce an error diagnostic
+    
+/-- This one is here not because it's different to Perl, but because the --/
+/-- way the captured single-byte is displayed. (In Perl it becomes a --/
+/-- character, and you can't tell the difference.) --/
+    
+/X(\C)(.*)/8
+    X\x{1234}
+    X\nabc 
+    
+/^[ab]/8D
+    bar
+    *** Failers
+    c
+    \x{ff}
+    \x{100}  
+
+/^[^ab]/8D
+    c
+    \x{ff}
+    \x{100}  
+    *** Failers 
+    aaa
+  
+/[^ab\xC0-\xF0]/8SD
+    \x{f1}
+    \x{bf}
+    \x{100}
+    \x{1000}   
+    *** Failers
+    \x{c0} 
+    \x{f0} 
+
+/Ä€{3,4}/8SD
+  \x{100}\x{100}\x{100}\x{100\x{100}
+
+/(\x{100}+|x)/8SD
+
+/(\x{100}*a|x)/8SD
+
+/(\x{100}{0,2}a|x)/8SD
+
+/(\x{100}{1,2}a|x)/8SD
+
+/\x{100}*(\d+|"(?1)")/8
+    1234
+    "1234" 
+    \x{100}1234
+    "\x{100}1234"  
+    \x{100}\x{100}12ab 
+    \x{100}\x{100}"12" 
+    *** Failers 
+    \x{100}\x{100}abcd
+
+/\x{100}/8D
+
+/\x{100}*/8D
+
+/a\x{100}*/8D
+
+/ab\x{100}*/8D
+
+/a\x{100}\x{101}*/8D
+
+/a\x{100}\x{101}+/8D
+
+/\x{100}*A/8D
+    A
+
+/\x{100}*\d(?R)/8D
+
+/[^\x{c4}]/D
+
+/[^\x{c4}]/8D
+
+/[\x{100}]/8DM
+    \x{100}
+    Z\x{100}
+    \x{100}Z
+    *** Failers 
+
+/[Z\x{100}]/8DM
+    Z\x{100}
+    \x{100}
+    \x{100}Z
+    *** Failers 
+
+/[\x{200}-\x{100}]/8
+
+/[Ä€-Ä„]/8
+    \x{100}
+    \x{104}
+    *** Failers
+    \x{105}
+    \x{ff}    
+
+/[z-\x{100}]/8D
+
+/[z\Qa-d]Ä€\E]/8D
+    \x{100}
+    Ā 
+
+/[\xFF]/D
+    >\xff<
+
+/[\xff]/D8
+    >\x{ff}<
+
+/[^\xFF]/D
+
+/[^\xff]/8D
+
+/[Ä-Ü]/8
+    Ö # Matches without Study
+    \x{d6}
+    
+/[Ä-Ü]/8S
+    Ö <-- Same with Study
+    \x{d6}
+    
+/[\x{c4}-\x{dc}]/8 
+    Ö # Matches without Study
+    \x{d6} 
+
+/[\x{c4}-\x{dc}]/8S
+    Ö <-- Same with Study
+    \x{d6} 
+
+/[Ã]/8
+
+/Ã/8
+
+/ÃÃÃxxx/8
+
+/ÃÃÃxxx/8?D
+
+/abc/8
+    Ã]
+    Ã
+    ÃÃÃ
+    ÃÃÃ\?
+
+/anything/8
+    \xc0\x80
+    \xc1\x8f 
+    \xe0\x9f\x80
+    \xf0\x8f\x80\x80 
+    \xf8\x87\x80\x80\x80  
+    \xfc\x83\x80\x80\x80\x80
+    \xfe\x80\x80\x80\x80\x80  
+    \xff\x80\x80\x80\x80\x80  
+    \xc3\x8f
+    \xe0\xaf\x80
+    \xe1\x80\x80
+    \xf0\x9f\x80\x80 
+    \xf1\x8f\x80\x80 
+    \xf8\x88\x80\x80\x80  
+    \xf9\x87\x80\x80\x80  
+    \xfc\x84\x80\x80\x80\x80
+    \xfd\x83\x80\x80\x80\x80
+
+/\x{100}abc(xyz(?1))/8D
+
+/[^\x{100}]abc(xyz(?1))/8D
+
+/[ab\x{100}]abc(xyz(?1))/8D
+
+/(\x{100}(b(?2)c))?/D8
+
+/(\x{100}(b(?2)c)){0,2}/D8
+
+/(\x{100}(b(?1)c))?/D8
+
+/(\x{100}(b(?1)c)){0,2}/D8
+
+/\W/8
+    A.B
+    A\x{100}B 
+  
+/\w/8
+    \x{100}X   
+
+/ End of testinput5 /

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/testdata/testinput6
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/testdata/testinput6	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/testdata/testinput6	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,517 @@
+/^\pC\pL\pM\pN\pP\pS\pZ</8
+    \x7f\x{c0}\x{30f}\x{660}\x{66c}\x{f01}\x{1680}<
+    \np\x{300}9!\$ < 
+    ** Failers 
+    ap\x{300}9!\$ < 
+  
+/^\PC/8
+    X
+    ** Failers 
+    \x7f
+  
+/^\PL/8
+    9
+    ** Failers 
+    \x{c0}
+  
+/^\PM/8
+    X
+    ** Failers 
+    \x{30f}
+  
+/^\PN/8
+    X
+    ** Failers 
+    \x{660}
+  
+/^\PP/8
+    X
+    ** Failers 
+    \x{66c}
+  
+/^\PS/8
+    X
+    ** Failers 
+    \x{f01}
+  
+/^\PZ/8
+    X
+    ** Failers 
+    \x{1680}
+    
+/^\p{Cc}/8
+    \x{017}
+    \x{09f} 
+    ** Failers
+    \x{0600} 
+  
+/^\p{Cf}/8
+    \x{601}
+    ** Failers
+    \x{09f} 
+  
+/^\p{Cn}/8
+    ** Failers
+    \x{09f} 
+  
+/^\p{Co}/8
+    \x{f8ff}
+    ** Failers
+    \x{09f} 
+  
+/^\p{Cs}/8
+    \x{dfff}
+    ** Failers
+    \x{09f} 
+  
+/^\p{Ll}/8
+    a
+    ** Failers 
+    Z
+    \x{dfff}  
+  
+/^\p{Lm}/8
+    \x{2b0}
+    ** Failers
+    a 
+  
+/^\p{Lo}/8
+    \x{1bb}
+    ** Failers
+    a 
+    \x{2b0}
+  
+/^\p{Lt}/8
+    \x{1c5}
+    ** Failers
+    a 
+    \x{2b0}
+  
+/^\p{Lu}/8
+    A
+    ** Failers
+    \x{2b0}
+  
+/^\p{Mc}/8
+    \x{903}
+    ** Failers
+    X
+    \x{300}
+       
+/^\p{Me}/8
+    \x{488}
+    ** Failers
+    X
+    \x{903}
+    \x{300}
+  
+/^\p{Mn}/8
+    \x{300}
+    ** Failers
+    X
+    \x{903}
+  
+/^\p{Nd}+/8
+    0123456789\x{660}\x{661}\x{662}\x{663}\x{664}\x{665}\x{666}\x{667}\x{668}\x{669}\x{66a}
+    \x{6f0}\x{6f1}\x{6f2}\x{6f3}\x{6f4}\x{6f5}\x{6f6}\x{6f7}\x{6f8}\x{6f9}\x{6fa}
+    \x{966}\x{967}\x{968}\x{969}\x{96a}\x{96b}\x{96c}\x{96d}\x{96e}\x{96f}\x{970}
+    ** Failers
+    X
+  
+/^\p{Nl}/8
+    \x{16ee}
+    ** Failers
+    X
+    \x{966}
+  
+/^\p{No}/8
+    \x{b2}
+    \x{b3}
+    ** Failers
+    X
+    \x{16ee}
+  
+/^\p{Pc}/8
+    \x5f
+    \x{203f}
+    ** Failers
+    X
+    -
+    \x{58a}
+  
+/^\p{Pd}/8
+    -
+    \x{58a}
+    ** Failers
+    X
+    \x{203f}
+  
+/^\p{Pe}/8
+    )
+    ]
+    }
+    \x{f3b}
+    ** Failers
+    X
+    \x{203f}
+    (
+    [
+    {
+    \x{f3c}
+  
+/^\p{Pf}/8
+    \x{bb}
+    \x{2019}
+    ** Failers
+    X
+    \x{203f}
+  
+/^\p{Pi}/8
+    \x{ab}
+    \x{2018}
+    ** Failers
+    X
+    \x{203f}
+  
+/^\p{Po}/8
+    !
+    \x{37e}
+    ** Failers
+    X
+    \x{203f}
+  
+/^\p{Ps}/8
+    (
+    [
+    {
+    \x{f3c}
+    ** Failers
+    X
+    )
+    ]
+    }
+    \x{f3b}
+  
+/^\p{Sc}+/8
+    $\x{a2}\x{a3}\x{a4}\x{a5}\x{a6}
+    \x{9f2}
+    ** Failers
+    X
+    \x{2c2}
+  
+/^\p{Sk}/8
+    \x{2c2}
+    ** Failers
+    X
+    \x{9f2}
+  
+/^\p{Sm}+/8
+    +<|~\x{ac}\x{2044}
+    ** Failers
+    X
+    \x{9f2}
+  
+/^\p{So}/8
+    \x{a6}
+    \x{482} 
+    ** Failers
+    X
+    \x{9f2}
+  
+/^\p{Zl}/8
+    \x{2028}
+    ** Failers
+    X
+    \x{2029}
+  
+/^\p{Zp}/8
+    \x{2029}
+    ** Failers
+    X
+    \x{2028}
+  
+/^\p{Zs}/8
+    \ \
+    \x{a0}
+    \x{1680}
+    \x{180e}
+    \x{2000}
+    \x{2001}     
+    ** Failers
+    \x{2028}
+    \x{200d} 
+  
+/\p{Nd}+(..)/8
+      \x{660}\x{661}\x{662}ABC
+  
+/\p{Nd}+?(..)/8
+      \x{660}\x{661}\x{662}ABC
+  
+/\p{Nd}{2,}(..)/8
+      \x{660}\x{661}\x{662}ABC
+  
+/\p{Nd}{2,}?(..)/8
+      \x{660}\x{661}\x{662}ABC
+  
+/\p{Nd}*(..)/8
+      \x{660}\x{661}\x{662}ABC
+  
+/\p{Nd}*?(..)/8
+      \x{660}\x{661}\x{662}ABC
+  
+/\p{Nd}{2}(..)/8
+      \x{660}\x{661}\x{662}ABC
+  
+/\p{Nd}{2,3}(..)/8
+      \x{660}\x{661}\x{662}ABC
+  
+/\p{Nd}{2,3}?(..)/8
+      \x{660}\x{661}\x{662}ABC
+  
+/\p{Nd}?(..)/8
+      \x{660}\x{661}\x{662}ABC
+  
+/\p{Nd}??(..)/8
+      \x{660}\x{661}\x{662}ABC
+  
+/\p{Nd}*+(..)/8
+      \x{660}\x{661}\x{662}ABC
+  
+/\p{Nd}*+(...)/8
+      \x{660}\x{661}\x{662}ABC
+  
+/\p{Nd}*+(....)/8
+      ** Failers
+      \x{660}\x{661}\x{662}ABC
+  
+/\p{Lu}/8i
+    A
+    a\x{10a0}B 
+    ** Failers 
+    a
+    \x{1d00}  
+
+/\p{^Lu}/8i
+    1234
+    ** Failers
+    ABC 
+
+/\P{Lu}/8i
+    1234
+    ** Failers
+    ABC 
+
+/(?<=A\p{Nd})XYZ/8
+    A2XYZ
+    123A5XYZPQR
+    ABA\x{660}XYZpqr
+    ** Failers
+    AXYZ
+    XYZ     
+    
+/(?<!\pL)XYZ/8
+    1XYZ
+    AB=XYZ.. 
+    XYZ 
+    ** Failers
+    WXYZ 
+
+/[\p{L}]/D
+
+/[\p{^L}]/D
+
+/[\P{L}]/D
+
+/[\P{^L}]/D
+
+/[abc\p{L}\x{0660}]/8D
+
+/[\p{Nd}]/8DM
+    1234
+
+/[\p{Nd}+-]+/8DM
+    1234
+    12-34
+    12+\x{661}-34  
+    ** Failers
+    abcd  
+
+/[\P{Nd}]+/8
+    abcd
+    ** Failers
+    1234
+
+/\D+/8
+    11111111111111111111111111111111111111111111111111111111111111111111111
+    aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+     
+/\P{Nd}+/8
+    11111111111111111111111111111111111111111111111111111111111111111111111
+    aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+
+/[\D]+/8
+    11111111111111111111111111111111111111111111111111111111111111111111111
+    aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+
+/[\P{Nd}]+/8
+    11111111111111111111111111111111111111111111111111111111111111111111111
+    aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+
+/[\D\P{Nd}]+/8
+    11111111111111111111111111111111111111111111111111111111111111111111111
+    aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+
+/\pL/8
+    a
+    A 
+
+/\pL/8i
+    a
+    A 
+    
+/\p{Lu}/8 
+    A
+    aZ
+    ** Failers
+    abc   
+
+/\p{Lu}/8i
+    A
+    aZ
+    ** Failers
+    abc   
+
+/\p{Ll}/8 
+    a
+    Az
+    ** Failers
+    ABC   
+
+/\p{Ll}/8i 
+    a
+    Az
+    ** Failers
+    ABC   
+
+/^\x{c0}$/8i
+    \x{c0}
+    \x{e0} 
+
+/^\x{e0}$/8i
+    \x{c0}
+    \x{e0} 
+
+/A\x{391}\x{10427}\x{ff3a}\x{1fb0}/8
+    A\x{391}\x{10427}\x{ff3a}\x{1fb0}
+    ** Failers
+    a\x{391}\x{10427}\x{ff3a}\x{1fb0}   
+    A\x{3b1}\x{10427}\x{ff3a}\x{1fb0}
+    A\x{391}\x{1044F}\x{ff3a}\x{1fb0}
+    A\x{391}\x{10427}\x{ff5a}\x{1fb0}
+    A\x{391}\x{10427}\x{ff3a}\x{1fb8}
+
+/A\x{391}\x{10427}\x{ff3a}\x{1fb0}/8i
+    A\x{391}\x{10427}\x{ff3a}\x{1fb0}
+    a\x{391}\x{10427}\x{ff3a}\x{1fb0}   
+    A\x{3b1}\x{10427}\x{ff3a}\x{1fb0}
+    A\x{391}\x{1044F}\x{ff3a}\x{1fb0}
+    A\x{391}\x{10427}\x{ff5a}\x{1fb0}
+    A\x{391}\x{10427}\x{ff3a}\x{1fb8}
+
+/A\x{391}\x{10427}\x{ff3a}\x{1fb0}/8iD
+
+/A\x{391}\x{10427}\x{ff3a}\x{1fb0}/8D
+
+/AB\x{1fb0}/8D
+
+/AB\x{1fb0}/8Di
+
+/\x{391}+/8i
+    \x{391}\x{3b1}\x{3b1}\x{3b1}\x{391}
+
+/\x{391}{3,5}(.)/8i
+    \x{391}\x{3b1}\x{3b1}\x{3b1}\x{391}X
+
+/\x{391}{3,5}?(.)/8i
+    \x{391}\x{3b1}\x{3b1}\x{3b1}\x{391}X
+
+/[\x{391}\x{ff3a}]/8i
+    \x{391}
+    \x{ff3a}
+    \x{3b1}
+    \x{ff5a}   
+    
+/[\x{c0}\x{391}]/8i
+    \x{c0}
+    \x{e0} 
+
+/[\x{105}-\x{109}]/8iD
+    \x{104}
+    \x{105}
+    \x{109}  
+    ** Failers
+    \x{100}
+    \x{10a} 
+    
+/[z-\x{100}]/8iD 
+    Z
+    z
+    \x{39c}
+    \x{178}
+    |
+    \x{80}
+    \x{ff}
+    \x{100}
+    \x{101} 
+    ** Failers
+    \x{102}
+    Y
+    y           
+
+/[z-\x{100}]/8Di
+
+/^\X/8
+    A
+    A\x{300}BC 
+    A\x{300}\x{301}\x{302}BC 
+    *** Failers
+    \x{300}  
+
+/^[\X]/8
+    X123
+    *** Failers
+    AXYZ
+
+/^(\X*)C/8
+    A\x{300}\x{301}\x{302}BCA\x{300}\x{301} 
+    A\x{300}\x{301}\x{302}BCA\x{300}\x{301}C 
+
+/^(\X*?)C/8
+    A\x{300}\x{301}\x{302}BCA\x{300}\x{301} 
+    A\x{300}\x{301}\x{302}BCA\x{300}\x{301}C 
+
+/^(\X*)(.)/8
+    A\x{300}\x{301}\x{302}BCA\x{300}\x{301} 
+    A\x{300}\x{301}\x{302}BCA\x{300}\x{301}C 
+
+/^(\X*?)(.)/8
+    A\x{300}\x{301}\x{302}BCA\x{300}\x{301} 
+    A\x{300}\x{301}\x{302}BCA\x{300}\x{301}C 
+
+/^\X(.)/8
+    *** Failers
+    A\x{300}\x{301}\x{302}
+
+/^\X{2,3}(.)/8
+    A\x{300}\x{301}B\x{300}X
+    A\x{300}\x{301}B\x{300}C\x{300}\x{301}
+    A\x{300}\x{301}B\x{300}C\x{300}\x{301}X
+    A\x{300}\x{301}B\x{300}C\x{300}\x{301}DA\x{300}X
+    
+/^\X{2,3}?(.)/8
+    A\x{300}\x{301}B\x{300}X
+    A\x{300}\x{301}B\x{300}C\x{300}\x{301}
+    A\x{300}\x{301}B\x{300}C\x{300}\x{301}X
+    A\x{300}\x{301}B\x{300}C\x{300}\x{301}DA\x{300}X
+    
+/ End of testinput6 /

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/testdata/testoutput1
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/testdata/testoutput1	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/testdata/testoutput1	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,6275 @@
+PCRE version 5.0 13-Sep-2004
+
+/the quick brown fox/
+    the quick brown fox
+ 0: the quick brown fox
+    The quick brown FOX
+No match
+    What do you know about the quick brown fox?
+ 0: the quick brown fox
+    What do you know about THE QUICK BROWN FOX?
+No match
+
+/The quick brown fox/i
+    the quick brown fox
+ 0: the quick brown fox
+    The quick brown FOX
+ 0: The quick brown FOX
+    What do you know about the quick brown fox?
+ 0: the quick brown fox
+    What do you know about THE QUICK BROWN FOX?
+ 0: THE QUICK BROWN FOX
+
+/abcd\t\n\r\f\a\e\071\x3b\$\\\?caxyz/
+    abcd\t\n\r\f\a\e9;\$\\?caxyz
+ 0: abcd\x09\x0a\x0d\x0c\x07\x1b9;$\?caxyz
+
+/a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz/
+    abxyzpqrrrabbxyyyypqAzz
+ 0: abxyzpqrrrabbxyyyypqAzz
+    abxyzpqrrrabbxyyyypqAzz
+ 0: abxyzpqrrrabbxyyyypqAzz
+    aabxyzpqrrrabbxyyyypqAzz
+ 0: aabxyzpqrrrabbxyyyypqAzz
+    aaabxyzpqrrrabbxyyyypqAzz
+ 0: aaabxyzpqrrrabbxyyyypqAzz
+    aaaabxyzpqrrrabbxyyyypqAzz
+ 0: aaaabxyzpqrrrabbxyyyypqAzz
+    abcxyzpqrrrabbxyyyypqAzz
+ 0: abcxyzpqrrrabbxyyyypqAzz
+    aabcxyzpqrrrabbxyyyypqAzz
+ 0: aabcxyzpqrrrabbxyyyypqAzz
+    aaabcxyzpqrrrabbxyyyypAzz
+ 0: aaabcxyzpqrrrabbxyyyypAzz
+    aaabcxyzpqrrrabbxyyyypqAzz
+ 0: aaabcxyzpqrrrabbxyyyypqAzz
+    aaabcxyzpqrrrabbxyyyypqqAzz
+ 0: aaabcxyzpqrrrabbxyyyypqqAzz
+    aaabcxyzpqrrrabbxyyyypqqqAzz
+ 0: aaabcxyzpqrrrabbxyyyypqqqAzz
+    aaabcxyzpqrrrabbxyyyypqqqqAzz
+ 0: aaabcxyzpqrrrabbxyyyypqqqqAzz
+    aaabcxyzpqrrrabbxyyyypqqqqqAzz
+ 0: aaabcxyzpqrrrabbxyyyypqqqqqAzz
+    aaabcxyzpqrrrabbxyyyypqqqqqqAzz
+ 0: aaabcxyzpqrrrabbxyyyypqqqqqqAzz
+    aaaabcxyzpqrrrabbxyyyypqAzz
+ 0: aaaabcxyzpqrrrabbxyyyypqAzz
+    abxyzzpqrrrabbxyyyypqAzz
+ 0: abxyzzpqrrrabbxyyyypqAzz
+    aabxyzzzpqrrrabbxyyyypqAzz
+ 0: aabxyzzzpqrrrabbxyyyypqAzz
+    aaabxyzzzzpqrrrabbxyyyypqAzz
+ 0: aaabxyzzzzpqrrrabbxyyyypqAzz
+    aaaabxyzzzzpqrrrabbxyyyypqAzz
+ 0: aaaabxyzzzzpqrrrabbxyyyypqAzz
+    abcxyzzpqrrrabbxyyyypqAzz
+ 0: abcxyzzpqrrrabbxyyyypqAzz
+    aabcxyzzzpqrrrabbxyyyypqAzz
+ 0: aabcxyzzzpqrrrabbxyyyypqAzz
+    aaabcxyzzzzpqrrrabbxyyyypqAzz
+ 0: aaabcxyzzzzpqrrrabbxyyyypqAzz
+    aaaabcxyzzzzpqrrrabbxyyyypqAzz
+ 0: aaaabcxyzzzzpqrrrabbxyyyypqAzz
+    aaaabcxyzzzzpqrrrabbbxyyyypqAzz
+ 0: aaaabcxyzzzzpqrrrabbbxyyyypqAzz
+    aaaabcxyzzzzpqrrrabbbxyyyyypqAzz
+ 0: aaaabcxyzzzzpqrrrabbbxyyyyypqAzz
+    aaabcxyzpqrrrabbxyyyypABzz
+ 0: aaabcxyzpqrrrabbxyyyypABzz
+    aaabcxyzpqrrrabbxyyyypABBzz
+ 0: aaabcxyzpqrrrabbxyyyypABBzz
+    >>>aaabxyzpqrrrabbxyyyypqAzz
+ 0: aaabxyzpqrrrabbxyyyypqAzz
+    >aaaabxyzpqrrrabbxyyyypqAzz
+ 0: aaaabxyzpqrrrabbxyyyypqAzz
+    >>>>abcxyzpqrrrabbxyyyypqAzz
+ 0: abcxyzpqrrrabbxyyyypqAzz
+    *** Failers
+No match
+    abxyzpqrrabbxyyyypqAzz
+No match
+    abxyzpqrrrrabbxyyyypqAzz
+No match
+    abxyzpqrrrabxyyyypqAzz
+No match
+    aaaabcxyzzzzpqrrrabbbxyyyyyypqAzz
+No match
+    aaaabcxyzzzzpqrrrabbbxyyypqAzz
+No match
+    aaabcxyzpqrrrabbxyyyypqqqqqqqAzz
+No match
+
+/^(abc){1,2}zz/
+    abczz
+ 0: abczz
+ 1: abc
+    abcabczz
+ 0: abcabczz
+ 1: abc
+    *** Failers
+No match
+    zz
+No match
+    abcabcabczz
+No match
+    >>abczz
+No match
+
+/^(b+?|a){1,2}?c/
+    bc
+ 0: bc
+ 1: b
+    bbc
+ 0: bbc
+ 1: b
+    bbbc
+ 0: bbbc
+ 1: bb
+    bac
+ 0: bac
+ 1: a
+    bbac
+ 0: bbac
+ 1: a
+    aac
+ 0: aac
+ 1: a
+    abbbbbbbbbbbc
+ 0: abbbbbbbbbbbc
+ 1: bbbbbbbbbbb
+    bbbbbbbbbbbac
+ 0: bbbbbbbbbbbac
+ 1: a
+    *** Failers
+No match
+    aaac
+No match
+    abbbbbbbbbbbac
+No match
+
+/^(b+|a){1,2}c/
+    bc
+ 0: bc
+ 1: b
+    bbc
+ 0: bbc
+ 1: bb
+    bbbc
+ 0: bbbc
+ 1: bbb
+    bac
+ 0: bac
+ 1: a
+    bbac
+ 0: bbac
+ 1: a
+    aac
+ 0: aac
+ 1: a
+    abbbbbbbbbbbc
+ 0: abbbbbbbbbbbc
+ 1: bbbbbbbbbbb
+    bbbbbbbbbbbac
+ 0: bbbbbbbbbbbac
+ 1: a
+    *** Failers
+No match
+    aaac
+No match
+    abbbbbbbbbbbac
+No match
+
+/^(b+|a){1,2}?bc/
+    bbc
+ 0: bbc
+ 1: b
+
+/^(b*|ba){1,2}?bc/
+    babc
+ 0: babc
+ 1: ba
+    bbabc
+ 0: bbabc
+ 1: ba
+    bababc
+ 0: bababc
+ 1: ba
+    *** Failers
+No match
+    bababbc
+No match
+    babababc
+No match
+
+/^(ba|b*){1,2}?bc/
+    babc
+ 0: babc
+ 1: ba
+    bbabc
+ 0: bbabc
+ 1: ba
+    bababc
+ 0: bababc
+ 1: ba
+    *** Failers
+No match
+    bababbc
+No match
+    babababc
+No match
+
+/^\ca\cA\c[\c{\c:/
+    \x01\x01\e;z
+ 0: \x01\x01\x1b;z
+
+/^[ab\]cde]/
+    athing
+ 0: a
+    bthing
+ 0: b
+    ]thing
+ 0: ]
+    cthing
+ 0: c
+    dthing
+ 0: d
+    ething
+ 0: e
+    *** Failers
+No match
+    fthing
+No match
+    [thing
+No match
+    \\thing
+No match
+
+/^[]cde]/
+    ]thing
+ 0: ]
+    cthing
+ 0: c
+    dthing
+ 0: d
+    ething
+ 0: e
+    *** Failers
+No match
+    athing
+No match
+    fthing
+No match
+
+/^[^ab\]cde]/
+    fthing
+ 0: f
+    [thing
+ 0: [
+    \\thing
+ 0: \
+    *** Failers
+ 0: *
+    athing
+No match
+    bthing
+No match
+    ]thing
+No match
+    cthing
+No match
+    dthing
+No match
+    ething
+No match
+
+/^[^]cde]/
+    athing
+ 0: a
+    fthing
+ 0: f
+    *** Failers
+ 0: *
+    ]thing
+No match
+    cthing
+No match
+    dthing
+No match
+    ething
+No match
+
+/^\?/
+    ?
+ 0: \x81
+
+/^ÿ/
+    ÿ
+ 0: \xff
+
+/^[0-9]+$/
+    0
+ 0: 0
+    1
+ 0: 1
+    2
+ 0: 2
+    3
+ 0: 3
+    4
+ 0: 4
+    5
+ 0: 5
+    6
+ 0: 6
+    7
+ 0: 7
+    8
+ 0: 8
+    9
+ 0: 9
+    10
+ 0: 10
+    100
+ 0: 100
+    *** Failers
+No match
+    abc
+No match
+
+/^.*nter/
+    enter
+ 0: enter
+    inter
+ 0: inter
+    uponter
+ 0: uponter
+
+/^xxx[0-9]+$/
+    xxx0
+ 0: xxx0
+    xxx1234
+ 0: xxx1234
+    *** Failers
+No match
+    xxx
+No match
+
+/^.+[0-9][0-9][0-9]$/
+    x123
+ 0: x123
+    xx123
+ 0: xx123
+    123456
+ 0: 123456
+    *** Failers
+No match
+    123
+No match
+    x1234
+ 0: x1234
+
+/^.+?[0-9][0-9][0-9]$/
+    x123
+ 0: x123
+    xx123
+ 0: xx123
+    123456
+ 0: 123456
+    *** Failers
+No match
+    123
+No match
+    x1234
+ 0: x1234
+
+/^([^!]+)!(.+)=apquxz\.ixr\.zzz\.ac\.uk$/
+    abc!pqr=apquxz.ixr.zzz.ac.uk
+ 0: abc!pqr=apquxz.ixr.zzz.ac.uk
+ 1: abc
+ 2: pqr
+    *** Failers
+No match
+    !pqr=apquxz.ixr.zzz.ac.uk
+No match
+    abc!=apquxz.ixr.zzz.ac.uk
+No match
+    abc!pqr=apquxz:ixr.zzz.ac.uk
+No match
+    abc!pqr=apquxz.ixr.zzz.ac.ukk
+No match
+
+/:/
+    Well, we need a colon: somewhere
+ 0: :
+    *** Fail if we don't
+No match
+
+/([\da-f:]+)$/i
+    0abc
+ 0: 0abc
+ 1: 0abc
+    abc
+ 0: abc
+ 1: abc
+    fed
+ 0: fed
+ 1: fed
+    E
+ 0: E
+ 1: E
+    ::
+ 0: ::
+ 1: ::
+    5f03:12C0::932e
+ 0: 5f03:12C0::932e
+ 1: 5f03:12C0::932e
+    fed def
+ 0: def
+ 1: def
+    Any old stuff
+ 0: ff
+ 1: ff
+    *** Failers
+No match
+    0zzz
+No match
+    gzzz
+No match
+    fed\x20
+No match
+    Any old rubbish
+No match
+
+/^.*\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/
+    .1.2.3
+ 0: .1.2.3
+ 1: 1
+ 2: 2
+ 3: 3
+    A.12.123.0
+ 0: A.12.123.0
+ 1: 12
+ 2: 123
+ 3: 0
+    *** Failers
+No match
+    .1.2.3333
+No match
+    1.2.3
+No match
+    1234.2.3
+No match
+
+/^(\d+)\s+IN\s+SOA\s+(\S+)\s+(\S+)\s*\(\s*$/
+    1 IN SOA non-sp1 non-sp2(
+ 0: 1 IN SOA non-sp1 non-sp2(
+ 1: 1
+ 2: non-sp1
+ 3: non-sp2
+    1    IN    SOA    non-sp1    non-sp2   (
+ 0: 1    IN    SOA    non-sp1    non-sp2   (
+ 1: 1
+ 2: non-sp1
+ 3: non-sp2
+    *** Failers
+No match
+    1IN SOA non-sp1 non-sp2(
+No match
+
+/^[a-zA-Z\d][a-zA-Z\d\-]*(\.[a-zA-Z\d][a-zA-z\d\-]*)*\.$/
+    a.
+ 0: a.
+    Z.
+ 0: Z.
+    2.
+ 0: 2.
+    ab-c.pq-r.
+ 0: ab-c.pq-r.
+ 1: .pq-r
+    sxk.zzz.ac.uk.
+ 0: sxk.zzz.ac.uk.
+ 1: .uk
+    x-.y-.
+ 0: x-.y-.
+ 1: .y-
+    *** Failers
+No match
+    -abc.peq.
+No match
+
+/^\*\.[a-z]([a-z\-\d]*[a-z\d]+)?(\.[a-z]([a-z\-\d]*[a-z\d]+)?)*$/
+    *.a
+ 0: *.a
+    *.b0-a
+ 0: *.b0-a
+ 1: 0-a
+    *.c3-b.c
+ 0: *.c3-b.c
+ 1: 3-b
+ 2: .c
+    *.c-a.b-c
+ 0: *.c-a.b-c
+ 1: -a
+ 2: .b-c
+ 3: -c
+    *** Failers
+No match
+    *.0
+No match
+    *.a-
+No match
+    *.a-b.c-
+No match
+    *.c-a.0-c
+No match
+
+/^(?=ab(de))(abd)(e)/
+    abde
+ 0: abde
+ 1: de
+ 2: abd
+ 3: e
+
+/^(?!(ab)de|x)(abd)(f)/
+    abdf
+ 0: abdf
+ 1: <unset>
+ 2: abd
+ 3: f
+
+/^(?=(ab(cd)))(ab)/
+    abcd
+ 0: ab
+ 1: abcd
+ 2: cd
+ 3: ab
+
+/^[\da-f](\.[\da-f])*$/i
+    a.b.c.d
+ 0: a.b.c.d
+ 1: .d
+    A.B.C.D
+ 0: A.B.C.D
+ 1: .D
+    a.b.c.1.2.3.C
+ 0: a.b.c.1.2.3.C
+ 1: .C
+
+/^\".*\"\s*(;.*)?$/
+    \"1234\"
+ 0: "1234"
+    \"abcd\" ;
+ 0: "abcd" ;
+ 1: ;
+    \"\" ; rhubarb
+ 0: "" ; rhubarb
+ 1: ; rhubarb
+    *** Failers
+No match
+    \"1234\" : things
+No match
+
+/^$/
+    \
+ 0: 
+    *** Failers
+No match
+
+/   ^    a   (?# begins with a)  b\sc (?# then b c) $ (?# then end)/x
+    ab c
+ 0: ab c
+    *** Failers
+No match
+    abc
+No match
+    ab cde
+No match
+
+/(?x)   ^    a   (?# begins with a)  b\sc (?# then b c) $ (?# then end)/
+    ab c
+ 0: ab c
+    *** Failers
+No match
+    abc
+No match
+    ab cde
+No match
+
+/^   a\ b[c ]d       $/x
+    a bcd
+ 0: a bcd
+    a b d
+ 0: a b d
+    *** Failers
+No match
+    abcd
+No match
+    ab d
+No match
+
+/^(a(b(c)))(d(e(f)))(h(i(j)))(k(l(m)))$/
+    abcdefhijklm
+ 0: abcdefhijklm
+ 1: abc
+ 2: bc
+ 3: c
+ 4: def
+ 5: ef
+ 6: f
+ 7: hij
+ 8: ij
+ 9: j
+10: klm
+11: lm
+12: m
+
+/^(?:a(b(c)))(?:d(e(f)))(?:h(i(j)))(?:k(l(m)))$/
+    abcdefhijklm
+ 0: abcdefhijklm
+ 1: bc
+ 2: c
+ 3: ef
+ 4: f
+ 5: ij
+ 6: j
+ 7: lm
+ 8: m
+
+/^[\w][\W][\s][\S][\d][\D][\b][\n][\c]][\022]/
+    a+ Z0+\x08\n\x1d\x12
+ 0: a+ Z0+\x08\x0a\x1d\x12
+
+/^[.^$|()*+?{,}]+/
+    .^\$(*+)|{?,?}
+ 0: .^$(*+)|{?,?}
+
+/^a*\w/
+    z
+ 0: z
+    az
+ 0: az
+    aaaz
+ 0: aaaz
+    a
+ 0: a
+    aa
+ 0: aa
+    aaaa
+ 0: aaaa
+    a+
+ 0: a
+    aa+
+ 0: aa
+
+/^a*?\w/
+    z
+ 0: z
+    az
+ 0: a
+    aaaz
+ 0: a
+    a
+ 0: a
+    aa
+ 0: a
+    aaaa
+ 0: a
+    a+
+ 0: a
+    aa+
+ 0: a
+
+/^a+\w/
+    az
+ 0: az
+    aaaz
+ 0: aaaz
+    aa
+ 0: aa
+    aaaa
+ 0: aaaa
+    aa+
+ 0: aa
+
+/^a+?\w/
+    az
+ 0: az
+    aaaz
+ 0: aa
+    aa
+ 0: aa
+    aaaa
+ 0: aa
+    aa+
+ 0: aa
+
+/^\d{8}\w{2,}/
+    1234567890
+ 0: 1234567890
+    12345678ab
+ 0: 12345678ab
+    12345678__
+ 0: 12345678__
+    *** Failers
+No match
+    1234567
+No match
+
+/^[aeiou\d]{4,5}$/
+    uoie
+ 0: uoie
+    1234
+ 0: 1234
+    12345
+ 0: 12345
+    aaaaa
+ 0: aaaaa
+    *** Failers
+No match
+    123456
+No match
+
+/^[aeiou\d]{4,5}?/
+    uoie
+ 0: uoie
+    1234
+ 0: 1234
+    12345
+ 0: 1234
+    aaaaa
+ 0: aaaa
+    123456
+ 0: 1234
+
+/\A(abc|def)=(\1){2,3}\Z/
+    abc=abcabc
+ 0: abc=abcabc
+ 1: abc
+ 2: abc
+    def=defdefdef
+ 0: def=defdefdef
+ 1: def
+ 2: def
+    *** Failers
+No match
+    abc=defdef
+No match
+
+/^(a)(b)(c)(d)(e)(f)(g)(h)(i)(j)(k)\11*(\3\4)\1(?#)2$/
+    abcdefghijkcda2
+ 0: abcdefghijkcda2
+ 1: a
+ 2: b
+ 3: c
+ 4: d
+ 5: e
+ 6: f
+ 7: g
+ 8: h
+ 9: i
+10: j
+11: k
+12: cd
+    abcdefghijkkkkcda2
+ 0: abcdefghijkkkkcda2
+ 1: a
+ 2: b
+ 3: c
+ 4: d
+ 5: e
+ 6: f
+ 7: g
+ 8: h
+ 9: i
+10: j
+11: k
+12: cd
+
+/(cat(a(ract|tonic)|erpillar)) \1()2(3)/
+    cataract cataract23
+ 0: cataract cataract23
+ 1: cataract
+ 2: aract
+ 3: ract
+ 4: 
+ 5: 3
+    catatonic catatonic23
+ 0: catatonic catatonic23
+ 1: catatonic
+ 2: atonic
+ 3: tonic
+ 4: 
+ 5: 3
+    caterpillar caterpillar23
+ 0: caterpillar caterpillar23
+ 1: caterpillar
+ 2: erpillar
+ 3: <unset>
+ 4: 
+ 5: 3
+
+
+/^From +([^ ]+) +[a-zA-Z][a-zA-Z][a-zA-Z] +[a-zA-Z][a-zA-Z][a-zA-Z] +[0-9]?[0-9] +[0-9][0-9]:[0-9][0-9]/
+    From abcd  Mon Sep 01 12:33:02 1997
+ 0: From abcd  Mon Sep 01 12:33
+ 1: abcd
+
+/^From\s+\S+\s+([a-zA-Z]{3}\s+){2}\d{1,2}\s+\d\d:\d\d/
+    From abcd  Mon Sep 01 12:33:02 1997
+ 0: From abcd  Mon Sep 01 12:33
+ 1: Sep 
+    From abcd  Mon Sep  1 12:33:02 1997
+ 0: From abcd  Mon Sep  1 12:33
+ 1: Sep  
+    *** Failers
+No match
+    From abcd  Sep 01 12:33:02 1997
+No match
+
+/^12.34/s
+    12\n34
+ 0: 12\x0a34
+    12\r34
+ 0: 12\x0d34
+
+/\w+(?=\t)/
+    the quick brown\t fox
+ 0: brown
+
+/foo(?!bar)(.*)/
+    foobar is foolish see?
+ 0: foolish see?
+ 1: lish see?
+
+/(?:(?!foo)...|^.{0,2})bar(.*)/
+    foobar crowbar etc
+ 0: rowbar etc
+ 1:  etc
+    barrel
+ 0: barrel
+ 1: rel
+    2barrel
+ 0: 2barrel
+ 1: rel
+    A barrel
+ 0: A barrel
+ 1: rel
+
+/^(\D*)(?=\d)(?!123)/
+    abc456
+ 0: abc
+ 1: abc
+    *** Failers
+No match
+    abc123
+No match
+
+/^1234(?# test newlines
+  inside)/
+    1234
+ 0: 1234
+
+/^1234 #comment in extended re
+  /x
+    1234
+ 0: 1234
+
+/#rhubarb
+  abcd/x
+    abcd
+ 0: abcd
+
+/^abcd#rhubarb/x
+    abcd
+ 0: abcd
+
+/^(a)\1{2,3}(.)/
+    aaab
+ 0: aaab
+ 1: a
+ 2: b
+    aaaab
+ 0: aaaab
+ 1: a
+ 2: b
+    aaaaab
+ 0: aaaaa
+ 1: a
+ 2: a
+    aaaaaab
+ 0: aaaaa
+ 1: a
+ 2: a
+
+/(?!^)abc/
+    the abc
+ 0: abc
+    *** Failers
+No match
+    abc
+No match
+
+/(?=^)abc/
+    abc
+ 0: abc
+    *** Failers
+No match
+    the abc
+No match
+
+/^[ab]{1,3}(ab*|b)/
+    aabbbbb
+ 0: aabb
+ 1: b
+
+/^[ab]{1,3}?(ab*|b)/
+    aabbbbb
+ 0: aabbbbb
+ 1: abbbbb
+
+/^[ab]{1,3}?(ab*?|b)/
+    aabbbbb
+ 0: aa
+ 1: a
+
+/^[ab]{1,3}(ab*?|b)/
+    aabbbbb
+ 0: aabb
+ 1: b
+
+/  (?: [\040\t] |  \(
+(?:  [^\\\x80-\xff\n\015()]  |  \\ [^\x80-\xff]  |  \( (?:  [^\\\x80-\xff\n\015()]  |  \\ [^\x80-\xff]  )* \)  )*
+\)  )*                          # optional leading comment
+(?:    (?:
+[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+    # some number of atom characters...
+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom
+|
+" (?:                      # opening quote...
+[^\\\x80-\xff\n\015"]                #   Anything except backslash and quote
+|                     #    or
+\\ [^\x80-\xff]           #   Escaped something (something != CR)
+)* "  # closing quote
+)                    # initial word
+(?:  (?: [\040\t] |  \(
+(?:  [^\\\x80-\xff\n\015()]  |  \\ [^\x80-\xff]  |  \( (?:  [^\\\x80-\xff\n\015()]  |  \\ [^\x80-\xff]  )* \)  )*
+\)  )*  \.  (?: [\040\t] |  \(
+(?:  [^\\\x80-\xff\n\015()]  |  \\ [^\x80-\xff]  |  \( (?:  [^\\\x80-\xff\n\015()]  |  \\ [^\x80-\xff]  )* \)  )*
+\)  )*   (?:
+[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+    # some number of atom characters...
+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom
+|
+" (?:                      # opening quote...
+[^\\\x80-\xff\n\015"]                #   Anything except backslash and quote
+|                     #    or
+\\ [^\x80-\xff]           #   Escaped something (something != CR)
+)* "  # closing quote
+)  )* # further okay, if led by a period
+(?: [\040\t] |  \(
+(?:  [^\\\x80-\xff\n\015()]  |  \\ [^\x80-\xff]  |  \( (?:  [^\\\x80-\xff\n\015()]  |  \\ [^\x80-\xff]  )* \)  )*
+\)  )*  @  (?: [\040\t] |  \(
+(?:  [^\\\x80-\xff\n\015()]  |  \\ [^\x80-\xff]  |  \( (?:  [^\\\x80-\xff\n\015()]  |  \\ [^\x80-\xff]  )* \)  )*
+\)  )*    (?:
+[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+    # some number of atom characters...
+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom
+|   \[                         # [
+(?: [^\\\x80-\xff\n\015\[\]] |  \\ [^\x80-\xff]  )*    #    stuff
+\]                        #           ]
+)                           # initial subdomain
+(?:                                  #
+(?: [\040\t] |  \(
+(?:  [^\\\x80-\xff\n\015()]  |  \\ [^\x80-\xff]  |  \( (?:  [^\\\x80-\xff\n\015()]  |  \\ [^\x80-\xff]  )* \)  )*
+\)  )*  \.                        # if led by a period...
+(?: [\040\t] |  \(
+(?:  [^\\\x80-\xff\n\015()]  |  \\ [^\x80-\xff]  |  \( (?:  [^\\\x80-\xff\n\015()]  |  \\ [^\x80-\xff]  )* \)  )*
+\)  )*   (?:
+[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+    # some number of atom characters...
+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom
+|   \[                         # [
+(?: [^\\\x80-\xff\n\015\[\]] |  \\ [^\x80-\xff]  )*    #    stuff
+\]                        #           ]
+)                     #   ...further okay
+)*
+# address
+|                     #  or
+(?:
+[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+    # some number of atom characters...
+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom
+|
+" (?:                      # opening quote...
+[^\\\x80-\xff\n\015"]                #   Anything except backslash and quote
+|                     #    or
+\\ [^\x80-\xff]           #   Escaped something (something != CR)
+)* "  # closing quote
+)             # one word, optionally followed by....
+(?:
+[^()<>@,;:".\\\[\]\x80-\xff\000-\010\012-\037]  |  # atom and space parts, or...
+\(
+(?:  [^\\\x80-\xff\n\015()]  |  \\ [^\x80-\xff]  |  \( (?:  [^\\\x80-\xff\n\015()]  |  \\ [^\x80-\xff]  )* \)  )*
+\)       |  # comments, or...
+
+" (?:                      # opening quote...
+[^\\\x80-\xff\n\015"]                #   Anything except backslash and quote
+|                     #    or
+\\ [^\x80-\xff]           #   Escaped something (something != CR)
+)* "  # closing quote
+# quoted strings
+)*
+<  (?: [\040\t] |  \(
+(?:  [^\\\x80-\xff\n\015()]  |  \\ [^\x80-\xff]  |  \( (?:  [^\\\x80-\xff\n\015()]  |  \\ [^\x80-\xff]  )* \)  )*
+\)  )*                     # leading <
+(?:  @  (?: [\040\t] |  \(
+(?:  [^\\\x80-\xff\n\015()]  |  \\ [^\x80-\xff]  |  \( (?:  [^\\\x80-\xff\n\015()]  |  \\ [^\x80-\xff]  )* \)  )*
+\)  )*    (?:
+[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+    # some number of atom characters...
+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom
+|   \[                         # [
+(?: [^\\\x80-\xff\n\015\[\]] |  \\ [^\x80-\xff]  )*    #    stuff
+\]                        #           ]
+)                           # initial subdomain
+(?:                                  #
+(?: [\040\t] |  \(
+(?:  [^\\\x80-\xff\n\015()]  |  \\ [^\x80-\xff]  |  \( (?:  [^\\\x80-\xff\n\015()]  |  \\ [^\x80-\xff]  )* \)  )*
+\)  )*  \.                        # if led by a period...
+(?: [\040\t] |  \(
+(?:  [^\\\x80-\xff\n\015()]  |  \\ [^\x80-\xff]  |  \( (?:  [^\\\x80-\xff\n\015()]  |  \\ [^\x80-\xff]  )* \)  )*
+\)  )*   (?:
+[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+    # some number of atom characters...
+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom
+|   \[                         # [
+(?: [^\\\x80-\xff\n\015\[\]] |  \\ [^\x80-\xff]  )*    #    stuff
+\]                        #           ]
+)                     #   ...further okay
+)*
+
+(?:  (?: [\040\t] |  \(
+(?:  [^\\\x80-\xff\n\015()]  |  \\ [^\x80-\xff]  |  \( (?:  [^\\\x80-\xff\n\015()]  |  \\ [^\x80-\xff]  )* \)  )*
+\)  )*  ,  (?: [\040\t] |  \(
+(?:  [^\\\x80-\xff\n\015()]  |  \\ [^\x80-\xff]  |  \( (?:  [^\\\x80-\xff\n\015()]  |  \\ [^\x80-\xff]  )* \)  )*
+\)  )*  @  (?: [\040\t] |  \(
+(?:  [^\\\x80-\xff\n\015()]  |  \\ [^\x80-\xff]  |  \( (?:  [^\\\x80-\xff\n\015()]  |  \\ [^\x80-\xff]  )* \)  )*
+\)  )*    (?:
+[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+    # some number of atom characters...
+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom
+|   \[                         # [
+(?: [^\\\x80-\xff\n\015\[\]] |  \\ [^\x80-\xff]  )*    #    stuff
+\]                        #           ]
+)                           # initial subdomain
+(?:                                  #
+(?: [\040\t] |  \(
+(?:  [^\\\x80-\xff\n\015()]  |  \\ [^\x80-\xff]  |  \( (?:  [^\\\x80-\xff\n\015()]  |  \\ [^\x80-\xff]  )* \)  )*
+\)  )*  \.                        # if led by a period...
+(?: [\040\t] |  \(
+(?:  [^\\\x80-\xff\n\015()]  |  \\ [^\x80-\xff]  |  \( (?:  [^\\\x80-\xff\n\015()]  |  \\ [^\x80-\xff]  )* \)  )*
+\)  )*   (?:
+[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+    # some number of atom characters...
+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom
+|   \[                         # [
+(?: [^\\\x80-\xff\n\015\[\]] |  \\ [^\x80-\xff]  )*    #    stuff
+\]                        #           ]
+)                     #   ...further okay
+)*
+)* # further okay, if led by comma
+:                                # closing colon
+(?: [\040\t] |  \(
+(?:  [^\\\x80-\xff\n\015()]  |  \\ [^\x80-\xff]  |  \( (?:  [^\\\x80-\xff\n\015()]  |  \\ [^\x80-\xff]  )* \)  )*
+\)  )*  )? #       optional route
+(?:
+[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+    # some number of atom characters...
+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom
+|
+" (?:                      # opening quote...
+[^\\\x80-\xff\n\015"]                #   Anything except backslash and quote
+|                     #    or
+\\ [^\x80-\xff]           #   Escaped something (something != CR)
+)* "  # closing quote
+)                    # initial word
+(?:  (?: [\040\t] |  \(
+(?:  [^\\\x80-\xff\n\015()]  |  \\ [^\x80-\xff]  |  \( (?:  [^\\\x80-\xff\n\015()]  |  \\ [^\x80-\xff]  )* \)  )*
+\)  )*  \.  (?: [\040\t] |  \(
+(?:  [^\\\x80-\xff\n\015()]  |  \\ [^\x80-\xff]  |  \( (?:  [^\\\x80-\xff\n\015()]  |  \\ [^\x80-\xff]  )* \)  )*
+\)  )*   (?:
+[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+    # some number of atom characters...
+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom
+|
+" (?:                      # opening quote...
+[^\\\x80-\xff\n\015"]                #   Anything except backslash and quote
+|                     #    or
+\\ [^\x80-\xff]           #   Escaped something (something != CR)
+)* "  # closing quote
+)  )* # further okay, if led by a period
+(?: [\040\t] |  \(
+(?:  [^\\\x80-\xff\n\015()]  |  \\ [^\x80-\xff]  |  \( (?:  [^\\\x80-\xff\n\015()]  |  \\ [^\x80-\xff]  )* \)  )*
+\)  )*  @  (?: [\040\t] |  \(
+(?:  [^\\\x80-\xff\n\015()]  |  \\ [^\x80-\xff]  |  \( (?:  [^\\\x80-\xff\n\015()]  |  \\ [^\x80-\xff]  )* \)  )*
+\)  )*    (?:
+[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+    # some number of atom characters...
+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom
+|   \[                         # [
+(?: [^\\\x80-\xff\n\015\[\]] |  \\ [^\x80-\xff]  )*    #    stuff
+\]                        #           ]
+)                           # initial subdomain
+(?:                                  #
+(?: [\040\t] |  \(
+(?:  [^\\\x80-\xff\n\015()]  |  \\ [^\x80-\xff]  |  \( (?:  [^\\\x80-\xff\n\015()]  |  \\ [^\x80-\xff]  )* \)  )*
+\)  )*  \.                        # if led by a period...
+(?: [\040\t] |  \(
+(?:  [^\\\x80-\xff\n\015()]  |  \\ [^\x80-\xff]  |  \( (?:  [^\\\x80-\xff\n\015()]  |  \\ [^\x80-\xff]  )* \)  )*
+\)  )*   (?:
+[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+    # some number of atom characters...
+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom
+|   \[                         # [
+(?: [^\\\x80-\xff\n\015\[\]] |  \\ [^\x80-\xff]  )*    #    stuff
+\]                        #           ]
+)                     #   ...further okay
+)*
+#       address spec
+(?: [\040\t] |  \(
+(?:  [^\\\x80-\xff\n\015()]  |  \\ [^\x80-\xff]  |  \( (?:  [^\\\x80-\xff\n\015()]  |  \\ [^\x80-\xff]  )* \)  )*
+\)  )*  > #                  trailing >
+# name and address
+)  (?: [\040\t] |  \(
+(?:  [^\\\x80-\xff\n\015()]  |  \\ [^\x80-\xff]  |  \( (?:  [^\\\x80-\xff\n\015()]  |  \\ [^\x80-\xff]  )* \)  )*
+\)  )*                       # optional trailing comment
+/x
+    Alan Other <user\@dom.ain>
+ 0: Alan Other <user at dom.ain>
+    <user\@dom.ain>
+ 0: user at dom.ain
+    user\@dom.ain
+ 0: user at dom.ain
+    \"A. Other\" <user.1234\@dom.ain> (a comment)
+ 0: "A. Other" <user.1234 at dom.ain> (a comment)
+    A. Other <user.1234\@dom.ain> (a comment)
+ 0:  Other <user.1234 at dom.ain> (a comment)
+    \"/s=user/ou=host/o=place/prmd=uu.yy/admd= /c=gb/\"\@x400-re.lay
+ 0: "/s=user/ou=host/o=place/prmd=uu.yy/admd= /c=gb/"@x400-re.lay
+    A missing angle <user\@some.where
+ 0: user at some.where
+    *** Failers
+No match
+    The quick brown fox
+No match
+
+/[\040\t]*                    # Nab whitespace.
+(?:
+\(                              #  (
+[^\\\x80-\xff\n\015()] *                             #     normal*
+(?:                                 #       (
+(?:  \\ [^\x80-\xff]  |
+\(                            #  (
+[^\\\x80-\xff\n\015()] *                            #     normal*
+(?:  \\ [^\x80-\xff]   [^\\\x80-\xff\n\015()] * )*        #     (special normal*)*
+\)                           #                       )
+)    #         special
+[^\\\x80-\xff\n\015()] *                         #         normal*
+)*                                  #            )*
+\)                             #                )
+[\040\t]* )*    # If comment found, allow more spaces.
+# optional leading comment
+(?:
+(?:
+[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+    # some number of atom characters...
+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom
+# Atom
+|                       #  or
+"                                     # "
+[^\\\x80-\xff\n\015"] *                            #   normal
+(?:  \\ [^\x80-\xff]  [^\\\x80-\xff\n\015"] * )*        #   ( special normal* )*
+"                                     #        "
+# Quoted string
+)
+[\040\t]*                    # Nab whitespace.
+(?:
+\(                              #  (
+[^\\\x80-\xff\n\015()] *                             #     normal*
+(?:                                 #       (
+(?:  \\ [^\x80-\xff]  |
+\(                            #  (
+[^\\\x80-\xff\n\015()] *                            #     normal*
+(?:  \\ [^\x80-\xff]   [^\\\x80-\xff\n\015()] * )*        #     (special normal*)*
+\)                           #                       )
+)    #         special
+[^\\\x80-\xff\n\015()] *                         #         normal*
+)*                                  #            )*
+\)                             #                )
+[\040\t]* )*    # If comment found, allow more spaces.
+(?:
+\.
+[\040\t]*                    # Nab whitespace.
+(?:
+\(                              #  (
+[^\\\x80-\xff\n\015()] *                             #     normal*
+(?:                                 #       (
+(?:  \\ [^\x80-\xff]  |
+\(                            #  (
+[^\\\x80-\xff\n\015()] *                            #     normal*
+(?:  \\ [^\x80-\xff]   [^\\\x80-\xff\n\015()] * )*        #     (special normal*)*
+\)                           #                       )
+)    #         special
+[^\\\x80-\xff\n\015()] *                         #         normal*
+)*                                  #            )*
+\)                             #                )
+[\040\t]* )*    # If comment found, allow more spaces.
+(?:
+[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+    # some number of atom characters...
+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom
+# Atom
+|                       #  or
+"                                     # "
+[^\\\x80-\xff\n\015"] *                            #   normal
+(?:  \\ [^\x80-\xff]  [^\\\x80-\xff\n\015"] * )*        #   ( special normal* )*
+"                                     #        "
+# Quoted string
+)
+[\040\t]*                    # Nab whitespace.
+(?:
+\(                              #  (
+[^\\\x80-\xff\n\015()] *                             #     normal*
+(?:                                 #       (
+(?:  \\ [^\x80-\xff]  |
+\(                            #  (
+[^\\\x80-\xff\n\015()] *                            #     normal*
+(?:  \\ [^\x80-\xff]   [^\\\x80-\xff\n\015()] * )*        #     (special normal*)*
+\)                           #                       )
+)    #         special
+[^\\\x80-\xff\n\015()] *                         #         normal*
+)*                                  #            )*
+\)                             #                )
+[\040\t]* )*    # If comment found, allow more spaces.
+# additional words
+)*
+@
+[\040\t]*                    # Nab whitespace.
+(?:
+\(                              #  (
+[^\\\x80-\xff\n\015()] *                             #     normal*
+(?:                                 #       (
+(?:  \\ [^\x80-\xff]  |
+\(                            #  (
+[^\\\x80-\xff\n\015()] *                            #     normal*
+(?:  \\ [^\x80-\xff]   [^\\\x80-\xff\n\015()] * )*        #     (special normal*)*
+\)                           #                       )
+)    #         special
+[^\\\x80-\xff\n\015()] *                         #         normal*
+)*                                  #            )*
+\)                             #                )
+[\040\t]* )*    # If comment found, allow more spaces.
+(?:
+[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+    # some number of atom characters...
+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom
+|
+\[                            # [
+(?: [^\\\x80-\xff\n\015\[\]] |  \\ [^\x80-\xff]  )*     #    stuff
+\]                           #           ]
+)
+[\040\t]*                    # Nab whitespace.
+(?:
+\(                              #  (
+[^\\\x80-\xff\n\015()] *                             #     normal*
+(?:                                 #       (
+(?:  \\ [^\x80-\xff]  |
+\(                            #  (
+[^\\\x80-\xff\n\015()] *                            #     normal*
+(?:  \\ [^\x80-\xff]   [^\\\x80-\xff\n\015()] * )*        #     (special normal*)*
+\)                           #                       )
+)    #         special
+[^\\\x80-\xff\n\015()] *                         #         normal*
+)*                                  #            )*
+\)                             #                )
+[\040\t]* )*    # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\.
+[\040\t]*                    # Nab whitespace.
+(?:
+\(                              #  (
+[^\\\x80-\xff\n\015()] *                             #     normal*
+(?:                                 #       (
+(?:  \\ [^\x80-\xff]  |
+\(                            #  (
+[^\\\x80-\xff\n\015()] *                            #     normal*
+(?:  \\ [^\x80-\xff]   [^\\\x80-\xff\n\015()] * )*        #     (special normal*)*
+\)                           #                       )
+)    #         special
+[^\\\x80-\xff\n\015()] *                         #         normal*
+)*                                  #            )*
+\)                             #                )
+[\040\t]* )*    # If comment found, allow more spaces.
+(?:
+[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+    # some number of atom characters...
+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom
+|
+\[                            # [
+(?: [^\\\x80-\xff\n\015\[\]] |  \\ [^\x80-\xff]  )*     #    stuff
+\]                           #           ]
+)
+[\040\t]*                    # Nab whitespace.
+(?:
+\(                              #  (
+[^\\\x80-\xff\n\015()] *                             #     normal*
+(?:                                 #       (
+(?:  \\ [^\x80-\xff]  |
+\(                            #  (
+[^\\\x80-\xff\n\015()] *                            #     normal*
+(?:  \\ [^\x80-\xff]   [^\\\x80-\xff\n\015()] * )*        #     (special normal*)*
+\)                           #                       )
+)    #         special
+[^\\\x80-\xff\n\015()] *                         #         normal*
+)*                                  #            )*
+\)                             #                )
+[\040\t]* )*    # If comment found, allow more spaces.
+# optional trailing comments
+)*
+# address
+|                             #  or
+(?:
+[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+    # some number of atom characters...
+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom
+# Atom
+|                       #  or
+"                                     # "
+[^\\\x80-\xff\n\015"] *                            #   normal
+(?:  \\ [^\x80-\xff]  [^\\\x80-\xff\n\015"] * )*        #   ( special normal* )*
+"                                     #        "
+# Quoted string
+)
+# leading word
+[^()<>@,;:".\\\[\]\x80-\xff\000-\010\012-\037] *               # "normal" atoms and or spaces
+(?:
+(?:
+\(                              #  (
+[^\\\x80-\xff\n\015()] *                             #     normal*
+(?:                                 #       (
+(?:  \\ [^\x80-\xff]  |
+\(                            #  (
+[^\\\x80-\xff\n\015()] *                            #     normal*
+(?:  \\ [^\x80-\xff]   [^\\\x80-\xff\n\015()] * )*        #     (special normal*)*
+\)                           #                       )
+)    #         special
+[^\\\x80-\xff\n\015()] *                         #         normal*
+)*                                  #            )*
+\)                             #                )
+|
+"                                     # "
+[^\\\x80-\xff\n\015"] *                            #   normal
+(?:  \\ [^\x80-\xff]  [^\\\x80-\xff\n\015"] * )*        #   ( special normal* )*
+"                                     #        "
+) # "special" comment or quoted string
+[^()<>@,;:".\\\[\]\x80-\xff\000-\010\012-\037] *            #  more "normal"
+)*
+<
+[\040\t]*                    # Nab whitespace.
+(?:
+\(                              #  (
+[^\\\x80-\xff\n\015()] *                             #     normal*
+(?:                                 #       (
+(?:  \\ [^\x80-\xff]  |
+\(                            #  (
+[^\\\x80-\xff\n\015()] *                            #     normal*
+(?:  \\ [^\x80-\xff]   [^\\\x80-\xff\n\015()] * )*        #     (special normal*)*
+\)                           #                       )
+)    #         special
+[^\\\x80-\xff\n\015()] *                         #         normal*
+)*                                  #            )*
+\)                             #                )
+[\040\t]* )*    # If comment found, allow more spaces.
+# <
+(?:
+@
+[\040\t]*                    # Nab whitespace.
+(?:
+\(                              #  (
+[^\\\x80-\xff\n\015()] *                             #     normal*
+(?:                                 #       (
+(?:  \\ [^\x80-\xff]  |
+\(                            #  (
+[^\\\x80-\xff\n\015()] *                            #     normal*
+(?:  \\ [^\x80-\xff]   [^\\\x80-\xff\n\015()] * )*        #     (special normal*)*
+\)                           #                       )
+)    #         special
+[^\\\x80-\xff\n\015()] *                         #         normal*
+)*                                  #            )*
+\)                             #                )
+[\040\t]* )*    # If comment found, allow more spaces.
+(?:
+[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+    # some number of atom characters...
+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom
+|
+\[                            # [
+(?: [^\\\x80-\xff\n\015\[\]] |  \\ [^\x80-\xff]  )*     #    stuff
+\]                           #           ]
+)
+[\040\t]*                    # Nab whitespace.
+(?:
+\(                              #  (
+[^\\\x80-\xff\n\015()] *                             #     normal*
+(?:                                 #       (
+(?:  \\ [^\x80-\xff]  |
+\(                            #  (
+[^\\\x80-\xff\n\015()] *                            #     normal*
+(?:  \\ [^\x80-\xff]   [^\\\x80-\xff\n\015()] * )*        #     (special normal*)*
+\)                           #                       )
+)    #         special
+[^\\\x80-\xff\n\015()] *                         #         normal*
+)*                                  #            )*
+\)                             #                )
+[\040\t]* )*    # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\.
+[\040\t]*                    # Nab whitespace.
+(?:
+\(                              #  (
+[^\\\x80-\xff\n\015()] *                             #     normal*
+(?:                                 #       (
+(?:  \\ [^\x80-\xff]  |
+\(                            #  (
+[^\\\x80-\xff\n\015()] *                            #     normal*
+(?:  \\ [^\x80-\xff]   [^\\\x80-\xff\n\015()] * )*        #     (special normal*)*
+\)                           #                       )
+)    #         special
+[^\\\x80-\xff\n\015()] *                         #         normal*
+)*                                  #            )*
+\)                             #                )
+[\040\t]* )*    # If comment found, allow more spaces.
+(?:
+[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+    # some number of atom characters...
+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom
+|
+\[                            # [
+(?: [^\\\x80-\xff\n\015\[\]] |  \\ [^\x80-\xff]  )*     #    stuff
+\]                           #           ]
+)
+[\040\t]*                    # Nab whitespace.
+(?:
+\(                              #  (
+[^\\\x80-\xff\n\015()] *                             #     normal*
+(?:                                 #       (
+(?:  \\ [^\x80-\xff]  |
+\(                            #  (
+[^\\\x80-\xff\n\015()] *                            #     normal*
+(?:  \\ [^\x80-\xff]   [^\\\x80-\xff\n\015()] * )*        #     (special normal*)*
+\)                           #                       )
+)    #         special
+[^\\\x80-\xff\n\015()] *                         #         normal*
+)*                                  #            )*
+\)                             #                )
+[\040\t]* )*    # If comment found, allow more spaces.
+# optional trailing comments
+)*
+(?: ,
+[\040\t]*                    # Nab whitespace.
+(?:
+\(                              #  (
+[^\\\x80-\xff\n\015()] *                             #     normal*
+(?:                                 #       (
+(?:  \\ [^\x80-\xff]  |
+\(                            #  (
+[^\\\x80-\xff\n\015()] *                            #     normal*
+(?:  \\ [^\x80-\xff]   [^\\\x80-\xff\n\015()] * )*        #     (special normal*)*
+\)                           #                       )
+)    #         special
+[^\\\x80-\xff\n\015()] *                         #         normal*
+)*                                  #            )*
+\)                             #                )
+[\040\t]* )*    # If comment found, allow more spaces.
+@
+[\040\t]*                    # Nab whitespace.
+(?:
+\(                              #  (
+[^\\\x80-\xff\n\015()] *                             #     normal*
+(?:                                 #       (
+(?:  \\ [^\x80-\xff]  |
+\(                            #  (
+[^\\\x80-\xff\n\015()] *                            #     normal*
+(?:  \\ [^\x80-\xff]   [^\\\x80-\xff\n\015()] * )*        #     (special normal*)*
+\)                           #                       )
+)    #         special
+[^\\\x80-\xff\n\015()] *                         #         normal*
+)*                                  #            )*
+\)                             #                )
+[\040\t]* )*    # If comment found, allow more spaces.
+(?:
+[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+    # some number of atom characters...
+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom
+|
+\[                            # [
+(?: [^\\\x80-\xff\n\015\[\]] |  \\ [^\x80-\xff]  )*     #    stuff
+\]                           #           ]
+)
+[\040\t]*                    # Nab whitespace.
+(?:
+\(                              #  (
+[^\\\x80-\xff\n\015()] *                             #     normal*
+(?:                                 #       (
+(?:  \\ [^\x80-\xff]  |
+\(                            #  (
+[^\\\x80-\xff\n\015()] *                            #     normal*
+(?:  \\ [^\x80-\xff]   [^\\\x80-\xff\n\015()] * )*        #     (special normal*)*
+\)                           #                       )
+)    #         special
+[^\\\x80-\xff\n\015()] *                         #         normal*
+)*                                  #            )*
+\)                             #                )
+[\040\t]* )*    # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\.
+[\040\t]*                    # Nab whitespace.
+(?:
+\(                              #  (
+[^\\\x80-\xff\n\015()] *                             #     normal*
+(?:                                 #       (
+(?:  \\ [^\x80-\xff]  |
+\(                            #  (
+[^\\\x80-\xff\n\015()] *                            #     normal*
+(?:  \\ [^\x80-\xff]   [^\\\x80-\xff\n\015()] * )*        #     (special normal*)*
+\)                           #                       )
+)    #         special
+[^\\\x80-\xff\n\015()] *                         #         normal*
+)*                                  #            )*
+\)                             #                )
+[\040\t]* )*    # If comment found, allow more spaces.
+(?:
+[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+    # some number of atom characters...
+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom
+|
+\[                            # [
+(?: [^\\\x80-\xff\n\015\[\]] |  \\ [^\x80-\xff]  )*     #    stuff
+\]                           #           ]
+)
+[\040\t]*                    # Nab whitespace.
+(?:
+\(                              #  (
+[^\\\x80-\xff\n\015()] *                             #     normal*
+(?:                                 #       (
+(?:  \\ [^\x80-\xff]  |
+\(                            #  (
+[^\\\x80-\xff\n\015()] *                            #     normal*
+(?:  \\ [^\x80-\xff]   [^\\\x80-\xff\n\015()] * )*        #     (special normal*)*
+\)                           #                       )
+)    #         special
+[^\\\x80-\xff\n\015()] *                         #         normal*
+)*                                  #            )*
+\)                             #                )
+[\040\t]* )*    # If comment found, allow more spaces.
+# optional trailing comments
+)*
+)*  # additional domains
+:
+[\040\t]*                    # Nab whitespace.
+(?:
+\(                              #  (
+[^\\\x80-\xff\n\015()] *                             #     normal*
+(?:                                 #       (
+(?:  \\ [^\x80-\xff]  |
+\(                            #  (
+[^\\\x80-\xff\n\015()] *                            #     normal*
+(?:  \\ [^\x80-\xff]   [^\\\x80-\xff\n\015()] * )*        #     (special normal*)*
+\)                           #                       )
+)    #         special
+[^\\\x80-\xff\n\015()] *                         #         normal*
+)*                                  #            )*
+\)                             #                )
+[\040\t]* )*    # If comment found, allow more spaces.
+# optional trailing comments
+)?     #       optional route
+(?:
+[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+    # some number of atom characters...
+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom
+# Atom
+|                       #  or
+"                                     # "
+[^\\\x80-\xff\n\015"] *                            #   normal
+(?:  \\ [^\x80-\xff]  [^\\\x80-\xff\n\015"] * )*        #   ( special normal* )*
+"                                     #        "
+# Quoted string
+)
+[\040\t]*                    # Nab whitespace.
+(?:
+\(                              #  (
+[^\\\x80-\xff\n\015()] *                             #     normal*
+(?:                                 #       (
+(?:  \\ [^\x80-\xff]  |
+\(                            #  (
+[^\\\x80-\xff\n\015()] *                            #     normal*
+(?:  \\ [^\x80-\xff]   [^\\\x80-\xff\n\015()] * )*        #     (special normal*)*
+\)                           #                       )
+)    #         special
+[^\\\x80-\xff\n\015()] *                         #         normal*
+)*                                  #            )*
+\)                             #                )
+[\040\t]* )*    # If comment found, allow more spaces.
+(?:
+\.
+[\040\t]*                    # Nab whitespace.
+(?:
+\(                              #  (
+[^\\\x80-\xff\n\015()] *                             #     normal*
+(?:                                 #       (
+(?:  \\ [^\x80-\xff]  |
+\(                            #  (
+[^\\\x80-\xff\n\015()] *                            #     normal*
+(?:  \\ [^\x80-\xff]   [^\\\x80-\xff\n\015()] * )*        #     (special normal*)*
+\)                           #                       )
+)    #         special
+[^\\\x80-\xff\n\015()] *                         #         normal*
+)*                                  #            )*
+\)                             #                )
+[\040\t]* )*    # If comment found, allow more spaces.
+(?:
+[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+    # some number of atom characters...
+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom
+# Atom
+|                       #  or
+"                                     # "
+[^\\\x80-\xff\n\015"] *                            #   normal
+(?:  \\ [^\x80-\xff]  [^\\\x80-\xff\n\015"] * )*        #   ( special normal* )*
+"                                     #        "
+# Quoted string
+)
+[\040\t]*                    # Nab whitespace.
+(?:
+\(                              #  (
+[^\\\x80-\xff\n\015()] *                             #     normal*
+(?:                                 #       (
+(?:  \\ [^\x80-\xff]  |
+\(                            #  (
+[^\\\x80-\xff\n\015()] *                            #     normal*
+(?:  \\ [^\x80-\xff]   [^\\\x80-\xff\n\015()] * )*        #     (special normal*)*
+\)                           #                       )
+)    #         special
+[^\\\x80-\xff\n\015()] *                         #         normal*
+)*                                  #            )*
+\)                             #                )
+[\040\t]* )*    # If comment found, allow more spaces.
+# additional words
+)*
+@
+[\040\t]*                    # Nab whitespace.
+(?:
+\(                              #  (
+[^\\\x80-\xff\n\015()] *                             #     normal*
+(?:                                 #       (
+(?:  \\ [^\x80-\xff]  |
+\(                            #  (
+[^\\\x80-\xff\n\015()] *                            #     normal*
+(?:  \\ [^\x80-\xff]   [^\\\x80-\xff\n\015()] * )*        #     (special normal*)*
+\)                           #                       )
+)    #         special
+[^\\\x80-\xff\n\015()] *                         #         normal*
+)*                                  #            )*
+\)                             #                )
+[\040\t]* )*    # If comment found, allow more spaces.
+(?:
+[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+    # some number of atom characters...
+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom
+|
+\[                            # [
+(?: [^\\\x80-\xff\n\015\[\]] |  \\ [^\x80-\xff]  )*     #    stuff
+\]                           #           ]
+)
+[\040\t]*                    # Nab whitespace.
+(?:
+\(                              #  (
+[^\\\x80-\xff\n\015()] *                             #     normal*
+(?:                                 #       (
+(?:  \\ [^\x80-\xff]  |
+\(                            #  (
+[^\\\x80-\xff\n\015()] *                            #     normal*
+(?:  \\ [^\x80-\xff]   [^\\\x80-\xff\n\015()] * )*        #     (special normal*)*
+\)                           #                       )
+)    #         special
+[^\\\x80-\xff\n\015()] *                         #         normal*
+)*                                  #            )*
+\)                             #                )
+[\040\t]* )*    # If comment found, allow more spaces.
+# optional trailing comments
+(?:
+\.
+[\040\t]*                    # Nab whitespace.
+(?:
+\(                              #  (
+[^\\\x80-\xff\n\015()] *                             #     normal*
+(?:                                 #       (
+(?:  \\ [^\x80-\xff]  |
+\(                            #  (
+[^\\\x80-\xff\n\015()] *                            #     normal*
+(?:  \\ [^\x80-\xff]   [^\\\x80-\xff\n\015()] * )*        #     (special normal*)*
+\)                           #                       )
+)    #         special
+[^\\\x80-\xff\n\015()] *                         #         normal*
+)*                                  #            )*
+\)                             #                )
+[\040\t]* )*    # If comment found, allow more spaces.
+(?:
+[^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]+    # some number of atom characters...
+(?![^(\040)<>@,;:".\\\[\]\000-\037\x80-\xff]) # ..not followed by something that could be part of an atom
+|
+\[                            # [
+(?: [^\\\x80-\xff\n\015\[\]] |  \\ [^\x80-\xff]  )*     #    stuff
+\]                           #           ]
+)
+[\040\t]*                    # Nab whitespace.
+(?:
+\(                              #  (
+[^\\\x80-\xff\n\015()] *                             #     normal*
+(?:                                 #       (
+(?:  \\ [^\x80-\xff]  |
+\(                            #  (
+[^\\\x80-\xff\n\015()] *                            #     normal*
+(?:  \\ [^\x80-\xff]   [^\\\x80-\xff\n\015()] * )*        #     (special normal*)*
+\)                           #                       )
+)    #         special
+[^\\\x80-\xff\n\015()] *                         #         normal*
+)*                                  #            )*
+\)                             #                )
+[\040\t]* )*    # If comment found, allow more spaces.
+# optional trailing comments
+)*
+#       address spec
+>                    #                 >
+# name and address
+)
+/x
+    Alan Other <user\@dom.ain>
+ 0: Alan Other <user at dom.ain>
+    <user\@dom.ain>
+ 0: user at dom.ain
+    user\@dom.ain
+ 0: user at dom.ain
+    \"A. Other\" <user.1234\@dom.ain> (a comment)
+ 0: "A. Other" <user.1234 at dom.ain>
+    A. Other <user.1234\@dom.ain> (a comment)
+ 0:  Other <user.1234 at dom.ain>
+    \"/s=user/ou=host/o=place/prmd=uu.yy/admd= /c=gb/\"\@x400-re.lay
+ 0: "/s=user/ou=host/o=place/prmd=uu.yy/admd= /c=gb/"@x400-re.lay
+    A missing angle <user\@some.where
+ 0: user at some.where
+    *** Failers
+No match
+    The quick brown fox
+No match
+
+/abc\0def\00pqr\000xyz\0000AB/
+    abc\0def\00pqr\000xyz\0000AB
+ 0: abc\x00def\x00pqr\x00xyz\x000AB
+    abc456 abc\0def\00pqr\000xyz\0000ABCDE
+ 0: abc\x00def\x00pqr\x00xyz\x000AB
+
+/abc\x0def\x00pqr\x000xyz\x0000AB/
+    abc\x0def\x00pqr\x000xyz\x0000AB
+ 0: abc\x0def\x00pqr\x000xyz\x0000AB
+    abc456 abc\x0def\x00pqr\x000xyz\x0000ABCDE
+ 0: abc\x0def\x00pqr\x000xyz\x0000AB
+
+/^[\000-\037]/
+    \0A
+ 0: \x00
+    \01B
+ 0: \x01
+    \037C
+ 0: \x1f
+
+/\0*/
+    \0\0\0\0
+ 0: \x00\x00\x00\x00
+
+/A\x0{2,3}Z/
+    The A\x0\x0Z
+ 0: A\x00\x00Z
+    An A\0\x0\0Z
+ 0: A\x00\x00\x00Z
+    *** Failers
+No match
+    A\0Z
+No match
+    A\0\x0\0\x0Z
+No match
+
+/^(cow|)\1(bell)/
+    cowcowbell
+ 0: cowcowbell
+ 1: cow
+ 2: bell
+    bell
+ 0: bell
+ 1: 
+ 2: bell
+    *** Failers
+No match
+    cowbell
+No match
+
+/^\s/
+    \040abc
+ 0:  
+    \x0cabc
+ 0: \x0c
+    \nabc
+ 0: \x0a
+    \rabc
+ 0: \x0d
+    \tabc
+ 0: \x09
+    *** Failers
+No match
+    abc
+No match
+
+/^a	b
+  
+    c/x
+    abc
+ 0: abc
+
+/^(a|)\1*b/
+    ab
+ 0: ab
+ 1: a
+    aaaab
+ 0: aaaab
+ 1: a
+    b
+ 0: b
+ 1: 
+    *** Failers
+No match
+    acb
+No match
+
+/^(a|)\1+b/
+    aab
+ 0: aab
+ 1: a
+    aaaab
+ 0: aaaab
+ 1: a
+    b
+ 0: b
+ 1: 
+    *** Failers
+No match
+    ab
+No match
+
+/^(a|)\1?b/
+    ab
+ 0: ab
+ 1: a
+    aab
+ 0: aab
+ 1: a
+    b
+ 0: b
+ 1: 
+    *** Failers
+No match
+    acb
+No match
+
+/^(a|)\1{2}b/
+    aaab
+ 0: aaab
+ 1: a
+    b
+ 0: b
+ 1: 
+    *** Failers
+No match
+    ab
+No match
+    aab
+No match
+    aaaab
+No match
+
+/^(a|)\1{2,3}b/
+    aaab
+ 0: aaab
+ 1: a
+    aaaab
+ 0: aaaab
+ 1: a
+    b
+ 0: b
+ 1: 
+    *** Failers
+No match
+    ab
+No match
+    aab
+No match
+    aaaaab
+No match
+
+/ab{1,3}bc/
+    abbbbc
+ 0: abbbbc
+    abbbc
+ 0: abbbc
+    abbc
+ 0: abbc
+    *** Failers
+No match
+    abc
+No match
+    abbbbbc
+No match
+
+/([^.]*)\.([^:]*):[T ]+(.*)/
+    track1.title:TBlah blah blah
+ 0: track1.title:TBlah blah blah
+ 1: track1
+ 2: title
+ 3: Blah blah blah
+
+/([^.]*)\.([^:]*):[T ]+(.*)/i
+    track1.title:TBlah blah blah
+ 0: track1.title:TBlah blah blah
+ 1: track1
+ 2: title
+ 3: Blah blah blah
+
+/([^.]*)\.([^:]*):[t ]+(.*)/i
+    track1.title:TBlah blah blah
+ 0: track1.title:TBlah blah blah
+ 1: track1
+ 2: title
+ 3: Blah blah blah
+
+/^[W-c]+$/
+    WXY_^abc
+ 0: WXY_^abc
+    *** Failers
+No match
+    wxy
+No match
+
+/^[W-c]+$/i
+    WXY_^abc
+ 0: WXY_^abc
+    wxy_^ABC
+ 0: wxy_^ABC
+
+/^[\x3f-\x5F]+$/i
+    WXY_^abc
+ 0: WXY_^abc
+    wxy_^ABC
+ 0: wxy_^ABC
+
+/^abc$/m
+    abc
+ 0: abc
+    qqq\nabc
+ 0: abc
+    abc\nzzz
+ 0: abc
+    qqq\nabc\nzzz
+ 0: abc
+
+/^abc$/
+    abc
+ 0: abc
+    *** Failers
+No match
+    qqq\nabc
+No match
+    abc\nzzz
+No match
+    qqq\nabc\nzzz
+No match
+
+/\Aabc\Z/m
+    abc
+ 0: abc
+    abc\n 
+ 0: abc
+    *** Failers
+No match
+    qqq\nabc
+No match
+    abc\nzzz
+No match
+    qqq\nabc\nzzz
+No match
+    
+/\A(.)*\Z/s
+    abc\ndef
+ 0: abc\x0adef
+ 1: f
+
+/\A(.)*\Z/m
+    *** Failers
+ 0: *** Failers
+ 1: s
+    abc\ndef
+No match
+
+/(?:b)|(?::+)/
+    b::c
+ 0: b
+    c::b
+ 0: ::
+
+/[-az]+/
+    az-
+ 0: az-
+    *** Failers
+ 0: a
+    b
+No match
+
+/[az-]+/
+    za-
+ 0: za-
+    *** Failers
+ 0: a
+    b
+No match
+
+/[a\-z]+/
+    a-z
+ 0: a-z
+    *** Failers
+ 0: a
+    b
+No match
+
+/[a-z]+/
+    abcdxyz
+ 0: abcdxyz
+
+/[\d-]+/
+    12-34
+ 0: 12-34
+    *** Failers
+No match
+    aaa
+No match
+
+/[\d-z]+/
+    12-34z
+ 0: 12-34z
+    *** Failers
+No match
+    aaa
+No match
+
+/\x5c/
+    \\
+ 0: \
+
+/\x20Z/
+    the Zoo
+ 0:  Z
+    *** Failers
+No match
+    Zulu
+No match
+
+/(abc)\1/i
+    abcabc
+ 0: abcabc
+ 1: abc
+    ABCabc
+ 0: ABCabc
+ 1: ABC
+    abcABC
+ 0: abcABC
+ 1: abc
+
+/ab{3cd/
+    ab{3cd
+ 0: ab{3cd
+
+/ab{3,cd/
+    ab{3,cd
+ 0: ab{3,cd
+
+/ab{3,4a}cd/
+    ab{3,4a}cd
+ 0: ab{3,4a}cd
+
+/{4,5a}bc/
+    {4,5a}bc
+ 0: {4,5a}bc
+
+/^a.b/
+    a\rb
+ 0: a\x0db
+    *** Failers
+No match
+    a\nb
+No match
+
+/abc$/
+    abc
+ 0: abc
+    abc\n
+ 0: abc
+    *** Failers
+No match
+    abc\ndef
+No match
+
+/(abc)\123/
+    abc\x53
+ 0: abcS
+ 1: abc
+
+/(abc)\223/
+    abc\x93
+ 0: abc\x93
+ 1: abc
+
+/(abc)\323/
+    abc\xd3
+ 0: abc\xd3
+ 1: abc
+
+/(abc)\500/
+    abc\x40
+ 0: abc@
+ 1: abc
+    abc\100
+ 0: abc@
+ 1: abc
+
+/(abc)\5000/
+    abc\x400
+ 0: abc at 0
+ 1: abc
+    abc\x40\x30
+ 0: abc at 0
+ 1: abc
+    abc\1000
+ 0: abc at 0
+ 1: abc
+    abc\100\x30
+ 0: abc at 0
+ 1: abc
+    abc\100\060
+ 0: abc at 0
+ 1: abc
+    abc\100\60
+ 0: abc at 0
+ 1: abc
+
+/abc\81/
+    abc\081
+ 0: abc\x0081
+    abc\0\x38\x31
+ 0: abc\x0081
+
+/abc\91/
+    abc\091
+ 0: abc\x0091
+    abc\0\x39\x31
+ 0: abc\x0091
+
+/(a)(b)(c)(d)(e)(f)(g)(h)(i)(j)(k)(l)\12\123/
+    abcdefghijkllS
+ 0: abcdefghijkllS
+ 1: a
+ 2: b
+ 3: c
+ 4: d
+ 5: e
+ 6: f
+ 7: g
+ 8: h
+ 9: i
+10: j
+11: k
+12: l
+
+/(a)(b)(c)(d)(e)(f)(g)(h)(i)(j)(k)\12\123/
+    abcdefghijk\12S
+ 0: abcdefghijk\x0aS
+ 1: a
+ 2: b
+ 3: c
+ 4: d
+ 5: e
+ 6: f
+ 7: g
+ 8: h
+ 9: i
+10: j
+11: k
+
+/ab\gdef/
+    abgdef
+ 0: abgdef
+
+/a{0}bc/
+    bc
+ 0: bc
+
+/(a|(bc)){0,0}?xyz/
+    xyz
+ 0: xyz
+
+/abc[\10]de/
+    abc\010de
+ 0: abc\x08de
+
+/abc[\1]de/
+    abc\1de
+ 0: abc\x01de
+
+/(abc)[\1]de/
+    abc\1de
+ 0: abc\x01de
+ 1: abc
+
+/(?s)a.b/
+    a\nb
+ 0: a\x0ab
+
+/^([^a])([^\b])([^c]*)([^d]{3,4})/
+    baNOTccccd
+ 0: baNOTcccc
+ 1: b
+ 2: a
+ 3: NOT
+ 4: cccc
+    baNOTcccd
+ 0: baNOTccc
+ 1: b
+ 2: a
+ 3: NOT
+ 4: ccc
+    baNOTccd
+ 0: baNOTcc
+ 1: b
+ 2: a
+ 3: NO
+ 4: Tcc
+    bacccd
+ 0: baccc
+ 1: b
+ 2: a
+ 3: 
+ 4: ccc
+    *** Failers
+ 0: *** Failers
+ 1: *
+ 2: *
+ 3: * Fail
+ 4: ers
+    anything
+No match
+    b\bc   
+No match
+    baccd
+No match
+
+/[^a]/
+    Abc
+ 0: A
+  
+/[^a]/i
+    Abc 
+ 0: b
+
+/[^a]+/
+    AAAaAbc
+ 0: AAA
+  
+/[^a]+/i
+    AAAaAbc 
+ 0: bc
+
+/[^a]+/
+    bbb\nccc
+ 0: bbb\x0accc
+   
+/[^k]$/
+    abc
+ 0: c
+    *** Failers
+ 0: s
+    abk   
+No match
+   
+/[^k]{2,3}$/
+    abc
+ 0: abc
+    kbc
+ 0: bc
+    kabc 
+ 0: abc
+    *** Failers
+ 0: ers
+    abk
+No match
+    akb
+No match
+    akk 
+No match
+
+/^\d{8,}\@.+[^k]$/
+    12345678\@a.b.c.d
+ 0: 12345678 at a.b.c.d
+    123456789\@x.y.z
+ 0: 123456789 at x.y.z
+    *** Failers
+No match
+    12345678\@x.y.uk
+No match
+    1234567\@a.b.c.d       
+No match
+
+/(a)\1{8,}/
+    aaaaaaaaa
+ 0: aaaaaaaaa
+ 1: a
+    aaaaaaaaaa
+ 0: aaaaaaaaaa
+ 1: a
+    *** Failers
+No match
+    aaaaaaa   
+No match
+
+/[^a]/
+    aaaabcd
+ 0: b
+    aaAabcd 
+ 0: A
+
+/[^a]/i
+    aaaabcd
+ 0: b
+    aaAabcd 
+ 0: b
+
+/[^az]/
+    aaaabcd
+ 0: b
+    aaAabcd 
+ 0: A
+
+/[^az]/i
+    aaaabcd
+ 0: b
+    aaAabcd 
+ 0: b
+
+/\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327\330\331\332\333\334\335\336\337\340\341\342\343\344\345\346\347\350\351\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373\374\375\376\377/
+ \000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327\330\331\332\333\334\335\336\337\340\341\342\343\344\345\346\347\350\351\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373\374\375\376\377
+ 0: \x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~\x7f\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff
+
+/P[^*]TAIRE[^*]{1,6}?LL/
+    xxxxxxxxxxxPSTAIREISLLxxxxxxxxx
+ 0: PSTAIREISLL
+
+/P[^*]TAIRE[^*]{1,}?LL/
+    xxxxxxxxxxxPSTAIREISLLxxxxxxxxx
+ 0: PSTAIREISLL
+
+/(\.\d\d[1-9]?)\d+/
+    1.230003938
+ 0: .230003938
+ 1: .23
+    1.875000282   
+ 0: .875000282
+ 1: .875
+    1.235  
+ 0: .235
+ 1: .23
+                  
+/(\.\d\d((?=0)|\d(?=\d)))/
+    1.230003938      
+ 0: .23
+ 1: .23
+ 2: 
+    1.875000282
+ 0: .875
+ 1: .875
+ 2: 5
+    *** Failers 
+No match
+    1.235 
+No match
+    
+/a(?)b/
+    ab 
+ 0: ab
+ 
+/\b(foo)\s+(\w+)/i
+    Food is on the foo table
+ 0: foo table
+ 1: foo
+ 2: table
+    
+/foo(.*)bar/
+    The food is under the bar in the barn.
+ 0: food is under the bar in the bar
+ 1: d is under the bar in the 
+    
+/foo(.*?)bar/  
+    The food is under the bar in the barn.
+ 0: food is under the bar
+ 1: d is under the 
+
+/(.*)(\d*)/
+    I have 2 numbers: 53147
+ 0: I have 2 numbers: 53147
+ 1: I have 2 numbers: 53147
+ 2: 
+    
+/(.*)(\d+)/
+    I have 2 numbers: 53147
+ 0: I have 2 numbers: 53147
+ 1: I have 2 numbers: 5314
+ 2: 7
+ 
+/(.*?)(\d*)/
+    I have 2 numbers: 53147
+ 0: 
+ 1: 
+ 2: 
+
+/(.*?)(\d+)/
+    I have 2 numbers: 53147
+ 0: I have 2
+ 1: I have 
+ 2: 2
+
+/(.*)(\d+)$/
+    I have 2 numbers: 53147
+ 0: I have 2 numbers: 53147
+ 1: I have 2 numbers: 5314
+ 2: 7
+
+/(.*?)(\d+)$/
+    I have 2 numbers: 53147
+ 0: I have 2 numbers: 53147
+ 1: I have 2 numbers: 
+ 2: 53147
+
+/(.*)\b(\d+)$/
+    I have 2 numbers: 53147
+ 0: I have 2 numbers: 53147
+ 1: I have 2 numbers: 
+ 2: 53147
+
+/(.*\D)(\d+)$/
+    I have 2 numbers: 53147
+ 0: I have 2 numbers: 53147
+ 1: I have 2 numbers: 
+ 2: 53147
+
+/^\D*(?!123)/
+    ABC123
+ 0: AB
+     
+/^(\D*)(?=\d)(?!123)/
+    ABC445
+ 0: ABC
+ 1: ABC
+    *** Failers
+No match
+    ABC123
+No match
+    
+/^[W-]46]/
+    W46]789 
+ 0: W46]
+    -46]789
+ 0: -46]
+    *** Failers
+No match
+    Wall
+No match
+    Zebra
+No match
+    42
+No match
+    [abcd] 
+No match
+    ]abcd[
+No match
+       
+/^[W-\]46]/
+    W46]789 
+ 0: W
+    Wall
+ 0: W
+    Zebra
+ 0: Z
+    Xylophone  
+ 0: X
+    42
+ 0: 4
+    [abcd] 
+ 0: [
+    ]abcd[
+ 0: ]
+    \\backslash 
+ 0: \
+    *** Failers
+No match
+    -46]789
+No match
+    well
+No match
+    
+/\d\d\/\d\d\/\d\d\d\d/
+    01/01/2000
+ 0: 01/01/2000
+
+/word (?:[a-zA-Z0-9]+ ){0,10}otherword/
+  word cat dog elephant mussel cow horse canary baboon snake shark otherword
+ 0: word cat dog elephant mussel cow horse canary baboon snake shark otherword
+  word cat dog elephant mussel cow horse canary baboon snake shark
+No match
+
+/word (?:[a-zA-Z0-9]+ ){0,300}otherword/
+  word cat dog elephant mussel cow horse canary baboon snake shark the quick brown fox and the lazy dog and several other words getting close to thirty by now I hope
+No match
+
+/^(a){0,0}/
+    bcd
+ 0: 
+    abc
+ 0: 
+    aab     
+ 0: 
+
+/^(a){0,1}/
+    bcd
+ 0: 
+    abc
+ 0: a
+ 1: a
+    aab  
+ 0: a
+ 1: a
+
+/^(a){0,2}/
+    bcd
+ 0: 
+    abc
+ 0: a
+ 1: a
+    aab  
+ 0: aa
+ 1: a
+
+/^(a){0,3}/
+    bcd
+ 0: 
+    abc
+ 0: a
+ 1: a
+    aab
+ 0: aa
+ 1: a
+    aaa   
+ 0: aaa
+ 1: a
+
+/^(a){0,}/
+    bcd
+ 0: 
+    abc
+ 0: a
+ 1: a
+    aab
+ 0: aa
+ 1: a
+    aaa
+ 0: aaa
+ 1: a
+    aaaaaaaa    
+ 0: aaaaaaaa
+ 1: a
+
+/^(a){1,1}/
+    bcd
+No match
+    abc
+ 0: a
+ 1: a
+    aab  
+ 0: a
+ 1: a
+
+/^(a){1,2}/
+    bcd
+No match
+    abc
+ 0: a
+ 1: a
+    aab  
+ 0: aa
+ 1: a
+
+/^(a){1,3}/
+    bcd
+No match
+    abc
+ 0: a
+ 1: a
+    aab
+ 0: aa
+ 1: a
+    aaa   
+ 0: aaa
+ 1: a
+
+/^(a){1,}/
+    bcd
+No match
+    abc
+ 0: a
+ 1: a
+    aab
+ 0: aa
+ 1: a
+    aaa
+ 0: aaa
+ 1: a
+    aaaaaaaa    
+ 0: aaaaaaaa
+ 1: a
+
+/.*\.gif/
+    borfle\nbib.gif\nno
+ 0: bib.gif
+
+/.{0,}\.gif/
+    borfle\nbib.gif\nno
+ 0: bib.gif
+
+/.*\.gif/m
+    borfle\nbib.gif\nno
+ 0: bib.gif
+
+/.*\.gif/s
+    borfle\nbib.gif\nno
+ 0: borfle\x0abib.gif
+
+/.*\.gif/ms
+    borfle\nbib.gif\nno
+ 0: borfle\x0abib.gif
+    
+/.*$/
+    borfle\nbib.gif\nno
+ 0: no
+
+/.*$/m
+    borfle\nbib.gif\nno
+ 0: borfle
+
+/.*$/s
+    borfle\nbib.gif\nno
+ 0: borfle\x0abib.gif\x0ano
+
+/.*$/ms
+    borfle\nbib.gif\nno
+ 0: borfle\x0abib.gif\x0ano
+    
+/.*$/
+    borfle\nbib.gif\nno\n
+ 0: no
+
+/.*$/m
+    borfle\nbib.gif\nno\n
+ 0: borfle
+
+/.*$/s
+    borfle\nbib.gif\nno\n
+ 0: borfle\x0abib.gif\x0ano\x0a
+
+/.*$/ms
+    borfle\nbib.gif\nno\n
+ 0: borfle\x0abib.gif\x0ano\x0a
+    
+/(.*X|^B)/
+    abcde\n1234Xyz
+ 0: 1234X
+ 1: 1234X
+    BarFoo 
+ 0: B
+ 1: B
+    *** Failers
+No match
+    abcde\nBar  
+No match
+
+/(.*X|^B)/m
+    abcde\n1234Xyz
+ 0: 1234X
+ 1: 1234X
+    BarFoo 
+ 0: B
+ 1: B
+    abcde\nBar  
+ 0: B
+ 1: B
+
+/(.*X|^B)/s
+    abcde\n1234Xyz
+ 0: abcde\x0a1234X
+ 1: abcde\x0a1234X
+    BarFoo 
+ 0: B
+ 1: B
+    *** Failers
+No match
+    abcde\nBar  
+No match
+
+/(.*X|^B)/ms
+    abcde\n1234Xyz
+ 0: abcde\x0a1234X
+ 1: abcde\x0a1234X
+    BarFoo 
+ 0: B
+ 1: B
+    abcde\nBar  
+ 0: B
+ 1: B
+
+/(?s)(.*X|^B)/
+    abcde\n1234Xyz
+ 0: abcde\x0a1234X
+ 1: abcde\x0a1234X
+    BarFoo 
+ 0: B
+ 1: B
+    *** Failers 
+No match
+    abcde\nBar  
+No match
+
+/(?s:.*X|^B)/
+    abcde\n1234Xyz
+ 0: abcde\x0a1234X
+    BarFoo 
+ 0: B
+    *** Failers 
+No match
+    abcde\nBar  
+No match
+
+/^.*B/
+    **** Failers
+No match
+    abc\nB
+No match
+     
+/(?s)^.*B/
+    abc\nB
+ 0: abc\x0aB
+
+/(?m)^.*B/
+    abc\nB
+ 0: B
+     
+/(?ms)^.*B/
+    abc\nB
+ 0: abc\x0aB
+
+/(?ms)^B/
+    abc\nB
+ 0: B
+
+/(?s)B$/
+    B\n
+ 0: B
+
+/^[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]/
+    123456654321
+ 0: 123456654321
+  
+/^\d\d\d\d\d\d\d\d\d\d\d\d/
+    123456654321 
+ 0: 123456654321
+
+/^[\d][\d][\d][\d][\d][\d][\d][\d][\d][\d][\d][\d]/
+    123456654321
+ 0: 123456654321
+  
+/^[abc]{12}/
+    abcabcabcabc
+ 0: abcabcabcabc
+    
+/^[a-c]{12}/
+    abcabcabcabc
+ 0: abcabcabcabc
+    
+/^(a|b|c){12}/
+    abcabcabcabc 
+ 0: abcabcabcabc
+ 1: c
+
+/^[abcdefghijklmnopqrstuvwxy0123456789]/
+    n
+ 0: n
+    *** Failers 
+No match
+    z 
+No match
+
+/abcde{0,0}/
+    abcd
+ 0: abcd
+    *** Failers
+No match
+    abce  
+No match
+
+/ab[cd]{0,0}e/
+    abe
+ 0: abe
+    *** Failers
+No match
+    abcde 
+No match
+    
+/ab(c){0,0}d/
+    abd
+ 0: abd
+    *** Failers
+No match
+    abcd   
+No match
+
+/a(b*)/
+    a
+ 0: a
+ 1: 
+    ab
+ 0: ab
+ 1: b
+    abbbb
+ 0: abbbb
+ 1: bbbb
+    *** Failers
+ 0: a
+ 1: 
+    bbbbb    
+No match
+    
+/ab\d{0}e/
+    abe
+ 0: abe
+    *** Failers
+No match
+    ab1e   
+No match
+    
+/"([^\\"]+|\\.)*"/
+    the \"quick\" brown fox
+ 0: "quick"
+ 1: quick
+    \"the \\\"quick\\\" brown fox\" 
+ 0: "the \"quick\" brown fox"
+ 1:  brown fox
+
+/.*?/g+
+    abc
+ 0: 
+ 0+ abc
+ 0: a
+ 0+ bc
+ 0: 
+ 0+ bc
+ 0: b
+ 0+ c
+ 0: 
+ 0+ c
+ 0: c
+ 0+ 
+ 0: 
+ 0+ 
+  
+/\b/g+
+    abc 
+ 0: 
+ 0+ abc
+ 0: 
+ 0+ 
+
+/\b/+g
+    abc 
+ 0: 
+ 0+ abc
+ 0: 
+ 0+ 
+
+//g
+    abc
+ 0: 
+ 0: 
+ 0: 
+ 0: 
+
+/<tr([\w\W\s\d][^<>]{0,})><TD([\w\W\s\d][^<>]{0,})>([\d]{0,}\.)(.*)((<BR>([\w\W\s\d][^<>]{0,})|[\s]{0,}))<\/a><\/TD><TD([\w\W\s\d][^<>]{0,})>([\w\W\s\d][^<>]{0,})<\/TD><TD([\w\W\s\d][^<>]{0,})>([\w\W\s\d][^<>]{0,})<\/TD><\/TR>/is
+  <TR BGCOLOR='#DBE9E9'><TD align=left valign=top>43.<a href='joblist.cfm?JobID=94 6735&Keyword='>Word Processor<BR>(N-1286)</a></TD><TD align=left valign=top>Lega lstaff.com</TD><TD align=left valign=top>CA - Statewide</TD></TR>
+ 0: <TR BGCOLOR='#DBE9E9'><TD align=left valign=top>43.<a href='joblist.cfm?JobID=94 6735&Keyword='>Word Processor<BR>(N-1286)</a></TD><TD align=left valign=top>Lega lstaff.com</TD><TD align=left valign=top>CA - Statewide</TD></TR>
+ 1:  BGCOLOR='#DBE9E9'
+ 2:  align=left valign=top
+ 3: 43.
+ 4: <a href='joblist.cfm?JobID=94 6735&Keyword='>Word Processor<BR>(N-1286)
+ 5: 
+ 6: 
+ 7: <unset>
+ 8:  align=left valign=top
+ 9: Lega lstaff.com
+10:  align=left valign=top
+11: CA - Statewide
+
+/a[^a]b/
+    acb
+ 0: acb
+    a\nb
+ 0: a\x0ab
+    
+/a.b/
+    acb
+ 0: acb
+    *** Failers 
+No match
+    a\nb   
+No match
+    
+/a[^a]b/s
+    acb
+ 0: acb
+    a\nb  
+ 0: a\x0ab
+    
+/a.b/s
+    acb
+ 0: acb
+    a\nb  
+ 0: a\x0ab
+
+/^(b+?|a){1,2}?c/
+    bac
+ 0: bac
+ 1: a
+    bbac
+ 0: bbac
+ 1: a
+    bbbac
+ 0: bbbac
+ 1: a
+    bbbbac
+ 0: bbbbac
+ 1: a
+    bbbbbac 
+ 0: bbbbbac
+ 1: a
+
+/^(b+|a){1,2}?c/
+    bac
+ 0: bac
+ 1: a
+    bbac
+ 0: bbac
+ 1: a
+    bbbac
+ 0: bbbac
+ 1: a
+    bbbbac
+ 0: bbbbac
+ 1: a
+    bbbbbac 
+ 0: bbbbbac
+ 1: a
+    
+/(?!\A)x/m
+    x\nb\n
+No match
+    a\bx\n  
+ 0: x
+    
+/\x0{ab}/
+    \0{ab} 
+ 0: \x00{ab}
+
+/(A|B)*?CD/
+    CD 
+ 0: CD
+    
+/(A|B)*CD/
+    CD 
+ 0: CD
+
+/(AB)*?\1/
+    ABABAB
+ 0: ABAB
+ 1: AB
+
+/(AB)*\1/
+    ABABAB
+ 0: ABABAB
+ 1: AB
+    
+/(?<!bar)foo/
+    foo
+ 0: foo
+    catfood
+ 0: foo
+    arfootle
+ 0: foo
+    rfoosh
+ 0: foo
+    *** Failers
+No match
+    barfoo
+No match
+    towbarfoo
+No match
+
+/\w{3}(?<!bar)foo/
+    catfood
+ 0: catfoo
+    *** Failers
+No match
+    foo
+No match
+    barfoo
+No match
+    towbarfoo
+No match
+
+/(?<=(foo)a)bar/
+    fooabar
+ 0: bar
+ 1: foo
+    *** Failers
+No match
+    bar
+No match
+    foobbar
+No match
+      
+/\Aabc\z/m
+    abc
+ 0: abc
+    *** Failers
+No match
+    abc\n   
+No match
+    qqq\nabc
+No match
+    abc\nzzz
+No match
+    qqq\nabc\nzzz
+No match
+
+"(?>.*/)foo"
+    /this/is/a/very/long/line/in/deed/with/very/many/slashes/in/it/you/see/
+No match
+
+"(?>.*/)foo"
+    /this/is/a/very/long/line/in/deed/with/very/many/slashes/in/and/foo
+ 0: /this/is/a/very/long/line/in/deed/with/very/many/slashes/in/and/foo
+
+/(?>(\.\d\d[1-9]?))\d+/
+    1.230003938
+ 0: .230003938
+ 1: .23
+    1.875000282
+ 0: .875000282
+ 1: .875
+    *** Failers 
+No match
+    1.235 
+No match
+
+/^((?>\w+)|(?>\s+))*$/
+    now is the time for all good men to come to the aid of the party
+ 0: now is the time for all good men to come to the aid of the party
+ 1: party
+    *** Failers
+No match
+    this is not a line with only words and spaces!
+No match
+    
+/(\d+)(\w)/
+    12345a
+ 0: 12345a
+ 1: 12345
+ 2: a
+    12345+ 
+ 0: 12345
+ 1: 1234
+ 2: 5
+
+/((?>\d+))(\w)/
+    12345a
+ 0: 12345a
+ 1: 12345
+ 2: a
+    *** Failers
+No match
+    12345+ 
+No match
+
+/(?>a+)b/
+    aaab
+ 0: aaab
+
+/((?>a+)b)/
+    aaab
+ 0: aaab
+ 1: aaab
+
+/(?>(a+))b/
+    aaab
+ 0: aaab
+ 1: aaa
+
+/(?>b)+/
+    aaabbbccc
+ 0: bbb
+
+/(?>a+|b+|c+)*c/
+    aaabbbbccccd
+ 0: aaabbbbc
+
+/((?>[^()]+)|\([^()]*\))+/
+    ((abc(ade)ufh()()x
+ 0: abc(ade)ufh()()x
+ 1: x
+    
+/\(((?>[^()]+)|\([^()]+\))+\)/ 
+    (abc)
+ 0: (abc)
+ 1: abc
+    (abc(def)xyz)
+ 0: (abc(def)xyz)
+ 1: xyz
+    *** Failers
+No match
+    ((()aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa   
+No match
+
+/a(?-i)b/i
+    ab
+ 0: ab
+    Ab
+ 0: Ab
+    *** Failers 
+No match
+    aB
+No match
+    AB
+No match
+        
+/(a (?x)b c)d e/
+    a bcd e
+ 0: a bcd e
+ 1: a bc
+    *** Failers
+No match
+    a b cd e
+No match
+    abcd e   
+No match
+    a bcde 
+No match
+ 
+/(a b(?x)c d (?-x)e f)/
+    a bcde f
+ 0: a bcde f
+ 1: a bcde f
+    *** Failers
+No match
+    abcdef  
+No match
+
+/(a(?i)b)c/
+    abc
+ 0: abc
+ 1: ab
+    aBc
+ 0: aBc
+ 1: aB
+    *** Failers
+No match
+    abC
+No match
+    aBC  
+No match
+    Abc
+No match
+    ABc
+No match
+    ABC
+No match
+    AbC
+No match
+    
+/a(?i:b)c/
+    abc
+ 0: abc
+    aBc
+ 0: aBc
+    *** Failers 
+No match
+    ABC
+No match
+    abC
+No match
+    aBC
+No match
+    
+/a(?i:b)*c/
+    aBc
+ 0: aBc
+    aBBc
+ 0: aBBc
+    *** Failers 
+No match
+    aBC
+No match
+    aBBC
+No match
+    
+/a(?=b(?i)c)\w\wd/
+    abcd
+ 0: abcd
+    abCd
+ 0: abCd
+    *** Failers
+No match
+    aBCd
+No match
+    abcD     
+No match
+    
+/(?s-i:more.*than).*million/i
+    more than million
+ 0: more than million
+    more than MILLION
+ 0: more than MILLION
+    more \n than Million 
+ 0: more \x0a than Million
+    *** Failers
+No match
+    MORE THAN MILLION    
+No match
+    more \n than \n million 
+No match
+
+/(?:(?s-i)more.*than).*million/i
+    more than million
+ 0: more than million
+    more than MILLION
+ 0: more than MILLION
+    more \n than Million 
+ 0: more \x0a than Million
+    *** Failers
+No match
+    MORE THAN MILLION    
+No match
+    more \n than \n million 
+No match
+    
+/(?>a(?i)b+)+c/ 
+    abc
+ 0: abc
+    aBbc
+ 0: aBbc
+    aBBc 
+ 0: aBBc
+    *** Failers
+No match
+    Abc
+No match
+    abAb    
+No match
+    abbC 
+No match
+    
+/(?=a(?i)b)\w\wc/
+    abc
+ 0: abc
+    aBc
+ 0: aBc
+    *** Failers
+No match
+    Ab 
+No match
+    abC
+No match
+    aBC     
+No match
+    
+/(?<=a(?i)b)(\w\w)c/
+    abxxc
+ 0: xxc
+ 1: xx
+    aBxxc
+ 0: xxc
+ 1: xx
+    *** Failers
+No match
+    Abxxc
+No match
+    ABxxc
+No match
+    abxxC      
+No match
+
+/(?:(a)|b)(?(1)A|B)/
+    aA
+ 0: aA
+ 1: a
+    bB
+ 0: bB
+    *** Failers
+No match
+    aB
+No match
+    bA    
+No match
+
+/^(a)?(?(1)a|b)+$/
+    aa
+ 0: aa
+ 1: a
+    b
+ 0: b
+    bb  
+ 0: bb
+    *** Failers
+No match
+    ab   
+No match
+
+/^(?(?=abc)\w{3}:|\d\d)$/
+    abc:
+ 0: abc:
+    12
+ 0: 12
+    *** Failers
+No match
+    123
+No match
+    xyz    
+No match
+
+/^(?(?!abc)\d\d|\w{3}:)$/
+    abc:
+ 0: abc:
+    12
+ 0: 12
+    *** Failers
+No match
+    123
+No match
+    xyz    
+No match
+    
+/(?(?<=foo)bar|cat)/
+    foobar
+ 0: bar
+    cat
+ 0: cat
+    fcat
+ 0: cat
+    focat   
+ 0: cat
+    *** Failers
+No match
+    foocat  
+No match
+
+/(?(?<!foo)cat|bar)/
+    foobar
+ 0: bar
+    cat
+ 0: cat
+    fcat
+ 0: cat
+    focat   
+ 0: cat
+    *** Failers
+No match
+    foocat  
+No match
+
+/( \( )? [^()]+ (?(1) \) |) /x
+    abcd
+ 0: abcd
+    (abcd)
+ 0: (abcd)
+ 1: (
+    the quick (abcd) fox
+ 0: the quick 
+    (abcd   
+ 0: abcd
+
+/( \( )? [^()]+ (?(1) \) ) /x
+    abcd
+ 0: abcd
+    (abcd)
+ 0: (abcd)
+ 1: (
+    the quick (abcd) fox
+ 0: the quick 
+    (abcd   
+ 0: abcd
+
+/^(?(2)a|(1)(2))+$/
+    12
+ 0: 12
+ 1: 1
+ 2: 2
+    12a
+ 0: 12a
+ 1: 1
+ 2: 2
+    12aa
+ 0: 12aa
+ 1: 1
+ 2: 2
+    *** Failers
+No match
+    1234    
+No match
+
+/((?i)blah)\s+\1/
+    blah blah
+ 0: blah blah
+ 1: blah
+    BLAH BLAH
+ 0: BLAH BLAH
+ 1: BLAH
+    Blah Blah
+ 0: Blah Blah
+ 1: Blah
+    blaH blaH
+ 0: blaH blaH
+ 1: blaH
+    *** Failers
+No match
+    blah BLAH
+No match
+    Blah blah      
+No match
+    blaH blah 
+No match
+
+/((?i)blah)\s+(?i:\1)/
+    blah blah
+ 0: blah blah
+ 1: blah
+    BLAH BLAH
+ 0: BLAH BLAH
+ 1: BLAH
+    Blah Blah
+ 0: Blah Blah
+ 1: Blah
+    blaH blaH
+ 0: blaH blaH
+ 1: blaH
+    blah BLAH
+ 0: blah BLAH
+ 1: blah
+    Blah blah      
+ 0: Blah blah
+ 1: Blah
+    blaH blah 
+ 0: blaH blah
+ 1: blaH
+
+/(?>a*)*/
+    a
+ 0: a
+    aa
+ 0: aa
+    aaaa
+ 0: aaaa
+    
+/(abc|)+/
+    abc
+ 0: abc
+ 1: 
+    abcabc
+ 0: abcabc
+ 1: 
+    abcabcabc
+ 0: abcabcabc
+ 1: 
+    xyz      
+ 0: 
+ 1: 
+
+/([a]*)*/
+    a
+ 0: a
+ 1: 
+    aaaaa 
+ 0: aaaaa
+ 1: 
+ 
+/([ab]*)*/
+    a
+ 0: a
+ 1: 
+    b
+ 0: b
+ 1: 
+    ababab
+ 0: ababab
+ 1: 
+    aaaabcde
+ 0: aaaab
+ 1: 
+    bbbb    
+ 0: bbbb
+ 1: 
+ 
+/([^a]*)*/
+    b
+ 0: b
+ 1: 
+    bbbb
+ 0: bbbb
+ 1: 
+    aaa   
+ 0: 
+ 1: 
+ 
+/([^ab]*)*/
+    cccc
+ 0: cccc
+ 1: 
+    abab  
+ 0: 
+ 1: 
+ 
+/([a]*?)*/
+    a
+ 0: 
+ 1: 
+    aaaa 
+ 0: 
+ 1: 
+ 
+/([ab]*?)*/
+    a
+ 0: 
+ 1: 
+    b
+ 0: 
+ 1: 
+    abab
+ 0: 
+ 1: 
+    baba   
+ 0: 
+ 1: 
+ 
+/([^a]*?)*/
+    b
+ 0: 
+ 1: 
+    bbbb
+ 0: 
+ 1: 
+    aaa   
+ 0: 
+ 1: 
+ 
+/([^ab]*?)*/
+    c
+ 0: 
+ 1: 
+    cccc
+ 0: 
+ 1: 
+    baba   
+ 0: 
+ 1: 
+ 
+/(?>a*)*/
+    a
+ 0: a
+    aaabcde 
+ 0: aaa
+ 
+/((?>a*))*/
+    aaaaa
+ 0: aaaaa
+ 1: 
+    aabbaa 
+ 0: aa
+ 1: 
+ 
+/((?>a*?))*/
+    aaaaa
+ 0: 
+ 1: 
+    aabbaa 
+ 0: 
+ 1: 
+
+/(?(?=[^a-z]+[a-z])  \d{2}-[a-z]{3}-\d{2}  |  \d{2}-\d{2}-\d{2} ) /x
+    12-sep-98
+ 0: 12-sep-98
+    12-09-98
+ 0: 12-09-98
+    *** Failers
+No match
+    sep-12-98
+No match
+        
+/(?<=(foo))bar\1/
+    foobarfoo
+ 0: barfoo
+ 1: foo
+    foobarfootling 
+ 0: barfoo
+ 1: foo
+    *** Failers
+No match
+    foobar
+No match
+    barfoo   
+No match
+
+/(?i:saturday|sunday)/
+    saturday
+ 0: saturday
+    sunday
+ 0: sunday
+    Saturday
+ 0: Saturday
+    Sunday
+ 0: Sunday
+    SATURDAY
+ 0: SATURDAY
+    SUNDAY
+ 0: SUNDAY
+    SunDay
+ 0: SunDay
+    
+/(a(?i)bc|BB)x/
+    abcx
+ 0: abcx
+ 1: abc
+    aBCx
+ 0: aBCx
+ 1: aBC
+    bbx
+ 0: bbx
+ 1: bb
+    BBx
+ 0: BBx
+ 1: BB
+    *** Failers
+No match
+    abcX
+No match
+    aBCX
+No match
+    bbX
+No match
+    BBX               
+No match
+
+/^([ab](?i)[cd]|[ef])/
+    ac
+ 0: ac
+ 1: ac
+    aC
+ 0: aC
+ 1: aC
+    bD
+ 0: bD
+ 1: bD
+    elephant
+ 0: e
+ 1: e
+    Europe 
+ 0: E
+ 1: E
+    frog
+ 0: f
+ 1: f
+    France
+ 0: F
+ 1: F
+    *** Failers
+No match
+    Africa     
+No match
+
+/^(ab|a(?i)[b-c](?m-i)d|x(?i)y|z)/
+    ab
+ 0: ab
+ 1: ab
+    aBd
+ 0: aBd
+ 1: aBd
+    xy
+ 0: xy
+ 1: xy
+    xY
+ 0: xY
+ 1: xY
+    zebra
+ 0: z
+ 1: z
+    Zambesi
+ 0: Z
+ 1: Z
+    *** Failers
+No match
+    aCD  
+No match
+    XY  
+No match
+
+/(?<=foo\n)^bar/m
+    foo\nbar
+ 0: bar
+    *** Failers
+No match
+    bar
+No match
+    baz\nbar   
+No match
+
+/(?<=(?<!foo)bar)baz/
+    barbaz
+ 0: baz
+    barbarbaz 
+ 0: baz
+    koobarbaz 
+ 0: baz
+    *** Failers
+No match
+    baz
+No match
+    foobarbaz 
+No match
+
+/The case of aaaaaa is missed out below because I think Perl 5.005_02 gets/
+/it wrong; it sets $1 to aaa rather than aa. Compare the following test,/
+No match
+/where it does set $1 to aa when matching aaaaaa./
+No match
+
+/^(a\1?){4}$/
+    a
+No match
+    aa
+No match
+    aaa
+No match
+    aaaa
+ 0: aaaa
+ 1: a
+    aaaaa
+ 0: aaaaa
+ 1: a
+    aaaaaaa
+ 0: aaaaaaa
+ 1: a
+    aaaaaaaa
+No match
+    aaaaaaaaa
+No match
+    aaaaaaaaaa
+ 0: aaaaaaaaaa
+ 1: aaaa
+    aaaaaaaaaaa
+No match
+    aaaaaaaaaaaa
+No match
+    aaaaaaaaaaaaa
+No match
+    aaaaaaaaaaaaaa
+No match
+    aaaaaaaaaaaaaaa
+No match
+    aaaaaaaaaaaaaaaa               
+No match
+
+/^(a\1?)(a\1?)(a\2?)(a\3?)$/
+    a
+No match
+    aa
+No match
+    aaa
+No match
+    aaaa
+ 0: aaaa
+ 1: a
+ 2: a
+ 3: a
+ 4: a
+    aaaaa
+ 0: aaaaa
+ 1: a
+ 2: aa
+ 3: a
+ 4: a
+    aaaaaa
+ 0: aaaaaa
+ 1: a
+ 2: aa
+ 3: a
+ 4: aa
+    aaaaaaa
+ 0: aaaaaaa
+ 1: a
+ 2: aa
+ 3: aaa
+ 4: a
+    aaaaaaaa
+No match
+    aaaaaaaaa
+No match
+    aaaaaaaaaa
+ 0: aaaaaaaaaa
+ 1: a
+ 2: aa
+ 3: aaa
+ 4: aaaa
+    aaaaaaaaaaa
+No match
+    aaaaaaaaaaaa
+No match
+    aaaaaaaaaaaaa
+No match
+    aaaaaaaaaaaaaa
+No match
+    aaaaaaaaaaaaaaa
+No match
+    aaaaaaaaaaaaaaaa               
+No match
+
+/The following tests are taken from the Perl 5.005 test suite; some of them/
+/are compatible with 5.004, but I'd rather not have to sort them out./
+No match
+
+/abc/
+    abc
+ 0: abc
+    xabcy
+ 0: abc
+    ababc
+ 0: abc
+    *** Failers
+No match
+    xbc
+No match
+    axc
+No match
+    abx
+No match
+
+/ab*c/
+    abc
+ 0: abc
+
+/ab*bc/
+    abc
+ 0: abc
+    abbc
+ 0: abbc
+    abbbbc
+ 0: abbbbc
+
+/.{1}/
+    abbbbc
+ 0: a
+
+/.{3,4}/
+    abbbbc
+ 0: abbb
+
+/ab{0,}bc/
+    abbbbc
+ 0: abbbbc
+
+/ab+bc/
+    abbc
+ 0: abbc
+    *** Failers
+No match
+    abc
+No match
+    abq
+No match
+
+/ab{1,}bc/
+
+/ab+bc/
+    abbbbc
+ 0: abbbbc
+
+/ab{1,}bc/
+    abbbbc
+ 0: abbbbc
+
+/ab{1,3}bc/
+    abbbbc
+ 0: abbbbc
+
+/ab{3,4}bc/
+    abbbbc
+ 0: abbbbc
+
+/ab{4,5}bc/
+    *** Failers
+No match
+    abq
+No match
+    abbbbc
+No match
+
+/ab?bc/
+    abbc
+ 0: abbc
+    abc
+ 0: abc
+
+/ab{0,1}bc/
+    abc
+ 0: abc
+
+/ab?bc/
+
+/ab?c/
+    abc
+ 0: abc
+
+/ab{0,1}c/
+    abc
+ 0: abc
+
+/^abc$/
+    abc
+ 0: abc
+    *** Failers
+No match
+    abbbbc
+No match
+    abcc
+No match
+
+/^abc/
+    abcc
+ 0: abc
+
+/^abc$/
+
+/abc$/
+    aabc
+ 0: abc
+    *** Failers
+No match
+    aabc
+ 0: abc
+    aabcd
+No match
+
+/^/
+    abc
+ 0: 
+
+/$/
+    abc
+ 0: 
+
+/a.c/
+    abc
+ 0: abc
+    axc
+ 0: axc
+
+/a.*c/
+    axyzc
+ 0: axyzc
+
+/a[bc]d/
+    abd
+ 0: abd
+    *** Failers
+No match
+    axyzd
+No match
+    abc
+No match
+
+/a[b-d]e/
+    ace
+ 0: ace
+
+/a[b-d]/
+    aac
+ 0: ac
+
+/a[-b]/
+    a-
+ 0: a-
+
+/a[b-]/
+    a-
+ 0: a-
+
+/a]/
+    a]
+ 0: a]
+
+/a[]]b/
+    a]b
+ 0: a]b
+
+/a[^bc]d/
+    aed
+ 0: aed
+    *** Failers
+No match
+    abd
+No match
+    abd
+No match
+
+/a[^-b]c/
+    adc
+ 0: adc
+
+/a[^]b]c/
+    adc
+ 0: adc
+    *** Failers
+No match
+    a-c
+ 0: a-c
+    a]c
+No match
+
+/\ba\b/
+    a-
+ 0: a
+    -a
+ 0: a
+    -a-
+ 0: a
+
+/\by\b/
+    *** Failers
+No match
+    xy
+No match
+    yz
+No match
+    xyz
+No match
+
+/\Ba\B/
+    *** Failers
+ 0: a
+    a-
+No match
+    -a
+No match
+    -a-
+No match
+
+/\By\b/
+    xy
+ 0: y
+
+/\by\B/
+    yz
+ 0: y
+
+/\By\B/
+    xyz
+ 0: y
+
+/\w/
+    a
+ 0: a
+
+/\W/
+    -
+ 0: -
+    *** Failers
+ 0: *
+    -
+ 0: -
+    a
+No match
+
+/a\sb/
+    a b
+ 0: a b
+
+/a\Sb/
+    a-b
+ 0: a-b
+    *** Failers
+No match
+    a-b
+ 0: a-b
+    a b
+No match
+
+/\d/
+    1
+ 0: 1
+
+/\D/
+    -
+ 0: -
+    *** Failers
+ 0: *
+    -
+ 0: -
+    1
+No match
+
+/[\w]/
+    a
+ 0: a
+
+/[\W]/
+    -
+ 0: -
+    *** Failers
+ 0: *
+    -
+ 0: -
+    a
+No match
+
+/a[\s]b/
+    a b
+ 0: a b
+
+/a[\S]b/
+    a-b
+ 0: a-b
+    *** Failers
+No match
+    a-b
+ 0: a-b
+    a b
+No match
+
+/[\d]/
+    1
+ 0: 1
+
+/[\D]/
+    -
+ 0: -
+    *** Failers
+ 0: *
+    -
+ 0: -
+    1
+No match
+
+/ab|cd/
+    abc
+ 0: ab
+    abcd
+ 0: ab
+
+/()ef/
+    def
+ 0: ef
+ 1: 
+
+/$b/
+
+/a\(b/
+    a(b
+ 0: a(b
+
+/a\(*b/
+    ab
+ 0: ab
+    a((b
+ 0: a((b
+
+/a\\b/
+    a\b
+No match
+
+/((a))/
+    abc
+ 0: a
+ 1: a
+ 2: a
+
+/(a)b(c)/
+    abc
+ 0: abc
+ 1: a
+ 2: c
+
+/a+b+c/
+    aabbabc
+ 0: abc
+
+/a{1,}b{1,}c/
+    aabbabc
+ 0: abc
+
+/a.+?c/
+    abcabc
+ 0: abc
+
+/(a+|b)*/
+    ab
+ 0: ab
+ 1: b
+
+/(a+|b){0,}/
+    ab
+ 0: ab
+ 1: b
+
+/(a+|b)+/
+    ab
+ 0: ab
+ 1: b
+
+/(a+|b){1,}/
+    ab
+ 0: ab
+ 1: b
+
+/(a+|b)?/
+    ab
+ 0: a
+ 1: a
+
+/(a+|b){0,1}/
+    ab
+ 0: a
+ 1: a
+
+/[^ab]*/
+    cde
+ 0: cde
+
+/abc/
+    *** Failers
+No match
+    b
+No match
+    
+
+/a*/
+    
+
+/([abc])*d/
+    abbbcd
+ 0: abbbcd
+ 1: c
+
+/([abc])*bcd/
+    abcd
+ 0: abcd
+ 1: a
+
+/a|b|c|d|e/
+    e
+ 0: e
+
+/(a|b|c|d|e)f/
+    ef
+ 0: ef
+ 1: e
+
+/abcd*efg/
+    abcdefg
+ 0: abcdefg
+
+/ab*/
+    xabyabbbz
+ 0: ab
+    xayabbbz
+ 0: a
+
+/(ab|cd)e/
+    abcde
+ 0: cde
+ 1: cd
+
+/[abhgefdc]ij/
+    hij
+ 0: hij
+
+/^(ab|cd)e/
+
+/(abc|)ef/
+    abcdef
+ 0: ef
+ 1: 
+
+/(a|b)c*d/
+    abcd
+ 0: bcd
+ 1: b
+
+/(ab|ab*)bc/
+    abc
+ 0: abc
+ 1: a
+
+/a([bc]*)c*/
+    abc
+ 0: abc
+ 1: bc
+
+/a([bc]*)(c*d)/
+    abcd
+ 0: abcd
+ 1: bc
+ 2: d
+
+/a([bc]+)(c*d)/
+    abcd
+ 0: abcd
+ 1: bc
+ 2: d
+
+/a([bc]*)(c+d)/
+    abcd
+ 0: abcd
+ 1: b
+ 2: cd
+
+/a[bcd]*dcdcde/
+    adcdcde
+ 0: adcdcde
+
+/a[bcd]+dcdcde/
+    *** Failers
+No match
+    abcde
+No match
+    adcdcde
+No match
+
+/(ab|a)b*c/
+    abc
+ 0: abc
+ 1: ab
+
+/((a)(b)c)(d)/
+    abcd
+ 0: abcd
+ 1: abc
+ 2: a
+ 3: b
+ 4: d
+
+/[a-zA-Z_][a-zA-Z0-9_]*/
+    alpha
+ 0: alpha
+
+/^a(bc+|b[eh])g|.h$/
+    abh
+ 0: bh
+
+/(bc+d$|ef*g.|h?i(j|k))/
+    effgz
+ 0: effgz
+ 1: effgz
+    ij
+ 0: ij
+ 1: ij
+ 2: j
+    reffgz
+ 0: effgz
+ 1: effgz
+    *** Failers
+No match
+    effg
+No match
+    bcdd
+No match
+
+/((((((((((a))))))))))/
+    a
+ 0: a
+ 1: a
+ 2: a
+ 3: a
+ 4: a
+ 5: a
+ 6: a
+ 7: a
+ 8: a
+ 9: a
+10: a
+
+/((((((((((a))))))))))\10/
+    aa
+ 0: aa
+ 1: a
+ 2: a
+ 3: a
+ 4: a
+ 5: a
+ 6: a
+ 7: a
+ 8: a
+ 9: a
+10: a
+
+/(((((((((a)))))))))/
+    a
+ 0: a
+ 1: a
+ 2: a
+ 3: a
+ 4: a
+ 5: a
+ 6: a
+ 7: a
+ 8: a
+ 9: a
+
+/multiple words of text/
+    *** Failers
+No match
+    aa
+No match
+    uh-uh
+No match
+
+/multiple words/
+    multiple words, yeah
+ 0: multiple words
+
+/(.*)c(.*)/
+    abcde
+ 0: abcde
+ 1: ab
+ 2: de
+
+/\((.*), (.*)\)/
+    (a, b)
+ 0: (a, b)
+ 1: a
+ 2: b
+
+/[k]/
+
+/abcd/
+    abcd
+ 0: abcd
+
+/a(bc)d/
+    abcd
+ 0: abcd
+ 1: bc
+
+/a[-]?c/
+    ac
+ 0: ac
+
+/(abc)\1/
+    abcabc
+ 0: abcabc
+ 1: abc
+
+/([a-c]*)\1/
+    abcabc
+ 0: abcabc
+ 1: abc
+
+/(a)|\1/
+    a
+ 0: a
+ 1: a
+    *** Failers
+ 0: a
+ 1: a
+    ab
+ 0: a
+ 1: a
+    x
+No match
+
+/(([a-c])b*?\2)*/
+    ababbbcbc
+ 0: ababb
+ 1: bb
+ 2: b
+
+/(([a-c])b*?\2){3}/
+    ababbbcbc
+ 0: ababbbcbc
+ 1: cbc
+ 2: c
+
+/((\3|b)\2(a)x)+/
+    aaaxabaxbaaxbbax
+ 0: bbax
+ 1: bbax
+ 2: b
+ 3: a
+
+/((\3|b)\2(a)){2,}/
+    bbaababbabaaaaabbaaaabba
+ 0: bbaaaabba
+ 1: bba
+ 2: b
+ 3: a
+
+/abc/i
+    ABC
+ 0: ABC
+    XABCY
+ 0: ABC
+    ABABC
+ 0: ABC
+    *** Failers
+No match
+    aaxabxbaxbbx
+No match
+    XBC
+No match
+    AXC
+No match
+    ABX
+No match
+
+/ab*c/i
+    ABC
+ 0: ABC
+
+/ab*bc/i
+    ABC
+ 0: ABC
+    ABBC
+ 0: ABBC
+
+/ab*?bc/i
+    ABBBBC
+ 0: ABBBBC
+
+/ab{0,}?bc/i
+    ABBBBC
+ 0: ABBBBC
+
+/ab+?bc/i
+    ABBC
+ 0: ABBC
+
+/ab+bc/i
+    *** Failers
+No match
+    ABC
+No match
+    ABQ
+No match
+
+/ab{1,}bc/i
+
+/ab+bc/i
+    ABBBBC
+ 0: ABBBBC
+
+/ab{1,}?bc/i
+    ABBBBC
+ 0: ABBBBC
+
+/ab{1,3}?bc/i
+    ABBBBC
+ 0: ABBBBC
+
+/ab{3,4}?bc/i
+    ABBBBC
+ 0: ABBBBC
+
+/ab{4,5}?bc/i
+    *** Failers
+No match
+    ABQ
+No match
+    ABBBBC
+No match
+
+/ab??bc/i
+    ABBC
+ 0: ABBC
+    ABC
+ 0: ABC
+
+/ab{0,1}?bc/i
+    ABC
+ 0: ABC
+
+/ab??bc/i
+
+/ab??c/i
+    ABC
+ 0: ABC
+
+/ab{0,1}?c/i
+    ABC
+ 0: ABC
+
+/^abc$/i
+    ABC
+ 0: ABC
+    *** Failers
+No match
+    ABBBBC
+No match
+    ABCC
+No match
+
+/^abc/i
+    ABCC
+ 0: ABC
+
+/^abc$/i
+
+/abc$/i
+    AABC
+ 0: ABC
+
+/^/i
+    ABC
+ 0: 
+
+/$/i
+    ABC
+ 0: 
+
+/a.c/i
+    ABC
+ 0: ABC
+    AXC
+ 0: AXC
+
+/a.*?c/i
+    AXYZC
+ 0: AXYZC
+
+/a.*c/i
+    *** Failers
+No match
+    AABC
+ 0: AABC
+    AXYZD
+No match
+
+/a[bc]d/i
+    ABD
+ 0: ABD
+
+/a[b-d]e/i
+    ACE
+ 0: ACE
+    *** Failers
+No match
+    ABC
+No match
+    ABD
+No match
+
+/a[b-d]/i
+    AAC
+ 0: AC
+
+/a[-b]/i
+    A-
+ 0: A-
+
+/a[b-]/i
+    A-
+ 0: A-
+
+/a]/i
+    A]
+ 0: A]
+
+/a[]]b/i
+    A]B
+ 0: A]B
+
+/a[^bc]d/i
+    AED
+ 0: AED
+
+/a[^-b]c/i
+    ADC
+ 0: ADC
+    *** Failers
+No match
+    ABD
+No match
+    A-C
+No match
+
+/a[^]b]c/i
+    ADC
+ 0: ADC
+
+/ab|cd/i
+    ABC
+ 0: AB
+    ABCD
+ 0: AB
+
+/()ef/i
+    DEF
+ 0: EF
+ 1: 
+
+/$b/i
+    *** Failers
+No match
+    A]C
+No match
+    B
+No match
+
+/a\(b/i
+    A(B
+ 0: A(B
+
+/a\(*b/i
+    AB
+ 0: AB
+    A((B
+ 0: A((B
+
+/a\\b/i
+    A\B
+No match
+
+/((a))/i
+    ABC
+ 0: A
+ 1: A
+ 2: A
+
+/(a)b(c)/i
+    ABC
+ 0: ABC
+ 1: A
+ 2: C
+
+/a+b+c/i
+    AABBABC
+ 0: ABC
+
+/a{1,}b{1,}c/i
+    AABBABC
+ 0: ABC
+
+/a.+?c/i
+    ABCABC
+ 0: ABC
+
+/a.*?c/i
+    ABCABC
+ 0: ABC
+
+/a.{0,5}?c/i
+    ABCABC
+ 0: ABC
+
+/(a+|b)*/i
+    AB
+ 0: AB
+ 1: B
+
+/(a+|b){0,}/i
+    AB
+ 0: AB
+ 1: B
+
+/(a+|b)+/i
+    AB
+ 0: AB
+ 1: B
+
+/(a+|b){1,}/i
+    AB
+ 0: AB
+ 1: B
+
+/(a+|b)?/i
+    AB
+ 0: A
+ 1: A
+
+/(a+|b){0,1}/i
+    AB
+ 0: A
+ 1: A
+
+/(a+|b){0,1}?/i
+    AB
+ 0: 
+
+/[^ab]*/i
+    CDE
+ 0: CDE
+
+/abc/i
+
+/a*/i
+    
+
+/([abc])*d/i
+    ABBBCD
+ 0: ABBBCD
+ 1: C
+
+/([abc])*bcd/i
+    ABCD
+ 0: ABCD
+ 1: A
+
+/a|b|c|d|e/i
+    E
+ 0: E
+
+/(a|b|c|d|e)f/i
+    EF
+ 0: EF
+ 1: E
+
+/abcd*efg/i
+    ABCDEFG
+ 0: ABCDEFG
+
+/ab*/i
+    XABYABBBZ
+ 0: AB
+    XAYABBBZ
+ 0: A
+
+/(ab|cd)e/i
+    ABCDE
+ 0: CDE
+ 1: CD
+
+/[abhgefdc]ij/i
+    HIJ
+ 0: HIJ
+
+/^(ab|cd)e/i
+    ABCDE
+No match
+
+/(abc|)ef/i
+    ABCDEF
+ 0: EF
+ 1: 
+
+/(a|b)c*d/i
+    ABCD
+ 0: BCD
+ 1: B
+
+/(ab|ab*)bc/i
+    ABC
+ 0: ABC
+ 1: A
+
+/a([bc]*)c*/i
+    ABC
+ 0: ABC
+ 1: BC
+
+/a([bc]*)(c*d)/i
+    ABCD
+ 0: ABCD
+ 1: BC
+ 2: D
+
+/a([bc]+)(c*d)/i
+    ABCD
+ 0: ABCD
+ 1: BC
+ 2: D
+
+/a([bc]*)(c+d)/i
+    ABCD
+ 0: ABCD
+ 1: B
+ 2: CD
+
+/a[bcd]*dcdcde/i
+    ADCDCDE
+ 0: ADCDCDE
+
+/a[bcd]+dcdcde/i
+
+/(ab|a)b*c/i
+    ABC
+ 0: ABC
+ 1: AB
+
+/((a)(b)c)(d)/i
+    ABCD
+ 0: ABCD
+ 1: ABC
+ 2: A
+ 3: B
+ 4: D
+
+/[a-zA-Z_][a-zA-Z0-9_]*/i
+    ALPHA
+ 0: ALPHA
+
+/^a(bc+|b[eh])g|.h$/i
+    ABH
+ 0: BH
+
+/(bc+d$|ef*g.|h?i(j|k))/i
+    EFFGZ
+ 0: EFFGZ
+ 1: EFFGZ
+    IJ
+ 0: IJ
+ 1: IJ
+ 2: J
+    REFFGZ
+ 0: EFFGZ
+ 1: EFFGZ
+    *** Failers
+No match
+    ADCDCDE
+No match
+    EFFG
+No match
+    BCDD
+No match
+
+/((((((((((a))))))))))/i
+    A
+ 0: A
+ 1: A
+ 2: A
+ 3: A
+ 4: A
+ 5: A
+ 6: A
+ 7: A
+ 8: A
+ 9: A
+10: A
+
+/((((((((((a))))))))))\10/i
+    AA
+ 0: AA
+ 1: A
+ 2: A
+ 3: A
+ 4: A
+ 5: A
+ 6: A
+ 7: A
+ 8: A
+ 9: A
+10: A
+
+/(((((((((a)))))))))/i
+    A
+ 0: A
+ 1: A
+ 2: A
+ 3: A
+ 4: A
+ 5: A
+ 6: A
+ 7: A
+ 8: A
+ 9: A
+
+/(?:(?:(?:(?:(?:(?:(?:(?:(?:(a))))))))))/i
+    A
+ 0: A
+ 1: A
+
+/(?:(?:(?:(?:(?:(?:(?:(?:(?:(a|b|c))))))))))/i
+    C
+ 0: C
+ 1: C
+
+/multiple words of text/i
+    *** Failers
+No match
+    AA
+No match
+    UH-UH
+No match
+
+/multiple words/i
+    MULTIPLE WORDS, YEAH
+ 0: MULTIPLE WORDS
+
+/(.*)c(.*)/i
+    ABCDE
+ 0: ABCDE
+ 1: AB
+ 2: DE
+
+/\((.*), (.*)\)/i
+    (A, B)
+ 0: (A, B)
+ 1: A
+ 2: B
+
+/[k]/i
+
+/abcd/i
+    ABCD
+ 0: ABCD
+
+/a(bc)d/i
+    ABCD
+ 0: ABCD
+ 1: BC
+
+/a[-]?c/i
+    AC
+ 0: AC
+
+/(abc)\1/i
+    ABCABC
+ 0: ABCABC
+ 1: ABC
+
+/([a-c]*)\1/i
+    ABCABC
+ 0: ABCABC
+ 1: ABC
+
+/a(?!b)./
+    abad
+ 0: ad
+
+/a(?=d)./
+    abad
+ 0: ad
+
+/a(?=c|d)./
+    abad
+ 0: ad
+
+/a(?:b|c|d)(.)/
+    ace
+ 0: ace
+ 1: e
+
+/a(?:b|c|d)*(.)/
+    ace
+ 0: ace
+ 1: e
+
+/a(?:b|c|d)+?(.)/
+    ace
+ 0: ace
+ 1: e
+    acdbcdbe
+ 0: acd
+ 1: d
+
+/a(?:b|c|d)+(.)/
+    acdbcdbe
+ 0: acdbcdbe
+ 1: e
+
+/a(?:b|c|d){2}(.)/
+    acdbcdbe
+ 0: acdb
+ 1: b
+
+/a(?:b|c|d){4,5}(.)/
+    acdbcdbe
+ 0: acdbcdb
+ 1: b
+
+/a(?:b|c|d){4,5}?(.)/
+    acdbcdbe
+ 0: acdbcd
+ 1: d
+
+/((foo)|(bar))*/
+    foobar
+ 0: foobar
+ 1: bar
+ 2: foo
+ 3: bar
+
+/a(?:b|c|d){6,7}(.)/
+    acdbcdbe
+ 0: acdbcdbe
+ 1: e
+
+/a(?:b|c|d){6,7}?(.)/
+    acdbcdbe
+ 0: acdbcdbe
+ 1: e
+
+/a(?:b|c|d){5,6}(.)/
+    acdbcdbe
+ 0: acdbcdbe
+ 1: e
+
+/a(?:b|c|d){5,6}?(.)/
+    acdbcdbe
+ 0: acdbcdb
+ 1: b
+
+/a(?:b|c|d){5,7}(.)/
+    acdbcdbe
+ 0: acdbcdbe
+ 1: e
+
+/a(?:b|c|d){5,7}?(.)/
+    acdbcdbe
+ 0: acdbcdb
+ 1: b
+
+/a(?:b|(c|e){1,2}?|d)+?(.)/
+    ace
+ 0: ace
+ 1: c
+ 2: e
+
+/^(.+)?B/
+    AB
+ 0: AB
+ 1: A
+
+/^([^a-z])|(\^)$/
+    .
+ 0: .
+ 1: .
+
+/^[<>]&/
+    <&OUT
+ 0: <&
+
+/^(a\1?){4}$/
+    aaaaaaaaaa
+ 0: aaaaaaaaaa
+ 1: aaaa
+    *** Failers
+No match
+    AB
+No match
+    aaaaaaaaa
+No match
+    aaaaaaaaaaa
+No match
+
+/^(a(?(1)\1)){4}$/
+    aaaaaaaaaa
+ 0: aaaaaaaaaa
+ 1: aaaa
+    *** Failers
+No match
+    aaaaaaaaa
+No match
+    aaaaaaaaaaa
+No match
+
+/(?:(f)(o)(o)|(b)(a)(r))*/
+    foobar
+ 0: foobar
+ 1: f
+ 2: o
+ 3: o
+ 4: b
+ 5: a
+ 6: r
+
+/(?<=a)b/
+    ab
+ 0: b
+    *** Failers
+No match
+    cb
+No match
+    b
+No match
+
+/(?<!c)b/
+    ab
+ 0: b
+    b
+ 0: b
+    b
+ 0: b
+
+/(?:..)*a/
+    aba
+ 0: aba
+
+/(?:..)*?a/
+    aba
+ 0: a
+
+/^(?:b|a(?=(.)))*\1/
+    abc
+ 0: ab
+ 1: b
+
+/^(){3,5}/
+    abc
+ 0: 
+ 1: 
+
+/^(a+)*ax/
+    aax
+ 0: aax
+ 1: a
+
+/^((a|b)+)*ax/
+    aax
+ 0: aax
+ 1: a
+ 2: a
+
+/^((a|bc)+)*ax/
+    aax
+ 0: aax
+ 1: a
+ 2: a
+
+/(a|x)*ab/
+    cab
+ 0: ab
+
+/(a)*ab/
+    cab
+ 0: ab
+
+/(?:(?i)a)b/
+    ab
+ 0: ab
+
+/((?i)a)b/
+    ab
+ 0: ab
+ 1: a
+
+/(?:(?i)a)b/
+    Ab
+ 0: Ab
+
+/((?i)a)b/
+    Ab
+ 0: Ab
+ 1: A
+
+/(?:(?i)a)b/
+    *** Failers
+No match
+    cb
+No match
+    aB
+No match
+
+/((?i)a)b/
+
+/(?i:a)b/
+    ab
+ 0: ab
+
+/((?i:a))b/
+    ab
+ 0: ab
+ 1: a
+
+/(?i:a)b/
+    Ab
+ 0: Ab
+
+/((?i:a))b/
+    Ab
+ 0: Ab
+ 1: A
+
+/(?i:a)b/
+    *** Failers
+No match
+    aB
+No match
+    aB
+No match
+
+/((?i:a))b/
+
+/(?:(?-i)a)b/i
+    ab
+ 0: ab
+
+/((?-i)a)b/i
+    ab
+ 0: ab
+ 1: a
+
+/(?:(?-i)a)b/i
+    aB
+ 0: aB
+
+/((?-i)a)b/i
+    aB
+ 0: aB
+ 1: a
+
+/(?:(?-i)a)b/i
+    *** Failers
+No match
+    aB
+ 0: aB
+    Ab
+No match
+
+/((?-i)a)b/i
+
+/(?:(?-i)a)b/i
+    aB
+ 0: aB
+
+/((?-i)a)b/i
+    aB
+ 0: aB
+ 1: a
+
+/(?:(?-i)a)b/i
+    *** Failers
+No match
+    Ab
+No match
+    AB
+No match
+
+/((?-i)a)b/i
+
+/(?-i:a)b/i
+    ab
+ 0: ab
+
+/((?-i:a))b/i
+    ab
+ 0: ab
+ 1: a
+
+/(?-i:a)b/i
+    aB
+ 0: aB
+
+/((?-i:a))b/i
+    aB
+ 0: aB
+ 1: a
+
+/(?-i:a)b/i
+    *** Failers
+No match
+    AB
+No match
+    Ab
+No match
+
+/((?-i:a))b/i
+
+/(?-i:a)b/i
+    aB
+ 0: aB
+
+/((?-i:a))b/i
+    aB
+ 0: aB
+ 1: a
+
+/(?-i:a)b/i
+    *** Failers
+No match
+    Ab
+No match
+    AB
+No match
+
+/((?-i:a))b/i
+
+/((?-i:a.))b/i
+    *** Failers
+No match
+    AB
+No match
+    a\nB
+No match
+
+/((?s-i:a.))b/i
+    a\nB
+ 0: a\x0aB
+ 1: a\x0a
+
+/(?:c|d)(?:)(?:a(?:)(?:b)(?:b(?:))(?:b(?:)(?:b)))/
+    cabbbb
+ 0: cabbbb
+
+/(?:c|d)(?:)(?:aaaaaaaa(?:)(?:bbbbbbbb)(?:bbbbbbbb(?:))(?:bbbbbbbb(?:)(?:bbbbbbbb)))/
+    caaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
+ 0: caaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
+
+/(ab)\d\1/i
+    Ab4ab
+ 0: Ab4ab
+ 1: Ab
+    ab4Ab
+ 0: ab4Ab
+ 1: ab
+
+/foo\w*\d{4}baz/
+    foobar1234baz
+ 0: foobar1234baz
+
+/x(~~)*(?:(?:F)?)?/
+    x~~
+ 0: x~~
+ 1: ~~
+
+/^a(?#xxx){3}c/
+    aaac
+ 0: aaac
+
+/^a (?#xxx) (?#yyy) {3}c/x
+    aaac
+ 0: aaac
+
+/(?<![cd])b/
+    *** Failers
+No match
+    B\nB
+No match
+    dbcb
+No match
+
+/(?<![cd])[ab]/
+    dbaacb
+ 0: a
+
+/(?<!(c|d))b/
+
+/(?<!(c|d))[ab]/
+    dbaacb
+ 0: a
+
+/(?<!cd)[ab]/
+    cdaccb
+ 0: b
+
+/^(?:a?b?)*$/
+    *** Failers
+No match
+    dbcb
+No match
+    a--
+No match
+
+/((?s)^a(.))((?m)^b$)/
+    a\nb\nc\n
+ 0: a\x0ab
+ 1: a\x0a
+ 2: \x0a
+ 3: b
+
+/((?m)^b$)/
+    a\nb\nc\n
+ 0: b
+ 1: b
+
+/(?m)^b/
+    a\nb\n
+ 0: b
+
+/(?m)^(b)/
+    a\nb\n
+ 0: b
+ 1: b
+
+/((?m)^b)/
+    a\nb\n
+ 0: b
+ 1: b
+
+/\n((?m)^b)/
+    a\nb\n
+ 0: \x0ab
+ 1: b
+
+/((?s).)c(?!.)/
+    a\nb\nc\n
+ 0: \x0ac
+ 1: \x0a
+    a\nb\nc\n
+ 0: \x0ac
+ 1: \x0a
+
+/((?s)b.)c(?!.)/
+    a\nb\nc\n
+ 0: b\x0ac
+ 1: b\x0a
+    a\nb\nc\n
+ 0: b\x0ac
+ 1: b\x0a
+
+/^b/
+
+/()^b/
+    *** Failers
+No match
+    a\nb\nc\n
+No match
+    a\nb\nc\n
+No match
+
+/((?m)^b)/
+    a\nb\nc\n
+ 0: b
+ 1: b
+
+/(?(1)a|b)/
+
+/(?(1)b|a)/
+    a
+ 0: a
+
+/(x)?(?(1)a|b)/
+    *** Failers
+No match
+    a
+No match
+    a
+No match
+
+/(x)?(?(1)b|a)/
+    a
+ 0: a
+
+/()?(?(1)b|a)/
+    a
+ 0: a
+
+/()(?(1)b|a)/
+
+/()?(?(1)a|b)/
+    a
+ 0: a
+ 1: 
+
+/^(\()?blah(?(1)(\)))$/
+    (blah)
+ 0: (blah)
+ 1: (
+ 2: )
+    blah
+ 0: blah
+    *** Failers
+No match
+    a
+No match
+    blah)
+No match
+    (blah
+No match
+
+/^(\(+)?blah(?(1)(\)))$/
+    (blah)
+ 0: (blah)
+ 1: (
+ 2: )
+    blah
+ 0: blah
+    *** Failers
+No match
+    blah)
+No match
+    (blah
+No match
+
+/(?(?!a)a|b)/
+
+/(?(?!a)b|a)/
+    a
+ 0: a
+
+/(?(?=a)b|a)/
+    *** Failers
+No match
+    a
+No match
+    a
+No match
+
+/(?(?=a)a|b)/
+    a
+ 0: a
+
+/(?=(a+?))(\1ab)/
+    aaab
+ 0: aab
+ 1: a
+ 2: aab
+
+/^(?=(a+?))\1ab/
+
+/(\w+:)+/
+    one:
+ 0: one:
+ 1: one:
+
+/$(?<=^(a))/
+    a
+ 0: 
+ 1: a
+
+/(?=(a+?))(\1ab)/
+    aaab
+ 0: aab
+ 1: a
+ 2: aab
+
+/^(?=(a+?))\1ab/
+    *** Failers
+No match
+    aaab
+No match
+    aaab
+No match
+
+/([\w:]+::)?(\w+)$/
+    abcd
+ 0: abcd
+ 1: <unset>
+ 2: abcd
+    xy:z:::abcd
+ 0: xy:z:::abcd
+ 1: xy:z:::
+ 2: abcd
+
+/^[^bcd]*(c+)/
+    aexycd
+ 0: aexyc
+ 1: c
+
+/(a*)b+/
+    caab
+ 0: aab
+ 1: aa
+
+/([\w:]+::)?(\w+)$/
+    abcd
+ 0: abcd
+ 1: <unset>
+ 2: abcd
+    xy:z:::abcd
+ 0: xy:z:::abcd
+ 1: xy:z:::
+ 2: abcd
+    *** Failers
+ 0: Failers
+ 1: <unset>
+ 2: Failers
+    abcd:
+No match
+    abcd:
+No match
+
+/^[^bcd]*(c+)/
+    aexycd
+ 0: aexyc
+ 1: c
+
+/(>a+)ab/
+
+/(?>a+)b/
+    aaab
+ 0: aaab
+
+/([[:]+)/
+    a:[b]:
+ 0: :[
+ 1: :[
+
+/([[=]+)/
+    a=[b]=
+ 0: =[
+ 1: =[
+
+/([[.]+)/
+    a.[b].
+ 0: .[
+ 1: .[
+
+/((?>a+)b)/
+    aaab
+ 0: aaab
+ 1: aaab
+
+/(?>(a+))b/
+    aaab
+ 0: aaab
+ 1: aaa
+
+/((?>[^()]+)|\([^()]*\))+/
+    ((abc(ade)ufh()()x
+ 0: abc(ade)ufh()()x
+ 1: x
+
+/a\Z/
+    *** Failers
+No match
+    aaab
+No match
+    a\nb\n
+No match
+
+/b\Z/
+    a\nb\n
+ 0: b
+
+/b\z/
+
+/b\Z/
+    a\nb
+ 0: b
+
+/b\z/
+    a\nb
+ 0: b
+    *** Failers
+No match
+    
+/^(?>(?(1)\.|())[^\W_](?>[a-z0-9-]*[^\W_])?)+$/
+    a
+ 0: a
+ 1: 
+    abc
+ 0: abc
+ 1: 
+    a-b
+ 0: a-b
+ 1: 
+    0-9 
+ 0: 0-9
+ 1: 
+    a.b
+ 0: a.b
+ 1: 
+    5.6.7  
+ 0: 5.6.7
+ 1: 
+    the.quick.brown.fox
+ 0: the.quick.brown.fox
+ 1: 
+    a100.b200.300c  
+ 0: a100.b200.300c
+ 1: 
+    12-ab.1245 
+ 0: 12-ab.1245
+ 1: 
+    *** Failers
+No match
+    \
+No match
+    .a
+No match
+    -a
+No match
+    a-
+No match
+    a.  
+No match
+    a_b 
+No match
+    a.-
+No match
+    a..  
+No match
+    ab..bc 
+No match
+    the.quick.brown.fox-
+No match
+    the.quick.brown.fox.
+No match
+    the.quick.brown.fox_
+No match
+    the.quick.brown.fox+       
+No match
+
+/(?>.*)(?<=(abcd|wxyz))/
+    alphabetabcd
+ 0: alphabetabcd
+ 1: abcd
+    endingwxyz
+ 0: endingwxyz
+ 1: wxyz
+    *** Failers
+No match
+    a rather long string that doesn't end with one of them
+No match
+
+/word (?>(?:(?!otherword)[a-zA-Z0-9]+ ){0,30})otherword/
+    word cat dog elephant mussel cow horse canary baboon snake shark otherword
+ 0: word cat dog elephant mussel cow horse canary baboon snake shark otherword
+    word cat dog elephant mussel cow horse canary baboon snake shark
+No match
+  
+/word (?>[a-zA-Z0-9]+ ){0,30}otherword/
+    word cat dog elephant mussel cow horse canary baboon snake shark the quick brown fox and the lazy dog and several other words getting close to thirty by now I hope
+No match
+
+/(?<=\d{3}(?!999))foo/
+    999foo
+ 0: foo
+    123999foo 
+ 0: foo
+    *** Failers
+No match
+    123abcfoo
+No match
+    
+/(?<=(?!...999)\d{3})foo/
+    999foo
+ 0: foo
+    123999foo 
+ 0: foo
+    *** Failers
+No match
+    123abcfoo
+No match
+
+/(?<=\d{3}(?!999)...)foo/
+    123abcfoo
+ 0: foo
+    123456foo 
+ 0: foo
+    *** Failers
+No match
+    123999foo  
+No match
+    
+/(?<=\d{3}...)(?<!999)foo/
+    123abcfoo   
+ 0: foo
+    123456foo 
+ 0: foo
+    *** Failers
+No match
+    123999foo  
+No match
+
+/<a[\s]+href[\s]*=[\s]*          # find <a href=
+ ([\"\'])?                       # find single or double quote
+ (?(1) (.*?)\1 | ([^\s]+))       # if quote found, match up to next matching
+                                 # quote, otherwise match up to next space
+/isx
+    <a href=abcd xyz
+ 0: <a href=abcd
+ 1: <unset>
+ 2: <unset>
+ 3: abcd
+    <a href=\"abcd xyz pqr\" cats
+ 0: <a href="abcd xyz pqr"
+ 1: "
+ 2: abcd xyz pqr
+    <a href=\'abcd xyz pqr\' cats
+ 0: <a href='abcd xyz pqr'
+ 1: '
+ 2: abcd xyz pqr
+
+/<a\s+href\s*=\s*                # find <a href=
+ (["'])?                         # find single or double quote
+ (?(1) (.*?)\1 | (\S+))          # if quote found, match up to next matching
+                                 # quote, otherwise match up to next space
+/isx
+    <a href=abcd xyz
+ 0: <a href=abcd
+ 1: <unset>
+ 2: <unset>
+ 3: abcd
+    <a href=\"abcd xyz pqr\" cats
+ 0: <a href="abcd xyz pqr"
+ 1: "
+ 2: abcd xyz pqr
+    <a href       =       \'abcd xyz pqr\' cats
+ 0: <a href       =       'abcd xyz pqr'
+ 1: '
+ 2: abcd xyz pqr
+
+/<a\s+href(?>\s*)=(?>\s*)        # find <a href=
+ (["'])?                         # find single or double quote
+ (?(1) (.*?)\1 | (\S+))          # if quote found, match up to next matching
+                                 # quote, otherwise match up to next space
+/isx
+    <a href=abcd xyz
+ 0: <a href=abcd
+ 1: <unset>
+ 2: <unset>
+ 3: abcd
+    <a href=\"abcd xyz pqr\" cats
+ 0: <a href="abcd xyz pqr"
+ 1: "
+ 2: abcd xyz pqr
+    <a href       =       \'abcd xyz pqr\' cats
+ 0: <a href       =       'abcd xyz pqr'
+ 1: '
+ 2: abcd xyz pqr
+
+/((Z)+|A)*/
+    ZABCDEFG
+ 0: ZA
+ 1: A
+ 2: Z
+
+/(Z()|A)*/
+    ZABCDEFG
+ 0: ZA
+ 1: A
+ 2: 
+
+/(Z(())|A)*/
+    ZABCDEFG
+ 0: ZA
+ 1: A
+ 2: 
+ 3: 
+
+/((?>Z)+|A)*/
+    ZABCDEFG
+ 0: ZA
+ 1: A
+
+/((?>)+|A)*/
+    ZABCDEFG
+ 0: 
+ 1: 
+
+/a*/g
+    abbab
+ 0: a
+ 0: 
+ 0: 
+ 0: a
+ 0: 
+ 0: 
+
+/^[a-\d]/
+    abcde
+ 0: a
+    -things
+ 0: -
+    0digit
+ 0: 0
+    *** Failers
+No match
+    bcdef    
+No match
+
+/^[\d-a]/
+    abcde
+ 0: a
+    -things
+ 0: -
+    0digit
+ 0: 0
+    *** Failers
+No match
+    bcdef    
+No match
+    
+/[[:space:]]+/
+    > \x09\x0a\x0c\x0d\x0b<
+ 0:  \x09\x0a\x0c\x0d\x0b
+     
+/[[:blank:]]+/
+    > \x09\x0a\x0c\x0d\x0b<
+ 0:  \x09
+     
+/[\s]+/
+    > \x09\x0a\x0c\x0d\x0b<
+ 0:  \x09\x0a\x0c\x0d
+     
+/\s+/
+    > \x09\x0a\x0c\x0d\x0b<
+ 0:  \x09\x0a\x0c\x0d
+     
+/ab/x
+    ab
+No match
+
+/(?!\A)x/m
+  a\nxb\n
+ 0: x
+
+/(?!^)x/m
+  a\nxb\n
+No match
+
+/abc\Qabc\Eabc/
+    abcabcabc
+ 0: abcabcabc
+    
+/abc\Q(*+|\Eabc/
+    abc(*+|abc 
+ 0: abc(*+|abc
+
+/   abc\Q abc\Eabc/x
+    abc abcabc
+ 0: abc abcabc
+    *** Failers
+No match
+    abcabcabc  
+No match
+    
+/abc#comment
+    \Q#not comment
+    literal\E/x
+    abc#not comment\n    literal     
+ 0: abc#not comment\x0a    literal
+
+/abc#comment
+    \Q#not comment
+    literal/x
+    abc#not comment\n    literal     
+ 0: abc#not comment\x0a    literal
+
+/abc#comment
+    \Q#not comment
+    literal\E #more comment
+    /x
+    abc#not comment\n    literal     
+ 0: abc#not comment\x0a    literal
+
+/abc#comment
+    \Q#not comment
+    literal\E #more comment/x
+    abc#not comment\n    literal     
+ 0: abc#not comment\x0a    literal
+
+/\Qabc\$xyz\E/
+    abc\\\$xyz
+ 0: abc\$xyz
+
+/\Qabc\E\$\Qxyz\E/
+    abc\$xyz
+ 0: abc$xyz
+
+/\Gabc/
+    abc
+ 0: abc
+    *** Failers
+No match
+    xyzabc  
+No match
+
+/\Gabc./g
+    abc1abc2xyzabc3
+ 0: abc1
+ 0: abc2
+
+/abc./g
+    abc1abc2xyzabc3 
+ 0: abc1
+ 0: abc2
+ 0: abc3
+
+/a(?x: b c )d/
+    XabcdY
+ 0: abcd
+    *** Failers 
+No match
+    Xa b c d Y 
+No match
+
+/((?x)x y z | a b c)/
+    XabcY
+ 0: abc
+ 1: abc
+    AxyzB 
+ 0: xyz
+ 1: xyz
+
+/(?i)AB(?-i)C/
+    XabCY
+ 0: abC
+    *** Failers
+No match
+    XabcY  
+No match
+
+/((?i)AB(?-i)C|D)E/
+    abCE
+ 0: abCE
+ 1: abC
+    DE
+ 0: DE
+ 1: D
+    *** Failers
+No match
+    abcE
+No match
+    abCe  
+No match
+    dE
+No match
+    De    
+No match
+
+/(.*)\d+\1/
+    abc123abc
+ 0: abc123abc
+ 1: abc
+    abc123bc 
+ 0: bc123bc
+ 1: bc
+
+/(.*)\d+\1/s
+    abc123abc
+ 0: abc123abc
+ 1: abc
+    abc123bc 
+ 0: bc123bc
+ 1: bc
+    
+/((.*))\d+\1/
+    abc123abc
+ 0: abc123abc
+ 1: abc
+ 2: abc
+    abc123bc  
+ 0: bc123bc
+ 1: bc
+ 2: bc
+
+/-- This tests for an IPv6 address in the form where it can have up to --/
+/-- eight components, one and only one of which is empty. This must be --/
+No match
+/-- an internal component. --/
+No match
+
+/^(?!:)                       # colon disallowed at start
+  (?:                         # start of item
+    (?: [0-9a-f]{1,4} |       # 1-4 hex digits or
+    (?(1)0 | () ) )           # if null previously matched, fail; else null
+    :                         # followed by colon
+  ){1,7}                      # end item; 1-7 of them required               
+  [0-9a-f]{1,4} $             # final hex number at end of string
+  (?(1)|.)                    # check that there was an empty component
+  /xi
+    a123::a123
+ 0: a123::a123
+ 1: 
+    a123:b342::abcd
+ 0: a123:b342::abcd
+ 1: 
+    a123:b342::324e:abcd
+ 0: a123:b342::324e:abcd
+ 1: 
+    a123:ddde:b342::324e:abcd
+ 0: a123:ddde:b342::324e:abcd
+ 1: 
+    a123:ddde:b342::324e:dcba:abcd
+ 0: a123:ddde:b342::324e:dcba:abcd
+ 1: 
+    a123:ddde:9999:b342::324e:dcba:abcd
+ 0: a123:ddde:9999:b342::324e:dcba:abcd
+ 1: 
+    *** Failers
+No match
+    1:2:3:4:5:6:7:8
+No match
+    a123:bce:ddde:9999:b342::324e:dcba:abcd
+No match
+    a123::9999:b342::324e:dcba:abcd
+No match
+    abcde:2:3:4:5:6:7:8
+No match
+    ::1
+No match
+    abcd:fee0:123::   
+No match
+    :1
+No match
+    1:  
+No match
+
+/[z\Qa-d]\E]/
+    z
+ 0: z
+    a
+ 0: a
+    -
+ 0: -
+    d
+ 0: d
+    ] 
+ 0: ]
+    *** Failers
+ 0: a
+    b     
+No match
+
+/[\z\C]/
+    z
+ 0: z
+    C 
+ 0: C
+    
+/\M/
+    M 
+ 0: M
+    
+/(a+)*b/
+    aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 
+No match
+    
+/(?i)reg(?:ul(?:[aä]|ae)r|ex)/
+    REGular
+ 0: REGular
+    regulaer
+ 0: regulaer
+    Regex  
+ 0: Regex
+    regulär 
+ 0: regul\xe4r
+
+/Åæåä[à-ÿÀ-ß]+/
+    Åæåäà
+ 0: \xc5\xe6\xe5\xe4\xe0
+    Åæåäÿ
+ 0: \xc5\xe6\xe5\xe4\xff
+    ÅæåäÀ
+ 0: \xc5\xe6\xe5\xe4\xc0
+    Åæåäß
+ 0: \xc5\xe6\xe5\xe4\xdf
+
+/(?<=Z)X./
+  \x84XAZXB
+ 0: XB
+
+/ End of testinput1 /

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/testdata/testoutput2
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/testdata/testoutput2	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/testdata/testoutput2	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,5607 @@
+PCRE version 5.0 13-Sep-2004
+
+/(a)b|/
+Capturing subpattern count = 1
+No options
+No first char
+No need char
+
+/abc/
+Capturing subpattern count = 0
+No options
+First char = 'a'
+Need char = 'c'
+    abc
+ 0: abc
+    defabc
+ 0: abc
+    \Aabc
+ 0: abc
+    *** Failers
+No match
+    \Adefabc
+No match
+    ABC
+No match
+
+/^abc/
+Capturing subpattern count = 0
+Options: anchored
+No first char
+No need char
+    abc
+ 0: abc
+    \Aabc
+ 0: abc
+    *** Failers
+No match
+    defabc
+No match
+    \Adefabc
+No match
+
+/a+bc/
+Capturing subpattern count = 0
+Partial matching not supported
+No options
+First char = 'a'
+Need char = 'c'
+
+/a*bc/
+Capturing subpattern count = 0
+Partial matching not supported
+No options
+No first char
+Need char = 'c'
+
+/a{3}bc/
+Capturing subpattern count = 0
+Partial matching not supported
+No options
+First char = 'a'
+Need char = 'c'
+
+/(abc|a+z)/
+Capturing subpattern count = 1
+Partial matching not supported
+No options
+First char = 'a'
+No need char
+
+/^abc$/
+Capturing subpattern count = 0
+Options: anchored
+No first char
+No need char
+    abc
+ 0: abc
+    *** Failers
+No match
+    def\nabc
+No match
+
+/ab\gdef/X
+Failed: unrecognized character follows \ at offset 3
+
+/(?X)ab\gdef/X
+Failed: unrecognized character follows \ at offset 7
+
+/x{5,4}/
+Failed: numbers out of order in {} quantifier at offset 5
+
+/z{65536}/
+Failed: number too big in {} quantifier at offset 7
+
+/[abcd/
+Failed: missing terminating ] for character class at offset 5
+
+/(?X)[\B]/
+Failed: invalid escape sequence in character class at offset 6
+
+/[z-a]/
+Failed: range out of order in character class at offset 3
+
+/^*/
+Failed: nothing to repeat at offset 1
+
+/(abc/
+Failed: missing ) at offset 4
+
+/(?# abc/
+Failed: missing ) after comment at offset 7
+
+/(?z)abc/
+Failed: unrecognized character after (? at offset 2
+
+/.*b/
+Capturing subpattern count = 0
+Partial matching not supported
+No options
+First char at start or follows \n
+Need char = 'b'
+
+/.*?b/
+Capturing subpattern count = 0
+Partial matching not supported
+No options
+First char at start or follows \n
+Need char = 'b'
+
+/cat|dog|elephant/
+Capturing subpattern count = 0
+No options
+No first char
+No need char
+    this sentence eventually mentions a cat
+ 0: cat
+    this sentences rambles on and on for a while and then reaches elephant
+ 0: elephant
+
+/cat|dog|elephant/S
+Capturing subpattern count = 0
+No options
+No first char
+No need char
+Starting byte set: c d e 
+    this sentence eventually mentions a cat
+ 0: cat
+    this sentences rambles on and on for a while and then reaches elephant
+ 0: elephant
+
+/cat|dog|elephant/iS
+Capturing subpattern count = 0
+Options: caseless
+No first char
+No need char
+Starting byte set: C D E c d e 
+    this sentence eventually mentions a CAT cat
+ 0: CAT
+    this sentences rambles on and on for a while to elephant ElePhant
+ 0: elephant
+
+/a|[bcd]/S
+Capturing subpattern count = 0
+No options
+No first char
+No need char
+Starting byte set: a b c d 
+
+/(a|[^\dZ])/S
+Capturing subpattern count = 1
+No options
+No first char
+No need char
+Starting byte set: \x00 \x01 \x02 \x03 \x04 \x05 \x06 \x07 \x08 \x09 \x0a 
+  \x0b \x0c \x0d \x0e \x0f \x10 \x11 \x12 \x13 \x14 \x15 \x16 \x17 \x18 \x19 
+  \x1a \x1b \x1c \x1d \x1e \x1f \x20 ! " # $ % & ' ( ) * + , - . / : ; < = > 
+  ? @ A B C D E F G H I J K L M N O P Q R S T U V W X Y [ \ ] ^ _ ` a b c d 
+  e f g h i j k l m n o p q r s t u v w x y z { | } ~ \x7f \x80 \x81 \x82 \x83 
+  \x84 \x85 \x86 \x87 \x88 \x89 \x8a \x8b \x8c \x8d \x8e \x8f \x90 \x91 \x92 
+  \x93 \x94 \x95 \x96 \x97 \x98 \x99 \x9a \x9b \x9c \x9d \x9e \x9f \xa0 \xa1 
+  \xa2 \xa3 \xa4 \xa5 \xa6 \xa7 \xa8 \xa9 \xaa \xab \xac \xad \xae \xaf \xb0 
+  \xb1 \xb2 \xb3 \xb4 \xb5 \xb6 \xb7 \xb8 \xb9 \xba \xbb \xbc \xbd \xbe \xbf 
+  \xc0 \xc1 \xc2 \xc3 \xc4 \xc5 \xc6 \xc7 \xc8 \xc9 \xca \xcb \xcc \xcd \xce 
+  \xcf \xd0 \xd1 \xd2 \xd3 \xd4 \xd5 \xd6 \xd7 \xd8 \xd9 \xda \xdb \xdc \xdd 
+  \xde \xdf \xe0 \xe1 \xe2 \xe3 \xe4 \xe5 \xe6 \xe7 \xe8 \xe9 \xea \xeb \xec 
+  \xed \xee \xef \xf0 \xf1 \xf2 \xf3 \xf4 \xf5 \xf6 \xf7 \xf8 \xf9 \xfa \xfb 
+  \xfc \xfd \xfe \xff 
+
+/(a|b)*[\s]/S
+Capturing subpattern count = 1
+No options
+No first char
+No need char
+Starting byte set: \x09 \x0a \x0c \x0d \x20 a b 
+
+/(ab\2)/
+Failed: reference to non-existent subpattern at offset 6
+
+/{4,5}abc/
+Failed: nothing to repeat at offset 4
+
+/(a)(b)(c)\2/
+Capturing subpattern count = 3
+Max back reference = 2
+No options
+First char = 'a'
+Need char = 'c'
+    abcb
+ 0: abcb
+ 1: a
+ 2: b
+ 3: c
+    \O0abcb
+Matched, but too many substrings
+    \O3abcb
+Matched, but too many substrings
+ 0: abcb
+    \O6abcb
+Matched, but too many substrings
+ 0: abcb
+ 1: a
+    \O9abcb
+Matched, but too many substrings
+ 0: abcb
+ 1: a
+ 2: b
+    \O12abcb 
+ 0: abcb
+ 1: a
+ 2: b
+ 3: c
+
+/(a)bc|(a)(b)\2/
+Capturing subpattern count = 3
+Max back reference = 2
+No options
+First char = 'a'
+No need char
+    abc
+ 0: abc
+ 1: a
+    \O0abc
+Matched, but too many substrings
+    \O3abc
+Matched, but too many substrings
+ 0: abc
+    \O6abc
+ 0: abc
+ 1: a
+    aba
+ 0: aba
+ 1: <unset>
+ 2: a
+ 3: b
+    \O0aba
+Matched, but too many substrings
+    \O3aba
+Matched, but too many substrings
+ 0: aba
+    \O6aba
+Matched, but too many substrings
+ 0: aba
+ 1: <unset>
+    \O9aba
+Matched, but too many substrings
+ 0: aba
+ 1: <unset>
+ 2: a
+    \O12aba
+ 0: aba
+ 1: <unset>
+ 2: a
+ 3: b
+
+/abc$/E
+Capturing subpattern count = 0
+Options: dollar_endonly
+First char = 'a'
+Need char = 'c'
+    abc
+ 0: abc
+    *** Failers
+No match
+    abc\n
+No match
+    abc\ndef
+No match
+
+/(a)(b)(c)(d)(e)\6/
+Failed: reference to non-existent subpattern at offset 17
+
+/the quick brown fox/
+Capturing subpattern count = 0
+No options
+First char = 't'
+Need char = 'x'
+    the quick brown fox
+ 0: the quick brown fox
+    this is a line with the quick brown fox
+ 0: the quick brown fox
+
+/the quick brown fox/A
+Capturing subpattern count = 0
+Options: anchored
+No first char
+No need char
+    the quick brown fox
+ 0: the quick brown fox
+    *** Failers
+No match
+    this is a line with the quick brown fox
+No match
+
+/ab(?z)cd/
+Failed: unrecognized character after (? at offset 4
+
+/^abc|def/
+Capturing subpattern count = 0
+No options
+No first char
+No need char
+    abcdef
+ 0: abc
+    abcdef\B
+ 0: def
+
+/.*((abc)$|(def))/
+Capturing subpattern count = 3
+Partial matching not supported
+No options
+First char at start or follows \n
+No need char
+    defabc
+ 0: defabc
+ 1: abc
+ 2: abc
+    \Zdefabc
+ 0: def
+ 1: def
+ 2: <unset>
+ 3: def
+
+/abc/P
+    abc
+ 0: abc
+    *** Failers
+No match: POSIX code 17: match failed
+    
+/^abc|def/P
+    abcdef
+ 0: abc
+    abcdef\B
+ 0: def
+
+/.*((abc)$|(def))/P
+    defabc
+ 0: defabc
+ 1: abc
+ 2: abc
+    \Zdefabc
+ 0: def
+ 1: def
+ 3: def
+  
+/the quick brown fox/P
+    the quick brown fox
+ 0: the quick brown fox
+    *** Failers 
+No match: POSIX code 17: match failed
+    The Quick Brown Fox 
+No match: POSIX code 17: match failed
+
+/the quick brown fox/Pi
+    the quick brown fox
+ 0: the quick brown fox
+    The Quick Brown Fox 
+ 0: The Quick Brown Fox
+
+/abc.def/P
+    *** Failers
+No match: POSIX code 17: match failed
+    abc\ndef
+No match: POSIX code 17: match failed
+    
+/abc$/P
+    abc
+ 0: abc
+    abc\n 
+ 0: abc
+
+/(abc)\2/P
+Failed: POSIX code 15: bad back reference at offset 7     
+
+/(abc\1)/P
+    abc
+No match: POSIX code 17: match failed
+
+/)/
+Failed: unmatched parentheses at offset 0
+
+/a[]b/
+Failed: missing terminating ] for character class at offset 4
+
+/[^aeiou ]{3,}/
+Capturing subpattern count = 0
+Partial matching not supported
+No options
+No first char
+No need char
+    co-processors, and for 
+ 0: -pr
+    
+/<.*>/
+Capturing subpattern count = 0
+Partial matching not supported
+No options
+First char = '<'
+Need char = '>'
+    abc<def>ghi<klm>nop
+ 0: <def>ghi<klm>
+
+/<.*?>/
+Capturing subpattern count = 0
+Partial matching not supported
+No options
+First char = '<'
+Need char = '>'
+    abc<def>ghi<klm>nop
+ 0: <def>
+
+/<.*>/U
+Capturing subpattern count = 0
+Partial matching not supported
+Options: ungreedy
+First char = '<'
+Need char = '>'
+    abc<def>ghi<klm>nop
+ 0: <def>
+    
+/(?U)<.*>/
+Capturing subpattern count = 0
+Partial matching not supported
+Options: ungreedy
+First char = '<'
+Need char = '>'
+    abc<def>ghi<klm>nop
+ 0: <def>
+
+/<.*?>/U
+Capturing subpattern count = 0
+Partial matching not supported
+Options: ungreedy
+First char = '<'
+Need char = '>'
+    abc<def>ghi<klm>nop
+ 0: <def>ghi<klm>
+    
+/={3,}/U
+Capturing subpattern count = 0
+Partial matching not supported
+Options: ungreedy
+First char = '='
+Need char = '='
+    abc========def
+ 0: ===
+    
+/(?U)={3,}?/
+Capturing subpattern count = 0
+Partial matching not supported
+Options: ungreedy
+First char = '='
+Need char = '='
+    abc========def
+ 0: ========
+    
+/(?<!bar|cattle)foo/
+Capturing subpattern count = 0
+No options
+First char = 'f'
+Need char = 'o'
+    foo
+ 0: foo
+    catfoo 
+ 0: foo
+    *** Failers
+No match
+    the barfoo
+No match
+    and cattlefoo   
+No match
+
+/(?<=a+)b/
+Failed: lookbehind assertion is not fixed length at offset 6
+
+/(?<=aaa|b{0,3})b/
+Failed: lookbehind assertion is not fixed length at offset 14
+
+/(?<!(foo)a\1)bar/
+Failed: lookbehind assertion is not fixed length at offset 12
+
+/(?i)abc/
+Capturing subpattern count = 0
+Options: caseless
+First char = 'a' (caseless)
+Need char = 'c' (caseless)
+
+/(a|(?m)a)/
+Capturing subpattern count = 1
+No options
+First char = 'a'
+No need char
+
+/(?i)^1234/
+Capturing subpattern count = 0
+Options: anchored caseless
+No first char
+No need char
+
+/(^b|(?i)^d)/
+Capturing subpattern count = 1
+Options: anchored
+Case state changes
+No first char
+No need char
+
+/(?s).*/
+Capturing subpattern count = 0
+Partial matching not supported
+Options: anchored dotall
+No first char
+No need char
+
+/[abcd]/S
+Capturing subpattern count = 0
+No options
+No first char
+No need char
+Starting byte set: a b c d 
+
+/(?i)[abcd]/S
+Capturing subpattern count = 0
+Options: caseless
+No first char
+No need char
+Starting byte set: A B C D a b c d 
+
+/(?m)[xy]|(b|c)/S
+Capturing subpattern count = 1
+Options: multiline
+No first char
+No need char
+Starting byte set: b c x y 
+
+/(^a|^b)/m
+Capturing subpattern count = 1
+Options: multiline
+First char at start or follows \n
+No need char
+
+/(?i)(^a|^b)/m
+Capturing subpattern count = 1
+Options: caseless multiline
+First char at start or follows \n
+No need char
+
+/(a)(?(1)a|b|c)/
+Failed: conditional group contains more than two branches at offset 13
+
+/(?(?=a)a|b|c)/
+Failed: conditional group contains more than two branches at offset 12
+
+/(?(1a)/
+Failed: malformed number after (?( at offset 4
+
+/(?(?i))/
+Failed: assertion expected after (?( at offset 3
+
+/(?(abc))/
+Failed: assertion expected after (?( at offset 3
+
+/(?(?<ab))/
+Failed: unrecognized character after (?< at offset 5
+
+/((?s)blah)\s+\1/
+Capturing subpattern count = 1
+Max back reference = 1
+Partial matching not supported
+No options
+First char = 'b'
+Need char = 'h'
+
+/((?i)blah)\s+\1/
+Capturing subpattern count = 1
+Max back reference = 1
+Partial matching not supported
+No options
+Case state changes
+First char = 'b' (caseless)
+Need char = 'h' (caseless)
+
+/((?i)b)/DS
+------------------------------------------------------------------
+  0  15 Bra 0
+  3   7 Bra 1
+  6  01 Opt
+  8  NC b
+ 10   7 Ket
+ 13  00 Opt
+ 15  15 Ket
+ 18     End
+------------------------------------------------------------------
+Capturing subpattern count = 1
+No options
+Case state changes
+First char = 'b' (caseless)
+No need char
+Study returned NULL
+
+/(a*b|(?i:c*(?-i)d))/S
+Capturing subpattern count = 1
+Partial matching not supported
+No options
+Case state changes
+No first char
+No need char
+Starting byte set: C a b c d 
+
+/a$/
+Capturing subpattern count = 0
+No options
+First char = 'a'
+No need char
+    a
+ 0: a
+    a\n
+ 0: a
+    *** Failers 
+No match
+    \Za
+No match
+    \Za\n   
+No match
+
+/a$/m
+Capturing subpattern count = 0
+Options: multiline
+First char = 'a'
+No need char
+    a
+ 0: a
+    a\n
+ 0: a
+    \Za\n   
+ 0: a
+    *** Failers 
+No match
+    \Za
+No match
+    
+/\Aabc/m
+Capturing subpattern count = 0
+Options: anchored multiline
+No first char
+No need char
+
+/^abc/m 
+Capturing subpattern count = 0
+Options: multiline
+First char at start or follows \n
+Need char = 'c'
+
+/^((a+)(?U)([ab]+)(?-U)([bc]+)(\w*))/
+Capturing subpattern count = 5
+Partial matching not supported
+Options: anchored
+No first char
+No need char
+  aaaaabbbbbcccccdef
+ 0: aaaaabbbbbcccccdef
+ 1: aaaaabbbbbcccccdef
+ 2: aaaaa
+ 3: b
+ 4: bbbbccccc
+ 5: def
+
+/(?<=foo)[ab]/S
+Capturing subpattern count = 0
+No options
+No first char
+No need char
+Starting byte set: a b 
+
+/(?<!foo)(alpha|omega)/S
+Capturing subpattern count = 1
+No options
+No first char
+Need char = 'a'
+Starting byte set: a o 
+
+/(?!alphabet)[ab]/S
+Capturing subpattern count = 0
+No options
+No first char
+No need char
+Starting byte set: a b 
+
+/(?<=foo\n)^bar/m
+Capturing subpattern count = 0
+Options: multiline
+No first char
+Need char = 'r'
+    foo\nbarbar 
+ 0: bar
+    ***Failers
+No match
+    rhubarb 
+No match
+    barbell
+No match
+    abc\nbarton 
+No match
+
+/^(?<=foo\n)bar/m
+Capturing subpattern count = 0
+Options: multiline
+First char at start or follows \n
+Need char = 'r'
+    foo\nbarbar 
+ 0: bar
+    ***Failers
+No match
+    rhubarb 
+No match
+    barbell
+No match
+    abc\nbarton 
+No match
+
+/(?>^abc)/m
+Capturing subpattern count = 0
+Options: multiline
+First char at start or follows \n
+Need char = 'c'
+    abc
+ 0: abc
+    def\nabc
+ 0: abc
+    *** Failers
+No match
+    defabc   
+No match
+
+/(?<=ab(c+)d)ef/
+Failed: lookbehind assertion is not fixed length at offset 11
+
+/(?<=ab(?<=c+)d)ef/
+Failed: lookbehind assertion is not fixed length at offset 12
+
+/(?<=ab(c|de)f)g/
+Failed: lookbehind assertion is not fixed length at offset 13
+
+/The next three are in testinput2 because they have variable length branches/
+Capturing subpattern count = 0
+No options
+First char = 'T'
+Need char = 's'
+
+/(?<=bullock|donkey)-cart/
+Capturing subpattern count = 0
+No options
+First char = '-'
+Need char = 't'
+    the bullock-cart
+ 0: -cart
+    a donkey-cart race
+ 0: -cart
+    *** Failers
+No match
+    cart
+No match
+    horse-and-cart    
+No match
+      
+/(?<=ab(?i)x|y|z)/
+Capturing subpattern count = 0
+No options
+Case state changes
+No first char
+No need char
+
+/(?>.*)(?<=(abcd)|(xyz))/
+Capturing subpattern count = 2
+Partial matching not supported
+No options
+First char at start or follows \n
+No need char
+    alphabetabcd
+ 0: alphabetabcd
+ 1: abcd
+    endingxyz
+ 0: endingxyz
+ 1: <unset>
+ 2: xyz
+
+/(?<=ab(?i)x(?-i)y|(?i)z|b)ZZ/
+Capturing subpattern count = 0
+No options
+Case state changes
+First char = 'Z'
+Need char = 'Z'
+    abxyZZ
+ 0: ZZ
+    abXyZZ
+ 0: ZZ
+    ZZZ
+ 0: ZZ
+    zZZ
+ 0: ZZ
+    bZZ
+ 0: ZZ
+    BZZ     
+ 0: ZZ
+    *** Failers
+No match
+    ZZ 
+No match
+    abXYZZ 
+No match
+    zzz
+No match
+    bzz  
+No match
+
+/(?<!(foo)a)bar/
+Capturing subpattern count = 1
+No options
+First char = 'b'
+Need char = 'r'
+    bar
+ 0: bar
+    foobbar 
+ 0: bar
+    *** Failers
+No match
+    fooabar  
+No match
+
+/This one is here because Perl 5.005_02 doesn't fail it/
+Capturing subpattern count = 0
+No options
+First char = 'T'
+Need char = 't'
+
+/^(a)?(?(1)a|b)+$/
+Capturing subpattern count = 1
+Options: anchored
+No first char
+No need char
+    *** Failers
+No match
+    a 
+No match
+
+/This one is here because I think Perl 5.005_02 gets the setting of $1 wrong/
+Capturing subpattern count = 0
+No options
+First char = 'T'
+Need char = 'g'
+
+/^(a\1?){4}$/
+Capturing subpattern count = 1
+Max back reference = 1
+Options: anchored
+No first char
+No need char
+    aaaaaa
+ 0: aaaaaa
+ 1: aa
+    
+/These are syntax tests from Perl 5.005/
+Capturing subpattern count = 0
+No options
+First char = 'T'
+Need char = '5'
+
+/a[b-a]/
+Failed: range out of order in character class at offset 4
+
+/a[]b/
+Failed: missing terminating ] for character class at offset 4
+
+/a[/
+Failed: missing terminating ] for character class at offset 2
+
+/*a/
+Failed: nothing to repeat at offset 0
+
+/(*)b/
+Failed: nothing to repeat at offset 1
+
+/abc)/
+Failed: unmatched parentheses at offset 3
+
+/(abc/
+Failed: missing ) at offset 4
+
+/a**/
+Failed: nothing to repeat at offset 2
+
+/)(/
+Failed: unmatched parentheses at offset 0
+
+/\1/
+Failed: reference to non-existent subpattern at offset 2
+
+/\2/
+Failed: reference to non-existent subpattern at offset 2
+
+/(a)|\2/
+Failed: reference to non-existent subpattern at offset 6
+
+/a[b-a]/i
+Failed: range out of order in character class at offset 4
+
+/a[]b/i
+Failed: missing terminating ] for character class at offset 4
+
+/a[/i
+Failed: missing terminating ] for character class at offset 2
+
+/*a/i
+Failed: nothing to repeat at offset 0
+
+/(*)b/i
+Failed: nothing to repeat at offset 1
+
+/abc)/i
+Failed: unmatched parentheses at offset 3
+
+/(abc/i
+Failed: missing ) at offset 4
+
+/a**/i
+Failed: nothing to repeat at offset 2
+
+/)(/i
+Failed: unmatched parentheses at offset 0
+
+/:(?:/
+Failed: missing ) at offset 4
+
+/(?<%)b/
+Failed: unrecognized character after (?< at offset 3
+
+/a(?{)b/
+Failed: unrecognized character after (? at offset 3
+
+/a(?{{})b/
+Failed: unrecognized character after (? at offset 3
+
+/a(?{}})b/
+Failed: unrecognized character after (? at offset 3
+
+/a(?{"{"})b/
+Failed: unrecognized character after (? at offset 3
+
+/a(?{"{"}})b/
+Failed: unrecognized character after (? at offset 3
+
+/(?(1?)a|b)/
+Failed: malformed number after (?( at offset 4
+
+/(?(1)a|b|c)/
+Failed: conditional group contains more than two branches at offset 10
+
+/[a[:xyz:/
+Failed: missing terminating ] for character class at offset 8
+
+/(?<=x+)y/
+Failed: lookbehind assertion is not fixed length at offset 6
+
+/a{37,17}/
+Failed: numbers out of order in {} quantifier at offset 7
+
+/abc/\
+Failed: \ at end of pattern at offset 4
+
+/abc/\P
+Failed: POSIX code 9: bad escape sequence at offset 4     
+
+/abc/\i
+Failed: \ at end of pattern at offset 4
+
+/(a)bc(d)/
+Capturing subpattern count = 2
+No options
+First char = 'a'
+Need char = 'd'
+    abcd
+ 0: abcd
+ 1: a
+ 2: d
+    abcd\C2
+ 0: abcd
+ 1: a
+ 2: d
+ 2C d (1)
+    abcd\C5
+ 0: abcd
+ 1: a
+ 2: d
+copy substring 5 failed -7
+     
+/(.{20})/
+Capturing subpattern count = 1
+Partial matching not supported
+No options
+No first char
+No need char
+    abcdefghijklmnopqrstuvwxyz
+ 0: abcdefghijklmnopqrst
+ 1: abcdefghijklmnopqrst
+    abcdefghijklmnopqrstuvwxyz\C1
+ 0: abcdefghijklmnopqrst
+ 1: abcdefghijklmnopqrst
+copy substring 1 failed -6
+    abcdefghijklmnopqrstuvwxyz\G1
+ 0: abcdefghijklmnopqrst
+ 1: abcdefghijklmnopqrst
+ 1G abcdefghijklmnopqrst (20)
+     
+/(.{15})/
+Capturing subpattern count = 1
+Partial matching not supported
+No options
+No first char
+No need char
+    abcdefghijklmnopqrstuvwxyz
+ 0: abcdefghijklmno
+ 1: abcdefghijklmno
+    abcdefghijklmnopqrstuvwxyz\C1\G1
+ 0: abcdefghijklmno
+ 1: abcdefghijklmno
+ 1C abcdefghijklmno (15)
+ 1G abcdefghijklmno (15)
+
+/(.{16})/
+Capturing subpattern count = 1
+Partial matching not supported
+No options
+No first char
+No need char
+    abcdefghijklmnopqrstuvwxyz
+ 0: abcdefghijklmnop
+ 1: abcdefghijklmnop
+    abcdefghijklmnopqrstuvwxyz\C1\G1\L
+ 0: abcdefghijklmnop
+ 1: abcdefghijklmnop
+copy substring 1 failed -6
+ 1G abcdefghijklmnop (16)
+ 0L abcdefghijklmnop
+ 1L abcdefghijklmnop
+    
+/^(a|(bc))de(f)/
+Capturing subpattern count = 3
+Options: anchored
+No first char
+No need char
+    adef\G1\G2\G3\G4\L 
+ 0: adef
+ 1: a
+ 2: <unset>
+ 3: f
+ 1G a (1)
+ 2G  (0)
+ 3G f (1)
+get substring 4 failed -7
+ 0L adef
+ 1L a
+ 2L 
+ 3L f
+    bcdef\G1\G2\G3\G4\L 
+ 0: bcdef
+ 1: bc
+ 2: bc
+ 3: f
+ 1G bc (2)
+ 2G bc (2)
+ 3G f (1)
+get substring 4 failed -7
+ 0L bcdef
+ 1L bc
+ 2L bc
+ 3L f
+    adefghijk\C0 
+ 0: adef
+ 1: a
+ 2: <unset>
+ 3: f
+ 0C adef (4)
+    
+/^abc\00def/
+Capturing subpattern count = 0
+Options: anchored
+No first char
+No need char
+    abc\00def\L\C0 
+ 0: abc\x00def
+ 0C abc (7)
+ 0L abc
+    
+/word ((?:[a-zA-Z0-9]+ )((?:[a-zA-Z0-9]+ )((?:[a-zA-Z0-9]+ )((?:[a-zA-Z0-9]+ 
+)((?:[a-zA-Z0-9]+ )((?:[a-zA-Z0-9]+ )((?:[a-zA-Z0-9]+ )((?:[a-zA-Z0-9]+ 
+)?)?)?)?)?)?)?)?)?otherword/M
+Memory allocation (code space): 432
+Capturing subpattern count = 8
+Partial matching not supported
+No options
+First char = 'w'
+Need char = 'd'
+
+/.*X/D
+------------------------------------------------------------------
+  0   7 Bra 0
+  3     Any*
+  5     X
+  7   7 Ket
+ 10     End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Partial matching not supported
+No options
+First char at start or follows \n
+Need char = 'X'
+
+/.*X/Ds
+------------------------------------------------------------------
+  0   7 Bra 0
+  3     Any*
+  5     X
+  7   7 Ket
+ 10     End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Partial matching not supported
+Options: anchored dotall
+No first char
+Need char = 'X'
+
+/(.*X|^B)/D
+------------------------------------------------------------------
+  0  19 Bra 0
+  3   7 Bra 1
+  6     Any*
+  8     X
+ 10   6 Alt
+ 13     ^
+ 14     B
+ 16  13 Ket
+ 19  19 Ket
+ 22     End
+------------------------------------------------------------------
+Capturing subpattern count = 1
+Partial matching not supported
+No options
+First char at start or follows \n
+No need char
+
+/(.*X|^B)/Ds
+------------------------------------------------------------------
+  0  19 Bra 0
+  3   7 Bra 1
+  6     Any*
+  8     X
+ 10   6 Alt
+ 13     ^
+ 14     B
+ 16  13 Ket
+ 19  19 Ket
+ 22     End
+------------------------------------------------------------------
+Capturing subpattern count = 1
+Partial matching not supported
+Options: anchored dotall
+No first char
+No need char
+    
+/(?s)(.*X|^B)/D
+------------------------------------------------------------------
+  0  19 Bra 0
+  3   7 Bra 1
+  6     Any*
+  8     X
+ 10   6 Alt
+ 13     ^
+ 14     B
+ 16  13 Ket
+ 19  19 Ket
+ 22     End
+------------------------------------------------------------------
+Capturing subpattern count = 1
+Partial matching not supported
+Options: anchored dotall
+No first char
+No need char
+
+/(?s:.*X|^B)/D
+------------------------------------------------------------------
+  0  25 Bra 0
+  3   9 Bra 0
+  6  04 Opt
+  8     Any*
+ 10     X
+ 12   8 Alt
+ 15  04 Opt
+ 17     ^
+ 18     B
+ 20  17 Ket
+ 23  00 Opt
+ 25  25 Ket
+ 28     End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Partial matching not supported
+No options
+First char at start or follows \n
+No need char
+
+/\Biss\B/+
+Capturing subpattern count = 0
+No options
+First char = 'i'
+Need char = 's'
+    Mississippi
+ 0: iss
+ 0+ issippi
+
+/\Biss\B/+P
+    Mississippi
+ 0: iss
+ 0+ issippi
+
+/iss/G+
+Capturing subpattern count = 0
+No options
+First char = 'i'
+Need char = 's'
+    Mississippi
+ 0: iss
+ 0+ issippi
+ 0: iss
+ 0+ ippi
+
+/\Biss\B/G+
+Capturing subpattern count = 0
+No options
+First char = 'i'
+Need char = 's'
+    Mississippi
+ 0: iss
+ 0+ issippi
+
+/\Biss\B/g+
+Capturing subpattern count = 0
+No options
+First char = 'i'
+Need char = 's'
+    Mississippi
+ 0: iss
+ 0+ issippi
+ 0: iss
+ 0+ ippi
+    *** Failers
+No match
+    Mississippi\A
+No match
+
+/(?<=[Ms])iss/g+
+Capturing subpattern count = 0
+No options
+First char = 'i'
+Need char = 's'
+    Mississippi
+ 0: iss
+ 0+ issippi
+ 0: iss
+ 0+ ippi
+
+/(?<=[Ms])iss/G+
+Capturing subpattern count = 0
+No options
+First char = 'i'
+Need char = 's'
+    Mississippi
+ 0: iss
+ 0+ issippi
+
+/^iss/g+
+Capturing subpattern count = 0
+Options: anchored
+No first char
+No need char
+    ississippi
+ 0: iss
+ 0+ issippi
+    
+/.*iss/g+
+Capturing subpattern count = 0
+Partial matching not supported
+No options
+First char at start or follows \n
+Need char = 's'
+    abciss\nxyzisspqr 
+ 0: abciss
+ 0+ \x0axyzisspqr
+ 0: xyziss
+ 0+ pqr
+
+/.i./+g
+Capturing subpattern count = 0
+No options
+No first char
+Need char = 'i'
+    Mississippi
+ 0: Mis
+ 0+ sissippi
+ 0: sis
+ 0+ sippi
+ 0: sip
+ 0+ pi
+    Mississippi\A
+ 0: Mis
+ 0+ sissippi
+ 0: sis
+ 0+ sippi
+ 0: sip
+ 0+ pi
+    Missouri river
+ 0: Mis
+ 0+ souri river
+ 0: ri 
+ 0+ river
+ 0: riv
+ 0+ er
+    Missouri river\A  
+ 0: Mis
+ 0+ souri river
+
+/^.is/+g
+Capturing subpattern count = 0
+Options: anchored
+No first char
+No need char
+    Mississippi
+ 0: Mis
+ 0+ sissippi
+
+/^ab\n/g+
+Capturing subpattern count = 0
+Options: anchored
+No first char
+No need char
+    ab\nab\ncd
+ 0: ab\x0a
+ 0+ ab\x0acd
+
+/^ab\n/mg+
+Capturing subpattern count = 0
+Options: multiline
+First char at start or follows \n
+Need char = 10
+    ab\nab\ncd
+ 0: ab\x0a
+ 0+ ab\x0acd
+ 0: ab\x0a
+ 0+ cd
+
+/abc/
+Capturing subpattern count = 0
+No options
+First char = 'a'
+Need char = 'c'
+
+/abc|bac/
+Capturing subpattern count = 0
+No options
+No first char
+Need char = 'c'
+
+/(abc|bac)/
+Capturing subpattern count = 1
+No options
+No first char
+Need char = 'c'
+
+/(abc|(c|dc))/
+Capturing subpattern count = 2
+No options
+No first char
+Need char = 'c'
+
+/(abc|(d|de)c)/
+Capturing subpattern count = 2
+No options
+No first char
+Need char = 'c'
+
+/a*/
+Capturing subpattern count = 0
+Partial matching not supported
+No options
+No first char
+No need char
+
+/a+/
+Capturing subpattern count = 0
+Partial matching not supported
+No options
+First char = 'a'
+No need char
+
+/(baa|a+)/
+Capturing subpattern count = 1
+Partial matching not supported
+No options
+No first char
+Need char = 'a'
+
+/a{0,3}/
+Capturing subpattern count = 0
+Partial matching not supported
+No options
+No first char
+No need char
+
+/baa{3,}/
+Capturing subpattern count = 0
+Partial matching not supported
+No options
+First char = 'b'
+Need char = 'a'
+
+/"([^\\"]+|\\.)*"/
+Capturing subpattern count = 1
+Partial matching not supported
+No options
+First char = '"'
+Need char = '"'
+
+/(abc|ab[cd])/
+Capturing subpattern count = 1
+No options
+First char = 'a'
+No need char
+
+/(a|.)/
+Capturing subpattern count = 1
+No options
+No first char
+No need char
+
+/a|ba|\w/
+Capturing subpattern count = 0
+No options
+No first char
+No need char
+
+/abc(?=pqr)/
+Capturing subpattern count = 0
+No options
+First char = 'a'
+Need char = 'r'
+
+/...(?<=abc)/
+Capturing subpattern count = 0
+No options
+No first char
+No need char
+
+/abc(?!pqr)/
+Capturing subpattern count = 0
+No options
+First char = 'a'
+Need char = 'c'
+
+/ab./
+Capturing subpattern count = 0
+No options
+First char = 'a'
+Need char = 'b'
+
+/ab[xyz]/
+Capturing subpattern count = 0
+No options
+First char = 'a'
+Need char = 'b'
+
+/abc*/
+Capturing subpattern count = 0
+Partial matching not supported
+No options
+First char = 'a'
+Need char = 'b'
+
+/ab.c*/
+Capturing subpattern count = 0
+Partial matching not supported
+No options
+First char = 'a'
+Need char = 'b'
+
+/a.c*/
+Capturing subpattern count = 0
+Partial matching not supported
+No options
+First char = 'a'
+No need char
+
+/.c*/
+Capturing subpattern count = 0
+Partial matching not supported
+No options
+No first char
+No need char
+
+/ac*/
+Capturing subpattern count = 0
+Partial matching not supported
+No options
+First char = 'a'
+No need char
+
+/(a.c*|b.c*)/
+Capturing subpattern count = 1
+Partial matching not supported
+No options
+No first char
+No need char
+
+/a.c*|aba/
+Capturing subpattern count = 0
+Partial matching not supported
+No options
+First char = 'a'
+No need char
+
+/.+a/
+Capturing subpattern count = 0
+Partial matching not supported
+No options
+No first char
+Need char = 'a'
+
+/(?=abcda)a.*/
+Capturing subpattern count = 0
+Partial matching not supported
+No options
+First char = 'a'
+Need char = 'a'
+
+/(?=a)a.*/
+Capturing subpattern count = 0
+Partial matching not supported
+No options
+First char = 'a'
+No need char
+
+/a(b)*/
+Capturing subpattern count = 1
+No options
+First char = 'a'
+No need char
+
+/a\d*/
+Capturing subpattern count = 0
+Partial matching not supported
+No options
+First char = 'a'
+No need char
+
+/ab\d*/
+Capturing subpattern count = 0
+Partial matching not supported
+No options
+First char = 'a'
+Need char = 'b'
+
+/a(\d)*/
+Capturing subpattern count = 1
+No options
+First char = 'a'
+No need char
+
+/abcde{0,0}/
+Capturing subpattern count = 0
+No options
+First char = 'a'
+Need char = 'd'
+
+/ab\d+/
+Capturing subpattern count = 0
+Partial matching not supported
+No options
+First char = 'a'
+Need char = 'b'
+
+/a(?(1)b)/
+Capturing subpattern count = 0
+No options
+First char = 'a'
+No need char
+
+/a(?(1)bag|big)/
+Capturing subpattern count = 0
+No options
+First char = 'a'
+Need char = 'g'
+
+/a(?(1)bag|big)*/
+Capturing subpattern count = 0
+No options
+First char = 'a'
+No need char
+
+/a(?(1)bag|big)+/
+Capturing subpattern count = 0
+No options
+First char = 'a'
+Need char = 'g'
+
+/a(?(1)b..|b..)/
+Capturing subpattern count = 0
+No options
+First char = 'a'
+Need char = 'b'
+
+/ab\d{0}e/
+Capturing subpattern count = 0
+No options
+First char = 'a'
+Need char = 'e'
+
+/a?b?/
+Capturing subpattern count = 0
+No options
+No first char
+No need char
+    a
+ 0: a
+    b
+ 0: b
+    ab
+ 0: ab
+    \
+ 0: 
+    *** Failers
+ 0: 
+    \N     
+No match
+    
+/|-/
+Capturing subpattern count = 0
+No options
+No first char
+No need char
+    abcd
+ 0: 
+    -abc
+ 0: 
+    \Nab-c
+ 0: -
+    *** Failers
+ 0: 
+    \Nabc     
+No match
+
+/a*(b+)(z)(z)/P
+    aaaabbbbzzzz
+ 0: aaaabbbbzz
+ 1: bbbb
+ 2: z
+ 3: z
+    aaaabbbbzzzz\O0
+    aaaabbbbzzzz\O1
+ 0: aaaabbbbzz
+    aaaabbbbzzzz\O2
+ 0: aaaabbbbzz
+ 1: bbbb
+    aaaabbbbzzzz\O3
+ 0: aaaabbbbzz
+ 1: bbbb
+ 2: z
+    aaaabbbbzzzz\O4
+ 0: aaaabbbbzz
+ 1: bbbb
+ 2: z
+ 3: z
+    aaaabbbbzzzz\O5
+ 0: aaaabbbbzz
+ 1: bbbb
+ 2: z
+ 3: z
+    
+/^.?abcd/S 
+Capturing subpattern count = 0
+Options: anchored
+No first char
+Need char = 'd'
+Study returned NULL
+
+/\(             # ( at start
+  (?:           # Non-capturing bracket
+  (?>[^()]+)    # Either a sequence of non-brackets (no backtracking)
+  |             # Or
+  (?R)          # Recurse - i.e. nested bracketed string
+  )*            # Zero or more contents
+  \)            # Closing )
+  /x
+Capturing subpattern count = 0
+Partial matching not supported
+Options: extended
+First char = '('
+Need char = ')'
+    (abcd)
+ 0: (abcd)
+    (abcd)xyz
+ 0: (abcd)
+    xyz(abcd)
+ 0: (abcd)
+    (ab(xy)cd)pqr 
+ 0: (ab(xy)cd)
+    (ab(xycd)pqr 
+ 0: (xycd)
+    () abc () 
+ 0: ()
+    12(abcde(fsh)xyz(foo(bar))lmno)89
+ 0: (abcde(fsh)xyz(foo(bar))lmno)
+    *** Failers
+No match
+    abcd 
+No match
+    abcd)
+No match
+    (abcd  
+No match
+
+/\(  ( (?>[^()]+) | (?R) )* \) /xg
+Capturing subpattern count = 1
+Partial matching not supported
+Options: extended
+First char = '('
+Need char = ')'
+    (ab(xy)cd)pqr 
+ 0: (ab(xy)cd)
+ 1: cd
+    1(abcd)(x(y)z)pqr
+ 0: (abcd)
+ 1: abcd
+ 0: (x(y)z)
+ 1: z
+
+/\(  (?: (?>[^()]+) | (?R) ) \) /x
+Capturing subpattern count = 0
+Partial matching not supported
+Options: extended
+First char = '('
+Need char = ')'
+    (abcd)
+ 0: (abcd)
+    (ab(xy)cd)
+ 0: (xy)
+    (a(b(c)d)e) 
+ 0: (c)
+    ((ab)) 
+ 0: ((ab))
+    *** Failers
+No match
+    ()   
+No match
+
+/\(  (?: (?>[^()]+) | (?R) )? \) /x
+Capturing subpattern count = 0
+Partial matching not supported
+Options: extended
+First char = '('
+Need char = ')'
+    ()
+ 0: ()
+    12(abcde(fsh)xyz(foo(bar))lmno)89
+ 0: (fsh)
+
+/\(  ( (?>[^()]+) | (?R) )* \) /x
+Capturing subpattern count = 1
+Partial matching not supported
+Options: extended
+First char = '('
+Need char = ')'
+    (ab(xy)cd)
+ 0: (ab(xy)cd)
+ 1: cd
+
+/\( ( ( (?>[^()]+) | (?R) )* ) \) /x
+Capturing subpattern count = 2
+Partial matching not supported
+Options: extended
+First char = '('
+Need char = ')'
+    (ab(xy)cd)
+ 0: (ab(xy)cd)
+ 1: ab(xy)cd
+ 2: cd
+
+/\( (123)? ( ( (?>[^()]+) | (?R) )* ) \) /x
+Capturing subpattern count = 3
+Partial matching not supported
+Options: extended
+First char = '('
+Need char = ')'
+    (ab(xy)cd)
+ 0: (ab(xy)cd)
+ 1: <unset>
+ 2: ab(xy)cd
+ 3: cd
+    (123ab(xy)cd)
+ 0: (123ab(xy)cd)
+ 1: 123
+ 2: ab(xy)cd
+ 3: cd
+
+/\( ( (123)? ( (?>[^()]+) | (?R) )* ) \) /x
+Capturing subpattern count = 3
+Partial matching not supported
+Options: extended
+First char = '('
+Need char = ')'
+    (ab(xy)cd)
+ 0: (ab(xy)cd)
+ 1: ab(xy)cd
+ 2: <unset>
+ 3: cd
+    (123ab(xy)cd)
+ 0: (123ab(xy)cd)
+ 1: 123ab(xy)cd
+ 2: 123
+ 3: cd
+
+/\( (((((((((( ( (?>[^()]+) | (?R) )* )))))))))) \) /x
+Capturing subpattern count = 11
+Partial matching not supported
+Options: extended
+First char = '('
+Need char = ')'
+    (ab(xy)cd)
+ 0: (ab(xy)cd)
+ 1: ab(xy)cd
+ 2: ab(xy)cd
+ 3: ab(xy)cd
+ 4: ab(xy)cd
+ 5: ab(xy)cd
+ 6: ab(xy)cd
+ 7: ab(xy)cd
+ 8: ab(xy)cd
+ 9: ab(xy)cd
+10: ab(xy)cd
+11: cd
+
+/\( ( ( (?>[^()<>]+) | ((?>[^()]+)) | (?R) )* ) \) /x
+Capturing subpattern count = 3
+Partial matching not supported
+Options: extended
+First char = '('
+Need char = ')'
+    (abcd(xyz<p>qrs)123)
+ 0: (abcd(xyz<p>qrs)123)
+ 1: abcd(xyz<p>qrs)123
+ 2: 123
+ 3: <unset>
+
+/\( ( ( (?>[^()]+) | ((?R)) )* ) \) /x
+Capturing subpattern count = 3
+Partial matching not supported
+Options: extended
+First char = '('
+Need char = ')'
+    (ab(cd)ef)
+ 0: (ab(cd)ef)
+ 1: ab(cd)ef
+ 2: ef
+ 3: (cd)
+    (ab(cd(ef)gh)ij)
+ 0: (ab(cd(ef)gh)ij)
+ 1: ab(cd(ef)gh)ij
+ 2: ij
+ 3: (cd(ef)gh)
+
+/^[[:alnum:]]/D
+------------------------------------------------------------------
+  0  37 Bra 0
+  3     ^
+  4     [0-9A-Za-z]
+ 37  37 Ket
+ 40     End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Options: anchored
+No first char
+No need char
+
+/^[[:^alnum:]]/D
+------------------------------------------------------------------
+  0  37 Bra 0
+  3     ^
+  4     [\x00-/:-@[-`{-\xff]
+ 37  37 Ket
+ 40     End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Options: anchored
+No first char
+No need char
+
+/^[[:alpha:]]/D
+------------------------------------------------------------------
+  0  37 Bra 0
+  3     ^
+  4     [A-Za-z]
+ 37  37 Ket
+ 40     End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Options: anchored
+No first char
+No need char
+
+/^[[:^alpha:]]/D
+------------------------------------------------------------------
+  0  37 Bra 0
+  3     ^
+  4     [\x00-@[-`{-\xff]
+ 37  37 Ket
+ 40     End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Options: anchored
+No first char
+No need char
+             
+/^[[:ascii:]]/D
+------------------------------------------------------------------
+  0  37 Bra 0
+  3     ^
+  4     [\x00-\x7f]
+ 37  37 Ket
+ 40     End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Options: anchored
+No first char
+No need char
+
+/^[[:^ascii:]]/D
+------------------------------------------------------------------
+  0  37 Bra 0
+  3     ^
+  4     [\x80-\xff]
+ 37  37 Ket
+ 40     End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Options: anchored
+No first char
+No need char
+
+/^[[:blank:]]/D
+------------------------------------------------------------------
+  0  37 Bra 0
+  3     ^
+  4     [\x09 ]
+ 37  37 Ket
+ 40     End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Options: anchored
+No first char
+No need char
+
+/^[[:cntrl:]]/D
+------------------------------------------------------------------
+  0  37 Bra 0
+  3     ^
+  4     [\x00-\x1f\x7f]
+ 37  37 Ket
+ 40     End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Options: anchored
+No first char
+No need char
+
+/^[[:digit:]]/D
+------------------------------------------------------------------
+  0  37 Bra 0
+  3     ^
+  4     [0-9]
+ 37  37 Ket
+ 40     End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Options: anchored
+No first char
+No need char
+
+/^[[:graph:]]/D
+------------------------------------------------------------------
+  0  37 Bra 0
+  3     ^
+  4     [!-~]
+ 37  37 Ket
+ 40     End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Options: anchored
+No first char
+No need char
+
+/^[[:lower:]]/D
+------------------------------------------------------------------
+  0  37 Bra 0
+  3     ^
+  4     [a-z]
+ 37  37 Ket
+ 40     End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Options: anchored
+No first char
+No need char
+
+/^[[:print:]]/D
+------------------------------------------------------------------
+  0  37 Bra 0
+  3     ^
+  4     [ -~]
+ 37  37 Ket
+ 40     End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Options: anchored
+No first char
+No need char
+
+/^[[:punct:]]/D
+------------------------------------------------------------------
+  0  37 Bra 0
+  3     ^
+  4     [!-/:-@[-`{-~]
+ 37  37 Ket
+ 40     End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Options: anchored
+No first char
+No need char
+
+/^[[:space:]]/D
+------------------------------------------------------------------
+  0  37 Bra 0
+  3     ^
+  4     [\x09-\x0d ]
+ 37  37 Ket
+ 40     End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Options: anchored
+No first char
+No need char
+
+/^[[:upper:]]/D
+------------------------------------------------------------------
+  0  37 Bra 0
+  3     ^
+  4     [A-Z]
+ 37  37 Ket
+ 40     End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Options: anchored
+No first char
+No need char
+
+/^[[:xdigit:]]/D
+------------------------------------------------------------------
+  0  37 Bra 0
+  3     ^
+  4     [0-9A-Fa-f]
+ 37  37 Ket
+ 40     End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Options: anchored
+No first char
+No need char
+
+/^[[:word:]]/D
+------------------------------------------------------------------
+  0  37 Bra 0
+  3     ^
+  4     [0-9A-Z_a-z]
+ 37  37 Ket
+ 40     End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Options: anchored
+No first char
+No need char
+
+/^[[:^cntrl:]]/D
+------------------------------------------------------------------
+  0  37 Bra 0
+  3     ^
+  4     [ -~\x80-\xff]
+ 37  37 Ket
+ 40     End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Options: anchored
+No first char
+No need char
+
+/^[12[:^digit:]]/D
+------------------------------------------------------------------
+  0  37 Bra 0
+  3     ^
+  4     [\x00-/12:-\xff]
+ 37  37 Ket
+ 40     End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Options: anchored
+No first char
+No need char
+
+/^[[:^blank:]]/D
+------------------------------------------------------------------
+  0  37 Bra 0
+  3     ^
+  4     [\x00-\x08\x0a-\x1f!-\xff]
+ 37  37 Ket
+ 40     End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Options: anchored
+No first char
+No need char
+
+/[01[:alpha:]%]/D
+------------------------------------------------------------------
+  0  36 Bra 0
+  3     [%01A-Za-z]
+ 36  36 Ket
+ 39     End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+No options
+No first char
+No need char
+
+/[[.ch.]]/
+Failed: POSIX collating elements are not supported at offset 1
+
+/[[=ch=]]/
+Failed: POSIX collating elements are not supported at offset 1
+
+/[[:rhubarb:]]/
+Failed: unknown POSIX class name at offset 3
+
+/[[:upper:]]/i
+Capturing subpattern count = 0
+Options: caseless
+No first char
+No need char
+    A
+ 0: A
+    a 
+ 0: a
+    
+/[[:lower:]]/i
+Capturing subpattern count = 0
+Options: caseless
+No first char
+No need char
+    A
+ 0: A
+    a 
+ 0: a
+
+/((?-i)[[:lower:]])[[:lower:]]/i
+Capturing subpattern count = 1
+Options: caseless
+Case state changes
+No first char
+No need char
+    ab
+ 0: ab
+ 1: a
+    aB
+ 0: aB
+ 1: a
+    *** Failers
+ 0: ai
+ 1: a
+    Ab
+No match
+    AB        
+No match
+
+/[\200-\410]/
+Failed: range out of order in character class at offset 9
+
+/^(?(0)f|b)oo/
+Failed: invalid condition (?(0) at offset 5
+
+/This one's here because of the large output vector needed/
+Capturing subpattern count = 0
+No options
+First char = 'T'
+Need char = 'd'
+
+/(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\d+(?:\s|$))(\w+)\s+(\270)/
+Capturing subpattern count = 271
+Max back reference = 270
+Partial matching not supported
+No options
+No first char
+No need char
+    \O900 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 ABC ABC
+ 0: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 ABC ABC
+ 1: 1 
+ 2: 2 
+ 3: 3 
+ 4: 4 
+ 5: 5 
+ 6: 6 
+ 7: 7 
+ 8: 8 
+ 9: 9 
+10: 10 
+11: 11 
+12: 12 
+13: 13 
+14: 14 
+15: 15 
+16: 16 
+17: 17 
+18: 18 
+19: 19 
+20: 20 
+21: 21 
+22: 22 
+23: 23 
+24: 24 
+25: 25 
+26: 26 
+27: 27 
+28: 28 
+29: 29 
+30: 30 
+31: 31 
+32: 32 
+33: 33 
+34: 34 
+35: 35 
+36: 36 
+37: 37 
+38: 38 
+39: 39 
+40: 40 
+41: 41 
+42: 42 
+43: 43 
+44: 44 
+45: 45 
+46: 46 
+47: 47 
+48: 48 
+49: 49 
+50: 50 
+51: 51 
+52: 52 
+53: 53 
+54: 54 
+55: 55 
+56: 56 
+57: 57 
+58: 58 
+59: 59 
+60: 60 
+61: 61 
+62: 62 
+63: 63 
+64: 64 
+65: 65 
+66: 66 
+67: 67 
+68: 68 
+69: 69 
+70: 70 
+71: 71 
+72: 72 
+73: 73 
+74: 74 
+75: 75 
+76: 76 
+77: 77 
+78: 78 
+79: 79 
+80: 80 
+81: 81 
+82: 82 
+83: 83 
+84: 84 
+85: 85 
+86: 86 
+87: 87 
+88: 88 
+89: 89 
+90: 90 
+91: 91 
+92: 92 
+93: 93 
+94: 94 
+95: 95 
+96: 96 
+97: 97 
+98: 98 
+99: 99 
+100: 100 
+101: 101 
+102: 102 
+103: 103 
+104: 104 
+105: 105 
+106: 106 
+107: 107 
+108: 108 
+109: 109 
+110: 110 
+111: 111 
+112: 112 
+113: 113 
+114: 114 
+115: 115 
+116: 116 
+117: 117 
+118: 118 
+119: 119 
+120: 120 
+121: 121 
+122: 122 
+123: 123 
+124: 124 
+125: 125 
+126: 126 
+127: 127 
+128: 128 
+129: 129 
+130: 130 
+131: 131 
+132: 132 
+133: 133 
+134: 134 
+135: 135 
+136: 136 
+137: 137 
+138: 138 
+139: 139 
+140: 140 
+141: 141 
+142: 142 
+143: 143 
+144: 144 
+145: 145 
+146: 146 
+147: 147 
+148: 148 
+149: 149 
+150: 150 
+151: 151 
+152: 152 
+153: 153 
+154: 154 
+155: 155 
+156: 156 
+157: 157 
+158: 158 
+159: 159 
+160: 160 
+161: 161 
+162: 162 
+163: 163 
+164: 164 
+165: 165 
+166: 166 
+167: 167 
+168: 168 
+169: 169 
+170: 170 
+171: 171 
+172: 172 
+173: 173 
+174: 174 
+175: 175 
+176: 176 
+177: 177 
+178: 178 
+179: 179 
+180: 180 
+181: 181 
+182: 182 
+183: 183 
+184: 184 
+185: 185 
+186: 186 
+187: 187 
+188: 188 
+189: 189 
+190: 190 
+191: 191 
+192: 192 
+193: 193 
+194: 194 
+195: 195 
+196: 196 
+197: 197 
+198: 198 
+199: 199 
+200: 200 
+201: 201 
+202: 202 
+203: 203 
+204: 204 
+205: 205 
+206: 206 
+207: 207 
+208: 208 
+209: 209 
+210: 210 
+211: 211 
+212: 212 
+213: 213 
+214: 214 
+215: 215 
+216: 216 
+217: 217 
+218: 218 
+219: 219 
+220: 220 
+221: 221 
+222: 222 
+223: 223 
+224: 224 
+225: 225 
+226: 226 
+227: 227 
+228: 228 
+229: 229 
+230: 230 
+231: 231 
+232: 232 
+233: 233 
+234: 234 
+235: 235 
+236: 236 
+237: 237 
+238: 238 
+239: 239 
+240: 240 
+241: 241 
+242: 242 
+243: 243 
+244: 244 
+245: 245 
+246: 246 
+247: 247 
+248: 248 
+249: 249 
+250: 250 
+251: 251 
+252: 252 
+253: 253 
+254: 254 
+255: 255 
+256: 256 
+257: 257 
+258: 258 
+259: 259 
+260: 260 
+261: 261 
+262: 262 
+263: 263 
+264: 264 
+265: 265 
+266: 266 
+267: 267 
+268: 268 
+269: 269 
+270: ABC
+271: ABC
+
+/This one's here because Perl does this differently and PCRE can't at present/
+Capturing subpattern count = 0
+No options
+First char = 'T'
+Need char = 't'
+
+/(main(O)?)+/
+Capturing subpattern count = 2
+No options
+First char = 'm'
+Need char = 'n'
+    mainmain
+ 0: mainmain
+ 1: main
+    mainOmain
+ 0: mainOmain
+ 1: main
+ 2: O
+    
+/These are all cases where Perl does it differently (nested captures)/
+Capturing subpattern count = 1
+No options
+First char = 'T'
+Need char = 's'
+
+/^(a(b)?)+$/
+Capturing subpattern count = 2
+Options: anchored
+No first char
+No need char
+    aba
+ 0: aba
+ 1: a
+ 2: b
+   
+/^(aa(bb)?)+$/
+Capturing subpattern count = 2
+Options: anchored
+No first char
+No need char
+    aabbaa    
+ 0: aabbaa
+ 1: aa
+ 2: bb
+    
+/^(aa|aa(bb))+$/
+Capturing subpattern count = 2
+Options: anchored
+No first char
+No need char
+    aabbaa 
+ 0: aabbaa
+ 1: aa
+ 2: bb
+    
+/^(aa(bb)??)+$/
+Capturing subpattern count = 2
+Options: anchored
+No first char
+No need char
+    aabbaa    
+ 0: aabbaa
+ 1: aa
+ 2: bb
+    
+/^(?:aa(bb)?)+$/
+Capturing subpattern count = 1
+Options: anchored
+No first char
+No need char
+    aabbaa    
+ 0: aabbaa
+ 1: bb
+    
+/^(aa(b(b))?)+$/
+Capturing subpattern count = 3
+Options: anchored
+No first char
+No need char
+    aabbaa    
+ 0: aabbaa
+ 1: aa
+ 2: bb
+ 3: b
+
+/^(?:aa(b(b))?)+$/
+Capturing subpattern count = 2
+Options: anchored
+No first char
+No need char
+    aabbaa    
+ 0: aabbaa
+ 1: bb
+ 2: b
+
+/^(?:aa(b(?:b))?)+$/
+Capturing subpattern count = 1
+Options: anchored
+No first char
+No need char
+    aabbaa    
+ 0: aabbaa
+ 1: bb
+
+/^(?:aa(bb(?:b))?)+$/
+Capturing subpattern count = 1
+Options: anchored
+No first char
+No need char
+    aabbbaa    
+ 0: aabbbaa
+ 1: bbb
+    
+/^(?:aa(b(?:bb))?)+$/
+Capturing subpattern count = 1
+Options: anchored
+No first char
+No need char
+    aabbbaa    
+ 0: aabbbaa
+ 1: bbb
+
+/^(?:aa(?:b(b))?)+$/
+Capturing subpattern count = 1
+Options: anchored
+No first char
+No need char
+    aabbaa    
+ 0: aabbaa
+ 1: b
+
+/^(?:aa(?:b(bb))?)+$/
+Capturing subpattern count = 1
+Options: anchored
+No first char
+No need char
+    aabbbaa    
+ 0: aabbbaa
+ 1: bb
+
+/^(aa(b(bb))?)+$/
+Capturing subpattern count = 3
+Options: anchored
+No first char
+No need char
+    aabbbaa    
+ 0: aabbbaa
+ 1: aa
+ 2: bbb
+ 3: bb
+
+/^(aa(bb(bb))?)+$/
+Capturing subpattern count = 3
+Options: anchored
+No first char
+No need char
+    aabbbbaa    
+ 0: aabbbbaa
+ 1: aa
+ 2: bbbb
+ 3: bb
+
+/--------------------------------------------------------------------/ 
+Capturing subpattern count = 0
+No options
+First char = '-'
+Need char = '-'
+    
+/#/xMD
+Memory allocation (code space): 7
+------------------------------------------------------------------
+  0   3 Bra 0
+  3   3 Ket
+  6     End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Options: extended
+No first char
+No need char
+
+/a#/xMD
+Memory allocation (code space): 9
+------------------------------------------------------------------
+  0   5 Bra 0
+  3     a
+  5   5 Ket
+  8     End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Options: extended
+First char = 'a'
+No need char
+
+/[\s]/D
+------------------------------------------------------------------
+  0  36 Bra 0
+  3     [\x09\x0a\x0c\x0d ]
+ 36  36 Ket
+ 39     End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+No options
+No first char
+No need char
+
+/[\S]/D
+------------------------------------------------------------------
+  0  36 Bra 0
+  3     [\x00-\x08\x0b\x0e-\x1f!-\xff]
+ 36  36 Ket
+ 39     End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+No options
+No first char
+No need char
+
+/a(?i)b/D
+------------------------------------------------------------------
+  0   9 Bra 0
+  3     a
+  5  01 Opt
+  7  NC b
+  9   9 Ket
+ 12     End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+No options
+Case state changes
+First char = 'a'
+Need char = 'b' (caseless)
+    ab
+ 0: ab
+    aB
+ 0: aB
+    *** Failers 
+No match
+    AB  
+No match
+
+/(a(?i)b)/D
+------------------------------------------------------------------
+  0  17 Bra 0
+  3   9 Bra 1
+  6     a
+  8  01 Opt
+ 10  NC b
+ 12   9 Ket
+ 15  00 Opt
+ 17  17 Ket
+ 20     End
+------------------------------------------------------------------
+Capturing subpattern count = 1
+No options
+Case state changes
+First char = 'a'
+Need char = 'b' (caseless)
+    ab
+ 0: ab
+ 1: ab
+    aB
+ 0: aB
+ 1: aB
+    *** Failers 
+No match
+    AB  
+No match
+    
+/   (?i)abc/xD
+------------------------------------------------------------------
+  0   9 Bra 0
+  3  NC abc
+  9   9 Ket
+ 12     End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Options: caseless extended
+First char = 'a' (caseless)
+Need char = 'c' (caseless)
+
+/#this is a comment
+  (?i)abc/xD
+------------------------------------------------------------------
+  0   9 Bra 0
+  3  NC abc
+  9   9 Ket
+ 12     End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Options: caseless extended
+First char = 'a' (caseless)
+Need char = 'c' (caseless)
+
+/123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890/D
+------------------------------------------------------------------
+  0 603 Bra 0
+  3     123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+603 603 Ket
+606     End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+No options
+First char = '1'
+Need char = '0'
+
+/\Q123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890/D
+------------------------------------------------------------------
+  0 603 Bra 0
+  3     123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+603 603 Ket
+606     End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+No options
+First char = '1'
+Need char = '0'
+
+/\Q\E/D
+------------------------------------------------------------------
+  0   3 Bra 0
+  3   3 Ket
+  6     End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+No options
+No first char
+No need char
+    \
+ 0: 
+
+/\Q\Ex/D
+------------------------------------------------------------------
+  0   5 Bra 0
+  3     x
+  5   5 Ket
+  8     End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+No options
+First char = 'x'
+No need char
+
+/ \Q\E/D
+------------------------------------------------------------------
+  0   5 Bra 0
+  3      
+  5   5 Ket
+  8     End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+No options
+First char = ' '
+No need char
+
+/a\Q\E/D
+------------------------------------------------------------------
+  0   5 Bra 0
+  3     a
+  5   5 Ket
+  8     End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+No options
+First char = 'a'
+No need char
+  abc
+ 0: a
+  bca
+ 0: a
+  bac  
+ 0: a
+
+/a\Q\Eb/D
+------------------------------------------------------------------
+  0   7 Bra 0
+  3     ab
+  7   7 Ket
+ 10     End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+No options
+First char = 'a'
+Need char = 'b'
+  abc
+ 0: ab
+
+/\Q\Eabc/D
+------------------------------------------------------------------
+  0   9 Bra 0
+  3     abc
+  9   9 Ket
+ 12     End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+No options
+First char = 'a'
+Need char = 'c'
+
+/x*+\w/D
+------------------------------------------------------------------
+  0  12 Bra 0
+  3   5 Once
+  6     x*
+  8   5 Ket
+ 11     \w
+ 12  12 Ket
+ 15     End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Partial matching not supported
+No options
+No first char
+No need char
+    *** Failers
+ 0: F
+    xxxxx
+No match
+    
+/x?+/D
+------------------------------------------------------------------
+  0  11 Bra 0
+  3   5 Once
+  6     x?
+  8   5 Ket
+ 11  11 Ket
+ 14     End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+No options
+No first char
+No need char
+
+/x++/D
+------------------------------------------------------------------
+  0  11 Bra 0
+  3   5 Once
+  6     x+
+  8   5 Ket
+ 11  11 Ket
+ 14     End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Partial matching not supported
+No options
+First char = 'x'
+No need char
+
+/x{1,3}+/D 
+------------------------------------------------------------------
+  0  15 Bra 0
+  3   9 Once
+  6     x
+  8     x{,2}
+ 12   9 Ket
+ 15  15 Ket
+ 18     End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Partial matching not supported
+No options
+First char = 'x'
+No need char
+
+/(x)*+/D
+------------------------------------------------------------------
+  0  18 Bra 0
+  3  12 Once
+  6     Brazero
+  7   5 Bra 1
+ 10     x
+ 12   5 KetRmax
+ 15  12 Ket
+ 18  18 Ket
+ 21     End
+------------------------------------------------------------------
+Capturing subpattern count = 1
+No options
+No first char
+No need char
+
+/^(\w++|\s++)*$/
+Capturing subpattern count = 1
+Partial matching not supported
+Options: anchored
+No first char
+No need char
+    now is the time for all good men to come to the aid of the party
+ 0: now is the time for all good men to come to the aid of the party
+ 1: party
+    *** Failers
+No match
+    this is not a line with only words and spaces!
+No match
+    
+/(\d++)(\w)/
+Capturing subpattern count = 2
+Partial matching not supported
+No options
+No first char
+No need char
+    12345a
+ 0: 12345a
+ 1: 12345
+ 2: a
+    *** Failers
+No match
+    12345+ 
+No match
+
+/a++b/
+Capturing subpattern count = 0
+Partial matching not supported
+No options
+First char = 'a'
+Need char = 'b'
+    aaab
+ 0: aaab
+
+/(a++b)/
+Capturing subpattern count = 1
+Partial matching not supported
+No options
+First char = 'a'
+Need char = 'b'
+    aaab
+ 0: aaab
+ 1: aaab
+
+/(a++)b/
+Capturing subpattern count = 1
+Partial matching not supported
+No options
+First char = 'a'
+Need char = 'b'
+    aaab
+ 0: aaab
+ 1: aaa
+
+/([^()]++|\([^()]*\))+/
+Capturing subpattern count = 1
+Partial matching not supported
+No options
+No first char
+No need char
+    ((abc(ade)ufh()()x
+ 0: abc(ade)ufh()()x
+ 1: x
+    
+/\(([^()]++|\([^()]+\))+\)/ 
+Capturing subpattern count = 1
+Partial matching not supported
+No options
+First char = '('
+Need char = ')'
+    (abc)
+ 0: (abc)
+ 1: abc
+    (abc(def)xyz)
+ 0: (abc(def)xyz)
+ 1: xyz
+    *** Failers
+No match
+    ((()aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa   
+No match
+
+/(abc){1,3}+/D
+------------------------------------------------------------------
+  0  53 Bra 0
+  3  47 Once
+  6   9 Bra 1
+  9     abc
+ 15   9 Ket
+ 18     Brazero
+ 19  28 Bra 0
+ 22   9 Bra 1
+ 25     abc
+ 31   9 Ket
+ 34     Brazero
+ 35   9 Bra 1
+ 38     abc
+ 44   9 Ket
+ 47  28 Ket
+ 50  47 Ket
+ 53  53 Ket
+ 56     End
+------------------------------------------------------------------
+Capturing subpattern count = 1
+No options
+First char = 'a'
+Need char = 'c'
+
+/a+?+/
+Failed: nothing to repeat at offset 3
+
+/a{2,3}?+b/
+Failed: nothing to repeat at offset 7
+
+/(?U)a+?+/
+Failed: nothing to repeat at offset 7
+
+/a{2,3}?+b/U
+Failed: nothing to repeat at offset 7
+
+/x(?U)a++b/D
+------------------------------------------------------------------
+  0  15 Bra 0
+  3     x
+  5   5 Once
+  8     a+
+ 10   5 Ket
+ 13     b
+ 15  15 Ket
+ 18     End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Partial matching not supported
+No options
+First char = 'x'
+Need char = 'b'
+    xaaaab
+ 0: xaaaab
+
+/(?U)xa++b/D
+------------------------------------------------------------------
+  0  15 Bra 0
+  3     x
+  5   5 Once
+  8     a+
+ 10   5 Ket
+ 13     b
+ 15  15 Ket
+ 18     End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Partial matching not supported
+Options: ungreedy
+First char = 'x'
+Need char = 'b'
+    xaaaab
+ 0: xaaaab
+
+/^((a+)(?U)([ab]+)(?-U)([bc]+)(\w*))/D
+------------------------------------------------------------------
+  0 106 Bra 0
+  3     ^
+  4  99 Bra 1
+  7   5 Bra 2
+ 10     a+
+ 12   5 Ket
+ 15  37 Bra 3
+ 18     [ab]+?
+ 52  37 Ket
+ 55  37 Bra 4
+ 58     [bc]+
+ 92  37 Ket
+ 95   5 Bra 5
+ 98     \w*
+100   5 Ket
+103  99 Ket
+106 106 Ket
+109     End
+------------------------------------------------------------------
+Capturing subpattern count = 5
+Partial matching not supported
+Options: anchored
+No first char
+No need char
+
+/^x(?U)a+b/D
+------------------------------------------------------------------
+  0  10 Bra 0
+  3     ^
+  4     x
+  6     a+?
+  8     b
+ 10  10 Ket
+ 13     End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Partial matching not supported
+Options: anchored
+No first char
+Need char = 'b'
+
+/^x(?U)(a+)b/D
+------------------------------------------------------------------
+  0  16 Bra 0
+  3     ^
+  4     x
+  6   5 Bra 1
+  9     a+?
+ 11   5 Ket
+ 14     b
+ 16  16 Ket
+ 19     End
+------------------------------------------------------------------
+Capturing subpattern count = 1
+Partial matching not supported
+Options: anchored
+No first char
+Need char = 'b'
+
+/[.x.]/
+Failed: POSIX collating elements are not supported at offset 0
+
+/[=x=]/
+Failed: POSIX collating elements are not supported at offset 0
+
+/[:x:]/
+Failed: POSIX named classes are supported only within a class at offset 0
+
+/\l/
+Failed: PCRE does not support \L, \l, \N, \U, or \u at offset 1
+
+/\L/
+Failed: PCRE does not support \L, \l, \N, \U, or \u at offset 1
+
+/\N{name}/
+Failed: PCRE does not support \L, \l, \N, \U, or \u at offset 1
+
+/\u/
+Failed: PCRE does not support \L, \l, \N, \U, or \u at offset 1
+
+/\U/
+Failed: PCRE does not support \L, \l, \N, \U, or \u at offset 1
+
+/[/
+Failed: missing terminating ] for character class at offset 1
+
+/[a-/
+Failed: missing terminating ] for character class at offset 3
+
+/[[:space:]/
+Failed: missing terminating ] for character class at offset 10
+
+/[\s]/DM
+Memory allocation (code space): 40
+------------------------------------------------------------------
+  0  36 Bra 0
+  3     [\x09\x0a\x0c\x0d ]
+ 36  36 Ket
+ 39     End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+No options
+No first char
+No need char
+
+/[[:space:]]/DM
+Memory allocation (code space): 40
+------------------------------------------------------------------
+  0  36 Bra 0
+  3     [\x09-\x0d ]
+ 36  36 Ket
+ 39     End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+No options
+No first char
+No need char
+
+/[[:space:]abcde]/DM
+Memory allocation (code space): 40
+------------------------------------------------------------------
+  0  36 Bra 0
+  3     [\x09-\x0d a-e]
+ 36  36 Ket
+ 39     End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+No options
+No first char
+No need char
+
+/< (?: (?(R) \d++  | [^<>]*+) | (?R)) * >/x
+Capturing subpattern count = 0
+Partial matching not supported
+Options: extended
+First char = '<'
+Need char = '>'
+    <>
+ 0: <>
+    <abcd>
+ 0: <abcd>
+    <abc <123> hij>
+ 0: <abc <123> hij>
+    <abc <def> hij>
+ 0: <def>
+    <abc<>def> 
+ 0: <abc<>def>
+    <abc<>      
+ 0: <>
+    *** Failers
+No match
+    <abc
+No match
+
+|8J\$WE\<\.rX\+ix\[d1b\!H\#\?vV0vrK\:ZH1\=2M\>iV\;\?aPhFB\<\*vW\@QW\@sO9\}cfZA\-i\'w\%hKd6gt1UJP\,15_\#QY\$M\^Mss_U\/\]\&LK9\[5vQub\^w\[KDD\<EjmhUZ\?\.akp2dF\>qmj\;2\}YWFdYx\.Ap\]hjCPTP\(n28k\+3\;o\&WXqs\/gOXdr\$\:r\'do0\;b4c\(f_Gr\=\"\\4\)\[01T7ajQJvL\$W\~mL_sS\/4h\:x\*\[ZN\=KLs\&L5zX\/\/\>it\,o\:aU\(\;Z\>pW\&T7oP\'2K\^E\:x9\'c\[\%z\-\,64JQ5AeH_G\#KijUKghQw\^\\vea3a\?kka_G\$8\#\`\*kynsxzBLru\'\]k_\[7FrVx\}\^\=\$blx\>s\-N\%j\;D\*aZDnsw\:YKZ\%Q\.Kne9\#hP\?\+b3\(SOvL\,\^\;\&u5\@\?5C5Bhb\=m\-vEh_L15Jl\]U\)0RP6\{q\%L\^_z5E\'Dw6X\b|DM
+Memory allocation (code space): 826
+------------------------------------------------------------------
+  0 822 Bra 0
+  3     8J$WE<.rX+ix[d1b!H#?vV0vrK:ZH1=2M>iV;?aPhFB<*vW at QW@sO9}cfZA-i'w%hKd6gt1UJP,15_#QY$M^Mss_U/]&LK9[5vQub^w[KDD<EjmhUZ?.akp2dF>qmj;2}YWFdYx.Ap]hjCPTP(n28k+3;o&WXqs/gOXdr$:r'do0;b4c(f_Gr="\4)[01T7ajQJvL$W~mL_sS/4h:x*[ZN=KLs&L5zX//>it,o:aU(;Z>pW&T7oP'2K^E:x9'c[%z-,64JQ5AeH_G#KijUKghQw^\vea3a?kka_G$8#`*kynsxzBLru']k_[7FrVx}^=$blx>s-N%j;D*aZDnsw:YKZ%Q.Kne9#hP?+b3(SOvL,^;&u5@?5C5Bhb=m-vEh_L15Jl]U)0RP6{q%L^_z5E'Dw6X
+821     \b
+822 822 Ket
+825     End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+No options
+First char = '8'
+Need char = 'X'
+
+|\$\<\.X\+ix\[d1b\!H\#\?vV0vrK\:ZH1\=2M\>iV\;\?aPhFB\<\*vW\@QW\@sO9\}cfZA\-i\'w\%hKd6gt1UJP\,15_\#QY\$M\^Mss_U\/\]\&LK9\[5vQub\^w\[KDD\<EjmhUZ\?\.akp2dF\>qmj\;2\}YWFdYx\.Ap\]hjCPTP\(n28k\+3\;o\&WXqs\/gOXdr\$\:r\'do0\;b4c\(f_Gr\=\"\\4\)\[01T7ajQJvL\$W\~mL_sS\/4h\:x\*\[ZN\=KLs\&L5zX\/\/\>it\,o\:aU\(\;Z\>pW\&T7oP\'2K\^E\:x9\'c\[\%z\-\,64JQ5AeH_G\#KijUKghQw\^\\vea3a\?kka_G\$8\#\`\*kynsxzBLru\'\]k_\[7FrVx\}\^\=\$blx\>s\-N\%j\;D\*aZDnsw\:YKZ\%Q\.Kne9\#hP\?\+b3\(SOvL\,\^\;\&u5\@\?5C5Bhb\=m\-vEh_L15Jl\]U\)0RP6\{q\%L\^_z5E\'Dw6X\b|DM
+Memory allocation (code space): 816
+------------------------------------------------------------------
+  0 812 Bra 0
+  3     $<.X+ix[d1b!H#?vV0vrK:ZH1=2M>iV;?aPhFB<*vW at QW@sO9}cfZA-i'w%hKd6gt1UJP,15_#QY$M^Mss_U/]&LK9[5vQub^w[KDD<EjmhUZ?.akp2dF>qmj;2}YWFdYx.Ap]hjCPTP(n28k+3;o&WXqs/gOXdr$:r'do0;b4c(f_Gr="\4)[01T7ajQJvL$W~mL_sS/4h:x*[ZN=KLs&L5zX//>it,o:aU(;Z>pW&T7oP'2K^E:x9'c[%z-,64JQ5AeH_G#KijUKghQw^\vea3a?kka_G$8#`*kynsxzBLru']k_[7FrVx}^=$blx>s-N%j;D*aZDnsw:YKZ%Q.Kne9#hP?+b3(SOvL,^;&u5@?5C5Bhb=m-vEh_L15Jl]U)0RP6{q%L^_z5E'Dw6X
+811     \b
+812 812 Ket
+815     End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+No options
+First char = '$'
+Need char = 'X'
+
+/(.*)\d+\1/I
+Capturing subpattern count = 1
+Max back reference = 1
+Partial matching not supported
+No options
+No first char
+No need char
+
+/(.*)\d+/I
+Capturing subpattern count = 1
+Partial matching not supported
+No options
+First char at start or follows \n
+No need char
+    
+/(.*)\d+\1/Is
+Capturing subpattern count = 1
+Max back reference = 1
+Partial matching not supported
+Options: dotall
+No first char
+No need char
+
+/(.*)\d+/Is
+Capturing subpattern count = 1
+Partial matching not supported
+Options: anchored dotall
+No first char
+No need char
+
+/(.*(xyz))\d+\2/I
+Capturing subpattern count = 2
+Max back reference = 2
+Partial matching not supported
+No options
+First char at start or follows \n
+Need char = 'z'
+
+/((.*))\d+\1/I
+Capturing subpattern count = 2
+Max back reference = 1
+Partial matching not supported
+No options
+No first char
+No need char
+    abc123bc
+ 0: bc123bc
+ 1: bc
+ 2: bc
+    
+/a[b]/I
+Capturing subpattern count = 0
+No options
+First char = 'a'
+Need char = 'b'
+
+/(?=a).*/I
+Capturing subpattern count = 0
+Partial matching not supported
+No options
+First char = 'a'
+No need char
+
+/(?=abc).xyz/iI
+Capturing subpattern count = 0
+Options: caseless
+First char = 'a' (caseless)
+Need char = 'z' (caseless)
+
+/(?=abc)(?i).xyz/I
+Capturing subpattern count = 0
+No options
+Case state changes
+First char = 'a'
+Need char = 'z' (caseless)
+
+/(?=a)(?=b)/I
+Capturing subpattern count = 0
+No options
+First char = 'a'
+No need char
+
+/(?=.)a/I
+Capturing subpattern count = 0
+No options
+First char = 'a'
+No need char
+
+/((?=abcda)a)/I
+Capturing subpattern count = 1
+No options
+First char = 'a'
+Need char = 'a'
+
+/((?=abcda)ab)/I
+Capturing subpattern count = 1
+No options
+First char = 'a'
+Need char = 'b'
+
+/()a/I
+Capturing subpattern count = 1
+No options
+No first char
+Need char = 'a'
+
+/(?(1)ab|ac)/I
+Capturing subpattern count = 0
+No options
+First char = 'a'
+No need char
+
+/(?(1)abz|acz)/I
+Capturing subpattern count = 0
+No options
+First char = 'a'
+Need char = 'z'
+
+/(?(1)abz)/I
+Capturing subpattern count = 0
+No options
+No first char
+No need char
+
+/(?(1)abz)123/I
+Capturing subpattern count = 0
+No options
+No first char
+Need char = '3'
+
+/(a)+/I
+Capturing subpattern count = 1
+No options
+First char = 'a'
+No need char
+
+/(a){2,3}/I
+Capturing subpattern count = 1
+No options
+First char = 'a'
+Need char = 'a'
+
+/(a)*/I
+Capturing subpattern count = 1
+No options
+No first char
+No need char
+
+/[a]/I
+Capturing subpattern count = 0
+No options
+First char = 'a'
+No need char
+
+/[ab]/I
+Capturing subpattern count = 0
+No options
+No first char
+No need char
+
+/[ab]/IS
+Capturing subpattern count = 0
+No options
+No first char
+No need char
+Starting byte set: a b 
+
+/[^a]/I
+Capturing subpattern count = 0
+No options
+No first char
+No need char
+
+/\d456/I
+Capturing subpattern count = 0
+No options
+No first char
+Need char = '6'
+
+/\d456/IS
+Capturing subpattern count = 0
+No options
+No first char
+Need char = '6'
+Starting byte set: 0 1 2 3 4 5 6 7 8 9 
+
+/a^b/I
+Capturing subpattern count = 0
+No options
+First char = 'a'
+Need char = 'b'
+
+/^a/mI
+Capturing subpattern count = 0
+Options: multiline
+First char at start or follows \n
+Need char = 'a'
+  abcde
+ 0: a
+  xy\nabc 
+ 0: a
+  *** Failers 
+No match
+  xyabc 
+No match
+
+/c|abc/I
+Capturing subpattern count = 0
+No options
+No first char
+Need char = 'c'
+
+/(?i)[ab]/IS
+Capturing subpattern count = 0
+Options: caseless
+No first char
+No need char
+Starting byte set: A B a b 
+
+/[ab](?i)cd/IS
+Capturing subpattern count = 0
+No options
+Case state changes
+No first char
+Need char = 'd' (caseless)
+Starting byte set: a b 
+
+/abc(?C)def/
+Capturing subpattern count = 0
+No options
+First char = 'a'
+Need char = 'f'
+    abcdef
+--->abcdef
+  0 ^  ^       d
+ 0: abcdef
+    1234abcdef 
+--->1234abcdef
+  0     ^  ^       d
+ 0: abcdef
+    *** Failers
+No match
+    abcxyz
+No match
+    abcxyzf   
+--->abcxyzf
+  0 ^  ^        d
+No match
+
+/abc(?C)de(?C1)f/
+Capturing subpattern count = 0
+No options
+First char = 'a'
+Need char = 'f'
+    123abcdef
+--->123abcdef
+  0    ^  ^       d
+  1    ^    ^     f
+ 0: abcdef
+    
+/(?C1)\dabc(?C2)def/ 
+Capturing subpattern count = 0
+No options
+No first char
+Need char = 'f'
+    1234abcdef
+--->1234abcdef
+  1 ^              \d
+  1  ^             \d
+  1   ^            \d
+  1    ^           \d
+  2    ^   ^       d
+ 0: 4abcdef
+    *** Failers
+No match
+    abcdef 
+--->abcdef
+  1 ^          \d
+  1  ^         \d
+  1   ^        \d
+  1    ^       \d
+  1     ^      \d
+  1      ^     \d
+No match
+    
+/(?C255)ab/
+Capturing subpattern count = 0
+No options
+First char = 'a'
+Need char = 'b'
+
+/(?C256)ab/
+Failed: number after (?C is > 255 at offset 6
+
+/(?Cab)xx/ 
+Failed: closing ) for (?C expected at offset 3
+
+/(?C12vr)x/
+Failed: closing ) for (?C expected at offset 5
+
+/abc(?C)def/
+Capturing subpattern count = 0
+No options
+First char = 'a'
+Need char = 'f'
+    *** Failers
+No match
+    \x83\x0\x61bcdef
+--->\x83\x00abcdef
+  0         ^  ^       d
+ 0: abcdef
+
+/(abc)(?C)de(?C1)f/
+Capturing subpattern count = 1
+No options
+First char = 'a'
+Need char = 'f'
+    123abcdef
+--->123abcdef
+  0    ^  ^       d
+  1    ^    ^     f
+ 0: abcdef
+ 1: abc
+    123abcdef\C+ 
+Callout 0: last capture = 1
+ 0: <unset>
+ 1: abc
+--->123abcdef
+       ^  ^       d
+Callout 1: last capture = 1
+ 0: <unset>
+ 1: abc
+--->123abcdef
+       ^    ^     f
+ 0: abcdef
+ 1: abc
+    123abcdef\C- 
+ 0: abcdef
+ 1: abc
+    *** Failers
+No match
+    123abcdef\C!1 
+--->123abcdef
+  0    ^  ^       d
+  1    ^    ^     f
+No match
+    
+/(?C0)(abc(?C1))*/
+Capturing subpattern count = 1
+No options
+No first char
+No need char
+    abcabcabc
+--->abcabcabc
+  0 ^             (abc(?C1))*
+  1 ^  ^          )
+  1 ^     ^       )
+  1 ^        ^    )
+ 0: abcabcabc
+ 1: abc
+    abcabc\C!1!3   
+--->abcabc
+  0 ^          (abc(?C1))*
+  1 ^  ^       )
+  1 ^     ^    )
+ 0: abcabc
+ 1: abc
+    *** Failers
+--->*** Failers
+  0 ^               (abc(?C1))*
+ 0: 
+    abcabcabc\C!1!3   
+--->abcabcabc
+  0 ^             (abc(?C1))*
+  1 ^  ^          )
+  1 ^     ^       )
+  1 ^        ^    )
+ 0: abcabc
+ 1: abc
+
+/(\d{3}(?C))*/
+Capturing subpattern count = 1
+Partial matching not supported
+No options
+No first char
+No need char
+    123\C+
+Callout 0: last capture = -1
+ 0: <unset>
+--->123
+    ^  ^    )
+ 0: 123
+ 1: 123
+    123456\C+
+Callout 0: last capture = -1
+ 0: <unset>
+--->123456
+    ^  ^       )
+Callout 0: last capture = 1
+ 0: <unset>
+ 1: 123
+--->123456
+    ^     ^    )
+ 0: 123456
+ 1: 456
+    123456789\C+  
+Callout 0: last capture = -1
+ 0: <unset>
+--->123456789
+    ^  ^          )
+Callout 0: last capture = 1
+ 0: <unset>
+ 1: 123
+--->123456789
+    ^     ^       )
+Callout 0: last capture = 1
+ 0: <unset>
+ 1: 456
+--->123456789
+    ^        ^    )
+ 0: 123456789
+ 1: 789
+
+/((xyz)(?C)p|(?C1)xyzabc)/
+Capturing subpattern count = 2
+No options
+First char = 'x'
+No need char
+    xyzabc\C+
+Callout 0: last capture = 2
+ 0: <unset>
+ 1: <unset>
+ 2: xyz
+--->xyzabc
+    ^  ^       p
+Callout 1: last capture = -1
+ 0: <unset>
+--->xyzabc
+    ^          x
+ 0: xyzabc
+ 1: xyzabc
+
+/(X)((xyz)(?C)p|(?C1)xyzabc)/
+Capturing subpattern count = 3
+No options
+First char = 'X'
+Need char = 'x'
+    Xxyzabc\C+
+Callout 0: last capture = 3
+ 0: <unset>
+ 1: X
+ 2: <unset>
+ 3: xyz
+--->Xxyzabc
+    ^   ^       p
+Callout 1: last capture = 1
+ 0: <unset>
+ 1: X
+--->Xxyzabc
+    ^^          x
+ 0: Xxyzabc
+ 1: X
+ 2: xyzabc
+
+/(?=(abc))(?C)abcdef/
+Capturing subpattern count = 1
+No options
+First char = 'a'
+Need char = 'f'
+    abcdef\C+
+Callout 0: last capture = 1
+ 0: <unset>
+ 1: abc
+--->abcdef
+    ^          a
+ 0: abcdef
+ 1: abc
+    
+/(?!(abc)(?C1)d)(?C2)abcxyz/
+Capturing subpattern count = 1
+No options
+First char = 'a'
+Need char = 'z'
+    abcxyz\C+ 
+Callout 1: last capture = 1
+ 0: <unset>
+ 1: abc
+--->abcxyz
+    ^  ^       d
+Callout 2: last capture = -1
+ 0: <unset>
+--->abcxyz
+    ^          a
+ 0: abcxyz
+
+/(?<=(abc)(?C))xyz/
+Capturing subpattern count = 1
+No options
+First char = 'x'
+Need char = 'z'
+   abcxyz\C+
+Callout 0: last capture = 1
+ 0: <unset>
+ 1: abc
+--->abcxyz
+       ^       )
+ 0: xyz
+ 1: abc
+   
+/(?C)abc/ 
+Capturing subpattern count = 0
+No options
+First char = 'a'
+Need char = 'c'
+
+/(?C)^abc/
+Capturing subpattern count = 0
+Options: anchored
+No first char
+No need char
+
+/(?C)a|b/S
+Capturing subpattern count = 0
+No options
+No first char
+No need char
+Starting byte set: a b 
+
+/(?R)/
+Failed: recursive call could loop indefinitely at offset 3
+
+/(a|(?R))/
+Failed: recursive call could loop indefinitely at offset 6
+
+/(ab|(bc|(de|(?R))))/
+Failed: recursive call could loop indefinitely at offset 15
+
+/x(ab|(bc|(de|(?R))))/
+Capturing subpattern count = 3
+No options
+First char = 'x'
+No need char
+    xab
+ 0: xab
+ 1: ab
+    xbc
+ 0: xbc
+ 1: bc
+ 2: bc
+    xde
+ 0: xde
+ 1: de
+ 2: de
+ 3: de
+    xxab
+ 0: xxab
+ 1: xab
+ 2: xab
+ 3: xab
+    xxxab
+ 0: xxxab
+ 1: xxab
+ 2: xxab
+ 3: xxab
+    *** Failers
+No match
+    xyab   
+No match
+
+/(ab|(bc|(de|(?1))))/
+Failed: recursive call could loop indefinitely at offset 15
+
+/x(ab|(bc|(de|(?1)x)x)x)/
+Failed: recursive call could loop indefinitely at offset 16
+
+/^([^()]|\((?1)*\))*$/
+Capturing subpattern count = 1
+Options: anchored
+No first char
+No need char
+    abc
+ 0: abc
+ 1: c
+    a(b)c
+ 0: a(b)c
+ 1: c
+    a(b(c))d  
+ 0: a(b(c))d
+ 1: d
+    *** Failers)
+No match
+    a(b(c)d  
+No match
+
+/^>abc>([^()]|\((?1)*\))*<xyz<$/
+Capturing subpattern count = 1
+Options: anchored
+No first char
+Need char = '<'
+   >abc>123<xyz<
+ 0: >abc>123<xyz<
+ 1: 3
+   >abc>1(2)3<xyz<
+ 0: >abc>1(2)3<xyz<
+ 1: 3
+   >abc>(1(2)3)<xyz<
+ 0: >abc>(1(2)3)<xyz<
+ 1: (1(2)3)
+
+/(a(?1)b)/D
+------------------------------------------------------------------
+  0  16 Bra 0
+  3  10 Bra 1
+  6     a
+  8   3 Recurse
+ 11     b
+ 13  10 Ket
+ 16  16 Ket
+ 19     End
+------------------------------------------------------------------
+Capturing subpattern count = 1
+No options
+First char = 'a'
+Need char = 'b'
+
+/(a(?1)+b)/D
+------------------------------------------------------------------
+  0  22 Bra 0
+  3  16 Bra 1
+  6     a
+  8   6 Bra 0
+ 11   3 Recurse
+ 14   6 KetRmax
+ 17     b
+ 19  16 Ket
+ 22  22 Ket
+ 25     End
+------------------------------------------------------------------
+Capturing subpattern count = 1
+No options
+First char = 'a'
+Need char = 'b'
+
+/^\W*(?:((.)\W*(?1)\W*\2|)|((.)\W*(?3)\W*\4|\W*.\W*))\W*$/i
+Capturing subpattern count = 4
+Max back reference = 4
+Partial matching not supported
+Options: anchored caseless
+No first char
+No need char
+    1221
+ 0: 1221
+ 1: 1221
+ 2: 1
+    Satan, oscillate my metallic sonatas!
+ 0: Satan, oscillate my metallic sonatas!
+ 1: <unset>
+ 2: <unset>
+ 3: Satan, oscillate my metallic sonatas
+ 4: S
+    A man, a plan, a canal: Panama!
+ 0: A man, a plan, a canal: Panama!
+ 1: <unset>
+ 2: <unset>
+ 3: A man, a plan, a canal: Panama
+ 4: A
+    Able was I ere I saw Elba. 
+ 0: Able was I ere I saw Elba.
+ 1: <unset>
+ 2: <unset>
+ 3: Able was I ere I saw Elba
+ 4: A
+    *** Failers
+No match
+    The quick brown fox  
+No match
+    
+/^(\d+|\((?1)([+*-])(?1)\)|-(?1))$/
+Capturing subpattern count = 2
+Partial matching not supported
+Options: anchored
+No first char
+No need char
+    12
+ 0: 12
+ 1: 12
+    (((2+2)*-3)-7)
+ 0: (((2+2)*-3)-7)
+ 1: (((2+2)*-3)-7)
+ 2: -
+    -12
+ 0: -12
+ 1: -12
+    *** Failers
+No match
+    ((2+2)*-3)-7)
+No match
+         
+/^(x(y|(?1){2})z)/
+Capturing subpattern count = 2
+Options: anchored
+No first char
+No need char
+    xyz
+ 0: xyz
+ 1: xyz
+ 2: y
+    xxyzxyzz 
+ 0: xxyzxyzz
+ 1: xxyzxyzz
+ 2: xyzxyz
+    *** Failers
+No match
+    xxyzz
+No match
+    xxyzxyzxyzz   
+No match
+
+/((< (?: (?(R) \d++  | [^<>]*+) | (?2)) * >))/x
+Capturing subpattern count = 2
+Partial matching not supported
+Options: extended
+First char = '<'
+Need char = '>'
+    <>
+ 0: <>
+ 1: <>
+ 2: <>
+    <abcd>
+ 0: <abcd>
+ 1: <abcd>
+ 2: <abcd>
+    <abc <123> hij>
+ 0: <abc <123> hij>
+ 1: <abc <123> hij>
+ 2: <abc <123> hij>
+    <abc <def> hij>
+ 0: <def>
+ 1: <def>
+ 2: <def>
+    <abc<>def> 
+ 0: <abc<>def>
+ 1: <abc<>def>
+ 2: <abc<>def>
+    <abc<>      
+ 0: <>
+ 1: <>
+ 2: <>
+    *** Failers
+No match
+    <abc
+No match
+
+/(?1)/
+Failed: reference to non-existent subpattern at offset 3
+
+/((?2)(abc)/
+Failed: reference to non-existent subpattern at offset 4
+
+/^(abc)def(?1)/
+Capturing subpattern count = 1
+Options: anchored
+No first char
+No need char
+    abcdefabc
+ 0: abcdefabc
+ 1: abc
+
+/^(a|b|c)=(?1)+/
+Capturing subpattern count = 1
+Options: anchored
+No first char
+No need char
+    a=a
+ 0: a=a
+ 1: a
+    a=b
+ 0: a=b
+ 1: a
+    a=bc  
+ 0: a=bc
+ 1: a
+
+/^(a|b|c)=((?1))+/
+Capturing subpattern count = 2
+Options: anchored
+No first char
+No need char
+    a=a
+ 0: a=a
+ 1: a
+ 2: a
+    a=b
+ 0: a=b
+ 1: a
+ 2: b
+    a=bc  
+ 0: a=bc
+ 1: a
+ 2: c
+
+/a(?P<name1>b|c)d(?P<longername2>e)/D
+------------------------------------------------------------------
+  0  28 Bra 0
+  3     a
+  5   5 Bra 1
+  8     b
+ 10   5 Alt
+ 13     c
+ 15  10 Ket
+ 18     d
+ 20   5 Bra 2
+ 23     e
+ 25   5 Ket
+ 28  28 Ket
+ 31     End
+------------------------------------------------------------------
+Capturing subpattern count = 2
+Named capturing subpatterns:
+  longername2   2
+  name1         1
+No options
+First char = 'a'
+Need char = 'e'
+    abde
+ 0: abde
+ 1: b
+ 2: e
+    acde 
+ 0: acde
+ 1: c
+ 2: e
+
+/(?:a(?P<c>c(?P<d>d)))(?P<a>a)/D
+------------------------------------------------------------------
+  0  35 Bra 0
+  3  21 Bra 0
+  6     a
+  8  13 Bra 1
+ 11     c
+ 13   5 Bra 2
+ 16     d
+ 18   5 Ket
+ 21  13 Ket
+ 24  21 Ket
+ 27   5 Bra 3
+ 30     a
+ 32   5 Ket
+ 35  35 Ket
+ 38     End
+------------------------------------------------------------------
+Capturing subpattern count = 3
+Named capturing subpatterns:
+  a   3
+  c   1
+  d   2
+No options
+First char = 'a'
+Need char = 'a'
+
+/(?P<a>a)...(?P=a)bbb(?P>a)d/D
+------------------------------------------------------------------
+  0  28 Bra 0
+  3   5 Bra 1
+  6     a
+  8   5 Ket
+ 11     Any
+ 12     Any
+ 13     Any
+ 14     \1
+ 17     bbb
+ 23   3 Recurse
+ 26     d
+ 28  28 Ket
+ 31     End
+------------------------------------------------------------------
+Capturing subpattern count = 1
+Max back reference = 1
+Named capturing subpatterns:
+  a   1
+No options
+First char = 'a'
+Need char = 'd'
+
+/^\W*(?:(?P<one>(?P<two>.)\W*(?P>one)\W*(?P=two)|)|(?P<three>(?P<four>.)\W*(?P>three)\W*(?P=four)|\W*.\W*))\W*$/i
+Capturing subpattern count = 4
+Max back reference = 4
+Named capturing subpatterns:
+  four    4
+  one     1
+  three   3
+  two     2
+Partial matching not supported
+Options: anchored caseless
+No first char
+No need char
+    1221
+ 0: 1221
+ 1: 1221
+ 2: 1
+    Satan, oscillate my metallic sonatas!
+ 0: Satan, oscillate my metallic sonatas!
+ 1: <unset>
+ 2: <unset>
+ 3: Satan, oscillate my metallic sonatas
+ 4: S
+    A man, a plan, a canal: Panama!
+ 0: A man, a plan, a canal: Panama!
+ 1: <unset>
+ 2: <unset>
+ 3: A man, a plan, a canal: Panama
+ 4: A
+    Able was I ere I saw Elba. 
+ 0: Able was I ere I saw Elba.
+ 1: <unset>
+ 2: <unset>
+ 3: Able was I ere I saw Elba
+ 4: A
+    *** Failers
+No match
+    The quick brown fox  
+No match
+    
+/((?(R)a|b))\1(?1)?/
+Capturing subpattern count = 1
+Max back reference = 1
+No options
+No first char
+No need char
+  bb
+ 0: bb
+ 1: b
+  bbaa 
+ 0: bba
+ 1: b
+
+/(.*)a/sI
+Capturing subpattern count = 1
+Partial matching not supported
+Options: anchored dotall
+No first char
+Need char = 'a'
+
+/(.*)a\1/sI
+Capturing subpattern count = 1
+Max back reference = 1
+Partial matching not supported
+Options: dotall
+No first char
+Need char = 'a'
+
+/(.*)a(b)\2/sI
+Capturing subpattern count = 2
+Max back reference = 2
+Partial matching not supported
+Options: anchored dotall
+No first char
+Need char = 'b'
+
+/((.*)a|(.*)b)z/sI
+Capturing subpattern count = 3
+Partial matching not supported
+Options: anchored dotall
+No first char
+Need char = 'z'
+
+/((.*)a|(.*)b)z\1/sI
+Capturing subpattern count = 3
+Max back reference = 1
+Partial matching not supported
+Options: dotall
+No first char
+Need char = 'z'
+
+/((.*)a|(.*)b)z\2/sI
+Capturing subpattern count = 3
+Max back reference = 2
+Partial matching not supported
+Options: dotall
+No first char
+Need char = 'z'
+
+/((.*)a|(.*)b)z\3/sI
+Capturing subpattern count = 3
+Max back reference = 3
+Partial matching not supported
+Options: dotall
+No first char
+Need char = 'z'
+
+/((.*)a|^(.*)b)z\3/sI
+Capturing subpattern count = 3
+Max back reference = 3
+Partial matching not supported
+Options: anchored dotall
+No first char
+Need char = 'z'
+
+/(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)a/sI
+Capturing subpattern count = 31
+Partial matching not supported
+Options: anchored dotall
+No first char
+No need char
+
+/(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)a\31/sI
+Capturing subpattern count = 31
+Max back reference = 31
+Partial matching not supported
+Options: dotall
+No first char
+No need char
+
+/(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)|(.*)a\32/sI
+Capturing subpattern count = 32
+Max back reference = 32
+Partial matching not supported
+Options: dotall
+No first char
+No need char
+
+/(a)(bc)/ND
+------------------------------------------------------------------
+  0  21 Bra 0
+  3   5 Bra 0
+  6     a
+  8   5 Ket
+ 11   7 Bra 0
+ 14     bc
+ 18   7 Ket
+ 21  21 Ket
+ 24     End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Options:
+First char = 'a'
+Need char = 'c'
+  abc
+ 0: abc
+
+/(?P<one>a)(bc)/ND
+------------------------------------------------------------------
+  0  21 Bra 0
+  3   5 Bra 1
+  6     a
+  8   5 Ket
+ 11   7 Bra 0
+ 14     bc
+ 18   7 Ket
+ 21  21 Ket
+ 24     End
+------------------------------------------------------------------
+Capturing subpattern count = 1
+Named capturing subpatterns:
+  one   1
+Options:
+First char = 'a'
+Need char = 'c'
+  abc
+ 0: abc
+ 1: a
+
+/(a)(?P<named>bc)/ND
+------------------------------------------------------------------
+  0  21 Bra 0
+  3   5 Bra 0
+  6     a
+  8   5 Ket
+ 11   7 Bra 1
+ 14     bc
+ 18   7 Ket
+ 21  21 Ket
+ 24     End
+------------------------------------------------------------------
+Capturing subpattern count = 1
+Named capturing subpatterns:
+  named   1
+Options:
+First char = 'a'
+Need char = 'c'
+
+/(a+)*zz/
+Capturing subpattern count = 1
+Partial matching not supported
+No options
+No first char
+Need char = 'z'
+  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaazzbbbbbb\M
+Minimum match limit = 8
+ 0: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaazz
+ 1: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+  aaaaaaaaaaaaaz\M
+Minimum match limit = 32768
+No match
+
+/(aaa(?C1)bbb|ab)/
+Capturing subpattern count = 1
+No options
+First char = 'a'
+Need char = 'b'
+   aaabbb
+--->aaabbb
+  1 ^  ^       b
+ 0: aaabbb
+ 1: aaabbb
+   aaabbb\C*0
+--->aaabbb
+  1 ^  ^       b
+ 0: aaabbb
+ 1: aaabbb
+   aaabbb\C*1
+--->aaabbb
+  1 ^  ^       b
+Callout data = 1
+ 0: ab
+ 1: ab
+   aaabbb\C*-1
+--->aaabbb
+  1 ^  ^       b
+Callout data = -1
+No match
+
+/ab(?P<one>cd)ef(?P<two>gh)/
+Capturing subpattern count = 2
+Named capturing subpatterns:
+  one   1
+  two   2
+No options
+First char = 'a'
+Need char = 'h'
+    abcdefgh
+ 0: abcdefgh
+ 1: cd
+ 2: gh
+    abcdefgh\C1\Gtwo
+ 0: abcdefgh
+ 1: cd
+ 2: gh
+ 1C cd (2)
+ 2G gh (2)
+    abcdefgh\Cone\Ctwo
+ 0: abcdefgh
+ 1: cd
+ 2: gh
+ 1C cd (2)
+ 2C gh (2)
+    abcdefgh\Cthree  
+no parentheses with name "three"
+ 0: abcdefgh
+ 1: cd
+ 2: gh
+
+/(?P<Tes>)(?P<Test>)/D
+------------------------------------------------------------------
+  0  15 Bra 0
+  3   3 Bra 1
+  6   3 Ket
+  9   3 Bra 2
+ 12   3 Ket
+ 15  15 Ket
+ 18     End
+------------------------------------------------------------------
+Capturing subpattern count = 2
+Named capturing subpatterns:
+  Tes    1
+  Test   2
+No options
+No first char
+No need char
+
+/(?P<Test>)(?P<Tes>)/D
+------------------------------------------------------------------
+  0  15 Bra 0
+  3   3 Bra 1
+  6   3 Ket
+  9   3 Bra 2
+ 12   3 Ket
+ 15  15 Ket
+ 18     End
+------------------------------------------------------------------
+Capturing subpattern count = 2
+Named capturing subpatterns:
+  Tes    2
+  Test   1
+No options
+No first char
+No need char
+
+/(?P<Z>zz)(?P<A>aa)/
+Capturing subpattern count = 2
+Named capturing subpatterns:
+  A   2
+  Z   1
+No options
+First char = 'z'
+Need char = 'a'
+    zzaa\CZ
+ 0: zzaa
+ 1: zz
+ 2: aa
+ 1C zz (2)
+    zzaa\CA
+ 0: zzaa
+ 1: zz
+ 2: aa
+ 2C aa (2)
+
+/(?P<x>eks)(?P<x>eccs)/
+Failed: two named groups have the same name at offset 16
+
+/(?P<abc>abc(?P<def>def)(?P<abc>xyz))/
+Failed: two named groups have the same name at offset 31
+
+"\[((?P<elem>\d+)(,(?P>elem))*)\]"
+Capturing subpattern count = 3
+Named capturing subpatterns:
+  elem   2
+Partial matching not supported
+No options
+First char = '['
+Need char = ']'
+    [10,20,30,5,5,4,4,2,43,23,4234]
+ 0: [10,20,30,5,5,4,4,2,43,23,4234]
+ 1: 10,20,30,5,5,4,4,2,43,23,4234
+ 2: 10
+ 3: ,4234
+    *** Failers
+No match
+    []  
+No match
+
+"\[((?P<elem>\d+)(,(?P>elem))*)?\]"
+Capturing subpattern count = 3
+Named capturing subpatterns:
+  elem   2
+Partial matching not supported
+No options
+First char = '['
+Need char = ']'
+    [10,20,30,5,5,4,4,2,43,23,4234]
+ 0: [10,20,30,5,5,4,4,2,43,23,4234]
+ 1: 10,20,30,5,5,4,4,2,43,23,4234
+ 2: 10
+ 3: ,4234
+    [] 
+ 0: []
+
+/(a(b(?2)c))?/D
+------------------------------------------------------------------
+  0  25 Bra 0
+  3     Brazero
+  4  18 Bra 1
+  7     a
+  9  10 Bra 2
+ 12     b
+ 14   9 Recurse
+ 17     c
+ 19  10 Ket
+ 22  18 Ket
+ 25  25 Ket
+ 28     End
+------------------------------------------------------------------
+Capturing subpattern count = 2
+No options
+No first char
+No need char
+
+/(a(b(?2)c))*/D
+------------------------------------------------------------------
+  0  25 Bra 0
+  3     Brazero
+  4  18 Bra 1
+  7     a
+  9  10 Bra 2
+ 12     b
+ 14   9 Recurse
+ 17     c
+ 19  10 Ket
+ 22  18 KetRmax
+ 25  25 Ket
+ 28     End
+------------------------------------------------------------------
+Capturing subpattern count = 2
+No options
+No first char
+No need char
+
+/(a(b(?2)c)){0,2}/D
+------------------------------------------------------------------
+  0  53 Bra 0
+  3     Brazero
+  4  46 Bra 0
+  7  18 Bra 1
+ 10     a
+ 12  10 Bra 2
+ 15     b
+ 17  12 Recurse
+ 20     c
+ 22  10 Ket
+ 25  18 Ket
+ 28     Brazero
+ 29  18 Bra 1
+ 32     a
+ 34  10 Bra 2
+ 37     b
+ 39  12 Recurse
+ 42     c
+ 44  10 Ket
+ 47  18 Ket
+ 50  46 Ket
+ 53  53 Ket
+ 56     End
+------------------------------------------------------------------
+Capturing subpattern count = 2
+No options
+No first char
+No need char
+
+/[ab]{1}+/D
+------------------------------------------------------------------
+  0  47 Bra 0
+  3  41 Once
+  6     [ab]{1,1}
+ 44  41 Ket
+ 47  47 Ket
+ 50     End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+No options
+No first char
+No need char
+
+/((w\/|-|with)*(free|immediate)*.*?shipping\s*[!.-]*)/i
+Capturing subpattern count = 3
+Partial matching not supported
+Options: caseless
+No first char
+Need char = 'g' (caseless)
+     Baby Bjorn Active Carrier - With free SHIPPING!!
+ 0: Baby Bjorn Active Carrier - With free SHIPPING!!
+ 1: Baby Bjorn Active Carrier - With free SHIPPING!!
+
+/((w\/|-|with)*(free|immediate)*.*?shipping\s*[!.-]*)/iS
+Capturing subpattern count = 3
+Partial matching not supported
+Options: caseless
+No first char
+Need char = 'g' (caseless)
+Study returned NULL
+     Baby Bjorn Active Carrier - With free SHIPPING!!
+ 0: Baby Bjorn Active Carrier - With free SHIPPING!!
+ 1: Baby Bjorn Active Carrier - With free SHIPPING!!
+     
+/a*.*b/SD
+------------------------------------------------------------------
+  0   9 Bra 0
+  3     a*
+  5     Any*
+  7     b
+  9   9 Ket
+ 12     End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Partial matching not supported
+No options
+No first char
+Need char = 'b'
+Study returned NULL
+
+/(a|b)*.?c/SD 
+------------------------------------------------------------------
+  0  21 Bra 0
+  3     Brazero
+  4   5 Bra 1
+  7     a
+  9   5 Alt
+ 12     b
+ 14  10 KetRmax
+ 17     Any?
+ 19     c
+ 21  21 Ket
+ 24     End
+------------------------------------------------------------------
+Capturing subpattern count = 1
+No options
+No first char
+Need char = 'c'
+Study returned NULL
+
+/abc(?C255)de(?C)f/D
+------------------------------------------------------------------
+  0  27 Bra 0
+  3     abc
+  9     Callout 255 10 1
+ 15     de
+ 19     Callout 0 16 1
+ 25     f
+ 27  27 Ket
+ 30     End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+No options
+First char = 'a'
+Need char = 'f'
+
+/abcde/CD
+------------------------------------------------------------------
+  0  49 Bra 0
+  3     Callout 255 0 1
+  9     a
+ 11     Callout 255 1 1
+ 17     b
+ 19     Callout 255 2 1
+ 25     c
+ 27     Callout 255 3 1
+ 33     d
+ 35     Callout 255 4 1
+ 41     e
+ 43     Callout 255 5 0
+ 49  49 Ket
+ 52     End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Options:
+First char = 'a'
+Need char = 'e'
+  abcde
+--->abcde
+ +0 ^         a
+ +1 ^^        b
+ +2 ^ ^       c
+ +3 ^  ^      d
+ +4 ^   ^     e
+ +5 ^    ^    
+ 0: abcde
+  abcdfe 
+--->abcdfe
+ +0 ^          a
+ +1 ^^         b
+ +2 ^ ^        c
+ +3 ^  ^       d
+ +4 ^   ^      e
+No match
+  
+/a*b/CD
+------------------------------------------------------------------
+  0  25 Bra 0
+  3     Callout 255 0 2
+  9     a*
+ 11     Callout 255 2 1
+ 17     b
+ 19     Callout 255 3 0
+ 25  25 Ket
+ 28     End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Partial matching not supported
+Options:
+No first char
+Need char = 'b'
+  ab
+--->ab
+ +0 ^      a*
+ +2 ^^     b
+ +3 ^ ^    
+ 0: ab
+  aaaab
+--->aaaab
+ +0 ^         a*
+ +2 ^   ^     b
+ +3 ^    ^    
+ 0: aaaab
+  aaaacb   
+--->aaaacb
+ +0 ^          a*
+ +2 ^   ^      b
+ +2 ^  ^       b
+ +2 ^ ^        b
+ +2 ^^         b
+ +2 ^          b
+ +0  ^         a*
+ +2  ^  ^      b
+ +2  ^ ^       b
+ +2  ^^        b
+ +2  ^         b
+ +0   ^        a*
+ +2   ^ ^      b
+ +2   ^^       b
+ +2   ^        b
+ +0    ^       a*
+ +2    ^^      b
+ +2    ^       b
+ +0     ^      a*
+ +2     ^      b
+ +0      ^     a*
+ +2      ^     b
+ +3      ^^    
+ 0: b
+
+/a+b/CD
+------------------------------------------------------------------
+  0  25 Bra 0
+  3     Callout 255 0 2
+  9     a+
+ 11     Callout 255 2 1
+ 17     b
+ 19     Callout 255 3 0
+ 25  25 Ket
+ 28     End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Partial matching not supported
+Options:
+First char = 'a'
+Need char = 'b'
+  ab
+--->ab
+ +0 ^      a+
+ +2 ^^     b
+ +3 ^ ^    
+ 0: ab
+  aaaab
+--->aaaab
+ +0 ^         a+
+ +2 ^   ^     b
+ +3 ^    ^    
+ 0: aaaab
+  aaaacb   
+--->aaaacb
+ +0 ^          a+
+ +2 ^   ^      b
+ +2 ^  ^       b
+ +2 ^ ^        b
+ +2 ^^         b
+ +0  ^         a+
+ +2  ^  ^      b
+ +2  ^ ^       b
+ +2  ^^        b
+ +0   ^        a+
+ +2   ^ ^      b
+ +2   ^^       b
+ +0    ^       a+
+ +2    ^^      b
+No match
+
+/(abc|def)x/CD
+------------------------------------------------------------------
+  0  92 Bra 0
+  3     Callout 255 0 9
+  9  33 Bra 1
+ 12     Callout 255 1 1
+ 18     a
+ 20     Callout 255 2 1
+ 26     b
+ 28     Callout 255 3 1
+ 34     c
+ 36     Callout 255 4 0
+ 42  33 Alt
+ 45     Callout 255 5 1
+ 51     d
+ 53     Callout 255 6 1
+ 59     e
+ 61     Callout 255 7 1
+ 67     f
+ 69     Callout 255 8 0
+ 75  66 Ket
+ 78     Callout 255 9 1
+ 84     x
+ 86     Callout 255 10 0
+ 92  92 Ket
+ 95     End
+------------------------------------------------------------------
+Capturing subpattern count = 1
+Options:
+No first char
+Need char = 'x'
+  abcx
+--->abcx
+ +0 ^        (abc|def)
+ +1 ^        a
+ +2 ^^       b
+ +3 ^ ^      c
+ +4 ^  ^     |
+ +9 ^  ^     x
++10 ^   ^    
+ 0: abcx
+ 1: abc
+  defx
+--->defx
+ +0 ^        (abc|def)
+ +1 ^        a
+ +5 ^        d
+ +6 ^^       e
+ +7 ^ ^      f
+ +8 ^  ^     )
+ +9 ^  ^     x
++10 ^   ^    
+ 0: defx
+ 1: def
+  abcdefzx
+--->abcdefzx
+ +0 ^            (abc|def)
+ +1 ^            a
+ +2 ^^           b
+ +3 ^ ^          c
+ +4 ^  ^         |
+ +9 ^  ^         x
+ +5 ^            d
+ +0  ^           (abc|def)
+ +1  ^           a
+ +5  ^           d
+ +0   ^          (abc|def)
+ +1   ^          a
+ +5   ^          d
+ +0    ^         (abc|def)
+ +1    ^         a
+ +5    ^         d
+ +6    ^^        e
+ +7    ^ ^       f
+ +8    ^  ^      )
+ +9    ^  ^      x
+ +0     ^        (abc|def)
+ +1     ^        a
+ +5     ^        d
+ +0      ^       (abc|def)
+ +1      ^       a
+ +5      ^       d
+ +0       ^      (abc|def)
+ +1       ^      a
+ +5       ^      d
+ +0        ^     (abc|def)
+ +1        ^     a
+ +5        ^     d
+No match
+
+/(ab|cd){3,4}/C
+Capturing subpattern count = 1
+Options:
+No first char
+No need char
+  ababab
+--->ababab
+ +0 ^          (ab|cd){3,4}
+ +1 ^          a
+ +2 ^^         b
+ +3 ^ ^        |
+ +1 ^ ^        a
+ +2 ^  ^       b
+ +3 ^   ^      |
+ +1 ^   ^      a
+ +2 ^    ^     b
+ +3 ^     ^    |
+ +1 ^     ^    a
+ +4 ^     ^    c
++12 ^     ^    
+ 0: ababab
+ 1: ab
+  abcdabcd
+--->abcdabcd
+ +0 ^            (ab|cd){3,4}
+ +1 ^            a
+ +2 ^^           b
+ +3 ^ ^          |
+ +1 ^ ^          a
+ +4 ^ ^          c
+ +5 ^  ^         d
+ +6 ^   ^        )
+ +1 ^   ^        a
+ +2 ^    ^       b
+ +3 ^     ^      |
+ +1 ^     ^      a
+ +4 ^     ^      c
+ +5 ^      ^     d
+ +6 ^       ^    )
++12 ^       ^    
+ 0: abcdabcd
+ 1: cd
+  abcdcdcdcdcd  
+--->abcdcdcdcdcd
+ +0 ^                (ab|cd){3,4}
+ +1 ^                a
+ +2 ^^               b
+ +3 ^ ^              |
+ +1 ^ ^              a
+ +4 ^ ^              c
+ +5 ^  ^             d
+ +6 ^   ^            )
+ +1 ^   ^            a
+ +4 ^   ^            c
+ +5 ^    ^           d
+ +6 ^     ^          )
+ +1 ^     ^          a
+ +4 ^     ^          c
+ +5 ^      ^         d
+ +6 ^       ^        )
++12 ^       ^        
+ 0: abcdcdcd
+ 1: cd
+
+/([ab]{,4}c|xy)/CD
+------------------------------------------------------------------
+  0 131 Bra 0
+  3     Callout 255 0 14
+  9  88 Bra 1
+ 12     Callout 255 1 4
+ 18     [ab]
+ 51     Callout 255 5 1
+ 57     {
+ 59     Callout 255 6 1
+ 65     ,
+ 67     Callout 255 7 1
+ 73     4
+ 75     Callout 255 8 1
+ 81     }
+ 83     Callout 255 9 1
+ 89     c
+ 91     Callout 255 10 0
+ 97  25 Alt
+100     Callout 255 11 1
+106     x
+108     Callout 255 12 1
+114     y
+116     Callout 255 13 0
+122 113 Ket
+125     Callout 255 14 0
+131 131 Ket
+134     End
+------------------------------------------------------------------
+Capturing subpattern count = 1
+Options:
+No first char
+No need char
+    Note: that { does NOT introduce a quantifier
+--->Note: that { does NOT introduce a quantifier
+ +0 ^                                                ([ab]{,4}c|xy)
+ +1 ^                                                [ab]
++11 ^                                                x
+ +0  ^                                               ([ab]{,4}c|xy)
+ +1  ^                                               [ab]
++11  ^                                               x
+ +0   ^                                              ([ab]{,4}c|xy)
+ +1   ^                                              [ab]
++11   ^                                              x
+ +0    ^                                             ([ab]{,4}c|xy)
+ +1    ^                                             [ab]
++11    ^                                             x
+ +0     ^                                            ([ab]{,4}c|xy)
+ +1     ^                                            [ab]
++11     ^                                            x
+ +0      ^                                           ([ab]{,4}c|xy)
+ +1      ^                                           [ab]
++11      ^                                           x
+ +0       ^                                          ([ab]{,4}c|xy)
+ +1       ^                                          [ab]
++11       ^                                          x
+ +0        ^                                         ([ab]{,4}c|xy)
+ +1        ^                                         [ab]
++11        ^                                         x
+ +0         ^                                        ([ab]{,4}c|xy)
+ +1         ^                                        [ab]
+ +5         ^^                                       {
++11         ^                                        x
+ +0          ^                                       ([ab]{,4}c|xy)
+ +1          ^                                       [ab]
++11          ^                                       x
+ +0           ^                                      ([ab]{,4}c|xy)
+ +1           ^                                      [ab]
++11           ^                                      x
+ +0            ^                                     ([ab]{,4}c|xy)
+ +1            ^                                     [ab]
++11            ^                                     x
+ +0             ^                                    ([ab]{,4}c|xy)
+ +1             ^                                    [ab]
++11             ^                                    x
+ +0              ^                                   ([ab]{,4}c|xy)
+ +1              ^                                   [ab]
++11              ^                                   x
+ +0               ^                                  ([ab]{,4}c|xy)
+ +1               ^                                  [ab]
++11               ^                                  x
+ +0                ^                                 ([ab]{,4}c|xy)
+ +1                ^                                 [ab]
++11                ^                                 x
+ +0                 ^                                ([ab]{,4}c|xy)
+ +1                 ^                                [ab]
++11                 ^                                x
+ +0                  ^                               ([ab]{,4}c|xy)
+ +1                  ^                               [ab]
++11                  ^                               x
+ +0                   ^                              ([ab]{,4}c|xy)
+ +1                   ^                              [ab]
++11                   ^                              x
+ +0                    ^                             ([ab]{,4}c|xy)
+ +1                    ^                             [ab]
++11                    ^                             x
+ +0                     ^                            ([ab]{,4}c|xy)
+ +1                     ^                            [ab]
++11                     ^                            x
+ +0                      ^                           ([ab]{,4}c|xy)
+ +1                      ^                           [ab]
++11                      ^                           x
+ +0                       ^                          ([ab]{,4}c|xy)
+ +1                       ^                          [ab]
++11                       ^                          x
+ +0                        ^                         ([ab]{,4}c|xy)
+ +1                        ^                         [ab]
++11                        ^                         x
+ +0                         ^                        ([ab]{,4}c|xy)
+ +1                         ^                        [ab]
++11                         ^                        x
+ +0                          ^                       ([ab]{,4}c|xy)
+ +1                          ^                       [ab]
++11                          ^                       x
+ +0                           ^                      ([ab]{,4}c|xy)
+ +1                           ^                      [ab]
++11                           ^                      x
+ +0                            ^                     ([ab]{,4}c|xy)
+ +1                            ^                     [ab]
++11                            ^                     x
+ +0                             ^                    ([ab]{,4}c|xy)
+ +1                             ^                    [ab]
++11                             ^                    x
+ +0                              ^                   ([ab]{,4}c|xy)
+ +1                              ^                   [ab]
++11                              ^                   x
+ +0                               ^                  ([ab]{,4}c|xy)
+ +1                               ^                  [ab]
++11                               ^                  x
+ +0                                ^                 ([ab]{,4}c|xy)
+ +1                                ^                 [ab]
++11                                ^                 x
+ +0                                 ^                ([ab]{,4}c|xy)
+ +1                                 ^                [ab]
+ +5                                 ^^               {
++11                                 ^                x
+ +0                                  ^               ([ab]{,4}c|xy)
+ +1                                  ^               [ab]
++11                                  ^               x
+ +0                                   ^              ([ab]{,4}c|xy)
+ +1                                   ^              [ab]
++11                                   ^              x
+ +0                                    ^             ([ab]{,4}c|xy)
+ +1                                    ^             [ab]
++11                                    ^             x
+ +0                                     ^            ([ab]{,4}c|xy)
+ +1                                     ^            [ab]
+ +5                                     ^^           {
++11                                     ^            x
+ +0                                      ^           ([ab]{,4}c|xy)
+ +1                                      ^           [ab]
++11                                      ^           x
+ +0                                       ^          ([ab]{,4}c|xy)
+ +1                                       ^          [ab]
++11                                       ^          x
+ +0                                        ^         ([ab]{,4}c|xy)
+ +1                                        ^         [ab]
++11                                        ^         x
+ +0                                         ^        ([ab]{,4}c|xy)
+ +1                                         ^        [ab]
++11                                         ^        x
+ +0                                          ^       ([ab]{,4}c|xy)
+ +1                                          ^       [ab]
++11                                          ^       x
+ +0                                           ^      ([ab]{,4}c|xy)
+ +1                                           ^      [ab]
++11                                           ^      x
+ +0                                            ^     ([ab]{,4}c|xy)
+ +1                                            ^     [ab]
++11                                            ^     x
+ +0                                             ^    ([ab]{,4}c|xy)
+ +1                                             ^    [ab]
++11                                             ^    x
+No match
+
+/([ab]{1,4}c|xy){4,5}?123/CD
+------------------------------------------------------------------
+  0 485 Bra 0
+  3     Callout 255 0 21
+  9  61 Bra 1
+ 12     Callout 255 1 9
+ 18     [ab]{1,4}
+ 56     Callout 255 10 1
+ 62     c
+ 64     Callout 255 11 0
+ 70  25 Alt
+ 73     Callout 255 12 1
+ 79     x
+ 81     Callout 255 13 1
+ 87     y
+ 89     Callout 255 14 0
+ 95  86 Ket
+ 98  61 Bra 1
+101     Callout 255 1 9
+107     [ab]{1,4}
+145     Callout 255 10 1
+151     c
+153     Callout 255 11 0
+159  25 Alt
+162     Callout 255 12 1
+168     x
+170     Callout 255 13 1
+176     y
+178     Callout 255 14 0
+184  86 Ket
+187  61 Bra 1
+190     Callout 255 1 9
+196     [ab]{1,4}
+234     Callout 255 10 1
+240     c
+242     Callout 255 11 0
+248  25 Alt
+251     Callout 255 12 1
+257     x
+259     Callout 255 13 1
+265     y
+267     Callout 255 14 0
+273  86 Ket
+276  61 Bra 1
+279     Callout 255 1 9
+285     [ab]{1,4}
+323     Callout 255 10 1
+329     c
+331     Callout 255 11 0
+337  25 Alt
+340     Callout 255 12 1
+346     x
+348     Callout 255 13 1
+354     y
+356     Callout 255 14 0
+362  86 Ket
+365     Braminzero
+366  61 Bra 1
+369     Callout 255 1 9
+375     [ab]{1,4}
+413     Callout 255 10 1
+419     c
+421     Callout 255 11 0
+427  25 Alt
+430     Callout 255 12 1
+436     x
+438     Callout 255 13 1
+444     y
+446     Callout 255 14 0
+452  86 Ket
+455     Callout 255 21 1
+461     1
+463     Callout 255 22 1
+469     2
+471     Callout 255 23 1
+477     3
+479     Callout 255 24 0
+485 485 Ket
+488     End
+------------------------------------------------------------------
+Capturing subpattern count = 1
+Partial matching not supported
+Options:
+No first char
+Need char = '3'
+    aacaacaacaacaac123
+--->aacaacaacaacaac123
+ +0 ^                      ([ab]{1,4}c|xy){4,5}?
+ +1 ^                      [ab]{1,4}
++10 ^ ^                    c
++11 ^  ^                   |
+ +1 ^  ^                   [ab]{1,4}
++10 ^    ^                 c
++11 ^     ^                |
+ +1 ^     ^                [ab]{1,4}
++10 ^       ^              c
++11 ^        ^             |
+ +1 ^        ^             [ab]{1,4}
++10 ^          ^           c
++11 ^           ^          |
++21 ^           ^          1
+ +1 ^           ^          [ab]{1,4}
++10 ^             ^        c
++11 ^              ^       |
++21 ^              ^       1
++22 ^               ^      2
++23 ^                ^     3
++24 ^                 ^    
+ 0: aacaacaacaacaac123
+ 1: aac
+
+/\b.*/I
+Capturing subpattern count = 0
+Partial matching not supported
+No options
+No first char
+No need char
+  ab cd\>1
+ 0:  cd
+  
+/\b.*/Is 
+Capturing subpattern count = 0
+Partial matching not supported
+Options: dotall
+No first char
+No need char
+  ab cd\>1
+ 0:  cd
+  
+/(?!.bcd).*/I
+Capturing subpattern count = 0
+Partial matching not supported
+No options
+No first char
+No need char
+  Xbcd12345 
+ 0: bcd12345
+
+/abcde/
+Capturing subpattern count = 0
+No options
+First char = 'a'
+Need char = 'e'
+    ab\P
+Partial match
+    abc\P
+Partial match
+    abcd\P
+Partial match
+    abcde\P   
+ 0: abcde
+    the quick brown abc\P
+Partial match
+    ** Failers\P
+No match
+    the quick brown abxyz fox\P
+No match
+    
+"^(0?[1-9]|[12][0-9]|3[01])/(0?[1-9]|1[012])/(20)?\d\d$"
+Capturing subpattern count = 3
+Options: anchored
+No first char
+Need char = '/'
+    13/05/04\P
+ 0: 13/05/04
+ 1: 13
+ 2: 05
+    13/5/2004\P
+ 0: 13/5/2004
+ 1: 13
+ 2: 5
+ 3: 20
+    02/05/09\P 
+ 0: 02/05/09
+ 1: 02
+ 2: 05
+    1\P
+Partial match
+    1/2\P
+Partial match
+    1/2/0\P
+Partial match
+    1/2/04\P    
+ 0: 1/2/04
+ 1: 1
+ 2: 2
+    0\P
+Partial match
+    02/\P
+Partial match
+    02/0\P   
+Partial match
+    02/1\P
+Partial match
+    ** Failers\P
+No match
+    \P
+No match
+    123\P
+No match
+    33/4/04\P
+No match
+    3/13/04\P
+No match
+    0/1/2003\P
+No match
+    0/\P 
+No match
+    02/0/\P 
+No match
+    02/13\P  
+No match
+
+/0{0,2}ABC/I
+Capturing subpattern count = 0
+Partial matching not supported
+No options
+No first char
+Need char = 'C'
+    
+/\d{3,}ABC/I
+Capturing subpattern count = 0
+Partial matching not supported
+No options
+No first char
+Need char = 'C'
+    
+/\d*ABC/I
+Capturing subpattern count = 0
+Partial matching not supported
+No options
+No first char
+Need char = 'C'
+
+/[abc]+DE/I
+Capturing subpattern count = 0
+Partial matching not supported
+No options
+No first char
+Need char = 'E'
+
+/[abc]?123/
+Capturing subpattern count = 0
+No options
+No first char
+Need char = '3'
+    123\P
+ 0: 123
+    a\P
+Partial match
+    b\P
+Partial match
+    c\P
+Partial match
+    c12\P
+Partial match
+    c123\P      
+ 0: c123
+
+/^(?:\d){3,5}X/
+Capturing subpattern count = 0
+Options: anchored
+No first char
+Need char = 'X'
+    1\P
+Partial match
+    123\P
+Partial match
+    123X
+ 0: 123X
+    1234\P
+Partial match
+    1234X
+ 0: 1234X
+    12345\P
+Partial match
+    12345X      
+ 0: 12345X
+    *** Failers 
+No match
+    1X 
+No match
+    123456\P 
+No match
+
+/abc/>testsavedregex
+Capturing subpattern count = 0
+No options
+First char = 'a'
+Need char = 'c'
+Compiled regex written to testsavedregex
+<testsavedregex
+Compiled regex loaded from testsavedregex
+No study data
+Capturing subpattern count = 0
+No options
+First char = 'a'
+Need char = 'c'
+    abc
+ 0: abc
+    ** Failers
+No match
+    bca
+No match
+    
+/abc/F>testsavedregex
+Capturing subpattern count = 0
+No options
+First char = 'a'
+Need char = 'c'
+Compiled regex written to testsavedregex
+<testsavedregex
+Compiled regex (byte-inverted) loaded from testsavedregex
+No study data
+Capturing subpattern count = 0
+No options
+First char = 'a'
+Need char = 'c'
+    abc
+ 0: abc
+    ** Failers
+No match
+    bca
+No match
+
+/(a|b)/S>testsavedregex
+Capturing subpattern count = 1
+No options
+No first char
+No need char
+Starting byte set: a b 
+Compiled regex written to testsavedregex
+Study data written to testsavedregex
+<testsavedregex
+Compiled regex loaded from testsavedregex
+Study data loaded from testsavedregex
+Capturing subpattern count = 1
+No options
+No first char
+No need char
+Starting byte set: a b 
+    abc
+ 0: a
+ 1: a
+    ** Failers
+ 0: a
+ 1: a
+    def  
+No match
+    
+/(a|b)/SF>testsavedregex
+Capturing subpattern count = 1
+No options
+No first char
+No need char
+Starting byte set: a b 
+Compiled regex written to testsavedregex
+Study data written to testsavedregex
+<testsavedregex
+Compiled regex (byte-inverted) loaded from testsavedregex
+Study data loaded from testsavedregex
+Capturing subpattern count = 1
+No options
+No first char
+No need char
+Starting byte set: a b 
+    abc
+ 0: a
+ 1: a
+    ** Failers
+ 0: a
+ 1: a
+    def  
+No match
+    
+~<(\w+)/?>(.)*</(\1)>~smg
+Capturing subpattern count = 3
+Max back reference = 1
+Partial matching not supported
+Options: multiline dotall
+First char = '<'
+Need char = '>'
+    <!DOCTYPE seite SYSTEM "http://www.lco.lineas.de/xmlCms.dtd">\n<seite>\n<dokumenteninformation>\n<seitentitel>Partner der LCO</seitentitel>\n<sprache>de</sprache>\n<seitenbeschreibung>Partner der LINEAS Consulting\nGmbH</seitenbeschreibung>\n<schluesselworte>LINEAS Consulting GmbH Hamburg\nPartnerfirmen</schluesselworte>\n<revisit>30 days</revisit>\n<robots>index,follow</robots>\n<menueinformation>\n<aktiv>ja</aktiv>\n<menueposition>3</menueposition>\n<menuetext>Partner</menuetext>\n</menueinformation>\n<lastedited>\n<autor>LCO</autor>\n<firma>LINEAS Consulting</firma>\n<datum>15.10.2003</datum>\n</lastedited>\n</dokumenteninformation>\n<inhalt>\n\n<absatzueberschrift>Die Partnerfirmen der LINEAS Consulting\nGmbH</absatzueberschrift>\n\n<absatz><link ziel="http://www.ca.com/" zielfenster="_blank">\n<bild name="logo_ca.gif" rahmen="no"/></link> <link\nziel="http://www.ey.com/" zielfenster="_blank"><bild\nname="logo_euy.gif" rahmen="no"/></link>\n</absatz>\n\n<absatz><link ziel="http://www.cisco.de/" zielfenster="_blank">\n<bild name="logo_cisco.gif" rahmen="ja"/></link></absatz>\n\n<absatz><link ziel="http://www.atelion.de/"\nzielfenster="_blank"><bild\nname="logo_atelion.gif" rahmen="no"/></link>\n</absatz>\n\n<absatz><link ziel="http://www.line-information.de/"\nzielfenster="_blank">\n<bild name="logo_line_information.gif" rahmen="no"/></link>\n</absatz>\n\n<absatz><bild name="logo_aw.gif" rahmen="no"/></absatz>\n\n<absatz><link ziel="http://www.incognis.de/"\nzielfenster="_blank"><bild\nname="logo_incognis.gif" rahmen="no"/></link></absatz>\n\n<absatz><link ziel="http://www.addcraft.com/"\nzielfenster="_blank"><bild\nname="logo_addcraft.gif" rahmen="no"/></link></absatz>\n\n<absatz><link ziel="http://www.comendo.com/"\nzielfenster="_blank"><bild\nname="logo_comendo.gif" rahmen="no"/></link></absatz>\n\n</inhalt>\n</seite>
+ 0: <seite>\x0a<dokumenteninformation>\x0a<seitentitel>Partner der LCO</seitentitel>\x0a<sprache>de</sprache>\x0a<seitenbeschreibung>Partner der LINEAS Consulting\x0aGmbH</seitenbeschreibung>\x0a<schluesselworte>LINEAS Consulting GmbH Hamburg\x0aPartnerfirmen</schluesselworte>\x0a<revisit>30 days</revisit>\x0a<robots>index,follow</robots>\x0a<menueinformation>\x0a<aktiv>ja</aktiv>\x0a<menueposition>3</menueposition>\x0a<menuetext>Partner</menuetext>\x0a</menueinformation>\x0a<lastedited>\x0a<autor>LCO</autor>\x0a<firma>LINEAS Consulting</firma>\x0a<datum>15.10.2003</datum>\x0a</lastedited>\x0a</dokumenteninformation>\x0a<inhalt>\x0a\x0a<absatzueberschrift>Die Partnerfirmen der LINEAS Consulting\x0aGmbH</absatzueberschrift>\x0a\x0a<absatz><link ziel="http://www.ca.com/" zielfenster="_blank">\x0a<bild name="logo_ca.gif" rahmen="no"/></link> <link\x0aziel="http://www.ey.com/" zielfenster="_blank"><bild\x0aname="logo_euy.gif" rahmen="no"/></link>\x0a</absatz>\x0a\x0a<absatz><link ziel="http://www.cisco.de/" zielfenster="_blank">\x0a<bild name="logo_cisco.gif" rahmen="ja"/></link></absatz>\x0a\x0a<absatz><link ziel="http://www.atelion.de/"\x0azielfenster="_blank"><bild\x0aname="logo_atelion.gif" rahmen="no"/></link>\x0a</absatz>\x0a\x0a<absatz><link ziel="http://www.line-information.de/"\x0azielfenster="_blank">\x0a<bild name="logo_line_information.gif" rahmen="no"/></link>\x0a</absatz>\x0a\x0a<absatz><bild name="logo_aw.gif" rahmen="no"/></absatz>\x0a\x0a<absatz><link ziel="http://www.incognis.de/"\x0azielfenster="_blank"><bild\x0aname="logo_incognis.gif" rahmen="no"/></link></absatz>\x0a\x0a<absatz><link ziel="http://www.addcraft.com/"\x0azielfenster="_blank"><bild\x0aname="logo_addcraft.gif" rahmen="no"/></link></absatz>\x0a\x0a<absatz><link ziel="http://www.comendo.com/"\x0azielfenster="_blank"><bild\x0aname="logo_comendo.gif" rahmen="no"/></link></absatz>\x0a\x0a</inhalt>\x0a</seite>
+ 1: seite
+ 2: \x0a
+ 3: seite
+
+/^a/IF
+Capturing subpattern count = 0
+Options: anchored
+No first char
+No need char
+
+/ End of testinput2 /
+Capturing subpattern count = 0
+No options
+First char = ' '
+Need char = ' '

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/testdata/testoutput3
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/testdata/testoutput3	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/testdata/testoutput3	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,115 @@
+PCRE version 5.0 13-Sep-2004
+
+/^[\w]+/
+    *** Failers
+No match
+    École
+No match
+
+/^[\w]+/Lfr_FR
+    École
+ 0: École
+
+/^[\w]+/
+    *** Failers
+No match
+    École
+No match
+
+/^[\W]+/
+    École
+ 0: \xc9
+
+/^[\W]+/Lfr_FR
+    *** Failers
+ 0: *** 
+    École
+No match
+
+/[\b]/
+    \b
+ 0: \x08
+    *** Failers
+No match
+    a
+No match
+
+/[\b]/Lfr_FR
+    \b
+ 0: \x08
+    *** Failers
+No match
+    a
+No match
+
+/^\w+/
+    *** Failers
+No match
+    École
+No match
+
+/^\w+/Lfr_FR
+    École
+ 0: École
+
+/(.+)\b(.+)/
+    École
+ 0: \xc9cole
+ 1: \xc9
+ 2: cole
+
+/(.+)\b(.+)/Lfr_FR
+    *** Failers
+ 0: *** Failers
+ 1: *** 
+ 2: Failers
+    École
+No match
+
+/École/i
+    École
+ 0: \xc9cole
+    *** Failers
+No match
+    école
+No match
+
+/École/iLfr_FR
+    École
+ 0: École
+    école
+ 0: école
+
+/\w/IS
+Capturing subpattern count = 0
+No options
+No first char
+No need char
+Starting byte set: 0 1 2 3 4 5 6 7 8 9 A B C D E F G H I J K L M N O P 
+  Q R S T U V W X Y Z _ a b c d e f g h i j k l m n o p q r s t u v w x y z 
+
+/\w/ISLfr_FR
+Capturing subpattern count = 0
+No options
+No first char
+No need char
+Starting byte set: 0 1 2 3 4 5 6 7 8 9 A B C D E F G H I J K L M N O P 
+  Q R S T U V W X Y Z _ a b c d e f g h i j k l m n o p q r s t u v w x y z 
+  µ À Á Â Ã Ä Å Æ Ç È É Ê Ë Ì Í Î Ï Ð Ñ Ò Ó Ô Õ Ö Ø Ù Ú Û Ü Ý Þ ß à á â ã ä 
+  å æ ç è é ê ë ì í î ï ð ñ ò ó ô õ ö ø ù ú û ü ý þ ÿ 
+
+/^[\xc8-\xc9]/iLfr_FR
+    École
+ 0: É
+    école
+ 0: é
+
+/^[\xc8-\xc9]/Lfr_FR
+    École
+ 0: É
+    *** Failers 
+No match
+    école
+No match
+
+/ End of testinput3 /

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/testdata/testoutput4
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/testdata/testoutput4	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/testdata/testoutput4	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,903 @@
+PCRE version 5.0 13-Sep-2004
+
+/-- Do not use the \x{} construct except with patterns that have the --/
+/-- /8 option set, because PCRE doesn't recognize them as UTF-8 unless --/
+No match
+/-- that option is set. However, the latest Perls recognize them always. --/
+No match
+
+/a.b/8
+    acb
+ 0: acb
+    a\x7fb
+ 0: a\x{7f}b
+    a\x{100}b 
+ 0: a\x{100}b
+    *** Failers
+No match
+    a\nb  
+No match
+
+/a(.{3})b/8
+    a\x{4000}xyb 
+ 0: a\x{4000}xyb
+ 1: \x{4000}xy
+    a\x{4000}\x7fyb 
+ 0: a\x{4000}\x{7f}yb
+ 1: \x{4000}\x{7f}y
+    a\x{4000}\x{100}yb 
+ 0: a\x{4000}\x{100}yb
+ 1: \x{4000}\x{100}y
+    *** Failers
+No match
+    a\x{4000}b 
+No match
+    ac\ncb 
+No match
+
+/a(.*?)(.)/
+    a\xc0\x88b
+ 0: a\xc0
+ 1: 
+ 2: \xc0
+
+/a(.*?)(.)/8
+    a\x{100}b
+ 0: a\x{100}
+ 1: 
+ 2: \x{100}
+
+/a(.*)(.)/
+    a\xc0\x88b
+ 0: a\xc0\x88b
+ 1: \xc0\x88
+ 2: b
+
+/a(.*)(.)/8
+    a\x{100}b
+ 0: a\x{100}b
+ 1: \x{100}
+ 2: b
+
+/a(.)(.)/
+    a\xc0\x92bcd
+ 0: a\xc0\x92
+ 1: \xc0
+ 2: \x92
+
+/a(.)(.)/8
+    a\x{240}bcd
+ 0: a\x{240}b
+ 1: \x{240}
+ 2: b
+
+/a(.?)(.)/
+    a\xc0\x92bcd
+ 0: a\xc0\x92
+ 1: \xc0
+ 2: \x92
+
+/a(.?)(.)/8
+    a\x{240}bcd
+ 0: a\x{240}b
+ 1: \x{240}
+ 2: b
+
+/a(.??)(.)/
+    a\xc0\x92bcd
+ 0: a\xc0
+ 1: 
+ 2: \xc0
+
+/a(.??)(.)/8
+    a\x{240}bcd
+ 0: a\x{240}
+ 1: 
+ 2: \x{240}
+
+/a(.{3})b/8
+    a\x{1234}xyb 
+ 0: a\x{1234}xyb
+ 1: \x{1234}xy
+    a\x{1234}\x{4321}yb 
+ 0: a\x{1234}\x{4321}yb
+ 1: \x{1234}\x{4321}y
+    a\x{1234}\x{4321}\x{3412}b 
+ 0: a\x{1234}\x{4321}\x{3412}b
+ 1: \x{1234}\x{4321}\x{3412}
+    *** Failers
+No match
+    a\x{1234}b 
+No match
+    ac\ncb 
+No match
+
+/a(.{3,})b/8
+    a\x{1234}xyb 
+ 0: a\x{1234}xyb
+ 1: \x{1234}xy
+    a\x{1234}\x{4321}yb 
+ 0: a\x{1234}\x{4321}yb
+ 1: \x{1234}\x{4321}y
+    a\x{1234}\x{4321}\x{3412}b 
+ 0: a\x{1234}\x{4321}\x{3412}b
+ 1: \x{1234}\x{4321}\x{3412}
+    axxxxbcdefghijb 
+ 0: axxxxbcdefghijb
+ 1: xxxxbcdefghij
+    a\x{1234}\x{4321}\x{3412}\x{3421}b 
+ 0: a\x{1234}\x{4321}\x{3412}\x{3421}b
+ 1: \x{1234}\x{4321}\x{3412}\x{3421}
+    *** Failers
+No match
+    a\x{1234}b 
+No match
+
+/a(.{3,}?)b/8
+    a\x{1234}xyb 
+ 0: a\x{1234}xyb
+ 1: \x{1234}xy
+    a\x{1234}\x{4321}yb 
+ 0: a\x{1234}\x{4321}yb
+ 1: \x{1234}\x{4321}y
+    a\x{1234}\x{4321}\x{3412}b 
+ 0: a\x{1234}\x{4321}\x{3412}b
+ 1: \x{1234}\x{4321}\x{3412}
+    axxxxbcdefghijb 
+ 0: axxxxb
+ 1: xxxx
+    a\x{1234}\x{4321}\x{3412}\x{3421}b 
+ 0: a\x{1234}\x{4321}\x{3412}\x{3421}b
+ 1: \x{1234}\x{4321}\x{3412}\x{3421}
+    *** Failers
+No match
+    a\x{1234}b 
+No match
+
+/a(.{3,5})b/8
+    a\x{1234}xyb 
+ 0: a\x{1234}xyb
+ 1: \x{1234}xy
+    a\x{1234}\x{4321}yb 
+ 0: a\x{1234}\x{4321}yb
+ 1: \x{1234}\x{4321}y
+    a\x{1234}\x{4321}\x{3412}b 
+ 0: a\x{1234}\x{4321}\x{3412}b
+ 1: \x{1234}\x{4321}\x{3412}
+    axxxxbcdefghijb 
+ 0: axxxxb
+ 1: xxxx
+    a\x{1234}\x{4321}\x{3412}\x{3421}b 
+ 0: a\x{1234}\x{4321}\x{3412}\x{3421}b
+ 1: \x{1234}\x{4321}\x{3412}\x{3421}
+    axbxxbcdefghijb 
+ 0: axbxxb
+ 1: xbxx
+    axxxxxbcdefghijb 
+ 0: axxxxxb
+ 1: xxxxx
+    *** Failers
+No match
+    a\x{1234}b 
+No match
+    axxxxxxbcdefghijb 
+No match
+
+/a(.{3,5}?)b/8
+    a\x{1234}xyb 
+ 0: a\x{1234}xyb
+ 1: \x{1234}xy
+    a\x{1234}\x{4321}yb 
+ 0: a\x{1234}\x{4321}yb
+ 1: \x{1234}\x{4321}y
+    a\x{1234}\x{4321}\x{3412}b 
+ 0: a\x{1234}\x{4321}\x{3412}b
+ 1: \x{1234}\x{4321}\x{3412}
+    axxxxbcdefghijb 
+ 0: axxxxb
+ 1: xxxx
+    a\x{1234}\x{4321}\x{3412}\x{3421}b 
+ 0: a\x{1234}\x{4321}\x{3412}\x{3421}b
+ 1: \x{1234}\x{4321}\x{3412}\x{3421}
+    axbxxbcdefghijb 
+ 0: axbxxb
+ 1: xbxx
+    axxxxxbcdefghijb 
+ 0: axxxxxb
+ 1: xxxxx
+    *** Failers
+No match
+    a\x{1234}b 
+No match
+    axxxxxxbcdefghijb 
+No match
+
+/^[a\x{c0}]/8
+    *** Failers
+No match
+    \x{100}
+No match
+
+/(?<=aXb)cd/8
+    aXbcd
+ 0: cd
+
+/(?<=a\x{100}b)cd/8
+    a\x{100}bcd
+ 0: cd
+
+/(?<=a\x{100000}b)cd/8
+    a\x{100000}bcd
+ 0: cd
+    
+/(?:\x{100}){3}b/8
+    \x{100}\x{100}\x{100}b
+ 0: \x{100}\x{100}\x{100}b
+    *** Failers 
+No match
+    \x{100}\x{100}b
+No match
+
+/\x{ab}/8
+    \x{ab} 
+ 0: \x{ab}
+    \xc2\xab
+ 0: \x{ab}
+    *** Failers 
+No match
+    \x00{ab}
+No match
+
+/(?<=(.))X/8
+    WXYZ
+ 0: X
+ 1: W
+    \x{256}XYZ 
+ 0: X
+ 1: \x{256}
+    *** Failers
+No match
+    XYZ 
+No match
+
+/X(\C{3})/8
+    X\x{1234}
+ 0: X\x{1234}
+ 1: \x{1234}
+
+/X(\C{4})/8
+    X\x{1234}YZ
+ 0: X\x{1234}Y
+ 1: \x{1234}Y
+    
+/X\C*/8
+    XYZabcdce
+ 0: XYZabcdce
+    
+/X\C*?/8
+    XYZabcde
+ 0: X
+    
+/X\C{3,5}/8
+    Xabcdefg   
+ 0: Xabcde
+    X\x{1234} 
+ 0: X\x{1234}
+    X\x{1234}YZ
+ 0: X\x{1234}YZ
+    X\x{1234}\x{512}  
+ 0: X\x{1234}\x{512}
+    X\x{1234}\x{512}YZ
+ 0: X\x{1234}\x{512}
+
+/X\C{3,5}?/8
+    Xabcdefg   
+ 0: Xabc
+    X\x{1234} 
+ 0: X\x{1234}
+    X\x{1234}YZ
+ 0: X\x{1234}
+    X\x{1234}\x{512}  
+ 0: X\x{1234}
+
+/[^a]+/8g
+    bcd
+ 0: bcd
+    \x{100}aY\x{256}Z 
+ 0: \x{100}
+ 0: Y\x{256}Z
+    
+/^[^a]{2}/8
+    \x{100}bc
+ 0: \x{100}b
+ 
+/^[^a]{2,}/8
+    \x{100}bcAa
+ 0: \x{100}bcA
+
+/^[^a]{2,}?/8
+    \x{100}bca
+ 0: \x{100}b
+
+/[^a]+/8ig
+    bcd
+ 0: bcd
+    \x{100}aY\x{256}Z 
+ 0: \x{100}
+ 0: Y\x{256}Z
+    
+/^[^a]{2}/8i
+    \x{100}bc
+ 0: \x{100}b
+ 
+/^[^a]{2,}/8i
+    \x{100}bcAa
+ 0: \x{100}bc
+
+/^[^a]{2,}?/8i
+    \x{100}bca
+ 0: \x{100}b
+
+/\x{100}{0,0}/8
+    abcd
+ 0: 
+ 
+/\x{100}?/8
+    abcd
+ 0: 
+    \x{100}\x{100} 
+ 0: \x{100}
+
+/\x{100}{0,3}/8 
+    \x{100}\x{100} 
+ 0: \x{100}\x{100}
+    \x{100}\x{100}\x{100}\x{100} 
+ 0: \x{100}\x{100}\x{100}
+    
+/\x{100}*/8
+    abce
+ 0: 
+    \x{100}\x{100}\x{100}\x{100} 
+ 0: \x{100}\x{100}\x{100}\x{100}
+
+/\x{100}{1,1}/8
+    abcd\x{100}\x{100}\x{100}\x{100} 
+ 0: \x{100}
+
+/\x{100}{1,3}/8
+    abcd\x{100}\x{100}\x{100}\x{100} 
+ 0: \x{100}\x{100}\x{100}
+
+/\x{100}+/8
+    abcd\x{100}\x{100}\x{100}\x{100} 
+ 0: \x{100}\x{100}\x{100}\x{100}
+
+/\x{100}{3}/8
+    abcd\x{100}\x{100}\x{100}XX
+ 0: \x{100}\x{100}\x{100}
+
+/\x{100}{3,5}/8
+    abcd\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}XX
+ 0: \x{100}\x{100}\x{100}\x{100}\x{100}
+
+/\x{100}{3,}/8
+    abcd\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}XX
+ 0: \x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}
+
+/(?<=a\x{100}{2}b)X/8+
+    Xyyya\x{100}\x{100}bXzzz
+ 0: X
+ 0+ zzz
+
+/\D*/8
+  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+ 0: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+
+/\D*/8
+  \x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}
+ 0: \x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}\x{100}
+
+/\D/8
+    1X2
+ 0: X
+    1\x{100}2 
+ 0: \x{100}
+  
+/>\S/8
+    > >X Y
+ 0: >X
+    > >\x{100} Y
+ 0: >\x{100}
+  
+/\d/8
+    \x{100}3
+ 0: 3
+    
+/\s/8
+    \x{100} X
+ 0:  
+    
+/\D+/8
+    12abcd34
+ 0: abcd
+    *** Failers
+ 0: *** Failers
+    1234  
+No match
+
+/\D{2,3}/8
+    12abcd34
+ 0: abc
+    12ab34
+ 0: ab
+    *** Failers  
+ 0: ***
+    1234
+No match
+    12a34  
+No match
+
+/\D{2,3}?/8
+    12abcd34
+ 0: ab
+    12ab34
+ 0: ab
+    *** Failers  
+ 0: **
+    1234
+No match
+    12a34  
+No match
+
+/\d+/8
+    12abcd34
+ 0: 12
+    *** Failers
+No match
+
+/\d{2,3}/8
+    12abcd34
+ 0: 12
+    1234abcd
+ 0: 123
+    *** Failers  
+No match
+    1.4 
+No match
+
+/\d{2,3}?/8
+    12abcd34
+ 0: 12
+    1234abcd
+ 0: 12
+    *** Failers  
+No match
+    1.4 
+No match
+
+/\S+/8
+    12abcd34
+ 0: 12abcd34
+    *** Failers
+ 0: ***
+    \    \ 
+No match
+
+/\S{2,3}/8
+    12abcd34
+ 0: 12a
+    1234abcd
+ 0: 123
+    *** Failers
+ 0: ***
+    \     \  
+No match
+
+/\S{2,3}?/8
+    12abcd34
+ 0: 12
+    1234abcd
+ 0: 12
+    *** Failers
+ 0: **
+    \     \  
+No match
+
+/>\s+</8+
+    12>      <34
+ 0: >      <
+ 0+ 34
+    *** Failers
+No match
+
+/>\s{2,3}</8+
+    ab>  <cd
+ 0: >  <
+ 0+ cd
+    ab>   <ce
+ 0: >   <
+ 0+ ce
+    *** Failers
+No match
+    ab>    <cd 
+No match
+
+/>\s{2,3}?</8+
+    ab>  <cd
+ 0: >  <
+ 0+ cd
+    ab>   <ce
+ 0: >   <
+ 0+ ce
+    *** Failers
+No match
+    ab>    <cd 
+No match
+
+/\w+/8
+    12      34
+ 0: 12
+    *** Failers
+ 0: Failers
+    +++=*! 
+No match
+
+/\w{2,3}/8
+    ab  cd
+ 0: ab
+    abcd ce
+ 0: abc
+    *** Failers
+ 0: Fai
+    a.b.c
+No match
+
+/\w{2,3}?/8
+    ab  cd
+ 0: ab
+    abcd ce
+ 0: ab
+    *** Failers
+ 0: Fa
+    a.b.c
+No match
+
+/\W+/8
+    12====34
+ 0: ====
+    *** Failers
+ 0: *** 
+    abcd 
+No match
+
+/\W{2,3}/8
+    ab====cd
+ 0: ===
+    ab==cd
+ 0: ==
+    *** Failers
+ 0: ***
+    a.b.c
+No match
+
+/\W{2,3}?/8
+    ab====cd
+ 0: ==
+    ab==cd
+ 0: ==
+    *** Failers
+ 0: **
+    a.b.c
+No match
+
+/[\x{100}]/8
+    \x{100}
+ 0: \x{100}
+    Z\x{100}
+ 0: \x{100}
+    \x{100}Z
+ 0: \x{100}
+    *** Failers 
+No match
+
+/[Z\x{100}]/8
+    Z\x{100}
+ 0: Z
+    \x{100}
+ 0: \x{100}
+    \x{100}Z
+ 0: \x{100}
+    *** Failers 
+No match
+
+/[\x{100}\x{200}]/8
+   ab\x{100}cd
+ 0: \x{100}
+   ab\x{200}cd
+ 0: \x{200}
+   *** Failers  
+No match
+
+/[\x{100}-\x{200}]/8
+   ab\x{100}cd
+ 0: \x{100}
+   ab\x{200}cd
+ 0: \x{200}
+   ab\x{111}cd 
+ 0: \x{111}
+   *** Failers  
+No match
+
+/[z-\x{200}]/8
+   ab\x{100}cd
+ 0: \x{100}
+   ab\x{200}cd
+ 0: \x{200}
+   ab\x{111}cd 
+ 0: \x{111}
+   abzcd
+ 0: z
+   ab|cd  
+ 0: |
+   *** Failers  
+No match
+
+/[Q\x{100}\x{200}]/8
+   ab\x{100}cd
+ 0: \x{100}
+   ab\x{200}cd
+ 0: \x{200}
+   Q? 
+ 0: Q
+   *** Failers  
+No match
+
+/[Q\x{100}-\x{200}]/8
+   ab\x{100}cd
+ 0: \x{100}
+   ab\x{200}cd
+ 0: \x{200}
+   ab\x{111}cd 
+ 0: \x{111}
+   Q? 
+ 0: Q
+   *** Failers  
+No match
+
+/[Qz-\x{200}]/8
+   ab\x{100}cd
+ 0: \x{100}
+   ab\x{200}cd
+ 0: \x{200}
+   ab\x{111}cd 
+ 0: \x{111}
+   abzcd
+ 0: z
+   ab|cd  
+ 0: |
+   Q? 
+ 0: Q
+   *** Failers  
+No match
+
+/[\x{100}\x{200}]{1,3}/8
+   ab\x{100}cd
+ 0: \x{100}
+   ab\x{200}cd
+ 0: \x{200}
+   ab\x{200}\x{100}\x{200}\x{100}cd
+ 0: \x{200}\x{100}\x{200}
+   *** Failers  
+No match
+
+/[\x{100}\x{200}]{1,3}?/8
+   ab\x{100}cd
+ 0: \x{100}
+   ab\x{200}cd
+ 0: \x{200}
+   ab\x{200}\x{100}\x{200}\x{100}cd
+ 0: \x{200}
+   *** Failers  
+No match
+
+/[Q\x{100}\x{200}]{1,3}/8
+   ab\x{100}cd
+ 0: \x{100}
+   ab\x{200}cd
+ 0: \x{200}
+   ab\x{200}\x{100}\x{200}\x{100}cd
+ 0: \x{200}\x{100}\x{200}
+   *** Failers  
+No match
+
+/[Q\x{100}\x{200}]{1,3}?/8
+   ab\x{100}cd
+ 0: \x{100}
+   ab\x{200}cd
+ 0: \x{200}
+   ab\x{200}\x{100}\x{200}\x{100}cd
+ 0: \x{200}
+   *** Failers  
+No match
+
+/(?<=[\x{100}\x{200}])X/8
+    abc\x{200}X
+ 0: X
+    abc\x{100}X 
+ 0: X
+    *** Failers
+No match
+    X  
+No match
+
+/(?<=[Q\x{100}\x{200}])X/8
+    abc\x{200}X
+ 0: X
+    abc\x{100}X 
+ 0: X
+    abQX 
+ 0: X
+    *** Failers
+No match
+    X  
+No match
+
+/(?<=[\x{100}\x{200}]{3})X/8
+    abc\x{100}\x{200}\x{100}X
+ 0: X
+    *** Failers
+No match
+    abc\x{200}X
+No match
+    X  
+No match
+
+/[^\x{100}\x{200}]X/8
+    AX
+ 0: AX
+    \x{150}X
+ 0: \x{150}X
+    \x{500}X 
+ 0: \x{500}X
+    *** Failers
+No match
+    \x{100}X
+No match
+    \x{200}X   
+No match
+
+/[^Q\x{100}\x{200}]X/8
+    AX
+ 0: AX
+    \x{150}X
+ 0: \x{150}X
+    \x{500}X 
+ 0: \x{500}X
+    *** Failers
+No match
+    \x{100}X
+No match
+    \x{200}X   
+No match
+    QX 
+No match
+
+/[^\x{100}-\x{200}]X/8
+    AX
+ 0: AX
+    \x{500}X 
+ 0: \x{500}X
+    *** Failers
+No match
+    \x{100}X
+No match
+    \x{150}X
+No match
+    \x{200}X   
+No match
+
+/a\Cb/
+    aXb
+ 0: aXb
+    a\nb
+ 0: a\x0ab
+  
+/a\Cb/8
+    aXb
+ 0: aXb
+    a\nb
+ 0: a\x{0a}b
+    *** Failers 
+No match
+    a\x{100}b 
+No match
+
+/[z-\x{100}]/8i
+    z
+ 0: z
+    Z 
+ 0: Z
+    \x{100}
+ 0: \x{100}
+    *** Failers
+No match
+    \x{102}
+No match
+    y    
+No match
+
+/[\xFF]/
+    >\xff<
+ 0: \xff
+
+/[\xff]/8
+    >\x{ff}<
+ 0: \x{ff}
+
+/[^\xFF]/
+    XYZ
+ 0: X
+
+/[^\xff]/8
+    XYZ
+ 0: X
+    \x{123} 
+ 0: \x{123}
+
+/^[ac]*b/8
+  xb
+No match
+
+/^[ac\x{100}]*b/8
+  xb
+No match
+
+/^[^x]*b/8i
+  xb
+No match
+
+/^[^x]*b/8
+  xb
+No match
+  
+/^\d*b/8
+  xb 
+No match
+
+/(|a)/g8
+    catac
+ 0: 
+ 1: 
+ 0: 
+ 1: 
+ 0: a
+ 1: a
+ 0: 
+ 1: 
+ 0: 
+ 1: 
+ 0: a
+ 1: a
+ 0: 
+ 1: 
+ 0: 
+ 1: 
+    a\x{256}a 
+ 0: 
+ 1: 
+ 0: a
+ 1: a
+ 0: 
+ 1: 
+ 0: 
+ 1: 
+ 0: a
+ 1: a
+ 0: 
+ 1: 
+
+/^\x{85}$/8i
+    \x{85}
+ 0: \x{85}
+
+/ End of testinput4 /

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/testdata/testoutput5
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/testdata/testoutput5	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/testdata/testoutput5	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,1075 @@
+PCRE version 5.0 13-Sep-2004
+
+/\x{100}/8DM
+Memory allocation (code space): 10
+------------------------------------------------------------------
+  0   6 Bra 0
+  3     \x{100}
+  6   6 Ket
+  9     End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Options: utf8
+First char = 196
+Need char = 128
+
+/\x{1000}/8DM
+Memory allocation (code space): 11
+------------------------------------------------------------------
+  0   7 Bra 0
+  3     \x{1000}
+  7   7 Ket
+ 10     End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Options: utf8
+First char = 225
+Need char = 128
+
+/\x{10000}/8DM
+Memory allocation (code space): 12
+------------------------------------------------------------------
+  0   8 Bra 0
+  3     \x{10000}
+  8   8 Ket
+ 11     End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Options: utf8
+First char = 240
+Need char = 128
+
+/\x{100000}/8DM
+Memory allocation (code space): 12
+------------------------------------------------------------------
+  0   8 Bra 0
+  3     \x{100000}
+  8   8 Ket
+ 11     End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Options: utf8
+First char = 244
+Need char = 128
+
+/\x{1000000}/8DM
+Memory allocation (code space): 13
+------------------------------------------------------------------
+  0   9 Bra 0
+  3     \x{1000000}
+  9   9 Ket
+ 12     End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Options: utf8
+First char = 249
+Need char = 128
+
+/\x{4000000}/8DM
+Memory allocation (code space): 14
+------------------------------------------------------------------
+  0  10 Bra 0
+  3     \x{4000000}
+ 10  10 Ket
+ 13     End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Options: utf8
+First char = 252
+Need char = 128
+
+/\x{7fffFFFF}/8DM
+Memory allocation (code space): 14
+------------------------------------------------------------------
+  0  10 Bra 0
+  3     \x{7fffffff}
+ 10  10 Ket
+ 13     End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Options: utf8
+First char = 253
+Need char = 191
+
+/[\x{ff}]/8DM
+Memory allocation (code space): 10
+------------------------------------------------------------------
+  0   6 Bra 0
+  3     \x{ff}
+  6   6 Ket
+  9     End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Options: utf8
+First char = 195
+Need char = 191
+
+/[\x{100}]/8DM
+Memory allocation (code space): 47
+------------------------------------------------------------------
+  0  11 Bra 0
+  3     [\x{100}]
+ 11  11 Ket
+ 14     End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Options: utf8
+No first char
+No need char
+
+/\x{ffffffff}/8
+Failed: character value in \x{...} sequence is too large at offset 11
+
+/\x{100000000}/8
+Failed: character value in \x{...} sequence is too large at offset 12
+
+/^\x{100}a\x{1234}/8
+    \x{100}a\x{1234}bcd
+ 0: \x{100}a\x{1234}
+
+/\x80/8D
+------------------------------------------------------------------
+  0   6 Bra 0
+  3     \x{80}
+  6   6 Ket
+  9     End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Options: utf8
+First char = 194
+Need char = 128
+
+/\xff/8D
+------------------------------------------------------------------
+  0   6 Bra 0
+  3     \x{ff}
+  6   6 Ket
+  9     End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Options: utf8
+First char = 195
+Need char = 191
+
+/\x{0041}\x{2262}\x{0391}\x{002e}/D8
+------------------------------------------------------------------
+  0  14 Bra 0
+  3     A\x{2262}\x{391}.
+ 14  14 Ket
+ 17     End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Options: utf8
+First char = 'A'
+Need char = '.'
+    \x{0041}\x{2262}\x{0391}\x{002e}
+ 0: A\x{2262}\x{391}.
+    
+/\x{D55c}\x{ad6d}\x{C5B4}/D8 
+------------------------------------------------------------------
+  0  15 Bra 0
+  3     \x{d55c}\x{ad6d}\x{c5b4}
+ 15  15 Ket
+ 18     End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Options: utf8
+First char = 237
+Need char = 180
+    \x{D55c}\x{ad6d}\x{C5B4} 
+ 0: \x{d55c}\x{ad6d}\x{c5b4}
+
+/\x{65e5}\x{672c}\x{8a9e}/D8
+------------------------------------------------------------------
+  0  15 Bra 0
+  3     \x{65e5}\x{672c}\x{8a9e}
+ 15  15 Ket
+ 18     End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Options: utf8
+First char = 230
+Need char = 158
+    \x{65e5}\x{672c}\x{8a9e}
+ 0: \x{65e5}\x{672c}\x{8a9e}
+
+/\x{80}/D8
+------------------------------------------------------------------
+  0   6 Bra 0
+  3     \x{80}
+  6   6 Ket
+  9     End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Options: utf8
+First char = 194
+Need char = 128
+
+/\x{084}/D8
+------------------------------------------------------------------
+  0   6 Bra 0
+  3     \x{84}
+  6   6 Ket
+  9     End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Options: utf8
+First char = 194
+Need char = 132
+
+/\x{104}/D8
+------------------------------------------------------------------
+  0   6 Bra 0
+  3     \x{104}
+  6   6 Ket
+  9     End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Options: utf8
+First char = 196
+Need char = 132
+
+/\x{861}/D8
+------------------------------------------------------------------
+  0   7 Bra 0
+  3     \x{861}
+  7   7 Ket
+ 10     End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Options: utf8
+First char = 224
+Need char = 161
+
+/\x{212ab}/D8
+------------------------------------------------------------------
+  0   8 Bra 0
+  3     \x{212ab}
+  8   8 Ket
+ 11     End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Options: utf8
+First char = 240
+Need char = 171
+
+/.{3,5}X/D8
+------------------------------------------------------------------
+  0  13 Bra 0
+  3     Any{3}
+  7     Any{0,2}
+ 11     X
+ 13  13 Ket
+ 16     End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Partial matching not supported
+Options: utf8
+No first char
+Need char = 'X'
+    \x{212ab}\x{212ab}\x{212ab}\x{861}X
+ 0: \x{212ab}\x{212ab}\x{212ab}\x{861}X
+
+
+/.{3,5}?/D8
+------------------------------------------------------------------
+  0  11 Bra 0
+  3     Any{3}
+  7     Any{0,2}?
+ 11  11 Ket
+ 14     End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Partial matching not supported
+Options: utf8
+No first char
+No need char
+    \x{212ab}\x{212ab}\x{212ab}\x{861}
+ 0: \x{212ab}\x{212ab}\x{212ab}
+
+/-- These tests are here rather than in testinput4 because Perl 5.6 has --/
+/-- some problems with UTF-8 support, in the area of \x{..} where the   --/
+No match
+/-- value is < 255. It grumbles about invalid UTF-8 strings.            --/
+No match
+
+/^[a\x{c0}]b/8
+    \x{c0}b
+ 0: \x{c0}b
+    
+/^([a\x{c0}]*?)aa/8
+    a\x{c0}aaaa/ 
+ 0: a\x{c0}aa
+ 1: a\x{c0}
+
+/^([a\x{c0}]*?)aa/8
+    a\x{c0}aaaa/ 
+ 0: a\x{c0}aa
+ 1: a\x{c0}
+    a\x{c0}a\x{c0}aaa/ 
+ 0: a\x{c0}a\x{c0}aa
+ 1: a\x{c0}a\x{c0}
+
+/^([a\x{c0}]*)aa/8
+    a\x{c0}aaaa/ 
+ 0: a\x{c0}aaaa
+ 1: a\x{c0}aa
+    a\x{c0}a\x{c0}aaa/ 
+ 0: a\x{c0}a\x{c0}aaa
+ 1: a\x{c0}a\x{c0}a
+
+/^([a\x{c0}]*)a\x{c0}/8
+    a\x{c0}aaaa/ 
+ 0: a\x{c0}
+ 1: 
+    a\x{c0}a\x{c0}aaa/ 
+ 0: a\x{c0}a\x{c0}
+ 1: a\x{c0}
+    
+/-- --/ 
+    
+/(?<=\C)X/8
+Failed: \C not allowed in lookbehind assertion at offset 6
+
+/-- This one is here not because it's different to Perl, but because the --/
+/-- way the captured single-byte is displayed. (In Perl it becomes a --/
+No match
+/-- character, and you can't tell the difference.) --/
+No match
+    
+/X(\C)(.*)/8
+    X\x{1234}
+ 0: X\x{1234}
+ 1: \xe1
+ 2: \x88\xb4
+    X\nabc 
+ 0: X\x{0a}abc
+ 1: \x{0a}
+ 2: abc
+    
+/^[ab]/8D
+------------------------------------------------------------------
+  0  37 Bra 0
+  3     ^
+  4     [ab]
+ 37  37 Ket
+ 40     End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Options: anchored utf8
+No first char
+No need char
+    bar
+ 0: b
+    *** Failers
+No match
+    c
+No match
+    \x{ff}
+No match
+    \x{100}  
+No match
+
+/^[^ab]/8D
+------------------------------------------------------------------
+  0  37 Bra 0
+  3     ^
+  4     [\x00-`c-\xff] (neg)
+ 37  37 Ket
+ 40     End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Options: anchored utf8
+No first char
+No need char
+    c
+ 0: c
+    \x{ff}
+ 0: \x{ff}
+    \x{100}  
+ 0: \x{100}
+    *** Failers 
+ 0: *
+    aaa
+No match
+  
+/[^ab\xC0-\xF0]/8SD
+------------------------------------------------------------------
+  0  36 Bra 0
+  3     [\x00-`c-\xbf\xf1-\xff] (neg)
+ 36  36 Ket
+ 39     End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Options: utf8
+No first char
+No need char
+Starting byte set: \x00 \x01 \x02 \x03 \x04 \x05 \x06 \x07 \x08 \x09 \x0a 
+  \x0b \x0c \x0d \x0e \x0f \x10 \x11 \x12 \x13 \x14 \x15 \x16 \x17 \x18 \x19 
+  \x1a \x1b \x1c \x1d \x1e \x1f \x20 ! " # $ % & ' ( ) * + , - . / 0 1 2 3 4 
+  5 6 7 8 9 : ; < = > ? @ A B C D E F G H I J K L M N O P Q R S T U V W X Y 
+  Z [ \ ] ^ _ ` c d e f g h i j k l m n o p q r s t u v w x y z { | } ~ \x7f 
+  \xc2 \xc3 \xc4 \xc5 \xc6 \xc7 \xc8 \xc9 \xca \xcb \xcc \xcd \xce \xcf \xd0 
+  \xd1 \xd2 \xd3 \xd4 \xd5 \xd6 \xd7 \xd8 \xd9 \xda \xdb \xdc \xdd \xde \xdf 
+  \xe0 \xe1 \xe2 \xe3 \xe4 \xe5 \xe6 \xe7 \xe8 \xe9 \xea \xeb \xec \xed \xee 
+  \xef \xf0 \xf1 \xf2 \xf3 \xf4 \xf5 \xf6 \xf7 \xf8 \xf9 \xfa \xfb \xfc \xfd 
+  \xfe \xff 
+    \x{f1}
+ 0: \x{f1}
+    \x{bf}
+ 0: \x{bf}
+    \x{100}
+ 0: \x{100}
+    \x{1000}   
+ 0: \x{1000}
+    *** Failers
+ 0: *
+    \x{c0} 
+No match
+    \x{f0} 
+No match
+
+/Ä€{3,4}/8SD
+------------------------------------------------------------------
+  0  13 Bra 0
+  3     \x{100}{3}
+  8     \x{100}{,1}
+ 13  13 Ket
+ 16     End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Partial matching not supported
+Options: utf8
+First char = 196
+Need char = 128
+Study returned NULL
+  \x{100}\x{100}\x{100}\x{100\x{100}
+ 0: \x{100}\x{100}\x{100}
+
+/(\x{100}+|x)/8SD
+------------------------------------------------------------------
+  0  17 Bra 0
+  3   6 Bra 1
+  6     \x{100}+
+  9   5 Alt
+ 12     x
+ 14  11 Ket
+ 17  17 Ket
+ 20     End
+------------------------------------------------------------------
+Capturing subpattern count = 1
+Partial matching not supported
+Options: utf8
+No first char
+No need char
+Starting byte set: x \xc4 
+
+/(\x{100}*a|x)/8SD
+------------------------------------------------------------------
+  0  19 Bra 0
+  3   8 Bra 1
+  6     \x{100}*
+  9     a
+ 11   5 Alt
+ 14     x
+ 16  13 Ket
+ 19  19 Ket
+ 22     End
+------------------------------------------------------------------
+Capturing subpattern count = 1
+Partial matching not supported
+Options: utf8
+No first char
+No need char
+Starting byte set: a x \xc4 
+
+/(\x{100}{0,2}a|x)/8SD
+------------------------------------------------------------------
+  0  21 Bra 0
+  3  10 Bra 1
+  6     \x{100}{,2}
+ 11     a
+ 13   5 Alt
+ 16     x
+ 18  15 Ket
+ 21  21 Ket
+ 24     End
+------------------------------------------------------------------
+Capturing subpattern count = 1
+Partial matching not supported
+Options: utf8
+No first char
+No need char
+Starting byte set: a x \xc4 
+
+/(\x{100}{1,2}a|x)/8SD
+------------------------------------------------------------------
+  0  24 Bra 0
+  3  13 Bra 1
+  6     \x{100}
+  9     \x{100}{,1}
+ 14     a
+ 16   5 Alt
+ 19     x
+ 21  18 Ket
+ 24  24 Ket
+ 27     End
+------------------------------------------------------------------
+Capturing subpattern count = 1
+Partial matching not supported
+Options: utf8
+No first char
+No need char
+Starting byte set: x \xc4 
+
+/\x{100}*(\d+|"(?1)")/8
+    1234
+ 0: 1234
+ 1: 1234
+    "1234" 
+ 0: "1234"
+ 1: "1234"
+    \x{100}1234
+ 0: \x{100}1234
+ 1: 1234
+    "\x{100}1234"  
+ 0: \x{100}1234
+ 1: 1234
+    \x{100}\x{100}12ab 
+ 0: \x{100}\x{100}12
+ 1: 12
+    \x{100}\x{100}"12" 
+ 0: \x{100}\x{100}"12"
+ 1: "12"
+    *** Failers 
+No match
+    \x{100}\x{100}abcd
+No match
+
+/\x{100}/8D
+------------------------------------------------------------------
+  0   6 Bra 0
+  3     \x{100}
+  6   6 Ket
+  9     End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Options: utf8
+First char = 196
+Need char = 128
+
+/\x{100}*/8D
+------------------------------------------------------------------
+  0   6 Bra 0
+  3     \x{100}*
+  6   6 Ket
+  9     End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Partial matching not supported
+Options: utf8
+No first char
+No need char
+
+/a\x{100}*/8D
+------------------------------------------------------------------
+  0   8 Bra 0
+  3     a
+  5     \x{100}*
+  8   8 Ket
+ 11     End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Partial matching not supported
+Options: utf8
+First char = 'a'
+No need char
+
+/ab\x{100}*/8D
+------------------------------------------------------------------
+  0  10 Bra 0
+  3     ab
+  7     \x{100}*
+ 10  10 Ket
+ 13     End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Partial matching not supported
+Options: utf8
+First char = 'a'
+Need char = 'b'
+
+/a\x{100}\x{101}*/8D
+------------------------------------------------------------------
+  0  11 Bra 0
+  3     a\x{100}
+  8     \x{101}*
+ 11  11 Ket
+ 14     End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Partial matching not supported
+Options: utf8
+First char = 'a'
+Need char = 128
+
+/a\x{100}\x{101}+/8D
+------------------------------------------------------------------
+  0  11 Bra 0
+  3     a\x{100}
+  8     \x{101}+
+ 11  11 Ket
+ 14     End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Partial matching not supported
+Options: utf8
+First char = 'a'
+Need char = 129
+
+/\x{100}*A/8D
+------------------------------------------------------------------
+  0   8 Bra 0
+  3     \x{100}*
+  6     A
+  8   8 Ket
+ 11     End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Partial matching not supported
+Options: utf8
+No first char
+Need char = 'A'
+    A
+ 0: A
+
+/\x{100}*\d(?R)/8D
+------------------------------------------------------------------
+  0  10 Bra 0
+  3     \x{100}*
+  6     \d
+  7   0 Recurse
+ 10  10 Ket
+ 13     End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Partial matching not supported
+Options: utf8
+No first char
+No need char
+
+/[^\x{c4}]/D
+------------------------------------------------------------------
+  0  36 Bra 0
+  3     [\x01-35-bd-z|~-\xff] (neg)
+ 36  36 Ket
+ 39     End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+No options
+No first char
+No need char
+
+/[^\x{c4}]/8D
+------------------------------------------------------------------
+  0  36 Bra 0
+  3     [\x00-\xc3\xc5-\xff] (neg)
+ 36  36 Ket
+ 39     End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Options: utf8
+No first char
+No need char
+
+/[\x{100}]/8DM
+Memory allocation (code space): 47
+------------------------------------------------------------------
+  0  11 Bra 0
+  3     [\x{100}]
+ 11  11 Ket
+ 14     End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Options: utf8
+No first char
+No need char
+    \x{100}
+ 0: \x{100}
+    Z\x{100}
+ 0: \x{100}
+    \x{100}Z
+ 0: \x{100}
+    *** Failers 
+No match
+
+/[Z\x{100}]/8DM
+Memory allocation (code space): 47
+------------------------------------------------------------------
+  0  43 Bra 0
+  3     [Z\x{100}]
+ 43  43 Ket
+ 46     End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Options: utf8
+No first char
+No need char
+    Z\x{100}
+ 0: Z
+    \x{100}
+ 0: \x{100}
+    \x{100}Z
+ 0: \x{100}
+    *** Failers 
+No match
+
+/[\x{200}-\x{100}]/8
+Failed: range out of order in character class at offset 15
+
+/[Ä€-Ä„]/8
+    \x{100}
+ 0: \x{100}
+    \x{104}
+ 0: \x{104}
+    *** Failers
+No match
+    \x{105}
+No match
+    \x{ff}    
+No match
+
+/[z-\x{100}]/8D
+------------------------------------------------------------------
+  0  12 Bra 0
+  3     [z-\x{100}]
+ 12  12 Ket
+ 15     End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Options: utf8
+No first char
+No need char
+
+/[z\Qa-d]Ä€\E]/8D
+------------------------------------------------------------------
+  0  43 Bra 0
+  3     [\-\]adz\x{100}]
+ 43  43 Ket
+ 46     End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Options: utf8
+No first char
+No need char
+    \x{100}
+ 0: \x{100}
+    Ā 
+ 0: \x{100}
+
+/[\xFF]/D
+------------------------------------------------------------------
+  0   5 Bra 0
+  3     \xff
+  5   5 Ket
+  8     End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+No options
+First char = 255
+No need char
+    >\xff<
+ 0: \xff
+
+/[\xff]/D8
+------------------------------------------------------------------
+  0   6 Bra 0
+  3     \x{ff}
+  6   6 Ket
+  9     End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Options: utf8
+First char = 195
+Need char = 191
+    >\x{ff}<
+ 0: \x{ff}
+
+/[^\xFF]/D
+------------------------------------------------------------------
+  0   5 Bra 0
+  3     [^\xff]
+  5   5 Ket
+  8     End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+No options
+No first char
+No need char
+
+/[^\xff]/8D
+------------------------------------------------------------------
+  0  36 Bra 0
+  3     [\x00-\xfe] (neg)
+ 36  36 Ket
+ 39     End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Options: utf8
+No first char
+No need char
+
+/[Ä-Ü]/8
+    Ö # Matches without Study
+ 0: \x{d6}
+    \x{d6}
+ 0: \x{d6}
+    
+/[Ä-Ü]/8S
+    Ö <-- Same with Study
+ 0: \x{d6}
+    \x{d6}
+ 0: \x{d6}
+    
+/[\x{c4}-\x{dc}]/8 
+    Ö # Matches without Study
+ 0: \x{d6}
+    \x{d6} 
+ 0: \x{d6}
+
+/[\x{c4}-\x{dc}]/8S
+    Ö <-- Same with Study
+ 0: \x{d6}
+    \x{d6} 
+ 0: \x{d6}
+
+/[Ã]/8
+Failed: invalid UTF-8 string at offset 2
+
+/Ã/8
+Failed: invalid UTF-8 string at offset 0
+
+/ÃÃÃxxx/8
+Failed: invalid UTF-8 string at offset 1
+
+/ÃÃÃxxx/8?D
+------------------------------------------------------------------
+  0  15 Bra 0
+  3     \X{c0}\X{c0}\X{c0}xxx
+ 15  15 Ket
+ 18     End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Options: utf8 no_utf8_check
+First char = 195
+Need char = 'x'
+
+/abc/8
+    Ã]
+Error -10
+    Ã
+Error -10
+    ÃÃÃ
+Error -10
+    ÃÃÃ\?
+No match
+
+/anything/8
+    \xc0\x80
+Error -10
+    \xc1\x8f 
+Error -10
+    \xe0\x9f\x80
+Error -10
+    \xf0\x8f\x80\x80 
+Error -10
+    \xf8\x87\x80\x80\x80  
+Error -10
+    \xfc\x83\x80\x80\x80\x80
+Error -10
+    \xfe\x80\x80\x80\x80\x80  
+Error -10
+    \xff\x80\x80\x80\x80\x80  
+Error -10
+    \xc3\x8f
+No match
+    \xe0\xaf\x80
+No match
+    \xe1\x80\x80
+No match
+    \xf0\x9f\x80\x80 
+No match
+    \xf1\x8f\x80\x80 
+No match
+    \xf8\x88\x80\x80\x80  
+No match
+    \xf9\x87\x80\x80\x80  
+No match
+    \xfc\x84\x80\x80\x80\x80
+No match
+    \xfd\x83\x80\x80\x80\x80
+No match
+
+/\x{100}abc(xyz(?1))/8D
+------------------------------------------------------------------
+  0  27 Bra 0
+  3     \x{100}abc
+ 12  12 Bra 1
+ 15     xyz
+ 21  12 Recurse
+ 24  12 Ket
+ 27  27 Ket
+ 30     End
+------------------------------------------------------------------
+Capturing subpattern count = 1
+Options: utf8
+First char = 196
+Need char = 'z'
+
+/[^\x{100}]abc(xyz(?1))/8D
+------------------------------------------------------------------
+  0  32 Bra 0
+  3     [^\x{100}]
+ 11     abc
+ 17  12 Bra 1
+ 20     xyz
+ 26  17 Recurse
+ 29  12 Ket
+ 32  32 Ket
+ 35     End
+------------------------------------------------------------------
+Capturing subpattern count = 1
+Options: utf8
+No first char
+Need char = 'z'
+
+/[ab\x{100}]abc(xyz(?1))/8D
+------------------------------------------------------------------
+  0  64 Bra 0
+  3     [ab\x{100}]
+ 43     abc
+ 49  12 Bra 1
+ 52     xyz
+ 58  49 Recurse
+ 61  12 Ket
+ 64  64 Ket
+ 67     End
+------------------------------------------------------------------
+Capturing subpattern count = 1
+Options: utf8
+No first char
+Need char = 'z'
+
+/(\x{100}(b(?2)c))?/D8
+------------------------------------------------------------------
+  0  26 Bra 0
+  3     Brazero
+  4  19 Bra 1
+  7     \x{100}
+ 10  10 Bra 2
+ 13     b
+ 15  10 Recurse
+ 18     c
+ 20  10 Ket
+ 23  19 Ket
+ 26  26 Ket
+ 29     End
+------------------------------------------------------------------
+Capturing subpattern count = 2
+Options: utf8
+No first char
+No need char
+
+/(\x{100}(b(?2)c)){0,2}/D8
+------------------------------------------------------------------
+  0  55 Bra 0
+  3     Brazero
+  4  48 Bra 0
+  7  19 Bra 1
+ 10     \x{100}
+ 13  10 Bra 2
+ 16     b
+ 18  13 Recurse
+ 21     c
+ 23  10 Ket
+ 26  19 Ket
+ 29     Brazero
+ 30  19 Bra 1
+ 33     \x{100}
+ 36  10 Bra 2
+ 39     b
+ 41  13 Recurse
+ 44     c
+ 46  10 Ket
+ 49  19 Ket
+ 52  48 Ket
+ 55  55 Ket
+ 58     End
+------------------------------------------------------------------
+Capturing subpattern count = 2
+Options: utf8
+No first char
+No need char
+
+/(\x{100}(b(?1)c))?/D8
+------------------------------------------------------------------
+  0  26 Bra 0
+  3     Brazero
+  4  19 Bra 1
+  7     \x{100}
+ 10  10 Bra 2
+ 13     b
+ 15   4 Recurse
+ 18     c
+ 20  10 Ket
+ 23  19 Ket
+ 26  26 Ket
+ 29     End
+------------------------------------------------------------------
+Capturing subpattern count = 2
+Options: utf8
+No first char
+No need char
+
+/(\x{100}(b(?1)c)){0,2}/D8
+------------------------------------------------------------------
+  0  55 Bra 0
+  3     Brazero
+  4  48 Bra 0
+  7  19 Bra 1
+ 10     \x{100}
+ 13  10 Bra 2
+ 16     b
+ 18   7 Recurse
+ 21     c
+ 23  10 Ket
+ 26  19 Ket
+ 29     Brazero
+ 30  19 Bra 1
+ 33     \x{100}
+ 36  10 Bra 2
+ 39     b
+ 41   7 Recurse
+ 44     c
+ 46  10 Ket
+ 49  19 Ket
+ 52  48 Ket
+ 55  55 Ket
+ 58     End
+------------------------------------------------------------------
+Capturing subpattern count = 2
+Options: utf8
+No first char
+No need char
+
+/\W/8
+    A.B
+ 0: .
+    A\x{100}B 
+ 0: \x{100}
+  
+/\w/8
+    \x{100}X   
+ 0: X
+
+/ End of testinput5 /

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/testdata/testoutput6
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/testdata/testoutput6	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/testdata/testoutput6	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,1013 @@
+PCRE version 5.0 13-Sep-2004
+
+/^\pC\pL\pM\pN\pP\pS\pZ</8
+    \x7f\x{c0}\x{30f}\x{660}\x{66c}\x{f01}\x{1680}<
+ 0: \x{7f}\x{c0}\x{30f}\x{660}\x{66c}\x{f01}\x{1680}<
+    \np\x{300}9!\$ < 
+ 0: \x{0a}p\x{300}9!$ <
+    ** Failers 
+No match
+    ap\x{300}9!\$ < 
+No match
+  
+/^\PC/8
+    X
+ 0: X
+    ** Failers 
+ 0: *
+    \x7f
+No match
+  
+/^\PL/8
+    9
+ 0: 9
+    ** Failers 
+ 0: *
+    \x{c0}
+No match
+  
+/^\PM/8
+    X
+ 0: X
+    ** Failers 
+ 0: *
+    \x{30f}
+No match
+  
+/^\PN/8
+    X
+ 0: X
+    ** Failers 
+ 0: *
+    \x{660}
+No match
+  
+/^\PP/8
+    X
+ 0: X
+    ** Failers 
+No match
+    \x{66c}
+No match
+  
+/^\PS/8
+    X
+ 0: X
+    ** Failers 
+ 0: *
+    \x{f01}
+No match
+  
+/^\PZ/8
+    X
+ 0: X
+    ** Failers 
+ 0: *
+    \x{1680}
+No match
+    
+/^\p{Cc}/8
+    \x{017}
+ 0: \x{17}
+    \x{09f} 
+ 0: \x{9f}
+    ** Failers
+No match
+    \x{0600} 
+No match
+  
+/^\p{Cf}/8
+    \x{601}
+ 0: \x{601}
+    ** Failers
+No match
+    \x{09f} 
+No match
+  
+/^\p{Cn}/8
+    ** Failers
+No match
+    \x{09f} 
+No match
+  
+/^\p{Co}/8
+    \x{f8ff}
+ 0: \x{f8ff}
+    ** Failers
+No match
+    \x{09f} 
+No match
+  
+/^\p{Cs}/8
+    \x{dfff}
+ 0: \x{dfff}
+    ** Failers
+No match
+    \x{09f} 
+No match
+  
+/^\p{Ll}/8
+    a
+ 0: a
+    ** Failers 
+No match
+    Z
+No match
+    \x{dfff}  
+No match
+  
+/^\p{Lm}/8
+    \x{2b0}
+ 0: \x{2b0}
+    ** Failers
+No match
+    a 
+No match
+  
+/^\p{Lo}/8
+    \x{1bb}
+ 0: \x{1bb}
+    ** Failers
+No match
+    a 
+No match
+    \x{2b0}
+No match
+  
+/^\p{Lt}/8
+    \x{1c5}
+ 0: \x{1c5}
+    ** Failers
+No match
+    a 
+No match
+    \x{2b0}
+No match
+  
+/^\p{Lu}/8
+    A
+ 0: A
+    ** Failers
+No match
+    \x{2b0}
+No match
+  
+/^\p{Mc}/8
+    \x{903}
+ 0: \x{903}
+    ** Failers
+No match
+    X
+No match
+    \x{300}
+No match
+       
+/^\p{Me}/8
+    \x{488}
+ 0: \x{488}
+    ** Failers
+No match
+    X
+No match
+    \x{903}
+No match
+    \x{300}
+No match
+  
+/^\p{Mn}/8
+    \x{300}
+ 0: \x{300}
+    ** Failers
+No match
+    X
+No match
+    \x{903}
+No match
+  
+/^\p{Nd}+/8
+    0123456789\x{660}\x{661}\x{662}\x{663}\x{664}\x{665}\x{666}\x{667}\x{668}\x{669}\x{66a}
+ 0: 0123456789\x{660}\x{661}\x{662}\x{663}\x{664}\x{665}\x{666}\x{667}\x{668}\x{669}
+    \x{6f0}\x{6f1}\x{6f2}\x{6f3}\x{6f4}\x{6f5}\x{6f6}\x{6f7}\x{6f8}\x{6f9}\x{6fa}
+ 0: \x{6f0}\x{6f1}\x{6f2}\x{6f3}\x{6f4}\x{6f5}\x{6f6}\x{6f7}\x{6f8}\x{6f9}
+    \x{966}\x{967}\x{968}\x{969}\x{96a}\x{96b}\x{96c}\x{96d}\x{96e}\x{96f}\x{970}
+ 0: \x{966}\x{967}\x{968}\x{969}\x{96a}\x{96b}\x{96c}\x{96d}\x{96e}\x{96f}
+    ** Failers
+No match
+    X
+No match
+  
+/^\p{Nl}/8
+    \x{16ee}
+ 0: \x{16ee}
+    ** Failers
+No match
+    X
+No match
+    \x{966}
+No match
+  
+/^\p{No}/8
+    \x{b2}
+ 0: \x{b2}
+    \x{b3}
+ 0: \x{b3}
+    ** Failers
+No match
+    X
+No match
+    \x{16ee}
+No match
+  
+/^\p{Pc}/8
+    \x5f
+ 0: _
+    \x{203f}
+ 0: \x{203f}
+    ** Failers
+No match
+    X
+No match
+    -
+No match
+    \x{58a}
+No match
+  
+/^\p{Pd}/8
+    -
+ 0: -
+    \x{58a}
+ 0: \x{58a}
+    ** Failers
+No match
+    X
+No match
+    \x{203f}
+No match
+  
+/^\p{Pe}/8
+    )
+ 0: )
+    ]
+ 0: ]
+    }
+ 0: }
+    \x{f3b}
+ 0: \x{f3b}
+    ** Failers
+No match
+    X
+No match
+    \x{203f}
+No match
+    (
+No match
+    [
+No match
+    {
+No match
+    \x{f3c}
+No match
+  
+/^\p{Pf}/8
+    \x{bb}
+ 0: \x{bb}
+    \x{2019}
+ 0: \x{2019}
+    ** Failers
+No match
+    X
+No match
+    \x{203f}
+No match
+  
+/^\p{Pi}/8
+    \x{ab}
+ 0: \x{ab}
+    \x{2018}
+ 0: \x{2018}
+    ** Failers
+No match
+    X
+No match
+    \x{203f}
+No match
+  
+/^\p{Po}/8
+    !
+ 0: !
+    \x{37e}
+ 0: \x{37e}
+    ** Failers
+ 0: *
+    X
+No match
+    \x{203f}
+No match
+  
+/^\p{Ps}/8
+    (
+ 0: (
+    [
+ 0: [
+    {
+ 0: {
+    \x{f3c}
+ 0: \x{f3c}
+    ** Failers
+No match
+    X
+No match
+    )
+No match
+    ]
+No match
+    }
+No match
+    \x{f3b}
+No match
+  
+/^\p{Sc}+/8
+    $\x{a2}\x{a3}\x{a4}\x{a5}\x{a6}
+ 0: $\x{a2}\x{a3}\x{a4}\x{a5}
+    \x{9f2}
+ 0: \x{9f2}
+    ** Failers
+No match
+    X
+No match
+    \x{2c2}
+No match
+  
+/^\p{Sk}/8
+    \x{2c2}
+ 0: \x{2c2}
+    ** Failers
+No match
+    X
+No match
+    \x{9f2}
+No match
+  
+/^\p{Sm}+/8
+    +<|~\x{ac}\x{2044}
+ 0: +<|~\x{ac}\x{2044}
+    ** Failers
+No match
+    X
+No match
+    \x{9f2}
+No match
+  
+/^\p{So}/8
+    \x{a6}
+ 0: \x{a6}
+    \x{482} 
+ 0: \x{482}
+    ** Failers
+No match
+    X
+No match
+    \x{9f2}
+No match
+  
+/^\p{Zl}/8
+    \x{2028}
+ 0: \x{2028}
+    ** Failers
+No match
+    X
+No match
+    \x{2029}
+No match
+  
+/^\p{Zp}/8
+    \x{2029}
+ 0: \x{2029}
+    ** Failers
+No match
+    X
+No match
+    \x{2028}
+No match
+  
+/^\p{Zs}/8
+    \ \
+ 0:  
+    \x{a0}
+ 0: \x{a0}
+    \x{1680}
+ 0: \x{1680}
+    \x{180e}
+ 0: \x{180e}
+    \x{2000}
+ 0: \x{2000}
+    \x{2001}     
+ 0: \x{2001}
+    ** Failers
+No match
+    \x{2028}
+No match
+    \x{200d} 
+No match
+  
+/\p{Nd}+(..)/8
+      \x{660}\x{661}\x{662}ABC
+ 0: \x{660}\x{661}\x{662}AB
+ 1: AB
+  
+/\p{Nd}+?(..)/8
+      \x{660}\x{661}\x{662}ABC
+ 0: \x{660}\x{661}\x{662}
+ 1: \x{661}\x{662}
+  
+/\p{Nd}{2,}(..)/8
+      \x{660}\x{661}\x{662}ABC
+ 0: \x{660}\x{661}\x{662}AB
+ 1: AB
+  
+/\p{Nd}{2,}?(..)/8
+      \x{660}\x{661}\x{662}ABC
+ 0: \x{660}\x{661}\x{662}A
+ 1: \x{662}A
+  
+/\p{Nd}*(..)/8
+      \x{660}\x{661}\x{662}ABC
+ 0: \x{660}\x{661}\x{662}AB
+ 1: AB
+  
+/\p{Nd}*?(..)/8
+      \x{660}\x{661}\x{662}ABC
+ 0: \x{660}\x{661}
+ 1: \x{660}\x{661}
+  
+/\p{Nd}{2}(..)/8
+      \x{660}\x{661}\x{662}ABC
+ 0: \x{660}\x{661}\x{662}A
+ 1: \x{662}A
+  
+/\p{Nd}{2,3}(..)/8
+      \x{660}\x{661}\x{662}ABC
+ 0: \x{660}\x{661}\x{662}AB
+ 1: AB
+  
+/\p{Nd}{2,3}?(..)/8
+      \x{660}\x{661}\x{662}ABC
+ 0: \x{660}\x{661}\x{662}A
+ 1: \x{662}A
+  
+/\p{Nd}?(..)/8
+      \x{660}\x{661}\x{662}ABC
+ 0: \x{660}\x{661}\x{662}
+ 1: \x{661}\x{662}
+  
+/\p{Nd}??(..)/8
+      \x{660}\x{661}\x{662}ABC
+ 0: \x{660}\x{661}
+ 1: \x{660}\x{661}
+  
+/\p{Nd}*+(..)/8
+      \x{660}\x{661}\x{662}ABC
+ 0: \x{660}\x{661}\x{662}AB
+ 1: AB
+  
+/\p{Nd}*+(...)/8
+      \x{660}\x{661}\x{662}ABC
+ 0: \x{660}\x{661}\x{662}ABC
+ 1: ABC
+  
+/\p{Nd}*+(....)/8
+      ** Failers
+ 0: ** F
+ 1: ** F
+      \x{660}\x{661}\x{662}ABC
+No match
+  
+/\p{Lu}/8i
+    A
+ 0: A
+    a\x{10a0}B 
+ 0: \x{10a0}
+    ** Failers 
+ 0: F
+    a
+No match
+    \x{1d00}  
+No match
+
+/\p{^Lu}/8i
+    1234
+ 0: 1
+    ** Failers
+ 0: *
+    ABC 
+No match
+
+/\P{Lu}/8i
+    1234
+ 0: 1
+    ** Failers
+ 0: *
+    ABC 
+No match
+
+/(?<=A\p{Nd})XYZ/8
+    A2XYZ
+ 0: XYZ
+    123A5XYZPQR
+ 0: XYZ
+    ABA\x{660}XYZpqr
+ 0: XYZ
+    ** Failers
+No match
+    AXYZ
+No match
+    XYZ     
+No match
+    
+/(?<!\pL)XYZ/8
+    1XYZ
+ 0: XYZ
+    AB=XYZ.. 
+ 0: XYZ
+    XYZ 
+ 0: XYZ
+    ** Failers
+No match
+    WXYZ 
+No match
+
+/[\p{L}]/D
+------------------------------------------------------------------
+  0  10 Bra 0
+  3     [\p{L}]
+ 10  10 Ket
+ 13     End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+No options
+No first char
+No need char
+
+/[\p{^L}]/D
+------------------------------------------------------------------
+  0  10 Bra 0
+  3     [\P{L}]
+ 10  10 Ket
+ 13     End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+No options
+No first char
+No need char
+
+/[\P{L}]/D
+------------------------------------------------------------------
+  0  10 Bra 0
+  3     [\P{L}]
+ 10  10 Ket
+ 13     End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+No options
+No first char
+No need char
+
+/[\P{^L}]/D
+------------------------------------------------------------------
+  0  10 Bra 0
+  3     [\p{L}]
+ 10  10 Ket
+ 13     End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+No options
+No first char
+No need char
+
+/[abc\p{L}\x{0660}]/8D
+------------------------------------------------------------------
+  0  45 Bra 0
+  3     [a-c\p{L}\x{660}]
+ 45  45 Ket
+ 48     End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Options: utf8
+No first char
+No need char
+
+/[\p{Nd}]/8DM
+Memory allocation (code space): 46
+------------------------------------------------------------------
+  0  10 Bra 0
+  3     [\p{Nd}]
+ 10  10 Ket
+ 13     End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Options: utf8
+No first char
+No need char
+    1234
+ 0: 1
+
+/[\p{Nd}+-]+/8DM
+Memory allocation (code space): 47
+------------------------------------------------------------------
+  0  43 Bra 0
+  3     [+\-\p{Nd}]+
+ 43  43 Ket
+ 46     End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Partial matching not supported
+Options: utf8
+No first char
+No need char
+    1234
+ 0: 1234
+    12-34
+ 0: 12-34
+    12+\x{661}-34  
+ 0: 12+\x{661}-34
+    ** Failers
+No match
+    abcd  
+No match
+
+/[\P{Nd}]+/8
+    abcd
+ 0: abcd
+    ** Failers
+ 0: ** Failers
+    1234
+No match
+
+/\D+/8
+    11111111111111111111111111111111111111111111111111111111111111111111111
+No match
+    aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+ 0: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+     
+/\P{Nd}+/8
+    11111111111111111111111111111111111111111111111111111111111111111111111
+No match
+    aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+ 0: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+
+/[\D]+/8
+    11111111111111111111111111111111111111111111111111111111111111111111111
+No match
+    aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+ 0: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+
+/[\P{Nd}]+/8
+    11111111111111111111111111111111111111111111111111111111111111111111111
+No match
+    aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+ 0: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+
+/[\D\P{Nd}]+/8
+    11111111111111111111111111111111111111111111111111111111111111111111111
+No match
+    aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+ 0: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+
+/\pL/8
+    a
+ 0: a
+    A 
+ 0: A
+
+/\pL/8i
+    a
+ 0: a
+    A 
+ 0: A
+    
+/\p{Lu}/8 
+    A
+ 0: A
+    aZ
+ 0: Z
+    ** Failers
+ 0: F
+    abc   
+No match
+
+/\p{Lu}/8i
+    A
+ 0: A
+    aZ
+ 0: Z
+    ** Failers
+ 0: F
+    abc   
+No match
+
+/\p{Ll}/8 
+    a
+ 0: a
+    Az
+ 0: z
+    ** Failers
+ 0: a
+    ABC   
+No match
+
+/\p{Ll}/8i 
+    a
+ 0: a
+    Az
+ 0: z
+    ** Failers
+ 0: a
+    ABC   
+No match
+
+/^\x{c0}$/8i
+    \x{c0}
+ 0: \x{c0}
+    \x{e0} 
+ 0: \x{e0}
+
+/^\x{e0}$/8i
+    \x{c0}
+ 0: \x{c0}
+    \x{e0} 
+ 0: \x{e0}
+
+/A\x{391}\x{10427}\x{ff3a}\x{1fb0}/8
+    A\x{391}\x{10427}\x{ff3a}\x{1fb0}
+ 0: A\x{391}\x{10427}\x{ff3a}\x{1fb0}
+    ** Failers
+No match
+    a\x{391}\x{10427}\x{ff3a}\x{1fb0}   
+No match
+    A\x{3b1}\x{10427}\x{ff3a}\x{1fb0}
+No match
+    A\x{391}\x{1044F}\x{ff3a}\x{1fb0}
+No match
+    A\x{391}\x{10427}\x{ff5a}\x{1fb0}
+No match
+    A\x{391}\x{10427}\x{ff3a}\x{1fb8}
+No match
+
+/A\x{391}\x{10427}\x{ff3a}\x{1fb0}/8i
+    A\x{391}\x{10427}\x{ff3a}\x{1fb0}
+ 0: A\x{391}\x{10427}\x{ff3a}\x{1fb0}
+    a\x{391}\x{10427}\x{ff3a}\x{1fb0}   
+ 0: a\x{391}\x{10427}\x{ff3a}\x{1fb0}
+    A\x{3b1}\x{10427}\x{ff3a}\x{1fb0}
+ 0: A\x{3b1}\x{10427}\x{ff3a}\x{1fb0}
+    A\x{391}\x{1044F}\x{ff3a}\x{1fb0}
+ 0: A\x{391}\x{1044f}\x{ff3a}\x{1fb0}
+    A\x{391}\x{10427}\x{ff5a}\x{1fb0}
+ 0: A\x{391}\x{10427}\x{ff5a}\x{1fb0}
+    A\x{391}\x{10427}\x{ff3a}\x{1fb8}
+ 0: A\x{391}\x{10427}\x{ff3a}\x{1fb8}
+
+/A\x{391}\x{10427}\x{ff3a}\x{1fb0}/8iD
+------------------------------------------------------------------
+  0  21 Bra 0
+  3  NC A\x{391}\x{10427}\x{ff3a}\x{1fb0}
+ 21  21 Ket
+ 24     End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Options: caseless utf8
+First char = 'A' (caseless)
+No need char
+
+/A\x{391}\x{10427}\x{ff3a}\x{1fb0}/8D
+------------------------------------------------------------------
+  0  21 Bra 0
+  3     A\x{391}\x{10427}\x{ff3a}\x{1fb0}
+ 21  21 Ket
+ 24     End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Options: utf8
+First char = 'A'
+Need char = 176
+
+/AB\x{1fb0}/8D
+------------------------------------------------------------------
+  0  11 Bra 0
+  3     AB\x{1fb0}
+ 11  11 Ket
+ 14     End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Options: utf8
+First char = 'A'
+Need char = 176
+
+/AB\x{1fb0}/8Di
+------------------------------------------------------------------
+  0  11 Bra 0
+  3  NC AB\x{1fb0}
+ 11  11 Ket
+ 14     End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Options: caseless utf8
+First char = 'A' (caseless)
+Need char = 'B' (caseless)
+
+/\x{391}+/8i
+    \x{391}\x{3b1}\x{3b1}\x{3b1}\x{391}
+ 0: \x{391}\x{3b1}\x{3b1}\x{3b1}\x{391}
+
+/\x{391}{3,5}(.)/8i
+    \x{391}\x{3b1}\x{3b1}\x{3b1}\x{391}X
+ 0: \x{391}\x{3b1}\x{3b1}\x{3b1}\x{391}X
+ 1: X
+
+/\x{391}{3,5}?(.)/8i
+    \x{391}\x{3b1}\x{3b1}\x{3b1}\x{391}X
+ 0: \x{391}\x{3b1}\x{3b1}\x{3b1}
+ 1: \x{3b1}
+
+/[\x{391}\x{ff3a}]/8i
+    \x{391}
+ 0: \x{391}
+    \x{ff3a}
+ 0: \x{ff3a}
+    \x{3b1}
+ 0: \x{3b1}
+    \x{ff5a}   
+ 0: \x{ff5a}
+    
+/[\x{c0}\x{391}]/8i
+    \x{c0}
+ 0: \x{c0}
+    \x{e0} 
+ 0: \x{e0}
+
+/[\x{105}-\x{109}]/8iD
+------------------------------------------------------------------
+  0  13 Bra 0
+  3     [\x{104}-\x{109}]
+ 13  13 Ket
+ 16     End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Options: caseless utf8
+No first char
+No need char
+    \x{104}
+ 0: \x{104}
+    \x{105}
+ 0: \x{105}
+    \x{109}  
+ 0: \x{109}
+    ** Failers
+No match
+    \x{100}
+No match
+    \x{10a} 
+No match
+    
+/[z-\x{100}]/8iD 
+------------------------------------------------------------------
+  0  20 Bra 0
+  3     [Z\x{39c}\x{178}z-\x{101}]
+ 20  20 Ket
+ 23     End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Options: caseless utf8
+No first char
+No need char
+    Z
+ 0: Z
+    z
+ 0: z
+    \x{39c}
+ 0: \x{39c}
+    \x{178}
+ 0: \x{178}
+    |
+ 0: |
+    \x{80}
+ 0: \x{80}
+    \x{ff}
+ 0: \x{ff}
+    \x{100}
+ 0: \x{100}
+    \x{101} 
+ 0: \x{101}
+    ** Failers
+No match
+    \x{102}
+No match
+    Y
+No match
+    y           
+No match
+
+/[z-\x{100}]/8Di
+------------------------------------------------------------------
+  0  20 Bra 0
+  3     [Z\x{39c}\x{178}z-\x{101}]
+ 20  20 Ket
+ 23     End
+------------------------------------------------------------------
+Capturing subpattern count = 0
+Options: caseless utf8
+No first char
+No need char
+
+/^\X/8
+    A
+ 0: A
+    A\x{300}BC 
+ 0: A\x{300}
+    A\x{300}\x{301}\x{302}BC 
+ 0: A\x{300}\x{301}\x{302}
+    *** Failers
+ 0: *
+    \x{300}  
+No match
+
+/^[\X]/8
+    X123
+ 0: X
+    *** Failers
+No match
+    AXYZ
+No match
+
+/^(\X*)C/8
+    A\x{300}\x{301}\x{302}BCA\x{300}\x{301} 
+ 0: A\x{300}\x{301}\x{302}BC
+ 1: A\x{300}\x{301}\x{302}B
+    A\x{300}\x{301}\x{302}BCA\x{300}\x{301}C 
+ 0: A\x{300}\x{301}\x{302}BCA\x{300}\x{301}C
+ 1: A\x{300}\x{301}\x{302}BCA\x{300}\x{301}
+
+/^(\X*?)C/8
+    A\x{300}\x{301}\x{302}BCA\x{300}\x{301} 
+ 0: A\x{300}\x{301}\x{302}BC
+ 1: A\x{300}\x{301}\x{302}B
+    A\x{300}\x{301}\x{302}BCA\x{300}\x{301}C 
+ 0: A\x{300}\x{301}\x{302}BC
+ 1: A\x{300}\x{301}\x{302}B
+
+/^(\X*)(.)/8
+    A\x{300}\x{301}\x{302}BCA\x{300}\x{301} 
+ 0: A\x{300}\x{301}\x{302}BCA
+ 1: A\x{300}\x{301}\x{302}BC
+ 2: A
+    A\x{300}\x{301}\x{302}BCA\x{300}\x{301}C 
+ 0: A\x{300}\x{301}\x{302}BCA\x{300}\x{301}C
+ 1: A\x{300}\x{301}\x{302}BCA\x{300}\x{301}
+ 2: C
+
+/^(\X*?)(.)/8
+    A\x{300}\x{301}\x{302}BCA\x{300}\x{301} 
+ 0: A
+ 1: 
+ 2: A
+    A\x{300}\x{301}\x{302}BCA\x{300}\x{301}C 
+ 0: A
+ 1: 
+ 2: A
+
+/^\X(.)/8
+    *** Failers
+ 0: **
+ 1: *
+    A\x{300}\x{301}\x{302}
+No match
+
+/^\X{2,3}(.)/8
+    A\x{300}\x{301}B\x{300}X
+ 0: A\x{300}\x{301}B\x{300}X
+ 1: X
+    A\x{300}\x{301}B\x{300}C\x{300}\x{301}
+ 0: A\x{300}\x{301}B\x{300}C
+ 1: C
+    A\x{300}\x{301}B\x{300}C\x{300}\x{301}X
+ 0: A\x{300}\x{301}B\x{300}C\x{300}\x{301}X
+ 1: X
+    A\x{300}\x{301}B\x{300}C\x{300}\x{301}DA\x{300}X
+ 0: A\x{300}\x{301}B\x{300}C\x{300}\x{301}D
+ 1: D
+    
+/^\X{2,3}?(.)/8
+    A\x{300}\x{301}B\x{300}X
+ 0: A\x{300}\x{301}B\x{300}X
+ 1: X
+    A\x{300}\x{301}B\x{300}C\x{300}\x{301}
+ 0: A\x{300}\x{301}B\x{300}C
+ 1: C
+    A\x{300}\x{301}B\x{300}C\x{300}\x{301}X
+ 0: A\x{300}\x{301}B\x{300}C
+ 1: C
+    A\x{300}\x{301}B\x{300}C\x{300}\x{301}DA\x{300}X
+ 0: A\x{300}\x{301}B\x{300}C
+ 1: C
+    
+/ End of testinput6 /

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/ucp.c
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/ucp.c	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/ucp.c	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,151 @@
+/*************************************************
+*     libucp - Unicode Property Table handler    *
+*************************************************/
+
+/* This function provides a fast way of obtaining the basic Unicode properties
+of a character, using a compact binary tree that occupies less than 100K bytes.
+
+           Copyright (c) 2004 University of Cambridge
+
+-------------------------------------------------------------------------------
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice,
+      this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+
+    * Neither the name of the University of Cambridge nor the names of its
+      contributors may be used to endorse or promote products derived from
+      this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+-------------------------------------------------------------------------------
+*/
+
+
+#include "ucp.h"               /* Exported interface */
+#include "ucpinternal.h"       /* Internal table details */
+#include "ucptable.c"          /* The table itself */
+
+
+
+/*************************************************
+*         Search table and return data           *
+*************************************************/
+
+/* Two values are returned: the category is ucp_C, ucp_L, etc. The detailed
+character type is ucp_Lu, ucp_Nd, etc.
+
+Arguments:
+  c           the character value
+  type_ptr    the detailed character type is returned here
+  case_ptr    for letters, the opposite case is returned here, if there
+                is one, else zero
+
+Returns:      the character type category or -1 if not found
+*/
+
+static int
+ucp_findchar(const int c, int *type_ptr, int *case_ptr)
+{
+cnode *node = ucp_table;
+register int cc = c;
+int case_offset;
+
+for (;;)
+  {
+  register int d = node->f1 | ((node->f0 & f0_chhmask) << 16);
+  if (cc == d) break;
+  if (cc < d)
+    {
+    if ((node->f0 & f0_leftexists) == 0) return -1;
+    node ++;
+    }
+  else
+    {
+    register int roffset = (node->f2 & f2_rightmask) >> f2_rightshift;
+    if (roffset == 0) return -1;
+    node += 1 << (roffset - 1);
+    }
+  }
+
+switch ((*type_ptr = ((node->f0 & f0_typemask) >> f0_typeshift)))
+  {
+  case ucp_Cc:
+  case ucp_Cf:
+  case ucp_Cn:
+  case ucp_Co:
+  case ucp_Cs:
+  return ucp_C;
+  break;
+
+  case ucp_Ll:
+  case ucp_Lu:
+  case_offset = node->f2 & f2_casemask;
+  if ((case_offset & 0x0100) != 0) case_offset |= 0xfffff000;
+  *case_ptr = (case_offset == 0)? 0 : cc + case_offset;
+  return ucp_L;
+
+  case ucp_Lm:
+  case ucp_Lo:
+  case ucp_Lt:
+  *case_ptr = 0;
+  return ucp_L;
+  break;
+
+  case ucp_Mc:
+  case ucp_Me:
+  case ucp_Mn:
+  return ucp_M;
+  break;
+
+  case ucp_Nd:
+  case ucp_Nl:
+  case ucp_No:
+  return ucp_N;
+  break;
+
+  case ucp_Pc:
+  case ucp_Pd:
+  case ucp_Pe:
+  case ucp_Pf:
+  case ucp_Pi:
+  case ucp_Ps:
+  case ucp_Po:
+  return ucp_P;
+  break;
+
+  case ucp_Sc:
+  case ucp_Sk:
+  case ucp_Sm:
+  case ucp_So:
+  return ucp_S;
+  break;
+
+  case ucp_Zl:
+  case ucp_Zp:
+  case ucp_Zs:
+  return ucp_Z;
+  break;
+
+  default:         /* "Should never happen" */
+  return -1;
+  break;
+  }
+}
+
+/* End of ucp.c */

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/ucp.h
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/ucp.h	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/ucp.h	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,58 @@
+/*************************************************
+*     libucp - Unicode Property Table handler    *
+*************************************************/
+
+/* These are the character categories that are returned by ucp_findchar */
+
+enum {
+  ucp_C,     /* Other */
+  ucp_L,     /* Letter */
+  ucp_M,     /* Mark */
+  ucp_N,     /* Number */
+  ucp_P,     /* Punctuation */
+  ucp_S,     /* Symbol */
+  ucp_Z      /* Separator */
+};
+
+/* These are the detailed character types that are returned by ucp_findchar */
+
+enum {
+  ucp_Cc,    /* Control */
+  ucp_Cf,    /* Format */
+  ucp_Cn,    /* Unassigned */
+  ucp_Co,    /* Private use */
+  ucp_Cs,    /* Surrogate */
+  ucp_Ll,    /* Lower case letter */
+  ucp_Lm,    /* Modifier letter */
+  ucp_Lo,    /* Other letter */
+  ucp_Lt,    /* Title case letter */
+  ucp_Lu,    /* Upper case letter */
+  ucp_Mc,    /* Spacing mark */
+  ucp_Me,    /* Enclosing mark */
+  ucp_Mn,    /* Non-spacing mark */
+  ucp_Nd,    /* Decimal number */
+  ucp_Nl,    /* Letter number */
+  ucp_No,    /* Other number */
+  ucp_Pc,    /* Connector punctuation */
+  ucp_Pd,    /* Dash punctuation */
+  ucp_Pe,    /* Close punctuation */
+  ucp_Pf,    /* Final punctuation */
+  ucp_Pi,    /* Initial punctuation */
+  ucp_Po,    /* Other punctuation */
+  ucp_Ps,    /* Open punctuation */
+  ucp_Sc,    /* Currency symbol */
+  ucp_Sk,    /* Modifier symbol */
+  ucp_Sm,    /* Mathematical symbol */
+  ucp_So,    /* Other symbol */
+  ucp_Zl,    /* Line separator */
+  ucp_Zp,    /* Paragraph separator */
+  ucp_Zs     /* Space separator */
+};
+
+/* For use in PCRE we make this function static so that there is no conflict if
+PCRE is linked with an application that makes use of an external version -
+assuming an external version is ever released... */
+
+static int ucp_findchar(const int, int *, int *);
+
+/* End of ucp.h */

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/ucpinternal.h
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/ucpinternal.h	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/ucpinternal.h	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,91 @@
+/*************************************************
+*     libucp - Unicode Property Table handler    *
+*************************************************/
+
+/* Internal header file defining the layout of compact nodes in the tree. */
+
+typedef struct cnode {
+  unsigned short int f0;
+  unsigned short int f1;
+  unsigned short int f2;
+} cnode;
+
+/* Things for the f0 field */
+
+#define f0_leftexists   0x8000    /* Left child exists */
+#define f0_typemask     0x3f00    /* Type bits */
+#define f0_typeshift         8    /* Type shift */
+#define f0_chhmask      0x00ff    /* Character high bits */
+
+/* Things for the f2 field */
+
+#define f2_rightmask    0xf000    /* Mask for right offset bits */
+#define f2_rightshift       12    /* Shift for right offset */
+#define f2_casemask     0x0fff    /* Mask for case offset */
+
+/* The tree consists of a vector of structures of type cnode, with the root
+node as the first element. The three short ints (16-bits) are used as follows:
+
+(f0) (1) The 0x8000 bit of f0 is set if a left child exists. The child's node
+         is the next node in the vector.
+     (2) The 0x4000 bits of f0 is spare.
+     (3) The 0x3f00 bits of f0 contain the character type; this is a number
+         defined by the enumeration in ucp.h (e.g. ucp_Lu).
+     (4) The bottom 8 bits of f0 contain the most significant byte of the
+         character's 24-bit codepoint.
+
+(f1) (1) The f1 field contains the two least significant bytes of the
+         codepoint.
+
+(f2) (1) The 0xf000 bits of f2 contain zero if there is no right child of this
+         node. Otherwise, they contain one plus the exponent of the power of
+         two of the offset to the right node (e.g. a value of 3 means 8). The
+         units of the offset are node items.
+
+     (2) The 0x0fff bits of f2 contain the signed offset from this character to
+         its alternate cased value. They are zero if there is no such
+         character.
+
+
+-----------------------------------------------------------------------------
+||.|.| type (6) | ms char (8) ||  ls char (16)  ||....|  case offset (12)  ||
+-----------------------------------------------------------------------------
+  | |                                              |
+  | |-> spare                                      |
+  |                                        exponent of right
+  |-> left child exists                       child offset
+
+
+The upper/lower casing information is set only for characters that come in
+pairs. There are (at present) four non-one-to-one mappings in the Unicode data.
+These are ignored. They are:
+
+  1FBE Greek Prosgegrammeni (lower, with upper -> capital iota)
+  2126 Ohm
+  212A Kelvin
+  212B Angstrom
+
+Certainly for the last three, having an alternate case would seem to be a
+mistake. I don't know any Greek, so cannot comment on the first one.
+
+
+When searching the tree, proceed as follows:
+
+(1) Start at the first node.
+
+(2) Extract the character value from f1 and the bottom 8 bits of f0;
+
+(3) Compare with the character being sought. If equal, we are done.
+
+(4) If the test character is smaller, inspect the f0_leftexists flag. If it is
+    not set, the character is not in the tree. If it is set, move to the next
+    node, and go to (2).
+
+(5) If the test character is bigger, extract the f2_rightmask bits from f2, and
+    shift them right by f2_rightshift. If the result is zero, the character is
+    not in the tree. Otherwise, calculate the number of nodes to skip by
+    shifting the value 1 left by this number minus one. Go to (2).
+*/
+
+
+/* End of internal.h */

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/ucptable.c
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/ucptable.c	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/ucptable.c	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,15105 @@
+/* This source module is automatically generated from the Unicode
+property table. See internal.h for a description of the layout. */
+
+static cnode ucp_table[] = {
+  { 0x9a00, 0x2f1f, 0xe000 },
+  { 0x8700, 0x1558, 0xd000 },
+  { 0x8700, 0x0a99, 0xc000 },
+  { 0x8500, 0x0435, 0xbfe0 },
+  { 0x8500, 0x01ff, 0xafff },
+  { 0x8500, 0x00ff, 0x9079 },
+  { 0x8000, 0x007f, 0x8000 },
+  { 0x9500, 0x003f, 0x7000 },
+  { 0x8000, 0x001f, 0x6000 },
+  { 0x8000, 0x000f, 0x5000 },
+  { 0x8000, 0x0007, 0x4000 },
+  { 0x8000, 0x0003, 0x3000 },
+  { 0x8000, 0x0001, 0x2000 },
+  { 0x0000, 0x0000, 0x0000 },
+  { 0x0000, 0x0002, 0x0000 },
+  { 0x8000, 0x0005, 0x2000 },
+  { 0x0000, 0x0004, 0x0000 },
+  { 0x0000, 0x0006, 0x0000 },
+  { 0x8000, 0x000b, 0x3000 },
+  { 0x8000, 0x0009, 0x2000 },
+  { 0x0000, 0x0008, 0x0000 },
+  { 0x0000, 0x000a, 0x0000 },
+  { 0x8000, 0x000d, 0x2000 },
+  { 0x0000, 0x000c, 0x0000 },
+  { 0x0000, 0x000e, 0x0000 },
+  { 0x8000, 0x0017, 0x4000 },
+  { 0x8000, 0x0013, 0x3000 },
+  { 0x8000, 0x0011, 0x2000 },
+  { 0x0000, 0x0010, 0x0000 },
+  { 0x0000, 0x0012, 0x0000 },
+  { 0x8000, 0x0015, 0x2000 },
+  { 0x0000, 0x0014, 0x0000 },
+  { 0x0000, 0x0016, 0x0000 },
+  { 0x8000, 0x001b, 0x3000 },
+  { 0x8000, 0x0019, 0x2000 },
+  { 0x0000, 0x0018, 0x0000 },
+  { 0x0000, 0x001a, 0x0000 },
+  { 0x8000, 0x001d, 0x2000 },
+  { 0x0000, 0x001c, 0x0000 },
+  { 0x0000, 0x001e, 0x0000 },
+  { 0x9500, 0x002f, 0x5000 },
+  { 0x9500, 0x0027, 0x4000 },
+  { 0x9500, 0x0023, 0x3000 },
+  { 0x9500, 0x0021, 0x2000 },
+  { 0x1d00, 0x0020, 0x0000 },
+  { 0x1500, 0x0022, 0x0000 },
+  { 0x9500, 0x0025, 0x2000 },
+  { 0x1700, 0x0024, 0x0000 },
+  { 0x1500, 0x0026, 0x0000 },
+  { 0x9900, 0x002b, 0x3000 },
+  { 0x9200, 0x0029, 0x2000 },
+  { 0x1600, 0x0028, 0x0000 },
+  { 0x1500, 0x002a, 0x0000 },
+  { 0x9100, 0x002d, 0x2000 },
+  { 0x1500, 0x002c, 0x0000 },
+  { 0x1500, 0x002e, 0x0000 },
+  { 0x8d00, 0x0037, 0x4000 },
+  { 0x8d00, 0x0033, 0x3000 },
+  { 0x8d00, 0x0031, 0x2000 },
+  { 0x0d00, 0x0030, 0x0000 },
+  { 0x0d00, 0x0032, 0x0000 },
+  { 0x8d00, 0x0035, 0x2000 },
+  { 0x0d00, 0x0034, 0x0000 },
+  { 0x0d00, 0x0036, 0x0000 },
+  { 0x9500, 0x003b, 0x3000 },
+  { 0x8d00, 0x0039, 0x2000 },
+  { 0x0d00, 0x0038, 0x0000 },
+  { 0x1500, 0x003a, 0x0000 },
+  { 0x9900, 0x003d, 0x2000 },
+  { 0x1900, 0x003c, 0x0000 },
+  { 0x1900, 0x003e, 0x0000 },
+  { 0x9000, 0x005f, 0x6000 },
+  { 0x8900, 0x004f, 0x5020 },
+  { 0x8900, 0x0047, 0x4020 },
+  { 0x8900, 0x0043, 0x3020 },
+  { 0x8900, 0x0041, 0x2020 },
+  { 0x1500, 0x0040, 0x0000 },
+  { 0x0900, 0x0042, 0x0020 },
+  { 0x8900, 0x0045, 0x2020 },
+  { 0x0900, 0x0044, 0x0020 },
+  { 0x0900, 0x0046, 0x0020 },
+  { 0x8900, 0x004b, 0x3020 },
+  { 0x8900, 0x0049, 0x2020 },
+  { 0x0900, 0x0048, 0x0020 },
+  { 0x0900, 0x004a, 0x0020 },
+  { 0x8900, 0x004d, 0x2020 },
+  { 0x0900, 0x004c, 0x0020 },
+  { 0x0900, 0x004e, 0x0020 },
+  { 0x8900, 0x0057, 0x4020 },
+  { 0x8900, 0x0053, 0x3020 },
+  { 0x8900, 0x0051, 0x2020 },
+  { 0x0900, 0x0050, 0x0020 },
+  { 0x0900, 0x0052, 0x0020 },
+  { 0x8900, 0x0055, 0x2020 },
+  { 0x0900, 0x0054, 0x0020 },
+  { 0x0900, 0x0056, 0x0020 },
+  { 0x9600, 0x005b, 0x3000 },
+  { 0x8900, 0x0059, 0x2020 },
+  { 0x0900, 0x0058, 0x0020 },
+  { 0x0900, 0x005a, 0x0020 },
+  { 0x9200, 0x005d, 0x2000 },
+  { 0x1500, 0x005c, 0x0000 },
+  { 0x1800, 0x005e, 0x0000 },
+  { 0x8500, 0x006f, 0x5fe0 },
+  { 0x8500, 0x0067, 0x4fe0 },
+  { 0x8500, 0x0063, 0x3fe0 },
+  { 0x8500, 0x0061, 0x2fe0 },
+  { 0x1800, 0x0060, 0x0000 },
+  { 0x0500, 0x0062, 0x0fe0 },
+  { 0x8500, 0x0065, 0x2fe0 },
+  { 0x0500, 0x0064, 0x0fe0 },
+  { 0x0500, 0x0066, 0x0fe0 },
+  { 0x8500, 0x006b, 0x3fe0 },
+  { 0x8500, 0x0069, 0x2fe0 },
+  { 0x0500, 0x0068, 0x0fe0 },
+  { 0x0500, 0x006a, 0x0fe0 },
+  { 0x8500, 0x006d, 0x2fe0 },
+  { 0x0500, 0x006c, 0x0fe0 },
+  { 0x0500, 0x006e, 0x0fe0 },
+  { 0x8500, 0x0077, 0x4fe0 },
+  { 0x8500, 0x0073, 0x3fe0 },
+  { 0x8500, 0x0071, 0x2fe0 },
+  { 0x0500, 0x0070, 0x0fe0 },
+  { 0x0500, 0x0072, 0x0fe0 },
+  { 0x8500, 0x0075, 0x2fe0 },
+  { 0x0500, 0x0074, 0x0fe0 },
+  { 0x0500, 0x0076, 0x0fe0 },
+  { 0x9600, 0x007b, 0x3000 },
+  { 0x8500, 0x0079, 0x2fe0 },
+  { 0x0500, 0x0078, 0x0fe0 },
+  { 0x0500, 0x007a, 0x0fe0 },
+  { 0x9200, 0x007d, 0x2000 },
+  { 0x1900, 0x007c, 0x0000 },
+  { 0x1900, 0x007e, 0x0000 },
+  { 0x9500, 0x00bf, 0x7000 },
+  { 0x8000, 0x009f, 0x6000 },
+  { 0x8000, 0x008f, 0x5000 },
+  { 0x8000, 0x0087, 0x4000 },
+  { 0x8000, 0x0083, 0x3000 },
+  { 0x8000, 0x0081, 0x2000 },
+  { 0x0000, 0x0080, 0x0000 },
+  { 0x0000, 0x0082, 0x0000 },
+  { 0x8000, 0x0085, 0x2000 },
+  { 0x0000, 0x0084, 0x0000 },
+  { 0x0000, 0x0086, 0x0000 },
+  { 0x8000, 0x008b, 0x3000 },
+  { 0x8000, 0x0089, 0x2000 },
+  { 0x0000, 0x0088, 0x0000 },
+  { 0x0000, 0x008a, 0x0000 },
+  { 0x8000, 0x008d, 0x2000 },
+  { 0x0000, 0x008c, 0x0000 },
+  { 0x0000, 0x008e, 0x0000 },
+  { 0x8000, 0x0097, 0x4000 },
+  { 0x8000, 0x0093, 0x3000 },
+  { 0x8000, 0x0091, 0x2000 },
+  { 0x0000, 0x0090, 0x0000 },
+  { 0x0000, 0x0092, 0x0000 },
+  { 0x8000, 0x0095, 0x2000 },
+  { 0x0000, 0x0094, 0x0000 },
+  { 0x0000, 0x0096, 0x0000 },
+  { 0x8000, 0x009b, 0x3000 },
+  { 0x8000, 0x0099, 0x2000 },
+  { 0x0000, 0x0098, 0x0000 },
+  { 0x0000, 0x009a, 0x0000 },
+  { 0x8000, 0x009d, 0x2000 },
+  { 0x0000, 0x009c, 0x0000 },
+  { 0x0000, 0x009e, 0x0000 },
+  { 0x9800, 0x00af, 0x5000 },
+  { 0x9a00, 0x00a7, 0x4000 },
+  { 0x9700, 0x00a3, 0x3000 },
+  { 0x9500, 0x00a1, 0x2000 },
+  { 0x1d00, 0x00a0, 0x0000 },
+  { 0x1700, 0x00a2, 0x0000 },
+  { 0x9700, 0x00a5, 0x2000 },
+  { 0x1700, 0x00a4, 0x0000 },
+  { 0x1a00, 0x00a6, 0x0000 },
+  { 0x9400, 0x00ab, 0x3000 },
+  { 0x9a00, 0x00a9, 0x2000 },
+  { 0x1800, 0x00a8, 0x0000 },
+  { 0x0500, 0x00aa, 0x0000 },
+  { 0x8100, 0x00ad, 0x2000 },
+  { 0x1900, 0x00ac, 0x0000 },
+  { 0x1a00, 0x00ae, 0x0000 },
+  { 0x9500, 0x00b7, 0x4000 },
+  { 0x8f00, 0x00b3, 0x3000 },
+  { 0x9900, 0x00b1, 0x2000 },
+  { 0x1a00, 0x00b0, 0x0000 },
+  { 0x0f00, 0x00b2, 0x0000 },
+  { 0x8500, 0x00b5, 0x22e7 },
+  { 0x1800, 0x00b4, 0x0000 },
+  { 0x1a00, 0x00b6, 0x0000 },
+  { 0x9300, 0x00bb, 0x3000 },
+  { 0x8f00, 0x00b9, 0x2000 },
+  { 0x1800, 0x00b8, 0x0000 },
+  { 0x0500, 0x00ba, 0x0000 },
+  { 0x8f00, 0x00bd, 0x2000 },
+  { 0x0f00, 0x00bc, 0x0000 },
+  { 0x0f00, 0x00be, 0x0000 },
+  { 0x8500, 0x00df, 0x6000 },
+  { 0x8900, 0x00cf, 0x5020 },
+  { 0x8900, 0x00c7, 0x4020 },
+  { 0x8900, 0x00c3, 0x3020 },
+  { 0x8900, 0x00c1, 0x2020 },
+  { 0x0900, 0x00c0, 0x0020 },
+  { 0x0900, 0x00c2, 0x0020 },
+  { 0x8900, 0x00c5, 0x2020 },
+  { 0x0900, 0x00c4, 0x0020 },
+  { 0x0900, 0x00c6, 0x0020 },
+  { 0x8900, 0x00cb, 0x3020 },
+  { 0x8900, 0x00c9, 0x2020 },
+  { 0x0900, 0x00c8, 0x0020 },
+  { 0x0900, 0x00ca, 0x0020 },
+  { 0x8900, 0x00cd, 0x2020 },
+  { 0x0900, 0x00cc, 0x0020 },
+  { 0x0900, 0x00ce, 0x0020 },
+  { 0x9900, 0x00d7, 0x4000 },
+  { 0x8900, 0x00d3, 0x3020 },
+  { 0x8900, 0x00d1, 0x2020 },
+  { 0x0900, 0x00d0, 0x0020 },
+  { 0x0900, 0x00d2, 0x0020 },
+  { 0x8900, 0x00d5, 0x2020 },
+  { 0x0900, 0x00d4, 0x0020 },
+  { 0x0900, 0x00d6, 0x0020 },
+  { 0x8900, 0x00db, 0x3020 },
+  { 0x8900, 0x00d9, 0x2020 },
+  { 0x0900, 0x00d8, 0x0020 },
+  { 0x0900, 0x00da, 0x0020 },
+  { 0x8900, 0x00dd, 0x2020 },
+  { 0x0900, 0x00dc, 0x0020 },
+  { 0x0900, 0x00de, 0x0020 },
+  { 0x8500, 0x00ef, 0x5fe0 },
+  { 0x8500, 0x00e7, 0x4fe0 },
+  { 0x8500, 0x00e3, 0x3fe0 },
+  { 0x8500, 0x00e1, 0x2fe0 },
+  { 0x0500, 0x00e0, 0x0fe0 },
+  { 0x0500, 0x00e2, 0x0fe0 },
+  { 0x8500, 0x00e5, 0x2fe0 },
+  { 0x0500, 0x00e4, 0x0fe0 },
+  { 0x0500, 0x00e6, 0x0fe0 },
+  { 0x8500, 0x00eb, 0x3fe0 },
+  { 0x8500, 0x00e9, 0x2fe0 },
+  { 0x0500, 0x00e8, 0x0fe0 },
+  { 0x0500, 0x00ea, 0x0fe0 },
+  { 0x8500, 0x00ed, 0x2fe0 },
+  { 0x0500, 0x00ec, 0x0fe0 },
+  { 0x0500, 0x00ee, 0x0fe0 },
+  { 0x9900, 0x00f7, 0x4000 },
+  { 0x8500, 0x00f3, 0x3fe0 },
+  { 0x8500, 0x00f1, 0x2fe0 },
+  { 0x0500, 0x00f0, 0x0fe0 },
+  { 0x0500, 0x00f2, 0x0fe0 },
+  { 0x8500, 0x00f5, 0x2fe0 },
+  { 0x0500, 0x00f4, 0x0fe0 },
+  { 0x0500, 0x00f6, 0x0fe0 },
+  { 0x8500, 0x00fb, 0x3fe0 },
+  { 0x8500, 0x00f9, 0x2fe0 },
+  { 0x0500, 0x00f8, 0x0fe0 },
+  { 0x0500, 0x00fa, 0x0fe0 },
+  { 0x8500, 0x00fd, 0x2fe0 },
+  { 0x0500, 0x00fc, 0x0fe0 },
+  { 0x0500, 0x00fe, 0x0fe0 },
+  { 0x8500, 0x017f, 0x8ed4 },
+  { 0x8900, 0x013f, 0x7001 },
+  { 0x8500, 0x011f, 0x6fff },
+  { 0x8500, 0x010f, 0x5fff },
+  { 0x8500, 0x0107, 0x4fff },
+  { 0x8500, 0x0103, 0x3fff },
+  { 0x8500, 0x0101, 0x2fff },
+  { 0x0900, 0x0100, 0x0001 },
+  { 0x0900, 0x0102, 0x0001 },
+  { 0x8500, 0x0105, 0x2fff },
+  { 0x0900, 0x0104, 0x0001 },
+  { 0x0900, 0x0106, 0x0001 },
+  { 0x8500, 0x010b, 0x3fff },
+  { 0x8500, 0x0109, 0x2fff },
+  { 0x0900, 0x0108, 0x0001 },
+  { 0x0900, 0x010a, 0x0001 },
+  { 0x8500, 0x010d, 0x2fff },
+  { 0x0900, 0x010c, 0x0001 },
+  { 0x0900, 0x010e, 0x0001 },
+  { 0x8500, 0x0117, 0x4fff },
+  { 0x8500, 0x0113, 0x3fff },
+  { 0x8500, 0x0111, 0x2fff },
+  { 0x0900, 0x0110, 0x0001 },
+  { 0x0900, 0x0112, 0x0001 },
+  { 0x8500, 0x0115, 0x2fff },
+  { 0x0900, 0x0114, 0x0001 },
+  { 0x0900, 0x0116, 0x0001 },
+  { 0x8500, 0x011b, 0x3fff },
+  { 0x8500, 0x0119, 0x2fff },
+  { 0x0900, 0x0118, 0x0001 },
+  { 0x0900, 0x011a, 0x0001 },
+  { 0x8500, 0x011d, 0x2fff },
+  { 0x0900, 0x011c, 0x0001 },
+  { 0x0900, 0x011e, 0x0001 },
+  { 0x8500, 0x012f, 0x5fff },
+  { 0x8500, 0x0127, 0x4fff },
+  { 0x8500, 0x0123, 0x3fff },
+  { 0x8500, 0x0121, 0x2fff },
+  { 0x0900, 0x0120, 0x0001 },
+  { 0x0900, 0x0122, 0x0001 },
+  { 0x8500, 0x0125, 0x2fff },
+  { 0x0900, 0x0124, 0x0001 },
+  { 0x0900, 0x0126, 0x0001 },
+  { 0x8500, 0x012b, 0x3fff },
+  { 0x8500, 0x0129, 0x2fff },
+  { 0x0900, 0x0128, 0x0001 },
+  { 0x0900, 0x012a, 0x0001 },
+  { 0x8500, 0x012d, 0x2fff },
+  { 0x0900, 0x012c, 0x0001 },
+  { 0x0900, 0x012e, 0x0001 },
+  { 0x8500, 0x0137, 0x4fff },
+  { 0x8500, 0x0133, 0x3fff },
+  { 0x8500, 0x0131, 0x2f18 },
+  { 0x0900, 0x0130, 0x0f39 },
+  { 0x0900, 0x0132, 0x0001 },
+  { 0x8500, 0x0135, 0x2fff },
+  { 0x0900, 0x0134, 0x0001 },
+  { 0x0900, 0x0136, 0x0001 },
+  { 0x8900, 0x013b, 0x3001 },
+  { 0x8900, 0x0139, 0x2001 },
+  { 0x0500, 0x0138, 0x0000 },
+  { 0x0500, 0x013a, 0x0fff },
+  { 0x8900, 0x013d, 0x2001 },
+  { 0x0500, 0x013c, 0x0fff },
+  { 0x0500, 0x013e, 0x0fff },
+  { 0x8500, 0x015f, 0x6fff },
+  { 0x8500, 0x014f, 0x5fff },
+  { 0x8900, 0x0147, 0x4001 },
+  { 0x8900, 0x0143, 0x3001 },
+  { 0x8900, 0x0141, 0x2001 },
+  { 0x0500, 0x0140, 0x0fff },
+  { 0x0500, 0x0142, 0x0fff },
+  { 0x8900, 0x0145, 0x2001 },
+  { 0x0500, 0x0144, 0x0fff },
+  { 0x0500, 0x0146, 0x0fff },
+  { 0x8500, 0x014b, 0x3fff },
+  { 0x8500, 0x0149, 0x2000 },
+  { 0x0500, 0x0148, 0x0fff },
+  { 0x0900, 0x014a, 0x0001 },
+  { 0x8500, 0x014d, 0x2fff },
+  { 0x0900, 0x014c, 0x0001 },
+  { 0x0900, 0x014e, 0x0001 },
+  { 0x8500, 0x0157, 0x4fff },
+  { 0x8500, 0x0153, 0x3fff },
+  { 0x8500, 0x0151, 0x2fff },
+  { 0x0900, 0x0150, 0x0001 },
+  { 0x0900, 0x0152, 0x0001 },
+  { 0x8500, 0x0155, 0x2fff },
+  { 0x0900, 0x0154, 0x0001 },
+  { 0x0900, 0x0156, 0x0001 },
+  { 0x8500, 0x015b, 0x3fff },
+  { 0x8500, 0x0159, 0x2fff },
+  { 0x0900, 0x0158, 0x0001 },
+  { 0x0900, 0x015a, 0x0001 },
+  { 0x8500, 0x015d, 0x2fff },
+  { 0x0900, 0x015c, 0x0001 },
+  { 0x0900, 0x015e, 0x0001 },
+  { 0x8500, 0x016f, 0x5fff },
+  { 0x8500, 0x0167, 0x4fff },
+  { 0x8500, 0x0163, 0x3fff },
+  { 0x8500, 0x0161, 0x2fff },
+  { 0x0900, 0x0160, 0x0001 },
+  { 0x0900, 0x0162, 0x0001 },
+  { 0x8500, 0x0165, 0x2fff },
+  { 0x0900, 0x0164, 0x0001 },
+  { 0x0900, 0x0166, 0x0001 },
+  { 0x8500, 0x016b, 0x3fff },
+  { 0x8500, 0x0169, 0x2fff },
+  { 0x0900, 0x0168, 0x0001 },
+  { 0x0900, 0x016a, 0x0001 },
+  { 0x8500, 0x016d, 0x2fff },
+  { 0x0900, 0x016c, 0x0001 },
+  { 0x0900, 0x016e, 0x0001 },
+  { 0x8500, 0x0177, 0x4fff },
+  { 0x8500, 0x0173, 0x3fff },
+  { 0x8500, 0x0171, 0x2fff },
+  { 0x0900, 0x0170, 0x0001 },
+  { 0x0900, 0x0172, 0x0001 },
+  { 0x8500, 0x0175, 0x2fff },
+  { 0x0900, 0x0174, 0x0001 },
+  { 0x0900, 0x0176, 0x0001 },
+  { 0x8900, 0x017b, 0x3001 },
+  { 0x8900, 0x0179, 0x2001 },
+  { 0x0900, 0x0178, 0x0f87 },
+  { 0x0500, 0x017a, 0x0fff },
+  { 0x8900, 0x017d, 0x2001 },
+  { 0x0500, 0x017c, 0x0fff },
+  { 0x0500, 0x017e, 0x0fff },
+  { 0x8500, 0x01bf, 0x7038 },
+  { 0x8900, 0x019f, 0x60d6 },
+  { 0x8900, 0x018f, 0x50ca },
+  { 0x8900, 0x0187, 0x4001 },
+  { 0x8500, 0x0183, 0x3fff },
+  { 0x8900, 0x0181, 0x20d2 },
+  { 0x0500, 0x0180, 0x0000 },
+  { 0x0900, 0x0182, 0x0001 },
+  { 0x8500, 0x0185, 0x2fff },
+  { 0x0900, 0x0184, 0x0001 },
+  { 0x0900, 0x0186, 0x00ce },
+  { 0x8900, 0x018b, 0x3001 },
+  { 0x8900, 0x0189, 0x20cd },
+  { 0x0500, 0x0188, 0x0fff },
+  { 0x0900, 0x018a, 0x00cd },
+  { 0x8500, 0x018d, 0x2000 },
+  { 0x0500, 0x018c, 0x0fff },
+  { 0x0900, 0x018e, 0x004f },
+  { 0x8900, 0x0197, 0x40d1 },
+  { 0x8900, 0x0193, 0x30cd },
+  { 0x8900, 0x0191, 0x2001 },
+  { 0x0900, 0x0190, 0x00cb },
+  { 0x0500, 0x0192, 0x0fff },
+  { 0x8500, 0x0195, 0x2061 },
+  { 0x0900, 0x0194, 0x00cf },
+  { 0x0900, 0x0196, 0x00d3 },
+  { 0x8500, 0x019b, 0x3000 },
+  { 0x8500, 0x0199, 0x2fff },
+  { 0x0900, 0x0198, 0x0001 },
+  { 0x0500, 0x019a, 0x0000 },
+  { 0x8900, 0x019d, 0x20d5 },
+  { 0x0900, 0x019c, 0x00d3 },
+  { 0x0500, 0x019e, 0x0082 },
+  { 0x8900, 0x01af, 0x5001 },
+  { 0x8900, 0x01a7, 0x4001 },
+  { 0x8500, 0x01a3, 0x3fff },
+  { 0x8500, 0x01a1, 0x2fff },
+  { 0x0900, 0x01a0, 0x0001 },
+  { 0x0900, 0x01a2, 0x0001 },
+  { 0x8500, 0x01a5, 0x2fff },
+  { 0x0900, 0x01a4, 0x0001 },
+  { 0x0900, 0x01a6, 0x00da },
+  { 0x8500, 0x01ab, 0x3000 },
+  { 0x8900, 0x01a9, 0x20da },
+  { 0x0500, 0x01a8, 0x0fff },
+  { 0x0500, 0x01aa, 0x0000 },
+  { 0x8500, 0x01ad, 0x2fff },
+  { 0x0900, 0x01ac, 0x0001 },
+  { 0x0900, 0x01ae, 0x00da },
+  { 0x8900, 0x01b7, 0x40db },
+  { 0x8900, 0x01b3, 0x3001 },
+  { 0x8900, 0x01b1, 0x20d9 },
+  { 0x0500, 0x01b0, 0x0fff },
+  { 0x0900, 0x01b2, 0x00d9 },
+  { 0x8900, 0x01b5, 0x2001 },
+  { 0x0500, 0x01b4, 0x0fff },
+  { 0x0500, 0x01b6, 0x0fff },
+  { 0x8700, 0x01bb, 0x3000 },
+  { 0x8500, 0x01b9, 0x2fff },
+  { 0x0900, 0x01b8, 0x0001 },
+  { 0x0500, 0x01ba, 0x0000 },
+  { 0x8500, 0x01bd, 0x2fff },
+  { 0x0900, 0x01bc, 0x0001 },
+  { 0x0500, 0x01be, 0x0000 },
+  { 0x8500, 0x01df, 0x6fff },
+  { 0x8900, 0x01cf, 0x5001 },
+  { 0x8900, 0x01c7, 0x4002 },
+  { 0x8700, 0x01c3, 0x3000 },
+  { 0x8700, 0x01c1, 0x2000 },
+  { 0x0700, 0x01c0, 0x0000 },
+  { 0x0700, 0x01c2, 0x0000 },
+  { 0x8800, 0x01c5, 0x2000 },
+  { 0x0900, 0x01c4, 0x0002 },
+  { 0x0500, 0x01c6, 0x0ffe },
+  { 0x8800, 0x01cb, 0x3000 },
+  { 0x8500, 0x01c9, 0x2ffe },
+  { 0x0800, 0x01c8, 0x0000 },
+  { 0x0900, 0x01ca, 0x0002 },
+  { 0x8900, 0x01cd, 0x2001 },
+  { 0x0500, 0x01cc, 0x0ffe },
+  { 0x0500, 0x01ce, 0x0fff },
+  { 0x8900, 0x01d7, 0x4001 },
+  { 0x8900, 0x01d3, 0x3001 },
+  { 0x8900, 0x01d1, 0x2001 },
+  { 0x0500, 0x01d0, 0x0fff },
+  { 0x0500, 0x01d2, 0x0fff },
+  { 0x8900, 0x01d5, 0x2001 },
+  { 0x0500, 0x01d4, 0x0fff },
+  { 0x0500, 0x01d6, 0x0fff },
+  { 0x8900, 0x01db, 0x3001 },
+  { 0x8900, 0x01d9, 0x2001 },
+  { 0x0500, 0x01d8, 0x0fff },
+  { 0x0500, 0x01da, 0x0fff },
+  { 0x8500, 0x01dd, 0x2fb1 },
+  { 0x0500, 0x01dc, 0x0fff },
+  { 0x0900, 0x01de, 0x0001 },
+  { 0x8500, 0x01ef, 0x5fff },
+  { 0x8500, 0x01e7, 0x4fff },
+  { 0x8500, 0x01e3, 0x3fff },
+  { 0x8500, 0x01e1, 0x2fff },
+  { 0x0900, 0x01e0, 0x0001 },
+  { 0x0900, 0x01e2, 0x0001 },
+  { 0x8500, 0x01e5, 0x2fff },
+  { 0x0900, 0x01e4, 0x0001 },
+  { 0x0900, 0x01e6, 0x0001 },
+  { 0x8500, 0x01eb, 0x3fff },
+  { 0x8500, 0x01e9, 0x2fff },
+  { 0x0900, 0x01e8, 0x0001 },
+  { 0x0900, 0x01ea, 0x0001 },
+  { 0x8500, 0x01ed, 0x2fff },
+  { 0x0900, 0x01ec, 0x0001 },
+  { 0x0900, 0x01ee, 0x0001 },
+  { 0x8900, 0x01f7, 0x4fc8 },
+  { 0x8500, 0x01f3, 0x3ffe },
+  { 0x8900, 0x01f1, 0x2002 },
+  { 0x0500, 0x01f0, 0x0000 },
+  { 0x0800, 0x01f2, 0x0000 },
+  { 0x8500, 0x01f5, 0x2fff },
+  { 0x0900, 0x01f4, 0x0001 },
+  { 0x0900, 0x01f6, 0x0f9f },
+  { 0x8500, 0x01fb, 0x3fff },
+  { 0x8500, 0x01f9, 0x2fff },
+  { 0x0900, 0x01f8, 0x0001 },
+  { 0x0900, 0x01fa, 0x0001 },
+  { 0x8500, 0x01fd, 0x2fff },
+  { 0x0900, 0x01fc, 0x0001 },
+  { 0x0900, 0x01fe, 0x0001 },
+  { 0x8c00, 0x0318, 0x9000 },
+  { 0x8500, 0x0298, 0x8000 },
+  { 0x8500, 0x0258, 0x7000 },
+  { 0x8500, 0x021f, 0x6fff },
+  { 0x8500, 0x020f, 0x5fff },
+  { 0x8500, 0x0207, 0x4fff },
+  { 0x8500, 0x0203, 0x3fff },
+  { 0x8500, 0x0201, 0x2fff },
+  { 0x0900, 0x0200, 0x0001 },
+  { 0x0900, 0x0202, 0x0001 },
+  { 0x8500, 0x0205, 0x2fff },
+  { 0x0900, 0x0204, 0x0001 },
+  { 0x0900, 0x0206, 0x0001 },
+  { 0x8500, 0x020b, 0x3fff },
+  { 0x8500, 0x0209, 0x2fff },
+  { 0x0900, 0x0208, 0x0001 },
+  { 0x0900, 0x020a, 0x0001 },
+  { 0x8500, 0x020d, 0x2fff },
+  { 0x0900, 0x020c, 0x0001 },
+  { 0x0900, 0x020e, 0x0001 },
+  { 0x8500, 0x0217, 0x4fff },
+  { 0x8500, 0x0213, 0x3fff },
+  { 0x8500, 0x0211, 0x2fff },
+  { 0x0900, 0x0210, 0x0001 },
+  { 0x0900, 0x0212, 0x0001 },
+  { 0x8500, 0x0215, 0x2fff },
+  { 0x0900, 0x0214, 0x0001 },
+  { 0x0900, 0x0216, 0x0001 },
+  { 0x8500, 0x021b, 0x3fff },
+  { 0x8500, 0x0219, 0x2fff },
+  { 0x0900, 0x0218, 0x0001 },
+  { 0x0900, 0x021a, 0x0001 },
+  { 0x8500, 0x021d, 0x2fff },
+  { 0x0900, 0x021c, 0x0001 },
+  { 0x0900, 0x021e, 0x0001 },
+  { 0x8500, 0x022f, 0x5fff },
+  { 0x8500, 0x0227, 0x4fff },
+  { 0x8500, 0x0223, 0x3fff },
+  { 0x8500, 0x0221, 0x2000 },
+  { 0x0900, 0x0220, 0x0f7e },
+  { 0x0900, 0x0222, 0x0001 },
+  { 0x8500, 0x0225, 0x2fff },
+  { 0x0900, 0x0224, 0x0001 },
+  { 0x0900, 0x0226, 0x0001 },
+  { 0x8500, 0x022b, 0x3fff },
+  { 0x8500, 0x0229, 0x2fff },
+  { 0x0900, 0x0228, 0x0001 },
+  { 0x0900, 0x022a, 0x0001 },
+  { 0x8500, 0x022d, 0x2fff },
+  { 0x0900, 0x022c, 0x0001 },
+  { 0x0900, 0x022e, 0x0001 },
+  { 0x8500, 0x0250, 0x4000 },
+  { 0x8500, 0x0233, 0x3fff },
+  { 0x8500, 0x0231, 0x2fff },
+  { 0x0900, 0x0230, 0x0001 },
+  { 0x0900, 0x0232, 0x0001 },
+  { 0x8500, 0x0235, 0x2000 },
+  { 0x0500, 0x0234, 0x0000 },
+  { 0x0500, 0x0236, 0x0000 },
+  { 0x8500, 0x0254, 0x3f32 },
+  { 0x8500, 0x0252, 0x2000 },
+  { 0x0500, 0x0251, 0x0000 },
+  { 0x0500, 0x0253, 0x0f2e },
+  { 0x8500, 0x0256, 0x2f33 },
+  { 0x0500, 0x0255, 0x0000 },
+  { 0x0500, 0x0257, 0x0f33 },
+  { 0x8500, 0x0278, 0x6000 },
+  { 0x8500, 0x0268, 0x5f2f },
+  { 0x8500, 0x0260, 0x4f33 },
+  { 0x8500, 0x025c, 0x3000 },
+  { 0x8500, 0x025a, 0x2000 },
+  { 0x0500, 0x0259, 0x0f36 },
+  { 0x0500, 0x025b, 0x0f35 },
+  { 0x8500, 0x025e, 0x2000 },
+  { 0x0500, 0x025d, 0x0000 },
+  { 0x0500, 0x025f, 0x0000 },
+  { 0x8500, 0x0264, 0x3000 },
+  { 0x8500, 0x0262, 0x2000 },
+  { 0x0500, 0x0261, 0x0000 },
+  { 0x0500, 0x0263, 0x0f31 },
+  { 0x8500, 0x0266, 0x2000 },
+  { 0x0500, 0x0265, 0x0000 },
+  { 0x0500, 0x0267, 0x0000 },
+  { 0x8500, 0x0270, 0x4000 },
+  { 0x8500, 0x026c, 0x3000 },
+  { 0x8500, 0x026a, 0x2000 },
+  { 0x0500, 0x0269, 0x0f2d },
+  { 0x0500, 0x026b, 0x0000 },
+  { 0x8500, 0x026e, 0x2000 },
+  { 0x0500, 0x026d, 0x0000 },
+  { 0x0500, 0x026f, 0x0f2d },
+  { 0x8500, 0x0274, 0x3000 },
+  { 0x8500, 0x0272, 0x2f2b },
+  { 0x0500, 0x0271, 0x0000 },
+  { 0x0500, 0x0273, 0x0000 },
+  { 0x8500, 0x0276, 0x2000 },
+  { 0x0500, 0x0275, 0x0f2a },
+  { 0x0500, 0x0277, 0x0000 },
+  { 0x8500, 0x0288, 0x5f26 },
+  { 0x8500, 0x0280, 0x4f26 },
+  { 0x8500, 0x027c, 0x3000 },
+  { 0x8500, 0x027a, 0x2000 },
+  { 0x0500, 0x0279, 0x0000 },
+  { 0x0500, 0x027b, 0x0000 },
+  { 0x8500, 0x027e, 0x2000 },
+  { 0x0500, 0x027d, 0x0000 },
+  { 0x0500, 0x027f, 0x0000 },
+  { 0x8500, 0x0284, 0x3000 },
+  { 0x8500, 0x0282, 0x2000 },
+  { 0x0500, 0x0281, 0x0000 },
+  { 0x0500, 0x0283, 0x0f26 },
+  { 0x8500, 0x0286, 0x2000 },
+  { 0x0500, 0x0285, 0x0000 },
+  { 0x0500, 0x0287, 0x0000 },
+  { 0x8500, 0x0290, 0x4000 },
+  { 0x8500, 0x028c, 0x3000 },
+  { 0x8500, 0x028a, 0x2f27 },
+  { 0x0500, 0x0289, 0x0000 },
+  { 0x0500, 0x028b, 0x0f27 },
+  { 0x8500, 0x028e, 0x2000 },
+  { 0x0500, 0x028d, 0x0000 },
+  { 0x0500, 0x028f, 0x0000 },
+  { 0x8500, 0x0294, 0x3000 },
+  { 0x8500, 0x0292, 0x2f25 },
+  { 0x0500, 0x0291, 0x0000 },
+  { 0x0500, 0x0293, 0x0000 },
+  { 0x8500, 0x0296, 0x2000 },
+  { 0x0500, 0x0295, 0x0000 },
+  { 0x0500, 0x0297, 0x0000 },
+  { 0x9800, 0x02d8, 0x7000 },
+  { 0x8600, 0x02b8, 0x6000 },
+  { 0x8500, 0x02a8, 0x5000 },
+  { 0x8500, 0x02a0, 0x4000 },
+  { 0x8500, 0x029c, 0x3000 },
+  { 0x8500, 0x029a, 0x2000 },
+  { 0x0500, 0x0299, 0x0000 },
+  { 0x0500, 0x029b, 0x0000 },
+  { 0x8500, 0x029e, 0x2000 },
+  { 0x0500, 0x029d, 0x0000 },
+  { 0x0500, 0x029f, 0x0000 },
+  { 0x8500, 0x02a4, 0x3000 },
+  { 0x8500, 0x02a2, 0x2000 },
+  { 0x0500, 0x02a1, 0x0000 },
+  { 0x0500, 0x02a3, 0x0000 },
+  { 0x8500, 0x02a6, 0x2000 },
+  { 0x0500, 0x02a5, 0x0000 },
+  { 0x0500, 0x02a7, 0x0000 },
+  { 0x8600, 0x02b0, 0x4000 },
+  { 0x8500, 0x02ac, 0x3000 },
+  { 0x8500, 0x02aa, 0x2000 },
+  { 0x0500, 0x02a9, 0x0000 },
+  { 0x0500, 0x02ab, 0x0000 },
+  { 0x8500, 0x02ae, 0x2000 },
+  { 0x0500, 0x02ad, 0x0000 },
+  { 0x0500, 0x02af, 0x0000 },
+  { 0x8600, 0x02b4, 0x3000 },
+  { 0x8600, 0x02b2, 0x2000 },
+  { 0x0600, 0x02b1, 0x0000 },
+  { 0x0600, 0x02b3, 0x0000 },
+  { 0x8600, 0x02b6, 0x2000 },
+  { 0x0600, 0x02b5, 0x0000 },
+  { 0x0600, 0x02b7, 0x0000 },
+  { 0x8600, 0x02c8, 0x5000 },
+  { 0x8600, 0x02c0, 0x4000 },
+  { 0x8600, 0x02bc, 0x3000 },
+  { 0x8600, 0x02ba, 0x2000 },
+  { 0x0600, 0x02b9, 0x0000 },
+  { 0x0600, 0x02bb, 0x0000 },
+  { 0x8600, 0x02be, 0x2000 },
+  { 0x0600, 0x02bd, 0x0000 },
+  { 0x0600, 0x02bf, 0x0000 },
+  { 0x9800, 0x02c4, 0x3000 },
+  { 0x9800, 0x02c2, 0x2000 },
+  { 0x0600, 0x02c1, 0x0000 },
+  { 0x1800, 0x02c3, 0x0000 },
+  { 0x8600, 0x02c6, 0x2000 },
+  { 0x1800, 0x02c5, 0x0000 },
+  { 0x0600, 0x02c7, 0x0000 },
+  { 0x8600, 0x02d0, 0x4000 },
+  { 0x8600, 0x02cc, 0x3000 },
+  { 0x8600, 0x02ca, 0x2000 },
+  { 0x0600, 0x02c9, 0x0000 },
+  { 0x0600, 0x02cb, 0x0000 },
+  { 0x8600, 0x02ce, 0x2000 },
+  { 0x0600, 0x02cd, 0x0000 },
+  { 0x0600, 0x02cf, 0x0000 },
+  { 0x9800, 0x02d4, 0x3000 },
+  { 0x9800, 0x02d2, 0x2000 },
+  { 0x0600, 0x02d1, 0x0000 },
+  { 0x1800, 0x02d3, 0x0000 },
+  { 0x9800, 0x02d6, 0x2000 },
+  { 0x1800, 0x02d5, 0x0000 },
+  { 0x1800, 0x02d7, 0x0000 },
+  { 0x9800, 0x02f8, 0x6000 },
+  { 0x9800, 0x02e8, 0x5000 },
+  { 0x8600, 0x02e0, 0x4000 },
+  { 0x9800, 0x02dc, 0x3000 },
+  { 0x9800, 0x02da, 0x2000 },
+  { 0x1800, 0x02d9, 0x0000 },
+  { 0x1800, 0x02db, 0x0000 },
+  { 0x9800, 0x02de, 0x2000 },
+  { 0x1800, 0x02dd, 0x0000 },
+  { 0x1800, 0x02df, 0x0000 },
+  { 0x8600, 0x02e4, 0x3000 },
+  { 0x8600, 0x02e2, 0x2000 },
+  { 0x0600, 0x02e1, 0x0000 },
+  { 0x0600, 0x02e3, 0x0000 },
+  { 0x9800, 0x02e6, 0x2000 },
+  { 0x1800, 0x02e5, 0x0000 },
+  { 0x1800, 0x02e7, 0x0000 },
+  { 0x9800, 0x02f0, 0x4000 },
+  { 0x9800, 0x02ec, 0x3000 },
+  { 0x9800, 0x02ea, 0x2000 },
+  { 0x1800, 0x02e9, 0x0000 },
+  { 0x1800, 0x02eb, 0x0000 },
+  { 0x8600, 0x02ee, 0x2000 },
+  { 0x1800, 0x02ed, 0x0000 },
+  { 0x1800, 0x02ef, 0x0000 },
+  { 0x9800, 0x02f4, 0x3000 },
+  { 0x9800, 0x02f2, 0x2000 },
+  { 0x1800, 0x02f1, 0x0000 },
+  { 0x1800, 0x02f3, 0x0000 },
+  { 0x9800, 0x02f6, 0x2000 },
+  { 0x1800, 0x02f5, 0x0000 },
+  { 0x1800, 0x02f7, 0x0000 },
+  { 0x8c00, 0x0308, 0x5000 },
+  { 0x8c00, 0x0300, 0x4000 },
+  { 0x9800, 0x02fc, 0x3000 },
+  { 0x9800, 0x02fa, 0x2000 },
+  { 0x1800, 0x02f9, 0x0000 },
+  { 0x1800, 0x02fb, 0x0000 },
+  { 0x9800, 0x02fe, 0x2000 },
+  { 0x1800, 0x02fd, 0x0000 },
+  { 0x1800, 0x02ff, 0x0000 },
+  { 0x8c00, 0x0304, 0x3000 },
+  { 0x8c00, 0x0302, 0x2000 },
+  { 0x0c00, 0x0301, 0x0000 },
+  { 0x0c00, 0x0303, 0x0000 },
+  { 0x8c00, 0x0306, 0x2000 },
+  { 0x0c00, 0x0305, 0x0000 },
+  { 0x0c00, 0x0307, 0x0000 },
+  { 0x8c00, 0x0310, 0x4000 },
+  { 0x8c00, 0x030c, 0x3000 },
+  { 0x8c00, 0x030a, 0x2000 },
+  { 0x0c00, 0x0309, 0x0000 },
+  { 0x0c00, 0x030b, 0x0000 },
+  { 0x8c00, 0x030e, 0x2000 },
+  { 0x0c00, 0x030d, 0x0000 },
+  { 0x0c00, 0x030f, 0x0000 },
+  { 0x8c00, 0x0314, 0x3000 },
+  { 0x8c00, 0x0312, 0x2000 },
+  { 0x0c00, 0x0311, 0x0000 },
+  { 0x0c00, 0x0313, 0x0000 },
+  { 0x8c00, 0x0316, 0x2000 },
+  { 0x0c00, 0x0315, 0x0000 },
+  { 0x0c00, 0x0317, 0x0000 },
+  { 0x8500, 0x03b0, 0x8000 },
+  { 0x8c00, 0x035d, 0x7000 },
+  { 0x8c00, 0x0338, 0x6000 },
+  { 0x8c00, 0x0328, 0x5000 },
+  { 0x8c00, 0x0320, 0x4000 },
+  { 0x8c00, 0x031c, 0x3000 },
+  { 0x8c00, 0x031a, 0x2000 },
+  { 0x0c00, 0x0319, 0x0000 },
+  { 0x0c00, 0x031b, 0x0000 },
+  { 0x8c00, 0x031e, 0x2000 },
+  { 0x0c00, 0x031d, 0x0000 },
+  { 0x0c00, 0x031f, 0x0000 },
+  { 0x8c00, 0x0324, 0x3000 },
+  { 0x8c00, 0x0322, 0x2000 },
+  { 0x0c00, 0x0321, 0x0000 },
+  { 0x0c00, 0x0323, 0x0000 },
+  { 0x8c00, 0x0326, 0x2000 },
+  { 0x0c00, 0x0325, 0x0000 },
+  { 0x0c00, 0x0327, 0x0000 },
+  { 0x8c00, 0x0330, 0x4000 },
+  { 0x8c00, 0x032c, 0x3000 },
+  { 0x8c00, 0x032a, 0x2000 },
+  { 0x0c00, 0x0329, 0x0000 },
+  { 0x0c00, 0x032b, 0x0000 },
+  { 0x8c00, 0x032e, 0x2000 },
+  { 0x0c00, 0x032d, 0x0000 },
+  { 0x0c00, 0x032f, 0x0000 },
+  { 0x8c00, 0x0334, 0x3000 },
+  { 0x8c00, 0x0332, 0x2000 },
+  { 0x0c00, 0x0331, 0x0000 },
+  { 0x0c00, 0x0333, 0x0000 },
+  { 0x8c00, 0x0336, 0x2000 },
+  { 0x0c00, 0x0335, 0x0000 },
+  { 0x0c00, 0x0337, 0x0000 },
+  { 0x8c00, 0x0348, 0x5000 },
+  { 0x8c00, 0x0340, 0x4000 },
+  { 0x8c00, 0x033c, 0x3000 },
+  { 0x8c00, 0x033a, 0x2000 },
+  { 0x0c00, 0x0339, 0x0000 },
+  { 0x0c00, 0x033b, 0x0000 },
+  { 0x8c00, 0x033e, 0x2000 },
+  { 0x0c00, 0x033d, 0x0000 },
+  { 0x0c00, 0x033f, 0x0000 },
+  { 0x8c00, 0x0344, 0x3000 },
+  { 0x8c00, 0x0342, 0x2000 },
+  { 0x0c00, 0x0341, 0x0000 },
+  { 0x0c00, 0x0343, 0x0000 },
+  { 0x8c00, 0x0346, 0x2000 },
+  { 0x0c00, 0x0345, 0x0000 },
+  { 0x0c00, 0x0347, 0x0000 },
+  { 0x8c00, 0x0350, 0x4000 },
+  { 0x8c00, 0x034c, 0x3000 },
+  { 0x8c00, 0x034a, 0x2000 },
+  { 0x0c00, 0x0349, 0x0000 },
+  { 0x0c00, 0x034b, 0x0000 },
+  { 0x8c00, 0x034e, 0x2000 },
+  { 0x0c00, 0x034d, 0x0000 },
+  { 0x0c00, 0x034f, 0x0000 },
+  { 0x8c00, 0x0354, 0x3000 },
+  { 0x8c00, 0x0352, 0x2000 },
+  { 0x0c00, 0x0351, 0x0000 },
+  { 0x0c00, 0x0353, 0x0000 },
+  { 0x8c00, 0x0356, 0x2000 },
+  { 0x0c00, 0x0355, 0x0000 },
+  { 0x0c00, 0x0357, 0x0000 },
+  { 0x8900, 0x038f, 0x603f },
+  { 0x8c00, 0x036d, 0x5000 },
+  { 0x8c00, 0x0365, 0x4000 },
+  { 0x8c00, 0x0361, 0x3000 },
+  { 0x8c00, 0x035f, 0x2000 },
+  { 0x0c00, 0x035e, 0x0000 },
+  { 0x0c00, 0x0360, 0x0000 },
+  { 0x8c00, 0x0363, 0x2000 },
+  { 0x0c00, 0x0362, 0x0000 },
+  { 0x0c00, 0x0364, 0x0000 },
+  { 0x8c00, 0x0369, 0x3000 },
+  { 0x8c00, 0x0367, 0x2000 },
+  { 0x0c00, 0x0366, 0x0000 },
+  { 0x0c00, 0x0368, 0x0000 },
+  { 0x8c00, 0x036b, 0x2000 },
+  { 0x0c00, 0x036a, 0x0000 },
+  { 0x0c00, 0x036c, 0x0000 },
+  { 0x9800, 0x0385, 0x4000 },
+  { 0x9800, 0x0375, 0x3000 },
+  { 0x8c00, 0x036f, 0x2000 },
+  { 0x0c00, 0x036e, 0x0000 },
+  { 0x1800, 0x0374, 0x0000 },
+  { 0x9500, 0x037e, 0x2000 },
+  { 0x0600, 0x037a, 0x0000 },
+  { 0x1800, 0x0384, 0x0000 },
+  { 0x8900, 0x0389, 0x3025 },
+  { 0x9500, 0x0387, 0x2000 },
+  { 0x0900, 0x0386, 0x0026 },
+  { 0x0900, 0x0388, 0x0025 },
+  { 0x8900, 0x038c, 0x2040 },
+  { 0x0900, 0x038a, 0x0025 },
+  { 0x0900, 0x038e, 0x003f },
+  { 0x8900, 0x039f, 0x5020 },
+  { 0x8900, 0x0397, 0x4020 },
+  { 0x8900, 0x0393, 0x3020 },
+  { 0x8900, 0x0391, 0x2020 },
+  { 0x0500, 0x0390, 0x0000 },
+  { 0x0900, 0x0392, 0x0020 },
+  { 0x8900, 0x0395, 0x2020 },
+  { 0x0900, 0x0394, 0x0020 },
+  { 0x0900, 0x0396, 0x0020 },
+  { 0x8900, 0x039b, 0x3020 },
+  { 0x8900, 0x0399, 0x2020 },
+  { 0x0900, 0x0398, 0x0020 },
+  { 0x0900, 0x039a, 0x0020 },
+  { 0x8900, 0x039d, 0x2020 },
+  { 0x0900, 0x039c, 0x0020 },
+  { 0x0900, 0x039e, 0x0020 },
+  { 0x8900, 0x03a8, 0x4020 },
+  { 0x8900, 0x03a4, 0x3020 },
+  { 0x8900, 0x03a1, 0x2020 },
+  { 0x0900, 0x03a0, 0x0020 },
+  { 0x0900, 0x03a3, 0x0020 },
+  { 0x8900, 0x03a6, 0x2020 },
+  { 0x0900, 0x03a5, 0x0020 },
+  { 0x0900, 0x03a7, 0x0020 },
+  { 0x8500, 0x03ac, 0x3fda },
+  { 0x8900, 0x03aa, 0x2020 },
+  { 0x0900, 0x03a9, 0x0020 },
+  { 0x0900, 0x03ab, 0x0020 },
+  { 0x8500, 0x03ae, 0x2fdb },
+  { 0x0500, 0x03ad, 0x0fdb },
+  { 0x0500, 0x03af, 0x0fdb },
+  { 0x8500, 0x03f1, 0x7fb0 },
+  { 0x8500, 0x03d1, 0x6fc7 },
+  { 0x8500, 0x03c0, 0x5fe0 },
+  { 0x8500, 0x03b8, 0x4fe0 },
+  { 0x8500, 0x03b4, 0x3fe0 },
+  { 0x8500, 0x03b2, 0x2fe0 },
+  { 0x0500, 0x03b1, 0x0fe0 },
+  { 0x0500, 0x03b3, 0x0fe0 },
+  { 0x8500, 0x03b6, 0x2fe0 },
+  { 0x0500, 0x03b5, 0x0fe0 },
+  { 0x0500, 0x03b7, 0x0fe0 },
+  { 0x8500, 0x03bc, 0x3fe0 },
+  { 0x8500, 0x03ba, 0x2fe0 },
+  { 0x0500, 0x03b9, 0x0fe0 },
+  { 0x0500, 0x03bb, 0x0fe0 },
+  { 0x8500, 0x03be, 0x2fe0 },
+  { 0x0500, 0x03bd, 0x0fe0 },
+  { 0x0500, 0x03bf, 0x0fe0 },
+  { 0x8500, 0x03c8, 0x4fe0 },
+  { 0x8500, 0x03c4, 0x3fe0 },
+  { 0x8500, 0x03c2, 0x2fe1 },
+  { 0x0500, 0x03c1, 0x0fe0 },
+  { 0x0500, 0x03c3, 0x0fe0 },
+  { 0x8500, 0x03c6, 0x2fe0 },
+  { 0x0500, 0x03c5, 0x0fe0 },
+  { 0x0500, 0x03c7, 0x0fe0 },
+  { 0x8500, 0x03cc, 0x3fc0 },
+  { 0x8500, 0x03ca, 0x2fe0 },
+  { 0x0500, 0x03c9, 0x0fe0 },
+  { 0x0500, 0x03cb, 0x0fe0 },
+  { 0x8500, 0x03ce, 0x2fc1 },
+  { 0x0500, 0x03cd, 0x0fc1 },
+  { 0x0500, 0x03d0, 0x0fc2 },
+  { 0x8500, 0x03e1, 0x5fff },
+  { 0x8500, 0x03d9, 0x4fff },
+  { 0x8500, 0x03d5, 0x3fd1 },
+  { 0x8900, 0x03d3, 0x2000 },
+  { 0x0900, 0x03d2, 0x0000 },
+  { 0x0900, 0x03d4, 0x0000 },
+  { 0x8500, 0x03d7, 0x2000 },
+  { 0x0500, 0x03d6, 0x0fca },
+  { 0x0900, 0x03d8, 0x0001 },
+  { 0x8500, 0x03dd, 0x3fff },
+  { 0x8500, 0x03db, 0x2fff },
+  { 0x0900, 0x03da, 0x0001 },
+  { 0x0900, 0x03dc, 0x0001 },
+  { 0x8500, 0x03df, 0x2fff },
+  { 0x0900, 0x03de, 0x0001 },
+  { 0x0900, 0x03e0, 0x0001 },
+  { 0x8500, 0x03e9, 0x4fff },
+  { 0x8500, 0x03e5, 0x3fff },
+  { 0x8500, 0x03e3, 0x2fff },
+  { 0x0900, 0x03e2, 0x0001 },
+  { 0x0900, 0x03e4, 0x0001 },
+  { 0x8500, 0x03e7, 0x2fff },
+  { 0x0900, 0x03e6, 0x0001 },
+  { 0x0900, 0x03e8, 0x0001 },
+  { 0x8500, 0x03ed, 0x3fff },
+  { 0x8500, 0x03eb, 0x2fff },
+  { 0x0900, 0x03ea, 0x0001 },
+  { 0x0900, 0x03ec, 0x0001 },
+  { 0x8500, 0x03ef, 0x2fff },
+  { 0x0900, 0x03ee, 0x0001 },
+  { 0x0500, 0x03f0, 0x0faa },
+  { 0x8900, 0x0415, 0x6020 },
+  { 0x8900, 0x0405, 0x5050 },
+  { 0x8900, 0x03f9, 0x4ff9 },
+  { 0x8500, 0x03f5, 0x3fa0 },
+  { 0x8500, 0x03f3, 0x2000 },
+  { 0x0500, 0x03f2, 0x0007 },
+  { 0x0900, 0x03f4, 0x0fc4 },
+  { 0x8900, 0x03f7, 0x2001 },
+  { 0x1900, 0x03f6, 0x0000 },
+  { 0x0500, 0x03f8, 0x0fff },
+  { 0x8900, 0x0401, 0x3050 },
+  { 0x8500, 0x03fb, 0x2fff },
+  { 0x0900, 0x03fa, 0x0001 },
+  { 0x0900, 0x0400, 0x0050 },
+  { 0x8900, 0x0403, 0x2050 },
+  { 0x0900, 0x0402, 0x0050 },
+  { 0x0900, 0x0404, 0x0050 },
+  { 0x8900, 0x040d, 0x4050 },
+  { 0x8900, 0x0409, 0x3050 },
+  { 0x8900, 0x0407, 0x2050 },
+  { 0x0900, 0x0406, 0x0050 },
+  { 0x0900, 0x0408, 0x0050 },
+  { 0x8900, 0x040b, 0x2050 },
+  { 0x0900, 0x040a, 0x0050 },
+  { 0x0900, 0x040c, 0x0050 },
+  { 0x8900, 0x0411, 0x3020 },
+  { 0x8900, 0x040f, 0x2050 },
+  { 0x0900, 0x040e, 0x0050 },
+  { 0x0900, 0x0410, 0x0020 },
+  { 0x8900, 0x0413, 0x2020 },
+  { 0x0900, 0x0412, 0x0020 },
+  { 0x0900, 0x0414, 0x0020 },
+  { 0x8900, 0x0425, 0x5020 },
+  { 0x8900, 0x041d, 0x4020 },
+  { 0x8900, 0x0419, 0x3020 },
+  { 0x8900, 0x0417, 0x2020 },
+  { 0x0900, 0x0416, 0x0020 },
+  { 0x0900, 0x0418, 0x0020 },
+  { 0x8900, 0x041b, 0x2020 },
+  { 0x0900, 0x041a, 0x0020 },
+  { 0x0900, 0x041c, 0x0020 },
+  { 0x8900, 0x0421, 0x3020 },
+  { 0x8900, 0x041f, 0x2020 },
+  { 0x0900, 0x041e, 0x0020 },
+  { 0x0900, 0x0420, 0x0020 },
+  { 0x8900, 0x0423, 0x2020 },
+  { 0x0900, 0x0422, 0x0020 },
+  { 0x0900, 0x0424, 0x0020 },
+  { 0x8900, 0x042d, 0x4020 },
+  { 0x8900, 0x0429, 0x3020 },
+  { 0x8900, 0x0427, 0x2020 },
+  { 0x0900, 0x0426, 0x0020 },
+  { 0x0900, 0x0428, 0x0020 },
+  { 0x8900, 0x042b, 0x2020 },
+  { 0x0900, 0x042a, 0x0020 },
+  { 0x0900, 0x042c, 0x0020 },
+  { 0x8500, 0x0431, 0x3fe0 },
+  { 0x8900, 0x042f, 0x2020 },
+  { 0x0900, 0x042e, 0x0020 },
+  { 0x0500, 0x0430, 0x0fe0 },
+  { 0x8500, 0x0433, 0x2fe0 },
+  { 0x0500, 0x0432, 0x0fe0 },
+  { 0x0500, 0x0434, 0x0fe0 },
+  { 0x8700, 0x06a4, 0xa000 },
+  { 0x8500, 0x0563, 0x9fd0 },
+  { 0x8900, 0x04b6, 0x8001 },
+  { 0x8500, 0x0475, 0x7fff },
+  { 0x8500, 0x0455, 0x6fb0 },
+  { 0x8500, 0x0445, 0x5fe0 },
+  { 0x8500, 0x043d, 0x4fe0 },
+  { 0x8500, 0x0439, 0x3fe0 },
+  { 0x8500, 0x0437, 0x2fe0 },
+  { 0x0500, 0x0436, 0x0fe0 },
+  { 0x0500, 0x0438, 0x0fe0 },
+  { 0x8500, 0x043b, 0x2fe0 },
+  { 0x0500, 0x043a, 0x0fe0 },
+  { 0x0500, 0x043c, 0x0fe0 },
+  { 0x8500, 0x0441, 0x3fe0 },
+  { 0x8500, 0x043f, 0x2fe0 },
+  { 0x0500, 0x043e, 0x0fe0 },
+  { 0x0500, 0x0440, 0x0fe0 },
+  { 0x8500, 0x0443, 0x2fe0 },
+  { 0x0500, 0x0442, 0x0fe0 },
+  { 0x0500, 0x0444, 0x0fe0 },
+  { 0x8500, 0x044d, 0x4fe0 },
+  { 0x8500, 0x0449, 0x3fe0 },
+  { 0x8500, 0x0447, 0x2fe0 },
+  { 0x0500, 0x0446, 0x0fe0 },
+  { 0x0500, 0x0448, 0x0fe0 },
+  { 0x8500, 0x044b, 0x2fe0 },
+  { 0x0500, 0x044a, 0x0fe0 },
+  { 0x0500, 0x044c, 0x0fe0 },
+  { 0x8500, 0x0451, 0x3fb0 },
+  { 0x8500, 0x044f, 0x2fe0 },
+  { 0x0500, 0x044e, 0x0fe0 },
+  { 0x0500, 0x0450, 0x0fb0 },
+  { 0x8500, 0x0453, 0x2fb0 },
+  { 0x0500, 0x0452, 0x0fb0 },
+  { 0x0500, 0x0454, 0x0fb0 },
+  { 0x8500, 0x0465, 0x5fff },
+  { 0x8500, 0x045d, 0x4fb0 },
+  { 0x8500, 0x0459, 0x3fb0 },
+  { 0x8500, 0x0457, 0x2fb0 },
+  { 0x0500, 0x0456, 0x0fb0 },
+  { 0x0500, 0x0458, 0x0fb0 },
+  { 0x8500, 0x045b, 0x2fb0 },
+  { 0x0500, 0x045a, 0x0fb0 },
+  { 0x0500, 0x045c, 0x0fb0 },
+  { 0x8500, 0x0461, 0x3fff },
+  { 0x8500, 0x045f, 0x2fb0 },
+  { 0x0500, 0x045e, 0x0fb0 },
+  { 0x0900, 0x0460, 0x0001 },
+  { 0x8500, 0x0463, 0x2fff },
+  { 0x0900, 0x0462, 0x0001 },
+  { 0x0900, 0x0464, 0x0001 },
+  { 0x8500, 0x046d, 0x4fff },
+  { 0x8500, 0x0469, 0x3fff },
+  { 0x8500, 0x0467, 0x2fff },
+  { 0x0900, 0x0466, 0x0001 },
+  { 0x0900, 0x0468, 0x0001 },
+  { 0x8500, 0x046b, 0x2fff },
+  { 0x0900, 0x046a, 0x0001 },
+  { 0x0900, 0x046c, 0x0001 },
+  { 0x8500, 0x0471, 0x3fff },
+  { 0x8500, 0x046f, 0x2fff },
+  { 0x0900, 0x046e, 0x0001 },
+  { 0x0900, 0x0470, 0x0001 },
+  { 0x8500, 0x0473, 0x2fff },
+  { 0x0900, 0x0472, 0x0001 },
+  { 0x0900, 0x0474, 0x0001 },
+  { 0x8900, 0x0496, 0x6001 },
+  { 0x8c00, 0x0485, 0x5000 },
+  { 0x8500, 0x047d, 0x4fff },
+  { 0x8500, 0x0479, 0x3fff },
+  { 0x8500, 0x0477, 0x2fff },
+  { 0x0900, 0x0476, 0x0001 },
+  { 0x0900, 0x0478, 0x0001 },
+  { 0x8500, 0x047b, 0x2fff },
+  { 0x0900, 0x047a, 0x0001 },
+  { 0x0900, 0x047c, 0x0001 },
+  { 0x8500, 0x0481, 0x3fff },
+  { 0x8500, 0x047f, 0x2fff },
+  { 0x0900, 0x047e, 0x0001 },
+  { 0x0900, 0x0480, 0x0001 },
+  { 0x8c00, 0x0483, 0x2000 },
+  { 0x1a00, 0x0482, 0x0000 },
+  { 0x0c00, 0x0484, 0x0000 },
+  { 0x8900, 0x048e, 0x4001 },
+  { 0x8900, 0x048a, 0x3001 },
+  { 0x8b00, 0x0488, 0x2000 },
+  { 0x0c00, 0x0486, 0x0000 },
+  { 0x0b00, 0x0489, 0x0000 },
+  { 0x8900, 0x048c, 0x2001 },
+  { 0x0500, 0x048b, 0x0fff },
+  { 0x0500, 0x048d, 0x0fff },
+  { 0x8900, 0x0492, 0x3001 },
+  { 0x8900, 0x0490, 0x2001 },
+  { 0x0500, 0x048f, 0x0fff },
+  { 0x0500, 0x0491, 0x0fff },
+  { 0x8900, 0x0494, 0x2001 },
+  { 0x0500, 0x0493, 0x0fff },
+  { 0x0500, 0x0495, 0x0fff },
+  { 0x8900, 0x04a6, 0x5001 },
+  { 0x8900, 0x049e, 0x4001 },
+  { 0x8900, 0x049a, 0x3001 },
+  { 0x8900, 0x0498, 0x2001 },
+  { 0x0500, 0x0497, 0x0fff },
+  { 0x0500, 0x0499, 0x0fff },
+  { 0x8900, 0x049c, 0x2001 },
+  { 0x0500, 0x049b, 0x0fff },
+  { 0x0500, 0x049d, 0x0fff },
+  { 0x8900, 0x04a2, 0x3001 },
+  { 0x8900, 0x04a0, 0x2001 },
+  { 0x0500, 0x049f, 0x0fff },
+  { 0x0500, 0x04a1, 0x0fff },
+  { 0x8900, 0x04a4, 0x2001 },
+  { 0x0500, 0x04a3, 0x0fff },
+  { 0x0500, 0x04a5, 0x0fff },
+  { 0x8900, 0x04ae, 0x4001 },
+  { 0x8900, 0x04aa, 0x3001 },
+  { 0x8900, 0x04a8, 0x2001 },
+  { 0x0500, 0x04a7, 0x0fff },
+  { 0x0500, 0x04a9, 0x0fff },
+  { 0x8900, 0x04ac, 0x2001 },
+  { 0x0500, 0x04ab, 0x0fff },
+  { 0x0500, 0x04ad, 0x0fff },
+  { 0x8900, 0x04b2, 0x3001 },
+  { 0x8900, 0x04b0, 0x2001 },
+  { 0x0500, 0x04af, 0x0fff },
+  { 0x0500, 0x04b1, 0x0fff },
+  { 0x8900, 0x04b4, 0x2001 },
+  { 0x0500, 0x04b3, 0x0fff },
+  { 0x0500, 0x04b5, 0x0fff },
+  { 0x8500, 0x04f9, 0x7fff },
+  { 0x8500, 0x04d7, 0x6fff },
+  { 0x8500, 0x04c6, 0x5fff },
+  { 0x8900, 0x04be, 0x4001 },
+  { 0x8900, 0x04ba, 0x3001 },
+  { 0x8900, 0x04b8, 0x2001 },
+  { 0x0500, 0x04b7, 0x0fff },
+  { 0x0500, 0x04b9, 0x0fff },
+  { 0x8900, 0x04bc, 0x2001 },
+  { 0x0500, 0x04bb, 0x0fff },
+  { 0x0500, 0x04bd, 0x0fff },
+  { 0x8500, 0x04c2, 0x3fff },
+  { 0x8900, 0x04c0, 0x2000 },
+  { 0x0500, 0x04bf, 0x0fff },
+  { 0x0900, 0x04c1, 0x0001 },
+  { 0x8500, 0x04c4, 0x2fff },
+  { 0x0900, 0x04c3, 0x0001 },
+  { 0x0900, 0x04c5, 0x0001 },
+  { 0x8500, 0x04ce, 0x4fff },
+  { 0x8500, 0x04ca, 0x3fff },
+  { 0x8500, 0x04c8, 0x2fff },
+  { 0x0900, 0x04c7, 0x0001 },
+  { 0x0900, 0x04c9, 0x0001 },
+  { 0x8500, 0x04cc, 0x2fff },
+  { 0x0900, 0x04cb, 0x0001 },
+  { 0x0900, 0x04cd, 0x0001 },
+  { 0x8500, 0x04d3, 0x3fff },
+  { 0x8500, 0x04d1, 0x2fff },
+  { 0x0900, 0x04d0, 0x0001 },
+  { 0x0900, 0x04d2, 0x0001 },
+  { 0x8500, 0x04d5, 0x2fff },
+  { 0x0900, 0x04d4, 0x0001 },
+  { 0x0900, 0x04d6, 0x0001 },
+  { 0x8500, 0x04e7, 0x5fff },
+  { 0x8500, 0x04df, 0x4fff },
+  { 0x8500, 0x04db, 0x3fff },
+  { 0x8500, 0x04d9, 0x2fff },
+  { 0x0900, 0x04d8, 0x0001 },
+  { 0x0900, 0x04da, 0x0001 },
+  { 0x8500, 0x04dd, 0x2fff },
+  { 0x0900, 0x04dc, 0x0001 },
+  { 0x0900, 0x04de, 0x0001 },
+  { 0x8500, 0x04e3, 0x3fff },
+  { 0x8500, 0x04e1, 0x2fff },
+  { 0x0900, 0x04e0, 0x0001 },
+  { 0x0900, 0x04e2, 0x0001 },
+  { 0x8500, 0x04e5, 0x2fff },
+  { 0x0900, 0x04e4, 0x0001 },
+  { 0x0900, 0x04e6, 0x0001 },
+  { 0x8500, 0x04ef, 0x4fff },
+  { 0x8500, 0x04eb, 0x3fff },
+  { 0x8500, 0x04e9, 0x2fff },
+  { 0x0900, 0x04e8, 0x0001 },
+  { 0x0900, 0x04ea, 0x0001 },
+  { 0x8500, 0x04ed, 0x2fff },
+  { 0x0900, 0x04ec, 0x0001 },
+  { 0x0900, 0x04ee, 0x0001 },
+  { 0x8500, 0x04f3, 0x3fff },
+  { 0x8500, 0x04f1, 0x2fff },
+  { 0x0900, 0x04f0, 0x0001 },
+  { 0x0900, 0x04f2, 0x0001 },
+  { 0x8500, 0x04f5, 0x2fff },
+  { 0x0900, 0x04f4, 0x0001 },
+  { 0x0900, 0x04f8, 0x0001 },
+  { 0x8900, 0x0540, 0x6030 },
+  { 0x8500, 0x050f, 0x5fff },
+  { 0x8500, 0x0507, 0x4fff },
+  { 0x8500, 0x0503, 0x3fff },
+  { 0x8500, 0x0501, 0x2fff },
+  { 0x0900, 0x0500, 0x0001 },
+  { 0x0900, 0x0502, 0x0001 },
+  { 0x8500, 0x0505, 0x2fff },
+  { 0x0900, 0x0504, 0x0001 },
+  { 0x0900, 0x0506, 0x0001 },
+  { 0x8500, 0x050b, 0x3fff },
+  { 0x8500, 0x0509, 0x2fff },
+  { 0x0900, 0x0508, 0x0001 },
+  { 0x0900, 0x050a, 0x0001 },
+  { 0x8500, 0x050d, 0x2fff },
+  { 0x0900, 0x050c, 0x0001 },
+  { 0x0900, 0x050e, 0x0001 },
+  { 0x8900, 0x0538, 0x4030 },
+  { 0x8900, 0x0534, 0x3030 },
+  { 0x8900, 0x0532, 0x2030 },
+  { 0x0900, 0x0531, 0x0030 },
+  { 0x0900, 0x0533, 0x0030 },
+  { 0x8900, 0x0536, 0x2030 },
+  { 0x0900, 0x0535, 0x0030 },
+  { 0x0900, 0x0537, 0x0030 },
+  { 0x8900, 0x053c, 0x3030 },
+  { 0x8900, 0x053a, 0x2030 },
+  { 0x0900, 0x0539, 0x0030 },
+  { 0x0900, 0x053b, 0x0030 },
+  { 0x8900, 0x053e, 0x2030 },
+  { 0x0900, 0x053d, 0x0030 },
+  { 0x0900, 0x053f, 0x0030 },
+  { 0x8900, 0x0550, 0x5030 },
+  { 0x8900, 0x0548, 0x4030 },
+  { 0x8900, 0x0544, 0x3030 },
+  { 0x8900, 0x0542, 0x2030 },
+  { 0x0900, 0x0541, 0x0030 },
+  { 0x0900, 0x0543, 0x0030 },
+  { 0x8900, 0x0546, 0x2030 },
+  { 0x0900, 0x0545, 0x0030 },
+  { 0x0900, 0x0547, 0x0030 },
+  { 0x8900, 0x054c, 0x3030 },
+  { 0x8900, 0x054a, 0x2030 },
+  { 0x0900, 0x0549, 0x0030 },
+  { 0x0900, 0x054b, 0x0030 },
+  { 0x8900, 0x054e, 0x2030 },
+  { 0x0900, 0x054d, 0x0030 },
+  { 0x0900, 0x054f, 0x0030 },
+  { 0x9500, 0x055a, 0x4000 },
+  { 0x8900, 0x0554, 0x3030 },
+  { 0x8900, 0x0552, 0x2030 },
+  { 0x0900, 0x0551, 0x0030 },
+  { 0x0900, 0x0553, 0x0030 },
+  { 0x8900, 0x0556, 0x2030 },
+  { 0x0900, 0x0555, 0x0030 },
+  { 0x0600, 0x0559, 0x0000 },
+  { 0x9500, 0x055e, 0x3000 },
+  { 0x9500, 0x055c, 0x2000 },
+  { 0x1500, 0x055b, 0x0000 },
+  { 0x1500, 0x055d, 0x0000 },
+  { 0x8500, 0x0561, 0x2fd0 },
+  { 0x1500, 0x055f, 0x0000 },
+  { 0x0500, 0x0562, 0x0fd0 },
+  { 0x9a00, 0x060f, 0x8000 },
+  { 0x8c00, 0x05ab, 0x7000 },
+  { 0x8500, 0x0583, 0x6fd0 },
+  { 0x8500, 0x0573, 0x5fd0 },
+  { 0x8500, 0x056b, 0x4fd0 },
+  { 0x8500, 0x0567, 0x3fd0 },
+  { 0x8500, 0x0565, 0x2fd0 },
+  { 0x0500, 0x0564, 0x0fd0 },
+  { 0x0500, 0x0566, 0x0fd0 },
+  { 0x8500, 0x0569, 0x2fd0 },
+  { 0x0500, 0x0568, 0x0fd0 },
+  { 0x0500, 0x056a, 0x0fd0 },
+  { 0x8500, 0x056f, 0x3fd0 },
+  { 0x8500, 0x056d, 0x2fd0 },
+  { 0x0500, 0x056c, 0x0fd0 },
+  { 0x0500, 0x056e, 0x0fd0 },
+  { 0x8500, 0x0571, 0x2fd0 },
+  { 0x0500, 0x0570, 0x0fd0 },
+  { 0x0500, 0x0572, 0x0fd0 },
+  { 0x8500, 0x057b, 0x4fd0 },
+  { 0x8500, 0x0577, 0x3fd0 },
+  { 0x8500, 0x0575, 0x2fd0 },
+  { 0x0500, 0x0574, 0x0fd0 },
+  { 0x0500, 0x0576, 0x0fd0 },
+  { 0x8500, 0x0579, 0x2fd0 },
+  { 0x0500, 0x0578, 0x0fd0 },
+  { 0x0500, 0x057a, 0x0fd0 },
+  { 0x8500, 0x057f, 0x3fd0 },
+  { 0x8500, 0x057d, 0x2fd0 },
+  { 0x0500, 0x057c, 0x0fd0 },
+  { 0x0500, 0x057e, 0x0fd0 },
+  { 0x8500, 0x0581, 0x2fd0 },
+  { 0x0500, 0x0580, 0x0fd0 },
+  { 0x0500, 0x0582, 0x0fd0 },
+  { 0x8c00, 0x059a, 0x5000 },
+  { 0x8c00, 0x0592, 0x4000 },
+  { 0x8500, 0x0587, 0x3000 },
+  { 0x8500, 0x0585, 0x2fd0 },
+  { 0x0500, 0x0584, 0x0fd0 },
+  { 0x0500, 0x0586, 0x0fd0 },
+  { 0x9100, 0x058a, 0x2000 },
+  { 0x1500, 0x0589, 0x0000 },
+  { 0x0c00, 0x0591, 0x0000 },
+  { 0x8c00, 0x0596, 0x3000 },
+  { 0x8c00, 0x0594, 0x2000 },
+  { 0x0c00, 0x0593, 0x0000 },
+  { 0x0c00, 0x0595, 0x0000 },
+  { 0x8c00, 0x0598, 0x2000 },
+  { 0x0c00, 0x0597, 0x0000 },
+  { 0x0c00, 0x0599, 0x0000 },
+  { 0x8c00, 0x05a3, 0x4000 },
+  { 0x8c00, 0x059e, 0x3000 },
+  { 0x8c00, 0x059c, 0x2000 },
+  { 0x0c00, 0x059b, 0x0000 },
+  { 0x0c00, 0x059d, 0x0000 },
+  { 0x8c00, 0x05a0, 0x2000 },
+  { 0x0c00, 0x059f, 0x0000 },
+  { 0x0c00, 0x05a1, 0x0000 },
+  { 0x8c00, 0x05a7, 0x3000 },
+  { 0x8c00, 0x05a5, 0x2000 },
+  { 0x0c00, 0x05a4, 0x0000 },
+  { 0x0c00, 0x05a6, 0x0000 },
+  { 0x8c00, 0x05a9, 0x2000 },
+  { 0x0c00, 0x05a8, 0x0000 },
+  { 0x0c00, 0x05aa, 0x0000 },
+  { 0x8700, 0x05d7, 0x6000 },
+  { 0x8c00, 0x05bc, 0x5000 },
+  { 0x8c00, 0x05b3, 0x4000 },
+  { 0x8c00, 0x05af, 0x3000 },
+  { 0x8c00, 0x05ad, 0x2000 },
+  { 0x0c00, 0x05ac, 0x0000 },
+  { 0x0c00, 0x05ae, 0x0000 },
+  { 0x8c00, 0x05b1, 0x2000 },
+  { 0x0c00, 0x05b0, 0x0000 },
+  { 0x0c00, 0x05b2, 0x0000 },
+  { 0x8c00, 0x05b7, 0x3000 },
+  { 0x8c00, 0x05b5, 0x2000 },
+  { 0x0c00, 0x05b4, 0x0000 },
+  { 0x0c00, 0x05b6, 0x0000 },
+  { 0x8c00, 0x05b9, 0x2000 },
+  { 0x0c00, 0x05b8, 0x0000 },
+  { 0x0c00, 0x05bb, 0x0000 },
+  { 0x8c00, 0x05c4, 0x4000 },
+  { 0x9500, 0x05c0, 0x3000 },
+  { 0x9500, 0x05be, 0x2000 },
+  { 0x0c00, 0x05bd, 0x0000 },
+  { 0x0c00, 0x05bf, 0x0000 },
+  { 0x8c00, 0x05c2, 0x2000 },
+  { 0x0c00, 0x05c1, 0x0000 },
+  { 0x1500, 0x05c3, 0x0000 },
+  { 0x8700, 0x05d3, 0x3000 },
+  { 0x8700, 0x05d1, 0x2000 },
+  { 0x0700, 0x05d0, 0x0000 },
+  { 0x0700, 0x05d2, 0x0000 },
+  { 0x8700, 0x05d5, 0x2000 },
+  { 0x0700, 0x05d4, 0x0000 },
+  { 0x0700, 0x05d6, 0x0000 },
+  { 0x8700, 0x05e7, 0x5000 },
+  { 0x8700, 0x05df, 0x4000 },
+  { 0x8700, 0x05db, 0x3000 },
+  { 0x8700, 0x05d9, 0x2000 },
+  { 0x0700, 0x05d8, 0x0000 },
+  { 0x0700, 0x05da, 0x0000 },
+  { 0x8700, 0x05dd, 0x2000 },
+  { 0x0700, 0x05dc, 0x0000 },
+  { 0x0700, 0x05de, 0x0000 },
+  { 0x8700, 0x05e3, 0x3000 },
+  { 0x8700, 0x05e1, 0x2000 },
+  { 0x0700, 0x05e0, 0x0000 },
+  { 0x0700, 0x05e2, 0x0000 },
+  { 0x8700, 0x05e5, 0x2000 },
+  { 0x0700, 0x05e4, 0x0000 },
+  { 0x0700, 0x05e6, 0x0000 },
+  { 0x9500, 0x05f4, 0x4000 },
+  { 0x8700, 0x05f0, 0x3000 },
+  { 0x8700, 0x05e9, 0x2000 },
+  { 0x0700, 0x05e8, 0x0000 },
+  { 0x0700, 0x05ea, 0x0000 },
+  { 0x8700, 0x05f2, 0x2000 },
+  { 0x0700, 0x05f1, 0x0000 },
+  { 0x1500, 0x05f3, 0x0000 },
+  { 0x8100, 0x0603, 0x3000 },
+  { 0x8100, 0x0601, 0x2000 },
+  { 0x0100, 0x0600, 0x0000 },
+  { 0x0100, 0x0602, 0x0000 },
+  { 0x9500, 0x060d, 0x2000 },
+  { 0x1500, 0x060c, 0x0000 },
+  { 0x1a00, 0x060e, 0x0000 },
+  { 0x8d00, 0x0664, 0x7000 },
+  { 0x8700, 0x0638, 0x6000 },
+  { 0x8700, 0x0628, 0x5000 },
+  { 0x9500, 0x061f, 0x4000 },
+  { 0x8c00, 0x0613, 0x3000 },
+  { 0x8c00, 0x0611, 0x2000 },
+  { 0x0c00, 0x0610, 0x0000 },
+  { 0x0c00, 0x0612, 0x0000 },
+  { 0x8c00, 0x0615, 0x2000 },
+  { 0x0c00, 0x0614, 0x0000 },
+  { 0x1500, 0x061b, 0x0000 },
+  { 0x8700, 0x0624, 0x3000 },
+  { 0x8700, 0x0622, 0x2000 },
+  { 0x0700, 0x0621, 0x0000 },
+  { 0x0700, 0x0623, 0x0000 },
+  { 0x8700, 0x0626, 0x2000 },
+  { 0x0700, 0x0625, 0x0000 },
+  { 0x0700, 0x0627, 0x0000 },
+  { 0x8700, 0x0630, 0x4000 },
+  { 0x8700, 0x062c, 0x3000 },
+  { 0x8700, 0x062a, 0x2000 },
+  { 0x0700, 0x0629, 0x0000 },
+  { 0x0700, 0x062b, 0x0000 },
+  { 0x8700, 0x062e, 0x2000 },
+  { 0x0700, 0x062d, 0x0000 },
+  { 0x0700, 0x062f, 0x0000 },
+  { 0x8700, 0x0634, 0x3000 },
+  { 0x8700, 0x0632, 0x2000 },
+  { 0x0700, 0x0631, 0x0000 },
+  { 0x0700, 0x0633, 0x0000 },
+  { 0x8700, 0x0636, 0x2000 },
+  { 0x0700, 0x0635, 0x0000 },
+  { 0x0700, 0x0637, 0x0000 },
+  { 0x8c00, 0x064d, 0x5000 },
+  { 0x8700, 0x0645, 0x4000 },
+  { 0x8700, 0x0641, 0x3000 },
+  { 0x8700, 0x063a, 0x2000 },
+  { 0x0700, 0x0639, 0x0000 },
+  { 0x0600, 0x0640, 0x0000 },
+  { 0x8700, 0x0643, 0x2000 },
+  { 0x0700, 0x0642, 0x0000 },
+  { 0x0700, 0x0644, 0x0000 },
+  { 0x8700, 0x0649, 0x3000 },
+  { 0x8700, 0x0647, 0x2000 },
+  { 0x0700, 0x0646, 0x0000 },
+  { 0x0700, 0x0648, 0x0000 },
+  { 0x8c00, 0x064b, 0x2000 },
+  { 0x0700, 0x064a, 0x0000 },
+  { 0x0c00, 0x064c, 0x0000 },
+  { 0x8c00, 0x0655, 0x4000 },
+  { 0x8c00, 0x0651, 0x3000 },
+  { 0x8c00, 0x064f, 0x2000 },
+  { 0x0c00, 0x064e, 0x0000 },
+  { 0x0c00, 0x0650, 0x0000 },
+  { 0x8c00, 0x0653, 0x2000 },
+  { 0x0c00, 0x0652, 0x0000 },
+  { 0x0c00, 0x0654, 0x0000 },
+  { 0x8d00, 0x0660, 0x3000 },
+  { 0x8c00, 0x0657, 0x2000 },
+  { 0x0c00, 0x0656, 0x0000 },
+  { 0x0c00, 0x0658, 0x0000 },
+  { 0x8d00, 0x0662, 0x2000 },
+  { 0x0d00, 0x0661, 0x0000 },
+  { 0x0d00, 0x0663, 0x0000 },
+  { 0x8700, 0x0684, 0x6000 },
+  { 0x8700, 0x0674, 0x5000 },
+  { 0x9500, 0x066c, 0x4000 },
+  { 0x8d00, 0x0668, 0x3000 },
+  { 0x8d00, 0x0666, 0x2000 },
+  { 0x0d00, 0x0665, 0x0000 },
+  { 0x0d00, 0x0667, 0x0000 },
+  { 0x9500, 0x066a, 0x2000 },
+  { 0x0d00, 0x0669, 0x0000 },
+  { 0x1500, 0x066b, 0x0000 },
+  { 0x8c00, 0x0670, 0x3000 },
+  { 0x8700, 0x066e, 0x2000 },
+  { 0x1500, 0x066d, 0x0000 },
+  { 0x0700, 0x066f, 0x0000 },
+  { 0x8700, 0x0672, 0x2000 },
+  { 0x0700, 0x0671, 0x0000 },
+  { 0x0700, 0x0673, 0x0000 },
+  { 0x8700, 0x067c, 0x4000 },
+  { 0x8700, 0x0678, 0x3000 },
+  { 0x8700, 0x0676, 0x2000 },
+  { 0x0700, 0x0675, 0x0000 },
+  { 0x0700, 0x0677, 0x0000 },
+  { 0x8700, 0x067a, 0x2000 },
+  { 0x0700, 0x0679, 0x0000 },
+  { 0x0700, 0x067b, 0x0000 },
+  { 0x8700, 0x0680, 0x3000 },
+  { 0x8700, 0x067e, 0x2000 },
+  { 0x0700, 0x067d, 0x0000 },
+  { 0x0700, 0x067f, 0x0000 },
+  { 0x8700, 0x0682, 0x2000 },
+  { 0x0700, 0x0681, 0x0000 },
+  { 0x0700, 0x0683, 0x0000 },
+  { 0x8700, 0x0694, 0x5000 },
+  { 0x8700, 0x068c, 0x4000 },
+  { 0x8700, 0x0688, 0x3000 },
+  { 0x8700, 0x0686, 0x2000 },
+  { 0x0700, 0x0685, 0x0000 },
+  { 0x0700, 0x0687, 0x0000 },
+  { 0x8700, 0x068a, 0x2000 },
+  { 0x0700, 0x0689, 0x0000 },
+  { 0x0700, 0x068b, 0x0000 },
+  { 0x8700, 0x0690, 0x3000 },
+  { 0x8700, 0x068e, 0x2000 },
+  { 0x0700, 0x068d, 0x0000 },
+  { 0x0700, 0x068f, 0x0000 },
+  { 0x8700, 0x0692, 0x2000 },
+  { 0x0700, 0x0691, 0x0000 },
+  { 0x0700, 0x0693, 0x0000 },
+  { 0x8700, 0x069c, 0x4000 },
+  { 0x8700, 0x0698, 0x3000 },
+  { 0x8700, 0x0696, 0x2000 },
+  { 0x0700, 0x0695, 0x0000 },
+  { 0x0700, 0x0697, 0x0000 },
+  { 0x8700, 0x069a, 0x2000 },
+  { 0x0700, 0x0699, 0x0000 },
+  { 0x0700, 0x069b, 0x0000 },
+  { 0x8700, 0x06a0, 0x3000 },
+  { 0x8700, 0x069e, 0x2000 },
+  { 0x0700, 0x069d, 0x0000 },
+  { 0x0700, 0x069f, 0x0000 },
+  { 0x8700, 0x06a2, 0x2000 },
+  { 0x0700, 0x06a1, 0x0000 },
+  { 0x0700, 0x06a3, 0x0000 },
+  { 0x8700, 0x0926, 0x9000 },
+  { 0x8700, 0x0725, 0x8000 },
+  { 0x8c00, 0x06e4, 0x7000 },
+  { 0x8700, 0x06c4, 0x6000 },
+  { 0x8700, 0x06b4, 0x5000 },
+  { 0x8700, 0x06ac, 0x4000 },
+  { 0x8700, 0x06a8, 0x3000 },
+  { 0x8700, 0x06a6, 0x2000 },
+  { 0x0700, 0x06a5, 0x0000 },
+  { 0x0700, 0x06a7, 0x0000 },
+  { 0x8700, 0x06aa, 0x2000 },
+  { 0x0700, 0x06a9, 0x0000 },
+  { 0x0700, 0x06ab, 0x0000 },
+  { 0x8700, 0x06b0, 0x3000 },
+  { 0x8700, 0x06ae, 0x2000 },
+  { 0x0700, 0x06ad, 0x0000 },
+  { 0x0700, 0x06af, 0x0000 },
+  { 0x8700, 0x06b2, 0x2000 },
+  { 0x0700, 0x06b1, 0x0000 },
+  { 0x0700, 0x06b3, 0x0000 },
+  { 0x8700, 0x06bc, 0x4000 },
+  { 0x8700, 0x06b8, 0x3000 },
+  { 0x8700, 0x06b6, 0x2000 },
+  { 0x0700, 0x06b5, 0x0000 },
+  { 0x0700, 0x06b7, 0x0000 },
+  { 0x8700, 0x06ba, 0x2000 },
+  { 0x0700, 0x06b9, 0x0000 },
+  { 0x0700, 0x06bb, 0x0000 },
+  { 0x8700, 0x06c0, 0x3000 },
+  { 0x8700, 0x06be, 0x2000 },
+  { 0x0700, 0x06bd, 0x0000 },
+  { 0x0700, 0x06bf, 0x0000 },
+  { 0x8700, 0x06c2, 0x2000 },
+  { 0x0700, 0x06c1, 0x0000 },
+  { 0x0700, 0x06c3, 0x0000 },
+  { 0x9500, 0x06d4, 0x5000 },
+  { 0x8700, 0x06cc, 0x4000 },
+  { 0x8700, 0x06c8, 0x3000 },
+  { 0x8700, 0x06c6, 0x2000 },
+  { 0x0700, 0x06c5, 0x0000 },
+  { 0x0700, 0x06c7, 0x0000 },
+  { 0x8700, 0x06ca, 0x2000 },
+  { 0x0700, 0x06c9, 0x0000 },
+  { 0x0700, 0x06cb, 0x0000 },
+  { 0x8700, 0x06d0, 0x3000 },
+  { 0x8700, 0x06ce, 0x2000 },
+  { 0x0700, 0x06cd, 0x0000 },
+  { 0x0700, 0x06cf, 0x0000 },
+  { 0x8700, 0x06d2, 0x2000 },
+  { 0x0700, 0x06d1, 0x0000 },
+  { 0x0700, 0x06d3, 0x0000 },
+  { 0x8c00, 0x06dc, 0x4000 },
+  { 0x8c00, 0x06d8, 0x3000 },
+  { 0x8c00, 0x06d6, 0x2000 },
+  { 0x0700, 0x06d5, 0x0000 },
+  { 0x0c00, 0x06d7, 0x0000 },
+  { 0x8c00, 0x06da, 0x2000 },
+  { 0x0c00, 0x06d9, 0x0000 },
+  { 0x0c00, 0x06db, 0x0000 },
+  { 0x8c00, 0x06e0, 0x3000 },
+  { 0x8b00, 0x06de, 0x2000 },
+  { 0x0100, 0x06dd, 0x0000 },
+  { 0x0c00, 0x06df, 0x0000 },
+  { 0x8c00, 0x06e2, 0x2000 },
+  { 0x0c00, 0x06e1, 0x0000 },
+  { 0x0c00, 0x06e3, 0x0000 },
+  { 0x9500, 0x0704, 0x6000 },
+  { 0x8d00, 0x06f4, 0x5000 },
+  { 0x8c00, 0x06ec, 0x4000 },
+  { 0x8c00, 0x06e8, 0x3000 },
+  { 0x8600, 0x06e6, 0x2000 },
+  { 0x0600, 0x06e5, 0x0000 },
+  { 0x0c00, 0x06e7, 0x0000 },
+  { 0x8c00, 0x06ea, 0x2000 },
+  { 0x1a00, 0x06e9, 0x0000 },
+  { 0x0c00, 0x06eb, 0x0000 },
+  { 0x8d00, 0x06f0, 0x3000 },
+  { 0x8700, 0x06ee, 0x2000 },
+  { 0x0c00, 0x06ed, 0x0000 },
+  { 0x0700, 0x06ef, 0x0000 },
+  { 0x8d00, 0x06f2, 0x2000 },
+  { 0x0d00, 0x06f1, 0x0000 },
+  { 0x0d00, 0x06f3, 0x0000 },
+  { 0x8700, 0x06fc, 0x4000 },
+  { 0x8d00, 0x06f8, 0x3000 },
+  { 0x8d00, 0x06f6, 0x2000 },
+  { 0x0d00, 0x06f5, 0x0000 },
+  { 0x0d00, 0x06f7, 0x0000 },
+  { 0x8700, 0x06fa, 0x2000 },
+  { 0x0d00, 0x06f9, 0x0000 },
+  { 0x0700, 0x06fb, 0x0000 },
+  { 0x9500, 0x0700, 0x3000 },
+  { 0x9a00, 0x06fe, 0x2000 },
+  { 0x1a00, 0x06fd, 0x0000 },
+  { 0x0700, 0x06ff, 0x0000 },
+  { 0x9500, 0x0702, 0x2000 },
+  { 0x1500, 0x0701, 0x0000 },
+  { 0x1500, 0x0703, 0x0000 },
+  { 0x8700, 0x0715, 0x5000 },
+  { 0x9500, 0x070c, 0x4000 },
+  { 0x9500, 0x0708, 0x3000 },
+  { 0x9500, 0x0706, 0x2000 },
+  { 0x1500, 0x0705, 0x0000 },
+  { 0x1500, 0x0707, 0x0000 },
+  { 0x9500, 0x070a, 0x2000 },
+  { 0x1500, 0x0709, 0x0000 },
+  { 0x1500, 0x070b, 0x0000 },
+  { 0x8c00, 0x0711, 0x3000 },
+  { 0x8100, 0x070f, 0x2000 },
+  { 0x1500, 0x070d, 0x0000 },
+  { 0x0700, 0x0710, 0x0000 },
+  { 0x8700, 0x0713, 0x2000 },
+  { 0x0700, 0x0712, 0x0000 },
+  { 0x0700, 0x0714, 0x0000 },
+  { 0x8700, 0x071d, 0x4000 },
+  { 0x8700, 0x0719, 0x3000 },
+  { 0x8700, 0x0717, 0x2000 },
+  { 0x0700, 0x0716, 0x0000 },
+  { 0x0700, 0x0718, 0x0000 },
+  { 0x8700, 0x071b, 0x2000 },
+  { 0x0700, 0x071a, 0x0000 },
+  { 0x0700, 0x071c, 0x0000 },
+  { 0x8700, 0x0721, 0x3000 },
+  { 0x8700, 0x071f, 0x2000 },
+  { 0x0700, 0x071e, 0x0000 },
+  { 0x0700, 0x0720, 0x0000 },
+  { 0x8700, 0x0723, 0x2000 },
+  { 0x0700, 0x0722, 0x0000 },
+  { 0x0700, 0x0724, 0x0000 },
+  { 0x8700, 0x0797, 0x7000 },
+  { 0x8c00, 0x0745, 0x6000 },
+  { 0x8c00, 0x0735, 0x5000 },
+  { 0x8700, 0x072d, 0x4000 },
+  { 0x8700, 0x0729, 0x3000 },
+  { 0x8700, 0x0727, 0x2000 },
+  { 0x0700, 0x0726, 0x0000 },
+  { 0x0700, 0x0728, 0x0000 },
+  { 0x8700, 0x072b, 0x2000 },
+  { 0x0700, 0x072a, 0x0000 },
+  { 0x0700, 0x072c, 0x0000 },
+  { 0x8c00, 0x0731, 0x3000 },
+  { 0x8700, 0x072f, 0x2000 },
+  { 0x0700, 0x072e, 0x0000 },
+  { 0x0c00, 0x0730, 0x0000 },
+  { 0x8c00, 0x0733, 0x2000 },
+  { 0x0c00, 0x0732, 0x0000 },
+  { 0x0c00, 0x0734, 0x0000 },
+  { 0x8c00, 0x073d, 0x4000 },
+  { 0x8c00, 0x0739, 0x3000 },
+  { 0x8c00, 0x0737, 0x2000 },
+  { 0x0c00, 0x0736, 0x0000 },
+  { 0x0c00, 0x0738, 0x0000 },
+  { 0x8c00, 0x073b, 0x2000 },
+  { 0x0c00, 0x073a, 0x0000 },
+  { 0x0c00, 0x073c, 0x0000 },
+  { 0x8c00, 0x0741, 0x3000 },
+  { 0x8c00, 0x073f, 0x2000 },
+  { 0x0c00, 0x073e, 0x0000 },
+  { 0x0c00, 0x0740, 0x0000 },
+  { 0x8c00, 0x0743, 0x2000 },
+  { 0x0c00, 0x0742, 0x0000 },
+  { 0x0c00, 0x0744, 0x0000 },
+  { 0x8700, 0x0787, 0x5000 },
+  { 0x8700, 0x074f, 0x4000 },
+  { 0x8c00, 0x0749, 0x3000 },
+  { 0x8c00, 0x0747, 0x2000 },
+  { 0x0c00, 0x0746, 0x0000 },
+  { 0x0c00, 0x0748, 0x0000 },
+  { 0x8700, 0x074d, 0x2000 },
+  { 0x0c00, 0x074a, 0x0000 },
+  { 0x0700, 0x074e, 0x0000 },
+  { 0x8700, 0x0783, 0x3000 },
+  { 0x8700, 0x0781, 0x2000 },
+  { 0x0700, 0x0780, 0x0000 },
+  { 0x0700, 0x0782, 0x0000 },
+  { 0x8700, 0x0785, 0x2000 },
+  { 0x0700, 0x0784, 0x0000 },
+  { 0x0700, 0x0786, 0x0000 },
+  { 0x8700, 0x078f, 0x4000 },
+  { 0x8700, 0x078b, 0x3000 },
+  { 0x8700, 0x0789, 0x2000 },
+  { 0x0700, 0x0788, 0x0000 },
+  { 0x0700, 0x078a, 0x0000 },
+  { 0x8700, 0x078d, 0x2000 },
+  { 0x0700, 0x078c, 0x0000 },
+  { 0x0700, 0x078e, 0x0000 },
+  { 0x8700, 0x0793, 0x3000 },
+  { 0x8700, 0x0791, 0x2000 },
+  { 0x0700, 0x0790, 0x0000 },
+  { 0x0700, 0x0792, 0x0000 },
+  { 0x8700, 0x0795, 0x2000 },
+  { 0x0700, 0x0794, 0x0000 },
+  { 0x0700, 0x0796, 0x0000 },
+  { 0x8700, 0x0906, 0x6000 },
+  { 0x8c00, 0x07a7, 0x5000 },
+  { 0x8700, 0x079f, 0x4000 },
+  { 0x8700, 0x079b, 0x3000 },
+  { 0x8700, 0x0799, 0x2000 },
+  { 0x0700, 0x0798, 0x0000 },
+  { 0x0700, 0x079a, 0x0000 },
+  { 0x8700, 0x079d, 0x2000 },
+  { 0x0700, 0x079c, 0x0000 },
+  { 0x0700, 0x079e, 0x0000 },
+  { 0x8700, 0x07a3, 0x3000 },
+  { 0x8700, 0x07a1, 0x2000 },
+  { 0x0700, 0x07a0, 0x0000 },
+  { 0x0700, 0x07a2, 0x0000 },
+  { 0x8700, 0x07a5, 0x2000 },
+  { 0x0700, 0x07a4, 0x0000 },
+  { 0x0c00, 0x07a6, 0x0000 },
+  { 0x8c00, 0x07af, 0x4000 },
+  { 0x8c00, 0x07ab, 0x3000 },
+  { 0x8c00, 0x07a9, 0x2000 },
+  { 0x0c00, 0x07a8, 0x0000 },
+  { 0x0c00, 0x07aa, 0x0000 },
+  { 0x8c00, 0x07ad, 0x2000 },
+  { 0x0c00, 0x07ac, 0x0000 },
+  { 0x0c00, 0x07ae, 0x0000 },
+  { 0x8c00, 0x0902, 0x3000 },
+  { 0x8700, 0x07b1, 0x2000 },
+  { 0x0c00, 0x07b0, 0x0000 },
+  { 0x0c00, 0x0901, 0x0000 },
+  { 0x8700, 0x0904, 0x2000 },
+  { 0x0a00, 0x0903, 0x0000 },
+  { 0x0700, 0x0905, 0x0000 },
+  { 0x8700, 0x0916, 0x5000 },
+  { 0x8700, 0x090e, 0x4000 },
+  { 0x8700, 0x090a, 0x3000 },
+  { 0x8700, 0x0908, 0x2000 },
+  { 0x0700, 0x0907, 0x0000 },
+  { 0x0700, 0x0909, 0x0000 },
+  { 0x8700, 0x090c, 0x2000 },
+  { 0x0700, 0x090b, 0x0000 },
+  { 0x0700, 0x090d, 0x0000 },
+  { 0x8700, 0x0912, 0x3000 },
+  { 0x8700, 0x0910, 0x2000 },
+  { 0x0700, 0x090f, 0x0000 },
+  { 0x0700, 0x0911, 0x0000 },
+  { 0x8700, 0x0914, 0x2000 },
+  { 0x0700, 0x0913, 0x0000 },
+  { 0x0700, 0x0915, 0x0000 },
+  { 0x8700, 0x091e, 0x4000 },
+  { 0x8700, 0x091a, 0x3000 },
+  { 0x8700, 0x0918, 0x2000 },
+  { 0x0700, 0x0917, 0x0000 },
+  { 0x0700, 0x0919, 0x0000 },
+  { 0x8700, 0x091c, 0x2000 },
+  { 0x0700, 0x091b, 0x0000 },
+  { 0x0700, 0x091d, 0x0000 },
+  { 0x8700, 0x0922, 0x3000 },
+  { 0x8700, 0x0920, 0x2000 },
+  { 0x0700, 0x091f, 0x0000 },
+  { 0x0700, 0x0921, 0x0000 },
+  { 0x8700, 0x0924, 0x2000 },
+  { 0x0700, 0x0923, 0x0000 },
+  { 0x0700, 0x0925, 0x0000 },
+  { 0x8c00, 0x09cd, 0x8000 },
+  { 0x8d00, 0x096d, 0x7000 },
+  { 0x8c00, 0x0948, 0x6000 },
+  { 0x8700, 0x0936, 0x5000 },
+  { 0x8700, 0x092e, 0x4000 },
+  { 0x8700, 0x092a, 0x3000 },
+  { 0x8700, 0x0928, 0x2000 },
+  { 0x0700, 0x0927, 0x0000 },
+  { 0x0700, 0x0929, 0x0000 },
+  { 0x8700, 0x092c, 0x2000 },
+  { 0x0700, 0x092b, 0x0000 },
+  { 0x0700, 0x092d, 0x0000 },
+  { 0x8700, 0x0932, 0x3000 },
+  { 0x8700, 0x0930, 0x2000 },
+  { 0x0700, 0x092f, 0x0000 },
+  { 0x0700, 0x0931, 0x0000 },
+  { 0x8700, 0x0934, 0x2000 },
+  { 0x0700, 0x0933, 0x0000 },
+  { 0x0700, 0x0935, 0x0000 },
+  { 0x8a00, 0x0940, 0x4000 },
+  { 0x8c00, 0x093c, 0x3000 },
+  { 0x8700, 0x0938, 0x2000 },
+  { 0x0700, 0x0937, 0x0000 },
+  { 0x0700, 0x0939, 0x0000 },
+  { 0x8a00, 0x093e, 0x2000 },
+  { 0x0700, 0x093d, 0x0000 },
+  { 0x0a00, 0x093f, 0x0000 },
+  { 0x8c00, 0x0944, 0x3000 },
+  { 0x8c00, 0x0942, 0x2000 },
+  { 0x0c00, 0x0941, 0x0000 },
+  { 0x0c00, 0x0943, 0x0000 },
+  { 0x8c00, 0x0946, 0x2000 },
+  { 0x0c00, 0x0945, 0x0000 },
+  { 0x0c00, 0x0947, 0x0000 },
+  { 0x8700, 0x095d, 0x5000 },
+  { 0x8c00, 0x0952, 0x4000 },
+  { 0x8a00, 0x094c, 0x3000 },
+  { 0x8a00, 0x094a, 0x2000 },
+  { 0x0a00, 0x0949, 0x0000 },
+  { 0x0a00, 0x094b, 0x0000 },
+  { 0x8700, 0x0950, 0x2000 },
+  { 0x0c00, 0x094d, 0x0000 },
+  { 0x0c00, 0x0951, 0x0000 },
+  { 0x8700, 0x0959, 0x3000 },
+  { 0x8c00, 0x0954, 0x2000 },
+  { 0x0c00, 0x0953, 0x0000 },
+  { 0x0700, 0x0958, 0x0000 },
+  { 0x8700, 0x095b, 0x2000 },
+  { 0x0700, 0x095a, 0x0000 },
+  { 0x0700, 0x095c, 0x0000 },
+  { 0x9500, 0x0965, 0x4000 },
+  { 0x8700, 0x0961, 0x3000 },
+  { 0x8700, 0x095f, 0x2000 },
+  { 0x0700, 0x095e, 0x0000 },
+  { 0x0700, 0x0960, 0x0000 },
+  { 0x8c00, 0x0963, 0x2000 },
+  { 0x0c00, 0x0962, 0x0000 },
+  { 0x1500, 0x0964, 0x0000 },
+  { 0x8d00, 0x0969, 0x3000 },
+  { 0x8d00, 0x0967, 0x2000 },
+  { 0x0d00, 0x0966, 0x0000 },
+  { 0x0d00, 0x0968, 0x0000 },
+  { 0x8d00, 0x096b, 0x2000 },
+  { 0x0d00, 0x096a, 0x0000 },
+  { 0x0d00, 0x096c, 0x0000 },
+  { 0x8700, 0x09a2, 0x6000 },
+  { 0x8700, 0x0990, 0x5000 },
+  { 0x8700, 0x0986, 0x4000 },
+  { 0x8c00, 0x0981, 0x3000 },
+  { 0x8d00, 0x096f, 0x2000 },
+  { 0x0d00, 0x096e, 0x0000 },
+  { 0x1500, 0x0970, 0x0000 },
+  { 0x8a00, 0x0983, 0x2000 },
+  { 0x0a00, 0x0982, 0x0000 },
+  { 0x0700, 0x0985, 0x0000 },
+  { 0x8700, 0x098a, 0x3000 },
+  { 0x8700, 0x0988, 0x2000 },
+  { 0x0700, 0x0987, 0x0000 },
+  { 0x0700, 0x0989, 0x0000 },
+  { 0x8700, 0x098c, 0x2000 },
+  { 0x0700, 0x098b, 0x0000 },
+  { 0x0700, 0x098f, 0x0000 },
+  { 0x8700, 0x099a, 0x4000 },
+  { 0x8700, 0x0996, 0x3000 },
+  { 0x8700, 0x0994, 0x2000 },
+  { 0x0700, 0x0993, 0x0000 },
+  { 0x0700, 0x0995, 0x0000 },
+  { 0x8700, 0x0998, 0x2000 },
+  { 0x0700, 0x0997, 0x0000 },
+  { 0x0700, 0x0999, 0x0000 },
+  { 0x8700, 0x099e, 0x3000 },
+  { 0x8700, 0x099c, 0x2000 },
+  { 0x0700, 0x099b, 0x0000 },
+  { 0x0700, 0x099d, 0x0000 },
+  { 0x8700, 0x09a0, 0x2000 },
+  { 0x0700, 0x099f, 0x0000 },
+  { 0x0700, 0x09a1, 0x0000 },
+  { 0x8700, 0x09b7, 0x5000 },
+  { 0x8700, 0x09ab, 0x4000 },
+  { 0x8700, 0x09a6, 0x3000 },
+  { 0x8700, 0x09a4, 0x2000 },
+  { 0x0700, 0x09a3, 0x0000 },
+  { 0x0700, 0x09a5, 0x0000 },
+  { 0x8700, 0x09a8, 0x2000 },
+  { 0x0700, 0x09a7, 0x0000 },
+  { 0x0700, 0x09aa, 0x0000 },
+  { 0x8700, 0x09af, 0x3000 },
+  { 0x8700, 0x09ad, 0x2000 },
+  { 0x0700, 0x09ac, 0x0000 },
+  { 0x0700, 0x09ae, 0x0000 },
+  { 0x8700, 0x09b2, 0x2000 },
+  { 0x0700, 0x09b0, 0x0000 },
+  { 0x0700, 0x09b6, 0x0000 },
+  { 0x8c00, 0x09c1, 0x4000 },
+  { 0x8700, 0x09bd, 0x3000 },
+  { 0x8700, 0x09b9, 0x2000 },
+  { 0x0700, 0x09b8, 0x0000 },
+  { 0x0c00, 0x09bc, 0x0000 },
+  { 0x8a00, 0x09bf, 0x2000 },
+  { 0x0a00, 0x09be, 0x0000 },
+  { 0x0a00, 0x09c0, 0x0000 },
+  { 0x8a00, 0x09c7, 0x3000 },
+  { 0x8c00, 0x09c3, 0x2000 },
+  { 0x0c00, 0x09c2, 0x0000 },
+  { 0x0c00, 0x09c4, 0x0000 },
+  { 0x8a00, 0x09cb, 0x2000 },
+  { 0x0a00, 0x09c8, 0x0000 },
+  { 0x0a00, 0x09cc, 0x0000 },
+  { 0x8700, 0x0a2b, 0x7000 },
+  { 0x8a00, 0x0a03, 0x6000 },
+  { 0x8d00, 0x09ed, 0x5000 },
+  { 0x8c00, 0x09e3, 0x4000 },
+  { 0x8700, 0x09df, 0x3000 },
+  { 0x8700, 0x09dc, 0x2000 },
+  { 0x0a00, 0x09d7, 0x0000 },
+  { 0x0700, 0x09dd, 0x0000 },
+  { 0x8700, 0x09e1, 0x2000 },
+  { 0x0700, 0x09e0, 0x0000 },
+  { 0x0c00, 0x09e2, 0x0000 },
+  { 0x8d00, 0x09e9, 0x3000 },
+  { 0x8d00, 0x09e7, 0x2000 },
+  { 0x0d00, 0x09e6, 0x0000 },
+  { 0x0d00, 0x09e8, 0x0000 },
+  { 0x8d00, 0x09eb, 0x2000 },
+  { 0x0d00, 0x09ea, 0x0000 },
+  { 0x0d00, 0x09ec, 0x0000 },
+  { 0x8f00, 0x09f5, 0x4000 },
+  { 0x8700, 0x09f1, 0x3000 },
+  { 0x8d00, 0x09ef, 0x2000 },
+  { 0x0d00, 0x09ee, 0x0000 },
+  { 0x0700, 0x09f0, 0x0000 },
+  { 0x9700, 0x09f3, 0x2000 },
+  { 0x1700, 0x09f2, 0x0000 },
+  { 0x0f00, 0x09f4, 0x0000 },
+  { 0x8f00, 0x09f9, 0x3000 },
+  { 0x8f00, 0x09f7, 0x2000 },
+  { 0x0f00, 0x09f6, 0x0000 },
+  { 0x0f00, 0x09f8, 0x0000 },
+  { 0x8c00, 0x0a01, 0x2000 },
+  { 0x1a00, 0x09fa, 0x0000 },
+  { 0x0c00, 0x0a02, 0x0000 },
+  { 0x8700, 0x0a1a, 0x5000 },
+  { 0x8700, 0x0a10, 0x4000 },
+  { 0x8700, 0x0a08, 0x3000 },
+  { 0x8700, 0x0a06, 0x2000 },
+  { 0x0700, 0x0a05, 0x0000 },
+  { 0x0700, 0x0a07, 0x0000 },
+  { 0x8700, 0x0a0a, 0x2000 },
+  { 0x0700, 0x0a09, 0x0000 },
+  { 0x0700, 0x0a0f, 0x0000 },
+  { 0x8700, 0x0a16, 0x3000 },
+  { 0x8700, 0x0a14, 0x2000 },
+  { 0x0700, 0x0a13, 0x0000 },
+  { 0x0700, 0x0a15, 0x0000 },
+  { 0x8700, 0x0a18, 0x2000 },
+  { 0x0700, 0x0a17, 0x0000 },
+  { 0x0700, 0x0a19, 0x0000 },
+  { 0x8700, 0x0a22, 0x4000 },
+  { 0x8700, 0x0a1e, 0x3000 },
+  { 0x8700, 0x0a1c, 0x2000 },
+  { 0x0700, 0x0a1b, 0x0000 },
+  { 0x0700, 0x0a1d, 0x0000 },
+  { 0x8700, 0x0a20, 0x2000 },
+  { 0x0700, 0x0a1f, 0x0000 },
+  { 0x0700, 0x0a21, 0x0000 },
+  { 0x8700, 0x0a26, 0x3000 },
+  { 0x8700, 0x0a24, 0x2000 },
+  { 0x0700, 0x0a23, 0x0000 },
+  { 0x0700, 0x0a25, 0x0000 },
+  { 0x8700, 0x0a28, 0x2000 },
+  { 0x0700, 0x0a27, 0x0000 },
+  { 0x0700, 0x0a2a, 0x0000 },
+  { 0x8d00, 0x0a6a, 0x6000 },
+  { 0x8c00, 0x0a41, 0x5000 },
+  { 0x8700, 0x0a35, 0x4000 },
+  { 0x8700, 0x0a2f, 0x3000 },
+  { 0x8700, 0x0a2d, 0x2000 },
+  { 0x0700, 0x0a2c, 0x0000 },
+  { 0x0700, 0x0a2e, 0x0000 },
+  { 0x8700, 0x0a32, 0x2000 },
+  { 0x0700, 0x0a30, 0x0000 },
+  { 0x0700, 0x0a33, 0x0000 },
+  { 0x8c00, 0x0a3c, 0x3000 },
+  { 0x8700, 0x0a38, 0x2000 },
+  { 0x0700, 0x0a36, 0x0000 },
+  { 0x0700, 0x0a39, 0x0000 },
+  { 0x8a00, 0x0a3f, 0x2000 },
+  { 0x0a00, 0x0a3e, 0x0000 },
+  { 0x0a00, 0x0a40, 0x0000 },
+  { 0x8700, 0x0a5a, 0x4000 },
+  { 0x8c00, 0x0a4b, 0x3000 },
+  { 0x8c00, 0x0a47, 0x2000 },
+  { 0x0c00, 0x0a42, 0x0000 },
+  { 0x0c00, 0x0a48, 0x0000 },
+  { 0x8c00, 0x0a4d, 0x2000 },
+  { 0x0c00, 0x0a4c, 0x0000 },
+  { 0x0700, 0x0a59, 0x0000 },
+  { 0x8d00, 0x0a66, 0x3000 },
+  { 0x8700, 0x0a5c, 0x2000 },
+  { 0x0700, 0x0a5b, 0x0000 },
+  { 0x0700, 0x0a5e, 0x0000 },
+  { 0x8d00, 0x0a68, 0x2000 },
+  { 0x0d00, 0x0a67, 0x0000 },
+  { 0x0d00, 0x0a69, 0x0000 },
+  { 0x8700, 0x0a87, 0x5000 },
+  { 0x8700, 0x0a72, 0x4000 },
+  { 0x8d00, 0x0a6e, 0x3000 },
+  { 0x8d00, 0x0a6c, 0x2000 },
+  { 0x0d00, 0x0a6b, 0x0000 },
+  { 0x0d00, 0x0a6d, 0x0000 },
+  { 0x8c00, 0x0a70, 0x2000 },
+  { 0x0d00, 0x0a6f, 0x0000 },
+  { 0x0c00, 0x0a71, 0x0000 },
+  { 0x8c00, 0x0a82, 0x3000 },
+  { 0x8700, 0x0a74, 0x2000 },
+  { 0x0700, 0x0a73, 0x0000 },
+  { 0x0c00, 0x0a81, 0x0000 },
+  { 0x8700, 0x0a85, 0x2000 },
+  { 0x0a00, 0x0a83, 0x0000 },
+  { 0x0700, 0x0a86, 0x0000 },
+  { 0x8700, 0x0a90, 0x4000 },
+  { 0x8700, 0x0a8b, 0x3000 },
+  { 0x8700, 0x0a89, 0x2000 },
+  { 0x0700, 0x0a88, 0x0000 },
+  { 0x0700, 0x0a8a, 0x0000 },
+  { 0x8700, 0x0a8d, 0x2000 },
+  { 0x0700, 0x0a8c, 0x0000 },
+  { 0x0700, 0x0a8f, 0x0000 },
+  { 0x8700, 0x0a95, 0x3000 },
+  { 0x8700, 0x0a93, 0x2000 },
+  { 0x0700, 0x0a91, 0x0000 },
+  { 0x0700, 0x0a94, 0x0000 },
+  { 0x8700, 0x0a97, 0x2000 },
+  { 0x0700, 0x0a96, 0x0000 },
+  { 0x0700, 0x0a98, 0x0000 },
+  { 0x8700, 0x10ef, 0xb000 },
+  { 0x8700, 0x0dc6, 0xa000 },
+  { 0x8700, 0x0c31, 0x9000 },
+  { 0x8700, 0x0b5f, 0x8000 },
+  { 0x8a00, 0x0b03, 0x7000 },
+  { 0x8a00, 0x0abe, 0x6000 },
+  { 0x8700, 0x0aaa, 0x5000 },
+  { 0x8700, 0x0aa1, 0x4000 },
+  { 0x8700, 0x0a9d, 0x3000 },
+  { 0x8700, 0x0a9b, 0x2000 },
+  { 0x0700, 0x0a9a, 0x0000 },
+  { 0x0700, 0x0a9c, 0x0000 },
+  { 0x8700, 0x0a9f, 0x2000 },
+  { 0x0700, 0x0a9e, 0x0000 },
+  { 0x0700, 0x0aa0, 0x0000 },
+  { 0x8700, 0x0aa5, 0x3000 },
+  { 0x8700, 0x0aa3, 0x2000 },
+  { 0x0700, 0x0aa2, 0x0000 },
+  { 0x0700, 0x0aa4, 0x0000 },
+  { 0x8700, 0x0aa7, 0x2000 },
+  { 0x0700, 0x0aa6, 0x0000 },
+  { 0x0700, 0x0aa8, 0x0000 },
+  { 0x8700, 0x0ab3, 0x4000 },
+  { 0x8700, 0x0aae, 0x3000 },
+  { 0x8700, 0x0aac, 0x2000 },
+  { 0x0700, 0x0aab, 0x0000 },
+  { 0x0700, 0x0aad, 0x0000 },
+  { 0x8700, 0x0ab0, 0x2000 },
+  { 0x0700, 0x0aaf, 0x0000 },
+  { 0x0700, 0x0ab2, 0x0000 },
+  { 0x8700, 0x0ab8, 0x3000 },
+  { 0x8700, 0x0ab6, 0x2000 },
+  { 0x0700, 0x0ab5, 0x0000 },
+  { 0x0700, 0x0ab7, 0x0000 },
+  { 0x8c00, 0x0abc, 0x2000 },
+  { 0x0700, 0x0ab9, 0x0000 },
+  { 0x0700, 0x0abd, 0x0000 },
+  { 0x8700, 0x0ae1, 0x5000 },
+  { 0x8c00, 0x0ac7, 0x4000 },
+  { 0x8c00, 0x0ac2, 0x3000 },
+  { 0x8a00, 0x0ac0, 0x2000 },
+  { 0x0a00, 0x0abf, 0x0000 },
+  { 0x0c00, 0x0ac1, 0x0000 },
+  { 0x8c00, 0x0ac4, 0x2000 },
+  { 0x0c00, 0x0ac3, 0x0000 },
+  { 0x0c00, 0x0ac5, 0x0000 },
+  { 0x8a00, 0x0acc, 0x3000 },
+  { 0x8a00, 0x0ac9, 0x2000 },
+  { 0x0c00, 0x0ac8, 0x0000 },
+  { 0x0a00, 0x0acb, 0x0000 },
+  { 0x8700, 0x0ad0, 0x2000 },
+  { 0x0c00, 0x0acd, 0x0000 },
+  { 0x0700, 0x0ae0, 0x0000 },
+  { 0x8d00, 0x0aeb, 0x4000 },
+  { 0x8d00, 0x0ae7, 0x3000 },
+  { 0x8c00, 0x0ae3, 0x2000 },
+  { 0x0c00, 0x0ae2, 0x0000 },
+  { 0x0d00, 0x0ae6, 0x0000 },
+  { 0x8d00, 0x0ae9, 0x2000 },
+  { 0x0d00, 0x0ae8, 0x0000 },
+  { 0x0d00, 0x0aea, 0x0000 },
+  { 0x8d00, 0x0aef, 0x3000 },
+  { 0x8d00, 0x0aed, 0x2000 },
+  { 0x0d00, 0x0aec, 0x0000 },
+  { 0x0d00, 0x0aee, 0x0000 },
+  { 0x8c00, 0x0b01, 0x2000 },
+  { 0x1700, 0x0af1, 0x0000 },
+  { 0x0a00, 0x0b02, 0x0000 },
+  { 0x8700, 0x0b28, 0x6000 },
+  { 0x8700, 0x0b18, 0x5000 },
+  { 0x8700, 0x0b0c, 0x4000 },
+  { 0x8700, 0x0b08, 0x3000 },
+  { 0x8700, 0x0b06, 0x2000 },
+  { 0x0700, 0x0b05, 0x0000 },
+  { 0x0700, 0x0b07, 0x0000 },
+  { 0x8700, 0x0b0a, 0x2000 },
+  { 0x0700, 0x0b09, 0x0000 },
+  { 0x0700, 0x0b0b, 0x0000 },
+  { 0x8700, 0x0b14, 0x3000 },
+  { 0x8700, 0x0b10, 0x2000 },
+  { 0x0700, 0x0b0f, 0x0000 },
+  { 0x0700, 0x0b13, 0x0000 },
+  { 0x8700, 0x0b16, 0x2000 },
+  { 0x0700, 0x0b15, 0x0000 },
+  { 0x0700, 0x0b17, 0x0000 },
+  { 0x8700, 0x0b20, 0x4000 },
+  { 0x8700, 0x0b1c, 0x3000 },
+  { 0x8700, 0x0b1a, 0x2000 },
+  { 0x0700, 0x0b19, 0x0000 },
+  { 0x0700, 0x0b1b, 0x0000 },
+  { 0x8700, 0x0b1e, 0x2000 },
+  { 0x0700, 0x0b1d, 0x0000 },
+  { 0x0700, 0x0b1f, 0x0000 },
+  { 0x8700, 0x0b24, 0x3000 },
+  { 0x8700, 0x0b22, 0x2000 },
+  { 0x0700, 0x0b21, 0x0000 },
+  { 0x0700, 0x0b23, 0x0000 },
+  { 0x8700, 0x0b26, 0x2000 },
+  { 0x0700, 0x0b25, 0x0000 },
+  { 0x0700, 0x0b27, 0x0000 },
+  { 0x8700, 0x0b3d, 0x5000 },
+  { 0x8700, 0x0b32, 0x4000 },
+  { 0x8700, 0x0b2d, 0x3000 },
+  { 0x8700, 0x0b2b, 0x2000 },
+  { 0x0700, 0x0b2a, 0x0000 },
+  { 0x0700, 0x0b2c, 0x0000 },
+  { 0x8700, 0x0b2f, 0x2000 },
+  { 0x0700, 0x0b2e, 0x0000 },
+  { 0x0700, 0x0b30, 0x0000 },
+  { 0x8700, 0x0b37, 0x3000 },
+  { 0x8700, 0x0b35, 0x2000 },
+  { 0x0700, 0x0b33, 0x0000 },
+  { 0x0700, 0x0b36, 0x0000 },
+  { 0x8700, 0x0b39, 0x2000 },
+  { 0x0700, 0x0b38, 0x0000 },
+  { 0x0c00, 0x0b3c, 0x0000 },
+  { 0x8a00, 0x0b48, 0x4000 },
+  { 0x8c00, 0x0b41, 0x3000 },
+  { 0x8c00, 0x0b3f, 0x2000 },
+  { 0x0a00, 0x0b3e, 0x0000 },
+  { 0x0a00, 0x0b40, 0x0000 },
+  { 0x8c00, 0x0b43, 0x2000 },
+  { 0x0c00, 0x0b42, 0x0000 },
+  { 0x0a00, 0x0b47, 0x0000 },
+  { 0x8c00, 0x0b56, 0x3000 },
+  { 0x8a00, 0x0b4c, 0x2000 },
+  { 0x0a00, 0x0b4b, 0x0000 },
+  { 0x0c00, 0x0b4d, 0x0000 },
+  { 0x8700, 0x0b5c, 0x2000 },
+  { 0x0a00, 0x0b57, 0x0000 },
+  { 0x0700, 0x0b5d, 0x0000 },
+  { 0x8d00, 0x0be7, 0x7000 },
+  { 0x8700, 0x0b9c, 0x6000 },
+  { 0x8700, 0x0b83, 0x5000 },
+  { 0x8d00, 0x0b6b, 0x4000 },
+  { 0x8d00, 0x0b67, 0x3000 },
+  { 0x8700, 0x0b61, 0x2000 },
+  { 0x0700, 0x0b60, 0x0000 },
+  { 0x0d00, 0x0b66, 0x0000 },
+  { 0x8d00, 0x0b69, 0x2000 },
+  { 0x0d00, 0x0b68, 0x0000 },
+  { 0x0d00, 0x0b6a, 0x0000 },
+  { 0x8d00, 0x0b6f, 0x3000 },
+  { 0x8d00, 0x0b6d, 0x2000 },
+  { 0x0d00, 0x0b6c, 0x0000 },
+  { 0x0d00, 0x0b6e, 0x0000 },
+  { 0x8700, 0x0b71, 0x2000 },
+  { 0x1a00, 0x0b70, 0x0000 },
+  { 0x0c00, 0x0b82, 0x0000 },
+  { 0x8700, 0x0b8f, 0x4000 },
+  { 0x8700, 0x0b88, 0x3000 },
+  { 0x8700, 0x0b86, 0x2000 },
+  { 0x0700, 0x0b85, 0x0000 },
+  { 0x0700, 0x0b87, 0x0000 },
+  { 0x8700, 0x0b8a, 0x2000 },
+  { 0x0700, 0x0b89, 0x0000 },
+  { 0x0700, 0x0b8e, 0x0000 },
+  { 0x8700, 0x0b94, 0x3000 },
+  { 0x8700, 0x0b92, 0x2000 },
+  { 0x0700, 0x0b90, 0x0000 },
+  { 0x0700, 0x0b93, 0x0000 },
+  { 0x8700, 0x0b99, 0x2000 },
+  { 0x0700, 0x0b95, 0x0000 },
+  { 0x0700, 0x0b9a, 0x0000 },
+  { 0x8700, 0x0bb7, 0x5000 },
+  { 0x8700, 0x0bae, 0x4000 },
+  { 0x8700, 0x0ba4, 0x3000 },
+  { 0x8700, 0x0b9f, 0x2000 },
+  { 0x0700, 0x0b9e, 0x0000 },
+  { 0x0700, 0x0ba3, 0x0000 },
+  { 0x8700, 0x0ba9, 0x2000 },
+  { 0x0700, 0x0ba8, 0x0000 },
+  { 0x0700, 0x0baa, 0x0000 },
+  { 0x8700, 0x0bb2, 0x3000 },
+  { 0x8700, 0x0bb0, 0x2000 },
+  { 0x0700, 0x0baf, 0x0000 },
+  { 0x0700, 0x0bb1, 0x0000 },
+  { 0x8700, 0x0bb4, 0x2000 },
+  { 0x0700, 0x0bb3, 0x0000 },
+  { 0x0700, 0x0bb5, 0x0000 },
+  { 0x8a00, 0x0bc6, 0x4000 },
+  { 0x8a00, 0x0bbf, 0x3000 },
+  { 0x8700, 0x0bb9, 0x2000 },
+  { 0x0700, 0x0bb8, 0x0000 },
+  { 0x0a00, 0x0bbe, 0x0000 },
+  { 0x8a00, 0x0bc1, 0x2000 },
+  { 0x0c00, 0x0bc0, 0x0000 },
+  { 0x0a00, 0x0bc2, 0x0000 },
+  { 0x8a00, 0x0bcb, 0x3000 },
+  { 0x8a00, 0x0bc8, 0x2000 },
+  { 0x0a00, 0x0bc7, 0x0000 },
+  { 0x0a00, 0x0bca, 0x0000 },
+  { 0x8c00, 0x0bcd, 0x2000 },
+  { 0x0a00, 0x0bcc, 0x0000 },
+  { 0x0a00, 0x0bd7, 0x0000 },
+  { 0x8700, 0x0c0f, 0x6000 },
+  { 0x9a00, 0x0bf7, 0x5000 },
+  { 0x8d00, 0x0bef, 0x4000 },
+  { 0x8d00, 0x0beb, 0x3000 },
+  { 0x8d00, 0x0be9, 0x2000 },
+  { 0x0d00, 0x0be8, 0x0000 },
+  { 0x0d00, 0x0bea, 0x0000 },
+  { 0x8d00, 0x0bed, 0x2000 },
+  { 0x0d00, 0x0bec, 0x0000 },
+  { 0x0d00, 0x0bee, 0x0000 },
+  { 0x9a00, 0x0bf3, 0x3000 },
+  { 0x8f00, 0x0bf1, 0x2000 },
+  { 0x0f00, 0x0bf0, 0x0000 },
+  { 0x0f00, 0x0bf2, 0x0000 },
+  { 0x9a00, 0x0bf5, 0x2000 },
+  { 0x1a00, 0x0bf4, 0x0000 },
+  { 0x1a00, 0x0bf6, 0x0000 },
+  { 0x8700, 0x0c06, 0x4000 },
+  { 0x8a00, 0x0c01, 0x3000 },
+  { 0x9700, 0x0bf9, 0x2000 },
+  { 0x1a00, 0x0bf8, 0x0000 },
+  { 0x1a00, 0x0bfa, 0x0000 },
+  { 0x8a00, 0x0c03, 0x2000 },
+  { 0x0a00, 0x0c02, 0x0000 },
+  { 0x0700, 0x0c05, 0x0000 },
+  { 0x8700, 0x0c0a, 0x3000 },
+  { 0x8700, 0x0c08, 0x2000 },
+  { 0x0700, 0x0c07, 0x0000 },
+  { 0x0700, 0x0c09, 0x0000 },
+  { 0x8700, 0x0c0c, 0x2000 },
+  { 0x0700, 0x0c0b, 0x0000 },
+  { 0x0700, 0x0c0e, 0x0000 },
+  { 0x8700, 0x0c20, 0x5000 },
+  { 0x8700, 0x0c18, 0x4000 },
+  { 0x8700, 0x0c14, 0x3000 },
+  { 0x8700, 0x0c12, 0x2000 },
+  { 0x0700, 0x0c10, 0x0000 },
+  { 0x0700, 0x0c13, 0x0000 },
+  { 0x8700, 0x0c16, 0x2000 },
+  { 0x0700, 0x0c15, 0x0000 },
+  { 0x0700, 0x0c17, 0x0000 },
+  { 0x8700, 0x0c1c, 0x3000 },
+  { 0x8700, 0x0c1a, 0x2000 },
+  { 0x0700, 0x0c19, 0x0000 },
+  { 0x0700, 0x0c1b, 0x0000 },
+  { 0x8700, 0x0c1e, 0x2000 },
+  { 0x0700, 0x0c1d, 0x0000 },
+  { 0x0700, 0x0c1f, 0x0000 },
+  { 0x8700, 0x0c28, 0x4000 },
+  { 0x8700, 0x0c24, 0x3000 },
+  { 0x8700, 0x0c22, 0x2000 },
+  { 0x0700, 0x0c21, 0x0000 },
+  { 0x0700, 0x0c23, 0x0000 },
+  { 0x8700, 0x0c26, 0x2000 },
+  { 0x0700, 0x0c25, 0x0000 },
+  { 0x0700, 0x0c27, 0x0000 },
+  { 0x8700, 0x0c2d, 0x3000 },
+  { 0x8700, 0x0c2b, 0x2000 },
+  { 0x0700, 0x0c2a, 0x0000 },
+  { 0x0700, 0x0c2c, 0x0000 },
+  { 0x8700, 0x0c2f, 0x2000 },
+  { 0x0700, 0x0c2e, 0x0000 },
+  { 0x0700, 0x0c30, 0x0000 },
+  { 0x8700, 0x0d0e, 0x8000 },
+  { 0x8700, 0x0ca1, 0x7000 },
+  { 0x8d00, 0x0c6c, 0x6000 },
+  { 0x8c00, 0x0c47, 0x5000 },
+  { 0x8c00, 0x0c3e, 0x4000 },
+  { 0x8700, 0x0c36, 0x3000 },
+  { 0x8700, 0x0c33, 0x2000 },
+  { 0x0700, 0x0c32, 0x0000 },
+  { 0x0700, 0x0c35, 0x0000 },
+  { 0x8700, 0x0c38, 0x2000 },
+  { 0x0700, 0x0c37, 0x0000 },
+  { 0x0700, 0x0c39, 0x0000 },
+  { 0x8a00, 0x0c42, 0x3000 },
+  { 0x8c00, 0x0c40, 0x2000 },
+  { 0x0c00, 0x0c3f, 0x0000 },
+  { 0x0a00, 0x0c41, 0x0000 },
+  { 0x8a00, 0x0c44, 0x2000 },
+  { 0x0a00, 0x0c43, 0x0000 },
+  { 0x0c00, 0x0c46, 0x0000 },
+  { 0x8700, 0x0c60, 0x4000 },
+  { 0x8c00, 0x0c4c, 0x3000 },
+  { 0x8c00, 0x0c4a, 0x2000 },
+  { 0x0c00, 0x0c48, 0x0000 },
+  { 0x0c00, 0x0c4b, 0x0000 },
+  { 0x8c00, 0x0c55, 0x2000 },
+  { 0x0c00, 0x0c4d, 0x0000 },
+  { 0x0c00, 0x0c56, 0x0000 },
+  { 0x8d00, 0x0c68, 0x3000 },
+  { 0x8d00, 0x0c66, 0x2000 },
+  { 0x0700, 0x0c61, 0x0000 },
+  { 0x0d00, 0x0c67, 0x0000 },
+  { 0x8d00, 0x0c6a, 0x2000 },
+  { 0x0d00, 0x0c69, 0x0000 },
+  { 0x0d00, 0x0c6b, 0x0000 },
+  { 0x8700, 0x0c90, 0x5000 },
+  { 0x8700, 0x0c87, 0x4000 },
+  { 0x8a00, 0x0c82, 0x3000 },
+  { 0x8d00, 0x0c6e, 0x2000 },
+  { 0x0d00, 0x0c6d, 0x0000 },
+  { 0x0d00, 0x0c6f, 0x0000 },
+  { 0x8700, 0x0c85, 0x2000 },
+  { 0x0a00, 0x0c83, 0x0000 },
+  { 0x0700, 0x0c86, 0x0000 },
+  { 0x8700, 0x0c8b, 0x3000 },
+  { 0x8700, 0x0c89, 0x2000 },
+  { 0x0700, 0x0c88, 0x0000 },
+  { 0x0700, 0x0c8a, 0x0000 },
+  { 0x8700, 0x0c8e, 0x2000 },
+  { 0x0700, 0x0c8c, 0x0000 },
+  { 0x0700, 0x0c8f, 0x0000 },
+  { 0x8700, 0x0c99, 0x4000 },
+  { 0x8700, 0x0c95, 0x3000 },
+  { 0x8700, 0x0c93, 0x2000 },
+  { 0x0700, 0x0c92, 0x0000 },
+  { 0x0700, 0x0c94, 0x0000 },
+  { 0x8700, 0x0c97, 0x2000 },
+  { 0x0700, 0x0c96, 0x0000 },
+  { 0x0700, 0x0c98, 0x0000 },
+  { 0x8700, 0x0c9d, 0x3000 },
+  { 0x8700, 0x0c9b, 0x2000 },
+  { 0x0700, 0x0c9a, 0x0000 },
+  { 0x0700, 0x0c9c, 0x0000 },
+  { 0x8700, 0x0c9f, 0x2000 },
+  { 0x0700, 0x0c9e, 0x0000 },
+  { 0x0700, 0x0ca0, 0x0000 },
+  { 0x8c00, 0x0cc6, 0x6000 },
+  { 0x8700, 0x0cb2, 0x5000 },
+  { 0x8700, 0x0caa, 0x4000 },
+  { 0x8700, 0x0ca5, 0x3000 },
+  { 0x8700, 0x0ca3, 0x2000 },
+  { 0x0700, 0x0ca2, 0x0000 },
+  { 0x0700, 0x0ca4, 0x0000 },
+  { 0x8700, 0x0ca7, 0x2000 },
+  { 0x0700, 0x0ca6, 0x0000 },
+  { 0x0700, 0x0ca8, 0x0000 },
+  { 0x8700, 0x0cae, 0x3000 },
+  { 0x8700, 0x0cac, 0x2000 },
+  { 0x0700, 0x0cab, 0x0000 },
+  { 0x0700, 0x0cad, 0x0000 },
+  { 0x8700, 0x0cb0, 0x2000 },
+  { 0x0700, 0x0caf, 0x0000 },
+  { 0x0700, 0x0cb1, 0x0000 },
+  { 0x8700, 0x0cbd, 0x4000 },
+  { 0x8700, 0x0cb7, 0x3000 },
+  { 0x8700, 0x0cb5, 0x2000 },
+  { 0x0700, 0x0cb3, 0x0000 },
+  { 0x0700, 0x0cb6, 0x0000 },
+  { 0x8700, 0x0cb9, 0x2000 },
+  { 0x0700, 0x0cb8, 0x0000 },
+  { 0x0c00, 0x0cbc, 0x0000 },
+  { 0x8a00, 0x0cc1, 0x3000 },
+  { 0x8c00, 0x0cbf, 0x2000 },
+  { 0x0a00, 0x0cbe, 0x0000 },
+  { 0x0a00, 0x0cc0, 0x0000 },
+  { 0x8a00, 0x0cc3, 0x2000 },
+  { 0x0a00, 0x0cc2, 0x0000 },
+  { 0x0a00, 0x0cc4, 0x0000 },
+  { 0x8d00, 0x0cea, 0x5000 },
+  { 0x8a00, 0x0cd6, 0x4000 },
+  { 0x8a00, 0x0ccb, 0x3000 },
+  { 0x8a00, 0x0cc8, 0x2000 },
+  { 0x0a00, 0x0cc7, 0x0000 },
+  { 0x0a00, 0x0cca, 0x0000 },
+  { 0x8c00, 0x0ccd, 0x2000 },
+  { 0x0c00, 0x0ccc, 0x0000 },
+  { 0x0a00, 0x0cd5, 0x0000 },
+  { 0x8d00, 0x0ce6, 0x3000 },
+  { 0x8700, 0x0ce0, 0x2000 },
+  { 0x0700, 0x0cde, 0x0000 },
+  { 0x0700, 0x0ce1, 0x0000 },
+  { 0x8d00, 0x0ce8, 0x2000 },
+  { 0x0d00, 0x0ce7, 0x0000 },
+  { 0x0d00, 0x0ce9, 0x0000 },
+  { 0x8700, 0x0d05, 0x4000 },
+  { 0x8d00, 0x0cee, 0x3000 },
+  { 0x8d00, 0x0cec, 0x2000 },
+  { 0x0d00, 0x0ceb, 0x0000 },
+  { 0x0d00, 0x0ced, 0x0000 },
+  { 0x8a00, 0x0d02, 0x2000 },
+  { 0x0d00, 0x0cef, 0x0000 },
+  { 0x0a00, 0x0d03, 0x0000 },
+  { 0x8700, 0x0d09, 0x3000 },
+  { 0x8700, 0x0d07, 0x2000 },
+  { 0x0700, 0x0d06, 0x0000 },
+  { 0x0700, 0x0d08, 0x0000 },
+  { 0x8700, 0x0d0b, 0x2000 },
+  { 0x0700, 0x0d0a, 0x0000 },
+  { 0x0700, 0x0d0c, 0x0000 },
+  { 0x8d00, 0x0d6c, 0x7000 },
+  { 0x8700, 0x0d30, 0x6000 },
+  { 0x8700, 0x0d1f, 0x5000 },
+  { 0x8700, 0x0d17, 0x4000 },
+  { 0x8700, 0x0d13, 0x3000 },
+  { 0x8700, 0x0d10, 0x2000 },
+  { 0x0700, 0x0d0f, 0x0000 },
+  { 0x0700, 0x0d12, 0x0000 },
+  { 0x8700, 0x0d15, 0x2000 },
+  { 0x0700, 0x0d14, 0x0000 },
+  { 0x0700, 0x0d16, 0x0000 },
+  { 0x8700, 0x0d1b, 0x3000 },
+  { 0x8700, 0x0d19, 0x2000 },
+  { 0x0700, 0x0d18, 0x0000 },
+  { 0x0700, 0x0d1a, 0x0000 },
+  { 0x8700, 0x0d1d, 0x2000 },
+  { 0x0700, 0x0d1c, 0x0000 },
+  { 0x0700, 0x0d1e, 0x0000 },
+  { 0x8700, 0x0d27, 0x4000 },
+  { 0x8700, 0x0d23, 0x3000 },
+  { 0x8700, 0x0d21, 0x2000 },
+  { 0x0700, 0x0d20, 0x0000 },
+  { 0x0700, 0x0d22, 0x0000 },
+  { 0x8700, 0x0d25, 0x2000 },
+  { 0x0700, 0x0d24, 0x0000 },
+  { 0x0700, 0x0d26, 0x0000 },
+  { 0x8700, 0x0d2c, 0x3000 },
+  { 0x8700, 0x0d2a, 0x2000 },
+  { 0x0700, 0x0d28, 0x0000 },
+  { 0x0700, 0x0d2b, 0x0000 },
+  { 0x8700, 0x0d2e, 0x2000 },
+  { 0x0700, 0x0d2d, 0x0000 },
+  { 0x0700, 0x0d2f, 0x0000 },
+  { 0x8a00, 0x0d46, 0x5000 },
+  { 0x8700, 0x0d38, 0x4000 },
+  { 0x8700, 0x0d34, 0x3000 },
+  { 0x8700, 0x0d32, 0x2000 },
+  { 0x0700, 0x0d31, 0x0000 },
+  { 0x0700, 0x0d33, 0x0000 },
+  { 0x8700, 0x0d36, 0x2000 },
+  { 0x0700, 0x0d35, 0x0000 },
+  { 0x0700, 0x0d37, 0x0000 },
+  { 0x8a00, 0x0d40, 0x3000 },
+  { 0x8a00, 0x0d3e, 0x2000 },
+  { 0x0700, 0x0d39, 0x0000 },
+  { 0x0a00, 0x0d3f, 0x0000 },
+  { 0x8c00, 0x0d42, 0x2000 },
+  { 0x0c00, 0x0d41, 0x0000 },
+  { 0x0c00, 0x0d43, 0x0000 },
+  { 0x8700, 0x0d60, 0x4000 },
+  { 0x8a00, 0x0d4b, 0x3000 },
+  { 0x8a00, 0x0d48, 0x2000 },
+  { 0x0a00, 0x0d47, 0x0000 },
+  { 0x0a00, 0x0d4a, 0x0000 },
+  { 0x8c00, 0x0d4d, 0x2000 },
+  { 0x0a00, 0x0d4c, 0x0000 },
+  { 0x0a00, 0x0d57, 0x0000 },
+  { 0x8d00, 0x0d68, 0x3000 },
+  { 0x8d00, 0x0d66, 0x2000 },
+  { 0x0700, 0x0d61, 0x0000 },
+  { 0x0d00, 0x0d67, 0x0000 },
+  { 0x8d00, 0x0d6a, 0x2000 },
+  { 0x0d00, 0x0d69, 0x0000 },
+  { 0x0d00, 0x0d6b, 0x0000 },
+  { 0x8700, 0x0da2, 0x6000 },
+  { 0x8700, 0x0d8f, 0x5000 },
+  { 0x8700, 0x0d87, 0x4000 },
+  { 0x8a00, 0x0d82, 0x3000 },
+  { 0x8d00, 0x0d6e, 0x2000 },
+  { 0x0d00, 0x0d6d, 0x0000 },
+  { 0x0d00, 0x0d6f, 0x0000 },
+  { 0x8700, 0x0d85, 0x2000 },
+  { 0x0a00, 0x0d83, 0x0000 },
+  { 0x0700, 0x0d86, 0x0000 },
+  { 0x8700, 0x0d8b, 0x3000 },
+  { 0x8700, 0x0d89, 0x2000 },
+  { 0x0700, 0x0d88, 0x0000 },
+  { 0x0700, 0x0d8a, 0x0000 },
+  { 0x8700, 0x0d8d, 0x2000 },
+  { 0x0700, 0x0d8c, 0x0000 },
+  { 0x0700, 0x0d8e, 0x0000 },
+  { 0x8700, 0x0d9a, 0x4000 },
+  { 0x8700, 0x0d93, 0x3000 },
+  { 0x8700, 0x0d91, 0x2000 },
+  { 0x0700, 0x0d90, 0x0000 },
+  { 0x0700, 0x0d92, 0x0000 },
+  { 0x8700, 0x0d95, 0x2000 },
+  { 0x0700, 0x0d94, 0x0000 },
+  { 0x0700, 0x0d96, 0x0000 },
+  { 0x8700, 0x0d9e, 0x3000 },
+  { 0x8700, 0x0d9c, 0x2000 },
+  { 0x0700, 0x0d9b, 0x0000 },
+  { 0x0700, 0x0d9d, 0x0000 },
+  { 0x8700, 0x0da0, 0x2000 },
+  { 0x0700, 0x0d9f, 0x0000 },
+  { 0x0700, 0x0da1, 0x0000 },
+  { 0x8700, 0x0db3, 0x5000 },
+  { 0x8700, 0x0daa, 0x4000 },
+  { 0x8700, 0x0da6, 0x3000 },
+  { 0x8700, 0x0da4, 0x2000 },
+  { 0x0700, 0x0da3, 0x0000 },
+  { 0x0700, 0x0da5, 0x0000 },
+  { 0x8700, 0x0da8, 0x2000 },
+  { 0x0700, 0x0da7, 0x0000 },
+  { 0x0700, 0x0da9, 0x0000 },
+  { 0x8700, 0x0dae, 0x3000 },
+  { 0x8700, 0x0dac, 0x2000 },
+  { 0x0700, 0x0dab, 0x0000 },
+  { 0x0700, 0x0dad, 0x0000 },
+  { 0x8700, 0x0db0, 0x2000 },
+  { 0x0700, 0x0daf, 0x0000 },
+  { 0x0700, 0x0db1, 0x0000 },
+  { 0x8700, 0x0dbb, 0x4000 },
+  { 0x8700, 0x0db7, 0x3000 },
+  { 0x8700, 0x0db5, 0x2000 },
+  { 0x0700, 0x0db4, 0x0000 },
+  { 0x0700, 0x0db6, 0x0000 },
+  { 0x8700, 0x0db9, 0x2000 },
+  { 0x0700, 0x0db8, 0x0000 },
+  { 0x0700, 0x0dba, 0x0000 },
+  { 0x8700, 0x0dc2, 0x3000 },
+  { 0x8700, 0x0dc0, 0x2000 },
+  { 0x0700, 0x0dbd, 0x0000 },
+  { 0x0700, 0x0dc1, 0x0000 },
+  { 0x8700, 0x0dc4, 0x2000 },
+  { 0x0700, 0x0dc3, 0x0000 },
+  { 0x0700, 0x0dc5, 0x0000 },
+  { 0x8700, 0x0f55, 0x9000 },
+  { 0x8700, 0x0ea5, 0x8000 },
+  { 0x8700, 0x0e2d, 0x7000 },
+  { 0x8700, 0x0e0d, 0x6000 },
+  { 0x8a00, 0x0ddf, 0x5000 },
+  { 0x8c00, 0x0dd6, 0x4000 },
+  { 0x8a00, 0x0dd1, 0x3000 },
+  { 0x8a00, 0x0dcf, 0x2000 },
+  { 0x0c00, 0x0dca, 0x0000 },
+  { 0x0a00, 0x0dd0, 0x0000 },
+  { 0x8c00, 0x0dd3, 0x2000 },
+  { 0x0c00, 0x0dd2, 0x0000 },
+  { 0x0c00, 0x0dd4, 0x0000 },
+  { 0x8a00, 0x0ddb, 0x3000 },
+  { 0x8a00, 0x0dd9, 0x2000 },
+  { 0x0a00, 0x0dd8, 0x0000 },
+  { 0x0a00, 0x0dda, 0x0000 },
+  { 0x8a00, 0x0ddd, 0x2000 },
+  { 0x0a00, 0x0ddc, 0x0000 },
+  { 0x0a00, 0x0dde, 0x0000 },
+  { 0x8700, 0x0e05, 0x4000 },
+  { 0x8700, 0x0e01, 0x3000 },
+  { 0x8a00, 0x0df3, 0x2000 },
+  { 0x0a00, 0x0df2, 0x0000 },
+  { 0x1500, 0x0df4, 0x0000 },
+  { 0x8700, 0x0e03, 0x2000 },
+  { 0x0700, 0x0e02, 0x0000 },
+  { 0x0700, 0x0e04, 0x0000 },
+  { 0x8700, 0x0e09, 0x3000 },
+  { 0x8700, 0x0e07, 0x2000 },
+  { 0x0700, 0x0e06, 0x0000 },
+  { 0x0700, 0x0e08, 0x0000 },
+  { 0x8700, 0x0e0b, 0x2000 },
+  { 0x0700, 0x0e0a, 0x0000 },
+  { 0x0700, 0x0e0c, 0x0000 },
+  { 0x8700, 0x0e1d, 0x5000 },
+  { 0x8700, 0x0e15, 0x4000 },
+  { 0x8700, 0x0e11, 0x3000 },
+  { 0x8700, 0x0e0f, 0x2000 },
+  { 0x0700, 0x0e0e, 0x0000 },
+  { 0x0700, 0x0e10, 0x0000 },
+  { 0x8700, 0x0e13, 0x2000 },
+  { 0x0700, 0x0e12, 0x0000 },
+  { 0x0700, 0x0e14, 0x0000 },
+  { 0x8700, 0x0e19, 0x3000 },
+  { 0x8700, 0x0e17, 0x2000 },
+  { 0x0700, 0x0e16, 0x0000 },
+  { 0x0700, 0x0e18, 0x0000 },
+  { 0x8700, 0x0e1b, 0x2000 },
+  { 0x0700, 0x0e1a, 0x0000 },
+  { 0x0700, 0x0e1c, 0x0000 },
+  { 0x8700, 0x0e25, 0x4000 },
+  { 0x8700, 0x0e21, 0x3000 },
+  { 0x8700, 0x0e1f, 0x2000 },
+  { 0x0700, 0x0e1e, 0x0000 },
+  { 0x0700, 0x0e20, 0x0000 },
+  { 0x8700, 0x0e23, 0x2000 },
+  { 0x0700, 0x0e22, 0x0000 },
+  { 0x0700, 0x0e24, 0x0000 },
+  { 0x8700, 0x0e29, 0x3000 },
+  { 0x8700, 0x0e27, 0x2000 },
+  { 0x0700, 0x0e26, 0x0000 },
+  { 0x0700, 0x0e28, 0x0000 },
+  { 0x8700, 0x0e2b, 0x2000 },
+  { 0x0700, 0x0e2a, 0x0000 },
+  { 0x0700, 0x0e2c, 0x0000 },
+  { 0x8d00, 0x0e51, 0x6000 },
+  { 0x8700, 0x0e41, 0x5000 },
+  { 0x8c00, 0x0e35, 0x4000 },
+  { 0x8c00, 0x0e31, 0x3000 },
+  { 0x8700, 0x0e2f, 0x2000 },
+  { 0x0700, 0x0e2e, 0x0000 },
+  { 0x0700, 0x0e30, 0x0000 },
+  { 0x8700, 0x0e33, 0x2000 },
+  { 0x0700, 0x0e32, 0x0000 },
+  { 0x0c00, 0x0e34, 0x0000 },
+  { 0x8c00, 0x0e39, 0x3000 },
+  { 0x8c00, 0x0e37, 0x2000 },
+  { 0x0c00, 0x0e36, 0x0000 },
+  { 0x0c00, 0x0e38, 0x0000 },
+  { 0x9700, 0x0e3f, 0x2000 },
+  { 0x0c00, 0x0e3a, 0x0000 },
+  { 0x0700, 0x0e40, 0x0000 },
+  { 0x8c00, 0x0e49, 0x4000 },
+  { 0x8700, 0x0e45, 0x3000 },
+  { 0x8700, 0x0e43, 0x2000 },
+  { 0x0700, 0x0e42, 0x0000 },
+  { 0x0700, 0x0e44, 0x0000 },
+  { 0x8c00, 0x0e47, 0x2000 },
+  { 0x0600, 0x0e46, 0x0000 },
+  { 0x0c00, 0x0e48, 0x0000 },
+  { 0x8c00, 0x0e4d, 0x3000 },
+  { 0x8c00, 0x0e4b, 0x2000 },
+  { 0x0c00, 0x0e4a, 0x0000 },
+  { 0x0c00, 0x0e4c, 0x0000 },
+  { 0x9500, 0x0e4f, 0x2000 },
+  { 0x0c00, 0x0e4e, 0x0000 },
+  { 0x0d00, 0x0e50, 0x0000 },
+  { 0x8700, 0x0e8a, 0x5000 },
+  { 0x8d00, 0x0e59, 0x4000 },
+  { 0x8d00, 0x0e55, 0x3000 },
+  { 0x8d00, 0x0e53, 0x2000 },
+  { 0x0d00, 0x0e52, 0x0000 },
+  { 0x0d00, 0x0e54, 0x0000 },
+  { 0x8d00, 0x0e57, 0x2000 },
+  { 0x0d00, 0x0e56, 0x0000 },
+  { 0x0d00, 0x0e58, 0x0000 },
+  { 0x8700, 0x0e82, 0x3000 },
+  { 0x9500, 0x0e5b, 0x2000 },
+  { 0x1500, 0x0e5a, 0x0000 },
+  { 0x0700, 0x0e81, 0x0000 },
+  { 0x8700, 0x0e87, 0x2000 },
+  { 0x0700, 0x0e84, 0x0000 },
+  { 0x0700, 0x0e88, 0x0000 },
+  { 0x8700, 0x0e9b, 0x4000 },
+  { 0x8700, 0x0e96, 0x3000 },
+  { 0x8700, 0x0e94, 0x2000 },
+  { 0x0700, 0x0e8d, 0x0000 },
+  { 0x0700, 0x0e95, 0x0000 },
+  { 0x8700, 0x0e99, 0x2000 },
+  { 0x0700, 0x0e97, 0x0000 },
+  { 0x0700, 0x0e9a, 0x0000 },
+  { 0x8700, 0x0e9f, 0x3000 },
+  { 0x8700, 0x0e9d, 0x2000 },
+  { 0x0700, 0x0e9c, 0x0000 },
+  { 0x0700, 0x0e9e, 0x0000 },
+  { 0x8700, 0x0ea2, 0x2000 },
+  { 0x0700, 0x0ea1, 0x0000 },
+  { 0x0700, 0x0ea3, 0x0000 },
+  { 0x9a00, 0x0f14, 0x7000 },
+  { 0x8d00, 0x0ed0, 0x6000 },
+  { 0x8c00, 0x0eb9, 0x5000 },
+  { 0x8c00, 0x0eb1, 0x4000 },
+  { 0x8700, 0x0ead, 0x3000 },
+  { 0x8700, 0x0eaa, 0x2000 },
+  { 0x0700, 0x0ea7, 0x0000 },
+  { 0x0700, 0x0eab, 0x0000 },
+  { 0x8700, 0x0eaf, 0x2000 },
+  { 0x0700, 0x0eae, 0x0000 },
+  { 0x0700, 0x0eb0, 0x0000 },
+  { 0x8c00, 0x0eb5, 0x3000 },
+  { 0x8700, 0x0eb3, 0x2000 },
+  { 0x0700, 0x0eb2, 0x0000 },
+  { 0x0c00, 0x0eb4, 0x0000 },
+  { 0x8c00, 0x0eb7, 0x2000 },
+  { 0x0c00, 0x0eb6, 0x0000 },
+  { 0x0c00, 0x0eb8, 0x0000 },
+  { 0x8700, 0x0ec4, 0x4000 },
+  { 0x8700, 0x0ec0, 0x3000 },
+  { 0x8c00, 0x0ebc, 0x2000 },
+  { 0x0c00, 0x0ebb, 0x0000 },
+  { 0x0700, 0x0ebd, 0x0000 },
+  { 0x8700, 0x0ec2, 0x2000 },
+  { 0x0700, 0x0ec1, 0x0000 },
+  { 0x0700, 0x0ec3, 0x0000 },
+  { 0x8c00, 0x0eca, 0x3000 },
+  { 0x8c00, 0x0ec8, 0x2000 },
+  { 0x0600, 0x0ec6, 0x0000 },
+  { 0x0c00, 0x0ec9, 0x0000 },
+  { 0x8c00, 0x0ecc, 0x2000 },
+  { 0x0c00, 0x0ecb, 0x0000 },
+  { 0x0c00, 0x0ecd, 0x0000 },
+  { 0x9500, 0x0f04, 0x5000 },
+  { 0x8d00, 0x0ed8, 0x4000 },
+  { 0x8d00, 0x0ed4, 0x3000 },
+  { 0x8d00, 0x0ed2, 0x2000 },
+  { 0x0d00, 0x0ed1, 0x0000 },
+  { 0x0d00, 0x0ed3, 0x0000 },
+  { 0x8d00, 0x0ed6, 0x2000 },
+  { 0x0d00, 0x0ed5, 0x0000 },
+  { 0x0d00, 0x0ed7, 0x0000 },
+  { 0x8700, 0x0f00, 0x3000 },
+  { 0x8700, 0x0edc, 0x2000 },
+  { 0x0d00, 0x0ed9, 0x0000 },
+  { 0x0700, 0x0edd, 0x0000 },
+  { 0x9a00, 0x0f02, 0x2000 },
+  { 0x1a00, 0x0f01, 0x0000 },
+  { 0x1a00, 0x0f03, 0x0000 },
+  { 0x9500, 0x0f0c, 0x4000 },
+  { 0x9500, 0x0f08, 0x3000 },
+  { 0x9500, 0x0f06, 0x2000 },
+  { 0x1500, 0x0f05, 0x0000 },
+  { 0x1500, 0x0f07, 0x0000 },
+  { 0x9500, 0x0f0a, 0x2000 },
+  { 0x1500, 0x0f09, 0x0000 },
+  { 0x1500, 0x0f0b, 0x0000 },
+  { 0x9500, 0x0f10, 0x3000 },
+  { 0x9500, 0x0f0e, 0x2000 },
+  { 0x1500, 0x0f0d, 0x0000 },
+  { 0x1500, 0x0f0f, 0x0000 },
+  { 0x9500, 0x0f12, 0x2000 },
+  { 0x1500, 0x0f11, 0x0000 },
+  { 0x1a00, 0x0f13, 0x0000 },
+  { 0x9a00, 0x0f34, 0x6000 },
+  { 0x8d00, 0x0f24, 0x5000 },
+  { 0x9a00, 0x0f1c, 0x4000 },
+  { 0x8c00, 0x0f18, 0x3000 },
+  { 0x9a00, 0x0f16, 0x2000 },
+  { 0x1a00, 0x0f15, 0x0000 },
+  { 0x1a00, 0x0f17, 0x0000 },
+  { 0x9a00, 0x0f1a, 0x2000 },
+  { 0x0c00, 0x0f19, 0x0000 },
+  { 0x1a00, 0x0f1b, 0x0000 },
+  { 0x8d00, 0x0f20, 0x3000 },
+  { 0x9a00, 0x0f1e, 0x2000 },
+  { 0x1a00, 0x0f1d, 0x0000 },
+  { 0x1a00, 0x0f1f, 0x0000 },
+  { 0x8d00, 0x0f22, 0x2000 },
+  { 0x0d00, 0x0f21, 0x0000 },
+  { 0x0d00, 0x0f23, 0x0000 },
+  { 0x8f00, 0x0f2c, 0x4000 },
+  { 0x8d00, 0x0f28, 0x3000 },
+  { 0x8d00, 0x0f26, 0x2000 },
+  { 0x0d00, 0x0f25, 0x0000 },
+  { 0x0d00, 0x0f27, 0x0000 },
+  { 0x8f00, 0x0f2a, 0x2000 },
+  { 0x0d00, 0x0f29, 0x0000 },
+  { 0x0f00, 0x0f2b, 0x0000 },
+  { 0x8f00, 0x0f30, 0x3000 },
+  { 0x8f00, 0x0f2e, 0x2000 },
+  { 0x0f00, 0x0f2d, 0x0000 },
+  { 0x0f00, 0x0f2f, 0x0000 },
+  { 0x8f00, 0x0f32, 0x2000 },
+  { 0x0f00, 0x0f31, 0x0000 },
+  { 0x0f00, 0x0f33, 0x0000 },
+  { 0x8700, 0x0f44, 0x5000 },
+  { 0x9600, 0x0f3c, 0x4000 },
+  { 0x9a00, 0x0f38, 0x3000 },
+  { 0x9a00, 0x0f36, 0x2000 },
+  { 0x0c00, 0x0f35, 0x0000 },
+  { 0x0c00, 0x0f37, 0x0000 },
+  { 0x9600, 0x0f3a, 0x2000 },
+  { 0x0c00, 0x0f39, 0x0000 },
+  { 0x1200, 0x0f3b, 0x0000 },
+  { 0x8700, 0x0f40, 0x3000 },
+  { 0x8a00, 0x0f3e, 0x2000 },
+  { 0x1200, 0x0f3d, 0x0000 },
+  { 0x0a00, 0x0f3f, 0x0000 },
+  { 0x8700, 0x0f42, 0x2000 },
+  { 0x0700, 0x0f41, 0x0000 },
+  { 0x0700, 0x0f43, 0x0000 },
+  { 0x8700, 0x0f4d, 0x4000 },
+  { 0x8700, 0x0f49, 0x3000 },
+  { 0x8700, 0x0f46, 0x2000 },
+  { 0x0700, 0x0f45, 0x0000 },
+  { 0x0700, 0x0f47, 0x0000 },
+  { 0x8700, 0x0f4b, 0x2000 },
+  { 0x0700, 0x0f4a, 0x0000 },
+  { 0x0700, 0x0f4c, 0x0000 },
+  { 0x8700, 0x0f51, 0x3000 },
+  { 0x8700, 0x0f4f, 0x2000 },
+  { 0x0700, 0x0f4e, 0x0000 },
+  { 0x0700, 0x0f50, 0x0000 },
+  { 0x8700, 0x0f53, 0x2000 },
+  { 0x0700, 0x0f52, 0x0000 },
+  { 0x0700, 0x0f54, 0x0000 },
+  { 0x8700, 0x1013, 0x8000 },
+  { 0x8c00, 0x0fa0, 0x7000 },
+  { 0x8c00, 0x0f7b, 0x6000 },
+  { 0x8700, 0x0f65, 0x5000 },
+  { 0x8700, 0x0f5d, 0x4000 },
+  { 0x8700, 0x0f59, 0x3000 },
+  { 0x8700, 0x0f57, 0x2000 },
+  { 0x0700, 0x0f56, 0x0000 },
+  { 0x0700, 0x0f58, 0x0000 },
+  { 0x8700, 0x0f5b, 0x2000 },
+  { 0x0700, 0x0f5a, 0x0000 },
+  { 0x0700, 0x0f5c, 0x0000 },
+  { 0x8700, 0x0f61, 0x3000 },
+  { 0x8700, 0x0f5f, 0x2000 },
+  { 0x0700, 0x0f5e, 0x0000 },
+  { 0x0700, 0x0f60, 0x0000 },
+  { 0x8700, 0x0f63, 0x2000 },
+  { 0x0700, 0x0f62, 0x0000 },
+  { 0x0700, 0x0f64, 0x0000 },
+  { 0x8c00, 0x0f73, 0x4000 },
+  { 0x8700, 0x0f69, 0x3000 },
+  { 0x8700, 0x0f67, 0x2000 },
+  { 0x0700, 0x0f66, 0x0000 },
+  { 0x0700, 0x0f68, 0x0000 },
+  { 0x8c00, 0x0f71, 0x2000 },
+  { 0x0700, 0x0f6a, 0x0000 },
+  { 0x0c00, 0x0f72, 0x0000 },
+  { 0x8c00, 0x0f77, 0x3000 },
+  { 0x8c00, 0x0f75, 0x2000 },
+  { 0x0c00, 0x0f74, 0x0000 },
+  { 0x0c00, 0x0f76, 0x0000 },
+  { 0x8c00, 0x0f79, 0x2000 },
+  { 0x0c00, 0x0f78, 0x0000 },
+  { 0x0c00, 0x0f7a, 0x0000 },
+  { 0x8700, 0x0f8b, 0x5000 },
+  { 0x8c00, 0x0f83, 0x4000 },
+  { 0x8a00, 0x0f7f, 0x3000 },
+  { 0x8c00, 0x0f7d, 0x2000 },
+  { 0x0c00, 0x0f7c, 0x0000 },
+  { 0x0c00, 0x0f7e, 0x0000 },
+  { 0x8c00, 0x0f81, 0x2000 },
+  { 0x0c00, 0x0f80, 0x0000 },
+  { 0x0c00, 0x0f82, 0x0000 },
+  { 0x8c00, 0x0f87, 0x3000 },
+  { 0x9500, 0x0f85, 0x2000 },
+  { 0x0c00, 0x0f84, 0x0000 },
+  { 0x0c00, 0x0f86, 0x0000 },
+  { 0x8700, 0x0f89, 0x2000 },
+  { 0x0700, 0x0f88, 0x0000 },
+  { 0x0700, 0x0f8a, 0x0000 },
+  { 0x8c00, 0x0f97, 0x4000 },
+  { 0x8c00, 0x0f93, 0x3000 },
+  { 0x8c00, 0x0f91, 0x2000 },
+  { 0x0c00, 0x0f90, 0x0000 },
+  { 0x0c00, 0x0f92, 0x0000 },
+  { 0x8c00, 0x0f95, 0x2000 },
+  { 0x0c00, 0x0f94, 0x0000 },
+  { 0x0c00, 0x0f96, 0x0000 },
+  { 0x8c00, 0x0f9c, 0x3000 },
+  { 0x8c00, 0x0f9a, 0x2000 },
+  { 0x0c00, 0x0f99, 0x0000 },
+  { 0x0c00, 0x0f9b, 0x0000 },
+  { 0x8c00, 0x0f9e, 0x2000 },
+  { 0x0c00, 0x0f9d, 0x0000 },
+  { 0x0c00, 0x0f9f, 0x0000 },
+  { 0x9a00, 0x0fc1, 0x6000 },
+  { 0x8c00, 0x0fb0, 0x5000 },
+  { 0x8c00, 0x0fa8, 0x4000 },
+  { 0x8c00, 0x0fa4, 0x3000 },
+  { 0x8c00, 0x0fa2, 0x2000 },
+  { 0x0c00, 0x0fa1, 0x0000 },
+  { 0x0c00, 0x0fa3, 0x0000 },
+  { 0x8c00, 0x0fa6, 0x2000 },
+  { 0x0c00, 0x0fa5, 0x0000 },
+  { 0x0c00, 0x0fa7, 0x0000 },
+  { 0x8c00, 0x0fac, 0x3000 },
+  { 0x8c00, 0x0faa, 0x2000 },
+  { 0x0c00, 0x0fa9, 0x0000 },
+  { 0x0c00, 0x0fab, 0x0000 },
+  { 0x8c00, 0x0fae, 0x2000 },
+  { 0x0c00, 0x0fad, 0x0000 },
+  { 0x0c00, 0x0faf, 0x0000 },
+  { 0x8c00, 0x0fb8, 0x4000 },
+  { 0x8c00, 0x0fb4, 0x3000 },
+  { 0x8c00, 0x0fb2, 0x2000 },
+  { 0x0c00, 0x0fb1, 0x0000 },
+  { 0x0c00, 0x0fb3, 0x0000 },
+  { 0x8c00, 0x0fb6, 0x2000 },
+  { 0x0c00, 0x0fb5, 0x0000 },
+  { 0x0c00, 0x0fb7, 0x0000 },
+  { 0x8c00, 0x0fbc, 0x3000 },
+  { 0x8c00, 0x0fba, 0x2000 },
+  { 0x0c00, 0x0fb9, 0x0000 },
+  { 0x0c00, 0x0fbb, 0x0000 },
+  { 0x9a00, 0x0fbf, 0x2000 },
+  { 0x1a00, 0x0fbe, 0x0000 },
+  { 0x1a00, 0x0fc0, 0x0000 },
+  { 0x8700, 0x1003, 0x5000 },
+  { 0x9a00, 0x0fc9, 0x4000 },
+  { 0x9a00, 0x0fc5, 0x3000 },
+  { 0x9a00, 0x0fc3, 0x2000 },
+  { 0x1a00, 0x0fc2, 0x0000 },
+  { 0x1a00, 0x0fc4, 0x0000 },
+  { 0x9a00, 0x0fc7, 0x2000 },
+  { 0x0c00, 0x0fc6, 0x0000 },
+  { 0x1a00, 0x0fc8, 0x0000 },
+  { 0x9a00, 0x0fcf, 0x3000 },
+  { 0x9a00, 0x0fcb, 0x2000 },
+  { 0x1a00, 0x0fca, 0x0000 },
+  { 0x1a00, 0x0fcc, 0x0000 },
+  { 0x8700, 0x1001, 0x2000 },
+  { 0x0700, 0x1000, 0x0000 },
+  { 0x0700, 0x1002, 0x0000 },
+  { 0x8700, 0x100b, 0x4000 },
+  { 0x8700, 0x1007, 0x3000 },
+  { 0x8700, 0x1005, 0x2000 },
+  { 0x0700, 0x1004, 0x0000 },
+  { 0x0700, 0x1006, 0x0000 },
+  { 0x8700, 0x1009, 0x2000 },
+  { 0x0700, 0x1008, 0x0000 },
+  { 0x0700, 0x100a, 0x0000 },
+  { 0x8700, 0x100f, 0x3000 },
+  { 0x8700, 0x100d, 0x2000 },
+  { 0x0700, 0x100c, 0x0000 },
+  { 0x0700, 0x100e, 0x0000 },
+  { 0x8700, 0x1011, 0x2000 },
+  { 0x0700, 0x1010, 0x0000 },
+  { 0x0700, 0x1012, 0x0000 },
+  { 0x8900, 0x10a5, 0x7000 },
+  { 0x8c00, 0x1039, 0x6000 },
+  { 0x8700, 0x1024, 0x5000 },
+  { 0x8700, 0x101b, 0x4000 },
+  { 0x8700, 0x1017, 0x3000 },
+  { 0x8700, 0x1015, 0x2000 },
+  { 0x0700, 0x1014, 0x0000 },
+  { 0x0700, 0x1016, 0x0000 },
+  { 0x8700, 0x1019, 0x2000 },
+  { 0x0700, 0x1018, 0x0000 },
+  { 0x0700, 0x101a, 0x0000 },
+  { 0x8700, 0x101f, 0x3000 },
+  { 0x8700, 0x101d, 0x2000 },
+  { 0x0700, 0x101c, 0x0000 },
+  { 0x0700, 0x101e, 0x0000 },
+  { 0x8700, 0x1021, 0x2000 },
+  { 0x0700, 0x1020, 0x0000 },
+  { 0x0700, 0x1023, 0x0000 },
+  { 0x8c00, 0x102e, 0x4000 },
+  { 0x8700, 0x1029, 0x3000 },
+  { 0x8700, 0x1026, 0x2000 },
+  { 0x0700, 0x1025, 0x0000 },
+  { 0x0700, 0x1027, 0x0000 },
+  { 0x8a00, 0x102c, 0x2000 },
+  { 0x0700, 0x102a, 0x0000 },
+  { 0x0c00, 0x102d, 0x0000 },
+  { 0x8c00, 0x1032, 0x3000 },
+  { 0x8c00, 0x1030, 0x2000 },
+  { 0x0c00, 0x102f, 0x0000 },
+  { 0x0a00, 0x1031, 0x0000 },
+  { 0x8c00, 0x1037, 0x2000 },
+  { 0x0c00, 0x1036, 0x0000 },
+  { 0x0a00, 0x1038, 0x0000 },
+  { 0x9500, 0x104f, 0x5000 },
+  { 0x8d00, 0x1047, 0x4000 },
+  { 0x8d00, 0x1043, 0x3000 },
+  { 0x8d00, 0x1041, 0x2000 },
+  { 0x0d00, 0x1040, 0x0000 },
+  { 0x0d00, 0x1042, 0x0000 },
+  { 0x8d00, 0x1045, 0x2000 },
+  { 0x0d00, 0x1044, 0x0000 },
+  { 0x0d00, 0x1046, 0x0000 },
+  { 0x9500, 0x104b, 0x3000 },
+  { 0x8d00, 0x1049, 0x2000 },
+  { 0x0d00, 0x1048, 0x0000 },
+  { 0x1500, 0x104a, 0x0000 },
+  { 0x9500, 0x104d, 0x2000 },
+  { 0x1500, 0x104c, 0x0000 },
+  { 0x1500, 0x104e, 0x0000 },
+  { 0x8a00, 0x1057, 0x4000 },
+  { 0x8700, 0x1053, 0x3000 },
+  { 0x8700, 0x1051, 0x2000 },
+  { 0x0700, 0x1050, 0x0000 },
+  { 0x0700, 0x1052, 0x0000 },
+  { 0x8700, 0x1055, 0x2000 },
+  { 0x0700, 0x1054, 0x0000 },
+  { 0x0a00, 0x1056, 0x0000 },
+  { 0x8900, 0x10a1, 0x3000 },
+  { 0x8c00, 0x1059, 0x2000 },
+  { 0x0c00, 0x1058, 0x0000 },
+  { 0x0900, 0x10a0, 0x0000 },
+  { 0x8900, 0x10a3, 0x2000 },
+  { 0x0900, 0x10a2, 0x0000 },
+  { 0x0900, 0x10a4, 0x0000 },
+  { 0x8900, 0x10c5, 0x6000 },
+  { 0x8900, 0x10b5, 0x5000 },
+  { 0x8900, 0x10ad, 0x4000 },
+  { 0x8900, 0x10a9, 0x3000 },
+  { 0x8900, 0x10a7, 0x2000 },
+  { 0x0900, 0x10a6, 0x0000 },
+  { 0x0900, 0x10a8, 0x0000 },
+  { 0x8900, 0x10ab, 0x2000 },
+  { 0x0900, 0x10aa, 0x0000 },
+  { 0x0900, 0x10ac, 0x0000 },
+  { 0x8900, 0x10b1, 0x3000 },
+  { 0x8900, 0x10af, 0x2000 },
+  { 0x0900, 0x10ae, 0x0000 },
+  { 0x0900, 0x10b0, 0x0000 },
+  { 0x8900, 0x10b3, 0x2000 },
+  { 0x0900, 0x10b2, 0x0000 },
+  { 0x0900, 0x10b4, 0x0000 },
+  { 0x8900, 0x10bd, 0x4000 },
+  { 0x8900, 0x10b9, 0x3000 },
+  { 0x8900, 0x10b7, 0x2000 },
+  { 0x0900, 0x10b6, 0x0000 },
+  { 0x0900, 0x10b8, 0x0000 },
+  { 0x8900, 0x10bb, 0x2000 },
+  { 0x0900, 0x10ba, 0x0000 },
+  { 0x0900, 0x10bc, 0x0000 },
+  { 0x8900, 0x10c1, 0x3000 },
+  { 0x8900, 0x10bf, 0x2000 },
+  { 0x0900, 0x10be, 0x0000 },
+  { 0x0900, 0x10c0, 0x0000 },
+  { 0x8900, 0x10c3, 0x2000 },
+  { 0x0900, 0x10c2, 0x0000 },
+  { 0x0900, 0x10c4, 0x0000 },
+  { 0x8700, 0x10df, 0x5000 },
+  { 0x8700, 0x10d7, 0x4000 },
+  { 0x8700, 0x10d3, 0x3000 },
+  { 0x8700, 0x10d1, 0x2000 },
+  { 0x0700, 0x10d0, 0x0000 },
+  { 0x0700, 0x10d2, 0x0000 },
+  { 0x8700, 0x10d5, 0x2000 },
+  { 0x0700, 0x10d4, 0x0000 },
+  { 0x0700, 0x10d6, 0x0000 },
+  { 0x8700, 0x10db, 0x3000 },
+  { 0x8700, 0x10d9, 0x2000 },
+  { 0x0700, 0x10d8, 0x0000 },
+  { 0x0700, 0x10da, 0x0000 },
+  { 0x8700, 0x10dd, 0x2000 },
+  { 0x0700, 0x10dc, 0x0000 },
+  { 0x0700, 0x10de, 0x0000 },
+  { 0x8700, 0x10e7, 0x4000 },
+  { 0x8700, 0x10e3, 0x3000 },
+  { 0x8700, 0x10e1, 0x2000 },
+  { 0x0700, 0x10e0, 0x0000 },
+  { 0x0700, 0x10e2, 0x0000 },
+  { 0x8700, 0x10e5, 0x2000 },
+  { 0x0700, 0x10e4, 0x0000 },
+  { 0x0700, 0x10e6, 0x0000 },
+  { 0x8700, 0x10eb, 0x3000 },
+  { 0x8700, 0x10e9, 0x2000 },
+  { 0x0700, 0x10e8, 0x0000 },
+  { 0x0700, 0x10ea, 0x0000 },
+  { 0x8700, 0x10ed, 0x2000 },
+  { 0x0700, 0x10ec, 0x0000 },
+  { 0x0700, 0x10ee, 0x0000 },
+  { 0x8700, 0x1322, 0xa000 },
+  { 0x8700, 0x1205, 0x9000 },
+  { 0x8700, 0x117a, 0x8000 },
+  { 0x8700, 0x1135, 0x7000 },
+  { 0x8700, 0x1115, 0x6000 },
+  { 0x8700, 0x1105, 0x5000 },
+  { 0x8700, 0x10f7, 0x4000 },
+  { 0x8700, 0x10f3, 0x3000 },
+  { 0x8700, 0x10f1, 0x2000 },
+  { 0x0700, 0x10f0, 0x0000 },
+  { 0x0700, 0x10f2, 0x0000 },
+  { 0x8700, 0x10f5, 0x2000 },
+  { 0x0700, 0x10f4, 0x0000 },
+  { 0x0700, 0x10f6, 0x0000 },
+  { 0x8700, 0x1101, 0x3000 },
+  { 0x9500, 0x10fb, 0x2000 },
+  { 0x0700, 0x10f8, 0x0000 },
+  { 0x0700, 0x1100, 0x0000 },
+  { 0x8700, 0x1103, 0x2000 },
+  { 0x0700, 0x1102, 0x0000 },
+  { 0x0700, 0x1104, 0x0000 },
+  { 0x8700, 0x110d, 0x4000 },
+  { 0x8700, 0x1109, 0x3000 },
+  { 0x8700, 0x1107, 0x2000 },
+  { 0x0700, 0x1106, 0x0000 },
+  { 0x0700, 0x1108, 0x0000 },
+  { 0x8700, 0x110b, 0x2000 },
+  { 0x0700, 0x110a, 0x0000 },
+  { 0x0700, 0x110c, 0x0000 },
+  { 0x8700, 0x1111, 0x3000 },
+  { 0x8700, 0x110f, 0x2000 },
+  { 0x0700, 0x110e, 0x0000 },
+  { 0x0700, 0x1110, 0x0000 },
+  { 0x8700, 0x1113, 0x2000 },
+  { 0x0700, 0x1112, 0x0000 },
+  { 0x0700, 0x1114, 0x0000 },
+  { 0x8700, 0x1125, 0x5000 },
+  { 0x8700, 0x111d, 0x4000 },
+  { 0x8700, 0x1119, 0x3000 },
+  { 0x8700, 0x1117, 0x2000 },
+  { 0x0700, 0x1116, 0x0000 },
+  { 0x0700, 0x1118, 0x0000 },
+  { 0x8700, 0x111b, 0x2000 },
+  { 0x0700, 0x111a, 0x0000 },
+  { 0x0700, 0x111c, 0x0000 },
+  { 0x8700, 0x1121, 0x3000 },
+  { 0x8700, 0x111f, 0x2000 },
+  { 0x0700, 0x111e, 0x0000 },
+  { 0x0700, 0x1120, 0x0000 },
+  { 0x8700, 0x1123, 0x2000 },
+  { 0x0700, 0x1122, 0x0000 },
+  { 0x0700, 0x1124, 0x0000 },
+  { 0x8700, 0x112d, 0x4000 },
+  { 0x8700, 0x1129, 0x3000 },
+  { 0x8700, 0x1127, 0x2000 },
+  { 0x0700, 0x1126, 0x0000 },
+  { 0x0700, 0x1128, 0x0000 },
+  { 0x8700, 0x112b, 0x2000 },
+  { 0x0700, 0x112a, 0x0000 },
+  { 0x0700, 0x112c, 0x0000 },
+  { 0x8700, 0x1131, 0x3000 },
+  { 0x8700, 0x112f, 0x2000 },
+  { 0x0700, 0x112e, 0x0000 },
+  { 0x0700, 0x1130, 0x0000 },
+  { 0x8700, 0x1133, 0x2000 },
+  { 0x0700, 0x1132, 0x0000 },
+  { 0x0700, 0x1134, 0x0000 },
+  { 0x8700, 0x1155, 0x6000 },
+  { 0x8700, 0x1145, 0x5000 },
+  { 0x8700, 0x113d, 0x4000 },
+  { 0x8700, 0x1139, 0x3000 },
+  { 0x8700, 0x1137, 0x2000 },
+  { 0x0700, 0x1136, 0x0000 },
+  { 0x0700, 0x1138, 0x0000 },
+  { 0x8700, 0x113b, 0x2000 },
+  { 0x0700, 0x113a, 0x0000 },
+  { 0x0700, 0x113c, 0x0000 },
+  { 0x8700, 0x1141, 0x3000 },
+  { 0x8700, 0x113f, 0x2000 },
+  { 0x0700, 0x113e, 0x0000 },
+  { 0x0700, 0x1140, 0x0000 },
+  { 0x8700, 0x1143, 0x2000 },
+  { 0x0700, 0x1142, 0x0000 },
+  { 0x0700, 0x1144, 0x0000 },
+  { 0x8700, 0x114d, 0x4000 },
+  { 0x8700, 0x1149, 0x3000 },
+  { 0x8700, 0x1147, 0x2000 },
+  { 0x0700, 0x1146, 0x0000 },
+  { 0x0700, 0x1148, 0x0000 },
+  { 0x8700, 0x114b, 0x2000 },
+  { 0x0700, 0x114a, 0x0000 },
+  { 0x0700, 0x114c, 0x0000 },
+  { 0x8700, 0x1151, 0x3000 },
+  { 0x8700, 0x114f, 0x2000 },
+  { 0x0700, 0x114e, 0x0000 },
+  { 0x0700, 0x1150, 0x0000 },
+  { 0x8700, 0x1153, 0x2000 },
+  { 0x0700, 0x1152, 0x0000 },
+  { 0x0700, 0x1154, 0x0000 },
+  { 0x8700, 0x116a, 0x5000 },
+  { 0x8700, 0x1162, 0x4000 },
+  { 0x8700, 0x1159, 0x3000 },
+  { 0x8700, 0x1157, 0x2000 },
+  { 0x0700, 0x1156, 0x0000 },
+  { 0x0700, 0x1158, 0x0000 },
+  { 0x8700, 0x1160, 0x2000 },
+  { 0x0700, 0x115f, 0x0000 },
+  { 0x0700, 0x1161, 0x0000 },
+  { 0x8700, 0x1166, 0x3000 },
+  { 0x8700, 0x1164, 0x2000 },
+  { 0x0700, 0x1163, 0x0000 },
+  { 0x0700, 0x1165, 0x0000 },
+  { 0x8700, 0x1168, 0x2000 },
+  { 0x0700, 0x1167, 0x0000 },
+  { 0x0700, 0x1169, 0x0000 },
+  { 0x8700, 0x1172, 0x4000 },
+  { 0x8700, 0x116e, 0x3000 },
+  { 0x8700, 0x116c, 0x2000 },
+  { 0x0700, 0x116b, 0x0000 },
+  { 0x0700, 0x116d, 0x0000 },
+  { 0x8700, 0x1170, 0x2000 },
+  { 0x0700, 0x116f, 0x0000 },
+  { 0x0700, 0x1171, 0x0000 },
+  { 0x8700, 0x1176, 0x3000 },
+  { 0x8700, 0x1174, 0x2000 },
+  { 0x0700, 0x1173, 0x0000 },
+  { 0x0700, 0x1175, 0x0000 },
+  { 0x8700, 0x1178, 0x2000 },
+  { 0x0700, 0x1177, 0x0000 },
+  { 0x0700, 0x1179, 0x0000 },
+  { 0x8700, 0x11bf, 0x7000 },
+  { 0x8700, 0x119a, 0x6000 },
+  { 0x8700, 0x118a, 0x5000 },
+  { 0x8700, 0x1182, 0x4000 },
+  { 0x8700, 0x117e, 0x3000 },
+  { 0x8700, 0x117c, 0x2000 },
+  { 0x0700, 0x117b, 0x0000 },
+  { 0x0700, 0x117d, 0x0000 },
+  { 0x8700, 0x1180, 0x2000 },
+  { 0x0700, 0x117f, 0x0000 },
+  { 0x0700, 0x1181, 0x0000 },
+  { 0x8700, 0x1186, 0x3000 },
+  { 0x8700, 0x1184, 0x2000 },
+  { 0x0700, 0x1183, 0x0000 },
+  { 0x0700, 0x1185, 0x0000 },
+  { 0x8700, 0x1188, 0x2000 },
+  { 0x0700, 0x1187, 0x0000 },
+  { 0x0700, 0x1189, 0x0000 },
+  { 0x8700, 0x1192, 0x4000 },
+  { 0x8700, 0x118e, 0x3000 },
+  { 0x8700, 0x118c, 0x2000 },
+  { 0x0700, 0x118b, 0x0000 },
+  { 0x0700, 0x118d, 0x0000 },
+  { 0x8700, 0x1190, 0x2000 },
+  { 0x0700, 0x118f, 0x0000 },
+  { 0x0700, 0x1191, 0x0000 },
+  { 0x8700, 0x1196, 0x3000 },
+  { 0x8700, 0x1194, 0x2000 },
+  { 0x0700, 0x1193, 0x0000 },
+  { 0x0700, 0x1195, 0x0000 },
+  { 0x8700, 0x1198, 0x2000 },
+  { 0x0700, 0x1197, 0x0000 },
+  { 0x0700, 0x1199, 0x0000 },
+  { 0x8700, 0x11af, 0x5000 },
+  { 0x8700, 0x11a2, 0x4000 },
+  { 0x8700, 0x119e, 0x3000 },
+  { 0x8700, 0x119c, 0x2000 },
+  { 0x0700, 0x119b, 0x0000 },
+  { 0x0700, 0x119d, 0x0000 },
+  { 0x8700, 0x11a0, 0x2000 },
+  { 0x0700, 0x119f, 0x0000 },
+  { 0x0700, 0x11a1, 0x0000 },
+  { 0x8700, 0x11ab, 0x3000 },
+  { 0x8700, 0x11a9, 0x2000 },
+  { 0x0700, 0x11a8, 0x0000 },
+  { 0x0700, 0x11aa, 0x0000 },
+  { 0x8700, 0x11ad, 0x2000 },
+  { 0x0700, 0x11ac, 0x0000 },
+  { 0x0700, 0x11ae, 0x0000 },
+  { 0x8700, 0x11b7, 0x4000 },
+  { 0x8700, 0x11b3, 0x3000 },
+  { 0x8700, 0x11b1, 0x2000 },
+  { 0x0700, 0x11b0, 0x0000 },
+  { 0x0700, 0x11b2, 0x0000 },
+  { 0x8700, 0x11b5, 0x2000 },
+  { 0x0700, 0x11b4, 0x0000 },
+  { 0x0700, 0x11b6, 0x0000 },
+  { 0x8700, 0x11bb, 0x3000 },
+  { 0x8700, 0x11b9, 0x2000 },
+  { 0x0700, 0x11b8, 0x0000 },
+  { 0x0700, 0x11ba, 0x0000 },
+  { 0x8700, 0x11bd, 0x2000 },
+  { 0x0700, 0x11bc, 0x0000 },
+  { 0x0700, 0x11be, 0x0000 },
+  { 0x8700, 0x11df, 0x6000 },
+  { 0x8700, 0x11cf, 0x5000 },
+  { 0x8700, 0x11c7, 0x4000 },
+  { 0x8700, 0x11c3, 0x3000 },
+  { 0x8700, 0x11c1, 0x2000 },
+  { 0x0700, 0x11c0, 0x0000 },
+  { 0x0700, 0x11c2, 0x0000 },
+  { 0x8700, 0x11c5, 0x2000 },
+  { 0x0700, 0x11c4, 0x0000 },
+  { 0x0700, 0x11c6, 0x0000 },
+  { 0x8700, 0x11cb, 0x3000 },
+  { 0x8700, 0x11c9, 0x2000 },
+  { 0x0700, 0x11c8, 0x0000 },
+  { 0x0700, 0x11ca, 0x0000 },
+  { 0x8700, 0x11cd, 0x2000 },
+  { 0x0700, 0x11cc, 0x0000 },
+  { 0x0700, 0x11ce, 0x0000 },
+  { 0x8700, 0x11d7, 0x4000 },
+  { 0x8700, 0x11d3, 0x3000 },
+  { 0x8700, 0x11d1, 0x2000 },
+  { 0x0700, 0x11d0, 0x0000 },
+  { 0x0700, 0x11d2, 0x0000 },
+  { 0x8700, 0x11d5, 0x2000 },
+  { 0x0700, 0x11d4, 0x0000 },
+  { 0x0700, 0x11d6, 0x0000 },
+  { 0x8700, 0x11db, 0x3000 },
+  { 0x8700, 0x11d9, 0x2000 },
+  { 0x0700, 0x11d8, 0x0000 },
+  { 0x0700, 0x11da, 0x0000 },
+  { 0x8700, 0x11dd, 0x2000 },
+  { 0x0700, 0x11dc, 0x0000 },
+  { 0x0700, 0x11de, 0x0000 },
+  { 0x8700, 0x11ef, 0x5000 },
+  { 0x8700, 0x11e7, 0x4000 },
+  { 0x8700, 0x11e3, 0x3000 },
+  { 0x8700, 0x11e1, 0x2000 },
+  { 0x0700, 0x11e0, 0x0000 },
+  { 0x0700, 0x11e2, 0x0000 },
+  { 0x8700, 0x11e5, 0x2000 },
+  { 0x0700, 0x11e4, 0x0000 },
+  { 0x0700, 0x11e6, 0x0000 },
+  { 0x8700, 0x11eb, 0x3000 },
+  { 0x8700, 0x11e9, 0x2000 },
+  { 0x0700, 0x11e8, 0x0000 },
+  { 0x0700, 0x11ea, 0x0000 },
+  { 0x8700, 0x11ed, 0x2000 },
+  { 0x0700, 0x11ec, 0x0000 },
+  { 0x0700, 0x11ee, 0x0000 },
+  { 0x8700, 0x11f7, 0x4000 },
+  { 0x8700, 0x11f3, 0x3000 },
+  { 0x8700, 0x11f1, 0x2000 },
+  { 0x0700, 0x11f0, 0x0000 },
+  { 0x0700, 0x11f2, 0x0000 },
+  { 0x8700, 0x11f5, 0x2000 },
+  { 0x0700, 0x11f4, 0x0000 },
+  { 0x0700, 0x11f6, 0x0000 },
+  { 0x8700, 0x1201, 0x3000 },
+  { 0x8700, 0x11f9, 0x2000 },
+  { 0x0700, 0x11f8, 0x0000 },
+  { 0x0700, 0x1200, 0x0000 },
+  { 0x8700, 0x1203, 0x2000 },
+  { 0x0700, 0x1202, 0x0000 },
+  { 0x0700, 0x1204, 0x0000 },
+  { 0x8700, 0x1292, 0x8000 },
+  { 0x8700, 0x1246, 0x7000 },
+  { 0x8700, 0x1226, 0x6000 },
+  { 0x8700, 0x1216, 0x5000 },
+  { 0x8700, 0x120e, 0x4000 },
+  { 0x8700, 0x120a, 0x3000 },
+  { 0x8700, 0x1208, 0x2000 },
+  { 0x0700, 0x1206, 0x0000 },
+  { 0x0700, 0x1209, 0x0000 },
+  { 0x8700, 0x120c, 0x2000 },
+  { 0x0700, 0x120b, 0x0000 },
+  { 0x0700, 0x120d, 0x0000 },
+  { 0x8700, 0x1212, 0x3000 },
+  { 0x8700, 0x1210, 0x2000 },
+  { 0x0700, 0x120f, 0x0000 },
+  { 0x0700, 0x1211, 0x0000 },
+  { 0x8700, 0x1214, 0x2000 },
+  { 0x0700, 0x1213, 0x0000 },
+  { 0x0700, 0x1215, 0x0000 },
+  { 0x8700, 0x121e, 0x4000 },
+  { 0x8700, 0x121a, 0x3000 },
+  { 0x8700, 0x1218, 0x2000 },
+  { 0x0700, 0x1217, 0x0000 },
+  { 0x0700, 0x1219, 0x0000 },
+  { 0x8700, 0x121c, 0x2000 },
+  { 0x0700, 0x121b, 0x0000 },
+  { 0x0700, 0x121d, 0x0000 },
+  { 0x8700, 0x1222, 0x3000 },
+  { 0x8700, 0x1220, 0x2000 },
+  { 0x0700, 0x121f, 0x0000 },
+  { 0x0700, 0x1221, 0x0000 },
+  { 0x8700, 0x1224, 0x2000 },
+  { 0x0700, 0x1223, 0x0000 },
+  { 0x0700, 0x1225, 0x0000 },
+  { 0x8700, 0x1236, 0x5000 },
+  { 0x8700, 0x122e, 0x4000 },
+  { 0x8700, 0x122a, 0x3000 },
+  { 0x8700, 0x1228, 0x2000 },
+  { 0x0700, 0x1227, 0x0000 },
+  { 0x0700, 0x1229, 0x0000 },
+  { 0x8700, 0x122c, 0x2000 },
+  { 0x0700, 0x122b, 0x0000 },
+  { 0x0700, 0x122d, 0x0000 },
+  { 0x8700, 0x1232, 0x3000 },
+  { 0x8700, 0x1230, 0x2000 },
+  { 0x0700, 0x122f, 0x0000 },
+  { 0x0700, 0x1231, 0x0000 },
+  { 0x8700, 0x1234, 0x2000 },
+  { 0x0700, 0x1233, 0x0000 },
+  { 0x0700, 0x1235, 0x0000 },
+  { 0x8700, 0x123e, 0x4000 },
+  { 0x8700, 0x123a, 0x3000 },
+  { 0x8700, 0x1238, 0x2000 },
+  { 0x0700, 0x1237, 0x0000 },
+  { 0x0700, 0x1239, 0x0000 },
+  { 0x8700, 0x123c, 0x2000 },
+  { 0x0700, 0x123b, 0x0000 },
+  { 0x0700, 0x123d, 0x0000 },
+  { 0x8700, 0x1242, 0x3000 },
+  { 0x8700, 0x1240, 0x2000 },
+  { 0x0700, 0x123f, 0x0000 },
+  { 0x0700, 0x1241, 0x0000 },
+  { 0x8700, 0x1244, 0x2000 },
+  { 0x0700, 0x1243, 0x0000 },
+  { 0x0700, 0x1245, 0x0000 },
+  { 0x8700, 0x126e, 0x6000 },
+  { 0x8700, 0x125c, 0x5000 },
+  { 0x8700, 0x1252, 0x4000 },
+  { 0x8700, 0x124c, 0x3000 },
+  { 0x8700, 0x124a, 0x2000 },
+  { 0x0700, 0x1248, 0x0000 },
+  { 0x0700, 0x124b, 0x0000 },
+  { 0x8700, 0x1250, 0x2000 },
+  { 0x0700, 0x124d, 0x0000 },
+  { 0x0700, 0x1251, 0x0000 },
+  { 0x8700, 0x1256, 0x3000 },
+  { 0x8700, 0x1254, 0x2000 },
+  { 0x0700, 0x1253, 0x0000 },
+  { 0x0700, 0x1255, 0x0000 },
+  { 0x8700, 0x125a, 0x2000 },
+  { 0x0700, 0x1258, 0x0000 },
+  { 0x0700, 0x125b, 0x0000 },
+  { 0x8700, 0x1266, 0x4000 },
+  { 0x8700, 0x1262, 0x3000 },
+  { 0x8700, 0x1260, 0x2000 },
+  { 0x0700, 0x125d, 0x0000 },
+  { 0x0700, 0x1261, 0x0000 },
+  { 0x8700, 0x1264, 0x2000 },
+  { 0x0700, 0x1263, 0x0000 },
+  { 0x0700, 0x1265, 0x0000 },
+  { 0x8700, 0x126a, 0x3000 },
+  { 0x8700, 0x1268, 0x2000 },
+  { 0x0700, 0x1267, 0x0000 },
+  { 0x0700, 0x1269, 0x0000 },
+  { 0x8700, 0x126c, 0x2000 },
+  { 0x0700, 0x126b, 0x0000 },
+  { 0x0700, 0x126d, 0x0000 },
+  { 0x8700, 0x127e, 0x5000 },
+  { 0x8700, 0x1276, 0x4000 },
+  { 0x8700, 0x1272, 0x3000 },
+  { 0x8700, 0x1270, 0x2000 },
+  { 0x0700, 0x126f, 0x0000 },
+  { 0x0700, 0x1271, 0x0000 },
+  { 0x8700, 0x1274, 0x2000 },
+  { 0x0700, 0x1273, 0x0000 },
+  { 0x0700, 0x1275, 0x0000 },
+  { 0x8700, 0x127a, 0x3000 },
+  { 0x8700, 0x1278, 0x2000 },
+  { 0x0700, 0x1277, 0x0000 },
+  { 0x0700, 0x1279, 0x0000 },
+  { 0x8700, 0x127c, 0x2000 },
+  { 0x0700, 0x127b, 0x0000 },
+  { 0x0700, 0x127d, 0x0000 },
+  { 0x8700, 0x1286, 0x4000 },
+  { 0x8700, 0x1282, 0x3000 },
+  { 0x8700, 0x1280, 0x2000 },
+  { 0x0700, 0x127f, 0x0000 },
+  { 0x0700, 0x1281, 0x0000 },
+  { 0x8700, 0x1284, 0x2000 },
+  { 0x0700, 0x1283, 0x0000 },
+  { 0x0700, 0x1285, 0x0000 },
+  { 0x8700, 0x128c, 0x3000 },
+  { 0x8700, 0x128a, 0x2000 },
+  { 0x0700, 0x1288, 0x0000 },
+  { 0x0700, 0x128b, 0x0000 },
+  { 0x8700, 0x1290, 0x2000 },
+  { 0x0700, 0x128d, 0x0000 },
+  { 0x0700, 0x1291, 0x0000 },
+  { 0x8700, 0x12dc, 0x7000 },
+  { 0x8700, 0x12b4, 0x6000 },
+  { 0x8700, 0x12a2, 0x5000 },
+  { 0x8700, 0x129a, 0x4000 },
+  { 0x8700, 0x1296, 0x3000 },
+  { 0x8700, 0x1294, 0x2000 },
+  { 0x0700, 0x1293, 0x0000 },
+  { 0x0700, 0x1295, 0x0000 },
+  { 0x8700, 0x1298, 0x2000 },
+  { 0x0700, 0x1297, 0x0000 },
+  { 0x0700, 0x1299, 0x0000 },
+  { 0x8700, 0x129e, 0x3000 },
+  { 0x8700, 0x129c, 0x2000 },
+  { 0x0700, 0x129b, 0x0000 },
+  { 0x0700, 0x129d, 0x0000 },
+  { 0x8700, 0x12a0, 0x2000 },
+  { 0x0700, 0x129f, 0x0000 },
+  { 0x0700, 0x12a1, 0x0000 },
+  { 0x8700, 0x12aa, 0x4000 },
+  { 0x8700, 0x12a6, 0x3000 },
+  { 0x8700, 0x12a4, 0x2000 },
+  { 0x0700, 0x12a3, 0x0000 },
+  { 0x0700, 0x12a5, 0x0000 },
+  { 0x8700, 0x12a8, 0x2000 },
+  { 0x0700, 0x12a7, 0x0000 },
+  { 0x0700, 0x12a9, 0x0000 },
+  { 0x8700, 0x12ae, 0x3000 },
+  { 0x8700, 0x12ac, 0x2000 },
+  { 0x0700, 0x12ab, 0x0000 },
+  { 0x0700, 0x12ad, 0x0000 },
+  { 0x8700, 0x12b2, 0x2000 },
+  { 0x0700, 0x12b0, 0x0000 },
+  { 0x0700, 0x12b3, 0x0000 },
+  { 0x8700, 0x12ca, 0x5000 },
+  { 0x8700, 0x12be, 0x4000 },
+  { 0x8700, 0x12ba, 0x3000 },
+  { 0x8700, 0x12b8, 0x2000 },
+  { 0x0700, 0x12b5, 0x0000 },
+  { 0x0700, 0x12b9, 0x0000 },
+  { 0x8700, 0x12bc, 0x2000 },
+  { 0x0700, 0x12bb, 0x0000 },
+  { 0x0700, 0x12bd, 0x0000 },
+  { 0x8700, 0x12c4, 0x3000 },
+  { 0x8700, 0x12c2, 0x2000 },
+  { 0x0700, 0x12c0, 0x0000 },
+  { 0x0700, 0x12c3, 0x0000 },
+  { 0x8700, 0x12c8, 0x2000 },
+  { 0x0700, 0x12c5, 0x0000 },
+  { 0x0700, 0x12c9, 0x0000 },
+  { 0x8700, 0x12d3, 0x4000 },
+  { 0x8700, 0x12ce, 0x3000 },
+  { 0x8700, 0x12cc, 0x2000 },
+  { 0x0700, 0x12cb, 0x0000 },
+  { 0x0700, 0x12cd, 0x0000 },
+  { 0x8700, 0x12d1, 0x2000 },
+  { 0x0700, 0x12d0, 0x0000 },
+  { 0x0700, 0x12d2, 0x0000 },
+  { 0x8700, 0x12d8, 0x3000 },
+  { 0x8700, 0x12d5, 0x2000 },
+  { 0x0700, 0x12d4, 0x0000 },
+  { 0x0700, 0x12d6, 0x0000 },
+  { 0x8700, 0x12da, 0x2000 },
+  { 0x0700, 0x12d9, 0x0000 },
+  { 0x0700, 0x12db, 0x0000 },
+  { 0x8700, 0x12fd, 0x6000 },
+  { 0x8700, 0x12ec, 0x5000 },
+  { 0x8700, 0x12e4, 0x4000 },
+  { 0x8700, 0x12e0, 0x3000 },
+  { 0x8700, 0x12de, 0x2000 },
+  { 0x0700, 0x12dd, 0x0000 },
+  { 0x0700, 0x12df, 0x0000 },
+  { 0x8700, 0x12e2, 0x2000 },
+  { 0x0700, 0x12e1, 0x0000 },
+  { 0x0700, 0x12e3, 0x0000 },
+  { 0x8700, 0x12e8, 0x3000 },
+  { 0x8700, 0x12e6, 0x2000 },
+  { 0x0700, 0x12e5, 0x0000 },
+  { 0x0700, 0x12e7, 0x0000 },
+  { 0x8700, 0x12ea, 0x2000 },
+  { 0x0700, 0x12e9, 0x0000 },
+  { 0x0700, 0x12eb, 0x0000 },
+  { 0x8700, 0x12f5, 0x4000 },
+  { 0x8700, 0x12f1, 0x3000 },
+  { 0x8700, 0x12ee, 0x2000 },
+  { 0x0700, 0x12ed, 0x0000 },
+  { 0x0700, 0x12f0, 0x0000 },
+  { 0x8700, 0x12f3, 0x2000 },
+  { 0x0700, 0x12f2, 0x0000 },
+  { 0x0700, 0x12f4, 0x0000 },
+  { 0x8700, 0x12f9, 0x3000 },
+  { 0x8700, 0x12f7, 0x2000 },
+  { 0x0700, 0x12f6, 0x0000 },
+  { 0x0700, 0x12f8, 0x0000 },
+  { 0x8700, 0x12fb, 0x2000 },
+  { 0x0700, 0x12fa, 0x0000 },
+  { 0x0700, 0x12fc, 0x0000 },
+  { 0x8700, 0x130d, 0x5000 },
+  { 0x8700, 0x1305, 0x4000 },
+  { 0x8700, 0x1301, 0x3000 },
+  { 0x8700, 0x12ff, 0x2000 },
+  { 0x0700, 0x12fe, 0x0000 },
+  { 0x0700, 0x1300, 0x0000 },
+  { 0x8700, 0x1303, 0x2000 },
+  { 0x0700, 0x1302, 0x0000 },
+  { 0x0700, 0x1304, 0x0000 },
+  { 0x8700, 0x1309, 0x3000 },
+  { 0x8700, 0x1307, 0x2000 },
+  { 0x0700, 0x1306, 0x0000 },
+  { 0x0700, 0x1308, 0x0000 },
+  { 0x8700, 0x130b, 0x2000 },
+  { 0x0700, 0x130a, 0x0000 },
+  { 0x0700, 0x130c, 0x0000 },
+  { 0x8700, 0x1319, 0x4000 },
+  { 0x8700, 0x1313, 0x3000 },
+  { 0x8700, 0x1310, 0x2000 },
+  { 0x0700, 0x130e, 0x0000 },
+  { 0x0700, 0x1312, 0x0000 },
+  { 0x8700, 0x1315, 0x2000 },
+  { 0x0700, 0x1314, 0x0000 },
+  { 0x0700, 0x1318, 0x0000 },
+  { 0x8700, 0x131d, 0x3000 },
+  { 0x8700, 0x131b, 0x2000 },
+  { 0x0700, 0x131a, 0x0000 },
+  { 0x0700, 0x131c, 0x0000 },
+  { 0x8700, 0x1320, 0x2000 },
+  { 0x0700, 0x131e, 0x0000 },
+  { 0x0700, 0x1321, 0x0000 },
+  { 0x8700, 0x1458, 0x9000 },
+  { 0x8700, 0x13cc, 0x8000 },
+  { 0x8d00, 0x1369, 0x7000 },
+  { 0x8700, 0x1342, 0x6000 },
+  { 0x8700, 0x1332, 0x5000 },
+  { 0x8700, 0x132a, 0x4000 },
+  { 0x8700, 0x1326, 0x3000 },
+  { 0x8700, 0x1324, 0x2000 },
+  { 0x0700, 0x1323, 0x0000 },
+  { 0x0700, 0x1325, 0x0000 },
+  { 0x8700, 0x1328, 0x2000 },
+  { 0x0700, 0x1327, 0x0000 },
+  { 0x0700, 0x1329, 0x0000 },
+  { 0x8700, 0x132e, 0x3000 },
+  { 0x8700, 0x132c, 0x2000 },
+  { 0x0700, 0x132b, 0x0000 },
+  { 0x0700, 0x132d, 0x0000 },
+  { 0x8700, 0x1330, 0x2000 },
+  { 0x0700, 0x132f, 0x0000 },
+  { 0x0700, 0x1331, 0x0000 },
+  { 0x8700, 0x133a, 0x4000 },
+  { 0x8700, 0x1336, 0x3000 },
+  { 0x8700, 0x1334, 0x2000 },
+  { 0x0700, 0x1333, 0x0000 },
+  { 0x0700, 0x1335, 0x0000 },
+  { 0x8700, 0x1338, 0x2000 },
+  { 0x0700, 0x1337, 0x0000 },
+  { 0x0700, 0x1339, 0x0000 },
+  { 0x8700, 0x133e, 0x3000 },
+  { 0x8700, 0x133c, 0x2000 },
+  { 0x0700, 0x133b, 0x0000 },
+  { 0x0700, 0x133d, 0x0000 },
+  { 0x8700, 0x1340, 0x2000 },
+  { 0x0700, 0x133f, 0x0000 },
+  { 0x0700, 0x1341, 0x0000 },
+  { 0x8700, 0x1353, 0x5000 },
+  { 0x8700, 0x134b, 0x4000 },
+  { 0x8700, 0x1346, 0x3000 },
+  { 0x8700, 0x1344, 0x2000 },
+  { 0x0700, 0x1343, 0x0000 },
+  { 0x0700, 0x1345, 0x0000 },
+  { 0x8700, 0x1349, 0x2000 },
+  { 0x0700, 0x1348, 0x0000 },
+  { 0x0700, 0x134a, 0x0000 },
+  { 0x8700, 0x134f, 0x3000 },
+  { 0x8700, 0x134d, 0x2000 },
+  { 0x0700, 0x134c, 0x0000 },
+  { 0x0700, 0x134e, 0x0000 },
+  { 0x8700, 0x1351, 0x2000 },
+  { 0x0700, 0x1350, 0x0000 },
+  { 0x0700, 0x1352, 0x0000 },
+  { 0x9500, 0x1361, 0x4000 },
+  { 0x8700, 0x1357, 0x3000 },
+  { 0x8700, 0x1355, 0x2000 },
+  { 0x0700, 0x1354, 0x0000 },
+  { 0x0700, 0x1356, 0x0000 },
+  { 0x8700, 0x1359, 0x2000 },
+  { 0x0700, 0x1358, 0x0000 },
+  { 0x0700, 0x135a, 0x0000 },
+  { 0x9500, 0x1365, 0x3000 },
+  { 0x9500, 0x1363, 0x2000 },
+  { 0x1500, 0x1362, 0x0000 },
+  { 0x1500, 0x1364, 0x0000 },
+  { 0x9500, 0x1367, 0x2000 },
+  { 0x1500, 0x1366, 0x0000 },
+  { 0x1500, 0x1368, 0x0000 },
+  { 0x8700, 0x13ac, 0x6000 },
+  { 0x8f00, 0x1379, 0x5000 },
+  { 0x8d00, 0x1371, 0x4000 },
+  { 0x8d00, 0x136d, 0x3000 },
+  { 0x8d00, 0x136b, 0x2000 },
+  { 0x0d00, 0x136a, 0x0000 },
+  { 0x0d00, 0x136c, 0x0000 },
+  { 0x8d00, 0x136f, 0x2000 },
+  { 0x0d00, 0x136e, 0x0000 },
+  { 0x0d00, 0x1370, 0x0000 },
+  { 0x8f00, 0x1375, 0x3000 },
+  { 0x8f00, 0x1373, 0x2000 },
+  { 0x0f00, 0x1372, 0x0000 },
+  { 0x0f00, 0x1374, 0x0000 },
+  { 0x8f00, 0x1377, 0x2000 },
+  { 0x0f00, 0x1376, 0x0000 },
+  { 0x0f00, 0x1378, 0x0000 },
+  { 0x8700, 0x13a4, 0x4000 },
+  { 0x8700, 0x13a0, 0x3000 },
+  { 0x8f00, 0x137b, 0x2000 },
+  { 0x0f00, 0x137a, 0x0000 },
+  { 0x0f00, 0x137c, 0x0000 },
+  { 0x8700, 0x13a2, 0x2000 },
+  { 0x0700, 0x13a1, 0x0000 },
+  { 0x0700, 0x13a3, 0x0000 },
+  { 0x8700, 0x13a8, 0x3000 },
+  { 0x8700, 0x13a6, 0x2000 },
+  { 0x0700, 0x13a5, 0x0000 },
+  { 0x0700, 0x13a7, 0x0000 },
+  { 0x8700, 0x13aa, 0x2000 },
+  { 0x0700, 0x13a9, 0x0000 },
+  { 0x0700, 0x13ab, 0x0000 },
+  { 0x8700, 0x13bc, 0x5000 },
+  { 0x8700, 0x13b4, 0x4000 },
+  { 0x8700, 0x13b0, 0x3000 },
+  { 0x8700, 0x13ae, 0x2000 },
+  { 0x0700, 0x13ad, 0x0000 },
+  { 0x0700, 0x13af, 0x0000 },
+  { 0x8700, 0x13b2, 0x2000 },
+  { 0x0700, 0x13b1, 0x0000 },
+  { 0x0700, 0x13b3, 0x0000 },
+  { 0x8700, 0x13b8, 0x3000 },
+  { 0x8700, 0x13b6, 0x2000 },
+  { 0x0700, 0x13b5, 0x0000 },
+  { 0x0700, 0x13b7, 0x0000 },
+  { 0x8700, 0x13ba, 0x2000 },
+  { 0x0700, 0x13b9, 0x0000 },
+  { 0x0700, 0x13bb, 0x0000 },
+  { 0x8700, 0x13c4, 0x4000 },
+  { 0x8700, 0x13c0, 0x3000 },
+  { 0x8700, 0x13be, 0x2000 },
+  { 0x0700, 0x13bd, 0x0000 },
+  { 0x0700, 0x13bf, 0x0000 },
+  { 0x8700, 0x13c2, 0x2000 },
+  { 0x0700, 0x13c1, 0x0000 },
+  { 0x0700, 0x13c3, 0x0000 },
+  { 0x8700, 0x13c8, 0x3000 },
+  { 0x8700, 0x13c6, 0x2000 },
+  { 0x0700, 0x13c5, 0x0000 },
+  { 0x0700, 0x13c7, 0x0000 },
+  { 0x8700, 0x13ca, 0x2000 },
+  { 0x0700, 0x13c9, 0x0000 },
+  { 0x0700, 0x13cb, 0x0000 },
+  { 0x8700, 0x1418, 0x7000 },
+  { 0x8700, 0x13ec, 0x6000 },
+  { 0x8700, 0x13dc, 0x5000 },
+  { 0x8700, 0x13d4, 0x4000 },
+  { 0x8700, 0x13d0, 0x3000 },
+  { 0x8700, 0x13ce, 0x2000 },
+  { 0x0700, 0x13cd, 0x0000 },
+  { 0x0700, 0x13cf, 0x0000 },
+  { 0x8700, 0x13d2, 0x2000 },
+  { 0x0700, 0x13d1, 0x0000 },
+  { 0x0700, 0x13d3, 0x0000 },
+  { 0x8700, 0x13d8, 0x3000 },
+  { 0x8700, 0x13d6, 0x2000 },
+  { 0x0700, 0x13d5, 0x0000 },
+  { 0x0700, 0x13d7, 0x0000 },
+  { 0x8700, 0x13da, 0x2000 },
+  { 0x0700, 0x13d9, 0x0000 },
+  { 0x0700, 0x13db, 0x0000 },
+  { 0x8700, 0x13e4, 0x4000 },
+  { 0x8700, 0x13e0, 0x3000 },
+  { 0x8700, 0x13de, 0x2000 },
+  { 0x0700, 0x13dd, 0x0000 },
+  { 0x0700, 0x13df, 0x0000 },
+  { 0x8700, 0x13e2, 0x2000 },
+  { 0x0700, 0x13e1, 0x0000 },
+  { 0x0700, 0x13e3, 0x0000 },
+  { 0x8700, 0x13e8, 0x3000 },
+  { 0x8700, 0x13e6, 0x2000 },
+  { 0x0700, 0x13e5, 0x0000 },
+  { 0x0700, 0x13e7, 0x0000 },
+  { 0x8700, 0x13ea, 0x2000 },
+  { 0x0700, 0x13e9, 0x0000 },
+  { 0x0700, 0x13eb, 0x0000 },
+  { 0x8700, 0x1408, 0x5000 },
+  { 0x8700, 0x13f4, 0x4000 },
+  { 0x8700, 0x13f0, 0x3000 },
+  { 0x8700, 0x13ee, 0x2000 },
+  { 0x0700, 0x13ed, 0x0000 },
+  { 0x0700, 0x13ef, 0x0000 },
+  { 0x8700, 0x13f2, 0x2000 },
+  { 0x0700, 0x13f1, 0x0000 },
+  { 0x0700, 0x13f3, 0x0000 },
+  { 0x8700, 0x1404, 0x3000 },
+  { 0x8700, 0x1402, 0x2000 },
+  { 0x0700, 0x1401, 0x0000 },
+  { 0x0700, 0x1403, 0x0000 },
+  { 0x8700, 0x1406, 0x2000 },
+  { 0x0700, 0x1405, 0x0000 },
+  { 0x0700, 0x1407, 0x0000 },
+  { 0x8700, 0x1410, 0x4000 },
+  { 0x8700, 0x140c, 0x3000 },
+  { 0x8700, 0x140a, 0x2000 },
+  { 0x0700, 0x1409, 0x0000 },
+  { 0x0700, 0x140b, 0x0000 },
+  { 0x8700, 0x140e, 0x2000 },
+  { 0x0700, 0x140d, 0x0000 },
+  { 0x0700, 0x140f, 0x0000 },
+  { 0x8700, 0x1414, 0x3000 },
+  { 0x8700, 0x1412, 0x2000 },
+  { 0x0700, 0x1411, 0x0000 },
+  { 0x0700, 0x1413, 0x0000 },
+  { 0x8700, 0x1416, 0x2000 },
+  { 0x0700, 0x1415, 0x0000 },
+  { 0x0700, 0x1417, 0x0000 },
+  { 0x8700, 0x1438, 0x6000 },
+  { 0x8700, 0x1428, 0x5000 },
+  { 0x8700, 0x1420, 0x4000 },
+  { 0x8700, 0x141c, 0x3000 },
+  { 0x8700, 0x141a, 0x2000 },
+  { 0x0700, 0x1419, 0x0000 },
+  { 0x0700, 0x141b, 0x0000 },
+  { 0x8700, 0x141e, 0x2000 },
+  { 0x0700, 0x141d, 0x0000 },
+  { 0x0700, 0x141f, 0x0000 },
+  { 0x8700, 0x1424, 0x3000 },
+  { 0x8700, 0x1422, 0x2000 },
+  { 0x0700, 0x1421, 0x0000 },
+  { 0x0700, 0x1423, 0x0000 },
+  { 0x8700, 0x1426, 0x2000 },
+  { 0x0700, 0x1425, 0x0000 },
+  { 0x0700, 0x1427, 0x0000 },
+  { 0x8700, 0x1430, 0x4000 },
+  { 0x8700, 0x142c, 0x3000 },
+  { 0x8700, 0x142a, 0x2000 },
+  { 0x0700, 0x1429, 0x0000 },
+  { 0x0700, 0x142b, 0x0000 },
+  { 0x8700, 0x142e, 0x2000 },
+  { 0x0700, 0x142d, 0x0000 },
+  { 0x0700, 0x142f, 0x0000 },
+  { 0x8700, 0x1434, 0x3000 },
+  { 0x8700, 0x1432, 0x2000 },
+  { 0x0700, 0x1431, 0x0000 },
+  { 0x0700, 0x1433, 0x0000 },
+  { 0x8700, 0x1436, 0x2000 },
+  { 0x0700, 0x1435, 0x0000 },
+  { 0x0700, 0x1437, 0x0000 },
+  { 0x8700, 0x1448, 0x5000 },
+  { 0x8700, 0x1440, 0x4000 },
+  { 0x8700, 0x143c, 0x3000 },
+  { 0x8700, 0x143a, 0x2000 },
+  { 0x0700, 0x1439, 0x0000 },
+  { 0x0700, 0x143b, 0x0000 },
+  { 0x8700, 0x143e, 0x2000 },
+  { 0x0700, 0x143d, 0x0000 },
+  { 0x0700, 0x143f, 0x0000 },
+  { 0x8700, 0x1444, 0x3000 },
+  { 0x8700, 0x1442, 0x2000 },
+  { 0x0700, 0x1441, 0x0000 },
+  { 0x0700, 0x1443, 0x0000 },
+  { 0x8700, 0x1446, 0x2000 },
+  { 0x0700, 0x1445, 0x0000 },
+  { 0x0700, 0x1447, 0x0000 },
+  { 0x8700, 0x1450, 0x4000 },
+  { 0x8700, 0x144c, 0x3000 },
+  { 0x8700, 0x144a, 0x2000 },
+  { 0x0700, 0x1449, 0x0000 },
+  { 0x0700, 0x144b, 0x0000 },
+  { 0x8700, 0x144e, 0x2000 },
+  { 0x0700, 0x144d, 0x0000 },
+  { 0x0700, 0x144f, 0x0000 },
+  { 0x8700, 0x1454, 0x3000 },
+  { 0x8700, 0x1452, 0x2000 },
+  { 0x0700, 0x1451, 0x0000 },
+  { 0x0700, 0x1453, 0x0000 },
+  { 0x8700, 0x1456, 0x2000 },
+  { 0x0700, 0x1455, 0x0000 },
+  { 0x0700, 0x1457, 0x0000 },
+  { 0x8700, 0x14d8, 0x8000 },
+  { 0x8700, 0x1498, 0x7000 },
+  { 0x8700, 0x1478, 0x6000 },
+  { 0x8700, 0x1468, 0x5000 },
+  { 0x8700, 0x1460, 0x4000 },
+  { 0x8700, 0x145c, 0x3000 },
+  { 0x8700, 0x145a, 0x2000 },
+  { 0x0700, 0x1459, 0x0000 },
+  { 0x0700, 0x145b, 0x0000 },
+  { 0x8700, 0x145e, 0x2000 },
+  { 0x0700, 0x145d, 0x0000 },
+  { 0x0700, 0x145f, 0x0000 },
+  { 0x8700, 0x1464, 0x3000 },
+  { 0x8700, 0x1462, 0x2000 },
+  { 0x0700, 0x1461, 0x0000 },
+  { 0x0700, 0x1463, 0x0000 },
+  { 0x8700, 0x1466, 0x2000 },
+  { 0x0700, 0x1465, 0x0000 },
+  { 0x0700, 0x1467, 0x0000 },
+  { 0x8700, 0x1470, 0x4000 },
+  { 0x8700, 0x146c, 0x3000 },
+  { 0x8700, 0x146a, 0x2000 },
+  { 0x0700, 0x1469, 0x0000 },
+  { 0x0700, 0x146b, 0x0000 },
+  { 0x8700, 0x146e, 0x2000 },
+  { 0x0700, 0x146d, 0x0000 },
+  { 0x0700, 0x146f, 0x0000 },
+  { 0x8700, 0x1474, 0x3000 },
+  { 0x8700, 0x1472, 0x2000 },
+  { 0x0700, 0x1471, 0x0000 },
+  { 0x0700, 0x1473, 0x0000 },
+  { 0x8700, 0x1476, 0x2000 },
+  { 0x0700, 0x1475, 0x0000 },
+  { 0x0700, 0x1477, 0x0000 },
+  { 0x8700, 0x1488, 0x5000 },
+  { 0x8700, 0x1480, 0x4000 },
+  { 0x8700, 0x147c, 0x3000 },
+  { 0x8700, 0x147a, 0x2000 },
+  { 0x0700, 0x1479, 0x0000 },
+  { 0x0700, 0x147b, 0x0000 },
+  { 0x8700, 0x147e, 0x2000 },
+  { 0x0700, 0x147d, 0x0000 },
+  { 0x0700, 0x147f, 0x0000 },
+  { 0x8700, 0x1484, 0x3000 },
+  { 0x8700, 0x1482, 0x2000 },
+  { 0x0700, 0x1481, 0x0000 },
+  { 0x0700, 0x1483, 0x0000 },
+  { 0x8700, 0x1486, 0x2000 },
+  { 0x0700, 0x1485, 0x0000 },
+  { 0x0700, 0x1487, 0x0000 },
+  { 0x8700, 0x1490, 0x4000 },
+  { 0x8700, 0x148c, 0x3000 },
+  { 0x8700, 0x148a, 0x2000 },
+  { 0x0700, 0x1489, 0x0000 },
+  { 0x0700, 0x148b, 0x0000 },
+  { 0x8700, 0x148e, 0x2000 },
+  { 0x0700, 0x148d, 0x0000 },
+  { 0x0700, 0x148f, 0x0000 },
+  { 0x8700, 0x1494, 0x3000 },
+  { 0x8700, 0x1492, 0x2000 },
+  { 0x0700, 0x1491, 0x0000 },
+  { 0x0700, 0x1493, 0x0000 },
+  { 0x8700, 0x1496, 0x2000 },
+  { 0x0700, 0x1495, 0x0000 },
+  { 0x0700, 0x1497, 0x0000 },
+  { 0x8700, 0x14b8, 0x6000 },
+  { 0x8700, 0x14a8, 0x5000 },
+  { 0x8700, 0x14a0, 0x4000 },
+  { 0x8700, 0x149c, 0x3000 },
+  { 0x8700, 0x149a, 0x2000 },
+  { 0x0700, 0x1499, 0x0000 },
+  { 0x0700, 0x149b, 0x0000 },
+  { 0x8700, 0x149e, 0x2000 },
+  { 0x0700, 0x149d, 0x0000 },
+  { 0x0700, 0x149f, 0x0000 },
+  { 0x8700, 0x14a4, 0x3000 },
+  { 0x8700, 0x14a2, 0x2000 },
+  { 0x0700, 0x14a1, 0x0000 },
+  { 0x0700, 0x14a3, 0x0000 },
+  { 0x8700, 0x14a6, 0x2000 },
+  { 0x0700, 0x14a5, 0x0000 },
+  { 0x0700, 0x14a7, 0x0000 },
+  { 0x8700, 0x14b0, 0x4000 },
+  { 0x8700, 0x14ac, 0x3000 },
+  { 0x8700, 0x14aa, 0x2000 },
+  { 0x0700, 0x14a9, 0x0000 },
+  { 0x0700, 0x14ab, 0x0000 },
+  { 0x8700, 0x14ae, 0x2000 },
+  { 0x0700, 0x14ad, 0x0000 },
+  { 0x0700, 0x14af, 0x0000 },
+  { 0x8700, 0x14b4, 0x3000 },
+  { 0x8700, 0x14b2, 0x2000 },
+  { 0x0700, 0x14b1, 0x0000 },
+  { 0x0700, 0x14b3, 0x0000 },
+  { 0x8700, 0x14b6, 0x2000 },
+  { 0x0700, 0x14b5, 0x0000 },
+  { 0x0700, 0x14b7, 0x0000 },
+  { 0x8700, 0x14c8, 0x5000 },
+  { 0x8700, 0x14c0, 0x4000 },
+  { 0x8700, 0x14bc, 0x3000 },
+  { 0x8700, 0x14ba, 0x2000 },
+  { 0x0700, 0x14b9, 0x0000 },
+  { 0x0700, 0x14bb, 0x0000 },
+  { 0x8700, 0x14be, 0x2000 },
+  { 0x0700, 0x14bd, 0x0000 },
+  { 0x0700, 0x14bf, 0x0000 },
+  { 0x8700, 0x14c4, 0x3000 },
+  { 0x8700, 0x14c2, 0x2000 },
+  { 0x0700, 0x14c1, 0x0000 },
+  { 0x0700, 0x14c3, 0x0000 },
+  { 0x8700, 0x14c6, 0x2000 },
+  { 0x0700, 0x14c5, 0x0000 },
+  { 0x0700, 0x14c7, 0x0000 },
+  { 0x8700, 0x14d0, 0x4000 },
+  { 0x8700, 0x14cc, 0x3000 },
+  { 0x8700, 0x14ca, 0x2000 },
+  { 0x0700, 0x14c9, 0x0000 },
+  { 0x0700, 0x14cb, 0x0000 },
+  { 0x8700, 0x14ce, 0x2000 },
+  { 0x0700, 0x14cd, 0x0000 },
+  { 0x0700, 0x14cf, 0x0000 },
+  { 0x8700, 0x14d4, 0x3000 },
+  { 0x8700, 0x14d2, 0x2000 },
+  { 0x0700, 0x14d1, 0x0000 },
+  { 0x0700, 0x14d3, 0x0000 },
+  { 0x8700, 0x14d6, 0x2000 },
+  { 0x0700, 0x14d5, 0x0000 },
+  { 0x0700, 0x14d7, 0x0000 },
+  { 0x8700, 0x1518, 0x7000 },
+  { 0x8700, 0x14f8, 0x6000 },
+  { 0x8700, 0x14e8, 0x5000 },
+  { 0x8700, 0x14e0, 0x4000 },
+  { 0x8700, 0x14dc, 0x3000 },
+  { 0x8700, 0x14da, 0x2000 },
+  { 0x0700, 0x14d9, 0x0000 },
+  { 0x0700, 0x14db, 0x0000 },
+  { 0x8700, 0x14de, 0x2000 },
+  { 0x0700, 0x14dd, 0x0000 },
+  { 0x0700, 0x14df, 0x0000 },
+  { 0x8700, 0x14e4, 0x3000 },
+  { 0x8700, 0x14e2, 0x2000 },
+  { 0x0700, 0x14e1, 0x0000 },
+  { 0x0700, 0x14e3, 0x0000 },
+  { 0x8700, 0x14e6, 0x2000 },
+  { 0x0700, 0x14e5, 0x0000 },
+  { 0x0700, 0x14e7, 0x0000 },
+  { 0x8700, 0x14f0, 0x4000 },
+  { 0x8700, 0x14ec, 0x3000 },
+  { 0x8700, 0x14ea, 0x2000 },
+  { 0x0700, 0x14e9, 0x0000 },
+  { 0x0700, 0x14eb, 0x0000 },
+  { 0x8700, 0x14ee, 0x2000 },
+  { 0x0700, 0x14ed, 0x0000 },
+  { 0x0700, 0x14ef, 0x0000 },
+  { 0x8700, 0x14f4, 0x3000 },
+  { 0x8700, 0x14f2, 0x2000 },
+  { 0x0700, 0x14f1, 0x0000 },
+  { 0x0700, 0x14f3, 0x0000 },
+  { 0x8700, 0x14f6, 0x2000 },
+  { 0x0700, 0x14f5, 0x0000 },
+  { 0x0700, 0x14f7, 0x0000 },
+  { 0x8700, 0x1508, 0x5000 },
+  { 0x8700, 0x1500, 0x4000 },
+  { 0x8700, 0x14fc, 0x3000 },
+  { 0x8700, 0x14fa, 0x2000 },
+  { 0x0700, 0x14f9, 0x0000 },
+  { 0x0700, 0x14fb, 0x0000 },
+  { 0x8700, 0x14fe, 0x2000 },
+  { 0x0700, 0x14fd, 0x0000 },
+  { 0x0700, 0x14ff, 0x0000 },
+  { 0x8700, 0x1504, 0x3000 },
+  { 0x8700, 0x1502, 0x2000 },
+  { 0x0700, 0x1501, 0x0000 },
+  { 0x0700, 0x1503, 0x0000 },
+  { 0x8700, 0x1506, 0x2000 },
+  { 0x0700, 0x1505, 0x0000 },
+  { 0x0700, 0x1507, 0x0000 },
+  { 0x8700, 0x1510, 0x4000 },
+  { 0x8700, 0x150c, 0x3000 },
+  { 0x8700, 0x150a, 0x2000 },
+  { 0x0700, 0x1509, 0x0000 },
+  { 0x0700, 0x150b, 0x0000 },
+  { 0x8700, 0x150e, 0x2000 },
+  { 0x0700, 0x150d, 0x0000 },
+  { 0x0700, 0x150f, 0x0000 },
+  { 0x8700, 0x1514, 0x3000 },
+  { 0x8700, 0x1512, 0x2000 },
+  { 0x0700, 0x1511, 0x0000 },
+  { 0x0700, 0x1513, 0x0000 },
+  { 0x8700, 0x1516, 0x2000 },
+  { 0x0700, 0x1515, 0x0000 },
+  { 0x0700, 0x1517, 0x0000 },
+  { 0x8700, 0x1538, 0x6000 },
+  { 0x8700, 0x1528, 0x5000 },
+  { 0x8700, 0x1520, 0x4000 },
+  { 0x8700, 0x151c, 0x3000 },
+  { 0x8700, 0x151a, 0x2000 },
+  { 0x0700, 0x1519, 0x0000 },
+  { 0x0700, 0x151b, 0x0000 },
+  { 0x8700, 0x151e, 0x2000 },
+  { 0x0700, 0x151d, 0x0000 },
+  { 0x0700, 0x151f, 0x0000 },
+  { 0x8700, 0x1524, 0x3000 },
+  { 0x8700, 0x1522, 0x2000 },
+  { 0x0700, 0x1521, 0x0000 },
+  { 0x0700, 0x1523, 0x0000 },
+  { 0x8700, 0x1526, 0x2000 },
+  { 0x0700, 0x1525, 0x0000 },
+  { 0x0700, 0x1527, 0x0000 },
+  { 0x8700, 0x1530, 0x4000 },
+  { 0x8700, 0x152c, 0x3000 },
+  { 0x8700, 0x152a, 0x2000 },
+  { 0x0700, 0x1529, 0x0000 },
+  { 0x0700, 0x152b, 0x0000 },
+  { 0x8700, 0x152e, 0x2000 },
+  { 0x0700, 0x152d, 0x0000 },
+  { 0x0700, 0x152f, 0x0000 },
+  { 0x8700, 0x1534, 0x3000 },
+  { 0x8700, 0x1532, 0x2000 },
+  { 0x0700, 0x1531, 0x0000 },
+  { 0x0700, 0x1533, 0x0000 },
+  { 0x8700, 0x1536, 0x2000 },
+  { 0x0700, 0x1535, 0x0000 },
+  { 0x0700, 0x1537, 0x0000 },
+  { 0x8700, 0x1548, 0x5000 },
+  { 0x8700, 0x1540, 0x4000 },
+  { 0x8700, 0x153c, 0x3000 },
+  { 0x8700, 0x153a, 0x2000 },
+  { 0x0700, 0x1539, 0x0000 },
+  { 0x0700, 0x153b, 0x0000 },
+  { 0x8700, 0x153e, 0x2000 },
+  { 0x0700, 0x153d, 0x0000 },
+  { 0x0700, 0x153f, 0x0000 },
+  { 0x8700, 0x1544, 0x3000 },
+  { 0x8700, 0x1542, 0x2000 },
+  { 0x0700, 0x1541, 0x0000 },
+  { 0x0700, 0x1543, 0x0000 },
+  { 0x8700, 0x1546, 0x2000 },
+  { 0x0700, 0x1545, 0x0000 },
+  { 0x0700, 0x1547, 0x0000 },
+  { 0x8700, 0x1550, 0x4000 },
+  { 0x8700, 0x154c, 0x3000 },
+  { 0x8700, 0x154a, 0x2000 },
+  { 0x0700, 0x1549, 0x0000 },
+  { 0x0700, 0x154b, 0x0000 },
+  { 0x8700, 0x154e, 0x2000 },
+  { 0x0700, 0x154d, 0x0000 },
+  { 0x0700, 0x154f, 0x0000 },
+  { 0x8700, 0x1554, 0x3000 },
+  { 0x8700, 0x1552, 0x2000 },
+  { 0x0700, 0x1551, 0x0000 },
+  { 0x0700, 0x1553, 0x0000 },
+  { 0x8700, 0x1556, 0x2000 },
+  { 0x0700, 0x1555, 0x0000 },
+  { 0x0700, 0x1557, 0x0000 },
+  { 0x9900, 0x22ae, 0xc000 },
+  { 0x8900, 0x1e24, 0xb001 },
+  { 0x8700, 0x17a2, 0xa000 },
+  { 0x8700, 0x1658, 0x9000 },
+  { 0x8700, 0x15d8, 0x8000 },
+  { 0x8700, 0x1598, 0x7000 },
+  { 0x8700, 0x1578, 0x6000 },
+  { 0x8700, 0x1568, 0x5000 },
+  { 0x8700, 0x1560, 0x4000 },
+  { 0x8700, 0x155c, 0x3000 },
+  { 0x8700, 0x155a, 0x2000 },
+  { 0x0700, 0x1559, 0x0000 },
+  { 0x0700, 0x155b, 0x0000 },
+  { 0x8700, 0x155e, 0x2000 },
+  { 0x0700, 0x155d, 0x0000 },
+  { 0x0700, 0x155f, 0x0000 },
+  { 0x8700, 0x1564, 0x3000 },
+  { 0x8700, 0x1562, 0x2000 },
+  { 0x0700, 0x1561, 0x0000 },
+  { 0x0700, 0x1563, 0x0000 },
+  { 0x8700, 0x1566, 0x2000 },
+  { 0x0700, 0x1565, 0x0000 },
+  { 0x0700, 0x1567, 0x0000 },
+  { 0x8700, 0x1570, 0x4000 },
+  { 0x8700, 0x156c, 0x3000 },
+  { 0x8700, 0x156a, 0x2000 },
+  { 0x0700, 0x1569, 0x0000 },
+  { 0x0700, 0x156b, 0x0000 },
+  { 0x8700, 0x156e, 0x2000 },
+  { 0x0700, 0x156d, 0x0000 },
+  { 0x0700, 0x156f, 0x0000 },
+  { 0x8700, 0x1574, 0x3000 },
+  { 0x8700, 0x1572, 0x2000 },
+  { 0x0700, 0x1571, 0x0000 },
+  { 0x0700, 0x1573, 0x0000 },
+  { 0x8700, 0x1576, 0x2000 },
+  { 0x0700, 0x1575, 0x0000 },
+  { 0x0700, 0x1577, 0x0000 },
+  { 0x8700, 0x1588, 0x5000 },
+  { 0x8700, 0x1580, 0x4000 },
+  { 0x8700, 0x157c, 0x3000 },
+  { 0x8700, 0x157a, 0x2000 },
+  { 0x0700, 0x1579, 0x0000 },
+  { 0x0700, 0x157b, 0x0000 },
+  { 0x8700, 0x157e, 0x2000 },
+  { 0x0700, 0x157d, 0x0000 },
+  { 0x0700, 0x157f, 0x0000 },
+  { 0x8700, 0x1584, 0x3000 },
+  { 0x8700, 0x1582, 0x2000 },
+  { 0x0700, 0x1581, 0x0000 },
+  { 0x0700, 0x1583, 0x0000 },
+  { 0x8700, 0x1586, 0x2000 },
+  { 0x0700, 0x1585, 0x0000 },
+  { 0x0700, 0x1587, 0x0000 },
+  { 0x8700, 0x1590, 0x4000 },
+  { 0x8700, 0x158c, 0x3000 },
+  { 0x8700, 0x158a, 0x2000 },
+  { 0x0700, 0x1589, 0x0000 },
+  { 0x0700, 0x158b, 0x0000 },
+  { 0x8700, 0x158e, 0x2000 },
+  { 0x0700, 0x158d, 0x0000 },
+  { 0x0700, 0x158f, 0x0000 },
+  { 0x8700, 0x1594, 0x3000 },
+  { 0x8700, 0x1592, 0x2000 },
+  { 0x0700, 0x1591, 0x0000 },
+  { 0x0700, 0x1593, 0x0000 },
+  { 0x8700, 0x1596, 0x2000 },
+  { 0x0700, 0x1595, 0x0000 },
+  { 0x0700, 0x1597, 0x0000 },
+  { 0x8700, 0x15b8, 0x6000 },
+  { 0x8700, 0x15a8, 0x5000 },
+  { 0x8700, 0x15a0, 0x4000 },
+  { 0x8700, 0x159c, 0x3000 },
+  { 0x8700, 0x159a, 0x2000 },
+  { 0x0700, 0x1599, 0x0000 },
+  { 0x0700, 0x159b, 0x0000 },
+  { 0x8700, 0x159e, 0x2000 },
+  { 0x0700, 0x159d, 0x0000 },
+  { 0x0700, 0x159f, 0x0000 },
+  { 0x8700, 0x15a4, 0x3000 },
+  { 0x8700, 0x15a2, 0x2000 },
+  { 0x0700, 0x15a1, 0x0000 },
+  { 0x0700, 0x15a3, 0x0000 },
+  { 0x8700, 0x15a6, 0x2000 },
+  { 0x0700, 0x15a5, 0x0000 },
+  { 0x0700, 0x15a7, 0x0000 },
+  { 0x8700, 0x15b0, 0x4000 },
+  { 0x8700, 0x15ac, 0x3000 },
+  { 0x8700, 0x15aa, 0x2000 },
+  { 0x0700, 0x15a9, 0x0000 },
+  { 0x0700, 0x15ab, 0x0000 },
+  { 0x8700, 0x15ae, 0x2000 },
+  { 0x0700, 0x15ad, 0x0000 },
+  { 0x0700, 0x15af, 0x0000 },
+  { 0x8700, 0x15b4, 0x3000 },
+  { 0x8700, 0x15b2, 0x2000 },
+  { 0x0700, 0x15b1, 0x0000 },
+  { 0x0700, 0x15b3, 0x0000 },
+  { 0x8700, 0x15b6, 0x2000 },
+  { 0x0700, 0x15b5, 0x0000 },
+  { 0x0700, 0x15b7, 0x0000 },
+  { 0x8700, 0x15c8, 0x5000 },
+  { 0x8700, 0x15c0, 0x4000 },
+  { 0x8700, 0x15bc, 0x3000 },
+  { 0x8700, 0x15ba, 0x2000 },
+  { 0x0700, 0x15b9, 0x0000 },
+  { 0x0700, 0x15bb, 0x0000 },
+  { 0x8700, 0x15be, 0x2000 },
+  { 0x0700, 0x15bd, 0x0000 },
+  { 0x0700, 0x15bf, 0x0000 },
+  { 0x8700, 0x15c4, 0x3000 },
+  { 0x8700, 0x15c2, 0x2000 },
+  { 0x0700, 0x15c1, 0x0000 },
+  { 0x0700, 0x15c3, 0x0000 },
+  { 0x8700, 0x15c6, 0x2000 },
+  { 0x0700, 0x15c5, 0x0000 },
+  { 0x0700, 0x15c7, 0x0000 },
+  { 0x8700, 0x15d0, 0x4000 },
+  { 0x8700, 0x15cc, 0x3000 },
+  { 0x8700, 0x15ca, 0x2000 },
+  { 0x0700, 0x15c9, 0x0000 },
+  { 0x0700, 0x15cb, 0x0000 },
+  { 0x8700, 0x15ce, 0x2000 },
+  { 0x0700, 0x15cd, 0x0000 },
+  { 0x0700, 0x15cf, 0x0000 },
+  { 0x8700, 0x15d4, 0x3000 },
+  { 0x8700, 0x15d2, 0x2000 },
+  { 0x0700, 0x15d1, 0x0000 },
+  { 0x0700, 0x15d3, 0x0000 },
+  { 0x8700, 0x15d6, 0x2000 },
+  { 0x0700, 0x15d5, 0x0000 },
+  { 0x0700, 0x15d7, 0x0000 },
+  { 0x8700, 0x1618, 0x7000 },
+  { 0x8700, 0x15f8, 0x6000 },
+  { 0x8700, 0x15e8, 0x5000 },
+  { 0x8700, 0x15e0, 0x4000 },
+  { 0x8700, 0x15dc, 0x3000 },
+  { 0x8700, 0x15da, 0x2000 },
+  { 0x0700, 0x15d9, 0x0000 },
+  { 0x0700, 0x15db, 0x0000 },
+  { 0x8700, 0x15de, 0x2000 },
+  { 0x0700, 0x15dd, 0x0000 },
+  { 0x0700, 0x15df, 0x0000 },
+  { 0x8700, 0x15e4, 0x3000 },
+  { 0x8700, 0x15e2, 0x2000 },
+  { 0x0700, 0x15e1, 0x0000 },
+  { 0x0700, 0x15e3, 0x0000 },
+  { 0x8700, 0x15e6, 0x2000 },
+  { 0x0700, 0x15e5, 0x0000 },
+  { 0x0700, 0x15e7, 0x0000 },
+  { 0x8700, 0x15f0, 0x4000 },
+  { 0x8700, 0x15ec, 0x3000 },
+  { 0x8700, 0x15ea, 0x2000 },
+  { 0x0700, 0x15e9, 0x0000 },
+  { 0x0700, 0x15eb, 0x0000 },
+  { 0x8700, 0x15ee, 0x2000 },
+  { 0x0700, 0x15ed, 0x0000 },
+  { 0x0700, 0x15ef, 0x0000 },
+  { 0x8700, 0x15f4, 0x3000 },
+  { 0x8700, 0x15f2, 0x2000 },
+  { 0x0700, 0x15f1, 0x0000 },
+  { 0x0700, 0x15f3, 0x0000 },
+  { 0x8700, 0x15f6, 0x2000 },
+  { 0x0700, 0x15f5, 0x0000 },
+  { 0x0700, 0x15f7, 0x0000 },
+  { 0x8700, 0x1608, 0x5000 },
+  { 0x8700, 0x1600, 0x4000 },
+  { 0x8700, 0x15fc, 0x3000 },
+  { 0x8700, 0x15fa, 0x2000 },
+  { 0x0700, 0x15f9, 0x0000 },
+  { 0x0700, 0x15fb, 0x0000 },
+  { 0x8700, 0x15fe, 0x2000 },
+  { 0x0700, 0x15fd, 0x0000 },
+  { 0x0700, 0x15ff, 0x0000 },
+  { 0x8700, 0x1604, 0x3000 },
+  { 0x8700, 0x1602, 0x2000 },
+  { 0x0700, 0x1601, 0x0000 },
+  { 0x0700, 0x1603, 0x0000 },
+  { 0x8700, 0x1606, 0x2000 },
+  { 0x0700, 0x1605, 0x0000 },
+  { 0x0700, 0x1607, 0x0000 },
+  { 0x8700, 0x1610, 0x4000 },
+  { 0x8700, 0x160c, 0x3000 },
+  { 0x8700, 0x160a, 0x2000 },
+  { 0x0700, 0x1609, 0x0000 },
+  { 0x0700, 0x160b, 0x0000 },
+  { 0x8700, 0x160e, 0x2000 },
+  { 0x0700, 0x160d, 0x0000 },
+  { 0x0700, 0x160f, 0x0000 },
+  { 0x8700, 0x1614, 0x3000 },
+  { 0x8700, 0x1612, 0x2000 },
+  { 0x0700, 0x1611, 0x0000 },
+  { 0x0700, 0x1613, 0x0000 },
+  { 0x8700, 0x1616, 0x2000 },
+  { 0x0700, 0x1615, 0x0000 },
+  { 0x0700, 0x1617, 0x0000 },
+  { 0x8700, 0x1638, 0x6000 },
+  { 0x8700, 0x1628, 0x5000 },
+  { 0x8700, 0x1620, 0x4000 },
+  { 0x8700, 0x161c, 0x3000 },
+  { 0x8700, 0x161a, 0x2000 },
+  { 0x0700, 0x1619, 0x0000 },
+  { 0x0700, 0x161b, 0x0000 },
+  { 0x8700, 0x161e, 0x2000 },
+  { 0x0700, 0x161d, 0x0000 },
+  { 0x0700, 0x161f, 0x0000 },
+  { 0x8700, 0x1624, 0x3000 },
+  { 0x8700, 0x1622, 0x2000 },
+  { 0x0700, 0x1621, 0x0000 },
+  { 0x0700, 0x1623, 0x0000 },
+  { 0x8700, 0x1626, 0x2000 },
+  { 0x0700, 0x1625, 0x0000 },
+  { 0x0700, 0x1627, 0x0000 },
+  { 0x8700, 0x1630, 0x4000 },
+  { 0x8700, 0x162c, 0x3000 },
+  { 0x8700, 0x162a, 0x2000 },
+  { 0x0700, 0x1629, 0x0000 },
+  { 0x0700, 0x162b, 0x0000 },
+  { 0x8700, 0x162e, 0x2000 },
+  { 0x0700, 0x162d, 0x0000 },
+  { 0x0700, 0x162f, 0x0000 },
+  { 0x8700, 0x1634, 0x3000 },
+  { 0x8700, 0x1632, 0x2000 },
+  { 0x0700, 0x1631, 0x0000 },
+  { 0x0700, 0x1633, 0x0000 },
+  { 0x8700, 0x1636, 0x2000 },
+  { 0x0700, 0x1635, 0x0000 },
+  { 0x0700, 0x1637, 0x0000 },
+  { 0x8700, 0x1648, 0x5000 },
+  { 0x8700, 0x1640, 0x4000 },
+  { 0x8700, 0x163c, 0x3000 },
+  { 0x8700, 0x163a, 0x2000 },
+  { 0x0700, 0x1639, 0x0000 },
+  { 0x0700, 0x163b, 0x0000 },
+  { 0x8700, 0x163e, 0x2000 },
+  { 0x0700, 0x163d, 0x0000 },
+  { 0x0700, 0x163f, 0x0000 },
+  { 0x8700, 0x1644, 0x3000 },
+  { 0x8700, 0x1642, 0x2000 },
+  { 0x0700, 0x1641, 0x0000 },
+  { 0x0700, 0x1643, 0x0000 },
+  { 0x8700, 0x1646, 0x2000 },
+  { 0x0700, 0x1645, 0x0000 },
+  { 0x0700, 0x1647, 0x0000 },
+  { 0x8700, 0x1650, 0x4000 },
+  { 0x8700, 0x164c, 0x3000 },
+  { 0x8700, 0x164a, 0x2000 },
+  { 0x0700, 0x1649, 0x0000 },
+  { 0x0700, 0x164b, 0x0000 },
+  { 0x8700, 0x164e, 0x2000 },
+  { 0x0700, 0x164d, 0x0000 },
+  { 0x0700, 0x164f, 0x0000 },
+  { 0x8700, 0x1654, 0x3000 },
+  { 0x8700, 0x1652, 0x2000 },
+  { 0x0700, 0x1651, 0x0000 },
+  { 0x0700, 0x1653, 0x0000 },
+  { 0x8700, 0x1656, 0x2000 },
+  { 0x0700, 0x1655, 0x0000 },
+  { 0x0700, 0x1657, 0x0000 },
+  { 0x8700, 0x16e4, 0x8000 },
+  { 0x8700, 0x16a4, 0x7000 },
+  { 0x8700, 0x1681, 0x6000 },
+  { 0x8700, 0x1668, 0x5000 },
+  { 0x8700, 0x1660, 0x4000 },
+  { 0x8700, 0x165c, 0x3000 },
+  { 0x8700, 0x165a, 0x2000 },
+  { 0x0700, 0x1659, 0x0000 },
+  { 0x0700, 0x165b, 0x0000 },
+  { 0x8700, 0x165e, 0x2000 },
+  { 0x0700, 0x165d, 0x0000 },
+  { 0x0700, 0x165f, 0x0000 },
+  { 0x8700, 0x1664, 0x3000 },
+  { 0x8700, 0x1662, 0x2000 },
+  { 0x0700, 0x1661, 0x0000 },
+  { 0x0700, 0x1663, 0x0000 },
+  { 0x8700, 0x1666, 0x2000 },
+  { 0x0700, 0x1665, 0x0000 },
+  { 0x0700, 0x1667, 0x0000 },
+  { 0x8700, 0x1670, 0x4000 },
+  { 0x8700, 0x166c, 0x3000 },
+  { 0x8700, 0x166a, 0x2000 },
+  { 0x0700, 0x1669, 0x0000 },
+  { 0x0700, 0x166b, 0x0000 },
+  { 0x9500, 0x166e, 0x2000 },
+  { 0x1500, 0x166d, 0x0000 },
+  { 0x0700, 0x166f, 0x0000 },
+  { 0x8700, 0x1674, 0x3000 },
+  { 0x8700, 0x1672, 0x2000 },
+  { 0x0700, 0x1671, 0x0000 },
+  { 0x0700, 0x1673, 0x0000 },
+  { 0x8700, 0x1676, 0x2000 },
+  { 0x0700, 0x1675, 0x0000 },
+  { 0x1d00, 0x1680, 0x0000 },
+  { 0x8700, 0x1691, 0x5000 },
+  { 0x8700, 0x1689, 0x4000 },
+  { 0x8700, 0x1685, 0x3000 },
+  { 0x8700, 0x1683, 0x2000 },
+  { 0x0700, 0x1682, 0x0000 },
+  { 0x0700, 0x1684, 0x0000 },
+  { 0x8700, 0x1687, 0x2000 },
+  { 0x0700, 0x1686, 0x0000 },
+  { 0x0700, 0x1688, 0x0000 },
+  { 0x8700, 0x168d, 0x3000 },
+  { 0x8700, 0x168b, 0x2000 },
+  { 0x0700, 0x168a, 0x0000 },
+  { 0x0700, 0x168c, 0x0000 },
+  { 0x8700, 0x168f, 0x2000 },
+  { 0x0700, 0x168e, 0x0000 },
+  { 0x0700, 0x1690, 0x0000 },
+  { 0x8700, 0x1699, 0x4000 },
+  { 0x8700, 0x1695, 0x3000 },
+  { 0x8700, 0x1693, 0x2000 },
+  { 0x0700, 0x1692, 0x0000 },
+  { 0x0700, 0x1694, 0x0000 },
+  { 0x8700, 0x1697, 0x2000 },
+  { 0x0700, 0x1696, 0x0000 },
+  { 0x0700, 0x1698, 0x0000 },
+  { 0x8700, 0x16a0, 0x3000 },
+  { 0x9600, 0x169b, 0x2000 },
+  { 0x0700, 0x169a, 0x0000 },
+  { 0x1200, 0x169c, 0x0000 },
+  { 0x8700, 0x16a2, 0x2000 },
+  { 0x0700, 0x16a1, 0x0000 },
+  { 0x0700, 0x16a3, 0x0000 },
+  { 0x8700, 0x16c4, 0x6000 },
+  { 0x8700, 0x16b4, 0x5000 },
+  { 0x8700, 0x16ac, 0x4000 },
+  { 0x8700, 0x16a8, 0x3000 },
+  { 0x8700, 0x16a6, 0x2000 },
+  { 0x0700, 0x16a5, 0x0000 },
+  { 0x0700, 0x16a7, 0x0000 },
+  { 0x8700, 0x16aa, 0x2000 },
+  { 0x0700, 0x16a9, 0x0000 },
+  { 0x0700, 0x16ab, 0x0000 },
+  { 0x8700, 0x16b0, 0x3000 },
+  { 0x8700, 0x16ae, 0x2000 },
+  { 0x0700, 0x16ad, 0x0000 },
+  { 0x0700, 0x16af, 0x0000 },
+  { 0x8700, 0x16b2, 0x2000 },
+  { 0x0700, 0x16b1, 0x0000 },
+  { 0x0700, 0x16b3, 0x0000 },
+  { 0x8700, 0x16bc, 0x4000 },
+  { 0x8700, 0x16b8, 0x3000 },
+  { 0x8700, 0x16b6, 0x2000 },
+  { 0x0700, 0x16b5, 0x0000 },
+  { 0x0700, 0x16b7, 0x0000 },
+  { 0x8700, 0x16ba, 0x2000 },
+  { 0x0700, 0x16b9, 0x0000 },
+  { 0x0700, 0x16bb, 0x0000 },
+  { 0x8700, 0x16c0, 0x3000 },
+  { 0x8700, 0x16be, 0x2000 },
+  { 0x0700, 0x16bd, 0x0000 },
+  { 0x0700, 0x16bf, 0x0000 },
+  { 0x8700, 0x16c2, 0x2000 },
+  { 0x0700, 0x16c1, 0x0000 },
+  { 0x0700, 0x16c3, 0x0000 },
+  { 0x8700, 0x16d4, 0x5000 },
+  { 0x8700, 0x16cc, 0x4000 },
+  { 0x8700, 0x16c8, 0x3000 },
+  { 0x8700, 0x16c6, 0x2000 },
+  { 0x0700, 0x16c5, 0x0000 },
+  { 0x0700, 0x16c7, 0x0000 },
+  { 0x8700, 0x16ca, 0x2000 },
+  { 0x0700, 0x16c9, 0x0000 },
+  { 0x0700, 0x16cb, 0x0000 },
+  { 0x8700, 0x16d0, 0x3000 },
+  { 0x8700, 0x16ce, 0x2000 },
+  { 0x0700, 0x16cd, 0x0000 },
+  { 0x0700, 0x16cf, 0x0000 },
+  { 0x8700, 0x16d2, 0x2000 },
+  { 0x0700, 0x16d1, 0x0000 },
+  { 0x0700, 0x16d3, 0x0000 },
+  { 0x8700, 0x16dc, 0x4000 },
+  { 0x8700, 0x16d8, 0x3000 },
+  { 0x8700, 0x16d6, 0x2000 },
+  { 0x0700, 0x16d5, 0x0000 },
+  { 0x0700, 0x16d7, 0x0000 },
+  { 0x8700, 0x16da, 0x2000 },
+  { 0x0700, 0x16d9, 0x0000 },
+  { 0x0700, 0x16db, 0x0000 },
+  { 0x8700, 0x16e0, 0x3000 },
+  { 0x8700, 0x16de, 0x2000 },
+  { 0x0700, 0x16dd, 0x0000 },
+  { 0x0700, 0x16df, 0x0000 },
+  { 0x8700, 0x16e2, 0x2000 },
+  { 0x0700, 0x16e1, 0x0000 },
+  { 0x0700, 0x16e3, 0x0000 },
+  { 0x8700, 0x1748, 0x7000 },
+  { 0x8c00, 0x1714, 0x6000 },
+  { 0x8700, 0x1703, 0x5000 },
+  { 0x9500, 0x16ec, 0x4000 },
+  { 0x8700, 0x16e8, 0x3000 },
+  { 0x8700, 0x16e6, 0x2000 },
+  { 0x0700, 0x16e5, 0x0000 },
+  { 0x0700, 0x16e7, 0x0000 },
+  { 0x8700, 0x16ea, 0x2000 },
+  { 0x0700, 0x16e9, 0x0000 },
+  { 0x1500, 0x16eb, 0x0000 },
+  { 0x8e00, 0x16f0, 0x3000 },
+  { 0x8e00, 0x16ee, 0x2000 },
+  { 0x1500, 0x16ed, 0x0000 },
+  { 0x0e00, 0x16ef, 0x0000 },
+  { 0x8700, 0x1701, 0x2000 },
+  { 0x0700, 0x1700, 0x0000 },
+  { 0x0700, 0x1702, 0x0000 },
+  { 0x8700, 0x170b, 0x4000 },
+  { 0x8700, 0x1707, 0x3000 },
+  { 0x8700, 0x1705, 0x2000 },
+  { 0x0700, 0x1704, 0x0000 },
+  { 0x0700, 0x1706, 0x0000 },
+  { 0x8700, 0x1709, 0x2000 },
+  { 0x0700, 0x1708, 0x0000 },
+  { 0x0700, 0x170a, 0x0000 },
+  { 0x8700, 0x1710, 0x3000 },
+  { 0x8700, 0x170e, 0x2000 },
+  { 0x0700, 0x170c, 0x0000 },
+  { 0x0700, 0x170f, 0x0000 },
+  { 0x8c00, 0x1712, 0x2000 },
+  { 0x0700, 0x1711, 0x0000 },
+  { 0x0c00, 0x1713, 0x0000 },
+  { 0x8700, 0x172f, 0x5000 },
+  { 0x8700, 0x1727, 0x4000 },
+  { 0x8700, 0x1723, 0x3000 },
+  { 0x8700, 0x1721, 0x2000 },
+  { 0x0700, 0x1720, 0x0000 },
+  { 0x0700, 0x1722, 0x0000 },
+  { 0x8700, 0x1725, 0x2000 },
+  { 0x0700, 0x1724, 0x0000 },
+  { 0x0700, 0x1726, 0x0000 },
+  { 0x8700, 0x172b, 0x3000 },
+  { 0x8700, 0x1729, 0x2000 },
+  { 0x0700, 0x1728, 0x0000 },
+  { 0x0700, 0x172a, 0x0000 },
+  { 0x8700, 0x172d, 0x2000 },
+  { 0x0700, 0x172c, 0x0000 },
+  { 0x0700, 0x172e, 0x0000 },
+  { 0x8700, 0x1740, 0x4000 },
+  { 0x8c00, 0x1733, 0x3000 },
+  { 0x8700, 0x1731, 0x2000 },
+  { 0x0700, 0x1730, 0x0000 },
+  { 0x0c00, 0x1732, 0x0000 },
+  { 0x9500, 0x1735, 0x2000 },
+  { 0x0c00, 0x1734, 0x0000 },
+  { 0x1500, 0x1736, 0x0000 },
+  { 0x8700, 0x1744, 0x3000 },
+  { 0x8700, 0x1742, 0x2000 },
+  { 0x0700, 0x1741, 0x0000 },
+  { 0x0700, 0x1743, 0x0000 },
+  { 0x8700, 0x1746, 0x2000 },
+  { 0x0700, 0x1745, 0x0000 },
+  { 0x0700, 0x1747, 0x0000 },
+  { 0x8700, 0x1782, 0x6000 },
+  { 0x8700, 0x1764, 0x5000 },
+  { 0x8700, 0x1750, 0x4000 },
+  { 0x8700, 0x174c, 0x3000 },
+  { 0x8700, 0x174a, 0x2000 },
+  { 0x0700, 0x1749, 0x0000 },
+  { 0x0700, 0x174b, 0x0000 },
+  { 0x8700, 0x174e, 0x2000 },
+  { 0x0700, 0x174d, 0x0000 },
+  { 0x0700, 0x174f, 0x0000 },
+  { 0x8700, 0x1760, 0x3000 },
+  { 0x8c00, 0x1752, 0x2000 },
+  { 0x0700, 0x1751, 0x0000 },
+  { 0x0c00, 0x1753, 0x0000 },
+  { 0x8700, 0x1762, 0x2000 },
+  { 0x0700, 0x1761, 0x0000 },
+  { 0x0700, 0x1763, 0x0000 },
+  { 0x8700, 0x176c, 0x4000 },
+  { 0x8700, 0x1768, 0x3000 },
+  { 0x8700, 0x1766, 0x2000 },
+  { 0x0700, 0x1765, 0x0000 },
+  { 0x0700, 0x1767, 0x0000 },
+  { 0x8700, 0x176a, 0x2000 },
+  { 0x0700, 0x1769, 0x0000 },
+  { 0x0700, 0x176b, 0x0000 },
+  { 0x8c00, 0x1772, 0x3000 },
+  { 0x8700, 0x176f, 0x2000 },
+  { 0x0700, 0x176e, 0x0000 },
+  { 0x0700, 0x1770, 0x0000 },
+  { 0x8700, 0x1780, 0x2000 },
+  { 0x0c00, 0x1773, 0x0000 },
+  { 0x0700, 0x1781, 0x0000 },
+  { 0x8700, 0x1792, 0x5000 },
+  { 0x8700, 0x178a, 0x4000 },
+  { 0x8700, 0x1786, 0x3000 },
+  { 0x8700, 0x1784, 0x2000 },
+  { 0x0700, 0x1783, 0x0000 },
+  { 0x0700, 0x1785, 0x0000 },
+  { 0x8700, 0x1788, 0x2000 },
+  { 0x0700, 0x1787, 0x0000 },
+  { 0x0700, 0x1789, 0x0000 },
+  { 0x8700, 0x178e, 0x3000 },
+  { 0x8700, 0x178c, 0x2000 },
+  { 0x0700, 0x178b, 0x0000 },
+  { 0x0700, 0x178d, 0x0000 },
+  { 0x8700, 0x1790, 0x2000 },
+  { 0x0700, 0x178f, 0x0000 },
+  { 0x0700, 0x1791, 0x0000 },
+  { 0x8700, 0x179a, 0x4000 },
+  { 0x8700, 0x1796, 0x3000 },
+  { 0x8700, 0x1794, 0x2000 },
+  { 0x0700, 0x1793, 0x0000 },
+  { 0x0700, 0x1795, 0x0000 },
+  { 0x8700, 0x1798, 0x2000 },
+  { 0x0700, 0x1797, 0x0000 },
+  { 0x0700, 0x1799, 0x0000 },
+  { 0x8700, 0x179e, 0x3000 },
+  { 0x8700, 0x179c, 0x2000 },
+  { 0x0700, 0x179b, 0x0000 },
+  { 0x0700, 0x179d, 0x0000 },
+  { 0x8700, 0x17a0, 0x2000 },
+  { 0x0700, 0x179f, 0x0000 },
+  { 0x0700, 0x17a1, 0x0000 },
+  { 0x8700, 0x1915, 0x9000 },
+  { 0x8700, 0x1837, 0x8000 },
+  { 0x8d00, 0x17e4, 0x7000 },
+  { 0x8a00, 0x17c2, 0x6000 },
+  { 0x8700, 0x17b2, 0x5000 },
+  { 0x8700, 0x17aa, 0x4000 },
+  { 0x8700, 0x17a6, 0x3000 },
+  { 0x8700, 0x17a4, 0x2000 },
+  { 0x0700, 0x17a3, 0x0000 },
+  { 0x0700, 0x17a5, 0x0000 },
+  { 0x8700, 0x17a8, 0x2000 },
+  { 0x0700, 0x17a7, 0x0000 },
+  { 0x0700, 0x17a9, 0x0000 },
+  { 0x8700, 0x17ae, 0x3000 },
+  { 0x8700, 0x17ac, 0x2000 },
+  { 0x0700, 0x17ab, 0x0000 },
+  { 0x0700, 0x17ad, 0x0000 },
+  { 0x8700, 0x17b0, 0x2000 },
+  { 0x0700, 0x17af, 0x0000 },
+  { 0x0700, 0x17b1, 0x0000 },
+  { 0x8c00, 0x17ba, 0x4000 },
+  { 0x8a00, 0x17b6, 0x3000 },
+  { 0x8100, 0x17b4, 0x2000 },
+  { 0x0700, 0x17b3, 0x0000 },
+  { 0x0100, 0x17b5, 0x0000 },
+  { 0x8c00, 0x17b8, 0x2000 },
+  { 0x0c00, 0x17b7, 0x0000 },
+  { 0x0c00, 0x17b9, 0x0000 },
+  { 0x8a00, 0x17be, 0x3000 },
+  { 0x8c00, 0x17bc, 0x2000 },
+  { 0x0c00, 0x17bb, 0x0000 },
+  { 0x0c00, 0x17bd, 0x0000 },
+  { 0x8a00, 0x17c0, 0x2000 },
+  { 0x0a00, 0x17bf, 0x0000 },
+  { 0x0a00, 0x17c1, 0x0000 },
+  { 0x8c00, 0x17d2, 0x5000 },
+  { 0x8c00, 0x17ca, 0x4000 },
+  { 0x8c00, 0x17c6, 0x3000 },
+  { 0x8a00, 0x17c4, 0x2000 },
+  { 0x0a00, 0x17c3, 0x0000 },
+  { 0x0a00, 0x17c5, 0x0000 },
+  { 0x8a00, 0x17c8, 0x2000 },
+  { 0x0a00, 0x17c7, 0x0000 },
+  { 0x0c00, 0x17c9, 0x0000 },
+  { 0x8c00, 0x17ce, 0x3000 },
+  { 0x8c00, 0x17cc, 0x2000 },
+  { 0x0c00, 0x17cb, 0x0000 },
+  { 0x0c00, 0x17cd, 0x0000 },
+  { 0x8c00, 0x17d0, 0x2000 },
+  { 0x0c00, 0x17cf, 0x0000 },
+  { 0x0c00, 0x17d1, 0x0000 },
+  { 0x9500, 0x17da, 0x4000 },
+  { 0x9500, 0x17d6, 0x3000 },
+  { 0x9500, 0x17d4, 0x2000 },
+  { 0x0c00, 0x17d3, 0x0000 },
+  { 0x1500, 0x17d5, 0x0000 },
+  { 0x9500, 0x17d8, 0x2000 },
+  { 0x0600, 0x17d7, 0x0000 },
+  { 0x1500, 0x17d9, 0x0000 },
+  { 0x8d00, 0x17e0, 0x3000 },
+  { 0x8700, 0x17dc, 0x2000 },
+  { 0x1700, 0x17db, 0x0000 },
+  { 0x0c00, 0x17dd, 0x0000 },
+  { 0x8d00, 0x17e2, 0x2000 },
+  { 0x0d00, 0x17e1, 0x0000 },
+  { 0x0d00, 0x17e3, 0x0000 },
+  { 0x8d00, 0x1811, 0x6000 },
+  { 0x9500, 0x1800, 0x5000 },
+  { 0x8f00, 0x17f2, 0x4000 },
+  { 0x8d00, 0x17e8, 0x3000 },
+  { 0x8d00, 0x17e6, 0x2000 },
+  { 0x0d00, 0x17e5, 0x0000 },
+  { 0x0d00, 0x17e7, 0x0000 },
+  { 0x8f00, 0x17f0, 0x2000 },
+  { 0x0d00, 0x17e9, 0x0000 },
+  { 0x0f00, 0x17f1, 0x0000 },
+  { 0x8f00, 0x17f6, 0x3000 },
+  { 0x8f00, 0x17f4, 0x2000 },
+  { 0x0f00, 0x17f3, 0x0000 },
+  { 0x0f00, 0x17f5, 0x0000 },
+  { 0x8f00, 0x17f8, 0x2000 },
+  { 0x0f00, 0x17f7, 0x0000 },
+  { 0x0f00, 0x17f9, 0x0000 },
+  { 0x9500, 0x1808, 0x4000 },
+  { 0x9500, 0x1804, 0x3000 },
+  { 0x9500, 0x1802, 0x2000 },
+  { 0x1500, 0x1801, 0x0000 },
+  { 0x1500, 0x1803, 0x0000 },
+  { 0x9100, 0x1806, 0x2000 },
+  { 0x1500, 0x1805, 0x0000 },
+  { 0x1500, 0x1807, 0x0000 },
+  { 0x8c00, 0x180c, 0x3000 },
+  { 0x9500, 0x180a, 0x2000 },
+  { 0x1500, 0x1809, 0x0000 },
+  { 0x0c00, 0x180b, 0x0000 },
+  { 0x9d00, 0x180e, 0x2000 },
+  { 0x0c00, 0x180d, 0x0000 },
+  { 0x0d00, 0x1810, 0x0000 },
+  { 0x8700, 0x1827, 0x5000 },
+  { 0x8d00, 0x1819, 0x4000 },
+  { 0x8d00, 0x1815, 0x3000 },
+  { 0x8d00, 0x1813, 0x2000 },
+  { 0x0d00, 0x1812, 0x0000 },
+  { 0x0d00, 0x1814, 0x0000 },
+  { 0x8d00, 0x1817, 0x2000 },
+  { 0x0d00, 0x1816, 0x0000 },
+  { 0x0d00, 0x1818, 0x0000 },
+  { 0x8700, 0x1823, 0x3000 },
+  { 0x8700, 0x1821, 0x2000 },
+  { 0x0700, 0x1820, 0x0000 },
+  { 0x0700, 0x1822, 0x0000 },
+  { 0x8700, 0x1825, 0x2000 },
+  { 0x0700, 0x1824, 0x0000 },
+  { 0x0700, 0x1826, 0x0000 },
+  { 0x8700, 0x182f, 0x4000 },
+  { 0x8700, 0x182b, 0x3000 },
+  { 0x8700, 0x1829, 0x2000 },
+  { 0x0700, 0x1828, 0x0000 },
+  { 0x0700, 0x182a, 0x0000 },
+  { 0x8700, 0x182d, 0x2000 },
+  { 0x0700, 0x182c, 0x0000 },
+  { 0x0700, 0x182e, 0x0000 },
+  { 0x8700, 0x1833, 0x3000 },
+  { 0x8700, 0x1831, 0x2000 },
+  { 0x0700, 0x1830, 0x0000 },
+  { 0x0700, 0x1832, 0x0000 },
+  { 0x8700, 0x1835, 0x2000 },
+  { 0x0700, 0x1834, 0x0000 },
+  { 0x0700, 0x1836, 0x0000 },
+  { 0x8700, 0x1877, 0x7000 },
+  { 0x8700, 0x1857, 0x6000 },
+  { 0x8700, 0x1847, 0x5000 },
+  { 0x8700, 0x183f, 0x4000 },
+  { 0x8700, 0x183b, 0x3000 },
+  { 0x8700, 0x1839, 0x2000 },
+  { 0x0700, 0x1838, 0x0000 },
+  { 0x0700, 0x183a, 0x0000 },
+  { 0x8700, 0x183d, 0x2000 },
+  { 0x0700, 0x183c, 0x0000 },
+  { 0x0700, 0x183e, 0x0000 },
+  { 0x8600, 0x1843, 0x3000 },
+  { 0x8700, 0x1841, 0x2000 },
+  { 0x0700, 0x1840, 0x0000 },
+  { 0x0700, 0x1842, 0x0000 },
+  { 0x8700, 0x1845, 0x2000 },
+  { 0x0700, 0x1844, 0x0000 },
+  { 0x0700, 0x1846, 0x0000 },
+  { 0x8700, 0x184f, 0x4000 },
+  { 0x8700, 0x184b, 0x3000 },
+  { 0x8700, 0x1849, 0x2000 },
+  { 0x0700, 0x1848, 0x0000 },
+  { 0x0700, 0x184a, 0x0000 },
+  { 0x8700, 0x184d, 0x2000 },
+  { 0x0700, 0x184c, 0x0000 },
+  { 0x0700, 0x184e, 0x0000 },
+  { 0x8700, 0x1853, 0x3000 },
+  { 0x8700, 0x1851, 0x2000 },
+  { 0x0700, 0x1850, 0x0000 },
+  { 0x0700, 0x1852, 0x0000 },
+  { 0x8700, 0x1855, 0x2000 },
+  { 0x0700, 0x1854, 0x0000 },
+  { 0x0700, 0x1856, 0x0000 },
+  { 0x8700, 0x1867, 0x5000 },
+  { 0x8700, 0x185f, 0x4000 },
+  { 0x8700, 0x185b, 0x3000 },
+  { 0x8700, 0x1859, 0x2000 },
+  { 0x0700, 0x1858, 0x0000 },
+  { 0x0700, 0x185a, 0x0000 },
+  { 0x8700, 0x185d, 0x2000 },
+  { 0x0700, 0x185c, 0x0000 },
+  { 0x0700, 0x185e, 0x0000 },
+  { 0x8700, 0x1863, 0x3000 },
+  { 0x8700, 0x1861, 0x2000 },
+  { 0x0700, 0x1860, 0x0000 },
+  { 0x0700, 0x1862, 0x0000 },
+  { 0x8700, 0x1865, 0x2000 },
+  { 0x0700, 0x1864, 0x0000 },
+  { 0x0700, 0x1866, 0x0000 },
+  { 0x8700, 0x186f, 0x4000 },
+  { 0x8700, 0x186b, 0x3000 },
+  { 0x8700, 0x1869, 0x2000 },
+  { 0x0700, 0x1868, 0x0000 },
+  { 0x0700, 0x186a, 0x0000 },
+  { 0x8700, 0x186d, 0x2000 },
+  { 0x0700, 0x186c, 0x0000 },
+  { 0x0700, 0x186e, 0x0000 },
+  { 0x8700, 0x1873, 0x3000 },
+  { 0x8700, 0x1871, 0x2000 },
+  { 0x0700, 0x1870, 0x0000 },
+  { 0x0700, 0x1872, 0x0000 },
+  { 0x8700, 0x1875, 0x2000 },
+  { 0x0700, 0x1874, 0x0000 },
+  { 0x0700, 0x1876, 0x0000 },
+  { 0x8700, 0x189f, 0x6000 },
+  { 0x8700, 0x188f, 0x5000 },
+  { 0x8700, 0x1887, 0x4000 },
+  { 0x8700, 0x1883, 0x3000 },
+  { 0x8700, 0x1881, 0x2000 },
+  { 0x0700, 0x1880, 0x0000 },
+  { 0x0700, 0x1882, 0x0000 },
+  { 0x8700, 0x1885, 0x2000 },
+  { 0x0700, 0x1884, 0x0000 },
+  { 0x0700, 0x1886, 0x0000 },
+  { 0x8700, 0x188b, 0x3000 },
+  { 0x8700, 0x1889, 0x2000 },
+  { 0x0700, 0x1888, 0x0000 },
+  { 0x0700, 0x188a, 0x0000 },
+  { 0x8700, 0x188d, 0x2000 },
+  { 0x0700, 0x188c, 0x0000 },
+  { 0x0700, 0x188e, 0x0000 },
+  { 0x8700, 0x1897, 0x4000 },
+  { 0x8700, 0x1893, 0x3000 },
+  { 0x8700, 0x1891, 0x2000 },
+  { 0x0700, 0x1890, 0x0000 },
+  { 0x0700, 0x1892, 0x0000 },
+  { 0x8700, 0x1895, 0x2000 },
+  { 0x0700, 0x1894, 0x0000 },
+  { 0x0700, 0x1896, 0x0000 },
+  { 0x8700, 0x189b, 0x3000 },
+  { 0x8700, 0x1899, 0x2000 },
+  { 0x0700, 0x1898, 0x0000 },
+  { 0x0700, 0x189a, 0x0000 },
+  { 0x8700, 0x189d, 0x2000 },
+  { 0x0700, 0x189c, 0x0000 },
+  { 0x0700, 0x189e, 0x0000 },
+  { 0x8700, 0x1905, 0x5000 },
+  { 0x8700, 0x18a7, 0x4000 },
+  { 0x8700, 0x18a3, 0x3000 },
+  { 0x8700, 0x18a1, 0x2000 },
+  { 0x0700, 0x18a0, 0x0000 },
+  { 0x0700, 0x18a2, 0x0000 },
+  { 0x8700, 0x18a5, 0x2000 },
+  { 0x0700, 0x18a4, 0x0000 },
+  { 0x0700, 0x18a6, 0x0000 },
+  { 0x8700, 0x1901, 0x3000 },
+  { 0x8c00, 0x18a9, 0x2000 },
+  { 0x0700, 0x18a8, 0x0000 },
+  { 0x0700, 0x1900, 0x0000 },
+  { 0x8700, 0x1903, 0x2000 },
+  { 0x0700, 0x1902, 0x0000 },
+  { 0x0700, 0x1904, 0x0000 },
+  { 0x8700, 0x190d, 0x4000 },
+  { 0x8700, 0x1909, 0x3000 },
+  { 0x8700, 0x1907, 0x2000 },
+  { 0x0700, 0x1906, 0x0000 },
+  { 0x0700, 0x1908, 0x0000 },
+  { 0x8700, 0x190b, 0x2000 },
+  { 0x0700, 0x190a, 0x0000 },
+  { 0x0700, 0x190c, 0x0000 },
+  { 0x8700, 0x1911, 0x3000 },
+  { 0x8700, 0x190f, 0x2000 },
+  { 0x0700, 0x190e, 0x0000 },
+  { 0x0700, 0x1910, 0x0000 },
+  { 0x8700, 0x1913, 0x2000 },
+  { 0x0700, 0x1912, 0x0000 },
+  { 0x0700, 0x1914, 0x0000 },
+  { 0x8500, 0x1d10, 0x8000 },
+  { 0x8700, 0x1963, 0x7000 },
+  { 0x9a00, 0x1940, 0x6000 },
+  { 0x8c00, 0x1928, 0x5000 },
+  { 0x8c00, 0x1920, 0x4000 },
+  { 0x8700, 0x1919, 0x3000 },
+  { 0x8700, 0x1917, 0x2000 },
+  { 0x0700, 0x1916, 0x0000 },
+  { 0x0700, 0x1918, 0x0000 },
+  { 0x8700, 0x191b, 0x2000 },
+  { 0x0700, 0x191a, 0x0000 },
+  { 0x0700, 0x191c, 0x0000 },
+  { 0x8a00, 0x1924, 0x3000 },
+  { 0x8c00, 0x1922, 0x2000 },
+  { 0x0c00, 0x1921, 0x0000 },
+  { 0x0a00, 0x1923, 0x0000 },
+  { 0x8a00, 0x1926, 0x2000 },
+  { 0x0a00, 0x1925, 0x0000 },
+  { 0x0c00, 0x1927, 0x0000 },
+  { 0x8a00, 0x1934, 0x4000 },
+  { 0x8a00, 0x1930, 0x3000 },
+  { 0x8a00, 0x192a, 0x2000 },
+  { 0x0a00, 0x1929, 0x0000 },
+  { 0x0a00, 0x192b, 0x0000 },
+  { 0x8c00, 0x1932, 0x2000 },
+  { 0x0a00, 0x1931, 0x0000 },
+  { 0x0a00, 0x1933, 0x0000 },
+  { 0x8a00, 0x1938, 0x3000 },
+  { 0x8a00, 0x1936, 0x2000 },
+  { 0x0a00, 0x1935, 0x0000 },
+  { 0x0a00, 0x1937, 0x0000 },
+  { 0x8c00, 0x193a, 0x2000 },
+  { 0x0c00, 0x1939, 0x0000 },
+  { 0x0c00, 0x193b, 0x0000 },
+  { 0x8700, 0x1953, 0x5000 },
+  { 0x8d00, 0x194b, 0x4000 },
+  { 0x8d00, 0x1947, 0x3000 },
+  { 0x9500, 0x1945, 0x2000 },
+  { 0x1500, 0x1944, 0x0000 },
+  { 0x0d00, 0x1946, 0x0000 },
+  { 0x8d00, 0x1949, 0x2000 },
+  { 0x0d00, 0x1948, 0x0000 },
+  { 0x0d00, 0x194a, 0x0000 },
+  { 0x8d00, 0x194f, 0x3000 },
+  { 0x8d00, 0x194d, 0x2000 },
+  { 0x0d00, 0x194c, 0x0000 },
+  { 0x0d00, 0x194e, 0x0000 },
+  { 0x8700, 0x1951, 0x2000 },
+  { 0x0700, 0x1950, 0x0000 },
+  { 0x0700, 0x1952, 0x0000 },
+  { 0x8700, 0x195b, 0x4000 },
+  { 0x8700, 0x1957, 0x3000 },
+  { 0x8700, 0x1955, 0x2000 },
+  { 0x0700, 0x1954, 0x0000 },
+  { 0x0700, 0x1956, 0x0000 },
+  { 0x8700, 0x1959, 0x2000 },
+  { 0x0700, 0x1958, 0x0000 },
+  { 0x0700, 0x195a, 0x0000 },
+  { 0x8700, 0x195f, 0x3000 },
+  { 0x8700, 0x195d, 0x2000 },
+  { 0x0700, 0x195c, 0x0000 },
+  { 0x0700, 0x195e, 0x0000 },
+  { 0x8700, 0x1961, 0x2000 },
+  { 0x0700, 0x1960, 0x0000 },
+  { 0x0700, 0x1962, 0x0000 },
+  { 0x9a00, 0x19f0, 0x6000 },
+  { 0x9a00, 0x19e0, 0x5000 },
+  { 0x8700, 0x196b, 0x4000 },
+  { 0x8700, 0x1967, 0x3000 },
+  { 0x8700, 0x1965, 0x2000 },
+  { 0x0700, 0x1964, 0x0000 },
+  { 0x0700, 0x1966, 0x0000 },
+  { 0x8700, 0x1969, 0x2000 },
+  { 0x0700, 0x1968, 0x0000 },
+  { 0x0700, 0x196a, 0x0000 },
+  { 0x8700, 0x1971, 0x3000 },
+  { 0x8700, 0x196d, 0x2000 },
+  { 0x0700, 0x196c, 0x0000 },
+  { 0x0700, 0x1970, 0x0000 },
+  { 0x8700, 0x1973, 0x2000 },
+  { 0x0700, 0x1972, 0x0000 },
+  { 0x0700, 0x1974, 0x0000 },
+  { 0x9a00, 0x19e8, 0x4000 },
+  { 0x9a00, 0x19e4, 0x3000 },
+  { 0x9a00, 0x19e2, 0x2000 },
+  { 0x1a00, 0x19e1, 0x0000 },
+  { 0x1a00, 0x19e3, 0x0000 },
+  { 0x9a00, 0x19e6, 0x2000 },
+  { 0x1a00, 0x19e5, 0x0000 },
+  { 0x1a00, 0x19e7, 0x0000 },
+  { 0x9a00, 0x19ec, 0x3000 },
+  { 0x9a00, 0x19ea, 0x2000 },
+  { 0x1a00, 0x19e9, 0x0000 },
+  { 0x1a00, 0x19eb, 0x0000 },
+  { 0x9a00, 0x19ee, 0x2000 },
+  { 0x1a00, 0x19ed, 0x0000 },
+  { 0x1a00, 0x19ef, 0x0000 },
+  { 0x8500, 0x1d00, 0x5000 },
+  { 0x9a00, 0x19f8, 0x4000 },
+  { 0x9a00, 0x19f4, 0x3000 },
+  { 0x9a00, 0x19f2, 0x2000 },
+  { 0x1a00, 0x19f1, 0x0000 },
+  { 0x1a00, 0x19f3, 0x0000 },
+  { 0x9a00, 0x19f6, 0x2000 },
+  { 0x1a00, 0x19f5, 0x0000 },
+  { 0x1a00, 0x19f7, 0x0000 },
+  { 0x9a00, 0x19fc, 0x3000 },
+  { 0x9a00, 0x19fa, 0x2000 },
+  { 0x1a00, 0x19f9, 0x0000 },
+  { 0x1a00, 0x19fb, 0x0000 },
+  { 0x9a00, 0x19fe, 0x2000 },
+  { 0x1a00, 0x19fd, 0x0000 },
+  { 0x1a00, 0x19ff, 0x0000 },
+  { 0x8500, 0x1d08, 0x4000 },
+  { 0x8500, 0x1d04, 0x3000 },
+  { 0x8500, 0x1d02, 0x2000 },
+  { 0x0500, 0x1d01, 0x0000 },
+  { 0x0500, 0x1d03, 0x0000 },
+  { 0x8500, 0x1d06, 0x2000 },
+  { 0x0500, 0x1d05, 0x0000 },
+  { 0x0500, 0x1d07, 0x0000 },
+  { 0x8500, 0x1d0c, 0x3000 },
+  { 0x8500, 0x1d0a, 0x2000 },
+  { 0x0500, 0x1d09, 0x0000 },
+  { 0x0500, 0x1d0b, 0x0000 },
+  { 0x8500, 0x1d0e, 0x2000 },
+  { 0x0500, 0x1d0d, 0x0000 },
+  { 0x0500, 0x1d0f, 0x0000 },
+  { 0x8600, 0x1d50, 0x7000 },
+  { 0x8600, 0x1d30, 0x6000 },
+  { 0x8500, 0x1d20, 0x5000 },
+  { 0x8500, 0x1d18, 0x4000 },
+  { 0x8500, 0x1d14, 0x3000 },
+  { 0x8500, 0x1d12, 0x2000 },
+  { 0x0500, 0x1d11, 0x0000 },
+  { 0x0500, 0x1d13, 0x0000 },
+  { 0x8500, 0x1d16, 0x2000 },
+  { 0x0500, 0x1d15, 0x0000 },
+  { 0x0500, 0x1d17, 0x0000 },
+  { 0x8500, 0x1d1c, 0x3000 },
+  { 0x8500, 0x1d1a, 0x2000 },
+  { 0x0500, 0x1d19, 0x0000 },
+  { 0x0500, 0x1d1b, 0x0000 },
+  { 0x8500, 0x1d1e, 0x2000 },
+  { 0x0500, 0x1d1d, 0x0000 },
+  { 0x0500, 0x1d1f, 0x0000 },
+  { 0x8500, 0x1d28, 0x4000 },
+  { 0x8500, 0x1d24, 0x3000 },
+  { 0x8500, 0x1d22, 0x2000 },
+  { 0x0500, 0x1d21, 0x0000 },
+  { 0x0500, 0x1d23, 0x0000 },
+  { 0x8500, 0x1d26, 0x2000 },
+  { 0x0500, 0x1d25, 0x0000 },
+  { 0x0500, 0x1d27, 0x0000 },
+  { 0x8600, 0x1d2c, 0x3000 },
+  { 0x8500, 0x1d2a, 0x2000 },
+  { 0x0500, 0x1d29, 0x0000 },
+  { 0x0500, 0x1d2b, 0x0000 },
+  { 0x8600, 0x1d2e, 0x2000 },
+  { 0x0600, 0x1d2d, 0x0000 },
+  { 0x0600, 0x1d2f, 0x0000 },
+  { 0x8600, 0x1d40, 0x5000 },
+  { 0x8600, 0x1d38, 0x4000 },
+  { 0x8600, 0x1d34, 0x3000 },
+  { 0x8600, 0x1d32, 0x2000 },
+  { 0x0600, 0x1d31, 0x0000 },
+  { 0x0600, 0x1d33, 0x0000 },
+  { 0x8600, 0x1d36, 0x2000 },
+  { 0x0600, 0x1d35, 0x0000 },
+  { 0x0600, 0x1d37, 0x0000 },
+  { 0x8600, 0x1d3c, 0x3000 },
+  { 0x8600, 0x1d3a, 0x2000 },
+  { 0x0600, 0x1d39, 0x0000 },
+  { 0x0600, 0x1d3b, 0x0000 },
+  { 0x8600, 0x1d3e, 0x2000 },
+  { 0x0600, 0x1d3d, 0x0000 },
+  { 0x0600, 0x1d3f, 0x0000 },
+  { 0x8600, 0x1d48, 0x4000 },
+  { 0x8600, 0x1d44, 0x3000 },
+  { 0x8600, 0x1d42, 0x2000 },
+  { 0x0600, 0x1d41, 0x0000 },
+  { 0x0600, 0x1d43, 0x0000 },
+  { 0x8600, 0x1d46, 0x2000 },
+  { 0x0600, 0x1d45, 0x0000 },
+  { 0x0600, 0x1d47, 0x0000 },
+  { 0x8600, 0x1d4c, 0x3000 },
+  { 0x8600, 0x1d4a, 0x2000 },
+  { 0x0600, 0x1d49, 0x0000 },
+  { 0x0600, 0x1d4b, 0x0000 },
+  { 0x8600, 0x1d4e, 0x2000 },
+  { 0x0600, 0x1d4d, 0x0000 },
+  { 0x0600, 0x1d4f, 0x0000 },
+  { 0x8900, 0x1e04, 0x6001 },
+  { 0x8600, 0x1d60, 0x5000 },
+  { 0x8600, 0x1d58, 0x4000 },
+  { 0x8600, 0x1d54, 0x3000 },
+  { 0x8600, 0x1d52, 0x2000 },
+  { 0x0600, 0x1d51, 0x0000 },
+  { 0x0600, 0x1d53, 0x0000 },
+  { 0x8600, 0x1d56, 0x2000 },
+  { 0x0600, 0x1d55, 0x0000 },
+  { 0x0600, 0x1d57, 0x0000 },
+  { 0x8600, 0x1d5c, 0x3000 },
+  { 0x8600, 0x1d5a, 0x2000 },
+  { 0x0600, 0x1d59, 0x0000 },
+  { 0x0600, 0x1d5b, 0x0000 },
+  { 0x8600, 0x1d5e, 0x2000 },
+  { 0x0600, 0x1d5d, 0x0000 },
+  { 0x0600, 0x1d5f, 0x0000 },
+  { 0x8500, 0x1d68, 0x4000 },
+  { 0x8500, 0x1d64, 0x3000 },
+  { 0x8500, 0x1d62, 0x2000 },
+  { 0x0600, 0x1d61, 0x0000 },
+  { 0x0500, 0x1d63, 0x0000 },
+  { 0x8500, 0x1d66, 0x2000 },
+  { 0x0500, 0x1d65, 0x0000 },
+  { 0x0500, 0x1d67, 0x0000 },
+  { 0x8900, 0x1e00, 0x3001 },
+  { 0x8500, 0x1d6a, 0x2000 },
+  { 0x0500, 0x1d69, 0x0000 },
+  { 0x0500, 0x1d6b, 0x0000 },
+  { 0x8900, 0x1e02, 0x2001 },
+  { 0x0500, 0x1e01, 0x0fff },
+  { 0x0500, 0x1e03, 0x0fff },
+  { 0x8900, 0x1e14, 0x5001 },
+  { 0x8900, 0x1e0c, 0x4001 },
+  { 0x8900, 0x1e08, 0x3001 },
+  { 0x8900, 0x1e06, 0x2001 },
+  { 0x0500, 0x1e05, 0x0fff },
+  { 0x0500, 0x1e07, 0x0fff },
+  { 0x8900, 0x1e0a, 0x2001 },
+  { 0x0500, 0x1e09, 0x0fff },
+  { 0x0500, 0x1e0b, 0x0fff },
+  { 0x8900, 0x1e10, 0x3001 },
+  { 0x8900, 0x1e0e, 0x2001 },
+  { 0x0500, 0x1e0d, 0x0fff },
+  { 0x0500, 0x1e0f, 0x0fff },
+  { 0x8900, 0x1e12, 0x2001 },
+  { 0x0500, 0x1e11, 0x0fff },
+  { 0x0500, 0x1e13, 0x0fff },
+  { 0x8900, 0x1e1c, 0x4001 },
+  { 0x8900, 0x1e18, 0x3001 },
+  { 0x8900, 0x1e16, 0x2001 },
+  { 0x0500, 0x1e15, 0x0fff },
+  { 0x0500, 0x1e17, 0x0fff },
+  { 0x8900, 0x1e1a, 0x2001 },
+  { 0x0500, 0x1e19, 0x0fff },
+  { 0x0500, 0x1e1b, 0x0fff },
+  { 0x8900, 0x1e20, 0x3001 },
+  { 0x8900, 0x1e1e, 0x2001 },
+  { 0x0500, 0x1e1d, 0x0fff },
+  { 0x0500, 0x1e1f, 0x0fff },
+  { 0x8900, 0x1e22, 0x2001 },
+  { 0x0500, 0x1e21, 0x0fff },
+  { 0x0500, 0x1e23, 0x0fff },
+  { 0x9600, 0x2045, 0xa000 },
+  { 0x8500, 0x1f32, 0x9008 },
+  { 0x8900, 0x1ea8, 0x8001 },
+  { 0x8900, 0x1e64, 0x7001 },
+  { 0x8900, 0x1e44, 0x6001 },
+  { 0x8900, 0x1e34, 0x5001 },
+  { 0x8900, 0x1e2c, 0x4001 },
+  { 0x8900, 0x1e28, 0x3001 },
+  { 0x8900, 0x1e26, 0x2001 },
+  { 0x0500, 0x1e25, 0x0fff },
+  { 0x0500, 0x1e27, 0x0fff },
+  { 0x8900, 0x1e2a, 0x2001 },
+  { 0x0500, 0x1e29, 0x0fff },
+  { 0x0500, 0x1e2b, 0x0fff },
+  { 0x8900, 0x1e30, 0x3001 },
+  { 0x8900, 0x1e2e, 0x2001 },
+  { 0x0500, 0x1e2d, 0x0fff },
+  { 0x0500, 0x1e2f, 0x0fff },
+  { 0x8900, 0x1e32, 0x2001 },
+  { 0x0500, 0x1e31, 0x0fff },
+  { 0x0500, 0x1e33, 0x0fff },
+  { 0x8900, 0x1e3c, 0x4001 },
+  { 0x8900, 0x1e38, 0x3001 },
+  { 0x8900, 0x1e36, 0x2001 },
+  { 0x0500, 0x1e35, 0x0fff },
+  { 0x0500, 0x1e37, 0x0fff },
+  { 0x8900, 0x1e3a, 0x2001 },
+  { 0x0500, 0x1e39, 0x0fff },
+  { 0x0500, 0x1e3b, 0x0fff },
+  { 0x8900, 0x1e40, 0x3001 },
+  { 0x8900, 0x1e3e, 0x2001 },
+  { 0x0500, 0x1e3d, 0x0fff },
+  { 0x0500, 0x1e3f, 0x0fff },
+  { 0x8900, 0x1e42, 0x2001 },
+  { 0x0500, 0x1e41, 0x0fff },
+  { 0x0500, 0x1e43, 0x0fff },
+  { 0x8900, 0x1e54, 0x5001 },
+  { 0x8900, 0x1e4c, 0x4001 },
+  { 0x8900, 0x1e48, 0x3001 },
+  { 0x8900, 0x1e46, 0x2001 },
+  { 0x0500, 0x1e45, 0x0fff },
+  { 0x0500, 0x1e47, 0x0fff },
+  { 0x8900, 0x1e4a, 0x2001 },
+  { 0x0500, 0x1e49, 0x0fff },
+  { 0x0500, 0x1e4b, 0x0fff },
+  { 0x8900, 0x1e50, 0x3001 },
+  { 0x8900, 0x1e4e, 0x2001 },
+  { 0x0500, 0x1e4d, 0x0fff },
+  { 0x0500, 0x1e4f, 0x0fff },
+  { 0x8900, 0x1e52, 0x2001 },
+  { 0x0500, 0x1e51, 0x0fff },
+  { 0x0500, 0x1e53, 0x0fff },
+  { 0x8900, 0x1e5c, 0x4001 },
+  { 0x8900, 0x1e58, 0x3001 },
+  { 0x8900, 0x1e56, 0x2001 },
+  { 0x0500, 0x1e55, 0x0fff },
+  { 0x0500, 0x1e57, 0x0fff },
+  { 0x8900, 0x1e5a, 0x2001 },
+  { 0x0500, 0x1e59, 0x0fff },
+  { 0x0500, 0x1e5b, 0x0fff },
+  { 0x8900, 0x1e60, 0x3001 },
+  { 0x8900, 0x1e5e, 0x2001 },
+  { 0x0500, 0x1e5d, 0x0fff },
+  { 0x0500, 0x1e5f, 0x0fff },
+  { 0x8900, 0x1e62, 0x2001 },
+  { 0x0500, 0x1e61, 0x0fff },
+  { 0x0500, 0x1e63, 0x0fff },
+  { 0x8900, 0x1e84, 0x6001 },
+  { 0x8900, 0x1e74, 0x5001 },
+  { 0x8900, 0x1e6c, 0x4001 },
+  { 0x8900, 0x1e68, 0x3001 },
+  { 0x8900, 0x1e66, 0x2001 },
+  { 0x0500, 0x1e65, 0x0fff },
+  { 0x0500, 0x1e67, 0x0fff },
+  { 0x8900, 0x1e6a, 0x2001 },
+  { 0x0500, 0x1e69, 0x0fff },
+  { 0x0500, 0x1e6b, 0x0fff },
+  { 0x8900, 0x1e70, 0x3001 },
+  { 0x8900, 0x1e6e, 0x2001 },
+  { 0x0500, 0x1e6d, 0x0fff },
+  { 0x0500, 0x1e6f, 0x0fff },
+  { 0x8900, 0x1e72, 0x2001 },
+  { 0x0500, 0x1e71, 0x0fff },
+  { 0x0500, 0x1e73, 0x0fff },
+  { 0x8900, 0x1e7c, 0x4001 },
+  { 0x8900, 0x1e78, 0x3001 },
+  { 0x8900, 0x1e76, 0x2001 },
+  { 0x0500, 0x1e75, 0x0fff },
+  { 0x0500, 0x1e77, 0x0fff },
+  { 0x8900, 0x1e7a, 0x2001 },
+  { 0x0500, 0x1e79, 0x0fff },
+  { 0x0500, 0x1e7b, 0x0fff },
+  { 0x8900, 0x1e80, 0x3001 },
+  { 0x8900, 0x1e7e, 0x2001 },
+  { 0x0500, 0x1e7d, 0x0fff },
+  { 0x0500, 0x1e7f, 0x0fff },
+  { 0x8900, 0x1e82, 0x2001 },
+  { 0x0500, 0x1e81, 0x0fff },
+  { 0x0500, 0x1e83, 0x0fff },
+  { 0x8900, 0x1e94, 0x5001 },
+  { 0x8900, 0x1e8c, 0x4001 },
+  { 0x8900, 0x1e88, 0x3001 },
+  { 0x8900, 0x1e86, 0x2001 },
+  { 0x0500, 0x1e85, 0x0fff },
+  { 0x0500, 0x1e87, 0x0fff },
+  { 0x8900, 0x1e8a, 0x2001 },
+  { 0x0500, 0x1e89, 0x0fff },
+  { 0x0500, 0x1e8b, 0x0fff },
+  { 0x8900, 0x1e90, 0x3001 },
+  { 0x8900, 0x1e8e, 0x2001 },
+  { 0x0500, 0x1e8d, 0x0fff },
+  { 0x0500, 0x1e8f, 0x0fff },
+  { 0x8900, 0x1e92, 0x2001 },
+  { 0x0500, 0x1e91, 0x0fff },
+  { 0x0500, 0x1e93, 0x0fff },
+  { 0x8900, 0x1ea0, 0x4001 },
+  { 0x8500, 0x1e98, 0x3000 },
+  { 0x8500, 0x1e96, 0x2000 },
+  { 0x0500, 0x1e95, 0x0fff },
+  { 0x0500, 0x1e97, 0x0000 },
+  { 0x8500, 0x1e9a, 0x2000 },
+  { 0x0500, 0x1e99, 0x0000 },
+  { 0x0500, 0x1e9b, 0x0fc5 },
+  { 0x8900, 0x1ea4, 0x3001 },
+  { 0x8900, 0x1ea2, 0x2001 },
+  { 0x0500, 0x1ea1, 0x0fff },
+  { 0x0500, 0x1ea3, 0x0fff },
+  { 0x8900, 0x1ea6, 0x2001 },
+  { 0x0500, 0x1ea5, 0x0fff },
+  { 0x0500, 0x1ea7, 0x0fff },
+  { 0x8900, 0x1ee8, 0x7001 },
+  { 0x8900, 0x1ec8, 0x6001 },
+  { 0x8900, 0x1eb8, 0x5001 },
+  { 0x8900, 0x1eb0, 0x4001 },
+  { 0x8900, 0x1eac, 0x3001 },
+  { 0x8900, 0x1eaa, 0x2001 },
+  { 0x0500, 0x1ea9, 0x0fff },
+  { 0x0500, 0x1eab, 0x0fff },
+  { 0x8900, 0x1eae, 0x2001 },
+  { 0x0500, 0x1ead, 0x0fff },
+  { 0x0500, 0x1eaf, 0x0fff },
+  { 0x8900, 0x1eb4, 0x3001 },
+  { 0x8900, 0x1eb2, 0x2001 },
+  { 0x0500, 0x1eb1, 0x0fff },
+  { 0x0500, 0x1eb3, 0x0fff },
+  { 0x8900, 0x1eb6, 0x2001 },
+  { 0x0500, 0x1eb5, 0x0fff },
+  { 0x0500, 0x1eb7, 0x0fff },
+  { 0x8900, 0x1ec0, 0x4001 },
+  { 0x8900, 0x1ebc, 0x3001 },
+  { 0x8900, 0x1eba, 0x2001 },
+  { 0x0500, 0x1eb9, 0x0fff },
+  { 0x0500, 0x1ebb, 0x0fff },
+  { 0x8900, 0x1ebe, 0x2001 },
+  { 0x0500, 0x1ebd, 0x0fff },
+  { 0x0500, 0x1ebf, 0x0fff },
+  { 0x8900, 0x1ec4, 0x3001 },
+  { 0x8900, 0x1ec2, 0x2001 },
+  { 0x0500, 0x1ec1, 0x0fff },
+  { 0x0500, 0x1ec3, 0x0fff },
+  { 0x8900, 0x1ec6, 0x2001 },
+  { 0x0500, 0x1ec5, 0x0fff },
+  { 0x0500, 0x1ec7, 0x0fff },
+  { 0x8900, 0x1ed8, 0x5001 },
+  { 0x8900, 0x1ed0, 0x4001 },
+  { 0x8900, 0x1ecc, 0x3001 },
+  { 0x8900, 0x1eca, 0x2001 },
+  { 0x0500, 0x1ec9, 0x0fff },
+  { 0x0500, 0x1ecb, 0x0fff },
+  { 0x8900, 0x1ece, 0x2001 },
+  { 0x0500, 0x1ecd, 0x0fff },
+  { 0x0500, 0x1ecf, 0x0fff },
+  { 0x8900, 0x1ed4, 0x3001 },
+  { 0x8900, 0x1ed2, 0x2001 },
+  { 0x0500, 0x1ed1, 0x0fff },
+  { 0x0500, 0x1ed3, 0x0fff },
+  { 0x8900, 0x1ed6, 0x2001 },
+  { 0x0500, 0x1ed5, 0x0fff },
+  { 0x0500, 0x1ed7, 0x0fff },
+  { 0x8900, 0x1ee0, 0x4001 },
+  { 0x8900, 0x1edc, 0x3001 },
+  { 0x8900, 0x1eda, 0x2001 },
+  { 0x0500, 0x1ed9, 0x0fff },
+  { 0x0500, 0x1edb, 0x0fff },
+  { 0x8900, 0x1ede, 0x2001 },
+  { 0x0500, 0x1edd, 0x0fff },
+  { 0x0500, 0x1edf, 0x0fff },
+  { 0x8900, 0x1ee4, 0x3001 },
+  { 0x8900, 0x1ee2, 0x2001 },
+  { 0x0500, 0x1ee1, 0x0fff },
+  { 0x0500, 0x1ee3, 0x0fff },
+  { 0x8900, 0x1ee6, 0x2001 },
+  { 0x0500, 0x1ee5, 0x0fff },
+  { 0x0500, 0x1ee7, 0x0fff },
+  { 0x8900, 0x1f0e, 0x6ff8 },
+  { 0x8900, 0x1ef8, 0x5001 },
+  { 0x8900, 0x1ef0, 0x4001 },
+  { 0x8900, 0x1eec, 0x3001 },
+  { 0x8900, 0x1eea, 0x2001 },
+  { 0x0500, 0x1ee9, 0x0fff },
+  { 0x0500, 0x1eeb, 0x0fff },
+  { 0x8900, 0x1eee, 0x2001 },
+  { 0x0500, 0x1eed, 0x0fff },
+  { 0x0500, 0x1eef, 0x0fff },
+  { 0x8900, 0x1ef4, 0x3001 },
+  { 0x8900, 0x1ef2, 0x2001 },
+  { 0x0500, 0x1ef1, 0x0fff },
+  { 0x0500, 0x1ef3, 0x0fff },
+  { 0x8900, 0x1ef6, 0x2001 },
+  { 0x0500, 0x1ef5, 0x0fff },
+  { 0x0500, 0x1ef7, 0x0fff },
+  { 0x8500, 0x1f06, 0x4008 },
+  { 0x8500, 0x1f02, 0x3008 },
+  { 0x8500, 0x1f00, 0x2008 },
+  { 0x0500, 0x1ef9, 0x0fff },
+  { 0x0500, 0x1f01, 0x0008 },
+  { 0x8500, 0x1f04, 0x2008 },
+  { 0x0500, 0x1f03, 0x0008 },
+  { 0x0500, 0x1f05, 0x0008 },
+  { 0x8900, 0x1f0a, 0x3ff8 },
+  { 0x8900, 0x1f08, 0x2ff8 },
+  { 0x0500, 0x1f07, 0x0008 },
+  { 0x0900, 0x1f09, 0x0ff8 },
+  { 0x8900, 0x1f0c, 0x2ff8 },
+  { 0x0900, 0x1f0b, 0x0ff8 },
+  { 0x0900, 0x1f0d, 0x0ff8 },
+  { 0x8500, 0x1f22, 0x5008 },
+  { 0x8900, 0x1f18, 0x4ff8 },
+  { 0x8500, 0x1f12, 0x3008 },
+  { 0x8500, 0x1f10, 0x2008 },
+  { 0x0900, 0x1f0f, 0x0ff8 },
+  { 0x0500, 0x1f11, 0x0008 },
+  { 0x8500, 0x1f14, 0x2008 },
+  { 0x0500, 0x1f13, 0x0008 },
+  { 0x0500, 0x1f15, 0x0008 },
+  { 0x8900, 0x1f1c, 0x3ff8 },
+  { 0x8900, 0x1f1a, 0x2ff8 },
+  { 0x0900, 0x1f19, 0x0ff8 },
+  { 0x0900, 0x1f1b, 0x0ff8 },
+  { 0x8500, 0x1f20, 0x2008 },
+  { 0x0900, 0x1f1d, 0x0ff8 },
+  { 0x0500, 0x1f21, 0x0008 },
+  { 0x8900, 0x1f2a, 0x4ff8 },
+  { 0x8500, 0x1f26, 0x3008 },
+  { 0x8500, 0x1f24, 0x2008 },
+  { 0x0500, 0x1f23, 0x0008 },
+  { 0x0500, 0x1f25, 0x0008 },
+  { 0x8900, 0x1f28, 0x2ff8 },
+  { 0x0500, 0x1f27, 0x0008 },
+  { 0x0900, 0x1f29, 0x0ff8 },
+  { 0x8900, 0x1f2e, 0x3ff8 },
+  { 0x8900, 0x1f2c, 0x2ff8 },
+  { 0x0900, 0x1f2b, 0x0ff8 },
+  { 0x0900, 0x1f2d, 0x0ff8 },
+  { 0x8500, 0x1f30, 0x2008 },
+  { 0x0900, 0x1f2f, 0x0ff8 },
+  { 0x0500, 0x1f31, 0x0008 },
+  { 0x9800, 0x1fbd, 0x8000 },
+  { 0x8500, 0x1f7a, 0x7070 },
+  { 0x8500, 0x1f56, 0x6000 },
+  { 0x8500, 0x1f42, 0x5008 },
+  { 0x8900, 0x1f3a, 0x4ff8 },
+  { 0x8500, 0x1f36, 0x3008 },
+  { 0x8500, 0x1f34, 0x2008 },
+  { 0x0500, 0x1f33, 0x0008 },
+  { 0x0500, 0x1f35, 0x0008 },
+  { 0x8900, 0x1f38, 0x2ff8 },
+  { 0x0500, 0x1f37, 0x0008 },
+  { 0x0900, 0x1f39, 0x0ff8 },
+  { 0x8900, 0x1f3e, 0x3ff8 },
+  { 0x8900, 0x1f3c, 0x2ff8 },
+  { 0x0900, 0x1f3b, 0x0ff8 },
+  { 0x0900, 0x1f3d, 0x0ff8 },
+  { 0x8500, 0x1f40, 0x2008 },
+  { 0x0900, 0x1f3f, 0x0ff8 },
+  { 0x0500, 0x1f41, 0x0008 },
+  { 0x8900, 0x1f4c, 0x4ff8 },
+  { 0x8900, 0x1f48, 0x3ff8 },
+  { 0x8500, 0x1f44, 0x2008 },
+  { 0x0500, 0x1f43, 0x0008 },
+  { 0x0500, 0x1f45, 0x0008 },
+  { 0x8900, 0x1f4a, 0x2ff8 },
+  { 0x0900, 0x1f49, 0x0ff8 },
+  { 0x0900, 0x1f4b, 0x0ff8 },
+  { 0x8500, 0x1f52, 0x3000 },
+  { 0x8500, 0x1f50, 0x2000 },
+  { 0x0900, 0x1f4d, 0x0ff8 },
+  { 0x0500, 0x1f51, 0x0008 },
+  { 0x8500, 0x1f54, 0x2000 },
+  { 0x0500, 0x1f53, 0x0008 },
+  { 0x0500, 0x1f55, 0x0008 },
+  { 0x8900, 0x1f6a, 0x5ff8 },
+  { 0x8500, 0x1f62, 0x4008 },
+  { 0x8900, 0x1f5d, 0x3ff8 },
+  { 0x8900, 0x1f59, 0x2ff8 },
+  { 0x0500, 0x1f57, 0x0008 },
+  { 0x0900, 0x1f5b, 0x0ff8 },
+  { 0x8500, 0x1f60, 0x2008 },
+  { 0x0900, 0x1f5f, 0x0ff8 },
+  { 0x0500, 0x1f61, 0x0008 },
+  { 0x8500, 0x1f66, 0x3008 },
+  { 0x8500, 0x1f64, 0x2008 },
+  { 0x0500, 0x1f63, 0x0008 },
+  { 0x0500, 0x1f65, 0x0008 },
+  { 0x8900, 0x1f68, 0x2ff8 },
+  { 0x0500, 0x1f67, 0x0008 },
+  { 0x0900, 0x1f69, 0x0ff8 },
+  { 0x8500, 0x1f72, 0x4056 },
+  { 0x8900, 0x1f6e, 0x3ff8 },
+  { 0x8900, 0x1f6c, 0x2ff8 },
+  { 0x0900, 0x1f6b, 0x0ff8 },
+  { 0x0900, 0x1f6d, 0x0ff8 },
+  { 0x8500, 0x1f70, 0x204a },
+  { 0x0900, 0x1f6f, 0x0ff8 },
+  { 0x0500, 0x1f71, 0x004a },
+  { 0x8500, 0x1f76, 0x3064 },
+  { 0x8500, 0x1f74, 0x2056 },
+  { 0x0500, 0x1f73, 0x0056 },
+  { 0x0500, 0x1f75, 0x0056 },
+  { 0x8500, 0x1f78, 0x2080 },
+  { 0x0500, 0x1f77, 0x0064 },
+  { 0x0500, 0x1f79, 0x0080 },
+  { 0x8800, 0x1f9c, 0x6000 },
+  { 0x8800, 0x1f8c, 0x5000 },
+  { 0x8500, 0x1f84, 0x4008 },
+  { 0x8500, 0x1f80, 0x3008 },
+  { 0x8500, 0x1f7c, 0x207e },
+  { 0x0500, 0x1f7b, 0x0070 },
+  { 0x0500, 0x1f7d, 0x007e },
+  { 0x8500, 0x1f82, 0x2008 },
+  { 0x0500, 0x1f81, 0x0008 },
+  { 0x0500, 0x1f83, 0x0008 },
+  { 0x8800, 0x1f88, 0x3000 },
+  { 0x8500, 0x1f86, 0x2008 },
+  { 0x0500, 0x1f85, 0x0008 },
+  { 0x0500, 0x1f87, 0x0008 },
+  { 0x8800, 0x1f8a, 0x2000 },
+  { 0x0800, 0x1f89, 0x0000 },
+  { 0x0800, 0x1f8b, 0x0000 },
+  { 0x8500, 0x1f94, 0x4008 },
+  { 0x8500, 0x1f90, 0x3008 },
+  { 0x8800, 0x1f8e, 0x2000 },
+  { 0x0800, 0x1f8d, 0x0000 },
+  { 0x0800, 0x1f8f, 0x0000 },
+  { 0x8500, 0x1f92, 0x2008 },
+  { 0x0500, 0x1f91, 0x0008 },
+  { 0x0500, 0x1f93, 0x0008 },
+  { 0x8800, 0x1f98, 0x3000 },
+  { 0x8500, 0x1f96, 0x2008 },
+  { 0x0500, 0x1f95, 0x0008 },
+  { 0x0500, 0x1f97, 0x0008 },
+  { 0x8800, 0x1f9a, 0x2000 },
+  { 0x0800, 0x1f99, 0x0000 },
+  { 0x0800, 0x1f9b, 0x0000 },
+  { 0x8800, 0x1fac, 0x5000 },
+  { 0x8500, 0x1fa4, 0x4008 },
+  { 0x8500, 0x1fa0, 0x3008 },
+  { 0x8800, 0x1f9e, 0x2000 },
+  { 0x0800, 0x1f9d, 0x0000 },
+  { 0x0800, 0x1f9f, 0x0000 },
+  { 0x8500, 0x1fa2, 0x2008 },
+  { 0x0500, 0x1fa1, 0x0008 },
+  { 0x0500, 0x1fa3, 0x0008 },
+  { 0x8800, 0x1fa8, 0x3000 },
+  { 0x8500, 0x1fa6, 0x2008 },
+  { 0x0500, 0x1fa5, 0x0008 },
+  { 0x0500, 0x1fa7, 0x0008 },
+  { 0x8800, 0x1faa, 0x2000 },
+  { 0x0800, 0x1fa9, 0x0000 },
+  { 0x0800, 0x1fab, 0x0000 },
+  { 0x8500, 0x1fb4, 0x4000 },
+  { 0x8500, 0x1fb0, 0x3008 },
+  { 0x8800, 0x1fae, 0x2000 },
+  { 0x0800, 0x1fad, 0x0000 },
+  { 0x0800, 0x1faf, 0x0000 },
+  { 0x8500, 0x1fb2, 0x2000 },
+  { 0x0500, 0x1fb1, 0x0008 },
+  { 0x0500, 0x1fb3, 0x0009 },
+  { 0x8900, 0x1fb9, 0x3ff8 },
+  { 0x8500, 0x1fb7, 0x2000 },
+  { 0x0500, 0x1fb6, 0x0000 },
+  { 0x0900, 0x1fb8, 0x0ff8 },
+  { 0x8900, 0x1fbb, 0x2fb6 },
+  { 0x0900, 0x1fba, 0x0fb6 },
+  { 0x0800, 0x1fbc, 0x0000 },
+  { 0x9d00, 0x2005, 0x7000 },
+  { 0x8500, 0x1fe1, 0x6008 },
+  { 0x9800, 0x1fce, 0x5000 },
+  { 0x8500, 0x1fc6, 0x4000 },
+  { 0x9800, 0x1fc1, 0x3000 },
+  { 0x9800, 0x1fbf, 0x2000 },
+  { 0x0500, 0x1fbe, 0x0000 },
+  { 0x1800, 0x1fc0, 0x0000 },
+  { 0x8500, 0x1fc3, 0x2009 },
+  { 0x0500, 0x1fc2, 0x0000 },
+  { 0x0500, 0x1fc4, 0x0000 },
+  { 0x8900, 0x1fca, 0x3faa },
+  { 0x8900, 0x1fc8, 0x2faa },
+  { 0x0500, 0x1fc7, 0x0000 },
+  { 0x0900, 0x1fc9, 0x0faa },
+  { 0x8800, 0x1fcc, 0x2000 },
+  { 0x0900, 0x1fcb, 0x0faa },
+  { 0x1800, 0x1fcd, 0x0000 },
+  { 0x8900, 0x1fd8, 0x4ff8 },
+  { 0x8500, 0x1fd2, 0x3000 },
+  { 0x8500, 0x1fd0, 0x2008 },
+  { 0x1800, 0x1fcf, 0x0000 },
+  { 0x0500, 0x1fd1, 0x0008 },
+  { 0x8500, 0x1fd6, 0x2000 },
+  { 0x0500, 0x1fd3, 0x0000 },
+  { 0x0500, 0x1fd7, 0x0000 },
+  { 0x9800, 0x1fdd, 0x3000 },
+  { 0x8900, 0x1fda, 0x2f9c },
+  { 0x0900, 0x1fd9, 0x0ff8 },
+  { 0x0900, 0x1fdb, 0x0f9c },
+  { 0x9800, 0x1fdf, 0x2000 },
+  { 0x1800, 0x1fde, 0x0000 },
+  { 0x0500, 0x1fe0, 0x0008 },
+  { 0x8500, 0x1ff3, 0x5009 },
+  { 0x8900, 0x1fe9, 0x4ff8 },
+  { 0x8500, 0x1fe5, 0x3007 },
+  { 0x8500, 0x1fe3, 0x2000 },
+  { 0x0500, 0x1fe2, 0x0000 },
+  { 0x0500, 0x1fe4, 0x0000 },
+  { 0x8500, 0x1fe7, 0x2000 },
+  { 0x0500, 0x1fe6, 0x0000 },
+  { 0x0900, 0x1fe8, 0x0ff8 },
+  { 0x9800, 0x1fed, 0x3000 },
+  { 0x8900, 0x1feb, 0x2f90 },
+  { 0x0900, 0x1fea, 0x0f90 },
+  { 0x0900, 0x1fec, 0x0ff9 },
+  { 0x9800, 0x1fef, 0x2000 },
+  { 0x1800, 0x1fee, 0x0000 },
+  { 0x0500, 0x1ff2, 0x0000 },
+  { 0x8800, 0x1ffc, 0x4000 },
+  { 0x8900, 0x1ff8, 0x3f80 },
+  { 0x8500, 0x1ff6, 0x2000 },
+  { 0x0500, 0x1ff4, 0x0000 },
+  { 0x0500, 0x1ff7, 0x0000 },
+  { 0x8900, 0x1ffa, 0x2f82 },
+  { 0x0900, 0x1ff9, 0x0f80 },
+  { 0x0900, 0x1ffb, 0x0f82 },
+  { 0x9d00, 0x2001, 0x3000 },
+  { 0x9800, 0x1ffe, 0x2000 },
+  { 0x1800, 0x1ffd, 0x0000 },
+  { 0x1d00, 0x2000, 0x0000 },
+  { 0x9d00, 0x2003, 0x2000 },
+  { 0x1d00, 0x2002, 0x0000 },
+  { 0x1d00, 0x2004, 0x0000 },
+  { 0x9500, 0x2025, 0x6000 },
+  { 0x9100, 0x2015, 0x5000 },
+  { 0x8100, 0x200d, 0x4000 },
+  { 0x9d00, 0x2009, 0x3000 },
+  { 0x9d00, 0x2007, 0x2000 },
+  { 0x1d00, 0x2006, 0x0000 },
+  { 0x1d00, 0x2008, 0x0000 },
+  { 0x9d00, 0x200b, 0x2000 },
+  { 0x1d00, 0x200a, 0x0000 },
+  { 0x0100, 0x200c, 0x0000 },
+  { 0x9100, 0x2011, 0x3000 },
+  { 0x8100, 0x200f, 0x2000 },
+  { 0x0100, 0x200e, 0x0000 },
+  { 0x1100, 0x2010, 0x0000 },
+  { 0x9100, 0x2013, 0x2000 },
+  { 0x1100, 0x2012, 0x0000 },
+  { 0x1100, 0x2014, 0x0000 },
+  { 0x9300, 0x201d, 0x4000 },
+  { 0x9300, 0x2019, 0x3000 },
+  { 0x9500, 0x2017, 0x2000 },
+  { 0x1500, 0x2016, 0x0000 },
+  { 0x1400, 0x2018, 0x0000 },
+  { 0x9400, 0x201b, 0x2000 },
+  { 0x1600, 0x201a, 0x0000 },
+  { 0x1400, 0x201c, 0x0000 },
+  { 0x9500, 0x2021, 0x3000 },
+  { 0x9400, 0x201f, 0x2000 },
+  { 0x1600, 0x201e, 0x0000 },
+  { 0x1500, 0x2020, 0x0000 },
+  { 0x9500, 0x2023, 0x2000 },
+  { 0x1500, 0x2022, 0x0000 },
+  { 0x1500, 0x2024, 0x0000 },
+  { 0x9500, 0x2035, 0x5000 },
+  { 0x8100, 0x202d, 0x4000 },
+  { 0x9c00, 0x2029, 0x3000 },
+  { 0x9500, 0x2027, 0x2000 },
+  { 0x1500, 0x2026, 0x0000 },
+  { 0x1b00, 0x2028, 0x0000 },
+  { 0x8100, 0x202b, 0x2000 },
+  { 0x0100, 0x202a, 0x0000 },
+  { 0x0100, 0x202c, 0x0000 },
+  { 0x9500, 0x2031, 0x3000 },
+  { 0x9d00, 0x202f, 0x2000 },
+  { 0x0100, 0x202e, 0x0000 },
+  { 0x1500, 0x2030, 0x0000 },
+  { 0x9500, 0x2033, 0x2000 },
+  { 0x1500, 0x2032, 0x0000 },
+  { 0x1500, 0x2034, 0x0000 },
+  { 0x9500, 0x203d, 0x4000 },
+  { 0x9400, 0x2039, 0x3000 },
+  { 0x9500, 0x2037, 0x2000 },
+  { 0x1500, 0x2036, 0x0000 },
+  { 0x1500, 0x2038, 0x0000 },
+  { 0x9500, 0x203b, 0x2000 },
+  { 0x1300, 0x203a, 0x0000 },
+  { 0x1500, 0x203c, 0x0000 },
+  { 0x9500, 0x2041, 0x3000 },
+  { 0x9000, 0x203f, 0x2000 },
+  { 0x1500, 0x203e, 0x0000 },
+  { 0x1000, 0x2040, 0x0000 },
+  { 0x9500, 0x2043, 0x2000 },
+  { 0x1500, 0x2042, 0x0000 },
+  { 0x1900, 0x2044, 0x0000 },
+  { 0x9900, 0x21ae, 0x9000 },
+  { 0x8900, 0x211a, 0x8000 },
+  { 0x9700, 0x20a7, 0x7000 },
+  { 0x8f00, 0x2076, 0x6000 },
+  { 0x9500, 0x2057, 0x5000 },
+  { 0x9500, 0x204d, 0x4000 },
+  { 0x9500, 0x2049, 0x3000 },
+  { 0x9500, 0x2047, 0x2000 },
+  { 0x1200, 0x2046, 0x0000 },
+  { 0x1500, 0x2048, 0x0000 },
+  { 0x9500, 0x204b, 0x2000 },
+  { 0x1500, 0x204a, 0x0000 },
+  { 0x1500, 0x204c, 0x0000 },
+  { 0x9500, 0x2051, 0x3000 },
+  { 0x9500, 0x204f, 0x2000 },
+  { 0x1500, 0x204e, 0x0000 },
+  { 0x1500, 0x2050, 0x0000 },
+  { 0x9500, 0x2053, 0x2000 },
+  { 0x1900, 0x2052, 0x0000 },
+  { 0x1000, 0x2054, 0x0000 },
+  { 0x8100, 0x206c, 0x4000 },
+  { 0x8100, 0x2062, 0x3000 },
+  { 0x8100, 0x2060, 0x2000 },
+  { 0x1d00, 0x205f, 0x0000 },
+  { 0x0100, 0x2061, 0x0000 },
+  { 0x8100, 0x206a, 0x2000 },
+  { 0x0100, 0x2063, 0x0000 },
+  { 0x0100, 0x206b, 0x0000 },
+  { 0x8f00, 0x2070, 0x3000 },
+  { 0x8100, 0x206e, 0x2000 },
+  { 0x0100, 0x206d, 0x0000 },
+  { 0x0100, 0x206f, 0x0000 },
+  { 0x8f00, 0x2074, 0x2000 },
+  { 0x0500, 0x2071, 0x0000 },
+  { 0x0f00, 0x2075, 0x0000 },
+  { 0x8f00, 0x2086, 0x5000 },
+  { 0x9200, 0x207e, 0x4000 },
+  { 0x9900, 0x207a, 0x3000 },
+  { 0x8f00, 0x2078, 0x2000 },
+  { 0x0f00, 0x2077, 0x0000 },
+  { 0x0f00, 0x2079, 0x0000 },
+  { 0x9900, 0x207c, 0x2000 },
+  { 0x1900, 0x207b, 0x0000 },
+  { 0x1600, 0x207d, 0x0000 },
+  { 0x8f00, 0x2082, 0x3000 },
+  { 0x8f00, 0x2080, 0x2000 },
+  { 0x0500, 0x207f, 0x0000 },
+  { 0x0f00, 0x2081, 0x0000 },
+  { 0x8f00, 0x2084, 0x2000 },
+  { 0x0f00, 0x2083, 0x0000 },
+  { 0x0f00, 0x2085, 0x0000 },
+  { 0x9200, 0x208e, 0x4000 },
+  { 0x9900, 0x208a, 0x3000 },
+  { 0x8f00, 0x2088, 0x2000 },
+  { 0x0f00, 0x2087, 0x0000 },
+  { 0x0f00, 0x2089, 0x0000 },
+  { 0x9900, 0x208c, 0x2000 },
+  { 0x1900, 0x208b, 0x0000 },
+  { 0x1600, 0x208d, 0x0000 },
+  { 0x9700, 0x20a3, 0x3000 },
+  { 0x9700, 0x20a1, 0x2000 },
+  { 0x1700, 0x20a0, 0x0000 },
+  { 0x1700, 0x20a2, 0x0000 },
+  { 0x9700, 0x20a5, 0x2000 },
+  { 0x1700, 0x20a4, 0x0000 },
+  { 0x1700, 0x20a6, 0x0000 },
+  { 0x8c00, 0x20e5, 0x6000 },
+  { 0x8c00, 0x20d5, 0x5000 },
+  { 0x9700, 0x20af, 0x4000 },
+  { 0x9700, 0x20ab, 0x3000 },
+  { 0x9700, 0x20a9, 0x2000 },
+  { 0x1700, 0x20a8, 0x0000 },
+  { 0x1700, 0x20aa, 0x0000 },
+  { 0x9700, 0x20ad, 0x2000 },
+  { 0x1700, 0x20ac, 0x0000 },
+  { 0x1700, 0x20ae, 0x0000 },
+  { 0x8c00, 0x20d1, 0x3000 },
+  { 0x9700, 0x20b1, 0x2000 },
+  { 0x1700, 0x20b0, 0x0000 },
+  { 0x0c00, 0x20d0, 0x0000 },
+  { 0x8c00, 0x20d3, 0x2000 },
+  { 0x0c00, 0x20d2, 0x0000 },
+  { 0x0c00, 0x20d4, 0x0000 },
+  { 0x8b00, 0x20dd, 0x4000 },
+  { 0x8c00, 0x20d9, 0x3000 },
+  { 0x8c00, 0x20d7, 0x2000 },
+  { 0x0c00, 0x20d6, 0x0000 },
+  { 0x0c00, 0x20d8, 0x0000 },
+  { 0x8c00, 0x20db, 0x2000 },
+  { 0x0c00, 0x20da, 0x0000 },
+  { 0x0c00, 0x20dc, 0x0000 },
+  { 0x8c00, 0x20e1, 0x3000 },
+  { 0x8b00, 0x20df, 0x2000 },
+  { 0x0b00, 0x20de, 0x0000 },
+  { 0x0b00, 0x20e0, 0x0000 },
+  { 0x8b00, 0x20e3, 0x2000 },
+  { 0x0b00, 0x20e2, 0x0000 },
+  { 0x0b00, 0x20e4, 0x0000 },
+  { 0x8500, 0x210a, 0x5000 },
+  { 0x8900, 0x2102, 0x4000 },
+  { 0x8c00, 0x20e9, 0x3000 },
+  { 0x8c00, 0x20e7, 0x2000 },
+  { 0x0c00, 0x20e6, 0x0000 },
+  { 0x0c00, 0x20e8, 0x0000 },
+  { 0x9a00, 0x2100, 0x2000 },
+  { 0x0c00, 0x20ea, 0x0000 },
+  { 0x1a00, 0x2101, 0x0000 },
+  { 0x9a00, 0x2106, 0x3000 },
+  { 0x9a00, 0x2104, 0x2000 },
+  { 0x1a00, 0x2103, 0x0000 },
+  { 0x1a00, 0x2105, 0x0000 },
+  { 0x9a00, 0x2108, 0x2000 },
+  { 0x0900, 0x2107, 0x0000 },
+  { 0x1a00, 0x2109, 0x0000 },
+  { 0x8900, 0x2112, 0x4000 },
+  { 0x8500, 0x210e, 0x3000 },
+  { 0x8900, 0x210c, 0x2000 },
+  { 0x0900, 0x210b, 0x0000 },
+  { 0x0900, 0x210d, 0x0000 },
+  { 0x8900, 0x2110, 0x2000 },
+  { 0x0500, 0x210f, 0x0000 },
+  { 0x0900, 0x2111, 0x0000 },
+  { 0x9a00, 0x2116, 0x3000 },
+  { 0x9a00, 0x2114, 0x2000 },
+  { 0x0500, 0x2113, 0x0000 },
+  { 0x0900, 0x2115, 0x0000 },
+  { 0x9a00, 0x2118, 0x2000 },
+  { 0x1a00, 0x2117, 0x0000 },
+  { 0x0900, 0x2119, 0x0000 },
+  { 0x8e00, 0x2162, 0x7000 },
+  { 0x9a00, 0x213a, 0x6000 },
+  { 0x8900, 0x212a, 0x5000 },
+  { 0x9a00, 0x2122, 0x4000 },
+  { 0x9a00, 0x211e, 0x3000 },
+  { 0x8900, 0x211c, 0x2000 },
+  { 0x0900, 0x211b, 0x0000 },
+  { 0x0900, 0x211d, 0x0000 },
+  { 0x9a00, 0x2120, 0x2000 },
+  { 0x1a00, 0x211f, 0x0000 },
+  { 0x1a00, 0x2121, 0x0000 },
+  { 0x8900, 0x2126, 0x3000 },
+  { 0x8900, 0x2124, 0x2000 },
+  { 0x1a00, 0x2123, 0x0000 },
+  { 0x1a00, 0x2125, 0x0000 },
+  { 0x8900, 0x2128, 0x2000 },
+  { 0x1a00, 0x2127, 0x0000 },
+  { 0x1a00, 0x2129, 0x0000 },
+  { 0x9a00, 0x2132, 0x4000 },
+  { 0x9a00, 0x212e, 0x3000 },
+  { 0x8900, 0x212c, 0x2000 },
+  { 0x0900, 0x212b, 0x0000 },
+  { 0x0900, 0x212d, 0x0000 },
+  { 0x8900, 0x2130, 0x2000 },
+  { 0x0500, 0x212f, 0x0000 },
+  { 0x0900, 0x2131, 0x0000 },
+  { 0x8700, 0x2136, 0x3000 },
+  { 0x8500, 0x2134, 0x2000 },
+  { 0x0900, 0x2133, 0x0000 },
+  { 0x0700, 0x2135, 0x0000 },
+  { 0x8700, 0x2138, 0x2000 },
+  { 0x0700, 0x2137, 0x0000 },
+  { 0x0500, 0x2139, 0x0000 },
+  { 0x9900, 0x214b, 0x5000 },
+  { 0x9900, 0x2143, 0x4000 },
+  { 0x8900, 0x213f, 0x3000 },
+  { 0x8500, 0x213d, 0x2000 },
+  { 0x1a00, 0x213b, 0x0000 },
+  { 0x0900, 0x213e, 0x0000 },
+  { 0x9900, 0x2141, 0x2000 },
+  { 0x1900, 0x2140, 0x0000 },
+  { 0x1900, 0x2142, 0x0000 },
+  { 0x8500, 0x2147, 0x3000 },
+  { 0x8900, 0x2145, 0x2000 },
+  { 0x1900, 0x2144, 0x0000 },
+  { 0x0500, 0x2146, 0x0000 },
+  { 0x8500, 0x2149, 0x2000 },
+  { 0x0500, 0x2148, 0x0000 },
+  { 0x1a00, 0x214a, 0x0000 },
+  { 0x8f00, 0x215a, 0x4000 },
+  { 0x8f00, 0x2156, 0x3000 },
+  { 0x8f00, 0x2154, 0x2000 },
+  { 0x0f00, 0x2153, 0x0000 },
+  { 0x0f00, 0x2155, 0x0000 },
+  { 0x8f00, 0x2158, 0x2000 },
+  { 0x0f00, 0x2157, 0x0000 },
+  { 0x0f00, 0x2159, 0x0000 },
+  { 0x8f00, 0x215e, 0x3000 },
+  { 0x8f00, 0x215c, 0x2000 },
+  { 0x0f00, 0x215b, 0x0000 },
+  { 0x0f00, 0x215d, 0x0000 },
+  { 0x8e00, 0x2160, 0x2000 },
+  { 0x0f00, 0x215f, 0x0000 },
+  { 0x0e00, 0x2161, 0x0000 },
+  { 0x8e00, 0x2182, 0x6000 },
+  { 0x8e00, 0x2172, 0x5000 },
+  { 0x8e00, 0x216a, 0x4000 },
+  { 0x8e00, 0x2166, 0x3000 },
+  { 0x8e00, 0x2164, 0x2000 },
+  { 0x0e00, 0x2163, 0x0000 },
+  { 0x0e00, 0x2165, 0x0000 },
+  { 0x8e00, 0x2168, 0x2000 },
+  { 0x0e00, 0x2167, 0x0000 },
+  { 0x0e00, 0x2169, 0x0000 },
+  { 0x8e00, 0x216e, 0x3000 },
+  { 0x8e00, 0x216c, 0x2000 },
+  { 0x0e00, 0x216b, 0x0000 },
+  { 0x0e00, 0x216d, 0x0000 },
+  { 0x8e00, 0x2170, 0x2000 },
+  { 0x0e00, 0x216f, 0x0000 },
+  { 0x0e00, 0x2171, 0x0000 },
+  { 0x8e00, 0x217a, 0x4000 },
+  { 0x8e00, 0x2176, 0x3000 },
+  { 0x8e00, 0x2174, 0x2000 },
+  { 0x0e00, 0x2173, 0x0000 },
+  { 0x0e00, 0x2175, 0x0000 },
+  { 0x8e00, 0x2178, 0x2000 },
+  { 0x0e00, 0x2177, 0x0000 },
+  { 0x0e00, 0x2179, 0x0000 },
+  { 0x8e00, 0x217e, 0x3000 },
+  { 0x8e00, 0x217c, 0x2000 },
+  { 0x0e00, 0x217b, 0x0000 },
+  { 0x0e00, 0x217d, 0x0000 },
+  { 0x8e00, 0x2180, 0x2000 },
+  { 0x0e00, 0x217f, 0x0000 },
+  { 0x0e00, 0x2181, 0x0000 },
+  { 0x9a00, 0x219e, 0x5000 },
+  { 0x9a00, 0x2196, 0x4000 },
+  { 0x9900, 0x2192, 0x3000 },
+  { 0x9900, 0x2190, 0x2000 },
+  { 0x0e00, 0x2183, 0x0000 },
+  { 0x1900, 0x2191, 0x0000 },
+  { 0x9900, 0x2194, 0x2000 },
+  { 0x1900, 0x2193, 0x0000 },
+  { 0x1a00, 0x2195, 0x0000 },
+  { 0x9900, 0x219a, 0x3000 },
+  { 0x9a00, 0x2198, 0x2000 },
+  { 0x1a00, 0x2197, 0x0000 },
+  { 0x1a00, 0x2199, 0x0000 },
+  { 0x9a00, 0x219c, 0x2000 },
+  { 0x1900, 0x219b, 0x0000 },
+  { 0x1a00, 0x219d, 0x0000 },
+  { 0x9900, 0x21a6, 0x4000 },
+  { 0x9a00, 0x21a2, 0x3000 },
+  { 0x9900, 0x21a0, 0x2000 },
+  { 0x1a00, 0x219f, 0x0000 },
+  { 0x1a00, 0x21a1, 0x0000 },
+  { 0x9a00, 0x21a4, 0x2000 },
+  { 0x1900, 0x21a3, 0x0000 },
+  { 0x1a00, 0x21a5, 0x0000 },
+  { 0x9a00, 0x21aa, 0x3000 },
+  { 0x9a00, 0x21a8, 0x2000 },
+  { 0x1a00, 0x21a7, 0x0000 },
+  { 0x1a00, 0x21a9, 0x0000 },
+  { 0x9a00, 0x21ac, 0x2000 },
+  { 0x1a00, 0x21ab, 0x0000 },
+  { 0x1a00, 0x21ad, 0x0000 },
+  { 0x9900, 0x222e, 0x8000 },
+  { 0x9a00, 0x21ee, 0x7000 },
+  { 0x9900, 0x21ce, 0x6000 },
+  { 0x9a00, 0x21be, 0x5000 },
+  { 0x9a00, 0x21b6, 0x4000 },
+  { 0x9a00, 0x21b2, 0x3000 },
+  { 0x9a00, 0x21b0, 0x2000 },
+  { 0x1a00, 0x21af, 0x0000 },
+  { 0x1a00, 0x21b1, 0x0000 },
+  { 0x9a00, 0x21b4, 0x2000 },
+  { 0x1a00, 0x21b3, 0x0000 },
+  { 0x1a00, 0x21b5, 0x0000 },
+  { 0x9a00, 0x21ba, 0x3000 },
+  { 0x9a00, 0x21b8, 0x2000 },
+  { 0x1a00, 0x21b7, 0x0000 },
+  { 0x1a00, 0x21b9, 0x0000 },
+  { 0x9a00, 0x21bc, 0x2000 },
+  { 0x1a00, 0x21bb, 0x0000 },
+  { 0x1a00, 0x21bd, 0x0000 },
+  { 0x9a00, 0x21c6, 0x4000 },
+  { 0x9a00, 0x21c2, 0x3000 },
+  { 0x9a00, 0x21c0, 0x2000 },
+  { 0x1a00, 0x21bf, 0x0000 },
+  { 0x1a00, 0x21c1, 0x0000 },
+  { 0x9a00, 0x21c4, 0x2000 },
+  { 0x1a00, 0x21c3, 0x0000 },
+  { 0x1a00, 0x21c5, 0x0000 },
+  { 0x9a00, 0x21ca, 0x3000 },
+  { 0x9a00, 0x21c8, 0x2000 },
+  { 0x1a00, 0x21c7, 0x0000 },
+  { 0x1a00, 0x21c9, 0x0000 },
+  { 0x9a00, 0x21cc, 0x2000 },
+  { 0x1a00, 0x21cb, 0x0000 },
+  { 0x1a00, 0x21cd, 0x0000 },
+  { 0x9a00, 0x21de, 0x5000 },
+  { 0x9a00, 0x21d6, 0x4000 },
+  { 0x9900, 0x21d2, 0x3000 },
+  { 0x9a00, 0x21d0, 0x2000 },
+  { 0x1900, 0x21cf, 0x0000 },
+  { 0x1a00, 0x21d1, 0x0000 },
+  { 0x9900, 0x21d4, 0x2000 },
+  { 0x1a00, 0x21d3, 0x0000 },
+  { 0x1a00, 0x21d5, 0x0000 },
+  { 0x9a00, 0x21da, 0x3000 },
+  { 0x9a00, 0x21d8, 0x2000 },
+  { 0x1a00, 0x21d7, 0x0000 },
+  { 0x1a00, 0x21d9, 0x0000 },
+  { 0x9a00, 0x21dc, 0x2000 },
+  { 0x1a00, 0x21db, 0x0000 },
+  { 0x1a00, 0x21dd, 0x0000 },
+  { 0x9a00, 0x21e6, 0x4000 },
+  { 0x9a00, 0x21e2, 0x3000 },
+  { 0x9a00, 0x21e0, 0x2000 },
+  { 0x1a00, 0x21df, 0x0000 },
+  { 0x1a00, 0x21e1, 0x0000 },
+  { 0x9a00, 0x21e4, 0x2000 },
+  { 0x1a00, 0x21e3, 0x0000 },
+  { 0x1a00, 0x21e5, 0x0000 },
+  { 0x9a00, 0x21ea, 0x3000 },
+  { 0x9a00, 0x21e8, 0x2000 },
+  { 0x1a00, 0x21e7, 0x0000 },
+  { 0x1a00, 0x21e9, 0x0000 },
+  { 0x9a00, 0x21ec, 0x2000 },
+  { 0x1a00, 0x21eb, 0x0000 },
+  { 0x1a00, 0x21ed, 0x0000 },
+  { 0x9900, 0x220e, 0x6000 },
+  { 0x9900, 0x21fe, 0x5000 },
+  { 0x9900, 0x21f6, 0x4000 },
+  { 0x9a00, 0x21f2, 0x3000 },
+  { 0x9a00, 0x21f0, 0x2000 },
+  { 0x1a00, 0x21ef, 0x0000 },
+  { 0x1a00, 0x21f1, 0x0000 },
+  { 0x9900, 0x21f4, 0x2000 },
+  { 0x1a00, 0x21f3, 0x0000 },
+  { 0x1900, 0x21f5, 0x0000 },
+  { 0x9900, 0x21fa, 0x3000 },
+  { 0x9900, 0x21f8, 0x2000 },
+  { 0x1900, 0x21f7, 0x0000 },
+  { 0x1900, 0x21f9, 0x0000 },
+  { 0x9900, 0x21fc, 0x2000 },
+  { 0x1900, 0x21fb, 0x0000 },
+  { 0x1900, 0x21fd, 0x0000 },
+  { 0x9900, 0x2206, 0x4000 },
+  { 0x9900, 0x2202, 0x3000 },
+  { 0x9900, 0x2200, 0x2000 },
+  { 0x1900, 0x21ff, 0x0000 },
+  { 0x1900, 0x2201, 0x0000 },
+  { 0x9900, 0x2204, 0x2000 },
+  { 0x1900, 0x2203, 0x0000 },
+  { 0x1900, 0x2205, 0x0000 },
+  { 0x9900, 0x220a, 0x3000 },
+  { 0x9900, 0x2208, 0x2000 },
+  { 0x1900, 0x2207, 0x0000 },
+  { 0x1900, 0x2209, 0x0000 },
+  { 0x9900, 0x220c, 0x2000 },
+  { 0x1900, 0x220b, 0x0000 },
+  { 0x1900, 0x220d, 0x0000 },
+  { 0x9900, 0x221e, 0x5000 },
+  { 0x9900, 0x2216, 0x4000 },
+  { 0x9900, 0x2212, 0x3000 },
+  { 0x9900, 0x2210, 0x2000 },
+  { 0x1900, 0x220f, 0x0000 },
+  { 0x1900, 0x2211, 0x0000 },
+  { 0x9900, 0x2214, 0x2000 },
+  { 0x1900, 0x2213, 0x0000 },
+  { 0x1900, 0x2215, 0x0000 },
+  { 0x9900, 0x221a, 0x3000 },
+  { 0x9900, 0x2218, 0x2000 },
+  { 0x1900, 0x2217, 0x0000 },
+  { 0x1900, 0x2219, 0x0000 },
+  { 0x9900, 0x221c, 0x2000 },
+  { 0x1900, 0x221b, 0x0000 },
+  { 0x1900, 0x221d, 0x0000 },
+  { 0x9900, 0x2226, 0x4000 },
+  { 0x9900, 0x2222, 0x3000 },
+  { 0x9900, 0x2220, 0x2000 },
+  { 0x1900, 0x221f, 0x0000 },
+  { 0x1900, 0x2221, 0x0000 },
+  { 0x9900, 0x2224, 0x2000 },
+  { 0x1900, 0x2223, 0x0000 },
+  { 0x1900, 0x2225, 0x0000 },
+  { 0x9900, 0x222a, 0x3000 },
+  { 0x9900, 0x2228, 0x2000 },
+  { 0x1900, 0x2227, 0x0000 },
+  { 0x1900, 0x2229, 0x0000 },
+  { 0x9900, 0x222c, 0x2000 },
+  { 0x1900, 0x222b, 0x0000 },
+  { 0x1900, 0x222d, 0x0000 },
+  { 0x9900, 0x226e, 0x7000 },
+  { 0x9900, 0x224e, 0x6000 },
+  { 0x9900, 0x223e, 0x5000 },
+  { 0x9900, 0x2236, 0x4000 },
+  { 0x9900, 0x2232, 0x3000 },
+  { 0x9900, 0x2230, 0x2000 },
+  { 0x1900, 0x222f, 0x0000 },
+  { 0x1900, 0x2231, 0x0000 },
+  { 0x9900, 0x2234, 0x2000 },
+  { 0x1900, 0x2233, 0x0000 },
+  { 0x1900, 0x2235, 0x0000 },
+  { 0x9900, 0x223a, 0x3000 },
+  { 0x9900, 0x2238, 0x2000 },
+  { 0x1900, 0x2237, 0x0000 },
+  { 0x1900, 0x2239, 0x0000 },
+  { 0x9900, 0x223c, 0x2000 },
+  { 0x1900, 0x223b, 0x0000 },
+  { 0x1900, 0x223d, 0x0000 },
+  { 0x9900, 0x2246, 0x4000 },
+  { 0x9900, 0x2242, 0x3000 },
+  { 0x9900, 0x2240, 0x2000 },
+  { 0x1900, 0x223f, 0x0000 },
+  { 0x1900, 0x2241, 0x0000 },
+  { 0x9900, 0x2244, 0x2000 },
+  { 0x1900, 0x2243, 0x0000 },
+  { 0x1900, 0x2245, 0x0000 },
+  { 0x9900, 0x224a, 0x3000 },
+  { 0x9900, 0x2248, 0x2000 },
+  { 0x1900, 0x2247, 0x0000 },
+  { 0x1900, 0x2249, 0x0000 },
+  { 0x9900, 0x224c, 0x2000 },
+  { 0x1900, 0x224b, 0x0000 },
+  { 0x1900, 0x224d, 0x0000 },
+  { 0x9900, 0x225e, 0x5000 },
+  { 0x9900, 0x2256, 0x4000 },
+  { 0x9900, 0x2252, 0x3000 },
+  { 0x9900, 0x2250, 0x2000 },
+  { 0x1900, 0x224f, 0x0000 },
+  { 0x1900, 0x2251, 0x0000 },
+  { 0x9900, 0x2254, 0x2000 },
+  { 0x1900, 0x2253, 0x0000 },
+  { 0x1900, 0x2255, 0x0000 },
+  { 0x9900, 0x225a, 0x3000 },
+  { 0x9900, 0x2258, 0x2000 },
+  { 0x1900, 0x2257, 0x0000 },
+  { 0x1900, 0x2259, 0x0000 },
+  { 0x9900, 0x225c, 0x2000 },
+  { 0x1900, 0x225b, 0x0000 },
+  { 0x1900, 0x225d, 0x0000 },
+  { 0x9900, 0x2266, 0x4000 },
+  { 0x9900, 0x2262, 0x3000 },
+  { 0x9900, 0x2260, 0x2000 },
+  { 0x1900, 0x225f, 0x0000 },
+  { 0x1900, 0x2261, 0x0000 },
+  { 0x9900, 0x2264, 0x2000 },
+  { 0x1900, 0x2263, 0x0000 },
+  { 0x1900, 0x2265, 0x0000 },
+  { 0x9900, 0x226a, 0x3000 },
+  { 0x9900, 0x2268, 0x2000 },
+  { 0x1900, 0x2267, 0x0000 },
+  { 0x1900, 0x2269, 0x0000 },
+  { 0x9900, 0x226c, 0x2000 },
+  { 0x1900, 0x226b, 0x0000 },
+  { 0x1900, 0x226d, 0x0000 },
+  { 0x9900, 0x228e, 0x6000 },
+  { 0x9900, 0x227e, 0x5000 },
+  { 0x9900, 0x2276, 0x4000 },
+  { 0x9900, 0x2272, 0x3000 },
+  { 0x9900, 0x2270, 0x2000 },
+  { 0x1900, 0x226f, 0x0000 },
+  { 0x1900, 0x2271, 0x0000 },
+  { 0x9900, 0x2274, 0x2000 },
+  { 0x1900, 0x2273, 0x0000 },
+  { 0x1900, 0x2275, 0x0000 },
+  { 0x9900, 0x227a, 0x3000 },
+  { 0x9900, 0x2278, 0x2000 },
+  { 0x1900, 0x2277, 0x0000 },
+  { 0x1900, 0x2279, 0x0000 },
+  { 0x9900, 0x227c, 0x2000 },
+  { 0x1900, 0x227b, 0x0000 },
+  { 0x1900, 0x227d, 0x0000 },
+  { 0x9900, 0x2286, 0x4000 },
+  { 0x9900, 0x2282, 0x3000 },
+  { 0x9900, 0x2280, 0x2000 },
+  { 0x1900, 0x227f, 0x0000 },
+  { 0x1900, 0x2281, 0x0000 },
+  { 0x9900, 0x2284, 0x2000 },
+  { 0x1900, 0x2283, 0x0000 },
+  { 0x1900, 0x2285, 0x0000 },
+  { 0x9900, 0x228a, 0x3000 },
+  { 0x9900, 0x2288, 0x2000 },
+  { 0x1900, 0x2287, 0x0000 },
+  { 0x1900, 0x2289, 0x0000 },
+  { 0x9900, 0x228c, 0x2000 },
+  { 0x1900, 0x228b, 0x0000 },
+  { 0x1900, 0x228d, 0x0000 },
+  { 0x9900, 0x229e, 0x5000 },
+  { 0x9900, 0x2296, 0x4000 },
+  { 0x9900, 0x2292, 0x3000 },
+  { 0x9900, 0x2290, 0x2000 },
+  { 0x1900, 0x228f, 0x0000 },
+  { 0x1900, 0x2291, 0x0000 },
+  { 0x9900, 0x2294, 0x2000 },
+  { 0x1900, 0x2293, 0x0000 },
+  { 0x1900, 0x2295, 0x0000 },
+  { 0x9900, 0x229a, 0x3000 },
+  { 0x9900, 0x2298, 0x2000 },
+  { 0x1900, 0x2297, 0x0000 },
+  { 0x1900, 0x2299, 0x0000 },
+  { 0x9900, 0x229c, 0x2000 },
+  { 0x1900, 0x229b, 0x0000 },
+  { 0x1900, 0x229d, 0x0000 },
+  { 0x9900, 0x22a6, 0x4000 },
+  { 0x9900, 0x22a2, 0x3000 },
+  { 0x9900, 0x22a0, 0x2000 },
+  { 0x1900, 0x229f, 0x0000 },
+  { 0x1900, 0x22a1, 0x0000 },
+  { 0x9900, 0x22a4, 0x2000 },
+  { 0x1900, 0x22a3, 0x0000 },
+  { 0x1900, 0x22a5, 0x0000 },
+  { 0x9900, 0x22aa, 0x3000 },
+  { 0x9900, 0x22a8, 0x2000 },
+  { 0x1900, 0x22a7, 0x0000 },
+  { 0x1900, 0x22a9, 0x0000 },
+  { 0x9900, 0x22ac, 0x2000 },
+  { 0x1900, 0x22ab, 0x0000 },
+  { 0x1900, 0x22ad, 0x0000 },
+  { 0x8f00, 0x2787, 0xb000 },
+  { 0x9a00, 0x250b, 0xa000 },
+  { 0x9900, 0x23ae, 0x9000 },
+  { 0x9a00, 0x232e, 0x8000 },
+  { 0x9900, 0x22ee, 0x7000 },
+  { 0x9900, 0x22ce, 0x6000 },
+  { 0x9900, 0x22be, 0x5000 },
+  { 0x9900, 0x22b6, 0x4000 },
+  { 0x9900, 0x22b2, 0x3000 },
+  { 0x9900, 0x22b0, 0x2000 },
+  { 0x1900, 0x22af, 0x0000 },
+  { 0x1900, 0x22b1, 0x0000 },
+  { 0x9900, 0x22b4, 0x2000 },
+  { 0x1900, 0x22b3, 0x0000 },
+  { 0x1900, 0x22b5, 0x0000 },
+  { 0x9900, 0x22ba, 0x3000 },
+  { 0x9900, 0x22b8, 0x2000 },
+  { 0x1900, 0x22b7, 0x0000 },
+  { 0x1900, 0x22b9, 0x0000 },
+  { 0x9900, 0x22bc, 0x2000 },
+  { 0x1900, 0x22bb, 0x0000 },
+  { 0x1900, 0x22bd, 0x0000 },
+  { 0x9900, 0x22c6, 0x4000 },
+  { 0x9900, 0x22c2, 0x3000 },
+  { 0x9900, 0x22c0, 0x2000 },
+  { 0x1900, 0x22bf, 0x0000 },
+  { 0x1900, 0x22c1, 0x0000 },
+  { 0x9900, 0x22c4, 0x2000 },
+  { 0x1900, 0x22c3, 0x0000 },
+  { 0x1900, 0x22c5, 0x0000 },
+  { 0x9900, 0x22ca, 0x3000 },
+  { 0x9900, 0x22c8, 0x2000 },
+  { 0x1900, 0x22c7, 0x0000 },
+  { 0x1900, 0x22c9, 0x0000 },
+  { 0x9900, 0x22cc, 0x2000 },
+  { 0x1900, 0x22cb, 0x0000 },
+  { 0x1900, 0x22cd, 0x0000 },
+  { 0x9900, 0x22de, 0x5000 },
+  { 0x9900, 0x22d6, 0x4000 },
+  { 0x9900, 0x22d2, 0x3000 },
+  { 0x9900, 0x22d0, 0x2000 },
+  { 0x1900, 0x22cf, 0x0000 },
+  { 0x1900, 0x22d1, 0x0000 },
+  { 0x9900, 0x22d4, 0x2000 },
+  { 0x1900, 0x22d3, 0x0000 },
+  { 0x1900, 0x22d5, 0x0000 },
+  { 0x9900, 0x22da, 0x3000 },
+  { 0x9900, 0x22d8, 0x2000 },
+  { 0x1900, 0x22d7, 0x0000 },
+  { 0x1900, 0x22d9, 0x0000 },
+  { 0x9900, 0x22dc, 0x2000 },
+  { 0x1900, 0x22db, 0x0000 },
+  { 0x1900, 0x22dd, 0x0000 },
+  { 0x9900, 0x22e6, 0x4000 },
+  { 0x9900, 0x22e2, 0x3000 },
+  { 0x9900, 0x22e0, 0x2000 },
+  { 0x1900, 0x22df, 0x0000 },
+  { 0x1900, 0x22e1, 0x0000 },
+  { 0x9900, 0x22e4, 0x2000 },
+  { 0x1900, 0x22e3, 0x0000 },
+  { 0x1900, 0x22e5, 0x0000 },
+  { 0x9900, 0x22ea, 0x3000 },
+  { 0x9900, 0x22e8, 0x2000 },
+  { 0x1900, 0x22e7, 0x0000 },
+  { 0x1900, 0x22e9, 0x0000 },
+  { 0x9900, 0x22ec, 0x2000 },
+  { 0x1900, 0x22eb, 0x0000 },
+  { 0x1900, 0x22ed, 0x0000 },
+  { 0x9a00, 0x230e, 0x6000 },
+  { 0x9900, 0x22fe, 0x5000 },
+  { 0x9900, 0x22f6, 0x4000 },
+  { 0x9900, 0x22f2, 0x3000 },
+  { 0x9900, 0x22f0, 0x2000 },
+  { 0x1900, 0x22ef, 0x0000 },
+  { 0x1900, 0x22f1, 0x0000 },
+  { 0x9900, 0x22f4, 0x2000 },
+  { 0x1900, 0x22f3, 0x0000 },
+  { 0x1900, 0x22f5, 0x0000 },
+  { 0x9900, 0x22fa, 0x3000 },
+  { 0x9900, 0x22f8, 0x2000 },
+  { 0x1900, 0x22f7, 0x0000 },
+  { 0x1900, 0x22f9, 0x0000 },
+  { 0x9900, 0x22fc, 0x2000 },
+  { 0x1900, 0x22fb, 0x0000 },
+  { 0x1900, 0x22fd, 0x0000 },
+  { 0x9a00, 0x2306, 0x4000 },
+  { 0x9a00, 0x2302, 0x3000 },
+  { 0x9a00, 0x2300, 0x2000 },
+  { 0x1900, 0x22ff, 0x0000 },
+  { 0x1a00, 0x2301, 0x0000 },
+  { 0x9a00, 0x2304, 0x2000 },
+  { 0x1a00, 0x2303, 0x0000 },
+  { 0x1a00, 0x2305, 0x0000 },
+  { 0x9900, 0x230a, 0x3000 },
+  { 0x9900, 0x2308, 0x2000 },
+  { 0x1a00, 0x2307, 0x0000 },
+  { 0x1900, 0x2309, 0x0000 },
+  { 0x9a00, 0x230c, 0x2000 },
+  { 0x1900, 0x230b, 0x0000 },
+  { 0x1a00, 0x230d, 0x0000 },
+  { 0x9a00, 0x231e, 0x5000 },
+  { 0x9a00, 0x2316, 0x4000 },
+  { 0x9a00, 0x2312, 0x3000 },
+  { 0x9a00, 0x2310, 0x2000 },
+  { 0x1a00, 0x230f, 0x0000 },
+  { 0x1a00, 0x2311, 0x0000 },
+  { 0x9a00, 0x2314, 0x2000 },
+  { 0x1a00, 0x2313, 0x0000 },
+  { 0x1a00, 0x2315, 0x0000 },
+  { 0x9a00, 0x231a, 0x3000 },
+  { 0x9a00, 0x2318, 0x2000 },
+  { 0x1a00, 0x2317, 0x0000 },
+  { 0x1a00, 0x2319, 0x0000 },
+  { 0x9a00, 0x231c, 0x2000 },
+  { 0x1a00, 0x231b, 0x0000 },
+  { 0x1a00, 0x231d, 0x0000 },
+  { 0x9a00, 0x2326, 0x4000 },
+  { 0x9a00, 0x2322, 0x3000 },
+  { 0x9900, 0x2320, 0x2000 },
+  { 0x1a00, 0x231f, 0x0000 },
+  { 0x1900, 0x2321, 0x0000 },
+  { 0x9a00, 0x2324, 0x2000 },
+  { 0x1a00, 0x2323, 0x0000 },
+  { 0x1a00, 0x2325, 0x0000 },
+  { 0x9200, 0x232a, 0x3000 },
+  { 0x9a00, 0x2328, 0x2000 },
+  { 0x1a00, 0x2327, 0x0000 },
+  { 0x1600, 0x2329, 0x0000 },
+  { 0x9a00, 0x232c, 0x2000 },
+  { 0x1a00, 0x232b, 0x0000 },
+  { 0x1a00, 0x232d, 0x0000 },
+  { 0x9a00, 0x236e, 0x7000 },
+  { 0x9a00, 0x234e, 0x6000 },
+  { 0x9a00, 0x233e, 0x5000 },
+  { 0x9a00, 0x2336, 0x4000 },
+  { 0x9a00, 0x2332, 0x3000 },
+  { 0x9a00, 0x2330, 0x2000 },
+  { 0x1a00, 0x232f, 0x0000 },
+  { 0x1a00, 0x2331, 0x0000 },
+  { 0x9a00, 0x2334, 0x2000 },
+  { 0x1a00, 0x2333, 0x0000 },
+  { 0x1a00, 0x2335, 0x0000 },
+  { 0x9a00, 0x233a, 0x3000 },
+  { 0x9a00, 0x2338, 0x2000 },
+  { 0x1a00, 0x2337, 0x0000 },
+  { 0x1a00, 0x2339, 0x0000 },
+  { 0x9a00, 0x233c, 0x2000 },
+  { 0x1a00, 0x233b, 0x0000 },
+  { 0x1a00, 0x233d, 0x0000 },
+  { 0x9a00, 0x2346, 0x4000 },
+  { 0x9a00, 0x2342, 0x3000 },
+  { 0x9a00, 0x2340, 0x2000 },
+  { 0x1a00, 0x233f, 0x0000 },
+  { 0x1a00, 0x2341, 0x0000 },
+  { 0x9a00, 0x2344, 0x2000 },
+  { 0x1a00, 0x2343, 0x0000 },
+  { 0x1a00, 0x2345, 0x0000 },
+  { 0x9a00, 0x234a, 0x3000 },
+  { 0x9a00, 0x2348, 0x2000 },
+  { 0x1a00, 0x2347, 0x0000 },
+  { 0x1a00, 0x2349, 0x0000 },
+  { 0x9a00, 0x234c, 0x2000 },
+  { 0x1a00, 0x234b, 0x0000 },
+  { 0x1a00, 0x234d, 0x0000 },
+  { 0x9a00, 0x235e, 0x5000 },
+  { 0x9a00, 0x2356, 0x4000 },
+  { 0x9a00, 0x2352, 0x3000 },
+  { 0x9a00, 0x2350, 0x2000 },
+  { 0x1a00, 0x234f, 0x0000 },
+  { 0x1a00, 0x2351, 0x0000 },
+  { 0x9a00, 0x2354, 0x2000 },
+  { 0x1a00, 0x2353, 0x0000 },
+  { 0x1a00, 0x2355, 0x0000 },
+  { 0x9a00, 0x235a, 0x3000 },
+  { 0x9a00, 0x2358, 0x2000 },
+  { 0x1a00, 0x2357, 0x0000 },
+  { 0x1a00, 0x2359, 0x0000 },
+  { 0x9a00, 0x235c, 0x2000 },
+  { 0x1a00, 0x235b, 0x0000 },
+  { 0x1a00, 0x235d, 0x0000 },
+  { 0x9a00, 0x2366, 0x4000 },
+  { 0x9a00, 0x2362, 0x3000 },
+  { 0x9a00, 0x2360, 0x2000 },
+  { 0x1a00, 0x235f, 0x0000 },
+  { 0x1a00, 0x2361, 0x0000 },
+  { 0x9a00, 0x2364, 0x2000 },
+  { 0x1a00, 0x2363, 0x0000 },
+  { 0x1a00, 0x2365, 0x0000 },
+  { 0x9a00, 0x236a, 0x3000 },
+  { 0x9a00, 0x2368, 0x2000 },
+  { 0x1a00, 0x2367, 0x0000 },
+  { 0x1a00, 0x2369, 0x0000 },
+  { 0x9a00, 0x236c, 0x2000 },
+  { 0x1a00, 0x236b, 0x0000 },
+  { 0x1a00, 0x236d, 0x0000 },
+  { 0x9a00, 0x238e, 0x6000 },
+  { 0x9a00, 0x237e, 0x5000 },
+  { 0x9a00, 0x2376, 0x4000 },
+  { 0x9a00, 0x2372, 0x3000 },
+  { 0x9a00, 0x2370, 0x2000 },
+  { 0x1a00, 0x236f, 0x0000 },
+  { 0x1a00, 0x2371, 0x0000 },
+  { 0x9a00, 0x2374, 0x2000 },
+  { 0x1a00, 0x2373, 0x0000 },
+  { 0x1a00, 0x2375, 0x0000 },
+  { 0x9a00, 0x237a, 0x3000 },
+  { 0x9a00, 0x2378, 0x2000 },
+  { 0x1a00, 0x2377, 0x0000 },
+  { 0x1a00, 0x2379, 0x0000 },
+  { 0x9900, 0x237c, 0x2000 },
+  { 0x1a00, 0x237b, 0x0000 },
+  { 0x1a00, 0x237d, 0x0000 },
+  { 0x9a00, 0x2386, 0x4000 },
+  { 0x9a00, 0x2382, 0x3000 },
+  { 0x9a00, 0x2380, 0x2000 },
+  { 0x1a00, 0x237f, 0x0000 },
+  { 0x1a00, 0x2381, 0x0000 },
+  { 0x9a00, 0x2384, 0x2000 },
+  { 0x1a00, 0x2383, 0x0000 },
+  { 0x1a00, 0x2385, 0x0000 },
+  { 0x9a00, 0x238a, 0x3000 },
+  { 0x9a00, 0x2388, 0x2000 },
+  { 0x1a00, 0x2387, 0x0000 },
+  { 0x1a00, 0x2389, 0x0000 },
+  { 0x9a00, 0x238c, 0x2000 },
+  { 0x1a00, 0x238b, 0x0000 },
+  { 0x1a00, 0x238d, 0x0000 },
+  { 0x9900, 0x239e, 0x5000 },
+  { 0x9a00, 0x2396, 0x4000 },
+  { 0x9a00, 0x2392, 0x3000 },
+  { 0x9a00, 0x2390, 0x2000 },
+  { 0x1a00, 0x238f, 0x0000 },
+  { 0x1a00, 0x2391, 0x0000 },
+  { 0x9a00, 0x2394, 0x2000 },
+  { 0x1a00, 0x2393, 0x0000 },
+  { 0x1a00, 0x2395, 0x0000 },
+  { 0x9a00, 0x239a, 0x3000 },
+  { 0x9a00, 0x2398, 0x2000 },
+  { 0x1a00, 0x2397, 0x0000 },
+  { 0x1a00, 0x2399, 0x0000 },
+  { 0x9900, 0x239c, 0x2000 },
+  { 0x1900, 0x239b, 0x0000 },
+  { 0x1900, 0x239d, 0x0000 },
+  { 0x9900, 0x23a6, 0x4000 },
+  { 0x9900, 0x23a2, 0x3000 },
+  { 0x9900, 0x23a0, 0x2000 },
+  { 0x1900, 0x239f, 0x0000 },
+  { 0x1900, 0x23a1, 0x0000 },
+  { 0x9900, 0x23a4, 0x2000 },
+  { 0x1900, 0x23a3, 0x0000 },
+  { 0x1900, 0x23a5, 0x0000 },
+  { 0x9900, 0x23aa, 0x3000 },
+  { 0x9900, 0x23a8, 0x2000 },
+  { 0x1900, 0x23a7, 0x0000 },
+  { 0x1900, 0x23a9, 0x0000 },
+  { 0x9900, 0x23ac, 0x2000 },
+  { 0x1900, 0x23ab, 0x0000 },
+  { 0x1900, 0x23ad, 0x0000 },
+  { 0x8f00, 0x248b, 0x8000 },
+  { 0x9a00, 0x241d, 0x7000 },
+  { 0x9a00, 0x23ce, 0x6000 },
+  { 0x9a00, 0x23be, 0x5000 },
+  { 0x9500, 0x23b6, 0x4000 },
+  { 0x9900, 0x23b2, 0x3000 },
+  { 0x9900, 0x23b0, 0x2000 },
+  { 0x1900, 0x23af, 0x0000 },
+  { 0x1900, 0x23b1, 0x0000 },
+  { 0x9600, 0x23b4, 0x2000 },
+  { 0x1900, 0x23b3, 0x0000 },
+  { 0x1200, 0x23b5, 0x0000 },
+  { 0x9a00, 0x23ba, 0x3000 },
+  { 0x9a00, 0x23b8, 0x2000 },
+  { 0x1a00, 0x23b7, 0x0000 },
+  { 0x1a00, 0x23b9, 0x0000 },
+  { 0x9a00, 0x23bc, 0x2000 },
+  { 0x1a00, 0x23bb, 0x0000 },
+  { 0x1a00, 0x23bd, 0x0000 },
+  { 0x9a00, 0x23c6, 0x4000 },
+  { 0x9a00, 0x23c2, 0x3000 },
+  { 0x9a00, 0x23c0, 0x2000 },
+  { 0x1a00, 0x23bf, 0x0000 },
+  { 0x1a00, 0x23c1, 0x0000 },
+  { 0x9a00, 0x23c4, 0x2000 },
+  { 0x1a00, 0x23c3, 0x0000 },
+  { 0x1a00, 0x23c5, 0x0000 },
+  { 0x9a00, 0x23ca, 0x3000 },
+  { 0x9a00, 0x23c8, 0x2000 },
+  { 0x1a00, 0x23c7, 0x0000 },
+  { 0x1a00, 0x23c9, 0x0000 },
+  { 0x9a00, 0x23cc, 0x2000 },
+  { 0x1a00, 0x23cb, 0x0000 },
+  { 0x1a00, 0x23cd, 0x0000 },
+  { 0x9a00, 0x240d, 0x5000 },
+  { 0x9a00, 0x2405, 0x4000 },
+  { 0x9a00, 0x2401, 0x3000 },
+  { 0x9a00, 0x23d0, 0x2000 },
+  { 0x1a00, 0x23cf, 0x0000 },
+  { 0x1a00, 0x2400, 0x0000 },
+  { 0x9a00, 0x2403, 0x2000 },
+  { 0x1a00, 0x2402, 0x0000 },
+  { 0x1a00, 0x2404, 0x0000 },
+  { 0x9a00, 0x2409, 0x3000 },
+  { 0x9a00, 0x2407, 0x2000 },
+  { 0x1a00, 0x2406, 0x0000 },
+  { 0x1a00, 0x2408, 0x0000 },
+  { 0x9a00, 0x240b, 0x2000 },
+  { 0x1a00, 0x240a, 0x0000 },
+  { 0x1a00, 0x240c, 0x0000 },
+  { 0x9a00, 0x2415, 0x4000 },
+  { 0x9a00, 0x2411, 0x3000 },
+  { 0x9a00, 0x240f, 0x2000 },
+  { 0x1a00, 0x240e, 0x0000 },
+  { 0x1a00, 0x2410, 0x0000 },
+  { 0x9a00, 0x2413, 0x2000 },
+  { 0x1a00, 0x2412, 0x0000 },
+  { 0x1a00, 0x2414, 0x0000 },
+  { 0x9a00, 0x2419, 0x3000 },
+  { 0x9a00, 0x2417, 0x2000 },
+  { 0x1a00, 0x2416, 0x0000 },
+  { 0x1a00, 0x2418, 0x0000 },
+  { 0x9a00, 0x241b, 0x2000 },
+  { 0x1a00, 0x241a, 0x0000 },
+  { 0x1a00, 0x241c, 0x0000 },
+  { 0x8f00, 0x246b, 0x6000 },
+  { 0x9a00, 0x2446, 0x5000 },
+  { 0x9a00, 0x2425, 0x4000 },
+  { 0x9a00, 0x2421, 0x3000 },
+  { 0x9a00, 0x241f, 0x2000 },
+  { 0x1a00, 0x241e, 0x0000 },
+  { 0x1a00, 0x2420, 0x0000 },
+  { 0x9a00, 0x2423, 0x2000 },
+  { 0x1a00, 0x2422, 0x0000 },
+  { 0x1a00, 0x2424, 0x0000 },
+  { 0x9a00, 0x2442, 0x3000 },
+  { 0x9a00, 0x2440, 0x2000 },
+  { 0x1a00, 0x2426, 0x0000 },
+  { 0x1a00, 0x2441, 0x0000 },
+  { 0x9a00, 0x2444, 0x2000 },
+  { 0x1a00, 0x2443, 0x0000 },
+  { 0x1a00, 0x2445, 0x0000 },
+  { 0x8f00, 0x2463, 0x4000 },
+  { 0x9a00, 0x244a, 0x3000 },
+  { 0x9a00, 0x2448, 0x2000 },
+  { 0x1a00, 0x2447, 0x0000 },
+  { 0x1a00, 0x2449, 0x0000 },
+  { 0x8f00, 0x2461, 0x2000 },
+  { 0x0f00, 0x2460, 0x0000 },
+  { 0x0f00, 0x2462, 0x0000 },
+  { 0x8f00, 0x2467, 0x3000 },
+  { 0x8f00, 0x2465, 0x2000 },
+  { 0x0f00, 0x2464, 0x0000 },
+  { 0x0f00, 0x2466, 0x0000 },
+  { 0x8f00, 0x2469, 0x2000 },
+  { 0x0f00, 0x2468, 0x0000 },
+  { 0x0f00, 0x246a, 0x0000 },
+  { 0x8f00, 0x247b, 0x5000 },
+  { 0x8f00, 0x2473, 0x4000 },
+  { 0x8f00, 0x246f, 0x3000 },
+  { 0x8f00, 0x246d, 0x2000 },
+  { 0x0f00, 0x246c, 0x0000 },
+  { 0x0f00, 0x246e, 0x0000 },
+  { 0x8f00, 0x2471, 0x2000 },
+  { 0x0f00, 0x2470, 0x0000 },
+  { 0x0f00, 0x2472, 0x0000 },
+  { 0x8f00, 0x2477, 0x3000 },
+  { 0x8f00, 0x2475, 0x2000 },
+  { 0x0f00, 0x2474, 0x0000 },
+  { 0x0f00, 0x2476, 0x0000 },
+  { 0x8f00, 0x2479, 0x2000 },
+  { 0x0f00, 0x2478, 0x0000 },
+  { 0x0f00, 0x247a, 0x0000 },
+  { 0x8f00, 0x2483, 0x4000 },
+  { 0x8f00, 0x247f, 0x3000 },
+  { 0x8f00, 0x247d, 0x2000 },
+  { 0x0f00, 0x247c, 0x0000 },
+  { 0x0f00, 0x247e, 0x0000 },
+  { 0x8f00, 0x2481, 0x2000 },
+  { 0x0f00, 0x2480, 0x0000 },
+  { 0x0f00, 0x2482, 0x0000 },
+  { 0x8f00, 0x2487, 0x3000 },
+  { 0x8f00, 0x2485, 0x2000 },
+  { 0x0f00, 0x2484, 0x0000 },
+  { 0x0f00, 0x2486, 0x0000 },
+  { 0x8f00, 0x2489, 0x2000 },
+  { 0x0f00, 0x2488, 0x0000 },
+  { 0x0f00, 0x248a, 0x0000 },
+  { 0x9a00, 0x24cb, 0x7000 },
+  { 0x9a00, 0x24ab, 0x6000 },
+  { 0x8f00, 0x249b, 0x5000 },
+  { 0x8f00, 0x2493, 0x4000 },
+  { 0x8f00, 0x248f, 0x3000 },
+  { 0x8f00, 0x248d, 0x2000 },
+  { 0x0f00, 0x248c, 0x0000 },
+  { 0x0f00, 0x248e, 0x0000 },
+  { 0x8f00, 0x2491, 0x2000 },
+  { 0x0f00, 0x2490, 0x0000 },
+  { 0x0f00, 0x2492, 0x0000 },
+  { 0x8f00, 0x2497, 0x3000 },
+  { 0x8f00, 0x2495, 0x2000 },
+  { 0x0f00, 0x2494, 0x0000 },
+  { 0x0f00, 0x2496, 0x0000 },
+  { 0x8f00, 0x2499, 0x2000 },
+  { 0x0f00, 0x2498, 0x0000 },
+  { 0x0f00, 0x249a, 0x0000 },
+  { 0x9a00, 0x24a3, 0x4000 },
+  { 0x9a00, 0x249f, 0x3000 },
+  { 0x9a00, 0x249d, 0x2000 },
+  { 0x1a00, 0x249c, 0x0000 },
+  { 0x1a00, 0x249e, 0x0000 },
+  { 0x9a00, 0x24a1, 0x2000 },
+  { 0x1a00, 0x24a0, 0x0000 },
+  { 0x1a00, 0x24a2, 0x0000 },
+  { 0x9a00, 0x24a7, 0x3000 },
+  { 0x9a00, 0x24a5, 0x2000 },
+  { 0x1a00, 0x24a4, 0x0000 },
+  { 0x1a00, 0x24a6, 0x0000 },
+  { 0x9a00, 0x24a9, 0x2000 },
+  { 0x1a00, 0x24a8, 0x0000 },
+  { 0x1a00, 0x24aa, 0x0000 },
+  { 0x9a00, 0x24bb, 0x5000 },
+  { 0x9a00, 0x24b3, 0x4000 },
+  { 0x9a00, 0x24af, 0x3000 },
+  { 0x9a00, 0x24ad, 0x2000 },
+  { 0x1a00, 0x24ac, 0x0000 },
+  { 0x1a00, 0x24ae, 0x0000 },
+  { 0x9a00, 0x24b1, 0x2000 },
+  { 0x1a00, 0x24b0, 0x0000 },
+  { 0x1a00, 0x24b2, 0x0000 },
+  { 0x9a00, 0x24b7, 0x3000 },
+  { 0x9a00, 0x24b5, 0x2000 },
+  { 0x1a00, 0x24b4, 0x0000 },
+  { 0x1a00, 0x24b6, 0x0000 },
+  { 0x9a00, 0x24b9, 0x2000 },
+  { 0x1a00, 0x24b8, 0x0000 },
+  { 0x1a00, 0x24ba, 0x0000 },
+  { 0x9a00, 0x24c3, 0x4000 },
+  { 0x9a00, 0x24bf, 0x3000 },
+  { 0x9a00, 0x24bd, 0x2000 },
+  { 0x1a00, 0x24bc, 0x0000 },
+  { 0x1a00, 0x24be, 0x0000 },
+  { 0x9a00, 0x24c1, 0x2000 },
+  { 0x1a00, 0x24c0, 0x0000 },
+  { 0x1a00, 0x24c2, 0x0000 },
+  { 0x9a00, 0x24c7, 0x3000 },
+  { 0x9a00, 0x24c5, 0x2000 },
+  { 0x1a00, 0x24c4, 0x0000 },
+  { 0x1a00, 0x24c6, 0x0000 },
+  { 0x9a00, 0x24c9, 0x2000 },
+  { 0x1a00, 0x24c8, 0x0000 },
+  { 0x1a00, 0x24ca, 0x0000 },
+  { 0x8f00, 0x24eb, 0x6000 },
+  { 0x9a00, 0x24db, 0x5000 },
+  { 0x9a00, 0x24d3, 0x4000 },
+  { 0x9a00, 0x24cf, 0x3000 },
+  { 0x9a00, 0x24cd, 0x2000 },
+  { 0x1a00, 0x24cc, 0x0000 },
+  { 0x1a00, 0x24ce, 0x0000 },
+  { 0x9a00, 0x24d1, 0x2000 },
+  { 0x1a00, 0x24d0, 0x0000 },
+  { 0x1a00, 0x24d2, 0x0000 },
+  { 0x9a00, 0x24d7, 0x3000 },
+  { 0x9a00, 0x24d5, 0x2000 },
+  { 0x1a00, 0x24d4, 0x0000 },
+  { 0x1a00, 0x24d6, 0x0000 },
+  { 0x9a00, 0x24d9, 0x2000 },
+  { 0x1a00, 0x24d8, 0x0000 },
+  { 0x1a00, 0x24da, 0x0000 },
+  { 0x9a00, 0x24e3, 0x4000 },
+  { 0x9a00, 0x24df, 0x3000 },
+  { 0x9a00, 0x24dd, 0x2000 },
+  { 0x1a00, 0x24dc, 0x0000 },
+  { 0x1a00, 0x24de, 0x0000 },
+  { 0x9a00, 0x24e1, 0x2000 },
+  { 0x1a00, 0x24e0, 0x0000 },
+  { 0x1a00, 0x24e2, 0x0000 },
+  { 0x9a00, 0x24e7, 0x3000 },
+  { 0x9a00, 0x24e5, 0x2000 },
+  { 0x1a00, 0x24e4, 0x0000 },
+  { 0x1a00, 0x24e6, 0x0000 },
+  { 0x9a00, 0x24e9, 0x2000 },
+  { 0x1a00, 0x24e8, 0x0000 },
+  { 0x0f00, 0x24ea, 0x0000 },
+  { 0x8f00, 0x24fb, 0x5000 },
+  { 0x8f00, 0x24f3, 0x4000 },
+  { 0x8f00, 0x24ef, 0x3000 },
+  { 0x8f00, 0x24ed, 0x2000 },
+  { 0x0f00, 0x24ec, 0x0000 },
+  { 0x0f00, 0x24ee, 0x0000 },
+  { 0x8f00, 0x24f1, 0x2000 },
+  { 0x0f00, 0x24f0, 0x0000 },
+  { 0x0f00, 0x24f2, 0x0000 },
+  { 0x8f00, 0x24f7, 0x3000 },
+  { 0x8f00, 0x24f5, 0x2000 },
+  { 0x0f00, 0x24f4, 0x0000 },
+  { 0x0f00, 0x24f6, 0x0000 },
+  { 0x8f00, 0x24f9, 0x2000 },
+  { 0x0f00, 0x24f8, 0x0000 },
+  { 0x0f00, 0x24fa, 0x0000 },
+  { 0x9a00, 0x2503, 0x4000 },
+  { 0x8f00, 0x24ff, 0x3000 },
+  { 0x8f00, 0x24fd, 0x2000 },
+  { 0x0f00, 0x24fc, 0x0000 },
+  { 0x0f00, 0x24fe, 0x0000 },
+  { 0x9a00, 0x2501, 0x2000 },
+  { 0x1a00, 0x2500, 0x0000 },
+  { 0x1a00, 0x2502, 0x0000 },
+  { 0x9a00, 0x2507, 0x3000 },
+  { 0x9a00, 0x2505, 0x2000 },
+  { 0x1a00, 0x2504, 0x0000 },
+  { 0x1a00, 0x2506, 0x0000 },
+  { 0x9a00, 0x2509, 0x2000 },
+  { 0x1a00, 0x2508, 0x0000 },
+  { 0x1a00, 0x250a, 0x0000 },
+  { 0x9a00, 0x260b, 0x9000 },
+  { 0x9a00, 0x258b, 0x8000 },
+  { 0x9a00, 0x254b, 0x7000 },
+  { 0x9a00, 0x252b, 0x6000 },
+  { 0x9a00, 0x251b, 0x5000 },
+  { 0x9a00, 0x2513, 0x4000 },
+  { 0x9a00, 0x250f, 0x3000 },
+  { 0x9a00, 0x250d, 0x2000 },
+  { 0x1a00, 0x250c, 0x0000 },
+  { 0x1a00, 0x250e, 0x0000 },
+  { 0x9a00, 0x2511, 0x2000 },
+  { 0x1a00, 0x2510, 0x0000 },
+  { 0x1a00, 0x2512, 0x0000 },
+  { 0x9a00, 0x2517, 0x3000 },
+  { 0x9a00, 0x2515, 0x2000 },
+  { 0x1a00, 0x2514, 0x0000 },
+  { 0x1a00, 0x2516, 0x0000 },
+  { 0x9a00, 0x2519, 0x2000 },
+  { 0x1a00, 0x2518, 0x0000 },
+  { 0x1a00, 0x251a, 0x0000 },
+  { 0x9a00, 0x2523, 0x4000 },
+  { 0x9a00, 0x251f, 0x3000 },
+  { 0x9a00, 0x251d, 0x2000 },
+  { 0x1a00, 0x251c, 0x0000 },
+  { 0x1a00, 0x251e, 0x0000 },
+  { 0x9a00, 0x2521, 0x2000 },
+  { 0x1a00, 0x2520, 0x0000 },
+  { 0x1a00, 0x2522, 0x0000 },
+  { 0x9a00, 0x2527, 0x3000 },
+  { 0x9a00, 0x2525, 0x2000 },
+  { 0x1a00, 0x2524, 0x0000 },
+  { 0x1a00, 0x2526, 0x0000 },
+  { 0x9a00, 0x2529, 0x2000 },
+  { 0x1a00, 0x2528, 0x0000 },
+  { 0x1a00, 0x252a, 0x0000 },
+  { 0x9a00, 0x253b, 0x5000 },
+  { 0x9a00, 0x2533, 0x4000 },
+  { 0x9a00, 0x252f, 0x3000 },
+  { 0x9a00, 0x252d, 0x2000 },
+  { 0x1a00, 0x252c, 0x0000 },
+  { 0x1a00, 0x252e, 0x0000 },
+  { 0x9a00, 0x2531, 0x2000 },
+  { 0x1a00, 0x2530, 0x0000 },
+  { 0x1a00, 0x2532, 0x0000 },
+  { 0x9a00, 0x2537, 0x3000 },
+  { 0x9a00, 0x2535, 0x2000 },
+  { 0x1a00, 0x2534, 0x0000 },
+  { 0x1a00, 0x2536, 0x0000 },
+  { 0x9a00, 0x2539, 0x2000 },
+  { 0x1a00, 0x2538, 0x0000 },
+  { 0x1a00, 0x253a, 0x0000 },
+  { 0x9a00, 0x2543, 0x4000 },
+  { 0x9a00, 0x253f, 0x3000 },
+  { 0x9a00, 0x253d, 0x2000 },
+  { 0x1a00, 0x253c, 0x0000 },
+  { 0x1a00, 0x253e, 0x0000 },
+  { 0x9a00, 0x2541, 0x2000 },
+  { 0x1a00, 0x2540, 0x0000 },
+  { 0x1a00, 0x2542, 0x0000 },
+  { 0x9a00, 0x2547, 0x3000 },
+  { 0x9a00, 0x2545, 0x2000 },
+  { 0x1a00, 0x2544, 0x0000 },
+  { 0x1a00, 0x2546, 0x0000 },
+  { 0x9a00, 0x2549, 0x2000 },
+  { 0x1a00, 0x2548, 0x0000 },
+  { 0x1a00, 0x254a, 0x0000 },
+  { 0x9a00, 0x256b, 0x6000 },
+  { 0x9a00, 0x255b, 0x5000 },
+  { 0x9a00, 0x2553, 0x4000 },
+  { 0x9a00, 0x254f, 0x3000 },
+  { 0x9a00, 0x254d, 0x2000 },
+  { 0x1a00, 0x254c, 0x0000 },
+  { 0x1a00, 0x254e, 0x0000 },
+  { 0x9a00, 0x2551, 0x2000 },
+  { 0x1a00, 0x2550, 0x0000 },
+  { 0x1a00, 0x2552, 0x0000 },
+  { 0x9a00, 0x2557, 0x3000 },
+  { 0x9a00, 0x2555, 0x2000 },
+  { 0x1a00, 0x2554, 0x0000 },
+  { 0x1a00, 0x2556, 0x0000 },
+  { 0x9a00, 0x2559, 0x2000 },
+  { 0x1a00, 0x2558, 0x0000 },
+  { 0x1a00, 0x255a, 0x0000 },
+  { 0x9a00, 0x2563, 0x4000 },
+  { 0x9a00, 0x255f, 0x3000 },
+  { 0x9a00, 0x255d, 0x2000 },
+  { 0x1a00, 0x255c, 0x0000 },
+  { 0x1a00, 0x255e, 0x0000 },
+  { 0x9a00, 0x2561, 0x2000 },
+  { 0x1a00, 0x2560, 0x0000 },
+  { 0x1a00, 0x2562, 0x0000 },
+  { 0x9a00, 0x2567, 0x3000 },
+  { 0x9a00, 0x2565, 0x2000 },
+  { 0x1a00, 0x2564, 0x0000 },
+  { 0x1a00, 0x2566, 0x0000 },
+  { 0x9a00, 0x2569, 0x2000 },
+  { 0x1a00, 0x2568, 0x0000 },
+  { 0x1a00, 0x256a, 0x0000 },
+  { 0x9a00, 0x257b, 0x5000 },
+  { 0x9a00, 0x2573, 0x4000 },
+  { 0x9a00, 0x256f, 0x3000 },
+  { 0x9a00, 0x256d, 0x2000 },
+  { 0x1a00, 0x256c, 0x0000 },
+  { 0x1a00, 0x256e, 0x0000 },
+  { 0x9a00, 0x2571, 0x2000 },
+  { 0x1a00, 0x2570, 0x0000 },
+  { 0x1a00, 0x2572, 0x0000 },
+  { 0x9a00, 0x2577, 0x3000 },
+  { 0x9a00, 0x2575, 0x2000 },
+  { 0x1a00, 0x2574, 0x0000 },
+  { 0x1a00, 0x2576, 0x0000 },
+  { 0x9a00, 0x2579, 0x2000 },
+  { 0x1a00, 0x2578, 0x0000 },
+  { 0x1a00, 0x257a, 0x0000 },
+  { 0x9a00, 0x2583, 0x4000 },
+  { 0x9a00, 0x257f, 0x3000 },
+  { 0x9a00, 0x257d, 0x2000 },
+  { 0x1a00, 0x257c, 0x0000 },
+  { 0x1a00, 0x257e, 0x0000 },
+  { 0x9a00, 0x2581, 0x2000 },
+  { 0x1a00, 0x2580, 0x0000 },
+  { 0x1a00, 0x2582, 0x0000 },
+  { 0x9a00, 0x2587, 0x3000 },
+  { 0x9a00, 0x2585, 0x2000 },
+  { 0x1a00, 0x2584, 0x0000 },
+  { 0x1a00, 0x2586, 0x0000 },
+  { 0x9a00, 0x2589, 0x2000 },
+  { 0x1a00, 0x2588, 0x0000 },
+  { 0x1a00, 0x258a, 0x0000 },
+  { 0x9a00, 0x25cb, 0x7000 },
+  { 0x9a00, 0x25ab, 0x6000 },
+  { 0x9a00, 0x259b, 0x5000 },
+  { 0x9a00, 0x2593, 0x4000 },
+  { 0x9a00, 0x258f, 0x3000 },
+  { 0x9a00, 0x258d, 0x2000 },
+  { 0x1a00, 0x258c, 0x0000 },
+  { 0x1a00, 0x258e, 0x0000 },
+  { 0x9a00, 0x2591, 0x2000 },
+  { 0x1a00, 0x2590, 0x0000 },
+  { 0x1a00, 0x2592, 0x0000 },
+  { 0x9a00, 0x2597, 0x3000 },
+  { 0x9a00, 0x2595, 0x2000 },
+  { 0x1a00, 0x2594, 0x0000 },
+  { 0x1a00, 0x2596, 0x0000 },
+  { 0x9a00, 0x2599, 0x2000 },
+  { 0x1a00, 0x2598, 0x0000 },
+  { 0x1a00, 0x259a, 0x0000 },
+  { 0x9a00, 0x25a3, 0x4000 },
+  { 0x9a00, 0x259f, 0x3000 },
+  { 0x9a00, 0x259d, 0x2000 },
+  { 0x1a00, 0x259c, 0x0000 },
+  { 0x1a00, 0x259e, 0x0000 },
+  { 0x9a00, 0x25a1, 0x2000 },
+  { 0x1a00, 0x25a0, 0x0000 },
+  { 0x1a00, 0x25a2, 0x0000 },
+  { 0x9a00, 0x25a7, 0x3000 },
+  { 0x9a00, 0x25a5, 0x2000 },
+  { 0x1a00, 0x25a4, 0x0000 },
+  { 0x1a00, 0x25a6, 0x0000 },
+  { 0x9a00, 0x25a9, 0x2000 },
+  { 0x1a00, 0x25a8, 0x0000 },
+  { 0x1a00, 0x25aa, 0x0000 },
+  { 0x9a00, 0x25bb, 0x5000 },
+  { 0x9a00, 0x25b3, 0x4000 },
+  { 0x9a00, 0x25af, 0x3000 },
+  { 0x9a00, 0x25ad, 0x2000 },
+  { 0x1a00, 0x25ac, 0x0000 },
+  { 0x1a00, 0x25ae, 0x0000 },
+  { 0x9a00, 0x25b1, 0x2000 },
+  { 0x1a00, 0x25b0, 0x0000 },
+  { 0x1a00, 0x25b2, 0x0000 },
+  { 0x9900, 0x25b7, 0x3000 },
+  { 0x9a00, 0x25b5, 0x2000 },
+  { 0x1a00, 0x25b4, 0x0000 },
+  { 0x1a00, 0x25b6, 0x0000 },
+  { 0x9a00, 0x25b9, 0x2000 },
+  { 0x1a00, 0x25b8, 0x0000 },
+  { 0x1a00, 0x25ba, 0x0000 },
+  { 0x9a00, 0x25c3, 0x4000 },
+  { 0x9a00, 0x25bf, 0x3000 },
+  { 0x9a00, 0x25bd, 0x2000 },
+  { 0x1a00, 0x25bc, 0x0000 },
+  { 0x1a00, 0x25be, 0x0000 },
+  { 0x9900, 0x25c1, 0x2000 },
+  { 0x1a00, 0x25c0, 0x0000 },
+  { 0x1a00, 0x25c2, 0x0000 },
+  { 0x9a00, 0x25c7, 0x3000 },
+  { 0x9a00, 0x25c5, 0x2000 },
+  { 0x1a00, 0x25c4, 0x0000 },
+  { 0x1a00, 0x25c6, 0x0000 },
+  { 0x9a00, 0x25c9, 0x2000 },
+  { 0x1a00, 0x25c8, 0x0000 },
+  { 0x1a00, 0x25ca, 0x0000 },
+  { 0x9a00, 0x25eb, 0x6000 },
+  { 0x9a00, 0x25db, 0x5000 },
+  { 0x9a00, 0x25d3, 0x4000 },
+  { 0x9a00, 0x25cf, 0x3000 },
+  { 0x9a00, 0x25cd, 0x2000 },
+  { 0x1a00, 0x25cc, 0x0000 },
+  { 0x1a00, 0x25ce, 0x0000 },
+  { 0x9a00, 0x25d1, 0x2000 },
+  { 0x1a00, 0x25d0, 0x0000 },
+  { 0x1a00, 0x25d2, 0x0000 },
+  { 0x9a00, 0x25d7, 0x3000 },
+  { 0x9a00, 0x25d5, 0x2000 },
+  { 0x1a00, 0x25d4, 0x0000 },
+  { 0x1a00, 0x25d6, 0x0000 },
+  { 0x9a00, 0x25d9, 0x2000 },
+  { 0x1a00, 0x25d8, 0x0000 },
+  { 0x1a00, 0x25da, 0x0000 },
+  { 0x9a00, 0x25e3, 0x4000 },
+  { 0x9a00, 0x25df, 0x3000 },
+  { 0x9a00, 0x25dd, 0x2000 },
+  { 0x1a00, 0x25dc, 0x0000 },
+  { 0x1a00, 0x25de, 0x0000 },
+  { 0x9a00, 0x25e1, 0x2000 },
+  { 0x1a00, 0x25e0, 0x0000 },
+  { 0x1a00, 0x25e2, 0x0000 },
+  { 0x9a00, 0x25e7, 0x3000 },
+  { 0x9a00, 0x25e5, 0x2000 },
+  { 0x1a00, 0x25e4, 0x0000 },
+  { 0x1a00, 0x25e6, 0x0000 },
+  { 0x9a00, 0x25e9, 0x2000 },
+  { 0x1a00, 0x25e8, 0x0000 },
+  { 0x1a00, 0x25ea, 0x0000 },
+  { 0x9900, 0x25fb, 0x5000 },
+  { 0x9a00, 0x25f3, 0x4000 },
+  { 0x9a00, 0x25ef, 0x3000 },
+  { 0x9a00, 0x25ed, 0x2000 },
+  { 0x1a00, 0x25ec, 0x0000 },
+  { 0x1a00, 0x25ee, 0x0000 },
+  { 0x9a00, 0x25f1, 0x2000 },
+  { 0x1a00, 0x25f0, 0x0000 },
+  { 0x1a00, 0x25f2, 0x0000 },
+  { 0x9a00, 0x25f7, 0x3000 },
+  { 0x9a00, 0x25f5, 0x2000 },
+  { 0x1a00, 0x25f4, 0x0000 },
+  { 0x1a00, 0x25f6, 0x0000 },
+  { 0x9900, 0x25f9, 0x2000 },
+  { 0x1900, 0x25f8, 0x0000 },
+  { 0x1900, 0x25fa, 0x0000 },
+  { 0x9a00, 0x2603, 0x4000 },
+  { 0x9900, 0x25ff, 0x3000 },
+  { 0x9900, 0x25fd, 0x2000 },
+  { 0x1900, 0x25fc, 0x0000 },
+  { 0x1900, 0x25fe, 0x0000 },
+  { 0x9a00, 0x2601, 0x2000 },
+  { 0x1a00, 0x2600, 0x0000 },
+  { 0x1a00, 0x2602, 0x0000 },
+  { 0x9a00, 0x2607, 0x3000 },
+  { 0x9a00, 0x2605, 0x2000 },
+  { 0x1a00, 0x2604, 0x0000 },
+  { 0x1a00, 0x2606, 0x0000 },
+  { 0x9a00, 0x2609, 0x2000 },
+  { 0x1a00, 0x2608, 0x0000 },
+  { 0x1a00, 0x260a, 0x0000 },
+  { 0x9a00, 0x268e, 0x8000 },
+  { 0x9a00, 0x264c, 0x7000 },
+  { 0x9a00, 0x262c, 0x6000 },
+  { 0x9a00, 0x261c, 0x5000 },
+  { 0x9a00, 0x2613, 0x4000 },
+  { 0x9a00, 0x260f, 0x3000 },
+  { 0x9a00, 0x260d, 0x2000 },
+  { 0x1a00, 0x260c, 0x0000 },
+  { 0x1a00, 0x260e, 0x0000 },
+  { 0x9a00, 0x2611, 0x2000 },
+  { 0x1a00, 0x2610, 0x0000 },
+  { 0x1a00, 0x2612, 0x0000 },
+  { 0x9a00, 0x2617, 0x3000 },
+  { 0x9a00, 0x2615, 0x2000 },
+  { 0x1a00, 0x2614, 0x0000 },
+  { 0x1a00, 0x2616, 0x0000 },
+  { 0x9a00, 0x261a, 0x2000 },
+  { 0x1a00, 0x2619, 0x0000 },
+  { 0x1a00, 0x261b, 0x0000 },
+  { 0x9a00, 0x2624, 0x4000 },
+  { 0x9a00, 0x2620, 0x3000 },
+  { 0x9a00, 0x261e, 0x2000 },
+  { 0x1a00, 0x261d, 0x0000 },
+  { 0x1a00, 0x261f, 0x0000 },
+  { 0x9a00, 0x2622, 0x2000 },
+  { 0x1a00, 0x2621, 0x0000 },
+  { 0x1a00, 0x2623, 0x0000 },
+  { 0x9a00, 0x2628, 0x3000 },
+  { 0x9a00, 0x2626, 0x2000 },
+  { 0x1a00, 0x2625, 0x0000 },
+  { 0x1a00, 0x2627, 0x0000 },
+  { 0x9a00, 0x262a, 0x2000 },
+  { 0x1a00, 0x2629, 0x0000 },
+  { 0x1a00, 0x262b, 0x0000 },
+  { 0x9a00, 0x263c, 0x5000 },
+  { 0x9a00, 0x2634, 0x4000 },
+  { 0x9a00, 0x2630, 0x3000 },
+  { 0x9a00, 0x262e, 0x2000 },
+  { 0x1a00, 0x262d, 0x0000 },
+  { 0x1a00, 0x262f, 0x0000 },
+  { 0x9a00, 0x2632, 0x2000 },
+  { 0x1a00, 0x2631, 0x0000 },
+  { 0x1a00, 0x2633, 0x0000 },
+  { 0x9a00, 0x2638, 0x3000 },
+  { 0x9a00, 0x2636, 0x2000 },
+  { 0x1a00, 0x2635, 0x0000 },
+  { 0x1a00, 0x2637, 0x0000 },
+  { 0x9a00, 0x263a, 0x2000 },
+  { 0x1a00, 0x2639, 0x0000 },
+  { 0x1a00, 0x263b, 0x0000 },
+  { 0x9a00, 0x2644, 0x4000 },
+  { 0x9a00, 0x2640, 0x3000 },
+  { 0x9a00, 0x263e, 0x2000 },
+  { 0x1a00, 0x263d, 0x0000 },
+  { 0x1a00, 0x263f, 0x0000 },
+  { 0x9a00, 0x2642, 0x2000 },
+  { 0x1a00, 0x2641, 0x0000 },
+  { 0x1a00, 0x2643, 0x0000 },
+  { 0x9a00, 0x2648, 0x3000 },
+  { 0x9a00, 0x2646, 0x2000 },
+  { 0x1a00, 0x2645, 0x0000 },
+  { 0x1a00, 0x2647, 0x0000 },
+  { 0x9a00, 0x264a, 0x2000 },
+  { 0x1a00, 0x2649, 0x0000 },
+  { 0x1a00, 0x264b, 0x0000 },
+  { 0x9a00, 0x266c, 0x6000 },
+  { 0x9a00, 0x265c, 0x5000 },
+  { 0x9a00, 0x2654, 0x4000 },
+  { 0x9a00, 0x2650, 0x3000 },
+  { 0x9a00, 0x264e, 0x2000 },
+  { 0x1a00, 0x264d, 0x0000 },
+  { 0x1a00, 0x264f, 0x0000 },
+  { 0x9a00, 0x2652, 0x2000 },
+  { 0x1a00, 0x2651, 0x0000 },
+  { 0x1a00, 0x2653, 0x0000 },
+  { 0x9a00, 0x2658, 0x3000 },
+  { 0x9a00, 0x2656, 0x2000 },
+  { 0x1a00, 0x2655, 0x0000 },
+  { 0x1a00, 0x2657, 0x0000 },
+  { 0x9a00, 0x265a, 0x2000 },
+  { 0x1a00, 0x2659, 0x0000 },
+  { 0x1a00, 0x265b, 0x0000 },
+  { 0x9a00, 0x2664, 0x4000 },
+  { 0x9a00, 0x2660, 0x3000 },
+  { 0x9a00, 0x265e, 0x2000 },
+  { 0x1a00, 0x265d, 0x0000 },
+  { 0x1a00, 0x265f, 0x0000 },
+  { 0x9a00, 0x2662, 0x2000 },
+  { 0x1a00, 0x2661, 0x0000 },
+  { 0x1a00, 0x2663, 0x0000 },
+  { 0x9a00, 0x2668, 0x3000 },
+  { 0x9a00, 0x2666, 0x2000 },
+  { 0x1a00, 0x2665, 0x0000 },
+  { 0x1a00, 0x2667, 0x0000 },
+  { 0x9a00, 0x266a, 0x2000 },
+  { 0x1a00, 0x2669, 0x0000 },
+  { 0x1a00, 0x266b, 0x0000 },
+  { 0x9a00, 0x267c, 0x5000 },
+  { 0x9a00, 0x2674, 0x4000 },
+  { 0x9a00, 0x2670, 0x3000 },
+  { 0x9a00, 0x266e, 0x2000 },
+  { 0x1a00, 0x266d, 0x0000 },
+  { 0x1900, 0x266f, 0x0000 },
+  { 0x9a00, 0x2672, 0x2000 },
+  { 0x1a00, 0x2671, 0x0000 },
+  { 0x1a00, 0x2673, 0x0000 },
+  { 0x9a00, 0x2678, 0x3000 },
+  { 0x9a00, 0x2676, 0x2000 },
+  { 0x1a00, 0x2675, 0x0000 },
+  { 0x1a00, 0x2677, 0x0000 },
+  { 0x9a00, 0x267a, 0x2000 },
+  { 0x1a00, 0x2679, 0x0000 },
+  { 0x1a00, 0x267b, 0x0000 },
+  { 0x9a00, 0x2686, 0x4000 },
+  { 0x9a00, 0x2682, 0x3000 },
+  { 0x9a00, 0x2680, 0x2000 },
+  { 0x1a00, 0x267d, 0x0000 },
+  { 0x1a00, 0x2681, 0x0000 },
+  { 0x9a00, 0x2684, 0x2000 },
+  { 0x1a00, 0x2683, 0x0000 },
+  { 0x1a00, 0x2685, 0x0000 },
+  { 0x9a00, 0x268a, 0x3000 },
+  { 0x9a00, 0x2688, 0x2000 },
+  { 0x1a00, 0x2687, 0x0000 },
+  { 0x1a00, 0x2689, 0x0000 },
+  { 0x9a00, 0x268c, 0x2000 },
+  { 0x1a00, 0x268b, 0x0000 },
+  { 0x1a00, 0x268d, 0x0000 },
+  { 0x9a00, 0x273f, 0x7000 },
+  { 0x9a00, 0x271e, 0x6000 },
+  { 0x9a00, 0x270e, 0x5000 },
+  { 0x9a00, 0x2703, 0x4000 },
+  { 0x9a00, 0x26a0, 0x3000 },
+  { 0x9a00, 0x2690, 0x2000 },
+  { 0x1a00, 0x268f, 0x0000 },
+  { 0x1a00, 0x2691, 0x0000 },
+  { 0x9a00, 0x2701, 0x2000 },
+  { 0x1a00, 0x26a1, 0x0000 },
+  { 0x1a00, 0x2702, 0x0000 },
+  { 0x9a00, 0x2708, 0x3000 },
+  { 0x9a00, 0x2706, 0x2000 },
+  { 0x1a00, 0x2704, 0x0000 },
+  { 0x1a00, 0x2707, 0x0000 },
+  { 0x9a00, 0x270c, 0x2000 },
+  { 0x1a00, 0x2709, 0x0000 },
+  { 0x1a00, 0x270d, 0x0000 },
+  { 0x9a00, 0x2716, 0x4000 },
+  { 0x9a00, 0x2712, 0x3000 },
+  { 0x9a00, 0x2710, 0x2000 },
+  { 0x1a00, 0x270f, 0x0000 },
+  { 0x1a00, 0x2711, 0x0000 },
+  { 0x9a00, 0x2714, 0x2000 },
+  { 0x1a00, 0x2713, 0x0000 },
+  { 0x1a00, 0x2715, 0x0000 },
+  { 0x9a00, 0x271a, 0x3000 },
+  { 0x9a00, 0x2718, 0x2000 },
+  { 0x1a00, 0x2717, 0x0000 },
+  { 0x1a00, 0x2719, 0x0000 },
+  { 0x9a00, 0x271c, 0x2000 },
+  { 0x1a00, 0x271b, 0x0000 },
+  { 0x1a00, 0x271d, 0x0000 },
+  { 0x9a00, 0x272f, 0x5000 },
+  { 0x9a00, 0x2726, 0x4000 },
+  { 0x9a00, 0x2722, 0x3000 },
+  { 0x9a00, 0x2720, 0x2000 },
+  { 0x1a00, 0x271f, 0x0000 },
+  { 0x1a00, 0x2721, 0x0000 },
+  { 0x9a00, 0x2724, 0x2000 },
+  { 0x1a00, 0x2723, 0x0000 },
+  { 0x1a00, 0x2725, 0x0000 },
+  { 0x9a00, 0x272b, 0x3000 },
+  { 0x9a00, 0x2729, 0x2000 },
+  { 0x1a00, 0x2727, 0x0000 },
+  { 0x1a00, 0x272a, 0x0000 },
+  { 0x9a00, 0x272d, 0x2000 },
+  { 0x1a00, 0x272c, 0x0000 },
+  { 0x1a00, 0x272e, 0x0000 },
+  { 0x9a00, 0x2737, 0x4000 },
+  { 0x9a00, 0x2733, 0x3000 },
+  { 0x9a00, 0x2731, 0x2000 },
+  { 0x1a00, 0x2730, 0x0000 },
+  { 0x1a00, 0x2732, 0x0000 },
+  { 0x9a00, 0x2735, 0x2000 },
+  { 0x1a00, 0x2734, 0x0000 },
+  { 0x1a00, 0x2736, 0x0000 },
+  { 0x9a00, 0x273b, 0x3000 },
+  { 0x9a00, 0x2739, 0x2000 },
+  { 0x1a00, 0x2738, 0x0000 },
+  { 0x1a00, 0x273a, 0x0000 },
+  { 0x9a00, 0x273d, 0x2000 },
+  { 0x1a00, 0x273c, 0x0000 },
+  { 0x1a00, 0x273e, 0x0000 },
+  { 0x9a00, 0x2767, 0x6000 },
+  { 0x9a00, 0x2751, 0x5000 },
+  { 0x9a00, 0x2747, 0x4000 },
+  { 0x9a00, 0x2743, 0x3000 },
+  { 0x9a00, 0x2741, 0x2000 },
+  { 0x1a00, 0x2740, 0x0000 },
+  { 0x1a00, 0x2742, 0x0000 },
+  { 0x9a00, 0x2745, 0x2000 },
+  { 0x1a00, 0x2744, 0x0000 },
+  { 0x1a00, 0x2746, 0x0000 },
+  { 0x9a00, 0x274b, 0x3000 },
+  { 0x9a00, 0x2749, 0x2000 },
+  { 0x1a00, 0x2748, 0x0000 },
+  { 0x1a00, 0x274a, 0x0000 },
+  { 0x9a00, 0x274f, 0x2000 },
+  { 0x1a00, 0x274d, 0x0000 },
+  { 0x1a00, 0x2750, 0x0000 },
+  { 0x9a00, 0x275d, 0x4000 },
+  { 0x9a00, 0x2759, 0x3000 },
+  { 0x9a00, 0x2756, 0x2000 },
+  { 0x1a00, 0x2752, 0x0000 },
+  { 0x1a00, 0x2758, 0x0000 },
+  { 0x9a00, 0x275b, 0x2000 },
+  { 0x1a00, 0x275a, 0x0000 },
+  { 0x1a00, 0x275c, 0x0000 },
+  { 0x9a00, 0x2763, 0x3000 },
+  { 0x9a00, 0x2761, 0x2000 },
+  { 0x1a00, 0x275e, 0x0000 },
+  { 0x1a00, 0x2762, 0x0000 },
+  { 0x9a00, 0x2765, 0x2000 },
+  { 0x1a00, 0x2764, 0x0000 },
+  { 0x1a00, 0x2766, 0x0000 },
+  { 0x8f00, 0x2777, 0x5000 },
+  { 0x9200, 0x276f, 0x4000 },
+  { 0x9200, 0x276b, 0x3000 },
+  { 0x9200, 0x2769, 0x2000 },
+  { 0x1600, 0x2768, 0x0000 },
+  { 0x1600, 0x276a, 0x0000 },
+  { 0x9200, 0x276d, 0x2000 },
+  { 0x1600, 0x276c, 0x0000 },
+  { 0x1600, 0x276e, 0x0000 },
+  { 0x9200, 0x2773, 0x3000 },
+  { 0x9200, 0x2771, 0x2000 },
+  { 0x1600, 0x2770, 0x0000 },
+  { 0x1600, 0x2772, 0x0000 },
+  { 0x9200, 0x2775, 0x2000 },
+  { 0x1600, 0x2774, 0x0000 },
+  { 0x0f00, 0x2776, 0x0000 },
+  { 0x8f00, 0x277f, 0x4000 },
+  { 0x8f00, 0x277b, 0x3000 },
+  { 0x8f00, 0x2779, 0x2000 },
+  { 0x0f00, 0x2778, 0x0000 },
+  { 0x0f00, 0x277a, 0x0000 },
+  { 0x8f00, 0x277d, 0x2000 },
+  { 0x0f00, 0x277c, 0x0000 },
+  { 0x0f00, 0x277e, 0x0000 },
+  { 0x8f00, 0x2783, 0x3000 },
+  { 0x8f00, 0x2781, 0x2000 },
+  { 0x0f00, 0x2780, 0x0000 },
+  { 0x0f00, 0x2782, 0x0000 },
+  { 0x8f00, 0x2785, 0x2000 },
+  { 0x0f00, 0x2784, 0x0000 },
+  { 0x0f00, 0x2786, 0x0000 },
+  { 0x9900, 0x29a0, 0xa000 },
+  { 0x9a00, 0x28a0, 0x9000 },
+  { 0x9a00, 0x2820, 0x8000 },
+  { 0x9900, 0x27dc, 0x7000 },
+  { 0x9a00, 0x27aa, 0x6000 },
+  { 0x9a00, 0x279a, 0x5000 },
+  { 0x8f00, 0x278f, 0x4000 },
+  { 0x8f00, 0x278b, 0x3000 },
+  { 0x8f00, 0x2789, 0x2000 },
+  { 0x0f00, 0x2788, 0x0000 },
+  { 0x0f00, 0x278a, 0x0000 },
+  { 0x8f00, 0x278d, 0x2000 },
+  { 0x0f00, 0x278c, 0x0000 },
+  { 0x0f00, 0x278e, 0x0000 },
+  { 0x8f00, 0x2793, 0x3000 },
+  { 0x8f00, 0x2791, 0x2000 },
+  { 0x0f00, 0x2790, 0x0000 },
+  { 0x0f00, 0x2792, 0x0000 },
+  { 0x9a00, 0x2798, 0x2000 },
+  { 0x1a00, 0x2794, 0x0000 },
+  { 0x1a00, 0x2799, 0x0000 },
+  { 0x9a00, 0x27a2, 0x4000 },
+  { 0x9a00, 0x279e, 0x3000 },
+  { 0x9a00, 0x279c, 0x2000 },
+  { 0x1a00, 0x279b, 0x0000 },
+  { 0x1a00, 0x279d, 0x0000 },
+  { 0x9a00, 0x27a0, 0x2000 },
+  { 0x1a00, 0x279f, 0x0000 },
+  { 0x1a00, 0x27a1, 0x0000 },
+  { 0x9a00, 0x27a6, 0x3000 },
+  { 0x9a00, 0x27a4, 0x2000 },
+  { 0x1a00, 0x27a3, 0x0000 },
+  { 0x1a00, 0x27a5, 0x0000 },
+  { 0x9a00, 0x27a8, 0x2000 },
+  { 0x1a00, 0x27a7, 0x0000 },
+  { 0x1a00, 0x27a9, 0x0000 },
+  { 0x9a00, 0x27bb, 0x5000 },
+  { 0x9a00, 0x27b3, 0x4000 },
+  { 0x9a00, 0x27ae, 0x3000 },
+  { 0x9a00, 0x27ac, 0x2000 },
+  { 0x1a00, 0x27ab, 0x0000 },
+  { 0x1a00, 0x27ad, 0x0000 },
+  { 0x9a00, 0x27b1, 0x2000 },
+  { 0x1a00, 0x27af, 0x0000 },
+  { 0x1a00, 0x27b2, 0x0000 },
+  { 0x9a00, 0x27b7, 0x3000 },
+  { 0x9a00, 0x27b5, 0x2000 },
+  { 0x1a00, 0x27b4, 0x0000 },
+  { 0x1a00, 0x27b6, 0x0000 },
+  { 0x9a00, 0x27b9, 0x2000 },
+  { 0x1a00, 0x27b8, 0x0000 },
+  { 0x1a00, 0x27ba, 0x0000 },
+  { 0x9900, 0x27d4, 0x4000 },
+  { 0x9900, 0x27d0, 0x3000 },
+  { 0x9a00, 0x27bd, 0x2000 },
+  { 0x1a00, 0x27bc, 0x0000 },
+  { 0x1a00, 0x27be, 0x0000 },
+  { 0x9900, 0x27d2, 0x2000 },
+  { 0x1900, 0x27d1, 0x0000 },
+  { 0x1900, 0x27d3, 0x0000 },
+  { 0x9900, 0x27d8, 0x3000 },
+  { 0x9900, 0x27d6, 0x2000 },
+  { 0x1900, 0x27d5, 0x0000 },
+  { 0x1900, 0x27d7, 0x0000 },
+  { 0x9900, 0x27da, 0x2000 },
+  { 0x1900, 0x27d9, 0x0000 },
+  { 0x1900, 0x27db, 0x0000 },
+  { 0x9a00, 0x2800, 0x6000 },
+  { 0x9900, 0x27f0, 0x5000 },
+  { 0x9900, 0x27e4, 0x4000 },
+  { 0x9900, 0x27e0, 0x3000 },
+  { 0x9900, 0x27de, 0x2000 },
+  { 0x1900, 0x27dd, 0x0000 },
+  { 0x1900, 0x27df, 0x0000 },
+  { 0x9900, 0x27e2, 0x2000 },
+  { 0x1900, 0x27e1, 0x0000 },
+  { 0x1900, 0x27e3, 0x0000 },
+  { 0x9600, 0x27e8, 0x3000 },
+  { 0x9600, 0x27e6, 0x2000 },
+  { 0x1900, 0x27e5, 0x0000 },
+  { 0x1200, 0x27e7, 0x0000 },
+  { 0x9600, 0x27ea, 0x2000 },
+  { 0x1200, 0x27e9, 0x0000 },
+  { 0x1200, 0x27eb, 0x0000 },
+  { 0x9900, 0x27f8, 0x4000 },
+  { 0x9900, 0x27f4, 0x3000 },
+  { 0x9900, 0x27f2, 0x2000 },
+  { 0x1900, 0x27f1, 0x0000 },
+  { 0x1900, 0x27f3, 0x0000 },
+  { 0x9900, 0x27f6, 0x2000 },
+  { 0x1900, 0x27f5, 0x0000 },
+  { 0x1900, 0x27f7, 0x0000 },
+  { 0x9900, 0x27fc, 0x3000 },
+  { 0x9900, 0x27fa, 0x2000 },
+  { 0x1900, 0x27f9, 0x0000 },
+  { 0x1900, 0x27fb, 0x0000 },
+  { 0x9900, 0x27fe, 0x2000 },
+  { 0x1900, 0x27fd, 0x0000 },
+  { 0x1900, 0x27ff, 0x0000 },
+  { 0x9a00, 0x2810, 0x5000 },
+  { 0x9a00, 0x2808, 0x4000 },
+  { 0x9a00, 0x2804, 0x3000 },
+  { 0x9a00, 0x2802, 0x2000 },
+  { 0x1a00, 0x2801, 0x0000 },
+  { 0x1a00, 0x2803, 0x0000 },
+  { 0x9a00, 0x2806, 0x2000 },
+  { 0x1a00, 0x2805, 0x0000 },
+  { 0x1a00, 0x2807, 0x0000 },
+  { 0x9a00, 0x280c, 0x3000 },
+  { 0x9a00, 0x280a, 0x2000 },
+  { 0x1a00, 0x2809, 0x0000 },
+  { 0x1a00, 0x280b, 0x0000 },
+  { 0x9a00, 0x280e, 0x2000 },
+  { 0x1a00, 0x280d, 0x0000 },
+  { 0x1a00, 0x280f, 0x0000 },
+  { 0x9a00, 0x2818, 0x4000 },
+  { 0x9a00, 0x2814, 0x3000 },
+  { 0x9a00, 0x2812, 0x2000 },
+  { 0x1a00, 0x2811, 0x0000 },
+  { 0x1a00, 0x2813, 0x0000 },
+  { 0x9a00, 0x2816, 0x2000 },
+  { 0x1a00, 0x2815, 0x0000 },
+  { 0x1a00, 0x2817, 0x0000 },
+  { 0x9a00, 0x281c, 0x3000 },
+  { 0x9a00, 0x281a, 0x2000 },
+  { 0x1a00, 0x2819, 0x0000 },
+  { 0x1a00, 0x281b, 0x0000 },
+  { 0x9a00, 0x281e, 0x2000 },
+  { 0x1a00, 0x281d, 0x0000 },
+  { 0x1a00, 0x281f, 0x0000 },
+  { 0x9a00, 0x2860, 0x7000 },
+  { 0x9a00, 0x2840, 0x6000 },
+  { 0x9a00, 0x2830, 0x5000 },
+  { 0x9a00, 0x2828, 0x4000 },
+  { 0x9a00, 0x2824, 0x3000 },
+  { 0x9a00, 0x2822, 0x2000 },
+  { 0x1a00, 0x2821, 0x0000 },
+  { 0x1a00, 0x2823, 0x0000 },
+  { 0x9a00, 0x2826, 0x2000 },
+  { 0x1a00, 0x2825, 0x0000 },
+  { 0x1a00, 0x2827, 0x0000 },
+  { 0x9a00, 0x282c, 0x3000 },
+  { 0x9a00, 0x282a, 0x2000 },
+  { 0x1a00, 0x2829, 0x0000 },
+  { 0x1a00, 0x282b, 0x0000 },
+  { 0x9a00, 0x282e, 0x2000 },
+  { 0x1a00, 0x282d, 0x0000 },
+  { 0x1a00, 0x282f, 0x0000 },
+  { 0x9a00, 0x2838, 0x4000 },
+  { 0x9a00, 0x2834, 0x3000 },
+  { 0x9a00, 0x2832, 0x2000 },
+  { 0x1a00, 0x2831, 0x0000 },
+  { 0x1a00, 0x2833, 0x0000 },
+  { 0x9a00, 0x2836, 0x2000 },
+  { 0x1a00, 0x2835, 0x0000 },
+  { 0x1a00, 0x2837, 0x0000 },
+  { 0x9a00, 0x283c, 0x3000 },
+  { 0x9a00, 0x283a, 0x2000 },
+  { 0x1a00, 0x2839, 0x0000 },
+  { 0x1a00, 0x283b, 0x0000 },
+  { 0x9a00, 0x283e, 0x2000 },
+  { 0x1a00, 0x283d, 0x0000 },
+  { 0x1a00, 0x283f, 0x0000 },
+  { 0x9a00, 0x2850, 0x5000 },
+  { 0x9a00, 0x2848, 0x4000 },
+  { 0x9a00, 0x2844, 0x3000 },
+  { 0x9a00, 0x2842, 0x2000 },
+  { 0x1a00, 0x2841, 0x0000 },
+  { 0x1a00, 0x2843, 0x0000 },
+  { 0x9a00, 0x2846, 0x2000 },
+  { 0x1a00, 0x2845, 0x0000 },
+  { 0x1a00, 0x2847, 0x0000 },
+  { 0x9a00, 0x284c, 0x3000 },
+  { 0x9a00, 0x284a, 0x2000 },
+  { 0x1a00, 0x2849, 0x0000 },
+  { 0x1a00, 0x284b, 0x0000 },
+  { 0x9a00, 0x284e, 0x2000 },
+  { 0x1a00, 0x284d, 0x0000 },
+  { 0x1a00, 0x284f, 0x0000 },
+  { 0x9a00, 0x2858, 0x4000 },
+  { 0x9a00, 0x2854, 0x3000 },
+  { 0x9a00, 0x2852, 0x2000 },
+  { 0x1a00, 0x2851, 0x0000 },
+  { 0x1a00, 0x2853, 0x0000 },
+  { 0x9a00, 0x2856, 0x2000 },
+  { 0x1a00, 0x2855, 0x0000 },
+  { 0x1a00, 0x2857, 0x0000 },
+  { 0x9a00, 0x285c, 0x3000 },
+  { 0x9a00, 0x285a, 0x2000 },
+  { 0x1a00, 0x2859, 0x0000 },
+  { 0x1a00, 0x285b, 0x0000 },
+  { 0x9a00, 0x285e, 0x2000 },
+  { 0x1a00, 0x285d, 0x0000 },
+  { 0x1a00, 0x285f, 0x0000 },
+  { 0x9a00, 0x2880, 0x6000 },
+  { 0x9a00, 0x2870, 0x5000 },
+  { 0x9a00, 0x2868, 0x4000 },
+  { 0x9a00, 0x2864, 0x3000 },
+  { 0x9a00, 0x2862, 0x2000 },
+  { 0x1a00, 0x2861, 0x0000 },
+  { 0x1a00, 0x2863, 0x0000 },
+  { 0x9a00, 0x2866, 0x2000 },
+  { 0x1a00, 0x2865, 0x0000 },
+  { 0x1a00, 0x2867, 0x0000 },
+  { 0x9a00, 0x286c, 0x3000 },
+  { 0x9a00, 0x286a, 0x2000 },
+  { 0x1a00, 0x2869, 0x0000 },
+  { 0x1a00, 0x286b, 0x0000 },
+  { 0x9a00, 0x286e, 0x2000 },
+  { 0x1a00, 0x286d, 0x0000 },
+  { 0x1a00, 0x286f, 0x0000 },
+  { 0x9a00, 0x2878, 0x4000 },
+  { 0x9a00, 0x2874, 0x3000 },
+  { 0x9a00, 0x2872, 0x2000 },
+  { 0x1a00, 0x2871, 0x0000 },
+  { 0x1a00, 0x2873, 0x0000 },
+  { 0x9a00, 0x2876, 0x2000 },
+  { 0x1a00, 0x2875, 0x0000 },
+  { 0x1a00, 0x2877, 0x0000 },
+  { 0x9a00, 0x287c, 0x3000 },
+  { 0x9a00, 0x287a, 0x2000 },
+  { 0x1a00, 0x2879, 0x0000 },
+  { 0x1a00, 0x287b, 0x0000 },
+  { 0x9a00, 0x287e, 0x2000 },
+  { 0x1a00, 0x287d, 0x0000 },
+  { 0x1a00, 0x287f, 0x0000 },
+  { 0x9a00, 0x2890, 0x5000 },
+  { 0x9a00, 0x2888, 0x4000 },
+  { 0x9a00, 0x2884, 0x3000 },
+  { 0x9a00, 0x2882, 0x2000 },
+  { 0x1a00, 0x2881, 0x0000 },
+  { 0x1a00, 0x2883, 0x0000 },
+  { 0x9a00, 0x2886, 0x2000 },
+  { 0x1a00, 0x2885, 0x0000 },
+  { 0x1a00, 0x2887, 0x0000 },
+  { 0x9a00, 0x288c, 0x3000 },
+  { 0x9a00, 0x288a, 0x2000 },
+  { 0x1a00, 0x2889, 0x0000 },
+  { 0x1a00, 0x288b, 0x0000 },
+  { 0x9a00, 0x288e, 0x2000 },
+  { 0x1a00, 0x288d, 0x0000 },
+  { 0x1a00, 0x288f, 0x0000 },
+  { 0x9a00, 0x2898, 0x4000 },
+  { 0x9a00, 0x2894, 0x3000 },
+  { 0x9a00, 0x2892, 0x2000 },
+  { 0x1a00, 0x2891, 0x0000 },
+  { 0x1a00, 0x2893, 0x0000 },
+  { 0x9a00, 0x2896, 0x2000 },
+  { 0x1a00, 0x2895, 0x0000 },
+  { 0x1a00, 0x2897, 0x0000 },
+  { 0x9a00, 0x289c, 0x3000 },
+  { 0x9a00, 0x289a, 0x2000 },
+  { 0x1a00, 0x2899, 0x0000 },
+  { 0x1a00, 0x289b, 0x0000 },
+  { 0x9a00, 0x289e, 0x2000 },
+  { 0x1a00, 0x289d, 0x0000 },
+  { 0x1a00, 0x289f, 0x0000 },
+  { 0x9900, 0x2920, 0x8000 },
+  { 0x9a00, 0x28e0, 0x7000 },
+  { 0x9a00, 0x28c0, 0x6000 },
+  { 0x9a00, 0x28b0, 0x5000 },
+  { 0x9a00, 0x28a8, 0x4000 },
+  { 0x9a00, 0x28a4, 0x3000 },
+  { 0x9a00, 0x28a2, 0x2000 },
+  { 0x1a00, 0x28a1, 0x0000 },
+  { 0x1a00, 0x28a3, 0x0000 },
+  { 0x9a00, 0x28a6, 0x2000 },
+  { 0x1a00, 0x28a5, 0x0000 },
+  { 0x1a00, 0x28a7, 0x0000 },
+  { 0x9a00, 0x28ac, 0x3000 },
+  { 0x9a00, 0x28aa, 0x2000 },
+  { 0x1a00, 0x28a9, 0x0000 },
+  { 0x1a00, 0x28ab, 0x0000 },
+  { 0x9a00, 0x28ae, 0x2000 },
+  { 0x1a00, 0x28ad, 0x0000 },
+  { 0x1a00, 0x28af, 0x0000 },
+  { 0x9a00, 0x28b8, 0x4000 },
+  { 0x9a00, 0x28b4, 0x3000 },
+  { 0x9a00, 0x28b2, 0x2000 },
+  { 0x1a00, 0x28b1, 0x0000 },
+  { 0x1a00, 0x28b3, 0x0000 },
+  { 0x9a00, 0x28b6, 0x2000 },
+  { 0x1a00, 0x28b5, 0x0000 },
+  { 0x1a00, 0x28b7, 0x0000 },
+  { 0x9a00, 0x28bc, 0x3000 },
+  { 0x9a00, 0x28ba, 0x2000 },
+  { 0x1a00, 0x28b9, 0x0000 },
+  { 0x1a00, 0x28bb, 0x0000 },
+  { 0x9a00, 0x28be, 0x2000 },
+  { 0x1a00, 0x28bd, 0x0000 },
+  { 0x1a00, 0x28bf, 0x0000 },
+  { 0x9a00, 0x28d0, 0x5000 },
+  { 0x9a00, 0x28c8, 0x4000 },
+  { 0x9a00, 0x28c4, 0x3000 },
+  { 0x9a00, 0x28c2, 0x2000 },
+  { 0x1a00, 0x28c1, 0x0000 },
+  { 0x1a00, 0x28c3, 0x0000 },
+  { 0x9a00, 0x28c6, 0x2000 },
+  { 0x1a00, 0x28c5, 0x0000 },
+  { 0x1a00, 0x28c7, 0x0000 },
+  { 0x9a00, 0x28cc, 0x3000 },
+  { 0x9a00, 0x28ca, 0x2000 },
+  { 0x1a00, 0x28c9, 0x0000 },
+  { 0x1a00, 0x28cb, 0x0000 },
+  { 0x9a00, 0x28ce, 0x2000 },
+  { 0x1a00, 0x28cd, 0x0000 },
+  { 0x1a00, 0x28cf, 0x0000 },
+  { 0x9a00, 0x28d8, 0x4000 },
+  { 0x9a00, 0x28d4, 0x3000 },
+  { 0x9a00, 0x28d2, 0x2000 },
+  { 0x1a00, 0x28d1, 0x0000 },
+  { 0x1a00, 0x28d3, 0x0000 },
+  { 0x9a00, 0x28d6, 0x2000 },
+  { 0x1a00, 0x28d5, 0x0000 },
+  { 0x1a00, 0x28d7, 0x0000 },
+  { 0x9a00, 0x28dc, 0x3000 },
+  { 0x9a00, 0x28da, 0x2000 },
+  { 0x1a00, 0x28d9, 0x0000 },
+  { 0x1a00, 0x28db, 0x0000 },
+  { 0x9a00, 0x28de, 0x2000 },
+  { 0x1a00, 0x28dd, 0x0000 },
+  { 0x1a00, 0x28df, 0x0000 },
+  { 0x9900, 0x2900, 0x6000 },
+  { 0x9a00, 0x28f0, 0x5000 },
+  { 0x9a00, 0x28e8, 0x4000 },
+  { 0x9a00, 0x28e4, 0x3000 },
+  { 0x9a00, 0x28e2, 0x2000 },
+  { 0x1a00, 0x28e1, 0x0000 },
+  { 0x1a00, 0x28e3, 0x0000 },
+  { 0x9a00, 0x28e6, 0x2000 },
+  { 0x1a00, 0x28e5, 0x0000 },
+  { 0x1a00, 0x28e7, 0x0000 },
+  { 0x9a00, 0x28ec, 0x3000 },
+  { 0x9a00, 0x28ea, 0x2000 },
+  { 0x1a00, 0x28e9, 0x0000 },
+  { 0x1a00, 0x28eb, 0x0000 },
+  { 0x9a00, 0x28ee, 0x2000 },
+  { 0x1a00, 0x28ed, 0x0000 },
+  { 0x1a00, 0x28ef, 0x0000 },
+  { 0x9a00, 0x28f8, 0x4000 },
+  { 0x9a00, 0x28f4, 0x3000 },
+  { 0x9a00, 0x28f2, 0x2000 },
+  { 0x1a00, 0x28f1, 0x0000 },
+  { 0x1a00, 0x28f3, 0x0000 },
+  { 0x9a00, 0x28f6, 0x2000 },
+  { 0x1a00, 0x28f5, 0x0000 },
+  { 0x1a00, 0x28f7, 0x0000 },
+  { 0x9a00, 0x28fc, 0x3000 },
+  { 0x9a00, 0x28fa, 0x2000 },
+  { 0x1a00, 0x28f9, 0x0000 },
+  { 0x1a00, 0x28fb, 0x0000 },
+  { 0x9a00, 0x28fe, 0x2000 },
+  { 0x1a00, 0x28fd, 0x0000 },
+  { 0x1a00, 0x28ff, 0x0000 },
+  { 0x9900, 0x2910, 0x5000 },
+  { 0x9900, 0x2908, 0x4000 },
+  { 0x9900, 0x2904, 0x3000 },
+  { 0x9900, 0x2902, 0x2000 },
+  { 0x1900, 0x2901, 0x0000 },
+  { 0x1900, 0x2903, 0x0000 },
+  { 0x9900, 0x2906, 0x2000 },
+  { 0x1900, 0x2905, 0x0000 },
+  { 0x1900, 0x2907, 0x0000 },
+  { 0x9900, 0x290c, 0x3000 },
+  { 0x9900, 0x290a, 0x2000 },
+  { 0x1900, 0x2909, 0x0000 },
+  { 0x1900, 0x290b, 0x0000 },
+  { 0x9900, 0x290e, 0x2000 },
+  { 0x1900, 0x290d, 0x0000 },
+  { 0x1900, 0x290f, 0x0000 },
+  { 0x9900, 0x2918, 0x4000 },
+  { 0x9900, 0x2914, 0x3000 },
+  { 0x9900, 0x2912, 0x2000 },
+  { 0x1900, 0x2911, 0x0000 },
+  { 0x1900, 0x2913, 0x0000 },
+  { 0x9900, 0x2916, 0x2000 },
+  { 0x1900, 0x2915, 0x0000 },
+  { 0x1900, 0x2917, 0x0000 },
+  { 0x9900, 0x291c, 0x3000 },
+  { 0x9900, 0x291a, 0x2000 },
+  { 0x1900, 0x2919, 0x0000 },
+  { 0x1900, 0x291b, 0x0000 },
+  { 0x9900, 0x291e, 0x2000 },
+  { 0x1900, 0x291d, 0x0000 },
+  { 0x1900, 0x291f, 0x0000 },
+  { 0x9900, 0x2960, 0x7000 },
+  { 0x9900, 0x2940, 0x6000 },
+  { 0x9900, 0x2930, 0x5000 },
+  { 0x9900, 0x2928, 0x4000 },
+  { 0x9900, 0x2924, 0x3000 },
+  { 0x9900, 0x2922, 0x2000 },
+  { 0x1900, 0x2921, 0x0000 },
+  { 0x1900, 0x2923, 0x0000 },
+  { 0x9900, 0x2926, 0x2000 },
+  { 0x1900, 0x2925, 0x0000 },
+  { 0x1900, 0x2927, 0x0000 },
+  { 0x9900, 0x292c, 0x3000 },
+  { 0x9900, 0x292a, 0x2000 },
+  { 0x1900, 0x2929, 0x0000 },
+  { 0x1900, 0x292b, 0x0000 },
+  { 0x9900, 0x292e, 0x2000 },
+  { 0x1900, 0x292d, 0x0000 },
+  { 0x1900, 0x292f, 0x0000 },
+  { 0x9900, 0x2938, 0x4000 },
+  { 0x9900, 0x2934, 0x3000 },
+  { 0x9900, 0x2932, 0x2000 },
+  { 0x1900, 0x2931, 0x0000 },
+  { 0x1900, 0x2933, 0x0000 },
+  { 0x9900, 0x2936, 0x2000 },
+  { 0x1900, 0x2935, 0x0000 },
+  { 0x1900, 0x2937, 0x0000 },
+  { 0x9900, 0x293c, 0x3000 },
+  { 0x9900, 0x293a, 0x2000 },
+  { 0x1900, 0x2939, 0x0000 },
+  { 0x1900, 0x293b, 0x0000 },
+  { 0x9900, 0x293e, 0x2000 },
+  { 0x1900, 0x293d, 0x0000 },
+  { 0x1900, 0x293f, 0x0000 },
+  { 0x9900, 0x2950, 0x5000 },
+  { 0x9900, 0x2948, 0x4000 },
+  { 0x9900, 0x2944, 0x3000 },
+  { 0x9900, 0x2942, 0x2000 },
+  { 0x1900, 0x2941, 0x0000 },
+  { 0x1900, 0x2943, 0x0000 },
+  { 0x9900, 0x2946, 0x2000 },
+  { 0x1900, 0x2945, 0x0000 },
+  { 0x1900, 0x2947, 0x0000 },
+  { 0x9900, 0x294c, 0x3000 },
+  { 0x9900, 0x294a, 0x2000 },
+  { 0x1900, 0x2949, 0x0000 },
+  { 0x1900, 0x294b, 0x0000 },
+  { 0x9900, 0x294e, 0x2000 },
+  { 0x1900, 0x294d, 0x0000 },
+  { 0x1900, 0x294f, 0x0000 },
+  { 0x9900, 0x2958, 0x4000 },
+  { 0x9900, 0x2954, 0x3000 },
+  { 0x9900, 0x2952, 0x2000 },
+  { 0x1900, 0x2951, 0x0000 },
+  { 0x1900, 0x2953, 0x0000 },
+  { 0x9900, 0x2956, 0x2000 },
+  { 0x1900, 0x2955, 0x0000 },
+  { 0x1900, 0x2957, 0x0000 },
+  { 0x9900, 0x295c, 0x3000 },
+  { 0x9900, 0x295a, 0x2000 },
+  { 0x1900, 0x2959, 0x0000 },
+  { 0x1900, 0x295b, 0x0000 },
+  { 0x9900, 0x295e, 0x2000 },
+  { 0x1900, 0x295d, 0x0000 },
+  { 0x1900, 0x295f, 0x0000 },
+  { 0x9900, 0x2980, 0x6000 },
+  { 0x9900, 0x2970, 0x5000 },
+  { 0x9900, 0x2968, 0x4000 },
+  { 0x9900, 0x2964, 0x3000 },
+  { 0x9900, 0x2962, 0x2000 },
+  { 0x1900, 0x2961, 0x0000 },
+  { 0x1900, 0x2963, 0x0000 },
+  { 0x9900, 0x2966, 0x2000 },
+  { 0x1900, 0x2965, 0x0000 },
+  { 0x1900, 0x2967, 0x0000 },
+  { 0x9900, 0x296c, 0x3000 },
+  { 0x9900, 0x296a, 0x2000 },
+  { 0x1900, 0x2969, 0x0000 },
+  { 0x1900, 0x296b, 0x0000 },
+  { 0x9900, 0x296e, 0x2000 },
+  { 0x1900, 0x296d, 0x0000 },
+  { 0x1900, 0x296f, 0x0000 },
+  { 0x9900, 0x2978, 0x4000 },
+  { 0x9900, 0x2974, 0x3000 },
+  { 0x9900, 0x2972, 0x2000 },
+  { 0x1900, 0x2971, 0x0000 },
+  { 0x1900, 0x2973, 0x0000 },
+  { 0x9900, 0x2976, 0x2000 },
+  { 0x1900, 0x2975, 0x0000 },
+  { 0x1900, 0x2977, 0x0000 },
+  { 0x9900, 0x297c, 0x3000 },
+  { 0x9900, 0x297a, 0x2000 },
+  { 0x1900, 0x2979, 0x0000 },
+  { 0x1900, 0x297b, 0x0000 },
+  { 0x9900, 0x297e, 0x2000 },
+  { 0x1900, 0x297d, 0x0000 },
+  { 0x1900, 0x297f, 0x0000 },
+  { 0x9200, 0x2990, 0x5000 },
+  { 0x9200, 0x2988, 0x4000 },
+  { 0x9200, 0x2984, 0x3000 },
+  { 0x9900, 0x2982, 0x2000 },
+  { 0x1900, 0x2981, 0x0000 },
+  { 0x1600, 0x2983, 0x0000 },
+  { 0x9200, 0x2986, 0x2000 },
+  { 0x1600, 0x2985, 0x0000 },
+  { 0x1600, 0x2987, 0x0000 },
+  { 0x9200, 0x298c, 0x3000 },
+  { 0x9200, 0x298a, 0x2000 },
+  { 0x1600, 0x2989, 0x0000 },
+  { 0x1600, 0x298b, 0x0000 },
+  { 0x9200, 0x298e, 0x2000 },
+  { 0x1600, 0x298d, 0x0000 },
+  { 0x1600, 0x298f, 0x0000 },
+  { 0x9200, 0x2998, 0x4000 },
+  { 0x9200, 0x2994, 0x3000 },
+  { 0x9200, 0x2992, 0x2000 },
+  { 0x1600, 0x2991, 0x0000 },
+  { 0x1600, 0x2993, 0x0000 },
+  { 0x9200, 0x2996, 0x2000 },
+  { 0x1600, 0x2995, 0x0000 },
+  { 0x1600, 0x2997, 0x0000 },
+  { 0x9900, 0x299c, 0x3000 },
+  { 0x9900, 0x299a, 0x2000 },
+  { 0x1900, 0x2999, 0x0000 },
+  { 0x1900, 0x299b, 0x0000 },
+  { 0x9900, 0x299e, 0x2000 },
+  { 0x1900, 0x299d, 0x0000 },
+  { 0x1900, 0x299f, 0x0000 },
+  { 0x9900, 0x2aa0, 0x9000 },
+  { 0x9900, 0x2a20, 0x8000 },
+  { 0x9900, 0x29e0, 0x7000 },
+  { 0x9900, 0x29c0, 0x6000 },
+  { 0x9900, 0x29b0, 0x5000 },
+  { 0x9900, 0x29a8, 0x4000 },
+  { 0x9900, 0x29a4, 0x3000 },
+  { 0x9900, 0x29a2, 0x2000 },
+  { 0x1900, 0x29a1, 0x0000 },
+  { 0x1900, 0x29a3, 0x0000 },
+  { 0x9900, 0x29a6, 0x2000 },
+  { 0x1900, 0x29a5, 0x0000 },
+  { 0x1900, 0x29a7, 0x0000 },
+  { 0x9900, 0x29ac, 0x3000 },
+  { 0x9900, 0x29aa, 0x2000 },
+  { 0x1900, 0x29a9, 0x0000 },
+  { 0x1900, 0x29ab, 0x0000 },
+  { 0x9900, 0x29ae, 0x2000 },
+  { 0x1900, 0x29ad, 0x0000 },
+  { 0x1900, 0x29af, 0x0000 },
+  { 0x9900, 0x29b8, 0x4000 },
+  { 0x9900, 0x29b4, 0x3000 },
+  { 0x9900, 0x29b2, 0x2000 },
+  { 0x1900, 0x29b1, 0x0000 },
+  { 0x1900, 0x29b3, 0x0000 },
+  { 0x9900, 0x29b6, 0x2000 },
+  { 0x1900, 0x29b5, 0x0000 },
+  { 0x1900, 0x29b7, 0x0000 },
+  { 0x9900, 0x29bc, 0x3000 },
+  { 0x9900, 0x29ba, 0x2000 },
+  { 0x1900, 0x29b9, 0x0000 },
+  { 0x1900, 0x29bb, 0x0000 },
+  { 0x9900, 0x29be, 0x2000 },
+  { 0x1900, 0x29bd, 0x0000 },
+  { 0x1900, 0x29bf, 0x0000 },
+  { 0x9900, 0x29d0, 0x5000 },
+  { 0x9900, 0x29c8, 0x4000 },
+  { 0x9900, 0x29c4, 0x3000 },
+  { 0x9900, 0x29c2, 0x2000 },
+  { 0x1900, 0x29c1, 0x0000 },
+  { 0x1900, 0x29c3, 0x0000 },
+  { 0x9900, 0x29c6, 0x2000 },
+  { 0x1900, 0x29c5, 0x0000 },
+  { 0x1900, 0x29c7, 0x0000 },
+  { 0x9900, 0x29cc, 0x3000 },
+  { 0x9900, 0x29ca, 0x2000 },
+  { 0x1900, 0x29c9, 0x0000 },
+  { 0x1900, 0x29cb, 0x0000 },
+  { 0x9900, 0x29ce, 0x2000 },
+  { 0x1900, 0x29cd, 0x0000 },
+  { 0x1900, 0x29cf, 0x0000 },
+  { 0x9600, 0x29d8, 0x4000 },
+  { 0x9900, 0x29d4, 0x3000 },
+  { 0x9900, 0x29d2, 0x2000 },
+  { 0x1900, 0x29d1, 0x0000 },
+  { 0x1900, 0x29d3, 0x0000 },
+  { 0x9900, 0x29d6, 0x2000 },
+  { 0x1900, 0x29d5, 0x0000 },
+  { 0x1900, 0x29d7, 0x0000 },
+  { 0x9900, 0x29dc, 0x3000 },
+  { 0x9600, 0x29da, 0x2000 },
+  { 0x1200, 0x29d9, 0x0000 },
+  { 0x1200, 0x29db, 0x0000 },
+  { 0x9900, 0x29de, 0x2000 },
+  { 0x1900, 0x29dd, 0x0000 },
+  { 0x1900, 0x29df, 0x0000 },
+  { 0x9900, 0x2a00, 0x6000 },
+  { 0x9900, 0x29f0, 0x5000 },
+  { 0x9900, 0x29e8, 0x4000 },
+  { 0x9900, 0x29e4, 0x3000 },
+  { 0x9900, 0x29e2, 0x2000 },
+  { 0x1900, 0x29e1, 0x0000 },
+  { 0x1900, 0x29e3, 0x0000 },
+  { 0x9900, 0x29e6, 0x2000 },
+  { 0x1900, 0x29e5, 0x0000 },
+  { 0x1900, 0x29e7, 0x0000 },
+  { 0x9900, 0x29ec, 0x3000 },
+  { 0x9900, 0x29ea, 0x2000 },
+  { 0x1900, 0x29e9, 0x0000 },
+  { 0x1900, 0x29eb, 0x0000 },
+  { 0x9900, 0x29ee, 0x2000 },
+  { 0x1900, 0x29ed, 0x0000 },
+  { 0x1900, 0x29ef, 0x0000 },
+  { 0x9900, 0x29f8, 0x4000 },
+  { 0x9900, 0x29f4, 0x3000 },
+  { 0x9900, 0x29f2, 0x2000 },
+  { 0x1900, 0x29f1, 0x0000 },
+  { 0x1900, 0x29f3, 0x0000 },
+  { 0x9900, 0x29f6, 0x2000 },
+  { 0x1900, 0x29f5, 0x0000 },
+  { 0x1900, 0x29f7, 0x0000 },
+  { 0x9600, 0x29fc, 0x3000 },
+  { 0x9900, 0x29fa, 0x2000 },
+  { 0x1900, 0x29f9, 0x0000 },
+  { 0x1900, 0x29fb, 0x0000 },
+  { 0x9900, 0x29fe, 0x2000 },
+  { 0x1200, 0x29fd, 0x0000 },
+  { 0x1900, 0x29ff, 0x0000 },
+  { 0x9900, 0x2a10, 0x5000 },
+  { 0x9900, 0x2a08, 0x4000 },
+  { 0x9900, 0x2a04, 0x3000 },
+  { 0x9900, 0x2a02, 0x2000 },
+  { 0x1900, 0x2a01, 0x0000 },
+  { 0x1900, 0x2a03, 0x0000 },
+  { 0x9900, 0x2a06, 0x2000 },
+  { 0x1900, 0x2a05, 0x0000 },
+  { 0x1900, 0x2a07, 0x0000 },
+  { 0x9900, 0x2a0c, 0x3000 },
+  { 0x9900, 0x2a0a, 0x2000 },
+  { 0x1900, 0x2a09, 0x0000 },
+  { 0x1900, 0x2a0b, 0x0000 },
+  { 0x9900, 0x2a0e, 0x2000 },
+  { 0x1900, 0x2a0d, 0x0000 },
+  { 0x1900, 0x2a0f, 0x0000 },
+  { 0x9900, 0x2a18, 0x4000 },
+  { 0x9900, 0x2a14, 0x3000 },
+  { 0x9900, 0x2a12, 0x2000 },
+  { 0x1900, 0x2a11, 0x0000 },
+  { 0x1900, 0x2a13, 0x0000 },
+  { 0x9900, 0x2a16, 0x2000 },
+  { 0x1900, 0x2a15, 0x0000 },
+  { 0x1900, 0x2a17, 0x0000 },
+  { 0x9900, 0x2a1c, 0x3000 },
+  { 0x9900, 0x2a1a, 0x2000 },
+  { 0x1900, 0x2a19, 0x0000 },
+  { 0x1900, 0x2a1b, 0x0000 },
+  { 0x9900, 0x2a1e, 0x2000 },
+  { 0x1900, 0x2a1d, 0x0000 },
+  { 0x1900, 0x2a1f, 0x0000 },
+  { 0x9900, 0x2a60, 0x7000 },
+  { 0x9900, 0x2a40, 0x6000 },
+  { 0x9900, 0x2a30, 0x5000 },
+  { 0x9900, 0x2a28, 0x4000 },
+  { 0x9900, 0x2a24, 0x3000 },
+  { 0x9900, 0x2a22, 0x2000 },
+  { 0x1900, 0x2a21, 0x0000 },
+  { 0x1900, 0x2a23, 0x0000 },
+  { 0x9900, 0x2a26, 0x2000 },
+  { 0x1900, 0x2a25, 0x0000 },
+  { 0x1900, 0x2a27, 0x0000 },
+  { 0x9900, 0x2a2c, 0x3000 },
+  { 0x9900, 0x2a2a, 0x2000 },
+  { 0x1900, 0x2a29, 0x0000 },
+  { 0x1900, 0x2a2b, 0x0000 },
+  { 0x9900, 0x2a2e, 0x2000 },
+  { 0x1900, 0x2a2d, 0x0000 },
+  { 0x1900, 0x2a2f, 0x0000 },
+  { 0x9900, 0x2a38, 0x4000 },
+  { 0x9900, 0x2a34, 0x3000 },
+  { 0x9900, 0x2a32, 0x2000 },
+  { 0x1900, 0x2a31, 0x0000 },
+  { 0x1900, 0x2a33, 0x0000 },
+  { 0x9900, 0x2a36, 0x2000 },
+  { 0x1900, 0x2a35, 0x0000 },
+  { 0x1900, 0x2a37, 0x0000 },
+  { 0x9900, 0x2a3c, 0x3000 },
+  { 0x9900, 0x2a3a, 0x2000 },
+  { 0x1900, 0x2a39, 0x0000 },
+  { 0x1900, 0x2a3b, 0x0000 },
+  { 0x9900, 0x2a3e, 0x2000 },
+  { 0x1900, 0x2a3d, 0x0000 },
+  { 0x1900, 0x2a3f, 0x0000 },
+  { 0x9900, 0x2a50, 0x5000 },
+  { 0x9900, 0x2a48, 0x4000 },
+  { 0x9900, 0x2a44, 0x3000 },
+  { 0x9900, 0x2a42, 0x2000 },
+  { 0x1900, 0x2a41, 0x0000 },
+  { 0x1900, 0x2a43, 0x0000 },
+  { 0x9900, 0x2a46, 0x2000 },
+  { 0x1900, 0x2a45, 0x0000 },
+  { 0x1900, 0x2a47, 0x0000 },
+  { 0x9900, 0x2a4c, 0x3000 },
+  { 0x9900, 0x2a4a, 0x2000 },
+  { 0x1900, 0x2a49, 0x0000 },
+  { 0x1900, 0x2a4b, 0x0000 },
+  { 0x9900, 0x2a4e, 0x2000 },
+  { 0x1900, 0x2a4d, 0x0000 },
+  { 0x1900, 0x2a4f, 0x0000 },
+  { 0x9900, 0x2a58, 0x4000 },
+  { 0x9900, 0x2a54, 0x3000 },
+  { 0x9900, 0x2a52, 0x2000 },
+  { 0x1900, 0x2a51, 0x0000 },
+  { 0x1900, 0x2a53, 0x0000 },
+  { 0x9900, 0x2a56, 0x2000 },
+  { 0x1900, 0x2a55, 0x0000 },
+  { 0x1900, 0x2a57, 0x0000 },
+  { 0x9900, 0x2a5c, 0x3000 },
+  { 0x9900, 0x2a5a, 0x2000 },
+  { 0x1900, 0x2a59, 0x0000 },
+  { 0x1900, 0x2a5b, 0x0000 },
+  { 0x9900, 0x2a5e, 0x2000 },
+  { 0x1900, 0x2a5d, 0x0000 },
+  { 0x1900, 0x2a5f, 0x0000 },
+  { 0x9900, 0x2a80, 0x6000 },
+  { 0x9900, 0x2a70, 0x5000 },
+  { 0x9900, 0x2a68, 0x4000 },
+  { 0x9900, 0x2a64, 0x3000 },
+  { 0x9900, 0x2a62, 0x2000 },
+  { 0x1900, 0x2a61, 0x0000 },
+  { 0x1900, 0x2a63, 0x0000 },
+  { 0x9900, 0x2a66, 0x2000 },
+  { 0x1900, 0x2a65, 0x0000 },
+  { 0x1900, 0x2a67, 0x0000 },
+  { 0x9900, 0x2a6c, 0x3000 },
+  { 0x9900, 0x2a6a, 0x2000 },
+  { 0x1900, 0x2a69, 0x0000 },
+  { 0x1900, 0x2a6b, 0x0000 },
+  { 0x9900, 0x2a6e, 0x2000 },
+  { 0x1900, 0x2a6d, 0x0000 },
+  { 0x1900, 0x2a6f, 0x0000 },
+  { 0x9900, 0x2a78, 0x4000 },
+  { 0x9900, 0x2a74, 0x3000 },
+  { 0x9900, 0x2a72, 0x2000 },
+  { 0x1900, 0x2a71, 0x0000 },
+  { 0x1900, 0x2a73, 0x0000 },
+  { 0x9900, 0x2a76, 0x2000 },
+  { 0x1900, 0x2a75, 0x0000 },
+  { 0x1900, 0x2a77, 0x0000 },
+  { 0x9900, 0x2a7c, 0x3000 },
+  { 0x9900, 0x2a7a, 0x2000 },
+  { 0x1900, 0x2a79, 0x0000 },
+  { 0x1900, 0x2a7b, 0x0000 },
+  { 0x9900, 0x2a7e, 0x2000 },
+  { 0x1900, 0x2a7d, 0x0000 },
+  { 0x1900, 0x2a7f, 0x0000 },
+  { 0x9900, 0x2a90, 0x5000 },
+  { 0x9900, 0x2a88, 0x4000 },
+  { 0x9900, 0x2a84, 0x3000 },
+  { 0x9900, 0x2a82, 0x2000 },
+  { 0x1900, 0x2a81, 0x0000 },
+  { 0x1900, 0x2a83, 0x0000 },
+  { 0x9900, 0x2a86, 0x2000 },
+  { 0x1900, 0x2a85, 0x0000 },
+  { 0x1900, 0x2a87, 0x0000 },
+  { 0x9900, 0x2a8c, 0x3000 },
+  { 0x9900, 0x2a8a, 0x2000 },
+  { 0x1900, 0x2a89, 0x0000 },
+  { 0x1900, 0x2a8b, 0x0000 },
+  { 0x9900, 0x2a8e, 0x2000 },
+  { 0x1900, 0x2a8d, 0x0000 },
+  { 0x1900, 0x2a8f, 0x0000 },
+  { 0x9900, 0x2a98, 0x4000 },
+  { 0x9900, 0x2a94, 0x3000 },
+  { 0x9900, 0x2a92, 0x2000 },
+  { 0x1900, 0x2a91, 0x0000 },
+  { 0x1900, 0x2a93, 0x0000 },
+  { 0x9900, 0x2a96, 0x2000 },
+  { 0x1900, 0x2a95, 0x0000 },
+  { 0x1900, 0x2a97, 0x0000 },
+  { 0x9900, 0x2a9c, 0x3000 },
+  { 0x9900, 0x2a9a, 0x2000 },
+  { 0x1900, 0x2a99, 0x0000 },
+  { 0x1900, 0x2a9b, 0x0000 },
+  { 0x9900, 0x2a9e, 0x2000 },
+  { 0x1900, 0x2a9d, 0x0000 },
+  { 0x1900, 0x2a9f, 0x0000 },
+  { 0x9a00, 0x2e92, 0x8000 },
+  { 0x9900, 0x2ae0, 0x7000 },
+  { 0x9900, 0x2ac0, 0x6000 },
+  { 0x9900, 0x2ab0, 0x5000 },
+  { 0x9900, 0x2aa8, 0x4000 },
+  { 0x9900, 0x2aa4, 0x3000 },
+  { 0x9900, 0x2aa2, 0x2000 },
+  { 0x1900, 0x2aa1, 0x0000 },
+  { 0x1900, 0x2aa3, 0x0000 },
+  { 0x9900, 0x2aa6, 0x2000 },
+  { 0x1900, 0x2aa5, 0x0000 },
+  { 0x1900, 0x2aa7, 0x0000 },
+  { 0x9900, 0x2aac, 0x3000 },
+  { 0x9900, 0x2aaa, 0x2000 },
+  { 0x1900, 0x2aa9, 0x0000 },
+  { 0x1900, 0x2aab, 0x0000 },
+  { 0x9900, 0x2aae, 0x2000 },
+  { 0x1900, 0x2aad, 0x0000 },
+  { 0x1900, 0x2aaf, 0x0000 },
+  { 0x9900, 0x2ab8, 0x4000 },
+  { 0x9900, 0x2ab4, 0x3000 },
+  { 0x9900, 0x2ab2, 0x2000 },
+  { 0x1900, 0x2ab1, 0x0000 },
+  { 0x1900, 0x2ab3, 0x0000 },
+  { 0x9900, 0x2ab6, 0x2000 },
+  { 0x1900, 0x2ab5, 0x0000 },
+  { 0x1900, 0x2ab7, 0x0000 },
+  { 0x9900, 0x2abc, 0x3000 },
+  { 0x9900, 0x2aba, 0x2000 },
+  { 0x1900, 0x2ab9, 0x0000 },
+  { 0x1900, 0x2abb, 0x0000 },
+  { 0x9900, 0x2abe, 0x2000 },
+  { 0x1900, 0x2abd, 0x0000 },
+  { 0x1900, 0x2abf, 0x0000 },
+  { 0x9900, 0x2ad0, 0x5000 },
+  { 0x9900, 0x2ac8, 0x4000 },
+  { 0x9900, 0x2ac4, 0x3000 },
+  { 0x9900, 0x2ac2, 0x2000 },
+  { 0x1900, 0x2ac1, 0x0000 },
+  { 0x1900, 0x2ac3, 0x0000 },
+  { 0x9900, 0x2ac6, 0x2000 },
+  { 0x1900, 0x2ac5, 0x0000 },
+  { 0x1900, 0x2ac7, 0x0000 },
+  { 0x9900, 0x2acc, 0x3000 },
+  { 0x9900, 0x2aca, 0x2000 },
+  { 0x1900, 0x2ac9, 0x0000 },
+  { 0x1900, 0x2acb, 0x0000 },
+  { 0x9900, 0x2ace, 0x2000 },
+  { 0x1900, 0x2acd, 0x0000 },
+  { 0x1900, 0x2acf, 0x0000 },
+  { 0x9900, 0x2ad8, 0x4000 },
+  { 0x9900, 0x2ad4, 0x3000 },
+  { 0x9900, 0x2ad2, 0x2000 },
+  { 0x1900, 0x2ad1, 0x0000 },
+  { 0x1900, 0x2ad3, 0x0000 },
+  { 0x9900, 0x2ad6, 0x2000 },
+  { 0x1900, 0x2ad5, 0x0000 },
+  { 0x1900, 0x2ad7, 0x0000 },
+  { 0x9900, 0x2adc, 0x3000 },
+  { 0x9900, 0x2ada, 0x2000 },
+  { 0x1900, 0x2ad9, 0x0000 },
+  { 0x1900, 0x2adb, 0x0000 },
+  { 0x9900, 0x2ade, 0x2000 },
+  { 0x1900, 0x2add, 0x0000 },
+  { 0x1900, 0x2adf, 0x0000 },
+  { 0x9a00, 0x2b00, 0x6000 },
+  { 0x9900, 0x2af0, 0x5000 },
+  { 0x9900, 0x2ae8, 0x4000 },
+  { 0x9900, 0x2ae4, 0x3000 },
+  { 0x9900, 0x2ae2, 0x2000 },
+  { 0x1900, 0x2ae1, 0x0000 },
+  { 0x1900, 0x2ae3, 0x0000 },
+  { 0x9900, 0x2ae6, 0x2000 },
+  { 0x1900, 0x2ae5, 0x0000 },
+  { 0x1900, 0x2ae7, 0x0000 },
+  { 0x9900, 0x2aec, 0x3000 },
+  { 0x9900, 0x2aea, 0x2000 },
+  { 0x1900, 0x2ae9, 0x0000 },
+  { 0x1900, 0x2aeb, 0x0000 },
+  { 0x9900, 0x2aee, 0x2000 },
+  { 0x1900, 0x2aed, 0x0000 },
+  { 0x1900, 0x2aef, 0x0000 },
+  { 0x9900, 0x2af8, 0x4000 },
+  { 0x9900, 0x2af4, 0x3000 },
+  { 0x9900, 0x2af2, 0x2000 },
+  { 0x1900, 0x2af1, 0x0000 },
+  { 0x1900, 0x2af3, 0x0000 },
+  { 0x9900, 0x2af6, 0x2000 },
+  { 0x1900, 0x2af5, 0x0000 },
+  { 0x1900, 0x2af7, 0x0000 },
+  { 0x9900, 0x2afc, 0x3000 },
+  { 0x9900, 0x2afa, 0x2000 },
+  { 0x1900, 0x2af9, 0x0000 },
+  { 0x1900, 0x2afb, 0x0000 },
+  { 0x9900, 0x2afe, 0x2000 },
+  { 0x1900, 0x2afd, 0x0000 },
+  { 0x1900, 0x2aff, 0x0000 },
+  { 0x9a00, 0x2e82, 0x5000 },
+  { 0x9a00, 0x2b08, 0x4000 },
+  { 0x9a00, 0x2b04, 0x3000 },
+  { 0x9a00, 0x2b02, 0x2000 },
+  { 0x1a00, 0x2b01, 0x0000 },
+  { 0x1a00, 0x2b03, 0x0000 },
+  { 0x9a00, 0x2b06, 0x2000 },
+  { 0x1a00, 0x2b05, 0x0000 },
+  { 0x1a00, 0x2b07, 0x0000 },
+  { 0x9a00, 0x2b0c, 0x3000 },
+  { 0x9a00, 0x2b0a, 0x2000 },
+  { 0x1a00, 0x2b09, 0x0000 },
+  { 0x1a00, 0x2b0b, 0x0000 },
+  { 0x9a00, 0x2e80, 0x2000 },
+  { 0x1a00, 0x2b0d, 0x0000 },
+  { 0x1a00, 0x2e81, 0x0000 },
+  { 0x9a00, 0x2e8a, 0x4000 },
+  { 0x9a00, 0x2e86, 0x3000 },
+  { 0x9a00, 0x2e84, 0x2000 },
+  { 0x1a00, 0x2e83, 0x0000 },
+  { 0x1a00, 0x2e85, 0x0000 },
+  { 0x9a00, 0x2e88, 0x2000 },
+  { 0x1a00, 0x2e87, 0x0000 },
+  { 0x1a00, 0x2e89, 0x0000 },
+  { 0x9a00, 0x2e8e, 0x3000 },
+  { 0x9a00, 0x2e8c, 0x2000 },
+  { 0x1a00, 0x2e8b, 0x0000 },
+  { 0x1a00, 0x2e8d, 0x0000 },
+  { 0x9a00, 0x2e90, 0x2000 },
+  { 0x1a00, 0x2e8f, 0x0000 },
+  { 0x1a00, 0x2e91, 0x0000 },
+  { 0x9a00, 0x2ed3, 0x7000 },
+  { 0x9a00, 0x2eb3, 0x6000 },
+  { 0x9a00, 0x2ea3, 0x5000 },
+  { 0x9a00, 0x2e9b, 0x4000 },
+  { 0x9a00, 0x2e96, 0x3000 },
+  { 0x9a00, 0x2e94, 0x2000 },
+  { 0x1a00, 0x2e93, 0x0000 },
+  { 0x1a00, 0x2e95, 0x0000 },
+  { 0x9a00, 0x2e98, 0x2000 },
+  { 0x1a00, 0x2e97, 0x0000 },
+  { 0x1a00, 0x2e99, 0x0000 },
+  { 0x9a00, 0x2e9f, 0x3000 },
+  { 0x9a00, 0x2e9d, 0x2000 },
+  { 0x1a00, 0x2e9c, 0x0000 },
+  { 0x1a00, 0x2e9e, 0x0000 },
+  { 0x9a00, 0x2ea1, 0x2000 },
+  { 0x1a00, 0x2ea0, 0x0000 },
+  { 0x1a00, 0x2ea2, 0x0000 },
+  { 0x9a00, 0x2eab, 0x4000 },
+  { 0x9a00, 0x2ea7, 0x3000 },
+  { 0x9a00, 0x2ea5, 0x2000 },
+  { 0x1a00, 0x2ea4, 0x0000 },
+  { 0x1a00, 0x2ea6, 0x0000 },
+  { 0x9a00, 0x2ea9, 0x2000 },
+  { 0x1a00, 0x2ea8, 0x0000 },
+  { 0x1a00, 0x2eaa, 0x0000 },
+  { 0x9a00, 0x2eaf, 0x3000 },
+  { 0x9a00, 0x2ead, 0x2000 },
+  { 0x1a00, 0x2eac, 0x0000 },
+  { 0x1a00, 0x2eae, 0x0000 },
+  { 0x9a00, 0x2eb1, 0x2000 },
+  { 0x1a00, 0x2eb0, 0x0000 },
+  { 0x1a00, 0x2eb2, 0x0000 },
+  { 0x9a00, 0x2ec3, 0x5000 },
+  { 0x9a00, 0x2ebb, 0x4000 },
+  { 0x9a00, 0x2eb7, 0x3000 },
+  { 0x9a00, 0x2eb5, 0x2000 },
+  { 0x1a00, 0x2eb4, 0x0000 },
+  { 0x1a00, 0x2eb6, 0x0000 },
+  { 0x9a00, 0x2eb9, 0x2000 },
+  { 0x1a00, 0x2eb8, 0x0000 },
+  { 0x1a00, 0x2eba, 0x0000 },
+  { 0x9a00, 0x2ebf, 0x3000 },
+  { 0x9a00, 0x2ebd, 0x2000 },
+  { 0x1a00, 0x2ebc, 0x0000 },
+  { 0x1a00, 0x2ebe, 0x0000 },
+  { 0x9a00, 0x2ec1, 0x2000 },
+  { 0x1a00, 0x2ec0, 0x0000 },
+  { 0x1a00, 0x2ec2, 0x0000 },
+  { 0x9a00, 0x2ecb, 0x4000 },
+  { 0x9a00, 0x2ec7, 0x3000 },
+  { 0x9a00, 0x2ec5, 0x2000 },
+  { 0x1a00, 0x2ec4, 0x0000 },
+  { 0x1a00, 0x2ec6, 0x0000 },
+  { 0x9a00, 0x2ec9, 0x2000 },
+  { 0x1a00, 0x2ec8, 0x0000 },
+  { 0x1a00, 0x2eca, 0x0000 },
+  { 0x9a00, 0x2ecf, 0x3000 },
+  { 0x9a00, 0x2ecd, 0x2000 },
+  { 0x1a00, 0x2ecc, 0x0000 },
+  { 0x1a00, 0x2ece, 0x0000 },
+  { 0x9a00, 0x2ed1, 0x2000 },
+  { 0x1a00, 0x2ed0, 0x0000 },
+  { 0x1a00, 0x2ed2, 0x0000 },
+  { 0x9a00, 0x2ef3, 0x6000 },
+  { 0x9a00, 0x2ee3, 0x5000 },
+  { 0x9a00, 0x2edb, 0x4000 },
+  { 0x9a00, 0x2ed7, 0x3000 },
+  { 0x9a00, 0x2ed5, 0x2000 },
+  { 0x1a00, 0x2ed4, 0x0000 },
+  { 0x1a00, 0x2ed6, 0x0000 },
+  { 0x9a00, 0x2ed9, 0x2000 },
+  { 0x1a00, 0x2ed8, 0x0000 },
+  { 0x1a00, 0x2eda, 0x0000 },
+  { 0x9a00, 0x2edf, 0x3000 },
+  { 0x9a00, 0x2edd, 0x2000 },
+  { 0x1a00, 0x2edc, 0x0000 },
+  { 0x1a00, 0x2ede, 0x0000 },
+  { 0x9a00, 0x2ee1, 0x2000 },
+  { 0x1a00, 0x2ee0, 0x0000 },
+  { 0x1a00, 0x2ee2, 0x0000 },
+  { 0x9a00, 0x2eeb, 0x4000 },
+  { 0x9a00, 0x2ee7, 0x3000 },
+  { 0x9a00, 0x2ee5, 0x2000 },
+  { 0x1a00, 0x2ee4, 0x0000 },
+  { 0x1a00, 0x2ee6, 0x0000 },
+  { 0x9a00, 0x2ee9, 0x2000 },
+  { 0x1a00, 0x2ee8, 0x0000 },
+  { 0x1a00, 0x2eea, 0x0000 },
+  { 0x9a00, 0x2eef, 0x3000 },
+  { 0x9a00, 0x2eed, 0x2000 },
+  { 0x1a00, 0x2eec, 0x0000 },
+  { 0x1a00, 0x2eee, 0x0000 },
+  { 0x9a00, 0x2ef1, 0x2000 },
+  { 0x1a00, 0x2ef0, 0x0000 },
+  { 0x1a00, 0x2ef2, 0x0000 },
+  { 0x9a00, 0x2f0f, 0x5000 },
+  { 0x9a00, 0x2f07, 0x4000 },
+  { 0x9a00, 0x2f03, 0x3000 },
+  { 0x9a00, 0x2f01, 0x2000 },
+  { 0x1a00, 0x2f00, 0x0000 },
+  { 0x1a00, 0x2f02, 0x0000 },
+  { 0x9a00, 0x2f05, 0x2000 },
+  { 0x1a00, 0x2f04, 0x0000 },
+  { 0x1a00, 0x2f06, 0x0000 },
+  { 0x9a00, 0x2f0b, 0x3000 },
+  { 0x9a00, 0x2f09, 0x2000 },
+  { 0x1a00, 0x2f08, 0x0000 },
+  { 0x1a00, 0x2f0a, 0x0000 },
+  { 0x9a00, 0x2f0d, 0x2000 },
+  { 0x1a00, 0x2f0c, 0x0000 },
+  { 0x1a00, 0x2f0e, 0x0000 },
+  { 0x9a00, 0x2f17, 0x4000 },
+  { 0x9a00, 0x2f13, 0x3000 },
+  { 0x9a00, 0x2f11, 0x2000 },
+  { 0x1a00, 0x2f10, 0x0000 },
+  { 0x1a00, 0x2f12, 0x0000 },
+  { 0x9a00, 0x2f15, 0x2000 },
+  { 0x1a00, 0x2f14, 0x0000 },
+  { 0x1a00, 0x2f16, 0x0000 },
+  { 0x9a00, 0x2f1b, 0x3000 },
+  { 0x9a00, 0x2f19, 0x2000 },
+  { 0x1a00, 0x2f18, 0x0000 },
+  { 0x1a00, 0x2f1a, 0x0000 },
+  { 0x9a00, 0x2f1d, 0x2000 },
+  { 0x1a00, 0x2f1c, 0x0000 },
+  { 0x1a00, 0x2f1e, 0x0000 },
+  { 0x8701, 0x00f0, 0xd000 },
+  { 0x8700, 0xa34d, 0xc000 },
+  { 0x9a00, 0x3391, 0xb000 },
+  { 0x8700, 0x3149, 0xa000 },
+  { 0x9500, 0x303d, 0x9000 },
+  { 0x9a00, 0x2f9f, 0x8000 },
+  { 0x9a00, 0x2f5f, 0x7000 },
+  { 0x9a00, 0x2f3f, 0x6000 },
+  { 0x9a00, 0x2f2f, 0x5000 },
+  { 0x9a00, 0x2f27, 0x4000 },
+  { 0x9a00, 0x2f23, 0x3000 },
+  { 0x9a00, 0x2f21, 0x2000 },
+  { 0x1a00, 0x2f20, 0x0000 },
+  { 0x1a00, 0x2f22, 0x0000 },
+  { 0x9a00, 0x2f25, 0x2000 },
+  { 0x1a00, 0x2f24, 0x0000 },
+  { 0x1a00, 0x2f26, 0x0000 },
+  { 0x9a00, 0x2f2b, 0x3000 },
+  { 0x9a00, 0x2f29, 0x2000 },
+  { 0x1a00, 0x2f28, 0x0000 },
+  { 0x1a00, 0x2f2a, 0x0000 },
+  { 0x9a00, 0x2f2d, 0x2000 },
+  { 0x1a00, 0x2f2c, 0x0000 },
+  { 0x1a00, 0x2f2e, 0x0000 },
+  { 0x9a00, 0x2f37, 0x4000 },
+  { 0x9a00, 0x2f33, 0x3000 },
+  { 0x9a00, 0x2f31, 0x2000 },
+  { 0x1a00, 0x2f30, 0x0000 },
+  { 0x1a00, 0x2f32, 0x0000 },
+  { 0x9a00, 0x2f35, 0x2000 },
+  { 0x1a00, 0x2f34, 0x0000 },
+  { 0x1a00, 0x2f36, 0x0000 },
+  { 0x9a00, 0x2f3b, 0x3000 },
+  { 0x9a00, 0x2f39, 0x2000 },
+  { 0x1a00, 0x2f38, 0x0000 },
+  { 0x1a00, 0x2f3a, 0x0000 },
+  { 0x9a00, 0x2f3d, 0x2000 },
+  { 0x1a00, 0x2f3c, 0x0000 },
+  { 0x1a00, 0x2f3e, 0x0000 },
+  { 0x9a00, 0x2f4f, 0x5000 },
+  { 0x9a00, 0x2f47, 0x4000 },
+  { 0x9a00, 0x2f43, 0x3000 },
+  { 0x9a00, 0x2f41, 0x2000 },
+  { 0x1a00, 0x2f40, 0x0000 },
+  { 0x1a00, 0x2f42, 0x0000 },
+  { 0x9a00, 0x2f45, 0x2000 },
+  { 0x1a00, 0x2f44, 0x0000 },
+  { 0x1a00, 0x2f46, 0x0000 },
+  { 0x9a00, 0x2f4b, 0x3000 },
+  { 0x9a00, 0x2f49, 0x2000 },
+  { 0x1a00, 0x2f48, 0x0000 },
+  { 0x1a00, 0x2f4a, 0x0000 },
+  { 0x9a00, 0x2f4d, 0x2000 },
+  { 0x1a00, 0x2f4c, 0x0000 },
+  { 0x1a00, 0x2f4e, 0x0000 },
+  { 0x9a00, 0x2f57, 0x4000 },
+  { 0x9a00, 0x2f53, 0x3000 },
+  { 0x9a00, 0x2f51, 0x2000 },
+  { 0x1a00, 0x2f50, 0x0000 },
+  { 0x1a00, 0x2f52, 0x0000 },
+  { 0x9a00, 0x2f55, 0x2000 },
+  { 0x1a00, 0x2f54, 0x0000 },
+  { 0x1a00, 0x2f56, 0x0000 },
+  { 0x9a00, 0x2f5b, 0x3000 },
+  { 0x9a00, 0x2f59, 0x2000 },
+  { 0x1a00, 0x2f58, 0x0000 },
+  { 0x1a00, 0x2f5a, 0x0000 },
+  { 0x9a00, 0x2f5d, 0x2000 },
+  { 0x1a00, 0x2f5c, 0x0000 },
+  { 0x1a00, 0x2f5e, 0x0000 },
+  { 0x9a00, 0x2f7f, 0x6000 },
+  { 0x9a00, 0x2f6f, 0x5000 },
+  { 0x9a00, 0x2f67, 0x4000 },
+  { 0x9a00, 0x2f63, 0x3000 },
+  { 0x9a00, 0x2f61, 0x2000 },
+  { 0x1a00, 0x2f60, 0x0000 },
+  { 0x1a00, 0x2f62, 0x0000 },
+  { 0x9a00, 0x2f65, 0x2000 },
+  { 0x1a00, 0x2f64, 0x0000 },
+  { 0x1a00, 0x2f66, 0x0000 },
+  { 0x9a00, 0x2f6b, 0x3000 },
+  { 0x9a00, 0x2f69, 0x2000 },
+  { 0x1a00, 0x2f68, 0x0000 },
+  { 0x1a00, 0x2f6a, 0x0000 },
+  { 0x9a00, 0x2f6d, 0x2000 },
+  { 0x1a00, 0x2f6c, 0x0000 },
+  { 0x1a00, 0x2f6e, 0x0000 },
+  { 0x9a00, 0x2f77, 0x4000 },
+  { 0x9a00, 0x2f73, 0x3000 },
+  { 0x9a00, 0x2f71, 0x2000 },
+  { 0x1a00, 0x2f70, 0x0000 },
+  { 0x1a00, 0x2f72, 0x0000 },
+  { 0x9a00, 0x2f75, 0x2000 },
+  { 0x1a00, 0x2f74, 0x0000 },
+  { 0x1a00, 0x2f76, 0x0000 },
+  { 0x9a00, 0x2f7b, 0x3000 },
+  { 0x9a00, 0x2f79, 0x2000 },
+  { 0x1a00, 0x2f78, 0x0000 },
+  { 0x1a00, 0x2f7a, 0x0000 },
+  { 0x9a00, 0x2f7d, 0x2000 },
+  { 0x1a00, 0x2f7c, 0x0000 },
+  { 0x1a00, 0x2f7e, 0x0000 },
+  { 0x9a00, 0x2f8f, 0x5000 },
+  { 0x9a00, 0x2f87, 0x4000 },
+  { 0x9a00, 0x2f83, 0x3000 },
+  { 0x9a00, 0x2f81, 0x2000 },
+  { 0x1a00, 0x2f80, 0x0000 },
+  { 0x1a00, 0x2f82, 0x0000 },
+  { 0x9a00, 0x2f85, 0x2000 },
+  { 0x1a00, 0x2f84, 0x0000 },
+  { 0x1a00, 0x2f86, 0x0000 },
+  { 0x9a00, 0x2f8b, 0x3000 },
+  { 0x9a00, 0x2f89, 0x2000 },
+  { 0x1a00, 0x2f88, 0x0000 },
+  { 0x1a00, 0x2f8a, 0x0000 },
+  { 0x9a00, 0x2f8d, 0x2000 },
+  { 0x1a00, 0x2f8c, 0x0000 },
+  { 0x1a00, 0x2f8e, 0x0000 },
+  { 0x9a00, 0x2f97, 0x4000 },
+  { 0x9a00, 0x2f93, 0x3000 },
+  { 0x9a00, 0x2f91, 0x2000 },
+  { 0x1a00, 0x2f90, 0x0000 },
+  { 0x1a00, 0x2f92, 0x0000 },
+  { 0x9a00, 0x2f95, 0x2000 },
+  { 0x1a00, 0x2f94, 0x0000 },
+  { 0x1a00, 0x2f96, 0x0000 },
+  { 0x9a00, 0x2f9b, 0x3000 },
+  { 0x9a00, 0x2f99, 0x2000 },
+  { 0x1a00, 0x2f98, 0x0000 },
+  { 0x1a00, 0x2f9a, 0x0000 },
+  { 0x9a00, 0x2f9d, 0x2000 },
+  { 0x1a00, 0x2f9c, 0x0000 },
+  { 0x1a00, 0x2f9e, 0x0000 },
+  { 0x9a00, 0x2ff9, 0x7000 },
+  { 0x9a00, 0x2fbf, 0x6000 },
+  { 0x9a00, 0x2faf, 0x5000 },
+  { 0x9a00, 0x2fa7, 0x4000 },
+  { 0x9a00, 0x2fa3, 0x3000 },
+  { 0x9a00, 0x2fa1, 0x2000 },
+  { 0x1a00, 0x2fa0, 0x0000 },
+  { 0x1a00, 0x2fa2, 0x0000 },
+  { 0x9a00, 0x2fa5, 0x2000 },
+  { 0x1a00, 0x2fa4, 0x0000 },
+  { 0x1a00, 0x2fa6, 0x0000 },
+  { 0x9a00, 0x2fab, 0x3000 },
+  { 0x9a00, 0x2fa9, 0x2000 },
+  { 0x1a00, 0x2fa8, 0x0000 },
+  { 0x1a00, 0x2faa, 0x0000 },
+  { 0x9a00, 0x2fad, 0x2000 },
+  { 0x1a00, 0x2fac, 0x0000 },
+  { 0x1a00, 0x2fae, 0x0000 },
+  { 0x9a00, 0x2fb7, 0x4000 },
+  { 0x9a00, 0x2fb3, 0x3000 },
+  { 0x9a00, 0x2fb1, 0x2000 },
+  { 0x1a00, 0x2fb0, 0x0000 },
+  { 0x1a00, 0x2fb2, 0x0000 },
+  { 0x9a00, 0x2fb5, 0x2000 },
+  { 0x1a00, 0x2fb4, 0x0000 },
+  { 0x1a00, 0x2fb6, 0x0000 },
+  { 0x9a00, 0x2fbb, 0x3000 },
+  { 0x9a00, 0x2fb9, 0x2000 },
+  { 0x1a00, 0x2fb8, 0x0000 },
+  { 0x1a00, 0x2fba, 0x0000 },
+  { 0x9a00, 0x2fbd, 0x2000 },
+  { 0x1a00, 0x2fbc, 0x0000 },
+  { 0x1a00, 0x2fbe, 0x0000 },
+  { 0x9a00, 0x2fcf, 0x5000 },
+  { 0x9a00, 0x2fc7, 0x4000 },
+  { 0x9a00, 0x2fc3, 0x3000 },
+  { 0x9a00, 0x2fc1, 0x2000 },
+  { 0x1a00, 0x2fc0, 0x0000 },
+  { 0x1a00, 0x2fc2, 0x0000 },
+  { 0x9a00, 0x2fc5, 0x2000 },
+  { 0x1a00, 0x2fc4, 0x0000 },
+  { 0x1a00, 0x2fc6, 0x0000 },
+  { 0x9a00, 0x2fcb, 0x3000 },
+  { 0x9a00, 0x2fc9, 0x2000 },
+  { 0x1a00, 0x2fc8, 0x0000 },
+  { 0x1a00, 0x2fca, 0x0000 },
+  { 0x9a00, 0x2fcd, 0x2000 },
+  { 0x1a00, 0x2fcc, 0x0000 },
+  { 0x1a00, 0x2fce, 0x0000 },
+  { 0x9a00, 0x2ff1, 0x4000 },
+  { 0x9a00, 0x2fd3, 0x3000 },
+  { 0x9a00, 0x2fd1, 0x2000 },
+  { 0x1a00, 0x2fd0, 0x0000 },
+  { 0x1a00, 0x2fd2, 0x0000 },
+  { 0x9a00, 0x2fd5, 0x2000 },
+  { 0x1a00, 0x2fd4, 0x0000 },
+  { 0x1a00, 0x2ff0, 0x0000 },
+  { 0x9a00, 0x2ff5, 0x3000 },
+  { 0x9a00, 0x2ff3, 0x2000 },
+  { 0x1a00, 0x2ff2, 0x0000 },
+  { 0x1a00, 0x2ff4, 0x0000 },
+  { 0x9a00, 0x2ff7, 0x2000 },
+  { 0x1a00, 0x2ff6, 0x0000 },
+  { 0x1a00, 0x2ff8, 0x0000 },
+  { 0x9600, 0x301d, 0x6000 },
+  { 0x9200, 0x300d, 0x5000 },
+  { 0x8600, 0x3005, 0x4000 },
+  { 0x9500, 0x3001, 0x3000 },
+  { 0x9a00, 0x2ffb, 0x2000 },
+  { 0x1a00, 0x2ffa, 0x0000 },
+  { 0x1d00, 0x3000, 0x0000 },
+  { 0x9500, 0x3003, 0x2000 },
+  { 0x1500, 0x3002, 0x0000 },
+  { 0x1a00, 0x3004, 0x0000 },
+  { 0x9200, 0x3009, 0x3000 },
+  { 0x8e00, 0x3007, 0x2000 },
+  { 0x0700, 0x3006, 0x0000 },
+  { 0x1600, 0x3008, 0x0000 },
+  { 0x9200, 0x300b, 0x2000 },
+  { 0x1600, 0x300a, 0x0000 },
+  { 0x1600, 0x300c, 0x0000 },
+  { 0x9200, 0x3015, 0x4000 },
+  { 0x9200, 0x3011, 0x3000 },
+  { 0x9200, 0x300f, 0x2000 },
+  { 0x1600, 0x300e, 0x0000 },
+  { 0x1600, 0x3010, 0x0000 },
+  { 0x9a00, 0x3013, 0x2000 },
+  { 0x1a00, 0x3012, 0x0000 },
+  { 0x1600, 0x3014, 0x0000 },
+  { 0x9200, 0x3019, 0x3000 },
+  { 0x9200, 0x3017, 0x2000 },
+  { 0x1600, 0x3016, 0x0000 },
+  { 0x1600, 0x3018, 0x0000 },
+  { 0x9200, 0x301b, 0x2000 },
+  { 0x1600, 0x301a, 0x0000 },
+  { 0x1100, 0x301c, 0x0000 },
+  { 0x8c00, 0x302d, 0x5000 },
+  { 0x8e00, 0x3025, 0x4000 },
+  { 0x8e00, 0x3021, 0x3000 },
+  { 0x9200, 0x301f, 0x2000 },
+  { 0x1200, 0x301e, 0x0000 },
+  { 0x1a00, 0x3020, 0x0000 },
+  { 0x8e00, 0x3023, 0x2000 },
+  { 0x0e00, 0x3022, 0x0000 },
+  { 0x0e00, 0x3024, 0x0000 },
+  { 0x8e00, 0x3029, 0x3000 },
+  { 0x8e00, 0x3027, 0x2000 },
+  { 0x0e00, 0x3026, 0x0000 },
+  { 0x0e00, 0x3028, 0x0000 },
+  { 0x8c00, 0x302b, 0x2000 },
+  { 0x0c00, 0x302a, 0x0000 },
+  { 0x0c00, 0x302c, 0x0000 },
+  { 0x8600, 0x3035, 0x4000 },
+  { 0x8600, 0x3031, 0x3000 },
+  { 0x8c00, 0x302f, 0x2000 },
+  { 0x0c00, 0x302e, 0x0000 },
+  { 0x1100, 0x3030, 0x0000 },
+  { 0x8600, 0x3033, 0x2000 },
+  { 0x0600, 0x3032, 0x0000 },
+  { 0x0600, 0x3034, 0x0000 },
+  { 0x8e00, 0x3039, 0x3000 },
+  { 0x9a00, 0x3037, 0x2000 },
+  { 0x1a00, 0x3036, 0x0000 },
+  { 0x0e00, 0x3038, 0x0000 },
+  { 0x8600, 0x303b, 0x2000 },
+  { 0x0e00, 0x303a, 0x0000 },
+  { 0x0700, 0x303c, 0x0000 },
+  { 0x8700, 0x30c0, 0x8000 },
+  { 0x8700, 0x307e, 0x7000 },
+  { 0x8700, 0x305e, 0x6000 },
+  { 0x8700, 0x304e, 0x5000 },
+  { 0x8700, 0x3046, 0x4000 },
+  { 0x8700, 0x3042, 0x3000 },
+  { 0x9a00, 0x303f, 0x2000 },
+  { 0x1a00, 0x303e, 0x0000 },
+  { 0x0700, 0x3041, 0x0000 },
+  { 0x8700, 0x3044, 0x2000 },
+  { 0x0700, 0x3043, 0x0000 },
+  { 0x0700, 0x3045, 0x0000 },
+  { 0x8700, 0x304a, 0x3000 },
+  { 0x8700, 0x3048, 0x2000 },
+  { 0x0700, 0x3047, 0x0000 },
+  { 0x0700, 0x3049, 0x0000 },
+  { 0x8700, 0x304c, 0x2000 },
+  { 0x0700, 0x304b, 0x0000 },
+  { 0x0700, 0x304d, 0x0000 },
+  { 0x8700, 0x3056, 0x4000 },
+  { 0x8700, 0x3052, 0x3000 },
+  { 0x8700, 0x3050, 0x2000 },
+  { 0x0700, 0x304f, 0x0000 },
+  { 0x0700, 0x3051, 0x0000 },
+  { 0x8700, 0x3054, 0x2000 },
+  { 0x0700, 0x3053, 0x0000 },
+  { 0x0700, 0x3055, 0x0000 },
+  { 0x8700, 0x305a, 0x3000 },
+  { 0x8700, 0x3058, 0x2000 },
+  { 0x0700, 0x3057, 0x0000 },
+  { 0x0700, 0x3059, 0x0000 },
+  { 0x8700, 0x305c, 0x2000 },
+  { 0x0700, 0x305b, 0x0000 },
+  { 0x0700, 0x305d, 0x0000 },
+  { 0x8700, 0x306e, 0x5000 },
+  { 0x8700, 0x3066, 0x4000 },
+  { 0x8700, 0x3062, 0x3000 },
+  { 0x8700, 0x3060, 0x2000 },
+  { 0x0700, 0x305f, 0x0000 },
+  { 0x0700, 0x3061, 0x0000 },
+  { 0x8700, 0x3064, 0x2000 },
+  { 0x0700, 0x3063, 0x0000 },
+  { 0x0700, 0x3065, 0x0000 },
+  { 0x8700, 0x306a, 0x3000 },
+  { 0x8700, 0x3068, 0x2000 },
+  { 0x0700, 0x3067, 0x0000 },
+  { 0x0700, 0x3069, 0x0000 },
+  { 0x8700, 0x306c, 0x2000 },
+  { 0x0700, 0x306b, 0x0000 },
+  { 0x0700, 0x306d, 0x0000 },
+  { 0x8700, 0x3076, 0x4000 },
+  { 0x8700, 0x3072, 0x3000 },
+  { 0x8700, 0x3070, 0x2000 },
+  { 0x0700, 0x306f, 0x0000 },
+  { 0x0700, 0x3071, 0x0000 },
+  { 0x8700, 0x3074, 0x2000 },
+  { 0x0700, 0x3073, 0x0000 },
+  { 0x0700, 0x3075, 0x0000 },
+  { 0x8700, 0x307a, 0x3000 },
+  { 0x8700, 0x3078, 0x2000 },
+  { 0x0700, 0x3077, 0x0000 },
+  { 0x0700, 0x3079, 0x0000 },
+  { 0x8700, 0x307c, 0x2000 },
+  { 0x0700, 0x307b, 0x0000 },
+  { 0x0700, 0x307d, 0x0000 },
+  { 0x9100, 0x30a0, 0x6000 },
+  { 0x8700, 0x308e, 0x5000 },
+  { 0x8700, 0x3086, 0x4000 },
+  { 0x8700, 0x3082, 0x3000 },
+  { 0x8700, 0x3080, 0x2000 },
+  { 0x0700, 0x307f, 0x0000 },
+  { 0x0700, 0x3081, 0x0000 },
+  { 0x8700, 0x3084, 0x2000 },
+  { 0x0700, 0x3083, 0x0000 },
+  { 0x0700, 0x3085, 0x0000 },
+  { 0x8700, 0x308a, 0x3000 },
+  { 0x8700, 0x3088, 0x2000 },
+  { 0x0700, 0x3087, 0x0000 },
+  { 0x0700, 0x3089, 0x0000 },
+  { 0x8700, 0x308c, 0x2000 },
+  { 0x0700, 0x308b, 0x0000 },
+  { 0x0700, 0x308d, 0x0000 },
+  { 0x8700, 0x3096, 0x4000 },
+  { 0x8700, 0x3092, 0x3000 },
+  { 0x8700, 0x3090, 0x2000 },
+  { 0x0700, 0x308f, 0x0000 },
+  { 0x0700, 0x3091, 0x0000 },
+  { 0x8700, 0x3094, 0x2000 },
+  { 0x0700, 0x3093, 0x0000 },
+  { 0x0700, 0x3095, 0x0000 },
+  { 0x9800, 0x309c, 0x3000 },
+  { 0x8c00, 0x309a, 0x2000 },
+  { 0x0c00, 0x3099, 0x0000 },
+  { 0x1800, 0x309b, 0x0000 },
+  { 0x8600, 0x309e, 0x2000 },
+  { 0x0600, 0x309d, 0x0000 },
+  { 0x0700, 0x309f, 0x0000 },
+  { 0x8700, 0x30b0, 0x5000 },
+  { 0x8700, 0x30a8, 0x4000 },
+  { 0x8700, 0x30a4, 0x3000 },
+  { 0x8700, 0x30a2, 0x2000 },
+  { 0x0700, 0x30a1, 0x0000 },
+  { 0x0700, 0x30a3, 0x0000 },
+  { 0x8700, 0x30a6, 0x2000 },
+  { 0x0700, 0x30a5, 0x0000 },
+  { 0x0700, 0x30a7, 0x0000 },
+  { 0x8700, 0x30ac, 0x3000 },
+  { 0x8700, 0x30aa, 0x2000 },
+  { 0x0700, 0x30a9, 0x0000 },
+  { 0x0700, 0x30ab, 0x0000 },
+  { 0x8700, 0x30ae, 0x2000 },
+  { 0x0700, 0x30ad, 0x0000 },
+  { 0x0700, 0x30af, 0x0000 },
+  { 0x8700, 0x30b8, 0x4000 },
+  { 0x8700, 0x30b4, 0x3000 },
+  { 0x8700, 0x30b2, 0x2000 },
+  { 0x0700, 0x30b1, 0x0000 },
+  { 0x0700, 0x30b3, 0x0000 },
+  { 0x8700, 0x30b6, 0x2000 },
+  { 0x0700, 0x30b5, 0x0000 },
+  { 0x0700, 0x30b7, 0x0000 },
+  { 0x8700, 0x30bc, 0x3000 },
+  { 0x8700, 0x30ba, 0x2000 },
+  { 0x0700, 0x30b9, 0x0000 },
+  { 0x0700, 0x30bb, 0x0000 },
+  { 0x8700, 0x30be, 0x2000 },
+  { 0x0700, 0x30bd, 0x0000 },
+  { 0x0700, 0x30bf, 0x0000 },
+  { 0x8700, 0x3105, 0x7000 },
+  { 0x8700, 0x30e0, 0x6000 },
+  { 0x8700, 0x30d0, 0x5000 },
+  { 0x8700, 0x30c8, 0x4000 },
+  { 0x8700, 0x30c4, 0x3000 },
+  { 0x8700, 0x30c2, 0x2000 },
+  { 0x0700, 0x30c1, 0x0000 },
+  { 0x0700, 0x30c3, 0x0000 },
+  { 0x8700, 0x30c6, 0x2000 },
+  { 0x0700, 0x30c5, 0x0000 },
+  { 0x0700, 0x30c7, 0x0000 },
+  { 0x8700, 0x30cc, 0x3000 },
+  { 0x8700, 0x30ca, 0x2000 },
+  { 0x0700, 0x30c9, 0x0000 },
+  { 0x0700, 0x30cb, 0x0000 },
+  { 0x8700, 0x30ce, 0x2000 },
+  { 0x0700, 0x30cd, 0x0000 },
+  { 0x0700, 0x30cf, 0x0000 },
+  { 0x8700, 0x30d8, 0x4000 },
+  { 0x8700, 0x30d4, 0x3000 },
+  { 0x8700, 0x30d2, 0x2000 },
+  { 0x0700, 0x30d1, 0x0000 },
+  { 0x0700, 0x30d3, 0x0000 },
+  { 0x8700, 0x30d6, 0x2000 },
+  { 0x0700, 0x30d5, 0x0000 },
+  { 0x0700, 0x30d7, 0x0000 },
+  { 0x8700, 0x30dc, 0x3000 },
+  { 0x8700, 0x30da, 0x2000 },
+  { 0x0700, 0x30d9, 0x0000 },
+  { 0x0700, 0x30db, 0x0000 },
+  { 0x8700, 0x30de, 0x2000 },
+  { 0x0700, 0x30dd, 0x0000 },
+  { 0x0700, 0x30df, 0x0000 },
+  { 0x8700, 0x30f0, 0x5000 },
+  { 0x8700, 0x30e8, 0x4000 },
+  { 0x8700, 0x30e4, 0x3000 },
+  { 0x8700, 0x30e2, 0x2000 },
+  { 0x0700, 0x30e1, 0x0000 },
+  { 0x0700, 0x30e3, 0x0000 },
+  { 0x8700, 0x30e6, 0x2000 },
+  { 0x0700, 0x30e5, 0x0000 },
+  { 0x0700, 0x30e7, 0x0000 },
+  { 0x8700, 0x30ec, 0x3000 },
+  { 0x8700, 0x30ea, 0x2000 },
+  { 0x0700, 0x30e9, 0x0000 },
+  { 0x0700, 0x30eb, 0x0000 },
+  { 0x8700, 0x30ee, 0x2000 },
+  { 0x0700, 0x30ed, 0x0000 },
+  { 0x0700, 0x30ef, 0x0000 },
+  { 0x8700, 0x30f8, 0x4000 },
+  { 0x8700, 0x30f4, 0x3000 },
+  { 0x8700, 0x30f2, 0x2000 },
+  { 0x0700, 0x30f1, 0x0000 },
+  { 0x0700, 0x30f3, 0x0000 },
+  { 0x8700, 0x30f6, 0x2000 },
+  { 0x0700, 0x30f5, 0x0000 },
+  { 0x0700, 0x30f7, 0x0000 },
+  { 0x8600, 0x30fc, 0x3000 },
+  { 0x8700, 0x30fa, 0x2000 },
+  { 0x0700, 0x30f9, 0x0000 },
+  { 0x1000, 0x30fb, 0x0000 },
+  { 0x8600, 0x30fe, 0x2000 },
+  { 0x0600, 0x30fd, 0x0000 },
+  { 0x0700, 0x30ff, 0x0000 },
+  { 0x8700, 0x3125, 0x6000 },
+  { 0x8700, 0x3115, 0x5000 },
+  { 0x8700, 0x310d, 0x4000 },
+  { 0x8700, 0x3109, 0x3000 },
+  { 0x8700, 0x3107, 0x2000 },
+  { 0x0700, 0x3106, 0x0000 },
+  { 0x0700, 0x3108, 0x0000 },
+  { 0x8700, 0x310b, 0x2000 },
+  { 0x0700, 0x310a, 0x0000 },
+  { 0x0700, 0x310c, 0x0000 },
+  { 0x8700, 0x3111, 0x3000 },
+  { 0x8700, 0x310f, 0x2000 },
+  { 0x0700, 0x310e, 0x0000 },
+  { 0x0700, 0x3110, 0x0000 },
+  { 0x8700, 0x3113, 0x2000 },
+  { 0x0700, 0x3112, 0x0000 },
+  { 0x0700, 0x3114, 0x0000 },
+  { 0x8700, 0x311d, 0x4000 },
+  { 0x8700, 0x3119, 0x3000 },
+  { 0x8700, 0x3117, 0x2000 },
+  { 0x0700, 0x3116, 0x0000 },
+  { 0x0700, 0x3118, 0x0000 },
+  { 0x8700, 0x311b, 0x2000 },
+  { 0x0700, 0x311a, 0x0000 },
+  { 0x0700, 0x311c, 0x0000 },
+  { 0x8700, 0x3121, 0x3000 },
+  { 0x8700, 0x311f, 0x2000 },
+  { 0x0700, 0x311e, 0x0000 },
+  { 0x0700, 0x3120, 0x0000 },
+  { 0x8700, 0x3123, 0x2000 },
+  { 0x0700, 0x3122, 0x0000 },
+  { 0x0700, 0x3124, 0x0000 },
+  { 0x8700, 0x3139, 0x5000 },
+  { 0x8700, 0x3131, 0x4000 },
+  { 0x8700, 0x3129, 0x3000 },
+  { 0x8700, 0x3127, 0x2000 },
+  { 0x0700, 0x3126, 0x0000 },
+  { 0x0700, 0x3128, 0x0000 },
+  { 0x8700, 0x312b, 0x2000 },
+  { 0x0700, 0x312a, 0x0000 },
+  { 0x0700, 0x312c, 0x0000 },
+  { 0x8700, 0x3135, 0x3000 },
+  { 0x8700, 0x3133, 0x2000 },
+  { 0x0700, 0x3132, 0x0000 },
+  { 0x0700, 0x3134, 0x0000 },
+  { 0x8700, 0x3137, 0x2000 },
+  { 0x0700, 0x3136, 0x0000 },
+  { 0x0700, 0x3138, 0x0000 },
+  { 0x8700, 0x3141, 0x4000 },
+  { 0x8700, 0x313d, 0x3000 },
+  { 0x8700, 0x313b, 0x2000 },
+  { 0x0700, 0x313a, 0x0000 },
+  { 0x0700, 0x313c, 0x0000 },
+  { 0x8700, 0x313f, 0x2000 },
+  { 0x0700, 0x313e, 0x0000 },
+  { 0x0700, 0x3140, 0x0000 },
+  { 0x8700, 0x3145, 0x3000 },
+  { 0x8700, 0x3143, 0x2000 },
+  { 0x0700, 0x3142, 0x0000 },
+  { 0x0700, 0x3144, 0x0000 },
+  { 0x8700, 0x3147, 0x2000 },
+  { 0x0700, 0x3146, 0x0000 },
+  { 0x0700, 0x3148, 0x0000 },
+  { 0x9a00, 0x3290, 0x9000 },
+  { 0x9a00, 0x3202, 0x8000 },
+  { 0x8700, 0x3189, 0x7000 },
+  { 0x8700, 0x3169, 0x6000 },
+  { 0x8700, 0x3159, 0x5000 },
+  { 0x8700, 0x3151, 0x4000 },
+  { 0x8700, 0x314d, 0x3000 },
+  { 0x8700, 0x314b, 0x2000 },
+  { 0x0700, 0x314a, 0x0000 },
+  { 0x0700, 0x314c, 0x0000 },
+  { 0x8700, 0x314f, 0x2000 },
+  { 0x0700, 0x314e, 0x0000 },
+  { 0x0700, 0x3150, 0x0000 },
+  { 0x8700, 0x3155, 0x3000 },
+  { 0x8700, 0x3153, 0x2000 },
+  { 0x0700, 0x3152, 0x0000 },
+  { 0x0700, 0x3154, 0x0000 },
+  { 0x8700, 0x3157, 0x2000 },
+  { 0x0700, 0x3156, 0x0000 },
+  { 0x0700, 0x3158, 0x0000 },
+  { 0x8700, 0x3161, 0x4000 },
+  { 0x8700, 0x315d, 0x3000 },
+  { 0x8700, 0x315b, 0x2000 },
+  { 0x0700, 0x315a, 0x0000 },
+  { 0x0700, 0x315c, 0x0000 },
+  { 0x8700, 0x315f, 0x2000 },
+  { 0x0700, 0x315e, 0x0000 },
+  { 0x0700, 0x3160, 0x0000 },
+  { 0x8700, 0x3165, 0x3000 },
+  { 0x8700, 0x3163, 0x2000 },
+  { 0x0700, 0x3162, 0x0000 },
+  { 0x0700, 0x3164, 0x0000 },
+  { 0x8700, 0x3167, 0x2000 },
+  { 0x0700, 0x3166, 0x0000 },
+  { 0x0700, 0x3168, 0x0000 },
+  { 0x8700, 0x3179, 0x5000 },
+  { 0x8700, 0x3171, 0x4000 },
+  { 0x8700, 0x316d, 0x3000 },
+  { 0x8700, 0x316b, 0x2000 },
+  { 0x0700, 0x316a, 0x0000 },
+  { 0x0700, 0x316c, 0x0000 },
+  { 0x8700, 0x316f, 0x2000 },
+  { 0x0700, 0x316e, 0x0000 },
+  { 0x0700, 0x3170, 0x0000 },
+  { 0x8700, 0x3175, 0x3000 },
+  { 0x8700, 0x3173, 0x2000 },
+  { 0x0700, 0x3172, 0x0000 },
+  { 0x0700, 0x3174, 0x0000 },
+  { 0x8700, 0x3177, 0x2000 },
+  { 0x0700, 0x3176, 0x0000 },
+  { 0x0700, 0x3178, 0x0000 },
+  { 0x8700, 0x3181, 0x4000 },
+  { 0x8700, 0x317d, 0x3000 },
+  { 0x8700, 0x317b, 0x2000 },
+  { 0x0700, 0x317a, 0x0000 },
+  { 0x0700, 0x317c, 0x0000 },
+  { 0x8700, 0x317f, 0x2000 },
+  { 0x0700, 0x317e, 0x0000 },
+  { 0x0700, 0x3180, 0x0000 },
+  { 0x8700, 0x3185, 0x3000 },
+  { 0x8700, 0x3183, 0x2000 },
+  { 0x0700, 0x3182, 0x0000 },
+  { 0x0700, 0x3184, 0x0000 },
+  { 0x8700, 0x3187, 0x2000 },
+  { 0x0700, 0x3186, 0x0000 },
+  { 0x0700, 0x3188, 0x0000 },
+  { 0x8700, 0x31aa, 0x6000 },
+  { 0x9a00, 0x319a, 0x5000 },
+  { 0x8f00, 0x3192, 0x4000 },
+  { 0x8700, 0x318d, 0x3000 },
+  { 0x8700, 0x318b, 0x2000 },
+  { 0x0700, 0x318a, 0x0000 },
+  { 0x0700, 0x318c, 0x0000 },
+  { 0x9a00, 0x3190, 0x2000 },
+  { 0x0700, 0x318e, 0x0000 },
+  { 0x1a00, 0x3191, 0x0000 },
+  { 0x9a00, 0x3196, 0x3000 },
+  { 0x8f00, 0x3194, 0x2000 },
+  { 0x0f00, 0x3193, 0x0000 },
+  { 0x0f00, 0x3195, 0x0000 },
+  { 0x9a00, 0x3198, 0x2000 },
+  { 0x1a00, 0x3197, 0x0000 },
+  { 0x1a00, 0x3199, 0x0000 },
+  { 0x8700, 0x31a2, 0x4000 },
+  { 0x9a00, 0x319e, 0x3000 },
+  { 0x9a00, 0x319c, 0x2000 },
+  { 0x1a00, 0x319b, 0x0000 },
+  { 0x1a00, 0x319d, 0x0000 },
+  { 0x8700, 0x31a0, 0x2000 },
+  { 0x1a00, 0x319f, 0x0000 },
+  { 0x0700, 0x31a1, 0x0000 },
+  { 0x8700, 0x31a6, 0x3000 },
+  { 0x8700, 0x31a4, 0x2000 },
+  { 0x0700, 0x31a3, 0x0000 },
+  { 0x0700, 0x31a5, 0x0000 },
+  { 0x8700, 0x31a8, 0x2000 },
+  { 0x0700, 0x31a7, 0x0000 },
+  { 0x0700, 0x31a9, 0x0000 },
+  { 0x8700, 0x31f2, 0x5000 },
+  { 0x8700, 0x31b2, 0x4000 },
+  { 0x8700, 0x31ae, 0x3000 },
+  { 0x8700, 0x31ac, 0x2000 },
+  { 0x0700, 0x31ab, 0x0000 },
+  { 0x0700, 0x31ad, 0x0000 },
+  { 0x8700, 0x31b0, 0x2000 },
+  { 0x0700, 0x31af, 0x0000 },
+  { 0x0700, 0x31b1, 0x0000 },
+  { 0x8700, 0x31b6, 0x3000 },
+  { 0x8700, 0x31b4, 0x2000 },
+  { 0x0700, 0x31b3, 0x0000 },
+  { 0x0700, 0x31b5, 0x0000 },
+  { 0x8700, 0x31f0, 0x2000 },
+  { 0x0700, 0x31b7, 0x0000 },
+  { 0x0700, 0x31f1, 0x0000 },
+  { 0x8700, 0x31fa, 0x4000 },
+  { 0x8700, 0x31f6, 0x3000 },
+  { 0x8700, 0x31f4, 0x2000 },
+  { 0x0700, 0x31f3, 0x0000 },
+  { 0x0700, 0x31f5, 0x0000 },
+  { 0x8700, 0x31f8, 0x2000 },
+  { 0x0700, 0x31f7, 0x0000 },
+  { 0x0700, 0x31f9, 0x0000 },
+  { 0x8700, 0x31fe, 0x3000 },
+  { 0x8700, 0x31fc, 0x2000 },
+  { 0x0700, 0x31fb, 0x0000 },
+  { 0x0700, 0x31fd, 0x0000 },
+  { 0x9a00, 0x3200, 0x2000 },
+  { 0x0700, 0x31ff, 0x0000 },
+  { 0x1a00, 0x3201, 0x0000 },
+  { 0x9a00, 0x3243, 0x7000 },
+  { 0x8f00, 0x3223, 0x6000 },
+  { 0x9a00, 0x3212, 0x5000 },
+  { 0x9a00, 0x320a, 0x4000 },
+  { 0x9a00, 0x3206, 0x3000 },
+  { 0x9a00, 0x3204, 0x2000 },
+  { 0x1a00, 0x3203, 0x0000 },
+  { 0x1a00, 0x3205, 0x0000 },
+  { 0x9a00, 0x3208, 0x2000 },
+  { 0x1a00, 0x3207, 0x0000 },
+  { 0x1a00, 0x3209, 0x0000 },
+  { 0x9a00, 0x320e, 0x3000 },
+  { 0x9a00, 0x320c, 0x2000 },
+  { 0x1a00, 0x320b, 0x0000 },
+  { 0x1a00, 0x320d, 0x0000 },
+  { 0x9a00, 0x3210, 0x2000 },
+  { 0x1a00, 0x320f, 0x0000 },
+  { 0x1a00, 0x3211, 0x0000 },
+  { 0x9a00, 0x321a, 0x4000 },
+  { 0x9a00, 0x3216, 0x3000 },
+  { 0x9a00, 0x3214, 0x2000 },
+  { 0x1a00, 0x3213, 0x0000 },
+  { 0x1a00, 0x3215, 0x0000 },
+  { 0x9a00, 0x3218, 0x2000 },
+  { 0x1a00, 0x3217, 0x0000 },
+  { 0x1a00, 0x3219, 0x0000 },
+  { 0x9a00, 0x321e, 0x3000 },
+  { 0x9a00, 0x321c, 0x2000 },
+  { 0x1a00, 0x321b, 0x0000 },
+  { 0x1a00, 0x321d, 0x0000 },
+  { 0x8f00, 0x3221, 0x2000 },
+  { 0x0f00, 0x3220, 0x0000 },
+  { 0x0f00, 0x3222, 0x0000 },
+  { 0x9a00, 0x3233, 0x5000 },
+  { 0x9a00, 0x322b, 0x4000 },
+  { 0x8f00, 0x3227, 0x3000 },
+  { 0x8f00, 0x3225, 0x2000 },
+  { 0x0f00, 0x3224, 0x0000 },
+  { 0x0f00, 0x3226, 0x0000 },
+  { 0x8f00, 0x3229, 0x2000 },
+  { 0x0f00, 0x3228, 0x0000 },
+  { 0x1a00, 0x322a, 0x0000 },
+  { 0x9a00, 0x322f, 0x3000 },
+  { 0x9a00, 0x322d, 0x2000 },
+  { 0x1a00, 0x322c, 0x0000 },
+  { 0x1a00, 0x322e, 0x0000 },
+  { 0x9a00, 0x3231, 0x2000 },
+  { 0x1a00, 0x3230, 0x0000 },
+  { 0x1a00, 0x3232, 0x0000 },
+  { 0x9a00, 0x323b, 0x4000 },
+  { 0x9a00, 0x3237, 0x3000 },
+  { 0x9a00, 0x3235, 0x2000 },
+  { 0x1a00, 0x3234, 0x0000 },
+  { 0x1a00, 0x3236, 0x0000 },
+  { 0x9a00, 0x3239, 0x2000 },
+  { 0x1a00, 0x3238, 0x0000 },
+  { 0x1a00, 0x323a, 0x0000 },
+  { 0x9a00, 0x323f, 0x3000 },
+  { 0x9a00, 0x323d, 0x2000 },
+  { 0x1a00, 0x323c, 0x0000 },
+  { 0x1a00, 0x323e, 0x0000 },
+  { 0x9a00, 0x3241, 0x2000 },
+  { 0x1a00, 0x3240, 0x0000 },
+  { 0x1a00, 0x3242, 0x0000 },
+  { 0x9a00, 0x326f, 0x6000 },
+  { 0x8f00, 0x325f, 0x5000 },
+  { 0x8f00, 0x3257, 0x4000 },
+  { 0x8f00, 0x3253, 0x3000 },
+  { 0x8f00, 0x3251, 0x2000 },
+  { 0x1a00, 0x3250, 0x0000 },
+  { 0x0f00, 0x3252, 0x0000 },
+  { 0x8f00, 0x3255, 0x2000 },
+  { 0x0f00, 0x3254, 0x0000 },
+  { 0x0f00, 0x3256, 0x0000 },
+  { 0x8f00, 0x325b, 0x3000 },
+  { 0x8f00, 0x3259, 0x2000 },
+  { 0x0f00, 0x3258, 0x0000 },
+  { 0x0f00, 0x325a, 0x0000 },
+  { 0x8f00, 0x325d, 0x2000 },
+  { 0x0f00, 0x325c, 0x0000 },
+  { 0x0f00, 0x325e, 0x0000 },
+  { 0x9a00, 0x3267, 0x4000 },
+  { 0x9a00, 0x3263, 0x3000 },
+  { 0x9a00, 0x3261, 0x2000 },
+  { 0x1a00, 0x3260, 0x0000 },
+  { 0x1a00, 0x3262, 0x0000 },
+  { 0x9a00, 0x3265, 0x2000 },
+  { 0x1a00, 0x3264, 0x0000 },
+  { 0x1a00, 0x3266, 0x0000 },
+  { 0x9a00, 0x326b, 0x3000 },
+  { 0x9a00, 0x3269, 0x2000 },
+  { 0x1a00, 0x3268, 0x0000 },
+  { 0x1a00, 0x326a, 0x0000 },
+  { 0x9a00, 0x326d, 0x2000 },
+  { 0x1a00, 0x326c, 0x0000 },
+  { 0x1a00, 0x326e, 0x0000 },
+  { 0x8f00, 0x3280, 0x5000 },
+  { 0x9a00, 0x3277, 0x4000 },
+  { 0x9a00, 0x3273, 0x3000 },
+  { 0x9a00, 0x3271, 0x2000 },
+  { 0x1a00, 0x3270, 0x0000 },
+  { 0x1a00, 0x3272, 0x0000 },
+  { 0x9a00, 0x3275, 0x2000 },
+  { 0x1a00, 0x3274, 0x0000 },
+  { 0x1a00, 0x3276, 0x0000 },
+  { 0x9a00, 0x327b, 0x3000 },
+  { 0x9a00, 0x3279, 0x2000 },
+  { 0x1a00, 0x3278, 0x0000 },
+  { 0x1a00, 0x327a, 0x0000 },
+  { 0x9a00, 0x327d, 0x2000 },
+  { 0x1a00, 0x327c, 0x0000 },
+  { 0x1a00, 0x327f, 0x0000 },
+  { 0x8f00, 0x3288, 0x4000 },
+  { 0x8f00, 0x3284, 0x3000 },
+  { 0x8f00, 0x3282, 0x2000 },
+  { 0x0f00, 0x3281, 0x0000 },
+  { 0x0f00, 0x3283, 0x0000 },
+  { 0x8f00, 0x3286, 0x2000 },
+  { 0x0f00, 0x3285, 0x0000 },
+  { 0x0f00, 0x3287, 0x0000 },
+  { 0x9a00, 0x328c, 0x3000 },
+  { 0x9a00, 0x328a, 0x2000 },
+  { 0x0f00, 0x3289, 0x0000 },
+  { 0x1a00, 0x328b, 0x0000 },
+  { 0x9a00, 0x328e, 0x2000 },
+  { 0x1a00, 0x328d, 0x0000 },
+  { 0x1a00, 0x328f, 0x0000 },
+  { 0x9a00, 0x3311, 0x8000 },
+  { 0x9a00, 0x32d0, 0x7000 },
+  { 0x9a00, 0x32b0, 0x6000 },
+  { 0x9a00, 0x32a0, 0x5000 },
+  { 0x9a00, 0x3298, 0x4000 },
+  { 0x9a00, 0x3294, 0x3000 },
+  { 0x9a00, 0x3292, 0x2000 },
+  { 0x1a00, 0x3291, 0x0000 },
+  { 0x1a00, 0x3293, 0x0000 },
+  { 0x9a00, 0x3296, 0x2000 },
+  { 0x1a00, 0x3295, 0x0000 },
+  { 0x1a00, 0x3297, 0x0000 },
+  { 0x9a00, 0x329c, 0x3000 },
+  { 0x9a00, 0x329a, 0x2000 },
+  { 0x1a00, 0x3299, 0x0000 },
+  { 0x1a00, 0x329b, 0x0000 },
+  { 0x9a00, 0x329e, 0x2000 },
+  { 0x1a00, 0x329d, 0x0000 },
+  { 0x1a00, 0x329f, 0x0000 },
+  { 0x9a00, 0x32a8, 0x4000 },
+  { 0x9a00, 0x32a4, 0x3000 },
+  { 0x9a00, 0x32a2, 0x2000 },
+  { 0x1a00, 0x32a1, 0x0000 },
+  { 0x1a00, 0x32a3, 0x0000 },
+  { 0x9a00, 0x32a6, 0x2000 },
+  { 0x1a00, 0x32a5, 0x0000 },
+  { 0x1a00, 0x32a7, 0x0000 },
+  { 0x9a00, 0x32ac, 0x3000 },
+  { 0x9a00, 0x32aa, 0x2000 },
+  { 0x1a00, 0x32a9, 0x0000 },
+  { 0x1a00, 0x32ab, 0x0000 },
+  { 0x9a00, 0x32ae, 0x2000 },
+  { 0x1a00, 0x32ad, 0x0000 },
+  { 0x1a00, 0x32af, 0x0000 },
+  { 0x9a00, 0x32c0, 0x5000 },
+  { 0x8f00, 0x32b8, 0x4000 },
+  { 0x8f00, 0x32b4, 0x3000 },
+  { 0x8f00, 0x32b2, 0x2000 },
+  { 0x0f00, 0x32b1, 0x0000 },
+  { 0x0f00, 0x32b3, 0x0000 },
+  { 0x8f00, 0x32b6, 0x2000 },
+  { 0x0f00, 0x32b5, 0x0000 },
+  { 0x0f00, 0x32b7, 0x0000 },
+  { 0x8f00, 0x32bc, 0x3000 },
+  { 0x8f00, 0x32ba, 0x2000 },
+  { 0x0f00, 0x32b9, 0x0000 },
+  { 0x0f00, 0x32bb, 0x0000 },
+  { 0x8f00, 0x32be, 0x2000 },
+  { 0x0f00, 0x32bd, 0x0000 },
+  { 0x0f00, 0x32bf, 0x0000 },
+  { 0x9a00, 0x32c8, 0x4000 },
+  { 0x9a00, 0x32c4, 0x3000 },
+  { 0x9a00, 0x32c2, 0x2000 },
+  { 0x1a00, 0x32c1, 0x0000 },
+  { 0x1a00, 0x32c3, 0x0000 },
+  { 0x9a00, 0x32c6, 0x2000 },
+  { 0x1a00, 0x32c5, 0x0000 },
+  { 0x1a00, 0x32c7, 0x0000 },
+  { 0x9a00, 0x32cc, 0x3000 },
+  { 0x9a00, 0x32ca, 0x2000 },
+  { 0x1a00, 0x32c9, 0x0000 },
+  { 0x1a00, 0x32cb, 0x0000 },
+  { 0x9a00, 0x32ce, 0x2000 },
+  { 0x1a00, 0x32cd, 0x0000 },
+  { 0x1a00, 0x32cf, 0x0000 },
+  { 0x9a00, 0x32f0, 0x6000 },
+  { 0x9a00, 0x32e0, 0x5000 },
+  { 0x9a00, 0x32d8, 0x4000 },
+  { 0x9a00, 0x32d4, 0x3000 },
+  { 0x9a00, 0x32d2, 0x2000 },
+  { 0x1a00, 0x32d1, 0x0000 },
+  { 0x1a00, 0x32d3, 0x0000 },
+  { 0x9a00, 0x32d6, 0x2000 },
+  { 0x1a00, 0x32d5, 0x0000 },
+  { 0x1a00, 0x32d7, 0x0000 },
+  { 0x9a00, 0x32dc, 0x3000 },
+  { 0x9a00, 0x32da, 0x2000 },
+  { 0x1a00, 0x32d9, 0x0000 },
+  { 0x1a00, 0x32db, 0x0000 },
+  { 0x9a00, 0x32de, 0x2000 },
+  { 0x1a00, 0x32dd, 0x0000 },
+  { 0x1a00, 0x32df, 0x0000 },
+  { 0x9a00, 0x32e8, 0x4000 },
+  { 0x9a00, 0x32e4, 0x3000 },
+  { 0x9a00, 0x32e2, 0x2000 },
+  { 0x1a00, 0x32e1, 0x0000 },
+  { 0x1a00, 0x32e3, 0x0000 },
+  { 0x9a00, 0x32e6, 0x2000 },
+  { 0x1a00, 0x32e5, 0x0000 },
+  { 0x1a00, 0x32e7, 0x0000 },
+  { 0x9a00, 0x32ec, 0x3000 },
+  { 0x9a00, 0x32ea, 0x2000 },
+  { 0x1a00, 0x32e9, 0x0000 },
+  { 0x1a00, 0x32eb, 0x0000 },
+  { 0x9a00, 0x32ee, 0x2000 },
+  { 0x1a00, 0x32ed, 0x0000 },
+  { 0x1a00, 0x32ef, 0x0000 },
+  { 0x9a00, 0x3301, 0x5000 },
+  { 0x9a00, 0x32f8, 0x4000 },
+  { 0x9a00, 0x32f4, 0x3000 },
+  { 0x9a00, 0x32f2, 0x2000 },
+  { 0x1a00, 0x32f1, 0x0000 },
+  { 0x1a00, 0x32f3, 0x0000 },
+  { 0x9a00, 0x32f6, 0x2000 },
+  { 0x1a00, 0x32f5, 0x0000 },
+  { 0x1a00, 0x32f7, 0x0000 },
+  { 0x9a00, 0x32fc, 0x3000 },
+  { 0x9a00, 0x32fa, 0x2000 },
+  { 0x1a00, 0x32f9, 0x0000 },
+  { 0x1a00, 0x32fb, 0x0000 },
+  { 0x9a00, 0x32fe, 0x2000 },
+  { 0x1a00, 0x32fd, 0x0000 },
+  { 0x1a00, 0x3300, 0x0000 },
+  { 0x9a00, 0x3309, 0x4000 },
+  { 0x9a00, 0x3305, 0x3000 },
+  { 0x9a00, 0x3303, 0x2000 },
+  { 0x1a00, 0x3302, 0x0000 },
+  { 0x1a00, 0x3304, 0x0000 },
+  { 0x9a00, 0x3307, 0x2000 },
+  { 0x1a00, 0x3306, 0x0000 },
+  { 0x1a00, 0x3308, 0x0000 },
+  { 0x9a00, 0x330d, 0x3000 },
+  { 0x9a00, 0x330b, 0x2000 },
+  { 0x1a00, 0x330a, 0x0000 },
+  { 0x1a00, 0x330c, 0x0000 },
+  { 0x9a00, 0x330f, 0x2000 },
+  { 0x1a00, 0x330e, 0x0000 },
+  { 0x1a00, 0x3310, 0x0000 },
+  { 0x9a00, 0x3351, 0x7000 },
+  { 0x9a00, 0x3331, 0x6000 },
+  { 0x9a00, 0x3321, 0x5000 },
+  { 0x9a00, 0x3319, 0x4000 },
+  { 0x9a00, 0x3315, 0x3000 },
+  { 0x9a00, 0x3313, 0x2000 },
+  { 0x1a00, 0x3312, 0x0000 },
+  { 0x1a00, 0x3314, 0x0000 },
+  { 0x9a00, 0x3317, 0x2000 },
+  { 0x1a00, 0x3316, 0x0000 },
+  { 0x1a00, 0x3318, 0x0000 },
+  { 0x9a00, 0x331d, 0x3000 },
+  { 0x9a00, 0x331b, 0x2000 },
+  { 0x1a00, 0x331a, 0x0000 },
+  { 0x1a00, 0x331c, 0x0000 },
+  { 0x9a00, 0x331f, 0x2000 },
+  { 0x1a00, 0x331e, 0x0000 },
+  { 0x1a00, 0x3320, 0x0000 },
+  { 0x9a00, 0x3329, 0x4000 },
+  { 0x9a00, 0x3325, 0x3000 },
+  { 0x9a00, 0x3323, 0x2000 },
+  { 0x1a00, 0x3322, 0x0000 },
+  { 0x1a00, 0x3324, 0x0000 },
+  { 0x9a00, 0x3327, 0x2000 },
+  { 0x1a00, 0x3326, 0x0000 },
+  { 0x1a00, 0x3328, 0x0000 },
+  { 0x9a00, 0x332d, 0x3000 },
+  { 0x9a00, 0x332b, 0x2000 },
+  { 0x1a00, 0x332a, 0x0000 },
+  { 0x1a00, 0x332c, 0x0000 },
+  { 0x9a00, 0x332f, 0x2000 },
+  { 0x1a00, 0x332e, 0x0000 },
+  { 0x1a00, 0x3330, 0x0000 },
+  { 0x9a00, 0x3341, 0x5000 },
+  { 0x9a00, 0x3339, 0x4000 },
+  { 0x9a00, 0x3335, 0x3000 },
+  { 0x9a00, 0x3333, 0x2000 },
+  { 0x1a00, 0x3332, 0x0000 },
+  { 0x1a00, 0x3334, 0x0000 },
+  { 0x9a00, 0x3337, 0x2000 },
+  { 0x1a00, 0x3336, 0x0000 },
+  { 0x1a00, 0x3338, 0x0000 },
+  { 0x9a00, 0x333d, 0x3000 },
+  { 0x9a00, 0x333b, 0x2000 },
+  { 0x1a00, 0x333a, 0x0000 },
+  { 0x1a00, 0x333c, 0x0000 },
+  { 0x9a00, 0x333f, 0x2000 },
+  { 0x1a00, 0x333e, 0x0000 },
+  { 0x1a00, 0x3340, 0x0000 },
+  { 0x9a00, 0x3349, 0x4000 },
+  { 0x9a00, 0x3345, 0x3000 },
+  { 0x9a00, 0x3343, 0x2000 },
+  { 0x1a00, 0x3342, 0x0000 },
+  { 0x1a00, 0x3344, 0x0000 },
+  { 0x9a00, 0x3347, 0x2000 },
+  { 0x1a00, 0x3346, 0x0000 },
+  { 0x1a00, 0x3348, 0x0000 },
+  { 0x9a00, 0x334d, 0x3000 },
+  { 0x9a00, 0x334b, 0x2000 },
+  { 0x1a00, 0x334a, 0x0000 },
+  { 0x1a00, 0x334c, 0x0000 },
+  { 0x9a00, 0x334f, 0x2000 },
+  { 0x1a00, 0x334e, 0x0000 },
+  { 0x1a00, 0x3350, 0x0000 },
+  { 0x9a00, 0x3371, 0x6000 },
+  { 0x9a00, 0x3361, 0x5000 },
+  { 0x9a00, 0x3359, 0x4000 },
+  { 0x9a00, 0x3355, 0x3000 },
+  { 0x9a00, 0x3353, 0x2000 },
+  { 0x1a00, 0x3352, 0x0000 },
+  { 0x1a00, 0x3354, 0x0000 },
+  { 0x9a00, 0x3357, 0x2000 },
+  { 0x1a00, 0x3356, 0x0000 },
+  { 0x1a00, 0x3358, 0x0000 },
+  { 0x9a00, 0x335d, 0x3000 },
+  { 0x9a00, 0x335b, 0x2000 },
+  { 0x1a00, 0x335a, 0x0000 },
+  { 0x1a00, 0x335c, 0x0000 },
+  { 0x9a00, 0x335f, 0x2000 },
+  { 0x1a00, 0x335e, 0x0000 },
+  { 0x1a00, 0x3360, 0x0000 },
+  { 0x9a00, 0x3369, 0x4000 },
+  { 0x9a00, 0x3365, 0x3000 },
+  { 0x9a00, 0x3363, 0x2000 },
+  { 0x1a00, 0x3362, 0x0000 },
+  { 0x1a00, 0x3364, 0x0000 },
+  { 0x9a00, 0x3367, 0x2000 },
+  { 0x1a00, 0x3366, 0x0000 },
+  { 0x1a00, 0x3368, 0x0000 },
+  { 0x9a00, 0x336d, 0x3000 },
+  { 0x9a00, 0x336b, 0x2000 },
+  { 0x1a00, 0x336a, 0x0000 },
+  { 0x1a00, 0x336c, 0x0000 },
+  { 0x9a00, 0x336f, 0x2000 },
+  { 0x1a00, 0x336e, 0x0000 },
+  { 0x1a00, 0x3370, 0x0000 },
+  { 0x9a00, 0x3381, 0x5000 },
+  { 0x9a00, 0x3379, 0x4000 },
+  { 0x9a00, 0x3375, 0x3000 },
+  { 0x9a00, 0x3373, 0x2000 },
+  { 0x1a00, 0x3372, 0x0000 },
+  { 0x1a00, 0x3374, 0x0000 },
+  { 0x9a00, 0x3377, 0x2000 },
+  { 0x1a00, 0x3376, 0x0000 },
+  { 0x1a00, 0x3378, 0x0000 },
+  { 0x9a00, 0x337d, 0x3000 },
+  { 0x9a00, 0x337b, 0x2000 },
+  { 0x1a00, 0x337a, 0x0000 },
+  { 0x1a00, 0x337c, 0x0000 },
+  { 0x9a00, 0x337f, 0x2000 },
+  { 0x1a00, 0x337e, 0x0000 },
+  { 0x1a00, 0x3380, 0x0000 },
+  { 0x9a00, 0x3389, 0x4000 },
+  { 0x9a00, 0x3385, 0x3000 },
+  { 0x9a00, 0x3383, 0x2000 },
+  { 0x1a00, 0x3382, 0x0000 },
+  { 0x1a00, 0x3384, 0x0000 },
+  { 0x9a00, 0x3387, 0x2000 },
+  { 0x1a00, 0x3386, 0x0000 },
+  { 0x1a00, 0x3388, 0x0000 },
+  { 0x9a00, 0x338d, 0x3000 },
+  { 0x9a00, 0x338b, 0x2000 },
+  { 0x1a00, 0x338a, 0x0000 },
+  { 0x1a00, 0x338c, 0x0000 },
+  { 0x9a00, 0x338f, 0x2000 },
+  { 0x1a00, 0x338e, 0x0000 },
+  { 0x1a00, 0x3390, 0x0000 },
+  { 0x8700, 0xa14d, 0xa000 },
+  { 0x8700, 0xa04d, 0x9000 },
+  { 0x9a00, 0x4dcf, 0x8000 },
+  { 0x9a00, 0x33d1, 0x7000 },
+  { 0x9a00, 0x33b1, 0x6000 },
+  { 0x9a00, 0x33a1, 0x5000 },
+  { 0x9a00, 0x3399, 0x4000 },
+  { 0x9a00, 0x3395, 0x3000 },
+  { 0x9a00, 0x3393, 0x2000 },
+  { 0x1a00, 0x3392, 0x0000 },
+  { 0x1a00, 0x3394, 0x0000 },
+  { 0x9a00, 0x3397, 0x2000 },
+  { 0x1a00, 0x3396, 0x0000 },
+  { 0x1a00, 0x3398, 0x0000 },
+  { 0x9a00, 0x339d, 0x3000 },
+  { 0x9a00, 0x339b, 0x2000 },
+  { 0x1a00, 0x339a, 0x0000 },
+  { 0x1a00, 0x339c, 0x0000 },
+  { 0x9a00, 0x339f, 0x2000 },
+  { 0x1a00, 0x339e, 0x0000 },
+  { 0x1a00, 0x33a0, 0x0000 },
+  { 0x9a00, 0x33a9, 0x4000 },
+  { 0x9a00, 0x33a5, 0x3000 },
+  { 0x9a00, 0x33a3, 0x2000 },
+  { 0x1a00, 0x33a2, 0x0000 },
+  { 0x1a00, 0x33a4, 0x0000 },
+  { 0x9a00, 0x33a7, 0x2000 },
+  { 0x1a00, 0x33a6, 0x0000 },
+  { 0x1a00, 0x33a8, 0x0000 },
+  { 0x9a00, 0x33ad, 0x3000 },
+  { 0x9a00, 0x33ab, 0x2000 },
+  { 0x1a00, 0x33aa, 0x0000 },
+  { 0x1a00, 0x33ac, 0x0000 },
+  { 0x9a00, 0x33af, 0x2000 },
+  { 0x1a00, 0x33ae, 0x0000 },
+  { 0x1a00, 0x33b0, 0x0000 },
+  { 0x9a00, 0x33c1, 0x5000 },
+  { 0x9a00, 0x33b9, 0x4000 },
+  { 0x9a00, 0x33b5, 0x3000 },
+  { 0x9a00, 0x33b3, 0x2000 },
+  { 0x1a00, 0x33b2, 0x0000 },
+  { 0x1a00, 0x33b4, 0x0000 },
+  { 0x9a00, 0x33b7, 0x2000 },
+  { 0x1a00, 0x33b6, 0x0000 },
+  { 0x1a00, 0x33b8, 0x0000 },
+  { 0x9a00, 0x33bd, 0x3000 },
+  { 0x9a00, 0x33bb, 0x2000 },
+  { 0x1a00, 0x33ba, 0x0000 },
+  { 0x1a00, 0x33bc, 0x0000 },
+  { 0x9a00, 0x33bf, 0x2000 },
+  { 0x1a00, 0x33be, 0x0000 },
+  { 0x1a00, 0x33c0, 0x0000 },
+  { 0x9a00, 0x33c9, 0x4000 },
+  { 0x9a00, 0x33c5, 0x3000 },
+  { 0x9a00, 0x33c3, 0x2000 },
+  { 0x1a00, 0x33c2, 0x0000 },
+  { 0x1a00, 0x33c4, 0x0000 },
+  { 0x9a00, 0x33c7, 0x2000 },
+  { 0x1a00, 0x33c6, 0x0000 },
+  { 0x1a00, 0x33c8, 0x0000 },
+  { 0x9a00, 0x33cd, 0x3000 },
+  { 0x9a00, 0x33cb, 0x2000 },
+  { 0x1a00, 0x33ca, 0x0000 },
+  { 0x1a00, 0x33cc, 0x0000 },
+  { 0x9a00, 0x33cf, 0x2000 },
+  { 0x1a00, 0x33ce, 0x0000 },
+  { 0x1a00, 0x33d0, 0x0000 },
+  { 0x9a00, 0x33f1, 0x6000 },
+  { 0x9a00, 0x33e1, 0x5000 },
+  { 0x9a00, 0x33d9, 0x4000 },
+  { 0x9a00, 0x33d5, 0x3000 },
+  { 0x9a00, 0x33d3, 0x2000 },
+  { 0x1a00, 0x33d2, 0x0000 },
+  { 0x1a00, 0x33d4, 0x0000 },
+  { 0x9a00, 0x33d7, 0x2000 },
+  { 0x1a00, 0x33d6, 0x0000 },
+  { 0x1a00, 0x33d8, 0x0000 },
+  { 0x9a00, 0x33dd, 0x3000 },
+  { 0x9a00, 0x33db, 0x2000 },
+  { 0x1a00, 0x33da, 0x0000 },
+  { 0x1a00, 0x33dc, 0x0000 },
+  { 0x9a00, 0x33df, 0x2000 },
+  { 0x1a00, 0x33de, 0x0000 },
+  { 0x1a00, 0x33e0, 0x0000 },
+  { 0x9a00, 0x33e9, 0x4000 },
+  { 0x9a00, 0x33e5, 0x3000 },
+  { 0x9a00, 0x33e3, 0x2000 },
+  { 0x1a00, 0x33e2, 0x0000 },
+  { 0x1a00, 0x33e4, 0x0000 },
+  { 0x9a00, 0x33e7, 0x2000 },
+  { 0x1a00, 0x33e6, 0x0000 },
+  { 0x1a00, 0x33e8, 0x0000 },
+  { 0x9a00, 0x33ed, 0x3000 },
+  { 0x9a00, 0x33eb, 0x2000 },
+  { 0x1a00, 0x33ea, 0x0000 },
+  { 0x1a00, 0x33ec, 0x0000 },
+  { 0x9a00, 0x33ef, 0x2000 },
+  { 0x1a00, 0x33ee, 0x0000 },
+  { 0x1a00, 0x33f0, 0x0000 },
+  { 0x8700, 0x4db5, 0x5000 },
+  { 0x9a00, 0x33f9, 0x4000 },
+  { 0x9a00, 0x33f5, 0x3000 },
+  { 0x9a00, 0x33f3, 0x2000 },
+  { 0x1a00, 0x33f2, 0x0000 },
+  { 0x1a00, 0x33f4, 0x0000 },
+  { 0x9a00, 0x33f7, 0x2000 },
+  { 0x1a00, 0x33f6, 0x0000 },
+  { 0x1a00, 0x33f8, 0x0000 },
+  { 0x9a00, 0x33fd, 0x3000 },
+  { 0x9a00, 0x33fb, 0x2000 },
+  { 0x1a00, 0x33fa, 0x0000 },
+  { 0x1a00, 0x33fc, 0x0000 },
+  { 0x9a00, 0x33ff, 0x2000 },
+  { 0x1a00, 0x33fe, 0x0000 },
+  { 0x0700, 0x3400, 0x0000 },
+  { 0x9a00, 0x4dc7, 0x4000 },
+  { 0x9a00, 0x4dc3, 0x3000 },
+  { 0x9a00, 0x4dc1, 0x2000 },
+  { 0x1a00, 0x4dc0, 0x0000 },
+  { 0x1a00, 0x4dc2, 0x0000 },
+  { 0x9a00, 0x4dc5, 0x2000 },
+  { 0x1a00, 0x4dc4, 0x0000 },
+  { 0x1a00, 0x4dc6, 0x0000 },
+  { 0x9a00, 0x4dcb, 0x3000 },
+  { 0x9a00, 0x4dc9, 0x2000 },
+  { 0x1a00, 0x4dc8, 0x0000 },
+  { 0x1a00, 0x4dca, 0x0000 },
+  { 0x9a00, 0x4dcd, 0x2000 },
+  { 0x1a00, 0x4dcc, 0x0000 },
+  { 0x1a00, 0x4dce, 0x0000 },
+  { 0x8700, 0xa00d, 0x7000 },
+  { 0x9a00, 0x4def, 0x6000 },
+  { 0x9a00, 0x4ddf, 0x5000 },
+  { 0x9a00, 0x4dd7, 0x4000 },
+  { 0x9a00, 0x4dd3, 0x3000 },
+  { 0x9a00, 0x4dd1, 0x2000 },
+  { 0x1a00, 0x4dd0, 0x0000 },
+  { 0x1a00, 0x4dd2, 0x0000 },
+  { 0x9a00, 0x4dd5, 0x2000 },
+  { 0x1a00, 0x4dd4, 0x0000 },
+  { 0x1a00, 0x4dd6, 0x0000 },
+  { 0x9a00, 0x4ddb, 0x3000 },
+  { 0x9a00, 0x4dd9, 0x2000 },
+  { 0x1a00, 0x4dd8, 0x0000 },
+  { 0x1a00, 0x4dda, 0x0000 },
+  { 0x9a00, 0x4ddd, 0x2000 },
+  { 0x1a00, 0x4ddc, 0x0000 },
+  { 0x1a00, 0x4dde, 0x0000 },
+  { 0x9a00, 0x4de7, 0x4000 },
+  { 0x9a00, 0x4de3, 0x3000 },
+  { 0x9a00, 0x4de1, 0x2000 },
+  { 0x1a00, 0x4de0, 0x0000 },
+  { 0x1a00, 0x4de2, 0x0000 },
+  { 0x9a00, 0x4de5, 0x2000 },
+  { 0x1a00, 0x4de4, 0x0000 },
+  { 0x1a00, 0x4de6, 0x0000 },
+  { 0x9a00, 0x4deb, 0x3000 },
+  { 0x9a00, 0x4de9, 0x2000 },
+  { 0x1a00, 0x4de8, 0x0000 },
+  { 0x1a00, 0x4dea, 0x0000 },
+  { 0x9a00, 0x4ded, 0x2000 },
+  { 0x1a00, 0x4dec, 0x0000 },
+  { 0x1a00, 0x4dee, 0x0000 },
+  { 0x9a00, 0x4dff, 0x5000 },
+  { 0x9a00, 0x4df7, 0x4000 },
+  { 0x9a00, 0x4df3, 0x3000 },
+  { 0x9a00, 0x4df1, 0x2000 },
+  { 0x1a00, 0x4df0, 0x0000 },
+  { 0x1a00, 0x4df2, 0x0000 },
+  { 0x9a00, 0x4df5, 0x2000 },
+  { 0x1a00, 0x4df4, 0x0000 },
+  { 0x1a00, 0x4df6, 0x0000 },
+  { 0x9a00, 0x4dfb, 0x3000 },
+  { 0x9a00, 0x4df9, 0x2000 },
+  { 0x1a00, 0x4df8, 0x0000 },
+  { 0x1a00, 0x4dfa, 0x0000 },
+  { 0x9a00, 0x4dfd, 0x2000 },
+  { 0x1a00, 0x4dfc, 0x0000 },
+  { 0x1a00, 0x4dfe, 0x0000 },
+  { 0x8700, 0xa005, 0x4000 },
+  { 0x8700, 0xa001, 0x3000 },
+  { 0x8700, 0x9fa5, 0x2000 },
+  { 0x0700, 0x4e00, 0x0000 },
+  { 0x0700, 0xa000, 0x0000 },
+  { 0x8700, 0xa003, 0x2000 },
+  { 0x0700, 0xa002, 0x0000 },
+  { 0x0700, 0xa004, 0x0000 },
+  { 0x8700, 0xa009, 0x3000 },
+  { 0x8700, 0xa007, 0x2000 },
+  { 0x0700, 0xa006, 0x0000 },
+  { 0x0700, 0xa008, 0x0000 },
+  { 0x8700, 0xa00b, 0x2000 },
+  { 0x0700, 0xa00a, 0x0000 },
+  { 0x0700, 0xa00c, 0x0000 },
+  { 0x8700, 0xa02d, 0x6000 },
+  { 0x8700, 0xa01d, 0x5000 },
+  { 0x8700, 0xa015, 0x4000 },
+  { 0x8700, 0xa011, 0x3000 },
+  { 0x8700, 0xa00f, 0x2000 },
+  { 0x0700, 0xa00e, 0x0000 },
+  { 0x0700, 0xa010, 0x0000 },
+  { 0x8700, 0xa013, 0x2000 },
+  { 0x0700, 0xa012, 0x0000 },
+  { 0x0700, 0xa014, 0x0000 },
+  { 0x8700, 0xa019, 0x3000 },
+  { 0x8700, 0xa017, 0x2000 },
+  { 0x0700, 0xa016, 0x0000 },
+  { 0x0700, 0xa018, 0x0000 },
+  { 0x8700, 0xa01b, 0x2000 },
+  { 0x0700, 0xa01a, 0x0000 },
+  { 0x0700, 0xa01c, 0x0000 },
+  { 0x8700, 0xa025, 0x4000 },
+  { 0x8700, 0xa021, 0x3000 },
+  { 0x8700, 0xa01f, 0x2000 },
+  { 0x0700, 0xa01e, 0x0000 },
+  { 0x0700, 0xa020, 0x0000 },
+  { 0x8700, 0xa023, 0x2000 },
+  { 0x0700, 0xa022, 0x0000 },
+  { 0x0700, 0xa024, 0x0000 },
+  { 0x8700, 0xa029, 0x3000 },
+  { 0x8700, 0xa027, 0x2000 },
+  { 0x0700, 0xa026, 0x0000 },
+  { 0x0700, 0xa028, 0x0000 },
+  { 0x8700, 0xa02b, 0x2000 },
+  { 0x0700, 0xa02a, 0x0000 },
+  { 0x0700, 0xa02c, 0x0000 },
+  { 0x8700, 0xa03d, 0x5000 },
+  { 0x8700, 0xa035, 0x4000 },
+  { 0x8700, 0xa031, 0x3000 },
+  { 0x8700, 0xa02f, 0x2000 },
+  { 0x0700, 0xa02e, 0x0000 },
+  { 0x0700, 0xa030, 0x0000 },
+  { 0x8700, 0xa033, 0x2000 },
+  { 0x0700, 0xa032, 0x0000 },
+  { 0x0700, 0xa034, 0x0000 },
+  { 0x8700, 0xa039, 0x3000 },
+  { 0x8700, 0xa037, 0x2000 },
+  { 0x0700, 0xa036, 0x0000 },
+  { 0x0700, 0xa038, 0x0000 },
+  { 0x8700, 0xa03b, 0x2000 },
+  { 0x0700, 0xa03a, 0x0000 },
+  { 0x0700, 0xa03c, 0x0000 },
+  { 0x8700, 0xa045, 0x4000 },
+  { 0x8700, 0xa041, 0x3000 },
+  { 0x8700, 0xa03f, 0x2000 },
+  { 0x0700, 0xa03e, 0x0000 },
+  { 0x0700, 0xa040, 0x0000 },
+  { 0x8700, 0xa043, 0x2000 },
+  { 0x0700, 0xa042, 0x0000 },
+  { 0x0700, 0xa044, 0x0000 },
+  { 0x8700, 0xa049, 0x3000 },
+  { 0x8700, 0xa047, 0x2000 },
+  { 0x0700, 0xa046, 0x0000 },
+  { 0x0700, 0xa048, 0x0000 },
+  { 0x8700, 0xa04b, 0x2000 },
+  { 0x0700, 0xa04a, 0x0000 },
+  { 0x0700, 0xa04c, 0x0000 },
+  { 0x8700, 0xa0cd, 0x8000 },
+  { 0x8700, 0xa08d, 0x7000 },
+  { 0x8700, 0xa06d, 0x6000 },
+  { 0x8700, 0xa05d, 0x5000 },
+  { 0x8700, 0xa055, 0x4000 },
+  { 0x8700, 0xa051, 0x3000 },
+  { 0x8700, 0xa04f, 0x2000 },
+  { 0x0700, 0xa04e, 0x0000 },
+  { 0x0700, 0xa050, 0x0000 },
+  { 0x8700, 0xa053, 0x2000 },
+  { 0x0700, 0xa052, 0x0000 },
+  { 0x0700, 0xa054, 0x0000 },
+  { 0x8700, 0xa059, 0x3000 },
+  { 0x8700, 0xa057, 0x2000 },
+  { 0x0700, 0xa056, 0x0000 },
+  { 0x0700, 0xa058, 0x0000 },
+  { 0x8700, 0xa05b, 0x2000 },
+  { 0x0700, 0xa05a, 0x0000 },
+  { 0x0700, 0xa05c, 0x0000 },
+  { 0x8700, 0xa065, 0x4000 },
+  { 0x8700, 0xa061, 0x3000 },
+  { 0x8700, 0xa05f, 0x2000 },
+  { 0x0700, 0xa05e, 0x0000 },
+  { 0x0700, 0xa060, 0x0000 },
+  { 0x8700, 0xa063, 0x2000 },
+  { 0x0700, 0xa062, 0x0000 },
+  { 0x0700, 0xa064, 0x0000 },
+  { 0x8700, 0xa069, 0x3000 },
+  { 0x8700, 0xa067, 0x2000 },
+  { 0x0700, 0xa066, 0x0000 },
+  { 0x0700, 0xa068, 0x0000 },
+  { 0x8700, 0xa06b, 0x2000 },
+  { 0x0700, 0xa06a, 0x0000 },
+  { 0x0700, 0xa06c, 0x0000 },
+  { 0x8700, 0xa07d, 0x5000 },
+  { 0x8700, 0xa075, 0x4000 },
+  { 0x8700, 0xa071, 0x3000 },
+  { 0x8700, 0xa06f, 0x2000 },
+  { 0x0700, 0xa06e, 0x0000 },
+  { 0x0700, 0xa070, 0x0000 },
+  { 0x8700, 0xa073, 0x2000 },
+  { 0x0700, 0xa072, 0x0000 },
+  { 0x0700, 0xa074, 0x0000 },
+  { 0x8700, 0xa079, 0x3000 },
+  { 0x8700, 0xa077, 0x2000 },
+  { 0x0700, 0xa076, 0x0000 },
+  { 0x0700, 0xa078, 0x0000 },
+  { 0x8700, 0xa07b, 0x2000 },
+  { 0x0700, 0xa07a, 0x0000 },
+  { 0x0700, 0xa07c, 0x0000 },
+  { 0x8700, 0xa085, 0x4000 },
+  { 0x8700, 0xa081, 0x3000 },
+  { 0x8700, 0xa07f, 0x2000 },
+  { 0x0700, 0xa07e, 0x0000 },
+  { 0x0700, 0xa080, 0x0000 },
+  { 0x8700, 0xa083, 0x2000 },
+  { 0x0700, 0xa082, 0x0000 },
+  { 0x0700, 0xa084, 0x0000 },
+  { 0x8700, 0xa089, 0x3000 },
+  { 0x8700, 0xa087, 0x2000 },
+  { 0x0700, 0xa086, 0x0000 },
+  { 0x0700, 0xa088, 0x0000 },
+  { 0x8700, 0xa08b, 0x2000 },
+  { 0x0700, 0xa08a, 0x0000 },
+  { 0x0700, 0xa08c, 0x0000 },
+  { 0x8700, 0xa0ad, 0x6000 },
+  { 0x8700, 0xa09d, 0x5000 },
+  { 0x8700, 0xa095, 0x4000 },
+  { 0x8700, 0xa091, 0x3000 },
+  { 0x8700, 0xa08f, 0x2000 },
+  { 0x0700, 0xa08e, 0x0000 },
+  { 0x0700, 0xa090, 0x0000 },
+  { 0x8700, 0xa093, 0x2000 },
+  { 0x0700, 0xa092, 0x0000 },
+  { 0x0700, 0xa094, 0x0000 },
+  { 0x8700, 0xa099, 0x3000 },
+  { 0x8700, 0xa097, 0x2000 },
+  { 0x0700, 0xa096, 0x0000 },
+  { 0x0700, 0xa098, 0x0000 },
+  { 0x8700, 0xa09b, 0x2000 },
+  { 0x0700, 0xa09a, 0x0000 },
+  { 0x0700, 0xa09c, 0x0000 },
+  { 0x8700, 0xa0a5, 0x4000 },
+  { 0x8700, 0xa0a1, 0x3000 },
+  { 0x8700, 0xa09f, 0x2000 },
+  { 0x0700, 0xa09e, 0x0000 },
+  { 0x0700, 0xa0a0, 0x0000 },
+  { 0x8700, 0xa0a3, 0x2000 },
+  { 0x0700, 0xa0a2, 0x0000 },
+  { 0x0700, 0xa0a4, 0x0000 },
+  { 0x8700, 0xa0a9, 0x3000 },
+  { 0x8700, 0xa0a7, 0x2000 },
+  { 0x0700, 0xa0a6, 0x0000 },
+  { 0x0700, 0xa0a8, 0x0000 },
+  { 0x8700, 0xa0ab, 0x2000 },
+  { 0x0700, 0xa0aa, 0x0000 },
+  { 0x0700, 0xa0ac, 0x0000 },
+  { 0x8700, 0xa0bd, 0x5000 },
+  { 0x8700, 0xa0b5, 0x4000 },
+  { 0x8700, 0xa0b1, 0x3000 },
+  { 0x8700, 0xa0af, 0x2000 },
+  { 0x0700, 0xa0ae, 0x0000 },
+  { 0x0700, 0xa0b0, 0x0000 },
+  { 0x8700, 0xa0b3, 0x2000 },
+  { 0x0700, 0xa0b2, 0x0000 },
+  { 0x0700, 0xa0b4, 0x0000 },
+  { 0x8700, 0xa0b9, 0x3000 },
+  { 0x8700, 0xa0b7, 0x2000 },
+  { 0x0700, 0xa0b6, 0x0000 },
+  { 0x0700, 0xa0b8, 0x0000 },
+  { 0x8700, 0xa0bb, 0x2000 },
+  { 0x0700, 0xa0ba, 0x0000 },
+  { 0x0700, 0xa0bc, 0x0000 },
+  { 0x8700, 0xa0c5, 0x4000 },
+  { 0x8700, 0xa0c1, 0x3000 },
+  { 0x8700, 0xa0bf, 0x2000 },
+  { 0x0700, 0xa0be, 0x0000 },
+  { 0x0700, 0xa0c0, 0x0000 },
+  { 0x8700, 0xa0c3, 0x2000 },
+  { 0x0700, 0xa0c2, 0x0000 },
+  { 0x0700, 0xa0c4, 0x0000 },
+  { 0x8700, 0xa0c9, 0x3000 },
+  { 0x8700, 0xa0c7, 0x2000 },
+  { 0x0700, 0xa0c6, 0x0000 },
+  { 0x0700, 0xa0c8, 0x0000 },
+  { 0x8700, 0xa0cb, 0x2000 },
+  { 0x0700, 0xa0ca, 0x0000 },
+  { 0x0700, 0xa0cc, 0x0000 },
+  { 0x8700, 0xa10d, 0x7000 },
+  { 0x8700, 0xa0ed, 0x6000 },
+  { 0x8700, 0xa0dd, 0x5000 },
+  { 0x8700, 0xa0d5, 0x4000 },
+  { 0x8700, 0xa0d1, 0x3000 },
+  { 0x8700, 0xa0cf, 0x2000 },
+  { 0x0700, 0xa0ce, 0x0000 },
+  { 0x0700, 0xa0d0, 0x0000 },
+  { 0x8700, 0xa0d3, 0x2000 },
+  { 0x0700, 0xa0d2, 0x0000 },
+  { 0x0700, 0xa0d4, 0x0000 },
+  { 0x8700, 0xa0d9, 0x3000 },
+  { 0x8700, 0xa0d7, 0x2000 },
+  { 0x0700, 0xa0d6, 0x0000 },
+  { 0x0700, 0xa0d8, 0x0000 },
+  { 0x8700, 0xa0db, 0x2000 },
+  { 0x0700, 0xa0da, 0x0000 },
+  { 0x0700, 0xa0dc, 0x0000 },
+  { 0x8700, 0xa0e5, 0x4000 },
+  { 0x8700, 0xa0e1, 0x3000 },
+  { 0x8700, 0xa0df, 0x2000 },
+  { 0x0700, 0xa0de, 0x0000 },
+  { 0x0700, 0xa0e0, 0x0000 },
+  { 0x8700, 0xa0e3, 0x2000 },
+  { 0x0700, 0xa0e2, 0x0000 },
+  { 0x0700, 0xa0e4, 0x0000 },
+  { 0x8700, 0xa0e9, 0x3000 },
+  { 0x8700, 0xa0e7, 0x2000 },
+  { 0x0700, 0xa0e6, 0x0000 },
+  { 0x0700, 0xa0e8, 0x0000 },
+  { 0x8700, 0xa0eb, 0x2000 },
+  { 0x0700, 0xa0ea, 0x0000 },
+  { 0x0700, 0xa0ec, 0x0000 },
+  { 0x8700, 0xa0fd, 0x5000 },
+  { 0x8700, 0xa0f5, 0x4000 },
+  { 0x8700, 0xa0f1, 0x3000 },
+  { 0x8700, 0xa0ef, 0x2000 },
+  { 0x0700, 0xa0ee, 0x0000 },
+  { 0x0700, 0xa0f0, 0x0000 },
+  { 0x8700, 0xa0f3, 0x2000 },
+  { 0x0700, 0xa0f2, 0x0000 },
+  { 0x0700, 0xa0f4, 0x0000 },
+  { 0x8700, 0xa0f9, 0x3000 },
+  { 0x8700, 0xa0f7, 0x2000 },
+  { 0x0700, 0xa0f6, 0x0000 },
+  { 0x0700, 0xa0f8, 0x0000 },
+  { 0x8700, 0xa0fb, 0x2000 },
+  { 0x0700, 0xa0fa, 0x0000 },
+  { 0x0700, 0xa0fc, 0x0000 },
+  { 0x8700, 0xa105, 0x4000 },
+  { 0x8700, 0xa101, 0x3000 },
+  { 0x8700, 0xa0ff, 0x2000 },
+  { 0x0700, 0xa0fe, 0x0000 },
+  { 0x0700, 0xa100, 0x0000 },
+  { 0x8700, 0xa103, 0x2000 },
+  { 0x0700, 0xa102, 0x0000 },
+  { 0x0700, 0xa104, 0x0000 },
+  { 0x8700, 0xa109, 0x3000 },
+  { 0x8700, 0xa107, 0x2000 },
+  { 0x0700, 0xa106, 0x0000 },
+  { 0x0700, 0xa108, 0x0000 },
+  { 0x8700, 0xa10b, 0x2000 },
+  { 0x0700, 0xa10a, 0x0000 },
+  { 0x0700, 0xa10c, 0x0000 },
+  { 0x8700, 0xa12d, 0x6000 },
+  { 0x8700, 0xa11d, 0x5000 },
+  { 0x8700, 0xa115, 0x4000 },
+  { 0x8700, 0xa111, 0x3000 },
+  { 0x8700, 0xa10f, 0x2000 },
+  { 0x0700, 0xa10e, 0x0000 },
+  { 0x0700, 0xa110, 0x0000 },
+  { 0x8700, 0xa113, 0x2000 },
+  { 0x0700, 0xa112, 0x0000 },
+  { 0x0700, 0xa114, 0x0000 },
+  { 0x8700, 0xa119, 0x3000 },
+  { 0x8700, 0xa117, 0x2000 },
+  { 0x0700, 0xa116, 0x0000 },
+  { 0x0700, 0xa118, 0x0000 },
+  { 0x8700, 0xa11b, 0x2000 },
+  { 0x0700, 0xa11a, 0x0000 },
+  { 0x0700, 0xa11c, 0x0000 },
+  { 0x8700, 0xa125, 0x4000 },
+  { 0x8700, 0xa121, 0x3000 },
+  { 0x8700, 0xa11f, 0x2000 },
+  { 0x0700, 0xa11e, 0x0000 },
+  { 0x0700, 0xa120, 0x0000 },
+  { 0x8700, 0xa123, 0x2000 },
+  { 0x0700, 0xa122, 0x0000 },
+  { 0x0700, 0xa124, 0x0000 },
+  { 0x8700, 0xa129, 0x3000 },
+  { 0x8700, 0xa127, 0x2000 },
+  { 0x0700, 0xa126, 0x0000 },
+  { 0x0700, 0xa128, 0x0000 },
+  { 0x8700, 0xa12b, 0x2000 },
+  { 0x0700, 0xa12a, 0x0000 },
+  { 0x0700, 0xa12c, 0x0000 },
+  { 0x8700, 0xa13d, 0x5000 },
+  { 0x8700, 0xa135, 0x4000 },
+  { 0x8700, 0xa131, 0x3000 },
+  { 0x8700, 0xa12f, 0x2000 },
+  { 0x0700, 0xa12e, 0x0000 },
+  { 0x0700, 0xa130, 0x0000 },
+  { 0x8700, 0xa133, 0x2000 },
+  { 0x0700, 0xa132, 0x0000 },
+  { 0x0700, 0xa134, 0x0000 },
+  { 0x8700, 0xa139, 0x3000 },
+  { 0x8700, 0xa137, 0x2000 },
+  { 0x0700, 0xa136, 0x0000 },
+  { 0x0700, 0xa138, 0x0000 },
+  { 0x8700, 0xa13b, 0x2000 },
+  { 0x0700, 0xa13a, 0x0000 },
+  { 0x0700, 0xa13c, 0x0000 },
+  { 0x8700, 0xa145, 0x4000 },
+  { 0x8700, 0xa141, 0x3000 },
+  { 0x8700, 0xa13f, 0x2000 },
+  { 0x0700, 0xa13e, 0x0000 },
+  { 0x0700, 0xa140, 0x0000 },
+  { 0x8700, 0xa143, 0x2000 },
+  { 0x0700, 0xa142, 0x0000 },
+  { 0x0700, 0xa144, 0x0000 },
+  { 0x8700, 0xa149, 0x3000 },
+  { 0x8700, 0xa147, 0x2000 },
+  { 0x0700, 0xa146, 0x0000 },
+  { 0x0700, 0xa148, 0x0000 },
+  { 0x8700, 0xa14b, 0x2000 },
+  { 0x0700, 0xa14a, 0x0000 },
+  { 0x0700, 0xa14c, 0x0000 },
+  { 0x8700, 0xa24d, 0x9000 },
+  { 0x8700, 0xa1cd, 0x8000 },
+  { 0x8700, 0xa18d, 0x7000 },
+  { 0x8700, 0xa16d, 0x6000 },
+  { 0x8700, 0xa15d, 0x5000 },
+  { 0x8700, 0xa155, 0x4000 },
+  { 0x8700, 0xa151, 0x3000 },
+  { 0x8700, 0xa14f, 0x2000 },
+  { 0x0700, 0xa14e, 0x0000 },
+  { 0x0700, 0xa150, 0x0000 },
+  { 0x8700, 0xa153, 0x2000 },
+  { 0x0700, 0xa152, 0x0000 },
+  { 0x0700, 0xa154, 0x0000 },
+  { 0x8700, 0xa159, 0x3000 },
+  { 0x8700, 0xa157, 0x2000 },
+  { 0x0700, 0xa156, 0x0000 },
+  { 0x0700, 0xa158, 0x0000 },
+  { 0x8700, 0xa15b, 0x2000 },
+  { 0x0700, 0xa15a, 0x0000 },
+  { 0x0700, 0xa15c, 0x0000 },
+  { 0x8700, 0xa165, 0x4000 },
+  { 0x8700, 0xa161, 0x3000 },
+  { 0x8700, 0xa15f, 0x2000 },
+  { 0x0700, 0xa15e, 0x0000 },
+  { 0x0700, 0xa160, 0x0000 },
+  { 0x8700, 0xa163, 0x2000 },
+  { 0x0700, 0xa162, 0x0000 },
+  { 0x0700, 0xa164, 0x0000 },
+  { 0x8700, 0xa169, 0x3000 },
+  { 0x8700, 0xa167, 0x2000 },
+  { 0x0700, 0xa166, 0x0000 },
+  { 0x0700, 0xa168, 0x0000 },
+  { 0x8700, 0xa16b, 0x2000 },
+  { 0x0700, 0xa16a, 0x0000 },
+  { 0x0700, 0xa16c, 0x0000 },
+  { 0x8700, 0xa17d, 0x5000 },
+  { 0x8700, 0xa175, 0x4000 },
+  { 0x8700, 0xa171, 0x3000 },
+  { 0x8700, 0xa16f, 0x2000 },
+  { 0x0700, 0xa16e, 0x0000 },
+  { 0x0700, 0xa170, 0x0000 },
+  { 0x8700, 0xa173, 0x2000 },
+  { 0x0700, 0xa172, 0x0000 },
+  { 0x0700, 0xa174, 0x0000 },
+  { 0x8700, 0xa179, 0x3000 },
+  { 0x8700, 0xa177, 0x2000 },
+  { 0x0700, 0xa176, 0x0000 },
+  { 0x0700, 0xa178, 0x0000 },
+  { 0x8700, 0xa17b, 0x2000 },
+  { 0x0700, 0xa17a, 0x0000 },
+  { 0x0700, 0xa17c, 0x0000 },
+  { 0x8700, 0xa185, 0x4000 },
+  { 0x8700, 0xa181, 0x3000 },
+  { 0x8700, 0xa17f, 0x2000 },
+  { 0x0700, 0xa17e, 0x0000 },
+  { 0x0700, 0xa180, 0x0000 },
+  { 0x8700, 0xa183, 0x2000 },
+  { 0x0700, 0xa182, 0x0000 },
+  { 0x0700, 0xa184, 0x0000 },
+  { 0x8700, 0xa189, 0x3000 },
+  { 0x8700, 0xa187, 0x2000 },
+  { 0x0700, 0xa186, 0x0000 },
+  { 0x0700, 0xa188, 0x0000 },
+  { 0x8700, 0xa18b, 0x2000 },
+  { 0x0700, 0xa18a, 0x0000 },
+  { 0x0700, 0xa18c, 0x0000 },
+  { 0x8700, 0xa1ad, 0x6000 },
+  { 0x8700, 0xa19d, 0x5000 },
+  { 0x8700, 0xa195, 0x4000 },
+  { 0x8700, 0xa191, 0x3000 },
+  { 0x8700, 0xa18f, 0x2000 },
+  { 0x0700, 0xa18e, 0x0000 },
+  { 0x0700, 0xa190, 0x0000 },
+  { 0x8700, 0xa193, 0x2000 },
+  { 0x0700, 0xa192, 0x0000 },
+  { 0x0700, 0xa194, 0x0000 },
+  { 0x8700, 0xa199, 0x3000 },
+  { 0x8700, 0xa197, 0x2000 },
+  { 0x0700, 0xa196, 0x0000 },
+  { 0x0700, 0xa198, 0x0000 },
+  { 0x8700, 0xa19b, 0x2000 },
+  { 0x0700, 0xa19a, 0x0000 },
+  { 0x0700, 0xa19c, 0x0000 },
+  { 0x8700, 0xa1a5, 0x4000 },
+  { 0x8700, 0xa1a1, 0x3000 },
+  { 0x8700, 0xa19f, 0x2000 },
+  { 0x0700, 0xa19e, 0x0000 },
+  { 0x0700, 0xa1a0, 0x0000 },
+  { 0x8700, 0xa1a3, 0x2000 },
+  { 0x0700, 0xa1a2, 0x0000 },
+  { 0x0700, 0xa1a4, 0x0000 },
+  { 0x8700, 0xa1a9, 0x3000 },
+  { 0x8700, 0xa1a7, 0x2000 },
+  { 0x0700, 0xa1a6, 0x0000 },
+  { 0x0700, 0xa1a8, 0x0000 },
+  { 0x8700, 0xa1ab, 0x2000 },
+  { 0x0700, 0xa1aa, 0x0000 },
+  { 0x0700, 0xa1ac, 0x0000 },
+  { 0x8700, 0xa1bd, 0x5000 },
+  { 0x8700, 0xa1b5, 0x4000 },
+  { 0x8700, 0xa1b1, 0x3000 },
+  { 0x8700, 0xa1af, 0x2000 },
+  { 0x0700, 0xa1ae, 0x0000 },
+  { 0x0700, 0xa1b0, 0x0000 },
+  { 0x8700, 0xa1b3, 0x2000 },
+  { 0x0700, 0xa1b2, 0x0000 },
+  { 0x0700, 0xa1b4, 0x0000 },
+  { 0x8700, 0xa1b9, 0x3000 },
+  { 0x8700, 0xa1b7, 0x2000 },
+  { 0x0700, 0xa1b6, 0x0000 },
+  { 0x0700, 0xa1b8, 0x0000 },
+  { 0x8700, 0xa1bb, 0x2000 },
+  { 0x0700, 0xa1ba, 0x0000 },
+  { 0x0700, 0xa1bc, 0x0000 },
+  { 0x8700, 0xa1c5, 0x4000 },
+  { 0x8700, 0xa1c1, 0x3000 },
+  { 0x8700, 0xa1bf, 0x2000 },
+  { 0x0700, 0xa1be, 0x0000 },
+  { 0x0700, 0xa1c0, 0x0000 },
+  { 0x8700, 0xa1c3, 0x2000 },
+  { 0x0700, 0xa1c2, 0x0000 },
+  { 0x0700, 0xa1c4, 0x0000 },
+  { 0x8700, 0xa1c9, 0x3000 },
+  { 0x8700, 0xa1c7, 0x2000 },
+  { 0x0700, 0xa1c6, 0x0000 },
+  { 0x0700, 0xa1c8, 0x0000 },
+  { 0x8700, 0xa1cb, 0x2000 },
+  { 0x0700, 0xa1ca, 0x0000 },
+  { 0x0700, 0xa1cc, 0x0000 },
+  { 0x8700, 0xa20d, 0x7000 },
+  { 0x8700, 0xa1ed, 0x6000 },
+  { 0x8700, 0xa1dd, 0x5000 },
+  { 0x8700, 0xa1d5, 0x4000 },
+  { 0x8700, 0xa1d1, 0x3000 },
+  { 0x8700, 0xa1cf, 0x2000 },
+  { 0x0700, 0xa1ce, 0x0000 },
+  { 0x0700, 0xa1d0, 0x0000 },
+  { 0x8700, 0xa1d3, 0x2000 },
+  { 0x0700, 0xa1d2, 0x0000 },
+  { 0x0700, 0xa1d4, 0x0000 },
+  { 0x8700, 0xa1d9, 0x3000 },
+  { 0x8700, 0xa1d7, 0x2000 },
+  { 0x0700, 0xa1d6, 0x0000 },
+  { 0x0700, 0xa1d8, 0x0000 },
+  { 0x8700, 0xa1db, 0x2000 },
+  { 0x0700, 0xa1da, 0x0000 },
+  { 0x0700, 0xa1dc, 0x0000 },
+  { 0x8700, 0xa1e5, 0x4000 },
+  { 0x8700, 0xa1e1, 0x3000 },
+  { 0x8700, 0xa1df, 0x2000 },
+  { 0x0700, 0xa1de, 0x0000 },
+  { 0x0700, 0xa1e0, 0x0000 },
+  { 0x8700, 0xa1e3, 0x2000 },
+  { 0x0700, 0xa1e2, 0x0000 },
+  { 0x0700, 0xa1e4, 0x0000 },
+  { 0x8700, 0xa1e9, 0x3000 },
+  { 0x8700, 0xa1e7, 0x2000 },
+  { 0x0700, 0xa1e6, 0x0000 },
+  { 0x0700, 0xa1e8, 0x0000 },
+  { 0x8700, 0xa1eb, 0x2000 },
+  { 0x0700, 0xa1ea, 0x0000 },
+  { 0x0700, 0xa1ec, 0x0000 },
+  { 0x8700, 0xa1fd, 0x5000 },
+  { 0x8700, 0xa1f5, 0x4000 },
+  { 0x8700, 0xa1f1, 0x3000 },
+  { 0x8700, 0xa1ef, 0x2000 },
+  { 0x0700, 0xa1ee, 0x0000 },
+  { 0x0700, 0xa1f0, 0x0000 },
+  { 0x8700, 0xa1f3, 0x2000 },
+  { 0x0700, 0xa1f2, 0x0000 },
+  { 0x0700, 0xa1f4, 0x0000 },
+  { 0x8700, 0xa1f9, 0x3000 },
+  { 0x8700, 0xa1f7, 0x2000 },
+  { 0x0700, 0xa1f6, 0x0000 },
+  { 0x0700, 0xa1f8, 0x0000 },
+  { 0x8700, 0xa1fb, 0x2000 },
+  { 0x0700, 0xa1fa, 0x0000 },
+  { 0x0700, 0xa1fc, 0x0000 },
+  { 0x8700, 0xa205, 0x4000 },
+  { 0x8700, 0xa201, 0x3000 },
+  { 0x8700, 0xa1ff, 0x2000 },
+  { 0x0700, 0xa1fe, 0x0000 },
+  { 0x0700, 0xa200, 0x0000 },
+  { 0x8700, 0xa203, 0x2000 },
+  { 0x0700, 0xa202, 0x0000 },
+  { 0x0700, 0xa204, 0x0000 },
+  { 0x8700, 0xa209, 0x3000 },
+  { 0x8700, 0xa207, 0x2000 },
+  { 0x0700, 0xa206, 0x0000 },
+  { 0x0700, 0xa208, 0x0000 },
+  { 0x8700, 0xa20b, 0x2000 },
+  { 0x0700, 0xa20a, 0x0000 },
+  { 0x0700, 0xa20c, 0x0000 },
+  { 0x8700, 0xa22d, 0x6000 },
+  { 0x8700, 0xa21d, 0x5000 },
+  { 0x8700, 0xa215, 0x4000 },
+  { 0x8700, 0xa211, 0x3000 },
+  { 0x8700, 0xa20f, 0x2000 },
+  { 0x0700, 0xa20e, 0x0000 },
+  { 0x0700, 0xa210, 0x0000 },
+  { 0x8700, 0xa213, 0x2000 },
+  { 0x0700, 0xa212, 0x0000 },
+  { 0x0700, 0xa214, 0x0000 },
+  { 0x8700, 0xa219, 0x3000 },
+  { 0x8700, 0xa217, 0x2000 },
+  { 0x0700, 0xa216, 0x0000 },
+  { 0x0700, 0xa218, 0x0000 },
+  { 0x8700, 0xa21b, 0x2000 },
+  { 0x0700, 0xa21a, 0x0000 },
+  { 0x0700, 0xa21c, 0x0000 },
+  { 0x8700, 0xa225, 0x4000 },
+  { 0x8700, 0xa221, 0x3000 },
+  { 0x8700, 0xa21f, 0x2000 },
+  { 0x0700, 0xa21e, 0x0000 },
+  { 0x0700, 0xa220, 0x0000 },
+  { 0x8700, 0xa223, 0x2000 },
+  { 0x0700, 0xa222, 0x0000 },
+  { 0x0700, 0xa224, 0x0000 },
+  { 0x8700, 0xa229, 0x3000 },
+  { 0x8700, 0xa227, 0x2000 },
+  { 0x0700, 0xa226, 0x0000 },
+  { 0x0700, 0xa228, 0x0000 },
+  { 0x8700, 0xa22b, 0x2000 },
+  { 0x0700, 0xa22a, 0x0000 },
+  { 0x0700, 0xa22c, 0x0000 },
+  { 0x8700, 0xa23d, 0x5000 },
+  { 0x8700, 0xa235, 0x4000 },
+  { 0x8700, 0xa231, 0x3000 },
+  { 0x8700, 0xa22f, 0x2000 },
+  { 0x0700, 0xa22e, 0x0000 },
+  { 0x0700, 0xa230, 0x0000 },
+  { 0x8700, 0xa233, 0x2000 },
+  { 0x0700, 0xa232, 0x0000 },
+  { 0x0700, 0xa234, 0x0000 },
+  { 0x8700, 0xa239, 0x3000 },
+  { 0x8700, 0xa237, 0x2000 },
+  { 0x0700, 0xa236, 0x0000 },
+  { 0x0700, 0xa238, 0x0000 },
+  { 0x8700, 0xa23b, 0x2000 },
+  { 0x0700, 0xa23a, 0x0000 },
+  { 0x0700, 0xa23c, 0x0000 },
+  { 0x8700, 0xa245, 0x4000 },
+  { 0x8700, 0xa241, 0x3000 },
+  { 0x8700, 0xa23f, 0x2000 },
+  { 0x0700, 0xa23e, 0x0000 },
+  { 0x0700, 0xa240, 0x0000 },
+  { 0x8700, 0xa243, 0x2000 },
+  { 0x0700, 0xa242, 0x0000 },
+  { 0x0700, 0xa244, 0x0000 },
+  { 0x8700, 0xa249, 0x3000 },
+  { 0x8700, 0xa247, 0x2000 },
+  { 0x0700, 0xa246, 0x0000 },
+  { 0x0700, 0xa248, 0x0000 },
+  { 0x8700, 0xa24b, 0x2000 },
+  { 0x0700, 0xa24a, 0x0000 },
+  { 0x0700, 0xa24c, 0x0000 },
+  { 0x8700, 0xa2cd, 0x8000 },
+  { 0x8700, 0xa28d, 0x7000 },
+  { 0x8700, 0xa26d, 0x6000 },
+  { 0x8700, 0xa25d, 0x5000 },
+  { 0x8700, 0xa255, 0x4000 },
+  { 0x8700, 0xa251, 0x3000 },
+  { 0x8700, 0xa24f, 0x2000 },
+  { 0x0700, 0xa24e, 0x0000 },
+  { 0x0700, 0xa250, 0x0000 },
+  { 0x8700, 0xa253, 0x2000 },
+  { 0x0700, 0xa252, 0x0000 },
+  { 0x0700, 0xa254, 0x0000 },
+  { 0x8700, 0xa259, 0x3000 },
+  { 0x8700, 0xa257, 0x2000 },
+  { 0x0700, 0xa256, 0x0000 },
+  { 0x0700, 0xa258, 0x0000 },
+  { 0x8700, 0xa25b, 0x2000 },
+  { 0x0700, 0xa25a, 0x0000 },
+  { 0x0700, 0xa25c, 0x0000 },
+  { 0x8700, 0xa265, 0x4000 },
+  { 0x8700, 0xa261, 0x3000 },
+  { 0x8700, 0xa25f, 0x2000 },
+  { 0x0700, 0xa25e, 0x0000 },
+  { 0x0700, 0xa260, 0x0000 },
+  { 0x8700, 0xa263, 0x2000 },
+  { 0x0700, 0xa262, 0x0000 },
+  { 0x0700, 0xa264, 0x0000 },
+  { 0x8700, 0xa269, 0x3000 },
+  { 0x8700, 0xa267, 0x2000 },
+  { 0x0700, 0xa266, 0x0000 },
+  { 0x0700, 0xa268, 0x0000 },
+  { 0x8700, 0xa26b, 0x2000 },
+  { 0x0700, 0xa26a, 0x0000 },
+  { 0x0700, 0xa26c, 0x0000 },
+  { 0x8700, 0xa27d, 0x5000 },
+  { 0x8700, 0xa275, 0x4000 },
+  { 0x8700, 0xa271, 0x3000 },
+  { 0x8700, 0xa26f, 0x2000 },
+  { 0x0700, 0xa26e, 0x0000 },
+  { 0x0700, 0xa270, 0x0000 },
+  { 0x8700, 0xa273, 0x2000 },
+  { 0x0700, 0xa272, 0x0000 },
+  { 0x0700, 0xa274, 0x0000 },
+  { 0x8700, 0xa279, 0x3000 },
+  { 0x8700, 0xa277, 0x2000 },
+  { 0x0700, 0xa276, 0x0000 },
+  { 0x0700, 0xa278, 0x0000 },
+  { 0x8700, 0xa27b, 0x2000 },
+  { 0x0700, 0xa27a, 0x0000 },
+  { 0x0700, 0xa27c, 0x0000 },
+  { 0x8700, 0xa285, 0x4000 },
+  { 0x8700, 0xa281, 0x3000 },
+  { 0x8700, 0xa27f, 0x2000 },
+  { 0x0700, 0xa27e, 0x0000 },
+  { 0x0700, 0xa280, 0x0000 },
+  { 0x8700, 0xa283, 0x2000 },
+  { 0x0700, 0xa282, 0x0000 },
+  { 0x0700, 0xa284, 0x0000 },
+  { 0x8700, 0xa289, 0x3000 },
+  { 0x8700, 0xa287, 0x2000 },
+  { 0x0700, 0xa286, 0x0000 },
+  { 0x0700, 0xa288, 0x0000 },
+  { 0x8700, 0xa28b, 0x2000 },
+  { 0x0700, 0xa28a, 0x0000 },
+  { 0x0700, 0xa28c, 0x0000 },
+  { 0x8700, 0xa2ad, 0x6000 },
+  { 0x8700, 0xa29d, 0x5000 },
+  { 0x8700, 0xa295, 0x4000 },
+  { 0x8700, 0xa291, 0x3000 },
+  { 0x8700, 0xa28f, 0x2000 },
+  { 0x0700, 0xa28e, 0x0000 },
+  { 0x0700, 0xa290, 0x0000 },
+  { 0x8700, 0xa293, 0x2000 },
+  { 0x0700, 0xa292, 0x0000 },
+  { 0x0700, 0xa294, 0x0000 },
+  { 0x8700, 0xa299, 0x3000 },
+  { 0x8700, 0xa297, 0x2000 },
+  { 0x0700, 0xa296, 0x0000 },
+  { 0x0700, 0xa298, 0x0000 },
+  { 0x8700, 0xa29b, 0x2000 },
+  { 0x0700, 0xa29a, 0x0000 },
+  { 0x0700, 0xa29c, 0x0000 },
+  { 0x8700, 0xa2a5, 0x4000 },
+  { 0x8700, 0xa2a1, 0x3000 },
+  { 0x8700, 0xa29f, 0x2000 },
+  { 0x0700, 0xa29e, 0x0000 },
+  { 0x0700, 0xa2a0, 0x0000 },
+  { 0x8700, 0xa2a3, 0x2000 },
+  { 0x0700, 0xa2a2, 0x0000 },
+  { 0x0700, 0xa2a4, 0x0000 },
+  { 0x8700, 0xa2a9, 0x3000 },
+  { 0x8700, 0xa2a7, 0x2000 },
+  { 0x0700, 0xa2a6, 0x0000 },
+  { 0x0700, 0xa2a8, 0x0000 },
+  { 0x8700, 0xa2ab, 0x2000 },
+  { 0x0700, 0xa2aa, 0x0000 },
+  { 0x0700, 0xa2ac, 0x0000 },
+  { 0x8700, 0xa2bd, 0x5000 },
+  { 0x8700, 0xa2b5, 0x4000 },
+  { 0x8700, 0xa2b1, 0x3000 },
+  { 0x8700, 0xa2af, 0x2000 },
+  { 0x0700, 0xa2ae, 0x0000 },
+  { 0x0700, 0xa2b0, 0x0000 },
+  { 0x8700, 0xa2b3, 0x2000 },
+  { 0x0700, 0xa2b2, 0x0000 },
+  { 0x0700, 0xa2b4, 0x0000 },
+  { 0x8700, 0xa2b9, 0x3000 },
+  { 0x8700, 0xa2b7, 0x2000 },
+  { 0x0700, 0xa2b6, 0x0000 },
+  { 0x0700, 0xa2b8, 0x0000 },
+  { 0x8700, 0xa2bb, 0x2000 },
+  { 0x0700, 0xa2ba, 0x0000 },
+  { 0x0700, 0xa2bc, 0x0000 },
+  { 0x8700, 0xa2c5, 0x4000 },
+  { 0x8700, 0xa2c1, 0x3000 },
+  { 0x8700, 0xa2bf, 0x2000 },
+  { 0x0700, 0xa2be, 0x0000 },
+  { 0x0700, 0xa2c0, 0x0000 },
+  { 0x8700, 0xa2c3, 0x2000 },
+  { 0x0700, 0xa2c2, 0x0000 },
+  { 0x0700, 0xa2c4, 0x0000 },
+  { 0x8700, 0xa2c9, 0x3000 },
+  { 0x8700, 0xa2c7, 0x2000 },
+  { 0x0700, 0xa2c6, 0x0000 },
+  { 0x0700, 0xa2c8, 0x0000 },
+  { 0x8700, 0xa2cb, 0x2000 },
+  { 0x0700, 0xa2ca, 0x0000 },
+  { 0x0700, 0xa2cc, 0x0000 },
+  { 0x8700, 0xa30d, 0x7000 },
+  { 0x8700, 0xa2ed, 0x6000 },
+  { 0x8700, 0xa2dd, 0x5000 },
+  { 0x8700, 0xa2d5, 0x4000 },
+  { 0x8700, 0xa2d1, 0x3000 },
+  { 0x8700, 0xa2cf, 0x2000 },
+  { 0x0700, 0xa2ce, 0x0000 },
+  { 0x0700, 0xa2d0, 0x0000 },
+  { 0x8700, 0xa2d3, 0x2000 },
+  { 0x0700, 0xa2d2, 0x0000 },
+  { 0x0700, 0xa2d4, 0x0000 },
+  { 0x8700, 0xa2d9, 0x3000 },
+  { 0x8700, 0xa2d7, 0x2000 },
+  { 0x0700, 0xa2d6, 0x0000 },
+  { 0x0700, 0xa2d8, 0x0000 },
+  { 0x8700, 0xa2db, 0x2000 },
+  { 0x0700, 0xa2da, 0x0000 },
+  { 0x0700, 0xa2dc, 0x0000 },
+  { 0x8700, 0xa2e5, 0x4000 },
+  { 0x8700, 0xa2e1, 0x3000 },
+  { 0x8700, 0xa2df, 0x2000 },
+  { 0x0700, 0xa2de, 0x0000 },
+  { 0x0700, 0xa2e0, 0x0000 },
+  { 0x8700, 0xa2e3, 0x2000 },
+  { 0x0700, 0xa2e2, 0x0000 },
+  { 0x0700, 0xa2e4, 0x0000 },
+  { 0x8700, 0xa2e9, 0x3000 },
+  { 0x8700, 0xa2e7, 0x2000 },
+  { 0x0700, 0xa2e6, 0x0000 },
+  { 0x0700, 0xa2e8, 0x0000 },
+  { 0x8700, 0xa2eb, 0x2000 },
+  { 0x0700, 0xa2ea, 0x0000 },
+  { 0x0700, 0xa2ec, 0x0000 },
+  { 0x8700, 0xa2fd, 0x5000 },
+  { 0x8700, 0xa2f5, 0x4000 },
+  { 0x8700, 0xa2f1, 0x3000 },
+  { 0x8700, 0xa2ef, 0x2000 },
+  { 0x0700, 0xa2ee, 0x0000 },
+  { 0x0700, 0xa2f0, 0x0000 },
+  { 0x8700, 0xa2f3, 0x2000 },
+  { 0x0700, 0xa2f2, 0x0000 },
+  { 0x0700, 0xa2f4, 0x0000 },
+  { 0x8700, 0xa2f9, 0x3000 },
+  { 0x8700, 0xa2f7, 0x2000 },
+  { 0x0700, 0xa2f6, 0x0000 },
+  { 0x0700, 0xa2f8, 0x0000 },
+  { 0x8700, 0xa2fb, 0x2000 },
+  { 0x0700, 0xa2fa, 0x0000 },
+  { 0x0700, 0xa2fc, 0x0000 },
+  { 0x8700, 0xa305, 0x4000 },
+  { 0x8700, 0xa301, 0x3000 },
+  { 0x8700, 0xa2ff, 0x2000 },
+  { 0x0700, 0xa2fe, 0x0000 },
+  { 0x0700, 0xa300, 0x0000 },
+  { 0x8700, 0xa303, 0x2000 },
+  { 0x0700, 0xa302, 0x0000 },
+  { 0x0700, 0xa304, 0x0000 },
+  { 0x8700, 0xa309, 0x3000 },
+  { 0x8700, 0xa307, 0x2000 },
+  { 0x0700, 0xa306, 0x0000 },
+  { 0x0700, 0xa308, 0x0000 },
+  { 0x8700, 0xa30b, 0x2000 },
+  { 0x0700, 0xa30a, 0x0000 },
+  { 0x0700, 0xa30c, 0x0000 },
+  { 0x8700, 0xa32d, 0x6000 },
+  { 0x8700, 0xa31d, 0x5000 },
+  { 0x8700, 0xa315, 0x4000 },
+  { 0x8700, 0xa311, 0x3000 },
+  { 0x8700, 0xa30f, 0x2000 },
+  { 0x0700, 0xa30e, 0x0000 },
+  { 0x0700, 0xa310, 0x0000 },
+  { 0x8700, 0xa313, 0x2000 },
+  { 0x0700, 0xa312, 0x0000 },
+  { 0x0700, 0xa314, 0x0000 },
+  { 0x8700, 0xa319, 0x3000 },
+  { 0x8700, 0xa317, 0x2000 },
+  { 0x0700, 0xa316, 0x0000 },
+  { 0x0700, 0xa318, 0x0000 },
+  { 0x8700, 0xa31b, 0x2000 },
+  { 0x0700, 0xa31a, 0x0000 },
+  { 0x0700, 0xa31c, 0x0000 },
+  { 0x8700, 0xa325, 0x4000 },
+  { 0x8700, 0xa321, 0x3000 },
+  { 0x8700, 0xa31f, 0x2000 },
+  { 0x0700, 0xa31e, 0x0000 },
+  { 0x0700, 0xa320, 0x0000 },
+  { 0x8700, 0xa323, 0x2000 },
+  { 0x0700, 0xa322, 0x0000 },
+  { 0x0700, 0xa324, 0x0000 },
+  { 0x8700, 0xa329, 0x3000 },
+  { 0x8700, 0xa327, 0x2000 },
+  { 0x0700, 0xa326, 0x0000 },
+  { 0x0700, 0xa328, 0x0000 },
+  { 0x8700, 0xa32b, 0x2000 },
+  { 0x0700, 0xa32a, 0x0000 },
+  { 0x0700, 0xa32c, 0x0000 },
+  { 0x8700, 0xa33d, 0x5000 },
+  { 0x8700, 0xa335, 0x4000 },
+  { 0x8700, 0xa331, 0x3000 },
+  { 0x8700, 0xa32f, 0x2000 },
+  { 0x0700, 0xa32e, 0x0000 },
+  { 0x0700, 0xa330, 0x0000 },
+  { 0x8700, 0xa333, 0x2000 },
+  { 0x0700, 0xa332, 0x0000 },
+  { 0x0700, 0xa334, 0x0000 },
+  { 0x8700, 0xa339, 0x3000 },
+  { 0x8700, 0xa337, 0x2000 },
+  { 0x0700, 0xa336, 0x0000 },
+  { 0x0700, 0xa338, 0x0000 },
+  { 0x8700, 0xa33b, 0x2000 },
+  { 0x0700, 0xa33a, 0x0000 },
+  { 0x0700, 0xa33c, 0x0000 },
+  { 0x8700, 0xa345, 0x4000 },
+  { 0x8700, 0xa341, 0x3000 },
+  { 0x8700, 0xa33f, 0x2000 },
+  { 0x0700, 0xa33e, 0x0000 },
+  { 0x0700, 0xa340, 0x0000 },
+  { 0x8700, 0xa343, 0x2000 },
+  { 0x0700, 0xa342, 0x0000 },
+  { 0x0700, 0xa344, 0x0000 },
+  { 0x8700, 0xa349, 0x3000 },
+  { 0x8700, 0xa347, 0x2000 },
+  { 0x0700, 0xa346, 0x0000 },
+  { 0x0700, 0xa348, 0x0000 },
+  { 0x8700, 0xa34b, 0x2000 },
+  { 0x0700, 0xa34a, 0x0000 },
+  { 0x0700, 0xa34c, 0x0000 },
+  { 0x8700, 0xfc4d, 0xb000 },
+  { 0x8700, 0xf97f, 0xa000 },
+  { 0x8700, 0xa44d, 0x9000 },
+  { 0x8700, 0xa3cd, 0x8000 },
+  { 0x8700, 0xa38d, 0x7000 },
+  { 0x8700, 0xa36d, 0x6000 },
+  { 0x8700, 0xa35d, 0x5000 },
+  { 0x8700, 0xa355, 0x4000 },
+  { 0x8700, 0xa351, 0x3000 },
+  { 0x8700, 0xa34f, 0x2000 },
+  { 0x0700, 0xa34e, 0x0000 },
+  { 0x0700, 0xa350, 0x0000 },
+  { 0x8700, 0xa353, 0x2000 },
+  { 0x0700, 0xa352, 0x0000 },
+  { 0x0700, 0xa354, 0x0000 },
+  { 0x8700, 0xa359, 0x3000 },
+  { 0x8700, 0xa357, 0x2000 },
+  { 0x0700, 0xa356, 0x0000 },
+  { 0x0700, 0xa358, 0x0000 },
+  { 0x8700, 0xa35b, 0x2000 },
+  { 0x0700, 0xa35a, 0x0000 },
+  { 0x0700, 0xa35c, 0x0000 },
+  { 0x8700, 0xa365, 0x4000 },
+  { 0x8700, 0xa361, 0x3000 },
+  { 0x8700, 0xa35f, 0x2000 },
+  { 0x0700, 0xa35e, 0x0000 },
+  { 0x0700, 0xa360, 0x0000 },
+  { 0x8700, 0xa363, 0x2000 },
+  { 0x0700, 0xa362, 0x0000 },
+  { 0x0700, 0xa364, 0x0000 },
+  { 0x8700, 0xa369, 0x3000 },
+  { 0x8700, 0xa367, 0x2000 },
+  { 0x0700, 0xa366, 0x0000 },
+  { 0x0700, 0xa368, 0x0000 },
+  { 0x8700, 0xa36b, 0x2000 },
+  { 0x0700, 0xa36a, 0x0000 },
+  { 0x0700, 0xa36c, 0x0000 },
+  { 0x8700, 0xa37d, 0x5000 },
+  { 0x8700, 0xa375, 0x4000 },
+  { 0x8700, 0xa371, 0x3000 },
+  { 0x8700, 0xa36f, 0x2000 },
+  { 0x0700, 0xa36e, 0x0000 },
+  { 0x0700, 0xa370, 0x0000 },
+  { 0x8700, 0xa373, 0x2000 },
+  { 0x0700, 0xa372, 0x0000 },
+  { 0x0700, 0xa374, 0x0000 },
+  { 0x8700, 0xa379, 0x3000 },
+  { 0x8700, 0xa377, 0x2000 },
+  { 0x0700, 0xa376, 0x0000 },
+  { 0x0700, 0xa378, 0x0000 },
+  { 0x8700, 0xa37b, 0x2000 },
+  { 0x0700, 0xa37a, 0x0000 },
+  { 0x0700, 0xa37c, 0x0000 },
+  { 0x8700, 0xa385, 0x4000 },
+  { 0x8700, 0xa381, 0x3000 },
+  { 0x8700, 0xa37f, 0x2000 },
+  { 0x0700, 0xa37e, 0x0000 },
+  { 0x0700, 0xa380, 0x0000 },
+  { 0x8700, 0xa383, 0x2000 },
+  { 0x0700, 0xa382, 0x0000 },
+  { 0x0700, 0xa384, 0x0000 },
+  { 0x8700, 0xa389, 0x3000 },
+  { 0x8700, 0xa387, 0x2000 },
+  { 0x0700, 0xa386, 0x0000 },
+  { 0x0700, 0xa388, 0x0000 },
+  { 0x8700, 0xa38b, 0x2000 },
+  { 0x0700, 0xa38a, 0x0000 },
+  { 0x0700, 0xa38c, 0x0000 },
+  { 0x8700, 0xa3ad, 0x6000 },
+  { 0x8700, 0xa39d, 0x5000 },
+  { 0x8700, 0xa395, 0x4000 },
+  { 0x8700, 0xa391, 0x3000 },
+  { 0x8700, 0xa38f, 0x2000 },
+  { 0x0700, 0xa38e, 0x0000 },
+  { 0x0700, 0xa390, 0x0000 },
+  { 0x8700, 0xa393, 0x2000 },
+  { 0x0700, 0xa392, 0x0000 },
+  { 0x0700, 0xa394, 0x0000 },
+  { 0x8700, 0xa399, 0x3000 },
+  { 0x8700, 0xa397, 0x2000 },
+  { 0x0700, 0xa396, 0x0000 },
+  { 0x0700, 0xa398, 0x0000 },
+  { 0x8700, 0xa39b, 0x2000 },
+  { 0x0700, 0xa39a, 0x0000 },
+  { 0x0700, 0xa39c, 0x0000 },
+  { 0x8700, 0xa3a5, 0x4000 },
+  { 0x8700, 0xa3a1, 0x3000 },
+  { 0x8700, 0xa39f, 0x2000 },
+  { 0x0700, 0xa39e, 0x0000 },
+  { 0x0700, 0xa3a0, 0x0000 },
+  { 0x8700, 0xa3a3, 0x2000 },
+  { 0x0700, 0xa3a2, 0x0000 },
+  { 0x0700, 0xa3a4, 0x0000 },
+  { 0x8700, 0xa3a9, 0x3000 },
+  { 0x8700, 0xa3a7, 0x2000 },
+  { 0x0700, 0xa3a6, 0x0000 },
+  { 0x0700, 0xa3a8, 0x0000 },
+  { 0x8700, 0xa3ab, 0x2000 },
+  { 0x0700, 0xa3aa, 0x0000 },
+  { 0x0700, 0xa3ac, 0x0000 },
+  { 0x8700, 0xa3bd, 0x5000 },
+  { 0x8700, 0xa3b5, 0x4000 },
+  { 0x8700, 0xa3b1, 0x3000 },
+  { 0x8700, 0xa3af, 0x2000 },
+  { 0x0700, 0xa3ae, 0x0000 },
+  { 0x0700, 0xa3b0, 0x0000 },
+  { 0x8700, 0xa3b3, 0x2000 },
+  { 0x0700, 0xa3b2, 0x0000 },
+  { 0x0700, 0xa3b4, 0x0000 },
+  { 0x8700, 0xa3b9, 0x3000 },
+  { 0x8700, 0xa3b7, 0x2000 },
+  { 0x0700, 0xa3b6, 0x0000 },
+  { 0x0700, 0xa3b8, 0x0000 },
+  { 0x8700, 0xa3bb, 0x2000 },
+  { 0x0700, 0xa3ba, 0x0000 },
+  { 0x0700, 0xa3bc, 0x0000 },
+  { 0x8700, 0xa3c5, 0x4000 },
+  { 0x8700, 0xa3c1, 0x3000 },
+  { 0x8700, 0xa3bf, 0x2000 },
+  { 0x0700, 0xa3be, 0x0000 },
+  { 0x0700, 0xa3c0, 0x0000 },
+  { 0x8700, 0xa3c3, 0x2000 },
+  { 0x0700, 0xa3c2, 0x0000 },
+  { 0x0700, 0xa3c4, 0x0000 },
+  { 0x8700, 0xa3c9, 0x3000 },
+  { 0x8700, 0xa3c7, 0x2000 },
+  { 0x0700, 0xa3c6, 0x0000 },
+  { 0x0700, 0xa3c8, 0x0000 },
+  { 0x8700, 0xa3cb, 0x2000 },
+  { 0x0700, 0xa3ca, 0x0000 },
+  { 0x0700, 0xa3cc, 0x0000 },
+  { 0x8700, 0xa40d, 0x7000 },
+  { 0x8700, 0xa3ed, 0x6000 },
+  { 0x8700, 0xa3dd, 0x5000 },
+  { 0x8700, 0xa3d5, 0x4000 },
+  { 0x8700, 0xa3d1, 0x3000 },
+  { 0x8700, 0xa3cf, 0x2000 },
+  { 0x0700, 0xa3ce, 0x0000 },
+  { 0x0700, 0xa3d0, 0x0000 },
+  { 0x8700, 0xa3d3, 0x2000 },
+  { 0x0700, 0xa3d2, 0x0000 },
+  { 0x0700, 0xa3d4, 0x0000 },
+  { 0x8700, 0xa3d9, 0x3000 },
+  { 0x8700, 0xa3d7, 0x2000 },
+  { 0x0700, 0xa3d6, 0x0000 },
+  { 0x0700, 0xa3d8, 0x0000 },
+  { 0x8700, 0xa3db, 0x2000 },
+  { 0x0700, 0xa3da, 0x0000 },
+  { 0x0700, 0xa3dc, 0x0000 },
+  { 0x8700, 0xa3e5, 0x4000 },
+  { 0x8700, 0xa3e1, 0x3000 },
+  { 0x8700, 0xa3df, 0x2000 },
+  { 0x0700, 0xa3de, 0x0000 },
+  { 0x0700, 0xa3e0, 0x0000 },
+  { 0x8700, 0xa3e3, 0x2000 },
+  { 0x0700, 0xa3e2, 0x0000 },
+  { 0x0700, 0xa3e4, 0x0000 },
+  { 0x8700, 0xa3e9, 0x3000 },
+  { 0x8700, 0xa3e7, 0x2000 },
+  { 0x0700, 0xa3e6, 0x0000 },
+  { 0x0700, 0xa3e8, 0x0000 },
+  { 0x8700, 0xa3eb, 0x2000 },
+  { 0x0700, 0xa3ea, 0x0000 },
+  { 0x0700, 0xa3ec, 0x0000 },
+  { 0x8700, 0xa3fd, 0x5000 },
+  { 0x8700, 0xa3f5, 0x4000 },
+  { 0x8700, 0xa3f1, 0x3000 },
+  { 0x8700, 0xa3ef, 0x2000 },
+  { 0x0700, 0xa3ee, 0x0000 },
+  { 0x0700, 0xa3f0, 0x0000 },
+  { 0x8700, 0xa3f3, 0x2000 },
+  { 0x0700, 0xa3f2, 0x0000 },
+  { 0x0700, 0xa3f4, 0x0000 },
+  { 0x8700, 0xa3f9, 0x3000 },
+  { 0x8700, 0xa3f7, 0x2000 },
+  { 0x0700, 0xa3f6, 0x0000 },
+  { 0x0700, 0xa3f8, 0x0000 },
+  { 0x8700, 0xa3fb, 0x2000 },
+  { 0x0700, 0xa3fa, 0x0000 },
+  { 0x0700, 0xa3fc, 0x0000 },
+  { 0x8700, 0xa405, 0x4000 },
+  { 0x8700, 0xa401, 0x3000 },
+  { 0x8700, 0xa3ff, 0x2000 },
+  { 0x0700, 0xa3fe, 0x0000 },
+  { 0x0700, 0xa400, 0x0000 },
+  { 0x8700, 0xa403, 0x2000 },
+  { 0x0700, 0xa402, 0x0000 },
+  { 0x0700, 0xa404, 0x0000 },
+  { 0x8700, 0xa409, 0x3000 },
+  { 0x8700, 0xa407, 0x2000 },
+  { 0x0700, 0xa406, 0x0000 },
+  { 0x0700, 0xa408, 0x0000 },
+  { 0x8700, 0xa40b, 0x2000 },
+  { 0x0700, 0xa40a, 0x0000 },
+  { 0x0700, 0xa40c, 0x0000 },
+  { 0x8700, 0xa42d, 0x6000 },
+  { 0x8700, 0xa41d, 0x5000 },
+  { 0x8700, 0xa415, 0x4000 },
+  { 0x8700, 0xa411, 0x3000 },
+  { 0x8700, 0xa40f, 0x2000 },
+  { 0x0700, 0xa40e, 0x0000 },
+  { 0x0700, 0xa410, 0x0000 },
+  { 0x8700, 0xa413, 0x2000 },
+  { 0x0700, 0xa412, 0x0000 },
+  { 0x0700, 0xa414, 0x0000 },
+  { 0x8700, 0xa419, 0x3000 },
+  { 0x8700, 0xa417, 0x2000 },
+  { 0x0700, 0xa416, 0x0000 },
+  { 0x0700, 0xa418, 0x0000 },
+  { 0x8700, 0xa41b, 0x2000 },
+  { 0x0700, 0xa41a, 0x0000 },
+  { 0x0700, 0xa41c, 0x0000 },
+  { 0x8700, 0xa425, 0x4000 },
+  { 0x8700, 0xa421, 0x3000 },
+  { 0x8700, 0xa41f, 0x2000 },
+  { 0x0700, 0xa41e, 0x0000 },
+  { 0x0700, 0xa420, 0x0000 },
+  { 0x8700, 0xa423, 0x2000 },
+  { 0x0700, 0xa422, 0x0000 },
+  { 0x0700, 0xa424, 0x0000 },
+  { 0x8700, 0xa429, 0x3000 },
+  { 0x8700, 0xa427, 0x2000 },
+  { 0x0700, 0xa426, 0x0000 },
+  { 0x0700, 0xa428, 0x0000 },
+  { 0x8700, 0xa42b, 0x2000 },
+  { 0x0700, 0xa42a, 0x0000 },
+  { 0x0700, 0xa42c, 0x0000 },
+  { 0x8700, 0xa43d, 0x5000 },
+  { 0x8700, 0xa435, 0x4000 },
+  { 0x8700, 0xa431, 0x3000 },
+  { 0x8700, 0xa42f, 0x2000 },
+  { 0x0700, 0xa42e, 0x0000 },
+  { 0x0700, 0xa430, 0x0000 },
+  { 0x8700, 0xa433, 0x2000 },
+  { 0x0700, 0xa432, 0x0000 },
+  { 0x0700, 0xa434, 0x0000 },
+  { 0x8700, 0xa439, 0x3000 },
+  { 0x8700, 0xa437, 0x2000 },
+  { 0x0700, 0xa436, 0x0000 },
+  { 0x0700, 0xa438, 0x0000 },
+  { 0x8700, 0xa43b, 0x2000 },
+  { 0x0700, 0xa43a, 0x0000 },
+  { 0x0700, 0xa43c, 0x0000 },
+  { 0x8700, 0xa445, 0x4000 },
+  { 0x8700, 0xa441, 0x3000 },
+  { 0x8700, 0xa43f, 0x2000 },
+  { 0x0700, 0xa43e, 0x0000 },
+  { 0x0700, 0xa440, 0x0000 },
+  { 0x8700, 0xa443, 0x2000 },
+  { 0x0700, 0xa442, 0x0000 },
+  { 0x0700, 0xa444, 0x0000 },
+  { 0x8700, 0xa449, 0x3000 },
+  { 0x8700, 0xa447, 0x2000 },
+  { 0x0700, 0xa446, 0x0000 },
+  { 0x0700, 0xa448, 0x0000 },
+  { 0x8700, 0xa44b, 0x2000 },
+  { 0x0700, 0xa44a, 0x0000 },
+  { 0x0700, 0xa44c, 0x0000 },
+  { 0x8300, 0xf8ff, 0x8000 },
+  { 0x9a00, 0xa490, 0x7000 },
+  { 0x8700, 0xa46d, 0x6000 },
+  { 0x8700, 0xa45d, 0x5000 },
+  { 0x8700, 0xa455, 0x4000 },
+  { 0x8700, 0xa451, 0x3000 },
+  { 0x8700, 0xa44f, 0x2000 },
+  { 0x0700, 0xa44e, 0x0000 },
+  { 0x0700, 0xa450, 0x0000 },
+  { 0x8700, 0xa453, 0x2000 },
+  { 0x0700, 0xa452, 0x0000 },
+  { 0x0700, 0xa454, 0x0000 },
+  { 0x8700, 0xa459, 0x3000 },
+  { 0x8700, 0xa457, 0x2000 },
+  { 0x0700, 0xa456, 0x0000 },
+  { 0x0700, 0xa458, 0x0000 },
+  { 0x8700, 0xa45b, 0x2000 },
+  { 0x0700, 0xa45a, 0x0000 },
+  { 0x0700, 0xa45c, 0x0000 },
+  { 0x8700, 0xa465, 0x4000 },
+  { 0x8700, 0xa461, 0x3000 },
+  { 0x8700, 0xa45f, 0x2000 },
+  { 0x0700, 0xa45e, 0x0000 },
+  { 0x0700, 0xa460, 0x0000 },
+  { 0x8700, 0xa463, 0x2000 },
+  { 0x0700, 0xa462, 0x0000 },
+  { 0x0700, 0xa464, 0x0000 },
+  { 0x8700, 0xa469, 0x3000 },
+  { 0x8700, 0xa467, 0x2000 },
+  { 0x0700, 0xa466, 0x0000 },
+  { 0x0700, 0xa468, 0x0000 },
+  { 0x8700, 0xa46b, 0x2000 },
+  { 0x0700, 0xa46a, 0x0000 },
+  { 0x0700, 0xa46c, 0x0000 },
+  { 0x8700, 0xa47d, 0x5000 },
+  { 0x8700, 0xa475, 0x4000 },
+  { 0x8700, 0xa471, 0x3000 },
+  { 0x8700, 0xa46f, 0x2000 },
+  { 0x0700, 0xa46e, 0x0000 },
+  { 0x0700, 0xa470, 0x0000 },
+  { 0x8700, 0xa473, 0x2000 },
+  { 0x0700, 0xa472, 0x0000 },
+  { 0x0700, 0xa474, 0x0000 },
+  { 0x8700, 0xa479, 0x3000 },
+  { 0x8700, 0xa477, 0x2000 },
+  { 0x0700, 0xa476, 0x0000 },
+  { 0x0700, 0xa478, 0x0000 },
+  { 0x8700, 0xa47b, 0x2000 },
+  { 0x0700, 0xa47a, 0x0000 },
+  { 0x0700, 0xa47c, 0x0000 },
+  { 0x8700, 0xa485, 0x4000 },
+  { 0x8700, 0xa481, 0x3000 },
+  { 0x8700, 0xa47f, 0x2000 },
+  { 0x0700, 0xa47e, 0x0000 },
+  { 0x0700, 0xa480, 0x0000 },
+  { 0x8700, 0xa483, 0x2000 },
+  { 0x0700, 0xa482, 0x0000 },
+  { 0x0700, 0xa484, 0x0000 },
+  { 0x8700, 0xa489, 0x3000 },
+  { 0x8700, 0xa487, 0x2000 },
+  { 0x0700, 0xa486, 0x0000 },
+  { 0x0700, 0xa488, 0x0000 },
+  { 0x8700, 0xa48b, 0x2000 },
+  { 0x0700, 0xa48a, 0x0000 },
+  { 0x0700, 0xa48c, 0x0000 },
+  { 0x9a00, 0xa4b0, 0x6000 },
+  { 0x9a00, 0xa4a0, 0x5000 },
+  { 0x9a00, 0xa498, 0x4000 },
+  { 0x9a00, 0xa494, 0x3000 },
+  { 0x9a00, 0xa492, 0x2000 },
+  { 0x1a00, 0xa491, 0x0000 },
+  { 0x1a00, 0xa493, 0x0000 },
+  { 0x9a00, 0xa496, 0x2000 },
+  { 0x1a00, 0xa495, 0x0000 },
+  { 0x1a00, 0xa497, 0x0000 },
+  { 0x9a00, 0xa49c, 0x3000 },
+  { 0x9a00, 0xa49a, 0x2000 },
+  { 0x1a00, 0xa499, 0x0000 },
+  { 0x1a00, 0xa49b, 0x0000 },
+  { 0x9a00, 0xa49e, 0x2000 },
+  { 0x1a00, 0xa49d, 0x0000 },
+  { 0x1a00, 0xa49f, 0x0000 },
+  { 0x9a00, 0xa4a8, 0x4000 },
+  { 0x9a00, 0xa4a4, 0x3000 },
+  { 0x9a00, 0xa4a2, 0x2000 },
+  { 0x1a00, 0xa4a1, 0x0000 },
+  { 0x1a00, 0xa4a3, 0x0000 },
+  { 0x9a00, 0xa4a6, 0x2000 },
+  { 0x1a00, 0xa4a5, 0x0000 },
+  { 0x1a00, 0xa4a7, 0x0000 },
+  { 0x9a00, 0xa4ac, 0x3000 },
+  { 0x9a00, 0xa4aa, 0x2000 },
+  { 0x1a00, 0xa4a9, 0x0000 },
+  { 0x1a00, 0xa4ab, 0x0000 },
+  { 0x9a00, 0xa4ae, 0x2000 },
+  { 0x1a00, 0xa4ad, 0x0000 },
+  { 0x1a00, 0xa4af, 0x0000 },
+  { 0x9a00, 0xa4c0, 0x5000 },
+  { 0x9a00, 0xa4b8, 0x4000 },
+  { 0x9a00, 0xa4b4, 0x3000 },
+  { 0x9a00, 0xa4b2, 0x2000 },
+  { 0x1a00, 0xa4b1, 0x0000 },
+  { 0x1a00, 0xa4b3, 0x0000 },
+  { 0x9a00, 0xa4b6, 0x2000 },
+  { 0x1a00, 0xa4b5, 0x0000 },
+  { 0x1a00, 0xa4b7, 0x0000 },
+  { 0x9a00, 0xa4bc, 0x3000 },
+  { 0x9a00, 0xa4ba, 0x2000 },
+  { 0x1a00, 0xa4b9, 0x0000 },
+  { 0x1a00, 0xa4bb, 0x0000 },
+  { 0x9a00, 0xa4be, 0x2000 },
+  { 0x1a00, 0xa4bd, 0x0000 },
+  { 0x1a00, 0xa4bf, 0x0000 },
+  { 0x8700, 0xd7a3, 0x4000 },
+  { 0x9a00, 0xa4c4, 0x3000 },
+  { 0x9a00, 0xa4c2, 0x2000 },
+  { 0x1a00, 0xa4c1, 0x0000 },
+  { 0x1a00, 0xa4c3, 0x0000 },
+  { 0x9a00, 0xa4c6, 0x2000 },
+  { 0x1a00, 0xa4c5, 0x0000 },
+  { 0x0700, 0xac00, 0x0000 },
+  { 0x8400, 0xdbff, 0x3000 },
+  { 0x8400, 0xdb7f, 0x2000 },
+  { 0x0400, 0xd800, 0x0000 },
+  { 0x0400, 0xdb80, 0x0000 },
+  { 0x8400, 0xdfff, 0x2000 },
+  { 0x0400, 0xdc00, 0x0000 },
+  { 0x0300, 0xe000, 0x0000 },
+  { 0x8700, 0xf93f, 0x7000 },
+  { 0x8700, 0xf91f, 0x6000 },
+  { 0x8700, 0xf90f, 0x5000 },
+  { 0x8700, 0xf907, 0x4000 },
+  { 0x8700, 0xf903, 0x3000 },
+  { 0x8700, 0xf901, 0x2000 },
+  { 0x0700, 0xf900, 0x0000 },
+  { 0x0700, 0xf902, 0x0000 },
+  { 0x8700, 0xf905, 0x2000 },
+  { 0x0700, 0xf904, 0x0000 },
+  { 0x0700, 0xf906, 0x0000 },
+  { 0x8700, 0xf90b, 0x3000 },
+  { 0x8700, 0xf909, 0x2000 },
+  { 0x0700, 0xf908, 0x0000 },
+  { 0x0700, 0xf90a, 0x0000 },
+  { 0x8700, 0xf90d, 0x2000 },
+  { 0x0700, 0xf90c, 0x0000 },
+  { 0x0700, 0xf90e, 0x0000 },
+  { 0x8700, 0xf917, 0x4000 },
+  { 0x8700, 0xf913, 0x3000 },
+  { 0x8700, 0xf911, 0x2000 },
+  { 0x0700, 0xf910, 0x0000 },
+  { 0x0700, 0xf912, 0x0000 },
+  { 0x8700, 0xf915, 0x2000 },
+  { 0x0700, 0xf914, 0x0000 },
+  { 0x0700, 0xf916, 0x0000 },
+  { 0x8700, 0xf91b, 0x3000 },
+  { 0x8700, 0xf919, 0x2000 },
+  { 0x0700, 0xf918, 0x0000 },
+  { 0x0700, 0xf91a, 0x0000 },
+  { 0x8700, 0xf91d, 0x2000 },
+  { 0x0700, 0xf91c, 0x0000 },
+  { 0x0700, 0xf91e, 0x0000 },
+  { 0x8700, 0xf92f, 0x5000 },
+  { 0x8700, 0xf927, 0x4000 },
+  { 0x8700, 0xf923, 0x3000 },
+  { 0x8700, 0xf921, 0x2000 },
+  { 0x0700, 0xf920, 0x0000 },
+  { 0x0700, 0xf922, 0x0000 },
+  { 0x8700, 0xf925, 0x2000 },
+  { 0x0700, 0xf924, 0x0000 },
+  { 0x0700, 0xf926, 0x0000 },
+  { 0x8700, 0xf92b, 0x3000 },
+  { 0x8700, 0xf929, 0x2000 },
+  { 0x0700, 0xf928, 0x0000 },
+  { 0x0700, 0xf92a, 0x0000 },
+  { 0x8700, 0xf92d, 0x2000 },
+  { 0x0700, 0xf92c, 0x0000 },
+  { 0x0700, 0xf92e, 0x0000 },
+  { 0x8700, 0xf937, 0x4000 },
+  { 0x8700, 0xf933, 0x3000 },
+  { 0x8700, 0xf931, 0x2000 },
+  { 0x0700, 0xf930, 0x0000 },
+  { 0x0700, 0xf932, 0x0000 },
+  { 0x8700, 0xf935, 0x2000 },
+  { 0x0700, 0xf934, 0x0000 },
+  { 0x0700, 0xf936, 0x0000 },
+  { 0x8700, 0xf93b, 0x3000 },
+  { 0x8700, 0xf939, 0x2000 },
+  { 0x0700, 0xf938, 0x0000 },
+  { 0x0700, 0xf93a, 0x0000 },
+  { 0x8700, 0xf93d, 0x2000 },
+  { 0x0700, 0xf93c, 0x0000 },
+  { 0x0700, 0xf93e, 0x0000 },
+  { 0x8700, 0xf95f, 0x6000 },
+  { 0x8700, 0xf94f, 0x5000 },
+  { 0x8700, 0xf947, 0x4000 },
+  { 0x8700, 0xf943, 0x3000 },
+  { 0x8700, 0xf941, 0x2000 },
+  { 0x0700, 0xf940, 0x0000 },
+  { 0x0700, 0xf942, 0x0000 },
+  { 0x8700, 0xf945, 0x2000 },
+  { 0x0700, 0xf944, 0x0000 },
+  { 0x0700, 0xf946, 0x0000 },
+  { 0x8700, 0xf94b, 0x3000 },
+  { 0x8700, 0xf949, 0x2000 },
+  { 0x0700, 0xf948, 0x0000 },
+  { 0x0700, 0xf94a, 0x0000 },
+  { 0x8700, 0xf94d, 0x2000 },
+  { 0x0700, 0xf94c, 0x0000 },
+  { 0x0700, 0xf94e, 0x0000 },
+  { 0x8700, 0xf957, 0x4000 },
+  { 0x8700, 0xf953, 0x3000 },
+  { 0x8700, 0xf951, 0x2000 },
+  { 0x0700, 0xf950, 0x0000 },
+  { 0x0700, 0xf952, 0x0000 },
+  { 0x8700, 0xf955, 0x2000 },
+  { 0x0700, 0xf954, 0x0000 },
+  { 0x0700, 0xf956, 0x0000 },
+  { 0x8700, 0xf95b, 0x3000 },
+  { 0x8700, 0xf959, 0x2000 },
+  { 0x0700, 0xf958, 0x0000 },
+  { 0x0700, 0xf95a, 0x0000 },
+  { 0x8700, 0xf95d, 0x2000 },
+  { 0x0700, 0xf95c, 0x0000 },
+  { 0x0700, 0xf95e, 0x0000 },
+  { 0x8700, 0xf96f, 0x5000 },
+  { 0x8700, 0xf967, 0x4000 },
+  { 0x8700, 0xf963, 0x3000 },
+  { 0x8700, 0xf961, 0x2000 },
+  { 0x0700, 0xf960, 0x0000 },
+  { 0x0700, 0xf962, 0x0000 },
+  { 0x8700, 0xf965, 0x2000 },
+  { 0x0700, 0xf964, 0x0000 },
+  { 0x0700, 0xf966, 0x0000 },
+  { 0x8700, 0xf96b, 0x3000 },
+  { 0x8700, 0xf969, 0x2000 },
+  { 0x0700, 0xf968, 0x0000 },
+  { 0x0700, 0xf96a, 0x0000 },
+  { 0x8700, 0xf96d, 0x2000 },
+  { 0x0700, 0xf96c, 0x0000 },
+  { 0x0700, 0xf96e, 0x0000 },
+  { 0x8700, 0xf977, 0x4000 },
+  { 0x8700, 0xf973, 0x3000 },
+  { 0x8700, 0xf971, 0x2000 },
+  { 0x0700, 0xf970, 0x0000 },
+  { 0x0700, 0xf972, 0x0000 },
+  { 0x8700, 0xf975, 0x2000 },
+  { 0x0700, 0xf974, 0x0000 },
+  { 0x0700, 0xf976, 0x0000 },
+  { 0x8700, 0xf97b, 0x3000 },
+  { 0x8700, 0xf979, 0x2000 },
+  { 0x0700, 0xf978, 0x0000 },
+  { 0x0700, 0xf97a, 0x0000 },
+  { 0x8700, 0xf97d, 0x2000 },
+  { 0x0700, 0xf97c, 0x0000 },
+  { 0x0700, 0xf97e, 0x0000 },
+  { 0x8700, 0xfb27, 0x9000 },
+  { 0x8700, 0xf9ff, 0x8000 },
+  { 0x8700, 0xf9bf, 0x7000 },
+  { 0x8700, 0xf99f, 0x6000 },
+  { 0x8700, 0xf98f, 0x5000 },
+  { 0x8700, 0xf987, 0x4000 },
+  { 0x8700, 0xf983, 0x3000 },
+  { 0x8700, 0xf981, 0x2000 },
+  { 0x0700, 0xf980, 0x0000 },
+  { 0x0700, 0xf982, 0x0000 },
+  { 0x8700, 0xf985, 0x2000 },
+  { 0x0700, 0xf984, 0x0000 },
+  { 0x0700, 0xf986, 0x0000 },
+  { 0x8700, 0xf98b, 0x3000 },
+  { 0x8700, 0xf989, 0x2000 },
+  { 0x0700, 0xf988, 0x0000 },
+  { 0x0700, 0xf98a, 0x0000 },
+  { 0x8700, 0xf98d, 0x2000 },
+  { 0x0700, 0xf98c, 0x0000 },
+  { 0x0700, 0xf98e, 0x0000 },
+  { 0x8700, 0xf997, 0x4000 },
+  { 0x8700, 0xf993, 0x3000 },
+  { 0x8700, 0xf991, 0x2000 },
+  { 0x0700, 0xf990, 0x0000 },
+  { 0x0700, 0xf992, 0x0000 },
+  { 0x8700, 0xf995, 0x2000 },
+  { 0x0700, 0xf994, 0x0000 },
+  { 0x0700, 0xf996, 0x0000 },
+  { 0x8700, 0xf99b, 0x3000 },
+  { 0x8700, 0xf999, 0x2000 },
+  { 0x0700, 0xf998, 0x0000 },
+  { 0x0700, 0xf99a, 0x0000 },
+  { 0x8700, 0xf99d, 0x2000 },
+  { 0x0700, 0xf99c, 0x0000 },
+  { 0x0700, 0xf99e, 0x0000 },
+  { 0x8700, 0xf9af, 0x5000 },
+  { 0x8700, 0xf9a7, 0x4000 },
+  { 0x8700, 0xf9a3, 0x3000 },
+  { 0x8700, 0xf9a1, 0x2000 },
+  { 0x0700, 0xf9a0, 0x0000 },
+  { 0x0700, 0xf9a2, 0x0000 },
+  { 0x8700, 0xf9a5, 0x2000 },
+  { 0x0700, 0xf9a4, 0x0000 },
+  { 0x0700, 0xf9a6, 0x0000 },
+  { 0x8700, 0xf9ab, 0x3000 },
+  { 0x8700, 0xf9a9, 0x2000 },
+  { 0x0700, 0xf9a8, 0x0000 },
+  { 0x0700, 0xf9aa, 0x0000 },
+  { 0x8700, 0xf9ad, 0x2000 },
+  { 0x0700, 0xf9ac, 0x0000 },
+  { 0x0700, 0xf9ae, 0x0000 },
+  { 0x8700, 0xf9b7, 0x4000 },
+  { 0x8700, 0xf9b3, 0x3000 },
+  { 0x8700, 0xf9b1, 0x2000 },
+  { 0x0700, 0xf9b0, 0x0000 },
+  { 0x0700, 0xf9b2, 0x0000 },
+  { 0x8700, 0xf9b5, 0x2000 },
+  { 0x0700, 0xf9b4, 0x0000 },
+  { 0x0700, 0xf9b6, 0x0000 },
+  { 0x8700, 0xf9bb, 0x3000 },
+  { 0x8700, 0xf9b9, 0x2000 },
+  { 0x0700, 0xf9b8, 0x0000 },
+  { 0x0700, 0xf9ba, 0x0000 },
+  { 0x8700, 0xf9bd, 0x2000 },
+  { 0x0700, 0xf9bc, 0x0000 },
+  { 0x0700, 0xf9be, 0x0000 },
+  { 0x8700, 0xf9df, 0x6000 },
+  { 0x8700, 0xf9cf, 0x5000 },
+  { 0x8700, 0xf9c7, 0x4000 },
+  { 0x8700, 0xf9c3, 0x3000 },
+  { 0x8700, 0xf9c1, 0x2000 },
+  { 0x0700, 0xf9c0, 0x0000 },
+  { 0x0700, 0xf9c2, 0x0000 },
+  { 0x8700, 0xf9c5, 0x2000 },
+  { 0x0700, 0xf9c4, 0x0000 },
+  { 0x0700, 0xf9c6, 0x0000 },
+  { 0x8700, 0xf9cb, 0x3000 },
+  { 0x8700, 0xf9c9, 0x2000 },
+  { 0x0700, 0xf9c8, 0x0000 },
+  { 0x0700, 0xf9ca, 0x0000 },
+  { 0x8700, 0xf9cd, 0x2000 },
+  { 0x0700, 0xf9cc, 0x0000 },
+  { 0x0700, 0xf9ce, 0x0000 },
+  { 0x8700, 0xf9d7, 0x4000 },
+  { 0x8700, 0xf9d3, 0x3000 },
+  { 0x8700, 0xf9d1, 0x2000 },
+  { 0x0700, 0xf9d0, 0x0000 },
+  { 0x0700, 0xf9d2, 0x0000 },
+  { 0x8700, 0xf9d5, 0x2000 },
+  { 0x0700, 0xf9d4, 0x0000 },
+  { 0x0700, 0xf9d6, 0x0000 },
+  { 0x8700, 0xf9db, 0x3000 },
+  { 0x8700, 0xf9d9, 0x2000 },
+  { 0x0700, 0xf9d8, 0x0000 },
+  { 0x0700, 0xf9da, 0x0000 },
+  { 0x8700, 0xf9dd, 0x2000 },
+  { 0x0700, 0xf9dc, 0x0000 },
+  { 0x0700, 0xf9de, 0x0000 },
+  { 0x8700, 0xf9ef, 0x5000 },
+  { 0x8700, 0xf9e7, 0x4000 },
+  { 0x8700, 0xf9e3, 0x3000 },
+  { 0x8700, 0xf9e1, 0x2000 },
+  { 0x0700, 0xf9e0, 0x0000 },
+  { 0x0700, 0xf9e2, 0x0000 },
+  { 0x8700, 0xf9e5, 0x2000 },
+  { 0x0700, 0xf9e4, 0x0000 },
+  { 0x0700, 0xf9e6, 0x0000 },
+  { 0x8700, 0xf9eb, 0x3000 },
+  { 0x8700, 0xf9e9, 0x2000 },
+  { 0x0700, 0xf9e8, 0x0000 },
+  { 0x0700, 0xf9ea, 0x0000 },
+  { 0x8700, 0xf9ed, 0x2000 },
+  { 0x0700, 0xf9ec, 0x0000 },
+  { 0x0700, 0xf9ee, 0x0000 },
+  { 0x8700, 0xf9f7, 0x4000 },
+  { 0x8700, 0xf9f3, 0x3000 },
+  { 0x8700, 0xf9f1, 0x2000 },
+  { 0x0700, 0xf9f0, 0x0000 },
+  { 0x0700, 0xf9f2, 0x0000 },
+  { 0x8700, 0xf9f5, 0x2000 },
+  { 0x0700, 0xf9f4, 0x0000 },
+  { 0x0700, 0xf9f6, 0x0000 },
+  { 0x8700, 0xf9fb, 0x3000 },
+  { 0x8700, 0xf9f9, 0x2000 },
+  { 0x0700, 0xf9f8, 0x0000 },
+  { 0x0700, 0xf9fa, 0x0000 },
+  { 0x8700, 0xf9fd, 0x2000 },
+  { 0x0700, 0xf9fc, 0x0000 },
+  { 0x0700, 0xf9fe, 0x0000 },
+  { 0x8700, 0xfa41, 0x7000 },
+  { 0x8700, 0xfa1f, 0x6000 },
+  { 0x8700, 0xfa0f, 0x5000 },
+  { 0x8700, 0xfa07, 0x4000 },
+  { 0x8700, 0xfa03, 0x3000 },
+  { 0x8700, 0xfa01, 0x2000 },
+  { 0x0700, 0xfa00, 0x0000 },
+  { 0x0700, 0xfa02, 0x0000 },
+  { 0x8700, 0xfa05, 0x2000 },
+  { 0x0700, 0xfa04, 0x0000 },
+  { 0x0700, 0xfa06, 0x0000 },
+  { 0x8700, 0xfa0b, 0x3000 },
+  { 0x8700, 0xfa09, 0x2000 },
+  { 0x0700, 0xfa08, 0x0000 },
+  { 0x0700, 0xfa0a, 0x0000 },
+  { 0x8700, 0xfa0d, 0x2000 },
+  { 0x0700, 0xfa0c, 0x0000 },
+  { 0x0700, 0xfa0e, 0x0000 },
+  { 0x8700, 0xfa17, 0x4000 },
+  { 0x8700, 0xfa13, 0x3000 },
+  { 0x8700, 0xfa11, 0x2000 },
+  { 0x0700, 0xfa10, 0x0000 },
+  { 0x0700, 0xfa12, 0x0000 },
+  { 0x8700, 0xfa15, 0x2000 },
+  { 0x0700, 0xfa14, 0x0000 },
+  { 0x0700, 0xfa16, 0x0000 },
+  { 0x8700, 0xfa1b, 0x3000 },
+  { 0x8700, 0xfa19, 0x2000 },
+  { 0x0700, 0xfa18, 0x0000 },
+  { 0x0700, 0xfa1a, 0x0000 },
+  { 0x8700, 0xfa1d, 0x2000 },
+  { 0x0700, 0xfa1c, 0x0000 },
+  { 0x0700, 0xfa1e, 0x0000 },
+  { 0x8700, 0xfa31, 0x5000 },
+  { 0x8700, 0xfa27, 0x4000 },
+  { 0x8700, 0xfa23, 0x3000 },
+  { 0x8700, 0xfa21, 0x2000 },
+  { 0x0700, 0xfa20, 0x0000 },
+  { 0x0700, 0xfa22, 0x0000 },
+  { 0x8700, 0xfa25, 0x2000 },
+  { 0x0700, 0xfa24, 0x0000 },
+  { 0x0700, 0xfa26, 0x0000 },
+  { 0x8700, 0xfa2b, 0x3000 },
+  { 0x8700, 0xfa29, 0x2000 },
+  { 0x0700, 0xfa28, 0x0000 },
+  { 0x0700, 0xfa2a, 0x0000 },
+  { 0x8700, 0xfa2d, 0x2000 },
+  { 0x0700, 0xfa2c, 0x0000 },
+  { 0x0700, 0xfa30, 0x0000 },
+  { 0x8700, 0xfa39, 0x4000 },
+  { 0x8700, 0xfa35, 0x3000 },
+  { 0x8700, 0xfa33, 0x2000 },
+  { 0x0700, 0xfa32, 0x0000 },
+  { 0x0700, 0xfa34, 0x0000 },
+  { 0x8700, 0xfa37, 0x2000 },
+  { 0x0700, 0xfa36, 0x0000 },
+  { 0x0700, 0xfa38, 0x0000 },
+  { 0x8700, 0xfa3d, 0x3000 },
+  { 0x8700, 0xfa3b, 0x2000 },
+  { 0x0700, 0xfa3a, 0x0000 },
+  { 0x0700, 0xfa3c, 0x0000 },
+  { 0x8700, 0xfa3f, 0x2000 },
+  { 0x0700, 0xfa3e, 0x0000 },
+  { 0x0700, 0xfa40, 0x0000 },
+  { 0x8700, 0xfa61, 0x6000 },
+  { 0x8700, 0xfa51, 0x5000 },
+  { 0x8700, 0xfa49, 0x4000 },
+  { 0x8700, 0xfa45, 0x3000 },
+  { 0x8700, 0xfa43, 0x2000 },
+  { 0x0700, 0xfa42, 0x0000 },
+  { 0x0700, 0xfa44, 0x0000 },
+  { 0x8700, 0xfa47, 0x2000 },
+  { 0x0700, 0xfa46, 0x0000 },
+  { 0x0700, 0xfa48, 0x0000 },
+  { 0x8700, 0xfa4d, 0x3000 },
+  { 0x8700, 0xfa4b, 0x2000 },
+  { 0x0700, 0xfa4a, 0x0000 },
+  { 0x0700, 0xfa4c, 0x0000 },
+  { 0x8700, 0xfa4f, 0x2000 },
+  { 0x0700, 0xfa4e, 0x0000 },
+  { 0x0700, 0xfa50, 0x0000 },
+  { 0x8700, 0xfa59, 0x4000 },
+  { 0x8700, 0xfa55, 0x3000 },
+  { 0x8700, 0xfa53, 0x2000 },
+  { 0x0700, 0xfa52, 0x0000 },
+  { 0x0700, 0xfa54, 0x0000 },
+  { 0x8700, 0xfa57, 0x2000 },
+  { 0x0700, 0xfa56, 0x0000 },
+  { 0x0700, 0xfa58, 0x0000 },
+  { 0x8700, 0xfa5d, 0x3000 },
+  { 0x8700, 0xfa5b, 0x2000 },
+  { 0x0700, 0xfa5a, 0x0000 },
+  { 0x0700, 0xfa5c, 0x0000 },
+  { 0x8700, 0xfa5f, 0x2000 },
+  { 0x0700, 0xfa5e, 0x0000 },
+  { 0x0700, 0xfa60, 0x0000 },
+  { 0x8500, 0xfb06, 0x5000 },
+  { 0x8700, 0xfa69, 0x4000 },
+  { 0x8700, 0xfa65, 0x3000 },
+  { 0x8700, 0xfa63, 0x2000 },
+  { 0x0700, 0xfa62, 0x0000 },
+  { 0x0700, 0xfa64, 0x0000 },
+  { 0x8700, 0xfa67, 0x2000 },
+  { 0x0700, 0xfa66, 0x0000 },
+  { 0x0700, 0xfa68, 0x0000 },
+  { 0x8500, 0xfb02, 0x3000 },
+  { 0x8500, 0xfb00, 0x2000 },
+  { 0x0700, 0xfa6a, 0x0000 },
+  { 0x0500, 0xfb01, 0x0000 },
+  { 0x8500, 0xfb04, 0x2000 },
+  { 0x0500, 0xfb03, 0x0000 },
+  { 0x0500, 0xfb05, 0x0000 },
+  { 0x8700, 0xfb1f, 0x4000 },
+  { 0x8500, 0xfb16, 0x3000 },
+  { 0x8500, 0xfb14, 0x2000 },
+  { 0x0500, 0xfb13, 0x0000 },
+  { 0x0500, 0xfb15, 0x0000 },
+  { 0x8700, 0xfb1d, 0x2000 },
+  { 0x0500, 0xfb17, 0x0000 },
+  { 0x0c00, 0xfb1e, 0x0000 },
+  { 0x8700, 0xfb23, 0x3000 },
+  { 0x8700, 0xfb21, 0x2000 },
+  { 0x0700, 0xfb20, 0x0000 },
+  { 0x0700, 0xfb22, 0x0000 },
+  { 0x8700, 0xfb25, 0x2000 },
+  { 0x0700, 0xfb24, 0x0000 },
+  { 0x0700, 0xfb26, 0x0000 },
+  { 0x8700, 0xfbac, 0x8000 },
+  { 0x8700, 0xfb6c, 0x7000 },
+  { 0x8700, 0xfb4c, 0x6000 },
+  { 0x8700, 0xfb38, 0x5000 },
+  { 0x8700, 0xfb2f, 0x4000 },
+  { 0x8700, 0xfb2b, 0x3000 },
+  { 0x9900, 0xfb29, 0x2000 },
+  { 0x0700, 0xfb28, 0x0000 },
+  { 0x0700, 0xfb2a, 0x0000 },
+  { 0x8700, 0xfb2d, 0x2000 },
+  { 0x0700, 0xfb2c, 0x0000 },
+  { 0x0700, 0xfb2e, 0x0000 },
+  { 0x8700, 0xfb33, 0x3000 },
+  { 0x8700, 0xfb31, 0x2000 },
+  { 0x0700, 0xfb30, 0x0000 },
+  { 0x0700, 0xfb32, 0x0000 },
+  { 0x8700, 0xfb35, 0x2000 },
+  { 0x0700, 0xfb34, 0x0000 },
+  { 0x0700, 0xfb36, 0x0000 },
+  { 0x8700, 0xfb43, 0x4000 },
+  { 0x8700, 0xfb3c, 0x3000 },
+  { 0x8700, 0xfb3a, 0x2000 },
+  { 0x0700, 0xfb39, 0x0000 },
+  { 0x0700, 0xfb3b, 0x0000 },
+  { 0x8700, 0xfb40, 0x2000 },
+  { 0x0700, 0xfb3e, 0x0000 },
+  { 0x0700, 0xfb41, 0x0000 },
+  { 0x8700, 0xfb48, 0x3000 },
+  { 0x8700, 0xfb46, 0x2000 },
+  { 0x0700, 0xfb44, 0x0000 },
+  { 0x0700, 0xfb47, 0x0000 },
+  { 0x8700, 0xfb4a, 0x2000 },
+  { 0x0700, 0xfb49, 0x0000 },
+  { 0x0700, 0xfb4b, 0x0000 },
+  { 0x8700, 0xfb5c, 0x5000 },
+  { 0x8700, 0xfb54, 0x4000 },
+  { 0x8700, 0xfb50, 0x3000 },
+  { 0x8700, 0xfb4e, 0x2000 },
+  { 0x0700, 0xfb4d, 0x0000 },
+  { 0x0700, 0xfb4f, 0x0000 },
+  { 0x8700, 0xfb52, 0x2000 },
+  { 0x0700, 0xfb51, 0x0000 },
+  { 0x0700, 0xfb53, 0x0000 },
+  { 0x8700, 0xfb58, 0x3000 },
+  { 0x8700, 0xfb56, 0x2000 },
+  { 0x0700, 0xfb55, 0x0000 },
+  { 0x0700, 0xfb57, 0x0000 },
+  { 0x8700, 0xfb5a, 0x2000 },
+  { 0x0700, 0xfb59, 0x0000 },
+  { 0x0700, 0xfb5b, 0x0000 },
+  { 0x8700, 0xfb64, 0x4000 },
+  { 0x8700, 0xfb60, 0x3000 },
+  { 0x8700, 0xfb5e, 0x2000 },
+  { 0x0700, 0xfb5d, 0x0000 },
+  { 0x0700, 0xfb5f, 0x0000 },
+  { 0x8700, 0xfb62, 0x2000 },
+  { 0x0700, 0xfb61, 0x0000 },
+  { 0x0700, 0xfb63, 0x0000 },
+  { 0x8700, 0xfb68, 0x3000 },
+  { 0x8700, 0xfb66, 0x2000 },
+  { 0x0700, 0xfb65, 0x0000 },
+  { 0x0700, 0xfb67, 0x0000 },
+  { 0x8700, 0xfb6a, 0x2000 },
+  { 0x0700, 0xfb69, 0x0000 },
+  { 0x0700, 0xfb6b, 0x0000 },
+  { 0x8700, 0xfb8c, 0x6000 },
+  { 0x8700, 0xfb7c, 0x5000 },
+  { 0x8700, 0xfb74, 0x4000 },
+  { 0x8700, 0xfb70, 0x3000 },
+  { 0x8700, 0xfb6e, 0x2000 },
+  { 0x0700, 0xfb6d, 0x0000 },
+  { 0x0700, 0xfb6f, 0x0000 },
+  { 0x8700, 0xfb72, 0x2000 },
+  { 0x0700, 0xfb71, 0x0000 },
+  { 0x0700, 0xfb73, 0x0000 },
+  { 0x8700, 0xfb78, 0x3000 },
+  { 0x8700, 0xfb76, 0x2000 },
+  { 0x0700, 0xfb75, 0x0000 },
+  { 0x0700, 0xfb77, 0x0000 },
+  { 0x8700, 0xfb7a, 0x2000 },
+  { 0x0700, 0xfb79, 0x0000 },
+  { 0x0700, 0xfb7b, 0x0000 },
+  { 0x8700, 0xfb84, 0x4000 },
+  { 0x8700, 0xfb80, 0x3000 },
+  { 0x8700, 0xfb7e, 0x2000 },
+  { 0x0700, 0xfb7d, 0x0000 },
+  { 0x0700, 0xfb7f, 0x0000 },
+  { 0x8700, 0xfb82, 0x2000 },
+  { 0x0700, 0xfb81, 0x0000 },
+  { 0x0700, 0xfb83, 0x0000 },
+  { 0x8700, 0xfb88, 0x3000 },
+  { 0x8700, 0xfb86, 0x2000 },
+  { 0x0700, 0xfb85, 0x0000 },
+  { 0x0700, 0xfb87, 0x0000 },
+  { 0x8700, 0xfb8a, 0x2000 },
+  { 0x0700, 0xfb89, 0x0000 },
+  { 0x0700, 0xfb8b, 0x0000 },
+  { 0x8700, 0xfb9c, 0x5000 },
+  { 0x8700, 0xfb94, 0x4000 },
+  { 0x8700, 0xfb90, 0x3000 },
+  { 0x8700, 0xfb8e, 0x2000 },
+  { 0x0700, 0xfb8d, 0x0000 },
+  { 0x0700, 0xfb8f, 0x0000 },
+  { 0x8700, 0xfb92, 0x2000 },
+  { 0x0700, 0xfb91, 0x0000 },
+  { 0x0700, 0xfb93, 0x0000 },
+  { 0x8700, 0xfb98, 0x3000 },
+  { 0x8700, 0xfb96, 0x2000 },
+  { 0x0700, 0xfb95, 0x0000 },
+  { 0x0700, 0xfb97, 0x0000 },
+  { 0x8700, 0xfb9a, 0x2000 },
+  { 0x0700, 0xfb99, 0x0000 },
+  { 0x0700, 0xfb9b, 0x0000 },
+  { 0x8700, 0xfba4, 0x4000 },
+  { 0x8700, 0xfba0, 0x3000 },
+  { 0x8700, 0xfb9e, 0x2000 },
+  { 0x0700, 0xfb9d, 0x0000 },
+  { 0x0700, 0xfb9f, 0x0000 },
+  { 0x8700, 0xfba2, 0x2000 },
+  { 0x0700, 0xfba1, 0x0000 },
+  { 0x0700, 0xfba3, 0x0000 },
+  { 0x8700, 0xfba8, 0x3000 },
+  { 0x8700, 0xfba6, 0x2000 },
+  { 0x0700, 0xfba5, 0x0000 },
+  { 0x0700, 0xfba7, 0x0000 },
+  { 0x8700, 0xfbaa, 0x2000 },
+  { 0x0700, 0xfba9, 0x0000 },
+  { 0x0700, 0xfbab, 0x0000 },
+  { 0x8700, 0xfc0d, 0x7000 },
+  { 0x8700, 0xfbed, 0x6000 },
+  { 0x8700, 0xfbdd, 0x5000 },
+  { 0x8700, 0xfbd5, 0x4000 },
+  { 0x8700, 0xfbb0, 0x3000 },
+  { 0x8700, 0xfbae, 0x2000 },
+  { 0x0700, 0xfbad, 0x0000 },
+  { 0x0700, 0xfbaf, 0x0000 },
+  { 0x8700, 0xfbd3, 0x2000 },
+  { 0x0700, 0xfbb1, 0x0000 },
+  { 0x0700, 0xfbd4, 0x0000 },
+  { 0x8700, 0xfbd9, 0x3000 },
+  { 0x8700, 0xfbd7, 0x2000 },
+  { 0x0700, 0xfbd6, 0x0000 },
+  { 0x0700, 0xfbd8, 0x0000 },
+  { 0x8700, 0xfbdb, 0x2000 },
+  { 0x0700, 0xfbda, 0x0000 },
+  { 0x0700, 0xfbdc, 0x0000 },
+  { 0x8700, 0xfbe5, 0x4000 },
+  { 0x8700, 0xfbe1, 0x3000 },
+  { 0x8700, 0xfbdf, 0x2000 },
+  { 0x0700, 0xfbde, 0x0000 },
+  { 0x0700, 0xfbe0, 0x0000 },
+  { 0x8700, 0xfbe3, 0x2000 },
+  { 0x0700, 0xfbe2, 0x0000 },
+  { 0x0700, 0xfbe4, 0x0000 },
+  { 0x8700, 0xfbe9, 0x3000 },
+  { 0x8700, 0xfbe7, 0x2000 },
+  { 0x0700, 0xfbe6, 0x0000 },
+  { 0x0700, 0xfbe8, 0x0000 },
+  { 0x8700, 0xfbeb, 0x2000 },
+  { 0x0700, 0xfbea, 0x0000 },
+  { 0x0700, 0xfbec, 0x0000 },
+  { 0x8700, 0xfbfd, 0x5000 },
+  { 0x8700, 0xfbf5, 0x4000 },
+  { 0x8700, 0xfbf1, 0x3000 },
+  { 0x8700, 0xfbef, 0x2000 },
+  { 0x0700, 0xfbee, 0x0000 },
+  { 0x0700, 0xfbf0, 0x0000 },
+  { 0x8700, 0xfbf3, 0x2000 },
+  { 0x0700, 0xfbf2, 0x0000 },
+  { 0x0700, 0xfbf4, 0x0000 },
+  { 0x8700, 0xfbf9, 0x3000 },
+  { 0x8700, 0xfbf7, 0x2000 },
+  { 0x0700, 0xfbf6, 0x0000 },
+  { 0x0700, 0xfbf8, 0x0000 },
+  { 0x8700, 0xfbfb, 0x2000 },
+  { 0x0700, 0xfbfa, 0x0000 },
+  { 0x0700, 0xfbfc, 0x0000 },
+  { 0x8700, 0xfc05, 0x4000 },
+  { 0x8700, 0xfc01, 0x3000 },
+  { 0x8700, 0xfbff, 0x2000 },
+  { 0x0700, 0xfbfe, 0x0000 },
+  { 0x0700, 0xfc00, 0x0000 },
+  { 0x8700, 0xfc03, 0x2000 },
+  { 0x0700, 0xfc02, 0x0000 },
+  { 0x0700, 0xfc04, 0x0000 },
+  { 0x8700, 0xfc09, 0x3000 },
+  { 0x8700, 0xfc07, 0x2000 },
+  { 0x0700, 0xfc06, 0x0000 },
+  { 0x0700, 0xfc08, 0x0000 },
+  { 0x8700, 0xfc0b, 0x2000 },
+  { 0x0700, 0xfc0a, 0x0000 },
+  { 0x0700, 0xfc0c, 0x0000 },
+  { 0x8700, 0xfc2d, 0x6000 },
+  { 0x8700, 0xfc1d, 0x5000 },
+  { 0x8700, 0xfc15, 0x4000 },
+  { 0x8700, 0xfc11, 0x3000 },
+  { 0x8700, 0xfc0f, 0x2000 },
+  { 0x0700, 0xfc0e, 0x0000 },
+  { 0x0700, 0xfc10, 0x0000 },
+  { 0x8700, 0xfc13, 0x2000 },
+  { 0x0700, 0xfc12, 0x0000 },
+  { 0x0700, 0xfc14, 0x0000 },
+  { 0x8700, 0xfc19, 0x3000 },
+  { 0x8700, 0xfc17, 0x2000 },
+  { 0x0700, 0xfc16, 0x0000 },
+  { 0x0700, 0xfc18, 0x0000 },
+  { 0x8700, 0xfc1b, 0x2000 },
+  { 0x0700, 0xfc1a, 0x0000 },
+  { 0x0700, 0xfc1c, 0x0000 },
+  { 0x8700, 0xfc25, 0x4000 },
+  { 0x8700, 0xfc21, 0x3000 },
+  { 0x8700, 0xfc1f, 0x2000 },
+  { 0x0700, 0xfc1e, 0x0000 },
+  { 0x0700, 0xfc20, 0x0000 },
+  { 0x8700, 0xfc23, 0x2000 },
+  { 0x0700, 0xfc22, 0x0000 },
+  { 0x0700, 0xfc24, 0x0000 },
+  { 0x8700, 0xfc29, 0x3000 },
+  { 0x8700, 0xfc27, 0x2000 },
+  { 0x0700, 0xfc26, 0x0000 },
+  { 0x0700, 0xfc28, 0x0000 },
+  { 0x8700, 0xfc2b, 0x2000 },
+  { 0x0700, 0xfc2a, 0x0000 },
+  { 0x0700, 0xfc2c, 0x0000 },
+  { 0x8700, 0xfc3d, 0x5000 },
+  { 0x8700, 0xfc35, 0x4000 },
+  { 0x8700, 0xfc31, 0x3000 },
+  { 0x8700, 0xfc2f, 0x2000 },
+  { 0x0700, 0xfc2e, 0x0000 },
+  { 0x0700, 0xfc30, 0x0000 },
+  { 0x8700, 0xfc33, 0x2000 },
+  { 0x0700, 0xfc32, 0x0000 },
+  { 0x0700, 0xfc34, 0x0000 },
+  { 0x8700, 0xfc39, 0x3000 },
+  { 0x8700, 0xfc37, 0x2000 },
+  { 0x0700, 0xfc36, 0x0000 },
+  { 0x0700, 0xfc38, 0x0000 },
+  { 0x8700, 0xfc3b, 0x2000 },
+  { 0x0700, 0xfc3a, 0x0000 },
+  { 0x0700, 0xfc3c, 0x0000 },
+  { 0x8700, 0xfc45, 0x4000 },
+  { 0x8700, 0xfc41, 0x3000 },
+  { 0x8700, 0xfc3f, 0x2000 },
+  { 0x0700, 0xfc3e, 0x0000 },
+  { 0x0700, 0xfc40, 0x0000 },
+  { 0x8700, 0xfc43, 0x2000 },
+  { 0x0700, 0xfc42, 0x0000 },
+  { 0x0700, 0xfc44, 0x0000 },
+  { 0x8700, 0xfc49, 0x3000 },
+  { 0x8700, 0xfc47, 0x2000 },
+  { 0x0700, 0xfc46, 0x0000 },
+  { 0x0700, 0xfc48, 0x0000 },
+  { 0x8700, 0xfc4b, 0x2000 },
+  { 0x0700, 0xfc4a, 0x0000 },
+  { 0x0700, 0xfc4c, 0x0000 },
+  { 0x8700, 0xfeac, 0xa000 },
+  { 0x8700, 0xfd5d, 0x9000 },
+  { 0x8700, 0xfccd, 0x8000 },
+  { 0x8700, 0xfc8d, 0x7000 },
+  { 0x8700, 0xfc6d, 0x6000 },
+  { 0x8700, 0xfc5d, 0x5000 },
+  { 0x8700, 0xfc55, 0x4000 },
+  { 0x8700, 0xfc51, 0x3000 },
+  { 0x8700, 0xfc4f, 0x2000 },
+  { 0x0700, 0xfc4e, 0x0000 },
+  { 0x0700, 0xfc50, 0x0000 },
+  { 0x8700, 0xfc53, 0x2000 },
+  { 0x0700, 0xfc52, 0x0000 },
+  { 0x0700, 0xfc54, 0x0000 },
+  { 0x8700, 0xfc59, 0x3000 },
+  { 0x8700, 0xfc57, 0x2000 },
+  { 0x0700, 0xfc56, 0x0000 },
+  { 0x0700, 0xfc58, 0x0000 },
+  { 0x8700, 0xfc5b, 0x2000 },
+  { 0x0700, 0xfc5a, 0x0000 },
+  { 0x0700, 0xfc5c, 0x0000 },
+  { 0x8700, 0xfc65, 0x4000 },
+  { 0x8700, 0xfc61, 0x3000 },
+  { 0x8700, 0xfc5f, 0x2000 },
+  { 0x0700, 0xfc5e, 0x0000 },
+  { 0x0700, 0xfc60, 0x0000 },
+  { 0x8700, 0xfc63, 0x2000 },
+  { 0x0700, 0xfc62, 0x0000 },
+  { 0x0700, 0xfc64, 0x0000 },
+  { 0x8700, 0xfc69, 0x3000 },
+  { 0x8700, 0xfc67, 0x2000 },
+  { 0x0700, 0xfc66, 0x0000 },
+  { 0x0700, 0xfc68, 0x0000 },
+  { 0x8700, 0xfc6b, 0x2000 },
+  { 0x0700, 0xfc6a, 0x0000 },
+  { 0x0700, 0xfc6c, 0x0000 },
+  { 0x8700, 0xfc7d, 0x5000 },
+  { 0x8700, 0xfc75, 0x4000 },
+  { 0x8700, 0xfc71, 0x3000 },
+  { 0x8700, 0xfc6f, 0x2000 },
+  { 0x0700, 0xfc6e, 0x0000 },
+  { 0x0700, 0xfc70, 0x0000 },
+  { 0x8700, 0xfc73, 0x2000 },
+  { 0x0700, 0xfc72, 0x0000 },
+  { 0x0700, 0xfc74, 0x0000 },
+  { 0x8700, 0xfc79, 0x3000 },
+  { 0x8700, 0xfc77, 0x2000 },
+  { 0x0700, 0xfc76, 0x0000 },
+  { 0x0700, 0xfc78, 0x0000 },
+  { 0x8700, 0xfc7b, 0x2000 },
+  { 0x0700, 0xfc7a, 0x0000 },
+  { 0x0700, 0xfc7c, 0x0000 },
+  { 0x8700, 0xfc85, 0x4000 },
+  { 0x8700, 0xfc81, 0x3000 },
+  { 0x8700, 0xfc7f, 0x2000 },
+  { 0x0700, 0xfc7e, 0x0000 },
+  { 0x0700, 0xfc80, 0x0000 },
+  { 0x8700, 0xfc83, 0x2000 },
+  { 0x0700, 0xfc82, 0x0000 },
+  { 0x0700, 0xfc84, 0x0000 },
+  { 0x8700, 0xfc89, 0x3000 },
+  { 0x8700, 0xfc87, 0x2000 },
+  { 0x0700, 0xfc86, 0x0000 },
+  { 0x0700, 0xfc88, 0x0000 },
+  { 0x8700, 0xfc8b, 0x2000 },
+  { 0x0700, 0xfc8a, 0x0000 },
+  { 0x0700, 0xfc8c, 0x0000 },
+  { 0x8700, 0xfcad, 0x6000 },
+  { 0x8700, 0xfc9d, 0x5000 },
+  { 0x8700, 0xfc95, 0x4000 },
+  { 0x8700, 0xfc91, 0x3000 },
+  { 0x8700, 0xfc8f, 0x2000 },
+  { 0x0700, 0xfc8e, 0x0000 },
+  { 0x0700, 0xfc90, 0x0000 },
+  { 0x8700, 0xfc93, 0x2000 },
+  { 0x0700, 0xfc92, 0x0000 },
+  { 0x0700, 0xfc94, 0x0000 },
+  { 0x8700, 0xfc99, 0x3000 },
+  { 0x8700, 0xfc97, 0x2000 },
+  { 0x0700, 0xfc96, 0x0000 },
+  { 0x0700, 0xfc98, 0x0000 },
+  { 0x8700, 0xfc9b, 0x2000 },
+  { 0x0700, 0xfc9a, 0x0000 },
+  { 0x0700, 0xfc9c, 0x0000 },
+  { 0x8700, 0xfca5, 0x4000 },
+  { 0x8700, 0xfca1, 0x3000 },
+  { 0x8700, 0xfc9f, 0x2000 },
+  { 0x0700, 0xfc9e, 0x0000 },
+  { 0x0700, 0xfca0, 0x0000 },
+  { 0x8700, 0xfca3, 0x2000 },
+  { 0x0700, 0xfca2, 0x0000 },
+  { 0x0700, 0xfca4, 0x0000 },
+  { 0x8700, 0xfca9, 0x3000 },
+  { 0x8700, 0xfca7, 0x2000 },
+  { 0x0700, 0xfca6, 0x0000 },
+  { 0x0700, 0xfca8, 0x0000 },
+  { 0x8700, 0xfcab, 0x2000 },
+  { 0x0700, 0xfcaa, 0x0000 },
+  { 0x0700, 0xfcac, 0x0000 },
+  { 0x8700, 0xfcbd, 0x5000 },
+  { 0x8700, 0xfcb5, 0x4000 },
+  { 0x8700, 0xfcb1, 0x3000 },
+  { 0x8700, 0xfcaf, 0x2000 },
+  { 0x0700, 0xfcae, 0x0000 },
+  { 0x0700, 0xfcb0, 0x0000 },
+  { 0x8700, 0xfcb3, 0x2000 },
+  { 0x0700, 0xfcb2, 0x0000 },
+  { 0x0700, 0xfcb4, 0x0000 },
+  { 0x8700, 0xfcb9, 0x3000 },
+  { 0x8700, 0xfcb7, 0x2000 },
+  { 0x0700, 0xfcb6, 0x0000 },
+  { 0x0700, 0xfcb8, 0x0000 },
+  { 0x8700, 0xfcbb, 0x2000 },
+  { 0x0700, 0xfcba, 0x0000 },
+  { 0x0700, 0xfcbc, 0x0000 },
+  { 0x8700, 0xfcc5, 0x4000 },
+  { 0x8700, 0xfcc1, 0x3000 },
+  { 0x8700, 0xfcbf, 0x2000 },
+  { 0x0700, 0xfcbe, 0x0000 },
+  { 0x0700, 0xfcc0, 0x0000 },
+  { 0x8700, 0xfcc3, 0x2000 },
+  { 0x0700, 0xfcc2, 0x0000 },
+  { 0x0700, 0xfcc4, 0x0000 },
+  { 0x8700, 0xfcc9, 0x3000 },
+  { 0x8700, 0xfcc7, 0x2000 },
+  { 0x0700, 0xfcc6, 0x0000 },
+  { 0x0700, 0xfcc8, 0x0000 },
+  { 0x8700, 0xfccb, 0x2000 },
+  { 0x0700, 0xfcca, 0x0000 },
+  { 0x0700, 0xfccc, 0x0000 },
+  { 0x8700, 0xfd0d, 0x7000 },
+  { 0x8700, 0xfced, 0x6000 },
+  { 0x8700, 0xfcdd, 0x5000 },
+  { 0x8700, 0xfcd5, 0x4000 },
+  { 0x8700, 0xfcd1, 0x3000 },
+  { 0x8700, 0xfccf, 0x2000 },
+  { 0x0700, 0xfcce, 0x0000 },
+  { 0x0700, 0xfcd0, 0x0000 },
+  { 0x8700, 0xfcd3, 0x2000 },
+  { 0x0700, 0xfcd2, 0x0000 },
+  { 0x0700, 0xfcd4, 0x0000 },
+  { 0x8700, 0xfcd9, 0x3000 },
+  { 0x8700, 0xfcd7, 0x2000 },
+  { 0x0700, 0xfcd6, 0x0000 },
+  { 0x0700, 0xfcd8, 0x0000 },
+  { 0x8700, 0xfcdb, 0x2000 },
+  { 0x0700, 0xfcda, 0x0000 },
+  { 0x0700, 0xfcdc, 0x0000 },
+  { 0x8700, 0xfce5, 0x4000 },
+  { 0x8700, 0xfce1, 0x3000 },
+  { 0x8700, 0xfcdf, 0x2000 },
+  { 0x0700, 0xfcde, 0x0000 },
+  { 0x0700, 0xfce0, 0x0000 },
+  { 0x8700, 0xfce3, 0x2000 },
+  { 0x0700, 0xfce2, 0x0000 },
+  { 0x0700, 0xfce4, 0x0000 },
+  { 0x8700, 0xfce9, 0x3000 },
+  { 0x8700, 0xfce7, 0x2000 },
+  { 0x0700, 0xfce6, 0x0000 },
+  { 0x0700, 0xfce8, 0x0000 },
+  { 0x8700, 0xfceb, 0x2000 },
+  { 0x0700, 0xfcea, 0x0000 },
+  { 0x0700, 0xfcec, 0x0000 },
+  { 0x8700, 0xfcfd, 0x5000 },
+  { 0x8700, 0xfcf5, 0x4000 },
+  { 0x8700, 0xfcf1, 0x3000 },
+  { 0x8700, 0xfcef, 0x2000 },
+  { 0x0700, 0xfcee, 0x0000 },
+  { 0x0700, 0xfcf0, 0x0000 },
+  { 0x8700, 0xfcf3, 0x2000 },
+  { 0x0700, 0xfcf2, 0x0000 },
+  { 0x0700, 0xfcf4, 0x0000 },
+  { 0x8700, 0xfcf9, 0x3000 },
+  { 0x8700, 0xfcf7, 0x2000 },
+  { 0x0700, 0xfcf6, 0x0000 },
+  { 0x0700, 0xfcf8, 0x0000 },
+  { 0x8700, 0xfcfb, 0x2000 },
+  { 0x0700, 0xfcfa, 0x0000 },
+  { 0x0700, 0xfcfc, 0x0000 },
+  { 0x8700, 0xfd05, 0x4000 },
+  { 0x8700, 0xfd01, 0x3000 },
+  { 0x8700, 0xfcff, 0x2000 },
+  { 0x0700, 0xfcfe, 0x0000 },
+  { 0x0700, 0xfd00, 0x0000 },
+  { 0x8700, 0xfd03, 0x2000 },
+  { 0x0700, 0xfd02, 0x0000 },
+  { 0x0700, 0xfd04, 0x0000 },
+  { 0x8700, 0xfd09, 0x3000 },
+  { 0x8700, 0xfd07, 0x2000 },
+  { 0x0700, 0xfd06, 0x0000 },
+  { 0x0700, 0xfd08, 0x0000 },
+  { 0x8700, 0xfd0b, 0x2000 },
+  { 0x0700, 0xfd0a, 0x0000 },
+  { 0x0700, 0xfd0c, 0x0000 },
+  { 0x8700, 0xfd2d, 0x6000 },
+  { 0x8700, 0xfd1d, 0x5000 },
+  { 0x8700, 0xfd15, 0x4000 },
+  { 0x8700, 0xfd11, 0x3000 },
+  { 0x8700, 0xfd0f, 0x2000 },
+  { 0x0700, 0xfd0e, 0x0000 },
+  { 0x0700, 0xfd10, 0x0000 },
+  { 0x8700, 0xfd13, 0x2000 },
+  { 0x0700, 0xfd12, 0x0000 },
+  { 0x0700, 0xfd14, 0x0000 },
+  { 0x8700, 0xfd19, 0x3000 },
+  { 0x8700, 0xfd17, 0x2000 },
+  { 0x0700, 0xfd16, 0x0000 },
+  { 0x0700, 0xfd18, 0x0000 },
+  { 0x8700, 0xfd1b, 0x2000 },
+  { 0x0700, 0xfd1a, 0x0000 },
+  { 0x0700, 0xfd1c, 0x0000 },
+  { 0x8700, 0xfd25, 0x4000 },
+  { 0x8700, 0xfd21, 0x3000 },
+  { 0x8700, 0xfd1f, 0x2000 },
+  { 0x0700, 0xfd1e, 0x0000 },
+  { 0x0700, 0xfd20, 0x0000 },
+  { 0x8700, 0xfd23, 0x2000 },
+  { 0x0700, 0xfd22, 0x0000 },
+  { 0x0700, 0xfd24, 0x0000 },
+  { 0x8700, 0xfd29, 0x3000 },
+  { 0x8700, 0xfd27, 0x2000 },
+  { 0x0700, 0xfd26, 0x0000 },
+  { 0x0700, 0xfd28, 0x0000 },
+  { 0x8700, 0xfd2b, 0x2000 },
+  { 0x0700, 0xfd2a, 0x0000 },
+  { 0x0700, 0xfd2c, 0x0000 },
+  { 0x8700, 0xfd3d, 0x5000 },
+  { 0x8700, 0xfd35, 0x4000 },
+  { 0x8700, 0xfd31, 0x3000 },
+  { 0x8700, 0xfd2f, 0x2000 },
+  { 0x0700, 0xfd2e, 0x0000 },
+  { 0x0700, 0xfd30, 0x0000 },
+  { 0x8700, 0xfd33, 0x2000 },
+  { 0x0700, 0xfd32, 0x0000 },
+  { 0x0700, 0xfd34, 0x0000 },
+  { 0x8700, 0xfd39, 0x3000 },
+  { 0x8700, 0xfd37, 0x2000 },
+  { 0x0700, 0xfd36, 0x0000 },
+  { 0x0700, 0xfd38, 0x0000 },
+  { 0x8700, 0xfd3b, 0x2000 },
+  { 0x0700, 0xfd3a, 0x0000 },
+  { 0x0700, 0xfd3c, 0x0000 },
+  { 0x8700, 0xfd55, 0x4000 },
+  { 0x8700, 0xfd51, 0x3000 },
+  { 0x9200, 0xfd3f, 0x2000 },
+  { 0x1600, 0xfd3e, 0x0000 },
+  { 0x0700, 0xfd50, 0x0000 },
+  { 0x8700, 0xfd53, 0x2000 },
+  { 0x0700, 0xfd52, 0x0000 },
+  { 0x0700, 0xfd54, 0x0000 },
+  { 0x8700, 0xfd59, 0x3000 },
+  { 0x8700, 0xfd57, 0x2000 },
+  { 0x0700, 0xfd56, 0x0000 },
+  { 0x0700, 0xfd58, 0x0000 },
+  { 0x8700, 0xfd5b, 0x2000 },
+  { 0x0700, 0xfd5a, 0x0000 },
+  { 0x0700, 0xfd5c, 0x0000 },
+  { 0x8c00, 0xfe09, 0x8000 },
+  { 0x8700, 0xfd9f, 0x7000 },
+  { 0x8700, 0xfd7d, 0x6000 },
+  { 0x8700, 0xfd6d, 0x5000 },
+  { 0x8700, 0xfd65, 0x4000 },
+  { 0x8700, 0xfd61, 0x3000 },
+  { 0x8700, 0xfd5f, 0x2000 },
+  { 0x0700, 0xfd5e, 0x0000 },
+  { 0x0700, 0xfd60, 0x0000 },
+  { 0x8700, 0xfd63, 0x2000 },
+  { 0x0700, 0xfd62, 0x0000 },
+  { 0x0700, 0xfd64, 0x0000 },
+  { 0x8700, 0xfd69, 0x3000 },
+  { 0x8700, 0xfd67, 0x2000 },
+  { 0x0700, 0xfd66, 0x0000 },
+  { 0x0700, 0xfd68, 0x0000 },
+  { 0x8700, 0xfd6b, 0x2000 },
+  { 0x0700, 0xfd6a, 0x0000 },
+  { 0x0700, 0xfd6c, 0x0000 },
+  { 0x8700, 0xfd75, 0x4000 },
+  { 0x8700, 0xfd71, 0x3000 },
+  { 0x8700, 0xfd6f, 0x2000 },
+  { 0x0700, 0xfd6e, 0x0000 },
+  { 0x0700, 0xfd70, 0x0000 },
+  { 0x8700, 0xfd73, 0x2000 },
+  { 0x0700, 0xfd72, 0x0000 },
+  { 0x0700, 0xfd74, 0x0000 },
+  { 0x8700, 0xfd79, 0x3000 },
+  { 0x8700, 0xfd77, 0x2000 },
+  { 0x0700, 0xfd76, 0x0000 },
+  { 0x0700, 0xfd78, 0x0000 },
+  { 0x8700, 0xfd7b, 0x2000 },
+  { 0x0700, 0xfd7a, 0x0000 },
+  { 0x0700, 0xfd7c, 0x0000 },
+  { 0x8700, 0xfd8d, 0x5000 },
+  { 0x8700, 0xfd85, 0x4000 },
+  { 0x8700, 0xfd81, 0x3000 },
+  { 0x8700, 0xfd7f, 0x2000 },
+  { 0x0700, 0xfd7e, 0x0000 },
+  { 0x0700, 0xfd80, 0x0000 },
+  { 0x8700, 0xfd83, 0x2000 },
+  { 0x0700, 0xfd82, 0x0000 },
+  { 0x0700, 0xfd84, 0x0000 },
+  { 0x8700, 0xfd89, 0x3000 },
+  { 0x8700, 0xfd87, 0x2000 },
+  { 0x0700, 0xfd86, 0x0000 },
+  { 0x0700, 0xfd88, 0x0000 },
+  { 0x8700, 0xfd8b, 0x2000 },
+  { 0x0700, 0xfd8a, 0x0000 },
+  { 0x0700, 0xfd8c, 0x0000 },
+  { 0x8700, 0xfd97, 0x4000 },
+  { 0x8700, 0xfd93, 0x3000 },
+  { 0x8700, 0xfd8f, 0x2000 },
+  { 0x0700, 0xfd8e, 0x0000 },
+  { 0x0700, 0xfd92, 0x0000 },
+  { 0x8700, 0xfd95, 0x2000 },
+  { 0x0700, 0xfd94, 0x0000 },
+  { 0x0700, 0xfd96, 0x0000 },
+  { 0x8700, 0xfd9b, 0x3000 },
+  { 0x8700, 0xfd99, 0x2000 },
+  { 0x0700, 0xfd98, 0x0000 },
+  { 0x0700, 0xfd9a, 0x0000 },
+  { 0x8700, 0xfd9d, 0x2000 },
+  { 0x0700, 0xfd9c, 0x0000 },
+  { 0x0700, 0xfd9e, 0x0000 },
+  { 0x8700, 0xfdbf, 0x6000 },
+  { 0x8700, 0xfdaf, 0x5000 },
+  { 0x8700, 0xfda7, 0x4000 },
+  { 0x8700, 0xfda3, 0x3000 },
+  { 0x8700, 0xfda1, 0x2000 },
+  { 0x0700, 0xfda0, 0x0000 },
+  { 0x0700, 0xfda2, 0x0000 },
+  { 0x8700, 0xfda5, 0x2000 },
+  { 0x0700, 0xfda4, 0x0000 },
+  { 0x0700, 0xfda6, 0x0000 },
+  { 0x8700, 0xfdab, 0x3000 },
+  { 0x8700, 0xfda9, 0x2000 },
+  { 0x0700, 0xfda8, 0x0000 },
+  { 0x0700, 0xfdaa, 0x0000 },
+  { 0x8700, 0xfdad, 0x2000 },
+  { 0x0700, 0xfdac, 0x0000 },
+  { 0x0700, 0xfdae, 0x0000 },
+  { 0x8700, 0xfdb7, 0x4000 },
+  { 0x8700, 0xfdb3, 0x3000 },
+  { 0x8700, 0xfdb1, 0x2000 },
+  { 0x0700, 0xfdb0, 0x0000 },
+  { 0x0700, 0xfdb2, 0x0000 },
+  { 0x8700, 0xfdb5, 0x2000 },
+  { 0x0700, 0xfdb4, 0x0000 },
+  { 0x0700, 0xfdb6, 0x0000 },
+  { 0x8700, 0xfdbb, 0x3000 },
+  { 0x8700, 0xfdb9, 0x2000 },
+  { 0x0700, 0xfdb8, 0x0000 },
+  { 0x0700, 0xfdba, 0x0000 },
+  { 0x8700, 0xfdbd, 0x2000 },
+  { 0x0700, 0xfdbc, 0x0000 },
+  { 0x0700, 0xfdbe, 0x0000 },
+  { 0x8700, 0xfdf7, 0x5000 },
+  { 0x8700, 0xfdc7, 0x4000 },
+  { 0x8700, 0xfdc3, 0x3000 },
+  { 0x8700, 0xfdc1, 0x2000 },
+  { 0x0700, 0xfdc0, 0x0000 },
+  { 0x0700, 0xfdc2, 0x0000 },
+  { 0x8700, 0xfdc5, 0x2000 },
+  { 0x0700, 0xfdc4, 0x0000 },
+  { 0x0700, 0xfdc6, 0x0000 },
+  { 0x8700, 0xfdf3, 0x3000 },
+  { 0x8700, 0xfdf1, 0x2000 },
+  { 0x0700, 0xfdf0, 0x0000 },
+  { 0x0700, 0xfdf2, 0x0000 },
+  { 0x8700, 0xfdf5, 0x2000 },
+  { 0x0700, 0xfdf4, 0x0000 },
+  { 0x0700, 0xfdf6, 0x0000 },
+  { 0x8c00, 0xfe01, 0x4000 },
+  { 0x8700, 0xfdfb, 0x3000 },
+  { 0x8700, 0xfdf9, 0x2000 },
+  { 0x0700, 0xfdf8, 0x0000 },
+  { 0x0700, 0xfdfa, 0x0000 },
+  { 0x9a00, 0xfdfd, 0x2000 },
+  { 0x1700, 0xfdfc, 0x0000 },
+  { 0x0c00, 0xfe00, 0x0000 },
+  { 0x8c00, 0xfe05, 0x3000 },
+  { 0x8c00, 0xfe03, 0x2000 },
+  { 0x0c00, 0xfe02, 0x0000 },
+  { 0x0c00, 0xfe04, 0x0000 },
+  { 0x8c00, 0xfe07, 0x2000 },
+  { 0x0c00, 0xfe06, 0x0000 },
+  { 0x0c00, 0xfe08, 0x0000 },
+  { 0x9900, 0xfe66, 0x7000 },
+  { 0x9500, 0xfe45, 0x6000 },
+  { 0x9600, 0xfe35, 0x5000 },
+  { 0x8c00, 0xfe21, 0x4000 },
+  { 0x8c00, 0xfe0d, 0x3000 },
+  { 0x8c00, 0xfe0b, 0x2000 },
+  { 0x0c00, 0xfe0a, 0x0000 },
+  { 0x0c00, 0xfe0c, 0x0000 },
+  { 0x8c00, 0xfe0f, 0x2000 },
+  { 0x0c00, 0xfe0e, 0x0000 },
+  { 0x0c00, 0xfe20, 0x0000 },
+  { 0x9100, 0xfe31, 0x3000 },
+  { 0x8c00, 0xfe23, 0x2000 },
+  { 0x0c00, 0xfe22, 0x0000 },
+  { 0x1500, 0xfe30, 0x0000 },
+  { 0x9000, 0xfe33, 0x2000 },
+  { 0x1100, 0xfe32, 0x0000 },
+  { 0x1000, 0xfe34, 0x0000 },
+  { 0x9600, 0xfe3d, 0x4000 },
+  { 0x9600, 0xfe39, 0x3000 },
+  { 0x9600, 0xfe37, 0x2000 },
+  { 0x1200, 0xfe36, 0x0000 },
+  { 0x1200, 0xfe38, 0x0000 },
+  { 0x9600, 0xfe3b, 0x2000 },
+  { 0x1200, 0xfe3a, 0x0000 },
+  { 0x1200, 0xfe3c, 0x0000 },
+  { 0x9600, 0xfe41, 0x3000 },
+  { 0x9600, 0xfe3f, 0x2000 },
+  { 0x1200, 0xfe3e, 0x0000 },
+  { 0x1200, 0xfe40, 0x0000 },
+  { 0x9600, 0xfe43, 0x2000 },
+  { 0x1200, 0xfe42, 0x0000 },
+  { 0x1200, 0xfe44, 0x0000 },
+  { 0x9500, 0xfe56, 0x5000 },
+  { 0x9000, 0xfe4d, 0x4000 },
+  { 0x9500, 0xfe49, 0x3000 },
+  { 0x9600, 0xfe47, 0x2000 },
+  { 0x1500, 0xfe46, 0x0000 },
+  { 0x1200, 0xfe48, 0x0000 },
+  { 0x9500, 0xfe4b, 0x2000 },
+  { 0x1500, 0xfe4a, 0x0000 },
+  { 0x1500, 0xfe4c, 0x0000 },
+  { 0x9500, 0xfe51, 0x3000 },
+  { 0x9000, 0xfe4f, 0x2000 },
+  { 0x1000, 0xfe4e, 0x0000 },
+  { 0x1500, 0xfe50, 0x0000 },
+  { 0x9500, 0xfe54, 0x2000 },
+  { 0x1500, 0xfe52, 0x0000 },
+  { 0x1500, 0xfe55, 0x0000 },
+  { 0x9200, 0xfe5e, 0x4000 },
+  { 0x9200, 0xfe5a, 0x3000 },
+  { 0x9100, 0xfe58, 0x2000 },
+  { 0x1500, 0xfe57, 0x0000 },
+  { 0x1600, 0xfe59, 0x0000 },
+  { 0x9200, 0xfe5c, 0x2000 },
+  { 0x1600, 0xfe5b, 0x0000 },
+  { 0x1600, 0xfe5d, 0x0000 },
+  { 0x9900, 0xfe62, 0x3000 },
+  { 0x9500, 0xfe60, 0x2000 },
+  { 0x1500, 0xfe5f, 0x0000 },
+  { 0x1500, 0xfe61, 0x0000 },
+  { 0x9900, 0xfe64, 0x2000 },
+  { 0x1100, 0xfe63, 0x0000 },
+  { 0x1900, 0xfe65, 0x0000 },
+  { 0x8700, 0xfe8c, 0x6000 },
+  { 0x8700, 0xfe7c, 0x5000 },
+  { 0x8700, 0xfe73, 0x4000 },
+  { 0x9500, 0xfe6b, 0x3000 },
+  { 0x9700, 0xfe69, 0x2000 },
+  { 0x1500, 0xfe68, 0x0000 },
+  { 0x1500, 0xfe6a, 0x0000 },
+  { 0x8700, 0xfe71, 0x2000 },
+  { 0x0700, 0xfe70, 0x0000 },
+  { 0x0700, 0xfe72, 0x0000 },
+  { 0x8700, 0xfe78, 0x3000 },
+  { 0x8700, 0xfe76, 0x2000 },
+  { 0x0700, 0xfe74, 0x0000 },
+  { 0x0700, 0xfe77, 0x0000 },
+  { 0x8700, 0xfe7a, 0x2000 },
+  { 0x0700, 0xfe79, 0x0000 },
+  { 0x0700, 0xfe7b, 0x0000 },
+  { 0x8700, 0xfe84, 0x4000 },
+  { 0x8700, 0xfe80, 0x3000 },
+  { 0x8700, 0xfe7e, 0x2000 },
+  { 0x0700, 0xfe7d, 0x0000 },
+  { 0x0700, 0xfe7f, 0x0000 },
+  { 0x8700, 0xfe82, 0x2000 },
+  { 0x0700, 0xfe81, 0x0000 },
+  { 0x0700, 0xfe83, 0x0000 },
+  { 0x8700, 0xfe88, 0x3000 },
+  { 0x8700, 0xfe86, 0x2000 },
+  { 0x0700, 0xfe85, 0x0000 },
+  { 0x0700, 0xfe87, 0x0000 },
+  { 0x8700, 0xfe8a, 0x2000 },
+  { 0x0700, 0xfe89, 0x0000 },
+  { 0x0700, 0xfe8b, 0x0000 },
+  { 0x8700, 0xfe9c, 0x5000 },
+  { 0x8700, 0xfe94, 0x4000 },
+  { 0x8700, 0xfe90, 0x3000 },
+  { 0x8700, 0xfe8e, 0x2000 },
+  { 0x0700, 0xfe8d, 0x0000 },
+  { 0x0700, 0xfe8f, 0x0000 },
+  { 0x8700, 0xfe92, 0x2000 },
+  { 0x0700, 0xfe91, 0x0000 },
+  { 0x0700, 0xfe93, 0x0000 },
+  { 0x8700, 0xfe98, 0x3000 },
+  { 0x8700, 0xfe96, 0x2000 },
+  { 0x0700, 0xfe95, 0x0000 },
+  { 0x0700, 0xfe97, 0x0000 },
+  { 0x8700, 0xfe9a, 0x2000 },
+  { 0x0700, 0xfe99, 0x0000 },
+  { 0x0700, 0xfe9b, 0x0000 },
+  { 0x8700, 0xfea4, 0x4000 },
+  { 0x8700, 0xfea0, 0x3000 },
+  { 0x8700, 0xfe9e, 0x2000 },
+  { 0x0700, 0xfe9d, 0x0000 },
+  { 0x0700, 0xfe9f, 0x0000 },
+  { 0x8700, 0xfea2, 0x2000 },
+  { 0x0700, 0xfea1, 0x0000 },
+  { 0x0700, 0xfea3, 0x0000 },
+  { 0x8700, 0xfea8, 0x3000 },
+  { 0x8700, 0xfea6, 0x2000 },
+  { 0x0700, 0xfea5, 0x0000 },
+  { 0x0700, 0xfea7, 0x0000 },
+  { 0x8700, 0xfeaa, 0x2000 },
+  { 0x0700, 0xfea9, 0x0000 },
+  { 0x0700, 0xfeab, 0x0000 },
+  { 0x8700, 0xffaf, 0x9000 },
+  { 0x8900, 0xff2f, 0x8020 },
+  { 0x8700, 0xfeec, 0x7000 },
+  { 0x8700, 0xfecc, 0x6000 },
+  { 0x8700, 0xfebc, 0x5000 },
+  { 0x8700, 0xfeb4, 0x4000 },
+  { 0x8700, 0xfeb0, 0x3000 },
+  { 0x8700, 0xfeae, 0x2000 },
+  { 0x0700, 0xfead, 0x0000 },
+  { 0x0700, 0xfeaf, 0x0000 },
+  { 0x8700, 0xfeb2, 0x2000 },
+  { 0x0700, 0xfeb1, 0x0000 },
+  { 0x0700, 0xfeb3, 0x0000 },
+  { 0x8700, 0xfeb8, 0x3000 },
+  { 0x8700, 0xfeb6, 0x2000 },
+  { 0x0700, 0xfeb5, 0x0000 },
+  { 0x0700, 0xfeb7, 0x0000 },
+  { 0x8700, 0xfeba, 0x2000 },
+  { 0x0700, 0xfeb9, 0x0000 },
+  { 0x0700, 0xfebb, 0x0000 },
+  { 0x8700, 0xfec4, 0x4000 },
+  { 0x8700, 0xfec0, 0x3000 },
+  { 0x8700, 0xfebe, 0x2000 },
+  { 0x0700, 0xfebd, 0x0000 },
+  { 0x0700, 0xfebf, 0x0000 },
+  { 0x8700, 0xfec2, 0x2000 },
+  { 0x0700, 0xfec1, 0x0000 },
+  { 0x0700, 0xfec3, 0x0000 },
+  { 0x8700, 0xfec8, 0x3000 },
+  { 0x8700, 0xfec6, 0x2000 },
+  { 0x0700, 0xfec5, 0x0000 },
+  { 0x0700, 0xfec7, 0x0000 },
+  { 0x8700, 0xfeca, 0x2000 },
+  { 0x0700, 0xfec9, 0x0000 },
+  { 0x0700, 0xfecb, 0x0000 },
+  { 0x8700, 0xfedc, 0x5000 },
+  { 0x8700, 0xfed4, 0x4000 },
+  { 0x8700, 0xfed0, 0x3000 },
+  { 0x8700, 0xfece, 0x2000 },
+  { 0x0700, 0xfecd, 0x0000 },
+  { 0x0700, 0xfecf, 0x0000 },
+  { 0x8700, 0xfed2, 0x2000 },
+  { 0x0700, 0xfed1, 0x0000 },
+  { 0x0700, 0xfed3, 0x0000 },
+  { 0x8700, 0xfed8, 0x3000 },
+  { 0x8700, 0xfed6, 0x2000 },
+  { 0x0700, 0xfed5, 0x0000 },
+  { 0x0700, 0xfed7, 0x0000 },
+  { 0x8700, 0xfeda, 0x2000 },
+  { 0x0700, 0xfed9, 0x0000 },
+  { 0x0700, 0xfedb, 0x0000 },
+  { 0x8700, 0xfee4, 0x4000 },
+  { 0x8700, 0xfee0, 0x3000 },
+  { 0x8700, 0xfede, 0x2000 },
+  { 0x0700, 0xfedd, 0x0000 },
+  { 0x0700, 0xfedf, 0x0000 },
+  { 0x8700, 0xfee2, 0x2000 },
+  { 0x0700, 0xfee1, 0x0000 },
+  { 0x0700, 0xfee3, 0x0000 },
+  { 0x8700, 0xfee8, 0x3000 },
+  { 0x8700, 0xfee6, 0x2000 },
+  { 0x0700, 0xfee5, 0x0000 },
+  { 0x0700, 0xfee7, 0x0000 },
+  { 0x8700, 0xfeea, 0x2000 },
+  { 0x0700, 0xfee9, 0x0000 },
+  { 0x0700, 0xfeeb, 0x0000 },
+  { 0x9500, 0xff0f, 0x6000 },
+  { 0x8700, 0xfefc, 0x5000 },
+  { 0x8700, 0xfef4, 0x4000 },
+  { 0x8700, 0xfef0, 0x3000 },
+  { 0x8700, 0xfeee, 0x2000 },
+  { 0x0700, 0xfeed, 0x0000 },
+  { 0x0700, 0xfeef, 0x0000 },
+  { 0x8700, 0xfef2, 0x2000 },
+  { 0x0700, 0xfef1, 0x0000 },
+  { 0x0700, 0xfef3, 0x0000 },
+  { 0x8700, 0xfef8, 0x3000 },
+  { 0x8700, 0xfef6, 0x2000 },
+  { 0x0700, 0xfef5, 0x0000 },
+  { 0x0700, 0xfef7, 0x0000 },
+  { 0x8700, 0xfefa, 0x2000 },
+  { 0x0700, 0xfef9, 0x0000 },
+  { 0x0700, 0xfefb, 0x0000 },
+  { 0x9500, 0xff07, 0x4000 },
+  { 0x9500, 0xff03, 0x3000 },
+  { 0x9500, 0xff01, 0x2000 },
+  { 0x0100, 0xfeff, 0x0000 },
+  { 0x1500, 0xff02, 0x0000 },
+  { 0x9500, 0xff05, 0x2000 },
+  { 0x1700, 0xff04, 0x0000 },
+  { 0x1500, 0xff06, 0x0000 },
+  { 0x9900, 0xff0b, 0x3000 },
+  { 0x9200, 0xff09, 0x2000 },
+  { 0x1600, 0xff08, 0x0000 },
+  { 0x1500, 0xff0a, 0x0000 },
+  { 0x9100, 0xff0d, 0x2000 },
+  { 0x1500, 0xff0c, 0x0000 },
+  { 0x1500, 0xff0e, 0x0000 },
+  { 0x9500, 0xff1f, 0x5000 },
+  { 0x8d00, 0xff17, 0x4000 },
+  { 0x8d00, 0xff13, 0x3000 },
+  { 0x8d00, 0xff11, 0x2000 },
+  { 0x0d00, 0xff10, 0x0000 },
+  { 0x0d00, 0xff12, 0x0000 },
+  { 0x8d00, 0xff15, 0x2000 },
+  { 0x0d00, 0xff14, 0x0000 },
+  { 0x0d00, 0xff16, 0x0000 },
+  { 0x9500, 0xff1b, 0x3000 },
+  { 0x8d00, 0xff19, 0x2000 },
+  { 0x0d00, 0xff18, 0x0000 },
+  { 0x1500, 0xff1a, 0x0000 },
+  { 0x9900, 0xff1d, 0x2000 },
+  { 0x1900, 0xff1c, 0x0000 },
+  { 0x1900, 0xff1e, 0x0000 },
+  { 0x8900, 0xff27, 0x4020 },
+  { 0x8900, 0xff23, 0x3020 },
+  { 0x8900, 0xff21, 0x2020 },
+  { 0x1500, 0xff20, 0x0000 },
+  { 0x0900, 0xff22, 0x0020 },
+  { 0x8900, 0xff25, 0x2020 },
+  { 0x0900, 0xff24, 0x0020 },
+  { 0x0900, 0xff26, 0x0020 },
+  { 0x8900, 0xff2b, 0x3020 },
+  { 0x8900, 0xff29, 0x2020 },
+  { 0x0900, 0xff28, 0x0020 },
+  { 0x0900, 0xff2a, 0x0020 },
+  { 0x8900, 0xff2d, 0x2020 },
+  { 0x0900, 0xff2c, 0x0020 },
+  { 0x0900, 0xff2e, 0x0020 },
+  { 0x8700, 0xff6f, 0x7000 },
+  { 0x8500, 0xff4f, 0x6fe0 },
+  { 0x9000, 0xff3f, 0x5000 },
+  { 0x8900, 0xff37, 0x4020 },
+  { 0x8900, 0xff33, 0x3020 },
+  { 0x8900, 0xff31, 0x2020 },
+  { 0x0900, 0xff30, 0x0020 },
+  { 0x0900, 0xff32, 0x0020 },
+  { 0x8900, 0xff35, 0x2020 },
+  { 0x0900, 0xff34, 0x0020 },
+  { 0x0900, 0xff36, 0x0020 },
+  { 0x9600, 0xff3b, 0x3000 },
+  { 0x8900, 0xff39, 0x2020 },
+  { 0x0900, 0xff38, 0x0020 },
+  { 0x0900, 0xff3a, 0x0020 },
+  { 0x9200, 0xff3d, 0x2000 },
+  { 0x1500, 0xff3c, 0x0000 },
+  { 0x1800, 0xff3e, 0x0000 },
+  { 0x8500, 0xff47, 0x4fe0 },
+  { 0x8500, 0xff43, 0x3fe0 },
+  { 0x8500, 0xff41, 0x2fe0 },
+  { 0x1800, 0xff40, 0x0000 },
+  { 0x0500, 0xff42, 0x0fe0 },
+  { 0x8500, 0xff45, 0x2fe0 },
+  { 0x0500, 0xff44, 0x0fe0 },
+  { 0x0500, 0xff46, 0x0fe0 },
+  { 0x8500, 0xff4b, 0x3fe0 },
+  { 0x8500, 0xff49, 0x2fe0 },
+  { 0x0500, 0xff48, 0x0fe0 },
+  { 0x0500, 0xff4a, 0x0fe0 },
+  { 0x8500, 0xff4d, 0x2fe0 },
+  { 0x0500, 0xff4c, 0x0fe0 },
+  { 0x0500, 0xff4e, 0x0fe0 },
+  { 0x9600, 0xff5f, 0x5000 },
+  { 0x8500, 0xff57, 0x4fe0 },
+  { 0x8500, 0xff53, 0x3fe0 },
+  { 0x8500, 0xff51, 0x2fe0 },
+  { 0x0500, 0xff50, 0x0fe0 },
+  { 0x0500, 0xff52, 0x0fe0 },
+  { 0x8500, 0xff55, 0x2fe0 },
+  { 0x0500, 0xff54, 0x0fe0 },
+  { 0x0500, 0xff56, 0x0fe0 },
+  { 0x9600, 0xff5b, 0x3000 },
+  { 0x8500, 0xff59, 0x2fe0 },
+  { 0x0500, 0xff58, 0x0fe0 },
+  { 0x0500, 0xff5a, 0x0fe0 },
+  { 0x9200, 0xff5d, 0x2000 },
+  { 0x1900, 0xff5c, 0x0000 },
+  { 0x1900, 0xff5e, 0x0000 },
+  { 0x8700, 0xff67, 0x4000 },
+  { 0x9200, 0xff63, 0x3000 },
+  { 0x9500, 0xff61, 0x2000 },
+  { 0x1200, 0xff60, 0x0000 },
+  { 0x1600, 0xff62, 0x0000 },
+  { 0x9000, 0xff65, 0x2000 },
+  { 0x1500, 0xff64, 0x0000 },
+  { 0x0700, 0xff66, 0x0000 },
+  { 0x8700, 0xff6b, 0x3000 },
+  { 0x8700, 0xff69, 0x2000 },
+  { 0x0700, 0xff68, 0x0000 },
+  { 0x0700, 0xff6a, 0x0000 },
+  { 0x8700, 0xff6d, 0x2000 },
+  { 0x0700, 0xff6c, 0x0000 },
+  { 0x0700, 0xff6e, 0x0000 },
+  { 0x8700, 0xff8f, 0x6000 },
+  { 0x8700, 0xff7f, 0x5000 },
+  { 0x8700, 0xff77, 0x4000 },
+  { 0x8700, 0xff73, 0x3000 },
+  { 0x8700, 0xff71, 0x2000 },
+  { 0x0600, 0xff70, 0x0000 },
+  { 0x0700, 0xff72, 0x0000 },
+  { 0x8700, 0xff75, 0x2000 },
+  { 0x0700, 0xff74, 0x0000 },
+  { 0x0700, 0xff76, 0x0000 },
+  { 0x8700, 0xff7b, 0x3000 },
+  { 0x8700, 0xff79, 0x2000 },
+  { 0x0700, 0xff78, 0x0000 },
+  { 0x0700, 0xff7a, 0x0000 },
+  { 0x8700, 0xff7d, 0x2000 },
+  { 0x0700, 0xff7c, 0x0000 },
+  { 0x0700, 0xff7e, 0x0000 },
+  { 0x8700, 0xff87, 0x4000 },
+  { 0x8700, 0xff83, 0x3000 },
+  { 0x8700, 0xff81, 0x2000 },
+  { 0x0700, 0xff80, 0x0000 },
+  { 0x0700, 0xff82, 0x0000 },
+  { 0x8700, 0xff85, 0x2000 },
+  { 0x0700, 0xff84, 0x0000 },
+  { 0x0700, 0xff86, 0x0000 },
+  { 0x8700, 0xff8b, 0x3000 },
+  { 0x8700, 0xff89, 0x2000 },
+  { 0x0700, 0xff88, 0x0000 },
+  { 0x0700, 0xff8a, 0x0000 },
+  { 0x8700, 0xff8d, 0x2000 },
+  { 0x0700, 0xff8c, 0x0000 },
+  { 0x0700, 0xff8e, 0x0000 },
+  { 0x8600, 0xff9f, 0x5000 },
+  { 0x8700, 0xff97, 0x4000 },
+  { 0x8700, 0xff93, 0x3000 },
+  { 0x8700, 0xff91, 0x2000 },
+  { 0x0700, 0xff90, 0x0000 },
+  { 0x0700, 0xff92, 0x0000 },
+  { 0x8700, 0xff95, 0x2000 },
+  { 0x0700, 0xff94, 0x0000 },
+  { 0x0700, 0xff96, 0x0000 },
+  { 0x8700, 0xff9b, 0x3000 },
+  { 0x8700, 0xff99, 0x2000 },
+  { 0x0700, 0xff98, 0x0000 },
+  { 0x0700, 0xff9a, 0x0000 },
+  { 0x8700, 0xff9d, 0x2000 },
+  { 0x0700, 0xff9c, 0x0000 },
+  { 0x0600, 0xff9e, 0x0000 },
+  { 0x8700, 0xffa7, 0x4000 },
+  { 0x8700, 0xffa3, 0x3000 },
+  { 0x8700, 0xffa1, 0x2000 },
+  { 0x0700, 0xffa0, 0x0000 },
+  { 0x0700, 0xffa2, 0x0000 },
+  { 0x8700, 0xffa5, 0x2000 },
+  { 0x0700, 0xffa4, 0x0000 },
+  { 0x0700, 0xffa6, 0x0000 },
+  { 0x8700, 0xffab, 0x3000 },
+  { 0x8700, 0xffa9, 0x2000 },
+  { 0x0700, 0xffa8, 0x0000 },
+  { 0x0700, 0xffaa, 0x0000 },
+  { 0x8700, 0xffad, 0x2000 },
+  { 0x0700, 0xffac, 0x0000 },
+  { 0x0700, 0xffae, 0x0000 },
+  { 0x8701, 0x004c, 0x8000 },
+  { 0x8701, 0x0008, 0x7000 },
+  { 0x8700, 0xffd6, 0x6000 },
+  { 0x8700, 0xffc2, 0x5000 },
+  { 0x8700, 0xffb7, 0x4000 },
+  { 0x8700, 0xffb3, 0x3000 },
+  { 0x8700, 0xffb1, 0x2000 },
+  { 0x0700, 0xffb0, 0x0000 },
+  { 0x0700, 0xffb2, 0x0000 },
+  { 0x8700, 0xffb5, 0x2000 },
+  { 0x0700, 0xffb4, 0x0000 },
+  { 0x0700, 0xffb6, 0x0000 },
+  { 0x8700, 0xffbb, 0x3000 },
+  { 0x8700, 0xffb9, 0x2000 },
+  { 0x0700, 0xffb8, 0x0000 },
+  { 0x0700, 0xffba, 0x0000 },
+  { 0x8700, 0xffbd, 0x2000 },
+  { 0x0700, 0xffbc, 0x0000 },
+  { 0x0700, 0xffbe, 0x0000 },
+  { 0x8700, 0xffcc, 0x4000 },
+  { 0x8700, 0xffc6, 0x3000 },
+  { 0x8700, 0xffc4, 0x2000 },
+  { 0x0700, 0xffc3, 0x0000 },
+  { 0x0700, 0xffc5, 0x0000 },
+  { 0x8700, 0xffca, 0x2000 },
+  { 0x0700, 0xffc7, 0x0000 },
+  { 0x0700, 0xffcb, 0x0000 },
+  { 0x8700, 0xffd2, 0x3000 },
+  { 0x8700, 0xffce, 0x2000 },
+  { 0x0700, 0xffcd, 0x0000 },
+  { 0x0700, 0xffcf, 0x0000 },
+  { 0x8700, 0xffd4, 0x2000 },
+  { 0x0700, 0xffd3, 0x0000 },
+  { 0x0700, 0xffd5, 0x0000 },
+  { 0x9900, 0xffec, 0x5000 },
+  { 0x9800, 0xffe3, 0x4000 },
+  { 0x8700, 0xffdc, 0x3000 },
+  { 0x8700, 0xffda, 0x2000 },
+  { 0x0700, 0xffd7, 0x0000 },
+  { 0x0700, 0xffdb, 0x0000 },
+  { 0x9700, 0xffe1, 0x2000 },
+  { 0x1700, 0xffe0, 0x0000 },
+  { 0x1900, 0xffe2, 0x0000 },
+  { 0x9a00, 0xffe8, 0x3000 },
+  { 0x9700, 0xffe5, 0x2000 },
+  { 0x1a00, 0xffe4, 0x0000 },
+  { 0x1700, 0xffe6, 0x0000 },
+  { 0x9900, 0xffea, 0x2000 },
+  { 0x1900, 0xffe9, 0x0000 },
+  { 0x1900, 0xffeb, 0x0000 },
+  { 0x8701, 0x0000, 0x4000 },
+  { 0x8100, 0xfffa, 0x3000 },
+  { 0x9a00, 0xffee, 0x2000 },
+  { 0x1a00, 0xffed, 0x0000 },
+  { 0x0100, 0xfff9, 0x0000 },
+  { 0x9a00, 0xfffc, 0x2000 },
+  { 0x0100, 0xfffb, 0x0000 },
+  { 0x1a00, 0xfffd, 0x0000 },
+  { 0x8701, 0x0004, 0x3000 },
+  { 0x8701, 0x0002, 0x2000 },
+  { 0x0701, 0x0001, 0x0000 },
+  { 0x0701, 0x0003, 0x0000 },
+  { 0x8701, 0x0006, 0x2000 },
+  { 0x0701, 0x0005, 0x0000 },
+  { 0x0701, 0x0007, 0x0000 },
+  { 0x8701, 0x002a, 0x6000 },
+  { 0x8701, 0x0019, 0x5000 },
+  { 0x8701, 0x0011, 0x4000 },
+  { 0x8701, 0x000d, 0x3000 },
+  { 0x8701, 0x000a, 0x2000 },
+  { 0x0701, 0x0009, 0x0000 },
+  { 0x0701, 0x000b, 0x0000 },
+  { 0x8701, 0x000f, 0x2000 },
+  { 0x0701, 0x000e, 0x0000 },
+  { 0x0701, 0x0010, 0x0000 },
+  { 0x8701, 0x0015, 0x3000 },
+  { 0x8701, 0x0013, 0x2000 },
+  { 0x0701, 0x0012, 0x0000 },
+  { 0x0701, 0x0014, 0x0000 },
+  { 0x8701, 0x0017, 0x2000 },
+  { 0x0701, 0x0016, 0x0000 },
+  { 0x0701, 0x0018, 0x0000 },
+  { 0x8701, 0x0021, 0x4000 },
+  { 0x8701, 0x001d, 0x3000 },
+  { 0x8701, 0x001b, 0x2000 },
+  { 0x0701, 0x001a, 0x0000 },
+  { 0x0701, 0x001c, 0x0000 },
+  { 0x8701, 0x001f, 0x2000 },
+  { 0x0701, 0x001e, 0x0000 },
+  { 0x0701, 0x0020, 0x0000 },
+  { 0x8701, 0x0025, 0x3000 },
+  { 0x8701, 0x0023, 0x2000 },
+  { 0x0701, 0x0022, 0x0000 },
+  { 0x0701, 0x0024, 0x0000 },
+  { 0x8701, 0x0028, 0x2000 },
+  { 0x0701, 0x0026, 0x0000 },
+  { 0x0701, 0x0029, 0x0000 },
+  { 0x8701, 0x003a, 0x5000 },
+  { 0x8701, 0x0032, 0x4000 },
+  { 0x8701, 0x002e, 0x3000 },
+  { 0x8701, 0x002c, 0x2000 },
+  { 0x0701, 0x002b, 0x0000 },
+  { 0x0701, 0x002d, 0x0000 },
+  { 0x8701, 0x0030, 0x2000 },
+  { 0x0701, 0x002f, 0x0000 },
+  { 0x0701, 0x0031, 0x0000 },
+  { 0x8701, 0x0036, 0x3000 },
+  { 0x8701, 0x0034, 0x2000 },
+  { 0x0701, 0x0033, 0x0000 },
+  { 0x0701, 0x0035, 0x0000 },
+  { 0x8701, 0x0038, 0x2000 },
+  { 0x0701, 0x0037, 0x0000 },
+  { 0x0701, 0x0039, 0x0000 },
+  { 0x8701, 0x0044, 0x4000 },
+  { 0x8701, 0x0040, 0x3000 },
+  { 0x8701, 0x003d, 0x2000 },
+  { 0x0701, 0x003c, 0x0000 },
+  { 0x0701, 0x003f, 0x0000 },
+  { 0x8701, 0x0042, 0x2000 },
+  { 0x0701, 0x0041, 0x0000 },
+  { 0x0701, 0x0043, 0x0000 },
+  { 0x8701, 0x0048, 0x3000 },
+  { 0x8701, 0x0046, 0x2000 },
+  { 0x0701, 0x0045, 0x0000 },
+  { 0x0701, 0x0047, 0x0000 },
+  { 0x8701, 0x004a, 0x2000 },
+  { 0x0701, 0x0049, 0x0000 },
+  { 0x0701, 0x004b, 0x0000 },
+  { 0x8701, 0x00b0, 0x7000 },
+  { 0x8701, 0x0090, 0x6000 },
+  { 0x8701, 0x0080, 0x5000 },
+  { 0x8701, 0x0056, 0x4000 },
+  { 0x8701, 0x0052, 0x3000 },
+  { 0x8701, 0x0050, 0x2000 },
+  { 0x0701, 0x004d, 0x0000 },
+  { 0x0701, 0x0051, 0x0000 },
+  { 0x8701, 0x0054, 0x2000 },
+  { 0x0701, 0x0053, 0x0000 },
+  { 0x0701, 0x0055, 0x0000 },
+  { 0x8701, 0x005a, 0x3000 },
+  { 0x8701, 0x0058, 0x2000 },
+  { 0x0701, 0x0057, 0x0000 },
+  { 0x0701, 0x0059, 0x0000 },
+  { 0x8701, 0x005c, 0x2000 },
+  { 0x0701, 0x005b, 0x0000 },
+  { 0x0701, 0x005d, 0x0000 },
+  { 0x8701, 0x0088, 0x4000 },
+  { 0x8701, 0x0084, 0x3000 },
+  { 0x8701, 0x0082, 0x2000 },
+  { 0x0701, 0x0081, 0x0000 },
+  { 0x0701, 0x0083, 0x0000 },
+  { 0x8701, 0x0086, 0x2000 },
+  { 0x0701, 0x0085, 0x0000 },
+  { 0x0701, 0x0087, 0x0000 },
+  { 0x8701, 0x008c, 0x3000 },
+  { 0x8701, 0x008a, 0x2000 },
+  { 0x0701, 0x0089, 0x0000 },
+  { 0x0701, 0x008b, 0x0000 },
+  { 0x8701, 0x008e, 0x2000 },
+  { 0x0701, 0x008d, 0x0000 },
+  { 0x0701, 0x008f, 0x0000 },
+  { 0x8701, 0x00a0, 0x5000 },
+  { 0x8701, 0x0098, 0x4000 },
+  { 0x8701, 0x0094, 0x3000 },
+  { 0x8701, 0x0092, 0x2000 },
+  { 0x0701, 0x0091, 0x0000 },
+  { 0x0701, 0x0093, 0x0000 },
+  { 0x8701, 0x0096, 0x2000 },
+  { 0x0701, 0x0095, 0x0000 },
+  { 0x0701, 0x0097, 0x0000 },
+  { 0x8701, 0x009c, 0x3000 },
+  { 0x8701, 0x009a, 0x2000 },
+  { 0x0701, 0x0099, 0x0000 },
+  { 0x0701, 0x009b, 0x0000 },
+  { 0x8701, 0x009e, 0x2000 },
+  { 0x0701, 0x009d, 0x0000 },
+  { 0x0701, 0x009f, 0x0000 },
+  { 0x8701, 0x00a8, 0x4000 },
+  { 0x8701, 0x00a4, 0x3000 },
+  { 0x8701, 0x00a2, 0x2000 },
+  { 0x0701, 0x00a1, 0x0000 },
+  { 0x0701, 0x00a3, 0x0000 },
+  { 0x8701, 0x00a6, 0x2000 },
+  { 0x0701, 0x00a5, 0x0000 },
+  { 0x0701, 0x00a7, 0x0000 },
+  { 0x8701, 0x00ac, 0x3000 },
+  { 0x8701, 0x00aa, 0x2000 },
+  { 0x0701, 0x00a9, 0x0000 },
+  { 0x0701, 0x00ab, 0x0000 },
+  { 0x8701, 0x00ae, 0x2000 },
+  { 0x0701, 0x00ad, 0x0000 },
+  { 0x0701, 0x00af, 0x0000 },
+  { 0x8701, 0x00d0, 0x6000 },
+  { 0x8701, 0x00c0, 0x5000 },
+  { 0x8701, 0x00b8, 0x4000 },
+  { 0x8701, 0x00b4, 0x3000 },
+  { 0x8701, 0x00b2, 0x2000 },
+  { 0x0701, 0x00b1, 0x0000 },
+  { 0x0701, 0x00b3, 0x0000 },
+  { 0x8701, 0x00b6, 0x2000 },
+  { 0x0701, 0x00b5, 0x0000 },
+  { 0x0701, 0x00b7, 0x0000 },
+  { 0x8701, 0x00bc, 0x3000 },
+  { 0x8701, 0x00ba, 0x2000 },
+  { 0x0701, 0x00b9, 0x0000 },
+  { 0x0701, 0x00bb, 0x0000 },
+  { 0x8701, 0x00be, 0x2000 },
+  { 0x0701, 0x00bd, 0x0000 },
+  { 0x0701, 0x00bf, 0x0000 },
+  { 0x8701, 0x00c8, 0x4000 },
+  { 0x8701, 0x00c4, 0x3000 },
+  { 0x8701, 0x00c2, 0x2000 },
+  { 0x0701, 0x00c1, 0x0000 },
+  { 0x0701, 0x00c3, 0x0000 },
+  { 0x8701, 0x00c6, 0x2000 },
+  { 0x0701, 0x00c5, 0x0000 },
+  { 0x0701, 0x00c7, 0x0000 },
+  { 0x8701, 0x00cc, 0x3000 },
+  { 0x8701, 0x00ca, 0x2000 },
+  { 0x0701, 0x00c9, 0x0000 },
+  { 0x0701, 0x00cb, 0x0000 },
+  { 0x8701, 0x00ce, 0x2000 },
+  { 0x0701, 0x00cd, 0x0000 },
+  { 0x0701, 0x00cf, 0x0000 },
+  { 0x8701, 0x00e0, 0x5000 },
+  { 0x8701, 0x00d8, 0x4000 },
+  { 0x8701, 0x00d4, 0x3000 },
+  { 0x8701, 0x00d2, 0x2000 },
+  { 0x0701, 0x00d1, 0x0000 },
+  { 0x0701, 0x00d3, 0x0000 },
+  { 0x8701, 0x00d6, 0x2000 },
+  { 0x0701, 0x00d5, 0x0000 },
+  { 0x0701, 0x00d7, 0x0000 },
+  { 0x8701, 0x00dc, 0x3000 },
+  { 0x8701, 0x00da, 0x2000 },
+  { 0x0701, 0x00d9, 0x0000 },
+  { 0x0701, 0x00db, 0x0000 },
+  { 0x8701, 0x00de, 0x2000 },
+  { 0x0701, 0x00dd, 0x0000 },
+  { 0x0701, 0x00df, 0x0000 },
+  { 0x8701, 0x00e8, 0x4000 },
+  { 0x8701, 0x00e4, 0x3000 },
+  { 0x8701, 0x00e2, 0x2000 },
+  { 0x0701, 0x00e1, 0x0000 },
+  { 0x0701, 0x00e3, 0x0000 },
+  { 0x8701, 0x00e6, 0x2000 },
+  { 0x0701, 0x00e5, 0x0000 },
+  { 0x0701, 0x00e7, 0x0000 },
+  { 0x8701, 0x00ec, 0x3000 },
+  { 0x8701, 0x00ea, 0x2000 },
+  { 0x0701, 0x00e9, 0x0000 },
+  { 0x0701, 0x00eb, 0x0000 },
+  { 0x8701, 0x00ee, 0x2000 },
+  { 0x0701, 0x00ed, 0x0000 },
+  { 0x0701, 0x00ef, 0x0000 },
+  { 0x8501, 0xd459, 0xb000 },
+  { 0x9a01, 0xd080, 0xa000 },
+  { 0x8701, 0x045f, 0x9000 },
+  { 0x8701, 0x0349, 0x8000 },
+  { 0x9a01, 0x013c, 0x7000 },
+  { 0x8f01, 0x0119, 0x6000 },
+  { 0x8f01, 0x0109, 0x5000 },
+  { 0x8701, 0x00f8, 0x4000 },
+  { 0x8701, 0x00f4, 0x3000 },
+  { 0x8701, 0x00f2, 0x2000 },
+  { 0x0701, 0x00f1, 0x0000 },
+  { 0x0701, 0x00f3, 0x0000 },
+  { 0x8701, 0x00f6, 0x2000 },
+  { 0x0701, 0x00f5, 0x0000 },
+  { 0x0701, 0x00f7, 0x0000 },
+  { 0x9501, 0x0101, 0x3000 },
+  { 0x8701, 0x00fa, 0x2000 },
+  { 0x0701, 0x00f9, 0x0000 },
+  { 0x1501, 0x0100, 0x0000 },
+  { 0x8f01, 0x0107, 0x2000 },
+  { 0x1a01, 0x0102, 0x0000 },
+  { 0x0f01, 0x0108, 0x0000 },
+  { 0x8f01, 0x0111, 0x4000 },
+  { 0x8f01, 0x010d, 0x3000 },
+  { 0x8f01, 0x010b, 0x2000 },
+  { 0x0f01, 0x010a, 0x0000 },
+  { 0x0f01, 0x010c, 0x0000 },
+  { 0x8f01, 0x010f, 0x2000 },
+  { 0x0f01, 0x010e, 0x0000 },
+  { 0x0f01, 0x0110, 0x0000 },
+  { 0x8f01, 0x0115, 0x3000 },
+  { 0x8f01, 0x0113, 0x2000 },
+  { 0x0f01, 0x0112, 0x0000 },
+  { 0x0f01, 0x0114, 0x0000 },
+  { 0x8f01, 0x0117, 0x2000 },
+  { 0x0f01, 0x0116, 0x0000 },
+  { 0x0f01, 0x0118, 0x0000 },
+  { 0x8f01, 0x0129, 0x5000 },
+  { 0x8f01, 0x0121, 0x4000 },
+  { 0x8f01, 0x011d, 0x3000 },
+  { 0x8f01, 0x011b, 0x2000 },
+  { 0x0f01, 0x011a, 0x0000 },
+  { 0x0f01, 0x011c, 0x0000 },
+  { 0x8f01, 0x011f, 0x2000 },
+  { 0x0f01, 0x011e, 0x0000 },
+  { 0x0f01, 0x0120, 0x0000 },
+  { 0x8f01, 0x0125, 0x3000 },
+  { 0x8f01, 0x0123, 0x2000 },
+  { 0x0f01, 0x0122, 0x0000 },
+  { 0x0f01, 0x0124, 0x0000 },
+  { 0x8f01, 0x0127, 0x2000 },
+  { 0x0f01, 0x0126, 0x0000 },
+  { 0x0f01, 0x0128, 0x0000 },
+  { 0x8f01, 0x0131, 0x4000 },
+  { 0x8f01, 0x012d, 0x3000 },
+  { 0x8f01, 0x012b, 0x2000 },
+  { 0x0f01, 0x012a, 0x0000 },
+  { 0x0f01, 0x012c, 0x0000 },
+  { 0x8f01, 0x012f, 0x2000 },
+  { 0x0f01, 0x012e, 0x0000 },
+  { 0x0f01, 0x0130, 0x0000 },
+  { 0x9a01, 0x0138, 0x3000 },
+  { 0x8f01, 0x0133, 0x2000 },
+  { 0x0f01, 0x0132, 0x0000 },
+  { 0x1a01, 0x0137, 0x0000 },
+  { 0x9a01, 0x013a, 0x2000 },
+  { 0x1a01, 0x0139, 0x0000 },
+  { 0x1a01, 0x013b, 0x0000 },
+  { 0x8701, 0x031c, 0x6000 },
+  { 0x8701, 0x030c, 0x5000 },
+  { 0x8701, 0x0304, 0x4000 },
+  { 0x8701, 0x0300, 0x3000 },
+  { 0x9a01, 0x013e, 0x2000 },
+  { 0x1a01, 0x013d, 0x0000 },
+  { 0x1a01, 0x013f, 0x0000 },
+  { 0x8701, 0x0302, 0x2000 },
+  { 0x0701, 0x0301, 0x0000 },
+  { 0x0701, 0x0303, 0x0000 },
+  { 0x8701, 0x0308, 0x3000 },
+  { 0x8701, 0x0306, 0x2000 },
+  { 0x0701, 0x0305, 0x0000 },
+  { 0x0701, 0x0307, 0x0000 },
+  { 0x8701, 0x030a, 0x2000 },
+  { 0x0701, 0x0309, 0x0000 },
+  { 0x0701, 0x030b, 0x0000 },
+  { 0x8701, 0x0314, 0x4000 },
+  { 0x8701, 0x0310, 0x3000 },
+  { 0x8701, 0x030e, 0x2000 },
+  { 0x0701, 0x030d, 0x0000 },
+  { 0x0701, 0x030f, 0x0000 },
+  { 0x8701, 0x0312, 0x2000 },
+  { 0x0701, 0x0311, 0x0000 },
+  { 0x0701, 0x0313, 0x0000 },
+  { 0x8701, 0x0318, 0x3000 },
+  { 0x8701, 0x0316, 0x2000 },
+  { 0x0701, 0x0315, 0x0000 },
+  { 0x0701, 0x0317, 0x0000 },
+  { 0x8701, 0x031a, 0x2000 },
+  { 0x0701, 0x0319, 0x0000 },
+  { 0x0701, 0x031b, 0x0000 },
+  { 0x8701, 0x0339, 0x5000 },
+  { 0x8701, 0x0331, 0x4000 },
+  { 0x8f01, 0x0321, 0x3000 },
+  { 0x8701, 0x031e, 0x2000 },
+  { 0x0701, 0x031d, 0x0000 },
+  { 0x0f01, 0x0320, 0x0000 },
+  { 0x8f01, 0x0323, 0x2000 },
+  { 0x0f01, 0x0322, 0x0000 },
+  { 0x0701, 0x0330, 0x0000 },
+  { 0x8701, 0x0335, 0x3000 },
+  { 0x8701, 0x0333, 0x2000 },
+  { 0x0701, 0x0332, 0x0000 },
+  { 0x0701, 0x0334, 0x0000 },
+  { 0x8701, 0x0337, 0x2000 },
+  { 0x0701, 0x0336, 0x0000 },
+  { 0x0701, 0x0338, 0x0000 },
+  { 0x8701, 0x0341, 0x4000 },
+  { 0x8701, 0x033d, 0x3000 },
+  { 0x8701, 0x033b, 0x2000 },
+  { 0x0701, 0x033a, 0x0000 },
+  { 0x0701, 0x033c, 0x0000 },
+  { 0x8701, 0x033f, 0x2000 },
+  { 0x0701, 0x033e, 0x0000 },
+  { 0x0701, 0x0340, 0x0000 },
+  { 0x8701, 0x0345, 0x3000 },
+  { 0x8701, 0x0343, 0x2000 },
+  { 0x0701, 0x0342, 0x0000 },
+  { 0x0701, 0x0344, 0x0000 },
+  { 0x8701, 0x0347, 0x2000 },
+  { 0x0701, 0x0346, 0x0000 },
+  { 0x0701, 0x0348, 0x0000 },
+  { 0x8901, 0x041f, 0x7028 },
+  { 0x9501, 0x039f, 0x6000 },
+  { 0x8701, 0x038e, 0x5000 },
+  { 0x8701, 0x0386, 0x4000 },
+  { 0x8701, 0x0382, 0x3000 },
+  { 0x8701, 0x0380, 0x2000 },
+  { 0x0e01, 0x034a, 0x0000 },
+  { 0x0701, 0x0381, 0x0000 },
+  { 0x8701, 0x0384, 0x2000 },
+  { 0x0701, 0x0383, 0x0000 },
+  { 0x0701, 0x0385, 0x0000 },
+  { 0x8701, 0x038a, 0x3000 },
+  { 0x8701, 0x0388, 0x2000 },
+  { 0x0701, 0x0387, 0x0000 },
+  { 0x0701, 0x0389, 0x0000 },
+  { 0x8701, 0x038c, 0x2000 },
+  { 0x0701, 0x038b, 0x0000 },
+  { 0x0701, 0x038d, 0x0000 },
+  { 0x8701, 0x0396, 0x4000 },
+  { 0x8701, 0x0392, 0x3000 },
+  { 0x8701, 0x0390, 0x2000 },
+  { 0x0701, 0x038f, 0x0000 },
+  { 0x0701, 0x0391, 0x0000 },
+  { 0x8701, 0x0394, 0x2000 },
+  { 0x0701, 0x0393, 0x0000 },
+  { 0x0701, 0x0395, 0x0000 },
+  { 0x8701, 0x039a, 0x3000 },
+  { 0x8701, 0x0398, 0x2000 },
+  { 0x0701, 0x0397, 0x0000 },
+  { 0x0701, 0x0399, 0x0000 },
+  { 0x8701, 0x039c, 0x2000 },
+  { 0x0701, 0x039b, 0x0000 },
+  { 0x0701, 0x039d, 0x0000 },
+  { 0x8901, 0x040f, 0x5028 },
+  { 0x8901, 0x0407, 0x4028 },
+  { 0x8901, 0x0403, 0x3028 },
+  { 0x8901, 0x0401, 0x2028 },
+  { 0x0901, 0x0400, 0x0028 },
+  { 0x0901, 0x0402, 0x0028 },
+  { 0x8901, 0x0405, 0x2028 },
+  { 0x0901, 0x0404, 0x0028 },
+  { 0x0901, 0x0406, 0x0028 },
+  { 0x8901, 0x040b, 0x3028 },
+  { 0x8901, 0x0409, 0x2028 },
+  { 0x0901, 0x0408, 0x0028 },
+  { 0x0901, 0x040a, 0x0028 },
+  { 0x8901, 0x040d, 0x2028 },
+  { 0x0901, 0x040c, 0x0028 },
+  { 0x0901, 0x040e, 0x0028 },
+  { 0x8901, 0x0417, 0x4028 },
+  { 0x8901, 0x0413, 0x3028 },
+  { 0x8901, 0x0411, 0x2028 },
+  { 0x0901, 0x0410, 0x0028 },
+  { 0x0901, 0x0412, 0x0028 },
+  { 0x8901, 0x0415, 0x2028 },
+  { 0x0901, 0x0414, 0x0028 },
+  { 0x0901, 0x0416, 0x0028 },
+  { 0x8901, 0x041b, 0x3028 },
+  { 0x8901, 0x0419, 0x2028 },
+  { 0x0901, 0x0418, 0x0028 },
+  { 0x0901, 0x041a, 0x0028 },
+  { 0x8901, 0x041d, 0x2028 },
+  { 0x0901, 0x041c, 0x0028 },
+  { 0x0901, 0x041e, 0x0028 },
+  { 0x8501, 0x043f, 0x6fd8 },
+  { 0x8501, 0x042f, 0x5fd8 },
+  { 0x8901, 0x0427, 0x4028 },
+  { 0x8901, 0x0423, 0x3028 },
+  { 0x8901, 0x0421, 0x2028 },
+  { 0x0901, 0x0420, 0x0028 },
+  { 0x0901, 0x0422, 0x0028 },
+  { 0x8901, 0x0425, 0x2028 },
+  { 0x0901, 0x0424, 0x0028 },
+  { 0x0901, 0x0426, 0x0028 },
+  { 0x8501, 0x042b, 0x3fd8 },
+  { 0x8501, 0x0429, 0x2fd8 },
+  { 0x0501, 0x0428, 0x0fd8 },
+  { 0x0501, 0x042a, 0x0fd8 },
+  { 0x8501, 0x042d, 0x2fd8 },
+  { 0x0501, 0x042c, 0x0fd8 },
+  { 0x0501, 0x042e, 0x0fd8 },
+  { 0x8501, 0x0437, 0x4fd8 },
+  { 0x8501, 0x0433, 0x3fd8 },
+  { 0x8501, 0x0431, 0x2fd8 },
+  { 0x0501, 0x0430, 0x0fd8 },
+  { 0x0501, 0x0432, 0x0fd8 },
+  { 0x8501, 0x0435, 0x2fd8 },
+  { 0x0501, 0x0434, 0x0fd8 },
+  { 0x0501, 0x0436, 0x0fd8 },
+  { 0x8501, 0x043b, 0x3fd8 },
+  { 0x8501, 0x0439, 0x2fd8 },
+  { 0x0501, 0x0438, 0x0fd8 },
+  { 0x0501, 0x043a, 0x0fd8 },
+  { 0x8501, 0x043d, 0x2fd8 },
+  { 0x0501, 0x043c, 0x0fd8 },
+  { 0x0501, 0x043e, 0x0fd8 },
+  { 0x8501, 0x044f, 0x5fd8 },
+  { 0x8501, 0x0447, 0x4fd8 },
+  { 0x8501, 0x0443, 0x3fd8 },
+  { 0x8501, 0x0441, 0x2fd8 },
+  { 0x0501, 0x0440, 0x0fd8 },
+  { 0x0501, 0x0442, 0x0fd8 },
+  { 0x8501, 0x0445, 0x2fd8 },
+  { 0x0501, 0x0444, 0x0fd8 },
+  { 0x0501, 0x0446, 0x0fd8 },
+  { 0x8501, 0x044b, 0x3fd8 },
+  { 0x8501, 0x0449, 0x2fd8 },
+  { 0x0501, 0x0448, 0x0fd8 },
+  { 0x0501, 0x044a, 0x0fd8 },
+  { 0x8501, 0x044d, 0x2fd8 },
+  { 0x0501, 0x044c, 0x0fd8 },
+  { 0x0501, 0x044e, 0x0fd8 },
+  { 0x8701, 0x0457, 0x4000 },
+  { 0x8701, 0x0453, 0x3000 },
+  { 0x8701, 0x0451, 0x2000 },
+  { 0x0701, 0x0450, 0x0000 },
+  { 0x0701, 0x0452, 0x0000 },
+  { 0x8701, 0x0455, 0x2000 },
+  { 0x0701, 0x0454, 0x0000 },
+  { 0x0701, 0x0456, 0x0000 },
+  { 0x8701, 0x045b, 0x3000 },
+  { 0x8701, 0x0459, 0x2000 },
+  { 0x0701, 0x0458, 0x0000 },
+  { 0x0701, 0x045a, 0x0000 },
+  { 0x8701, 0x045d, 0x2000 },
+  { 0x0701, 0x045c, 0x0000 },
+  { 0x0701, 0x045e, 0x0000 },
+  { 0x9a01, 0xd000, 0x8000 },
+  { 0x8d01, 0x04a1, 0x7000 },
+  { 0x8701, 0x047f, 0x6000 },
+  { 0x8701, 0x046f, 0x5000 },
+  { 0x8701, 0x0467, 0x4000 },
+  { 0x8701, 0x0463, 0x3000 },
+  { 0x8701, 0x0461, 0x2000 },
+  { 0x0701, 0x0460, 0x0000 },
+  { 0x0701, 0x0462, 0x0000 },
+  { 0x8701, 0x0465, 0x2000 },
+  { 0x0701, 0x0464, 0x0000 },
+  { 0x0701, 0x0466, 0x0000 },
+  { 0x8701, 0x046b, 0x3000 },
+  { 0x8701, 0x0469, 0x2000 },
+  { 0x0701, 0x0468, 0x0000 },
+  { 0x0701, 0x046a, 0x0000 },
+  { 0x8701, 0x046d, 0x2000 },
+  { 0x0701, 0x046c, 0x0000 },
+  { 0x0701, 0x046e, 0x0000 },
+  { 0x8701, 0x0477, 0x4000 },
+  { 0x8701, 0x0473, 0x3000 },
+  { 0x8701, 0x0471, 0x2000 },
+  { 0x0701, 0x0470, 0x0000 },
+  { 0x0701, 0x0472, 0x0000 },
+  { 0x8701, 0x0475, 0x2000 },
+  { 0x0701, 0x0474, 0x0000 },
+  { 0x0701, 0x0476, 0x0000 },
+  { 0x8701, 0x047b, 0x3000 },
+  { 0x8701, 0x0479, 0x2000 },
+  { 0x0701, 0x0478, 0x0000 },
+  { 0x0701, 0x047a, 0x0000 },
+  { 0x8701, 0x047d, 0x2000 },
+  { 0x0701, 0x047c, 0x0000 },
+  { 0x0701, 0x047e, 0x0000 },
+  { 0x8701, 0x048f, 0x5000 },
+  { 0x8701, 0x0487, 0x4000 },
+  { 0x8701, 0x0483, 0x3000 },
+  { 0x8701, 0x0481, 0x2000 },
+  { 0x0701, 0x0480, 0x0000 },
+  { 0x0701, 0x0482, 0x0000 },
+  { 0x8701, 0x0485, 0x2000 },
+  { 0x0701, 0x0484, 0x0000 },
+  { 0x0701, 0x0486, 0x0000 },
+  { 0x8701, 0x048b, 0x3000 },
+  { 0x8701, 0x0489, 0x2000 },
+  { 0x0701, 0x0488, 0x0000 },
+  { 0x0701, 0x048a, 0x0000 },
+  { 0x8701, 0x048d, 0x2000 },
+  { 0x0701, 0x048c, 0x0000 },
+  { 0x0701, 0x048e, 0x0000 },
+  { 0x8701, 0x0497, 0x4000 },
+  { 0x8701, 0x0493, 0x3000 },
+  { 0x8701, 0x0491, 0x2000 },
+  { 0x0701, 0x0490, 0x0000 },
+  { 0x0701, 0x0492, 0x0000 },
+  { 0x8701, 0x0495, 0x2000 },
+  { 0x0701, 0x0494, 0x0000 },
+  { 0x0701, 0x0496, 0x0000 },
+  { 0x8701, 0x049b, 0x3000 },
+  { 0x8701, 0x0499, 0x2000 },
+  { 0x0701, 0x0498, 0x0000 },
+  { 0x0701, 0x049a, 0x0000 },
+  { 0x8701, 0x049d, 0x2000 },
+  { 0x0701, 0x049c, 0x0000 },
+  { 0x0d01, 0x04a0, 0x0000 },
+  { 0x8701, 0x081a, 0x6000 },
+  { 0x8701, 0x080a, 0x5000 },
+  { 0x8d01, 0x04a9, 0x4000 },
+  { 0x8d01, 0x04a5, 0x3000 },
+  { 0x8d01, 0x04a3, 0x2000 },
+  { 0x0d01, 0x04a2, 0x0000 },
+  { 0x0d01, 0x04a4, 0x0000 },
+  { 0x8d01, 0x04a7, 0x2000 },
+  { 0x0d01, 0x04a6, 0x0000 },
+  { 0x0d01, 0x04a8, 0x0000 },
+  { 0x8701, 0x0803, 0x3000 },
+  { 0x8701, 0x0801, 0x2000 },
+  { 0x0701, 0x0800, 0x0000 },
+  { 0x0701, 0x0802, 0x0000 },
+  { 0x8701, 0x0805, 0x2000 },
+  { 0x0701, 0x0804, 0x0000 },
+  { 0x0701, 0x0808, 0x0000 },
+  { 0x8701, 0x0812, 0x4000 },
+  { 0x8701, 0x080e, 0x3000 },
+  { 0x8701, 0x080c, 0x2000 },
+  { 0x0701, 0x080b, 0x0000 },
+  { 0x0701, 0x080d, 0x0000 },
+  { 0x8701, 0x0810, 0x2000 },
+  { 0x0701, 0x080f, 0x0000 },
+  { 0x0701, 0x0811, 0x0000 },
+  { 0x8701, 0x0816, 0x3000 },
+  { 0x8701, 0x0814, 0x2000 },
+  { 0x0701, 0x0813, 0x0000 },
+  { 0x0701, 0x0815, 0x0000 },
+  { 0x8701, 0x0818, 0x2000 },
+  { 0x0701, 0x0817, 0x0000 },
+  { 0x0701, 0x0819, 0x0000 },
+  { 0x8701, 0x082a, 0x5000 },
+  { 0x8701, 0x0822, 0x4000 },
+  { 0x8701, 0x081e, 0x3000 },
+  { 0x8701, 0x081c, 0x2000 },
+  { 0x0701, 0x081b, 0x0000 },
+  { 0x0701, 0x081d, 0x0000 },
+  { 0x8701, 0x0820, 0x2000 },
+  { 0x0701, 0x081f, 0x0000 },
+  { 0x0701, 0x0821, 0x0000 },
+  { 0x8701, 0x0826, 0x3000 },
+  { 0x8701, 0x0824, 0x2000 },
+  { 0x0701, 0x0823, 0x0000 },
+  { 0x0701, 0x0825, 0x0000 },
+  { 0x8701, 0x0828, 0x2000 },
+  { 0x0701, 0x0827, 0x0000 },
+  { 0x0701, 0x0829, 0x0000 },
+  { 0x8701, 0x0832, 0x4000 },
+  { 0x8701, 0x082e, 0x3000 },
+  { 0x8701, 0x082c, 0x2000 },
+  { 0x0701, 0x082b, 0x0000 },
+  { 0x0701, 0x082d, 0x0000 },
+  { 0x8701, 0x0830, 0x2000 },
+  { 0x0701, 0x082f, 0x0000 },
+  { 0x0701, 0x0831, 0x0000 },
+  { 0x8701, 0x0837, 0x3000 },
+  { 0x8701, 0x0834, 0x2000 },
+  { 0x0701, 0x0833, 0x0000 },
+  { 0x0701, 0x0835, 0x0000 },
+  { 0x8701, 0x083c, 0x2000 },
+  { 0x0701, 0x0838, 0x0000 },
+  { 0x0701, 0x083f, 0x0000 },
+  { 0x9a01, 0xd040, 0x7000 },
+  { 0x9a01, 0xd020, 0x6000 },
+  { 0x9a01, 0xd010, 0x5000 },
+  { 0x9a01, 0xd008, 0x4000 },
+  { 0x9a01, 0xd004, 0x3000 },
+  { 0x9a01, 0xd002, 0x2000 },
+  { 0x1a01, 0xd001, 0x0000 },
+  { 0x1a01, 0xd003, 0x0000 },
+  { 0x9a01, 0xd006, 0x2000 },
+  { 0x1a01, 0xd005, 0x0000 },
+  { 0x1a01, 0xd007, 0x0000 },
+  { 0x9a01, 0xd00c, 0x3000 },
+  { 0x9a01, 0xd00a, 0x2000 },
+  { 0x1a01, 0xd009, 0x0000 },
+  { 0x1a01, 0xd00b, 0x0000 },
+  { 0x9a01, 0xd00e, 0x2000 },
+  { 0x1a01, 0xd00d, 0x0000 },
+  { 0x1a01, 0xd00f, 0x0000 },
+  { 0x9a01, 0xd018, 0x4000 },
+  { 0x9a01, 0xd014, 0x3000 },
+  { 0x9a01, 0xd012, 0x2000 },
+  { 0x1a01, 0xd011, 0x0000 },
+  { 0x1a01, 0xd013, 0x0000 },
+  { 0x9a01, 0xd016, 0x2000 },
+  { 0x1a01, 0xd015, 0x0000 },
+  { 0x1a01, 0xd017, 0x0000 },
+  { 0x9a01, 0xd01c, 0x3000 },
+  { 0x9a01, 0xd01a, 0x2000 },
+  { 0x1a01, 0xd019, 0x0000 },
+  { 0x1a01, 0xd01b, 0x0000 },
+  { 0x9a01, 0xd01e, 0x2000 },
+  { 0x1a01, 0xd01d, 0x0000 },
+  { 0x1a01, 0xd01f, 0x0000 },
+  { 0x9a01, 0xd030, 0x5000 },
+  { 0x9a01, 0xd028, 0x4000 },
+  { 0x9a01, 0xd024, 0x3000 },
+  { 0x9a01, 0xd022, 0x2000 },
+  { 0x1a01, 0xd021, 0x0000 },
+  { 0x1a01, 0xd023, 0x0000 },
+  { 0x9a01, 0xd026, 0x2000 },
+  { 0x1a01, 0xd025, 0x0000 },
+  { 0x1a01, 0xd027, 0x0000 },
+  { 0x9a01, 0xd02c, 0x3000 },
+  { 0x9a01, 0xd02a, 0x2000 },
+  { 0x1a01, 0xd029, 0x0000 },
+  { 0x1a01, 0xd02b, 0x0000 },
+  { 0x9a01, 0xd02e, 0x2000 },
+  { 0x1a01, 0xd02d, 0x0000 },
+  { 0x1a01, 0xd02f, 0x0000 },
+  { 0x9a01, 0xd038, 0x4000 },
+  { 0x9a01, 0xd034, 0x3000 },
+  { 0x9a01, 0xd032, 0x2000 },
+  { 0x1a01, 0xd031, 0x0000 },
+  { 0x1a01, 0xd033, 0x0000 },
+  { 0x9a01, 0xd036, 0x2000 },
+  { 0x1a01, 0xd035, 0x0000 },
+  { 0x1a01, 0xd037, 0x0000 },
+  { 0x9a01, 0xd03c, 0x3000 },
+  { 0x9a01, 0xd03a, 0x2000 },
+  { 0x1a01, 0xd039, 0x0000 },
+  { 0x1a01, 0xd03b, 0x0000 },
+  { 0x9a01, 0xd03e, 0x2000 },
+  { 0x1a01, 0xd03d, 0x0000 },
+  { 0x1a01, 0xd03f, 0x0000 },
+  { 0x9a01, 0xd060, 0x6000 },
+  { 0x9a01, 0xd050, 0x5000 },
+  { 0x9a01, 0xd048, 0x4000 },
+  { 0x9a01, 0xd044, 0x3000 },
+  { 0x9a01, 0xd042, 0x2000 },
+  { 0x1a01, 0xd041, 0x0000 },
+  { 0x1a01, 0xd043, 0x0000 },
+  { 0x9a01, 0xd046, 0x2000 },
+  { 0x1a01, 0xd045, 0x0000 },
+  { 0x1a01, 0xd047, 0x0000 },
+  { 0x9a01, 0xd04c, 0x3000 },
+  { 0x9a01, 0xd04a, 0x2000 },
+  { 0x1a01, 0xd049, 0x0000 },
+  { 0x1a01, 0xd04b, 0x0000 },
+  { 0x9a01, 0xd04e, 0x2000 },
+  { 0x1a01, 0xd04d, 0x0000 },
+  { 0x1a01, 0xd04f, 0x0000 },
+  { 0x9a01, 0xd058, 0x4000 },
+  { 0x9a01, 0xd054, 0x3000 },
+  { 0x9a01, 0xd052, 0x2000 },
+  { 0x1a01, 0xd051, 0x0000 },
+  { 0x1a01, 0xd053, 0x0000 },
+  { 0x9a01, 0xd056, 0x2000 },
+  { 0x1a01, 0xd055, 0x0000 },
+  { 0x1a01, 0xd057, 0x0000 },
+  { 0x9a01, 0xd05c, 0x3000 },
+  { 0x9a01, 0xd05a, 0x2000 },
+  { 0x1a01, 0xd059, 0x0000 },
+  { 0x1a01, 0xd05b, 0x0000 },
+  { 0x9a01, 0xd05e, 0x2000 },
+  { 0x1a01, 0xd05d, 0x0000 },
+  { 0x1a01, 0xd05f, 0x0000 },
+  { 0x9a01, 0xd070, 0x5000 },
+  { 0x9a01, 0xd068, 0x4000 },
+  { 0x9a01, 0xd064, 0x3000 },
+  { 0x9a01, 0xd062, 0x2000 },
+  { 0x1a01, 0xd061, 0x0000 },
+  { 0x1a01, 0xd063, 0x0000 },
+  { 0x9a01, 0xd066, 0x2000 },
+  { 0x1a01, 0xd065, 0x0000 },
+  { 0x1a01, 0xd067, 0x0000 },
+  { 0x9a01, 0xd06c, 0x3000 },
+  { 0x9a01, 0xd06a, 0x2000 },
+  { 0x1a01, 0xd069, 0x0000 },
+  { 0x1a01, 0xd06b, 0x0000 },
+  { 0x9a01, 0xd06e, 0x2000 },
+  { 0x1a01, 0xd06d, 0x0000 },
+  { 0x1a01, 0xd06f, 0x0000 },
+  { 0x9a01, 0xd078, 0x4000 },
+  { 0x9a01, 0xd074, 0x3000 },
+  { 0x9a01, 0xd072, 0x2000 },
+  { 0x1a01, 0xd071, 0x0000 },
+  { 0x1a01, 0xd073, 0x0000 },
+  { 0x9a01, 0xd076, 0x2000 },
+  { 0x1a01, 0xd075, 0x0000 },
+  { 0x1a01, 0xd077, 0x0000 },
+  { 0x9a01, 0xd07c, 0x3000 },
+  { 0x9a01, 0xd07a, 0x2000 },
+  { 0x1a01, 0xd079, 0x0000 },
+  { 0x1a01, 0xd07b, 0x0000 },
+  { 0x9a01, 0xd07e, 0x2000 },
+  { 0x1a01, 0xd07d, 0x0000 },
+  { 0x1a01, 0xd07f, 0x0000 },
+  { 0x9a01, 0xd18d, 0x9000 },
+  { 0x9a01, 0xd10a, 0x8000 },
+  { 0x9a01, 0xd0c0, 0x7000 },
+  { 0x9a01, 0xd0a0, 0x6000 },
+  { 0x9a01, 0xd090, 0x5000 },
+  { 0x9a01, 0xd088, 0x4000 },
+  { 0x9a01, 0xd084, 0x3000 },
+  { 0x9a01, 0xd082, 0x2000 },
+  { 0x1a01, 0xd081, 0x0000 },
+  { 0x1a01, 0xd083, 0x0000 },
+  { 0x9a01, 0xd086, 0x2000 },
+  { 0x1a01, 0xd085, 0x0000 },
+  { 0x1a01, 0xd087, 0x0000 },
+  { 0x9a01, 0xd08c, 0x3000 },
+  { 0x9a01, 0xd08a, 0x2000 },
+  { 0x1a01, 0xd089, 0x0000 },
+  { 0x1a01, 0xd08b, 0x0000 },
+  { 0x9a01, 0xd08e, 0x2000 },
+  { 0x1a01, 0xd08d, 0x0000 },
+  { 0x1a01, 0xd08f, 0x0000 },
+  { 0x9a01, 0xd098, 0x4000 },
+  { 0x9a01, 0xd094, 0x3000 },
+  { 0x9a01, 0xd092, 0x2000 },
+  { 0x1a01, 0xd091, 0x0000 },
+  { 0x1a01, 0xd093, 0x0000 },
+  { 0x9a01, 0xd096, 0x2000 },
+  { 0x1a01, 0xd095, 0x0000 },
+  { 0x1a01, 0xd097, 0x0000 },
+  { 0x9a01, 0xd09c, 0x3000 },
+  { 0x9a01, 0xd09a, 0x2000 },
+  { 0x1a01, 0xd099, 0x0000 },
+  { 0x1a01, 0xd09b, 0x0000 },
+  { 0x9a01, 0xd09e, 0x2000 },
+  { 0x1a01, 0xd09d, 0x0000 },
+  { 0x1a01, 0xd09f, 0x0000 },
+  { 0x9a01, 0xd0b0, 0x5000 },
+  { 0x9a01, 0xd0a8, 0x4000 },
+  { 0x9a01, 0xd0a4, 0x3000 },
+  { 0x9a01, 0xd0a2, 0x2000 },
+  { 0x1a01, 0xd0a1, 0x0000 },
+  { 0x1a01, 0xd0a3, 0x0000 },
+  { 0x9a01, 0xd0a6, 0x2000 },
+  { 0x1a01, 0xd0a5, 0x0000 },
+  { 0x1a01, 0xd0a7, 0x0000 },
+  { 0x9a01, 0xd0ac, 0x3000 },
+  { 0x9a01, 0xd0aa, 0x2000 },
+  { 0x1a01, 0xd0a9, 0x0000 },
+  { 0x1a01, 0xd0ab, 0x0000 },
+  { 0x9a01, 0xd0ae, 0x2000 },
+  { 0x1a01, 0xd0ad, 0x0000 },
+  { 0x1a01, 0xd0af, 0x0000 },
+  { 0x9a01, 0xd0b8, 0x4000 },
+  { 0x9a01, 0xd0b4, 0x3000 },
+  { 0x9a01, 0xd0b2, 0x2000 },
+  { 0x1a01, 0xd0b1, 0x0000 },
+  { 0x1a01, 0xd0b3, 0x0000 },
+  { 0x9a01, 0xd0b6, 0x2000 },
+  { 0x1a01, 0xd0b5, 0x0000 },
+  { 0x1a01, 0xd0b7, 0x0000 },
+  { 0x9a01, 0xd0bc, 0x3000 },
+  { 0x9a01, 0xd0ba, 0x2000 },
+  { 0x1a01, 0xd0b9, 0x0000 },
+  { 0x1a01, 0xd0bb, 0x0000 },
+  { 0x9a01, 0xd0be, 0x2000 },
+  { 0x1a01, 0xd0bd, 0x0000 },
+  { 0x1a01, 0xd0bf, 0x0000 },
+  { 0x9a01, 0xd0e0, 0x6000 },
+  { 0x9a01, 0xd0d0, 0x5000 },
+  { 0x9a01, 0xd0c8, 0x4000 },
+  { 0x9a01, 0xd0c4, 0x3000 },
+  { 0x9a01, 0xd0c2, 0x2000 },
+  { 0x1a01, 0xd0c1, 0x0000 },
+  { 0x1a01, 0xd0c3, 0x0000 },
+  { 0x9a01, 0xd0c6, 0x2000 },
+  { 0x1a01, 0xd0c5, 0x0000 },
+  { 0x1a01, 0xd0c7, 0x0000 },
+  { 0x9a01, 0xd0cc, 0x3000 },
+  { 0x9a01, 0xd0ca, 0x2000 },
+  { 0x1a01, 0xd0c9, 0x0000 },
+  { 0x1a01, 0xd0cb, 0x0000 },
+  { 0x9a01, 0xd0ce, 0x2000 },
+  { 0x1a01, 0xd0cd, 0x0000 },
+  { 0x1a01, 0xd0cf, 0x0000 },
+  { 0x9a01, 0xd0d8, 0x4000 },
+  { 0x9a01, 0xd0d4, 0x3000 },
+  { 0x9a01, 0xd0d2, 0x2000 },
+  { 0x1a01, 0xd0d1, 0x0000 },
+  { 0x1a01, 0xd0d3, 0x0000 },
+  { 0x9a01, 0xd0d6, 0x2000 },
+  { 0x1a01, 0xd0d5, 0x0000 },
+  { 0x1a01, 0xd0d7, 0x0000 },
+  { 0x9a01, 0xd0dc, 0x3000 },
+  { 0x9a01, 0xd0da, 0x2000 },
+  { 0x1a01, 0xd0d9, 0x0000 },
+  { 0x1a01, 0xd0db, 0x0000 },
+  { 0x9a01, 0xd0de, 0x2000 },
+  { 0x1a01, 0xd0dd, 0x0000 },
+  { 0x1a01, 0xd0df, 0x0000 },
+  { 0x9a01, 0xd0f0, 0x5000 },
+  { 0x9a01, 0xd0e8, 0x4000 },
+  { 0x9a01, 0xd0e4, 0x3000 },
+  { 0x9a01, 0xd0e2, 0x2000 },
+  { 0x1a01, 0xd0e1, 0x0000 },
+  { 0x1a01, 0xd0e3, 0x0000 },
+  { 0x9a01, 0xd0e6, 0x2000 },
+  { 0x1a01, 0xd0e5, 0x0000 },
+  { 0x1a01, 0xd0e7, 0x0000 },
+  { 0x9a01, 0xd0ec, 0x3000 },
+  { 0x9a01, 0xd0ea, 0x2000 },
+  { 0x1a01, 0xd0e9, 0x0000 },
+  { 0x1a01, 0xd0eb, 0x0000 },
+  { 0x9a01, 0xd0ee, 0x2000 },
+  { 0x1a01, 0xd0ed, 0x0000 },
+  { 0x1a01, 0xd0ef, 0x0000 },
+  { 0x9a01, 0xd102, 0x4000 },
+  { 0x9a01, 0xd0f4, 0x3000 },
+  { 0x9a01, 0xd0f2, 0x2000 },
+  { 0x1a01, 0xd0f1, 0x0000 },
+  { 0x1a01, 0xd0f3, 0x0000 },
+  { 0x9a01, 0xd100, 0x2000 },
+  { 0x1a01, 0xd0f5, 0x0000 },
+  { 0x1a01, 0xd101, 0x0000 },
+  { 0x9a01, 0xd106, 0x3000 },
+  { 0x9a01, 0xd104, 0x2000 },
+  { 0x1a01, 0xd103, 0x0000 },
+  { 0x1a01, 0xd105, 0x0000 },
+  { 0x9a01, 0xd108, 0x2000 },
+  { 0x1a01, 0xd107, 0x0000 },
+  { 0x1a01, 0xd109, 0x0000 },
+  { 0x9a01, 0xd14d, 0x7000 },
+  { 0x9a01, 0xd12d, 0x6000 },
+  { 0x9a01, 0xd11a, 0x5000 },
+  { 0x9a01, 0xd112, 0x4000 },
+  { 0x9a01, 0xd10e, 0x3000 },
+  { 0x9a01, 0xd10c, 0x2000 },
+  { 0x1a01, 0xd10b, 0x0000 },
+  { 0x1a01, 0xd10d, 0x0000 },
+  { 0x9a01, 0xd110, 0x2000 },
+  { 0x1a01, 0xd10f, 0x0000 },
+  { 0x1a01, 0xd111, 0x0000 },
+  { 0x9a01, 0xd116, 0x3000 },
+  { 0x9a01, 0xd114, 0x2000 },
+  { 0x1a01, 0xd113, 0x0000 },
+  { 0x1a01, 0xd115, 0x0000 },
+  { 0x9a01, 0xd118, 0x2000 },
+  { 0x1a01, 0xd117, 0x0000 },
+  { 0x1a01, 0xd119, 0x0000 },
+  { 0x9a01, 0xd122, 0x4000 },
+  { 0x9a01, 0xd11e, 0x3000 },
+  { 0x9a01, 0xd11c, 0x2000 },
+  { 0x1a01, 0xd11b, 0x0000 },
+  { 0x1a01, 0xd11d, 0x0000 },
+  { 0x9a01, 0xd120, 0x2000 },
+  { 0x1a01, 0xd11f, 0x0000 },
+  { 0x1a01, 0xd121, 0x0000 },
+  { 0x9a01, 0xd126, 0x3000 },
+  { 0x9a01, 0xd124, 0x2000 },
+  { 0x1a01, 0xd123, 0x0000 },
+  { 0x1a01, 0xd125, 0x0000 },
+  { 0x9a01, 0xd12b, 0x2000 },
+  { 0x1a01, 0xd12a, 0x0000 },
+  { 0x1a01, 0xd12c, 0x0000 },
+  { 0x9a01, 0xd13d, 0x5000 },
+  { 0x9a01, 0xd135, 0x4000 },
+  { 0x9a01, 0xd131, 0x3000 },
+  { 0x9a01, 0xd12f, 0x2000 },
+  { 0x1a01, 0xd12e, 0x0000 },
+  { 0x1a01, 0xd130, 0x0000 },
+  { 0x9a01, 0xd133, 0x2000 },
+  { 0x1a01, 0xd132, 0x0000 },
+  { 0x1a01, 0xd134, 0x0000 },
+  { 0x9a01, 0xd139, 0x3000 },
+  { 0x9a01, 0xd137, 0x2000 },
+  { 0x1a01, 0xd136, 0x0000 },
+  { 0x1a01, 0xd138, 0x0000 },
+  { 0x9a01, 0xd13b, 0x2000 },
+  { 0x1a01, 0xd13a, 0x0000 },
+  { 0x1a01, 0xd13c, 0x0000 },
+  { 0x9a01, 0xd145, 0x4000 },
+  { 0x9a01, 0xd141, 0x3000 },
+  { 0x9a01, 0xd13f, 0x2000 },
+  { 0x1a01, 0xd13e, 0x0000 },
+  { 0x1a01, 0xd140, 0x0000 },
+  { 0x9a01, 0xd143, 0x2000 },
+  { 0x1a01, 0xd142, 0x0000 },
+  { 0x1a01, 0xd144, 0x0000 },
+  { 0x9a01, 0xd149, 0x3000 },
+  { 0x9a01, 0xd147, 0x2000 },
+  { 0x1a01, 0xd146, 0x0000 },
+  { 0x1a01, 0xd148, 0x0000 },
+  { 0x9a01, 0xd14b, 0x2000 },
+  { 0x1a01, 0xd14a, 0x0000 },
+  { 0x1a01, 0xd14c, 0x0000 },
+  { 0x8a01, 0xd16d, 0x6000 },
+  { 0x9a01, 0xd15d, 0x5000 },
+  { 0x9a01, 0xd155, 0x4000 },
+  { 0x9a01, 0xd151, 0x3000 },
+  { 0x9a01, 0xd14f, 0x2000 },
+  { 0x1a01, 0xd14e, 0x0000 },
+  { 0x1a01, 0xd150, 0x0000 },
+  { 0x9a01, 0xd153, 0x2000 },
+  { 0x1a01, 0xd152, 0x0000 },
+  { 0x1a01, 0xd154, 0x0000 },
+  { 0x9a01, 0xd159, 0x3000 },
+  { 0x9a01, 0xd157, 0x2000 },
+  { 0x1a01, 0xd156, 0x0000 },
+  { 0x1a01, 0xd158, 0x0000 },
+  { 0x9a01, 0xd15b, 0x2000 },
+  { 0x1a01, 0xd15a, 0x0000 },
+  { 0x1a01, 0xd15c, 0x0000 },
+  { 0x8a01, 0xd165, 0x4000 },
+  { 0x9a01, 0xd161, 0x3000 },
+  { 0x9a01, 0xd15f, 0x2000 },
+  { 0x1a01, 0xd15e, 0x0000 },
+  { 0x1a01, 0xd160, 0x0000 },
+  { 0x9a01, 0xd163, 0x2000 },
+  { 0x1a01, 0xd162, 0x0000 },
+  { 0x1a01, 0xd164, 0x0000 },
+  { 0x8c01, 0xd169, 0x3000 },
+  { 0x8c01, 0xd167, 0x2000 },
+  { 0x0a01, 0xd166, 0x0000 },
+  { 0x0c01, 0xd168, 0x0000 },
+  { 0x9a01, 0xd16b, 0x2000 },
+  { 0x1a01, 0xd16a, 0x0000 },
+  { 0x1a01, 0xd16c, 0x0000 },
+  { 0x8c01, 0xd17d, 0x5000 },
+  { 0x8101, 0xd175, 0x4000 },
+  { 0x8a01, 0xd171, 0x3000 },
+  { 0x8a01, 0xd16f, 0x2000 },
+  { 0x0a01, 0xd16e, 0x0000 },
+  { 0x0a01, 0xd170, 0x0000 },
+  { 0x8101, 0xd173, 0x2000 },
+  { 0x0a01, 0xd172, 0x0000 },
+  { 0x0101, 0xd174, 0x0000 },
+  { 0x8101, 0xd179, 0x3000 },
+  { 0x8101, 0xd177, 0x2000 },
+  { 0x0101, 0xd176, 0x0000 },
+  { 0x0101, 0xd178, 0x0000 },
+  { 0x8c01, 0xd17b, 0x2000 },
+  { 0x0101, 0xd17a, 0x0000 },
+  { 0x0c01, 0xd17c, 0x0000 },
+  { 0x8c01, 0xd185, 0x4000 },
+  { 0x8c01, 0xd181, 0x3000 },
+  { 0x8c01, 0xd17f, 0x2000 },
+  { 0x0c01, 0xd17e, 0x0000 },
+  { 0x0c01, 0xd180, 0x0000 },
+  { 0x9a01, 0xd183, 0x2000 },
+  { 0x0c01, 0xd182, 0x0000 },
+  { 0x1a01, 0xd184, 0x0000 },
+  { 0x8c01, 0xd189, 0x3000 },
+  { 0x8c01, 0xd187, 0x2000 },
+  { 0x0c01, 0xd186, 0x0000 },
+  { 0x0c01, 0xd188, 0x0000 },
+  { 0x8c01, 0xd18b, 0x2000 },
+  { 0x0c01, 0xd18a, 0x0000 },
+  { 0x1a01, 0xd18c, 0x0000 },
+  { 0x9a01, 0xd32f, 0x8000 },
+  { 0x9a01, 0xd1cd, 0x7000 },
+  { 0x8c01, 0xd1ad, 0x6000 },
+  { 0x9a01, 0xd19d, 0x5000 },
+  { 0x9a01, 0xd195, 0x4000 },
+  { 0x9a01, 0xd191, 0x3000 },
+  { 0x9a01, 0xd18f, 0x2000 },
+  { 0x1a01, 0xd18e, 0x0000 },
+  { 0x1a01, 0xd190, 0x0000 },
+  { 0x9a01, 0xd193, 0x2000 },
+  { 0x1a01, 0xd192, 0x0000 },
+  { 0x1a01, 0xd194, 0x0000 },
+  { 0x9a01, 0xd199, 0x3000 },
+  { 0x9a01, 0xd197, 0x2000 },
+  { 0x1a01, 0xd196, 0x0000 },
+  { 0x1a01, 0xd198, 0x0000 },
+  { 0x9a01, 0xd19b, 0x2000 },
+  { 0x1a01, 0xd19a, 0x0000 },
+  { 0x1a01, 0xd19c, 0x0000 },
+  { 0x9a01, 0xd1a5, 0x4000 },
+  { 0x9a01, 0xd1a1, 0x3000 },
+  { 0x9a01, 0xd19f, 0x2000 },
+  { 0x1a01, 0xd19e, 0x0000 },
+  { 0x1a01, 0xd1a0, 0x0000 },
+  { 0x9a01, 0xd1a3, 0x2000 },
+  { 0x1a01, 0xd1a2, 0x0000 },
+  { 0x1a01, 0xd1a4, 0x0000 },
+  { 0x9a01, 0xd1a9, 0x3000 },
+  { 0x9a01, 0xd1a7, 0x2000 },
+  { 0x1a01, 0xd1a6, 0x0000 },
+  { 0x1a01, 0xd1a8, 0x0000 },
+  { 0x8c01, 0xd1ab, 0x2000 },
+  { 0x0c01, 0xd1aa, 0x0000 },
+  { 0x0c01, 0xd1ac, 0x0000 },
+  { 0x9a01, 0xd1bd, 0x5000 },
+  { 0x9a01, 0xd1b5, 0x4000 },
+  { 0x9a01, 0xd1b1, 0x3000 },
+  { 0x9a01, 0xd1af, 0x2000 },
+  { 0x1a01, 0xd1ae, 0x0000 },
+  { 0x1a01, 0xd1b0, 0x0000 },
+  { 0x9a01, 0xd1b3, 0x2000 },
+  { 0x1a01, 0xd1b2, 0x0000 },
+  { 0x1a01, 0xd1b4, 0x0000 },
+  { 0x9a01, 0xd1b9, 0x3000 },
+  { 0x9a01, 0xd1b7, 0x2000 },
+  { 0x1a01, 0xd1b6, 0x0000 },
+  { 0x1a01, 0xd1b8, 0x0000 },
+  { 0x9a01, 0xd1bb, 0x2000 },
+  { 0x1a01, 0xd1ba, 0x0000 },
+  { 0x1a01, 0xd1bc, 0x0000 },
+  { 0x9a01, 0xd1c5, 0x4000 },
+  { 0x9a01, 0xd1c1, 0x3000 },
+  { 0x9a01, 0xd1bf, 0x2000 },
+  { 0x1a01, 0xd1be, 0x0000 },
+  { 0x1a01, 0xd1c0, 0x0000 },
+  { 0x9a01, 0xd1c3, 0x2000 },
+  { 0x1a01, 0xd1c2, 0x0000 },
+  { 0x1a01, 0xd1c4, 0x0000 },
+  { 0x9a01, 0xd1c9, 0x3000 },
+  { 0x9a01, 0xd1c7, 0x2000 },
+  { 0x1a01, 0xd1c6, 0x0000 },
+  { 0x1a01, 0xd1c8, 0x0000 },
+  { 0x9a01, 0xd1cb, 0x2000 },
+  { 0x1a01, 0xd1ca, 0x0000 },
+  { 0x1a01, 0xd1cc, 0x0000 },
+  { 0x9a01, 0xd30f, 0x6000 },
+  { 0x9a01, 0xd1dd, 0x5000 },
+  { 0x9a01, 0xd1d5, 0x4000 },
+  { 0x9a01, 0xd1d1, 0x3000 },
+  { 0x9a01, 0xd1cf, 0x2000 },
+  { 0x1a01, 0xd1ce, 0x0000 },
+  { 0x1a01, 0xd1d0, 0x0000 },
+  { 0x9a01, 0xd1d3, 0x2000 },
+  { 0x1a01, 0xd1d2, 0x0000 },
+  { 0x1a01, 0xd1d4, 0x0000 },
+  { 0x9a01, 0xd1d9, 0x3000 },
+  { 0x9a01, 0xd1d7, 0x2000 },
+  { 0x1a01, 0xd1d6, 0x0000 },
+  { 0x1a01, 0xd1d8, 0x0000 },
+  { 0x9a01, 0xd1db, 0x2000 },
+  { 0x1a01, 0xd1da, 0x0000 },
+  { 0x1a01, 0xd1dc, 0x0000 },
+  { 0x9a01, 0xd307, 0x4000 },
+  { 0x9a01, 0xd303, 0x3000 },
+  { 0x9a01, 0xd301, 0x2000 },
+  { 0x1a01, 0xd300, 0x0000 },
+  { 0x1a01, 0xd302, 0x0000 },
+  { 0x9a01, 0xd305, 0x2000 },
+  { 0x1a01, 0xd304, 0x0000 },
+  { 0x1a01, 0xd306, 0x0000 },
+  { 0x9a01, 0xd30b, 0x3000 },
+  { 0x9a01, 0xd309, 0x2000 },
+  { 0x1a01, 0xd308, 0x0000 },
+  { 0x1a01, 0xd30a, 0x0000 },
+  { 0x9a01, 0xd30d, 0x2000 },
+  { 0x1a01, 0xd30c, 0x0000 },
+  { 0x1a01, 0xd30e, 0x0000 },
+  { 0x9a01, 0xd31f, 0x5000 },
+  { 0x9a01, 0xd317, 0x4000 },
+  { 0x9a01, 0xd313, 0x3000 },
+  { 0x9a01, 0xd311, 0x2000 },
+  { 0x1a01, 0xd310, 0x0000 },
+  { 0x1a01, 0xd312, 0x0000 },
+  { 0x9a01, 0xd315, 0x2000 },
+  { 0x1a01, 0xd314, 0x0000 },
+  { 0x1a01, 0xd316, 0x0000 },
+  { 0x9a01, 0xd31b, 0x3000 },
+  { 0x9a01, 0xd319, 0x2000 },
+  { 0x1a01, 0xd318, 0x0000 },
+  { 0x1a01, 0xd31a, 0x0000 },
+  { 0x9a01, 0xd31d, 0x2000 },
+  { 0x1a01, 0xd31c, 0x0000 },
+  { 0x1a01, 0xd31e, 0x0000 },
+  { 0x9a01, 0xd327, 0x4000 },
+  { 0x9a01, 0xd323, 0x3000 },
+  { 0x9a01, 0xd321, 0x2000 },
+  { 0x1a01, 0xd320, 0x0000 },
+  { 0x1a01, 0xd322, 0x0000 },
+  { 0x9a01, 0xd325, 0x2000 },
+  { 0x1a01, 0xd324, 0x0000 },
+  { 0x1a01, 0xd326, 0x0000 },
+  { 0x9a01, 0xd32b, 0x3000 },
+  { 0x9a01, 0xd329, 0x2000 },
+  { 0x1a01, 0xd328, 0x0000 },
+  { 0x1a01, 0xd32a, 0x0000 },
+  { 0x9a01, 0xd32d, 0x2000 },
+  { 0x1a01, 0xd32c, 0x0000 },
+  { 0x1a01, 0xd32e, 0x0000 },
+  { 0x8901, 0xd418, 0x7000 },
+  { 0x9a01, 0xd34f, 0x6000 },
+  { 0x9a01, 0xd33f, 0x5000 },
+  { 0x9a01, 0xd337, 0x4000 },
+  { 0x9a01, 0xd333, 0x3000 },
+  { 0x9a01, 0xd331, 0x2000 },
+  { 0x1a01, 0xd330, 0x0000 },
+  { 0x1a01, 0xd332, 0x0000 },
+  { 0x9a01, 0xd335, 0x2000 },
+  { 0x1a01, 0xd334, 0x0000 },
+  { 0x1a01, 0xd336, 0x0000 },
+  { 0x9a01, 0xd33b, 0x3000 },
+  { 0x9a01, 0xd339, 0x2000 },
+  { 0x1a01, 0xd338, 0x0000 },
+  { 0x1a01, 0xd33a, 0x0000 },
+  { 0x9a01, 0xd33d, 0x2000 },
+  { 0x1a01, 0xd33c, 0x0000 },
+  { 0x1a01, 0xd33e, 0x0000 },
+  { 0x9a01, 0xd347, 0x4000 },
+  { 0x9a01, 0xd343, 0x3000 },
+  { 0x9a01, 0xd341, 0x2000 },
+  { 0x1a01, 0xd340, 0x0000 },
+  { 0x1a01, 0xd342, 0x0000 },
+  { 0x9a01, 0xd345, 0x2000 },
+  { 0x1a01, 0xd344, 0x0000 },
+  { 0x1a01, 0xd346, 0x0000 },
+  { 0x9a01, 0xd34b, 0x3000 },
+  { 0x9a01, 0xd349, 0x2000 },
+  { 0x1a01, 0xd348, 0x0000 },
+  { 0x1a01, 0xd34a, 0x0000 },
+  { 0x9a01, 0xd34d, 0x2000 },
+  { 0x1a01, 0xd34c, 0x0000 },
+  { 0x1a01, 0xd34e, 0x0000 },
+  { 0x8901, 0xd408, 0x5000 },
+  { 0x8901, 0xd400, 0x4000 },
+  { 0x9a01, 0xd353, 0x3000 },
+  { 0x9a01, 0xd351, 0x2000 },
+  { 0x1a01, 0xd350, 0x0000 },
+  { 0x1a01, 0xd352, 0x0000 },
+  { 0x9a01, 0xd355, 0x2000 },
+  { 0x1a01, 0xd354, 0x0000 },
+  { 0x1a01, 0xd356, 0x0000 },
+  { 0x8901, 0xd404, 0x3000 },
+  { 0x8901, 0xd402, 0x2000 },
+  { 0x0901, 0xd401, 0x0000 },
+  { 0x0901, 0xd403, 0x0000 },
+  { 0x8901, 0xd406, 0x2000 },
+  { 0x0901, 0xd405, 0x0000 },
+  { 0x0901, 0xd407, 0x0000 },
+  { 0x8901, 0xd410, 0x4000 },
+  { 0x8901, 0xd40c, 0x3000 },
+  { 0x8901, 0xd40a, 0x2000 },
+  { 0x0901, 0xd409, 0x0000 },
+  { 0x0901, 0xd40b, 0x0000 },
+  { 0x8901, 0xd40e, 0x2000 },
+  { 0x0901, 0xd40d, 0x0000 },
+  { 0x0901, 0xd40f, 0x0000 },
+  { 0x8901, 0xd414, 0x3000 },
+  { 0x8901, 0xd412, 0x2000 },
+  { 0x0901, 0xd411, 0x0000 },
+  { 0x0901, 0xd413, 0x0000 },
+  { 0x8901, 0xd416, 0x2000 },
+  { 0x0901, 0xd415, 0x0000 },
+  { 0x0901, 0xd417, 0x0000 },
+  { 0x8901, 0xd438, 0x6000 },
+  { 0x8501, 0xd428, 0x5000 },
+  { 0x8501, 0xd420, 0x4000 },
+  { 0x8501, 0xd41c, 0x3000 },
+  { 0x8501, 0xd41a, 0x2000 },
+  { 0x0901, 0xd419, 0x0000 },
+  { 0x0501, 0xd41b, 0x0000 },
+  { 0x8501, 0xd41e, 0x2000 },
+  { 0x0501, 0xd41d, 0x0000 },
+  { 0x0501, 0xd41f, 0x0000 },
+  { 0x8501, 0xd424, 0x3000 },
+  { 0x8501, 0xd422, 0x2000 },
+  { 0x0501, 0xd421, 0x0000 },
+  { 0x0501, 0xd423, 0x0000 },
+  { 0x8501, 0xd426, 0x2000 },
+  { 0x0501, 0xd425, 0x0000 },
+  { 0x0501, 0xd427, 0x0000 },
+  { 0x8501, 0xd430, 0x4000 },
+  { 0x8501, 0xd42c, 0x3000 },
+  { 0x8501, 0xd42a, 0x2000 },
+  { 0x0501, 0xd429, 0x0000 },
+  { 0x0501, 0xd42b, 0x0000 },
+  { 0x8501, 0xd42e, 0x2000 },
+  { 0x0501, 0xd42d, 0x0000 },
+  { 0x0501, 0xd42f, 0x0000 },
+  { 0x8901, 0xd434, 0x3000 },
+  { 0x8501, 0xd432, 0x2000 },
+  { 0x0501, 0xd431, 0x0000 },
+  { 0x0501, 0xd433, 0x0000 },
+  { 0x8901, 0xd436, 0x2000 },
+  { 0x0901, 0xd435, 0x0000 },
+  { 0x0901, 0xd437, 0x0000 },
+  { 0x8901, 0xd448, 0x5000 },
+  { 0x8901, 0xd440, 0x4000 },
+  { 0x8901, 0xd43c, 0x3000 },
+  { 0x8901, 0xd43a, 0x2000 },
+  { 0x0901, 0xd439, 0x0000 },
+  { 0x0901, 0xd43b, 0x0000 },
+  { 0x8901, 0xd43e, 0x2000 },
+  { 0x0901, 0xd43d, 0x0000 },
+  { 0x0901, 0xd43f, 0x0000 },
+  { 0x8901, 0xd444, 0x3000 },
+  { 0x8901, 0xd442, 0x2000 },
+  { 0x0901, 0xd441, 0x0000 },
+  { 0x0901, 0xd443, 0x0000 },
+  { 0x8901, 0xd446, 0x2000 },
+  { 0x0901, 0xd445, 0x0000 },
+  { 0x0901, 0xd447, 0x0000 },
+  { 0x8501, 0xd450, 0x4000 },
+  { 0x8901, 0xd44c, 0x3000 },
+  { 0x8901, 0xd44a, 0x2000 },
+  { 0x0901, 0xd449, 0x0000 },
+  { 0x0901, 0xd44b, 0x0000 },
+  { 0x8501, 0xd44e, 0x2000 },
+  { 0x0901, 0xd44d, 0x0000 },
+  { 0x0501, 0xd44f, 0x0000 },
+  { 0x8501, 0xd454, 0x3000 },
+  { 0x8501, 0xd452, 0x2000 },
+  { 0x0501, 0xd451, 0x0000 },
+  { 0x0501, 0xd453, 0x0000 },
+  { 0x8501, 0xd457, 0x2000 },
+  { 0x0501, 0xd456, 0x0000 },
+  { 0x0501, 0xd458, 0x0000 },
+  { 0x8702, 0xf876, 0xb000 },
+  { 0x8901, 0xd670, 0xa000 },
+  { 0x8901, 0xd570, 0x9000 },
+  { 0x8901, 0xd4e4, 0x8000 },
+  { 0x8501, 0xd499, 0x7000 },
+  { 0x8901, 0xd479, 0x6000 },
+  { 0x8901, 0xd469, 0x5000 },
+  { 0x8501, 0xd461, 0x4000 },
+  { 0x8501, 0xd45d, 0x3000 },
+  { 0x8501, 0xd45b, 0x2000 },
+  { 0x0501, 0xd45a, 0x0000 },
+  { 0x0501, 0xd45c, 0x0000 },
+  { 0x8501, 0xd45f, 0x2000 },
+  { 0x0501, 0xd45e, 0x0000 },
+  { 0x0501, 0xd460, 0x0000 },
+  { 0x8501, 0xd465, 0x3000 },
+  { 0x8501, 0xd463, 0x2000 },
+  { 0x0501, 0xd462, 0x0000 },
+  { 0x0501, 0xd464, 0x0000 },
+  { 0x8501, 0xd467, 0x2000 },
+  { 0x0501, 0xd466, 0x0000 },
+  { 0x0901, 0xd468, 0x0000 },
+  { 0x8901, 0xd471, 0x4000 },
+  { 0x8901, 0xd46d, 0x3000 },
+  { 0x8901, 0xd46b, 0x2000 },
+  { 0x0901, 0xd46a, 0x0000 },
+  { 0x0901, 0xd46c, 0x0000 },
+  { 0x8901, 0xd46f, 0x2000 },
+  { 0x0901, 0xd46e, 0x0000 },
+  { 0x0901, 0xd470, 0x0000 },
+  { 0x8901, 0xd475, 0x3000 },
+  { 0x8901, 0xd473, 0x2000 },
+  { 0x0901, 0xd472, 0x0000 },
+  { 0x0901, 0xd474, 0x0000 },
+  { 0x8901, 0xd477, 0x2000 },
+  { 0x0901, 0xd476, 0x0000 },
+  { 0x0901, 0xd478, 0x0000 },
+  { 0x8501, 0xd489, 0x5000 },
+  { 0x8901, 0xd481, 0x4000 },
+  { 0x8901, 0xd47d, 0x3000 },
+  { 0x8901, 0xd47b, 0x2000 },
+  { 0x0901, 0xd47a, 0x0000 },
+  { 0x0901, 0xd47c, 0x0000 },
+  { 0x8901, 0xd47f, 0x2000 },
+  { 0x0901, 0xd47e, 0x0000 },
+  { 0x0901, 0xd480, 0x0000 },
+  { 0x8501, 0xd485, 0x3000 },
+  { 0x8501, 0xd483, 0x2000 },
+  { 0x0501, 0xd482, 0x0000 },
+  { 0x0501, 0xd484, 0x0000 },
+  { 0x8501, 0xd487, 0x2000 },
+  { 0x0501, 0xd486, 0x0000 },
+  { 0x0501, 0xd488, 0x0000 },
+  { 0x8501, 0xd491, 0x4000 },
+  { 0x8501, 0xd48d, 0x3000 },
+  { 0x8501, 0xd48b, 0x2000 },
+  { 0x0501, 0xd48a, 0x0000 },
+  { 0x0501, 0xd48c, 0x0000 },
+  { 0x8501, 0xd48f, 0x2000 },
+  { 0x0501, 0xd48e, 0x0000 },
+  { 0x0501, 0xd490, 0x0000 },
+  { 0x8501, 0xd495, 0x3000 },
+  { 0x8501, 0xd493, 0x2000 },
+  { 0x0501, 0xd492, 0x0000 },
+  { 0x0501, 0xd494, 0x0000 },
+  { 0x8501, 0xd497, 0x2000 },
+  { 0x0501, 0xd496, 0x0000 },
+  { 0x0501, 0xd498, 0x0000 },
+  { 0x8501, 0xd4c3, 0x6000 },
+  { 0x8901, 0xd4b1, 0x5000 },
+  { 0x8901, 0xd4a6, 0x4000 },
+  { 0x8901, 0xd49e, 0x3000 },
+  { 0x8501, 0xd49b, 0x2000 },
+  { 0x0501, 0xd49a, 0x0000 },
+  { 0x0901, 0xd49c, 0x0000 },
+  { 0x8901, 0xd4a2, 0x2000 },
+  { 0x0901, 0xd49f, 0x0000 },
+  { 0x0901, 0xd4a5, 0x0000 },
+  { 0x8901, 0xd4ac, 0x3000 },
+  { 0x8901, 0xd4aa, 0x2000 },
+  { 0x0901, 0xd4a9, 0x0000 },
+  { 0x0901, 0xd4ab, 0x0000 },
+  { 0x8901, 0xd4af, 0x2000 },
+  { 0x0901, 0xd4ae, 0x0000 },
+  { 0x0901, 0xd4b0, 0x0000 },
+  { 0x8501, 0xd4b9, 0x4000 },
+  { 0x8901, 0xd4b5, 0x3000 },
+  { 0x8901, 0xd4b3, 0x2000 },
+  { 0x0901, 0xd4b2, 0x0000 },
+  { 0x0901, 0xd4b4, 0x0000 },
+  { 0x8501, 0xd4b7, 0x2000 },
+  { 0x0501, 0xd4b6, 0x0000 },
+  { 0x0501, 0xd4b8, 0x0000 },
+  { 0x8501, 0xd4bf, 0x3000 },
+  { 0x8501, 0xd4bd, 0x2000 },
+  { 0x0501, 0xd4bb, 0x0000 },
+  { 0x0501, 0xd4be, 0x0000 },
+  { 0x8501, 0xd4c1, 0x2000 },
+  { 0x0501, 0xd4c0, 0x0000 },
+  { 0x0501, 0xd4c2, 0x0000 },
+  { 0x8901, 0xd4d4, 0x5000 },
+  { 0x8501, 0xd4cc, 0x4000 },
+  { 0x8501, 0xd4c8, 0x3000 },
+  { 0x8501, 0xd4c6, 0x2000 },
+  { 0x0501, 0xd4c5, 0x0000 },
+  { 0x0501, 0xd4c7, 0x0000 },
+  { 0x8501, 0xd4ca, 0x2000 },
+  { 0x0501, 0xd4c9, 0x0000 },
+  { 0x0501, 0xd4cb, 0x0000 },
+  { 0x8901, 0xd4d0, 0x3000 },
+  { 0x8501, 0xd4ce, 0x2000 },
+  { 0x0501, 0xd4cd, 0x0000 },
+  { 0x0501, 0xd4cf, 0x0000 },
+  { 0x8901, 0xd4d2, 0x2000 },
+  { 0x0901, 0xd4d1, 0x0000 },
+  { 0x0901, 0xd4d3, 0x0000 },
+  { 0x8901, 0xd4dc, 0x4000 },
+  { 0x8901, 0xd4d8, 0x3000 },
+  { 0x8901, 0xd4d6, 0x2000 },
+  { 0x0901, 0xd4d5, 0x0000 },
+  { 0x0901, 0xd4d7, 0x0000 },
+  { 0x8901, 0xd4da, 0x2000 },
+  { 0x0901, 0xd4d9, 0x0000 },
+  { 0x0901, 0xd4db, 0x0000 },
+  { 0x8901, 0xd4e0, 0x3000 },
+  { 0x8901, 0xd4de, 0x2000 },
+  { 0x0901, 0xd4dd, 0x0000 },
+  { 0x0901, 0xd4df, 0x0000 },
+  { 0x8901, 0xd4e2, 0x2000 },
+  { 0x0901, 0xd4e1, 0x0000 },
+  { 0x0901, 0xd4e3, 0x0000 },
+  { 0x8501, 0xd529, 0x7000 },
+  { 0x8901, 0xd504, 0x6000 },
+  { 0x8501, 0xd4f4, 0x5000 },
+  { 0x8501, 0xd4ec, 0x4000 },
+  { 0x8901, 0xd4e8, 0x3000 },
+  { 0x8901, 0xd4e6, 0x2000 },
+  { 0x0901, 0xd4e5, 0x0000 },
+  { 0x0901, 0xd4e7, 0x0000 },
+  { 0x8501, 0xd4ea, 0x2000 },
+  { 0x0901, 0xd4e9, 0x0000 },
+  { 0x0501, 0xd4eb, 0x0000 },
+  { 0x8501, 0xd4f0, 0x3000 },
+  { 0x8501, 0xd4ee, 0x2000 },
+  { 0x0501, 0xd4ed, 0x0000 },
+  { 0x0501, 0xd4ef, 0x0000 },
+  { 0x8501, 0xd4f2, 0x2000 },
+  { 0x0501, 0xd4f1, 0x0000 },
+  { 0x0501, 0xd4f3, 0x0000 },
+  { 0x8501, 0xd4fc, 0x4000 },
+  { 0x8501, 0xd4f8, 0x3000 },
+  { 0x8501, 0xd4f6, 0x2000 },
+  { 0x0501, 0xd4f5, 0x0000 },
+  { 0x0501, 0xd4f7, 0x0000 },
+  { 0x8501, 0xd4fa, 0x2000 },
+  { 0x0501, 0xd4f9, 0x0000 },
+  { 0x0501, 0xd4fb, 0x0000 },
+  { 0x8501, 0xd500, 0x3000 },
+  { 0x8501, 0xd4fe, 0x2000 },
+  { 0x0501, 0xd4fd, 0x0000 },
+  { 0x0501, 0xd4ff, 0x0000 },
+  { 0x8501, 0xd502, 0x2000 },
+  { 0x0501, 0xd501, 0x0000 },
+  { 0x0501, 0xd503, 0x0000 },
+  { 0x8901, 0xd518, 0x5000 },
+  { 0x8901, 0xd50f, 0x4000 },
+  { 0x8901, 0xd509, 0x3000 },
+  { 0x8901, 0xd507, 0x2000 },
+  { 0x0901, 0xd505, 0x0000 },
+  { 0x0901, 0xd508, 0x0000 },
+  { 0x8901, 0xd50d, 0x2000 },
+  { 0x0901, 0xd50a, 0x0000 },
+  { 0x0901, 0xd50e, 0x0000 },
+  { 0x8901, 0xd513, 0x3000 },
+  { 0x8901, 0xd511, 0x2000 },
+  { 0x0901, 0xd510, 0x0000 },
+  { 0x0901, 0xd512, 0x0000 },
+  { 0x8901, 0xd516, 0x2000 },
+  { 0x0901, 0xd514, 0x0000 },
+  { 0x0901, 0xd517, 0x0000 },
+  { 0x8501, 0xd521, 0x4000 },
+  { 0x8901, 0xd51c, 0x3000 },
+  { 0x8901, 0xd51a, 0x2000 },
+  { 0x0901, 0xd519, 0x0000 },
+  { 0x0901, 0xd51b, 0x0000 },
+  { 0x8501, 0xd51f, 0x2000 },
+  { 0x0501, 0xd51e, 0x0000 },
+  { 0x0501, 0xd520, 0x0000 },
+  { 0x8501, 0xd525, 0x3000 },
+  { 0x8501, 0xd523, 0x2000 },
+  { 0x0501, 0xd522, 0x0000 },
+  { 0x0501, 0xd524, 0x0000 },
+  { 0x8501, 0xd527, 0x2000 },
+  { 0x0501, 0xd526, 0x0000 },
+  { 0x0501, 0xd528, 0x0000 },
+  { 0x8901, 0xd54f, 0x6000 },
+  { 0x8901, 0xd539, 0x5000 },
+  { 0x8501, 0xd531, 0x4000 },
+  { 0x8501, 0xd52d, 0x3000 },
+  { 0x8501, 0xd52b, 0x2000 },
+  { 0x0501, 0xd52a, 0x0000 },
+  { 0x0501, 0xd52c, 0x0000 },
+  { 0x8501, 0xd52f, 0x2000 },
+  { 0x0501, 0xd52e, 0x0000 },
+  { 0x0501, 0xd530, 0x0000 },
+  { 0x8501, 0xd535, 0x3000 },
+  { 0x8501, 0xd533, 0x2000 },
+  { 0x0501, 0xd532, 0x0000 },
+  { 0x0501, 0xd534, 0x0000 },
+  { 0x8501, 0xd537, 0x2000 },
+  { 0x0501, 0xd536, 0x0000 },
+  { 0x0901, 0xd538, 0x0000 },
+  { 0x8901, 0xd543, 0x4000 },
+  { 0x8901, 0xd53e, 0x3000 },
+  { 0x8901, 0xd53c, 0x2000 },
+  { 0x0901, 0xd53b, 0x0000 },
+  { 0x0901, 0xd53d, 0x0000 },
+  { 0x8901, 0xd541, 0x2000 },
+  { 0x0901, 0xd540, 0x0000 },
+  { 0x0901, 0xd542, 0x0000 },
+  { 0x8901, 0xd54b, 0x3000 },
+  { 0x8901, 0xd546, 0x2000 },
+  { 0x0901, 0xd544, 0x0000 },
+  { 0x0901, 0xd54a, 0x0000 },
+  { 0x8901, 0xd54d, 0x2000 },
+  { 0x0901, 0xd54c, 0x0000 },
+  { 0x0901, 0xd54e, 0x0000 },
+  { 0x8501, 0xd560, 0x5000 },
+  { 0x8501, 0xd558, 0x4000 },
+  { 0x8501, 0xd554, 0x3000 },
+  { 0x8501, 0xd552, 0x2000 },
+  { 0x0901, 0xd550, 0x0000 },
+  { 0x0501, 0xd553, 0x0000 },
+  { 0x8501, 0xd556, 0x2000 },
+  { 0x0501, 0xd555, 0x0000 },
+  { 0x0501, 0xd557, 0x0000 },
+  { 0x8501, 0xd55c, 0x3000 },
+  { 0x8501, 0xd55a, 0x2000 },
+  { 0x0501, 0xd559, 0x0000 },
+  { 0x0501, 0xd55b, 0x0000 },
+  { 0x8501, 0xd55e, 0x2000 },
+  { 0x0501, 0xd55d, 0x0000 },
+  { 0x0501, 0xd55f, 0x0000 },
+  { 0x8501, 0xd568, 0x4000 },
+  { 0x8501, 0xd564, 0x3000 },
+  { 0x8501, 0xd562, 0x2000 },
+  { 0x0501, 0xd561, 0x0000 },
+  { 0x0501, 0xd563, 0x0000 },
+  { 0x8501, 0xd566, 0x2000 },
+  { 0x0501, 0xd565, 0x0000 },
+  { 0x0501, 0xd567, 0x0000 },
+  { 0x8901, 0xd56c, 0x3000 },
+  { 0x8501, 0xd56a, 0x2000 },
+  { 0x0501, 0xd569, 0x0000 },
+  { 0x0501, 0xd56b, 0x0000 },
+  { 0x8901, 0xd56e, 0x2000 },
+  { 0x0901, 0xd56d, 0x0000 },
+  { 0x0901, 0xd56f, 0x0000 },
+  { 0x8501, 0xd5f0, 0x8000 },
+  { 0x8901, 0xd5b0, 0x7000 },
+  { 0x8501, 0xd590, 0x6000 },
+  { 0x8901, 0xd580, 0x5000 },
+  { 0x8901, 0xd578, 0x4000 },
+  { 0x8901, 0xd574, 0x3000 },
+  { 0x8901, 0xd572, 0x2000 },
+  { 0x0901, 0xd571, 0x0000 },
+  { 0x0901, 0xd573, 0x0000 },
+  { 0x8901, 0xd576, 0x2000 },
+  { 0x0901, 0xd575, 0x0000 },
+  { 0x0901, 0xd577, 0x0000 },
+  { 0x8901, 0xd57c, 0x3000 },
+  { 0x8901, 0xd57a, 0x2000 },
+  { 0x0901, 0xd579, 0x0000 },
+  { 0x0901, 0xd57b, 0x0000 },
+  { 0x8901, 0xd57e, 0x2000 },
+  { 0x0901, 0xd57d, 0x0000 },
+  { 0x0901, 0xd57f, 0x0000 },
+  { 0x8501, 0xd588, 0x4000 },
+  { 0x8901, 0xd584, 0x3000 },
+  { 0x8901, 0xd582, 0x2000 },
+  { 0x0901, 0xd581, 0x0000 },
+  { 0x0901, 0xd583, 0x0000 },
+  { 0x8501, 0xd586, 0x2000 },
+  { 0x0901, 0xd585, 0x0000 },
+  { 0x0501, 0xd587, 0x0000 },
+  { 0x8501, 0xd58c, 0x3000 },
+  { 0x8501, 0xd58a, 0x2000 },
+  { 0x0501, 0xd589, 0x0000 },
+  { 0x0501, 0xd58b, 0x0000 },
+  { 0x8501, 0xd58e, 0x2000 },
+  { 0x0501, 0xd58d, 0x0000 },
+  { 0x0501, 0xd58f, 0x0000 },
+  { 0x8901, 0xd5a0, 0x5000 },
+  { 0x8501, 0xd598, 0x4000 },
+  { 0x8501, 0xd594, 0x3000 },
+  { 0x8501, 0xd592, 0x2000 },
+  { 0x0501, 0xd591, 0x0000 },
+  { 0x0501, 0xd593, 0x0000 },
+  { 0x8501, 0xd596, 0x2000 },
+  { 0x0501, 0xd595, 0x0000 },
+  { 0x0501, 0xd597, 0x0000 },
+  { 0x8501, 0xd59c, 0x3000 },
+  { 0x8501, 0xd59a, 0x2000 },
+  { 0x0501, 0xd599, 0x0000 },
+  { 0x0501, 0xd59b, 0x0000 },
+  { 0x8501, 0xd59e, 0x2000 },
+  { 0x0501, 0xd59d, 0x0000 },
+  { 0x0501, 0xd59f, 0x0000 },
+  { 0x8901, 0xd5a8, 0x4000 },
+  { 0x8901, 0xd5a4, 0x3000 },
+  { 0x8901, 0xd5a2, 0x2000 },
+  { 0x0901, 0xd5a1, 0x0000 },
+  { 0x0901, 0xd5a3, 0x0000 },
+  { 0x8901, 0xd5a6, 0x2000 },
+  { 0x0901, 0xd5a5, 0x0000 },
+  { 0x0901, 0xd5a7, 0x0000 },
+  { 0x8901, 0xd5ac, 0x3000 },
+  { 0x8901, 0xd5aa, 0x2000 },
+  { 0x0901, 0xd5a9, 0x0000 },
+  { 0x0901, 0xd5ab, 0x0000 },
+  { 0x8901, 0xd5ae, 0x2000 },
+  { 0x0901, 0xd5ad, 0x0000 },
+  { 0x0901, 0xd5af, 0x0000 },
+  { 0x8501, 0xd5d0, 0x6000 },
+  { 0x8501, 0xd5c0, 0x5000 },
+  { 0x8901, 0xd5b8, 0x4000 },
+  { 0x8901, 0xd5b4, 0x3000 },
+  { 0x8901, 0xd5b2, 0x2000 },
+  { 0x0901, 0xd5b1, 0x0000 },
+  { 0x0901, 0xd5b3, 0x0000 },
+  { 0x8901, 0xd5b6, 0x2000 },
+  { 0x0901, 0xd5b5, 0x0000 },
+  { 0x0901, 0xd5b7, 0x0000 },
+  { 0x8501, 0xd5bc, 0x3000 },
+  { 0x8501, 0xd5ba, 0x2000 },
+  { 0x0901, 0xd5b9, 0x0000 },
+  { 0x0501, 0xd5bb, 0x0000 },
+  { 0x8501, 0xd5be, 0x2000 },
+  { 0x0501, 0xd5bd, 0x0000 },
+  { 0x0501, 0xd5bf, 0x0000 },
+  { 0x8501, 0xd5c8, 0x4000 },
+  { 0x8501, 0xd5c4, 0x3000 },
+  { 0x8501, 0xd5c2, 0x2000 },
+  { 0x0501, 0xd5c1, 0x0000 },
+  { 0x0501, 0xd5c3, 0x0000 },
+  { 0x8501, 0xd5c6, 0x2000 },
+  { 0x0501, 0xd5c5, 0x0000 },
+  { 0x0501, 0xd5c7, 0x0000 },
+  { 0x8501, 0xd5cc, 0x3000 },
+  { 0x8501, 0xd5ca, 0x2000 },
+  { 0x0501, 0xd5c9, 0x0000 },
+  { 0x0501, 0xd5cb, 0x0000 },
+  { 0x8501, 0xd5ce, 0x2000 },
+  { 0x0501, 0xd5cd, 0x0000 },
+  { 0x0501, 0xd5cf, 0x0000 },
+  { 0x8901, 0xd5e0, 0x5000 },
+  { 0x8901, 0xd5d8, 0x4000 },
+  { 0x8901, 0xd5d4, 0x3000 },
+  { 0x8501, 0xd5d2, 0x2000 },
+  { 0x0501, 0xd5d1, 0x0000 },
+  { 0x0501, 0xd5d3, 0x0000 },
+  { 0x8901, 0xd5d6, 0x2000 },
+  { 0x0901, 0xd5d5, 0x0000 },
+  { 0x0901, 0xd5d7, 0x0000 },
+  { 0x8901, 0xd5dc, 0x3000 },
+  { 0x8901, 0xd5da, 0x2000 },
+  { 0x0901, 0xd5d9, 0x0000 },
+  { 0x0901, 0xd5db, 0x0000 },
+  { 0x8901, 0xd5de, 0x2000 },
+  { 0x0901, 0xd5dd, 0x0000 },
+  { 0x0901, 0xd5df, 0x0000 },
+  { 0x8901, 0xd5e8, 0x4000 },
+  { 0x8901, 0xd5e4, 0x3000 },
+  { 0x8901, 0xd5e2, 0x2000 },
+  { 0x0901, 0xd5e1, 0x0000 },
+  { 0x0901, 0xd5e3, 0x0000 },
+  { 0x8901, 0xd5e6, 0x2000 },
+  { 0x0901, 0xd5e5, 0x0000 },
+  { 0x0901, 0xd5e7, 0x0000 },
+  { 0x8901, 0xd5ec, 0x3000 },
+  { 0x8901, 0xd5ea, 0x2000 },
+  { 0x0901, 0xd5e9, 0x0000 },
+  { 0x0901, 0xd5eb, 0x0000 },
+  { 0x8501, 0xd5ee, 0x2000 },
+  { 0x0901, 0xd5ed, 0x0000 },
+  { 0x0501, 0xd5ef, 0x0000 },
+  { 0x8501, 0xd630, 0x7000 },
+  { 0x8901, 0xd610, 0x6000 },
+  { 0x8501, 0xd600, 0x5000 },
+  { 0x8501, 0xd5f8, 0x4000 },
+  { 0x8501, 0xd5f4, 0x3000 },
+  { 0x8501, 0xd5f2, 0x2000 },
+  { 0x0501, 0xd5f1, 0x0000 },
+  { 0x0501, 0xd5f3, 0x0000 },
+  { 0x8501, 0xd5f6, 0x2000 },
+  { 0x0501, 0xd5f5, 0x0000 },
+  { 0x0501, 0xd5f7, 0x0000 },
+  { 0x8501, 0xd5fc, 0x3000 },
+  { 0x8501, 0xd5fa, 0x2000 },
+  { 0x0501, 0xd5f9, 0x0000 },
+  { 0x0501, 0xd5fb, 0x0000 },
+  { 0x8501, 0xd5fe, 0x2000 },
+  { 0x0501, 0xd5fd, 0x0000 },
+  { 0x0501, 0xd5ff, 0x0000 },
+  { 0x8901, 0xd608, 0x4000 },
+  { 0x8501, 0xd604, 0x3000 },
+  { 0x8501, 0xd602, 0x2000 },
+  { 0x0501, 0xd601, 0x0000 },
+  { 0x0501, 0xd603, 0x0000 },
+  { 0x8501, 0xd606, 0x2000 },
+  { 0x0501, 0xd605, 0x0000 },
+  { 0x0501, 0xd607, 0x0000 },
+  { 0x8901, 0xd60c, 0x3000 },
+  { 0x8901, 0xd60a, 0x2000 },
+  { 0x0901, 0xd609, 0x0000 },
+  { 0x0901, 0xd60b, 0x0000 },
+  { 0x8901, 0xd60e, 0x2000 },
+  { 0x0901, 0xd60d, 0x0000 },
+  { 0x0901, 0xd60f, 0x0000 },
+  { 0x8901, 0xd620, 0x5000 },
+  { 0x8901, 0xd618, 0x4000 },
+  { 0x8901, 0xd614, 0x3000 },
+  { 0x8901, 0xd612, 0x2000 },
+  { 0x0901, 0xd611, 0x0000 },
+  { 0x0901, 0xd613, 0x0000 },
+  { 0x8901, 0xd616, 0x2000 },
+  { 0x0901, 0xd615, 0x0000 },
+  { 0x0901, 0xd617, 0x0000 },
+  { 0x8901, 0xd61c, 0x3000 },
+  { 0x8901, 0xd61a, 0x2000 },
+  { 0x0901, 0xd619, 0x0000 },
+  { 0x0901, 0xd61b, 0x0000 },
+  { 0x8901, 0xd61e, 0x2000 },
+  { 0x0901, 0xd61d, 0x0000 },
+  { 0x0901, 0xd61f, 0x0000 },
+  { 0x8501, 0xd628, 0x4000 },
+  { 0x8501, 0xd624, 0x3000 },
+  { 0x8501, 0xd622, 0x2000 },
+  { 0x0901, 0xd621, 0x0000 },
+  { 0x0501, 0xd623, 0x0000 },
+  { 0x8501, 0xd626, 0x2000 },
+  { 0x0501, 0xd625, 0x0000 },
+  { 0x0501, 0xd627, 0x0000 },
+  { 0x8501, 0xd62c, 0x3000 },
+  { 0x8501, 0xd62a, 0x2000 },
+  { 0x0501, 0xd629, 0x0000 },
+  { 0x0501, 0xd62b, 0x0000 },
+  { 0x8501, 0xd62e, 0x2000 },
+  { 0x0501, 0xd62d, 0x0000 },
+  { 0x0501, 0xd62f, 0x0000 },
+  { 0x8901, 0xd650, 0x6000 },
+  { 0x8901, 0xd640, 0x5000 },
+  { 0x8501, 0xd638, 0x4000 },
+  { 0x8501, 0xd634, 0x3000 },
+  { 0x8501, 0xd632, 0x2000 },
+  { 0x0501, 0xd631, 0x0000 },
+  { 0x0501, 0xd633, 0x0000 },
+  { 0x8501, 0xd636, 0x2000 },
+  { 0x0501, 0xd635, 0x0000 },
+  { 0x0501, 0xd637, 0x0000 },
+  { 0x8901, 0xd63c, 0x3000 },
+  { 0x8501, 0xd63a, 0x2000 },
+  { 0x0501, 0xd639, 0x0000 },
+  { 0x0501, 0xd63b, 0x0000 },
+  { 0x8901, 0xd63e, 0x2000 },
+  { 0x0901, 0xd63d, 0x0000 },
+  { 0x0901, 0xd63f, 0x0000 },
+  { 0x8901, 0xd648, 0x4000 },
+  { 0x8901, 0xd644, 0x3000 },
+  { 0x8901, 0xd642, 0x2000 },
+  { 0x0901, 0xd641, 0x0000 },
+  { 0x0901, 0xd643, 0x0000 },
+  { 0x8901, 0xd646, 0x2000 },
+  { 0x0901, 0xd645, 0x0000 },
+  { 0x0901, 0xd647, 0x0000 },
+  { 0x8901, 0xd64c, 0x3000 },
+  { 0x8901, 0xd64a, 0x2000 },
+  { 0x0901, 0xd649, 0x0000 },
+  { 0x0901, 0xd64b, 0x0000 },
+  { 0x8901, 0xd64e, 0x2000 },
+  { 0x0901, 0xd64d, 0x0000 },
+  { 0x0901, 0xd64f, 0x0000 },
+  { 0x8501, 0xd660, 0x5000 },
+  { 0x8501, 0xd658, 0x4000 },
+  { 0x8901, 0xd654, 0x3000 },
+  { 0x8901, 0xd652, 0x2000 },
+  { 0x0901, 0xd651, 0x0000 },
+  { 0x0901, 0xd653, 0x0000 },
+  { 0x8501, 0xd656, 0x2000 },
+  { 0x0901, 0xd655, 0x0000 },
+  { 0x0501, 0xd657, 0x0000 },
+  { 0x8501, 0xd65c, 0x3000 },
+  { 0x8501, 0xd65a, 0x2000 },
+  { 0x0501, 0xd659, 0x0000 },
+  { 0x0501, 0xd65b, 0x0000 },
+  { 0x8501, 0xd65e, 0x2000 },
+  { 0x0501, 0xd65d, 0x0000 },
+  { 0x0501, 0xd65f, 0x0000 },
+  { 0x8501, 0xd668, 0x4000 },
+  { 0x8501, 0xd664, 0x3000 },
+  { 0x8501, 0xd662, 0x2000 },
+  { 0x0501, 0xd661, 0x0000 },
+  { 0x0501, 0xd663, 0x0000 },
+  { 0x8501, 0xd666, 0x2000 },
+  { 0x0501, 0xd665, 0x0000 },
+  { 0x0501, 0xd667, 0x0000 },
+  { 0x8501, 0xd66c, 0x3000 },
+  { 0x8501, 0xd66a, 0x2000 },
+  { 0x0501, 0xd669, 0x0000 },
+  { 0x0501, 0xd66b, 0x0000 },
+  { 0x8501, 0xd66e, 0x2000 },
+  { 0x0501, 0xd66d, 0x0000 },
+  { 0x0501, 0xd66f, 0x0000 },
+  { 0x8501, 0xd774, 0x9000 },
+  { 0x8901, 0xd6f4, 0x8000 },
+  { 0x8901, 0xd6b4, 0x7000 },
+  { 0x8501, 0xd690, 0x6000 },
+  { 0x8901, 0xd680, 0x5000 },
+  { 0x8901, 0xd678, 0x4000 },
+  { 0x8901, 0xd674, 0x3000 },
+  { 0x8901, 0xd672, 0x2000 },
+  { 0x0901, 0xd671, 0x0000 },
+  { 0x0901, 0xd673, 0x0000 },
+  { 0x8901, 0xd676, 0x2000 },
+  { 0x0901, 0xd675, 0x0000 },
+  { 0x0901, 0xd677, 0x0000 },
+  { 0x8901, 0xd67c, 0x3000 },
+  { 0x8901, 0xd67a, 0x2000 },
+  { 0x0901, 0xd679, 0x0000 },
+  { 0x0901, 0xd67b, 0x0000 },
+  { 0x8901, 0xd67e, 0x2000 },
+  { 0x0901, 0xd67d, 0x0000 },
+  { 0x0901, 0xd67f, 0x0000 },
+  { 0x8901, 0xd688, 0x4000 },
+  { 0x8901, 0xd684, 0x3000 },
+  { 0x8901, 0xd682, 0x2000 },
+  { 0x0901, 0xd681, 0x0000 },
+  { 0x0901, 0xd683, 0x0000 },
+  { 0x8901, 0xd686, 0x2000 },
+  { 0x0901, 0xd685, 0x0000 },
+  { 0x0901, 0xd687, 0x0000 },
+  { 0x8501, 0xd68c, 0x3000 },
+  { 0x8501, 0xd68a, 0x2000 },
+  { 0x0901, 0xd689, 0x0000 },
+  { 0x0501, 0xd68b, 0x0000 },
+  { 0x8501, 0xd68e, 0x2000 },
+  { 0x0501, 0xd68d, 0x0000 },
+  { 0x0501, 0xd68f, 0x0000 },
+  { 0x8501, 0xd6a0, 0x5000 },
+  { 0x8501, 0xd698, 0x4000 },
+  { 0x8501, 0xd694, 0x3000 },
+  { 0x8501, 0xd692, 0x2000 },
+  { 0x0501, 0xd691, 0x0000 },
+  { 0x0501, 0xd693, 0x0000 },
+  { 0x8501, 0xd696, 0x2000 },
+  { 0x0501, 0xd695, 0x0000 },
+  { 0x0501, 0xd697, 0x0000 },
+  { 0x8501, 0xd69c, 0x3000 },
+  { 0x8501, 0xd69a, 0x2000 },
+  { 0x0501, 0xd699, 0x0000 },
+  { 0x0501, 0xd69b, 0x0000 },
+  { 0x8501, 0xd69e, 0x2000 },
+  { 0x0501, 0xd69d, 0x0000 },
+  { 0x0501, 0xd69f, 0x0000 },
+  { 0x8901, 0xd6ac, 0x4000 },
+  { 0x8901, 0xd6a8, 0x3000 },
+  { 0x8501, 0xd6a2, 0x2000 },
+  { 0x0501, 0xd6a1, 0x0000 },
+  { 0x0501, 0xd6a3, 0x0000 },
+  { 0x8901, 0xd6aa, 0x2000 },
+  { 0x0901, 0xd6a9, 0x0000 },
+  { 0x0901, 0xd6ab, 0x0000 },
+  { 0x8901, 0xd6b0, 0x3000 },
+  { 0x8901, 0xd6ae, 0x2000 },
+  { 0x0901, 0xd6ad, 0x0000 },
+  { 0x0901, 0xd6af, 0x0000 },
+  { 0x8901, 0xd6b2, 0x2000 },
+  { 0x0901, 0xd6b1, 0x0000 },
+  { 0x0901, 0xd6b3, 0x0000 },
+  { 0x8501, 0xd6d4, 0x6000 },
+  { 0x8501, 0xd6c4, 0x5000 },
+  { 0x8901, 0xd6bc, 0x4000 },
+  { 0x8901, 0xd6b8, 0x3000 },
+  { 0x8901, 0xd6b6, 0x2000 },
+  { 0x0901, 0xd6b5, 0x0000 },
+  { 0x0901, 0xd6b7, 0x0000 },
+  { 0x8901, 0xd6ba, 0x2000 },
+  { 0x0901, 0xd6b9, 0x0000 },
+  { 0x0901, 0xd6bb, 0x0000 },
+  { 0x8901, 0xd6c0, 0x3000 },
+  { 0x8901, 0xd6be, 0x2000 },
+  { 0x0901, 0xd6bd, 0x0000 },
+  { 0x0901, 0xd6bf, 0x0000 },
+  { 0x8501, 0xd6c2, 0x2000 },
+  { 0x1901, 0xd6c1, 0x0000 },
+  { 0x0501, 0xd6c3, 0x0000 },
+  { 0x8501, 0xd6cc, 0x4000 },
+  { 0x8501, 0xd6c8, 0x3000 },
+  { 0x8501, 0xd6c6, 0x2000 },
+  { 0x0501, 0xd6c5, 0x0000 },
+  { 0x0501, 0xd6c7, 0x0000 },
+  { 0x8501, 0xd6ca, 0x2000 },
+  { 0x0501, 0xd6c9, 0x0000 },
+  { 0x0501, 0xd6cb, 0x0000 },
+  { 0x8501, 0xd6d0, 0x3000 },
+  { 0x8501, 0xd6ce, 0x2000 },
+  { 0x0501, 0xd6cd, 0x0000 },
+  { 0x0501, 0xd6cf, 0x0000 },
+  { 0x8501, 0xd6d2, 0x2000 },
+  { 0x0501, 0xd6d1, 0x0000 },
+  { 0x0501, 0xd6d3, 0x0000 },
+  { 0x8901, 0xd6e4, 0x5000 },
+  { 0x8501, 0xd6dc, 0x4000 },
+  { 0x8501, 0xd6d8, 0x3000 },
+  { 0x8501, 0xd6d6, 0x2000 },
+  { 0x0501, 0xd6d5, 0x0000 },
+  { 0x0501, 0xd6d7, 0x0000 },
+  { 0x8501, 0xd6da, 0x2000 },
+  { 0x0501, 0xd6d9, 0x0000 },
+  { 0x1901, 0xd6db, 0x0000 },
+  { 0x8501, 0xd6e0, 0x3000 },
+  { 0x8501, 0xd6de, 0x2000 },
+  { 0x0501, 0xd6dd, 0x0000 },
+  { 0x0501, 0xd6df, 0x0000 },
+  { 0x8901, 0xd6e2, 0x2000 },
+  { 0x0501, 0xd6e1, 0x0000 },
+  { 0x0901, 0xd6e3, 0x0000 },
+  { 0x8901, 0xd6ec, 0x4000 },
+  { 0x8901, 0xd6e8, 0x3000 },
+  { 0x8901, 0xd6e6, 0x2000 },
+  { 0x0901, 0xd6e5, 0x0000 },
+  { 0x0901, 0xd6e7, 0x0000 },
+  { 0x8901, 0xd6ea, 0x2000 },
+  { 0x0901, 0xd6e9, 0x0000 },
+  { 0x0901, 0xd6eb, 0x0000 },
+  { 0x8901, 0xd6f0, 0x3000 },
+  { 0x8901, 0xd6ee, 0x2000 },
+  { 0x0901, 0xd6ed, 0x0000 },
+  { 0x0901, 0xd6ef, 0x0000 },
+  { 0x8901, 0xd6f2, 0x2000 },
+  { 0x0901, 0xd6f1, 0x0000 },
+  { 0x0901, 0xd6f3, 0x0000 },
+  { 0x8901, 0xd734, 0x7000 },
+  { 0x8501, 0xd714, 0x6000 },
+  { 0x8501, 0xd704, 0x5000 },
+  { 0x8501, 0xd6fc, 0x4000 },
+  { 0x8901, 0xd6f8, 0x3000 },
+  { 0x8901, 0xd6f6, 0x2000 },
+  { 0x0901, 0xd6f5, 0x0000 },
+  { 0x0901, 0xd6f7, 0x0000 },
+  { 0x8901, 0xd6fa, 0x2000 },
+  { 0x0901, 0xd6f9, 0x0000 },
+  { 0x1901, 0xd6fb, 0x0000 },
+  { 0x8501, 0xd700, 0x3000 },
+  { 0x8501, 0xd6fe, 0x2000 },
+  { 0x0501, 0xd6fd, 0x0000 },
+  { 0x0501, 0xd6ff, 0x0000 },
+  { 0x8501, 0xd702, 0x2000 },
+  { 0x0501, 0xd701, 0x0000 },
+  { 0x0501, 0xd703, 0x0000 },
+  { 0x8501, 0xd70c, 0x4000 },
+  { 0x8501, 0xd708, 0x3000 },
+  { 0x8501, 0xd706, 0x2000 },
+  { 0x0501, 0xd705, 0x0000 },
+  { 0x0501, 0xd707, 0x0000 },
+  { 0x8501, 0xd70a, 0x2000 },
+  { 0x0501, 0xd709, 0x0000 },
+  { 0x0501, 0xd70b, 0x0000 },
+  { 0x8501, 0xd710, 0x3000 },
+  { 0x8501, 0xd70e, 0x2000 },
+  { 0x0501, 0xd70d, 0x0000 },
+  { 0x0501, 0xd70f, 0x0000 },
+  { 0x8501, 0xd712, 0x2000 },
+  { 0x0501, 0xd711, 0x0000 },
+  { 0x0501, 0xd713, 0x0000 },
+  { 0x8901, 0xd724, 0x5000 },
+  { 0x8901, 0xd71c, 0x4000 },
+  { 0x8501, 0xd718, 0x3000 },
+  { 0x8501, 0xd716, 0x2000 },
+  { 0x1901, 0xd715, 0x0000 },
+  { 0x0501, 0xd717, 0x0000 },
+  { 0x8501, 0xd71a, 0x2000 },
+  { 0x0501, 0xd719, 0x0000 },
+  { 0x0501, 0xd71b, 0x0000 },
+  { 0x8901, 0xd720, 0x3000 },
+  { 0x8901, 0xd71e, 0x2000 },
+  { 0x0901, 0xd71d, 0x0000 },
+  { 0x0901, 0xd71f, 0x0000 },
+  { 0x8901, 0xd722, 0x2000 },
+  { 0x0901, 0xd721, 0x0000 },
+  { 0x0901, 0xd723, 0x0000 },
+  { 0x8901, 0xd72c, 0x4000 },
+  { 0x8901, 0xd728, 0x3000 },
+  { 0x8901, 0xd726, 0x2000 },
+  { 0x0901, 0xd725, 0x0000 },
+  { 0x0901, 0xd727, 0x0000 },
+  { 0x8901, 0xd72a, 0x2000 },
+  { 0x0901, 0xd729, 0x0000 },
+  { 0x0901, 0xd72b, 0x0000 },
+  { 0x8901, 0xd730, 0x3000 },
+  { 0x8901, 0xd72e, 0x2000 },
+  { 0x0901, 0xd72d, 0x0000 },
+  { 0x0901, 0xd72f, 0x0000 },
+  { 0x8901, 0xd732, 0x2000 },
+  { 0x0901, 0xd731, 0x0000 },
+  { 0x0901, 0xd733, 0x0000 },
+  { 0x8501, 0xd754, 0x6000 },
+  { 0x8501, 0xd744, 0x5000 },
+  { 0x8501, 0xd73c, 0x4000 },
+  { 0x8501, 0xd738, 0x3000 },
+  { 0x8501, 0xd736, 0x2000 },
+  { 0x1901, 0xd735, 0x0000 },
+  { 0x0501, 0xd737, 0x0000 },
+  { 0x8501, 0xd73a, 0x2000 },
+  { 0x0501, 0xd739, 0x0000 },
+  { 0x0501, 0xd73b, 0x0000 },
+  { 0x8501, 0xd740, 0x3000 },
+  { 0x8501, 0xd73e, 0x2000 },
+  { 0x0501, 0xd73d, 0x0000 },
+  { 0x0501, 0xd73f, 0x0000 },
+  { 0x8501, 0xd742, 0x2000 },
+  { 0x0501, 0xd741, 0x0000 },
+  { 0x0501, 0xd743, 0x0000 },
+  { 0x8501, 0xd74c, 0x4000 },
+  { 0x8501, 0xd748, 0x3000 },
+  { 0x8501, 0xd746, 0x2000 },
+  { 0x0501, 0xd745, 0x0000 },
+  { 0x0501, 0xd747, 0x0000 },
+  { 0x8501, 0xd74a, 0x2000 },
+  { 0x0501, 0xd749, 0x0000 },
+  { 0x0501, 0xd74b, 0x0000 },
+  { 0x8501, 0xd750, 0x3000 },
+  { 0x8501, 0xd74e, 0x2000 },
+  { 0x0501, 0xd74d, 0x0000 },
+  { 0x1901, 0xd74f, 0x0000 },
+  { 0x8501, 0xd752, 0x2000 },
+  { 0x0501, 0xd751, 0x0000 },
+  { 0x0501, 0xd753, 0x0000 },
+  { 0x8901, 0xd764, 0x5000 },
+  { 0x8901, 0xd75c, 0x4000 },
+  { 0x8901, 0xd758, 0x3000 },
+  { 0x8901, 0xd756, 0x2000 },
+  { 0x0501, 0xd755, 0x0000 },
+  { 0x0901, 0xd757, 0x0000 },
+  { 0x8901, 0xd75a, 0x2000 },
+  { 0x0901, 0xd759, 0x0000 },
+  { 0x0901, 0xd75b, 0x0000 },
+  { 0x8901, 0xd760, 0x3000 },
+  { 0x8901, 0xd75e, 0x2000 },
+  { 0x0901, 0xd75d, 0x0000 },
+  { 0x0901, 0xd75f, 0x0000 },
+  { 0x8901, 0xd762, 0x2000 },
+  { 0x0901, 0xd761, 0x0000 },
+  { 0x0901, 0xd763, 0x0000 },
+  { 0x8901, 0xd76c, 0x4000 },
+  { 0x8901, 0xd768, 0x3000 },
+  { 0x8901, 0xd766, 0x2000 },
+  { 0x0901, 0xd765, 0x0000 },
+  { 0x0901, 0xd767, 0x0000 },
+  { 0x8901, 0xd76a, 0x2000 },
+  { 0x0901, 0xd769, 0x0000 },
+  { 0x0901, 0xd76b, 0x0000 },
+  { 0x8501, 0xd770, 0x3000 },
+  { 0x8901, 0xd76e, 0x2000 },
+  { 0x0901, 0xd76d, 0x0000 },
+  { 0x1901, 0xd76f, 0x0000 },
+  { 0x8501, 0xd772, 0x2000 },
+  { 0x0501, 0xd771, 0x0000 },
+  { 0x0501, 0xd773, 0x0000 },
+  { 0x8d01, 0xd7f8, 0x8000 },
+  { 0x8501, 0xd7b4, 0x7000 },
+  { 0x8901, 0xd794, 0x6000 },
+  { 0x8501, 0xd784, 0x5000 },
+  { 0x8501, 0xd77c, 0x4000 },
+  { 0x8501, 0xd778, 0x3000 },
+  { 0x8501, 0xd776, 0x2000 },
+  { 0x0501, 0xd775, 0x0000 },
+  { 0x0501, 0xd777, 0x0000 },
+  { 0x8501, 0xd77a, 0x2000 },
+  { 0x0501, 0xd779, 0x0000 },
+  { 0x0501, 0xd77b, 0x0000 },
+  { 0x8501, 0xd780, 0x3000 },
+  { 0x8501, 0xd77e, 0x2000 },
+  { 0x0501, 0xd77d, 0x0000 },
+  { 0x0501, 0xd77f, 0x0000 },
+  { 0x8501, 0xd782, 0x2000 },
+  { 0x0501, 0xd781, 0x0000 },
+  { 0x0501, 0xd783, 0x0000 },
+  { 0x8501, 0xd78c, 0x4000 },
+  { 0x8501, 0xd788, 0x3000 },
+  { 0x8501, 0xd786, 0x2000 },
+  { 0x0501, 0xd785, 0x0000 },
+  { 0x0501, 0xd787, 0x0000 },
+  { 0x8501, 0xd78a, 0x2000 },
+  { 0x1901, 0xd789, 0x0000 },
+  { 0x0501, 0xd78b, 0x0000 },
+  { 0x8901, 0xd790, 0x3000 },
+  { 0x8501, 0xd78e, 0x2000 },
+  { 0x0501, 0xd78d, 0x0000 },
+  { 0x0501, 0xd78f, 0x0000 },
+  { 0x8901, 0xd792, 0x2000 },
+  { 0x0901, 0xd791, 0x0000 },
+  { 0x0901, 0xd793, 0x0000 },
+  { 0x8901, 0xd7a4, 0x5000 },
+  { 0x8901, 0xd79c, 0x4000 },
+  { 0x8901, 0xd798, 0x3000 },
+  { 0x8901, 0xd796, 0x2000 },
+  { 0x0901, 0xd795, 0x0000 },
+  { 0x0901, 0xd797, 0x0000 },
+  { 0x8901, 0xd79a, 0x2000 },
+  { 0x0901, 0xd799, 0x0000 },
+  { 0x0901, 0xd79b, 0x0000 },
+  { 0x8901, 0xd7a0, 0x3000 },
+  { 0x8901, 0xd79e, 0x2000 },
+  { 0x0901, 0xd79d, 0x0000 },
+  { 0x0901, 0xd79f, 0x0000 },
+  { 0x8901, 0xd7a2, 0x2000 },
+  { 0x0901, 0xd7a1, 0x0000 },
+  { 0x0901, 0xd7a3, 0x0000 },
+  { 0x8501, 0xd7ac, 0x4000 },
+  { 0x8901, 0xd7a8, 0x3000 },
+  { 0x8901, 0xd7a6, 0x2000 },
+  { 0x0901, 0xd7a5, 0x0000 },
+  { 0x0901, 0xd7a7, 0x0000 },
+  { 0x8501, 0xd7aa, 0x2000 },
+  { 0x1901, 0xd7a9, 0x0000 },
+  { 0x0501, 0xd7ab, 0x0000 },
+  { 0x8501, 0xd7b0, 0x3000 },
+  { 0x8501, 0xd7ae, 0x2000 },
+  { 0x0501, 0xd7ad, 0x0000 },
+  { 0x0501, 0xd7af, 0x0000 },
+  { 0x8501, 0xd7b2, 0x2000 },
+  { 0x0501, 0xd7b1, 0x0000 },
+  { 0x0501, 0xd7b3, 0x0000 },
+  { 0x8d01, 0xd7d8, 0x6000 },
+  { 0x8501, 0xd7c4, 0x5000 },
+  { 0x8501, 0xd7bc, 0x4000 },
+  { 0x8501, 0xd7b8, 0x3000 },
+  { 0x8501, 0xd7b6, 0x2000 },
+  { 0x0501, 0xd7b5, 0x0000 },
+  { 0x0501, 0xd7b7, 0x0000 },
+  { 0x8501, 0xd7ba, 0x2000 },
+  { 0x0501, 0xd7b9, 0x0000 },
+  { 0x0501, 0xd7bb, 0x0000 },
+  { 0x8501, 0xd7c0, 0x3000 },
+  { 0x8501, 0xd7be, 0x2000 },
+  { 0x0501, 0xd7bd, 0x0000 },
+  { 0x0501, 0xd7bf, 0x0000 },
+  { 0x8501, 0xd7c2, 0x2000 },
+  { 0x0501, 0xd7c1, 0x0000 },
+  { 0x1901, 0xd7c3, 0x0000 },
+  { 0x8d01, 0xd7d0, 0x4000 },
+  { 0x8501, 0xd7c8, 0x3000 },
+  { 0x8501, 0xd7c6, 0x2000 },
+  { 0x0501, 0xd7c5, 0x0000 },
+  { 0x0501, 0xd7c7, 0x0000 },
+  { 0x8d01, 0xd7ce, 0x2000 },
+  { 0x0501, 0xd7c9, 0x0000 },
+  { 0x0d01, 0xd7cf, 0x0000 },
+  { 0x8d01, 0xd7d4, 0x3000 },
+  { 0x8d01, 0xd7d2, 0x2000 },
+  { 0x0d01, 0xd7d1, 0x0000 },
+  { 0x0d01, 0xd7d3, 0x0000 },
+  { 0x8d01, 0xd7d6, 0x2000 },
+  { 0x0d01, 0xd7d5, 0x0000 },
+  { 0x0d01, 0xd7d7, 0x0000 },
+  { 0x8d01, 0xd7e8, 0x5000 },
+  { 0x8d01, 0xd7e0, 0x4000 },
+  { 0x8d01, 0xd7dc, 0x3000 },
+  { 0x8d01, 0xd7da, 0x2000 },
+  { 0x0d01, 0xd7d9, 0x0000 },
+  { 0x0d01, 0xd7db, 0x0000 },
+  { 0x8d01, 0xd7de, 0x2000 },
+  { 0x0d01, 0xd7dd, 0x0000 },
+  { 0x0d01, 0xd7df, 0x0000 },
+  { 0x8d01, 0xd7e4, 0x3000 },
+  { 0x8d01, 0xd7e2, 0x2000 },
+  { 0x0d01, 0xd7e1, 0x0000 },
+  { 0x0d01, 0xd7e3, 0x0000 },
+  { 0x8d01, 0xd7e6, 0x2000 },
+  { 0x0d01, 0xd7e5, 0x0000 },
+  { 0x0d01, 0xd7e7, 0x0000 },
+  { 0x8d01, 0xd7f0, 0x4000 },
+  { 0x8d01, 0xd7ec, 0x3000 },
+  { 0x8d01, 0xd7ea, 0x2000 },
+  { 0x0d01, 0xd7e9, 0x0000 },
+  { 0x0d01, 0xd7eb, 0x0000 },
+  { 0x8d01, 0xd7ee, 0x2000 },
+  { 0x0d01, 0xd7ed, 0x0000 },
+  { 0x0d01, 0xd7ef, 0x0000 },
+  { 0x8d01, 0xd7f4, 0x3000 },
+  { 0x8d01, 0xd7f2, 0x2000 },
+  { 0x0d01, 0xd7f1, 0x0000 },
+  { 0x0d01, 0xd7f3, 0x0000 },
+  { 0x8d01, 0xd7f6, 0x2000 },
+  { 0x0d01, 0xd7f5, 0x0000 },
+  { 0x0d01, 0xd7f7, 0x0000 },
+  { 0x8702, 0xf836, 0x7000 },
+  { 0x8702, 0xf816, 0x6000 },
+  { 0x8702, 0xf806, 0x5000 },
+  { 0x8702, 0x0000, 0x4000 },
+  { 0x8d01, 0xd7fc, 0x3000 },
+  { 0x8d01, 0xd7fa, 0x2000 },
+  { 0x0d01, 0xd7f9, 0x0000 },
+  { 0x0d01, 0xd7fb, 0x0000 },
+  { 0x8d01, 0xd7fe, 0x2000 },
+  { 0x0d01, 0xd7fd, 0x0000 },
+  { 0x0d01, 0xd7ff, 0x0000 },
+  { 0x8702, 0xf802, 0x3000 },
+  { 0x8702, 0xf800, 0x2000 },
+  { 0x0702, 0xa6d6, 0x0000 },
+  { 0x0702, 0xf801, 0x0000 },
+  { 0x8702, 0xf804, 0x2000 },
+  { 0x0702, 0xf803, 0x0000 },
+  { 0x0702, 0xf805, 0x0000 },
+  { 0x8702, 0xf80e, 0x4000 },
+  { 0x8702, 0xf80a, 0x3000 },
+  { 0x8702, 0xf808, 0x2000 },
+  { 0x0702, 0xf807, 0x0000 },
+  { 0x0702, 0xf809, 0x0000 },
+  { 0x8702, 0xf80c, 0x2000 },
+  { 0x0702, 0xf80b, 0x0000 },
+  { 0x0702, 0xf80d, 0x0000 },
+  { 0x8702, 0xf812, 0x3000 },
+  { 0x8702, 0xf810, 0x2000 },
+  { 0x0702, 0xf80f, 0x0000 },
+  { 0x0702, 0xf811, 0x0000 },
+  { 0x8702, 0xf814, 0x2000 },
+  { 0x0702, 0xf813, 0x0000 },
+  { 0x0702, 0xf815, 0x0000 },
+  { 0x8702, 0xf826, 0x5000 },
+  { 0x8702, 0xf81e, 0x4000 },
+  { 0x8702, 0xf81a, 0x3000 },
+  { 0x8702, 0xf818, 0x2000 },
+  { 0x0702, 0xf817, 0x0000 },
+  { 0x0702, 0xf819, 0x0000 },
+  { 0x8702, 0xf81c, 0x2000 },
+  { 0x0702, 0xf81b, 0x0000 },
+  { 0x0702, 0xf81d, 0x0000 },
+  { 0x8702, 0xf822, 0x3000 },
+  { 0x8702, 0xf820, 0x2000 },
+  { 0x0702, 0xf81f, 0x0000 },
+  { 0x0702, 0xf821, 0x0000 },
+  { 0x8702, 0xf824, 0x2000 },
+  { 0x0702, 0xf823, 0x0000 },
+  { 0x0702, 0xf825, 0x0000 },
+  { 0x8702, 0xf82e, 0x4000 },
+  { 0x8702, 0xf82a, 0x3000 },
+  { 0x8702, 0xf828, 0x2000 },
+  { 0x0702, 0xf827, 0x0000 },
+  { 0x0702, 0xf829, 0x0000 },
+  { 0x8702, 0xf82c, 0x2000 },
+  { 0x0702, 0xf82b, 0x0000 },
+  { 0x0702, 0xf82d, 0x0000 },
+  { 0x8702, 0xf832, 0x3000 },
+  { 0x8702, 0xf830, 0x2000 },
+  { 0x0702, 0xf82f, 0x0000 },
+  { 0x0702, 0xf831, 0x0000 },
+  { 0x8702, 0xf834, 0x2000 },
+  { 0x0702, 0xf833, 0x0000 },
+  { 0x0702, 0xf835, 0x0000 },
+  { 0x8702, 0xf856, 0x6000 },
+  { 0x8702, 0xf846, 0x5000 },
+  { 0x8702, 0xf83e, 0x4000 },
+  { 0x8702, 0xf83a, 0x3000 },
+  { 0x8702, 0xf838, 0x2000 },
+  { 0x0702, 0xf837, 0x0000 },
+  { 0x0702, 0xf839, 0x0000 },
+  { 0x8702, 0xf83c, 0x2000 },
+  { 0x0702, 0xf83b, 0x0000 },
+  { 0x0702, 0xf83d, 0x0000 },
+  { 0x8702, 0xf842, 0x3000 },
+  { 0x8702, 0xf840, 0x2000 },
+  { 0x0702, 0xf83f, 0x0000 },
+  { 0x0702, 0xf841, 0x0000 },
+  { 0x8702, 0xf844, 0x2000 },
+  { 0x0702, 0xf843, 0x0000 },
+  { 0x0702, 0xf845, 0x0000 },
+  { 0x8702, 0xf84e, 0x4000 },
+  { 0x8702, 0xf84a, 0x3000 },
+  { 0x8702, 0xf848, 0x2000 },
+  { 0x0702, 0xf847, 0x0000 },
+  { 0x0702, 0xf849, 0x0000 },
+  { 0x8702, 0xf84c, 0x2000 },
+  { 0x0702, 0xf84b, 0x0000 },
+  { 0x0702, 0xf84d, 0x0000 },
+  { 0x8702, 0xf852, 0x3000 },
+  { 0x8702, 0xf850, 0x2000 },
+  { 0x0702, 0xf84f, 0x0000 },
+  { 0x0702, 0xf851, 0x0000 },
+  { 0x8702, 0xf854, 0x2000 },
+  { 0x0702, 0xf853, 0x0000 },
+  { 0x0702, 0xf855, 0x0000 },
+  { 0x8702, 0xf866, 0x5000 },
+  { 0x8702, 0xf85e, 0x4000 },
+  { 0x8702, 0xf85a, 0x3000 },
+  { 0x8702, 0xf858, 0x2000 },
+  { 0x0702, 0xf857, 0x0000 },
+  { 0x0702, 0xf859, 0x0000 },
+  { 0x8702, 0xf85c, 0x2000 },
+  { 0x0702, 0xf85b, 0x0000 },
+  { 0x0702, 0xf85d, 0x0000 },
+  { 0x8702, 0xf862, 0x3000 },
+  { 0x8702, 0xf860, 0x2000 },
+  { 0x0702, 0xf85f, 0x0000 },
+  { 0x0702, 0xf861, 0x0000 },
+  { 0x8702, 0xf864, 0x2000 },
+  { 0x0702, 0xf863, 0x0000 },
+  { 0x0702, 0xf865, 0x0000 },
+  { 0x8702, 0xf86e, 0x4000 },
+  { 0x8702, 0xf86a, 0x3000 },
+  { 0x8702, 0xf868, 0x2000 },
+  { 0x0702, 0xf867, 0x0000 },
+  { 0x0702, 0xf869, 0x0000 },
+  { 0x8702, 0xf86c, 0x2000 },
+  { 0x0702, 0xf86b, 0x0000 },
+  { 0x0702, 0xf86d, 0x0000 },
+  { 0x8702, 0xf872, 0x3000 },
+  { 0x8702, 0xf870, 0x2000 },
+  { 0x0702, 0xf86f, 0x0000 },
+  { 0x0702, 0xf871, 0x0000 },
+  { 0x8702, 0xf874, 0x2000 },
+  { 0x0702, 0xf873, 0x0000 },
+  { 0x0702, 0xf875, 0x0000 },
+  { 0x8702, 0xf976, 0x9000 },
+  { 0x8702, 0xf8f6, 0x8000 },
+  { 0x8702, 0xf8b6, 0x7000 },
+  { 0x8702, 0xf896, 0x6000 },
+  { 0x8702, 0xf886, 0x5000 },
+  { 0x8702, 0xf87e, 0x4000 },
+  { 0x8702, 0xf87a, 0x3000 },
+  { 0x8702, 0xf878, 0x2000 },
+  { 0x0702, 0xf877, 0x0000 },
+  { 0x0702, 0xf879, 0x0000 },
+  { 0x8702, 0xf87c, 0x2000 },
+  { 0x0702, 0xf87b, 0x0000 },
+  { 0x0702, 0xf87d, 0x0000 },
+  { 0x8702, 0xf882, 0x3000 },
+  { 0x8702, 0xf880, 0x2000 },
+  { 0x0702, 0xf87f, 0x0000 },
+  { 0x0702, 0xf881, 0x0000 },
+  { 0x8702, 0xf884, 0x2000 },
+  { 0x0702, 0xf883, 0x0000 },
+  { 0x0702, 0xf885, 0x0000 },
+  { 0x8702, 0xf88e, 0x4000 },
+  { 0x8702, 0xf88a, 0x3000 },
+  { 0x8702, 0xf888, 0x2000 },
+  { 0x0702, 0xf887, 0x0000 },
+  { 0x0702, 0xf889, 0x0000 },
+  { 0x8702, 0xf88c, 0x2000 },
+  { 0x0702, 0xf88b, 0x0000 },
+  { 0x0702, 0xf88d, 0x0000 },
+  { 0x8702, 0xf892, 0x3000 },
+  { 0x8702, 0xf890, 0x2000 },
+  { 0x0702, 0xf88f, 0x0000 },
+  { 0x0702, 0xf891, 0x0000 },
+  { 0x8702, 0xf894, 0x2000 },
+  { 0x0702, 0xf893, 0x0000 },
+  { 0x0702, 0xf895, 0x0000 },
+  { 0x8702, 0xf8a6, 0x5000 },
+  { 0x8702, 0xf89e, 0x4000 },
+  { 0x8702, 0xf89a, 0x3000 },
+  { 0x8702, 0xf898, 0x2000 },
+  { 0x0702, 0xf897, 0x0000 },
+  { 0x0702, 0xf899, 0x0000 },
+  { 0x8702, 0xf89c, 0x2000 },
+  { 0x0702, 0xf89b, 0x0000 },
+  { 0x0702, 0xf89d, 0x0000 },
+  { 0x8702, 0xf8a2, 0x3000 },
+  { 0x8702, 0xf8a0, 0x2000 },
+  { 0x0702, 0xf89f, 0x0000 },
+  { 0x0702, 0xf8a1, 0x0000 },
+  { 0x8702, 0xf8a4, 0x2000 },
+  { 0x0702, 0xf8a3, 0x0000 },
+  { 0x0702, 0xf8a5, 0x0000 },
+  { 0x8702, 0xf8ae, 0x4000 },
+  { 0x8702, 0xf8aa, 0x3000 },
+  { 0x8702, 0xf8a8, 0x2000 },
+  { 0x0702, 0xf8a7, 0x0000 },
+  { 0x0702, 0xf8a9, 0x0000 },
+  { 0x8702, 0xf8ac, 0x2000 },
+  { 0x0702, 0xf8ab, 0x0000 },
+  { 0x0702, 0xf8ad, 0x0000 },
+  { 0x8702, 0xf8b2, 0x3000 },
+  { 0x8702, 0xf8b0, 0x2000 },
+  { 0x0702, 0xf8af, 0x0000 },
+  { 0x0702, 0xf8b1, 0x0000 },
+  { 0x8702, 0xf8b4, 0x2000 },
+  { 0x0702, 0xf8b3, 0x0000 },
+  { 0x0702, 0xf8b5, 0x0000 },
+  { 0x8702, 0xf8d6, 0x6000 },
+  { 0x8702, 0xf8c6, 0x5000 },
+  { 0x8702, 0xf8be, 0x4000 },
+  { 0x8702, 0xf8ba, 0x3000 },
+  { 0x8702, 0xf8b8, 0x2000 },
+  { 0x0702, 0xf8b7, 0x0000 },
+  { 0x0702, 0xf8b9, 0x0000 },
+  { 0x8702, 0xf8bc, 0x2000 },
+  { 0x0702, 0xf8bb, 0x0000 },
+  { 0x0702, 0xf8bd, 0x0000 },
+  { 0x8702, 0xf8c2, 0x3000 },
+  { 0x8702, 0xf8c0, 0x2000 },
+  { 0x0702, 0xf8bf, 0x0000 },
+  { 0x0702, 0xf8c1, 0x0000 },
+  { 0x8702, 0xf8c4, 0x2000 },
+  { 0x0702, 0xf8c3, 0x0000 },
+  { 0x0702, 0xf8c5, 0x0000 },
+  { 0x8702, 0xf8ce, 0x4000 },
+  { 0x8702, 0xf8ca, 0x3000 },
+  { 0x8702, 0xf8c8, 0x2000 },
+  { 0x0702, 0xf8c7, 0x0000 },
+  { 0x0702, 0xf8c9, 0x0000 },
+  { 0x8702, 0xf8cc, 0x2000 },
+  { 0x0702, 0xf8cb, 0x0000 },
+  { 0x0702, 0xf8cd, 0x0000 },
+  { 0x8702, 0xf8d2, 0x3000 },
+  { 0x8702, 0xf8d0, 0x2000 },
+  { 0x0702, 0xf8cf, 0x0000 },
+  { 0x0702, 0xf8d1, 0x0000 },
+  { 0x8702, 0xf8d4, 0x2000 },
+  { 0x0702, 0xf8d3, 0x0000 },
+  { 0x0702, 0xf8d5, 0x0000 },
+  { 0x8702, 0xf8e6, 0x5000 },
+  { 0x8702, 0xf8de, 0x4000 },
+  { 0x8702, 0xf8da, 0x3000 },
+  { 0x8702, 0xf8d8, 0x2000 },
+  { 0x0702, 0xf8d7, 0x0000 },
+  { 0x0702, 0xf8d9, 0x0000 },
+  { 0x8702, 0xf8dc, 0x2000 },
+  { 0x0702, 0xf8db, 0x0000 },
+  { 0x0702, 0xf8dd, 0x0000 },
+  { 0x8702, 0xf8e2, 0x3000 },
+  { 0x8702, 0xf8e0, 0x2000 },
+  { 0x0702, 0xf8df, 0x0000 },
+  { 0x0702, 0xf8e1, 0x0000 },
+  { 0x8702, 0xf8e4, 0x2000 },
+  { 0x0702, 0xf8e3, 0x0000 },
+  { 0x0702, 0xf8e5, 0x0000 },
+  { 0x8702, 0xf8ee, 0x4000 },
+  { 0x8702, 0xf8ea, 0x3000 },
+  { 0x8702, 0xf8e8, 0x2000 },
+  { 0x0702, 0xf8e7, 0x0000 },
+  { 0x0702, 0xf8e9, 0x0000 },
+  { 0x8702, 0xf8ec, 0x2000 },
+  { 0x0702, 0xf8eb, 0x0000 },
+  { 0x0702, 0xf8ed, 0x0000 },
+  { 0x8702, 0xf8f2, 0x3000 },
+  { 0x8702, 0xf8f0, 0x2000 },
+  { 0x0702, 0xf8ef, 0x0000 },
+  { 0x0702, 0xf8f1, 0x0000 },
+  { 0x8702, 0xf8f4, 0x2000 },
+  { 0x0702, 0xf8f3, 0x0000 },
+  { 0x0702, 0xf8f5, 0x0000 },
+  { 0x8702, 0xf936, 0x7000 },
+  { 0x8702, 0xf916, 0x6000 },
+  { 0x8702, 0xf906, 0x5000 },
+  { 0x8702, 0xf8fe, 0x4000 },
+  { 0x8702, 0xf8fa, 0x3000 },
+  { 0x8702, 0xf8f8, 0x2000 },
+  { 0x0702, 0xf8f7, 0x0000 },
+  { 0x0702, 0xf8f9, 0x0000 },
+  { 0x8702, 0xf8fc, 0x2000 },
+  { 0x0702, 0xf8fb, 0x0000 },
+  { 0x0702, 0xf8fd, 0x0000 },
+  { 0x8702, 0xf902, 0x3000 },
+  { 0x8702, 0xf900, 0x2000 },
+  { 0x0702, 0xf8ff, 0x0000 },
+  { 0x0702, 0xf901, 0x0000 },
+  { 0x8702, 0xf904, 0x2000 },
+  { 0x0702, 0xf903, 0x0000 },
+  { 0x0702, 0xf905, 0x0000 },
+  { 0x8702, 0xf90e, 0x4000 },
+  { 0x8702, 0xf90a, 0x3000 },
+  { 0x8702, 0xf908, 0x2000 },
+  { 0x0702, 0xf907, 0x0000 },
+  { 0x0702, 0xf909, 0x0000 },
+  { 0x8702, 0xf90c, 0x2000 },
+  { 0x0702, 0xf90b, 0x0000 },
+  { 0x0702, 0xf90d, 0x0000 },
+  { 0x8702, 0xf912, 0x3000 },
+  { 0x8702, 0xf910, 0x2000 },
+  { 0x0702, 0xf90f, 0x0000 },
+  { 0x0702, 0xf911, 0x0000 },
+  { 0x8702, 0xf914, 0x2000 },
+  { 0x0702, 0xf913, 0x0000 },
+  { 0x0702, 0xf915, 0x0000 },
+  { 0x8702, 0xf926, 0x5000 },
+  { 0x8702, 0xf91e, 0x4000 },
+  { 0x8702, 0xf91a, 0x3000 },
+  { 0x8702, 0xf918, 0x2000 },
+  { 0x0702, 0xf917, 0x0000 },
+  { 0x0702, 0xf919, 0x0000 },
+  { 0x8702, 0xf91c, 0x2000 },
+  { 0x0702, 0xf91b, 0x0000 },
+  { 0x0702, 0xf91d, 0x0000 },
+  { 0x8702, 0xf922, 0x3000 },
+  { 0x8702, 0xf920, 0x2000 },
+  { 0x0702, 0xf91f, 0x0000 },
+  { 0x0702, 0xf921, 0x0000 },
+  { 0x8702, 0xf924, 0x2000 },
+  { 0x0702, 0xf923, 0x0000 },
+  { 0x0702, 0xf925, 0x0000 },
+  { 0x8702, 0xf92e, 0x4000 },
+  { 0x8702, 0xf92a, 0x3000 },
+  { 0x8702, 0xf928, 0x2000 },
+  { 0x0702, 0xf927, 0x0000 },
+  { 0x0702, 0xf929, 0x0000 },
+  { 0x8702, 0xf92c, 0x2000 },
+  { 0x0702, 0xf92b, 0x0000 },
+  { 0x0702, 0xf92d, 0x0000 },
+  { 0x8702, 0xf932, 0x3000 },
+  { 0x8702, 0xf930, 0x2000 },
+  { 0x0702, 0xf92f, 0x0000 },
+  { 0x0702, 0xf931, 0x0000 },
+  { 0x8702, 0xf934, 0x2000 },
+  { 0x0702, 0xf933, 0x0000 },
+  { 0x0702, 0xf935, 0x0000 },
+  { 0x8702, 0xf956, 0x6000 },
+  { 0x8702, 0xf946, 0x5000 },
+  { 0x8702, 0xf93e, 0x4000 },
+  { 0x8702, 0xf93a, 0x3000 },
+  { 0x8702, 0xf938, 0x2000 },
+  { 0x0702, 0xf937, 0x0000 },
+  { 0x0702, 0xf939, 0x0000 },
+  { 0x8702, 0xf93c, 0x2000 },
+  { 0x0702, 0xf93b, 0x0000 },
+  { 0x0702, 0xf93d, 0x0000 },
+  { 0x8702, 0xf942, 0x3000 },
+  { 0x8702, 0xf940, 0x2000 },
+  { 0x0702, 0xf93f, 0x0000 },
+  { 0x0702, 0xf941, 0x0000 },
+  { 0x8702, 0xf944, 0x2000 },
+  { 0x0702, 0xf943, 0x0000 },
+  { 0x0702, 0xf945, 0x0000 },
+  { 0x8702, 0xf94e, 0x4000 },
+  { 0x8702, 0xf94a, 0x3000 },
+  { 0x8702, 0xf948, 0x2000 },
+  { 0x0702, 0xf947, 0x0000 },
+  { 0x0702, 0xf949, 0x0000 },
+  { 0x8702, 0xf94c, 0x2000 },
+  { 0x0702, 0xf94b, 0x0000 },
+  { 0x0702, 0xf94d, 0x0000 },
+  { 0x8702, 0xf952, 0x3000 },
+  { 0x8702, 0xf950, 0x2000 },
+  { 0x0702, 0xf94f, 0x0000 },
+  { 0x0702, 0xf951, 0x0000 },
+  { 0x8702, 0xf954, 0x2000 },
+  { 0x0702, 0xf953, 0x0000 },
+  { 0x0702, 0xf955, 0x0000 },
+  { 0x8702, 0xf966, 0x5000 },
+  { 0x8702, 0xf95e, 0x4000 },
+  { 0x8702, 0xf95a, 0x3000 },
+  { 0x8702, 0xf958, 0x2000 },
+  { 0x0702, 0xf957, 0x0000 },
+  { 0x0702, 0xf959, 0x0000 },
+  { 0x8702, 0xf95c, 0x2000 },
+  { 0x0702, 0xf95b, 0x0000 },
+  { 0x0702, 0xf95d, 0x0000 },
+  { 0x8702, 0xf962, 0x3000 },
+  { 0x8702, 0xf960, 0x2000 },
+  { 0x0702, 0xf95f, 0x0000 },
+  { 0x0702, 0xf961, 0x0000 },
+  { 0x8702, 0xf964, 0x2000 },
+  { 0x0702, 0xf963, 0x0000 },
+  { 0x0702, 0xf965, 0x0000 },
+  { 0x8702, 0xf96e, 0x4000 },
+  { 0x8702, 0xf96a, 0x3000 },
+  { 0x8702, 0xf968, 0x2000 },
+  { 0x0702, 0xf967, 0x0000 },
+  { 0x0702, 0xf969, 0x0000 },
+  { 0x8702, 0xf96c, 0x2000 },
+  { 0x0702, 0xf96b, 0x0000 },
+  { 0x0702, 0xf96d, 0x0000 },
+  { 0x8702, 0xf972, 0x3000 },
+  { 0x8702, 0xf970, 0x2000 },
+  { 0x0702, 0xf96f, 0x0000 },
+  { 0x0702, 0xf971, 0x0000 },
+  { 0x8702, 0xf974, 0x2000 },
+  { 0x0702, 0xf973, 0x0000 },
+  { 0x0702, 0xf975, 0x0000 },
+  { 0x810e, 0x0077, 0x9000 },
+  { 0x8702, 0xf9f6, 0x8000 },
+  { 0x8702, 0xf9b6, 0x7000 },
+  { 0x8702, 0xf996, 0x6000 },
+  { 0x8702, 0xf986, 0x5000 },
+  { 0x8702, 0xf97e, 0x4000 },
+  { 0x8702, 0xf97a, 0x3000 },
+  { 0x8702, 0xf978, 0x2000 },
+  { 0x0702, 0xf977, 0x0000 },
+  { 0x0702, 0xf979, 0x0000 },
+  { 0x8702, 0xf97c, 0x2000 },
+  { 0x0702, 0xf97b, 0x0000 },
+  { 0x0702, 0xf97d, 0x0000 },
+  { 0x8702, 0xf982, 0x3000 },
+  { 0x8702, 0xf980, 0x2000 },
+  { 0x0702, 0xf97f, 0x0000 },
+  { 0x0702, 0xf981, 0x0000 },
+  { 0x8702, 0xf984, 0x2000 },
+  { 0x0702, 0xf983, 0x0000 },
+  { 0x0702, 0xf985, 0x0000 },
+  { 0x8702, 0xf98e, 0x4000 },
+  { 0x8702, 0xf98a, 0x3000 },
+  { 0x8702, 0xf988, 0x2000 },
+  { 0x0702, 0xf987, 0x0000 },
+  { 0x0702, 0xf989, 0x0000 },
+  { 0x8702, 0xf98c, 0x2000 },
+  { 0x0702, 0xf98b, 0x0000 },
+  { 0x0702, 0xf98d, 0x0000 },
+  { 0x8702, 0xf992, 0x3000 },
+  { 0x8702, 0xf990, 0x2000 },
+  { 0x0702, 0xf98f, 0x0000 },
+  { 0x0702, 0xf991, 0x0000 },
+  { 0x8702, 0xf994, 0x2000 },
+  { 0x0702, 0xf993, 0x0000 },
+  { 0x0702, 0xf995, 0x0000 },
+  { 0x8702, 0xf9a6, 0x5000 },
+  { 0x8702, 0xf99e, 0x4000 },
+  { 0x8702, 0xf99a, 0x3000 },
+  { 0x8702, 0xf998, 0x2000 },
+  { 0x0702, 0xf997, 0x0000 },
+  { 0x0702, 0xf999, 0x0000 },
+  { 0x8702, 0xf99c, 0x2000 },
+  { 0x0702, 0xf99b, 0x0000 },
+  { 0x0702, 0xf99d, 0x0000 },
+  { 0x8702, 0xf9a2, 0x3000 },
+  { 0x8702, 0xf9a0, 0x2000 },
+  { 0x0702, 0xf99f, 0x0000 },
+  { 0x0702, 0xf9a1, 0x0000 },
+  { 0x8702, 0xf9a4, 0x2000 },
+  { 0x0702, 0xf9a3, 0x0000 },
+  { 0x0702, 0xf9a5, 0x0000 },
+  { 0x8702, 0xf9ae, 0x4000 },
+  { 0x8702, 0xf9aa, 0x3000 },
+  { 0x8702, 0xf9a8, 0x2000 },
+  { 0x0702, 0xf9a7, 0x0000 },
+  { 0x0702, 0xf9a9, 0x0000 },
+  { 0x8702, 0xf9ac, 0x2000 },
+  { 0x0702, 0xf9ab, 0x0000 },
+  { 0x0702, 0xf9ad, 0x0000 },
+  { 0x8702, 0xf9b2, 0x3000 },
+  { 0x8702, 0xf9b0, 0x2000 },
+  { 0x0702, 0xf9af, 0x0000 },
+  { 0x0702, 0xf9b1, 0x0000 },
+  { 0x8702, 0xf9b4, 0x2000 },
+  { 0x0702, 0xf9b3, 0x0000 },
+  { 0x0702, 0xf9b5, 0x0000 },
+  { 0x8702, 0xf9d6, 0x6000 },
+  { 0x8702, 0xf9c6, 0x5000 },
+  { 0x8702, 0xf9be, 0x4000 },
+  { 0x8702, 0xf9ba, 0x3000 },
+  { 0x8702, 0xf9b8, 0x2000 },
+  { 0x0702, 0xf9b7, 0x0000 },
+  { 0x0702, 0xf9b9, 0x0000 },
+  { 0x8702, 0xf9bc, 0x2000 },
+  { 0x0702, 0xf9bb, 0x0000 },
+  { 0x0702, 0xf9bd, 0x0000 },
+  { 0x8702, 0xf9c2, 0x3000 },
+  { 0x8702, 0xf9c0, 0x2000 },
+  { 0x0702, 0xf9bf, 0x0000 },
+  { 0x0702, 0xf9c1, 0x0000 },
+  { 0x8702, 0xf9c4, 0x2000 },
+  { 0x0702, 0xf9c3, 0x0000 },
+  { 0x0702, 0xf9c5, 0x0000 },
+  { 0x8702, 0xf9ce, 0x4000 },
+  { 0x8702, 0xf9ca, 0x3000 },
+  { 0x8702, 0xf9c8, 0x2000 },
+  { 0x0702, 0xf9c7, 0x0000 },
+  { 0x0702, 0xf9c9, 0x0000 },
+  { 0x8702, 0xf9cc, 0x2000 },
+  { 0x0702, 0xf9cb, 0x0000 },
+  { 0x0702, 0xf9cd, 0x0000 },
+  { 0x8702, 0xf9d2, 0x3000 },
+  { 0x8702, 0xf9d0, 0x2000 },
+  { 0x0702, 0xf9cf, 0x0000 },
+  { 0x0702, 0xf9d1, 0x0000 },
+  { 0x8702, 0xf9d4, 0x2000 },
+  { 0x0702, 0xf9d3, 0x0000 },
+  { 0x0702, 0xf9d5, 0x0000 },
+  { 0x8702, 0xf9e6, 0x5000 },
+  { 0x8702, 0xf9de, 0x4000 },
+  { 0x8702, 0xf9da, 0x3000 },
+  { 0x8702, 0xf9d8, 0x2000 },
+  { 0x0702, 0xf9d7, 0x0000 },
+  { 0x0702, 0xf9d9, 0x0000 },
+  { 0x8702, 0xf9dc, 0x2000 },
+  { 0x0702, 0xf9db, 0x0000 },
+  { 0x0702, 0xf9dd, 0x0000 },
+  { 0x8702, 0xf9e2, 0x3000 },
+  { 0x8702, 0xf9e0, 0x2000 },
+  { 0x0702, 0xf9df, 0x0000 },
+  { 0x0702, 0xf9e1, 0x0000 },
+  { 0x8702, 0xf9e4, 0x2000 },
+  { 0x0702, 0xf9e3, 0x0000 },
+  { 0x0702, 0xf9e5, 0x0000 },
+  { 0x8702, 0xf9ee, 0x4000 },
+  { 0x8702, 0xf9ea, 0x3000 },
+  { 0x8702, 0xf9e8, 0x2000 },
+  { 0x0702, 0xf9e7, 0x0000 },
+  { 0x0702, 0xf9e9, 0x0000 },
+  { 0x8702, 0xf9ec, 0x2000 },
+  { 0x0702, 0xf9eb, 0x0000 },
+  { 0x0702, 0xf9ed, 0x0000 },
+  { 0x8702, 0xf9f2, 0x3000 },
+  { 0x8702, 0xf9f0, 0x2000 },
+  { 0x0702, 0xf9ef, 0x0000 },
+  { 0x0702, 0xf9f1, 0x0000 },
+  { 0x8702, 0xf9f4, 0x2000 },
+  { 0x0702, 0xf9f3, 0x0000 },
+  { 0x0702, 0xf9f5, 0x0000 },
+  { 0x810e, 0x0037, 0x7000 },
+  { 0x8702, 0xfa16, 0x6000 },
+  { 0x8702, 0xfa06, 0x5000 },
+  { 0x8702, 0xf9fe, 0x4000 },
+  { 0x8702, 0xf9fa, 0x3000 },
+  { 0x8702, 0xf9f8, 0x2000 },
+  { 0x0702, 0xf9f7, 0x0000 },
+  { 0x0702, 0xf9f9, 0x0000 },
+  { 0x8702, 0xf9fc, 0x2000 },
+  { 0x0702, 0xf9fb, 0x0000 },
+  { 0x0702, 0xf9fd, 0x0000 },
+  { 0x8702, 0xfa02, 0x3000 },
+  { 0x8702, 0xfa00, 0x2000 },
+  { 0x0702, 0xf9ff, 0x0000 },
+  { 0x0702, 0xfa01, 0x0000 },
+  { 0x8702, 0xfa04, 0x2000 },
+  { 0x0702, 0xfa03, 0x0000 },
+  { 0x0702, 0xfa05, 0x0000 },
+  { 0x8702, 0xfa0e, 0x4000 },
+  { 0x8702, 0xfa0a, 0x3000 },
+  { 0x8702, 0xfa08, 0x2000 },
+  { 0x0702, 0xfa07, 0x0000 },
+  { 0x0702, 0xfa09, 0x0000 },
+  { 0x8702, 0xfa0c, 0x2000 },
+  { 0x0702, 0xfa0b, 0x0000 },
+  { 0x0702, 0xfa0d, 0x0000 },
+  { 0x8702, 0xfa12, 0x3000 },
+  { 0x8702, 0xfa10, 0x2000 },
+  { 0x0702, 0xfa0f, 0x0000 },
+  { 0x0702, 0xfa11, 0x0000 },
+  { 0x8702, 0xfa14, 0x2000 },
+  { 0x0702, 0xfa13, 0x0000 },
+  { 0x0702, 0xfa15, 0x0000 },
+  { 0x810e, 0x0027, 0x5000 },
+  { 0x810e, 0x0001, 0x4000 },
+  { 0x8702, 0xfa1a, 0x3000 },
+  { 0x8702, 0xfa18, 0x2000 },
+  { 0x0702, 0xfa17, 0x0000 },
+  { 0x0702, 0xfa19, 0x0000 },
+  { 0x8702, 0xfa1c, 0x2000 },
+  { 0x0702, 0xfa1b, 0x0000 },
+  { 0x0702, 0xfa1d, 0x0000 },
+  { 0x810e, 0x0023, 0x3000 },
+  { 0x810e, 0x0021, 0x2000 },
+  { 0x010e, 0x0020, 0x0000 },
+  { 0x010e, 0x0022, 0x0000 },
+  { 0x810e, 0x0025, 0x2000 },
+  { 0x010e, 0x0024, 0x0000 },
+  { 0x010e, 0x0026, 0x0000 },
+  { 0x810e, 0x002f, 0x4000 },
+  { 0x810e, 0x002b, 0x3000 },
+  { 0x810e, 0x0029, 0x2000 },
+  { 0x010e, 0x0028, 0x0000 },
+  { 0x010e, 0x002a, 0x0000 },
+  { 0x810e, 0x002d, 0x2000 },
+  { 0x010e, 0x002c, 0x0000 },
+  { 0x010e, 0x002e, 0x0000 },
+  { 0x810e, 0x0033, 0x3000 },
+  { 0x810e, 0x0031, 0x2000 },
+  { 0x010e, 0x0030, 0x0000 },
+  { 0x010e, 0x0032, 0x0000 },
+  { 0x810e, 0x0035, 0x2000 },
+  { 0x010e, 0x0034, 0x0000 },
+  { 0x010e, 0x0036, 0x0000 },
+  { 0x810e, 0x0057, 0x6000 },
+  { 0x810e, 0x0047, 0x5000 },
+  { 0x810e, 0x003f, 0x4000 },
+  { 0x810e, 0x003b, 0x3000 },
+  { 0x810e, 0x0039, 0x2000 },
+  { 0x010e, 0x0038, 0x0000 },
+  { 0x010e, 0x003a, 0x0000 },
+  { 0x810e, 0x003d, 0x2000 },
+  { 0x010e, 0x003c, 0x0000 },
+  { 0x010e, 0x003e, 0x0000 },
+  { 0x810e, 0x0043, 0x3000 },
+  { 0x810e, 0x0041, 0x2000 },
+  { 0x010e, 0x0040, 0x0000 },
+  { 0x010e, 0x0042, 0x0000 },
+  { 0x810e, 0x0045, 0x2000 },
+  { 0x010e, 0x0044, 0x0000 },
+  { 0x010e, 0x0046, 0x0000 },
+  { 0x810e, 0x004f, 0x4000 },
+  { 0x810e, 0x004b, 0x3000 },
+  { 0x810e, 0x0049, 0x2000 },
+  { 0x010e, 0x0048, 0x0000 },
+  { 0x010e, 0x004a, 0x0000 },
+  { 0x810e, 0x004d, 0x2000 },
+  { 0x010e, 0x004c, 0x0000 },
+  { 0x010e, 0x004e, 0x0000 },
+  { 0x810e, 0x0053, 0x3000 },
+  { 0x810e, 0x0051, 0x2000 },
+  { 0x010e, 0x0050, 0x0000 },
+  { 0x010e, 0x0052, 0x0000 },
+  { 0x810e, 0x0055, 0x2000 },
+  { 0x010e, 0x0054, 0x0000 },
+  { 0x010e, 0x0056, 0x0000 },
+  { 0x810e, 0x0067, 0x5000 },
+  { 0x810e, 0x005f, 0x4000 },
+  { 0x810e, 0x005b, 0x3000 },
+  { 0x810e, 0x0059, 0x2000 },
+  { 0x010e, 0x0058, 0x0000 },
+  { 0x010e, 0x005a, 0x0000 },
+  { 0x810e, 0x005d, 0x2000 },
+  { 0x010e, 0x005c, 0x0000 },
+  { 0x010e, 0x005e, 0x0000 },
+  { 0x810e, 0x0063, 0x3000 },
+  { 0x810e, 0x0061, 0x2000 },
+  { 0x010e, 0x0060, 0x0000 },
+  { 0x010e, 0x0062, 0x0000 },
+  { 0x810e, 0x0065, 0x2000 },
+  { 0x010e, 0x0064, 0x0000 },
+  { 0x010e, 0x0066, 0x0000 },
+  { 0x810e, 0x006f, 0x4000 },
+  { 0x810e, 0x006b, 0x3000 },
+  { 0x810e, 0x0069, 0x2000 },
+  { 0x010e, 0x0068, 0x0000 },
+  { 0x010e, 0x006a, 0x0000 },
+  { 0x810e, 0x006d, 0x2000 },
+  { 0x010e, 0x006c, 0x0000 },
+  { 0x010e, 0x006e, 0x0000 },
+  { 0x810e, 0x0073, 0x3000 },
+  { 0x810e, 0x0071, 0x2000 },
+  { 0x010e, 0x0070, 0x0000 },
+  { 0x010e, 0x0072, 0x0000 },
+  { 0x810e, 0x0075, 0x2000 },
+  { 0x010e, 0x0074, 0x0000 },
+  { 0x010e, 0x0076, 0x0000 },
+  { 0x8c0e, 0x0177, 0x8000 },
+  { 0x8c0e, 0x0137, 0x7000 },
+  { 0x8c0e, 0x0117, 0x6000 },
+  { 0x8c0e, 0x0107, 0x5000 },
+  { 0x810e, 0x007f, 0x4000 },
+  { 0x810e, 0x007b, 0x3000 },
+  { 0x810e, 0x0079, 0x2000 },
+  { 0x010e, 0x0078, 0x0000 },
+  { 0x010e, 0x007a, 0x0000 },
+  { 0x810e, 0x007d, 0x2000 },
+  { 0x010e, 0x007c, 0x0000 },
+  { 0x010e, 0x007e, 0x0000 },
+  { 0x8c0e, 0x0103, 0x3000 },
+  { 0x8c0e, 0x0101, 0x2000 },
+  { 0x0c0e, 0x0100, 0x0000 },
+  { 0x0c0e, 0x0102, 0x0000 },
+  { 0x8c0e, 0x0105, 0x2000 },
+  { 0x0c0e, 0x0104, 0x0000 },
+  { 0x0c0e, 0x0106, 0x0000 },
+  { 0x8c0e, 0x010f, 0x4000 },
+  { 0x8c0e, 0x010b, 0x3000 },
+  { 0x8c0e, 0x0109, 0x2000 },
+  { 0x0c0e, 0x0108, 0x0000 },
+  { 0x0c0e, 0x010a, 0x0000 },
+  { 0x8c0e, 0x010d, 0x2000 },
+  { 0x0c0e, 0x010c, 0x0000 },
+  { 0x0c0e, 0x010e, 0x0000 },
+  { 0x8c0e, 0x0113, 0x3000 },
+  { 0x8c0e, 0x0111, 0x2000 },
+  { 0x0c0e, 0x0110, 0x0000 },
+  { 0x0c0e, 0x0112, 0x0000 },
+  { 0x8c0e, 0x0115, 0x2000 },
+  { 0x0c0e, 0x0114, 0x0000 },
+  { 0x0c0e, 0x0116, 0x0000 },
+  { 0x8c0e, 0x0127, 0x5000 },
+  { 0x8c0e, 0x011f, 0x4000 },
+  { 0x8c0e, 0x011b, 0x3000 },
+  { 0x8c0e, 0x0119, 0x2000 },
+  { 0x0c0e, 0x0118, 0x0000 },
+  { 0x0c0e, 0x011a, 0x0000 },
+  { 0x8c0e, 0x011d, 0x2000 },
+  { 0x0c0e, 0x011c, 0x0000 },
+  { 0x0c0e, 0x011e, 0x0000 },
+  { 0x8c0e, 0x0123, 0x3000 },
+  { 0x8c0e, 0x0121, 0x2000 },
+  { 0x0c0e, 0x0120, 0x0000 },
+  { 0x0c0e, 0x0122, 0x0000 },
+  { 0x8c0e, 0x0125, 0x2000 },
+  { 0x0c0e, 0x0124, 0x0000 },
+  { 0x0c0e, 0x0126, 0x0000 },
+  { 0x8c0e, 0x012f, 0x4000 },
+  { 0x8c0e, 0x012b, 0x3000 },
+  { 0x8c0e, 0x0129, 0x2000 },
+  { 0x0c0e, 0x0128, 0x0000 },
+  { 0x0c0e, 0x012a, 0x0000 },
+  { 0x8c0e, 0x012d, 0x2000 },
+  { 0x0c0e, 0x012c, 0x0000 },
+  { 0x0c0e, 0x012e, 0x0000 },
+  { 0x8c0e, 0x0133, 0x3000 },
+  { 0x8c0e, 0x0131, 0x2000 },
+  { 0x0c0e, 0x0130, 0x0000 },
+  { 0x0c0e, 0x0132, 0x0000 },
+  { 0x8c0e, 0x0135, 0x2000 },
+  { 0x0c0e, 0x0134, 0x0000 },
+  { 0x0c0e, 0x0136, 0x0000 },
+  { 0x8c0e, 0x0157, 0x6000 },
+  { 0x8c0e, 0x0147, 0x5000 },
+  { 0x8c0e, 0x013f, 0x4000 },
+  { 0x8c0e, 0x013b, 0x3000 },
+  { 0x8c0e, 0x0139, 0x2000 },
+  { 0x0c0e, 0x0138, 0x0000 },
+  { 0x0c0e, 0x013a, 0x0000 },
+  { 0x8c0e, 0x013d, 0x2000 },
+  { 0x0c0e, 0x013c, 0x0000 },
+  { 0x0c0e, 0x013e, 0x0000 },
+  { 0x8c0e, 0x0143, 0x3000 },
+  { 0x8c0e, 0x0141, 0x2000 },
+  { 0x0c0e, 0x0140, 0x0000 },
+  { 0x0c0e, 0x0142, 0x0000 },
+  { 0x8c0e, 0x0145, 0x2000 },
+  { 0x0c0e, 0x0144, 0x0000 },
+  { 0x0c0e, 0x0146, 0x0000 },
+  { 0x8c0e, 0x014f, 0x4000 },
+  { 0x8c0e, 0x014b, 0x3000 },
+  { 0x8c0e, 0x0149, 0x2000 },
+  { 0x0c0e, 0x0148, 0x0000 },
+  { 0x0c0e, 0x014a, 0x0000 },
+  { 0x8c0e, 0x014d, 0x2000 },
+  { 0x0c0e, 0x014c, 0x0000 },
+  { 0x0c0e, 0x014e, 0x0000 },
+  { 0x8c0e, 0x0153, 0x3000 },
+  { 0x8c0e, 0x0151, 0x2000 },
+  { 0x0c0e, 0x0150, 0x0000 },
+  { 0x0c0e, 0x0152, 0x0000 },
+  { 0x8c0e, 0x0155, 0x2000 },
+  { 0x0c0e, 0x0154, 0x0000 },
+  { 0x0c0e, 0x0156, 0x0000 },
+  { 0x8c0e, 0x0167, 0x5000 },
+  { 0x8c0e, 0x015f, 0x4000 },
+  { 0x8c0e, 0x015b, 0x3000 },
+  { 0x8c0e, 0x0159, 0x2000 },
+  { 0x0c0e, 0x0158, 0x0000 },
+  { 0x0c0e, 0x015a, 0x0000 },
+  { 0x8c0e, 0x015d, 0x2000 },
+  { 0x0c0e, 0x015c, 0x0000 },
+  { 0x0c0e, 0x015e, 0x0000 },
+  { 0x8c0e, 0x0163, 0x3000 },
+  { 0x8c0e, 0x0161, 0x2000 },
+  { 0x0c0e, 0x0160, 0x0000 },
+  { 0x0c0e, 0x0162, 0x0000 },
+  { 0x8c0e, 0x0165, 0x2000 },
+  { 0x0c0e, 0x0164, 0x0000 },
+  { 0x0c0e, 0x0166, 0x0000 },
+  { 0x8c0e, 0x016f, 0x4000 },
+  { 0x8c0e, 0x016b, 0x3000 },
+  { 0x8c0e, 0x0169, 0x2000 },
+  { 0x0c0e, 0x0168, 0x0000 },
+  { 0x0c0e, 0x016a, 0x0000 },
+  { 0x8c0e, 0x016d, 0x2000 },
+  { 0x0c0e, 0x016c, 0x0000 },
+  { 0x0c0e, 0x016e, 0x0000 },
+  { 0x8c0e, 0x0173, 0x3000 },
+  { 0x8c0e, 0x0171, 0x2000 },
+  { 0x0c0e, 0x0170, 0x0000 },
+  { 0x0c0e, 0x0172, 0x0000 },
+  { 0x8c0e, 0x0175, 0x2000 },
+  { 0x0c0e, 0x0174, 0x0000 },
+  { 0x0c0e, 0x0176, 0x0000 },
+  { 0x8c0e, 0x01b7, 0x7000 },
+  { 0x8c0e, 0x0197, 0x6000 },
+  { 0x8c0e, 0x0187, 0x5000 },
+  { 0x8c0e, 0x017f, 0x4000 },
+  { 0x8c0e, 0x017b, 0x3000 },
+  { 0x8c0e, 0x0179, 0x2000 },
+  { 0x0c0e, 0x0178, 0x0000 },
+  { 0x0c0e, 0x017a, 0x0000 },
+  { 0x8c0e, 0x017d, 0x2000 },
+  { 0x0c0e, 0x017c, 0x0000 },
+  { 0x0c0e, 0x017e, 0x0000 },
+  { 0x8c0e, 0x0183, 0x3000 },
+  { 0x8c0e, 0x0181, 0x2000 },
+  { 0x0c0e, 0x0180, 0x0000 },
+  { 0x0c0e, 0x0182, 0x0000 },
+  { 0x8c0e, 0x0185, 0x2000 },
+  { 0x0c0e, 0x0184, 0x0000 },
+  { 0x0c0e, 0x0186, 0x0000 },
+  { 0x8c0e, 0x018f, 0x4000 },
+  { 0x8c0e, 0x018b, 0x3000 },
+  { 0x8c0e, 0x0189, 0x2000 },
+  { 0x0c0e, 0x0188, 0x0000 },
+  { 0x0c0e, 0x018a, 0x0000 },
+  { 0x8c0e, 0x018d, 0x2000 },
+  { 0x0c0e, 0x018c, 0x0000 },
+  { 0x0c0e, 0x018e, 0x0000 },
+  { 0x8c0e, 0x0193, 0x3000 },
+  { 0x8c0e, 0x0191, 0x2000 },
+  { 0x0c0e, 0x0190, 0x0000 },
+  { 0x0c0e, 0x0192, 0x0000 },
+  { 0x8c0e, 0x0195, 0x2000 },
+  { 0x0c0e, 0x0194, 0x0000 },
+  { 0x0c0e, 0x0196, 0x0000 },
+  { 0x8c0e, 0x01a7, 0x5000 },
+  { 0x8c0e, 0x019f, 0x4000 },
+  { 0x8c0e, 0x019b, 0x3000 },
+  { 0x8c0e, 0x0199, 0x2000 },
+  { 0x0c0e, 0x0198, 0x0000 },
+  { 0x0c0e, 0x019a, 0x0000 },
+  { 0x8c0e, 0x019d, 0x2000 },
+  { 0x0c0e, 0x019c, 0x0000 },
+  { 0x0c0e, 0x019e, 0x0000 },
+  { 0x8c0e, 0x01a3, 0x3000 },
+  { 0x8c0e, 0x01a1, 0x2000 },
+  { 0x0c0e, 0x01a0, 0x0000 },
+  { 0x0c0e, 0x01a2, 0x0000 },
+  { 0x8c0e, 0x01a5, 0x2000 },
+  { 0x0c0e, 0x01a4, 0x0000 },
+  { 0x0c0e, 0x01a6, 0x0000 },
+  { 0x8c0e, 0x01af, 0x4000 },
+  { 0x8c0e, 0x01ab, 0x3000 },
+  { 0x8c0e, 0x01a9, 0x2000 },
+  { 0x0c0e, 0x01a8, 0x0000 },
+  { 0x0c0e, 0x01aa, 0x0000 },
+  { 0x8c0e, 0x01ad, 0x2000 },
+  { 0x0c0e, 0x01ac, 0x0000 },
+  { 0x0c0e, 0x01ae, 0x0000 },
+  { 0x8c0e, 0x01b3, 0x3000 },
+  { 0x8c0e, 0x01b1, 0x2000 },
+  { 0x0c0e, 0x01b0, 0x0000 },
+  { 0x0c0e, 0x01b2, 0x0000 },
+  { 0x8c0e, 0x01b5, 0x2000 },
+  { 0x0c0e, 0x01b4, 0x0000 },
+  { 0x0c0e, 0x01b6, 0x0000 },
+  { 0x8c0e, 0x01d7, 0x6000 },
+  { 0x8c0e, 0x01c7, 0x5000 },
+  { 0x8c0e, 0x01bf, 0x4000 },
+  { 0x8c0e, 0x01bb, 0x3000 },
+  { 0x8c0e, 0x01b9, 0x2000 },
+  { 0x0c0e, 0x01b8, 0x0000 },
+  { 0x0c0e, 0x01ba, 0x0000 },
+  { 0x8c0e, 0x01bd, 0x2000 },
+  { 0x0c0e, 0x01bc, 0x0000 },
+  { 0x0c0e, 0x01be, 0x0000 },
+  { 0x8c0e, 0x01c3, 0x3000 },
+  { 0x8c0e, 0x01c1, 0x2000 },
+  { 0x0c0e, 0x01c0, 0x0000 },
+  { 0x0c0e, 0x01c2, 0x0000 },
+  { 0x8c0e, 0x01c5, 0x2000 },
+  { 0x0c0e, 0x01c4, 0x0000 },
+  { 0x0c0e, 0x01c6, 0x0000 },
+  { 0x8c0e, 0x01cf, 0x4000 },
+  { 0x8c0e, 0x01cb, 0x3000 },
+  { 0x8c0e, 0x01c9, 0x2000 },
+  { 0x0c0e, 0x01c8, 0x0000 },
+  { 0x0c0e, 0x01ca, 0x0000 },
+  { 0x8c0e, 0x01cd, 0x2000 },
+  { 0x0c0e, 0x01cc, 0x0000 },
+  { 0x0c0e, 0x01ce, 0x0000 },
+  { 0x8c0e, 0x01d3, 0x3000 },
+  { 0x8c0e, 0x01d1, 0x2000 },
+  { 0x0c0e, 0x01d0, 0x0000 },
+  { 0x0c0e, 0x01d2, 0x0000 },
+  { 0x8c0e, 0x01d5, 0x2000 },
+  { 0x0c0e, 0x01d4, 0x0000 },
+  { 0x0c0e, 0x01d6, 0x0000 },
+  { 0x8c0e, 0x01e7, 0x5000 },
+  { 0x8c0e, 0x01df, 0x4000 },
+  { 0x8c0e, 0x01db, 0x3000 },
+  { 0x8c0e, 0x01d9, 0x2000 },
+  { 0x0c0e, 0x01d8, 0x0000 },
+  { 0x0c0e, 0x01da, 0x0000 },
+  { 0x8c0e, 0x01dd, 0x2000 },
+  { 0x0c0e, 0x01dc, 0x0000 },
+  { 0x0c0e, 0x01de, 0x0000 },
+  { 0x8c0e, 0x01e3, 0x3000 },
+  { 0x8c0e, 0x01e1, 0x2000 },
+  { 0x0c0e, 0x01e0, 0x0000 },
+  { 0x0c0e, 0x01e2, 0x0000 },
+  { 0x8c0e, 0x01e5, 0x2000 },
+  { 0x0c0e, 0x01e4, 0x0000 },
+  { 0x0c0e, 0x01e6, 0x0000 },
+  { 0x8c0e, 0x01ef, 0x4000 },
+  { 0x8c0e, 0x01eb, 0x3000 },
+  { 0x8c0e, 0x01e9, 0x2000 },
+  { 0x0c0e, 0x01e8, 0x0000 },
+  { 0x0c0e, 0x01ea, 0x0000 },
+  { 0x8c0e, 0x01ed, 0x2000 },
+  { 0x0c0e, 0x01ec, 0x0000 },
+  { 0x0c0e, 0x01ee, 0x0000 },
+  { 0x830f, 0xfffd, 0x2000 },
+  { 0x030f, 0x0000, 0x0000 },
+  { 0x0310, 0x0000, 0x1000 },
+  { 0x0310, 0xfffd, 0x0000 },
+};

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/ucptypetable.c
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/ucptypetable.c	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/iis/pcre/ucptypetable.c	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,93 @@
+/*************************************************
+*      Perl-Compatible Regular Expressions       *
+*************************************************/
+
+/*
+This is a library of functions to support regular expressions whose syntax
+and semantics are as close as possible to those of the Perl 5 language. See
+the file Tech.Notes for some information on the internals.
+
+Written by: Philip Hazel <ph10 at cam.ac.uk>
+
+           Copyright (c) 1997-2004 University of Cambridge
+
+-----------------------------------------------------------------------------
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice,
+      this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+
+    * Neither the name of the University of Cambridge nor the names of its
+      contributors may be used to endorse or promote products derived from
+      this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+-----------------------------------------------------------------------------
+*/
+
+/* This module contains a table for translating Unicode property names into
+code values for the ucp_findchar function. It is in a separate module so that
+it can be included both in the main pcre library, and into pcretest (for
+printing out internals). */
+
+typedef struct {
+  const char *name;
+  int value;
+} ucp_type_table;
+
+static ucp_type_table utt[] = {
+  { "C",  128 + ucp_C },
+  { "Cc", ucp_Cc },
+  { "Cf", ucp_Cf },
+  { "Cn", ucp_Cn },
+  { "Co", ucp_Co },
+  { "Cs", ucp_Cs },
+  { "L",  128 + ucp_L },
+  { "Ll", ucp_Ll },
+  { "Lm", ucp_Lm },
+  { "Lo", ucp_Lo },
+  { "Lt", ucp_Lt },
+  { "Lu", ucp_Lu },
+  { "M",  128 + ucp_M },
+  { "Mc", ucp_Mc },
+  { "Me", ucp_Me },
+  { "Mn", ucp_Mn },
+  { "N",  128 + ucp_N },
+  { "Nd", ucp_Nd },
+  { "Nl", ucp_Nl },
+  { "No", ucp_No },
+  { "P",  128 + ucp_P },
+  { "Pc", ucp_Pc },
+  { "Pd", ucp_Pd },
+  { "Pe", ucp_Pe },
+  { "Pf", ucp_Pf },
+  { "Pi", ucp_Pi },
+  { "Po", ucp_Po },
+  { "Ps", ucp_Ps },
+  { "S",  128 + ucp_S },
+  { "Sc", ucp_Sc },
+  { "Sk", ucp_Sk },
+  { "Sm", ucp_Sm },
+  { "So", ucp_So },
+  { "Z",  128 + ucp_Z },
+  { "Zl", ucp_Zl },
+  { "Zp", ucp_Zp },
+  { "Zs", ucp_Zs }
+};
+
+/* End of ucptypetable.c */

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/jni/Makefile.in
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/jni/Makefile.in	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/jni/Makefile.in	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,30 @@
+OEXT=.lo
+include @APACHE_CONFIG_VARS@
+
+JK=../common/
+COMMON_OBJECTS=${JK}jk_map${OEXT} ${JK}jk_util${OEXT} ${JK}jk_pool${OEXT}
+JNI_OBJECTS=jk_jnicb${OEXT} ${COMMON_OBJECTS}
+
+
+JAVA_INCL=-I @JAVA_HOME@/include -I @JAVA_HOME@/include/@OS@ -I../common
+CFLAGS=@apache_include@ @CFLAGS@ ${JAVA_INCL} -D_REENTRANT 
+
+include ../scripts/build/rules.mk
+
+all: Makefile jni_connect.so 
+
+Makefile: Makefile.in
+	echo Regenerating Makefile
+	( cd ..; ./config.status )
+
+jk_jnicb.la: ${JNI_OBJECTS}
+	$(LIBTOOL) --mode=link $(COMPILE) -module -o $@ -rpath `pwd` -g -O2 -avoid-version ${JNI_OBJECTS} 
+
+jni_connect.so: jk_jnicb.la
+	$(LIBTOOL) --mode=install cp $< `pwd`/jni_connect.so
+
+install:
+
+clean:
+	rm -f *.o *.lo *.a *.la *.so *.so.* *.slo
+	rm -rf .libs

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/jni/Makefile.linux
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/jni/Makefile.linux	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/jni/Makefile.linux	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,31 @@
+# Defines for example NSAPI programs running under SOLARIS
+
+CC_CMD=gcc -D_REENTRANT
+LD_SHAREDCMD=ld -G
+
+all:
+
+prepare:
+
+OS_TYPE=linux
+INCLUDEDIR=../common
+JAVA_INCLUDE=$(JAVA_HOME)/include
+
+JK_OBJS =  ../common/jk_map.o ../common/jk_util.o ../common/jk_pool.o jk_jnicb.o
+
+INCLUDE_FLAGS=-I$(INCLUDEDIR) -I$(JAVA_INCLUDE) -I$(JAVA_INCLUDE)/$(OS_TYPE)
+COMMON_DEFS=
+
+
+all: jni_connect.so 
+
+
+jni_connect.so: $(JK_OBJS)
+#	$(MAKE) prepare
+	$(LD_SHAREDCMD) $(JK_OBJS) -o jni_connect.so $(EXTRA_LDDEFINES)
+
+.c.o:
+	$(CC_CMD) $(COMMON_DEFS) $(INCLUDE_FLAGS) -c $< 
+
+clean:
+	rm $(JK_OBJS)

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/jni/Makefile.netware
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/jni/Makefile.netware	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/jni/Makefile.netware	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,241 @@
+#
+# Makefile for jk_nsapi_plugin (NetWare version - gnu make)
+# created by Guenter Knauf <eflash at gmx.net>
+#
+
+# Edit the path below to point to the base of your Netscape includes.
+ifndef NS_HOME
+NS_HOME	= c:/projects/sdks/netscape
+endif
+# Edit the path below to point to the base of your NetWare Java SDK.
+ifndef NW_JDK
+NW_JDK	= c:/projects/sdks/java-nw
+endif
+# Edit the path below to point to the base of your Novell NDK.
+ifndef NDKBASE
+NDKBASE	= c:/novell
+endif
+INSTDIR = /mnt/sys/novonyx/modules
+
+# Edit the vars below to change NLM target settings.
+TARGET  = jni_conn
+VERSION	= $(JK_VERSION)
+COPYR	= Copyright (c) 2000-2004 The Apache Software Foundation. All rights reserved.
+DESCR	= JNI natives for Tomcat $(JK_VERSION_STR)
+MTSAFE	= NO
+STACK	= 64000
+#SCREEN	= System Console
+MODULES	= nsapi
+EXPORTS	= \
+	Java_org_apache_tomcat_modules_server_JNIConnectionHandler_write \
+	Java_org_apache_tomcat_modules_server_JNIConnectionHandler_startReasponse \
+	Java_org_apache_tomcat_modules_server_JNIConnectionHandler_readHeaders \
+	Java_org_apache_tomcat_modules_server_JNIConnectionHandler_readEnvironment \
+	Java_org_apache_tomcat_modules_server_JNIConnectionHandler_read \
+	Java_org_apache_tomcat_modules_server_JNIConnectionHandler_getNumberOfHeaders
+
+#IMPORTS	= __nsapi30_table
+
+# Edit the var below to point to your lib architecture.
+ifndef LIBARCH
+LIBARCH = CLIB
+# LIBARCH = LIBC
+endif
+
+# must be equal to DEBUG or NDEBUG
+DB	= NDEBUG
+# DB	= DEBUG
+# Optimization: -O<n> or debugging: -g
+ifeq ($(DB),NDEBUG)
+	OPT	= -O2
+	OBJDIR	= release
+else
+	OPT	= -g
+	OBJDIR	= debug
+endif
+
+# Include the version info retrieved from jk_version.h
+-include $(OBJDIR)/version.inc
+
+# The following line defines your compiler.
+ifdef METROWERKS
+	CC = mwccnlm
+else
+	CC = gcc
+endif
+# RM	= rm -f
+# CP	= cp -fv
+# if you want to mark the target as MTSAFE you will need a tool for
+# generating the xdc data for the linker; here's a minimal tool:
+# http://www.gknw.com/development/prgtools/mkxdc.zip
+MPKXDC	= mkxdc
+
+# Global flags for all compilers
+CFLAGS	= $(OPT) -D$(DB) -DNETWARE -DXP_NETWARE -nostdinc
+
+ifeq ($(CC),mwccnlm)
+LD	= mwldnlm
+LDFLAGS	= -nostdlib $(PRELUDE) $(OBJDIR)/*.o -o $(OBJDIR)/$(TARGET).nlm -commandfile
+CFLAGS	+= -gccinc -inline off -opt nointrinsics
+#CFLAGS	+= -w on
+ifeq ($(LIBARCH),LIBC)
+	PRELUDE = $(SDK_LIBC)/imports/libcpre.o
+	CFLAGS += -align 4 -inst mmx -proc 686
+#	CFLAGS += -D__ANSIC__
+else
+	PRELUDE = "$(METROWERKS)/Novell Support/libraries/runtime/prelude.obj"
+#	CFLAGS += -include "$(METROWERKS)/Novell Support/headers/nlm_prefix.h"
+	CFLAGS += -align 1 -proc 586
+endif
+else
+LD	= nlmconv
+LDFLAGS	= -T
+CFLAGS	+= -fno-builtin -fpack-struct -fpcc-struct-return
+CFLAGS	+= -Wall -Wno-main # -pedantic
+ifeq ($(LIBARCH),LIBC)
+	PRELUDE = $(SDK_LIBC)/imports/libcpre.gcc.o
+#	CFLAGS += -D__ANSIC__
+else
+	PRELUDE = $(SDK_CLIB)/imports/clibpre.gcc.o
+	CFLAGS += -include $(NDKBASE)/nlmconv/genlm.h
+endif
+endif
+
+LDLIBS	=
+
+NDK_ROOT = $(NDKBASE)/ndk
+SDK_CLIB = $(NDK_ROOT)/nwsdk
+SDK_LIBC = $(NDK_ROOT)/libc
+JKCOMMON = ../common
+
+INCLUDES = -I$(NS_HOME)/include -I$(NS_HOME)/include/base
+INCLUDES += -I$(JKCOMMON) -I$(NW_JDK)/include -I$(NW_JDK)/include/netware 
+
+ifeq ($(LIBARCH),LIBC)
+	INCLUDES += -I$(SDK_LIBC)/include -I$(SDK_LIBC)/include/nks
+	INCLUDES += -I$(SDK_LIBC)/include/winsock
+else
+	INCLUDES += -I$(SDK_CLIB)/include/nlm -I$(SDK_CLIB)/include
+	INCLUDES += -I$(SDK_CLIB)/include/nlm/obsolete
+	CFLAGS += -DNETDB_USE_INTERNET
+endif
+CFLAGS	+= $(INCLUDES)
+
+ifeq ($(MTSAFE),YES)
+	XDCDATA = $(OBJDIR)/$(TARGET).xdc
+endif
+
+ifeq ($(findstring linux,$(OSTYPE)),linux)
+DL	= '
+#-include $(NDKBASE)/nlmconv/ncpfs.inc
+endif
+
+OBJS	= \
+	$(OBJDIR)/jk_nwmain.o \
+	$(OBJDIR)/jk_map.o \
+	$(OBJDIR)/jk_pool.o \
+	$(OBJDIR)/jk_util.o \
+	$(OBJDIR)/jk_jnicb.o
+
+
+all: $(OBJDIR) $(OBJDIR)/version.inc $(OBJDIR)/$(TARGET).nlm 
+
+$(OBJDIR)/%.o: %.c
+	@echo Compiling $<
+	@$(CC) $(CFLAGS) -c $< -o $@
+
+$(OBJDIR)/%.o: $(JKCOMMON)/%.c
+	@echo Compiling $<
+	@$(CC) $(CFLAGS) -c $< -o $@
+
+$(OBJDIR)/version.inc: $(JKCOMMON)/jk_version.h $(OBJDIR)
+	@echo Creating $@
+	@awk -f ../../support/get_ver.awk $< > $@
+
+dist: all
+	-$(RM) $(OBJDIR)/*.o $(OBJDIR)/$(TARGET).map $(OBJDIR)/$(TARGET).ncv
+	-$(RM) $(OBJDIR)/$(TARGET).def $(OBJDIR)/version.inc $(XDCDATA)
+#	-$(CP) ../changes.txt $(OBJDIR)/
+
+install: all
+	@[ -d $(INSTDIR) ] || mkdir $(INSTDIR)
+	@$(CP) $(TARGET).nlm $(INSTDIR)
+
+clean:
+	-$(RM) -r $(OBJDIR)
+
+$(OBJDIR):
+	@mkdir $(OBJDIR)
+
+$(OBJDIR)/$(TARGET).nlm: $(OBJS) $(OBJDIR)/$(TARGET).def $(XDCDATA)
+	@echo Linking $@
+	@-$(RM) $@
+	@$(LD) $(LDFLAGS) $(OBJDIR)/$(TARGET).def
+
+$(OBJDIR)/%.xdc: Makefile.netware
+	@echo Creating $@
+	@$(MPKXDC) $(XDCOPT) $@
+
+$(OBJDIR)/%.def: Makefile.netware
+	@echo $(DL)# DEF file for linking with $(LD)$(DL) > $@
+	@echo $(DL)# Do not edit this file - it is created by make!$(DL) >> $@
+	@echo $(DL)# All your changes will be lost!!$(DL) >> $@
+	@echo $(DL)#$(DL) >> $@
+	@echo $(DL)copyright "$(COPYR)"$(DL) >> $@
+	@echo $(DL)description "$(DESCR)"$(DL) >> $@
+	@echo $(DL)version $(VERSION)$(DL) >> $@
+ifdef NLMTYPE
+	@echo $(DL)type $(NLMTYPE)$(DL) >> $@
+endif
+ifdef STACK
+	@echo $(DL)stack $(STACK)$(DL) >> $@
+endif
+ifdef SCREEN
+	@echo $(DL)screenname "$(SCREEN)"$(DL) >> $@
+else
+	@echo $(DL)screenname "DEFAULT"$(DL) >> $@
+endif
+ifeq ($(DB),DEBUG)
+	@echo $(DL)debug$(DL) >> $@
+endif
+	@echo $(DL)threadname "$(TARGET)"$(DL) >> $@
+ifdef XDCDATA
+	@echo $(DL)xdcdata $(XDCDATA)$(DL) >> $@
+endif
+ifeq ($(LIBARCH),CLIB)
+	@echo $(DL)start _Prelude$(DL) >> $@
+	@echo $(DL)exit _Stop$(DL) >> $@
+	@echo $(DL)import @$(NDK_ROOT)/nwsdk/imports/clib.imp$(DL) >> $@
+	@echo $(DL)import @$(NDK_ROOT)/nwsdk/imports/threads.imp$(DL) >> $@
+	@echo $(DL)import @$(NDK_ROOT)/nwsdk/imports/nlmlib.imp$(DL) >> $@
+	@echo $(DL)import @$(NDK_ROOT)/nwsdk/imports/socklib.imp$(DL) >> $@
+	@echo $(DL)module clib$(DL) >> $@
+else
+ifeq ($(LD),nlmconv)
+	@echo $(DL)flag_on 64$(DL) >> $@
+else
+	@echo $(DL)autounload$(DL) >> $@
+endif
+	@echo $(DL)pseudopreemption$(DL) >> $@
+	@echo $(DL)start _LibCPrelude$(DL) >> $@
+	@echo $(DL)exit _LibCPostlude$(DL) >> $@
+	@echo $(DL)check _LibCCheckUnload$(DL) >> $@
+	@echo $(DL)import @$(NDK_ROOT)/libc/imports/libc.imp$(DL) >> $@
+	@echo $(DL)import @$(NDK_ROOT)/libc/imports/netware.imp$(DL) >> $@
+	@echo $(DL)module libc$(DL) >> $@
+endif
+ifdef MODULES
+	@echo $(DL)module $(MODULES)$(DL) >> $@
+endif
+ifdef EXPORTS
+	@echo $(DL)export $(EXPORTS)$(DL) >> $@
+endif
+ifdef IMPORTS
+	@echo $(DL)import $(IMPORTS)$(DL) >> $@
+endif
+ifeq ($(LD),nlmconv)
+	@echo $(DL)input $(OBJS)$(DL) >> $@
+	@echo $(DL)input $(PRELUDE)$(DL) >> $@
+	@echo $(DL)output $(TARGET).nlm$(DL) >> $@
+endif
+

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/jni/Makefile.solaris
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/jni/Makefile.solaris	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/jni/Makefile.solaris	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,30 @@
+# Defines for example NSAPI programs running under SOLARIS
+
+CC_CMD=gcc -DSOLARIS -D_REENTRANT
+LD_SHAREDCMD=ld -G
+
+all:
+prepare:
+
+OS_TYPE=solaris
+INCLUDEDIR=../common
+JAVA_INCLUDE=$(JAVA_HOME)/include
+
+JK_OBJS =  ../common/jk_map.o ../common/jk_util.o ../common/jk_pool.o jk_jnicb.o
+
+INCLUDE_FLAGS=-I$(INCLUDEDIR) -I$(JAVA_INCLUDE) -I$(JAVA_INCLUDE)/$(OS_TYPE)
+COMMON_DEFS=
+
+
+all: jni_connect.so 
+
+
+jni_connect.so: $(JK_OBJS)
+	$(MAKE) prepare
+	$(LD_SHAREDCMD) $(JK_OBJS) -o jni_connect.so $(EXTRA_LDDEFINES)
+
+.c.o:
+	$(CC_CMD) $(COMMON_DEFS) $(INCLUDE_FLAGS) -c $< 
+
+clean:
+	rm $(JK_OBJS)

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/jni/jk_jnicb.c
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/jni/jk_jnicb.c	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/jni/jk_jnicb.c	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,494 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.
+ */
+
+/***************************************************************************
+ * Description: JNI callbacks implementation for the JNI in process adapter*
+ * Author:      Gal Shachor <shachor at il.ibm.com>                           *
+ * Version:     $Revision: 299830 $                                           *
+ ***************************************************************************/
+
+#include "jk_jnicb.h"
+#include "jk_service.h"
+#include "jk_util.h"
+#include "jk_pool.h"
+
+/*
+ * Class:     org_apache_tomcat_modules_server_JNIConnectionHandler
+ * Method:    getNumberOfHeaders
+ * Signature: (JJ)I
+ */
+JNIEXPORT jint JNICALL
+    Java_org_apache_tomcat_modules_server_JNIConnectionHandler_getNumberOfHeaders
+    (JNIEnv * env, jobject o, jlong s, jlong l)
+{
+    /* [V] Convert indirectly from jlong -> int -> pointer to shut up gcc */
+    /*     I hope it's okay on other compilers and/or machines...         */
+    jk_ws_service_t *ps = (jk_ws_service_t *)(int)s;
+    jk_logger_t *pl = (jk_logger_t *)(int)l;
+
+    jk_log(pl, JK_LOG_DEBUG,
+           "Into JNIConnectionHandler::getNumberOfHeaders\n");
+
+    if (!ps) {
+        jk_log(pl, JK_LOG_ERROR,
+               "In JNIConnectionHandler::getNumberOfHeaders, NULL ws service object\n");
+        /* [V] JNIConnectionHandler doesn't handle this */
+        return -1;
+    }
+
+    jk_log(pl, JK_LOG_DEBUG,
+           "Done JNIConnectionHandler::getNumberOfHeaders, found %d headers\n",
+           ps->num_headers);
+    return (jint) ps->num_headers;
+}
+
+/*
+ * Class:     org_apache_tomcat_modules_server_JNIConnectionHandler
+ * Method:    read
+ * Signature: (JJ[BII)I
+ */
+JNIEXPORT jint JNICALL
+    Java_org_apache_tomcat_modules_server_JNIConnectionHandler_read
+    (JNIEnv * env, jobject o, jlong s, jlong l, jbyteArray buf, jint from,
+     jint cnt)
+{
+    jk_ws_service_t *ps = (jk_ws_service_t *)(int)s;
+    jk_logger_t *pl = (jk_logger_t *)(int)l;
+    jint rc = -1;
+    jboolean iscommit;
+    jbyte *nbuf;
+    unsigned nfrom = (unsigned)from;
+    unsigned ncnt = (unsigned)cnt;
+    unsigned acc = 0;
+
+    jk_log(pl, JK_LOG_DEBUG, "Into JNIConnectionHandler::read\n");
+
+    if (!ps) {
+        jk_log(pl, JK_LOG_ERROR,
+               "In JNIConnectionHandler::read, NULL ws service object\n");
+        return -1;
+    }
+
+    nbuf = (*env)->GetByteArrayElements(env, buf, &iscommit);
+
+    if (!nbuf) {
+        jk_log(pl, JK_LOG_ERROR,
+               "In JNIConnectionHandler::read, GetByteArrayElements error\n");
+        return -1;
+    }
+
+    if (!ps->read(ps, nbuf + nfrom, ncnt, &acc)) {
+        jk_log(pl, JK_LOG_ERROR,
+               "In JNIConnectionHandler::read, failed to read from web server\n");
+    }
+    else {
+        rc = (jint) acc;
+    }
+
+    (*env)->ReleaseByteArrayElements(env, buf, nbuf, 0);
+
+    jk_log(pl, JK_LOG_DEBUG, "Done JNIConnectionHandler::read\n");
+    return rc;
+}
+
+/*
+ * Class:     org_apache_tomcat_modules_server_JNIConnectionHandler
+ * Method:    readEnvironment
+ * Signature: (JJ[Ljava/lang/String;)I
+ */
+JNIEXPORT jint JNICALL
+    Java_org_apache_tomcat_modules_server_JNIConnectionHandler_readEnvironment
+    (JNIEnv * env, jobject o, jlong s, jlong l, jobjectArray envbuf)
+{
+    jk_ws_service_t *ps = (jk_ws_service_t *)(int)s;
+    jk_logger_t *pl = (jk_logger_t *)(int)l;
+    char port[10];
+
+    jk_log(pl, JK_LOG_DEBUG,
+           "Into JNIConnectionHandler::readEnvironment. Environment follows --->\n");
+
+    if (!ps) {
+        jk_log(pl, JK_LOG_ERROR,
+               "In JNIConnectionHandler::readEnvironment, NULL ws service object\n");
+        return JK_FALSE;
+    }
+
+    sprintf(port, "%d", ps->server_port);
+
+    if (ps->method) {
+        (*env)->SetObjectArrayElement(env,
+                                      envbuf,
+                                      0,
+                                      (*env)->NewStringUTF(env, ps->method));
+        jk_log(pl, JK_LOG_DEBUG, "---> method: %s\n", ps->method);
+    }
+    if (ps->req_uri) {
+        (*env)->SetObjectArrayElement(env,
+                                      envbuf,
+                                      1,
+                                      (*env)->NewStringUTF(env, ps->req_uri));
+        jk_log(pl, JK_LOG_DEBUG, "---> req_uri: %s\n", ps->req_uri);
+    }
+    if (ps->query_string) {
+        (*env)->SetObjectArrayElement(env,
+                                      envbuf,
+                                      2,
+                                      (*env)->NewStringUTF(env,
+                                                           ps->query_string));
+        jk_log(pl, JK_LOG_DEBUG, "---> query_string: %s\n", ps->query_string);
+    }
+    if (ps->remote_addr) {
+        (*env)->SetObjectArrayElement(env,
+                                      envbuf,
+                                      3,
+                                      (*env)->NewStringUTF(env,
+                                                           ps->remote_addr));
+        jk_log(pl, JK_LOG_DEBUG, "---> remote_addr: %s\n", ps->remote_addr);
+    }
+    if (ps->remote_host) {
+        (*env)->SetObjectArrayElement(env,
+                                      envbuf,
+                                      4,
+                                      (*env)->NewStringUTF(env,
+                                                           ps->remote_host));
+        jk_log(pl, JK_LOG_DEBUG, "---> remote_host: %s\n", ps->remote_host);
+    }
+    if (ps->server_name) {
+        (*env)->SetObjectArrayElement(env,
+                                      envbuf,
+                                      5,
+                                      (*env)->NewStringUTF(env,
+                                                           ps->server_name));
+        jk_log(pl, JK_LOG_DEBUG, "---> server_name: %s\n", ps->server_name);
+    }
+
+    (*env)->SetObjectArrayElement(env,
+                                  envbuf, 6, (*env)->NewStringUTF(env, port));
+    jk_log(pl, JK_LOG_DEBUG, "---> server_port: %s\n", port);
+
+    if (ps->auth_type) {
+        (*env)->SetObjectArrayElement(env,
+                                      envbuf,
+                                      7,
+                                      (*env)->NewStringUTF(env,
+                                                           ps->auth_type));
+        jk_log(pl, JK_LOG_DEBUG, "---> auth_type: %s\n", ps->auth_type);
+    }
+    if (ps->remote_user) {
+        (*env)->SetObjectArrayElement(env,
+                                      envbuf,
+                                      8,
+                                      (*env)->NewStringUTF(env,
+                                                           ps->remote_user));
+        jk_log(pl, JK_LOG_DEBUG, "---> remote_user: %s\n", ps->remote_user);
+    }
+    if (ps->is_ssl) {
+        (*env)->SetObjectArrayElement(env,
+                                      envbuf,
+                                      9, (*env)->NewStringUTF(env, "https"));
+    }
+    else {
+        (*env)->SetObjectArrayElement(env,
+                                      envbuf,
+                                      9, (*env)->NewStringUTF(env, "http"));
+    }
+    jk_log(pl, JK_LOG_DEBUG, "---> is_ssl: %s\n", ps->is_ssl ? "yes" : "no");
+
+    if (ps->protocol) {
+        (*env)->SetObjectArrayElement(env,
+                                      envbuf,
+                                      10,
+                                      (*env)->NewStringUTF(env,
+                                                           ps->protocol));
+        jk_log(pl, JK_LOG_DEBUG, "---> protocol: %s\n", ps->protocol);
+    }
+    if (ps->server_software) {
+        (*env)->SetObjectArrayElement(env,
+                                      envbuf,
+                                      11,
+                                      (*env)->NewStringUTF(env,
+                                                           ps->
+                                                           server_software));
+        jk_log(pl, JK_LOG_DEBUG, "---> server_software: %s\n",
+               ps->server_software);
+    }
+    if (ps->is_ssl) {
+        if (ps->ssl_cert) {
+            (*env)->SetObjectArrayElement(env,
+                                          envbuf,
+                                          12,
+                                          (*env)->NewStringUTF(env,
+                                                               ps->ssl_cert));
+            jk_log(pl, JK_LOG_DEBUG, "---> ssl_cert: %s\n", ps->ssl_cert);
+        }
+
+        if (ps->ssl_cipher) {
+            (*env)->SetObjectArrayElement(env,
+                                          envbuf,
+                                          13,
+                                          (*env)->NewStringUTF(env,
+                                                               ps->
+                                                               ssl_cipher));
+            jk_log(pl, JK_LOG_DEBUG, "---> ssl_cipher: %s\n", ps->ssl_cipher);
+        }
+
+        if (ps->ssl_session) {
+            (*env)->SetObjectArrayElement(env,
+                                          envbuf,
+                                          14,
+                                          (*env)->NewStringUTF(env,
+                                                               ps->
+                                                               ssl_session));
+            jk_log(pl, JK_LOG_DEBUG, "---> ssl_session: %s\n",
+                   ps->ssl_session);
+        }
+    }
+
+    jk_log(pl, JK_LOG_DEBUG, "Done JNIConnectionHandler::readEnvironment\n");
+
+
+    return JK_TRUE;
+}
+
+/*
+ * Class:     org_apache_tomcat_modules_server_JNIConnectionHandler
+ * Method:    readHeaders
+ * Signature: (JJ[Ljava/lang/String;[Ljava/lang/String;)I
+ */
+JNIEXPORT jint JNICALL
+    Java_org_apache_tomcat_modules_server_JNIConnectionHandler_readHeaders
+    (JNIEnv * env, jobject o, jlong s, jlong l, jobjectArray hnames,
+     jobjectArray hvalues)
+{
+    jk_ws_service_t *ps = (jk_ws_service_t *)(int)s;
+    jk_logger_t *pl = (jk_logger_t *)(int)l;
+    unsigned i;
+
+    jk_log(pl, JK_LOG_DEBUG, "Into JNIConnectionHandler::readHeaders\n");
+
+    if (!ps) {
+        jk_log(pl, JK_LOG_ERROR,
+               "In JNIConnectionHandler::readHeaders, NULL ws service object\n");
+        return JK_FALSE;
+    }
+
+    jk_log(pl, JK_LOG_DEBUG,
+           "In JNIConnectionHandler::readHeaders, %d headers follow --->\n",
+           ps->num_headers);
+
+    for (i = 0; i < ps->num_headers; i++) {
+        (*env)->SetObjectArrayElement(env,
+                                      hnames,
+                                      i,
+                                      (*env)->NewStringUTF(env,
+                                                           ps->
+                                                           headers_names[i]));
+        (*env)->SetObjectArrayElement(env, hvalues, i,
+                                      (*env)->NewStringUTF(env,
+                                                           ps->
+                                                           headers_values
+                                                           [i]));
+        jk_log(pl, JK_LOG_DEBUG, "---> %s = %s\n", ps->headers_names[i],
+               ps->headers_values[i]);
+    }
+    jk_log(pl, JK_LOG_DEBUG, "Done JNIConnectionHandler::readHeaders\n");
+
+    return JK_TRUE;
+}
+
+/*
+ * Class:     org_apache_tomcat_modules_server_JNIConnectionHandler
+ * Method:    startReasponse
+ * Signature: (JJILjava/lang/String;[Ljava/lang/String;[Ljava/lang/String;I)I
+ */
+JNIEXPORT jint JNICALL
+    Java_org_apache_tomcat_modules_server_JNIConnectionHandler_startReasponse
+    (JNIEnv * env, jobject o, jlong s, jlong l,
+     jint sc, jstring msg, jobjectArray hnames, jobjectArray hvalues,
+     jint hcnt)
+{
+    jk_ws_service_t *ps = (jk_ws_service_t *)(int)s;
+    jk_logger_t *pl = (jk_logger_t *)(int)l;
+    const char *nmsg = NULL;
+    char **nhnames = NULL;
+    char **nhvalues = NULL;
+    jstring *shnames = NULL;
+    jstring *shvalues = NULL;
+    int i = 0;
+    int ok = JK_TRUE;
+
+    jk_log(pl, JK_LOG_DEBUG, "Into JNIConnectionHandler::startReasponse\n");
+
+    if (!ps) {
+        jk_log(pl, JK_LOG_ERROR,
+               "In JNIConnectionHandler::startReasponse, NULL ws service object\n");
+        return JK_FALSE;
+    }
+
+    jk_log(pl, JK_LOG_DEBUG,
+           "In JNIConnectionHandler::startReasponse, %d headers follow --->\n",
+           hcnt);
+
+    if (hcnt) {
+        ok = JK_FALSE;
+
+        nhnames = (char **)jk_pool_alloc(ps->pool, hcnt * sizeof(char *));
+        nhvalues = (char **)jk_pool_alloc(ps->pool, hcnt * sizeof(char *));
+        shnames = (jstring *) jk_pool_alloc(ps->pool, hcnt * sizeof(jstring));
+        shvalues =
+            (jstring *) jk_pool_alloc(ps->pool, hcnt * sizeof(jstring));
+
+        if (nhvalues && nhnames && shnames && shnames) {
+            for (; i < hcnt; i++) {
+                jboolean iscommit;
+
+                shvalues[i] = shnames[i] = NULL;
+                nhnames[i] = nhvalues[i] = NULL;
+
+                shnames[i] = (*env)->GetObjectArrayElement(env, hnames, i);
+                shvalues[i] = (*env)->GetObjectArrayElement(env, hvalues, i);
+
+                if (!shvalues[i] || !shnames[i]) {
+                    jk_log(pl, JK_LOG_ERROR,
+                           "In JNIConnectionHandler::startReasponse, GetObjectArrayElement error\n");
+                    break;
+                }
+
+                nhnames[i] =
+                    (char *)(*env)->GetStringUTFChars(env, shnames[i],
+                                                      &iscommit);
+                nhvalues[i] =
+                    (char *)(*env)->GetStringUTFChars(env, shvalues[i],
+                                                      &iscommit);
+
+                if (!nhvalues[i] || !nhnames[i]) {
+                    jk_log(pl, JK_LOG_ERROR,
+                           "In JNIConnectionHandler::startReasponse, GetStringUTFChars error\n");
+                    break;
+                }
+
+                jk_log(pl, JK_LOG_DEBUG, "---> %s=%s\n", nhnames[i],
+                       nhvalues[i]);
+            }
+            if (i == hcnt) {
+                ok = JK_TRUE;
+                jk_log(pl, JK_LOG_DEBUG,
+                       "In JNIConnectionHandler::startReasponse. ----- End headers.\n",
+                       hcnt);
+            }
+        }
+        else {
+            jk_log(pl, JK_LOG_ERROR,
+                   "In JNIConnectionHandler::startReasponse, memory allocation error\n");
+        }
+    }
+
+    if (msg && ok) {
+        jboolean iscommit;
+        nmsg = (*env)->GetStringUTFChars(env, msg, &iscommit);
+        if (!nmsg) {
+            ok = JK_FALSE;
+        }
+    }
+
+    if (ok) {
+        if (!ps->
+            start_response(ps, sc, nmsg, (const char **)nhnames,
+                           (const char **)nhvalues, hcnt)) {
+            ok = JK_FALSE;
+            jk_log(pl, JK_LOG_ERROR,
+                   "In JNIConnectionHandler::startReasponse, servers startReasponse failed\n");
+        }
+    }
+
+    if (nmsg) {
+        (*env)->ReleaseStringUTFChars(env, msg, nmsg);
+    }
+
+    if (i < hcnt) {
+        i++;
+    }
+
+    if (nhvalues) {
+        int j;
+
+        for (j = 0; j < i; j++) {
+            if (nhvalues[j]) {
+                (*env)->ReleaseStringUTFChars(env, shvalues[j], nhvalues[j]);
+            }
+        }
+    }
+
+    if (nhnames) {
+        int j;
+
+        for (j = 0; j < i; j++) {
+            if (nhnames[j]) {
+                (*env)->ReleaseStringUTFChars(env, shnames[j], nhnames[j]);
+            }
+        }
+    }
+    jk_log(pl, JK_LOG_DEBUG, "Done JNIConnectionHandler::startReasponse.\n");
+
+    return ok;
+}
+
+/*
+ * Class:     org_apache_tomcat_modules_server_JNIConnectionHandler
+ * Method:    write
+ * Signature: (JJ[BII)I
+ */
+JNIEXPORT jint JNICALL
+    Java_org_apache_tomcat_modules_server_JNIConnectionHandler_write
+    (JNIEnv * env, jobject o, jlong s, jlong l, jbyteArray buf, jint from,
+     jint cnt)
+{
+    jk_ws_service_t *ps = (jk_ws_service_t *)(int)s;
+    jk_logger_t *pl = (jk_logger_t *)(int)l;
+    jint rc = JK_FALSE;
+    jboolean iscommit;
+    jbyte *nbuf;
+    unsigned nfrom = (unsigned)from;
+    unsigned ncnt = (unsigned)cnt;
+
+    jk_log(pl, JK_LOG_DEBUG, "In JNIConnectionHandler::write\n");
+
+    if (!ps) {
+        jk_log(pl, JK_LOG_ERROR,
+               "In JNIConnectionHandler::write, NULL ws service object\n");
+        return JK_FALSE;
+    }
+
+    nbuf = (*env)->GetByteArrayElements(env, buf, &iscommit);
+
+    if (!nbuf) {
+        jk_log(pl, JK_LOG_ERROR,
+               "In JNIConnectionHandler::write, GetByteArrayElements error\n");
+        return JK_FALSE;
+    }
+
+    if (!ps->write(ps, nbuf + nfrom, ncnt)) {
+        jk_log(pl, JK_LOG_ERROR,
+               "In JNIConnectionHandler::write, failed to write to the web server\n");
+    }
+    else {
+        rc = (jint) JK_TRUE;
+    }
+
+    (*env)->ReleaseByteArrayElements(env, buf, nbuf, JNI_ABORT);
+
+    return rc;
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/jni/jk_jnicb.exp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/jni/jk_jnicb.exp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/jni/jk_jnicb.exp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,7 @@
+Java_org_apache_tomcat_modules_server_JNIConnectionHandler_getNumberOfHeaders,
+Java_org_apache_tomcat_modules_server_JNIConnectionHandler_read,
+Java_org_apache_tomcat_modules_server_JNIConnectionHandler_readEnvironment,
+Java_org_apache_tomcat_modules_server_JNIConnectionHandler_readHeaders,
+Java_org_apache_tomcat_modules_server_JNIConnectionHandler_startReasponse,
+Java_org_apache_tomcat_modules_server_JNIConnectionHandler_write
+

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/jni/jk_jnicb.h
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/jni/jk_jnicb.h	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/jni/jk_jnicb.h	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,61 @@
+/* DO NOT EDIT THIS FILE - it is machine generated */
+#include <jni.h>
+/* Header for class org_apache_tomcat_modules_server_JNIConnectionHandler */
+
+#ifndef _Included_org_apache_tomcat_modules_server_JNIConnectionHandler
+#define _Included_org_apache_tomcat_modules_server_JNIConnectionHandler
+#ifdef __cplusplus
+extern "C" {
+#endif
+/*
+ * Class:     org_apache_tomcat_modules_server_JNIConnectionHandler
+ * Method:    getNumberOfHeaders
+ * Signature: (JJ)I
+ */
+JNIEXPORT jint JNICALL Java_org_apache_tomcat_modules_server_JNIConnectionHandler_getNumberOfHeaders
+  (JNIEnv *, jobject, jlong, jlong);
+
+/*
+ * Class:     org_apache_tomcat_modules_server_JNIConnectionHandler
+ * Method:    read
+ * Signature: (JJ[BII)I
+ */
+JNIEXPORT jint JNICALL Java_org_apache_tomcat_modules_server_JNIConnectionHandler_read
+  (JNIEnv *, jobject, jlong, jlong, jbyteArray, jint, jint);
+
+/*
+ * Class:     org_apache_tomcat_modules_server_JNIConnectionHandler
+ * Method:    readEnvironment
+ * Signature: (JJ[Ljava/lang/String;)I
+ */
+JNIEXPORT jint JNICALL Java_org_apache_tomcat_modules_server_JNIConnectionHandler_readEnvironment
+  (JNIEnv *, jobject, jlong, jlong, jobjectArray);
+
+/*
+ * Class:     org_apache_tomcat_modules_server_JNIConnectionHandler
+ * Method:    readHeaders
+ * Signature: (JJ[Ljava/lang/String;[Ljava/lang/String;)I
+ */
+JNIEXPORT jint JNICALL Java_org_apache_tomcat_modules_server_JNIConnectionHandler_readHeaders
+  (JNIEnv *, jobject, jlong, jlong, jobjectArray, jobjectArray);
+
+/*
+ * Class:     org_apache_tomcat_modules_server_JNIConnectionHandler
+ * Method:    startReasponse
+ * Signature: (JJILjava/lang/String;[Ljava/lang/String;[Ljava/lang/String;I)I
+ */
+JNIEXPORT jint JNICALL Java_org_apache_tomcat_modules_server_JNIConnectionHandler_startReasponse
+  (JNIEnv *, jobject, jlong, jlong, jint, jstring, jobjectArray, jobjectArray, jint);
+
+/*
+ * Class:     org_apache_tomcat_modules_server_JNIConnectionHandler
+ * Method:    write
+ * Signature: (JJ[BII)I
+ */
+JNIEXPORT jint JNICALL Java_org_apache_tomcat_modules_server_JNIConnectionHandler_write
+  (JNIEnv *, jobject, jlong, jlong, jbyteArray, jint, jint);
+
+#ifdef __cplusplus
+}
+#endif
+#endif

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/jni/jni_connect.dsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/jni/jni_connect.dsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/jni/jni_connect.dsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,151 @@
+# Microsoft Developer Studio Project File - Name="jni_connect" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
+
+CFG=jni_connect - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE 
+!MESSAGE NMAKE /f "jni_connect.mak".
+!MESSAGE 
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE 
+!MESSAGE NMAKE /f "jni_connect.mak" CFG="jni_connect - Win32 Debug"
+!MESSAGE 
+!MESSAGE Possible choices for configuration are:
+!MESSAGE 
+!MESSAGE "jni_connect - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "jni_connect - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE 
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+MTL=midl.exe
+RSC=rc.exe
+
+!IF  "$(CFG)" == "jni_connect - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "release"
+# PROP Intermediate_Dir "release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MD /W3 /GX /Zi /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "JNI_CONNECT_EXPORTS" /FD /c
+# ADD CPP /nologo /MD /W3 /GX /Zi /O2 /I "$(JAVA_HOME)\include" /I "$(JAVA_HOME)\include\win32" /I "..\common" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "JNI_CONNECT_EXPORTS" /Fd"Release/jni_connect_src" /FD /c
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /base:"0x6A6E0000" /subsystem:windows /dll /incremental:no /debug /machine:I386 /opt:ref
+
+!ELSEIF  "$(CFG)" == "jni_connect - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "debug"
+# PROP Intermediate_Dir "debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MDd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "JNI_CONNECT_EXPORTS" /FD /c
+# ADD CPP /nologo /MDd /W3 /Gm /GX /Zi /Od /I "$(JAVA_HOME)\include" /I "$(JAVA_HOME)\include\win32" /I "..\common" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "JNI_CONNECT_EXPORTS" /Fd"Debug/jni_connect_src" /FD /c
+# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /base:"0x6A6E0000" /subsystem:windows /dll /incremental:no /debug /machine:I386
+
+!ENDIF 
+
+# Begin Target
+
+# Name "jni_connect - Win32 Release"
+# Name "jni_connect - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# Begin Source File
+
+SOURCE=.\jk_jnicb.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_map.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_pool.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_util.c
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl"
+# Begin Source File
+
+SOURCE=..\common\jk_ajp12_worker.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_global.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\jk_jnicb.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_logger.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_map.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_pool.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_service.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_util.h
+# End Source File
+# End Group
+# Begin Group "Resource Files"
+
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
+# End Group
+# End Target
+# End Project

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/netscape/Makefile.netware
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/netscape/Makefile.netware	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/netscape/Makefile.netware	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,251 @@
+#
+# Makefile for jk_nsapi_plugin (NetWare version - gnu make)
+# created by Guenter Knauf <eflash at gmx.net>
+#
+
+# Edit the path below to point to the base of your Netscape includes.
+ifndef NS_HOME
+NS_HOME	= c:/projects/sdks/netscape
+endif
+# Edit the path below to point to the base of your NetWare Java SDK.
+ifndef NW_JDK
+NW_JDK	= c:/projects/sdks/java-nw
+endif
+# Edit the path below to point to the base of your Novell NDK.
+ifndef NDKBASE
+NDKBASE	= c:/novell
+endif
+INSTDIR = /mnt/sys/novonyx/modules
+
+# Edit the vars below to change NLM target settings.
+TARGET  = nsapi_rd
+VERSION	= $(JK_VERSION)
+COPYR	= Copyright (c) 2000-2005 The Apache Software Foundation. All rights reserved.
+DESCR	= Netscape plugin for Tomcat $(JK_VERSION_STR)
+MTSAFE	= NO
+STACK	= 64000
+#SCREEN	= System Console
+MODULES	= nshttpd
+EXPORTS	= jk_init jk_service
+IMPORTS	= __nsapi30_table
+
+# Edit the var below to point to your lib architecture.
+ifndef LIBARCH
+LIBARCH = CLIB
+# LIBARCH = LIBC
+endif
+
+# must be equal to DEBUG or NDEBUG
+DB	= NDEBUG
+# DB	= DEBUG
+# Optimization: -O<n> or debugging: -g
+ifeq ($(DB),NDEBUG)
+	OPT	= -O2
+	OBJDIR	= release
+else
+	OPT	= -g
+	OBJDIR	= debug
+endif
+
+# Include the version info retrieved from jk_version.h
+-include $(OBJDIR)/version.inc
+
+# The following line defines your compiler.
+ifdef METROWERKS
+	CC = mwccnlm
+else
+	CC = gcc
+endif
+# RM	= rm -f
+# CP	= cp -fv
+# if you want to mark the target as MTSAFE you will need a tool for
+# generating the xdc data for the linker; here's a minimal tool:
+# http://www.gknw.de/development/prgtools/mkxdc.zip
+MPKXDC	= mkxdc
+
+# Global flags for all compilers
+CFLAGS	= $(OPT) -D$(DB) -DNETWARE -DXP_NETWARE -nostdinc
+
+ifeq ($(CC),mwccnlm)
+LD	= mwldnlm
+LDFLAGS	= -nostdlib $(PRELUDE) $(OBJDIR)/*.o -o $(OBJDIR)/$(TARGET).nlm -commandfile
+CFLAGS	+= -gccinc -inline off -opt nointrinsics
+#CFLAGS	+= -w on
+ifeq ($(LIBARCH),LIBC)
+	PRELUDE = $(SDK_LIBC)/imports/libcpre.o
+	CFLAGS += -align 4 -inst mmx -proc 686
+#	CFLAGS += -D__ANSIC__
+else
+	PRELUDE = "$(METROWERKS)/Novell Support/libraries/runtime/prelude.obj"
+#	CFLAGS += -include "$(METROWERKS)/Novell Support/headers/nlm_prefix.h"
+	CFLAGS += -align 1 -proc 586
+endif
+else
+LD	= nlmconv
+LDFLAGS	= -T
+CFLAGS	+= -fno-builtin -fpack-struct -fpcc-struct-return
+CFLAGS	+= -Wall -Wno-main # -pedantic
+ifeq ($(LIBARCH),LIBC)
+	PRELUDE = $(SDK_LIBC)/imports/libcpre.gcc.o
+#	CFLAGS += -D__ANSIC__
+else
+	PRELUDE = $(SDK_CLIB)/imports/clibpre.gcc.o
+	CFLAGS += -include $(NDKBASE)/nlmconv/genlm.h
+endif
+endif
+
+LDLIBS	=
+
+NDK_ROOT = $(NDKBASE)/ndk
+SDK_CLIB = $(NDK_ROOT)/nwsdk
+SDK_LIBC = $(NDK_ROOT)/libc
+JKCOMMON = ../common
+
+INCLUDES = -I$(NS_HOME)/include -I$(NS_HOME)/include/base
+INCLUDES += -I$(JKCOMMON) -I$(NW_JDK)/include -I$(NW_JDK)/include/netware 
+
+ifeq ($(LIBARCH),LIBC)
+	INCLUDES += -I$(SDK_LIBC)/include -I$(SDK_LIBC)/include/nks
+	INCLUDES += -I$(SDK_LIBC)/include/winsock
+else
+	INCLUDES += -I$(SDK_CLIB)/include/nlm -I$(SDK_CLIB)/include
+	INCLUDES += -I$(SDK_CLIB)/include/nlm/obsolete
+	CFLAGS += -DNETDB_USE_INTERNET
+endif
+CFLAGS	+= $(INCLUDES)
+
+ifeq ($(MTSAFE),YES)
+	XDCDATA = $(OBJDIR)/$(TARGET).xdc
+endif
+
+ifeq ($(findstring linux,$(OSTYPE)),linux)
+DL	= '
+#-include $(NDKBASE)/nlmconv/ncpfs.inc
+endif
+
+OBJS	= \
+	$(OBJDIR)/jk_nwmain.o \
+	$(OBJDIR)/jk_ajp12_worker.o \
+	$(OBJDIR)/jk_ajp13.o \
+	$(OBJDIR)/jk_ajp13_worker.o \
+	$(OBJDIR)/jk_ajp14.o \
+	$(OBJDIR)/jk_ajp14_worker.o \
+	$(OBJDIR)/jk_ajp_common.o \
+	$(OBJDIR)/jk_connect.o \
+	$(OBJDIR)/jk_context.o \
+	$(OBJDIR)/jk_jni_worker.o \
+	$(OBJDIR)/jk_lb_worker.o \
+	$(OBJDIR)/jk_map.o \
+	$(OBJDIR)/jk_md5.o \
+	$(OBJDIR)/jk_msg_buff.o \
+	$(OBJDIR)/jk_pool.o \
+	$(OBJDIR)/jk_shm.o \
+	$(OBJDIR)/jk_sockbuf.o \
+	$(OBJDIR)/jk_status.o \
+	$(OBJDIR)/jk_uri_worker_map.o \
+	$(OBJDIR)/jk_util.o \
+	$(OBJDIR)/jk_worker.o \
+	$(OBJDIR)/jk_nsapi_plugin.o
+
+
+all: $(OBJDIR) $(OBJDIR)/version.inc $(OBJDIR)/$(TARGET).nlm 
+
+$(OBJDIR)/%.o: %.c
+	@echo Compiling $<
+	@$(CC) $(CFLAGS) -c $< -o $@
+
+$(OBJDIR)/%.o: $(JKCOMMON)/%.c
+	@echo Compiling $<
+	@$(CC) $(CFLAGS) -c $< -o $@
+
+$(OBJDIR)/version.inc: $(JKCOMMON)/jk_version.h $(OBJDIR)
+	@echo Creating $@
+	@awk -f ../../support/get_ver.awk $< > $@
+
+dist: all
+	-$(RM) $(OBJDIR)/*.o $(OBJDIR)/$(TARGET).map $(OBJDIR)/$(TARGET).ncv
+	-$(RM) $(OBJDIR)/$(TARGET).def $(OBJDIR)/version.inc $(XDCDATA)
+#	-$(CP) ../changes.txt $(OBJDIR)/
+
+install: all
+	@[ -d $(INSTDIR) ] || mkdir $(INSTDIR)
+	@$(CP) $(TARGET).nlm $(INSTDIR)
+
+clean:
+	-$(RM) -r $(OBJDIR)
+
+$(OBJDIR):
+	@mkdir $(OBJDIR)
+
+$(OBJDIR)/$(TARGET).nlm: $(OBJS) $(OBJDIR)/$(TARGET).def $(XDCDATA)
+	@echo Linking $@
+	@-$(RM) $@
+	@$(LD) $(LDFLAGS) $(OBJDIR)/$(TARGET).def
+
+$(OBJDIR)/%.xdc: Makefile.netware
+	@echo Creating $@
+	@$(MPKXDC) $(XDCOPT) $@
+
+$(OBJDIR)/%.def: Makefile.netware
+	@echo $(DL)# DEF file for linking with $(LD)$(DL) > $@
+	@echo $(DL)# Do not edit this file - it is created by make!$(DL) >> $@
+	@echo $(DL)# All your changes will be lost!!$(DL) >> $@
+	@echo $(DL)#$(DL) >> $@
+	@echo $(DL)copyright "$(COPYR)"$(DL) >> $@
+	@echo $(DL)description "$(DESCR)"$(DL) >> $@
+	@echo $(DL)version $(VERSION)$(DL) >> $@
+ifdef NLMTYPE
+	@echo $(DL)type $(NLMTYPE)$(DL) >> $@
+endif
+ifdef STACK
+	@echo $(DL)stack $(STACK)$(DL) >> $@
+endif
+ifdef SCREEN
+	@echo $(DL)screenname "$(SCREEN)"$(DL) >> $@
+else
+	@echo $(DL)screenname "DEFAULT"$(DL) >> $@
+endif
+ifeq ($(DB),DEBUG)
+	@echo $(DL)debug$(DL) >> $@
+endif
+	@echo $(DL)threadname "$(TARGET)"$(DL) >> $@
+ifdef XDCDATA
+	@echo $(DL)xdcdata $(XDCDATA)$(DL) >> $@
+endif
+ifeq ($(LIBARCH),CLIB)
+	@echo $(DL)start _Prelude$(DL) >> $@
+	@echo $(DL)exit _Stop$(DL) >> $@
+	@echo $(DL)import @$(NDK_ROOT)/nwsdk/imports/clib.imp$(DL) >> $@
+	@echo $(DL)import @$(NDK_ROOT)/nwsdk/imports/threads.imp$(DL) >> $@
+	@echo $(DL)import @$(NDK_ROOT)/nwsdk/imports/nlmlib.imp$(DL) >> $@
+	@echo $(DL)import @$(NDK_ROOT)/nwsdk/imports/socklib.imp$(DL) >> $@
+	@echo $(DL)module clib$(DL) >> $@
+else
+ifeq ($(LD),nlmconv)
+	@echo $(DL)flag_on 64$(DL) >> $@
+else
+	@echo $(DL)autounload$(DL) >> $@
+endif
+	@echo $(DL)pseudopreemption$(DL) >> $@
+	@echo $(DL)start _LibCPrelude$(DL) >> $@
+	@echo $(DL)exit _LibCPostlude$(DL) >> $@
+	@echo $(DL)check _LibCCheckUnload$(DL) >> $@
+	@echo $(DL)import @$(NDK_ROOT)/libc/imports/libc.imp$(DL) >> $@
+	@echo $(DL)import @$(NDK_ROOT)/libc/imports/netware.imp$(DL) >> $@
+	@echo $(DL)module libc$(DL) >> $@
+endif
+ifdef MODULES
+	@echo $(DL)module $(MODULES)$(DL) >> $@
+endif
+ifdef EXPORTS
+	@echo $(DL)export $(EXPORTS)$(DL) >> $@
+endif
+ifdef IMPORTS
+	@echo $(DL)import $(IMPORTS)$(DL) >> $@
+endif
+ifeq ($(LD),nlmconv)
+	@echo $(DL)input $(OBJS)$(DL) >> $@
+	@echo $(DL)input $(PRELUDE)$(DL) >> $@
+	@echo $(DL)output $(TARGET).nlm$(DL) >> $@
+endif
+

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/netscape/Makefile.solaris
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/netscape/Makefile.solaris	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/netscape/Makefile.solaris	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,36 @@
+# Defines for example NSAPI programs running under SOLARIS
+
+CC_CMD=gcc -DNET_SSL -DSOLARIS -D_REENTRANT -DXP_UNIX \
+	-DMCC_HTTPD -DSPAPI20 \
+	-fPIC
+LD_SHAREDCMD=ld -G -fPIC
+
+all:
+
+prepare:
+
+OS_TYPE=solaris
+INCLUDEDIR=$(SUITSPOT_HOME)/include
+JAVA_INCLUDE=$(JAVA_HOME)/include
+JK_DIR=../common
+VPATH=.:$(JK_DIR)
+
+JK_SRCS = $(shell ls $(JK_DIR)/*.c)
+JK_OBJS = $(patsubst $(JK_DIR)/%.c,%.o,$(JK_SRCS))
+
+PLUGIN_OBJ = jk_nsapi_plugin.o
+
+INCLUDE_FLAGS=	-I$(JK_DIR) -I$(INCLUDEDIR) -I$(INCLUDEDIR)/base \
+		-I$(INCLUDEDIR)/frame -I$(JAVA_INCLUDE) -I$(JAVA_INCLUDE)/$(OS_TYPE)
+
+all: nsapi_redirector.so 
+
+
+nsapi_redirector.so: $(JK_OBJS) $(PLUGIN_OBJ)
+	$(LD_SHAREDCMD) $(JK_OBJS) $(PLUGIN_OBJ) -o nsapi_redirector.so $(EXTRA_LDDEFINES)
+
+clean:
+	rm -f *.o nsapi_redirector.so 
+
+%.o : %.c
+	$(CC_CMD) $(INCLUDE_FLAGS) -c $< 

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/netscape/README
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/netscape/README	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/netscape/README	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,33 @@
+ABOUT
+-----
+
+The redirector was originally developed using Visual C++ Ver.6.0, 
+so having this environment is a prerequisite if you want to perform 
+a custom build on Windows systems
+
+On Unix system, a Makefile.solaris is provided and should be 
+adapted to tailor to your own configuration.
+
+
+REQUIREMENT for Windows build
+-----------------------------
+
+MS VC 6.0 (+ update, latest service pack is 6)
+
+BUILDING on Windows
+-------------------
+ 
+The steps that you need to take are:
+
+   1. Change directory to the nsapi redirector plugins source directory.
+   2. Set the SUNONE_HOME system environment value to SunONE installation
+      directory or edit the nsapi.dsp and replace all $(SUNONE_HOME)
+      occurrences with the real path
+   3. Execute the following command:
+      MSDEV nsapi.dsp /MAKE ALL
+      If msdev is not in your path, enter the full path to msdev.exe
+
+This will build both release and debug versions of the redirector plugin.
+
+An alternative will be to open the isapi workspace file (nsapi.dsw) in msdev and 
+build it using the build menu.

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/netscape/jk_nsapi_plugin.c
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/netscape/jk_nsapi_plugin.c	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/netscape/jk_nsapi_plugin.c	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,522 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.
+ */
+
+/***************************************************************************
+ * Description: NSAPI plugin for Netscape servers                          *
+ * Author:      Gal Shachor <shachor at il.ibm.com>                           *
+ * Version:     $Revision: 437379 $                                           *
+ ***************************************************************************/
+
+
+#include "nsapi.h"
+#include "jk_global.h"
+#include "jk_util.h"
+#include "jk_map.h"
+#include "jk_pool.h"
+#include "jk_service.h"
+#include "jk_worker.h"
+#include "jk_shm.h"
+
+#define URI_PATTERN "path"
+#define DEFAULT_WORKER_NAME ("ajp13")
+
+struct nsapi_private_data
+{
+    jk_pool_t p;
+
+    int request_started;
+
+    pblock *pb;
+    Session *sn;
+    Request *rq;
+};
+typedef struct nsapi_private_data nsapi_private_data_t;
+
+static int init_on_other_thread_is_done = JK_FALSE;
+static int init_on_other_thread_is_ok = JK_FALSE;
+
+static const char ssl_cert_start[] = "-----BEGIN CERTIFICATE-----\r\n";
+static const char ssl_cert_end[] = "\r\n-----END CERTIFICATE-----\r\n";
+
+static jk_logger_t *logger = NULL;
+static jk_worker_env_t worker_env;
+static jk_map_t *init_map = NULL;
+static jk_uri_worker_map_t *uw_map = NULL;
+
+#ifdef NETWARE
+int (*PR_IsSocketSecure) (SYS_NETFD * csd);     /* pointer to PR_IsSocketSecure function */
+#endif
+
+static int JK_METHOD start_response(jk_ws_service_t *s,
+                                    int status,
+                                    const char *reason,
+                                    const char *const *header_names,
+                                    const char *const *header_values,
+                                    unsigned num_of_headers);
+
+static int JK_METHOD ws_read(jk_ws_service_t *s,
+                             void *b, unsigned l, unsigned *a);
+
+static int JK_METHOD ws_write(jk_ws_service_t *s, const void *b, unsigned l);
+
+NSAPI_PUBLIC int jk_init(pblock * pb, Session * sn, Request * rq);
+
+NSAPI_PUBLIC void jk_term(void *p);
+
+NSAPI_PUBLIC int jk_service(pblock * pb, Session * sn, Request * rq);
+
+static int init_ws_service(nsapi_private_data_t * private_data,
+                           jk_ws_service_t *s);
+
+static int setup_http_headers(nsapi_private_data_t * private_data,
+                              jk_ws_service_t *s);
+
+static void init_workers_on_other_threads(void *init_d)
+{
+    init_map = (jk_map_t *)init_d;
+    /* we add the URI->WORKER MAP since workers using AJP14 will feed it */
+    /* but where are they here in Netscape ? */
+    if (wc_open(init_map, &worker_env, logger)) {
+        if (uri_worker_map_alloc(&uw_map, NULL, logger)) {
+            uw_map->fname = "";
+            worker_env.uri_to_worker = uw_map;
+            init_on_other_thread_is_ok = JK_TRUE;
+        }
+        else {
+            jk_log(logger, JK_LOG_EMERG,
+                   "In init_workers_on_other_threads, failed");
+        }
+    }
+    else {
+        jk_log(logger, JK_LOG_EMERG,
+               "In init_workers_on_other_threads, failed");
+    }
+
+    init_on_other_thread_is_done = JK_TRUE;
+}
+
+static int JK_METHOD start_response(jk_ws_service_t *s,
+                                    int status,
+                                    const char *reason,
+                                    const char *const *header_names,
+                                    const char *const *header_values,
+                                    unsigned num_of_headers)
+{
+    if (s && s->ws_private) {
+        nsapi_private_data_t *p = s->ws_private;
+        if (!p->request_started) {
+            unsigned i;
+
+            p->request_started = JK_TRUE;
+
+            /* Remove "old" content type */
+            param_free(pblock_remove("content-type", p->rq->srvhdrs));
+
+            if (num_of_headers) {
+                for (i = 0; i < (int)num_of_headers; i++) {
+                    pblock_nvinsert(header_names[i],
+                                    header_values[i], p->rq->srvhdrs);
+                }
+            }
+            else {
+                pblock_nvinsert("content-type", "text/plain", p->rq->srvhdrs);
+            }
+
+            protocol_status(p->sn, p->rq, status, (char *)reason);
+
+            protocol_start_response(p->sn, p->rq);
+        }
+        return JK_TRUE;
+
+    }
+    return JK_FALSE;
+}
+
+static int JK_METHOD ws_read(jk_ws_service_t *s,
+                             void *b, unsigned l, unsigned *a)
+{
+    if (s && s->ws_private && b && a) {
+        nsapi_private_data_t *p = s->ws_private;
+
+        *a = 0;
+        if (l) {
+            char *buf = b;
+            unsigned i;
+            netbuf *inbuf = p->sn->inbuf;
+
+/* Until we get a service pack for NW5.1 and earlier that has the latest */
+/* Enterprise Server, we have to go through the else version of this code*/
+#if defined(netbuf_getbytes) && !defined(NETWARE)
+            i = netbuf_getbytes(inbuf, b, l);
+            if (NETBUF_EOF == i || NETBUF_ERROR == i) {
+                return JK_FALSE;
+            }
+
+#else
+            int ch;
+            for (i = 0; i < l; i++) {
+                ch = netbuf_getc(inbuf);
+                /*
+                 * IO_EOF is 0 (zero) which is a very reasonable byte
+                 * when it comes to binary data. So we are not breaking
+                 * out of the read loop when reading it.
+                 *
+                 * We are protected from an infinit loop by the Java part of
+                 * Tomcat.
+                 */
+                if (IO_ERROR == ch) {
+                    break;
+                }
+
+                buf[i] = ch;
+            }
+
+            if (0 == i) {
+                return JK_FALSE;
+            }
+#endif
+            *a = i;
+
+        }
+        return JK_TRUE;
+    }
+    return JK_FALSE;
+}
+
+static int JK_METHOD ws_write(jk_ws_service_t *s, const void *b, unsigned l)
+{
+    if (s && s->ws_private && b) {
+        nsapi_private_data_t *p = s->ws_private;
+
+        if (l) {
+            if (!p->request_started) {
+                start_response(s, 200, NULL, NULL, NULL, 0);
+            }
+
+            if (net_write(p->sn->csd, (char *)b, (int)l) == IO_ERROR) {
+                return JK_FALSE;
+            }
+        }
+
+        return JK_TRUE;
+
+    }
+    return JK_FALSE;
+}
+
+NSAPI_PUBLIC int jk_init(pblock * pb, Session * sn, Request * rq)
+{
+    char *worker_prp_file = pblock_findval(JK_WORKER_FILE_TAG, pb);
+    char *log_level_str = pblock_findval(JK_LOG_LEVEL_TAG, pb);
+    char *log_file = pblock_findval(JK_LOG_FILE_TAG, pb);
+    char *shm_file = pblock_findval(JK_SHM_FILE_TAG, pb);
+
+    int rc = REQ_ABORTED;
+
+    fprintf(stderr,
+            "In jk_init.\n   Worker file = %s.\n   Log level = %s.\n   Log File = %s\n",
+            worker_prp_file, log_level_str, log_file);
+    if (!worker_prp_file) {
+        worker_prp_file = JK_WORKER_FILE_DEF;
+    }
+
+    if (!log_level_str) {
+        log_level_str = JK_LOG_DEF_VERB;
+    }
+
+    if (!jk_open_file_logger(&logger, log_file,
+                             jk_parse_log_level(log_level_str))) {
+        logger = NULL;
+    }
+    
+    jk_shm_open(shm_file, JK_SHM_DEF_SIZE, logger);
+    if (jk_map_alloc(&init_map)) {
+        if (jk_map_read_properties(init_map, worker_prp_file, NULL, logger)) {
+            int sleep_cnt;
+            SYS_THREAD s;
+
+            s = systhread_start(SYSTHREAD_DEFAULT_PRIORITY,
+                                0, init_workers_on_other_threads, init_map);
+            for (sleep_cnt = 0; sleep_cnt < 60; sleep_cnt++) {
+                systhread_sleep(1000);
+                jk_log(logger, JK_LOG_DEBUG, "jk_init, a second passed");
+                if (init_on_other_thread_is_done) {
+                    break;
+                }
+            }
+
+            if (init_on_other_thread_is_done && init_on_other_thread_is_ok) {
+                magnus_atrestart(jk_term, NULL);
+                rc = REQ_PROCEED;
+            }
+
+/*            if(wc_open(init_map, NULL, logger)) {
+                magnus_atrestart(jk_term, NULL);
+                rc = REQ_PROCEED;
+            }
+*/
+        }
+    }
+
+#ifdef NETWARE
+    PR_IsSocketSecure =
+        (int (*)(void **))ImportSymbol(GetNLMHandle(), "PR_IsSocketSecure");
+#endif
+    return rc;
+}
+
+NSAPI_PUBLIC void jk_term(void *p)
+{
+#ifdef NETWARE
+    if (NULL != PR_IsSocketSecure) {
+        UnimportSymbol(GetNLMHandle(), "PR_IsSocketSecure");
+        PR_IsSocketSecure = NULL;
+    }
+#endif
+    if (uw_map) {
+        uri_worker_map_free(&uw_map, logger);
+    }
+
+    wc_close(logger);
+    if (logger) {
+        jk_close_file_logger(&logger);
+    }
+
+	if (init_map) {
+        jk_map_free(&init_map);
+    }
+}
+
+NSAPI_PUBLIC int jk_service(pblock * pb, Session * sn, Request * rq)
+{
+    char *worker_name = pblock_findval(JK_WORKER_NAME_TAG, pb);
+    char *uri_pattern = pblock_findval(URI_PATTERN, pb);
+    jk_worker_t *worker;
+    int rc = REQ_ABORTED;
+
+    if (uri_pattern) {
+        char *uri = pblock_findval("uri", rq->reqpb);
+
+        if (0 != shexp_match(uri, uri_pattern)) {
+            return REQ_NOACTION;
+        }
+    }
+
+    if (!worker_name) {
+        worker_name = DEFAULT_WORKER_NAME;
+    }
+
+    worker = wc_get_worker_for_name(worker_name, logger);
+    if (worker) {
+        nsapi_private_data_t private_data;
+        jk_ws_service_t s;
+        jk_pool_atom_t buf[SMALL_POOL_SIZE];
+
+        jk_open_pool(&private_data.p, buf, sizeof(buf));
+
+        private_data.request_started = JK_FALSE;
+        private_data.pb = pb;
+        private_data.sn = sn;
+        private_data.rq = rq;
+
+        jk_init_ws_service(&s);
+
+        s.ws_private = &private_data;
+        s.pool = &private_data.p;
+
+        wc_maintain(logger);
+        if (init_ws_service(&private_data, &s)) {
+            jk_endpoint_t *e = NULL;
+            if (worker->get_endpoint(worker, &e, logger)) {
+                int recover = JK_FALSE;
+                if (e->service(e, &s, logger, &recover)) {
+                    rc = REQ_PROCEED;
+                }
+                e->done(&e, logger);
+            }
+        }
+        jk_close_pool(&private_data.p);
+    }
+
+    return rc;
+}
+
+static int init_ws_service(nsapi_private_data_t * private_data,
+                           jk_ws_service_t *s)
+{
+    char *tmp;
+    int rc;
+
+    s->jvm_route = NULL;
+    s->start_response = start_response;
+    s->read = ws_read;
+    s->write = ws_write;
+    s->flush = NULL;
+
+    /* Clear RECO status */
+    s->reco_status = RECO_NONE;
+
+    s->auth_type = pblock_findval("auth-type", private_data->rq->vars);
+    s->remote_user = pblock_findval("auth-user", private_data->rq->vars);
+
+    s->content_length = 0;
+    tmp = NULL;
+    rc = request_header("content-length",
+                        &tmp, private_data->sn, private_data->rq);
+
+    if ((rc != REQ_ABORTED) && tmp) {
+        s->content_length = atoi(tmp);
+    }
+
+    s->method = pblock_findval("method", private_data->rq->reqpb);
+    s->protocol = pblock_findval("protocol", private_data->rq->reqpb);
+
+    s->remote_host = session_dns(private_data->sn);
+    s->remote_addr = pblock_findval("ip", private_data->sn->client);
+
+    s->req_uri = pblock_findval("uri", private_data->rq->reqpb);
+    s->query_string = pblock_findval("query", private_data->rq->reqpb);
+
+    s->server_name = server_hostname;
+
+#ifdef NETWARE
+    /* On NetWare, since we have virtual servers, we have a different way of
+     * getting the port that we need to try first.
+     */
+    tmp = pblock_findval("server_port", private_data->sn->client);
+    if (NULL != tmp)
+        s->server_port = atoi(tmp);
+    else
+#endif
+        s->server_port = server_portnum;
+    s->server_software = system_version();
+
+
+    s->headers_names = NULL;
+    s->headers_values = NULL;
+    s->num_headers = 0;
+	s->uw_map = uw_map;
+
+#ifdef NETWARE
+    /* on NetWare, we can have virtual servers that are secure.
+     * PR_IsSocketSecure is an api made available with virtual servers to check
+     * if the socket is secure or not
+     */
+    if (NULL != PR_IsSocketSecure)
+        s->is_ssl = PR_IsSocketSecure(private_data->sn->csd);
+    else
+#endif
+        s->is_ssl = security_active;
+
+    s->ssl_key_size = -1;       /* required by Servlet 2.3 Api, added in jtc */
+    if (s->is_ssl) {
+        char *ssl_cert = pblock_findval("auth-cert", private_data->rq->vars);
+        if (ssl_cert != NULL) {
+            s->ssl_cert = jk_pool_alloc(s->pool, sizeof(ssl_cert_start)+
+                                                 strlen(ssl_cert)+
+                                                 sizeof(ssl_cert_end));
+            strcpy(s->ssl_cert, ssl_cert_start);
+            strcat(s->ssl_cert, ssl_cert);
+            strcat(s->ssl_cert, ssl_cert_end);
+            s->ssl_cert_len = strlen(s->ssl_cert);
+        }
+        s->ssl_cipher = pblock_findval("cipher", private_data->sn->client);
+        s->ssl_session = pblock_findval("ssl-id", private_data->sn->client);
+    }
+    else {
+        s->ssl_cert = NULL;
+        s->ssl_cert_len = 0;
+        s->ssl_cipher = NULL;
+        s->ssl_session = NULL;
+    }
+
+    return setup_http_headers(private_data, s);
+}
+
+static int setup_http_headers(nsapi_private_data_t * private_data,
+                              jk_ws_service_t *s)
+{
+    int need_content_length_header =
+        (s->content_length == 0) ? JK_TRUE : JK_FALSE;
+
+    pblock *headers_jar = private_data->rq->headers;
+    int cnt;
+    int i;
+
+    for (i = 0, cnt = 0; i < headers_jar->hsize; i++) {
+        struct pb_entry *h = headers_jar->ht[i];
+        while (h && h->param) {
+            cnt++;
+            h = h->next;
+        }
+    }
+
+    s->headers_names = NULL;
+    s->headers_values = NULL;
+    s->num_headers = cnt;
+    if (cnt) {
+        /* allocate an extra header slot in case we need to add a content-length header */
+        s->headers_names =
+            jk_pool_alloc(&private_data->p, (cnt + 1) * sizeof(char *));
+        s->headers_values =
+            jk_pool_alloc(&private_data->p, (cnt + 1) * sizeof(char *));
+
+        if (s->headers_names && s->headers_values) {
+            for (i = 0, cnt = 0; i < headers_jar->hsize; i++) {
+                struct pb_entry *h = headers_jar->ht[i];
+                while (h && h->param) {
+                    s->headers_names[cnt] = h->param->name;
+                    s->headers_values[cnt] = h->param->value;
+                    if (need_content_length_header &&
+                        !strncmp(h->param->name, "content-length", 14)) {
+                        need_content_length_header = JK_FALSE;
+                    }
+                    cnt++;
+                    h = h->next;
+                }
+            }
+            /* Add a content-length = 0 header if needed.
+             * Ajp13 assumes an absent content-length header means an unknown,
+             * but non-zero length body.
+             */
+            if (need_content_length_header) {
+                s->headers_names[cnt] = "content-length";
+                s->headers_values[cnt] = "0";
+                cnt++;
+            }
+            s->num_headers = cnt;
+            return JK_TRUE;
+        }
+    }
+    else {
+        if (need_content_length_header) {
+            s->headers_names =
+                jk_pool_alloc(&private_data->p, sizeof(char *));
+            s->headers_values =
+                jk_pool_alloc(&private_data->p, sizeof(char *));
+            if (s->headers_names && s->headers_values) {
+                s->headers_names[0] = "content-length";
+                s->headers_values[0] = "0";
+                s->num_headers++;
+                return JK_TRUE;
+            }
+        }
+        else
+            return JK_TRUE;
+    }
+
+    return JK_FALSE;
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/netscape/nsapi.dsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/netscape/nsapi.dsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/netscape/nsapi.dsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,275 @@
+# Microsoft Developer Studio Project File - Name="nsapi" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
+
+CFG=nsapi - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE 
+!MESSAGE NMAKE /f "nsapi.mak".
+!MESSAGE 
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE 
+!MESSAGE NMAKE /f "nsapi.mak" CFG="nsapi - Win32 Debug"
+!MESSAGE 
+!MESSAGE Possible choices for configuration are:
+!MESSAGE 
+!MESSAGE "nsapi - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "nsapi - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE 
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+MTL=midl.exe
+RSC=rc.exe
+
+!IF  "$(CFG)" == "nsapi - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "nsapi_release"
+# PROP Intermediate_Dir "nsapi_release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "NSAPI_EXPORTS" /YX /FD /c
+# ADD CPP /nologo /MD /W3 /Zi /O2 /I "..\common" /I "$(SUNONE_HOME)\plugins\include" /I "$(JAVA_HOME)\include" /I "$(JAVA_HOME)\include\win32" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "NSAPI_EXPORTS" /D "XP_WIN32" /D "MCC_HTTPD" /D "SPAPI20" /Fd"Release/nsapi_redirect_src" /FD /c
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386
+# ADD LINK32 ns-httpd40.lib kernel32.lib user32.lib advapi32.lib ws2_32.lib mswsock.lib /nologo /base:"0x6A6B0000" /dll /debug /machine:I386 /out:"nsapi_release/nsapi_redirect.dll" /libpath:"$(SUNONE_HOME)\plugins\lib"
+
+!ELSEIF  "$(CFG)" == "nsapi - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "nsapi___Win32_Debug"
+# PROP BASE Intermediate_Dir "nsapi___Win32_Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "nsapi_debug"
+# PROP Intermediate_Dir "nsapi_debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "NSAPI_EXPORTS" /YX /FD /GZ /c
+# ADD CPP /nologo /MDd /W3 /GX /Zi /Od /I "..\common" /I "$(SUNONE_HOME)\plugins\include" /I "$(JAVA_HOME)\include" /I "$(JAVA_HOME)\include\win32" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "NSAPI_EXPORTS" /D "XP_WIN32" /D "MCC_HTTPD" /D "SPAPI20" /Fd"Debug/nsapi_redirect_src" /FD /c
+# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 ns-httpd40.lib kernel32.lib user32.lib advapi32.lib ws2_32.lib mswsock.lib /nologo /base:"0x6A6B0000" /dll /debug /machine:I386 /out:"nsapi_debug/nsapi_redirect.dll" /pdbtype:sept /libpath:"$(SUNONE_HOME)\plugins\lib"
+
+!ENDIF 
+
+# Begin Target
+
+# Name "nsapi - Win32 Release"
+# Name "nsapi - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# Begin Source File
+
+SOURCE=..\common\jk_ajp12_worker.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_ajp13.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_ajp13_worker.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_ajp14.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_ajp14_worker.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_ajp_common.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_connect.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_context.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_jni_worker.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_lb_worker.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_map.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_md5.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_msg_buff.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\jk_nsapi_plugin.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_pool.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_shm.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_sockbuf.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_status.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_uri_worker_map.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_util.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_worker.c
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl"
+# Begin Source File
+
+SOURCE=..\common\jk_ajp13.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_ajp13_worker.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_ajp14.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_ajp14_worker.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_ajp_common.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_connect.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_context.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_global.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_jni_worker.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_lb_worker.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_logger.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_map.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_md5.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_msg_buff.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_mt.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_pool.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_service.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_shm.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_status.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_uri_worker_map.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_util.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_worker.h
+# End Source File
+# End Group
+# Begin Group "Resource Files"
+
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
+# End Group
+# End Target
+# End Project

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/nt_service/jk_nt_service.c
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/nt_service/jk_nt_service.c	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/nt_service/jk_nt_service.c	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,1230 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.
+ */
+
+/***************************************************************************
+ * Description: NT System service for Tomcat                       *
+ * Author:      Gal Shachor <shachor at il.ibm.com>                           *
+ *              Dave Oxley <Dave at JungleMoss.com>                           *
+ * Version:     $Revision: 437379 $                                           *
+ ***************************************************************************/
+
+#include "jk_global.h"
+#include "jk_util.h"
+#include "jk_ajp13.h"
+#include "jk_connect.h"
+#include <windows.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <process.h>
+
+#define AJP12_TAG              ("ajp12")
+#define AJP13_TAG              ("ajp13")
+#define BASE_REGISTRY_LOCATION ("SYSTEM\\CurrentControlSet\\Services\\")
+#define IMAGE_NAME             ("ImagePath")
+#define PARAMS_LOCATION        ("Parameters")
+#define PRP_LOCATION           ("PropertyFile")
+
+// internal variables
+static SERVICE_STATUS          ssStatus;       // current status of the service
+static SERVICE_STATUS_HANDLE   sshStatusHandle;
+static DWORD                   dwErr = 0;
+static char                    szErr[1024] = "";
+static HANDLE                  hServerStopEvent = NULL;
+static int                     shutdown_port;
+static char                    *shutdown_protocol = AJP12_TAG;
+static char                    *shutdown_secret = NULL;
+static char                    *shutdown_cmd=NULL;
+
+typedef enum ActionEnum
+{   acNoAction  = 0,
+    acInstall   = 1,
+    acRemove    = 2,
+    acStartTC   = 3,
+    acStopTC    = 4
+}   ActionEnum;
+
+
+struct jk_tomcat_startup_data {
+    char *cmd_line; /* Start command line */
+    char *stdout_file;
+    char *stderr_file;
+    char *extra_path;
+    char *tomcat_home;
+    char *java_bin;
+
+    char *shutdown_protocol;
+    /* for cmd */
+    char *stop_cmd;
+    /* For ajp13/ajp12/catalina */
+    int  shutdown_port;
+    char *shutdown_secret;
+
+    /* Optional/not needed */
+    char *classpath;
+    char *tomcat_class;
+    char *server_file;
+};
+
+typedef struct jk_tomcat_startup_data jk_tomcat_startup_data_t;
+
+// internal function prototypes
+static void WINAPI service_ctrl(DWORD dwCtrlCode);
+static void WINAPI service_main(DWORD dwArgc, 
+                                char **lpszArgv);
+static void install_service(char *name,
+                            char *dname,
+                            char *user, 
+                            char *password, 
+                            char *deps, 
+                            BOOL bAutomatic, 
+                            char *rel_prp_file);
+static void remove_service(char *name);
+static void start_service(char *name,
+                          char *machine);
+static void stop_service(char *name,
+                         char *machine);
+static char *GetLastErrorText(char *lpszBuf, DWORD dwSize);
+static void AddToMessageLog(char *lpszMsg);
+static BOOL ReportStatusToSCMgr(DWORD dwCurrentState,
+                                DWORD dwWin32ExitCode,
+                                DWORD dwWaitHint);
+static void start_jk_service(char *name);
+static void stop_jk_service(void);
+static int set_registry_values(SC_HANDLE   schService, char *name, 
+                               char *prp_file);
+static int create_registry_key(const char *tag, 
+                               HKEY *key);
+static int set_registry_config_parameter(HKEY hkey, 
+                                         const char *tag, 
+                                         char *value);
+static int get_registry_config_parameter(HKEY hkey, 
+                                         const char *tag,  
+                                         char *b, DWORD sz);
+static int start_tomcat(const char *name, 
+                        HANDLE *hTomcat);
+static void stop_tomcat(char *name,
+                        int port, 
+                        const char *protocol,
+                        char *secret,
+                        HANDLE hTomcat);
+static int read_startup_data(jk_map_t *init_map, 
+                             jk_tomcat_startup_data_t *data, 
+                             jk_pool_t *p);
+static int exec_cmd(const char *name, HANDLE *hTomcat, char *cmdLine);
+
+static void usage_message(const char *name)
+{
+    printf("%s - Usage:\n\n", name);
+    printf("To install the service:\n");
+    printf("%s -i <service name> {optional params} <config properties file>\n", name);
+    printf("    Optional parameters\n");
+    printf("        -u <user name> - In the form DomainName\\UserName (.\\UserName for local)\n");
+    printf("        -n <service display name> - In quotes if contains non-lphanumeric chars\n");
+    printf("        -p <user password>\n");
+    printf("        -a - Set startup type to automatic\n");
+    printf("        -d <service dependency> - Can be entered multiple times\n\n");
+    printf("To remove the service:\n");
+    printf("%s -r <service name>\n\n", name);
+    printf("To start the service:\n");
+    printf("%s -s <service name> {optional params}\n", name);
+    printf("    Optional parameters\n");
+    printf("        -m <machine>\n\n");
+    printf("To stop the service:\n");
+    printf("%s -t <service name> {optional params}\n", name);
+    printf("    Optional parameters\n");
+    printf("        -m <machine>\n");
+}
+
+void main(int argc, char **argv)
+{
+    WORD wVersionRequested;
+    WSADATA wsaData;
+    int i;
+    int err;
+    int count;
+    int iAction = acNoAction;
+    char *pServiceDisplayName = NULL;
+    char *pServiceName = NULL;
+    char *pUserName = NULL;
+    char *pPassword = NULL;
+    char *pMachine = NULL;
+    BOOL bAutomatic = FALSE;
+    char strDependancy[256] = "";
+
+    memset(strDependancy, 0, 255);
+
+    wVersionRequested = MAKEWORD(1, 1); 
+    err = WSAStartup(wVersionRequested, &wsaData);
+    if(0 != err) {
+        fprintf(stderr, "Error connecting to winsock");
+        return;
+    } 
+
+    if(LOBYTE( wsaData.wVersion ) != 1 || 
+       HIBYTE( wsaData.wVersion ) != 1)  {
+        fprintf(stderr, 
+                "Error winsock version is %d %d \n", 
+                LOBYTE( wsaData.wVersion ),HIBYTE( wsaData.wVersion ));
+        WSACleanup();
+        return; 
+    } 
+
+    fprintf(stderr, "Asked (and given) winsock %d.%d \n", 
+                    LOBYTE(wsaData.wVersion),
+                    HIBYTE(wsaData.wVersion));
+
+    __try {
+        if(argc > 2) {
+            count=0;
+            for (i=1;i<argc;i++) {
+                if ((*argv[i] == '-') || (*argv[i] == '/')) {
+                    char *cmd = argv[i];
+                    cmd++;
+                    if(0 == stricmp("i", cmd)) {
+                        iAction = acInstall;
+                        pServiceName = argv[i+1];
+                    } else if(0 == stricmp("r", cmd)) {
+                        iAction = acRemove;
+                        pServiceName = argv[i+1];
+                    } else if(0 == stricmp("s", cmd)) {
+                        iAction = acStartTC;
+                        pServiceName = argv[i+1];
+                    } else if(0 == stricmp("t", cmd)) {
+                        iAction = acStopTC;
+                        pServiceName = argv[i+1];
+                    } else if(0 == stricmp("u", cmd)) {
+                        pUserName = argv[i+1];
+                    } else if(0 == stricmp("p", cmd)) {
+                        pPassword = argv[i+1];
+                    } else if(0 == stricmp("m", cmd)) {
+                        pMachine = argv[i+1];
+                    } else if(0 == stricmp("a", cmd)) {
+                        bAutomatic = TRUE;
+                    } else if(0 == stricmp("n", cmd)) {
+                        pServiceDisplayName = argv[i+1];
+                    } else if(0 == stricmp("d", cmd)) {
+                        memcpy(strDependancy+count, argv[i+1], strlen(argv[i+1]));
+                        count+= strlen(argv[i+1])+1;
+                    }
+                }
+            }
+            switch (iAction) {
+            case acInstall:
+                if (pServiceDisplayName == NULL) {
+                    pServiceDisplayName = pServiceName;
+                }
+                install_service(pServiceName, pServiceDisplayName, pUserName,
+                                pPassword, strDependancy, bAutomatic, argv[i-1]);
+                return;
+            case acRemove:
+                remove_service(pServiceName);
+                return;
+            case acStartTC:
+                start_service(pServiceName, pMachine);
+                return;
+            case acStopTC:
+                stop_service(pServiceName, pMachine);
+                return;
+            }
+        } else if(2  == argc) {
+
+            SERVICE_TABLE_ENTRY dispatchTable[] =
+            {
+                { argv[1], (LPSERVICE_MAIN_FUNCTION)service_main },
+                { NULL, NULL }
+            };
+
+            if(!StartServiceCtrlDispatcher(dispatchTable)) {
+                AddToMessageLog("StartServiceCtrlDispatcher failed.");
+            }
+            return;
+        } 
+
+        usage_message(argv[0]);
+        exit(-1);
+    } __finally {
+        WSACleanup();
+    }
+}
+
+void WINAPI service_main(DWORD dwArgc, char **lpszArgv)
+{
+    // register our service control handler:
+    //
+    //
+    sshStatusHandle = RegisterServiceCtrlHandler(lpszArgv[0], service_ctrl);
+
+    if(sshStatusHandle) {
+
+        ssStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
+        ssStatus.dwServiceSpecificExitCode = 0;
+
+        // report the status to the service control manager.
+        //
+        if(ReportStatusToSCMgr(SERVICE_START_PENDING, // service state
+                                NO_ERROR,              // exit code
+                                3000)) {                 // wait hint    
+            start_jk_service(lpszArgv[0]);
+        }
+    }
+
+    // try to report the stopped status to the service control manager.
+    //
+    if(sshStatusHandle) {
+        ReportStatusToSCMgr(SERVICE_STOPPED,
+                            dwErr,
+                            0);
+    }
+}
+
+
+void WINAPI service_ctrl(DWORD dwCtrlCode)
+{
+    /*
+     * Handle the requested control code.
+     */
+    switch(dwCtrlCode)
+    {
+        /*
+         * Stop the service.
+         */
+        case SERVICE_CONTROL_SHUTDOWN:
+        case SERVICE_CONTROL_STOP:
+            ssStatus.dwCurrentState = SERVICE_STOP_PENDING;
+            stop_jk_service();
+            break;
+
+        /*
+         * Update the service status.
+         */
+        case SERVICE_CONTROL_INTERROGATE:
+            break;
+
+        /*
+         * Invalid control code, nothing to do.
+         */
+        default:
+            break;
+
+    }
+
+    ReportStatusToSCMgr(ssStatus.dwCurrentState, NO_ERROR, 0);
+
+}
+
+BOOL ReportStatusToSCMgr(DWORD dwCurrentState,
+                         DWORD dwWin32ExitCode,
+                         DWORD dwWaitHint)
+{
+    static DWORD dwCheckPoint = 1;
+    BOOL fResult = TRUE;
+
+    if(dwCurrentState == SERVICE_START_PENDING) {
+        ssStatus.dwControlsAccepted = 0;
+    } else {
+        ssStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
+    }
+
+    ssStatus.dwCurrentState = dwCurrentState;
+    ssStatus.dwWin32ExitCode = dwWin32ExitCode;
+    ssStatus.dwWaitHint = dwWaitHint;
+
+    if((dwCurrentState == SERVICE_RUNNING) ||
+       (dwCurrentState == SERVICE_STOPPED)) {
+        ssStatus.dwCheckPoint = 0;
+    } else {
+        ssStatus.dwCheckPoint = dwCheckPoint++;
+    }
+
+    if(!(fResult = SetServiceStatus(sshStatusHandle, &ssStatus))) {
+        AddToMessageLog(TEXT("SetServiceStatus"));
+    }
+
+    return fResult;
+}
+
+typedef WINADVAPI BOOL (WINAPI * pfnChangeServiceConfig2_t)
+                       (SC_HANDLE hService, DWORD dwInfoLevel, LPVOID lpInfo);
+
+
+void install_service(char *name, 
+                     char *dname, 
+                     char *user, 
+                     char *password, 
+                     char *deps, 
+                     BOOL bAutomatic,
+                     char *rel_prp_file)
+{
+    SC_HANDLE   schService;
+    SC_HANDLE   schSCManager;
+    char        szExecPath[2048];
+    char        szPropPath[2048];
+    char        szTrueName[256];
+    char        *dummy;
+    char        *src, *dst;
+
+    dst = szTrueName;
+    for (src = name; *src; ++src) {
+        if (dst >= szTrueName + sizeof(szTrueName) - 1) {
+            break;
+        }
+        if (!isspace(*src) && *src != '/' && *src != '\\') {
+            *(dst++) = *src;
+        }
+    }
+    *dst = '\0';
+
+    if (0 == stricmp("", deps))
+        deps = NULL;
+
+    /* XXX strcat( deps, "Tcpip\0Afd\0" ); */
+    
+    if(!GetFullPathName(rel_prp_file, sizeof(szPropPath) - 1, szPropPath, &dummy)) {
+        printf("Unable to install %s - %s\n", 
+               name, 
+               GetLastErrorText(szErr, sizeof(szErr)));
+        return;
+    }
+
+    if(!jk_file_exists(szPropPath)) {
+        printf("Unable to install %s - File [%s] does not exists\n", 
+               name, 
+               szPropPath);
+        return;
+    }
+
+    szExecPath[0] = '\"';
+    if(GetModuleFileName( NULL, szExecPath + 1, sizeof(szExecPath) - 2) == 0) {
+        /* Was: if(GetModuleFileName( NULL, szExecPath, sizeof(szExecPath) - 1) == 0) { */
+        printf("Unable to install %s - %s\n", 
+               name, 
+               GetLastErrorText(szErr, sizeof(szErr)));
+        return;
+    }
+    strcat(szExecPath, "\" ");
+    strcat(szExecPath, szTrueName);
+
+
+    schSCManager = OpenSCManager(NULL,     // machine (NULL == local)
+                                 NULL,     // database (NULL == default)
+                                 SC_MANAGER_ALL_ACCESS);   // access required                       
+    if(schSCManager) {
+
+        schService = CreateService(schSCManager, // SCManager database
+                                   szTrueName,   // name of service
+                                   dname,         // name to display
+                                   SERVICE_ALL_ACCESS, // desired access
+                                   SERVICE_WIN32_OWN_PROCESS,  // service type
+                                   bAutomatic ? SERVICE_AUTO_START : SERVICE_DEMAND_START,       // start type
+                                   SERVICE_ERROR_NORMAL,       // error control type
+                                   szExecPath,                 // service's binary
+                                   NULL,                       // no load ordering group
+                                   NULL,                       // no tag identifier
+                                   deps,                       // dependencies
+                                   user,                       // account
+                                   password);                  // password
+
+        if(schService) {
+            
+            printf("The service named %s was created. Now adding registry entries\n", name);
+            
+            if(set_registry_values(schService, szTrueName, szPropPath)) {
+                CloseServiceHandle(schService);
+            } else {
+                printf("CreateService failed setting the private registry - %s\n", GetLastErrorText(szErr, sizeof(szErr)));
+                DeleteService(schService);
+                CloseServiceHandle(schService);
+            }
+        } else {
+            printf("CreateService failed - %s\n", GetLastErrorText(szErr, sizeof(szErr)));
+        }
+
+        CloseServiceHandle(schSCManager);
+    } else { 
+        printf("OpenSCManager failed - %s\n", GetLastErrorText(szErr, sizeof(szErr)));
+    }
+}
+
+void remove_service(char *name)
+{
+    SC_HANDLE   schService;
+    SC_HANDLE   schSCManager;
+    char        szNameBuff[256];
+    DWORD       lenNameBuff = 256;
+    char        *szTrueName = name;
+
+    schSCManager = OpenSCManager(NULL,          // machine (NULL == local)
+                                 NULL,          // database (NULL == default)
+                                 SC_MANAGER_ALL_ACCESS );  // access required
+                        
+    if(schSCManager) {
+        if (GetServiceKeyName(schSCManager, name, szNameBuff, &lenNameBuff)) {
+            szTrueName = szNameBuff;
+        }
+        schService = OpenService(schSCManager, szTrueName, SERVICE_ALL_ACCESS);
+
+        if(schService) {
+            // try to stop the service
+            if(ControlService( schService, SERVICE_CONTROL_STOP, &ssStatus )) {
+                printf("Stopping %s.", name);
+                Sleep(1000);
+
+                while(QueryServiceStatus(schService, &ssStatus )) {
+                    if(ssStatus.dwCurrentState == SERVICE_STOP_PENDING) {
+                        printf(".");
+                        Sleep(1000);
+                    } else {
+                        break;
+                    }
+                }
+
+                if(ssStatus.dwCurrentState == SERVICE_STOPPED) {
+                    printf("\n%s stopped.\n", name);
+                } else {
+                    printf("\n%s failed to stop.\n", name);
+                }
+            }
+
+            // now remove the service
+            if(DeleteService(schService)) {
+                printf("%s removed.\n", name);
+            } else {
+                printf("DeleteService failed - %s\n", GetLastErrorText(szErr, sizeof(szErr)));
+            }
+
+            CloseServiceHandle(schService);
+        } else {
+            printf("OpenService failed - %s\n", GetLastErrorText(szErr, sizeof(szErr)));
+        }
+
+        CloseServiceHandle(schSCManager);
+    } else {
+        printf("OpenSCManager failed - %s\n", GetLastErrorText(szErr, sizeof(szErr)));
+    }
+}
+
+void start_service(char *name, char *machine)
+{
+    SC_HANDLE   schService;
+    SC_HANDLE   schSCManager;
+
+    schSCManager = OpenSCManager(machine,  // machine (NULL == local)
+                                 NULL,     // database (NULL == default)
+                                 SC_MANAGER_ALL_ACCESS);   // access required                       
+
+    if(schSCManager) {
+        schService = OpenService(schSCManager, name, SERVICE_ALL_ACCESS);
+ 
+       if(schService) {
+            // try to start the service
+            if(StartService(schService, 0, NULL)) {
+                printf("Starting %s.", name);
+                Sleep(1000);
+
+                while(QueryServiceStatus(schService, &ssStatus )) {
+                    if(ssStatus.dwCurrentState == SERVICE_START_PENDING) {
+                        printf(".");
+                        Sleep(1000);
+                    } else {
+                        break;
+                    }
+                }
+
+                if(ssStatus.dwCurrentState == SERVICE_RUNNING) {
+                    printf("\n%s started.\n", name);
+                } else {
+                    printf("\n%s failed to start.\n", name);
+                }
+            }
+            else
+                printf("StartService failed - %s\n", GetLastErrorText(szErr, sizeof(szErr)));
+
+            CloseServiceHandle(schService);
+        } else {
+            printf("OpenService failed - %s\n", GetLastErrorText(szErr, sizeof(szErr)));
+        }
+
+        CloseServiceHandle(schSCManager);
+    } else {
+        printf("OpenSCManager failed - %s\n", GetLastErrorText(szErr, sizeof(szErr)));
+    }
+}
+
+void stop_service(char *name, char *machine)
+{
+    SC_HANDLE   schService;
+    SC_HANDLE   schSCManager;
+
+    schSCManager = OpenSCManager(machine,  // machine (NULL == local)
+                                 NULL,     // database (NULL == default)
+                                 SC_MANAGER_ALL_ACCESS);   // access required                       
+
+    if(schSCManager) {
+        schService = OpenService(schSCManager, name, SERVICE_ALL_ACCESS);
+
+        if(schService) {
+            // try to stop the service
+            if(ControlService( schService, SERVICE_CONTROL_STOP, &ssStatus )) {
+                printf("Stopping %s.", name);
+                Sleep(1000);
+
+                while(QueryServiceStatus(schService, &ssStatus )) {
+                    if(ssStatus.dwCurrentState == SERVICE_STOP_PENDING) {
+                        printf(".");
+                        Sleep(1000);
+                    } else {
+                        break;
+                    }
+                }
+
+                if(ssStatus.dwCurrentState == SERVICE_STOPPED) {
+                    printf("\n%s stopped.\n", name);
+                } else {
+                    printf("\n%s failed to stop.\n", name);
+                }
+            }
+            else
+                printf("StopService failed - %s\n", GetLastErrorText(szErr, sizeof(szErr)));
+
+            CloseServiceHandle(schService);
+        } else {
+            printf("OpenService failed - %s\n", GetLastErrorText(szErr, sizeof(szErr)));
+        }
+
+        CloseServiceHandle(schSCManager);
+    } else {
+        printf("OpenSCManager failed - %s\n", GetLastErrorText(szErr, sizeof(szErr)));
+    }
+}
+
+static int set_registry_values(SC_HANDLE   schService, char *name, 
+                               char *prp_file)
+{
+    char  tag[1024];
+    HKEY  hk;
+    int rc;
+    /* Api based */
+    HANDLE hAdvApi32;
+    char *szDescription = "Tomcat Server";
+    pfnChangeServiceConfig2_t pfnChangeServiceConfig2;
+            
+    if((hAdvApi32 = GetModuleHandle("advapi32.dll"))
+       && ((pfnChangeServiceConfig2 = (pfnChangeServiceConfig2_t)
+            GetProcAddress(hAdvApi32, "ChangeServiceConfig2A")))) {
+        (void) pfnChangeServiceConfig2(schService, // Service Handle
+                                       1,          // SERVICE_CONFIG_DESCRIPTION
+                                       &szDescription);
+    } else {
+        char value[2024];
+
+        rc = JK_FALSE;
+
+        strcpy(tag, BASE_REGISTRY_LOCATION);
+        strcat(tag, name);
+        
+        if(ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE,
+                                         tag,
+                                         (DWORD)0,         
+                                         KEY_WRITE | KEY_READ,
+                                         &hk)) {
+            rc = get_registry_config_parameter(hk,
+                                               IMAGE_NAME, 
+                                               value,
+                                               sizeof(value));
+            if(rc) {
+                strcat(value, " ");
+                strcat(value, name);
+                rc = set_registry_config_parameter(hk,
+                                                   IMAGE_NAME, 
+                                                   value);
+                if(rc) {
+                    printf("Registry values were added\n");
+                    printf("If you have already updated wrapper.properties you may start the %s"
+                           "service by executing \"jk_nt_service -s %s\" from the command prompt\n",
+                           name,
+                           name);                    
+                }
+            }
+            RegCloseKey(hk);
+        }
+        if(!rc) {
+            printf("Error: Failed to update the service command line - %s\n", 
+                   GetLastErrorText(szErr, sizeof(szErr)));                
+        }
+    }
+    
+    strcpy(tag, BASE_REGISTRY_LOCATION);
+    strcat(tag, name);
+    strcat(tag, "\\");
+    strcat(tag, PARAMS_LOCATION);
+
+    rc = create_registry_key(tag, &hk);
+
+    if(rc) {
+        rc = set_registry_config_parameter(hk, PRP_LOCATION, prp_file);
+        if(!rc) {
+            printf("Error: Can not create value [%s] - %s\n", 
+                    PRP_LOCATION, 
+                    GetLastErrorText(szErr, sizeof(szErr)));                
+        }
+        RegCloseKey(hk);
+    } else {
+        printf("Error: Can not create key [%s] - %s\n", 
+                tag, 
+                GetLastErrorText(szErr, sizeof(szErr)));                
+    }
+    return rc;
+}
+
+static void start_jk_service(char *name)
+{
+    /*
+     * report the status to the service control manager.
+     */
+    if(ReportStatusToSCMgr(SERVICE_START_PENDING, // service state
+                           NO_ERROR,              // exit code
+                           3000)) {               // wait hint
+        
+        /* 
+         * create the event object. The control handler function signals
+         * this event when it receives the "stop" control code.
+         */
+        hServerStopEvent = CreateEvent(NULL,    // no security attributes
+                                       TRUE,    // manual reset event
+                                       FALSE,   // not-signalled
+                                       NULL);   // no name
+
+        if(hServerStopEvent) {
+            if(ReportStatusToSCMgr(SERVICE_START_PENDING, // service state
+                                   NO_ERROR,              // exit code
+                                   20000)) {              // wait hint
+                HANDLE hTomcat = NULL;
+                char   szNameBuff[256];
+                DWORD  lenNameBuff = 256;
+                char   *szTrueName = name;
+                SC_HANDLE   schSCManager;
+                int rc;
+
+                schSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS );
+                if(schSCManager) {
+                    if (GetServiceKeyName(schSCManager, name, szNameBuff, &lenNameBuff)) {
+                        szTrueName = szNameBuff;
+                    }
+                    CloseServiceHandle(schSCManager);
+                }
+
+                rc = start_tomcat(szTrueName, &hTomcat);
+
+                if(rc && ReportStatusToSCMgr(SERVICE_RUNNING, // service state
+                                             NO_ERROR,        // exit code
+                                             0)) {            // wait hint       
+                    HANDLE waitfor[] = { hServerStopEvent, hTomcat};
+                    DWORD dwIndex = WaitForMultipleObjects(2, waitfor, FALSE, INFINITE);
+
+                    switch(dwIndex) {
+                    case WAIT_OBJECT_0:
+                        /* 
+                         * Stop order arrived 
+                         */ 
+                        ResetEvent(hServerStopEvent);
+                        stop_tomcat(name, shutdown_port, shutdown_protocol,
+                                    shutdown_secret, hTomcat);
+                        break;
+                    case (WAIT_OBJECT_0 + 1):
+                        /* 
+                         * Tomcat died !!!
+                         */ 
+                        CloseHandle(hServerStopEvent);
+                        CloseHandle(hTomcat);
+                        exit(0); // exit ungracefully so
+                                 // Service Control Manager 
+                                 // will attempt a restart.
+                        break;
+                    default:
+                        /* 
+                         * some error... 
+                         * close the servlet container and exit 
+                         */ 
+                        stop_tomcat(name, shutdown_port, shutdown_protocol,
+                                    shutdown_secret, hTomcat);
+                    }
+                    CloseHandle(hServerStopEvent);
+                    CloseHandle(hTomcat);
+                }                
+            }
+        }
+    }
+
+    if(hServerStopEvent) {
+        CloseHandle(hServerStopEvent);
+    }
+}
+
+
+static void stop_jk_service(void)
+{
+    if(hServerStopEvent) {
+        SetEvent(hServerStopEvent);
+    }
+}
+
+static void AddToMessageLog(char *lpszMsg)
+{   
+    char    szMsg[2048];
+    HANDLE  hEventSource;
+    char *  lpszStrings[2];
+
+    printf("Error: %s\n", lpszMsg);
+
+    dwErr = GetLastError();
+
+    hEventSource = RegisterEventSource(NULL, "Tomcat");
+
+    sprintf(szMsg, "%s error: %d", "Tomcat", dwErr);
+    lpszStrings[0] = szMsg;
+    lpszStrings[1] = lpszMsg;
+
+    if(hEventSource != NULL) {
+        ReportEvent(hEventSource, // handle of event source
+            EVENTLOG_ERROR_TYPE,  // event type
+            0,                    // event category
+            0,                    // event ID
+            NULL,                 // current user's SID
+            2,                    // strings in lpszStrings
+            0,                    // no bytes of raw data
+            lpszStrings,          // array of error strings
+            NULL);                // no raw data
+
+        DeregisterEventSource(hEventSource);
+    }
+    
+}
+
+//
+//  FUNCTION: GetLastErrorText
+//
+//  PURPOSE: copies error message text to string
+//
+//  PARAMETERS:
+//    lpszBuf - destination buffer
+//    dwSize - size of buffer
+//
+//  RETURN VALUE:
+//    destination buffer
+//
+//  COMMENTS:
+//
+char *GetLastErrorText( char *lpszBuf, DWORD dwSize )
+{
+    DWORD dwRet;
+    char *lpszTemp = NULL;
+
+    dwRet = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |FORMAT_MESSAGE_ARGUMENT_ARRAY,
+                          NULL,
+                          GetLastError(),
+                          LANG_NEUTRAL,
+                          (char *)&lpszTemp,
+                          0,
+                          NULL);
+
+    // supplied buffer is not long enough
+    if(!dwRet || ((long)dwSize < (long)dwRet+14)) {
+        lpszBuf[0] = '\0';
+    } else {
+        lpszTemp[lstrlen(lpszTemp)-2] = '\0';  //remove cr and newline character
+        sprintf(lpszBuf, "%s (0x%x)", lpszTemp, GetLastError());
+    }
+
+    if(lpszTemp) {
+        LocalFree((HLOCAL) lpszTemp );
+    }
+
+    return lpszBuf;
+}
+
+static void stop_tomcat(char *name,
+                        int port, 
+                        const char *protocol,
+                        char *secret,
+                        HANDLE hTomcat)
+{
+    struct sockaddr_in in;
+
+    if(strcasecmp(protocol, "cmd") == 0 ) {
+        exec_cmd( name, hTomcat, shutdown_cmd);
+        /* XXX sleep 100 */
+        TerminateProcess(hTomcat, 0);
+        return;
+    } 
+    
+    if(jk_resolve("localhost", port, &in)) {
+        int sd = jk_open_socket(&in, JK_TRUE, 0, -1, NULL);
+        if(sd >0) {
+            int rc = JK_FALSE;
+
+            if(strcasecmp(protocol, "catalina") == 0 ) {
+                char len;
+                
+                if( secret==NULL )
+                    secret="SHUTDOWN";
+                len=strlen( secret );
+                
+                rc = send(sd, secret, len , 0);
+                if(len == rc) {
+                    rc = JK_TRUE;
+                }
+            } else if(!strcasecmp(protocol, "ajp13")) {
+                jk_pool_t pool;
+                jk_msg_buf_t *msg = NULL;
+                jk_pool_atom_t buf[TINY_POOL_SIZE];
+
+                jk_open_pool(&pool, buf, sizeof(buf));
+
+                msg = jk_b_new(&pool);
+                jk_b_set_buffer_size(msg, 512); 
+
+                rc = ajp13_marshal_shutdown_into_msgb(msg, 
+                                                      &pool,
+                                                      NULL);
+                if( secret!=NULL ) {
+                    /** will work with old clients, as well as new
+                     */
+                    rc = jk_b_append_string(msg, secret);
+                }
+                if(rc) {
+                    jk_b_end(msg, AJP13_PROTO);
+    
+                    if(0 > jk_tcp_socket_sendfull(sd, 
+                                                  msg->buf,
+                                                  msg->len)) {
+                        rc = JK_FALSE;
+                    }
+                }                                                    
+            } else {
+                char b[] = {(char)254, (char)15};
+                rc = send(sd, b, 2, 0);
+                if(2 == rc) {
+                    rc = JK_TRUE;
+                }
+            }
+            jk_close_socket(sd);
+            if(JK_TRUE == rc) {
+                if(WAIT_OBJECT_0 == WaitForSingleObject(hTomcat, 30*1000)) {
+                    return;
+                }
+            }            
+        }
+    }
+
+    TerminateProcess(hTomcat, 0);    
+}
+
+static int exec_cmd(const char *name, HANDLE *hTomcat, char *cmdLine)
+{
+    char  tag[1024];
+    HKEY  hk;
+
+    strcpy(tag, BASE_REGISTRY_LOCATION);
+    strcat(tag, name);
+    strcat(tag, "\\");
+    strcat(tag, PARAMS_LOCATION);
+
+    if(ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE,
+                                     tag,
+                                     (DWORD)0,         
+                                     KEY_READ,
+                                     &hk)) {
+        char prp_file[2048];
+        if(get_registry_config_parameter(hk,
+                                         PRP_LOCATION, 
+                                         prp_file,
+                                         sizeof(prp_file))) {
+            jk_map_t *init_map;
+            
+            if(jk_map_alloc(&init_map)) {
+                if(jk_map_read_properties(init_map, prp_file, NULL, NULL)) {
+                    jk_tomcat_startup_data_t data;
+                    jk_pool_t p;
+                    jk_pool_atom_t buf[HUGE_POOL_SIZE];
+                    jk_open_pool(&p, buf, sizeof(buf));
+            
+                    if(read_startup_data(init_map, &data, &p)) {
+                        STARTUPINFO startupInfo;
+                        PROCESS_INFORMATION processInformation;
+                        SECURITY_ATTRIBUTES sa = { sizeof(SECURITY_ATTRIBUTES), NULL, TRUE };
+
+                        if(data.extra_path) {
+                            jk_append_libpath(&p, data.extra_path);
+                        }
+
+                        memset(&startupInfo, 0, sizeof(startupInfo));
+                        startupInfo.cb = sizeof(startupInfo);
+                        startupInfo.lpTitle = "Tomcat";
+                        startupInfo.dwFlags = STARTF_USESTDHANDLES;
+                        startupInfo.hStdInput = NULL;
+                        startupInfo.hStdOutput = CreateFile(data.stdout_file,
+                                                            GENERIC_WRITE,
+                                                            FILE_SHARE_READ,
+                                                            &sa,
+                                                            OPEN_ALWAYS,
+                                                            FILE_ATTRIBUTE_NORMAL,
+                                                            NULL);
+                        SetFilePointer(startupInfo.hStdOutput,
+                                       0,
+                                       NULL,
+                                       FILE_END);
+                        startupInfo.hStdError = CreateFile(data.stderr_file,
+                                                           GENERIC_WRITE,
+                                                           FILE_SHARE_READ,
+                                                           &sa,
+                                                           OPEN_ALWAYS,
+                                                           FILE_ATTRIBUTE_NORMAL,
+                                                           NULL);
+                        SetFilePointer(startupInfo.hStdError,
+                                       0,
+                                       NULL,
+                                       FILE_END);
+
+                        memset(&processInformation, 0, sizeof(processInformation));
+                        
+						if( cmdLine==NULL ) 
+							cmdLine=data.cmd_line;
+
+                        printf(cmdLine);
+                        if(CreateProcess(data.java_bin,
+                                        cmdLine,
+                                        NULL,
+                                        NULL,
+                                        TRUE,
+                                        CREATE_NEW_CONSOLE,
+                                        NULL,
+                                        data.tomcat_home,
+                                        &startupInfo,
+                                        &processInformation)){
+
+                            *hTomcat = processInformation.hProcess;
+                            CloseHandle(processInformation.hThread);
+                            CloseHandle(startupInfo.hStdOutput);
+                            CloseHandle(startupInfo.hStdError);
+
+                            shutdown_port = data.shutdown_port;
+                            shutdown_secret = data.shutdown_secret;
+                            shutdown_protocol = strdup(data.shutdown_protocol);
+							shutdown_cmd = strdup(data.stop_cmd);
+
+                            return JK_TRUE;
+                        } else {
+                            printf("Error: Can not create new process - %s\n", 
+                                    GetLastErrorText(szErr, sizeof(szErr)));                
+                        }
+
+                    }                    
+                }
+            }
+            jk_map_free(&init_map);
+        }
+        RegCloseKey(hk);
+    } 
+
+    return JK_FALSE;
+}
+
+static int start_tomcat(const char *name, HANDLE *hTomcat)
+{
+    return exec_cmd( name, hTomcat, NULL );
+}
+
+static int create_registry_key(const char *tag,
+                               HKEY *key)
+{
+    LONG  lrc = RegCreateKeyEx(HKEY_LOCAL_MACHINE,
+                               tag,
+                               0,
+                               NULL,
+                               REG_OPTION_NON_VOLATILE,
+                               KEY_WRITE,
+                               NULL,
+                               key,
+                               NULL);
+    if(ERROR_SUCCESS != lrc) {
+        return JK_FALSE;        
+    }
+
+    return JK_TRUE;
+}
+
+static int set_registry_config_parameter(HKEY hkey,
+                                         const char *tag, 
+                                         char *value)
+{       
+    LONG  lrc;
+
+    lrc = RegSetValueEx(hkey, 
+                        tag,            
+                        0,              
+                        REG_SZ,  
+                        value, 
+                        strlen(value));
+
+    if(ERROR_SUCCESS != lrc) {
+        return JK_FALSE;        
+    }
+
+    return JK_TRUE;     
+}
+
+
+
+static int get_registry_config_parameter(HKEY hkey,
+                                         const char *tag, 
+                                         char *b,
+                                         DWORD sz)
+{   
+    DWORD type = 0;
+    LONG  lrc;
+
+    lrc = RegQueryValueEx(hkey,     
+                          tag,      
+                          (LPDWORD)0,
+                          &type,    
+                          (LPBYTE)b,
+                          &sz); 
+    if(ERROR_SUCCESS != lrc) {
+        return JK_FALSE;        
+    }
+    
+    b[sz] = '\0';
+
+    return JK_TRUE;     
+}
+
+static int read_startup_data(jk_map_t *init_map, 
+                             jk_tomcat_startup_data_t *data, 
+                             jk_pool_t *p)
+{
+    
+    data->classpath = NULL;
+    data->tomcat_home = NULL;
+    data->stdout_file = NULL;
+    data->stderr_file = NULL;
+    data->java_bin = NULL;
+    data->extra_path = NULL;
+    data->tomcat_class = NULL;
+    data->server_file = NULL;
+
+    /* All this is wrong - you just need to configure cmd_line */
+    /* Optional - you may have cmd_line defined */
+    data->server_file = jk_map_get_string(init_map, 
+                                          "wrapper.server_xml", 
+                                          NULL);
+    data->classpath = jk_map_get_string(init_map, 
+                                        "wrapper.class_path", 
+                                        NULL);
+    data->tomcat_home = jk_map_get_string(init_map, 
+                                          "wrapper.tomcat_home", 
+                                          NULL);
+    data->java_bin = jk_map_get_string(init_map, 
+                                       "wrapper.javabin", 
+                                       NULL);
+    data->tomcat_class = jk_map_get_string(init_map,
+                                           "wrapper.startup_class",
+                                           "org.apache.tomcat.startup.Tomcat");
+
+    data->cmd_line = jk_map_get_string(init_map,
+                                       "wrapper.cmd_line",
+                                       NULL);
+
+    data->stop_cmd = jk_map_get_string(init_map,
+                                       "wrapper.stop_cmd",
+                                       NULL);
+
+    if(NULL == data->cmd_line &&
+       ( (NULL == data->tomcat_class) ||
+         (NULL == data->server_file) ||
+         (NULL == data->tomcat_home) ||
+         (NULL == data->java_bin) )) {
+       return JK_FALSE;
+    }
+
+    if(NULL == data->cmd_line) {
+        data->cmd_line = (char *)jk_pool_alloc(p, (20 + 
+                                                   strlen(data->java_bin) +
+                                                   strlen(" -classpath ") +
+                                                   strlen(data->classpath) +
+                                                   strlen(data->tomcat_class) +
+                                                   strlen(" -home ") +
+                                                   strlen(data->tomcat_home) +
+                                                   strlen(" -config ") +
+                                                   strlen(data->server_file)
+                                                   ) * sizeof(char));
+        if(NULL == data->cmd_line) {
+            return JK_FALSE;
+        }
+
+        strcpy(data->cmd_line, data->java_bin);
+        strcat(data->cmd_line, " -classpath ");
+        strcat(data->cmd_line, data->classpath);
+        strcat(data->cmd_line, " ");
+        strcat(data->cmd_line, data->tomcat_class);
+        strcat(data->cmd_line, " -home ");
+        strcat(data->cmd_line, data->tomcat_home);
+        strcat(data->cmd_line, " -config ");
+        strcat(data->cmd_line, data->server_file);
+    }
+
+    data->shutdown_port = jk_map_get_int(init_map,
+                                         "wrapper.shutdown_port",
+                                         8007);
+
+    data->shutdown_secret = jk_map_get_string(init_map,
+                                              "wrapper.shutdown_secret", 
+                                              NULL);
+    
+    data->shutdown_protocol = jk_map_get_string(init_map,
+                                                "wrapper.shutdown_protocol",
+                                                AJP12_TAG);
+
+    data->extra_path = jk_map_get_string(init_map,
+                                         "wrapper.ld_path",
+                                         NULL);
+
+    data->stdout_file = jk_map_get_string(init_map,
+                                          "wrapper.stdout",
+                                          NULL);
+
+    if(NULL == data->stdout_file && NULL == data->tomcat_home ) {
+        return JK_FALSE;
+    }
+    
+    if(NULL == data->stdout_file) {
+        data->stdout_file = jk_pool_alloc(p, strlen(data->tomcat_home) + 2 + strlen("\\stdout.log"));
+        strcpy(data->stdout_file, data->tomcat_home);
+        strcat(data->stdout_file, "\\stdout.log");        
+    }
+
+    data->stderr_file = jk_map_get_string(init_map,
+                                          "wrapper.stderr",
+                                          NULL);
+
+    if(NULL == data->stderr_file) {
+        data->stderr_file = jk_pool_alloc(p, strlen(data->tomcat_home) + 2 + strlen("\\stderr.log"));
+        strcpy(data->stderr_file, data->tomcat_home);
+        strcat(data->stderr_file, "\\stderr.log");        
+    }
+
+    return JK_TRUE;
+}
+

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/nt_service/nt_service.dsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/nt_service/nt_service.dsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/nt_service/nt_service.dsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,199 @@
+# Microsoft Developer Studio Project File - Name="nt_service" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=nt_service - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE 
+!MESSAGE NMAKE /f "nt_service.mak".
+!MESSAGE 
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE 
+!MESSAGE NMAKE /f "nt_service.mak" CFG="nt_service - Win32 Debug"
+!MESSAGE 
+!MESSAGE Possible choices for configuration are:
+!MESSAGE 
+!MESSAGE "nt_service - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "nt_service - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE 
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF  "$(CFG)" == "nt_service - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /FD /c
+# ADD CPP /nologo /W3 /GX /Zi /O2 /I "../common" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /Fd"Release/jk_nt_service_src" /FD /c
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+# ADD LINK32 wsock32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /out:"Release/jk_nt_service.exe" /opt:ref
+
+!ELSEIF  "$(CFG)" == "nt_service - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MD /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FD /c
+# ADD CPP /nologo /MD /W3 /Gm /GX /Zi /Od /I "../common" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /Fd"Debug/jk_nt_service_src" /FD /c
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 wsock32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /out:"Debug/jk_nt_service.exe"
+
+!ENDIF 
+
+# Begin Target
+
+# Name "nt_service - Win32 Release"
+# Name "nt_service - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# Begin Source File
+
+SOURCE=..\common\jk_ajp13.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_connect.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_map.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_msg_buff.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\jk_nt_service.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_pool.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_util.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_ajp14.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_ajp14_worker.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_md5.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_context.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_uri_worker_map.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_ajp_common.c
+# End Source File
+# End Group
+
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl"
+# Begin Source File
+
+SOURCE=..\common\jk_connect.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_global.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_logger.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_uri_worker_map.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_map.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_pool.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_service.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_util.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_ajp14.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_ajp14_worker.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_md5.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_context.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\common\jk_ajp_common.h
+# End Source File
+# End Group
+# End Target
+# End Project

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/scripts/build/config_vars.mk
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/scripts/build/config_vars.mk	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/scripts/build/config_vars.mk	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,2 @@
+# libtool is given by Apache-2.0 when installed otherwise we provide it.
+LIBTOOL      = $(SHELL) ../libtool

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/scripts/build/rules.mk
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/scripts/build/rules.mk	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/scripts/build/rules.mk	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,28 @@
+# That an extract of what is in APR.
+#
+
+# Compile commands
+#VPATH=.:../common
+COMPILE      = $(CC) $(CFLAGS)
+LT_COMPILE   = $(LIBTOOL) --mode=compile $(COMPILE) -c $< -o $@
+
+# Implicit rules for creating outputs from input files
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .slo .s
+
+.c.o:
+	$(COMPILE) -c $<
+
+.s.o:
+	$(COMPILE) -c $<
+
+.c.lo:
+	$(LT_COMPILE)
+
+.s.lo:
+	$(LT_COMPILE)
+
+.c.slo:
+	$(SH_COMPILE)
+

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/native/scripts/build/unix/dummy
===================================================================

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/support/apache.m4
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/support/apache.m4	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/support/apache.m4	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,196 @@
+dnl
+dnl apache.m4: autoconf macro for Apache/apxs
+dnl
+
+dnl
+dnl check for apxs.
+dnl
+
+AC_DEFUN(JTC_CHECK_APXS,[
+WEBSERVER=""
+apache_dir=""
+apache_include=""
+APXS="apxs"
+AC_ARG_WITH(apxs,
+[  --with-apxs[=FILE]      Build shared Apache module. FILE is the optional
+                        pathname to the apxs tool; defaults to finding
+			apxs in your PATH.],
+[
+    case "${withval}" in 
+        y | yes | true) find_apxs=true ;;
+        n | no | false) find_apxs=false ;;
+        *) find_apxs=false ;;
+    esac
+
+    if ${TEST} ${find_apxs} ; then    
+        AC_MSG_RESULT([need to check for Perl first, apxs depends on it...])
+        AC_PATH_PROG(PERL,perl,$PATH)dnl
+    
+        if ${TEST} ${find_apxs} ; then
+            APXS=${withval}
+        else
+            AC_PATH_PROG(APXS,apxs,$PATH)dnl
+        fi
+    
+        if ${TEST} -n "${APXS}" ; then
+            dnl Seems that we have it, but have to check if it is OK first        
+            if ${TEST} ! -x "${APXS}" ; then
+                AC_MSG_ERROR(Invalid location for apxs: '${APXS}')
+            fi
+            
+            $APXS -q PREFIX >/dev/null 2>/dev/null || apxs_support=false
+    
+            if ${TEST} "${apxs_support}" = "false" ; then
+                AC_MSG_RESULT(could not find apxs)
+                AC_MSG_ERROR(You must specify a valid --with-apxs path)
+            fi
+
+            dnl test apache version
+            $RM -rf test
+            $APXS -n test -g
+            APA=`grep STANDARD20 test/mod_test.c`
+            $RM -rf test
+            if ${TEST} -z "$APA" ; then
+                WEBSERVER="apache-1.3"
+            else
+                WEBSERVER="apache-2.0"
+            fi
+            AC_MSG_RESULT([building connector for \"$WEBSERVER\"])
+    
+            AC_SUBST(APXS)
+
+            dnl apache_dir and apache_include are also needed.
+	    apache_dir=`$APXS -q PREFIX`
+	    apache_include="-I`$APXS -q INCLUDEDIR`"
+        fi
+    fi
+],
+[
+	AC_MSG_RESULT(no apxs given)
+])
+])dnl
+
+dnl
+dnl check for apache (static link).
+dnl
+
+AC_DEFUN(JTC_CHECK_APACHE,[
+
+dnl it is copied from the configure of JServ ;=)
+dnl and adapted. 
+
+apache_dir_is_src="false"
+AC_ARG_WITH(apache,
+[  --with-apache=DIR      Build static Apache module. DIR is the pathname 
+                        to the Apache source directory.],
+[
+    if ${TEST} ! -z "$WEBSERVER" ; then
+        AC_MSG_ERROR([Sorry cannot use --with-apxs=${APXS} and --with-apache=${withval} togother, please choose one of both])
+    fi
+
+    AC_MSG_CHECKING([for Apache source directory (assume static build)])
+
+    if ${TEST} -n "${withval}" && ${TEST} -d "${withval}" ; then
+        if ${TEST} -d "${withval}/src" ; then
+           # handle the case where people use relative paths to 
+           # the apache source directory by pre-pending the current
+           # build directory to the path. there are probably 
+           # errors with this if configure is run while in a 
+           # different directory than what you are in at the time
+           if ${TEST} -n "`${ECHO} ${withval}|${GREP} \"^\.\.\"`" ; then
+               withval=`pwd`/${withval}
+           fi
+
+           apache_dir=${withval}
+           apache_dir_is_src="true"
+           AC_MSG_RESULT(${apache_dir})
+        
+           AC_MSG_CHECKING(for Apache include directory)
+
+           if ${TEST} -d "${withval}/src/include" ; then
+               # read osdir from the existing apache.
+               osdir=`${GREP} '^OSDIR=' ${withval}/src/Makefile.config | ${SED} -e 's:^OSDIR=.*/os:os:'`
+               if ${TEST} -z "${osdir}" ; then
+                   osdir=os/unix
+               fi
+               apache_include="-I${withval}/src/include \
+                   -I${withval}/src/${osdir}"
+               WEBSERVER="apache-1.3"
+               AC_MSG_RESULT([${apache_include}, version 1.3])
+           else
+               AC_MSG_ERROR([Sorry Apache 1.2.x is no longer supported.])
+           fi
+        else
+           if ${TEST} -d "${withval}/include" ; then
+              # osdir for Apache20.
+              WEBSERVER="apache-2.0"
+              apache_dir=${withval}
+              apache_dir_is_src="true"
+              AC_MSG_RESULT(${apache_dir})
+           fi
+        fi
+    fi
+
+    dnl Make sure we have a result.
+    if ${TEST} -z "$WEBSERVER" ; then
+        AC_MSG_ERROR([Directory $apache_dir is not a valid Apache source distribution])
+    fi
+
+# VT: Now, which one I'm supposed to use? Let's figure it out later
+
+    configure_apache=true
+    configure_src=true
+    
+    AC_MSG_RESULT([building connector for \"$WEBSERVER\"])
+],
+[
+	AC_MSG_RESULT(no apache given)
+])
+AC_SUBST(apache_include)
+APACHE_DIR=${apache_dir}
+AC_SUBST(APACHE_DIR)
+])
+
+dnl
+dnl check for EAPI (static link only).
+dnl
+
+AC_DEFUN(JTC_CHECK_EAPI,[
+
+dnl CFLAGS for EAPI mod_ssl (Apache 1.3)
+dnl it also allows the CFLAGS environment variable.
+CFLAGS="${CFLAGS}"
+AC_ARG_ENABLE(
+EAPI,
+[  --enable-EAPI           Enable EAPI support (mod_ssl, Apache 1.3)],
+[
+case "${enableval}" in
+    y | Y | YES | yes | TRUE | true )
+        CFLAGS="${CFLAGS} -DEAPI"
+        AC_MSG_RESULT([...Enabling EAPI Support...])
+        ;;
+esac
+])
+AC_SUBST(CFLAGS)
+])
+
+
+dnl
+dnl set flags for apxs.
+dnl
+
+AC_DEFUN(JTC_SET_APXS_FLAGS,[
+dnl the APXSCFLAGS is given by apxs to the C compiler
+dnl the APXSLDFLAGS is given to the linker (for APRVARS).
+APXSLDFLAGS=""
+APXSCFLAGS=""
+if ${TEST} -n "${CFLAGS}" ; then
+	APXSCFLAGS="${CFLAGS}"
+fi
+dnl the APXSLDFLAGS is normaly empty but APXSCFLAGS is not.
+if ${TEST} -n "${LDFLAGS}" ; then
+	APXSLDFLAGS="-Wl,${LDFLAGS}"
+fi
+AC_SUBST(APXSCFLAGS)
+AC_SUBST(APXSLDFLAGS)
+])

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/support/get_ver.awk
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/support/get_ver.awk	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/support/get_ver.awk	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,67 @@
+BEGIN {
+
+  # fetch mod_jk version numbers from input file and writes them to STDOUT
+
+  while ((getline < ARGV[1]) > 0) {
+    if (match ($0, /^#define JK_VERMAJOR [^"]+/)) {
+      jk_ver_major = substr($3, 1, length($3));
+    }
+    else if (match ($0, /^#define JK_VERMINOR [^"]+/)) {
+      jk_ver_minor = substr($3, 1, length($3));
+    }
+    else if (match ($0, /^#define JK_VERFIX [^"]+/)) {
+      jk_ver_fix = substr($3, 1, length($3));
+    }
+    else if (match ($0, /^#define JK_VERISRELEASE [^"]+/)) {
+      jk_ver_isrelease = substr($3, 1, length($3));
+    }
+    else if (match ($0, /^#define JK_VERBETA [^"]+/)) {
+      jk_ver_isbeta = substr($3, 1, length($3));
+    }
+    else if (match ($0, /^#define JK_BETASTRING [^"]+/)) {
+      jk_ver_betastr = substr($3, 2, length($3) - 2);
+    }
+  }
+  jk_ver = jk_ver_major "," jk_ver_minor "," jk_ver_fix;
+  jk_ver_str = jk_ver_major "." jk_ver_minor "." jk_ver_fix;
+  if (jk_ver_isrelease != 1) {
+    jk_ver_str = jk_ver_str "-dev";
+  }
+  if (jk_ver_isbeta == 1) {
+    jk_ver_str = jk_ver_str "-beta-" jk_ver_betastr;
+  }
+  
+  # fetch Apache version numbers from input file and writes them to STDOUT
+
+  if (ARGV[2]) {
+    if (match (ARGV[2], /ap_release.h/)) {
+      while ((getline < ARGV[2]) > 0) {
+        if (match ($0, /^#define AP_SERVER_MAJORVERSION "[^"]+"/)) {
+          ap_ver_major = substr($3, 2, length($3) - 2);
+        }
+        else if (match ($0, /^#define AP_SERVER_MINORVERSION "[^"]+"/)) {
+          ap_ver_minor = substr($3, 2, length($3) - 2);
+        }
+        else if (match ($0, /^#define AP_SERVER_PATCHLEVEL/)) {
+          ap_ver_str_patch = substr($3, 2, length($3) - 2);
+          if (match (ap_ver_str_patch, /[0-9][0-9]*/)) {
+            ap_ver_patch = substr(ap_ver_str_patch, RSTART, RLENGTH); 
+          }
+        }
+      }
+      ap_ver_str = ap_ver_major "." ap_ver_minor "." ap_ver_str_patch;
+    }
+    if (match (ARGV[2], /httpd.h/)) {
+      while ((getline < ARGV[2]) > 0) {
+        if (match ($0, /^#define SERVER_BASEREVISION "[^"]+"/)) {
+          ap_ver_str = substr($3, 2, length($3) - 2);
+        }
+      }
+    }
+    print "AP_VERSION_STR = " ap_ver_str "";
+  }
+
+  print "JK_VERSION = " jk_ver "";
+  print "JK_VERSION_STR = " jk_ver_str "";
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/support/jk_apache_static.m4
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/support/jk_apache_static.m4	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/support/jk_apache_static.m4	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,132 @@
+dnl
+dnl Copyright 1999-2004 The Apache Software Foundation
+dnl
+dnl Licensed under the Apache License, Version 2.0 (the "License");
+dnl you may not use this file except in compliance with the License.
+dnl You may obtain a copy of the License at
+dnl
+dnl     http://www.apache.org/licenses/LICENSE-2.0
+dnl
+dnl Unless required by applicable law or agreed to in writing, software
+dnl distributed under the License is distributed on an "AS IS" BASIS,
+dnl WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+dnl See the License for the specific language governing permissions and
+dnl limitations under the License.
+dnl
+
+dnl --------------------------------------------------------------------------
+dnl Author Henri Gomez <hgomez at apache.org>
+dnl
+dnl Inspired by Pier works on webapp m4 macros :)
+dnl 
+dnl Version $Id: jk_apache_static.m4 300972 2005-07-12 19:38:18Z wrowe $
+dnl --------------------------------------------------------------------------
+
+dnl Apache-2.0 needs the os subdirectory to include os.h
+dnl this include is copy from os/config.m4
+sinclude(os_apache.m4)
+
+dnl --------------------------------------------------------------------------
+dnl JK_APACHE_STATIC
+dnl   Set the APACHE 1.3/2.0 source dir.
+dnl   $1 => apache source dir to detect ("", 2)
+dnl   $2 => apache 1.3 build dir 
+dnl   $3 => apache 2.0 build dir
+dnl
+dnl --------------------------------------------------------------------------
+AC_DEFUN(
+  [JK_APACHE_STATIC],
+  [
+    tempval=""
+
+    AC_ARG_WITH(
+      [apache$1],
+      [  --with-apache$1=DIR  Location of Apache$2 source dir],
+      [
+        if ${TEST} ${use_apxs$1} ; then
+          AC_MSG_ERROR([Sorry cannot use --with-apxs= and --with-apache= together, please choose one])
+        fi
+
+        AC_MSG_CHECKING([for Apache source directory (assume static build)])
+        
+        if ${TEST} -n "${withval}" && ${TEST} -d "${withval}" ; then
+
+          if ${TEST} -d "${withval}/src" ; then
+            # handle the case where people use relative paths to 
+            # the apache source directory by pre-pending the current
+            # build directory to the path. there are probably 
+            # errors with this if configure is run while in a 
+            # different directory than what you are in at the time
+            if ${TEST} -n "`${ECHO} ${withval}|${GREP} \"^\.\.\"`" ; then
+              withval=`pwd`/${withval}
+            fi
+
+            APACHE$1_DIR=${withval}
+            use_static="true"
+            AC_MSG_RESULT(${APACHE$1_DIR})
+        
+            AC_MSG_CHECKING(for Apache include directory)
+
+            if ${TEST} -d "${withval}/src/include" ; then
+              # read osdir from the existing apache.
+              osdir=`${GREP} '^OSDIR=' ${withval}/src/Makefile.config | ${SED} -e 's:^OSDIR=.*/os:os:'`
+
+              if ${TEST} -z "${osdir}" ; then
+                osdir=os/unix
+              fi
+
+              APACHE$1_DIR=${withval}
+              APACHE$1_HOME=${withval}
+              APACHE$1_INCL="-I${withval}/src/include -I${withval}/src/${osdir}"
+              EXTRA_CFLAGS=""
+              EXTRA_CPPFLAGS=""
+              REPORTED_SERVER="apache-1.3"
+              SERVER_DIR="$3"
+              use_static="true"
+              use_apache13="true"
+              AC_MSG_RESULT([${APACHE$1_INCL}, version 1.3])
+            else
+              AC_MSG_ERROR([Sorry Apache 1.2.x is no longer supported.])
+            fi
+
+          else
+
+            if ${TEST} -d "${withval}/include" ; then
+              # osdir for Apache20.
+              APACHE$1_DIR=${withval}
+              APACHE$1_HOME=${withval}
+              APACHE$1_INCL="-I${withval}/include -I${withval}/srclib/apr/include -I${withval}/os/${OS_APACHE_DIR} -I${withval}/srclib/apr-util/include"
+              EXTRA_CFLAGS=""
+              EXTRA_CPPFLAGS=""
+              REPORTED_SERVER="apache-2.0"
+              SERVER_DIR="$3"
+              use_static="true"
+              use_apache2="true"
+              APACHE$1_INCL="-I${withval}/include -I${withval}/srclib/apr/include -I${withval}/os/${OS_APACHE_DIR} -I${withval}/srclib/apr-util/include"
+              AC_MSG_RESULT(${APACHE$1_DIR})
+
+              
+              JK_CHANNEL_APR_SOCKET="\${JK}jk_channel_apr_socket\${OEXT}"
+              JK_POOL_APR="\${JK}jk_pool_apr\${OEXT}"
+              HAS_APR="-DHAS_APR"
+           fi
+        fi
+    fi
+
+    dnl Make sure we have a result.
+    if ${TEST} -z "$WEBSERVER" ; then
+        AC_MSG_ERROR([Directory $apache_dir is not a valid Apache source distribution])
+    fi
+
+# VT: Now, which one I'm supposed to use? Let's figure it out later
+
+    configure_apache=true
+    configure_src=true
+    
+    AC_MSG_RESULT([building connector for \"$WEBSERVER\"])
+],
+[
+	AC_MSG_RESULT(no apache$1 dir given)
+])
+
+dnl vi:set sts=2 sw=2 autoindent:

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/support/jk_apr.m4
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/support/jk_apr.m4	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/support/jk_apr.m4	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,319 @@
+dnl
+dnl Copyright 1999-2004 The Apache Software Foundation
+dnl
+dnl Licensed under the Apache License, Version 2.0 (the "License");
+dnl you may not use this file except in compliance with the License.
+dnl You may obtain a copy of the License at
+dnl
+dnl     http://www.apache.org/licenses/LICENSE-2.0
+dnl
+dnl Unless required by applicable law or agreed to in writing, software
+dnl distributed under the License is distributed on an "AS IS" BASIS,
+dnl WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+dnl See the License for the specific language governing permissions and
+dnl limitations under the License.
+dnl
+
+dnl --------------------------------------------------------------------------
+dnl Author Henri Gomez <hgomez at apache.org>
+dnl
+dnl Inspired by Pier works on webapp m4 macros :)
+dnl 
+dnl Version $Id: jk_apr.m4 299214 2004-02-24 08:42:04Z hgomez $
+dnl --------------------------------------------------------------------------
+
+dnl --------------------------------------------------------------------------
+dnl JK_APR_THREADS
+dnl   Configure APR threading for use with --with-apr.
+dnl   Result goes into APR_CONFIGURE_ARGS
+dnl --------------------------------------------------------------------------
+AC_DEFUN(
+  [JK_APR_THREADS],
+  [
+    AC_ARG_ENABLE(
+      [apr-threads],
+      [  --enable-apr-threads        Configure APR threading for use with --with-apr ],
+      [
+        case "${enableval}" in
+          ""|"yes"|"YES"|"true"|"TRUE")
+            APR_CONFIGURE_ARGS="--enable-threads ${APR_CONFIGURE_ARGS}"
+          ;;
+          "no"|"NO"|"false"|"FALSE")
+            APR_CONFIGURE_ARGS="--disable-threads ${APR_CONFIGURE_ARGS}"
+          ;;
+        *)
+          APR_CONFIGURE_ARGS="--enable-threads=${enableval} ${APR_CONFIGURE_ARGS}"
+         esac
+      ])
+  ])
+
+dnl --------------------------------------------------------------------------
+dnl JK_APR
+dnl   Set the APR source dir.
+dnl   $1 => File which should be present
+dnl --------------------------------------------------------------------------
+AC_DEFUN(
+  [JK_APR],
+  [
+    tempval=""
+    AC_ARG_WITH(
+      [apr],
+      [  --with-apr=DIR           Location of APR source dir ],
+      [
+        case "${withval}" in
+          ""|"yes"|"YES"|"true"|"TRUE")
+            AC_MSG_ERROR(valid apr source dir location required)
+          ;;
+          "no"|"NO"|"false"|"FALSE")
+            AC_MSG_ERROR(valid apr source dir location required)
+          ;;
+        *)
+          tempval="${withval}"
+
+          if ${TEST} ! -d ${tempval} ; then
+            AC_MSG_ERROR(Not a directory: ${tempval})
+          fi
+
+          if ${TEST} ! -f ${tempval}/$1; then
+            AC_MSG_ERROR(can't locate ${tempval}/$1)
+          fi
+
+          if ${TEST} ! -z "$tempval" ; then
+            APR_BUILD="apr-build"
+            APR_CFLAGS="-I ${tempval}/include"
+            APR_CLEAN="apr-clean"
+            APR_DIR=${tempval}
+            APR_INCDIR="${tempval}/include"
+            AC_MSG_RESULT(configuring apr...)
+            tempret="0"
+            JK_EXEC(
+              [tempret],
+              [${SHELL} ./configure --prefix=${APR_DIR} --with-installbuilddir=${APR_DIR}/instbuild --disable-shared ${APR_CONFIGURE_ARGS}],
+              [apr],
+              [${APR_DIR}])
+            if ${TEST} "${tempret}" = "0"; then
+              AC_MSG_RESULT(apr configure ok)
+            else
+              AC_MSG_ERROR(apr configure failed with ${tempret})
+            fi
+            JK_APR_LIBNAME(apr_libname,${APR_DIR})
+            APR_LDFLAGS="${APR_DIR}/lib/${apr_libname}"
+            APR_LIBDIR=""
+			use_apr=true
+            COMMON_APR_OBJECTS="\${COMMON_APR_OBJECTS}"
+          fi
+          ;;
+        esac
+      ])
+
+      unset tempret
+      unset tempval
+      unset apr_libname
+  ])
+
+dnl --------------------------------------------------------------------------
+dnl JK_APR_UTIL
+dnl   Set the APR-UTIL source dir.
+dnl   $1 => File which should be present
+dnl --------------------------------------------------------------------------
+AC_DEFUN(
+  [JK_APR_UTIL],
+  [
+    tempval=""
+    AC_ARG_WITH(
+      [apr-util],
+      [  --with-apr-util=DIR      Location of APR-UTIL source dir ],
+      [
+        case "${withval}" in
+          ""|"yes"|"YES"|"true"|"TRUE")
+            AC_MSG_ERROR(valid apr-util source dir location required)
+          ;;
+          "no"|"NO"|"false"|"FALSE")
+            AC_MSG_ERROR(valid apr-util source dir location required)
+          ;;
+        *)
+          tempval="${withval}"
+
+          if ${TEST} ! -d ${tempval} ; then
+            AC_MSG_ERROR(Not a directory: ${tempval})
+          fi
+
+          if ${TEST} ! -f ${tempval}/$1; then
+            AC_MSG_ERROR(can't locate ${tempval}/$1)
+          fi
+
+          if ${TEST} -z "${APR_BUILD}"; then
+            AC_MSG_ERROR([--with-apr and --with-apr-util must be used together])
+          fi
+
+          if ${TEST} ! -z "$tempval" ; then
+            APR_UTIL_DIR=${tempval}
+            APR_CFLAGS="${APR_CFLAGS} -I ${APR_UTIL_DIR}/include"
+            APR_UTIL_INCDIR="${APR_UTIL_DIR}/include"
+            AC_MSG_RESULT(configuring apr-util...)
+            tempret="0"
+            JK_EXEC(
+              [tempret],
+              [${SHELL} ./configure --prefix=${APR_UTIL_DIR} --with-apr=${APR_DIR}],
+              [apr-util],
+              [${APR_UTIL_DIR}])
+            if ${TEST} "${tempret}" = "0"; then
+              AC_MSG_RESULT(apr-util configure ok)
+            else
+              AC_MSG_ERROR(apr-util configure failed with ${tempret})
+            fi
+            JK_APR_UTIL_LIBNAME(apr_util_libname,${APR_UTIL_DIR})
+            APR_LDFLAGS="${APR_LDFLAGS} ${APR_UTIL_DIR}/lib/${apr_util_libname}"
+            APR_UTIL_LIBDIR=""
+			use_apr=true
+            COMMON_APR_OBJECTS="\${COMMON_APR_OBJECTS}"
+          fi
+          ;;
+        esac
+      ])
+
+      unset tempret
+      unset tempval
+      unset apr_util_libname
+  ])
+
+
+dnl --------------------------------------------------------------------------
+dnl JK_APR_INCDIR
+dnl   Set the APR include dir.
+dnl   $1 => File which should be present
+dnl --------------------------------------------------------------------------
+AC_DEFUN(
+  [JK_APR_INCDIR],
+  [
+    tempval=""
+    AC_ARG_WITH(
+      [apr-include],
+      [  --with-apr-include=DIR   Location of APR include dir ],
+      [  
+        case "${withval}" in
+          ""|"yes"|"YES"|"true"|"TRUE")
+          ;;
+          "no"|"NO"|"false"|"FALSE")
+            AC_MSG_ERROR(valid apr include dir location required)
+          ;;
+        *)
+          tempval="${withval}"
+          if ${TEST} ! -d ${tempval} ; then
+            AC_MSG_ERROR(Not a directory: ${tempval})
+          fi
+
+          if ${TEST} ! -f ${tempval}/$1; then
+            AC_MSG_ERROR(can't locate ${tempval}/$1)
+          fi
+
+          if ${TEST} ! -z "$tempval" ; then
+            APR_BUILD=""
+            APR_CFLAGS="-I${tempval}"
+            APR_CLEAN=""
+            APR_DIR=""
+            APR_INCDIR=${tempval}
+            COMMON_APR_OBJECTS="\${COMMON_APR_OBJECTS}"
+			use_apr=true
+          fi
+          ;;
+
+        esac
+      ])
+
+      unset tempval
+  ])
+
+
+dnl --------------------------------------------------------------------------
+dnl JK_APR_LIBDIR
+dnl   Set the APR library dir.
+dnl --------------------------------------------------------------------------
+AC_DEFUN(
+  [JK_APR_LIBDIR],
+  [
+    tempval=""
+    AC_ARG_WITH(
+      [apr-lib],
+      [  --with-apr-lib=DIR       Location of APR lib dir ],
+      [
+        case "${withval}" in
+          ""|"yes"|"YES"|"true"|"TRUE")
+          ;;
+          "no"|"NO"|"false"|"FALSE")
+            AC_MSG_ERROR(valid apr lib dir location required)
+          ;;
+          *)
+            tempval="${withval}"
+
+            if ${TEST} ! -d ${tempval} ; then
+              AC_MSG_ERROR(Not a directory: ${tempval})
+            fi
+
+            if ${TEST} ! -z "$tempval" ; then
+              APR_BUILD=""
+              APR_CLEAN=""
+              APR_DIR=""
+              APR_LIBDIR=${tempval}
+              APR_LDFLAGS="`apr-config --link-ld` -L${tempval}"
+              COMMON_APR_OBJECTS="\${COMMON_APR_OBJECTS}"
+			  use_apr=true
+            fi
+
+            ;;
+            esac
+      ])
+
+      unset tempval
+  ])
+
+
+dnl --------------------------------------------------------------------------
+dnl JK_APR_LIBNAME
+dnl   Retrieve the complete name of the library.
+dnl   $1 => Environment variable name for the returned value
+dnl   $2 => APR sources directory
+dnl --------------------------------------------------------------------------
+AC_DEFUN(
+  [JK_APR_LIBNAME],
+  [
+    AC_MSG_CHECKING([for apr APR_LIBNAME])
+    if ${TEST} ! -f "$2/apr-config" ; then
+      AC_MSG_ERROR([cannot find apr-config file in $2])
+    fi
+    jk_apr_get_tempval=`$2/apr-config --link-libtool 2> /dev/null`
+    if ${TEST} -z "${jk_apr_get_tempval}" ; then
+      AC_MSG_ERROR([$2/apr-config --link-libtool failed])
+    fi
+    jk_apr_get_tempval=`basename ${jk_apr_get_tempval}`
+    $1="${jk_apr_get_tempval}"
+    AC_MSG_RESULT([${jk_apr_get_tempval}])
+    unset jk_apr_get_tempval
+  ])
+
+
+dnl --------------------------------------------------------------------------
+dnl JK_APR_UTIL_LIBNAME
+dnl   Retrieve the complete name of the library.
+dnl   $1 => Environment variable name for the returned value
+dnl   $2 => APR_UTIL sources directory
+dnl --------------------------------------------------------------------------
+AC_DEFUN(
+  [JK_APR_UTIL_LIBNAME],
+  [
+    AC_MSG_CHECKING([for apr-util APR_UTIL_LIBNAME])
+    if ${TEST} ! -f "$2/apu-config" ; then
+      AC_MSG_ERROR([cannot find apu-config file in $2])
+    fi
+    jk_apu_get_tempval=`$2/apu-config --link-libtool 2> /dev/null`
+    if ${TEST} -z "${jk_apu_get_tempval}" ; then
+      AC_MSG_ERROR([$2/apu-config --link-libtool failed])
+    fi
+    jk_apu_get_tempval=`basename ${jk_apu_get_tempval}`
+    $1="${jk_apu_get_tempval}"
+    AC_MSG_RESULT([${jk_apu_get_tempval}])
+    unset jk_apu_get_tempval
+  ])
+
+dnl vi:set sts=2 sw=2 autoindent:
+

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/support/jk_apxs.m4
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/support/jk_apxs.m4	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/support/jk_apxs.m4	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,149 @@
+dnl
+dnl Copyright 1999-2004 The Apache Software Foundation
+dnl
+dnl Licensed under the Apache License, Version 2.0 (the "License");
+dnl you may not use this file except in compliance with the License.
+dnl You may obtain a copy of the License at
+dnl
+dnl     http://www.apache.org/licenses/LICENSE-2.0
+dnl
+dnl Unless required by applicable law or agreed to in writing, software
+dnl distributed under the License is distributed on an "AS IS" BASIS,
+dnl WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+dnl See the License for the specific language governing permissions and
+dnl limitations under the License.
+dnl
+
+dnl --------------------------------------------------------------------------
+dnl Author Henri Gomez <hgomez at apache.org>
+dnl
+dnl Inspired by Pier works on webapp m4 macros :)
+dnl 
+dnl Version $Id: jk_apxs.m4 300131 2005-01-31 08:14:03Z jfclere $
+dnl --------------------------------------------------------------------------
+
+dnl --------------------------------------------------------------------------
+dnl JK_APXS
+dnl
+dnl Get APXS to be used, determine if Apache 1.3 or 2.0 are target
+dnl $1 => blank/2 if you want to detect Apache 1.3 & 2.0 
+dnl $2 => comment for --with-apxs
+dnl --------------------------------------------------------------------------
+AC_DEFUN(
+  [JK_APXS],
+  [
+    tempval=""
+    AC_ARG_WITH(apxs$1,
+    [  --with-apxs$1[=FILE]      $2],
+    [
+      case "${withval}" in 
+        y | yes | true) find_apxs=true ;;
+        n | no | false) find_apxs=false ;;
+        *) find_apxs=false ;;
+      esac
+
+      if ${TEST} ${find_apxs} ; then    
+        AC_MSG_RESULT([need to check for Perl first, apxs depends on it...])
+        AC_PATH_PROG(PERL,perl,$PATH)dnl
+    
+        if ${TEST} ${find_apxs} ; then
+            APXS$1=${withval}
+        else
+            AC_PATH_PROG(APXS$1,apxs$1,$PATH)dnl
+        fi
+    
+		use_apxs$1=true;
+		
+        if ${TEST} -n "${APXS$1}" ; then
+            dnl Seems that we have it, but have to check if it is OK first        
+            if ${TEST} ! -x "${APXS$1}" ; then
+                AC_MSG_ERROR(Invalid location for apxs: '${APXS$1}')
+            fi
+            
+            ${APXS$1} -q PREFIX >/dev/null 2>/dev/null || apxs_support=false
+    
+            if ${TEST} "${apxs_support}" = "false" ; then
+                AC_MSG_RESULT(could not find ${APXS$1})
+                AC_MSG_ERROR(You must specify a valid --with-apxs$1 path)
+            fi
+
+            dnl apache_dir and apache_include are also needed.
+            APACHE$1_HOME=`${APXS$1} -q PREFIX`
+            APACHE$1_INCL="-I`${APXS$1} -q INCLUDEDIR`"
+            APACHE$1_INCDIR="`${APXS$1} -q INCLUDEDIR`"
+            APACHE$1_LIBEXEC="`${APXS$1} -q LIBEXECDIR`"
+            APACHE$1_CC="`${APXS$1} -q CC`"
+
+            dnl test apache version
+            APA=`${GREP} STANDARD20 ${APXS$1}`
+
+            dnl check if we have an apxs for Apache 1.3 or 2.0
+            if ${TEST} -z "$APA" ; then
+	      if ${TEST} ! -z "$1" ; then
+                AC_MSG_ERROR(Do not use --with-apxs$1 but --with-apxs)
+	      fi
+              WEBSERVERS="${WEBSERVERS} server/apache13"
+              RWEBSERVER="apache-1.3"
+              APXS$1_CFLAGS="`${APXS$1} -q CFLAGS`"
+              APXS$1_CPPFLAGS=""
+            else
+	      if ${TEST} -z "$1" ; then
+                AC_MSG_ERROR(Do not use --with-apxs but --with-apxs2)
+	      fi
+              WEBSERVERS="${WEBSERVERS} server/apache2"
+              RWEBSERVER="apache-2.0"
+              APACHE2_CONFIG_VARS=${apache_dir}/build/config_vars.mk
+              JK_CHANNEL_APR_SOCKET="\${JK}jk_channel_apr_socket\${OEXT}"
+              JK_POOL_APR="\${JK}jk_pool_apr\${OEXT}"
+              APXS$1_CFLAGS="`${APXS$1} -q CFLAGS` `${APXS$1} -q EXTRA_CFLAGS`"
+              APXS$1_CPPFLAGS="`${APXS$1} -q EXTRA_CPPFLAGS`"
+              APR_INCDIR="-I`${APXS$1} -q APR_INCLUDEDIR`"
+			  APR_UTIL_INCDIR="-I`${APXS$1} -q APU_INCLUDEDIR`"
+              APACHE2_LIBDIR="`${APXS$1} -q LIBDIR`"
+              LIBTOOL=`${APXS$1} -q LIBTOOL`
+              if ${TEST} -f ${APACHE2_LIBDIR}/libapr-1.so \
+                      -o -f ${APACHE2_LIBDIR}/libapr-1.sl \
+                      -o -f ${APACHE2_LIBDIR}/libapr-1.dylib; then
+                APR_LIBS="-L${APACHE2_LIBDIR} -lapr-1"
+              elif ${TEST} -f ${APACHE2_LIBDIR}/libapr-0.so \
+                        -o -f ${APACHE2_LIBDIR}/libapr-0.sl \
+                        -o -f ${APACHE2_LIBDIR}/libapr-0.dylib; then
+                APR_LIBS="-L${APACHE2_LIBDIR} -lapr-0"
+              elif ${TEST} -f ${APACHE2_LIBDIR}/libapr.so \
+                        -o -f ${APACHE2_LIBDIR}/libapr.sl \
+                        -o -f ${APACHE2_LIBDIR}/libapr.dylib; then
+                APR_LIBS="-L${APACHE2_LIBDIR} -lapr"
+              else
+                AC_MSG_ERROR(can't locate libapr)
+              fi
+            fi
+            
+            AC_MSG_RESULT([building connector for \"$RWEBSERVER\"])
+        fi
+
+      fi
+  ],
+  [
+	  AC_MSG_RESULT(no apxs$1 given)
+  ])
+
+  unset tempval
+
+  AC_SUBST(APXS$1)
+  AC_SUBST(APXS$1_CFLAGS)
+  AC_SUBST(APACHE$1_CONFIG_VARS)
+  AC_SUBST(APXS$1_CPPFLAGS)
+  AC_SUBST(APACHE$1_DIR)
+  AC_SUBST(APACHE$1_HOME)
+  AC_SUBST(APACHE$1_INCDIR)
+  AC_SUBST(APACHE$1_INCL)
+  AC_SUBST(APACHE$1_LIBEXEC)
+  AC_SUBST(APACHE$1_LIBDIR)
+  AC_SUBST(APACHE$1_CC)
+  AC_SUBST(APXS$1_LDFLAGS)
+  AC_SUBST(APR_LIBS)
+
+])
+
+dnl vi:set sts=2 sw=2 autoindent:
+

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/support/jk_dominohome.m4
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/support/jk_dominohome.m4	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/support/jk_dominohome.m4	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,73 @@
+dnl
+dnl Copyright 1999-2004 The Apache Software Foundation
+dnl
+dnl Licensed under the Apache License, Version 2.0 (the "License");
+dnl you may not use this file except in compliance with the License.
+dnl You may obtain a copy of the License at
+dnl
+dnl     http://www.apache.org/licenses/LICENSE-2.0
+dnl
+dnl Unless required by applicable law or agreed to in writing, software
+dnl distributed under the License is distributed on an "AS IS" BASIS,
+dnl WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+dnl See the License for the specific language governing permissions and
+dnl limitations under the License.
+dnl
+
+dnl --------------------------------------------------------------------------
+dnl Author Andy Armstrong <andy at tagish.com>
+dnl Shamelessly cribbed from  Henri Gomez <hgomez at apache.org>
+dnl
+dnl He was inspired by Pier works on webapp m4 macros :)
+dnl 
+dnl Version $Id: jk_dominohome.m4 299412 2004-04-29 17:03:31Z andya $
+dnl --------------------------------------------------------------------------
+
+dnl --------------------------------------------------------------------------
+dnl JK_DOMHOME
+dnl   Set the Domino Home directory.
+dnl   $1 => Domino Name
+dnl   $2 => Domino VarName
+dnl   $3 => File which should be present
+dnl --------------------------------------------------------------------------
+AC_DEFUN(
+  [JK_DOMHOME],
+  [
+    tempval=""
+
+    AC_MSG_CHECKING([for $1 location])
+    AC_ARG_WITH(
+      [$1],
+      [  --with-$1=DIR      Location of $1 ],
+      [ 
+        case "${withval}" in
+        ""|"yes"|"YES"|"true"|"TRUE")
+          ;;
+        "no"|"NO"|"false"|"FALSE")
+          AC_MSG_ERROR(valid $1 location required)
+          ;;
+        *)
+          tempval="${withval}"
+
+          if ${TEST} ! -d ${tempval} ; then
+            AC_MSG_ERROR(Not a directory: ${tempval})
+          fi
+
+          if ${TEST} ! -f ${tempval}/$3; then
+            AC_MSG_ERROR(can't locate ${tempval}/$3)
+          fi
+          ;;
+        esac
+      ])  
+
+      if ${TEST} -z "$tempval" ; then
+        AC_MSG_RESULT(not provided)
+      else
+        [$2]=${tempval}
+        AC_MSG_RESULT(${[$2]})
+      fi
+
+      unset tempval
+  ])
+
+dnl vi:set sts=2 sw=2 autoindent:

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/support/jk_exec.m4
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/support/jk_exec.m4	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/support/jk_exec.m4	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,90 @@
+dnl
+dnl Copyright 1999-2004 The Apache Software Foundation
+dnl
+dnl Licensed under the Apache License, Version 2.0 (the "License");
+dnl you may not use this file except in compliance with the License.
+dnl You may obtain a copy of the License at
+dnl
+dnl     http://www.apache.org/licenses/LICENSE-2.0
+dnl
+dnl Unless required by applicable law or agreed to in writing, software
+dnl distributed under the License is distributed on an "AS IS" BASIS,
+dnl WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+dnl See the License for the specific language governing permissions and
+dnl limitations under the License.
+dnl
+
+dnl --------------------------------------------------------------------------
+dnl
+dnl Inspired by Pier works on webapp m4 macros :)
+dnl
+dnl Version $Id:$
+dnl --------------------------------------------------------------------------
+
+dnl --------------------------------------------------------------------------
+dnl JK_EXEC
+dnl   Execute a program filtering its output (pretty printing).
+dnl
+dnl   Parameters:
+dnl     $1 => name of the variable containing the return value (error code).
+dnl     $2 => name of the binary/script to invoke
+dnl     $3 => message used for pretty printing output
+dnl     $4 => the directory where the command must be executed
+dnl --------------------------------------------------------------------------
+AC_DEFUN(
+  [JK_EXEC],
+  [
+    jk_exec_curdir="`pwd`"
+    if test -d "$4" ; then
+      cd "$4"
+    else
+      AC_MSG_ERROR([can't switch to directory $4])
+    fi
+
+    echo "  invoking \"$2\""
+    echo "  in directory \"$4\""
+    echo "-1" > retvalue.tmp
+
+    set $2
+    jk_exec_file=[$]1
+    if test ! -x "${jk_exec_file}" ; then
+      cd "${jk_exec_curdir}"
+      AC_MSG_ERROR([cannot find or execute \"${jk_exec_file}\" in \"$4\"])
+      exit 1
+    fi
+    unset jk_exec_file
+
+    {
+      $2
+      echo
+      echo "jk_exec_retvalue $?"
+    } | {
+      jk_exec_ret=0
+      while true ; do
+        read jk_exec_first jk_exec_line
+        if test ! "$?" -eq "0" ; then
+          break
+        else
+          if test "${jk_exec_first}" = "jk_exec_retvalue" ; then
+            jk_exec_ret="${jk_exec_line}"
+          else
+            if test -n "${jk_exec_line}" ; then
+             echo "    $3: ${jk_exec_first} ${jk_exec_line}"
+            fi
+          fi
+        fi
+      done
+      echo "${jk_exec_ret}" > retvalue.tmp
+      unset jk_exec_first
+      unset jk_exec_line
+      unset jk_exec_ret
+    }
+
+    $1="`cat retvalue.tmp`"
+    rm -f retvalue.tmp
+    echo "  execution of \"$2\""
+    echo "  returned with value \"${$1}\""
+
+    cd "${jk_exec_curdir}"
+    unset jk_exec_curdir
+  ])

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/support/jk_java.m4
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/support/jk_java.m4	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/support/jk_java.m4	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,223 @@
+dnl
+dnl Copyright 1999-2004 The Apache Software Foundation
+dnl
+dnl Licensed under the Apache License, Version 2.0 (the "License");
+dnl you may not use this file except in compliance with the License.
+dnl You may obtain a copy of the License at
+dnl
+dnl     http://www.apache.org/licenses/LICENSE-2.0
+dnl
+dnl Unless required by applicable law or agreed to in writing, software
+dnl distributed under the License is distributed on an "AS IS" BASIS,
+dnl WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+dnl See the License for the specific language governing permissions and
+dnl limitations under the License.
+dnl
+
+dnl --------------------------------------------------------------------------
+dnl Author Henri Gomez <hgomez at apache.org>
+dnl
+dnl Inspired by Pier works on webapp m4 macros :)
+dnl 
+dnl Version $Id: jk_java.m4 299440 2004-05-28 00:04:43Z yoavs $
+dnl --------------------------------------------------------------------------
+
+dnl --------------------------------------------------------------------------
+dnl JK_JDK
+dnl
+dnl Detection of JDK location and Java Platform (1.1, 1.2, 1.3, 1.4)
+dnl result goes in JAVA_HOME / JAVA_PLATFORM (1 -> 1.1, 2 -> 1.2 and higher)
+dnl 
+dnl --------------------------------------------------------------------------
+AC_DEFUN(
+  [JK_JNI],
+  [
+    AC_ARG_WITH(jni,
+      [  --with-jni               Build jni support],
+      [
+		case "${withval}" in
+		  y | yes | true) use_jni=true ;;
+		  n | no | false) use_jni=false ;;
+	    *) use_jni=true ;;
+	      esac
+
+		if ${TEST} "${use_jni}" = "true"; then
+		  HAVE_JNI="-DHAVE_JNI"
+		  JNI_BUILD="jni-build"
+		fi
+      ])
+  ])
+
+AC_DEFUN(
+  [JK_JDK],
+  [
+    if ${TEST} "${use_jni}" = "true"; then
+      tempval=""
+      AC_MSG_CHECKING([for JDK location (please wait)])
+      if ${TEST} -n "${JAVA_HOME}" ; then
+        JAVA_HOME_ENV="${JAVA_HOME}"
+      else
+        JAVA_HOME_ENV=""
+      fi
+
+      JAVA_HOME=""
+      JAVA_PLATFORM=""
+
+      AC_ARG_WITH(
+        [java-home],
+        [  --with-java-home=DIR     Location of JDK directory.],
+        [
+
+        # This stuff works if the command line parameter --with-java-home was
+        # specified, so it takes priority rightfully.
+  
+        tempval=${withval}
+
+        if ${TEST} ! -d "${tempval}" ; then
+            AC_MSG_ERROR(Not a directory: ${tempval})
+        fi
+  
+        JAVA_HOME=${tempval}
+        AC_MSG_RESULT(${JAVA_HOME})
+      ],
+      [
+        # This works if the parameter was NOT specified, so it's a good time
+        # to see what the enviroment says.
+        # Since Sun uses JAVA_HOME a lot, we check it first and ignore the
+        # JAVA_HOME, otherwise just use whatever JAVA_HOME was specified.
+
+        if ${TEST} -n "${JAVA_HOME_ENV}" ; then
+          JAVA_HOME=${JAVA_HOME_ENV}
+          AC_MSG_RESULT(${JAVA_HOME_ENV} from environment)
+        fi
+      ])
+
+      if ${TEST} -z "${JAVA_HOME}" ; then
+
+        # Oh well, nobody set neither JAVA_HOME nor JAVA_HOME, have to guess
+        # The following code is based on the code submitted by Henner Zeller
+        # for ${srcdir}/src/scripts/package/rpm/ApacheJServ.spec
+        # Two variables will be set as a result:
+        #
+        # JAVA_HOME
+        # JAVA_PLATFORM
+        AC_MSG_CHECKING([Try to guess JDK location])
+
+        for JAVA_PREFIX in /usr/local /usr/local/lib /usr /usr/lib /opt /usr/java ; do
+
+          for JAVA_PLATFORM in 4 3 2 1 ; do
+
+            for subversion in .9 .8 .7 .6 .5 .4 .3 .2 .1 "" ; do
+
+              for VARIANT in IBMJava2- java java- jdk jdk-; do
+                GUESS="${JAVA_PREFIX}/${VARIANT}1.${JAVA_PLATFORM}${subversion}"
+dnl             AC_MSG_CHECKING([${GUESS}])
+                if ${TEST} -d "${GUESS}/bin" & ${TEST} -d "${GUESS}/include" ; then
+                  JAVA_HOME="${GUESS}"
+                  AC_MSG_RESULT([${GUESS}])
+                  break
+                fi
+              done
+
+              if ${TEST} -n "${JAVA_HOME}" ; then
+                break;
+              fi
+
+            done
+
+            if ${TEST} -n "${JAVA_HOME}" ; then
+              break;
+            fi
+
+          done
+
+          if ${TEST} -n "${JAVA_HOME}" ; then
+            break;
+          fi
+
+        done
+
+        if ${TEST} ! -n "${JAVA_HOME}" ; then
+          AC_MSG_ERROR(can't locate a valid JDK location)
+        fi
+
+      fi
+
+      if ${TEST} -n "${JAVA_PLATFORM}"; then
+        AC_MSG_RESULT(Java Platform detected - 1.${JAVA_PLATFORM})
+      else
+        AC_MSG_CHECKING(Java platform)
+      fi
+
+      AC_ARG_WITH(java-platform,
+       [  --with-java-platform[=2] Force the Java platorm
+                                   (value is 1 for 1.1.x or 2 for 1.2.x or greater)],
+       [
+          case "${withval}" in
+            "1"|"2")
+              JAVA_PLATFORM=${withval}
+              ;;
+            *)
+              AC_MSG_ERROR(invalid java platform provided)
+              ;;
+          esac
+       ],
+       [
+          if ${TEST} -n "${JAVA_PLATFORM}"; then
+            AC_MSG_RESULT(Java Platform detected - 1.${JAVA_PLATFORM})
+          else
+            AC_MSG_CHECKING(Java platform)
+          fi
+       ])
+
+       AC_MSG_RESULT(${JAVA_PLATFORM})
+
+      unset tempval
+    else
+      # no jni, then make sure JAVA_HOME is not picked up from env
+      JAVA_HOME=""
+      JAVA_PLATFORM=""
+    fi
+  ])
+
+
+AC_DEFUN(
+  [JK_JDK_OS],
+  [
+    if ${TEST} "${use_jni}" = "true"; then
+      tempval=""
+      OS=""
+      AC_ARG_WITH(os-type,
+        [  --with-os-type[=SUBDIR]  Location of JDK os-type subdirectory.],
+        [
+          tempval=${withval}
+
+          if ${TEST} ! -d "${JAVA_HOME}/${tempval}" ; then
+            AC_MSG_ERROR(Not a directory: ${JAVA_HOME}/${tempval})
+          fi
+
+          OS = ${tempval}
+        ],
+        [   
+          AC_MSG_CHECKING(os_type directory)
+          if ${TEST} -f ${JAVA_HOME}/include/jni_md.h; then
+            OS=""
+          else
+            for f in ${JAVA_HOME}/include/*/jni_md.h; do
+              if ${TEST} -f $f; then
+                OS=`dirname ${f}`
+                OS=`basename ${OS}`
+                echo " ${OS}"
+              fi
+            done
+            if ${TEST} -z "${OS}"; then
+              AC_MSG_RESULT(Cannot find jni_md.h in ${JAVA_HOME}/${OS})
+              AC_MSG_ERROR(You should retry --with-os-type=SUBDIR)
+            fi
+          fi
+        ])
+    fi
+  ])
+
+dnl vi:set sts=2 sw=2 autoindent:
+

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/support/jk_pcre.m4
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/support/jk_pcre.m4	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/support/jk_pcre.m4	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,39 @@
+dnl
+dnl Copyright 1999-2004 The Apache Software Foundation
+dnl
+dnl Licensed under the Apache License, Version 2.0 (the "License");
+dnl you may not use this file except in compliance with the License.
+dnl You may obtain a copy of the License at
+dnl
+dnl     http://www.apache.org/licenses/LICENSE-2.0
+dnl
+dnl Unless required by applicable law or agreed to in writing, software
+dnl distributed under the License is distributed on an "AS IS" BASIS,
+dnl WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+dnl See the License for the specific language governing permissions and
+dnl limitations under the License.
+dnl
+
+
+
+AC_DEFUN(
+  [JK_PCRE],
+  [
+    AC_ARG_WITH(pcre,
+      [  --with-pcre              Build pcre support],
+      [
+		case "${withval}" in
+		  y | yes | true) use_pcre=true ;;
+		  n | no | false) use_pcre=false ;;
+	    *) use_pcre=true ;;
+	      esac
+
+		if ${TEST} ${use_pcre} ; then
+		  HAS_PCRE="-I${includedir} -DHAS_PCRE"
+		  PCRE_LIBS="-L${libdir} -lpcre -lpcreposix"
+		fi
+      ])
+  ])
+
+dnl vi:set sts=2 sw=2 autoindent:
+

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/support/jk_tchome.m4
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/support/jk_tchome.m4	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/support/jk_tchome.m4	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,72 @@
+dnl
+dnl Copyright 1999-2004 The Apache Software Foundation
+dnl
+dnl Licensed under the Apache License, Version 2.0 (the "License");
+dnl you may not use this file except in compliance with the License.
+dnl You may obtain a copy of the License at
+dnl
+dnl     http://www.apache.org/licenses/LICENSE-2.0
+dnl
+dnl Unless required by applicable law or agreed to in writing, software
+dnl distributed under the License is distributed on an "AS IS" BASIS,
+dnl WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+dnl See the License for the specific language governing permissions and
+dnl limitations under the License.
+dnl
+
+dnl --------------------------------------------------------------------------
+dnl Author Henri Gomez <hgomez at apache.org>
+dnl
+dnl Inspired by Pier works on webapp m4 macros :)
+dnl 
+dnl Version $Id: jk_tchome.m4 299214 2004-02-24 08:42:04Z hgomez $
+dnl --------------------------------------------------------------------------
+
+dnl --------------------------------------------------------------------------
+dnl JK_TCHOME
+dnl   Set the Tomcat Home directory.
+dnl   $1 => Tomcat Name
+dnl   $2 => Tomcat VarName
+dnl   $3 => File which should be present
+dnl --------------------------------------------------------------------------
+AC_DEFUN(
+  [JK_TCHOME],
+  [
+    tempval=""
+
+    AC_MSG_CHECKING([for $1 location])
+    AC_ARG_WITH(
+      [$1],
+      [  --with-$1=DIR      Location of $1 ],
+      [ 
+        case "${withval}" in
+        ""|"yes"|"YES"|"true"|"TRUE")
+          ;;
+        "no"|"NO"|"false"|"FALSE")
+          AC_MSG_ERROR(valid $1 location required)
+          ;;
+        *)
+          tempval="${withval}"
+
+          if ${TEST} ! -d ${tempval} ; then
+            AC_MSG_ERROR(Not a directory: ${tempval})
+          fi
+
+          if ${TEST} ! -f ${tempval}/$3; then
+            AC_MSG_ERROR(can't locate ${tempval}/$3)
+          fi
+          ;;
+        esac
+      ])  
+
+      if ${TEST} -z "$tempval" ; then
+        AC_MSG_RESULT(not provided)
+      else
+        [$2]=${tempval}
+        AC_MSG_RESULT(${[$2]})
+      fi
+
+      unset tempval
+  ])
+
+dnl vi:set sts=2 sw=2 autoindent:

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/support/jk_ws.m4
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/support/jk_ws.m4	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/support/jk_ws.m4	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,228 @@
+dnl
+dnl Copyright 1999-2004 The Apache Software Foundation
+dnl
+dnl Licensed under the Apache License, Version 2.0 (the "License");
+dnl you may not use this file except in compliance with the License.
+dnl You may obtain a copy of the License at
+dnl
+dnl     http://www.apache.org/licenses/LICENSE-2.0
+dnl
+dnl Unless required by applicable law or agreed to in writing, software
+dnl distributed under the License is distributed on an "AS IS" BASIS,
+dnl WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+dnl See the License for the specific language governing permissions and
+dnl limitations under the License.
+dnl
+
+dnl --------------------------------------------------------------------------
+dnl Author Henri Gomez <hgomez at apache.org>
+dnl
+dnl Inspired by Pier works on webapp m4 macros :)
+dnl 
+dnl Version $Id: jk_ws.m4 299223 2004-02-24 13:17:07Z truk $
+dnl --------------------------------------------------------------------------
+
+dnl --------------------------------------------------------------------------
+dnl JK_WS_DIR
+dnl   Set the WebServer source dir.
+dnl   $1 => Webserver name
+dnl   $2 => Webserver vars prefix name
+dnl   $3 => File which should be present
+dnl   $4 => Server specific source directory 
+dnl --------------------------------------------------------------------------
+AC_DEFUN(
+  [JK_WS_DIR],
+  [
+    tempval=""
+    AC_ARG_WITH(
+      [$1],
+      [  --with-$1=DIR           Location of $1 source dir ],
+      [
+        case "${withval}" in
+          ""|"yes"|"YES"|"true"|"TRUE")
+          AC_MSG_ERROR(valid $1 source dir location required)
+          ;;
+          "no"|"NO"|"false"|"FALSE")
+          AC_MSG_ERROR(Don't use with/without $1 if you don't have $1)
+          ;;
+          *)
+          tempval="${withval}"
+
+          if ${TEST} ! -d ${tempval} ; then
+            AC_MSG_ERROR(Not a directory: ${tempval})
+          fi
+
+          if ${TEST} ! -f ${tempval}/$3; then
+            AC_MSG_ERROR(can't locate ${tempval}/$3)
+          fi
+
+          if ${TEST} ! -z "$tempval" ; then
+            $2_BUILD="true"
+            $2_CFLAGS="-I ${tempval}/include"
+            $2_DIR=${tempval}
+            $2_HOME="${tempval}"
+            $2_LIBDIR=""
+	    if ${TEST} -d ${withval}/include ; then
+	      $2_INCL="-I${tempval}/include"
+              $2_INCDIR="${tempval}/include"
+	    fi
+	    if ${TEST} -d ${withval}/src/include ; then
+	      # read osdir from the existing apache.
+	      osdir=`${GREP} '^OSDIR=' ${withval}/src/Makefile.config | ${SED} -e 's:^OSDIR=.*/os:os:'`
+	      if ${TEST} -z "${osdir}" ; then
+	        osdir=os/unix
+	      fi
+	      $2_INCL="-I${tempval}/src/include -I${withval}/src/${osdir}"
+              $2_INCDIR="${tempval}/src/include"
+	    fi
+	    if ${TEST} -d ${tempval}/srclib/apr ; then
+	      # Apache 2 contains apr.
+	      if ${TEST} ! -f ${tempval}/srclib/apr/config.status ; then
+                AC_MSG_ERROR(configure Apache2 before mod_jk2)
+	      fi
+	      osdir=`${GREP} @OSDIR@ ${tempval}/srclib/apr/config.status | sed 's:s, at OSDIR@,::' | sed 's:,;t t::'`
+	      $2_INCL="-I${tempval}/include -I${withval}/os/${osdir}"
+	      $2_LIBEXEC=`${GREP} "^exp_libexecdir =" ${tempval}/build/config_vars.mk | sed 's:exp_libexecdir = ::'`
+	      LIBTOOL=${tempval}/srclib/apr/libtool
+	      APR_INCDIR=-I${tempval}/srclib/apr/include
+	      APR_CFLAGS=`${tempval}/srclib/apr/apr-config --cflags`
+	      APR_UTIL_INCDIR=-I${tempval}/srclib/apr-util/include
+	      APR_LIBDIR_LA=`${tempval}/srclib/apr/apr-config --apr-la-file`
+              $2_LIBDIR=${tempval}/lib
+
+	      AC_SUBST(APR_INCDIR)
+	      AC_SUBST(APR_CFLAGS)
+	      AC_SUBST(APR_INCDIR)
+	      AC_SUBST(APR_UTIL_INCDIR)
+	    fi
+            $2_LDFLAGS=""
+	    WEBSERVERS="${WEBSERVERS} $4"
+
+	    AC_SUBST($2_BUILD)
+	    AC_SUBST($2_CFLAGS)
+	    AC_SUBST($2_DIR)
+	    AC_SUBST($2_HOME)
+	    AC_SUBST($2_INCL)
+	    AC_SUBST($2_INCDIR)
+	    AC_SUBST($2_LDFLAGS)
+	    AC_SUBST($2_LIBDIR)
+
+          fi
+          ;;
+        esac
+      ])
+
+      if ${TEST} -z "$tempval" ; then
+        AC_MSG_RESULT(not provided)
+      else	
+        AC_MSG_RESULT(${tempval})
+      fi
+
+      unset tempval
+  ])
+
+
+dnl --------------------------------------------------------------------------
+dnl JK_WS_INCDIR
+dnl   Set the WebServer include dir.
+dnl   $1 => Webserver name
+dnl   $2 => Webserver vars prefix name
+dnl   $3 => File which should be present
+dnl --------------------------------------------------------------------------
+AC_DEFUN(
+  [JK_WS_INCDIR],
+  [
+    tempval=""
+    AC_ARG_WITH(
+      [$1-include],
+      [  --with-$1-include=DIR   Location of $1 include dir ],
+      [  
+        case "${withval}" in
+          ""|"yes"|"YES"|"true"|"TRUE")
+          ;;
+          "no"|"NO"|"false"|"FALSE")
+          AC_MSG_ERROR(valid $1 include dir location required)
+          ;;
+          *)
+          tempval="${withval}"
+          if ${TEST} ! -d ${tempval} ; then
+            AC_MSG_ERROR(Not a directory: ${tempval})
+          fi
+
+          if ${TEST} ! -f ${tempval}/$3; then
+            AC_MSG_ERROR(can't locate ${tempval}/$3)
+          fi
+
+          if ${TEST} ! -z "$tempval" ; then
+            $2_BUILD=""
+            $2_CFLAGS="-I${tempval}"
+            $2_CLEAN=""
+            $2_DIR=""
+            $2_INCDIR=${tempval}
+            AC_MSG_RESULT($2_INCDIR)
+	    
+	    AC_SUBST($2_BUILD)
+	    AC_SUBST($2_CFLAGS)
+	    AC_SUBST($2_CLEAN)
+	    AC_SUBST($2_DIR)
+	    AC_SUBST($2_INCDIR)
+          fi
+          ;;
+        esac
+      ])
+
+      unset tempval
+  ])
+
+
+dnl --------------------------------------------------------------------------
+dnl JK_WS_LIBDIR
+dnl   Set the WebServer library dir.
+dnl   $1 => Webserver name
+dnl   $2 => Webserver vars prefix name
+dnl --------------------------------------------------------------------------
+AC_DEFUN(
+  [JK_WS_LIBDIR],
+  [
+    tempval=""
+    AC_ARG_WITH(
+      [$1-lib],
+      [  --with-$1-lib=DIR       Location of $1 lib dir ],
+      [
+        case "${withval}" in
+          ""|"yes"|"YES"|"true"|"TRUE")
+          ;;
+          "no"|"NO"|"false"|"FALSE")
+          AC_MSG_ERROR(valid $1 lib directory location required)
+          ;;
+        *)
+          tempval="${withval}"
+
+          if ${TEST} ! -d ${tempval} ; then
+            AC_MSG_ERROR(Not a directory: ${tempval})
+          fi
+
+          if ${TEST} ! -z "$tempval" ; then
+            $2_BUILD=""
+            $2_CLEAN=""
+            $2_DIR=""
+            $2_LIBDIR=${tempval}
+            $2_LDFLAGS=""
+            AC_MSG_RESULT($2_LIBDIR)
+
+	    AC_SUBST($2_BUILD)
+	    AC_SUBST($2_CLEAN)
+	    AC_SUBST($2_DIR)
+	    AC_SUBST($2_LIBDIR)
+	    AC_SUBST($2_LDFLAGS)
+          fi
+
+          ;;
+          esac
+      ])
+
+      unset tempval
+  ])
+
+dnl vi:set sts=2 sw=2 autoindent:
+

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/support/os_apache.m4
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/support/os_apache.m4	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/support/os_apache.m4	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,27 @@
+dnl copied from httpd-2.0/os/config.m4
+dnl OS changed to OS_APACHE and OS_DIR to OS_APACHE_DIR
+
+AC_MSG_CHECKING(for target platform)
+
+#PLATFORM=`${CONFIG_SHELL-/bin/sh} $ac_config_guess`
+PLATFORM=$host
+
+case "$PLATFORM" in
+*beos*)
+  OS_APACHE="beos"
+  OS_APACHE_DIR=$OS_APACHE
+  ;;
+*pc-os2_emx*)
+  OS_APACHE="os2"
+  OS_APACHE_DIR=$OS_APACHE
+  ;;
+bs2000*)
+  OS_APACHE="unix"
+  OS_APACHE_DIR=bs2000  # only the OS_APACHE_DIR is platform specific.
+  ;;
+*)
+  OS_APACHE="unix"
+  OS_APACHE_DIR=$OS_APACHE;;
+esac
+
+AC_MSG_RESULT($OS_APACHE)

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/test/org/apache/ajp/test/TestAjp13.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/test/org/apache/ajp/test/TestAjp13.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/test/org/apache/ajp/test/TestAjp13.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,280 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.ajp.test;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.ServerSocket;
+import java.net.Socket;
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+
+import org.apache.ajp.Ajp13;
+import org.apache.ajp.Ajp13Packet;
+import org.apache.ajp.RequestHandler;
+import org.apache.tomcat.util.http.BaseRequest;
+import org.apache.tomcat.util.http.MimeHeaders;
+
+public class TestAjp13 extends TestCase {
+
+    private static org.apache.commons.logging.Log log=
+        org.apache.commons.logging.LogFactory.getLog( TestAjp13.class );
+
+    Ajp13Server server = null;
+
+    public TestAjp13(String name) {
+        super(name);
+    }
+
+    public static Test suite() {
+        return new TestSuite(TestAjp13.class);
+    }
+
+    protected void setUp() {
+        println("setup...");
+
+        server = new Ajp13Server();
+        server.start();
+    }
+
+    protected void tearDown() {
+        println("tear down...");
+
+        server.shutdown();
+    }
+
+    public void test1() throws Exception {
+        println("running test1");
+
+        Socket s = new Socket("localhost", 8009);
+
+        Ajp13Packet p = new Ajp13Packet(Ajp13.MAX_PACKET_SIZE);
+        p.appendInt(0x1234);
+        p.appendInt(0);
+        p.setByteOff(4);
+        p.appendByte(RequestHandler.JK_AJP13_FORWARD_REQUEST);
+        p.appendByte((byte)2);
+        p.appendString("http");
+        p.appendString("/test_uri");
+        p.appendString("remote_addr");
+        p.appendString("remote_host");
+        p.appendString("server_name");
+        p.appendInt(80);
+        p.appendBool(false);
+        p.appendInt(3);
+        p.appendString("my header");
+        p.appendString("my header value");
+        p.appendInt((0xA0 << 8) + RequestHandler.SC_REQ_AUTHORIZATION);
+        p.appendString("some auth string");
+        p.appendInt((0xA0 << 8) + RequestHandler.SC_REQ_USER_AGENT);
+        p.appendString("TestAjp13 User Agent");
+        p.appendByte(RequestHandler.SC_A_ARE_DONE);
+
+        int len = p.getByteOff() - 4;
+        p.setByteOff(2);
+        p.appendInt(len);
+
+        OutputStream os = s.getOutputStream();
+        os.write(p.getBuff(), 0, len + 4);
+
+        InputStream is = s.getInputStream();
+
+        println("decoding response...");
+        
+        boolean done = false;
+        while (!done) {
+            int b1, b2;
+            // read a packet
+
+            // first 2 bytes should be AB
+            b1 = is.read();
+            assertTrue("byte 1 was " + (char)b1, b1 == (int)'A');
+            b2 = is.read();
+            assertTrue("byte 2 was " + (char)b2, b2 == (int)'B');
+
+            println("b1 = " + (char)b1 + "; b2 = " + (char)b2);
+            
+            // next is length
+            b1 = is.read();
+            b1 &= 0xFF;
+            b2 = is.read();
+            b2 &= 0xFF;
+            
+            int l = (b1 << 8) + b2;
+
+            println("length = " + l);
+
+            // now get data
+            byte[] buf = new byte[l];
+            int n = 0;
+            int off = 0;
+            int total = 0;
+            while ((n = is.read(buf, off, l - off)) != -1 && (l - off != 0)) {
+                total += n;
+                off += n;
+            }
+
+            println("read " + total);
+
+            assertTrue("total read was " + total +
+                       ", should have been " + l,
+                       total == l);
+
+            
+
+            int code = (int)buf[0];
+
+            switch (code) {
+            case 3:
+                println("AJP13_SEND_BODY_CHUNK ");
+                break;
+            case 4:
+                println("AJP13_SEND_HEADERS ");
+                break;
+            case 5:
+                println("AJP13_END_RESPONSE ");
+                done = true;
+                break;
+            case 6:
+                println("AJP13_GET_BODY_CHUNK ");
+                break;
+            default:
+                assertTrue("invalid prefix code:  " + code, false);
+                break;
+            }
+        }
+
+        println("shutting down socket...");
+        s.shutdownOutput();
+        s.shutdownInput();
+        s.close();
+
+        println("done test1...");
+    }
+
+    protected static void println(String msg) {
+        if (log.isDebugEnabled())
+            log.debug("[TestAjp13] " + msg);
+    }
+
+    public static void main(String[] args) throws Exception {
+    }
+}
+
+
+class Ajp13Server extends Thread {
+
+    boolean shutdown = false;
+
+    void shutdown() {
+        this.shutdown = true;
+        this.interrupt();
+    }
+
+    public void run() {
+        try {
+            ServerSocket server = new ServerSocket(8009);
+            TestAjp13.println("Ajp13Server running...");
+            Socket socket = server.accept();
+            Ajp13 ajp13 = new Ajp13();
+            MimeHeaders headers = new MimeHeaders();
+            BaseRequest request = new BaseRequest();
+            ajp13.setSocket(socket);
+
+            boolean moreRequests = true;
+            while (moreRequests && !shutdown) {
+            
+                int status = 0;
+                try {
+                    status = ajp13.receiveNextRequest(request);
+                } catch (IOException e) {
+                    if (shutdown) {
+                        TestAjp13.println("Ajp13Server told to shutdown");
+                        break;
+                    }
+                    TestAjp13.println("process: ajp13.receiveNextRequest -> " + e);
+                }
+            
+                if( status==-2) {
+                    // special case - shutdown
+                    // XXX need better communication, refactor it
+                    //                  if( !doShutdown(socket.getLocalAddress(),
+                    //                                  socket.getInetAddress())) {
+                    //                      moreRequests = false;
+                    //                      continue;
+                    //                  }
+                    break;
+                }
+            
+            	// Special low level request allready handled (ie: PING/PONG)
+            	if( status == 999 )
+            	{
+					request.recycle();
+            		continue;
+            	}
+            	
+                if( status != 200 )
+                    break;
+
+                TestAjp13.println(request.toString());
+
+                String message =
+                    "<html><body><pre>" +
+                    "hello from ajp13:  " +
+                    System.getProperty("line.separator") +
+                    request.toString() +
+                    "</pre></body></html>";
+
+                headers.addValue("content-type").setString( "text/html");
+                headers.addValue("content-length").setInt(message.length());
+                headers.addValue("my-header").setString( "my value");
+                ajp13.sendHeaders(200, headers);
+
+                byte[] b = message.getBytes();
+                ajp13.doWrite(b, 0, b.length);
+
+                ajp13.finish();
+
+                request.recycle();
+                headers.recycle();
+            }
+
+            try {
+                ajp13.close();
+            } catch (IOException e) {
+                TestAjp13.println("process: ajp13.close ->" + e);
+            }
+
+            try {
+                socket.close();
+            } catch (IOException e) {
+                TestAjp13.println("process: socket.close ->" + e);
+            }
+            socket = null;
+
+            TestAjp13.println("process:  done");
+
+        } catch (Exception e) {
+            e.printStackTrace();
+            throw new RuntimeException(e.toString());
+        }
+    }
+}
+

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/test/org/apache/ajp/test/TestAll.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/test/org/apache/ajp/test/TestAll.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/test/org/apache/ajp/test/TestAll.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,40 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.ajp.test;
+
+// junit
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+
+public class TestAll extends TestCase {
+
+    public TestAll(String testName) {
+        super(testName);
+    }
+
+    public static Test suite() {
+        TestSuite suite = new TestSuite();
+        suite.addTest(TestAjp13.suite());
+        return suite;
+    }
+
+    public static void main(String args[]) {
+        String[] testCaseName = { TestAll.class.getName() };
+        junit.textui.TestRunner.main(testCaseName);
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/tools/jkrelease.sh
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/tools/jkrelease.sh	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/tools/jkrelease.sh	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,166 @@
+#!/bin/ksh
+
+# Make sure to set your path so that we can find
+# the following binaries:
+# cd, mkdir, cp, rm, find
+# svn
+# ant
+# libtoolize, aclocal, autoheader, automake, autoconf
+# tar, zip, gzip
+# gpg
+# And any one of: w3m, elinks, links
+
+export ANT_HOME=/usr/local/ant
+export JAVA_HOME=/usr/local/jdk1.4.2
+
+# You need to change the version numbers
+JK_VERMAJOR="1"
+JK_VERMINOR="2"
+JK_VERFIX="19"
+ASFROOT="http://svn.apache.org/repos/asf"
+JK_CVST="tomcat-connectors"
+
+JK_OWNER="asf"
+JK_GROUP="asf"
+
+COPY_TOP="KEYS LICENSE NOTICE"
+COPY_JK="BUILD.txt native support tools xdocs"
+COPY_CONF="uriworkermap.properties workers.properties workers.properties.minimal"
+
+JK_VER="${JK_VERMAJOR}.${JK_VERMINOR}.${JK_VERFIX}"
+JK_BRANCH="jk${JK_VERMAJOR}.${JK_VERMINOR}.x"
+JK_TAG="JK_${JK_VERMAJOR}_${JK_VERMINOR}_${JK_VERFIX}"
+
+JK_DIST=${JK_CVST}-${JK_VER}-src
+JK_SVN_URL="${ASFROOT}/tomcat/connectors/tags/${JK_BRANCH}/${JK_TAG}"
+
+#################### NO CHANGE BELOW THIS LINE ##############
+
+umask 022
+
+rm -rf ${JK_DIST}
+rm -rf ${JK_DIST}.tmp
+
+mkdir -p ${JK_DIST}.tmp
+svn export "${JK_SVN_URL}/jk" ${JK_DIST}.tmp/jk
+for item in ${COPY_TOP}
+do
+    svn export "${JK_SVN_URL}/${item}" ${JK_DIST}.tmp/${item}
+done
+
+# Build documentation.
+cd ${JK_DIST}.tmp/jk/xdocs
+ant
+cd ../../..
+
+# Copying things into source distribution
+srcdir=${JK_DIST}.tmp
+targetdir=${JK_DIST}
+mkdir -p ${targetdir}
+for item in ${COPY_TOP}
+do
+    echo "Copying $item from ${srcdir} ..."
+    cp -pr ${srcdir}/$item ${targetdir}/
+done
+
+srcdir=${JK_DIST}.tmp/jk
+targetdir=${JK_DIST}
+mkdir -p ${targetdir}
+for item in ${COPY_JK}
+do
+    echo "Copying $item from ${srcdir} ..."
+    cp -pr ${srcdir}/$item ${targetdir}/
+done
+
+srcdir=${JK_DIST}.tmp/jk/build
+targetdir=${JK_DIST}
+mkdir -p ${targetdir}
+for item in docs
+do
+    echo "Copying $item from ${srcdir} ..."
+    cp -pr ${srcdir}/$item ${targetdir}/
+done
+
+srcdir=${JK_DIST}.tmp/jk/conf
+targetdir=${JK_DIST}/conf
+mkdir -p ${targetdir}
+for item in ${COPY_CONF}
+do
+    echo "Copying $item from ${srcdir} ..."
+    cp -pr ${srcdir}/$item ${targetdir}/
+done
+
+# Remove extra directories and files
+targetdir=${JK_DIST}
+rm -rf ${targetdir}/xdocs/jk2
+rm -rf ${targetdir}/native/CHANGES.txt
+rm -rf ${targetdir}/native/build.xml
+find ${JK_DIST} -name .cvsignore -exec rm -rf \{\} \; 
+find ${JK_DIST} -name CVS -exec rm -rf \{\} \; 
+find ${JK_DIST} -name .svn -exec rm -rf \{\} \; 
+
+cd ${JK_DIST}/native
+
+# Check for links, elinks or w3m
+W3MOPTS="-dump -cols 80 -t 4 -S -O iso-8859-1 -T text/html"
+LNKOPTS="-dump"
+ELNKOPTS="--dump --no-numbering --no-home"
+failed=true
+for tool in `echo "w3m elinks links"`
+do
+  found=false
+  for dir in `echo ${PATH} | sed 's!^:!.:!;s!:$!:.!;s!::!:.:!g;s!:! !g'`
+  do
+    if [ -x ${dir}/${tool} ]
+    then
+      found=true
+      break
+    fi
+  done
+
+  # Try to run it
+  if ${found}
+  then
+    case ${tool} in
+      w3m)
+        TOOL="w3m $W3MOPTS"
+        ;;
+      links)
+        TOOL="links $LNKOPTS"
+        ;;
+      elinks)
+        TOOL="elinks $ELNKOPTS"
+        ;;
+    esac
+    rm -f CHANGES
+    ${TOOL} ../docs/printer/changelog.html > CHANGES 2>/dev/null
+    if [ -f CHANGES -a -s CHANGES ]
+    then
+      failed=false
+      break
+    fi
+  fi
+done
+if [ ${failed} = "true" ]
+then
+  echo "Can't convert html to text (CHANGES)"
+  exit 1
+fi
+
+# Export text docs
+${TOOL} ../docs/printer/changelog.html >CHANGES
+${TOOL} ../docs/news/printer/20060101.html >NEWS
+${TOOL} ../docs/news/printer/20050101.html >>NEWS
+${TOOL} ../docs/news/printer/20041100.html >>NEWS
+
+# Generate configure et. al.
+./buildconf.sh
+cd ../../
+
+# Pack and sign
+tar cvf ${JK_DIST}.tar --owner="${JK_OWNER}" --group="${JK_GROUP}" ${JK_DIST}
+gzip ${JK_DIST}.tar
+zip -9 -r ${JK_DIST}.zip ${JK_DIST}
+# Create detatched signature
+gpg -ba ${JK_DIST}.tar.gz
+gpg -ba ${JK_DIST}.zip

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/tools/reports/README.txt
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/tools/reports/README.txt	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/tools/reports/README.txt	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,18 @@
+This directory contains perl scripts which can be used to generate
+statistics for tomcat requests and errors logged by mod_jk.
+
+See the comments in the scripts for more details.
+
+A great deal of statistical data is generated but at this time
+only long term trend graphs are being created and no reports.
+This is only a start.  Many more graphs and reports could be
+generated from the data. Please consider contributing back any
+new reports or graphs you create.  Thanks.
+
+Requires the following perl modules and libraries:
+
+GD 1.8.x graphics library http://www.boutell.com/gd/.
+GD 1.4.x perl module.
+GD Graph perl module.
+GD TextUtil perl module.
+StatisticsDescriptive perl module.

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/tools/reports/tomcat_reports.pl
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/tools/reports/tomcat_reports.pl	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/tools/reports/tomcat_reports.pl	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,430 @@
+#!/usr/local/bin/perl
+
+#
+# Copyright 1999-2004 The Apache Software Foundation
+#
+# Licensed 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.
+#
+
+# $Id: tomcat_reports.pl 417697 2006-06-28 08:27:04Z rjung $
+
+# Author: Glenn Nielsen
+
+# Script for generating reports and graphs using statistical data generated
+# by the tomcat_trend.pl script.
+#
+# The following graphs are created:
+#
+#  tomcat_request.png
+#    Long term trend graph of total number of tomcat requests handled
+#
+#  tomcat_median.png
+#    Long term overall trend graph of tomcat request latency median
+#
+#  tomcat_deviation.png
+#    Long term overall trend graph of tomcat request mean and standard deviation
+#
+#  tomcat_error.png
+#    Long term trend graph of requests rejected by tomcat. Shows requests rejected
+#    when tomcat has no request processors available.  Can be an indicator that tomcat
+#    is overloaded or having other scaling problems.
+#
+#  tomcat_client.png
+#    Long term trend graph of requests forward to tomcat which were aborted by the remote
+#    client (browser).  You will normally see some aborted requests.  High numbers of these
+#    can be an indicator that tomcat is overloaded or there are requests which have very high
+#    latency.
+#
+# tomcat_reports.pl <directory where statistics are archived> <directory to place graphs/reports in>
+
+use GD;
+use GD::Graph;
+use GD::Graph::Data;
+use GD::Graph::lines;
+use GD::Graph::linespoints;
+use Statistics::Descriptive;
+use Time::Local;
+
+# Constants
+
+%MON = ('JAN' => 0, 'Jan' => 0,
+        'FEB' => 1, 'Feb' => 1,
+        'MAR' => 2, 'Mar' => 2,
+        'APR' => 3, 'Apr' => 3,
+        'MAY' => 4, 'May' => 4,
+        'JUN' => 5, 'Jun' => 5,
+        'JUL' => 6, 'Jul' => 6,
+        'AUG' => 7, 'Aug' => 7,
+        'SEP' => 8, 'Sep' => 8,
+        'OCT' => 9, 'Oct' => 9,
+        'NOV' => 10, 'Nov' => 10,
+        'DEC' => 11, 'Dec' => 11,);
+
+ at Months = ("Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec");
+
+# Check the args
+
+$archivedir = $ARGV[0];
+$reportdir = $ARGV[1];
+
+die "Usage: $0 archivedir reportdir"
+   unless( length($archivedir) && ($reportdir) );
+
+die "Archive Directory $archivedir doesn't exist"
+   unless( -d $archivedir);
+
+die "Report Directory $reportdir doesn't exist"
+   unless( -d $reportdir);
+
+# Read in data from file
+die "Archive Directory $archivedir has no global.data file"
+   unless( -e "$archivedir/global.data" );
+
+ at Data = `tail -365 $archivedir/global.data`;
+$numdays = $#Data;
+$daycounter = $numdays;
+
+foreach( @Data ) {
+   $line = $_;
+   chomp($line);
+   ($date,$count,$median,$mean,$stddev,$min,$max,$client_gone,$tomcat_full) = split /\s+/,$line;
+   # print "$daycounter $date $count $median $mean $stdev $min $max $client_gone $tomcat_full\n";
+   $start_time = $date unless $start_time>0;
+   $end_time = $date;
+   push @days,int($daycounter/7);
+   push @count,$count;
+   push @median,$median;
+   push @mean,$mean;
+   push @stddev,$mean+$stddev;
+   push @min,$min;
+   push @max,$max;
+   push @client_gone,$client_gone;
+   push @tomcat_full,$tomcat_full;
+   $daycounter--;
+}
+
+($day,$mon,$year) = (localtime($start_time))[3..5];
+$year += 1900;
+$startdate = "$Months[$mon] $day, $year";
+($day,$mon,$year) = (localtime($end_time))[3..5];
+$year += 1900;
+$enddate = "$Months[$mon] $day, $year";
+
+# Output request trend graph
+$outfile = "$reportdir/tomcat_request.png";
+unlink $outfile;
+
+$stats = Statistics::Descriptive::Sparse->new();
+$stats->add_data(@count);
+$max = $stats->max();
+$min = $stats->min();
+
+&RequestGraph();
+
+# Output median latency trend graph
+$outfile = "$reportdir/tomcat_median.png";
+unlink $outfile;
+
+$stats = Statistics::Descriptive::Sparse->new();
+$stats->add_data(@median);
+$max = $stats->max();
+$min = $stats->min();
+
+&MedianGraph();
+
+# Output latency deviation trend graph
+$outfile = "$reportdir/tomcat_deviation.png";
+unlink $outfile;
+
+$stats = Statistics::Descriptive::Sparse->new();
+$stats->add_data(@stddev);
+$stats->add_data(@mean);
+$max = $stats->max();
+$min = $stats->min();
+
+&DeviationGraph();
+
+# Output request error trend graph
+$outfile = "$reportdir/tomcat_error.png";
+unlink $outfile;
+
+$stats = Statistics::Descriptive::Sparse->new();
+$stats->add_data(@tomcat_full);
+$max = $stats->max();
+$min = $stats->min();
+
+&ErrorGraph();
+
+# Output request error trend graph
+$outfile = "$reportdir/tomcat_client.png";
+unlink $outfile;
+
+$stats = Statistics::Descriptive::Sparse->new();
+$stats->add_data(@client_gone);
+$max = $stats->max();
+$min = $stats->min();
+
+&ClientGraph();
+
+exit;
+
+sub RequestGraph {
+
+  $graph = GD::Graph::lines->new(800,600);
+  @data = (\@days,\@count);
+
+  $div = 100;
+  $div = 500 if $max >= 2000;
+  $div = 1000 if $max >= 5000;
+  $div = 5000 if $max >= 20000;
+  $div = 10000 if $max >= 50000;
+  $div = 50000 if $max >= 200000;
+  $div = 100000 if $max >= 500000;
+  $div = 500000 if $max >= 2000000;
+  $div = 1000000 if $max >= 5000000;
+  $ymax = (int($max/$div) + 1)*$div;
+  $ymin = int($min/$div)*$div;
+  $ytick = ($ymax - $ymin)/$div;
+
+  $graph->set(
+    y_label             => 'Requests',
+    title               => "Tomcat Requests by Day from $startdate to $enddate",
+    y_min_value         => $ymin,
+    y_max_value         => $ymax,
+    y_tick_number       => $ytick,
+    y_number_format     => \&val_format,
+    x_label		=> 'Weeks Ago',
+    x_label_skip	=> 7,
+    x_tick_offset	=> $numdays%7,
+    dclrs               => [ qw(green) ],
+    legend_placement    => 'BC'
+  ) or warn $graph->error;
+
+  $graph->set_legend( 'Requests' );
+  $graph->set_title_font(GD::gdGiantFont);
+  $graph->set_x_axis_font(GD::gdSmallFont);
+  $graph->set_y_axis_font(GD::gdSmallFont);
+  $graph->set_legend_font(GD::gdSmallFont);
+  $gd = $graph->plot(\@data);
+  die "Graph Plot Failed: " . $graph->error unless defined $gd;
+
+  open IMG, ">$outfile" or die $!;
+  print IMG $gd->png or die $gd->error;
+  close IMG;
+}
+
+sub MedianGraph {
+
+  $graph = GD::Graph::lines->new(800,600);
+  @data = (\@days,\@median);
+
+  $div = .05;
+  $div = .1 if $max >= .5;
+  $div = .5 if $max >= 2;
+  $div = 1 if $max >= 5;
+  $div = 5 if $max >= 20;
+  $div = 10 if $max >= 50;
+  $div = 50 if $max >= 200;
+  $div = 100 if $max >= 500;
+  $ymax = (int($max/$div) + 1)*$div;
+  $ytick = $ymax/$div;
+
+  $graph->set(
+    y_label             => 'Latency (Seconds)',
+    title               => "Tomcat Request Median Latency by Day from $startdate to $enddate",
+    y_min_value		=> 0,
+    y_max_value         => $ymax,
+    y_tick_number       => $ytick,
+    y_number_format     => \&val_format,
+    x_label             => 'Weeks Ago',
+    x_label_skip        => 7,
+    x_tick_offset       => $numdays%7,
+    dclrs               => [ qw(green) ],
+    legend_placement    => 'BC'
+  ) or warn $graph->error;
+
+  $graph->set_legend( 'Median' );
+  $graph->set_title_font(GD::gdGiantFont);
+  $graph->set_x_axis_font(GD::gdSmallFont);
+  $graph->set_y_axis_font(GD::gdSmallFont);
+  $graph->set_legend_font(GD::gdSmallFont);
+  $gd = $graph->plot(\@data);
+  die "Graph Plot Failed: " . $graph->error unless defined $gd;
+
+  open IMG, ">$outfile" or die $!;
+  print IMG $gd->png or die $gd->error;
+  close IMG;
+}
+
+sub DeviationGraph {
+
+  $graph = GD::Graph::lines->new(800,600);
+  @data = (\@days,\@mean,\@stddev);
+
+  $div = .1;
+  $div = .5 if $max >= 2;
+  $div = 1 if $max >= 5;
+  $div = 5 if $max >= 20;
+  $div = 10 if $max >= 50;
+  $div = 50 if $max >= 200;
+  $div = 100 if $max >= 500;
+  $ymax = (int($max/$div) + 1)*$div;
+  $ytick = $ymax/$div;
+
+  $graph->set(
+    y_label             => 'Latency (Seconds)',
+    title               => "Tomcat Request Latency Mean and Deviation by Day from $startdate to $enddate",
+    y_max_value         => $ymax,
+    y_tick_number       => $ytick,
+    x_label             => 'Weeks Ago',
+    x_label_skip        => 7,
+    x_tick_offset       => $numdays%7,
+    dclrs               => [ qw(green yellow) ],
+    legend_placement    => 'BC'
+  ) or warn $graph->error;
+
+  $graph->set_legend( 'Mean', 'Mean plus Standard Deviation' );
+  $graph->set_title_font(GD::gdGiantFont);
+  $graph->set_x_axis_font(GD::gdSmallFont);
+  $graph->set_y_axis_font(GD::gdSmallFont);
+  $graph->set_legend_font(GD::gdSmallFont);
+  $gd = $graph->plot(\@data);
+  die "Graph Plot Failed: " . $graph->error unless defined $gd;
+
+  open IMG, ">$outfile" or die $!;
+  print IMG $gd->png or die $gd->error;
+  close IMG;
+}
+
+sub ErrorGraph {
+
+  $graph = GD::Graph::lines->new(800,600);
+  @data = (\@days,\@tomcat_full);
+
+  $div = 5;
+  $div = 10 if $max >=100;
+  $div = 50 if $max >= 200;
+  $div = 100 if $max >= 1000;
+  $div = 500 if $max >= 2000;
+  $div = 1000 if $max >= 5000;
+  $div = 5000 if $max >= 20000;
+  $div = 10000 if $max >= 50000;
+  $div = 50000 if $max >= 200000;
+  $div = 100000 if $max >= 500000;
+  $div = 500000 if $max >= 2000000;
+  $div = 1000000 if $max >= 5000000;
+  $ymax = (int($max/$div) + 1)*$div;
+  $ymin = int($min/$div)*$div;
+  $ytick = ($ymax - $ymin)/$div;
+
+  $graph->set(
+    y_label             => 'Requests',
+    title               => "Tomcat Rejected Request by Day from $startdate to $enddate",
+    y_min_value         => $ymin,
+    y_max_value         => $ymax,
+    y_tick_number       => $ytick,
+    y_number_format     => \&val_format,
+    x_label             => 'Weeks Ago',
+    x_label_skip        => 7,
+    x_tick_offset       => $numdays%7,
+    dclrs               => [ qw(green) ],
+    legend_placement    => 'BC'
+  ) or warn $graph->error;
+
+  $graph->set_legend( 'Tomcat Rejected Requests' );
+  $graph->set_title_font(GD::gdGiantFont);
+  $graph->set_x_axis_font(GD::gdSmallFont);
+  $graph->set_y_axis_font(GD::gdSmallFont);
+  $graph->set_legend_font(GD::gdSmallFont);
+  $gd = $graph->plot(\@data);
+  die "Graph Plot Failed: " . $graph->error unless defined $gd;
+
+  open IMG, ">$outfile" or die $!;
+  print IMG $gd->png or die $gd->error;
+  close IMG;
+}
+
+sub ClientGraph {
+
+  $graph = GD::Graph::lines->new(800,600);
+  @data = (\@days,\@client_gone);
+
+  $div = 5;
+  $div = 10 if $max >=100;
+  $div = 50 if $max >= 200;
+  $div = 100 if $max >= 1000;
+  $div = 500 if $max >= 2000;
+  $div = 1000 if $max >= 5000;
+  $div = 5000 if $max >= 20000;
+  $div = 10000 if $max >= 50000;
+  $div = 50000 if $max >= 200000;
+  $div = 100000 if $max >= 500000;
+  $div = 500000 if $max >= 2000000;
+  $div = 1000000 if $max >= 5000000;
+  $ymax = (int($max/$div) + 1)*$div;
+  $ymin = int($min/$div)*$div;
+  $ytick = ($ymax - $ymin)/$div;
+
+  $graph->set(
+    y_label             => 'Requests',
+    title               => "Tomcat Client Aborted Requests by Day from $startdate to $enddate",
+    y_min_value         => $ymin,
+    y_max_value         => $ymax,
+    y_tick_number       => $ytick,
+    y_number_format     => \&val_format,
+    x_label             => 'Weeks Ago',
+    x_label_skip        => 7,
+    x_tick_offset       => $numdays%7,
+    dclrs               => [ qw(green) ],
+    legend_placement    => 'BC'
+  ) or warn $graph->error;
+
+  $graph->set_legend( 'Tomcat Client Aborted Requests' );
+  $graph->set_title_font(GD::gdGiantFont);
+  $graph->set_x_axis_font(GD::gdSmallFont);
+  $graph->set_y_axis_font(GD::gdSmallFont);
+  $graph->set_legend_font(GD::gdSmallFont);
+  $gd = $graph->plot(\@data);
+  die "Graph Plot Failed: " . $graph->error unless defined $gd;
+
+  open IMG, ">$outfile" or die $!;
+  print IMG $gd->png or die $gd->error;
+  close IMG;
+}
+
+sub val_format {
+  my $value = shift;
+  my $ret;
+
+  $ret = $value;
+  if( $ret =~ /\./ ) {
+    $ret =~ s/\.(\d\d\d).*/\.$1/;
+  } else {
+    $ret =~ s/(\d+)(\d\d\d)$/$1,$2/;
+    $ret =~ s/(\d+)(\d\d\d),(\d\d\d)$/$1,$2,$3/;
+  }
+  return $ret;
+}
+
+sub size_format {
+  my $value = shift;
+  my $ret;
+
+  if( $max >= 5000 ) {
+     $value = int(($value/1024)+.5);
+  }
+  $ret = $value;
+  $ret =~ s/(\d+)(\d\d\d)$/$1,$2/;
+  $ret =~ s/(\d+)(\d\d\d),(\d\d\d)$/$1,$2,$3/;
+  return $ret;
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/tools/reports/tomcat_trend.pl
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/tools/reports/tomcat_trend.pl	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/tools/reports/tomcat_trend.pl	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,407 @@
+#!/usr/local/bin/perl
+
+#
+# Copyright 1999-2004 The Apache Software Foundation
+#
+# Licensed 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.
+#
+
+# $Id: tomcat_trend.pl 417697 2006-06-28 08:27:04Z rjung $
+
+# Author:  Glenn Nielsen
+
+# Script for analyzing mod_jk.log data when logging tomcat request data using
+# the JkRequestLogFormat Apache mod_jk configuration.
+#
+# Generates statistics for request latency and errors.  Archives the generated
+# data to files for later use in long term trend graphs and reports.
+#
+# tomcat_trend.pl <directory containing mod_jk.log> <directory for archiving statistics>
+
+use FileHandle;
+use Statistics::Descriptive;
+use Time::Local;
+
+# Constants
+
+%MON = ('JAN' => 0, 'Jan' => 0,
+        'FEB' => 1, 'Feb' => 1,
+        'MAR' => 2, 'Mar' => 2,
+        'APR' => 3, 'Apr' => 3,
+        'MAY' => 4, 'May' => 4,
+        'JUN' => 5, 'Jun' => 5,
+        'JUL' => 6, 'Jul' => 6,
+        'AUG' => 7, 'Aug' => 7,
+        'SEP' => 8, 'Sep' => 8,
+        'OCT' => 9, 'Oct' => 9,
+        'NOV' => 10, 'Nov' => 10,
+        'DEC' => 11, 'Dec' => 11,);
+
+ at Months = ("Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec");
+
+# Check the args
+
+$logdir= $ARGV[0];
+$archivedir = $ARGV[1];
+
+die "Usage: $0 logdir archivedir"
+   unless( length($logdir) && length($archivedir) );
+
+die "Log Directory $logdir doesn't exist"
+   unless( -d $logdir);
+
+die "Archive Directory $archivedir doesn't exist"
+   unless( -d $archivedir);
+
+# Get start date from global.data if it exists
+
+if( -e "$archivedir/global.data" ) {
+   # Get the start date from the last entry in global.data
+   @tail = `tail -1 $archivedir/global.data`;
+   $startdate = (split /\s+/,$tail[0])[0];
+   ($day, $mon, $year) = (localtime($startdate))[3..5];
+   if ($day == 31) {
+      $day=1;
+      $month++;
+      if ($month > 11) {
+         $month=0;
+         $year++;
+      }
+   }
+   $startdate = timelocal(0,0,0,$day+1,$mon,$year);
+
+}
+
+($day, $mon, $year) = (localtime(time))[3..5];
+$curdate = timelocal(0,0,0,$day,$mon,$year);
+print "Today: " . scalar(localtime($curdate)) . "\n";
+
+# Get the log files names and date they start
+ at logs = `ls -1 $logdir/mod_jk.log*`;
+foreach( @logs ) {
+   $logfile = $_;
+   chomp($logfile);
+   next if ( $logfile =~ /\.(bz2|gz|zip)$/ );
+   @head = `head -1 $logfile`;
+   ($mon, $day, $time, $year) = (split /\s+/,$head[0])[1..4];
+   ($hour, $min, $sec) = split /:/,$time;
+   $year =~ s/\]$//;
+   $logtime = timelocal($sec,$min,$hour,$day,$MON{$mon},$year-1900);
+   $modjklog{$logtime} = $logfile;
+}
+
+# Set the startdate if this is the first time processing the logs
+# If we have a startdate, remove log files we con't need to process
+foreach $logtime ( sort {$a <=> $b} keys %modjklog ) {
+   # If logs haven't been processed before, set startdate to time of 
+   # first log entry
+   if( $startdate !~ /^\d+$/ ) {
+      $startdate = $logtime;
+      ($day, $mon, $year) = (localtime($startdate))[3..5];
+      $startdate = timelocal(0,0,0,$day,$mon,$year);
+      last;
+   }
+   if( $logtime > $startdate ) {
+      last;
+   }
+   # Save the previous log file since start date may start here
+   $prevlogfile = $modjklog{$logtime};
+   $prevlogtime = $logtime;
+   # Remove log files we don't need to process
+   delete $modjklog{$logtime};
+}
+
+# Add back in the previous log file where we need to start processing
+if( defined $prevlogtime ) {
+   $modjklog{$prevlogtime} = $prevlogfile;
+}
+
+print "StartDate: " . scalar(localtime($startdate)) . "\n";
+$processdate = $startdate;
+
+foreach $key ( sort {$a <=> $b} keys %modjklog ) {
+   $logtime = $processdate;
+   $logfile = $modjklog{$key};
+   print "Processing log: $logfile\n";
+   last if( $key >= $curdate );
+   $fh = new FileHandle "<$logfile";  
+   die "Open of logfile $logfile failed: $!"
+      unless defined $fh;
+   while( $line = $fh->getline) {
+      chomp($line);
+      ($mon, $day, $time, $year) = (split /\s+/,$line)[1..4];
+      ($hour, $min, $sec) = split /:/,$time;
+      $year =~ s/\]$//;
+      if( $day !~ /^\d+/ || $hour !~ /^\d+/ || $min!~ /^\d+/ || $sec !~ /^\d+/ ) {
+         print "Unknown log entry: $origline\n" unless $origline =~ /\.c /;
+         next;
+      }
+      $logtime = timelocal($sec,$min,$hour,$day,$MON{$mon},$year-1900);
+
+      if( $logtime > $processdate ) {
+         $origline = $line;
+         # Strip off the leading date and time
+         $line =~ s/^\[.*\] //;
+
+         # See if this is a new 5 minute period
+         $interval = int($logtime/300);
+         if( $interval != $previnterval ) {
+            if( defined $previnterval ) {
+               &IntervalStats(\%Global,\%Interval,$previnterval*300);
+            }
+            undef %Interval;
+            undef @IntervalLatency;
+            undef %IntervalWorkers;
+            $Interval{tomcat_full} = 0;
+            $Interval{client_gone} = 0;
+            $Interval{latency} = \@IntervalLatency;
+            $Interval{workers} = \%IntervalWorkers;
+            $previnterval = $interval;
+         }
+
+         # See if this is a new day
+         if( $day != $prevday ) {
+            if( defined $prevday ) {
+               &DailyStats($processdate,\%Global);
+            }
+            undef %Global;
+            undef %GlobalWorkers;
+            undef @GlobalLatency;
+            $Global{tomcat_full} = 0;
+            $Global{client_gone} = 0;
+            $Global{interval} = "";
+            $Global{latency} = \@GlobalLatency;
+            $Global{workers} = \%GlobalWorkers;
+            $Global{errors} = "";
+            $prevday = $day;
+            $processdate = $logtime;
+         }
+
+         # Stop processing if logtime is today
+         last if( $logtime >= $curdate );
+
+         if( $line =~ /\d\)\]{0,1}: / ) {
+            # Handle a mod_jk error
+            if( $line =~ /(jk_tcp_socket_recvfull failed|ERROR: Receiving from tomcat failed)/ ) {
+               $Global{tomcat_full}++;
+               $Interval{tomcat_full}++;
+            } elsif( $line =~ /(ajp_process_callback - write failed|ERROR sending data to client. Connection aborted or network problems|Client connection aborted or network problems)/ ) {
+               $Global{client_gone}++;
+               $Interval{client_gone}++;
+            }
+            next;
+         } else {
+            # Handle a mod_jk request log entry
+            $line =~ s/^\[.*\] //;
+            $line =~ s/\"(GET|POST|OPTIONS|HEAD)[^\"]*\" //;
+            $line =~ s/[\?\;].*\"//;
+            $line =~ s/\"//g;
+            ($work, $host, $page, $status, $latency) = split /\s+/,$line;
+            $page =~ s/\/\//\//g;
+            $page =~ s/\.\//\//g;
+            if( length($work) <= 0 || length($host) <= 0 ||
+                length($page) <= 0 || $status !~ /^\d+$/ || $latency !~ /^\d+\.\d+$/ ) {
+               print "Unknown log entry: $origline\n" unless $origline =~ /\.c /;
+               next;
+            }
+
+            # Throw out abnormally long requests and log them as an error
+            if( $latency >= 1800 ) {
+               $Global{errors} .= "Error: $page has an HTTP status of $status and an ";
+               $Global{errors} .= "abnormally long request latency of $latency seconds\n";
+               next;
+            }
+
+            # Save the data by day for Global, Worker, and Host
+            push @{$Global{latency}},$latency;
+            $workers = $Global{workers};
+            if( !defined $$workers{$work} ) {
+               undef @{"$work"};
+               undef %{"$work"};
+               undef %{"$work-hosts"};
+               ${"$work"}{latency} = \@{"$work"};
+               ${"$work"}{hosts} = \%{"$work-hosts"};
+               ${"$work"}{interval} = "";
+               $$workers{$work} = \%{"$work"};
+            }
+            $worker = $$workers{$work};
+            push @{$$worker{latency}},$latency;
+
+            if( !defined $$worker{hosts}{$host} ) {
+               undef @{"$work-$host"};
+               undef %{"$work-$host"};
+               undef %{"$work-$host-pages"};
+               ${"$work-$host"}{latency} = \@{"$work-$host"};
+               ${"$work-$host"}{pages} = \%{"$work-$host-pages"};
+               ${"$work-$host"}{interval} = "";
+               $$worker{hosts}{$host} = \%{"$work-$host"};
+            }
+            $hoster = $$worker{hosts}{$host};
+            push @{$$hoster{latency}},$latency;
+
+            if( !defined $$hoster{pages}{$page} ) {
+                undef @{"$work-$host-$page"};
+                $$hoster{pages}{$page} = \@{"$work-$host-$page"};
+            }
+            push @{$$hoster{pages}{$page}},$latency;
+
+            # Save the data by 5 minute interval for Global, Worker, and Host
+            push @{$Interval{latency}},$latency;
+            $workers = $Interval{workers};
+            if( !defined $$workers{"$work"} ) {
+               undef @{"int-$work"};
+               undef %{"int-$work"};
+               undef %{"int-$work-hosts"};
+               ${"int-$work"}{latency} = \@{"int-$work"};
+               ${"int-$work"}{hosts} = \%{"int-$work-hosts"};
+               $$workers{$work} = \%{"int-$work"};
+            }
+            $worker = $$workers{$work};
+            push @{$$worker{latency}},$latency;
+
+            if( !defined $$worker{hosts}{$host} ) {
+               undef @{"int-$work-$host"};
+               undef %{"int-$work-$host"};
+               ${"int-$work-$host"}{latency} = \@{"int-$work-$host"};
+               $$worker{hosts}{$host} = \%{"int-$work-$host"};
+            }
+            $hoster = $$worker{hosts}{$host};
+            push @{$$hoster{latency}},$latency;
+         }
+      }
+   }
+   undef $fh;
+}
+
+# If the last log file ends before switch to the current day,
+# output the last days data
+if( $logtime < $curdate ) {
+   &IntervalStats(\%Global,\%Interval,$previnterval*300);
+   &DailyStats($processdate,\%Global);
+}
+
+exit;
+
+sub IntervalStats($$$) {
+   my $global = $_[0];
+   my $data = $_[1];
+   my $interval = $_[2];
+
+   ($count,$median,$mean,$stddev,$min,$max) = &CalcStats($$data{latency});
+   $$global{interval} .= "$interval $count $median $mean $stddev $min $max $$data{client_gone} $$data{tomcat_full}\n";
+
+   foreach $work ( keys %{$$data{workers}} ) {
+      $worker = $$data{workers}{$work};
+      $gworker = $$global{workers}{$work};
+      ($count,$median,$mean,$stddev,$min,$max) = &CalcStats($$worker{latency});
+      $$gworker{interval} .= "$interval $count $median $mean $stddev $min $max\n";
+      foreach $host ( keys %{$$worker{hosts}} ) {
+         $hoster = $$worker{hosts}{$host};
+         $ghoster = $$gworker{hosts}{$host};
+         ($count,$median,$mean,$stddev,$min,$max) = &CalcStats($$hoster{latency});
+         $$ghoster{interval} .= "$interval $count $median $mean $stddev $min $max\n";
+      }
+   }
+}
+
+sub DailyStats($$) {
+   my $date = $_[0];
+   my $data = $_[1];
+
+   &SaveStats($data,$date,"","global");
+   &SaveFile($$data{interval},$date,"","daily");
+   foreach $work ( keys %{$$data{workers}} ) {
+      $worker = $$data{workers}{$work};
+      &SaveStats($worker,$date,$work,"global");
+      &SaveFile($$worker{interval},$date,$work,"daily");
+      foreach $host ( keys %{$$worker{hosts}} ) {
+         $hoster = $$worker{hosts}{$host};
+         &SaveStats($hoster,$date,"$work/$host","global");
+         &SaveFile($$hoster{interval},$date,"$work/$host","daily");
+         $pagedata = "";
+         foreach $page ( sort keys %{$$hoster{pages}} ) {
+            $pager = $$hoster{pages}{$page};
+            ($count,$median,$mean,$stddev,$min,$max) = &CalcStats($pager);
+            $pagedata .= "$page $count $median $mean $stddev $min $max\n";
+         }
+         $pagedata .= $$data{errors};
+         &SaveFile($pagedata,$date,"$work/$host","request");
+      }
+   }
+}
+
+sub CalcStats($) {
+   my $data = $_[0];
+
+   $stats = Statistics::Descriptive::Full->new();
+   $stats->add_data(@{$data});
+   $median = $stats->median();
+   $mean = $stats->mean();
+   $stddev = $stats->standard_deviation();
+   $max = $stats->max();
+   $min = $stats->min();
+   $count = $stats->count();
+   return ($count,$median,$mean,$stddev,$min,$max);
+}
+
+sub SaveStats($$$$) {
+   my $data = $_[0];
+   my $date = $_[1];
+   my $dir = $_[2];
+   my $file = $_[3];
+
+   if( length($dir) > 0 ) {
+      $dir = "$archivedir/$dir";
+   } else {
+      $dir = $archivedir;
+   }
+   mkdir "$dir",0755;
+
+   $outfile = "$dir/${file}.data";
+
+   ($count,$median,$mean,$stddev,$min,$max) = &CalcStats($$data{latency});
+
+   open DATA, ">>$outfile" or die $!;
+   print DATA "$date $count $median $mean $stddev $min $max";
+   print DATA " $$data{client_gone} $$data{tomcat_full}" if defined $$data{tomcat_full};
+   print DATA "\n";
+   close DATA;
+}
+
+sub SaveFile($$$$) {
+   my $data = $_[0];
+   my $date = $_[1];
+   my $dir = $_[2];
+   my $file = $_[3];
+   my ($day, $mon, $year);
+
+   ($day, $mon, $year) = (localtime($date))[3..5];
+   $year += 1900;
+   $mon++;
+   $mon = "0$mon" if $mon < 10;
+   $day = "0$day" if $day < 10;
+   $file = "$year-$mon-$day-$file";
+
+   if( length($dir) > 0 ) {
+      $dir = "$archivedir/$dir";
+   } else {
+      $dir = $archivedir;
+   }
+   mkdir "$dir",0755;
+
+   $outfile = "$dir/${file}.data";
+
+   open DATA, ">>$outfile" or die $!;
+   print DATA $data;
+   close DATA;
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/build.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/build.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/build.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,202 @@
+<project name="tomcat-docs" default="build-main" basedir=".">
+
+
+  <!-- ===================== Initialize Property Values =================== -->
+
+  <!-- See "build.properties.sample" in the top level directory for all     -->
+  <!-- property values you must customize for successful building!!!        -->
+  <property file="build.properties"/>
+  <property file="../build.properties"/>
+  <property file="../../build.properties"/>
+  <property file="${user.home}/build.properties"/>
+
+  <property name="build.compiler"  value="modern"/>
+  <property name="build.dir"   value="../build"/>
+  <property name="dist.dir"    value="../dist"/>
+  <property name="dist.name"     value="docs"/>
+
+
+  <!-- =================== BUILD: Create Directories ====================== -->
+  <target name="build-prepare">
+    <mkdir dir="${build.dir}"/>
+    <mkdir dir="${build.dir}/${dist.name}"/>
+  </target>
+
+
+  <!-- ================ BUILD: Copy Static Files ========================== -->
+  <target name="build-static" depends="build-prepare">
+
+    <!-- Top Level Static Files -->
+    <copy    todir="${build.dir}/${dist.name}">
+      <fileset dir=".">
+        <include name="BUILDING.txt"/>
+        <include name="README.txt"/>
+        <include name="RUNNING.txt"/>
+        <include name="style.css"/>
+      </fileset>
+    </copy>
+    <copy    todir="${build.dir}/${dist.name}">
+      <fileset dir="." includes="**/*.html"/>
+    </copy>
+
+    <!-- Images Subdirectory -->
+    <mkdir     dir="${build.dir}/${dist.name}/images"/>
+    <copy    todir="${build.dir}/${dist.name}/images">
+      <fileset dir="images"/>
+    </copy>
+
+    <mkdir     dir="${build.dir}/${dist.name}/printer"/>
+    <!-- Top Level Static Files -->
+    <copy    todir="${build.dir}/${dist.name}/printer">
+      <fileset dir=".">
+        <include name="BUILDING.txt"/>
+        <include name="README.txt"/>
+        <include name="RUNNING.txt"/>
+      </fileset>
+    </copy>
+    <style basedir="."
+           destdir="${build.dir}/${dist.name}/printer"
+         extension=".html"
+             style="style.xsl"
+          excludes="build.xml project.xml empty.xml"
+          includes="*.xml">
+      <param name="relative-path" expression="./.."/>
+      <param name="project-menu" expression="nomenu"/>
+    </style>
+
+    <!-- News -->
+    <style basedir="news"
+           destdir="${build.dir}/${dist.name}/news"
+         extension=".html"
+             style="style.xsl"
+          excludes="project.xml"
+          includes="*.xml">
+      <param name="relative-path" expression=".."/>
+    </style>
+    <mkdir     dir="${build.dir}/${dist.name}/news/printer"/>
+    <style basedir="news"
+           destdir="${build.dir}/${dist.name}/news/printer"
+         extension=".html"
+             style="style.xsl"
+          excludes="project.xml"
+          includes="*.xml">
+      <param name="relative-path" expression="../.."/>
+      <param name="project-menu" expression="nomenu"/>
+    </style>
+
+    <!-- Common -->
+    <style basedir="common"
+           destdir="${build.dir}/${dist.name}/common"
+         extension=".html"
+             style="style.xsl"
+          excludes="project.xml"
+          includes="*.xml">
+      <param name="relative-path" expression=".."/>
+    </style>
+    <mkdir     dir="${build.dir}/${dist.name}/common/printer"/>
+    <style basedir="common"
+           destdir="${build.dir}/${dist.name}/common/printer"
+         extension=".html"
+             style="style.xsl"
+          excludes="project.xml"
+          includes="*.xml">
+      <param name="relative-path" expression="../.."/>
+      <param name="project-menu" expression="nomenu"/>
+    </style>
+
+    <!-- Howto -->
+    <style basedir="howto"
+           destdir="${build.dir}/${dist.name}/howto"
+         extension=".html"
+             style="style.xsl"
+          excludes="project.xml"
+          includes="*.xml">
+      <param name="relative-path" expression=".."/>
+    </style>
+    <mkdir     dir="${build.dir}/${dist.name}/howto/printer"/>
+    <style basedir="howto"
+           destdir="${build.dir}/${dist.name}/howto/printer"
+         extension=".html"
+             style="style.xsl"
+          excludes="project.xml"
+          includes="*.xml">
+      <param name="relative-path" expression="../.."/>
+      <param name="project-menu" expression="nomenu"/>
+    </style>
+
+    <!-- Config -->
+    <style basedir="config"
+           destdir="${build.dir}/${dist.name}/config"
+         extension=".html"
+             style="style.xsl"
+          excludes="project.xml"
+          includes="*.xml">
+      <param name="relative-path" expression=".."/>
+    </style>
+    <mkdir     dir="${build.dir}/${dist.name}/config/printer"/>
+    <style basedir="config"
+           destdir="${build.dir}/${dist.name}/config/printer"
+         extension=".html"
+             style="style.xsl"
+          excludes="project.xml"
+          includes="*.xml">
+      <param name="relative-path" expression="../.."/>
+      <param name="project-menu" expression="nomenu"/>
+    </style>
+ 
+  </target>
+
+
+  <!-- ================= BUILD: XML-HTML Generation ======================= -->
+  <target name="build-main" depends="build-static">
+
+    <!-- Top Level Directory -->
+    <style basedir="."
+           destdir="${build.dir}/${dist.name}"
+         extension=".html"
+             style="style.xsl"
+          excludes="build.xml project.xml empty.xml"
+          includes="*.xml">
+      <param name="relative-path" expression="."/>
+    </style>
+
+  </target>
+
+
+  <!-- ==================== BUILD: Rebuild Everything ===================== -->
+  <target name="all" depends="build-clean,build-main"
+   description="Clean and build documentation"/>
+
+
+  <!-- ======================= BUILD: Clean Directory ===================== -->
+  <target name="build-clean">
+    <delete dir="${build.dir}/${dist.name}"/>
+  </target>
+
+
+  <!-- ======================= DIST: Create Directories =================== -->
+  <target name="dist-prepare">
+    <mkdir dir="${dist.dir}"/>
+  </target>
+
+
+  <!-- ======================= DIST: Create Distribution Files ============ -->
+  <target name="dist" depends="build-main,dist-prepare"
+   description="Create documentation binary distribution">
+      <jar   jarfile="${dist.dir}/${dist.name}.war"
+             basedir="${build.dir}/${dist.name}" includes="**"/>
+  </target>
+
+
+  <!-- ======================= DIST: Clean Directory ====================== -->
+  <target name="dist-clean">
+    <delete dir="${dist.dir}/${dist.name}"/>
+  </target>
+
+
+  <!-- ====================== Convenient Synonyms ========================= -->
+  <target name="clean" depends="build-clean,dist-clean"
+   description="Clean build and dist directories"/>
+
+
+</project>

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/changelog.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/changelog.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/changelog.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,632 @@
+<?xml version="1.0"?>
+<!DOCTYPE document [
+  <!ENTITY project SYSTEM "project.xml">
+]>
+<document url="changelog.html">
+
+  &project;
+
+  <properties>
+    <author email="mturk at apache.org">Mladen Turk</author>
+    <title>Changelog</title>
+  </properties>
+
+<body>
+
+<section name="Preface">
+  <p>
+  This is the Changelog for Tomcat Connectors. This changelog
+  does not contain all updates and fixes to the Tomcat connectors (yet).
+  It should contain fixes made only after November 10th 2004, when the
+  new documentation project for JK was started.
+  </p>
+</section>
+<section name="Changes between 1.2.18 and 1.2.19">
+  <br />
+  <subsection name="Native">
+    <changelog>
+      <update>
+      Add feature to force the recovery of workers that are
+      member of loadbalancer if all the members are in error
+      state. This fixes the time gap where 503 was returned
+      caused by recovery_timeout although the backend was
+      ready to handle the requests. (mturk)
+      </update>
+      <update>
+      Docs: Seperate deprecated directives in their own table. (rjung)
+      </update>
+      <update>
+      Docs: Allow "-" and "_" in worker names. (rjung)
+      </update>
+      <update>
+      Allow multiple lines with attributes "balance_workers" and "mount". (rjung)
+      </update>
+      <fix>
+      Make jk_is_some_property match more precisely. (rjung)
+      </fix>
+      <update>
+      JkStatus: Make refresh interval changeable. (rjung)
+      </update>
+      <fix>
+      JkStatus: Adjust display of recover time wrt. global maintenance. (rjung)
+      </fix>
+      <update>
+      LB: Resetting worker state from OK to NA, if worker has been idle
+      too long. (rjung)
+      </update>
+      <fix>
+      Avoid compiler warnings concerning the use of lb_*_type arrays.
+      Use functions instead. (rjung)
+      </fix>
+      <update>
+      Added %R JkRequestLogFormat option for Apache 1 and Apache 2. (mturk)
+      </update>
+      <update>
+      Allow changing jvm Route from status manager. (mturk)
+      </update>
+      <fix>
+      Do not retun 400 if Tomcat fails in the midle of the post
+      request. Return 500 insted. (mturk)
+      </fix>
+      <update>
+      LB: Combine ok/error/recovering/busy runtime states into a single scalar. (rjung)
+      </update>
+      <update>
+      LB: Combine active/disabled/stopped configuration states into a single scalar. (rjung)
+      </update>
+      <update>
+      LB: Add several Apache notes to enable standard logging for load balancer results. (rjung)
+      </update>
+      <update>
+      LB: Reorganisation of the main load balancer service loop. (rjung)
+      </update>
+      <update>
+      Implement hierarchical worker configuration via attribute "reference". (rjung)
+      </update>
+      <update>
+      Log deprecated properties. (rjung)
+      </update>
+      <fix>
+      IIS: Fix simple_rewrite for the cases where the
+      rewritten url is larger then the original one. (mturk)
+      </fix>
+      <update>
+      New JkOption "DisableReuse" to disable connection persistence. (jim)
+      </update>
+      <update>
+      LB: Move sessionid retrieval out of get_most_suitable_worker into service. (rjung)
+      </update>
+      <update>
+      Code cleanup for all service methods (use TRACE, JK_LOG_NULL_PARAMS, null pointer checks). (rjung)
+      </update>
+      <update>
+      JKSTATUS: add refresh link. No refresh for updates. Redirect to list view after update. (rjung)
+      </update>
+      <update>
+      Add new hook add_log_items into servers. (rjung)
+      </update>
+      <update>
+      APACHE httpd: Rename apache logging notes. (rjung)
+      </update>
+      <update>
+      LB: Rename lock and method constants. Add constants for defaults. (rjung)
+      </update>
+      <fix>
+      Default log level should be INFO and not DEBUG.
+      Default log level should be the same for all server types. (rjung)
+      </fix>
+      <fix>
+      Make rewrite_rule_map and log_level as non mandatory
+      directives for isapi_redirect. (mturk)
+      </fix>
+      <fix>
+      <bug>40107</bug>: Rewrite is_socket_connected function.
+      Non blocking socket is not used any more. (mturk)
+      </fix>
+      <update>
+      Allow building with VS2005 without too many warnings. (mturk)
+      </update>
+      <fix>
+      Decide by MMN, which piped log API we should use.
+      mod_jk 1.2.18 broke compilation with Apache 1.3 pre 1.3.28. (rjung)
+      </fix>
+    </changelog>
+  </subsection>
+</section>
+<section name="Changes between 1.2.17 and 1.2.18">
+  <br />
+  <subsection name="Native">
+    <changelog>
+      <fix>
+      Using socklen_t in getsockopt. Also introducing jk_sock_t. (mturk)
+      </fix>
+      <update>
+      Allow recovery wait time below 60 seconds (new minimum is 1 second). (mturk)
+      </update>
+    </changelog>
+  </subsection>
+</section>
+<section name="Changes between 1.2.16 and JK 1.2.17">
+  <br />
+  <subsection name="Native">
+    <changelog>
+      <fix>
+      Fix hanging jk status worker when certain attributes are being updated
+      due to double locking. (rjung)
+      </fix>
+      <update>
+      Allow JkMount to behave like uriworkermap.properties
+      by parsing pipe symbol as two directive marker. (mturk)
+      </update>
+    </changelog>
+  </subsection>
+</section>
+<section name="Changes between 1.2.15 and JK 1.2.16">
+  <br />
+  <subsection name="Native">
+    <changelog>
+      <update>
+      Added simple rewrite capability for IIS. Although simple it
+      will fulfill most needs. (mturk)
+      </update>
+      <update>
+      Added RECOVER_ABORT_IF_CLIENTERROR recovery_option that closes
+      the connection if client connection is broken during the request. (mturk)
+      </update>
+      <update>
+      Renamed cache_timeout directive to connection_pool_timeout. (mturk)
+      </update>
+      <update>
+      Added connection_pool_minsize directive. (mturk)
+      </update>
+      <update>
+      Deprecate recycle_timeout directive. (mturk)
+      </update>
+      <update>
+      Corrected some HTML syntax bugs in output of status worker. (rjung)
+      </update>
+      <update>
+      Added the refresh=n parameter to the status worker. It will update the display every n seconds. (rjung)
+      </update>
+      <update>
+      Balancer: Add attribute distance to balanced workers to express preferences between workers. (rjung)
+      </update>
+      <update>
+      Balancer: Add attribute jvm_route to balanced workers to be able to use the same target in different balancers. (rjung)
+      </update>
+      <update>
+      Status: Add lb_mult to status. (rjung)
+      </update>
+      <update>
+      Balancer: Make different balancing strategies work in a similar way (use lb_value, use decay during global maintenance, use integer factors for weights. (rjung)
+      </update>
+      <update>
+      Balancer: Improve locking. (rjung)
+      </update>
+      <update>
+      Balancer: Workers start slower after recovering. (rjung)
+      </update>
+      <update>
+      Balancer: Make different balancing strategies work in a similar way (use lb_value, use decay during global maintenance, use integer factors lb_mult for weights). (rjung)
+      </update>
+      <update>
+      Balancer: Move recovery check to global maintenance. (rjung)
+      </update>
+      <update>
+      Balancer: Add global maintenance method, that is called in only one process. (rjung)
+      </update>
+      <update>
+      Extend our use of autoconf to find a 32Bit and a 64Bit unsigned type and their printf formats. (rjung)
+      </update>
+      <update>
+      Logging: piped loggers for JkLogFile and Apache 1.3. (rjung)
+      </update>
+      <update>
+      Logging: Add PID to log lines for each log level apart from REQUEST. (rjung)
+      </update>
+      <update>
+      Logging: flush buffered logs to keep lines in correct order. Output final newline together with log message. (rjung)
+      </update>
+      <update>
+      Reducing shm size. (rjung)
+      </update>
+      <update>
+      Only log removing of old worker, when we actually do it. (rjung)
+      </update>
+      <fix>
+      <bug>37469</bug>: Fix shared memory close for forked childs.
+      The shared memory will be closed by the parent process. (mturk)
+      </fix>
+      <fix>
+      <bug>37332</bug>: Fix potential misuse of buffer length with
+      snprintf functions. (mturk)
+      </fix>
+      <fix>
+      <bug>38859</bug>: Protect mod_jk against buggy or malicious
+      AJP servers in the backend. Patch provided by Ruediger Pluem. (mturk)
+      </fix>
+      <fix>
+      <bug>38889</bug>: Use worker map sorting depending on the path
+      elements, to comply with Servlet spec. Patch provided by
+      Steve Revilak. (mturk)
+      </fix>
+      <update>
+      <bug>36138</bug>: Added Busyness lb method. Patch provided
+      by  Chris Lamprecht. (mturk)
+      </update>
+      <fix>
+      Fix pessimistic locking mode. The patch correctly handles the
+      burst load, by syncing the access to the shared memory data. (mturk)
+      </fix>
+      <fix>
+      <bug>38806</bug>: Reclycle worker even if it is disabled.
+      This fixes hot-standby workers in error state. (mturk)
+      </fix>
+      <fix>
+      <bug>37167</bug>: Allow building with BSD-ish like make. (mturk)
+      </fix>
+      <fix>
+      ISAPI plugin (isapi_redirect.dll) did not provide correct request data
+      for IIS
+ to include in the IIS log. (markt)
+      </fix>
+    </changelog>
+  </subsection>
+</section>
+<section name="Changes between 1.2.14 and 1.2.15">
+  <br />
+  <subsection name="Native">
+    <changelog>
+      <fix>
+      Fix AJP13 Cookie2 parsing. Cookie2 was always send as Cookie.
+      Patch provided by Andre Gebers. (mturk)
+      </fix>
+      <fix>
+      <bug>35862</bug>: NSAPI plugin attempts to read freed memory and attempts to
+      dereference a null pointer. Patch provided by Brian Kavanagh. (markt)
+      </fix>
+    </changelog>
+  </subsection>
+</section>
+<section name="Changes between 1.2.13 and 1.2.14">
+  <br />
+  <subsection name="Native">
+    <changelog>
+      <fix>
+        Fix lb for worker mpm's with cachesize set to lower number then
+        ThreadsPerChild is. If retries is set to value larger then 3 sleep for
+        100 ms on each attempt. This enables to tune the connection cache,
+        and serialize incoming connections instead returning busy if connection
+        count is larger then cachesize. (mturk)
+      </fix>
+      <fix>
+      <bug>36525</bug>: Solaris core dump. (mturk)
+      </fix>
+      <fix>
+      <bug>36102</bug>: Worker actions do not persist. (mturk)
+      </fix>
+      <fix>
+      <bug>35864</bug>: Status worker doesn't list workers.
+      Patch provided by Martin Goldhahn. (mturk)
+      </fix>
+      <fix>
+      <bug>35809</bug>: JkMountCopy don't work for Apache 2.0 Patch provided by
+       Christophe Dubach. (mturk)
+      </fix>
+      <fix>
+      <bug>35298</bug>: Multiple JK/ISAPI redirectors on a single IIS site are not supported
+       Patch provided by Tim Whittington. (mturk)
+      </fix>
+    </changelog>
+  </subsection>
+</section>
+<section name="Changes between 1.2.12 and 1.2.13">
+  <br />
+  <subsection name="Native">
+    <changelog>
+      <fix>
+      <bug>34397</bug>: Emergency was handled as Error. (jfclere)
+      </fix>
+      <fix>
+      <bug>34474</bug>: // in URL were not handled correctly with Apache-1.3. (jfclere)
+      </fix>
+      <fix>
+      Use 64 bits int for transferred/read bytes.
+      </fix>
+      <update>
+      Added JkOptions +FlushPackets used to optimize memory
+      usage when sending large data. (mturk)
+      </update>
+      <update>
+      Added lock directive for load balancer that allows more acurate
+      load balancing in case of burst load. (mturk)
+      </update>
+      <update>
+      Added worker.maintain directive to allow customizing default 10
+      second timeout. On busy servers this value needs to be set on
+      higher value. (mturk)
+      </update>
+      <fix>
+      Fix for NetWare compiler to deal with different types between AP13
+      and AP2 SDKs. (fuankg)
+      </fix>
+      <update>
+      Emit much more legible user.dmp crash analysis output for WIN32. (wrowe)
+      </update>
+     <fix>
+     <bug>34558</bug>: Fix first failover request. (mturk)
+     </fix>
+    </changelog>
+  </subsection>
+</section>
+
+<section name="Changes between 1.2.11 and 1.2.12">
+  <br />
+  <subsection name="Native">
+    <changelog>
+      <update>
+      Added ForwardLocallAddres JkOptions flag for passing local instead remote
+      address. Useful for remote addr valve. (mturk)
+      </update>
+     <fix>Fix that worker not used, when stopped flag is true. (pero)
+     </fix>
+      <update>
+      Add loadbalance default worker secret attribute to the documentation (pero)
+      </update>
+    </changelog>
+  </subsection>
+</section>
+
+<section name="Changes between 1.2.10 and 1.2.11">
+  <br />
+  <subsection name="Native">
+    <changelog>
+      <fix>Backport SC_M_JK_STORED from JK2 for passing arbitrary
+      methods instead failing the request. (mturk)
+      </fix>
+      <fix>Added missing SEARCH and ACL http methods. (mturk)
+      </fix>
+      <update>
+      Add worker secret attribute to the documentation (pero)
+      </update>
+      <update>
+      Add a stopped flag to worker configuration. Set flag True and
+      complete traffic to worker is stopped.
+      Also update the Ant JkStatusUpdateTask at Tomcat 5.5.10 release.
+      Only usefull in a replicated session cluster.(pero)
+      </update>
+      <update>Added worker maintain function that will maintain all
+      the workers instead just the current one. This enables to recycle
+      the connections on all workers. (mturk)
+      </update>
+      <update>Use shutdown when recycling connections instead hard
+      breaking the socket. (mturk)
+      </update>
+      <update>Add unique directives checking. The directives if
+      unique are now overwritten instead concatenated. (mturk)
+      </update>
+      <update>Allow multiple worker.list directives. (mturk)
+      </update>
+      <fix>
+      <bug>34577</bug>: For IIS log original request instead loging
+      the request for ISAPI extension. (mturk)
+      </fix>
+      <fix>
+      <bug>34558</bug>: Make sure the returned status codes are the same
+      for ajp and lb workers. (mturk)
+      </fix>
+      <fix>
+      <bug>34423</bug>: Use APR_USE_FLOCK_SERIALIZE for setting log lock
+      on platforms like FreeBSD. Patch provided by Allan Saddi. (mturk)
+      </fix>
+      <fix>
+      <bug>33843</bug>: Fix obtaining LDFLAGS that were used for building
+      Apache HTTPD. Patch provided by Beat Kneubuehl. (mturk)
+      </fix>
+      <fix>
+      <bug>34358</bug>: Enable load balancer method configuration. (glenn)
+      </fix>
+      <fix>
+      <bug>34357</bug>: In some situations Apache 2 mod_jk could segfault
+      when the JkAutoAlias directive is used. (glenn)
+      </fix>
+      <update>
+        Add --enable-prefork to the documentation (pero)
+      </update>
+    </changelog>
+  </subsection>
+</section>
+<section name="Changes between 1.2.9 and 1.2.10">
+  <br />
+  <subsection name="Native">
+    <changelog>
+      <update>Set default shared memory to 64K instead 1M. (mturk)
+      </update>
+      <fix>Do not mark the worker in error state if headers are
+      larger then AJP13 limit. (mturk)
+      </fix>
+      <update>
+      On Series you should use the latest PTF for Apache 2.0
+      (which is now 2.0.52) and ad minima SI17402/SI17061 or cumulative
+      including them. (hgomez)
+      </update>
+      <update>
+      Change the xml status format to xml attribute syntax (pero)
+      </update>
+      <fix>
+      <bug>33248</bug>: Fix builds where apxs defines multiple
+      directories for APR includes. (mturk)
+      </fix>
+      <fix>
+      <bug>32696</bug>: Return 404 instead 403 when WEB-INF is requested
+      to comply with Servlet spec. (mturk)
+      </fix>
+      <update>Added ANT task for managing jkstatus. (pero)
+      </update>
+      <update>
+      If socket_timeout is set, check if socket is alive before
+      sending any request to Tomcat. (mturk)
+      </update>
+      <update>
+      Added JkMountFile for Apache web servers. This file can contain
+      uri mappings in the form (/url=worker), and is checked for
+      updates at regular 60 second interval. (mturk)
+      </update>
+      <update>
+      Added status worker for managing worker runtime data using
+      web page. (mturk)
+      </update>
+      <update>
+      Added load balancer method directive that is used for setting
+      the algorithm used for balancing workers. Method can be either
+      Request (default) or Traffic. (mturk)
+      </update>
+      <update>
+      Added shared memory to allow dynamic configuration. Shared memory
+      is needed only for unix platform and web servers having multiple
+      child processes. For Apache web server two new directives has been
+      added (JkShmFile and JkShmSize). (mturk)
+      </update>
+      <update>
+      Added textupdate mode to status worker to handle remote updates
+      from ant tasks.(pero)
+      </update>
+      <fix>
+      <bug>33562</bug>: Fix Reply_timeout when recovery_options
+      is larger than 1. Patch provided by Takashi Satou. (mturk)
+      </fix>
+      <fix>
+      <bug>33308</bug>: Fix segfaults when ForwardDirectories is enabled
+        with Apache 1.3
+      </fix>
+    </changelog>
+  </subsection>
+</section>
+<section name="Changes between 1.2.7 and 1.2.8">
+  <br />
+  <subsection name="Native">
+    <changelog>
+      <update>
+      Allow anyone to debug and diagnose stack dumps using windbg or any
+      other debugging tool, and (if they add the .pdb files to their
+      installation) to make sense of dr watson logs.
+      Patch provided by William A. Rowe (wrowe)
+      </update>
+      <fix>
+      Fix in_addr_t usage by using the real struct ignoring typedef.
+      Patch provided by William A. Rowe (wrowe)
+      </fix>
+      <fix>
+      Fix url rewriting by restoring the in place uri from which the
+      jsessionid was removed. (mturk)
+      </fix>
+      <update>
+      Make load balancer algorithm thread safe by introducing mutex
+      to the load balancer worker. (mturk)
+      </update>
+      <fix>
+      Fix sending error pages for IIS to client by adding Content-Type header
+      using correct api function call. (mturk)
+      </fix>
+      <fix>
+      <bug>32696</bug>: Prevent IIS from crushing when web-inf url was requested. (mturk)
+      </fix>
+      <update>
+      Use default cachesize for servers that support discovering the number of
+      threads per child process. (mturk).
+      </update>
+      <fix>
+      Fix Apache content-length header parsing using case insensitive compare. (billbarker)
+      </fix>
+      <fix>
+      Fix parsing AJP headers using case insensitive compare. (mturk)
+      </fix>
+      <fix>
+      Use infinite socket timeout if socket_timeout is set to zero or less then zero. (mturk)
+      </fix>
+      <update>
+      Change <b>balanced_workers</b> to <b>balance_workers</b> but keep
+      backward compatibility preserving the old directive. (mturk).
+      </update>
+      <fix>
+      Fix ajp initialization for workers with cache_size set to zero. (mturk)
+      </fix>
+      <update>
+      <bug>32317</bug>: Making mod_jk replication aware (Clustering Support).
+      Patch provided by Rainer Jung. (mturk).
+      </update>
+      <fix>
+      <bug>31132</bug>: Core dump when JkLogFile is missing from conf. (mturk)
+      </fix>
+    </changelog>
+  </subsection>
+</section>
+<section name="Changes between 1.2.6 and 1.2.7">
+  <br />
+  <subsection name="Native">
+    <changelog>
+      <update>
+      Added new property named recover_time that can be used to change the
+      default 60 second recover time. (mturk)
+      </update>
+      <update>
+      Added custom retries for worker, so we don't depend on default setting.
+      If set to a number grater then 3, it will sleep for 100ms on retry greater
+      then 3 and then try again. (mturk)
+      </update>
+      <update>
+      Added JkWorkerProperty directive that enables omiting workers.properties file.
+      For example: JkWorkerProperty worker.ajp13a.port=8009. (mturk)
+      </update>
+      <fix>
+      Check all JSESSIONID cookies for a valid jvmRoute. If you have multiple Tomcats
+      with overlapping domains, then you can get multiple cookies without a defined order.
+      This will route correctly as long as the different domains don't have any
+      Tomcats in common. (billbarker)
+      </fix>
+      <update>
+      Added JkUnMount directive for negative mappings that works as opposite to JkMount directives.
+      It is used for blocking of particular URL or content type. (mturk)
+      </update>
+      <update>
+      Added wildchar match uri mappings. One can now use JkMount to
+      map /app/*/servlet/* or /app?/*/*.jsp. (mturk)
+      </update>
+      <update>
+      Rewrite the logging by adding Trace options. (mturk)
+      </update>
+      <update>
+      Added socket_timeout property that sets the timeout
+      for the socket itself. (mturk)
+      </update>
+      <fix>
+      Changed socket_timeout property to recycle_timeout. This better
+      explains what the directive actually does. (mturk)
+      </fix>
+      <fix>
+        Changed the load balancer algorithm.
+        The idea behind this new scheduler is the following:
+        lbfactor is <i>how much we expect this worker to work</i>,
+        or <i>the worker's work quota</i>.
+        lbstatus is <i>how urgent this worker has to work to fulfill its quota
+        of work</i>. We distribute each worker's work quota to the worker, and then look
+        which of them needs to work most urgently (biggest lbstatus).  This
+        worker is then selected for work, and its lbstatus reduced by the
+        total work quota we distributed to all workers.  Thus the sum of all
+        lbstatus does not change.(*)
+        If some workers are disabled, the others will
+        still be scheduled correctly. (mturk)
+      </fix>
+    </changelog>
+  </subsection>
+</section>
+<section name="JK 2">
+<p>JK2 has been put in maintainer mode and no further development will take place.
+The reason for shutting down JK2 development was the lack of developers interest.
+Other reason was lack of users interest in adopting JK2, caused by configuration
+complexity when compared to JK.
+</p>
+</section>
+
+</body>
+</document>

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/common/ajpv13a.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/common/ajpv13a.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/common/ajpv13a.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,693 @@
+<?xml version="1.0"?> 
+<!DOCTYPE document [
+  <!ENTITY project SYSTEM "project.xml">
+]>
+<document url="ajpv13a.html">
+
+  &project;
+ <copyright>
+   Copyright 1999-2005 The Apache Software Foundation
+ 
+   Licensed 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.
+</copyright>
+<properties>
+<title>AJPv13</title>
+<author email="danmil at shore.net">danmil at shore.net</author>
+<author email="jfrederic.clere at fujitsu-siemens.com">Jean-Frederic Clere</author>
+<date>$Date: 2005-07-04 03:22:24 -0500 (Mon, 04 Jul 2005) $</date>
+</properties>
+<body>
+<section name="Intro">
+
+<p>
+The original document was written by
+Dan Milstein, <author email="danmil at shore.net">danmil at shore.net</author>
+on December 2000. The present document is generated out of an xml file
+to allow a more easy integration in the Tomcat documentation.
+
+</p>
+
+<p>
+This describes the Apache JServ Protocol version 1.3 (hereafter
+<b>ajp13</b>).  There is, apparently, no current documentation of how the
+protocol works.  This document is an attempt to remedy that, in order to
+make life easier for maintainers of JK, and for anyone who wants to
+port the protocol somewhere (into jakarta 4.x, for example).
+</p>
+
+</section>
+
+<section name="author">
+
+<p>
+I am not one of the designers of this protocol -- I believe that Gal
+Shachor was the original designer.  Everything in this document is derived
+from the actual implementation I found in the tomcat 3.x code.  I hope it
+is useful, but I can't make any grand claims to perfect accuracy.  I also
+don't know why certain design decisions were made.  Where I was able, I've
+offered some possible justifications for certain choices, but those are
+only my guesses.  In general, the C code which Shachor wrote is very clean
+and comprehensible (if almost totally undocumented).  I've cleaned up the
+Java code, and I think it's reasonably readable.
+</p>
+</section>
+
+<section name="Design Goals">
+
+<p>
+According to email from Gal Shachor to the jakarta-dev mailing list,
+the original goals of <b>JK</b> (and thus <b>ajp13</b>) were to extend
+<b>mod_jserv</b> and <b>ajp12</b> by (I am only including the goals which
+relate to communication between the web server and the servlet container):
+
+<ul>
+  <li> Increasing performance (speed, specifically). </li>
+
+  <li> Adding support for SSL, so that <code>isSecure()</code> and
+       <code>getScheme()</code> will function correctly within the servlet
+       container.  The client certificates and cipher suite will be
+       available to servlets as request attributes. </li>
+
+</ul>
+</p>
+</section>
+
+<section name="Overview of the protocol">
+
+<p>
+The <b>ajp13</b> protocol is packet-oriented.  A binary format was
+presumably chosen over the more readable plain text for reasons of
+performance.  The web server communicates with the servlet container over
+TCP connections.  To cut down on the expensive process of socket creation,
+the web server will attempt to maintain persistent TCP connections to the
+servlet container, and to reuse a connection for multiple request/response
+cycles.
+</p><p>
+Once a connection is assigned to a particular request, it will not be
+used for any others until the request-handling cycle has terminated.  In
+other words, requests are not multiplexed over connections.  This makes
+for much simpler code at either end of the connection, although it does
+cause more connections to be open at once.
+</p><p>
+Once the web server has opened a connection to the servlet container,
+the connection can be in one of the following states:
+</p><p>
+<ul>
+  <li> Idle <br/> No request is being handled over this connection. </li>
+  <li> Assigned <br/> The connecton is handling a specific request.</li>
+</ul>
+
+</p><p>
+Once a connection is assigned to handle a particular request, the basic
+request informaton (e.g. HTTP headers, etc) is sent over the connection in
+a highly condensed form (e.g. common strings are encoded as integers).
+Details of that format are below in Request Packet Structure. If there is a
+body to the request (content-length > 0), that is sent in a separate
+packet immediately after.
+</p><p>
+At this point, the servlet container is presumably ready to start
+processing the request.  As it does so, it can send the
+following messages back to the web server:
+
+<ul>
+  <li>SEND_HEADERS <br/>Send a set of headers back to the browser.</li>
+
+  <li>SEND_BODY_CHUNK <br/>Send a chunk of body data back to the browser.</li>
+
+  <li>GET_BODY_CHUNK <br/>Get further data from the request if it hasn't all
+  been transferred yet.  This is necessary because the packets have a fixed
+  maximum size and arbitrary amounts of data can be included the body of a
+  request (for uploaded files, for example).  (Note: this is unrelated to
+  HTTP chunked tranfer).</li>
+
+  <li>END_RESPONSE <br/> Finish the request-handling cycle.</li>
+</ul>
+</p><p>
+
+Each message is accompanied by a differently formatted packet of data.  See
+Response Packet Structures below for details.
+</p>
+</section>
+
+<section name="Basic Packet Structure">
+
+<p>
+There is a bit of an XDR heritage to this protocol, but it differs in
+lots of ways (no 4 byte alignment, for example).
+</p><p>
+Byte order: I am not clear about the endian-ness of the individual
+bytes.  I'm guessing the bytes are little-endian, because that's what XDR
+specifies, and I'm guessing that sys/socket library is magically making
+that so (on the C side).  If anyone with a better knowledge of socket calls
+can step in, that would be great.
+</p><p>
+There are four data types in the protocol: bytes, booleans, integers and
+strings.
+
+<dl>
+  <dt><b>Byte</b></dt>
+  <dd>A single byte.</dd>
+
+  <dt><b>Boolean</b></dt>
+  <dd>A single byte, 1 = true, 0 = false.  Using other non-zero values as
+  true (i.e. C-style) may work in some places, but it won't in
+  others.</dd>
+  
+  <dt><b>Integer</b></dt>
+  <dd>A number in the range of 0 to 2^16 (32768).  Stored in 2 bytes with
+  the high-order byte first.</dd>
+
+  <dt><b>String</b></dt>
+  <dd>A variable-sized string (length bounded by 2^16). Encoded with the
+  length packed into two bytes first, followed by the string (including the
+  terminating '\0').  Note that the encoded length does <b>not</b> include
+  the trailing '\0' -- it is like <code>strlen</code>.  This is a touch
+  confusing on the Java side, which is littered with odd autoincrement
+  statements to skip over these terminators.  I believe the reason this was
+  done was to allow the C code to be extra efficient when reading strings
+  which the servlet container is sending back -- with the terminating \0
+  character, the C code can pass around references into a single buffer,
+  without copying.  If the \0 was missing, the C code would have to copy
+  things out in order to get its notion of a string.</dd>
+</dl>
+</p>
+
+<subsection name="Packet Size">
+<p>
+According to much of the code, the max packet
+size is 8 * 1024 bytes (8K).  The actual length of the packet is encoded in the
+header.
+</p>
+</subsection>
+
+<subsection name="Packet Headers">
+<p>
+Packets sent from the server to the container begin with
+<code>0x1234</code>.  Packets sent from the container to the server begin
+with <code>AB</code> (that's the ASCII code for A followed by the ASCII
+code for B).  After those first two bytes, there is an integer (encoded as
+above) with the length of the payload.  Although this might suggest that
+the maximum payload could be as large as 2^16, in fact, the code sets the
+maximum to be 8K.
+
+
+<table>
+  <tr>
+    <th colspan="6">Packet Format (Server->Container)</th>
+  </tr>
+
+  <tr>
+    <th>Byte</th>
+    <td>0</td>
+    <td>1</td>
+    <td>2</td>
+    <td>3</td>
+    <td>4...(n+3)</td>
+  </tr>
+
+  <tr>
+    <th>Contents</th>
+    <td>0x12</td>
+    <td>0x34</td>
+    <td colspan="2">Data Length (n)</td>
+    <td>Data</td>
+  </tr>
+</table>
+
+<table>
+  <tr>
+    <th colspan="6"><b>Packet Format (Container->Server)</b></th>
+  </tr>
+
+  <tr>
+    <th>Byte</th>
+    <td>0</td>
+    <td>1</td>
+    <td>2</td>
+    <td>3</td>
+    <td>4...(n+3)</td>
+  </tr>
+
+  <tr>
+    <th>Contents</th>
+    <td>A</td>
+    <td>B</td>
+    <td colspan="2">Data Length (n)</td>
+    <td>Data</td>
+  </tr>
+</table>
+</p>
+<p>
+<A NAME="prefix-codes"></A> For most packets, the first byte of the
+payload encodes the type of message.  The exception is for request body
+packets sent from the server to the container -- they are sent with a
+standard packet header (0x1234 and then length of the packet), but without
+any prefix code after that (this seems like a mistake to me).
+</p><p>
+The web server can send the following messages to the servlet container:
+
+<table>
+  <tr>
+    <th>Code</th>
+    <th>Type of Packet</th>
+    <th>Meaning</th>
+  </tr>
+  <tr>
+    <td>2</td>
+    <td>Forward Request</td>
+    <td>Begin the request-processing cycle with the following data</td>
+  </tr>
+  <tr>
+    <td>7</td>
+    <td>Shutdown</td>
+    <td>The web server asks the container to shut itself down.</td>
+  </tr>
+  <tr>
+    <td>8</td>
+    <td>Ping</td>
+    <td>The web server asks the container to take control (secure login phase).</td>
+  </tr>
+  <tr>
+    <td>10</td>
+    <td>CPing</td>
+    <td>The web server asks the container to respond quickly with a CPong.</td>
+  </tr>
+  <tr>
+    <td>none</td>
+    <td>Data</td>
+    <td>Size (2 bytes) and corresponding body data.</td>
+  </tr>
+</table>
+</p>
+<p>
+To ensure some
+basic security, the container will only actually do the <code>Shutdown</code> if the
+request comes from the same machine on which it's hosted.
+</p>
+<p>
+The first <code>Data</code> packet is send immediatly after the <code>Forward Request</code> by the web server.
+</p>
+
+<p>The servlet container can send the following types of messages to the web
+server:
+<table>
+  <tr>
+    <th>Code</th>
+    <th>Type of Packet</th>
+    <th>Meaning</th>
+  </tr>
+  <tr>
+    <td>3</td>
+    <td>Send Body Chunk</td>
+    <td>Send a chunk of the body from the servlet container to the web
+    server (and presumably, onto the browser). </td>
+  </tr>
+  <tr>
+    <td>4</td>
+    <td>Send Headers</td>
+    <td>Send the response headers from the servlet container to the web
+    server (and presumably, onto the browser).</td>
+  </tr>
+  <tr>
+    <td>5</td>
+    <td>End Response</td>
+    <td>Marks the end of the response (and thus the request-handling cycle).</td>
+  </tr>
+  <tr>
+    <td>6</td>
+    <td>Get Body Chunk</td>
+    <td>Get further data from the request if it hasn't all been transferred
+    yet.</td>
+  </tr>
+  <tr>
+    <td>9</td>
+    <td>CPong Reply</td>
+    <td>The reply to a CPing request</td>
+  </tr>
+</table>
+</p>
+<p>
+Each of the above messages has a different internal structure, detailed below.
+</p>
+</subsection>
+</section>
+
+<section name="Request Packet Structure">
+
+<p>
+For messages from the server to the container of type "Forward Request":
+</p><p>
+<source>
+AJP13_FORWARD_REQUEST :=
+    prefix_code      (byte) 0x02 = JK_AJP13_FORWARD_REQUEST
+    method           (byte)
+    protocol         (string)
+    req_uri          (string)
+    remote_addr      (string)
+    remote_host      (string)
+    server_name      (string)
+    server_port      (integer)
+    is_ssl           (boolean)
+    num_headers      (integer)
+    request_headers *(req_header_name req_header_value)
+    attributes      *(attribut_name attribute_value)
+    request_terminator (byte) OxFF
+</source>
+</p><p>
+The <code>request_headers</code> have the following structure:
+</p><p>
+<source>
+req_header_name := 
+    sc_req_header_name | (string)  [see below for how this is parsed]
+
+sc_req_header_name := 0xA0xx (integer)
+
+req_header_value := (string)
+</source>
+</p><p>
+
+The <code>attributes</code> are optional and have the following structure:
+</p><p>
+<source>
+attribute_name := sc_a_name | (sc_a_req_attribute string)
+
+attribute_value := (string)
+
+</source>
+</p><p>
+Not that the all-important header is "content-length', because it
+determines whether or not the container looks for another packet
+immediately.
+</p><p>
+Detailed description of the elements of Forward Request.
+</p>
+<subsection name="request_prefix">
+<p>
+For all requests, this will be 2.
+See above for details on other <A HREF="#prefix-codes">prefix codes</A>.
+</p>
+</subsection>
+
+<subsection name="method">
+<p>
+The HTTP method, encoded as a single byte:
+</p>
+
+<p>
+<table>
+  <tr><th>Command Name</th><th>Code</th></tr>
+  <tr><td>OPTIONS</td><td>1</td></tr>
+  <tr><td>GET</td><td>2</td></tr>
+  <tr><td>HEAD</td><td>3</td></tr>
+  <tr><td>POST</td><td>4</td></tr>
+  <tr><td>PUT</td><td>5</td></tr>
+  <tr><td>DELETE</td><td>6</td></tr>
+  <tr><td>TRACE</td><td>7</td></tr>
+  <tr><td>PROPFIND</td><td>8</td></tr>
+  <tr><td>PROPPATCH</td><td>9</td></tr>
+  <tr><td>MKCOL</td><td>10</td></tr>
+  <tr><td>COPY</td><td>11</td></tr>
+  <tr><td>MOVE</td><td>12</td></tr>
+  <tr><td>LOCK</td><td>13</td></tr>
+  <tr><td>UNLOCK</td><td>14</td></tr>
+  <tr><td>ACL</td><td>15</td></tr>
+  <tr><td>REPORT</td><td>16</td></tr>
+  <tr><td>VERSION-CONTROL</td><td>17</td></tr>
+  <tr><td>CHECKIN</td><td>18</td></tr>
+  <tr><td>CHECKOUT</td><td>19</td></tr>
+  <tr><td>UNCHECKOUT</td><td>20</td></tr>
+  <tr><td>SEARCH</td><td>21</td></tr>
+  <tr><td>MKWORKSPACE</td><td>22</td></tr>
+  <tr><td>UPDATE</td><td>23</td></tr>
+  <tr><td>LABEL</td><td>24</td></tr>
+  <tr><td>MERGE</td><td>25</td></tr>
+  <tr><td>BASELINE_CONTROL</td><td>26</td></tr>
+  <tr><td>MKACTIVITY</td><td>27</td></tr>
+</table>
+</p>
+
+<p>Later version of ajp13, when used with mod_jk2, will transport 
+additional methods, even if they are not in this list.
+</p>
+
+</subsection>
+
+<subsection  name="protocol, req_uri, remote_addr, remote_host, server_name, server_port, is_ssl">
+<p>
+  These are all fairly self-explanatory.  Each of these is required, and
+  will be sent for every request.
+</p>
+</subsection>
+
+<subsection name="Headers">
+<p>
+  The structure of <code>request_headers</code> is the following:
+  First, the number of headers <code>num_headers</code> is encoded.
+  Then, a series of header name <code>req_header_name</code> / value
+  <code>req_header_value</code> pairs follows.
+  Common header names are encoded as integers,
+  to save space.  If the header name is not in the list of basic headers,
+  it is encoded normally (as a string, with prefixed length).  The list of
+  common headers <code>sc_req_header_name</code>and their codes
+  is as follows (all are case-sensitive):
+</p><p>
+<table>
+  <tr><th>Name</th><th>Code value</th><th>Code name</th></tr>
+  <tr><td>accept</td><td>0xA001</td><td>SC_REQ_ACCEPT</td></tr>
+  <tr><td>accept-charset</td><td>0xA002</td><td>SC_REQ_ACCEPT_CHARSET</td></tr>
+  <tr><td>accept-encoding</td><td>0xA003</td><td>SC_REQ_ACCEPT_ENCODING</td></tr>
+  <tr><td>accept-language</td><td>0xA004</td><td>SC_REQ_ACCEPT_LANGUAGE</td></tr>
+  <tr><td>authorization</td><td>0xA005</td><td>SC_REQ_AUTHORIZATION</td></tr>
+  <tr><td>connection</td><td>0xA006</td><td>SC_REQ_CONNECTION</td></tr>
+  <tr><td>content-type</td><td>0xA007</td><td>SC_REQ_CONTENT_TYPE</td></tr>
+  <tr><td>content-length</td><td>0xA008</td><td>SC_REQ_CONTENT_LENGTH</td></tr>
+  <tr><td>cookie</td><td>0xA009</td><td>SC_REQ_COOKIE</td></tr>
+  <tr><td>cookie2</td><td>0xA00A</td><td>SC_REQ_COOKIE2</td></tr>
+  <tr><td>host</td><td>0xA00B</td><td>SC_REQ_HOST</td></tr>
+  <tr><td>pragma</td><td>0xA00C</td><td>SC_REQ_PRAGMA</td></tr>
+  <tr><td>referer</td><td>0xA00D</td><td>SC_REQ_REFERER</td></tr>
+  <tr><td>user-agent</td><td>0xA00E</td><td>SC_REQ_USER_AGENT</td></tr>
+</table>
+</p><p>
+  The Java code that reads this grabs the first two-byte integer and if
+  it sees an <code>'0xA0'</code> in the most significant
+  byte, it uses the integer in the second byte as an index into an array of
+  header names.  If the first byte is not '0xA0', it assumes that the
+  two-byte integer is the length of a string, which is then read in.
+</p><p>
+  This works on the assumption that no header names will have length
+  greater than 0x9999 (==0xA000 - 1), which is perfectly reasonable, though
+  somewhat arbitrary. (If you, like me, started to think about the cookie
+  spec here, and about how long headers can get, fear not -- this limit is
+  on header <b>names</b> not header <b>values</b>.  It seems unlikely that
+  unmanageably huge header names will be showing up in the HTTP spec any time
+  soon).
+</p><p>
+  <b>Note:</b> The <code>content-length</code> header is extremely
+  important.  If it is present and non-zero, the container assumes that
+  the request has a body (a POST request, for example), and immediately
+  reads a separate packet off the input stream to get that body.
+</p>
+</subsection>
+
+<subsection name="Attributes">
+<p>
+
+  The attributes prefixed with a <code>?</code>
+  (e.g. <code>?context</code>) are all optional.  For each, there is a
+  single byte code to indicate the type of attribute, and then a string to
+  give its value.  They can be sent in any order (thogh the C code always
+  sends them in the order listed below).  A special terminating code is
+  sent to signal the end of the list of optional attributes. The list of
+  byte codes is:
+</p><p>
+
+<table>
+  <tr><th>Information</th><th>Code Value</th><th>Note</th></tr>
+  <tr><td>?context</td><td>0x01</td><td>Not currently implemented</td></tr>
+  <tr><td>?servlet_path</td><td>0x02</td><td>Not currently implemented</td></tr>
+  <tr><td>?remote_user</td><td>0x03</td><td></td></tr>
+  <tr><td>?auth_type</td><td>0x04</td><td></td></tr>
+  <tr><td>?query_string</td><td>0x05</td><td></td></tr>
+  <tr><td>?jvm_route</td><td>0x06</td><td></td></tr>
+  <tr><td>?ssl_cert</td><td>0x07</td><td></td></tr>
+  <tr><td>?ssl_cipher</td><td>0x08</td><td></td></tr>
+  <tr><td>?ssl_session</td><td>0x09</td><td></td></tr>
+  <tr><td>?req_attribute</td><td>0x0A</td><td>Name (the name of the attribut follows)</td></tr>
+  <tr><td>?ssl_key_size</td><td>0x0B</td><td></td></tr>
+  <tr><td>are_done</td><td>0xFF</td><td>request_terminator</td></tr>
+</table>
+
+</p><p>
+
+  The <code>context</code> and <code>servlet_path</code> are not currently
+  set by the C code, and most of the Java code completely ignores whatever
+  is sent over for those fields (and some of it will actually break if a
+  string is sent along after one of those codes).  I don't know if this is
+  a bug or an unimplemented feature or just vestigial code, but it's
+  missing from both sides of the connection.
+</p><p>
+  The <code>remote_user</code> and <code>auth_type</code> presumably refer
+  to HTTP-level authentication, and communicate the remote user's username
+  and the type of authentication used to establish their identity (e.g. Basic,
+  Digest).  I'm not clear on why the password isn't also sent, but I don't
+  know HTTP authentication inside and out.
+</p><p>
+  The <code>query_string</code>, <code>ssl_cert</code>,
+  <code>ssl_cipher</code>, and <code>ssl_session</code> refer to the
+  corresponding pieces of HTTP and HTTPS.
+</p><p>
+  The <code>jvm_route</code>, as I understand it, is used to support sticky
+  sessions -- associating a user's sesson with a particular Tomcat instance
+  in the presence of multiple, load-balancing servers.  I don't know the
+  details.
+</p><p>
+  Beyond this list of basic attributes, any number of other attributes can
+  be sent via the <code>req_attribute</code> code (0x0A).  A pair of strings
+  to represent the attribute name and value are sent immediately after each
+  instance of that code.  Environment values are passed in via this method.
+</p><p>
+  Finally, after all the attributes have been sent, the attribute terminator,
+  0xFF, is sent.  This signals both the end of the list of attributes and
+  also then end of the Request Packet.
+</p>
+</subsection>
+
+</section>
+
+<section name="Response Packet Structure">
+
+<p>
+For messages which the container can send back to the server.
+
+<source>
+AJP13_SEND_BODY_CHUNK := 
+  prefix_code   3
+  chunk_length  (integer)
+  chunk        *(byte)
+
+
+AJP13_SEND_HEADERS :=
+  prefix_code       4
+  http_status_code  (integer)
+  http_status_msg   (string)
+  num_headers       (integer)
+  response_headers *(res_header_name header_value)
+
+res_header_name := 
+    sc_res_header_name | (string)   [see below for how this is parsed]
+
+sc_res_header_name := 0xA0 (byte)
+
+header_value := (string)
+
+AJP13_END_RESPONSE :=
+  prefix_code       5
+  reuse             (boolean)
+
+
+AJP13_GET_BODY_CHUNK :=
+  prefix_code       6
+  requested_length  (integer)
+</source>
+
+</p>
+<p>
+Details:
+</p>
+
+<subsection name="Send Body Chunk">
+<p>
+  The chunk is basically binary data, and is sent directly back to the browser.
+</p>
+</subsection>
+
+<subsection name="Send Headers">
+<p>
+  The status code and message are the usual HTTP things (e.g. "200" and "OK").
+  The response header names are encoded the same way the request header names are.
+  See <A HREF="#header_encoding">above</A> for details about how the the
+  codes are distinguished from the strings.  The codes for common headers are:
+</p>
+
+<p>
+<table>
+  <tr><th>Name</th><th>Code value</th></tr>
+  <tr><td>Content-Type</td><td>0xA001</td></tr>
+  <tr><td>Content-Language</td><td>0xA002</td></tr>
+  <tr><td>Content-Length</td><td>0xA003</td></tr>
+  <tr><td>Date</td><td>0xA004</td></tr>
+  <tr><td>Last-Modified</td><td>0xA005</td></tr>
+  <tr><td>Location</td><td>0xA006</td></tr>
+  <tr><td>Set-Cookie</td><td>0xA007</td></tr>
+  <tr><td>Set-Cookie2</td><td>0xA008</td></tr>
+  <tr><td>Servlet-Engine</td><td>0xA009</td></tr>
+  <tr><td>Status</td><td>0xA00A</td></tr>
+  <tr><td>WWW-Authenticate</td><td>0xA00B</td></tr>
+</table>
+
+</p>
+
+<p> 
+  After the code or the string header name, the header value is immediately
+  encoded.
+</p>
+
+</subsection>
+
+<subsection name="End Response">
+<p>
+  Signals the end of this request-handling cycle.  If the
+  <code>reuse</code> flag is true (==1), this TCP connection can now be used to
+  handle new incoming requests.  If <code>reuse</code> is false (anything
+  other than 1 in the actual C code), the connection should be closed.
+</p>
+</subsection>
+
+<subsection name="Get Body Chunk">
+<p>
+  The container asks for more data from the request (If the body was
+  too large to fit in the first packet sent over or when the request is
+  chuncked).
+  The server will send a body packet back with an amount of data which is
+  the minimum of the <code>request_length</code>,
+  the maximum send body size (8186 (8 Kbytes - 6)), and the
+  number of bytes actually left to send from the request body.
+<br/>
+  If there is no more data in the body (i.e. the servlet container is
+  trying to read past the end of the body), the server will send back an
+  "empty" packet, which is a body packet with a payload length of 0.
+  (0x12,0x34,0x00,0x00)
+</p>
+</subsection>
+</section>
+
+<section name="Questions I Have">
+
+<p> What happens if the request headers > max packet size?  There is no
+provision to send a second packet of request headers in case there are more
+than 8K (I think this is correctly handled for response headers, though I'm
+not certain).  I don't know if there is a way to get more than 8K worth of
+data into that initial set of request headers, but I'll bet there is
+(combine long cookies with long ssl information and a lot of environment
+variables, and you should hit 8K easily).  I think the connector would just
+fail before trying to send any headers in this case, but I'm not certain.</p>
+
+<p> What about authentication?  There doesn't seem to be any authentication
+of the connection between the web server and the container.  This strikes
+me as potentially dangerous.</p>
+
+</section>
+
+</body>
+</document>

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/common/ajpv13ext.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/common/ajpv13ext.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/common/ajpv13ext.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,685 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!DOCTYPE document [
+  <!ENTITY project SYSTEM "project.xml">
+]>
+<document url="ajpv13ext.html">
+
+  &project;
+<copyright>
+   Copyright 1999-2004 The Apache Software Foundation
+ 
+   Licensed 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.
+</copyright>
+<properties>
+<title>AJPv13 extensions Proposal</title>
+<author email="hgomez at apache.org">Henri Gomez</author>
+<date>$Date: 2004-11-18 12:24:08 -0600 (Thu, 18 Nov 2004) $</date>
+</properties>
+<body>
+<section name="Introduction">
+<p>
+This document is a proposal of evolution of the current
+Apache JServ Protocol version 1.3, also known as ajp13.  
+I'll not cover here the full protocol but only the add-on from ajp13.
+
+This nth pass include comments from the tomcat-dev list and
+misses discovered during developpment.
+</p>
+<subsection name="Missing features in AJP13">
+<p>
+ajp13 is a good protocol to link a servlet engine like tomcat to a web server like Apache: 
+
+<ul>
+<li>
+use persistants connections to avoid reconnect time at each request
+</li>
+<li>
+encode many http commands to reduce stream size
+</li>
+<li>
+send to servlet engine many info from web server (like SSL certs)
+</li>
+</ul>
+<p>
+But ajp13 lacks support for : 
+</p>
+<ul>
+<li>
+  security between web server and servlet engine.
+  Anybody can connect to an ajp13 port (no login mecanism used)
+  You could connect, for example with telnet, and keep the remote thread
+  up by not sending any data (no timeout in connection)
+</li>
+<li>
+  context information passed from servlet engine to web server.
+  Part of the configuration of JK, the web server connector, is to
+  indicate to the web server which URI to handle. 
+  The mod_jk JkMount directive, told to web server which URI must be 
+  forwarded to servlet engine.
+  A servlet engine allready knows which URI it handle and TC 3.3 is
+  allready capable to generate a config file for JK from the list
+  of available contexts.
+</li>
+<li>
+  state update of contexts from servlet engine to web server.
+  Big site with farm of Tomcat, like ISP and virtuals hosters,
+  may need to stop a context for admin purposes. In that case the front
+  web server must know that the context is currently down, to eventually
+  relay the request to another Tomcat
+</li>
+<li>
+  verify state of connection before sending request.
+  Actually JK send the request to the servlet engine and next wait 
+  for the answer. But one of the beauty of the socket API, is you that 
+  you could write() to a closed connection without any error reporting, 
+  but a read() to a closed connection return you the error code. 
+</li>
+</ul>
+
+</p>
+</subsection>
+
+<subsection name="Proposed add-ons to AJP13">
+<p>
+Let's descrive here the features and add-on that could be added to AJP13.
+Since this document is a proposal, a reasonable level of chaos must be expected at first.
+Be sure that discussion on tomcat list will help clarify points, add 
+features but the current list seems to be a 'minimun vital'
+
+<ul>
+
+<li>
+Advanced login features at connect time
+</li>
+
+<li>
+Basic authorisation system, where a shared secret key is
+present in web server and servlet engine.
+</li>
+
+<li>
+Basic protocol negociation, just to be sure that if functionnalities are added
+to AJP13 in the future, current implementations will still works.
+</li>
+
+<li>
+Clean handling of 'Unknown packets'
+</li>
+
+<li>
+Extended env vars passed from web-server to servlet engine.
+</li>
+
+<li>
+Add extra SSL informations needed by Servlet 2.3 API (like SSL_KEY_SIZE)
+</li>
+
+</ul>
+
+</p>
+</subsection>
+
+<subsection name="Advanced login">
+<p>
+
+<ol>
+<li>
+WEB-SERVER send LOGIN INIT CMD + NEGOCIATION DATA + WEB SERVER INFO
+</li>
+<li>
+  TOMCAT respond with LOGIN SEED CMD + RANDOM DATA
+</li>
+<li>
+  WEB-SERVER calculted the MD5 of RANDOM DATA+SECRET DATA
+</li>
+<li>
+  WEB-SERVER send LOGIN COMP CMD + MD5 (SECRET DATA + RANDOM DATA)
+</li>
+<li>
+  TOMCAT respond with LOGIN STATUS CMD + NEGOCIED DATA + SERVLET ENGINE INFO
+</li>
+</ol>
+
+To prevent DOS attack, the servlet engine will wait
+the LOGIN CMD only 15/30 seconds and reports the
+timeout exception for admins investigation.
+
+The login command will contains basic protocol
+negociation information like compressing ability, 
+crypto, context info (at start up), context update at 
+run-time (up/down), level of SSL env vars, AJP protocol
+level supported (level1/level2/level3...)
+
+The Web server info will contain web server info and
+connector name (ie Apache 1.3.26 + mod_ssl 2.8.8 + mod_jk 1.2.1 + mod_perl 1.25).
+
+The servlet engine will mask the negociation mask with it's own
+mask (what it can do) and return it when loggin is accepted.
+
+This will help having a basic AJP13 implementation (level 1)
+on a web-server working with a more advanced protocol handler on
+the servlet engine side or vice-versa.
+
+AJP13 was designed to be small and fast and so many
+SSL informations present in the web-server are not
+forwarded to the servlet engine. 
+
+We add here four negociations flags to provide more
+informations on client SSL data (certs), server SSL datas, 
+crypto used, and misc datas (timeout...). 
+</p>
+</subsection>
+
+<subsection name="Messages Stream">
+<p>
+<source>
++----------------+------------------+-----------------+
+| LOGIN INIT CMD | NEGOCIATION DATA | WEB SERVER INFO |
++----------------+------------------+-----------------+
+
++----------------+----------------+
+| LOGIN SEED CMD | MD5 of entropy |
++----------------+----------------+
+
++----------------+----------------------------+
+| LOGIN COMP CMD | MD5 of RANDOM + SECRET KEY |
++----------------+----------------------------+
+
++-----------+---------------+---------------------+
+| LOGOK CMD | NEGOCIED DATA | SERVLET ENGINE INFO |
++-----------+---------------+---------------------+
+
++------------+--------------+
+| LOGNOK CMD | FAILURE CODE |
++------------+--------------+
+</source>
+
+<ul>
+<li>
+LOGIN INIT CMD, LOGIN SEED CMD, LOGIN COMP CMD, LOGOK CMD, LOGNOK CMD are 1 byte long.
+</li>
+<li>
+MD5, MD5 of RANDOM + SECRET KEY are 32 chars long.
+</li>
+<li>
+NEGOCIATION DATA, NEGOCIED DATA, FAILURE CODE are 32 bits long.
+</li>
+<li>
+WEB SERVER INFO, SERVLET ENGINE INFO are CString.
+</li>
+</ul>
+
+The secret key will be set by a new propertie in
+workers.properties : secretkey
+<source>
+worker.ajp13.port=8009
+worker.ajp13.host=localhost
+worker.ajp13.type=ajp13
+worker.ajp13.secretkey=myverysecretkey
+</source>
+</p>
+</subsection>
+
+<subsection name="Shutdown feature">
+<p>
+AJP13 miss a functionnality of AJP12, which is shutdown command.
+A logout will tell servlet engine to shutdown itself.
+<source>
++--------------+----------------------------+
+| SHUTDOWN CMD | MD5 of RANDOM + SECRET KEY |
++--------------+----------------------------+
+
++------------+
+| SHUTOK CMD |
++------------+
+
++-------------+--------------+
+| SHUTNOK CMD | FAILURE CODE |
++-------------+--------------+
+</source>
+
+<ul>
+<li>
+SHUTDOWN CMD, SHUTOK CMD, SHUTNOK CMD are 1 byte long.
+</li>
+<li>
+MD5 of RANDOM + SECRET KEY are 32 chars long.
+</li>
+<li>
+FAILURE CODE is 32 bits long.
+</li>
+</ul>
+
+</p>
+</subsection>
+
+<subsection name="Extended Env Vars feature">
+<p>
+NOTA:
+
+While working on AJP13 in JK, I really discovered "JkEnvVar". 
+The following "Extended Env Vars feature" description may not
+be implemented in extended AJP13 since allready available in original
+implementation.
+
+DESC:
+
+Many users will want to see some of their web-server env vars 
+passed to their servlet engine.
+
+To reduce the network traffic, the web-servlet will send a 
+table to describing the external vars in a shorter fashion.
+
+We'll use there a functionnality allready present in AJP13,
+attributes list :
+
+In the AJP13, we've got :
+
+<source>
+AJP13_FORWARD_REQUEST :=
+    prefix_code      2
+    method           (byte)
+    protocol         (string)
+    req_uri          (string)
+    remote_addr      (string)
+    remote_host      (string)
+    server_name      (string)
+    server_port      (integer)
+    is_ssl           (boolean)
+    num_headers      (integer)
+    request_headers *(req_header_name req_header_value)
+
+    ?context       (byte string)
+    ?servlet_path  (byte string)
+    ?remote_user   (byte string)
+    ?auth_type     (byte string)
+    ?query_string  (byte string)
+    ?jvm_route     (byte string)
+    ?ssl_cert      (byte string)
+    ?ssl_cipher    (byte string)
+    ?ssl_session   (byte string)
+
+    ?attributes   *(attribute_name attribute_value)
+    request_terminator (byte)
+</source>
+
+Using short 'web server attribute name' will reduce the 
+network traffic.
+ 
+<source>
++-------------------+---------------------------+-------------------------------+----+
+| EXTENDED VARS CMD | WEB SERVER ATTRIBUTE NAME | SERVLET ENGINE ATTRIBUTE NAME | ES |
++-------------------+---------------------------+-------------------------------+----+
+</source>
+
+ie :
+
+<source>
+JkExtVars S1 SSL_CLIENT_V_START javax.servlet.request.ssl_start_cert_date
+JkExtVars S2 SSL_CLIENT_V_END   javax.servlet.request.ssl_end_cert_date
+JkExtVars S3 SSL_SESSION_ID     javax.servlet.request.ssl_session_id
+
+
++-------------------+----+-------------------------------------------+
+| EXTENDED VARS CMD | S1 | javax.servlet.request.ssl_start_cert_date |
++-------------------+----+-------------------------------------------+
++----+-----------------------------------------+
+| S2 | javax.servlet.request.ssl_end_cert_date |
++----+-----------------------------------------+
++----+-----------------------------------------+
+| S3 | javax.servlet.request.ssl_end_cert_date |
++----+-----------------------------------------+
+</source>
+
+During transmission in extended AJP13 we'll see attributes name
+containing S1, S2, S3 and attributes values of 
+2001/01/03, 2002/01/03, 0123AFE56.
+ 
+This example showed the use of extended SSL vars but 
+any 'personnal' web-server vars like custom authentification
+vars could be reused in the servlet engine.
+The cost will be only some more bytes in the AJP traffic.
+
+<ul>
+<li>
+EXTENDED VARS CMD is 1 byte long.
+</li>
+<li>
+WEB SERVER ATTRIBUTE NAME, SERVLET ENGINE ATTRIBUTE NAME are CString.
+</li>
+<li>
+ES is an empty CString.
+</li>
+</ul>
+
+</p>
+</subsection>
+
+<subsection name="Context informations forwarding for Servlet engine to Web Server">
+<p>
+Just after the LOGON PHASE, the web server will ask for the list of contexts
+and URLs/URIs handled by the servlet engine.
+It will ease installation in many sites, reduce questions about configuration 
+on tomcat-user list, and be ready for servlet API 2.3.
+
+This mode will be activated by a new directive JkAutoMount 
+
+ie: JkAutoMount examples myworker1 /examples/
+
+If we want to get ALL the contexts handled by the servlet engine, willcard
+could be used :
+
+ie: JkAutoMount * myworker1 *
+
+A servlet engine could have many contexts, /examples, /admin, /test.
+We may want to use only some contexts for a given worker. It was
+done previously, in apache HTTP server for example, by setting by 
+hand the JkMount accordingly in each [virtual] area of Apache.
+
+If you web-server support virtual hosting, we'll forward also that
+information to servlet engine which will only return contexts for
+that virtual host. 
+In that case the servlet engine will only return the URL/URI matching
+these particular virtual server (defined in server.xml). 
+This feature will help ISP and big sites which mutualize large farm
+of Tomcat in load-balancing configuration.
+
+<source>
++-----------------+-------------------+----------+----------+----+
+| CONTEXT QRY CMD | VIRTUAL HOST NAME | CONTEXTA | CONTEXTB | ES |
++-----------------+-------------------+----------+----------+----+
+
++------------------+-------------------+----------+-------------------+----------+---------------+----+
+| CONTEXT INFO CMD | VIRTUAL HOST NAME | CONTEXTA | URL1 URL2 URL3 ES | CONTEXTB | URL1 URL2 ... | ES |
++------------------+-------------------+----------+-------------------+----------+---------------+----+
+</source>
+
+We'll discover via context-query, the list of URL/MIMES handled by the remove servlet engine
+for a list of contextes.
+In wildcard mode, CONTEXTA will contains just '*'.
+
+<ul>
+<li>
+CONTEXT QRY CMD and CONTEXT INFO CMD are 1 byte long.
+</li>
+<li>
+VIRTUAL HOST NAME is a CString, ie an array of chars terminated by a null byte (/0).
+</li>
+<li>
+An empty string is just a null byte (/0).
+</li>
+<li>
+ES is an empty CString. Indicate end of URI/URLs or end of CONTEXTs.
+</li>
+</ul>
+
+NB:<br/>
+When VirtualMode is not to be used, the VIRTUAL HOST NAME is '*'.
+In that case the servlet engine will send all contexts handled.
+</p>
+</subsection>
+
+<subsection name="Context informations updates from Servlet engine to Web Server">
+<p>
+Context update are messages caming from the servlet engine each time a context 
+is desactivated/reactivated. The update will be in use when the directive JkUpdateMount.
+This directive will set the AJP13_CONTEXT_UPDATE_NEG flag.
+
+ie: JkUpdateMount myworker1
+
+<source>
++--------------------+-------------------+----------+--------+----------+--------+----+
+| CONTEXT UPDATE CMD | VIRTUAL HOST NAME | CONTEXTA | STATUS | CONTEXTB | STATUS | ES |
++--------------------+-------------------+----------+--------+----------+--------+----+
+</source>
+
+<ul>
+<li>
+CONTEXT UPDATE CMD, STATUS are 1 byte long.
+</li>
+<li>
+VIRTUAL HOST NAME, CONTEXTS are CString.
+</li>
+<li>
+ES is an empty CString. Indicate end of CONTEXTs.
+</li>
+</ul>
+
+NB:<br/>
+When VirtualMode is not in use, the VIRTUAL HOST NAME is '*'.
+STATUS is one byte indicating if context is UP/DOWN/INVALID
+</p>
+</subsection>
+
+<subsection name="Context status query to Servlet engine">
+<p>
+This query will be used by the web-server to determine if a given
+contexts are UP, DOWN or INVALID (and should be removed).
+
+<source>
++-------------------+--------------------+----------+----------+----+
+| CONTEXT STATE CMD |  VIRTUAL HOST NAME | CONTEXTA | CONTEXTB | ES |
++-------------------+--------------------+----------+----------+----+
+
++-------------------------+-------------------+----------+--------+----------+--------+----+
+| CONTEXT STATE REPLY CMD | VIRTUAL HOST NAME | CONTEXTA | STATUS | CONTEXTB | STATUS | ES |
++-------------------------+-------------------+----------+-------------------+--------+----+
+</source>
+
+<ul>
+<li>
+CONTEXT STATE CMD, CONTEXT STATE REPLY CMD, STATUS are 1 byte long.
+</li>
+<li>
+VIRTUAL HOST NAME, CONTEXTs are CString
+</li>
+<li>
+ES is an empty CString
+</li>
+</ul>
+
+NB:<br/>
+When VirtualMode is not in use, the VIRTUAL HOST NAME is an empty string. 
+</p>
+</subsection>
+
+<subsection name="Handling of unknown packets">
+<p>
+Sometimes even with a well negocied protocol, we may be in a situation 
+where one end (web server or servlet engine), will receive a message it
+couldn't understand. In that case the receiver will send an 
+'UNKNOW PACKET CMD' with attached the unhandled message.
+
+<source>
++--------------------+------------------------+-------------------+
+| UNKNOWN PACKET CMD | UNHANDLED MESSAGE SIZE | UNHANDLED MESSAGE |
++--------------------+------------------------+-------------------+
+</source>
+
+Depending on the message, the sender will report an error and if 
+possible will try to forward the message to another endpoint.
+
+<ul>
+<li>
+UNKNOWN PACKET CMD is 1 byte long.
+</li>
+<li>
+UNHANDLED MESSAGE SIZE is 16bits long.
+</li>
+<li>
+UNHANDLED MESSAGE is an array of byte (length is contained in UNHANDLED MESSAGE SIZE)
+</li>
+</ul>
+
+NB:<br/>
+added UNHANDLED MESSAGE SIZE (development)
+</p>
+</subsection>
+
+<subsection name="Verification of connection before sending request">
+<p>
+NOTA: This fonctionality may never be used, since it may slow up the normal process
+since requiring on the web-server side an extra IO (read) before forwarding
+the request.....
+
+One of the beauty of socket APIs, is that you could write on a half closed socket.
+When servlet engine close the socket, the web server will discover it only at the
+next read() to the socket. 
+Basically, in the AJP13 protocol, the web server send the HTTP HEADER and HTTP BODY 
+(POST by chunk of 8K) to the servlet engine and then try to receive the reply. 
+If the connection was broken the web server will learn it only at receive time.
+
+We could use a buffering scheme but what happen when you use the servlet engine
+for upload operations with more than 8ko of datas ?
+
+The hack in the AJP13 protocol is to add some bytes to read after the end of the
+service :
+
+<source>
+EXAMPLE OF DISCUSSION BETWEEN WEB SERVER AND SERVLET ENGINE
+
+AJP HTTP-HEADER (+ HTTP-POST)   (WEB->SERVLET)
+
+AJP HTTP-REPLY					(SERVLET->WEB)
+
+AJP END OF DISCUSSION			(SERVLET->WEB)
+						
+---> AJP STATUS 				(SERVLET->WEB AJP13)
+</source>
+
+The AJP STATUS will not be read by the servlet engine at the end of 
+the request/response #N but at the begining of the next session.
+
+More at that time the web server could also use OS dependants functions
+(or better APR functions) to determine if there is also more data 
+to read. And that datas could be CONTEXT Updates. 
+
+This will avoid the web server sending a request to a 
+desactivated context. In that case, if the load-balancing is used,
+it will search for another servlet engine to handle the request.
+
+And that feature will help ISP and big sites with farm of tomcat, 
+to updates their servlet engine without any service interruption.
+
+<source>
++------------+-------------+
+| STATUS CMD | STATUS DATA |
++------------+-------------+
+</source>
+
+<ul>
+<li>
+STATUS CMD and STATUS DATA are one byte long.
+</li>
+</ul>
+</p>
+</subsection>
+
+</section>
+
+<section name="Conclusion">
+<p>
+The goal of the extended AJP13 protocol is to overcome some of the original AJP13 limitation.
+An easier configuration, a better support for large site and farm of Tomcat, 
+a simple authentification system and provision for protocol updates.
+
+Using the stable ajp13 implementation in JK (native) and in servlet 
+engine (java), it's a reasonable evolution of the well known ajp13.
+</p>
+</section>
+
+<section name="Commands and IDs in extended AJP13 Index">
+<p>
+Index of Commands and ID to be added in AJP13 Protocol
+</p>
+
+<subsection name="Commands IDs">
+<p>
+<table>
+  <tr><th>Command Name</th><th>Command Number</th></tr>
+  <tr><td>AJP13_LOGINIT_CMD</td><td>0x10</td></tr>
+  <tr><td>AJP13_LOGSEED_CMD</td><td>0x11</td></tr>
+  <tr><td>AJP13_LOGCOMP_CMD</td><td>0x12</td></tr>
+  <tr><td>AJP13_LOGOK_CMD</td><td>0x13</td></tr>
+  <tr><td>AJP13_LOGNOK_CMD</td><td>0x14</td></tr>
+  <tr><td>AJP13_CONTEXT_QRY_CMD</td><td>0x15</td></tr>
+  <tr><td>AJP13_CONTEXT_INFO_CMD</td><td>0x16</td></tr>
+  <tr><td>AJP13_CONTEXT_UPDATE_CMD</td><td>0x17</td></tr>
+  <tr><td>AJP13_STATUS_CMD</td><td>0x18</td></tr>
+  <tr><td>AJP13_SHUTDOWN_CMD</td><td>0x19</td></tr>
+  <tr><td>AJP13_SHUTOK_CMD</td><td>0x1A</td></tr>
+  <tr><td>AJP13_SHUTNOK_CMD</td><td>0x1B</td></tr>
+  <tr><td>AJP13_CONTEXT_STATE_CMD</td><td>0x1C</td></tr>
+  <tr><td>AJP13_CONTEXT_STATE_REP_CMD</td><td>0x1D</td></tr>
+  <tr><td>AJP13_UNKNOW_PACKET_CMD</td><td>0x1E</td></tr>
+</table>
+
+</p>
+</subsection>
+
+<subsection name="Negociations Flags">
+<p>
+<table>
+  <tr><th>Command Name</th><th>Number</th><th>Description</th></tr>
+  <tr><td>AJP13_CONTEXT_INFO_NEG</td><td>0x80000000</td><td>web-server want context info after login</td></tr>
+  <tr><td>AJP13_CONTEXT_UPDATE_NEG</td><td>0x40000000</td><td>web-server want context updates</td></tr>
+  <tr><td>AJP13_GZIP_STREAM_NEG</td><td>0x20000000</td><td>web-server want compressed stream</td></tr>
+  <tr><td>AJP13_DES56_STREAM_NEG</td><td>0x10000000</td><td>web-server want crypted DES56 stream with secret key</td></tr>
+  <tr><td>AJP13_SSL_VSERVER_NEG</td><td>0x08000000</td><td>Extended info on server SSL vars</td></tr>
+  <tr><td>AJP13_SSL_VCLIENT_NEG</td><td>0x04000000</td><td>Extended info on client SSL vars</td></tr>
+  <tr><td>AJP13_SSL_VCRYPTO_NEG</td><td>0x02000000</td><td>Extended info on crypto SSL vars</td></tr>
+  <tr><td>AJP13_SSL_VMISC_NEG</td><td>0x01000000</td><td>Extended info on misc SSL vars</td></tr>
+</table>
+
+<br/>
+
+<table>
+  <tr><th>Negociation ID</th><th>Number</th><th>Description</th></tr>
+  <tr><td>AJP13_PROTO_SUPPORT_AJPXX_NEG</td><td>0x00FF0000</td><td>mask of protocol supported</td></tr>
+  <tr><td>AJP13_PROTO_SUPPORT_AJP13L1_NEG</td><td>0x00010000</td><td>communication could use AJP13 Level 1</td></tr>
+  <tr><td>AJP13_PROTO_SUPPORT_AJP13L2_NEG</td><td>0x00020000</td><td>communication could use AJP13 Level 2</td></tr>
+  <tr><td>AJP13_PROTO_SUPPORT_AJP13L3_NEG</td><td>0x00040000</td><td>communication could use AJP13 Level 3</td></tr>
+</table>
+
+<br/>
+All others flags must be set to 0 since they are reserved for future use.
+
+</p>
+</subsection>
+
+<subsection name="Failure IDs">
+<p>
+<table>
+  <tr><th>Failure Id</th><th>Number</th></tr>
+  <tr><td>AJP13_BAD_KEY_ERR</td><td>0xFFFFFFFF</td></tr>
+  <tr><td>AJP13_ENGINE_DOWN_ERR</td><td>0xFFFFFFFE</td></tr>
+  <tr><td>AJP13_RETRY_LATER_ERR</td><td>0xFFFFFFFD</td></tr>
+  <tr><td>AJP13_SHUT_AUTHOR_FAILED_ERR</td><td>0xFFFFFFFC</td></tr>
+</table>
+</p>
+</subsection>
+
+<subsection name="Status">
+<p>
+<table>
+  <tr><th>Failure Id</th><th>Number</th></tr>
+  <tr><td>AJP13_CONTEXT_DOWN</td><td>0x01</td></tr>
+  <tr><td>AJP13_CONTEXT_UP</td><td>0x02</td></tr>
+  <tr><td>AJP13_CONTEXT_OK</td><td>0x03</td></tr>
+</table>
+</p>
+</subsection>
+
+</section>
+</body>
+</document>

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/common/project.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/common/project.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/common/project.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<project name="Application Developer's Guide"
+        href="http://tomcat.apache.org/">
+
+    <title>Tomcat Connector</title>
+
+    <logo href="/images/tomcat.gif">
+    Tomcat Connector
+    </logo>    
+<body>
+
+    <menu name="Links">
+        <item name="Docs Home"             href="../index.html"/>
+    </menu>
+
+    <menu name="AJP Protocol">
+        <item name="AJPv13"                     href="ajpv13a.html"/>
+        <item name="AJPv13 extension Proposal"  href="ajpv13ext.html"/>
+    </menu>
+
+</body>
+</project>

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/common/tools.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/common/tools.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/common/tools.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,94 @@
+<?xml version="1.0"?>
+<!DOCTYPE document [
+  <!ENTITY project SYSTEM "project.xml">
+]>
+<document url="tools.html">
+ 
+  &project;
+<copyright>
+   Copyright 1999-2005 The Apache Software Foundation
+ 
+   Licensed 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.
+</copyright>
+<properties>
+<title>Tools</title>
+<author>Glenn Nielsen</author>
+<date>$Date: 2005-07-04 09:14:53 -0500 (Mon, 04 Jul 2005) $</date>
+</properties>
+<body>
+<section name="Introduction">
+<p>Documentation for additional mod_jk related tools.</p>
+</section>
+
+<section name="Reports">
+<p>
+The mod_jk source distribution contains two perl scripts in the
+jk/tools/reports directory which can be used to analyze the mod_jk
+logs, save statistical data, and generate report graphs.
+</p>
+
+<p><code>tomcat_trend.pl log_dir archive_dir</code></p>
+<p>
+Script for analyzing mod_jk.log data when logging tomcat request data using
+the <code>JkRequestLogFormat</code> Apache mod_jk configuration.
+Generates statistics for request latency and errors.  Archives the generated
+data to files for later use in long term trend graphs and reports.
+</p>
+
+<p><code>tomcat_reports.pl archive_dir reports_dir</code></p>
+<p>
+Script for generating reports and graphs using statistical data generated
+by the <code>tomcat_trend.pl</code> script.
+
+The following graphs are created:
+<ul>
+  <li>tomcat_request.png - Long term trend graph of total number of tomcat
+    requests handled.</li>
+  <li>tomcat_median.png - Long term overall trend graph of tomcat request
+    latency median.</li>
+  <li>tomcat_deviation.png - Long term overall trend graph of tomcat request
+    mean and standard deviation.</li>
+  <li>tomcat_error.png - Long term trend graph of requests rejected by tomcat.
+    Shows requests rejected when tomcat has no request processors available.
+    Can be an indicator that tomcat is overloaded or having other scaling
+    problems.</li>
+  <li>tomcat_client.png - Long term trend graph of requests forward to tomcat
+    which were aborted by the remote client (browser).  You will normally see
+    some aborted requests.  High numbers of these can be an indicator that
+    tomcat is overloaded or there are requests which have very high latency.</li>
+</ul>
+</p>
+
+<p>
+A great deal of statistical data is generated but at this time
+only long term trend graphs are being created and no reports.
+This is only a start.  Many more graphs and reports could be
+generated from the data. Please consider contributing back any
+new reports or graphs you create.  Thanks.
+</p>
+
+<p>
+These perl scripts depend upon the following perl modules and libraries:
+<ul>
+  <li>GD 1.8.x graphics library <a href="http://www.boutell.com/gd/">
+    http://www.boutell.com/gd/</a></li>
+  <li>GD 1.4.x perl module</li>
+  <li>GD Graph perl module</li>
+  <li>GD TextUtil perl module</li>
+  <li>StatisticsDescriptive perl module</li>
+</ul>
+</p>
+</section>
+
+</body>
+</document>

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/config/apache.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/config/apache.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/config/apache.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,547 @@
+<?xml version="1.0"?>
+<!DOCTYPE document [
+  <!ENTITY project SYSTEM "project.xml">
+]>
+<document url="apache.html">
+
+    &project; 
+
+    <properties>
+        <author email="mturk at apache.org">Mladen Turk</author>
+        <title>Configuring Apache</title>
+    </properties>
+
+<body>
+
+<section name="Configuration Directives">
+<p>
+Here are the all directives supported by Apache:
+</p>
+<attributes name="Directive">
+<attribute name="JkWorkersFile" required="false"><p>
+The name of a worker file for the Tomcat servlet containers
+</p></attribute>
+<attribute name="JkWorkerProperty" required="false"><p>
+Enables setting workers.properties inside Apache configuration file.
+This directive is available in jk1.2.7 version and later.
+</p></attribute>
+<attribute name="JkMount" required="false"><p>
+A mount point from a context to a Tomcat worker
+</p></attribute>
+<attribute name="JkMountFile" required="false"><p>
+File containing multiple mappings from a context to a Tomcat worker
+</p></attribute>
+<attribute name="JkUnMount" required="false"><p>
+A no mount point from a context to a Tomcat worker
+This directive is available in jk1.2.7 version and later.
+</p></attribute>
+<attribute name="JkMountCopy" required="false"><p>
+Should the base server mounts be copied to the virtual server.
+</p></attribute>
+<attribute name="JkLogFile" required="false"><p>
+Full or server relative path to the Tomcat Connector module log file
+</p></attribute>
+<attribute name="JkLogLevel" required="false"><p>
+The Tomcat Connector module log level, can be debug, info, warn
+error or trace
+</p></attribute>
+<attribute name="JkLogStampFormat" required="false"><p>
+The Tomcat Connector module <b>date</b> log format, follow strftime syntax
+</p></attribute>
+<attribute name="JkRequestLogFormat" required="false"><p>
+Request log format string. See detailed description below.
+</p></attribute>
+<attribute name="JkAutoAlias" required="false"><p>
+Automatically Alias webapp context directories into the Apache
+document space. 
+</p></attribute>
+<attribute name="JkHTTPSIndicator" required="false"><p>
+Name of the Apache environment variable that contains SSL indication
+</p></attribute>
+<attribute name="JkCERTSIndicator" required="false"><p>
+Name of the Apache environment variable that contains SSL client certificates
+</p></attribute>
+<attribute name="JkCIPHERIndicator" required="false"><p>
+Name of the Apache environment variable that contains SSL client cipher
+</p></attribute>
+<attribute name="JkSESSIONIndicator" required="false"><p>
+Name of the Apache environment variable that contains SSL session
+</p></attribute>
+<attribute name="JkKEYSIZEIndicator" required="false"><p>
+Name of the Apache environment variable that contains SSL key size in use
+</p></attribute>
+<attribute name="JkExtractSSL" required="false"><p>
+Turns on SSL processing and information gathering by mod_jk
+</p></attribute>
+<attribute name="JkOptions" required="false"><p>
+Set one of more options to configure the mod_jk module. See below for
+details about this directive
+</p></attribute>
+<attribute name="JkEnvVar" required="false"><p>
+Adds a name of environment variable that should be sent to servlet-engine as a request atribute
+</p></attribute>
+
+<attribute name="JkShmFile" required="false"><p>
+Shared memory file name. Used only on unix platforms.
+</p></attribute>
+<attribute name="JkShmSize" required="false"><p>
+Size of the shared memory file name. Default is 64 k.
+</p></attribute>
+
+</attributes>
+</section>
+
+<section name="Configuration Directives Types">
+<p>
+We'll discuss here the mod_jk directive types.
+</p>
+
+<subsection name="Define workers">
+<p>
+<b>JkWorkersFile</b> specify the location where mod_jk will find the workers definitions.
+Take a look at <a href="workers.html">Workers documentation</a> for detailed description.
+
+<source>
+  
+  JkWorkersFile     /etc/httpd/conf/workers.properties
+</source>
+
+<br/>
+<br/>
+</p>
+</subsection>
+
+<subsection name="Logging">
+<p>
+<b>JkLogFile</b> specify the location where mod_jk is going to place its log file.
+</p>
+
+<source>
+  JkLogFile     /var/log/httpd/mod_jk.log
+</source>
+
+<p>
+Since JK 1.2.3 for Apache 2.0 and JK 1.2.16 for Apache 1.3 this can also
+be used for piped logging:
+</p>
+
+<source>
+  JkLogFile     "|/usr/bin/rotatelogs /var/log/httpd/mod_jk.log 86400"
+</source>
+
+<p>
+<b>JkLogLevel</b>
+set the log level between :
+</p>
+
+<ul>
+<li>
+<b>info</b> log will contain standard mod_jk activity (default).
+</li>
+<li>
+<b>warn</b> log will contain non fatal error reports.
+</li>
+<li>
+<b>error</b> log will contain also error reports.
+</li>
+<li>
+<b>debug</b> log will contain all information on mod_jk activity
+</li>
+<li>
+<b>trace</b> log will contain all tracing information on mod_jk activity
+</li>
+</ul>
+
+<source>  
+  JkLogLevel    info
+</source>
+
+<p>
+<code>info</code> should be your default selection for normal operations.
+<br/>
+<br/>
+</p>
+
+<p>
+<b>JkLogStampFormat</b> will configure the date/time format found on mod_jk log file. 
+Using the strftime() format string it's set by<br />
+default to <b>"[%a %b %d %H:%M:%S %Y]"</b>
+</p>
+
+<source>
+  JkLogStampFormat "[%a %b %d %H:%M:%S %Y] "
+</source>
+
+<p>
+<br/>
+<br/>
+</p>
+
+<p>
+<b>JkRequestLogFormat</b> will configure the format of mod_jk individual request logging. 
+Request logging is configured and enabled on a per virtual host basis. 
+To enable request logging for a virtual host just add a JkRequestLogFormat config. 
+The syntax of the format string is similar to the Apache LogFormat command, 
+here is a list of the available request log format options:
+</p>
+                       
+<p>
+<attributes name="Options">
+  <attribute name="%b" required="false">Bytes sent, excluding HTTP headers (CLF format)</attribute>
+  <attribute name="%B" required="false">Bytes sent, excluding HTTP headers</attribute>
+  <attribute name="%H" required="false">The request protocol</attribute>
+  <attribute name="%m" required="false">The request method</attribute>
+  <attribute name="%p" required="false">The canonical Port of the server serving the request</attribute>
+  <attribute name="%q" required="false">The query string (prepended with a ? if a query string exists, otherwise an empty string)</attribute>
+  <attribute name="%r" required="false">First line of request</attribute>
+  <attribute name="%s" required="false">Request HTTP status code</attribute>
+  <attribute name="%T" required="false">Request duration, elapsed time to handle request in seconds '.' micro seconds</attribute>
+  <attribute name="%U" required="false">The URL path requested, not including any query string.</attribute>
+  <attribute name="%v" required="false">The canonical ServerName of the server serving the request</attribute>
+  <attribute name="%V" required="false">The server name according to the UseCanonicalName setting</attribute>
+  <attribute name="%w" required="false">Tomcat worker name</attribute>
+</attributes>
+
+<source>
+  JkRequestLogFormat     "%w %V %T"
+</source>
+
+<br/>
+<br/>
+</p>
+
+<p>
+You can also log mod_jk information using the Apache standard module <b>mod_log_config</b>.
+The module sets several notes in the Apache httpd notes table.
+Most of them are are only useful in combination with a load balancer worker.
+</p>
+                       
+<p>
+<attributes name="Note">
+  <attribute name="JK_WORKER_NAME" required="false">Name of the worker selected by the URI mapping</attribute>
+  <attribute name="JK_WORKER_TYPE" required="false">Type of the worker selected by the URI mapping</attribute>
+  <attribute name="JK_REQUEST_DURATION" required="false">Request duration in seconds and microseconds.
+                                                         At the moment only available if JkRequestLogFormat is set.</attribute>
+  <attribute name="JK_LB_FIRST_NAME" required="false">Load-Balancer: Name of the first worker tried</attribute>
+  <attribute name="JK_LB_FIRST_TYPE" required="false">Load-Balancer: Type of the first worker tried</attribute>
+  <attribute name="JK_LB_FIRST_ACCESSED" required="false">Load-Balancer: Access count for the first worker tried</attribute>
+  <attribute name="JK_LB_FIRST_READ" required="false">Load-Balancer: Bytes read for the first worker tried</attribute>
+  <attribute name="JK_LB_FIRST_TRANSFERRED" required="false">Load-Balancer: Bytes transferred for the first worker tried</attribute>
+  <attribute name="JK_LB_FIRST_ERRORS" required="false">Load-Balancer: Error count for the first worker tried</attribute>
+  <attribute name="JK_LB_FIRST_BUSY" required="false">Load-Balancer: Busy count for the first worker tried</attribute>
+  <attribute name="JK_LB_LAST_NAME" required="false">Load-Balancer: Name of the last worker tried</attribute>
+  <attribute name="JK_LB_LAST_TYPE" required="false">Load-Balancer: Type of the last worker tried</attribute>
+  <attribute name="JK_LB_LAST_ACCESSED" required="false">Load-Balancer: Access count for the last worker tried</attribute>
+  <attribute name="JK_LB_LAST_READ" required="false">Load-Balancer: Bytes read for the last worker tried</attribute>
+  <attribute name="JK_LB_LAST_TRANSFERRED" required="false">Load-Balancer: Bytes transferred for the last worker tried</attribute>
+  <attribute name="JK_LB_LAST_ERRORS" required="false">Load-Balancer: Error count for the last worker tried</attribute>
+  <attribute name="JK_LB_LAST_BUSY" required="false">Load-Balancer: Busy count for the last worker tried</attribute>
+</attributes>
+
+<source>
+  LogFormat     "%h %l %u %t \"%r\" %>s %b %{JK_WORKER_NAME}n %{JK_LB_FIRST_NAME}n %{JK_LB_FIRST_BUSY}n %{JK_LB_LAST_NAME}n %{JK_LB_LAST_BUSY}n" mod_jk_log
+  CustomLog     logs/access_log     mod_jk_log
+</source>
+
+<br/>
+<br/>
+</p>
+
+</subsection>
+
+<subsection name="Forwarding">
+<p>
+The directive JkOptions allow you to set many forwarding options which will enable (+)
+or disable (-) following option.
+<br/>
+<br/>
+</p>
+
+<p>
+JkOptions <b>ForwardKeySize</b>,  you ask mod_jk, when using ajp13, to forward also the SSL Key Size  as 
+required by Servlet API 2.3.
+This flag shouldn't be set when servlet engine is Tomcat 3.2.x (on by default).
+
+<source>  
+  JkOptions     +ForwardKeySize
+</source>
+
+<br/>
+<br/>
+</p>
+
+<p>
+JkOptions <b>ForwardURICompat</b>, you ask mod_jk to send the URI to Tomcat normally, 
+which is less spec compliant but mod_rewrite compatible, 
+use it for compatibility with Tomcat 3.2.x engines (on by default).
+
+<source>  
+  JkOptions     +ForwardURICompat
+</source>
+
+<br/>
+<br/>
+</p>
+
+<p>
+JkOptions <b>ForwardURICompatUnparsed</b>, the forwarded URI 
+is unparsed, it's spec compliant but broke mod_rewrite.
+
+<source>  
+  JkOptions     +ForwardURICompatUnparsed
+</source>
+
+<br/>
+<br/>
+</p>
+
+<p>
+JkOptions <b>ForwardURIEscaped</b>, the forwarded URI is escaped and 
+Tomcat (since 3.3 rc2) will do the decoding part.
+
+<source>  
+  JkOptions     +ForwardURIEscaped
+</source>
+
+<br/>
+<br/>
+</p>
+
+<p>
+JkOptions <b>ForwardDirectories</b> is used in conjunction with <b>DirectoryIndex</b> 
+directive of Apache web server. As such mod_dir should be available to Apache,
+statically or dynamically (DSO)
+<br/>
+<br/>
+</p>
+
+<p>
+When DirectoryIndex is configured, Apache will create sub-requests for
+each of the local-url's specified in the directive, to determine if there is a
+local file that matches (this is done by stat-ing the file).
+</p>
+
+<p>
+If ForwardDirectories is set to false (default) and Apache doesn't find any
+files that match, Apache will serve the content of the directory (if directive
+Options specifies Indexes for that directory) or a <code>403 Forbidden</code> response (if
+directive Options doesn't specify Indexes for that directory).
+</p>
+
+<p>
+If ForwarDirectories is set to true and Apache doesn't find any files that
+match, the request will be forwarded to Tomcat for resolution. This is used in
+cases when Apache cannot see the index files on the file system for various
+reasons: Tomcat is running on a different machine, the JSP file has been
+precompiled etc. 
+</p>
+
+<p>Note that locally visible files will take precedence over the
+ones visible only to Tomcat (i.e. if Apache can see the file, that's the one
+that's going to get served). This is important if there is more then one type of
+file that Tomcat normally serves - for instance Velocity pages and JSP pages.
+
+<source>  
+  JkOptions     +ForwardDirectories
+</source>
+<br/>
+<br/>
+</p>
+
+<p>
+JkOptions <b>ForwardLocalAddress</b>, you ask mod_jk to send the local address,
+of the Apache web server instead remote client address. This can be used by
+Tomcat remote address valve for allowing connections only from registered Apache
+web servers.
+
+<source>  
+  JkOptions     +ForwardLocalAddress
+</source>
+
+<br/>
+<br/>
+</p>
+
+<p>
+JkOptions <b>FlushPackets</b>, you ask mod_jk to flush Apache's connection
+buffer after each AJP packet chunk received from Tomcat. This option can have
+a strong performance penalty for Apache and Tomcat as writes are performed
+more often than would normally be required (ie: at the end of each
+response).
+
+<source>  
+  JkOptions     +FlushPackets
+</source>
+
+<br/>
+<br/>
+</p>
+
+<p>
+JkOptions <b>DisableReuse</b>, you ask mod_jk to close connections immediately
+after their use. Normally mod_jk uses persistent connections and pools idle
+connections to reuse them, when new requests have to be sent to Tomcat.
+</p>
+
+<p>
+Using this option will have a strong performance penalty for Apache and Tomcat.
+Use this only as a last resort in case of unfixable network problems.
+If a firewall between Apache and Tomcat silently kills idle connections,
+try to use the worker attribute socket_keepalive in combination with an appropriate
+TCP keepalive value in your OS.
+
+<source>  
+  JkOptions     +DisableReuse
+</source>
+
+<br/>
+<br/>
+</p>
+
+<p>
+The directive <b>JkEnvVar</b> allows you to forward an environment variable from Apache server to Tomcat engine.
+The variable can be retrieved on the Tomcat side as a request attribute.
+You must add a default value as a second parameter to the directive.
+
+<source>  
+  JkEnvVar     SSL_CLIENT_V_START     undefined
+</source>
+<br/>
+<br/>
+</p>
+
+</subsection>
+
+<subsection name="Assigning URLs to Tomcat">
+<p>
+If you have created a custom or local version of mod_jk.conf-local as noted above, 
+you can change settings such as the workers or URL prefix.
+</p>
+<p>
+<b>JkMount</b> directive assign specific URLs to Tomcat. 
+In general the structure of a JkMount directive is:
+</p>
+
+<source>  
+  JkMount [URL prefix] [Worker name]
+</source>
+
+<source>
+  # send all requests ending in .jsp to worker1
+  JkMount /*.jsp worker1
+  # send all requests ending /servlet to worker1
+  JkMount /*/servlet/ worker1
+  # send all requests jsp requests to files located in /otherworker will go worker2
+  JkMount /otherworker/*.jsp worker2
+</source>
+
+<p>
+You can use the JkMount directive at the top level or inside &lt;VirtualHost&gt;
+sections of your httpd.conf file.
+</p>
+<p><b>JkUnmount</b> directive acts as an opposite to JkMount and blocks access
+to a particular URL. The purpose is to be able to filter out the particular content
+types from mounted context. The following example mounts /servlet/*
+context, but all .gif files that belongs to that context are not served.
+</p>
+<source>
+  # send all requests ending with /servlet to worker1
+  JkMount /servlet/* worker1
+  # do not send requests ending with .gif to worker1
+  JkUnMount /servlet/*.gif worker1
+</source>
+<p>
+JkUnMount takes precedence over JkMount directives, meaning that the JK
+will first look for unmount and then for mount directives. The following
+example will block all .gif files.
+</p>
+<source>
+  # do not send requests ending with .gif to worker1
+  JkUnMount /*.gif worker1
+  # The .gif files will not be mounted cause JkUnMount takes
+  # precedence over JkMount directive
+  JkMount /servlet/*.gif worker1
+</source>
+
+<p>
+<b>JkAutoAlias</b> directive automatically <b>Alias</b> webapp context directories into
+the Apache document space. It enables Apache to serve a static context while Tomcat
+serving dynamic context. This directive is used for convenience so that you don't
+have to put an apache Alias directive for each application directory inside Tomcat's
+webapp directory.
+</p>
+
+<source>
+  # enter the full path to the tomcat webapps directory
+  JkAutoAlias /opt/tomtact/webapps
+</source>
+<p>The following example shows how to serve a dynamic context by
+Tomcat and static using Apache. The webapps directory has to
+be accessible by apache.</p>
+
+<source>
+  # enter the full path to the tomcat webapps directory
+  JkAutoAlias /opt/tomtact/webapps
+
+  # Mount 'servlets-examples' directory. It's physical location
+  # is assumed to be in the /opt/tomtact/webapps/servlets-examples
+  # ajp13w is a worker defined in the workers.properties
+  JkMount /servlets-examples/* ajp13w
+
+  # Unmount desired static content from servlets-examples webapp.
+  # This content will be served by the httpd directly.
+  JkUnMount /servlets-examples/*.gif ajp13w
+  JkUnMount /servlets-examples/*.jpg ajp13w
+</source>
+<p>Note that you can have a single JkAutoAlias directive per virtual
+host inside your httpd.conf
+</p>
+<p>
+<b>JkWorkerProperty</b> is a new directive available from JK 1.2.7
+version. It is a convenient method for setting directives that are
+usually set inside <b>workers.propeties</b>file. The parameter for
+that directive is raw line from workers.properties file.
+</p>
+<source>
+  # Just like workers.properties but exact line is prefixed
+  # with JkWorkerProperty
+
+  # Minimal jk configuration
+  JkWorkerProperty worker.list=ajp13w
+  JkWorkerProperty worker.ajp13w.type=ajp13
+  JkWorkerProperty worker.ajp13w.host=localhost
+  JkWorkerProperty worker.ajp13w.port=8009   
+</source>
+<p>
+<b>JkMountFile</b> is a new directive available from JK 1.2.9
+version. It is used for dynamic updates of mount points at runtime.
+When the mount file is changed, JK will reload it's content.
+</p>
+<source>
+  # Load mount points
+
+  JkMountFile conf/uriworkermap.properties
+</source>
+<p>If mount point uri starts with minus '-' char the mount point
+will be disabled.
+</p>
+<source>
+  # Sample uriworkermap.properties file
+
+  /servlets-examples/*=ajp13w
+  # Do not map .jpeg files
+  !/servlets-examples/*.jpeg=ajp13w
+  # Make jsp examples initially disabled  
+  -/jsp-examples/*=ajp13w
+</source>
+<p>At run time you can change the content of this file. For example
+removing minus char will enable the uri mapping. You can add any
+number of new entries at runtime that reflects the newly deployed
+applications. Apache will reload the file and update the mount
+points within 60 second interval.
+</p>
+
+</subsection>
+ </section>
+</body>
+</document>

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/config/iis.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/config/iis.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/config/iis.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,154 @@
+<?xml version="1.0"?>
+<!DOCTYPE document [
+  <!ENTITY project SYSTEM "project.xml">
+]>
+<document url="iis.html">
+
+    &project; 
+
+    <properties>
+        <author email="mturk at apache.org">Mladen Turk</author>
+        <title>Configuring IIS</title>
+    </properties>
+
+<body>
+
+<section name="Requirements">
+<p>
+The Tomcat redirector requires three entities:
+
+<ul>
+<li>
+<b>isapi_redirect.dll</b> - The IIS server plugin, either obtain a pre-built DLL or build it yourself (see the build section).
+</li>
+<li>
+<b>workers.properties</b> - A file that describes the host(s) and port(s) used by the workers (Tomcat processes). 
+A sample workers.properties can be found under the conf directory.
+</li>
+<li>
+<b>uriworkermap.properties</b> - A file that maps URL-Path patterns to workers. 
+A sample uriworkermap.properties can be found under the conf directory as well.
+</li>
+</ul>
+</p>
+
+<p>
+The installation includes the following parts:
+
+<ul>
+<li>
+Configuring the ISAPI redirector with a default /examples context and checking that you can serve servlets with IIS.
+</li>
+<li>
+Adding more contexts to the configuration.
+</li>
+</ul>
+</p>
+</section>
+<section name="Registry settings">
+<p>
+ISAPI redirector reads configuration from the registry, create a new registry key named :
+</p>
+<p>
+<b>"HKEY_LOCAL_MACHINE\SOFTWARE\Apache Software Foundation\Jakarta Isapi Redirector\1.0"</b>
+</p>
+<attributes name="Key Name">
+<attribute name="extension_uri" required="true"><p>
+A string value pointing to the ISAPI extension <b>/jakarta/isapi_redirect.dll</b>
+</p></attribute>
+<attribute name="log_file" required="false"><p>
+A value pointing to location where log file will be created.
+(for example <b>c:\tomcat\logs\isapi.log</b>)
+</p></attribute>
+<attribute name="log_level" required="false"><p>
+A string value for log level 
+(can be debug, info, warn, error or trace).
+</p></attribute>
+<attribute name="worker_file" required="true"><p>
+A string value with the full path to workers.properties file
+(for example <b>c:\tomcat\conf\workers.properties</b>)
+</p></attribute>
+<attribute name="worker_mount_file" required="true"><p>
+A string value with is the full path to uriworkermap.properties file
+(for example <b>c:\tomcat\conf\uriworkermap.properties</b>)
+</p></attribute>
+<attribute name="rewrite_rule_file" required="true"><p>
+A string value with is the full path to rewrite.properties file
+(for example <b>c:\tomcat\conf\rewrite.properties</b>)
+</p></attribute>
+
+</attributes>
+</section> 
+<section name="Using a properties file for configuration">
+<p>
+The ISAPI redirector can read it's configuration from a properties file instead of the registry. 
+This has the advantage that you can use multiple ISAPI redirectors with independant configurations on the same server.
+The redirector will check for the properties file during initialisation, and use it in preference to the registry if present.
+</p>
+<p>
+Create a properties file in the same directory as the ISAPI redirector called <b>isapi_redirect.properties</b> i.e. with the same name as the ISAPI redirector DLL but with a <em>.properties</em> extension. A sample isapi_redirect.properties can be found under the conf directory.
+</p>
+<p>
+The property names and values in the properties file are the same as for the registry settings described above. For example:
+</p>
+<p>
+<source>
+# Configuration file for the Jakarta ISAPI Redirector
+
+# The path to the ISAPI Redirector Extension, relative to the website
+# This must be in a virtual directory with execute privileges
+extension_uri=/jakarta/isapi_redirect.dll
+
+# Full path to the log file for the ISAPI Redirector
+log_file=c:\tomcat\logs\isapi_redirect.log
+
+# Log level (debug, info, warn, error or trace)
+log_level=info
+
+# Full path to the workers.properties file
+worker_file=c:\tomcat\conf\workers.properties
+
+# Full path to the uriworkermap.properties file
+worker_mount_file=c:\tomcat\conf\uriworkermap.properties
+</source>
+</p>
+<p>
+    Notes: 
+    <ul>
+        <li>
+            Back-slashes - '\' - are not escape characters.
+        </li>
+        <li>
+            Comment lines begin with '#'.
+        </li>
+    </ul>
+</p>
+</section>
+
+<section name="Using a simple rewrite rules">
+<p>
+The ISAPI redirector with version 1.2.16 can do a simple URL rewriting. Althought not
+as powerfull as Apache Httpd's mod_rewrite, it allows a simple exchange of request uris
+</p>
+<p>
+The rule is in the form rewritten=real-url.
+</p>
+<p>
+The rules must be simple strings. For example:
+</p>
+<p>
+<source>
+# Simple rewrite rules
+
+/jsp/=/jsp-examples/
+/servlets/=/servlets-examples/
+
+</source>
+</p>
+<p>
+Note that the uriworkermap or mount point must point to that new rule.
+</p>
+</section>
+
+</body>
+</document>

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/config/project.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/config/project.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/config/project.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<project name="Application Developer's Guide"
+        href="http://tomcat.apache.org/">
+
+    <title>Tomcat Connector</title>
+
+    <logo href="/images/tomcat.gif">
+    Tomcat Connector
+    </logo>    
+<body>
+
+    <menu name="Links">
+        <item name="Docs Home"                  href="../index.html"/>
+    </menu>
+    <menu name="Configuration">
+        <item name="Workers.properties"    href="workers.html"/>
+        <item name="Apache"                href="apache.html"/>
+        <item name="IIS"                   href="iis.html"/>
+    </menu>
+    
+</body>
+</project>

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/config/workers.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/config/workers.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/config/workers.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,606 @@
+<?xml version="1.0"?>
+<!DOCTYPE document [
+  <!ENTITY project SYSTEM "project.xml">
+]>
+<document url="workers.html">
+
+    &project;
+
+    <properties>
+        <author email="mturk at apache.org">Mladen Turk</author>
+        <title>workers.properties configuration</title>
+    </properties>
+
+<body>
+
+<section name="Introduction">
+<br/>
+<p>
+A <b>Tomcat worker</b> is a Tomcat instance that is waiting to execute servlets or any other content
+on behalf of some web server. For example, we can have a web server such as
+Apache forwarding servlet requests to a Tomcat process (the worker) running behind it.
+</p>
+<p>
+The scenario described above is a very simple one;
+in fact one can configure multiple Tomcat workers to serve servlets on
+behalf of a certain web server.
+The reasons for such configuration can be:
+</p>
+<ul>
+<li>
+We want different contexts to be served by different Tomcat workers to provide a
+development environment where all the developers share the same web server but
+own a Tomcat worker of their own.
+</li>
+<li>
+We want different virtual hosts served by different Tomcat processes to provide a
+clear separation between sites belonging to different companies.
+</li>
+<li>
+We want to provide load balancing, meaning run multiple Tomcat workers each on a
+machine of its own and distribute the requests between them.
+</li>
+</ul>
+
+<p>
+There are probably more reasons for having multiple workers but I guess that this list is enough...
+Tomcat workers are defined in a properties file dubbed <b>workers.properties</b> and this tutorial
+explains how to work with it.
+</p>
+</section>
+
+<section name="Directives">
+<br/>
+<p>Each workers.properties directive consists of three words separated by dot. The first word is always
+<b>worker</b>. The second word is the worker name that can be any name. The worker name reflects the
+name of the <b>jvmRoute</b> defined in Tomcat's server.xml configuration file.
+</p>
+<p>
+<warn>
+The name of the worker can contain only the alphanumeric characters <b>[a-z][A-Z][0-9][_\-]</b> and is case sensitive.
+</warn>
+</p>
+
+<subsection name="Defining workers">
+<br/>
+<p>The generic workers.properties directive is in the form:</p>
+<p><strong>worker.&lt;worker name&gt;.&lt;directive&gt;=&lt;value&gt;</strong></p>
+<p>Defining workers to the Tomcat web server plugin can be done using a properties file
+(a sample file named workers.properties is available in the conf/ directory).
+</p>
+<directives>
+<directive name="worker.list" default="ajp13" required="true">
+A comma separated list of workers names that the JK will use. When starting up,
+the web server plugin will instantiate the workers whose name appears in the
+worker.list property, these are also the workers to whom you can map requests.
+<p>
+This directive can be used multiple times.
+</p>
+</directive>
+<directive name="worker.maintain" default="60" required="false">
+Worker connection pool maintain interval in seconds. If set to the positive
+value JK will scan all connections for all workers specified in worker.list
+directive and check if connections needs to be recycled.
+<p>
+Furthermore any load balancer does a global maintenance every worker.maintain
+seconds. During global maintenance load counters are decayed and workers
+in error are checked for recover_time.
+</p>
+<p>
+This feature has been added in <b>jk 1.2.13</b>.
+</p>
+</directive>
+</directives>
+</subsection>
+
+<subsection name="Mandatory directives">
+<br/>
+<p>Mandatory directives are the one that each worker <b>must</b> contain. Without them the worker will
+be unavailable or will misbehave.
+</p>
+<directives>
+<directive name="type" default="ajp13" required="true">
+Type of the worker (can be one of ajp13, ajp14, jni, lb or status). The type of the worker
+defines the directives that can be applied to the worker.
+<p>AJP13 worker is the preferred worker type that JK uses for communication
+between web server and Tomcat. This type of worker uses sockets as communication
+channel. For detailed description of the AJP13 protocol stack browse to
+<a href="../common/ajpv13a.html">AJPv13 protocol specification</a>
+</p>
+</directive>
+</directives>
+</subsection>
+
+<subsection name="Connection directives">
+<p>Connection directives defines the parameters needed to connect and maintain
+the connections pool of persistent connections between JK and remote Tomcat.
+</p>
+<directives>
+
+<directive name="host" default="localhost" required="false">
+Host name or IP address of the backend Tomcat instance. The remote Tomcat must
+support the ajp13 protocol stack. The host name can have a <b>port</b> number
+embedded separated by the colon (':') character.
+</directive>
+
+<directive name="port" default="8009" required="false">
+Port number of the remote Tomcat instance listening for defined protocol requests.
+The default value depends on the worker type. For AJP13 workers the default port is
+<b>8009</b>, while for AJP14 type of worker that value is <b>8011</b>.
+</directive>
+
+<directive name="socket_timeout" default="0" required="false">
+Socket timeout in seconds used for communication channel between JK and remote host.
+If remote host does not respond inside that timeout the JK will generate an error,
+and retry again. If set to value zero (default) the JK will wait for infinite
+on all socket operations.
+</directive>
+
+<directive name="socket_keepalive" default="False" required="false">
+This directive should be used when you have a firewall between your webserver
+and the Tomcat engine, who tend to drop inactive connections. This flag will told Operating System
+to send <code>KEEP_ALIVE</code> message on inactive connections (interval depend on global OS settings,
+generally 120 minutes), and thus prevent the firewall to cut the connection.
+To enable keepalive set this property value to the <b>True</b>.
+<p>
+The problem with Firewall cutting inactive connections is that sometimes, neither webserver or tomcat
+have information about the cut and couldn't handle it.
+</p>
+</directive>
+
+<directive name="retries" default="3" required="false">
+The number of retries that the worker will try in case of error returned from remote
+Tomcat. If the number of retries set is greater then three (the default value), on
+each retry after default an extra wait of 100ms will be inserted.
+</directive>
+
+<directive name="connection_pool_size" default="1" required="false">
+This defines the number of connections made to the AJP backend that
+are maintained as a connection pool.
+It will limit the number of those connection that each web server child
+process can made.
+<p>
+Connection pool size property is used only for multi threaded
+web servers such as Apache 2.0 (worker), IIS and Netscape. The connection_pool_size property
+should reflect the number of threads per child process. JK will discover
+the number of threads per child process on Apache 2 web server with worker-mpm and set
+its default value to match the ThreadsPerChild Apache directive. For IIS the default
+value is 10. For other web servers this value has to be set manually.
+</p>
+<warn>Do not use connection_pool_size with values higher then 1 on <b>Apache 2.x prefork</b> or <b>Apache 1.3.x</b>!</warn>
+</directive>
+
+<directive name="connection_pool_minsize" default="pool/2" required="false">
+Minimum size of the connection pool that will be maintained.
+<p>
+This property is used only when the <b>connection_pool_size</b> is specified.
+Its default value is connection_pool_size/2.
+</p>
+<warn>Do not use connection_pool_size with values higher then 1 on <b>Apache 2.x prefork</b> or <b>Apache 1.3.x</b>!</warn>
+<p>
+This feature has been added in <b>jk 1.2.16</b>.
+</p>
+</directive>
+
+<directive name="connection_pool_timeout" default="0" required="false">
+Cache timeout property should be used with <b>connection_pool_size</b> to specify how long JK should keep
+an inactive socket in cache before closing it. This property should be used to reduce the number of threads
+on the Tomcat WebServer.
+<p>
+Each child could open an ajp13 connection if it have to forward a request to Tomcat, creating
+a new ajp13 thread on Tomcat side.
+</p>
+<p>
+The problem is that after an ajp13 connection is created, the child won't drop it
+until killed. And since the webserver will keep its childs/threads running
+to handle high-load, even it the child/thread handle only static contents, you could
+finish having many unused ajp13 threads on the Tomcat side.
+</p>
+</directive>
+
+<directive name="lbfactor" default="1" required="false">
+Integer number used when the worker will be used inside load balancer worker,
+this is the load-balancing factor for the worker.
+The load-balancing factor is <i>how much we expect this worker to work</i>, or
+<i>the worker's work quota</i>. Load balancing factor is compared with other workers
+that makes the load balancer. For example if one worker has lb_factor 5 times higher then
+other worker, then it will receive five times more requests.
+</directive>
+
+</directives>
+
+</subsection>
+
+<subsection name="Load balancing directives">
+<br/>
+<p>Load balancer is a virtual worker that does not really communicate with Tomcat workers.
+Instead it is responsible for the management of several "real" workers.
+The worker is supposed to be a load balancer if it's worker type is <b>lb</b>.
+See worker's <b>type</b> directive. The workers that
+are member of load balancer must not appear in the <b>worker.list</b> directive.
+</p>
+<p>Loadbalancer directives defines the parameters needed to create a workers that are
+connecting to a remote cluster of backend Tomcat servers. Each cluster node has to
+have a worker defined.
+</p>
+<p>
+Load balancer management includes:
+</p>
+
+<ul>
+<li>
+Instantiating the workers in the web server.
+</li>
+<li>
+Using the worker's load-balancing factor, perform weighed-round-robin load balancing where
+high lbfactor means stronger machine (that is going to handle more requests)
+</li>
+<li>
+Keeping requests belonging to the same session executing on the same Tomcat worker.
+</li>
+<li>
+Identifying failed Tomcat workers, suspending requests to them and instead fall-backing on
+other workers managed by the lb worker.
+</li>
+</ul>
+
+<p>
+The overall result is that workers managed by the same lb worker are load-balanced
+(based on their lbfactor and current user session) and also fall-backed so a single
+Tomcat process death will not "kill" the entire site.
+The following table specifies properties that the lb worker can accept:
+</p>
+
+<directives>
+<directive name="balance_workers" default="" required="true">
+A comma separated list of workers that the load balancer
+need to manage.
+<p>
+This directive can be used multiple times for the same load balancer.
+</p>
+<p>
+This directive replaces old <b>balanced_workers</b> directive and
+can be used only with mod_jk versions 1.2.7 and up.
+</p>
+<warn>These workers should <b>not</b> appear in the worker.list property!</warn>
+</directive>
+
+<directive name="sticky_session" default="True" required="false">
+Specifies whether requests with SESSION ID's should be routed back to the same
+Tomcat worker. If sticky_session is set to <b>True</b> or <b>1</b> sessions are sticky, otherwise
+sticky_session is set to <b>False</b>. Set sticky_session to <b>False</b> when Tomcat
+is using a Session Manager which can persist session data across multiple
+instances of Tomcat. By default sticky_session is set to True.
+</directive>
+
+<directive name="sticky_session_force" default="False" required="false">
+Specifies whether requests with SESSION ID's for workers that are in error state
+should be rejected. If sticky_session_force is set to <b>True</b> or <b>1</b>
+and the worker that matches that SESSION ID is in error state, client will
+recieve 500 (Server Error). If set to <b>False</b> or <b>0</b> failover on
+another worker will be issued with loosing client session. This directive is
+used only when you set <b>sticky_session=True</b>.
+<p>
+This feature has been added in <b>jk 1.2.9</b>.
+</p>
+</directive>
+
+<directive name="method" default="Request" required="false">
+Specifies what method load balancer is using for electing best worker.
+If method is set to <b>R[equest]</b> balancer will use number of requests
+to find the best worker. If set to <b>T[raffic]</b> balancer will use
+the network traffic between JK and Tomcat to find the best worker.
+If set to <b>B[usyness]</b> balancer will
+pick the worker with the lowest current load, based on how many requests the
+worker is currently serving. This number is divided by the workers lbfactor,
+and the lowest value (least busy) worker is picked.
+<p>
+This feature has been added in <b>jk 1.2.9</b>.
+</p>
+</directive>
+
+<directive name="lock" default="Optimistic" required="false">
+Specifies what lock method the load balancer will use for synchronizing
+shared memory runtime data.
+If lock is set to <b>O[ptimistic]</b> balancer will not use shared memory lock
+to find the best worker. If set to <b>P[essimistic]</b> balancer will use
+shared memory lock. The balancer will work more accurately in case of
+Pessimistic locking, but can slow down the average response time.
+<p>
+This feature has been added in <b>jk 1.2.13</b>.
+</p>
+</directive>
+
+<directive name="secret" default="" required="false">
+Set a default secret word for all defined workers.
+See worker secret attribute description for more info.
+<p>
+This feature has been added in <b>jk 1.2.12</b>.
+</p>
+</directive>
+
+</directives>
+
+</subsection>
+
+<subsection name="Status Worker directives">
+<br />
+<p>
+The status worker does not communicate with Tomcat.
+Instead it is responsible for the load balancer management.
+</p>
+<directives>
+<directive name="css" default="" required="false">
+Specifies the url for cascading stylesheet to use.
+</directive>
+</directives>
+</subsection>
+
+<subsection name="Advanced worker directives">
+<br />
+<directives>
+<directive name="connect_timeout" default="0" required="false">
+Connect timeout property told webserver to send a PING request on ajp13 connection after
+connection is established. The parameter is the delay in milliseconds to wait for the PONG reply.
+<p>
+This features has been added in <b>jk 1.2.6</b> to avoid problem with hung tomcat's and require ajp13
+ping/pong support which has been implemented on Tomcat <b>3.3.2+, 4.1.28+ and 5.0.13+</b>.
+Disabled by default.
+</p>
+</directive>
+
+<directive name="prepost_timeout" default="0" required="false">
+Prepost timeout property told webserver to send a PING request on ajp13 connection before
+forwarding to it a request. The parameter is the delay in milliseconds to wait for the PONG reply.
+<p>
+This features has been added in <b>jk 1.2.6</b> to avoid problem with hung tomcat's and require ajp13
+ping/pong support which has been implemented on <b>Tomcat 3.3.2+, 4.1.28+ and 5.0.13+</b>.
+Disabled by default.
+</p>
+</directive>
+
+<directive name="reply_timeout" default="0" required="false">
+Reply_timeout property told webserver to wait some time for reply to a forwarded request
+before considering the remote tomcat is dead and eventually switch to another tomcat in a cluster
+group. By default webserver will wait forever which could be an issue for you.
+The parameter is the number of milliseconds to wait for reply, so adjust it carefully if you
+have long running servlets.
+<p>
+This features has been added in <b>jk 1.2.6</b> to avoid problem with hung tomcat's and works on all
+servlet engines supporting ajp13.
+Disabled by default.
+</p>
+</directive>
+
+<directive name="recover_time" default="60" required="false">
+The recover time is the time in seconds the load balancer will not try
+to use a worker, after it went into error state. Only after this time has passed,
+a worker in error state will be marked as in recovering, so that it will be
+tried for new requests.
+<p>
+This interval is not checked every time a request is being processed.
+Instead it is being checked during global maintenance. The time between two
+runs of global maintenance is controlled by worker.maintain.
+</p>
+<p>
+Do not set recover_time to a very short time unless you understand the implications.
+Every recovery attempt for a worker in error is done by a real request!
+</p>
+</directive>
+
+<directive name="recovery_options" default="0" required="false">
+Recovery options property told webserver how to handle recovery when
+it detect that tomcat failed.
+By default, webserver will forward the request to another tomcat in LB mode
+(or to another ajp thread in ajp13 mode).
+values are : 0 (full recovery), 1 (don't recover if tomcat failed after getting the request),
+2 (don't recover if tomcat failed after sending the headers to client), 3 (don't recover if tomcat failed
+getting the request or after sending the headers to client).
+<p>
+This features has been added in <b>jk 1.2.6</b> to avoid problem with hung/broken tomcat's
+and works on all servlet engines supporting ajp13.
+Full recovery by default.
+</p>
+<p>If the value 4 is added to the recovery options, the connection
+between the webserver and tomcat will be closed if the client connection
+to the webserver is terminated during the request/response cycle. This allows
+to inform the servlet engine about broken client connections during lengthy operations.
+This feature has been added in <b>jk 1.2.16</b>
+</p>
+</directive>
+
+<directive name="distance" default="0" required="false">
+Express preferences between the balanced workers of an lb worker.
+A load balancer will never choose some balanced worker 
+in case there is another usable worker with lower distance.
+<p>
+Only in case all workers below a given distance are in error, disabled or stopped,
+workers of a larger distance are eligible for balancing.
+</p>
+<p>
+This feature has been added in <b>jk 1.2.16</b>.
+</p>
+</directive>
+
+<directive name="domain" default="" required="false">
+Domain directive can be used only when the worker is a member of the load balancer.
+Workers that share the same domain name are treated as single worker. If sticky_session
+is used, then the domain name is used as session route.
+<p>This directive is used for large system with more then 6 Tomcats, to be able
+to cluster the Tomcats in two groups and thus lowering the session replication
+transfer between them.
+</p>
+<p>
+This feature has been added in <b>jk 1.2.8</b>.
+</p>
+</directive>
+
+<directive name="redirect" default="" required="false">
+Set to the preferred failover worker. If worker matching SESSION ID is in
+error state then the redirect worker will be used instead. It will be used
+even if being disabled, thus offering hot standby.
+<p>
+This feature has been added in <b>jk 1.2.9</b>.
+</p>
+</directive>
+
+<directive name="activation" default="Active" required="false">
+Using this directive, a balanced worker of a load balancer
+can be configured as disabled or stopped. A disabled worker only gets
+requests, which belong to sessions for that worker. A stopped
+worker does not get any requests. Users will loose their sessions,
+unless session replication via clustering is used.
+<p>
+Use <b>d</b> or <b>D</b> to disable and <b>s</b> or <b>S</b> to stop.
+If this directive is not present the deprecated directives
+"disabled" or "stopped" are used.
+</p>
+<p>
+This flag can be changed at runtime using status worker.
+</p>
+<p>
+This feature has been added in <b>jk 1.2.19</b>.
+</p>
+</directive>
+
+<directive name="jvm_route" default="" required="false">
+Normally the name of a balanced worker in a load balancer is equal to the jvmRoute
+of the corresponding Tomcat instance. If you want to include a worker corresponding
+to a Tomcat instance into several load balancers with different balancing configuration
+(e.g. disabled, stopped) you can use this attribute.
+<p>
+Define a seperate worker per lb and per Tomcat instance with an arbitrary worker name and 
+set the jvm_route attribute of the worker equal to the jvmRoute of the target Tomcat instance.
+</p>
+<p>
+If this attribute is left empty, the name of the worker will be used.
+</p>
+<p>
+This attribute can be changed at runtime using status worker.
+</p>
+<p>
+This feature has been added in <b>jk 1.2.16</b>.
+</p>
+</directive>
+
+<directive name="reference" default="" required="false">
+This directive allows to copy configurations between workers
+in a hierarchical way. If worker castor sets <b>worker.castor.reference=worker.pollux</b>
+then it inherits all properties of <b>pollux</b>, except for the ones that
+are explicitely set for <b>castor</b>.
+<p>
+Please note, that the value of the directive is not only the name of the referred worker,
+but the complete prefix including "worker.".
+</p>
+<p>
+This directive is especially useful, if one has a lot of balanced workers in a load balancer
+and these workers share most of their properties. You can set all of these properties
+in a phantom worker, e.g. using the prefix "worker.template1", and then simply
+reference those common properties in all balanced workers.
+</p>
+<p>
+This feature has been added in <b>jk 1.2.19</b>.
+</p>
+</directive>
+
+<directive name="secret" default="" required="false">
+If set to AJP Connector secret keyword, only request with this keyword are successfull responding.
+Use <b>request.useSecret="true"</b> and <b>request.secret="secret key word"</b> at your tomcat ajp
+Connector configuration.
+</directive>
+
+<directive name="mount" default="" required="false">
+Space delimited list of uri maps the worker should handle.
+<p>
+This directive can be used multiple times for the same worker.
+</p>
+</directive>
+
+</directives>
+</subsection>
+
+<subsection name="Deprecated worker directives">
+<br/>
+<p>The following directives have been deprecated in the past. We include their documentation
+in case you need to use an older version of mod_jk. We urge you to update and not use
+them any more. Please migrate your existing configurations.
+</p>
+<deprecations>
+<directive name="cachesize" successor="connection_pool_size" default="1" required="false">
+<warn>This directive has been deprecated since 1.2.16.</warn>
+Cachesize defines the number of connections made to the AJP backend that
+are maintained as a connection pool.
+It will limit the number of those connection that each web server child
+process can make.
+<p>
+Cachesize property is used only for multi threaded 
+web servers such as Apache 2.0 (worker), IIS and Netscape. The cachesize property
+should reflect the number of threads per child process. JK will discover
+the number of threads per child process on Apache 2 web server with worker-mpm and set
+its default value to match the ThreadsPerChild Apache directive. For IIS the default
+value is 10. For other web servers this value has to be set manually.
+</p>
+<warn>Do not use cachesize with values higher then 1 on <b>Apache 2.x prefork</b> or <b>Apache 1.3.x</b>!</warn>
+</directive>
+
+<directive name="cache_timeout" successor="connection_pool_timeout" default="0" required="false">
+<warn>This directive has been deprecated since 1.2.16.</warn>
+Cache timeout property should be used with <b>cachesize</b> to specify how to time JK should keep
+an open socket in cache before closing it. This property should be used to reduce the number of threads 
+on the Tomcat WebServer.
+<p> 
+Each child could open an ajp13 connection if it have to forward a request to Tomcat, creating
+a new ajp13 thread on Tomcat side.
+</p>
+<p>
+The problem is that after an ajp13 connection is created, the child won't drop it
+until killed. And since the webserver will keep its childs/threads running
+to handle high-load, even it the child/thread handle only static contents, you could
+finish having many unused ajp13 threads on the Tomcat side.
+</p>
+</directive>
+
+<directive name="recycle_timeout" successor="connection_pool_timeout" default="0" required="false">
+<warn>This directive has been deprecated since 1.2.16.</warn>
+The number of seconds that told webserver to cut an ajp13 connection after some time of 
+inactivity. When choosing an endpoint for a request and the assigned socket is open, it will be
+closed if it was not used for the configured time.
+It's a good way to ensure that there won't too old threads living on Tomcat side, 
+with the extra cost you need to reopen the socket next time a request be forwarded.
+This property is very similar to <b>cache_timeout</b> but works also in non-cache mode.
+If set to value zero (default) no recycle will took place. 
+</directive>
+
+<directive name="balanced_workers" successor="balance_workers" default="" required="true">
+<warn>This directive has been deprecated since 1.2.7.</warn>
+A comma separated list of workers that the load balancer
+need to manage.
+</directive>
+
+<directive name="disabled" successor="activation" default="False" required="false">
+<warn>This directive has been deprecated since 1.2.19.</warn>
+If set to <b>True</b> or <b>1</b> the worker will be disabled if member
+of load balancer. This flag can be changed at runtime using status worker.
+<p>
+This feature has been added in <b>jk 1.2.9</b>.
+</p>
+</directive>
+
+<directive name="stopped" successor="activation" default="False" required="false">
+<warn>This directive has been deprecated since 1.2.19.</warn>
+If set to <b>True</b> or <b>1</b> the worker will be stopped if member
+of load balancer. The flag is needed for stop complete traffic of a sticky session
+worker. It is only usefull, when you have a cluster that replicated the sessions.
+This flag can be changed at runtime using status worker.
+<p>
+This feature has been added in <b>jk 1.2.11</b>.
+</p>
+</directive>
+
+</deprecations>
+</subsection>
+
+</section>
+
+</body>
+</document>

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/empty.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/empty.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/empty.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,39 @@
+<?xml version="1.0"?>
+<!DOCTYPE document [
+  <!ENTITY project SYSTEM "project.xml">
+]>
+<document url="empty.html">
+  &project;
+<copyright>
+   Copyright 1999-2006 The Apache Software Foundation
+ 
+   Licensed 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.
+</copyright>
+<properties>
+
+<title>Empty template</title>
+<author email="developer at apache.org">Developer Name</author>
+
+<date>$Date: 2006-05-31 04:10:09 -0500 (Wed, 31 May 2006) $</date>
+</properties>
+<body>
+
+<section name="Generic">
+<p>
+This is a generic template for JK documentation. Please fill in the <b>url</b> and <b>title</b>
+tags, as well as <b>author</b> tags.
+</p>
+</section>
+
+</body>
+</document>

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/faq.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/faq.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/faq.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,338 @@
+<?xml version="1.0"?>
+<!DOCTYPE document [
+  <!ENTITY project SYSTEM "project.xml">
+]>
+<document url="faq.html">
+
+  &project;
+<copyright>
+   Copyright 1999-2004 The Apache Software Foundation
+ 
+   Licensed 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.
+</copyright>
+<properties>
+<title>FAQ</title>
+<author email="hgomez at apache.org">Henri Gomez</author>
+<date>$Date: 2006-06-28 18:56:49 -0500 (Wed, 28 Jun 2006) $</date>
+</properties>
+<body>
+<section name="General">
+<p>
+General Informations and FAQ about JK
+</p>
+<subsection name="Where can I get help/support for JK ?">
+<p>
+The primary mechanism for support is through the JK 
+documentation included in the doc directory.
+Documentation is also available on the Apache Tomcat web site devoted to the
+<a href="http://tomcat.apache.org/connectors-doc/">
+Apache Tomcat Connectors Project</a>
+For additional help, the best resource is the Tomcat Users Discussion list.  
+You should start by searching
+<a href="http://mail-archives.apache.org/mod_mbox/tomcat-users/">
+the mail list archive</a>
+before you post questions to the list.  
+If you are unable to locate the answer to your question in the archive, 
+you can post questions about JK to the user list for assistance.  
+Make sure that you include the version of your Webserver, 
+that you are using as well as the platform you are running on
+and go 
+<a href="http://tomcat.apache.org/lists.html">
+here</a>
+to determine how to subscribe to tomcat mailing list.
+</p>
+</subsection>
+
+<subsection name="I can't find JK anywhere. Where is it?">
+<p>
+Now that JK moved to the <b>tomcat-connectors</b> repository, 
+the source and the binaries for JK can be downloaded from a mirror at the
+<a href="http://tomcat.apache.org/download-connectors.cgi">
+Tomcat Connectors (mod_jk, mod_jk2) Downloads</a> page.
+</p>
+</subsection>
+
+<subsection name="What's the difference between JK and mod_jk ?">
+<br />
+<p>
+<b>JK</b> is a project covering web-servers to Tomcat connectors,
+whereas <b>mod_jk</b> is the <a href="howto/apache.html">Apache module</a> developed in JK.
+</p>
+
+<p>
+<a href="howto/domino.html">Domino webserver</a> support is implemented on JK, using a redirector
+called <b>dsapi redirector</b>.
+</p>
+
+<p>
+<a href="howto/iis.html">IIS webserver</a>support is implemented on JK, using a redirector
+called <b>isapi redirector</b>.
+</p>
+
+<p>
+<a href="howto/nes.html">Netscape/iPlanet webserver</a>webserver support is implemented on JK, using a redirector
+called <b>nsapi redirector</b>.
+</p>
+
+</subsection>
+
+<subsection name="Where can I get more information ?">
+<p>
+For <b>JK 1.2.x</b>, you should read :
+</p>
+
+<ul>
+
+<li>
+<a href="howto/quick.html">For the impatients</a>
+</li>
+
+<li>
+<a href="howto/apache.html">Apache and JK</a>
+</li>
+
+<li>
+<a href="howto/domino.html">Domino and JK</a>
+</li>
+
+<li>
+<a href="howto/iis.html">IIS and JK</a>
+</li>
+
+<li>
+<a href="howto/nes.html">Netscape/iPlanet and JK</a>
+</li>
+
+<li>
+<a href="howto/workers.html">Workers configuration</a>
+</li>
+</ul>
+
+<p> 
+You could also try searching the mailing list archives for "JK" or look at the source.
+</p>
+</subsection>
+
+<subsection name="Which protocol should I use? Ajp12 or Ajp13?">
+<p>
+<a href="common/ajpv13a.html">Ajp13</a> is a newer protocol, it's faster, and it works better with SSL. 
+You almost certainly want to use it now that <strong>ajp12 is deprecated</strong>.
+</p>
+<p> 
+Also ajp13 is supported by all Apache Tomcat including 3.2.x , 3.3.x, 4.0.x, 4.1.x and the new tomcat 5. 
+</p>
+
+<p>
+Others Servlet engines like <b>jetty</b> have support for Ajp13.
+</p>
+</subsection>
+
+<subsection name="I've got a firewall between my WebServer and Tomcat who drop ajp13 connections after some times">
+<p>
+Ajp13 use persistant connections where the traffic could be null if there is no request to be sent to Tomcat. 
+Firewall used to drop inactive connections and will make your WebServer and Tomcat think the connection is valid. 
+</p>
+<p>
+Starting with JK 1.2.0, a <b>socket_keepalive</b> property as been added to ajp13 settings, and you should take a look at 
+it in <a href="howto/workers.html">Workers HowTo</a>.
+</p>
+</subsection>
+
+<subsection name="Under heavy load, I've got many threads in Tomcat even if my Apache Web Server handle much of the load">
+<p>
+Under heavy load, Apache WebServer create many childs to handle the load, which will in turn create many connections 
+to Tomcat to forward the requests they should handle. 
+Apache WebServer will normally kill the childs/threads when the load decrease. But if the load is still there and 
+even if only Apache handle the requests, ie static contents, the childs are kept and with them the ajp13 connections, 
+even if they are no more used. 
+</p>
+<p>
+Since JK 1.2.0, <b>cache_timeout</b> and <b>recycle_timeout</b> properties as been added to close 
+connections after some time of inactivity, for more informations refer to <a href="howto/workers.html">Workers HowTo</a>.
+</p>
+</subsection>
+
+</section>
+
+<section name="Apache">
+<p>
+Informations and FAQ about mod_jk and Apache Web Servers. 
+</p>
+<subsection name="Whenever I restart Tomcat, Apache locks up!">
+<p>
+The Ajp13 protocol keeps an open socket between Tomcat and Apache. Release of mod_jk present in J-T-C handle the network failure. 
+But with previous release of mod_jk, you may have to restart Apache as well.
+</p>
+</subsection>
+
+<subsection name="Why did exist two files mod_jk.so (-eapi ad -noeapi) in download dir for Linux ?">
+<p>
+Many versions of Apache use of modified API, known at Extended API, developed for use with the
+<a href="http://www.modssl.org">mod_ssl module</a>.
+</p>
+
+<p>
+For example, Apache present in certains recent Linux distributions include the
+<b>mod_ssl</b> module.
+</p>
+
+<p>
+So if you got such 'Extended Apache', you need to use <b>mod_jk.so-eapi</b>.
+</p>
+
+<p> 
+You should use <b>mod_jk.so-noeapi</b> only for 'Standard Apache' (ie without mod_ssl).
+</p>
+
+<p>
+It's wise to avoid using EAPI modules on STD API Apache or to use standard API modules on EAPI Apache. 
+Allways be sure to have the <b>mod_jk.so</b> witch match your version of Apache
+</p>
+</subsection>
+
+<subsection name="What's that message about 'garbled DSO ?'">
+<p>
+It's related to Apache EAPI, the message <code>'mod_jk.so is garbled - perhaps this is not an Apache module DSO ?'</code> 
+just told you, that your're trying to install a mod_jk.so DSO module that was compiled on an Apache using EAPI, 
+like apache-mod_ssl or apache from Redhat distro 6.2/7.0 but your system use the standard apache with normal API.
+</p>
+</subsection>
+
+<subsection name="And the message about 'module might crash under EAPI!">
+<p>
+Also related to EAPI, the message <code>'[warn] Loaded DSO /usr/lib/apache/mod_jk.so uses plain Apache 1.3 API, 
+this module might crash under EAPI! (please recompile it with -DEAPI)'</code>, the mod_jk.so was compiled under normal 
+Apache with standard API and you try to install the module on an Apache using EAPI.
+</p>
+</subsection>
+
+<subsection name="APXS is getting an error during the build of mod_jk, like rc=0 or rc=255.  I tried all of the steps in the build section, what do I do now ?">
+<p>
+APXS is a Perl script that is created when you build the Apache web server from source.  
+Chances are that if you are getting these errors and you obtained Apache as a binary distribution, 
+that APXS is not configured correctly for your system.  
+Your best bet is to get the Apache source from http://httpd.apache.org and build it yourself.  
+Use the following for a basic build (read the Apache docs for other options):
+<screen>
+<type>cd /usr/local/src</type><br/>
+<type>gzip -dc apache_1.3.19.tar.gz|tar xvf -</type><br/>
+<type>cd apache_1.3.19</type><br/>
+<type>./configure --prefix=/usr/local/apache \</type><br/>
+<type>            --enable-module=most \</type><br/>
+<type>            --enable-shared=max</type><br/>
+<type>make</type><br/>
+<type>make install</type><br/>
+</screen>
+</p>
+<p>
+Note: The above steps assume that you downloaded the Apache source and placed it in your /usr/local/src directory.
+</p>
+</subsection>
+
+<subsection name="Apache 2.0 complains about incorrect module version">
+<p>
+Since Apache 2.0 API still change often, the Apache 2.0 teams decide to put in headers of compiled modules the 
+Apache 2.0 version used to compile the module. This check is called Magic Module Number bump.
+</p>
+<p>
+At start time Apache 2.0 check that version in modules headers and stop if it detect that a module was compiled 
+for another Apache 2.0 version. As such you should allways use modules compiled for the same Apache 2.0 version. 
+This check may be removed if the future.
+</p>
+</subsection>
+
+<subsection name="JNI didn't works with Apache 1.3">
+<p>
+JNI support require a multi-threaded environment which is not the general case for Apache 1.3. 
+You should verify if Apache 1.3 has been build with thread support and if not you could add the 
+the pthreads library to your <b>httpd.conf</b> file. 
+</p>
+
+<source>
+  # Add pthread to Apache in httpd.conf
+  LoadModule "/usr/lib/libpthreads.so"
+</source>
+
+<p>
+Also keep in mind that JNI is suited for multi-threaded servers and you should consider upgrading 
+to Apache 2.0 to support JNI.
+</p>
+</subsection>
+
+<subsection name="JNI report that JVM couldn't be started under Linux">
+<p>
+Under Linux, you should set some environment variables BEFORE launching your Apache server :
+</p>
+
+<screen>
+<read>export LD_LIBRARY_PATH=$jre/bin:$jre/bin/classic:$LD_LIBRARY_PATH</read>
+</screen>
+
+<p>
+Also some Linux distributions have enabled a GLIBC feature called 'floating stacks' which may not works with kernel 
+less than 2.4.10 on SMP machines. You should disable floating stacks by exporting an environment variable :
+</p>
+
+<screen>
+<read>export LD_ASSUME_KERNEL=2.2.5</read>
+</screen>
+
+<p>
+You could have to update your service scripts, ie <b>/etc/rc.d/init.d/httpd</b>, to set these env vars 
+before your httpd server starts.
+</p>
+</subsection>
+
+<subsection name="Mixed errors when building via configure">
+<p>
+configure assume you have some GNU tools allready installed and configured for your system, and ad minima <b>libtool</b>.
+</p>
+<p>
+Also some systems may have mixed cc and gcc setup which may make you puzzled when trying to link an Apache built with native
+c compiler with a jk/jk2 build with gcc.
+</p>
+<p>
+In fine some native make didn't works as expect so you should use a GNU make <b>gmake</b>.
+</p>
+</subsection>
+
+<subsection name="JK2 build report error about missing FIONBIO on Solaris 8">
+<p>
+In JK2 before v2.0.2, you should add <source>#define BSD_COMP</source> in top
+of jk/native2/common/jk_channel_socket.c to have Solaris build succeed.
+</p>
+</subsection>
+
+
+</section>
+
+<section name="IIS">
+<p>
+Informations and FAQ about JK and IIS Web Servers. 
+</p>
+<todo>
+More informations to be added.
+</todo>
+</section>
+
+<section name="NES/iPlanet">
+<p>
+Informations and FAQ about JK and NES/iPlanet Web Servers. 
+</p>
+<todo>
+More informations to be added.
+</todo>
+</section>
+
+</body>
+</document>

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/howto/apache.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/howto/apache.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/howto/apache.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,1026 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!DOCTYPE document [
+  <!ENTITY project SYSTEM "project.xml">
+]>
+<document url="apache.html">
+
+  &project;
+<copyright>
+   Copyright 1999-2006 The Apache Software Foundation
+
+   Licensed 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.
+</copyright>
+<properties>
+<title>Apache HowTo</title>
+<author email="hgomez at apache.org">Henri Gomez</author>
+<author email="shachor at il.ibm.com">Gal Shachor</author>
+<date>$Date: 2006-09-04 16:44:41 -0500 (Mon, 04 Sep 2006) $</date>
+</properties>
+<body>
+<section name="Introduction">
+<p>
+This document explains how to connect Tomcat to the popular open source web server, Apache.
+There is actually three versions of Apache, 1.3, 2.0 and 2.2 and all can be used with mod_jk,
+the Tomcat redirector module.
+</p>
+
+<p>
+It is recommanded that you also read the <a href="workers.html">Workers HowTo</a> document
+to learn how to setup the working entities between your WebServer and Tomcat Engines.
+</p>
+
+<p>
+This document was originally part of <b>Tomcat: A Minimalistic User's Guide</b> written by Gal Shachor,
+but has been split off for organizational reasons.
+</p>
+
+<subsection name="Document Conventions and Assumptions">
+<p>
+${tomcat_home} is the root directory of tomcat.
+Your Tomcat installation should have the following subdirectories:
+
+<ul>
+<li>
+${tomcat_home}\conf - Where you can place various configuration files
+</li>
+<li>
+${tomcat_home}\webapps - Containing example applications
+</li>
+<li>
+${tomcat_home}\bin - Where you place web server plugins
+</li>
+</ul>
+</p>
+<p>
+In all the examples in this document ${tomcat_home} will be <b>/var/tomcat3</b>.
+A <a href="workers.html">worker</a> is defined to be a tomcat process that accepts work from the Apache server.
+</p>
+</subsection>
+
+<subsection name="Supported Configuration">
+<p>
+The mod_jk module was developed and tested on:
+<ul>
+<li>
+Linux, FreeBSD, AIX, HP-UX, MacOS X, and should works on major Unixes platforms supporting Apache 1.3 and/or 2.0
+</li>
+<li>
+WinNT4.0-i386 SP4/SP5/SP6a (should be able to work with other service packs), Win2K and WinXP and Win98
+</li>
+<li>
+Cygwin (until you have an apache server and autoconf/automake support tools)
+</li>
+<li>
+Netware
+</li>
+<li>
+iSeries V5R1 and V5R2 with Apache 2.0.39. Be sure to have the latest Apache PTF installed.
+</li>
+<li>
+Tomcat 3.2.x, Tomcat 3.3.x, Tomcat 4.0.x, Tomcat 4.1.x and Tomcat 5
+</li>
+</ul>
+</p>
+
+<p>
+The redirector uses <b>ajp12</b> and <b>ajp13</b> to send requests to the Tomcat containers. There is also an option to use Tomcat in process,
+more about the in-process mode can be found in the in process howto.
+</p>
+</subsection>
+
+<subsection name="Who support ajp protocols ?">
+<p>
+The ajp12 protocol is only available in Tomcat 3.2.x and 3.3.x.
+</p>
+
+<p>
+The <b>ajp12</b> has been <b>deprecated</b> with Tomcat 3.3.x and you should use instead
+<b>ajp13</b> which is the only ajp protocol known by Tomcat 4.0.x, 4.1.x and 5.
+</p>
+
+<p>
+Of course Tomcat 3.2.x and 3.3.x also support ajp13 protocol.
+</p>
+
+<p>
+Others servlet engines such as <b>jetty</b> have support for ajp13 protocol
+</p>
+
+</subsection>
+
+<subsection name="How does it work ?">
+<p>
+In a nutshell a web server is waiting for client HTTP requests.
+When these requests arrive the server does whatever is needed to serve the
+requests by providing the necessary content.
+</p>
+
+<p>
+Adding a servlet container may somewhat change this behavior.
+Now the web server needs also to perform the following:
+</p>
+
+<ul>
+<li>
+Load the servlet container adapter library and initialize it (prior to serving requests).
+</li>
+<li>
+When a request arrives, it needs to check and see if a certain request belongs to a servlet,
+if so it needs to let the adapter take the request and handle it.
+</li>
+</ul>
+
+<p>
+The adapter on the other hand needs to know what requests it is going to serve,
+usually based on some pattern in the request URL, and to where to direct these requests.
+</p>
+
+<p>
+Things are even more complex when the user wants to set a configuration that uses virtual hosts,
+or when they want multiple developers to work on the same web server
+but on different servlet container JVMs.
+We will cover these two cases in the advanced sections.
+</p>
+
+</subsection>
+
+</section>
+
+<section name="Obtaining mod_jk">
+<p>
+mod_jk can be obtained in two formats - binary and source.
+Depending on the platform you are running your web server on, a binary version of mod_jk may be available.
+</p>
+
+<p>
+It is recommended to use the binary version if one is available.
+If the binary is not available, follow the instructions for building mod_jk from source.
+The mod_jk source can be downloaded from a mirror
+<a href="http://tomcat.apache.org/download-connectors.cgi">
+here</a>
+</p>
+
+<p>
+The binaries for mod_jk are now available for several platforms.
+The binaries are located in subdirectories by platform.
+</p>
+
+<p>
+For some platforms, such as Windows, this is the typical way of obtaining mod_jk
+since most Windows systems do not have C compilers.
+</p>
+
+<p>
+For others, the binary distribution of mod_jk offers simpler installation.
+</p>
+
+<p>
+For example JK 1.2.5 can be downloaded from a mirror
+<a href="http://tomcat.apache.org/download-connectors.cgi">
+here</a> (look for JK 1.2 Binary Releases). The "JK 1.2 Binary Releases" link contains binary version for a variety of
+operating systems for both Apache 1.3 and Apache 2.
+</p>
+
+</section>
+
+<section name="Installation">
+<p>
+mod_jk requires two entities:
+
+<ul>
+<li>
+<b>mod_jk.xxx</b> - The Apache module, depending on your operating system, it will be mod_jk.so, mod_jk.nlm or
+or QZTCJK.SRVPGM (see the build section).
+</li>
+<li>
+<b>workers.properties</b> - A file that describes the host(s) and port(s) used by the workers (Tomcat processes).
+A sample workers.properties can be found under the conf directory.
+</li>
+</ul>
+</p>
+
+<p>
+Also as with other Apache modules, mod_jk should be first installed on the modules directory of your
+Apache webserver, ie : /usr/lib/apache and you should update your <b>httpd.conf</b> file.
+</p>
+
+
+<subsection name="Disabling old mod_jserv">
+<p>
+If you've previously configured Apache to use <b>mod_jserv</b>, remove any <b>ApJServMount</b> directives
+from your httpd.conf.
+</p>
+
+<p>If you're including <b>tomcat-apache.conf</b> or <b>tomcat.conf</b>, you'll want to remove them as well -
+they are specific to <b>mod_jserv</b>.
+</p>
+
+<p>
+The mod_jserv configuration directives are not compatible with mod_jk !
+</p>
+</subsection>
+
+<subsection name="Using Tomcat auto-configure">
+<p>
+The auto-configure works only for a single Tomcat running on the same machine where Apache (httpd) is running.
+The simplest way to configure Apache to use mod_jk is to turn on the Apache auto-configure setting
+in Tomcat and put the following include directive at the end of your Apache httpd.conf file
+(make sure you replace $TOMCAT_HOME with the correct path for your Tomcat installation:
+</p>
+
+<source>
+    #To be added at the end of your httpd.conf
+    Include $TOMCAT_HOME/conf/jk/mod_jk.conf-auto
+</source>
+
+<p>
+This will tell Apache to use directives in the <b>mod_jk.conf-auto</b> file in the Apache configuration.
+This file is created by enabling the Apache auto-configuration as follows, in your server.xml file.
+<b>Please note that this example is specific to Tomcat 5.x, unlike other sections of this document
+   which also apply to previous Tomcat branches.</b>
+</p>
+<source>
+  ...
+  &lt;Engine ...&gt;
+    &lt;Listener className="org.apache.jk.config.ApacheConfig" modJk="/path/to/mod_jk.so" /&gt;
+  &lt;/Engine&gt;
+  ...
+</source>
+
+<p>
+Then restart Tomcat and mod_jk.conf should be generated. For more information on
+this topic, please refer to the API documentation at the
+<a href="http://tomcat.apache.org/tomcat-5.5-doc/catalina/docs/api/org/apache/jk/config/ApacheConfig.html">
+Tomcat docs website</a>.
+</p>
+
+</subsection>
+
+<subsection name="Custom mod_jk configuration">
+<p>
+You should use custom configuration when :
+</p>
+<ul>
+<li>
+You couldn't use <b>mod_jk.conf-auto</b> since Tomcat engine isn't on the same machine that your Apache WebServer,
+ie when you have an Apache in front of a Tomcat Farm.
+</li>
+<li>
+Another case for custom configuration is when your Apache is in front of many differents Tomcat engines,
+each one having it's own configuration, a general case in ISP hosting
+</li>
+<li>
+Also all Apache webmaster will retain custom configuration to be able to tune the settings
+to their real needs.
+</li>
+</ul>
+
+</subsection>
+
+<subsection name="Simple configuration example">
+<p>
+Here is a simple configuration:
+</p>
+
+<source>
+    # Load mod_jk module
+    LoadModule    jk_module  libexec/mod_jk.so
+    # Declare the module for &lt;IfModule directive&gt; (remove this line on Apache 2.0.x)
+    AddModule     mod_jk.c
+    # Where to find workers.properties
+    JkWorkersFile /etc/httpd/conf/workers.properties
+    # Where to put jk logs
+    JkLogFile     /var/log/httpd/mod_jk.log
+    # Set the jk log level [debug/error/info]
+    JkLogLevel    info
+    # Select the log format
+    JkLogStampFormat "[%a %b %d %H:%M:%S %Y] "
+    # JkOptions indicate to send SSL KEY SIZE,
+    JkOptions     +ForwardKeySize +ForwardURICompat -ForwardDirectories
+    # JkRequestLogFormat set the request format
+    JkRequestLogFormat     "%w %V %T"
+    # Send servlet for context /examples to worker named worker1
+    JkMount  /examples/servlet/* worker1
+    # Send JSPs  for context /examples to worker named worker1
+    JkMount  /examples/*.jsp worker1
+</source>
+
+</subsection>
+</section>
+
+<section name="mod_jk Directives">
+<p>
+We'll discuss here the mod_jk directives and details behind them
+</p>
+
+<subsection name="Define workers">
+<p>
+<b>JkWorkersFile</b> specify the location where mod_jk will find the workers definitions.
+
+<source>
+  JkWorkersFile     /etc/httpd/conf/workers.properties
+</source>
+
+<br/>
+<br/>
+</p>
+</subsection>
+
+<subsection name="Logging">
+<p>
+<b>JkLogFile</b> specify the location where mod_jk is going to place its log file.
+</p>
+
+<source>
+  JkLogFile     /var/log/httpd/mod_jk.log
+</source>
+
+<p>
+Since JK 1.2.3 for Apache 2.0 and JK 1.2.16 for Apache 1.3 this can also
+be used for piped logging:
+</p>
+
+<source>
+  JkLogFile     "|/usr/bin/rotatelogs /var/log/httpd/mod_jk.log 86400"
+</source>
+
+<p>
+<b>JkLogLevel</b>
+set the log level between :
+</p>
+
+<ul>
+<li>
+<b>info</b> log will contains standard mod_jk activity (default).
+</li>
+<li>
+<b>error</b> log will contains also error reports.
+</li>
+<li>
+<b>debug</b> log will contains all informations on mod_jk activity
+</li>
+</ul>
+
+<source>
+  JkLogLevel    info
+</source>
+
+<p>
+<code>info</code> should be your default selection for normal operations.
+<br/>
+<br/>
+</p>
+
+<p>
+<b>JkLogStampFormat</b> will configure the date/time format found on mod_jk logfile.
+Using the strftime() format string it's set by default to <b>"[%a %b %d %H:%M:%S %Y]"</b>
+</p>
+
+<source>
+  JkLogStampFormat "[%a %b %d %H:%M:%S %Y] "
+</source>
+
+<p>
+<br/>
+<br/>
+</p>
+
+<p>
+<b>JkRequestLogFormat</b> will configure the format of mod_jk individual request logging.
+Request logging is configured and enabled on a per virtual host basis.
+To enable request logging for a virtual host just add a JkRequestLogFormat config.
+The syntax of the format string is similiar to the Apache LogFormat command,
+here is a list of the available request log format options:
+</p>
+
+<p>
+<table>
+  <tr><th>Options</th><th>Description</th></tr>
+  <tr><td>%b</td><td>Bytes sent, excluding HTTP headers (CLF format)</td></tr>
+  <tr><td>%B</td><td>Bytes sent, excluding HTTP headers</td></tr>
+  <tr><td>%H</td><td>The request protocol</td></tr>
+  <tr><td>%m</td><td>The request method</td></tr>
+  <tr><td>%p</td><td>The canonical Port of the server serving the request</td></tr>
+  <tr><td>%q</td><td>The query string (prepended with a ? if a query string exists, otherwise an empty string)</td></tr>
+  <tr><td>%r</td><td>First line of request</td></tr>
+  <tr><td>%s</td><td>Request HTTP status code</td></tr>
+  <tr><td>%T</td><td>Request duration, elapsed time to handle request in seconds '.' micro seconds</td></tr>
+  <tr><td>%U</td><td>The URL path requested, not including any query string.</td></tr>
+  <tr><td>%v</td><td>The canonical ServerName of the server serving the request</td></tr>
+  <tr><td>%V</td><td>The server name according to the UseCanonicalName setting</td></tr>
+  <tr><td>%w</td><td>Tomcat worker name</td></tr>
+  <tr><td>%R</td><td>Session route name (available with 1.2.19 and up)</td></tr>
+</table>
+
+<source>
+  JkRequestLogFormat     "%w %V %T"
+</source>
+
+<br/>
+<br/>
+</p>
+
+</subsection>
+
+<subsection name="Forwarding">
+<p>
+The directive JkOptions allow you to set many forwarding options which will enable (+)
+or disable (-) following option.
+<br/>
+<br/>
+</p>
+
+<p>
+JkOptions <b>ForwardKeySize</b>,  you ask mod_jk, when using ajp13, to forward also the SSL Key Size  as
+required by Servlet API 2.3.
+This flag shouldn't be set when servlet engine is Tomcat 3.2.x (on by default).
+
+<source>
+  JkOptions     +ForwardKeySize
+</source>
+
+<br/>
+<br/>
+</p>
+
+<p>
+JkOptions <b>ForwardURICompat</b>, you told mod_jk to send the URI to Tomcat normally,
+which is less spec compliant but mod_rewrite compatible,
+use it for compatibility with Tomcat 3.2.x engines (on by default).
+
+<source>
+  JkOptions     +ForwardURICompat
+</source>
+
+<br/>
+<br/>
+</p>
+<p>
+ At least one <b>+ForwardURIxxx</b> is required. By default, the ForwardURICompat
+ is turned on. So if you turn this off you will need to switch on one of the other
+ two described below.
+<br/>
+<br/>
+</p>
+<p>
+JkOptions <b>ForwardURICompatUnparsed</b>, the forwarded URI
+is unparsed, it's spec compliant but broke mod_rewrite.
+
+<source>
+  JkOptions     +ForwardURICompatUnparsed
+</source>
+
+<br/>
+<br/>
+</p>
+<p>
+JkOptions <b>ForwardURIEscaped</b>, the forwarded URI is escaped and
+Tomcat (since 3.3 rc2) will do the decoding part.
+
+<source>
+  JkOptions     +ForwardURIEscaped
+</source>
+
+<br/>
+<br/>
+</p>
+
+<p>
+JkOptions <b>ForwardDirectories</b> is used in conjunction with <b>DirectoryIndex</b>
+directive of Apache web server. As such mod_dir should be available to Apache,
+statically or dynamically (DSO)
+<br/>
+<br/>
+</p>
+
+<p>
+When DirectoryIndex is configured, Apache will create sub-requests for
+each of the local-url's specified in the directive, to determine if there is a
+local file that matches (this is done by stat-ing the file).
+</p>
+
+<p>
+If ForwardDirectories is set to false (default) and Apache doesn't find any
+files that match, Apache will serve the content of the directory (if directive
+Options specifies Indexes for that directory) or a <code>403 Forbidden</code> response (if
+directive Options doesn't specify Indexes for that directory).
+</p>
+
+<p>
+If ForwarDirectories is set to true and Apache doesn't find any files that
+match, the request will be forwarded to Tomcat for resolution. This is used in
+cases when Apache cannot see the index files on the file system for various
+reasons: Tomcat is running on a different machine, the JSP file has been
+precompiled etc.
+</p>
+
+<p>Note that locally visible files will take precedence over the
+ones visible only to Tomcat (i.e. if Apache can see the file, that's the one
+that's going to get served). This is important if there is more then one type of
+file that Tomcat normally serves - for instance Velocity pages and JSP pages.
+
+<source>
+  JkOptions     +ForwardDirectories
+</source>
+<br/>
+<br/>
+</p>
+
+<p>
+The directive <b>JkEnvVar</b> allows you to forward an environment variable from Apache server to Tomcat engine.
+The variable can be retrieved on the Tomcat side as a request attribute.
+You must add a default value as a second parameter to the directive.
+
+<source>
+  JkEnvVar     SSL_CLIENT_V_START     undefined
+</source>
+<br/>
+<br/>
+</p>
+
+</subsection>
+
+<subsection name="Assigning URLs to Tomcat">
+<p>
+If you have created a custom or local version of mod_jk.conf-local as noted above,
+you can change settings such as the workers or URL prefix.
+</p>
+
+<p>
+<b>JkMount</b> directive assign specific URLs to Tomcat.
+In general the structure of a JkMount directive is:
+</p>
+
+<source>  JkMount [URL prefix] [Worker name]</source>
+
+<source>
+  # send all requests ending in .jsp to worker1
+  JkMount /*.jsp worker1
+  # send all requests ending /servlet to worker1
+  JkMount /*/servlet/ worker1
+  # send all requests jsp requests to files located in /otherworker will go worker2
+  JkMount /otherworker/*.jsp worker2
+</source>
+
+<p>
+You can use the JkMount directive at the top level or inside &lt;VirtualHost&gt; sections of your httpd.conf file.
+</p>
+</subsection>
+
+<subsection name="Configuring Apache to serve static web application files">
+<p>
+If the Tomcat Host appBase (webapps) directory is accessible by the Apache web server,
+Apache can be configured to serve web application context directory static files instead
+of passing the request to Tomcat.
+</p>
+
+<p>
+Caution: If Apache is configured to serve static pages for a web application it bypasses
+any security contraints you may have configured in your web application web.xml config file.
+</p>
+
+<p>Use Apache's <b>Alias</b> directive to map a single web application context directory into Apache's
+document space for a VirtualHost:
+</p>
+
+<source>
+  # Static files in the examples webapp are served by apache
+  Alias /examples /vat/tomcat3/webapps/examples
+  # The following line prohibits users from directly access WEB-INF
+  &lt;Location "/examples/WEB-INF/"&gt;
+      AllowOverride None
+      deny from all
+  &lt;/Location&gt;
+  # All JSP will goes to worker1
+  JkMount /*.jsp worker1
+  # All servlets goes to worker1
+  JkMount /*/servlet/ worker1
+</source>
+
+<p>
+Starting with mod_jk 1.2.6, and under Apache 2.0, it's possible to exclude some URL/URI from
+jk processing by setting the env var <b>no-jk</b>, for example with the SetEnvIf Directive.
+</p>
+
+<p>
+You could use <b>no-jk</b> env var to fix problem with mod_alias or mod_userdir
+directive when jk and alias/userdir URLs matches.
+</p>
+
+<source>
+  # All URL goes to tomcat except the one containing /home
+  &lt;VirtualHost *:80&gt;
+      ServerName testxxx.mysys
+      DocumentRoot /www/testxxx/htdocs
+
+  # Use SetEnvIf to st no-jk when /home/ is encountered
+      SetEnvIf Request_URI "/home/*" no-jk
+
+  # Now /home will goes to /home/dataxxx/
+      Alias /home /home/dataxxx/
+
+      &lt;Directory "/home/dataxxx"&gt;
+          Options Indexes MultiViews
+          AllowOverride None
+          Order allow,deny
+          Allow from all
+      &lt;/Directory&gt;
+
+      JkMount /* myssys-xxx
+
+  &lt;/VirtualHost&gt;
+</source>
+
+
+<p>
+Use the mod_jk <b>JkAutoAlias</b> directive to map all web application context directories
+into Apache's document space.
+</p>
+
+<p>
+Attempts to access the WEB-INF or META-INF directories within a web application context
+or a Web Archive *.war within the Tomcat Host appBase (webapps) directory will fail with an
+<code>HTTP 403, Access Forbidden</code>
+</p>
+
+<source>
+  # Static files in all Tomcat webapp context directories are served by apache
+  JkAutoAlias /var/tomcat3/webapps
+  JkMount /*.jsp ajp13
+  JkMount /*/servlet/ ajp13
+</source>
+
+</subsection>
+</section>
+
+<section name="Building mod_jk on Unix">
+<p>
+The mod_jk build use the widely used configure system.
+</p>
+<subsection name="Prepare your mod_jk configure from subversion">
+In case you get source from subversion, ie without an existing configure script,
+you should have autoconf for configuration and installation.
+<p>
+To create tomcat-connectors's autoconf script, you will need libtool 1.5.2 or higher,
+and autoconf 2.59 or newer.
+</p><p>
+Those tools will not be required if you are just using a package downloaded from apache.org,
+they are only required for developers.
+</p>
+<p>
+To create the configure script just type :
+
+<screen>
+<type>./buildconf.sh</type>
+</screen>
+</p>
+</subsection>
+
+<subsection name="Using configure to build mod_jk">
+<p>Here's how to use configure to prepare mod_jk for building, just type:
+<source>
+./configure [autoconf arguments] [tomcat-connectors arguments]
+</source>
+</p>
+
+<p>
+You could set <b>CFLAGS</b> and <b>LDFLAGS</b> to add some platform specifics:
+</p>
+
+<screen>
+<type>LDFLAGS=-lc ./configure -with-apxs=/home2/local/apache/bin/apxs</type>
+</screen>
+
+<p>
+If you want to build mod_jk for Apache 1.3 and 2.0, you should
+<ul>
+<li>
+use configure and indicate Apache 1.3 apxs location (--with-apxs)
+</li>
+<li>
+use make
+</li>
+<li>
+copy the mod_jk binary to the apache modules location
+</li>
+<li>
+make clean (to remove all previously compiled modules)
+</li>
+<li>
+use configure and indicate Apache 2.0 apxs location,
+</li>
+<li>
+then make.
+</li>
+</ul>
+
+</p>
+</subsection>
+
+<subsection name="configure arguments">
+<p>
+<table>
+  <tr><th>Apache related parameters</th><th></th></tr>
+  <tr>
+  <td>--with-apxs[=FILE]</td>
+  <td>FILE is the location of the apxs tool. Default is finding apxs in PATH.
+It builds a shared Apache module. It detects automaticly the Apache version.
+(2.0 and 1.3)</td>
+  </tr>
+  <tr><td>--with-apache=DIR</td>
+  <td>DIR is the path where apache sources are located.
+The apache sources should have been configured before configuring mod_jk.
+DIR is something like: /home/apache/apache_1.3.19
+It builds a static Apache module.</td>
+  </tr>
+  <tr><td>--enable-EAPI</td>
+  <td>This parameter is needed when using Apache-1.3 and mod_ssl, otherwise you will get the error message:
+"this module might crash under EAPI!" when loading mod_jk.so in httpd.
+Not needed when --with-apxs has been used</td>
+</tr>
+</table>
+<br/>
+<table>
+  <tr><th>JNI related parameters</th><th></th></tr>
+  <tr><td>--enable-jni</td>
+  <td>Build the JNI worker and so the build process will require
+some informations about your Java Environment</td>
+  </tr>
+  <tr><td>--with-java-home=DIR</td>
+  <td>DIR is the  patch to the JDK root directory. Something like: /opt/java/jdk12</td>
+  </tr>
+  <tr><td>--with-os-type=SUBDIR</td><td>SUBDIR is the os-type subdirectory,
+  configure should guess it correctly.</td>
+  </tr>
+  <tr><td>--with-arch-type=SUBDIR</td><td>SUBDIR is the arch subdirectory,
+  configure should guess it correctly.</td>
+  </tr>
+  <tr><td>--with-java-platform=VAL</td><td>VAL is the Java platform 1 is 1.1.x and 2 is for 1.2 anf higher,
+  configure should guess it correctly.</td>
+  </tr>
+</table>
+</p>
+</subsection>
+
+<subsection name="Examples of configure use">
+
+<screen>
+<note>Apache 1.3 and 2.0 build</note>
+<type>./configure --with-apxs=/usr/sbin/apxs</type><br/>
+<type>make</type><br/>
+<type>cp ./apache-1.3/mod_jk.so /usr/lib/apache</type><br/>
+<type>make clean</type><br/>
+<type>./configure --with-apxs=/usr/sbin/apxs2</type><br/>
+<type>make</type><br/>
+<type>cp ./apache-2.0/mod_jk.so /usr/lib/apache2</type><br/>
+</screen>
+
+<screen>
+<note>Apache 2.0 build with JNI support</note>
+<type>./configure --with-apxs2=/opt/apache2/bin/apxs \</type>
+<typenext>--with-java-home=${JAVA_HOME} --with-java-platform=2 \</typenext>
+<typenext>--enable-jni</typenext><br/>
+</screen>
+
+<screen>
+<note>Apache 1.3 build without JNI support</note>
+<type>./configure --with-apxs=/usr/sbin/apxs</type><br/>
+</screen>
+
+</subsection>
+
+</section>
+
+<section name="Building mod_jk for Apache on Windows NT/2K/XP">
+<p>
+The module was developed using Visual C++ version 6.0, so having this environment is a prerequisite
+if you want to perform a custom build.
+</p>
+<p>
+The steps that you need to take are:
+</p>
+<ul>
+<li>
+Change directory to the apache 1.3 or apache 2.0 source directory depending on your version of Apache.
+</li>
+<li>
+If you want to build mod_jk for Apache 1.3, set an <b>APACHE1_HOME</b> environment variable which points
+to where your Apache 1.3 is installed.
+A mod_jk module for Apache 2.0 build will require <b>APACHE2_HOME</b> environment variable to be set.
+</li>
+<li>
+Copy mod_jk.so to Apache's modules directory.
+</li>
+</ul>
+<p>
+An example on how to build mod_jk for Apache 1.3:
+</p>
+<screen>
+<note>Set location for Apache 1.3 sources</note>
+<typedos>set APACHE1_HOME=c:\apache13</typedos>
+<note>Change directory to the mod_jk module for Apache 1.3</note>
+<typedos>cd c:\home\apache\jk\native\apache-1.3</typedos>
+<note>Build the sources using MSDEV</note>
+<typedos>MSDEV mod_jk.dsp /MAKE ALL</typedos>
+<note>Copy the dll to your apache modules directory</note>
+<typedos>cp release\mod_jk.so c:\apache13\modules\</typedos>
+</screen>
+
+<p>
+An example on how to build mod_jk for Apache 2.0:
+</p>
+<screen>
+<note>Set location for Apache 2.0 sources</note>
+<typedos>set APACHE2_HOME=c:\apache20</typedos>
+<note>Change directory to the mod_jk module for Apache 2.0</note>
+<typedos>cd c:\home\apache\jk\native\apache-2.0</typedos>
+<note>Build the sources using MSDEV</note>
+<typedos>MSDEV mod_jk.dsp /MAKE ALL</typedos>
+<note>Copy the dll to your apache modules directory</note>
+<typedos>cp release\mod_jk.so c:\apache20\modules\</typedos>
+</screen>
+
+<p>
+If msdev is not in your path, enter the full path to msdev.exe.
+Also, ApacheCore.lib is expected to exist in the <b>${APACHEX_HOME}\src\CoreD</b> and
+<b>${APACHEX_HOME}\src\CoreR</b> directories before linking will succeed.
+You will need to build enough of the Apache source to create these libraries.
+This will build both release and debug versions of the redirector plug-in (mod_jk).
+An alternative will be to open mod_jk.dsp in msdev and build it using the build menu.
+</p>
+</section>
+
+<section name="Building mod_jk for Apache on iSeries/OS400">
+<p>
+Since OS400 V4R5, iSeries (AS/400) has used Apache 2.0 as their primary web server,
+replacing the old IBM webserver.
+It's now possible to build mod_jk on iSeries thanks to the help of the IBM
+Rochester Labs which has provided information and patches
+to adapt mod_jk to OS400.
+</p>
+<p>
+You should have at least Apache 2.0.48 (product 5722DG1), a C Compiler and IFS.
+Apache 2.0.48 is provided with the most recent set of PTFs for the iSeries Apache
+server, which can be found at <a href="http://www.ibm.com/servers/eserver/iseries/software/http/">
+http://www.ibm.com/servers/eserver/iseries/software/http/</a>
+</p>
+<p>
+The all latest Apache 2 for OS400 V5R3 is now 2.0.52 (2005/03/23).
+Be sure to have the latest PTF loaded (SI17402/SI17061) if you want
+to make use of jk 1.2.8 and higher.
+</p>
+
+<p>
+To configure mod_jk on iSeries use the CL source provided with the mod_jk source.
+</p>
+<ul>
+<li>
+Get the latest mod_jk source and untar it on a Windows or Unix boxes
+</li>
+<li>
+Create a directory in IFS, ie /home/apache
+</li>
+<li>
+Send the whole jk source directory to iSeries directory via FTP.
+</li>
+<li>
+Then go to the iSeries command line :
+</li>
+</ul>
+<screen>
+<note>Create mod_jk library</note>
+<type5250>CRTLIB MOD_JK TEXT(‘Apache mod_jk tomcat connector module’)</type5250>
+<note>Create service program source file</note>
+<type5250>CRTSRCPF MOD_JK/QSRVSRC TEXT(‘Service program source file’)</type5250>
+<note>Create the CL build program source file</note>
+<type5250>CRTSRCPF FILE(MOD_JK/QCLSRC) TEXT(‘Build program source file’)</type5250>
+<note>Edit the service program source file</note>
+<type5250>STRSEU MOD_JK/QSRVSRC MOD_JK</type5250>
+</screen>
+<p>
+In the edited file, specify that only jk_module should be exported :
+<screen>
+<note> Columns   . . :    1  71     Edit                               MOD_JK/QSRVSRC </note>
+<note> SEU==>                                                                  MOD_JK </note>
+<note>        *************** Beginning of data ************************************* </note>
+<note>0001.00 STRPGMEXP PGMLVL(*CURRENT)                                              </note>
+<note>0002.00 EXPORT SYMBOL("jk_module")                                              </note>
+<note>0003.00 ENDPGMEXP                                                               </note>
+<note>        ****************** End of data **************************************** </note>
+</screen>
+</p>
+<p>
+You could start to build all the modules of mod_jk :
+</p>
+<screen>
+<note>Copy the CL build program source from IFS</note>
+<type5250>CPYFRMSTMF FROMSTMF('/home/apache/jk/native/apache-2.0/bldjk.qclsrc') +</type5250>
+<note>TOMBR('/QSYS.LIB/MOD_JK.LIB/QCLSRC.FILE/BLDJK.MBR') MBROPT(*REPLACE)</note>
+<note>Build the CL build program</note>
+<type5250>CRTCLPGM PGM(MOD_JK/BLDJK) SRCFILE(MOD_JK/QCLSRC) TEXT('Apache mod_jk build program')</type5250>
+<note>Launch the build</note>
+<type5250>CALL MOD_JK/BLDJK</type5250><br/>
+<note>If the build if successfull, copy the new mod_jk module</note>
+<type5250>CRTDUPOBJ OBJ(MOD_JK) FROMLIB(MOD_JK) OBJTYPE(*SRVPGM) TOLIB(QHTTPSVR) NEWOBJ(MOD_JK)</type5250>
+</screen>
+<p>
+Next, you should restart your Apache 2.0 server and enjoy this piece of OpenSource on iSeries.
+</p>
+</section>
+
+<section name="Building mod_jk for Apache on MacOS/X">
+<p>
+Mac OS X (10.2.x) build notes :
+</p>
+<p>
+Assuming that you are root :
+</p>
+<screen>
+<note>For Apache 1.3:</note>
+<type>./configure --with-apxs=/usr/sbin/apxs</type>
+<type>cd apache-1.3</type>
+<type>make -f Makefile.apxs</type>
+<type>cp mod_jk.so /etc/libexec/httpd</type>
+
+<note>For Apache 2.0:</note>
+<type>./configure --with-apxs=/usr/local/apache2/bin/apxs</type>
+<note>(you should point to the directory where you installed Apache 2.0)</note>
+<type>cd apache-2.0</type>
+<type>make -f Makefile.apxs install</type>
+</screen>
+</section>
+
+<section name="Getting mod_jk linked statically with Apache">
+<p>
+mod_jk allows to install mod_jk in the Apache source tree to get a statically
+linked mod_jk. Having mod_jk in the httpd executable brings some performance
+improvements. The configure option --with-apache prepare mod_jk to install it
+in the Apache source tree.
+The option --with-apache works both for Apache-1.3 and Apache-2.0.
+The examples below show how to get mod_jk in the httpd process.
+</p>
+
+<subsection name="Installation in Apache-2.0">
+<screen>
+<note> /home/apache20/httpd-2.0.43 is the directory where the httpd-2.0 sources
+are located. </note>
+<type>./configure --with-apache=/home/apache20/httpd-2.0.43</type><br/>
+<type>make</type><br/>
+<note>Install the mod_jk library and other files in
+/home/apache20/httpd-2.0.43/modules: </note>
+<type>make install</type><br/>
+<note> It is not possible to configure Apache directly because the config.m4 of mod_jk must
+be added to the configure of httpd-2.0. </note>
+<type>cd /home/apache20/httpd-2.0.43</type>
+<type>sh buildconf</type>
+<type>configure ... --with-mod_jk</type>
+<type>make</type>
+<type>make install</type><br/>
+</screen>
+<p>
+The enable-jk=share and enable-jk=static are not supported. --with-mod_jk only
+allow static linking of mod_jk.
+</p>
+</subsection>
+
+<subsection name="Installation in Apache-1.3">
+<screen>
+<note> /home/apache/apache_1.3.27 is the directory where the apache-1.3 sources
+are located. </note>
+<type>./configure --with-apache=/home/apache/apache_1.3.27</type><br/>
+<type>make</type><br/>
+<note>Install the libjk library, mod_jk.c, includes and other files in
+/home/apache/apache_1.3.27/src/modules/jk: </note>
+<type>make install</type><br/>
+<note> Configure in the Apache sources: </note>
+<type>cd /home/apache/apache_1.3.27</type>
+<type>configure ... --enable-module=dir --disable-shared=dir \</type>
+<typenext>              --activate-module=src/modules/jk/libjk.a \</typenext>
+<typenext>              --disable-shared=jk</typenext>
+<type>make</type>
+<type>make install</type><br/>
+</screen>
+<p>
+The --enable-shared=jk is also working and builds a dso file.
+</p>
+<screen>
+<note> Just change the configure in the Apache sources: </note>
+<type>configure ... --enable-module=dir --enable-shared=dir \</type>
+<typenext>              --activate-module=src/modules/jk/libjk.a \</typenext>
+<typenext>              --enable-shared=jk</typenext>
+</screen>
+</subsection>
+
+</section>
+</body>
+</document>

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/howto/doccontrib.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/howto/doccontrib.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/howto/doccontrib.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,331 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!DOCTYPE document [
+  <!ENTITY project SYSTEM "project.xml">
+]>
+<document url="doccontrib.html">
+
+  &project;
+<copyright>
+   Copyright 1999-2006 The Apache Software Foundation
+ 
+   Licensed 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.
+</copyright>
+<properties>
+<title>How to Contribute to the Documentation</title>
+<author email="rsowders at usgs.gov">Robert Sowders</author>
+<date>$Date: 2006-06-28 18:56:49 -0500 (Wed, 28 Jun 2006) $</date>
+</properties>
+<body>
+<section name="Introduction">
+<p>
+    This document describes how you can easily contribute to the 
+documentation.  I'm going to try to make it easy for everyone to help out with 
+the documentation of Tomcat, more specifically the documentation for the 
+connectors.  This is written from a windows user perspective as I believe they 
+will most benefit from it.  For people using Unix it should be easy for them to 
+apply these steps.  Just substitute Unix syntax where needed.
+</p>
+<p>
+    The documentation is produced using xml with xsl style sheets.  This 
+effectivly seperates the content of the documents from the style, so all that 
+contributers need to worry about the content.  It is much easier to use than 
+html.
+</p>
+<p>
+    It's all really quite simple.  Here is what you will need:
+<ul>
+<li>
+<b>A recent version of Ant</b>
+</li>
+<li>
+<b>The source code for the connectors from subversion</b>
+</li>
+<li>
+<b>Any ascii text editor</b>
+</li>
+</ul>
+</p>
+</section>
+<section name="Getting Started Step by Step">
+<p>
+    After you get these tools they are simple to set up.
+</p>
+    <subsection name="STEP 1. Get Ant">
+<p>
+    Install <a href="http://ant.apache.org/">Ant</a>. The only advice I 
+have is to choose a simple installation path.  Now set an environment variable 
+for ANT_HOME, and then add the location of the Ant/bin directory to your PATH 
+variable.  Consult your Operating system documentation for information on how 
+to do this.  When you are finished verify that you can run ant from the command 
+line.
+</p>
+<p>
+    Ant is used to build the documentation, among other things, and it must be 
+able to see a file called <b>build.xml</b>.  This file is located in the 
+<b>SVN_HOME\tomcat\connectors\trunk\jk\xdocs</b> directory.  In the 
+<b>build.xml</b> file there is a target named <b>all</b> that will be used to build 
+the docs.
+</p>
+</subsection>
+<subsection name="STEP 2.  Get the sources">
+<p>
+    Get the sources for
+<a href="http://svn.apache.org/repos/asf/tomcat/connectors/">tomcat-connectors</a>
+from the subversion repository.  If you'll 
+be editing from a windows platform you will need a windows subversion client.  There 
+are several available.  I like <a href="http://tortoisesvn.tigris.org/">turtoiseSVN</a>.  
+Unix users should install the subversion client of their choice,
+if they don't already have one.
+</p>
+<p>
+    You are ready to download the sources now.  Change directory to the 
+location where you want your repository to be.  For simplicity we will call this 
+your <b>SVN_HOME</b>.  Mine is located in C:\build.
+</p>
+<p>
+    Run the following command to <b>checkout</b> the sources for the first time.
+You should only need to do this once.
+<screen>
+<read> </read>
+<read>C:\build\>svn checkout http://svn.apache.org/repos/asf/tomcat/connectors/
+tomcat-connectors</read>
+<read> </read>
+</screen>
+</p>
+<p>
+    You should now be watching all the downloads come in.  Now that you have 
+the sources on your machine the hard part is over.  From now on, to update your 
+sources all you have to do is cd into any directory in your repository and run 
+the <b>svn update</b> command.
+    <screen>
+<note>    To update your xdocs directory simply cd into the xdocs directory 
+and:</note>
+<read>C:\build\tomcat-connectors\jk\>cd xdocs</read>
+<read>C:\build\tomcat-connectors\jk\xdocs\>svn update</read>
+</screen>
+</p>
+</subsection>
+<subsection name="STEP 3.  Test your build environment">
+<p>
+    Open a command prompt window and cd to the directory where you downloaded 
+the source.  Now cd into the jk directory and then into the xdocs directory so
+that <b>Ant</b> can see the 
+<b>build.xml</b> file. Then from a command prompt, run the following:
+<screen>
+<read> </read>
+<read>C:\build\tomcat-connectors>cd jk</read>
+<read>C:\build\tomcat-connectors\jk>cd xdocs</read>
+<read>C:\build\tomcat-connectors\jk\xdocs>ant all</read>
+<read> </read>
+</screen>
+</p>.
+<p>
+    You should see the ant compiler messages scrolling by rapidly and then stop 
+with the following:
+<screen>
+<read>[style] Transforming into C:\build\tomcat-connectors\jk\build\docs></read>
+<read>[style] Processing C:\build\tomcat-connectors\jk\xdocs\faq.xml 
+to</read>
+<read>C:\build\tomcat-connectors\jk\build\docs\faq.html</read>
+<read>[style] Loading stylesheet C:\build\tomcat-connectors\jk\xdocs\style.xsl</read>
+<read>[style] Processing C:\build\tomcat-connectors\jk\xdocs\index.xml 
+to</read>
+<read>C:\build\tomcat-connectors\jk\build\docs\index.html</read>
+<read>[copy] Copying 8 files to C:\build\tomcat-connectors\jk\build\docs</read>
+<read> </read>
+<read>BUILD SUCCESSFUL</read>
+<read>Total time: 10 seconds</read>
+<read>C:\build\tomcat-connectors\jk></read>
+</screen>
+</p>
+<p>
+    All the xml files present in the xdocs directory structure were transformed 
+to html and copied to the <b>SVN_HOME\tomcat-connectors\jk\build\docs</b>
+directory.  Open one of the 
+html files in your browser and see how it looks.
+</p>
+</subsection>
+<subsection name="STEP 4.   The editing process.">
+<p>
+    I find it easier to use two windows while doing my updates.  One I call my 
+<b>build</b> window.  I keep this one in the <b>SVN_HOME\tomcat-connectors\jk\xdocs</b>
+directory and I only run two commands in this window:
+<screen>
+<read> </read>
+<note>   First I run</note>
+<read>ant clean</read>
+<note>   Then I run</note>
+<read>ant all</read>
+<read> </read>
+</screen>
+</p>
+<p>
+    My second window I call my <b>edit</b> window and I keep that one in the 
+<b>SVN_HOME\tomcat-connectors\jk\xdocs</b> directory where I'm doing my
+edits, diffs and svn updates.
+</p>
+<p>
+    Before you start editing you should always update your local repository to 
+prevent conflicts.
+<screen>
+<note>    You only need to update the xdocs directory</note>
+<read>C:\build\tomcat-connectors\jk>cd xdocs</read>
+<read>C:\build\tomcat-connectors\jk\xdocs></read>
+<read>C:\build\tomcat-connectors\jk\xdocs>svn update</read>
+</screen>
+</p>
+<p>
+    Now that your repository is up to date you can begin editing.  Find 
+something in the documentation to edit.  When you find something remember the 
+name of the file.  In your <b>edit</b> window find and edit the xml source file 
+with the same name.  After you are done return to the  <b>build</b> window, and 
+in the <b>SVN_HOME\tomcat-connectors\jk\xdocs</b> directory run:
+<screen>
+<read> </read>
+<read>C:\build\tomcat-connectors\jk\xdocs> ant clean</read>
+<read> </read>
+</screen>
+</p>
+<p>
+    This will delete all the previous html files and make the area ready for 
+updated material.  Now to make fresh documents that incorporate your changes 
+run:
+<screen>
+<read> </read>
+<read>C:\build\tomcat-connectors\jk\xdocs>ant all</read>
+<read> </read>
+</screen>
+</p>
+<p>
+    Use your browser to view the edits you just made, they will be in the 
+<b>SVN_HOME\tomcat-connectors\jk\build\docs</b> sub-tree.  If it looks
+good and is ready to go, 
+all that is left to do is to create a patch and submit it.
+</p>
+</subsection>
+<subsection name="STEP 5.  Creating a patch and submitting it.">
+<p>
+    From your <b>edit</b> window cd into the directory that contains the xml 
+file you are working on, and run the <b>svn update</b> command.  For example, 
+to produce a diff of the index.xml file and call it patch.txt, you 
+would cd into the directory containing the index.xml file and:
+<screen>
+<read>C:\build\tomcat-connectors\jk\xdocs\>svn diff index.xml >  
+patch.txt.</read>
+<read> </read>
+</screen>
+</p>
+<p>
+    Now that you have your patch you are ready to send it in.
+</p>
+<p>
+    Patches to the documentation are handled just like a bug report.  You 
+should submit your patches to <a 
+href="http://issues.apache.org/bugzilla/">http://issues.apache.org/bugzilla/</a>
+ and include a good one line subject.  If this is your first time to use the 
+bug database then you should read  <a 
+href="http://issues.apache.org/bugzilla/bugwritinghelp.html">http://issues.apach
+e.org/bugzilla/bugwritinghelp.html.</a>  You will need to create a user 
+account.  At the web site paste your patch into the web form and don't forget 
+to describe what it is your patch is for.  Sooner or later a someone with 
+commit privileges will review your suggestion.
+</p>
+</subsection>
+</section>
+<section name="Subversion Basics">
+<p>
+    After you have checked out the sources the first time it is much easier to 
+use subversion.  You can cd into any directory of the repository and run <b>svn 
+update</b> to get the latest sources for that directory.  For editing 
+purposes you should always update your repository before you start editing to 
+reduce conflicts.
+</p>
+<p>
+    You will need to run <b>svn diff</b> to generate patches for submission.  
+Again cd into the directory containing the file you are editing and run <b>svn 
+diff name_of_the_file_you_edited > patch.txt</b> to generate a patch for 
+submission.
+</p>
+<p>
+    Pay attention to the terminal window during the update.
+</p>
+<p>
+    Lines begining with a <b>A</b> indicate files that have been added.
+</p>
+<p>
+    Lines begining with a <b>D</b> indicate files that have been deleted.
+</p>
+<p>
+    Lines begining with a <b>U</b> mean the local copy was patched to update it 
+to the current version in the master repository.
+</p>
+<p>
+    Lines begining with a <b>G</b> mean your local copy is different from the 
+master copy, and the changes were successfully merged into your copy.
+</p>
+<p>
+    Lines begining with a <b>C</b> mean there was a conflict in merging the 
+changes and you need to review the file and merge the changes manually.  Search 
+for  >>>> and merge the changes.
+</p>
+<p>
+    Lines begining with a <b>?</b> indicate files that reside on your local 
+system which are not part of the repository.  You will normally see this when 
+you are creating new files for submission.
+</p>
+</section>
+
+<section name="Updating Web site">
+<p>
+    Only Committers are able to update the web site (http://tomcat.apache.org/connectors-doc/).
+    To do it:
+    <ul>
+    <li>Connect to people.apache.org.</li>
+    <li>umask 002</li>
+    <li>Copy the changed files to /www/tomcat.apache.org/connectors-doc/.</li>
+    <li>or use ant from a checkout tomcat/connectors/jk/xdocs repository:<br />
+        ant -Dbuild.dir=/www/tomcat.apache.org -Ddist.name=connectors-doc 
+    </li>
+    <li>The changes need around 4 hours to be synced to tomcat.apache.org.</li>
+    </ul>
+</p>
+</section>
+<section name="Guides and Resources">
+<p>
+    A little help to get you started if you need it
+</p>
+<ul>
+<li>
+<a href="http://www.xml.org/xml/resources_focus_beginnerguide.shtml">XML 
+Beginner's Guide</a>
+</li>
+<li>
+<a href="http://issues.apache.org/bugzilla/">Bugzilla</a>
+</li>
+<li>
+<a href="http://issues.apache.org/bugzilla/bugwritinghelp.html">Bugzilla Bug 
+Writing Guide</a>
+</li>
+<li>
+<a href="http://ant.apache.org/">Ant</a>
+</li>
+<li>
+<a href="http://subversion.tigris.org/">Subversion Home</a>
+</li>
+<li>
+<a href="http://svn.apache.org/repos/asf/tomcat/connectors/jk/xdocs/">JK Docs repository</a>
+</li>
+</ul>
+</section>
+</body>
+</document>

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/howto/domino.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/howto/domino.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/howto/domino.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,531 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!DOCTYPE document [
+  <!ENTITY project SYSTEM "project.xml">
+]>
+<document url="domino.html">
+
+  &project;
+<copyright>
+   Copyright 1999-2006 The Apache Software Foundation
+ 
+   Licensed 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.
+</copyright>
+<properties>
+<title>Domino HowTo</title>
+<author email="andy at tagish.com">Andy Armstrong</author>
+<author email="hgomez at apache.org">Henri Gomez</author>
+<date>$Date: 2006-06-28 18:56:49 -0500 (Wed, 28 Jun 2006) $</date>
+</properties>
+<body>
+<section name="Introduction">
+
+<p>
+This document explains how to set up Domino to cooperate with Tomcat. 
+</p>
+
+<p>
+It is recommended that you also read the <a href="workers.html">Workers HowTo</a> document
+to learn how to setup the working entities between your WebServer and Tomcat Engines.
+</p>
+
+<p>
+Recent versions of the Lotus Domino web server have had the ability to host Java servlets, 
+but at the time of writing the Domino servlet container uses JDK 1.2.2 and it is not (apparently) 
+possible to replace this with JDK 1.3. 
+</p>
+
+<p>
+That means if you want to use JAAS or any other API 
+that is JDK 1.3 only in your servlets you're stuck. 
+</p>
+
+<subsection name="Document Conventions and Assumptions">
+<p>
+${tomcat_home} is the root directory of tomcat. 
+Your Tomcat installation should have the following subdirectories:
+
+<ul>
+<li>
+${tomcat_home}\conf - Where you can place various configuration files
+</li>
+<li>
+${tomcat_home}\webapps - Containing example applications
+</li>
+<li>
+${tomcat_home}\bin - Where you place web server plugins
+</li>
+</ul>
+</p>
+<p>
+In all the examples in this document ${tomcat_home} will be <b>c:\tomcat</b>.
+A worker is defined to be a tomcat process that accepts work from the Domino server.
+</p>
+</subsection>
+
+
+<subsection name="Supported Configuration">
+<p>
+The Domino Tomcat redirector was developed and tested on:
+<ul>
+<li>
+WinNT4.0-i386 SP6a (it should be able to work on other versions of the NT service pack.) and Win2K Professional
+</li>
+<li>
+RedHat Linux 7
+</li>
+<li>
+Lotus Domino 5.0.6a
+</li>
+<li>
+Tomcat 3.2.x, Tomcat 3.3.x, Tomcat 4.0.x, Tomcat 4.1.x and Tomcat 5
+</li>
+</ul>
+</p>
+
+<p>
+The redirector uses <b>ajp12</b> and <b>ajp13</b> to send requests to the Tomcat containers.
+It probably also works with Tomcat in process, but that hasn't been tested.
+</p>
+</subsection>
+
+<subsection name="Who support ajp protocols ?">
+<p>
+The ajp12 protocol is only available in Tomcat 3.2.x and 3.3.x.
+</p>
+
+<p>
+The <b>ajp12</b> has been <b>deprecated</b> with Tomcat 3.3.x and you should use instead 
+<b>ajp13</b> which is the only ajp protocol known by Tomcat 4.0.x, 4.1.x and 5.
+</p>
+
+<p>
+Of course Tomcat 3.2.x and 3.3.x also support ajp13 protocol.
+</p>
+
+<p>
+Others servlet engines such as <b>jetty</b> have support for ajp13 protocol
+</p>
+
+</subsection>
+</section>
+
+<section name="Installation on Windows">
+<p>
+The Tomcat redirector requires 3 entities:
+</p>
+
+<ul>
+<li>
+tomcat_redirect.dll - The Domino plugin; either obtain a pre-built DLL or build it yourself 
+(see the build section).
+</li>
+<li>
+workers.properties - A file that describes the host(s) and port(s) used by the workers (Tomcat processes). 
+A sample workers.properties can be found under the conf directory.
+</li>
+<li>
+tomcat_redirector.reg - Registry entries
+</li>
+</ul>
+
+<p>
+We'll assume that tomcat redirector is placed in <b>c:\jk\lib\tomcat_redirector.dll</b>, 
+the properties file is in<b>c:\jk\conf</b>
+and you created a log directory <b>c:\jk\logs</b>
+</p>
+
+<p>
+Copy the file <b>tomcat_redirector.dll</b> to the Domino program directory 
+(this is the directory, which may be called something like <b>c:\Lotus\Domino</b>, that contains a file called 
+<b>nlnotes.exe</b>). 
+</p>
+
+<screen>
+<note>Copy redirector dll to Domino program directory</note>
+<typedos>copy c:\jk\lib\tomcat_redirector.dll c:\Lotus\Domino</typedos>
+</screen>
+
+<p>
+Shortly we will tell Domino where to find this file, but before we do that we need to make some registry entries. 
+The simplest way is to edit the supplied file <b>tomcat_redirector.reg</b>, which initially will look like this :
+</p>
+
+<source>
+  REGEDIT4
+  
+  [HKEY_LOCAL_MACHINE\SOFTWARE\Apache Software Foundation\Jakarta Dsapi Redirector\1.0]
+  "log_file"="c:\\jk\\logs\\domino.log"
+  "log_level"="debug"
+  "worker_file"="c:\\jk\\conf\\workers.properties"
+  "worker_mount_file"="c:\\jk\\conf\\uriworkermap.properties"
+  "tomcat_start"="c:\\tomcat\\bin\\tomcat.bat start"
+  "tomcat_stop"="c:\\tomcat\\bin\\tomcat.bat stop"
+</source>
+
+<p>
+Edit this file to reflect the location where Tomcat has been installed, i.e. replace the instances 
+of <b>c:\\tomcat</b> and <b>c:\\jk</b> with the appropriate path remembering to <b>retain the double backslashes</b>. 
+</p>
+
+<p>
+Once you've made the necessary changes save this file and double click on it to enter it into the registry.
+</p>
+
+<p>
+Note that the files referred to by the worker_file and worker_mount_file keys need to exist and contain sane values. 
+Default Tomcat installations will have these files. Note also that recent versions of Tomcat write a file called uriworkermap.properties-auto when they start up that can be renamed uriworkermap.properties to obtain default behaviour.
+</p>
+
+<subsection name="Note for Windows 2000 users">
+<p>
+For some reason Windows 2000 seems to have a problem resolving the references to localhost 
+in the default workers.properties. 
+</p>
+
+<p>
+The easiest solution is to replace 'localhost' with '127.0.0.1' everywhere it appears.
+</p>
+</subsection>
+
+<subsection name="Automatically Starting Tomcat">
+<p>
+The last two registry entries above provide commands that the redirector DLL will use to 
+start and stop Tomcat when the Domino http server starts and stops respectively. 
+</p>
+
+<p>
+If you don't require this behaviour these two lines can be omitted 
+(or deleted if you've already placed them in the registry).
+</p>
+</subsection>
+
+<subsection name="Configuring Domino">
+<p>
+Finally we need to configure Domino to use the DSAPI extension DLL. 
+For those who are unfamiliar with Domino server configuration most of a server's configurable behavior 
+is dictated by a document called the "server document" in a database called the 
+<b>"Public Name and Address Book"</b> or <b>"NAB"</b> for short
+</p>
+<p>
+(N.B. Lotus have renamed the NAB to "Domino Directory" from Domino 5 onwards). 
+Each Domino server will have a NAB (called names.nsf) and each NAB will have a number of server documents 
+including one for the current server. 
+</p>
+
+<p>
+If you have not previously configured a Domino server you may need to refer to the supplied documentation, 
+or you may need to pass this document to your tame Domino administrator.
+</p>
+
+<p>
+Assuming you know your way around a Domino server document what we're going to do is actually quite simple. 
+Open the server document for this server, place it in Edit mode, then locate the DSAPIsection and the 'DSAPI filter file names' field on the Internet Protocols tab, HTTP sub-tab. Add "tomcat_redirector.dll" to the DSAPI field, then save and close the document.
+</p>
+</subsection>
+
+<subsection name="Restart Domino">
+<p>
+In order to get these settings to take effect and make sure that you haven't disrupted anything 
+else you should now restart the Domino server. 
+</p>
+
+<p>If the server is running as a service and you have changed any relevant system variables 
+(JAVA_HOME, TOMCAT_HOME, CLASSPATH) since the last time you restarted the computer you should 
+do a complete restart now because updates to system variables are not seen by services until after a reboot. 
+</p>
+
+<p>
+If all goes well you should see something like this on the server console when the web server starts up :
+</p>
+
+<screen>
+<read>29/05/2001 18:54:13   JVM: Java Virtual Machine initialized.</read>
+<read>29/05/2001 18:54:14   Attempting to start Tomcat: c:\tomcat\bin\tomcat.bat start</read>
+<read>Including all jars in c:\tomcat\lib in your CLASSPATH.</read>
+<read/>
+<read>Using CLASSPATH: c:\tomcat\classes;c:\tomcat\lib\ant.jar;c:\tomcat\lib\servlet.jar</read>
+<read/>
+<read>Starting Tomcat in new window</read>
+<read>29/05/2001 18:54:15   Apache Tomcat Interceptor (Jakarta/DSAPI/1.0) loaded</read>
+<read>29/05/2001 18:54:16   HTTP Web Server started</read>
+</screen>
+
+<p>
+At about the same time Tomcat should open in a new window (assuming you enabled the autostart option in the registry settings). 
+</p>
+
+<p>
+You should now be able to visit a URL that is handled by Tomcat. 
+Something like may be available, depending on how Tomcat is configured :
+</p>
+
+<source>
+http://name of server/servlet/SnoopServlet
+</source>
+
+<p>
+If that all works you're done ;-) 
+</p>
+
+</subsection>
+
+</section>
+
+<section name="Installation on Linux">
+<p>
+The Tomcat redirector requires 3 entities:
+</p>
+
+<ul>
+<li>
+libtomcat.so - The Domino plugin; either obtain a pre-built shared lib or build it yourself 
+(see the build section).
+</li>
+<li>
+workers.properties - A file that describes the host(s) and port(s) used by the workers (Tomcat processes). 
+A sample workers.properties can be found under the conf directory.
+</li>
+<li>
+libtomcat.ini - configuration entries
+</li>
+</ul>
+
+<p>
+Copy the file <b>libtomcat.so</b> to the Domino program directory which may be called 
+something like <b>/opt/lotus/notes/5601/linux</b>, it should contains a file called <b>libnotes.so</b>
+and copy <b>libtomcat.ini</b> to the Domino data directory.
+</p>
+
+<screen>
+<note>Copy redirector shared lib to Domino program directory</note>
+<type>cp c:\jk\lib\libtomcat.so /opt/lotus/notes/5601/linux</type>
+<note>Copy config to Domino data directory</note>
+<type>cp c:\jk\conf\libtomcat.ini /opt/datalotus</type>
+</screen>
+
+
+<p>
+Note that if you're building the redirector from source these files should already 
+have been copied to the appropriate locations. 
+</p>
+
+<p>
+Before using the redirector you may like to review the settings in <b>libtomcat.ini</b> which, 
+by default, will look something like this:
+</p>
+
+<source>
+  log_file=/var/log/domino.log
+  log_level=debug
+  worker_file=/var/tomcat3/conf/workers.properties
+  worker_mount_file=/var/tomcat3/conf/uriworkermap.properties
+  tomcat_start=/var/tomcat3/bin/tomcat.sh start
+  tomcat_stop=/var/tomcat3/bin/tomcat.sh stop
+</source>
+
+<p>
+If you're building the redirector from the source you may not need to make any changes, 
+otherwise you may have to edit this file to reflect the location where Tomcat has been installed, 
+i.e. replace the instances of /usr/local/apache/tomcat with the appropriate path.
+</p>
+
+<p>
+Note that the files referred to by the <b>worker_file</b> and <b>worker_mount_file</b> keys need to exist 
+and contain sane values. 
+</p>
+
+<p>
+Default Tomcat installations will have these files. 
+Note also that recent versions of Tomcat write a file called <b>uriworkermap.properties-auto</b> 
+when they start up that can be renamed <b>uriworkermap.properties</b> to obtain default behaviour.
+</p>
+
+<subsection name="Automatically Starting Tomcat">
+<p>
+The last two registry entries above provide commands that the redirector will use to start and stop 
+Tomcat when the Domino http server starts and stops respectively. 
+</p>
+
+<p>
+If you don't require this behaviour these two lines can be deleted.
+</p>
+</subsection>
+
+
+<subsection name="Configuring Domino">
+<p>
+Finally we need to configure Domino to use the DSAPI extension. 
+</p>
+
+<p>
+For those who are unfamiliar with Domino server configuration most of a server's 
+configurable behavior is dictated by a document called the "server document" in a database called the 
+<b>"Public Name and Address Book"</b> or <b>"NAB"</b> for short
+</p>
+
+<p>
+N.B. Lotus have renamed the NAB to "Domino Directory" from Domino 5 onwards). 
+</p>
+
+<p>
+Each Domino server will have a NAB (called names.nsf) and each NAB will have a number of server documents 
+including one for the current server. 
+
+If you have not previously configured a Domino server you may need to refer to the supplied documentation, 
+or you may need to pass this document to your tame Domino administrator.
+</p>
+
+<p>
+Assuming you know your way around a Domino server document what we're going to do is actually quite simple. 
+</p>
+
+<p>
+Open the server document for this server, place it in Edit mode, then locate the 
+<b>DSAPIsection</b> and the <b>'DSAPI filter file names'</b> field on the Internet Protocols tab, 
+HTTP sub-tab. 
+</p>
+
+<p>
+Add <b>"libtomcat.so"</b> to the DSAPI field, then save and close the document.
+</p>
+
+</subsection>
+
+<subsection name="Restart Domino">
+<p>
+In order to get these settings to take effect and make sure that you haven't 
+disrupted anything else you should now restart the Domino HTTP server. 
+</p>
+
+<p>
+At the Domino console type
+</p>
+
+<screen>
+<read>> tell http quit</read>
+<read>> load http</read>
+</screen>
+
+<p>
+You should see the HTTP server reload along with messages that will confirm that the redirector 
+has loaded and that Tomcat has (if you used Tomcat autostart) started. 
+</p>
+
+<p>
+You should now be able to visit a URL that is handled by Tomcat. Something like
+</p>
+
+<source>
+http://name of server/servlet/SnoopServlet
+</source>
+
+may be available, depending on how Tomcat is configured.
+
+</subsection>
+
+</section>
+
+<section name="Building for Windows">
+<p>
+To compile it you'll need the JK Domino sources and Microsoft Visual C++ 6.0. 
+</p>
+
+<p>
+You will probably also want the Lotus Notes C API version 5.0.7 or later.
+You can build the DLL without the C API, in which case you'll need to define the macro NO_CAPI in config.h. 
+If you do this Domino logging from the DLL will be disabled.
+</p>
+
+<ul>
+<li>
+Change directory to the domino plugin source directory.
+</li>
+<li>
+Edit <b>dsapi.dsp</b> and update the include and library path to reflect your own Domino server installation 
+(search for a <b>/I compiler</b> option and <b>/libpath</b> linker option)
+</li>
+<li>
+Make the source with MSDEV
+</li>
+</ul>
+
+<screen>
+<note>Change directory to the dsapi plugins source directory</note>
+<typedos>cd c:\home\apache\jk\domino</typedos>
+<note>Build the sources using MSDEV</note>
+<typedos>MSDEV dsapi.dsp /MAKE ALL</typedos>
+</screen>
+
+</section>
+
+<section name="Building for Linux">
+<p>
+You will probably also want the Lotus Notes C API version 5.0.3 for Unix or later.
+</p>
+
+<p>
+You can build the redirector without the C API, in which case you'll need to define the macro NO_CAPI in config.h. 
+If you do this, Domino logging from the redirector will be disabled.
+</p>
+
+<ul>
+<li>
+Change directory to the Domino plugin source directory.
+</li>
+<li>
+Edit <b>Makefile</b> and update the include and library path to reflect your own Domino server installation 
+</li>
+</ul>
+
+<source>
+  edit the Makefile providing appropriate values for these variables
+  
+  # The root of your Domino installation. Mine's in /usr/local/lotus, but your's
+  # may well be /opt/lotus
+  NOTESROOT=/usr/local/lotus
+  
+  # The place where the Notes API is installed
+  NOTESAPI=$(NOTESROOT)/notesapi
+  
+  # The Domino program directory.
+  NOTESHOME=$(NOTESROOT)/notes/5061/linux
+  
+  # The Domino data directory (the directory containing names.nsf)
+  NOTESDATA=$(NOTESROOT)/notes/data
+  
+  # The include path for the Notes C API headers
+  NOTESINC=$(NOTESAPI)/include
+  
+  # Where tomcat is installed. This is where conf, lib, webapps et al normally are
+  TOMCATHOME=/var/tomcat3
+  
+  # Your JDK's include directory
+  JAVAINC=$(JAVA_HOME)/include
+</source>
+
+<ul>
+<li>
+Now you should build via make
+</li>
+</ul>
+
+<screen>
+<note>Launch build via make</note>
+<type>make</type>
+<note>place the redirector (libtomcat.so) and its settings file (libtomcat.ini) in the appropriate places</note>
+<type>make install</type>
+</screen>
+
+</section>
+</body>
+</document>

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/howto/iis.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/howto/iis.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/howto/iis.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,707 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!DOCTYPE document [
+  <!ENTITY project SYSTEM "project.xml">
+]>
+<document url="iis.html">
+
+  &project;
+<copyright>
+   Copyright 1999-2006 The Apache Software Foundation
+ 
+   Licensed 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.
+</copyright>
+<properties>
+<title>IIS HowTo</title>
+<author email="hgomez at apache.org">Henri Gomez</author>
+<author email="shachor at il.ibm.com">Gal Shachor</author>
+<author email="yoavs at apache.org">Yoav Shapira</author>
+<date>$Date: 2006-06-28 18:56:49 -0500 (Wed, 28 Jun 2006) $</date>
+</properties>
+<body>
+<section name="Introduction">
+<p>
+This document explains how to set up IIS to cooperate with Tomcat. 
+</p>
+
+<p>
+Normally IIS can not execute Servlets and Java Server Pages (JSPs), 
+configuring IIS to use the JK ISAPI redirector plugin will let IIS send servlet and 
+JSP requests to Tomcat (and this way, serve them to clients).
+</p>
+
+<p>
+It is recommanded that you also read the <a href="workers.html">Workers HowTo</a> document
+to learn how to setup the working entities between your WebServer and Tomcat Engines.
+</p>
+
+
+<subsection name="Document Conventions and Assumptions">
+<p>
+${tomcat_home} is the root directory of tomcat. 
+Your Tomcat installation should have the following subdirectories:
+
+<ul>
+<li>
+${tomcat_home}\conf - Where you can place various configuration files
+</li>
+<li>
+${tomcat_home}\webapps - Containing example applications
+</li>
+<li>
+${tomcat_home}\bin - Where you place web server plugins
+</li>
+</ul>
+</p>
+<p>
+In all the examples in this document ${tomcat_home} will be <b>c:\tomcat</b>.
+A worker is defined to be a tomcat process that accepts work from the IIS server.
+</p>
+</subsection>
+
+
+<subsection name="Supported Configuration">
+<p>
+The IIS-Tomcat redirector was developed and tested on:
+<ul>
+<li>
+WinNT4.0-i386 SP4/SP5/SP6a (should be able to work with other service packs), Win2K and WinXP and Win98
+</li>
+<li>
+IIS4.0 and PWS4.0 (numerous people have working IIS 5 and IIS 6 configurations)
+</li>
+<li>
+Tomcat 3.2 and later, Tomcat 4.x and Tomcat 5
+</li>
+</ul>
+</p>
+
+<p>
+The redirector uses <b>ajp12</b> and <b>ajp13</b> to send requests to the Tomcat containers. There is also an option to use Tomcat in process, 
+more about the in-process mode can be found in the in process howto.
+</p>
+</subsection>
+
+<subsection name="IIS 5 and 6 Notes">
+<p>
+There are extra steps you need to take for configuring Tomcat with IIS 5 and 6.  Please see the appropriate links from 
+<a href="http://wiki.apache.org/tomcat/Tomcat/Links">Tomcat Useful Links</a>.
+</p>
+</subsection>
+
+<subsection name="Who support ajp protocols ?">
+<p>
+The ajp12 protocol is only available in Tomcat 3.2.x and 3.3.x.
+</p>
+
+<p>
+The <b>ajp12</b> has been <b>deprecated</b> with Tomcat 3.3.x and you should use instead 
+<b>ajp13</b> which is the only ajp protocol known by Tomcat 4.x and 5.
+</p>
+
+<p>
+Of course Tomcat 3.2.x and 3.3.x also support ajp13 protocol.
+</p>
+
+<p>
+Others servlet engines such as <b>jetty</b> have support for ajp13 protocol
+</p>
+
+</subsection>
+
+<subsection name="How does it work ?">
+<p>
+<ol>
+<li>
+The IIS-Tomcat redirector is an IIS plugin (filter + extension), IIS load the redirector plugin and calls its 
+filter function for each in-coming request.
+</li>
+<li>
+The filter then tests the request URL against a list of URI-paths held inside uriworkermap.properties, 
+If the current request matches one of the entries in the list of URI-paths, 
+the filter transfer the request to the extension.
+</li>
+<li>
+The extension collects the request parameters and forwards them to the appropriate worker using the defined
+protocol like <b>ajp13</b>.
+</li>
+<li>
+The extension collects the response from the worker and returns it to the browser.
+</li>
+</ol>
+</p>
+</subsection>
+
+</section>
+
+<section name="Installation">
+<p>
+A pre-built version of the ISAPI redirector server plugin, isapi_redirect.dll, is available under 
+the win32/i386 directory of tomcat-connectors distribution. 
+For those using Netscape as your browser, try downloading a zip version of the file, if available. 
+There can be problems using Netscape to download DLL files.
+
+You can also build a copy locally from the source present in tomcat-connectors distribution.
+
+The Tomcat redirector requires three entities:
+
+<ul>
+<li>
+<b>isapi_redirect.dll</b> - The IIS server plugin, either obtain a pre-built DLL or build it yourself (see the build section).
+</li>
+<li>
+<b>workers.properties</b> - A file that describes the host(s) and port(s) used by the workers (Tomcat processes). 
+A sample workers.properties can be found under the conf directory.
+</li>
+<li>
+<b>uriworkermap.properties</b> - A file that maps URL-Path patterns to workers. 
+A sample uriworkermap.properties can be found under the conf directory as well.
+</li>
+</ul>
+</p>
+
+<p>
+The installation includes the following parts:
+
+<ul>
+<li>
+Configuring the ISAPI redirector with a default /examples context and checking that you can serve servlets with IIS.
+</li>
+<li>
+Adding more contexts to the configuration.
+</li>
+</ul>
+</p>
+
+</section>
+
+<section name="Configuring the ISAPI Redirector">
+<p>
+In this document I will assume that isapi_redirect.dll is placed in 
+<b>c:\tomcat\bin\win32\i386\isapi_redirect.dll</b> and 
+that you created the properties files are in <b>c:\tomcat\conf</b>.
+</p>
+<p>
+<ol>
+<li>
+In the registry, create a new registry key named
+<b>"HKEY_LOCAL_MACHINE\SOFTWARE\Apache Software Foundation\Jakarta Isapi Redirector\1.0"</b>
+</li>
+<li>
+Add a string value with the name <b>extension_uri</b> and a value of <b>/jakarta/isapi_redirect.dll</b>
+</li>
+<li>
+Add a string value with the name <b>log_file</b> and a value pointing to where you want your 
+log file to be (for example <b>c:\tomcat\logs\isapi.log</b>).
+</li>
+<li>
+Add a string value with the name <b>log_level</b> and a value for your log level 
+(can be debug, info, error or emerg).
+</li>
+<li>
+Add a string value with the name <b>worker_file</b> and a value which is the full path 
+to your workers.properties file (for example <b>c:\tomcat\conf\workers.properties</b>)
+</li>
+<li>
+Add a string value with the name <b>worker_mount_file</b> and a value which is the full path 
+to your uriworkermap.properties file (for example <b>c:\tomcat\conf\uriworkermap.properties</b>)
+</li>
+<li>
+Using the IIS management console, add a new virtual directory to your IIS/PWS web site.
+The name of the virtual directory must be jakarta. 
+Its physical path should be the directory where you placed isapi_redirect.dll 
+(in our example it is c:\tomcat\bin\win32\i386). 
+While creating this new virtual directory assign it with execute access.
+</li>
+<li>
+Using the IIS management console, add isapi_redirect.dll as a filter in your IIS/PWS web site. 
+The name of the filter should reflect its task (I use the name tomcat), 
+its executable must be our c:\tomcat\bin\win32\i386\isapi_redirect.dll. 
+For PWS, you'll need to use regedit and add/edit the <b>"Filter DLLs"</b> key under 
+<b>HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\W3SVC\Parameters</b>. 
+This key contains a "," separated list of dlls ( full paths ) - 
+you need to insert the full path to isapi_redirect.dll.
+</li>
+<li>
+Restart IIS (stop + start the IIS service), make sure that the tomcat filter is marked with a green up-pointing arrow.
+Under Win98 you may need to <b>cd WINDOWS\SYSTEM\inetsrv</b> and type PWS /stop 
+( the DLL and log files are locked - even if you click the stop button, 
+PWS will still keep the DLLs in memory. ). Type pws to start it again.
+</li>
+</ol>
+</p>
+<p>
+That's all, you should now start Tomcat and ask IIS to serve you the /examples context. 
+Try <a href="http://localhost/examples/jsp/index.html">http://localhost/examples/jsp/index.html</a> for example and 
+execute some of the JSP examples. 
+</p>
+<p>
+If this does not work successfully, refer to the Troubleshooting section below for help on correcting the problem.
+</p>
+
+<subsection name="Adding additional Contexts">
+<p>
+The examples context is useful for verifying your installation, 
+but you will also need to add your own contexts. Adding a new context requires two operations:
+</p>
+<p>
+<ol>
+<li>
+Adding the context to Tomcat (I am not going to talk about this).
+</li>
+<li>
+Adding the context to the ISAPI redirector.
+</li>
+</ol>
+</p>
+<p>
+Adding a context to the ISAPI redirector is simple, all you need to do is to edit 
+your uriworkermap.properties and to add a line that looks like:
+</p>
+
+<source>
+  /context/*=worker_name
+</source>
+
+<p>
+Workers and their name are defined in workers.properties, by default workers.properties comes 
+with a single pre-configured worker named <b>"defworker"</b> so you can use it. 
+As an example, if you want to add a context named "shop", the line that you should add to 
+uriworkermap.properties will be:
+</p>
+
+<source>
+  /shop/*=defworker
+</source>
+
+After saving uriworkermap.properties restart IIS and it will serve the new context.
+
+<p>
+A feature is present till Tomcat 3.2, where a uriworkermap.properties-auto is automatically 
+written each time Tomcat is started. This file includes settings for each of the contexts that 
+Tomcat will serve during its run. 
+</p>
+<p>
+Each context has settings to have Tomcat handle servlet and JSP requests, 
+but by default static content is left to be served by IIS. 
+</p>
+<p>
+Each context also has a commented out setting to have Tomcat handle all requests to the context. 
+You can rename this file (so it won't be overwritten the next time Tomcat is started) and 
+uncomment this setting or make other customizations. 
+</p>
+<p>
+You may also use this file as is in your worker_mount_file setting.
+</p>
+</subsection>
+
+<subsection name="Advanced Context Configuration">
+<p>
+Sometimes it is better to have IIS serve the static pages (html, gif, jpeg etc.) 
+even if these files are part of a context served by Tomcat. 
+</p>
+<p>
+For example, consider the html and gif files in the examples context, there is no need 
+to serve them from the Tomcat process, IIS will suffice.
+</p>
+
+<p>
+Making IIS serve static files that are part of the Tomcat contexts requires the following:
+<ol>
+<li>
+Configuring IIS to know about the Tomcat contexts
+</li>
+<li>
+Configuring the redirector to leave the static files for IIS
+</li>
+</ol>
+</p>
+
+<p>
+Adding a Tomcat context to IIS requires the addition of a new IIS virtual directory that covers the Tomcat context. 
+For example adding a /example IIS virtual directory that covers the c:\tomcat\webapps\examples directory.
+</p>
+
+<p>
+Configuring the redirector is somewhat harder, you will need to specify the exact 
+URL-Path pattern(s) that you want Tomcat to handle (usually only JSP files and servlets). 
+This requires a change to the uriworkermap.properties : 
+
+<source>
+  For the examples context it requires to replace the following line
+  /examples/*=defworker
+  with the following two lines
+  /examples/*.jsp=defworker
+  /examples/servlet/*=defworker
+</source>
+</p>
+
+<p>
+As you can see the second configuration is more explicit, it actually instruct the redirector 
+to redirect only requests to resources under /examples/servlet/ and resources under /examples/ 
+whose name ends with .jsp. 
+This is similar to what is automically written to the uriworkermap.properties-auto file for each context.
+</p>
+
+<p>
+You can even be more explicit and provide lines such as:
+
+<source>
+  /example/servletname=defworker
+</source>
+</p>
+
+<p>
+that instructs the redirector to redirect request whose URL-Path equals /example/servletname 
+to the worker named defworker.
+</p>
+
+</subsection>
+
+<subsection name="Protecting the WEB-INF Directory">
+<p>
+Each servlet application (context) has a special directory named WEB-INF, 
+this directory contains sensitive configurations data and Java classes and must be kept hidden from web users. 
+Using the IIS management console it is possible to protect the WEB-INF directory from user access, 
+this however requires the administrator to remember that. 
+</p>
+<p>
+To avoid this need the redirector plugin automatically protects your WEB-INF directories by rejecting 
+any request that contains WEB-INF in its URL-Path.
+</p>
+</subsection>
+
+<subsection name="Advanced Worker Configuration">
+<p>
+Sometimes you want to serve different contexts with different Tomcat processes 
+(for example to spread the load among different machines). 
+To achieve such goal you will need to define several workers and assign each context with its own worker.
+</p>
+<p>
+Defining workers is done in workers.properties, this file includes two types of entries:
+</p>
+
+<p>
+<source>
+  # An entry that lists all the workers defined
+  worker.list=worker1, worker2
+  # Entries that define the host and port associated with these workers
+  worker.worker1.host=localhost
+  worker.worker1.port=8009
+  worker.worker1.type=ajp13
+  worker.worker2.host=otherhost
+  worker.worker2.port=8009
+  worker.worker2.type=ajp13
+</source>
+</p>
+
+<p>
+The above example defined two workers, now we can use these workers to serve two different contexts 
+each with its own worker : 
+<source>
+  example uriworkermap.properties fragment
+  /examples/*=worker1
+  /webpages/*=worker2
+</source>>
+</p>
+
+<p>
+As you can see the <b>examples</b> context is served by <b>worker1</b> while the 
+<b>webpages</b> context is served by <b>worker2</b>.
+</p>
+
+<p>
+More informations on using and configuring workers in the <a href="workers.html">Workers HowTO</a>
+</p>
+
+</subsection>
+
+</section>
+
+<section name="Building ISAPI redirector">
+<p>
+The redirector was developed using Visual C++ Ver.6.0, so having this environment is a prereq if you want 
+to perform a custom build. You should also have IIS developer SDK
+
+The steps that you need to take are:
+<ul>
+<li>
+Change directory to the isapi plugins source directory.
+</li>
+<li>
+Make the source with MSDEV
+</li>
+</ul>
+<screen>
+<note>Change directory to the isapi plugins source directory</note>
+<typedos>cd c:\home\apache\jk\iis</typedos>
+<note>Build the sources using MSDEV</note>
+<typedos>MSDEV isapi.dsp /MAKE ALL</typedos>
+</screen>
+</p>
+<p>
+If msdev is not in your path, enter the full path to msdev.exe. 
+This will build both release and debug versions of the redirector plugin.
+An alternative will be to open the isapi workspace file (isapi.dsw) in msdev and 
+build it using the build menu.
+</p>
+</section>
+
+<section name="Troubleshooting">
+<p>
+It is easy to have the ISAPI redirector not work the first time you try to install it.
+</p>
+<p>
+If this happens to you, here are some steps to follow to try to correct the problem.
+</p>
+<p>
+These steps aren't guaranteed to cover all possible problems, 
+but they should help find the typical mistakes.
+</p>
+<p>
+If you make any corrections during these steps, restart the IIS service as described above in the last step 
+of the installation, then retry the step.
+</p>
+
+<p>To enable error tracking, make sure web site activity is being logged. 
+For PWS 4.0 make sure "Save Web Site Activity Log" is checked in the Advanced Options of the Personal Web Manager.
+</p>
+   
+<p>
+Note: These steps assume your <b>worker_mount_file</b> setting points to an unmodified copy of the 
+<b>uriworkermap.properties</b> file.<br/>
+Results may be misleading if <b>worker_mount_file</b> points to a modified <b>uriworkermap.properties</b>
+or the <b>uriworkermap.properties-auto</b> file.<br/>
+It is also assumed that the <b>"/examples" context</b> works correcly if you access Tomcat directly.
+</p>
+
+<subsection name="Win98">
+<p>
+Start the IIS service and Tomcat.
+</p>
+<p>
+Check for the presence of the ISAPI redirector log file you specified in the log_file setting. 
+If not found, verify the following:
+</p>
+<ul>
+<li>
+Check the "Filter DLLs" setting in the "HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\W3SVC\Parameters" 
+key and make sure the path is correct.
+</li>
+<li>
+Check the spelling of the "HKEY_LOCAL_MACHINE\SOFTWARE\Apache Software Foundation\Jakarta Isapi Redirector\1.0" key. 
+Case isn't important, but an incorrect letter will prevent the isapi_redirect.dll from finding its registry settings.
+</li>
+<li>
+Check the log_file setting for typos, name and data. Also insure the directory in which the log file will appear already exists.
+</li>
+If the above are set correctly, the ISAPI redirector should be able to create the log file.
+</ul>
+<p>
+Invoke the URL <a href="http://localhost/examples/jsp/index.html">http://localhost/examples/jsp/index.html</a>
+in your browser. 
+Case is important in Tomcat. The characters following "localhost" in the URL must be lower case. 
+If the page fails to appear, stop the IIS service (required to view the IIS log file). 
+Then examine the last line in the IIS log file in found in SYSTEM/LogFiles/W3SVC1 :
+</p>
+<p>
+If the last line contains: 
+</p>
+<source>
+  GET "/examples/jsp/index.html HTTP/1.1" 404
+</source>
+<p> 
+then the ISAPI redirector is not recognizing that it should be handling requests for the "/examples" context. 
+Check the following:
+</p>
+<ul>
+<li>
+Check the extension_uri name for typos.
+</li>
+<li>
+Check the worker_file setting for typos, name and data.
+</li>
+<li>
+Check the worker_mount_file setting typos, name and data.
+</li>
+If these are set correctly, the ISAPI redirector should recognize that it should handle requests for the "/examples" context.
+</ul>
+
+<p>If the last line contains something like:
+</p>
+
+<source>
+  GET "/jakarta/isapi_redirect.dll HTTP1.1"
+</source>
+
+<p>
+then the ISAPI redirector is recognizing that it should handle the request, 
+but is not successful at getting Tomcat to service the request.
+</p>
+
+<p>
+You should check the HTTP error code following GET "/..." :
+</p>
+
+<source>
+  Error 404
+  GET "/..." 404
+</source>
+
+<ul>
+<li>
+Make sure you entered the URL correctly.
+</li>
+<li>
+Make sure the virtual directory created was called "jakarta". 
+It should display in Personal Web Manager as "/jakarta" (without the quotes).
+</li>
+<li>
+Make sure the extension_uri data begins with "/jakarta/" (without the quotes).
+</li>
+</ul>
+
+<source>
+  Error 500
+  GET "/..." 500
+</source>
+
+<ul>
+<li>
+Make sure that "isapi_redirect.dll" follows "/jakarta/" in the extension_uri setting.
+</li>
+<li>
+Check the workers.properties file and make sure the port setting for worker.ajp12.port is the same as the port specified in the server.xml for the "Apache AJP12 support".
+</li>
+</ul>
+
+<source>
+  Error 200 or 403
+  GET "/..." 200
+  GET "/..." 403
+</source>
+
+<ul>
+<li>
+Make sure you have checked Execute Access 
+for the jakarta virtual directory in the Advanced Options of the Personal Web Manager.
+</li>
+</ul>
+
+<p>
+If the above settings are correct, the index.html page should appear in your browser. 
+You should also be able to click the Execute links to execute the JSP examples.
+</p>
+
+</subsection>
+
+<subsection name="WinNT/Win2K/WinXP">
+<p>
+Start the World Wide Web Publishing Service and Tomcat.
+</p>
+<p>
+Check for the presence of the ISAPI redirector log file you specified in the log_file setting. 
+If not found, check the following:
+</p>
+<ul>
+<li>
+Check the "executable" you set for the filter in the IIS Management Console and make sure the path is correct.
+</li>
+<li>Check the spelling of the "HKEY_LOCAL_MACHINE\SOFTWARE\Apache Software Foundation\Jakarta Isapi Redirector\1.0" key.
+Case isn't important, but an incorrect letter will prevent the isapi_redirect.dll from finding its registry settings.
+</li>
+<li>
+Check the log_file setting for typos, name and data. Also insure the directory in which the log file will appear already exists.
+</li>
+If the above are set correctly, the ISAPI redirector should be able to create the log file.
+</ul>
+
+<p>
+Check the tomcat filter you added and make sure its status shows a green upward-pointing arrow. 
+If not, check the following:
+</p>
+<ul>
+<li>
+Check the worker_file setting for typos, name and data.
+</li>
+<li>
+Check the worker_mount_file setting typos, name and data.
+</li>
+If the above are set correctly, the green upward-pointing arrow should appear, even if the other settings are wrong.
+</ul>
+
+<p>
+Invoke the URL <a href="http://localhost/examples/jsp/index.html">http://localhost/examples/jsp/index.html</a> 
+in your browser. Case is important in Tomcat. The characters following "localhost" in the URL must be lower case. 
+If the page fails to appear, examine the last line in the IIS server log file in found in SYSTEM32/LogFiles/W3SVC1.
+</p>
+
+<p>
+The last line should contain something like: GET "/jakarta/isapi_redirect.dll HTTP1.1", 
+which indicates the ISAPI redirector is recognizing that it should handle the request.
+</p>
+
+<p>
+You should check the HTTP error code following GET "/..." :
+</p>
+
+<source>
+  Error 404
+  GET "/..." 404
+</source>
+
+<ul>
+<li>
+Make sure you entered the URL correctly.
+</li>
+</ul>
+
+<source>
+  Error 500
+  GET "/..." 500
+</source>
+
+<ul>
+<li>
+Make sure the virtual directory created was called "jakarta".
+</li>
+<li>
+Make sure that the extension_uri setting is correct.
+</li>
+<li>
+Check the workers.properties file and make sure the port setting for worker.ajp12.port is the same as the port specified in the server.xml for the "Apache AJP12 support".
+</li>
+</ul>
+
+<source>
+  Error 200 or 403
+  GET "/..." 200
+  GET "/..." 403
+</source>
+
+<ul>
+<li>
+Make sure you have checked Execute Access for the jakarta virtual directory in the 
+Advanced Options of the Personal Web Manager.
+</li>
+</ul>
+
+<p>
+If the above settings are correct, the index.html page should appear in your browser. 
+You should also be able to click the Execute links to execute the JSP examples.
+</p>
+</subsection>
+
+
+</section>
+</body>
+</document>

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/howto/index.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/howto/index.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/howto/index.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,54 @@
+<?xml version="1.0"?>
+<!DOCTYPE document [
+  <!ENTITY project SYSTEM "project.xml">
+]>
+<document url="index.html">
+
+  &project;
+
+  <properties>
+    <author email="mturk at apache.org">Mladen Turk</author>
+    <title>HowTo Documentation index</title>
+  </properties>
+
+<body>
+
+<section name="Introduction">
+
+<p>This is the top-level entry point of the HowTo documentation bundle for the
+<strong>Apache Tomcat Connectors</strong>.
+
+</p>
+<p>Select one of the links from the navigation menu (to the left) to drill
+down to the more detailed documentation that is available.</p>
+
+</section>
+
+<!-- 
+<section name="Sticky Sessions">
+<p>
+TODO
+</p>
+</section>
+
+<section name="Failover">
+<p>
+TODO
+</p>
+</section>
+
+<section name="Domain Clustering">
+<p>
+TODO
+</p>
+</section>
+
+<section name="Hot Standby">
+<p>
+TODO
+</p>
+</section>
+-->
+
+</body>
+</document>

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/howto/loadbalancers.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/howto/loadbalancers.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/howto/loadbalancers.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!DOCTYPE document [
+  <!ENTITY project SYSTEM "project.xml">
+]>
+<document url="loadbalancers.html">
+
+  &project;
+<copyright>
+   Copyright 1999-2006 The Apache Software Foundation
+ 
+   Licensed 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.
+</copyright>
+<properties>
+<title>LoadBalancer HowTo</title>
+<author email="mturk at apache.org">Mladen Tur</author>
+<date>$Date: 2006-05-31 04:14:07 -0500 (Wed, 31 May 2006) $</date>
+</properties>
+<body>
+<section name="Introduction"> 
+<br/>
+<p>Load balancer is a virtual worker that does not really communicate with Tomcat workers.
+Instead it is responsible for the management of several "real" workers.
+The worker is supposed to be a load balancer if it's worker type is <b>lb</b>.
+See worker's <b>type</b> directive.
+<warn>The workers that are member of load balancer must not appear in the
+<b>worker.list</b> directive.</warn>
+</p>
+</section>
+
+</body>
+</document>

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/howto/nes.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/howto/nes.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/howto/nes.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,444 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!DOCTYPE document [
+  <!ENTITY project SYSTEM "project.xml">
+]>
+<document url="nes.html">
+
+  &project;
+<copyright>
+   Copyright 1999-2006 The Apache Software Foundation
+ 
+   Licensed 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.
+</copyright>
+<properties>
+<title>SunOne -- Netscape/iPlanet HowTo</title>
+<author email="hgomez at apache.org">Henri Gomez</author>
+<author email="shachor at il.ibm.com">Gal Shachor</author>
+<author email="mturk at apache.org">Mladen Turk</author>
+<date>$Date: 2006-06-28 18:56:49 -0500 (Wed, 28 Jun 2006) $</date>
+</properties>
+<body>
+<section name="Introduction">
+<p>
+This document explains how to set up Sun ONE Web Server previously known as
+Netscape web servers to cooperate with Tomcat. 
+</p>
+
+<p>
+Normally the Sun ONE Web Servers come with their own Servlet engine, 
+but you can also configure them to send servlet and JSP requests to Tomcat 
+using the NSAPI redirector plugin.
+</p>
+
+<p>
+It is recommanded that you also read the <a href="workers.html">Workers HowTo</a> document
+to learn how to setup the working entities between your WebServer and Tomcat Engines.
+</p>
+
+
+<subsection name="Document Conventions and Assumptions">
+<p>
+${tomcat_home} is the root directory of tomcat. 
+Your Tomcat installation should have the following subdirectories:
+
+<ul>
+<li>
+${tomcat_home}\conf - Where you can place various configuration files
+</li>
+<li>
+${tomcat_home}\webapps - Containing example applications
+</li>
+<li>
+${tomcat_home}\bin - Where you place web server plugins
+</li>
+</ul>
+</p>
+<p>
+In all the examples in this document ${tomcat_home} will be <b>c:\tomcat</b>.
+A worker is defined to be a tomcat process that accepts work from the Sun ONE Web Server.
+</p>
+</subsection>
+
+
+<subsection name="Supported Configuration">
+<p>
+The NSAPI-Tomcat redirector was developed and tested on:
+<ul>
+<li>
+WINNT 2000/XP/2003 (should be able to work with other service packs) and some Unixes
+</li>
+<li>
+Sun ONE Web Server 6.1
+</li>
+<li>
+Tomcat 4.1.x , Tomcat 5.0.x and Tomcat 5.5.x
+</li>
+</ul>
+</p>
+
+<p>
+The redirector uses <b>ajp12</b> and <b>ajp13</b> to send requests to the Tomcat containers. 
+There is also an option to use Tomcat in process, 
+more about the in-process mode can be found in the in process howto.
+</p>
+</subsection>
+
+<subsection name="Who support ajp protocols ?">
+<p>
+The ajp12 protocol is only available in Tomcat 3.2.x and 3.3.x.
+</p>
+
+<p>
+The <b>ajp12</b> has been <b>deprecated</b> with Tomcat 3.3.x and you should use instead 
+<b>ajp13</b> which is the only ajp protocol known by Tomcat 4.0.x, 4.1.x and 5.
+</p>
+
+<p>
+Of course Tomcat 3.2.x and 3.3.x also support ajp13 protocol.
+</p>
+
+<p>
+Others servlet engines such as <b>jetty</b> have support for ajp13 protocol
+</p>
+
+</subsection>
+
+
+<subsection name="How does it work ?">
+<p>
+<ol>
+<li>
+The NSAPI-Tomcat redirector is an Netscape service step plugin, 
+Netscape load the redirector plugin and calls its service handler 
+function for request that are assigned to the "servlet" configuration object.
+</li>
+<li>
+For each in-coming request Netscape will execute the set of NameTrans directives 
+that we added to obj.conf, the assign-name function will check if it's from 
+parameter matches the request URL.
+</li>
+<li>
+If a match is found, assign-name will assign the servlet object name to the request. 
+This will cause Netscape to send the request to the servlet configuration object.
+</li>
+<li>
+Netscape will execute our jk_service extension. The extension collects the 
+request parameters and forwards them to the appropriate worker using the ajp13 protocol 
+(the worker="defworker" parameter in jk_service inform it that the worker for this request is named <b>defworker</b>).
+the workers properties files, <b>workers.properties</b>, will indicate that defworker use ajp13 protocol.
+</li>
+<li>
+The extension collects the response from the worker and returns it to the browser.
+</li>
+</ol>
+</p>
+</subsection>
+
+</section>
+
+<section name="Installation">
+<p>
+A pre-built version of the NSAPI redirector, nsapi_redirect.dll, may be available under 
+the win32/i386 directory of tomcat-connectors distribution. 
+For those using Netscape as your browser, try downloading a zip version of the file, if available. 
+
+You can also build a copy locally from the source present in tomcat-connectors distribution.
+
+
+The Tomcat redirector requires two entities:
+<ul>
+<li>
+nsapi_redirect.dll - The NSAPI server plugin, either obtain a pre-built DLL or build it yourself 
+(see the build section).
+</li>
+<li>
+workers.properties - A file that describes the host(s) and port(s) used by the workers (Tomcat processes). 
+A sample workers.properties can be found under the conf directory.
+</li>
+</ul>
+
+The installation includes the following parts:
+
+<ul>
+<li>
+Configuring the NSAPI redirector with a default /examples context and checking that you can serve servlets 
+with Netscape.
+</li>
+<li>
+Adding more contexts to the configuration.
+</li>
+</ul>
+
+</p>
+</section>
+
+<section name="Configuring the NSAPI Redirector">
+<p>
+In this document we'll assume that nsapi_redirect.dll is placed in 
+<b>c:\jk\lib\nsapi_redirect.dll</b>, the properties file is in<b>c:\jk\conf</b>
+and you created a log directory <b>c:\jk\logs</b>
+</p>
+
+<ul>
+<li>
+If the built in servlet support is working disable it.
+</li>
+<li>
+Add the redirector plugin into the Netscape server configuration. 
+Edit your server <b>magnus.conf</b> and add the following lines:
+</li>
+</ul>
+
+<source>
+  
+  Init fn="load-modules" funcs="jk_init,jk_service" shlib="c:/jk/lib/nsapi_redirect.dll" shlib_flags="(global|now)"
+  Init fn="jk_init" worker_file="c:/jk/conf/workers.properties" log_level="debug" log_file="c:/jk/logs/nsapi.log"
+</source>
+<ul>
+<li>
+Edit your server <b>obj.conf</b> and add the following lines:
+</li>
+</ul>
+<source>
+
+  
+  In the default object NameTrans section
+  &lt;Object name="default"&gt;
+      
+  NameTrans fn="assign-name" from="/servlets-examples(|/*)" name="jknsapi" 
+  NameTrans fn="assign-name" from="/jsp-examples(|/*)" name="jknsapi"
+  ....
+  &lt;/Object&gt;
+  
+  Create a new configuration object by adding the following lines to the end of the obj.conf file
+  
+  &lt;Object name="jknsapi"&gt;
+    ObjectType fn=force-type type=text/plain
+    Service fn="jk_service" method="*" worker="worker1"
+  &lt;/Object&gt;
+</source>
+
+<ul>
+<li>
+Restart Web Server (stop and start the server)
+</li>
+</ul>
+
+<p>
+That's all, now you should start tomcat and ask for http://server:port/servlets-examples/
+</p>
+
+<subsection name="Adding additional Contexts">
+<p>
+The examples context is useful for verifying your installation, but you will also need to add your own contexts. 
+Adding a new context requires two operations:
+</p>
+<ul>
+<li>
+Adding the context to Tomcat (I am not going to talk about this).
+</li>
+<li>
+Assigning the NSAPI redirector to handle this context.
+</li>
+</ul>
+
+<p>
+Assigning the NSAPI redirector to handle this context is simple, 
+all you need to do is to edit <b>obj.conf</b> and add a NameTrans line that looks like:
+</p>
+
+<source>
+  NameTrans fn="assign-name" from="/&lt;context name&gt;/*" name="jknsapi"
+</source>
+
+<p>
+After saving <b>obj.conf</b> restart Netscape and it will serve the new context.
+</p>
+</subsection>
+
+<subsection name="Advanced Context Configuration">
+<p>
+Sometimes it is better to have Netscape serve the static pages (html, gif, jpeg etc.) 
+even if these files are part of a context served by Tomcat. For example, consider the html and gif files in the examples context, there is no need to serve them from the Tomcat process, Netscape will suffice.
+</p>
+<p>
+Making Netscape serve static files that are part of the Tomcat contexts requires the following:
+</p>
+<ul>
+<li>
+Configuring Netscape to know about the Tomcat contexts
+</li>
+<li>
+Make sure that the WEB-INF directory is protected from access.
+</li>
+<li>
+Configuring Netscape to assign the NSAPI redirector only specific requests that requires JSP/Servlet handling.
+</li>
+</ul>
+
+<p>
+Adding a Tomcat context to Netscape requires the addition of a new Netscape virtual directory 
+that covers the Tomcat context.
+</p>
+
+<p>
+For example, adding a /example Netscape virtual directory that 
+covers the <b>c:\tomcat\webapps\examples</b> directory. 
+</p>
+
+<p>
+To add a new virtual directory add the following line to your <b>obj.conf</b>:
+</p>
+
+<source>
+  NameTrans fn=pfx2dir from=/examples dir="c:/tomcat/webapps/examples"
+</source>
+
+<p>
+WEB-INF protection requires some explanation; Each servlet application (context) has a special directory named <b>WEB-INF</b>,
+this directory contains sensitive configurations data and Java classes and must be kept hidden from web users. 
+WEB-INF can be protected by adding the following line to the PathCheck section in the default configuration object:
+</p>
+
+<source>
+  PathCheck fn="deny-existence" path="*/WEB-INF/*"
+  
+  This line instructs the Netscape server to reject any request with a URL that contain the path /WEB-INF/.
+</source>
+
+<p>
+Configuring Netscape to assign the NSAPI redirector only specific requests is somewhat harder, 
+you will need to specify the exact URL-Path pattern(s) that you want Tomcat to handle 
+(usually only JSP files and servlets). 
+</p>
+
+<p>
+This requires a change to NemaTrans portion of <b>obj.conf</b>. 
+</p>
+
+<source>
+  For the examples context it requires to replace the following line:
+  
+  NameTrans fn="assign-name" from="/examples/*" name="jknsapi"
+  
+  with the following two lines:
+  
+  NameTrans fn="assign-name" from="/examples/jsp/*.jsp" name="jknsapi"
+  NameTrans fn="assign-name" from="/examples/servlet/*" name="jknsapi"
+</source>
+
+<p>
+As you can see the second configuration is more explicit, it actually instructs 
+Netscape to assign the redirector with only requests to resources under 
+<b>/examples/servlet/</b> and resources under <b>/examples/</b> whose name ends with <b>.jsp</b>.
+</p>
+
+<p>
+You can be even more explicit and provide lines such as:
+</p>
+
+<source>
+  NameTrans fn="assign-name" from="/examples/servletname" name="jknsapi"
+  
+  Instructs Netscape to assign the redirector request whose URL-Path equals /example/servletname
+</source>
+
+</subsection>
+
+<subsection name="Advanced Worker Configuration">
+<p>
+Sometimes you want to serve different contexts with different Tomcat processes 
+(for example to spread the load among different machines). 
+To achieve such goal you will need to define several workers and assign each context with its own worker.
+</p>
+
+<p>
+Defining workers is done in <b>workers.properties</b>, this file includes two types of entries:
+</p>
+
+<source>
+  #An entry that lists all the workers defined. For example:
+  worker.list=worker1,worker2
+  
+  # Entries that define the host and port associated with these workers.
+  worker.worker1.host=localhost
+  worker.worker1.port=8009
+  worker.worker1.type=ajp13
+
+  worker.worker2.host=otherhost
+  worker.worker2.port=8009
+  worker.worker2.type=ajp13
+</source>
+
+<p>
+The above examples defined two workers, now we can use these workers to serve two different 
+contexts each with it’s own worker. 
+Submitting requests to different workers is accomplished by using multiple Service directives 
+in the servlet configuration Object, each with a different path pattern parameter. 
+</p>
+
+<p>
+For example, if we want to submit the <b>/examples</b> context to the worker named <b>worker1</b> and the 
+<b>/webpages</b> context to the worker named <b>worker2</b> we should use the following configuration:
+</p>
+
+<source>
+  &lt;Object name="jknsapi"&gt;
+    ObjectType fn=force-type type=text/plain
+    Service fn="jk_service" worker="worker1" path="/examples/*"
+    Service fn="jk_service" worker="worker2" path="/webpages/*"
+    Service fn="jk_service" worker="worker1"
+  &lt;/Object&gt;
+</source>
+
+<p>
+More informations on using and configuring workers in the <a href="workers.html">Workers HowTO</a>
+</p>
+</subsection>
+
+</section>
+
+<section name="Building NSAPI redirector">
+<p>
+The redirector was developed using Visual C++ Ver.6.0, so having this environment is a prereq if you want 
+to perform a custom build. You should also have NES developer SDK
+
+The steps that you need to take are:
+<ul>
+<li>
+Change directory to the nsapi plugins source directory.
+</li>
+<li>
+Edit <b>nsapi.dsp</b> and update the include and library path to reflect your own Netscape server installation 
+(search for a <b>/I compiler</b> option and <b>/libpath</b> linker option)
+</li>
+<li>
+Make the source with MSDEV
+</li>
+</ul>
+<screendos>
+<notedos>Change directory to the nsapi plugins source directory</notedos>
+<typedos>cd c:\home\apache\jk\nsapi</typedos>
+<notedos>Build the sources using MSDEV</notedos>
+<typedos>MSDEV nsapi.dsp /MAKE ALL</typedos>
+</screendos>
+</p>
+<p>
+If msdev is not in your path, enter the full path to msdev.exe. 
+This will build both release and debug versions of the redirector plugin.
+An alternative will be to open the nsapi workspace file (nsapi.dsw) in msdev and 
+build it using the build menu.
+</p>
+</section>
+</body>
+</document>

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/howto/project.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/howto/project.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/howto/project.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<project name="Application Developer's Guide"
+        href="http://tomcat.apache.org/">
+
+    <title>Tomcat Connector</title>
+
+    <logo href="/images/tomcat.gif">
+    Tomcat Connector
+    </logo>    
+<body>
+
+    <menu name="Links">
+        <item name="Docs Home"                  href="../index.html"/>
+    </menu>
+    <menu name="Generic Howto">
+        <item name="For the impatient"          href="quick.html"/>
+        <item name="All about workers"          href="workers.html"/>
+        <item name="Load Balancing"             href="loadbalancers.html"/>
+    </menu>
+    <menu name="Webservers">
+        <item name="Apache"                     href="apache.html"/>
+        <item name="IIS"                        href="iis.html"/>
+        <item name="Domino"                     href="domino.html"/>
+        <item name="SunOne (Netscape)"          href="nes.html"/>
+    </menu>
+    <menu name="Get Involved">
+        <item name="Contribute documentation"    href="doccontrib.html"/>
+    </menu>
+    
+</body>
+</project>

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/howto/quick.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/howto/quick.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/howto/quick.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,184 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!DOCTYPE document [
+  <!ENTITY project SYSTEM "project.xml">
+]>
+<document url="quick.html">
+
+  &project;
+<copyright>
+   Copyright 1999-2006 The Apache Software Foundation
+ 
+   Licensed 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.
+</copyright>
+<properties>
+<title>Quick Start HowTo</title>
+<author email="hgomez at apache.org">Henri Gomez</author>
+<date>$Date: 2006-06-28 18:56:49 -0500 (Wed, 28 Jun 2006) $</date>
+</properties>
+<body>
+<section name="Introduction">
+<p>
+  This document describes the configuration files used by JK on the
+  Web Server side for the 'impatients':
+    <ul>
+    <li>
+    <b>workers.properties</b> is a mandatory file used by the webserver and which
+    is the same for all JK implementations (Apache/IIS/NES).
+    </li>
+    <li>
+    <b>WebServers</b> add-ons to be set on the webserver side. 
+    </li>
+    </ul>
+</p>
+<p>        
+  We'll give here minimum servers configuration and an example <b>workers.properties</b> 
+  to be able to install and check quickly your configuration.
+</p>
+</section>
+
+<section name="Minimum workers.properties">
+<p>
+    Here is a minimum <b>workers.properties</b>, using just ajp13 to connect your Apache webserver
+    to the Tomcat engine, complete documentation is available in <a href="workers.html">Workers HowTo</a>. 
+</p>
+<p>
+<source>
+
+  # Define 1 real worker using ajp13
+  worker.list=worker1
+  # Set properties for worker1 (ajp13)
+  worker.worker1.type=ajp13
+  worker.worker1.host=localhost
+  worker.worker1.port=8009
+  worker.worker1.lbfactor=50
+  worker.worker1.cachesize=10
+  worker.worker1.cache_timeout=600
+  worker.worker1.socket_keepalive=1
+  worker.worker1.recycle_timeout=300
+
+</source>
+</p>
+</section>
+
+<section name="Minimum Apache WebServer configuration">
+<p>
+   Here is a minimun informations about Apache configuration, a 
+   complete documentation is available in <a href="apache.html">Apache HowTo</a>.
+</p>
+<p>
+	You should first have <b>mod_jk.so</b> (unix) or <b>mod_jk.dll</b> (Windows) installed
+	in your Apache module directory (see your Apache documentation to locate it).
+</p>
+<p>
+	Usual locations for modules directory on Unix:
+	<ul>
+	<li>/usr/lib/apache/</li>
+	<li>/usr/lib/apache2/</li>
+	<li>/usr/local/apache/libexec/</li>
+	</ul>
+</p>
+<p>
+	Usual locations for modules directory on Windows :
+	<ul>
+	<li>C:\Program Files\Apache Group\Apache\modules\</li>
+	<li>C:\Program Files\Apache Group\Apache2\modules\</li>
+	</ul>
+</p>
+<p>
+	You'll find a link to prebuilt binaries
+        <a href="http://tomcat.apache.org/download-connectors.cgi/">here</a>
+</p>
+<p>
+    Here is the minimum which should be set in <b>httpd.conf</b> directly or 
+    included from another file:
+</p>    
+<p>
+	Usual locations for configuration directory on Unix:
+	<ul>
+	<li>/etc/httpd/conf/</li>
+	<li>/etc/httpd2/conf/</li>
+	<li>/usr/local/apache/conf/</li>
+	</ul>
+</p>
+<p>
+	Usual locations for configuration directory on Windows :
+	<ul>
+	<li>C:\Program Files\Apache Group\Apache\conf\</li>
+	<li>C:\Program Files\Apache Group\Apache2\conf\</li>
+	</ul>
+</p>
+<p>
+<source>
+
+  # Load mod_jk module
+  # Update this path to match your modules location
+  LoadModule    jk_module  libexec/mod_jk.so
+  # Declare the module for &lt;IfModule directive&gt; (remove this line on Apache 2.x)
+  AddModule     mod_jk.c
+  # Where to find workers.properties
+  # Update this path to match your conf directory location (put workers.properties next to httpd.conf)
+  JkWorkersFile /etc/httpd/conf/workers.properties
+  # Where to put jk logs
+  # Update this path to match your logs directory location (put mod_jk.log next to access_log)
+  JkLogFile     /var/log/httpd/mod_jk.log
+  # Set the jk log level [debug/error/info]
+  JkLogLevel    info
+  # Select the log format
+  JkLogStampFormat "[%a %b %d %H:%M:%S %Y] "
+  # JkOptions indicate to send SSL KEY SIZE, 
+  JkOptions     +ForwardKeySize +ForwardURICompat -ForwardDirectories
+  # JkRequestLogFormat set the request format 
+  JkRequestLogFormat     "%w %V %T"
+  # Send everything for context /examples to worker named worker1 (ajp13)
+  JkMount  /examples/* worker1
+
+</source>
+</p>
+</section>
+
+<section name="Minimum Domino WebServer configuration">
+<p>
+	A complete documentation is available in <a href="domino.html">Domino HowTo</a>.
+<todo>
+More informations to be added!
+</todo>
+</p>
+</section>
+
+<section name="Minimum IIS WebServer configuration">
+<p>
+	A complete documentation is available in <a href="iis.html">IIS HowTo</a>.
+</p>
+<todo>
+More informations to be added!
+</todo>
+</section>
+
+<section name="Minimum NES/iPlanet WebServer configuration">
+<p>
+	A complete documentation is available in <a href="nes.html">Netscape/iPlanet HowTo</a>.
+<todo>
+More informations to be added?
+</todo>
+</p>
+</section>
+
+
+<section name="Test your configuration">
+<p>
+	(Re)start the Web server and browse to the <a href="http://localhost/examples/">http://localhost/examples/</a>
+</p>
+
+</section>
+</body>
+</document>

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/howto/workers.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/howto/workers.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/howto/workers.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,515 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!DOCTYPE document [
+  <!ENTITY project SYSTEM "project.xml">
+]>
+<document url="workers.html">
+
+  &project;
+<copyright>
+   Copyright 1999-2006 The Apache Software Foundation
+ 
+   Licensed 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.
+</copyright>
+<properties>
+<title>Workers HowTo</title>
+<author email="hgomez at apache.org">Henri Gomez</author>
+<author email="shachor at il.ibm.com">Gal Shachor</author>
+<author email="mturk at apache.org">Mladen Tur</author>
+<date>$Date: 2006-09-03 13:55:19 -0500 (Sun, 03 Sep 2006) $</date>
+</properties>
+<body>
+<section name="Introduction">
+<p>
+A Tomcat worker is a Tomcat instance that is waiting to execute servlets on behalf of some web server. 
+For example, we can have a web server such as Apache forwarding servlet requests to a 
+Tomcat process (the worker) running behind it.
+</p>
+<p>
+The scenario described above is a very simple one; 
+in fact one can configure multiple Tomcat workers to serve servlets on 
+behalf of a certain web server. 
+The reasons for such configuration can be:
+</p>
+<ul>
+<li>
+We want different contexts to be served by different Tomcat workers to provide a 
+development environment where all the developers share the same web server but own a Tomcat worker of their own.
+</li>
+<li>
+We want different virtual hosts served by different Tomcat processes to provide a 
+clear separation between sites belonging to different companies.
+</li>
+<li>
+We want to provide load balancing, meaning run multiple Tomcat workers each on a 
+machine of its own and distribute the requests between them.
+</li>
+</ul>
+
+<p>
+There are probably more reasons for having multiple workers but I guess that this list is enough...
+Tomcat workers are defined in a properties file dubbed workers.properties and this tutorial 
+explains how to work with it.
+</p>
+
+<p>
+This document was originally part of <b>Tomcat: A Minimalistic User's Guide</b> written by Gal Shachor, 
+but has been split off for organizational reasons. 
+</p>
+</section>
+
+<section name="Defining Workers">
+<p>
+Defining workers to the Tomcat web server plugin can be done using a properties file 
+(a sample file named workers.properties is available in the conf/ directory).
+</p>
+
+<p>
+the file contains entries of the following form:
+</p>
+
+<p>
+<b>worker.list</b>=&lt;a comma separated list of worker names&gt;
+</p>
+
+<source>
+  # the list of workers
+  worker.list= worker1, worker2
+</source>
+
+<p>
+When starting up, the web server plugin will instantiate the workers whose name appears in the 
+<b>worker.list</b> property, these are also the workers to whom you can map requests. The directive can be used multiple times.
+</p>
+
+<subsection name="Workers Type">
+<p>
+Each named worker should also have a few entries to provide additional information on his behalf.
+This information includes the worker's type and other related worker information. 
+Currently the following worker types that exists are (JK 1.2.5):
+</p>
+
+<table>
+  <tr><th>Type</th><th>Description</th></tr>
+  <tr><td>ajp12</td><td>This worker knows how to forward requests to out-of-process Tomcat workers using the ajpv12 protocol.</td></tr>
+  <tr><td>ajp13</td><td>This worker knows how to forward requests to out-of-process Tomcat workers using the ajpv13 protocol.</td></tr>
+  <tr><td>jni</td><td>This worker knows how to forward requests to in-process Tomcat workers using JNI.</td></tr>
+  <tr><td>lb</td><td>This is a load-balancing worker; it knows how to provide round-robin based sticky load balancing with a certain level of fault-tolerance.</td></tr>
+  <tr><td>status</td><td>This is a status worker for managing load balancers.</td></tr>
+</table>
+
+<p>
+Defining workers of a certain type should be done with the following property format:
+</p>
+
+<p>
+<b>worker</b>. <b>worker name</b>.<b>type</b>=&lt;worker type&gt;
+Where worker name is the name assigned to the worker and the worker type is one of the four types defined 
+in the table (a worker name may not contain any space (a good naming convention for queue named should 
+follow the Java variable naming rules).
+</p>
+
+<source>
+  # Defines a worker named "local" that uses the ajpv12 protocol to forward requests to a Tomcat process.
+  worker.local.type=ajp12
+  # Defines a worker named "remote" that uses the ajpv13 protocol to forward requests to a Tomcat process.
+  worker.remote.type=ajp13
+  # Defines a worker named "fast" that uses JNI to forward requests to a Tomcat process.
+  worker.fast.type=jni
+  # Defines a worker named "loadbalancer" that loadbalances several Tomcat processes transparently.
+  worker.loadbalancer.type=lb
+</source>
+
+</subsection>
+
+</section>
+
+<section name="Setting Worker Properties">
+<p>
+After defining the workers you can also specify properties for them. 
+Properties can be specified in the following manner:
+</p>
+
+<p>
+worker.&lt;worker name&gt;.&lt;property&gt;=&lt;property value&gt;
+</p>
+
+Each worker has a set of properties that you can set as specified in the following subsections:
+
+<subsection name="ajp12 Worker properties">
+<p><warn>
+The <b>ajp12</b> has been <b>deprecated</b> with Tomcat 3.3.x and you should use instead 
+<b>ajp13</b> which is the only ajp protocol known by Tomcat 4.x and 5.
+</warn></p> 
+<p>
+The ajp12 typed workers forward requests to out-of-process Tomcat workers 
+using the ajpv12 protocol over TCP/IP sockets.
+</p>
+
+<p>
+the ajp12 worker properties are :
+</p>
+
+<p>
+<b>host</b> property set the host where the Tomcat worker is listening for ajp12 requests.
+</p>
+
+<p>
+<b>port</b> property set The port where the Tomcat worker is listening for ajp12 requests
+</p>
+
+<p>
+<b>lbfactor</b>property is used when working with a load balancer worker, this is the load-balancing factor for the worker.
+We'll see more on this in the lb worker section.
+</p>
+
+<source>
+  # worker "worker1" will talk to Tomcat listening on machine www.x.com at port 8007 using 2 lb factor
+  worker.worker1.host=www.x.com
+  worker.worker1.port=8007
+  worker.worker1.lbfactor=2
+</source>
+
+<p>
+Notes: In the ajpv12 protocol, connections are created, used and then closed at each request.
+The default port for ajp12 is 8007
+</p>
+
+</subsection>
+
+<subsection name="ajp13 Worker properties">
+<p>
+The ajp13 typed workers forward requests to out-of-process Tomcat workers using the ajpv13 protocol over TCP/IP sockets.
+The main difference between ajpv12 and ajpv13 are that:
+<ul>
+<li>
+ajpv13 is a more binary protocol and it try to compress some of the request data by coding 
+frequently used strings as small integers.
+</li>
+<li>
+ajpv13 reuse open sockets and leaves them open for future requests (remember when you've got a Firewall between your 
+WebServer and Tomcat).
+</li>
+<li>
+ajpv13 has special treatment for SSL information so that the container can implement 
+SSL related methods such as isSecure().
+</li>
+</ul>
+
+</p>
+
+<p>
+You should note that Ajp13 is now the only out-process protocol supported by Tomcat 4.0.x, 4.1.x and 5.
+</p>
+
+
+<source>
+  # worker "worker2" will talk to Tomcat listening on machine www2.x.com at port 8009 using 3 lb factor
+  worker.worker2.host=www2.x.com
+  worker.worker2.port=8009
+  worker.worker2.lbfactor=3
+  # worker "worker2" use up to 10 sockets, which will stay no more than 10mn in the connection pool
+  worker.worker2.connection_pool_size=10
+  worker.worker2.connection_pool_timeout=600
+  # worker "worker2" ask operating system to send KEEP-ALIVE signal on the connection
+  worker.worker2.socket_keepalive=1
+  # mount can be used as an alternative to the JkMount directive
+  worker.worker2.mount=/contexta /contexta/* /contextb /contextb/*
+</source>
+
+<p>
+Notes: In the ajpv13 protocol, the default port is 8009
+</p>
+
+</subsection>
+
+<subsection name="lb Worker properties">
+<p>
+The load-balancing worker does not really communicate with Tomcat workers.
+Instead it is responsible for the management of several "real" workers. 
+This management includes:
+</p>
+
+<ul>
+<li>
+Instantiating the workers in the web server.
+</li>
+<li>
+Using the worker's load-balancing factor, perform weighed-round-robin load balancing where 
+high lbfactor means stronger machine (that is going to handle more requests)
+</li>
+<li>
+Keeping requests belonging to the same session executing on the same Tomcat worker.
+</li>
+<li>
+Identifying failed Tomcat workers, suspending requests to them and instead fall-backing on 
+other workers managed by the lb worker.
+</li>
+</ul>
+
+<p>
+The overall result is that workers managed by the same lb worker are load-balanced (based on their lbfactor and current user session) and also fall-backed so a single Tomcat process death will not "kill" the entire site.
+The following table specifies properties that the lb worker can accept:
+<ul>
+<li><b>balance_workers</b> is a comma separated list of workers that the load balancer need to manage. 
+These workers should not appear in the worker.list property. This directive can be used multiple times for the same load balancer.</li>
+<li><b>sticky_session</b> specifies whether requests with SESSION ID's should be routed back to the same
+Tomcat worker. If sticky_session is an flag and if it is set to True and sessions are sticky, otherwise
+sticky_session is set to false. Set sticky_session to False when Tomcat is using a Session Manager which
+can persist session data across multiple instances of Tomcat. By default sticky_session is set to True.</li>
+</ul>
+</p>
+
+<source>
+   The worker balance1 while use "real" workers worker1 and worker2
+  worker.balance1.balance_workers=worker1, worker2
+</source>
+
+</subsection>
+
+<subsection name="Advanced lb Worker properties">
+<p>
+With JK 1.2.x, new load-balancing and fault-tolerant support has been added via
+2 new properties, <b>redirect</b> and <b>activation</b>.
+</p>
+
+<p>
+Let's take an example environment:
+</p>
+
+<p>
+A cluster with two nodes (worker1+worker2), running a webserver + tomcat tandem on each node and 
+a loadbalancer in front of the nodes.
+</p>
+
+<source>
+  # The advanced router LB worker
+  worker.list=router
+
+  # Define a worker using ajp13
+  worker.worker1.port=8009
+  worker.worker1.host=node1.domain.org
+  worker.worker1.type=ajp13
+  worker.worker1.lbfactor=1
+  # Define prefered failover node for worker1
+  worker.worker1.redirect=worker2
+
+  # Define another worker using ajp13
+  worker.worker2.port=8009
+  worker.worker2.host=node2.domain.org
+  worker.worker2.type=ajp13
+  worker.worker2.lbfactor=1
+  # Disable worker2 for all requests except failover
+  worker.worker2.activation=disabled
+  
+  # Define the LB worker
+  worker.router.type=lb
+  worker.router.balance_workers=worker1,worker2
+</source>
+
+<p>
+The <b>redirect</b> flag on worker1 tells the <b>lb_worker</b> to redirect the requests
+to worker2 only if worker1 is in error state. In other cases worker2 will not receive
+any requests, thus acting like a hot standby.
+</p>
+
+
+</subsection>
+
+<subsection name="Status Worker properties">
+<p>
+The status worker does not communicate with Tomcat.
+Instead it is responsible for the load balancer management. 
+</p>
+<source>
+  # Add the status worker to the worker list
+  worker.list=jkstatus
+  # Define a 'jkstatus' worker using status
+  worker.jkstatus.type=status
+</source>
+<p>Next thing is to mount the requests to the jkstatus worker. For Apache
+web servers use the:</p>
+<source>
+  # Add the jkstatus mount point
+  JkMount /jkmanager/* jkstatus 
+</source>
+<p>To obtain a higher level of security use the:</p>
+<source>
+  # Enable the JK manager access from localhost only
+ &lt;Location /jkmanager/&gt;
+    JkMount jkstatus
+    Order deny,allow
+    Deny from all
+    Allow from 127.0.0.1
+ &lt;/Location&gt;
+</source>
+
+</subsection>
+
+<subsection name="Property file macros">
+<p>
+You can define "macros" in the property files. 
+These macros let you define properties and later on use them while 
+constructing other properties and it's very usefull when you want to
+change your Java Home, Tomcat Home or OS path separator
+</p>
+
+<source>
+  # property example, don't hardcode path separator
+  ps=\
+  workers.tomcat_home=d:\tomcat
+  workers.java_home=d:\sdk\jdk1.2.2
+  # Using macros we'll have : worker.inprocess.class_path=d:\tomcat\classes
+  worker.inprocess.class_path=$(workers.tomcat_home)$(ps)classes
+  # Using macros we'll have : worker.inprocess.class_path=d:\sdk\jdk1.2.2\lib\tools.jar
+  worker.inprocess.class_path=$(workers.java_home)$(ps)lib$(ps)tools.jar
+</source>
+
+</subsection>
+
+<subsection name="Hierarchical property configuration">
+<p>
+Workers can reference configurations of other workers.
+If worker "x" references worker "y", then it inherits all
+configuration parameters from "y", except for the ones
+that have explicitely been set for "x".
+</p>
+
+<source>
+  # worker toe defines some default settings
+  worker.toe.type=ajp13
+  worker.toe.socket_keepalive=true
+  worker.toe.connect_timeout=10000
+  worker.toe.recovery_options=7
+  # workers tic and tac inherit those values
+  worker.tic.reference=worker.toe
+  worker.tac.reference=worker.toe
+</source>
+
+<p>
+Please note, that the reference contains
+the full prefix to the referenced configuration attributes,
+not only the name of the referenced worker.
+</p>
+
+<p>
+References can be nested. Be careful to avoid loops!
+</p>
+
+<p>
+References are especially useful, when configuring load balancers.
+Try to understand the following two stage references:
+</p>
+
+<source>
+  # We only use one load balancer
+  worker.list=lb
+  # Let's define some defaults
+  worker.basic.port=8009
+  worker.basic.type=ajp13
+  worker.basic.socket_keepalive=true
+  worker.basic.connect_timeout=10000
+  worker.basic.recovery_options=7
+  # And we use them in two groups
+  worker.lb1.domain=dom1
+  worker.lb1.distance=0
+  worker.lb1.reference=worker.basic
+  worker.lb2.domain=dom2
+  worker.lb2.distance=1
+  worker.lb2.reference=worker.basic
+  # Now we configure the load balancer
+  worker.lb.type=lb
+  worker.lb.method=B
+  worker.lb.balanced_workers=w11,w12,w21,w22
+  worker.w11.host=myhost11
+  worker.w11.reference=worker.lb1
+  worker.w12.host=myhost12
+  worker.w12.reference=worker.lb1
+  worker.w21.host=myhost21
+  worker.w21.reference=worker.lb2
+  worker.w22.host=myhost22
+  worker.w22.reference=worker.lb2
+</source>
+
+</subsection>
+
+</section>
+
+<section name="A sample worker.properties">
+<p>
+Since coping with worker.properties on your own is not an easy thing to do, 
+a sample worker.properties file is bundled along JK. 
+</p>
+
+<p>
+You could also find here a sample workers.properties defining :
+</p>
+
+<ul>
+<li>
+An ajp12 worker that used the host localhost and the port 8007
+</li>
+<li>
+An ajp13 worker that used the host localhost and the port 8008
+</li>
+<li>
+A jni worker
+</li>
+<li>
+A lb worker that load balance the ajp12 and ajp13 workers
+</li>
+</ul>
+
+<source>
+  # Define some properties
+  workers.apache_log=/var/log/httpd/
+  workers.tomcat_home=/var/tomcat3
+  workers.java_home=/opt/IBMJava2-131/
+  ps=/
+  # Define 4 workers, 3 real workers using ajp12, ajp13, jni, the last one being a loadbalancing worker 
+  worker.list=worker1, worker2, worker3, worker4
+  # Set properties for worker1 (ajp12)
+  worker.worker1.type=ajp12
+  worker.worker1.host=locahost
+  worker.worker1.port=8007
+  worker.worker1.lbfactor=1
+  # Set properties for worker2 (ajp13)
+  worker.worker2.type=ajp13
+  worker.worker2.host=locahost
+  worker.worker2.port=8009
+  worker.worker2.lbfactor=1
+  worker.worker2.connection_pool_size=10
+  worker.worker2.connection_pool_timeout=600
+  worker.worker2.socket_keepalive=1
+  worker.worker2.socket_timeout=60
+  # Set properties for worker3 (jni)
+  worker.worker3.type=jni
+  # Set worker3 bridge type, here Tomcat 3.3
+  worker.worker3.bridge=tomcat33
+  # Set worker3 classpath
+  worker.worker3.class_path=$(workers.tomcat_home)$(ps)classes
+  worker.worker3.class_path=$(workers.tomcat_home)$(ps)lib$(ps)tomcat.jar
+  # Set worker3 tomcat command line
+  worker.worker3.cmd_line=-home
+  worker.worker3.cmd_line=$(workers.tomcat_home)
+  # Set worker3 Tomcat/JVM settings
+  worker.worker3.jvm_lib=$(workers.java_home)$(ps)jre$(ps)bin$(ps)classic$(ps)libjvm.so
+  worker.worker3.stdout=$(workers.apache_log)$(ps)inprocess.stdout
+  worker.worker3.stderr=$(workers.apache_log)$(ps)inprocess.stderr
+  worker.worker3.sysprops=tomcat.home=$(workers.tomcat_home)
+  # Set properties for worker4 (lb) which use worker1 and worker2
+  worker.worker4.balance_workers=worker1,worker2
+</source>
+
+</section>
+</body>
+</document>

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/images/add.gif
===================================================================
(Binary files differ)


Property changes on: branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/images/add.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/images/code.gif
===================================================================
(Binary files differ)


Property changes on: branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/images/code.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/images/design.gif
===================================================================
(Binary files differ)


Property changes on: branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/images/design.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/images/docs.gif
===================================================================
(Binary files differ)


Property changes on: branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/images/docs.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/images/fix.gif
===================================================================
(Binary files differ)


Property changes on: branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/images/fix.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/images/jakarta-logo.gif
===================================================================
(Binary files differ)


Property changes on: branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/images/jakarta-logo.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/images/printer.gif
===================================================================
(Binary files differ)


Property changes on: branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/images/printer.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/images/tomcat.gif
===================================================================
(Binary files differ)


Property changes on: branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/images/tomcat.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/images/update.gif
===================================================================
(Binary files differ)


Property changes on: branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/images/update.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/images/void.gif
===================================================================
(Binary files differ)


Property changes on: branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/images/void.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/index.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/index.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/index.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,282 @@
+<?xml version="1.0"?>
+<!DOCTYPE document [
+  <!ENTITY project SYSTEM "project.xml">
+]>
+<document url="index.html">
+
+  &project;
+
+  <properties>
+    <author email="mturk at apache.org">Mladen Turk</author>
+    <title>Documentation Index</title>
+  </properties>
+
+<body>
+
+<section name="Introduction">
+
+<p>This is the top-level entry point of the documentation bundle for the
+<strong>Apache Tomcat Connectors</strong> 
+
+</p>
+<p>Select one of the links from the navigation menu (to the left) to drill
+down to the more detailed documentation that is available.  Each available
+manual is described in more detail below.</p>
+
+</section>
+
+<section name="Headlines">
+<br />
+<ul>
+<li><a href="news/20060101.html#20060720.1">27 July 2006 - <b>JK-1.2.18 released</b></a>
+<p>The Apache Tomcat team is proud to announce the immediate availability
+of Tomcat Connectors 1.2.18 Stable.
+</p>
+<p>Download the <a href="http://www.apache.org/dist/tomcat/tomcat-connectors/jk/source/jk-1.2.18/tomcat-connectors-1.2.18-src.tar.gz">JK 1.2.18 release sources</a>
+ | <a href="http://www.apache.org/dist/tomcat/tomcat-connectors/jk/source/jk-1.2.18/tomcat-connectors-1.2.18-src.tar.gz.asc">PGP signature</a>
+</p>
+<p>Download the <a href="http://www.apache.org/dist/tomcat/tomcat-connectors/jk/binaries/">binaries</a> for selected platforms.
+</p>
+</li>
+
+<li><a href="news/20060101.html#20060708.1"><b>JK-1.2.17 not released</b></a>
+<p>Version 1.2.17 of Tomcat Connectors has not been released due to a bug in socket function argument types.
+</p>
+<p>Thanks to all testers for their feedback. All reported new errors have been fixed in Version 1.2.18.
+</p>
+</li>
+
+<li><a href="news/20060101.html#20060629.1"><b>JK-1.2.16 not released</b></a>
+<p>Version 1.2.16 of Tomcat Connectors has not been released due to a bug in the jk status worker.
+</p>
+<p>Thanks to all testers for their feedback. All reported new errors have been fixed in Version 1.2.17.
+</p>
+</li>
+
+<li><a href="news/20050101.html#20051108.1">8 November 2005 - <b>JK-1.2.15 released</b></a>
+<p>The Apache Tomcat team is proud to announce the immediate availability
+of Jakarta Tomcat Connectors 1.2.15 Stable.
+</p>
+<p>Download the <a href="http://www.apache.org/dist/tomcat/tomcat-connectors/jk/source/jk-1.2.15/jakarta-tomcat-connectors-1.2.15-src.tar.gz">JK 1.2.15 release sources</a>
+ | <a href="http://www.apache.org/dist/tomcat/tomcat-connectors/jk/source/jk-1.2.15/jakarta-tomcat-connectors-1.2.15-src.tar.gz.asc">PGP signature</a>
+</p>
+<p>Download the <a href="http://www.apache.org/dist/tomcat/tomcat-connectors/jk/binaries/">binaries</a> for selected platforms.
+</p>
+</li>
+
+<li><a href="news/20050101.html#20050713.1">13 July 2005 - <b>JK-1.2.14 released</b></a>
+<p>The Apache Tomcat team is proud to announce the immediate availability
+of Jakarta Tomcat Connectors 1.2.14 Stable.
+</p>
+<p>Download the <a href="http://www.apache.org/dist/tomcat/tomcat-connectors/jk/source/jk-1.2.14/jakarta-tomcat-connectors-1.2.14.1-src.tar.gz">JK 1.2.14 release sources</a>
+ | <a href="http://www.apache.org/dist/tomcat/tomcat-connectors/jk/source/jk-1.2.14/jakarta-tomcat-connectors-1.2.14.1-src.tar.gz.asc">PGP signature</a>
+</p>
+<p>Download the <a href="http://www.apache.org/dist/tomcat/tomcat-connectors/jk/binaries/">binaries</a> for selected platforms.
+</p>
+</li>
+
+<li><a href="news/20050101.html#20050516.1">16 May 2005 - <b>JK-1.2.13 released</b></a>
+<p>The Apache Jakarta Tomcat team is proud to announce the immediate availability
+of Jakarta Tomcat Connectors 1.2.13 tarbals for testing.
+</p>
+<p>Download the <a href="http://www.apache.org/dist/tomcat/tomcat-connectors/jk/source/jk-1.2.13/jakarta-tomcat-connectors-1.2.13-src.tar.gz">JK 1.2.13 release sources</a>
+ | <a href="http://www.apache.org/dist/tomcat/tomcat-connectors/jk/source/jk-1.2.13/jakarta-tomcat-connectors-1.2.13-src.tar.gz.asc">PGP signature</a>
+</p>
+<p>Download the <a href="http://www.apache.org/dist/tomcat/tomcat-connectors/jk/binaries/">binaries</a> for selected platforms.
+</p>
+</li>
+<li><a href="news/20050101.html#20050507.1">7 May 2005 - <b>JK-1.2.12 released</b></a>
+<p>The Apache Jakarta Tomcat team is proud to announce the immediate availability
+of Jakarta Tomcat Connectors 1.2.12.
+</p>
+<p>Download the <a href="http://www.apache.org/dist/tomcat/tomcat-connectors/jk/source/jk-1.2.12/jakarta-tomcat-connectors-1.2.12-src.tar.gz">JK 1.2.12 release sources</a>
+ | <a href="http://www.apache.org/dist/tomcat/tomcat-connectors/jk/source/jk-1.2.12/jakarta-tomcat-connectors-1.2.12-src.tar.gz.asc">PGP signature</a>
+</p>
+<p>Download the <a href="http://www.apache.org/dist/tomcat/tomcat-connectors/jk/binaries/">binaries</a> for selected platforms.
+</p>
+</li>
+<li><a href="news/20050101.html#20050429.1">29 April 2005 - <b>JK-1.2.11 released</b></a>
+<p>The Apache Jakarta Tomcat team is proud to announce the immediate availability
+of Jakarta Tomcat Connectors 1.2.11.
+</p>
+<p>Downlad the <a href="http://www.apache.org/dist/tomcat/tomcat-connectors/jk/source/jk-1.2.11/jakarta-tomcat-connectors-1.2.11-src.tar.gz">JK 1.2.11 release sources</a>
+ | <a href="http://www.apache.org/dist/tomcat/tomcat-connectors/jk/source/jk-1.2.11/jakarta-tomcat-connectors-1.2.11-src.tar.gz.asc">PGP signature</a>
+</p>
+<p>Download the <a href="http://www.apache.org/dist/tomcat/tomcat-connectors/jk/binaries/">binaries</a> for selected platforms.
+</p>
+</li>
+<li><a href="news/20050101.html#20050330.1">30 March 2005 - <b>JK-1.2.10 released</b></a>
+<p>The Apache Jakarta Tomcat team is proud to announce the immediate availability
+of Jakarta Tomcat Connectors 1.2.10.
+</p>
+<p>Downlad the <a href="http://www.apache.org/dist/tomcat/tomcat-connectors/jk/source/jk-1.2.10/jakarta-tomcat-connectors-1.2.10-src.tar.gz">JK 1.2.10 release sources</a>
+ | <a href="http://www.apache.org/dist/tomcat/tomcat-connectors/jk/source/jk-1.2.10/jakarta-tomcat-connectors-1.2.10-src.tar.gz.asc">PGP signature</a>
+</p>
+<p>Download the <a href="http://www.apache.org/dist/tomcat/tomcat-connectors/jk/binaries/">binaries</a> for selected platforms.
+</p>
+</li>
+<li><a href="news/20041100.html#20041224.1">24 December 2004 - <b>JK-1.2.8 released</b></a>
+<p>The Apache Jakarta Tomcat team is proud to announce the immediate availability
+of Jakarta Tomcat Connectors 1.2.8.
+</p>
+<p>Downlad the <a href="http://www.apache.org/dist/tomcat/tomcat-connectors/jk/source/jk-1.2.8/jakarta-tomcat-connectors-1.2.8-src.tar.gz">JK 1.2.8 release sources</a>
+ | <a href="http://www.apache.org/dist/tomcat/tomcat-connectors/jk/source/jk-1.2.8/jakarta-tomcat-connectors-1.2.8-src.tar.gz.asc">PGP signature</a>
+</p>
+<p>Download the <a href="http://www.apache.org/dist/tomcat/tomcat-connectors/jk/binaries/">binaries</a> for selected platforms.
+</p>
+</li>
+<li><a href="news/20041100.html#20041218.1">17 December 2004 - <b>JK-1.2.8-rc-1 released</b></a>
+<p>The Apache Jakarta Tomcat team is proud to announce the immediate availability
+of Jakarta Tomcat Connectors 1.2.8-rc-1 (Relase Canditate 1).
+</p>
+<p>
+We expect it to be ratified as a Stable release when the vote takes place
+in the next week.
+</p> 
+<p>Downlad the <a href="http://www.apache.org/dist/tomcat/tomcat-connectors/jk/source/jakarta-tomcat-connectors-1.2.8-rc-1.tar.gz">JK 1.2.8 release candidate 1 sources</a>
+ | <a href="http://www.apache.org/dist/tomcat/tomcat-connectors/jk/source/jakarta-tomcat-connectors-1.2.8-rc-1.tar.gz.asc">PGP signature</a>
+</p>
+</li>
+<li><a href="news/20041100.html#20041213.1">13 December 2004 - <b>JK-1.2.7-beta-3 released</b></a>
+<p>The Apache Jakarta Tomcat team is proud to announce the immediate availability
+of Jakarta Tomcat Connectors 1.2.7-beta-3. The release contains a fix to few configuraton
+problems detected with JK-1.2.7-beta-2 version. 
+</p>
+<p>Downlad the <a href="http://www.apache.org/dist/tomcat/tomcat-connectors/jk/source/jakarta-tomcat-connectors-1.2.7-beta-3.tar.gz">JK 1.2.7 beta sources</a>
+ | <a href="http://www.apache.org/dist/tomcat/tomcat-connectors/jk/source/jakarta-tomcat-connectors-1.2.7-beta-3.tar.gz.asc">PGP signature</a>
+</p>
+</li>
+<li><a href="news/20041100.html#20041207.1">7 December 2004 - <b>JK-1.2.7-beta-2 released</b></a>
+<p>The Apache Jakarta Tomcat team is proud to announce the immediate availability
+of Jakarta Tomcat Connectors 1.2.7-beta-2. The release contains a fix to few compilation
+problems detected with JK-1.2.7-beta version. 
+</p>
+<p>Downlad the <a href="http://www.apache.org/dist/tomcat/tomcat-connectors/jk/source/jakarta-tomcat-connectors-1.2.7-beta-2.tar.gz">JK 1.2.7 beta sources</a>
+ | <a href="http://www.apache.org/dist/tomcat/tomcat-connectors/jk/source/jakarta-tomcat-connectors-1.2.7-beta-2.tar.gz.asc">PGP signature</a>
+</p>
+</li>
+<li><a href="news/20041100.html#20041130.1">30 November 2004 - <b>JK-1.2.7-beta released</b></a>
+<p>The Apache Jakarta Tomcat team is proud to announce the immediate availability
+of Jakarta Tomcat Connectors 1.2.7-beta. The release contains a significant number
+of bug fixes and new features. 
+</p>
+<p>Downlad the <a href="http://www.apache.org/dist/tomcat/tomcat-connectors/jk/source/jakarta-tomcat-connectors-1.2.7-beta-1.tar.gz">JK 1.2.7 beta sources</a>
+ | <a href="http://www.apache.org/dist/tomcat/tomcat-connectors/jk/source/jakarta-tomcat-connectors-1.2.7-beta-1.tar.gz.asc">PGP signature</a>
+</p>
+</li>
+<li><a href="news/20041100.html#20041115.1">15 November 2004 - <b>JK2 is officially unsupported!</b></a>
+<p>JK2 has been put in maintainer mode and no further development will take place.
+The reason for shutting down JK2 development was the lack of developers interest.
+Other reason was lack of users interest in adopting JK2, caused by configuration
+complexity when compared to JK.
+</p>
+<p>JK2 will have it's successor within core Apache2.1/2.2 distribution.
+We have developed new <b>proxy_ajp</b> that is an addition to
+the mod_proxy and uses Tomcat's AJP protocol stack. It is developped in httpd-2.1
+and integrated in it. We have also developed a new <b>proxy_balancer</b> module
+for load balancing http and ajp protocol stacks.
+</p>
+<p>JK will be fully supported for all other web servers. The next JK release is
+planned for the end of November. Lots of code from JK2 has been ported to JK
+</p>
+</li>
+</ul>
+</section>
+
+<section name="Configuration">
+<br />
+<ul>
+<li><a href="config/workers.html"><b>Workers.properties Documentation</b></a>
+<p>A Tomcat worker is a Tomcat instance that is waiting to execute servlets
+on behalf of some web server. For example, we can have a web server such as Apache
+forwarding servlet requests to a Tomcat process (the worker) running behind it. 
+</p>
+<p>This section contains detail description of all workers.properties
+directives.
+</p>
+</li>
+
+<li><a href="config/apache.html"><b>Apache Documentation</b></a>
+<p>This section contains detail description of all directives related to
+Aapache web server. 
+</p>
+</li>
+<li><a href="config/iis.html"><b>IIS Documentation</b></a>
+<p>This section contains detail description of all IIS directives.
+</p>
+</li>
+
+</ul>
+</section>
+
+<section name="Installation">
+<br />
+<ul>
+<li><a href="install/apache1.html"><b>Apache 1.3.x installation documentation</b></a>
+<p>This section contains detail description of how to build and
+install mod_jk for Apache 1.3.x web server. Browse to this section if you need to
+build mod_jk for Apache 1.3.x web server from sources.
+</p>
+</li>
+<li><a href="install/apache2.html"><b>Apache 2.0.x installation documentation</b></a>
+<p>This section contains detail description of how to build and
+install mod_jk for Apache 2.0.x web server. Browse to this section if you need to
+build mod_jk for Apache 2.0.x web server from sources.
+</p>
+</li>
+
+<li><a href="install/iis.html"><b>IIS installation documentation</b></a>
+<p>This section contains detail description of how to build and
+install isapi_redirector for IIS web server.
+</p>
+</li>
+
+</ul>
+</section>
+
+
+<section name="Miscellaneous documentation">
+<br />
+<ul>
+<li><a href="common/ajpv13a.html"><b>AJPv13 Protocol Documentation</b></a>
+<p>This section describes the Apache JServ Protocol version 1.3 (hereafter
+<b>ajp13</b>). There is, apparently, no current documentation of how the
+protocol works. This document is an attempt to remedy that, in order to
+make life easier for maintainers of JK, and for anyone who wants to
+port the protocol to some other container. 
+</p>
+</li>
+<li><a href="howto/index.html"><b>HowTo Documentation</b></a>
+<p>This section contains various howto documents General Informations and FAQ about JK 
+</p>
+</li>
+<li><a href="faq.html"><b>General Informations and FAQ about JK</b></a>
+<p>
+</p>
+</li>
+<li><a href="changelog.html"><b>Details the changes made to JK</b></a>
+<p>
+</p>
+</li>
+<li><a href="proxy.html"><b>Using ajp-proxy in httpd-2.1</b></a>
+<p>
+mod-proxy in httpd-2.1 offers an AJP connection as well as load balancing.
+</p>
+</li>
+<li><a href="http://tomcat.apache.org/connectors-doc-archive/jk2/index.html">
+<b>Old JK/JK2 documentation archive.</b></a>
+<p>Here you can find old JK and JK2 documentation.
+</p>
+</li>
+<li><a href="http://issues.apache.org/bugzilla/buglist.cgi?query_format=advanced&amp;short_desc_type=allwordssubstr&amp;short_desc=&amp;product=Tomcat+5&amp;component=Native%3AJK&amp;long_desc_type=substring&amp;long_desc=&amp;bug_file_loc_type=allwordssubstr&amp;bug_file_loc=&amp;keywords_type=allwords&amp;keywords=&amp;bug_status=NEW&amp;bug_status=ASSIGNED&amp;bug_status=REOPENED&amp;emailassigned_to1=1&amp;emailtype1=substring&amp;email1=&amp;emailassigned_to2=1&amp;emailreporter2=1&amp;emailcc2=1&amp;emailtype2=substring&amp;email2=&amp;bugidtype=include&amp;bug_id=&amp;votes=&amp;chfieldfrom=&amp;chfieldto=Now&amp;chfieldvalue=&amp;cmdtype=doit&amp;order=Reuse+same+sort+as+last+time&amp;field0-0-0=noop&amp;type0-0-0=noop&amp;value0-0-0=">
+<b>Current Native:JK bugs</b></a>
+<p>This is Buzgilla Bug List related to Native:JK.
+</p>
+</li>
+</ul>
+
+</section>
+
+
+</body>
+</document>

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/jk2/confighowto.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/jk2/confighowto.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/jk2/confighowto.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,132 @@
+<?xml version="1.0"?>
+<document>
+<copyright>
+   Copyright 1999-2004 The Apache Software Foundation
+ 
+   Licensed 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.
+</copyright>
+<properties>
+<title>Quick Start JK2 Configuration Guide</title>
+<author email="mturk at mappingsoft.com">Mladen Turk</author>
+<date>$Date: 2004-03-03 22:46:34 -0600 (Wed, 03 Mar 2004) $</date>
+</properties>
+<section name="Introduction">
+<p>
+  This document describes the configuration files used by JK2 on the
+  Tomcat and Web Server side:
+    <ul>
+    <li>
+    <b>jk2.properties</b> is used on the Tomcat side. It's installation path in
+    the $TOMCAT_HOME/conf directory.
+    </li>
+    <li>
+    <b>workers2.properties</b> is used on the webserver side. For the Apache
+    servers the default path is in the ServerRoot/conf directory.
+    </li>
+    </ul>    
+  Although JK2 has many things in common with mod_jk, the configuration is quite
+  different, and all the directives should be inside the workers2.properties.
+  This enables JK2 to have the same configuration file no mater what the web server
+  it's connected to.
+</p>
+</section>
+
+<section name="Minimum Configuration">
+<p>
+    Minimum configuration is the simplest one to make the JK2 working. The used
+    channel will be socket, and lot of options are used by default. Both the
+    Tomcat and web server are on the same computer.
+</p>
+<p>
+jk2.properties:
+<source>
+# The default port is 8009 but you can use another one
+# channelSocket.port=8019
+</source>
+That is all needed on the Tomcat side to configure the JK2.
+</p>
+<p>
+workers2.properties:
+<source>
+# Define the communication channel 
+[channel.socket:localhost:8009]
+info=Ajp13 forwarding over socket
+tomcatId=localhost:8009
+
+# Map the Tomcat examples webapp to the Web server uri space
+[uri:/examples/*]
+info=Map the whole webapp
+</source>
+</p>
+<p>
+Start the Tomcat and Web server and browse to the <a>http://localhost/examples/</a>
+</p>
+</section>
+
+<section name="Minimum JNI Configuration">
+<p>
+    Minimum JNI configuration is the simplest one to make the Tomcat working
+    from inside the web server as inprocess. The only comunication channel used
+    is JNI. The JK2 will register all the native calls by itself, so there is
+    no need to specify the native library on Java side.
+</p>
+<p>
+jk2.properties:
+<source>
+# Add the apr and channelJni to the list of handlers
+handler.list=apr,request,container,channelJni
+# The native libraries will be registered by JK2
+apr.jniModeSo=inprocess
+</source>
+</p>
+<p>
+workers2.properties:
+<source>
+# Define the comunication channel 
+[channel.jni:jni]
+info=The jni channel, used if tomcat is started inprocess
+
+# Define the parameters for the Java Virtual Machine
+[vm:]
+info=Parameters used to load a JVM in the server process
+OPT=-Djava.class.path=${TOMCAT_HOME}/lib/tomcat-jni.jar;${TOMCAT_HOME}/lib/tomcat.jar
+OPT=-Dtomcat.home=${TOMCAT_HOME}
+OPT=-Dcatalina.home=${TOMCAT_HOME}
+OPT=-Xmx128M
+
+# JNI worker startup handler
+[worker.jni:onStartup]
+info=Command to be executed by the VM on startup. This one will start tomcat.
+class=org/apache/jk/apr/TomcatStarter
+ARG=start
+stdout=${serverRoot}/logs/stdout.log
+stderr=${serverRoot}/logs/stderr.log
+
+# JNI worker shutdown handler
+[worker.jni:onShutdown]
+info=Command to be executed by the VM on shutdown. This one will stop tomcat.
+class=org/apache/jk/apr/TomcatStarter
+ARG=stop
+
+# Map the Tomcat examples webapp to the Web server uri space
+[uri:/examples/*]
+info=Map the whole webapp
+</source>
+</p>
+<p>
+Start the Web server and browse to the <a>http://localhost/examples/</a>
+</p>
+
+</section>
+
+</document>

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/jk2/configtc.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/jk2/configtc.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/jk2/configtc.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,57 @@
+<?xml version="1.0"?>
+<document>
+<copyright>
+   Copyright 1999-2004 The Apache Software Foundation
+ 
+   Licensed 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.
+</copyright>
+	<properties>
+		<title>Configuration options</title>
+		<author email="jfrederic.clere at fujitsu-siemens.com">Jean-Frederic Clere</author>
+		<date>$Date: 2004-03-03 22:46:34 -0600 (Wed, 03 Mar 2004) $</date>
+	</properties>
+	<section name="Intro">
+		<p>
+  This document describes the configuration file used by mod_jk2 on the
+  Tomcat site. Its default name is ${jkHome}/conf/jk2.properties,
+  where ${jkHome} is the well known ${catalina.base} property.
+</p>
+	</section>
+	<section name="Config File Format">
+	<p> settings are specified in the following format:
+	<source>
+	handler.propertie=value
+	</source>
+	</p></section>
+	<section name="Generic properties">
+		<p>
+			<table>
+				<tr>
+					<th>Property name</th>
+					<th>Default</th>
+					<th>Description</th>
+				</tr>
+				<tr>
+					<td>handler.list</td>
+					<td>request,container,channelSocket</td>
+					<td>Handlers to load.</td>
+				</tr>
+				<tr>
+					<td>class.myhandler</td>
+					<td>No default value</td>
+					<td>Define the class of the handler myhandler.</td>
+				</tr>
+			</table>
+		</p>
+	</section>
+</document>

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/jk2/configtccom.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/jk2/configtccom.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/jk2/configtccom.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,314 @@
+<?xml version="1.0"?>
+<document>
+<copyright>
+   Copyright 1999-2004 The Apache Software Foundation
+ 
+   Licensed 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.
+</copyright>
+	<properties>
+		<title>Coyote/JK2 Handlers</title>
+		<author email="jfrederic.clere at fujitsu-siemens.com">Jean-Frederic Clere</author>
+		<date>$Date: 2004-03-03 22:46:34 -0600 (Wed, 03 Mar 2004) $</date>
+	</properties>
+	<section name="apr">
+		<p>
+APR descriptor
+</p>
+		<p>
+			<table>
+				<tr>
+					<th>Property name</th>
+					<th>Default</th>
+					<th>Description</th>
+				</tr>
+				<tr>
+					<td>NativeSo</td>
+					<td>jkjni</td>
+					<td>
+    Location of the jkjni dynamic library.
+    It is searched in java.library.path but a absolute path can be specified.
+  </td>
+				</tr>
+				<tr>
+					<td>jniModeSo</td>
+					<td>inprocess</td>
+					<td>
+    If set to "inprocess" the jk2 will regiter native library functions by itself.
+	If not then it has to be the absolute path of the jkjni dynamic library.
+  </td>
+				</tr>
+				<tr>
+					<td>baseDir</td>
+					<td></td>
+					<td></td>
+				</tr>
+				<tr>
+					<td>aprHome</td>
+					<td></td>
+					<td></td>
+				</tr>
+				<tr>
+					<td>soExt</td>
+					<td></td>
+					<td></td>
+				</tr>
+			</table>
+		</p>
+	</section>
+	<section name="channelSocket">
+		<p>
+					A communication transport from a remote Web Server.
+</p>
+		<p>
+			<table>
+				<tr>
+					<th>Property name</th>
+					<th>Default</th>
+					<th>Description</th>
+				</tr>
+				<tr>
+					<td>port</td>
+					<td>8009</td>
+					<td>First port where Tomcat is listening</td>
+				</tr>
+				<tr>
+					<td>address</td>
+					<td>127.0.0.1</td>
+					<td>Local address where Tomcat is listening.</td>
+				</tr>
+				<tr>
+					<td>maxPort</td>
+					<td>port+10</td>
+					<td>Max port used to listen.</td>
+				</tr>
+				<tr>
+					<td>maxThreads</td>
+					<td></td>
+					<td></td>
+				</tr>
+				<tr>
+					<td>backLog</td>
+					<td></td>
+					<td></td>
+				</tr>
+				<tr>
+					<td>tcpNoDelay</td>
+					<td></td>
+					<td></td>
+				</tr>
+				<tr>
+					<td>soTimeout</td>
+					<td></td>
+					<td></td>
+				</tr>
+				<tr>
+					<td>soLinger</td>
+					<td></td>
+					<td></td>
+				</tr>
+				<tr>
+					<td>serverTimeout</td>
+					<td></td>
+					<td></td>
+				</tr>
+			</table>
+		</p>
+	</section>
+	<section name="channelUnix">
+		<p>	A AF_UNIX socket communication transport from a local Web Server.</p>
+		<p>
+			<table>
+				<tr>
+					<th>Property name</th>
+					<th>Default</th>
+					<th>Description</th>
+				</tr>
+				<tr>
+					<td>file</td>
+					<td>No default value</td>
+					<td>
+    Name of the "file" associate with the socket.
+    That must be absolut path name.
+  </td>
+				</tr>
+			</table>
+		</p>
+	</section>
+	<section name="channelJni">
+		<p>A in Web Server process communication.</p>
+		<p>
+			<table>
+				<tr>
+					<th>Property name</th>
+					<th>Default</th>
+					<th>Description</th>
+				</tr>
+			</table>
+		</p>
+	</section>
+	<section name="mx">
+		<p>mx4j adapter.</p>
+		<p>
+			<table>
+				<tr>
+					<th>Property name</th>
+					<th>Default</th>
+					<th>Description</th>
+				</tr>
+				<tr>
+					<td>port</td>
+					<td>-1 (Disabled)</td>
+					<td>Port Number.</td>
+				</tr>
+			</table>
+		</p>
+	</section>
+	<section name="shm">
+		<p>				shared memory objects handler.</p>
+		<p>
+			<table>
+				<tr>
+					<th>Property name</th>
+					<th>Default</th>
+					<th>Description</th>
+				</tr>
+				<tr>
+					<td>file</td>
+					<td>/tmp/shm.file</td>
+					<td>Shared memory file.</td>
+				</tr>
+				<tr>
+					<td>host</td>
+					<td>localhost</td>
+					<td>Host name.</td>
+				</tr>
+				<tr>
+					<td>port</td>
+					<td>8009</td>
+					<td>Port number.</td>
+				</tr>
+				<tr>
+					<td>unixSocket</td>
+					<td>No default value</td>
+					<td>Unix socket where tomcat is listening.</td>
+				</tr>
+			</table>
+		</p>
+	</section>
+	<section name="request">
+		<p>Request handler</p>
+		<p>
+			<table>
+				<tr>
+					<th>Property name</th>
+					<th>Default</th>
+					<th>Description</th>
+				</tr>
+				<tr>
+					<td>tomcatAuthentication</td>
+					<td>true</td>
+					<td>the request handler will get the authenticated user from the HTTP server, honoring any auth done there.</td>
+				</tr>
+				<tr>
+					<td>ajpidDir</td>
+					<td></td>
+					<td></td>
+				</tr>
+				<tr>
+					<td>decodedUri</td>
+					<td></td>
+					<td></td>
+				</tr>
+				<tr>
+					<td>secret</td>
+					<td></td>
+					<td></td>
+				</tr>
+				<tr>
+					<td>useSecret</td>
+					<td></td>
+					<td></td>
+				</tr>
+			</table>
+		</p>
+	</section>
+	<section name="modeler">
+		<p>????</p>
+		<p>
+			<table>
+				<tr>
+					<th>Property name</th>
+					<th>Default</th>
+					<th>Description</th>
+				</tr>
+				<tr/>
+			</table>
+		</p>
+	</section>
+	<section name="container">
+		<p>????</p>
+		<p>
+			<table>
+				<tr>
+					<th>Property name</th>
+					<th>Default</th>
+					<th>Description</th>
+				</tr>
+				<tr/>
+			</table>
+		</p>
+	</section>
+	<section name="modjk">
+		<p>????</p>
+		<p>
+			<table>
+				<tr>
+					<th>Property name</th>
+					<th>Default</th>
+					<th>Description</th>
+				</tr>
+				<tr>
+					<td>pass</td>
+					<td></td>
+					<td></td>
+				</tr>
+				<tr>
+					<td>statusPath</td>
+					<td></td>
+					<td></td>
+				</tr>
+				<tr>
+					<td>updateInterval</td>
+					<td></td>
+					<td></td>
+				</tr>
+				<tr>
+					<td>user</td>
+					<td></td>
+					<td></td>
+				</tr>
+				<tr>
+					<td>webServerHost</td>
+					<td></td>
+					<td></td>
+				</tr>
+				<tr>
+					<td>webServerPort</td>
+					<td></td>
+					<td></td>
+				</tr>
+			</table>
+		</p>
+	</section>
+</document>
+

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/jk2/configtcex.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/jk2/configtcex.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/jk2/configtcex.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,120 @@
+<?xml version="1.0"?>
+<document>
+<copyright>
+   Copyright 1999-2004 The Apache Software Foundation
+ 
+   Licensed 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.
+</copyright>
+<properties>
+<title>Examples</title>
+<author email="jfrederic.clere at fujitsu-siemens.com">Jean-Frederic Clere</author>
+<date>$Date: 2004-03-03 22:46:34 -0600 (Wed, 03 Mar 2004) $</date>
+</properties>
+
+<section name="jk2.properties">
+<p>
+The examples below are working when the Web Server is configured according the 
+examples described in the configweb file.
+</p>
+<subsection name="using normal socket">
+<p>
+There is no need to use the jkjni logic to use normal socket, so that just for
+Fun.
+</p>
+
+<p>
+<source>
+# list of needed handlers.
+handler.list=apr,channelSocket,request
+
+# Override the default port for the channelSocket
+channelSocket.port=8019
+
+# Dynamic library
+apr.NativeSo=/home1/jakarta/jakarta-tomcat-connectors/jk/build/jk2/apache2/jkjni.so
+</source>
+</p>
+</subsection>
+
+<subsection name="using AF_UNIX socket">
+<p>
+Create and listen on a AF_UNIX socket. The location of the socket must be the
+same in the Web Server configuration file.
+</p>
+
+<p>
+<source>
+# list of needed handlers.
+handler.list=apr,channelUnix,request
+
+# Location of the socket.
+channelUnix.file=${jkHome}/work/jk2.socket
+
+# Dynamic library
+jtc=/home1/jakarta/jakarta-tomcat-connectors
+apr.NativeSo=${jtc}/jk/build/jk2/apache2/jkjni.so
+</source>
+</p>
+</subsection>
+
+<subsection name="using user defined class for communication">
+<p>
+It is possible to have a user defined class for the communication.
+Here we have used the ChannelUn as example.
+</p>
+
+<p>
+<source>
+# Define our own handler.
+class.mychannel=org.apache.jk.common.ChannelUn
+# list of needed handlers.
+handler.list=apr,mychannel,request
+
+# Location of the socket.
+channelUnix.file=${jkHome}/work/jk2.socket
+
+# Dynamic library
+jtc=/home1/jakarta/jakarta-tomcat-connectors
+apr.NativeSo=${jtc}/jk/build/jk2/apache2/jkjni.so
+</source>
+</p>
+</subsection>
+
+<subsection name="using jni channel class for communication">
+<p>
+Here we have the minimum configuration needed for the jni communication.
+</p>
+
+<p>
+<source>
+# list of needed handlers.
+handler.list=apr,request,channelJni
+
+# Dynamic library needs to be defined only if Tomcat is used
+# out of process
+jtc=/home1/jakarta/jakarta-tomcat-connectors
+apr.NativeSo=${jtc}/jk/build/jk2/apache2/jkjni.so
+# Or you can use the mod_jk2 directly
+apr.jniModeSo=/opt/apache2/modules/mod_jk2.so
+
+# If you wish to start the Tomcat from inside web server then
+# you don't need any above directive. Here is shown the default
+# value for the apr that you can ommit
+apr.jniModeSo=inprocess
+
+</source>
+</p>
+</subsection>
+
+</section>
+</document>

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/jk2/configweb.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/jk2/configweb.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/jk2/configweb.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,186 @@
+<?xml version="1.0"?>
+<document>
+<copyright>
+   Copyright 1999-2004 The Apache Software Foundation
+ 
+   Licensed 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.
+</copyright>
+<properties>
+<title>Configuration file</title>
+<author email="cmanolache at yahoo.com">Costin Manolache</author>
+<author email="jfrederic.clere at fujitsu-siemens.com">Jean-Frederic Clere</author>
+<date>$Date: 2004-03-03 22:46:34 -0600 (Wed, 03 Mar 2004) $</date>
+</properties>
+    <section name="Intro">
+
+        <p>Jk2 uses an architecture and configuration mechanism modeled after JMX. It consist of 
+"jk_bean" components, with a registry and API that attempts to mirror JMX.</p>
+
+        <p>As in JMX, multiple config formats and stores are possible. The default is a neutral .INI-style 
+file, and Apache2 also supports configuration in httpd.conf. Other formats and repositories can be
+easily implemented, but the general concept is the same.</p>
+
+        <p>Each component has a name, a type and a set of attributes. Reasonable defaults are provided, and 
+some components are created automatically using the defaults if not explicitely configured. 
+You need to specify the config only where you want to override the defaults.</p>
+
+    </section>
+
+    <section name="Config file format">
+
+        <p>The config file is named "workers2.properties", located by default in ${serverRoot}/conf, 
+where ${serverRoot} is the web server dir, like /usr/local/apache. It is possible to modify the location
+of the file using server-specific directives.</p>
+
+        <p>Settings are grouped in sections - one section for each object. The section head is the component
+name, and must include the type and local name of the component, separated by ":". Inside each section
+you must define the attributes of the component. The attribute name is a simple string, with no '.' or
+special characters. The value is a string - no quoting is currently supported. It should be noted that
+the component name is processed to compute default for the component attributes - for example 
+[channel.socket:localhost:8009] name will create a socket channel object with host=locahost and 
+port=8009. You don't need to provide this information twice. It is highly recommended to use
+this naming scheme for consistency, even if you could use any name and then specify the properties
+explicitely.</p>
+
+        <p>The general syntax is:
+            <source>
+                [TYPE:NAME]
+                PROPERTY=VALUE
+            </source>
+        </p>
+
+        <p>It is also possible to use an alternate format, mostly for backward compatibility:
+            <source>
+                TYPE:NAME.PROPERTY=VALUE 
+            </source>
+        </p>
+    </section>
+
+    <section name="Runtime reconfiguration">
+
+      <p>The main purpose of this reconfiguration is to implement "graceful" shutdown and 
+to allow adding or disabling of more tomcat instances in the load balancing mode</p>
+
+      <p>Each component has a "ver" attribute - it is initially set to the value in the 
+config file or 0 if this is not specified. Every time the config file is read, jk will 
+check the version number in the component, and reconfigure if it is different.</p>
+
+   <p>If Jk2 reloads the config file, it detect modified components using "ver" and reconfigures them.
+To avoid performance hits, the check is done only when the /jkstatus page is accessed - or 
+if the scoreboard signature changes. An access to /jkstatus will check the timestamp of the 
+config file and if a change is detected it'll reload the config file. In apache and multiprocess
+servers - this can only affect the current process, so /jkstatus will increment the scoreboard mark.
+All other processes in a multiprocess server will see the modified byte and reload before serving the next request.</p>
+
+<p>Changing the file and forcing a reload is currently the easiest way to reconfigure. A JMX proxy 
+is in experimental stage and will allow the user to perform all configuration in JMX - using same 
+tools that he uses for tomcat, and completely transparent. The internal implementation will also
+save the file - it is the cleanest way to sync multi-process web servers.
+</p>
+
+
+    </section>
+
+    <section name="Changing 'graceful' stop state">
+
+      <p>Each tomcat instance corresponds to a "channel" jk component that defines the host and port. The 
+channel can be set in a special "graceful" mode or back to active by setting the corresponding attribute.
+This mode disables sending any new requests to that tomcat instance - only requests for
+an existing session are permitted.</p>
+
+      <p>When you want to disable a tomcat instance, you should first set the channel in
+"graceful" mode, then wait until all existing sessions expire or are completed. If the sessions
+are serializable and tomcat is configured in clustering mode - you can also migrate the 
+sessions to a different instance.</p>
+
+     <p>1. Edit workers2.properties. Find the channel. Change "graceful" to "1" to disable or "0"
+        to reactivate". Increment "ver".<br></br>
+      2. Access /jkstatus page. You should see the value changed in the channel and worker info.</p>
+
+     <p>When a worker is in this state, no new requests will be sent to that worker - only requests that have an 
+explicit session ID for that particular worker. It is recommended you wait for all sessions to expire 
+before stopping the tomcat instance, or you use a session migration mechanism.
+</p> 
+
+</section>
+    <section name="Adding a new tomcat instance">
+
+     <p>1. Edit workers2.properties. Add a new channel. If you want, also add a worker.ajp entry - 
+but this is optional</p>
+     <p>2. Access the /jkstatus page or triger reloading with a program. You should see the 
+new channel displayed in the status page, and requests should start going to the new tomcat instance</p>
+
+</section>
+    <section name="Advanced: reconfiguration using JMX">
+
+        <p>This is very experimental. On tomcat side, you must enable the JMX proxy. This is done by
+setting "modjk.webServerHost" and "modjk.webServerPort" in jk2.properties to point to the web server 
+port that contains /jkstatus. ( recent versions of jk and mod_jk are required ). You can also add mx4j-tools.jar to 
+server/lib and set "mx.enable=true" in jk2.properties to enable the console, or use your favorite JMX
+console or tools. You could also select http and/or jrmp protocol, with mx.httpPort, mx.httpHost, mxjrmpPort
+and mx.jrmpPort</p>
+   
+         <p>When tomcat starts up, it'll connect to the web server and create JMX mbean proxies for each
+mod_jk component. The data will be refreshed when JMX operations are performed - a set or invoke will
+allways refresh, while get will use cached values and refresh only periodically ( 5 sec default ).</p>
+
+<p>Every time  a change is made, the config file will be written ( for persistence and to allow other 
+processes to get the same change ). The scoreboard will be changed, and then all other server processes will 
+act just like in the case of a file change. All comments will be lost - you should use "info" attributes
+in components and set "disabled" to 1 if you want to temporary disable some components.</p>   
+
+
+</section>
+    <section name="Native server configuration">
+
+<p>For Apache2 you can also use httpd.conf instead or in addition to workers2.properties.
+Other servers may support similar configuration - for example using registry or their native
+formats. This configuration mode is less tested - but provides some
+unique advantages (and disadvantages )</p>
+
+<p>I'll describe the apache2 specifics, since this is the only one implemented. We use 2 directives - JkSet
+is a top-level directive is used to set global config options, and JkUriSet is used to set options
+ for Location sections</p>
+
+<p>JkSet takes 2 parameters, the property name ( including component name ) and the value. (Note:
+probably we should change it to 3 params, and separate the component name from property )</p>
+
+<p>Each Location that has a JkUriSet will automatically create a jk2 [uri] object,
+using the Location path and the vhost. All JkUriSet directives will set attributes
+in this [uri] object, exactly like properties in a ini file section</p>
+
+<p>You can mix workers2.properties and JkUriSet - for example workers and global options
+can be set in worker2.properties, but all uri properties in httpd.conf. Some people 
+might preffer to have only one config file and use httpd.conf for all configuration.</p>
+
+<p>The biggest benefit is that Apache2 mapping is used instead of jk2 to detect the
+requests that need to be sent to tomcat. Apache2 has been optimized and tuned to
+server huge number of servers and uris - if you have only few the diference may be
+hard to notice. Some people preffer to use the httpd.conf format and some tools 
+could be better used in this mode.</p>
+
+<p>One major problem is that reconfiguration is not supported if httpd.conf is used. 
+You can still enable/disable/add workers if you use workers2.properties, and 
+you could add or change uri properties in that file. </p>
+
+</section>
+    <section name="Config generators">
+ 
+<p>There is work in progress to support automatic generation of the config file. The code is
+included in org.apache.jk.config and consist of a number of ant tasks ( that work from CLI as well)
+ that process web.xml files and generate worker2.properties or server-specific config files</p>
+
+</section>
+
+
+</document>

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/jk2/configwebcom.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/jk2/configwebcom.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/jk2/configwebcom.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,765 @@
+<?xml version="1.0"?>
+<document>
+<copyright>
+   Copyright 1999-2004 The Apache Software Foundation
+ 
+   Licensed 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.
+</copyright>
+
+<properties>
+  <title>Components</title>
+
+  <author email="cmanolache at yahoo.com">Costin Manolache</author>
+  <author email="jfrederic.clere at fujitsu-siemens.com">Jean-Frederic Clere</author>
+  <author email="yoavs at apache.org">Yoav Shapira</author>
+
+  <date>$Date: 2004-08-11 13:06:27 -0500 (Wed, 11 Aug 2004) $</date>
+</properties>
+
+<section name="Intro">
+  <p>
+    Each component instance has a name, that is used for configuration and at runtime.
+    Each component has a number of configurable properties. The following rules are used:
+    <ul>
+      <li>The name is composed from the type and a local part, separated with a ':' ( example: channel.unixsocket:/tmp/jk.socket ) </li>
+      <li>The 'type' consist of '.' and ascii characters.  It is mapped to a JMX 'domain'.  </li>
+      <li>The local part consists of ascii characters and .:/; 
+
+        <p>
+          Note that '=,' are not currently allowed - a future version may support the jmx syntax by using quotes to separate the local part from the property and value ( in .properties mode we must use '=' to separate the value from type, local name and property name ).
+        </p>
+      </li>
+      <li>The property is a simple name, with no dots. </li>
+      <li>A simple form of substitution is used in values, where $(property) will be replaced with a previously defined setting. If the property has ':' in it, it'll take the value from the object, if not it'll take the value from a global map.
+      </li>
+    </ul>
+  </p>
+</section>
+
+<section name="Common properties">
+  <p>
+    Common properties for all components
+  </p>
+  <p>
+    <table>
+      <tr>
+        <th>Property name</th>
+        <th>Default</th>
+        <th>Description</th>
+      </tr>
+      <tr>
+        <td>disabled</td>
+        <td>0 (false)</td>
+        <td>"disabled" state for the component, 1=true 0=false</td>
+      </tr>
+      <tr>
+        <td>debug</td>
+        <td>0 (false)</td>
+        <td>Debug level for the component, 0=disabled, 1..10 enabled. Higher levels
+            generate more debug information.</td>
+      </tr>
+      <tr>
+        <td>ver (short for, and formerly known as, version)</td>
+        <td>0</td>
+        <td>'Generation' of the component config. Important for runtime reconfiguration.
+            If you edit the config file or set the shmem properties, you need to also
+            upgrade the version of the modified component. The config layer will detect
+            the change and call the setter method.</td>
+      </tr>
+    </table>
+  </p>
+</section>
+
+        <section name="workerEnv">
+            <p>This component represent the core jk2, it has the default logger for all other components. Is the central controller, it controls global properties
+and  provides access to all other objects</p>
+            <p>
+                <table>
+                    <tr>
+                        <th>Property name</th>
+                        <th>Default</th>
+                        <th>Description</th>
+                    </tr>
+                    <tr>
+                        <td>logger</td>
+                        <td>logger</td>
+                        <td>Default loger used by jk2 components, can be changed in the config file, normally it defaults to "logger" the Alias for the default logger for the Server/platform.</td>
+                    </tr>
+                    <tr>
+                        <td>sslEnable</td>
+                        <td>1 (true)</td>
+                        <td>Enable handling of SSL</td>
+                    </tr>
+                    <tr>
+                        <td>timing</td>
+                        <td>0</td>
+                        <td>Will jk2 get request timing (needs APR?)</td>
+                    </tr>
+                    <tr>
+                        <td>forwardKeySize</td>
+                        <td>not set</td>
+                        <td>Enable filling of javax.servlet.request.key_size</td>
+                    </tr>
+                    <tr>
+                        <td>forwardURICompat</td>
+                        <td>set</td>
+                        <td>Pass the URI untouched.</td>
+                    </tr>
+                    <tr>
+                        <td>forwardURICompatUnparsed</td>
+                        <td>not set</td>
+                        <td>Parse the URI until the '?'.</td>
+                    </tr>
+                    <tr>
+                        <td>forwardURIEscaped</td>
+                        <td>not set</td>
+                        <td>Pass the URI escaped.</td>
+                    </tr>
+                    <tr>
+                        <td>noRecoveryIfRequestSent</td>
+                        <td>set</td>
+                        <td>No recovery in LB mode if a Tomcat allready received the request.</td>
+                    </tr>
+                    <tr>
+                        <td>noRecoveryIfHeaderSent</td>
+                        <td>set</td>
+                        <td>No recovery in LB mode if a Tomcat allready start to send reply to client.</td>
+                    </tr>
+                </table>
+            </p>
+            <p>Only one of the forwardURI option could be used it replaces the default value.</p>
+        </section>
+        <section name="config">
+            <p>The config component, hold the detail of the conifg system, such config file name, create global defines</p>
+            <p>
+                <table>
+                    <tr>
+                       <th>Property name</th>
+                       <th>Default</th>
+                       <th>Description</th>
+                    </tr>
+                    <tr>
+                        <td>file</td>
+                        <td>${serverRoot}/conf/workers2.properties</td>
+                        <td>Location of the workers2.properties file</td>
+                    </tr>
+                    <tr>
+                        <td>debug</td>
+                        <td>0</td>
+                        <td>Set the debug level of the config component</td>
+                    </tr>
+                    <tr>
+                        <td>debugEnv</td>
+                        <td>0</td>
+                        <td>Set the debug level of the hidden env component </td>
+                    </tr>
+                </table>
+            </p>
+        </section>
+        <section name="uriMap"/>
+        <section name="shm">
+            <p>Shared memory descriptor</p>
+            <p>
+                <table>
+                    <tr>
+                        <th>Property name</th>
+                        <th>Default</th>
+                        <th>Description</th>
+                    </tr>
+                    <tr>
+                        <td>file</td>
+                        <td>No default value</td>
+                        <td>Name of the file that will be mmapped to use as shared memory, If set to 'anonymous' use the anonymous shered memory</td>
+                    </tr>
+                    <tr>
+                        <td>size</td>
+                        <td>No default value</td>
+                        <td>Deprecated. Size of the file.</td>
+                    </tr>
+                    <tr>
+                        <td>slots</td>
+                        <td>256</td>
+                        <td>Number of shared memory slots. Set to the number of child processes</td>
+                    </tr>
+                    <tr>
+                        <td>useMemory</td>
+                        <td>0</td>
+                        <td>Use process memory instead of shared memory. Useful for single child mpm's</td>
+                    </tr>
+                </table>
+            </p>
+        </section>
+        <section name="uri">
+            <p>A uri stores a pattern that is used
+ to match requests to workers, and asociated properties</p>
+            <p>If the uri name doesn't have a slash then it is considered as a virtual host
+            directive. Uri name can have a virtual host name and(or) port associated with. Format
+            of such a name is <b>hostname</b> or <b>hostname:port</b> where hostname
+            is virtual server name and the port is vitual server port number. The port number
+            is used only for the non default server ports.</p>
+            <p>
+            Special case is a default server named as <b>[uri:*]</b> that is used when the virtual
+            host cannot be found inside the configuration. All the uri directives not containing
+            host name belongs to this default server making global mappings.
+            </p>
+            <p>
+            Addition wild char scheme id <b>[uri:*:port]</b> that is used when you wish to
+            match any virtual host having specified (non-default) port number, like [uri:*:443].
+            This will map all the virtual hosts no mather what is their name but that have port number 443.            
+            </p>
+            <p>
+            The order how the host names are resolved is :
+            <ul>
+                <li>Exact host name and optional non default port number</li>
+                <li>Alias matching host name and port number</li>
+                <li>*:port if the port is other then default</li>
+                <li>Default server</li>
+            </ul>
+            </p>
+            <p>
+                <table>                
+                    <tr>
+                        <th>Property name</th>
+                        <th>Default</th>
+                        <th>Description</th>
+                    </tr>
+                    <tr>
+                        <td>group</td>
+                        <td>lb:lb (The default loadbalancer)</td>
+                        <td>Name of the tomcat group or worker that will process the request corresponding to the uri. This used
+                            to be called 'worker'</td>
+                    </tr>
+                    <tr>
+                        <td>context</td>
+                        <td/>
+                        <td>the context path for this uri component (webapp style).</td>
+                    </tr>
+                    <tr>
+                        <td>servlet</td>
+                        <td/>
+                        <td>Servlet path for this mapping</td>
+                    </tr>
+                    <tr>
+                        <td>alias</td>
+                        <td/>
+                        <td>server name alias. This setting should only be used for 
+                            host uris like [uri:myHost:myPort] ( i.e. no /) </td>
+                    </tr>
+                </table>
+            </p>
+        </section>
+        <section name="vm">
+            <p>Represents the JVM when used as inprocess container
+            </p>
+            <p>
+                <table>
+                    <tr>
+                        <th>Property name</th>
+                        <th>Default</th>
+                        <th>Description</th>
+                    </tr>
+                    <tr>
+                        <td>JVM</td>
+                        <td>(Autoguess)</td>
+                        <td>JVM to use for this vm</td>
+                    </tr>
+                    <tr>
+                        <td>OPT</td>
+                        <td/>
+                        <td>Option to pass to this vm, this is a multivalued property</td>
+                    </tr>
+                    <tr>
+                        <td>classpath</td>
+                        <td/>
+                        <td>-Djava.class.path 0ption to pass to this vm, this is a multivalued property</td>
+                    </tr>
+                </table>
+            </p>
+        </section>
+        <section name="channels">
+            <p>A channel represents a transport protocol, connecting 2
+sides  for RPC communication. The most common and standard is the tcp socket.
+Other  important  channels are unix socket and jni</p>
+            <subsection name="channel.un">
+                <p>
+    AF_UNIX socket. Only on UNIX like platform. These sockets are faster
+    than "normal" sockets but they are limited to the machine. 
+</p>
+                <p>
+                    <table>
+                        <tr>
+                            <th>Property name</th>
+                            <th>Default</th>
+                            <th>Description</th>
+                        </tr>
+                        <tr>
+                            <td>file</td>
+                            <td>Name of socket</td>
+                            <td>Name of the socket file (It is created by the Tomcat ChannelUn)</td>
+                        </tr>
+                    </table>
+                </p>
+            </subsection>
+            <subsection name="channel.socket">
+                <p>
+    Defines a communication transport to a remote Servlet Engine. </p>
+
+<p>The name of the channels should be: channel.socket:HOST:PORT, where HOST and PORT are the 
+tomcat Ajp location.  You could use other names and explicitely set HOST and PORT, but this
+is discouraged. In most cases, you don't need to set any other config - just add a line like
+[channel.socket:localhost:8009] and all other things will have good defaults. 
+</p>
+<p>
+NB: Starting with JK2 2.0.4, APR is mandatory and the channel.socket use APR (previously
+called channel.apr).
+</p>
+<p>
+Tomcat Engine must be set with jvmRoute="HOST:PORT", to match the default tomcatId of the channel.
+</p>
+                <p>
+                    <table>
+                        <tr>
+                            <th>Property name</th>
+                            <th>Default</th>
+                            <th>Description</th>
+                        </tr>
+                        <tr>
+                            <td>port</td>
+                            <td>extracted from the component name</td>
+                            <td>Port where Tomcat is listening. It is automatically extracted from the name - you shouldn't have to specify it explicitely.</td>
+                        </tr>
+                        <tr>
+                            <td>host</td>
+                            <td>extracted from the component name</td>
+                            <td>Remote host. You should use the name, no need to override it</td>
+                        </tr>
+                        <tr>
+                            <td>graceful</td>
+                            <td>0</td>
+                            <td>If 1, only requests for existing sessions will be forwarded</td>
+                        </tr>
+                        <tr>
+                            <td>keepalive</td>
+                            <td>0</td>
+                            <td>? </td>
+                        </tr>
+                        <tr>
+                            <td>timeout</td>
+                            <td>0 (infinite)</td>
+                            <td>Socket timeout for sending and receiving</td>
+                        </tr>
+                        <tr>
+                            <td>ndelay</td>
+                            <td>0</td>
+                            <td>If set to 1 Disables the Nagle algorithm for send coalescing</td>
+                        </tr>
+                        <tr>
+                            <td>lb_factor</td>
+                            <td>1</td>
+                            <td>Load balancing factor to use. The lower the lb_factor the more often that tomcat will get requests but see
+                                "level" below.</td>
+                        </tr>
+                        <tr>
+                            <td>level</td>
+                            <td>1</td>
+                            <td>Worker Priority.  Valid values are 0-3.  The functioning workers with the lowest level
+                                will be checked for the lowest lb_value, and if found will be run.  The upper level workers are
+                                only checked upon failure of all workers on ALL of the levels below them.  This is very 
+                                useful for implementing failover withing a cluster.  You could set the tomcat server local 
+                                on the same machine as the apache instance to level 0 and all of the other workers to level 1.
+                                This would cause apache to only use the external tomcats when the local tomcat is down.</td>
+                        </tr>
+                        <tr>
+                            <td>group</td>
+                            <td>lb</td>
+                            <td>loadbalanced groups to which this channel and the associated worker will be added, multivalued. You need to set it only if you have an advanced setup with multiple clusters.</td>
+                        </tr>
+                        <tr>
+                            <td>tomcatId</td>
+                            <td>Automatically set to the localname ( host:port )</td>
+                            <td>Must match the JVM route on tomcat the server.xml Engine element, for load balancing</td>
+                        </tr>
+                        <tr>
+                            <td>route</td>
+                            <td>Automatically set to the localname ( host:port )</td>
+                            <td>Same as tomcatId</td>
+                        </tr>                        
+                    </table>
+                </p>
+            </subsection>
+            <subsection name="channel.jni">
+                <p>The jni channel, used if tomcat is started inprocess</p>
+            </subsection>
+        </section>
+        <section name="workers">
+            <p>
+             For the moment 4 worker types are supported: worker.jni,ajp13,status,lb.
+            </p>
+            <subsection name="worker.jni">
+                <p>worker used in inprocess, holds the details of the Tomcat class to startup, and parameters to pass</p>
+                <p>There are two predefined jni workers <b>onStartup</b> and <b>onShutdown</b>. Those two workers are executed
+                during startup and shutdown phase of the connector. Both must exists in the configuration to be able to start
+                and shutdown Tomcat.
+                </p>
+                <p>
+                    <table>
+                        <tr>
+                            <th>Property name</th>
+                            <th>Default</th>
+                            <th>Description</th>
+                        </tr>
+                        <tr>
+                            <td>class</td>
+                            <td>org/apache/jk/apr/TomcatStarter</td>
+                            <td>class that holds the main method called to start tomcat</td>
+                        </tr>
+                        <tr>
+                            <td>ARG</td>
+                            <td/>
+                            <td>Arguments to pass to main method when called</td>
+                        </tr>
+                        <tr>
+                            <td>stdout</td>
+                            <td>NULL</td>
+                            <td>file to redirect Standard output from the java process</td>
+                        </tr>
+                        <tr>
+                            <td>stderr</td>
+                            <td>NULL</td>
+                            <td>file to redirect Standard output from the java process </td>
+                        </tr>
+                    </table>
+                </p>
+            </subsection>
+            <subsection name="ajp13">
+                <p>Default worker.  If a property is in both the worker and the channel, you only need to define it in one place.
+                    The channel passes down the properties to its worker.  (at least in the ajp13-channel.socket linkage)</p>
+                <p>
+                    <table>
+                        <tr>
+                            <th>Property name</th>
+                            <th>Default</th>
+                            <th>Description</th>
+                        </tr>
+                        <tr>
+                            <td>secretkey</td>
+                            <td>NULL</td>
+                            <td>
+                                <b>Magic:</b> The secret key will be set automatically on the associated
+    worker.
+  </td>
+                        </tr>
+                        <tr>
+                            <td>tomcatId</td>
+                            <td>Automatically set to the localname ( host:port )</td>
+                            <td>Must match the JVM route on the tomcat server.xml Engine element, for load balancing</td>
+                        </tr>
+                        <tr>
+                            <td>route</td>
+                            <td>Automatically set to the localname ( host:port )</td>
+                            <td>Same as tomcatId</td>
+                        </tr>
+                        <tr>
+                            <td>group</td>
+                            <td>lb</td>
+                            <td>loadbalanced groups to which this channel and the associated worker will be added, multivalued. You need to set it only if you have an advanced setup with multiple clusters.</td>
+                        </tr>
+                        <tr>
+                            <td>lb_factor</td>
+                            <td>1</td>
+                            <td>Load balancing factor to use. The lower the lb_factor the more often that tomcat will get requests but see
+                                "level" below.</td>
+                        </tr>
+                        <tr>
+                            <td>level</td>
+                            <td>1</td>
+                            <td>Worker Priority.  Valid values are 0-3.  The functioning workers with the lowest level
+                                will be checked for the lowest lb_value, and if found will be run.  The upper level workers are
+                                only checked upon failure of all workers on ALL of the levels below them.  This is very 
+                                useful for implementing failover withing a cluster.  You could set the tomcat server local 
+                                on the same machine as the apache instance to level 0 and all of the other workers to level 1.
+                                This would cause apache to only use the external tomcats when the local tomcat is down.</td>
+                        </tr>
+                        <tr>
+                            <td>channel</td>
+                            <td/>
+                            <td>Communication channel used by the worker.  Use the full name of the channel (everything between the []'s).</td>
+                        </tr>
+                        <tr>
+                            <td>max_connections</td>
+                            <td>0 (unlimited)</td>
+                            <td>Maximum number of currently used endpoints.
+                                If the specified number is reached then the load balancer has the chance
+                                to try another worker. This is very useful in situations when having multiple
+                                servers and you wish to finer grade the lb_factor.
+                            </td>
+                        </tr>
+                        <tr>
+                            <td>connectTimeout</td>
+                            <td>0 (no timeout)</td>
+                            <td>With such timeout set, the web-server will send a CPING request just after physical connect to the remote Tomcat 
+                                and will wait for a CPONG reply for the connectTimeout milliseconds, a guarantee that the remote Tomcat is not hang.
+                                Side effect, this round trip add a little delay at connection time and require a recent AJP13 implementation, 
+                                with support for CPING/CPONG command.
+                            </td>
+                        </tr>
+                        <tr>
+                            <td>replyTimeout</td>
+                            <td>0 (no timeout)</td>
+                            <td>With such timeout set, the web-server will wait for Tomcat reply to a forwarded request for replyTimeout milliseconds.
+                                Another guarantee that the remote Tomcat is not hang.
+                                Warning, if you have 'normal' long running processes on Tomcat side, you shouldn't use this feature to avoid
+                                invalid errors reports or set the timeout accordingly.
+                            </td>
+                        </tr>
+                        <tr>
+                            <td>prepostTimeout</td>
+                            <td>0 (no timeout)</td>
+                            <td>With such timeout set, the web-server will send a CPING request just before forwarding the request to the remote Tomcat 
+                                and will wait for a CPONG reply for the prepostTimeout milliseconds, a guarantee that the remote Tomcat is not hang.
+                                Side effect, this round trip add a little delay in forwarding request and require a recent AJP13 implementation, 
+                                with support for CPING/CPONG command.
+                            </td>
+                        </tr>
+                    </table>
+                </p>
+            </subsection>
+            <subsection name="status">
+                <p>An optional worker that outputs (HTML) pages with useful information to monitor JK2.</p>
+                <p>To create the worker, add a [status:] or [status:'a name'] section.</p>
+                <p>The status worker needs no 'local' name, although one can be used if desired.</p>
+                <p>To access the worker, add a [uri] section with the group= assigned to this worker.</p>
+                <p>The status worker has the following additional properties:
+                    <table>
+                        <tr>
+                            <th>Property name</th>
+                            <th>Default</th>
+                            <th>Description</th>
+                        </tr>
+                        <tr>
+                            <td>styleMode</td>
+                            <td>0 (None)</td>
+                            <td>Defines if or how the status worker will apply a Style Sheet to returned pages.</td>
+                        </tr>
+                        <tr>
+                            <td>stylePath</td>
+                            <td>NULL</td>
+                            <td>For styleMode=2 or 3, where to find the Style Sheet file.</td>
+                        </tr>
+                    </table>
+                </p>
+                <p>The syleMode setting accepts the following values:
+                    <table>
+                        <tr>
+                            <th>styleMode value</th>
+                            <th>Description</th>
+                        </tr>
+                        <tr>
+                            <td>0</td>
+                            <td>No Style settings are used. (Default)</td>
+                        </tr>
+                        <tr>
+                            <td>1</td>
+                            <td>Use the built-in Default Style Sheet. It is presented as an 'Internal Style Sheet' to HTML pages.</td>
+                        </tr>
+                        <tr>
+                            <td>2</td>
+                            <td>Use stylePath as a URI context to an external Style Sheet file to be returned by the Web Server.</td>
+                        </tr>
+                        <tr>
+                            <td>3</td>
+                            <td>Use stylePath as a file-system reference to a Style Sheet file. It is presented as an 'Internal Style
+                                Sheet' to HTML pages.</td>
+                        </tr>
+                    </table>
+                </p>
+                <p>If the stylePath has not been set, styleMode=2 and 3 are ignored.</p>
+                <p>The sylePath setting accepts the following values:
+                    <table>
+                        <tr>
+                            <th>styleMode value</th>
+                            <th>stylePath Description</th>
+                        </tr>
+                        <tr>
+                            <td>2</td>
+                            <td>A URI context to a file (e.g  /styles/jkstatus.css). It must begin with '/' and include the file name.</td>
+                        </tr>
+                        <tr>
+                            <td>3</td>
+                            <td>A file-system path (suitable for the OS in use) plus file name. Also ${serverRoot}/conf/'file name'
+                                allows the file to be located in Apache's conf directory.</td>
+                        </tr>
+                    </table>
+                </p>
+                <p>If the Style file cannot be found, Mode 2 and 3 record Apache log entries.</p>
+                <p>For styleMode=2 and 3, changes in the Style Sheet are effective on the next access to the status worker.</p>
+            </subsection>
+            <subsection name="lb">
+                <p>Loadbalanced worker</p>
+                <p>
+                    <table>
+                        <tr>
+                            <th>Property name</th>
+                            <th>Default</th>
+                            <th>Description</th>
+                        </tr>
+                        <tr>
+                            <td>worker</td>
+                            <td/>
+                            <td/>
+                        </tr>
+                        <tr>
+                            <td>noErrorHeader</td>
+                            <td>1 (true)</td>
+                            <td>If set, jk2 won't touch the headers in case of error and will let for example Apache present the ErrorDocument via mod_alias. 
+                            </td>
+                        </tr>
+                        <tr>
+                            <td>noWorkerMsg</td>
+                            <td/>
+                            <td/>
+                        </tr>
+                        <tr>
+                            <td>noWorkerCode</td>
+                            <td>503</td>
+                            <td/>
+                        </tr>
+                        <tr>
+                            <td>hwBalanceErr</td>
+                            <td/>
+                            <td/>
+                        </tr>
+                        <tr>
+                            <td>timeout</td>
+                            <td>0 (disabled)</td>
+                            <td>If all the workers are in the error state, probably by Tomcat
+refusing any new connections due to the overload, you can set the timeout forcing lb to wait that some
+worker becomes available, instead of immediately returning error to the client. This is very useful in
+situations with high peek load. The timeout should be set to the maximum application call time, but
+not less then 1 second.
+                            </td>
+                        </tr>
+                        <tr>
+                            <td>attempts</td>
+                            <td>3</td>
+                            <td>Number of attempts that lb will try on each worker before
+                            giving up.
+                            </td>
+                        </tr>
+                        <tr>
+                            <td>recovery</td>
+                            <td>60 (seconds)</td>
+                            <td>Time to wait before retrying to see if the worker came out
+                            of the error state.
+                            </td>
+                        </tr>                        
+                        <tr>
+                            <td>stickySession</td>
+                            <td>1 (true)</td>
+                            <td>Sessions stick to the same worker, 1=true 0=false
+                            </td>
+                        </tr>
+                    </table>
+                </p>
+            </subsection>
+        </section>
+        <section name="loggers">
+            <p>Any connector based on jk2, at least has a default logger, that can be reached using the "logger" alias, the logger used is the more appropiate for the plataform/server combination, Apache2 under in any platform has logger.apache2 as default, IIS on his only platform uses logger.win32, and Any apache 1 install uses logger.file as default.., the config file lets you change that defaults, you can end using logger.file in IIs i.e</p>
+            <p>The properties shared by all loggers are:
+<table>
+                    <tr>
+                        <th>Property name</th>
+                        <th>Default</th>
+                        <th>Description</th>
+                    </tr>
+                    <tr>
+                        <td>level</td>
+                        <td>INFO</td>
+                        <td>Text of the log level. Strings supported: EMERG, ERROR, INFO, DEBUG</td>
+                    </tr>
+                </table>
+            </p>
+            <subsection name="logger.file">
+                <p>
+                    <table>
+                        <tr>
+                            <th>Property name</th>
+                            <th>Default</th>
+                            <th>Description</th>
+                        </tr>
+                        <tr>
+                            <td>file</td>
+                            <td>${serverRoot}/logs/jk2.log</td>
+                            <td>
+    Log file.  XXX you may be able to change this at runtime,
+               to implement rolling.
+  </td>
+                        </tr>
+                    </table>
+                </p>
+            </subsection>
+            <subsection name="logger.win32">
+                <p>logger used in the IIS server by default, it ends at native Application Event Log.</p>
+            </subsection>
+            <subsection name="logger.apache2">
+                <p>Logger used in Apache2 servers, it normally in ends in error.log </p>
+            </subsection>
+        </section>
+    <section name="How Load Balancing Works">
+        <p>The lb_factor and level properties combine to deliver a flexible static load balancing solution.
+            The level property is used to create up to four pools over workers in descending priority and lb_factor
+            is used to weight the workers within a pool.  The lower the level the more likely the worker is to be used
+            and the lower the lb_factor the more likely the worker is to be used.  Here is how the algorithm is
+            currently implemented:</p>
+        <p>
+(Assume that every worker's lb_value is set to their lb_factor)<br/>
+<br/><source>
+if (loadbalancer has a route) and (stickysession=1){<br/>
+    worker= loadbanlancer.getWorkerForRoute(route)<br/>
+    if worker.hasRedirect<br/>
+        redirect=worker.redirect<br/>
+    else if !worker.hasError<br/>
+        return worker<br/>
+    }<br/>
+<br/>
+selectedWorker=null<br/>
+foreach lb_level {<br/>
+    foreach worker in the level {<br/>
+        if worker.isNotWorking<br/>
+            continue<br/>
+        if selectedWorker == null<br/>
+            selectedWorker = worker<br/>
+            continue<br/>
+        if worker.lb_value &lt; selectedWorker.lb_value<br/>
+            selectedWorker = worker<br/>
+            continue<br/>
+    }<br/>
+    if selectedWorker !=null<br/>
+        break<br/>
+}<br/>
+<br/>
+Reenable workers in error state if the timeout has passed()<br/>
+<br/>
+if selectedWorker !=null {<br/>
+    selectedWorker.lb_value += selectedWorker.lb_factor<br/>
+    if selectedWorker.lb_value > 255 {<br/>
+        foreach worker in load_balancer.workers[selectedWorker.level]<br/>
+            worker.lb_value=worker.lb_factor<br/>
+        }<br/>
+    }<br/>
+    return selectedWorker<br/>
+}<br/></source>
+</p>
+            
+    </section>
+</document>

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/jk2/configwebex.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/jk2/configwebex.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/jk2/configwebex.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,108 @@
+<?xml version="1.0"?>
+<document>
+<copyright>
+   Copyright 1999-2004 The Apache Software Foundation
+ 
+   Licensed 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.
+</copyright>
+<properties>
+<title>Examples</title>
+<author email="cmanolache at yahoo.com">Costin Manolache</author>
+<author email="jfrederic.clere at fujitsu-siemens.com">Jean-Frederic Clere</author>
+<date>$Date: 2004-03-03 22:46:34 -0600 (Wed, 03 Mar 2004) $</date>
+</properties>
+    <section name="Sockets">
+        <p>
+The examples below are working when the Tomcat is configured according the 
+examples described in the configtc file.
+</p>
+        <subsection name="/example using normal socket">
+            <p> 
+Map /examples to the Tomcat /examples context using a normal socket. Note the 
+IP instead localhost (The JVM listens on the IPV4 address not no the IPV6).
+</p>
+            <p>
+                <source>
+[shm]
+file=${serverRoot}/logs/shm.file
+size=1048576
+
+# Example socket channel, override port and host.
+[channel.socket:localhost:8019]
+port=8019
+host=127.0.0.1
+
+# define the worker
+[ajp13:localhost:8019]
+channel=channel.socket:localhost:8019
+
+# Uri mapping
+[uri:/examples/*]
+worker=ajp13:localhost:8019
+</source>
+            </p>
+        </subsection>
+        <subsection name="/jkstatus">
+            <p>
+Map /jkstatus to the status worker.
+</p>
+            <p>
+                <source>
+[shm]
+file=${serverRoot}/logs/shm.file
+size=1048576
+
+# define the worker
+[status:status]
+
+# Uri mapping
+[uri:/jkstatus/*]
+worker=status:status
+</source>
+            </p>
+        </subsection>
+        <subsection name="/example using AF_UNIX socket">
+            <p>
+Map /examples to the Tomcat /examples context using a AF_UNIX socket.
+Socket file is create by the Tomcat becarefull when the Web Server runs in
+a different user than the Tomcat with the permission of the socket file:
+<source>
+apache20 at jfcexpert:~/apache> ls -l /home1/jakarta/jakarta-tomcat-4.1/dist/work/jk2.socket
+srw-rw----    1 jakarta  jakarta         0 Jun 20 08:27 /home1/jakarta/jakarta-tomcat-4.1/dist/work/jk2.socket
+</source>
+Here the Tomcat user and the Web Server user must be in the same group.
+</p>
+            <p>
+                <source>
+[shm]
+file=${serverRoot}/logs/shm.file
+size=1048576
+
+# Example unixsocket channel.
+[channel.un:unixsocket]
+file=/home1/jakarta/jakarta-tomcat-4.1/dist/work/jk2.socket
+
+# define the worker
+[ajp13:unixsocket]
+channel=channel.un:unixsocket
+
+# Uri mapping
+[uri:/examples/*]
+worker=ajp13:unixsocket
+</source>
+            </p>
+        </subsection>
+    </section>
+    <section name="JNI">
+    </section>
+</document>

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/jk2/davhowto.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/jk2/davhowto.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/jk2/davhowto.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,67 @@
+<?xml version="1.0"?>
+<document>
+<properties>
+<title>Apache 2.x/mod-dav - Tomcat/jk2 - HOWTO</title>
+<author email="jfrederic.clere at fujitsu-siemens.com">Jean-Frederic Clere</author>
+<date>Wed Mar  3 10:31:06 CET 2004</date>
+</properties>
+<section name="Purpose">
+<p>
+Use mod_dav to modify JSP pages.
+</p>
+</section>
+
+<section name="extract of httpd.conf">
+<p>
+The Alias is just for confort ;-)
+<source>
+  Alias /examples/jsp-source /home/jfclere/jakarta-tomcat-4.1.24/webapps/examples/jsp
+  &lt;Location /examples/jsp-source&gt;
+    Dav On
+ 
+    AuthType Basic
+    AuthName DAV
+    AuthUserFile user.passwd
+ 
+    &lt;LimitExcept GET OPTIONS&gt;
+      require user admin
+    &lt;/LimitExcept&gt;
+  &lt;/Location&gt;
+
+  &lt;LocationMatch "/*.jsp"&gt;
+    JkUriSet worker ajp13:localhost:8009
+  &lt;/LocationMatch&gt;
+
+</source>
+The LocationMatch only maps the *.jsp files.
+To have also the images it is possible to the DefaultServlet by mapping /examples.
+<source>
+  &lt;Location /examples&gt;
+    JkUriSet worker ajp13:localhost:8009
+  &lt;/Location&gt;
+</source>
+Or to get the images served by httpd and not by Tomcat.
+<source>
+  Alias /examples/images /home/jfclere/jakarta-tomcat-4.1.24/webapps/examples/images
+</source>
+<source>
+</source>
+</p>
+</section>
+<section name="extract of workers2.properties">
+<p>
+The worker ajp13:localhost:8009 of the JkUriSet Directive has to be defined
+in workers2.properties.
+<source>
+# Example socket channel, override port and host.
+[channel.socket:localhost:8009]
+port=8009
+host=127.0.0.1
+ 
+# define the worker
+[ajp13:localhost:8009]
+channel=channel.socket:localhost:8009
+</source>
+</p>
+</section>
+</document>

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/jk2/installhowto.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/jk2/installhowto.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/jk2/installhowto.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,262 @@
+<?xml version="1.0"?>
+<document>
+<copyright>
+   Copyright 1999-2004 The Apache Software Foundation
+ 
+   Licensed 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.
+</copyright>
+
+<properties>
+  <title>Installation of jk2 in the Web Server</title>
+
+  <author email="jfrederic.clere at fujitsu-siemens.com">Jean-Frederic Clere</author>
+  <author email="andy at tagish.com">Andy Armstrng</author>
+  <author email="yoavs at apache.org">Yoav Shapira</author>
+
+  <date>$Date: 2004-08-11 13:06:27 -0500 (Wed, 11 Aug 2004) $</date>
+</properties>
+
+  <section name="Installation">
+    <p>
+      The actual build mechanism creates the dso files in the
+      build/jk2/${servername} subdirectory of the jakarta-tomcat-connectors/jk.
+      When configure --with-jni is used 2 dso files are created.
+      These files have to be copied in the right location of the web server
+      installation.
+    </p>
+    <p>
+      JNI support in JK2 require APR, which is provded in Apache 2.0, and is
+      available for many platforms, so Apache 1.3, IIS and NES/iPlanet should be
+      able to use it
+    </p>
+    <subsection name="Apache 1.3">
+      <p>
+        In the following example Apache-1.3 is installed in
+        /home/apache13/ and the commands are executed in
+        the jakarta-tomcat-connectors directory.
+      </p>
+      <p>
+        Apache 1.3 require APR, and if APR has been built with pthread support
+        and your Apache 1.3 wasn't (general case in Unix platforms) you should :
+        <ul>
+        <li>
+        Rebuild Apache 1.3 with pthread support (recommanded)
+        </li>
+        <li>
+        Add the LoadFile /usr/lib/pthread.so in beginning of your httpd.conf
+        </li>
+        </ul>
+      </p>
+      <p>
+        You should also ensure that the linker will be able to locate the apr shared libraries,
+        <code>libapr.so</code>, and <code>libaprutil.so</code>, make sure they have been installed
+        in linker search locations.
+      </p>
+      <screen>
+        <note>Copy the dso files in the modules location:</note>
+        <type>cp jk/build/jk2/apache13/mod_jk2.so /home/apache13/modules</type>
+        <note>Copy jkjni.so if you're using JNI</note>
+        <type>cp jk/build/jk2/apache13/jkjni.so /home/apache13/modules</type>
+        <note>You may have to add pthread library in the httpd.conf:</note>
+        <read>LoadFile /usr/lib/pthread.so</read>
+        <note>Add mod_jk2 loading in the httpd.conf</note>
+        <read>LoadModule jk2_module modules/mod_jk2.so</read>
+      </screen>
+    </subsection>
+    <subsection name="Apache 2">
+      <p>
+        In the following example Apache-2.0 is installed in
+        /home/apache20/apache40 and the commands are executed in
+        the jakarta-tomcat-connectors directory.
+      </p>
+      <screen>
+        <note>Copy the dso files in the modules location:</note>
+        <type>cp jk/build/jk2/apache2/mod_jk2.so /home/apache20/apache40/modules</type>
+        <note>Copy jkjni.so if you're using JNI</note>
+        <type>cp jk/build/jk2/apache2/jkjni.so /home/apache20/apache40/modules</type>
+        <note>Add mod_jk2 loading in the httpd.conf:</note>
+        <read>LoadModule jk2_module modules/mod_jk2.so</read>
+      </screen>
+    </subsection>
+    <subsection name="IIS">
+        <p>A pre-built version of the ISAPI redirector server plugin, isapi_redirector2.dll,
+        is available under the win32/i386 directory of jakarta-tomcat-connectors distribution.
+        You can also build a copy locally from the source present in jakarta-tomcat-connectors
+        distribution.<br />The Tomcat redirector requires three entities:
+            <ul>
+            <li>
+            <b>isapi_redirector2.dll</b> - The IIS server plugin, either obtain a pre-built DLL or build it yourself (see the build section).
+            </li><li>
+            <b>workers2.properties</b> - A file that describes the host(s) and port(s) used by the workers (Tomcat processes). 
+                A sample workers2.properties can be found under the conf directory.
+            </li><li>
+            <b>jk2.properties</b> - A configuration file used by mod_jk2 on the Tomcat side.
+            </li>
+            </ul>
+        </p>
+        <p>
+            <ol><li>In the registry, create a new registry key named
+            <b>"HKEY_LOCAL_MACHINE\SOFTWARE\Apache Software Foundation\Jakarta Isapi Redirector\2.0"</b>
+            </li><li>
+            Add a string value with the name <b>serverRoot</b> and a value which is a full path
+            to your Tomcat installation (for example <b>c:\jakarta-tomcat</b>).  If Tomcat is installed
+            on a different server, this entry must point to the location (directory) where the
+            workers2.properties file resides.
+            </li><li>
+            Add a string value with the name <b>extensionUri</b> and a value of <b>/jakarta/isapi_redirector2.dll</b>
+            </li><li>
+            Add a string value with the name <b>workersFile</b> and a value which is the full path 
+            to your workers2.properties file (for example <b>c:\jakarta-tomcat\conf\workers2.properties</b>)
+            </li><li>
+            Add a string value with the name <b>logLevel</b> and a value for your log level 
+            (can be DEBUG, INFO or ERROR).
+            </li><li>Using the IIS management console, add a new virtual directory to your IIS web site.
+            The name of the virtual directory must be jakarta. 
+            Its physical path should be the directory where you placed isapi_redirector2.dll 
+            While creating this new virtual directory assign it with execute access.
+            </li><li>
+            Using the IIS management console, add isapi_redirector2.dll as a filter in your IIS web site. 
+            The name of the filter should reflect its task (I use the name jakarta), 
+            its executable must full path to the isapi_redirector2.dll. 
+            </li>            
+            </ol>        
+        </p>
+        <p>Install using provided script <b>install4iis.js</b><br/>
+        This script creates the virtual directory and installs ISAPI filter for Default webserver<br/>
+        <i>C:\Program Files\Apache Software Foundation\Tomcat 5.0</i>
+        <screen>
+        <note>Open the command prompt and cd to bin folder</note>
+        <type>cd C:\Program Files\Apache Software Foundation\Tomcat 5.0\bin</type>
+        <note>Copy the isapi_redirector2.dll and install4iis.js to that folder</note>
+        <type>cscript install4iis.js</type>
+        </screen>
+        </p>
+        <p>        
+        You may modify the default installation using various command line options.
+        To see what the options are type <b>csrcipt install4iis.js -h</b>        
+        </p>
+        <p>
+        That's all, you should now start Tomcat and ask IIS to serve you the /examples context. 
+        Try <a href="http://localhost/examples/jsp/index.html">http://localhost/examples/jsp/index.html</a> for example and 
+        execute some of the JSP examples. 
+        </p>        
+    </subsection>
+    <subsection name="Lotus Domino">
+	<p><i>At the time of writing these instruction are applicable to Windows only.
+	As soon as there are versions of the Domino redirector available for other
+	platforms these instructions will be updated.</i></p>
+	
+	<p>If necessary build dsapi_redirector2.dll as per the instructions in the
+	jk/native2/server/dsapi directory. Copy the DLL into the Domino program
+	directory (this is the directory, which may be called something like
+	C:\Lotus\Domino, that contains a file called nlnotes.exe). Shortly we will
+	tell Domino where to find this file, but before we do that we need to make
+	some registry entries. The simplest way is to edit the supplied file
+	dsapi_redirector2.reg, which initially will look like this</p>
+	
+	<screen>
+	    <read>Windows Registry Editor Version 5.00</read>
+  	    <read></read>
+	    <read>[HKEY_LOCAL_MACHINE\SOFTWARE\Apache Software Foundation\Jakarta Dsapi Redirector\2.0]</read>
+	    <read>"serverRoot"="D:\\Works\\Tomcat\\jakarta-tomcat-4.1.27"</read>
+	    <read>"workersFile"="conf\\workers2.properties"</read>
+	    <read>"tomcatStart"="bin\\startup.bat"</read>
+	    <read>"tomcatStop"="bin\\shutdown.bat"</read>
+	    <read>"tomcatTimeout"="30000"</read>
+	</screen>
+
+	<p>Change serverRoot to reflect the location of your Tomcat installation. The
+	other filename parameters can either be relative to serverRoot or absolute
+	paths. Once edited double click on dsapi_redirector2.reg to enter it into the
+	registry.</p>
+
+	<p><b>Starting Tomcat:</b> The last three registry entries above provide
+	commands that the redirector DLL will use to start and stop Tomcat when the
+	Domino http server starts and stops respectively. If you don't require this
+	behaviour these two lines can be omitted (or deleted if you've already placed
+	them in the registry).</p>
+
+	<p><b>The Workers file:</b> If necessary take the sample workers2.properties
+	file from jakarta- tomcat- connectors\jk\conf and place it in the location
+	specified in the registry settings above (typically the conf directory of your
+	Tomcat installation). Edit the file to suit your Tomcat setup.</p>
+
+	<p><b>Configuring Domino:</b> Finally we need to configure Domino to use the
+	DSAPI extension DLL. For those who are unfamiliar with Domino server
+	configuration most of a server's configurable behavior is dictated by a
+	document called the "server document" in a database called the "Public Name
+	and Address Book" or "NAB" for short (N.B. Lotus have renamed the NAB to
+	"Domino Directory" from Domino 5 onwards). Each Domino server will have a NAB
+	(called names.nsf) and each NAB will have a number of server documents
+	including one for the current server. If you have not previously configured a
+	Domino server you may need to refer to the supplied documentation, or you may
+	need to pass this document to your tame Domino administrator.</p>
+
+	<p>Assuming you know your way around a Domino server document what we're going
+	to do is actually quite simple. Open the server document for this server,
+	place it in Edit mode, then locate the DSAPI section and the 'DSAPI filter
+	file names' field on the Internet Protocols tab, HTTP sub- tab. Add
+	"dsapi_redirector2.dll" to the DSAPI field, then save and close the
+	document.</p>
+
+	<p><b>Restart Domino:</b> In order to get these settings to take effect and
+	make sure that you haven't disrupted anything else you should now restart the
+	Domino server. If the server is running as a service and you have changed any
+	relevant system variables (JAVA_HOME, TOMCAT_HOME, CLASSPATH) since the last
+	time you restarted the computer you should do a complete restart now because
+	updates to system variables are not seen by services until after a reboot. If
+	all goes well you should see something like this on the server console when
+	the web server starts up.</p>
+
+	<screen>
+	    <read>14/11/2003 13:02:18   Attempting to start Tomcat: D:\...\startup.bat</read>
+	    <read>Using CATALINA_BASE:   D:\Works\Tomcat\jakarta-tomcat-4.1.27</read>
+	    <read>Using CATALINA_HOME:   D:\Works\Tomcat\jakarta-tomcat-4.1.27</read>
+	    <read>Using CATALINA_TMPDIR: D:\Works\Tomcat\jakarta-tomcat-4.1.27\temp</read>
+	    <read>Using JAVA_HOME:       C:\JBuilder8\jdk1.4</read>
+	    <read>14/11/2003 13:02:18   Apache Tomcat Interceptor (Jakarta/DSAPI/2.0.0) loaded</read>
+	    <read>14/11/2003 13:02:19   HTTP Web Server started</read>
+	</screen>
+
+	<p>At about the same time Tomcat should open in a new window (assuming you
+	enabled the autostart option in the registry settings). You should now be able
+	to visit a URL that is handled by Tomcat. Something like</p>
+
+	<p><code>http://name-of-server/servlet/SnoopServlet</code></p>
+
+	<p>may be available, depending on how Tomcat is configured. If that all works
+	you're done.</p>
+
+	<p><b>Mailing Lists:</b> There are two mailing lists dedicated to the Domino
+	Tomcat redirector:</p>
+
+	<p><a href="http://nomen.tagish.co.uk/mailman/listinfo/domino-tomcat-l">domino-tomcat-l</a></p>
+
+	<p><b>domino-tomcat-l</b> is a general discussion list for issues with the
+	redirector and also wider Tomcat/Domino integration issues such as calling the
+	Domino Java API from a Tomcat servlet. This list is fairly low volume so
+	please subscribe if you're actively using the redirector. If you have an issue
+	with the redirector please post it to the list where it will be seen not only
+	by the author but by other users who may be able to help with any problems.</p>
+
+	<p><a href="http://nomen.tagish.co.uk/mailman/listinfo/domino-tomcat-announce-l">domino-tomcat-announce-l</a></p>
+
+	<p><b>domino-tomcat-announce-l</b> is for announcements about the Domino Tomcat
+	redirector. Mainly this list will be used for new releases but serious
+	bugs will also be posted to it. This list will be very low volume; not more than
+	a few posts per month. For this reason if you'd like to keep track of new redirector versions
+	please subscribe to this list.</p>
+  
+    </subsection>
+  </section>
+</document>

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/jk2/vhosthowto.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/jk2/vhosthowto.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/jk2/vhosthowto.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,610 @@
+<?xml version="1.0"?>
+<document>
+<copyright>
+   Copyright 1999-2004 The Apache Software Foundation
+ 
+   Licensed 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.
+</copyright>
+<properties>
+<title>Apache 2.0.43 - Tomcat 4.1.12 - jk2 - virtual host HOWTO</title>
+<author email="unicoletti at prometeo.it">Umberto Nicoletti</author>
+<date>Tue 22 Oct 2002 11:58:28 AM GMT-5</date>
+</properties>
+<section name="Scenario">
+<ul>
+<li>RedHat Linux 7.2</li>
+<li>Latest 1.4.x Sun JDK</li>
+<li>Tomcat 4.1.12 binary</li>
+<li>Apache 2.0.43 built from source</li>
+<li>jk2 connector binary from jakarta.apache.org</li>
+</ul>
+</section>
+
+<section name="Requirements">
+<p>
+Deploy three (in my case) web applications under three different virtual hosts,
+making the default vhost
+respond to any name and to the bare IP address.
+</p>
+</section>
+
+<section name="Installing JDK">
+	<p>Note: download the jdk, not just the jre!</p>
+<screen>
+<note>
+Uncompress the jdk somewhere in the filesystem.
+I chose /usr/local/:
+</note>
+<type>
+ll /usr/local/
+</type>
+<read>
+drwxr-xr-x    9 root     root         4096 Oct 18 16:37 j2sdk1.4.1_01
+</read>
+<read>
+lrwxrwxrwx    1 root     root           14 Oct 18 16:38 java -> j2sdk1.4.1_01/
+</read>
+</screen>
+<p>
+make a symlink named java to j2sdk1.4.1_01/ so that you can
+easily switch back and forth
+between different jvms. We will use the same trick for apache and tomcat afterwards.
+</p>
+<p>
+Now tell your bash shell where to find java binaries: create a file named java.sh in
+/etc/profile.d with the following content:
+</p>
+<screen>
+<type>
+cat /etc/profile.d/java.sh 
+</type>type>
+<read># set java environment</read>
+<read></read>
+<read>export JAVA_HOME=/usr/local/java</read>
+<read>export PATH=$PATH:$JAVA_HOME/bin</read>
+<read></read>
+<read>export CLASSPATH=$JAVA_HOME/lib</read>
+</screen>
+<p>
+do a chmod:
+</p>
+<screen>
+<note>
+Make java.sh readable and executable by anyone:
+</note>
+<type>
+#chmod 755 /etc/profile.d/java.sh
+</type>
+</screen>
+Now open a new shell and try this:
+<screen>
+<type>
+which java
+</type>
+<read>
+/usr/local/java/bin/java
+</read>
+</screen>
+<p>
+You should get the answer given above. If not chek your environment and make
+sure that java.sh is executed
+when opening a new shell.
+Try to run a java program or the following: java -version.
+</p>
+<p>
+If you don't like this way of installing java please ignore it.
+
+Make sure everything is ok and then jump to the next step.
+</p>
+</section>
+
+<section name="Installing Apache">
+<p>
+Download the latest release, uncompress it, cd into the newly created directory
+and run the following:
+</p>
+<screen>
+<type>
+./configure -prefix=/usr/local/apache2.0.43 --sysconfdir=/etc/apache --localstatedir=/var --enable-so
+</type>
+</screen>
+<p>
+Of course you can customize the installation specifying other modules to enable
+or whatever you like.
+Just don't forget to ENABLE-SO, because that's what you need to load the
+apache-tomcat connector.
+</p>
+<p>
+Run make and make install. Create the log directories and others (you can skip
+this if you know how
+to configure where apache puts its log files -> edit httpd.conf):
+</p>
+<screen>
+<type>
+#mkdir /var/logs
+</type>
+<type>
+#mkdir /usr/local/apache2.0.43/conf
+</type>
+<type>
+#mkdir /usr/local/apache2.0.43/logs
+</type>
+</screen>
+<p>
+Create the symlink /usr/local/apache to /usr/local/apache2.0.43 and test your
+installation
+by executing:
+</p>
+<screen>
+<type>
+#/usr/local/apache/bin/apachectl start
+</type>
+</screen>
+<p>
+Open a browser and point it to the linux box: you should get a page telling you
+that the apache installation
+was successful.
+If that doesn't happen check the logs and troubleshoot: common errors in this configuration
+are that some directory holding log or configuration files is missing or maybe you have another web
+server listening on port 80.
+</p>
+</section>
+
+<section name="Installing Tomcat">
+<p>
+Uncompress the tomcat binaries in a directory of your choice. In this howto we
+will use /opt.
+Create a symlink named jakarta to the newly created directory so that you have
+something like the following:
+</p>
+<screen>
+<type>
+ll /opt/
+</type>
+<read>total 4</read>
+<read>lrwxrwxrwx    1 root     root           31 Oct 18 16:38 jakarta ->jakarta-tomcat-4.1.12-LE-jdk14/</read>
+<read>drwxr-xr-x   12 root     root         4096 Oct 18 18:10 jakarta-tomcat-4.1.12-LE-jdk14</read>
+<note>
+Start tomcat by running:
+</note>
+<type>
+/opt/jakarta/bin/startup.sh
+</type>
+</screen>
+<p>After a
+few seconds point your browser at the IP of
+the linux box on port 8080 and you should see the tomcat welcome page.
+If not check the catalina.out log file in /opt/jakarta/logs and fix all errors
+until Tomcat comes up.
+</p>
+</section>
+
+<section name="Configuring Tomcat to listen to Apache ajp13 requests">
+<p>
+Here is a sample server.xml file. Please note that the location of directories
+and log files is absolutely
+arbitrary and you have to edit it to make it suit your needs.
+<source>
+&lt;!-- Umberto Server Configuration File --&gt;
+
+&lt;Server port="8005" shutdown="SHUTDOWN" debug="0"&gt;
+  &lt;!-- Define an Apache-Connector Service --&gt;
+
+  &lt;Service name="Tomcat-Apache"&gt;
+ 
+   &lt;!-- Define a Coyote/JK2 AJP 1.3 Connector on port 8009 --&gt;
+    &lt;Connector className="org.apache.coyote.tomcat4.CoyoteConnector"
+               port="8009" minProcessors="5" maxProcessors="75"
+               enableLookups="true" redirectPort="8443"
+               acceptCount="10" debug="0" connectionTimeout="20000"
+               useURIValidationHack="false"
+               protocolHandlerClassName="org.apache.jk.server.JkCoyoteHandler"/&gt;
+
+	&lt;Engine name="Apache" defaultHost="www.home.net" debug="0"&gt;
+
+      &lt;Logger className="org.apache.catalina.logger.FileLogger"
+              prefix="apache_log." suffix=".txt"
+              timestamp="true"/&gt;
+	  &lt;!-- Access log processes all requests for this virtual host. --&gt;
+      &lt;Valve className="org.apache.catalina.valves.AccessLogValve"
+                 directory="logs"  prefix="localhost_access_log." suffix=".txt"
+                 pattern="common" resolveHosts="false"/&gt;
+
+	&lt;Host name="www.home.net" debug="0"
+appBase="/opt/jakarta-tomcat-4.1.12-LE-jdk14/webapps/struts-example" 
+       unpackWARs="true" autoDeploy="true"&gt;
+		&lt;Alias&gt;localhost&lt;/Alias&gt;
+		&lt;Alias&gt;www&lt;/Alias&gt;
+		&lt;Alias&gt;10.0.0.10&lt;/Alias&gt;
+
+
+		&lt;Context path="" docBase="" debug="1"/&gt;
+
+		&lt;Valve className="org.apache.catalina.valves.AccessLogValve"
+                 directory="logs"  prefix="home_access_log." suffix=".txt"
+                 pattern="common" resolveHosts="false"/&gt;
+	&lt;/Host&gt;
+
+	&lt;Host name="www.customer1.it" debug="0"
+appBase="/opt/jakarta-tomcat-4.1.12-LE-jdk14/webapps/struts-blank" 
+       unpackWARs="true" autoDeploy="true"&gt;
+
+		&lt;Context path="" docBase="" debug="1"/&gt;
+
+		&lt;Valve className="org.apache.catalina.valves.AccessLogValve"
+                 directory="logs"  prefix="cust1_access_log." suffix=".txt"
+                 pattern="common" resolveHosts="false"/&gt;
+	&lt;/Host&gt;
+
+	&lt;Host name="www.customer2.net" debug="0"
+appBase="/opt/jakarta-tomcat-4.1.12-LE-jdk14/webapps/root" 
+       unpackWARs="true" autoDeploy="true"&gt;
+
+		&lt;Context path="" docBase="" debug="1"/&gt;
+
+		&lt;Valve className="org.apache.catalina.valves.AccessLogValve"
+                 directory="logs"  prefix="cust2_log." suffix=".txt"
+                 pattern="common" resolveHosts="false"/&gt;
+	&lt;/Host&gt;
+
+    &lt;/Engine&gt;
+
+  &lt;/Service&gt;
+
+&lt;/Server&gt;
+</source>
+
+This is a very minimalistic conf file, because we have taken away the HTTP1.1
+connector that allows us to talk directly to Tomcat.
+It might not be good for development, but it should be good for production.
+If you feel like you need also the Tomcat Standalone service then copy and paste
+it from your original server.xml file
+(you did back it up, didn't you?).
+<br/>
+Try to start tomcat again and check catalina.out to see if everything is up and
+running. If it complains about
+missing apr stuff try to edit /opt/jakarta/conf/jk2.properties and make it look so:
+
+<source>
+# list of needed handlers.
+handler.list=channelSocket,request
+# Override the default port for the channelSocket
+channelSocket.port=8009
+</source>
+
+If everything is ok move on to next section.
+</p>
+</section>
+
+<section name="Configuring Apache virtual hosting">
+<p>
+rtfm at <a
+href="http://httpd.apache.org/docs-2.0/vhosts/">http://httpd.apache.org/docs-2.0/vhosts/</a>
+In the appendix you can find the httpd.conf file I used to write and test this
+HOWTO.
+</p>
+</section>
+
+<section name="Configuring Apache to talk to Tomcat">
+<p>
+Download the jk2 shared library for you version of apache and copy it in
+/usr/local/apache/modules
+(create the  directory if necessary). If you can't find a suitable version of
+jk2 ask it to the tomcat-user mailing list
+or download the source and build it yourself (this is another HOWTO).
+</p>
+<p>
+Create, if you haven't already, the /usr/local/apache/conf directory and create
+a file named
+workers2.properties with this content in it:
+
+<source>
+# only at beginnin. In production uncomment it out
+[logger.apache2]
+level=DEBUG
+
+[shm]
+file=/usr/local/apache/logs/shm.file
+size=1048576
+
+# Example socket channel, override port and host.
+[channel.socket:localhost:8009]
+port=8009
+host=127.0.0.1
+
+# define the worker
+[ajp13:localhost:8009]
+channel=channel.socket:localhost:8009
+
+# Uri mapping
+[uri:10.0.0.10/*.jsp]
+worker=ajp13:localhost:8009
+
+[uri:www.home.net/*.jsp]
+worker=ajp13:localhost:8009
+
+[uri:www.customer1.it/*.jsp]
+worker=ajp13:localhost:8009
+
+[uri:www.customer2.net/*.jsp]
+worker=ajp13:localhost:8009
+</source>
+
+Edit the file, change ip addresses and names to suit your needs and save it.
+</p>
+<p>
+Edit http.conf and add the following line in the Modules section:
+
+<source>
+LoadModule jk2_module modules/mod_jk2.so
+</source>
+
+Save http.conf and try to start apache. It should now load the jk2 connector and
+the configuration
+from workers2.properties.
+Check the error log to make sure everything is ok.
+</p>
+<p>
+Start tomcat and try to load a HTML page in your browser: apache should return
+the page
+without problems.
+Now try with a jsp page: it should display after a little.
+<br/>
+If you get errors check that the path and host names (double check also the
+configuration of DNS
+with your network administrator) are ok, the directories are readable by both
+Tomcat and Apache.
+Again look into the log files.
+</p>
+<p>
+If everything works go to next section.
+</p>
+</section>
+
+<section name="The last trick">
+<p>
+Now ask your network administrator to set up an alias for your brand new server
+(use jspsrc if
+you like to stick to this howto).
+If you don't have easy access to dns try to edit your hosts file (on the client
+where you open the browser)
+and add a line as follows:
+
+<source>
+10.0.0.10		jspsrc
+</source>
+
+where 10.0.0.10 is the ip of your server. Open your browser and type this in
+your location bar:
+
+<source>
+http://jspsrc
+</source>
+
+and navigate to a jsp page. You should get the source of the jsp page into your
+browser!
+</p>
+<p>
+This is clearly a security problem, if not a major annoyance.
+</p>
+<p>
+What's wrong with the setup we came up so far? The problem is (or should be)
+that the ajp13
+connector can't find a virtual host that matches the jspsrc uri.
+What we need to do is set up the default virtual host so that ALL *.jsp requests
+get handled by tomcat.
+</p>
+<p>
+How do we do it?
+</p>
+<p>
+Read on if you want to know how.
+</p>
+</section>
+
+<section name="JK directives in httpd.conf">
+<p>
+In addition to the workers2.properties you can put Jk diretives directly into
+the httpd.conf file (just as you did
+with jk and webapp).
+Edit the default virtual host section in httpd.conf and add the following lines
+in the end, before
+<code>&lt;/VirtualHost&gt;</code>:
+
+<source>
+    &lt;Location "/*.jsp"&gt;
+        JkUriSet worker ajp13:localhost:8009 
+    &lt;/Location&gt;
+</source>
+
+Restart Apache and test the jspsrc url again.
+</p>
+<p>
+The jsp source should not be displayed anymore.
+</p>
+</section>
+
+<section name="Notes">
+<p>
+I think a better approach would be to remove all uri directives from
+workers2.properties
+and to put them in http.conf as we did in the previous section for the defualt
+virtual host.
+Experiment and let me know.
+</p>
+</section>
+
+<section name="APPENDIX A: httpd.conf">
+<p>
+<source>
+#
+# Umberto Nicoletti, 18/10/2002
+#
+
+### Section 1: Global Environment
+
+ServerRoot "/usr/local/apache"
+ErrorLog logs/error_log
+
+&lt;IfModule !mpm_winnt.c&gt;
+&lt;IfModule !mpm_netware.c&gt;
+#LockFile logs/accept.lock
+&lt;/IfModule&gt;
+&lt;/IfModule&gt;
+
+# ScoreBoardFile: File used to store internal server process information.
+&lt;IfModule !mpm_netware.c&gt;
+&lt;IfModule !perchild.c&gt;
+#ScoreBoardFile logs/apache_runtime_status
+&lt;/IfModule&gt;
+&lt;/IfModule&gt;
+
+&lt;IfModule !mpm_netware.c&gt;
+PidFile logs/httpd.pid
+&lt;/IfModule&gt;
+
+Timeout 300
+
+KeepAlive On
+MaxKeepAliveRequests 100
+KeepAliveTimeout 15
+
+&lt;IfModule prefork.c&gt;
+StartServers         5
+MinSpareServers      5
+MaxSpareServers     10
+MaxClients         150
+MaxRequestsPerChild  0
+&lt;/IfModule&gt;
+
+&lt;IfModule worker.c&gt;
+StartServers         2
+MaxClients         150
+MinSpareThreads     25
+MaxSpareThreads     75 
+ThreadsPerChild     25
+MaxRequestsPerChild  0
+&lt;/IfModule&gt;
+
+&lt;IfModule perchild.c&gt;
+NumServers           5
+StartThreads         5
+MinSpareThreads      5
+MaxSpareThreads     10
+MaxThreadsPerChild  20
+MaxRequestsPerChild  0
+&lt;/IfModule&gt;
+
+# listen on all ports
+Listen 80
+
+#
+# Dynamic Shared Object (DSO) Support
+#
+LoadModule jk2_module modules/mod_jk2.so
+
+### Section 2: 'Main' server configuration
+
+&lt;IfModule !mpm_winnt.c&gt;
+&lt;IfModule !mpm_netware.c&gt;
+#
+# If you wish httpd to run as a different user or group, you must run
+# httpd as root initially and it will switch.  
+#
+# User/Group: The name (or #number) of the user/group to run httpd as.
+#  . On SCO (ODT 3) use "User nouser" and "Group nogroup".
+#  . On HPUX you may not be able to use shared memory as nobody, and the
+#    suggested workaround is to create a user www and use that user.
+#  NOTE that some kernels refuse to setgid(Group) or semctl(IPC_SET)
+#  when the value of (unsigned)Group is above 60000; 
+#  don't use Group #-1 on these systems!
+#
+User nobody
+Group #-1
+&lt;/IfModule&gt;
+&lt;/IfModule&gt;
+
+ServerAdmin whatever at you.want
+ServerName www.home.net
+UseCanonicalName Off
+
+#
+# The following directives define some format nicknames for use with
+# a CustomLog directive (see below).
+#
+LogFormat "%h %l %u %t \"%r\" %&gt;s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
+LogFormat "%h %l %u %t \"%r\" %&gt;s %b" common
+LogFormat "%{Referer}i -&gt; %U" referer
+LogFormat "%{User-agent}i" agent
+
+LogLevel debug
+CustomLog logs/access.log common
+
+DocumentRoot "/opt/jakarta-tomcat-4.1.12-LE-jdk14/webapps/struts-example"
+
+&lt;Directory /opt/jakarta-tomcat-4.1.12-LE-jdk14/webapps/struts-example&gt;
+    Options None
+    AllowOverride None
+&lt;/Directory&gt;
+
+DirectoryIndex index.html index.jsp
+
+&lt;Directory /&gt;
+    Options None
+    AllowOverride None
+&lt;/Directory&gt;
+
+&lt;Files ~ "^\.ht"&gt;
+    Order allow,deny
+    Deny from all
+&lt;/Files&gt;
+
+&lt;Location /WEB-INF/&gt;
+    Order Allow,Deny
+&lt;/Location&gt;
+
+NameVirtualHost *
+
+&lt;VirtualHost *&gt;
+    ServerName www.home.net
+	ServerAlias www
+	ServerAlias localhost
+    ServerAdmin sysmaster at arpa.veneto.it
+    DocumentRoot /opt/jakarta-tomcat-4.1.12-LE-jdk14/webapps/struts-example
+
+    ErrorLog logs/home.net-errorlog
+	CustomLog logs/home.net-access.log common
+
+    &lt;Location "/*.jsp"&gt;
+        JkUriSet worker ajp13:localhost:8009 
+    &lt;/Location&gt;
+&lt;/VirtualHost&gt;
+
+&lt;VirtualHost *&gt;
+    ServerName www.customer1.it
+    ServerAdmin sysmaster at arpa.veneto.it
+    DocumentRoot /opt/jakarta-tomcat-4.1.12-LE-jdk14/webapps/struts-blank
+    ErrorLog logs/cust1-errorlog
+&lt;/VirtualHost&gt;
+
+&lt;VirtualHost *&gt;
+    ServerName www.customer2.net
+    ServerAdmin sysmaster at arpa.veneto.it
+    DocumentRoot /opt/jakarta-tomcat-4.1.12-LE-jdk14/webapps/root
+    ErrorLog logs/cust2-errorlog
+&lt;/VirtualHost&gt;
+</source>
+</p>
+
+</section>
+</document>

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/news/20041100.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/news/20041100.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/news/20041100.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,145 @@
+<?xml version="1.0"?>
+<!DOCTYPE document [
+  <!ENTITY project SYSTEM "project.xml">
+]>
+<document url="20041100.html">
+ 
+  &project;
+ 
+  <properties>
+    <author email="general.AT.tomcat.DOT.apache.DOT.org">Apache Jakarta Project</author>
+    <title>2004 News and Status</title>
+  </properties>
+
+<body>
+
+<section name="2004 News &amp; Status">
+<br />
+<!--
+<a name="2004****.1">
+<h3></h3>
+</a>
+<hr size="1" noshade="noshade" />
+-->
+<a name="20041224.1"> 
+<h3>17 December - JK-1.2.8 released</h3>
+<p>The Apache Jakarta Tomcat team is proud to announce the immediate availability
+of Jakarta Tomcat Connectors 1.2.8.
+</p>
+<p>
+ Please see the <a href="../changelog.html">ChangeLog</a> for a full list of changes.
+</p>
+<p>If you find any bugs during testing this release, please fill in the
+<a href="http://issues.apache.org/bugzilla/enter_bug.cgi?product=Tomcat%205">Bugzilla</a>
+Bug Report. When entering bug select <b>Native:JK</b> Component.
+</p>
+</a> 
+<hr size="1" noshade="noshade" />
+<a name="20041218.1"> 
+<h3>17 December - JK-1.2.8-rc-1 released</h3>
+<p>The Apache Jakarta Tomcat team is proud to announce the immediate availability
+of Jakarta Tomcat Connectors 1.2.8-rc-1 (Relase Canditate 1).
+</p>
+<p>
+We expect it to be ratified as a Stable release when the vote takes place
+in the next week.
+</p>
+<p>
+ Please see the <a href="../changelog.html">ChangeLog</a> for a full list of changes.
+</p>
+<p>If you find any bugs during testing this release, please fill in the
+<a href="http://issues.apache.org/bugzilla/enter_bug.cgi?product=Tomcat%205">Bugzilla</a>
+Bug Report. When entering bug select <b>Native:JK</b> Component.
+</p>
+</a> 
+<hr size="1" noshade="noshade" />
+<a name="20041213.1"> 
+<h3>13 December - JK-1.2.7-beta-3 released</h3>
+<p>The Apache Jakarta Tomcat team is proud to announce the immediate availability
+of Jakarta Tomcat Connectors 1.2.7-beta-3. The release contains a fix to few configuration
+problems detected with JK-1.2.7-beta-2 version.
+</p>
+<p>
+We expect it to be ratified as a Stable release when the vote takes place
+in the next week.
+</p>
+<p>
+ Please see the <a href="../changelog.html">ChangeLog</a> for a full list of changes.
+</p>
+<p>If you find any bugs during testing this release, please fill in the
+<a href="http://issues.apache.org/bugzilla/enter_bug.cgi?product=Tomcat%205">Bugzilla</a>
+Bug Report. When entering bug select <b>Native:JK</b> Component.
+</p>
+</a> 
+<hr size="1" noshade="noshade" />
+<a name="20041207.1"> 
+<h3>7 December - JK-1.2.7-beta-2 released</h3>
+<p>The Apache Jakarta Tomcat team is proud to announce the immediate availability
+of Jakarta Tomcat Connectors 1.2.7-beta-2. The release contains a fix to few compilation
+problems detected with JK-1.2.7-beta version. This release also introduces a new
+<b>domain</b> concept clustering support. See <bug>32317</bug> for details.
+</p>
+<p>
+We expect it to be ratified as a Stable release when the vote takes place
+in the next two weeks.
+</p>
+<p>
+ Please see the <a href="../changelog.html">ChangeLog</a> for a full list of changes.
+</p>
+<p>If you find any bugs during testing this release, please fill in the
+<a href="http://issues.apache.org/bugzilla/enter_bug.cgi?product=Tomcat%205">Bugzilla</a>
+Bug Report. When entering bug select <b>Native:JK</b> Component.
+</p>
+</a> 
+<hr size="1" noshade="noshade" />
+
+<a name="20041130.1"> 
+<h3>30 November - JK-1.2.7-beta released</h3>
+<p>The Apache Jakarta Tomcat team is proud to announce the immediate availability
+of Jakarta Tomcat Connectors 1.2.7-beta. The release contains a significant number
+of bug fixes and new features. 
+</p>
+<p>
+We expect it to be ratified as a Stable release when the vote takes place
+in the next two weeks.
+</p>
+<p>
+ Please see the <a href="../changelog.html">ChangeLog</a> for a full list of changes.
+</p>
+<warn>
+Since release 1.2.7 the <b>socket_timeout</b> property has been renamed to
+<b>recycle_timeout</b>.
+The socket_timeout now sets the real timeout for socket operations.
+</warn>
+<p>If you find any bugs during testing this release, please fill in the
+<a href="http://issues.apache.org/bugzilla/enter_bug.cgi?product=Tomcat%205">Bugzilla</a>
+Bug Report. When entering bug select <b>Native:JK</b> Component.
+</p>
+</a> 
+
+<hr size="1" noshade="noshade" />
+
+<a name="20041115.1"> 
+<h3>15 November - JK2 is officially unsupported</h3>
+<p>JK2 has been put in maintainer mode and no further development will take place.
+The reason for shutting down JK2 development was the lack of developers interest.
+Other reason was lack of users interest in adopting JK2, caused by configuration
+complexity when compared to JK.
+</p>
+<p>The latest official JK2 release is 2.0.4.
+</p>
+<p>JK2 will have it's successor within core Apache2.1/2.2 distribution.
+We have developed new <b>proxy_ajp</b> that is an addition to
+the mod_proxy and uses Tomcat's AJP protocol stack. It is developped in httpd-2.1
+and integrated in it. We have also developed a new <b>proxy_balancer</b> module
+for load balancing http and ajp protocol stacks.
+</p>
+<p>JK will be fully supported for all other web servers. The next JK release is
+planned for the end of November. Lots of code from JK2 has been ported to JK
+</p>
+</a> 
+<hr size="1" noshade="noshade" />
+
+</section>
+</body>
+</document>  

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/news/20050101.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/news/20050101.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/news/20050101.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,158 @@
+<?xml version="1.0"?>
+<!DOCTYPE document [
+  <!ENTITY project SYSTEM "project.xml">
+]>
+<document url="20050101.html">
+ 
+  &project;
+ 
+  <properties>
+    <author email="general.AT.tomcat.DOT.apache.DOT.org">Apache Jakarta Project</author>
+    <title>2005 News and Status</title>
+  </properties>
+
+<body>
+
+<section name="2005 News &amp; Status">
+<br />
+<!--
+<a name="2004****.1">
+<h3></h3>
+</a>
+<hr size="1" noshade="noshade" />
+-->
+<a name="20051108.1"> 
+<h3>8 November - JK-1.2.15 released</h3>
+<p>The Apache Tomcat team is proud to announce the immediate availability
+of Jakarta Tomcat Connectors 1.2.15. This is Stable release and it contains
+few bug fixes found in 1.2.14 version.
+</p>
+<p>
+ Please see the <a href="../changelog.html">ChangeLog</a> for a full list of changes.
+</p>
+<p>If you find any bugs while using this release, please fill in the
+<a href="http://issues.apache.org/bugzilla/enter_bug.cgi?product=Tomcat%205">Bugzilla</a>
+Bug Report. When entering bug select <b>Native:JK</b> Component.
+</p>
+</a>
+<hr size="1" noshade="noshade" />
+
+<a name="20050713.1"> 
+<h3>13 July - JK-1.2.14 released</h3>
+<p>The Apache Tomcat team is proud to announce the immediate availability
+of Jakarta Tomcat Connectors 1.2.14. This is Stable release and it contains
+few bug fixes found in 1.2.13 version.
+</p>
+<p>
+ Please see the <a href="../changelog.html">ChangeLog</a> for a full list of changes.
+</p>
+<p>If you find any bugs while using this release, please fill in the
+<a href="http://issues.apache.org/bugzilla/enter_bug.cgi?product=Tomcat%205">Bugzilla</a>
+Bug Report. When entering bug select <b>Native:JK</b> Component.
+</p>
+</a>
+<hr size="1" noshade="noshade" />
+<a name="20050516.1"> 
+<h3>7 May - JK-1.2.13 released</h3>
+<p>The Apache Jakarta Tomcat team is proud to announce the immediate availability
+of Jakarta Tomcat Connectors 1.2.13. This is development release and contains
+few bug fixes found in 1.2.12 version.
+</p>
+<p>
+ Please see the <a href="../changelog.html">ChangeLog</a> for a full list of changes.
+</p>
+<p>If you find any bugs while using this release, please fill in the
+<a href="http://issues.apache.org/bugzilla/enter_bug.cgi?product=Tomcat%205">Bugzilla</a>
+Bug Report. When entering bug select <b>Native:JK</b> Component.
+</p>
+</a>
+<hr size="1" noshade="noshade" />
+<a name="20050507.1"> 
+<h3>7 May - JK-1.2.12 released</h3>
+<p>The Apache Jakarta Tomcat team is proud to announce the immediate availability
+of Jakarta Tomcat Connectors 1.2.12 The release contains a significant number
+of bug fixes and new features. 
+</p>
+<p>
+We expect it to be ratified as a Stable release when the vote takes place
+in the next week.
+</p>
+<p>
+ Please see the <a href="../changelog.html">ChangeLog</a> for a full list of changes.
+</p>
+<p>If you find any bugs while using this release, please fill in the
+<a href="http://issues.apache.org/bugzilla/enter_bug.cgi?product=Tomcat%205">Bugzilla</a>
+Bug Report. When entering bug select <b>Native:JK</b> Component.
+</p>
+</a> 
+<hr size="1" noshade="noshade" />
+<a name="20050429.1"> 
+<h3>29 April - JK-1.2.11 released</h3>
+<p>The Apache Jakarta Tomcat team is proud to announce the immediate availability
+of Jakarta Tomcat Connectors 1.2.11 The release contains a significant number
+of bug fixes and new features. 
+</p>
+<p>
+This version has not been released.
+</p>
+<p>
+ Please see the <a href="../changelog.html">ChangeLog</a> for a full list of changes.
+</p>
+<p>If you find any bugs while using this release, please fill in the
+<a href="http://issues.apache.org/bugzilla/enter_bug.cgi?product=Tomcat%205">Bugzilla</a>
+Bug Report. When entering bug select <b>Native:JK</b> Component.
+</p>
+</a> 
+<hr size="1" noshade="noshade" />
+<a name="20050330.1"> 
+<h3>30 March - JK-1.2.10 released</h3>
+<p>The Apache Jakarta Tomcat team is proud to announce the immediate availability
+of Jakarta Tomcat Connectors 1.2.10 The release contains a significant number
+of bug fixes and new features. 
+</p>
+<p>
+We expect it to be ratified as a Stable release when the vote takes place
+in the next two weeks.
+</p>
+<p>
+ Please see the <a href="../changelog.html">ChangeLog</a> for a full list of changes.
+</p>
+<warn>
+Since release 1.2.10 the <b>JkShmFile</b> property has been added for
+Apache 1.3.x and Apache 2.x web servers on UNIX and LINUX platforms.
+Load balancer will not work properly if this directive is not present.
+</warn>
+<p>If you find any bugs while using this release, please fill in the
+<a href="http://issues.apache.org/bugzilla/enter_bug.cgi?product=Tomcat%205">Bugzilla</a>
+Bug Report. When entering bug select <b>Native:JK</b> Component.
+</p>
+</a> 
+<hr size="1" noshade="noshade" />
+<a name="20050318.1"> 
+<h3>18 March - JK-1.2.9-beta released</h3>
+<p>The Apache Jakarta Tomcat team is proud to announce the immediate availability
+of Jakarta Tomcat Connectors 1.2.9-beta. The release contains a significant number
+of bug fixes and new features. 
+</p>
+<p>
+We expect it to be ratified as a Stable release when the vote takes place
+in the next two weeks.
+</p>
+<p>
+ Please see the <a href="../changelog.html">ChangeLog</a> for a full list of changes.
+</p>
+<warn>
+Since release 1.2.9 the <b>JkShmFile</b> property has been added for
+Apache 1.3.x and Apache 2.x web servers on UNIX and LINUX platforms.
+Load balancer will not work properly if this directive is not present.
+</warn>
+<p>If you find any bugs during testing this release, please fill in the
+<a href="http://issues.apache.org/bugzilla/enter_bug.cgi?product=Tomcat%205">Bugzilla</a>
+Bug Report. When entering bug select <b>Native:JK</b> Component.
+</p>
+</a> 
+<hr size="1" noshade="noshade" />
+
+</section>
+</body>
+</document>  

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/news/20060101.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/news/20060101.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/news/20060101.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,60 @@
+<?xml version="1.0"?>
+<!DOCTYPE document [
+  <!ENTITY project SYSTEM "project.xml">
+]>
+<document url="20060101.html">
+ 
+  &project;
+ 
+  <properties>
+    <author email="general.AT.tomcat.DOT.apache.DOT.org">Apache Tomcat Connectors Project</author>
+    <title>2006 News and Status</title>
+  </properties>
+
+<body>
+
+<section name="2006 News &amp; Status">
+<br />
+<a name="20060720.1"> 
+<h3>13 July - JK-1.2.18 released</h3>
+<p>The Apache Tomcat team is proud to announce the immediate availability
+of Tomcat Connectors 1.2.18. This is a stable release adding
+a few bug fixes to the not released 1.2.17 version.
+</p>
+<p>
+ Please see the <a href="../changelog.html">ChangeLog</a> for a full list of changes.
+</p>
+<p>If you find any bugs while using this release, please fill in the
+<a href="http://issues.apache.org/bugzilla/enter_bug.cgi?product=Tomcat%205">Bugzilla</a>
+Bug Report. When entering bug select <b>Native:JK</b> Component.
+</p>
+</a>
+<hr size="1" noshade="noshade" />
+
+<a name="20060708.1"> 
+<h3>JK-1.2.17 not released</h3>
+<p>Version 1.2.17 of Tomcat Connectors 1.2.17 has not been released 
+due to a bug in the types chosen for socket arguments.
+</p>
+<p>
+ Please see the <a href="../changelog.html">ChangeLog</a> for a full list of changes.
+</p>
+</a>
+<hr size="1" noshade="noshade" />
+
+<a name="20060606.1"> 
+<h3>JK-1.2.16 not released</h3>
+<p>Version 1.2.16 of Tomcat Connectors 1.2.16 has not been released 
+due to a bug in the jk status worker. This version adds some features
+and a few bug fixes to the 1.2.15 version. Furthermore some worker attributes
+have been <a href="../config/workers.html">deprecated</a>.
+</p>
+<p>
+ Please see the <a href="../changelog.html">ChangeLog</a> for a full list of changes.
+</p>
+</a>
+<hr size="1" noshade="noshade" />
+
+</section>
+</body>
+</document>  

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/news/project.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/news/project.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/news/project.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<project name="Apache Tomcat Connector Documentation - Top Level Directory"
+        href="http://tomcat.apache.org/connector-docs/">
+
+    <title>Apache Tomcat Connector</title>
+
+    <logo href="/images/tomcat.gif">
+    Breaking News
+    </logo>
+<body>
+
+    <menu name="Links">
+        <item name="Docs Home"             href="../index.html"/>
+        <item name="2006"                  href="20060101.html"/>
+        <item name="2005"                  href="20050101.html"/>
+        <item name="2004"                  href="20041100.html"/>
+    </menu>
+
+</body>
+</project>

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/project.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/project.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/project.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<project name="Apache Tomcat Connector Documentation - Top Level Directory"
+        href="http://tomcat.apache.org/">
+
+    <title>The Apache Tomcat Connector</title>
+
+    <logo href="/images/tomcat.gif">
+      The Apache Tomcat Connector
+    </logo>
+<body>
+
+    <menu name="Links">
+        <item name="Docs Home"             href="index.html"/>
+    </menu>
+    <menu name="Configuration">
+        <item name="Workers.properties"    href="config/workers.html"/>
+        <item name="Apache"                href="config/apache.html"/>
+        <item name="IIS"                   href="config/iis.html"/>
+    </menu>
+    <menu name="Documentation">
+        <item name="AJPv13 Protocol"       href="common/ajpv13a.html"/>
+        <item name="HowTo and Install"     href="howto/index.html"/>
+        <item name="Frequently asked questions"  href="faq.html"/>
+        <item name="Changelog"             href="changelog.html"/>
+        <item name="Tools"             href="common/tools.html"/>
+        <item name="Old JK/JK2 documentation" href="http://tomcat.apache.org/connectors-doc-archive/jk2/index.html"/>
+    </menu>
+
+</body>
+</project>

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/proxy.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/proxy.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/proxy.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,82 @@
+<?xml version="1.0"?>
+<!DOCTYPE document [
+  <!ENTITY project SYSTEM "project.xml">
+]>
+<document url="proxy.html">
+ 
+  &project;
+
+<copyright>
+   Copyright 1999-2005 The Apache Software Foundation
+ 
+   Licensed 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.
+</copyright>
+<properties>
+<title>Using proxies with Tomcat</title>
+<date>$Date: 2005-07-05 04:34:31 -0500 (Tue, 05 Jul 2005) $</date>
+</properties>
+
+<body>
+
+<section name="Http proxy">
+<p>
+It easy to use the standard Http proxy of Apache when single Tomcat is connected to Apache.
+<source>
+&lt;Location /examples/&gt;
+ProxyPass http://localhost:8080/examples/
+ProxyPassReverse http://localhost:8080/examples/
+&lt;/Location&gt;
+</source>
+</p>
+</section>
+
+<section name="AJP proxy">
+<p>
+The AJP proxy is a new module based on the standard Http proxy it uses AJP instead of HTTP.
+<source>
+&lt;Location /examples/&gt;
+   ProxyPass ajp://localhost:8009/examples/
+&lt;/Location&gt;
+</source>
+</p>
+</section>
+
+<section name="AJP proxy and proxy balancer">
+<p>
+It is possible to use the load balancer of the mod_proxy_balancer module.
+<source>
+&lt;Proxy balancer://myCluster&gt;
+   BalancerMember ajp://localhost:8009
+   BalancerMember ajp://example.org:8009
+&lt;/Proxy&gt;
+&lt;Location /examples/&gt;
+    ProxyPass balancer://myCluster/examples/
+&lt;/Location&gt;
+</source>
+</p>
+</section>
+
+<section name="Source and Configuration">
+<p>
+AJP proxy is integrated in httpd-2.1 and the developement and discussions take
+place <a href="http://httpd.apache.org/lists.html">there</a>.
+The documentation can be found there
+<a href="http://httpd.apache.org/docs-2.1/mod/mod_proxy_ajp.html">mod_proxy_ajp</a>
+and
+<a href="http://httpd.apache.org/docs-2.1/mod/mod_proxy_balancer.html">mod_proxy_balancer</a>.
+</p>
+</section>
+
+</body>
+
+</document>

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/style.css
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/style.css	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/style.css	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,57 @@
+div.screen {
+    margin: 10px 0px 10px 20px;
+    font-size: smaller;
+    color: #ffffff; 
+}
+div.example {
+    background-color: #e5ecf3;
+    color: #000;
+    padding: 0.5em;
+    margin: 1em 2em 1em 1em;
+}
+pre {
+    font-family: "Courier New", Courier, monospace;
+    font-weight: normal;
+    font-style: normal;
+    font-size: smaller;
+}
+em.screen {
+    font-weight: normal;
+    font-style: normal;
+    color: #c0c0c0;
+}
+p.screen {
+    background-color: #000000;
+    border-style: none;
+    color: #c0c0c0;
+    margin-left: 10px;
+    margin-right: 0px;
+    text-align: left;         
+}
+b.screen {
+    font-weight: normal;
+    font-style: normal;
+    color: #c0c0c0;
+}   
+code.screen {
+    background-color: #000000;
+    border-style: none;
+    color: #c0c0c0;
+    margin-left: 10px;
+    margin-right: 0px;
+    text-align: left; 
+}
+b.code {
+    font-weight: normal;
+    font-style: normal;
+    color: #023264;
+}
+p.todo {
+    background-color: #ffffff;
+    border-style: none;
+    color: #000000;
+    margin-left: 20px;
+    margin-right: 10px;
+    text-align: justify;
+    font-size: smaller;
+}                                  

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/style.xsl
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/style.xsl	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jk/xdocs/style.xsl	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,635 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!-- Content Stylesheet for "tomcat-docs" Documentation -->
+
+<!-- $Id: style.xsl 439829 2006-09-03 18:57:12Z rjung $ -->
+
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+  version="1.0">
+
+
+  <!-- Output method -->
+  <xsl:output method="html"
+            encoding="iso-8859-1"
+              indent="no"/>
+
+
+  <!-- Defined parameters (overrideable) -->
+  <xsl:param    name="home-name"        select="'Apache Tomcat'"/>
+  <xsl:param    name="home-href"        select="'http://tomcat.apache.org/'"/>
+  <xsl:param    name="home-logo"        select="'/images/tomcat.gif'"/>
+  <xsl:param    name="printer-logo"     select="'/images/printer.gif'"/>
+  <xsl:param    name="relative-path"    select="'.'"/>
+  <xsl:param    name="void-image"       select="'/images/void.gif'"/>
+  <xsl:param    name="project-menu"     select="'menu'"/>
+  <xsl:param    name="standalone"       select="''"/>
+  <xsl:param    name="buglink"          select="'http://issues.apache.org/bugzilla/show_bug.cgi?id='"/>
+
+  <!-- Defined variables (non-overrideable) -->
+  <xsl:variable name="body-bg"          select="'#ffffff'"/>
+  <xsl:variable name="body-fg"          select="'#000000'"/>
+  <xsl:variable name="body-link"        select="'#525D76'"/>
+  <xsl:variable name="banner-bg"        select="'#525D76'"/>
+  <xsl:variable name="banner-fg"        select="'#ffffff'"/>
+  <xsl:variable name="sub-banner-bg"    select="'#828DA6'"/>
+  <xsl:variable name="sub-banner-fg"    select="'#ffffff'"/>
+  <xsl:variable name="source-color"     select="'#023264'"/>
+  <xsl:variable name="attributes-color" select="'#023264'"/>
+  <xsl:variable name="table-th-bg"      select="'#039acc'"/>
+  <xsl:variable name="table-td-bg"      select="'#a0ddf0'"/>
+
+  <!-- Process an entire document into an HTML page -->
+  <xsl:template match="document">
+    <html>
+    <head>
+    <title><xsl:value-of select="project/title"/> - <xsl:value-of select="properties/title"/></title>
+    <xsl:for-each select="properties/author">
+      <xsl:variable name="name">
+        <xsl:value-of select="."/>
+      </xsl:variable>
+      <xsl:variable name="email">
+        <xsl:value-of select="@email"/>
+      </xsl:variable>
+      <meta name="author" value="{$name}"/>
+      <meta name="email" value="{$email}"/>
+    </xsl:for-each>
+    <link href="{$relative-path}/style.css" type="text/css" rel="stylesheet"/>    
+    </head>
+
+    <body bgcolor="{$body-bg}" text="{$body-fg}" link="{$body-link}"
+          alink="{$body-link}" vlink="{$body-link}">
+
+    <table border="0" width="100%" cellspacing="4">
+
+      <xsl:comment>PAGE HEADER</xsl:comment>
+      <tr><td colspan="2">
+
+        <xsl:comment>TOMCAT LOGO</xsl:comment>
+        <xsl:variable name="alt">
+          <xsl:value-of select="$home-name"/>
+        </xsl:variable>
+        <xsl:variable name="href">
+          <xsl:value-of select="$home-href"/>
+        </xsl:variable>
+        <xsl:variable name="src">
+          <xsl:value-of select="$relative-path"/><xsl:value-of select="$home-logo"/>
+        </xsl:variable>
+        <a href="{$href}">
+          <img src="{$src}" align="left" alt="{$alt}" border="0"/>
+        </a>
+        <xsl:if test="project/logo">
+          <xsl:variable name="alt">
+            <xsl:value-of select="project/logo"/>
+          </xsl:variable>
+          <xsl:variable name="home">
+            <xsl:value-of select="project/@href"/>
+          </xsl:variable>
+          <xsl:variable name="src">
+            <xsl:value-of select="$relative-path"/><xsl:value-of select="project/logo/@href"/>
+          </xsl:variable>
+
+          <xsl:comment>APACHE LOGO</xsl:comment>
+          <a href="http://www.apache.org/">
+            <img src="http://www.apache.org/images/asf-logo.gif"
+                 align="right" alt="Apache Logo" border="0"/>
+          </a>
+
+        </xsl:if>
+
+      </td></tr>
+
+      <xsl:comment>HEADER SEPARATOR</xsl:comment>
+      <tr>
+        <td colspan="2">
+          <hr noshade="noshade" size="1"/>
+        </td>
+      </tr>
+
+      <tr>
+
+        <!-- Don't generate a menu if styling printer friendly docs -->
+        <xsl:if test="$project-menu = 'menu'">
+          <xsl:comment>LEFT SIDE NAVIGATION</xsl:comment>
+          <td width="20%" valign="top" nowrap="true">
+            <xsl:apply-templates select="project/body/menu"/>
+          </td>
+        </xsl:if>
+
+        <xsl:comment>RIGHT SIDE MAIN BODY</xsl:comment>
+        <td width="80%" valign="top" align="left">
+          <table border="0" width="100%" cellspacing="4">
+            <tr>
+              <td align="left" valign="top">
+                <h1><xsl:value-of select="project/title"/></h1>
+                <h2><xsl:value-of select="properties/title"/></h2>
+              </td>
+              <td align="right" valign="top" nowrap="true">
+                <!-- Add the printer friendly link for docs with a menu -->
+                <xsl:if test="$project-menu = 'menu'">
+                  <xsl:variable name="src">
+                    <xsl:value-of select="$relative-path"/><xsl:value-of select="$printer-logo"/>
+                  </xsl:variable>
+                  <xsl:variable name="url">
+                    <xsl:value-of select="/document/@url"/>
+                  </xsl:variable>
+                  <small>
+                    <a href="printer/{$url}">
+                      <img src="{$src}" border="0" alt="Printer Friendly Version"/>
+                      <br />print-friendly<br />version
+                    </a>
+                  </small>
+                </xsl:if>
+                <xsl:if test="$project-menu != 'menu'">
+                  <xsl:variable name="void">
+                    <xsl:value-of select="$relative-path"/><xsl:value-of select="$void-image"/>
+                    </xsl:variable>
+                  <img src="{$void}" width="1" height="1" vspace="0" hspace="0" border="0"/>
+                </xsl:if>
+              </td>
+            </tr>
+          </table>
+          <xsl:apply-templates select="body/section"/>
+        </td>
+
+      </tr>
+
+      <xsl:comment>FOOTER SEPARATOR</xsl:comment>
+      <tr>
+        <td colspan="2">
+          <hr noshade="noshade" size="1"/>
+        </td>
+      </tr>
+
+      <xsl:comment>PAGE FOOTER</xsl:comment>
+      <tr><td colspan="2">
+        <div align="center"><font color="{$body-link}" size="-1"><em>
+        Copyright &#169; 1999-2005, Apache Software Foundation
+        </em></font></div>
+      </td></tr>
+
+    </table>
+    </body>
+    </html>
+
+  </xsl:template>
+
+
+  <!-- Process a menu for the navigation bar -->
+  <xsl:template match="menu">
+    <p><strong><xsl:value-of select="@name"/></strong></p>
+    <ul>
+      <xsl:apply-templates select="item"/>
+    </ul>
+  </xsl:template>
+
+
+  <!-- Process a menu item for the navigation bar -->
+  <xsl:template match="item">
+    <xsl:variable name="href">
+      <xsl:value-of select="@href"/>
+    </xsl:variable>
+    <li><a href="{$href}"><xsl:value-of select="@name"/></a></li>
+  </xsl:template>
+
+
+  <!-- Process a documentation section -->
+  <xsl:template match="section">
+    <xsl:variable name="name">
+      <xsl:value-of select="@name"/>
+    </xsl:variable>
+    <table border="0" cellspacing="0" cellpadding="2" width="100%">
+      <!-- Section heading -->
+      <tr><td bgcolor="{$banner-bg}">
+          <font color="{$banner-fg}" face="arial,helvetica.sanserif">
+          <a name="{$name}">
+          <strong><xsl:value-of select="@name"/></strong></a></font>
+      </td></tr>
+      <!-- Section body -->
+      <tr><td><blockquote>
+        <xsl:apply-templates/>
+      </blockquote></td></tr>
+    </table>
+  </xsl:template>
+
+
+  <!-- Process a documentation subsection -->
+  <xsl:template match="subsection">
+    <xsl:variable name="name">
+      <xsl:value-of select="@name"/>
+    </xsl:variable>
+    <table border="0" cellspacing="0" cellpadding="2" width="100%">
+      <!-- Subsection heading -->
+      <tr><td bgcolor="{$sub-banner-bg}">
+          <font color="{$sub-banner-fg}" face="arial,helvetica.sanserif">
+          <a name="{$name}">
+          <strong><xsl:value-of select="@name"/></strong></a></font>
+      </td></tr>
+      <!-- Subsection body -->
+      <tr><td><blockquote>
+        <xsl:apply-templates/>
+      </blockquote></td></tr>
+    </table>
+  </xsl:template>
+
+
+  <!-- Process a source code example -->
+  <xsl:template match="source">
+    <xsl:variable name="void">
+      <xsl:value-of select="$relative-path"/><xsl:value-of select="$void-image"/>
+    </xsl:variable>
+    <div class="example"><pre>
+        <xsl:value-of select="."/>
+        </pre>
+    </div>
+  </xsl:template>
+
+
+  <!-- Process an attributes list with nested attribute elements -->
+  <xsl:template match="attributes">
+    <table border="1" cellpadding="5">
+      <tr>
+        <th width="220px" bgcolor="{$attributes-color}">
+     	  <xsl:choose>
+            <xsl:when test="@name != ''">
+               <font color="#ffffff"><xsl:value-of select="@name"/></font>
+            </xsl:when>
+            <xsl:otherwise>
+               <font color="#ffffff">Attribute</font>
+            </xsl:otherwise>
+          </xsl:choose>          
+        </th>
+        <th width="*" bgcolor="{$attributes-color}">
+          <font color="#ffffff">Description</font>
+        </th>
+      </tr>
+      <xsl:for-each select="attribute">
+        <tr>
+          <td align="left" valign="center">
+            <xsl:if test="@required = 'true'">
+              <strong><code><xsl:value-of select="@name"/></code></strong>
+            </xsl:if>
+            <xsl:if test="@required != 'true'">
+              <code><xsl:value-of select="@name"/></code>
+            </xsl:if>
+          </td>
+          <td align="left" valign="center">
+            <xsl:apply-templates/>
+          </td>
+        </tr>
+      </xsl:for-each>
+    </table>
+  </xsl:template>
+
+  <!-- Process an directives list with nested directive elements -->
+  <xsl:template match="directives">
+    <table border="1" cellpadding="5">
+      <tr>
+        <th width="15%" bgcolor="{$attributes-color}">
+          <font color="#ffffff">Directive</font>
+        </th>
+        <th width="10%" bgcolor="{$attributes-color}">
+          <font color="#ffffff">Default</font>
+        </th>
+        <th width="75%" bgcolor="{$attributes-color}">
+          <font color="#ffffff">Description</font>
+        </th>
+      </tr>
+      <xsl:for-each select="directive">
+        <tr>
+          <td align="left" valign="center">
+            <xsl:if test="@required = 'true'">
+              <strong><code><xsl:value-of select="@name"/></code></strong>
+            </xsl:if>
+            <xsl:if test="@required != 'true'">
+              <code><xsl:value-of select="@name"/></code>
+            </xsl:if>
+          </td>
+     	  <xsl:choose>
+            <xsl:when test="@default != ''">
+               <td align="center" valign="center">          
+               <code><xsl:value-of select="@default"/></code>
+              </td>
+            </xsl:when>
+            <xsl:otherwise>
+              <td align="center" valign="center">          
+              <code>-</code>
+              </td>
+            </xsl:otherwise>
+          </xsl:choose>          
+          <td align="left" valign="center">
+            <xsl:apply-templates/>
+          </td>
+        </tr>
+      </xsl:for-each>
+    </table>
+  </xsl:template>
+
+  <!-- Process an directives list with nested directive elements -->
+  <xsl:template match="deprecations">
+    <table border="1" cellpadding="5">
+      <tr>
+        <th width="15%" bgcolor="{$attributes-color}">
+          <font color="#ffffff">Directive</font>
+        </th>
+        <th width="15%" bgcolor="{$attributes-color}">
+          <font color="#ffffff">Successor</font>
+        </th>
+        <th width="10%" bgcolor="{$attributes-color}">
+          <font color="#ffffff">Default</font>
+        </th>
+        <th width="60%" bgcolor="{$attributes-color}">
+          <font color="#ffffff">Description</font>
+        </th>
+      </tr>
+      <xsl:for-each select="directive">
+        <tr>
+          <td align="left" valign="center">
+            <code><xsl:value-of select="@name"/></code>
+          </td>
+     	  <xsl:choose>
+            <xsl:when test="@successor != ''">
+               <td align="center" valign="center">          
+               <code><xsl:value-of select="@successor"/></code>
+              </td>
+            </xsl:when>
+            <xsl:otherwise>
+              <td align="center" valign="center">          
+              <code>-</code>
+              </td>
+            </xsl:otherwise>
+          </xsl:choose>          
+     	  <xsl:choose>
+            <xsl:when test="@default != ''">
+               <td align="center" valign="center">          
+               <code><xsl:value-of select="@default"/></code>
+              </td>
+            </xsl:when>
+            <xsl:otherwise>
+              <td align="center" valign="center">          
+              <code>-</code>
+              </td>
+            </xsl:otherwise>
+          </xsl:choose>          
+          <td align="left" valign="center">
+            <xsl:apply-templates/>
+          </td>
+        </tr>
+      </xsl:for-each>
+    </table>
+  </xsl:template>
+
+  <!-- Fix relative links in printer friendly versions of the docs -->
+  <xsl:template match="a">
+    <xsl:variable name="href" select="@href"/>
+    <xsl:choose>
+      <xsl:when test="$standalone = 'standalone'">
+        <xsl:apply-templates/>
+      </xsl:when>
+      <xsl:when test="$project-menu != 'menu' and starts-with(@href,'../')">
+        <a href="../{$href}"><xsl:apply-templates/></a>
+      </xsl:when>
+      <xsl:when test="$project-menu != 'menu' and starts-with(@href,'./') and contains(substring(@href,3),'/')">
+        <a href=".{$href}"><xsl:apply-templates/></a>
+      </xsl:when>
+      <xsl:when test="$project-menu != 'menu' and not(contains(@href,'//')) and not(starts-with(@href,'/')) and not(starts-with(@href,'#')) and contains(@href,'/')">
+        <a href="../{$href}"><xsl:apply-templates/></a>
+      </xsl:when>
+      <xsl:when test="$href != ''">
+        <a href="{$href}"><xsl:apply-templates/></a>
+      </xsl:when>
+      <xsl:otherwise>
+        <xsl:variable name="name" select="@name"/>
+        <a name="{$name}"><xsl:apply-templates/></a>
+      </xsl:otherwise>
+    </xsl:choose>
+  </xsl:template>
+    
+  <!-- Warning -->
+  <xsl:template match="warn">
+    <p>
+    <font color="#ff0000">
+    <xsl:apply-templates/>
+    </font>
+    </p>
+  </xsl:template>
+
+  <!-- Changelog related tags -->
+  <xsl:template match="changelog">
+    <table border="0" cellpadding="2" cellspacing="2">
+      <xsl:apply-templates/>
+    </table>
+  </xsl:template>
+
+  <xsl:template match="changelog/add">
+    <tr>
+      <xsl:variable name="src"><xsl:value-of select="$relative-path"/>/images/add.gif</xsl:variable>
+      <td valign="top"><img alt="add" class="icon" src="{$src}"/></td>
+      <td><xsl:apply-templates/></td>
+    </tr>
+  </xsl:template>
+
+  <xsl:template match="changelog/update">
+    <tr>
+      <xsl:variable name="src"><xsl:value-of select="$relative-path"/>/images/update.gif</xsl:variable>
+      <td valign="top"><img alt="update" class="icon" src="{$src}"/></td>
+      <td><xsl:apply-templates/></td>
+    </tr>
+  </xsl:template>
+
+  <xsl:template match="changelog/design">
+    <tr>
+      <xsl:variable name="src"><xsl:value-of select="$relative-path"/>/images/design.gif</xsl:variable>
+      <td valign="top"><img alt="design" class="icon" src="{$src}"/></td>
+      <td><xsl:apply-templates/></td>
+    </tr>
+  </xsl:template>
+
+  <xsl:template match="changelog/docs">
+    <tr>
+      <xsl:variable name="src"><xsl:value-of select="$relative-path"/>/images/docs.gif</xsl:variable>
+      <td valign="top"><img alt="docs" class="icon" src="{$src}"/></td>
+      <td><xsl:apply-templates/></td>
+    </tr>
+  </xsl:template>
+
+  <xsl:template match="changelog/fix">
+    <tr>
+      <xsl:variable name="src"><xsl:value-of select="$relative-path"/>/images/fix.gif</xsl:variable>
+      <td valign="top"><img alt="fix" class="icon" src="{$src}"/></td>
+      <td><xsl:apply-templates/></td>
+    </tr>
+  </xsl:template>
+
+  <xsl:template match="changelog/scode">
+    <tr>
+      <xsl:variable name="src"><xsl:value-of select="$relative-path"/>/images/code.gif</xsl:variable>
+      <td valign="top"><img alt="code" class="icon" src="{$src}"/></td>
+      <td><xsl:apply-templates/></td>
+    </tr>
+  </xsl:template>
+
+  <!-- Process an attributes list with nested attribute elements -->
+  <xsl:template match="status">
+    <table border="1" cellpadding="5">
+      <tr>
+        <th width="15%" bgcolor="{$attributes-color}">
+          <font color="#ffffff">Priority</font>
+        </th>
+        <th width="50%" bgcolor="{$attributes-color}">
+          <font color="#ffffff">Action Item</font>
+        </th>
+        <th width="25%" bgcolor="{$attributes-color}">
+          <font color="#ffffff">Volunteers</font>
+        </th>
+        <xsl:for-each select="item">
+        <tr>
+          <td align="left" valign="center">
+            <xsl:value-of select="@priority"/>
+          </td>
+          <td align="left" valign="center">
+            <xsl:apply-templates/>
+          </td>
+          <td align="left" valign="center">
+            <xsl:value-of select="@owner"/>
+          </td>
+        </tr>
+        </xsl:for-each>
+      </tr>
+    </table>
+  </xsl:template>
+
+  <!-- Link to a bug report -->
+  <xsl:template match="bug">
+      <xsl:variable name="link"><xsl:value-of select="$buglink"/><xsl:value-of select="text()"/></xsl:variable>
+      <a href="{$link}"><xsl:apply-templates/></a>
+  </xsl:template>
+
+
+  <xsl:template match="code">
+    <b class="code"><xsl:apply-templates select="text()"/></b>
+  </xsl:template>
+
+  <xsl:template match="todo">
+    <p class="todo">
+      This paragraph has not been written yet, but <b>you</b> can contribute to it.
+      <xsl:if test="string-length(@note) > 0">
+        The original author left a note attached to this TO-DO item:
+        <b><xsl:value-of select="@note"/></b>
+      </xsl:if>
+    </p>
+  </xsl:template>
+ 
+  <!-- Screens -->
+
+  <xsl:template match="screen">
+    <p class="screen">
+      <div align="left">
+        <table width="80%" border="1" cellspacing="0" cellpadding="2" bgcolor="#000000">
+          <tr>
+            <td bgcolor="#000000" align="left">
+              <xsl:apply-templates select="note|wait|type|typedos|type5250|typenext|read"/>
+            </td>
+          </tr>
+        </table>
+      </div>
+    </p>
+  </xsl:template>
+  
+  <xsl:template match="note">
+    <div class="screen">
+      <xsl:value-of select="text()"/>
+    </div>
+  </xsl:template>
+
+  <xsl:template match="wait">
+    <div class="screen">[...]</div>
+  </xsl:template>
+
+  <xsl:template match="type">
+    <code>
+      <nobr>
+        <em class="screen">
+          <xsl:text>[user at host] ~</xsl:text>
+          <xsl:if test="string-length(@dir) > 0">
+            <xsl:text>/</xsl:text>
+            <xsl:value-of select="@dir"/>
+          </xsl:if>
+          <xsl:text> $ </xsl:text>
+        </em>
+        <xsl:if test="string-length(text()) > 0">
+          <b class="screen"><xsl:value-of select="text()"/></b>
+        </xsl:if>
+      </nobr>
+    </code>
+    <br/>
+  </xsl:template>
+
+  <xsl:template match="typedos">
+    <code>
+      <nobr>
+        <em class="screen">
+          <xsl:text>c:\</xsl:text>
+          <xsl:if test="string-length(@dir) > 0">
+            <xsl:text>/</xsl:text>
+            <xsl:value-of select="@dir"/>
+          </xsl:if>
+          <xsl:text>></xsl:text>
+        </em>
+        <xsl:if test="string-length(text()) > 0">
+          <b class="screen"><xsl:value-of select="text()"/></b>
+        </xsl:if>
+      </nobr>
+    </code>
+    <br/>
+  </xsl:template>
+ 
+  <xsl:template match="type5250">
+    <code>
+      <nobr>
+        <em class="screen">
+          <xsl:text>===></xsl:text>
+        </em>
+        <xsl:if test="string-length(text()) > 0">
+          <b class="screen"><xsl:value-of select="text()"/></b>
+        </xsl:if>
+      </nobr>
+    </code>
+    <br/>
+  </xsl:template>
+
+  <xsl:template match="typenext">
+    <code>
+      <nobr>
+        <em class="screen">        
+          <xsl:text> </xsl:text>
+        </em>
+        <xsl:if test="string-length(text()) > 0">
+          <b class="screen"><xsl:value-of select="text()"/></b>
+        </xsl:if>
+      </nobr>
+    </code>
+    <br/>
+  </xsl:template>
+   
+  <xsl:template match="read">
+    <code class="screen">
+      <nobr>
+        <xsl:apply-templates select="text()|enter"/>
+      </nobr>
+    </code>
+    <br/>
+  </xsl:template>
+
+  <xsl:template match="enter">
+    <b class="screen"><xsl:value-of select="text()"/></b>
+  </xsl:template>
+ 
+  
+
+  <!-- Process everything else by just passing it through -->
+  <xsl:template match="*|@*">
+    <xsl:copy>
+      <xsl:apply-templates select="@*|*|text()"/>
+    </xsl:copy>
+  </xsl:template>
+
+</xsl:stylesheet>

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jni/NOTICE.txt
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jni/NOTICE.txt	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jni/NOTICE.txt	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,3 @@
+This product includes software developed by
+The Apache Software Foundation (http://www.apache.org/).
+

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jni/README.txt
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jni/README.txt	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jni/README.txt	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,18 @@
+This directory contains both the native and java-side code for
+Tomcat Native Library.
+
+Building
+========
+ant
+To build the native part see native/BUILDING
+
+Running the examples
+====================
+before running the examples you may have to set LD_LIBRARY_PATH, something like
+LD_LIBRARY_PATH=/opt/SMAWoIS/openssl/lib; export LD_LIBRARY_PATH
+1 - echo: (port in examples/org/apache/tomcat/jni/Echo.properties).
+    ant echo-example
+2 - ssl server:
+    (see parameters in ./examples/org/apache/tomcat/jni/SSL.properties)
+    The certificate and key should be in dist/classes/examples.
+    ant server-example

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jni/build.properties.sample
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jni/build.properties.sample	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jni/build.properties.sample	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,6 @@
+# The directory containing your binary distribution of JUnit,
+# version 3.8 or later
+junit.home = /usr/local/java/junit3.8.1
+
+# The pathname of the "junit.jar" JAR file
+junit.jar = ${junit.home}/junit.jar

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jni/build.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jni/build.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jni/build.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,322 @@
+<?xml version="1.0"?>
+<!-- Build file for Tomcat Native -->
+<project name="Tomcat Native" default="compile" basedir=".">
+    <!-- Give user a chance to override without editing this file
+        (and without typing -D each time it compiles it
+    -->
+    <property file="${user.home}/.ant.properties" />
+    <property file="${user.home}/build.properties" />
+    <property file="build.properties" />
+    <property file=".ant.properties" />
+
+    <!-- Initialization properties -->
+    <property name="name" value="Tomcat Native"/>
+    <property name="title" value="Tomcat Native Library"/>
+    <property name="version" value="1.0.0"/>
+    <property name="version.number" value="100"/>
+    <property name="project" value="tomcat-native"/>
+    <property name="build.dir" value="./dist"/>
+    <property name="build.src" value="${build.dir}/src"/>
+    <property name="build.dest" value="${build.dir}/classes"/>
+    <property name="src.dir" value="."/>
+    <property name="final.name" value="${project}-${version}"/>
+    <property name="dist.root" value="./dist"/>
+    <property name="ant.home" value="."/>
+
+    <property name="debug" value="off"/>
+    <property name="optimize" value="on"/>
+    <property name="deprecation" value="on"/>
+
+    <property name="docs.src" value="./xdocs"/>
+    <property name="docs.dest" value="${dist.root}/doc"/>
+    <property name="docs.dest.print" value="${dist.root}/doc/printable"/>
+    <property name="test.runner" value="junit.textui.TestRunner"/>
+    <property name="test.dir" value="${build.dest}/test"/>
+    <property name="examples.dir" value="${build.dest}/examples"/>
+    <property name="junit.home" value="/usr/local/junit3.8"/>
+    <property name="junit.jar" value="${junit.home}/junit.jar"/>
+    <property name="tc.library.path" value="${basedir}/native/.libs"/>
+
+      <!-- The base directory for component sources -->
+      <property name="source.home"             value="java"/>
+
+    <!-- Build classpath -->
+    <path id="classpath">
+        <pathelement location="${build.dest}/java"/>
+    </path>
+
+    <!-- Test classpath -->
+    <path id="test.classpath">
+        <pathelement location="${build.dest}/java"/>
+        <pathelement location="${build.dest}/test"/>
+        <pathelement location="${junit.jar}"/>
+    </path>
+
+    <!-- Examples classpath -->
+    <path id="examples.classpath">
+        <pathelement location="${build.dest}/java"/>
+        <pathelement location="${build.dest}/examples"/>
+    </path>
+
+    <!-- =================================================================== -->
+    <!-- prints the environment                                              -->
+    <!-- =================================================================== -->
+    <target name="env">
+        <echo message="java.home = ${java.home}"/>
+        <echo message="user.home = ${user.home}"/>
+        <!--
+        <echo message="java.class.path = ${java.class.path}"/>
+        -->
+        <echo message="tc.library.path = ${tc.library.path}"/>
+        <echo message=""/>
+    </target>
+
+    <target name="prepare" depends="env">
+       <mkdir dir="${build.dir}"/>
+    </target>
+
+    <!-- =================================================================== -->
+    <!-- Creates the API documentation                                       -->
+    <!-- =================================================================== -->
+    <target name="javadocs" description="Java documentation">
+        <mkdir dir="${docs.dest}"/>
+        <mkdir dir="${docs.dest}/api"/>
+        <javadoc sourcepath="${build.src}/java"
+            destdir="${docs.dest}/api"
+            author="true"
+            version="true"
+            overview="${src.dir}/java/overview.html"
+            packagenames="org.apache.tomcat.*"
+            windowtitle="${title} (Version ${version})"
+            doctitle="&lt;h1&gt;${title} (Version ${version})&lt;/h1&gt;"
+            bottom="Copyright 2002-2004 The Apache Software Foundation.&lt;!--
+
+Licensed 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.--&gt;">
+            <classpath refid="classpath"/>
+        </javadoc>
+     </target>
+
+    <!-- =================================================================== -->
+    <!-- Cleans up the build directory                                       -->
+    <!-- =================================================================== -->
+    <target name="clean">
+        <delete dir="${build.dir}"/>
+    </target>
+
+    <!-- =================================================================== -->
+    <!-- Compiles the source directory                                       -->
+    <!-- =================================================================== -->
+    <target name="compile" depends="prepare">
+        <mkdir dir="${build.dest}"/>
+        <mkdir dir="${build.dest}/java"/>
+        <mkdir dir="${build.src}"/>
+        <mkdir dir="${build.src}/java"/>
+        <tstamp>
+            <format property="TODAY" pattern="MMM d yyyy" locale="en"/>
+            <format property="TSTAMP" pattern="hh:mm:ss"/>
+        </tstamp>
+        <!-- Copy static resource files -->
+        <filter token="VERSION" value="${version}"/>
+        <filter token="VERSION_NUMBER" value="${version.number}"/>
+        <filter token="VERSION_BUILT" value="${TODAY} ${TSTAMP}"/>
+        <copy todir="${build.src}/java" filtering="yes">
+            <fileset dir="${src.dir}/java">
+                <include name="**/*.java"/>
+                <include name="**/*.xml"/>
+                <include name="**/*.properties"/>
+            </fileset>
+        </copy>
+
+        <javac srcdir="${build.src}/java"
+            destdir="${build.dest}/java"
+            debug="${debug}"
+            deprecation="${deprecation}"
+            optimize="${optimize}">
+            <classpath refid="classpath"/>
+        </javac>
+        <copy todir="${build.dest}/java" filtering="yes">
+            <fileset dir="${build.src}/java">
+                <include name="**/*.xml"/>
+                <include name="**/*.properties"/>
+            </fileset>
+        </copy>
+    </target>
+
+      <target name="compile-only"
+              description="Compile shareable components">
+
+        <javac  srcdir="${source.home}"
+               destdir="${build.home}/classes"
+                 debug="${compile.debug}"
+           deprecation="${compile.deprecation}"
+              optimize="${compile.optimize}">
+          <classpath refid="classpath"/>
+        </javac>
+        <copy    todir="${build.home}/classes" filtering="on">
+          <fileset dir="${source.home}" excludes="**/*.java"/>
+        </copy>
+      </target>
+
+    <!-- =================================================================== -->
+    <!-- Compiles the examples directory                                     -->
+    <!-- =================================================================== -->
+    <target name="examples" depends="compile">
+        <mkdir dir="${build.dest}"/>
+        <mkdir dir="${build.dest}/examples"/>
+        <mkdir dir="${build.src}"/>
+        <mkdir dir="${build.src}/examples"/>
+        <tstamp>
+            <format property="TODAY" pattern="MMM d yyyy" locale="en"/>
+            <format property="TSTAMP" pattern="hh:mm:ss"/>
+        </tstamp>
+        <!-- Copy static resource files -->
+        <filter token="VERSION" value="${version}"/>
+        <filter token="VERSION_NUMBER" value="${version.number}"/>
+        <filter token="VERSION_BUILT" value="${TODAY} ${TSTAMP}"/>
+        <copy todir="${build.src}/examples" filtering="yes">
+            <fileset dir="${src.dir}/examples">
+                <include name="**/*.java"/>
+                <include name="**/*.xml"/>
+                <include name="**/*.properties"/>
+            </fileset>
+        </copy>
+
+        <javac srcdir="${build.src}/examples"
+            destdir="${build.dest}/examples"
+            debug="${debug}"
+            deprecation="${deprecation}"
+            optimize="${optimize}">
+            <classpath refid="examples.classpath"/>
+        </javac>
+        <copy todir="${build.dest}/examples" filtering="yes">
+            <fileset dir="${build.src}/examples">
+                <include name="**/*.xml"/>
+                <include name="**/*.properties"/>
+            </fileset>
+        </copy>
+    </target>
+
+    <!-- ================================================================== -->
+    <!-- Make Tomcat Native jar                                             -->
+    <!-- ================================================================== -->
+    <target name="jar" depends="compile"
+        description="Generates the Jar file">
+        <jar
+            destfile="${build.dir}/${final.name}.jar"
+            basedir="${build.dir}/classes/java"
+            excludes="**/*.java">
+            <manifest>
+                <section name="org/apache/tomcat/jni">
+                    <attribute name="Specification-Title" value="Tomcat Native"/>
+                    <attribute name="Specification-Version" value="${version}"/>
+                    <attribute name="Specification-Vendor" value="Apache Software Foundation"/>
+                    <attribute name="Implementation-Title" value="org.apache.tomcat.jni"/>
+                    <attribute name="Implementation-Vendor" value="Apache Software Foundation"/>
+                    <attribute name="Implementation-Vendor-Id" value="org.apache"/>
+                    <attribute name="Implementation-Version" value="${version} (build ${DSTAMP} ${TSTAMP})"/>
+                </section>
+            </manifest>
+        </jar>
+    </target>
+
+    <!-- =================================================================== -->
+    <!-- Compiles the test directory                                         -->
+    <!-- =================================================================== -->
+    <target name="compile-tests" depends="compile">
+        <mkdir dir="${build.dest}/test"/>
+        <mkdir dir="${build.src}/test"/>
+        <copy todir="${build.src}/test" filtering="yes">
+            <fileset dir="${src.dir}/test">
+                <include name="**/*.java"/>
+                <include name="**/*.xml"/>
+                <include name="**/*.properties"/>
+            </fileset>
+        </copy>
+        <javac srcdir="${build.src}/test"
+            destdir="${build.dest}/test"
+            debug="${debug}"
+            deprecation="${deprecation}"
+            optimize="${optimize}">
+
+            <classpath refid="test.classpath"/>
+        </javac>
+    </target>
+
+    <!-- =================================================================== -->
+    <!-- Junit tests                                                         -->
+    <!-- =================================================================== -->
+    <target name="test.file" depends="compile-tests">
+        <echo message="Running Tomcat Native package tests ..."/>
+        <java dir="${test.dir}" classname="${test.runner}" fork="yes" failonerror="${test.failonerror}">
+            <arg value="org.apache.tomcat.jni.FileTestSuite"/>
+            <classpath refid="test.classpath"/>
+        </java>
+    </target>
+
+    <!-- =================================================================== -->
+    <!-- Compiles the examples directory                                     -->
+    <!-- =================================================================== -->
+    <target name="compile-examples" depends="compile">
+        <mkdir dir="${build.dest}/examples"/>
+        <mkdir dir="${build.src}/examples"/>
+        <copy todir="${build.src}/examples" filtering="yes">
+            <fileset dir="${src.dir}/examples">
+                <include name="**/*.java"/>
+                <include name="**/*.xml"/>
+                <include name="**/*.properties"/>
+            </fileset>
+        </copy>
+        <javac srcdir="${build.src}/examples"
+            destdir="${build.dest}/examples"
+            debug="${debug}"
+            deprecation="${deprecation}"
+            optimize="${optimize}">
+
+            <classpath refid="examples.classpath"/>
+        </javac>
+    </target>
+
+    <!-- =================================================================== -->
+    <!-- excutes the examples                                                -->
+    <!-- =================================================================== -->
+    <target name="echo-example" depends="examples">
+        <echo message="Running Tomcat Native Echo example ..."/>
+        <java dir="${examples.dir}" classname="org.apache.tomcat.jni.Echo"
+             fork="yes" failonerror="${test.failonerror}">
+            <classpath refid="examples.classpath"/>
+            <env key="PATH" path="${tc.library.path}:${java.library.path}"/>
+            <env key="Path" path="${tc.library.path}:${java.library.path}"/>
+            <jvmarg value="-Djava.library.path=${tc.library.path}"/>
+        </java>
+    </target>
+    <target name="server-example" depends="examples">
+        <echo message="Running Tomcat Native SSL Server example ..."/>
+        <java dir="${examples.dir}" classname="org.apache.tomcat.jni.SSLServer"
+             fork="yes" failonerror="${test.failonerror}">
+            <env key="PATH" path="${tc.library.path}:${java.library.path}"/>
+            <env key="Path" path="${tc.library.path}:${java.library.path}"/>
+            <classpath refid="examples.classpath"/>
+            <jvmarg value="-Djava.library.path=${tc.library.path}"/>
+        </java>
+    </target>
+    <target name="locals-example" depends="examples">
+        <echo message="Running Tomcat Native Local Server example ..."/>
+        <java dir="${examples.dir}" classname="org.apache.tomcat.jni.LocalServer"
+             fork="yes" failonerror="${test.failonerror}">
+            <classpath refid="examples.classpath"/>
+            <env key="PATH" path="${tc.library.path}:${java.library.path}"/>
+            <env key="Path" path="${tc.library.path}:${java.library.path}"/>
+            <jvmarg value="-Djava.library.path=${tc.library.path}"/>
+        </java>
+    </target>
+</project>

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jni/examples/mkcerts
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jni/examples/mkcerts	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jni/examples/mkcerts	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,215 @@
+#!/bin/sh
+#
+# Copyright 1999-2006 The Apache Software Foundation
+#
+# Licensed 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.
+#
+#
+# This is the configuration file to treate the CA certificate of the
+# _DEMONSTRATION ONLY_ 'Coyote' Certificate Authority.
+# This CA is used to sign the localhost.crt and user.crt
+# because self-signed server certificates are not accepted by all browsers.
+# NEVER USE THIS CA YOURSELF FOR REAL LIFE! INSTEAD EITHER USE A PUBLICALLY
+# KNOWN CA OR CREATE YOUR OWN CA!
+
+if [ -z "$OPENSSL" ]; then OPENSSL=openssl; fi
+
+PASSPHRASE="pass:secret"
+# Encrypt all keys
+GENRSA="$OPENSSL genrsa -des3"
+# Uncomment for no key encryption
+# GENRSA="$OPENSSL genrsa"
+REQ="$OPENSSL req -new"
+CA="$OPENSSL ca"
+X509="$OPENSSL x509"
+
+$OPENSSL rand -out .rnd 8192
+$GENRSA -passout $PASSPHRASE -out ca.key -rand .rnd 1024
+
+cat >ca.cfg <<EOT
+[ ca ]
+default_ca                      = default_db
+[ default_db ]
+dir                             = .
+certs                           = .
+new_certs_dir                   = ca.certs
+database                        = ca.index
+serial                          = ca.serial
+RANDFILE                        = .rnd
+certificate                     = ca.crt
+private_key                     = ca.key
+default_days                    = 365
+default_crl_days                = 30
+default_md                      = md5
+preserve                        = no
+name_opt                        = ca_default
+cert_opt                        = ca_default
+unique_subject                  = no
+[ server_policy ]
+countryName                     = supplied
+stateOrProvinceName             = supplied
+localityName                    = supplied
+organizationName                = supplied
+organizationalUnitName          = supplied
+commonName                      = supplied
+emailAddress                    = supplied
+[ server_cert ]
+subjectKeyIdentifier            = hash
+authorityKeyIdentifier          = keyid:always
+extendedKeyUsage                = serverAuth,clientAuth,msSGC,nsSGC
+basicConstraints                = critical,CA:false
+[ user_policy ]
+commonName                      = supplied
+emailAddress                    = supplied
+[ user_cert ]
+subjectAltName                  = email:copy
+basicConstraints                = critical,CA:false
+authorityKeyIdentifier          = keyid:always
+extendedKeyUsage                = clientAuth,emailProtection
+
+[ req ]
+default_bits                    = 1024
+default_keyfile                 = ca.key
+distinguished_name              = default_ca
+x509_extensions                 = extensions
+string_mask                     = nombstr
+req_extensions                  = req_extensions
+input_password                  = secret
+output_password                 = secret
+[ default_ca ]
+countryName                     = Country Code
+countryName_value               = US
+countryName_min                 = 2
+countryName_max                 = 2
+stateOrProvinceName             = State Name
+stateOrProvinceName_value       = Delaware
+localityName                    = Locality Name
+localityName_value              = Wilmington
+organizationName                = Organization Name
+organizationName_value          = Apache Software Foundation
+organizationalUnitName          = Organizational Unit Name
+organizationalUnitName_value    = Apache Tomcat
+commonName                      = Common Name
+commonName_value                = Apache Tomcat demo root CA
+commonName_max                  = 64
+emailAddress                    = Email Address
+emailAddress_value              = coyote at tomcat.apache.org
+emailAddress_max                = 40
+[ extensions ]
+subjectKeyIdentifier            = hash
+authorityKeyIdentifier          = keyid:always
+basicConstraints                = critical,CA:true
+[ req_extensions ]
+nsCertType                      = objsign,email,server
+EOT
+
+$REQ -x509 -days 3650 -batch -config ca.cfg -key ca.key -out ca.crt
+
+# Create cabundle.crt that can be used for CAfile
+cat >cabundle.crt <<EOT
+Tomcat Demo Root CA
+=========================================
+`$X509 -noout -fingerprint -in ca.crt`
+PEM Data:
+`$X509 -in ca.crt`
+`$X509 -noout -text -in ca.crt`
+EOT
+
+$GENRSA -passout $PASSPHRASE -out localhost.key  -rand .rnd 1024
+
+cat >localhost.cfg <<EOT
+[ req ]
+default_bits                    = 1024
+distinguished_name              = localhost
+string_mask                     = nombstr
+req_extensions                  = extensions
+input_password                  = secret
+output_password                 = secret
+[ localhost ]
+countryName                     = Country Code
+countryName_value               = US
+countryName_min                 = 2
+countryName_max                 = 2
+stateOrProvinceName             = State Name
+stateOrProvinceName_value       = Delaware
+localityName                    = Locality Name
+localityName_value              = Wilmington
+organizationName                = Organization Name
+organizationName_value          = Apache Software Foundation
+organizationalUnitName          = Organizational Unit Name
+organizationalUnitName_value    = Apache Tomcat
+commonName                      = Common Name
+commonName_value                = Apache Tomcat localhost secure demo server
+commonName_max                  = 64
+emailAddress                    = Email Address
+emailAddress_value              = tomcat at localhost.edu
+emailAddress_max                = 40
+[ extensions ]
+nsCertType                      = server
+basicConstraints                = critical,CA:false
+EOT
+
+$REQ -passin $PASSPHRASE -batch -config localhost.cfg -key localhost.key -out localhost.csr
+rm -f localhost.cfg
+
+#  make sure environment exists
+if [ ! -d ca.certs ]; then
+    mkdir ca.certs
+    echo '01' >ca.serial
+    cp /dev/null ca.index
+fi
+
+$CA -passin $PASSPHRASE -batch -config ca.cfg -extensions server_cert -policy server_policy  -out x.crt -infiles localhost.csr
+$X509 -in x.crt -out localhost.crt
+rm -f x.crt
+# Create PKCS12 localhost certificate
+$OPENSSL pkcs12 -export -passout $PASSPHRASE -passin $PASSPHRASE -in localhost.crt -inkey localhost.key -certfile ca.crt -out localhost.p12
+
+$GENRSA -passout $PASSPHRASE -out user.key -rand .rnd 1024
+
+cat >user.cfg <<EOT
+[ req ]
+default_bits            = 1024
+distinguished_name      = admin
+string_mask             = nombstr
+req_extensions          = extensions
+input_password          = secret
+output_password         = secret
+[ admin ]
+commonName              = User Name
+commonName_value        = Localhost Administrator
+commonName_max          = 64
+emailAddress            = Email Address
+emailAddress_value      = admin at localhost.edu
+emailAddress_max        = 40
+[ extensions ]
+nsCertType              = client,email
+basicConstraints        = critical,CA:false
+EOT
+
+$REQ -passin $PASSPHRASE -batch -config user.cfg -key user.key -out user.csr
+rm -f user.cfg
+$CA -passin $PASSPHRASE -batch -config ca.cfg -extensions user_cert -policy user_policy  -out x.crt -infiles user.csr
+$X509 -in x.crt -out user.crt
+rm -f x.crt
+
+# $OPENSSL verify -CAfile ca.crt localhost.crt
+# $OPENSSL verify -CAfile ca.crt user.crt
+
+# Create PKCS12 user certificate
+$OPENSSL pkcs12 -export -passout $PASSPHRASE -passin $PASSPHRASE -in user.crt -inkey user.key -certfile ca.crt -out user.p12
+
+rm -f ca.cfg
+rm -f *.old
+rm -f ca.index.attr
+rm -f .rnd

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jni/examples/org/apache/tomcat/jni/Echo.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jni/examples/org/apache/tomcat/jni/Echo.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jni/examples/org/apache/tomcat/jni/Echo.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,343 @@
+/*
+ *  Copyright 2000-2005 The Apache Software Foundation
+ *
+ *  Licensed 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.jni;
+
+import java.util.Properties;
+
+import java.io.*;
+import java.net.*;
+import java.lang.*;
+
+/** Echo server example
+ *
+ * @author Mladen Turk
+ * @version $Revision: 300969 $, $Date: 2005-07-12 09:56:11 -0500 (Tue, 12 Jul 2005) $
+ */
+
+public class Echo {
+
+    public static String echoEcho = null;
+    public static String echoAddr = null;
+    public static int echoPort    = 0;
+    public static int echoNmax    = 0;
+    public static int echoNrun    = 0;
+    public static long echoPool   = 0;
+
+    private static Poller echoPoller     = null;
+    private static Acceptor echoAcceptor = null;
+
+    private static Object threadLock = new Object();
+
+    static {
+
+        try {
+            InputStream is = Echo.class.getResourceAsStream
+                ("/org/apache/tomcat/jni/Echo.properties");
+            Properties props = new Properties();
+            props.load(is);
+            is.close();
+            echoAddr = props.getProperty("echo.ip", "127.0.0.1");
+            echoPort = Integer.decode(props.getProperty("echo.port", "23")).intValue();
+            echoNmax = Integer.decode(props.getProperty("echo.max", "1")).intValue();
+        }
+        catch (Throwable t) {
+            ; // Nothing
+        }
+    }
+
+    /* Acceptor thread. Listens for new connections */
+    private class Acceptor extends Thread {
+        private long serverSock = 0;
+        private long inetAddress = 0;
+        private long pool = 0;
+        public Acceptor() throws Exception {
+            try {
+
+                pool = Pool.create(Echo.echoPool);
+                System.out.println("Accepting: " +  Echo.echoAddr + ":" +
+                                   Echo.echoPort);
+                inetAddress = Address.info(Echo.echoAddr, Socket.APR_INET,
+                                           Echo.echoPort, 0,
+                                           pool);
+                serverSock = Socket.create(Socket.APR_INET, Socket.SOCK_STREAM,
+                                           Socket.APR_PROTO_TCP, pool);
+                long sa = Address.get(Socket.APR_LOCAL, serverSock);
+                Sockaddr addr = new Sockaddr();
+                if (Address.fill(addr, sa)) {
+                    System.out.println("Host: " + addr.hostname);
+                    System.out.println("Server: " + addr.servname);
+                    System.out.println("IP: " + Address.getip(sa) +
+                                       ":" + addr.port);
+                }
+                int rc = Socket.bind(serverSock, inetAddress);
+                if (rc != 0) {
+                  throw(new Exception("Can't create Acceptor: bind: " + Error.strerror(rc)));
+                }
+                Socket.listen(serverSock, 5);
+            }
+            catch( Exception ex ) {
+                ex.printStackTrace();
+                throw(new Exception("Can't create Acceptor"));
+            }
+        }
+
+        public void run() {
+            int i = 0;
+            try {
+                while (true) {
+                    long clientSock = Socket.accept(serverSock);
+                    System.out.println("Accepted id: " +  i);
+
+                    try {
+                        long sa = Address.get(Socket.APR_REMOTE, clientSock);
+                        Sockaddr raddr = new Sockaddr();
+                        if (Address.fill(raddr, sa)) {
+                            System.out.println("Remote Host: " + Address.getnameinfo(sa, 0));
+                            System.out.println("Remote IP: " + Address.getip(sa) +
+                                               ":" + raddr.port);
+                        }
+                        sa = Address.get(Socket.APR_LOCAL, clientSock);
+                        Sockaddr laddr = new Sockaddr();
+                        if (Address.fill(laddr, sa)) {
+                            System.out.println("Local Host: " + laddr.hostname);
+                            System.out.println("Local Server: " + Address.getnameinfo(sa, 0));
+                            System.out.println("Local IP: " + Address.getip(sa) +
+                                               ":" + laddr.port);
+                        }
+
+                    } catch (Exception e) {
+                        // Ignore
+                        e.printStackTrace();
+                    }
+
+                    Socket.timeoutSet(clientSock, 10000000);
+                    Worker worker = new Worker(clientSock, i++,
+                                               this.getClass().getName());
+                    Echo.incThreads();
+                    worker.start();
+                }
+            }
+            catch( Exception ex ) {
+                ex.printStackTrace();
+            }
+        }
+    }
+
+    /* Poller thread. Listens for new recycled connections */
+    private class Poller extends Thread {
+        private long serverPollset = 0;
+        private long pool = 0;
+        private int nsocks = 0;
+        public Poller() {
+            try {
+
+                pool = Pool.create(Echo.echoPool);
+                serverPollset = Poll.create(16, pool, 0, 10000000);
+            }
+            catch( Exception ex ) {
+                ex.printStackTrace();
+            }
+        }
+
+        public void add(long socket) {
+            int rv = Poll.add(serverPollset, socket,
+                              Poll.APR_POLLIN);
+            if (rv == Status.APR_SUCCESS) {
+                System.out.println("Added worker to pollset");
+                nsocks++;
+            }
+        }
+
+        public void remove(long socket) {
+            int rv = Poll.remove(serverPollset, socket);
+            if (rv == Status.APR_SUCCESS) {
+               nsocks--;
+               System.out.println("Removed worker from pollset");
+            }
+            else {
+               System.out.println("Failed removing worker from pollset");
+            }
+        }
+
+        public void run() {
+            while (true) {
+                try {
+                    if (nsocks < 1) {
+                        Thread.sleep(1);
+                        continue;
+                    }
+                    /* Two times size then  created pollset */
+                    long [] desc = new long[64];
+                    /* USe 1 second poll timeout */
+                    int rv = Poll.poll(serverPollset, 1000000, desc, false);
+                    if (rv > 0) {
+                        for (int n = 0; n < rv; n++) {
+                            long clientSock = desc[n*2+1];
+                            System.out.println("Poll flags " + desc[n*2]);
+                            remove(clientSock);
+                            Worker worker = new Worker(clientSock, n,
+                                                       this.getClass().getName());
+                            Echo.incThreads();
+                            worker.start();
+                        }
+                    }
+                    else {
+                        if (Status.APR_STATUS_IS_TIMEUP(-rv))
+                            System.out.println("Timeup");
+                        else {
+                            System.out.println("Error " + (-rv));
+                        }
+                    }
+                }
+                /* XXX: JFC quick hack
+                catch(Error err ) {
+                    if (Status.APR_STATUS_IS_TIMEUP(err.getError())) {
+                        /0 TODO: deal with timeout 0/
+                    }
+                    else {
+                        err.printStackTrace();
+                        break;
+                    }
+                }
+                 */
+                catch( Exception ex ) {
+                    ex.printStackTrace();
+                    break;
+                }
+            }
+        }
+    }
+
+    private class Worker extends Thread {
+        private int workerId = 0;
+        private long clientSock = 0;
+        private byte [] wellcomeMsg = null;
+        public Worker(long clientSocket, int workerId, String from) {
+            this.clientSock = clientSocket;
+            this.workerId = workerId;
+            wellcomeMsg = ("Echo server id: " + this.workerId + " from " +
+                           from + "\r\n").getBytes();
+        }
+
+        public void run() {
+            boolean doClose = false;
+            try {
+                Socket.send(clientSock, wellcomeMsg, 0, wellcomeMsg.length);
+                /* Do a blocking read byte at a time */
+                byte [] buf = new byte[1];
+                while (Socket.recv(clientSock, buf, 0, 1) == 1) {
+                    if (buf[0] == '\n')
+                        break;
+                    else if (buf[0] == '!') {
+                        doClose = true;
+                        break;
+                    }
+                }
+                if (doClose) {
+                    try {
+                        byte [] msg = ("Bye from worker: " + workerId + "\r\n").getBytes();
+                        Socket.send(clientSock, msg, 0, msg.length);
+                    } catch(Exception e) { }
+
+                    Socket.close(clientSock);
+                }
+                else {
+                    try {
+                        byte [] msg = ("Recycling worker: " + workerId + "\r\n").getBytes();
+                        Socket.send(clientSock, msg, 0, msg.length);
+                    } catch(Exception e) { }
+                    /* Put the socket to the keep-alive poll */
+                    Echo.echoPoller.add(clientSock);
+                }
+            } catch (Exception e) {
+                Socket.close(clientSock);
+                e.printStackTrace();
+            }
+            Echo.decThreads();
+            System.out.println("Worker: " +  workerId + " finished");
+        }
+    }
+
+    public Echo()
+    {
+        int i;
+        echoPool = Pool.create(0);
+        try {
+            echoAcceptor = new Acceptor();
+            echoAcceptor.start();
+            echoPoller = new Poller();
+            echoPoller.start();
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+
+    }
+
+    public static void incThreads() {
+        synchronized(threadLock) {
+            echoNrun++;
+        }
+    }
+
+    public static void decThreads() {
+        synchronized(threadLock) {
+            echoNrun--;
+        }
+    }
+
+    public static void main(String [] args) {
+        try {
+            Library.initialize(null);
+            long [] inf = new long[16];
+            System.out.println("Info ...");
+            System.out.println("  Native        " + Library.versionString());
+            System.out.println("  APR           " + Library.aprVersionString());
+            OS.info(inf);
+            System.out.println("OS Info ...");
+            System.out.println("  Physical      " + inf[0]);
+            System.out.println("  Avail         " + inf[1]);
+            System.out.println("  Swap          " + inf[2]);
+            System.out.println("  Swap free     " + inf[3]);
+            System.out.println("  Shared        " + inf[4]);
+            System.out.println("  Buffers size  " + inf[5]);
+            System.out.println("  Load          " + inf[6]);
+
+            System.out.println("  Idle          " + inf[7]);
+            System.out.println("  Kernel        " + inf[8]);
+            System.out.println("  User          " + inf[9]);
+
+            System.out.println("  Proc creation " + inf[10]);
+            System.out.println("  Proc kernel   " + inf[11]);
+            System.out.println("  Proc user     " + inf[12]);
+            System.out.println("  Curr working  " + inf[13]);
+            System.out.println("  Peak working  " + inf[14]);
+            System.out.println("  Page faults   " + inf[15]);
+
+            SSL.initialize(null);
+            System.out.println("OpenSSL ...");
+            System.out.println("  version       " + SSL.versionString());
+            System.out.println("  number        " + SSL.version());
+
+            System.out.println("Starting Native Echo server example on port " +
+                               echoAddr + ":" + echoPort);
+            Echo echo = new Echo();
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jni/examples/org/apache/tomcat/jni/Echo.properties
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jni/examples/org/apache/tomcat/jni/Echo.properties	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jni/examples/org/apache/tomcat/jni/Echo.properties	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,2 @@
+# Telnet properties
+echo.port=23

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jni/examples/org/apache/tomcat/jni/Local.properties
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jni/examples/org/apache/tomcat/jni/Local.properties	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jni/examples/org/apache/tomcat/jni/Local.properties	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,8 @@
+# Local properties
+local.max=10
+
+# For NT Pipes use something like
+local.path=\\\\.\\PIPE\\test
+
+# For Unix Sockets use
+# local.path=/tmp/testsock

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jni/examples/org/apache/tomcat/jni/LocalServer.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jni/examples/org/apache/tomcat/jni/LocalServer.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jni/examples/org/apache/tomcat/jni/LocalServer.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,172 @@
+package org.apache.tomcat.jni;
+
+import java.util.Properties;
+
+import java.io.*;
+import java.net.*;
+import java.lang.*;
+
+/** Local Socket server example
+ *
+ * @author Mladen Turk
+ * @version $Revision: 300883 $, $Date: 2005-06-24 03:22:58 -0500 (Fri, 24 Jun 2005) $
+ */
+
+public class LocalServer {
+
+    public static String serverAddr = null;
+    public static int serverNmax    = 0;
+    public static int serverNrun    = 0;
+    public static long serverPool   = 0;
+
+    private static Acceptor serverAcceptor = null;
+
+    private static Object threadLock = new Object();
+
+    static {
+
+        try {
+            InputStream is = LocalServer.class.getResourceAsStream
+                ("/org/apache/tomcat/jni/Local.properties");
+            Properties props = new Properties();
+            props.load(is);
+            is.close();
+            serverAddr = props.getProperty("local.path", null);
+            serverNmax = Integer.decode(props.getProperty("local.max", "0")).intValue();
+        }
+        catch (Throwable t) {
+            ; // Nothing
+        }
+    }
+
+    public LocalServer()
+    {
+        int i;
+        serverPool = Pool.create(0);
+        try {
+            serverAcceptor = new Acceptor();
+            serverAcceptor.start();
+
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+
+    }
+    public static void incThreads() {
+        synchronized(threadLock) {
+            serverNrun++;
+        }
+    }
+
+    public static void decThreads() {
+        synchronized(threadLock) {
+            serverNrun--;
+        }
+    }
+
+    /* Acceptor thread. Listens for new connections */
+    private class Acceptor extends Thread {
+        private long serverSock = 0;
+        private long inetAddress = 0;
+        private long pool = 0;
+        public Acceptor() throws Exception {
+            try {
+
+                pool = Pool.create(LocalServer.serverPool);
+                System.out.println("Accepting: " +  LocalServer.serverAddr);
+                serverSock = Local.create(LocalServer.serverAddr, pool);
+                int rc = Local.bind(serverSock, inetAddress);
+                if (rc != 0) {
+                  throw(new Exception("Can't create Acceptor: bind: " + Error.strerror(rc)));
+                }
+                Local.listen(serverSock, LocalServer.serverNmax);
+            }
+            catch( Exception ex ) {
+                ex.printStackTrace();
+                throw(new Exception("Can't create Acceptor"));
+            }
+        }
+
+        public void run() {
+            int i = 0;
+            try {
+                while (true) {
+                    long clientSock = Local.accept(serverSock);
+                    System.out.println("Accepted id: " +  i);
+
+                    Socket.timeoutSet(clientSock, 10000000);
+                    Worker worker = new Worker(clientSock, i++,
+                                               this.getClass().getName());
+                    LocalServer.incThreads();
+                    worker.start();
+                }
+            }
+            catch( Exception ex ) {
+                ex.printStackTrace();
+            }
+        }
+    }
+
+    private class Worker extends Thread {
+        private int workerId = 0;
+        private long clientSock = 0;
+        private byte [] wellcomeMsg = null;
+
+        public Worker(long clientSocket, int workerId, String from) {
+            this.clientSock = clientSocket;
+            this.workerId = workerId;
+            wellcomeMsg = ("LocalServer server id: " + this.workerId + " from " +
+                           from).getBytes();
+        }
+
+        public void run() {
+            boolean doClose = false;
+            try {
+                Socket.send(clientSock, wellcomeMsg, 0, wellcomeMsg.length);
+                while (!doClose) {
+                    /* Do a blocking read byte at a time */
+                    byte [] buf = new byte[1];
+                    byte [] msg = new byte[256];
+                    int p = 0;
+                    while (Socket.recv(clientSock, buf, 0, 1) == 1) {
+                        if (buf[0] == '\n')
+                            break;
+                        else if (buf[0] == '!') {
+                            doClose = true;
+                            break;
+                        }
+                        if (p > 250)
+                           break;
+                        msg[p++] = buf[0];
+                    }
+                    if (doClose) {
+                        try {
+                            byte [] snd = ("Bye from worker: " + workerId).getBytes();
+                            Socket.send(clientSock, snd, 0, snd.length);
+                        } catch(Exception e) { }
+
+                        Socket.close(clientSock);
+                    }
+                    else
+                        Socket.send(clientSock, msg, 0, p);                
+                }
+            } catch (Exception e) {
+                Socket.destroy(clientSock);
+                e.printStackTrace();
+            }
+            LocalServer.decThreads();
+            System.out.println("Worker: " +  workerId + " finished");
+        }
+    }
+
+
+    public static void main(String [] args) {
+        try {
+            Library.initialize(null);
+
+            LocalServer server = new LocalServer();
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+ }

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jni/examples/org/apache/tomcat/jni/SSL.properties
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jni/examples/org/apache/tomcat/jni/SSL.properties	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jni/examples/org/apache/tomcat/jni/SSL.properties	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,7 @@
+# SSL Server and client properties
+server.port=4443
+server.cert=localhost.crt
+server.key=localhost.key
+server.password=secret
+server.ciphers=ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP:+eNULL
+server.verify=none

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jni/examples/org/apache/tomcat/jni/SSLServer.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jni/examples/org/apache/tomcat/jni/SSLServer.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jni/examples/org/apache/tomcat/jni/SSLServer.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,227 @@
+package org.apache.tomcat.jni;
+
+import java.util.Properties;
+
+import java.io.*;
+import java.net.*;
+import java.lang.*;
+
+/** SSL Server server example
+ *
+ * @author Mladen Turk
+ * @version $Revision: 300872 $, $Date: 2005-06-21 11:20:45 -0500 (Tue, 21 Jun 2005) $
+ */
+
+public class SSLServer {
+
+    public static String serverAddr = null;
+    public static int serverPort    = 0;
+    public static int serverNmax    = 0;
+    public static int serverNrun    = 0;
+    public static long serverCtx    = 0;
+    public static long serverPool   = 0;
+    public static String serverCert = null;
+    public static String serverKey  = null;
+    public static String serverCiphers  = null;
+    public static String serverPassword = null;
+    public static String serverCAFile   = null;
+
+    private static Acceptor serverAcceptor = null;
+
+    private static Object threadLock = new Object();
+
+    static {
+
+        try {
+            InputStream is = SSLServer.class.getResourceAsStream
+                ("/org/apache/tomcat/jni/SSL.properties");
+            Properties props = new Properties();
+            props.load(is);
+            is.close();
+            serverAddr = props.getProperty("server.ip", "127.0.0.1");
+            serverPort = Integer.decode(props.getProperty("server.port", "4443")).intValue();
+            serverNmax = Integer.decode(props.getProperty("server.max", "1")).intValue();
+            serverCert = props.getProperty("server.cert", "server.pem");
+            serverKey  = props.getProperty("server.key", null);
+            serverCAFile   = props.getProperty("server.cacertificate", null);
+            serverCiphers  = props.getProperty("server.ciphers", "ALL");
+            serverPassword = props.getProperty("server.password", null);
+        }
+        catch (Throwable t) {
+            ; // Nothing
+        }
+    }
+
+    public SSLServer()
+    {
+        int i;
+        serverPool = Pool.create(0);
+        try {
+            /* Create SSL Context, one for each Virtual Host */
+            serverCtx = SSLContext.make(serverPool, SSL.SSL_PROTOCOL_SSLV2 | SSL.SSL_PROTOCOL_SSLV3, SSL.SSL_MODE_SERVER);
+            /* List the ciphers that the client is permitted to negotiate. */
+            SSLContext.setCipherSuite(serverCtx, serverCiphers);
+            /* Load Server key and certificate */
+            SSLContext.setCertificate(serverCtx, serverCert, serverKey, serverPassword, SSL.SSL_AIDX_RSA);
+            SSLContext.setVerify(serverCtx, SSL.SSL_CVERIFY_NONE, 10);
+            serverAcceptor = new Acceptor();
+            serverAcceptor.start();
+
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+
+    }
+    public static void incThreads() {
+        synchronized(threadLock) {
+            serverNrun++;
+        }
+    }
+
+    public static void decThreads() {
+        synchronized(threadLock) {
+            serverNrun--;
+        }
+    }
+
+    /* Acceptor thread. Listens for new connections */
+    private class Acceptor extends Thread {
+        private long serverSock = 0;
+        private long inetAddress = 0;
+        private long pool = 0;
+        public Acceptor() throws Exception {
+            try {
+
+                pool = Pool.create(SSLServer.serverPool);
+                System.out.println("Accepting: " +  SSLServer.serverAddr + ":" +
+                                   SSLServer.serverPort);
+                inetAddress = Address.info(SSLServer.serverAddr, Socket.APR_INET,
+                                           SSLServer.serverPort, 0,
+                                           pool);
+                serverSock = Socket.create(Socket.APR_INET, Socket.SOCK_STREAM,
+                                           Socket.APR_PROTO_TCP, pool);
+                int rc = Socket.bind(serverSock, inetAddress);
+                if (rc != 0) {
+                  throw(new Exception("Can't create Acceptor: bind: " + Error.strerror(rc)));
+                }
+                Socket.listen(serverSock, 5);
+            }
+            catch( Exception ex ) {
+                ex.printStackTrace();
+                throw(new Exception("Can't create Acceptor"));
+            }
+        }
+
+        public void run() {
+            int i = 0;
+            try {
+                while (true) {
+                    long clientSock = Socket.accept(serverSock);
+                    System.out.println("Accepted id: " +  i);
+
+                    try {
+                        long sa = Address.get(Socket.APR_REMOTE, clientSock);
+                        Sockaddr raddr = new Sockaddr();
+                        if (Address.fill(raddr, sa)) {
+                            System.out.println("Remote Host: " + Address.getnameinfo(sa, 0));
+                            System.out.println("Remote IP: " + Address.getip(sa) +
+                                               ":" + raddr.port);
+                        }
+                        sa = Address.get(Socket.APR_LOCAL, clientSock);
+                        Sockaddr laddr = new Sockaddr();
+                        if (Address.fill(laddr, sa)) {
+                            System.out.println("Local Host: " + laddr.hostname);
+                            System.out.println("Local Server: " + Address.getnameinfo(sa, 0));
+                            System.out.println("Local IP: " + Address.getip(sa) +
+                                               ":" + laddr.port);
+                        }
+
+                    } catch (Exception e) {
+                        // Ignore
+                        e.printStackTrace();
+                    }
+
+                    Socket.timeoutSet(clientSock, 10000000);
+                    SSLSocket.attach(SSLServer.serverCtx, clientSock);
+                    i = SSLSocket.handshake(clientSock);
+                    if (i == 0) {
+
+                        Worker worker = new Worker(clientSock, i++,
+                                                   this.getClass().getName());
+                        SSLServer.incThreads();
+                        worker.start();
+                        
+                    }
+                    else {
+                        System.out.println("Handshake error: " + SSL.getLastError());
+                        Socket.destroy(clientSock);
+                    }
+                }
+            }
+            catch( Exception ex ) {
+                ex.printStackTrace();
+            }
+        }
+    }
+
+    private class Worker extends Thread {
+        private int workerId = 0;
+        private long clientSock = 0;
+        private byte [] wellcomeMsg = null;
+
+        public Worker(long clientSocket, int workerId, String from) {
+            this.clientSock = clientSocket;
+            this.workerId = workerId;
+            wellcomeMsg = ("SSLServer server id: " + this.workerId + " from " +
+                           from + "\r\n").getBytes();
+        }
+
+        public void run() {
+            boolean doClose = false;
+            try {
+                Socket.send(clientSock, wellcomeMsg, 0, wellcomeMsg.length);
+                while (!doClose) {
+                    /* Do a blocking read byte at a time */
+                    byte [] buf = new byte[1];
+                    int ret;
+                    ret = Socket.recv(clientSock, buf, 0, 1);
+                    if (ret != 1)
+                        throw(new Exception("Socket.recv failed"));
+
+                    if (buf[0] == '\n')
+                        continue;
+                    else if (buf[0] == '!') {
+                        doClose = true;
+                    }
+                    Socket.send(clientSock, buf, 0, 1);
+
+                    if (doClose) {
+                        try {
+                            byte [] msg = ("Bye from worker: " + workerId + "\r\n").getBytes();
+                            Socket.send(clientSock, msg, 0, msg.length);
+                        } catch(Exception e) { }
+
+                        Socket.close(clientSock);
+                    }
+                }
+            } catch (Exception e) {
+                Socket.destroy(clientSock);
+                e.printStackTrace();
+            }
+            Echo.decThreads();
+            System.out.println("Worker: " +  workerId + " finished");
+        }
+    }
+
+
+    public static void main(String [] args) {
+        try {
+            Library.initialize(null);
+            SSL.initialize(null);
+
+            SSLServer server = new SSLServer();
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+ }

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jni/java/org/apache/tomcat/Apr.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jni/java/org/apache/tomcat/Apr.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jni/java/org/apache/tomcat/Apr.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2000-2005 The Apache Software Foundation
+ *
+ * Licensed 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;
+
+import java.io.InputStream;
+import java.util.Properties;
+
+public class Apr {
+    private static String aprInfo = null;
+
+    static {
+
+        try {
+            InputStream is = Apr.class.getResourceAsStream
+                ("/org/apache/tomcat/apr.properties");
+            Properties props = new Properties();
+            props.load(is);
+            is.close();
+            aprInfo = props.getProperty("tcn.info");
+        }
+        catch (Throwable t) {
+            ; // Nothing
+        }
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jni/java/org/apache/tomcat/apr.properties
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jni/java/org/apache/tomcat/apr.properties	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jni/java/org/apache/tomcat/apr.properties	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1 @@
+tcn.info=Tomcat Native/@VERSION@

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jni/java/org/apache/tomcat/jni/Address.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jni/java/org/apache/tomcat/jni/Address.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jni/java/org/apache/tomcat/jni/Address.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,113 @@
+/*
+ *  Copyright 2000-2005 The Apache Software Foundation
+ *
+ *  Licensed 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.jni;
+
+/** Address
+ *
+ * @author Mladen Turk
+ * @version $Revision: 300969 $, $Date: 2005-07-12 09:56:11 -0500 (Tue, 12 Jul 2005) $
+ */
+
+public class Address {
+
+    static public String APR_ANYADDR = "0.0.0.0";
+    /**
+     * Fill the Sockaddr class from apr_sockaddr_t
+     * @param info Sockaddr class to fill
+     * @param sa Structure pointer
+     */
+    public static native boolean fill(Sockaddr info, long sa);
+
+    /**
+     * Create the Sockaddr object from apr_sockaddr_t
+     * @param sa Structure pointer
+     */
+    public static native Sockaddr getInfo(long sa);
+
+    /**
+     * Create apr_sockaddr_t from hostname, address family, and port.
+     * @param hostname The hostname or numeric address string to resolve/parse, or
+     *               NULL to build an address that corresponds to 0.0.0.0 or ::
+     * @param family The address family to use, or APR_UNSPEC if the system should
+     *               decide.
+     * @param port The port number.
+     * @param flags Special processing flags:
+     * <PRE>
+     *       APR_IPV4_ADDR_OK          first query for IPv4 addresses; only look
+     *                                 for IPv6 addresses if the first query failed;
+     *                                 only valid if family is APR_UNSPEC and hostname
+     *                                 isn't NULL; mutually exclusive with
+     *                                 APR_IPV6_ADDR_OK
+     *       APR_IPV6_ADDR_OK          first query for IPv6 addresses; only look
+     *                                 for IPv4 addresses if the first query failed;
+     *                                 only valid if family is APR_UNSPEC and hostname
+     *                                 isn't NULL and APR_HAVE_IPV6; mutually exclusive
+     *                                 with APR_IPV4_ADDR_OK
+     * </PRE>
+     * @param p The pool for the apr_sockaddr_t and associated storage.
+     * @return The new apr_sockaddr_t.
+     */
+    public static native long info(String hostname, int family,
+                                   int port, int flags, long p)
+        throws Exception;
+    /**
+     * Look up the host name from an apr_sockaddr_t.
+     * @param sa The apr_sockaddr_t.
+     * @param flags Special processing flags.
+     * @return The hostname.
+     */
+    public static native String getnameinfo(long sa, int flags);
+
+    /**
+     * Return the IP address (in numeric address string format) in
+     * an APR socket address.  APR will allocate storage for the IP address
+     * string from the pool of the apr_sockaddr_t.
+     * @param sa The socket address to reference.
+     * @return The IP address.
+     */
+    public static native String getip(long sa);
+
+    /**
+     * Given an apr_sockaddr_t and a service name, set the port for the service
+     * @param sockaddr The apr_sockaddr_t that will have its port set
+     * @param servname The name of the service you wish to use
+     * @return APR status code.
+     */
+    public static native int getservbyname(long sockaddr, String servname);
+
+    /**
+     * Return an apr_sockaddr_t from an apr_socket_t
+     * @param which Which interface do we want the apr_sockaddr_t for?
+     * @param sock The socket to use
+     * @return The returned apr_sockaddr_t.
+     */
+    public static native long get(int which, long sock)
+        throws Exception;
+
+    /**
+     * See if the IP addresses in two APR socket addresses are
+     * equivalent.  Appropriate logic is present for comparing
+     * IPv4-mapped IPv6 addresses with IPv4 addresses.
+     *
+     * @param a One of the APR socket addresses.
+     * @param b The other APR socket address.
+     * The return value will be True if the addresses
+     * are equivalent.
+     */
+    public static native boolean equal(long a, long b);
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jni/java/org/apache/tomcat/jni/BIOCallback.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jni/java/org/apache/tomcat/jni/BIOCallback.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jni/java/org/apache/tomcat/jni/BIOCallback.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,55 @@
+/*
+ *  Copyright 2000-2005 The Apache Software Foundation
+ *
+ *  Licensed 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.jni;
+
+/** Open SSL BIO Callback Interface
+ *
+ * @author Mladen Turk
+ * @version $Revision: 300969 $, $Date: 2005-07-12 09:56:11 -0500 (Tue, 12 Jul 2005) $
+ */
+
+public interface BIOCallback {
+
+    /**
+     * Write data
+     * @param buf containg the bytes to write.
+     * @return Number of characters written.
+     */
+    public int write(byte [] buf);
+
+    /**
+     * Read data
+     * @param buf buffer to store the read bytes.
+     * @return number of bytes read.
+     */
+    public int read(byte [] buf);
+
+    /**
+     * Puts string
+     * @param data String to write
+     * @return Number of characters written
+     */
+    public int puts(String data);
+
+    /**
+     * Read string up to the len or CLRLF
+     * @param len Maximum number of characters to read
+     * @return String with up to len bytes readed
+     */
+    public String gets(int len);
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jni/java/org/apache/tomcat/jni/Directory.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jni/java/org/apache/tomcat/jni/Directory.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jni/java/org/apache/tomcat/jni/Directory.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,96 @@
+/*
+ *  Copyright 2000-2005 The Apache Software Foundation
+ *
+ *  Licensed 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.jni;
+
+/** Directory
+ *
+ * @author Mladen Turk
+ * @version $Revision: 300969 $, $Date: 2005-07-12 09:56:11 -0500 (Tue, 12 Jul 2005) $
+ */
+
+public class Directory {
+
+    /**
+     * Create a new directory on the file system.
+     * @param path the path for the directory to be created. (use / on all systems)
+     * @param perm Permissions for the new direcoty.
+     * @param pool the pool to use.
+     */
+    public static native int make(String path, int perm, long pool);
+
+    /** Creates a new directory on the file system, but behaves like
+     * 'mkdir -p'. Creates intermediate directories as required. No error
+     * will be reported if PATH already exists.
+     * @param path the path for the directory to be created. (use / on all systems)
+     * @param perm Permissions for the new direcoty.
+     * @param pool the pool to use.
+     */
+    public static native int makeRecursive(String path, int perm, long pool);
+
+    /**
+     * Remove directory from the file system.
+     * @param path the path for the directory to be removed. (use / on all systems)
+     * @param pool the pool to use.
+     */
+    public static native int remove(String path, long pool);
+
+    /**
+     * Find an existing directory suitable as a temporary storage location.
+     * @param pool The pool to use for any necessary allocations.
+     * @return The temp directory.
+     * 
+     * This function uses an algorithm to search for a directory that an
+     * an application can use for temporary storage.  Once such a
+     * directory is found, that location is cached by the library.  Thus,
+     * callers only pay the cost of this algorithm once if that one time
+     * is successful.
+     *
+     */
+    public static native String tempGet(long pool);
+
+    /**
+     * Open the specified directory.
+     * @param dirname The full path to the directory (use / on all systems)
+     * @param pool The pool to use.
+     * @return The opened directory descriptor.
+     */
+    public static native long open(String dirname, long pool)
+        throws Error;
+
+    /**
+     * close the specified directory.
+     * @param thedir the directory descriptor to close.
+     */
+    public static native int close(long thedir);
+
+    /**
+     * Rewind the directory to the first entry.
+     * @param thedir the directory descriptor to rewind.
+     */
+    public static native int rewind(long thedir);
+
+
+    /**
+     * Read the next entry from the specified directory.
+     * @param finfo the file info structure and filled in by apr_dir_read
+     * @param wanted The desired apr_finfo_t fields, as a bit flag of APR_FINFO_ values
+     * @param thedir the directory descriptor returned from apr_dir_open
+     * No ordering is guaranteed for the entries read.
+     */
+    public static native int read(FileInfo finfo, int wanted, long thedir);
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jni/java/org/apache/tomcat/jni/Error.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jni/java/org/apache/tomcat/jni/Error.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jni/java/org/apache/tomcat/jni/Error.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,95 @@
+/*
+ *  Copyright 2000-2005 The Apache Software Foundation
+ *
+ *  Licensed 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.jni;
+
+/** Error
+ *
+ * @author Mladen Turk
+ * @version $Revision: 300969 $, $Date: 2005-07-12 09:56:11 -0500 (Tue, 12 Jul 2005) $
+ */
+
+public class Error extends Exception {
+
+    /**
+     * APR error type.
+     */
+    private int error;
+
+    /**
+     * A description of the problem.
+     */
+    private String description;
+
+    /**
+     * Construct an APRException.
+     *
+     * @param error one of the value in Error
+     * @param description error message
+     */
+    private Error(int error, String description)
+    {
+        super(description);
+        this.error = error;
+        this.description = description;
+    }
+
+    /**
+     * Get the APR error code of the exception.
+     *
+     * @return error of the Exception
+     */
+    public int getError()
+    {
+        return error;
+    }
+
+    /**
+     * Get the APR description of the exception.
+     *
+     * @return description of the Exception
+     */
+    public String getDescription()
+    {
+        return description;
+    }
+
+    /**
+     * Get the last platform error.
+     * @return apr_status_t the last platform error, folded into apr_status_t, on most platforms
+     * This retrieves errno, or calls a GetLastError() style function, and
+     *      folds it with APR_FROM_OS_ERROR.  Some platforms (such as OS2) have no
+     *      such mechanism, so this call may be unsupported.  Do NOT use this
+     *      call for socket errors from socket, send, recv etc!
+     */
+    public static native int osError();
+
+    /**
+     * Get the last platform socket error.
+     * @return the last socket error, folded into apr_status_t, on all platforms
+     * This retrieves errno or calls a GetLastSocketError() style function,
+     *      and folds it with APR_FROM_OS_ERROR.
+     */
+    public static native int netosError();
+
+    /**
+     * Return a human readable string describing the specified error.
+     * @param statcode The error code the get a string for.
+     * @return The error string.
+    */
+    public static native String strerror(int statcode);
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jni/java/org/apache/tomcat/jni/File.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jni/java/org/apache/tomcat/jni/File.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jni/java/org/apache/tomcat/jni/File.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,702 @@
+/*
+ *  Copyright 2000-2005 The Apache Software Foundation
+ *
+ *  Licensed 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.jni;
+/* Import needed classes */
+import java.nio.ByteBuffer;
+/** File
+ *
+ * @author Mladen Turk
+ * @version $Revision: 369000 $, $Date: 2006-01-14 02:08:44 -0600 (Sat, 14 Jan 2006) $
+ */
+
+public class File {
+
+    /** Open the file for reading */
+    public static final int APR_FOPEN_READ       = 0x00001;
+    /** Open the file for writing */
+    public static final int APR_FOPEN_WRITE      = 0x00002;
+    /** Create the file if not there */
+    public static final int APR_FOPEN_CREATE     = 0x00004;
+    /** Append to the end of the file */
+    public static final int APR_FOPEN_APPEND     = 0x00008;
+    /** Open the file and truncate to 0 length */
+    public static final int APR_FOPEN_TRUNCATE   = 0x00010;
+    /** Open the file in binary mode */
+    public static final int APR_FOPEN_BINARY     = 0x00020;
+    /** Open should fail if APR_CREATE and file exists. */
+    public static final int APR_FOPEN_EXCL       = 0x00040;
+    /** Open the file for buffered I/O */
+    public static final int APR_FOPEN_BUFFERED   = 0x00080;
+    /** Delete the file after close */
+    public static final int APR_FOPEN_DELONCLOSE = 0x00100;
+    /** Platform dependent tag to open the file for
+     * use across multiple threads
+     */
+    public static final int APR_FOPEN_XTHREAD     = 0x00200;
+    /** Platform dependent support for higher level locked read/write
+     * access to support writes across process/machines
+     */
+    public static final int APR_FOPEN_SHARELOCK   = 0x00400;
+    /** Do not register a cleanup when the file is opened */
+    public static final int APR_FOPEN_NOCLEANUP   = 0x00800;
+    /** Advisory flag that this file should support
+     * apr_socket_sendfile operation
+     */
+    public static final int APR_FOPEN_SENDFILE_ENABLED = 0x01000;
+    /** Platform dependent flag to enable large file support;
+     * <br /><b>Warning :</b> The APR_LARGEFILE flag only has effect on some platforms
+     * where sizeof(apr_off_t) == 4.  Where implemented, it allows opening
+     * and writing to a file which exceeds the size which can be
+     * represented by apr_off_t (2 gigabytes).  When a file's size does
+     * exceed 2Gb, apr_file_info_get() will fail with an error on the
+     * descriptor, likewise apr_stat()/apr_lstat() will fail on the
+     * filename.  apr_dir_read() will fail with APR_INCOMPLETE on a
+     * directory entry for a large file depending on the particular
+     * APR_FINFO_* flags.  Generally, it is not recommended to use this
+     * flag.
+     */
+    public static final int APR_FOPEN_LARGEFILE      = 0x04000;
+
+    /** Set the file position */
+    public static final int APR_SET = 0;
+    /** Current */
+    public static final int APR_CUR = 1;
+    /** Go to end of file */
+    public static final int APR_END = 2;
+
+    /* flags for apr_file_attrs_set */
+
+    /** File is read-only */
+    public static final int APR_FILE_ATTR_READONLY   = 0x01;
+    /** File is executable */
+    public static final int APR_FILE_ATTR_EXECUTABLE = 0x02;
+    /** File is hidden */
+    public static final int APR_FILE_ATTR_HIDDEN     = 0x04;
+
+
+    /* File lock types/flags */
+
+    /** Shared lock. More than one process or thread can hold a shared lock
+     * at any given time. Essentially, this is a "read lock", preventing
+     * writers from establishing an exclusive lock.
+     */
+    public static final int APR_FLOCK_SHARED    = 1;
+
+    /** Exclusive lock. Only one process may hold an exclusive lock at any
+     * given time. This is analogous to a "write lock".
+     */
+    public static final int APR_FLOCK_EXCLUSIVE = 2;
+    /** mask to extract lock type */
+    public static final int APR_FLOCK_TYPEMASK  = 0x000F;
+    /** do not block while acquiring the file lock */
+    public static final int APR_FLOCK_NONBLOCK  = 0x0010;
+
+    /* apr_filetype_e values for the filetype member of the
+     * apr_file_info_t structure
+     * <br /><b>Warning :</b>: Not all of the filetypes below can be determined.
+     * For example, a given platform might not correctly report
+     * a socket descriptor as APR_SOCK if that type isn't
+     * well-identified on that platform.  In such cases where
+     * a filetype exists but cannot be described by the recognized
+     * flags below, the filetype will be APR_UNKFILE.  If the
+     * filetype member is not determined, the type will be APR_NOFILE.
+     */
+
+    /** no file type determined */
+    public static final int APR_NOFILE  = 0;
+    /** a regular file */
+    public static final int APR_REG     = 1;
+    /** a directory */
+    public static final int APR_DIR     = 2;
+    /** a character device */
+    public static final int APR_CHR     = 3;
+    /** a block device */
+    public static final int APR_BLK     = 4;
+    /** a FIFO / pipe */
+    public static final int APR_PIPE    = 5;
+    /** a symbolic link */
+    public static final int APR_LNK     = 6;
+    /** a [unix domain] socket */
+    public static final int APR_SOCK    = 7;
+    /** a file of some other unknown type */
+    public static final int APR_UNKFILE = 127;
+
+
+    /*
+     * apr_file_permissions File Permissions flags
+     */
+
+    public static final int APR_FPROT_USETID     = 0x8000; /** Set user id */
+    public static final int APR_FPROT_UREAD      = 0x0400; /** Read by user */
+    public static final int APR_FPROT_UWRITE     = 0x0200; /** Write by user */
+    public static final int APR_FPROT_UEXECUTE   = 0x0100; /** Execute by user */
+
+    public static final int APR_FPROT_GSETID     = 0x4000; /** Set group id */
+    public static final int APR_FPROT_GREAD      = 0x0040; /** Read by group */
+    public static final int APR_FPROT_GWRITE     = 0x0020; /** Write by group */
+    public static final int APR_FPROT_GEXECUTE   = 0x0010; /** Execute by group */
+
+    public static final int APR_FPROT_WSTICKY    = 0x2000; /** Sticky bit */
+    public static final int APR_FPROT_WREAD      = 0x0004; /** Read by others */
+    public static final int APR_FPROT_WWRITE     = 0x0002; /** Write by others */
+    public static final int APR_FPROT_WEXECUTE   = 0x0001; /** Execute by others */
+    public static final int APR_FPROT_OS_DEFAULT = 0x0FFF; /** use OS's default permissions */
+
+
+    public static final int APR_FINFO_LINK   = 0x00000001; /** Stat the link not the file itself if it is a link */
+    public static final int APR_FINFO_MTIME  = 0x00000010; /** Modification Time */
+    public static final int APR_FINFO_CTIME  = 0x00000020; /** Creation or inode-changed time */
+    public static final int APR_FINFO_ATIME  = 0x00000040; /** Access Time */
+    public static final int APR_FINFO_SIZE   = 0x00000100; /** Size of the file */
+    public static final int APR_FINFO_CSIZE  = 0x00000200; /** Storage size consumed by the file */
+    public static final int APR_FINFO_DEV    = 0x00001000; /** Device */
+    public static final int APR_FINFO_INODE  = 0x00002000; /** Inode */
+    public static final int APR_FINFO_NLINK  = 0x00004000; /** Number of links */
+    public static final int APR_FINFO_TYPE   = 0x00008000; /** Type */
+    public static final int APR_FINFO_USER   = 0x00010000; /** User */
+    public static final int APR_FINFO_GROUP  = 0x00020000; /** Group */
+    public static final int APR_FINFO_UPROT  = 0x00100000; /** User protection bits */
+    public static final int APR_FINFO_GPROT  = 0x00200000; /** Group protection bits */
+    public static final int APR_FINFO_WPROT  = 0x00400000; /** World protection bits */
+    public static final int APR_FINFO_ICASE  = 0x01000000; /** if dev is case insensitive */
+    public static final int APR_FINFO_NAME   = 0x02000000; /** ->name in proper case */
+
+    public static final int APR_FINFO_MIN    = 0x00008170; /** type, mtime, ctime, atime, size */
+    public static final int APR_FINFO_IDENT  = 0x00003000; /** dev and inode */
+    public static final int APR_FINFO_OWNER  = 0x00030000; /** user and group */
+    public static final int APR_FINFO_PROT   = 0x00700000; /**  all protections */
+    public static final int APR_FINFO_NORM   = 0x0073b170; /**  an atomic unix apr_stat() */
+    public static final int APR_FINFO_DIRENT = 0x02000000; /**  an atomic unix apr_dir_read() */
+
+
+
+    /**
+     * Open the specified file.
+     * @param fname The full path to the file (using / on all systems)
+     * @param flag Or'ed value of:
+     * <PRE>
+     * APR_FOPEN_READ              open for reading
+     * APR_FOPEN_WRITE             open for writing
+     * APR_FOPEN_CREATE            create the file if not there
+     * APR_FOPEN_APPEND            file ptr is set to end prior to all writes
+     * APR_FOPEN_TRUNCATE          set length to zero if file exists
+     * APR_FOPEN_BINARY            not a text file (This flag is ignored on
+     *                             UNIX because it has no meaning)
+     * APR_FOPEN_BUFFERED          buffer the data.  Default is non-buffered
+     * APR_FOPEN_EXCL              return error if APR_CREATE and file exists
+     * APR_FOPEN_DELONCLOSE        delete the file after closing.
+     * APR_FOPEN_XTHREAD           Platform dependent tag to open the file
+     *                             for use across multiple threads
+     * APR_FOPEN_SHARELOCK         Platform dependent support for higher
+     *                             level locked read/write access to support
+     *                             writes across process/machines
+     * APR_FOPEN_NOCLEANUP         Do not register a cleanup with the pool
+     *                             passed in on the <EM>pool</EM> argument (see below).
+     *                             The apr_os_file_t handle in apr_file_t will not
+     *                             be closed when the pool is destroyed.
+     * APR_FOPEN_SENDFILE_ENABLED  Open with appropriate platform semantics
+     *                             for sendfile operations.  Advisory only,
+     *                             apr_socket_sendfile does not check this flag.
+     * </PRE>
+     * @param perm Access permissions for file.
+     * @param pool The pool to use.
+     * If perm is APR_OS_DEFAULT and the file is being created,
+     * appropriate default permissions will be used.
+     * @return The opened file descriptor.
+     */
+    public static native long open(String fname, int flag, int perm, long pool)
+        throws Error;
+
+    /**
+     * Close the specified file.
+     * @param file The file descriptor to close.
+     */
+    public static native int close(long file);
+
+    /**
+     * Flush the file's buffer.
+     * @param thefile The file descriptor to flush
+     */
+    public static native int flush(long thefile);
+
+    /**
+     * Open a temporary file
+     * @param templ The template to use when creating a temp file.
+     * @param flags The flags to open the file with. If this is zero,
+     *              the file is opened with
+     *              APR_CREATE | APR_READ | APR_WRITE | APR_EXCL | APR_DELONCLOSE
+     * @param pool The pool to allocate the file out of.
+     * @return The apr file to use as a temporary file.
+     * 
+     * This function  generates  a unique temporary file name from template.
+     * The last six characters of template must be XXXXXX and these are replaced
+     * with a string that makes the filename unique. Since it will  be  modified,
+     * template must not be a string constant, but should be declared as a character
+     * array.
+     *
+     */
+    public static native long mktemp(String templ, int flags, long pool)
+        throws Error;
+
+    /**
+     * Delete the specified file.
+     * @param path The full path to the file (using / on all systems)
+     * @param pool The pool to use.
+     * If the file is open, it won't be removed until all
+     * instances are closed.
+     */
+    public static native int remove(String path, long pool);
+
+    /**
+     * Rename the specified file.
+     * <br /><b>Warning :</b> If a file exists at the new location, then it will be
+     * overwritten.  Moving files or directories across devices may not be
+     * possible.
+     * @param fromPath The full path to the original file (using / on all systems)
+     * @param toPath The full path to the new file (using / on all systems)
+     * @param pool The pool to use.
+     */
+    public static native int rename(String fromPath, String toPath, long pool);
+
+    /**
+     * Copy the specified file to another file.
+     * The new file does not need to exist, it will be created if required.
+     * <br /><b>Warning :</b> If the new file already exists, its contents will be overwritten.
+     * @param fromPath The full path to the original file (using / on all systems)
+     * @param toPath The full path to the new file (using / on all systems)
+     * @param perms Access permissions for the new file if it is created.
+     *     In place of the usual or'd combination of file permissions, the
+     *     value APR_FILE_SOURCE_PERMS may be given, in which case the source
+     *     file's permissions are copied.
+     * @param pool The pool to use.
+     */
+    public static native int copy(String fromPath, String toPath, int perms, long pool);
+
+    /**
+     * Append the specified file to another file.
+     * The new file does not need to exist, it will be created if required.
+     * @param fromPath The full path to the source file (use / on all systems)
+     * @param toPath The full path to the destination file (use / on all systems)
+     * @param perms Access permissions for the destination file if it is created.
+     *     In place of the usual or'd combination of file permissions, the
+     *     value APR_FILE_SOURCE_PERMS may be given, in which case the source
+     *     file's permissions are copied.
+     * @param pool The pool to use.
+     */
+    public static native int append(String fromPath, String toPath, int perms, long pool);
+
+    /**
+     * Write the string into the specified file.
+     * @param str The string to write. Must be NUL terminated!
+     * @param thefile The file descriptor to write to
+     */
+    public static native int puts(byte [] str, long thefile);
+
+    /**
+     * Move the read/write file offset to a specified byte within a file.
+     * @param thefile The file descriptor
+     * @param where How to move the pointer, one of:
+     * <PRE>
+     * APR_SET  --  set the offset to offset
+     * APR_CUR  --  add the offset to the current position
+     * APR_END  --  add the offset to the current file size
+     * </PRE>
+     * @param offset The offset to move the pointer to.
+     * @return Offset the pointer was actually moved to.
+     */
+    public static native long seek(long thefile, int where, long offset)
+        throws Error;
+
+    /**
+     * Write a character into the specified file.
+     * @param ch The character to write.
+     * @param thefile The file descriptor to write to
+     */
+    public static native int putc(byte ch, long thefile);
+
+    /**
+     * Put a character back onto a specified stream.
+     * @param ch The character to write.
+     * @param thefile The file descriptor to write to
+     */
+    public static native int ungetc(byte ch, long thefile);
+
+    /**
+     * Write data to the specified file.
+     *
+     * Write will write up to the specified number of
+     * bytes, but never more.  If the OS cannot write that many bytes, it
+     * will write as many as it can.  The third argument is modified to
+     * reflect the * number of bytes written.
+     *
+     * It is possible for both bytes to be written and an error to
+     * be returned.  APR_EINTR is never returned.
+     * @param thefile The file descriptor to write to.
+     * @param buf The buffer which contains the data.
+     * @param offset Start offset in buf
+     * @param nbytes The number of bytes to write; (-1) for full array.
+     * @return The number of bytes written.
+     */
+    public static native int write(long thefile, byte[] buf, int offset, int nbytes);
+
+    /**
+     * Write data to the specified file.
+     *
+     * Write will write up to the specified number of
+     * bytes, but never more.  If the OS cannot write that many bytes, it
+     * will write as many as it can.  The third argument is modified to
+     * reflect the * number of bytes written.
+     *
+     * It is possible for both bytes to be written and an error to
+     * be returned.  APR_EINTR is never returned.
+     * @param thefile The file descriptor to write to.
+     * @param buf The direct Byte buffer which contains the data.
+     * @param offset Start offset in buf
+     * @param nbytes The number of bytes to write
+     * @return The number of bytes written.
+     */
+    public static native int writeb(long thefile, ByteBuffer buf, int offset, int nbytes);
+
+    /**
+     * Write data to the specified file, ensuring that all of the data is
+     * written before returning.
+     *
+     * Write will write up to the specified number of
+     * bytes, but never more.  If the OS cannot write that many bytes, the
+     * process/thread will block until they can be written. Exceptional
+     * error such as "out of space" or "pipe closed" will terminate with
+     * an error.
+     *
+     * It is possible for both bytes to be written and an error to
+     * be returned.  And if *bytes_written is less than nbytes, an
+     * accompanying error is _always_ returned.
+     *
+     * APR_EINTR is never returned.
+     * @param thefile The file descriptor to write to.
+     * @param buf The buffer which contains the data.
+     * @param offset Start offset in buf
+     * @param nbytes The number of bytes to write; (-1) for full array.
+     * @return The number of bytes written.
+     */
+    public static native int writeFull(long thefile, byte[] buf, int offset, int nbytes);
+
+    /**
+     * Write data to the specified file, ensuring that all of the data is
+     * written before returning.
+     *
+     * Write will write up to the specified number of
+     * bytes, but never more.  If the OS cannot write that many bytes, the
+     * process/thread will block until they can be written. Exceptional
+     * error such as "out of space" or "pipe closed" will terminate with
+     * an error.
+     *
+     * It is possible for both bytes to be written and an error to
+     * be returned.  And if *bytes_written is less than nbytes, an
+     * accompanying error is _always_ returned.
+     *
+     * APR_EINTR is never returned.
+     * @param thefile The file descriptor to write to.
+     * @param buf The direct ByteBuffer which contains the data.
+     * @param offset Start offset in buf
+     * @param nbytes The number of bytes to write.
+     * @return The number of bytes written.
+     */
+    public static native int writeFullb(long thefile, ByteBuffer buf, int offset, int nbytes);
+
+    /**
+     * Write data from aray of byte arrays to the specified file.
+     *
+     * It is possible for both bytes to be written and an error to
+     * be returned.  APR_EINTR is never returned.
+     *
+     * apr_file_writev is available even if the underlying
+     * operating system doesn't provide writev().
+     * @param thefile The file descriptor to write to.
+     * @param vec The array from which to get the data to write to the file.
+     * @return The number of bytes written.
+     */
+    public static native int writev(long thefile, byte[][] vec);
+
+    /**
+     * Write data from aray of byte arrays to the specified file,
+     * ensuring that all of the data is written before returning.
+     *
+     * writevFull is available even if the underlying
+     * operating system doesn't provide writev().
+     * @param thefile The file descriptor to write to.
+     * @param vec The array from which to get the data to write to the file.
+     * @return The number of bytes written.
+     */
+    public static native int writevFull(long thefile, byte[][] vec);
+
+    /**
+     * Read data from the specified file.
+     *
+     * apr_file_read will read up to the specified number of
+     * bytes, but never more.  If there isn't enough data to fill that
+     * number of bytes, all of the available data is read.  The third
+     * argument is modified to reflect the number of bytes read.  If a
+     * char was put back into the stream via ungetc, it will be the first
+     * character returned.
+     *
+     * It is not possible for both bytes to be read and an APR_EOF
+     * or other error to be returned.  APR_EINTR is never returned.
+     * @param thefile The file descriptor to read from.
+     * @param buf The buffer to store the data to.
+     * @param offset Start offset in buf
+     * @param nbytes The number of bytes to read (-1) for full array.
+     * @return the number of bytes read.
+     */
+    public static native int read(long thefile, byte[] buf,  int offset, int nbytes);
+
+    /**
+     * Read data from the specified file.
+     *
+     * apr_file_read will read up to the specified number of
+     * bytes, but never more.  If there isn't enough data to fill that
+     * number of bytes, all of the available data is read.  The third
+     * argument is modified to reflect the number of bytes read.  If a
+     * char was put back into the stream via ungetc, it will be the first
+     * character returned.
+     *
+     * It is not possible for both bytes to be read and an APR_EOF
+     * or other error to be returned.  APR_EINTR is never returned.
+     * @param thefile The file descriptor to read from.
+     * @param buf The direct Byte buffer to store the data to.
+     * @param offset Start offset in buf
+     * @param nbytes The number of bytes to read.
+     * @return the number of bytes read.
+     */
+    public static native int readb(long thefile, ByteBuffer buf,  int offset, int nbytes);
+
+    /**
+     * Read data from the specified file, ensuring that the buffer is filled
+     * before returning.
+     *
+     * Read will read up to the specified number of
+     * bytes, but never more.  If there isn't enough data to fill that
+     * number of bytes, then the process/thread will block until it is
+     * available or EOF is reached.  If a char was put back into the
+     * stream via ungetc, it will be the first character returned.
+     *
+     * It is possible for both bytes to be read and an error to be
+     * returned.  And if *bytes_read is less than nbytes, an accompanying
+     * error is _always_ returned.
+     *
+     * APR_EINTR is never returned.
+     * @param thefile The file descriptor to read from.
+     * @param buf The buffer to store the data to.
+     * @param offset Start offset in buf
+     * @param nbytes The number of bytes to read (-1) for full array.
+     * @return the number of bytes read.
+     */
+    public static native int readFull(long thefile, byte[] buf,  int offset, int nbytes);
+
+    /**
+     * Read data from the specified file, ensuring that the buffer is filled
+     * before returning.
+     *
+     * Read will read up to the specified number of
+     * bytes, but never more.  If there isn't enough data to fill that
+     * number of bytes, then the process/thread will block until it is
+     * available or EOF is reached.  If a char was put back into the
+     * stream via ungetc, it will be the first character returned.
+     *
+     * It is possible for both bytes to be read and an error to be
+     * returned.  And if *bytes_read is less than nbytes, an accompanying
+     * error is _always_ returned.
+     *
+     * APR_EINTR is never returned.
+     * @param thefile The file descriptor to read from.
+     * @param buf The direct ByteBuffer to store the data to.
+     * @param offset Start offset in buf
+     * @param nbytes The number of bytes to read.
+     * @return the number of bytes read.
+     */
+    public static native int readFullb(long thefile, ByteBuffer buf,  int offset, int nbytes);
+
+    /**
+     * Read a string from the specified file.
+     * The buffer will be NUL-terminated if any characters are stored.
+     * @param buf The buffer to store the string in.
+     * @param offset Start offset in buf
+     * @param thefile The file descriptor to read from
+     */
+    public static native int gets(byte[] buf,  int offset, long thefile);
+
+
+    /**
+     * Read a character from the specified file.
+     * @param thefile The file descriptor to read from
+     * @return The readed character
+     */
+    public static native int getc(long thefile)
+        throws Error;
+
+    /**
+     * Are we at the end of the file
+     * @param fptr The apr file we are testing.
+     * @return Returns APR_EOF if we are at the end of file, APR_SUCCESS otherwise.
+     */
+    public static native int eof(long fptr);
+
+    /**
+     * return the file name of the current file.
+     * @param thefile The currently open file.
+     */
+    public static native String nameGet(long thefile);
+
+    /**
+     * Set the specified file's permission bits.
+     * <br /><b>Warning :</b> Some platforms may not be able to apply all of the
+     * available permission bits; APR_INCOMPLETE will be returned if some
+     * permissions are specified which could not be set.
+     * <br /><b>Warning :</b> Platforms which do not implement this feature will return
+     * APR_ENOTIMPL.
+     * @param fname The file (name) to apply the permissions to.
+     * @param perms The permission bits to apply to the file.
+     *
+     */
+    public static native int permsSet(String fname, int perms);
+
+    /**
+     * Set attributes of the specified file.
+     * This function should be used in preference to explict manipulation
+     *      of the file permissions, because the operations to provide these
+     *      attributes are platform specific and may involve more than simply
+     *      setting permission bits.
+     * <br /><b>Warning :</b> Platforms which do not implement this feature will return
+     *      APR_ENOTIMPL.
+     * @param fname The full path to the file (using / on all systems)
+     * @param attributes Or'd combination of
+     * <PRE>
+     *            APR_FILE_ATTR_READONLY   - make the file readonly
+     *            APR_FILE_ATTR_EXECUTABLE - make the file executable
+     *            APR_FILE_ATTR_HIDDEN     - make the file hidden
+     * </PRE>
+     * @param mask Mask of valid bits in attributes.
+     * @param pool the pool to use.
+     */
+    public static native int  attrsSet(String fname, int attributes, int mask, long pool);
+
+    /**
+     * Set the mtime of the specified file.
+     * <br /><b>Warning :</b> Platforms which do not implement this feature will return
+     *      APR_ENOTIMPL.
+     * @param fname The full path to the file (using / on all systems)
+     * @param mtime The mtime to apply to the file in microseconds
+     * @param pool The pool to use.
+     */
+    public static native int  mtimeSet(String fname, long mtime, long pool);
+
+    /**
+     * Establish a lock on the specified, open file. The lock may be advisory
+     * or mandatory, at the discretion of the platform. The lock applies to
+     * the file as a whole, rather than a specific range. Locks are established
+     * on a per-thread/process basis; a second lock by the same thread will not
+     * block.
+     * @param thefile The file to lock.
+     * @param type The type of lock to establish on the file.
+     */
+    public static native int lock(long thefile, int type);
+
+    /**
+     * Remove any outstanding locks on the file.
+     * @param thefile The file to unlock.
+     */
+    public static native int unlock(long thefile);
+
+    /**
+     * Retrieve the flags that were passed into apr_file_open()
+     * when the file was opened.
+     * @param file The file to retrive flags.
+     * @return the flags
+     */
+    public static native int flagsGet(long file);
+
+    /**
+     * Truncate the file's length to the specified offset
+     * @param fp The file to truncate
+     * @param offset The offset to truncate to.
+     */
+    public static native int trunc(long fp, long offset);
+
+    /**
+     * Create an anonymous pipe.
+     * @param io io[0] The file descriptors to use as input to the pipe.
+     *           io[1] The file descriptor to use as output from the pipe.
+     * @param pool The pool to operate on.
+     */
+    public static native int pipeCreate(long [] io, long pool);
+
+    /**
+     * Get the timeout value for a pipe or manipulate the blocking state.
+     * @param thepipe The pipe we are getting a timeout for.
+     * @return The current timeout value in microseconds.
+     */
+    public static native long pipeTimeoutGet(long thepipe)
+        throws Error;
+
+    /**
+     * Set the timeout value for a pipe or manipulate the blocking state.
+     * @param thepipe The pipe we are setting a timeout on.
+     * @param timeout The timeout value in microseconds.  Values < 0 mean wait
+     *        forever, 0 means do not wait at all.
+     */
+    public static native int pipeTimeoutSet(long thepipe, long timeout);
+
+    /**
+     * Duplicate the specified file descriptor.
+     * @param newFile The file to duplicate.
+     * newFile must point to a valid apr_file_t, or point to NULL.
+     * @param oldFile The file to duplicate.
+     * @param pool The pool to use for the new file.
+     * @return Duplicated file structure.
+     */
+    public static native long dup(long newFile, long oldFile, long pool)
+        throws Error;
+
+    /**
+     * Duplicate the specified file descriptor and close the original.
+     * @param newFile The old file that is to be closed and reused.
+     * newFile MUST point at a valid apr_file_t. It cannot be NULL.
+     * @param oldFile The file to duplicate.
+     * @param pool The pool to use for the new file.
+     * @return Status code.
+     */
+    public static native int dup2(long newFile, long oldFile, long pool);
+
+    /**
+     * Get the specified file's stats.  The file is specified by filename,
+     * instead of using a pre-opened file.
+     * @param finfo Where to store the information about the file, which is
+     * never touched if the call fails.
+     * @param fname The name of the file to stat.
+     * @param wanted The desired apr_finfo_t fields, as a bit flag of APR_FINFO_ values
+     * @param pool the pool to use to allocate the new file.
+     */
+    public static native int stat(FileInfo finfo, String fname, int wanted, long pool);
+
+    /**
+     * Get the specified file's stats.
+     * @param finfo Where to store the information about the file.
+     * @param wanted The desired apr_finfo_t fields, as a bit flag of APR_FINFO_ values
+     * @param thefile The file to get information about.
+     */
+    public static native int infoGet(FileInfo finfo, int wanted, long thefile);
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jni/java/org/apache/tomcat/jni/FileInfo.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jni/java/org/apache/tomcat/jni/FileInfo.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jni/java/org/apache/tomcat/jni/FileInfo.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,66 @@
+/*
+ *  Copyright 2000-2005 The Apache Software Foundation
+ *
+ *  Licensed 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.jni;
+
+/** Fileinfo
+ *
+ * @author Mladen Turk
+ * @version $Revision: 300969 $, $Date: 2005-07-12 09:56:11 -0500 (Tue, 12 Jul 2005) $
+ */
+
+public class FileInfo {
+
+    /** Allocates memory and closes lingering handles in the specified pool */
+    public long pool;
+    /** The bitmask describing valid fields of this apr_finfo_t structure
+     *  including all available 'wanted' fields and potentially more */
+    public int valid;
+    /** The access permissions of the file.  Mimics Unix access rights. */
+    public int protection;
+    /** The type of file.  One of APR_REG, APR_DIR, APR_CHR, APR_BLK, APR_PIPE,
+     * APR_LNK or APR_SOCK.  If the type is undetermined, the value is APR_NOFILE.
+     * If the type cannot be determined, the value is APR_UNKFILE.
+     */
+    public int filetype;
+    /** The user id that owns the file */
+    public int user;
+    /** The group id that owns the file */
+    public int group;
+    /** The inode of the file. */
+    public int inode;
+    /** The id of the device the file is on. */
+    public int device;
+    /** The number of hard links to the file. */
+    public int nlink;
+    /** The size of the file */
+    public long size;
+    /** The storage size consumed by the file */
+    public long csize;
+    /** The time the file was last accessed */
+    public long atime;
+    /** The time the file was last modified */
+    public long mtime;
+    /** The time the file was created, or the inode was last changed */
+    public long ctime;
+    /** The pathname of the file (possibly unrooted) */
+    public String fname;
+    /** The file's name (no path) in filesystem case */
+    public String name;
+    /** The file's handle, if accessed (can be submitted to apr_duphandle) */
+    public long filehand;
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jni/java/org/apache/tomcat/jni/Global.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jni/java/org/apache/tomcat/jni/Global.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jni/java/org/apache/tomcat/jni/Global.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,95 @@
+/*
+ *  Copyright 2000-2005 The Apache Software Foundation
+ *
+ *  Licensed 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.jni;
+
+/** Global
+ *
+ * @author Mladen Turk
+ * @version $Revision: 300969 $, $Date: 2005-07-12 09:56:11 -0500 (Tue, 12 Jul 2005) $
+ */
+
+public class Global {
+
+    /**
+     * Create and initialize a mutex that can be used to synchronize both
+     * processes and threads. Note: There is considerable overhead in using
+     * this API if only cross-process or cross-thread mutual exclusion is
+     * required. See apr_proc_mutex.h and apr_thread_mutex.h for more
+     * specialized lock routines.
+     * <br /><b>Warning :</b> Check APR_HAS_foo_SERIALIZE defines to see if the platform supports
+     *          APR_LOCK_foo.  Only APR_LOCK_DEFAULT is portable.
+     * @param fname A file name to use if the lock mechanism requires one.  This
+     *        argument should always be provided.  The lock code itself will
+     *        determine if it should be used.
+     * @param mech The mechanism to use for the interprocess lock, if any; one of
+     * <PRE>
+     *            APR_LOCK_FCNTL
+     *            APR_LOCK_FLOCK
+     *            APR_LOCK_SYSVSEM
+     *            APR_LOCK_POSIXSEM
+     *            APR_LOCK_PROC_PTHREAD
+     *            APR_LOCK_DEFAULT     pick the default mechanism for the platform
+     * </PRE>
+     * @param pool the pool from which to allocate the mutex.
+     * @return Newly created mutex.
+     */
+    public static native long create(String fname, int mech, long pool)
+        throws Error;
+
+    /**
+     * Re-open a mutex in a child process.
+     * @param fname A file name to use if the mutex mechanism requires one.  This
+     *              argument should always be provided.  The mutex code itself will
+     *              determine if it should be used.  This filename should be the
+     *              same one that was passed to apr_proc_mutex_create().
+     * @param pool The pool to operate on.
+     * This function must be called to maintain portability, even
+     *         if the underlying lock mechanism does not require it.
+     * @return Newly opened mutex.
+     */
+    public static native long childInit(String fname, long pool)
+        throws Error;
+
+    /**
+     * Acquire the lock for the given mutex. If the mutex is already locked,
+     * the current thread will be put to sleep until the lock becomes available.
+     * @param mutex the mutex on which to acquire the lock.
+     */
+    public static native int lock(long mutex);
+
+    /**
+     * Attempt to acquire the lock for the given mutex. If the mutex has already
+     * been acquired, the call returns immediately with APR_EBUSY. Note: it
+     * is important that the APR_STATUS_IS_EBUSY(s) macro be used to determine
+     * if the return value was APR_EBUSY, for portability reasons.
+     * @param mutex the mutex on which to attempt the lock acquiring.
+     */
+    public static native int trylock(long mutex);
+
+    /**
+     * Release the lock for the given mutex.
+     * @param mutex the mutex from which to release the lock.
+     */
+    public static native int unlock(long mutex);
+
+    /**
+     * Destroy the mutex and free the memory associated with the lock.
+     * @param mutex the mutex to destroy.
+     */
+    public static native int destroy(long mutex);
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jni/java/org/apache/tomcat/jni/Library.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jni/java/org/apache/tomcat/jni/Library.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jni/java/org/apache/tomcat/jni/Library.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,207 @@
+/*
+ *  Copyright 2000-2005 The Apache Software Foundation
+ *
+ *  Licensed 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.jni;
+
+/** Library
+ *
+ * @author Mladen Turk
+ * @version $Revision: 300969 $, $Date: 2005-07-12 09:56:11 -0500 (Tue, 12 Jul 2005) $
+ */
+
+public final class Library {
+
+    /* Default library names */
+    private static String [] NAMES = {"tcnative-1", "libtcnative-1"};
+    /*
+     * A handle to the unique Library singleton instance.
+     */
+    static private Library _instance = null;
+
+    private Library()
+    {
+        boolean loaded = false;
+        String err = "";
+        for (int i = 0; i < NAMES.length; i++) {
+            try {
+                System.loadLibrary(NAMES[i]);
+                loaded = true;
+            }
+            catch (Throwable e) {
+                if ( i > 0)
+                    err += ", ";
+                err +=  e.getMessage();
+            }
+            if (loaded)
+                break;
+        }
+        if (!loaded) {
+            err += "(";
+            err += System.getProperty("java.library.path");
+            err += ")";
+            throw new UnsatisfiedLinkError(err);
+        }
+    }
+
+    private Library(String libraryName)
+    {
+        System.loadLibrary(libraryName);
+    }
+
+    /* create global TCN's APR pool
+     * This has to be the first call to TCN library.
+     */
+    private static native boolean initialize();
+    /* destroy global TCN's APR pool
+     * This has to be the last call to TCN library.
+     */
+    public static native void terminate();
+    /* Internal function for loading APR Features */
+    private static native boolean has(int what);
+    /* Internal function for loading APR Features */
+    private static native int version(int what);
+    /* Internal function for loading APR sizes */
+    private static native int size(int what);
+
+    /* TCN_MAJOR_VERSION */
+    public static int TCN_MAJOR_VERSION  = 0;
+    /* TCN_MINOR_VERSION */
+    public static int TCN_MINOR_VERSION  = 0;
+    /* TCN_PATCH_VERSION */
+    public static int TCN_PATCH_VERSION  = 0;
+    /* TCN_IS_DEV_VERSION */
+    public static int TCN_IS_DEV_VERSION = 0;
+    /* APR_MAJOR_VERSION */
+    public static int APR_MAJOR_VERSION  = 0;
+    /* APR_MINOR_VERSION */
+    public static int APR_MINOR_VERSION  = 0;
+    /* APR_PATCH_VERSION */
+    public static int APR_PATCH_VERSION  = 0;
+    /* APR_IS_DEV_VERSION */
+    public static int APR_IS_DEV_VERSION = 0;
+
+    /* TCN_VERSION_STRING */
+    public static native String versionString();
+    /* APR_VERSION_STRING */
+    public static native String aprVersionString();
+
+    /*  APR Feature Macros */
+    public static boolean APR_HAVE_IPV6           = false;
+    public static boolean APR_HAS_SHARED_MEMORY   = false;
+    public static boolean APR_HAS_THREADS         = false;
+    public static boolean APR_HAS_SENDFILE        = false;
+    public static boolean APR_HAS_MMAP            = false;
+    public static boolean APR_HAS_FORK            = false;
+    public static boolean APR_HAS_RANDOM          = false;
+    public static boolean APR_HAS_OTHER_CHILD     = false;
+    public static boolean APR_HAS_DSO             = false;
+    public static boolean APR_HAS_SO_ACCEPTFILTER = false;
+    public static boolean APR_HAS_UNICODE_FS      = false;
+    public static boolean APR_HAS_PROC_INVOKED    = false;
+    public static boolean APR_HAS_USER            = false;
+    public static boolean APR_HAS_LARGE_FILES     = false;
+    public static boolean APR_HAS_XTHREAD_FILES   = false;
+    public static boolean APR_HAS_OS_UUID         = false;
+    /* Are we big endian? */
+    public static boolean APR_IS_BIGENDIAN        = false;
+    /* APR sets APR_FILES_AS_SOCKETS to 1 on systems where it is possible
+     * to poll on files/pipes.
+     */
+    public static boolean APR_FILES_AS_SOCKETS    = false;
+    /* This macro indicates whether or not EBCDIC is the native character set.
+     */
+    public static boolean APR_CHARSET_EBCDIC      = false;
+    /* Is the TCP_NODELAY socket option inherited from listening sockets?
+     */
+    public static boolean APR_TCP_NODELAY_INHERITED = false;
+    /* Is the O_NONBLOCK flag inherited from listening sockets?
+     */
+    public static boolean APR_O_NONBLOCK_INHERITED  = false;
+
+
+    public static int APR_SIZEOF_VOIDP;
+    public static int APR_PATH_MAX;
+    public static int APRMAXHOSTLEN;
+    public static int APR_MAX_IOVEC_SIZE;
+    public static int APR_MAX_SECS_TO_LINGER;
+    public static int APR_MMAP_THRESHOLD;
+    public static int APR_MMAP_LIMIT;
+
+    /* return global TCN's APR pool */
+    public static native long globalPool();
+
+    /**
+     * Setup any APR internal data structures.  This MUST be the first function
+     * called for any APR library.
+     * @param libraryName the name of the library to load
+     */
+    static public boolean initialize(String libraryName)
+        throws Exception
+    {
+        if (_instance == null) {
+            if (libraryName == null)
+                _instance = new Library();
+            else
+                _instance = new Library(libraryName);
+            TCN_MAJOR_VERSION  = version(0x01);
+            TCN_MINOR_VERSION  = version(0x02);
+            TCN_PATCH_VERSION  = version(0x03);
+            TCN_IS_DEV_VERSION = version(0x04);
+            APR_MAJOR_VERSION  = version(0x11);
+            APR_MINOR_VERSION  = version(0x12);
+            APR_PATCH_VERSION  = version(0x13);
+            APR_IS_DEV_VERSION = version(0x14);
+
+            APR_SIZEOF_VOIDP        = size(1);
+            APR_PATH_MAX            = size(2);
+            APRMAXHOSTLEN           = size(3);
+            APR_MAX_IOVEC_SIZE      = size(4);
+            APR_MAX_SECS_TO_LINGER  = size(5);
+            APR_MMAP_THRESHOLD      = size(6);
+            APR_MMAP_LIMIT          = size(7);
+
+            APR_HAVE_IPV6           = has(0);
+            APR_HAS_SHARED_MEMORY   = has(1);
+            APR_HAS_THREADS         = has(2);
+            APR_HAS_SENDFILE        = has(3);
+            APR_HAS_MMAP            = has(4);
+            APR_HAS_FORK            = has(5);
+            APR_HAS_RANDOM          = has(6);
+            APR_HAS_OTHER_CHILD     = has(7);
+            APR_HAS_DSO             = has(8);
+            APR_HAS_SO_ACCEPTFILTER = has(9);
+            APR_HAS_UNICODE_FS      = has(10);
+            APR_HAS_PROC_INVOKED    = has(11);
+            APR_HAS_USER            = has(12);
+            APR_HAS_LARGE_FILES     = has(13);
+            APR_HAS_XTHREAD_FILES   = has(14);
+            APR_HAS_OS_UUID         = has(15);
+            APR_IS_BIGENDIAN        = has(16);
+            APR_FILES_AS_SOCKETS    = has(17);
+            APR_CHARSET_EBCDIC      = has(18);
+            APR_TCP_NODELAY_INHERITED = has(19);
+            APR_O_NONBLOCK_INHERITED  = has(20);
+            if (APR_MAJOR_VERSION < 1) {
+                throw new UnsatisfiedLinkError("Unsupported APR Version (" +
+                                               aprVersionString() + ")");
+            }
+            if (!APR_HAS_THREADS) {
+                throw new UnsatisfiedLinkError("Missing APR_HAS_THREADS");
+            }
+        }
+        return initialize();
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jni/java/org/apache/tomcat/jni/Local.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jni/java/org/apache/tomcat/jni/Local.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jni/java/org/apache/tomcat/jni/Local.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,75 @@
+/*
+ *  Copyright 2000-2005 The Apache Software Foundation
+ *
+ *  Licensed 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.jni;
+
+/** Local socket
+ *
+ * @author Mladen Turk
+ * @version $Revision: 300969 $, $Date: 2005-07-12 09:56:11 -0500 (Tue, 12 Jul 2005) $
+ */
+
+public class Local {
+
+    /**
+     * Create a socket.
+     * @param path The address of the new socket.
+     * @param cont The parent pool to use
+     * @return The new socket that has been set up.
+     */
+    public static native long create(String path, long cont)
+        throws Exception;
+
+    /**
+     * Bind the socket to its associated port
+     * @param sock The socket to bind
+     * @param sa The socket address to bind to
+     * This may be where we will find out if there is any other process
+     *      using the selected port.
+     */
+    public static native int bind(long sock, long sa);
+
+    /**
+     * Listen to a bound socket for connections.
+     * @param sock The socket to listen on
+     * @param backlog The number of outstanding connections allowed in the sockets
+     *                listen queue.  If this value is less than zero, for NT pipes
+     *                the number of instances is unlimite.
+     *
+     */
+    public static native int listen(long sock, int backlog);
+
+    /**
+     * Accept a new connection request
+     * @param sock The socket we are listening on.
+     * @param pool The pool for the new socket.
+     * @return  A copy of the socket that is connected to the socket that
+     *          made the connection request.  This is the socket which should
+     *          be used for all future communication.
+     */
+    public static native long accept(long sock)
+        throws Exception;
+
+    /**
+     * Issue a connection request to a socket either on the same machine
+     * or a different one.
+     * @param sock The socket we wish to use for our side of the connection
+     * @param sa The address of the machine we wish to connect to.
+     *           Unused for NT Pipes.
+     */
+    public static native int connect(long sock, long sa);
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jni/java/org/apache/tomcat/jni/Lock.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jni/java/org/apache/tomcat/jni/Lock.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jni/java/org/apache/tomcat/jni/Lock.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,122 @@
+/*
+ *  Copyright 2000-2005 The Apache Software Foundation
+ *
+ *  Licensed 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.jni;
+
+/** Lock
+ *
+ * @author Mladen Turk
+ * @version $Revision: 300969 $, $Date: 2005-07-12 09:56:11 -0500 (Tue, 12 Jul 2005) $
+ */
+
+public class Lock {
+
+    /**
+     * Enumerated potential types for APR process locking methods
+     * <br /><b>Warning :</b> Check APR_HAS_foo_SERIALIZE defines to see if the platform supports
+     *          APR_LOCK_foo.  Only APR_LOCK_DEFAULT is portable.
+     */
+
+    public static final int APR_LOCK_FCNTL        = 0; /** fcntl() */
+    public static final int APR_LOCK_FLOCK        = 1; /** flock() */
+    public static final int APR_LOCK_SYSVSEM      = 2; /** System V Semaphores */
+    public static final int APR_LOCK_PROC_PTHREAD = 3; /** POSIX pthread process-based locking */
+    public static final int APR_LOCK_POSIXSEM     = 4; /** POSIX semaphore process-based locking */
+    public static final int APR_LOCK_DEFAULT      = 5; /** Use the default process lock */
+
+    /**
+     * Create and initialize a mutex that can be used to synchronize processes.
+     * <br /><b>Warning :</b> Check APR_HAS_foo_SERIALIZE defines to see if the platform supports
+     *          APR_LOCK_foo.  Only APR_LOCK_DEFAULT is portable.
+     * @param fname A file name to use if the lock mechanism requires one.  This
+     *        argument should always be provided.  The lock code itself will
+     *        determine if it should be used.
+     * @param mech The mechanism to use for the interprocess lock, if any; one of
+     * <PRE>
+     *            APR_LOCK_FCNTL
+     *            APR_LOCK_FLOCK
+     *            APR_LOCK_SYSVSEM
+     *            APR_LOCK_POSIXSEM
+     *            APR_LOCK_PROC_PTHREAD
+     *            APR_LOCK_DEFAULT     pick the default mechanism for the platform
+     * </PRE>
+     * @param pool the pool from which to allocate the mutex.
+     * @return Newly created mutex.
+     */
+    public static native long create(String fname, int mech, long pool)
+        throws Error;
+
+    /**
+     * Re-open a mutex in a child process.
+     * This function must be called to maintain portability, even
+     * if the underlying lock mechanism does not require it.
+     * @param fname A file name to use if the mutex mechanism requires one.  This
+     *              argument should always be provided.  The mutex code itself will
+     *              determine if it should be used.  This filename should be the
+     *              same one that was passed to apr_proc_mutex_create().
+     * @param pool The pool to operate on.
+     * @return Newly opened mutex.
+     */
+    public static native long childInit(String fname, long pool)
+        throws Error;
+
+    /**
+     * Acquire the lock for the given mutex. If the mutex is already locked,
+     * the current thread will be put to sleep until the lock becomes available.
+     * @param mutex the mutex on which to acquire the lock.
+     */
+    public static native int lock(long mutex);
+
+    /**
+     * Attempt to acquire the lock for the given mutex. If the mutex has already
+     * been acquired, the call returns immediately with APR_EBUSY. Note: it
+     * is important that the APR_STATUS_IS_EBUSY(s) macro be used to determine
+     * if the return value was APR_EBUSY, for portability reasons.
+     * @param mutex the mutex on which to attempt the lock acquiring.
+     */
+    public static native int trylock(long mutex);
+
+    /**
+     * Release the lock for the given mutex.
+     * @param mutex the mutex from which to release the lock.
+     */
+    public static native int unlock(long mutex);
+
+    /**
+     * Destroy the mutex and free the memory associated with the lock.
+     * @param mutex the mutex to destroy.
+     */
+    public static native int destroy(long mutex);
+
+    /**
+     * Return the name of the lockfile for the mutex, or NULL
+     * if the mutex doesn't use a lock file
+     */
+    public static native String lockfile(long mutex);
+
+    /**
+     * Display the name of the mutex, as it relates to the actual method used.
+     * This matches the valid options for Apache's AcceptMutex directive
+     * @param mutex the name of the mutex
+     */
+    public static native String name(long mutex);
+
+    /**
+     * Display the name of the default mutex: APR_LOCK_DEFAULT
+     */
+    public static native String defname();
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jni/java/org/apache/tomcat/jni/Mmap.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jni/java/org/apache/tomcat/jni/Mmap.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jni/java/org/apache/tomcat/jni/Mmap.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,72 @@
+/*
+ *  Copyright 2000-2005 The Apache Software Foundation
+ *
+ *  Licensed 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.jni;
+
+/** Mmap
+ *
+ * @author Mladen Turk
+ * @version $Revision: 300969 $, $Date: 2005-07-12 09:56:11 -0500 (Tue, 12 Jul 2005) $
+ */
+
+public class Mmap {
+    /** MMap opened for reading */
+    public static final int APR_MMAP_READ  = 1;
+    /** MMap opened for writing */
+    public static final int APR_MMAP_WRITE = 2;
+
+
+    /**
+     * Create a new mmap'ed file out of an existing APR file.
+     * @param file The file turn into an mmap.
+     * @param offset The offset into the file to start the data pointer at.
+     * @param size The size of the file
+     * @param flag bit-wise or of:
+     * <PRE>
+     * APR_MMAP_READ       MMap opened for reading
+     * APR_MMAP_WRITE      MMap opened for writing
+     * </PRE>
+     * @param pool The pool to use when creating the mmap.
+     * @return The newly created mmap'ed file.
+     */
+    public static native long create(long file, long offset, long size, int flag, long pool)
+        throws Error;
+
+    /**
+     * Duplicate the specified MMAP.
+     * @param mmap The mmap to duplicate.
+     * @param pool The pool to use for new_mmap.
+     * @return Duplicated mmap'ed file.
+     */
+    public static native long dup(long mmap, long pool)
+        throws Error;
+
+    /**
+     * Remove a mmap'ed.
+     * @param mm The mmap'ed file.
+     */
+    public static native int delete(long mm);
+
+    /**
+     * Move the pointer into the mmap'ed file to the specified offset.
+     * @param mm The mmap'ed file.
+     * @param offset The offset to move to.
+     * @return The pointer to the offset specified.
+     */
+    public static native long offset(long mm, long offset)
+        throws Error;
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jni/java/org/apache/tomcat/jni/Multicast.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jni/java/org/apache/tomcat/jni/Multicast.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jni/java/org/apache/tomcat/jni/Multicast.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,77 @@
+/*
+ *  Copyright 2000-2005 The Apache Software Foundation
+ *
+ *  Licensed 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.jni;
+
+/** Multicast
+ *
+ * @author Mladen Turk
+ * @version $Revision: 300969 $, $Date: 2005-07-12 09:56:11 -0500 (Tue, 12 Jul 2005) $
+ */
+
+public class Multicast {
+
+    /**
+     * Join a Multicast Group
+     * @param sock The socket to join a multicast group
+     * @param join The address of the multicast group to join
+     * @param iface Address of the interface to use.  If NULL is passed, the
+     *              default multicast interface will be used. (OS Dependent)
+     * @param source Source Address to accept transmissions from (non-NULL
+     *               implies Source-Specific Multicast)
+     */
+    public static native int join(long sock, long join,
+                                  long iface, long source);
+
+    /**
+     * Leave a Multicast Group.  All arguments must be the same as
+     * apr_mcast_join.
+     * @param sock The socket to leave a multicast group
+     * @param addr The address of the multicast group to leave
+     * @param iface Address of the interface to use.  If NULL is passed, the
+     *              default multicast interface will be used. (OS Dependent)
+     * @param source Source Address to accept transmissions from (non-NULL
+     *               implies Source-Specific Multicast)
+     */
+    public static native int leave(long sock, long addr,
+                                   long iface, long source);
+
+    /**
+     * Set the Multicast Time to Live (ttl) for a multicast transmission.
+     * @param sock The socket to set the multicast ttl
+     * @param ttl Time to live to Assign. 0-255, default=1
+     * <br /><b>Remark :</b> If the TTL is 0, packets will only be seen
+     * by sockets on the local machine,
+     * and only when multicast loopback is enabled.
+     */
+    public static native int hops(long sock, int ttl);
+
+    /**
+     * Toggle IP Multicast Loopback
+     * @param sock The socket to set multicast loopback
+     * @param opt false=disable, true=enable
+     */
+    public static native int loopback(long sock, boolean opt);
+
+
+    /**
+     * Set the Interface to be used for outgoing Multicast Transmissions.
+     * @param sock The socket to set the multicast interface on
+     * @param iface Address of the interface to use for Multicast
+     */
+    public static native int ointerface(long sock, long iface);
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jni/java/org/apache/tomcat/jni/OS.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jni/java/org/apache/tomcat/jni/OS.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jni/java/org/apache/tomcat/jni/OS.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,127 @@
+/*
+ *  Copyright 2000-2005 The Apache Software Foundation
+ *
+ *  Licensed 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.jni;
+
+/** OS
+ *
+ * @author Mladen Turk
+ * @version $Revision: 386278 $, $Date: 2006-03-16 01:15:58 -0600 (Thu, 16 Mar 2006) $
+ */
+
+public class OS {
+
+    /* OS Enums */
+    private static final int UNIX      = 1;
+    private static final int NETWARE   = 2;
+    private static final int WIN32     = 3;
+    private static final int WIN64     = 4;
+    private static final int LINUX     = 5;
+    private static final int SOLARIS   = 6;
+    private static final int BSD       = 7;
+
+    public static final int LOG_EMERG  = 1;
+    public static final int LOG_ERROR  = 2;
+    public static final int LOG_NOTICE = 3;
+    public static final int LOG_WARN   = 4;
+    public static final int LOG_INFO   = 5;
+    public static final int LOG_DEBUG  = 6;
+
+    /**
+     * Check for OS type.
+     * @param type OS type to test.
+     */
+    private static native boolean is(int type);
+
+    public static final boolean IS_UNIX    = is(UNIX);
+    public static final boolean IS_NETWARE = is(NETWARE);
+    public static final boolean IS_WIN32   = is(WIN32);
+    public static final boolean IS_WIN64   = is(WIN64);
+    public static final boolean IS_LINUX   = is(LINUX);
+    public static final boolean IS_SOLARIS = is(SOLARIS);
+    public static final boolean IS_BSD     = is(BSD);
+
+    /**
+     * Get the name of the system default characer set.
+     * @param pool the pool to allocate the name from, if needed
+     */
+    public static native String defaultEncoding(long pool);
+
+    /**
+     * Get the name of the current locale character set.
+     * Defers to apr_os_default_encoding if the current locale's
+     * data can't be retreved on this system.
+     * @param pool the pool to allocate the name from, if needed
+     */
+    public static native String localeEncoding(long pool);
+
+    /**
+     * Generate random bytes.
+     * @param buf Buffer to fill with random bytes
+     * @param len Length of buffer in bytes
+     */
+    public static native int random(byte [] buf, int len);
+
+    /**
+     * Gather system info.
+     * <PRE>
+     * On exit the inf array will be filled with:
+     * inf[0]  - Total usable main memory size
+     * inf[1]  - Available memory size
+     * inf[2]  - Total page file/swap space size
+     * inf[3]  - Page file/swap space still available
+     * inf[4]  - Amount of shared memory
+     * inf[5]  - Memory used by buffers
+     * inf[6]  - Memory Load
+     *
+     * inf[7]  - Idle Time in microseconds
+     * inf[8]  - Kernel Time in microseconds
+     * inf[9]  - User Time in microseconds
+     *
+     * inf[10] - Process creation time (apr_time_t)
+     * inf[11] - Process Kernel Time in microseconds
+     * inf[12] - Process User Time in microseconds
+     *
+     * inf[13] - Current working set size.
+     * inf[14] - Peak working set size.
+     * inf[15] - Number of page faults.
+     * </PRE>
+     * @param inf array that will be filled with system information.
+     *            Array length must be at least 16.
+     */
+    public static native int info(long [] inf);
+
+    /**
+     * Expand environment variables.
+     * @param str String to expand
+     * @return Expanded string with replaced environment variables.
+     */
+    public static native String expand(String str);
+
+    /**
+     * Initialize system logging.
+     * @param domain String that will be prepended to every message
+     */
+    public static native void sysloginit(String domain);
+
+    /**
+     * Log message.
+     * @param level Log message severity. See LOG_XXX enums.
+     * @param message Message to log
+     */
+    public static native void syslog(int level, String message);
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jni/java/org/apache/tomcat/jni/PasswordCallback.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jni/java/org/apache/tomcat/jni/PasswordCallback.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jni/java/org/apache/tomcat/jni/PasswordCallback.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,33 @@
+/*
+ *  Copyright 2000-2005 The Apache Software Foundation
+ *
+ *  Licensed 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.jni;
+
+/** PasswordCallback Interface
+ *
+ * @author Mladen Turk
+ * @version $Revision: 300969 $, $Date: 2005-07-12 09:56:11 -0500 (Tue, 12 Jul 2005) $
+ */
+
+public interface PasswordCallback {
+
+    /**
+     * Called when the password is required
+     * @param prompt Password prompt
+     * @return Valid password or null
+     */
+    public String callback(String prompt);
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jni/java/org/apache/tomcat/jni/Poll.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jni/java/org/apache/tomcat/jni/Poll.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jni/java/org/apache/tomcat/jni/Poll.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,157 @@
+/*
+ *  Copyright 2000-2005 The Apache Software Foundation
+ *
+ *  Licensed 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.jni;
+
+/** Poll
+ *
+ * @author Mladen Turk
+ * @version $Revision: 300969 $, $Date: 2005-07-12 09:56:11 -0500 (Tue, 12 Jul 2005) $
+ */
+
+public class Poll {
+
+    /**
+     * Poll options
+     */
+    public static final int APR_POLLIN   = 0x001; /** Can read without blocking */
+    public static final int APR_POLLPRI  = 0x002; /** Priority data available */
+    public static final int APR_POLLOUT  = 0x004; /** Can write without blocking */
+    public static final int APR_POLLERR  = 0x010; /** Pending error */
+    public static final int APR_POLLHUP  = 0x020; /** Hangup occurred */
+    public static final int APR_POLLNVAL = 0x040; /** Descriptior invalid */
+
+    /**
+     * Pollset Flags
+     */
+    /** Adding or Removing a Descriptor is thread safe */
+    public static final int APR_POLLSET_THREADSAFE = 0x001;
+
+
+    /** Used in apr_pollfd_t to determine what the apr_descriptor is
+     * apr_datatype_e enum
+     */
+    public static final int APR_NO_DESC       = 0; /** nothing here */
+    public static final int APR_POLL_SOCKET   = 1; /** descriptor refers to a socket */
+    public static final int APR_POLL_FILE     = 2; /** descriptor refers to a file */
+    public static final int APR_POLL_LASTDESC = 3; /** descriptor is the last one in the list */
+
+    /**
+     * Setup a pollset object.
+     * If flags equals APR_POLLSET_THREADSAFE, then a pollset is
+     * created on which it is safe to make concurrent calls to
+     * apr_pollset_add(), apr_pollset_remove() and apr_pollset_poll() from
+     * separate threads.  This feature is only supported on some
+     * platforms; the apr_pollset_create() call will fail with
+     * APR_ENOTIMPL on platforms where it is not supported.
+     * @param size The maximum number of descriptors that this pollset can hold
+     * @param p The pool from which to allocate the pollset
+     * @param flags Optional flags to modify the operation of the pollset.
+     * @param ttl Maximum time to live for a particular socket.
+     * @return  The pointer in which to return the newly created object
+     */
+    public static native long create(int size, long p, int flags, long ttl)
+        throws Error;
+    /**
+     * Destroy a pollset object
+     * @param pollset The pollset to destroy
+     */
+    public static native int destroy(long pollset);
+
+    /**
+     * Add a socket or to a pollset
+     * If you set client_data in the descriptor, that value
+     * will be returned in the client_data field whenever this
+     * descriptor is signalled in apr_pollset_poll().
+     * @param pollset The pollset to which to add the descriptor
+     * @param sock The sockets to add
+     * @param data Client data to add
+     * @param reqevents requested events
+     */
+    public static native int add(long pollset, long sock,
+                                 int reqevents);
+
+    /**
+     * Remove a descriptor from a pollset
+     * @param pollset The pollset from which to remove the descriptor
+     * @param sock The socket to remove
+     */
+    public static native int remove(long pollset, long sock);
+
+    /**
+     * Block for activity on the descriptor(s) in a pollset
+     * @param pollset The pollset to use
+     * @param timeout Timeout in microseconds
+     * @param descriptors Array of signalled descriptors (output parameter)
+     *        The desctiptor array must be two times the size of pollset.
+     *        and are populated as follows:
+     * <PRE>
+     * descriptors[n + 0] -> returned events
+     * descriptors[n + 1] -> socket
+     * </PRE>
+     * @param remove Remove signaled descriptors from pollset
+     * @return Number of signalled descriptors (output parameter)
+     *         or negative APR error code.
+     */
+    public static native int poll(long pollset, long timeout,
+                                  long [] descriptors, boolean remove);
+
+    /**
+     * Maintain on the descriptor(s) in a pollset
+     * @param pollset The pollset to use
+     * @param descriptors Array of signalled descriptors (output parameter)
+     *        The desctiptor array must be the size of pollset.
+     *        and are populated as follows:
+     * <PRE>
+     * descriptors[n] -> socket
+     * </PRE>
+     * @param remove Remove signaled descriptors from pollset
+     * @return Number of signalled descriptors (output parameter)
+     *         or negative APR error code.
+     */
+    public static native int maintain(long pollset, long [] descriptors,
+                                      boolean remove);
+
+    /**
+     * Set the socket time to live.
+     * @param pollset The pollset to use
+     * @param ttl Timeout in microseconds
+     */
+    public static native void setTtl(long pollset, long ttl);
+
+    /**
+     * Get the socket time to live.
+     * @param pollset The pollset to use
+     * @return Timeout in microseconds
+     */
+    public static native long getTtl(long pollset);
+
+    /**
+     * Return all descriptor(s) in a pollset
+     * @param pollset The pollset to use
+     * @param descriptors Array of descriptors (output parameter)
+     *        The desctiptor array must be two times the size of pollset.
+     *        and are populated as follows:
+     * <PRE>
+     * descriptors[n + 0] -> returned events
+     * descriptors[n + 1] -> socket
+     * </PRE>
+     * @return Number of descriptors (output parameter) in the Poll
+     *         or negative APR error code.
+     */
+    public static native int pollset(long pollset, long [] descriptors);
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jni/java/org/apache/tomcat/jni/Pool.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jni/java/org/apache/tomcat/jni/Pool.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jni/java/org/apache/tomcat/jni/Pool.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,163 @@
+/*
+ *  Copyright 2000-2005 The Apache Software Foundation
+ *
+ *  Licensed 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.jni;
+
+import java.nio.ByteBuffer;
+
+/** Pool
+ *
+ * @author Mladen Turk
+ * @version $Revision: 300969 $, $Date: 2005-07-12 09:56:11 -0500 (Tue, 12 Jul 2005) $
+ */
+
+public class Pool {
+
+    /**
+     * Create a new pool.
+     * @param parent The parent pool.  If this is 0, the new pool is a root
+     * pool.  If it is non-zero, the new pool will inherit all
+     * of its parent pool's attributes, except the apr_pool_t will
+     * be a sub-pool.
+     * @return The pool we have just created.
+    */
+    public static native long create(long parent);
+
+    /**
+     * Clear all memory in the pool and run all the cleanups. This also destroys all
+     * subpools.
+     * @param pool The pool to clear
+     * This does not actually free the memory, it just allows the pool
+     *         to re-use this memory for the next allocation.
+     */
+    public static native void clear(long pool);
+
+    /**
+     * Destroy the pool. This takes similar action as apr_pool_clear() and then
+     * frees all the memory.
+     * This will actually free the memory
+     * @param pool The pool to destroy
+     */
+    public static native void destroy(long pool);
+
+    /**
+     * Get the parent pool of the specified pool.
+     * @param pool The pool for retrieving the parent pool.
+     * @return The parent of the given pool.
+     */
+    public static native long parentGet(long pool);
+
+    /**
+     * Determine if pool a is an ancestor of pool b
+     * @param a The pool to search
+     * @param b The pool to search for
+     * @return True if a is an ancestor of b, NULL is considered an ancestor
+     * of all pools.
+     */
+    public static native boolean isAncestor(long a, long b);
+
+
+    /*
+     * Cleanup
+     *
+     * Cleanups are performed in the reverse order they were registered.  That is:
+     * Last In, First Out.  A cleanup function can safely allocate memory from
+     * the pool that is being cleaned up. It can also safely register additional
+     * cleanups which will be run LIFO, directly after the current cleanup
+     * terminates.  Cleanups have to take caution in calling functions that
+     * create subpools. Subpools, created during cleanup will NOT automatically
+     * be cleaned up.  In other words, cleanups are to clean up after themselves.
+     */
+
+    /**
+     * Register a function to be called when a pool is cleared or destroyed
+     * @param pool The pool register the cleanup with
+     * @param o The object to call when the pool is cleared
+     *                      or destroyed
+     * @return The cleanup handler.
+     */
+    public static native long cleanupRegister(long pool, Object o);
+
+    /**
+     * Remove a previously registered cleanup function
+     * @param pool The pool remove the cleanup from
+     * @param data The cleanup handler to remove from cleanup
+     */
+    public static native void cleanupKill(long pool, long data);
+
+    /**
+     * Register a process to be killed when a pool dies.
+     * @param a The pool to use to define the processes lifetime
+     * @param proc The process to register
+     * @param how How to kill the process, one of:
+     * <PRE>
+     * APR_KILL_NEVER         -- process is never sent any signals
+     * APR_KILL_ALWAYS        -- process is sent SIGKILL on apr_pool_t cleanup
+     * APR_KILL_AFTER_TIMEOUT -- SIGTERM, wait 3 seconds, SIGKILL
+     * APR_JUST_WAIT          -- wait forever for the process to complete
+     * APR_KILL_ONLY_ONCE     -- send SIGTERM and then wait
+     * </PRE>
+     */
+    public static native void noteSubprocess(long a, long proc, int how);
+
+    /**
+     * Allocate a block of memory from a pool
+     * @param p The pool to allocate from
+     * @param size The amount of memory to allocate
+     * @return The ByteBuffer with allocated memory
+     */
+    public static native ByteBuffer alloc(long p, int size);
+
+    /**
+     * Allocate a block of memory from a pool and set all of the memory to 0
+     * @param p The pool to allocate from
+     * @param size The amount of memory to allocate
+     * @return The ByteBuffer with allocated memory
+     */
+    public static native ByteBuffer calloc(long p, int size);
+
+    /*
+     * User data management
+     */
+
+    /**
+     * Set the data associated with the current pool
+     * @param data The user data associated with the pool.
+     * @param key The key to use for association
+     * @param pool The current pool
+     * <br /><b>Warning :</b>
+     * The data to be attached to the pool should have a life span
+     * at least as long as the pool it is being attached to.
+     * Object attached to the pool will be globaly referenced
+     * untill the pool is cleared or dataSet is called with the null data.
+     * @return APR Status code.
+     */
+     public static native int dataSet(long pool, String key, Object data);
+
+    /**
+     * Return the data associated with the current pool.
+     * @param key The key for the data to retrieve
+     * @param pool The current pool.
+     */
+     public static native Object dataGet(long pool, String key);
+
+    /**
+     * Run all of the child_cleanups, so that any unnecessary files are
+     * closed because we are about to exec a new program
+     */
+    public static native void cleanupForExec();
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jni/java/org/apache/tomcat/jni/PoolCallback.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jni/java/org/apache/tomcat/jni/PoolCallback.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jni/java/org/apache/tomcat/jni/PoolCallback.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,32 @@
+/*
+ *  Copyright 2000-2005 The Apache Software Foundation
+ *
+ *  Licensed 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.jni;
+
+/** PoolCallback Interface
+ *
+ * @author Mladen Turk
+ * @version $Revision: 300969 $, $Date: 2005-07-12 09:56:11 -0500 (Tue, 12 Jul 2005) $
+ */
+
+public interface PoolCallback {
+
+    /**
+     * Called when the pool is destroyed or cleared
+     * @return Function must return APR_SUCCESS
+     */
+    public int callback();
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jni/java/org/apache/tomcat/jni/Proc.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jni/java/org/apache/tomcat/jni/Proc.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jni/java/org/apache/tomcat/jni/Proc.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,209 @@
+/*
+ *  Copyright 2000-2005 The Apache Software Foundation
+ *
+ *  Licensed 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.jni;
+
+/** Proc
+ *
+ * @author Mladen Turk
+ * @version $Revision: 300969 $, $Date: 2005-07-12 09:56:11 -0500 (Tue, 12 Jul 2005) $
+ */
+
+public class Proc {
+
+    /*
+     * apr_cmdtype_e enum
+     */
+    public static final int APR_SHELLCM      = 0; /** use the shell to invoke the program */
+    public static final int APR_PROGRAM      = 1; /** invoke the program directly, no copied env */
+    public static final int APR_PROGRAM_ENV  = 2; /** invoke the program, replicating our environment */
+    public static final int APR_PROGRAM_PATH = 3; /** find program on PATH, use our environment */
+    public static final int APR_SHELLCMD_ENV = 4; /** use the shell to invoke the program,
+                                                   *   replicating our environment
+                                                   */
+
+    /*
+     * apr_wait_how_e enum
+     */
+    public static final int APR_WAIT   = 0; /** wait for the specified process to finish */
+    public static final int APR_NOWAIT = 1; /** do not wait -- just see if it has finished */
+
+    /*
+     * apr_exit_why_e enum
+     */
+    public static final int APR_PROC_EXIT        = 1; /** process exited normally */
+    public static final int APR_PROC_SIGNAL      = 2; /** process exited due to a signal */
+    public static final int APR_PROC_SIGNAL_CORE = 4; /** process exited and dumped a core file */
+
+    public static final int APR_NO_PIPE       = 0;
+    public static final int APR_FULL_BLOCK    = 1;
+    public static final int APR_FULL_NONBLOCK = 2;
+    public static final int APR_PARENT_BLOCK  = 3;
+    public static final int APR_CHILD_BLOCK   = 4;
+
+    public static final int APR_LIMIT_CPU     = 0;
+    public static final int APR_LIMIT_MEM     = 1;
+    public static final int APR_LIMIT_NPROC   = 2;
+    public static final int APR_LIMIT_NOFILE  = 3;
+
+
+    /** child has died, caller must call unregister still */
+    public static final int APR_OC_REASON_DEATH      = 0;
+    /** write_fd is unwritable */
+    public static final int APR_OC_REASON_UNWRITABLE = 1;
+    /** a restart is occuring, perform any necessary cleanup (including
+     * sending a special signal to child)
+     */
+    public static final int APR_OC_REASON_RESTART    = 2;
+    /** unregister has been called, do whatever is necessary (including
+     * kill the child)
+     */
+    public static final int APR_OC_REASON_UNREGISTER = 3;
+    /** somehow the child exited without us knowing ... buggy os? */
+    public static final int APR_OC_REASON_LOST       = 4;
+    /** a health check is occuring, for most maintainence functions
+     * this is a no-op.
+     */
+    public static final int APR_OC_REASON_RUNNING    = 5;
+
+    /* apr_kill_conditions_e enumeration */
+    /** process is never sent any signals */
+    public static final int APR_KILL_NEVER         = 0;
+    /** process is sent SIGKILL on apr_pool_t cleanup */
+    public static final int APR_KILL_ALWAYS        = 1;
+    /** SIGTERM, wait 3 seconds, SIGKILL */
+    public static final int APR_KILL_AFTER_TIMEOUT = 2;
+    /** wait forever for the process to complete */
+    public static final int APR_JUST_WAIT          = 3;
+    /** send SIGTERM and then wait */
+    public static final int APR_KILL_ONLY_ONCE     = 4;
+
+    public static final int APR_PROC_DETACH_FOREGROUND = 0; /** Do not detach */
+    public static final int APR_PROC_DETACH_DAEMONIZE  = 1; /** Detach */
+
+    /* Maximum number of arguments for create process call */
+    public static final int MAX_ARGS_SIZE          = 1024;
+    /* Maximum number of environment variables for create process call */
+    public static final int MAX_ENV_SIZE           = 1024;
+
+    /**
+     * Allocate apr_proc_t stucture from pool
+     * This is not an apr function.
+     * @param cont The pool to use.
+     */
+    public static native long alloc(long cont);
+
+    /**
+     * This is currently the only non-portable call in APR.  This executes
+     * a standard unix fork.
+     * @param proc The resulting process handle.
+     * @param cont The pool to use.
+     * @return APR_INCHILD for the child, and APR_INPARENT for the parent
+     * or an error.
+     */
+    public static native int fork(long [] proc, long cont);
+
+    /**
+     * Create a new process and execute a new program within that process.
+     * This function returns without waiting for the new process to terminate;
+     * use apr_proc_wait for that.
+     * @param progname The program to run
+     * @param args The arguments to pass to the new program.  The first
+     *             one should be the program name.
+     * @param env The new environment table for the new process.  This
+     *            should be a list of NULL-terminated strings. This argument
+     *            is ignored for APR_PROGRAM_ENV, APR_PROGRAM_PATH, and
+     *            APR_SHELLCMD_ENV types of commands.
+     * @param attr The procattr we should use to determine how to create the new
+     * process
+     * @param pool The pool to use.
+     * @return The resulting process handle.
+     */
+    public static native int create(long proc, String progname,
+                                    String [] args, String [] env,
+                                    long attr, long pool);
+
+    /**
+     * Wait for a child process to die
+     * @param proc The process handle that corresponds to the desired child process
+     * @param exit exit[0] The returned exit status of the child, if a child process
+     *                dies, or the signal that caused the child to die.
+     *                On platforms that don't support obtaining this information,
+     *                the status parameter will be returned as APR_ENOTIMPL.
+     * exit[1] Why the child died, the bitwise or of:
+     * <PRE>
+     * APR_PROC_EXIT         -- process terminated normally
+     * APR_PROC_SIGNAL       -- process was killed by a signal
+     * APR_PROC_SIGNAL_CORE  -- process was killed by a signal, and
+     *                          generated a core dump.
+     * </PRE>
+     * @param waithow How should we wait.  One of:
+     * <PRE>
+     * APR_WAIT   -- block until the child process dies.
+     * APR_NOWAIT -- return immediately regardless of if the
+     *               child is dead or not.
+     * </PRE>
+     * @return The childs status is in the return code to this process.  It is one of:
+     * <PRE>
+     * APR_CHILD_DONE     -- child is no longer running.
+     * APR_CHILD_NOTDONE  -- child is still running.
+     * </PRE>
+     */
+    public static native int wait(long proc, int [] exit, int waithow);
+
+    /**
+     * Wait for any current child process to die and return information
+     * about that child.
+     * @param proc Pointer to NULL on entry, will be filled out with child's
+     *             information
+     * @param exit exit[0] The returned exit status of the child, if a child process
+     *                dies, or the signal that caused the child to die.
+     *                On platforms that don't support obtaining this information,
+     *                the status parameter will be returned as APR_ENOTIMPL.
+     * exit[1] Why the child died, the bitwise or of:
+     * <PRE>
+     * APR_PROC_EXIT         -- process terminated normally
+     * APR_PROC_SIGNAL       -- process was killed by a signal
+     * APR_PROC_SIGNAL_CORE  -- process was killed by a signal, and
+     *                          generated a core dump.
+     * </PRE>
+     * @param waithow How should we wait.  One of:
+     * <PRE>
+     * APR_WAIT   -- block until the child process dies.
+     * APR_NOWAIT -- return immediately regardless of if the
+     *               child is dead or not.
+     * </PRE>
+     * @param pool Pool to allocate child information out of.
+     */
+    public static native int waitAllProcs(long proc, int [] exit,
+                                          int waithow, long pool);
+
+     /**
+     * Detach the process from the controlling terminal.
+     * @param daemonize set to non-zero if the process should daemonize
+     *                  and become a background process, else it will
+     *                  stay in the foreground.
+     */
+    public static native int detach(int daemonize);
+
+    /**
+     * Terminate a process.
+     * @param proc The process to terminate.
+     * @param sig How to kill the process.
+     */
+    public static native int kill(long proc, int sig);
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jni/java/org/apache/tomcat/jni/ProcErrorCallback.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jni/java/org/apache/tomcat/jni/ProcErrorCallback.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jni/java/org/apache/tomcat/jni/ProcErrorCallback.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,37 @@
+/*
+ *  Copyright 2000-2005 The Apache Software Foundation
+ *
+ *  Licensed 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.jni;
+
+/** ProcErrorCallback Interface
+ *
+ * @author Mladen Turk
+ * @version $Revision: 300969 $, $Date: 2005-07-12 09:56:11 -0500 (Tue, 12 Jul 2005) $
+ */
+
+public interface ProcErrorCallback {
+
+    /**
+     * Called in the child process if APR encounters an error
+     * in the child prior to running the specified program.
+     * @param pool Pool associated with the apr_proc_t.  If your child
+     *             error function needs user data, associate it with this
+     *             pool.
+     * @param err APR error code describing the error
+     * @param description Text description of type of processing which failed
+     */
+    public void callback(long pool, int err, String description);
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jni/java/org/apache/tomcat/jni/Procattr.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jni/java/org/apache/tomcat/jni/Procattr.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jni/java/org/apache/tomcat/jni/Procattr.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,171 @@
+/*
+ *  Copyright 2000-2005 The Apache Software Foundation
+ *
+ *  Licensed 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.jni;
+
+/** Procattr
+ *
+ * @author Mladen Turk
+ * @version $Revision: 300969 $, $Date: 2005-07-12 09:56:11 -0500 (Tue, 12 Jul 2005) $
+ */
+
+public class Procattr {
+
+    /**
+     * Create and initialize a new procattr variable
+     * @param cont The pool to use
+     * @return The newly created procattr.
+     */
+    public static native long create(long cont)
+        throws Error;
+
+    /**
+     * Determine if any of stdin, stdout, or stderr should be linked to pipes
+     * when starting a child process.
+     * @param attr The procattr we care about.
+     * @param in Should stdin be a pipe back to the parent?
+     * @param out Should stdout be a pipe back to the parent?
+     * @param err Should stderr be a pipe back to the parent?
+     */
+    public static native int ioSet(long attr, int in, int out, int err);
+    /**
+     * Set the child_in and/or parent_in values to existing apr_file_t values.
+     * <br />
+     * This is NOT a required initializer function. This is
+     * useful if you have already opened a pipe (or multiple files)
+     * that you wish to use, perhaps persistently across multiple
+     * process invocations - such as a log file. You can save some
+     * extra function calls by not creating your own pipe since this
+     * creates one in the process space for you.
+     * @param attr The procattr we care about.
+     * @param in apr_file_t value to use as child_in. Must be a valid file.
+     * @param parent apr_file_t value to use as parent_in. Must be a valid file.
+     */
+    public static native int childInSet(long attr, long in, long parent);
+
+    /**
+     * Set the child_out and parent_out values to existing apr_file_t values.
+     * <br />
+     * This is NOT a required initializer function. This is
+     * useful if you have already opened a pipe (or multiple files)
+     * that you wish to use, perhaps persistently across multiple
+     * process invocations - such as a log file.
+     * @param attr The procattr we care about.
+     * @param out apr_file_t value to use as child_out. Must be a valid file.
+     * @param parent apr_file_t value to use as parent_out. Must be a valid file.
+     */
+    public static native int childOutSet(long attr, long out, long parent);
+
+    /**
+     * Set the child_err and parent_err values to existing apr_file_t values.
+     * <br />
+     * This is NOT a required initializer function. This is
+     * useful if you have already opened a pipe (or multiple files)
+     * that you wish to use, perhaps persistently across multiple
+     * process invocations - such as a log file.
+     * @param attr The procattr we care about.
+     * @param err apr_file_t value to use as child_err. Must be a valid file.
+     * @param parent apr_file_t value to use as parent_err. Must be a valid file.
+     */
+    public static native int childErrSet(long attr, long err, long parent);
+
+    /**
+     * Set which directory the child process should start executing in.
+     * @param attr The procattr we care about.
+     * @param dir Which dir to start in.  By default, this is the same dir as
+     *            the parent currently resides in, when the createprocess call
+     *            is made.
+     */
+    public static native int dirSet(long attr, String dir);
+
+    /**
+     * Set what type of command the child process will call.
+     * @param attr The procattr we care about.
+     * @param cmd The type of command.  One of:
+     * <PRE>
+     * APR_SHELLCMD     --  Anything that the shell can handle
+     * APR_PROGRAM      --  Executable program   (default)
+     * APR_PROGRAM_ENV  --  Executable program, copy environment
+     * APR_PROGRAM_PATH --  Executable program on PATH, copy env
+     * </PRE>
+     */
+    public static native int cmdtypeSet(long attr, int cmd);
+
+    /**
+     * Determine if the child should start in detached state.
+     * @param attr The procattr we care about.
+     * @param detach Should the child start in detached state?  Default is no.
+     */
+    public static native int detachSet(long attr, int detach);
+
+    /**
+     * Specify that apr_proc_create() should do whatever it can to report
+     * failures to the caller of apr_proc_create(), rather than find out in
+     * the child.
+     * @param attr The procattr describing the child process to be created.
+     * @param chk Flag to indicate whether or not extra work should be done
+     *            to try to report failures to the caller.
+     * <br />
+     * This flag only affects apr_proc_create() on platforms where
+     * fork() is used.  This leads to extra overhead in the calling
+     * process, but that may help the application handle such
+     * errors more gracefully.
+     */
+    public static native int errorCheckSet(long attr, int chk);
+
+    /**
+     * Determine if the child should start in its own address space or using the
+     * current one from its parent
+     * @param attr The procattr we care about.
+     * @param addrspace Should the child start in its own address space?  Default
+     * is no on NetWare and yes on other platforms.
+     */
+    public static native int addrspaceSet(long attr, int addrspace);
+
+    /**
+     * Specify an error function to be called in the child process if APR
+     * encounters an error in the child prior to running the specified program.
+     * @param attr The procattr describing the child process to be created.
+     * @param pool The the pool to use.
+     * @param o The Object to call in the child process.
+     * <br />
+     * At the present time, it will only be called from apr_proc_create()
+     * on platforms where fork() is used.  It will never be called on other
+     * platforms, on those platforms apr_proc_create() will return the error
+     * in the parent process rather than invoke the callback in the now-forked
+     * child process.
+     */
+    public static native void errfnSet(long attr, long pool, Object o);
+
+    /**
+     * Set the username used for running process
+     * @param attr The procattr we care about.
+     * @param username The username used
+     * @param password User password if needed. Password is needed on WIN32
+     *                 or any other platform having
+     *                 APR_PROCATTR_USER_SET_REQUIRES_PASSWORD set.
+     */
+    public static native int userSet(long attr, String username, String password);
+
+    /**
+     * Set the group used for running process
+     * @param attr The procattr we care about.
+     * @param groupname The group name  used
+     */
+    public static native int groupSet(long attr, String groupname);
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jni/java/org/apache/tomcat/jni/Registry.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jni/java/org/apache/tomcat/jni/Registry.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jni/java/org/apache/tomcat/jni/Registry.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,234 @@
+/*
+ *  Copyright 2000-2005 The Apache Software Foundation
+ *
+ *  Licensed 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.jni;
+
+/** Windows Registy support
+ *
+ * @author Mladen Turk
+ * @version $Revision: 301076 $, $Date: 2005-09-29 07:07:39 -0500 (Thu, 29 Sep 2005) $
+ */
+
+public class Registry {
+
+    /* Registry Enums */
+    public static final int HKEY_CLASSES_ROOT       = 1;
+    public static final int HKEY_CURRENT_CONFIG     = 2;
+    public static final int HKEY_CURRENT_USER       = 3;
+    public static final int HKEY_LOCAL_MACHINE      = 4;
+    public static final int HKEY_USERS              = 5;
+
+    public static final int KEY_ALL_ACCESS          = 0x0001;
+    public static final int KEY_CREATE_LINK         = 0x0002;
+    public static final int KEY_CREATE_SUB_KEY      = 0x0004;
+    public static final int KEY_ENUMERATE_SUB_KEYS  = 0x0008;
+    public static final int KEY_EXECUTE             = 0x0010;
+    public static final int KEY_NOTIFY              = 0x0020;
+    public static final int KEY_QUERY_VALUE         = 0x0040;
+    public static final int KEY_READ                = 0x0080;
+    public static final int KEY_SET_VALUE           = 0x0100;
+    public static final int KEY_WOW64_64KEY         = 0x0200;
+    public static final int KEY_WOW64_32KEY         = 0x0400;
+    public static final int KEY_WRITE               = 0x0800;
+
+    public static final int REG_BINARY              = 1;
+    public static final int REG_DWORD               = 2;
+    public static final int REG_EXPAND_SZ           = 3;
+    public static final int REG_MULTI_SZ            = 4;
+    public static final int REG_QWORD               = 5;
+    public static final int REG_SZ                  = 6;
+
+     /**
+     * Create or open a Registry Key.
+     * @param name Registry Subkey to open
+     * @param root Root key, one of HKEY_*
+     * @param som Access mask that specifies the access rights for the key.
+     * @return Opened Registry key
+     */
+    public static native long create(int root, String name, int sam, long pool)
+        throws Error;
+
+     /**
+     * Opens the specified Registry Key.
+     * @param name Registry Subkey to open
+     * @param root Root key, one of HKEY_*
+     * @param som Access mask that specifies the access rights for the key.
+     * @return Opened Registry key
+     */
+    public static native long open(int root, String name, int sam, long pool)
+        throws Error;
+
+    /**
+     * Close the specified Registry key.
+     * @param key The Registry key descriptor to close.
+     */
+    public static native int close(long key);
+
+    /**
+     * Get the Registry key type.
+     * @param key The Registry key descriptor to use.
+     * @param name The name of the value to query
+     * @return Value type or negative error value
+     */
+    public static native int getType(long key, String name);
+
+    /**
+     * Get the Registry value for REG_DWORD
+     * @param key The Registry key descriptor to use.
+     * @param name The name of the value to query
+     * @return Registry key value
+     */
+    public static native int getValueI(long key, String name)
+        throws Error;
+
+    /**
+     * Get the Registry value for REG_QWORD or REG_DWORD
+     * @param key The Registry key descriptor to use.
+     * @param name The name of the value to query
+     * @return Registry key value
+     */
+    public static native long getValueJ(long key, String name)
+        throws Error;
+
+    /**
+     * Get the Registry key length.
+     * @param key The Registry key descriptor to use.
+     * @param name The name of the value to query
+     * @return Value size or negative error value
+     */
+    public static native int getSize(long key, String name);
+
+    /**
+     * Get the Registry value for REG_SZ or REG_EXPAND_SZ
+     * @param key The Registry key descriptor to use.
+     * @param name The name of the value to query
+     * @return Registry key value
+     */
+    public static native String getValueS(long key, String name)
+        throws Error;
+
+    /**
+     * Get the Registry value for REG_MULTI_SZ
+     * @param key The Registry key descriptor to use.
+     * @param name The name of the value to query
+     * @return Registry key value
+     */
+    public static native String[] getValueA(long key, String name)
+        throws Error;
+
+    /**
+     * Get the Registry value for REG_BINARY
+     * @param key The Registry key descriptor to use.
+     * @param name The name of the value to query
+     * @return Registry key value
+     */
+    public static native byte[] getValueB(long key, String name)
+        throws Error;
+
+
+    /**
+     * Set the Registry value for REG_DWORD
+     * @param key The Registry key descriptor to use.
+     * @param name The name of the value to set
+     * @param val The the value to set
+     * @return If the function succeeds, the return value is 0
+     */
+    public static native int setValueI(long key, String name, int val);
+
+    /**
+     * Set the Registry value for REG_QWORD
+     * @param key The Registry key descriptor to use.
+     * @param name The name of the value to set
+     * @param val The the value to set
+     * @return If the function succeeds, the return value is 0
+     */
+    public static native int setValueJ(long key, String name, int val);
+
+    /**
+     * Set the Registry value for REG_SZ
+     * @param key The Registry key descriptor to use.
+     * @param name The name of the value to set
+     * @param val The the value to set
+     * @return If the function succeeds, the return value is 0
+     */
+    public static native int setValueS(long key, String name, String val);
+
+    /**
+     * Set the Registry value for REG_EXPAND_SZ
+     * @param key The Registry key descriptor to use.
+     * @param name The name of the value to set
+     * @param val The the value to set
+     * @return If the function succeeds, the return value is 0
+     */
+    public static native int setValueE(long key, String name, String val);
+
+     /**
+     * Set the Registry value for REG_MULTI_SZ
+     * @param key The Registry key descriptor to use.
+     * @param name The name of the value to set
+     * @param val The the value to set
+     * @return If the function succeeds, the return value is 0
+     */
+    public static native int setValueA(long key, String name, String[] val);
+
+     /**
+     * Set the Registry value for REG_BINARY
+     * @param key The Registry key descriptor to use.
+     * @param name The name of the value to set
+     * @param val The the value to set
+     * @return If the function succeeds, the return value is 0
+     */
+    public static native int setValueB(long key, String name, byte[] val);
+
+    /**
+     * Enumerate the Registry subkeys
+     * @param key The Registry key descriptor to use.
+     * @param name The name of the value to query
+     * @return Array of all subkey names
+     */
+    public static native String[] enumKeys(long key)
+        throws Error;
+
+    /**
+     * Enumerate the Registry values
+     * @param key The Registry key descriptor to use.
+     * @param name The name of the value to query
+     * @return Array of all value names
+     */
+    public static native String[] enumValues(long key)
+        throws Error;
+
+     /**
+     * Delete the Registry value
+     * @param key The Registry key descriptor to use.
+     * @param name The name of the value to delete
+     * @return If the function succeeds, the return value is 0
+     */
+    public static native int deleteValue(long key, String name);
+
+     /**
+     * Delete the Registry subkey
+     * @param root Root key, one of HKEY_*
+     * @param name Subkey to delete
+     * @param onlyIfEmpty If true will not delete a key if
+     *                    it contains any subkeys or values
+     * @return If the function succeeds, the return value is 0
+     */
+    public static native int deleteKey(int root, String name,
+                                       boolean onlyIfEmpty);
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jni/java/org/apache/tomcat/jni/SSL.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jni/java/org/apache/tomcat/jni/SSL.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jni/java/org/apache/tomcat/jni/SSL.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,327 @@
+/*
+ *  Copyright 2000-2005 The Apache Software Foundation
+ *
+ *  Licensed 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.jni;
+
+/** SSL
+ *
+ * @author Mladen Turk
+ * @version $Revision: 439948 $, $Date: 2006-09-04 01:29:33 -0500 (Mon, 04 Sep 2006) $
+ */
+
+public final class SSL {
+
+    /*
+     * Type definitions mostly from mod_ssl
+     */
+    public static final int UNSET            = -1;
+    /*
+     * Define the certificate algorithm types
+     */
+    public static final int SSL_ALGO_UNKNOWN = 0;
+    public static final int SSL_ALGO_RSA     = (1<<0);
+    public static final int SSL_ALGO_DSA     = (1<<1);
+    public static final int SSL_ALGO_ALL     = (SSL_ALGO_RSA|SSL_ALGO_DSA);
+
+    public static final int SSL_AIDX_RSA     = 0;
+    public static final int SSL_AIDX_DSA     = 1;
+    public static final int SSL_AIDX_MAX     = 2;
+    /*
+     * Define IDs for the temporary RSA keys and DH params
+     */
+
+    public static final int SSL_TMP_KEY_RSA_512  = 0;
+    public static final int SSL_TMP_KEY_RSA_1024 = 1;
+    public static final int SSL_TMP_KEY_RSA_2048 = 2;
+    public static final int SSL_TMP_KEY_RSA_4096 = 3;
+    public static final int SSL_TMP_KEY_DH_512   = 4;
+    public static final int SSL_TMP_KEY_DH_1024  = 5;
+    public static final int SSL_TMP_KEY_DH_2048  = 6;
+    public static final int SSL_TMP_KEY_DH_4096  = 7;
+    public static final int SSL_TMP_KEY_MAX      = 8;
+
+    /*
+     * Define the SSL options
+     */
+    public static final int SSL_OPT_NONE           = 0;
+    public static final int SSL_OPT_RELSET         = (1<<0);
+    public static final int SSL_OPT_STDENVVARS     = (1<<1);
+    public static final int SSL_OPT_EXPORTCERTDATA = (1<<3);
+    public static final int SSL_OPT_FAKEBASICAUTH  = (1<<4);
+    public static final int SSL_OPT_STRICTREQUIRE  = (1<<5);
+    public static final int SSL_OPT_OPTRENEGOTIATE = (1<<6);
+    public static final int SSL_OPT_ALL            = (SSL_OPT_STDENVVARS|SSL_OPT_EXPORTCERTDATA|SSL_OPT_FAKEBASICAUTH|SSL_OPT_STRICTREQUIRE|SSL_OPT_OPTRENEGOTIATE);
+
+    /*
+     * Define the SSL Protocol options
+     */
+    public static final int SSL_PROTOCOL_NONE  = 0;
+    public static final int SSL_PROTOCOL_SSLV2 = (1<<0);
+    public static final int SSL_PROTOCOL_SSLV3 = (1<<1);
+    public static final int SSL_PROTOCOL_TLSV1 = (1<<2);
+    public static final int SSL_PROTOCOL_ALL   = (SSL_PROTOCOL_SSLV2|SSL_PROTOCOL_SSLV3|SSL_PROTOCOL_TLSV1);
+
+    /*
+     * Define the SSL verify levels
+     */
+    public static final int SSL_CVERIFY_UNSET          = UNSET;
+    public static final int SSL_CVERIFY_NONE           = 0;
+    public static final int SSL_CVERIFY_OPTIONAL       = 1;
+    public static final int SSL_CVERIFY_REQUIRE        = 2;
+    public static final int SSL_CVERIFY_OPTIONAL_NO_CA = 3;
+
+    /* Use either SSL_VERIFY_NONE or SSL_VERIFY_PEER, the last 2 options
+     * are 'ored' with SSL_VERIFY_PEER if they are desired
+     */
+    public static final int SSL_VERIFY_NONE                 = 0;
+    public static final int SSL_VERIFY_PEER                 = 1;
+    public static final int SSL_VERIFY_FAIL_IF_NO_PEER_CERT = 2;
+    public static final int SSL_VERIFY_CLIENT_ONCE          = 4;
+    public static final int SSL_VERIFY_PEER_STRICT          = (SSL_VERIFY_PEER|SSL_VERIFY_FAIL_IF_NO_PEER_CERT);
+
+    public static final int SSL_OP_MICROSOFT_SESS_ID_BUG            = 0x00000001;
+    public static final int SSL_OP_NETSCAPE_CHALLENGE_BUG           = 0x00000002;
+    public static final int SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG = 0x00000008;
+    public static final int SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG      = 0x00000010;
+    public static final int SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER       = 0x00000020;
+    public static final int SSL_OP_MSIE_SSLV2_RSA_PADDING           = 0x00000040;
+    public static final int SSL_OP_SSLEAY_080_CLIENT_DH_BUG         = 0x00000080;
+    public static final int SSL_OP_TLS_D5_BUG                       = 0x00000100;
+    public static final int SSL_OP_TLS_BLOCK_PADDING_BUG            = 0x00000200;
+
+    /* Disable SSL 3.0/TLS 1.0 CBC vulnerability workaround that was added
+     * in OpenSSL 0.9.6d.  Usually (depending on the application protocol)
+     * the workaround is not needed.  Unfortunately some broken SSL/TLS
+     * implementations cannot handle it at all, which is why we include
+     * it in SSL_OP_ALL. */
+    public static final int SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS      = 0x00000800;
+
+    /* SSL_OP_ALL: various bug workarounds that should be rather harmless.
+     *             This used to be 0x000FFFFFL before 0.9.7. */
+    public static final int SSL_OP_ALL                              = 0x00000FFF;
+
+    /* As server, disallow session resumption on renegotiation */
+    public static final int SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION = 0x00010000;
+    /* If set, always create a new key when using tmp_dh parameters */
+    public static final int SSL_OP_SINGLE_DH_USE                    = 0x00100000;
+    /* Set to always use the tmp_rsa key when doing RSA operations,
+     * even when this violates protocol specs */
+    public static final int SSL_OP_EPHEMERAL_RSA                    = 0x00200000;
+    /* Set on servers to choose the cipher according to the server's
+     * preferences */
+    public static final int SSL_OP_CIPHER_SERVER_PREFERENCE         = 0x00400000;
+    /* If set, a server will allow a client to issue a SSLv3.0 version number
+     * as latest version supported in the premaster secret, even when TLSv1.0
+     * (version 3.1) was announced in the client hello. Normally this is
+     * forbidden to prevent version rollback attacks. */
+    public static final int SSL_OP_TLS_ROLLBACK_BUG                 = 0x00800000;
+
+    public static final int SSL_OP_NO_SSLv2                         = 0x01000000;
+    public static final int SSL_OP_NO_SSLv3                         = 0x02000000;
+    public static final int SSL_OP_NO_TLSv1                         = 0x04000000;
+
+    /* The next flag deliberately changes the ciphertest, this is a check
+     * for the PKCS#1 attack */
+    public static final int SSL_OP_PKCS1_CHECK_1                    = 0x08000000;
+    public static final int SSL_OP_PKCS1_CHECK_2                    = 0x10000000;
+    public static final int SSL_OP_NETSCAPE_CA_DN_BUG               = 0x20000000;
+    public static final int SSL_OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG  = 0x40000000;
+
+    public static final int SSL_CRT_FORMAT_UNDEF    = 0;
+    public static final int SSL_CRT_FORMAT_ASN1     = 1;
+    public static final int SSL_CRT_FORMAT_TEXT     = 2;
+    public static final int SSL_CRT_FORMAT_PEM      = 3;
+    public static final int SSL_CRT_FORMAT_NETSCAPE = 4;
+    public static final int SSL_CRT_FORMAT_PKCS12   = 5;
+    public static final int SSL_CRT_FORMAT_SMIME    = 6;
+    public static final int SSL_CRT_FORMAT_ENGINE   = 7;
+
+    public static final int SSL_MODE_CLIENT         = 0;
+    public static final int SSL_MODE_SERVER         = 1;
+    public static final int SSL_MODE_COMBINED       = 2;
+
+    public static final int SSL_SHUTDOWN_TYPE_UNSET    = 0;
+    public static final int SSL_SHUTDOWN_TYPE_STANDARD = 1;
+    public static final int SSL_SHUTDOWN_TYPE_UNCLEAN  = 2;
+    public static final int SSL_SHUTDOWN_TYPE_ACCURATE = 3;
+
+    public static final int SSL_INFO_SESSION_ID                = 0x0001;
+    public static final int SSL_INFO_CIPHER                    = 0x0002;
+    public static final int SSL_INFO_CIPHER_USEKEYSIZE         = 0x0003;
+    public static final int SSL_INFO_CIPHER_ALGKEYSIZE         = 0x0004;
+    public static final int SSL_INFO_CIPHER_VERSION            = 0x0005;
+    public static final int SSL_INFO_CIPHER_DESCRIPTION        = 0x0006;
+    public static final int SSL_INFO_PROTOCOL                  = 0x0007;
+
+    /* To obtain the CountryName of the Client Certificate Issuer
+     * use the SSL_INFO_CLIENT_I_DN + SSL_INFO_DN_COUNTRYNAME
+     */
+    public static final int SSL_INFO_CLIENT_S_DN               = 0x0010;
+    public static final int SSL_INFO_CLIENT_I_DN               = 0x0020;
+    public static final int SSL_INFO_SERVER_S_DN               = 0x0040;
+    public static final int SSL_INFO_SERVER_I_DN               = 0x0080;
+
+    public static final int SSL_INFO_DN_COUNTRYNAME            = 0x0001;
+    public static final int SSL_INFO_DN_STATEORPROVINCENAME    = 0x0002;
+    public static final int SSL_INFO_DN_LOCALITYNAME           = 0x0003;
+    public static final int SSL_INFO_DN_ORGANIZATIONNAME       = 0x0004;
+    public static final int SSL_INFO_DN_ORGANIZATIONALUNITNAME = 0x0005;
+    public static final int SSL_INFO_DN_COMMONNAME             = 0x0006;
+    public static final int SSL_INFO_DN_TITLE                  = 0x0007;
+    public static final int SSL_INFO_DN_INITIALS               = 0x0008;
+    public static final int SSL_INFO_DN_GIVENNAME              = 0x0009;
+    public static final int SSL_INFO_DN_SURNAME                = 0x000A;
+    public static final int SSL_INFO_DN_DESCRIPTION            = 0x000B;
+    public static final int SSL_INFO_DN_UNIQUEIDENTIFIER       = 0x000C;
+    public static final int SSL_INFO_DN_EMAILADDRESS           = 0x000D;
+
+    public static final int SSL_INFO_CLIENT_M_VERSION          = 0x0101;
+    public static final int SSL_INFO_CLIENT_M_SERIAL           = 0x0102;
+    public static final int SSL_INFO_CLIENT_V_START            = 0x0103;
+    public static final int SSL_INFO_CLIENT_V_END              = 0x0104;
+    public static final int SSL_INFO_CLIENT_A_SIG              = 0x0105;
+    public static final int SSL_INFO_CLIENT_A_KEY              = 0x0106;
+    public static final int SSL_INFO_CLIENT_CERT               = 0x0107;
+    public static final int SSL_INFO_CLIENT_V_REMAIN           = 0x0108;
+
+    public static final int SSL_INFO_SERVER_M_VERSION          = 0x0201;
+    public static final int SSL_INFO_SERVER_M_SERIAL           = 0x0202;
+    public static final int SSL_INFO_SERVER_V_START            = 0x0203;
+    public static final int SSL_INFO_SERVER_V_END              = 0x0204;
+    public static final int SSL_INFO_SERVER_A_SIG              = 0x0205;
+    public static final int SSL_INFO_SERVER_A_KEY              = 0x0206;
+    public static final int SSL_INFO_SERVER_CERT               = 0x0207;
+    /* Return client certificate chain.
+     * Add certificate chain number to that flag (0 ... verify depth)
+     */
+    public static final int SSL_INFO_CLIENT_CERT_CHAIN         = 0x0400;
+    /* Return OpenSSL version number */
+    public static native int version();
+
+    /* Return OpenSSL version string */
+    public static native String versionString();
+
+    /**
+     * Initialize OpenSSL support.
+     * This function needs to be called once for the
+     * lifetime of JVM. Library.init() has to be called before.
+     * @param engine Support for external a Crypto Device ("engine"),
+     *                usually
+     * a hardware accellerator card for crypto operations.
+     * @return APR status code
+     */
+    public static native int initialize(String engine);
+
+    /**
+     * Add content of the file to the PRNG
+     * @param filename Filename containing random data.
+     *        If null the default file will be tested.
+     *        The seed file is $RANDFILE if that environment variable is
+     *        set, $HOME/.rnd otherwise.
+     *        In case both files are unavailable builtin
+     *        random seed generator is used.
+     */
+    public static native boolean randLoad(String filename);
+
+    /**
+     * Writes a number of random bytes (currently 1024) to
+     * file <code>filename</code> which can be used to initialize the PRNG
+     * by calling randLoad in a later session.
+     * @param filename Filename to save the data
+     */
+    public static native boolean randSave(String filename);
+
+    /**
+     * Creates random data to filename
+     * @param filename Filename to save the data
+     * @param len The length of random sequence in bytes
+     * @param base64 Output the data in Base64 encoded format
+     */
+    public static native boolean randMake(String filename, int len,
+                                          boolean base64);
+
+    /**
+     * Sets global random filename.
+     * @param filename Filename to use.
+     *        If set it will be used for SSL initialization
+     *        and all contexts where explicitly not set.
+     */
+    public static native void randSet(String filename);
+
+    /**
+     * Initialize new BIO
+     * @param pool The pool to use.
+     * @param callback BIOCallback to use
+     * @return New BIO handle
+     */
+     public static native long newBIO(long pool, BIOCallback callback)
+            throws Exception;
+
+    /**
+     * Close BIO and derefrence callback object
+     * @param bio BIO to close and destroy.
+     * @return APR Status code
+     */
+     public static native int closeBIO(long bio);
+
+    /**
+     * Set global Password callback for obtaining passwords.
+     * @param callback PasswordCallback implementation to use.
+     */
+     public static native void setPasswordCallback(PasswordCallback callback);
+
+    /**
+     * Set global Password for decrypting certificates and keys.
+     * @param password Password to use.
+     */
+     public static native void setPassword(String password);
+
+    /**
+     * Generate temporary RSA key.
+     * <br />
+     * Index can be one of:
+     * <PRE>
+     * SSL_TMP_KEY_RSA_512
+     * SSL_TMP_KEY_RSA_1024
+     * SSL_TMP_KEY_RSA_2048
+     * SSL_TMP_KEY_RSA_4096
+     * </PRE>
+     * By default 512 and 1024 keys are generated on startup.
+     * You can use a low priority thread to generate them on the fly.
+     * @param idx temporary key index.
+     */
+    public static native boolean generateRSATempKey(int idx);
+
+    /**
+     * Load temporary DSA key from file
+     * <br />
+     * Index can be one of:
+     * <PRE>
+     * SSL_TMP_KEY_DH_512
+     * SSL_TMP_KEY_DH_1024
+     * SSL_TMP_KEY_DH_2048
+     * SSL_TMP_KEY_DH_4096
+     * </PRE>
+     * @param idx temporary key index.
+     * @param file File contatining DH params.
+     */
+    public static native boolean loadDSATempKey(int idx, String file);
+
+    /**
+     * Return last SSL error string
+     */
+    public static native String getLastError();
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jni/java/org/apache/tomcat/jni/SSLContext.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jni/java/org/apache/tomcat/jni/SSLContext.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jni/java/org/apache/tomcat/jni/SSLContext.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,276 @@
+/*
+ *  Copyright 2000-2005 The Apache Software Foundation
+ *
+ *  Licensed 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.jni;
+
+/** SSL Context
+ *
+ * @author Mladen Turk
+ * @version $Revision: 300969 $, $Date: 2005-07-12 09:56:11 -0500 (Tue, 12 Jul 2005) $
+ */
+
+public final class SSLContext {
+
+
+    /**
+     * Initialize new SSL context
+     * @param pool The pool to use.
+     * @param protocol The SSL protocol to use. It can be one of:
+     * <PRE>
+     * SSL_PROTOCOL_SSLV2
+     * SSL_PROTOCOL_SSLV3
+     * SSL_PROTOCOL_SSLV2 | SSL_PROTOCOL_SSLV3
+     * SSL_PROTOCOL_TLSV1
+     * SSL_PROTOCOL_ALL
+     * </PRE>
+     * @param mode SSL mode to use
+     * <PRE>
+     * SSL_MODE_CLIENT
+     * SSL_MODE_SERVER
+     * SSL_MODE_COMBINED
+     * </PRE>
+     */
+    public static native long make(long pool, int protocol, int mode)
+        throws Exception;
+
+    /**
+     * Free the resources used by the Context
+     * @param ctx Server or Client context to free.
+     * @return APR Status code.
+     */
+    public static native int free(long ctx);
+
+    /**
+     * Set Session context id. Usually host:port combination.
+     * @param ctx Context to use.
+     * @param id  String that uniquely identifies this context.
+     */
+    public static native void setContextId(long ctx, String id);
+
+    /**
+     * Asssociate BIOCallback for input or output data capture.
+     * <br />
+     * First word in the output string will contain error
+     * level in the form:
+     * <PRE>
+     * [ERROR]  -- Critical error messages
+     * [WARN]   -- Varning messages
+     * [INFO]   -- Informational messages
+     * [DEBUG]  -- Debugging messaged
+     * </PRE>
+     * Callback can use that word to determine application logging level
+     * by intercepting <b>write</b> call.
+     * If the <b>bio</b> is set to 0 no error messages will be displayed.
+     * Default is to use the stderr output stream.
+     * @param ctx Server or Client context to use.
+     * @param bio BIO handle to use, created with SSL.newBIO
+     * @param dir BIO direction (1 for input 0 for output).
+     */
+    public static native void setBIO(long ctx, long bio, int dir);
+
+    /**
+     * Set OpenSSL Option.
+     * @param ctx Server or Client context to use.
+     * @param options  See SSL.SSL_OP_* for option flags.
+     */
+    public static native void setOptions(long ctx, int options);
+
+    /**
+     * Sets the "quiet shutdown" flag for <b>ctx</b> to be
+     * <b>mode</b>. SSL objects created from <b>ctx</b> inherit the
+     * <b>mode</b> valid at the time and may be 0 or 1.
+     * <br />
+     * Normally when a SSL connection is finished, the parties must send out
+     * "close notify" alert messages using L<SSL_shutdown(3)|SSL_shutdown(3)>
+     * for a clean shutdown.
+     * <br />
+     * When setting the "quiet shutdown" flag to 1, <b>SSL.shutdown</b>
+     * will set the internal flags to SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN.
+     * (<b>SSL_shutdown</b> then behaves like called with
+     * SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN.)
+     * The session is thus considered to be shutdown, but no "close notify" alert
+     * is sent to the peer. This behaviour violates the TLS standard.
+     * The default is normal shutdown behaviour as described by the TLS standard.
+     * @param ctx Server or Client context to use.
+     * @param mode True to set the quiet shutdown.
+     */
+    public static native void setQuietShutdown(long ctx, boolean mode);
+
+    /**
+     * Cipher Suite available for negotiation in SSL handshake.
+     * <br />
+     * This complex directive uses a colon-separated cipher-spec string consisting
+     * of OpenSSL cipher specifications to configure the Cipher Suite the client
+     * is permitted to negotiate in the SSL handshake phase. Notice that this
+     * directive can be used both in per-server and per-directory context.
+     * In per-server context it applies to the standard SSL handshake when a
+     * connection is established. In per-directory context it forces a SSL
+     * renegotation with the reconfigured Cipher Suite after the HTTP request
+     * was read but before the HTTP response is sent.
+     * @param ctx Server or Client context to use.
+     * @param ciphers An SSL cipher specification.
+     */
+    public static native boolean setCipherSuite(long ctx, String ciphers)
+        throws Exception;
+
+    /**
+     * Set File of concatenated PEM-encoded CA CRLs or
+     * directory of PEM-encoded CA Certificates for Client Auth
+     * <br />
+     * This directive sets the all-in-one file where you can assemble the
+     * Certificate Revocation Lists (CRL) of Certification Authorities (CA)
+     * whose clients you deal with. These are used for Client Authentication.
+     * Such a file is simply the concatenation of the various PEM-encoded CRL
+     * files, in order of preference.
+     * <br />
+     * The files in this directory have to be PEM-encoded and are accessed through
+     * hash filenames. So usually you can't just place the Certificate files there:
+     * you also have to create symbolic links named hash-value.N. And you should
+     * always make sure this directory contains the appropriate symbolic links.
+     * Use the Makefile which comes with mod_ssl to accomplish this task.
+     * @param ctx Server or Client context to use.
+     * @param file File of concatenated PEM-encoded CA CRLs for Client Auth.
+     * @param path Directory of PEM-encoded CA Certificates for Client Auth.
+     */
+    public static native boolean setCARevocation(long ctx, String file,
+                                                 String path)
+        throws Exception;
+
+    /**
+     * Set File of PEM-encoded Server CA Certificates
+     * <br />
+     * This directive sets the optional all-in-one file where you can assemble the
+     * certificates of Certification Authorities (CA) which form the certificate
+     * chain of the server certificate. This starts with the issuing CA certificate
+     * of of the server certificate and can range up to the root CA certificate.
+     * Such a file is simply the concatenation of the various PEM-encoded CA
+     * Certificate files, usually in certificate chain order.
+     * <br />
+     * But be careful: Providing the certificate chain works only if you are using
+     * a single (either RSA or DSA) based server certificate. If you are using a
+     * coupled RSA+DSA certificate pair, this will work only if actually both
+     * certificates use the same certificate chain. Else the browsers will be
+     * confused in this situation.
+     * @param ctx Server or Client context to use.
+     * @param file File of PEM-encoded Server CA Certificates.
+     * @param skipfirst Skip first certificate if chain file is inside
+     *                  certificate file.
+     */
+    public static native boolean setCertificateChainFile(long ctx, String file,
+                                                         boolean skipfirst);
+
+    /**
+     * Set Certificate
+     * <br />
+     * Point setCertificateFile at a PEM encoded certificate.  If
+     * the certificate is encrypted, then you will be prompted for a
+     * pass phrase.  Note that a kill -HUP will prompt again. A test
+     * certificate can be generated with `make certificate' under
+     * built time. Keep in mind that if you've both a RSA and a DSA
+     * certificate you can configure both in parallel (to also allow
+     * the use of DSA ciphers, etc.)
+     * <br />
+     * If the key is not combined with the certificate, use key param
+     * to point at the key file.  Keep in mind that if
+     * you've both a RSA and a DSA private key you can configure
+     * both in parallel (to also allow the use of DSA ciphers, etc.)
+     * @param ctx Server or Client context to use.
+     * @param cert Certificate file.
+     * @param key Private Key file to use if not in cert.
+     * @param password Certificate password. If null and certificate
+     *                 is encrypted, password prompt will be dispayed.
+     * @param idx Certificate index SSL_AIDX_RSA or SSL_AIDX_DSA.
+     */
+    public static native boolean setCertificate(long ctx, String cert,
+                                                String key, String password,
+                                                int idx)
+        throws Exception;
+
+    /**
+     * Set File and Directory of concatenated PEM-encoded CA Certificates
+     * for Client Auth
+     * <br />
+     * This directive sets the all-in-one file where you can assemble the
+     * Certificates of Certification Authorities (CA) whose clients you deal with.
+     * These are used for Client Authentication. Such a file is simply the
+     * concatenation of the various PEM-encoded Certificate files, in order of
+     * preference. This can be used alternatively and/or additionally to
+     * path.
+     * <br />
+     * The files in this directory have to be PEM-encoded and are accessed through
+     * hash filenames. So usually you can't just place the Certificate files there:
+     * you also have to create symbolic links named hash-value.N. And you should
+     * always make sure this directory contains the appropriate symbolic links.
+     * Use the Makefile which comes with mod_ssl to accomplish this task.
+     * @param ctx Server or Client context to use.
+     * @param file File of concatenated PEM-encoded CA Certificates for
+     *             Client Auth.
+     * @param path Directory of PEM-encoded CA Certificates for Client Auth.
+     */
+    public static native boolean setCACertificate(long ctx, String file,
+                                                  String path)
+        throws Exception;
+
+    /**
+     * Set SSL connection shutdown type
+     * <br />
+     * The following levels are available for level:
+     * <PRE>
+     * SSL_SHUTDOWN_TYPE_STANDARD
+     * SSL_SHUTDOWN_TYPE_UNCLEAN
+     * SSL_SHUTDOWN_TYPE_ACCURATE
+     * </PRE>
+     * @param ctx Server or Client context to use.
+     * @param type Shutdown type to use.
+     */
+    public static native void setShutdowType(long ctx, int type);
+
+    /**
+     * Set Type of Client Certificate verification and Maximum depth of CA Certificates
+     * in Client Certificate verification.
+     * <br />
+     * This directive sets the Certificate verification level for the Client
+     * Authentication. Notice that this directive can be used both in per-server
+     * and per-directory context. In per-server context it applies to the client
+     * authentication process used in the standard SSL handshake when a connection
+     * is established. In per-directory context it forces a SSL renegotation with
+     * the reconfigured client verification level after the HTTP request was read
+     * but before the HTTP response is sent.
+     * <br />
+     * The following levels are available for level:
+     * <PRE>
+     * SSL_CVERIFY_NONE           - No client Certificate is required at all
+     * SSL_CVERIFY_OPTIONAL       - The client may present a valid Certificate
+     * SSL_CVERIFY_REQUIRE        - The client has to present a valid Certificate
+     * SSL_CVERIFY_OPTIONAL_NO_CA - The client may present a valid Certificate
+     *                              but it need not to be (successfully) verifiable
+     * </PRE>
+     * <br />
+     * The depth actually is the maximum number of intermediate certificate issuers,
+     * i.e. the number of CA certificates which are max allowed to be followed while
+     * verifying the client certificate. A depth of 0 means that self-signed client
+     * certificates are accepted only, the default depth of 1 means the client
+     * certificate can be self-signed or has to be signed by a CA which is directly
+     * known to the server (i.e. the CA's certificate is under
+     * <code>setCACertificatePath</code>), etc.
+     * @param ctx Server or Client context to use.
+     * @param level Type of Client Certificate verification.
+     * @param depth Maximum depth of CA Certificates in Client Certificate
+     *              verification.
+     */
+    public static native void setVerify(long ctx, int level, int depth);
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jni/java/org/apache/tomcat/jni/SSLSocket.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jni/java/org/apache/tomcat/jni/SSLSocket.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jni/java/org/apache/tomcat/jni/SSLSocket.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,88 @@
+/*
+ *  Copyright 2000-2005 The Apache Software Foundation
+ *
+ *  Licensed 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.jni;
+
+/** SSL Socket
+ *
+ * @author Mladen Turk
+ * @version $Revision: 300970 $, $Date: 2005-07-12 12:01:42 -0500 (Tue, 12 Jul 2005) $
+ */
+
+public class SSLSocket {
+
+    /**
+     * Attach APR socket on a SSL connection.
+     * @param ctx SSLContext to use.
+     * @param sock APR Socket that already did physical connect or accept.
+     * @return APR_STATUS code.
+     */
+    public static native int attach(long ctx, long sock)
+        throws Exception;
+
+    /**
+     * Do a SSL handshake.
+     * @param thesocket The socket to use
+     */
+    public static native int handshake(long thesocket);
+
+    /**
+     * Do a SSL renegotiation.
+     * SSL supports per-directory re-configuration of SSL parameters.
+     * This is implemented by performing an SSL renegotiation of the
+     * re-configured parameters after the request is read, but before the
+     * response is sent. In more detail: the renegotiation happens after the
+     * request line and MIME headers were read, but _before_ the attached
+     * request body is read. The reason simply is that in the HTTP protocol
+     * usually there is no acknowledgment step between the headers and the
+     * body (there is the 100-continue feature and the chunking facility
+     * only), so Apache has no API hook for this step.
+     *
+     * @param thesocket The socket to use
+     */
+    public static native int renegotiate(long thesocket);
+
+    /**
+     * Retrun SSL Info parameter as byte array.
+     *
+     * @param sock The socket to read the data from.
+     * @param id Parameter id.
+     * @return Byte array containing info id value.
+     */
+    public static native byte[] getInfoB(long sock, int id)
+        throws Exception;
+
+    /**
+     * Retrun SSL Info parameter as String.
+     *
+     * @param sock The socket to read the data from.
+     * @param id Parameter id.
+     * @return String containing info id value.
+     */
+    public static native String getInfoS(long sock, int id)
+        throws Exception;
+
+    /**
+     * Retrun SSL Info parameter as integer.
+     *
+     * @param sock The socket to read the data from.
+     * @param id Parameter id.
+     * @return Integer containing info id value or -1 on error.
+     */
+    public static native int getInfoI(long sock, int id)
+        throws Exception;
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jni/java/org/apache/tomcat/jni/Shm.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jni/java/org/apache/tomcat/jni/Shm.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jni/java/org/apache/tomcat/jni/Shm.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,123 @@
+/*
+ *  Copyright 2000-2005 The Apache Software Foundation
+ *
+ *  Licensed 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.jni;
+
+import java.nio.ByteBuffer;
+
+/** Shm
+ *
+ * @author Mladen Turk
+ * @version $Revision: 300969 $, $Date: 2005-07-12 09:56:11 -0500 (Tue, 12 Jul 2005) $
+ */
+
+public class Shm {
+
+    /**
+     * Create and make accessable a shared memory segment.
+     * <br />
+     * A note about Anonymous vs. Named shared memory segments:<br />
+     *         Not all plaforms support anonymous shared memory segments, but in
+     *         some cases it is prefered over other types of shared memory
+     *         implementations. Passing a NULL 'file' parameter to this function
+     *         will cause the subsystem to use anonymous shared memory segments.
+     *         If such a system is not available, APR_ENOTIMPL is returned.
+     * <br />
+     * A note about allocation sizes:<br />
+     *         On some platforms it is necessary to store some metainformation
+     *         about the segment within the actual segment. In order to supply
+     *         the caller with the requested size it may be necessary for the
+     *         implementation to request a slightly greater segment length
+     *         from the subsystem. In all cases, the apr_shm_baseaddr_get()
+     *         function will return the first usable byte of memory.
+     * @param reqsize The desired size of the segment.
+     * @param filename The file to use for shared memory on platforms that
+     *        require it.
+     * @param pool the pool from which to allocate the shared memory
+     *        structure.
+     * @return The created shared memory structure.
+     *
+     */
+    public static native long create(long reqsize, String filename, long pool)
+        throws Error;
+
+    /**
+     * Remove shared memory segment associated with a filename.
+     * <br />
+     * This function is only supported on platforms which support
+     * name-based shared memory segments, and will return APR_ENOTIMPL on
+     * platforms without such support.
+     * @param filename The filename associated with shared-memory segment which
+     *        needs to be removed
+     * @param pool The pool used for file operations
+     */
+    public static native int remove(String filename, long pool);
+
+    /**
+     * Destroy a shared memory segment and associated memory.
+     * @param m The shared memory segment structure to destroy.
+     */
+    public static native int destroy(long m);
+
+    /**
+     * Attach to a shared memory segment that was created
+     * by another process.
+     * @param filename The file used to create the original segment.
+     *        (This MUST match the original filename.)
+     * @param pool the pool from which to allocate the shared memory
+     *        structure for this process.
+     * @return The created shared memory structure.
+     */
+    public static native long attach(String filename, long pool)
+        throws Error;
+
+    /**
+     * Detach from a shared memory segment without destroying it.
+     * @param m The shared memory structure representing the segment
+     *        to detach from.
+     */
+    public static native int detach(long m);
+
+    /**
+     * Retrieve the base address of the shared memory segment.
+     * NOTE: This address is only usable within the callers address
+     * space, since this API does not guarantee that other attaching
+     * processes will maintain the same address mapping.
+     * @param m The shared memory segment from which to retrieve
+     *        the base address.
+     * @return address, aligned by APR_ALIGN_DEFAULT.
+     */
+    public static native long baseaddr(long m);
+
+    /**
+     * Retrieve the length of a shared memory segment in bytes.
+     * @param m The shared memory segment from which to retrieve
+     *        the segment length.
+     */
+    public static native long size(long m);
+
+    /**
+     * Retrieve new ByteBuffer base address of the shared memory segment.
+     * NOTE: This address is only usable within the callers address
+     * space, since this API does not guarantee that other attaching
+     * processes will maintain the same address mapping.
+     * @param m The shared memory segment from which to retrieve
+     *        the base address.
+     * @return address, aligned by APR_ALIGN_DEFAULT.
+     */
+    public static native ByteBuffer buffer(long m);
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jni/java/org/apache/tomcat/jni/Sockaddr.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jni/java/org/apache/tomcat/jni/Sockaddr.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jni/java/org/apache/tomcat/jni/Sockaddr.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,41 @@
+/*
+ *  Copyright 2000-2005 The Apache Software Foundation
+ *
+ *  Licensed 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.jni;
+
+/** Sockaddr
+ *
+ * @author Mladen Turk
+ * @version $Revision: 300969 $, $Date: 2005-07-12 09:56:11 -0500 (Tue, 12 Jul 2005) $
+ */
+
+public class Sockaddr {
+
+   /** The pool to use... */
+    public long pool;
+    /** The hostname */
+    public String hostname;
+    /** Either a string of the port number or the service name for the port */
+    public String servname;
+    /** The numeric port */
+    public int port;
+    /** The family */
+    public int family;
+    /** If multiple addresses were found by apr_sockaddr_info_get(), this
+     *  points to a representation of the next address. */
+    public long next;
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jni/java/org/apache/tomcat/jni/Socket.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jni/java/org/apache/tomcat/jni/Socket.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jni/java/org/apache/tomcat/jni/Socket.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,546 @@
+/*
+ *  Copyright 2000-2005 The Apache Software Foundation
+ *
+ *  Licensed 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.jni;
+
+/* Import needed classes */
+import java.nio.ByteBuffer;
+
+/** Socket
+ *
+ * @author Mladen Turk
+ * @version $Revision: 416780 $, $Date: 2006-06-23 12:58:41 -0500 (Fri, 23 Jun 2006) $
+ */
+
+public class Socket {
+
+    /* Standard socket defines */
+    public static final int SOCK_STREAM = 0;
+    public static final int SOCK_DGRAM  = 1;
+    /*
+     * apr_sockopt Socket option definitions
+     */
+    public static final int APR_SO_LINGER       = 1;    /** Linger */
+    public static final int APR_SO_KEEPALIVE    = 2;    /** Keepalive */
+    public static final int APR_SO_DEBUG        = 4;    /** Debug */
+    public static final int APR_SO_NONBLOCK     = 8;    /** Non-blocking IO */
+    public static final int APR_SO_REUSEADDR    = 16;   /** Reuse addresses */
+    public static final int APR_SO_SNDBUF       = 64;   /** Send buffer */
+    public static final int APR_SO_RCVBUF       = 128;  /** Receive buffer */
+    public static final int APR_SO_DISCONNECTED = 256;  /** Disconnected */
+    /** For SCTP sockets, this is mapped to STCP_NODELAY internally. */
+    public static final int APR_TCP_NODELAY     = 512;
+    public static final int APR_TCP_NOPUSH      = 1024; /** No push */
+    /** This flag is ONLY set internally when we set APR_TCP_NOPUSH with
+     * APR_TCP_NODELAY set to tell us that APR_TCP_NODELAY should be turned on
+     * again when NOPUSH is turned off
+     */
+    public static final int APR_RESET_NODELAY   = 2048;
+    /** Set on non-blocking sockets (timeout != 0) on which the
+     * previous read() did not fill a buffer completely.  the next
+     * apr_socket_recv()  will first call select()/poll() rather than
+     * going straight into read().  (Can also be set by an application to
+     * force a select()/poll() call before the next read, in cases where
+     * the app expects that an immediate read would fail.)
+     */
+    public static final int APR_INCOMPLETE_READ = 4096;
+    /** like APR_INCOMPLETE_READ, but for write
+     */
+    public static final int APR_INCOMPLETE_WRITE = 8192;
+    /** Don't accept IPv4 connections on an IPv6 listening socket.
+     */
+    public static final int APR_IPV6_V6ONLY      = 16384;
+    /** Delay accepting of new connections until data is available.
+     */
+    public static final int APR_TCP_DEFER_ACCEPT = 32768;
+
+    /** Define what type of socket shutdown should occur.
+     * apr_shutdown_how_e enum
+     */
+    public static final int APR_SHUTDOWN_READ      = 0; /** no longer allow read request */
+    public static final int APR_SHUTDOWN_WRITE     = 1; /** no longer allow write requests */
+    public static final int APR_SHUTDOWN_READWRITE = 2; /** no longer allow read or write requests */
+
+    public static final int APR_IPV4_ADDR_OK = 0x01;
+    public static final int APR_IPV6_ADDR_OK = 0x02;
+
+    /* TODO: Missing:
+     * APR_INET
+     * APR_UNSPEC
+     * APR_INET6
+     */
+    public static final int APR_UNSPEC = 0;
+    public static final int APR_INET   = 1;
+    public static final int APR_INET6  = 2;
+
+    public static final int APR_PROTO_TCP  =   6; /** TCP  */
+    public static final int APR_PROTO_UDP  =  17; /** UDP  */
+    public static final int APR_PROTO_SCTP = 132; /** SCTP */
+
+    /**
+     * Enum to tell us if we're interested in remote or local socket
+     * apr_interface_e
+     */
+    public static final int APR_LOCAL  = 0;
+    public static final int APR_REMOTE = 1;
+
+    /* Socket.get types */
+    public static final int SOCKET_GET_POOL = 0;
+    public static final int SOCKET_GET_IMPL = 1;
+    public static final int SOCKET_GET_APRS = 2;
+    public static final int SOCKET_GET_TYPE = 3;
+
+    /**
+     * Create a socket.
+     * @param family The address family of the socket (e.g., APR_INET).
+     * @param type The type of the socket (e.g., SOCK_STREAM).
+     * @param protocol The protocol of the socket (e.g., APR_PROTO_TCP).
+     * @param cont The parent pool to use
+     * @return The new socket that has been set up.
+     */
+    public static native long create(int family, int type,
+                                     int protocol, long cont)
+        throws Exception;
+
+
+    /**
+     * Shutdown either reading, writing, or both sides of a socket.
+     * <br />
+     * This does not actually close the socket descriptor, it just
+     *      controls which calls are still valid on the socket.
+     * @param thesocket The socket to close
+     * @param how How to shutdown the socket.  One of:
+     * <PRE>
+     * APR_SHUTDOWN_READ         no longer allow read requests
+     * APR_SHUTDOWN_WRITE        no longer allow write requests
+     * APR_SHUTDOWN_READWRITE    no longer allow read or write requests
+     * </PRE>
+     */
+    public static native int shutdown(long thesocket, int how);
+
+    /**
+     * Close a socket.
+     * @param thesocket The socket to close
+     */
+    public static native int close(long thesocket);
+
+    /**
+     * Destroy a pool associated with socket
+     * @param thesocket The destroy
+     */
+    public static native void destroy(long thesocket);
+
+    /**
+     * Bind the socket to its associated port
+     * @param sock The socket to bind
+     * @param sa The socket address to bind to
+     * This may be where we will find out if there is any other process
+     *      using the selected port.
+     */
+    public static native int bind(long sock, long sa);
+
+    /**
+     * Listen to a bound socket for connections.
+     * @param sock The socket to listen on
+     * @param backlog The number of outstanding connections allowed in the sockets
+     *                listen queue.  If this value is less than zero, the listen
+     *                queue size is set to zero.
+     */
+    public static native int listen(long sock, int backlog);
+
+    /**
+     * Accept a new connection request
+     * @param sock The socket we are listening on.
+     * @param pool The pool for the new socket.
+     * @return  A copy of the socket that is connected to the socket that
+     *          made the connection request.  This is the socket which should
+     *          be used for all future communication.
+     */
+    public static native long accept(long sock)
+        throws Exception;
+
+    /**
+     * Set an OS level accept filter.
+     * @param sock The socket to put the accept filter on.
+     * @param name The accept filter
+     * @param args Any extra args to the accept filter.  Passing NULL here removes
+     *             the accept filter.
+     */
+    public static native int acceptfilter(long sock, String name, String args);
+
+    /**
+     * Query the specified socket if at the OOB/Urgent data mark
+     * @param sock The socket to query
+     * @return True if socket is at the OOB/urgent mark,
+     *         otherwise return false.
+     */
+    public static native boolean atmark(long sock);
+
+    /**
+     * Issue a connection request to a socket either on the same machine
+     * or a different one.
+     * @param sock The socket we wish to use for our side of the connection
+     * @param sa The address of the machine we wish to connect to.
+     */
+    public static native int connect(long sock, long sa);
+
+    /**
+     * Send data over a network.
+     * <PRE>
+     * This functions acts like a blocking write by default.  To change
+     * this behavior, use apr_socket_timeout_set() or the APR_SO_NONBLOCK
+     * socket option.
+     *
+     * It is possible for both bytes to be sent and an error to be returned.
+     *
+     * APR_EINTR is never returned.
+     * </PRE>
+     * @param sock The socket to send the data over.
+     * @param buf The buffer which contains the data to be sent.
+     * @param offset Offset in the byte buffer.
+     * @param len The number of bytes to write; (-1) for full array.
+     * @return The number of bytes send.
+     *
+     */
+    public static native int send(long sock, byte[] buf, int offset, int len);
+
+    /**
+     * Send data over a network.
+     * <PRE>
+     * This functions acts like a blocking write by default.  To change
+     * this behavior, use apr_socket_timeout_set() or the APR_SO_NONBLOCK
+     * socket option.
+     *
+     * It is possible for both bytes to be sent and an error to be returned.
+     *
+     * APR_EINTR is never returned.
+     * </PRE>
+     * @param sock The socket to send the data over.
+     * @param buf The Byte buffer which contains the data to be sent.
+     * @param offset The offset within the buffer array of the first buffer from
+     *               which bytes are to be retrieved; must be non-negative
+     *               and no larger than buf.length
+     * @param len The maximum number of buffers to be accessed; must be non-negative
+     *            and no larger than buf.length - offset
+     * @return The number of bytes send.
+     *
+     */
+    public static native int sendb(long sock, ByteBuffer buf,
+                                   int offset, int len);
+    /**
+     * Send data over a network using internally set ByteBuffer
+     */
+    public static native int sendbb(long sock,
+                                   int offset, int len);
+
+    /**
+     * Send multiple packets of data over a network.
+     * <PRE>
+     * This functions acts like a blocking write by default.  To change
+     * this behavior, use apr_socket_timeout_set() or the APR_SO_NONBLOCK
+     * socket option.
+     * The number of bytes actually sent is stored in argument 3.
+     *
+     * It is possible for both bytes to be sent and an error to be returned.
+     *
+     * APR_EINTR is never returned.
+     * </PRE>
+     * @param sock The socket to send the data over.
+     * @param vec The array from which to get the data to send.
+     *
+     */
+    public static native int sendv(long sock, byte[][] vec);
+
+    /**
+     * @param sock The socket to send from
+     * @param where The apr_sockaddr_t describing where to send the data
+     * @param flags The flags to use
+     * @param buf  The data to send
+     * @param offset Offset in the byte buffer.
+     * @param len  The length of the data to send
+     */
+    public static native int sendto(long sock, long where, int flags,
+                                    byte[] buf, int offset, int len);
+
+    /**
+     * Read data from a network.
+     *
+     * <PRE>
+     * This functions acts like a blocking read by default.  To change
+     * this behavior, use apr_socket_timeout_set() or the APR_SO_NONBLOCK
+     * socket option.
+     * The number of bytes actually received is stored in argument 3.
+     *
+     * It is possible for both bytes to be received and an APR_EOF or
+     * other error to be returned.
+     *
+     * APR_EINTR is never returned.
+     * </PRE>
+     * @param sock The socket to read the data from.
+     * @param buf The buffer to store the data in.
+     * @param offset Offset in the byte buffer.
+     * @param nbytes The number of bytes to read (-1) for full array.
+     * @return the number of bytes received.
+     */
+    public static native int recv(long sock, byte[] buf, int offset, int nbytes);
+
+    /**
+     * Read data from a network with timeout.
+     *
+     * <PRE>
+     * This functions acts like a blocking read by default.  To change
+     * this behavior, use apr_socket_timeout_set() or the APR_SO_NONBLOCK
+     * socket option.
+     * The number of bytes actually received is stored in argument 3.
+     *
+     * It is possible for both bytes to be received and an APR_EOF or
+     * other error to be returned.
+     *
+     * APR_EINTR is never returned.
+     * </PRE>
+     * @param sock The socket to read the data from.
+     * @param buf The buffer to store the data in.
+     * @param offset Offset in the byte buffer.
+     * @param nbytes The number of bytes to read (-1) for full array.
+     * @param timeout The socket timeout in microseconds.
+     * @return the number of bytes received.
+     */
+    public static native int recvt(long sock, byte[] buf, int offset,
+                                   int nbytes, long timeout);
+
+    /**
+     * Read data from a network.
+     *
+     * <PRE>
+     * This functions acts like a blocking read by default.  To change
+     * this behavior, use apr_socket_timeout_set() or the APR_SO_NONBLOCK
+     * socket option.
+     * The number of bytes actually received is stored in argument 3.
+     *
+     * It is possible for both bytes to be received and an APR_EOF or
+     * other error to be returned.
+     *
+     * APR_EINTR is never returned.
+     * </PRE>
+     * @param sock The socket to read the data from.
+     * @param buf The buffer to store the data in.
+     * @param offset Offset in the byte buffer.
+     * @param nbytes The number of bytes to read (-1) for full array.
+     * @return the number of bytes received.
+     */
+    public static native int recvb(long sock, ByteBuffer buf,
+                                   int offset, int nbytes);
+    /**
+     * Read data from a network using internally set ByteBuffer
+     */
+    public static native int recvbb(long sock,
+                                    int offset, int nbytes);
+    /**
+     * Read data from a network with timeout.
+     *
+     * <PRE>
+     * This functions acts like a blocking read by default.  To change
+     * this behavior, use apr_socket_timeout_set() or the APR_SO_NONBLOCK
+     * socket option.
+     * The number of bytes actually received is stored in argument 3.
+     *
+     * It is possible for both bytes to be received and an APR_EOF or
+     * other error to be returned.
+     *
+     * APR_EINTR is never returned.
+     * </PRE>
+     * @param sock The socket to read the data from.
+     * @param buf The buffer to store the data in.
+     * @param offset Offset in the byte buffer.
+     * @param nbytes The number of bytes to read (-1) for full array.
+     * @param timeout The socket timeout in microseconds.
+     * @return the number of bytes received.
+     */
+    public static native int recvbt(long sock, ByteBuffer buf,
+                                    int offset, int nbytes, long timeout);
+    /**
+     * Read data from a network with timeout using internally set ByteBuffer
+     */
+    public static native int recvbbt(long sock,
+                                     int offset, int nbytes, long timeout);
+
+    /**
+     * @param from The apr_sockaddr_t to fill in the recipient info
+     * @param sock The socket to use
+     * @param flags The flags to use
+     * @param buf  The buffer to use
+     * @param offset Offset in the byte buffer.
+     * @param nbytes The number of bytes to read (-1) for full array.
+     * @return the number of bytes received.
+     */
+    public static native int recvFrom(long from, long sock, int flags,
+                                      byte[] buf, int offset, int nbytes);
+
+    /**
+     * Setup socket options for the specified socket
+     * @param sock The socket to set up.
+     * @param opt The option we would like to configure.  One of:
+     * <PRE>
+     * APR_SO_DEBUG      --  turn on debugging information
+     * APR_SO_KEEPALIVE  --  keep connections active
+     * APR_SO_LINGER     --  lingers on close if data is present
+     * APR_SO_NONBLOCK   --  Turns blocking on/off for socket
+     *                       When this option is enabled, use
+     *                       the APR_STATUS_IS_EAGAIN() macro to
+     *                       see if a send or receive function
+     *                       could not transfer data without
+     *                       blocking.
+     * APR_SO_REUSEADDR  --  The rules used in validating addresses
+     *                       supplied to bind should allow reuse
+     *                       of local addresses.
+     * APR_SO_SNDBUF     --  Set the SendBufferSize
+     * APR_SO_RCVBUF     --  Set the ReceiveBufferSize
+     * </PRE>
+     * @param on Value for the option.
+     */
+    public static native int optSet(long sock, int opt, int on);
+
+    /**
+     * Query socket options for the specified socket
+     * @param sock The socket to query
+     * @param opt The option we would like to query.  One of:
+     * <PRE>
+     * APR_SO_DEBUG      --  turn on debugging information
+     * APR_SO_KEEPALIVE  --  keep connections active
+     * APR_SO_LINGER     --  lingers on close if data is present
+     * APR_SO_NONBLOCK   --  Turns blocking on/off for socket
+     * APR_SO_REUSEADDR  --  The rules used in validating addresses
+     *                       supplied to bind should allow reuse
+     *                       of local addresses.
+     * APR_SO_SNDBUF     --  Set the SendBufferSize
+     * APR_SO_RCVBUF     --  Set the ReceiveBufferSize
+     * APR_SO_DISCONNECTED -- Query the disconnected state of the socket.
+     *                       (Currently only used on Windows)
+     * </PRE>
+     * @return Socket option returned on the call.
+     */
+    public static native int optGet(long sock, int opt)
+        throws Exception;
+
+    /**
+     * Setup socket timeout for the specified socket
+     * @param sock The socket to set up.
+     * @param t Value for the timeout in microseconds.
+     * <PRE>
+     * t > 0  -- read and write calls return APR_TIMEUP if specified time
+     *           elapsess with no data read or written
+     * t == 0 -- read and write calls never block
+     * t < 0  -- read and write calls block
+     * </PRE>
+     */
+    public static native int timeoutSet(long sock, long t);
+
+    /**
+     * Query socket timeout for the specified socket
+     * @param sock The socket to query
+     * @return Socket timeout returned from the query.
+     */
+    public static native long timeoutGet(long sock)
+        throws Exception;
+
+    /**
+     * Send a file from an open file descriptor to a socket, along with
+     * optional headers and trailers.
+     * <br />
+     * This functions acts like a blocking write by default.  To change
+     *         this behavior, use apr_socket_timeout_set() or the
+     *         APR_SO_NONBLOCK socket option.
+     * The number of bytes actually sent is stored in the len parameter.
+     * The offset parameter is passed by reference for no reason; its
+     * value will never be modified by the apr_socket_sendfile() function.
+     * @param sock The socket to which we're writing
+     * @param file The open file from which to read
+     * @param headers Array containing the headers to send
+     * @param trailers Array containing the trailers to send
+     * @param offset Offset into the file where we should begin writing
+     * @param len Number of bytes to send from the file
+     * @param flags APR flags that are mapped to OS specific flags
+     * @return Number of bytes actually sent, including headers,
+     *         file, and trailers
+     *
+     */
+    public static native long sendfile(long sock, long file, byte [][] headers,
+                                       byte[][] trailers, long offset,
+                                       long len, int flags);
+
+    /**
+     * Send a file without header and trailer arrays.
+     */
+    public static native long sendfilen(long sock, long file, long offset,
+                                        long len, int flags);
+
+    /**
+     * Create a child pool from associated socket pool.
+     * @param thesocket The socket to use
+     */
+    public static native long pool(long thesocket)
+        throws Exception;
+
+    /**
+     * Private method for geting the socket struct members
+     * @param socket The soocket to use
+     * @param what Struct member to obtain
+     * <PRE>
+     * SOCKET_GET_POOL  - The socket pool
+     * SOCKET_GET_IMPL  - The socket implementation object
+     * SOCKET_GET_APRS  - APR socket
+     * SOCKET_GET_TYPE  - Socket type
+     * </PRE>
+     * @return The stucture member address
+     */
+    private static native long get(long socket, int what);
+
+    /**
+     * Set internal send ByteBuffer.
+     * This function will preset internal Java ByteBuffer for
+     * consecutive sendbb calls.
+     * @param thesocket The socket to use
+     * @param buf The ByteBuffer
+     */
+    public static native void setsbb(long sock, ByteBuffer buf);
+
+    /**
+     * Set internal receive ByteBuffer.
+     * This function will preset internal Java ByteBuffer for
+     * consecutive revcvbb/recvbbt calls.
+     * @param thesocket The socket to use
+     * @param buf The ByteBuffer
+     */
+    public static native void setrbb(long sock, ByteBuffer buf);
+
+    /**
+     * Set the data associated with the current socket.
+     * @param sock The currently open socket.
+     * @param data The user data to associate with the socket.
+     * @param key The key to associate with the data.
+     * @param cleanup The cleanup to call when the socket is destroyed.
+     */
+      public static native int dataSet(long sock, String key, Object data);
+
+    /**
+     * Return the data associated with the current socket
+     * @param data The user data associated with the socket.
+     * @param key The key to associate with the user data.
+     * @param sock The currently open socket.
+     * @return Data or null in case of error.
+     */
+     public static native Object dataGet(long sock, String key);
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jni/java/org/apache/tomcat/jni/Status.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jni/java/org/apache/tomcat/jni/Status.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jni/java/org/apache/tomcat/jni/Status.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,264 @@
+/*
+ *  Copyright 2000-2005 The Apache Software Foundation
+ *
+ *  Licensed 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.jni;
+
+/** Status
+ *
+ * @author Mladen Turk
+ * @version $Revision: 300969 $, $Date: 2005-07-12 09:56:11 -0500 (Tue, 12 Jul 2005) $
+ */
+
+public class Status {
+
+    /**
+     * APR_OS_START_ERROR is where the APR specific error values start.
+     */
+     public static final int APR_OS_START_ERROR   = 20000;
+    /**
+     * APR_OS_ERRSPACE_SIZE is the maximum number of errors you can fit
+     *    into one of the error/status ranges below -- except for
+     *    APR_OS_START_USERERR, which see.
+     */
+     public static final int APR_OS_ERRSPACE_SIZE = 50000;
+    /**
+     * APR_OS_START_STATUS is where the APR specific status codes start.
+     */
+     public static final int APR_OS_START_STATUS  = (APR_OS_START_ERROR + APR_OS_ERRSPACE_SIZE);
+
+    /**
+     * APR_OS_START_USERERR are reserved for applications that use APR that
+     *     layer their own error codes along with APR's.  Note that the
+     *     error immediately following this one is set ten times farther
+     *     away than usual, so that users of apr have a lot of room in
+     *     which to declare custom error codes.
+     */
+    public static final int APR_OS_START_USERERR  = (APR_OS_START_STATUS + APR_OS_ERRSPACE_SIZE);
+    /**
+     * APR_OS_START_USEERR is obsolete, defined for compatibility only.
+     * Use APR_OS_START_USERERR instead.
+     */
+    public static final int APR_OS_START_USEERR    = APR_OS_START_USERERR;
+    /**
+     * APR_OS_START_CANONERR is where APR versions of errno values are defined
+     *     on systems which don't have the corresponding errno.
+     */
+    public static final int APR_OS_START_CANONERR  = (APR_OS_START_USERERR + (APR_OS_ERRSPACE_SIZE * 10));
+
+    /**
+     * APR_OS_START_EAIERR folds EAI_ error codes from getaddrinfo() into
+     *     apr_status_t values.
+     */
+    public static final int APR_OS_START_EAIERR  = (APR_OS_START_CANONERR + APR_OS_ERRSPACE_SIZE);
+    /**
+     * APR_OS_START_SYSERR folds platform-specific system error values into
+     *     apr_status_t values.
+     */
+    public static final int APR_OS_START_SYSERR  = (APR_OS_START_EAIERR + APR_OS_ERRSPACE_SIZE);
+
+    /** no error. */
+    public static final int APR_SUCCESS = 0;
+
+    /**
+     * APR Error Values
+     * <PRE>
+     * <b>APR ERROR VALUES</b>
+     * APR_ENOSTAT      APR was unable to perform a stat on the file
+     * APR_ENOPOOL      APR was not provided a pool with which to allocate memory
+     * APR_EBADDATE     APR was given an invalid date
+     * APR_EINVALSOCK   APR was given an invalid socket
+     * APR_ENOPROC      APR was not given a process structure
+     * APR_ENOTIME      APR was not given a time structure
+     * APR_ENODIR       APR was not given a directory structure
+     * APR_ENOLOCK      APR was not given a lock structure
+     * APR_ENOPOLL      APR was not given a poll structure
+     * APR_ENOSOCKET    APR was not given a socket
+     * APR_ENOTHREAD    APR was not given a thread structure
+     * APR_ENOTHDKEY    APR was not given a thread key structure
+     * APR_ENOSHMAVAIL  There is no more shared memory available
+     * APR_EDSOOPEN     APR was unable to open the dso object.  For more
+     *                  information call apr_dso_error().
+     * APR_EGENERAL     General failure (specific information not available)
+     * APR_EBADIP       The specified IP address is invalid
+     * APR_EBADMASK     The specified netmask is invalid
+     * APR_ESYMNOTFOUND Could not find the requested symbol
+     * </PRE>
+     *
+     */
+    public static final int APR_ENOSTAT       = (APR_OS_START_ERROR + 1);
+    public static final int APR_ENOPOOL       = (APR_OS_START_ERROR + 2);
+    public static final int APR_EBADDATE      = (APR_OS_START_ERROR + 4);
+    public static final int APR_EINVALSOCK    = (APR_OS_START_ERROR + 5);
+    public static final int APR_ENOPROC       = (APR_OS_START_ERROR + 6);
+    public static final int APR_ENOTIME       = (APR_OS_START_ERROR + 7);
+    public static final int APR_ENODIR        = (APR_OS_START_ERROR + 8);
+    public static final int APR_ENOLOCK       = (APR_OS_START_ERROR + 9);
+    public static final int APR_ENOPOLL       = (APR_OS_START_ERROR + 10);
+    public static final int APR_ENOSOCKET     = (APR_OS_START_ERROR + 11);
+    public static final int APR_ENOTHREAD     = (APR_OS_START_ERROR + 12);
+    public static final int APR_ENOTHDKEY     = (APR_OS_START_ERROR + 13);
+    public static final int APR_EGENERAL      = (APR_OS_START_ERROR + 14);
+    public static final int APR_ENOSHMAVAIL   = (APR_OS_START_ERROR + 15);
+    public static final int APR_EBADIP        = (APR_OS_START_ERROR + 16);
+    public static final int APR_EBADMASK      = (APR_OS_START_ERROR + 17);
+    public static final int APR_EDSOOPEN      = (APR_OS_START_ERROR + 19);
+    public static final int APR_EABSOLUTE     = (APR_OS_START_ERROR + 20);
+    public static final int APR_ERELATIVE     = (APR_OS_START_ERROR + 21);
+    public static final int APR_EINCOMPLETE   = (APR_OS_START_ERROR + 22);
+    public static final int APR_EABOVEROOT    = (APR_OS_START_ERROR + 23);
+    public static final int APR_EBADPATH      = (APR_OS_START_ERROR + 24);
+    public static final int APR_EPATHWILD     = (APR_OS_START_ERROR + 25);
+    public static final int APR_ESYMNOTFOUND  = (APR_OS_START_ERROR + 26);
+    public static final int APR_EPROC_UNKNOWN = (APR_OS_START_ERROR + 27);
+    public static final int APR_ENOTENOUGHENTROPY = (APR_OS_START_ERROR + 28);
+
+    /** APR Status Values
+     * <PRE>
+     * <b>APR STATUS VALUES</b>
+     * APR_INCHILD        Program is currently executing in the child
+     * APR_INPARENT       Program is currently executing in the parent
+     * APR_DETACH         The thread is detached
+     * APR_NOTDETACH      The thread is not detached
+     * APR_CHILD_DONE     The child has finished executing
+     * APR_CHILD_NOTDONE  The child has not finished executing
+     * APR_TIMEUP         The operation did not finish before the timeout
+     * APR_INCOMPLETE     The operation was incomplete although some processing
+     *                    was performed and the results are partially valid
+     * APR_BADCH          Getopt found an option not in the option string
+     * APR_BADARG         Getopt found an option that is missing an argument
+     *                    and an argument was specified in the option string
+     * APR_EOF            APR has encountered the end of the file
+     * APR_NOTFOUND       APR was unable to find the socket in the poll structure
+     * APR_ANONYMOUS      APR is using anonymous shared memory
+     * APR_FILEBASED      APR is using a file name as the key to the shared memory
+     * APR_KEYBASED       APR is using a shared key as the key to the shared memory
+     * APR_EINIT          Ininitalizer value.  If no option has been found, but
+     *                    the status variable requires a value, this should be used
+     * APR_ENOTIMPL       The APR function has not been implemented on this
+     *                    platform, either because nobody has gotten to it yet,
+     *                    or the function is impossible on this platform.
+     * APR_EMISMATCH      Two passwords do not match.
+     * APR_EBUSY          The given lock was busy.
+     * </PRE>
+     *
+     */
+    public static final int APR_INCHILD       = (APR_OS_START_STATUS + 1);
+    public static final int APR_INPARENT      = (APR_OS_START_STATUS + 2);
+    public static final int APR_DETACH        = (APR_OS_START_STATUS + 3);
+    public static final int APR_NOTDETACH     = (APR_OS_START_STATUS + 4);
+    public static final int APR_CHILD_DONE    = (APR_OS_START_STATUS + 5);
+    public static final int APR_CHILD_NOTDONE = (APR_OS_START_STATUS + 6);
+    public static final int APR_TIMEUP        = (APR_OS_START_STATUS + 7);
+    public static final int APR_INCOMPLETE    = (APR_OS_START_STATUS + 8);
+    public static final int APR_BADCH         = (APR_OS_START_STATUS + 12);
+    public static final int APR_BADARG        = (APR_OS_START_STATUS + 13);
+    public static final int APR_EOF           = (APR_OS_START_STATUS + 14);
+    public static final int APR_NOTFOUND      = (APR_OS_START_STATUS + 15);
+    public static final int APR_ANONYMOUS     = (APR_OS_START_STATUS + 19);
+    public static final int APR_FILEBASED     = (APR_OS_START_STATUS + 20);
+    public static final int APR_KEYBASED      = (APR_OS_START_STATUS + 21);
+    public static final int APR_EINIT         = (APR_OS_START_STATUS + 22);
+    public static final int APR_ENOTIMPL      = (APR_OS_START_STATUS + 23);
+    public static final int APR_EMISMATCH     = (APR_OS_START_STATUS + 24);
+    public static final int APR_EBUSY         = (APR_OS_START_STATUS + 25);
+
+    public static final int TIMEUP            = (APR_OS_START_USERERR + 1);
+    public static final int EAGAIN            = (APR_OS_START_USERERR + 2);
+    public static final int EINTR             = (APR_OS_START_USERERR + 3);
+    public static final int EINPROGRESS       = (APR_OS_START_USERERR + 4);
+    public static final int ETIMEDOUT         = (APR_OS_START_USERERR + 5);
+
+    private static native boolean is(int err, int idx);
+    /**
+     * APR_STATUS_IS Status Value Tests
+     * <br /><b>Warning :</b> For any particular error condition, more than one of these tests
+     *      may match. This is because platform-specific error codes may not
+     *      always match the semantics of the POSIX codes these tests (and the
+     *      corresponding APR error codes) are named after. A notable example
+     *      are the APR_STATUS_IS_ENOENT and APR_STATUS_IS_ENOTDIR tests on
+     *      Win32 platforms. The programmer should always be aware of this and
+     *      adjust the order of the tests accordingly.
+     *
+     */
+    public static final boolean APR_STATUS_IS_ENOSTAT(int s)    { return is(s, 1); }
+    public static final boolean APR_STATUS_IS_ENOPOOL(int s)    { return is(s, 2); }
+    /* empty slot: +3 */
+    public static final boolean APR_STATUS_IS_EBADDATE(int s)   { return is(s, 4); }
+    public static final boolean APR_STATUS_IS_EINVALSOCK(int s) { return is(s, 5); }
+    public static final boolean APR_STATUS_IS_ENOPROC(int s)    { return is(s, 6); }
+    public static final boolean APR_STATUS_IS_ENOTIME(int s)    { return is(s, 7); }
+    public static final boolean APR_STATUS_IS_ENODIR(int s)     { return is(s, 8); }
+    public static final boolean APR_STATUS_IS_ENOLOCK(int s)    { return is(s, 9); }
+    public static final boolean APR_STATUS_IS_ENOPOLL(int s)    { return is(s, 10); }
+    public static final boolean APR_STATUS_IS_ENOSOCKET(int s)  { return is(s, 11); }
+    public static final boolean APR_STATUS_IS_ENOTHREAD(int s)  { return is(s, 12); }
+    public static final boolean APR_STATUS_IS_ENOTHDKEY(int s)  { return is(s, 13); }
+    public static final boolean APR_STATUS_IS_EGENERAL(int s)   { return is(s, 14); }
+    public static final boolean APR_STATUS_IS_ENOSHMAVAIL(int s){ return is(s, 15); }
+    public static final boolean APR_STATUS_IS_EBADIP(int s)     { return is(s, 16); }
+    public static final boolean APR_STATUS_IS_EBADMASK(int s)   { return is(s, 17); }
+    /* empty slot: +18 */
+    public static final boolean APR_STATUS_IS_EDSOPEN(int s)    { return is(s, 19); }
+    public static final boolean APR_STATUS_IS_EABSOLUTE(int s)  { return is(s, 20); }
+    public static final boolean APR_STATUS_IS_ERELATIVE(int s)  { return is(s, 21); }
+    public static final boolean APR_STATUS_IS_EINCOMPLETE(int s){ return is(s, 22); }
+    public static final boolean APR_STATUS_IS_EABOVEROOT(int s) { return is(s, 23); }
+    public static final boolean APR_STATUS_IS_EBADPATH(int s)   { return is(s, 24); }
+    public static final boolean APR_STATUS_IS_EPATHWILD(int s)  { return is(s, 25); }
+    public static final boolean APR_STATUS_IS_ESYMNOTFOUND(int s)      { return is(s, 26); }
+    public static final boolean APR_STATUS_IS_EPROC_UNKNOWN(int s)     { return is(s, 27); }
+    public static final boolean APR_STATUS_IS_ENOTENOUGHENTROPY(int s) { return is(s, 28); }
+
+    /*
+     * APR_Error
+     */
+    public static final boolean APR_STATUS_IS_INCHILD(int s)    { return is(s, 51); }
+    public static final boolean APR_STATUS_IS_INPARENT(int s)   { return is(s, 52); }
+    public static final boolean APR_STATUS_IS_DETACH(int s)     { return is(s, 53); }
+    public static final boolean APR_STATUS_IS_NOTDETACH(int s)  { return is(s, 54); }
+    public static final boolean APR_STATUS_IS_CHILD_DONE(int s) { return is(s, 55); }
+    public static final boolean APR_STATUS_IS_CHILD_NOTDONE(int s)  { return is(s, 56); }
+    public static final boolean APR_STATUS_IS_TIMEUP(int s)     { return is(s, 57); }
+    public static final boolean APR_STATUS_IS_INCOMPLETE(int s) { return is(s, 58); }
+    /* empty slot: +9 */
+    /* empty slot: +10 */
+    /* empty slot: +11 */
+    public static final boolean APR_STATUS_IS_BADCH(int s)      { return is(s, 62); }
+    public static final boolean APR_STATUS_IS_BADARG(int s)     { return is(s, 63); }
+    public static final boolean APR_STATUS_IS_EOF(int s)        { return is(s, 64); }
+    public static final boolean APR_STATUS_IS_NOTFOUND(int s)   { return is(s, 65); }
+    /* empty slot: +16 */
+    /* empty slot: +17 */
+    /* empty slot: +18 */
+    public static final boolean APR_STATUS_IS_ANONYMOUS(int s)  { return is(s, 69); }
+    public static final boolean APR_STATUS_IS_FILEBASED(int s)  { return is(s, 70); }
+    public static final boolean APR_STATUS_IS_KEYBASED(int s)   { return is(s, 71); }
+    public static final boolean APR_STATUS_IS_EINIT(int s)      { return is(s, 72); }
+    public static final boolean APR_STATUS_IS_ENOTIMPL(int s)   { return is(s, 73); }
+    public static final boolean APR_STATUS_IS_EMISMATCH(int s)  { return is(s, 74); }
+    public static final boolean APR_STATUS_IS_EBUSY(int s)      { return is(s, 75); }
+
+    /* Socket errors */
+    public static final boolean APR_STATUS_IS_EAGAIN(int s)     { return is(s, 90); }
+    public static final boolean APR_STATUS_IS_ETIMEDOUT(int s)  { return is(s, 91); }
+    public static final boolean APR_STATUS_IS_ECONNABORTED(int s) { return is(s, 92); }
+    public static final boolean APR_STATUS_IS_ECONNRESET(int s)   { return is(s, 93); }
+    public static final boolean APR_STATUS_IS_EINPROGRESS(int s)  { return is(s, 94); }
+    public static final boolean APR_STATUS_IS_EINTR(int s)      { return is(s, 95); }
+    public static final boolean APR_STATUS_IS_ENOTSOCK(int s)   { return is(s, 96); }
+    public static final boolean APR_STATUS_IS_EINVAL(int s)     { return is(s, 97); }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jni/java/org/apache/tomcat/jni/Stdlib.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jni/java/org/apache/tomcat/jni/Stdlib.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jni/java/org/apache/tomcat/jni/Stdlib.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,89 @@
+/*
+ *  Copyright 2000-2005 The Apache Software Foundation
+ *
+ *  Licensed 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.jni;
+
+/** Stdlib
+ *
+ * @author Mladen Turk
+ * @version $Revision: 300969 $, $Date: 2005-07-12 09:56:11 -0500 (Tue, 12 Jul 2005) $
+ */
+
+public class Stdlib {
+
+    /**
+     * Read from plain memory
+     * @param dst Destination byte array
+     * @param src Source memory address
+     * @param sz Number of bytes to copy.
+     */
+    public static native boolean memread(byte [] dst, long src, int sz);
+
+    /**
+     * Write to plain memory
+     * @param dst Destination memory address
+     * @param src Source byte array
+     * @param sz Number of bytes to copy.
+     */
+    public static native boolean memwrite(long dst, byte [] src, int sz);
+
+    /**
+     * Sets buffers to a specified character
+     * @param dst Destination memory address
+     * @param c Character to set.
+     * @param sz Number of characters.
+     */
+    public static native boolean memset(long dst, int c, int sz);
+
+    /**
+     * Allocates memory blocks.
+     * @param sz Bytes to allocate.
+     */
+    public static native long malloc(int sz);
+
+    /**
+     * Reallocate memory blocks.
+     * @param mem Pointer to previously allocated memory block.
+     * @param sz New size in bytes.
+     */
+    public static native long realloc(long mem, int sz);
+
+    /**
+     * Allocates an array in memory with elements initialized to 0.
+     * @param num Number of elements.
+     * @param sz Length in bytes of each element.
+     */
+    public static native long calloc(long num, int sz);
+
+    /**
+     * Deallocates or frees a memory block.
+     * @param mem Previously allocated memory block to be freed.
+     */
+    public static native void free(long mem);
+
+    /**
+     * Get current process pid.
+     * @return current pid or < 1 in case of error.
+     */
+    public static native int getpid();
+
+    /**
+     * Get current process parent pid.
+     * @return parent pid or < 1 in case of error.
+     */
+    public static native int getppid();
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jni/java/org/apache/tomcat/jni/Thread.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jni/java/org/apache/tomcat/jni/Thread.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jni/java/org/apache/tomcat/jni/Thread.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,32 @@
+/*
+ *  Copyright 2000-2005 The Apache Software Foundation
+ *
+ *  Licensed 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.jni;
+
+/** Thread
+ *
+ * @author Mladen Turk
+ * @version $Revision: 300969 $, $Date: 2005-07-12 16:56:11 +0200 (uto, 12 srp 2005) $
+ */
+
+public class Thread {
+    
+    /**
+     * Get the current thread ID handle.
+     */
+    public static native long current();    
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jni/java/org/apache/tomcat/jni/Time.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jni/java/org/apache/tomcat/jni/Time.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jni/java/org/apache/tomcat/jni/Time.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,73 @@
+/*
+ *  Copyright 2000-2005 The Apache Software Foundation
+ *
+ *  Licensed 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.jni;
+
+/** Time
+ *
+ * @author Mladen Turk
+ * @version $Revision: 300969 $, $Date: 2005-07-12 09:56:11 -0500 (Tue, 12 Jul 2005) $
+ */
+
+public class Time {
+
+    /** number of microseconds per second */
+    public static final long APR_USEC_PER_SEC  = 1000000L;
+    /** number of miliseconds per microsecond */
+    public static final long APR_MSEC_PER_USEC = 1000L;
+
+    /** @return apr_time_t as a second */
+    public static long sec(long t)
+    {
+        return t / APR_USEC_PER_SEC;
+    }
+
+    /** @return apr_time_t as a msec */
+    public static long msec(long t)
+    {
+        return t / APR_MSEC_PER_USEC;
+    }
+
+    /**
+     * number of microseconds since 00:00:00 january 1, 1970 UTC
+     * @return the current time
+     */
+    public static native long now();
+
+    /**
+     * Formats dates in the RFC822
+     * format in an efficient manner.
+     * @param t the time to convert
+     */
+    public static native String rfc822(long t);
+
+    /**
+     * Formats dates in the ctime() format
+     * in an efficient manner.
+     * Unlike ANSI/ISO C ctime(), apr_ctime() does not include
+     * a \n at the end of the string.
+     * @param t the time to convert
+     */
+    public static native String ctime(long t);
+
+    /**
+     * Sleep for the specified number of micro-seconds.
+     * <br /><b>Warning :</b> May sleep for longer than the specified time.
+     * @param t desired amount of time to sleep.
+     */
+    public static native void sleep(long t);
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jni/java/org/apache/tomcat/jni/User.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jni/java/org/apache/tomcat/jni/User.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jni/java/org/apache/tomcat/jni/User.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,126 @@
+/*
+ *  Copyright 2000-2005 The Apache Software Foundation
+ *
+ *  Licensed 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.jni;
+
+/** User
+ *
+ * @author Mladen Turk
+ * @version $Revision: 300969 $, $Date: 2005-07-12 09:56:11 -0500 (Tue, 12 Jul 2005) $
+ */
+
+public class User {
+
+    /**
+     * Get the userid (and groupid) of the calling process
+     * This function is available only if APR_HAS_USER is defined.
+     * @param p The pool from which to allocate working space
+     * @return Returns the user id
+     */
+     public static native long uidCurrent(long p)
+        throws Error;
+
+    /**
+     * Get the groupid of the calling process
+     * This function is available only if APR_HAS_USER is defined.
+     * @param p The pool from which to allocate working space
+     * @return Returns the group id
+     */
+     public static native long gidCurrent(long p)
+        throws Error;
+
+
+    /**
+     * Get the userid for the specified username
+     * This function is available only if APR_HAS_USER is defined.
+     * @param username The username to lookup
+     * @param p The pool from which to allocate working space
+     * @return Returns the user id
+     */
+     public static native long uid(String username, long p)
+        throws Error;
+
+    /**
+     * Get the groupid for the specified username
+     * This function is available only if APR_HAS_USER is defined.
+     * @param username The username to lookup
+     * @param p The pool from which to allocate working space
+     * @return  Returns the user's group id
+     */
+     public static native long usergid(String username, long p)
+        throws Error;
+
+    /**
+     * Get the groupid for a specified group name
+     * This function is available only if APR_HAS_USER is defined.
+     * @param groupname The group name to look up
+     * @param p The pool from which to allocate working space
+     * @return  Returns the user's group id
+     */
+     public static native long gid(String groupname, long p)
+        throws Error;
+
+    /**
+     * Get the user name for a specified userid
+     * This function is available only if APR_HAS_USER is defined.
+     * @param userid The userid
+     * @param p The pool from which to allocate the string
+     * @return New string containing user name
+     */
+     public static native String username(long userid, long p)
+        throws Error;
+
+    /**
+     * Get the group name for a specified groupid
+     * This function is available only if APR_HAS_USER is defined.
+     * @param groupid The groupid
+     * @param p The pool from which to allocate the string
+     * @return New string containing group name
+     */
+     public static native String groupname(long groupid, long p)
+        throws Error;
+
+    /**
+     * Compare two user identifiers for equality.
+     * This function is available only if APR_HAS_USER is defined.
+     * @param left One uid to test
+     * @param right Another uid to test
+     * @return APR_SUCCESS if the apr_uid_t strutures identify the same user,
+     * APR_EMISMATCH if not, APR_BADARG if an apr_uid_t is invalid.
+     */
+     public static native int uidcompare(long left, long right);
+
+    /**
+     * Compare two group identifiers for equality.
+     * This function is available only if APR_HAS_USER is defined.
+     * @param left One gid to test
+     * @param right Another gid to test
+     * @return APR_SUCCESS if the apr_gid_t strutures identify the same group,
+     * APR_EMISMATCH if not, APR_BADARG if an apr_gid_t is invalid.
+     */
+     public static native int gidcompare(long left, long right);
+
+    /**
+     * Get the home directory for the named user
+     * This function is available only if APR_HAS_USER is defined.
+     * @param username The named user
+     * @param p The pool from which to allocate the string
+     * @return New string containing directory name
+     */
+     public static native String homepath(String username, long p)
+        throws Error;
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jni/java/overview.html
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jni/java/overview.html	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jni/java/overview.html	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,29 @@
+<!--
+
+ Copyright 2001-2004 The Apache Software Foundation.
+
+ Licensed 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.
+
+-->
+
+<html>
+<head>
+<title>Overview Documentation for Tomcat Native</title>
+</head>
+<body bgcolor="white">
+<p>The <em>Tomcat Native Library</em> component of the Jakarta Tomcat
+Connectors project offers JNI wrappers around APR and various other
+system libraries.</p>
+
+</body>
+</html>

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jni/jnirelease.sh
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jni/jnirelease.sh	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jni/jnirelease.sh	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,45 @@
+#/bin/sh
+#
+# Copyright 1999-2005 The Apache Software Foundation
+#
+# Licensed 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.
+#
+# APRDIR have to be the location of the APR sources
+APRDIR=$HOME/apr
+#
+# Replace JKJNIEXT with branche/or tag
+#  and JKJNIVER by the version like -1.1.0
+JKJNIEXT="trunk"
+JKJNIVER="-dev"
+SVNBASE=https://svn.apache.org/repos/asf/tomcat/connectors/
+JKJNIDIST=tomcat-connectors${JKJNIVER}
+rm -rf ${JKJNIDIST}
+mkdir -p ${JKJNIDIST}/jni
+svn export $SVNBASE/${JKJNIEXT}/jni/native ${JKJNIDIST}/jni/native
+svn cat $SVNBASE/${JKJNIEXT}/KEYS > ${JKJNIDIST}/KEYS
+svn cat $SVNBASE/${JKJNIEXT}/LICENSE > ${JKJNIDIST}/LICENSE
+svn cat $SVNBASE/${JKJNIEXT}/NOTICE > ${JKJNIDIST}/NOTICE
+svn cat $SVNBASE/${JKJNIEXT}/jni/NOTICE.txt > ${JKJNIDIST}/NOTICE.txt
+svn cat $SVNBASE/${JKJNIEXT}/jni/README.txt > ${JKJNIDIST}/README.txt
+
+# Prebuild
+cd ${JKJNIDIST}/jni/native
+# Adjust the location of APR sources
+./buildconf --with-apr=$APRDIR
+cd ../../../
+# Create distribution
+tar cvf ${JKJNIDIST}.tar ${JKJNIDIST}
+gzip ${JKJNIDIST}.tar
+# Convert lineends to DOS
+perl $APRDIR/build/lineends.pl --cr ${JKJNIDIST}
+zip -9 -r  ${JKJNIDIST}.zip ${JKJNIDIST}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/BUILDING
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/BUILDING	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/BUILDING	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,30 @@
+  Building from the cvs tree:
+  sh buildconf --with-apr=apr_source_location.
+  configure --with-apr=apr_install_location --with-ssl=openssl_install_location
+  make
+
+  Testing the build:
+  The make should produce a .so file named libtcnative-1.so.
+  Build the jar containing the example by
+  cd ..
+  ant jar
+  Run the example:
+  ant example-basic
+ 
+  Using it in Tomcat:
+  1 - In <Connector> use of conf/server.xml:
+    protocol="org.apache.coyote.http11.Http11AprProtocol"
+  2 - In bin/setenv.sh add the following: 
+    CATALINA_OPTS="$CATALINA_OPTS -Djava.library.path=tclib_location"
+    In my machine I am using:
+    /home/jfclere/tomcat-connectors/jni/native/.libs for tclib_location
+
+NOTES:
+  - configure --without-ssl : Configure without ssl support.
+  - To use it in Tomcat you may have to add in bin/setenv.sh:
+    LD_LIBRARY_PATH=openssl_install_location/lib; export LD_LIBRARY_PATH
+    (use ldd ./.libs/libtcnative-1.so to check it).
+  - quick testing: openssl s_client -connect localhost:8443
+  - For MAC OS X you must manually add a link
+    cd ${tcnative installdir}
+    ln -d libtcnative-1.dylib libtcnative-1.jnilib

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/Makefile.in
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/Makefile.in	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/Makefile.in	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,65 @@
+#
+# Top-level Makefile for TCNATIVE
+#
+
+CFLAGS = @CFLAGS@
+CPPFLAGS = @CPPFLAGS@
+
+# gets substituted into some targets
+TCNATIVE_MAJOR_VERSION=@TCNATIVE_MAJOR_VERSION@
+TCNATIVE_DOTTED_VERSION=@TCNATIVE_DOTTED_VERSION@
+TCNATIVE_LIBTOOL_VERSION=@TCNATIVE_LIBTOOL_VERSION@
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+
+# this sucks, but it's the only way to add extra flags to the LT_COMPILE
+INCLUDES = @CFLAGS@ @CPPFLAGS@ @TCNATIVE_INCLUDES@ @TCNATIVE_PRIV_INCLUDES@ @APR_INCLUDES@
+TCNATIVE_LDFLAGS = @TCNATIVE_LDFLAGS@
+TCNATIVE_LIBS = @TCNATIVE_LIBS@
+
+TARGET_LIB = lib at TCNATIVE_LIBNAME@.la
+EXTRA_OS_LINK=@EXTRA_OS_LINK@
+TCNATIVE_PCFILE = tcnative-$(TCNATIVE_MAJOR_VERSION).pc
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+
+TARGETS = $(TARGET_LIB)
+
+# bring in rules.mk for standard functionality
+ at INCLUDE_RULES@
+ at INCLUDE_OUTPUTS@
+
+LINK          = $(LIBTOOL) $(LTFLAGS) --mode=link $(LT_LDFLAGS) $(COMPILE) -version-info $(TCNATIVE_LIBTOOL_VERSION) $(ALL_LDFLAGS) -o $@
+CLEAN_SUBDIRS = test
+
+CLEAN_TARGETS = .make.dirs
+DISTCLEAN_TARGETS = config.cache config.log config.status libtool \
+	build/rules.mk tcnative.pc
+EXTRACLEAN_TARGETS = configure aclocal.m4 build-outputs.mk \
+	build/apr_common.m4 build/find_apr.m4 build/install.sh \
+	build/config.guess build/config.sub tcnative.spec
+
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+bindir=@bindir@
+libdir=@libdir@
+includedir=@includedir@
+top_srcdir=@abs_srcdir@
+top_blddir=@abs_builddir@
+
+
+install: $(TARGET_LIB)
+	$(APR_MKDIR) $(DESTDIR)$(includedir) $(DESTDIR)$(libdir)/pkgconfig \
+		     $(DESTDIR)$(libdir) $(DESTDIR)$(bindir)
+	$(INSTALL_DATA) tcnative.pc $(DESTDIR)$(libdir)/pkgconfig/$(TCNATIVE_PCFILE)
+	list='$(INSTALL_SUBDIRS)'; for i in $$list; do \
+		( cd $$i ; $(MAKE) DESTDIR=$(DESTDIR) install ); \
+	done
+	$(LIBTOOL) --mode=install $(INSTALL) -m 755 $(TARGET_LIB) $(DESTDIR)$(libdir)
+
+$(TARGET_LIB): $(OBJECTS)
+	$(LINK) @lib_target@ @TCNATIVE_LDFLAGS@ @TCNATIVE_LIBS@ @SSL_LIBS@
+
+check: $(TARGET_LIB)
+	(cd test && $(MAKE) check)

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/build/buildcheck.sh
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/build/buildcheck.sh	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/build/buildcheck.sh	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,72 @@
+#! /bin/sh
+
+echo "buildconf: checking installation..."
+
+# any python
+python=`build/PrintPath python`
+if test -z "$python"; then
+echo "buildconf: python not found."
+echo "           You need python installed"
+echo "           to build APR from CVS."
+exit 1
+else
+py_version=`python -c 'import sys; print sys.version' 2>&1|sed 's/ .*//;q'`
+echo "buildconf: python version $py_version (ok)"
+fi
+
+# autoconf 2.13 or newer
+ac_version=`${AUTOCONF:-autoconf} --version 2>/dev/null|sed -e 's/^[^0-9]*//;s/[a-z]* *$//;q'`
+if test -z "$ac_version"; then
+echo "buildconf: autoconf not found."
+echo "           You need autoconf version 2.13 or newer installed"
+echo "           to build Apache from CVS."
+exit 1
+fi
+IFS=.; set $ac_version; IFS=' '
+if test "$1" = "2" -a "$2" -lt "13" || test "$1" -lt "2"; then
+echo "buildconf: autoconf version $ac_version found."
+echo "           You need autoconf version 2.13 or newer installed"
+echo "           to build Apache from CVS."
+exit 1
+else
+echo "buildconf: autoconf version $ac_version (ok)"
+fi
+
+# Sample libtool --version outputs:
+# ltmain.sh (GNU libtool) 1.3.3 (1.385.2.181 1999/07/02 15:49:11)
+# ltmain.sh (GNU libtool 1.1361 2004/01/02 23:10:52) 1.5a
+# output is multiline from 1.5 onwards
+
+# Require libtool 1.3.3 or newer
+libtool=`build/PrintPath glibtool libtool libtool15 libtool14`
+lt_pversion=`$libtool --version 2>/dev/null|sed -e 's/([^)]*)//g;s/^[^0-9]*//;s/[- ].*//g;q'`
+if test -z "$lt_pversion"; then
+echo "buildconf: libtool not found."
+echo "           You need libtool version 1.3.3 or newer installed"
+echo "           to build Apache from CVS."
+exit 1
+fi
+lt_version=`echo $lt_pversion|sed -e 's/\([a-z]*\)$/.\1/'`
+IFS=.; set $lt_version; IFS=' '
+lt_status="good"
+if test "$1" = "1"; then
+   if test "$2" -lt "3"; then
+      lt_status="bad"
+   else
+      if test "$2" = "3"; then
+         if test -z "$3" -o "$3" = "1" -o "$3" = "2"; then
+            lt_status="bad"
+         fi
+      fi
+   fi
+fi
+if test $lt_status = "good"; then
+   echo "buildconf: libtool version $lt_pversion (ok)"
+   exit 0
+fi
+
+echo "buildconf: libtool version $lt_pversion found."
+echo "           You need libtool version 1.3.3 or newer installed"
+echo "           to build Apache from CVS."
+
+exit 1

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/build/get-version.sh
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/build/get-version.sh	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/build/get-version.sh	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,37 @@
+#!/bin/sh
+#
+# extract version numbers from a header file
+#
+# USAGE: get-version.sh CMD VERSION_HEADER PREFIX
+#   where CMD is one of: all, major, libtool
+#   where PREFIX is the prefix to {MAJOR|MINOR|PATCH}_VERSION defines
+#
+#   get-version.sh all returns a dotted version number
+#   get-version.sh major returns just the major version number
+#   get-version.sh libtool returns a version "libtool -version-info" format
+#
+
+if test $# != 3; then
+  echo "USAGE: $0 CMD VERSION_HEADER PREFIX"
+  echo "  where CMD is one of: all, major, libtool"
+  exit 1
+fi
+
+major_sed="/#define.*$3_MAJOR_VERSION/s/^[^0-9]*\([0-9]*\).*$/\1/p"
+minor_sed="/#define.*$3_MINOR_VERSION/s/^[^0-9]*\([0-9]*\).*$/\1/p"
+patch_sed="/#define.*$3_PATCH_VERSION/s/^[^0-9]*\([0-9]*\).*$/\1/p"
+major="`sed -n $major_sed $2`"
+minor="`sed -n $minor_sed $2`"
+patch="`sed -n $patch_sed $2`"
+
+if test "$1" = "all"; then
+  echo ${major}.${minor}.${patch}
+elif test "$1" = "major"; then
+  echo ${major}
+elif test "$1" = "libtool"; then
+  # Yes, ${minor}:${patch}:${minor} is correct due to libtool idiocy.
+  echo ${minor}:${patch}:${minor}
+else
+  echo "ERROR: unknown version CMD ($1)"
+  exit 1
+fi

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/build/lineends.pl
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/build/lineends.pl	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/build/lineends.pl	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,149 @@
+#!/usr/local/bin/perl
+#
+#  Heuristically converts line endings to the current OS's preferred format
+#  
+#  All existing line endings must be identical (e.g. lf's only, or even
+#  the accedental cr.cr.lf sequence.)  If some lines end lf, and others as
+#  cr.lf, the file is presumed binary.  If the cr character appears anywhere
+#  except prefixed to an lf, the file is presumed binary.  If there is no 
+#  change in the resulting file size, or the file is binary, the conversion 
+#  is discarded.
+#  
+#  Todo: Handle NULL stdin characters gracefully.
+#
+
+use IO::File;
+use File::Find;
+
+# The ignore list is '-' seperated, with this leading hyphen and
+# trailing hyphens in ever concatinated list below.
+$ignore = "-";
+
+# Image formats
+$ignore .= "gif-jpg-jpeg-png-ico-bmp-";
+
+# Archive formats
+$ignore .= "tar-gz-z-zip-jar-war-";
+
+# Many document formats
+$ignore .= "eps-psd-pdf-ai-";
+
+# Some encodings
+$ignore .= "ucs2-ucs4-";
+
+# Some binary objects
+$ignore .= "class-so-dll-exe-obj-";
+
+# Some build env files in NW/Win32
+$ignore .= "mcp-xdc-ncb-opt-pdb-ilk-sbr-";
+
+$preservedate = 1;
+
+$forceending = 0;
+
+$givenpaths = 0;
+
+$notnative = 0;
+
+while (defined @ARGV[0]) {
+    if (@ARGV[0] eq '--touch') {
+        $preservedate = 0;
+    }
+    elsif (@ARGV[0] eq '--nocr') {
+        $notnative = -1;
+    }
+    elsif (@ARGV[0] eq '--cr') {
+        $notnative = 1;
+    }
+    elsif (@ARGV[0] eq '--force') {
+        $forceending = 1;
+    }
+    elsif (@ARGV[0] eq '--FORCE') {
+        $forceending = 2;
+    }
+    elsif (@ARGV[0] =~ m/^-/) {
+        die "What is " . @ARGV[0] . " supposed to mean?\n\n" 
+	  . "Syntax:\t$0 [option()s] [path(s)]\n\n" . <<'OUTCH'
+Where:	paths specifies the top level directory to convert (default of '.')
+	options are;
+
+	  --cr     keep/add one ^M
+	  --nocr   remove ^M's
+	  --touch  the datestamp (default: keeps date/attribs)
+	  --force  mismatched corrections (unbalanced ^M's)
+	  --FORCE  all files regardless of file name!
+
+OUTCH
+    }
+    else {
+        find(\&totxt, @ARGV[0]);
+	print "scanned " . @ARGV[0] . "\n";
+	$givenpaths = 1;
+    }
+    shift @ARGV;
+}
+
+if (!$givenpaths) {
+    find(\&totxt, '.');
+    print "did .\n";
+}
+
+sub totxt {
+        $oname = $_;
+	$tname = '.#' . $_;
+        if (!-f) {
+            return;
+        }
+	@exts = split /\./;
+	if ($forceending < 2) {
+            while ($#exts && ($ext = pop(@exts))) {
+                if ($ignore =~ m|-$ext-|i) {
+                    return;
+                }
+	    }
+        }
+	@ostat = stat($oname);
+        $srcfl = new IO::File $oname, "r" or die;
+	$dstfl = new IO::File $tname, "w" or die;
+        binmode $srcfl; 
+	if ($notnative) {
+            binmode $dstfl;
+	} 
+	undef $t;
+        while (<$srcfl>) { 
+            if (s/(\r*)\n$/\n/) {
+		$n = length $1;
+		if (!defined $t) { 
+		    $t = $n; 
+		}
+		if (!$forceending && (($n != $t) || m/\r/)) {
+		    print "mismatch in " .$oname. ":" .$n. " expected " .$t. "\n";
+		    undef $t;
+		    last;
+		}
+	        elsif ($notnative > 0) {
+                    s/\n$/\r\n/; 
+                }
+            }
+	    print $dstfl $_; 
+	}
+	if (defined $t && (tell $srcfl == tell $dstfl)) {
+	    undef $t;
+	}
+	undef $srcfl;
+	undef $dstfl;
+	if (defined $t) {
+            unlink $oname or die;
+            rename $tname, $oname or die;
+            @anames = ($oname);
+            if ($preservedate) {
+                utime $ostat[9], $ostat[9], @anames;
+            }
+            chmod $ostat[2] & 07777, @anames;
+            chown $ostat[5], $ostat[6], @anames;
+            print "Converted file " . $oname . " to text in " . $File::Find::dir . "\n"; 
+	}
+	else {
+	    unlink $tname or die;
+	}
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/build/mkdir.sh
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/build/mkdir.sh	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/build/mkdir.sh	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,37 @@
+#!/bin/sh
+## 
+##  mkdir.sh -- make directory hierarchy
+##
+##  Based on `mkinstalldirs' from Noah Friedman <friedman at prep.ai.mit.edu>
+##  as of 1994-03-25, which was placed in the Public Domain.
+##  Cleaned up for Apache's Autoconf-style Interface (APACI)
+##  by Ralf S. Engelschall <rse at apache.org>
+##
+#
+# This script falls under the Apache License.
+# See http://www.apache.org/docs/LICENSE
+
+
+umask 022
+errstatus=0
+for file in ${1+"$@"} ; do 
+    set fnord `echo ":$file" |\
+               sed -e 's/^:\//%/' -e 's/^://' -e 's/\// /g' -e 's/^%/\//'`
+    shift
+    pathcomp=
+    for d in ${1+"$@"}; do
+        pathcomp="$pathcomp$d"
+        case "$pathcomp" in
+            -* ) pathcomp=./$pathcomp ;;
+            ?: ) pathcomp="$pathcomp/" 
+                 continue ;;
+        esac
+        if test ! -d "$pathcomp"; then
+            echo "mkdir $pathcomp" 1>&2
+            mkdir "$pathcomp" || errstatus=$?
+        fi
+        pathcomp="$pathcomp/"
+    done
+done
+exit $errstatus
+

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/build/rpm/tcnative.spec.in
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/build/rpm/tcnative.spec.in	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/build/rpm/tcnative.spec.in	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,78 @@
+
+%define tcnver 1
+
+Summary: Tomcat Native Java library
+Name: tcnative
+Version: TCN_VERSION
+Release: TCN_RELEASE
+License: Apache Software License
+Group: System Environment/Libraries
+URL: http://apr.apache.org/
+Source0: %{name}-%{version}.tar.gz
+BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-buildroot
+BuildPrereq: autoconf, libtool, doxygen, apr-devel >= 0:{version}-{release}, openssl >= 0.9.7
+
+%description
+The mission of the Tomcat Native Library (TCN) is to provide a
+free library of C data structures and routines.  This library
+contains additional utility interfaces for Java.
+
+%package devel
+Group: Development/Libraries
+Summary: Tomcat Native development kit
+Requires: tcnative = %{version}-%{release}, apr-devel >= 0:{version}-{release}, openssl-devel >= 0.9.7
+
+%description devel
+The mission of the Tomcat Native Library (TCN) is to provide a
+free library of C data structures and routines.  This library
+contains additional utility interfaces for Java.
+
+%prep
+%setup -q
+
+%build
+%configure --with-apr=%{_prefix} \
+        --includedir=%{_includedir}/apr-%{tcnver}
+make %{?_smp_mflags} && make dox
+
+%check
+# Run non-interactive tests
+pushd test
+make %{?_smp_mflags} testall CFLAGS=-fno-strict-aliasing
+./testall -v || exit 1
+popd
+
+%install
+rm -rf $RPM_BUILD_ROOT
+make install DESTDIR=$RPM_BUILD_ROOT
+
+# Documentation
+mv docs/dox/html html
+
+# Unpackaged files
+rm -f $RPM_BUILD_ROOT%{_libdir}/tcnative.exp
+
+%clean
+rm -rf $RPM_BUILD_ROOT
+
+%post -p /sbin/ldconfig
+
+%postun -p /sbin/ldconfig
+
+%files
+%defattr(-,root,root,-)
+%doc CHANGES LICENSE NOTICE
+%{_libdir}/libtcnative-%{tcnver}.so.*
+
+%files devel
+%defattr(-,root,root,-)
+%{_libdir}/libtcnative-%{tcnver}.*a
+%{_libdir}/libtcnative-%{tcnver}.so
+%{_libdir}/pkgconfig/tcnative-%{tcnver}.pc
+%{_includedir}/apr-%{tcnver}/*.h
+%doc --parents html
+
+%changelog
+* Tue Jun 22 2004 Mladen Turk <mturk at jboss.com> 1.0.0-1
+- update to support v1.0.2 of APR
+                                                                                

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/build/tcnative.m4
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/build/tcnative.m4	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/build/tcnative.m4	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,343 @@
+dnl
+dnl TCN_FIND_APR: figure out where APR is located
+dnl
+AC_DEFUN(TCN_FIND_APR,[
+
+  dnl use the find_apr.m4 script to locate APR. sets apr_found and apr_config
+  APR_FIND_APR(,,,[1])
+  if test "$apr_found" = "no"; then
+    AC_MSG_ERROR(APR could not be located. Please use the --with-apr option.)
+  fi
+
+  APR_BUILD_DIR="`$apr_config --installbuilddir`"
+
+  dnl make APR_BUILD_DIR an absolute directory (we'll need it in the
+  dnl sub-projects in some cases)
+  APR_BUILD_DIR="`cd $APR_BUILD_DIR && pwd`"
+
+  APR_INCLUDES="`$apr_config --includes`"
+  APR_LIBS="`$apr_config --link-libtool --libs`"
+  APR_SO_EXT="`$apr_config --apr-so-ext`"
+  APR_LIB_TARGET="`$apr_config --apr-lib-target`"
+
+  AC_SUBST(APR_INCLUDES)
+  AC_SUBST(APR_LIBS)
+  AC_SUBST(APR_BUILD_DIR)
+])
+
+dnl --------------------------------------------------------------------------
+dnl TCN_JDK
+dnl
+dnl Detection of JDK location and Java Platform (1.2, 1.3, 1.4, 1.5, 1.6)
+dnl result goes in JAVA_HOME / JAVA_PLATFORM (2 -> 1.2 and higher)
+dnl 
+dnl --------------------------------------------------------------------------
+AC_DEFUN(
+  [TCN_FIND_JDK],
+  [
+    tempval=""
+    AC_MSG_CHECKING([for JDK location (please wait)])
+    if test -n "${JAVA_HOME}" ; then
+      JAVA_HOME_ENV="${JAVA_HOME}"
+    else
+      JAVA_HOME_ENV=""
+    fi
+
+    JAVA_HOME=""
+    JAVA_PLATFORM=""
+
+    AC_ARG_WITH(
+      [java-home],
+      [  --with-java-home=DIR     Location of JDK directory.],
+      [
+
+      # This stuff works if the command line parameter --with-java-home was
+      # specified, so it takes priority rightfully.
+  
+      tempval=${withval}
+
+      if test ! -d "${tempval}" ; then
+          AC_MSG_ERROR(Not a directory: ${tempval})
+      fi
+  
+      JAVA_HOME=${tempval}
+      AC_MSG_RESULT(${JAVA_HOME})
+    ],
+    [
+      # This works if the parameter was NOT specified, so it's a good time
+      # to see what the enviroment says.
+      # Since Sun uses JAVA_HOME a lot, we check it first and ignore the
+      # JAVA_HOME, otherwise just use whatever JAVA_HOME was specified.
+
+      if test -n "${JAVA_HOME_ENV}" ; then
+        JAVA_HOME=${JAVA_HOME_ENV}
+        AC_MSG_RESULT(${JAVA_HOME_ENV} from environment)
+      fi
+    ])
+
+    if test -z "${JAVA_HOME}" ; then
+
+      # Oh well, nobody set neither JAVA_HOME nor JAVA_HOME, have to guess
+      # The following code is based on the code submitted by Henner Zeller
+      # for ${srcdir}/src/scripts/package/rpm/ApacheJServ.spec
+      # Two variables will be set as a result:
+      #
+      # JAVA_HOME
+      # JAVA_PLATFORM
+      AC_MSG_CHECKING([Try to guess JDK location])
+
+      for JAVA_PREFIX in /usr/local /usr/local/lib /usr /usr/lib /opt /usr/java ; do
+
+        for JAVA_PLATFORM in 6 5 4 3 2 ; do
+
+          for subversion in .9 .8 .7 .6 .5 .4 .3 .2 .1 "" ; do
+
+            for VARIANT in IBMJava2- java java- jdk jdk-; do
+              GUESS="${JAVA_PREFIX}/${VARIANT}1.${JAVA_PLATFORM}${subversion}"
+dnl           AC_MSG_CHECKING([${GUESS}])
+              if test -d "${GUESS}/bin" & test -d "${GUESS}/include" ; then
+                JAVA_HOME="${GUESS}"
+                AC_MSG_RESULT([${GUESS}])
+                break
+              fi
+            done
+
+            if test -n "${JAVA_HOME}" ; then
+              break;
+            fi
+
+          done
+
+          if test -n "${JAVA_HOME}" ; then
+            break;
+          fi
+
+        done
+
+        if test -n "${JAVA_HOME}" ; then
+          break;
+        fi
+
+      done
+
+      if test ! -n "${JAVA_HOME}" ; then
+        AC_MSG_ERROR(can't locate a valid JDK location)
+      fi
+
+    fi
+
+    if test -n "${JAVA_PLATFORM}"; then
+      AC_MSG_RESULT(Java Platform detected - 1.${JAVA_PLATFORM})
+    else
+      AC_MSG_CHECKING(Java platform)
+    fi
+
+    AC_ARG_WITH(java-platform,
+     [  --with-java-platform[=2] Force the Java platorm
+                                 (value is 1 for 1.1.x or 2 for 1.2.x or greater)],
+     [
+        case "${withval}" in
+          "1"|"2")
+            JAVA_PLATFORM=${withval}
+            ;;
+          *)
+            AC_MSG_ERROR(invalid java platform provided)
+            ;;
+        esac
+     ],
+     [
+        if test -n "${JAVA_PLATFORM}"; then
+          AC_MSG_RESULT(Java Platform detected - 1.${JAVA_PLATFORM})
+        else
+          AC_MSG_CHECKING(Java platform)
+        fi
+     ])
+
+     AC_MSG_RESULT(${JAVA_PLATFORM})
+
+    unset tempval
+  ])
+
+
+AC_DEFUN(
+  [TCN_FIND_JDK_OS],
+  [
+    tempval=""
+    JAVA_OS=""
+    AC_ARG_WITH(os-type,
+      [  --with-os-type[=SUBDIR]  Location of JDK os-type subdirectory.],
+      [
+        tempval=${withval}
+
+        if test ! -d "${JAVA_HOME}/${tempval}" ; then
+          AC_MSG_ERROR(Not a directory: ${JAVA_HOME}/${tempval})
+        fi
+
+        JAVA_OS = ${tempval}
+      ],
+      [   
+        AC_MSG_CHECKING(os_type directory)
+        JAVA_OS=NONE
+        if test -f ${JAVA_HOME}/${JAVA_INC}/jni_md.h; then
+          JAVA_OS=""
+        else
+          for f in ${JAVA_HOME}/${JAVA_INC}/*/jni_md.h; do
+            if test -f $f; then
+              JAVA_OS=`dirname ${f}`
+              JAVA_OS=`basename ${JAVA_OS}`
+              echo " ${JAVA_OS}"
+            fi
+          done
+          if test "${JAVA_OS}" = "NONE"; then
+            AC_MSG_RESULT(Cannot find jni_md.h in ${JAVA_HOME}/${OS})
+            AC_MSG_ERROR(You should retry --with-os-type=SUBDIR)
+          fi
+        fi
+      ])
+  ])
+
+dnl check for sableVM
+dnl (copied from daemon/src/native/unix/support/apjava.m4)
+AC_DEFUN(
+  [TCN_SABLEVM],
+  [
+  if test x"$JAVA_HOME" != x
+  then
+    AC_PATH_PROG(SABLEVM,sablevm,NONE,$JAVA_HOME/bin)
+    if test "$SABLEVM" != "NONE"
+    then
+      AC_MSG_RESULT([Using sableVM: $SABLEVM])
+      CFLAGS="$CFLAGS -DHAVE_SABLEVM"
+    fi
+  fi
+  ])
+
+dnl TCN_HELP_STRING(LHS, RHS)
+dnl Autoconf 2.50 can not handle substr correctly.  It does have 
+dnl AC_HELP_STRING, so let's try to call it if we can.
+dnl Note: this define must be on one line so that it can be properly returned
+dnl as the help string.
+AC_DEFUN(TCN_HELP_STRING,[ifelse(regexp(AC_ACVERSION, 2\.1), -1, AC_HELP_STRING($1,$2),[  ]$1 substr([                       ],len($1))$2)])dnl
+
+dnl
+dnl TCN_CHECK_SSL_TOOLKIT
+dnl
+dnl Configure for the detected openssl toolkit installation, giving
+dnl preference to "--with-ssl=<path>" if it was specified.
+dnl
+AC_DEFUN(TCN_CHECK_SSL_TOOLKIT,[
+  dnl initialise the variables we use
+  tcn_ssltk_base=""
+  tcn_ssltk_inc=""
+  tcn_ssltk_lib=""
+  tcn_ssltk_type=""
+  AC_ARG_WITH(ssl, TCN_HELP_STRING(--with-ssl=DIR,OpenSSL SSL/TLS toolkit), [
+    dnl If --with-ssl specifies a directory, we use that directory or fail
+    if test "x$withval" != "xyes" -a "x$withval" != "x"; then
+      dnl This ensures $withval is actually a directory and that it is absolute
+      tcn_ssltk_base="`cd $withval ; pwd`"
+    fi
+  ])
+  if test "x$tcn_ssltk_base" = "x"; then
+    AC_MSG_RESULT(none)
+  else
+    AC_MSG_RESULT($tcn_ssltk_base)
+  fi
+
+  dnl Run header and version checks
+  saved_CPPFLAGS=$CPPFLAGS
+  if test "x$tcn_ssltk_base" != "x"; then
+    tcn_ssltk_inc="-I$tcn_ssltk_base/include"
+    CPPFLAGS="$CPPFLAGS $tcn_ssltk_inc"
+  fi
+
+  if test "x$tcn_ssltk_type" = "x"; then
+    AC_MSG_CHECKING(for OpenSSL version)
+    dnl First check for manditory headers
+    AC_CHECK_HEADERS([openssl/opensslv.h], [tcn_ssltk_type="openssl"], [])
+    if test "$tcn_ssltk_type" = "openssl"; then
+      dnl so it's OpenSSL - test for a good version
+      AC_TRY_COMPILE([#include <openssl/opensslv.h>],[
+#if !defined(OPENSSL_VERSION_NUMBER)
+  #error "Missing openssl version"
+#endif
+#if  (OPENSSL_VERSION_NUMBER < 0x0090701f)
+  #error "Unsuported openssl version " OPENSSL_VERSION_TEXT
+#endif],
+      [AC_MSG_RESULT(OK)],
+      [dnl Unsuported OpenSSL version
+         AC_MSG_ERROR([Unsupported OpenSSL version. Use 0.9.7a or higher version])
+      ])
+      dnl Look for additional, possibly missing headers
+      AC_CHECK_HEADERS(openssl/engine.h)
+      if test -n "$PKGCONFIG"; then
+        $PKGCONFIG openssl
+        if test $? -eq 0; then
+          tcn_ssltk_inc="$tcn_ssltk_inc `$PKGCONFIG --cflags-only-I openssl`"
+          CPPFLAGS="$CPPFLAGS $tcn_ssltk_inc"
+        fi
+      fi
+    else
+      AC_MSG_RESULT([no OpenSSL headers found])
+    fi
+  fi
+  if test "$tcn_ssltk_type" != "openssl"; then
+    AC_MSG_ERROR([... No OpenSSL headers found])
+  fi
+  dnl restore
+  CPPFLAGS=$saved_CPPFLAGS
+  if test "x$tcn_ssltk_type" = "x"; then
+    AC_MSG_ERROR([...No recognized SSL/TLS toolkit detected])
+  fi
+
+  dnl Run library and function checks
+  saved_LDFLAGS=$LDFLAGS
+  saved_LIBS=$LIBS
+  if test "x$tcn_ssltk_base" != "x"; then
+    if test -d "$tcn_ssltk_base/lib64"; then
+      tcn_ssltk_lib="$tcn_ssltk_base/lib64"
+    elif test -d "$tcn_ssltk_base/lib"; then
+      tcn_ssltk_lib="$tcn_ssltk_base/lib"
+    else
+      tcn_ssltk_lib="$tcn_ssltk_base"
+    fi
+    LDFLAGS="$LDFLAGS -L$tcn_ssltk_lib"
+  fi
+  dnl make sure "other" flags are available so libcrypto and libssl can link
+  LIBS="$LIBS `$apr_config --libs`"
+  liberrors=""
+  if test "$tcn_ssltk_type" = "openssl"; then
+    AC_CHECK_LIB(crypto, SSLeay_version, [], [liberrors="yes"])
+    AC_CHECK_LIB(ssl, SSL_CTX_new, [], [liberrors="yes"])
+    AC_CHECK_FUNCS(ENGINE_init)
+    AC_CHECK_FUNCS(ENGINE_load_builtin_engines)
+  else
+    AC_CHECK_LIB(sslc, SSLC_library_version, [], [liberrors="yes"])
+    AC_CHECK_LIB(sslc, SSL_CTX_new, [], [liberrors="yes"])
+    AC_CHECK_FUNCS(SSL_set_state)
+  fi
+  AC_CHECK_FUNCS(SSL_set_cert_store)
+  dnl restore
+  LDFLAGS=$saved_LDFLAGS
+  LIBS=$saved_LIBS
+  if test "x$liberrors" != "x"; then
+    AC_MSG_ERROR([... Error, SSL/TLS libraries were missing or unusable])
+  fi
+
+  dnl (b) hook up include paths
+  if test "x$tcn_ssltk_inc" != "x"; then
+    APR_ADDTO(TCNATIVE_PRIV_INCLUDES, [$tcn_ssltk_inc])
+  fi
+  dnl (c) hook up linker paths
+  if test "x$tcn_ssltk_lib" != "x"; then
+    APR_ADDTO(TCNATIVE_LDFLAGS, ["-L$tcn_ssltk_lib"])
+  fi
+
+  dnl Adjust configuration based on what we found above.
+  dnl (a) define preprocessor symbols
+  if test "$tcn_ssltk_type" = "openssl"; then
+    APR_SETVAR(SSL_LIBS, [-lssl -lcrypto])
+    APR_ADDTO(CFLAGS, [-DHAVE_OPENSSL])
+  fi
+  AC_SUBST(SSL_LIBS)
+])

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/build.conf
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/build.conf	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/build.conf	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,19 @@
+#
+# Configuration file for APRJAVA. Used by APR/build/gen-build.py
+#
+
+[options]
+
+# the platform-independent .c files
+paths =
+  src/*.c
+
+# we have no platform-specific subdirs
+platform_dirs =
+  os
+
+# the public headers
+headers = include/*.h
+
+# we have a recursive makefile for the test files (for now)
+# test/*.c

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/buildconf
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/buildconf	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/buildconf	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,95 @@
+#!/bin/sh
+#
+# Copyright 1999-2004 The Apache Software Foundation
+#
+# Licensed 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.
+#
+#
+
+# Default place to look for apr source.  Can be overridden with 
+#   --with-apr=[directory]
+apr_src_dir=../apr
+
+while test $# -gt 0 
+do
+  # Normalize
+  case "$1" in
+  -*=*) optarg=`echo "$1" | sed 's/[-_a-zA-Z0-9]*=//'` ;;
+  *) optarg= ;;
+  esac
+
+  case "$1" in
+  --with-apr=*)
+  apr_src_dir=$optarg
+  ;;
+  esac
+
+  shift
+done
+
+if test -d "$apr_src_dir"
+then
+  echo ""
+  echo "Looking for apr source in $apr_src_dir"
+else
+  echo ""
+  echo "Problem finding apr source in $apr_src_dir."
+  echo "Use:"
+  echo "  --with-apr=[directory]" 
+  exit 1
+fi
+
+# Remove some files, then copy them from apr source tree
+rm -f build/apr_common.m4 build/find_apr.m4 build/install.sh \
+      build/config.guess build/config.sub
+cp $apr_src_dir/build/apr_common.m4 $apr_src_dir/build/find_apr.m4 \
+   $apr_src_dir/build/install.sh $apr_src_dir/build/config.guess  \
+   $apr_src_dir/build/config.sub build
+
+# Remove aclocal.m4 as it'll break some builds...
+rm -rf aclocal.m4 autom4te*.cache
+
+echo "Creating configure ..."
+### do some work to toss config.cache?
+if ${AUTOCONF:-autoconf}; then
+  :
+else
+  echo "autoconf failed"
+  exit 1
+fi
+
+#
+# Generate build-outputs.mk for the build systme
+#
+echo "Generating 'make' outputs ..."
+$apr_src_dir/build/gen-build.py make
+
+# Remove autoconf cache again
+rm -rf autom4te*.cache
+
+# Create RPM Spec file
+if [ -f `which cut` ]; then
+  echo rebuilding rpm spec file
+  ( REVISION=`build/get-version.sh all include/tcn_version.h TCN`
+    VERSION=`echo $REVISION | cut -d- -s -f1`
+    RELEASE=`echo $REVISION | cut -d- -s -f2`
+    if [ "x$VERSION" = "x" ]; then
+      VERSION=$REVISION
+      RELEASE=1
+    fi
+    cat ./build/rpm/tcnative.spec.in | \
+    sed -e "s/TCN_VERSION/$VERSION/" \
+        -e "s/TCN_RELEASE/$RELEASE/" \
+    > tcnative.spec )
+fi
+

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/config.layout
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/config.layout	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/config.layout	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,232 @@
+##
+##  config.layout -- Pre-defined Installation Path Layouts
+##
+##  Hints:
+##  - layouts can be loaded with configure's --enable-layout=ID option
+##  - when no --enable-layout option is given, the default layout is `apr'
+##  - a trailing plus character (`+') on paths is replaced with a 
+##    `/<target>' suffix where <target> is currently hardcoded to 'apr'.
+##    (This may become a configurable parameter at some point.)
+##
+
+#   Classical Tomcat Native path layout designed for parallel installs.
+<Layout tcnative>
+    prefix:        /usr/local/apr
+    exec_prefix:   ${prefix}
+    bindir:        ${exec_prefix}/bin
+    sbindir:       ${exec_prefix}/bin
+    libdir:        ${exec_prefix}/lib
+    libexecdir:    ${exec_prefix}/modules
+    mandir:        ${prefix}/man
+    sysconfdir:    ${prefix}/conf
+    datadir:       ${prefix}
+    installbuilddir: ${datadir}/build
+    includedir:    ${prefix}/include/apr-${TCNATIVE_MAJOR_VERSION}
+    localstatedir: ${prefix}
+    libsuffix:     -${TCNATIVE_MAJOR_VERSION}
+</Layout>
+
+#   Classical single-installation APR path layout.
+<Layout classic>
+    prefix:        /usr/local/apr
+    exec_prefix:   ${prefix}
+    bindir:        ${exec_prefix}/bin
+    sbindir:       ${exec_prefix}/bin
+    libdir:        ${exec_prefix}/lib
+    libexecdir:    ${exec_prefix}/modules
+    mandir:        ${prefix}/man
+    sysconfdir:    ${prefix}/conf
+    datadir:       ${prefix}
+    installbuilddir: ${datadir}/build
+    includedir:    ${prefix}/include
+    localstatedir: ${prefix}
+</Layout>
+
+#   GNU standards conforming path layout.
+#   See FSF's GNU project `make-stds' document for details.
+<Layout GNU>
+    prefix:        /usr/local
+    exec_prefix:   ${prefix}
+    bindir:        ${exec_prefix}/bin
+    sbindir:       ${exec_prefix}/sbin
+    libdir:        ${exec_prefix}/lib
+    libexecdir:    ${exec_prefix}/libexec
+    mandir:        ${prefix}/man
+    sysconfdir:    ${prefix}/etc+
+    datadir:       ${prefix}/share+
+    installbuilddir: ${datadir}/build
+    includedir:    ${prefix}/include+
+    localstatedir: ${prefix}/var+
+    runtimedir:    ${localstatedir}/run
+</Layout>
+
+#   Mac OS X Server (Rhapsody)
+<Layout Mac OS X Server>
+    prefix:        /Local/Library/WebServer
+    exec_prefix:   /usr
+    bindir:        ${exec_prefix}/bin
+    sbindir:       ${exec_prefix}/sbin
+    libdir:        ${exec_prefix}/lib
+    libexecdir:    /System/Library/apr/Modules
+    mandir:        ${exec_prefix}/share/man
+    sysconfdir:    ${prefix}/Configuration
+    datadir:       ${prefix}
+    installbuilddir: /System/Library/apr/Build
+    includedir:    /System/Library/Frameworks/apr.framework/Versions/2.0/Headers
+    localstatedir: /var
+    runtimedir:    ${prefix}/Logs
+</Layout>
+
+#   Darwin/Mac OS Layout
+<Layout Darwin>
+    prefix:        /usr
+    exec_prefix:   ${prefix}
+    bindir:        ${exec_prefix}/bin
+    sbindir:       ${exec_prefix}/sbin
+    libdir:        ${exec_prefix}/lib
+    libexecdir:    ${exec_prefix}/libexec+
+    mandir:        ${prefix}/share/man
+    datadir:       /Library/WebServer
+    sysconfdir:    /etc+
+    installbuilddir: ${prefix}/share/httpd/build
+    includedir:    ${prefix}/include+
+    localstatedir: /var
+    runtimedir:    ${localstatedir}/run
+</Layout>
+
+#   Red Hat Linux 7.x layout
+<Layout RedHat>
+    prefix:        /usr
+    exec_prefix:   ${prefix}
+    bindir:        ${prefix}/bin
+    sbindir:       ${prefix}/sbin
+    libdir:        ${prefix}/lib
+    libexecdir:    ${prefix}/lib/apr
+    mandir:        ${prefix}/man
+    sysconfdir:    /etc/httpd/conf
+    datadir:       /var/www
+    installbuilddir: ${datadir}/build
+    includedir:    ${prefix}/include/apr
+    localstatedir: /var
+    runtimedir:    ${localstatedir}/run
+</Layout>     
+
+#   According to the /opt filesystem conventions
+<Layout opt>
+    prefix:        /opt/apr
+    exec_prefix:   ${prefix}
+    bindir:        ${exec_prefix}/bin
+    sbindir:       ${exec_prefix}/sbin
+    libdir:        ${exec_prefix}/lib
+    libexecdir:    ${exec_prefix}/libexec
+    mandir:        ${prefix}/man
+    sysconfdir:    /etc${prefix}
+    datadir:       ${prefix}/share
+    installbuilddir: ${datadir}/build
+    includedir:    ${prefix}/include
+    localstatedir: /var${prefix}
+    runtimedir:    ${localstatedir}/run
+</Layout>
+
+#  BeOS layout...
+<Layout beos>
+    prefix:        /boot/home/apr
+    exec_prefix:   ${prefix}
+    bindir:        ${exec_prefix}/bin
+    sbindir:       ${exec_prefix}/bin
+    libdir:        ${exec_prefix}/lib
+    libexecdir:    ${exec_prefix}/libexec
+    mandir:        ${prefix}/man
+    sysconfdir:    ${prefix}/conf
+    datadir:       ${prefix}
+    installbuilddir: ${datadir}/build
+    includedir:    ${prefix}/include
+    localstatedir: ${prefix}
+    runtimedir:    ${localstatedir}/logs
+</Layout>
+
+#   SuSE 6.x layout
+<Layout SuSE>
+    prefix:        /usr
+    exec_prefix:   ${prefix}
+    bindir:        ${prefix}/bin
+    sbindir:       ${prefix}/sbin
+    libdir:        ${prefix}/lib
+    libexecdir:    ${prefix}/lib/apr
+    mandir:        ${prefix}/share/man
+    sysconfdir:    /etc/httpd
+    datadir:       /usr/local/httpd
+    installbuilddir: ${datadir}/build
+    includedir:    ${prefix}/include/apr
+    localstatedir: /var/lib/httpd
+    runtimedir:    /var/run
+</Layout>
+
+#   BSD/OS layout
+<Layout BSDI>
+    prefix:        /var/www
+    exec_prefix:   /usr/contrib
+    bindir:        ${exec_prefix}/bin
+    sbindir:       ${exec_prefix}/bin
+    libdir:        ${exec_prefix}/lib
+    libexecdir:    ${exec_prefix}/libexec/apr
+    mandir:        ${exec_prefix}/man
+    sysconfdir:    ${prefix}/conf
+    datadir:       ${prefix}
+    installbuilddir: ${datadir}/build
+    includedir:    ${exec_prefix}/include/apr
+    localstatedir: /var
+    runtimedir:    ${localstatedir}/run
+</Layout>
+
+#   Solaris 8 Layout
+<Layout Solaris>
+    prefix:        /usr/apr
+    exec_prefix:   ${prefix}
+    bindir:        ${exec_prefix}/bin
+    sbindir:       ${exec_prefix}/bin
+    libdir:        ${exec_prefix}/lib
+    libexecdir:    ${exec_prefix}/libexec
+    mandir:        ${exec_prefix}/man
+    sysconfdir:    /etc/apr
+    datadir:       /var/apr
+    installbuilddir: ${datadir}/build
+    includedir:    ${exec_prefix}/include
+    localstatedir: ${prefix}
+    runtimedir:    /var/run
+</Layout>
+
+#   OpenBSD Layout
+<Layout OpenBSD>
+    prefix:        /var/www
+    exec_prefix:   /usr
+    bindir:        ${exec_prefix}/bin
+    sbindir:       ${exec_prefix}/sbin
+    libdir:        ${exec_prefix}/lib
+    libexecdir:    ${exec_prefix}/lib/apr/modules
+    mandir:        ${exec_prefix}/share/man
+    sysconfdir:    ${prefix}/conf
+    datadir:       ${prefix}
+    installbuilddir: ${prefix}/build
+    includedir:    ${exec_prefix}/lib/apr/include
+    localstatedir: ${prefix}
+    runtimedir:    ${prefix}/logs
+</Layout>
+
+# Debian layout
+<Layout Debian>
+    prefix:        
+    exec_prefix:   ${prefix}/usr
+    bindir:        ${exec_prefix}/bin
+    sbindir:       ${exec_prefix}/sbin
+    libdir:        ${exec_prefix}/lib
+    libexecdir:    ${exec_prefix}/lib/apr/modules
+    mandir:        ${exec_prefix}/share/man
+    datadir:       ${exec_prefix}/share/apr
+    includedir:    ${exec_prefix}/include/apr-${TCNATIVE_MAJOR_VERSION}
+    localstatedir: ${prefix}/var/run
+    runtimedir:    ${prefix}/var/run
+    infodir:       ${exec_prefix}/share/info
+    libsuffix     -${TCNATIVE_MAJOR_VERSION}
+    installbuilddir: ${prefix}/usr/share/apache2/build
+</Layout>

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/configure.in
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/configure.in	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/configure.in	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,232 @@
+dnl
+dnl Process this file with autoconf to produce a configure script
+dnl
+
+AC_PREREQ(2.13)
+AC_INIT(configure.in)
+
+AC_CONFIG_AUX_DIR(build)
+
+sinclude(build/apr_common.m4)
+sinclude(build/tcnative.m4)
+sinclude(build/find_apr.m4)
+
+dnl Generate ./config.nice for reproducing runs of configure
+dnl
+APR_CONFIG_NICE(config.nice)
+
+dnl # Some initial steps for configuration.  We setup the default directory
+dnl # and which files are to be configured.
+
+dnl Absolute source/build directory
+abs_srcdir=`(cd $srcdir && pwd)`
+abs_builddir=`pwd`
+
+if test "$abs_builddir" != "$abs_srcdir"; then
+  USE_VPATH=1
+  TCN_CONFIG_LOCATION=build
+else
+  TCN_CONFIG_LOCATION=source
+fi
+
+AC_SUBST(TCN_CONFIG_LOCATION)
+AC_CANONICAL_SYSTEM
+AC_PROG_INSTALL
+
+dnl
+dnl compute the top directory of the build
+dnl note: this is needed for LIBTOOL and exporting the bundled Expat
+dnl
+top_builddir="$abs_builddir"
+AC_SUBST(top_builddir)
+AC_SUBST(abs_srcdir)
+AC_SUBST(abs_builddir)
+
+dnl Initialize mkdir -p functionality.
+APR_MKDIR_P_CHECK($abs_srcdir/build/mkdir.sh)
+
+dnl get our version information
+get_version="$abs_srcdir/build/get-version.sh"
+version_hdr="$abs_srcdir/include/tcn_version.h"
+TCNATIVE_MAJOR_VERSION="`$get_version major $version_hdr TCN`"
+TCNATIVE_DOTTED_VERSION="`$get_version all $version_hdr TCN`"
+TCNATIVE_LIBTOOL_VERSION="`$get_version libtool $version_hdr TCN`"
+
+AC_SUBST(TCNATIVE_DOTTED_VERSION)
+AC_SUBST(TCNATIVE_MAJOR_VERSION)
+AC_SUBST(TCNATIVE_LIBTOOL_VERSION)
+
+echo "Tomcat Native Version: ${TCNATIVE_DOTTED_VERSION}"
+
+dnl Enable the layout handling code, then reparse the prefix-style
+dnl arguments due to autoconf being a PITA.
+APR_ENABLE_LAYOUT(tcnative)
+APR_PARSE_ARGUMENTS
+
+dnl
+dnl set up the compilation flags and stuff
+dnl
+
+TCNATIVE_INCLUDES=""
+TCNATIVE_PRIV_INCLUDES="-I$top_builddir/include"
+
+dnl
+dnl Find the APR includes directory and (possibly) the source (base) dir.
+dnl
+TCN_FIND_APR
+
+dnl
+dnl even though we use apr_rules.mk for building apr-util, we need
+dnl to grab CC and CPP ahead of time so that apr-util config tests
+dnl use the same compiler as APR; we need the same compiler options
+dnl and feature test macros as well
+dnl
+APR_SETIFNULL(CC, `$apr_config --cc`)
+APR_SETIFNULL(CPP, `$apr_config --cpp`)
+
+AC_PROG_INSTALL
+
+dnl
+dnl  Find the JVM related information
+dnl
+TCN_FIND_JDK
+TCN_SABLEVM
+
+dnl MAC OS X does not used include but Headers
+if test -d ${JAVA_HOME}/Headers; then
+  JAVA_INC=Headers
+else
+  JAVA_INC=include
+fi
+APR_ADDTO(TCNATIVE_PRIV_INCLUDES,[-I$JAVA_HOME/$JAVA_INC])
+
+dnl sableVM does not have/need $JAVA_OS/jni_md.h
+if test "$SABLEVM" = "NONE"
+then
+  TCN_FIND_JDK_OS
+  if test -z "${JAVA_OS}"; then
+    AC_MSG_RESULT([jni_md.h found in $JAVA_HOME/$JAVA_INC])
+  else
+    APR_ADDTO(TCNATIVE_PRIV_INCLUDES,[-I$JAVA_HOME/$JAVA_INC/$JAVA_OS])
+  fi
+fi
+
+AC_SUBST(JAVA_HOME)
+AC_SUBST(JAVA_PLATFORM)
+AC_SUBST(JAVA_OS)
+
+
+dnl
+dnl Detect openssl toolkit installation
+dnl
+TCN_CHECK_SSL_TOOLKIT
+
+so_ext=$APR_SO_EXT
+lib_target=$APR_LIB_TARGET
+AC_SUBST(so_ext)
+AC_SUBST(lib_target)
+
+TCNATIVE_LIBNAME="tcnative${libsuffix}"
+AC_SUBST(TCNATIVE_LIBNAME)
+
+EXTRA_OS_LINK=""
+host_alias=`uname -s`
+case "$host_alias" in
+    dnl ### BeOS requires that ALL symbols resolve at LINK time!
+    dnl ###
+    dnl ### So, if we're building on BeOS then we need to add in the
+    dnl ### apr and expat libraries to the build or it'll die a truly horrible
+    dnl ### death. We now use the apr-config tool to determine the correct
+    dnl ### library to link against :)
+*AIX*|*Darwin*|*BeOS*)
+    dnl need such stuff as -liconv to be specified when building libaprutil.la
+    EXTRA_OS_LINK='$(TCNATIVE_LDFLAGS) $(TCNATIVE_LIBS)'
+    ;;
+*)
+    ;;
+esac
+
+AC_SUBST(EXTRA_OS_LINK)
+
+dnl CFLAGS for maintainer mode
+dnl it also allows the CFLAGS environment variable.
+CFLAGS="${CFLAGS}"
+AC_ARG_ENABLE(
+maintainer-mode,
+[  --enable-maintainer-mode   Turn on debugging and compile time warnings],
+[
+  if test "$GCC" = "yes"; then
+    CFLAGS="${CFLAGS} -DDEBUG -Wall"
+  else
+    CFLAGS="${CFLAGS} -DDEBUG"
+  fi
+AC_MSG_RESULT([...Enabling Maintainer mode...])
+])
+
+dnl
+dnl Prep all the flags and stuff for compilation and export to other builds
+dnl
+APR_ADDTO(TCNATIVE_LIBS, [$LIBS])
+APR_ADDTO(TCNATIVE_LIBS, [$APR_LIBS])
+APR_ADDTO(TCNATIVE_LDFLAGS, [$LDFLAGS])
+
+# Link libkstat for Solaris
+case $host in
+    *-solaris2*)
+        APR_ADDTO(TCNATIVE_LIBS, -lkstat)
+        ;;
+    *)
+        ;;
+esac
+
+AC_SUBST(TCNATIVE_EXPORT_LIBS)
+AC_SUBST(TCNATIVE_PRIV_INCLUDES)
+AC_SUBST(TCNATIVE_INCLUDES)
+AC_SUBST(TCNATIVE_LDFLAGS)
+AC_SUBST(TCNATIVE_LIBS)
+AC_SUBST(CFLAGS)
+AC_SUBST(CPPFLAGS)
+
+dnl copy apr's rules.mk into our build directory.
+if test ! -d ./build; then
+   $mkdir_p build
+fi
+cp $APR_BUILD_DIR/apr_rules.mk $abs_builddir/build/rules.mk
+
+
+dnl
+dnl BSD/OS (BSDi) needs to use a different include syntax in the Makefiles
+dnl
+case "$host_alias" in
+*bsdi* | BSD/OS)
+    # Check whether they've installed GNU make
+    if make --version > /dev/null 2>&1; then
+        INCLUDE_RULES="include $abs_builddir/build/rules.mk"
+        INCLUDE_OUTPUTS="include $abs_srcdir/build-outputs.mk"
+    else
+        INCLUDE_RULES=".include \"$abs_builddir/build/rules.mk\""
+        INCLUDE_OUTPUTS=".include \"$abs_srcdir/build-outputs.mk\""
+    fi
+    ;;
+*)
+    INCLUDE_RULES="include $abs_builddir/build/rules.mk"
+    INCLUDE_OUTPUTS="include $abs_srcdir/build-outputs.mk"
+    ;;
+esac
+
+AC_SUBST(INCLUDE_RULES)
+AC_SUBST(INCLUDE_OUTPUTS)
+
+if test -d $srcdir/test; then
+    test_Makefile="test/Makefile"
+fi
+
+dnl
+dnl everthing is done.
+MAKEFILES="Makefile"
+AC_OUTPUT([
+    tcnative.pc
+    $MAKEFILES
+	],[
+TCNATIVE_MAJOR_VERSION=$TCNATIVE_MAJOR_VERSION
+])

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/include/ssl_private.h
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/include/ssl_private.h	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/include/ssl_private.h	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,293 @@
+/* Copyright 2000-2005 The Apache Software Foundation
+ *
+ * Licensed 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.
+ */
+
+/*
+ *
+ * @author Mladen Turk
+ * @version $Revision: 301018 $, $Date: 2005-08-01 02:23:09 -0500 (Mon, 01 Aug 2005) $
+ */
+
+#ifndef SSL_PRIVATE_H
+#define SSL_PRIVATE_H
+
+/* Exclude unused OpenSSL features
+ * even if the OpenSSL supports them
+ */
+#ifndef OPENSSL_NO_IDEA
+#define OPENSSL_NO_IDEA
+#endif
+#ifndef OPENSSL_NO_KRB5
+#define OPENSSL_NO_KRB5
+#endif
+#ifndef OPENSSL_NO_MDC2
+#define OPENSSL_NO_MDC2
+#endif
+#ifndef OPENSSL_NO_RC5
+#define OPENSSL_NO_RC5
+#endif
+
+/* OpenSSL headers */
+#include <openssl/ssl.h>
+#include <openssl/err.h>
+#include <openssl/x509.h>
+#include <openssl/pem.h>
+#include <openssl/crypto.h>
+#include <openssl/evp.h>
+#include <openssl/rand.h>
+#include <openssl/x509v3.h>
+#include <openssl/md5.h>
+/* Avoid tripping over an engine build installed globally and detected
+ * when the user points at an explicit non-engine flavor of OpenSSL
+ */
+#ifndef OPENSSL_NO_ENGINE
+#include <openssl/engine.h>
+#endif
+
+#ifndef RAND_MAX
+#include <limits.h>
+#define RAND_MAX INT_MAX
+#endif
+
+#define SSL_ALGO_UNKNOWN (0)
+#define SSL_ALGO_RSA     (1<<0)
+#define SSL_ALGO_DSA     (1<<1)
+#define SSL_ALGO_ALL     (SSL_ALGO_RSA|SSL_ALGO_DSA)
+
+#define SSL_AIDX_RSA     (0)
+#define SSL_AIDX_DSA     (1)
+#define SSL_AIDX_MAX     (2)
+
+/*
+ * Define IDs for the temporary RSA keys and DH params
+ */
+
+#define SSL_TMP_KEY_RSA_512     (0)
+#define SSL_TMP_KEY_RSA_1024    (1)
+#define SSL_TMP_KEY_RSA_2048    (2)
+#define SSL_TMP_KEY_RSA_4096    (3)
+#define SSL_TMP_KEY_DH_512      (4)
+#define SSL_TMP_KEY_DH_1024     (5)
+#define SSL_TMP_KEY_DH_2048     (6)
+#define SSL_TMP_KEY_DH_4096     (7)
+#define SSL_TMP_KEY_MAX         (8)
+
+#define SSL_CRT_FORMAT_UNDEF    (0)
+#define SSL_CRT_FORMAT_ASN1     (1)
+#define SSL_CRT_FORMAT_TEXT     (2)
+#define SSL_CRT_FORMAT_PEM      (3)
+#define SSL_CRT_FORMAT_NETSCAPE (4)
+#define SSL_CRT_FORMAT_PKCS12   (5)
+#define SSL_CRT_FORMAT_SMIME    (6)
+#define SSL_CRT_FORMAT_ENGINE   (7)
+/* XXX this stupid macro helps us to avoid
+ * adding yet another param to load_*key()
+ */
+#define SSL_KEY_FORMAT_IISSGC   (8)
+
+/*
+ * Define the SSL options
+ */
+#define SSL_OPT_NONE            (0)
+#define SSL_OPT_RELSET          (1<<0)
+#define SSL_OPT_STDENVVARS      (1<<1)
+#define SSL_OPT_EXPORTCERTDATA  (1<<3)
+#define SSL_OPT_FAKEBASICAUTH   (1<<4)
+#define SSL_OPT_STRICTREQUIRE   (1<<5)
+#define SSL_OPT_OPTRENEGOTIATE  (1<<6)
+#define SSL_OPT_ALL             (SSL_OPT_STDENVVARS|SSL_OPT_EXPORTCERTDATA|SSL_OPT_FAKEBASICAUTH|SSL_OPT_STRICTREQUIRE|SSL_OPT_OPTRENEGOTIATE)
+
+/*
+ * Define the SSL Protocol options
+ */
+#define SSL_PROTOCOL_NONE       (0)
+#define SSL_PROTOCOL_SSLV2      (1<<0)
+#define SSL_PROTOCOL_SSLV3      (1<<1)
+#define SSL_PROTOCOL_TLSV1      (1<<2)
+#define SSL_PROTOCOL_ALL        (SSL_PROTOCOL_SSLV2|SSL_PROTOCOL_SSLV3|SSL_PROTOCOL_TLSV1)
+
+#define SSL_MODE_CLIENT         (0)
+#define SSL_MODE_SERVER         (1)
+#define SSL_MODE_COMBINED       (2)
+
+#define SSL_BIO_FLAG_RDONLY     (1<<0)
+#define SSL_BIO_FLAG_CALLBACK   (1<<1)
+#define SSL_DEFAULT_CACHE_SIZE  (256)
+#define SSL_DEFAULT_VHOST_NAME  ("_default_:443")
+#define SSL_MAX_STR_LEN         (2048)
+#define SSL_MAX_PASSWORD_LEN    (256)
+
+#define SSL_CVERIFY_UNSET           (-1)
+#define SSL_CVERIFY_NONE            (0)
+#define SSL_CVERIFY_OPTIONAL        (1)
+#define SSL_CVERIFY_REQUIRE         (2)
+#define SSL_CVERIFY_OPTIONAL_NO_CA  (3)
+#define SSL_VERIFY_PEER_STRICT      (SSL_VERIFY_PEER|SSL_VERIFY_FAIL_IF_NO_PEER_CERT)
+
+#define SSL_SHUTDOWN_TYPE_UNSET     (0)
+#define SSL_SHUTDOWN_TYPE_STANDARD  (1)
+#define SSL_SHUTDOWN_TYPE_UNCLEAN   (2)
+#define SSL_SHUTDOWN_TYPE_ACCURATE  (3)
+
+#define SSL_TO_APR_ERROR(X)         (APR_OS_START_USERERR + 1000 + X)
+
+#define SSL_INFO_SESSION_ID                 (0x0001)
+#define SSL_INFO_CIPHER                     (0x0002)
+#define SSL_INFO_CIPHER_USEKEYSIZE          (0x0003)
+#define SSL_INFO_CIPHER_ALGKEYSIZE          (0x0004)
+#define SSL_INFO_CIPHER_VERSION             (0x0005)
+#define SSL_INFO_CIPHER_DESCRIPTION         (0x0006)
+#define SSL_INFO_PROTOCOL                   (0x0007)
+
+#define SSL_INFO_CLIENT_S_DN                (0x0010)
+#define SSL_INFO_CLIENT_I_DN                (0x0020)
+#define SSL_INFO_SERVER_S_DN                (0x0040)
+#define SSL_INFO_SERVER_I_DN                (0x0080)
+
+#define SSL_INFO_DN_COUNTRYNAME             (0x0001)
+#define SSL_INFO_DN_STATEORPROVINCENAME     (0x0002)
+#define SSL_INFO_DN_LOCALITYNAME            (0x0003)
+#define SSL_INFO_DN_ORGANIZATIONNAME        (0x0004)
+#define SSL_INFO_DN_ORGANIZATIONALUNITNAME  (0x0005)
+#define SSL_INFO_DN_COMMONNAME              (0x0006)
+#define SSL_INFO_DN_TITLE                   (0x0007)
+#define SSL_INFO_DN_INITIALS                (0x0008)
+#define SSL_INFO_DN_GIVENNAME               (0x0009)
+#define SSL_INFO_DN_SURNAME                 (0x000A)
+#define SSL_INFO_DN_DESCRIPTION             (0x000B)
+#define SSL_INFO_DN_UNIQUEIDENTIFIER        (0x000C)
+#define SSL_INFO_DN_EMAILADDRESS            (0x000D)
+
+#define SSL_INFO_CLIENT_MASK                (0x0100)
+
+#define SSL_INFO_CLIENT_M_VERSION           (0x0101)
+#define SSL_INFO_CLIENT_M_SERIAL            (0x0102)
+#define SSL_INFO_CLIENT_V_START             (0x0103)
+#define SSL_INFO_CLIENT_V_END               (0x0104)
+#define SSL_INFO_CLIENT_A_SIG               (0x0105)
+#define SSL_INFO_CLIENT_A_KEY               (0x0106)
+#define SSL_INFO_CLIENT_CERT                (0x0107)
+#define SSL_INFO_CLIENT_V_REMAIN            (0x0108)
+
+#define SSL_INFO_SERVER_MASK                (0x0200)
+
+#define SSL_INFO_SERVER_M_VERSION           (0x0201)
+#define SSL_INFO_SERVER_M_SERIAL            (0x0202)
+#define SSL_INFO_SERVER_V_START             (0x0203)
+#define SSL_INFO_SERVER_V_END               (0x0204)
+#define SSL_INFO_SERVER_A_SIG               (0x0205)
+#define SSL_INFO_SERVER_A_KEY               (0x0206)
+#define SSL_INFO_SERVER_CERT                (0x0207)
+#define SSL_INFO_CLIENT_CERT_CHAIN          (0x0400)
+
+#define SSL_VERIFY_ERROR_IS_OPTIONAL(errnum) \
+   ((errnum == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT) \
+    || (errnum == X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN) \
+    || (errnum == X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY) \
+    || (errnum == X509_V_ERR_CERT_UNTRUSTED) \
+    || (errnum == X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE))
+
+
+
+#define SSL_DEFAULT_PASS_PROMPT "Some of your private key files are encrypted for security reasons.\n"  \
+                                "In order to read them you have to provide the pass phrases.\n"         \
+                                "Enter password :"
+
+extern void *SSL_temp_keys[SSL_TMP_KEY_MAX];
+
+typedef struct {
+    /* client can have any number of cert/key pairs */
+    const char  *cert_file;
+    const char  *cert_path;
+    STACK_OF(X509_INFO) *certs;
+} ssl_pkc_t;
+
+typedef struct tcn_ssl_ctxt_t tcn_ssl_ctxt_t;
+
+typedef struct {
+    char            password[SSL_MAX_PASSWORD_LEN];
+    const char     *prompt;
+    tcn_callback_t cb;
+} tcn_pass_cb_t;
+
+extern tcn_pass_cb_t tcn_password_callback;
+
+struct tcn_ssl_ctxt_t {
+    apr_pool_t      *pool;
+    SSL_CTX         *ctx;
+    BIO             *bio_os;
+    BIO             *bio_is;
+
+    unsigned char   context_id[MD5_DIGEST_LENGTH];
+
+    int             protocol;
+    /* we are one or the other */
+    int             mode;
+
+    /* certificate revocation list */
+    X509_STORE      *crl;
+    /* pointer to the context verify store */
+    X509_STORE      *store;
+    const char      *cert_files[SSL_AIDX_MAX];
+    const char      *key_files[SSL_AIDX_MAX];
+    X509            *certs[SSL_AIDX_MAX];
+    EVP_PKEY        *keys[SSL_AIDX_MAX];
+
+    int             ca_certs;
+    int             shutdown_type;
+    char            *rand_file;
+
+    const char      *cipher_suite;
+    /* for client or downstream server authentication */
+    int             verify_depth;
+    int             verify_mode;
+    tcn_pass_cb_t   *cb_data;
+};
+
+typedef struct {
+    apr_pool_t     *pool;
+    tcn_ssl_ctxt_t *ctx;
+    SSL            *ssl;
+    X509           *peer;
+    int             shutdown_type;
+    apr_socket_t   *sock;
+    apr_pollset_t  *pollset;
+} tcn_ssl_conn_t;
+
+
+#define SSL_CTX_get_extra_certs(ctx)        ((ctx)->extra_certs)
+#define SSL_CTX_set_extra_certs(ctx, value) \
+    TCN_BEGIN_MACRO                         \
+        (ctx)->extra_certs = (value);       \
+    TCN_END_MACRO
+
+/*
+ *  Additional Functions
+ */
+void        SSL_init_app_data2_idx(void);
+void       *SSL_get_app_data2(SSL *);
+void        SSL_set_app_data2(SSL *, void *);
+int         SSL_password_prompt(tcn_pass_cb_t *);
+int         SSL_password_callback(char *, int, int, void *);
+void        SSL_BIO_close(BIO *);
+void        SSL_BIO_doref(BIO *);
+DH         *SSL_dh_get_tmp_param(int);
+DH         *SSL_dh_get_param_from_file(const char *);
+RSA        *SSL_callback_tmp_RSA(SSL *, int, int);
+DH         *SSL_callback_tmp_DH(SSL *, int, int);
+void        SSL_vhost_algo_id(const unsigned char *, unsigned char *, int);
+int         SSL_CTX_use_certificate_chain(SSL_CTX *, const char *, int);
+int         SSL_callback_SSL_verify(int, X509_STORE_CTX *);
+int         SSL_rand_seed(const char *file);
+#endif /* SSL_PRIVATE_H */

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/include/tcn.h
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/include/tcn.h	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/include/tcn.h	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,284 @@
+/* Copyright 2000-2005 The Apache Software Foundation
+ *
+ * Licensed 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.
+ */
+
+/*
+ *
+ * @author Mladen Turk
+ * @version $Revision: 440699 $, $Date: 2006-09-06 07:30:48 -0500 (Wed, 06 Sep 2006) $
+ */
+
+#ifndef TCN_H
+#define TCN_H
+
+#include "apr.h"
+#include "apr_general.h"
+#include "apr_pools.h"
+#include "apr_portable.h"
+#include "apr_network_io.h"
+#include "apr_strings.h"
+
+#ifndef APR_HAS_THREADS
+#error "Missing APR_HAS_THREADS support from APR."
+#endif
+
+#if defined(DEBUG) || defined(_DEBUG)
+/* On -DDEBUG use the statistics */
+#ifndef TCN_DO_STATISTICS
+#define TCN_DO_STATISTICS
+#endif
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#if defined(_WIN32) && !defined(__CYGWIN__)
+#include <process.h>
+#else
+#include <unistd.h>
+#endif
+
+#include "tcn_api.h"
+
+
+#if defined(_DEBUG) || defined(DEBUG)
+#include <assert.h>
+#define TCN_ASSERT(x)  assert((x))
+#else
+#define TCN_ASSERT(x) (void)0
+#endif
+
+#ifndef APR_MAX_IOVEC_SIZE
+#define APR_MAX_IOVEC_SIZE 1024
+#endif
+
+#define TCN_TIMEUP      APR_OS_START_USERERR + 1
+#define TCN_EAGAIN      APR_OS_START_USERERR + 2
+#define TCN_EINTR       APR_OS_START_USERERR + 3
+#define TCN_EINPROGRESS APR_OS_START_USERERR + 4
+#define TCN_ETIMEDOUT   APR_OS_START_USERERR + 5
+
+#define TCN_LOG_EMERG  1
+#define TCN_LOG_ERROR  2
+#define TCN_LOG_NOTICE 3
+#define TCN_LOG_WARN   4
+#define TCN_LOG_INFO   5
+#define TCN_LOG_DEBUG  6
+
+#define TCN_ERROR_WRAP(E)                   \
+    if (APR_STATUS_IS_TIMEUP(E))            \
+        (E) = TCN_TIMEUP;                   \
+    else if (APR_STATUS_IS_EAGAIN(E))       \
+        (E) = TCN_EAGAIN;                   \
+    else if (APR_STATUS_IS_EINTR(E))        \
+        (E) = TCN_EINTR;                    \
+    else if (APR_STATUS_IS_EINPROGRESS(E))  \
+        (E) = TCN_EINPROGRESS;              \
+    else if (APR_STATUS_IS_ETIMEDOUT(E))    \
+        (E) = TCN_ETIMEDOUT;                \
+    else                                    \
+        (E) = (E)
+
+#define TCN_CLASS_PATH  "org/apache/tomcat/jni/"
+#define TCN_FINFO_CLASS TCN_CLASS_PATH "FileInfo"
+#define TCN_AINFO_CLASS TCN_CLASS_PATH "Sockaddr"
+#define TCN_ERROR_CLASS TCN_CLASS_PATH "Error"
+#define TCN_PARENT_IDE  "TCN_PARENT_ID"
+
+#define UNREFERENCED(P)      (P) = (P)
+#define UNREFERENCED_STDARGS e = e; o = o
+#ifdef WIN32
+#define LLT(X) (X)
+#else
+#define LLT(X) ((long)(X))
+#endif
+#define P2J(P)          ((jlong)LLT(P))
+#define J2P(P, T)       ((T)LLT((jlong)P))
+/* On stack buffer size */
+#define TCN_BUFFER_SZ   8192
+#define TCN_STDARGS     JNIEnv *e, jobject o
+#define TCN_IMPARGS     JNIEnv *e, jobject o, void *sock
+#define TCN_IMPCALL(X)  e, o, X->opaque
+
+#define TCN_IMPLEMENT_CALL(RT, CL, FN)  \
+    JNIEXPORT RT JNICALL Java_org_apache_tomcat_jni_##CL##_##FN
+
+#define TCN_IMPLEMENT_METHOD(RT, FN)    \
+    static RT method_##FN
+
+#define TCN_GETNET_METHOD(FN)  method_##FN
+
+#define TCN_SOCKET_UNKNOWN  0
+#define TCN_SOCKET_APR      1
+#define TCN_SOCKET_SSL      2
+#define TCN_SOCKET_UNIX     3
+#define TCN_SOCKET_NTPIPE   4
+
+#define TCN_SOCKET_GET_POOL 0
+#define TCN_SOCKET_GET_IMPL 1
+#define TCN_SOCKET_GET_APRS 2
+#define TCN_SOCKET_GET_TYPE 3
+
+typedef struct {
+    int type;
+    apr_status_t (*cleanup)(void *);
+    apr_status_t (APR_THREAD_FUNC *close) (apr_socket_t *);
+    apr_status_t (APR_THREAD_FUNC *shutdown) (apr_socket_t *, apr_shutdown_how_e);
+    apr_status_t (APR_THREAD_FUNC *opt_get)(apr_socket_t *, apr_int32_t, apr_int32_t *);
+    apr_status_t (APR_THREAD_FUNC *opt_set)(apr_socket_t *, apr_int32_t, apr_int32_t);
+    apr_status_t (APR_THREAD_FUNC *timeout_get)(apr_socket_t *, apr_interval_time_t *);
+    apr_status_t (APR_THREAD_FUNC *timeout_set)(apr_socket_t *, apr_interval_time_t);
+    apr_status_t (APR_THREAD_FUNC *send) (apr_socket_t *, const char *, apr_size_t *);
+    apr_status_t (APR_THREAD_FUNC *sendv)(apr_socket_t *, const struct iovec *, apr_int32_t, apr_size_t *);
+    apr_status_t (APR_THREAD_FUNC *recv) (apr_socket_t *, char *, apr_size_t *);
+} tcn_nlayer_t;
+
+typedef struct {
+    apr_pool_t   *pool;
+    apr_socket_t *sock;
+    void         *opaque;
+    char         *jsbbuff;
+    char         *jrbbuff;
+    tcn_nlayer_t *net;
+} tcn_socket_t;
+
+/* Private helper functions */
+void            tcn_Throw(JNIEnv *, const char *, ...);
+void            tcn_ThrowException(JNIEnv *, const char *);
+void            tcn_ThrowMemoryException(JNIEnv *, const char *, int, const char *);
+void            tcn_ThrowAPRException(JNIEnv *, apr_status_t);
+jstring         tcn_new_string(JNIEnv *, const char *);
+jstring         tcn_new_stringn(JNIEnv *, const char *, size_t);
+jbyteArray      tcn_new_arrayb(JNIEnv *, const unsigned char *, size_t);
+jobjectArray    tcn_new_arrays(JNIEnv *env, size_t len);
+char           *tcn_get_string(JNIEnv *, jstring);
+char           *tcn_strdup(JNIEnv *, jstring);
+char           *tcn_pstrdup(JNIEnv *, jstring, apr_pool_t *);
+apr_status_t    tcn_load_finfo_class(JNIEnv *, jclass);
+apr_status_t    tcn_load_ainfo_class(JNIEnv *, jclass);
+
+#define J2S(V)  c##V
+#define J2L(V)  p##V
+
+#define J2T(T) (apr_time_t)((T))
+
+#define TCN_BEGIN_MACRO     if (1) {
+#define TCN_END_MACRO       } else (void)(0)
+
+#define TCN_ALLOC_CSTRING(V)     \
+    const char *c##V = V ? (const char *)((*e)->GetStringUTFChars(e, V, 0)) : NULL
+
+#define TCN_FREE_CSTRING(V)      \
+    if (c##V) (*e)->ReleaseStringUTFChars(e, V, c##V)
+
+#define TCN_ALLOC_JSTRING(V)     \
+    char *c##V = tcn_get_string(e, (V))
+
+#define AJP_TO_JSTRING(V)   (*e)->NewStringUTF((e), (V))
+
+#define TCN_FREE_JSTRING(V)      \
+    TCN_BEGIN_MACRO              \
+        if (c##V)                \
+            free(c##V);          \
+    TCN_END_MACRO
+
+#define TCN_CHECK_ALLOCATED(x)                              \
+        if (x == NULL) {                                    \
+            tcn_ThrowMemoryException(e, __FILE__, __LINE__, \
+            "APR memory allocation failed");                \
+            goto cleanup;                                   \
+        } else (void)(0)
+
+#define TCN_THROW_IF_ERR(x, r)                  \
+    TCN_BEGIN_MACRO                             \
+        apr_status_t R = (x);                   \
+        if (R != APR_SUCCESS) {                 \
+            tcn_ThrowAPRException(e, R);        \
+            (r) = 0;                            \
+            goto cleanup;                       \
+        }                                       \
+    TCN_END_MACRO
+
+#define TCN_THROW_OS_ERROR(E)   \
+    tcn_ThrowAPRException((E), apr_get_os_error())
+
+#define TCN_LOAD_CLASS(E, C, N, R)                  \
+    TCN_BEGIN_MACRO                                 \
+        jclass _##C = (*(E))->FindClass((E), N);    \
+        if (_##C == NULL) {                         \
+            (*(E))->ExceptionClear((E));            \
+            return R;                               \
+        }                                           \
+        C = (*(E))->NewGlobalRef((E), _##C);        \
+        (*(E))->DeleteLocalRef((E), _##C);          \
+    TCN_END_MACRO
+
+#define TCN_UNLOAD_CLASS(E, C)                      \
+        (*(E))->DeleteGlobalRef((E), (C))
+
+#define TCN_IS_NULL(E, O)                           \
+        ((*(E))->IsSameObject((E), (O), NULL) == JNI_TRUE)
+
+#define TCN_GET_METHOD(E, C, M, N, S, R)            \
+    TCN_BEGIN_MACRO                                 \
+        M = (*(E))->GetMethodID((E), C, N, S);      \
+        if (M == NULL) {                            \
+            return R;                               \
+        }                                           \
+    TCN_END_MACRO
+
+#define TCN_MAX_METHODS 8
+
+typedef struct {
+    jobject     obj;
+    jmethodID   mid[TCN_MAX_METHODS];
+    void        *opaque;
+} tcn_callback_t;
+
+#define TCN_MIN(a, b) ((a) < (b) ? (a) : (b))
+#define TCN_MAX(a, b) ((a) > (b) ? (a) : (b))
+
+#ifdef WIN32
+#define TCN_ALLOC_WSTRING(V)     \
+    jsize wl##V = (*e)->GetStringLength(e, V);   \
+    const jchar *ws##V = V ? (const jchar *)((*e)->GetStringChars(e, V, 0)) : NULL; \
+    jchar *w##V = NULL
+
+#define TCN_INIT_WSTRING(V)                                     \
+        w##V = (jchar *)malloc((wl##V + 1) * sizeof(jchar));    \
+        wcsncpy(w##V, ws##V, wl##V);                        \
+        w##V[wl##V] = 0
+
+#define TCN_FREE_WSTRING(V)      \
+    if (ws##V) (*e)->ReleaseStringChars(e, V, ws##V); \
+    if (ws##V) free (w##V)
+
+#define J2W(V)  w##V
+
+#endif
+
+#if  !APR_HAVE_IPV6
+#define APR_INET6 APR_INET
+#endif
+
+#define GET_S_FAMILY(T, F)           \
+    if (F == 0) T = APR_UNSPEC;      \
+    else if (F == 1) T = APR_INET;   \
+    else if (F == 2) T = APR_INET6;  \
+    else T = F
+
+#define GET_S_TYPE(T, F)             \
+    if (F == 0) T = SOCK_STREAM;     \
+    else if (F == 1) T = SOCK_DGRAM; \
+    else T = F
+
+#endif /* TCN_H */

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/include/tcn_api.h
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/include/tcn_api.h	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/include/tcn_api.h	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,166 @@
+/* Copyright 2000-2005 The Apache Software Foundation
+ *
+ * Licensed 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.
+ */
+
+/*
+ *
+ * @author Mladen Turk
+ * @version $Revision: 439960 $, $Date: 2006-09-04 02:15:58 -0500 (Mon, 04 Sep 2006) $
+ */
+
+#ifndef TCN_API_H
+#define TCN_API_H
+
+#include "apr.h"
+#include "apr_general.h"
+#include "apr_pools.h"
+#include "apr_portable.h"
+#include "apr_network_io.h"
+#include "apr_strings.h"
+
+#ifndef APR_HAS_THREADS
+#error "Missing APR_HAS_THREADS support from APR."
+#endif
+#include <jni.h>
+
+/**
+ * TCN_DECLARE_EXPORT is defined when building the TCN dynamic library,
+ * so that all public symbols are exported.
+ *
+ * TCN_DECLARE_STATIC is defined when including the TCN public headers,
+ * to provide static linkage when the dynamic library may be unavailable.
+ *
+ * TCN_DECLARE_STATIC and TCN_DECLARE_EXPORT are left undefined when
+ * including the TCN public headers, to import and link the symbols from
+ * the dynamic TCN library and assure appropriate indirection and calling
+ * conventions at compile time.
+ */
+
+#if !defined(WIN32)
+/**
+ * The public TCN functions are declared with TCN_DECLARE(), so they may
+ * use the most appropriate calling convention.  Public APR functions with
+ * variable arguments must use TCN_DECLARE_NONSTD().
+ *
+ * @deffunc TCN_DECLARE(rettype) apr_func(args);
+ */
+#define TCN_DECLARE(type)            type
+/**
+ * The public TCN functions using variable arguments are declared with
+ * TCN_DECLARE_NONSTD(), as they must use the C language calling convention.
+ *
+ * @deffunc TCN_DECLARE_NONSTD(rettype) apr_func(args, ...);
+ */
+#define TCN_DECLARE_NONSTD(type)     type
+/**
+ * The public TCN variables are declared with TCN_DECLARE_DATA.
+ * This assures the appropriate indirection is invoked at compile time.
+ *
+ * @deffunc TCN_DECLARE_DATA type apr_variable;
+ * @tip extern TCN_DECLARE_DATA type apr_variable; syntax is required for
+ * declarations within headers to properly import the variable.
+ */
+#define TCN_DECLARE_DATA
+#elif defined(TCN_DECLARE_STATIC)
+#define TCN_DECLARE(type)            type __stdcall
+#define TCN_DECLARE_NONSTD(type)     type
+#define TCN_DECLARE_DATA
+#elif defined(TCN_DECLARE_EXPORT)
+#define TCN_DECLARE(type)            __declspec(dllexport) type __stdcall
+#define TCN_DECLARE_NONSTD(type)     __declspec(dllexport) type
+#define TCN_DECLARE_DATA             __declspec(dllexport)
+#else
+/**
+ * The public TCN functions are declared with TCN_DECLARE(), so they may
+ * use the most appropriate calling convention.  Public APR functions with
+ * variable arguments must use TCN_DECLARE_NONSTD().
+ *
+ */
+#define TCN_DECLARE(type)            __declspec(dllimport) type __stdcall
+/**
+ * The public TCN functions using variable arguments are declared with
+ * TCN_DECLARE_NONSTD(), as they must use the C language calling convention.
+ *
+ */
+#define TCN_DECLARE_NONSTD(type)     __declspec(dllimport) type
+/**
+ * The public TCN variables are declared with TCN_DECLARE_DATA.
+ * This assures the appropriate indirection is invoked at compile time.
+ *
+ * @remark extern TCN_DECLARE_DATA type apr_variable; syntax is required for
+ * declarations within headers to properly import the variable.
+ */
+#define TCN_DECLARE_DATA             __declspec(dllimport)
+#endif
+
+#if !defined(WIN32) || defined(TCN_MODULE_DECLARE_STATIC)
+/**
+ * Declare a dso module's exported module structure as TCN_MODULE_DECLARE_DATA.
+ *
+ * Unless TCN_MODULE_DECLARE_STATIC is defined at compile time, symbols
+ * declared with TCN_MODULE_DECLARE_DATA are always exported.
+ * @code
+ * module TCN_MODULE_DECLARE_DATA mod_tag
+ * @endcode
+ */
+#if defined(WIN32)
+#define TCN_MODULE_DECLARE(type)            type __stdcall
+#else
+#define TCN_MODULE_DECLARE(type)            type
+#endif
+#define TCN_MODULE_DECLARE_NONSTD(type)     type
+#define TCN_MODULE_DECLARE_DATA
+#else
+/**
+ * TCN_MODULE_DECLARE_EXPORT is a no-op.  Unless contradicted by the
+ * TCN_MODULE_DECLARE_STATIC compile-time symbol, it is assumed and defined.
+ */
+#define TCN_MODULE_DECLARE_EXPORT
+#define TCN_MODULE_DECLARE(type)          __declspec(dllexport) type __stdcall
+#define TCN_MODULE_DECLARE_NONSTD(type)   __declspec(dllexport) type
+#define TCN_MODULE_DECLARE_DATA           __declspec(dllexport)
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @file tcn_api.h
+ * @brief
+ *
+ * Tomcat Native Public API
+ */
+
+/* Return global apr pool
+ */
+TCN_DECLARE(apr_pool_t *) tcn_get_global_pool(void);
+
+/* Return global String class
+ */
+TCN_DECLARE(jclass) tcn_get_string_class(void);
+
+/* Return global JVM initalized on JNI_OnLoad
+ */
+TCN_DECLARE(JavaVM *) tcn_get_java_vm(void);
+
+/* Get current thread JNIEnv
+ */
+TCN_DECLARE(jint) tcn_get_java_env(JNIEnv **);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* TCN_API_H */

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/include/tcn_version.h
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/include/tcn_version.h	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/include/tcn_version.h	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,98 @@
+/* Copyright 2000-2005 The Apache Software Foundation
+ *
+ * Licensed 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.
+ */
+
+/*
+ *
+ * @author Mladen Turk
+ * @version $Revision: 441018 $, $Date: 2006-09-07 03:28:19 -0500 (Thu, 07 Sep 2006) $
+ */
+
+#ifndef TCN_VERSION_H
+#define TCN_VERSION_H
+
+#include "apr_version.h"
+
+#include "tcn.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @file tcn_version.h
+ * @brief
+ *
+ * Tomcat Native Version
+ *
+ * There are several different mechanisms for accessing the version. There
+ * is a string form, and a set of numbers; in addition, there are constants
+ * which can be compiled into your application, and you can query the library
+ * being used for its actual version.
+ *
+ * Note that it is possible for an application to detect that it has been
+ * compiled against a different version of APU by use of the compile-time
+ * constants and the use of the run-time query function.
+ *
+ * TCN version numbering follows the guidelines specified in:
+ *
+ *     http://apr.apache.org/versioning.html
+ */
+
+/* The numeric compile-time version constants. These constants are the
+ * authoritative version numbers for TCN.
+ */
+
+/** major version
+ * Major API changes that could cause compatibility problems for older
+ * programs such as structure size changes.  No binary compatibility is
+ * possible across a change in the major version.
+ */
+#define TCN_MAJOR_VERSION       1
+
+/**
+ * Minor API changes that do not cause binary compatibility problems.
+ * Should be reset to 0 when upgrading TCN_MAJOR_VERSION
+ */
+#define TCN_MINOR_VERSION       1
+
+/** patch level */
+#define TCN_PATCH_VERSION       5
+
+/**
+ *  This symbol is defined for internal, "development" copies of TCN. This
+ *  symbol will be #undef'd for releases.
+ */
+#define TCN_IS_DEV_VERSION
+
+
+/** The formatted string of APU's version */
+#define TCN_VERSION_STRING \
+     APR_STRINGIFY(TCN_MAJOR_VERSION) "."\
+     APR_STRINGIFY(TCN_MINOR_VERSION) "."\
+     APR_STRINGIFY(TCN_PATCH_VERSION)\
+     TCN_IS_DEV_STRING
+
+/** Internal: string form of the "is dev" flag */
+#ifdef TCN_IS_DEV_VERSION
+#define TCN_IS_DEV_STRING "-dev"
+#else
+#define TCN_IS_DEV_STRING ""
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* TCN_VERSION_H */

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/libtcnative.dsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/libtcnative.dsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/libtcnative.dsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,231 @@
+# Microsoft Developer Studio Project File - Name="libtcnative" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
+
+CFG=libtcnative - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE 
+!MESSAGE NMAKE /f "libtcnative.mak".
+!MESSAGE 
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE 
+!MESSAGE NMAKE /f "libtcnative.mak" CFG="libtcnative - Win32 Debug"
+!MESSAGE 
+!MESSAGE Possible choices for configuration are:
+!MESSAGE 
+!MESSAGE "libtcnative - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "libtcnative - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE 
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+MTL=midl.exe
+RSC=rc.exe
+
+!IF  "$(CFG)" == "libtcnative - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MD /W3 /Zi /O2 /Oy- /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /FD /c
+# ADD CPP /nologo /MD /W3 /Zi /O2 /Oy- /I "./include" /I "../apr/include" /I "../apr/include/arch/win32" /I "$(JAVA_HOME)/include" /I "$(JAVA_HOME)/include/win32" /I "../openssl/inc32" /D "NDEBUG" /D "TCN_DECLARE_EXPORT" /D "WIN32" /D "_WINDOWS" /D "NO_IDEA" /D "NO_RC5" /D "NO_MDC2" /D "OPENSSL_NO_IDEA" /D "OPENSSL_NO_RC5" /D "OPENSSL_NO_MDC2" /D "HAVE_OPENSSL" /D HAVE_SSL_SET_STATE=1 /Fd"Release\libtcnative_src" /FD /c
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /o /win32 "NUL"
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /o /win32 "NUL"
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib advapi32.lib ws2_32.lib mswsock.lib wldap32.lib psapi.lib ole32.lib shlwapi.lib /nologo /base:"0x6EE00000" /subsystem:windows /dll /debug /machine:I386 /opt:ref
+# ADD LINK32 kernel32.lib advapi32.lib ws2_32.lib mswsock.lib wldap32.lib psapi.lib ole32.lib shlwapi.lib libeay32.lib ssleay32.lib /nologo /base:"0x6EE00000" /subsystem:windows /dll /debug /machine:I386 /out:"Release/libtcnative-1.dll" /libpath:"../openssl/out32" /libpath:"../openssl/out32dll" /opt:ref
+
+!ELSEIF  "$(CFG)" == "libtcnative - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MDd /W3 /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FD /c
+# ADD CPP /nologo /MDd /W4 /GX /Zi /Od /I "./include" /I "../apr/include" /I "../apr/include/arch/win32" /I "$(JAVA_HOME)/include" /I "$(JAVA_HOME)/include/win32" /I "../openssl/inc32" /D "_DEBUG" /D "TCN_DECLARE_EXPORT" /D "WIN32" /D "_WINDOWS" /D "NO_IDEA" /D "NO_RC5" /D "NO_MDC2" /D "OPENSSL_NO_IDEA" /D "OPENSSL_NO_RC5" /D "OPENSSL_NO_MDC2" /D "HAVE_OPENSSL" /D HAVE_SSL_SET_STATE=1 /Fd"Debug\libtcnative_src" /FD /c
+# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /o /win32 "NUL"
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /o /win32 "NUL"
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib advapi32.lib ws2_32.lib mswsock.lib wldap32.lib psapi.lib ole32.lib shlwapi.lib /nologo /base:"0x6EE00000" /subsystem:windows /dll /incremental:no /debug /machine:I386
+# ADD LINK32 kernel32.lib advapi32.lib ws2_32.lib mswsock.lib wldap32.lib psapi.lib ole32.lib shlwapi.lib libeay32.lib ssleay32.lib /nologo /base:"0x6EE00000" /subsystem:windows /dll /incremental:no /debug /machine:I386 /out:"Debug/libtcnative-1.dll" /libpath:"../openssl/out32" /libpath:"../openssl/out32dll"
+
+!ENDIF 
+
+# Begin Target
+
+# Name "libtcnative - Win32 Release"
+# Name "libtcnative - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=.\src\address.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\dir.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\error.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\file.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\info.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\jnilib.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\lock.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\misc.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\mmap.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\multicast.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\network.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\poll.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\pool.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\proc.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\shm.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\ssl.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\sslcontext.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\sslinfo.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\sslnetwork.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\sslutils.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\stdlib.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\thread.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\user.c
+# End Source File
+# End Group
+# Begin Group "Generated Files"
+
+# PROP Default_Filter ""
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=.\include\ssl_private.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\include\tcn.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\include\tcn_api.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\include\tcn_version.h
+# End Source File
+# End Group
+# Begin Group "Platform Files"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=.\os\win32\ntpipe.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\os\win32\registry.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\os\win32\system.c
+# End Source File
+# End Group
+# Begin Source File
+
+SOURCE=.\os\win32\libtcnative.rc
+# End Source File
+# End Target
+# End Project

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/libtcnative.dsw
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/libtcnative.dsw	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/libtcnative.dsw	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,71 @@
+Microsoft Developer Studio Workspace File, Format Version 6.00
+# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
+
+###############################################################################
+
+Project: "apr"=..\apr\apr.dsp - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Project: "libapr"=..\apr\libapr.dsp - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Project: "libtcnative"=.\libtcnative.dsp - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+    Begin Project Dependency
+    Project_Dep_Name libapr
+    End Project Dependency
+}}}
+
+###############################################################################
+
+Project: "tcnative"=.\tcnative.dsp - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+    Begin Project Dependency
+    Project_Dep_Name apr
+    End Project Dependency
+}}}
+
+###############################################################################
+
+Global:
+
+Package=<5>
+{{{
+}}}
+
+Package=<3>
+{{{
+}}}
+
+###############################################################################
+

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/os/netware/system.c
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/os/netware/system.c	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/os/netware/system.c	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,44 @@
+/* Copyright 2000-2005 The Apache Software Foundation
+ *
+ * Licensed 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.
+ */
+
+/*
+ *
+ * @author Mladen Turk
+ * @version $Revision: 300969 $, $Date: 2005-07-12 09:56:11 -0500 (Tue, 12 Jul 2005) $
+ */
+ 
+#include "apr.h"
+#include "apr_pools.h"
+#include "apr_network_io.h"
+#include "apr_poll.h"
+
+#include "tcn.h"
+
+TCN_IMPLEMENT_CALL(jboolean, OS, is)(TCN_STDARGS, jint type)
+{
+    UNREFERENCED_STDARGS;
+    if (type == 2)
+        return JNI_TRUE;
+    else
+        return JNI_FALSE;
+}
+
+TCN_IMPLEMENT_CALL(jint, OS, info)(TCN_STDARGS,
+                                   jlongArray inf)
+{
+    UNREFERENCED_STDARGS;
+    UNREFERENCED(inf);
+    return APR_ENOTIMPL;
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/os/unix/system.c
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/os/unix/system.c	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/os/unix/system.c	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,384 @@
+/* Copyright 2000-2005 The Apache Software Foundation
+ *
+ * Licensed 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.
+ */
+
+/*
+ *
+ * @author Mladen Turk
+ * @version $Revision: 405933 $, $Date: 2006-05-12 18:13:44 -0500 (Fri, 12 May 2006) $
+ */
+
+#include "apr.h"
+#include "apr_pools.h"
+#include "apr_network_io.h"
+#include "apr_poll.h"
+
+#include "tcn.h"
+#if defined(__linux__)
+#include <sys/sysinfo.h>
+#elif defined(sun)
+#include <unistd.h>
+#include <sys/swap.h>
+#include <procfs.h>
+#include <kstat.h>
+#include <sys/sysinfo.h>
+#endif
+
+#if defined(DARWIN)
+#include <mach/mach_init.h>
+#include <mach/mach_host.h>
+#include <mach/host_info.h>
+#include <sys/sysctl.h>
+#include <sys/stat.h>
+#endif
+
+#include <syslog.h>
+#include <stdarg.h>
+
+#ifndef LOG_WARN
+#define LOG_WARN LOG_WARNING
+#endif
+
+#if defined(sun)
+#define MAX_PROC_PATH_LEN 64
+#define MAX_CPUS 512
+#define PSINFO_T_SZ sizeof(psinfo_t)
+#define PRUSAGE_T_SZ sizeof(prusage_t)
+
+static int proc_open(const char *type)
+{
+    char proc_path[MAX_PROC_PATH_LEN+1];
+
+    sprintf(proc_path, "/proc/self/%s", type);
+    return open(proc_path, O_RDONLY);
+}
+
+static int proc_read(void *buf, const size_t size, int filedes)
+{
+    ssize_t bytes;
+
+    if (filedes >= 0) {
+        bytes = pread(filedes, buf, size, 0);
+        if (bytes != size)
+            return -1;
+        else
+            return 0;
+    }
+    else
+        return -1;
+}
+
+#endif
+
+TCN_IMPLEMENT_CALL(jboolean, OS, is)(TCN_STDARGS, jint type)
+{
+    UNREFERENCED_STDARGS;
+    if (type == 1)
+        return JNI_TRUE;
+#if defined(__linux__)
+    else if (type == 5)
+        return JNI_TRUE;
+#endif
+#if defined(sun)
+    else if (type == 6)
+        return JNI_TRUE;
+#endif
+#if defined(__FreeBSD__) || defined(__NetBSD__)
+    else if (type == 7)
+        return JNI_TRUE;
+#endif
+    else
+        return JNI_FALSE;
+}
+
+TCN_IMPLEMENT_CALL(jint, OS, info)(TCN_STDARGS,
+                                   jlongArray inf)
+{
+    jint rv;
+    int  i;
+    jsize ilen = (*e)->GetArrayLength(e, inf);
+    jlong *pvals = (*e)->GetLongArrayElements(e, inf, NULL);
+
+    UNREFERENCED(o);
+    if (ilen < 16) {
+        return APR_EINVAL;
+    }
+    for (i = 0; i < 16; i++)
+        pvals[i] = 0;
+#if defined(__linux__)
+    {
+        struct sysinfo info;
+        if (sysinfo(&info))
+            rv = apr_get_os_error();
+        else {
+            pvals[0] = (jlong)(info.totalram  * info.mem_unit);
+            pvals[1] = (jlong)(info.freeram   * info.mem_unit);
+            pvals[2] = (jlong)(info.totalswap * info.mem_unit);
+            pvals[3] = (jlong)(info.freeswap  * info.mem_unit);
+            pvals[4] = (jlong)(info.sharedram * info.mem_unit);
+            pvals[5] = (jlong)(info.bufferram * info.mem_unit);
+            pvals[6] = (jlong)(100 - (info.freeram * 100 / info.totalram));
+            rv = APR_SUCCESS;
+        }
+    }
+#elif defined(sun)
+    {
+        /* static variables with basic procfs info */
+        static long creation = 0;              /* unix timestamp of process creation */
+        static int psinf_fd = 0;               /* file descriptor for the psinfo procfs file */
+        static int prusg_fd = 0;               /* file descriptor for the usage procfs file */
+        static size_t rss = 0;                 /* maximum of resident set size from previous calls */
+        /* static variables with basic kstat info */
+        static kstat_ctl_t *kstat_ctl = NULL;  /* kstat control object, only initialized once */
+        static kstat_t *kstat_cpu[MAX_CPUS];   /* array of kstat objects for per cpu statistics */
+        static int cpu_count = 0;              /* number of cpu structures found in kstat */
+        static kid_t kid = 0;                  /* kstat ID, for which the kstat_ctl holds the correct chain */
+        /* non-static variables - general use */
+        int res = 0;                           /* general result state */
+        /* non-static variables - sysinfo/swapctl use */
+        long ret_sysconf;                      /* value returned from sysconf call */
+        long tck_dividend;                     /* factor used by transforming tick numbers to milliseconds */
+        long tck_divisor;                      /* divisor used by transforming tick numbers to milliseconds */
+        long sys_pagesize = sysconf(_SC_PAGESIZE); /* size of a system memory page in bytes */
+        long sys_clk_tck = sysconf(_SC_CLK_TCK); /* number of system ticks per second */
+        struct anoninfo info;                  /* structure for information about sizes in anonymous memory system */
+        /* non-static variables - procfs use */
+        psinfo_t psinf;                        /* psinfo structure from procfs */
+        prusage_t prusg;                       /* usage structure from procfs */
+        size_t new_rss = 0;                    /* resident set size read from procfs */
+        time_t now;                            /* time needed for calculating process creation time */
+        /* non-static variables - kstat use */
+        kstat_t *kstat = NULL;                 /* kstat working pointer */
+        cpu_sysinfo_t cpu;                     /* cpu sysinfo working pointer */
+        kid_t new_kid = 0;                     /* kstat ID returned from chain update */
+        int new_kstat = 0;                     /* flag indicating, if kstat structure has changed since last call */
+
+        rv = APR_SUCCESS;
+
+        if (sys_pagesize <= 0) {
+            rv = apr_get_os_error();
+        }
+        else {
+            ret_sysconf = sysconf(_SC_PHYS_PAGES);
+            if (ret_sysconf >= 0) {
+                pvals[0] = (jlong)((jlong)sys_pagesize * ret_sysconf);
+            }
+            else {
+                rv = apr_get_os_error();
+            }
+            ret_sysconf = sysconf(_SC_AVPHYS_PAGES);
+            if (ret_sysconf >= 0) {
+                pvals[1] = (jlong)((jlong)sys_pagesize * ret_sysconf);
+            }
+            else {
+                rv = apr_get_os_error();
+            }
+            res=swapctl(SC_AINFO, &info);
+            if (res >= 0) {
+                pvals[2] = (jlong)((jlong)sys_pagesize * info.ani_max);
+                pvals[3] = (jlong)((jlong)sys_pagesize * info.ani_free);
+                pvals[6] = (jlong)(100 - (jlong)info.ani_free * 100 / info.ani_max);
+            }
+            else {
+                rv = apr_get_os_error();
+            }
+        }
+
+        if (psinf_fd == 0) {
+            psinf_fd = proc_open("psinfo");
+        }
+        res = proc_read(&psinf, PSINFO_T_SZ, psinf_fd);
+        if (res >= 0) {
+            new_rss = psinf.pr_rssize*1024;
+            pvals[13] = (jlong)(new_rss);
+            if (new_rss > rss) {
+                rss = new_rss;
+            }
+            pvals[14] = (jlong)(rss);
+        }
+        else {
+            psinf_fd = 0;
+            rv = apr_get_os_error();
+        }
+        if (prusg_fd == 0) {
+            prusg_fd = proc_open("usage");
+        }
+        res = proc_read(&prusg, PRUSAGE_T_SZ, prusg_fd);
+        if (res >= 0) {
+            if (creation <= 0) {
+                time(&now);
+                creation = (long)(now - (prusg.pr_tstamp.tv_sec -
+                                         prusg.pr_create.tv_sec));
+            }
+            pvals[10] = (jlong)(creation);
+            pvals[11] = (jlong)((jlong)prusg.pr_stime.tv_sec * 1000 +
+                                (prusg.pr_stime.tv_nsec / 1000000));
+            pvals[12] = (jlong)((jlong)prusg.pr_utime.tv_sec * 1000 +
+                                (prusg.pr_utime.tv_nsec / 1000000));
+            pvals[15] = (jlong)(prusg.pr_majf);
+        }
+        else {
+            prusg_fd = 0;
+            rv = apr_get_os_error();
+        }
+
+        if (sys_clk_tck <= 0) {
+            rv = apr_get_os_error();
+        }
+        else {
+            tck_dividend = 1000;
+            tck_divisor = sys_clk_tck;
+            for (i = 0; i < 3; i++) {
+                if (tck_divisor % 2 == 0) {
+                    tck_divisor = tck_divisor / 2;
+                    tck_dividend = tck_dividend / 2;
+                }
+                if (tck_divisor % 5 == 0) {
+                    tck_divisor = tck_divisor / 5;
+                    tck_dividend = tck_dividend / 5;
+                }
+            }
+            if (kstat_ctl == NULL) {
+                kstat_ctl = kstat_open();
+                kid = kstat_ctl->kc_chain_id;
+                new_kstat = 1;
+            } else {
+                new_kid = kstat_chain_update(kstat_ctl);
+                if (new_kid < 0) {
+                    res=kstat_close(kstat_ctl);
+                    kstat_ctl = kstat_open();
+                    kid = kstat_ctl->kc_chain_id;
+                    new_kstat = 1;
+                } else if (new_kid > 0 && kid != new_kid) {
+                    kid = new_kid;
+                    new_kstat = 1;
+                }
+            }
+            if (new_kstat) {
+                cpu_count = 0;
+                for (kstat = kstat_ctl->kc_chain; kstat; kstat = kstat->ks_next) {
+                    if (strncmp(kstat->ks_name, "cpu_stat", 8) == 0) {
+                        kstat_cpu[cpu_count++]=kstat;
+                    }
+                }
+            }
+            for (i = 0; i < cpu_count; i++) {
+                new_kid = kstat_read(kstat_ctl, kstat_cpu[i], NULL);
+                if (new_kid >= 0) {
+                    cpu = ((cpu_stat_t *)kstat_cpu[i]->ks_data)->cpu_sysinfo;
+                    if ( tck_divisor == 1 ) {
+                        pvals[7] += (jlong)(((jlong)cpu.cpu[CPU_IDLE]) * tck_dividend);
+                        pvals[7] += (jlong)(((jlong)cpu.cpu[CPU_WAIT]) * tck_dividend);
+                        pvals[8] += (jlong)(((jlong)cpu.cpu[CPU_KERNEL]) * tck_dividend);
+                        pvals[9] += (jlong)(((jlong)cpu.cpu[CPU_USER]) * tck_dividend);
+                    } else {
+                        pvals[7] += (jlong)(((jlong)cpu.cpu[CPU_IDLE]) * tck_dividend / tck_divisor);
+                        pvals[7] += (jlong)(((jlong)cpu.cpu[CPU_WAIT]) * tck_dividend / tck_divisor);
+                        pvals[8] += (jlong)(((jlong)cpu.cpu[CPU_KERNEL]) * tck_dividend / tck_divisor);
+                        pvals[9] += (jlong)(((jlong)cpu.cpu[CPU_USER]) * tck_dividend / tck_divisor);
+                    }
+                }
+            }
+        }
+
+        /*
+         * The next two are not implemented yet for Solaris
+         * inf[4]  - Amount of shared memory
+         * inf[5]  - Memory used by buffers
+         *
+         */
+    }
+
+#elif defined(DARWIN)
+
+    uint64_t mem_total;
+    size_t len = sizeof(mem_total);
+
+    vm_statistics_data_t vm_info;
+    mach_msg_type_number_t info_count = HOST_VM_INFO_COUNT;
+
+    sysctlbyname("hw.memsize", &mem_total, &len, NULL, 0);
+    pvals[0] = (jlong)mem_total;
+
+    host_statistics(mach_host_self (), HOST_VM_INFO, (host_info_t)&vm_info, &info_count);
+    pvals[1] = (jlong)(((double)vm_info.free_count)*vm_page_size);
+    pvals[6] = (jlong)(100 - (pvals[1] * 100 / mem_total));
+    rv = APR_SUCCESS;
+
+/* DARWIN */
+#else
+    rv = APR_ENOTIMPL;
+#endif
+   (*e)->ReleaseLongArrayElements(e, inf, pvals, 0);
+    return rv;
+}
+
+#define LOG_MSG_DOMAIN                   "Native"
+
+
+TCN_IMPLEMENT_CALL(jstring, OS, expand)(TCN_STDARGS, jstring val)
+{
+    jstring str;
+    TCN_ALLOC_CSTRING(val);
+
+    UNREFERENCED(o);
+
+    /* TODO: Make ${ENVAR} expansion */
+    str = (*e)->NewStringUTF(e, J2S(val));
+
+    TCN_FREE_CSTRING(val);
+    return str;
+}
+
+TCN_IMPLEMENT_CALL(void, OS, sysloginit)(TCN_STDARGS, jstring domain)
+{
+    const char *d;
+    TCN_ALLOC_CSTRING(domain);
+
+    UNREFERENCED(o);
+    if ((d = J2S(domain)) == NULL)
+        d = LOG_MSG_DOMAIN;
+
+    openlog(d, LOG_CONS | LOG_PID, LOG_LOCAL0);
+    TCN_FREE_CSTRING(domain);
+}
+
+TCN_IMPLEMENT_CALL(void, OS, syslog)(TCN_STDARGS, jint level,
+                                     jstring msg)
+{
+    TCN_ALLOC_CSTRING(msg);
+    int id = LOG_DEBUG;
+    UNREFERENCED(o);
+
+    switch (level) {
+        case TCN_LOG_EMERG:
+            id = LOG_EMERG;
+        break;
+        case TCN_LOG_ERROR:
+            id = LOG_ERR;
+        break;
+        case TCN_LOG_NOTICE:
+            id = LOG_NOTICE;
+        break;
+        case TCN_LOG_WARN:
+            id = LOG_WARN;
+        break;
+        case TCN_LOG_INFO:
+            id = LOG_INFO;
+        break;
+    }
+    syslog (id, "%s", J2S(msg));
+
+    TCN_FREE_CSTRING(msg);
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/os/unix/uxpipe.c
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/os/unix/uxpipe.c	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/os/unix/uxpipe.c	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,354 @@
+/* Copyright 2000-2005 The Apache Software Foundation
+ *
+ * Licensed 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.
+ */
+
+/** UNIX AF_LOCAL network wrapper
+ *
+ * @author Mladen Turk
+ * @version $Revision: 300969 $, $Date: 2005-07-12 09:56:11 -0500 (Tue, 12 Jul 2005) $
+ */
+
+
+#include "tcn.h"
+#include "apr_thread_mutex.h"
+#include "apr_poll.h"
+
+/* ### should be tossed in favor of APR */
+#include <sys/stat.h>
+#include <sys/un.h> /* for sockaddr_un */
+
+#ifdef TCN_DO_STATISTICS
+#include "apr_atomic.h"
+
+static volatile apr_uint32_t uxp_created  = 0;
+static volatile apr_uint32_t uxp_closed   = 0;
+static volatile apr_uint32_t uxp_cleared  = 0;
+static volatile apr_uint32_t uxp_accepted = 0;
+
+void uxp_network_dump_statistics()
+{
+    fprintf(stderr, "NT Network Statistics ..\n");
+    fprintf(stderr, "Sockets created         : %d\n", uxp_created);
+    fprintf(stderr, "Sockets accepted        : %d\n", uxp_accepted);
+    fprintf(stderr, "Sockets closed          : %d\n", uxp_closed);
+    fprintf(stderr, "Sockets cleared         : %d\n", uxp_cleared);
+}
+
+#endif
+
+#define DEFNAME     "/var/run/tomcatnativesock"
+#define DEFNAME_FMT "/var/run/tomcatnativesock%08x%08x"
+#define DEFSIZE     8192
+#define DEFTIMEOUT  60000
+
+#define TCN_UXP_UNKNOWN     0
+#define TCN_UXP_CLIENT      1
+#define TCN_UXP_ACCEPTED    2
+#define TCN_UXP_SERVER      3
+
+#define TCN_UNIX_MAXPATH    1024
+typedef struct {
+    apr_pool_t          *pool;
+    apr_socket_t        *sock;               /* APR socket */
+    int                 sd;
+    struct sockaddr_un  uxaddr;
+    int                 timeout;
+    int                 mode;                 /* Client or server mode */
+    char                name[TCN_UNIX_MAXPATH+1];
+} tcn_uxp_conn_t;
+
+static apr_status_t APR_THREAD_FUNC
+uxp_socket_timeout_set(apr_socket_t *sock, apr_interval_time_t t)
+{
+    tcn_uxp_conn_t *con = (tcn_uxp_conn_t *)sock;
+    if (t < 0)
+        con->timeout = -1;
+    else
+        con->timeout = (int)(apr_time_as_msec(t));
+    return APR_SUCCESS;
+}
+
+static apr_status_t APR_THREAD_FUNC
+uxp_socket_timeout_get(apr_socket_t *sock, apr_interval_time_t *t)
+{
+    tcn_uxp_conn_t *con = (tcn_uxp_conn_t*)sock;
+    if (con->timeout < 0)
+        *t = -1;
+    else
+        *t = con->timeout * 1000;
+    return APR_SUCCESS;
+}
+
+static APR_INLINE apr_status_t APR_THREAD_FUNC
+uxp_socket_opt_set(apr_socket_t *sock, apr_int32_t opt, apr_int32_t on)
+{
+    tcn_uxp_conn_t *con = (tcn_uxp_conn_t *)sock;
+    return apr_socket_opt_set(con->sock, opt, on);
+}
+
+static APR_INLINE apr_status_t APR_THREAD_FUNC
+uxp_socket_opt_get(apr_socket_t *sock, apr_int32_t opt, apr_int32_t *on)
+{
+    tcn_uxp_conn_t *con = (tcn_uxp_conn_t *)sock;
+    return apr_socket_opt_get(con->sock, opt, on);
+}
+
+static apr_status_t uxp_cleanup(void *data)
+{
+    tcn_uxp_conn_t *con = (tcn_uxp_conn_t *)data;
+
+    if (con) {
+        if (con->sock) {
+            apr_socket_close(con->sock);
+            con->sock = NULL;
+        }
+        if (con->mode == TCN_UXP_SERVER) {
+            unlink(con->name);
+            con->mode = TCN_UXP_UNKNOWN;
+        }
+    }
+
+#ifdef TCN_DO_STATISTICS
+    apr_atomic_inc32(&uxp_cleared);
+#endif
+    return APR_SUCCESS;
+}
+
+static apr_status_t APR_THREAD_FUNC
+uxp_socket_shutdown(apr_socket_t *sock, apr_shutdown_how_e how)
+{
+    tcn_uxp_conn_t *con = (tcn_uxp_conn_t *)sock;
+    return apr_socket_shutdown(con->sock, how);
+}
+
+static apr_status_t APR_THREAD_FUNC
+uxp_socket_close(apr_socket_t *sock)
+{
+#ifdef TCN_DO_STATISTICS
+    apr_atomic_inc32(&uxp_closed);
+#endif
+    return uxp_cleanup(sock);
+}
+
+static apr_status_t APR_THREAD_FUNC
+uxp_socket_recv(apr_socket_t *sock, char *buf, apr_size_t *len)
+{
+    tcn_uxp_conn_t *con = (tcn_uxp_conn_t *)sock;
+    return apr_socket_recv(con->sock, buf, len);
+}
+
+
+static apr_status_t APR_THREAD_FUNC
+uxp_socket_send(apr_socket_t *sock, const char *buf,
+                apr_size_t *len)
+{
+    tcn_uxp_conn_t *con = (tcn_uxp_conn_t *)sock;
+    return apr_socket_send(con->sock, buf, len);
+}
+
+static apr_status_t APR_THREAD_FUNC
+uxp_socket_sendv(apr_socket_t *sock,
+                 const struct iovec *vec,
+                 apr_int32_t nvec, apr_size_t *len)
+{
+    tcn_uxp_conn_t *con = (tcn_uxp_conn_t *)sock;
+    return apr_socket_sendv(con->sock, vec, nvec, len);
+}
+
+static apr_status_t uxp_socket_cleanup(void *data)
+{
+    tcn_socket_t *s = (tcn_socket_t *)data;
+
+    if (s->net->cleanup) {
+        (*s->net->cleanup)(s->opaque);
+        s->net->cleanup = NULL;
+    }
+#ifdef TCN_DO_STATISTICS
+    apr_atomic_inc32(&uxp_cleared);
+#endif
+    return APR_SUCCESS;
+}
+
+static tcn_nlayer_t uxp_socket_layer = {
+    TCN_SOCKET_UNIX,
+    uxp_cleanup,
+    uxp_socket_close,
+    uxp_socket_shutdown,
+    uxp_socket_opt_get,
+    uxp_socket_opt_set,
+    uxp_socket_timeout_get,
+    uxp_socket_timeout_set,
+    uxp_socket_send,
+    uxp_socket_sendv,
+    uxp_socket_recv
+};
+
+TCN_IMPLEMENT_CALL(jlong, Local, create)(TCN_STDARGS, jstring name,
+                                         jlong pool)
+{
+    apr_pool_t *p = J2P(pool, apr_pool_t *);
+    tcn_socket_t   *s   = NULL;
+    tcn_uxp_conn_t *con = NULL;
+    int sd;
+    TCN_ALLOC_CSTRING(name);
+
+    UNREFERENCED(o);
+    TCN_ASSERT(pool != 0);
+
+    if ((sd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
+        tcn_ThrowAPRException(e, apr_get_netos_error());
+        return 0;
+    }
+#ifdef TCN_DO_STATISTICS
+    uxp_created++;
+#endif
+    con = (tcn_uxp_conn_t *)apr_pcalloc(p, sizeof(tcn_uxp_conn_t));
+    con->pool = p;
+    con->mode = TCN_UXP_UNKNOWN;
+    con->timeout = DEFTIMEOUT;
+    con->sd = sd;
+    con->uxaddr.sun_family = AF_UNIX;
+    if (J2S(name)) {
+        strcpy(con->uxaddr.sun_path, J2S(name));
+        TCN_FREE_CSTRING(name);
+    }
+    else
+        strcpy(con->uxaddr.sun_path, DEFNAME);
+    s = (tcn_socket_t *)apr_pcalloc(p, sizeof(tcn_socket_t));
+    s->pool   = p;
+    s->net    = &uxp_socket_layer;
+    s->opaque = con;
+    apr_pool_cleanup_register(p, (const void *)s,
+                              uxp_socket_cleanup,
+                              apr_pool_cleanup_null);
+
+    apr_os_sock_put(&(con->sock), &(con->sd), p);
+
+    return P2J(s);
+
+}
+
+TCN_IMPLEMENT_CALL(jint, Local, bind)(TCN_STDARGS, jlong sock,
+                                      jlong sa)
+{
+    tcn_socket_t *s = J2P(sock, tcn_socket_t *);
+    UNREFERENCED_STDARGS;
+    UNREFERENCED(sa);
+    TCN_ASSERT(sock != 0);
+    if (s->net->type == TCN_SOCKET_UNIX) {
+        int rc;
+        tcn_uxp_conn_t *c = (tcn_uxp_conn_t *)s->opaque;
+        c->mode = TCN_UXP_SERVER;
+        rc = bind(c->sd, (struct sockaddr *)&(c->uxaddr), sizeof(c->uxaddr));
+        if (rc < 0)
+            return errno;
+        else
+            return APR_SUCCESS;
+    }
+    else
+        return APR_EINVAL;
+}
+
+TCN_IMPLEMENT_CALL(jint, Local, listen)(TCN_STDARGS, jlong sock,
+                                        jint backlog)
+{
+    tcn_socket_t *s = J2P(sock, tcn_socket_t *);
+    UNREFERENCED_STDARGS;
+
+    TCN_ASSERT(sock != 0);
+    if (s->net->type == TCN_SOCKET_UNIX) {
+        tcn_uxp_conn_t *c = (tcn_uxp_conn_t *)s->opaque;
+        c->mode = TCN_UXP_SERVER;
+        return apr_socket_listen(c->sock, (apr_int32_t)backlog);
+    }
+    else
+        return APR_EINVAL;
+}
+
+TCN_IMPLEMENT_CALL(jlong, Local, accept)(TCN_STDARGS, jlong sock)
+{
+    tcn_socket_t *s = J2P(sock, tcn_socket_t *);
+    apr_pool_t   *p = NULL;
+    tcn_socket_t *a = NULL;
+    tcn_uxp_conn_t *con = NULL;
+
+    UNREFERENCED(o);
+    TCN_ASSERT(sock != 0);
+
+    TCN_THROW_IF_ERR(apr_pool_create(&p, s->pool), p);
+    if (s->net->type == TCN_SOCKET_UNIX) {
+        apr_socklen_t len;
+        tcn_uxp_conn_t *c = (tcn_uxp_conn_t *)s->opaque;
+        con = (tcn_uxp_conn_t *)apr_pcalloc(p, sizeof(tcn_uxp_conn_t));
+        con->pool = p;
+        con->mode = TCN_UXP_ACCEPTED;
+        con->timeout = c->timeout;
+        len = sizeof(c->uxaddr);
+        /* Block until a client connects */
+        con->sd = accept(c->sd, (struct sockaddr *)&(con->uxaddr), &len);
+        if (con->sd < 0) {
+            tcn_ThrowAPRException(e, apr_get_os_error());
+            goto cleanup;
+        }
+    }
+    else {
+        tcn_ThrowAPRException(e, APR_ENOTIMPL);
+        goto cleanup;
+    }
+    if (con) {
+#ifdef TCN_DO_STATISTICS
+        apr_atomic_inc32(&uxp_accepted);
+#endif
+        a = (tcn_socket_t *)apr_pcalloc(p, sizeof(tcn_socket_t));
+        a->pool   = p;
+	    a->net    = &uxp_socket_layer;
+        a->opaque = con;
+        apr_pool_cleanup_register(p, (const void *)a,
+                                  uxp_socket_cleanup,
+                                  apr_pool_cleanup_null);
+        apr_os_sock_put(&(con->sock), &(con->sd), p);
+    }
+    return P2J(a);
+cleanup:
+    if (p)
+        apr_pool_destroy(p);
+    return 0;
+}
+
+TCN_IMPLEMENT_CALL(jint, Local, connect)(TCN_STDARGS, jlong sock,
+                                         jlong sa)
+{
+    tcn_socket_t *s = J2P(sock, tcn_socket_t *);
+    tcn_uxp_conn_t *con = NULL;
+    int rc;
+
+    UNREFERENCED(o);
+    UNREFERENCED(sa);
+    TCN_ASSERT(sock != 0);
+    if (s->net->type != TCN_SOCKET_UNIX)
+        return APR_ENOTSOCK;
+    con = (tcn_uxp_conn_t *)s->opaque;
+    if (con->mode != TCN_UXP_UNKNOWN)
+        return APR_EINVAL;
+    do {
+        rc = connect(con->sd, (const struct sockaddr *)&(con->uxaddr),
+                     sizeof(con->uxaddr));
+    } while (rc == -1 && errno == EINTR);
+
+    if (rc == -1 && errno != EISCONN)
+        return errno;
+    con->mode = TCN_UXP_CLIENT;
+
+    return APR_SUCCESS;
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/os/win32/apache.ico
===================================================================
(Binary files differ)


Property changes on: branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/os/win32/apache.ico
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/os/win32/libtcnative.rc
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/os/win32/libtcnative.rc	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/os/win32/libtcnative.rc	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,69 @@
+#include <windows.h>
+
+LANGUAGE 0x9,0x1
+1 11 logmessages.bin
+
+#define TCN_COPYRIGHT "Copyright 2000-2006 The Apache Software " \
+                      "Foundation or its licensors, as applicable."
+
+#define TCN_LICENSE "Licensed 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\r\n\r\n" \
+                    "http://www.apache.org/licenses/LICENSE-2.0\r\n\r\n" \
+                    "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."
+
+#define TCN_VERISON "1.1.5"
+1000 ICON "apache.ico"
+
+1001 DIALOGEX 0, 0, 252, 51
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_CAPTION
+CAPTION "Password prompt"
+FONT 8, "MS Shell Dlg", 0, 0, 0x0
+BEGIN
+    ICON            1000,-1,8,6,21,20
+    LTEXT           "Some of your private key files are encrypted for security reasons.\nIn order to read them you have to provide the pass phrases.",
+                    -1,29,5,220,19
+    LTEXT           "Enter password:",-1,7,28,75,8
+    EDITTEXT        1002,67,27,174,12,ES_PASSWORD | ES_AUTOHSCROLL
+END
+
+1 VERSIONINFO
+ FILEVERSION 1,1,5,0
+ PRODUCTVERSION 1,1,5,0
+ FILEFLAGSMASK 0x3fL
+#ifdef _DEBUG
+ FILEFLAGS 0x1L
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS 0x40004L
+ FILETYPE 0x1L
+ FILESUBTYPE 0x0L
+BEGIN
+    BLOCK "StringFileInfo"
+    BEGIN
+        BLOCK "040904b0"
+        BEGIN
+            VALUE "Comments",  TCN_LICENSE "\0"
+            VALUE "CompanyName", "Apache Software Foundation\0"
+            VALUE "FileDescription", "Tomcat Native Java Library\0"
+            VALUE "FileVersion", TCN_VERISON "\0"
+            VALUE "InternalName", "libtcnative-1\0"
+            VALUE "LegalCopyright", TCN_COPYRIGHT "\0"
+            VALUE "OriginalFilename", "libtcnative-1.dll\0"
+            VALUE "ProductName", "Tomcat Native Java Library\0"
+            VALUE "ProductVersion", TCN_VERISON "\0"
+        END
+    END
+    BLOCK "VarFileInfo"
+    BEGIN
+        VALUE "Translation", 0x409, 1200
+    END
+END

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/os/win32/logmessages.bin
===================================================================
(Binary files differ)


Property changes on: branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/os/win32/logmessages.bin
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/os/win32/logmessages.mc
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/os/win32/logmessages.mc	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/os/win32/logmessages.mc	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,41 @@
+MessageId=0x1
+Severity=Error
+SymbolicName=LOG_MSG_EMERG
+Language=English
+Emerg: %1
+.
+
+MessageId=0x2
+Severity=Error
+SymbolicName=LOG_MSG_ERROR
+Language=English
+Error: %1
+.
+
+MessageId=0x3
+Severity=Warning
+SymbolicName=LOG_MSG_NOTICE
+Language=English
+Notice: %1
+.
+
+MessageId=0x4
+Severity=Warning
+SymbolicName=LOG_MSG_WARN
+Language=English
+Warn: %1
+.
+
+MessageId=0x5
+Severity=Informational
+SymbolicName=LOG_MSG_INFO
+Language=English
+Info: %1
+.
+
+MessageId=0x6
+Severity=Success
+SymbolicName=LOG_MSG_DEBUG
+Language=English
+Debug: %1
+.

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/os/win32/ntpipe.c
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/os/win32/ntpipe.c	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/os/win32/ntpipe.c	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,505 @@
+/* Copyright 2000-2005 The Apache Software Foundation
+ *
+ * Licensed 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.
+ */
+
+/** NT Pipes network wrapper
+ *
+ * @author Mladen Turk
+ * @version $Revision: 411550 $, $Date: 2006-06-04 07:06:09 -0500 (Sun, 04 Jun 2006) $
+ */
+
+
+#ifndef _WIN32_WINNT
+#define _WIN32_WINNT 0x0500
+#endif
+#define STRICT
+#include <winsock2.h>
+#include <mswsock.h>
+#include <ws2tcpip.h>
+#include <sddl.h>
+
+#include "tcn.h"
+#include "apr_thread_mutex.h"
+#include "apr_poll.h"
+
+#ifdef TCN_DO_STATISTICS
+#include "apr_atomic.h"
+
+static volatile apr_uint32_t ntp_created  = 0;
+static volatile apr_uint32_t ntp_closed   = 0;
+static volatile apr_uint32_t ntp_cleared  = 0;
+static volatile apr_uint32_t ntp_accepted = 0;
+
+void ntp_network_dump_statistics()
+{
+    fprintf(stderr, "NT Network Statistics ..\n");
+    fprintf(stderr, "Sockets created         : %d\n", ntp_created);
+    fprintf(stderr, "Sockets accepted        : %d\n", ntp_accepted);
+    fprintf(stderr, "Sockets closed          : %d\n", ntp_closed);
+    fprintf(stderr, "Sockets cleared         : %d\n", ntp_cleared);
+}
+
+#endif
+
+#define DEFNAME     "\\\\.\\PIPE\\TOMCATNATIVEPIPE"
+#define DEFNAME_FMT "\\\\.\\PIPE\\TOMCATNATIVEPIPE%08X%08X"
+#define DEFSIZE     8192
+#define DEFTIMEOUT  60000
+
+#define TCN_NTP_UNKNOWN 0
+#define TCN_NTP_CLIENT  1
+#define TCN_NTP_SERVER  2
+
+typedef struct {
+    apr_pool_t     *pool;
+    apr_socket_t   *sock;               /* Dummy socket */
+    OVERLAPPED     rd_o;
+    OVERLAPPED     wr_o;
+    HANDLE         h_pipe;
+    HANDLE         rd_event;
+    HANDLE         wr_event;
+    DWORD          timeout;
+    int            mode;                 /* Client or server mode */
+    int            nmax;
+    DWORD          sndbuf;
+    DWORD          rcvbuf;
+    char           name[MAX_PATH+1];
+    SECURITY_ATTRIBUTES sa;
+} tcn_ntp_conn_t;
+
+static const char *NTSD_STRING = "D:"     /* Discretionary ACL */
+                   "(D;OICI;GA;;;BG)"     /* Deny access to Built-in Guests */
+                   "(D;OICI;GA;;;AN)"     /* Deny access to Anonymous Logon */
+                   "(A;OICI;GRGWGX;;;AU)" /* Allow read/write/execute to Authenticated Users */
+                   "(A;OICI;GA;;;BA)"     /* Allow full control to Administrators */
+                   "(A;OICI;GA;;;LS)"     /* Allow full control to Local service account */
+                   "(A;OICI;GA;;;SY)";    /* Allow full control to Local system */
+
+
+
+static apr_status_t APR_THREAD_FUNC
+ntp_socket_timeout_set(apr_socket_t *sock, apr_interval_time_t t)
+{
+    tcn_ntp_conn_t *con = (tcn_ntp_conn_t *)sock;
+    if (t < 0)
+        con->timeout = INFINITE;
+    else
+        con->timeout = (DWORD)(apr_time_as_msec(t));
+    return APR_SUCCESS;
+}
+
+static apr_status_t APR_THREAD_FUNC
+ntp_socket_timeout_get(apr_socket_t *sock, apr_interval_time_t *t)
+{
+    tcn_ntp_conn_t *con = (tcn_ntp_conn_t*)sock;
+    if (con->timeout == INFINITE)
+        *t = -1;
+    else
+        *t = con->timeout * 1000;
+    return APR_SUCCESS;
+}
+
+static APR_INLINE apr_status_t APR_THREAD_FUNC
+ntp_socket_opt_set(apr_socket_t *sock, apr_int32_t opt, apr_int32_t on)
+{
+    tcn_ntp_conn_t *con = (tcn_ntp_conn_t *)sock;
+    apr_status_t rv = APR_SUCCESS;
+    switch (opt) {
+        case APR_SO_SNDBUF:
+            con->sndbuf = (DWORD)on;
+        break;
+        case APR_SO_RCVBUF:
+            con->rcvbuf = (DWORD)on;
+        break;
+        default:
+            rv = APR_EINVAL;
+        break;
+    }
+    return rv;
+}
+
+static APR_INLINE apr_status_t APR_THREAD_FUNC
+ntp_socket_opt_get(apr_socket_t *sock, apr_int32_t opt, apr_int32_t *on)
+{
+    tcn_ntp_conn_t *con = (tcn_ntp_conn_t *)sock;
+    apr_status_t rv = APR_SUCCESS;
+    switch (opt) {
+        case APR_SO_SNDBUF:
+            *on = con->sndbuf;
+        break;
+        case APR_SO_RCVBUF:
+            *on = con->rcvbuf;
+        break;
+        default:
+            rv = APR_EINVAL;
+        break;
+    }
+    return rv;
+}
+
+static apr_status_t ntp_cleanup(void *data)
+{
+    tcn_ntp_conn_t *con = (tcn_ntp_conn_t *)data;
+
+    if (con) {
+        if (con->h_pipe) {
+            FlushFileBuffers(con->h_pipe);
+            CloseHandle(con->h_pipe);
+            con->h_pipe = NULL;
+        }
+        if (con->rd_event) {
+            CloseHandle(con->rd_event);
+            con->rd_event = NULL;
+        }
+        if (con->wr_event) {
+            CloseHandle(con->wr_event);
+            con->wr_event= NULL;
+        }
+    }
+
+#ifdef TCN_DO_STATISTICS
+    apr_atomic_inc32(&ntp_cleared);
+#endif
+    return APR_SUCCESS;
+}
+
+static apr_status_t APR_THREAD_FUNC
+ntp_socket_shutdown(apr_socket_t *sock, apr_shutdown_how_e how)
+{
+    UNREFERENCED(how);
+    return ntp_cleanup(sock);;
+}
+
+static apr_status_t APR_THREAD_FUNC
+ntp_socket_close(apr_socket_t *sock)
+{
+#ifdef TCN_DO_STATISTICS
+    apr_atomic_inc32(&ntp_closed);
+#endif
+    return ntp_cleanup(sock);;
+}
+
+static apr_status_t APR_THREAD_FUNC
+ntp_socket_recv(apr_socket_t *sock, char *buf, apr_size_t *len)
+{
+    tcn_ntp_conn_t *con = (tcn_ntp_conn_t *)sock;
+    DWORD readed;
+
+    if (!ReadFile(con->h_pipe, buf, *len, &readed, &con->rd_o)) {
+        DWORD err = GetLastError();
+        if (err == ERROR_IO_PENDING) {
+            DWORD r = WaitForSingleObject(con->rd_event, con->timeout);
+            if (r == WAIT_TIMEOUT)
+                return APR_TIMEUP;
+            else if (r != WAIT_OBJECT_0)
+                return APR_EOF;
+        }
+        else if (err == ERROR_BROKEN_PIPE || err == ERROR_NO_DATA) {
+            /* Server closed the pipe */
+            return APR_EOF;
+        }
+        GetOverlappedResult(con->h_pipe, &con->rd_o, &readed, FALSE);
+    }
+    *len = readed;
+    return APR_SUCCESS;
+}
+
+static apr_status_t APR_THREAD_FUNC
+ntp_socket_send(apr_socket_t *sock, const char *buf,
+                apr_size_t *len)
+{
+    tcn_ntp_conn_t *con = (tcn_ntp_conn_t *)sock;
+    DWORD written;
+
+    if (!WriteFile(con->h_pipe, buf, *len, &written, &con->wr_o)) {
+        DWORD err = GetLastError();
+        if (err == ERROR_IO_PENDING) {
+            DWORD r = WaitForSingleObject(con->wr_event, con->timeout);
+            if (r == WAIT_TIMEOUT)
+                return APR_TIMEUP;
+            else if (r != WAIT_OBJECT_0)
+                return APR_EOF;
+        }
+        else if (err == ERROR_BROKEN_PIPE || err == ERROR_NO_DATA) {
+            /* Server closed the pipe */
+            return APR_EOF;
+        }
+        GetOverlappedResult(con->h_pipe, &con->wr_o, &written, FALSE);
+    }
+    *len = written;
+    return APR_SUCCESS;
+}
+
+static apr_status_t APR_THREAD_FUNC
+ntp_socket_sendv(apr_socket_t *sock,
+                 const struct iovec *vec,
+                 apr_int32_t nvec, apr_size_t *len)
+{
+    tcn_ntp_conn_t *con = (tcn_ntp_conn_t *)sock;
+    apr_status_t rv;
+    apr_size_t written = 0;
+    apr_int32_t i;
+
+    for (i = 0; i < nvec; i++) {
+        apr_size_t rd = vec[i].iov_len;
+        if ((rv = ntp_socket_send((apr_socket_t *)con,
+                                  vec[i].iov_base, &rd)) != APR_SUCCESS) {
+            *len = written;
+            return rv;
+        }
+        written += rd;
+    }
+    *len = written;
+    return APR_SUCCESS;
+}
+
+static apr_status_t ntp_socket_cleanup(void *data)
+{
+    tcn_socket_t *s = (tcn_socket_t *)data;
+
+    if (s->net->cleanup) {
+        (*s->net->cleanup)(s->opaque);
+        s->net->cleanup = NULL;
+    }
+#ifdef TCN_DO_STATISTICS
+    apr_atomic_inc32(&ntp_cleared);
+#endif
+    return APR_SUCCESS;
+}
+
+static tcn_nlayer_t ntp_socket_layer = {
+    TCN_SOCKET_NTPIPE,
+    ntp_cleanup,
+    ntp_socket_close,
+    ntp_socket_shutdown,
+    ntp_socket_opt_get,
+    ntp_socket_opt_set,
+    ntp_socket_timeout_get,
+    ntp_socket_timeout_set,
+    ntp_socket_send,
+    ntp_socket_sendv,
+    ntp_socket_recv
+};
+
+static BOOL create_DACL(LPSECURITY_ATTRIBUTES psa)
+{
+
+    return ConvertStringSecurityDescriptorToSecurityDescriptor(
+                NTSD_STRING,
+                SDDL_REVISION_1,
+                &(psa->lpSecurityDescriptor),
+                NULL);
+}
+
+TCN_IMPLEMENT_CALL(jlong, Local, create)(TCN_STDARGS, jstring name,
+                                         jlong pool)
+{
+    apr_pool_t *p = J2P(pool, apr_pool_t *);
+    tcn_socket_t   *s   = NULL;
+    tcn_ntp_conn_t *con = NULL;
+    TCN_ALLOC_CSTRING(name);
+
+    UNREFERENCED(o);
+    TCN_ASSERT(pool != 0);
+
+#ifdef TCN_DO_STATISTICS
+    ntp_created++;
+#endif
+    con = (tcn_ntp_conn_t *)apr_pcalloc(p, sizeof(tcn_ntp_conn_t));
+    con->pool = p;
+    con->mode = TCN_NTP_UNKNOWN;
+    con->nmax = PIPE_UNLIMITED_INSTANCES;
+    con->timeout = DEFTIMEOUT;
+    con->sndbuf  = DEFSIZE;
+    con->rcvbuf  = DEFSIZE;
+    if (J2S(name)) {
+        strncpy(con->name, J2S(name), MAX_PATH);
+        con->name[MAX_PATH] = '\0';
+        TCN_FREE_CSTRING(name);
+    }
+    else
+        strcpy(con->name, DEFNAME);
+    con->sa.nLength = sizeof(con->sa);
+    con->sa.bInheritHandle = TRUE;
+    if (!create_DACL(&con->sa)) {
+        tcn_ThrowAPRException(e, apr_get_os_error());
+        return 0;
+    }
+
+    s = (tcn_socket_t *)apr_pcalloc(p, sizeof(tcn_socket_t));
+    s->pool   = p;
+    s->net    = &ntp_socket_layer;
+    s->opaque = con;
+    apr_pool_cleanup_register(p, (const void *)s,
+                              ntp_socket_cleanup,
+                              apr_pool_cleanup_null);
+
+    fflush(stderr);
+    return P2J(s);
+
+}
+
+TCN_IMPLEMENT_CALL(jint, Local, bind)(TCN_STDARGS, jlong sock,
+                                      jlong sa)
+{
+    tcn_socket_t *s = J2P(sock, tcn_socket_t *);
+    UNREFERENCED_STDARGS;
+    UNREFERENCED(sa);
+    TCN_ASSERT(sock != 0);
+    if (s->net->type == TCN_SOCKET_NTPIPE) {
+        tcn_ntp_conn_t *c = (tcn_ntp_conn_t *)s->opaque;
+        c->mode = TCN_NTP_SERVER;
+        return APR_SUCCESS;
+    }
+    else
+        return APR_EINVAL;
+}
+
+TCN_IMPLEMENT_CALL(jint, Local, listen)(TCN_STDARGS, jlong sock,
+                                        jint backlog)
+{
+    tcn_socket_t *s = J2P(sock, tcn_socket_t *);
+    UNREFERENCED_STDARGS;
+
+    TCN_ASSERT(sock != 0);
+    if (s->net->type == TCN_SOCKET_NTPIPE) {
+        tcn_ntp_conn_t *c = (tcn_ntp_conn_t *)s->opaque;
+        c->mode = TCN_NTP_SERVER;
+        if (backlog > 0)
+            c->nmax = backlog;
+        else
+            c->nmax = PIPE_UNLIMITED_INSTANCES;
+        return APR_SUCCESS;
+    }
+    else
+        return APR_EINVAL;
+}
+
+TCN_IMPLEMENT_CALL(jlong, Local, accept)(TCN_STDARGS, jlong sock)
+{
+    tcn_socket_t *s = J2P(sock, tcn_socket_t *);
+    apr_pool_t   *p = NULL;
+    tcn_socket_t *a = NULL;
+    tcn_ntp_conn_t *con = NULL;
+
+    UNREFERENCED(o);
+    TCN_ASSERT(sock != 0);
+
+    TCN_THROW_IF_ERR(apr_pool_create(&p, s->pool), p);
+    if (s->net->type == TCN_SOCKET_NTPIPE) {
+        tcn_ntp_conn_t *c = (tcn_ntp_conn_t *)s->opaque;
+        con = (tcn_ntp_conn_t *)apr_pcalloc(p, sizeof(tcn_ntp_conn_t));
+        con->pool = p;
+        con->mode = TCN_NTP_SERVER;
+        con->nmax = c->nmax;
+        con->timeout = c->timeout;
+        strcpy(con->name, c->name);
+        con->h_pipe = CreateNamedPipe(con->name,
+                                      PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
+                                      PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
+                                      con->nmax,
+                                      con->sndbuf,
+                                      con->rcvbuf,
+                                      con->timeout,
+                                      &c->sa);
+        if (con->h_pipe == INVALID_HANDLE_VALUE) {
+            tcn_ThrowAPRException(e, apr_get_os_error());
+            goto cleanup;
+        }
+        /* Block until a client connects */
+        if (!ConnectNamedPipe(con->h_pipe, NULL)) {
+            DWORD err = GetLastError();
+            if (err != ERROR_PIPE_CONNECTED) {
+                CloseHandle(con->h_pipe);
+                tcn_ThrowAPRException(e, APR_FROM_OS_ERROR(err));
+                goto cleanup;
+            }
+        }
+        /* Create overlapped events */
+        con->rd_event    = CreateEvent(NULL, TRUE, FALSE, NULL);
+        con->rd_o.hEvent = con->rd_event;
+        con->wr_event    = CreateEvent(NULL, TRUE, FALSE, NULL);
+        con->wr_o.hEvent = con->wr_event;
+    }
+    else {
+        tcn_ThrowAPRException(e, APR_ENOTIMPL);
+        goto cleanup;
+    }
+    if (con) {
+#ifdef TCN_DO_STATISTICS
+        apr_atomic_inc32(&ntp_accepted);
+#endif
+        a = (tcn_socket_t *)apr_pcalloc(p, sizeof(tcn_socket_t));
+        a->pool   = p;
+        a->net    = &ntp_socket_layer;
+        a->opaque = con;
+        apr_pool_cleanup_register(p, (const void *)a,
+                                  ntp_socket_cleanup,
+                                  apr_pool_cleanup_null);
+    }
+    return P2J(a);
+cleanup:
+    if (p)
+        apr_pool_destroy(p);
+    return 0;
+}
+
+TCN_IMPLEMENT_CALL(jint, Local, connect)(TCN_STDARGS, jlong sock,
+                                         jlong sa)
+{
+    tcn_socket_t *s = J2P(sock, tcn_socket_t *);
+    apr_pool_t   *p = NULL;
+    tcn_socket_t *a = NULL;
+    tcn_ntp_conn_t *con = NULL;
+
+    UNREFERENCED(o);
+    UNREFERENCED(sa);
+    TCN_ASSERT(sock != 0);
+    if (s->net->type != TCN_SOCKET_NTPIPE)
+        return APR_ENOTSOCK;
+    con = (tcn_ntp_conn_t *)s->opaque;
+    if (con->mode == TCN_NTP_SERVER)
+        return APR_EINVAL;
+    con->mode = TCN_NTP_CLIENT;
+
+    while (TRUE) {
+        con->h_pipe = CreateFile(con->name,
+                                 GENERIC_WRITE | GENERIC_READ,
+                                 FILE_SHARE_READ | FILE_SHARE_WRITE ,
+                                 NULL,
+                                 OPEN_EXISTING,
+                                 FILE_FLAG_OVERLAPPED,
+                                 NULL);
+        if (con->h_pipe != INVALID_HANDLE_VALUE)
+            break;
+        if (GetLastError() == ERROR_PIPE_BUSY) {
+            /* All pipe instances are busy, so wait for
+             * timeout value specified by the server process in
+             * the CreateNamedPipe function.
+             */
+            if (!WaitNamedPipe(con->name, NMPWAIT_USE_DEFAULT_WAIT))
+                return apr_get_os_error();
+        }
+        else
+            return apr_get_os_error();
+    }
+
+    /* Create overlapped events */
+    con->rd_event    = CreateEvent(NULL, TRUE, FALSE, NULL);
+    con->rd_o.hEvent = con->rd_event;
+    con->wr_event    = CreateEvent(NULL, TRUE, FALSE, NULL);
+    con->wr_o.hEvent = con->wr_event;
+
+    return APR_SUCCESS;
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/os/win32/registry.c
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/os/win32/registry.c	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/os/win32/registry.c	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,788 @@
+/* Copyright 2000-2005 The Apache Software Foundation
+ *
+ * Licensed 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.
+ */
+
+/*
+ *
+ * @author Mladen Turk
+ * @version $Revision: 411550 $, $Date: 2006-06-04 07:06:09 -0500 (Sun, 04 Jun 2006) $
+ */
+
+#ifndef _WIN32_WINNT
+#define _WIN32_WINNT 0x0500
+#endif
+#include <winsock2.h>
+#include <mswsock.h>
+#include <ws2tcpip.h>
+#include <shlwapi.h>
+
+#include "apr.h"
+#include "apr_pools.h"
+#include "apr_arch_misc.h"   /* for apr_os_level */
+#include "apr_arch_atime.h"  /* for FileTimeToAprTime */
+
+#include "tcn.h"
+
+#define SAFE_CLOSE_KEY(k)                               \
+    if ((k) != NULL && (k) != INVALID_HANDLE_VALUE) {   \
+        RegCloseKey((k));                               \
+        (k) = NULL;                                     \
+    }
+
+typedef struct {
+    apr_pool_t     *pool;
+    HKEY           root;
+    HKEY           key;
+} tcn_nt_registry_t;
+
+
+#define TCN_HKEY_CLASSES_ROOT       1
+#define TCN_HKEY_CURRENT_CONFIG     2
+#define TCN_HKEY_CURRENT_USER       3
+#define TCN_HKEY_LOCAL_MACHINE      4
+#define TCN_HKEY_USERS              5
+
+static const struct {
+    HKEY k;
+} TCN_KEYS[] = {
+    INVALID_HANDLE_VALUE,
+    HKEY_CLASSES_ROOT,
+    HKEY_CURRENT_CONFIG,
+    HKEY_CURRENT_USER,
+    HKEY_LOCAL_MACHINE,
+    HKEY_USERS,
+    INVALID_HANDLE_VALUE
+};
+
+#define TCN_KEY_ALL_ACCESS          0x0001
+#define TCN_KEY_CREATE_LINK         0x0002
+#define TCN_KEY_CREATE_SUB_KEY      0x0004
+#define TCN_KEY_ENUMERATE_SUB_KEYS  0x0008
+#define TCN_KEY_EXECUTE             0x0010
+#define TCN_KEY_NOTIFY              0x0020
+#define TCN_KEY_QUERY_VALUE         0x0040
+#define TCN_KEY_READ                0x0080
+#define TCN_KEY_SET_VALUE           0x0100
+#define TCN_KEY_WOW64_64KEY         0x0200
+#define TCN_KEY_WOW64_32KEY         0x0400
+#define TCN_KEY_WRITE               0x0800
+
+#define TCN_REGSAM(s, x)                    \
+        s = 0;                              \
+        if (x & TCN_KEY_ALL_ACCESS)         \
+            s |= KEY_ALL_ACCESS;            \
+        if (x & TCN_KEY_CREATE_LINK)        \
+            s |= KEY_CREATE_LINK;           \
+        if (x & TCN_KEY_CREATE_SUB_KEY)     \
+            s |= KEY_CREATE_SUB_KEY;        \
+        if (x & TCN_KEY_ENUMERATE_SUB_KEYS) \
+            s |= KEY_ENUMERATE_SUB_KEYS;    \
+        if (x & TCN_KEY_EXECUTE)            \
+            s |= KEY_EXECUTE;               \
+        if (x & TCN_KEY_NOTIFY)             \
+            s |= KEY_NOTIFY;                \
+        if (x & TCN_KEY_READ)               \
+            s |= KEY_READ;                  \
+        if (x & TCN_KEY_SET_VALUE)          \
+            s |= KEY_SET_VALUE;             \
+        if (x & TCN_KEY_WOW64_64KEY)        \
+            s |= KEY_WOW64_64KEY;           \
+        if (x & TCN_KEY_WOW64_32KEY)        \
+            s |= KEY_WOW64_32KEY;           \
+        if (x & TCN_KEY_WRITE)              \
+            s |= KEY_WRITE
+
+#define TCN_REG_BINARY              1
+#define TCN_REG_DWORD               2
+#define TCN_REG_EXPAND_SZ           3
+#define TCN_REG_MULTI_SZ            4
+#define TCN_REG_QWORD               5
+#define TCN_REG_SZ                  6
+
+static const struct {
+    DWORD t;
+} TCN_REGTYPES[] = {
+    REG_NONE,
+    REG_BINARY,
+    REG_DWORD,
+    REG_EXPAND_SZ,
+    REG_MULTI_SZ,
+    REG_QWORD,
+    REG_SZ,
+    REG_NONE
+};
+
+static apr_status_t registry_cleanup(void *data)
+{
+    tcn_nt_registry_t *reg = (tcn_nt_registry_t *)data;
+
+    if (reg) {
+        SAFE_CLOSE_KEY(reg->key);
+    }
+    return APR_SUCCESS;
+}
+
+TCN_IMPLEMENT_CALL(jlong, Registry, create)(TCN_STDARGS, jint root, jstring name,
+                                            jint sam, jlong pool)
+{
+    apr_pool_t *p = J2P(pool, apr_pool_t *);
+    tcn_nt_registry_t *reg = NULL;
+    TCN_ALLOC_WSTRING(name);
+    HKEY key;
+    LONG rc;
+    REGSAM s;
+
+    UNREFERENCED(o);
+    TCN_ASSERT(pool != 0);
+
+    if (root < TCN_HKEY_CLASSES_ROOT || root > TCN_HKEY_USERS) {
+        tcn_ThrowException(e, "Invalid Registry Root Key");
+        goto cleanup;
+    }
+    if (sam < TCN_KEY_ALL_ACCESS || root > TCN_KEY_WRITE) {
+        tcn_ThrowException(e, "Invalid Registry Key Security");
+        goto cleanup;
+    }
+    reg = (tcn_nt_registry_t *)apr_palloc(p, sizeof(tcn_nt_registry_t));
+    reg->pool = p;
+    reg->root = TCN_KEYS[root].k;
+    reg->key  = NULL;
+    TCN_INIT_WSTRING(name);
+    TCN_REGSAM(s, sam);
+    rc = RegCreateKeyExW(reg->root, J2W(name), 0, NULL, REG_OPTION_NON_VOLATILE,
+                         s, NULL, &key, NULL);
+    if (rc !=  ERROR_SUCCESS) {
+        tcn_ThrowAPRException(e, APR_FROM_OS_ERROR(rc));
+        goto cleanup;
+    }
+    reg->key = key;
+    apr_pool_cleanup_register(p, (const void *)reg,
+                              registry_cleanup,
+                              apr_pool_cleanup_null);
+
+cleanup:
+    TCN_FREE_WSTRING(name);
+    return P2J(reg);
+}
+
+TCN_IMPLEMENT_CALL(jlong, Registry, open)(TCN_STDARGS, jint root, jstring name,
+                                          jint sam, jlong pool)
+{
+    apr_pool_t *p = J2P(pool, apr_pool_t *);
+    tcn_nt_registry_t *reg = NULL;
+    TCN_ALLOC_WSTRING(name);
+    HKEY key;
+    LONG rc;
+    REGSAM s;
+
+    UNREFERENCED(o);
+    TCN_ASSERT(pool != 0);
+
+    if (root < TCN_HKEY_CLASSES_ROOT || root > TCN_HKEY_USERS) {
+        tcn_ThrowException(e, "Invalid Registry Root Key");
+        goto cleanup;
+    }
+    if (sam < TCN_KEY_ALL_ACCESS || root > TCN_KEY_WRITE) {
+        tcn_ThrowException(e, "Invalid Registry Key Security");
+        goto cleanup;
+    }
+    reg = (tcn_nt_registry_t *)apr_palloc(p, sizeof(tcn_nt_registry_t));
+    reg->pool = p;
+    reg->root = TCN_KEYS[root].k;
+    reg->key  = NULL;
+    TCN_INIT_WSTRING(name);
+    TCN_REGSAM(s, sam);
+    rc = RegOpenKeyExW(reg->root, J2W(name), 0, s, &key);
+    if (rc !=  ERROR_SUCCESS) {
+        tcn_ThrowAPRException(e, APR_FROM_OS_ERROR(rc));
+        goto cleanup;
+    }
+    reg->key = key;
+    apr_pool_cleanup_register(p, (const void *)reg,
+                              registry_cleanup,
+                              apr_pool_cleanup_null);
+
+cleanup:
+    TCN_FREE_WSTRING(name);
+    return P2J(reg);
+}
+
+TCN_IMPLEMENT_CALL(jint, Registry, close)(TCN_STDARGS, jlong reg)
+{
+    tcn_nt_registry_t *r = J2P(reg, tcn_nt_registry_t *);
+    UNREFERENCED_STDARGS;
+
+    TCN_ASSERT(reg != 0);
+
+    registry_cleanup(r);
+    apr_pool_cleanup_kill(r->pool, r, registry_cleanup);
+    return APR_SUCCESS;
+}
+
+TCN_IMPLEMENT_CALL(jint, Registry, getType)(TCN_STDARGS, jlong key,
+                                            jstring name)
+{
+    tcn_nt_registry_t *k = J2P(key, tcn_nt_registry_t *);
+    TCN_ALLOC_WSTRING(name);
+    LONG rc;
+    DWORD v;
+
+    UNREFERENCED(o);
+    TCN_ASSERT(key != 0);
+    TCN_INIT_WSTRING(name);
+    rc = RegQueryValueExW(k->key, J2W(name), NULL, &v, NULL, NULL);
+    if (rc != ERROR_SUCCESS)
+        v = -rc;
+    TCN_FREE_WSTRING(name);
+    switch (v) {
+        case REG_BINARY:
+            v = TCN_REG_BINARY;
+            break;
+        case REG_DWORD:
+            v = TCN_REG_DWORD;
+            break;
+        case REG_EXPAND_SZ:
+            v = TCN_REG_EXPAND_SZ;
+            break;
+        case REG_MULTI_SZ:
+            v = TCN_REG_MULTI_SZ;
+            break;
+        case REG_QWORD:
+            v = TCN_REG_QWORD;
+            break;
+        case REG_SZ:
+            v = TCN_REG_SZ;
+            break;
+        case REG_DWORD_BIG_ENDIAN:
+            v = 0;
+            break;
+    }
+    return v;
+}
+
+TCN_IMPLEMENT_CALL(jint, Registry, getSize)(TCN_STDARGS, jlong key,
+                                            jstring name)
+{
+    tcn_nt_registry_t *k = J2P(key, tcn_nt_registry_t *);
+    TCN_ALLOC_WSTRING(name);
+    LONG rc;
+    DWORD v;
+
+    UNREFERENCED(o);
+    TCN_ASSERT(key != 0);
+    TCN_INIT_WSTRING(name);
+    rc = RegQueryValueExW(k->key, J2W(name), NULL, NULL, NULL, &v);
+    if (rc != ERROR_SUCCESS)
+        v = -rc;
+    TCN_FREE_WSTRING(name);
+    return v;
+}
+
+TCN_IMPLEMENT_CALL(jint, Registry, getValueI)(TCN_STDARGS, jlong key,
+                                              jstring name)
+{
+    tcn_nt_registry_t *k = J2P(key, tcn_nt_registry_t *);
+    TCN_ALLOC_WSTRING(name);
+    LONG rc;
+    DWORD t, l;
+    DWORD v = 0;
+
+    UNREFERENCED(o);
+    TCN_ASSERT(key != 0);
+    TCN_INIT_WSTRING(name);
+    rc = RegQueryValueExW(k->key, J2W(name), NULL, &t, NULL, &l);
+    if (rc != ERROR_SUCCESS) {
+        tcn_ThrowAPRException(e, APR_FROM_OS_ERROR(rc));
+        goto cleanup;
+    }
+    if (t == REG_DWORD) {
+        l = sizeof(DWORD);
+        rc = RegQueryValueExW(k->key, J2W(name), NULL, NULL, (LPBYTE)&v, &l);
+        if (rc != ERROR_SUCCESS) {
+            tcn_ThrowAPRException(e, APR_FROM_OS_ERROR(rc));
+            goto cleanup;
+        }
+    }
+    else if (t == REG_SZ || t == REG_BINARY ||
+             t == REG_MULTI_SZ || t == REG_EXPAND_SZ)
+        v = l;
+    else {
+        v = 0;
+        tcn_ThrowException(e, "Unable to convert the value to integer");
+    }
+cleanup:
+    TCN_FREE_WSTRING(name);
+    return v;
+}
+
+TCN_IMPLEMENT_CALL(jlong, Registry, getValueJ)(TCN_STDARGS, jlong key,
+                                               jstring name)
+{
+    tcn_nt_registry_t *k = J2P(key, tcn_nt_registry_t *);
+    TCN_ALLOC_WSTRING(name);
+    LONG rc;
+    DWORD t, l;
+    UINT64 v = 0;
+
+    UNREFERENCED(o);
+    TCN_ASSERT(key != 0);
+    TCN_INIT_WSTRING(name);
+    rc = RegQueryValueExW(k->key, J2W(name), NULL, &t, NULL, &l);
+    if (rc != ERROR_SUCCESS) {
+        tcn_ThrowAPRException(e, APR_FROM_OS_ERROR(rc));
+        goto cleanup;
+    }
+    if (t == REG_DWORD) {
+        DWORD tv;
+        l = sizeof(DWORD);
+        rc = RegQueryValueExW(k->key, J2W(name), NULL, NULL, (LPBYTE)&tv, &l);
+        if (rc != ERROR_SUCCESS) {
+            tcn_ThrowAPRException(e, APR_FROM_OS_ERROR(rc));
+            goto cleanup;
+        }
+        v = tv;
+    }
+    else if (t == REG_QWORD) {
+        l = sizeof(UINT64);
+        rc = RegQueryValueExW(k->key, J2W(name), NULL, NULL, (LPBYTE)&v, &l);
+        if (rc != ERROR_SUCCESS) {
+            tcn_ThrowAPRException(e, APR_FROM_OS_ERROR(rc));
+            goto cleanup;
+        }
+    }
+    else if (t == REG_SZ || t == REG_BINARY ||
+             t == REG_MULTI_SZ || t == REG_EXPAND_SZ)
+        v = l;
+    else {
+        v = 0;
+        tcn_ThrowException(e, "Unable to convert the value to long");
+    }
+cleanup:
+    TCN_FREE_WSTRING(name);
+    return v;
+}
+
+TCN_IMPLEMENT_CALL(jstring, Registry, getValueS)(TCN_STDARGS, jlong key,
+                                                 jstring name)
+{
+    tcn_nt_registry_t *k = J2P(key, tcn_nt_registry_t *);
+    TCN_ALLOC_WSTRING(name);
+    LONG rc;
+    DWORD t, l;
+    jstring v = NULL;
+
+    UNREFERENCED(o);
+    TCN_ASSERT(key != 0);
+    TCN_INIT_WSTRING(name);
+    rc = RegQueryValueExW(k->key, J2W(name), NULL, &t, NULL, &l);
+    if (rc != ERROR_SUCCESS) {
+        tcn_ThrowAPRException(e, APR_FROM_OS_ERROR(rc));
+        goto cleanup;
+    }
+    if (t == REG_SZ || t == REG_EXPAND_SZ) {
+        jchar *vw = (jchar *)malloc(l);
+        rc = RegQueryValueExW(k->key, J2W(name), NULL, NULL, (LPBYTE)vw, &l);
+        if (rc != ERROR_SUCCESS) {
+            tcn_ThrowAPRException(e, APR_FROM_OS_ERROR(rc));
+            free(vw);
+            goto cleanup;
+        }
+        v = (*e)->NewString((e), vw, wcslen(vw));
+        free(vw);
+    }
+cleanup:
+    TCN_FREE_WSTRING(name);
+    return v;
+}
+
+TCN_IMPLEMENT_CALL(jbyteArray, Registry, getValueB)(TCN_STDARGS, jlong key,
+                                                    jstring name)
+{
+    tcn_nt_registry_t *k = J2P(key, tcn_nt_registry_t *);
+    TCN_ALLOC_WSTRING(name);
+    LONG rc;
+    DWORD t, l;
+    jbyteArray v = NULL;
+
+    UNREFERENCED(o);
+    TCN_ASSERT(key != 0);
+    TCN_INIT_WSTRING(name);
+    rc = RegQueryValueExW(k->key, J2W(name), NULL, &t, NULL, &l);
+    if (rc != ERROR_SUCCESS) {
+        tcn_ThrowAPRException(e, APR_FROM_OS_ERROR(rc));
+        goto cleanup;
+    }
+    if (t == REG_BINARY) {
+        BYTE *b = (BYTE *)malloc(l);
+        rc = RegQueryValueExW(k->key, J2W(name), NULL, NULL, b, &l);
+        if (rc != ERROR_SUCCESS) {
+            tcn_ThrowAPRException(e, APR_FROM_OS_ERROR(rc));
+            free(b);
+            goto cleanup;
+        }
+        v = tcn_new_arrayb(e, b, l);
+        free(b);
+    }
+cleanup:
+    TCN_FREE_WSTRING(name);
+    return v;
+}
+
+static jsize get_multi_sz_count(LPCWSTR str)
+{
+    LPCWSTR p = str;
+    jsize   cnt = 0;
+    for ( ; p && *p; p++) {
+        cnt++;
+        while (*p)
+            p++;
+    }
+    return cnt;
+}
+
+TCN_IMPLEMENT_CALL(jobjectArray, Registry, getValueA)(TCN_STDARGS, jlong key,
+                                                      jstring name)
+{
+    tcn_nt_registry_t *k = J2P(key, tcn_nt_registry_t *);
+    TCN_ALLOC_WSTRING(name);
+    LONG rc;
+    DWORD t, l;
+    jobjectArray v = NULL;
+
+    UNREFERENCED(o);
+    TCN_ASSERT(key != 0);
+    TCN_INIT_WSTRING(name);
+    rc = RegQueryValueExW(k->key, J2W(name), NULL, &t, NULL, &l);
+    if (rc != ERROR_SUCCESS) {
+        tcn_ThrowAPRException(e, APR_FROM_OS_ERROR(rc));
+        goto cleanup;
+    }
+    if (t == REG_MULTI_SZ) {
+        jsize cnt = 0;
+        jchar *p;
+        jchar *vw = (jchar *)malloc(l);
+        rc = RegQueryValueExW(k->key, J2W(name), NULL, NULL, (LPBYTE)vw, &l);
+        if (rc != ERROR_SUCCESS) {
+            tcn_ThrowAPRException(e, APR_FROM_OS_ERROR(rc));
+            free(vw);
+            goto cleanup;
+        }
+        cnt = get_multi_sz_count(vw);
+        if (cnt) {
+            jsize idx = 0;
+            v = tcn_new_arrays(e, cnt);
+            for (p = vw ; p && *p; p++) {
+                jstring s;
+                jchar *b = p;
+                while (*p)
+                    p++;
+                s = (*e)->NewString((e), b, (jsize)(p - b));
+                (*e)->SetObjectArrayElement((e), v, idx++, s);
+            }
+        }
+        free(vw);
+    }
+cleanup:
+    TCN_FREE_WSTRING(name);
+    return v;
+}
+
+TCN_IMPLEMENT_CALL(jint, Registry, setValueI)(TCN_STDARGS, jlong key,
+                                              jstring name, jint val)
+{
+    tcn_nt_registry_t *k = J2P(key, tcn_nt_registry_t *);
+    TCN_ALLOC_WSTRING(name);
+    LONG rc;
+    DWORD v = (DWORD)val;
+
+    UNREFERENCED(o);
+    TCN_ASSERT(key != 0);
+    TCN_INIT_WSTRING(name);
+    rc = RegSetValueExW(k->key, J2W(name), 0, REG_DWORD, (CONST BYTE *)&v, sizeof(DWORD));
+    TCN_FREE_WSTRING(name);
+    return v;
+}
+
+TCN_IMPLEMENT_CALL(jint, Registry, setValueJ)(TCN_STDARGS, jlong key,
+                                              jstring name, jlong val)
+{
+    tcn_nt_registry_t *k = J2P(key, tcn_nt_registry_t *);
+    TCN_ALLOC_WSTRING(name);
+    LONG rc;
+    UINT64 v = (UINT64)val;
+
+    UNREFERENCED(o);
+    TCN_ASSERT(key != 0);
+    TCN_INIT_WSTRING(name);
+    rc = RegSetValueExW(k->key, J2W(name), 0, REG_QWORD, (CONST BYTE *)&v, sizeof(UINT64));
+    TCN_FREE_WSTRING(name);
+    return rc;
+}
+
+TCN_IMPLEMENT_CALL(jint, Registry, setValueS)(TCN_STDARGS, jlong key,
+                                              jstring name, jstring val)
+{
+    tcn_nt_registry_t *k = J2P(key, tcn_nt_registry_t *);
+    TCN_ALLOC_WSTRING(name);
+    TCN_ALLOC_WSTRING(val);
+    LONG rc;
+    DWORD len;
+
+    UNREFERENCED(o);
+    TCN_ASSERT(key != 0);
+    TCN_INIT_WSTRING(name);
+    TCN_INIT_WSTRING(val);
+    len = wcslen(J2W(val));
+    rc = RegSetValueExW(k->key, J2W(name), 0, REG_SZ,
+                        (CONST BYTE *)J2W(val), (len + 1) * 2);
+    TCN_FREE_WSTRING(name);
+    TCN_FREE_WSTRING(val);
+    return rc;
+}
+
+TCN_IMPLEMENT_CALL(jint, Registry, setValueE)(TCN_STDARGS, jlong key,
+                                              jstring name, jstring val)
+{
+    tcn_nt_registry_t *k = J2P(key, tcn_nt_registry_t *);
+    TCN_ALLOC_WSTRING(name);
+    TCN_ALLOC_WSTRING(val);
+    LONG rc;
+    DWORD len;
+
+    UNREFERENCED(o);
+    TCN_ASSERT(key != 0);
+    TCN_INIT_WSTRING(name);
+    TCN_INIT_WSTRING(val);
+    len = wcslen(J2W(val));
+    rc = RegSetValueExW(k->key, J2W(name), 0, REG_EXPAND_SZ,
+                        (CONST BYTE *)J2W(val), (len + 1) * 2);
+    TCN_FREE_WSTRING(name);
+    TCN_FREE_WSTRING(val);
+    return rc;
+}
+
+TCN_IMPLEMENT_CALL(jint, Registry, setValueA)(TCN_STDARGS, jlong key,
+                                              jstring name,
+                                              jobjectArray vals)
+{
+    tcn_nt_registry_t *k = J2P(key, tcn_nt_registry_t *);
+    TCN_ALLOC_WSTRING(name);
+    LONG rc;
+    jsize i, len;
+    jsize sl = 0;
+    jchar *msz, *p;
+    UNREFERENCED(o);
+    TCN_ASSERT(key != 0);
+    TCN_INIT_WSTRING(name);
+    len = (*e)->GetArrayLength((e), vals);
+    for (i = 0; i < len; i++) {
+        jstring s = (jstring)(*e)->GetObjectArrayElement((e), vals, i);
+        sl += (*e)->GetStringLength((e), s) + 1;
+    }
+    sl = (sl + 1) * 2;
+    p = msz = (jchar *)calloc(1, sl);
+    for (i = 0; i < len; i++) {
+        jsize   l;
+        jstring s = (jstring)(*e)->GetObjectArrayElement((e), vals, i);
+        l = (*e)->GetStringLength((e), s);
+        wcsncpy(p, (*e)->GetStringChars(e, s, 0), l);
+        p += l + 1;
+    }
+    rc = RegSetValueExW(k->key, J2W(name), 0, REG_MULTI_SZ,
+                        (CONST BYTE *)msz, sl);
+    TCN_FREE_WSTRING(name);
+    free(msz);
+    return rc;
+}
+
+TCN_IMPLEMENT_CALL(jint, Registry, setValueB)(TCN_STDARGS, jlong key,
+                                              jstring name,
+                                              jbyteArray val)
+{
+    tcn_nt_registry_t *k = J2P(key, tcn_nt_registry_t *);
+    TCN_ALLOC_WSTRING(name);
+    jsize nbytes = (*e)->GetArrayLength(e, val);
+    jbyte *bytes = (*e)->GetByteArrayElements(e, val, NULL);
+    LONG rc;
+
+    rc = RegSetValueExW(k->key, J2W(name), 0, REG_BINARY,
+                        bytes, (DWORD)nbytes);
+    (*e)->ReleaseByteArrayElements(e, val, bytes, JNI_ABORT);
+    TCN_FREE_WSTRING(name);
+    return rc;
+}
+
+#define MAX_VALUE_NAME 4096
+
+TCN_IMPLEMENT_CALL(jobjectArray, Registry, enumKeys)(TCN_STDARGS, jlong key)
+{
+    tcn_nt_registry_t *k = J2P(key, tcn_nt_registry_t *);
+    LONG rc;
+    jobjectArray v = NULL;
+    jsize cnt = 0;
+
+    WCHAR    achKey[MAX_PATH];
+    WCHAR    achClass[MAX_PATH] = L"";
+    DWORD    cchClassName = MAX_PATH;
+    DWORD    cSubKeys;
+    DWORD    cbMaxSubKey;
+    DWORD    cchMaxClass;
+    DWORD    cValues;
+    DWORD    cchMaxValue;
+    DWORD    cbMaxValueData;
+    DWORD    cbSecurityDescriptor;
+    FILETIME ftLastWriteTime;
+
+    DWORD cchValue = MAX_VALUE_NAME;
+
+    UNREFERENCED(o);
+    TCN_ASSERT(key != 0);
+    rc = RegQueryInfoKeyW(k->key,
+                          achClass,
+                          &cchClassName,
+                          NULL,
+                          &cSubKeys,
+                          &cbMaxSubKey,
+                          &cchMaxClass,
+                          &cValues,
+                          &cchMaxValue,
+                          &cbMaxValueData,
+                          &cbSecurityDescriptor,
+                          &ftLastWriteTime);
+    if (rc != ERROR_SUCCESS) {
+        tcn_ThrowAPRException(e, APR_FROM_OS_ERROR(rc));
+        goto cleanup;
+    }
+    cnt = cSubKeys;
+    if (cnt) {
+        jsize idx = 0;
+        v = tcn_new_arrays(e, cnt);
+        for (idx = 0; idx < cnt; idx++) {
+            jstring s;
+            DWORD achKeyLen = MAX_PATH;
+            rc = RegEnumKeyExW(k->key,
+                               idx,
+                               achKey,
+                               &achKeyLen,
+                               NULL,
+                               NULL,
+                               NULL,
+                               &ftLastWriteTime);
+            if (rc == (DWORD)ERROR_SUCCESS) {
+                s = (*e)->NewString((e), achKey, wcslen(achKey));
+                (*e)->SetObjectArrayElement((e), v, idx, s);
+            }
+        }
+    }
+cleanup:
+    return v;
+}
+
+TCN_IMPLEMENT_CALL(jobjectArray, Registry, enumValues)(TCN_STDARGS, jlong key)
+{
+    tcn_nt_registry_t *k = J2P(key, tcn_nt_registry_t *);
+    LONG rc;
+    jobjectArray v = NULL;
+    jsize cnt = 0;
+
+    WCHAR    achClass[MAX_PATH] = L"";
+    DWORD    cchClassName = MAX_PATH;
+    DWORD    cSubKeys;
+    DWORD    cbMaxSubKey;
+    DWORD    cchMaxClass;
+    DWORD    cValues;
+    DWORD    cchMaxValue;
+    DWORD    cbMaxValueData;
+    DWORD    cbSecurityDescriptor;
+    FILETIME ftLastWriteTime;
+
+    WCHAR  achValue[MAX_VALUE_NAME];
+    DWORD  cchValue = MAX_VALUE_NAME;
+
+    UNREFERENCED(o);
+    TCN_ASSERT(key != 0);
+    /* Get the class name and the value count. */
+    rc = RegQueryInfoKeyW(k->key,
+                          achClass,
+                          &cchClassName,
+                          NULL,
+                          &cSubKeys,
+                          &cbMaxSubKey,
+                          &cchMaxClass,
+                          &cValues,
+                          &cchMaxValue,
+                          &cbMaxValueData,
+                          &cbSecurityDescriptor,
+                          &ftLastWriteTime);
+    if (rc != ERROR_SUCCESS) {
+        tcn_ThrowAPRException(e, APR_FROM_OS_ERROR(rc));
+        goto cleanup;
+    }
+    cnt = cValues;
+    if (cnt) {
+        jsize idx = 0;
+        v = tcn_new_arrays(e, cnt);
+        for (idx = 0; idx < cnt; idx++) {
+            jstring s;
+            cchValue = MAX_VALUE_NAME;
+            achValue[0] = '\0';
+            rc = RegEnumValueW(k->key, idx,
+                               achValue,
+                               &cchValue,
+                               NULL,
+                               NULL,    // &dwType,
+                               NULL,    // &bData,
+                               NULL);   // &bcData
+            if (rc == (DWORD)ERROR_SUCCESS) {
+                s = (*e)->NewString((e), achValue, wcslen(achValue));
+                (*e)->SetObjectArrayElement((e), v, idx, s);
+            }
+        }
+    }
+cleanup:
+    return v;
+}
+
+TCN_IMPLEMENT_CALL(jint, Registry, deleteKey)(TCN_STDARGS, jint root, jstring name,
+                                              jboolean only_if_empty)
+{
+    DWORD rv;
+    TCN_ALLOC_WSTRING(name);
+
+    UNREFERENCED(o);
+    if (root < TCN_HKEY_CLASSES_ROOT || root > TCN_HKEY_USERS) {
+        rv = EBADF;
+        goto cleanup;
+    }
+    if (only_if_empty)
+        rv = SHDeleteEmptyKeyW(TCN_KEYS[root].k, J2W(name));
+    else
+        rv = SHDeleteKeyW(TCN_KEYS[root].k, J2W(name));
+cleanup:
+    TCN_FREE_WSTRING(name);
+    return rv;
+}
+
+TCN_IMPLEMENT_CALL(jint, Registry, deleteValue)(TCN_STDARGS, jlong key,
+                                                jstring name)
+{
+    LONG rv;
+    TCN_ALLOC_WSTRING(name);
+    tcn_nt_registry_t *k = J2P(key, tcn_nt_registry_t *);
+
+    UNREFERENCED(o);
+    rv = RegDeleteValueW(k->key, J2W(name));
+    TCN_FREE_WSTRING(name);
+    return (jint)rv;
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/os/win32/system.c
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/os/win32/system.c	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/os/win32/system.c	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,463 @@
+/* Copyright 2000-2005 The Apache Software Foundation
+ *
+ * Licensed 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.
+ */
+
+/*
+ *
+ * @author Mladen Turk
+ * @version $Revision: 411550 $, $Date: 2006-06-04 07:06:09 -0500 (Sun, 04 Jun 2006) $
+ */
+
+#ifndef _WIN32_WINNT
+#define _WIN32_WINNT 0x0500
+#endif
+#include <winsock2.h>
+#include <mswsock.h>
+#include <ws2tcpip.h>
+#include "apr.h"
+#include "apr_pools.h"
+#include "apr_poll.h"
+#include "apr_network_io.h"
+#include "apr_arch_misc.h" /* for apr_os_level */
+#include "apr_arch_atime.h"  /* for FileTimeToAprTime */
+
+#include "tcn.h"
+#include "ssl_private.h"
+
+#pragma warning(push)
+#pragma warning(disable : 4201)
+#if (_WIN32_WINNT < 0x0501)
+#include <winternl.h>
+#endif
+#include <psapi.h>
+#pragma warning(pop)
+
+
+static CRITICAL_SECTION dll_critical_section;   /* dll's critical section */
+static HINSTANCE        dll_instance = NULL;
+static SYSTEM_INFO      dll_system_info;
+static HANDLE           h_kernel = NULL;
+static HANDLE           h_ntdll  = NULL;
+static char             dll_file_name[MAX_PATH];
+
+typedef BOOL (WINAPI *pfnGetSystemTimes)(LPFILETIME, LPFILETIME, LPFILETIME);
+static pfnGetSystemTimes fnGetSystemTimes = NULL;
+#if (_WIN32_WINNT < 0x0501)
+typedef NTSTATUS (WINAPI *pfnNtQuerySystemInformation)(SYSTEM_INFORMATION_CLASS, PVOID, ULONG, PULONG);
+static pfnNtQuerySystemInformation fnNtQuerySystemInformation = NULL;
+#endif
+
+BOOL
+WINAPI
+DllMain(
+    HINSTANCE instance,
+    DWORD reason,
+    LPVOID reserved)
+{
+
+    switch (reason) {
+        /** The DLL is loading due to process
+         *  initialization or a call to LoadLibrary.
+         */
+        case DLL_PROCESS_ATTACH:
+            InitializeCriticalSection(&dll_critical_section);
+            dll_instance = instance;
+            GetSystemInfo(&dll_system_info);
+            if ((h_kernel = LoadLibrary("kernel32.dll")) != NULL)
+                fnGetSystemTimes = (pfnGetSystemTimes)GetProcAddress(h_kernel,
+                                                            "GetSystemTimes");
+            if (fnGetSystemTimes == NULL) {
+                FreeLibrary(h_kernel);
+                h_kernel = NULL;
+#if (_WIN32_WINNT < 0x0501)
+                if ((h_ntdll = LoadLibrary("ntdll.dll")) != NULL)
+                    fnNtQuerySystemInformation =
+                        (pfnNtQuerySystemInformation)GetProcAddress(h_ntdll,
+                                                "NtQuerySystemInformation");
+
+                if (fnNtQuerySystemInformation == NULL) {
+                    FreeLibrary(h_ntdll);
+                    h_ntdll = NULL;
+                }
+#endif
+            }
+            GetModuleFileName(instance, dll_file_name, sizeof(dll_file_name));
+            break;
+        /** The attached process creates a new thread.
+         */
+        case DLL_THREAD_ATTACH:
+            break;
+
+        /** The thread of the attached process terminates.
+         */
+        case DLL_THREAD_DETACH:
+            break;
+
+        /** DLL unload due to process termination
+         *  or FreeLibrary.
+         */
+        case DLL_PROCESS_DETACH:
+            /* Make sure the library is always terminated */
+            apr_terminate();
+            if (h_kernel)
+                FreeLibrary(h_kernel);
+            if (h_ntdll)
+                FreeLibrary(h_ntdll);
+            DeleteCriticalSection(&dll_critical_section);
+            break;
+
+        default:
+            break;
+    }
+
+    return TRUE;
+    UNREFERENCED_PARAMETER(reserved);
+}
+
+
+TCN_IMPLEMENT_CALL(jstring, OS, syserror)(TCN_STDARGS, jint err)
+{
+    jstring str;
+    void *buf;
+
+    UNREFERENCED(o);
+    if (!FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
+                       FORMAT_MESSAGE_FROM_SYSTEM |
+                       FORMAT_MESSAGE_IGNORE_INSERTS,
+                       NULL,
+                       err,
+                       MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+                       (LPTSTR)&buf,
+                       0,
+                       NULL)) {
+        str = AJP_TO_JSTRING("Unknown Error");
+    }
+    else {
+        str = AJP_TO_JSTRING((const char *)buf);
+        LocalFree(buf);
+    }
+    return str;
+}
+
+TCN_IMPLEMENT_CALL(jstring, OS, expand)(TCN_STDARGS, jstring val)
+{
+    jstring str;
+    jchar buf[TCN_BUFFER_SZ] = L"";
+    DWORD len;
+    TCN_ALLOC_WSTRING(val);
+
+    UNREFERENCED(o);
+    TCN_INIT_WSTRING(val);
+
+    len = ExpandEnvironmentStringsW(J2W(val), buf, TCN_BUFFER_SZ - 1);
+    if (len > (TCN_BUFFER_SZ - 1)) {
+        jchar *dbuf = malloc((len + 1) * 2);
+        ExpandEnvironmentStringsW(J2W(val), dbuf, len);
+        str = (*e)->NewString(e, dbuf, wcslen(dbuf));
+        free(dbuf);
+    }
+    else
+        str = (*e)->NewString(e, buf, wcslen(buf));
+
+    TCN_FREE_WSTRING(val);
+    return str;
+}
+
+#define LOG_MSG_EMERG                    0xC0000001L
+#define LOG_MSG_ERROR                    0xC0000002L
+#define LOG_MSG_NOTICE                   0x80000003L
+#define LOG_MSG_WARN                     0x80000004L
+#define LOG_MSG_INFO                     0x40000005L
+#define LOG_MSG_DEBUG                    0x00000006L
+#define LOG_MSG_DOMAIN                   "Native"
+
+static char log_domain[MAX_PATH] = "Native";
+
+static void init_log_source(const char *domain)
+{
+    HKEY  key;
+    DWORD ts;
+    char event_key[MAX_PATH];
+
+    strcpy(event_key, "SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application\\");
+    strcat(event_key, domain);
+    if (!RegCreateKey(HKEY_LOCAL_MACHINE, event_key, &key)) {
+        RegSetValueEx(key, "EventMessageFile", 0, REG_SZ, (LPBYTE)&dll_file_name[0],
+                      strlen(dll_file_name) + 1);
+        ts = EVENTLOG_ERROR_TYPE | EVENTLOG_WARNING_TYPE | EVENTLOG_INFORMATION_TYPE;
+
+        RegSetValueEx(key, "TypesSupported", 0, REG_DWORD, (LPBYTE) &ts, sizeof(DWORD));
+        RegCloseKey(key);
+    }
+    strcpy(log_domain, domain);
+}
+
+TCN_IMPLEMENT_CALL(void, OS, sysloginit)(TCN_STDARGS, jstring domain)
+{
+    const char *d;
+    TCN_ALLOC_CSTRING(domain);
+
+    UNREFERENCED(o);
+
+    if ((d = J2S(domain)) == NULL)
+        d = LOG_MSG_DOMAIN;
+    init_log_source(d);
+
+    TCN_FREE_CSTRING(domain);
+}
+
+TCN_IMPLEMENT_CALL(void, OS, syslog)(TCN_STDARGS, jint level,
+                                     jstring msg)
+{
+    TCN_ALLOC_CSTRING(msg);
+    DWORD id = LOG_MSG_DEBUG;
+    WORD  il = EVENTLOG_SUCCESS;
+    HANDLE  source;
+    const char *messages[1];
+    UNREFERENCED(o);
+
+    switch (level) {
+        case TCN_LOG_EMERG:
+            id = LOG_MSG_EMERG;
+            il = EVENTLOG_ERROR_TYPE;
+        break;
+        case TCN_LOG_ERROR:
+            id = LOG_MSG_ERROR;
+            il = EVENTLOG_ERROR_TYPE;
+        break;
+        case TCN_LOG_NOTICE:
+            id = LOG_MSG_NOTICE;
+            il = EVENTLOG_WARNING_TYPE;
+        break;
+        case TCN_LOG_WARN:
+            id = LOG_MSG_WARN;
+            il = EVENTLOG_WARNING_TYPE;
+        break;
+        case TCN_LOG_INFO:
+            id = LOG_MSG_INFO;
+            il = EVENTLOG_INFORMATION_TYPE;
+        break;
+    }
+
+    messages[0] = J2S(msg);
+    source = RegisterEventSource(NULL, log_domain);
+
+    if (source != NULL) {
+        ReportEvent(source, il,
+                    0,
+                    id,
+                    NULL,
+                    1, 0,
+                    messages, NULL);
+        DeregisterEventSource(source);
+    }
+
+    TCN_FREE_CSTRING(msg);
+}
+
+TCN_IMPLEMENT_CALL(jboolean, OS, is)(TCN_STDARGS, jint type)
+{
+    UNREFERENCED_STDARGS;
+#ifdef _WIN64
+    if (type == 4)
+        return JNI_TRUE;
+    else
+#endif
+    if (type == 3)
+        return JNI_TRUE;
+    else
+        return JNI_FALSE;
+}
+
+TCN_IMPLEMENT_CALL(jint, OS, info)(TCN_STDARGS,
+                                   jlongArray inf)
+{
+    MEMORYSTATUSEX ms;
+    ULONGLONG st[4];
+    FILETIME ft[4];
+    PROCESS_MEMORY_COUNTERS pmc;
+    jint rv;
+    int i;
+    jsize ilen = (*e)->GetArrayLength(e, inf);
+    jlong *pvals = (*e)->GetLongArrayElements(e, inf, NULL);
+
+    if (ilen < 16) {
+        return APR_EINVAL;
+    }
+    for (i = 0; i < 16; i++)
+        pvals[i] = 0;
+
+    ms.dwLength = sizeof(MEMORYSTATUSEX);
+
+    UNREFERENCED(o);
+    if (GlobalMemoryStatusEx(&ms)) {
+        pvals[0] = (jlong)ms.ullTotalPhys;
+        pvals[1] = (jlong)ms.ullAvailPhys;
+        pvals[2] = (jlong)ms.ullTotalPageFile;
+        pvals[3] = (jlong)ms.ullAvailPageFile;
+        /* Slots 4 and 5 are for shared memory */
+        pvals[6] = (jlong)ms.dwMemoryLoad;
+    }
+    else
+        goto cleanup;
+
+    memset(st, 0, sizeof(st));
+
+    if (fnGetSystemTimes) {
+        if ((*fnGetSystemTimes)(&ft[0], &ft[1], &ft[2])) {
+            st[0] = (((ULONGLONG)ft[0].dwHighDateTime << 32) | ft[0].dwLowDateTime) / 10;
+            st[1] = (((ULONGLONG)ft[1].dwHighDateTime << 32) | ft[1].dwLowDateTime) / 10;
+            st[2] = (((ULONGLONG)ft[2].dwHighDateTime << 32) | ft[2].dwLowDateTime) / 10;
+        }
+        else
+            goto cleanup;
+    }
+#if (_WIN32_WINNT < 0x0501)
+    else if (fnNtQuerySystemInformation) {
+        BYTE buf[2048]; /* This should ne enough for 32 processors */
+        NTSTATUS rs = (*fnNtQuerySystemInformation)(SystemProcessorPerformanceInformation,
+                                           (LPVOID)buf, 2048, NULL);
+        if (rs == 0) {
+            PSYSTEM_PROCESSOR_PERFORMANCE_INFORMATION pspi = (PSYSTEM_PROCESSOR_PERFORMANCE_INFORMATION)&buf[0];
+            DWORD i;
+            /* Calculate all processors */
+            for (i = 0; i < dll_system_info.dwNumberOfProcessors; i++) {
+                st[0] += pspi[i].IdleTime.QuadPart / 10;
+                st[1] += pspi[i].KernelTime.QuadPart / 10;
+                st[2] += pspi[i].UserTime.QuadPart / 10;
+            }
+        }
+        else
+            goto cleanup;
+    }
+#endif
+    pvals[7] = st[0];
+    pvals[8] = st[1];
+    pvals[9] = st[2];
+
+    memset(st, 0, sizeof(st));
+    if (GetProcessTimes(GetCurrentProcess(), &ft[0], &ft[1], &ft[2], &ft[3])) {
+        FileTimeToAprTime((apr_time_t *)&st[0], &ft[0]);
+        st[1] = (((ULONGLONG)ft[2].dwHighDateTime << 32) | ft[2].dwLowDateTime) / 10;
+        st[2] = (((ULONGLONG)ft[3].dwHighDateTime << 32) | ft[3].dwLowDateTime) / 10;
+    }
+    pvals[10] = st[0];
+    pvals[11] = st[1];
+    pvals[12] = st[2];
+
+    if (GetProcessMemoryInfo(GetCurrentProcess(), &pmc, sizeof(pmc))) {
+        pvals[13] = pmc.WorkingSetSize;
+        pvals[14] = pmc.PeakWorkingSetSize;
+        pvals[15] = pmc.PageFaultCount;
+    }
+
+    (*e)->ReleaseLongArrayElements(e, inf, pvals, 0);
+    return APR_SUCCESS;
+cleanup:
+    rv = apr_get_os_error();
+    (*e)->ReleaseLongArrayElements(e, inf, pvals, 0);
+    return rv;
+}
+
+static DWORD WINAPI password_thread(void *data)
+{
+    tcn_pass_cb_t *cb = (tcn_pass_cb_t *)data;
+    MSG     msg;
+    HWINSTA hwss;
+    HWINSTA hwsu;
+    HDESK   hwds;
+    HDESK   hwdu;
+    HWND    hwnd;
+
+    /* Ensure connection to service window station and desktop, and
+     * save their handles.
+     */
+    GetDesktopWindow();
+    hwss = GetProcessWindowStation();
+    hwds = GetThreadDesktop(GetCurrentThreadId());
+
+    /* Impersonate the client and connect to the User's
+     * window station and desktop.
+     */
+    hwsu = OpenWindowStation("WinSta0", FALSE, MAXIMUM_ALLOWED);
+    if (hwsu == NULL) {
+        ExitThread(1);
+        return 1;
+    }
+    SetProcessWindowStation(hwsu);
+    hwdu = OpenDesktop("Default", 0, FALSE, MAXIMUM_ALLOWED);
+    if (hwdu == NULL) {
+        SetProcessWindowStation(hwss);
+        CloseWindowStation(hwsu);
+        ExitThread(1);
+        return 1;
+    }
+    SetThreadDesktop(hwdu);
+
+    hwnd = CreateDialog(dll_instance, MAKEINTRESOURCE(1001), NULL, NULL);
+    if (hwnd != NULL)
+        ShowWindow(hwnd, SW_SHOW);
+    else  {
+        ExitThread(1);
+        return 1;
+    }
+    while (1) {
+        if (PeekMessage(&msg, hwnd, 0, 0, PM_REMOVE)) {
+            if (msg.message == WM_KEYUP) {
+                int nVirtKey = (int)msg.wParam;
+                if (nVirtKey == VK_ESCAPE) {
+                    DestroyWindow(hwnd);
+                    break;
+                }
+                else if (nVirtKey == VK_RETURN) {
+                    HWND he = GetDlgItem(hwnd, 1002);
+                    if (he) {
+                        int n = GetWindowText(he, cb->password, SSL_MAX_PASSWORD_LEN - 1);
+                        cb->password[n] = '\0';
+                    }
+                    DestroyWindow(hwnd);
+                    break;
+                }
+            }
+            TranslateMessage(&msg);
+            DispatchMessage(&msg);
+        }
+        else
+            Sleep(100);
+    }
+    /* Restore window station and desktop.
+     */
+    SetThreadDesktop(hwds);
+    SetProcessWindowStation(hwss);
+    CloseDesktop(hwdu);
+    CloseWindowStation(hwsu);
+
+    ExitThread(0);
+    return 0;
+}
+
+int WIN32_SSL_password_prompt(tcn_pass_cb_t *data)
+{
+    DWORD id;
+    HANDLE thread;
+    /* TODO: See how to display this from service mode */
+    thread = CreateThread(NULL, 0,
+                password_thread, data,
+                0, &id);
+    WaitForSingleObject(thread, INFINITE);
+    CloseHandle(thread);
+    return (int)strlen(data->password);
+}
+
+

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/src/address.c
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/src/address.c	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/src/address.c	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,105 @@
+/* Copyright 2000-2006 The Apache Software Foundation
+ *
+ * Licensed 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.
+ */
+
+/*
+ *
+ * @author Mladen Turk
+ * @version $Revision: 416783 $, $Date: 2006-06-23 20:06:15 +0200 (pet, 23 lip 2006) $
+ */
+
+#include "tcn.h"
+
+TCN_IMPLEMENT_CALL(jlong, Address, info)(TCN_STDARGS,
+                                         jstring hostname,
+                                         jint family, jint port,
+                                         jint flags, jlong pool)
+{
+    apr_pool_t *p = J2P(pool, apr_pool_t *);
+    TCN_ALLOC_CSTRING(hostname);
+    apr_sockaddr_t *sa = NULL;
+    apr_int32_t f;
+
+
+    UNREFERENCED(o);
+    GET_S_FAMILY(f, family);
+    TCN_THROW_IF_ERR(apr_sockaddr_info_get(&sa,
+            J2S(hostname), f, (apr_port_t)port,
+            (apr_int32_t)flags, p), sa);
+
+cleanup:
+    TCN_FREE_CSTRING(hostname);
+    return P2J(sa);
+}
+
+TCN_IMPLEMENT_CALL(jstring, Address, getnameinfo)(TCN_STDARGS,
+                                                  jlong sa, jint flags)
+{
+    apr_sockaddr_t *s = J2P(sa, apr_sockaddr_t *);
+    char *hostname;
+
+    UNREFERENCED(o);
+    if (apr_getnameinfo(&hostname, s, (apr_int32_t)flags) == APR_SUCCESS)
+        return AJP_TO_JSTRING(hostname);
+    else
+        return NULL;
+}
+
+TCN_IMPLEMENT_CALL(jstring, Address, getip)(TCN_STDARGS, jlong sa)
+{
+    apr_sockaddr_t *s = J2P(sa, apr_sockaddr_t *);
+    char *ipaddr;
+
+    UNREFERENCED(o);
+    if (apr_sockaddr_ip_get(&ipaddr, s) == APR_SUCCESS)
+        return AJP_TO_JSTRING(ipaddr);
+    else
+        return NULL;
+}
+
+TCN_IMPLEMENT_CALL(jlong, Address, get)(TCN_STDARGS, jint which,
+                                        jlong sock)
+{
+    tcn_socket_t *s = J2P(sock, tcn_socket_t *);
+    apr_sockaddr_t *sa = NULL;
+
+    UNREFERENCED(o);
+    TCN_THROW_IF_ERR(apr_socket_addr_get(&sa,
+                        (apr_interface_e)which, s->sock), sa);
+cleanup:
+    return P2J(sa);
+}
+
+TCN_IMPLEMENT_CALL(jint, Address, equal)(TCN_STDARGS,
+                                         jlong a, jlong b)
+{
+    apr_sockaddr_t *sa = J2P(a, apr_sockaddr_t *);
+    apr_sockaddr_t *sb = J2P(b, apr_sockaddr_t *);
+
+    UNREFERENCED_STDARGS;
+    return apr_sockaddr_equal(sa, sb) ? JNI_TRUE : JNI_FALSE;
+}
+
+TCN_IMPLEMENT_CALL(jint, Address, getservbyname)(TCN_STDARGS,
+                                                 jlong sa, jstring servname)
+{
+    apr_sockaddr_t *s = J2P(sa, apr_sockaddr_t *);
+    TCN_ALLOC_CSTRING(servname);
+    apr_status_t rv;
+
+    UNREFERENCED(o);
+    rv = apr_getservbyname(s, J2S(servname));
+    TCN_FREE_CSTRING(servname);
+    return (jint)rv;
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/src/dir.c
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/src/dir.c	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/src/dir.c	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,104 @@
+/* Copyright 2000-2005 The Apache Software Foundation
+ *
+ * Licensed 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.
+ */
+
+/*
+ *
+ * @author Mladen Turk
+ * @version $Revision: 300969 $, $Date: 2005-07-12 09:56:11 -0500 (Tue, 12 Jul 2005) $
+ */
+ 
+#include "tcn.h"
+#include "apr_file_io.h"
+
+TCN_IMPLEMENT_CALL(jint, Directory, make)(TCN_STDARGS, jstring path,
+                                          jint perm, jlong pool)
+{
+    apr_pool_t *p = J2P(pool, apr_pool_t *);
+    TCN_ALLOC_CSTRING(path);
+    apr_status_t rv;
+
+    UNREFERENCED(o);
+    rv = apr_dir_make(J2S(path), (apr_fileperms_t)perm, p);
+    TCN_FREE_CSTRING(path);
+    return (jint)rv;
+}
+
+TCN_IMPLEMENT_CALL(jint, Directory, makeRecursive)(TCN_STDARGS, jstring path,
+                                                    jint perm, jlong pool)
+{
+    apr_pool_t *p = J2P(pool, apr_pool_t *);
+    TCN_ALLOC_CSTRING(path);
+    apr_status_t rv;
+
+    UNREFERENCED(o);
+    rv = apr_dir_make_recursive(J2S(path), (apr_fileperms_t)perm, p);
+    TCN_FREE_CSTRING(path);
+    return (jint)rv;
+}
+
+TCN_IMPLEMENT_CALL(jint, Directory, remove)(TCN_STDARGS, jstring path,
+                                            jlong pool)
+{
+    apr_pool_t *p = J2P(pool, apr_pool_t *);
+    TCN_ALLOC_CSTRING(path);
+    apr_status_t rv;
+
+    UNREFERENCED(o);
+    rv = apr_dir_remove(J2S(path), p);
+    TCN_FREE_CSTRING(path);
+    return (jint)rv;
+}
+
+TCN_IMPLEMENT_CALL(jstring, Directory, tempGet)(TCN_STDARGS, jlong pool)
+{
+    apr_pool_t *p = J2P(pool, apr_pool_t *);
+    jstring name = NULL;
+    const char *tname;
+
+    UNREFERENCED(o);
+    if (apr_temp_dir_get(&tname, p) == APR_SUCCESS)
+        name = AJP_TO_JSTRING(tname);
+
+    return name;
+}
+
+TCN_IMPLEMENT_CALL(jlong, Directory, open)(TCN_STDARGS, jstring path,
+                                      jlong pool)
+{
+    apr_pool_t *p = J2P(pool, apr_pool_t *);
+    apr_dir_t *d = NULL;
+    TCN_ALLOC_CSTRING(path);
+
+    UNREFERENCED(o);
+    TCN_THROW_IF_ERR(apr_dir_open(&d, J2S(path), p), d);
+
+cleanup:
+    TCN_FREE_CSTRING(path);
+    return P2J(d);
+}
+
+TCN_IMPLEMENT_CALL(jint, Directory, close)(TCN_STDARGS, jlong dir)
+{
+    apr_dir_t *d = J2P(dir, apr_dir_t *);
+    UNREFERENCED_STDARGS;
+    return (jint)apr_dir_close(d);
+}
+
+TCN_IMPLEMENT_CALL(jint, Directory, rewind)(TCN_STDARGS, jlong dir)
+{
+    apr_dir_t *d = J2P(dir, apr_dir_t *);
+    UNREFERENCED_STDARGS;
+    return (jint)apr_dir_rewind(d);
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/src/error.c
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/src/error.c	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/src/error.c	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,247 @@
+/* Copyright 2000-2005 The Apache Software Foundation
+ *
+ * Licensed 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.
+ */
+
+/*
+ *
+ * @author Mladen Turk
+ * @version $Revision: 440699 $, $Date: 2006-09-06 07:30:48 -0500 (Wed, 06 Sep 2006) $
+ */
+
+#include "tcn.h"
+
+static const char *tcn_errors[] = {
+                            "Unknown user error",
+    /* TCN_TIMEUP      */   "Operation timed out",
+    /* TCN_EAGAIN      */   "There is no data ready",
+    /* TCN_EINTR       */   "Interrupted system call",
+    /* TCN_EINPROGRESS */   "Operation in progress",
+    /* TCN_ETIMEDOUT   */   "Connection timed out",
+    NULL
+};
+
+/* Merge IS_ETIMEDOUT with APR_TIMEUP
+ */
+#define TCN_STATUS_IS_ETIMEDOUT(x) (APR_STATUS_IS_ETIMEDOUT((x)) || ((x) == APR_TIMEUP))
+/*
+ * Convenience function to help throw an java.lang.Exception.
+ */
+void tcn_ThrowException(JNIEnv *env, const char *msg)
+{
+    jclass javaExceptionClass;
+
+    javaExceptionClass = (*env)->FindClass(env, "java/lang/Exception");
+    if (javaExceptionClass == NULL) {
+        fprintf(stderr, "Cannot find java/lang/Exception class\n");
+        return;
+    }
+    (*env)->ThrowNew(env, javaExceptionClass, msg);
+    (*env)->DeleteLocalRef(env, javaExceptionClass);
+
+}
+
+void tcn_ThrowMemoryException(JNIEnv *env, const char *file, int line, const char *msg)
+{
+    jclass javaExceptionClass;
+    javaExceptionClass = (*env)->FindClass(env, "java/lang/OutOfMemoryError");
+    if (javaExceptionClass == NULL) {
+        fprintf(stderr, "Cannot find java/lang/OutOfMemoryError\n");
+        return;
+    }
+
+    if (file) {
+        char fmt[TCN_BUFFER_SZ];
+        char *f = (char *)(file + strlen(file) - 1);
+        while (f != file && '\\' != *f && '/' != *f) {
+            f--;
+        }
+        if (f != file) {
+            f++;
+        }
+        sprintf(fmt, "%s for [%s::%04d]", msg, line, f);
+        (*env)->ThrowNew(env, javaExceptionClass, &fmt[0]);
+    }
+    else
+        (*env)->ThrowNew(env, javaExceptionClass, msg);
+    (*env)->DeleteLocalRef(env, javaExceptionClass);
+
+}
+
+
+void tcn_Throw(JNIEnv *env, const char *fmt, ...)
+{
+    char msg[TCN_BUFFER_SZ] = {'\0'};
+    va_list ap;
+
+    va_start(ap, fmt);
+    apr_vsnprintf(msg, TCN_BUFFER_SZ, fmt, ap);
+    tcn_ThrowException(env, msg);
+    va_end(ap);
+}
+
+/*
+ * Convenience function to help throw an APR Exception
+ * from native error code.
+ */
+void tcn_ThrowAPRException(JNIEnv *e, apr_status_t err)
+{
+    jclass aprErrorClass;
+    jmethodID constructorID = 0;
+    jobject throwObj;
+    jstring jdescription;
+    char serr[512] = {0};
+
+    aprErrorClass = (*e)->FindClass(e, TCN_ERROR_CLASS);
+    if (aprErrorClass == NULL) {
+        fprintf(stderr, "Cannot find " TCN_ERROR_CLASS " class\n");
+        return;
+    }
+
+    /* Find the constructor ID */
+    constructorID = (*e)->GetMethodID(e, aprErrorClass,
+                                      "<init>",
+                                      "(ILjava/lang/String;)V");
+    if (constructorID == NULL) {
+        fprintf(stderr,
+                "Cannot find constructor for " TCN_ERROR_CLASS " class\n");
+        goto cleanup;
+    }
+
+    apr_strerror(err, serr, 512);
+    /* Obtain the string objects */
+    jdescription = AJP_TO_JSTRING(serr);
+    if (jdescription == NULL) {
+        fprintf(stderr,
+                "Cannot allocate description for " TCN_ERROR_CLASS " class\n");
+        goto cleanup;
+    }
+    /* Create the APR Error object */
+    throwObj = (*e)->NewObject(e, aprErrorClass, constructorID,
+                               (jint)err, jdescription);
+    if (throwObj == NULL) {
+        fprintf(stderr,
+                "Cannot allocate new " TCN_ERROR_CLASS " object\n");
+        goto cleanup;
+    }
+
+    (*e)->Throw(e, throwObj);
+cleanup:
+    (*e)->DeleteLocalRef(e, aprErrorClass);
+}
+
+
+TCN_IMPLEMENT_CALL(jint, Error, osError)(TCN_STDARGS)
+{
+    UNREFERENCED_STDARGS;
+    return (jint)apr_get_os_error();
+}
+
+TCN_IMPLEMENT_CALL(jint, Error, netosError)(TCN_STDARGS)
+{
+    UNREFERENCED_STDARGS;
+    return (jint)apr_get_netos_error();
+}
+
+TCN_IMPLEMENT_CALL(jstring, Error, strerror)(TCN_STDARGS, jint err)
+{
+    char serr[512] = {0};
+    jstring jerr;
+
+    UNREFERENCED(o);
+    if (err >= TCN_TIMEUP && err <= TCN_ETIMEDOUT) {
+        err -= TCN_TIMEUP;
+        jerr = AJP_TO_JSTRING(tcn_errors[err + 1]);
+    }
+    else {
+        apr_strerror(err, serr, 512);
+        jerr = AJP_TO_JSTRING(serr);
+    }
+    return jerr;
+}
+
+TCN_IMPLEMENT_CALL(jboolean, Status, is)(TCN_STDARGS, jint err, jint idx)
+{
+#define APR_IS(I, E) case I: if (E(err)) return JNI_TRUE; break
+#define APR_ISX(I, E, T) case I: if (E(err) || (err == T)) return JNI_TRUE; break
+
+    UNREFERENCED_STDARGS;
+    switch (idx) {
+        APR_IS(1,  APR_STATUS_IS_ENOSTAT);
+        APR_IS(2,  APR_STATUS_IS_ENOPOOL);
+        /* empty slot: +3 */
+        APR_IS(4,  APR_STATUS_IS_EBADDATE);
+        APR_IS(5,  APR_STATUS_IS_EINVALSOCK);
+        APR_IS(6,  APR_STATUS_IS_ENOPROC);
+        APR_IS(7,  APR_STATUS_IS_ENOTIME);
+        APR_IS(8,  APR_STATUS_IS_ENODIR);
+        APR_IS(9,  APR_STATUS_IS_ENOLOCK);
+        APR_IS(10, APR_STATUS_IS_ENOPOLL);
+        APR_IS(11, APR_STATUS_IS_ENOSOCKET);
+        APR_IS(12, APR_STATUS_IS_ENOTHREAD);
+        APR_IS(13, APR_STATUS_IS_ENOTHDKEY);
+        APR_IS(14, APR_STATUS_IS_EGENERAL);
+        APR_IS(15, APR_STATUS_IS_ENOSHMAVAIL);
+        APR_IS(16, APR_STATUS_IS_EBADIP);
+        APR_IS(17, APR_STATUS_IS_EBADMASK);
+        /* empty slot: +18 */
+        APR_IS(19, APR_STATUS_IS_EDSOOPEN);
+        APR_IS(20, APR_STATUS_IS_EABSOLUTE);
+        APR_IS(21, APR_STATUS_IS_ERELATIVE);
+        APR_IS(22, APR_STATUS_IS_EINCOMPLETE);
+        APR_IS(23, APR_STATUS_IS_EABOVEROOT);
+        APR_IS(24, APR_STATUS_IS_EBADPATH);
+        APR_IS(25, APR_STATUS_IS_EPATHWILD);
+        APR_IS(26, APR_STATUS_IS_ESYMNOTFOUND);
+        APR_IS(27, APR_STATUS_IS_EPROC_UNKNOWN);
+        APR_IS(28, APR_STATUS_IS_ENOTENOUGHENTROPY);
+
+
+        /* APR_Error */
+        APR_IS(51, APR_STATUS_IS_INCHILD);
+        APR_IS(52, APR_STATUS_IS_INPARENT);
+        APR_IS(53, APR_STATUS_IS_DETACH);
+        APR_IS(54, APR_STATUS_IS_NOTDETACH);
+        APR_IS(55, APR_STATUS_IS_CHILD_DONE);
+        APR_IS(56, APR_STATUS_IS_CHILD_NOTDONE);
+        APR_ISX(57, APR_STATUS_IS_TIMEUP, TCN_TIMEUP);
+        APR_IS(58, APR_STATUS_IS_INCOMPLETE);
+        /* empty slot: +9 */
+        /* empty slot: +10 */
+        /* empty slot: +11 */
+        APR_IS(62, APR_STATUS_IS_BADCH);
+        APR_IS(63, APR_STATUS_IS_BADARG);
+        APR_IS(64, APR_STATUS_IS_EOF);
+        APR_IS(65, APR_STATUS_IS_NOTFOUND);
+        /* empty slot: +16 */
+        /* empty slot: +17 */
+        /* empty slot: +18 */
+        APR_IS(69, APR_STATUS_IS_ANONYMOUS);
+        APR_IS(70, APR_STATUS_IS_FILEBASED);
+        APR_IS(71, APR_STATUS_IS_KEYBASED);
+        APR_IS(72, APR_STATUS_IS_EINIT);
+        APR_IS(73, APR_STATUS_IS_ENOTIMPL);
+        APR_IS(74, APR_STATUS_IS_EMISMATCH);
+        APR_IS(75, APR_STATUS_IS_EBUSY);
+        /* Socket errors */
+        APR_ISX(90, APR_STATUS_IS_EAGAIN, TCN_EAGAIN);
+        APR_ISX(91, TCN_STATUS_IS_ETIMEDOUT, TCN_ETIMEDOUT);
+        APR_IS(92, APR_STATUS_IS_ECONNABORTED);
+        APR_IS(93, APR_STATUS_IS_ECONNRESET);
+        APR_ISX(94, APR_STATUS_IS_EINPROGRESS, TCN_EINPROGRESS);
+        APR_ISX(95, APR_STATUS_IS_EINTR, TCN_EINTR);
+        APR_IS(96, APR_STATUS_IS_ENOTSOCK);
+        APR_IS(97, APR_STATUS_IS_EINVAL);
+    }
+    return JNI_FALSE;
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/src/file.c
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/src/file.c	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/src/file.c	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,600 @@
+/* Copyright 2000-2005 The Apache Software Foundation
+ *
+ * Licensed 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.
+ */
+
+/*
+ *
+ * @author Mladen Turk
+ * @version $Revision: 377964 $, $Date: 2006-02-15 02:33:27 -0600 (Wed, 15 Feb 2006) $
+ */
+ 
+#include "tcn.h"
+#include "apr_file_io.h"
+
+
+TCN_IMPLEMENT_CALL(jint, File, close)(TCN_STDARGS, jlong file)
+{
+    apr_file_t *f = J2P(file, apr_file_t *);
+    UNREFERENCED_STDARGS;
+    return (jint)apr_file_close(f);
+}
+
+TCN_IMPLEMENT_CALL(jint, File, eof)(TCN_STDARGS, jlong file)
+{
+    apr_file_t *f = J2P(file, apr_file_t *);
+    UNREFERENCED_STDARGS;
+    return (jint)apr_file_eof(f);
+}
+
+TCN_IMPLEMENT_CALL(jint, File, flush)(TCN_STDARGS, jlong file)
+{
+    apr_file_t *f = J2P(file, apr_file_t *);
+    UNREFERENCED_STDARGS;
+    return (jint)apr_file_flush(f);
+}
+
+TCN_IMPLEMENT_CALL(jint, File, unlock)(TCN_STDARGS, jlong file)
+{
+    apr_file_t *f = J2P(file, apr_file_t *);
+    UNREFERENCED_STDARGS;
+    return (jint)apr_file_unlock(f);
+}
+
+TCN_IMPLEMENT_CALL(jint, File, flagsGet)(TCN_STDARGS, jlong file)
+{
+    apr_file_t *f = J2P(file, apr_file_t *);
+    UNREFERENCED_STDARGS;
+    return (jint)apr_file_flags_get(f);
+}
+
+TCN_IMPLEMENT_CALL(jint, File, lock)(TCN_STDARGS, jlong file, jint flags)
+{
+    apr_file_t *f = J2P(file, apr_file_t *);
+    UNREFERENCED_STDARGS;
+    return (jint)apr_file_lock(f, (int)flags);
+}
+
+TCN_IMPLEMENT_CALL(jint, File, trunc)(TCN_STDARGS, jlong file, jlong off)
+{
+    apr_file_t *f = J2P(file, apr_file_t *);
+    UNREFERENCED_STDARGS;
+    return (jint)apr_file_trunc(f, (apr_off_t)off);
+}
+
+TCN_IMPLEMENT_CALL(jlong, File, open)(TCN_STDARGS, jstring fname,
+                                      jint flag, jint perm,
+                                      jlong pool)
+{
+    apr_pool_t *p = J2P(pool, apr_pool_t *);
+    apr_file_t *f = NULL;
+    TCN_ALLOC_CSTRING(fname);
+
+    UNREFERENCED(o);
+    TCN_THROW_IF_ERR(apr_file_open(&f, J2S(fname), (apr_int32_t)flag,
+                     (apr_fileperms_t)perm, p), f);
+
+cleanup:
+    TCN_FREE_CSTRING(fname);
+    return P2J(f);
+}
+
+TCN_IMPLEMENT_CALL(jlong, File, mktemp)(TCN_STDARGS, jstring templ,
+                                      jint flags,
+                                      jint pool)
+{
+    apr_pool_t *p = J2P(pool, apr_pool_t *);
+    apr_file_t *f = NULL;
+    char *ctempl = tcn_strdup(e, templ);
+
+    UNREFERENCED(o);
+    if (!ctempl) {
+       TCN_THROW_OS_ERROR(e);
+       return 0;
+    }
+    TCN_THROW_IF_ERR(apr_file_mktemp(&f, ctempl,
+                     (apr_int32_t)flags, p), f);
+
+cleanup:
+    free(ctempl);
+    return P2J(f);
+}
+
+TCN_IMPLEMENT_CALL(jint, File, remove)(TCN_STDARGS, jstring path, jlong pool)
+{
+    apr_pool_t *p = J2P(pool, apr_pool_t *);
+    TCN_ALLOC_CSTRING(path);
+    apr_status_t rv;
+
+    UNREFERENCED(o);
+    rv = apr_file_remove(J2S(path), p);
+    TCN_FREE_CSTRING(path);
+    return (jint)rv;
+}
+
+TCN_IMPLEMENT_CALL(jint, File, rename)(TCN_STDARGS, jstring from,
+                                       jstring to, jlong pool)
+{
+    apr_pool_t *p = J2P(pool, apr_pool_t *);
+    TCN_ALLOC_CSTRING(from);
+    TCN_ALLOC_CSTRING(to);
+    apr_status_t rv;
+
+    UNREFERENCED(o);
+    rv = apr_file_rename(J2S(from), J2S(to), p);
+    TCN_FREE_CSTRING(from);
+    TCN_FREE_CSTRING(to);
+    return (jint)rv;
+}
+
+TCN_IMPLEMENT_CALL(jint, File, copy)(TCN_STDARGS, jstring from,
+                                     jstring to, jint perms, jlong pool)
+{
+    apr_pool_t *p = J2P(pool, apr_pool_t *);
+    TCN_ALLOC_CSTRING(from);
+    TCN_ALLOC_CSTRING(to);
+    apr_status_t rv;
+
+    UNREFERENCED(o);
+    rv = apr_file_copy(J2S(from), J2S(to), (apr_fileperms_t)perms, p);
+    TCN_FREE_CSTRING(from);
+    TCN_FREE_CSTRING(to);
+    return (jint)rv;
+}
+
+TCN_IMPLEMENT_CALL(jint, File, append)(TCN_STDARGS, jstring from,
+                                       jstring to, jint perms, jlong pool)
+{
+    apr_pool_t *p = J2P(pool, apr_pool_t *);
+    TCN_ALLOC_CSTRING(from);
+    TCN_ALLOC_CSTRING(to);
+    apr_status_t rv;
+
+    UNREFERENCED(o);
+    rv = apr_file_append(J2S(from), J2S(to), (apr_fileperms_t)perms, p);
+    TCN_FREE_CSTRING(from);
+    TCN_FREE_CSTRING(to);
+    return (jint)rv;
+}
+
+TCN_IMPLEMENT_CALL(jstring, File, nameGet)(TCN_STDARGS, jlong file)
+{
+    apr_file_t *f = J2P(file, apr_file_t *);
+    jstring name = NULL;
+    const char *fname;
+
+    UNREFERENCED(o);
+    if (apr_file_name_get(&fname, f) == APR_SUCCESS)
+        name = AJP_TO_JSTRING(fname);
+
+    return name;
+}
+
+TCN_IMPLEMENT_CALL(jint, File, permsSet)(TCN_STDARGS, jstring file, jint perms)
+{
+    TCN_ALLOC_CSTRING(file);
+    apr_status_t rv;
+
+    UNREFERENCED(o);
+    rv = apr_file_perms_set(J2S(file), (apr_fileperms_t)perms);
+    TCN_FREE_CSTRING(file);
+    return (jint)rv;
+}
+
+TCN_IMPLEMENT_CALL(jint, File, attrsSet)(TCN_STDARGS, jstring file, jint attrs,
+                                          jint mask, jlong pool)
+{
+    apr_pool_t *p = J2P(pool, apr_pool_t *);
+    TCN_ALLOC_CSTRING(file);
+    apr_status_t rv;
+
+    UNREFERENCED(o);
+    rv = apr_file_attrs_set(J2S(file), (apr_fileattrs_t)attrs,
+                            (apr_fileattrs_t)mask, p);
+    TCN_FREE_CSTRING(file);
+    return (jint)rv;
+}
+
+TCN_IMPLEMENT_CALL(jint, File, mtimeSet)(TCN_STDARGS, jstring file, jlong mtime,
+                                          jlong pool)
+{
+    apr_pool_t *p = J2P(pool, apr_pool_t *);
+    TCN_ALLOC_CSTRING(file);
+    apr_status_t rv;
+
+    UNREFERENCED(o);
+    rv = apr_file_mtime_set(J2S(file), J2T(mtime), p);
+    TCN_FREE_CSTRING(file);
+    return (jint)rv;
+}
+
+TCN_IMPLEMENT_CALL(jlong, File, seek)(TCN_STDARGS, jlong file,
+                                      jint where, jlong offset)
+{
+    apr_file_t *f = J2P(file, apr_file_t *);
+    apr_off_t pos = (apr_off_t)offset;
+    apr_seek_where_t w;
+    UNREFERENCED(o);
+    switch (where) {
+        case 1:
+            w = APR_CUR;
+            break;
+        case 2:
+            w = APR_END;
+            break;
+        default:
+            w = APR_SET;
+            break;
+    }
+    TCN_THROW_IF_ERR(apr_file_seek(f, w, &pos), pos);
+
+cleanup:
+    return (jlong)pos;
+}
+
+TCN_IMPLEMENT_CALL(jint, File, putc)(TCN_STDARGS, jbyte c, jlong file)
+{
+    apr_file_t *f = J2P(file, apr_file_t *);
+    UNREFERENCED_STDARGS;
+    return (jint)apr_file_putc((char)c, f);
+}
+
+TCN_IMPLEMENT_CALL(jint, File, getc)(TCN_STDARGS, jlong file)
+{
+    apr_file_t *f = J2P(file, apr_file_t *);
+    char ch;
+
+    UNREFERENCED_STDARGS;
+    TCN_THROW_IF_ERR(apr_file_getc(&ch, f), ch);
+
+cleanup:
+    return (jint)ch;
+}
+
+TCN_IMPLEMENT_CALL(jint, File, ungetc)(TCN_STDARGS, jbyte c, jlong file)
+{
+    apr_file_t *f = J2P(file, apr_file_t *);
+    UNREFERENCED_STDARGS;
+    return (jint)apr_file_ungetc((char)c, f);
+}
+
+TCN_IMPLEMENT_CALL(jint, File, puts)(TCN_STDARGS, jbyteArray str, jlong file)
+{
+    apr_status_t rv = APR_EINVAL;
+    apr_file_t *f = J2P(file, apr_file_t *);
+    jbyte *bytes = (*e)->GetPrimitiveArrayCritical(e, str, NULL);
+
+    UNREFERENCED(o);
+    if (bytes) {
+        rv = apr_file_puts((const char *)bytes, f);
+        (*e)->ReleasePrimitiveArrayCritical(e, str, bytes, JNI_ABORT);
+    }
+    return (jint)rv;
+}
+
+TCN_IMPLEMENT_CALL(jint, File, write)(TCN_STDARGS, jlong file,
+                                      jbyteArray buf, jint offset, jint towrite)
+{
+    apr_file_t *f = J2P(file, apr_file_t *);
+    apr_size_t nbytes = (apr_size_t)towrite;
+    jbyte *bytes = (*e)->GetPrimitiveArrayCritical(e, buf, NULL);
+    apr_status_t ss;
+
+    UNREFERENCED(o);
+    if (towrite < 0)
+        towrite = (*e)->GetArrayLength(e, buf);
+    ss = apr_file_write(f, bytes + offset, &nbytes);
+
+    (*e)->ReleasePrimitiveArrayCritical(e, buf, bytes, JNI_ABORT);
+    if (ss == APR_SUCCESS)
+        return (jint)nbytes;
+    else
+        return -(jint)ss;
+}
+
+TCN_IMPLEMENT_CALL(jint, File, writeb)(TCN_STDARGS, jlong file,
+                                       jobject buf, jint offset, jint towrite)
+{
+    apr_file_t *f = J2P(file, apr_file_t *);
+    apr_size_t nbytes = (apr_size_t)towrite;
+    char *bytes = (char *)(*e)->GetDirectBufferAddress(e, buf);
+    apr_status_t ss = APR_EINVAL;
+
+    UNREFERENCED(o);
+    if (bytes)
+        ss = apr_file_write(f, bytes + offset, &nbytes);
+
+    if (ss == APR_SUCCESS)
+        return (jint)nbytes;
+    else
+        return -(jint)ss;
+}
+
+TCN_IMPLEMENT_CALL(jint, File, writeFull)(TCN_STDARGS, jlong file,
+                                          jbyteArray buf, jint offset, jint towrite)
+{
+    apr_file_t *f = J2P(file, apr_file_t *);
+    apr_size_t nbytes = (apr_size_t)towrite;
+    apr_size_t written = 0;
+    apr_status_t ss;
+    jbyte *bytes = (*e)->GetByteArrayElements(e, buf, NULL);
+
+    UNREFERENCED(o);
+    if (towrite < 0)
+        towrite = (*e)->GetArrayLength(e, buf);
+    ss = apr_file_write_full(f, bytes + offset, nbytes, &written);
+
+    (*e)->ReleaseByteArrayElements(e, buf, bytes, JNI_ABORT);
+    if (ss == APR_SUCCESS)
+        return (jint)written;
+    else
+        return -(jint)ss;
+}
+
+TCN_IMPLEMENT_CALL(jint, File, writeFullb)(TCN_STDARGS, jlong file,
+                                           jobject buf, jint offset, jint towrite)
+{
+    apr_file_t *f = J2P(file, apr_file_t *);
+    apr_size_t nbytes = (apr_size_t)towrite;
+    apr_size_t written = 0;
+    apr_status_t ss = APR_EINVAL;
+    char *bytes = (char *)(*e)->GetDirectBufferAddress(e, buf);
+
+    UNREFERENCED(o);
+    if (bytes)
+        ss = apr_file_write_full(f, bytes + offset, nbytes, &written);
+
+    if (ss == APR_SUCCESS)
+        return (jint)written;
+    else
+        return -(jint)ss;
+}
+
+TCN_IMPLEMENT_CALL(jint, File, writev)(TCN_STDARGS, jlong file,
+                                       jobjectArray bufs)
+{
+    apr_file_t *f = J2P(file, apr_file_t *);
+    jsize nvec = (*e)->GetArrayLength(e, bufs);
+    jsize i;
+    struct iovec vec[APR_MAX_IOVEC_SIZE];
+    jobject ba[APR_MAX_IOVEC_SIZE];
+    apr_size_t written = 0;
+    apr_status_t ss;
+
+    UNREFERENCED(o);
+
+    if (nvec >= APR_MAX_IOVEC_SIZE) {
+        /* TODO: Throw something here */
+        return 0;
+    }
+    for (i = 0; i < nvec; i++) {
+        ba[i] = (*e)->GetObjectArrayElement(e, bufs, i);
+        vec[i].iov_len  = (*e)->GetArrayLength(e, ba[i]);
+        vec[i].iov_base = (*e)->GetByteArrayElements(e, ba[i], NULL);
+    }
+
+    ss = apr_file_writev(f, vec, nvec, &written);
+
+    for (i = 0; i < nvec; i++) {
+        (*e)->ReleaseByteArrayElements(e, ba[i], vec[i].iov_base, JNI_ABORT);
+    }
+    if (ss == APR_SUCCESS)
+        return (jint)written;
+    else
+        return -(jint)ss;
+}
+
+TCN_IMPLEMENT_CALL(jint, File, writevFull)(TCN_STDARGS, jlong file,
+                                           jobjectArray bufs)
+{
+    apr_file_t *f = J2P(file, apr_file_t *);
+    jsize nvec = (*e)->GetArrayLength(e, bufs);
+    jsize i;
+    struct iovec vec[APR_MAX_IOVEC_SIZE];
+    jobject ba[APR_MAX_IOVEC_SIZE];
+    apr_size_t written = 0;
+    apr_status_t ss;
+
+    UNREFERENCED(o);
+
+    if (nvec >= APR_MAX_IOVEC_SIZE) {
+        /* TODO: Throw something here */
+        return 0;
+    }
+    for (i = 0; i < nvec; i++) {
+        ba[i] = (*e)->GetObjectArrayElement(e, bufs, i);
+        vec[i].iov_len  = (*e)->GetArrayLength(e, ba[i]);
+        vec[i].iov_base = (*e)->GetByteArrayElements(e, ba[i], NULL);
+    }
+#if (APR_VERSION_MAJOR >= 1) && (APR_VERSION_MINOR >= 1)
+    ss = apr_file_writev_full(f, vec, nvec, &written);
+#else
+    ss = apr_file_writev(f, vec, nvec, &written);
+#endif
+
+    for (i = 0; i < nvec; i++) {
+        (*e)->ReleaseByteArrayElements(e, ba[i], vec[i].iov_base,
+                                       JNI_ABORT);
+    }
+    if (ss == APR_SUCCESS)
+        return (jint)written;
+    else
+        return -(jint)ss;
+}
+
+TCN_IMPLEMENT_CALL(jint, File, read)(TCN_STDARGS, jlong file,
+                                     jbyteArray buf, jint offset,
+                                     jint toread)
+{
+    apr_file_t *f = J2P(file, apr_file_t *);
+    apr_size_t nbytes = (apr_size_t)toread;
+    jbyte *bytes = (*e)->GetByteArrayElements(e, buf, NULL);
+    apr_status_t ss;
+
+    UNREFERENCED(o);
+    ss = apr_file_read(f, bytes + offset, &nbytes);
+
+    (*e)->ReleaseByteArrayElements(e, buf, bytes,
+                                   ss == APR_SUCCESS ? 0 : JNI_ABORT);
+    if (ss == APR_SUCCESS)
+        return (jint)nbytes;
+    else
+        return -(jint)ss;
+}
+
+TCN_IMPLEMENT_CALL(jint, File, readb)(TCN_STDARGS, jlong file,
+                                      jobject buf, jint offset,
+                                      jint toread)
+{
+    apr_file_t *f = J2P(file, apr_file_t *);
+    apr_size_t nbytes = (apr_size_t)toread;
+    char *bytes = (char *)(*e)->GetDirectBufferAddress(e, buf);
+    apr_status_t ss = APR_EINVAL;
+
+    UNREFERENCED(o);
+    if (bytes)
+        ss = apr_file_read(f, bytes + offset, &nbytes);
+
+    if (ss == APR_SUCCESS)
+        return (jint)nbytes;
+    else
+        return -(jint)ss;
+}
+
+TCN_IMPLEMENT_CALL(jint, File, readFull)(TCN_STDARGS, jlong file,
+                                         jbyteArray buf, jint offset,
+                                         jint toread)
+{
+    apr_file_t *f = J2P(file, apr_file_t *);
+    apr_size_t nbytes = (apr_size_t)toread;
+    apr_size_t nread  = 0;
+    apr_status_t ss;
+    jbyte *bytes = (*e)->GetByteArrayElements(e, buf, NULL);
+
+    UNREFERENCED(o);
+    ss = apr_file_read_full(f, bytes + offset, nbytes, &nread);
+
+    (*e)->ReleaseByteArrayElements(e, buf, bytes,
+                                   ss == APR_SUCCESS ? 0 : JNI_ABORT);
+    if (ss == APR_SUCCESS)
+        return (jint)nread;
+    else
+        return -(jint)ss;
+}
+
+TCN_IMPLEMENT_CALL(jint, File, readFullb)(TCN_STDARGS, jlong file,
+                                          jobject buf, jint offset,
+                                          jint toread)
+{
+    apr_file_t *f = J2P(file, apr_file_t *);
+    apr_size_t nbytes = (apr_size_t)toread;
+    apr_size_t nread  = 0;
+    char *bytes = (char *)(*e)->GetDirectBufferAddress(e, buf);
+    apr_status_t ss = APR_EINVAL;
+
+    UNREFERENCED(o);
+    if (bytes)
+        ss = apr_file_read_full(f, bytes + offset, nbytes, &nread);
+
+    if (ss == APR_SUCCESS)
+        return (jint)nread;
+    else
+        return -(jint)ss;
+}
+
+TCN_IMPLEMENT_CALL(jint, File, gets)(TCN_STDARGS, jbyteArray buf, jint offset,
+                                     jlong file)
+{
+    apr_status_t rv;
+    apr_file_t *f = J2P(file, apr_file_t *);
+    jsize nbytes = (*e)->GetArrayLength(e, buf);
+    jbyte *bytes = (*e)->GetByteArrayElements(e, buf, NULL);
+
+    UNREFERENCED(o);
+    rv = apr_file_gets((char*)(bytes + offset),nbytes - offset, f);
+    (*e)->ReleaseByteArrayElements(e, buf, bytes,
+                                   rv == APR_SUCCESS ? 0 : JNI_ABORT);
+    return (jint)rv;
+}
+
+TCN_IMPLEMENT_CALL(jint, File, pipeCreate)(TCN_STDARGS, jlongArray io, jlong pool)
+{
+    apr_status_t rv;
+    apr_pool_t *p = J2P(pool, apr_pool_t *);
+    jsize npipes = (*e)->GetArrayLength(e, io);
+    jlong *pipes = (*e)->GetLongArrayElements(e, io, NULL);
+    apr_file_t *in;
+    apr_file_t *out;
+
+    UNREFERENCED(o);
+    if (npipes < 2) {
+        (*e)->ReleaseLongArrayElements(e, io, pipes, JNI_ABORT);
+        return APR_EINVAL;
+    }
+
+    rv = apr_file_pipe_create(&in, &out, p);
+    if (rv == APR_SUCCESS) {
+        pipes[0] = P2J(in);
+        pipes[1] = P2J(out);
+        (*e)->ReleaseLongArrayElements(e, io, pipes, 0);
+    }
+    else
+        (*e)->ReleaseLongArrayElements(e, io, pipes, JNI_ABORT);
+
+    return (jint)rv;
+}
+
+TCN_IMPLEMENT_CALL(jint, File, pipeTimeoutSet)(TCN_STDARGS, jlong pipe,
+                                               jlong timeout)
+{
+    apr_file_t *f = J2P(pipe, apr_file_t *);
+    UNREFERENCED_STDARGS;
+    return (jint)apr_file_pipe_timeout_set(f, J2T(timeout));
+}
+
+TCN_IMPLEMENT_CALL(jlong, File, pipeTimeoutGet)(TCN_STDARGS, jlong pipe)
+{
+    apr_file_t *f = J2P(pipe, apr_file_t *);
+    apr_interval_time_t timeout;
+
+    UNREFERENCED(o);
+    TCN_THROW_IF_ERR(apr_file_pipe_timeout_get(f, &timeout), timeout);
+
+cleanup:
+    return (jlong)timeout;
+}
+
+TCN_IMPLEMENT_CALL(jlong, File, dup)(TCN_STDARGS, jlong newf, jlong file,
+                                     jlong pool)
+{
+    apr_file_t *f = J2P(file, apr_file_t *);
+    apr_pool_t *p = J2P(pool, apr_pool_t *);
+    apr_file_t *d = J2P(newf, apr_file_t *);
+
+    UNREFERENCED(o);
+    TCN_THROW_IF_ERR(apr_file_dup(&d, f, p), d);
+
+cleanup:
+    return P2J(d);
+}
+
+TCN_IMPLEMENT_CALL(jint, File, dup2)(TCN_STDARGS, jlong newf, jlong file,
+                                     jlong pool)
+{
+    apr_file_t *f = J2P(file, apr_file_t *);
+    apr_pool_t *p = J2P(pool, apr_pool_t *);
+    apr_file_t *d = J2P(newf, apr_file_t *);
+
+    UNREFERENCED_STDARGS;
+    return (jint)apr_file_dup2(d, f, p);
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/src/info.c
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/src/info.c	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/src/info.c	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,351 @@
+/* Copyright 2000-2005 The Apache Software Foundation
+ *
+ * Licensed 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.
+ */
+
+/*
+ *
+ * @author Mladen Turk
+ * @version $Revision: 300969 $, $Date: 2005-07-12 09:56:11 -0500 (Tue, 12 Jul 2005) $
+ */
+ 
+#include "tcn.h"
+#include "apr_file_io.h"
+
+#define DECLARE_FINFO_FIELD(name) static jfieldID _fid##name = NULL
+#define FINFO_FIELD(name)         _fid##name
+
+#define GET_FINFO_I(N)      \
+    _fid##N = (*e)->GetFieldID(e, finfo, #N, "I");  \
+    if (_fid##N == NULL) {                          \
+        (*e)->ExceptionClear(e);                    \
+        goto cleanup;                               \
+    } else (void)(0)
+
+#define GET_FINFO_J(N)      \
+    _fid##N = (*e)->GetFieldID(e, finfo, #N, "J");  \
+    if (_fid##N == NULL) {                          \
+        (*e)->ExceptionClear(e);                    \
+        goto cleanup;                               \
+    } else (void)(0)
+
+#define GET_FINFO_S(N)      \
+    _fid##N = (*e)->GetFieldID(e, finfo, #N,        \
+                             "Ljava/lang/String;"); \
+    if (_fid##N == NULL) {                          \
+        (*e)->ExceptionClear(e);                    \
+        goto cleanup;                               \
+    } else (void)(0)
+
+#define SET_FINFO_I(N, V)  \
+    (*e)->SetIntField(e, obj, _fid##N, (jint)(V))
+
+#define SET_FINFO_J(N, V)  \
+    (*e)->SetLongField(e, obj, _fid##N, (jlong)(V))
+
+#define SET_FINFO_S(N, V)                 \
+    (*e)->SetObjectField(e, obj, _fid##N, \
+        (V) ? AJP_TO_JSTRING((V)) : NULL)
+
+
+#define DECLARE_AINFO_FIELD(name) static jfieldID _aid##name = NULL
+#define AINFO_FIELD(name)         _aid##name
+
+#define GET_AINFO_I(N)      \
+    _aid##N = (*e)->GetFieldID(e, ainfo, #N, "I");  \
+    if (_aid##N == NULL) {                          \
+        (*e)->ExceptionClear(e);                    \
+        goto cleanup;                               \
+    } else (void)(0)
+
+#define GET_AINFO_J(N)      \
+    _aid##N = (*e)->GetFieldID(e, ainfo, #N, "J");  \
+    if (_aid##N == NULL) {                          \
+        (*e)->ExceptionClear(e);                    \
+        goto cleanup;                               \
+    } else (void)(0)
+
+#define GET_AINFO_S(N)      \
+    _aid##N = (*e)->GetFieldID(e, ainfo, #N,        \
+                             "Ljava/lang/String;"); \
+    if (_aid##N == NULL) {                          \
+        (*e)->ExceptionClear(e);                    \
+        goto cleanup;                               \
+    } else (void)(0)
+
+#define SET_AINFO_I(N, V)  \
+    (*e)->SetIntField(e, obj, _aid##N, (jint)(V))
+
+#define SET_AINFO_J(N, V)  \
+    (*e)->SetLongField(e, obj, _aid##N, (jlong)(V))
+
+#define SET_AINFO_S(N, V)                 \
+    (*e)->SetObjectField(e, obj, _aid##N, \
+        (V) ? AJP_TO_JSTRING((V)) : NULL)
+
+
+DECLARE_FINFO_FIELD(pool);
+DECLARE_FINFO_FIELD(valid);
+DECLARE_FINFO_FIELD(protection);
+DECLARE_FINFO_FIELD(filetype);
+DECLARE_FINFO_FIELD(user);
+DECLARE_FINFO_FIELD(group);
+DECLARE_FINFO_FIELD(inode);
+DECLARE_FINFO_FIELD(device);
+DECLARE_FINFO_FIELD(nlink);
+DECLARE_FINFO_FIELD(size);
+DECLARE_FINFO_FIELD(csize);
+DECLARE_FINFO_FIELD(atime);
+DECLARE_FINFO_FIELD(mtime);
+DECLARE_FINFO_FIELD(ctime);
+DECLARE_FINFO_FIELD(fname);
+DECLARE_FINFO_FIELD(name);
+DECLARE_FINFO_FIELD(filehand);
+
+DECLARE_AINFO_FIELD(pool);
+DECLARE_AINFO_FIELD(hostname);
+DECLARE_AINFO_FIELD(servname);
+DECLARE_AINFO_FIELD(port);
+DECLARE_AINFO_FIELD(family);
+DECLARE_AINFO_FIELD(next);
+
+static int finfo_class_initialized = 0;
+static int ainfo_class_initialized = 0;
+static jmethodID finfo_class_init = NULL;
+static jmethodID ainfo_class_init = NULL;
+static jclass finfo_class = NULL;
+static jclass ainfo_class = NULL;
+
+apr_status_t tcn_load_finfo_class(JNIEnv *e, jclass finfo)
+{
+    GET_FINFO_J(pool);
+    GET_FINFO_I(valid);
+    GET_FINFO_I(protection);
+    GET_FINFO_I(filetype);
+    GET_FINFO_I(user);
+    GET_FINFO_I(group);
+    GET_FINFO_I(inode);
+    GET_FINFO_I(device);
+    GET_FINFO_I(nlink);
+    GET_FINFO_J(size);
+    GET_FINFO_J(csize);
+    GET_FINFO_J(atime);
+    GET_FINFO_J(mtime);
+    GET_FINFO_J(ctime);
+    GET_FINFO_S(fname);
+    GET_FINFO_S(name);
+    GET_FINFO_J(filehand);
+    
+    finfo_class_init = (*e)->GetMethodID(e, finfo,
+                                      "<init>", "()V");
+    if (finfo_class_init == NULL)
+        goto cleanup;
+    finfo_class_initialized = 1;
+    finfo_class = finfo;
+cleanup:
+    return APR_SUCCESS;
+}
+
+apr_status_t tcn_load_ainfo_class(JNIEnv *e, jclass ainfo)
+{
+    GET_AINFO_J(pool);
+    GET_AINFO_S(hostname);
+    GET_AINFO_S(servname);
+    GET_AINFO_I(port);
+    GET_AINFO_I(family);
+    GET_AINFO_J(next);
+    ainfo_class_init = (*e)->GetMethodID(e, ainfo,
+                                      "<init>", "()V");
+
+    if (ainfo_class_init == NULL)
+        goto cleanup;
+    ainfo_class_initialized = 1;
+    ainfo_class = ainfo;
+cleanup:
+    return APR_SUCCESS;
+}
+
+static void fill_finfo(JNIEnv *e, jobject obj, apr_finfo_t *info)
+{
+
+    SET_FINFO_J(pool, P2J(info->pool));
+    SET_FINFO_I(valid, info->valid);
+    SET_FINFO_I(protection, info->protection);
+    SET_FINFO_I(filetype, info->filetype);
+    SET_FINFO_I(user, ((jlong)info->user));
+    SET_FINFO_I(group, ((jlong)info->group));
+    SET_FINFO_I(inode, info->inode);
+    SET_FINFO_I(device, info->device);
+    SET_FINFO_I(nlink, info->nlink);
+    SET_FINFO_J(size, info->size);
+    SET_FINFO_J(csize, info->csize);
+    SET_FINFO_J(atime, info->atime);
+    SET_FINFO_J(mtime, info->mtime);
+    SET_FINFO_J(ctime, info->ctime);
+    SET_FINFO_S(fname, info->fname);
+    SET_FINFO_S(name, info->name);
+    SET_FINFO_J(filehand, P2J(info->filehand));
+}
+
+static void fill_ainfo(JNIEnv *e, jobject obj, apr_sockaddr_t *info)
+{
+
+    SET_AINFO_J(pool, P2J(info->pool));
+    SET_AINFO_S(hostname, info->hostname);
+    SET_AINFO_S(servname, info->servname);
+    SET_AINFO_I(port, info->port);
+    SET_AINFO_I(family, info->family);
+    SET_AINFO_J(next, P2J(info->next));
+
+}
+
+TCN_IMPLEMENT_CALL(jint, File, stat)(TCN_STDARGS, jobject finfo,
+                                     jstring fname, jint wanted,
+                                     jlong pool)
+{
+    apr_pool_t *p = J2P(pool, apr_pool_t *);
+    TCN_ALLOC_CSTRING(fname);
+    apr_status_t rv;
+    apr_finfo_t info;
+
+    UNREFERENCED(o);
+
+    if ((rv =  apr_stat(&info, J2S(fname), wanted, p)) == APR_SUCCESS) {
+        jobject io = (*e)->NewLocalRef(e, finfo);
+        fill_finfo(e, io, &info);
+        (*e)->DeleteLocalRef(e, io);
+    }
+    TCN_FREE_CSTRING(fname);
+    return (jint)rv;
+}
+
+TCN_IMPLEMENT_CALL(jobject, File, getStat)(TCN_STDARGS, jstring fname,
+                                           jint wanted, jlong pool)
+{
+    apr_pool_t *p = J2P(pool, apr_pool_t *);
+    TCN_ALLOC_CSTRING(fname);
+    apr_status_t rv;
+    apr_finfo_t info;
+    jobject finfo = NULL;
+
+    UNREFERENCED(o);
+
+    if ((rv =  apr_stat(&info, J2S(fname), wanted, p)) == APR_SUCCESS) {
+        finfo = (*e)->NewObject(e, finfo_class, finfo_class_init);
+        if (finfo == NULL)
+            goto cleanup;
+        fill_finfo(e, finfo, &info);
+    }
+    else
+        tcn_ThrowAPRException(e, rv);
+cleanup:
+    TCN_FREE_CSTRING(fname);
+    return finfo;
+}
+
+TCN_IMPLEMENT_CALL(jint, File, infoGet)(TCN_STDARGS, jobject finfo,
+                                        jint wanted, jlong file)
+{
+    apr_file_t *f = J2P(file, apr_file_t *);
+    apr_status_t rv;
+    apr_finfo_t info;
+
+    UNREFERENCED(o);
+
+    if ((rv =  apr_file_info_get(&info, wanted, f)) == APR_SUCCESS) {
+        jobject io = (*e)->NewLocalRef(e, finfo);
+        fill_finfo(e, io, &info);
+        (*e)->DeleteLocalRef(e, io);
+    }
+    return (jint)rv;
+}
+
+TCN_IMPLEMENT_CALL(jobject, File, getInfo)(TCN_STDARGS, jint wanted, jlong file)
+{
+    apr_file_t *f = J2P(file, apr_file_t *);
+    apr_status_t rv;
+    apr_finfo_t  info;
+
+    UNREFERENCED(o);
+
+    if ((rv =  apr_file_info_get(&info, wanted, f)) == APR_SUCCESS) {
+        jobject finfo;
+        finfo = (*e)->NewObject(e, finfo_class, finfo_class_init);
+        if (finfo == NULL)
+            return NULL;
+        fill_finfo(e, finfo, &info);
+        return finfo;
+    }
+    else
+        tcn_ThrowAPRException(e, rv);
+    return NULL;
+}
+
+TCN_IMPLEMENT_CALL(jint, Directory, read)(TCN_STDARGS, jobject finfo,
+                                          jint wanted, jlong dir)
+{
+    apr_dir_t *d = J2P(dir, apr_dir_t *);
+    apr_status_t rv;
+    apr_finfo_t info;
+
+    UNREFERENCED(o);
+
+    if ((rv =  apr_dir_read(&info, wanted, d)) == APR_SUCCESS) {
+        jobject io = (*e)->NewLocalRef(e, finfo);
+        fill_finfo(e, io, &info);
+        if ((*e)->ExceptionCheck(e)) {
+            (*e)->ExceptionClear(e);
+        }
+        else
+            rv = APR_EGENERAL;
+        (*e)->DeleteLocalRef(e, io);
+    }
+    return (jint)rv;
+}
+
+TCN_IMPLEMENT_CALL(jboolean, Address, fill)(TCN_STDARGS,
+                                            jobject addr, jlong info)
+{
+    apr_sockaddr_t *i = J2P(info, apr_sockaddr_t *);
+    jobject ao;
+    jboolean rv = JNI_FALSE;
+
+    UNREFERENCED(o);
+
+    if (i) {
+        ao = (*e)->NewLocalRef(e, addr);
+        fill_ainfo(e, ao, i);
+        if ((*e)->ExceptionCheck(e)) {
+            (*e)->ExceptionClear(e);
+        }
+        else
+            rv = JNI_TRUE;
+        (*e)->DeleteLocalRef(e, ao);
+    }
+    return rv;
+}
+
+TCN_IMPLEMENT_CALL(jobject, Address, getInfo)(TCN_STDARGS, jlong info)
+{
+    apr_sockaddr_t *i = J2P(info, apr_sockaddr_t *);
+    jobject sockaddrObj = NULL;
+
+    UNREFERENCED(o);
+
+    /* Create the APR Error object */
+    sockaddrObj = (*e)->NewObject(e, ainfo_class, ainfo_class_init);
+    if (sockaddrObj == NULL)
+        return NULL;
+    fill_ainfo(e, sockaddrObj, i);
+    return sockaddrObj;
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/src/jnilib.c
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/src/jnilib.c	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/src/jnilib.c	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,469 @@
+/* Copyright 2000-2005 The Apache Software Foundation
+ *
+ * Licensed 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.
+ */
+
+/*
+ *
+ * @author Mladen Turk
+ * @version $Revision: 439960 $, $Date: 2006-09-04 02:15:58 -0500 (Mon, 04 Sep 2006) $
+ */
+
+#include "tcn.h"
+#include "apr_version.h"
+#include "apr_file_io.h"
+#include "apr_mmap.h"
+#include "apr_atomic.h"
+
+#include "tcn_version.h"
+
+#ifdef TCN_DO_STATISTICS
+extern void sp_poll_dump_statistics();
+extern void sp_network_dump_statistics();
+extern void ssl_network_dump_statistics();
+#endif
+
+apr_pool_t *tcn_global_pool = NULL;
+static JavaVM     *tcn_global_vm = NULL;
+
+static jclass    jString_class;
+static jclass    jFinfo_class;
+static jclass    jAinfo_class;
+static jmethodID jString_init;
+static jmethodID jString_getBytes;
+
+int tcn_parent_pid = 0;
+
+/* Called by the JVM when APR_JAVA is loaded */
+JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved)
+{
+    JNIEnv *env;
+
+    UNREFERENCED(reserved);
+    if ((*vm)->GetEnv(vm, (void **)&env, JNI_VERSION_1_4)) {
+        return JNI_ERR;
+    }
+    tcn_global_vm = vm;
+
+    /* Initialize global java.lang.String class */
+    TCN_LOAD_CLASS(env, jString_class, "java/lang/String", JNI_ERR);
+    TCN_LOAD_CLASS(env, jFinfo_class, TCN_FINFO_CLASS, JNI_ERR);
+    TCN_LOAD_CLASS(env, jAinfo_class, TCN_AINFO_CLASS, JNI_ERR);
+
+    TCN_GET_METHOD(env, jString_class, jString_init,
+                   "<init>", "([B)V", JNI_ERR);
+    TCN_GET_METHOD(env, jString_class, jString_getBytes,
+                   "getBytes", "()[B", JNI_ERR);
+
+    if(tcn_load_finfo_class(env, jFinfo_class) != APR_SUCCESS)
+        return JNI_ERR;
+    if(tcn_load_ainfo_class(env, jAinfo_class) != APR_SUCCESS)
+        return JNI_ERR;
+#ifdef WIN32
+    {
+        char *ppid = getenv(TCN_PARENT_IDE);
+        if (ppid)
+            tcn_parent_pid = atoi(ppid);
+    }
+#else
+    tcn_parent_pid = getppid();
+#endif
+    apr_initialize();
+
+    return  JNI_VERSION_1_4;
+}
+
+
+/* Called by the JVM before the APR_JAVA is unloaded */
+JNIEXPORT void JNICALL JNI_OnUnload(JavaVM *vm, void *reserved)
+{
+    JNIEnv *env;
+
+    UNREFERENCED(reserved);
+
+    if ((*vm)->GetEnv(vm, (void **)&env, JNI_VERSION_1_2)) {
+        return;
+    }
+    TCN_UNLOAD_CLASS(env, jString_class);
+    TCN_UNLOAD_CLASS(env, jFinfo_class);
+    TCN_UNLOAD_CLASS(env, jAinfo_class);
+    apr_terminate();
+}
+
+jstring tcn_new_stringn(JNIEnv *env, const char *str, size_t l)
+{
+    jstring result;
+    jbyteArray bytes = 0;
+    size_t len = l;
+
+    if (!str)
+        return NULL;
+    if ((*env)->EnsureLocalCapacity(env, 2) < 0) {
+        return NULL; /* out of memory error */
+    }
+    if (l < 0)
+        len = strlen(str);
+    bytes = (*env)->NewByteArray(env, (jsize)len);
+    if (bytes != NULL) {
+        (*env)->SetByteArrayRegion(env, bytes, 0, (jint)len, (jbyte *)str);
+        result = (*env)->NewObject(env, jString_class, jString_init, bytes);
+        (*env)->DeleteLocalRef(env, bytes);
+        return result;
+    } /* else fall through */
+    return NULL;
+}
+
+jbyteArray tcn_new_arrayb(JNIEnv *env, const unsigned char *data, size_t len)
+{
+    jbyteArray bytes = (*env)->NewByteArray(env, (jsize)len);
+    if (bytes != NULL) {
+        (*env)->SetByteArrayRegion(env, bytes, 0, (jint)len, (jbyte *)data);
+    }
+    return bytes;
+}
+
+jobjectArray tcn_new_arrays(JNIEnv *env, size_t len)
+{
+    return (*env)->NewObjectArray(env, (jsize)len, jString_class, NULL);
+}
+
+jstring tcn_new_string(JNIEnv *env, const char *str)
+{
+    if (!str)
+        return NULL;
+    else
+        return (*env)->NewStringUTF(env, str);
+}
+
+char *tcn_get_string(JNIEnv *env, jstring jstr)
+{
+    jbyteArray bytes = NULL;
+    jthrowable exc;
+    char *result = NULL;
+
+    if ((*env)->EnsureLocalCapacity(env, 2) < 0) {
+        return NULL; /* out of memory error */
+    }
+    bytes = (*env)->CallObjectMethod(env, jstr, jString_getBytes);
+    exc = (*env)->ExceptionOccurred(env);
+    if (!exc) {
+        jint len = (*env)->GetArrayLength(env, bytes);
+        result = (char *)malloc(len + 1);
+        if (result == NULL) {
+            TCN_THROW_OS_ERROR(env);
+            (*env)->DeleteLocalRef(env, bytes);
+            return 0;
+        }
+        (*env)->GetByteArrayRegion(env, bytes, 0, len, (jbyte *)result);
+        result[len] = '\0'; /* NULL-terminate */
+    }
+    else {
+        (*env)->DeleteLocalRef(env, exc);
+    }
+    (*env)->DeleteLocalRef(env, bytes);
+
+    return result;
+}
+
+char *tcn_strdup(JNIEnv *env, jstring jstr)
+{
+    char *result = NULL;
+    const char *cjstr;
+
+    cjstr = (const char *)((*env)->GetStringUTFChars(env, jstr, 0));
+    if (cjstr) {
+        result = strdup(cjstr);
+        (*env)->ReleaseStringUTFChars(env, jstr, cjstr);
+    }
+    return result;
+}
+
+char *tcn_pstrdup(JNIEnv *env, jstring jstr, apr_pool_t *pool)
+{
+    char *result = NULL;
+    const char *cjstr;
+
+    cjstr = (const char *)((*env)->GetStringUTFChars(env, jstr, 0));
+    if (cjstr) {
+        result = apr_pstrdup(pool, cjstr);
+        (*env)->ReleaseStringUTFChars(env, jstr, cjstr);
+    }
+    return result;
+}
+
+TCN_IMPLEMENT_CALL(jboolean, Library, initialize)(TCN_STDARGS)
+{
+
+    UNREFERENCED_STDARGS;
+    if (!tcn_global_pool) {
+        if (apr_pool_create(&tcn_global_pool, NULL) != APR_SUCCESS) {
+            return JNI_FALSE;
+        }
+        apr_atomic_init(tcn_global_pool);
+    }
+    return JNI_TRUE;
+}
+
+TCN_IMPLEMENT_CALL(void, Library, terminate)(TCN_STDARGS)
+{
+
+    UNREFERENCED_STDARGS;
+    if (tcn_global_pool) {
+#ifdef TCN_DO_STATISTICS
+        fprintf(stderr, "APR Statistical data ....\n");
+#endif
+        apr_pool_destroy(tcn_global_pool);
+        tcn_global_pool = NULL;
+#ifdef TCN_DO_STATISTICS
+        sp_poll_dump_statistics();
+        sp_network_dump_statistics();
+        ssl_network_dump_statistics();
+        fprintf(stderr, "APR Terminated\n");
+#endif
+    }
+}
+
+TCN_IMPLEMENT_CALL(jlong, Library, globalPool)(TCN_STDARGS)
+{
+    UNREFERENCED_STDARGS;
+    return P2J(tcn_global_pool);
+}
+
+TCN_IMPLEMENT_CALL(jint, Library, version)(TCN_STDARGS, jint what)
+{
+    apr_version_t apv;
+
+    UNREFERENCED_STDARGS;
+    apr_version(&apv);
+
+    switch (what) {
+        case 0x01:
+            return TCN_MAJOR_VERSION;
+        break;
+        case 0x02:
+            return TCN_MINOR_VERSION;
+        break;
+        case 0x03:
+            return TCN_PATCH_VERSION;
+        break;
+        case 0x04:
+#ifdef TCN_IS_DEV_VERSION
+            return 1;
+#else
+            return 0;
+#endif
+        break;
+        case 0x11:
+            return apv.major;
+        break;
+        case 0x12:
+            return apv.minor;
+        break;
+        case 0x13:
+            return apv.patch;
+        break;
+        case 0x14:
+            return apv.is_dev;
+        break;
+    }
+    return 0;
+}
+
+TCN_IMPLEMENT_CALL(jstring, Library, versionString)(TCN_STDARGS)
+{
+    UNREFERENCED(o);
+    return AJP_TO_JSTRING(TCN_VERSION_STRING);
+}
+
+TCN_IMPLEMENT_CALL(jstring, Library, aprVersionString)(TCN_STDARGS)
+{
+    UNREFERENCED(o);
+    return AJP_TO_JSTRING(apr_version_string());
+}
+
+TCN_IMPLEMENT_CALL(jboolean, Library, has)(TCN_STDARGS, jint what)
+{
+    jboolean rv = JNI_FALSE;
+    UNREFERENCED_STDARGS;
+    switch (what) {
+        case 0:
+#if APR_HAVE_IPV6
+            rv = JNI_TRUE;
+#endif
+        break;
+        case 1:
+#if APR_HAS_SHARED_MEMORY
+            rv = JNI_TRUE;
+#endif
+        break;
+        case 2:
+#if APR_HAS_THREADS
+            rv = JNI_TRUE;
+#endif
+        break;
+        case 3:
+#if APR_HAS_SENDFILE
+            rv = JNI_TRUE;
+#endif
+        break;
+        case 4:
+#if APR_HAS_MMAP
+            rv = JNI_TRUE;
+#endif
+        break;
+        case 5:
+#if APR_HAS_FORK
+            rv = JNI_TRUE;
+#endif
+        break;
+        case 6:
+#if APR_HAS_RANDOM
+            rv = JNI_TRUE;
+#endif
+        break;
+        case 7:
+#if APR_HAS_OTHER_CHILD
+            rv = JNI_TRUE;
+#endif
+        break;
+        case 8:
+#if APR_HAS_DSO
+            rv = JNI_TRUE;
+#endif
+        break;
+        case 9:
+#if APR_HAS_SO_ACCEPTFILTER
+            rv = JNI_TRUE;
+#endif
+        break;
+        case 10:
+#if APR_HAS_UNICODE_FS
+            rv = JNI_TRUE;
+#endif
+        break;
+        case 11:
+#if APR_HAS_PROC_INVOKED
+            rv = JNI_TRUE;
+#endif
+        break;
+        case 12:
+#if APR_HAS_USER
+            rv = JNI_TRUE;
+#endif
+        break;
+        case 13:
+#if APR_HAS_LARGE_FILES
+            rv = JNI_TRUE;
+#endif
+        break;
+        case 14:
+#if APR_HAS_XTHREAD_FILES
+            rv = JNI_TRUE;
+#endif
+        break;
+        case 15:
+#if APR_HAS_OS_UUID
+            rv = JNI_TRUE;
+#endif
+        break;
+        case 16:
+#if APR_IS_BIGENDIAN
+            rv = JNI_TRUE;
+#endif
+        break;
+
+        case 17:
+#if APR_FILES_AS_SOCKETS
+            rv = JNI_TRUE;
+#endif
+        break;
+        case 18:
+#if APR_CHARSET_EBCDIC
+            rv = JNI_TRUE;
+#endif
+        break;
+        case 19:
+#if APR_TCP_NODELAY_INHERITED
+            rv = JNI_TRUE;
+#endif
+        break;
+        case 20:
+#if APR_O_NONBLOCK_INHERITED
+            rv = JNI_TRUE;
+#endif
+        break;
+    }
+    return rv;
+}
+
+TCN_IMPLEMENT_CALL(jint, Library, size)(TCN_STDARGS, jint what)
+{
+
+    UNREFERENCED_STDARGS;
+
+    switch (what) {
+        case 1:
+            return APR_SIZEOF_VOIDP;
+        break;
+        case 2:
+            return APR_PATH_MAX;
+        break;
+        case 3:
+            return APRMAXHOSTLEN;
+        break;
+        case 4:
+            return APR_MAX_IOVEC_SIZE;
+        break;
+        case 5:
+            return APR_MAX_SECS_TO_LINGER;
+        break;
+        case 6:
+            return APR_MMAP_THRESHOLD;
+        break;
+        case 7:
+            return APR_MMAP_LIMIT;
+        break;
+
+    }
+    return 0;
+}
+
+TCN_DECLARE(apr_pool_t *) tcn_get_global_pool()
+{
+    if (!tcn_global_pool) {
+        if (apr_pool_create(&tcn_global_pool, NULL) != APR_SUCCESS) {
+            return NULL;
+        }
+        apr_atomic_init(tcn_global_pool);
+    }
+    return tcn_global_pool;
+}
+
+TCN_DECLARE(jclass) tcn_get_string_class()
+{
+    return jString_class;
+}
+
+TCN_DECLARE(JavaVM *) tcn_get_java_vm()
+{
+    return tcn_global_vm;
+}
+
+TCN_DECLARE(jint) tcn_get_java_env(JNIEnv **env)
+{
+    if ((*tcn_global_vm)->GetEnv(tcn_global_vm, (void **)env,
+                                 JNI_VERSION_1_4)) {
+        return JNI_ERR;
+    }
+    return JNI_OK;
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/src/lock.c
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/src/lock.c	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/src/lock.c	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,201 @@
+/* Copyright 2000-2005 The Apache Software Foundation
+ *
+ * Licensed 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.
+ */
+
+/*
+ *
+ * @author Mladen Turk
+ * @version $Revision: 300969 $, $Date: 2005-07-12 09:56:11 -0500 (Tue, 12 Jul 2005) $
+ */
+ 
+#include "tcn.h"
+#include "apr_proc_mutex.h"
+#include "apr_global_mutex.h"
+
+TCN_IMPLEMENT_CALL(jlong, Lock, create)(TCN_STDARGS,
+                                        jstring fname,
+                                        jint mech, jlong pool)
+{
+    apr_pool_t *p = J2P(pool, apr_pool_t *);
+    apr_proc_mutex_t *mutex;
+    TCN_ALLOC_CSTRING(fname);
+
+
+    UNREFERENCED(o);
+    TCN_THROW_IF_ERR(apr_proc_mutex_create(&mutex, J2S(fname),
+                                (apr_lockmech_e)mech, p), mutex);
+
+cleanup:
+    TCN_FREE_CSTRING(fname);
+    return P2J(mutex);
+}
+
+TCN_IMPLEMENT_CALL(jlong, Lock, childInit)(TCN_STDARGS,
+                                           jstring fname,
+                                           jlong pool)
+{
+    apr_pool_t *p = J2P(pool, apr_pool_t *);
+    apr_proc_mutex_t *mutex;
+    TCN_ALLOC_CSTRING(fname);
+
+
+    UNREFERENCED(o);
+    TCN_THROW_IF_ERR(apr_proc_mutex_child_init(&mutex,
+                                   J2S(fname), p), mutex);
+
+cleanup:
+    TCN_FREE_CSTRING(fname);
+    return P2J(mutex);
+}
+
+TCN_IMPLEMENT_CALL(jint, Lock, lock)(TCN_STDARGS, jlong mutex)
+{
+    apr_proc_mutex_t *m = J2P(mutex, apr_proc_mutex_t *);
+
+    UNREFERENCED_STDARGS;
+    return (jint)apr_proc_mutex_lock(m);
+}
+
+TCN_IMPLEMENT_CALL(jint, Lock, trylock)(TCN_STDARGS, jlong mutex)
+{
+    apr_proc_mutex_t *m = J2P(mutex, apr_proc_mutex_t *);
+
+    UNREFERENCED_STDARGS;
+    return (jint)apr_proc_mutex_trylock(m);
+}
+
+TCN_IMPLEMENT_CALL(jint, Lock, unlock)(TCN_STDARGS, jlong mutex)
+{
+    apr_proc_mutex_t *m = J2P(mutex, apr_proc_mutex_t *);
+
+    UNREFERENCED_STDARGS;
+    return (jint)apr_proc_mutex_unlock(m);
+}
+
+TCN_IMPLEMENT_CALL(jint, Lock, destoy)(TCN_STDARGS, jlong mutex)
+{
+    apr_proc_mutex_t *m = J2P(mutex, apr_proc_mutex_t *);
+
+    UNREFERENCED_STDARGS;
+    return (jint)apr_proc_mutex_destroy(m);
+}
+
+#if 0
+/* There is bug in APR implementing that function */
+TCN_IMPLEMENT_CALL(jint, Lock, cleanup)(TCN_STDARGS, jlong mutex)
+{
+   void *m = J2P(mutex, void *);
+
+    UNREFERENCED_STDARGS;
+    return (jint)apr_proc_mutex_cleanup(m);
+}
+#endif
+
+TCN_IMPLEMENT_CALL(jstring, Lock, lockfile)(TCN_STDARGS, jlong mutex)
+{
+    apr_proc_mutex_t *m = J2P(mutex, apr_proc_mutex_t *);
+    const char *s = apr_proc_mutex_lockfile(m);
+
+    UNREFERENCED_STDARGS;
+    if (s)
+        return AJP_TO_JSTRING(s);
+    else
+        return NULL;
+}
+
+TCN_IMPLEMENT_CALL(jstring, Lock, name)(TCN_STDARGS, jlong mutex)
+{
+    apr_proc_mutex_t *m = J2P(mutex, apr_proc_mutex_t *);
+
+    UNREFERENCED(o);
+    return AJP_TO_JSTRING(apr_proc_mutex_name(m));
+}
+
+TCN_IMPLEMENT_CALL(jstring, Lock, defname)(TCN_STDARGS)
+{
+
+    UNREFERENCED(o);
+    return AJP_TO_JSTRING(apr_proc_mutex_defname());
+}
+
+
+
+TCN_IMPLEMENT_CALL(jlong, Global, create)(TCN_STDARGS,
+                                          jstring fname,
+                                          jint mech, jlong pool)
+{
+    apr_pool_t *p = J2P(pool, apr_pool_t *);
+    apr_global_mutex_t *mutex;
+    TCN_ALLOC_CSTRING(fname);
+
+
+    UNREFERENCED(o);
+    TCN_THROW_IF_ERR(apr_global_mutex_create(&mutex, J2S(fname),
+                                (apr_lockmech_e)mech, p), mutex);
+
+cleanup:
+    TCN_FREE_CSTRING(fname);
+    return P2J(mutex);
+}
+
+TCN_IMPLEMENT_CALL(jlong, Global, childInit)(TCN_STDARGS,
+                                             jstring fname,
+                                             jlong pool)
+{
+    apr_pool_t *p = J2P(pool, apr_pool_t *);
+    apr_global_mutex_t *mutex;
+    TCN_ALLOC_CSTRING(fname);
+
+
+    UNREFERENCED(o);
+    TCN_THROW_IF_ERR(apr_global_mutex_child_init(&mutex,
+                                   J2S(fname), p), mutex);
+
+cleanup:
+    TCN_FREE_CSTRING(fname);
+    return P2J(mutex);
+}
+
+TCN_IMPLEMENT_CALL(jint, Global, lock)(TCN_STDARGS, jlong mutex)
+{
+    apr_global_mutex_t *m = J2P(mutex, apr_global_mutex_t *);
+
+    UNREFERENCED_STDARGS;
+    return (jint)apr_global_mutex_lock(m);
+}
+
+TCN_IMPLEMENT_CALL(jint, Global, trylock)(TCN_STDARGS, jlong mutex)
+{
+    apr_global_mutex_t *m = J2P(mutex, apr_global_mutex_t *);
+
+    UNREFERENCED_STDARGS;
+    return (jint)apr_global_mutex_trylock(m);
+}
+
+TCN_IMPLEMENT_CALL(jint, Global, unlock)(TCN_STDARGS, jlong mutex)
+{
+    apr_global_mutex_t *m = J2P(mutex, apr_global_mutex_t*);
+
+    UNREFERENCED_STDARGS;
+    return (jint)apr_global_mutex_unlock(m);
+}
+
+TCN_IMPLEMENT_CALL(jint, Global, destoy)(TCN_STDARGS, jlong mutex)
+{
+    apr_global_mutex_t *m = J2P(mutex, apr_global_mutex_t *);
+
+    UNREFERENCED_STDARGS;
+    return (jint)apr_global_mutex_destroy(m);
+}
+

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/src/misc.c
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/src/misc.c	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/src/misc.c	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,80 @@
+/* Copyright 2000-2005 The Apache Software Foundation
+ *
+ * Licensed 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.
+ */
+
+/*
+ *
+ * @author Mladen Turk
+ * @version $Revision: 300969 $, $Date: 2005-07-12 09:56:11 -0500 (Tue, 12 Jul 2005) $
+ */
+ 
+#include "tcn.h"
+#include "apr_time.h"
+
+TCN_IMPLEMENT_CALL(void, Time, sleep)(TCN_STDARGS, jlong t)
+{
+
+    UNREFERENCED_STDARGS;
+    apr_sleep((apr_interval_time_t)t);
+}
+
+TCN_IMPLEMENT_CALL(jint, OS, random)(TCN_STDARGS, jbyteArray buf,
+                                     jint len)
+{
+#if APR_HAS_RANDOM
+    apr_status_t rv;
+    jbyte *b = (*e)->GetPrimitiveArrayCritical(e, buf, NULL);
+
+    UNREFERENCED(o);
+    if ((rv = apr_generate_random_bytes((unsigned char *)b,
+            (apr_size_t)len)) == APR_SUCCESS)
+        (*e)->ReleasePrimitiveArrayCritical(e, buf, b, 0);
+    else
+        (*e)->ReleasePrimitiveArrayCritical(e, buf, b, JNI_ABORT);
+
+    if ((*e)->ExceptionCheck(e)) {
+        (*e)->ExceptionClear(e);
+        rv = APR_EGENERAL;
+    }
+    return (jint)rv;
+#else
+    return APR_ENOTIMPL;
+#endif
+}
+
+TCN_IMPLEMENT_CALL(jlong, Time, now)(TCN_STDARGS)
+{
+    UNREFERENCED_STDARGS;
+    return (jlong)apr_time_now();
+}
+
+TCN_IMPLEMENT_CALL(jstring, Time, rfc822)(TCN_STDARGS, jlong t)
+{
+    char ts[APR_RFC822_DATE_LEN];
+    UNREFERENCED(o);
+    if (apr_rfc822_date(ts, J2T(t)) == APR_SUCCESS)
+        return AJP_TO_JSTRING(ts);
+    else
+        return NULL;
+}
+
+TCN_IMPLEMENT_CALL(jstring, Time, ctime)(TCN_STDARGS, jlong t)
+{
+    char ts[APR_CTIME_LEN];
+    UNREFERENCED(o);
+    if (apr_ctime(ts, J2T(t)) == APR_SUCCESS)
+        return AJP_TO_JSTRING(ts);
+    else
+        return NULL;
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/src/mmap.c
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/src/mmap.c	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/src/mmap.c	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,101 @@
+/* Copyright 2000-2005 The Apache Software Foundation
+ *
+ * Licensed 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.
+ */
+
+/*
+ *
+ * @author Mladen Turk
+ * @version $Revision: 300969 $, $Date: 2005-07-12 09:56:11 -0500 (Tue, 12 Jul 2005) $
+ */
+ 
+#include "tcn.h"
+#include "apr_mmap.h"
+
+TCN_IMPLEMENT_CALL(jlong, Mmap, create)(TCN_STDARGS, jlong file,
+                                        jlong offset, jlong size,
+                                        jint flag, jlong pool)
+{
+#if APR_HAS_MMAP
+    apr_pool_t *p = J2P(pool, apr_pool_t *);
+    apr_file_t *f = J2P(file, apr_file_t *);
+    apr_mmap_t *m = NULL;
+
+    UNREFERENCED(o);
+    TCN_THROW_IF_ERR(apr_mmap_create(&m, f, (apr_off_t)offset,
+                                     (apr_size_t)size,
+                                     (apr_uint32_t)flag, p), m);
+
+cleanup:
+    return P2J(m);
+#else
+    UNREFERENCED(o);
+    tcn_ThrowAPRException(e, APR_ENOTIMPL);
+    return 0;
+#endif
+}
+
+TCN_IMPLEMENT_CALL(jlong, Mmap, dup)(TCN_STDARGS, jlong mmap,
+                                     jlong pool)
+{
+#if APR_HAS_MMAP
+    apr_pool_t *p = J2P(pool, apr_pool_t *);
+    apr_mmap_t *m = J2P(mmap, apr_mmap_t *);
+    apr_mmap_t *newm = NULL;
+
+    UNREFERENCED(o);
+    TCN_THROW_IF_ERR(apr_mmap_dup(&newm, m, p), newm);
+
+cleanup:
+    return P2J(newm);
+#else
+    UNREFERENCED(o);
+    tcn_ThrowAPRException(e, APR_ENOTIMPL);
+    return 0;
+#endif
+}
+
+TCN_IMPLEMENT_CALL(jint, Mmap, delete)(TCN_STDARGS, jlong mmap)
+{
+#if APR_HAS_MMAP
+    apr_mmap_t *m = J2P(mmap, apr_mmap_t *);
+
+    UNREFERENCED_STDARGS;
+    return apr_mmap_delete(m);
+
+#else
+    UNREFERENCED_STDARGS;
+    UNREFERENCED(mmap);
+    return APR_ENOTIMPL;
+#endif
+}
+
+TCN_IMPLEMENT_CALL(jlong, Mmap, offset)(TCN_STDARGS, jlong mmap,
+                                        jlong offset)
+{
+#if APR_HAS_MMAP
+    apr_mmap_t *m = J2P(mmap, apr_mmap_t *);
+    void *r;
+
+    UNREFERENCED(o);
+    TCN_THROW_IF_ERR(apr_mmap_offset(&r, m, (apr_off_t)offset), r);
+
+cleanup:
+    return P2J(r);
+
+#else
+    UNREFERENCED(o);
+    tcn_ThrowAPRException(e, APR_ENOTIMPL);
+    return 0;
+#endif
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/src/multicast.c
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/src/multicast.c	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/src/multicast.c	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,71 @@
+/* Copyright 2000-2006 The Apache Software Foundation
+ *
+ * Licensed 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.
+ */
+
+/*
+ *
+ * @author Mladen Turk
+ * @version $Revision: 416783 $, $Date: 2006-06-23 20:06:15 +0200 (pet, 23 lip 2006) $
+ */
+
+#include "tcn.h"
+
+TCN_IMPLEMENT_CALL(jint, Mulicast, join)(TCN_STDARGS,
+                                         jlong sock, jlong join,
+                                         jlong iface, jlong source)
+{
+    tcn_socket_t *s = J2P(sock, tcn_socket_t *);
+    apr_sockaddr_t *ja = J2P(join, apr_sockaddr_t *);
+    apr_sockaddr_t *ia = J2P(iface, apr_sockaddr_t *);
+    apr_sockaddr_t *sa = J2P(source, apr_sockaddr_t *);
+    UNREFERENCED_STDARGS;
+    return (jint)apr_mcast_join(s->sock, ja, ia, sa);
+};
+
+TCN_IMPLEMENT_CALL(jint, Mulicast, leave)(TCN_STDARGS,
+                                          jlong sock, jlong addr,
+                                          jlong iface, jlong source)
+{
+    tcn_socket_t *s = J2P(sock, tcn_socket_t *);
+    apr_sockaddr_t *aa = J2P(addr, apr_sockaddr_t *);
+    apr_sockaddr_t *ia = J2P(iface, apr_sockaddr_t *);
+    apr_sockaddr_t *sa = J2P(source, apr_sockaddr_t *);
+    UNREFERENCED_STDARGS;
+    return (jint)apr_mcast_leave(s->sock, aa, ia, sa);
+};
+
+TCN_IMPLEMENT_CALL(jint, Mulicast, hops)(TCN_STDARGS,
+                                         jlong sock, jint ttl)
+{
+    tcn_socket_t *s = J2P(sock, tcn_socket_t *);
+    UNREFERENCED_STDARGS;
+    return (jint)apr_mcast_hops(s->sock, (apr_byte_t)ttl);
+};
+
+TCN_IMPLEMENT_CALL(jint, Mulicast, loopback)(TCN_STDARGS,
+                                             jlong sock, jboolean opt)
+{
+    tcn_socket_t *s = J2P(sock, tcn_socket_t *);
+    UNREFERENCED_STDARGS;
+    return (jint)apr_mcast_loopback(s->sock, opt == JNI_TRUE ? 1 : 0);
+};
+
+TCN_IMPLEMENT_CALL(jint, Mulicast, ointerface)(TCN_STDARGS,
+                                               jlong sock, jlong iface)
+{
+    tcn_socket_t *s = J2P(sock, tcn_socket_t *);
+    apr_sockaddr_t *ia = J2P(iface, apr_sockaddr_t *);
+    UNREFERENCED_STDARGS;
+    return (jint)apr_mcast_interface(s->sock, ia);
+};

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/src/network.c
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/src/network.c	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/src/network.c	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,1211 @@
+/* Copyright 2000-2006 The Apache Software Foundation
+ *
+ * Licensed 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.
+ */
+
+/*
+ *
+ * @author Mladen Turk
+ * @version $Revision: 442529 $, $Date: 2006-09-12 03:54:10 -0500 (Tue, 12 Sep 2006) $
+ */
+
+#include "tcn.h"
+
+#ifdef TCN_DO_STATISTICS
+
+#include "apr_atomic.h"
+
+static volatile apr_uint32_t sp_created  = 0;
+static volatile apr_uint32_t sp_closed   = 0;
+static volatile apr_uint32_t sp_cleared  = 0;
+static volatile apr_uint32_t sp_accepted = 0;
+static volatile apr_uint32_t sp_max_send = 0;
+static volatile apr_uint32_t sp_min_send = 10000000;
+static volatile apr_uint32_t sp_num_send = 0;
+static volatile apr_off_t    sp_tot_send = 0;
+static volatile apr_uint32_t sp_max_recv = 0;
+static volatile apr_uint32_t sp_min_recv = 10000000;
+static volatile apr_uint32_t sp_num_recv = 0;
+static volatile apr_off_t    sp_tot_recv = 0;
+static volatile apr_uint32_t sp_err_recv = 0;
+static volatile apr_uint32_t sp_tmo_recv = 0;
+static volatile apr_uint32_t sp_rst_recv = 0;
+static volatile apr_status_t sp_erl_recv = 0;
+
+static volatile apr_size_t   sf_max_send = 0;
+static volatile apr_size_t   sf_min_send = 10000000;
+static volatile apr_uint32_t sf_num_send = 0;
+static volatile apr_off_t    sf_tot_send = 0;
+
+void sp_network_dump_statistics()
+{
+    fprintf(stderr, "Network Statistics ......\n");
+    fprintf(stderr, "Sockets created         : %d\n", sp_created);
+    fprintf(stderr, "Sockets accepted        : %d\n", sp_accepted);
+    fprintf(stderr, "Sockets closed          : %d\n", sp_closed);
+    fprintf(stderr, "Sockets cleared         : %d\n", sp_cleared);
+    fprintf(stderr, "Total send calls        : %d\n", sp_num_send);
+    fprintf(stderr, "Minimum send length     : %d\n", sp_min_send);
+    fprintf(stderr, "Maximum send length     : %d\n", sp_max_send);
+    fprintf(stderr, "Average send length     : %.2f\n", (double)sp_tot_send/(double)sp_num_send);
+    fprintf(stderr, "Total recv calls        : %d\n", sp_num_recv);
+    fprintf(stderr, "Minimum recv length     : %d\n", sp_min_recv);
+    fprintf(stderr, "Maximum recv length     : %d\n", sp_max_recv);
+    fprintf(stderr, "Average recv length     : %.2f\n", (double)sp_tot_recv/(double)sp_num_recv);
+    fprintf(stderr, "Receive timeouts        : %d\n", sp_tmo_recv);
+    fprintf(stderr, "Receive errors          : %d\n", sp_err_recv);
+    fprintf(stderr, "Receive resets          : %d\n", sp_rst_recv);
+    fprintf(stderr, "Last receive error      : %d\n", sp_erl_recv);
+
+    fprintf(stderr, "Total sendfile calls    : %d\n", sf_num_send);
+    fprintf(stderr, "Minimum sendfile lenght : %" APR_SIZE_T_FMT "\n", sf_min_send);
+    fprintf(stderr, "Maximum sendfile lenght : %" APR_SIZE_T_FMT "\n", sf_max_send);
+
+}
+
+#endif /* TCN_DO_STATISTICS */
+
+static apr_status_t sp_socket_cleanup(void *data)
+{
+    tcn_socket_t *s = (tcn_socket_t *)data;
+
+    if (s->net && s->net->cleanup)
+        (*s->net->cleanup)(s->opaque);
+    if (s->sock) {
+        apr_socket_close(s->sock);
+        s->sock = NULL;
+    }
+#ifdef TCN_DO_STATISTICS
+    apr_atomic_inc32(&sp_cleared);
+#endif
+    return APR_SUCCESS;
+}
+
+#if defined(DEBUG) || defined(_DEBUG)
+static APR_INLINE apr_status_t APR_THREAD_FUNC
+APR_socket_send(apr_socket_t *sock, const char *buf, apr_size_t *len)
+{
+    return apr_socket_send(sock, buf, len);
+}
+
+static APR_INLINE apr_status_t APR_THREAD_FUNC
+APR_socket_recv(apr_socket_t *sock, char *buf, apr_size_t *len)
+{
+    return apr_socket_recv(sock, buf, len);
+}
+
+static APR_INLINE apr_status_t APR_THREAD_FUNC
+APR_socket_sendv(apr_socket_t *sock, const struct iovec *vec,
+                 apr_int32_t nvec, apr_size_t *len)
+{
+    return apr_socket_sendv(sock, vec, nvec, len);
+}
+
+static APR_INLINE apr_status_t APR_THREAD_FUNC
+APR_socket_shutdown(apr_socket_t *sock, apr_shutdown_how_e how)
+{
+    return apr_socket_shutdown(sock, how);
+}
+
+static APR_INLINE apr_status_t APR_THREAD_FUNC
+APR_socket_timeout_set(apr_socket_t *sock, apr_interval_time_t t)
+{
+    return apr_socket_timeout_set(sock, t);
+}
+
+static APR_INLINE apr_status_t APR_THREAD_FUNC
+APR_socket_timeout_get(apr_socket_t *sock, apr_interval_time_t *t)
+{
+    return apr_socket_timeout_get(sock, t);
+}
+
+static APR_INLINE apr_status_t APR_THREAD_FUNC
+APR_socket_opt_set(apr_socket_t *sock, apr_int32_t opt, apr_int32_t on)
+{
+    return apr_socket_opt_set(sock, opt, on);
+}
+
+static APR_INLINE apr_status_t APR_THREAD_FUNC
+APR_socket_opt_get(apr_socket_t *sock, apr_int32_t opt, apr_int32_t *on)
+{
+    return apr_socket_opt_get(sock, opt, on);
+}
+
+#else
+#define APR_socket_send         apr_socket_send
+#define APR_socket_recv         apr_socket_recv
+#define APR_socket_sendv        apr_socket_sendv
+#define APR_socket_shutdown     apr_socket_shutdown
+#define APR_socket_timeout_set  apr_socket_timeout_set
+#define APR_socket_timeout_get  apr_socket_timeout_get
+#define APR_socket_opt_set      apr_socket_opt_set
+#define APR_socket_opt_get      apr_socket_opt_get
+#endif
+
+static tcn_nlayer_t apr_socket_layer = {
+    TCN_SOCKET_APR,
+    NULL,
+    NULL,
+    APR_socket_shutdown,
+    APR_socket_opt_get,
+    APR_socket_opt_set,
+    APR_socket_timeout_get,
+    APR_socket_timeout_set,
+    APR_socket_send,
+    APR_socket_sendv,
+    APR_socket_recv
+};
+
+TCN_IMPLEMENT_CALL(jlong, Socket, create)(TCN_STDARGS, jint family,
+                                          jint type, jint protocol,
+                                          jlong pool)
+{
+    apr_pool_t *p = J2P(pool, apr_pool_t *);
+    apr_socket_t *s = NULL;
+    tcn_socket_t *a = NULL;
+    apr_int32_t f, t;
+
+    UNREFERENCED(o);
+    TCN_ASSERT(pool != 0);
+    GET_S_FAMILY(f, family);
+    GET_S_TYPE(t, type);
+
+    if (family >= 0) {
+        TCN_THROW_IF_ERR(apr_socket_create(&s,
+                         f, t, protocol, p), a);
+    }
+#ifdef TCN_DO_STATISTICS
+    sp_created++;
+#endif
+    a = (tcn_socket_t *)apr_pcalloc(p, sizeof(tcn_socket_t));
+    TCN_CHECK_ALLOCATED(a);
+    a->sock = s;
+    a->pool = p;
+    if (family >= 0)
+        a->net = &apr_socket_layer;
+    a->opaque   = s;
+    apr_pool_cleanup_register(p, (const void *)a,
+                              sp_socket_cleanup,
+                              apr_pool_cleanup_null);
+
+cleanup:
+    return P2J(a);
+
+}
+
+TCN_IMPLEMENT_CALL(void, Socket, destroy)(TCN_STDARGS, jlong sock)
+{
+    tcn_socket_t *s = J2P(sock, tcn_socket_t *);
+    UNREFERENCED_STDARGS;
+    TCN_ASSERT(sock != 0);
+    apr_pool_destroy(s->pool);
+}
+
+TCN_IMPLEMENT_CALL(jlong, Socket, pool)(TCN_STDARGS, jlong sock)
+{
+    tcn_socket_t *s = J2P(sock, tcn_socket_t *);
+    apr_pool_t *n;
+
+    UNREFERENCED(o);
+    TCN_ASSERT(sock != 0);
+    TCN_THROW_IF_ERR(apr_pool_create(&n, s->pool), n);
+cleanup:
+    return P2J(n);
+}
+
+TCN_IMPLEMENT_CALL(jlong, Socket, get)(TCN_STDARGS, jlong sock, jint what)
+{
+    tcn_socket_t *s = J2P(sock, tcn_socket_t *);
+    UNREFERENCED_STDARGS;
+    TCN_ASSERT(sock != 0);
+
+    switch (what) {
+        case TCN_SOCKET_GET_POOL:
+            return P2J(s->pool);
+        break;
+        case TCN_SOCKET_GET_IMPL:
+            return P2J(s->opaque);
+        break;
+        case TCN_SOCKET_GET_APRS:
+            return P2J(s->sock);
+        break;
+        case TCN_SOCKET_GET_TYPE:
+            return (jlong)(s->net->type);
+        break;
+    }
+    return 0;
+}
+
+TCN_IMPLEMENT_CALL(jint, Socket, shutdown)(TCN_STDARGS, jlong sock,
+                                           jint how)
+{
+    tcn_socket_t *s = J2P(sock, tcn_socket_t *);
+
+    UNREFERENCED_STDARGS;
+    TCN_ASSERT(sock != 0);
+    return (jint)(*s->net->shutdown)(s->opaque, how);
+}
+
+TCN_IMPLEMENT_CALL(jint, Socket, close)(TCN_STDARGS, jlong sock)
+{
+    tcn_socket_t *s = J2P(sock, tcn_socket_t *);
+    jint rv = APR_SUCCESS;
+    UNREFERENCED_STDARGS;
+    TCN_ASSERT(sock != 0);
+
+#ifdef TCN_DO_STATISTICS
+    apr_atomic_inc32(&sp_closed);
+#endif
+    if (s->net && s->net->close) {
+        rv = (*s->net->close)(s->opaque);
+        s->net = NULL;
+    }
+    if (s->sock) {
+        rv = (jint)apr_socket_close(s->sock);
+        s->sock = NULL;
+    }
+    return rv;
+}
+
+TCN_IMPLEMENT_CALL(jint, Socket, bind)(TCN_STDARGS, jlong sock,
+                                       jlong sa)
+{
+    jint rv = APR_SUCCESS;
+    tcn_socket_t *s = J2P(sock, tcn_socket_t *);
+    apr_sockaddr_t *a = J2P(sa, apr_sockaddr_t *);
+
+    UNREFERENCED_STDARGS;
+    TCN_ASSERT(sock != 0);
+    TCN_ASSERT(s->sock != NULL);
+    rv = (jint)apr_socket_bind(s->sock, a);
+    return rv;
+}
+
+TCN_IMPLEMENT_CALL(jint, Socket, listen)(TCN_STDARGS, jlong sock,
+                                         jint backlog)
+{
+    tcn_socket_t *s = J2P(sock, tcn_socket_t *);
+
+    UNREFERENCED_STDARGS;
+    TCN_ASSERT(sock != 0);
+    TCN_ASSERT(s->sock != NULL);
+    return (jint)apr_socket_listen(s->sock, backlog);
+}
+
+TCN_IMPLEMENT_CALL(jlong, Socket, acceptx)(TCN_STDARGS, jlong sock,
+                                           jlong pool)
+{
+    tcn_socket_t *s = J2P(sock, tcn_socket_t *);
+    apr_pool_t   *p = J2P(pool, apr_pool_t *);
+    apr_socket_t *n = NULL;
+    tcn_socket_t *a = NULL;
+
+    UNREFERENCED(o);
+    TCN_ASSERT(sock != 0);
+
+    if (s->net->type == TCN_SOCKET_APR) {
+        TCN_ASSERT(s->sock != NULL);
+        TCN_THROW_IF_ERR(apr_socket_accept(&n, s->sock, p), n);
+    }
+    else {
+        tcn_ThrowAPRException(e, APR_ENOTIMPL);
+        goto cleanup;
+    }
+    if (n) {
+#ifdef TCN_DO_STATISTICS
+        apr_atomic_inc32(&sp_accepted);
+#endif
+        a = (tcn_socket_t *)apr_pcalloc(p, sizeof(tcn_socket_t));
+        TCN_CHECK_ALLOCATED(a);
+        a->sock   = n;
+        a->pool   = p;
+        a->net    = &apr_socket_layer;
+        a->opaque = n;
+        apr_pool_cleanup_register(p, (const void *)a,
+                                  sp_socket_cleanup,
+                                  apr_pool_cleanup_null);
+    }
+
+cleanup:
+    return P2J(a);
+}
+
+TCN_IMPLEMENT_CALL(jlong, Socket, accept)(TCN_STDARGS, jlong sock)
+{
+    tcn_socket_t *s = J2P(sock, tcn_socket_t *);
+    apr_pool_t   *p = NULL;
+    apr_socket_t *n = NULL;
+    tcn_socket_t *a = NULL;
+
+    UNREFERENCED(o);
+    TCN_ASSERT(sock != 0);
+
+    TCN_THROW_IF_ERR(apr_pool_create(&p, s->pool), p);
+    if (s->net->type == TCN_SOCKET_APR) {
+        TCN_ASSERT(s->sock != NULL);
+        TCN_THROW_IF_ERR(apr_socket_accept(&n, s->sock, p), n);
+    }
+    else {
+        tcn_ThrowAPRException(e, APR_ENOTIMPL);
+        goto cleanup;
+    }
+    if (n) {
+#ifdef TCN_DO_STATISTICS
+        apr_atomic_inc32(&sp_accepted);
+#endif
+        a = (tcn_socket_t *)apr_pcalloc(p, sizeof(tcn_socket_t));
+        TCN_CHECK_ALLOCATED(a);
+        a->sock   = n;
+        a->pool   = p;
+        a->net    = &apr_socket_layer;
+        a->opaque = n;
+        apr_pool_cleanup_register(p, (const void *)a,
+                                  sp_socket_cleanup,
+                                  apr_pool_cleanup_null);
+    }
+    return P2J(a);
+cleanup:
+    return 0;
+}
+
+TCN_IMPLEMENT_CALL(jint, Socket, connect)(TCN_STDARGS, jlong sock,
+                                          jlong sa)
+{
+    tcn_socket_t *s = J2P(sock, tcn_socket_t *);
+    apr_sockaddr_t *a = J2P(sa, apr_sockaddr_t *);
+
+    UNREFERENCED_STDARGS;
+    TCN_ASSERT(sock != 0);
+    TCN_ASSERT(s->sock != NULL);
+    return (jint)apr_socket_connect(s->sock, a);
+}
+
+TCN_IMPLEMENT_CALL(jint, Socket, send)(TCN_STDARGS, jlong sock,
+                                      jbyteArray buf, jint offset, jint tosend)
+{
+    tcn_socket_t *s = J2P(sock, tcn_socket_t *);
+    apr_size_t nbytes = (apr_size_t)tosend;
+    apr_status_t ss;
+
+    UNREFERENCED(o);
+    TCN_ASSERT(sock != 0);
+    TCN_ASSERT(s->opaque != NULL);
+#ifdef TCN_DO_STATISTICS
+    sp_max_send = TCN_MAX(sp_max_send, nbytes);
+    sp_min_send = TCN_MIN(sp_min_send, nbytes);
+    sp_tot_send += nbytes;
+    sp_num_send++;
+#endif
+
+    if (tosend <= TCN_BUFFER_SZ) {
+        jbyte sb[TCN_BUFFER_SZ];
+        (*e)->GetByteArrayRegion(e, buf, offset, tosend, &sb[0]);
+        ss = (*s->net->send)(s->opaque, sb, &nbytes);
+    }
+    else {
+        jbyte *sb = (jbyte *)malloc(nbytes);
+        if (sb == NULL)
+            return -APR_ENOMEM;
+        (*e)->GetByteArrayRegion(e, buf, offset, tosend, sb);
+        ss = (*s->net->send)(s->opaque, sb, &nbytes);
+        free(sb);
+    }
+    if (ss == APR_SUCCESS)
+        return (jint)nbytes;
+    else {
+        TCN_ERROR_WRAP(ss);
+        return -(jint)ss;
+    }
+}
+
+TCN_IMPLEMENT_CALL(void, Socket, setsbb)(TCN_STDARGS, jlong sock,
+                                         jobject buf)
+{
+    tcn_socket_t *s = J2P(sock, tcn_socket_t *);
+    UNREFERENCED(o);
+    TCN_ASSERT(sock != 0);
+    TCN_ASSERT(s->opaque != NULL);
+    if (buf)
+        s->jsbbuff = (char *)(*e)->GetDirectBufferAddress(e, buf);
+    else
+        s->jsbbuff = NULL;
+}
+
+TCN_IMPLEMENT_CALL(void, Socket, setrbb)(TCN_STDARGS, jlong sock,
+                                         jobject buf)
+{
+    tcn_socket_t *s = J2P(sock, tcn_socket_t *);
+    UNREFERENCED(o);
+    TCN_ASSERT(sock != 0);
+    TCN_ASSERT(s->opaque != NULL);
+    if (buf)
+        s->jrbbuff = (char *)(*e)->GetDirectBufferAddress(e, buf);
+    else
+        s->jrbbuff = NULL;
+}
+
+TCN_IMPLEMENT_CALL(jint, Socket, sendb)(TCN_STDARGS, jlong sock,
+                                        jobject buf, jint offset, jint len)
+{
+    tcn_socket_t *s = J2P(sock, tcn_socket_t *);
+    apr_size_t nbytes = (apr_size_t)len;
+    apr_size_t sent = 0;
+    char *bytes;
+    apr_status_t ss = APR_SUCCESS;
+
+    UNREFERENCED(o);
+    TCN_ASSERT(sock != 0);
+    TCN_ASSERT(s->opaque != NULL);
+    TCN_ASSERT(buf != NULL);
+#ifdef TCN_DO_STATISTICS
+    sp_max_send = TCN_MAX(sp_max_send, nbytes);
+    sp_min_send = TCN_MIN(sp_min_send, nbytes);
+    sp_tot_send += nbytes;
+    sp_num_send++;
+#endif
+
+    bytes  = (char *)(*e)->GetDirectBufferAddress(e, buf);
+
+    while (sent < nbytes) {
+        apr_size_t wr = nbytes - sent;
+        ss = (*s->net->send)(s->opaque, bytes + offset + sent, &wr);
+        if (ss != APR_SUCCESS)
+            break;
+        sent += wr;
+    }
+
+    if (ss == APR_SUCCESS)
+        return (jint)sent;
+    else {
+        TCN_ERROR_WRAP(ss);
+        return -(jint)ss;
+    }
+}
+
+TCN_IMPLEMENT_CALL(jint, Socket, sendbb)(TCN_STDARGS, jlong sock,
+                                         jint offset, jint len)
+{
+    tcn_socket_t *s = J2P(sock, tcn_socket_t *);
+    apr_size_t nbytes = (apr_size_t)len;
+    apr_size_t sent = 0;
+    apr_status_t ss = APR_SUCCESS;
+
+    UNREFERENCED_STDARGS;
+    TCN_ASSERT(sock != 0);
+    TCN_ASSERT(s->opaque != NULL);
+    TCN_ASSERT(s->jsbbuff != NULL);
+#ifdef TCN_DO_STATISTICS
+    sp_max_send = TCN_MAX(sp_max_send, nbytes);
+    sp_min_send = TCN_MIN(sp_min_send, nbytes);
+    sp_tot_send += nbytes;
+    sp_num_send++;
+#endif
+
+    while (sent < nbytes) {
+        apr_size_t wr = nbytes - sent;
+        ss = (*s->net->send)(s->opaque, s->jsbbuff + offset + sent, &wr);
+        if (ss != APR_SUCCESS)
+            break;
+        sent += wr;
+    }
+    if (ss == APR_SUCCESS)
+        return (jint)sent;
+    else {
+        TCN_ERROR_WRAP(ss);
+        return -(jint)ss;
+    }
+}
+
+TCN_IMPLEMENT_CALL(jint, Socket, sendv)(TCN_STDARGS, jlong sock,
+                                        jobjectArray bufs)
+{
+    tcn_socket_t *s = J2P(sock, tcn_socket_t *);
+    jsize nvec;
+    jsize i;
+    struct iovec vec[APR_MAX_IOVEC_SIZE];
+    jobject ba[APR_MAX_IOVEC_SIZE];
+    apr_size_t written = 0;
+    apr_status_t ss;
+
+    UNREFERENCED(o);
+    TCN_ASSERT(sock != 0);
+    TCN_ASSERT(s->opaque != NULL);
+
+    nvec = (*e)->GetArrayLength(e, bufs);
+    if (nvec >= APR_MAX_IOVEC_SIZE)
+        return (jint)(-APR_ENOMEM);
+
+    for (i = 0; i < nvec; i++) {
+        ba[i] = (*e)->GetObjectArrayElement(e, bufs, i);
+        vec[i].iov_len  = (*e)->GetArrayLength(e, ba[i]);
+        vec[i].iov_base = (*e)->GetByteArrayElements(e, ba[i], NULL);
+    }
+
+    ss = (*s->net->sendv)(s->opaque, vec, nvec, &written);
+
+    for (i = 0; i < nvec; i++) {
+        (*e)->ReleaseByteArrayElements(e, ba[i], vec[i].iov_base, JNI_ABORT);
+    }
+    if (ss == APR_SUCCESS)
+        return (jint)written;
+    else {
+        TCN_ERROR_WRAP(ss);
+        return -(jint)ss;
+    }
+}
+
+TCN_IMPLEMENT_CALL(jint, Socket, sendto)(TCN_STDARGS, jlong sock,
+                                         jlong where, jint flag,
+                                         jbyteArray buf, jint offset, jint tosend)
+{
+    tcn_socket_t *s = J2P(sock, tcn_socket_t *);
+    apr_sockaddr_t *w = J2P(where, apr_sockaddr_t *);
+    apr_size_t nbytes = (apr_size_t)tosend;
+    jbyte *bytes;
+    apr_int32_t nb;
+    apr_status_t ss;
+
+    UNREFERENCED(o);
+    TCN_ASSERT(sock != 0);
+    TCN_ASSERT(s->sock != NULL);
+
+    bytes = (*e)->GetByteArrayElements(e, buf, NULL);
+    TCN_ASSERT(bytes != NULL);
+    apr_socket_opt_get(s->sock, APR_SO_NONBLOCK, &nb);
+    if (nb)
+         bytes = (*e)->GetPrimitiveArrayCritical(e, buf, NULL);
+    else
+         bytes = (*e)->GetByteArrayElements(e, buf, NULL);
+    ss = apr_socket_sendto(s->sock, w, flag, (char *)(bytes + offset), &nbytes);
+
+    if (nb)
+        (*e)->ReleasePrimitiveArrayCritical(e, buf, bytes, 0);
+    else
+        (*e)->ReleaseByteArrayElements(e, buf, bytes, JNI_ABORT);
+    if (ss == APR_SUCCESS)
+        return (jint)nbytes;
+    else {
+        TCN_ERROR_WRAP(ss);
+        return -(jint)ss;
+    }
+}
+
+TCN_IMPLEMENT_CALL(jint, Socket, recv)(TCN_STDARGS, jlong sock,
+                                       jbyteArray buf, jint offset, jint toread)
+{
+    tcn_socket_t *s = J2P(sock, tcn_socket_t *);
+    apr_size_t nbytes = (apr_size_t)toread;
+    apr_status_t ss;
+
+    UNREFERENCED(o);
+    TCN_ASSERT(sock != 0);
+    TCN_ASSERT(s->opaque != NULL);
+
+    if (toread <= TCN_BUFFER_SZ) {
+        char sb[TCN_BUFFER_SZ];
+
+        if ((ss = (*s->net->recv)(s->opaque, sb, &nbytes)) == APR_SUCCESS)
+            (*e)->SetByteArrayRegion(e, buf, offset, (jsize)nbytes, (jbyte*)&sb[0]);
+    }
+    else {
+        jbyte *bytes = (*e)->GetByteArrayElements(e, buf, NULL);
+        if ((ss = (*s->net->recv)(s->opaque, (char*)(bytes + offset),
+                                  &nbytes)) == APR_SUCCESS)
+            (*e)->ReleaseByteArrayElements(e, buf, bytes,
+                                           nbytes ? 0 : JNI_ABORT);
+    }
+#ifdef TCN_DO_STATISTICS
+    if (ss == APR_SUCCESS) {
+        sp_max_recv = TCN_MAX(sp_max_recv, nbytes);
+        sp_min_recv = TCN_MIN(sp_min_recv, nbytes);
+        sp_tot_recv += nbytes;
+        sp_num_recv++;
+    }
+    else {
+        if (APR_STATUS_IS_ETIMEDOUT(ss) ||
+            APR_STATUS_IS_TIMEUP(ss))
+            sp_tmo_recv++;
+        else if (APR_STATUS_IS_ECONNABORTED(ss) ||
+                 APR_STATUS_IS_ECONNRESET(ss) ||
+                 APR_STATUS_IS_EOF(ss))
+            sp_rst_recv++;
+        else {
+            sp_err_recv++;
+            sp_erl_recv = ss;
+        }
+    }
+#endif
+    if (ss == APR_SUCCESS)
+        return (jint)nbytes;
+    else {
+        TCN_ERROR_WRAP(ss);
+        return -(jint)ss;
+    }
+}
+
+TCN_IMPLEMENT_CALL(jint, Socket, recvt)(TCN_STDARGS, jlong sock,
+                                        jbyteArray buf, jint offset,
+                                        jint toread, jlong timeout)
+{
+    tcn_socket_t *s = J2P(sock, tcn_socket_t *);
+    apr_size_t nbytes = (apr_size_t)toread;
+    apr_status_t ss;
+
+    UNREFERENCED(o);
+    TCN_ASSERT(sock != 0);
+    TCN_ASSERT(s->opaque != NULL);
+    TCN_ASSERT(buf != NULL);
+
+    if ((ss = (*s->net->timeout_set)(s->opaque, J2T(timeout))) != APR_SUCCESS)
+        goto cleanup;
+    if (toread <= TCN_BUFFER_SZ) {
+        jbyte sb[TCN_BUFFER_SZ];
+        if ((ss = (*s->net->recv)(s->opaque, sb, &nbytes)) == APR_SUCCESS)
+            (*e)->SetByteArrayRegion(e, buf, offset, (jsize)nbytes, &sb[0]);
+    }
+    else {
+        jbyte *sb = (jbyte *)malloc(nbytes);
+        if (sb == NULL)
+            return -APR_ENOMEM;
+        if ((ss = (*s->net->recv)(s->opaque, sb, &nbytes)) == APR_SUCCESS)
+            (*e)->SetByteArrayRegion(e, buf, offset, (jsize)nbytes, &sb[0]);
+        free(sb);
+    }
+#ifdef TCN_DO_STATISTICS
+    if (ss == APR_SUCCESS) {
+        sp_max_recv = TCN_MAX(sp_max_recv, nbytes);
+        sp_min_recv = TCN_MIN(sp_min_recv, nbytes);
+        sp_tot_recv += nbytes;
+        sp_num_recv++;
+    }
+    else {
+        if (APR_STATUS_IS_ETIMEDOUT(ss) ||
+            APR_STATUS_IS_TIMEUP(ss))
+            sp_tmo_recv++;
+        else if (APR_STATUS_IS_ECONNABORTED(ss) ||
+                 APR_STATUS_IS_ECONNRESET(ss) ||
+                 APR_STATUS_IS_EOF(ss))
+            sp_rst_recv++;
+        else {
+            sp_err_recv++;
+            sp_erl_recv = ss;
+        }
+    }
+#endif
+cleanup:
+    if (ss == APR_SUCCESS)
+        return (jint)nbytes;
+    else {
+        TCN_ERROR_WRAP(ss);
+        return -(jint)ss;
+    }
+}
+
+TCN_IMPLEMENT_CALL(jint, Socket, recvb)(TCN_STDARGS, jlong sock,
+                                        jobject buf, jint offset, jint len)
+{
+    tcn_socket_t *s = J2P(sock, tcn_socket_t *);
+    apr_status_t ss;
+    apr_size_t nbytes = (apr_size_t)len;
+    char *bytes;
+
+    UNREFERENCED(o);
+    TCN_ASSERT(sock != 0);
+    TCN_ASSERT(s->opaque != NULL);
+    TCN_ASSERT(buf != NULL);
+
+    bytes  = (char *)(*e)->GetDirectBufferAddress(e, buf);
+    TCN_ASSERT(bytes != NULL);
+    ss = (*s->net->recv)(s->opaque, bytes + offset, &nbytes);
+#ifdef TCN_DO_STATISTICS
+    if (ss == APR_SUCCESS) {
+        sp_max_recv = TCN_MAX(sp_max_recv, nbytes);
+        sp_min_recv = TCN_MIN(sp_min_recv, nbytes);
+        sp_tot_recv += nbytes;
+        sp_num_recv++;
+    }
+    else {
+        if (APR_STATUS_IS_ETIMEDOUT(ss) ||
+            APR_STATUS_IS_TIMEUP(ss))
+            sp_tmo_recv++;
+        else if (APR_STATUS_IS_ECONNABORTED(ss) ||
+                 APR_STATUS_IS_ECONNRESET(ss) ||
+                 APR_STATUS_IS_EOF(ss))
+            sp_rst_recv++;
+        else {
+            sp_err_recv++;
+            sp_erl_recv = ss;
+        }
+    }
+#endif
+    if (ss == APR_SUCCESS)
+        return (jint)nbytes;
+    else {
+        TCN_ERROR_WRAP(ss);
+        return -(jint)ss;
+    }
+}
+
+TCN_IMPLEMENT_CALL(jint, Socket, recvbb)(TCN_STDARGS, jlong sock,
+                                         jint offset, jint len)
+{
+    tcn_socket_t *s = J2P(sock, tcn_socket_t *);
+    apr_status_t ss;
+    apr_size_t nbytes = (apr_size_t)len;
+
+    UNREFERENCED_STDARGS;
+    TCN_ASSERT(sock != 0);
+    TCN_ASSERT(s->opaque != NULL);
+    TCN_ASSERT(s->jrbbuff != NULL);
+
+    ss = (*s->net->recv)(s->opaque, s->jrbbuff + offset, &nbytes);
+#ifdef TCN_DO_STATISTICS
+    if (ss == APR_SUCCESS) {
+        sp_max_recv = TCN_MAX(sp_max_recv, nbytes);
+        sp_min_recv = TCN_MIN(sp_min_recv, nbytes);
+        sp_tot_recv += nbytes;
+        sp_num_recv++;
+    }
+    else {
+        if (APR_STATUS_IS_ETIMEDOUT(ss) ||
+            APR_STATUS_IS_TIMEUP(ss))
+            sp_tmo_recv++;
+        else if (APR_STATUS_IS_ECONNABORTED(ss) ||
+                 APR_STATUS_IS_ECONNRESET(ss) ||
+                 APR_STATUS_IS_EOF(ss))
+            sp_rst_recv++;
+        else {
+            sp_err_recv++;
+            sp_erl_recv = ss;
+        }
+    }
+#endif
+    if (ss == APR_SUCCESS)
+        return (jint)nbytes;
+    else {
+        TCN_ERROR_WRAP(ss);
+        return -(jint)ss;
+    }
+}
+
+TCN_IMPLEMENT_CALL(jint, Socket, recvbt)(TCN_STDARGS, jlong sock,
+                                         jobject buf, jint offset,
+                                         jint len, jlong timeout)
+{
+    tcn_socket_t *s = J2P(sock, tcn_socket_t *);
+    apr_status_t ss;
+    apr_size_t nbytes = (apr_size_t)len;
+    char *bytes;
+
+    UNREFERENCED(o);
+    TCN_ASSERT(sock != 0);
+    TCN_ASSERT(buf != NULL);
+    TCN_ASSERT(s->opaque != NULL);
+
+    bytes  = (char *)(*e)->GetDirectBufferAddress(e, buf);
+    TCN_ASSERT(bytes != NULL);
+
+    if ((ss = (*s->net->timeout_set)(s->opaque, J2T(timeout))) != APR_SUCCESS)
+         return -(jint)ss;
+    ss = (*s->net->recv)(s->opaque, bytes + offset, &nbytes);
+#ifdef TCN_DO_STATISTICS
+    if (ss == APR_SUCCESS) {
+        sp_max_recv = TCN_MAX(sp_max_recv, nbytes);
+        sp_min_recv = TCN_MIN(sp_min_recv, nbytes);
+        sp_tot_recv += nbytes;
+        sp_num_recv++;
+    }
+    else {
+        if (APR_STATUS_IS_ETIMEDOUT(ss) ||
+            APR_STATUS_IS_TIMEUP(ss))
+            sp_tmo_recv++;
+        else if (APR_STATUS_IS_ECONNABORTED(ss) ||
+                 APR_STATUS_IS_ECONNRESET(ss) ||
+                 APR_STATUS_IS_EOF(ss))
+            sp_rst_recv++;
+        else {
+            sp_err_recv++;
+            sp_erl_recv = ss;
+        }
+    }
+#endif
+    if (ss == APR_SUCCESS)
+        return (jint)nbytes;
+    else {
+        TCN_ERROR_WRAP(ss);
+        return -(jint)ss;
+    }
+}
+
+TCN_IMPLEMENT_CALL(jint, Socket, recvbbt)(TCN_STDARGS, jlong sock,
+                                          jint offset,
+                                          jint len, jlong timeout)
+{
+    tcn_socket_t *s = J2P(sock, tcn_socket_t *);
+    apr_status_t ss;
+    apr_size_t nbytes = (apr_size_t)len;
+
+    UNREFERENCED_STDARGS;
+    TCN_ASSERT(sock != 0);
+    TCN_ASSERT(s->jrbbuff != NULL);
+    TCN_ASSERT(s->opaque != NULL);
+
+
+    if ((ss = (*s->net->timeout_set)(s->opaque, J2T(timeout))) != APR_SUCCESS)
+         return -(jint)ss;
+    ss = (*s->net->recv)(s->opaque, s->jrbbuff + offset, &nbytes);
+#ifdef TCN_DO_STATISTICS
+    if (ss == APR_SUCCESS) {
+        sp_max_recv = TCN_MAX(sp_max_recv, nbytes);
+        sp_min_recv = TCN_MIN(sp_min_recv, nbytes);
+        sp_tot_recv += nbytes;
+        sp_num_recv++;
+    }
+    else {
+        if (APR_STATUS_IS_ETIMEDOUT(ss) ||
+            APR_STATUS_IS_TIMEUP(ss))
+            sp_tmo_recv++;
+        else if (APR_STATUS_IS_ECONNABORTED(ss) ||
+                 APR_STATUS_IS_ECONNRESET(ss) ||
+                 APR_STATUS_IS_EOF(ss))
+            sp_rst_recv++;
+        else {
+            sp_err_recv++;
+            sp_erl_recv = ss;
+        }
+    }
+#endif
+    if (ss == APR_SUCCESS)
+        return (jint)nbytes;
+    else {
+        TCN_ERROR_WRAP(ss);
+        return -(jint)ss;
+    }
+}
+
+TCN_IMPLEMENT_CALL(jint, Socket, recvfrom)(TCN_STDARGS, jlong from,
+                                          jlong sock, jint flags,
+                                          jbyteArray buf, jint offset, jint toread)
+{
+    tcn_socket_t *s = J2P(sock, tcn_socket_t *);
+    apr_sockaddr_t *f = J2P(from, apr_sockaddr_t *);
+    apr_size_t nbytes = (apr_size_t)toread;
+    jbyte *bytes = (*e)->GetByteArrayElements(e, buf, NULL);
+    apr_status_t ss;
+
+    UNREFERENCED(o);
+    TCN_ASSERT(sock != 0);
+    TCN_ASSERT(s->sock != NULL);
+    TCN_ASSERT(buf != NULL);
+    ss = apr_socket_recvfrom(f, s->sock, (apr_int32_t)flags, (char*)(bytes + offset), &nbytes);
+
+    (*e)->ReleaseByteArrayElements(e, buf, bytes,
+                                   nbytes ? 0 : JNI_ABORT);
+    if (ss == APR_SUCCESS)
+        return (jint)nbytes;
+    else {
+        TCN_ERROR_WRAP(ss);
+        return -(jint)ss;
+    }
+}
+
+TCN_IMPLEMENT_CALL(jint, Socket, optSet)(TCN_STDARGS, jlong sock,
+                                         jint opt, jint on)
+{
+    tcn_socket_t *s = J2P(sock, tcn_socket_t *);
+
+    UNREFERENCED_STDARGS;
+    TCN_ASSERT(sock != 0);
+    if (!s->sock)
+        return APR_EINVAL;
+    else
+        return (jint)(*s->net->opt_set)(s->opaque, (apr_int32_t)opt, (apr_int32_t)on);
+}
+
+TCN_IMPLEMENT_CALL(jint, Socket, optGet)(TCN_STDARGS, jlong sock,
+                                         jint opt)
+{
+    tcn_socket_t *s = J2P(sock, tcn_socket_t *);
+    apr_int32_t on = 0;
+
+    UNREFERENCED(o);
+    TCN_ASSERT(sock != 0);
+    if (s->sock)
+        tcn_ThrowAPRException(e, APR_EINVAL);
+    else {
+        TCN_THROW_IF_ERR((*s->net->opt_get)(s->opaque, (apr_int32_t)opt,
+                                            &on), on);
+    }
+cleanup:
+    return (jint)on;
+}
+
+TCN_IMPLEMENT_CALL(jint, Socket, timeoutSet)(TCN_STDARGS, jlong sock,
+                                             jlong timeout)
+{
+    tcn_socket_t *s = J2P(sock, tcn_socket_t *);
+
+    UNREFERENCED_STDARGS;
+    TCN_ASSERT(sock != 0);
+    TCN_ASSERT(s->opaque != NULL);
+    return (jint)(*s->net->timeout_set)(s->opaque, J2T(timeout));
+}
+
+TCN_IMPLEMENT_CALL(jlong, Socket, timeoutGet)(TCN_STDARGS, jlong sock)
+{
+    tcn_socket_t *s = J2P(sock, tcn_socket_t *);
+    apr_interval_time_t timeout;
+
+    UNREFERENCED(o);
+    TCN_ASSERT(sock != 0);
+    TCN_ASSERT(s->opaque != NULL);
+    TCN_THROW_IF_ERR((*s->net->timeout_get)(s->opaque, &timeout), timeout);
+cleanup:
+    return (jlong)timeout;
+}
+
+TCN_IMPLEMENT_CALL(jboolean, Socket, atmark)(TCN_STDARGS, jlong sock)
+{
+    tcn_socket_t *s = J2P(sock, tcn_socket_t *);
+    apr_int32_t mark;
+
+    UNREFERENCED_STDARGS;
+    TCN_ASSERT(sock != 0);
+    TCN_ASSERT(s->sock != NULL);
+
+    if (apr_socket_atmark(s->sock, &mark) != APR_SUCCESS)
+        return JNI_FALSE;
+    return mark ? JNI_TRUE : JNI_FALSE;
+}
+
+#if APR_HAS_SENDFILE
+
+TCN_IMPLEMENT_CALL(jlong, Socket, sendfile)(TCN_STDARGS, jlong sock,
+                                            jlong file,
+                                            jobjectArray headers,
+                                            jobjectArray trailers,
+                                            jlong offset, jlong len,
+                                            jint flags)
+{
+    tcn_socket_t *s = J2P(sock, tcn_socket_t *);
+    apr_file_t *f = J2P(file, apr_file_t *);
+    jsize nh = 0;
+    jsize nt = 0;
+    jsize i;
+    struct iovec hvec[APR_MAX_IOVEC_SIZE];
+    struct iovec tvec[APR_MAX_IOVEC_SIZE];
+    jobject hba[APR_MAX_IOVEC_SIZE];
+    jobject tba[APR_MAX_IOVEC_SIZE];
+    apr_off_t off = (apr_off_t)offset;
+    apr_size_t written = (apr_size_t)len;
+    apr_hdtr_t hdrs;
+    apr_status_t ss;
+
+    UNREFERENCED(o);
+    TCN_ASSERT(sock != 0);
+    TCN_ASSERT(file != 0);
+
+    if (s->net->type != TCN_SOCKET_APR)
+        return (jint)(-APR_ENOTIMPL);
+    if (headers)
+        nh = (*e)->GetArrayLength(e, headers);
+    if (trailers)
+        nt = (*e)->GetArrayLength(e, trailers);
+    /* Check for overflow */
+    if (nh >= APR_MAX_IOVEC_SIZE || nt >= APR_MAX_IOVEC_SIZE)
+        return (jint)(-APR_ENOMEM);
+
+    for (i = 0; i < nh; i++) {
+        hba[i] = (*e)->GetObjectArrayElement(e, headers, i);
+        hvec[i].iov_len  = (*e)->GetArrayLength(e, hba[i]);
+        hvec[i].iov_base = (*e)->GetByteArrayElements(e, hba[i], NULL);
+    }
+    for (i = 0; i < nt; i++) {
+        tba[i] = (*e)->GetObjectArrayElement(e, trailers, i);
+        tvec[i].iov_len  = (*e)->GetArrayLength(e, tba[i]);
+        tvec[i].iov_base = (*e)->GetByteArrayElements(e, tba[i], NULL);
+    }
+    hdrs.headers = &hvec[0];
+    hdrs.numheaders = nh;
+    hdrs.trailers = &tvec[0];
+    hdrs.numtrailers = nt;
+
+
+    ss = apr_socket_sendfile(s->sock, f, &hdrs, &off, &written, (apr_int32_t)flags);
+
+#ifdef TCN_DO_STATISTICS
+    sf_max_send = TCN_MAX(sf_max_send, written);
+    sf_min_send = TCN_MIN(sf_min_send, written);
+    sf_tot_send += written;
+    sf_num_send++;
+#endif
+
+    for (i = 0; i < nh; i++) {
+        (*e)->ReleaseByteArrayElements(e, hba[i], hvec[i].iov_base, JNI_ABORT);
+    }
+
+    for (i = 0; i < nt; i++) {
+        (*e)->ReleaseByteArrayElements(e, tba[i], tvec[i].iov_base, JNI_ABORT);
+    }
+    /* Return Number of bytes actually sent,
+     * including headers, file, and trailers
+     */
+    if (ss == APR_SUCCESS)
+        return (jlong)written;
+    else {
+        TCN_ERROR_WRAP(ss);
+        return -(jlong)ss;
+    }
+}
+
+TCN_IMPLEMENT_CALL(jlong, Socket, sendfilen)(TCN_STDARGS, jlong sock,
+                                             jlong file,
+                                             jlong offset, jlong len,
+                                             jint flags)
+{
+    tcn_socket_t *s = J2P(sock, tcn_socket_t *);
+    apr_file_t *f = J2P(file, apr_file_t *);
+    apr_off_t off = (apr_off_t)offset;
+    apr_size_t written = (apr_size_t)len;
+    apr_hdtr_t hdrs;
+    apr_status_t ss;
+
+    UNREFERENCED_STDARGS;
+    TCN_ASSERT(sock != 0);
+    TCN_ASSERT(file != 0);
+
+    if (s->net->type != TCN_SOCKET_APR)
+        return (jint)(-APR_ENOTIMPL);
+
+    hdrs.headers = NULL;
+    hdrs.numheaders = 0;
+    hdrs.trailers = NULL;
+    hdrs.numtrailers = 0;
+
+
+    ss = apr_socket_sendfile(s->sock, f, &hdrs, &off, &written, (apr_int32_t)flags);
+
+#ifdef TCN_DO_STATISTICS
+    sf_max_send = TCN_MAX(sf_max_send, written);
+    sf_min_send = TCN_MIN(sf_min_send, written);
+    sf_tot_send += written;
+    sf_num_send++;
+#endif
+
+    /* Return Number of bytes actually sent,
+     * including headers, file, and trailers
+     */
+    if (ss == APR_SUCCESS)
+        return (jlong)written;
+    else {
+        TCN_ERROR_WRAP(ss);
+        return -(jlong)ss;
+    }
+}
+
+#else /* APR_HAS_SENDIFLE */
+
+TCN_IMPLEMENT_CALL(jlong, Socket, sendfile)(TCN_STDARGS, jlong sock,
+                                            jlong file,
+                                            jobjectArray headers,
+                                            jobjectArray trailers,
+                                            jlong offset, jlong len,
+                                            jint flags)
+{
+
+    UNREFERENCED_STDARGS;
+    UNREFERENCED(sock);
+    UNREFERENCED(file);
+    UNREFERENCED(headers);
+    UNREFERENCED(trailers);
+    UNREFERENCED(offset);
+    UNREFERENCED(len);
+    UNREFERENCED(flags);
+    return -(jlong)APR_ENOTIMPL;
+}
+
+TCN_IMPLEMENT_CALL(jlong, Socket, sendfilen)(TCN_STDARGS, jlong sock,
+                                             jlong file,
+                                             jlong offset, jlong len,
+                                             jint flags)
+{
+    UNREFERENCED_STDARGS;
+    UNREFERENCED(sock);
+    UNREFERENCED(file);
+    UNREFERENCED(offset);
+    UNREFERENCED(len);
+    UNREFERENCED(flags);
+    return -(jlong)APR_ENOTIMPL;
+}
+
+#endif  /* APR_HAS_SENDIFLE */
+
+
+TCN_IMPLEMENT_CALL(jint, Socket, acceptfilter)(TCN_STDARGS,
+                                               jlong sock,
+                                               jstring name,
+                                               jstring args)
+{
+#if APR_HAS_SO_ACCEPTFILTER
+    tcn_socket_t *s = J2P(sock, tcn_socket_t *);
+    TCN_ALLOC_CSTRING(name);
+    TCN_ALLOC_CSTRING(args);
+    apr_status_t rv;
+
+
+    UNREFERENCED(o);
+    rv = apr_socket_accept_filter(s->sock, J2S(name),
+                                  J2S(args) ? J2S(args) : "");
+    TCN_FREE_CSTRING(name);
+    TCN_FREE_CSTRING(args);
+    return (jint)rv;
+#else
+    UNREFERENCED_STDARGS;
+    UNREFERENCED(sock);
+    UNREFERENCED(name);
+    UNREFERENCED(args);
+    return (jint)APR_ENOTIMPL;
+#endif
+}
+
+TCN_IMPLEMENT_CALL(jint, Socket, dataSet)(TCN_STDARGS, jlong sock,
+                                          jstring key, jobject data)
+{
+    tcn_socket_t *s = J2P(sock, tcn_socket_t *);
+    apr_status_t rv = APR_SUCCESS;
+    TCN_ALLOC_CSTRING(key);
+
+    UNREFERENCED(o);
+    TCN_ASSERT(sock != 0);
+
+    rv = apr_socket_data_set(s->sock, data, J2S(key), NULL);
+    TCN_FREE_CSTRING(key);
+    return rv;
+}
+
+TCN_IMPLEMENT_CALL(jobject, Socket, dataGet)(TCN_STDARGS, jlong socket,
+                                             jstring key)
+{
+    tcn_socket_t *s = J2P(socket, tcn_socket_t *);
+    TCN_ALLOC_CSTRING(key);
+    jobject rv = NULL;
+
+    UNREFERENCED(o);
+    TCN_ASSERT(sock != 0);
+
+    if (apr_socket_data_get(&rv, J2S(key), s->sock) != APR_SUCCESS) {
+        rv = NULL;
+    }
+    TCN_FREE_CSTRING(key);
+    return rv;
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/src/os.c
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/src/os.c	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/src/os.c	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,39 @@
+/* Copyright 2000-2005 The Apache Software Foundation
+ *
+ * Licensed 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.
+ */
+
+/*
+ *
+ * @author Mladen Turk
+ * @version $Revision: 420070 $, $Date: 2006-07-08 02:18:55 -0500 (Sat, 08 Jul 2006) $
+ */
+
+#include "tcn.h"
+
+TCN_IMPLEMENT_CALL(jstring, OS, defaultEncoding)(TCN_STDARGS, jlong pool)
+{
+    apr_pool_t *p = J2P(pool, apr_pool_t *);
+
+    UNREFERENCED(o);
+    return AJP_TO_JSTRING(apr_os_default_encoding(p));
+}
+
+TCN_IMPLEMENT_CALL(jstring, OS, localeEncoding)(TCN_STDARGS, jlong pool)
+{
+    apr_pool_t *p = J2P(pool, apr_pool_t *);
+
+    UNREFERENCED(o);
+    return AJP_TO_JSTRING(apr_os_locale_encoding(p));
+}
+

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/src/poll.c
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/src/poll.c	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/src/poll.c	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,385 @@
+/* Copyright 2000-2006 The Apache Software Foundation
+ *
+ * Licensed 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.
+ */
+
+/*
+ *
+ * @author Mladen Turk
+ * @version $Revision: 440712 $, $Date: 2006-09-06 08:44:02 -0500 (Wed, 06 Sep 2006) $
+ */
+
+#include "tcn.h"
+#include "apr_poll.h"
+
+
+#ifdef TCN_DO_STATISTICS
+static int sp_created       = 0;
+static int sp_destroyed     = 0;
+static int sp_cleared       = 0;
+#endif
+
+/* Internal poll structure for queryset
+ */
+
+typedef struct tcn_pollset {
+    apr_pool_t    *pool;
+    apr_int32_t   nelts;
+    apr_int32_t   nalloc;
+    apr_pollset_t *pollset;
+    jlong         *set;
+    apr_pollfd_t  *socket_set;
+    apr_interval_time_t *socket_ttl;
+    apr_interval_time_t max_ttl;
+#ifdef TCN_DO_STATISTICS
+    int sp_added;
+    int sp_max_count;
+    int sp_poll;
+    int sp_polled;
+    int sp_max_polled;
+    int sp_remove;
+    int sp_removed;
+    int sp_maintained;
+    int sp_max_maintained;
+    int sp_err_poll;
+    int sp_poll_timeout;
+    int sp_overflow;
+    int sp_equals;
+    int sp_eintr;
+#endif
+} tcn_pollset_t;
+
+#ifdef TCN_DO_STATISTICS
+static void sp_poll_statistics(tcn_pollset_t *p)
+{
+    fprintf(stderr, "Pollset Statistics ......\n");
+    fprintf(stderr, "Number of added sockets : %d\n", p->sp_added);
+    fprintf(stderr, "Max. number of sockets  : %d\n", p->sp_max_count);
+    fprintf(stderr, "Poll calls              : %d\n", p->sp_poll);
+    fprintf(stderr, "Poll timeouts           : %d\n", p->sp_poll_timeout);
+    fprintf(stderr, "Poll errors             : %d\n", p->sp_err_poll);
+    fprintf(stderr, "Poll overflows          : %d\n", p->sp_overflow);
+    fprintf(stderr, "Polled sockets          : %d\n", p->sp_polled);
+    fprintf(stderr, "Max. Polled sockets     : %d\n", p->sp_max_polled);
+    fprintf(stderr, "Poll remove             : %d\n", p->sp_remove);
+    fprintf(stderr, "Total removed           : %d\n", p->sp_removed);
+    fprintf(stderr, "Maintained              : %d\n", p->sp_maintained);
+    fprintf(stderr, "Max. maintained         : %d\n", p->sp_max_maintained);
+    fprintf(stderr, "Number of duplicates    : %d\n", p->sp_equals);
+    fprintf(stderr, "Number of interrupts    : %d\n", p->sp_eintr);
+
+}
+
+static apr_status_t sp_poll_cleanup(void *data)
+{
+    sp_cleared++;
+    sp_poll_statistics(data);
+    return APR_SUCCESS;
+}
+
+void sp_poll_dump_statistics()
+{
+    fprintf(stderr, "Poll Statistics .........\n");
+    fprintf(stderr, "Polls created           : %d\n", sp_created);
+    fprintf(stderr, "Polls destroyed         : %d\n", sp_destroyed);
+    fprintf(stderr, "Polls cleared           : %d\n", sp_cleared);
+}
+#endif
+
+TCN_IMPLEMENT_CALL(jlong, Poll, create)(TCN_STDARGS, jint size,
+                                        jlong pool, jint flags,
+                                        jlong ttl)
+{
+    apr_pool_t *p = J2P(pool, apr_pool_t *);
+    apr_pollset_t *pollset = NULL;
+    tcn_pollset_t *tps = NULL;
+    apr_uint32_t f = (apr_uint32_t)flags;
+    UNREFERENCED(o);
+    TCN_ASSERT(pool != 0);
+
+    if (f & APR_POLLSET_THREADSAFE) {
+        apr_status_t rv = apr_pollset_create(&pollset, (apr_uint32_t)size, p, f);
+        if (rv == APR_ENOTIMPL)
+            f &= ~APR_POLLSET_THREADSAFE;
+        else if (rv != APR_SUCCESS) {
+            tcn_ThrowAPRException(e, rv);
+            goto cleanup;
+        }
+    }
+    if (pollset == NULL) {
+        TCN_THROW_IF_ERR(apr_pollset_create(&pollset,
+                         (apr_uint32_t)size, p, f), pollset);
+    }
+    tps = apr_pcalloc(p, sizeof(tcn_pollset_t));
+    TCN_CHECK_ALLOCATED(tps);
+    tps->pollset = pollset;
+    tps->set        = apr_palloc(p, size * sizeof(jlong) * 2);
+    TCN_CHECK_ALLOCATED(tps->set);
+    tps->socket_set = apr_palloc(p, size * sizeof(apr_pollfd_t));
+    TCN_CHECK_ALLOCATED(tps->socket_set);
+    tps->socket_ttl = apr_palloc(p, size * sizeof(apr_interval_time_t));
+    TCN_CHECK_ALLOCATED(tps->socket_ttl);
+    tps->nelts  = 0;
+    tps->nalloc = size;
+    tps->pool   = p;
+    tps->max_ttl = J2T(ttl);
+#ifdef TCN_DO_STATISTICS
+    sp_created++;
+    apr_pool_cleanup_register(p, (const void *)tps,
+                              sp_poll_cleanup,
+                              apr_pool_cleanup_null);
+#endif
+cleanup:
+    return P2J(tps);
+}
+
+TCN_IMPLEMENT_CALL(jint, Poll, destroy)(TCN_STDARGS, jlong pollset)
+{
+    tcn_pollset_t *p = J2P(pollset,  tcn_pollset_t *);
+
+    UNREFERENCED_STDARGS;
+    TCN_ASSERT(pollset != 0);
+#ifdef TCN_DO_STATISTICS
+    sp_destroyed++;
+    apr_pool_cleanup_kill(p->pool, p, sp_poll_cleanup);
+    sp_poll_statistics(p);
+#endif
+    return (jint)apr_pollset_destroy(p->pollset);
+}
+
+TCN_IMPLEMENT_CALL(jint, Poll, add)(TCN_STDARGS, jlong pollset,
+                                    jlong socket, jint reqevents)
+{
+    tcn_pollset_t *p = J2P(pollset,  tcn_pollset_t *);
+    tcn_socket_t *s  = J2P(socket, tcn_socket_t *);
+    apr_pollfd_t fd;
+
+    UNREFERENCED_STDARGS;
+    TCN_ASSERT(socket != 0);
+
+    if (p->nelts == p->nalloc) {
+#ifdef TCN_DO_STATISTICS
+        p->sp_overflow++;
+#endif
+        return APR_ENOMEM;
+    }
+    memset(&fd, 0, sizeof(apr_pollfd_t));
+    fd.desc_type = APR_POLL_SOCKET;
+    fd.reqevents = (apr_int16_t)reqevents;
+    fd.desc.s    = s->sock;
+    fd.client_data = s;
+    p->socket_ttl[p->nelts] = apr_time_now();
+    p->socket_set[p->nelts] = fd;
+    p->nelts++;
+#ifdef TCN_DO_STATISTICS
+    p->sp_added++;
+    p->sp_max_count = TCN_MAX(p->sp_max_count, p->sp_added);
+#endif
+    return (jint)apr_pollset_add(p->pollset, &fd);
+}
+
+static apr_status_t do_remove(tcn_pollset_t *p, const apr_pollfd_t *fd)
+{
+    apr_int32_t i;
+
+    for (i = 0; i < p->nelts; i++) {
+        if (fd->desc.s == p->socket_set[i].desc.s) {
+            /* Found an instance of the fd: remove this and any other copies */
+            apr_int32_t dst = i;
+            apr_int32_t old_nelts = p->nelts;
+            p->nelts--;
+#ifdef TCN_DO_STATISTICS
+            p->sp_removed++;
+#endif
+            for (i++; i < old_nelts; i++) {
+                if (fd->desc.s == p->socket_set[i].desc.s) {
+#ifdef TCN_DO_STATISTICS
+                    p->sp_equals++;
+#endif
+                    p->nelts--;
+                }
+                else {
+                    p->socket_set[dst] = p->socket_set[i];
+                    dst++;
+                }
+            }
+            break;
+        }
+    }
+    return apr_pollset_remove(p->pollset, fd);
+}
+
+TCN_IMPLEMENT_CALL(jint, Poll, remove)(TCN_STDARGS, jlong pollset,
+                                       jlong socket)
+{
+    tcn_pollset_t *p = J2P(pollset,  tcn_pollset_t *);
+    tcn_socket_t *s  = J2P(socket, tcn_socket_t *);
+    apr_pollfd_t fd;
+
+    UNREFERENCED_STDARGS;
+    TCN_ASSERT(socket != 0);
+
+    memset(&fd, 0, sizeof(apr_pollfd_t));
+    fd.desc_type = APR_POLL_SOCKET;
+    fd.desc.s    = s->sock;
+    fd.reqevents = APR_POLLIN | APR_POLLOUT;
+#ifdef TCN_DO_STATISTICS
+    p->sp_remove++;
+#endif
+
+    return (jint)do_remove(p, &fd);
+}
+
+
+TCN_IMPLEMENT_CALL(jint, Poll, poll)(TCN_STDARGS, jlong pollset,
+                                     jlong timeout, jlongArray set,
+                                     jboolean remove)
+{
+    const apr_pollfd_t *fd = NULL;
+    tcn_pollset_t *p = J2P(pollset,  tcn_pollset_t *);
+    apr_int32_t  i, num = 0;
+    apr_status_t rv = APR_SUCCESS;
+    apr_interval_time_t ptime = J2T(timeout);
+    UNREFERENCED(o);
+    TCN_ASSERT(pollset != 0);
+
+#ifdef TCN_DO_STATISTICS
+     p->sp_poll++;
+#endif
+
+    if (timeout > 0) {
+        apr_time_t now = apr_time_now();
+
+        /* Find the minimum timeout */
+        for (i = 0; i < p->nelts; i++) {
+            apr_interval_time_t t = now - p->socket_ttl[i];
+            if (t >= p->max_ttl) {
+                ptime = 0;
+                break;
+            }
+            else {
+                ptime = TCN_MIN(p->max_ttl - t, ptime);
+            }
+        }
+    }
+    for (;;) {
+        rv = apr_pollset_poll(p->pollset, ptime, &num, &fd);
+        if (rv != APR_SUCCESS) {
+            if (APR_STATUS_IS_EINTR(rv)) {
+#ifdef TCN_DO_STATISTICS
+                p->sp_eintr++;
+#endif
+                continue;
+            }
+            TCN_ERROR_WRAP(rv);
+#ifdef TCN_DO_STATISTICS
+            if (rv == TCN_TIMEUP)
+                p->sp_poll_timeout++;
+            else
+                p->sp_err_poll++;
+#endif
+            num = (apr_int32_t)(-rv);
+        }
+        break;
+    }
+    if (num > 0) {
+#ifdef TCN_DO_STATISTICS
+         p->sp_polled += num;
+         p->sp_max_polled = TCN_MAX(p->sp_max_polled, num);
+#endif
+        for (i = 0; i < num; i++) {
+            p->set[i*2+0] = (jlong)(fd->rtnevents);
+            p->set[i*2+1] = P2J(fd->client_data);
+            if (remove)
+                do_remove(p, fd);
+            fd ++;
+        }
+        (*e)->SetLongArrayRegion(e, set, 0, num * 2, p->set);
+    }
+
+    return (jint)num;
+}
+
+TCN_IMPLEMENT_CALL(jint, Poll, maintain)(TCN_STDARGS, jlong pollset,
+                                         jlongArray set, jboolean remove)
+{
+    tcn_pollset_t *p = J2P(pollset,  tcn_pollset_t *);
+    apr_int32_t  i = 0, num = 0;
+    apr_time_t now = apr_time_now();
+    apr_pollfd_t fd;
+
+    UNREFERENCED(o);
+    TCN_ASSERT(pollset != 0);
+
+    /* Check for timeout sockets */
+    if (p->max_ttl > 0) {
+        for (i = 0; i < p->nelts; i++) {
+            if ((now - p->socket_ttl[i]) >= p->max_ttl) {
+                fd = p->socket_set[i];
+                p->set[num++] = P2J(fd.client_data);
+            }
+        }
+        if (remove && num) {
+            memset(&fd, 0, sizeof(apr_pollfd_t));
+#ifdef TCN_DO_STATISTICS
+             p->sp_maintained += num;
+             p->sp_max_maintained = TCN_MAX(p->sp_max_maintained, num);
+#endif
+            for (i = 0; i < num; i++) {
+                fd.desc_type = APR_POLL_SOCKET;
+                fd.reqevents = APR_POLLIN | APR_POLLOUT;
+                fd.desc.s = (J2P(p->set[i], tcn_socket_t *))->sock;
+                do_remove(p, &fd);
+            }
+        }
+    }
+    if (num)
+        (*e)->SetLongArrayRegion(e, set, 0, num, p->set);
+    return (jint)num;
+}
+
+TCN_IMPLEMENT_CALL(void, Poll, setTtl)(TCN_STDARGS, jlong pollset,
+                                       jlong ttl)
+{
+    tcn_pollset_t *p = J2P(pollset,  tcn_pollset_t *);
+    UNREFERENCED_STDARGS;
+    p->max_ttl = J2T(ttl);
+}
+
+TCN_IMPLEMENT_CALL(jlong, Poll, getTtl)(TCN_STDARGS, jlong pollset)
+{
+    tcn_pollset_t *p = J2P(pollset,  tcn_pollset_t *);
+    UNREFERENCED_STDARGS;
+    return (jlong)p->max_ttl;
+}
+
+TCN_IMPLEMENT_CALL(jint, Poll, pollset)(TCN_STDARGS, jlong pollset,
+                                        jlongArray set)
+{
+    tcn_pollset_t *p = J2P(pollset,  tcn_pollset_t *);
+    apr_int32_t  i = 0;
+    apr_pollfd_t fd;
+
+    UNREFERENCED(o);
+    TCN_ASSERT(pollset != 0);
+
+    for (i = 0; i < p->nelts; i++) {
+        p->socket_set[i].rtnevents = APR_POLLHUP | APR_POLLIN;
+        fd = p->socket_set[i];
+        p->set[i*2+0] = (jlong)(fd.rtnevents);
+        p->set[i*2+1] = P2J(fd.client_data);
+    }
+    if (p->nelts)
+        (*e)->SetLongArrayRegion(e, set, 0, p->nelts * 2, p->set);
+    return (jint)p->nelts;
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/src/pool.c
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/src/pool.c	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/src/pool.c	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,249 @@
+/* Copyright 2000-2005 The Apache Software Foundation
+ *
+ * Licensed 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.
+ */
+
+/*
+ *
+ * @author Mladen Turk
+ * @version $Revision: 439960 $, $Date: 2006-09-04 02:15:58 -0500 (Mon, 04 Sep 2006) $
+ */
+
+#include "tcn.h"
+
+extern apr_pool_t *tcn_global_pool;
+
+static apr_status_t generic_pool_cleanup(void *data)
+{
+    apr_status_t rv = APR_SUCCESS;
+    tcn_callback_t *cb = (tcn_callback_t *)data;
+
+    if (data) {
+        JNIEnv *env;
+        tcn_get_java_env(&env);
+        if (!TCN_IS_NULL(env, cb->obj)) {
+            rv = (*(env))->CallIntMethod(env, cb->obj, cb->mid[0],
+                                         NULL);
+            TCN_UNLOAD_CLASS(env, cb->obj);
+        }
+        free(cb);
+    }
+    return rv;
+}
+
+TCN_IMPLEMENT_CALL(jlong, Pool, create)(TCN_STDARGS, jlong parent)
+{
+    apr_pool_t *p = J2P(parent, apr_pool_t *);
+    apr_pool_t *n;
+
+    UNREFERENCED(o);
+    /* Make sure our global pool is accessor for all pools */
+    if (p == NULL)
+        p = tcn_global_pool;
+    TCN_THROW_IF_ERR(apr_pool_create(&n, p), n);
+cleanup:
+    return P2J(n);
+}
+
+TCN_IMPLEMENT_CALL(void, Pool, clear)(TCN_STDARGS, jlong pool)
+{
+    apr_pool_t *p = J2P(pool, apr_pool_t *);
+    UNREFERENCED_STDARGS;
+    TCN_ASSERT(pool != 0);
+    apr_pool_clear(p);
+}
+
+TCN_IMPLEMENT_CALL(void, Pool, destroy)(TCN_STDARGS, jlong pool)
+{
+    apr_pool_t *p = J2P(pool, apr_pool_t *);
+    UNREFERENCED_STDARGS;
+    TCN_ASSERT(pool != 0);
+    apr_pool_destroy(p);
+}
+
+TCN_IMPLEMENT_CALL(jlong, Pool, parentGet)(TCN_STDARGS, jlong pool)
+{
+    apr_pool_t *p = J2P(pool, apr_pool_t *);
+    UNREFERENCED_STDARGS;
+    TCN_ASSERT(pool != 0);
+    return P2J(apr_pool_parent_get(p));
+}
+
+TCN_IMPLEMENT_CALL(jboolean, Pool, isAncestor)(TCN_STDARGS, jlong a, jlong b)
+{
+    apr_pool_t *pa = J2P(a, apr_pool_t *);
+    apr_pool_t *pb = J2P(b, apr_pool_t *);
+    UNREFERENCED_STDARGS;
+    return apr_pool_is_ancestor(pa, pb) ? JNI_TRUE : JNI_FALSE;
+}
+
+TCN_IMPLEMENT_CALL(jlong, Pool, palloc)(TCN_STDARGS, jlong pool, jint size)
+{
+    apr_pool_t *p = J2P(pool, apr_pool_t *);
+    UNREFERENCED_STDARGS;
+    return P2J(apr_palloc(p, (apr_size_t)size));
+}
+
+TCN_IMPLEMENT_CALL(jlong, Pool, pcalloc)(TCN_STDARGS, jlong pool, jint size)
+{
+    apr_pool_t *p = J2P(pool, apr_pool_t *);
+    UNREFERENCED_STDARGS;
+    return P2J(apr_pcalloc(p, (apr_size_t)size));
+}
+
+TCN_IMPLEMENT_CALL(jlong, Pool, cleanupRegister)(TCN_STDARGS, jlong pool,
+                                                 jobject obj)
+{
+    apr_pool_t *p = J2P(pool, apr_pool_t *);
+    tcn_callback_t *cb = (tcn_callback_t *)malloc(sizeof(tcn_callback_t));
+    jclass cls;
+
+    UNREFERENCED(o);
+
+    if (cb == NULL) {
+       TCN_THROW_OS_ERROR(e);
+       return 0;
+    }
+    cls = (*e)->GetObjectClass(e, obj);
+    cb->obj    = (*e)->NewGlobalRef(e, obj);
+    cb->mid[0] = (*e)->GetMethodID(e, cls, "callback", "()I");
+
+    apr_pool_cleanup_register(p, (const void *)cb,
+                              generic_pool_cleanup,
+                              apr_pool_cleanup_null);
+
+    return P2J(cb);
+}
+
+TCN_IMPLEMENT_CALL(void, Pool, cleanupKill)(TCN_STDARGS, jlong pool,
+                                            jlong data)
+{
+    apr_pool_t *p = J2P(pool, apr_pool_t *);
+    tcn_callback_t *cb = J2P(data, tcn_callback_t *);
+
+    UNREFERENCED(o);
+    TCN_ASSERT(pool != 0);
+    apr_pool_cleanup_kill(p, cb, generic_pool_cleanup);
+    (*e)->DeleteGlobalRef(e, cb->obj);
+    free(cb);
+}
+
+TCN_IMPLEMENT_CALL(jobject, Pool, alloc)(TCN_STDARGS, jlong pool,
+                                         jint size)
+{
+    apr_pool_t *p = J2P(pool, apr_pool_t *);
+    apr_size_t sz = (apr_size_t)size;
+    void *mem;
+
+    UNREFERENCED(o);
+    TCN_ASSERT(pool != 0);
+
+    if ((mem = apr_palloc(p, sz)) != NULL)
+        return (*e)->NewDirectByteBuffer(e, mem, (jlong)sz);
+    else
+        return NULL;
+}
+
+TCN_IMPLEMENT_CALL(jobject, Pool, calloc)(TCN_STDARGS, jlong pool,
+                                          jint size)
+{
+    apr_pool_t *p = J2P(pool, apr_pool_t *);
+    apr_size_t sz = (apr_size_t)size;
+    void *mem;
+
+    UNREFERENCED(o);
+    TCN_ASSERT(pool != 0);
+
+    if ((mem = apr_pcalloc(p, sz)) != NULL)
+        return (*e)->NewDirectByteBuffer(e, mem, (jlong)sz);
+    else
+        return NULL;
+}
+
+static apr_status_t generic_pool_data_cleanup(void *data)
+{
+    apr_status_t rv = APR_SUCCESS;
+    tcn_callback_t *cb = (tcn_callback_t *)data;
+
+    if (data) {
+        JNIEnv *env;
+        tcn_get_java_env(&env);
+        
+        if (!TCN_IS_NULL(env, cb->obj)) {
+            TCN_UNLOAD_CLASS(env, cb->obj);
+        }
+        free(cb);
+    }
+    return rv;
+}
+
+TCN_IMPLEMENT_CALL(jint, Pool, dataSet)(TCN_STDARGS, jlong pool,
+                                        jstring key, jobject data)
+{
+    apr_pool_t *p = J2P(pool, apr_pool_t *);
+    apr_status_t rv = APR_SUCCESS;
+    void *old = NULL;
+    TCN_ALLOC_CSTRING(key);
+
+    UNREFERENCED(o);
+    TCN_ASSERT(pool != 0);
+
+    if (apr_pool_userdata_get(&old, J2S(key), p) == APR_SUCCESS) {
+        if (old)
+            apr_pool_cleanup_run(p, old, generic_pool_data_cleanup);
+    }
+    if (data) {
+        JNIEnv *e;        
+        tcn_callback_t *cb = (tcn_callback_t *)malloc(sizeof(tcn_callback_t));
+        tcn_get_java_env(&e);
+        cb->obj = (*e)->NewGlobalRef(e, data);
+        if ((rv = apr_pool_userdata_set(cb, J2S(key), generic_pool_data_cleanup,
+                                        p)) != APR_SUCCESS) {
+            (*e)->DeleteGlobalRef(e, cb->obj);
+            free(cb);
+        }
+    }
+    else {
+        /* Clear the exiting user data */
+        rv = apr_pool_userdata_set(NULL, J2S(key), NULL, p);
+    }
+    TCN_FREE_CSTRING(key);
+    return rv;
+}
+
+TCN_IMPLEMENT_CALL(jobject, Pool, dataGet)(TCN_STDARGS, jlong pool,
+                                           jstring key)
+{
+    apr_pool_t *p = J2P(pool, apr_pool_t *);
+    void *old = NULL;
+    TCN_ALLOC_CSTRING(key);
+    jobject rv = NULL;
+
+    UNREFERENCED(o);
+    TCN_ASSERT(pool != 0);
+
+    if (apr_pool_userdata_get(&old, J2S(key), p) == APR_SUCCESS) {
+        if (old) {
+            tcn_callback_t *cb = (tcn_callback_t *)old;
+            rv = cb->obj;
+        }
+    }
+    TCN_FREE_CSTRING(key);
+    return rv;
+}
+
+TCN_IMPLEMENT_CALL(void, Pool, cleanupForExec)(TCN_STDARGS)
+{
+    UNREFERENCED_STDARGS;
+    apr_pool_cleanup_for_exec();
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/src/proc.c
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/src/proc.c	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/src/proc.c	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,453 @@
+/* Copyright 2000-2005 The Apache Software Foundation
+ *
+ * Licensed 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.
+ */
+
+/*
+ *
+ * @author Mladen Turk
+ * @version $Revision: 439960 $, $Date: 2006-09-04 02:15:58 -0500 (Mon, 04 Sep 2006) $
+ */
+ 
+#include "tcn.h"
+#include "apr_thread_proc.h"
+#include "apr_version.h"
+
+#define ERRFN_USERDATA_KEY    "TCNATIVECHILDERRFN"
+
+static void generic_child_errfn(apr_pool_t *pool, apr_status_t err,
+                                const char *description)
+{
+    void *data;
+    tcn_callback_t *cb;
+
+    apr_pool_userdata_get(&data, ERRFN_USERDATA_KEY, pool);
+    cb = (tcn_callback_t *)data;
+    if (cb) {
+        JNIEnv *env;
+        tcn_get_java_env(&env);
+        if (!TCN_IS_NULL(env, cb->obj)) {
+            (*(env))->CallVoidMethod(env, cb->obj, cb->mid[0],
+                                P2J(pool), (jint)err,
+                                (*(env))->NewStringUTF(env, description),
+                                NULL);
+        }
+    }
+}
+
+static apr_status_t child_errfn_pool_cleanup(void *data)
+{
+    tcn_callback_t *cb = (tcn_callback_t *)data;
+
+    if (data) {
+        JNIEnv *env;
+        if (!TCN_IS_NULL(env, cb->obj)) {
+            TCN_UNLOAD_CLASS(env, cb->obj);
+        }
+        free(cb);
+    }
+    return APR_SUCCESS;
+}
+
+TCN_IMPLEMENT_CALL(jlong, Procattr, create)(TCN_STDARGS,
+                                            jlong pool)
+{
+    apr_pool_t *p = J2P(pool, apr_pool_t *);
+    apr_procattr_t *attr;
+
+
+    UNREFERENCED(o);
+    TCN_THROW_IF_ERR(apr_procattr_create(&attr, p), attr);
+
+cleanup:
+    return P2J(attr);
+}
+
+TCN_IMPLEMENT_CALL(jint, Procattr, ioSet)(TCN_STDARGS,
+                                          jlong attr, jint in,
+                                          jint out, jint err)
+{
+    apr_procattr_t *a = J2P(attr, apr_procattr_t *);
+
+    UNREFERENCED_STDARGS;
+    return (jint)apr_procattr_io_set(a, (apr_int32_t)in,
+                     (apr_int32_t)out, (apr_int32_t)err);
+}
+
+TCN_IMPLEMENT_CALL(jint, Procattr, childInSet)(TCN_STDARGS,
+                                          jlong attr, jlong in,
+                                          jlong parent)
+{
+    apr_procattr_t *a = J2P(attr, apr_procattr_t *);
+    apr_file_t *f = J2P(in, apr_file_t *);
+    apr_file_t *p = J2P(parent, apr_file_t *);
+
+    UNREFERENCED_STDARGS;
+    return (jint)apr_procattr_child_in_set(a, f, p);
+}
+
+TCN_IMPLEMENT_CALL(jint, Procattr, childOutSet)(TCN_STDARGS,
+                                          jlong attr, jlong out,
+                                          jlong parent)
+{
+    apr_procattr_t *a = J2P(attr, apr_procattr_t *);
+    apr_file_t *f = J2P(out, apr_file_t *);
+    apr_file_t *p = J2P(parent, apr_file_t *);
+
+    UNREFERENCED_STDARGS;
+    return (jint)apr_procattr_child_out_set(a, f, p);
+}
+
+TCN_IMPLEMENT_CALL(jint, Procattr, childErrSet)(TCN_STDARGS,
+                                          jlong attr, jlong err,
+                                          jlong parent)
+{
+    apr_procattr_t *a = J2P(attr, apr_procattr_t *);
+    apr_file_t *f = J2P(err, apr_file_t *);
+    apr_file_t *p = J2P(parent, apr_file_t *);
+
+    UNREFERENCED_STDARGS;
+    return (jint)apr_procattr_child_in_set(a, f, p);
+}
+
+TCN_IMPLEMENT_CALL(jint, Procattr, dirSet)(TCN_STDARGS,
+                                           jlong attr,
+                                           jstring dir)
+{
+    apr_status_t rv;
+    apr_procattr_t *a = J2P(attr, apr_procattr_t *);
+    TCN_ALLOC_CSTRING(dir);
+
+    UNREFERENCED(o);
+
+    rv = apr_procattr_dir_set(a, J2S(dir));
+    TCN_FREE_CSTRING(dir);
+    return (jint) rv;
+}
+
+TCN_IMPLEMENT_CALL(jint, Procattr, cmdtypeSet)(TCN_STDARGS,
+                                          jlong attr, jint cmd)
+{
+    apr_procattr_t *a = J2P(attr, apr_procattr_t *);
+
+    UNREFERENCED_STDARGS;
+    return (jint)apr_procattr_cmdtype_set(a, (apr_int32_t)cmd);
+}
+
+TCN_IMPLEMENT_CALL(jint, Procattr, detachSet)(TCN_STDARGS,
+                                          jlong attr, jint detach)
+{
+    apr_procattr_t *a = J2P(attr, apr_procattr_t *);
+
+    UNREFERENCED_STDARGS;
+    return (jint)apr_procattr_detach_set(a, (apr_int32_t)detach);
+}
+
+TCN_IMPLEMENT_CALL(jint, Procattr, errorCheckSet)(TCN_STDARGS,
+                                          jlong attr, jint chk)
+{
+    apr_procattr_t *a = J2P(attr, apr_procattr_t *);
+
+    UNREFERENCED_STDARGS;
+    return (jint)apr_procattr_error_check_set(a, (apr_int32_t)chk);
+}
+
+TCN_IMPLEMENT_CALL(jint, Procattr, addrspaceSet)(TCN_STDARGS,
+                                          jlong attr, jint addr)
+{
+    apr_procattr_t *a = J2P(attr, apr_procattr_t *);
+
+    UNREFERENCED_STDARGS;
+    return (jint)apr_procattr_addrspace_set(a, (apr_int32_t)addr);
+}
+
+TCN_IMPLEMENT_CALL(jlong, Proc, alloc)(TCN_STDARGS,
+                                       jlong pool)
+{
+    apr_pool_t *p = J2P(pool, apr_pool_t *);
+    apr_proc_t *proc;
+
+
+    UNREFERENCED_STDARGS;
+    proc = (apr_proc_t *)apr_pcalloc(p, sizeof(apr_proc_t));
+
+    return P2J(proc);
+}
+
+
+#define MAX_ARGS_SIZE 1024
+#define MAX_ENV_SIZE  1024
+
+TCN_IMPLEMENT_CALL(jint, Proc, create)(TCN_STDARGS, jlong proc,
+                                       jstring progname,
+                                       jobjectArray args,
+                                       jobjectArray env,
+                                       jlong attr, jlong pool)
+{
+    apr_status_t rv;
+    apr_pool_t *p = J2P(pool, apr_pool_t *);
+    apr_procattr_t *a = J2P(attr, apr_procattr_t *);
+    apr_proc_t *np = J2P(proc, apr_proc_t *);
+    TCN_ALLOC_CSTRING(progname);
+    char *s_args[MAX_ARGS_SIZE];
+    char *s_env[MAX_ENV_SIZE];
+    const char * const *pargs = NULL;
+    const char * const *penv  = NULL;
+    jsize as = 0;
+    jsize es = 0;
+    jsize i;
+
+    UNREFERENCED(o);
+    if (args)
+        as = (*e)->GetArrayLength(e, args);
+    if (env)
+        es = (*e)->GetArrayLength(e, args);
+    if (as > (MAX_ARGS_SIZE - 1) || es > (MAX_ENV_SIZE - 2)) {
+        TCN_FREE_CSTRING(progname);
+        return APR_EINVAL;
+    }
+    if (as) {
+        for (i = 0; i < as; i++) {
+            jstring str = (*e)->GetObjectArrayElement(e, args, i);
+            s_args[i] = tcn_get_string(e, str);
+            (*e)->DeleteLocalRef(e, str);
+        }
+        s_args[i] = NULL;
+        pargs = (const char * const *)&s_args[0];
+    }
+    if (es) {
+        for (i = 0; i < es; i++) {
+            jstring str = (*e)->GetObjectArrayElement(e, env, i);
+            s_env[i+1] = tcn_get_string(e, str);
+            (*e)->DeleteLocalRef(e, str);
+        }
+#ifdef WIN32
+        s_env[i++] = apr_psprintf(p, TCN_PARENT_IDE "=%d", getpid());
+#endif
+        s_env[i] = NULL;
+        penv = (const char * const *)&s_env[0];
+    }
+#ifdef WIN32
+    else {
+        char pps[32];
+        itoa(getpid(), pps, 10);
+        SetEnvironmentVariable(TCN_PARENT_IDE, pps);
+    }
+#endif
+    rv = apr_proc_create(np, J2S(progname), pargs,
+                         penv, a, p);
+#ifdef WIN32
+    if (!es)
+        SetEnvironmentVariable(TCN_PARENT_IDE, NULL);
+#endif
+
+    /* Free local resources */
+    TCN_FREE_CSTRING(progname);
+    for (i = 0; i < as; i++) {
+        if (s_args[i])
+            free(s_args[i]);
+    }
+    for (i = 0; i < es; i++) {
+        if (s_env[i])
+            free(s_env[i]);
+    }
+    return rv;
+}
+
+TCN_IMPLEMENT_CALL(jint, Proc, wait)(TCN_STDARGS, jlong proc,
+                                     jintArray rvals, jint waithow)
+{
+    apr_status_t rv;
+    apr_proc_t *p = J2P(proc, apr_proc_t *);
+    int exitcode;
+    apr_exit_why_e exitwhy;
+
+    UNREFERENCED(o);
+
+    rv = apr_proc_wait(p, &exitcode, &exitwhy, (apr_wait_how_e)waithow);
+    if (rv == APR_SUCCESS && rvals) {
+        jsize n = (*e)->GetArrayLength(e, rvals);
+        if (n > 1) {
+            jint *ints = (*e)->GetIntArrayElements(e, rvals, NULL);
+            ints[0] = exitcode;
+            ints[1] = exitwhy;
+            (*e)->ReleaseIntArrayElements(e, rvals, ints, 0);
+        }
+    }
+    return rv;
+}
+
+TCN_IMPLEMENT_CALL(jint, Proc, waitAllProcs)(TCN_STDARGS,
+                                             jlong proc, jintArray rvals,
+                                             jint waithow, jlong pool)
+{
+    apr_status_t rv;
+    apr_proc_t *p = J2P(proc, apr_proc_t *);
+    apr_pool_t *c = J2P(pool, apr_pool_t *);
+    int exitcode;
+    apr_exit_why_e exitwhy;
+
+    UNREFERENCED(o);
+
+    rv = apr_proc_wait_all_procs(p, &exitcode, &exitwhy,
+                                 (apr_wait_how_e)waithow, c);
+    if (rv == APR_SUCCESS && rvals) {
+        jsize n = (*e)->GetArrayLength(e, rvals);
+        if (n > 1) {
+            jint *ints = (*e)->GetIntArrayElements(e, rvals, NULL);
+            ints[0] = exitcode;
+            ints[1] = exitwhy;
+            (*e)->ReleaseIntArrayElements(e, rvals, ints, 0);
+        }
+    }
+    return rv;
+}
+
+TCN_IMPLEMENT_CALL(jint, Proc, detach)(TCN_STDARGS, jint daemonize)
+{
+
+    UNREFERENCED_STDARGS;
+#if defined(WIN32) || defined (NETWARE)
+    UNREFERENCED(daemonize);
+    return APR_ENOTIMPL;
+#else
+    return (jint)apr_proc_detach(daemonize);
+#endif
+}
+
+TCN_IMPLEMENT_CALL(jint, Proc, kill)(TCN_STDARGS, jlong proc, jint sig)
+{
+    apr_proc_t *p = J2P(proc, apr_proc_t *);
+
+    UNREFERENCED_STDARGS;
+    return (jint)apr_proc_kill(p, (int)sig);
+}
+
+TCN_IMPLEMENT_CALL(void, Pool, noteSubprocess)(TCN_STDARGS, jlong pool,
+                                               jlong proc, jint how)
+{
+    apr_proc_t *p = J2P(proc, apr_proc_t *);
+    apr_pool_t *a = J2P(pool, apr_pool_t *);
+
+    UNREFERENCED_STDARGS;
+    apr_pool_note_subprocess(a, p, (apr_kill_conditions_e)how);
+}
+
+TCN_IMPLEMENT_CALL(jint, Proc, fork)(TCN_STDARGS,
+                                     jlongArray proc,
+                                     jlong pool)
+{
+    apr_status_t rv = APR_EINVAL;
+
+#if APR_HAS_FORK
+    apr_pool_t *p = J2P(pool, apr_pool_t *);
+    apr_proc_t *f = apr_pcalloc(p, sizeof(apr_proc_t));
+
+    UNREFERENCED(o);
+
+    rv = apr_proc_fork(f, p);
+    if (rv == APR_SUCCESS && proc) {
+        jsize n = (*e)->GetArrayLength(e, proc);
+        if (n > 0) {
+            jlong *rp = (*e)->GetLongArrayElements(e, proc, NULL);
+            rp[0] = P2J(f);
+            (*e)->ReleaseLongArrayElements(e, proc, rp, 0);
+        }
+    }
+#else
+    UNREFERENCED_STDARGS;
+    UNREFERENCED(proc);
+    UNREFERENCED(pool);
+
+#endif
+    return rv;
+}
+
+TCN_IMPLEMENT_CALL(void, Procattr, errfnSet)(TCN_STDARGS, jlong attr,
+                                             jlong pool, jobject obj)
+{
+    apr_procattr_t *a = J2P(attr, apr_procattr_t *);
+    apr_pool_t *p = J2P(pool, apr_pool_t *);
+    tcn_callback_t *cb = (tcn_callback_t *)malloc(sizeof(tcn_callback_t));
+    jclass cls;
+
+    UNREFERENCED(o);
+
+    if (cb == NULL) {
+       return;
+    }
+    cls = (*e)->GetObjectClass(e, obj);
+    cb->obj    = (*e)->NewGlobalRef(e, obj);
+    cb->mid[0] = (*e)->GetMethodID(e, cls, "callback", "(JILjava/lang/String;)V");
+
+    apr_pool_userdata_setn(cb, ERRFN_USERDATA_KEY, child_errfn_pool_cleanup, p);
+    apr_procattr_child_errfn_set(a, generic_child_errfn);
+
+}
+
+TCN_IMPLEMENT_CALL(jint, Procattr, userSet)(TCN_STDARGS,
+                                            jlong attr,
+                                            jstring username,
+                                            jstring password)
+{
+
+#if ((APR_MAJOR_VERSION >= 1) && (APR_MINOR_VERSION >= 1))
+    apr_status_t rv;
+    apr_procattr_t *a = J2P(attr, apr_procattr_t *);
+    TCN_ALLOC_CSTRING(username);
+#if APR_PROCATTR_USER_SET_REQUIRES_PASSWORD
+    TCN_ALLOC_CSTRING(password);
+#else
+    const char *cpassword = NULL;
+#endif
+    UNREFERENCED(o);
+
+    rv = apr_procattr_user_set(a, J2S(username), J2S(password));
+    TCN_FREE_CSTRING(username);
+#if APR_PROCATTR_USER_SET_REQUIRES_PASSWORD
+    TCN_FREE_CSTRING(password);
+#endif
+    return (jint) rv;
+#else
+    UNREFERENCED_STDARGS;
+    UNREFERENCED(attr);
+    UNREFERENCED(username);
+    UNREFERENCED(password);
+
+    return APR_ENOTIMPL;
+#endif
+}
+
+TCN_IMPLEMENT_CALL(jint, Procattr, groupSet)(TCN_STDARGS,
+                                             jlong attr,
+                                             jstring group)
+{
+
+#if ((APR_MAJOR_VERSION >= 1) && (APR_MINOR_VERSION >= 1))
+    apr_status_t rv;
+    apr_procattr_t *a = J2P(attr, apr_procattr_t *);
+    TCN_ALLOC_CSTRING(group);
+
+    UNREFERENCED(o);
+
+    rv = apr_procattr_group_set(a, J2S(group));
+    TCN_FREE_CSTRING(group);
+    return (jint) rv;
+#else
+    UNREFERENCED_STDARGS;
+    UNREFERENCED(attr);
+    UNREFERENCED(group);
+
+    return APR_ENOTIMPL;
+#endif
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/src/shm.c
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/src/shm.c	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/src/shm.c	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,126 @@
+/* Copyright 2000-2005 The Apache Software Foundation
+ *
+ * Licensed 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.
+ */
+
+/*
+ *
+ * @author Mladen Turk
+ * @version $Revision: 300969 $, $Date: 2005-07-12 09:56:11 -0500 (Tue, 12 Jul 2005) $
+ */
+ 
+#include "tcn.h"
+#include "apr_shm.h"
+
+TCN_IMPLEMENT_CALL(jlong, Shm, create)(TCN_STDARGS, jlong reqsize,
+                                       jstring filename,
+                                       jlong pool)
+{
+    apr_pool_t *p = J2P(pool, apr_pool_t *);
+    const char *fname = NULL;
+    apr_shm_t *shm;
+
+
+    UNREFERENCED(o);
+    if (filename)
+        fname = (const char *)((*e)->GetStringUTFChars(e, filename, 0));
+    TCN_THROW_IF_ERR(apr_shm_create(&shm, (apr_size_t)reqsize,
+                                    fname, p), shm);
+
+cleanup:
+    if (fname)
+        (*e)->ReleaseStringUTFChars(e, filename, fname);
+    return P2J(shm);
+}
+
+TCN_IMPLEMENT_CALL(jint, Shm, remove)(TCN_STDARGS,
+                                      jstring filename,
+                                      jlong pool)
+{
+    apr_status_t rv;
+    apr_pool_t *p = J2P(pool, apr_pool_t *);
+    TCN_ALLOC_CSTRING(filename);
+
+
+    UNREFERENCED(o);
+    rv = apr_shm_remove(J2S(filename), p);
+    TCN_FREE_CSTRING(filename);
+
+    return (jint)rv;
+}
+
+TCN_IMPLEMENT_CALL(jint, Shm, destroy)(TCN_STDARGS, jlong shm)
+{
+    apr_shm_t *s = J2P(shm, apr_shm_t *);
+
+    UNREFERENCED_STDARGS;
+    return (jint)apr_shm_destroy(s);
+}
+
+TCN_IMPLEMENT_CALL(jlong, Shm, attach)(TCN_STDARGS,
+                                       jstring filename,
+                                       jlong pool)
+{
+    apr_pool_t *p = J2P(pool, apr_pool_t *);
+    const char *fname = NULL;
+    apr_shm_t *shm;
+
+
+    UNREFERENCED(o);
+    if (filename)
+        fname = (const char *)((*e)->GetStringUTFChars(e, filename, 0));
+    TCN_THROW_IF_ERR(apr_shm_attach(&shm, fname, p), shm);
+
+cleanup:
+    if (fname)
+        (*e)->ReleaseStringUTFChars(e, filename, fname);
+    return P2J(shm);
+}
+
+TCN_IMPLEMENT_CALL(jint, Shm, detach)(TCN_STDARGS, jlong shm)
+{
+    apr_shm_t *s = J2P(shm, apr_shm_t *);
+
+    UNREFERENCED_STDARGS;
+    return (jint)apr_shm_detach(s);
+}
+
+TCN_IMPLEMENT_CALL(jlong, Shm, baseaddr)(TCN_STDARGS, jlong shm)
+{
+    apr_shm_t *s = J2P(shm, apr_shm_t *);
+
+    UNREFERENCED_STDARGS;
+    return P2J(apr_shm_baseaddr_get(s));
+}
+
+TCN_IMPLEMENT_CALL(jlong, Shm, size)(TCN_STDARGS, jlong shm)
+{
+    apr_shm_t *s = J2P(shm, apr_shm_t *);
+
+    UNREFERENCED_STDARGS;
+    return (jlong)apr_shm_size_get(s);
+}
+
+TCN_IMPLEMENT_CALL(jobject, Shm, buffer)(TCN_STDARGS, jlong shm)
+{
+    apr_shm_t *s = J2P(shm, apr_shm_t *);
+    jlong sz = (jlong)apr_shm_size_get(s);
+    void *a;
+
+    UNREFERENCED(o);
+
+    if ((a = apr_shm_baseaddr_get(s)) != NULL)
+        return (*e)->NewDirectByteBuffer(e, a, sz);
+    else
+        return NULL;
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/src/ssl.c
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/src/ssl.c	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/src/ssl.c	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,809 @@
+/* Copyright 2000-2005 The Apache Software Foundation
+ *
+ * Licensed 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.
+ */
+
+/*
+ *
+ * @author Mladen Turk
+ * @version $Revision: 439960 $, $Date: 2006-09-04 02:15:58 -0500 (Mon, 04 Sep 2006) $
+ */
+
+#include "tcn.h"
+#include "apr_file_io.h"
+#include "apr_thread_mutex.h"
+#include "apr_atomic.h"
+#include "apr_poll.h"
+
+#ifdef HAVE_OPENSSL
+#include "ssl_private.h"
+
+static int ssl_initialized = 0;
+static char *ssl_global_rand_file = NULL;
+extern apr_pool_t *tcn_global_pool;
+
+ENGINE *tcn_ssl_engine = NULL;
+void *SSL_temp_keys[SSL_TMP_KEY_MAX];
+tcn_pass_cb_t tcn_password_callback;
+
+/*
+ * Handle the Temporary RSA Keys and DH Params
+ */
+
+#define SSL_TMP_KEY_FREE(type, idx)                     \
+    if (SSL_temp_keys[idx]) {                           \
+        type##_free((type *)SSL_temp_keys[idx]);        \
+        SSL_temp_keys[idx] = NULL;                      \
+    } else (void)(0)
+
+#define SSL_TMP_KEYS_FREE(type) \
+    SSL_TMP_KEY_FREE(type, SSL_TMP_KEY_##type##_512);   \
+    SSL_TMP_KEY_FREE(type, SSL_TMP_KEY_##type##_1024);  \
+    SSL_TMP_KEY_FREE(type, SSL_TMP_KEY_##type##_2048);  \
+    SSL_TMP_KEY_FREE(type, SSL_TMP_KEY_##type##_4096)
+
+#define SSL_TMP_KEY_INIT_RSA(bits) \
+    ssl_tmp_key_init_rsa(bits, SSL_TMP_KEY_RSA_##bits)
+
+#define SSL_TMP_KEY_INIT_DH(bits)  \
+    ssl_tmp_key_init_dh(bits, SSL_TMP_KEY_DH_##bits)
+
+#define SSL_TMP_KEYS_INIT(R)                    \
+    SSL_temp_keys[SSL_TMP_KEY_RSA_2048] = NULL; \
+    SSL_temp_keys[SSL_TMP_KEY_RSA_4096] = NULL; \
+    R |= SSL_TMP_KEY_INIT_RSA(512);             \
+    R |= SSL_TMP_KEY_INIT_RSA(1024);            \
+    R |= SSL_TMP_KEY_INIT_DH(512);              \
+    R |= SSL_TMP_KEY_INIT_DH(1024);             \
+    R |= SSL_TMP_KEY_INIT_DH(2048);             \
+    R |= SSL_TMP_KEY_INIT_DH(4096)
+
+static int ssl_tmp_key_init_rsa(int bits, int idx)
+{
+    if (!(SSL_temp_keys[idx] =
+          RSA_generate_key(bits, RSA_F4, NULL, NULL)))
+        return 1;
+    else
+        return 0;
+}
+
+static int ssl_tmp_key_init_dh(int bits, int idx)
+{
+    if (!(SSL_temp_keys[idx] =
+          SSL_dh_get_tmp_param(bits)))
+        return 1;
+    else
+        return 0;
+}
+
+
+TCN_IMPLEMENT_CALL(jint, SSL, version)(TCN_STDARGS)
+{
+    UNREFERENCED_STDARGS;
+    return OPENSSL_VERSION_NUMBER;
+}
+
+TCN_IMPLEMENT_CALL(jstring, SSL, versionString)(TCN_STDARGS)
+{
+    UNREFERENCED(o);
+    return AJP_TO_JSTRING(OPENSSL_VERSION_TEXT);
+}
+
+/*
+ *  the various processing hooks
+ */
+static apr_status_t ssl_init_cleanup(void *data)
+{
+    UNREFERENCED(data);
+
+    if (!ssl_initialized)
+        return APR_SUCCESS;
+    ssl_initialized = 0;
+
+    if (tcn_password_callback.cb.obj) {
+        JNIEnv *env;
+        tcn_get_java_env(&env);
+        TCN_UNLOAD_CLASS(env,
+                         tcn_password_callback.cb.obj);
+    }
+
+    SSL_TMP_KEYS_FREE(RSA);
+    SSL_TMP_KEYS_FREE(DH);
+    /*
+     * Try to kill the internals of the SSL library.
+     */
+#if OPENSSL_VERSION_NUMBER >= 0x00907001
+    /* Corresponds to OPENSSL_load_builtin_modules():
+     * XXX: borrowed from apps.h, but why not CONF_modules_free()
+     * which also invokes CONF_modules_finish()?
+     */
+    CONF_modules_unload(1);
+#endif
+    /* Corresponds to SSL_library_init: */
+    EVP_cleanup();
+#if HAVE_ENGINE_LOAD_BUILTIN_ENGINES
+    ENGINE_cleanup();
+#endif
+#if OPENSSL_VERSION_NUMBER >= 0x00907001
+    CRYPTO_cleanup_all_ex_data();
+#endif
+    ERR_remove_state(0);
+
+    /* Don't call ERR_free_strings here; ERR_load_*_strings only
+     * actually load the error strings once per process due to static
+     * variable abuse in OpenSSL. */
+
+    /*
+     * TODO: determine somewhere we can safely shove out diagnostics
+     *       (when enabled) at this late stage in the game:
+     * CRYPTO_mem_leaks_fp(stderr);
+     */
+    return APR_SUCCESS;
+}
+
+#ifndef OPENSSL_NO_ENGINE
+/* Try to load an engine in a shareable library */
+static ENGINE *ssl_try_load_engine(const char *engine)
+{
+    ENGINE *e = ENGINE_by_id("dynamic");
+    if (e) {
+        if (!ENGINE_ctrl_cmd_string(e, "SO_PATH", engine, 0)
+            || !ENGINE_ctrl_cmd_string(e, "LOAD", NULL, 0)) {
+            ENGINE_free(e);
+            e = NULL;
+        }
+    }
+    return e;
+}
+#endif
+
+/*
+ * To ensure thread-safetyness in OpenSSL
+ */
+
+static apr_thread_mutex_t **ssl_lock_cs;
+static int                  ssl_lock_num_locks;
+
+static void ssl_thread_lock(int mode, int type,
+                            const char *file, int line)
+{
+    UNREFERENCED(file);
+    UNREFERENCED(line);
+    if (type < ssl_lock_num_locks) {
+        if (mode & CRYPTO_LOCK) {
+            apr_thread_mutex_lock(ssl_lock_cs[type]);
+        }
+        else {
+            apr_thread_mutex_unlock(ssl_lock_cs[type]);
+        }
+    }
+}
+
+static unsigned long ssl_thread_id(void)
+{
+    /* OpenSSL needs this to return an unsigned long.  On OS/390, the pthread
+     * id is a structure twice that big.  Use the TCB pointer instead as a
+     * unique unsigned long.
+     */
+#ifdef __MVS__
+    struct PSA {
+        char unmapped[540];
+        unsigned long PSATOLD;
+    } *psaptr = 0;
+
+    return psaptr->PSATOLD;
+#else
+    return (unsigned long)(apr_os_thread_current());
+#endif
+}
+
+static apr_status_t ssl_thread_cleanup(void *data)
+{
+    UNREFERENCED(data);
+    CRYPTO_set_locking_callback(NULL);
+    CRYPTO_set_id_callback(NULL);
+    /* Let the registered mutex cleanups do their own thing
+     */
+    return APR_SUCCESS;
+}
+
+static void ssl_thread_setup(apr_pool_t *p)
+{
+    int i;
+
+    ssl_lock_num_locks = CRYPTO_num_locks();
+    ssl_lock_cs = apr_palloc(p, ssl_lock_num_locks * sizeof(*ssl_lock_cs));
+
+    for (i = 0; i < ssl_lock_num_locks; i++) {
+        apr_thread_mutex_create(&(ssl_lock_cs[i]),
+                                APR_THREAD_MUTEX_DEFAULT, p);
+    }
+
+    CRYPTO_set_id_callback(ssl_thread_id);
+    CRYPTO_set_locking_callback(ssl_thread_lock);
+
+    apr_pool_cleanup_register(p, NULL, ssl_thread_cleanup,
+                              apr_pool_cleanup_null);
+}
+
+static int ssl_rand_choosenum(int l, int h)
+{
+    int i;
+    char buf[50];
+
+    apr_snprintf(buf, sizeof(buf), "%.0f",
+                 (((double)(rand()%RAND_MAX)/RAND_MAX)*(h-l)));
+    i = atoi(buf)+1;
+    if (i < l) i = l;
+    if (i > h) i = h;
+    return i;
+}
+
+static int ssl_rand_load_file(const char *file)
+{
+    char buffer[APR_PATH_MAX];
+    int n;
+
+    if (file == NULL)
+        file = ssl_global_rand_file;
+
+    if (file == NULL)
+        file = RAND_file_name(buffer, sizeof(buffer));
+    else if ((n = RAND_egd(file)) > 0) {
+        return n;
+    }
+    if (file && (n = RAND_load_file(file, -1)) > 0)
+        return n;
+    else
+        return -1;
+}
+
+/*
+ * writes a number of random bytes (currently 1024) to
+ * file which can be used to initialize the PRNG by calling
+ * RAND_load_file() in a later session
+ */
+static int ssl_rand_save_file(const char *file)
+{
+    char buffer[APR_PATH_MAX];
+    int n;
+
+    if (file == NULL)
+        file = RAND_file_name(buffer, sizeof(buffer));
+    else if ((n = RAND_egd(file)) > 0) {
+        return 0;
+    }
+    if (file == NULL || !RAND_write_file(file))
+        return 0;
+    else
+        return 1;
+}
+
+int SSL_rand_seed(const char *file)
+{
+    unsigned char stackdata[256];
+    static volatile apr_uint32_t counter = 0;
+
+    if (ssl_rand_load_file(file) < 0) {
+        int n;
+        struct {
+            apr_time_t    t;
+            pid_t         p;
+            unsigned long i;
+            apr_uint32_t  u;
+        } _ssl_seed;
+        if (counter == 0) {
+            apr_generate_random_bytes(stackdata, 256);
+            RAND_seed(stackdata, 128);
+        }
+        _ssl_seed.t = apr_time_now();
+        _ssl_seed.p = getpid();
+        _ssl_seed.i = ssl_thread_id();
+        apr_atomic_inc32(&counter);
+        _ssl_seed.u = counter;
+        RAND_seed((unsigned char *)&_ssl_seed, sizeof(_ssl_seed));
+        /*
+         * seed in some current state of the run-time stack (128 bytes)
+         */
+        n = ssl_rand_choosenum(0, sizeof(stackdata)-128-1);
+        RAND_seed(stackdata + n, 128);
+    }
+    return RAND_status();
+}
+
+static int ssl_rand_make(const char *file, int len, int base64)
+{
+    int r;
+    int num = len;
+    BIO *out = NULL;
+
+    out = BIO_new(BIO_s_file());
+    if (out == NULL)
+        return 0;
+    if ((r = BIO_write_filename(out, (char *)file)) < 0) {
+        BIO_free_all(out);
+        return 0;
+    }
+    if (base64) {
+        BIO *b64 = BIO_new(BIO_f_base64());
+        if (b64 == NULL) {
+            BIO_free_all(out);
+            return 0;
+        }
+        out = BIO_push(b64, out);
+    }
+    while (num > 0) {
+        unsigned char buf[4096];
+        int len = num;
+        if (len > sizeof(buf))
+            len = sizeof(buf);
+        r = RAND_bytes(buf, len);
+        if (r <= 0) {
+            BIO_free_all(out);
+            return 0;
+        }
+        BIO_write(out, buf, len);
+        num -= len;
+    }
+    BIO_flush(out);
+    BIO_free_all(out);
+    return 1;
+}
+
+TCN_IMPLEMENT_CALL(jint, SSL, initialize)(TCN_STDARGS, jstring engine)
+{
+    int r = 0;
+    TCN_ALLOC_CSTRING(engine);
+
+    UNREFERENCED(o);
+    if (!tcn_global_pool) {
+        TCN_FREE_CSTRING(engine);
+        return (jint)APR_EINVAL;
+    }
+    /* Check if already initialized */
+    if (ssl_initialized++) {
+        TCN_FREE_CSTRING(engine);
+        return (jint)APR_SUCCESS;
+    }
+    if (SSLeay() < 0x0090700L) {
+        TCN_FREE_CSTRING(engine);
+        return (jint)APR_EINVAL;
+    }
+    /* We must register the library in full, to ensure our configuration
+     * code can successfully test the SSL environment.
+     */
+    CRYPTO_malloc_init();
+    ERR_load_crypto_strings();
+    SSL_load_error_strings();
+    SSL_library_init();
+#if HAVE_ENGINE_LOAD_BUILTIN_ENGINES
+    ENGINE_load_builtin_engines();
+#endif
+#if OPENSSL_VERSION_NUMBER >= 0x00907001
+    OPENSSL_load_builtin_modules();
+#endif
+
+#ifndef OPENSSL_NO_ENGINE
+    if (J2S(engine)) {
+        ENGINE *ee = NULL;
+        apr_status_t err = APR_SUCCESS;
+        if(strcmp(J2S(engine), "auto") == 0) {
+            ENGINE_register_all_complete();
+        }
+        else {
+            if ((ee = ENGINE_by_id(J2S(engine))) == NULL
+                && (ee = ssl_try_load_engine(J2S(engine))) == NULL)
+                err = APR_ENOTIMPL;
+            else {
+                if (strcmp(J2S(engine), "chil") == 0)
+                    ENGINE_ctrl(ee, ENGINE_CTRL_CHIL_SET_FORKCHECK, 1, 0, 0);
+                if (!ENGINE_set_default(ee, ENGINE_METHOD_ALL))
+                    err = APR_ENOTIMPL;
+            }
+            /* Free our "structural" reference. */
+            if (ee)
+                ENGINE_free(ee);
+        }
+        if (err != APR_SUCCESS) {
+            TCN_FREE_CSTRING(engine);
+            ssl_init_cleanup(NULL);
+            return (jint)err;
+        }
+        tcn_ssl_engine = ee;
+    }
+#endif
+
+    memset(&tcn_password_callback, 0, sizeof(tcn_pass_cb_t));
+    /* Initialize PRNG
+     * This will in most cases call the builtin
+     * low entropy seed.
+     */
+    SSL_rand_seed(NULL);
+    /* For SSL_get_app_data2() at request time */
+    SSL_init_app_data2_idx();
+
+    SSL_TMP_KEYS_INIT(r);
+    if (r) {
+        TCN_FREE_CSTRING(engine);
+        ssl_init_cleanup(NULL);
+        return APR_ENOTIMPL;
+    }
+    /*
+     * Let us cleanup the ssl library when the library is unloaded
+     */
+    apr_pool_cleanup_register(tcn_global_pool, NULL,
+                              ssl_init_cleanup,
+                              apr_pool_cleanup_null);
+    /* Initialize thread support */
+    ssl_thread_setup(tcn_global_pool);
+    TCN_FREE_CSTRING(engine);
+    return (jint)APR_SUCCESS;
+}
+
+TCN_IMPLEMENT_CALL(jboolean, SSL, randLoad)(TCN_STDARGS, jstring file)
+{
+    TCN_ALLOC_CSTRING(file);
+    int r;
+    UNREFERENCED(o);
+    r = SSL_rand_seed(J2S(file));
+    TCN_FREE_CSTRING(file);
+    return r ? JNI_TRUE : JNI_FALSE;
+}
+
+TCN_IMPLEMENT_CALL(jboolean, SSL, randSave)(TCN_STDARGS, jstring file)
+{
+    TCN_ALLOC_CSTRING(file);
+    int r;
+    UNREFERENCED(o);
+    r = ssl_rand_save_file(J2S(file));
+    TCN_FREE_CSTRING(file);
+    return r ? JNI_TRUE : JNI_FALSE;
+}
+
+TCN_IMPLEMENT_CALL(jboolean, SSL, randMake)(TCN_STDARGS, jstring file,
+                                            jint length, jboolean base64)
+{
+    TCN_ALLOC_CSTRING(file);
+    int r;
+    UNREFERENCED(o);
+    r = ssl_rand_make(J2S(file), length, base64);
+    TCN_FREE_CSTRING(file);
+    return r ? JNI_TRUE : JNI_FALSE;
+}
+
+TCN_IMPLEMENT_CALL(void, SSL, randSet)(TCN_STDARGS, jstring file)
+{
+    TCN_ALLOC_CSTRING(file);
+    UNREFERENCED(o);
+    if (J2S(file)) {
+        ssl_global_rand_file = apr_pstrdup(tcn_global_pool, J2S(file));        
+    }
+    TCN_FREE_CSTRING(file);
+}
+/* OpenSSL Java Stream BIO */
+
+typedef struct  {
+    int            refcount;
+    apr_pool_t     *pool;
+    tcn_callback_t cb;
+} BIO_JAVA;
+
+
+static apr_status_t generic_bio_cleanup(void *data)
+{
+    BIO *b = (BIO *)data;
+
+    if (b) {
+        BIO_free(b);
+    }
+    return APR_SUCCESS;
+}
+
+void SSL_BIO_close(BIO *bi)
+{
+    if (bi == NULL)
+        return;
+    if (bi->ptr != NULL && (bi->flags & SSL_BIO_FLAG_CALLBACK)) {
+        BIO_JAVA *j = (BIO_JAVA *)bi->ptr;
+        j->refcount--;
+        if (j->refcount == 0) {
+            if (j->pool)
+                apr_pool_cleanup_run(j->pool, bi, generic_bio_cleanup);
+            else
+                BIO_free(bi);
+        }
+    }
+    else
+        BIO_free(bi);
+}
+
+void SSL_BIO_doref(BIO *bi)
+{
+    if (bi == NULL)
+        return;
+    if (bi->ptr != NULL && (bi->flags & SSL_BIO_FLAG_CALLBACK)) {
+        BIO_JAVA *j = (BIO_JAVA *)bi->ptr;
+        j->refcount++;
+    }
+}
+
+
+static int jbs_new(BIO *bi)
+{
+    BIO_JAVA *j;
+
+    if ((j = OPENSSL_malloc(sizeof(BIO_JAVA))) == NULL)
+        return 0;
+    j->pool      = NULL;
+    j->refcount  = 1;
+    bi->shutdown = 1;
+    bi->init     = 0;
+    bi->num      = -1;
+    bi->ptr      = (char *)j;
+
+    return 1;
+}
+
+static int jbs_free(BIO *bi)
+{
+    if (bi == NULL)
+        return 0;
+    if (bi->ptr != NULL) {
+        BIO_JAVA *j = (BIO_JAVA *)bi->ptr;
+        if (bi->init) {
+            JNIEnv   *e = NULL;
+            bi->init = 0;
+            tcn_get_java_env(&e);            
+            TCN_UNLOAD_CLASS(e, j->cb.obj);
+        }
+        OPENSSL_free(bi->ptr);
+    }
+    bi->ptr = NULL;
+    return 1;
+}
+
+static int jbs_write(BIO *b, const char *in, int inl)
+{
+    jint ret = 0;
+    if (b->init && in != NULL) {
+        BIO_JAVA *j = (BIO_JAVA *)b->ptr;
+        JNIEnv   *e = NULL;
+        jbyteArray jb = (*e)->NewByteArray(e, inl);
+        tcn_get_java_env(&e);
+        if (!(*e)->ExceptionOccurred(e)) {
+            (*e)->SetByteArrayRegion(e, jb, 0, inl, (jbyte *)in);
+            ret = (*e)->CallIntMethod(e, j->cb.obj,
+                                      j->cb.mid[0], jb);
+            (*e)->ReleaseByteArrayElements(e, jb, (jbyte *)in, JNI_ABORT);
+            (*e)->DeleteLocalRef(e, jb);
+        }
+    }
+    return ret;
+}
+
+static int jbs_read(BIO *b, char *out, int outl)
+{
+    jint ret = 0;
+    if (b->init && out != NULL) {
+        BIO_JAVA *j = (BIO_JAVA *)b->ptr;
+        JNIEnv   *e = NULL;
+        jbyteArray jb = (*e)->NewByteArray(e, outl);
+        tcn_get_java_env(&e);
+        if (!(*e)->ExceptionOccurred(e)) {
+            ret = (*e)->CallIntMethod(e, j->cb.obj,
+                                      j->cb.mid[1], jb);
+            if (ret > 0) {
+                jbyte *jout = (*e)->GetPrimitiveArrayCritical(e, jb, NULL);
+                memcpy(out, jout, ret);
+                (*e)->ReleasePrimitiveArrayCritical(e, jb, jout, 0);
+            }
+            (*e)->DeleteLocalRef(e, jb);
+        }
+    }
+    return ret;
+}
+
+static int jbs_puts(BIO *b, const char *in)
+{
+    int ret = 0;
+    if (b->init && in != NULL) {
+        BIO_JAVA *j = (BIO_JAVA *)b->ptr;
+        JNIEnv   *e = NULL;
+        tcn_get_java_env(&e);        
+        ret = (*e)->CallIntMethod(e, j->cb.obj,
+                                  j->cb.mid[2],
+                                  tcn_new_string(e, in));
+    }
+    return ret;
+}
+
+static int jbs_gets(BIO *b, char *out, int outl)
+{
+    int ret = 0;
+    if (b->init && out != NULL) {
+        BIO_JAVA *j = (BIO_JAVA *)b->ptr;
+        JNIEnv   *e = NULL;
+        jobject  o;
+        tcn_get_java_env(&e);
+        if ((o = (*e)->CallObjectMethod(e, j->cb.obj,
+                            j->cb.mid[3], (jint)(outl - 1)))) {
+            TCN_ALLOC_CSTRING(o);
+            if (J2S(o)) {
+                int l = (int)strlen(J2S(o));
+                if (l < outl) {
+                    strcpy(out, J2S(o));
+                    ret = outl;
+                }
+            }
+            TCN_FREE_CSTRING(o);
+        }
+    }
+    return ret;
+}
+
+static long jbs_ctrl(BIO *b, int cmd, long num, void *ptr)
+{
+    return 0;
+}
+
+static BIO_METHOD jbs_methods = {
+    BIO_TYPE_FILE,
+    "Java Callback",
+    jbs_write,
+    jbs_read,
+    jbs_puts,
+    jbs_gets,
+    jbs_ctrl,
+    jbs_new,
+    jbs_free,
+    NULL
+};
+
+static BIO_METHOD *BIO_jbs()
+{
+    return(&jbs_methods);
+}
+
+TCN_IMPLEMENT_CALL(jlong, SSL, newBIO)(TCN_STDARGS, jlong pool,
+                                       jobject callback)
+{
+    BIO *bio = NULL;
+    BIO_JAVA *j;
+    jclass cls;
+
+    UNREFERENCED(o);
+
+    if ((bio = BIO_new(BIO_jbs())) == NULL) {
+        tcn_ThrowException(e, "Create BIO failed");
+        goto init_failed;
+    }
+    j = (BIO_JAVA *)bio->ptr;
+    if ((j = (BIO_JAVA *)bio->ptr) == NULL) {
+        tcn_ThrowException(e, "Create BIO failed");
+        goto init_failed;
+    }
+    j->pool = J2P(pool, apr_pool_t *);
+    if (j->pool) {
+        apr_pool_cleanup_register(j->pool, (const void *)bio,
+                                  generic_bio_cleanup,
+                                  apr_pool_cleanup_null);
+    }
+
+    cls = (*e)->GetObjectClass(e, callback);
+    j->cb.mid[0] = (*e)->GetMethodID(e, cls, "write", "([B)I");
+    j->cb.mid[1] = (*e)->GetMethodID(e, cls, "read",  "([B)I");
+    j->cb.mid[2] = (*e)->GetMethodID(e, cls, "puts",  "(Ljava/lang/String;)I");
+    j->cb.mid[3] = (*e)->GetMethodID(e, cls, "gets",  "(I)Ljava/lang/String;");
+    /* TODO: Check if method id's are valid */
+    j->cb.obj    = (*e)->NewGlobalRef(e, callback);
+
+    bio->init  = 1;
+    bio->flags = SSL_BIO_FLAG_CALLBACK;
+    return P2J(bio);
+init_failed:
+    return 0;
+}
+
+TCN_IMPLEMENT_CALL(jint, SSL, closeBIO)(TCN_STDARGS, jlong bio)
+{
+    BIO *b = J2P(bio, BIO *);
+    UNREFERENCED_STDARGS;
+    SSL_BIO_close(b);
+    return APR_SUCCESS;
+}
+
+TCN_IMPLEMENT_CALL(void, SSL, setPasswordCallback)(TCN_STDARGS,
+                                                   jobject callback)
+{
+    jclass cls;
+
+    UNREFERENCED(o);
+    if (tcn_password_callback.cb.obj) {
+        TCN_UNLOAD_CLASS(e,
+                         tcn_password_callback.cb.obj);
+    }
+    cls = (*e)->GetObjectClass(e, callback);
+    tcn_password_callback.cb.mid[0] = (*e)->GetMethodID(e, cls, "callback",
+                           "(Ljava/lang/String;)Ljava/lang/String;");
+    /* TODO: Check if method id is valid */
+    tcn_password_callback.cb.obj    = (*e)->NewGlobalRef(e, callback);
+
+}
+
+TCN_IMPLEMENT_CALL(void, SSL, setPassword)(TCN_STDARGS, jstring password)
+{
+    TCN_ALLOC_CSTRING(password);
+    UNREFERENCED(o);
+    if (J2S(password)) {
+        strncpy(tcn_password_callback.password, J2S(password), SSL_MAX_PASSWORD_LEN);
+        tcn_password_callback.password[SSL_MAX_PASSWORD_LEN-1] = '\0';
+    }
+    TCN_FREE_CSTRING(password);
+}
+
+TCN_IMPLEMENT_CALL(jboolean, SSL, generateRSATempKey)(TCN_STDARGS, jint idx)
+{
+    int r = 1;
+    UNREFERENCED_STDARGS;
+    SSL_TMP_KEY_FREE(RSA, idx);
+    switch (idx) {
+        case SSL_TMP_KEY_RSA_512:
+            r = SSL_TMP_KEY_INIT_RSA(512);
+        break;
+        case SSL_TMP_KEY_RSA_1024:
+            r = SSL_TMP_KEY_INIT_RSA(1024);
+        break;
+        case SSL_TMP_KEY_RSA_2048:
+            r = SSL_TMP_KEY_INIT_RSA(2048);
+        break;
+        case SSL_TMP_KEY_RSA_4096:
+            r = SSL_TMP_KEY_INIT_RSA(4096);
+        break;
+    }
+    return r ? JNI_FALSE : JNI_TRUE;
+}
+
+TCN_IMPLEMENT_CALL(jboolean, SSL, loadDSATempKey)(TCN_STDARGS, jint idx,
+                                                  jstring file)
+{
+    jboolean r = JNI_FALSE;
+    TCN_ALLOC_CSTRING(file);
+    DH *dh;
+    UNREFERENCED(o);
+
+    if (!J2S(file))
+        return JNI_FALSE;
+    SSL_TMP_KEY_FREE(DSA, idx);
+    if ((dh = SSL_dh_get_param_from_file(J2S(file)))) {
+        SSL_temp_keys[idx] = dh;
+        r = JNI_TRUE;
+    }
+    TCN_FREE_CSTRING(file);
+    return r;
+}
+
+TCN_IMPLEMENT_CALL(jstring, SSL, getLastError)(TCN_STDARGS)
+{
+    char buf[256];
+    UNREFERENCED(o);
+    ERR_error_string(ERR_get_error(), buf);
+    return tcn_new_string(e, buf);
+}
+
+#else
+/* OpenSSL is not supported
+ * If someday we make OpenSSL optional
+ * APR_ENOTIMPL will go here
+ */
+#error "No OpenSSL Toolkit defined."
+#endif

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/src/sslcontext.c
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/src/sslcontext.c	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/src/sslcontext.c	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,571 @@
+/* Copyright 2000-2005 The Apache Software Foundation
+ *
+ * Licensed 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.
+ */
+
+/** SSL Context wrapper
+ *
+ * @author Mladen Turk
+ * @version $Revision: 300969 $, $Date: 2005-07-12 09:56:11 -0500 (Tue, 12 Jul 2005) $
+ */
+
+#include "tcn.h"
+
+#include "apr_file_io.h"
+#include "apr_thread_mutex.h"
+#include "apr_poll.h"
+
+#ifdef HAVE_OPENSSL
+#include "ssl_private.h"
+
+static apr_status_t ssl_context_cleanup(void *data)
+{
+    tcn_ssl_ctxt_t *c = (tcn_ssl_ctxt_t *)data;
+    if (c) {
+        int i;
+        if (c->crl)
+            X509_STORE_free(c->crl);
+        c->crl = NULL;
+        if (c->ctx)
+            SSL_CTX_free(c->ctx);
+        c->ctx = NULL;
+        for (i = 0; i < SSL_AIDX_MAX; i++) {
+            if (c->certs[i]) {
+                X509_free(c->certs[i]);
+                c->certs[i] = NULL;
+            }
+            if (c->keys[i]) {
+                EVP_PKEY_free(c->keys[i]);
+                c->keys[i] = NULL;
+            }
+        }
+        if (c->bio_is) {
+            SSL_BIO_close(c->bio_is);
+            c->bio_is = NULL;
+        }
+        if (c->bio_os) {
+            SSL_BIO_close(c->bio_os);
+            c->bio_os = NULL;
+        }
+    }
+    return APR_SUCCESS;
+}
+
+/* Initialize server context */
+TCN_IMPLEMENT_CALL(jlong, SSLContext, make)(TCN_STDARGS, jlong pool,
+                                            jint protocol, jint mode)
+{
+    apr_pool_t *p = J2P(pool, apr_pool_t *);
+    tcn_ssl_ctxt_t *c = NULL;
+    SSL_CTX *ctx = NULL;
+    UNREFERENCED(o);
+
+    switch (protocol) {
+        case SSL_PROTOCOL_SSLV2:
+        case SSL_PROTOCOL_SSLV2 | SSL_PROTOCOL_TLSV1:
+            if (mode == SSL_MODE_CLIENT)
+                ctx = SSL_CTX_new(SSLv2_client_method());
+            else if (mode == SSL_MODE_SERVER)
+                ctx = SSL_CTX_new(SSLv2_server_method());
+            else
+                ctx = SSL_CTX_new(SSLv2_method());
+        break;
+        case SSL_PROTOCOL_SSLV3:
+        case SSL_PROTOCOL_SSLV3 | SSL_PROTOCOL_TLSV1:
+            if (mode == SSL_MODE_CLIENT)
+                ctx = SSL_CTX_new(SSLv3_client_method());
+            else if (mode == SSL_MODE_SERVER)
+                ctx = SSL_CTX_new(SSLv3_server_method());
+            else
+                ctx = SSL_CTX_new(SSLv3_method());
+        break;
+        case SSL_PROTOCOL_SSLV2 | SSL_PROTOCOL_SSLV3:
+        case SSL_PROTOCOL_ALL:
+            if (mode == SSL_MODE_CLIENT)
+                ctx = SSL_CTX_new(SSLv23_client_method());
+            else if (mode == SSL_MODE_SERVER)
+                ctx = SSL_CTX_new(SSLv23_server_method());
+            else
+                ctx = SSL_CTX_new(SSLv23_method());
+        break;
+        case SSL_PROTOCOL_TLSV1:
+            if (mode == SSL_MODE_CLIENT)
+                ctx = SSL_CTX_new(TLSv1_client_method());
+            else if (mode == SSL_MODE_SERVER)
+                ctx = SSL_CTX_new(TLSv1_server_method());
+            else
+                ctx = SSL_CTX_new(TLSv1_method());
+        break;
+    }
+    if (!ctx) {
+        tcn_ThrowException(e, "Invalid Server SSL Protocol");
+        goto init_failed;
+    }
+    if ((c = apr_pcalloc(p, sizeof(tcn_ssl_ctxt_t))) == NULL) {
+        tcn_ThrowAPRException(e, apr_get_os_error());
+        goto init_failed;
+    }
+
+    c->protocol = protocol;
+    c->mode     = mode;
+    c->ctx      = ctx;
+    c->pool     = p;
+    c->bio_os   = BIO_new(BIO_s_file());
+    if (c->bio_os != NULL)
+        BIO_set_fp(c->bio_os, stderr, BIO_NOCLOSE | BIO_FP_TEXT);
+    SSL_CTX_set_options(c->ctx, SSL_OP_ALL);
+    if (!(protocol & SSL_PROTOCOL_SSLV2))
+        SSL_CTX_set_options(c->ctx, SSL_OP_NO_SSLv2);
+    if (!(protocol & SSL_PROTOCOL_SSLV3))
+        SSL_CTX_set_options(c->ctx, SSL_OP_NO_SSLv3);
+    if (!(protocol & SSL_PROTOCOL_TLSV1))
+        SSL_CTX_set_options(c->ctx, SSL_OP_NO_TLSv1);
+    /*
+     * Configure additional context ingredients
+     */
+    SSL_CTX_set_options(c->ctx, SSL_OP_SINGLE_DH_USE);
+
+#ifdef SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION
+    /*
+     * Disallow a session from being resumed during a renegotiation,
+     * so that an acceptable cipher suite can be negotiated.
+     */
+    SSL_CTX_set_options(c->ctx, SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION);
+#endif
+    /* Default session context id and cache size */
+    SSL_CTX_sess_set_cache_size(c->ctx, SSL_DEFAULT_CACHE_SIZE);
+    MD5((const unsigned char *)SSL_DEFAULT_VHOST_NAME,
+        (unsigned long)(sizeof(SSL_DEFAULT_VHOST_NAME) - 1),
+        &(c->context_id[0]));
+    if (mode) {
+        SSL_CTX_set_tmp_rsa_callback(c->ctx, SSL_callback_tmp_RSA);
+        SSL_CTX_set_tmp_dh_callback(c->ctx,  SSL_callback_tmp_DH);
+    }
+    /* Set default Certificate verification level
+     * and depth for the Client Authentication
+     */
+    c->verify_depth  = 1;
+    c->verify_mode   = SSL_CVERIFY_UNSET;
+    c->shutdown_type = SSL_SHUTDOWN_TYPE_UNSET;
+
+    /* Set default password callback */
+    SSL_CTX_set_default_passwd_cb(c->ctx, (pem_password_cb *)SSL_password_callback);
+    SSL_CTX_set_default_passwd_cb_userdata(c->ctx, (void *)(&tcn_password_callback));
+    /*
+     * Let us cleanup the ssl context when the pool is destroyed
+     */
+    apr_pool_cleanup_register(p, (const void *)c,
+                              ssl_context_cleanup,
+                              apr_pool_cleanup_null);
+
+    return P2J(c);
+init_failed:
+    return 0;
+}
+
+TCN_IMPLEMENT_CALL(jint, SSLContext, free)(TCN_STDARGS, jlong ctx)
+{
+    tcn_ssl_ctxt_t *c = J2P(ctx, tcn_ssl_ctxt_t *);
+    UNREFERENCED_STDARGS;
+    TCN_ASSERT(ctx != 0);
+    /* Run and destroy the cleanup callback */
+    return apr_pool_cleanup_run(c->pool, c, ssl_context_cleanup);
+}
+
+TCN_IMPLEMENT_CALL(void, SSLContext, setContextId)(TCN_STDARGS, jlong ctx,
+                                                   jstring id)
+{
+    tcn_ssl_ctxt_t *c = J2P(ctx, tcn_ssl_ctxt_t *);
+    TCN_ALLOC_CSTRING(id);
+
+    TCN_ASSERT(ctx != 0);
+    UNREFERENCED(o);
+    if (J2S(id)) {
+        MD5((const unsigned char *)J2S(id),
+            (unsigned long)strlen(J2S(id)),
+            &(c->context_id[0]));
+    }
+    TCN_FREE_CSTRING(id);
+}
+
+TCN_IMPLEMENT_CALL(void, SSLContext, setBIO)(TCN_STDARGS, jlong ctx,
+                                             jlong bio, jint dir)
+{
+    tcn_ssl_ctxt_t *c = J2P(ctx, tcn_ssl_ctxt_t *);
+    BIO *bio_handle   = J2P(bio, BIO *);
+
+    UNREFERENCED_STDARGS;
+    TCN_ASSERT(ctx != 0);
+    if (dir == 0) {
+        if (c->bio_os && c->bio_os != bio_handle)
+            SSL_BIO_close(c->bio_os);
+        c->bio_os = bio_handle;
+    }
+    else if (dir == 1) {
+        if (c->bio_is && c->bio_is != bio_handle)
+            SSL_BIO_close(c->bio_is);
+        c->bio_is = bio_handle;
+    }
+    else
+        return;
+    SSL_BIO_doref(bio_handle);
+}
+
+TCN_IMPLEMENT_CALL(void, SSLContext, setOptions)(TCN_STDARGS, jlong ctx,
+                                                 jint opt)
+{
+    tcn_ssl_ctxt_t *c = J2P(ctx, tcn_ssl_ctxt_t *);
+
+    UNREFERENCED_STDARGS;
+    TCN_ASSERT(ctx != 0);
+    SSL_CTX_set_options(c->ctx, opt);
+}
+
+TCN_IMPLEMENT_CALL(void, SSLContext, setQuietShutdown)(TCN_STDARGS, jlong ctx,
+                                                       jboolean mode)
+{
+    tcn_ssl_ctxt_t *c = J2P(ctx, tcn_ssl_ctxt_t *);
+
+    UNREFERENCED_STDARGS;
+    TCN_ASSERT(ctx != 0);
+    SSL_CTX_set_quiet_shutdown(c->ctx, mode ? 1 : 0);
+}
+
+TCN_IMPLEMENT_CALL(jboolean, SSLContext, setCipherSuite)(TCN_STDARGS, jlong ctx,
+                                                         jstring ciphers)
+{
+    tcn_ssl_ctxt_t *c = J2P(ctx, tcn_ssl_ctxt_t *);
+    TCN_ALLOC_CSTRING(ciphers);
+    jboolean rv = JNI_TRUE;
+
+    UNREFERENCED(o);
+    TCN_ASSERT(ctx != 0);
+    if (!J2S(ciphers))
+        return JNI_FALSE;
+
+    if (!SSL_CTX_set_cipher_list(c->ctx, J2S(ciphers))) {
+        char err[256];
+        ERR_error_string(ERR_get_error(), err);
+        tcn_Throw(e, "Unable to configure permitted SSL ciphers (%s)", err);
+        rv = JNI_FALSE;
+    }
+    TCN_FREE_CSTRING(ciphers);
+    return rv;
+}
+
+TCN_IMPLEMENT_CALL(jboolean, SSLContext, setCARevocation)(TCN_STDARGS, jlong ctx,
+                                                          jstring file,
+                                                          jstring path)
+{
+    tcn_ssl_ctxt_t *c = J2P(ctx, tcn_ssl_ctxt_t *);
+    TCN_ALLOC_CSTRING(file);
+    TCN_ALLOC_CSTRING(path);
+    jboolean rv = JNI_FALSE;
+    X509_LOOKUP *lookup;
+    char err[256];
+
+    UNREFERENCED(o);
+    TCN_ASSERT(ctx != 0);
+    if (J2S(file) == NULL && J2S(path) == NULL)
+        return JNI_FALSE;
+
+    if (!c->crl) {
+        if ((c->crl = X509_STORE_new()) == NULL)
+            goto cleanup;
+    }
+    if (J2S(file)) {
+        lookup = X509_STORE_add_lookup(c->crl, X509_LOOKUP_file());
+        if (lookup == NULL) {
+            ERR_error_string(ERR_get_error(), err);
+            X509_STORE_free(c->crl);
+            c->crl = NULL;
+            tcn_Throw(e, "Lookup failed for file %s (%s)", J2S(file), err);
+            goto cleanup;
+        }
+        X509_LOOKUP_load_file(lookup, J2S(file), X509_FILETYPE_PEM);
+    }
+    if (J2S(path)) {
+        lookup = X509_STORE_add_lookup(c->crl, X509_LOOKUP_hash_dir());
+        if (lookup == NULL) {
+            ERR_error_string(ERR_get_error(), err);
+            X509_STORE_free(c->crl);
+            c->crl = NULL;
+            tcn_Throw(e, "Lookup failed for path %s (%s)", J2S(file), err);
+            goto cleanup;
+        }
+        X509_LOOKUP_add_dir(lookup, J2S(path), X509_FILETYPE_PEM);
+    }
+    rv = JNI_TRUE;
+cleanup:
+    TCN_FREE_CSTRING(file);
+    TCN_FREE_CSTRING(path);
+    return rv;
+}
+
+TCN_IMPLEMENT_CALL(jboolean, SSLContext, setCertificateChainFile)(TCN_STDARGS, jlong ctx,
+                                                                  jstring file,
+                                                                  jboolean skipfirst)
+{
+    tcn_ssl_ctxt_t *c = J2P(ctx, tcn_ssl_ctxt_t *);
+    jboolean rv = JNI_FALSE;
+    TCN_ALLOC_CSTRING(file);
+
+    UNREFERENCED(o);
+    TCN_ASSERT(ctx != 0);
+    if (!J2S(file))
+        return JNI_FALSE;
+    if (SSL_CTX_use_certificate_chain(c->ctx, J2S(file), skipfirst) > 0)
+        rv = JNI_TRUE;
+    TCN_FREE_CSTRING(file);
+    return rv;
+}
+
+TCN_IMPLEMENT_CALL(jboolean, SSLContext, setCACertificate)(TCN_STDARGS,
+                                                           jlong ctx,
+                                                           jstring file,
+                                                           jstring path)
+{
+    tcn_ssl_ctxt_t *c = J2P(ctx, tcn_ssl_ctxt_t *);
+    jboolean rv = JNI_TRUE;
+    TCN_ALLOC_CSTRING(file);
+    TCN_ALLOC_CSTRING(path);
+
+    UNREFERENCED(o);
+    TCN_ASSERT(ctx != 0);
+    if (file == NULL && path == NULL)
+        return JNI_FALSE;
+
+   /*
+     * Configure Client Authentication details
+     */
+    if (!SSL_CTX_load_verify_locations(c->ctx,
+                                       J2S(file), J2S(path))) {
+        char err[256];
+        ERR_error_string(ERR_get_error(), err);
+        tcn_Throw(e, "Unable to configure locations "
+                  "for client authentication (%s)", err);
+        rv = JNI_FALSE;
+        goto cleanup;
+    }
+    c->store = SSL_CTX_get_cert_store(c->ctx);
+    if (c->mode) {
+        STACK_OF(X509_NAME) *ca_certs;
+        c->ca_certs++;
+        ca_certs = SSL_CTX_get_client_CA_list(c->ctx);
+        if (ca_certs == NULL) {
+            SSL_load_client_CA_file(J2S(file));
+            if (ca_certs != NULL)
+                SSL_CTX_set_client_CA_list(c->ctx, (STACK *)ca_certs);
+        }
+        else {
+            if (!SSL_add_file_cert_subjects_to_stack((STACK *)ca_certs, J2S(file)))
+                ca_certs = NULL;
+        }
+        if (ca_certs == NULL && c->verify_mode == SSL_CVERIFY_REQUIRE) {
+            /*
+             * Give a warning when no CAs were configured but client authentication
+             * should take place. This cannot work.
+            */
+            BIO_printf(c->bio_os,
+                        "[WARN] Oops, you want to request client "
+                        "authentication, but no CAs are known for "
+                        "verification!?");
+        }
+    }
+cleanup:
+    TCN_FREE_CSTRING(file);
+    TCN_FREE_CSTRING(path);
+    return rv;
+}
+
+TCN_IMPLEMENT_CALL(void, SSLContext, setShutdownType)(TCN_STDARGS, jlong ctx,
+                                                      jint type)
+{
+    tcn_ssl_ctxt_t *c = J2P(ctx, tcn_ssl_ctxt_t *);
+
+    UNREFERENCED_STDARGS;
+    TCN_ASSERT(ctx != 0);
+    c->shutdown_type = type;
+}
+
+TCN_IMPLEMENT_CALL(void, SSLContext, setVerify)(TCN_STDARGS, jlong ctx,
+                                                jint level, jint depth)
+{
+    tcn_ssl_ctxt_t *c = J2P(ctx, tcn_ssl_ctxt_t *);
+    int verify = SSL_VERIFY_NONE;
+
+    UNREFERENCED(o);
+    TCN_ASSERT(ctx != 0);
+    c->verify_mode = level;
+
+    if (c->verify_mode == SSL_CVERIFY_UNSET)
+        c->verify_mode = SSL_CVERIFY_NONE;
+    if (depth > 0)
+        c->verify_depth = depth;
+    /*
+     *  Configure callbacks for SSL context
+     */
+    if (c->verify_mode == SSL_CVERIFY_REQUIRE)
+        verify |= SSL_VERIFY_PEER_STRICT;
+    if ((c->verify_mode == SSL_CVERIFY_OPTIONAL) ||
+        (c->verify_mode == SSL_CVERIFY_OPTIONAL_NO_CA))
+        verify |= SSL_VERIFY_PEER;
+    if (!c->store) {
+        if (SSL_CTX_set_default_verify_paths(c->ctx)) {
+            c->store = SSL_CTX_get_cert_store(c->ctx);
+            X509_STORE_set_flags(c->store, 0);
+        }
+        else {
+            /* XXX: See if this is fatal */ 
+        }
+    }
+
+    SSL_CTX_set_verify(c->ctx, verify, SSL_callback_SSL_verify);
+}
+
+static EVP_PKEY *load_pem_key(tcn_ssl_ctxt_t *c, const char *file)
+{
+    BIO *bio = NULL;
+    EVP_PKEY *key = NULL;
+    void *cb_data = c->cb_data;
+
+    if ((bio = BIO_new(BIO_s_file())) == NULL) {
+        return NULL;
+    }
+    if (BIO_read_filename(bio, file) <= 0) {
+        BIO_free(bio);
+        return NULL;
+    }
+    if (!cb_data)
+        cb_data = &tcn_password_callback;
+    key = PEM_read_bio_PrivateKey(bio, NULL,
+                (pem_password_cb *)SSL_password_callback,
+                cb_data);
+    BIO_free(bio);
+    return key;
+}
+
+static X509 *load_pem_cert(const char *file)
+{
+    BIO *bio = NULL;
+    X509 *cert = NULL;
+
+    if ((bio = BIO_new(BIO_s_file())) == NULL) {
+        return NULL;
+    }
+    if (BIO_read_filename(bio, file) <= 0) {
+        BIO_free(bio);
+        return NULL;
+    }
+    cert = PEM_read_bio_X509_AUX(bio, NULL,
+                (pem_password_cb *)SSL_password_callback,
+                 NULL);
+    BIO_free(bio);
+    return cert;
+}
+
+TCN_IMPLEMENT_CALL(void, SSLContext, setRandom)(TCN_STDARGS, jlong ctx,
+                                                jstring file)
+{
+    tcn_ssl_ctxt_t *c = J2P(ctx, tcn_ssl_ctxt_t *);
+    TCN_ALLOC_CSTRING(file);    
+
+    TCN_ASSERT(ctx != 0);
+    UNREFERENCED(o);
+    if (J2S(file))
+        c->rand_file = apr_pstrdup(c->pool, J2S(file));
+    TCN_FREE_CSTRING(file);
+}
+
+TCN_IMPLEMENT_CALL(jboolean, SSLContext, setCertificate)(TCN_STDARGS, jlong ctx,
+                                                         jstring cert, jstring key,
+                                                         jstring password, jint idx)
+{
+    tcn_ssl_ctxt_t *c = J2P(ctx, tcn_ssl_ctxt_t *);
+    jboolean rv = JNI_TRUE;
+    TCN_ALLOC_CSTRING(cert);
+    TCN_ALLOC_CSTRING(key);
+    TCN_ALLOC_CSTRING(password);
+    const char *key_file, *cert_file;
+    char err[256];
+
+    UNREFERENCED(o);
+    TCN_ASSERT(ctx != 0);
+
+    if (idx < 0 || idx >= SSL_AIDX_MAX) {
+        /* TODO: Throw something */
+        rv = JNI_FALSE;
+        goto cleanup;
+    }
+    if (J2S(password)) {
+        if (!c->cb_data)
+            c->cb_data = &tcn_password_callback;
+        strncpy(c->cb_data->password, J2S(password), SSL_MAX_PASSWORD_LEN);
+        c->cb_data->password[SSL_MAX_PASSWORD_LEN-1] = '\0';
+    }
+    key_file  = J2S(key);
+    cert_file = J2S(cert);
+    if (!key_file)
+        key_file = cert_file;
+    if (!key_file) {
+        tcn_Throw(e, "No Certificate file specified");
+        rv = JNI_FALSE;
+        goto cleanup;
+    }
+    if ((c->keys[idx] = load_pem_key(c, key_file)) == NULL) {
+        ERR_error_string(ERR_get_error(), err);
+        tcn_Throw(e, "Unable to load certificate key %s (%s)",
+                  key_file, err);
+        rv = JNI_FALSE;
+        goto cleanup;
+    }
+    if ((c->certs[idx] = load_pem_cert(cert_file)) == NULL) {
+        ERR_error_string(ERR_get_error(), err);
+        tcn_Throw(e, "Unable to load certificate %s (%s)",
+                  cert_file, err);
+        rv = JNI_FALSE;
+        goto cleanup;
+    }
+    if (SSL_CTX_use_certificate(c->ctx, c->certs[idx]) <= 0) {
+        ERR_error_string(ERR_get_error(), err);
+        tcn_Throw(e, "Error setting certificate (%s)", err);
+        rv = JNI_FALSE;
+        goto cleanup;
+    }
+    if (SSL_CTX_use_PrivateKey(c->ctx, c->keys[idx]) <= 0) {
+        ERR_error_string(ERR_get_error(), err);
+        tcn_Throw(e, "Error setting private key (%s)", err);
+        rv = JNI_FALSE;
+        goto cleanup;
+    }
+    if (SSL_CTX_check_private_key(c->ctx) <= 0) {
+        ERR_error_string(ERR_get_error(), err);
+        tcn_Throw(e, "Private key does not match the certificate public key (%s)",
+                  err);
+        rv = JNI_FALSE;
+        goto cleanup;
+    }
+cleanup:
+    TCN_FREE_CSTRING(cert);
+    TCN_FREE_CSTRING(key);
+    TCN_FREE_CSTRING(password);
+    return rv;
+}
+
+#else
+/* OpenSSL is not supported
+ * If someday we make OpenSSL optional
+ * APR_ENOTIMPL will go here
+ */
+#error "No OpenSSL Toolkit defined."
+#endif

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/src/sslinfo.c
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/src/sslinfo.c	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/src/sslinfo.c	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,562 @@
+/* Copyright 2000-2005 The Apache Software Foundation
+ *
+ * Licensed 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.
+ */
+
+/** SSL info wrapper
+ *
+ * @author Mladen Turk
+ * @version $Revision: 392531 $, $Date: 2006-04-08 09:24:55 -0500 (Sat, 08 Apr 2006) $
+ */
+
+#include "tcn.h"
+#include "apr_file_io.h"
+#include "apr_thread_mutex.h"
+#include "apr_poll.h"
+
+#ifdef HAVE_OPENSSL
+#include "ssl_private.h"
+
+static const char *hex_basis = "0123456789ABCDEF";
+
+static char *convert_to_hex(const void *buf, size_t len)
+{
+    const unsigned char *p = ( const unsigned char *)buf;
+    char *str, *s;
+    size_t i;
+
+    if ((len < 1) || ((str = malloc(len * 2 + 1)) == NULL))
+        return NULL;
+    for (i = 0, s = str; i < len; i++) {
+        unsigned char c = *p++;
+        *s++ = hex_basis[c >> 4];
+        *s++ = hex_basis[c & 0x0F];
+    }
+    *s = '\0';
+    return str;
+}
+
+#define DIGIT2NUM(x) (((x)[0] - '0') * 10 + (x)[1] - '0')
+
+static int get_days_remaining(ASN1_UTCTIME *tm)
+{
+    apr_time_t then, now = apr_time_now();
+    apr_time_exp_t exp = {0};
+    int diff;
+
+    /* Fail if the time isn't a valid ASN.1 UTCTIME; RFC3280 mandates
+     * that the seconds digits are present even though ASN.1
+     * doesn't. */
+    if (tm->length < 11 || !ASN1_UTCTIME_check(tm))
+        return 0;
+
+    exp.tm_year = DIGIT2NUM(tm->data);
+    exp.tm_mon  = DIGIT2NUM(tm->data + 2) - 1;
+    exp.tm_mday = DIGIT2NUM(tm->data + 4) + 1;
+    exp.tm_hour = DIGIT2NUM(tm->data + 6);
+    exp.tm_min  = DIGIT2NUM(tm->data + 8);
+    exp.tm_sec  = DIGIT2NUM(tm->data + 10);
+
+    if (exp.tm_year <= 50)
+        exp.tm_year += 100;
+    if (apr_time_exp_gmt_get(&then, &exp) != APR_SUCCESS)
+        return 0;
+
+    diff = (int)((apr_time_sec(then) - apr_time_sec(now)) / (60*60*24));
+    return diff > 0 ? diff : 0;
+}
+
+static char *get_cert_valid(ASN1_UTCTIME *tm)
+{
+    char *result;
+    BIO* bio;
+    int n;
+
+    if ((bio = BIO_new(BIO_s_mem())) == NULL)
+        return NULL;
+    ASN1_UTCTIME_print(bio, tm);
+    n = BIO_pending(bio);
+    result = malloc(n+1);
+    n = BIO_read(bio, result, n);
+    result[n] = '\0';
+    BIO_free(bio);
+    return result;
+}
+
+static char *get_cert_PEM(X509 *xs)
+{
+    char *result = NULL;
+    BIO *bio;
+
+    if ((bio = BIO_new(BIO_s_mem())) == NULL)
+        return NULL;
+    if (PEM_write_bio_X509(bio, xs)) {
+        int n = BIO_pending(bio);
+        result = malloc(n+1);
+        n = BIO_read(bio, result, n);
+        result[n] = '\0';
+    }
+    BIO_free(bio);
+    return result;
+}
+
+static unsigned char *get_cert_ASN1(X509 *xs, int *len)
+{
+    unsigned char *result = NULL;
+    BIO *bio;
+
+    *len = 0;
+    if ((bio = BIO_new(BIO_s_mem())) == NULL)
+        return NULL;
+    if (i2d_X509_bio(bio, xs)) {
+        int n = BIO_pending(bio);
+        result = malloc(n);
+        n = BIO_read(bio, result, n);
+        *len = n;
+    }
+    BIO_free(bio);
+    return result;
+}
+
+
+static char *get_cert_serial(X509 *xs)
+{
+    char *result;
+    BIO *bio;
+    int n;
+
+    if ((bio = BIO_new(BIO_s_mem())) == NULL)
+        return NULL;
+    i2a_ASN1_INTEGER(bio, X509_get_serialNumber(xs));
+    n = BIO_pending(bio);
+    result = malloc(n+1);
+    n = BIO_read(bio, result, n);
+    result[n] = '\0';
+    BIO_free(bio);
+    return result;
+}
+
+static const struct {
+    int   fid;
+    int   nid;
+} info_cert_dn_rec[] = {
+    { SSL_INFO_DN_COUNTRYNAME,            NID_countryName            },
+    { SSL_INFO_DN_STATEORPROVINCENAME,    NID_stateOrProvinceName    },
+    { SSL_INFO_DN_LOCALITYNAME,           NID_localityName           },
+    { SSL_INFO_DN_ORGANIZATIONNAME,       NID_organizationName       },
+    { SSL_INFO_DN_ORGANIZATIONALUNITNAME, NID_organizationalUnitName },
+    { SSL_INFO_DN_COMMONNAME,             NID_commonName             },
+    { SSL_INFO_DN_TITLE,                  NID_title                  },
+    { SSL_INFO_DN_INITIALS,               NID_initials               },
+    { SSL_INFO_DN_GIVENNAME,              NID_givenName              },
+    { SSL_INFO_DN_SURNAME,                NID_surname                },
+    { SSL_INFO_DN_DESCRIPTION,            NID_description            },
+    { SSL_INFO_DN_UNIQUEIDENTIFIER,       NID_x500UniqueIdentifier   },
+    { SSL_INFO_DN_EMAILADDRESS,           NID_pkcs9_emailAddress     },
+    { 0,                                  0                          }
+};
+
+static char *lookup_ssl_cert_dn(X509_NAME *xsname, int dnidx)
+{
+    char *result;
+    X509_NAME_ENTRY *xsne;
+    int i, j, n, idx = 0;
+
+    result = NULL;
+
+    for (i = 0; info_cert_dn_rec[i].fid != 0; i++) {
+        if (info_cert_dn_rec[i].fid == dnidx) {
+            for (j = 0; j < sk_X509_NAME_ENTRY_num((STACK_OF(X509_NAME_ENTRY) *)
+                                                   (xsname->entries)); j++) {
+                xsne = sk_X509_NAME_ENTRY_value((STACK_OF(X509_NAME_ENTRY) *)
+                                                (xsname->entries), j);
+
+                n =OBJ_obj2nid((ASN1_OBJECT *)X509_NAME_ENTRY_get_object(xsne));
+                if (n == info_cert_dn_rec[i].nid && idx-- == 0) {
+                    result = malloc(xsne->value->length + 1);
+                    memcpy(result, xsne->value->data,
+                                   xsne->value->length);
+                    result[xsne->value->length] = '\0';
+
+#if APR_CHARSET_EBCDIC
+                    ap_xlate_proto_from_ascii(result, xsne->value->length);
+#endif /* APR_CHARSET_EBCDIC */
+                    break;
+                }
+            }
+            break;
+        }
+    }
+    return result;
+}
+
+TCN_IMPLEMENT_CALL(jobject, SSLSocket, getInfoB)(TCN_STDARGS, jlong sock,
+                                                 jint what)
+{
+    tcn_socket_t   *a = J2P(sock, tcn_socket_t *);
+    tcn_ssl_conn_t *s;
+    jbyteArray array = NULL;
+    apr_status_t rv = APR_SUCCESS;
+
+    UNREFERENCED(o);
+    TCN_ASSERT(sock != 0);
+
+    s = (tcn_ssl_conn_t *)(a->opaque);
+    switch (what) {
+        case SSL_INFO_SESSION_ID:
+        {
+            SSL_SESSION *session  = SSL_get_session(s->ssl);
+            if (session) {
+                array = tcn_new_arrayb(e, &session->session_id[0],
+                                       session->session_id_length);
+            }
+        }
+        break;
+        default:
+            rv = APR_EINVAL;
+        break;
+    }
+    if (what & SSL_INFO_CLIENT_MASK) {
+        X509 *xs;
+        unsigned char *result;
+        int len;
+        if ((xs = SSL_get_peer_certificate(s->ssl)) != NULL) {
+            switch (what) {
+                case SSL_INFO_CLIENT_CERT:
+                    if ((result = get_cert_ASN1(xs, &len))) {
+                        array = tcn_new_arrayb(e, result, len);
+                        free(result);
+                    }
+                break;
+            }
+            X509_free(xs);
+        }
+        rv = APR_SUCCESS;
+    }
+    else if (what & SSL_INFO_SERVER_MASK) {
+        X509 *xs;
+        unsigned char *result;
+        int len;
+        if ((xs = SSL_get_certificate(s->ssl)) != NULL) {
+            switch (what) {
+                case SSL_INFO_SERVER_CERT:
+                    if ((result = get_cert_ASN1(xs, &len))) {
+                        array = tcn_new_arrayb(e, result, len);
+                        free(result);
+                    }
+                break;
+            }
+            /* XXX: No need to call the X509_free(xs); */
+        }
+        rv = APR_SUCCESS;
+    }
+    else if (what & SSL_INFO_CLIENT_CERT_CHAIN) {
+        X509 *xs;
+        unsigned char *result;
+        STACK_OF(X509) *sk =  SSL_get_peer_cert_chain(s->ssl);
+        int len, n = what & 0x0F;
+        if (n < sk_X509_num(sk)) {
+            xs = sk_X509_value(sk, n);
+            if ((result = get_cert_ASN1(xs, &len))) {
+                array = tcn_new_arrayb(e, result, len);
+                free(result);
+            }
+        }
+        rv = APR_SUCCESS;
+    }
+    if (rv != APR_SUCCESS)
+        tcn_ThrowAPRException(e, rv);
+
+    return array;
+}
+
+TCN_IMPLEMENT_CALL(jstring, SSLSocket, getInfoS)(TCN_STDARGS, jlong sock,
+                                                 jint what)
+{
+    tcn_socket_t   *a = J2P(sock, tcn_socket_t *);
+    tcn_ssl_conn_t *s;
+    jstring value = NULL;
+    apr_status_t rv = APR_SUCCESS;
+
+    UNREFERENCED(o);
+    TCN_ASSERT(sock != 0);
+
+    s = (tcn_ssl_conn_t *)(a->opaque);
+    switch (what) {
+        case SSL_INFO_SESSION_ID:
+        {
+            SSL_SESSION *session  = SSL_get_session(s->ssl);
+            if (session) {
+                char *hs = convert_to_hex(&session->session_id[0],
+                                          session->session_id_length);
+                if (hs) {
+                    value = tcn_new_string(e, hs);
+                    free(hs);
+                }
+            }
+        }
+        break;
+        case SSL_INFO_PROTOCOL:
+            value = tcn_new_string(e, SSL_get_version(s->ssl));
+        break;
+        case SSL_INFO_CIPHER:
+            value = tcn_new_string(e, SSL_get_cipher_name(s->ssl));
+        break;
+        case SSL_INFO_CIPHER_VERSION:
+            value = tcn_new_string(e, SSL_get_cipher_version(s->ssl));
+        break;
+        case SSL_INFO_CIPHER_DESCRIPTION:
+            {
+                SSL_CIPHER *cipher = SSL_get_current_cipher(s->ssl);
+                if (cipher) {
+                    char buf[256];
+                    char *desc = SSL_CIPHER_description(cipher, buf, 256);
+                    value = tcn_new_string(e, desc);
+                }
+            }
+        break;
+        default:
+            rv = APR_EINVAL;
+        break;
+    }
+    if (what & (SSL_INFO_CLIENT_S_DN | SSL_INFO_CLIENT_I_DN)) {
+        X509 *xs;
+        X509_NAME *xsname;
+        if ((xs = SSL_get_peer_certificate(s->ssl)) != NULL) {
+            char *result;
+            int idx = what & 0x0F;
+            if (what & SSL_INFO_CLIENT_S_DN)
+                xsname = X509_get_subject_name(xs);
+            else
+                xsname = X509_get_issuer_name(xs);
+            if (idx) {
+                result = lookup_ssl_cert_dn(xsname, idx);
+                if (result) {
+                    value = tcn_new_string(e, result);
+                    free(result);
+                }
+            }
+            else
+                value = tcn_new_string(e, X509_NAME_oneline(xsname, NULL, 0));
+            X509_free(xs);
+        }
+        rv = APR_SUCCESS;
+    }
+    else if (what & (SSL_INFO_SERVER_S_DN | SSL_INFO_SERVER_I_DN)) {
+        X509 *xs;
+        X509_NAME *xsname;
+        if ((xs = SSL_get_certificate(s->ssl)) != NULL) {
+            char *result;
+            int idx = what & 0x0F;
+            if (what & SSL_INFO_SERVER_S_DN)
+                xsname = X509_get_subject_name(xs);
+            else
+                xsname = X509_get_issuer_name(xs);
+            if (idx) {
+                result = lookup_ssl_cert_dn(xsname, what & 0x0F);
+                if (result) {
+                    value = tcn_new_string(e, result);
+                    free(result);
+                }
+            }
+            else
+                value = tcn_new_string(e, X509_NAME_oneline(xsname, NULL, 0));
+            /* XXX: No need to call the X509_free(xs); */
+        }
+        rv = APR_SUCCESS;
+    }
+    else if (what & SSL_INFO_CLIENT_MASK) {
+        X509 *xs;
+        char *result;
+        int nid;
+        if ((xs = SSL_get_peer_certificate(s->ssl)) != NULL) {
+            switch (what) {
+                case SSL_INFO_CLIENT_V_START:
+                    if ((result = get_cert_valid(X509_get_notBefore(xs)))) {
+                        value = tcn_new_string(e, result);
+                        free(result);
+                    }
+                break;
+                case SSL_INFO_CLIENT_V_END:
+                    if ((result = get_cert_valid(X509_get_notAfter(xs)))) {
+                        value = tcn_new_string(e, result);
+                        free(result);
+                    }
+                break;
+                case SSL_INFO_CLIENT_A_SIG:
+                    nid = OBJ_obj2nid((ASN1_OBJECT *)xs->cert_info->signature->algorithm);
+                    if (nid == NID_undef)
+                        value = tcn_new_string(e, "UNKNOWN");
+                    else
+                        value = tcn_new_string(e, OBJ_nid2ln(nid));
+                break;
+                case SSL_INFO_CLIENT_A_KEY:
+                    nid = OBJ_obj2nid((ASN1_OBJECT *)xs->cert_info->key->algor->algorithm);
+                    if (nid == NID_undef)
+                        value = tcn_new_string(e, "UNKNOWN");
+                    else
+                        value = tcn_new_string(e, OBJ_nid2ln(nid));
+                break;
+                case SSL_INFO_CLIENT_CERT:
+                    if ((result = get_cert_PEM(xs))) {
+                        value = tcn_new_string(e, result);
+                        free(result);
+                    }
+                break;
+                case SSL_INFO_CLIENT_M_SERIAL:
+                    if ((result = get_cert_serial(xs))) {
+                        value = tcn_new_string(e, result);
+                        free(result);
+                    }
+                break;
+            }
+            X509_free(xs);
+        }
+        rv = APR_SUCCESS;
+    }
+    else if (what & SSL_INFO_SERVER_MASK) {
+        X509 *xs;
+        char *result;
+        int nid;
+        if ((xs = SSL_get_certificate(s->ssl)) != NULL) {
+            switch (what) {
+                case SSL_INFO_SERVER_V_START:
+                    if ((result = get_cert_valid(X509_get_notBefore(xs)))) {
+                        value = tcn_new_string(e, result);
+                        free(result);
+                    }
+                break;
+                case SSL_INFO_SERVER_V_END:
+                    if ((result = get_cert_valid(X509_get_notAfter(xs)))) {
+                        value = tcn_new_string(e, result);
+                        free(result);
+                    }
+                break;
+                case SSL_INFO_SERVER_A_SIG:
+                    nid = OBJ_obj2nid((ASN1_OBJECT *)xs->cert_info->signature->algorithm);
+                    if (nid == NID_undef)
+                        value = tcn_new_string(e, "UNKNOWN");
+                    else
+                        value = tcn_new_string(e, OBJ_nid2ln(nid));
+                break;
+                case SSL_INFO_SERVER_A_KEY:
+                    nid = OBJ_obj2nid((ASN1_OBJECT *)xs->cert_info->key->algor->algorithm);
+                    if (nid == NID_undef)
+                        value = tcn_new_string(e, "UNKNOWN");
+                    else
+                        value = tcn_new_string(e, OBJ_nid2ln(nid));
+                break;
+                case SSL_INFO_SERVER_CERT:
+                    if ((result = get_cert_PEM(xs))) {
+                        value = tcn_new_string(e, result);
+                        free(result);
+                    }
+                break;
+                case SSL_INFO_SERVER_M_SERIAL:
+                    if ((result = get_cert_serial(xs))) {
+                        value = tcn_new_string(e, result);
+                        free(result);
+                    }
+                break;
+            }
+            /* XXX: No need to call the X509_free(xs); */
+        }
+        rv = APR_SUCCESS;
+    }
+    else if (what & SSL_INFO_CLIENT_CERT_CHAIN) {
+        X509 *xs;
+        char *result;
+        STACK_OF(X509) *sk =  SSL_get_peer_cert_chain(s->ssl);
+        int n = what & 0x0F;
+        if (n < sk_X509_num(sk)) {
+            xs = sk_X509_value(sk, n);
+            if ((result = get_cert_PEM(xs))) {
+                value = tcn_new_string(e, result);
+                free(result);
+            }
+        }
+        rv = APR_SUCCESS;
+    }
+    if (rv != APR_SUCCESS)
+        tcn_ThrowAPRException(e, rv);
+
+    return value;
+}
+
+TCN_IMPLEMENT_CALL(jint, SSLSocket, getInfoI)(TCN_STDARGS, jlong sock,
+                                              jint what)
+{
+    tcn_socket_t   *a = J2P(sock, tcn_socket_t *);
+    tcn_ssl_conn_t *s;
+    apr_status_t rv = APR_SUCCESS;
+    jint value = -1;
+
+    UNREFERENCED(o);
+    TCN_ASSERT(sock != 0);
+
+    s = (tcn_ssl_conn_t *)(a->opaque);
+
+    switch (what) {
+        case SSL_INFO_CIPHER_USEKEYSIZE:
+        case SSL_INFO_CIPHER_ALGKEYSIZE:
+        {
+            int usekeysize = 0;
+            int algkeysize = 0;
+            SSL_CIPHER *cipher = SSL_get_current_cipher(s->ssl);
+            if (cipher) {
+                usekeysize = SSL_CIPHER_get_bits(cipher, &algkeysize);
+                if (what == SSL_INFO_CIPHER_USEKEYSIZE)
+                    value = usekeysize;
+                else
+                    value = algkeysize;
+            }
+        }
+        break;
+        case SSL_INFO_CLIENT_CERT_CHAIN:
+        {
+            STACK_OF(X509) *sk =  SSL_get_peer_cert_chain(s->ssl);
+            value = sk_X509_num(sk);
+        }
+        break;
+        default:
+            rv = APR_EINVAL;
+        break;
+    }
+    if (what & SSL_INFO_CLIENT_MASK) {
+        X509 *xs;
+        if ((xs = SSL_get_peer_certificate(s->ssl)) != NULL) {
+            switch (what) {
+                case SSL_INFO_CLIENT_V_REMAIN:
+                    value = get_days_remaining(X509_get_notAfter(xs));
+                    rv = APR_SUCCESS;
+                break;
+                default:
+                    rv = APR_EINVAL;
+                break;                    
+           }
+           X509_free(xs);
+        }
+    }
+
+    if (rv != APR_SUCCESS)
+        tcn_ThrowAPRException(e, rv);
+    return value;
+}
+
+#else
+/* OpenSSL is not supported
+ * If someday we make OpenSSL optional
+ * APR_ENOTIMPL will go here
+ */
+#error "No OpenSSL Toolkit defined."
+#endif

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/src/sslnetwork.c
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/src/sslnetwork.c	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/src/sslnetwork.c	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,528 @@
+/* Copyright 2000-2005 The Apache Software Foundation
+ *
+ * Licensed 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.
+ */
+
+/** SSL network wrapper
+ *
+ * @author Mladen Turk
+ * @version $Revision: 391652 $, $Date: 2006-04-05 10:54:34 -0500 (Wed, 05 Apr 2006) $
+ */
+
+#include "tcn.h"
+#include "apr_thread_mutex.h"
+#include "apr_poll.h"
+
+
+#ifdef HAVE_OPENSSL
+#include "ssl_private.h"
+
+#ifdef TCN_DO_STATISTICS
+#include "apr_atomic.h"
+
+static volatile apr_uint32_t ssl_created  = 0;
+static volatile apr_uint32_t ssl_closed   = 0;
+static volatile apr_uint32_t ssl_cleared  = 0;
+static volatile apr_uint32_t ssl_accepted = 0;
+
+void ssl_network_dump_statistics()
+{
+    fprintf(stderr, "SSL Network Statistics ..\n");
+    fprintf(stderr, "Sockets created         : %d\n", ssl_created);
+    fprintf(stderr, "Sockets accepted        : %d\n", ssl_accepted);
+    fprintf(stderr, "Sockets closed          : %d\n", ssl_closed);
+    fprintf(stderr, "Sockets cleared         : %d\n", ssl_cleared);
+}
+
+#endif
+
+static int ssl_smart_shutdown(SSL *ssl, int shutdown_type)
+{
+    int i;
+    int rc = 0;
+
+    switch (shutdown_type) {
+        case SSL_SHUTDOWN_TYPE_UNCLEAN:
+            /* perform no close notify handshake at all
+             * (violates the SSL/TLS standard!)
+             */
+            shutdown_type = SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN;
+        break;
+        case SSL_SHUTDOWN_TYPE_ACCURATE:
+            /* send close notify and wait for clients close notify
+             * (standard compliant, but usually causes connection hangs)
+             */
+            shutdown_type = 0;
+        break;
+        default:
+            /*
+             * case SSL_SHUTDOWN_TYPE_UNSET:
+             * case SSL_SHUTDOWN_TYPE_STANDARD:
+             * send close notify, but don't wait for clients close notify
+             * (standard compliant and safe, so it's the DEFAULT!)
+             */
+            shutdown_type = SSL_RECEIVED_SHUTDOWN;
+        break;
+    }
+
+    SSL_set_shutdown(ssl, shutdown_type);
+    /*
+     * Repeat the calls, because SSL_shutdown internally dispatches through a
+     * little state machine. Usually only one or two interation should be
+     * needed, so we restrict the total number of restrictions in order to
+     * avoid process hangs in case the client played bad with the socket
+     * connection and OpenSSL cannot recognize it.
+     *  max 2x pending + 2x data = 4
+     */
+    for (i = 0; i < 4; i++) {
+        if ((rc = SSL_shutdown(ssl)))
+            break;
+    }
+    return rc;
+}
+
+static apr_status_t ssl_cleanup(void *data)
+{
+    tcn_ssl_conn_t *con = (tcn_ssl_conn_t *)data;
+
+    if (con) {
+        if (con->ssl) {
+            ssl_smart_shutdown(con->ssl, con->shutdown_type);
+            SSL_free(con->ssl);
+            con->ssl = NULL;
+        }
+        if (con->peer) {
+            X509_free(con->peer);
+            con->peer = NULL;
+        }
+    }
+
+#ifdef TCN_DO_STATISTICS
+    apr_atomic_inc32(&ssl_cleared);
+#endif
+    return APR_SUCCESS;
+}
+
+static tcn_ssl_conn_t *ssl_create(JNIEnv *env, tcn_ssl_ctxt_t *ctx, apr_pool_t *pool)
+{
+    tcn_ssl_conn_t *con;
+    SSL *ssl;
+
+    if ((con = apr_pcalloc(pool, sizeof(tcn_ssl_conn_t))) == NULL) {
+        tcn_ThrowAPRException(env, apr_get_os_error());
+        return NULL;
+    }
+    if ((ssl = SSL_new(ctx->ctx)) == NULL) {
+        char err[256];
+        ERR_error_string(ERR_get_error(), err);
+        tcn_Throw(env, "SSL_new failed (%s)", err);
+        con = NULL;
+        return NULL;
+    }
+    SSL_clear(ssl);
+    con->pool = pool;
+    con->ctx  = ctx;
+    con->ssl  = ssl;
+    con->shutdown_type = ctx->shutdown_type;
+    apr_pollset_create(&(con->pollset), 1, pool, 0);
+
+    SSL_set_app_data(ssl, (void *)con);
+
+    if (ctx->mode) {
+        /*
+         *  Configure callbacks for SSL connection
+         */
+        SSL_set_tmp_rsa_callback(ssl, SSL_callback_tmp_RSA);
+        SSL_set_tmp_dh_callback(ssl,  SSL_callback_tmp_DH);
+        SSL_set_session_id_context(ssl, &(ctx->context_id[0]),
+                                   MD5_DIGEST_LENGTH);
+    }
+    SSL_set_verify_result(ssl, X509_V_OK);
+    SSL_rand_seed(ctx->rand_file);
+
+#ifdef TCN_DO_STATISTICS
+    ssl_created++;
+#endif
+    return con;
+}
+
+static apr_status_t wait_for_io_or_timeout(tcn_ssl_conn_t *con,
+                                           int for_what)
+{
+    apr_interval_time_t timeout;
+    apr_pollfd_t pfd;
+    int type;
+    apr_status_t status;
+
+    /* Figure out the the poll direction */
+    switch (for_what) {
+        case SSL_ERROR_WANT_WRITE:
+        case SSL_ERROR_WANT_CONNECT:
+        case SSL_ERROR_WANT_ACCEPT:
+            type = APR_POLLOUT;
+        break;
+        case SSL_ERROR_WANT_READ:
+            type = APR_POLLIN;
+        break;
+        default:
+            return APR_EINVAL;
+        break;
+    }
+
+    apr_socket_timeout_get(con->sock, &timeout);
+    pfd.desc_type = APR_POLL_SOCKET;
+    pfd.desc.s    = con->sock;
+    pfd.reqevents = type;
+
+    /* Remove the object if it was in the pollset, then add in the new
+     * object with the correct reqevents value. Ignore the status result
+     * on the remove, because it might not be in there (yet).
+     */
+    apr_pollset_remove(con->pollset, &pfd);
+
+    /* ### check status code */
+    apr_pollset_add(con->pollset, &pfd);
+
+    do {
+        int numdesc;
+        const apr_pollfd_t *pdesc;
+
+        status = apr_pollset_poll(con->pollset, timeout, &numdesc, &pdesc);
+        if (numdesc == 1 && (pdesc[0].rtnevents & type) != 0)
+            return APR_SUCCESS;
+    } while (APR_STATUS_IS_EINTR(status));
+
+    return status;
+}
+
+static apr_status_t APR_THREAD_FUNC
+ssl_socket_timeout_set(apr_socket_t *sock, apr_interval_time_t t)
+{
+    tcn_ssl_conn_t *con = (tcn_ssl_conn_t *)sock;
+    return apr_socket_timeout_set(con->sock, t);
+}
+
+static apr_status_t APR_THREAD_FUNC
+ssl_socket_timeout_get(apr_socket_t *sock, apr_interval_time_t *t)
+{
+    tcn_ssl_conn_t *con = (tcn_ssl_conn_t *)sock;
+    return apr_socket_timeout_get(con->sock, t);
+}
+
+static APR_INLINE apr_status_t APR_THREAD_FUNC
+ssl_socket_opt_set(apr_socket_t *sock, apr_int32_t opt, apr_int32_t on)
+{
+    tcn_ssl_conn_t *con = (tcn_ssl_conn_t *)sock;
+    return apr_socket_opt_set(con->sock, opt, on);
+}
+
+static APR_INLINE apr_status_t APR_THREAD_FUNC
+ssl_socket_opt_get(apr_socket_t *sock, apr_int32_t opt, apr_int32_t *on)
+{
+    tcn_ssl_conn_t *con = (tcn_ssl_conn_t *)sock;
+    return apr_socket_opt_get(con->sock, opt, on);
+}
+
+static apr_status_t APR_THREAD_FUNC
+ssl_socket_shutdown(apr_socket_t *sock, apr_shutdown_how_e how)
+{
+    apr_status_t rv = APR_SUCCESS;
+    tcn_ssl_conn_t *con = (tcn_ssl_conn_t *)sock;
+
+    if (con->ssl) {
+        if (how < 1)
+            how = con->shutdown_type;
+        rv = ssl_smart_shutdown(con->ssl, how);
+        /* TODO: Translate OpenSSL Error codes */
+        SSL_free(con->ssl);
+        con->ssl = NULL;
+    }
+    return rv;
+}
+
+static apr_status_t APR_THREAD_FUNC
+ssl_socket_close(apr_socket_t *sock)
+{
+    tcn_ssl_conn_t *con = (tcn_ssl_conn_t *)sock;
+    apr_status_t rv = APR_SUCCESS;
+
+#ifdef TCN_DO_STATISTICS
+    apr_atomic_inc32(&ssl_closed);
+#endif
+    if (con->ssl) {
+        rv = ssl_smart_shutdown(con->ssl, con->shutdown_type);
+        SSL_free(con->ssl);
+        con->ssl = NULL;
+    }
+    if (con->peer) {
+        X509_free(con->peer);
+        con->peer = NULL;
+    }
+    return rv;
+}
+
+TCN_IMPLEMENT_CALL(jint, SSLSocket, handshake)(TCN_STDARGS, jlong sock)
+{
+    tcn_socket_t *ss = J2P(sock, tcn_socket_t *);
+    tcn_ssl_conn_t *con;
+    int s;
+    apr_status_t rv;
+    X509 *peer;
+
+    UNREFERENCED_STDARGS;
+    TCN_ASSERT(sock != 0);
+    if (ss->net->type != TCN_SOCKET_SSL)
+        return APR_EINVAL;
+    con = (tcn_ssl_conn_t *)ss->opaque;
+    while (!SSL_is_init_finished(con->ssl)) {
+        if ((s = SSL_do_handshake(con->ssl)) <= 0) {
+            int i = SSL_get_error(con->ssl, s);
+            switch (i) {
+                case SSL_ERROR_NONE:
+                    con->shutdown_type = SSL_SHUTDOWN_TYPE_STANDARD;
+                    return APR_SUCCESS;
+                break;
+                case SSL_ERROR_WANT_READ:
+                case SSL_ERROR_WANT_WRITE:
+                    if ((rv = wait_for_io_or_timeout(con, i)) != APR_SUCCESS) {
+                        con->shutdown_type = SSL_SHUTDOWN_TYPE_UNCLEAN;
+                        return rv;
+                    }
+                break;
+                case SSL_ERROR_SYSCALL:
+                case SSL_ERROR_SSL:
+                    s = apr_get_netos_error();
+                    if (!APR_STATUS_IS_EAGAIN(s) &&
+                        !APR_STATUS_IS_EINTR(s)) {
+                        con->shutdown_type = SSL_SHUTDOWN_TYPE_UNCLEAN;
+                        return s;
+                    }
+                break;
+                default:
+                    /*
+                    * Anything else is a fatal error
+                    */
+                    con->shutdown_type = SSL_SHUTDOWN_TYPE_UNCLEAN;
+                    return SSL_TO_APR_ERROR(i);
+                break;
+            }
+        }
+        /*
+        * Check for failed client authentication
+        */
+        if (SSL_get_verify_result(con->ssl) != X509_V_OK) {
+            /* TODO: Log SSL client authentication failed */
+            con->shutdown_type = SSL_SHUTDOWN_TYPE_UNCLEAN;
+            /* TODO: Figure out the correct return value */
+            return APR_EGENERAL;
+        }
+
+        /*
+         * Remember the peer certificate
+         */
+        if ((peer = SSL_get_peer_certificate(con->ssl)) != NULL) {
+            if (con->peer)
+                X509_free(con->peer);
+            con->peer = peer;
+        }
+    }
+    return APR_SUCCESS;
+}
+
+static apr_status_t APR_THREAD_FUNC
+ssl_socket_recv(apr_socket_t *sock, char *buf, apr_size_t *len)
+{
+    tcn_ssl_conn_t *con = (tcn_ssl_conn_t *)sock;
+    int s, wr = (int)(*len);
+    apr_status_t rv = APR_SUCCESS;
+
+    for (;;) {
+        if ((s = SSL_read(con->ssl, buf, wr)) <= 0) {
+            apr_status_t os = apr_get_netos_error();
+            int i = SSL_get_error(con->ssl, s);
+            /* Special case if the "close notify" alert send by peer */
+            if (s == 0 && (con->ssl->shutdown & SSL_RECEIVED_SHUTDOWN)) {
+                *len = 0;
+                return APR_EOF;
+            }
+            switch (i) {
+                case SSL_ERROR_ZERO_RETURN:
+                    *len = 0;
+                    con->shutdown_type = SSL_SHUTDOWN_TYPE_STANDARD;
+                    return APR_EOF;
+                break;
+                case SSL_ERROR_WANT_READ:
+                case SSL_ERROR_WANT_WRITE:
+                    if ((rv = wait_for_io_or_timeout(con, i)) != APR_SUCCESS) {
+                        con->shutdown_type = SSL_SHUTDOWN_TYPE_UNCLEAN;
+                        return rv;
+                    }
+                break;
+                case SSL_ERROR_SYSCALL:
+                case SSL_ERROR_SSL:
+                    if (!APR_STATUS_IS_EAGAIN(os) &&
+                        !APR_STATUS_IS_EINTR(os)) {
+                        con->shutdown_type = SSL_SHUTDOWN_TYPE_UNCLEAN;
+                        return os;
+                    }
+                break;
+                default:
+                    con->shutdown_type = SSL_SHUTDOWN_TYPE_UNCLEAN;
+                    return os;
+                break;
+            }
+        }
+        else {
+            *len = s;
+            con->shutdown_type = SSL_SHUTDOWN_TYPE_STANDARD;
+            break;
+        }
+    }
+    return rv;
+}
+
+static apr_status_t APR_THREAD_FUNC
+ssl_socket_send(apr_socket_t *sock, const char *buf,
+                apr_size_t *len)
+{
+    tcn_ssl_conn_t *con = (tcn_ssl_conn_t *)sock;
+    int s, wr = (int)(*len);
+    apr_status_t rv = APR_SUCCESS;
+
+    for (;;) {
+        if ((s = SSL_write(con->ssl, buf, wr)) <= 0) {
+            apr_status_t os = apr_get_netos_error();
+            int i = SSL_get_error(con->ssl, s);
+            switch (i) {
+                case SSL_ERROR_ZERO_RETURN:
+                    *len = 0;
+                    con->shutdown_type = SSL_SHUTDOWN_TYPE_STANDARD;
+                    return APR_EOF;
+                break;
+                case SSL_ERROR_WANT_READ:
+                case SSL_ERROR_WANT_WRITE:
+                    if ((rv = wait_for_io_or_timeout(con, i)) != APR_SUCCESS) {
+                        con->shutdown_type = SSL_SHUTDOWN_TYPE_UNCLEAN;
+                        return rv;
+                    }
+                break;
+                case SSL_ERROR_SYSCALL:
+                case SSL_ERROR_SSL:
+                    if (!APR_STATUS_IS_EAGAIN(os) &&
+                        !APR_STATUS_IS_EINTR(os)) {
+                        con->shutdown_type = SSL_SHUTDOWN_TYPE_UNCLEAN;
+                        return os;
+                    }
+                break;
+                default:
+                    con->shutdown_type = SSL_SHUTDOWN_TYPE_UNCLEAN;
+                    return os;
+                break;
+            }
+        }
+        else {
+            *len = s;
+            break;
+        }
+    }
+    return rv;
+}
+
+static apr_status_t APR_THREAD_FUNC
+ssl_socket_sendv(apr_socket_t *sock,
+                 const struct iovec *vec,
+                 apr_int32_t nvec, apr_size_t *len)
+{
+    tcn_ssl_conn_t *con = (tcn_ssl_conn_t *)sock;
+    apr_status_t rv;
+    apr_size_t written = 0;
+    apr_int32_t i;
+
+    for (i = 0; i < nvec; i++) {
+        apr_size_t rd = vec[i].iov_len;
+        if ((rv = ssl_socket_send((apr_socket_t *)con,
+                                  vec[i].iov_base, &rd)) != APR_SUCCESS) {
+            *len = written;
+            return rv;
+        }
+        written += rd;
+    }
+    *len = written;
+    return APR_SUCCESS;
+}
+
+static tcn_nlayer_t ssl_socket_layer = {
+    TCN_SOCKET_SSL,
+    ssl_cleanup,
+    ssl_socket_close,
+    ssl_socket_shutdown,
+    ssl_socket_opt_get,
+    ssl_socket_opt_set,
+    ssl_socket_timeout_get,
+    ssl_socket_timeout_set,
+    ssl_socket_send,
+    ssl_socket_sendv,
+    ssl_socket_recv
+};
+
+
+TCN_IMPLEMENT_CALL(jint, SSLSocket, attach)(TCN_STDARGS, jlong ctx,
+                                            jlong sock)
+{
+    tcn_ssl_ctxt_t *c = J2P(ctx, tcn_ssl_ctxt_t *);
+    tcn_socket_t *s   = J2P(sock, tcn_socket_t *);
+    tcn_ssl_conn_t *con;
+    apr_os_sock_t  oss;
+    apr_status_t rv;
+
+    UNREFERENCED(o);
+    TCN_ASSERT(ctx != 0);
+    TCN_ASSERT(sock != 0);
+
+    if ((rv = apr_os_sock_get(&oss, s->sock)) != APR_SUCCESS)
+        return rv;
+    if ((con = ssl_create(e, c, s->pool)) == NULL)
+        return APR_EGENERAL;
+    con->sock = s->sock;
+
+    SSL_set_fd(con->ssl, (int)oss);
+    if (c->mode)
+        SSL_set_accept_state(con->ssl);
+    else
+        SSL_set_connect_state(con->ssl);
+    /* Change socket type */
+    s->net    = &ssl_socket_layer;
+    s->opaque = con;
+
+    return APR_SUCCESS;
+}
+
+TCN_IMPLEMENT_CALL(jint, SSLSocket, renegotiate)(TCN_STDARGS,
+                                                 jlong sock)
+{
+    tcn_socket_t *s   = J2P(sock, tcn_socket_t *);
+    tcn_ssl_conn_t *con;
+
+    UNREFERENCED_STDARGS;
+    TCN_ASSERT(sock != 0);
+    con = (tcn_ssl_conn_t *)s->opaque;
+    return SSL_renegotiate(con->ssl);
+}
+
+#else
+/* OpenSSL is not supported
+ * If someday we make OpenSSL optional
+ * APR_ENOTIMPL will go here
+ */
+#error "No OpenSSL Toolkit defined."
+#endif

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/src/sslutils.c
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/src/sslutils.c	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/src/sslutils.c	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,679 @@
+/* Copyright 2000-2005 The Apache Software Foundation
+ *
+ * Licensed 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.
+ */
+
+/** SSL Utilities
+ *
+ * @author Mladen Turk
+ * @version $Revision: 439960 $, $Date: 2006-09-04 02:15:58 -0500 (Mon, 04 Sep 2006) $
+ */
+
+#include "tcn.h"
+#include "apr_thread_mutex.h"
+#include "apr_poll.h"
+
+#ifdef HAVE_OPENSSL
+#include "ssl_private.h"
+
+#ifdef WIN32
+extern int WIN32_SSL_password_prompt(tcn_pass_cb_t *data);
+#endif
+
+/*  _________________________________________________________________
+**
+**  Additional High-Level Functions for OpenSSL
+**  _________________________________________________________________
+*/
+
+/* we initialize this index at startup time
+ * and never write to it at request time,
+ * so this static is thread safe.
+ * also note that OpenSSL increments at static variable when
+ * SSL_get_ex_new_index() is called, so we _must_ do this at startup.
+ */
+static int SSL_app_data2_idx = -1;
+
+void SSL_init_app_data2_idx(void)
+{
+    int i;
+
+    if (SSL_app_data2_idx > -1) {
+        return;
+    }
+
+    /* we _do_ need to call this twice */
+    for (i = 0; i <= 1; i++) {
+        SSL_app_data2_idx =
+            SSL_get_ex_new_index(0,
+                                 "Second Application Data for SSL",
+                                 NULL, NULL, NULL);
+    }
+}
+
+void *SSL_get_app_data2(SSL *ssl)
+{
+    return (void *)SSL_get_ex_data(ssl, SSL_app_data2_idx);
+}
+
+void SSL_set_app_data2(SSL *ssl, void *arg)
+{
+    SSL_set_ex_data(ssl, SSL_app_data2_idx, (char *)arg);
+    return;
+}
+
+/* Simple echo password prompting */
+int SSL_password_prompt(tcn_pass_cb_t *data)
+{
+    int rv = 0;
+    data->password[0] = '\0';
+    if (data->cb.obj) {
+        JNIEnv *e;
+        jobject  o;
+        jstring  prompt = AJP_TO_JSTRING(data->prompt);
+        tcn_get_java_env(&e);
+        if ((o = (*e)->CallObjectMethod(e, data->cb.obj,
+                            data->cb.mid[0], prompt))) {
+            TCN_ALLOC_CSTRING(o);
+            if (J2S(o)) {
+                strncpy(data->password, J2S(o), SSL_MAX_PASSWORD_LEN);
+                data->password[SSL_MAX_PASSWORD_LEN-1] = '\0';
+                rv = (int)strlen(data->password);
+            }
+            TCN_FREE_CSTRING(o);
+        }
+    }
+    else {
+#ifdef WIN32
+        rv = WIN32_SSL_password_prompt(data);
+#else
+        EVP_read_pw_string(data->password, SSL_MAX_PASSWORD_LEN,
+                           data->prompt, 0);
+#endif
+        rv = (int)strlen(data->password);
+    }
+    if (rv > 0) {
+        /* Remove LF char if present */
+        char *r = strchr(data->password, '\n');
+        if (r) {
+            *r = '\0';
+            rv--;
+        }
+#ifdef WIN32
+        if ((r = strchr(data->password, '\r'))) {
+            *r = '\0';
+            rv--;
+        }
+#endif
+    }
+    return rv;
+}
+
+int SSL_password_callback(char *buf, int bufsiz, int verify,
+                          void *cb)
+{
+    tcn_pass_cb_t *cb_data = (tcn_pass_cb_t *)cb;
+
+    if (buf == NULL)
+        return 0;
+    *buf = '\0';
+    if (cb_data == NULL)
+        cb_data = &tcn_password_callback;
+    if (!cb_data->prompt)
+        cb_data->prompt = SSL_DEFAULT_PASS_PROMPT;
+    if (cb_data->password[0]) {
+        /* Return already obtained password */
+        strncpy(buf, cb_data->password, bufsiz);
+        buf[bufsiz - 1] = '\0';
+        return (int)strlen(buf);
+    }
+    else {
+        if (SSL_password_prompt(cb_data) > 0)
+            strncpy(buf, cb_data->password, bufsiz);
+    }
+    buf[bufsiz - 1] = '\0';
+    return (int)strlen(buf);
+}
+
+static unsigned char dh0512_p[]={
+    0xD9,0xBA,0xBF,0xFD,0x69,0x38,0xC9,0x51,0x2D,0x19,0x37,0x39,
+    0xD7,0x7D,0x7E,0x3E,0x25,0x58,0x55,0x94,0x90,0x60,0x93,0x7A,
+    0xF2,0xD5,0x61,0x5F,0x06,0xE8,0x08,0xB4,0x57,0xF4,0xCF,0xB4,
+    0x41,0xCC,0xC4,0xAC,0xD4,0xF0,0x45,0x88,0xC9,0xD1,0x21,0x4C,
+    0xB6,0x72,0x48,0xBD,0x73,0x80,0xE0,0xDD,0x88,0x41,0xA0,0xF1,
+    0xEA,0x4B,0x71,0x13
+};
+static unsigned char dh1024_p[]={
+    0xA2,0x95,0x7E,0x7C,0xA9,0xD5,0x55,0x1D,0x7C,0x77,0x11,0xAC,
+    0xFD,0x48,0x8C,0x3B,0x94,0x1B,0xC5,0xC0,0x99,0x93,0xB5,0xDC,
+    0xDC,0x06,0x76,0x9E,0xED,0x1E,0x3D,0xBB,0x9A,0x29,0xD6,0x8B,
+    0x1F,0xF6,0xDA,0xC9,0xDF,0xD5,0x02,0x4F,0x09,0xDE,0xEC,0x2C,
+    0x59,0x1E,0x82,0x32,0x80,0x9B,0xED,0x51,0x68,0xD2,0xFB,0x1E,
+    0x25,0xDB,0xDF,0x9C,0x11,0x70,0xDF,0xCA,0x19,0x03,0x3D,0x3D,
+    0xC1,0xAC,0x28,0x88,0x4F,0x13,0xAF,0x16,0x60,0x6B,0x5B,0x2F,
+    0x56,0xC7,0x5B,0x5D,0xDE,0x8F,0x50,0x08,0xEC,0xB1,0xB9,0x29,
+    0xAA,0x54,0xF4,0x05,0xC9,0xDF,0x95,0x9D,0x79,0xC6,0xEA,0x3F,
+    0xC9,0x70,0x42,0xDA,0x90,0xC7,0xCC,0x12,0xB9,0x87,0x86,0x39,
+    0x1E,0x1A,0xCE,0xF7,0x3F,0x15,0xB5,0x2B
+};
+static unsigned char dh2048_p[]={
+    0xF2,0x4A,0xFC,0x7E,0x73,0x48,0x21,0x03,0xD1,0x1D,0xA8,0x16,
+    0x87,0xD0,0xD2,0xDC,0x42,0xA8,0xD2,0x73,0xE3,0xA9,0x21,0x31,
+    0x70,0x5D,0x69,0xC7,0x8F,0x95,0x0C,0x9F,0xB8,0x0E,0x37,0xAE,
+    0xD1,0x6F,0x36,0x1C,0x26,0x63,0x2A,0x36,0xBA,0x0D,0x2A,0xF5,
+    0x1A,0x0F,0xE8,0xC0,0xEA,0xD1,0xB5,0x52,0x47,0x1F,0x9A,0x0C,
+    0x0F,0xED,0x71,0x51,0xED,0xE6,0x62,0xD5,0xF8,0x81,0x93,0x55,
+    0xC1,0x0F,0xB4,0x72,0x64,0xB3,0x73,0xAA,0x90,0x9A,0x81,0xCE,
+    0x03,0xFD,0x6D,0xB1,0x27,0x7D,0xE9,0x90,0x5E,0xE2,0x10,0x74,
+    0x4F,0x94,0xC3,0x05,0x21,0x73,0xA9,0x12,0x06,0x9B,0x0E,0x20,
+    0xD1,0x5F,0xF7,0xC9,0x4C,0x9D,0x4F,0xFA,0xCA,0x4D,0xFD,0xFF,
+    0x6A,0x62,0x9F,0xF0,0x0F,0x3B,0xA9,0x1D,0xF2,0x69,0x29,0x00,
+    0xBD,0xE9,0xB0,0x9D,0x88,0xC7,0x4A,0xAE,0xB0,0x53,0xAC,0xA2,
+    0x27,0x40,0x88,0x58,0x8F,0x26,0xB2,0xC2,0x34,0x7D,0xA2,0xCF,
+    0x92,0x60,0x9B,0x35,0xF6,0xF3,0x3B,0xC3,0xAA,0xD8,0x58,0x9C,
+    0xCF,0x5D,0x9F,0xDB,0x14,0x93,0xFA,0xA3,0xFA,0x44,0xB1,0xB2,
+    0x4B,0x0F,0x08,0x70,0x44,0x71,0x3A,0x73,0x45,0x8E,0x6D,0x9C,
+    0x56,0xBC,0x9A,0xB5,0xB1,0x3D,0x8B,0x1F,0x1E,0x2B,0x0E,0x93,
+    0xC2,0x9B,0x84,0xE2,0xE8,0xFC,0x29,0x85,0x83,0x8D,0x2E,0x5C,
+    0xDD,0x9A,0xBB,0xFD,0xF0,0x87,0xBF,0xAF,0xC4,0xB6,0x1D,0xE7,
+    0xF9,0x46,0x50,0x7F,0xC3,0xAC,0xFD,0xC9,0x8C,0x9D,0x66,0x6B,
+    0x4C,0x6A,0xC9,0x3F,0x0C,0x0A,0x74,0x94,0x41,0x85,0x26,0x8F,
+    0x9F,0xF0,0x7C,0x0B
+};
+static unsigned char dh4096_p[] = {
+    0x8D,0xD3,0x8F,0x77,0x6F,0x6F,0xB0,0x74,0x3F,0x22,0xE9,0xD1,
+    0x17,0x15,0x69,0xD8,0x24,0x85,0xCD,0xC4,0xE4,0x0E,0xF6,0x52,
+    0x40,0xF7,0x1C,0x34,0xD0,0xA5,0x20,0x77,0xE2,0xFC,0x7D,0xA1,
+    0x82,0xF1,0xF3,0x78,0x95,0x05,0x5B,0xB8,0xDB,0xB3,0xE4,0x17,
+    0x93,0xD6,0x68,0xA7,0x0A,0x0C,0xC5,0xBB,0x9C,0x5E,0x1E,0x83,
+    0x72,0xB3,0x12,0x81,0xA2,0xF5,0xCD,0x44,0x67,0xAA,0xE8,0xAD,
+    0x1E,0x8F,0x26,0x25,0xF2,0x8A,0xA0,0xA5,0xF4,0xFB,0x95,0xAE,
+    0x06,0x50,0x4B,0xD0,0xE7,0x0C,0x55,0x88,0xAA,0xE6,0xB8,0xF6,
+    0xE9,0x2F,0x8D,0xA7,0xAD,0x84,0xBC,0x8D,0x4C,0xFE,0x76,0x60,
+    0xCD,0xC8,0xED,0x7C,0xBF,0xF3,0xC1,0xF8,0x6A,0xED,0xEC,0xE9,
+    0x13,0x7D,0x4E,0x72,0x20,0x77,0x06,0xA4,0x12,0xF8,0xD2,0x34,
+    0x6F,0xDC,0x97,0xAB,0xD3,0xA0,0x45,0x8E,0x7D,0x21,0xA9,0x35,
+    0x6E,0xE4,0xC9,0xC4,0x53,0xFF,0xE5,0xD9,0x72,0x61,0xC4,0x8A,
+    0x75,0x78,0x36,0x97,0x1A,0xAB,0x92,0x85,0x74,0x61,0x7B,0xE0,
+    0x92,0xB8,0xC6,0x12,0xA1,0x72,0xBB,0x5B,0x61,0xAA,0xE6,0x2C,
+    0x2D,0x9F,0x45,0x79,0x9E,0xF4,0x41,0x93,0x93,0xEF,0x8B,0xEF,
+    0xB7,0xBF,0x6D,0xF0,0x91,0x11,0x4F,0x7C,0x71,0x84,0xB5,0x88,
+    0xA3,0x8C,0x1A,0xD5,0xD0,0x81,0x9C,0x50,0xAC,0xA9,0x2B,0xE9,
+    0x92,0x2D,0x73,0x7C,0x0A,0xA3,0xFA,0xD3,0x6C,0x91,0x43,0xA6,
+    0x80,0x7F,0xD7,0xC4,0xD8,0x6F,0x85,0xF8,0x15,0xFD,0x08,0xA6,
+    0xF8,0x7B,0x3A,0xF4,0xD3,0x50,0xB4,0x2F,0x75,0xC8,0x48,0xB8,
+    0xA8,0xFD,0xCA,0x8F,0x62,0xF1,0x4C,0x89,0xB7,0x18,0x67,0xB2,
+    0x93,0x2C,0xC4,0xD4,0x71,0x29,0xA9,0x26,0x20,0xED,0x65,0x37,
+    0x06,0x87,0xFC,0xFB,0x65,0x02,0x1B,0x3C,0x52,0x03,0xA1,0xBB,
+    0xCF,0xE7,0x1B,0xA4,0x1A,0xE3,0x94,0x97,0x66,0x06,0xBF,0xA9,
+    0xCE,0x1B,0x07,0x10,0xBA,0xF8,0xD4,0xD4,0x05,0xCF,0x53,0x47,
+    0x16,0x2C,0xA1,0xFC,0x6B,0xEF,0xF8,0x6C,0x23,0x34,0xEF,0xB7,
+    0xD3,0x3F,0xC2,0x42,0x5C,0x53,0x9A,0x00,0x52,0xCF,0xAC,0x42,
+    0xD3,0x3B,0x2E,0xB6,0x04,0x32,0xE1,0x09,0xED,0x64,0xCD,0x6A,
+    0x63,0x58,0xB8,0x43,0x56,0x5A,0xBE,0xA4,0x9F,0x68,0xD4,0xF7,
+    0xC9,0x04,0xDF,0xCD,0xE5,0x93,0xB0,0x2F,0x06,0x19,0x3E,0xB8,
+    0xAB,0x7E,0xF8,0xE7,0xE7,0xC8,0x53,0xA2,0x06,0xC3,0xC7,0xF9,
+    0x18,0x3B,0x51,0xC3,0x9B,0xFF,0x8F,0x00,0x0E,0x87,0x19,0x68,
+    0x2F,0x40,0xC0,0x68,0xFA,0x12,0xAE,0x57,0xB5,0xF0,0x97,0xCA,
+    0x78,0x23,0x31,0xAB,0x67,0x7B,0x10,0x6B,0x59,0x32,0x9C,0x64,
+    0x20,0x38,0x1F,0xC5,0x07,0x84,0x9E,0xC4,0x49,0xB1,0xDF,0xED,
+    0x7A,0x8A,0xC3,0xE0,0xDD,0x30,0x55,0xFF,0x95,0x45,0xA6,0xEE,
+    0xCB,0xE4,0x26,0xB9,0x8E,0x89,0x37,0x63,0xD4,0x02,0x3D,0x5B,
+    0x4F,0xE5,0x90,0xF6,0x72,0xF8,0x10,0xEE,0x31,0x04,0x54,0x17,
+    0xE3,0xD5,0x63,0x84,0x80,0x62,0x54,0x46,0x85,0x6C,0xD2,0xC1,
+    0x3E,0x19,0xBD,0xE2,0x80,0x11,0x86,0xC7,0x4B,0x7F,0x67,0x86,
+    0x47,0xD2,0x38,0xCD,0x8F,0xFE,0x65,0x3C,0x11,0xCD,0x96,0x99,
+    0x4E,0x45,0xEB,0xEC,0x1D,0x94,0x8C,0x53,
+};
+static unsigned char dhxxx2_g[]={
+    0x02
+};
+
+static DH *get_dh(int idx)
+{
+    DH *dh;
+
+    if ((dh = DH_new()) == NULL)
+        return NULL;
+    switch (idx) {
+        case SSL_TMP_KEY_DH_512:
+            dh->p = BN_bin2bn(dh0512_p, sizeof(dh0512_p), NULL);
+        break;
+        case SSL_TMP_KEY_DH_1024:
+            dh->p = BN_bin2bn(dh1024_p, sizeof(dh1024_p), NULL);
+        break;
+        case SSL_TMP_KEY_DH_2048:
+            dh->p = BN_bin2bn(dh2048_p, sizeof(dh2048_p), NULL);
+        break;
+        case SSL_TMP_KEY_DH_4096:
+            dh->p = BN_bin2bn(dh4096_p, sizeof(dh2048_p), NULL);
+        break;
+    }
+    dh->g = BN_bin2bn(dhxxx2_g, sizeof(dhxxx2_g), NULL);
+    if ((dh->p == NULL) || (dh->g == NULL)) {
+        DH_free(dh);
+        return NULL;
+    }
+    else
+        return dh;
+}
+
+DH *SSL_dh_get_tmp_param(int key_len)
+{
+    DH *dh;
+
+    if (key_len == 512)
+        dh = get_dh(SSL_TMP_KEY_DH_512);
+    else if (key_len == 1024)
+        dh = get_dh(SSL_TMP_KEY_DH_1024);
+    else if (key_len == 2048)
+        dh = get_dh(SSL_TMP_KEY_DH_2048);
+    else if (key_len == 4096)
+        dh = get_dh(SSL_TMP_KEY_DH_4096);
+    else
+        dh = get_dh(SSL_TMP_KEY_DH_1024);
+    return dh;
+}
+
+DH *SSL_dh_get_param_from_file(const char *file)
+{
+    DH *dh = NULL;
+    BIO *bio;
+
+    if ((bio = BIO_new_file(file, "r")) == NULL)
+        return NULL;
+    dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL);
+    BIO_free(bio);
+    return dh;
+}
+
+/*
+ * Handle out temporary RSA private keys on demand
+ *
+ * The background of this as the TLSv1 standard explains it:
+ *
+ * | D.1. Temporary RSA keys
+ * |
+ * |    US Export restrictions limit RSA keys used for encryption to 512
+ * |    bits, but do not place any limit on lengths of RSA keys used for
+ * |    signing operations. Certificates often need to be larger than 512
+ * |    bits, since 512-bit RSA keys are not secure enough for high-value
+ * |    transactions or for applications requiring long-term security. Some
+ * |    certificates are also designated signing-only, in which case they
+ * |    cannot be used for key exchange.
+ * |
+ * |    When the public key in the certificate cannot be used for encryption,
+ * |    the server signs a temporary RSA key, which is then exchanged. In
+ * |    exportable applications, the temporary RSA key should be the maximum
+ * |    allowable length (i.e., 512 bits). Because 512-bit RSA keys are
+ * |    relatively insecure, they should be changed often. For typical
+ * |    electronic commerce applications, it is suggested that keys be
+ * |    changed daily or every 500 transactions, and more often if possible.
+ * |    Note that while it is acceptable to use the same temporary key for
+ * |    multiple transactions, it must be signed each time it is used.
+ * |
+ * |    RSA key generation is a time-consuming process. In many cases, a
+ * |    low-priority process can be assigned the task of key generation.
+ * |    Whenever a new key is completed, the existing temporary key can be
+ * |    replaced with the new one.
+ *
+ * XXX: base on comment above, if thread support is enabled,
+ * we should spawn a low-priority thread to generate new keys
+ * on the fly.
+ *
+ * So we generated 512 and 1024 bit temporary keys on startup
+ * which we now just hand out on demand....
+ */
+
+RSA *SSL_callback_tmp_RSA(SSL *ssl, int export, int keylen)
+{
+    int idx;
+
+    /* doesn't matter if export flag is on,
+     * we won't be asked for keylen > 512 in that case.
+     * if we are asked for a keylen > 1024, it is too expensive
+     * to generate on the fly.
+     */
+
+    switch (keylen) {
+        case 512:
+            idx = SSL_TMP_KEY_RSA_512;
+        break;
+        case 2048:
+            idx = SSL_TMP_KEY_RSA_2048;
+            if (SSL_temp_keys[idx] == NULL)
+                idx = SSL_TMP_KEY_RSA_1024;
+        break;
+        case 4096:
+            idx = SSL_TMP_KEY_RSA_4096;
+            if (SSL_temp_keys[idx] == NULL)
+                idx = SSL_TMP_KEY_RSA_2048;
+        break;
+        case 1024:
+        default:
+            idx = SSL_TMP_KEY_RSA_1024;
+        break;
+    }
+    return (RSA *)SSL_temp_keys[idx];
+}
+
+/*
+ * Hand out the already generated DH parameters...
+ */
+DH *SSL_callback_tmp_DH(SSL *ssl, int export, int keylen)
+{
+    int idx;
+    switch (keylen) {
+        case 512:
+            idx = SSL_TMP_KEY_DH_512;
+        break;
+        case 2048:
+            idx = SSL_TMP_KEY_DH_2048;
+        break;
+        case 4096:
+            idx = SSL_TMP_KEY_DH_4096;
+        break;
+        case 1024:
+        default:
+            idx = SSL_TMP_KEY_DH_1024;
+        break;
+    }
+    return (DH *)SSL_temp_keys[idx];
+}
+
+void SSL_vhost_algo_id(const unsigned char *vhost_id, unsigned char *md, int algo)
+{
+    MD5_CTX c;
+    MD5_Init(&c);
+    MD5_Update(&c, vhost_id, MD5_DIGEST_LENGTH);
+    switch (algo) {
+        case SSL_ALGO_UNKNOWN:
+            MD5_Update(&c, "UNKNOWN", 7);
+        break;
+        case SSL_ALGO_RSA:
+            MD5_Update(&c, "RSA", 3);
+        break;
+        case SSL_ALGO_DSA:
+            MD5_Update(&c, "DSA", 3);
+        break;
+    }
+    MD5_Final(md, &c);
+}
+
+/*
+ * Read a file that optionally contains the server certificate in PEM
+ * format, possibly followed by a sequence of CA certificates that
+ * should be sent to the peer in the SSL Certificate message.
+ */
+int SSL_CTX_use_certificate_chain(SSL_CTX *ctx, const char *file,
+                                  int skipfirst)
+{
+    BIO *bio;
+    X509 *x509;
+    unsigned long err;
+    int n;
+    STACK *extra_certs;
+
+    if ((bio = BIO_new(BIO_s_file_internal())) == NULL)
+        return -1;
+    if (BIO_read_filename(bio, file) <= 0) {
+        BIO_free(bio);
+        return -1;
+    }
+    /* optionally skip a leading server certificate */
+    if (skipfirst) {
+        if ((x509 = PEM_read_bio_X509(bio, NULL, NULL, NULL)) == NULL) {
+            BIO_free(bio);
+            return -1;
+        }
+        X509_free(x509);
+    }
+    /* free a perhaps already configured extra chain */
+    extra_certs = SSL_CTX_get_extra_certs(ctx);
+    if (extra_certs != NULL) {
+        sk_X509_pop_free((STACK_OF(X509) *)extra_certs, X509_free);
+        SSL_CTX_set_extra_certs(ctx,NULL);
+    }
+    /* create new extra chain by loading the certs */
+    n = 0;
+    while ((x509 = PEM_read_bio_X509(bio, NULL, NULL, NULL)) != NULL) {
+        if (!SSL_CTX_add_extra_chain_cert(ctx, x509)) {
+            X509_free(x509);
+            BIO_free(bio);
+            return -1;
+        }
+        n++;
+    }
+    /* Make sure that only the error is just an EOF */
+    if ((err = ERR_peek_error()) > 0) {
+        if (!(   ERR_GET_LIB(err) == ERR_LIB_PEM
+              && ERR_GET_REASON(err) == PEM_R_NO_START_LINE)) {
+            BIO_free(bio);
+            return -1;
+        }
+        while (ERR_get_error() > 0) ;
+    }
+    BIO_free(bio);
+    return n;
+}
+
+static int ssl_X509_STORE_lookup(X509_STORE *store, int yype,
+                                 X509_NAME *name, X509_OBJECT *obj)
+{
+    X509_STORE_CTX ctx;
+    int rc;
+
+    X509_STORE_CTX_init(&ctx, store, NULL, NULL);
+    rc = X509_STORE_get_by_subject(&ctx, yype, name, obj);
+    X509_STORE_CTX_cleanup(&ctx);
+    return rc;
+}
+
+static int ssl_verify_CRL(int ok, X509_STORE_CTX *ctx, tcn_ssl_conn_t *con)
+{
+    X509_OBJECT obj;
+    X509_NAME *subject, *issuer;
+    X509 *cert;
+    X509_CRL *crl;
+    EVP_PKEY *pubkey;
+    int i, n, rc;
+
+    /*
+     * Determine certificate ingredients in advance
+     */
+    cert    = X509_STORE_CTX_get_current_cert(ctx);
+    subject = X509_get_subject_name(cert);
+    issuer  = X509_get_issuer_name(cert);
+
+    /*
+     * OpenSSL provides the general mechanism to deal with CRLs but does not
+     * use them automatically when verifying certificates, so we do it
+     * explicitly here. We will check the CRL for the currently checked
+     * certificate, if there is such a CRL in the store.
+     *
+     * We come through this procedure for each certificate in the certificate
+     * chain, starting with the root-CA's certificate. At each step we've to
+     * both verify the signature on the CRL (to make sure it's a valid CRL)
+     * and it's revocation list (to make sure the current certificate isn't
+     * revoked).  But because to check the signature on the CRL we need the
+     * public key of the issuing CA certificate (which was already processed
+     * one round before), we've a little problem. But we can both solve it and
+     * at the same time optimize the processing by using the following
+     * verification scheme (idea and code snippets borrowed from the GLOBUS
+     * project):
+     *
+     * 1. We'll check the signature of a CRL in each step when we find a CRL
+     *    through the _subject_ name of the current certificate. This CRL
+     *    itself will be needed the first time in the next round, of course.
+     *    But we do the signature processing one round before this where the
+     *    public key of the CA is available.
+     *
+     * 2. We'll check the revocation list of a CRL in each step when
+     *    we find a CRL through the _issuer_ name of the current certificate.
+     *    This CRLs signature was then already verified one round before.
+     *
+     * This verification scheme allows a CA to revoke its own certificate as
+     * well, of course.
+     */
+
+    /*
+     * Try to retrieve a CRL corresponding to the _subject_ of
+     * the current certificate in order to verify it's integrity.
+     */
+    memset((char *)&obj, 0, sizeof(obj));
+    rc = ssl_X509_STORE_lookup(con->ctx->crl,
+                               X509_LU_CRL, subject, &obj);
+    crl = obj.data.crl;
+
+    if ((rc > 0) && crl) {
+        /*
+         * Log information about CRL
+         * (A little bit complicated because of ASN.1 and BIOs...)
+         */
+        /*
+         * Verify the signature on this CRL
+         */
+        pubkey = X509_get_pubkey(cert);
+        rc = X509_CRL_verify(crl, pubkey);
+        /* Only refcounted in OpenSSL */
+        if (pubkey)
+            EVP_PKEY_free(pubkey);
+        if (rc <= 0) {
+            /* TODO: Log Invalid signature on CRL */
+            X509_STORE_CTX_set_error(ctx, X509_V_ERR_CRL_SIGNATURE_FAILURE);
+            X509_OBJECT_free_contents(&obj);
+            return 0;
+        }
+
+        /*
+         * Check date of CRL to make sure it's not expired
+         */
+        i = X509_cmp_current_time(X509_CRL_get_nextUpdate(crl));
+
+        if (i == 0) {
+            /* TODO: Log Found CRL has invalid nextUpdate field */
+
+            X509_STORE_CTX_set_error(ctx,
+                                     X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD);
+            X509_OBJECT_free_contents(&obj);
+            return 0;
+        }
+
+        if (i < 0) {
+            /* TODO: Log Found CRL is expired */
+            X509_STORE_CTX_set_error(ctx, X509_V_ERR_CRL_HAS_EXPIRED);
+            X509_OBJECT_free_contents(&obj);
+
+            return 0;
+        }
+
+        X509_OBJECT_free_contents(&obj);
+    }
+
+    /*
+     * Try to retrieve a CRL corresponding to the _issuer_ of
+     * the current certificate in order to check for revocation.
+     */
+    memset((char *)&obj, 0, sizeof(obj));
+    rc = ssl_X509_STORE_lookup(con->ctx->crl,
+                               X509_LU_CRL, issuer, &obj);
+
+    crl = obj.data.crl;
+    if ((rc > 0) && crl) {
+        /*
+         * Check if the current certificate is revoked by this CRL
+         */
+        n = sk_X509_REVOKED_num(X509_CRL_get_REVOKED(crl));
+
+        for (i = 0; i < n; i++) {
+            X509_REVOKED *revoked =
+                sk_X509_REVOKED_value(X509_CRL_get_REVOKED(crl), i);
+
+            ASN1_INTEGER *sn = revoked->serialNumber;
+
+            if (!ASN1_INTEGER_cmp(sn, X509_get_serialNumber(cert))) {
+                X509_STORE_CTX_set_error(ctx, X509_V_ERR_CERT_REVOKED);
+                X509_OBJECT_free_contents(&obj);
+
+                return 0;
+            }
+        }
+
+        X509_OBJECT_free_contents(&obj);
+    }
+
+    return ok;
+}
+
+/*
+ * This OpenSSL callback function is called when OpenSSL
+ * does client authentication and verifies the certificate chain.
+ */
+int SSL_callback_SSL_verify(int ok, X509_STORE_CTX *ctx)
+{
+   /* Get Apache context back through OpenSSL context */
+    SSL *ssl = X509_STORE_CTX_get_ex_data(ctx,
+                                          SSL_get_ex_data_X509_STORE_CTX_idx());
+    tcn_ssl_conn_t *con = (tcn_ssl_conn_t *)SSL_get_app_data(ssl);
+    /* Get verify ingredients */
+    int errnum   = X509_STORE_CTX_get_error(ctx);
+    int errdepth = X509_STORE_CTX_get_error_depth(ctx);
+    int verify   = con->ctx->verify_mode;
+    int depth    = con->ctx->verify_depth;
+
+    if (verify == SSL_CVERIFY_UNSET ||
+        verify == SSL_CVERIFY_NONE)
+        return 1;
+
+    if (SSL_VERIFY_ERROR_IS_OPTIONAL(errnum) &&
+        (verify == SSL_CVERIFY_OPTIONAL_NO_CA)) {
+        ok = 1;
+        SSL_set_verify_result(ssl, X509_V_OK);
+    }
+    /*
+     * Additionally perform CRL-based revocation checks
+     */
+    if (ok && con->ctx->crl) {
+        if (!(ok = ssl_verify_CRL(ok, ctx, con))) {
+            errnum = X509_STORE_CTX_get_error(ctx);
+            /* TODO: Log something */
+        }
+    }
+    /*
+     * If we already know it's not ok, log the real reason
+     */
+    if (!ok) {
+        /* TODO: Some logging
+         * Certificate Verification: Error
+         */
+        if (con->peer) {
+            X509_free(con->peer);
+            con->peer = NULL;
+        }
+    }
+    if (errdepth > depth) {
+        /* TODO: Some logging
+         * Certificate Verification: Certificate Chain too long
+         */
+        ok = 0;
+    }
+    return ok;
+}
+
+#else
+/* OpenSSL is not supported
+ * If someday we make OpenSSL optional
+ * APR_ENOTIMPL will go here
+ */
+#error "No OpenSSL Toolkit defined."
+#endif

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/src/stdlib.c
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/src/stdlib.c	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/src/stdlib.c	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,119 @@
+/* Copyright 2000-2005 The Apache Software Foundation
+ *
+ * Licensed 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.
+ */
+
+/*
+ *
+ * @author Mladen Turk
+ * @version $Revision: 300969 $, $Date: 2005-07-12 09:56:11 -0500 (Tue, 12 Jul 2005) $
+ */
+ 
+#include "tcn.h"
+
+extern int tcn_parent_pid;
+
+TCN_IMPLEMENT_CALL(jlong, Stdlib, malloc)(TCN_STDARGS, jint size)
+{
+    UNREFERENCED_STDARGS;
+    if (size)
+        return P2J(malloc((size_t)size));
+    else
+        return 0;
+}
+
+TCN_IMPLEMENT_CALL(jlong, Stdlib, realloc)(TCN_STDARGS, jlong mem, jint size)
+{
+    void *ptr = J2P(mem, void *);
+    UNREFERENCED_STDARGS;
+    if (size)
+        return P2J(realloc(ptr, (size_t)size));
+    else
+        return 0;
+}
+
+TCN_IMPLEMENT_CALL(jlong, Stdlib, calloc)(TCN_STDARGS, jint num, jint size)
+{
+    UNREFERENCED_STDARGS;
+    if (num && size)
+        return P2J(calloc((size_t)num, (size_t)size));
+    else
+        return 0;
+}
+
+TCN_IMPLEMENT_CALL(void, Stdlib, free)(TCN_STDARGS, jlong mem)
+{
+    void *ptr = J2P(mem, void *);
+
+    UNREFERENCED_STDARGS;
+    if (ptr)
+        free(ptr);
+}
+
+TCN_IMPLEMENT_CALL(jboolean, Stdlib, memread)(TCN_STDARGS,
+                                              jbyteArray dst,
+                                              jlong src, jint sz)
+{
+    jbyte *s = J2P(src, jbyte *);
+    jbyte *dest = (*e)->GetPrimitiveArrayCritical(e, dst, NULL);
+
+    UNREFERENCED(o);
+    if (s && dest) {
+        memcpy(dest, s, (size_t)sz);
+        (*e)->ReleasePrimitiveArrayCritical(e, dst, dest, 0);
+        return JNI_TRUE;
+    }
+    else
+        return JNI_FALSE;
+}
+
+TCN_IMPLEMENT_CALL(jboolean, Stdlib, memwrite)(TCN_STDARGS, jlong dst,
+                                               jbyteArray src, jint sz)
+{
+    jbyte *dest = J2P(dst, jbyte *);
+    jbyte *s = (*e)->GetPrimitiveArrayCritical(e, src, NULL);
+
+    UNREFERENCED(o);
+    if (s && dest) {
+        memcpy(dest, s, (size_t)sz);
+        (*e)->ReleasePrimitiveArrayCritical(e, src, s, JNI_ABORT);
+        return JNI_TRUE;
+    }
+    else
+        return JNI_FALSE;
+}
+
+TCN_IMPLEMENT_CALL(jboolean, Stdlib, memset)(TCN_STDARGS, jlong dst,
+                                             jint  c, jint sz)
+{
+    jbyte *dest = J2P(dst, jbyte *);
+
+    UNREFERENCED_STDARGS;
+    if (memset(dest, (int)c, (size_t)sz))
+        return JNI_TRUE;
+    else
+        return JNI_FALSE;
+}
+
+TCN_IMPLEMENT_CALL(jint, Stdlib, getpid)(TCN_STDARGS)
+{
+    UNREFERENCED_STDARGS;
+    return (jint)getpid();
+}
+
+TCN_IMPLEMENT_CALL(jint, Stdlib, getppid)(TCN_STDARGS)
+{
+    UNREFERENCED_STDARGS;
+    return (jint)tcn_parent_pid;
+}
+

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/src/thread.c
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/src/thread.c	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/src/thread.c	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,28 @@
+/* Copyright 2000-2005 The Apache Software Foundation
+ *
+ * Licensed 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.
+ */
+
+/*
+ *
+ * @author Mladen Turk
+ * @version $Revision: 393735 $, $Date: 2006-04-13 08:41:49 +0200 (Ä?et, 13 tra 2006) $
+ */
+
+#include "tcn.h"
+
+TCN_IMPLEMENT_CALL(jlong, Thread, current)(TCN_STDARGS)
+{
+    UNREFERENCED_STDARGS;
+    return (jlong)((unsigned long)apr_os_thread_current());
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/src/user.c
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/src/user.c	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/src/user.c	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,162 @@
+/* Copyright 2000-2005 The Apache Software Foundation
+ *
+ * Licensed 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.
+ */
+
+/*
+ *
+ * @author Mladen Turk
+ * @version $Revision: 300969 $, $Date: 2005-07-12 09:56:11 -0500 (Tue, 12 Jul 2005) $
+ */
+ 
+#include "tcn.h"
+#include "apr_user.h"
+#include "apr_network_io.h"
+
+TCN_IMPLEMENT_CALL(jlong, User, uidCurrent)(TCN_STDARGS, jlong pool)
+{
+    apr_pool_t *p = J2P(pool, apr_pool_t *);
+    apr_uid_t uid;
+    apr_gid_t gid;
+
+    UNREFERENCED(o);
+    TCN_THROW_IF_ERR(apr_uid_current(&uid, &gid, p), uid);
+
+cleanup:
+    return (jlong)uid;
+}
+
+TCN_IMPLEMENT_CALL(jlong, User, gidCurrent)(TCN_STDARGS, jlong pool)
+{
+    apr_pool_t *p = J2P(pool, apr_pool_t *);
+    apr_uid_t uid;
+    apr_gid_t gid;
+
+    UNREFERENCED(o);
+    TCN_THROW_IF_ERR(apr_uid_current(&uid, &gid, p), gid);
+
+cleanup:
+    return (jlong)gid;
+}
+
+TCN_IMPLEMENT_CALL(jlong, User, uid)(TCN_STDARGS, jstring uname, jlong pool)
+{
+    apr_pool_t *p = J2P(pool, apr_pool_t *);
+    apr_uid_t uid;
+    apr_gid_t gid;
+    TCN_ALLOC_CSTRING(uname);
+
+    UNREFERENCED(o);
+    TCN_THROW_IF_ERR(apr_uid_get(&uid, &gid, J2S(uname), p), uid);
+
+cleanup:
+    TCN_FREE_CSTRING(uname);
+    return (jlong)uid;
+}
+
+TCN_IMPLEMENT_CALL(jlong, User, usergid)(TCN_STDARGS, jstring uname,
+                                         jlong pool)
+{
+    apr_pool_t *p = J2P(pool, apr_pool_t *);
+    apr_uid_t uid;
+    apr_gid_t gid;
+    TCN_ALLOC_CSTRING(uname);
+
+    UNREFERENCED(o);
+    TCN_THROW_IF_ERR(apr_uid_get(&uid, &gid, J2S(uname), p), gid);
+
+cleanup:
+    TCN_FREE_CSTRING(uname);
+    return (jlong)gid;
+}
+
+TCN_IMPLEMENT_CALL(jlong, User, gid)(TCN_STDARGS, jstring gname, jlong pool)
+{
+    apr_pool_t *p = J2P(pool, apr_pool_t *);
+    apr_gid_t gid;
+    TCN_ALLOC_CSTRING(gname);
+
+    UNREFERENCED(o);
+    TCN_THROW_IF_ERR( apr_gid_get(&gid, J2S(gname), p), gid);
+
+cleanup:
+    TCN_FREE_CSTRING(gname);
+    return (jlong)gid;
+}
+
+TCN_IMPLEMENT_CALL(jstring, User, username)(TCN_STDARGS, jlong userid, jlong pool)
+{
+    apr_pool_t *p = J2P(pool, apr_pool_t *);
+    apr_uid_t uid = (apr_uid_t)userid;
+    char *uname = NULL;
+
+    UNREFERENCED(o);
+    TCN_THROW_IF_ERR(apr_uid_name_get(&uname, uid, p), uname);
+
+cleanup:
+    if (uname)
+        return AJP_TO_JSTRING(uname);
+    else
+        return NULL;
+}
+
+TCN_IMPLEMENT_CALL(jstring, User, groupname)(TCN_STDARGS, jlong grpid, jlong pool)
+{
+    apr_pool_t *p = J2P(pool, apr_pool_t *);
+    apr_gid_t gid = (apr_uid_t)grpid;
+    char *gname = NULL;
+
+    UNREFERENCED(o);
+    TCN_THROW_IF_ERR(apr_gid_name_get(&gname, gid, p), gname);
+
+cleanup:
+    if (gname)
+        return AJP_TO_JSTRING(gname);
+    else
+        return NULL;
+}
+
+TCN_IMPLEMENT_CALL(jint, User,uidcompare)(TCN_STDARGS, jlong left, jlong right)
+{
+
+    UNREFERENCED_STDARGS;
+    return (int)apr_uid_compare((apr_uid_t)left,
+                                (apr_uid_t)right);
+}
+
+TCN_IMPLEMENT_CALL(jint, User,gidcompare)(TCN_STDARGS, jlong left, jlong right)
+{
+
+    UNREFERENCED_STDARGS;
+    return (int)apr_gid_compare((apr_gid_t)left,
+                                (apr_gid_t)right);
+}
+
+TCN_IMPLEMENT_CALL(jstring, User, homepath)(TCN_STDARGS, jstring uname, jlong pool)
+{
+    apr_pool_t *p = J2P(pool, apr_pool_t *);
+    char *dirname = NULL;
+    TCN_ALLOC_CSTRING(uname);
+
+    UNREFERENCED(o);
+    TCN_THROW_IF_ERR(apr_uid_homepath_get(&dirname, J2S(uname),
+                                          p), dirname);
+
+cleanup:
+    TCN_FREE_CSTRING(uname);
+    if (dirname)
+        return AJP_TO_JSTRING(dirname);
+    else
+        return NULL;
+}
+

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/tcnative.dsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/tcnative.dsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/tcnative.dsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,231 @@
+# Microsoft Developer Studio Project File - Name="tcnative" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
+
+CFG=tcnative - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE 
+!MESSAGE NMAKE /f "tcnative.mak".
+!MESSAGE 
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE 
+!MESSAGE NMAKE /f "tcnative.mak" CFG="tcnative - Win32 Debug"
+!MESSAGE 
+!MESSAGE Possible choices for configuration are:
+!MESSAGE 
+!MESSAGE "tcnative - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "tcnative - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE 
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+MTL=midl.exe
+RSC=rc.exe
+
+!IF  "$(CFG)" == "tcnative - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "LibR"
+# PROP Intermediate_Dir "LibR"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MD /W3 /Zi /O2 /Oy- /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /FD /c
+# ADD CPP /nologo /MD /W3 /Zi /O2 /Oy- /I "./include" /I "../apr/include" /I "../apr/include/arch/win32" /I "$(JAVA_HOME)/include" /I "$(JAVA_HOME)/include/win32" /I "../openssl/inc32" /D "NDEBUG" /D "TCN_DECLARE_EXPORT" /D "WIN32" /D "_WINDOWS" /D "APR_DECLARE_STATIC" /D "NO_IDEA" /D "NO_RC5" /D "NO_MDC2" /D "OPENSSL_NO_IDEA" /D "OPENSSL_NO_RC5" /D "OPENSSL_NO_MDC2" /D "HAVE_OPENSSL" /D HAVE_SSL_SET_STATE=1 /Fd"LibR\tcnative_src" /FD /c
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /o /win32 "NUL"
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /o /win32 "NUL"
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib advapi32.lib ws2_32.lib mswsock.lib wldap32.lib psapi.lib ole32.lib shlwapi.lib /nologo /base:"0x6EE00000" /subsystem:windows /dll /debug /machine:I386 /opt:ref
+# ADD LINK32 kernel32.lib advapi32.lib ws2_32.lib mswsock.lib wldap32.lib psapi.lib ole32.lib shlwapi.lib libeay32.lib ssleay32.lib /nologo /base:"0x6EE00000" /subsystem:windows /dll /debug /machine:I386 /out:"LibR/tcnative-1.dll" /libpath:"../openssl/out32" /libpath:"../openssl/out32dll" /opt:ref
+
+!ELSEIF  "$(CFG)" == "tcnative - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "LibD"
+# PROP Intermediate_Dir "LibD"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MDd /W3 /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FD /c
+# ADD CPP /nologo /MDd /W4 /GX /Zi /Od /I "./include" /I "../apr/include" /I "../apr/include/arch/win32" /I "$(JAVA_HOME)/include" /I "$(JAVA_HOME)/include/win32" /I "../openssl/inc32" /D "_DEBUG" /D "TCN_DECLARE_EXPORT" /D "WIN32" /D "_WINDOWS" /D "APR_DECLARE_STATIC" /D "NO_IDEA" /D "NO_RC5" /D "NO_MDC2" /D "OPENSSL_NO_IDEA" /D "OPENSSL_NO_RC5" /D "OPENSSL_NO_MDC2" /D "HAVE_OPENSSL" /D HAVE_SSL_SET_STATE=1 /Fd"LibD\tcnative_src" /FD /c
+# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /o /win32 "NUL"
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /o /win32 "NUL"
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib advapi32.lib ws2_32.lib mswsock.lib wldap32.lib psapi.lib ole32.lib shlwapi.lib /nologo /base:"0x6EE00000" /subsystem:windows /dll /incremental:no /debug /machine:I386
+# ADD LINK32 kernel32.lib advapi32.lib ws2_32.lib mswsock.lib wldap32.lib psapi.lib ole32.lib shlwapi.lib libeay32.lib ssleay32.lib /nologo /base:"0x6EE00000" /subsystem:windows /dll /incremental:no /debug /machine:I386 /out:"LibD/tcnative-1.dll" /libpath:"../openssl/out32" /libpath:"../openssl/out32dll" 
+
+!ENDIF 
+
+# Begin Target
+
+# Name "tcnative - Win32 Release"
+# Name "tcnative - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=.\src\address.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\dir.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\error.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\file.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\info.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\jnilib.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\lock.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\misc.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\mmap.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\multicast.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\network.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\poll.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\pool.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\proc.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\shm.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\ssl.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\sslcontext.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\sslinfo.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\sslnetwork.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\sslutils.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\stdlib.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\thread.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\user.c
+# End Source File
+# End Group
+# Begin Group "Generated Files"
+
+# PROP Default_Filter ""
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=.\include\ssl_private.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\include\tcn.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\include\tcn_api.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\include\tcn_version.h
+# End Source File
+# End Group
+# Begin Group "Platform Files"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=.\os\win32\ntpipe.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\os\win32\registry.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\os\win32\system.c
+# End Source File
+# End Group
+# Begin Source File
+
+SOURCE=.\os\win32\libtcnative.rc
+# End Source File
+# End Target
+# End Project

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/tcnative.pc.in
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/tcnative.pc.in	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jni/native/tcnative.pc.in	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,13 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+TCNATIVE_MAJOR_VERSION=@TCNATIVE_MAJOR_VERSION@
+includedir=@includedir@
+
+Name: Tomcat native Java
+Description: Companion Native Java library
+Version: @TCNATIVE_DOTTED_VERSION@
+# assume that tcnative requires libapr of same major version
+Requires: apr- at TCNATIVE_MAJOR_VERSION@
+Libs: -L${libdir} -l at TCNATIVE_LIBNAME@ @TCNATIVE_EXPORT_LIBS@
+Cflags: -I${includedir}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/jni/test/org/apache/tomcat/jni/FileTestSuite.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/jni/test/org/apache/tomcat/jni/FileTestSuite.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/jni/test/org/apache/tomcat/jni/FileTestSuite.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,42 @@
+/*
+ * Copyright 1999-2005 The Apache Software Foundation.
+ * 
+ * Licensed 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.jni;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+import junit.textui.TestRunner;
+
+/**
+ * A basic test suite that tests File IO.
+ * 
+ * @author Mladen Turk
+ * @version $Revision: 300109 $, $Date: 2005-01-15 05:26:49 -0600 (Sat, 15 Jan 2005) $ 
+ * @see org.apache.tomcat.jni
+ */
+public class FileTestSuite
+{
+    
+    public static void main(String[] args) {
+        TestRunner.run(suite());
+    }
+    
+    public static Test suite()
+    {
+        TestSuite suite = new TestSuite( "Tomcat Native File IO" );
+        return suite;
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/juli/build.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/juli/build.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/juli/build.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,214 @@
+<project name="Juli" default="compile" basedir=".">
+
+
+<!--
+        "Coyote" connector framework for Jakarta Tomcat
+        $Id: build.xml 300326 2005-03-02 18:30:45Z remm $
+-->
+
+
+<!-- ========== Initialize Properties ===================================== -->
+
+
+  <property file="build.properties"/>                <!-- Component local   -->
+  <property file="../build.properties"/>             <!-- Commons local     -->
+  <property file="${user.home}/build.properties"/>   <!-- User local        -->
+
+
+<!-- ========== External Dependencies ===================================== -->
+
+
+  <!-- The directories corresponding to your necessary dependencies -->
+  <property name="junit.home"              value="/usr/local/junit3.5"/>
+
+
+<!-- ========== Derived Values ============================================ -->
+
+
+	  <property name="junit.jar"        value="${junit.home}/junit.jar"/>
+	  <property name="jmx.jar" location="../lib/mx4j.jar" />
+
+	
+<!-- ========== Component Declarations ==================================== -->
+
+
+  <!-- The name of this component -->
+  <property name="component.name"          value="juli"/>
+
+  <!-- The title of this component -->
+  <property name="component.title"         value="Java Util Logging Implementation"/>
+
+  <!-- The current version number of this component -->
+  <property name="component.version"       value="1.0-dev"/>
+
+  <!-- The base directory for compilation targets -->
+  <property name="build.home"              value="build"/>
+
+  <!-- The base directory for component configuration files -->
+  <property name="conf.home"               value="src/conf"/>
+
+  <!-- The base directory for component sources -->
+  <property name="source.home"             value="src/java"/>
+
+  <!-- The base directory for unit test sources -->
+  <property name="test.home"               value="src/test"/>
+
+<!-- ========== Compiler Defaults ========================================= -->
+
+
+  <!-- Should Java compilations set the 'debug' compiler option? -->
+  <property name="compile.debug"           value="true"/>
+
+  <!-- Should Java compilations set the 'deprecation' compiler option? -->
+  <property name="compile.deprecation"     value="false"/>
+
+  <!-- Should Java compilations set the 'optimize' compiler option? -->
+  <property name="compile.optimize"        value="true"/>
+
+  <!-- Construct compile classpath -->
+  <path id="compile.classpath">
+    <pathelement location="${build.home}/classes"/>
+    <pathelement location="${jmx.jar}"/>
+  </path>
+
+
+<!-- ========== Test Execution Defaults =================================== -->
+
+
+  <!-- Construct unit test classpath -->
+  <path id="test.classpath">
+    <pathelement location="${build.home}/classes"/>
+    <pathelement location="${build.home}/tests"/>
+    <pathelement location="${jmx.jar}"/>
+    <pathelement location="${junit.jar}"/>
+  </path>
+
+  <!-- Should all tests fail if one does? -->
+  <property name="test.failonerror"        value="true"/>
+
+
+<!-- ========== Executable Targets ======================================== -->
+
+
+  <target name="init"
+   description="Initialize and evaluate conditionals">
+    <echo message="-------- ${component.title} ${component.version} --------"/>
+    <filter  token="name"                  value="${component.name}"/>
+    <filter  token="version"               value="${component.version}"/>
+  </target>
+
+
+  <target name="prepare" depends="init"
+   description="Prepare build directory">
+    <mkdir dir="${build.home}"/>
+    <mkdir dir="${build.home}/classes"/>
+    <mkdir dir="${build.home}/conf"/>
+    <mkdir dir="${build.home}/lib"/>
+    <mkdir dir="${build.home}/docs"/>
+    <mkdir dir="${build.home}/docs/api"/>
+    <mkdir dir="${build.home}/tests"/>
+  </target>
+
+
+  <target name="static" depends="prepare"
+   description="Copy static files to build directory">
+    <tstamp/>
+    <copy  todir="${build.home}/conf" filtering="on">
+      <fileset dir="${conf.home}" includes="*.MF"/>
+    </copy>
+  </target>
+
+
+  <target name="javadoc" unless="docs-uptodate"
+   description="Create component Javadoc documentation">
+    <mkdir dir="${build.home}/docs/api"/>
+    <javadoc sourcepath="${source.home}"
+                destdir="${build.home}/docs/api"
+           packagenames="org.apache.coyote.*"
+                 author="true"
+                private="true"
+                version="true"
+               doctitle="&lt;h1&gt;${component.title}&lt;/h1&gt;"
+            windowtitle="${component.title} (Version ${component.version})"
+                 bottom="Copyright (c) 2005 - Apache Software Foundation">
+      <classpath refid="compile.classpath"/>
+    </javadoc>
+  </target>
+
+  <target name="compile-only" 
+          description="Compile shareable components">
+
+    <javac  srcdir="${source.home}"
+           destdir="${build.home}/classes"
+             debug="${compile.debug}"
+       deprecation="${compile.deprecation}"
+			source="1.4"
+          optimize="${compile.optimize}">
+      <classpath refid="compile.classpath"/>
+    </javac>
+    <copy    todir="${build.home}/classes" filtering="on">
+      <fileset dir="${source.home}" excludes="**/*.java"/>
+    </copy>
+    <property name="tomcat-juli.jar" value="${build.home}/lib/tomcat-${component.name}.jar"/>
+    <jar    jarfile="${tomcat-juli.jar}"
+             index="true"
+            basedir="${build.home}/classes"
+             manifest="${build.home}/conf/MANIFEST.MF">
+      <include name="org/apache/juli/**"/>
+    </jar>
+  </target>
+
+  <target name="compile" depends="static,compile-only"
+          description="Compile shareable components">
+  </target>
+
+
+  <target name="compile.tests" depends="compile"
+   description="Compile unit test cases">
+    <javac  srcdir="${test.home}/java"
+           destdir="${build.home}/tests"
+             debug="${compile.debug}"
+       deprecation="${compile.deprecation}"
+          optimize="${compile.optimize}">
+      <classpath refid="test.classpath"/>
+    </javac>
+    <copy    todir="${build.home}/tests" filtering="on">
+      <fileset dir="${test.home}" excludes="**/*.java"/>
+    </copy>
+  </target>
+
+
+  <target name="clean"
+   description="Clean build and distribution directories">
+    <delete    dir="${build.home}"/>
+    <delete    dir="${dist.home}"/>
+  </target>
+
+
+  <target name="all" depends="clean,compile,compile.tests"
+   description="Clean and compile all components"/>
+
+
+<!-- ========== Unit Test Targets ========================================= -->
+
+
+  <target name="test"  depends="compile.tests" if="test.entry"
+   description="Run all unit test cases">
+      <!--
+      <junit printsummary="yes" fork="on" haltonfailure="yes">
+      	<formatter type="plain" usefile="false"/>
+      	<test name="${test.entry}"/>
+        <classpath refid="test.classpath"/>
+      </junit>
+
+      <java classname="${test.runner}" fork="yes"
+       failonerror="${test.failonerror}">
+        <jvmarg value="${java.protocol.handler.pkgs}"/>
+        <arg value="${test.entry}"/>
+        <classpath refid="test.classpath"/>
+      </java>
+      -->
+  </target>
+
+
+</project>

Added: branches/tomcat5.5/upstream/5.5.20/connectors/juli/src/conf/logging.properties
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/juli/src/conf/logging.properties	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/juli/src/conf/logging.properties	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,24 @@
+handlers = org.apache.juli.FileHandler java.util.logging.ConsoleHandler
+
+############################################################
+# Handler specific properties.
+# Describes specific configuration info for Handlers.
+############################################################
+
+org.apache.juli.FileHandler.level = FINE
+org.apache.juli.FileHandler.directory = ${catalina.base}/logs
+
+java.util.logging.ConsoleHandler.level = FINE
+java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter
+
+
+############################################################
+# Facility specific properties.
+# Provides extra control for each logger.
+############################################################
+
+# For example, set the com.xyz.foo logger to only log SEVERE
+# messages:
+#org.apache.catalina.startup.ContextConfig.level = FINE
+#org.apache.catalina.startup.HostConfig.level = FINE
+#org.apache.catalina.session.ManagerBase.level = FINE

Added: branches/tomcat5.5/upstream/5.5.20/connectors/juli/src/java/org/apache/juli/ClassLoaderLogManager.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/juli/src/java/org/apache/juli/ClassLoaderLogManager.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/juli/src/java/org/apache/juli/ClassLoaderLogManager.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,566 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URLClassLoader;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Properties;
+import java.util.StringTokenizer;
+import java.util.WeakHashMap;
+import java.util.logging.Handler;
+import java.util.logging.Level;
+import java.util.logging.LogManager;
+import java.util.logging.Logger;
+
+
+/**
+ * Per classloader LogManager implementation.
+ */
+public class ClassLoaderLogManager extends LogManager {
+
+
+    // -------------------------------------------------------------- Variables
+
+
+    /**
+     * Map containing the classloader information, keyed per classloader. A
+     * weak hashmap is used to ensure no classloader reference is leaked from 
+     * application redeployment.
+     */
+    protected final Map classLoaderLoggers = new WeakHashMap();
+
+    
+    /**
+     * This prefix is used to allow using prefixes for the properties names
+     * of handlers and their subcomponents.
+     */
+    protected ThreadLocal prefix = new ThreadLocal();
+
+    
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Add the specified logger to the classloader local configuration.
+     * 
+     * @param logger The logger to be added
+     */
+    public synchronized boolean addLogger(final Logger logger) {
+
+        final String loggerName = logger.getName();
+
+        ClassLoader classLoader = 
+            Thread.currentThread().getContextClassLoader();
+        ClassLoaderLogInfo info = getClassLoaderInfo(classLoader);
+        if (info.loggers.containsKey(loggerName)) {
+            return false;
+        }
+        info.loggers.put(loggerName, logger);
+
+        // Apply initial level for new logger
+        final String levelString = getProperty(loggerName + ".level");
+        if (levelString != null) {
+            try {
+                AccessController.doPrivileged(new PrivilegedAction() {
+                    public Object run() {
+                        logger.setLevel(Level.parse(levelString.trim()));
+                        return null;
+                    }
+                });
+            } catch (IllegalArgumentException e) {
+                // Leave level set to null
+            }
+        }
+
+        // If any parent loggers have levels definied, make sure they are
+        // instantiated
+        int dotIndex = loggerName.lastIndexOf('.');
+        while (dotIndex >= 0) {
+            final String parentName = loggerName.substring(0, dotIndex);
+            if (getProperty(parentName + ".level") != null) {
+                Logger.getLogger(parentName);
+                break;
+            }
+            dotIndex = loggerName.lastIndexOf('.', dotIndex - 1);
+        }
+
+        // Find associated node
+        LogNode node = info.rootNode.findNode(loggerName);
+        node.logger = logger;
+
+        // Set parent logger
+        Logger parentLogger = node.findParentLogger();
+        if (parentLogger != null) {
+            doSetParentLogger(logger, parentLogger);
+        }
+
+        // Tell children we are their new parent
+        node.setParentLogger(logger);
+
+        // Add associated handlers, if any are defined using the .handlers property.
+        // In this case, handlers of the parent logger(s) will not be used
+        String handlers = getProperty(loggerName + ".handlers");
+        if (handlers != null) {
+            logger.setUseParentHandlers(false);
+            StringTokenizer tok = new StringTokenizer(handlers, ",");
+            while (tok.hasMoreTokens()) {
+                String handlerName = (tok.nextToken().trim());
+                Handler handler = null;
+                ClassLoader current = classLoader;
+                while (current != null) {
+                    info = (ClassLoaderLogInfo) classLoaderLoggers.get(current);
+                    if (info != null) {
+                        handler = (Handler) info.handlers.get(handlerName);
+                        if (handler != null) {
+                            break;
+                        }
+                    }
+                    current = current.getParent();
+                }
+                if (handler != null) {
+                    logger.addHandler(handler);
+                }
+            }
+        }
+
+        // Parse useParentHandlers to set if the logger should delegate to its parent.
+        // Unlike java.util.logging, the default is to not delegate if a list of handlers
+        // has been specified for the logger.
+        String useParentHandlersString = getProperty(loggerName + ".useParentHandlers");
+        if (Boolean.valueOf(useParentHandlersString).booleanValue()) {
+            logger.setUseParentHandlers(true);
+        }
+        
+        return true;
+    }
+
+    
+    /**
+     * Get the logger associated with the specified name inside 
+     * the classloader local configuration. If this returns null,
+     * and the call originated for Logger.getLogger, a new
+     * logger with the specified name will be instantiated and
+     * added using addLogger.
+     * 
+     * @param name The name of the logger to retrieve
+     */
+    public synchronized Logger getLogger(final String name) {
+        ClassLoader classLoader = Thread.currentThread()
+                .getContextClassLoader();
+        return (Logger) getClassLoaderInfo(classLoader).loggers.get(name);
+    }
+    
+    
+    /**
+     * Get an enumeration of the logger names currently defined in the 
+     * classloader local configuration.
+     */
+    public synchronized Enumeration getLoggerNames() {
+        ClassLoader classLoader = Thread.currentThread()
+                .getContextClassLoader();
+        return Collections.enumeration(getClassLoaderInfo(classLoader).loggers.keySet());
+    }
+
+    
+    /**
+     * Get the value of the specified property in the classloader local
+     * configuration.
+     * 
+     * @param name The property name
+     */    
+    public String getProperty(String name) {
+        ClassLoader classLoader = Thread.currentThread()
+            .getContextClassLoader();
+        String prefix = (String) this.prefix.get();
+        if (prefix != null) {
+            name = prefix + name;
+        }
+        ClassLoaderLogInfo info = getClassLoaderInfo(classLoader);
+        String result = info.props.getProperty(name);
+        // If the property was not found, and the current classloader had no 
+        // configuration (property list is empty), look for the parent classloader
+        // properties.
+        if ((result == null) && (info.props.isEmpty())) {
+            ClassLoader current = classLoader.getParent();
+            while (current != null) {
+                info = (ClassLoaderLogInfo) classLoaderLoggers.get(current);
+                if (info != null) {
+                    result = info.props.getProperty(name);
+                    if ((result != null) || (!info.props.isEmpty())) {
+                        break;
+                    }
+                }
+                current = current.getParent();
+            }
+            if (result == null) {
+                result = super.getProperty(name);
+            }
+        }
+        // Simple property replacement (mostly for folder names)
+        if (result != null) {
+            result = replace(result);
+        }
+        return result;
+    }
+    
+    
+    public void readConfiguration()
+        throws IOException, SecurityException {
+        
+        checkAccess();
+        
+        readConfiguration(Thread.currentThread().getContextClassLoader());
+        
+    }
+        
+    public void readConfiguration(InputStream is)
+        throws IOException, SecurityException {
+        
+        checkAccess();
+        reset();
+
+        readConfiguration(is, Thread.currentThread().getContextClassLoader());
+    
+    }
+        
+    // ------------------------------------------------------ Protected Methods
+
+
+    /**
+     * Retrieve the configuration associated with the specified classloader. If
+     * it does not exist, it will be created.
+     * 
+     * @param classLoader The classloader for which we will retrieve or build the 
+     *                    configuration
+     */
+    protected ClassLoaderLogInfo getClassLoaderInfo(ClassLoader classLoader) {
+        
+        if (classLoader == null) {
+            classLoader = ClassLoader.getSystemClassLoader();
+        }
+        ClassLoaderLogInfo info = (ClassLoaderLogInfo) classLoaderLoggers
+                .get(classLoader);
+        if (info == null) {
+            final ClassLoader classLoaderParam = classLoader;
+            AccessController.doPrivileged(new PrivilegedAction() {
+                public Object run() {
+                    try {
+                        readConfiguration(classLoaderParam);
+                    } catch (IOException e) {
+                        // Ignore
+                    }
+                    return null;
+                }
+            });
+            info = (ClassLoaderLogInfo) classLoaderLoggers.get(classLoader);
+        }
+        return info;
+    }
+
+    
+    /**
+     * Read configuration for the specified classloader.
+     * 
+     * @param classLoader 
+     * @throws IOException Errot
+     */
+    protected void readConfiguration(ClassLoader classLoader)
+        throws IOException {
+        
+        InputStream is = null;
+        // Special case for URL classloaders which are used in containers: 
+        // only look in the local repositories to avoid redefining loggers 20 times
+        if ((classLoader instanceof URLClassLoader) 
+                && (((URLClassLoader) classLoader).findResource("logging.properties") != null)) {
+            is = classLoader.getResourceAsStream("logging.properties");
+        }
+        if ((is == null) && (classLoader == ClassLoader.getSystemClassLoader())) {
+            String configFileStr = System.getProperty("java.util.logging.config.file");
+            if (configFileStr != null) {
+                try {
+                    is = new FileInputStream(replace(configFileStr));
+                } catch (IOException e) {
+                    // Ignore
+                }
+            }
+            // Try the default JVM configuration
+            if (is == null) {
+                File defaultFile = new File(new File(System.getProperty("java.home"), "lib"), 
+                    "logging.properties");
+                try {
+                    is = new FileInputStream(defaultFile);
+                } catch (IOException e) {
+                    // Critical problem, do something ...
+                }
+            }
+        }
+        
+        Logger localRootLogger = new RootLogger();
+        if (is == null) {
+            // Retrieve the root logger of the parent classloader instead
+            ClassLoader current = classLoader.getParent();
+            ClassLoaderLogInfo info = null;
+            while (current != null && info == null) {
+                info = getClassLoaderInfo(current);
+                current = current.getParent();
+            }
+            if (info != null) {
+                localRootLogger.setParent(info.rootNode.logger);
+            }
+        }
+        ClassLoaderLogInfo info = 
+            new ClassLoaderLogInfo(new LogNode(null, localRootLogger));
+        info.loggers.put("", localRootLogger);
+        classLoaderLoggers.put(classLoader, info);
+        
+        if (is != null) {
+            readConfiguration(is, classLoader);
+        }
+        
+    }
+    
+    
+    /**
+     * Load specified configuration.
+     * 
+     * @param is InputStream to the properties file
+     * @param classLoader for which the configuration will be loaded
+     * @throws IOException If something wrong happens during loading
+     */
+    protected void readConfiguration(InputStream is, ClassLoader classLoader)
+        throws IOException {
+        
+        ClassLoaderLogInfo info = 
+            (ClassLoaderLogInfo) classLoaderLoggers.get(classLoader);
+        
+        try {
+            info.props.load(is);
+        } catch (IOException e) {
+            // Report error
+            System.err.println("Configuration error");
+            e.printStackTrace();
+        } finally {
+            try {
+                is.close();
+            } catch (Throwable t) {}
+        }
+        
+        // Create handlers for the root logger of this classloader
+        String rootHandlers = info.props.getProperty(".handlers");
+        String handlers = info.props.getProperty("handlers");
+        Logger localRootLogger = info.rootNode.logger;
+        if (handlers != null) {
+            StringTokenizer tok = new StringTokenizer(handlers, ",");
+            while (tok.hasMoreTokens()) {
+                String handlerName = (tok.nextToken().trim());
+                String handlerClassName = handlerName;
+                String prefix = "";
+                if (handlerClassName.length() <= 0) {
+                    continue;
+                }
+                // Parse and remove a prefix (prefix start with a digit, such as 
+                // "10WebappFooHanlder.")
+                if (Character.isDigit(handlerClassName.charAt(0))) {
+                    int pos = handlerClassName.indexOf('.');
+                    if (pos >= 0) {
+                        prefix = handlerClassName.substring(0, pos + 1);
+                        handlerClassName = handlerClassName.substring(pos + 1);
+                    }
+                }
+                try {
+                    this.prefix.set(prefix);
+                    Handler handler = 
+                        (Handler) classLoader.loadClass(handlerClassName).newInstance();
+                    // The specification strongly implies all configuration should be done 
+                    // during the creation of the handler object.
+                    // This includes setting level, filter, formatter and encoding.
+                    this.prefix.set(null);
+                    info.handlers.put(handlerName, handler);
+                    if (rootHandlers == null) {
+                        localRootLogger.addHandler(handler);
+                    }
+                } catch (Exception e) {
+                    // Report error
+                    System.err.println("Handler error");
+                    e.printStackTrace();
+                }
+            }
+            
+            // Add handlers to the root logger, if any are defined using the .handlers property.
+            if (rootHandlers != null) {
+                StringTokenizer tok2 = new StringTokenizer(rootHandlers, ",");
+                while (tok2.hasMoreTokens()) {
+                    String handlerName = (tok2.nextToken().trim());
+                    Handler handler = (Handler) info.handlers.get(handlerName);
+                    if (handler != null) {
+                        localRootLogger.addHandler(handler);
+                    }
+                }
+            }
+            
+        }
+        
+    }
+    
+    
+    /**
+     * Set parent child relationship between the two specified loggers.
+     * 
+     * @param logger
+     * @param parent
+     */
+    protected static void doSetParentLogger(final Logger logger,
+            final Logger parent) {
+        AccessController.doPrivileged(new PrivilegedAction() {
+            public Object run() {
+                logger.setParent(parent);
+                return null;
+            }
+        });
+    }
+
+    
+    /**
+     * System property replacement in the given string.
+     * 
+     * @param str The original string
+     * @return the modified string
+     */
+    protected String replace(String str) {
+        String result = str.trim();
+        if (result.startsWith("${")) {
+            int pos = result.indexOf('}');
+            if (pos != -1) {
+                String propName = result.substring(2, pos);
+                String replacement = System.getProperty(propName);
+                if (replacement != null) {
+                    result = replacement + result.substring(pos + 1);
+                }
+            }
+        }
+        return result;
+    }
+    
+
+    // ---------------------------------------------------- LogNode Inner Class
+
+
+    protected static final class LogNode {
+        Logger logger;
+
+        protected final Map children = new HashMap();
+
+        protected final LogNode parent;
+
+        LogNode(final LogNode parent, final Logger logger) {
+            this.parent = parent;
+            this.logger = logger;
+        }
+
+        LogNode(final LogNode parent) {
+            this(parent, null);
+        }
+
+        LogNode findNode(String name) {
+            LogNode currentNode = this;
+            while (name != null) {
+                final int dotIndex = name.indexOf('.');
+                final String nextName;
+                if (dotIndex < 0) {
+                    nextName = name;
+                    name = null;
+                } else {
+                    nextName = name.substring(0, dotIndex);
+                    name = name.substring(dotIndex + 1);
+                }
+                LogNode childNode = (LogNode) currentNode.children
+                        .get(nextName);
+                if (childNode == null) {
+                    childNode = new LogNode(currentNode);
+                    currentNode.children.put(nextName, childNode);
+                }
+                currentNode = childNode;
+            }
+            return currentNode;
+        }
+
+        Logger findParentLogger() {
+            Logger logger = null;
+            LogNode node = parent;
+            while (node != null && logger == null) {
+                logger = node.logger;
+                node = node.parent;
+            }
+            return logger;
+        }
+
+        void setParentLogger(final Logger parent) {
+            for (final Iterator iter = children.values().iterator(); iter
+                    .hasNext();) {
+                final LogNode childNode = (LogNode) iter.next();
+                if (childNode.logger == null) {
+                    childNode.setParentLogger(parent);
+                } else {
+                    doSetParentLogger(childNode.logger, parent);
+                }
+            }
+        }
+
+    }
+
+
+    // -------------------------------------------- ClassLoaderInfo Inner Class
+
+
+    protected static final class ClassLoaderLogInfo {
+        final LogNode rootNode;
+        final Map loggers = new HashMap();
+        final Map handlers = new HashMap();
+        final Properties props = new Properties();
+
+        ClassLoaderLogInfo(final LogNode rootNode) {
+            this.rootNode = rootNode;
+        }
+
+    }
+
+
+    // ------------------------------------------------- RootLogger Inner Class
+
+
+    /**
+     * This class is needed to instantiate the root of each per classloader 
+     * hierarchy.
+     */
+    protected class RootLogger extends Logger {
+        public RootLogger() {
+            super("", null);
+        }
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/juli/src/java/org/apache/juli/FileHandler.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/juli/src/java/org/apache/juli/FileHandler.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/juli/src/java/org/apache/juli/FileHandler.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,266 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.io.File;
+import java.io.FileWriter;
+import java.io.PrintWriter;
+import java.sql.Timestamp;
+import java.util.logging.ErrorManager;
+import java.util.logging.Filter;
+import java.util.logging.Formatter;
+import java.util.logging.Handler;
+import java.util.logging.Level;
+import java.util.logging.LogManager;
+import java.util.logging.LogRecord;
+import java.util.logging.SimpleFormatter;
+
+/**
+ * Implementation of <b>Handler</b> that appends log messages to a file
+ * named {prefix}.{date}.{suffix} in a configured directory, with an
+ * optional preceding timestamp.
+ *
+ * @version $Revision: 300331 $ $Date: 2005-03-03 12:29:45 -0600 (Thu, 03 Mar 2005) $
+ */
+
+public class FileHandler
+    extends Handler {
+
+
+    // ------------------------------------------------------------ Constructor
+
+    
+    public FileHandler() {
+        configure();
+        open();
+    }
+    
+    
+    public FileHandler(String directory, String prefix, String suffix) {
+        this();
+        this.directory = directory;
+        this.prefix = prefix;
+        this.suffix = suffix;
+    }
+    
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The as-of date for the currently open log file, or a zero-length
+     * string if there is no open log file.
+     */
+    private String date = "";
+
+
+    /**
+     * The directory in which log files are created.
+     */
+    private String directory = null;
+
+
+    /**
+     * The prefix that is added to log file filenames.
+     */
+    private String prefix = null;
+
+
+    /**
+     * The suffix that is added to log file filenames.
+     */
+    private String suffix = null;
+
+
+    /**
+     * The PrintWriter to which we are currently logging, if any.
+     */
+    private PrintWriter writer = null;
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Format and publish a <tt>LogRecord</tt>.
+     *
+     * @param  record  description of the log event
+     */
+    public void publish(LogRecord record) {
+
+        if (!isLoggable(record)) {
+            return;
+        }
+
+        // Construct the timestamp we will use, if requested
+        Timestamp ts = new Timestamp(System.currentTimeMillis());
+        String tsString = ts.toString().substring(0, 19);
+        String tsDate = tsString.substring(0, 10);
+
+        // If the date has changed, switch log files
+        if (!date.equals(tsDate)) {
+            synchronized (this) {
+                if (!date.equals(tsDate)) {
+                    close();
+                    date = tsDate;
+                    open();
+                }
+            }
+        }
+
+        String result = null;
+        try {
+            result = getFormatter().format(record);
+        } catch (Exception e) {
+            reportError(null, e, ErrorManager.FORMAT_FAILURE);
+            return;
+        }
+        
+        try {
+            writer.write(result);
+            writer.flush();
+        } catch (Exception e) {
+            reportError(null, e, ErrorManager.WRITE_FAILURE);
+            return;
+        }
+        
+    }
+    
+    
+    // -------------------------------------------------------- Private Methods
+
+
+    /**
+     * Close the currently open log file (if any).
+     */
+    public void close() {
+        
+        try {
+            if (writer == null)
+                return;
+            writer.write(getFormatter().getTail(this));
+            writer.flush();
+            writer.close();
+            writer = null;
+            date = "";
+        } catch (Exception e) {
+            reportError(null, e, ErrorManager.CLOSE_FAILURE);
+        }
+        
+    }
+
+
+    /**
+     * Flush the writer.
+     */
+    public void flush() {
+
+        try {
+            writer.flush();
+        } catch (Exception e) {
+            reportError(null, e, ErrorManager.FLUSH_FAILURE);
+        }
+        
+    }
+    
+    
+    /**
+     * Configure from <code>LogManager</code> properties.
+     */
+    private void configure() {
+
+        Timestamp ts = new Timestamp(System.currentTimeMillis());
+        String tsString = ts.toString().substring(0, 19);
+        date = tsString.substring(0, 10);
+
+        LogManager manager = LogManager.getLogManager();
+        String className = FileHandler.class.getName();
+        
+        ClassLoader cl = Thread.currentThread().getContextClassLoader();
+        
+        // Retrieve configuration of logging file name
+        directory = getProperty(className + ".directory", "logs");
+        prefix = getProperty(className + ".prefix", "juli.");
+        suffix = getProperty(className + ".suffix", ".log");
+
+        // Get logging level for the handler
+        setLevel(Level.parse(getProperty(className + ".level", "" + Level.ALL)));
+
+        // Get filter configuration
+        String filterName = getProperty(className + ".filter", null);
+        if (filterName != null) {
+            try {
+                setFilter((Filter) cl.loadClass(filterName).newInstance());
+            } catch (Exception e) {
+                // Ignore
+            }
+        }
+
+        // Set formatter
+        String formatterName = getProperty(className + ".formatter", null);
+        if (formatterName != null) {
+            try {
+                setFormatter((Formatter) cl.loadClass(formatterName).newInstance());
+            } catch (Exception e) {
+                // Ignore
+            }
+        } else {
+            setFormatter(new SimpleFormatter());
+        }
+        
+        // Set error manager
+        setErrorManager(new ErrorManager());
+        
+    }
+
+    
+    private String getProperty(String name, String defaultValue) {
+        String value = LogManager.getLogManager().getProperty(name);
+        if (value == null) {
+            value = defaultValue;
+        } else {
+            value = value.trim();
+        }
+        return value;
+    }
+    
+    
+    /**
+     * Open the new log file for the date specified by <code>date</code>.
+     */
+    private void open() {
+
+        // Create the directory if necessary
+        File dir = new File(directory);
+        dir.mkdirs();
+
+        // Open the current log file
+        try {
+            String pathname = dir.getAbsolutePath() + File.separator +
+                prefix + date + suffix;
+            writer = new PrintWriter(new FileWriter(pathname, true), true);
+            writer.write(getFormatter().getHead(this));
+        } catch (Exception e) {
+            reportError(null, e, ErrorManager.OPEN_FAILURE);
+            writer = null;
+        }
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/procrun/README.txt
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/procrun/README.txt	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/procrun/README.txt	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,12 @@
+
+Placeholder for procrun binaries used for Tomcat 5.x
+
+Rename binaries to reflect default service name:
+  prunsrv.exe -> tomcat5.exe
+  prunmgr.exe -> tomcat5w.exe
+
+Documentation for the commons-daemon project, which is
+where procrun comes from, is at
+http://jakarta.apache.org/commons/daemon.  That site
+has links to the CVS repository and the source code for
+the project.

Added: branches/tomcat5.5/upstream/5.5.20/connectors/procrun/bin/tomcat5.exe
===================================================================
(Binary files differ)


Property changes on: branches/tomcat5.5/upstream/5.5.20/connectors/procrun/bin/tomcat5.exe
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: branches/tomcat5.5/upstream/5.5.20/connectors/procrun/bin/tomcat5.exe.amd64
===================================================================
(Binary files differ)


Property changes on: branches/tomcat5.5/upstream/5.5.20/connectors/procrun/bin/tomcat5.exe.amd64
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: branches/tomcat5.5/upstream/5.5.20/connectors/procrun/bin/tomcat5w.exe
===================================================================
(Binary files differ)


Property changes on: branches/tomcat5.5/upstream/5.5.20/connectors/procrun/bin/tomcat5w.exe
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: branches/tomcat5.5/upstream/5.5.20/connectors/procrun/bin/tomcat5w.exe.amd64
===================================================================
(Binary files differ)


Property changes on: branches/tomcat5.5/upstream/5.5.20/connectors/procrun/bin/tomcat5w.exe.amd64
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: branches/tomcat5.5/upstream/5.5.20/connectors/scandoc/scandoc.pl
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/scandoc/scandoc.pl	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/scandoc/scandoc.pl	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,1342 @@
+#!/usr/bin/perl
+#
+# ScanDoc - Version 0.14,  A C/C++ Embedded Documentation Analyser
+# ----------------------------------------------------------------
+#
+# Distributed under the "Artistic License".  See the file 
+# "COPYING" that accompanies the ScanDoc distribution.
+#
+# See http://scandoc.sourceforge.net/ for more information and
+# complete documentation.
+#
+# (c) 1997 - 2000 Talin and others.
+
+require "ctime.pl";
+require "getopts.pl";
+
+# 1 = on (verbose); 0 = off 
+$debug = 0;
+
+# Get the current date
+$date = &ctime(time);
+
+# Set the default tab size
+$tabSize = 4;
+
+$minorVersion = 14;
+$majorVersion = 0;
+$scandocURL   = "http://scandoc.sourceforge.net/";
+
+# Set up default templates
+&Getopts( 'i:d:p:t:' );
+
+if ($#ARGV < 0) {
+  die "Usage: -i <doc-template> -p <output-path> -t<tabsize> -d<sym>=<value> [ <input-files> ... ]\n";
+}
+
+# Read the template
+if (!defined $opt_i) {
+  $opt_i = "default.pl";
+}
+&readTemplate( $opt_i );
+
+# Set the destination path.
+$destPath = "";
+$destPath = $opt_p if (defined($opt_p));
+
+# Set the tab size.
+$tabSize = $opt_t if (defined($opt_t));
+
+# Handle defines
+if ($opt_d) {
+  foreach $def (split( /,/, $opt_d )) {
+    if ($def =~ /\s*(\w*)\=(.*)/) {
+      $${1} = $2;
+    }
+    else {
+      $${1} = 1;
+    }
+  }
+}
+
+# For each input filename, parse it
+while ($srcfile = shift(@ARGV)) {
+
+  $linenumber = 0;
+  open( FILE, $srcfile ) || die "Can't open file $srcfile\n";
+  print STDERR "Reading \"$srcfile\"\n";
+  
+  $docTag = 'description';
+  $docEmpty = 1;
+  $packageName = '.general';
+  $author = '';
+  $version = '';
+  $class = 0;
+  $_ = '';
+  
+  while (&parseDeclaration( '' )) {}
+}
+
+# Collate subclasses and associate with class record.
+foreach $className (keys %subclasses) {
+  my $class = &classRecord( $className );
+  
+  if ($class) {
+    my @subs = ();
+    # print STDERR "$className ", join( ',', @{$subclasses{ $className }} ), "\n";
+    foreach $subName ($subclasses{ $className }) {
+      if (&classRecord( $subName )) {
+	push @subs, $subName;
+      }
+      $class->{ 'subs' } = @subs;
+    }
+  }
+}
+
+# Turn packages into objects. Special case for "default" package.
+foreach $pkg (keys %packages)
+{
+  # print STDERR $pkg, "\n";
+  bless $packages{ $pkg }, PackageRecord;
+  if ($pkg eq '.general') {
+    $packages{ $pkg }{ 'name' } = "General";
+  }
+  else {
+    $packages{ $pkg }{ 'name' } = $pkg;
+  }
+  # print STDERR $packages{ $pkg }->Classes(), "\n";
+}
+
+# Execute template file
+# print STDERR $docTemplate; # For debugging
+eval $docTemplate;
+print STDERR $@;
+
+exit;
+
+# ======================= Subroutines ================================
+
+# Read a line of input, and remove blank lines and preprocessor directives.
+sub rdln {
+  my ($skip_next_line) = 0;
+  if (defined ($_)) {
+    my ($previous_line) = $_;
+    while ( (/^(\s*|\#.*)$/ || $skip_next_line ) && ($_ = <FILE>)) {
+      if ($previous_line =~ m/\\\s*/) { $skip_next_line = 1; }
+      else { $skip_next_line = 0; }
+      $previous_line = $_;
+      $linenumber++; 
+      if ($debug) { print STDERR "(0:$srcfile) $linenumber.\n"; } 
+    }
+  }
+}
+
+# Don't skip "#"
+sub rdln2 {
+  if (defined ($_)) {
+    while (/^(\s*)$/ && ($_ = <FILE>)) {$linenumber++; if ($debug) { print STDERR "(0:$srcfile) $linenumber.\n"; } }
+  }
+}
+
+# Remove comments from current line
+sub removeComment {
+  s|//.*||;
+}
+
+# parsing functions
+sub matchKW		{ &rdln; return (s/^\s*($_[0])//, $1) if defined ($_); return (0, 0); }
+#sub matchStruct		{ &rdln; return (s/^\s*(struct|class)//, $1) if defined ($_); return (0, 0); }
+#sub matchPermission	{ &rdln; return (s/^\s*(public|private|protected)// && $1) if defined ($_); return (0,0); }
+sub matchID		{ &rdln; return (s/^\s*([A-Za-z_]\w*)//, $1) if defined ($_); return (0,0); }
+sub matchColon		{ &rdln; return (s/^\s*\://) if defined ($_); return 0; }
+sub matchComma		{ &rdln; return (s/^\s*\,//) if defined ($_); return 0; }
+sub matchSemi		{ &rdln; return (s/^\s*\;//) if defined ($_); return 0; }
+sub matchRBracket	{ &rdln; return (s/^\s*\{//) if defined ($_); return 0; }
+sub matchLBracket	{ &rdln; return (s/^\s*\}//) if defined ($_); return 0; }
+sub matchRParen		{ &rdln; return (s/^\s*\(//) if defined ($_); return 0; }
+sub matchLParen		{ &rdln; return (s/^\s*\)//) if defined ($_); return 0; }
+sub matchRAngle		{ &rdln; return (s/^\s*\<//) if defined ($_); return 0; }
+sub matchLAngle		{ &rdln; return (s/^\s*\>//) if defined ($_); return 0; }
+sub matchDecl           { &rdln; return (s/^(\s*[\s\w\*\[\]\~\&\n\:]+)//, $1) if defined ($_); return (0, 0); }
+sub matchOper		{ &rdln; return (s/^\s*([\~\&\^\>\<\=\!\%\*\+\-\/\|\w]*)// && $1) if defined ($_); return 0; }
+sub matchFuncOper	{ &rdln; return (s/^\s*(\(\))// && $1) if defined ($_); return 0; }
+sub matchAny		{ &rdln; return (s/^\s*(\S+)//, $1) if defined ($_); return (0, 0); }
+sub matchChar		{ &rdln; return (s/^(.)//, $1) if defined ($_); return (0, 0); }
+sub matchChar2	        { &rdln2; return (s/^(.)//, $1) if defined ($_); return (0, 0); }
+sub matchString 	{ &rdln; return (s/^\"(([^\\\"]|(\\.)))*\"//, $1) if defined ($_); return (0, 0); }
+
+# Skip to next semicolon
+sub skipToSemi {
+  
+  while (!&matchSemi) {
+    
+    &rdln;
+    s|//.*||;			# Eat comments
+      if (&matchLBracket) {
+	&skipBody;
+	next;
+      }
+    last if !s/^\s*([^\s\{\;]+)//;
+    # print STDERR "$1 ";
+  }
+}
+
+# Skip function body
+sub skipBody {
+  local( $nest );
+  
+  $nest = 1;
+  
+  for (;;) {
+    if (&matchRBracket) { $nest++; }
+    elsif (&matchLBracket) {
+      $nest--;
+      last if !$nest;
+    }
+    else { 
+      last if ((($valid,) = &matchKW( "[^\{\}]")) && !$valid);
+    }
+  }
+}
+
+# Skip a string. (multiline)
+sub skipString {
+  local( $char, $lastchar);
+  $lastchar = "\"";
+  
+  for (;;) {
+    ($valid, $char) = &matchChar2;
+    if (($char eq "\"") && ($lastchar ne "\\")) { last; }
+    if ($lastchar eq "\\") { $lastchar = " "; }
+    else { $lastchar = $char; }
+  }
+}
+
+
+# Skip everything in parenthesis.
+sub skipParenBody {
+  local( $nest );
+  
+  $nest = 1;
+  
+  for (;;) {
+    if (&matchRParen) { $nest++; }
+    elsif (&matchLParen) {
+      $nest--;
+      last if !$nest;
+    }
+    else { 
+      last if ((($valid,) = &matchKW( "[^\(\)]")) && !$valid);
+    }
+  }
+}
+
+# Parse (*name) syntax
+sub parseParenPointer {
+
+  $parenPointerFunction = "";
+
+  if (s/^(\s*\(\s*\*)//) {
+    $decl .= $1;
+    $nest = 1;
+    
+    for (;;) {
+      # Preserve spaces, eliminate in-line comments
+      &removeComment;
+      while (s/^(\s+)//) { $decl .= $1; &rdln; }
+      
+      if (&matchRParen) { $nest++; $decl .= "("; }
+      elsif (&matchLParen) {
+	$decl .= ")";
+	$nest--;
+	last if !$nest;
+      }
+      elsif ((($valid, $d) = &matchKW( "[^\(\)]*")) && $valid) { $decl .= $d; }
+      else { last; }
+    }
+    
+    # Just in case there are array braces afterwards.
+    while ((($valid, $d) = &matchDecl) && $valid) { $decl .= $d; }
+    $parenPointerFunction = $decl;
+    $parenPointerFunction =~ s/^\s+//;	# Remove whitespace from beginning
+    $parenPointerFunction =~ s/\s+$//;	# Remove whitespace from end
+  }
+}
+
+# Parse template arguments
+sub matchAngleArgs {
+  
+  if (&matchRAngle) {
+    local ($args, $nest);
+    
+    $args = "&lt;";
+    $nest = 1;
+    
+    for (;;) {
+      if (&matchRAngle) { $nest++; $args .= "&lt;"; }
+      elsif (&matchLAngle) {
+	$nest--;
+	$args .= "&gt;";
+	last if !$nest;
+      }
+      elsif ((($valid, $d) = &matchChar) && $valid) { $args .= $d; }
+      else { last; }
+    }
+    return $args;
+  }
+  else { return ''; }
+}
+
+# convert tabs to spaces
+sub expandTabs {
+  local	($text) = @_;
+  local 	($n);
+  
+  while (($n = index($text,"\t")) >= 0) {
+    substr($text, $n, 1) = " " x ($tabSize-($n % $tabSize));
+  }
+  
+  return $text;
+}
+
+# Process a line of text from a "special" comment
+sub handleCommentLine {
+  local ($_) = @_;
+  
+  if ($docEmpty) {
+    # Eliminate blank lines at the head of the doc.
+    return if (/^\s*$/);
+  }
+  
+  # First, expand tabs.
+  $_ = &expandTabs( $_ );
+	
+  # Remove gratuitous \s*\s  (james)
+  s/(^|\n)\s*\*\s/$1/g;
+  
+  # If it's one of the standard tags
+  if (s/^\s*\@(see|package|version|author|param|return|result|exception|keywords|deffunc|defvar|heading|todo)\s*//) {
+    my $tag = $1;
+    $tag = 'return' if ($tag eq 'result');
+    
+    # for param and exception, split the param name and the text
+    # seperate them with tabs.
+    if ($tag eq "param" || $tag eq "exception") {
+      s/^\s*(\w+)\s*(.*)/\t$1\t$2/;
+    }
+    elsif ($tag eq "heading") {
+      # 'heading' is processed by the template, if at all.
+      $_ = "\@heading\t$_";
+      $tag = "description";
+    }
+    elsif ($tag eq 'todo') {
+      if ($todolist{ $srcfile } ne '') {
+	$todolist{ $srcfile } .= "\n";
+      }
+    }
+    
+    # If it's @deffunc or @defvar
+    if ($tag =~ /def(.*)/) {
+      
+      $type = $1;
+      
+      # @deffunc and @defvar force a comment to be written out as if there was a
+      # declaration.
+      # Designed for use with macros and other constructs I can't parse.
+      
+      if (/(\S+)\s+(.*)$/) {
+	$name = $1;
+	$decl = $2;
+	$dbname = &uniqueName( "$baseScope$name" );
+	
+	my $entry = { 'type'    => $type,
+		      'name'    => $name,
+		      'longname'=> $name,
+		      'fullname'=> "$name$decl",
+		      'scopename'=>"$baseScope$name",
+		      'uname'   => $dbname,
+		      'decl'    => $decl,
+		      'package' => $packageName };
+
+        bless $entry, MemberRecord;
+
+	if ($class) {
+	  $entry->{ 'class' } = "$context";
+	  $class->{ 'members' }{ $dbname } = $entry;
+	} 
+	else {
+	  $packages{ $packageName }{ 'globals' }{ $dbname } = $entry;
+	}
+	$docTag = 'description';
+	&dumpComments( $entry );
+	return;
+      }
+    }
+    elsif ($tag eq 'package') {
+      s/^\s*//;
+      s/\s*$//;
+      $packageName = $_;
+      $docTag = 'description';
+      return;
+    }
+    elsif ($tag eq 'author') {
+      $author = $_;
+      $docTag = 'description';
+      return;
+    }
+    elsif ($tag eq 'version') {
+      $version = $_;
+      $docTag = 'description';
+      return;
+    }
+    
+    $docTag = $tag;
+  }
+  elsif (/^\s*@\w+/) {
+    # any other line that begins with an @ should be inserted into the main
+    # description for later expansion.
+    $docTag = 'description';
+  }
+  
+  # "To-do" lists are handled specially, and not associated with a class.
+  if ($docTag eq 'todo') {
+    $todolist{ $srcfile } .= $_;
+    return;
+  }
+  
+  # Append to current doc tag, regardless of whether it's a new line
+  # or a continuation. Also mark this doc as non-empty.
+  $docTags{ $docTag } .= $_;
+  $docEmpty = 0;
+  
+  # @see doesn't persist.
+  if ($docTag eq 'see') { $docTag = 'description'; }
+  
+  # print STDERR ":$_";
+}
+
+# Clear doc tag information at end of class or file
+sub clearComments {
+  
+  $docTag = 'description';
+  $docEmpty = 1;
+  %docTags = ();
+}
+
+# Add doc tag information to current documented item
+sub dumpComments {
+  local ($hashref) = @_;
+  
+  if ($docEmpty == 0) {
+    
+    if ($author ne  '') { $hashref->{ 'author'  } = $author;  }
+    if ($version ne '') { $hashref->{ 'version' } = $version; }
+    $hashref->{ 'sourcefile' } = $srcfile;
+    
+    # Store the tags for this documentation into the global doc symbol table
+    foreach $key (keys %docTags) {
+      my $data = $docTags{ $key };
+
+      $data =~ s/\s*$//;
+      
+      $hashref->{ $key } = $data;
+    }
+  }
+  
+  &clearComments();
+}
+
+# Generate a unique name from the given name.
+sub uniqueName {
+  local ($name) = @_;
+  
+  # Duplicate doc entries need to be distinguished, so give them a different label.
+  while ($docs{ $name }) {
+    if ($name =~ /-(\d+)$/) {
+      $name = $` . "-" . ($1 + 1);
+    }
+    else { $name .= "-2"; }
+  }
+  
+  $docs{ $name } = 1;
+  return $name;
+}
+
+# Get the current class record.
+sub classRecord {
+  local ($className) = @_;
+  local ($pkg) = $classToPackage{ $className };
+  
+  if ($pkg) {
+    return $packages{ $pkg }{ 'classes' }{ $className };
+  }
+  return 0;
+}
+
+# Parse a declaration in the file
+sub parseDeclaration {
+  
+  local ($context) = @_;
+  local ($baseScope) = '';
+  local ($decl);
+  my ($token);
+  
+  if ($context) { $baseScope = $context . "::"; }
+  
+  &rdln;
+
+  if (!defined ($_)) { return 0; }
+  
+  if (s|^\s*//\*\s+||) {
+    # Special C++ comment
+    &handleCommentLine( $' );
+    $_ = ''; &rdln;
+  }	
+  elsif (s|^\s*//||) { 
+    # Ordinary C++ comment
+    $_ = '';
+    &rdln;
+  }
+  elsif (s|^\s*\/\*\*\s+||) {
+    # Special C comments
+    
+    s/\={3,}|\-{3,}|\*{3,}//;			# Eliminate banner strips
+    $text = '';
+    $docTag = 'description';
+    
+    # Special comment
+    while (!/\*\//) { &handleCommentLine( $_ ); $text .= $_; $_ = <FILE>; $linenumber++; if ($debug) { print STDERR "(1) $linenumber\n."; }}
+    s/\={3,}|\-{3,}|\*{3,}//;			# Eliminate banner strips
+    /\*\//;
+    &handleCommentLine( $` );
+    $text.= $`; $_ = $';
+  }
+  elsif (s|^\s*\/\*||) {
+    # Ordinary C comment
+    $text = "";
+    
+    while (!/\*\//) { $text .= $_; $_ = <FILE>; $linenumber++; if ($debug) { print STDERR "(2) $linenumber\n."; }}
+    /\*\//;
+    $text.= $`; $_ = $';
+  }
+  elsif ((($valid, $tag) = &matchKW( "template")) && $valid) {
+    # Template definition
+    $args = &matchAngleArgs;
+    &rdln;
+    
+    ##$tmplParams = $args; JAMES
+    $result = &parseDeclaration( $context );
+    ##$tmplParams = ''; JAMES
+    return $result;
+  }
+  elsif ((($valid, $tag) = &matchKW("class|struct")) && $valid) {
+    # Class or structure definition
+    local ($className,$class);
+    
+    if ((($valid, $className) = &matchID) && $valid) {
+      
+      return 1 if (&matchSemi);		# Only a struct tag
+      
+      # A class instance
+      if ((($valid,)=&matchID) && $valid) {
+	&matchSemi;
+	return 1;
+      }
+      
+      my $fullName = "$baseScope$className"; ##$tmplParams"; JAMES
+      # print STDERR "CLASS $fullName\n";
+      
+      my @bases = ();
+      
+      if (&matchColon) {
+	
+	for (;;) {
+	  my $p;
+	  &matchKW( "virtual" );
+	  $perm = "private";
+	  if ((($valid, $p) = &matchKW( "public|private|protected" )) && $valid) { $perm = $p; }
+	  &matchKW( "virtual" );
+	  
+	  last if !(  (($valid, $base) = &matchID) && $valid  );
+	  
+	  push @bases, $base;
+	  push @{ $subclasses{ $base } }, $fullName;
+	  # print STDERR " : $perm $base\n";
+	  last if !&matchComma;
+	}
+      }
+      
+      #	print STDERR "\n";
+      # print STDERR "parsing class $fullName\n";
+
+      if ($docEmpty == 0) {
+	$class = { 'type'    => $tag,
+		   'name'    => $fullName,
+		   'longname'=> "$tag $className",
+		   'fullname'=> "$tag $className",
+		   'scopename'=> "$tag $fullName",
+		   'uname'   => $fullName,
+		   'bases'   => \@bases,
+		   'package' => $packageName,
+		   'members' => {} };
+	
+	# print STDERR "$className: @bases\n";
+	
+	bless $class, ClassRecord;
+	
+	print STDERR "   parsing class $fullName\n";
+	# $classToPackage{ $className } = $packageName;
+	$classToPackage{ $fullName } = $packageName;
+	# $classList{ $className } = $class;
+	$classList{ $fullName } = $class;
+	$packages{ $packageName }{ 'classes' }{ $fullName } = $class;
+	&dumpComments( $class );
+      }
+      
+      if (&matchRBracket) {
+	local ($perm) = ("private");
+	
+	while (!&matchLBracket) {
+	  my $p;
+	  if ((($valid, $p) = &matchKW( "public\:|private\:|protected\:" )) && $valid) {
+	    $perm = $p;
+	  }
+	  else {
+	    &parseDeclaration( $fullName )
+	      || die "Unmatched brace! line = $linenumber\n";
+	  }
+	}
+	
+	&matchSemi;
+      }
+      
+      &clearComments;
+    }
+  }
+  elsif ( ((($valid,)=&matchKW( "enum")) && $valid) || ((($valid,)=&matchKW( "typedef" )) && $valid)) {
+    &skipToSemi;
+  }
+  elsif ((($valid,)=&matchKW( "friend\s*class" )) && $valid) {
+    &skipToSemi;
+  }
+  elsif ((($valid, $token) = &matchKW("extern\\s*\\\"C\\\"")) && $valid) {
+    &matchRBracket;
+    while (!&matchLBracket) {
+      &parseDeclaration( '' ) || die "Unmatched brace! line = $linenumber\n";
+    }
+    &matchSemi;
+  }
+  # elsif ($kw = &matchID) {
+  #   $type = "$kw ";
+  #
+  #   if ($kw =~/virtual|static|const|volatile/) {
+  #	$type .= &typ;
+  #   }
+  # }
+  elsif ((($valid, $decl) = &matchDecl) && $valid) {
+    my ($instanceClass) = "";
+    
+    # print STDERR "DECLARATION=$decl, REST=$_, baseScope=$baseScope\n";
+
+    return 1 if ($decl =~ /^\s*$/);
+
+    if (!($class)) {
+      if ($decl =~ s/(\S*\s*)(\S+)\:\:(\S+)\s*$/$1$3/) {
+        $instanceClass = $2;
+      }
+    }
+
+    # Eliminate in-line comments
+    &removeComment;
+    
+    # Check for multi-line declaration
+    while ((($valid, $d) = &matchDecl) && $valid) { $decl .= $d; }
+    
+    # Handle template args, but don't let operator overloading confuse us!
+    $tempArgs = '';
+    if (!($decl =~ /\boperator\b/) && ($tempArgs = &matchAngleArgs)) {
+      $tempArgs = $decl . $tempArgs;
+      $decl = '';
+      while ((($valid, $d) = &matchDecl) && $valid) { $decl .= $d; }
+    }
+    
+    # Look for (*name) syntax
+    &parseParenPointer;
+    
+    # Special handling for operator... syntax
+    $oper = "";
+    if ($decl =~ s/\boperator\b(.*)/operator/) {
+      $oper = $1;
+      $oper .= &matchOper;
+      # If, after all that there's no opers, then try a () operator
+      if (!($oper =~ /\S/)) { $oper .= &matchFuncOper; }
+    }
+
+    ($type,$mod,$decl) = $decl =~ /([\s\w]*)([\s\*\&]+\s?)(\~?\w+(\[.*\])*)/;
+    
+    if ($parenPointerFunction) {
+      $decl=$parenPointerFunction;
+    }
+    
+    $type = $tempArgs . $type;
+    $decl .= $oper;
+    
+    if ($mod =~ /\s/) { $type .= $mod; $mod = ""; }
+    
+    for (;;) {
+      
+      # print STDERR "Looping: $type/$mod/$decl\n";
+      
+      if (&matchRParen) {
+	$nest = 1;
+	$args = "";
+	
+	for (;;) {
+	  # print STDERR "Argloop $_\n";
+	  
+	  # Process argument lists.
+	  
+	  # Preserve spaces, eliminate in-line comments
+	  # REM: Change this to save inline comments and automatically
+	  # generate @param clauses
+	  s|//.*||;
+	  while (s/^(\s+)//) { $args .= " "; &rdln; }
+	  
+	  if (&matchRParen) { $nest++; $args .= "("; }
+	  elsif (&matchLParen) {
+	    $nest--;
+	    last if !$nest;
+	    $args .= ")";
+	  }
+	  elsif ((($valid, $d) = &matchKW( "[\,\=\.\:\-]" )) && $valid) { $args .= $d; }
+	  elsif ((($valid, $d) = &matchDecl) && $valid) { $args .= $d; }
+	  elsif ((($valid, $d) = &matchAngleArgs) && $valid) { $args .= $d; }
+	  elsif ((($valid, $d) = &matchString) && $valid) { $args .= "\"$d\""; }
+	  else { last; }
+	}
+				
+	# print STDERR "$type$mod$baseScope$decl($args);\n";
+	
+	&matchKW( "const" );
+	
+	# Search for any text within the name field
+	# if ($docTag && $decl =~ /\W*(~?\w*).*/)
+	if ($docEmpty == 0) {
+	  $type =~ s/^\s+//;
+	  $mod  =~ s/\&/\&amp;/g;
+	  $args =~ s/\&/\&amp;/g;
+	  $args =~ s/\s+/ /g;
+	  $dbname = &uniqueName( "$baseScope$decl" );
+	  
+	  my $entry = { 'type'    => 'func',
+			'name'    => $decl,
+			'longname'=> "$decl()",
+			'fullname'=> "$type$mod$decl($args)",
+			'scopename'=>"$type$mod$baseScope$decl($args)",
+			'uname'   => $dbname,
+			'decl'    => "$type$mod$decl($args)",
+			'package' => $packageName };
+	  
+	  bless $entry, MemberRecord;
+	  
+	  if ($class) {
+	    $entry->{ 'class' } = "$context";
+	    $class->{ 'members' }{ $dbname } = $entry;
+	  }
+	  elsif ($instanceClass) {
+	    $class = &classRecord ($instanceClass);
+	    if (!($class)) {
+	      print STDERR "WARNING: Skipping \"$instanceClass\:\:$decl\".  Class \"$instanceClass\" not declared ($linenumber).\n";
+	    } else {
+	      $entry->{ 'class' } = "$instanceClass";
+	      $class->{ 'members' }{ $dbname } = $entry;
+	      $class = 0;
+	    }
+	  }
+	  else {
+	    $packages{ $packageName }{ 'globals' }{ $dbname } = $entry;
+	  }
+	  &dumpComments( $entry );
+	}
+	else { &clearComments; }
+	
+	s|//.*||;
+	
+	# Constructor super-call syntax
+	if (&matchColon) {
+	  
+	  # Skip over it.
+	  for (;;) {
+	    &rdln;
+	    last if /^\s*(\{|\;)/;
+	    last if !((($valid,)=&matchAny) && $valid);
+	  }
+	}
+	
+	last if &matchSemi;
+	if (&matchRBracket) { &skipBody; last; }
+	last if !&matchComma;
+	last if !((($valid, $decl) = &matchDecl) && $valid);
+	
+	# Look for (*name) syntax
+	&parseParenPointer;
+	
+	$decl =~ s/^\s*//;
+	$oper = "";
+	if ($decl =~ /\boperator\b/) {
+	  $decl =~ s/\boperator\b(.*)/operator/;
+	  $oper = $1 . &matchOper;
+	}
+	($mod,$d) = $decl =~ /^\s*([\*\&]*)\s*(\~?\w+(\[.*\])*)/;
+	$decl .= $oper;
+	$decl = $d if $d ne "";
+      }
+      else {
+	s|//.*||;
+	
+	$final = 0;
+	
+	if ((($valid,)=&matchKW( "\=" )) && $valid) {
+	  for (;;) {
+	    
+	    if (&matchRBracket) {
+	      &skipBody;
+	      $final = 1;
+	      last;
+	    }
+	    
+	    if (&matchSemi) {
+	      $final = 1;
+	      last;
+	    }
+	    
+	    # var = new ... (...)
+	    if ((($valid,)=&matchKW("new")) && $valid) {
+	      &matchKW("[A-Za-z_0-9 ]*");
+	      if (&matchRParen) {
+	        &skipParenBody;
+	      }
+	    }
+	    
+	    # var = (.....) ...
+	    if (&matchRParen) {
+	      &skipParenBody;
+	    }
+	    
+	    # var = ... * ...
+	    &matchKW ("[\/\*\-\+]*");
+	    
+	    # var = "..."
+	    if ((($valid,) = &matchKW ("[\"]")) && $valid) {
+	      &skipString;
+	    }
+	    #&matchString;
+	    
+	    last if /^\s*,/;
+	    #last if !((($valid,)=&matchAny) && $valid);
+	    last if !((($valid,)=&matchKW("[A-Za-z_0-9 \-]*")) && $valid);
+	    if (&matchSemi) {
+	        $final = 1;
+	        last;
+	    }
+	  }
+	}
+	
+	s|//.*||;
+	
+	# void ~*&foo[];
+	# void foo[];
+	# void far*foo[];
+	# print STDERR "Decl: $type$mod$baseScope$decl;\n";
+
+	# Search for any text within the name field
+	if ($docEmpty == 0 && ($decl =~ /\W*(~?\w*).*/))
+	  {
+	    $mod  =~ s/\&/\&amp;/g;
+	    $name = $decl;
+	    
+	    $dbname = &uniqueName( "$baseScope$1" );
+	    
+	    my $entry = { 'type'     => 'var',
+			  'name'     => $1,
+			  'longname' => "$name",
+			  'fullname' => "$type$mod$decl",
+			  'scopename'=> "$baseScope$type$mod$decl",
+			  'uname'    => $dbname,
+			  'decl'     => "$type$mod$decl",
+			  'package'  => $packageName };
+	    
+	    bless $entry, MemberRecord;
+	    
+	    if ($class) {
+	      $entry->{ 'class' } = "$context";
+	      $class->{ 'members' }{ $dbname } = $entry;
+	    }
+	    else {
+	      $packages{ $packageName }{ 'globals' }{ $dbname } = $entry;
+	    }
+	    &dumpComments( $entry );
+	  }
+	else { &clearComments; }
+	
+	last if $final;
+	last if &matchSemi;
+	last if !&matchComma;
+	last if !((($valid, $decl) = &matchDecl) && $valid);
+	
+	# Look for (*name) syntax
+	&parseParenPointer;
+	
+	$decl =~ s/^\s*//;
+	($mod,$d) = $decl =~ /^\s*([\*\&]*)(\~?\w+(\[.*\])*)/;
+	$decl = $d if $d ne "";
+      }
+    }
+  }
+  elsif ($context ne "" && /^\s*\}/) {
+    # print STDERR "Popping!\n";
+    return 1;
+  }
+  elsif (&matchRBracket) {
+    &skipBody;
+  }
+  elsif ((($valid, $token) = &matchAny) && $valid) {
+    # Comment in for debugging
+    # print STDERR "token: $token \n";
+  }
+  else { return 0; }
+  
+  return 1;
+}
+
+# read a file into a string ( filename, default-value )
+sub readFile {
+  local ( $filename, $result ) = @_;
+  
+  if ($filename && open( FILE, $filename )) {
+    $result = "";
+    while (<FILE>) { $result .= $_; }
+    close( FILE );
+  }
+  return $result;
+}
+
+# Read the entire document template and translate into PERL code.
+sub readTemplate {
+  local ( $filename ) = @_;
+  $docTemplate = '';
+  $indent = '';
+  $literal = 1;  # We're in literal mode.
+  
+  if (!-e $filename) {
+    if (-e "./templates/$filename") { $filename = "./templates/$filename"; }
+    elsif (-e "../templates/$filename") { $filename = "../templates/$filename"; }
+    else { die "Could not find template '$filename'.\n"; }
+  }
+  
+  open( FILE, $filename ) || die "Error opening '$filename'.\n";
+  while (<FILE>) {
+    last if (/END/);
+    
+    # if we found a code entry.
+    for (;;) {
+      &expandTabs( $_ );
+      if ($literal) {
+	# Check for beginning of code block.
+	if (s/^(.*)\<\<//) {
+	  $line = $1; 
+	  if (substr( $line, 0, length( $indent ) ) eq $indent) {
+	    substr( $line, 0, length( $indent ) ) = '';
+	  }
+	  
+	  if ($line ne '') {
+	    $line =~ s/\"/\\\"/g;
+	    $line =~ s/\$\((\w+)\.(\w+)\)/\" \. \$$1->$2() \. \"/g;
+	    $docTemplate .= "${indent}print\"$line\";";
+	  }
+	  # else { $docTemplate .= "\n"; }
+	  $literal = 0;
+	}
+	else {
+	  if (substr( $_, 0, length( $indent ) ) eq $indent) {
+	    substr( $_, 0, length( $indent ) ) = "";
+	  }
+	  chop;
+	  s/\"/\\\"/g;
+	  s/\$\((\w+)\.(\w+)\)/\" \. \$$1->$2() \. \"/g;
+	  $_ = $indent . "print \"" . $_ . "\\n\";\n";
+	  last;
+	}
+      }
+      else {
+	# Check for beginning of literal block.
+	if (s/^(\s*)\>\>//) {
+	  $indent = $1;
+	  $literal = 1;
+	}
+	elsif (s/^(\s*)(.*)\>\>//) {
+	  $docTemplate .= "$indent$2";
+	  $literal = 1;
+	}
+	else {
+	  last;
+	}
+      }
+    }
+    
+    $docTemplate .= $_;
+  }
+  close( FILE );
+  # print $docTemplate;
+}
+
+# Functions intended to be called from doc template file.
+
+# Open a new output file
+sub file {
+  my $mfile = $_[ 0 ];
+  
+  open( STDOUT, ">$destPath$mfile" ) || die "Error writing to '$mfile'\n";
+}
+
+# return list of package objects
+sub packages {
+  my ($p, @r);
+  @r = ();
+  
+  foreach $p (sort keys %packages) {
+    push @r, $packages{ $p };
+  }
+  return @r;
+}
+
+# return list of source files which have to-do lists
+sub todolistFiles {
+  my ($p, @r);
+  @r = ();
+  
+  foreach $p (sort keys %todolist) {
+    push @r, $p;
+  }
+  return @r;
+}
+
+# return list of tab-delimited to-do-list texts.
+sub todolistEntries {
+  local $_ = $todolist{ $_[0] };
+  s/^\s+//;				# Remove whitespace from beginning
+  s/\s+$/\n/;				# Remove whitespace from end
+  return split( /\n/, $_ );
+}
+
+# Convert package name to URL.
+sub packageURL {
+  my $p = $_[0];
+  
+  if ($p eq 'General') { $p = '.general'; }
+  if ($p eq '') { $p = '.general'; }
+  
+  if (ref $packages{ $p }) {
+    return $packages{ $p }->url();
+  }
+  return 0;
+}
+
+# Get the see-also list for an object
+sub seealsoList {
+  my $self = shift;
+  my ($see, $name, $url, $p, @r);
+  @r = ();
+  
+  if (defined ($self->{ 'see' })) {
+    foreach $_ (split(/\n/,$self->{ 'see' })) {
+      
+      if (/^\<a\s+href/) { # if already an HREF.
+	$name = $_;
+	$url = 0;
+      }
+      elsif (/([^\#]*)\#(.*)/) { # If a package name is present
+	$url = &packageURL( $1 ) . '#' . $2;
+	$name = $2;
+      }
+      else {
+	$name = $_;
+	$url = "#$_";
+	
+	# This doesn't appear to do anything - so I commented it.  (james)
+	# Look up the package in the index and use it to construct the html filename.
+	#if (/^([^\:]*)\:\:(.*)/) {
+	#  $className = ($1 eq '') ? '' : $classToPackage{ $1 };
+	#  $p = $packageToFile{ $className };
+	#  if ($p ne '') {
+	#    $url = &packageURL( $1 ) . '#' . $_;
+	#  }
+	#}
+      }
+      
+      $url =~ s/^\:*//;		# Remove leading colons from name
+      $url =~ s/::/-/g;		# Replace :: with dash
+      
+      my $entry = { 'name' => $name,
+		    'url'  => $url };
+      
+      bless $entry, DocReference;
+      
+      push @r, $entry;
+    }
+  }
+  return @r;
+}
+
+# Class for parsed package
+package PackageRecord;
+
+sub classes {
+  my $self = shift;
+  my $classes = $self->{ 'classes' };
+  return map $classes->{ $_ }, (sort keys %$classes);
+}
+
+sub globals {
+  my $self = shift;
+  my $globals = $self->{ 'globals' };
+  return map $globals->{ $_ }, (sort keys %$globals);
+}
+
+sub globalvars {
+  my $self = shift;
+  my $globals = $self->{ 'globals' };
+  my ($p, @r);
+  @r = ();
+  
+  foreach $p (sort keys %$globals) {
+    my $m = $globals->{ $p };
+    if ($m->{ 'type' } ne 'func') { push @r, $m; }
+  }
+  return @r;
+}
+
+sub globalfuncs {
+  my $self = shift;
+  my $globals = $self->{ 'globals' };
+  my ($p, @r);
+  @r = ();
+  
+  foreach $p (sort keys %$globals) {
+    my $m = $globals->{ $p };
+    if ($m->{ 'type' } eq 'func') { push @r, $m; }
+  }
+  return @r;
+}
+
+sub name {
+  my $self = shift;
+  return $self->{ 'name' };
+}
+
+sub url {
+  my $self = shift;
+  return "default-pkg.html" if ($self->{ 'name' } eq '.general');
+  return $self->{ 'name' } . '.html';
+}
+
+sub anchor {
+  my $self = shift;
+  my $url = $self->{ 'name' };
+  return $url;
+}
+
+# Class for parsed class
+package ClassRecord;
+
+sub keywords    { return ${$_[0]}{ 'keywords' }; }
+sub author      { return ${$_[0]}{ 'author' }; }
+sub version     { return ${$_[0]}{ 'version' }; }
+sub name        { return ${$_[0]}{ 'name' }; }
+sub longname    { return ${$_[0]}{ 'longname' }; }
+sub fullname    { return ${$_[0]}{ 'fullname' }; }
+sub scopename   { return ${$_[0]}{ 'scopename' }; }
+sub sourcefile  { return ${$_[0]}{ 'sourcefile' }; }
+#sub description { return &::processDescription( ${$_[0]}{ 'description' } ); }
+sub description { return ${$_[0]}{ 'description' }; }
+sub seealso     { &::seealsoList( $_[0] ); }
+
+sub url {
+  my $self = shift;
+  return 0 unless $self->{ 'package' };
+  my $pname = ::packageURL( $self->{ 'package' } );
+  my $url = $self->{ 'uname' };
+  $url =~ s/::/-/g;
+  return "$pname#$url";
+}
+
+sub anchor {
+  my $self = shift;
+  my $url = $self->{ 'uname' };
+  $url =~ s/::/-/g;
+  return $url;
+}
+
+sub members {
+  my $self = shift;
+  my $members = $self->{ 'members' };
+  my ($p, @r);
+  @r = ();
+  
+  foreach $p (sort keys %$members) {
+    push @r, $members->{ $p };
+  }
+  return @r;
+}
+
+sub membervars {
+  my $self = shift;
+  my $members = $self->{ 'members' };
+  my ($p, @r);
+  @r = ();
+  
+  foreach $p (sort keys %$members) {
+    my $m = $members->{ $p };
+    if ($m->{ 'type' } ne 'func') { push @r, $m; }
+  }
+  return @r;
+}
+
+sub memberfuncs {
+  my $self = shift;
+  my $members = $self->{ 'members' };
+  my ($p, @r);
+  @r = ();
+  
+  foreach $p (sort keys %$members) {
+    my $m = $members->{ $p };
+    if ($m->{ 'type' } eq 'func') { push @r, $m; }
+  }
+  return @r;
+}
+
+sub baseclasses {
+  my $self = shift;
+  my $bases = $self->{ 'bases' };
+  my ($p, $class, @r);
+  @r = ();
+  
+  foreach $p (@$bases) {
+    
+    unless ($class = $::classList{ $p }) {
+      # It's one we don't know about, so just make something up
+      $class = { 'name'    => $p,
+		 'longname'=> "class $p",
+		 'fullname'=> "class $p",
+		 'scopename'=>"class $p",
+		 'uname'   => $p,
+		 'members' => {} };
+      
+      if ($::classToPackage{ $p }) {
+	$class->{ 'package' } = $::classToPackage{ $p };
+      }
+      
+      bless $class, ClassRecord;
+    }
+    push @r, $class;
+  }
+  return @r;
+}
+
+sub subclasses {
+  my $self = shift;
+  my $subs;
+  my ($p, $class, @r);
+  @r = ();
+  
+  if (defined ($self->{ 'subs' })) {
+    $subs = $self->{ 'subs' };
+    foreach $p (sort @$subs) {
+      $class = $::classList{ $p };
+      push @r, $class;
+    }
+  }
+  return @r;
+}
+
+# Class for parsed class member or global
+package MemberRecord;
+
+sub type         { return ${$_[0]}{ 'type' }; }
+sub keywords     { return ${$_[0]}{ 'keywords' }; }
+sub author       { return ${$_[0]}{ 'author' }; }
+sub version      { return ${$_[0]}{ 'version' }; }
+sub name         { return ${$_[0]}{ 'name' }; }
+sub longname     { return ${$_[0]}{ 'longname' }; }
+sub fullname     { return ${$_[0]}{ 'fullname' }; }
+sub scopename    { return ${$_[0]}{ 'scopename' }; }
+sub returnValue  { return ${$_[0]}{ 'return' }; }
+sub sourcefile   { return ${$_[0]}{ 'sourcefile' }; }
+sub description  { return ${$_[0]}{ 'description' }; }
+sub seealso      { &::seealsoList( $_[0] ); }
+
+sub url {
+  my $self = shift;
+  return 0 unless $self->{ 'package' };
+  my $pname = ::packageURL( $self->{ 'package' } );
+  my $url = $self->{ 'uname' };
+  $url =~ s/::/-/g;
+  return "$pname#$url";
+}
+
+sub anchor {
+  my $self = shift;
+  my $url = $self->{ 'uname' };
+  $url =~ s/::/-/g;
+  $url;
+}
+
+sub params {
+  my $self = shift;
+  my $params = $self->{ 'param' };
+  my @r;
+  @r = ();
+  
+  return 0 unless ($params);
+  
+  my @paramList = split( /\t/, $params );
+  
+  for ($i = 1; $i < $#paramList; $i += 2) {
+    my $entry = { 'name'        => $paramList[ $i ],
+		  'description' => $paramList[ $i + 1 ] };
+    
+    bless $entry, ArgRecord;
+    
+    push @r, $entry;
+  }
+  return @r;
+}
+
+sub exceptions {
+  my $self = shift;
+  my $params = $self->{ 'exception' };
+  my @r;
+  @r = ();
+  
+  return 0 unless ($params);
+  
+  my @paramList = split( /\t/, $params );
+  
+  for ($i = 1; $i < $#paramList; $i += 2) {
+    my $entry = { 'name'        => $paramList[ $i ],
+		  'description' => $paramList[ $i + 1 ] };
+    
+    bless $entry, ArgRecord;
+    
+    push @r, $entry;
+  }
+  return @r;
+}
+
+package ArgRecord;
+sub name        { return ${$_[0]}{ 'name' }; }
+sub description { return ${$_[0]}{ 'description' }; }
+
+package DocReference;
+sub name        { return ${$_[0]}{ 'name' }; }
+sub url         { return ${$_[0]}{ 'url' }; }

Added: branches/tomcat5.5/upstream/5.5.20/connectors/scandoc/template.pl
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/scandoc/template.pl	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/scandoc/template.pl	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,652 @@
+<<
+# Scandoc template file.
+#
+# This is an example set of templates that is designed to create several
+# different kinds of index files. It generates a "master index" which intended
+# for use with a frames browser; A "package index" which is the root page of
+# the index, and then "package files" containing documentation for all of the
+# classes within a single package.
+
+###############################################################################
+## Defaults for look and feel
+
+if ($project eq "") { $project = "WebApp Library"; }
+if ($copyright eq "") { $copyright = "2001, The Apache Software Foundation"; }
+if ($body_bgcolor eq "") { $body_bgcolor = '#ffffff'; }
+if ($body_text    eq "") { $body_text    = '#000000'; }
+if ($body_link    eq "") { $body_link    = '#0000ff'; }
+if ($body_vlink   eq "") { $body_vlink   = '#0000ff'; }
+if ($body_alink   eq "") { $body_alink   = '#0000ff'; }
+
+###############################################################################
+# Generate the frameset index                                                 #
+###############################################################################
+
+file "index.html";
+ at p = packages();
+$_ = @p[0]->url;
+s/\s/_/g;
+y/[A-Z]/[a-z]/;
+>>
+<html>
+  <head>
+    <meta http-equiv="Content-Type" content="text/html; iso-8859-1">
+    <title>$project API Documentation</title>
+  </head>
+  <frameset cols="200,*">
+    <frameset rows="150,*">
+      <frame src="packages.html">
+      <frame src="pkg.$_" name="pkg">
+    </frameset>
+    <frame src="doc.$_" name="doc">
+  </frameset>
+</html>
+<<
+
+###############################################################################
+# Generate the packages list                                                  #
+###############################################################################
+
+file "packages.html";
+>>
+<html>
+  <head>
+    <meta http-equiv="Content-Type" content="text/html; iso-8859-1">
+    <title>$project - Packages List</title>
+  </head>
+  <body link="$body_link" vlink="$body_vlink" alink="$body_alink"
+        bgcolor="$body_bgcolor" text="$body_text">
+    <font size="+1" face="arial,helvetica,sans serif">
+      <nobr><b>$project packages:</b></nobr>
+    </font>
+    <table border="0" cellspacing="0" cellpadding="0">
+      <tr>
+        <td width="10">&nbsp;</td>
+        <td>&nbsp;</td>
+      </tr>
+<<
+
+foreach $p (packages()) {
+    $_ = $p->url;
+    s/\s/_/g;
+    y/[A-Z]/[a-z]/;
+    >>
+          <tr>
+            <td width="10">&nbsp;</td>
+            <td>
+              <font face="arial,helvetica,sans serif">
+                <nobr><a href="pkg.$_" target="pkg">$(p.name)</a></nobr>
+              </font>
+            </td>
+          </tr>
+    <<
+}
+
+>>
+    </table>
+    <hr>
+    <font size="-2" face="arial,helvetica,sans serif">
+      <div align="center">
+        Copyright &copy; $copyright.<br>
+        All Rights Reserved.<br>
+      </div>
+    </font>
+  </body>
+</html>
+<<
+
+###############################################################################
+# Generate the packages table of content for each package                     #
+###############################################################################
+
+foreach $p (packages()) {
+    $_ = $p->url;
+    s/\s/_/g;
+    y/[A-Z]/[a-z]/;
+    file "pkg.$_";
+    >>
+    <html>
+      <head>
+        <meta http-equiv="Content-Type" content="text/html; iso-8859-1">
+        <title>$project - Packages List</title>
+      </head>
+
+      <body link="$body_link" vlink="$body_vlink" alink="$body_alink"
+            bgcolor="$body_bgcolor" text="$body_text">
+        <font size="+1" face="arial,helvetica,sans serif">
+          <nobr><b><a href="doc.$_" target="doc">$(p.name)</a> package:</b></nobr>
+        </font>
+        <table border="0" cellspacing="0" cellpadding="0">
+          <tr>
+            <td width="10">&nbsp;</td>
+            <td>&nbsp;</td>
+          </tr>
+          <tr>
+            <td colspan="2">
+              <font face="arial,helvetica,sans serif">
+                <nobr>Classes:</nobr>
+              </font>
+            </td>
+          </tr>
+    <<
+
+    # Generate a list of classes included in this package
+    foreach $e ($p->classes()) {
+        $_ = $e->url;
+        s/\s/_/g;
+        y/[A-Z]/[a-z]/;
+        >>
+              <tr>
+                <td width="10">&nbsp;</td>
+                <td>
+                  <font face="arial,helvetica,sans serif">
+                    <nobr><a href="doc.$_" target="doc">$(e.fullname)</a></nobr>
+                  </font>
+                </td>
+              </tr>
+        <<
+    }
+
+    # Generate a list of all global functions included in this package
+    if ($p->globalfuncs()) {
+        >>
+              <tr>
+                <td colspan="2">
+                  <font face="arial,helvetica,sans serif">
+                    <nobr>Global Functions:</nobr>
+                  </font>
+                </td>
+              </tr>
+        <<
+        foreach $e ($p->globalfuncs()) {
+            $_ = $e->url;
+            s/\s/_/g;
+            y/[A-Z]/[a-z]/;
+            >>
+                  <tr>
+                    <td width="10">&nbsp;</td>
+                    <td>
+                      <font face="arial,helvetica,sans serif">
+                        <nobr><a href="doc.$_" target="doc">$(e.fullname)</a></nobr>
+                      </font>
+                    </td>
+                  </tr>
+            <<
+        }
+    } else {
+        >>
+              <tr>
+                <td colspan="2">
+                  <font face="arial,helvetica,sans serif">
+                    <nobr><i>No Global Functions defined.</i></nobr>
+                  </font>
+                </td>
+              </tr>
+        <<
+    }
+
+    # Generate a list of all global variables included in this package
+    if ($p->globalvars()) {
+        >>
+              <tr>
+                <td colspan="2">
+                  <font face="arial,helvetica,sans serif">
+                    <nobr>Global Variables:</nobr>
+                  </font>
+                </td>
+              </tr>
+        <<
+        foreach $e ($p->globalvars()) {
+            $_ = $e->url;
+            s/\s/_/g;
+            y/[A-Z]/[a-z]/;
+            >>
+                  <tr>
+                    <td width="10">&nbsp;</td>
+                    <td>
+                      <font face="arial,helvetica,sans serif">
+                        <nobr><a href="doc.$_" target="doc">$(e.fullname)</a></nobr>
+                      </font>
+                    </td>
+                  </tr>
+            <<
+        }
+    } else {
+        >>
+              <tr>
+                <td colspan="2">
+                  <font face="arial,helvetica,sans serif">
+                    <nobr><i>No Global Variables defined.</i></nobr>
+                  </font>
+                </td>
+              </tr>
+        <<
+    }
+
+    # Copyright statement at the bottom
+    >>
+        </table>
+        <hr>
+        <font size="-2" face="arial,helvetica,sans serif">
+          <div align="center">
+            Copyright &copy; $copyright.<br>
+            All Rights Reserved.<br>
+          </div>
+        </font>
+      </body>
+    </html>
+    <<
+}
+
+###############################################################################
+# Generate the packages detailed description for each package                 #
+###############################################################################
+foreach $p (packages()) {
+    $_ = $p->url;
+    s/\s/_/g;
+    y/[A-Z]/[a-z]/;
+    file "doc.$_";
+    >>
+    <html>
+      <head>
+        <meta http-equiv="Content-Type" content="text/html; iso-8859-1">
+        <title>$project - Packages List</title>
+      </head>
+      <body link="$body_link" vlink="$body_vlink" alink="$body_alink"
+            bgcolor="$body_bgcolor" text="$body_text">
+        <table width="100%" cellspacing="0" cellpadding="2" border="1">
+          <tr>
+            <td bgcolor="ccccff">
+              <table border="0" width="100%" cellspacing="0" cellpadding="0">
+                <tr>
+                  <td bgcolor="ccccff" align="left">
+                    <font size="+1" face="arial,helvetica,sans serif">
+                      <b>$project</b>
+                    </font>
+                  </td>
+                  <td bgcolor="ccccff" align="right">
+                    <font size="+1" face="arial,helvetica,sans serif">
+                      <b>$(p.name) package</b>
+                    </font>
+                  </td>
+                </tr>
+              </table>
+            </td>
+          </tr>
+        </table>
+        <br>
+        <table width="100%" cellspacing="0" cellpadding="2" border="1">
+          <tr>
+            <td bgcolor="eeeeff" align="left">
+              <font face="arial,helvetica,sans serif">
+                <b>Classes</b>
+              </font>
+            </td>
+          </tr>
+    <<
+
+    # Generate a TOC of all classes at the top of the page
+    foreach $e ($p->classes()) {
+        $_ = $e->url;
+        s/\s/_/g;
+        y/[A-Z]/[a-z]/;
+        >>
+              <tr>
+                <td>
+                  <dl>
+                    <dt>
+                      <font face="arial,helvetica,sans serif">
+                        <nobr><a href="doc.$_">$(e.fullname)</a></nobr>
+                      </font>
+                    </dt>
+        <<
+        if ($e->members()) {
+            foreach $m ($e->members()) {
+                $_ = $m->url;
+                s/\s/_/g;
+                y/[A-Z]/[a-z]/;
+                >>
+                            <dd>
+                              <font size="-1" face="arial,helvetica,sans serif">
+                                <nobr><a href="doc.$_">$(m.fullname)</a></nobr>
+                              </font>
+                            </dd>
+                <<
+            }
+        }
+        >>
+                  </dl>
+                </td>
+              </tr>
+        <<
+    }
+
+    # Continue with the global functions TOC
+    if ($p->globalfuncs()) {
+        >>
+            </table>
+            <br>
+            <table width="100%" cellspacing="0" cellpadding="2" border="1">
+              <tr>
+                <td bgcolor="eeeeff" align="left">
+                  <font face="arial,helvetica,sans serif">
+                    <b>Global Functions</b>
+                  </font>
+                </td>
+              </tr>
+        <<
+        foreach $e ($p->globalfuncs()) {
+            $_ = $e->url;
+            s/\s/_/g;
+            y/[A-Z]/[a-z]/;
+            >>
+                  <tr>
+                    <td>
+                      <font face="arial,helvetica,sans serif">
+                        <nobr><a href="doc.$_">$(e.fullname)</a></nobr>
+                      </font>
+                    </td>
+                  </tr>
+            <<
+        }
+    }
+
+    # And then finish with the global variables TOC
+    if ($p->globalvars()) {
+        >>
+            </table>
+            <br>
+            <table width="100%" cellspacing="0" cellpadding="2" border="1">
+              <tr>
+                <td bgcolor="eeeeff" align="left">
+                  <font face="arial,helvetica,sans serif">
+                    <b>Global Variables</b>
+                  </font>
+                </td>
+              </tr>
+        <<
+        foreach $e ($p->globalvars()) {
+            $_ = $e->url;
+            s/\s/_/g;
+            y/[A-Z]/[a-z]/;
+            >>
+                  <tr>
+                    <td>
+                      <font face="arial,helvetica,sans serif">
+                        <nobr><a href="doc.$_">$(e.fullname)</a></nobr>
+                      </font>
+                    </td>
+                  </tr>
+            <<
+        }
+    }
+
+    >>
+        </table>
+        <br>
+    <<
+
+    # Then generate the detail for each class in this package
+    foreach $e ($p->classes()) {
+        $_ = $e->url;
+        s/\s/_/g;
+        y/[A-Z]/[a-z]/;
+        >>
+            <table width="100%" cellspacing="0" cellpadding="2" border="1">
+              <tr>
+                <td bgcolor="ccccff" align="left">
+                  <font size="+1" face="arial,helvetica,sans serif">
+                    <a name="$(e.name)">
+                      <b>Class &quot;$(e.name)&quot; Detail:</b>
+                    </a>
+                  </font>
+                </td>
+              </tr>
+            </table>
+              <font size="+1" face="arial,helvetica,sans serif">
+                <b>$(e.name)</b>
+              </font>
+            <dl>
+              <dt><code>$(e.fullname) {</code></dt>
+        <<
+
+        # Generate a code-like representation of the class
+        if ($e->members()) {
+            foreach $m ($e->members()) {
+                >>
+                      <dd><code>$(m.fullname);</code></dd>
+                <<
+            }
+        }
+        >>
+              <dt><code>};</code></dt>
+            </dl>
+            <p>
+              <font face="arial,helvetica,sans serif">
+                $(e.description)
+              </font>
+            </p>
+        <<
+
+        # If we have functions, output them
+        if ($e->memberfuncs()) {
+            >>
+                <table width="100%" cellspacing="0" cellpadding="2" border="1">
+                  <tr>
+                    <td bgcolor="eeeeff" align="left">
+                      <font face="arial,helvetica,sans serif">
+                        <b>Class &quot;$(e.name)&quot; Functions:</b>
+                      </font>
+                    </td>
+                  </tr>
+                </table>
+            <<
+            foreach $m ($e->memberfuncs()) {
+                $_ = join("-",$e->name,$m->name);
+                s/\s/_/g;
+                y/[A-Z]/[a-z]/;
+                >>
+                    <a name="$_">
+                <<
+                &function($m);
+            }
+        }
+
+        # If we have variables, output them
+        if ($e->membervars()) {
+            >>
+                <table width="100%" cellspacing="0" cellpadding="2" border="1">
+                  <tr>
+                    <td bgcolor="eeeeff" align="left">
+                      <font face="arial,helvetica,sans serif">
+                        <b>Class &quot;$(e.name)&quot; Variables:</b>
+                      </font>
+                    </td>
+                  </tr>
+                </table>
+            <<
+            foreach $m ($e->membervars()) {
+                $_ = join("-",$e->name,$m->name);
+                s/\s/_/g;
+                y/[A-Z]/[a-z]/;
+                >>
+                    <a name="$_">
+                <<
+                &variable($m);
+            }
+        }
+    }
+
+    # Output detailed information for each global function
+    if ($p->globalfuncs()) {
+        >>
+            <table width="100%" cellspacing="0" cellpadding="2" border="1">
+              <tr>
+                <td bgcolor="ccccff" align="left">
+                  <font size="+1" face="arial,helvetica,sans serif">
+                    <b>Global Functions Detail:</b>
+                  </font>
+                </td>
+              </tr>
+            </table>
+        <<
+        foreach $e ($p->globalfuncs()) {
+            $_ = $e->name;
+            s/\s/_/g;
+            y/[A-Z]/[a-z]/;
+            >>
+                <a name="$_">
+            <<
+            &function($e);
+        }
+    }
+
+    # Then write detailed information for each global variable
+    if ($p->globalvars()) {
+        >>
+            <table width="100%" cellspacing="0" cellpadding="2" border="1">
+              <tr>
+                <td bgcolor="ccccff" align="left">
+                  <font size="+1" face="arial,helvetica,sans serif">
+                    <b>Global Variables Detail:</b>
+                  </font>
+                </td>
+              </tr>
+            </table>
+        <<
+        foreach $e ($p->globalvars()) {
+            $_ = $e->name;
+            s/\s/_/g;
+            y/[A-Z]/[a-z]/;
+            >>
+                <a name="$_">
+            <<
+            &variable($e);
+        }
+    }
+
+    >>
+        <font size="-2" face="arial,helvetica,sans serif">
+          <div align="center">
+            Copyright &copy; $copyright.<br>
+            All Rights Reserved.<br>
+            Generated with <a href="$scandocURL">ScanDoc
+            $majorVersion.$minorVersion</a> on $date
+          </div>
+        </font>
+      </body>
+    </html>
+    <<
+}
+
+# Write out the detailed description of a function
+sub function {
+    local ($m) = @_;
+
+    # Output the function name and description
+    >>
+        <font size="+1" face="arial,helvetica,sans serif">
+          <b>$(m.name)</b>
+        </font>
+        <dl>
+          <dt><code>$(m.fullname);</code></dt>
+          <dd>
+            <dl>
+              <dt>
+                <font face="arial,helvetica,sans serif">
+                  $(m.description)
+                </font>
+              </dt>
+    <<
+
+    # Process all parameters (one by one)
+    if ($m->params()) {
+        >>
+                  <dt>
+                    <font face="arial,helvetica,sans serif">
+                      <b>Parameters</b>
+                    </font>
+                  </dt>
+        <<
+        foreach $a ($m->params()) {
+            >>
+                      <dd>
+                        <code>$(a.name)</code> -
+                        <font face="arial,helvetica,sans serif">
+                          $(a.description)
+                        </font>
+                      </dd>
+            <<
+        }
+    }
+
+    # Check for a return value
+    if ($m->returnValue()) {
+        >>
+                  <dt>
+                    <font face="arial,helvetica,sans serif">
+                      <b>Return Value</b>
+                    </font>
+                  </dt>
+                  <dd>
+                    <font face="arial,helvetica,sans serif">
+                      $(m.returnValue)
+                    </font>
+                  </dd>
+        <<
+    }
+
+    # Dig in for exceptions
+    if ($m->exceptions()) {
+        >>
+                  <dt>
+                    <font face="arial,helvetica,sans serif">
+                      <b>Exceptions</b>
+                    </font>
+                  </dt>
+        <<
+        foreach $a ($m->exceptions()) {
+            >>
+                      <dd>
+                        <code>$(a.name)</code>
+                        <font face="arial,helvetica,sans serif">
+                          $(a.description)
+                        </font>
+                      </dd>
+            <<
+        }
+    }
+
+    # Close the list
+    >>
+            </dl>
+          </dd>
+        </dl>
+        <hr>
+    <<
+}
+
+# Write out the detailed description of a variable
+sub variable {
+    local ($m) = @_;
+
+    # Output the variable name and description
+    >>
+        <font size="+1" face="arial,helvetica,sans serif">
+          <b>$(m.name)</b>
+        </font>
+        <dl>
+          <dt><code>$(m.fullname);</code></dt>
+          <dd>
+            <dl>
+              <dt>
+                <font face="arial,helvetica,sans serif">
+                  $(m.description)
+                </font>
+              </dt>
+            </dl>
+          </dd>
+        </dl>
+        <hr>
+    <<
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/util/README.txt
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/util/README.txt	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/util/README.txt	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,8 @@
+This subpackage contains a set of common utilities copied out
+of tomcat 3.3.
+
+It probably doesn't belong in jakarta-tomcat-connectors, but perhaps
+in something like jakarta-tomcat-util, or something.... [seguin].
+
+To build, simply run ant.  The default target creates tomcat-util.jar
+int ./build/lib.

Added: branches/tomcat5.5/upstream/5.5.20/connectors/util/build.properties.sample
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/util/build.properties.sample	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/util/build.properties.sample	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,32 @@
+# -------------------------------------------------------------------
+# build.properties.sample
+#
+# This is an example "build.properties" file, used to customize 
+# building Jakarta Tomcat Connectors Util for your local environment.  
+# Make any changes you need, and rename this file to 
+# "build.properties" 
+#
+# $Id: build.properties.sample 297726 2002-08-09 20:49:44Z costin $
+# -------------------------------------------------------------------
+
+
+# -------------------------------------------------------------------
+# CONFIGURATION OPTIONS
+# -------------------------------------------------------------------
+
+# 
+
+
+# -------------------------------------------------------------------
+# EXTERNAL DEPENDENCIES 
+# -------------------------------------------------------------------
+
+# ----- (optional) Java Secure Sockets Extension (JSSE), v1.0.2 or later -----
+jsse.home=${base.path}/jsse1.0.2
+jsse.lib=${jsse.home}/lib
+
+
+# ----- (optional) PureTLS Extension -----
+puretls.home=${base.path}/puretls-0.9b2
+puretls.lib=${puretls.home}/build
+puretls.jar=${puretls.lib}/puretls.jar

Added: branches/tomcat5.5/upstream/5.5.20/connectors/util/build.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/util/build.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/util/build.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,151 @@
+<project name="tomcat-util" default="build-main" basedir=".">
+
+    <!-- ===================== Initialize Property Values =================== -->
+    <property file="${user.home}/build.properties"/>
+    <property file="build.properties"/>
+    <property file="../build.properties.default"/>
+    <property file="build.properties.sample"/>
+
+    <property name="tomcat-util.build" value="${basedir}/build"/>
+
+    <property name="jsse.home" location="${base.path}/jsse1.0.2"/>
+    <property name="jsse.lib" location="${jsse.home}/lib"/>
+    <property name="jsse.jar" location="${jsse.lib}/jsse.jar"/>
+    <property name="jnet.jar" location="${jsse.lib}/jnet.jar"/>
+    <property name="jcert.jar" location="${jsse.lib}/jcert.jar"/>
+
+    <property name="puretls.home" location="${base.path}/puretls"/>
+    <property name="puretls.lib" location="${puretls.home}"/>
+    <property name="puretls.jar" location="${puretls.lib}/puretls.jar"/>
+    
+    <property name="commons-logging.jar" location="${base.path}/commons-logging-1.0.4/commons-logging.jar" />
+    <property name="jmx.jar" location="${base.path}/mx4j-2.0.1/lib/mx4j.jar" />
+    <property name="tomcat-util.lib" value="${tomcat-util.build}/lib" />
+    <property name="tomcat-util.jar" value="${tomcat-util.lib}/tomcat-util.jar" />
+    <property name="tomcat-loader.jar" value="${tomcat-util.lib}/tomcat-loader.jar" />
+    <property name="tomcat-jni.jar" value="../jni/dist/tomcat-native-1.0.0.jar" />
+
+    <path id="compile.classpath">
+        <pathelement location="${jmx.jar}" />
+        <pathelement location="${jsse.jar}" />
+        <pathelement location="${java.home}/lib/jsse.jar" />
+        <pathelement location="${jnet.jar}" />
+        <pathelement location="${jcert.jar}" />
+        <pathelement location="${puretls.jar}" />
+        <pathelement location="${commons-logging.jar}" />
+        <pathelement location="${commons-modeler.jar}" />
+        <pathelement location="${tomcat-jni.jar}" />
+    </path>
+
+    <target name="detect">
+        <available property="jsse.present" classname="javax.net.ssl.SSLSocket"/>
+        <available property="jmx.present" file="${jmx.jar}"/>
+        <available property="puretls.present" file="${puretls.jar}"/>
+        <available property="commons-logging.present" file="${commons-logging.jar}"/>
+        <available property="modeler.present" file="${commons-modeler.jar}"/>
+	<available property="jdk1.4.present" classname="java.lang.CharSequence" />
+        <available property="jdk1.5.present" classname="javax.net.ssl.CertPathTrustManagerParameters" />
+    </target>
+
+    <target name="build-prepare" depends="detect">
+        <mkdir dir="${tomcat-util.build}"/>
+        <mkdir dir="${tomcat-util.build}/classes"/>
+	<mkdir dir="${tomcat-util.lib}"/>
+    </target>
+
+    <target name="build-main" depends="tomcat-util.jar"/> <!--tomcat-loader.jar -->
+        
+    <target name="tomcat-util.jar" depends="build-prepare">
+        <echo message="----- Java-utils -----" />
+        <echo message="-- puretls.present = ${puretls.present}" />
+        <echo message="-- jsse.present = ${jsse.present} ${jsse.jar}"/>
+        <echo message="-- commons-logging = ${commons-logging.present}"/>
+        <echo message="-- jmx = ${jmx.present} ${jmx.jar}"/>
+        <echo message="-- modeler = ${modeler.present} ${commons-modeler.jar}"/>
+        <echo message="-- skip.digester = ${skip.digester}" />
+        <echo message="-- JDK14 = ${jdk1.4.present}"/>
+        <echo message="-- JDK15 = ${jdk1.5.present}" />
+
+        <javac srcdir="java"
+	       destdir="${tomcat-util.build}/classes"
+	       deprecation="${compile.deprecation}"
+	       debug="${compile.debug}"
+	       optimize="off"
+	       verbose="off"
+	       excludes="**/CVS/**">
+            <classpath refid="compile.classpath"/>
+            <exclude name="**/util/net/jsse/*" unless="jsse.present"/>
+            <exclude name="**/util/log/CommonLogHandler.java" unless="commons-logging.present"/>
+            <exclude name="**/util/net/puretls/*" unless="puretls.present"/>
+            <exclude name="**/util/mx/*" unless="jmx.present"/>
+            <exclude name="**/util/threads/ThreadPoolMX*" unless="modeler.present"/>
+            <exclude name="**/util/compat/Jdk14Compat.java" unless="jdk1.4.present" />
+            <exclude name="**/util/net/jsse/JSSE14*" unless="jdk1.4.present" />
+            <exclude name="**/util/net/jsse/JSSE15*" unless="jdk1.5.present" />
+            <exclude name="**/util/net/jsse/JSSEKeyManager.java" unless="jdk1.4.present" />
+            <exclude name="**/util/digester/*" if="skip.digester" />
+        </javac>
+
+	<!-- Copy static resource files -->
+	<copy todir="${tomcat-util.build}/classes">
+	    <fileset dir="java">
+	    	<include name="**/*.properties"/>
+	    </fileset>
+        </copy>
+
+	<!-- Copy static resource files -->
+	<copy todir="${tomcat-util.build}/classes">
+	    <fileset dir="java">
+	    	<include name="**/*.properties"/>
+	    </fileset>
+        </copy>
+
+	<jar jarfile="${tomcat-util.jar}"
+             index="true"
+             basedir="${tomcat-util.build}/classes"
+             manifest="java/tomcat-util.manifest" >
+            <include name="org/apache/tomcat/util/**"/>
+        </jar>
+
+    </target>
+
+    <target name="tomcat-loader.jar" depends="build-prepare">
+        <mkdir dir="${tomcat-util.build}/loader"/>
+        <javac srcdir="loader"
+           destdir="${tomcat-util.build}/loader"
+           deprecation="${compile.deprecation}"
+           debug="${compile.debug}"
+           optimize="off"
+           verbose="off"
+           excludes="**/CVS/**">
+            <classpath refid="compile.classpath"/>
+        </javac>
+     	<jar jarfile="${tomcat-loader.jar}"
+             index="true"
+             basedir="${tomcat-util.build}/loader"
+             manifest="loader/tomcat-loader.manifest" >
+            <include name="org/apache/tomcat/util/loader/**"/>
+        </jar>
+    </target>
+
+    <!-- ================ BUILD: Create Tomcat-Util Javadocs =================== -->
+    <target name="javadoc" unless="docs-uptodate">
+        <delete dir="${tomcat-util.build}/javadoc"/>
+	<mkdir dir="${tomcat-util.build}/javadoc"/>
+	<javadoc packagenames="org.apache.tomcat.util.*"
+               sourcepath="java"
+                  destdir="${tomcat-util.build}/javadoc"
+                   author="true"
+                  version="true"
+              windowtitle="Tomcat Utilities Documentation"
+                 doctitle="Tomcat Utilities"
+                   bottom="Copyright &#169; 2001 Apache Software Foundation.  All Rights Reserved.">
+            <classpath refid="compile.classpath"/>
+        </javadoc>
+    </target>
+
+
+    <target name="clean">
+        <delete dir="${tomcat-util.build}"/>
+    </target>
+</project>

Added: branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/IntrospectionUtils.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/IntrospectionUtils.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/IntrospectionUtils.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,1002 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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;
+
+import java.io.File;
+import java.io.FilenameFilter;
+import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.net.InetAddress;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.UnknownHostException;
+import java.util.Hashtable;
+import java.util.StringTokenizer;
+import java.util.Vector;
+
+// Depends: JDK1.1
+
+/**
+ * Utils for introspection and reflection
+ */
+public final class IntrospectionUtils {
+
+    
+    private static org.apache.commons.logging.Log log=
+        org.apache.commons.logging.LogFactory.getLog( IntrospectionUtils.class );
+    
+    /**
+     * Call execute() - any ant-like task should work
+     */
+    public static void execute(Object proxy, String method) throws Exception {
+        Method executeM = null;
+        Class c = proxy.getClass();
+        Class params[] = new Class[0];
+        //	params[0]=args.getClass();
+        executeM = findMethod(c, method, params);
+        if (executeM == null) {
+            throw new RuntimeException("No execute in " + proxy.getClass());
+        }
+        executeM.invoke(proxy, (Object[]) null);//new Object[] { args });
+    }
+
+    /**
+     * Call void setAttribute( String ,Object )
+     */
+    public static void setAttribute(Object proxy, String n, Object v)
+            throws Exception {
+        if (proxy instanceof AttributeHolder) {
+            ((AttributeHolder) proxy).setAttribute(n, v);
+            return;
+        }
+
+        Method executeM = null;
+        Class c = proxy.getClass();
+        Class params[] = new Class[2];
+        params[0] = String.class;
+        params[1] = Object.class;
+        executeM = findMethod(c, "setAttribute", params);
+        if (executeM == null) {
+            if (log.isDebugEnabled())
+                log.debug("No setAttribute in " + proxy.getClass());
+            return;
+        }
+        if (false)
+            if (log.isDebugEnabled())
+                log.debug("Setting " + n + "=" + v + "  in " + proxy);
+        executeM.invoke(proxy, new Object[] { n, v });
+        return;
+    }
+
+    /**
+     * Call void getAttribute( String )
+     */
+    public static Object getAttribute(Object proxy, String n) throws Exception {
+        Method executeM = null;
+        Class c = proxy.getClass();
+        Class params[] = new Class[1];
+        params[0] = String.class;
+        executeM = findMethod(c, "getAttribute", params);
+        if (executeM == null) {
+            if (log.isDebugEnabled())
+                log.debug("No getAttribute in " + proxy.getClass());
+            return null;
+        }
+        return executeM.invoke(proxy, new Object[] { n });
+    }
+
+    /**
+     * Construct a URLClassLoader. Will compile and work in JDK1.1 too.
+     */
+    public static ClassLoader getURLClassLoader(URL urls[], ClassLoader parent) {
+        try {
+            Class urlCL = Class.forName("java.net.URLClassLoader");
+            Class paramT[] = new Class[2];
+            paramT[0] = urls.getClass();
+            paramT[1] = ClassLoader.class;
+            Method m = findMethod(urlCL, "newInstance", paramT);
+            if (m == null)
+                return null;
+
+            ClassLoader cl = (ClassLoader) m.invoke(urlCL, new Object[] { urls,
+                    parent });
+            return cl;
+        } catch (ClassNotFoundException ex) {
+            // jdk1.1
+            return null;
+        } catch (Exception ex) {
+            ex.printStackTrace();
+            return null;
+        }
+    }
+
+    public static String guessInstall(String installSysProp,
+            String homeSysProp, String jarName) {
+        return guessInstall(installSysProp, homeSysProp, jarName, null);
+    }
+
+    /**
+     * Guess a product install/home by analyzing the class path. It works for
+     * product using the pattern: lib/executable.jar or if executable.jar is
+     * included in classpath by a shell script. ( java -jar also works )
+     * 
+     * Insures both "install" and "home" System properties are set. If either or
+     * both System properties are unset, "install" and "home" will be set to the
+     * same value. This value will be the other System property that is set, or
+     * the guessed value if neither is set.
+     */
+    public static String guessInstall(String installSysProp,
+            String homeSysProp, String jarName, String classFile) {
+        String install = null;
+        String home = null;
+
+        if (installSysProp != null)
+            install = System.getProperty(installSysProp);
+
+        if (homeSysProp != null)
+            home = System.getProperty(homeSysProp);
+
+        if (install != null) {
+            if (home == null)
+                System.getProperties().put(homeSysProp, install);
+            return install;
+        }
+
+        // Find the directory where jarName.jar is located
+
+        String cpath = System.getProperty("java.class.path");
+        String pathSep = System.getProperty("path.separator");
+        StringTokenizer st = new StringTokenizer(cpath, pathSep);
+        while (st.hasMoreTokens()) {
+            String path = st.nextToken();
+            //	    log( "path " + path );
+            if (path.endsWith(jarName)) {
+                home = path.substring(0, path.length() - jarName.length());
+                try {
+                    if ("".equals(home)) {
+                        home = new File("./").getCanonicalPath();
+                    } else if (home.endsWith(File.separator)) {
+                        home = home.substring(0, home.length() - 1);
+                    }
+                    File f = new File(home);
+                    String parentDir = f.getParent();
+                    if (parentDir == null)
+                        parentDir = home; // unix style
+                    File f1 = new File(parentDir);
+                    install = f1.getCanonicalPath();
+                    if (installSysProp != null)
+                        System.getProperties().put(installSysProp, install);
+                    if (home == null && homeSysProp != null)
+                        System.getProperties().put(homeSysProp, install);
+                    return install;
+                } catch (Exception ex) {
+                    ex.printStackTrace();
+                }
+            } else {
+                String fname = path + (path.endsWith("/") ? "" : "/")
+                        + classFile;
+                if (new File(fname).exists()) {
+                    try {
+                        File f = new File(path);
+                        String parentDir = f.getParent();
+                        if (parentDir == null)
+                            parentDir = path; // unix style
+                        File f1 = new File(parentDir);
+                        install = f1.getCanonicalPath();
+                        if (installSysProp != null)
+                            System.getProperties().put(installSysProp, install);
+                        if (home == null && homeSysProp != null)
+                            System.getProperties().put(homeSysProp, install);
+                        return install;
+                    } catch (Exception ex) {
+                        ex.printStackTrace();
+                    }
+                }
+            }
+        }
+
+        // if install directory can't be found, use home as the default
+        if (home != null) {
+            System.getProperties().put(installSysProp, home);
+            return home;
+        }
+
+        return null;
+    }
+
+    /**
+     * Debug method, display the classpath
+     */
+    public static void displayClassPath(String msg, URL[] cp) {
+        if (log.isDebugEnabled()) {
+            log.debug(msg);
+            for (int i = 0; i < cp.length; i++) {
+                log.debug(cp[i].getFile());
+            }
+        }
+    }
+
+    public static String PATH_SEPARATOR = System.getProperty("path.separator");
+
+    /**
+     * Adds classpath entries from a vector of URL's to the "tc_path_add" System
+     * property. This System property lists the classpath entries common to web
+     * applications. This System property is currently used by Jasper when its
+     * JSP servlet compiles the Java file for a JSP.
+     */
+    public static String classPathAdd(URL urls[], String cp) {
+        if (urls == null)
+            return cp;
+
+        for (int i = 0; i < urls.length; i++) {
+            if (cp != null)
+                cp += PATH_SEPARATOR + urls[i].getFile();
+            else
+                cp = urls[i].getFile();
+        }
+        return cp;
+    }
+
+    /**
+     * Find a method with the right name If found, call the method ( if param is
+     * int or boolean we'll convert value to the right type before) - that means
+     * you can have setDebug(1).
+     */
+    public static void setProperty(Object o, String name, String value) {
+        if (dbg > 1)
+            d("setProperty(" + o.getClass() + " " + name + "=" + value + ")");
+
+        String setter = "set" + capitalize(name);
+
+        try {
+            Method methods[] = findMethods(o.getClass());
+            Method setPropertyMethod = null;
+
+            // First, the ideal case - a setFoo( String ) method
+            for (int i = 0; i < methods.length; i++) {
+                Class paramT[] = methods[i].getParameterTypes();
+                if (setter.equals(methods[i].getName()) && paramT.length == 1
+                        && "java.lang.String".equals(paramT[0].getName())) {
+
+                    methods[i].invoke(o, new Object[] { value });
+                    return;
+                }
+            }
+
+            // Try a setFoo ( int ) or ( boolean )
+            for (int i = 0; i < methods.length; i++) {
+                boolean ok = true;
+                if (setter.equals(methods[i].getName())
+                        && methods[i].getParameterTypes().length == 1) {
+
+                    // match - find the type and invoke it
+                    Class paramType = methods[i].getParameterTypes()[0];
+                    Object params[] = new Object[1];
+
+                    // Try a setFoo ( int )
+                    if ("java.lang.Integer".equals(paramType.getName())
+                            || "int".equals(paramType.getName())) {
+                        try {
+                            params[0] = new Integer(value);
+                        } catch (NumberFormatException ex) {
+                            ok = false;
+                        }
+                    // Try a setFoo ( long )
+                    }else if ("java.lang.Long".equals(paramType.getName())
+                                || "long".equals(paramType.getName())) {
+                            try {
+                                params[0] = new Long(value);
+                            } catch (NumberFormatException ex) {
+                                ok = false;
+                            }
+
+                        // Try a setFoo ( boolean )
+                    } else if ("java.lang.Boolean".equals(paramType.getName())
+                            || "boolean".equals(paramType.getName())) {
+                        params[0] = new Boolean(value);
+
+                        // Try a setFoo ( InetAddress )
+                    } else if ("java.net.InetAddress".equals(paramType
+                            .getName())) {
+                        try {
+                            params[0] = InetAddress.getByName(value);
+                        } catch (UnknownHostException exc) {
+                            d("Unable to resolve host name:" + value);
+                            ok = false;
+                        }
+
+                        // Unknown type
+                    } else {
+                        d("Unknown type " + paramType.getName());
+                    }
+
+                    if (ok) {
+                        methods[i].invoke(o, params);
+                        return;
+                    }
+                }
+
+                // save "setProperty" for later
+                if ("setProperty".equals(methods[i].getName())) {
+                    setPropertyMethod = methods[i];
+                }
+            }
+
+            // Ok, no setXXX found, try a setProperty("name", "value")
+            if (setPropertyMethod != null) {
+                Object params[] = new Object[2];
+                params[0] = name;
+                params[1] = value;
+                setPropertyMethod.invoke(o, params);
+            }
+
+        } catch (IllegalArgumentException ex2) {
+            log.warn("IAE " + o + " " + name + " " + value, ex2);
+        } catch (SecurityException ex1) {
+            if (dbg > 0)
+                d("SecurityException for " + o.getClass() + " " + name + "="
+                        + value + ")");
+            if (dbg > 1)
+                ex1.printStackTrace();
+        } catch (IllegalAccessException iae) {
+            if (dbg > 0)
+                d("IllegalAccessException for " + o.getClass() + " " + name
+                        + "=" + value + ")");
+            if (dbg > 1)
+                iae.printStackTrace();
+        } catch (InvocationTargetException ie) {
+            if (dbg > 0)
+                d("InvocationTargetException for " + o.getClass() + " " + name
+                        + "=" + value + ")");
+            if (dbg > 1)
+                ie.printStackTrace();
+        }
+    }
+
+    public static Object getProperty(Object o, String name) {
+        String getter = "get" + capitalize(name);
+        String isGetter = "is" + capitalize(name);
+
+        try {
+            Method methods[] = findMethods(o.getClass());
+            Method getPropertyMethod = null;
+
+            // First, the ideal case - a getFoo() method
+            for (int i = 0; i < methods.length; i++) {
+                Class paramT[] = methods[i].getParameterTypes();
+                if (getter.equals(methods[i].getName()) && paramT.length == 0) {
+                    return methods[i].invoke(o, (Object[]) null);
+                }
+                if (isGetter.equals(methods[i].getName()) && paramT.length == 0) {
+                    return methods[i].invoke(o, (Object[]) null);
+                }
+
+                if ("getProperty".equals(methods[i].getName())) {
+                    getPropertyMethod = methods[i];
+                }
+            }
+
+            // Ok, no setXXX found, try a getProperty("name")
+            if (getPropertyMethod != null) {
+                Object params[] = new Object[1];
+                params[0] = name;
+                return getPropertyMethod.invoke(o, params);
+            }
+
+        } catch (IllegalArgumentException ex2) {
+            log.warn("IAE " + o + " " + name, ex2);
+        } catch (SecurityException ex1) {
+            if (dbg > 0)
+                d("SecurityException for " + o.getClass() + " " + name + ")");
+            if (dbg > 1)
+                ex1.printStackTrace();
+        } catch (IllegalAccessException iae) {
+            if (dbg > 0)
+                d("IllegalAccessException for " + o.getClass() + " " + name
+                        + ")");
+            if (dbg > 1)
+                iae.printStackTrace();
+        } catch (InvocationTargetException ie) {
+            if (dbg > 0)
+                d("InvocationTargetException for " + o.getClass() + " " + name
+                        + ")");
+            if (dbg > 1)
+                ie.printStackTrace();
+        }
+        return null;
+    }
+
+    /** 
+     */
+    public static void setProperty(Object o, String name) {
+        String setter = "set" + capitalize(name);
+        try {
+            Method methods[] = findMethods(o.getClass());
+            Method setPropertyMethod = null;
+            // find setFoo() method
+            for (int i = 0; i < methods.length; i++) {
+                Class paramT[] = methods[i].getParameterTypes();
+                if (setter.equals(methods[i].getName()) && paramT.length == 0) {
+                    methods[i].invoke(o, new Object[] {});
+                    return;
+                }
+            }
+        } catch (Exception ex1) {
+            if (dbg > 0)
+                d("Exception for " + o.getClass() + " " + name);
+            if (dbg > 1)
+                ex1.printStackTrace();
+        }
+    }
+
+    /**
+     * Replace ${NAME} with the property value
+     * 
+     * @deprecated Use the explicit method
+     */
+    public static String replaceProperties(String value, Object getter) {
+        if (getter instanceof Hashtable)
+            return replaceProperties(value, (Hashtable) getter, null);
+
+        if (getter instanceof PropertySource) {
+            PropertySource src[] = new PropertySource[] { (PropertySource) getter };
+            return replaceProperties(value, null, src);
+        }
+        return value;
+    }
+
+    /**
+     * Replace ${NAME} with the property value
+     */
+    public static String replaceProperties(String value, Hashtable staticProp,
+            PropertySource dynamicProp[]) {
+        StringBuffer sb = new StringBuffer();
+        int prev = 0;
+        // assert value!=nil
+        int pos;
+        while ((pos = value.indexOf("$", prev)) >= 0) {
+            if (pos > 0) {
+                sb.append(value.substring(prev, pos));
+            }
+            if (pos == (value.length() - 1)) {
+                sb.append('$');
+                prev = pos + 1;
+            } else if (value.charAt(pos + 1) != '{') {
+                sb.append('$');
+                prev = pos + 1; // XXX
+            } else {
+                int endName = value.indexOf('}', pos);
+                if (endName < 0) {
+                    sb.append(value.substring(pos));
+                    prev = value.length();
+                    continue;
+                }
+                String n = value.substring(pos + 2, endName);
+                String v = null;
+                if (staticProp != null) {
+                    v = (String) ((Hashtable) staticProp).get(n);
+                }
+                if (v == null && dynamicProp != null) {
+                    for (int i = 0; i < dynamicProp.length; i++) {
+                        v = dynamicProp[i].getProperty(n);
+                        if (v != null) {
+                            break;
+                        }
+                    }
+                }
+                if (v == null)
+                    v = "${" + n + "}";
+
+                sb.append(v);
+                prev = endName + 1;
+            }
+        }
+        if (prev < value.length())
+            sb.append(value.substring(prev));
+        return sb.toString();
+    }
+
+    /**
+     * Reverse of Introspector.decapitalize
+     */
+    public static String capitalize(String name) {
+        if (name == null || name.length() == 0) {
+            return name;
+        }
+        char chars[] = name.toCharArray();
+        chars[0] = Character.toUpperCase(chars[0]);
+        return new String(chars);
+    }
+
+    public static String unCapitalize(String name) {
+        if (name == null || name.length() == 0) {
+            return name;
+        }
+        char chars[] = name.toCharArray();
+        chars[0] = Character.toLowerCase(chars[0]);
+        return new String(chars);
+    }
+
+    // -------------------- Class path tools --------------------
+
+    /**
+     * Add all the jar files in a dir to the classpath, represented as a Vector
+     * of URLs.
+     */
+    public static void addToClassPath(Vector cpV, String dir) {
+        try {
+            String cpComp[] = getFilesByExt(dir, ".jar");
+            if (cpComp != null) {
+                int jarCount = cpComp.length;
+                for (int i = 0; i < jarCount; i++) {
+                    URL url = getURL(dir, cpComp[i]);
+                    if (url != null)
+                        cpV.addElement(url);
+                }
+            }
+        } catch (Exception ex) {
+            ex.printStackTrace();
+        }
+    }
+
+    public static void addToolsJar(Vector v) {
+        try {
+            // Add tools.jar in any case
+            File f = new File(System.getProperty("java.home")
+                    + "/../lib/tools.jar");
+
+            if (!f.exists()) {
+                // On some systems java.home gets set to the root of jdk.
+                // That's a bug, but we can work around and be nice.
+                f = new File(System.getProperty("java.home") + "/lib/tools.jar");
+                if (f.exists()) {
+                    if (log.isDebugEnabled())
+                        log.debug("Detected strange java.home value "
+                            + System.getProperty("java.home")
+                            + ", it should point to jre");
+                }
+            }
+            URL url = new URL("file", "", f.getAbsolutePath());
+
+            v.addElement(url);
+        } catch (MalformedURLException ex) {
+            ex.printStackTrace();
+        }
+    }
+
+    /**
+     * Return all files with a given extension in a dir
+     */
+    public static String[] getFilesByExt(String ld, String ext) {
+        File dir = new File(ld);
+        String[] names = null;
+        final String lext = ext;
+        if (dir.isDirectory()) {
+            names = dir.list(new FilenameFilter() {
+                public boolean accept(File d, String name) {
+                    if (name.endsWith(lext)) {
+                        return true;
+                    }
+                    return false;
+                }
+            });
+        }
+        return names;
+    }
+
+    /**
+     * Construct a file url from a file, using a base dir
+     */
+    public static URL getURL(String base, String file) {
+        try {
+            File baseF = new File(base);
+            File f = new File(baseF, file);
+            String path = f.getCanonicalPath();
+            if (f.isDirectory()) {
+                path += "/";
+            }
+            if (!f.exists())
+                return null;
+            return new URL("file", "", path);
+        } catch (Exception ex) {
+            ex.printStackTrace();
+            return null;
+        }
+    }
+
+    /**
+     * Add elements from the classpath <i>cp </i> to a Vector <i>jars </i> as
+     * file URLs (We use Vector for JDK 1.1 compat).
+     * <p>
+     * 
+     * @param jars The jar list
+     * @param cp a String classpath of directory or jar file elements
+     *   separated by path.separator delimiters.
+     * @throws IOException If an I/O error occurs
+     * @throws MalformedURLException Doh ;)
+     */
+    public static void addJarsFromClassPath(Vector jars, String cp)
+            throws IOException, MalformedURLException {
+        String sep = System.getProperty("path.separator");
+        String token;
+        StringTokenizer st;
+        if (cp != null) {
+            st = new StringTokenizer(cp, sep);
+            while (st.hasMoreTokens()) {
+                File f = new File(st.nextToken());
+                String path = f.getCanonicalPath();
+                if (f.isDirectory()) {
+                    path += "/";
+                }
+                URL url = new URL("file", "", path);
+                if (!jars.contains(url)) {
+                    jars.addElement(url);
+                }
+            }
+        }
+    }
+
+    /**
+     * Return a URL[] that can be used to construct a class loader
+     */
+    public static URL[] getClassPath(Vector v) {
+        URL[] urls = new URL[v.size()];
+        for (int i = 0; i < v.size(); i++) {
+            urls[i] = (URL) v.elementAt(i);
+        }
+        return urls;
+    }
+
+    /**
+     * Construct a URL classpath from files in a directory, a cpath property,
+     * and tools.jar.
+     */
+    public static URL[] getClassPath(String dir, String cpath,
+            String cpathProp, boolean addTools) throws IOException,
+            MalformedURLException {
+        Vector jarsV = new Vector();
+        if (dir != null) {
+            // Add dir/classes first, if it exists
+            URL url = getURL(dir, "classes");
+            if (url != null)
+                jarsV.addElement(url);
+            addToClassPath(jarsV, dir);
+        }
+
+        if (cpath != null)
+            addJarsFromClassPath(jarsV, cpath);
+
+        if (cpathProp != null) {
+            String cpath1 = System.getProperty(cpathProp);
+            addJarsFromClassPath(jarsV, cpath1);
+        }
+
+        if (addTools)
+            addToolsJar(jarsV);
+
+        return getClassPath(jarsV);
+    }
+
+    // -------------------- Mapping command line params to setters
+
+    public static boolean processArgs(Object proxy, String args[])
+            throws Exception {
+        String args0[] = null;
+        if (null != findMethod(proxy.getClass(), "getOptions1", new Class[] {})) {
+            args0 = (String[]) callMethod0(proxy, "getOptions1");
+        }
+
+        if (args0 == null) {
+            //args0=findVoidSetters(proxy.getClass());
+            args0 = findBooleanSetters(proxy.getClass());
+        }
+        Hashtable h = null;
+        if (null != findMethod(proxy.getClass(), "getOptionAliases",
+                new Class[] {})) {
+            h = (Hashtable) callMethod0(proxy, "getOptionAliases");
+        }
+        return processArgs(proxy, args, args0, null, h);
+    }
+
+    public static boolean processArgs(Object proxy, String args[],
+            String args0[], String args1[], Hashtable aliases) throws Exception {
+        for (int i = 0; i < args.length; i++) {
+            String arg = args[i];
+            if (arg.startsWith("-"))
+                arg = arg.substring(1);
+            if (aliases != null && aliases.get(arg) != null)
+                arg = (String) aliases.get(arg);
+
+            if (args0 != null) {
+                boolean set = false;
+                for (int j = 0; j < args0.length; j++) {
+                    if (args0[j].equalsIgnoreCase(arg)) {
+                        setProperty(proxy, args0[j], "true");
+                        set = true;
+                        break;
+                    }
+                }
+                if (set)
+                    continue;
+            }
+            if (args1 != null) {
+                for (int j = 0; j < args1.length; j++) {
+                    if (args1[j].equalsIgnoreCase(arg)) {
+                        i++;
+                        if (i >= args.length)
+                            return false;
+                        setProperty(proxy, arg, args[i]);
+                        break;
+                    }
+                }
+            } else {
+                // if args1 is not specified,assume all other options have param
+                i++;
+                if (i >= args.length)
+                    return false;
+                setProperty(proxy, arg, args[i]);
+            }
+
+        }
+        return true;
+    }
+
+    // -------------------- other utils --------------------
+    public static void clear() {
+        objectMethods.clear();
+    }
+    
+    public static String[] findVoidSetters(Class c) {
+        Method m[] = findMethods(c);
+        if (m == null)
+            return null;
+        Vector v = new Vector();
+        for (int i = 0; i < m.length; i++) {
+            if (m[i].getName().startsWith("set")
+                    && m[i].getParameterTypes().length == 0) {
+                String arg = m[i].getName().substring(3);
+                v.addElement(unCapitalize(arg));
+            }
+        }
+        String s[] = new String[v.size()];
+        for (int i = 0; i < s.length; i++) {
+            s[i] = (String) v.elementAt(i);
+        }
+        return s;
+    }
+
+    public static String[] findBooleanSetters(Class c) {
+        Method m[] = findMethods(c);
+        if (m == null)
+            return null;
+        Vector v = new Vector();
+        for (int i = 0; i < m.length; i++) {
+            if (m[i].getName().startsWith("set")
+                    && m[i].getParameterTypes().length == 1
+                    && "boolean".equalsIgnoreCase(m[i].getParameterTypes()[0]
+                            .getName())) {
+                String arg = m[i].getName().substring(3);
+                v.addElement(unCapitalize(arg));
+            }
+        }
+        String s[] = new String[v.size()];
+        for (int i = 0; i < s.length; i++) {
+            s[i] = (String) v.elementAt(i);
+        }
+        return s;
+    }
+
+    static Hashtable objectMethods = new Hashtable();
+
+    public static Method[] findMethods(Class c) {
+        Method methods[] = (Method[]) objectMethods.get(c);
+        if (methods != null)
+            return methods;
+
+        methods = c.getMethods();
+        objectMethods.put(c, methods);
+        return methods;
+    }
+
+    public static Method findMethod(Class c, String name, Class params[]) {
+        Method methods[] = findMethods(c);
+        if (methods == null)
+            return null;
+        for (int i = 0; i < methods.length; i++) {
+            if (methods[i].getName().equals(name)) {
+                Class methodParams[] = methods[i].getParameterTypes();
+                if (methodParams == null)
+                    if (params == null || params.length == 0)
+                        return methods[i];
+                if (params == null)
+                    if (methodParams == null || methodParams.length == 0)
+                        return methods[i];
+                if (params.length != methodParams.length)
+                    continue;
+                boolean found = true;
+                for (int j = 0; j < params.length; j++) {
+                    if (params[j] != methodParams[j]) {
+                        found = false;
+                        break;
+                    }
+                }
+                if (found)
+                    return methods[i];
+            }
+        }
+        return null;
+    }
+
+    /** Test if the object implements a particular
+     *  method
+     */
+    public static boolean hasHook(Object obj, String methodN) {
+        try {
+            Method myMethods[] = findMethods(obj.getClass());
+            for (int i = 0; i < myMethods.length; i++) {
+                if (methodN.equals(myMethods[i].getName())) {
+                    // check if it's overriden
+                    Class declaring = myMethods[i].getDeclaringClass();
+                    Class parentOfDeclaring = declaring.getSuperclass();
+                    // this works only if the base class doesn't extend
+                    // another class.
+
+                    // if the method is declared in a top level class
+                    // like BaseInterceptor parent is Object, otherwise
+                    // parent is BaseInterceptor or an intermediate class
+                    if (!"java.lang.Object".equals(parentOfDeclaring.getName())) {
+                        return true;
+                    }
+                }
+            }
+        } catch (Exception ex) {
+            ex.printStackTrace();
+        }
+        return false;
+    }
+
+    public static void callMain(Class c, String args[]) throws Exception {
+        Class p[] = new Class[1];
+        p[0] = args.getClass();
+        Method m = c.getMethod("main", p);
+        m.invoke(c, new Object[] { args });
+    }
+
+    public static Object callMethod1(Object target, String methodN,
+            Object param1, String typeParam1, ClassLoader cl) throws Exception {
+        if (target == null || param1 == null) {
+            d("Assert: Illegal params " + target + " " + param1);
+        }
+        if (dbg > 0)
+            d("callMethod1 " + target.getClass().getName() + " "
+                    + param1.getClass().getName() + " " + typeParam1);
+
+        Class params[] = new Class[1];
+        if (typeParam1 == null)
+            params[0] = param1.getClass();
+        else
+            params[0] = cl.loadClass(typeParam1);
+        Method m = findMethod(target.getClass(), methodN, params);
+        if (m == null)
+            throw new NoSuchMethodException(target.getClass().getName() + " "
+                    + methodN);
+        return m.invoke(target, new Object[] { param1 });
+    }
+
+    public static Object callMethod0(Object target, String methodN)
+            throws Exception {
+        if (target == null) {
+            d("Assert: Illegal params " + target);
+            return null;
+        }
+        if (dbg > 0)
+            d("callMethod0 " + target.getClass().getName() + "." + methodN);
+
+        Class params[] = new Class[0];
+        Method m = findMethod(target.getClass(), methodN, params);
+        if (m == null)
+            throw new NoSuchMethodException(target.getClass().getName() + " "
+                    + methodN);
+        return m.invoke(target, emptyArray);
+    }
+
+    static Object[] emptyArray = new Object[] {};
+
+    public static Object callMethodN(Object target, String methodN,
+            Object params[], Class typeParams[]) throws Exception {
+        Method m = null;
+        m = findMethod(target.getClass(), methodN, typeParams);
+        if (m == null) {
+            d("Can't find method " + methodN + " in " + target + " CLASS "
+                    + target.getClass());
+            return null;
+        }
+        Object o = m.invoke(target, params);
+
+        if (dbg > 0) {
+            // debug
+            StringBuffer sb = new StringBuffer();
+            sb.append("" + target.getClass().getName() + "." + methodN + "( ");
+            for (int i = 0; i < params.length; i++) {
+                if (i > 0)
+                    sb.append(", ");
+                sb.append(params[i]);
+            }
+            sb.append(")");
+            d(sb.toString());
+        }
+        return o;
+    }
+
+    public static Object convert(String object, Class paramType) {
+        Object result = null;
+        if ("java.lang.String".equals(paramType.getName())) {
+            result = object;
+        } else if ("java.lang.Integer".equals(paramType.getName())
+                || "int".equals(paramType.getName())) {
+            try {
+                result = new Integer(object);
+            } catch (NumberFormatException ex) {
+            }
+            // Try a setFoo ( boolean )
+        } else if ("java.lang.Boolean".equals(paramType.getName())
+                || "boolean".equals(paramType.getName())) {
+            result = new Boolean(object);
+
+            // Try a setFoo ( InetAddress )
+        } else if ("java.net.InetAddress".equals(paramType
+                .getName())) {
+            try {
+                result = InetAddress.getByName(object);
+            } catch (UnknownHostException exc) {
+                d("Unable to resolve host name:" + object);
+            }
+
+            // Unknown type
+        } else {
+            d("Unknown type " + paramType.getName());
+        }
+        if (result == null) {
+            throw new IllegalArgumentException("Can't convert argument: " + object);
+        }
+        return result;
+    }
+    
+    // -------------------- Get property --------------------
+    // This provides a layer of abstraction
+
+    public static interface PropertySource {
+
+        public String getProperty(String key);
+
+    }
+
+    public static interface AttributeHolder {
+
+        public void setAttribute(String key, Object o);
+
+    }
+
+    // debug --------------------
+    static final int dbg = 0;
+
+    static void d(String s) {
+        if (log.isDebugEnabled())
+            log.debug("IntrospectionUtils: " + s);
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/buf/Ascii.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/buf/Ascii.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/buf/Ascii.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,246 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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;
+
+/**
+ * This class implements some basic ASCII character handling functions.
+ *
+ * @author dac at eng.sun.com
+ * @author James Todd [gonzo at eng.sun.com]
+ */
+public final class Ascii {
+    /*
+     * Character translation tables.
+     */
+
+    private static final byte[] toUpper = new byte[256];
+    private static final byte[] toLower = new byte[256];
+
+    /*
+     * Character type tables.
+     */
+
+    private static final boolean[] isAlpha = new boolean[256];
+    private static final boolean[] isUpper = new boolean[256];
+    private static final boolean[] isLower = new boolean[256];
+    private static final boolean[] isWhite = new boolean[256];
+    private static final boolean[] isDigit = new boolean[256];
+
+    /*
+     * Initialize character translation and type tables.
+     */
+
+    static {
+        for (int i = 0; i < 256; i++) {
+            toUpper[i] = (byte)i;
+            toLower[i] = (byte)i;
+        }
+
+        for (int lc = 'a'; lc <= 'z'; lc++) {
+            int uc = lc + 'A' - 'a';
+
+            toUpper[lc] = (byte)uc;
+            toLower[uc] = (byte)lc;
+            isAlpha[lc] = true;
+            isAlpha[uc] = true;
+            isLower[lc] = true;
+            isUpper[uc] = true;
+        }
+
+        isWhite[ ' '] = true;
+        isWhite['\t'] = true;
+        isWhite['\r'] = true;
+        isWhite['\n'] = true;
+        isWhite['\f'] = true;
+        isWhite['\b'] = true;
+
+        for (int d = '0'; d <= '9'; d++) {
+            isDigit[d] = true;
+        }
+    }
+
+    /**
+     * Returns the upper case equivalent of the specified ASCII character.
+     */
+
+    public static int toUpper(int c) {
+        return toUpper[c & 0xff] & 0xff;
+    }
+
+    /**
+     * Returns the lower case equivalent of the specified ASCII character.
+     */
+
+    public static int toLower(int c) {
+        return toLower[c & 0xff] & 0xff;
+    }
+
+    /**
+     * Returns true if the specified ASCII character is upper or lower case.
+     */
+
+    public static boolean isAlpha(int c) {
+        return isAlpha[c & 0xff];
+    }
+
+    /**
+     * Returns true if the specified ASCII character is upper case.
+     */
+
+    public static boolean isUpper(int c) {
+        return isUpper[c & 0xff];
+    }
+
+    /**
+     * Returns true if the specified ASCII character is lower case.
+     */
+
+    public static boolean isLower(int c) {
+        return isLower[c & 0xff];
+    }
+
+    /**
+     * Returns true if the specified ASCII character is white space.
+     */
+
+    public static boolean isWhite(int c) {
+        return isWhite[c & 0xff];
+    }
+
+    /**
+     * Returns true if the specified ASCII character is a digit.
+     */
+
+    public static boolean isDigit(int c) {
+        return isDigit[c & 0xff];
+    }
+
+    /**
+     * Parses an unsigned integer from the specified subarray of bytes.
+     * @param b the bytes to parse
+     * @param off the start offset of the bytes
+     * @param len the length of the bytes
+     * @exception NumberFormatException if the integer format was invalid
+     */
+    public static int parseInt(byte[] b, int off, int len)
+        throws NumberFormatException
+    {
+        int c;
+
+        if (b == null || len <= 0 || !isDigit(c = b[off++])) {
+            throw new NumberFormatException();
+        }
+
+        int n = c - '0';
+
+        while (--len > 0) {
+            if (!isDigit(c = b[off++])) {
+                throw new NumberFormatException();
+            }
+            n = n * 10 + c - '0';
+        }
+
+        return n;
+    }
+
+    public static int parseInt(char[] b, int off, int len)
+        throws NumberFormatException
+    {
+        int c;
+
+        if (b == null || len <= 0 || !isDigit(c = b[off++])) {
+            throw new NumberFormatException();
+        }
+
+        int n = c - '0';
+
+        while (--len > 0) {
+            if (!isDigit(c = b[off++])) {
+                throw new NumberFormatException();
+            }
+            n = n * 10 + c - '0';
+        }
+
+        return n;
+    }
+
+    /**
+     * Parses an unsigned long from the specified subarray of bytes.
+     * @param b the bytes to parse
+     * @param off the start offset of the bytes
+     * @param len the length of the bytes
+     * @exception NumberFormatException if the long format was invalid
+     */
+    public static long parseLong(byte[] b, int off, int len)
+        throws NumberFormatException
+    {
+        int c;
+
+        if (b == null || len <= 0 || !isDigit(c = b[off++])) {
+            throw new NumberFormatException();
+        }
+
+        long n = c - '0';
+        long m;
+        
+        while (--len > 0) {
+            if (!isDigit(c = b[off++])) {
+                throw new NumberFormatException();
+            }
+            m = n * 10 + c - '0';
+
+            if (m < n) {
+                // Overflow
+                throw new NumberFormatException();
+            } else {
+                n = m;
+            }
+        }
+
+        return n;
+    }
+
+    public static long parseLong(char[] b, int off, int len)
+        throws NumberFormatException
+    {
+        int c;
+
+        if (b == null || len <= 0 || !isDigit(c = b[off++])) {
+            throw new NumberFormatException();
+        }
+
+        long n = c - '0';
+        long m;
+
+        while (--len > 0) {
+            if (!isDigit(c = b[off++])) {
+                throw new NumberFormatException();
+            }
+            m = n * 10 + c - '0';
+
+            if (m < n) {
+                // Overflow
+                throw new NumberFormatException();
+            } else {
+                n = m;
+            }
+        }
+
+        return n;
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/buf/B2CConverter.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/buf/B2CConverter.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/buf/B2CConverter.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,273 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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 java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.UnsupportedEncodingException;
+
+/** Efficient conversion of bytes  to character .
+ *  
+ *  This uses the standard JDK mechansim - a reader - but provides mechanisms
+ *  to recycle all the objects that are used. It is compatible with JDK1.1
+ *  and up,
+ *  ( nio is better, but it's not available even in 1.2 or 1.3 )
+ *
+ *  Not used in the current code, the performance gain is not very big
+ *  in the current case ( since String is created anyway ), but it will
+ *  be used in a later version or after the remaining optimizations.
+ */
+public class B2CConverter {
+    
+    
+    private static org.apache.commons.logging.Log log=
+        org.apache.commons.logging.LogFactory.getLog( B2CConverter.class );
+    
+    private IntermediateInputStream iis;
+    private ReadConvertor conv;
+    private String encoding;
+
+    protected B2CConverter() {
+    }
+    
+    /** Create a converter, with bytes going to a byte buffer
+     */
+    public B2CConverter(String encoding)
+	throws IOException
+    {
+	this.encoding=encoding;
+	reset();
+    }
+
+    
+    /** Reset the internal state, empty the buffers.
+     *  The encoding remain in effect, the internal buffers remain allocated.
+     */
+    public  void recycle() {
+	conv.recycle();
+    }
+
+    static final int BUFFER_SIZE=8192;
+    char result[]=new char[BUFFER_SIZE];
+
+    /** Convert a buffer of bytes into a chars
+     */
+    public  void convert( ByteChunk bb, CharChunk cb )
+	throws IOException
+    {
+	// Set the ByteChunk as input to the Intermediate reader
+	iis.setByteChunk( bb );
+	convert(cb);
+    }
+
+    private void convert(CharChunk cb)
+	throws IOException
+    {
+	try {
+	    // read from the reader
+	    while( true ) { // conv.ready() ) {
+		int cnt=conv.read( result, 0, BUFFER_SIZE );
+		if( cnt <= 0 ) {
+		    // End of stream ! - we may be in a bad state
+		    if( debug>0)
+			log( "EOF" );
+		    //		    reset();
+		    return;
+		}
+		if( debug > 1 )
+		    log("Converted: " + new String( result, 0, cnt ));
+
+		// XXX go directly
+		cb.append( result, 0, cnt );
+	    }
+	} catch( IOException ex) {
+	    if( debug>0)
+		log( "Reseting the converter " + ex.toString() );
+	    reset();
+	    throw ex;
+	}
+    }
+
+    public void reset()
+	throws IOException
+    {
+	// destroy the reader/iis
+	iis=new IntermediateInputStream();
+	conv=new ReadConvertor( iis, encoding );
+    }
+
+    private final int debug=0;
+    void log( String s ) {
+        if (log.isDebugEnabled())
+            log.debug("B2CConverter: " + s );
+    }
+
+    // -------------------- Not used - the speed improvemnt is quite small
+
+    /*
+    private Hashtable decoders;
+    public static final boolean useNewString=false;
+    public static final boolean useSpecialDecoders=true;
+    private UTF8Decoder utfD;
+    // private char[] conversionBuff;
+    CharChunk conversionBuf;
+
+
+    private  static String decodeString(ByteChunk mb, String enc)
+	throws IOException
+    {
+	byte buff=mb.getBuffer();
+	int start=mb.getStart();
+	int end=mb.getEnd();
+	if( useNewString ) {
+	    if( enc==null) enc="UTF8";
+	    return new String( buff, start, end-start, enc );
+	}
+	B2CConverter b2c=null;
+	if( useSpecialDecoders &&
+	    (enc==null || "UTF8".equalsIgnoreCase(enc))) {
+	    if( utfD==null ) utfD=new UTF8Decoder();
+	    b2c=utfD;
+	}
+	if(decoders == null ) decoders=new Hashtable();
+	if( enc==null ) enc="UTF8";
+	b2c=(B2CConverter)decoders.get( enc );
+	if( b2c==null ) {
+	    if( useSpecialDecoders ) {
+		if( "UTF8".equalsIgnoreCase( enc ) ) {
+		    b2c=new UTF8Decoder();
+		}
+	    }
+	    if( b2c==null )
+		b2c=new B2CConverter( enc );
+	    decoders.put( enc, b2c );
+	}
+	if( conversionBuf==null ) conversionBuf=new CharChunk(1024);
+
+	try {
+	    conversionBuf.recycle();
+	    b2c.convert( this, conversionBuf );
+	    //System.out.println("XXX 1 " + conversionBuf );
+	    return conversionBuf.toString();
+	} catch( IOException ex ) {
+	    ex.printStackTrace();
+	    return null;
+	}
+    }
+
+    */
+}
+
+// -------------------- Private implementation --------------------
+
+
+
+/**
+ * 
+ */
+final class  ReadConvertor extends InputStreamReader {
+    // stream with flush() and close(). overriden.
+    private IntermediateInputStream iis;
+    
+    // Has a private, internal byte[8192]
+    
+    /** Create a converter.
+     */
+    public ReadConvertor( IntermediateInputStream in, String enc )
+	throws UnsupportedEncodingException
+    {
+	super( in, enc );
+	iis=in;
+    }
+    
+    /** Overriden - will do nothing but reset internal state.
+     */
+    public  final void close() throws IOException {
+	// NOTHING
+	// Calling super.close() would reset out and cb.
+    }
+    
+    public  final int read(char cbuf[], int off, int len)
+	throws IOException
+    {
+	// will do the conversion and call write on the output stream
+	return super.read( cbuf, off, len );
+    }
+    
+    /** Reset the buffer
+     */
+    public  final void recycle() {
+    }
+}
+
+
+/** Special output stream where close() is overriden, so super.close()
+    is never called.
+    
+    This allows recycling. It can also be disabled, so callbacks will
+    not be called if recycling the converter and if data was not flushed.
+*/
+final class IntermediateInputStream extends InputStream {
+    byte buf[];
+    int pos;
+    int len;
+    int end;
+    
+    public IntermediateInputStream() {
+    }
+    
+    public  final void close() throws IOException {
+	// shouldn't be called - we filter it out in writer
+	throw new IOException("close() called - shouldn't happen ");
+    }
+    
+    public  final  int read(byte cbuf[], int off, int len) throws IOException {
+	if( pos >= end ) return -1;
+	if (pos + len > end) {
+	    len = end - pos;
+	}
+	if (len <= 0) {
+	    return 0;
+	}
+	System.arraycopy(buf, pos, cbuf, off, len);
+	pos += len;
+	return len;
+    }
+    
+    public  final int read() throws IOException {
+	return (pos < end ) ? (buf[pos++] & 0xff) : -1;
+    }
+
+    // -------------------- Internal methods --------------------
+
+    void setBuffer( byte b[], int p, int l ) {
+	buf=b;
+	pos=p;
+	len=l;
+	end=pos+len;
+    }
+
+    void setByteChunk( ByteChunk mb ) {
+	buf=mb.getBytes();
+	pos=mb.getStart();
+	len=mb.getLength();
+	end=pos+len;
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/buf/Base64.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/buf/Base64.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/buf/Base64.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,268 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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;
+
+
+/**
+ * This class provides encode/decode for RFC 2045 Base64 as
+ * defined by RFC 2045, N. Freed and N. Borenstein.
+ * RFC 2045: Multipurpose Internet Mail Extensions (MIME)
+ * Part One: Format of Internet Message Bodies. Reference
+ * 1996 Available at: http://www.ietf.org/rfc/rfc2045.txt
+ * This class is used by XML Schema binary format validation
+ *
+ * @author Jeffrey Rodriguez
+ * @version $Revision: 299789 $ $Date: 2004-09-17 13:34:19 -0500 (Fri, 17 Sep 2004) $
+ */
+
+public final class Base64 {
+
+
+    private static org.apache.commons.logging.Log log=
+        org.apache.commons.logging.LogFactory.getLog( Base64.class );
+    
+    static private final int  BASELENGTH         = 255;
+    static private final int  LOOKUPLENGTH       = 63;
+    static private final int  TWENTYFOURBITGROUP = 24;
+    static private final int  EIGHTBIT           = 8;
+    static private final int  SIXTEENBIT         = 16;
+    static private final int  SIXBIT             = 6;
+    static private final int  FOURBYTE           = 4;
+
+
+    static private final byte PAD               = ( byte ) '=';
+    static private byte [] base64Alphabet       = new byte[BASELENGTH];
+    static private byte [] lookUpBase64Alphabet = new byte[LOOKUPLENGTH];
+
+    static {
+
+        for (int i = 0; i<BASELENGTH; i++ ) {
+            base64Alphabet[i] = -1;
+        }
+        for ( int i = 'Z'; i >= 'A'; i-- ) {
+            base64Alphabet[i] = (byte) (i-'A');
+        }
+        for ( int i = 'z'; i>= 'a'; i--) {
+            base64Alphabet[i] = (byte) ( i-'a' + 26);
+        }
+
+        for ( int i = '9'; i >= '0'; i--) {
+            base64Alphabet[i] = (byte) (i-'0' + 52);
+        }
+
+        base64Alphabet['+']  = 62;
+        base64Alphabet['/']  = 63;
+
+       for (int i = 0; i<=25; i++ )
+            lookUpBase64Alphabet[i] = (byte) ('A'+i );
+
+        for (int i = 26,  j = 0; i<=51; i++, j++ )
+            lookUpBase64Alphabet[i] = (byte) ('a'+ j );
+
+        for (int i = 52,  j = 0; i<=61; i++, j++ )
+            lookUpBase64Alphabet[i] = (byte) ('0' + j );
+
+    }
+
+
+    static boolean isBase64( byte octect ) {
+        //shall we ignore white space? JEFF??
+        return(octect == PAD || base64Alphabet[octect] != -1 );
+    }
+
+
+    static boolean isArrayByteBase64( byte[] arrayOctect ) {
+        int length = arrayOctect.length;
+        if ( length == 0 )
+            return false;
+        for ( int i=0; i < length; i++ ) {
+            if ( Base64.isBase64( arrayOctect[i] ) == false)
+                return false;
+        }
+        return true;
+    }
+
+    /**
+     * Encodes hex octects into Base64
+     *
+     * @param binaryData Array containing binaryData
+     * @return Encoded Base64 array
+     */
+    public static byte[] encode( byte[] binaryData ) {
+        int      lengthDataBits    = binaryData.length*EIGHTBIT;
+        int      fewerThan24bits   = lengthDataBits%TWENTYFOURBITGROUP;
+        int      numberTriplets    = lengthDataBits/TWENTYFOURBITGROUP;
+        byte     encodedData[]     = null;
+
+
+        if ( fewerThan24bits != 0 ) //data not divisible by 24 bit
+            encodedData = new byte[ (numberTriplets + 1 )*4  ];
+        else // 16 or 8 bit
+            encodedData = new byte[ numberTriplets*4 ];
+
+        byte k=0, l=0, b1=0,b2=0,b3=0;
+
+        int encodedIndex = 0;
+        int dataIndex   = 0;
+        int i           = 0;
+        for ( i = 0; i<numberTriplets; i++ ) {
+
+            dataIndex = i*3;
+            b1 = binaryData[dataIndex];
+            b2 = binaryData[dataIndex + 1];
+            b3 = binaryData[dataIndex + 2];
+
+            l  = (byte)(b2 & 0x0f);
+            k  = (byte)(b1 & 0x03);
+
+            encodedIndex = i*4;
+            encodedData[encodedIndex]   = lookUpBase64Alphabet[ b1 >>2 ];
+            encodedData[encodedIndex+1] = lookUpBase64Alphabet[(b2 >>4 ) |
+( k<<4 )];
+            encodedData[encodedIndex+2] = lookUpBase64Alphabet[ (l <<2 ) |
+( b3>>6)];
+            encodedData[encodedIndex+3] = lookUpBase64Alphabet[ b3 & 0x3f ];
+        }
+
+        // form integral number of 6-bit groups
+        dataIndex    = i*3;
+        encodedIndex = i*4;
+        if (fewerThan24bits == EIGHTBIT ) {
+            b1 = binaryData[dataIndex];
+            k = (byte) ( b1 &0x03 );
+            encodedData[encodedIndex]     = lookUpBase64Alphabet[ b1 >>2 ];
+            encodedData[encodedIndex + 1] = lookUpBase64Alphabet[ k<<4 ];
+            encodedData[encodedIndex + 2] = PAD;
+            encodedData[encodedIndex + 3] = PAD;
+        } else if ( fewerThan24bits == SIXTEENBIT ) {
+
+            b1 = binaryData[dataIndex];
+            b2 = binaryData[dataIndex +1 ];
+            l = ( byte ) ( b2 &0x0f );
+            k = ( byte ) ( b1 &0x03 );
+            encodedData[encodedIndex]     = lookUpBase64Alphabet[ b1 >>2 ];
+            encodedData[encodedIndex + 1] = lookUpBase64Alphabet[ (b2 >>4 )
+| ( k<<4 )];
+            encodedData[encodedIndex + 2] = lookUpBase64Alphabet[ l<<2 ];
+            encodedData[encodedIndex + 3] = PAD;
+        }
+        return encodedData;
+    }
+
+
+    /**
+     * Decodes Base64 data into octects
+     *
+     * @param base64Data Byte array containing Base64 data
+     * @return Array containind decoded data.
+     */
+    public byte[] decode( byte[] base64Data ) {
+        int      numberQuadruple    = base64Data.length/FOURBYTE;
+        byte     decodedData[]      = null;
+        byte     b1=0,b2=0,b3=0, b4=0, marker0=0, marker1=0;
+
+        // Throw away anything not in base64Data
+        // Adjust size
+
+        int encodedIndex = 0;
+        int dataIndex    = 0;
+        decodedData      = new byte[ numberQuadruple*3 + 1 ];
+
+        for (int i = 0; i<numberQuadruple; i++ ) {
+            dataIndex = i*4;
+            marker0   = base64Data[dataIndex +2];
+            marker1   = base64Data[dataIndex +3];
+
+            b1 = base64Alphabet[base64Data[dataIndex]];
+            b2 = base64Alphabet[base64Data[dataIndex +1]];
+
+            if ( marker0 != PAD && marker1 != PAD ) {     //No PAD e.g 3cQl
+                b3 = base64Alphabet[ marker0 ];
+                b4 = base64Alphabet[ marker1 ];
+
+                decodedData[encodedIndex]   = (byte)(  b1 <<2 | b2>>4 ) ;
+                decodedData[encodedIndex+1] = (byte)(((b2 & 0xf)<<4 ) |(
+(b3>>2) & 0xf) );
+                decodedData[encodedIndex+2] = (byte)( b3<<6 | b4 );
+            } else if ( marker0 == PAD ) {               //Two PAD e.g. 3c[Pad][Pad]
+                decodedData[encodedIndex]   = (byte)(  b1 <<2 | b2>>4 ) ;
+                decodedData[encodedIndex+1] = (byte)((b2 & 0xf)<<4 );
+                decodedData[encodedIndex+2] = (byte) 0;
+            } else if ( marker1 == PAD ) {              //One PAD e.g. 3cQ[Pad]
+                b3 = base64Alphabet[ marker0 ];
+
+                decodedData[encodedIndex]   = (byte)(  b1 <<2 | b2>>4 );
+                decodedData[encodedIndex+1] = (byte)(((b2 & 0xf)<<4 ) |(
+(b3>>2) & 0xf) );
+                decodedData[encodedIndex+2] = (byte)( b3<<6);
+            }
+            encodedIndex += 3;
+        }
+        return decodedData;
+
+    }
+
+    static final int base64[]= {
+	64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
+	    64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
+	    64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 62, 64, 64, 64, 63,
+	    52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 64, 64, 64, 64, 64, 64,
+	    64,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14,
+	    15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 64, 64, 64, 64, 64,
+	    64, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
+	    41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 64, 64, 64, 64, 64,
+	    64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
+	    64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
+	    64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
+	    64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
+	    64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
+	    64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
+	    64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
+	    64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64
+    };
+
+    public static String base64Decode( String orig ) {
+	char chars[]=orig.toCharArray();
+	StringBuffer sb=new StringBuffer();
+	int i=0;
+
+	int shift = 0;   // # of excess bits stored in accum
+	int acc = 0;
+	
+	for (i=0; i<chars.length; i++) {
+	    int v = base64[ chars[i] & 0xFF ];
+	    
+	    if ( v >= 64 ) {
+		if( chars[i] != '=' )
+                    if (log.isDebugEnabled())
+                        log.debug("Wrong char in base64: " + chars[i]);
+	    } else {
+		acc= ( acc << 6 ) | v;
+		shift += 6;
+		if ( shift >= 8 ) {
+		    shift -= 8;
+		    sb.append( (char) ((acc >> shift) & 0xff));
+		}
+	    }
+	}
+	return sb.toString();
+    }
+
+
+}
+

Added: branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/buf/ByteChunk.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/buf/ByteChunk.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/buf/ByteChunk.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,824 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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 java.io.IOException;
+import java.io.Serializable;
+
+/*
+ * In a server it is very important to be able to operate on
+ * the original byte[] without converting everything to chars.
+ * Some protocols are ASCII only, and some allow different
+ * non-UNICODE encodings. The encoding is not known beforehand,
+ * and can even change during the execution of the protocol.
+ * ( for example a multipart message may have parts with different
+ *  encoding )
+ *
+ * For HTTP it is not very clear how the encoding of RequestURI
+ * and mime values can be determined, but it is a great advantage
+ * to be able to parse the request without converting to string.
+ */
+
+// TODO: This class could either extend ByteBuffer, or better a ByteBuffer inside
+// this way it could provide the search/etc on ByteBuffer, as a helper.
+
+/**
+ * This class is used to represent a chunk of bytes, and
+ * utilities to manipulate byte[].
+ *
+ * The buffer can be modified and used for both input and output.
+ *
+ * There are 2 modes: The chunk can be associated with a sink - ByteInputChannel or ByteOutputChannel,
+ * which will be used when the buffer is empty ( on input ) or filled ( on output ).
+ * For output, it can also grow. This operating mode is selected by calling setLimit() or
+ * allocate(initial, limit) with limit != -1.
+ *
+ * Various search and append method are defined - similar with String and StringBuffer, but
+ * operating on bytes.
+ *
+ * This is important because it allows processing the http headers directly on the received bytes,
+ * without converting to chars and Strings until the strings are needed. In addition, the charset
+ * is determined later, from headers or user code.
+ *
+ *
+ * @author dac at sun.com
+ * @author James Todd [gonzo at sun.com]
+ * @author Costin Manolache
+ * @author Remy Maucherat
+ */
+public final class ByteChunk implements Cloneable, Serializable {
+
+    /** Input interface, used when the buffer is emptiy
+     *
+     * Same as java.nio.channel.ReadableByteChannel
+     */
+    public static interface ByteInputChannel {
+        /** 
+         * Read new bytes ( usually the internal conversion buffer ).
+         * The implementation is allowed to ignore the parameters, 
+         * and mutate the chunk if it wishes to implement its own buffering.
+         */
+        public int realReadBytes(byte cbuf[], int off, int len)
+            throws IOException;
+    }
+
+    /** Same as java.nio.channel.WrittableByteChannel.
+     */
+    public static interface ByteOutputChannel {
+        /** 
+         * Send the bytes ( usually the internal conversion buffer ).
+         * Expect 8k output if the buffer is full.
+         */
+        public void realWriteBytes(byte cbuf[], int off, int len)
+            throws IOException;
+    }
+
+    // --------------------
+
+    /** Default encoding used to convert to strings. It should be UTF8,
+	as most standards seem to converge, but the servlet API requires
+	8859_1, and this object is used mostly for servlets. 
+    */
+    public static final String DEFAULT_CHARACTER_ENCODING="ISO-8859-1";
+        
+    // byte[]
+    private byte[] buff;
+
+    private int start=0;
+    private int end;
+
+    private String enc;
+
+    private boolean isSet=false; // XXX
+
+    // How much can it grow, when data is added
+    private int limit=-1;
+
+    private ByteInputChannel in = null;
+    private ByteOutputChannel out = null;
+
+    private boolean isOutput=false;
+    private boolean optimizedWrite=true;
+    
+    /**
+     * Creates a new, uninitialized ByteChunk object.
+     */
+    public ByteChunk() {
+    }
+
+    public ByteChunk( int initial ) {
+	allocate( initial, -1 );
+    }
+
+    //--------------------
+    public ByteChunk getClone() {
+	try {
+	    return (ByteChunk)this.clone();
+	} catch( Exception ex) {
+	    return null;
+	}
+    }
+
+    public boolean isNull() {
+	return ! isSet; // buff==null;
+    }
+    
+    /**
+     * Resets the message buff to an uninitialized state.
+     */
+    public void recycle() {
+	//	buff = null;
+	enc=null;
+	start=0;
+	end=0;
+	isSet=false;
+    }
+
+    public void reset() {
+	buff=null;
+    }
+
+    // -------------------- Setup --------------------
+
+    public void allocate( int initial, int limit  ) {
+	isOutput=true;
+	if( buff==null || buff.length < initial ) {
+	    buff=new byte[initial];
+	}    
+	this.limit=limit;
+	start=0;
+	end=0;
+	isSet=true;
+    }
+
+    /**
+     * Sets the message bytes to the specified subarray of bytes.
+     * 
+     * @param b the ascii bytes
+     * @param off the start offset of the bytes
+     * @param len the length of the bytes
+     */
+    public void setBytes(byte[] b, int off, int len) {
+        buff = b;
+        start = off;
+        end = start+ len;
+        isSet=true;
+    }
+
+    public void setOptimizedWrite(boolean optimizedWrite) {
+        this.optimizedWrite = optimizedWrite;
+    }
+
+    public void setEncoding( String enc ) {
+	this.enc=enc;
+    }
+    public String getEncoding() {
+        if (enc == null)
+            enc=DEFAULT_CHARACTER_ENCODING;
+        return enc;
+    }
+
+    /**
+     * Returns the message bytes.
+     */
+    public byte[] getBytes() {
+	return getBuffer();
+    }
+
+    /**
+     * Returns the message bytes.
+     */
+    public byte[] getBuffer() {
+	return buff;
+    }
+
+    /**
+     * Returns the start offset of the bytes.
+     * For output this is the end of the buffer.
+     */
+    public int getStart() {
+	return start;
+    }
+
+    public int getOffset() {
+	return start;
+    }
+
+    public void setOffset(int off) {
+        if (end < off ) end=off;
+	start=off;
+    }
+
+    /**
+     * Returns the length of the bytes.
+     * XXX need to clean this up
+     */
+    public int getLength() {
+	return end-start;
+    }
+
+    /** Maximum amount of data in this buffer.
+     *
+     *  If -1 or not set, the buffer will grow undefinitely.
+     *  Can be smaller than the current buffer size ( which will not shrink ).
+     *  When the limit is reached, the buffer will be flushed ( if out is set )
+     *  or throw exception.
+     */
+    public void setLimit(int limit) {
+	this.limit=limit;
+    }
+    
+    public int getLimit() {
+	return limit;
+    }
+
+    /**
+     * When the buffer is empty, read the data from the input channel.
+     */
+    public void setByteInputChannel(ByteInputChannel in) {
+        this.in = in;
+    }
+
+    /** When the buffer is full, write the data to the output channel.
+     * 	Also used when large amount of data is appended.
+     *
+     *  If not set, the buffer will grow to the limit.
+     */
+    public void setByteOutputChannel(ByteOutputChannel out) {
+	this.out=out;
+    }
+
+    public int getEnd() {
+	return end;
+    }
+
+    public void setEnd( int i ) {
+	end=i;
+    }
+
+    // -------------------- Adding data to the buffer --------------------
+    /** Append a char, by casting it to byte. This IS NOT intended for unicode.
+     *
+     * @param c
+     * @throws IOException
+     */
+    public void append( char c )
+	throws IOException
+    {
+	append( (byte)c);
+    }
+
+    public void append( byte b )
+	throws IOException
+    {
+	makeSpace( 1 );
+
+	// couldn't make space
+	if( limit >0 && end >= limit ) {
+	    flushBuffer();
+	}
+	buff[end++]=b;
+    }
+
+    public void append( ByteChunk src )
+	throws IOException
+    {
+	append( src.getBytes(), src.getStart(), src.getLength());
+    }
+
+    /** Add data to the buffer
+     */
+    public void append( byte src[], int off, int len )
+	throws IOException
+    {
+	// will grow, up to limit
+	makeSpace( len );
+
+	// if we don't have limit: makeSpace can grow as it wants
+	if( limit < 0 ) {
+	    // assert: makeSpace made enough space
+	    System.arraycopy( src, off, buff, end, len );
+	    end+=len;
+	    return;
+	}
+
+        // Optimize on a common case.
+        // If the buffer is empty and the source is going to fill up all the
+        // space in buffer, may as well write it directly to the output,
+        // and avoid an extra copy
+        if ( optimizedWrite && len == limit && end == start && out != null ) {
+            out.realWriteBytes( src, off, len );
+            return;
+        }
+	// if we have limit and we're below
+	if( len <= limit - end ) {
+	    // makeSpace will grow the buffer to the limit,
+	    // so we have space
+	    System.arraycopy( src, off, buff, end, len );
+	    end+=len;
+	    return;
+	}
+
+	// need more space than we can afford, need to flush
+	// buffer
+
+	// the buffer is already at ( or bigger than ) limit
+
+        // We chunk the data into slices fitting in the buffer limit, although
+        // if the data is written directly if it doesn't fit
+
+        int avail=limit-end;
+        System.arraycopy(src, off, buff, end, avail);
+        end += avail;
+
+        flushBuffer();
+
+        int remain = len - avail;
+
+        while (remain > (limit - end)) {
+            out.realWriteBytes( src, (off + len) - remain, limit - end );
+            remain = remain - (limit - end);
+        }
+
+        System.arraycopy(src, (off + len) - remain, buff, end, remain);
+        end += remain;
+
+    }
+
+
+    // -------------------- Removing data from the buffer --------------------
+
+    public int substract()
+        throws IOException {
+
+        if ((end - start) == 0) {
+            if (in == null)
+                return -1;
+            int n = in.realReadBytes( buff, 0, buff.length );
+            if (n < 0)
+                return -1;
+        }
+
+        return (buff[start++] & 0xFF);
+
+    }
+
+    public int substract(ByteChunk src)
+        throws IOException {
+
+        if ((end - start) == 0) {
+            if (in == null)
+                return -1;
+            int n = in.realReadBytes( buff, 0, buff.length );
+            if (n < 0)
+                return -1;
+        }
+
+        int len = getLength();
+        src.append(buff, start, len);
+        start = end;
+        return len;
+
+    }
+
+    public int substract( byte src[], int off, int len )
+        throws IOException {
+
+        if ((end - start) == 0) {
+            if (in == null)
+                return -1;
+            int n = in.realReadBytes( buff, 0, buff.length );
+            if (n < 0)
+                return -1;
+        }
+
+        int n = len;
+        if (len > getLength()) {
+            n = getLength();
+        }
+        System.arraycopy(buff, start, src, off, n);
+        start += n;
+        return n;
+
+    }
+
+
+    /** Send the buffer to the sink. Called by append() when the limit is reached.
+     *  You can also call it explicitely to force the data to be written.
+     *
+     * @throws IOException
+     */
+    public void flushBuffer()
+	throws IOException
+    {
+	//assert out!=null
+	if( out==null ) {
+	    throw new IOException( "Buffer overflow, no sink " + limit + " " +
+				   buff.length  );
+	}
+	out.realWriteBytes( buff, start, end-start );
+	end=start;
+    }
+
+    /** Make space for len chars. If len is small, allocate
+     *	a reserve space too. Never grow bigger than limit.
+     */
+    private void makeSpace(int count)
+    {
+	byte[] tmp = null;
+
+	int newSize;
+	int desiredSize=end + count;
+
+	// Can't grow above the limit
+	if( limit > 0 &&
+	    desiredSize > limit) {
+	    desiredSize=limit;
+	}
+
+	if( buff==null ) {
+	    if( desiredSize < 256 ) desiredSize=256; // take a minimum
+	    buff=new byte[desiredSize];
+	}
+	
+	// limit < buf.length ( the buffer is already big )
+	// or we already have space XXX
+	if( desiredSize <= buff.length ) {
+	    return;
+	}
+	// grow in larger chunks
+	if( desiredSize < 2 * buff.length ) {
+	    newSize= buff.length * 2;
+	    if( limit >0 &&
+		newSize > limit ) newSize=limit;
+	    tmp=new byte[newSize];
+	} else {
+	    newSize= buff.length * 2 + count ;
+	    if( limit > 0 &&
+		newSize > limit ) newSize=limit;
+	    tmp=new byte[newSize];
+	}
+	
+	System.arraycopy(buff, start, tmp, 0, end-start);
+	buff = tmp;
+	tmp = null;
+	end=end-start;
+	start=0;
+    }
+    
+    // -------------------- Conversion and getters --------------------
+
+    public String toString() {
+        if (null == buff) {
+            return null;
+        } else if (end-start == 0) {
+            return "";
+        }
+        return StringCache.toString(this);
+    }
+    
+    public String toStringInternal() {
+        String strValue=null;
+        try {
+            if( enc==null ) enc=DEFAULT_CHARACTER_ENCODING;
+            strValue = new String( buff, start, end-start, enc );
+            /*
+             Does not improve the speed too much on most systems,
+             it's safer to use the "clasical" new String().
+             
+             Most overhead is in creating char[] and copying,
+             the internal implementation of new String() is very close to
+             what we do. The decoder is nice for large buffers and if
+             we don't go to String ( so we can take advantage of reduced GC)
+             
+             // Method is commented out, in:
+              return B2CConverter.decodeString( enc );
+              */
+        } catch (java.io.UnsupportedEncodingException e) {
+            // Use the platform encoding in that case; the usage of a bad
+            // encoding will have been logged elsewhere already
+            strValue = new String(buff, start, end-start);
+        }
+        return strValue;
+    }
+
+    public int getInt()
+    {
+	return Ascii.parseInt(buff, start,end-start);
+    }
+
+    public long getLong() {
+        return Ascii.parseLong(buff, start,end-start);
+    }
+
+
+    // -------------------- equals --------------------
+
+    /**
+     * Compares the message bytes to the specified String object.
+     * @param s the String to compare
+     * @return true if the comparison succeeded, false otherwise
+     */
+    public boolean equals(String s) {
+	// XXX ENCODING - this only works if encoding is UTF8-compat
+	// ( ok for tomcat, where we compare ascii - header names, etc )!!!
+	
+	byte[] b = buff;
+	int blen = end-start;
+	if (b == null || blen != s.length()) {
+	    return false;
+	}
+	int boff = start;
+	for (int i = 0; i < blen; i++) {
+	    if (b[boff++] != s.charAt(i)) {
+		return false;
+	    }
+	}
+	return true;
+    }
+
+    /**
+     * Compares the message bytes to the specified String object.
+     * @param s the String to compare
+     * @return true if the comparison succeeded, false otherwise
+     */
+    public boolean equalsIgnoreCase(String s) {
+	byte[] b = buff;
+	int blen = end-start;
+	if (b == null || blen != s.length()) {
+	    return false;
+	}
+	int boff = start;
+	for (int i = 0; i < blen; i++) {
+	    if (Ascii.toLower(b[boff++]) != Ascii.toLower(s.charAt(i))) {
+		return false;
+	    }
+	}
+	return true;
+    }
+
+    public boolean equals( ByteChunk bb ) {
+	return equals( bb.getBytes(), bb.getStart(), bb.getLength());
+    }
+    
+    public boolean equals( byte b2[], int off2, int len2) {
+	byte b1[]=buff;
+	if( b1==null && b2==null ) return true;
+
+	int len=end-start;
+	if ( len2 != len || b1==null || b2==null ) 
+	    return false;
+		
+	int off1 = start;
+
+	while ( len-- > 0) {
+	    if (b1[off1++] != b2[off2++]) {
+		return false;
+	    }
+	}
+	return true;
+    }
+
+    public boolean equals( CharChunk cc ) {
+	return equals( cc.getChars(), cc.getStart(), cc.getLength());
+    }
+    
+    public boolean equals( char c2[], int off2, int len2) {
+	// XXX works only for enc compatible with ASCII/UTF !!!
+	byte b1[]=buff;
+	if( c2==null && b1==null ) return true;
+	
+	if (b1== null || c2==null || end-start != len2 ) {
+	    return false;
+	}
+	int off1 = start;
+	int len=end-start;
+	
+	while ( len-- > 0) {
+	    if ( (char)b1[off1++] != c2[off2++]) {
+		return false;
+	    }
+	}
+	return true;
+    }
+
+    /**
+     * Returns true if the message bytes starts with the specified string.
+     * @param s the string
+     */
+    public boolean startsWith(String s) {
+	// Works only if enc==UTF
+	byte[] b = buff;
+	int blen = s.length();
+	if (b == null || blen > end-start) {
+	    return false;
+	}
+	int boff = start;
+	for (int i = 0; i < blen; i++) {
+	    if (b[boff++] != s.charAt(i)) {
+		return false;
+	    }
+	}
+	return true;
+    }
+
+    /* Returns true if the message bytes start with the specified byte array */
+    public boolean startsWith(byte[] b2) {
+        byte[] b1 = buff;
+        if (b1 == null && b2 == null) {
+            return true;
+        }
+
+        int len = end - start;
+        if (b1 == null || b2 == null || b2.length > len) {
+            return false;
+        }
+        for (int i = start, j = 0; i < end && j < b2.length; ) {
+            if (b1[i++] != b2[j++]) 
+                return false;
+        }
+        return true;
+    }
+
+    /**
+     * Returns true if the message bytes starts with the specified string.
+     * @param s the string
+     * @param pos The position
+     */
+    public boolean startsWithIgnoreCase(String s, int pos) {
+	byte[] b = buff;
+	int len = s.length();
+	if (b == null || len+pos > end-start) {
+	    return false;
+	}
+	int off = start+pos;
+	for (int i = 0; i < len; i++) {
+	    if (Ascii.toLower( b[off++] ) != Ascii.toLower( s.charAt(i))) {
+		return false;
+	    }
+	}
+	return true;
+    }
+
+    public int indexOf( String src, int srcOff, int srcLen, int myOff ) {
+	char first=src.charAt( srcOff );
+
+	// Look for first char 
+	int srcEnd = srcOff + srcLen;
+        
+	for( int i=myOff+start; i <= (end - srcLen); i++ ) {
+	    if( buff[i] != first ) continue;
+	    // found first char, now look for a match
+            int myPos=i+1;
+	    for( int srcPos=srcOff + 1; srcPos< srcEnd; ) {
+                if( buff[myPos++] != src.charAt( srcPos++ ))
+		    break;
+                if( srcPos==srcEnd ) return i-start; // found it
+	    }
+	}
+	return -1;
+    }
+
+    // -------------------- Hash code  --------------------
+
+    // normal hash. 
+    public int hash() {
+	return hashBytes( buff, start, end-start);
+    }
+
+    // hash ignoring case
+    public int hashIgnoreCase() {
+	return hashBytesIC( buff, start, end-start );
+    }
+
+    private static int hashBytes( byte buff[], int start, int bytesLen ) {
+	int max=start+bytesLen;
+	byte bb[]=buff;
+	int code=0;
+	for (int i = start; i < max ; i++) {
+	    code = code * 37 + bb[i];
+	}
+	return code;
+    }
+
+    private static int hashBytesIC( byte bytes[], int start,
+				    int bytesLen )
+    {
+	int max=start+bytesLen;
+	byte bb[]=bytes;
+	int code=0;
+	for (int i = start; i < max ; i++) {
+	    code = code * 37 + Ascii.toLower(bb[i]);
+	}
+	return code;
+    }
+
+    /**
+     * Returns true if the message bytes starts with the specified string.
+     * @param c the character
+     * @param starting The start position
+     */
+    public int indexOf(char c, int starting) {
+	int ret = indexOf( buff, start+starting, end, c);
+	return (ret >= start) ? ret - start : -1;
+    }
+
+    public static int  indexOf( byte bytes[], int off, int end, char qq )
+    {
+	// Works only for UTF 
+	while( off < end ) {
+	    byte b=bytes[off];
+	    if( b==qq )
+		return off;
+	    off++;
+	}
+	return -1;
+    }
+
+    /** Find a character, no side effects.
+     *  @return index of char if found, -1 if not
+     */
+    public static int findChar( byte buf[], int start, int end, char c ) {
+	byte b=(byte)c;
+	int offset = start;
+	while (offset < end) {
+	    if (buf[offset] == b) {
+		return offset;
+	    }
+	    offset++;
+	}
+	return -1;
+    }
+
+    /** Find a character, no side effects.
+     *  @return index of char if found, -1 if not
+     */
+    public static int findChars( byte buf[], int start, int end, byte c[] ) {
+	int clen=c.length;
+	int offset = start;
+	while (offset < end) {
+	    for( int i=0; i<clen; i++ ) 
+		if (buf[offset] == c[i]) {
+		    return offset;
+		}
+	    offset++;
+	}
+	return -1;
+    }
+
+    /** Find the first character != c 
+     *  @return index of char if found, -1 if not
+     */
+    public static int findNotChars( byte buf[], int start, int end, byte c[] )
+    {
+	int clen=c.length;
+	int offset = start;
+	boolean found;
+		
+	while (offset < end) {
+	    found=true;
+	    for( int i=0; i<clen; i++ ) {
+		if (buf[offset] == c[i]) {
+		    found=false;
+		    break;
+		}
+	    }
+	    if( found ) { // buf[offset] != c[0..len]
+		return offset;
+	    }
+	    offset++;
+	}
+	return -1;
+    }
+
+
+    /**
+     * Convert specified String to a byte array. This ONLY WORKS for ascii, UTF chars will be truncated.
+     * 
+     * @param value to convert to byte array
+     * @return the byte array value
+     */
+    public static final byte[] convertToBytes(String value) {
+        byte[] result = new byte[value.length()];
+        for (int i = 0; i < value.length(); i++) {
+            result[i] = (byte) value.charAt(i);
+        }
+        return result;
+    }
+    
+    
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/buf/C2BConverter.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/buf/C2BConverter.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/buf/C2BConverter.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,261 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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 java.io.IOException;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.UnsupportedEncodingException;
+
+/** Efficient conversion of character to bytes.
+ *  
+ *  This uses the standard JDK mechansim - a writer - but provides mechanisms
+ *  to recycle all the objects that are used. It is compatible with JDK1.1 and up,
+ *  ( nio is better, but it's not available even in 1.2 or 1.3 )
+ * 
+ */
+public final class C2BConverter {
+    
+    private static org.apache.commons.logging.Log log=
+        org.apache.commons.logging.LogFactory.getLog(C2BConverter.class );
+    
+    private IntermediateOutputStream ios;
+    private WriteConvertor conv;
+    private ByteChunk bb;
+    private String enc;
+    
+    /** Create a converter, with bytes going to a byte buffer
+     */
+    public C2BConverter(ByteChunk output, String encoding) throws IOException {
+	this.bb=output;
+	ios=new IntermediateOutputStream( output );
+	conv=new WriteConvertor( ios, encoding );
+        this.enc=encoding;
+    }
+
+    /** Create a converter
+     */
+    public C2BConverter(String encoding) throws IOException {
+	this( new ByteChunk(1024), encoding );
+    }
+
+    public ByteChunk getByteChunk() {
+	return bb;
+    }
+
+    public String getEncoding() {
+        return enc;
+    }
+
+    public void setByteChunk(ByteChunk bb) {
+	this.bb=bb;
+	ios.setByteChunk( bb );
+    }
+
+    /** Reset the internal state, empty the buffers.
+     *  The encoding remain in effect, the internal buffers remain allocated.
+     */
+    public  final void recycle() {
+	conv.recycle();
+	bb.recycle();
+    }
+
+    /** Generate the bytes using the specified encoding
+     */
+    public  final void convert(char c[], int off, int len ) throws IOException {
+	conv.write( c, off, len );
+    }
+
+    /** Generate the bytes using the specified encoding
+     */
+    public  final void convert(String s ) throws IOException {
+	conv.write( s );
+    }
+
+    /** Generate the bytes using the specified encoding
+     */
+    public  final void convert(char c ) throws IOException {
+	conv.write( c );
+    }
+
+    /** Convert a message bytes chars to bytes
+     */
+    public final void convert(MessageBytes mb ) throws IOException {
+        int type=mb.getType();
+        if( type==MessageBytes.T_BYTES )
+            return;
+        ByteChunk orig=bb;
+        setByteChunk( mb.getByteChunk());
+        bb.recycle();
+        bb.allocate( 32, -1 );
+        
+        if( type==MessageBytes.T_STR ) {
+            convert( mb.getString() );
+            // System.out.println("XXX Converting " + mb.getString() );
+        } else if( type==MessageBytes.T_CHARS ) {
+            CharChunk charC=mb.getCharChunk();
+            convert( charC.getBuffer(),
+                                charC.getOffset(), charC.getLength());
+            //System.out.println("XXX Converting " + mb.getCharChunk() );
+        } else {
+            if (log.isDebugEnabled())
+                log.debug("XXX unknowon type " + type );
+        }
+        flushBuffer();
+        //System.out.println("C2B: XXX " + bb.getBuffer() + bb.getLength()); 
+        setByteChunk(orig);
+    }
+
+    /** Flush any internal buffers into the ByteOutput or the internal
+     *  byte[]
+     */
+    public  final void flushBuffer() throws IOException {
+	conv.flush();
+    }
+
+}
+
+// -------------------- Private implementation --------------------
+
+
+
+/**
+ *  Special writer class, where close() is overritten. The default implementation
+ *  would set byteOutputter to null, and the writter can't be recycled. 
+ *
+ *  Note that the flush method will empty the internal buffers _and_ call
+ *  flush on the output stream - that's why we use an intermediary output stream
+ *  that overrides flush(). The idea is to  have full control: flushing the
+ *  char->byte converter should be independent of flushing the OutputStream.
+ * 
+ *  When a WriteConverter is created, it'll allocate one or 2 byte buffers,
+ *  with a 8k size that can't be changed ( at least in JDK1.1 -> 1.4 ). It would
+ *  also allocate a ByteOutputter or equivalent - again some internal buffers.
+ *
+ *  It is essential to keep  this object around and reuse it. You can use either
+ *  pools or per thread data - but given that in most cases a converter will be
+ *  needed for every thread and most of the time only 1 ( or 2 ) encodings will
+ *  be used, it is far better to keep it per thread and eliminate the pool 
+ *  overhead too.
+ * 
+ */
+ final class	WriteConvertor extends OutputStreamWriter {
+    // stream with flush() and close(). overriden.
+    private IntermediateOutputStream ios;
+    
+    // Has a private, internal byte[8192]
+    
+    /** Create a converter.
+     */
+    public WriteConvertor( IntermediateOutputStream out, String enc )
+	throws UnsupportedEncodingException
+    {
+	super( out, enc );
+	ios=out;
+    }
+    
+    /** Overriden - will do nothing but reset internal state.
+     */
+    public  final void close() throws IOException {
+	// NOTHING
+	// Calling super.close() would reset out and cb.
+    }
+    
+    /**
+     *  Flush the characters only
+     */ 
+    public  final void flush() throws IOException {
+	// Will flushBuffer and out()
+	// flushBuffer put any remaining chars in the byte[] 
+	super.flush();
+    }
+    
+    public  final void write(char cbuf[], int off, int len) throws IOException {
+	// will do the conversion and call write on the output stream
+	super.write( cbuf, off, len );
+    }
+    
+    /** Reset the buffer
+     */
+    public  final void recycle() {
+	ios.disable();
+	try {
+	    //	    System.out.println("Reseting writer");
+	    flush();
+	} catch( Exception ex ) {
+	    ex.printStackTrace();
+	}
+	ios.enable();
+    }
+    
+}
+
+
+/** Special output stream where close() is overriden, so super.close()
+    is never called.
+    
+    This allows recycling. It can also be disabled, so callbacks will
+    not be called if recycling the converter and if data was not flushed.
+*/
+final class IntermediateOutputStream extends OutputStream {
+    private ByteChunk tbuff;
+    private boolean enabled=true;
+    
+    public IntermediateOutputStream(ByteChunk tbuff) {
+	    this.tbuff=tbuff;
+    }
+    
+    public  final void close() throws IOException {
+	// shouldn't be called - we filter it out in writer
+	throw new IOException("close() called - shouldn't happen ");
+    }
+    
+    public  final void flush() throws IOException {
+	// nothing - write will go directly to the buffer,
+	// we don't keep any state
+    }
+    
+    public  final  void write(byte cbuf[], int off, int len) throws IOException {
+	// will do the conversion and call write on the output stream
+	if( enabled ) {
+	    tbuff.append( cbuf, off, len );
+	}
+    }
+    
+    public  final void write( int i ) throws IOException {
+	throw new IOException("write( int ) called - shouldn't happen ");
+    }
+
+    // -------------------- Internal methods --------------------
+
+    void setByteChunk( ByteChunk bb ) {
+	tbuff=bb;
+    }
+    
+    /** Temporary disable - this is used to recycle the converter without
+     *  generating an output if the buffers were not flushed
+     */
+    final void disable() {
+	enabled=false;
+    }
+
+    /** Reenable - used to recycle the converter
+     */
+    final void enable() {
+	enabled=true;
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/buf/CharChunk.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/buf/CharChunk.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/buf/CharChunk.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,720 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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 java.io.IOException;
+import java.io.Serializable;
+
+/**
+ * Utilities to manipluate char chunks. While String is
+ * the easiest way to manipulate chars ( search, substrings, etc),
+ * it is known to not be the most efficient solution - Strings are
+ * designed as imutable and secure objects.
+ * 
+ * @author dac at sun.com
+ * @author James Todd [gonzo at sun.com]
+ * @author Costin Manolache
+ * @author Remy Maucherat
+ */
+public final class CharChunk implements Cloneable, Serializable, CharSequence {
+
+    // Input interface, used when the buffer is emptied.
+    public static interface CharInputChannel {
+        /** 
+         * Read new bytes ( usually the internal conversion buffer ).
+         * The implementation is allowed to ignore the parameters, 
+         * and mutate the chunk if it wishes to implement its own buffering.
+         */
+        public int realReadChars(char cbuf[], int off, int len)
+            throws IOException;
+    }
+    /**
+     *  When we need more space we'll either
+     *  grow the buffer ( up to the limit ) or send it to a channel.
+     */
+    public static interface CharOutputChannel {
+	/** Send the bytes ( usually the internal conversion buffer ).
+	 *  Expect 8k output if the buffer is full.
+	 */
+        public void realWriteChars(char cbuf[], int off, int len)
+            throws IOException;
+    }
+    
+    // -------------------- 
+    // char[]
+    private char buff[];
+
+    private int start;
+    private int end;
+
+    private boolean isSet=false;  // XXX 
+
+    private boolean isOutput=false;
+
+    // -1: grow undefinitely
+    // maximum amount to be cached
+    private int limit=-1;
+
+    private CharInputChannel in = null;
+    private CharOutputChannel out = null;
+    
+    private boolean optimizedWrite=true;
+
+    /**
+     * Creates a new, uninitialized CharChunk object.
+     */
+    public CharChunk() {
+    }
+
+    public CharChunk(int size) {
+	allocate( size, -1 );
+    }
+
+    // --------------------
+    
+    public CharChunk getClone() {
+	try {
+	    return (CharChunk)this.clone();
+	} catch( Exception ex) {
+	    return null;
+	}
+    }
+
+    public boolean isNull() {
+	if( end > 0 ) return false;
+	return !isSet; //XXX 
+    }
+    
+    /**
+     * Resets the message bytes to an uninitialized state.
+     */
+    public void recycle() {
+	//	buff=null;
+	isSet=false; // XXX
+	start=0;
+	end=0;
+    }
+
+    public void reset() {
+	buff=null;
+    }
+
+    // -------------------- Setup --------------------
+
+    public void allocate( int initial, int limit  ) {
+	isOutput=true;
+	if( buff==null || buff.length < initial ) {
+	    buff=new char[initial];
+	}
+	this.limit=limit;
+	start=0;
+	end=0;
+	isOutput=true;
+	isSet=true;
+    }
+
+
+    public void setOptimizedWrite(boolean optimizedWrite) {
+        this.optimizedWrite = optimizedWrite;
+    }
+
+    public void setChars( char[] c, int off, int len ) {
+        buff=c;
+        start=off;
+        end=start + len;
+        isSet=true;
+    }
+
+    /** Maximum amount of data in this buffer.
+     *
+     *  If -1 or not set, the buffer will grow undefinitely.
+     *  Can be smaller than the current buffer size ( which will not shrink ).
+     *  When the limit is reached, the buffer will be flushed ( if out is set )
+     *  or throw exception.
+     */
+    public void setLimit(int limit) {
+	this.limit=limit;
+    }
+    
+    public int getLimit() {
+	return limit;
+    }
+
+    /**
+     * When the buffer is empty, read the data from the input channel.
+     */
+    public void setCharInputChannel(CharInputChannel in) {
+        this.in = in;
+    }
+
+    /** When the buffer is full, write the data to the output channel.
+     * 	Also used when large amount of data is appended.
+     *
+     *  If not set, the buffer will grow to the limit.
+     */
+    public void setCharOutputChannel(CharOutputChannel out) {
+	this.out=out;
+    }
+
+    // compat 
+    public char[] getChars()
+    {
+	return getBuffer();
+    }
+    
+    public char[] getBuffer()
+    {
+	return buff;
+    }
+    
+    /**
+     * Returns the start offset of the bytes.
+     * For output this is the end of the buffer.
+     */
+    public int getStart() {
+	return start;
+    }
+    
+    public int getOffset() {
+	return start;
+    }
+
+    /**
+     * Returns the start offset of the bytes.
+     */
+    public void setOffset(int off) {
+	start=off;
+    }
+
+    /**
+     * Returns the length of the bytes.
+     */
+    public int getLength() {
+	return end-start;
+    }
+
+
+    public int getEnd() {
+	return end;
+    }
+
+    public void setEnd( int i ) {
+	end=i;
+    }
+
+    // -------------------- Adding data --------------------
+    
+    public void append( char b )
+	throws IOException
+    {
+	makeSpace( 1 );
+
+	// couldn't make space
+	if( limit >0 && end >= limit ) {
+	    flushBuffer();
+	}
+	buff[end++]=b;
+    }
+    
+    public void append( CharChunk src )
+	throws IOException
+    {
+	append( src.getBuffer(), src.getOffset(), src.getLength());
+    }
+
+    /** Add data to the buffer
+     */
+    public void append( char src[], int off, int len )
+	throws IOException
+    {
+	// will grow, up to limit
+	makeSpace( len );
+
+	// if we don't have limit: makeSpace can grow as it wants
+	if( limit < 0 ) {
+	    // assert: makeSpace made enough space
+	    System.arraycopy( src, off, buff, end, len );
+	    end+=len;
+	    return;
+	}
+
+        // Optimize on a common case.
+        // If the source is going to fill up all the space in buffer, may
+        // as well write it directly to the output, and avoid an extra copy
+        if ( optimizedWrite && len == limit && end == start && out != null ) {
+            out.realWriteChars( src, off, len );
+            return;
+        }
+	
+	// if we have limit and we're below
+	if( len <= limit - end ) {
+	    // makeSpace will grow the buffer to the limit,
+	    // so we have space
+	    System.arraycopy( src, off, buff, end, len );
+            
+	    end+=len;
+	    return;
+	}
+
+	// need more space than we can afford, need to flush
+	// buffer
+
+	// the buffer is already at ( or bigger than ) limit
+	
+	// Optimization:
+	// If len-avail < length ( i.e. after we fill the buffer with
+	// what we can, the remaining will fit in the buffer ) we'll just
+	// copy the first part, flush, then copy the second part - 1 write
+	// and still have some space for more. We'll still have 2 writes, but
+	// we write more on the first.
+
+	if( len + end < 2 * limit ) {
+	    /* If the request length exceeds the size of the output buffer,
+	       flush the output buffer and then write the data directly.
+	       We can't avoid 2 writes, but we can write more on the second
+	    */
+	    int avail=limit-end;
+	    System.arraycopy(src, off, buff, end, avail);
+	    end += avail;
+	    
+	    flushBuffer();
+	    
+	    System.arraycopy(src, off+avail, buff, end, len - avail);
+	    end+= len - avail;
+	    
+	} else {	// len > buf.length + avail
+	    // long write - flush the buffer and write the rest
+	    // directly from source
+	    flushBuffer();
+	    
+	    out.realWriteChars( src, off, len );
+	}
+    }
+
+
+    /** Add data to the buffer
+     */
+    public void append( StringBuffer sb )
+	throws IOException
+    {
+	int len=sb.length();
+
+	// will grow, up to limit
+	makeSpace( len );
+
+	// if we don't have limit: makeSpace can grow as it wants
+	if( limit < 0 ) {
+	    // assert: makeSpace made enough space
+	    sb.getChars(0, len, buff, end );
+	    end+=len;
+	    return;
+	}
+
+	int off=0;
+	int sbOff = off;
+	int sbEnd = off + len;
+	while (sbOff < sbEnd) {
+	    int d = min(limit - end, sbEnd - sbOff);
+	    sb.getChars( sbOff, sbOff+d, buff, end);
+	    sbOff += d;
+	    end += d;
+	    if (end >= limit)
+		flushBuffer();
+	}
+    }
+
+    /** Append a string to the buffer
+     */
+    public void append(String s) throws IOException {
+        append(s, 0, s.length());
+    }
+    
+    /** Append a string to the buffer
+     */
+    public void append(String s, int off, int len) throws IOException {
+	if (s==null) return;
+	
+	// will grow, up to limit
+	makeSpace( len );
+
+	// if we don't have limit: makeSpace can grow as it wants
+	if( limit < 0 ) {
+	    // assert: makeSpace made enough space
+	    s.getChars(off, off+len, buff, end );
+	    end+=len;
+	    return;
+	}
+
+	int sOff = off;
+	int sEnd = off + len;
+	while (sOff < sEnd) {
+	    int d = min(limit - end, sEnd - sOff);
+	    s.getChars( sOff, sOff+d, buff, end);
+	    sOff += d;
+	    end += d;
+	    if (end >= limit)
+		flushBuffer();
+	}
+    }
+    
+    // -------------------- Removing data from the buffer --------------------
+
+    public int substract()
+        throws IOException {
+
+        if ((end - start) == 0) {
+            if (in == null)
+                return -1;
+            int n = in.realReadChars(buff, end, buff.length - end);
+            if (n < 0)
+                return -1;
+        }
+
+        return (buff[start++]);
+
+    }
+
+    public int substract(CharChunk src)
+        throws IOException {
+
+        if ((end - start) == 0) {
+            if (in == null)
+                return -1;
+            int n = in.realReadChars( buff, end, buff.length - end);
+            if (n < 0)
+                return -1;
+        }
+
+        int len = getLength();
+        src.append(buff, start, len);
+        start = end;
+        return len;
+
+    }
+
+    public int substract( char src[], int off, int len )
+        throws IOException {
+
+        if ((end - start) == 0) {
+            if (in == null)
+                return -1;
+            int n = in.realReadChars( buff, end, buff.length - end);
+            if (n < 0)
+                return -1;
+        }
+
+        int n = len;
+        if (len > getLength()) {
+            n = getLength();
+        }
+        System.arraycopy(buff, start, src, off, n);
+        start += n;
+        return n;
+
+    }
+
+
+    public void flushBuffer()
+	throws IOException
+    {
+	//assert out!=null
+	if( out==null ) {
+	    throw new IOException( "Buffer overflow, no sink " + limit + " " +
+				   buff.length  );
+	}
+	out.realWriteChars( buff, start, end - start );
+	end=start;
+    }
+
+    /** Make space for len chars. If len is small, allocate
+     *	a reserve space too. Never grow bigger than limit.
+     */
+    private void makeSpace(int count)
+    {
+	char[] tmp = null;
+
+	int newSize;
+	int desiredSize=end + count;
+
+	// Can't grow above the limit
+	if( limit > 0 &&
+	    desiredSize > limit) {
+	    desiredSize=limit;
+	}
+
+	if( buff==null ) {
+	    if( desiredSize < 256 ) desiredSize=256; // take a minimum
+	    buff=new char[desiredSize];
+	}
+
+	// limit < buf.length ( the buffer is already big )
+	// or we already have space XXX
+	if( desiredSize <= buff.length) {
+	    return;
+	}
+	// grow in larger chunks
+	if( desiredSize < 2 * buff.length ) {
+	    newSize= buff.length * 2;
+	    if( limit >0 &&
+		newSize > limit ) newSize=limit;
+	    tmp=new char[newSize];
+	} else {
+	    newSize= buff.length * 2 + count ;
+	    if( limit > 0 &&
+		newSize > limit ) newSize=limit;
+	    tmp=new char[newSize];
+	}
+	
+	System.arraycopy(buff, start, tmp, start, end-start);
+	buff = tmp;
+	tmp = null;
+    }
+    
+    // -------------------- Conversion and getters --------------------
+
+    public String toString() {
+        if (null == buff) {
+            return null;
+        } else if (end-start == 0) {
+            return "";
+        }
+        return StringCache.toString(this);
+    }
+    
+    public String toStringInternal() {
+        return new String(buff, start, end-start);
+    }
+
+    public int getInt()
+    {
+	return Ascii.parseInt(buff, start,
+				end-start);
+    }
+    
+    // -------------------- equals --------------------
+
+    /**
+     * Compares the message bytes to the specified String object.
+     * @param s the String to compare
+     * @return true if the comparison succeeded, false otherwise
+     */
+    public boolean equals(String s) {
+	char[] c = buff;
+	int len = end-start;
+	if (c == null || len != s.length()) {
+	    return false;
+	}
+	int off = start;
+	for (int i = 0; i < len; i++) {
+	    if (c[off++] != s.charAt(i)) {
+		return false;
+	    }
+	}
+	return true;
+    }
+
+    /**
+     * Compares the message bytes to the specified String object.
+     * @param s the String to compare
+     * @return true if the comparison succeeded, false otherwise
+     */
+    public boolean equalsIgnoreCase(String s) {
+	char[] c = buff;
+	int len = end-start;
+	if (c == null || len != s.length()) {
+	    return false;
+	}
+	int off = start;
+	for (int i = 0; i < len; i++) {
+	    if (Ascii.toLower( c[off++] ) != Ascii.toLower( s.charAt(i))) {
+		return false;
+	    }
+	}
+	return true;
+    }
+
+    public boolean equals(CharChunk cc) {
+	return equals( cc.getChars(), cc.getOffset(), cc.getLength());
+    }
+
+    public boolean equals(char b2[], int off2, int len2) {
+	char b1[]=buff;
+	if( b1==null && b2==null ) return true;
+	
+	if (b1== null || b2==null || end-start != len2) {
+	    return false;
+	}
+	int off1 = start;
+	int len=end-start;
+	while ( len-- > 0) {
+	    if (b1[off1++] != b2[off2++]) {
+		return false;
+	    }
+	}
+	return true;
+    }
+
+    public boolean equals(byte b2[], int off2, int len2) {
+	char b1[]=buff;
+	if( b2==null && b1==null ) return true;
+
+	if (b1== null || b2==null || end-start != len2) {
+	    return false;
+	}
+	int off1 = start;
+	int len=end-start;
+	
+	while ( len-- > 0) {
+	    if ( b1[off1++] != (char)b2[off2++]) {
+		return false;
+	    }
+	}
+	return true;
+    }
+    
+    /**
+     * Returns true if the message bytes starts with the specified string.
+     * @param s the string
+     */
+    public boolean startsWith(String s) {
+	char[] c = buff;
+	int len = s.length();
+	if (c == null || len > end-start) {
+	    return false;
+	}
+	int off = start;
+	for (int i = 0; i < len; i++) {
+	    if (c[off++] != s.charAt(i)) {
+		return false;
+	    }
+	}
+	return true;
+    }
+    
+    /**
+     * Returns true if the message bytes starts with the specified string.
+     * @param s the string
+     */
+    public boolean startsWithIgnoreCase(String s, int pos) {
+	char[] c = buff;
+	int len = s.length();
+	if (c == null || len+pos > end-start) {
+	    return false;
+	}
+	int off = start+pos;
+	for (int i = 0; i < len; i++) {
+	    if (Ascii.toLower( c[off++] ) != Ascii.toLower( s.charAt(i))) {
+		return false;
+	    }
+	}
+	return true;
+    }
+    
+
+    // -------------------- Hash code  --------------------
+
+    // normal hash. 
+    public int hash() {
+	int code=0;
+	for (int i = start; i < start + end-start; i++) {
+	    code = code * 37 + buff[i];
+	}
+	return code;
+    }
+
+    // hash ignoring case
+    public int hashIgnoreCase() {
+	int code=0;
+	for (int i = start; i < end; i++) {
+	    code = code * 37 + Ascii.toLower(buff[i]);
+	}
+	return code;
+    }
+
+    public int indexOf(char c) {
+	return indexOf( c, start);
+    }
+    
+    /**
+     * Returns true if the message bytes starts with the specified string.
+     * @param c the character
+     */
+    public int indexOf(char c, int starting) {
+	int ret = indexOf( buff, start+starting, end, c );
+	return (ret >= start) ? ret - start : -1;
+    }
+
+    public static int indexOf( char chars[], int off, int cend, char qq )
+    {
+	while( off < cend ) {
+	    char b=chars[off];
+	    if( b==qq )
+		return off;
+	    off++;
+	}
+	return -1;
+    }
+    
+
+    public int indexOf( String src, int srcOff, int srcLen, int myOff ) {
+	char first=src.charAt( srcOff );
+
+	// Look for first char 
+	int srcEnd = srcOff + srcLen;
+        
+	for( int i=myOff+start; i <= (end - srcLen); i++ ) {
+	    if( buff[i] != first ) continue;
+	    // found first char, now look for a match
+            int myPos=i+1;
+	    for( int srcPos=srcOff + 1; srcPos< srcEnd; ) {
+                if( buff[myPos++] != src.charAt( srcPos++ ))
+		    break;
+                if( srcPos==srcEnd ) return i-start; // found it
+	    }
+	}
+	return -1;
+    }
+
+    // -------------------- utils
+    private int min(int a, int b) {
+	if (a < b) return a;
+	return b;
+    }
+
+    // Char sequence impl
+    
+    public char charAt(int index) {
+        return buff[index + start];
+    }
+    
+    public CharSequence subSequence(int start, int end) {
+        try {
+            CharChunk result = (CharChunk) this.clone();
+            result.setOffset(this.start + start);
+            result.setEnd(this.start + end);
+            return result;
+        } catch (CloneNotSupportedException e) {
+            // Cannot happen
+            return null;
+        }
+    }
+    
+    public int length() {
+        return end - start;
+    }
+    
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/buf/DateTool.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/buf/DateTool.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/buf/DateTool.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,164 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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 java.text.DateFormat;
+import java.text.FieldPosition;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Locale;
+import java.util.TimeZone;
+
+import org.apache.tomcat.util.res.StringManager;
+
+/**
+ *  Common place for date utils.
+ *
+ * @deprecated Will be replaced with a more efficient impl, based on
+ * FastDateFormat, with an API using less objects.
+ * @author dac at eng.sun.com
+ * @author Jason Hunter [jch at eng.sun.com]
+ * @author James Todd [gonzo at eng.sun.com]
+ * @author Costin Manolache
+ */
+public class DateTool {
+
+    /** US locale - all HTTP dates are in english
+     */
+    private final static Locale LOCALE_US = Locale.US;
+
+    /** GMT timezone - all HTTP dates are on GMT
+     */
+    public final static TimeZone GMT_ZONE = TimeZone.getTimeZone("GMT");
+
+    /** format for RFC 1123 date string -- "Sun, 06 Nov 1994 08:49:37 GMT"
+     */
+    public final static String RFC1123_PATTERN =
+        "EEE, dd MMM yyyy HH:mm:ss z";
+
+    // format for RFC 1036 date string -- "Sunday, 06-Nov-94 08:49:37 GMT"
+    public final static String rfc1036Pattern =
+        "EEEEEEEEE, dd-MMM-yy HH:mm:ss z";
+
+    // format for C asctime() date string -- "Sun Nov  6 08:49:37 1994"
+    public final static String asctimePattern =
+        "EEE MMM d HH:mm:ss yyyy";
+
+    /** Pattern used for old cookies
+     */
+    private final static String OLD_COOKIE_PATTERN = "EEE, dd-MMM-yyyy HH:mm:ss z";
+
+    /** DateFormat to be used to format dates. Called from MessageBytes
+     */
+    private final static DateFormat rfc1123Format =
+	new SimpleDateFormat(RFC1123_PATTERN, LOCALE_US);
+    
+    /** DateFormat to be used to format old netscape cookies
+	Called from ServerCookie
+     */
+    private final static DateFormat oldCookieFormat =
+	new SimpleDateFormat(OLD_COOKIE_PATTERN, LOCALE_US);
+    
+    private final static DateFormat rfc1036Format =
+	new SimpleDateFormat(rfc1036Pattern, LOCALE_US);
+    
+    private final static DateFormat asctimeFormat =
+	new SimpleDateFormat(asctimePattern, LOCALE_US);
+    
+    static {
+	rfc1123Format.setTimeZone(GMT_ZONE);
+	oldCookieFormat.setTimeZone(GMT_ZONE);
+	rfc1036Format.setTimeZone(GMT_ZONE);
+	asctimeFormat.setTimeZone(GMT_ZONE);
+    }
+ 
+    private static String rfc1123DS;
+    private static long   rfc1123Sec;
+
+    private static StringManager sm =
+        StringManager.getManager("org.apache.tomcat.util.buf.res");
+
+    // Called from MessageBytes.getTime()
+    static long parseDate( MessageBytes value ) {
+     	return parseDate( value.toString());
+    }
+
+    // Called from MessageBytes.setTime
+    /** 
+     */
+    public static String format1123( Date d ) {
+	String dstr=null;
+	synchronized(rfc1123Format) {
+	    dstr = format1123(d, rfc1123Format);
+	}
+	return dstr;
+    } 
+
+    public static String format1123( Date d,DateFormat df ) {
+        long dt = d.getTime() / 1000;
+        if ((rfc1123DS != null) && (dt == rfc1123Sec))
+            return rfc1123DS;
+        rfc1123DS  = df.format( d );
+        rfc1123Sec = dt;
+        return rfc1123DS;
+    } 
+
+
+    // Called from ServerCookie
+    /** 
+     */
+    public static void formatOldCookie( Date d, StringBuffer sb,
+					  FieldPosition fp )
+    {
+	synchronized(oldCookieFormat) {
+	    oldCookieFormat.format( d, sb, fp );
+	}
+    }
+
+    // Called from ServerCookie
+    public static String formatOldCookie( Date d )
+    {
+	String ocf=null;
+	synchronized(oldCookieFormat) {
+	    ocf= oldCookieFormat.format( d );
+	}
+	return ocf;
+    }
+
+    
+    /** Called from HttpServletRequest.getDateHeader().
+	Not efficient - but not very used.
+     */
+    public static long parseDate( String dateString ) {
+	DateFormat [] format = {rfc1123Format,rfc1036Format,asctimeFormat};
+	return parseDate(dateString,format);
+    }
+    public static long parseDate( String dateString, DateFormat []format ) {
+	Date date=null;
+	for(int i=0; i < format.length; i++) {
+	    try {
+		date = format[i].parse(dateString);
+		return date.getTime();
+	    } catch (ParseException e) { }
+	    catch (StringIndexOutOfBoundsException e) { }
+	}
+	String msg = sm.getString("httpDate.pe", dateString);
+	throw new IllegalArgumentException(msg);
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/buf/HexUtils.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/buf/HexUtils.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/buf/HexUtils.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,193 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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 java.io.ByteArrayOutputStream;
+import org.apache.tomcat.util.res.StringManager;
+
+/**
+ * Library of utility methods useful in dealing with converting byte arrays
+ * to and from strings of hexadecimal digits.
+ * Code from Ajp11, from Apache's JServ.
+ *
+ * @author Craig R. McClanahan
+ */
+
+public final class HexUtils {
+
+
+    // -------------------------------------------------------------- Constants
+
+
+    /**
+     *  Table for HEX to DEC byte translation.
+     */
+    public 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,
+    };
+
+
+    /**
+     * Table for DEC to HEX byte translation.
+     */
+    public static final byte[] HEX = 
+    { (byte) '0', (byte) '1', (byte) '2', (byte) '3', (byte) '4', (byte) '5', 
+      (byte) '6', (byte) '7', (byte) '8', (byte) '9', (byte) 'a', (byte) 'b', 
+      (byte) 'c', (byte) 'd', (byte) 'e', (byte) 'f' };
+
+
+    /**
+     * The string manager for this package.
+     */
+    private static StringManager sm =
+	StringManager.getManager("org.apache.tomcat.util.buf.res");
+
+
+    // --------------------------------------------------------- Static Methods
+
+
+    /**
+     * Convert a String of hexadecimal digits into the corresponding
+     * byte array by encoding each two hexadecimal digits as a byte.
+     *
+     * @param digits Hexadecimal digits representation
+     *
+     * @exception IllegalArgumentException if an invalid hexadecimal digit
+     *  is found, or the input string contains an odd number of hexadecimal
+     *  digits
+     */
+    public static byte[] convert(String digits) {
+
+	ByteArrayOutputStream baos = new ByteArrayOutputStream();
+	for (int i = 0; i < digits.length(); i += 2) {
+	    char c1 = digits.charAt(i);
+	    if ((i+1) >= digits.length())
+		throw new IllegalArgumentException
+		    (sm.getString("hexUtil.odd"));
+	    char c2 = digits.charAt(i + 1);
+	    byte b = 0;
+	    if ((c1 >= '0') && (c1 <= '9'))
+		b += ((c1 - '0') * 16);
+	    else if ((c1 >= 'a') && (c1 <= 'f'))
+		b += ((c1 - 'a' + 10) * 16);
+	    else if ((c1 >= 'A') && (c1 <= 'F'))
+		b += ((c1 - 'A' + 10) * 16);
+	    else
+		throw new IllegalArgumentException
+		    (sm.getString("hexUtil.bad"));
+	    if ((c2 >= '0') && (c2 <= '9'))
+		b += (c2 - '0');
+	    else if ((c2 >= 'a') && (c2 <= 'f'))
+		b += (c2 - 'a' + 10);
+	    else if ((c2 >= 'A') && (c2 <= 'F'))
+		b += (c2 - 'A' + 10);
+	    else
+		throw new IllegalArgumentException
+		    (sm.getString("hexUtil.bad"));
+	    baos.write(b);
+	}
+	return (baos.toByteArray());
+
+    }
+
+
+    /**
+     * Convert a byte array into a printable format containing a
+     * String of hexadecimal digit characters (two per byte).
+     *
+     * @param bytes Byte array representation
+     */
+    public static String convert(byte bytes[]) {
+
+	StringBuffer sb = new StringBuffer(bytes.length * 2);
+	for (int i = 0; i < bytes.length; i++) {
+	    sb.append(convertDigit((int) (bytes[i] >> 4)));
+	    sb.append(convertDigit((int) (bytes[i] & 0x0f)));
+	}
+	return (sb.toString());
+
+    }
+
+    /**
+     * Convert 4 hex digits to an int, and return the number of converted
+     * bytes.
+     *
+     * @param hex Byte array containing exactly four hexadecimal digits
+     *
+     * @exception IllegalArgumentException if an invalid hexadecimal digit
+     *  is included
+     */
+    public static int convert2Int( byte[] hex ) {
+	// Code from Ajp11, from Apache's JServ
+    
+	// assert b.length==4
+	// assert valid data
+	int len;
+	if(hex.length < 4 ) return 0;
+	if( DEC[hex[0]]<0 )
+	    throw new IllegalArgumentException(sm.getString("hexUtil.bad"));
+	len = DEC[hex[0]];
+	len = len << 4;
+	if( DEC[hex[1]]<0 )
+	    throw new IllegalArgumentException(sm.getString("hexUtil.bad"));
+	len += DEC[hex[1]];
+	len = len << 4;
+	if( DEC[hex[2]]<0 )
+	    throw new IllegalArgumentException(sm.getString("hexUtil.bad"));
+	len += DEC[hex[2]];
+	len = len << 4;
+	if( DEC[hex[3]]<0 )
+	    throw new IllegalArgumentException(sm.getString("hexUtil.bad"));
+	len += DEC[hex[3]];
+	return len;
+    }
+
+
+
+    /**
+     * [Private] Convert the specified value (0 .. 15) to the corresponding
+     * hexadecimal digit.
+     *
+     * @param value Value to be converted
+     */
+    private static char convertDigit(int value) {
+
+	value &= 0x0f;
+	if (value >= 10)
+	    return ((char) (value - 10 + 'a'));
+	else
+	    return ((char) (value + '0'));
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/buf/MessageBytes.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/buf/MessageBytes.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/buf/MessageBytes.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,732 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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 java.text.*;
+import java.util.*;
+import java.io.Serializable;
+import java.io.IOException;
+
+/**
+ * This class is used to represent a subarray of bytes in an HTTP message.
+ * It represents all request/response elements. The byte/char conversions are
+ * delayed and cached. Everything is recyclable.
+ *
+ * The object can represent a byte[], a char[], or a (sub) String. All
+ * operations can be made in case sensitive mode or not.
+ *
+ * @author dac at eng.sun.com
+ * @author James Todd [gonzo at eng.sun.com]
+ * @author Costin Manolache
+ */
+public final class MessageBytes implements Cloneable, Serializable {
+    // primary type ( whatever is set as original value )
+    private int type = T_NULL;
+
+    public static final int T_NULL = 0;
+    /** getType() is T_STR if the the object used to create the MessageBytes
+        was a String */
+    public static final int T_STR  = 1;
+    /** getType() is T_STR if the the object used to create the MessageBytes
+        was a byte[] */ 
+    public static final int T_BYTES = 2;
+    /** getType() is T_STR if the the object used to create the MessageBytes
+        was a char[] */ 
+    public static final int T_CHARS = 3;
+
+    private int hashCode=0;
+    // did we computed the hashcode ? 
+    private boolean hasHashCode=false;
+
+    // Is the represented object case sensitive ?
+    private boolean caseSensitive=true;
+
+    // Internal objects to represent array + offset, and specific methods
+    private ByteChunk byteC=new ByteChunk();
+    private CharChunk charC=new CharChunk();
+    
+    // String
+    private String strValue;
+    // true if a String value was computed. Probably not needed,
+    // strValue!=null is the same
+    private boolean hasStrValue=false;
+
+    /**
+     * Creates a new, uninitialized MessageBytes object.
+     * @deprecated Use static newInstance() in order to allow
+     *   future hooks.
+     */
+    public MessageBytes() {
+    }
+
+    /** Construct a new MessageBytes instance
+     */
+    public static MessageBytes newInstance() {
+	return factory.newInstance();
+    }
+
+    /** Configure the case sensitivity
+     */
+    public void setCaseSenitive( boolean b ) {
+	caseSensitive=b;
+    }
+
+    public MessageBytes getClone() {
+	try {
+	    return (MessageBytes)this.clone();
+	} catch( Exception ex) {
+	    return null;
+	}
+    }
+
+    public boolean isNull() {
+//		should we check also hasStrValue ???
+		return byteC.isNull() && charC.isNull() && ! hasStrValue;
+	// bytes==null && strValue==null;
+    }
+    
+    /**
+     * Resets the message bytes to an uninitialized (NULL) state.
+     */
+    public void recycle() {
+	type=T_NULL;
+	byteC.recycle();
+	charC.recycle();
+
+	strValue=null;
+	caseSensitive=true;
+
+	hasStrValue=false;
+	hasHashCode=false;
+	hasIntValue=false;
+    hasLongValue=false;
+	hasDateValue=false;	
+    }
+
+
+    /**
+     * Sets the content to the specified subarray of bytes.
+     *
+     * @param b the bytes
+     * @param off the start offset of the bytes
+     * @param len the length of the bytes
+     */
+    public void setBytes(byte[] b, int off, int len) {
+        byteC.setBytes( b, off, len );
+        type=T_BYTES;
+        hasStrValue=false;
+        hasHashCode=false;
+        hasIntValue=false;
+        hasLongValue=false;
+        hasDateValue=false; 
+    }
+
+    /** Set the encoding. If the object was constructed from bytes[]. any
+     *  previous conversion is reset.
+     *  If no encoding is set, we'll use 8859-1.
+     */
+    public void setEncoding( String enc ) {
+	if( !byteC.isNull() ) {
+	    // if the encoding changes we need to reset the converion results
+	    charC.recycle();
+	    hasStrValue=false;
+	}
+	byteC.setEncoding(enc);
+    }
+
+    /** 
+     * Sets the content to be a char[]
+     *
+     * @param c the bytes
+     * @param off the start offset of the bytes
+     * @param len the length of the bytes
+     */
+    public void setChars( char[] c, int off, int len ) {
+        charC.setChars( c, off, len );
+        type=T_CHARS;
+        hasStrValue=false;
+        hasHashCode=false;
+        hasIntValue=false;
+        hasLongValue=false;
+        hasDateValue=false; 
+    }
+
+    /** Remove the cached string value. Use it after a conversion on the
+     *	byte[] or after the encoding is changed
+     *  XXX Is this needed ?
+     */
+    public void resetStringValue() {
+	if( type != T_STR ) {
+	    // If this was cread as a byte[] or char[], we remove
+	    // the old string value
+	    hasStrValue=false;
+	    strValue=null;
+	}
+    }
+
+    /** 
+     * Set the content to be a string
+     */
+    public void setString( String s ) {
+        if (s == null)
+            return;
+        strValue=s;
+        hasStrValue=true;
+        hasHashCode=false;
+        hasIntValue=false;
+        hasLongValue=false;
+        hasDateValue=false; 
+        type=T_STR;
+    }
+
+    // -------------------- Conversion and getters --------------------
+
+    /** Compute the string value
+     */
+    public String toString() {
+        if( hasStrValue ) return strValue;
+        
+        switch (type) {
+        case T_CHARS:
+            strValue=charC.toString();
+            hasStrValue=true;
+            return strValue;
+        case T_BYTES:
+            strValue=byteC.toString();
+            hasStrValue=true;
+            return strValue;
+        }
+        return null;
+    }
+
+    //----------------------------------------
+    /** Return the type of the original content. Can be
+     *  T_STR, T_BYTES, T_CHARS or T_NULL
+     */
+    public int getType() {
+	return type;
+    }
+    
+    /**
+     * Returns the byte chunk, representing the byte[] and offset/length.
+     * Valid only if T_BYTES or after a conversion was made.
+     */
+    public ByteChunk getByteChunk() {
+	return byteC;
+    }
+
+    /**
+     * Returns the char chunk, representing the char[] and offset/length.
+     * Valid only if T_CHARS or after a conversion was made.
+     */
+    public CharChunk getCharChunk() {
+	return charC;
+    }
+
+    /**
+     * Returns the string value.
+     * Valid only if T_STR or after a conversion was made.
+     */
+    public String getString() {
+	return strValue;
+    }
+
+    /** Unimplemented yet. Do a char->byte conversion.
+     */
+    public void toBytes() {
+        if( ! byteC.isNull() ) {
+            type=T_BYTES;
+            return;
+        }
+        toString();
+        type=T_BYTES;
+        byte bb[] = strValue.getBytes();
+        byteC.setBytes(bb, 0, bb.length);
+    }
+
+    /** Convert to char[] and fill the CharChunk.
+     *  XXX Not optimized - it converts to String first.
+     */
+    public void toChars() {
+	if( ! charC.isNull() ) {
+            type=T_CHARS;
+	    return;
+	}
+	// inefficient
+	toString();
+        type=T_CHARS;
+	char cc[]=strValue.toCharArray();
+	charC.setChars(cc, 0, cc.length);
+    }
+    
+
+    /**
+     * Returns the length of the original buffer.
+     * Note that the length in bytes may be different from the length
+     * in chars.
+     */
+    public int getLength() {
+	if(type==T_BYTES)
+	    return byteC.getLength();
+	if(type==T_CHARS) {
+	    return charC.getLength();
+	}
+	if(type==T_STR)
+	    return strValue.length();
+	toString();
+	if( strValue==null ) return 0;
+	return strValue.length();
+    }
+
+    // -------------------- equals --------------------
+
+    /**
+     * Compares the message bytes to the specified String object.
+     * @param s the String to compare
+     * @return true if the comparison succeeded, false otherwise
+     */
+    public boolean equals(String s) {
+	if( ! caseSensitive )
+	    return equalsIgnoreCase( s );
+	switch (type) {
+	case T_STR:
+	    if( strValue==null && s!=null) return false;
+	    return strValue.equals( s );
+	case T_CHARS:
+	    return charC.equals( s );
+	case T_BYTES:
+	    return byteC.equals( s );
+	default:
+	    return false;
+	}
+    }
+
+    /**
+     * Compares the message bytes to the specified String object.
+     * @param s the String to compare
+     * @return true if the comparison succeeded, false otherwise
+     */
+    public boolean equalsIgnoreCase(String s) {
+	switch (type) {
+	case T_STR:
+	    if( strValue==null && s!=null) return false;
+	    return strValue.equalsIgnoreCase( s );
+	case T_CHARS:
+	    return charC.equalsIgnoreCase( s );
+	case T_BYTES:
+	    return byteC.equalsIgnoreCase( s );
+	default:
+	    return false;
+	}
+    }
+
+    public boolean equals(MessageBytes mb) {
+	switch (type) {
+	case T_STR:
+	    return mb.equals( strValue );
+	}
+
+	if( mb.type != T_CHARS &&
+	    mb.type!= T_BYTES ) {
+	    // it's a string or int/date string value
+	    return equals( mb.toString() );
+	}
+
+	// mb is either CHARS or BYTES.
+	// this is either CHARS or BYTES
+	// Deal with the 4 cases ( in fact 3, one is simetric)
+	
+	if( mb.type == T_CHARS && type==T_CHARS ) {
+	    return charC.equals( mb.charC );
+	} 
+	if( mb.type==T_BYTES && type== T_BYTES ) {
+	    return byteC.equals( mb.byteC );
+	}
+	if( mb.type== T_CHARS && type== T_BYTES ) {
+	    return byteC.equals( mb.charC );
+	}
+	if( mb.type== T_BYTES && type== T_CHARS ) {
+	    return mb.byteC.equals( charC );
+	}
+	// can't happen
+	return true;
+    }
+
+    
+    /**
+     * Returns true if the message bytes starts with the specified string.
+     * @param s the string
+     */
+    public boolean startsWith(String s) {
+	switch (type) {
+	case T_STR:
+	    return strValue.startsWith( s );
+	case T_CHARS:
+	    return charC.startsWith( s );
+	case T_BYTES:
+	    return byteC.startsWith( s );
+	default:
+	    return false;
+	}
+    }
+
+    /**
+     * Returns true if the message bytes starts with the specified string.
+     * @param s the string
+     * @param pos The start position
+     */
+    public boolean startsWithIgnoreCase(String s, int pos) {
+	switch (type) {
+	case T_STR:
+	    if( strValue==null ) return false;
+	    if( strValue.length() < pos + s.length() ) return false;
+	    
+	    for( int i=0; i<s.length(); i++ ) {
+		if( Ascii.toLower( s.charAt( i ) ) !=
+		    Ascii.toLower( strValue.charAt( pos + i ))) {
+		    return false;
+		}
+	    }
+	    return true;
+	case T_CHARS:
+	    return charC.startsWithIgnoreCase( s, pos );
+	case T_BYTES:
+	    return byteC.startsWithIgnoreCase( s, pos );
+	default:
+	    return false;
+	}
+    }
+
+    
+
+    // -------------------- Hash code  --------------------
+    public  int hashCode() {
+	if( hasHashCode ) return hashCode;
+	int code = 0;
+
+	if( caseSensitive ) 
+	    code=hash(); 
+	else
+	    code=hashIgnoreCase();
+	hashCode=code;
+	hasHashCode=true;
+	return code;
+    }
+
+    // normal hash. 
+    private int hash() {
+	int code=0;
+	switch (type) {
+	case T_STR:
+	    // We need to use the same hash function
+	    for (int i = 0; i < strValue.length(); i++) {
+		code = code * 37 + strValue.charAt( i );
+	    }
+	    return code;
+	case T_CHARS:
+	    return charC.hash();
+	case T_BYTES:
+	    return byteC.hash();
+	default:
+	    return 0;
+	}
+    }
+
+    // hash ignoring case
+    private int hashIgnoreCase() {
+	int code=0;
+	switch (type) {
+	case T_STR:
+	    for (int i = 0; i < strValue.length(); i++) {
+		code = code * 37 + Ascii.toLower(strValue.charAt( i ));
+	    }
+	    return code;
+	case T_CHARS:
+	    return charC.hashIgnoreCase();
+	case T_BYTES:
+	    return byteC.hashIgnoreCase();
+	default:
+	    return 0;
+	}
+    }
+
+    public int indexOf(char c) {
+	return indexOf( c, 0);
+    }
+
+    // Inefficient initial implementation. Will be replaced on the next
+    // round of tune-up
+    public int indexOf(String s, int starting) {
+	toString();
+	return strValue.indexOf( s, starting );
+    }
+    
+    // Inefficient initial implementation. Will be replaced on the next
+    // round of tune-up
+    public int indexOf(String s) {
+	return indexOf( s, 0 );
+    }
+    
+    public int indexOfIgnoreCase(String s, int starting) {
+	toString();
+	String upper=strValue.toUpperCase();
+	String sU=s.toUpperCase();
+	return upper.indexOf( sU, starting );
+    }
+    
+    /**
+     * Returns true if the message bytes starts with the specified string.
+     * @param c the character
+     * @param starting The start position
+     */
+    public int indexOf(char c, int starting) {
+	switch (type) {
+	case T_STR:
+	    return strValue.indexOf( c, starting );
+	case T_CHARS:
+	    return charC.indexOf( c, starting);
+	case T_BYTES:
+	    return byteC.indexOf( c, starting );
+	default:
+	    return -1;
+	}
+    }
+
+    /** Copy the src into this MessageBytes, allocating more space if
+     *  needed
+     */
+    public void duplicate( MessageBytes src ) throws IOException
+    {
+	switch( src.getType() ) {
+	case MessageBytes.T_BYTES:
+	    type=T_BYTES;
+	    ByteChunk bc=src.getByteChunk();
+	    byteC.allocate( 2 * bc.getLength(), -1 );
+	    byteC.append( bc );
+	    break;
+	case MessageBytes.T_CHARS:
+	    type=T_CHARS;
+	    CharChunk cc=src.getCharChunk();
+	    charC.allocate( 2 * cc.getLength(), -1 );
+	    charC.append( cc );
+	    break;
+	case MessageBytes.T_STR:
+	    type=T_STR;
+	    String sc=src.getString();
+	    this.setString( sc );
+	    break;
+	}
+    }
+
+    // -------------------- Deprecated code --------------------
+    // efficient int, long and date
+    // XXX used only for headers - shouldn't be
+    // stored here.
+    private int intValue;
+    private boolean hasIntValue=false;
+    private long longValue;
+    private boolean hasLongValue=false;
+    private Date dateValue;
+    private boolean hasDateValue=false;
+    
+    /**
+     *  @deprecated The buffer are general purpose, caching for headers should
+     *  be done in headers. The second parameter allows us to pass a date format
+     * instance to avoid synchronization problems.
+     */
+    public void setTime(long t, DateFormat df) {
+	// XXX replace it with a byte[] tool
+	recycle();
+	if( dateValue==null)
+	    dateValue=new Date(t);
+	else
+	    dateValue.setTime(t);
+	if( df==null )
+	    strValue=DateTool.format1123(dateValue);
+	else
+	    strValue=DateTool.format1123(dateValue,df);
+	hasStrValue=true;
+	hasDateValue=true;
+	type=T_STR;   
+    }
+
+    public void setTime(long t) {
+	setTime( t, null );
+    }
+
+    /** Set the buffer to the representation of an int
+     */
+    public void setInt(int i) {
+        byteC.allocate(16, 32);
+        int current = i;
+        byte[] buf = byteC.getBuffer();
+        int start = 0;
+        int end = 0;
+        if (i == 0) {
+            buf[end++] = (byte) '0';
+        }
+        if (i < 0) {
+            current = -i;
+            buf[end++] = (byte) '-';
+        }
+        while (current > 0) {
+            int digit = current % 10;
+            current = current / 10;
+            buf[end++] = HexUtils.HEX[digit];
+        }
+        byteC.setOffset(0);
+        byteC.setEnd(end);
+        // Inverting buffer
+        end--;
+        if (i < 0) {
+            start++;
+        }
+        while (end > start) {
+            byte temp = buf[start];
+            buf[start] = buf[end];
+            buf[end] = temp;
+            start++;
+            end--;
+        }
+        intValue=i;
+        hasStrValue=false;
+        hasHashCode=false;
+        hasIntValue=true;
+        hasLongValue=false;
+        hasDateValue=false; 
+        type=T_BYTES;
+    }
+
+    /** Set the buffer to the representation of an long
+     */
+    public void setLong(long l) {
+        byteC.allocate(32, 64);
+        long current = l;
+        byte[] buf = byteC.getBuffer();
+        int start = 0;
+        int end = 0;
+        if (l == 0) {
+            buf[end++] = (byte) '0';
+        }
+        if (l < 0) {
+            current = -l;
+            buf[end++] = (byte) '-';
+        }
+        while (current > 0) {
+            int digit = (int) (current % 10);
+            current = current / 10;
+            buf[end++] = HexUtils.HEX[digit];
+        }
+        byteC.setOffset(0);
+        byteC.setEnd(end);
+        // Inverting buffer
+        end--;
+        if (l < 0) {
+            start++;
+        }
+        while (end > start) {
+            byte temp = buf[start];
+            buf[start] = buf[end];
+            buf[end] = temp;
+            start++;
+            end--;
+        }
+        longValue=l;
+        hasStrValue=false;
+        hasHashCode=false;
+        hasIntValue=false;
+        hasLongValue=true;
+        hasDateValue=false; 
+        type=T_BYTES;
+    }
+
+    /**
+     *  @deprecated The buffer are general purpose, caching for headers should
+     *  be done in headers
+     */
+    public  long getTime()
+    {
+     	if( hasDateValue ) {
+	    if( dateValue==null) return -1;
+	    return dateValue.getTime();
+     	}
+	
+     	long l=DateTool.parseDate( this );
+     	if( dateValue==null)
+     	    dateValue=new Date(l);
+     	else
+     	    dateValue.setTime(l);
+     	hasDateValue=true;
+     	return l;
+    }
+    
+
+    // Used for headers conversion
+    /** Convert the buffer to an int, cache the value
+     */ 
+    public int getInt() 
+    {
+	if( hasIntValue )
+	    return intValue;
+	
+	switch (type) {
+	case T_BYTES:
+	    intValue=byteC.getInt();
+	    break;
+	default:
+	    intValue=Integer.parseInt(toString());
+	}
+	hasIntValue=true;
+	return intValue;
+    }
+
+    // Used for headers conversion
+    /** Convert the buffer to an long, cache the value
+     */ 
+    public long getLong() {
+        if( hasLongValue )
+            return longValue;
+        
+        switch (type) {
+        case T_BYTES:
+            longValue=byteC.getLong();
+            break;
+        default:
+            longValue=Long.parseLong(toString());
+        }
+
+        hasLongValue=true;
+        return longValue;
+
+     }
+
+    // -------------------- Future may be different --------------------
+    
+    private static MessageBytesFactory factory=new MessageBytesFactory();
+
+    public static void setFactory( MessageBytesFactory mbf ) {
+	factory=mbf;
+    }
+    
+    public static class MessageBytesFactory {
+	protected MessageBytesFactory() {
+	}
+	public MessageBytes newInstance() {
+	    return new MessageBytes();
+	}
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/buf/StringCache.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/buf/StringCache.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/buf/StringCache.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,669 @@
+/*
+ *  Copyright 1999-2005 The Apache Software Foundation
+ *
+ *  Licensed 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 java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.TreeMap;
+
+/**
+ * This class implements a String cache for ByteChunk and CharChunk.
+ *
+ * @author Remy Maucherat
+ */
+public class StringCache {
+
+
+    private static org.apache.commons.logging.Log log=
+        org.apache.commons.logging.LogFactory.getLog( StringCache.class );
+    
+    
+    // ------------------------------------------------------- Static Variables
+
+    
+    /**
+     * Enabled ?
+     */
+    protected static boolean byteEnabled = 
+        ("true".equals(System.getProperty("tomcat.util.buf.StringCache.byte.enabled", "false")));
+
+    
+    protected static boolean charEnabled = 
+        ("true".equals(System.getProperty("tomcat.util.buf.StringCache.char.enabled", "false")));
+
+    
+    protected static int trainThreshold = 
+        Integer.parseInt(System.getProperty("tomcat.util.buf.StringCache.trainThreshold", "20000"));
+    
+
+    protected static int cacheSize = 
+        Integer.parseInt(System.getProperty("tomcat.util.buf.StringCache.cacheSize", "200"));
+    
+
+    /**
+     * Statistics hash map for byte chunk.
+     */
+    protected static HashMap bcStats = new HashMap(cacheSize);
+
+    
+    /**
+     * toString count for byte chunk.
+     */
+    protected static int bcCount = 0;
+    
+    
+    /**
+     * Cache for byte chunk.
+     */
+    protected static ByteEntry[] bcCache = null;
+    
+
+    /**
+     * Statistics hash map for char chunk.
+     */
+    protected static HashMap ccStats = new HashMap(cacheSize);
+
+
+    /**
+     * toString count for char chunk.
+     */
+    protected static int ccCount = 0; 
+    
+
+    /**
+     * Cache for char chunk.
+     */
+    protected static CharEntry[] ccCache = null;
+
+    
+    /**
+     * Access count.
+     */
+    protected static int accessCount = 0;
+    
+
+    /**
+     * Hit count.
+     */
+    protected static int hitCount = 0;
+    
+
+    // ------------------------------------------------------------ Properties
+
+    
+    /**
+     * @return Returns the cacheSize.
+     */
+    public int getCacheSize() {
+        return cacheSize;
+    }
+    
+    
+    /**
+     * @param cacheSize The cacheSize to set.
+     */
+    public void setCacheSize(int cacheSize) {
+        StringCache.cacheSize = cacheSize;
+    }
+
+    
+    /**
+     * @return Returns the enabled.
+     */
+    public boolean getByteEnabled() {
+        return byteEnabled;
+    }
+    
+    
+    /**
+     * @param byteEnabled The enabled to set.
+     */
+    public void setByteEnabled(boolean byteEnabled) {
+        StringCache.byteEnabled = byteEnabled;
+    }
+    
+    
+    /**
+     * @return Returns the enabled.
+     */
+    public boolean getCharEnabled() {
+        return charEnabled;
+    }
+    
+    
+    /**
+     * @param charEnabled The enabled to set.
+     */
+    public void setCharEnabled(boolean charEnabled) {
+        StringCache.charEnabled = charEnabled;
+    }
+    
+    
+    /**
+     * @return Returns the trainThreshold.
+     */
+    public int getTrainThreshold() {
+        return trainThreshold;
+    }
+    
+    
+    /**
+     * @param trainThreshold The trainThreshold to set.
+     */
+    public void setTrainThreshold(int trainThreshold) {
+        StringCache.trainThreshold = trainThreshold;
+    }
+
+    
+    /**
+     * @return Returns the accessCount.
+     */
+    public int getAccessCount() {
+        return accessCount;
+    }
+    
+    
+    /**
+     * @return Returns the hitCount.
+     */
+    public int getHitCount() {
+        return hitCount;
+    }
+
+    
+    // -------------------------------------------------- Public Static Methods
+
+    
+    public void reset() {
+        hitCount = 0;
+        accessCount = 0;
+        synchronized (bcStats) {
+            bcCache = null;
+            bcCount = 0;
+        }
+        synchronized (ccStats) {
+            ccCache = null;
+            ccCount = 0;
+        }
+    }
+    
+    
+    public static String toString(ByteChunk bc) {
+
+        // If the cache is null, then either caching is disabled, or we're
+        // still training
+        if (bcCache == null) {
+            String value = bc.toStringInternal();
+            if (byteEnabled) {
+                // If training, everything is synced
+                synchronized (bcStats) {
+                    // If the cache has been generated on a previous invocation
+                    // while waiting fot the lock, just return the toString value
+                    // we just calculated
+                    if (bcCache != null) {
+                        return value;
+                    }
+                    // Two cases: either we just exceeded the train count, in which
+                    // case the cache must be created, or we just update the count for
+                    // the string
+                    if (bcCount > trainThreshold) {
+                        long t1 = System.currentTimeMillis();
+                        // Sort the entries according to occurrence
+                        TreeMap tempMap = new TreeMap();
+                        Iterator entries = bcStats.keySet().iterator();
+                        while (entries.hasNext()) {
+                            ByteEntry entry = (ByteEntry) entries.next();
+                            int[] countA = (int[]) bcStats.get(entry);
+                            Integer count = new Integer(countA[0]);
+                            // Add to the list for that count
+                            ArrayList list = (ArrayList) tempMap.get(count);
+                            if (list == null) {
+                                // Create list
+                                list = new ArrayList();
+                                tempMap.put(count, list);
+                            }
+                            list.add(entry);
+                        }
+                        // Allocate array of the right size
+                        int size = bcStats.size();
+                        if (size > cacheSize) {
+                            size = cacheSize;
+                        }
+                        ByteEntry[] tempbcCache = new ByteEntry[size];
+                        // Fill it up using an alphabetical order
+                        // and a dumb insert sort
+                        ByteChunk tempChunk = new ByteChunk();
+                        int n = 0;
+                        while (n < size) {
+                            Object key = tempMap.lastKey();
+                            ArrayList list = (ArrayList) tempMap.get(key);
+                            ByteEntry[] list2 = 
+                                (ByteEntry[]) list.toArray(new ByteEntry[list.size()]);
+                            for (int i = 0; i < list.size() && n < size; i++) {
+                                ByteEntry entry = (ByteEntry) list.get(i);
+                                tempChunk.setBytes(entry.name, 0, entry.name.length);
+                                int insertPos = findClosest(tempChunk, tempbcCache, n);
+                                if (insertPos == n) {
+                                    tempbcCache[n + 1] = entry;
+                                } else {
+                                    System.arraycopy(tempbcCache, insertPos + 1, tempbcCache, 
+                                            insertPos + 2, n - insertPos - 1);
+                                    tempbcCache[insertPos + 1] = entry;
+                                }
+                                n++;
+                            }
+                            tempMap.remove(key);
+                        }
+                        bcCount = 0;
+                        bcStats.clear();
+                        bcCache = tempbcCache;
+                        if (log.isDebugEnabled()) {
+                            long t2 = System.currentTimeMillis();
+                            log.debug("ByteCache generation time: " + (t2 - t1) + "ms");
+                        }
+                    } else {
+                        bcCount++;
+                        // Allocate new ByteEntry for the lookup
+                        ByteEntry entry = new ByteEntry();
+                        entry.value = value;
+                        int[] count = (int[]) bcStats.get(entry);
+                        if (count == null) {
+                            int end = bc.getEnd();
+                            int start = bc.getStart();
+                            // Create byte array and copy bytes
+                            entry.name = new byte[bc.getLength()];
+                            System.arraycopy(bc.getBuffer(), start, entry.name, 0, end - start);
+                            // Set encoding
+                            entry.enc = bc.getEncoding();
+                            // Initialize occurrence count to one 
+                            count = new int[1];
+                            count[0] = 1;
+                            // Set in the stats hash map
+                            bcStats.put(entry, count);
+                        } else {
+                            count[0] = count[0] + 1;
+                        }
+                    }
+                }
+            }
+            return value;
+        } else {
+            accessCount++;
+            // Find the corresponding String
+            String result = find(bc);
+            if (result == null) {
+                return bc.toStringInternal();
+            }
+            // Note: We don't care about safety for the stats
+            hitCount++;
+            return result;
+        }
+        
+    }
+
+
+    public static String toString(CharChunk cc) {
+        
+        // If the cache is null, then either caching is disabled, or we're
+        // still training
+        if (ccCache == null) {
+            String value = cc.toStringInternal();
+            if (charEnabled) {
+                // If training, everything is synced
+                synchronized (ccStats) {
+                    // If the cache has been generated on a previous invocation
+                    // while waiting fot the lock, just return the toString value
+                    // we just calculated
+                    if (ccCache != null) {
+                        return value;
+                    }
+                    // Two cases: either we just exceeded the train count, in which
+                    // case the cache must be created, or we just update the count for
+                    // the string
+                    if (ccCount > trainThreshold) {
+                        long t1 = System.currentTimeMillis();
+                        // Sort the entries according to occurrence
+                        TreeMap tempMap = new TreeMap();
+                        Iterator entries = ccStats.keySet().iterator();
+                        while (entries.hasNext()) {
+                            CharEntry entry = (CharEntry) entries.next();
+                            int[] countA = (int[]) ccStats.get(entry);
+                            Integer count = new Integer(countA[0]);
+                            // Add to the list for that count
+                            ArrayList list = (ArrayList) tempMap.get(count);
+                            if (list == null) {
+                                // Create list
+                                list = new ArrayList();
+                                tempMap.put(count, list);
+                            }
+                            list.add(entry);
+                        }
+                        // Allocate array of the right size
+                        int size = ccStats.size();
+                        if (size > cacheSize) {
+                            size = cacheSize;
+                        }
+                        CharEntry[] tempccCache = new CharEntry[size];
+                        // Fill it up using an alphabetical order
+                        // and a dumb insert sort
+                        CharChunk tempChunk = new CharChunk();
+                        int n = 0;
+                        while (n < size) {
+                            Object key = tempMap.lastKey();
+                            ArrayList list = (ArrayList) tempMap.get(key);
+                            CharEntry[] list2 = 
+                                (CharEntry[]) list.toArray(new CharEntry[list.size()]);
+                            for (int i = 0; i < list.size() && n < size; i++) {
+                                CharEntry entry = (CharEntry) list.get(i);
+                                tempChunk.setChars(entry.name, 0, entry.name.length);
+                                int insertPos = findClosest(tempChunk, tempccCache, n);
+                                if (insertPos == n) {
+                                    tempccCache[n + 1] = entry;
+                                } else {
+                                    System.arraycopy(tempccCache, insertPos + 1, tempccCache, 
+                                            insertPos + 2, n - insertPos - 1);
+                                    tempccCache[insertPos + 1] = entry;
+                                }
+                                n++;
+                            }
+                            tempMap.remove(key);
+                        }
+                        ccCount = 0;
+                        ccStats.clear();
+                        ccCache = tempccCache;
+                        if (log.isDebugEnabled()) {
+                            long t2 = System.currentTimeMillis();
+                            log.debug("CharCache generation time: " + (t2 - t1) + "ms");
+                        }
+                    } else {
+                        ccCount++;
+                        // Allocate new CharEntry for the lookup
+                        CharEntry entry = new CharEntry();
+                        entry.value = value;
+                        int[] count = (int[]) ccStats.get(entry);
+                        if (count == null) {
+                            int end = cc.getEnd();
+                            int start = cc.getStart();
+                            // Create char array and copy chars
+                            entry.name = new char[cc.getLength()];
+                            System.arraycopy(cc.getBuffer(), start, entry.name, 0, end - start);
+                            // Initialize occurrence count to one 
+                            count = new int[1];
+                            count[0] = 1;
+                            // Set in the stats hash map
+                            ccStats.put(entry, count);
+                        } else {
+                            count[0] = count[0] + 1;
+                        }
+                    }
+                }
+            }
+            return value;
+        } else {
+            accessCount++;
+            // Find the corresponding String
+            String result = find(cc);
+            if (result == null) {
+                return cc.toStringInternal();
+            }
+            // Note: We don't care about safety for the stats
+            hitCount++;
+            return result;
+        }
+        
+    }
+    
+    
+    // ----------------------------------------------------- Protected Methods
+
+
+    /**
+     * Compare given byte chunk with byte array.
+     * Return -1, 0 or +1 if inferior, equal, or superior to the String.
+     */
+    protected static final int compare(ByteChunk name, byte[] compareTo) {
+        int result = 0;
+
+        byte[] b = name.getBuffer();
+        int start = name.getStart();
+        int end = name.getEnd();
+        int len = compareTo.length;
+
+        if ((end - start) < len) {
+            len = end - start;
+        }
+        for (int i = 0; (i < len) && (result == 0); i++) {
+            if (b[i + start] > compareTo[i]) {
+                result = 1;
+            } else if (b[i + start] < compareTo[i]) {
+                result = -1;
+            }
+        }
+        if (result == 0) {
+            if (compareTo.length > (end - start)) {
+                result = -1;
+            } else if (compareTo.length < (end - start)) {
+                result = 1;
+            }
+        }
+        return result;
+    }
+
+    
+    /**
+     * Find an entry given its name in the cache and return the associated String.
+     */
+    protected static final String find(ByteChunk name) {
+        int pos = findClosest(name, bcCache, bcCache.length);
+        if ((pos < 0) || (compare(name, bcCache[pos].name) != 0)
+                || !(name.getEncoding().equals(bcCache[pos].enc))) {
+            return null;
+        } else {
+            return bcCache[pos].value;
+        }
+    }
+
+    
+    /**
+     * Find an entry given its name in a sorted array of map elements.
+     * This will return the index for the closest inferior or equal item in the
+     * given array.
+     */
+    protected static final int findClosest(ByteChunk name, ByteEntry[] array, int len) {
+
+        int a = 0;
+        int b = len - 1;
+
+        // Special cases: -1 and 0
+        if (b == -1) {
+            return -1;
+        }
+        
+        if (compare(name, array[0].name) < 0) {
+            return -1;
+        }         
+        if (b == 0) {
+            return 0;
+        }
+
+        int i = 0;
+        while (true) {
+            i = (b + a) / 2;
+            int result = compare(name, array[i].name);
+            if (result == 1) {
+                a = i;
+            } else if (result == 0) {
+                return i;
+            } else {
+                b = i;
+            }
+            if ((b - a) == 1) {
+                int result2 = compare(name, array[b].name);
+                if (result2 < 0) {
+                    return a;
+                } else {
+                    return b;
+                }
+            }
+        }
+
+    }
+
+
+    /**
+     * Compare given char chunk with char array.
+     * Return -1, 0 or +1 if inferior, equal, or superior to the String.
+     */
+    protected static final int compare(CharChunk name, char[] compareTo) {
+        int result = 0;
+
+        char[] c = name.getBuffer();
+        int start = name.getStart();
+        int end = name.getEnd();
+        int len = compareTo.length;
+
+        if ((end - start) < len) {
+            len = end - start;
+        }
+        for (int i = 0; (i < len) && (result == 0); i++) {
+            if (c[i + start] > compareTo[i]) {
+                result = 1;
+            } else if (c[i + start] < compareTo[i]) {
+                result = -1;
+            }
+        }
+        if (result == 0) {
+            if (compareTo.length > (end - start)) {
+                result = -1;
+            } else if (compareTo.length < (end - start)) {
+                result = 1;
+            }
+        }
+        return result;
+    }
+
+    
+    /**
+     * Find an entry given its name in the cache and return the associated String.
+     */
+    protected static final String find(CharChunk name) {
+        int pos = findClosest(name, ccCache, ccCache.length);
+        if ((pos < 0) || (compare(name, ccCache[pos].name) != 0)) {
+            return null;
+        } else {
+            return ccCache[pos].value;
+        }
+    }
+
+    
+    /**
+     * Find an entry given its name in a sorted array of map elements.
+     * This will return the index for the closest inferior or equal item in the
+     * given array.
+     */
+    protected static final int findClosest(CharChunk name, CharEntry[] array, int len) {
+
+        int a = 0;
+        int b = len - 1;
+
+        // Special cases: -1 and 0
+        if (b == -1) {
+            return -1;
+        }
+        
+        if (compare(name, array[0].name) < 0 ) {
+            return -1;
+        }         
+        if (b == 0) {
+            return 0;
+        }
+
+        int i = 0;
+        while (true) {
+            i = (b + a) / 2;
+            int result = compare(name, array[i].name);
+            if (result == 1) {
+                a = i;
+            } else if (result == 0) {
+                return i;
+            } else {
+                b = i;
+            }
+            if ((b - a) == 1) {
+                int result2 = compare(name, array[b].name);
+                if (result2 < 0) {
+                    return a;
+                } else {
+                    return b;
+                }
+            }
+        }
+
+    }
+
+
+    // -------------------------------------------------- ByteEntry Inner Class
+
+
+    public static class ByteEntry {
+
+        public byte[] name = null;
+        public String enc = null;
+        public String value = null;
+
+        public String toString() {
+            return value;
+        }
+        public int hashCode() {
+            return value.hashCode();
+        }
+        public boolean equals(Object obj) {
+            if (obj instanceof ByteEntry) {
+                return value.equals(((ByteEntry) obj).value);
+            }
+            return false;
+        }
+        
+    }
+
+
+    // -------------------------------------------------- CharEntry Inner Class
+
+
+    public static class CharEntry {
+
+        public char[] name = null;
+        public String value = null;
+
+        public String toString() {
+            return value;
+        }
+        public int hashCode() {
+            return value.hashCode();
+        }
+        public boolean equals(Object obj) {
+            if (obj instanceof CharEntry) {
+                return value.equals(((CharEntry) obj).value);
+            }
+            return false;
+        }
+        
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/buf/TimeStamp.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/buf/TimeStamp.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/buf/TimeStamp.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,155 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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 java.io.Serializable;
+
+// XXX Shouldn't be here - has nothing to do with buffers.
+
+/**
+ * Main tool for object expiry. 
+ * Marks creation and access time of an "expirable" object,
+ * and extra properties like "id", "valid", etc.
+ *
+ * Used for objects that expire - originally Sessions, but 
+ * also Contexts, Servlets, cache - or any other object that
+ * expires.
+ * 
+ * @author Costin Manolache
+ */
+public final class TimeStamp implements  Serializable {
+    private long creationTime = 0L;
+    private long lastAccessedTime = creationTime;
+    private long thisAccessedTime = creationTime;
+    private boolean isNew = true;
+    private long maxInactiveInterval = -1;
+    private boolean isValid = false;
+    MessageBytes name;
+    int id=-1;
+    
+    Object parent;
+    
+    public TimeStamp() {
+    }
+
+    // -------------------- Active methods --------------------
+
+    /**
+     *  Access notification. This method takes a time parameter in order
+     *  to allow callers to efficiently manage expensive calls to
+     *  System.currentTimeMillis() 
+     */
+    public void touch(long time) {
+	this.lastAccessedTime = this.thisAccessedTime;
+	this.thisAccessedTime = time;
+	this.isNew=false;
+    }
+
+    // -------------------- Property access --------------------
+
+    /** Return the "name" of the timestamp. This can be used
+     *  to associate unique identifier with each timestamped object.
+     *  The name is a MessageBytes - i.e. a modifiable byte[] or char[]. 
+     */
+    public MessageBytes getName() {
+	if( name==null ) name=MessageBytes.newInstance();//lazy
+	return name;
+    }
+
+    /** Each object can have an unique id, similar with name but
+     *  providing faster access ( array vs. hashtable lookup )
+     */
+    public int getId() {
+	return id;
+    }
+
+    public void setId( int id ) {
+	this.id=id;
+    }
+    
+    /** Returns the owner of this stamp ( the object that is
+     *  time-stamped ).
+     *  For a 
+     */
+    public void setParent( Object o ) {
+	parent=o;
+    }
+
+    public Object getParent() {
+	return parent;
+    }
+
+    public void setCreationTime(long time) {
+	this.creationTime = time;
+	this.lastAccessedTime = time;
+	this.thisAccessedTime = time;
+    }
+
+
+    public long getLastAccessedTime() {
+	return lastAccessedTime;
+    }
+
+    public long getThisAccessedTime() {
+        return thisAccessedTime;
+    }
+
+    /** Inactive interval in millis - the time is computed
+     *  in millis, convert to secs in the upper layer
+     */
+    public long getMaxInactiveInterval() {
+	return maxInactiveInterval;
+    }
+
+    public void setMaxInactiveInterval(long interval) {
+	maxInactiveInterval = interval;
+    }
+
+    public boolean isValid() {
+	return isValid;
+    }
+
+    public void setValid(boolean isValid) {
+	this.isValid = isValid;
+    }
+
+    public boolean isNew() {
+	return isNew;
+    }
+
+    public void setNew(boolean isNew) {
+	this.isNew = isNew;
+    }
+
+    public long getCreationTime() {
+	return creationTime;
+    }
+
+    // -------------------- Maintainance --------------------
+
+    public void recycle() {
+	creationTime = 0L;
+	lastAccessedTime = 0L;
+	maxInactiveInterval = -1;
+	isNew = true;
+	isValid = false;
+	id=-1;
+	if( name!=null) name.recycle();
+    }
+
+}
+

Added: branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/buf/UDecoder.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/buf/UDecoder.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/buf/UDecoder.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,276 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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 java.io.CharConversionException;
+import java.io.IOException;
+
+/** 
+ *  All URL decoding happens here. This way we can reuse, review, optimize
+ *  without adding complexity to the buffers.
+ *
+ *  The conversion will modify the original buffer.
+ * 
+ *  @author Costin Manolache
+ */
+public final class UDecoder {
+    
+    private static org.apache.commons.logging.Log log=
+        org.apache.commons.logging.LogFactory.getLog(UDecoder.class );
+    
+    public UDecoder() 
+    {
+    }
+
+    /** URLDecode, will modify the source.  Includes converting
+     *  '+' to ' '.
+     */
+    public void convert( ByteChunk mb )
+        throws IOException
+    {
+        convert(mb, true);
+    }
+
+    /** URLDecode, will modify the source.
+     */
+    public void convert( ByteChunk mb, boolean query )
+	throws IOException
+    {
+	int start=mb.getOffset();
+	byte buff[]=mb.getBytes();
+	int end=mb.getEnd();
+
+	int idx= ByteChunk.indexOf( buff, start, end, '%' );
+        int idx2=-1;
+        if( query )
+            idx2= ByteChunk.indexOf( buff, start, end, '+' );
+	if( idx<0 && idx2<0 ) {
+	    return;
+	}
+
+	// idx will be the smallest positive inxes ( first % or + )
+	if( idx2 >= 0 && idx2 < idx ) idx=idx2;
+	if( idx < 0 ) idx=idx2;
+
+	for( int j=idx; j<end; j++, idx++ ) {
+	    if( buff[ j ] == '+' && query) {
+		buff[idx]= (byte)' ' ;
+	    } else if( buff[ j ] != '%' ) {
+		buff[idx]= buff[j];
+	    } else {
+		// read next 2 digits
+		if( j+2 >= end ) {
+		    throw new CharConversionException("EOF");
+		}
+		byte b1= buff[j+1];
+		byte b2=buff[j+2];
+		if( !isHexDigit( b1 ) || ! isHexDigit(b2 ))
+		    throw new CharConversionException( "isHexDigit");
+		
+		j+=2;
+		int res=x2c( b1, b2 );
+		buff[idx]=(byte)res;
+	    }
+	}
+
+	mb.setEnd( idx );
+	
+	return;
+    }
+
+    // -------------------- Additional methods --------------------
+    // XXX What do we do about charset ????
+
+    /** In-buffer processing - the buffer will be modified
+     *  Includes converting  '+' to ' '.
+     */
+    public void convert( CharChunk mb )
+	throws IOException
+    {
+        convert(mb, true);
+    }
+
+    /** In-buffer processing - the buffer will be modified
+     */
+    public void convert( CharChunk mb, boolean query )
+	throws IOException
+    {
+	//	log( "Converting a char chunk ");
+	int start=mb.getOffset();
+	char buff[]=mb.getBuffer();
+	int cend=mb.getEnd();
+
+	int idx= CharChunk.indexOf( buff, start, cend, '%' );
+        int idx2=-1;
+        if( query )
+            idx2= CharChunk.indexOf( buff, start, cend, '+' );
+	if( idx<0 && idx2<0 ) {
+	    return;
+	}
+	
+	if( idx2 >= 0 && idx2 < idx ) idx=idx2; 
+	if( idx < 0 ) idx=idx2;
+
+	for( int j=idx; j<cend; j++, idx++ ) {
+	    if( buff[ j ] == '+' && query ) {
+		buff[idx]=( ' ' );
+	    } else if( buff[ j ] != '%' ) {
+		buff[idx]=buff[j];
+	    } else {
+		// read next 2 digits
+		if( j+2 >= cend ) {
+		    // invalid
+		    throw new CharConversionException("EOF");
+		}
+		char b1= buff[j+1];
+		char b2=buff[j+2];
+		if( !isHexDigit( b1 ) || ! isHexDigit(b2 ))
+		    throw new CharConversionException("isHexDigit");
+		
+		j+=2;
+		int res=x2c( b1, b2 );
+		buff[idx]=(char)res;
+	    }
+	}
+	mb.setEnd( idx );
+    }
+
+    /** URLDecode, will modify the source
+     *  Includes converting  '+' to ' '.
+     */
+    public void convert(MessageBytes mb)
+	throws IOException
+    {
+        convert(mb, true);
+    }
+
+    /** URLDecode, will modify the source
+     */
+    public void convert(MessageBytes mb, boolean query)
+	throws IOException
+    {
+	
+	switch (mb.getType()) {
+	case MessageBytes.T_STR:
+	    String strValue=mb.toString();
+	    if( strValue==null ) return;
+	    mb.setString( convert( strValue, query ));
+	    break;
+	case MessageBytes.T_CHARS:
+	    CharChunk charC=mb.getCharChunk();
+	    convert( charC, query );
+	    break;
+	case MessageBytes.T_BYTES:
+	    ByteChunk bytesC=mb.getByteChunk();
+	    convert( bytesC, query );
+	    break;
+	}
+    }
+
+    // XXX Old code, needs to be replaced !!!!
+    // 
+    public final String convert(String str)
+    {
+        return convert(str, true);
+    }
+
+    public final String convert(String str, boolean query)
+    {
+        if (str == null)  return  null;
+	
+	if( (!query || str.indexOf( '+' ) < 0) && str.indexOf( '%' ) < 0 )
+	    return str;
+	
+        StringBuffer dec = new StringBuffer();    // decoded string output
+        int strPos = 0;
+        int strLen = str.length();
+
+        dec.ensureCapacity(str.length());
+        while (strPos < strLen) {
+            int laPos;        // lookahead position
+
+            // look ahead to next URLencoded metacharacter, if any
+            for (laPos = strPos; laPos < strLen; laPos++) {
+                char laChar = str.charAt(laPos);
+                if ((laChar == '+' && query) || (laChar == '%')) {
+                    break;
+                }
+            }
+
+            // if there were non-metacharacters, copy them all as a block
+            if (laPos > strPos) {
+                dec.append(str.substring(strPos,laPos));
+                strPos = laPos;
+            }
+
+            // shortcut out of here if we're at the end of the string
+            if (strPos >= strLen) {
+                break;
+            }
+
+            // process next metacharacter
+            char metaChar = str.charAt(strPos);
+            if (metaChar == '+') {
+                dec.append(' ');
+                strPos++;
+                continue;
+            } else if (metaChar == '%') {
+		// We throw the original exception - the super will deal with
+		// it
+		//                try {
+		dec.append((char)Integer.
+			   parseInt(str.substring(strPos + 1, strPos + 3),16));
+                strPos += 3;
+            }
+        }
+
+        return dec.toString();
+    }
+
+
+
+    private static boolean isHexDigit( int c ) {
+	return ( ( c>='0' && c<='9' ) ||
+		 ( c>='a' && c<='f' ) ||
+		 ( c>='A' && c<='F' ));
+    }
+    
+    private static int x2c( byte b1, byte b2 ) {
+	int digit= (b1>='A') ? ( (b1 & 0xDF)-'A') + 10 :
+	    (b1 -'0');
+	digit*=16;
+	digit +=(b2>='A') ? ( (b2 & 0xDF)-'A') + 10 :
+	    (b2 -'0');
+	return digit;
+    }
+
+    private static int x2c( char b1, char b2 ) {
+	int digit= (b1>='A') ? ( (b1 & 0xDF)-'A') + 10 :
+	    (b1 -'0');
+	digit*=16;
+	digit +=(b2>='A') ? ( (b2 & 0xDF)-'A') + 10 :
+	    (b2 -'0');
+	return digit;
+    }
+
+    private final static int debug=0;
+    private static void log( String s ) {
+        if (log.isDebugEnabled())
+            log.debug("URLDecoder: " + s );
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/buf/UEncoder.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/buf/UEncoder.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/buf/UEncoder.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,181 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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 java.io.CharArrayWriter;
+import java.io.IOException;
+import java.io.Writer;
+import java.util.BitSet;
+
+/** Efficient implementation for encoders.
+ *  This class is not thread safe - you need one encoder per thread.
+ *  The encoder will save and recycle the internal objects, avoiding
+ *  garbage.
+ * 
+ *  You can add extra characters that you want preserved, for example
+ *  while encoding a URL you can add "/".
+ *
+ *  @author Costin Manolache
+ */
+public final class UEncoder {
+
+    private static org.apache.commons.logging.Log log=
+        org.apache.commons.logging.LogFactory.getLog(UEncoder.class );
+    
+    // Not static - the set may differ ( it's better than adding
+    // an extra check for "/", "+", etc
+    private BitSet safeChars=null;
+    private C2BConverter c2b=null;
+    private ByteChunk bb=null;
+
+    private String encoding="UTF8";
+    private static final int debug=0;
+    
+    public UEncoder() {
+	initSafeChars();
+    }
+
+    public void setEncoding( String s ) {
+	encoding=s;
+    }
+
+    public void addSafeCharacter( char c ) {
+	safeChars.set( c );
+    }
+
+
+    /** URL Encode string, using a specified encoding.
+     *
+     * @param buf The writer
+     * @param s string to be encoded
+     * @throws IOException If an I/O error occurs
+     */
+    public void urlEncode( Writer buf, String s )
+	throws IOException
+    {
+	if( c2b==null ) {
+	    bb=new ByteChunk(16); // small enough.
+	    c2b=new C2BConverter( bb, encoding );
+	}
+
+	for (int i = 0; i < s.length(); i++) {
+	    int c = (int) s.charAt(i);
+	    if( safeChars.get( c ) ) {
+		if( debug > 0 ) log("Safe: " + (char)c);
+		buf.write((char)c);
+	    } else {
+		if( debug > 0 ) log("Unsafe:  " + (char)c);
+		c2b.convert( (char)c );
+		
+		// "surrogate" - UTF is _not_ 16 bit, but 21 !!!!
+		// ( while UCS is 31 ). Amazing...
+		if (c >= 0xD800 && c <= 0xDBFF) {
+		    if ( (i+1) < s.length()) {
+			int d = (int) s.charAt(i+1);
+			if (d >= 0xDC00 && d <= 0xDFFF) {
+			    if( debug > 0 ) log("Unsafe:  " + c);
+			    c2b.convert( (char)d);
+			    i++;
+			}
+		    }
+		}
+
+		c2b.flushBuffer();
+		
+		urlEncode( buf, bb.getBuffer(), bb.getOffset(),
+			   bb.getLength() );
+		bb.recycle();
+	    }
+	}
+    }
+
+    /**
+     */
+    public void urlEncode( Writer buf, byte bytes[], int off, int len)
+	throws IOException
+    {
+	for( int j=off; j< len; j++ ) {
+	    buf.write( '%' );
+	    char ch = Character.forDigit((bytes[j] >> 4) & 0xF, 16);
+	    if( debug > 0 ) log("Encode:  " + ch);
+	    buf.write(ch);
+	    ch = Character.forDigit(bytes[j] & 0xF, 16);
+	    if( debug > 0 ) log("Encode:  " + ch);
+	    buf.write(ch);
+	}
+    }
+    
+    /**
+     * Utility funtion to re-encode the URL.
+     * Still has problems with charset, since UEncoder mostly
+     * ignores it.
+     */
+    public String encodeURL(String uri) {
+	String outUri=null;
+	try {
+	    // XXX optimize - recycle, etc
+	    CharArrayWriter out = new CharArrayWriter();
+	    urlEncode(out, uri);
+	    outUri=out.toString();
+	} catch (IOException iex) {
+	}
+	return outUri;
+    }
+    
+
+    // -------------------- Internal implementation --------------------
+    
+    // 
+    private void init() {
+	
+    }
+    
+    private void initSafeChars() {
+	safeChars=new BitSet(128);
+	int i;
+	for (i = 'a'; i <= 'z'; i++) {
+	    safeChars.set(i);
+	}
+	for (i = 'A'; i <= 'Z'; i++) {
+	    safeChars.set(i);
+	}
+	for (i = '0'; i <= '9'; i++) {
+	    safeChars.set(i);
+	}
+	//safe
+	safeChars.set('$');
+	safeChars.set('-');
+	safeChars.set('_');
+	safeChars.set('.');
+
+	// Dangerous: someone may treat this as " "
+	// RFC1738 does allow it, it's not reserved
+	//    safeChars.set('+');
+	//extra
+	safeChars.set('!');
+	safeChars.set('*');
+	safeChars.set('\'');
+	safeChars.set('(');
+	safeChars.set(')');
+	safeChars.set(',');	
+    }
+
+    private static void log( String s ) {
+        if (log.isDebugEnabled())
+            log.debug("Encoder: " + s );
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/buf/UTF8Decoder.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/buf/UTF8Decoder.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/buf/UTF8Decoder.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,149 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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 java.io.IOException;
+
+/**
+ * Moved from ByteChunk - code to convert from UTF8 bytes to chars.
+ * Not used in the current tomcat3.3 : the performance gain is not very
+ * big if the String is created, only if we avoid that and work only
+ * on char[]. Until than, it's better to be safe. ( I tested this code
+ * with 2 and 3 bytes chars, and it works fine in xerces )
+ * 
+ * Cut from xerces' UTF8Reader.copyMultiByteCharData() 
+ *
+ * @author Costin Manolache
+ * @author ( Xml-Xerces )
+ */
+public final class UTF8Decoder extends B2CConverter {
+    
+    
+    private static org.apache.commons.logging.Log log=
+        org.apache.commons.logging.LogFactory.getLog(UTF8Decoder.class );
+    
+    // may have state !!
+    
+    public UTF8Decoder() {
+
+    }
+    
+    public void recycle() {
+    }
+
+    public void convert(ByteChunk mb, CharChunk cb )
+	throws IOException
+    {
+	int bytesOff=mb.getOffset();
+	int bytesLen=mb.getLength();
+	byte bytes[]=mb.getBytes();
+	
+	int j=bytesOff;
+	int end=j+bytesLen;
+
+	while( j< end ) {
+	    int b0=0xff & bytes[j];
+
+	    if( (b0 & 0x80) == 0 ) {
+		cb.append((char)b0);
+		j++;
+		continue;
+	    }
+	    
+	    // 2 byte ?
+	    if( j++ >= end ) {
+		// ok, just ignore - we could throw exception
+		throw new IOException( "Conversion error - EOF " );
+	    }
+	    int b1=0xff & bytes[j];
+	    
+	    // ok, let's the fun begin - we're handling UTF8
+	    if ((0xe0 & b0) == 0xc0) { // 110yyyyy 10xxxxxx (0x80 to 0x7ff)
+		int ch = ((0x1f & b0)<<6) + (0x3f & b1);
+		if(debug>0)
+		    log("Convert " + b0 + " " + b1 + " " + ch + ((char)ch));
+		
+		cb.append((char)ch);
+		j++;
+		continue;
+	    }
+	    
+	    if( j++ >= end ) 
+		return ;
+	    int b2=0xff & bytes[j];
+	    
+	    if( (b0 & 0xf0 ) == 0xe0 ) {
+		if ((b0 == 0xED && b1 >= 0xA0) ||
+		    (b0 == 0xEF && b1 == 0xBF && b2 >= 0xBE)) {
+		    if(debug>0)
+			log("Error " + b0 + " " + b1+ " " + b2 );
+
+		    throw new IOException( "Conversion error 2"); 
+		}
+
+		int ch = ((0x0f & b0)<<12) + ((0x3f & b1)<<6) + (0x3f & b2);
+		cb.append((char)ch);
+		if(debug>0)
+		    log("Convert " + b0 + " " + b1+ " " + b2 + " " + ch +
+			((char)ch));
+		j++;
+		continue;
+	    }
+
+	    if( j++ >= end ) 
+		return ;
+	    int b3=0xff & bytes[j];
+
+	    if (( 0xf8 & b0 ) == 0xf0 ) {
+		if (b0 > 0xF4 || (b0 == 0xF4 && b1 >= 0x90)) {
+		    if(debug>0)
+			log("Convert " + b0 + " " + b1+ " " + b2 + " " + b3);
+		    throw new IOException( "Conversion error ");
+		}
+		int ch = ((0x0f & b0)<<18) + ((0x3f & b1)<<12) +
+		    ((0x3f & b2)<<6) + (0x3f & b3);
+
+		if(debug>0)
+		    log("Convert " + b0 + " " + b1+ " " + b2 + " " + b3 + " " +
+			ch + ((char)ch));
+
+		if (ch < 0x10000) {
+		    cb.append( (char)ch );
+		} else {
+		    cb.append((char)(((ch-0x00010000)>>10)+
+						   0xd800));
+		    cb.append((char)(((ch-0x00010000)&0x3ff)+
+						   0xdc00));
+		}
+		j++;
+		continue;
+	    } else {
+		// XXX Throw conversion exception !!!
+		if(debug>0)
+		    log("Convert " + b0 + " " + b1+ " " + b2 + " " + b3);
+		throw new IOException( "Conversion error 4" );
+	    }
+	}
+    }
+
+    private static int debug=1;
+    void log(String s ) {
+        if (log.isDebugEnabled())
+            log.debug("UTF8Decoder: " + s );
+    }
+    
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/buf/package.html
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/buf/package.html	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/buf/package.html	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,22 @@
+<html><body>
+<H1>Buffers and Encodings</h1>
+
+This package contains buffers and utils to perform encoding/decoding of buffers. That includes byte to char
+conversions, URL encodings, etc. 
+
+<p>
+Encoding is a critical operation for performance. There are few tricks in this package - the C2B and 
+B2C converters are caching a ISReader/OSWriter and keep everything allocated to do the conversions 
+in any VM without any garbage.
+
+<p>
+This package must accomodate future extensions and additional converters ( most imporant: the nio.charset, 
+which should be detected and used if available ). Also, we do have one hand-written UTF8Decoder, and 
+other tuned encoders could be added.
+
+<p>
+My benchmarks ( I'm costin :-) show only small differences between C2B, B2C and hand-written codders/decoders,
+so UTF8Decoder may be disabled. 
+
+<p>
+</body></html>

Added: branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/buf/res/LocalStrings.properties
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/buf/res/LocalStrings.properties	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/buf/res/LocalStrings.properties	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,3 @@
+hexUtil.bad=Bad hexadecimal digit
+hexUtil.odd=Odd number of hexadecimal digits
+httpDate.pe=invalid date format: {0}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/buf/res/LocalStrings_es.properties
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/buf/res/LocalStrings_es.properties	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/buf/res/LocalStrings_es.properties	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,4 @@
+hexUtil.bad=Dígito hexadecimal incorrecto
+hexUtil.odd=Número de dígitos hexadecimales incorrecto
+httpDate.pe=formato de fecha no válido: {0}
+

Added: branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/buf/res/LocalStrings_fr.properties
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/buf/res/LocalStrings_fr.properties	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/buf/res/LocalStrings_fr.properties	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,3 @@
+hexUtil.bad=Mauvais digit hexadécimal
+hexUtil.odd=Nombre impair de digits hexadécimaux
+httpDate.pe=Format de date invalide: {0}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/buf/res/LocalStrings_ja.properties
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/buf/res/LocalStrings_ja.properties	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/buf/res/LocalStrings_ja.properties	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,3 @@
+hexUtil.bad=\u7121\u52b9\u306a16\u9032\u6570\u5024\u3067\u3059
+hexUtil.odd=\u5947\u6570\u6841\u306e16\u9032\u6570\u5024\u3067\u3059
+httpDate.pe=\u7121\u52b9\u306a\u65e5\u4ed8\u30d5\u30a9\u30fc\u30de\u30c3\u30c8\u3067\u3059: {0}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/collections/EmptyEnumeration.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/collections/EmptyEnumeration.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/collections/EmptyEnumeration.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,41 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.Enumeration;
+import java.util.NoSuchElementException;
+
+public class EmptyEnumeration implements Enumeration {
+
+    static EmptyEnumeration staticInstance=new EmptyEnumeration();
+
+    public EmptyEnumeration() {
+    }
+
+    public static Enumeration getEmptyEnumeration() {
+	return staticInstance;
+    }
+    
+    public Object nextElement( ) {
+	throw new NoSuchElementException( "EmptyEnumeration");
+    }
+
+    public boolean hasMoreElements() {
+	return false;
+    }
+    
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/collections/LRUCache.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/collections/LRUCache.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/collections/LRUCache.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,150 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.Hashtable;
+
+/**
+ * This class implements a Generic LRU Cache
+ *
+ *
+ * @author Ignacio J. Ortega
+ *
+ */
+
+public class LRUCache
+{
+    class CacheNode
+    {
+
+        CacheNode prev;
+        CacheNode next;
+        Object value;
+        Object key;
+
+        CacheNode()
+        {
+        }
+    }
+
+
+    public LRUCache(int i)
+    {
+        currentSize = 0;
+        cacheSize = i;
+        nodes = new Hashtable(i);
+    }
+
+    public Object get(Object key)
+    {
+        CacheNode node = (CacheNode)nodes.get(key);
+        if(node != null)
+        {
+            moveToHead(node);
+            return node.value;
+        }
+        else
+        {
+            return null;
+        }
+    }
+
+    public void put(Object key, Object value)
+    {
+        CacheNode node = (CacheNode)nodes.get(key);
+        if(node == null)
+        {
+            if(currentSize >= cacheSize)
+            {
+                if(last != null)
+                    nodes.remove(last.key);
+                removeLast();
+            }
+            else
+            {
+                currentSize++;
+            }
+            node = new CacheNode();
+        }
+        node.value = value;
+        node.key = key;
+        moveToHead(node);
+        nodes.put(key, node);
+    }
+
+    public Object remove(Object key) {
+        CacheNode node = (CacheNode)nodes.get(key);
+        if (node != null) {
+            if (node.prev != null) {
+                node.prev.next = node.next;
+            }
+            if (node.next != null) {
+                node.next.prev = node.prev;
+            }
+            if (last == node)
+                last = node.prev;
+            if (first == node)
+                first = node.next;
+        }
+        return node;
+    }
+
+    public void clear()
+    {
+        first = null;
+        last = null;
+    }
+
+    private void removeLast()
+    {
+        if(last != null)
+        {
+            if(last.prev != null)
+                last.prev.next = null;
+            else
+                first = null;
+            last = last.prev;
+        }
+    }
+
+    private void moveToHead(CacheNode node)
+    {
+        if(node == first)
+            return;
+        if(node.prev != null)
+            node.prev.next = node.next;
+        if(node.next != null)
+            node.next.prev = node.prev;
+        if(last == node)
+            last = node.prev;
+        if(first != null)
+        {
+            node.next = first;
+            first.prev = node;
+        }
+        first = node;
+        node.prev = null;
+        if(last == null)
+            last = first;
+    }
+
+    private int cacheSize;
+    private Hashtable nodes;
+    private int currentSize;
+    private CacheNode first;
+    private CacheNode last;
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/collections/MultiMap.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/collections/MultiMap.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/collections/MultiMap.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,235 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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 org.apache.tomcat.util.buf.MessageBytes;
+
+// Originally MimeHeaders
+
+/**
+ * An efficient representation for certain type of map. The keys 
+ * can have a single or multi values, but most of the time there are
+ * single values.
+ *
+ * The data is of "MessageBytes" type, meaning bytes[] that can be
+ * converted to Strings ( if needed, and encoding is lazy-binded ).
+ *
+ * This is a base class for MimeHeaders, Parameters and Cookies.
+ *
+ * Data structures: each field is a single-valued key/value.
+ * The fields are allocated when needed, and are recycled.
+ * The current implementation does linear search, in future we'll
+ * also use the hashkey.
+ * 
+ * @author dac at eng.sun.com
+ * @author James Todd [gonzo at eng.sun.com]
+ * @author Costin Manolache
+ */
+public class MultiMap {
+
+    protected Field[] fields;
+    // fields in use
+    protected int count;
+
+    /**
+     * 
+     */
+    public MultiMap(int initial_size) {
+	fields=new Field[initial_size];
+    }
+
+    /**
+     * Clears all header fields.
+     */
+    public void recycle() {
+	for (int i = 0; i < count; i++) {
+	    fields[i].recycle();
+	}
+	count = 0;
+    }
+
+    // -------------------- Idx access to headers ----------
+    // This allows external iterators.
+    
+    /**
+     * Returns the current number of header fields.
+     */
+    public int size() {
+	return count;
+    }
+
+    /**
+     * Returns the Nth header name
+     * This may be used to iterate through all header fields.
+     *
+     * An exception is thrown if the index is not valid ( <0 or >size )
+     */
+    public MessageBytes getName(int n) {
+	// n >= 0 && n < count ? headers[n].getName() : null
+	return fields[n].name;
+    }
+
+    /**
+     * Returns the Nth header value
+     * This may be used to iterate through all header fields.
+     */
+    public MessageBytes getValue(int n) {
+	return fields[n].value;
+    }
+
+    /** Find the index of a field with the given name.
+     */
+    public int find( String name, int starting ) {
+	// We can use a hash - but it's not clear how much
+	// benefit you can get - there is an  overhead 
+	// and the number of headers is small (4-5 ?)
+	// Another problem is that we'll pay the overhead
+	// of constructing the hashtable
+
+	// A custom search tree may be better
+        for (int i = starting; i < count; i++) {
+	    if (fields[i].name.equals(name)) {
+                return i;
+            }
+        }
+        return -1;
+    }
+
+    /** Find the index of a field with the given name.
+     */
+    public int findIgnoreCase( String name, int starting ) {
+	// We can use a hash - but it's not clear how much
+	// benefit you can get - there is an  overhead 
+	// and the number of headers is small (4-5 ?)
+	// Another problem is that we'll pay the overhead
+	// of constructing the hashtable
+
+	// A custom search tree may be better
+        for (int i = starting; i < count; i++) {
+	    if (fields[i].name.equalsIgnoreCase(name)) {
+                return i;
+            }
+        }
+        return -1;
+    }
+
+    /**
+     * Removes the field at the specified position.  
+     *
+     * MultiMap will preserve the order of field add unless remove()
+     * is called. This is not thread-safe, and will invalidate all
+     * iterators. 
+     *
+     * This is not a frequent operation for Headers and Parameters -
+     * there are better ways ( like adding a "isValid" field )
+     */
+    public void remove( int i ) {
+	// reset and swap with last header
+	Field mh = fields[i];
+	// reset the field
+	mh.recycle();
+	
+	fields[i] = fields[count - 1];
+	fields[count - 1] = mh;
+	count--;
+    }
+
+    /** Create a new, unitialized entry. 
+     */
+    public int addField() {
+	int len = fields.length;
+	int pos=count;
+	if (count >= len) {
+	    // expand header list array
+	    Field tmp[] = new Field[pos * 2];
+	    System.arraycopy(fields, 0, tmp, 0, len);
+	    fields = tmp;
+	}
+	if (fields[pos] == null) {
+	    fields[pos] = new Field();
+	}
+	count++;
+	return pos;
+    }
+
+    public MessageBytes get( String name) {
+        for (int i = 0; i < count; i++) {
+	    if (fields[i].name.equals(name)) {
+		return fields[i].value;
+	    }
+	}
+        return null;
+    }
+
+    public int findFirst( String name ) {
+        for (int i = 0; i < count; i++) {
+	    if (fields[i].name.equals(name)) {
+		return i;
+	    }
+	}
+        return -1;
+    }
+
+    public int findNext( int startPos ) {
+	int next= fields[startPos].nextPos;
+	if( next != MultiMap.NEED_NEXT ) {
+	    return next;
+	}
+
+	// next==NEED_NEXT, we never searched for this header
+	MessageBytes name=fields[startPos].name;
+        for (int i = startPos; i < count; i++) {
+	    if (fields[i].name.equals(name)) {
+		// cache the search result
+		fields[startPos].nextPos=i;
+		return i;
+	    }
+	}
+	fields[startPos].nextPos= MultiMap.LAST;
+        return -1;
+    }
+
+    // workaround for JDK1.1.8/solaris
+    static final int NEED_NEXT=-2;
+    static final int LAST=-1;
+
+    // -------------------- Internal representation --------------------
+    final class Field {
+	MessageBytes name;
+	MessageBytes value;
+
+	// Extra info for speed
+	
+	//  multiple fields with same name - a linked list will
+	// speed up multiple name enumerations and search.
+	int nextPos;
+
+	// hashkey
+	int hash;
+	Field nextSameHash;
+
+	Field() {
+	    nextPos=MultiMap.NEED_NEXT;
+	}
+	
+	void recycle() {
+	    name.recycle();
+	    value.recycle();
+	    nextPos=MultiMap.NEED_NEXT;
+	}
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/collections/MultiMapNamesEnumeration.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/collections/MultiMapNamesEnumeration.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/collections/MultiMapNamesEnumeration.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,80 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.Enumeration;
+
+/** Enumerate the distinct header names.
+    Each nextElement() is O(n) ( a comparation is
+    done with all previous elements ).
+
+    This is less frequesnt than add() -
+    we want to keep add O(1).
+*/
+public final class MultiMapNamesEnumeration implements Enumeration {
+    int pos;
+    int size;
+    String next;
+    MultiMap headers;
+
+    // toString and unique options are not implemented -
+    // we allways to toString and unique.
+    
+    /** Create a new multi-map enumeration.
+     * @param  headers the collection to enumerate 
+     * @param  toString convert each name to string 
+     * @param  unique return only unique names
+     */
+    MultiMapNamesEnumeration(MultiMap headers, boolean toString,
+			     boolean unique) {
+	this.headers=headers;
+	pos=0;
+	size = headers.size();
+	findNext();
+    }
+
+    private void findNext() {
+	next=null;
+	for(  ; pos< size; pos++ ) {
+	    next=headers.getName( pos ).toString();
+	    for( int j=0; j<pos ; j++ ) {
+		if( headers.getName( j ).equalsIgnoreCase( next )) {
+		    // duplicate.
+		    next=null;
+		    break;
+		}
+	    }
+	    if( next!=null ) {
+		// it's not a duplicate
+		break;
+	    }
+	}
+	// next time findNext is called it will try the
+	// next element
+	pos++;
+    }
+    
+    public boolean hasMoreElements() {
+	return next!=null;
+    }
+
+    public Object nextElement() {
+	String current=next;
+	findNext();
+	return current;
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/collections/MultiMapValuesEnumeration.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/collections/MultiMapValuesEnumeration.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/collections/MultiMapValuesEnumeration.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,63 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.Enumeration;
+
+import org.apache.tomcat.util.buf.MessageBytes;
+
+/** Enumerate the values for a (possibly ) multiple
+ *    value element.
+ */
+class MultiMapValuesEnumeration implements Enumeration {
+    int pos;
+    int size;
+    MessageBytes next;
+    MultiMap headers;
+    String name;
+
+    MultiMapValuesEnumeration(MultiMap headers, String name,
+			      boolean toString) {
+        this.name=name;
+	this.headers=headers;
+	pos=0;
+	size = headers.size();
+	findNext();
+    }
+
+    private void findNext() {
+	next=null;
+	for( ; pos< size; pos++ ) {
+	    MessageBytes n1=headers.getName( pos );
+	    if( n1.equalsIgnoreCase( name )) {
+		next=headers.getValue( pos );
+		break;
+	    }
+	}
+	pos++;
+    }
+    
+    public boolean hasMoreElements() {
+	return next!=null;
+    }
+
+    public Object nextElement() {
+	MessageBytes current=next;
+	findNext();
+	return current.toString();
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/collections/Queue.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/collections/Queue.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/collections/Queue.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,102 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.Vector;
+
+/**
+ * A simple FIFO queue class which causes the calling thread to wait
+ * if the queue is empty and notifies threads that are waiting when it
+ * is not empty.
+ *
+ * @author Anil V (akv at eng.sun.com)
+ */
+public class Queue {
+    private Vector vector = new Vector();
+    private boolean stopWaiting=false;
+    private boolean waiting=false;
+    
+    /** 
+     * Put the object into the queue.
+     * 
+     * @param	object		the object to be appended to the
+     * 				queue. 
+     */
+    public synchronized void put(Object object) {
+	vector.addElement(object);
+	notify();
+    }
+
+    /** Break the pull(), allowing the calling thread to exit
+     */
+    public synchronized void stop() {
+	stopWaiting=true;
+	// just a hack to stop waiting 
+	if( waiting ) notify();
+    }
+    
+    /**
+     * Pull the first object out of the queue. Wait if the queue is
+     * empty.
+     */
+    public synchronized Object pull() {
+	while (isEmpty()) {
+	    try {
+		waiting=true;
+		wait();
+	    } catch (InterruptedException ex) {
+	    }
+	    waiting=false;
+	    if( stopWaiting ) return null;
+	}
+	return get();
+    }
+
+    /**
+     * Get the first object out of the queue. Return null if the queue
+     * is empty. 
+     */
+    public synchronized Object get() {
+	Object object = peek();
+	if (object != null)
+	    vector.removeElementAt(0);
+	return object;
+    }
+
+    /**
+     * Peek to see if something is available.
+     */
+    public Object peek() {
+	if (isEmpty())
+	    return null;
+	return vector.elementAt(0);
+    }
+    
+    /**
+     * Is the queue empty?
+     */
+    public boolean isEmpty() {
+	return vector.isEmpty();
+    }
+
+    /**
+     * How many elements are there in this queue?
+     */
+    public int size() {
+	return vector.size();
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/collections/SimpleHashtable.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/collections/SimpleHashtable.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/collections/SimpleHashtable.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,323 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.Enumeration;
+
+/* **************************************** Stolen from Crimson ******************** */
+/* From Crimson/Parser - in a perfect world we'll just have a common set of
+   utilities, and all apache project will just use those.
+
+*/
+
+// can't be replaced using a Java 2 "Collections" API
+// since this package must also run on JDK 1.1
+
+
+/**
+ * This class implements a special purpose hashtable.  It works like a
+ * normal <code>java.util.Hashtable</code> except that: <OL>
+ *
+ *	<LI> Keys to "get" are strings which are known to be interned,
+ *	so that "==" is used instead of "String.equals".  (Interning
+ *	could be document-relative instead of global.)
+ *
+ *	<LI> It's not synchronized, since it's to be used only by
+ *	one thread at a time.
+ *
+ *	<LI> The keys () enumerator allocates no memory, with live
+ *	updates to the data disallowed.
+ *
+ *	<LI> It's got fewer bells and whistles:  fixed threshold and
+ *	load factor, no JDK 1.2 collection support, only keys can be
+ *	enumerated, things can't be removed, simpler inheritance; more.
+ *
+ *	</OL>
+ *
+ * <P> The overall result is that it's less expensive to use these in
+ * performance-critical locations, in terms both of CPU and memory,
+ * than <code>java.util.Hashtable</code> instances.  In this package
+ * it makes a significant difference when normalizing attributes,
+ * which is done for each start-element construct.
+ *
+ */
+public final class SimpleHashtable implements Enumeration
+{
+    
+    private static org.apache.commons.logging.Log log=
+        org.apache.commons.logging.LogFactory.getLog( SimpleHashtable.class );
+    
+    // entries ...
+    private Entry		table[];
+
+    // currently enumerated key
+    private Entry		current = null;
+    private int			currentBucket = 0;
+
+    // number of elements in hashtable
+    private int			count;
+    private int			threshold;
+
+    private static final float	loadFactor = 0.75f;
+
+
+    /**
+     * Constructs a new, empty hashtable with the specified initial 
+     * capacity.
+     *
+     * @param      initialCapacity   the initial capacity of the hashtable.
+     */
+    public SimpleHashtable(int initialCapacity) {
+	if (initialCapacity < 0)
+	    throw new IllegalArgumentException("Illegal Capacity: "+
+                                               initialCapacity);
+        if (initialCapacity==0)
+            initialCapacity = 1;
+	table = new Entry[initialCapacity];
+	threshold = (int)(initialCapacity * loadFactor);
+    }
+
+    /**
+     * Constructs a new, empty hashtable with a default capacity.
+     */
+    public SimpleHashtable() {
+	this(11);
+    }
+
+    /**
+     */
+    public void clear ()
+    {
+	count = 0;
+	currentBucket = 0;
+	current = null;
+	for (int i = 0; i < table.length; i++)
+	    table [i] = null;
+    }
+
+    /**
+     * Returns the number of keys in this hashtable.
+     *
+     * @return  the number of keys in this hashtable.
+     */
+    public int size() {
+	return count;
+    }
+
+    /**
+     * Returns an enumeration of the keys in this hashtable.
+     *
+     * @return  an enumeration of the keys in this hashtable.
+     * @see     Enumeration
+     */
+    public Enumeration keys() {
+	currentBucket = 0;
+	current = null;
+	hasMoreElements();
+	return this;
+    }
+
+    /**
+     * Used to view this as an enumeration; returns true if there
+     * are more keys to be enumerated.
+     */
+    public boolean hasMoreElements ()
+    {
+	if (current != null)
+	    return true;
+	while (currentBucket < table.length) {
+	    current = table [currentBucket++];
+	    if (current != null)
+		return true;
+	}
+	return false;
+    }
+
+    /**
+     * Used to view this as an enumeration; returns the next key
+     * in the enumeration.
+     */
+    public Object nextElement ()
+    {
+	Object retval;
+
+	if (current == null)
+	    throw new IllegalStateException ();
+	retval = current.key;
+	current = current.next;
+	// Advance to the next position ( we may call next after next,
+	// without hasMore )
+	hasMoreElements();
+	return retval;
+    }
+
+
+    /**
+     * Returns the value to which the specified key is mapped in this hashtable.
+     */
+    public Object getInterned (String key) {
+	Entry tab[] = table;
+	int hash = key.hashCode();
+	int index = (hash & 0x7FFFFFFF) % tab.length;
+	for (Entry e = tab[index] ; e != null ; e = e.next) {
+	    if ((e.hash == hash) && (e.key == key))
+		return e.value;
+	}
+	return null;
+    }
+
+    /**
+     * Returns the value to which the specified key is mapped in this
+     * hashtable ... the key isn't necessarily interned, though.
+     */
+    public Object get(String key) {
+	Entry tab[] = table;
+	int hash = key.hashCode();
+	int index = (hash & 0x7FFFFFFF) % tab.length;
+	for (Entry e = tab[index] ; e != null ; e = e.next) {
+	    if ((e.hash == hash) && e.key.equals(key))
+		return e.value;
+	}
+	return null;
+    }
+
+    /**
+     * Increases the capacity of and internally reorganizes this 
+     * hashtable, in order to accommodate and access its entries more 
+     * efficiently.  This method is called automatically when the 
+     * number of keys in the hashtable exceeds this hashtable's capacity 
+     * and load factor. 
+     */
+    private void rehash() {
+	int oldCapacity = table.length;
+	Entry oldMap[] = table;
+
+	int newCapacity = oldCapacity * 2 + 1;
+	Entry newMap[] = new Entry[newCapacity];
+
+	threshold = (int)(newCapacity * loadFactor);
+	table = newMap;
+
+	/*
+	System.out.pr intln("rehash old=" + oldCapacity
+		+ ", new=" + newCapacity
+		+ ", thresh=" + threshold
+		+ ", count=" + count);
+	*/
+
+	for (int i = oldCapacity ; i-- > 0 ;) {
+	    for (Entry old = oldMap[i] ; old != null ; ) {
+		Entry e = old;
+		old = old.next;
+
+		int index = (e.hash & 0x7FFFFFFF) % newCapacity;
+		e.next = newMap[index];
+		newMap[index] = e;
+	    }
+	}
+    }
+
+    /**
+     * Maps the specified <code>key</code> to the specified 
+     * <code>value</code> in this hashtable. Neither the key nor the 
+     * value can be <code>null</code>. 
+     *
+     * <P>The value can be retrieved by calling the <code>get</code> method 
+     * with a key that is equal to the original key. 
+     */
+    public Object put(Object key, Object value) {
+	// Make sure the value is not null
+	if (value == null) {
+	    throw new NullPointerException();
+	}
+
+	// Makes sure the key is not already in the hashtable.
+	Entry tab[] = table;
+	int hash = key.hashCode();
+	int index = (hash & 0x7FFFFFFF) % tab.length;
+	for (Entry e = tab[index] ; e != null ; e = e.next) {
+	    // if ((e.hash == hash) && e.key.equals(key)) {
+	    if ((e.hash == hash) && (e.key == key)) {
+		Object old = e.value;
+		e.value = value;
+		return old;
+	    }
+	}
+
+	if (count >= threshold) {
+	    // Rehash the table if the threshold is exceeded
+	    rehash();
+
+            tab = table;
+            index = (hash & 0x7FFFFFFF) % tab.length;
+	} 
+
+	// Creates the new entry.
+	Entry e = new Entry(hash, key, value, tab[index]);
+	tab[index] = e;
+	count++;
+	return null;
+    }
+
+    public Object remove(Object key) {
+	Entry tab[] = table;
+	Entry prev=null;
+	int hash = key.hashCode();
+	int index = (hash & 0x7FFFFFFF) % tab.length;
+	if( dL > 0 ) d("Idx " + index +  " " + tab[index] );
+	for (Entry e = tab[index] ; e != null ; prev=e, e = e.next) {
+	    if( dL > 0 ) d("> " + prev + " " + e.next + " " + e + " " + e.key);
+	    if ((e.hash == hash) && e.key.equals(key)) {
+		if( prev!=null ) {
+		    prev.next=e.next;
+		} else {
+		    tab[index]=e.next;
+		}
+		if( dL > 0 ) d("Removing from list " + tab[index] + " " + prev +
+			       " " + e.value);
+		count--;
+		Object res=e.value;
+		e.value=null;
+		return res;
+	    }
+	}
+	return null;
+    }
+
+    /**
+     * Hashtable collision list.
+     */
+    private static class Entry {
+	int	hash;
+	Object	key;
+	Object	value;
+	Entry	next;
+
+	protected Entry(int hash, Object key, Object value, Entry next) {
+	    this.hash = hash;
+	    this.key = key;
+	    this.value = value;
+	    this.next = next;
+	}
+    }
+
+    private static final int dL=0;
+    private void d(String s ) {
+	if (log.isDebugEnabled())
+            log.debug( "SimpleHashtable: " + s );
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/collections/SimplePool.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/collections/SimplePool.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/collections/SimplePool.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,127 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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;
+
+/**
+ * Simple object pool. Based on ThreadPool and few other classes
+ *
+ * The pool will ignore overflow and return null if empty.
+ *
+ * @author Gal Shachor
+ * @author Costin Manolache
+ */
+public final class SimplePool  {
+    
+    
+    private static org.apache.commons.logging.Log log=
+        org.apache.commons.logging.LogFactory.getLog(SimplePool.class );
+    
+    /*
+     * Where the threads are held.
+     */
+    private Object pool[];
+
+    private int max;
+    private int last;
+    private int current=-1;
+    
+    private Object lock;
+    public static final int DEFAULT_SIZE=32;
+    static final int debug=0;
+    
+    public SimplePool() {
+	this(DEFAULT_SIZE,DEFAULT_SIZE);
+    }
+
+    public SimplePool(int size) {
+	this(size, size);
+    }
+
+    public SimplePool(int size, int max) {
+	this.max=max;
+	pool=new Object[size];
+	this.last=size-1;
+	lock=new Object();
+    }
+
+    public  void set(Object o) {
+	put(o);
+    }
+
+    /**
+     * Add the object to the pool, silent nothing if the pool is full
+     */
+    public  void put(Object o) {
+	synchronized( lock ) {
+	    if( current < last ) {
+		current++;
+		pool[current] = o;
+            } else if( current < max ) {
+		// realocate
+		int newSize=pool.length*2;
+		if( newSize > max ) newSize=max+1;
+		Object tmp[]=new Object[newSize];
+		last=newSize-1;
+		System.arraycopy( pool, 0, tmp, 0, pool.length);
+		pool=tmp;
+		current++;
+		pool[current] = o;
+	    }
+	    if( debug > 0 ) log("put " + o + " " + current + " " + max );
+	}
+    }
+
+    /**
+     * Get an object from the pool, null if the pool is empty.
+     */
+    public  Object get() {
+	Object item = null;
+	synchronized( lock ) {
+	    if( current >= 0 ) {
+		item = pool[current];
+		pool[current] = null;
+		current -= 1;
+	    }
+	    if( debug > 0 ) 
+		log("get " + item + " " + current + " " + max);
+	}
+	return item;
+    }
+
+    /**
+     * Return the size of the pool
+     */
+    public int getMax() {
+	return max;
+    }
+
+    /**
+     * Number of object in the pool
+     */
+    public int getCount() {
+	return current+1;
+    }
+
+
+    public void shutdown() {
+    }
+    
+    private void log( String s ) {
+        if (log.isDebugEnabled())
+            log.debug("SimplePool: " + s );
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/collections/package.html
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/collections/package.html	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/collections/package.html	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,17 @@
+<html>
+<head>
+<title>util.collections</title>
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+</head>
+
+<body bgcolor="#FFFFFF">
+<h1>Specialized collections</h1>
+
+This package includes a number of special collections, tunned for server-side
+applications. 
+
+The utils are not tomcat specific, but use MessageBytes and few other 
+top-level utils.
+
+</body>
+</html>

Added: branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/compat/Jdk14Compat.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/compat/Jdk14Compat.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/compat/Jdk14Compat.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,120 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.compat;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URL;
+
+//import org.apache.commons.logging.Log;
+//import org.apache.commons.logging.LogFactory;
+
+
+/**
+ *  See JdkCompat. This is an extension of that class for Jdk1.4 support.
+ *
+ * @author Tim Funk
+ * @author Remy Maucherat
+ */
+public class Jdk14Compat extends JdkCompat {
+    // -------------------------------------------------------------- Constants
+
+    // ------------------------------------------------------- Static Variables
+    //static Log logger = LogFactory.getLog(Jdk14Compat.class);
+
+    // ----------------------------------------------------------- Constructors
+    /**
+     *  Default no-arg constructor
+     */
+    protected Jdk14Compat() {
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+    /**
+     *  Return the URI for the given file. Originally created for
+     *  o.a.c.loader.WebappClassLoader
+     *
+     * @param file The file to wrap into URI
+     * @return A URI as a URL
+     * @throws MalformedURLException Doh ;)
+     */
+    public URL getURI(File file)
+        throws MalformedURLException {
+
+        File realFile = file;
+        try {
+            realFile = realFile.getCanonicalFile();
+        } catch (IOException e) {
+            // Ignore
+        }
+
+        return realFile.toURI().toURL();
+    }
+
+
+    /**
+     *  Return the maximum amount of memory the JVM will attempt to use.
+     */
+    public long getMaxMemory() {
+        return Runtime.getRuntime().maxMemory();
+    }
+
+
+    /**
+     * Print out a partial servlet stack trace (truncating at the last 
+     * occurrence of javax.servlet.).
+     */
+    public String getPartialServletStackTrace(Throwable t) {
+        StringBuffer trace = new StringBuffer();
+        trace.append(t.toString()).append('\n');
+        StackTraceElement[] elements = t.getStackTrace();
+        int pos = elements.length;
+        for (int i = 0; i < elements.length; i++) {
+            if ((elements[i].getClassName().startsWith
+                 ("org.apache.catalina.core.ApplicationFilterChain"))
+                && (elements[i].getMethodName().equals("internalDoFilter"))) {
+                pos = i;
+            }
+        }
+        for (int i = 0; i < pos; i++) {
+            if (!(elements[i].getClassName().startsWith
+                  ("org.apache.catalina.core."))) {
+                trace.append('\t').append(elements[i].toString()).append('\n');
+            }
+        }
+        return trace.toString();
+    }
+
+    public  String [] split(String path, String pat) {
+        return path.split(pat);
+    }
+
+
+    /**
+     * Chains the <tt>wrapped</tt> throwable to the <tt>wrapper</tt> throwable.
+     *
+     * @param wrapper The wrapper throwable 
+     * @param wrapped The throwable to be wrapped
+     */
+    public void chainException(Throwable wrapper, Throwable wrapped) {
+        wrapper.initCause(wrapped);
+    }
+
+ }

Added: branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/compat/JdkCompat.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/compat/JdkCompat.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/compat/JdkCompat.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,221 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.compat;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.Vector;
+
+
+/**
+ *  General-purpose utility to provide backward-compatibility and JDK
+ *  independence. This allow use of JDK1.3 ( or higher ) facilities if
+ *  available, while maintaining the code compatible with older VMs.
+ *
+ *  The goal is to make backward-compatiblity reasonably easy.
+ *
+ *  The base class supports JDK1.3 behavior.
+ *
+ *  @author Tim Funk
+ */
+public class JdkCompat {
+
+    // ------------------------------------------------------- Static Variables
+
+    /**
+     * class providing java2 support
+     */
+    static final String JAVA14_SUPPORT =
+        "org.apache.tomcat.util.compat.Jdk14Compat";
+
+    /** Return java version as a string
+     */
+    public static String getJavaVersion() {
+        return javaVersion;
+    }
+
+    public static boolean isJava2() {
+        return java2;
+    } 
+   
+    public static boolean isJava14() {
+        return java14;
+    }
+
+    public static boolean isJava15() {
+        return java15;
+    }
+
+    // -------------------- Implementation --------------------
+    
+    // from ant
+    public static final String JAVA_1_0 = "1.0";
+    public static final String JAVA_1_1 = "1.1";
+    public static final String JAVA_1_2 = "1.2";
+    public static final String JAVA_1_3 = "1.3";
+    public static final String JAVA_1_4 = "1.4";
+    public static final String JAVA_1_5 = "1.5";
+
+    static String javaVersion;
+    static boolean java2=false;
+    static boolean java14=false;
+    static boolean java15=false;
+    static JdkCompat jdkCompat;
+    
+    static {
+        init();
+    }
+
+    private static void init() {
+        try {
+            javaVersion = JAVA_1_0;
+            Class.forName("java.lang.Void");
+            javaVersion = JAVA_1_1;
+            Class.forName("java.lang.ThreadLocal");
+            java2=true;
+            javaVersion = JAVA_1_2;
+            Class.forName("java.lang.StrictMath");
+            javaVersion = JAVA_1_3;
+            Class.forName("java.lang.CharSequence");
+            javaVersion = JAVA_1_4;
+            java14=true;
+            Class.forName("java.lang.Appendable");
+            javaVersion = JAVA_1_5;
+            java15=true;
+        } catch (ClassNotFoundException cnfe) {
+            // swallow as we've hit the max class version that we have
+        }
+        if( java14 ) {
+            try {
+                Class c=Class.forName(JAVA14_SUPPORT);
+                jdkCompat=(JdkCompat)c.newInstance();
+            } catch( Exception ex ) {
+                jdkCompat=new JdkCompat();
+            }
+        } else {
+            jdkCompat=new JdkCompat();
+            // Install jar handler if none installed
+        }
+    }
+
+    // ----------------------------------------------------------- Constructors
+    /**
+     *  Default no-arg constructor
+     */
+    protected JdkCompat() {
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+    /**
+     * Get a compatibiliy helper class.
+     */
+    public static JdkCompat getJdkCompat() {
+        return jdkCompat;
+    }
+
+    /**
+     *  Return the URI for the given file. Originally created for
+     *  o.a.c.loader.WebappClassLoader
+     *
+     * @param file The file to wrap into URI
+     * @return A URI as a URL
+     * @throws MalformedURLException Doh ;)
+     */
+    public URL getURI(File file)
+        throws MalformedURLException {
+
+        File realFile = file;
+        try {
+            realFile = realFile.getCanonicalFile();
+        } catch (IOException e) {
+            // Ignore
+        }
+
+        return realFile.toURL();
+    }
+
+
+    /**
+     *  Return the maximum amount of memory the JVM will attempt to use.
+     */
+    public long getMaxMemory() {
+        return (-1L);
+    }
+
+
+    /**
+     * Print out a partial servlet stack trace (truncating at the last 
+     * occurrence of javax.servlet.).
+     */
+    public String getPartialServletStackTrace(Throwable t) {
+        StringWriter stackTrace = new StringWriter();
+        t.printStackTrace(new PrintWriter(stackTrace));
+        String st = stackTrace.toString();
+        int i = st.lastIndexOf
+            ("org.apache.catalina.core.ApplicationFilterChain.internalDoFilter");
+        if (i > -1) {
+            return st.substring(0, i - 4);
+        } else {
+            return st;
+        }
+    }
+
+    /**
+     * Splits a string into it's components.
+     * @param path String to split
+     * @param pat Pattern to split at
+     * @return the components of the path
+     */
+    public  String [] split(String path, String pat) {
+        Vector comps = new Vector();
+        int pos = path.indexOf(pat);
+        int start = 0;
+        while( pos >= 0 ) {
+            if(pos > start ) {
+                String comp = path.substring(start,pos);
+                comps.add(comp);
+            }
+            start = pos + pat.length();
+            pos = path.indexOf(pat,start);
+        }
+        if( start < path.length()) {
+            comps.add(path.substring(start));
+        }
+        String [] result = new String[comps.size()];
+        for(int i=0; i < comps.size(); i++) {
+            result[i] = (String)comps.elementAt(i);
+        }
+        return result;
+    }
+
+
+    /**
+     * Chains the <tt>wrapped</tt> throwable to the <tt>wrapper</tt> throwable.
+     *
+     * @param wrapper The wrapper throwable 
+     * @param wrapped The throwable to be wrapped
+     */
+    public void chainException(Throwable wrapper, Throwable wrapped) {
+        // do nothing
+    }
+
+ }

Added: branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/digester/AbstractObjectCreationFactory.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/digester/AbstractObjectCreationFactory.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/digester/AbstractObjectCreationFactory.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,78 @@
+/* $Id: AbstractObjectCreationFactory.java 299475 2004-06-26 17:41:32Z remm $
+ *
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.digester;
+
+
+import org.xml.sax.Attributes;
+
+
+/**
+ * <p>Abstract base class for <code>ObjectCreationFactory</code>
+ * implementations.</p>
+ */
+abstract public class AbstractObjectCreationFactory implements ObjectCreationFactory {
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The associated <code>Digester</code> instance that was set up by
+     * {@link FactoryCreateRule} upon initialization.
+     */
+    protected Digester digester = null;
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * <p>Factory method called by {@link FactoryCreateRule} to supply an
+     * object based on the element's attributes.
+     *
+     * @param attributes the element's attributes
+     *
+     * @throws Exception any exception thrown will be propagated upwards
+     */
+    public abstract Object createObject(Attributes attributes) throws Exception;
+
+
+    /**
+     * <p>Returns the {@link Digester} that was set by the
+     * {@link FactoryCreateRule} upon initialization.
+     */
+    public Digester getDigester() {
+
+        return (this.digester);
+
+    }
+
+
+    /**
+     * <p>Set the {@link Digester} to allow the implementation to do logging,
+     * classloading based on the digester's classloader, etc.
+     *
+     * @param digester parent Digester object
+     */
+    public void setDigester(Digester digester) {
+
+        this.digester = digester;
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/digester/AbstractRulesImpl.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/digester/AbstractRulesImpl.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/digester/AbstractRulesImpl.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,166 @@
+/* $Id: AbstractRulesImpl.java 299475 2004-06-26 17:41:32Z remm $
+ *
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.digester;
+
+
+import java.util.List;
+
+
+/**
+ * <p><code>AbstractRuleImpl</code> provides basic services for <code>Rules</code> implementations.
+ * Extending this class should make it easier to create a <code>Rules</code> implementation.</p>
+ * 
+ * <p><code>AbstractRuleImpl</code> manages the <code>Digester</code> 
+ * and <code>namespaceUri</code> properties.
+ * If the subclass overrides {@link #registerRule} (rather than {@link #add}),
+ * then the <code>Digester</code> and <code>namespaceURI</code> of the <code>Rule</code>
+ * will be set correctly before it is passed to <code>registerRule</code>.
+ * The subclass can then perform whatever it needs to do to register the rule.</p>
+ *
+ * @since 1.5
+ */
+
+abstract public class AbstractRulesImpl implements Rules {
+
+    // ------------------------------------------------------------- Fields
+    
+    /** Digester using this <code>Rules</code> implementation */
+    private Digester digester;
+    /** Namespace uri to assoicate with subsequent <code>Rule</code>'s */
+    private String namespaceURI;
+    
+    // ------------------------------------------------------------- Properties
+
+    /**
+     * Return the Digester instance with which this Rules instance is
+     * associated.
+     */
+    public Digester getDigester() {
+        return digester;
+    }
+
+    /**
+     * Set the Digester instance with which this Rules instance is associated.
+     *
+     * @param digester The newly associated Digester instance
+     */
+    public void setDigester(Digester digester) {
+        this.digester = digester;
+    }
+
+    /**
+     * Return the namespace URI that will be applied to all subsequently
+     * added <code>Rule</code> objects.
+     */
+    public String getNamespaceURI() {
+        return namespaceURI;
+    }
+
+    /**
+     * Set the namespace URI that will be applied to all subsequently
+     * added <code>Rule</code> objects.
+     *
+     * @param namespaceURI Namespace URI that must match on all
+     *  subsequently added rules, or <code>null</code> for matching
+     *  regardless of the current namespace URI
+     */
+    public void setNamespaceURI(String namespaceURI) {
+        this.namespaceURI = namespaceURI;
+    }
+
+    // --------------------------------------------------------- Public Methods
+
+    /**
+     * Registers a new Rule instance matching the specified pattern.
+     * This implementation sets the <code>Digester</code> and the
+     * <code>namespaceURI</code> on the <code>Rule</code> before calling {@link #registerRule}.
+     *
+     * @param pattern Nesting pattern to be matched for this Rule
+     * @param rule Rule instance to be registered
+     */
+    public void add(String pattern, Rule rule) {
+        // set up rule
+        if (this.digester != null) {
+            rule.setDigester(this.digester);
+        }
+        
+        if (this.namespaceURI != null) {
+            rule.setNamespaceURI(this.namespaceURI);
+        }
+        
+        registerRule(pattern, rule);
+        
+    }
+    
+    /** 
+     * Register rule at given pattern.
+     * The the Digester and namespaceURI properties of the given <code>Rule</code>
+     * can be assumed to have been set properly before this method is called.
+     *
+     * @param pattern Nesting pattern to be matched for this Rule
+     * @param rule Rule instance to be registered
+     */ 
+    abstract protected void registerRule(String pattern, Rule rule);
+
+    /**
+     * Clear all existing Rule instance registrations.
+     */
+    abstract public void clear();
+
+
+    /**
+     * Return a List of all registered Rule instances that match the specified
+     * nesting pattern, or a zero-length List if there are no matches.  If more
+     * than one Rule instance matches, they <strong>must</strong> be returned
+     * in the order originally registered through the <code>add()</code>
+     * method.
+     *
+     * @param pattern Nesting pattern to be matched
+     *
+     * @deprecated Call match(namespaceURI,pattern) instead.
+     */
+    public List match(String pattern) {
+        return match(namespaceURI, pattern);
+    }
+
+
+    /**
+     * Return a List of all registered Rule instances that match the specified
+     * nesting pattern, or a zero-length List if there are no matches.  If more
+     * than one Rule instance matches, they <strong>must</strong> be returned
+     * in the order originally registered through the <code>add()</code>
+     * method.
+     *
+     * @param namespaceURI Namespace URI for which to select matching rules,
+     *  or <code>null</code> to match regardless of namespace URI
+     * @param pattern Nesting pattern to be matched
+     */
+    abstract public List match(String namespaceURI, String pattern);
+
+
+    /**
+     * Return a List of all registered Rule instances, or a zero-length List
+     * if there are no registered Rule instances.  If more than one Rule
+     * instance has been registered, they <strong>must</strong> be returned
+     * in the order originally registered through the <code>add()</code>
+     * method.
+     */
+    abstract public List rules();
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/digester/ArrayStack.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/digester/ArrayStack.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/digester/ArrayStack.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,168 @@
+/* $Id: ArrayStack.java 299475 2004-06-26 17:41:32Z remm $
+ *
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.digester;
+
+import java.util.ArrayList;
+import java.util.EmptyStackException;
+
+/**
+ * <p>Imported copy of the <code>ArrayStack</code> class from
+ * Commons Collections, which was the only direct dependency from Digester.</p>
+ *
+ * <p><strong>WARNNG</strong> - This class is public solely to allow it to be
+ * used from subpackages of <code>org.apache.commons.digester</code>.
+ * It should not be considered part of the public API of Commons Digester.
+ * If you want to use such a class yourself, you should use the one from
+ * Commons Collections directly.</p>
+ *
+ * <p>An implementation of the {@link java.util.Stack} API that is based on an
+ * <code>ArrayList</code> instead of a <code>Vector</code>, so it is not
+ * synchronized to protect against multi-threaded access.  The implementation
+ * is therefore operates faster in environments where you do not need to
+ * worry about multiple thread contention.</p>
+ *
+ * <p>Unlike <code>Stack</code>, <code>ArrayStack</code> accepts null entries.
+ * </p>
+ *
+ * @see java.util.Stack
+ * @since Digester 1.6 (from Commons Collections 1.0)
+ */
+public class ArrayStack extends ArrayList {
+
+    /** Ensure serialization compatibility */    
+    private static final long serialVersionUID = 2130079159931574599L;
+
+    /**
+     * Constructs a new empty <code>ArrayStack</code>. The initial size
+     * is controlled by <code>ArrayList</code> and is currently 10.
+     */
+    public ArrayStack() {
+        super();
+    }
+
+    /**
+     * Constructs a new empty <code>ArrayStack</code> with an initial size.
+     * 
+     * @param initialSize  the initial size to use
+     * @throws IllegalArgumentException  if the specified initial size
+     *  is negative
+     */
+    public ArrayStack(int initialSize) {
+        super(initialSize);
+    }
+
+    /**
+     * Return <code>true</code> if this stack is currently empty.
+     * <p>
+     * This method exists for compatibility with <code>java.util.Stack</code>.
+     * New users of this class should use <code>isEmpty</code> instead.
+     * 
+     * @return true if the stack is currently empty
+     */
+    public boolean empty() {
+        return isEmpty();
+    }
+
+    /**
+     * Returns the top item off of this stack without removing it.
+     *
+     * @return the top item on the stack
+     * @throws EmptyStackException  if the stack is empty
+     */
+    public Object peek() throws EmptyStackException {
+        int n = size();
+        if (n <= 0) {
+            throw new EmptyStackException();
+        } else {
+            return get(n - 1);
+        }
+    }
+
+    /**
+     * Returns the n'th item down (zero-relative) from the top of this
+     * stack without removing it.
+     *
+     * @param n  the number of items down to go
+     * @return the n'th item on the stack, zero relative
+     * @throws EmptyStackException  if there are not enough items on the
+     *  stack to satisfy this request
+     */
+    public Object peek(int n) throws EmptyStackException {
+        int m = (size() - n) - 1;
+        if (m < 0) {
+            throw new EmptyStackException();
+        } else {
+            return get(m);
+        }
+    }
+
+    /**
+     * Pops the top item off of this stack and return it.
+     *
+     * @return the top item on the stack
+     * @throws EmptyStackException  if the stack is empty
+     */
+    public Object pop() throws EmptyStackException {
+        int n = size();
+        if (n <= 0) {
+            throw new EmptyStackException();
+        } else {
+            return remove(n - 1);
+        }
+    }
+
+    /**
+     * Pushes a new item onto the top of this stack. The pushed item is also
+     * returned. This is equivalent to calling <code>add</code>.
+     *
+     * @param item  the item to be added
+     * @return the item just pushed
+     */
+    public Object push(Object item) {
+        add(item);
+        return item;
+    }
+
+
+    /**
+     * Returns the one-based position of the distance from the top that the
+     * specified object exists on this stack, where the top-most element is
+     * considered to be at distance <code>1</code>.  If the object is not
+     * present on the stack, return <code>-1</code> instead.  The
+     * <code>equals()</code> method is used to compare to the items
+     * in this stack.
+     *
+     * @param object  the object to be searched for
+     * @return the 1-based depth into the stack of the object, or -1 if not found
+     */
+    public int search(Object object) {
+        int i = size() - 1;        // Current index
+        int n = 1;                 // Current distance
+        while (i >= 0) {
+            Object current = get(i);
+            if ((object == null && current == null) ||
+                (object != null && object.equals(current))) {
+                return n;
+            }
+            i--;
+            n++;
+        }
+        return -1;
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/digester/CallMethodRule.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/digester/CallMethodRule.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/digester/CallMethodRule.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,629 @@
+/* $Id: CallMethodRule.java 299765 2004-08-31 23:52:52Z yoavs $
+ *
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.digester;
+
+
+import org.apache.tomcat.util.IntrospectionUtils;
+import org.xml.sax.Attributes;
+
+
+/**
+ * <p>Rule implementation that calls a method on an object on the stack
+ * (normally the top/parent object), passing arguments collected from 
+ * subsequent <code>CallParamRule</code> rules or from the body of this
+ * element. </p>
+ *
+ * <p>By using {@link #CallMethodRule(String methodName)} 
+ * a method call can be made to a method which accepts no
+ * arguments.</p>
+ *
+ * <p>Incompatible method parameter types are converted 
+ * using <code>org.apache.commons.beanutils.ConvertUtils</code>.
+ * </p>
+ *
+ * <p>This rule now uses
+ * <a href="http://jakarta.apache.org/commons/beanutils/apidocs/org/apache/commons/beanutils/MethodUtils.html">
+ * org.apache.commons.beanutils.MethodUtils#invokeMethod
+ * </a> by default.
+ * This increases the kinds of methods successfully and allows primitives
+ * to be matched by passing in wrapper classes.
+ * There are rare cases when org.apache.commons.beanutils.MethodUtils#invokeExactMethod 
+ * (the old default) is required.
+ * This method is much stricter in its reflection.
+ * Setting the <code>UseExactMatch</code> to true reverts to the use of this 
+ * method.</p>
+ *
+ * <p>Note that the target method is invoked when the  <i>end</i> of
+ * the tag the CallMethodRule fired on is encountered, <i>not</i> when the
+ * last parameter becomes available. This implies that rules which fire on
+ * tags nested within the one associated with the CallMethodRule will 
+ * fire before the CallMethodRule invokes the target method. This behaviour is
+ * not configurable. </p>
+ *
+ * <p>Note also that if a CallMethodRule is expecting exactly one parameter
+ * and that parameter is not available (eg CallParamRule is used with an
+ * attribute name but the attribute does not exist) then the method will
+ * not be invoked. If a CallMethodRule is expecting more than one parameter,
+ * then it is always invoked, regardless of whether the parameters were
+ * available or not (missing parameters are passed as null values).</p>
+ */
+
+public class CallMethodRule extends Rule {
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Construct a "call method" rule with the specified method name.  The
+     * parameter types (if any) default to java.lang.String.
+     *
+     * @param digester The associated Digester
+     * @param methodName Method name of the parent method to call
+     * @param paramCount The number of parameters to collect, or
+     *  zero for a single argument from the body of this element.
+     *
+     *
+     * @deprecated The digester instance is now set in the {@link Digester#addRule} method. 
+     * Use {@link #CallMethodRule(String methodName,int paramCount)} instead.
+     */
+    public CallMethodRule(Digester digester, String methodName,
+                          int paramCount) {
+
+        this(methodName, paramCount);
+
+    }
+
+
+    /**
+     * Construct a "call method" rule with the specified method name.
+     *
+     * @param digester The associated Digester
+     * @param methodName Method name of the parent method to call
+     * @param paramCount The number of parameters to collect, or
+     *  zero for a single argument from the body of ths element
+     * @param paramTypes The Java class names of the arguments
+     *  (if you wish to use a primitive type, specify the corresonding
+     *  Java wrapper class instead, such as <code>java.lang.Boolean</code>
+     *  for a <code>boolean</code> parameter)
+     *
+     * @deprecated The digester instance is now set in the {@link Digester#addRule} method. 
+     * Use {@link #CallMethodRule(String methodName,int paramCount, String [] paramTypes)} instead.
+     */
+    public CallMethodRule(Digester digester, String methodName,
+                          int paramCount, String paramTypes[]) {
+
+        this(methodName, paramCount, paramTypes);
+
+    }
+
+
+    /**
+     * Construct a "call method" rule with the specified method name.
+     *
+     * @param digester The associated Digester
+     * @param methodName Method name of the parent method to call
+     * @param paramCount The number of parameters to collect, or
+     *  zero for a single argument from the body of ths element
+     * @param paramTypes The Java classes that represent the
+     *  parameter types of the method arguments
+     *  (if you wish to use a primitive type, specify the corresonding
+     *  Java wrapper class instead, such as <code>java.lang.Boolean.TYPE</code>
+     *  for a <code>boolean</code> parameter)
+     *
+     * @deprecated The digester instance is now set in the {@link Digester#addRule} method. 
+     * Use {@link #CallMethodRule(String methodName,int paramCount, Class [] paramTypes)} instead.
+     */
+    public CallMethodRule(Digester digester, String methodName,
+                          int paramCount, Class paramTypes[]) {
+
+        this(methodName, paramCount, paramTypes);
+    }
+
+
+    /**
+     * Construct a "call method" rule with the specified method name.  The
+     * parameter types (if any) default to java.lang.String.
+     *
+     * @param methodName Method name of the parent method to call
+     * @param paramCount The number of parameters to collect, or
+     *  zero for a single argument from the body of this element.
+     */
+    public CallMethodRule(String methodName,
+                          int paramCount) {
+        this(0, methodName, paramCount);
+    }
+
+    /**
+     * Construct a "call method" rule with the specified method name.  The
+     * parameter types (if any) default to java.lang.String.
+     *
+     * @param targetOffset location of the target object. Positive numbers are
+     * relative to the top of the digester object stack. Negative numbers 
+     * are relative to the bottom of the stack. Zero implies the top
+     * object on the stack.
+     * @param methodName Method name of the parent method to call
+     * @param paramCount The number of parameters to collect, or
+     *  zero for a single argument from the body of this element.
+     */
+    public CallMethodRule(int targetOffset,
+                          String methodName,
+                          int paramCount) {
+
+        this.targetOffset = targetOffset;
+        this.methodName = methodName;
+        this.paramCount = paramCount;        
+        if (paramCount == 0) {
+            this.paramTypes = new Class[] { String.class };
+        } else {
+            this.paramTypes = new Class[paramCount];
+            for (int i = 0; i < this.paramTypes.length; i++) {
+                this.paramTypes[i] = String.class;
+            }
+        }
+
+    }
+
+    /**
+     * Construct a "call method" rule with the specified method name.  
+     * The method should accept no parameters.
+     *
+     * @param methodName Method name of the parent method to call
+     */
+    public CallMethodRule(String methodName) {
+    
+        this(0, methodName, 0, (Class[]) null);
+    
+    }
+    
+
+    /**
+     * Construct a "call method" rule with the specified method name.  
+     * The method should accept no parameters.
+     *
+     * @param targetOffset location of the target object. Positive numbers are
+     * relative to the top of the digester object stack. Negative numbers 
+     * are relative to the bottom of the stack. Zero implies the top
+     * object on the stack.
+     * @param methodName Method name of the parent method to call
+     */
+    public CallMethodRule(int targetOffset, String methodName) {
+    
+        this(targetOffset, methodName, 0, (Class[]) null);
+    
+    }
+    
+
+    /**
+     * Construct a "call method" rule with the specified method name and
+     * parameter types. If <code>paramCount</code> is set to zero the rule
+     * will use the body of this element as the single argument of the
+     * method, unless <code>paramTypes</code> is null or empty, in this
+     * case the rule will call the specified method with no arguments.
+     *
+     * @param methodName Method name of the parent method to call
+     * @param paramCount The number of parameters to collect, or
+     *  zero for a single argument from the body of ths element
+     * @param paramTypes The Java class names of the arguments
+     *  (if you wish to use a primitive type, specify the corresonding
+     *  Java wrapper class instead, such as <code>java.lang.Boolean</code>
+     *  for a <code>boolean</code> parameter)
+     */
+    public CallMethodRule(
+                            String methodName,
+                            int paramCount, 
+                            String paramTypes[]) {
+        this(0, methodName, paramCount, paramTypes);
+    }
+
+    /**
+     * Construct a "call method" rule with the specified method name and
+     * parameter types. If <code>paramCount</code> is set to zero the rule
+     * will use the body of this element as the single argument of the
+     * method, unless <code>paramTypes</code> is null or empty, in this
+     * case the rule will call the specified method with no arguments.
+     *
+     * @param targetOffset location of the target object. Positive numbers are
+     * relative to the top of the digester object stack. Negative numbers 
+     * are relative to the bottom of the stack. Zero implies the top
+     * object on the stack.
+     * @param methodName Method name of the parent method to call
+     * @param paramCount The number of parameters to collect, or
+     *  zero for a single argument from the body of ths element
+     * @param paramTypes The Java class names of the arguments
+     *  (if you wish to use a primitive type, specify the corresonding
+     *  Java wrapper class instead, such as <code>java.lang.Boolean</code>
+     *  for a <code>boolean</code> parameter)
+     */
+    public CallMethodRule(  int targetOffset,
+                            String methodName,
+                            int paramCount, 
+                            String paramTypes[]) {
+
+        this.targetOffset = targetOffset;
+        this.methodName = methodName;
+        this.paramCount = paramCount;
+        if (paramTypes == null) {
+            this.paramTypes = new Class[paramCount];
+            for (int i = 0; i < this.paramTypes.length; i++) {
+                this.paramTypes[i] = "abc".getClass();
+            }
+        } else {
+            // copy the parameter class names into an array
+            // the classes will be loaded when the digester is set 
+            this.paramClassNames = new String[paramTypes.length];
+            for (int i = 0; i < this.paramClassNames.length; i++) {
+                this.paramClassNames[i] = paramTypes[i];
+            }
+        }
+
+    }
+
+
+    /**
+     * Construct a "call method" rule with the specified method name and
+     * parameter types. If <code>paramCount</code> is set to zero the rule
+     * will use the body of this element as the single argument of the
+     * method, unless <code>paramTypes</code> is null or empty, in this
+     * case the rule will call the specified method with no arguments.
+     *
+     * @param methodName Method name of the parent method to call
+     * @param paramCount The number of parameters to collect, or
+     *  zero for a single argument from the body of ths element
+     * @param paramTypes The Java classes that represent the
+     *  parameter types of the method arguments
+     *  (if you wish to use a primitive type, specify the corresonding
+     *  Java wrapper class instead, such as <code>java.lang.Boolean.TYPE</code>
+     *  for a <code>boolean</code> parameter)
+     */
+    public CallMethodRule(
+                            String methodName,
+                            int paramCount, 
+                            Class paramTypes[]) {
+        this(0, methodName, paramCount, paramTypes);
+    }
+
+    /**
+     * Construct a "call method" rule with the specified method name and
+     * parameter types. If <code>paramCount</code> is set to zero the rule
+     * will use the body of this element as the single argument of the
+     * method, unless <code>paramTypes</code> is null or empty, in this
+     * case the rule will call the specified method with no arguments.
+     *
+     * @param targetOffset location of the target object. Positive numbers are
+     * relative to the top of the digester object stack. Negative numbers 
+     * are relative to the bottom of the stack. Zero implies the top
+     * object on the stack.
+     * @param methodName Method name of the parent method to call
+     * @param paramCount The number of parameters to collect, or
+     *  zero for a single argument from the body of ths element
+     * @param paramTypes The Java classes that represent the
+     *  parameter types of the method arguments
+     *  (if you wish to use a primitive type, specify the corresonding
+     *  Java wrapper class instead, such as <code>java.lang.Boolean.TYPE</code>
+     *  for a <code>boolean</code> parameter)
+     */
+    public CallMethodRule(  int targetOffset,
+                            String methodName,
+                            int paramCount, 
+                            Class paramTypes[]) {
+
+        this.targetOffset = targetOffset;
+        this.methodName = methodName;
+        this.paramCount = paramCount;
+        if (paramTypes == null) {
+            this.paramTypes = new Class[paramCount];
+            for (int i = 0; i < this.paramTypes.length; i++) {
+                this.paramTypes[i] = "abc".getClass();
+            }
+        } else {
+            this.paramTypes = new Class[paramTypes.length];
+            for (int i = 0; i < this.paramTypes.length; i++) {
+                this.paramTypes[i] = paramTypes[i];
+            }
+        }
+
+    }
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The body text collected from this element.
+     */
+    protected String bodyText = null;
+
+
+    /** 
+     * location of the target object for the call, relative to the
+     * top of the digester object stack. The default value of zero
+     * means the target object is the one on top of the stack.
+     */
+    private int targetOffset = 0;
+
+    /**
+     * The method name to call on the parent object.
+     */
+    protected String methodName = null;
+
+
+    /**
+     * The number of parameters to collect from <code>MethodParam</code> rules.
+     * If this value is zero, a single parameter will be collected from the
+     * body of this element.
+     */
+    protected int paramCount = 0;
+
+
+    /**
+     * The parameter types of the parameters to be collected.
+     */
+    protected Class paramTypes[] = null;
+
+    /**
+     * The names of the classes of the parameters to be collected.
+     * This attribute allows creation of the classes to be postponed until the digester is set.
+     */
+    private String paramClassNames[] = null;
+    
+    /**
+     * Should <code>MethodUtils.invokeExactMethod</code> be used for reflection.
+     */
+    protected boolean useExactMatch = false;
+    
+    // --------------------------------------------------------- Public Methods
+    
+    /**
+     * Should <code>MethodUtils.invokeExactMethod</code>
+     * be used for the reflection.
+     */
+    public boolean getUseExactMatch() {
+        return useExactMatch;
+    }
+    
+    /**
+     * Set whether <code>MethodUtils.invokeExactMethod</code>
+     * should be used for the reflection.
+     */    
+    public void setUseExactMatch(boolean useExactMatch)
+    { 
+        this.useExactMatch = useExactMatch;
+    }
+
+    /**
+     * Set the associated digester.
+     * If needed, this class loads the parameter classes from their names.
+     */
+    public void setDigester(Digester digester)
+    {
+        // call superclass
+        super.setDigester(digester);
+        // if necessary, load parameter classes
+        if (this.paramClassNames != null) {
+            this.paramTypes = new Class[paramClassNames.length];
+            for (int i = 0; i < this.paramClassNames.length; i++) {
+                try {
+                    this.paramTypes[i] =
+                            digester.getClassLoader().loadClass(this.paramClassNames[i]);
+                } catch (ClassNotFoundException e) {
+                    // use the digester log
+                    digester.getLogger().error("(CallMethodRule) Cannot load class " + this.paramClassNames[i], e);
+                    this.paramTypes[i] = null; // Will cause NPE later
+                }
+            }
+        }
+    }
+
+    /**
+     * Process the start of this element.
+     *
+     * @param attributes The attribute list for this element
+     */
+    public void begin(Attributes attributes) throws Exception {
+
+        // Push an array to capture the parameter values if necessary
+        if (paramCount > 0) {
+            Object parameters[] = new Object[paramCount];
+            for (int i = 0; i < parameters.length; i++) {
+                parameters[i] = null;
+            }
+            digester.pushParams(parameters);
+        }
+
+    }
+
+
+    /**
+     * Process the body text of this element.
+     *
+     * @param bodyText The body text of this element
+     */
+    public void body(String bodyText) throws Exception {
+
+        if (paramCount == 0) {
+            this.bodyText = bodyText.trim();
+        }
+
+    }
+
+
+    /**
+     * Process the end of this element.
+     */
+    public void end() throws Exception {
+
+        // Retrieve or construct the parameter values array
+        Object parameters[] = null;
+        if (paramCount > 0) {
+
+            parameters = (Object[]) digester.popParams();
+            
+            if (digester.log.isTraceEnabled()) {
+                for (int i=0,size=parameters.length;i<size;i++) {
+                    digester.log.trace("[CallMethodRule](" + i + ")" + parameters[i]) ;
+                }
+            }
+            
+            // In the case where the parameter for the method
+            // is taken from an attribute, and that attribute
+            // isn't actually defined in the source XML file,
+            // skip the method call
+            if (paramCount == 1 && parameters[0] == null) {
+                return;
+            }
+
+        } else if (paramTypes != null && paramTypes.length != 0) {
+
+            // In the case where the parameter for the method
+            // is taken from the body text, but there is no
+            // body text included in the source XML file,
+            // skip the method call
+            if (bodyText == null) {
+                return;
+            }
+
+            parameters = new Object[1];
+            parameters[0] = bodyText;
+            if (paramTypes.length == 0) {
+                paramTypes = new Class[1];
+                paramTypes[0] = "abc".getClass();
+            }
+
+        }
+
+        // Construct the parameter values array we will need
+        // We only do the conversion if the param value is a String and
+        // the specified paramType is not String. 
+        Object paramValues[] = new Object[paramTypes.length];
+        for (int i = 0; i < paramTypes.length; i++) {
+            // convert nulls and convert stringy parameters 
+            // for non-stringy param types
+            if(
+                parameters[i] == null ||
+                 (parameters[i] instanceof String && 
+                   !String.class.isAssignableFrom(paramTypes[i]))) {
+                
+                paramValues[i] =
+                        IntrospectionUtils.convert((String) parameters[i], paramTypes[i]);
+            } else {
+                paramValues[i] = parameters[i];
+            }
+        }
+
+        // Determine the target object for the method call
+        Object target;
+        if (targetOffset >= 0) {
+            target = digester.peek(targetOffset);
+        } else {
+            target = digester.peek( digester.getCount() + targetOffset );
+        }
+        
+        if (target == null) {
+            StringBuffer sb = new StringBuffer();
+            sb.append("[CallMethodRule]{");
+            sb.append(digester.match);
+            sb.append("} Call target is null (");
+            sb.append("targetOffset=");
+            sb.append(targetOffset);
+            sb.append(",stackdepth=");
+            sb.append(digester.getCount());
+            sb.append(")");
+            throw new org.xml.sax.SAXException(sb.toString());
+        }
+        
+        // Invoke the required method on the top object
+        if (digester.log.isDebugEnabled()) {
+            StringBuffer sb = new StringBuffer("[CallMethodRule]{");
+            sb.append(digester.match);
+            sb.append("} Call ");
+            sb.append(target.getClass().getName());
+            sb.append(".");
+            sb.append(methodName);
+            sb.append("(");
+            for (int i = 0; i < paramValues.length; i++) {
+                if (i > 0) {
+                    sb.append(",");
+                }
+                if (paramValues[i] == null) {
+                    sb.append("null");
+                } else {
+                    sb.append(paramValues[i].toString());
+                }
+                sb.append("/");
+                if (paramTypes[i] == null) {
+                    sb.append("null");
+                } else {
+                    sb.append(paramTypes[i].getName());
+                }
+            }
+            sb.append(")");
+            digester.log.debug(sb.toString());
+        }
+        Object result = IntrospectionUtils.callMethodN(target, methodName,
+                paramValues, paramTypes);   
+        processMethodCallResult(result);
+    }
+
+
+    /**
+     * Clean up after parsing is complete.
+     */
+    public void finish() throws Exception {
+
+        bodyText = null;
+
+    }
+
+    /**
+     * Subclasses may override this method to perform additional processing of the 
+     * invoked method's result.
+     *
+     * @param result the Object returned by the method invoked, possibly null
+     */
+    protected void processMethodCallResult(Object result) {
+        // do nothing
+    }
+
+    /**
+     * Render a printable version of this Rule.
+     */
+    public String toString() {
+
+        StringBuffer sb = new StringBuffer("CallMethodRule[");
+        sb.append("methodName=");
+        sb.append(methodName);
+        sb.append(", paramCount=");
+        sb.append(paramCount);
+        sb.append(", paramTypes={");
+        if (paramTypes != null) {
+            for (int i = 0; i < paramTypes.length; i++) {
+                if (i > 0) {
+                    sb.append(", ");
+                }
+                sb.append(paramTypes[i].getName());
+            }
+        }
+        sb.append("}");
+        sb.append("]");
+        return (sb.toString());
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/digester/CallParamRule.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/digester/CallParamRule.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/digester/CallParamRule.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,262 @@
+/* $Id: CallParamRule.java 299475 2004-06-26 17:41:32Z remm $
+ *
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.digester;
+
+
+import org.xml.sax.Attributes;
+
+
+/**
+ * <p>Rule implementation that saves a parameter for use by a surrounding 
+ * <code>CallMethodRule<code>.</p>
+ *
+ * <p>This parameter may be:
+ * <ul>
+ * <li>from an attribute of the current element
+ * See {@link #CallParamRule(int paramIndex, String attributeName)}
+ * <li>from current the element body
+ * See {@link #CallParamRule(int paramIndex)}
+ * <li>from the top object on the stack. 
+ * See {@link #CallParamRule(int paramIndex, boolean fromStack)}
+ * <li>the current path being processed (separate <code>Rule</code>). 
+ * See {@link PathCallParamRule}
+ * </ul>
+ * </p>
+ */
+
+public class CallParamRule extends Rule {
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Construct a "call parameter" rule that will save the body text of this
+     * element as the parameter value.
+     *
+     * @param digester The associated Digester
+     * @param paramIndex The zero-relative parameter number
+     *
+     * @deprecated The digester instance is now set in the {@link Digester#addRule} method. 
+     * Use {@link #CallParamRule(int paramIndex)} instead.
+     */
+    public CallParamRule(Digester digester, int paramIndex) {
+
+        this(paramIndex);
+
+    }
+
+
+    /**
+     * Construct a "call parameter" rule that will save the value of the
+     * specified attribute as the parameter value.
+     *
+     * @param digester The associated Digester
+     * @param paramIndex The zero-relative parameter number
+     * @param attributeName The name of the attribute to save
+     *
+     * @deprecated The digester instance is now set in the {@link Digester#addRule} method. 
+     * Use {@link #CallParamRule(int paramIndex, String attributeName)} instead.
+     */
+    public CallParamRule(Digester digester, int paramIndex,
+                         String attributeName) {
+
+        this(paramIndex, attributeName);
+
+    }
+
+    /**
+     * Construct a "call parameter" rule that will save the body text of this
+     * element as the parameter value.
+     *
+     * @param paramIndex The zero-relative parameter number
+     */
+    public CallParamRule(int paramIndex) {
+
+        this(paramIndex, null);
+
+    }
+
+
+    /**
+     * Construct a "call parameter" rule that will save the value of the
+     * specified attribute as the parameter value.
+     *
+     * @param paramIndex The zero-relative parameter number
+     * @param attributeName The name of the attribute to save
+     */
+    public CallParamRule(int paramIndex,
+                         String attributeName) {
+
+        this.paramIndex = paramIndex;
+        this.attributeName = attributeName;
+
+    }
+
+
+    /**
+     * Construct a "call parameter" rule.
+     *
+     * @param paramIndex The zero-relative parameter number
+     * @param fromStack should this parameter be taken from the top of the stack?
+     */    
+    public CallParamRule(int paramIndex, boolean fromStack) {
+    
+        this.paramIndex = paramIndex;  
+        this.fromStack = fromStack;
+
+    }
+    
+    /**
+     * Constructs a "call parameter" rule which sets a parameter from the stack.
+     * If the stack contains too few objects, then the parameter will be set to null.
+     *
+     * @param paramIndex The zero-relative parameter number
+     * @param stackIndex the index of the object which will be passed as a parameter. 
+     * The zeroth object is the top of the stack, 1 is the next object down and so on.
+     */    
+    public CallParamRule(int paramIndex, int stackIndex) {
+    
+        this.paramIndex = paramIndex;  
+        this.fromStack = true;
+        this.stackIndex = stackIndex;
+    }
+ 
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The attribute from which to save the parameter value
+     */
+    protected String attributeName = null;
+
+
+    /**
+     * The zero-relative index of the parameter we are saving.
+     */
+    protected int paramIndex = 0;
+
+
+    /**
+     * Is the parameter to be set from the stack?
+     */
+    protected boolean fromStack = false;
+    
+    /**
+     * The position of the object from the top of the stack
+     */
+    protected int stackIndex = 0;
+
+    /** 
+     * Stack is used to allow nested body text to be processed.
+     * Lazy creation.
+     */
+    protected ArrayStack bodyTextStack;
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Process the start of this element.
+     *
+     * @param attributes The attribute list for this element
+     */
+    public void begin(Attributes attributes) throws Exception {
+
+        Object param = null;
+        
+        if (attributeName != null) {
+        
+            param = attributes.getValue(attributeName);
+            
+        } else if(fromStack) {
+        
+            param = digester.peek(stackIndex);
+            
+            if (digester.log.isDebugEnabled()) {
+            
+                StringBuffer sb = new StringBuffer("[CallParamRule]{");
+                sb.append(digester.match);
+                sb.append("} Save from stack; from stack?").append(fromStack);
+                sb.append("; object=").append(param);
+                digester.log.debug(sb.toString());
+            }   
+        }
+        
+        // Have to save the param object to the param stack frame here.
+        // Can't wait until end(). Otherwise, the object will be lost.
+        // We can't save the object as instance variables, as 
+        // the instance variables will be overwritten
+        // if this CallParamRule is reused in subsequent nesting.
+        
+        if(param != null) {
+            Object parameters[] = (Object[]) digester.peekParams();
+            parameters[paramIndex] = param;
+        }
+    }
+
+
+    /**
+     * Process the body text of this element.
+     *
+     * @param bodyText The body text of this element
+     */
+    public void body(String bodyText) throws Exception {
+
+        if (attributeName == null && !fromStack) {
+            // We must wait to set the parameter until end
+            // so that we can make sure that the right set of parameters
+            // is at the top of the stack
+            if (bodyTextStack == null) {
+                bodyTextStack = new ArrayStack();
+            }
+            bodyTextStack.push(bodyText.trim());
+        }
+
+    }
+    
+    /**
+     * Process any body texts now.
+     */
+    public void end(String namespace, String name) {
+        if (bodyTextStack != null && !bodyTextStack.empty()) {
+            // what we do now is push one parameter onto the top set of parameters
+            Object parameters[] = (Object[]) digester.peekParams();
+            parameters[paramIndex] = bodyTextStack.pop();
+        }
+    }
+
+    /**
+     * Render a printable version of this Rule.
+     */
+    public String toString() {
+
+        StringBuffer sb = new StringBuffer("CallParamRule[");
+        sb.append("paramIndex=");
+        sb.append(paramIndex);
+        sb.append(", attributeName=");
+        sb.append(attributeName);
+        sb.append(", from stack=");
+        sb.append(fromStack);
+        sb.append("]");
+        return (sb.toString());
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/digester/Digester.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/digester/Digester.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/digester/Digester.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,2824 @@
+/* $Id: Digester.java 380645 2006-02-24 11:37:46Z remm $
+ *
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.digester;
+
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.Reader;
+import java.lang.reflect.InvocationTargetException;
+import java.util.EmptyStackException;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.parsers.SAXParser;
+import javax.xml.parsers.SAXParserFactory;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.tomcat.util.IntrospectionUtils;
+import org.xml.sax.Attributes;
+import org.xml.sax.EntityResolver;
+import org.xml.sax.ErrorHandler;
+import org.xml.sax.InputSource;
+import org.xml.sax.Locator;
+import org.xml.sax.SAXException;
+import org.xml.sax.SAXNotRecognizedException;
+import org.xml.sax.SAXNotSupportedException;
+import org.xml.sax.SAXParseException;
+import org.xml.sax.XMLReader;
+import org.xml.sax.helpers.AttributesImpl;
+import org.xml.sax.helpers.DefaultHandler;
+
+
+
+
+/**
+ * <p>A <strong>Digester</strong> processes an XML input stream by matching a
+ * series of element nesting patterns to execute Rules that have been added
+ * prior to the start of parsing.  This package was inspired by the
+ * <code>XmlMapper</code> class that was part of Tomcat 3.0 and 3.1,
+ * but is organized somewhat differently.</p>
+ *
+ * <p>See the <a href="package-summary.html#package_description">Digester
+ * Developer Guide</a> for more information.</p>
+ *
+ * <p><strong>IMPLEMENTATION NOTE</strong> - A single Digester instance may
+ * only be used within the context of a single thread at a time, and a call
+ * to <code>parse()</code> must be completed before another can be initiated
+ * even from the same thread.</p>
+ *
+ * <p><strong>IMPLEMENTATION NOTE</strong> - A bug in Xerces 2.0.2 prevents
+ * the support of XML schema. You need Xerces 2.1/2.3 and up to make
+ * this class working with XML schema</p>
+ */
+
+public class Digester extends DefaultHandler {
+
+
+    // ---------------------------------------------------------- Static Fields
+
+
+    private static class SystemPropertySource 
+        implements IntrospectionUtils.PropertySource {
+        public String getProperty( String key ) {
+            return System.getProperty(key);
+        }
+    }
+
+    protected static IntrospectionUtils.PropertySource source[] = 
+        new IntrospectionUtils.PropertySource[] { new SystemPropertySource() };
+
+
+    // --------------------------------------------------------- Constructors
+
+
+    /**
+     * Construct a new Digester with default properties.
+     */
+    public Digester() {
+
+        super();
+
+    }
+
+
+    /**
+     * Construct a new Digester, allowing a SAXParser to be passed in.  This
+     * allows Digester to be used in environments which are unfriendly to
+     * JAXP1.1 (such as WebLogic 6.0).  Thanks for the request to change go to
+     * James House (james at interobjective.com).  This may help in places where
+     * you are able to load JAXP 1.1 classes yourself.
+     */
+    public Digester(SAXParser parser) {
+
+        super();
+
+        this.parser = parser;
+
+    }
+
+
+    /**
+     * Construct a new Digester, allowing an XMLReader to be passed in.  This
+     * allows Digester to be used in environments which are unfriendly to
+     * JAXP1.1 (such as WebLogic 6.0).  Note that if you use this option you
+     * have to configure namespace and validation support yourself, as these
+     * properties only affect the SAXParser and emtpy constructor.
+     */
+    public Digester(XMLReader reader) {
+
+        super();
+
+        this.reader = reader;
+
+    }
+
+
+    // --------------------------------------------------- Instance Variables
+
+
+    /**
+     * The body text of the current element.
+     */
+    protected StringBuffer bodyText = new StringBuffer();
+
+
+    /**
+     * The stack of body text string buffers for surrounding elements.
+     */
+    protected ArrayStack bodyTexts = new ArrayStack();
+
+
+    /**
+     * Stack whose elements are List objects, each containing a list of
+     * Rule objects as returned from Rules.getMatch(). As each xml element
+     * in the input is entered, the matching rules are pushed onto this
+     * stack. After the end tag is reached, the matches are popped again.
+     * The depth of is stack is therefore exactly the same as the current
+     * "nesting" level of the input xml. 
+     *
+     * @since 1.6
+     */
+    protected ArrayStack matches = new ArrayStack(10);
+    
+    /**
+     * The class loader to use for instantiating application objects.
+     * If not specified, the context class loader, or the class loader
+     * used to load Digester itself, is used, based on the value of the
+     * <code>useContextClassLoader</code> variable.
+     */
+    protected ClassLoader classLoader = null;
+
+
+    /**
+     * Has this Digester been configured yet.
+     */
+    protected boolean configured = false;
+
+
+    /**
+     * The EntityResolver used by the SAX parser. By default it use this class
+     */
+    protected EntityResolver entityResolver;
+    
+    /**
+     * The URLs of entityValidator that have been registered, keyed by the public
+     * identifier that corresponds.
+     */
+    protected HashMap entityValidator = new HashMap();
+
+
+    /**
+     * The application-supplied error handler that is notified when parsing
+     * warnings, errors, or fatal errors occur.
+     */
+    protected ErrorHandler errorHandler = null;
+
+
+    /**
+     * The SAXParserFactory that is created the first time we need it.
+     */
+    protected SAXParserFactory factory = null;
+
+    /**
+     * @deprecated This is now managed by {@link ParserFeatureSetterFactory}
+     */
+    protected String JAXP_SCHEMA_LANGUAGE =
+        "http://java.sun.com/xml/jaxp/properties/schemaLanguage";
+    
+    
+    /**
+     * The Locator associated with our parser.
+     */
+    protected Locator locator = null;
+
+
+    /**
+     * The current match pattern for nested element processing.
+     */
+    protected String match = "";
+
+
+    /**
+     * Do we want a "namespace aware" parser.
+     */
+    protected boolean namespaceAware = false;
+
+
+    /**
+     * Registered namespaces we are currently processing.  The key is the
+     * namespace prefix that was declared in the document.  The value is an
+     * ArrayStack of the namespace URIs this prefix has been mapped to --
+     * the top Stack element is the most current one.  (This architecture
+     * is required because documents can declare nested uses of the same
+     * prefix for different Namespace URIs).
+     */
+    protected HashMap namespaces = new HashMap();
+
+
+    /**
+     * The parameters stack being utilized by CallMethodRule and
+     * CallParamRule rules.
+     */
+    protected ArrayStack params = new ArrayStack();
+
+
+    /**
+     * The SAXParser we will use to parse the input stream.
+     */
+    protected SAXParser parser = null;
+
+
+    /**
+     * The public identifier of the DTD we are currently parsing under
+     * (if any).
+     */
+    protected String publicId = null;
+
+
+    /**
+     * The XMLReader used to parse digester rules.
+     */
+    protected XMLReader reader = null;
+
+
+    /**
+     * The "root" element of the stack (in other words, the last object
+     * that was popped.
+     */
+    protected Object root = null;
+
+
+    /**
+     * The <code>Rules</code> implementation containing our collection of
+     * <code>Rule</code> instances and associated matching policy.  If not
+     * established before the first rule is added, a default implementation
+     * will be provided.
+     */
+    protected Rules rules = null;
+
+   /**
+     * The XML schema language to use for validating an XML instance. By
+     * default this value is set to <code>W3C_XML_SCHEMA</code>
+     */
+    protected String schemaLanguage = W3C_XML_SCHEMA;
+    
+        
+    /**
+     * The XML schema to use for validating an XML instance.
+     */
+    protected String schemaLocation = null;
+    
+    
+    /**
+     * The object stack being constructed.
+     */
+    protected ArrayStack stack = new ArrayStack();
+
+
+    /**
+     * Do we want to use the Context ClassLoader when loading classes
+     * for instantiating new objects.  Default is <code>false</code>.
+     */
+    protected boolean useContextClassLoader = false;
+
+
+    /**
+     * Do we want to use a validating parser.
+     */
+    protected boolean validating = false;
+
+
+    /**
+     * The Log to which most logging calls will be made.
+     */
+    protected Log log =
+        LogFactory.getLog("org.apache.commons.digester.Digester");
+
+
+    /**
+     * The Log to which all SAX event related logging calls will be made.
+     */
+    protected Log saxLog =
+        LogFactory.getLog("org.apache.commons.digester.Digester.sax");
+    
+        
+    /**
+     * The schema language supported. By default, we use this one.
+     */
+    protected static final String W3C_XML_SCHEMA =
+        "http://www.w3.org/2001/XMLSchema";
+    
+    /** Stacks used for interrule communication, indexed by name String */
+    private HashMap stacksByName = new HashMap();
+    
+    // ------------------------------------------------------------- Properties
+
+    /**
+     * Return the currently mapped namespace URI for the specified prefix,
+     * if any; otherwise return <code>null</code>.  These mappings come and
+     * go dynamically as the document is parsed.
+     *
+     * @param prefix Prefix to look up
+     */
+    public String findNamespaceURI(String prefix) {
+        
+        ArrayStack stack = (ArrayStack) namespaces.get(prefix);
+        if (stack == null) {
+            return (null);
+        }
+        try {
+            return ((String) stack.peek());
+        } catch (EmptyStackException e) {
+            return (null);
+        }
+
+    }
+
+
+    /**
+     * Return the class loader to be used for instantiating application objects
+     * when required.  This is determined based upon the following rules:
+     * <ul>
+     * <li>The class loader set by <code>setClassLoader()</code>, if any</li>
+     * <li>The thread context class loader, if it exists and the
+     *     <code>useContextClassLoader</code> property is set to true</li>
+     * <li>The class loader used to load the Digester class itself.
+     * </ul>
+     */
+    public ClassLoader getClassLoader() {
+
+        if (this.classLoader != null) {
+            return (this.classLoader);
+        }
+        if (this.useContextClassLoader) {
+            ClassLoader classLoader =
+                    Thread.currentThread().getContextClassLoader();
+            if (classLoader != null) {
+                return (classLoader);
+            }
+        }
+        return (this.getClass().getClassLoader());
+
+    }
+
+
+    /**
+     * Set the class loader to be used for instantiating application objects
+     * when required.
+     *
+     * @param classLoader The new class loader to use, or <code>null</code>
+     *  to revert to the standard rules
+     */
+    public void setClassLoader(ClassLoader classLoader) {
+
+        this.classLoader = classLoader;
+
+    }
+
+
+    /**
+     * Return the current depth of the element stack.
+     */
+    public int getCount() {
+
+        return (stack.size());
+
+    }
+
+
+    /**
+     * Return the name of the XML element that is currently being processed.
+     */
+    public String getCurrentElementName() {
+
+        String elementName = match;
+        int lastSlash = elementName.lastIndexOf('/');
+        if (lastSlash >= 0) {
+            elementName = elementName.substring(lastSlash + 1);
+        }
+        return (elementName);
+
+    }
+
+
+    /**
+     * Return the debugging detail level of our currently enabled logger.
+     *
+     * @deprecated This method now always returns 0. Digester uses the apache
+     * jakarta commons-logging library; see the documentation for that library
+     * for more information.
+     */
+    public int getDebug() {
+
+        return (0);
+
+    }
+
+
+    /**
+     * Set the debugging detail level of our currently enabled logger.
+     *
+     * @param debug New debugging detail level (0=off, increasing integers
+     *  for more detail)
+     *
+     * @deprecated This method now has no effect at all. Digester uses
+     * the apache jakarta comons-logging library; see the documentation
+     * for that library for more information.
+     */
+    public void setDebug(int debug) {
+
+        ; // No action is taken
+
+    }
+
+
+    /**
+     * Return the error handler for this Digester.
+     */
+    public ErrorHandler getErrorHandler() {
+
+        return (this.errorHandler);
+
+    }
+
+
+    /**
+     * Set the error handler for this Digester.
+     *
+     * @param errorHandler The new error handler
+     */
+    public void setErrorHandler(ErrorHandler errorHandler) {
+
+        this.errorHandler = errorHandler;
+
+    }
+
+
+    /**
+     * Return the SAXParserFactory we will use, creating one if necessary.
+     */
+    public SAXParserFactory getFactory() {
+
+        if (factory == null) {
+            factory = SAXParserFactory.newInstance();
+            factory.setNamespaceAware(namespaceAware);
+            factory.setValidating(validating);
+        }
+        return (factory);
+
+    }
+
+
+    /**
+     * Returns a flag indicating whether the requested feature is supported
+     * by the underlying implementation of <code>org.xml.sax.XMLReader</code>.
+     * See <a href="http://www.saxproject.org/apidoc/xml/sax/package-summary.html#package-description"
+     * http://www.saxproject.org/apidoc/xml/sax/package-summary.html#package-description</a>
+     * for information about the standard SAX2 feature flags.
+     *
+     * @param feature Name of the feature to inquire about
+     *
+     * @exception ParserConfigurationException if a parser configuration error
+     *  occurs
+     * @exception SAXNotRecognizedException if the property name is
+     *  not recognized
+     * @exception SAXNotSupportedException if the property name is
+     *  recognized but not supported
+     */
+    public boolean getFeature(String feature)
+        throws ParserConfigurationException, SAXNotRecognizedException,
+        SAXNotSupportedException {
+
+        return (getFactory().getFeature(feature));
+
+    }
+
+
+    /**
+     * Sets a flag indicating whether the requested feature is supported
+     * by the underlying implementation of <code>org.xml.sax.XMLReader</code>.
+     * See <a href="http://www.saxproject.org/apidoc/xml/sax/package-summary.html#package-description"
+     * http://www.saxproject.org/apidoc/xml/sax/package-summary.html#package-description</a>
+     * for information about the standard SAX2 feature flags.  In order to be
+     * effective, this method must be called <strong>before</strong> the
+     * <code>getParser()</code> method is called for the first time, either
+     * directly or indirectly.
+     *
+     * @param feature Name of the feature to set the status for
+     * @param value The new value for this feature
+     *
+     * @exception ParserConfigurationException if a parser configuration error
+     *  occurs
+     * @exception SAXNotRecognizedException if the property name is
+     *  not recognized
+     * @exception SAXNotSupportedException if the property name is
+     *  recognized but not supported
+     */
+    public void setFeature(String feature, boolean value)
+        throws ParserConfigurationException, SAXNotRecognizedException,
+        SAXNotSupportedException {
+
+        getFactory().setFeature(feature, value);
+
+    }
+
+
+    /**
+     * Return the current Logger associated with this instance of the Digester
+     */
+    public Log getLogger() {
+
+        return log;
+
+    }
+
+
+    /**
+     * Set the current logger for this Digester.
+     */
+    public void setLogger(Log log) {
+
+        this.log = log;
+
+    }
+
+    /**
+     * Gets the logger used for logging SAX-related information.
+     * <strong>Note</strong> the output is finely grained.
+     *
+     * @since 1.6
+     */
+    public Log getSAXLogger() {
+        
+        return saxLog;
+    }
+    
+
+    /**
+     * Sets the logger used for logging SAX-related information.
+     * <strong>Note</strong> the output is finely grained.
+     * @param saxLog Log, not null
+     *
+     * @since 1.6
+     */    
+    public void setSAXLogger(Log saxLog) {
+    
+        this.saxLog = saxLog;
+    }
+
+    /**
+     * Return the current rule match path
+     */
+    public String getMatch() {
+
+        return match;
+
+    }
+
+
+    /**
+     * Return the "namespace aware" flag for parsers we create.
+     */
+    public boolean getNamespaceAware() {
+
+        return (this.namespaceAware);
+
+    }
+
+
+    /**
+     * Set the "namespace aware" flag for parsers we create.
+     *
+     * @param namespaceAware The new "namespace aware" flag
+     */
+    public void setNamespaceAware(boolean namespaceAware) {
+
+        this.namespaceAware = namespaceAware;
+
+    }
+
+    
+    /**
+     * Set the publid id of the current file being parse.
+     * @param publicId the DTD/Schema public's id.
+     */
+    public void setPublicId(String publicId){
+        this.publicId = publicId;
+    }
+    
+    
+    /**
+     * Return the public identifier of the DTD we are currently
+     * parsing under, if any.
+     */
+    public String getPublicId() {
+
+        return (this.publicId);
+
+    }
+
+
+    /**
+     * Return the namespace URI that will be applied to all subsequently
+     * added <code>Rule</code> objects.
+     */
+    public String getRuleNamespaceURI() {
+
+        return (getRules().getNamespaceURI());
+
+    }
+
+
+    /**
+     * Set the namespace URI that will be applied to all subsequently
+     * added <code>Rule</code> objects.
+     *
+     * @param ruleNamespaceURI Namespace URI that must match on all
+     *  subsequently added rules, or <code>null</code> for matching
+     *  regardless of the current namespace URI
+     */
+    public void setRuleNamespaceURI(String ruleNamespaceURI) {
+
+        getRules().setNamespaceURI(ruleNamespaceURI);
+
+    }
+
+
+    /**
+     * Return the SAXParser we will use to parse the input stream.  If there
+     * is a problem creating the parser, return <code>null</code>.
+     */
+    public SAXParser getParser() {
+
+        // Return the parser we already created (if any)
+        if (parser != null) {
+            return (parser);
+        }
+
+        // Create a new parser
+        try {
+            if (validating) {
+                Properties properties = new Properties();
+                properties.put("SAXParserFactory", getFactory());
+                if (schemaLocation != null) {
+                    properties.put("schemaLocation", schemaLocation);
+                    properties.put("schemaLanguage", schemaLanguage);
+                }
+                parser = ParserFeatureSetterFactory.newSAXParser(properties);               } else {
+                parser = getFactory().newSAXParser();
+            }
+        } catch (Exception e) {
+            log.error("Digester.getParser: ", e);
+            return (null);
+        }
+
+        return (parser);
+
+    }
+
+
+    /**
+     * Return the current value of the specified property for the underlying
+     * <code>XMLReader</code> implementation.
+     * See <a href="http://www.saxproject.org/apidoc/xml/sax/package-summary.html#package-description"
+     * http://www.saxproject.org/apidoc/xml/sax/package-summary.html#package-description</a>
+     * for information about the standard SAX2 properties.
+     *
+     * @param property Property name to be retrieved
+     *
+     * @exception SAXNotRecognizedException if the property name is
+     *  not recognized
+     * @exception SAXNotSupportedException if the property name is
+     *  recognized but not supported
+     */
+    public Object getProperty(String property)
+        throws SAXNotRecognizedException, SAXNotSupportedException {
+
+        return (getParser().getProperty(property));
+
+    }
+
+
+    /**
+     * Set the current value of the specified property for the underlying
+     * <code>XMLReader</code> implementation.
+     * See <a href="http://www.saxproject.org/apidoc/xml/sax/package-summary.html#package-description"
+     * http://www.saxproject.org/apidoc/xml/sax/package-summary.html#package-description</a>
+     * for information about the standard SAX2 properties.
+     *
+     * @param property Property name to be set
+     * @param value Property value to be set
+     *
+     * @exception SAXNotRecognizedException if the property name is
+     *  not recognized
+     * @exception SAXNotSupportedException if the property name is
+     *  recognized but not supported
+     */
+    public void setProperty(String property, Object value)
+        throws SAXNotRecognizedException, SAXNotSupportedException {
+
+        getParser().setProperty(property, value);
+
+    }
+
+
+    /**
+     * By setting the reader in the constructor, you can bypass JAXP and
+     * be able to use digester in Weblogic 6.0.  
+     *
+     * @deprecated Use getXMLReader() instead, which can throw a
+     *  SAXException if the reader cannot be instantiated
+     */
+    public XMLReader getReader() {
+
+        try {
+            return (getXMLReader());
+        } catch (SAXException e) {
+            log.error("Cannot get XMLReader", e);
+            return (null);
+        }
+
+    }
+
+
+    /**
+     * Return the <code>Rules</code> implementation object containing our
+     * rules collection and associated matching policy.  If none has been
+     * established, a default implementation will be created and returned.
+     */
+    public Rules getRules() {
+
+        if (this.rules == null) {
+            this.rules = new RulesBase();
+            this.rules.setDigester(this);
+        }
+        return (this.rules);
+
+    }
+
+    
+    /**
+     * Set the <code>Rules</code> implementation object containing our
+     * rules collection and associated matching policy.
+     *
+     * @param rules New Rules implementation
+     */
+    public void setRules(Rules rules) {
+
+        this.rules = rules;
+        this.rules.setDigester(this);
+
+    }
+
+
+    /**
+     * Return the XML Schema URI used for validating an XML instance.
+     */
+    public String getSchema() {
+
+        return (this.schemaLocation);
+
+    }
+
+
+    /**
+     * Set the XML Schema URI used for validating a XML Instance.
+     *
+     * @param schemaLocation a URI to the schema.
+     */
+    public void setSchema(String schemaLocation){
+
+        this.schemaLocation = schemaLocation;
+
+    }   
+    
+
+    /**
+     * Return the XML Schema language used when parsing.
+     */
+    public String getSchemaLanguage() {
+
+        return (this.schemaLanguage);
+
+    }
+
+
+    /**
+     * Set the XML Schema language used when parsing. By default, we use W3C.
+     *
+     * @param schemaLanguage a URI to the schema language.
+     */
+    public void setSchemaLanguage(String schemaLanguage){
+
+        this.schemaLanguage = schemaLanguage;
+
+    }   
+
+
+    /**
+     * Return the boolean as to whether the context classloader should be used.
+     */
+    public boolean getUseContextClassLoader() {
+
+        return useContextClassLoader;
+
+    }
+
+
+    /**
+     * Determine whether to use the Context ClassLoader (the one found by
+     * calling <code>Thread.currentThread().getContextClassLoader()</code>)
+     * to resolve/load classes that are defined in various rules.  If not
+     * using Context ClassLoader, then the class-loading defaults to
+     * using the calling-class' ClassLoader.
+     *
+     * @param use determines whether to use Context ClassLoader.
+     */
+    public void setUseContextClassLoader(boolean use) {
+
+        useContextClassLoader = use;
+
+    }
+
+
+    /**
+     * Return the validating parser flag.
+     */
+    public boolean getValidating() {
+
+        return (this.validating);
+
+    }
+
+
+    /**
+     * Set the validating parser flag.  This must be called before
+     * <code>parse()</code> is called the first time.
+     *
+     * @param validating The new validating parser flag.
+     */
+    public void setValidating(boolean validating) {
+
+        this.validating = validating;
+
+    }
+
+
+    /**
+     * Return the XMLReader to be used for parsing the input document.
+     *
+     * FIX ME: there is a bug in JAXP/XERCES that prevent the use of a 
+     * parser that contains a schema with a DTD.
+     * @exception SAXException if no XMLReader can be instantiated
+     */
+    public XMLReader getXMLReader() throws SAXException {
+        if (reader == null){
+            reader = getParser().getXMLReader();
+        }        
+                               
+        reader.setDTDHandler(this);           
+        reader.setContentHandler(this);        
+        
+        if (entityResolver == null){
+            reader.setEntityResolver(this);
+        } else {
+            reader.setEntityResolver(entityResolver);           
+        }
+        
+        reader.setErrorHandler(this);
+        return reader;
+    }
+
+    // ------------------------------------------------- ContentHandler Methods
+
+
+    /**
+     * Process notification of character data received from the body of
+     * an XML element.
+     *
+     * @param buffer The characters from the XML document
+     * @param start Starting offset into the buffer
+     * @param length Number of characters from the buffer
+     *
+     * @exception SAXException if a parsing error is to be reported
+     */
+    public void characters(char buffer[], int start, int length)
+            throws SAXException {
+
+        if (saxLog.isDebugEnabled()) {
+            saxLog.debug("characters(" + new String(buffer, start, length) + ")");
+        }
+
+        bodyText.append(buffer, start, length);
+
+    }
+
+
+    /**
+     * Process notification of the end of the document being reached.
+     *
+     * @exception SAXException if a parsing error is to be reported
+     */
+    public void endDocument() throws SAXException {
+
+        if (saxLog.isDebugEnabled()) {
+            if (getCount() > 1) {
+                saxLog.debug("endDocument():  " + getCount() +
+                             " elements left");
+            } else {
+                saxLog.debug("endDocument()");
+            }
+        }
+
+        while (getCount() > 1) {
+            pop();
+        }
+
+        // Fire "finish" events for all defined rules
+        Iterator rules = getRules().rules().iterator();
+        while (rules.hasNext()) {
+            Rule rule = (Rule) rules.next();
+            try {
+                rule.finish();
+            } catch (Exception e) {
+                log.error("Finish event threw exception", e);
+                throw createSAXException(e);
+            } catch (Error e) {
+                log.error("Finish event threw error", e);
+                throw e;
+            }
+        }
+
+        // Perform final cleanup
+        clear();
+
+    }
+
+
+    /**
+     * Process notification of the end of an XML element being reached.
+     *
+     * @param namespaceURI - The Namespace URI, or the empty string if the
+     *   element has no Namespace URI or if Namespace processing is not
+     *   being performed.
+     * @param localName - The local name (without prefix), or the empty
+     *   string if Namespace processing is not being performed.
+     * @param qName - The qualified XML 1.0 name (with prefix), or the
+     *   empty string if qualified names are not available.
+     * @exception SAXException if a parsing error is to be reported
+     */
+    public void endElement(String namespaceURI, String localName,
+                           String qName) throws SAXException {
+
+        boolean debug = log.isDebugEnabled();
+
+        if (debug) {
+            if (saxLog.isDebugEnabled()) {
+                saxLog.debug("endElement(" + namespaceURI + "," + localName +
+                        "," + qName + ")");
+            }
+            log.debug("  match='" + match + "'");
+            log.debug("  bodyText='" + bodyText + "'");
+        }
+
+        // Parse system properties
+        bodyText = updateBodyText(bodyText);
+
+        // the actual element name is either in localName or qName, depending 
+        // on whether the parser is namespace aware
+        String name = localName;
+        if ((name == null) || (name.length() < 1)) {
+            name = qName;
+        }
+
+        // Fire "body" events for all relevant rules
+        List rules = (List) matches.pop();
+        if ((rules != null) && (rules.size() > 0)) {
+            String bodyText = this.bodyText.toString();
+            for (int i = 0; i < rules.size(); i++) {
+                try {
+                    Rule rule = (Rule) rules.get(i);
+                    if (debug) {
+                        log.debug("  Fire body() for " + rule);
+                    }
+                    rule.body(namespaceURI, name, bodyText);
+                } catch (Exception e) {
+                    log.error("Body event threw exception", e);
+                    throw createSAXException(e);
+                } catch (Error e) {
+                    log.error("Body event threw error", e);
+                    throw e;
+                }
+            }
+        } else {
+            if (debug) {
+                log.debug("  No rules found matching '" + match + "'.");
+            }
+        }
+
+        // Recover the body text from the surrounding element
+        bodyText = (StringBuffer) bodyTexts.pop();
+        if (debug) {
+            log.debug("  Popping body text '" + bodyText.toString() + "'");
+        }
+
+        // Fire "end" events for all relevant rules in reverse order
+        if (rules != null) {
+            for (int i = 0; i < rules.size(); i++) {
+                int j = (rules.size() - i) - 1;
+                try {
+                    Rule rule = (Rule) rules.get(j);
+                    if (debug) {
+                        log.debug("  Fire end() for " + rule);
+                    }
+                    rule.end(namespaceURI, name);
+                } catch (Exception e) {
+                    log.error("End event threw exception", e);
+                    throw createSAXException(e);
+                } catch (Error e) {
+                    log.error("End event threw error", e);
+                    throw e;
+                }
+            }
+        }
+
+        // Recover the previous match expression
+        int slash = match.lastIndexOf('/');
+        if (slash >= 0) {
+            match = match.substring(0, slash);
+        } else {
+            match = "";
+        }
+
+    }
+
+
+    /**
+     * Process notification that a namespace prefix is going out of scope.
+     *
+     * @param prefix Prefix that is going out of scope
+     *
+     * @exception SAXException if a parsing error is to be reported
+     */
+    public void endPrefixMapping(String prefix) throws SAXException {
+
+        if (saxLog.isDebugEnabled()) {
+            saxLog.debug("endPrefixMapping(" + prefix + ")");
+        }
+
+        // Deregister this prefix mapping
+        ArrayStack stack = (ArrayStack) namespaces.get(prefix);
+        if (stack == null) {
+            return;
+        }
+        try {
+            stack.pop();
+            if (stack.empty())
+                namespaces.remove(prefix);
+        } catch (EmptyStackException e) {
+            throw createSAXException("endPrefixMapping popped too many times");
+        }
+
+    }
+
+
+    /**
+     * Process notification of ignorable whitespace received from the body of
+     * an XML element.
+     *
+     * @param buffer The characters from the XML document
+     * @param start Starting offset into the buffer
+     * @param len Number of characters from the buffer
+     *
+     * @exception SAXException if a parsing error is to be reported
+     */
+    public void ignorableWhitespace(char buffer[], int start, int len)
+            throws SAXException {
+
+        if (saxLog.isDebugEnabled()) {
+            saxLog.debug("ignorableWhitespace(" +
+                    new String(buffer, start, len) + ")");
+        }
+
+        ;   // No processing required
+
+    }
+
+
+    /**
+     * Process notification of a processing instruction that was encountered.
+     *
+     * @param target The processing instruction target
+     * @param data The processing instruction data (if any)
+     *
+     * @exception SAXException if a parsing error is to be reported
+     */
+    public void processingInstruction(String target, String data)
+            throws SAXException {
+
+        if (saxLog.isDebugEnabled()) {
+            saxLog.debug("processingInstruction('" + target + "','" + data + "')");
+        }
+
+        ;   // No processing is required
+
+    }
+
+
+    /**
+     * Gets the document locator associated with our parser.
+     *
+     * @return the Locator supplied by the document parser
+     */
+    public Locator getDocumentLocator() {
+
+        return locator;
+
+    }
+
+    /**
+     * Sets the document locator associated with our parser.
+     *
+     * @param locator The new locator
+     */
+    public void setDocumentLocator(Locator locator) {
+
+        if (saxLog.isDebugEnabled()) {
+            saxLog.debug("setDocumentLocator(" + locator + ")");
+        }
+
+        this.locator = locator;
+
+    }
+
+
+    /**
+     * Process notification of a skipped entity.
+     *
+     * @param name Name of the skipped entity
+     *
+     * @exception SAXException if a parsing error is to be reported
+     */
+    public void skippedEntity(String name) throws SAXException {
+
+        if (saxLog.isDebugEnabled()) {
+            saxLog.debug("skippedEntity(" + name + ")");
+        }
+
+        ; // No processing required
+
+    }
+
+
+    /**
+     * Process notification of the beginning of the document being reached.
+     *
+     * @exception SAXException if a parsing error is to be reported
+     */
+    public void startDocument() throws SAXException {
+
+        if (saxLog.isDebugEnabled()) {
+            saxLog.debug("startDocument()");
+        }
+
+        // ensure that the digester is properly configured, as 
+        // the digester could be used as a SAX ContentHandler
+        // rather than via the parse() methods.
+        configure();
+    }
+
+
+    /**
+     * Process notification of the start of an XML element being reached.
+     *
+     * @param namespaceURI The Namespace URI, or the empty string if the element
+     *   has no Namespace URI or if Namespace processing is not being performed.
+     * @param localName The local name (without prefix), or the empty
+     *   string if Namespace processing is not being performed.
+     * @param qName The qualified name (with prefix), or the empty
+     *   string if qualified names are not available.\
+     * @param list The attributes attached to the element. If there are
+     *   no attributes, it shall be an empty Attributes object. 
+     * @exception SAXException if a parsing error is to be reported
+     */
+    public void startElement(String namespaceURI, String localName,
+                             String qName, Attributes list)
+            throws SAXException {
+        boolean debug = log.isDebugEnabled();
+        
+        if (saxLog.isDebugEnabled()) {
+            saxLog.debug("startElement(" + namespaceURI + "," + localName + "," +
+                    qName + ")");
+        }
+        
+        // Parse system properties
+        list = updateAttributes(list);
+        
+        // Save the body text accumulated for our surrounding element
+        bodyTexts.push(bodyText);
+        if (debug) {
+            log.debug("  Pushing body text '" + bodyText.toString() + "'");
+        }
+        bodyText = new StringBuffer();
+
+        // the actual element name is either in localName or qName, depending 
+        // on whether the parser is namespace aware
+        String name = localName;
+        if ((name == null) || (name.length() < 1)) {
+            name = qName;
+        }
+
+        // Compute the current matching rule
+        StringBuffer sb = new StringBuffer(match);
+        if (match.length() > 0) {
+            sb.append('/');
+        }
+        sb.append(name);
+        match = sb.toString();
+        if (debug) {
+            log.debug("  New match='" + match + "'");
+        }
+
+        // Fire "begin" events for all relevant rules
+        List rules = getRules().match(namespaceURI, match);
+        matches.push(rules);
+        if ((rules != null) && (rules.size() > 0)) {
+            for (int i = 0; i < rules.size(); i++) {
+                try {
+                    Rule rule = (Rule) rules.get(i);
+                    if (debug) {
+                        log.debug("  Fire begin() for " + rule);
+                    }
+                    rule.begin(namespaceURI, name, list);
+                } catch (Exception e) {
+                    log.error("Begin event threw exception", e);
+                    throw createSAXException(e);
+                } catch (Error e) {
+                    log.error("Begin event threw error", e);
+                    throw e;
+                }
+            }
+        } else {
+            if (debug) {
+                log.debug("  No rules found matching '" + match + "'.");
+            }
+        }
+
+    }
+
+
+    /**
+     * Process notification that a namespace prefix is coming in to scope.
+     *
+     * @param prefix Prefix that is being declared
+     * @param namespaceURI Corresponding namespace URI being mapped to
+     *
+     * @exception SAXException if a parsing error is to be reported
+     */
+    public void startPrefixMapping(String prefix, String namespaceURI)
+            throws SAXException {
+
+        if (saxLog.isDebugEnabled()) {
+            saxLog.debug("startPrefixMapping(" + prefix + "," + namespaceURI + ")");
+        }
+
+        // Register this prefix mapping
+        ArrayStack stack = (ArrayStack) namespaces.get(prefix);
+        if (stack == null) {
+            stack = new ArrayStack();
+            namespaces.put(prefix, stack);
+        }
+        stack.push(namespaceURI);
+
+    }
+
+
+    // ----------------------------------------------------- DTDHandler Methods
+
+
+    /**
+     * Receive notification of a notation declaration event.
+     *
+     * @param name The notation name
+     * @param publicId The public identifier (if any)
+     * @param systemId The system identifier (if any)
+     */
+    public void notationDecl(String name, String publicId, String systemId) {
+
+        if (saxLog.isDebugEnabled()) {
+            saxLog.debug("notationDecl(" + name + "," + publicId + "," +
+                    systemId + ")");
+        }
+
+    }
+
+
+    /**
+     * Receive notification of an unparsed entity declaration event.
+     *
+     * @param name The unparsed entity name
+     * @param publicId The public identifier (if any)
+     * @param systemId The system identifier (if any)
+     * @param notation The name of the associated notation
+     */
+    public void unparsedEntityDecl(String name, String publicId,
+                                   String systemId, String notation) {
+
+        if (saxLog.isDebugEnabled()) {
+            saxLog.debug("unparsedEntityDecl(" + name + "," + publicId + "," +
+                    systemId + "," + notation + ")");
+        }
+
+    }
+
+
+    // ----------------------------------------------- EntityResolver Methods
+
+    /**
+     * Set the <code>EntityResolver</code> used by SAX when resolving
+     * public id and system id.
+     * This must be called before the first call to <code>parse()</code>.
+     * @param entityResolver a class that implement the <code>EntityResolver</code> interface.
+     */
+    public void setEntityResolver(EntityResolver entityResolver){
+        this.entityResolver = entityResolver;
+    }
+    
+    
+    /**
+     * Return the Entity Resolver used by the SAX parser.
+     * @return Return the Entity Resolver used by the SAX parser.
+     */
+    public EntityResolver getEntityResolver(){
+        return entityResolver;
+    }
+
+    /**
+     * Resolve the requested external entity.
+     *
+     * @param publicId The public identifier of the entity being referenced
+     * @param systemId The system identifier of the entity being referenced
+     *
+     * @exception SAXException if a parsing exception occurs
+     * 
+     */
+    public InputSource resolveEntity(String publicId, String systemId)
+            throws SAXException {     
+                
+        if (saxLog.isDebugEnabled()) {
+            saxLog.debug("resolveEntity('" + publicId + "', '" + systemId + "')");
+        }
+        
+        if (publicId != null)
+            this.publicId = publicId;
+                                       
+        // Has this system identifier been registered?
+        String entityURL = null;
+        if (publicId != null) {
+            entityURL = (String) entityValidator.get(publicId);
+        }
+         
+        // Redirect the schema location to a local destination
+        if (schemaLocation != null && entityURL == null && systemId != null){
+            entityURL = (String)entityValidator.get(systemId);
+        } 
+
+        if (entityURL == null) { 
+            if (systemId == null) {
+                // cannot resolve
+                if (log.isDebugEnabled()) {
+                    log.debug(" Cannot resolve entity: '" + entityURL + "'");
+                }
+                return (null);
+                
+            } else {
+                // try to resolve using system ID
+                if (log.isDebugEnabled()) {
+                    log.debug(" Trying to resolve using system ID '" + systemId + "'");
+                } 
+                entityURL = systemId;
+            }
+        }
+        
+        // Return an input source to our alternative URL
+        if (log.isDebugEnabled()) {
+            log.debug(" Resolving to alternate DTD '" + entityURL + "'");
+        }  
+        
+        try {
+            return (new InputSource(entityURL));
+        } catch (Exception e) {
+            throw createSAXException(e);
+        }
+    }
+
+
+    // ------------------------------------------------- ErrorHandler Methods
+
+
+    /**
+     * Forward notification of a parsing error to the application supplied
+     * error handler (if any).
+     *
+     * @param exception The error information
+     *
+     * @exception SAXException if a parsing exception occurs
+     */
+    public void error(SAXParseException exception) throws SAXException {
+
+        log.error("Parse Error at line " + exception.getLineNumber() +
+                " column " + exception.getColumnNumber() + ": " +
+                exception.getMessage(), exception);
+        if (errorHandler != null) {
+            errorHandler.error(exception);
+        }
+
+    }
+
+
+    /**
+     * Forward notification of a fatal parsing error to the application
+     * supplied error handler (if any).
+     *
+     * @param exception The fatal error information
+     *
+     * @exception SAXException if a parsing exception occurs
+     */
+    public void fatalError(SAXParseException exception) throws SAXException {
+
+        log.error("Parse Fatal Error at line " + exception.getLineNumber() +
+                " column " + exception.getColumnNumber() + ": " +
+                exception.getMessage(), exception);
+        if (errorHandler != null) {
+            errorHandler.fatalError(exception);
+        }
+
+    }
+
+
+    /**
+     * Forward notification of a parse warning to the application supplied
+     * error handler (if any).
+     *
+     * @param exception The warning information
+     *
+     * @exception SAXException if a parsing exception occurs
+     */
+    public void warning(SAXParseException exception) throws SAXException {
+         if (errorHandler != null) {
+            log.warn("Parse Warning Error at line " + exception.getLineNumber() +
+                " column " + exception.getColumnNumber() + ": " +
+                exception.getMessage(), exception);
+            
+            errorHandler.warning(exception);
+        }
+
+    }
+
+
+    // ------------------------------------------------------- Public Methods
+
+
+    /**
+     * Log a message to our associated logger.
+     *
+     * @param message The message to be logged
+     * @deprecated Call getLogger() and use it's logging methods
+     */
+    public void log(String message) {
+
+        log.info(message);
+
+    }
+
+
+    /**
+     * Log a message and exception to our associated logger.
+     *
+     * @param message The message to be logged
+     * @deprecated Call getLogger() and use it's logging methods
+     */
+    public void log(String message, Throwable exception) {
+
+        log.error(message, exception);
+
+    }
+
+
+    /**
+     * Parse the content of the specified file using this Digester.  Returns
+     * the root element from the object stack (if any).
+     *
+     * @param file File containing the XML data to be parsed
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception SAXException if a parsing exception occurs
+     */
+    public Object parse(File file) throws IOException, SAXException {
+
+        configure();
+        InputSource input = new InputSource(new FileInputStream(file));
+        input.setSystemId("file://" + file.getAbsolutePath());
+        getXMLReader().parse(input);
+        return (root);
+
+    }   
+    /**
+     * Parse the content of the specified input source using this Digester.
+     * Returns the root element from the object stack (if any).
+     *
+     * @param input Input source containing the XML data to be parsed
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception SAXException if a parsing exception occurs
+     */
+    public Object parse(InputSource input) throws IOException, SAXException {
+ 
+        configure();
+        getXMLReader().parse(input);
+        return (root);
+
+    }
+
+
+    /**
+     * Parse the content of the specified input stream using this Digester.
+     * Returns the root element from the object stack (if any).
+     *
+     * @param input Input stream containing the XML data to be parsed
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception SAXException if a parsing exception occurs
+     */
+    public Object parse(InputStream input) throws IOException, SAXException {
+
+        configure();
+        InputSource is = new InputSource(input);
+        getXMLReader().parse(is);
+        return (root);
+
+    }
+
+
+    /**
+     * Parse the content of the specified reader using this Digester.
+     * Returns the root element from the object stack (if any).
+     *
+     * @param reader Reader containing the XML data to be parsed
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception SAXException if a parsing exception occurs
+     */
+    public Object parse(Reader reader) throws IOException, SAXException {
+
+        configure();
+        InputSource is = new InputSource(reader);
+        getXMLReader().parse(is);
+        return (root);
+
+    }
+
+
+    /**
+     * Parse the content of the specified URI using this Digester.
+     * Returns the root element from the object stack (if any).
+     *
+     * @param uri URI containing the XML data to be parsed
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception SAXException if a parsing exception occurs
+     */
+    public Object parse(String uri) throws IOException, SAXException {
+
+        configure();
+        InputSource is = new InputSource(uri);
+        getXMLReader().parse(is);
+        return (root);
+
+    }
+
+
+    /**
+     * <p>Register the specified DTD URL for the specified public identifier.
+     * This must be called before the first call to <code>parse()</code>.
+     * </p><p>
+     * <code>Digester</code> contains an internal <code>EntityResolver</code>
+     * implementation. This maps <code>PUBLICID</code>'s to URLs 
+     * (from which the resource will be loaded). A common use case for this
+     * method is to register local URLs (possibly computed at runtime by a 
+     * classloader) for DTDs. This allows the performance advantage of using
+     * a local version without having to ensure every <code>SYSTEM</code>
+     * URI on every processed xml document is local. This implementation provides
+     * only basic functionality. If more sophisticated features are required,
+     * using {@link #setEntityResolver} to set a custom resolver is recommended.
+     * </p><p>
+     * <strong>Note:</strong> This method will have no effect when a custom 
+     * <code>EntityResolver</code> has been set. (Setting a custom 
+     * <code>EntityResolver</code> overrides the internal implementation.) 
+     * </p>
+     * @param publicId Public identifier of the DTD to be resolved
+     * @param entityURL The URL to use for reading this DTD
+     */
+    public void register(String publicId, String entityURL) {
+
+        if (log.isDebugEnabled()) {
+            log.debug("register('" + publicId + "', '" + entityURL + "'");
+        }
+        entityValidator.put(publicId, entityURL);
+
+    }
+
+
+    // --------------------------------------------------------- Rule Methods
+
+
+    /**
+     * <p>Register a new Rule matching the specified pattern.
+     * This method sets the <code>Digester</code> property on the rule.</p>
+     *
+     * @param pattern Element matching pattern
+     * @param rule Rule to be registered
+     */
+    public void addRule(String pattern, Rule rule) {
+
+        rule.setDigester(this);
+        getRules().add(pattern, rule);
+
+    }
+
+
+    /**
+     * Register a set of Rule instances defined in a RuleSet.
+     *
+     * @param ruleSet The RuleSet instance to configure from
+     */
+    public void addRuleSet(RuleSet ruleSet) {
+
+        String oldNamespaceURI = getRuleNamespaceURI();
+        String newNamespaceURI = ruleSet.getNamespaceURI();
+        if (log.isDebugEnabled()) {
+            if (newNamespaceURI == null) {
+                log.debug("addRuleSet() with no namespace URI");
+            } else {
+                log.debug("addRuleSet() with namespace URI " + newNamespaceURI);
+            }
+        }
+        setRuleNamespaceURI(newNamespaceURI);
+        ruleSet.addRuleInstances(this);
+        setRuleNamespaceURI(oldNamespaceURI);
+
+    }
+
+
+    /**
+     * Add an "call method" rule for a method which accepts no arguments.
+     *
+     * @param pattern Element matching pattern
+     * @param methodName Method name to be called
+     * @see CallMethodRule
+     */
+    public void addCallMethod(String pattern, String methodName) {
+
+        addRule(
+                pattern,
+                new CallMethodRule(methodName));
+
+    }
+
+    /**
+     * Add an "call method" rule for the specified parameters.
+     *
+     * @param pattern Element matching pattern
+     * @param methodName Method name to be called
+     * @param paramCount Number of expected parameters (or zero
+     *  for a single parameter from the body of this element)
+     * @see CallMethodRule
+     */
+    public void addCallMethod(String pattern, String methodName,
+                              int paramCount) {
+
+        addRule(pattern,
+                new CallMethodRule(methodName, paramCount));
+
+    }
+
+
+    /**
+     * Add an "call method" rule for the specified parameters.
+     * If <code>paramCount</code> is set to zero the rule will use
+     * the body of the matched element as the single argument of the
+     * method, unless <code>paramTypes</code> is null or empty, in this
+     * case the rule will call the specified method with no arguments.
+     *
+     * @param pattern Element matching pattern
+     * @param methodName Method name to be called
+     * @param paramCount Number of expected parameters (or zero
+     *  for a single parameter from the body of this element)
+     * @param paramTypes Set of Java class names for the types
+     *  of the expected parameters
+     *  (if you wish to use a primitive type, specify the corresonding
+     *  Java wrapper class instead, such as <code>java.lang.Boolean</code>
+     *  for a <code>boolean</code> parameter)
+     * @see CallMethodRule
+     */
+    public void addCallMethod(String pattern, String methodName,
+                              int paramCount, String paramTypes[]) {
+
+        addRule(pattern,
+                new CallMethodRule(
+                                    methodName,
+                                    paramCount, 
+                                    paramTypes));
+
+    }
+
+
+    /**
+     * Add an "call method" rule for the specified parameters.
+     * If <code>paramCount</code> is set to zero the rule will use
+     * the body of the matched element as the single argument of the
+     * method, unless <code>paramTypes</code> is null or empty, in this
+     * case the rule will call the specified method with no arguments.
+     *
+     * @param pattern Element matching pattern
+     * @param methodName Method name to be called
+     * @param paramCount Number of expected parameters (or zero
+     *  for a single parameter from the body of this element)
+     * @param paramTypes The Java class names of the arguments
+     *  (if you wish to use a primitive type, specify the corresonding
+     *  Java wrapper class instead, such as <code>java.lang.Boolean</code>
+     *  for a <code>boolean</code> parameter)
+     * @see CallMethodRule
+     */
+    public void addCallMethod(String pattern, String methodName,
+                              int paramCount, Class paramTypes[]) {
+
+        addRule(pattern,
+                new CallMethodRule(
+                                    methodName,
+                                    paramCount, 
+                                    paramTypes));
+
+    }
+
+
+    /**
+     * Add a "call parameter" rule for the specified parameters.
+     *
+     * @param pattern Element matching pattern
+     * @param paramIndex Zero-relative parameter index to set
+     *  (from the body of this element)
+     * @see CallParamRule
+     */
+    public void addCallParam(String pattern, int paramIndex) {
+
+        addRule(pattern,
+                new CallParamRule(paramIndex));
+
+    }
+
+
+    /**
+     * Add a "call parameter" rule for the specified parameters.
+     *
+     * @param pattern Element matching pattern
+     * @param paramIndex Zero-relative parameter index to set
+     *  (from the specified attribute)
+     * @param attributeName Attribute whose value is used as the
+     *  parameter value
+     * @see CallParamRule
+     */
+    public void addCallParam(String pattern, int paramIndex,
+                             String attributeName) {
+
+        addRule(pattern,
+                new CallParamRule(paramIndex, attributeName));
+
+    }
+
+
+    /**
+     * Add a "call parameter" rule.
+     * This will either take a parameter from the stack 
+     * or from the current element body text. 
+     *
+     * @param paramIndex The zero-relative parameter number
+     * @param fromStack Should the call parameter be taken from the top of the stack?
+     * @see CallParamRule
+     */    
+    public void addCallParam(String pattern, int paramIndex, boolean fromStack) {
+    
+        addRule(pattern,
+                new CallParamRule(paramIndex, fromStack));
+      
+    }
+
+    /**
+     * Add a "call parameter" rule that sets a parameter from the stack.
+     * This takes a parameter from the given position on the stack.
+     *
+     * @param paramIndex The zero-relative parameter number
+     * @param stackIndex set the call parameter to the stackIndex'th object down the stack,
+     * where 0 is the top of the stack, 1 the next element down and so on
+     * @see CallMethodRule
+     */    
+    public void addCallParam(String pattern, int paramIndex, int stackIndex) {
+    
+        addRule(pattern,
+                new CallParamRule(paramIndex, stackIndex));
+      
+    }
+    
+    /**
+     * Add a "call parameter" rule that sets a parameter from the current 
+     * <code>Digester</code> matching path.
+     * This is sometimes useful when using rules that support wildcards.
+     *
+     * @param pattern the pattern that this rule should match
+     * @param paramIndex The zero-relative parameter number
+     * @see CallMethodRule
+     */
+    public void addCallParamPath(String pattern,int paramIndex) {
+        addRule(pattern, new PathCallParamRule(paramIndex));
+    }
+    
+    /**
+     * Add a "call parameter" rule that sets a parameter from a 
+     * caller-provided object. This can be used to pass constants such as
+     * strings to methods; it can also be used to pass mutable objects,
+     * providing ways for objects to do things like "register" themselves
+     * with some shared object.
+     * <p>
+     * Note that when attempting to locate a matching method to invoke,
+     * the true type of the paramObj is used, so that despite the paramObj
+     * being passed in here as type Object, the target method can declare
+     * its parameters as being the true type of the object (or some ancestor
+     * type, according to the usual type-conversion rules).
+     *
+     * @param paramIndex The zero-relative parameter number
+     * @param paramObj Any arbitrary object to be passed to the target
+     * method.
+     * @see CallMethodRule
+     *
+     * @since 1.6
+     */    
+    public void addObjectParam(String pattern, int paramIndex, 
+                               Object paramObj) {
+    
+        addRule(pattern,
+                new ObjectParamRule(paramIndex, paramObj));
+      
+    }
+    
+    /**
+     * Add a "factory create" rule for the specified parameters.
+     * Exceptions thrown during the object creation process will be propagated.
+     *
+     * @param pattern Element matching pattern
+     * @param className Java class name of the object creation factory class
+     * @see FactoryCreateRule
+     */
+    public void addFactoryCreate(String pattern, String className) {
+
+        addFactoryCreate(pattern, className, false);
+
+    }
+
+
+    /**
+     * Add a "factory create" rule for the specified parameters.
+     * Exceptions thrown during the object creation process will be propagated.
+     *
+     * @param pattern Element matching pattern
+     * @param clazz Java class of the object creation factory class
+     * @see FactoryCreateRule
+     */
+    public void addFactoryCreate(String pattern, Class clazz) {
+
+        addFactoryCreate(pattern, clazz, false);
+
+    }
+
+
+    /**
+     * Add a "factory create" rule for the specified parameters.
+     * Exceptions thrown during the object creation process will be propagated.
+     *
+     * @param pattern Element matching pattern
+     * @param className Java class name of the object creation factory class
+     * @param attributeName Attribute name which, if present, overrides the
+     *  value specified by <code>className</code>
+     * @see FactoryCreateRule
+     */
+    public void addFactoryCreate(String pattern, String className,
+                                 String attributeName) {
+
+        addFactoryCreate(pattern, className, attributeName, false);
+
+    }
+
+
+    /**
+     * Add a "factory create" rule for the specified parameters.
+     * Exceptions thrown during the object creation process will be propagated.
+     *
+     * @param pattern Element matching pattern
+     * @param clazz Java class of the object creation factory class
+     * @param attributeName Attribute name which, if present, overrides the
+     *  value specified by <code>className</code>
+     * @see FactoryCreateRule
+     */
+    public void addFactoryCreate(String pattern, Class clazz,
+                                 String attributeName) {
+
+        addFactoryCreate(pattern, clazz, attributeName, false);
+
+    }
+
+
+    /**
+     * Add a "factory create" rule for the specified parameters.
+     * Exceptions thrown during the object creation process will be propagated.
+     *
+     * @param pattern Element matching pattern
+     * @param creationFactory Previously instantiated ObjectCreationFactory
+     *  to be utilized
+     * @see FactoryCreateRule
+     */
+    public void addFactoryCreate(String pattern,
+                                 ObjectCreationFactory creationFactory) {
+
+        addFactoryCreate(pattern, creationFactory, false);
+
+    }
+
+    /**
+     * Add a "factory create" rule for the specified parameters.
+     *
+     * @param pattern Element matching pattern
+     * @param className Java class name of the object creation factory class
+     * @param ignoreCreateExceptions when <code>true</code> any exceptions thrown during
+     * object creation will be ignored.
+     * @see FactoryCreateRule
+     */
+    public void addFactoryCreate(
+                                    String pattern, 
+                                    String className,
+                                    boolean ignoreCreateExceptions) {
+
+        addRule(
+                pattern,
+                new FactoryCreateRule(className, ignoreCreateExceptions));
+
+    }
+
+
+    /**
+     * Add a "factory create" rule for the specified parameters.
+     *
+     * @param pattern Element matching pattern
+     * @param clazz Java class of the object creation factory class
+     * @param ignoreCreateExceptions when <code>true</code> any exceptions thrown during
+     * object creation will be ignored.
+     * @see FactoryCreateRule
+     */
+    public void addFactoryCreate(
+                                    String pattern, 
+                                    Class clazz,
+                                    boolean ignoreCreateExceptions) {
+
+        addRule(
+                pattern,
+                new FactoryCreateRule(clazz, ignoreCreateExceptions));
+
+    }
+
+
+    /**
+     * Add a "factory create" rule for the specified parameters.
+     *
+     * @param pattern Element matching pattern
+     * @param className Java class name of the object creation factory class
+     * @param attributeName Attribute name which, if present, overrides the
+     *  value specified by <code>className</code>
+     * @param ignoreCreateExceptions when <code>true</code> any exceptions thrown during
+     * object creation will be ignored.
+     * @see FactoryCreateRule
+     */
+    public void addFactoryCreate(
+                                String pattern, 
+                                String className,
+                                String attributeName,
+                                boolean ignoreCreateExceptions) {
+
+        addRule(
+                pattern,
+                new FactoryCreateRule(className, attributeName, ignoreCreateExceptions));
+
+    }
+
+
+    /**
+     * Add a "factory create" rule for the specified parameters.
+     *
+     * @param pattern Element matching pattern
+     * @param clazz Java class of the object creation factory class
+     * @param attributeName Attribute name which, if present, overrides the
+     *  value specified by <code>className</code>
+     * @param ignoreCreateExceptions when <code>true</code> any exceptions thrown during
+     * object creation will be ignored.
+     * @see FactoryCreateRule
+     */
+    public void addFactoryCreate(
+                                    String pattern, 
+                                    Class clazz,
+                                    String attributeName,
+                                    boolean ignoreCreateExceptions) {
+
+        addRule(
+                pattern,
+                new FactoryCreateRule(clazz, attributeName, ignoreCreateExceptions));
+
+    }
+
+
+    /**
+     * Add a "factory create" rule for the specified parameters.
+     *
+     * @param pattern Element matching pattern
+     * @param creationFactory Previously instantiated ObjectCreationFactory
+     *  to be utilized
+     * @param ignoreCreateExceptions when <code>true</code> any exceptions thrown during
+     * object creation will be ignored.
+     * @see FactoryCreateRule
+     */
+    public void addFactoryCreate(String pattern,
+                                 ObjectCreationFactory creationFactory,
+                                 boolean ignoreCreateExceptions) {
+
+        creationFactory.setDigester(this);
+        addRule(pattern,
+                new FactoryCreateRule(creationFactory, ignoreCreateExceptions));
+
+    }
+
+    /**
+     * Add an "object create" rule for the specified parameters.
+     *
+     * @param pattern Element matching pattern
+     * @param className Java class name to be created
+     * @see ObjectCreateRule
+     */
+    public void addObjectCreate(String pattern, String className) {
+
+        addRule(pattern,
+                new ObjectCreateRule(className));
+
+    }
+
+
+    /**
+     * Add an "object create" rule for the specified parameters.
+     *
+     * @param pattern Element matching pattern
+     * @param clazz Java class to be created
+     * @see ObjectCreateRule
+     */
+    public void addObjectCreate(String pattern, Class clazz) {
+
+        addRule(pattern,
+                new ObjectCreateRule(clazz));
+
+    }
+
+
+    /**
+     * Add an "object create" rule for the specified parameters.
+     *
+     * @param pattern Element matching pattern
+     * @param className Default Java class name to be created
+     * @param attributeName Attribute name that optionally overrides
+     *  the default Java class name to be created
+     * @see ObjectCreateRule
+     */
+    public void addObjectCreate(String pattern, String className,
+                                String attributeName) {
+
+        addRule(pattern,
+                new ObjectCreateRule(className, attributeName));
+
+    }
+
+
+    /**
+     * Add an "object create" rule for the specified parameters.
+     *
+     * @param pattern Element matching pattern
+     * @param attributeName Attribute name that optionally overrides
+     * @param clazz Default Java class to be created
+     *  the default Java class name to be created
+     * @see ObjectCreateRule
+     */
+    public void addObjectCreate(String pattern,
+                                String attributeName,
+                                Class clazz) {
+
+        addRule(pattern,
+                new ObjectCreateRule(attributeName, clazz));
+
+    }
+
+    /**
+     * Add a "set next" rule for the specified parameters.
+     *
+     * @param pattern Element matching pattern
+     * @param methodName Method name to call on the parent element
+     * @see SetNextRule
+     */
+    public void addSetNext(String pattern, String methodName) {
+
+        addRule(pattern,
+                new SetNextRule(methodName));
+
+    }
+
+
+    /**
+     * Add a "set next" rule for the specified parameters.
+     *
+     * @param pattern Element matching pattern
+     * @param methodName Method name to call on the parent element
+     * @param paramType Java class name of the expected parameter type
+     *  (if you wish to use a primitive type, specify the corresonding
+     *  Java wrapper class instead, such as <code>java.lang.Boolean</code>
+     *  for a <code>boolean</code> parameter)
+     * @see SetNextRule
+     */
+    public void addSetNext(String pattern, String methodName,
+                           String paramType) {
+
+        addRule(pattern,
+                new SetNextRule(methodName, paramType));
+
+    }
+
+
+    /**
+     * Add {@link SetRootRule} with the specified parameters.
+     *
+     * @param pattern Element matching pattern
+     * @param methodName Method name to call on the root object
+     * @see SetRootRule
+     */
+    public void addSetRoot(String pattern, String methodName) {
+
+        addRule(pattern,
+                new SetRootRule(methodName));
+
+    }
+
+
+    /**
+     * Add {@link SetRootRule} with the specified parameters.
+     *
+     * @param pattern Element matching pattern
+     * @param methodName Method name to call on the root object
+     * @param paramType Java class name of the expected parameter type
+     * @see SetRootRule
+     */
+    public void addSetRoot(String pattern, String methodName,
+                           String paramType) {
+
+        addRule(pattern,
+                new SetRootRule(methodName, paramType));
+
+    }
+
+    /**
+     * Add a "set properties" rule for the specified parameters.
+     *
+     * @param pattern Element matching pattern
+     * @see SetPropertiesRule
+     */
+    public void addSetProperties(String pattern) {
+
+        addRule(pattern,
+                new SetPropertiesRule());
+
+    }
+
+    /**
+     * Add a "set properties" rule with a single overridden parameter.
+     * See {@link SetPropertiesRule#SetPropertiesRule(String attributeName, String propertyName)}
+     *
+     * @param pattern Element matching pattern
+     * @param attributeName map this attribute
+     * @param propertyName to this property
+     * @see SetPropertiesRule
+     */
+    public void addSetProperties(
+                                String pattern, 
+                                String attributeName,
+                                String propertyName) {
+
+        addRule(pattern,
+                new SetPropertiesRule(attributeName, propertyName));
+
+    }
+
+    /**
+     * Add a "set properties" rule with overridden parameters.
+     * See {@link SetPropertiesRule#SetPropertiesRule(String [] attributeNames, String [] propertyNames)}
+     *
+     * @param pattern Element matching pattern
+     * @param attributeNames names of attributes with custom mappings
+     * @param propertyNames property names these attributes map to
+     * @see SetPropertiesRule
+     */
+    public void addSetProperties(
+                                String pattern, 
+                                String [] attributeNames,
+                                String [] propertyNames) {
+
+        addRule(pattern,
+                new SetPropertiesRule(attributeNames, propertyNames));
+
+    }
+
+
+    /**
+     * Add a "set property" rule for the specified parameters.
+     *
+     * @param pattern Element matching pattern
+     * @param name Attribute name containing the property name to be set
+     * @param value Attribute name containing the property value to set
+     * @see SetPropertyRule
+     */
+    public void addSetProperty(String pattern, String name, String value) {
+
+        addRule(pattern,
+                new SetPropertyRule(name, value));
+
+    }
+
+
+    /**
+     * Add a "set top" rule for the specified parameters.
+     *
+     * @param pattern Element matching pattern
+     * @param methodName Method name to call on the parent element
+     * @see SetTopRule
+     */
+    public void addSetTop(String pattern, String methodName) {
+
+        addRule(pattern,
+                new SetTopRule(methodName));
+
+    }
+
+
+    /**
+     * Add a "set top" rule for the specified parameters.
+     *
+     * @param pattern Element matching pattern
+     * @param methodName Method name to call on the parent element
+     * @param paramType Java class name of the expected parameter type
+     *  (if you wish to use a primitive type, specify the corresonding
+     *  Java wrapper class instead, such as <code>java.lang.Boolean</code>
+     *  for a <code>boolean</code> parameter)
+     * @see SetTopRule
+     */
+    public void addSetTop(String pattern, String methodName,
+                          String paramType) {
+
+        addRule(pattern,
+                new SetTopRule(methodName, paramType));
+
+    }
+
+
+    // --------------------------------------------------- Object Stack Methods
+
+
+    /**
+     * Clear the current contents of the object stack.
+     * <p>
+     * Calling this method <i>might</i> allow another document of the same type
+     * to be correctly parsed. However this method was not intended for this 
+     * purpose. In general, a separate Digester object should be created for
+     * each document to be parsed.
+     */
+    public void clear() {
+
+        match = "";
+        bodyTexts.clear();
+        params.clear();
+        publicId = null;
+        stack.clear();
+        log = null;
+        saxLog = null;
+        configured = false;
+        
+    }
+
+    
+    public void reset() {
+        root = null;
+        setErrorHandler(null);
+        clear();
+    }
+
+
+    /**
+     * Return the top object on the stack without removing it.  If there are
+     * no objects on the stack, return <code>null</code>.
+     */
+    public Object peek() {
+
+        try {
+            return (stack.peek());
+        } catch (EmptyStackException e) {
+            log.warn("Empty stack (returning null)");
+            return (null);
+        }
+
+    }
+
+
+    /**
+     * Return the n'th object down the stack, where 0 is the top element
+     * and [getCount()-1] is the bottom element.  If the specified index
+     * is out of range, return <code>null</code>.
+     *
+     * @param n Index of the desired element, where 0 is the top of the stack,
+     *  1 is the next element down, and so on.
+     */
+    public Object peek(int n) {
+
+        try {
+            return (stack.peek(n));
+        } catch (EmptyStackException e) {
+            log.warn("Empty stack (returning null)");
+            return (null);
+        }
+
+    }
+
+
+    /**
+     * Pop the top object off of the stack, and return it.  If there are
+     * no objects on the stack, return <code>null</code>.
+     */
+    public Object pop() {
+
+        try {
+            return (stack.pop());
+        } catch (EmptyStackException e) {
+            log.warn("Empty stack (returning null)");
+            return (null);
+        }
+
+    }
+
+
+    /**
+     * Push a new object onto the top of the object stack.
+     *
+     * @param object The new object
+     */
+    public void push(Object object) {
+
+        if (stack.size() == 0) {
+            root = object;
+        }
+        stack.push(object);
+
+    }
+
+    /**
+     * Pushes the given object onto the stack with the given name.
+     * If no stack already exists with the given name then one will be created.
+     * 
+     * @param stackName the name of the stack onto which the object should be pushed
+     * @param value the Object to be pushed onto the named stack.
+     *
+     * @since 1.6
+     */
+    public void push(String stackName, Object value) {
+        ArrayStack namedStack = (ArrayStack) stacksByName.get(stackName);
+        if (namedStack == null) {
+            namedStack = new ArrayStack();
+            stacksByName.put(stackName, namedStack);
+        }
+        namedStack.push(value);
+    }
+
+    /**
+     * <p>Pops (gets and removes) the top object from the stack with the given name.</p>
+     *
+     * <p><strong>Note:</strong> a stack is considered empty
+     * if no objects have been pushed onto it yet.</p>
+     * 
+     * @param stackName the name of the stack from which the top value is to be popped
+     * @return the top <code>Object</code> on the stack or or null if the stack is either 
+     * empty or has not been created yet
+     * @throws EmptyStackException if the named stack is empty
+     *
+     * @since 1.6
+     */
+    public Object pop(String stackName) {
+        Object result = null;
+        ArrayStack namedStack = (ArrayStack) stacksByName.get(stackName);
+        if (namedStack == null) {
+            if (log.isDebugEnabled()) {
+                log.debug("Stack '" + stackName + "' is empty");
+            }
+            throw new EmptyStackException();
+            
+        } else {
+        
+            result = namedStack.pop();
+        }
+        return result;
+    }
+    
+    /**
+     * <p>Gets the top object from the stack with the given name.
+     * This method does not remove the object from the stack.
+     * </p>
+     * <p><strong>Note:</strong> a stack is considered empty
+     * if no objects have been pushed onto it yet.</p>
+     *
+     * @param stackName the name of the stack to be peeked
+     * @return the top <code>Object</code> on the stack or null if the stack is either 
+     * empty or has not been created yet
+     * @throws EmptyStackException if the named stack is empty 
+     *
+     * @since 1.6
+     */
+    public Object peek(String stackName) {
+        Object result = null;
+        ArrayStack namedStack = (ArrayStack) stacksByName.get(stackName);
+        if (namedStack == null ) {
+            if (log.isDebugEnabled()) {
+                log.debug("Stack '" + stackName + "' is empty");
+            }        
+            throw new EmptyStackException();
+        
+        } else {
+        
+            result = namedStack.peek();
+        }
+        return result;
+    }
+
+    /**
+     * <p>Is the stack with the given name empty?</p>
+     * <p><strong>Note:</strong> a stack is considered empty
+     * if no objects have been pushed onto it yet.</p>
+     * @param stackName the name of the stack whose emptiness 
+     * should be evaluated
+     * @return true if the given stack if empty 
+     *
+     * @since 1.6
+     */
+    public boolean isEmpty(String stackName) {
+        boolean result = true;
+        ArrayStack namedStack = (ArrayStack) stacksByName.get(stackName);
+        if (namedStack != null ) {
+            result = namedStack.isEmpty();
+        }
+        return result;
+    }
+    
+    /**
+     * When the Digester is being used as a SAXContentHandler, 
+     * this method allows you to access the root object that has been
+     * created after parsing.
+     * 
+     * @return the root object that has been created after parsing
+     *  or null if the digester has not parsed any XML yet.
+     */
+    public Object getRoot() {
+        return root;
+    }
+    
+
+    // ------------------------------------------------ Parameter Stack Methods
+
+
+    // ------------------------------------------------------ Protected Methods
+
+
+    /**
+     * <p>
+     * Provide a hook for lazy configuration of this <code>Digester</code>
+     * instance.  The default implementation does nothing, but subclasses
+     * can override as needed.
+     * </p>
+     *
+     * <p>
+     * <strong>Note</strong> This method may be called more than once.
+     * Once only initialization code should be placed in {@link #initialize}
+     * or the code should take responsibility by checking and setting the 
+     * {@link #configured} flag.
+     * </p>
+     */
+    protected void configure() {
+
+        // Do not configure more than once
+        if (configured) {
+            return;
+        }
+
+        log = LogFactory.getLog("org.apache.commons.digester.Digester");
+        saxLog = LogFactory.getLog("org.apache.commons.digester.Digester.sax");
+
+        // Perform lazy configuration as needed
+        initialize(); // call hook method for subclasses that want to be initialized once only
+        // Nothing else required by default
+
+        // Set the configuration flag to avoid repeating
+        configured = true;
+
+    }
+    
+    /**
+     * <p>
+     * Provides a hook for lazy initialization of this <code>Digester</code>
+     * instance.  
+     * The default implementation does nothing, but subclasses
+     * can override as needed.
+     * Digester (by default) only calls this method once.
+     * </p>
+     *
+     * <p>
+     * <strong>Note</strong> This method will be called by {@link #configure} 
+     * only when the {@link #configured} flag is false. 
+     * Subclasses that override <code>configure</code> or who set <code>configured</code>
+     * may find that this method may be called more than once.
+     * </p>
+     *
+     * @since 1.6
+     */
+    protected void initialize() {
+
+        // Perform lazy initialization as needed
+        ; // Nothing required by default
+
+    }    
+
+    // -------------------------------------------------------- Package Methods
+
+
+    /**
+     * Return the set of DTD URL registrations, keyed by public identifier.
+     */
+    Map getRegistrations() {
+
+        return (entityValidator);
+
+    }
+
+
+    /**
+     * Return the set of rules that apply to the specified match position.
+     * The selected rules are those that match exactly, or those rules
+     * that specify a suffix match and the tail of the rule matches the
+     * current match position.  Exact matches have precedence over
+     * suffix matches, then (among suffix matches) the longest match
+     * is preferred.
+     *
+     * @param match The current match position
+     *
+     * @deprecated Call <code>match()</code> on the <code>Rules</code>
+     *  implementation returned by <code>getRules()</code>
+     */
+    List getRules(String match) {
+
+        return (getRules().match(match));
+
+    }
+
+
+    /**
+     * <p>Return the top object on the parameters stack without removing it.  If there are
+     * no objects on the stack, return <code>null</code>.</p>
+     *
+     * <p>The parameters stack is used to store <code>CallMethodRule</code> parameters. 
+     * See {@link #params}.</p>
+     */
+    public Object peekParams() {
+
+        try {
+            return (params.peek());
+        } catch (EmptyStackException e) {
+            log.warn("Empty stack (returning null)");
+            return (null);
+        }
+
+    }
+
+
+    /**
+     * <p>Return the n'th object down the parameters stack, where 0 is the top element
+     * and [getCount()-1] is the bottom element.  If the specified index
+     * is out of range, return <code>null</code>.</p>
+     *
+     * <p>The parameters stack is used to store <code>CallMethodRule</code> parameters. 
+     * See {@link #params}.</p>
+     *
+     * @param n Index of the desired element, where 0 is the top of the stack,
+     *  1 is the next element down, and so on.
+     */
+    public Object peekParams(int n) {
+
+        try {
+            return (params.peek(n));
+        } catch (EmptyStackException e) {
+            log.warn("Empty stack (returning null)");
+            return (null);
+        }
+
+    }
+
+
+    /**
+     * <p>Pop the top object off of the parameters stack, and return it.  If there are
+     * no objects on the stack, return <code>null</code>.</p>
+     *
+     * <p>The parameters stack is used to store <code>CallMethodRule</code> parameters. 
+     * See {@link #params}.</p>
+     */
+    public Object popParams() {
+
+        try {
+            if (log.isTraceEnabled()) {
+                log.trace("Popping params");
+            }
+            return (params.pop());
+        } catch (EmptyStackException e) {
+            log.warn("Empty stack (returning null)");
+            return (null);
+        }
+
+    }
+
+
+    /**
+     * <p>Push a new object onto the top of the parameters stack.</p>
+     *
+     * <p>The parameters stack is used to store <code>CallMethodRule</code> parameters. 
+     * See {@link #params}.</p>
+     *
+     * @param object The new object
+     */
+    public void pushParams(Object object) {
+        if (log.isTraceEnabled()) {
+            log.trace("Pushing params");
+        }
+        params.push(object);
+
+    }
+
+    /**
+     * Create a SAX exception which also understands about the location in
+     * the digester file where the exception occurs
+     *
+     * @return the new exception
+     */
+    public SAXException createSAXException(String message, Exception e) {
+        if ((e != null) &&
+            (e instanceof InvocationTargetException)) {
+            Throwable t = ((InvocationTargetException) e).getTargetException();
+            if ((t != null) && (t instanceof Exception)) {
+                e = (Exception) t;
+            }
+        }
+        if (locator != null) {
+            String error = "Error at (" + locator.getLineNumber() + ", " +
+                    locator.getColumnNumber() + ": " + message;
+            if (e != null) {
+                return new SAXParseException(error, locator, e);
+            } else {
+                return new SAXParseException(error, locator);
+            }
+        }
+        log.error("No Locator!");
+        if (e != null) {
+            return new SAXException(message, e);
+        } else {
+            return new SAXException(message);
+        }
+    }
+
+    /**
+     * Create a SAX exception which also understands about the location in
+     * the digester file where the exception occurs
+     *
+     * @return the new exception
+     */
+    public SAXException createSAXException(Exception e) {
+        if (e instanceof InvocationTargetException) {
+            Throwable t = ((InvocationTargetException) e).getTargetException();
+            if ((t != null) && (t instanceof Exception)) {
+                e = (Exception) t;
+            }
+        }
+        return createSAXException(e.getMessage(), e);
+    }
+
+    /**
+     * Create a SAX exception which also understands about the location in
+     * the digester file where the exception occurs
+     *
+     * @return the new exception
+     */
+    public SAXException createSAXException(String message) {
+        return createSAXException(message, null);
+    }
+    
+
+    // ------------------------------------------------------- Private Methods
+
+
+   /**
+     * Returns an attributes list which contains all the attributes
+     * passed in, with any text of form "${xxx}" in an attribute value
+     * replaced by the appropriate value from the system property.
+     */
+    private Attributes updateAttributes(Attributes list) {
+
+        if (list.getLength() == 0) {
+            return list;
+        }
+        
+        AttributesImpl newAttrs = new AttributesImpl(list);
+        int nAttributes = newAttrs.getLength();
+        for (int i = 0; i < nAttributes; ++i) {
+            String value = newAttrs.getValue(i);
+            try {
+                String newValue = 
+                    IntrospectionUtils.replaceProperties(value, null, source);
+                if (value != newValue) {
+                    newAttrs.setValue(i, newValue);
+                }
+            }
+            catch (Exception e) {
+                // ignore - let the attribute have its original value
+            }
+        }
+
+        return newAttrs;
+
+    }
+
+
+    /**
+     * Return a new StringBuffer containing the same contents as the
+     * input buffer, except that data of form ${varname} have been
+     * replaced by the value of that var as defined in the system property.
+     */
+    private StringBuffer updateBodyText(StringBuffer bodyText) {
+        String in = bodyText.toString();
+        String out;
+        try {
+            out = IntrospectionUtils.replaceProperties(in, null, source);
+        } catch(Exception e) {
+            return bodyText; // return unchanged data
+        }
+
+        if (out == in)  {
+            // No substitutions required. Don't waste memory creating
+            // a new buffer
+            return bodyText;
+        } else {
+            return new StringBuffer(out);
+        }
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/digester/FactoryCreateRule.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/digester/FactoryCreateRule.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/digester/FactoryCreateRule.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,495 @@
+/* $Id: FactoryCreateRule.java 299475 2004-06-26 17:41:32Z remm $
+ *
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.digester;
+
+import org.xml.sax.Attributes;
+
+
+/**
+ * <p>Rule implementation that uses an {@link ObjectCreationFactory} to create
+ * a new object which it pushes onto the object stack.  When the element is
+ * complete, the object will be popped.</p>
+ *
+ * <p>This rule is intended in situations where the element's attributes are
+ * needed before the object can be created.  A common senario is for the
+ * ObjectCreationFactory implementation to use the attributes  as parameters
+ * in a call to either a factory method or to a non-empty constructor.
+ */
+
+public class FactoryCreateRule extends Rule {
+
+    // ----------------------------------------------------------- Fields
+    
+    /** Should exceptions thrown by the factory be ignored? */
+    private boolean ignoreCreateExceptions;
+    /** Stock to manage */
+    private ArrayStack exceptionIgnoredStack;
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Construct a factory create rule that will use the specified
+     * class name to create an {@link ObjectCreationFactory} which will
+     * then be used to create an object and push it on the stack.
+     *
+     * @param digester The associated Digester
+     * @param className Java class name of the object creation factory class
+     *
+     * @deprecated The digester instance is now set in the {@link Digester#addRule} method. 
+     * Use {@link #FactoryCreateRule(String className)} instead.
+     */
+    public FactoryCreateRule(Digester digester, String className) {
+
+        this(className);
+
+    }
+
+
+    /**
+     * Construct a factory create rule that will use the specified
+     * class to create an {@link ObjectCreationFactory} which will
+     * then be used to create an object and push it on the stack.
+     *
+     * @param digester The associated Digester
+     * @param clazz Java class name of the object creation factory class
+     *
+     * @deprecated The digester instance is now set in the {@link Digester#addRule} method. 
+     * Use {@link #FactoryCreateRule(Class clazz)} instead.
+     */
+    public FactoryCreateRule(Digester digester, Class clazz) {
+
+        this(clazz);
+
+    }
+
+
+    /**
+     * Construct a factory create rule that will use the specified
+     * class name (possibly overridden by the specified attribute if present)
+     * to create an {@link ObjectCreationFactory}, which will then be used
+     * to instantiate an object instance and push it onto the stack.
+     *
+     * @param digester The associated Digester
+     * @param className Default Java class name of the factory class
+     * @param attributeName Attribute name which, if present, contains an
+     *  override of the class name of the object creation factory to create.
+     *
+     * @deprecated The digester instance is now set in the {@link Digester#addRule} method. 
+     * Use {@link #FactoryCreateRule(String className, String attributeName)} instead.
+     */
+    public FactoryCreateRule(Digester digester,
+                             String className, String attributeName) {
+
+        this(className, attributeName);
+
+    }
+
+
+    /**
+     * Construct a factory create rule that will use the specified
+     * class (possibly overridden by the specified attribute if present)
+     * to create an {@link ObjectCreationFactory}, which will then be used
+     * to instantiate an object instance and push it onto the stack.
+     *
+     * @param digester The associated Digester
+     * @param clazz Default Java class name of the factory class
+     * @param attributeName Attribute name which, if present, contains an
+     *  override of the class name of the object creation factory to create.
+     *
+     * @deprecated The digester instance is now set in the {@link Digester#addRule} method. 
+     * Use {@link #FactoryCreateRule(Class clazz, String attributeName)} instead.
+     */
+    public FactoryCreateRule(Digester digester,
+                             Class clazz, String attributeName) {
+
+        this(clazz, attributeName);
+
+    }
+
+
+    /**
+     * Construct a factory create rule using the given, already instantiated,
+     * {@link ObjectCreationFactory}.
+     *
+     * @param digester The associated Digester
+     * @param creationFactory called on to create the object.
+     *
+     * @deprecated The digester instance is now set in the {@link Digester#addRule} method. 
+     * Use {@link #FactoryCreateRule(ObjectCreationFactory creationFactory)} instead.
+     */
+    public FactoryCreateRule(Digester digester,
+                             ObjectCreationFactory creationFactory) {
+
+        this(creationFactory);
+
+    }    
+
+    /**
+     * <p>Construct a factory create rule that will use the specified
+     * class name to create an {@link ObjectCreationFactory} which will
+     * then be used to create an object and push it on the stack.</p>
+     *
+     * <p>Exceptions thrown during the object creation process will be propagated.</p>
+     *
+     * @param className Java class name of the object creation factory class
+     */
+    public FactoryCreateRule(String className) {
+
+        this(className, false);
+
+    }
+
+
+    /**
+     * <p>Construct a factory create rule that will use the specified
+     * class to create an {@link ObjectCreationFactory} which will
+     * then be used to create an object and push it on the stack.</p>
+     *
+     * <p>Exceptions thrown during the object creation process will be propagated.</p>
+     *
+     * @param clazz Java class name of the object creation factory class
+     */
+    public FactoryCreateRule(Class clazz) {
+
+        this(clazz, false);
+
+    }
+
+
+    /**
+     * <p>Construct a factory create rule that will use the specified
+     * class name (possibly overridden by the specified attribute if present)
+     * to create an {@link ObjectCreationFactory}, which will then be used
+     * to instantiate an object instance and push it onto the stack.</p>
+     *
+     * <p>Exceptions thrown during the object creation process will be propagated.</p>
+     *
+     * @param className Default Java class name of the factory class
+     * @param attributeName Attribute name which, if present, contains an
+     *  override of the class name of the object creation factory to create.
+     */
+    public FactoryCreateRule(String className, String attributeName) {
+
+        this(className, attributeName, false);
+
+    }
+
+
+    /**
+     * <p>Construct a factory create rule that will use the specified
+     * class (possibly overridden by the specified attribute if present)
+     * to create an {@link ObjectCreationFactory}, which will then be used
+     * to instantiate an object instance and push it onto the stack.</p>
+     *
+     * <p>Exceptions thrown during the object creation process will be propagated.</p>
+     *
+     * @param clazz Default Java class name of the factory class
+     * @param attributeName Attribute name which, if present, contains an
+     *  override of the class name of the object creation factory to create.
+     */
+    public FactoryCreateRule(Class clazz, String attributeName) {
+
+        this(clazz, attributeName, false);
+
+    }
+
+
+    /**
+     * <p>Construct a factory create rule using the given, already instantiated,
+     * {@link ObjectCreationFactory}.</p>
+     *
+     * <p>Exceptions thrown during the object creation process will be propagated.</p>
+     *
+     * @param creationFactory called on to create the object.
+     */
+    public FactoryCreateRule(ObjectCreationFactory creationFactory) {
+
+        this(creationFactory, false);
+
+    }
+    
+    /**
+     * Construct a factory create rule that will use the specified
+     * class name to create an {@link ObjectCreationFactory} which will
+     * then be used to create an object and push it on the stack.
+     *
+     * @param className Java class name of the object creation factory class
+     * @param ignoreCreateExceptions if true, exceptions thrown by the object
+     *  creation factory
+     * will be ignored.
+     */
+    public FactoryCreateRule(String className, boolean ignoreCreateExceptions) {
+
+        this(className, null, ignoreCreateExceptions);
+
+    }
+
+
+    /**
+     * Construct a factory create rule that will use the specified
+     * class to create an {@link ObjectCreationFactory} which will
+     * then be used to create an object and push it on the stack.
+     *
+     * @param clazz Java class name of the object creation factory class
+     * @param ignoreCreateExceptions if true, exceptions thrown by the
+     *  object creation factory
+     * will be ignored.
+     */
+    public FactoryCreateRule(Class clazz, boolean ignoreCreateExceptions) {
+
+        this(clazz, null, ignoreCreateExceptions);
+
+    }
+
+
+    /**
+     * Construct a factory create rule that will use the specified
+     * class name (possibly overridden by the specified attribute if present)
+     * to create an {@link ObjectCreationFactory}, which will then be used
+     * to instantiate an object instance and push it onto the stack.
+     *
+     * @param className Default Java class name of the factory class
+     * @param attributeName Attribute name which, if present, contains an
+     *  override of the class name of the object creation factory to create.
+     * @param ignoreCreateExceptions if true, exceptions thrown by the object
+     *  creation factory will be ignored.
+     */
+    public FactoryCreateRule(
+                                String className, 
+                                String attributeName,
+                                boolean ignoreCreateExceptions) {
+
+        this.className = className;
+        this.attributeName = attributeName;
+        this.ignoreCreateExceptions = ignoreCreateExceptions;
+
+    }
+
+
+    /**
+     * Construct a factory create rule that will use the specified
+     * class (possibly overridden by the specified attribute if present)
+     * to create an {@link ObjectCreationFactory}, which will then be used
+     * to instantiate an object instance and push it onto the stack.
+     *
+     * @param clazz Default Java class name of the factory class
+     * @param attributeName Attribute name which, if present, contains an
+     *  override of the class name of the object creation factory to create.
+     * @param ignoreCreateExceptions if true, exceptions thrown by the object
+     *  creation factory will be ignored.
+     */
+    public FactoryCreateRule(
+                                Class clazz, 
+                                String attributeName,
+                                boolean ignoreCreateExceptions) {
+
+        this(clazz.getName(), attributeName, ignoreCreateExceptions);
+
+    }
+
+
+    /**
+     * Construct a factory create rule using the given, already instantiated,
+     * {@link ObjectCreationFactory}.
+     *
+     * @param creationFactory called on to create the object.
+     * @param ignoreCreateExceptions if true, exceptions thrown by the object
+     *  creation factory will be ignored.
+     */
+    public FactoryCreateRule(
+                            ObjectCreationFactory creationFactory, 
+                            boolean ignoreCreateExceptions) {
+
+        this.creationFactory = creationFactory;
+        this.ignoreCreateExceptions = ignoreCreateExceptions;
+    }
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The attribute containing an override class name if it is present.
+     */
+    protected String attributeName = null;
+
+
+    /**
+     * The Java class name of the ObjectCreationFactory to be created.
+     * This class must have a no-arguments constructor.
+     */
+    protected String className = null;
+
+
+    /**
+     * The object creation factory we will use to instantiate objects
+     * as required based on the attributes specified in the matched XML
+     * element.
+     */
+    protected ObjectCreationFactory creationFactory = null;
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Process the beginning of this element.
+     *
+     * @param attributes The attribute list of this element
+     */
+    public void begin(String namespace, String name, Attributes attributes) throws Exception {
+        
+        if (ignoreCreateExceptions) {
+        
+            if (exceptionIgnoredStack == null) {
+                exceptionIgnoredStack = new ArrayStack();
+            }
+            
+            try {
+                Object instance = getFactory(attributes).createObject(attributes);
+                
+                if (digester.log.isDebugEnabled()) {
+                    digester.log.debug("[FactoryCreateRule]{" + digester.match +
+                            "} New " + instance.getClass().getName());
+                }
+                digester.push(instance);
+                exceptionIgnoredStack.push(Boolean.FALSE);
+                
+            } catch (Exception e) {
+                // log message and error
+                if (digester.log.isInfoEnabled()) {
+                    digester.log.info("[FactoryCreateRule] Create exception ignored: " +
+                        ((e.getMessage() == null) ? e.getClass().getName() : e.getMessage()));
+                    if (digester.log.isDebugEnabled()) {
+                        digester.log.debug("[FactoryCreateRule] Ignored exception:", e);
+                    }
+                }
+                exceptionIgnoredStack.push(Boolean.TRUE);
+            }
+            
+        } else {
+            Object instance = getFactory(attributes).createObject(attributes);
+            
+            if (digester.log.isDebugEnabled()) {
+                digester.log.debug("[FactoryCreateRule]{" + digester.match +
+                        "} New " + instance.getClass().getName());
+            }
+            digester.push(instance);
+        }
+    }
+
+
+    /**
+     * Process the end of this element.
+     */
+    public void end(String namespace, String name) throws Exception {
+        
+        // check if object was created 
+        // this only happens if an exception was thrown and we're ignoring them
+        if (	
+                ignoreCreateExceptions &&
+                exceptionIgnoredStack != null &&
+                !(exceptionIgnoredStack.empty())) {
+                
+            if (((Boolean) exceptionIgnoredStack.pop()).booleanValue()) {
+                // creation exception was ignored
+                // nothing was put onto the stack
+                if (digester.log.isTraceEnabled()) {
+                    digester.log.trace("[FactoryCreateRule] No creation so no push so no pop");
+                }
+                return;
+            }
+        } 
+
+        Object top = digester.pop();
+        if (digester.log.isDebugEnabled()) {
+            digester.log.debug("[FactoryCreateRule]{" + digester.match +
+                    "} Pop " + top.getClass().getName());
+        }
+
+    }
+
+
+    /**
+     * Clean up after parsing is complete.
+     */
+    public void finish() throws Exception {
+
+        if (attributeName != null) {
+            creationFactory = null;
+        }
+
+    }
+
+
+    /**
+     * Render a printable version of this Rule.
+     */
+    public String toString() {
+
+        StringBuffer sb = new StringBuffer("FactoryCreateRule[");
+        sb.append("className=");
+        sb.append(className);
+        sb.append(", attributeName=");
+        sb.append(attributeName);
+        if (creationFactory != null) {
+            sb.append(", creationFactory=");
+            sb.append(creationFactory);
+        }
+        sb.append("]");
+        return (sb.toString());
+
+    }
+
+
+    // ------------------------------------------------------ Protected Methods
+
+
+    /**
+     * Return an instance of our associated object creation factory,
+     * creating one if necessary.
+     *
+     * @param attributes Attributes passed to our factory creation element
+     *
+     * @exception Exception if any error occurs
+     */
+    protected ObjectCreationFactory getFactory(Attributes attributes)
+            throws Exception {
+
+        if (creationFactory == null) {
+            String realClassName = className;
+            if (attributeName != null) {
+                String value = attributes.getValue(attributeName);
+                if (value != null) {
+                    realClassName = value;
+                }
+            }
+            if (digester.log.isDebugEnabled()) {
+                digester.log.debug("[FactoryCreateRule]{" + digester.match +
+                        "} New factory " + realClassName);
+            }
+            Class clazz = digester.getClassLoader().loadClass(realClassName);
+            creationFactory = (ObjectCreationFactory)
+                    clazz.newInstance();
+            creationFactory.setDigester(digester);
+        }
+        return (creationFactory);
+
+    }    
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/digester/GenericParser.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/digester/GenericParser.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/digester/GenericParser.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,86 @@
+/* $Id: GenericParser.java 299475 2004-06-26 17:41:32Z remm $
+ *
+ * Copyright 2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.digester;
+
+import java.util.Properties;
+
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.parsers.SAXParser;
+import javax.xml.parsers.SAXParserFactory;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.xml.sax.SAXException;
+import org.xml.sax.SAXNotRecognizedException;
+
+/**
+ * Create a <code>SAXParser</code> configured to support XML Schema and DTD.
+ *
+ * @since 1.6
+ */
+
+public class GenericParser{
+
+    /**
+     * The Log to which all SAX event related logging calls will be made.
+     */
+    protected static Log log =
+        LogFactory.getLog("org.apache.commons.digester.Digester.sax");
+
+    /**
+     * The JAXP 1.2 property required to set up the schema location.
+     */
+    private static final String JAXP_SCHEMA_SOURCE =
+        "http://java.sun.com/xml/jaxp/properties/schemaSource";
+
+    /**
+     * The JAXP 1.2 property to set up the schemaLanguage used.
+     */
+    protected static String JAXP_SCHEMA_LANGUAGE =
+        "http://java.sun.com/xml/jaxp/properties/schemaLanguage";
+
+    /**
+     * Create a <code>SAXParser</code> configured to support XML Scheman and DTD
+     * @param properties parser specific properties/features
+     * @return an XML Schema/DTD enabled <code>SAXParser</code>
+     */
+    public static SAXParser newSAXParser(Properties properties)
+            throws ParserConfigurationException, 
+                   SAXException,
+                   SAXNotRecognizedException{ 
+
+        SAXParserFactory factory = 
+                        (SAXParserFactory)properties.get("SAXParserFactory");
+        SAXParser parser = factory.newSAXParser();
+        String schemaLocation = (String)properties.get("schemaLocation");
+        String schemaLanguage = (String)properties.get("schemaLanguage");
+
+        try{
+            if (schemaLocation != null) {
+                parser.setProperty(JAXP_SCHEMA_LANGUAGE, schemaLanguage);
+                parser.setProperty(JAXP_SCHEMA_SOURCE, schemaLocation);
+            }
+        } catch (SAXNotRecognizedException e){
+            log.info(parser.getClass().getName() + ": "  
+                                        + e.getMessage() + " not supported."); 
+        }
+        return parser;
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/digester/NodeCreateRule.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/digester/NodeCreateRule.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/digester/NodeCreateRule.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,428 @@
+/* $Id: NodeCreateRule.java 299765 2004-08-31 23:52:52Z yoavs $
+ *
+ * Copyright 2002-2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.digester;
+
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+
+import org.w3c.dom.Attr;
+import org.w3c.dom.DOMException;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.xml.sax.Attributes;
+import org.xml.sax.ContentHandler;
+import org.xml.sax.SAXException;
+import org.xml.sax.XMLReader;
+import org.xml.sax.helpers.DefaultHandler;
+
+
+/**
+ * A rule implementation that creates a DOM
+ * {@link org.w3c.dom.Node Node} containing the XML at the element that matched
+ * the rule. Two concrete types of nodes can be created by this rule:
+ * <ul>
+ *   <li>the default is to create an {@link org.w3c.dom.Element Element} node.
+ *   The created element will correspond to the element that matched the rule,
+ *   containing all XML content underneath that element.</li>
+ *   <li>alternatively, this rule can create nodes of type
+ *   {@link org.w3c.dom.DocumentFragment DocumentFragment}, which will contain
+ *   only the XML content under the element the rule was trigged on.</li>
+ * </ul>
+ * The created node will be normalized, meaning it will not contain text nodes 
+ * that only contain white space characters.
+ * 
+
+ * 
+ * <p>The created <code>Node</code> will be pushed on Digester's object stack
+ * when done. To use it in the context of another DOM
+ * {@link org.w3c.dom.Document Document}, it must be imported first, using the
+ * Document method
+ * {@link org.w3c.dom.Document#importNode(org.w3c.dom.Node, boolean) importNode()}.
+ * </p>
+ *
+ * <p><strong>Important Note:</strong> This is implemented by replacing the SAX
+ * {@link org.xml.sax.ContentHandler ContentHandler} in the parser used by 
+ * Digester, and resetting it when the matched element is closed. As a side 
+ * effect, rules that would match XML nodes under the element that matches 
+ * a <code>NodeCreateRule</code> will never be triggered by Digester, which 
+ * usually is the behavior one would expect.</p>
+ * 
+ * <p><strong>Note</strong> that the current implementation does not set the namespace prefixes
+ * in the exported nodes. The (usually more important) namespace URIs are set,
+ * of course.</p>
+ *
+ * @since Digester 1.4
+ */
+
+public class NodeCreateRule extends Rule {
+
+
+    // ---------------------------------------------------------- Inner Classes
+
+
+    /**
+     * The SAX content handler that does all the actual work of assembling the 
+     * DOM node tree from the SAX events.
+     */
+    private class NodeBuilder
+        extends DefaultHandler {
+
+
+        // ------------------------------------------------------- Constructors
+
+
+        /**
+         * Constructor.
+         * 
+         * <p>Stores the content handler currently used by Digester so it can 
+         * be reset when done, and initializes the DOM objects needed to 
+         * build the node.</p>
+         * 
+         * @param doc the document to use to create nodes
+         * @param root the root node
+         * @throws ParserConfigurationException if the DocumentBuilderFactory 
+         *   could not be instantiated
+         * @throws SAXException if the XMLReader could not be instantiated by 
+         *   Digester (should not happen)
+         */
+        public NodeBuilder(Document doc, Node root)
+            throws ParserConfigurationException, SAXException {
+
+            this.doc = doc;
+            this.root = root;
+            this.top = root;
+            
+            oldContentHandler = digester.getXMLReader().getContentHandler();
+
+        }
+
+
+        // ------------------------------------------------- Instance Variables
+
+
+        /**
+         * The content handler used by Digester before it was set to this 
+         * content handler.
+         */
+        protected ContentHandler oldContentHandler = null;
+
+
+        /**
+         * Depth of the current node, relative to the element where the content
+         * handler was put into action.
+         */
+        protected int depth = 0;
+
+
+        /**
+         * A DOM Document used to create the various Node instances.
+         */
+        protected Document doc = null;
+
+
+        /**
+         * The DOM node that will be pushed on Digester's stack.
+         */
+        protected Node root = null;
+
+
+        /**
+         * The current top DOM mode.
+         */
+        protected Node top = null;
+
+
+        // --------------------------------------------- ContentHandler Methods
+
+
+        /**
+         * Appends a {@link org.w3c.dom.Text Text} node to the current node.
+         * 
+         * @param ch the characters from the XML document
+         * @param start the start position in the array
+         * @param length the number of characters to read from the array
+         * @throws SAXException if the DOM implementation throws an exception
+         */
+        public void characters(char[] ch, int start, int length)
+            throws SAXException {
+
+            try {
+                String str = new String(ch, start, length);
+                if (str.trim().length() > 0) { 
+                    top.appendChild(doc.createTextNode(str));
+                }
+            } catch (DOMException e) {
+                throw new SAXException(e.getMessage());
+            }
+
+        }
+
+
+        /**
+         * Checks whether control needs to be returned to Digester.
+         * 
+         * @param namespaceURI the namespace URI
+         * @param localName the local name
+         * @param qName the qualified (prefixed) name
+         * @throws SAXException if the DOM implementation throws an exception
+         */
+        public void endElement(String namespaceURI, String localName,
+                               String qName)
+            throws SAXException {
+            
+            try {
+                if (depth == 0) {
+                    getDigester().getXMLReader().setContentHandler(
+                        oldContentHandler);
+                    getDigester().push(root);
+                    getDigester().endElement(namespaceURI, localName, qName);
+                }
+    
+                top = top.getParentNode();
+                depth--;
+            } catch (DOMException e) {
+                throw new SAXException(e.getMessage());
+            }
+
+        }
+
+
+        /**
+         * Adds a new
+         * {@link org.w3c.dom.ProcessingInstruction ProcessingInstruction} to 
+         * the current node.
+         * 
+         * @param target the processing instruction target
+         * @param data the processing instruction data, or null if none was 
+         *   supplied
+         * @throws SAXException if the DOM implementation throws an exception
+         */
+        public void processingInstruction(String target, String data)
+            throws SAXException {
+            
+            try {
+                top.appendChild(doc.createProcessingInstruction(target, data));
+            } catch (DOMException e) {
+                throw new SAXException(e.getMessage());
+            }
+
+        }
+
+
+        /**
+         * Adds a new child {@link org.w3c.dom.Element Element} to the current
+         * node.
+         * 
+         * @param namespaceURI the namespace URI
+         * @param localName the local name
+         * @param qName the qualified (prefixed) name
+         * @param atts the list of attributes
+         * @throws SAXException if the DOM implementation throws an exception
+         */
+        public void startElement(String namespaceURI, String localName,
+                                 String qName, Attributes atts)
+            throws SAXException {
+
+            try {
+                Node previousTop = top;
+                if ((localName == null) || (localName.length() == 0)) { 
+                    top = doc.createElement(qName);
+                } else {
+                    top = doc.createElementNS(namespaceURI, localName);
+                }
+                for (int i = 0; i < atts.getLength(); i++) {
+                    Attr attr = null;
+                    if ((atts.getLocalName(i) == null) ||
+                        (atts.getLocalName(i).length() == 0)) {
+                        attr = doc.createAttribute(atts.getQName(i));
+                        attr.setNodeValue(atts.getValue(i));
+                        ((Element)top).setAttributeNode(attr);
+                    } else {
+                        attr = doc.createAttributeNS(atts.getURI(i),
+                                                     atts.getLocalName(i));
+                        attr.setNodeValue(atts.getValue(i));
+                        ((Element)top).setAttributeNodeNS(attr);
+                    }
+                }
+                previousTop.appendChild(top);
+                depth++;
+            } catch (DOMException e) {
+                throw new SAXException(e.getMessage());
+            }
+
+        }
+
+    }
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Default constructor. Creates an instance of this rule that will create a
+     * DOM {@link org.w3c.dom.Element Element}.
+     */
+    public NodeCreateRule() throws ParserConfigurationException {
+
+        this(Node.ELEMENT_NODE);
+
+    }
+
+
+    /**
+     * Constructor. Creates an instance of this rule that will create a DOM
+     * {@link org.w3c.dom.Element Element}, but lets you specify the JAXP 
+     * <code>DocumentBuilder</code> that should be used when constructing the
+     * node tree.
+     * 
+     * @param documentBuilder the JAXP <code>DocumentBuilder</code> to use
+     */
+    public NodeCreateRule(DocumentBuilder documentBuilder) {
+
+        this(Node.ELEMENT_NODE, documentBuilder);
+
+    }
+
+
+    /**
+     * Constructor. Creates an instance of this rule that will create either a 
+     * DOM {@link org.w3c.dom.Element Element} or a DOM 
+     * {@link org.w3c.dom.DocumentFragment DocumentFragment}, depending on the
+     * value of the <code>nodeType</code> parameter.
+     * 
+     * @param nodeType the type of node to create, which can be either
+     *   {@link org.w3c.dom.Node#ELEMENT_NODE Node.ELEMENT_NODE} or 
+     *   {@link org.w3c.dom.Node#DOCUMENT_FRAGMENT_NODE Node.DOCUMENT_FRAGMENT_NODE}
+     * @throws IllegalArgumentException if the node type is not supported
+     */
+    public NodeCreateRule(int nodeType) throws ParserConfigurationException {
+
+        this(nodeType,
+             DocumentBuilderFactory.newInstance().newDocumentBuilder());
+
+    }
+
+
+    /**
+     * Constructor. Creates an instance of this rule that will create either a 
+     * DOM {@link org.w3c.dom.Element Element} or a DOM 
+     * {@link org.w3c.dom.DocumentFragment DocumentFragment}, depending on the
+     * value of the <code>nodeType</code> parameter. This constructor lets you
+     * specify the JAXP <code>DocumentBuilder</code> that should be used when
+     * constructing the node tree.
+     * 
+     * @param nodeType the type of node to create, which can be either
+     *   {@link org.w3c.dom.Node#ELEMENT_NODE Node.ELEMENT_NODE} or 
+     *   {@link org.w3c.dom.Node#DOCUMENT_FRAGMENT_NODE Node.DOCUMENT_FRAGMENT_NODE}
+     * @param documentBuilder the JAXP <code>DocumentBuilder</code> to use
+     * @throws IllegalArgumentException if the node type is not supported
+     */
+    public NodeCreateRule(int nodeType, DocumentBuilder documentBuilder) {
+
+        if (!((nodeType == Node.DOCUMENT_FRAGMENT_NODE) ||
+              (nodeType == Node.ELEMENT_NODE))) {
+            throw new IllegalArgumentException(
+                "Can only create nodes of type DocumentFragment and Element");
+        }
+        this.nodeType = nodeType;
+        this.documentBuilder = documentBuilder;
+
+    }
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The JAXP <code>DocumentBuilder</code> to use.
+     */
+    private DocumentBuilder documentBuilder = null;
+
+
+    /**
+     * The type of the node that should be created. Must be one of the
+     * constants defined in {@link org.w3c.dom.Node Node}, but currently only
+     * {@link org.w3c.dom.Node#ELEMENT_NODE Node.ELEMENT_NODE} and 
+     * {@link org.w3c.dom.Node#DOCUMENT_FRAGMENT_NODE Node.DOCUMENT_FRAGMENT_NODE}
+     * are allowed values.
+     */
+    private int nodeType = Node.ELEMENT_NODE;
+
+
+    // ----------------------------------------------------------- Rule Methods
+
+
+    /**
+     * Implemented to replace the content handler currently in use by a 
+     * NodeBuilder.
+     * 
+     * @param namespaceURI 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 attributes The attribute list of this element
+     * @throws Exception indicates a JAXP configuration problem
+     */
+    public void begin(String namespaceURI, String name, Attributes attributes)
+        throws Exception {
+
+        XMLReader xmlReader = getDigester().getXMLReader();
+        Document doc = documentBuilder.newDocument();
+        NodeBuilder builder = null;
+        if (nodeType == Node.ELEMENT_NODE) {
+            Element element = null;
+            if (getDigester().getNamespaceAware()) {
+                element =
+                    doc.createElementNS(namespaceURI, name);
+                for (int i = 0; i < attributes.getLength(); i++) {
+                    element.setAttributeNS(attributes.getURI(i),
+                                           attributes.getLocalName(i),
+                                           attributes.getValue(i));
+                }
+            } else {
+                element = doc.createElement(name);
+                for (int i = 0; i < attributes.getLength(); i++) {
+                    element.setAttribute(attributes.getQName(i),
+                                         attributes.getValue(i));
+                }
+            }
+            builder = new NodeBuilder(doc, element);
+        } else {
+            builder = new NodeBuilder(doc, doc.createDocumentFragment());
+        }
+        xmlReader.setContentHandler(builder);
+
+    }
+
+
+    /**
+     * Pop the Node off the top of the stack.
+     */
+    public void end() throws Exception {
+
+        Object top = digester.pop();
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/digester/ObjectCreateRule.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/digester/ObjectCreateRule.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/digester/ObjectCreateRule.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,241 @@
+/* $Id: ObjectCreateRule.java 299475 2004-06-26 17:41:32Z remm $
+ *
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.digester;
+
+
+import org.xml.sax.Attributes;
+
+
+/**
+ * Rule implementation that creates a new object and pushes it
+ * onto the object stack.  When the element is complete, the
+ * object will be popped
+ */
+
+public class ObjectCreateRule extends Rule {
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Construct an object create rule with the specified class name.
+     *
+     * @param digester The associated Digester
+     * @param className Java class name of the object to be created
+     *
+     * @deprecated The digester instance is now set in the {@link Digester#addRule} method. 
+     * Use {@link #ObjectCreateRule(String className)} instead.
+     */
+    public ObjectCreateRule(Digester digester, String className) {
+
+        this(className);
+
+    }
+
+
+    /**
+     * Construct an object create rule with the specified class.
+     *
+     * @param digester The associated Digester
+     * @param clazz Java class name of the object to be created
+     *
+     * @deprecated The digester instance is now set in the {@link Digester#addRule} method. 
+     * Use {@link #ObjectCreateRule(Class clazz)} instead.
+     */
+    public ObjectCreateRule(Digester digester, Class clazz) {
+
+        this(clazz);
+
+    }
+
+
+    /**
+     * Construct an object create rule with the specified class name and an
+     * optional attribute name containing an override.
+     *
+     * @param digester The associated Digester
+     * @param className Java class name of the object to be created
+     * @param attributeName Attribute name which, if present, contains an
+     *  override of the class name to create
+     *
+     * @deprecated The digester instance is now set in the {@link Digester#addRule} method. 
+     * Use {@link #ObjectCreateRule(String className, String attributeName)} instead.
+     */
+    public ObjectCreateRule(Digester digester, String className,
+                            String attributeName) {
+
+        this (className, attributeName);
+
+    }
+
+
+    /**
+     * Construct an object create rule with the specified class and an
+     * optional attribute name containing an override.
+     *
+     * @param digester The associated Digester
+     * @param attributeName Attribute name which, if present, contains an
+     * @param clazz Java class name of the object to be created
+     *  override of the class name to create
+     *
+     * @deprecated The digester instance is now set in the {@link Digester#addRule} method. 
+     * Use {@link #ObjectCreateRule(String attributeName, Class clazz)} instead.
+     */
+    public ObjectCreateRule(Digester digester,
+                            String attributeName,
+                            Class clazz) {
+
+        this(attributeName, clazz);
+
+    }
+
+    /**
+     * Construct an object create rule with the specified class name.
+     *
+     * @param className Java class name of the object to be created
+     */
+    public ObjectCreateRule(String className) {
+
+        this(className, (String) null);
+
+    }
+
+
+    /**
+     * Construct an object create rule with the specified class.
+     *
+     * @param clazz Java class name of the object to be created
+     */
+    public ObjectCreateRule(Class clazz) {
+
+        this(clazz.getName(), (String) null);
+
+    }
+
+
+    /**
+     * Construct an object create rule with the specified class name and an
+     * optional attribute name containing an override.
+     *
+     * @param className Java class name of the object to be created
+     * @param attributeName Attribute name which, if present, contains an
+     *  override of the class name to create
+     */
+    public ObjectCreateRule(String className,
+                            String attributeName) {
+
+        this.className = className;
+        this.attributeName = attributeName;
+
+    }
+
+
+    /**
+     * Construct an object create rule with the specified class and an
+     * optional attribute name containing an override.
+     *
+     * @param attributeName Attribute name which, if present, contains an
+     * @param clazz Java class name of the object to be created
+     *  override of the class name to create
+     */
+    public ObjectCreateRule(String attributeName,
+                            Class clazz) {
+
+        this(clazz.getName(), attributeName);
+
+    }
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The attribute containing an override class name if it is present.
+     */
+    protected String attributeName = null;
+
+
+    /**
+     * The Java class name of the object to be created.
+     */
+    protected String className = null;
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Process the beginning of this element.
+     *
+     * @param attributes The attribute list of this element
+     */
+    public void begin(Attributes attributes) throws Exception {
+
+        // Identify the name of the class to instantiate
+        String realClassName = className;
+        if (attributeName != null) {
+            String value = attributes.getValue(attributeName);
+            if (value != null) {
+                realClassName = value;
+            }
+        }
+        if (digester.log.isDebugEnabled()) {
+            digester.log.debug("[ObjectCreateRule]{" + digester.match +
+                    "}New " + realClassName);
+        }
+
+        // Instantiate the new object and push it on the context stack
+        Class clazz = digester.getClassLoader().loadClass(realClassName);
+        Object instance = clazz.newInstance();
+        digester.push(instance);
+
+    }
+
+
+    /**
+     * Process the end of this element.
+     */
+    public void end() throws Exception {
+
+        Object top = digester.pop();
+        if (digester.log.isDebugEnabled()) {
+            digester.log.debug("[ObjectCreateRule]{" + digester.match +
+                    "} Pop " + top.getClass().getName());
+        }
+
+    }
+
+
+    /**
+     * Render a printable version of this Rule.
+     */
+    public String toString() {
+
+        StringBuffer sb = new StringBuffer("ObjectCreateRule[");
+        sb.append("className=");
+        sb.append(className);
+        sb.append(", attributeName=");
+        sb.append(attributeName);
+        sb.append("]");
+        return (sb.toString());
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/digester/ObjectCreationFactory.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/digester/ObjectCreationFactory.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/digester/ObjectCreationFactory.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,59 @@
+/* $Id: ObjectCreationFactory.java 299475 2004-06-26 17:41:32Z remm $
+ *
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.digester;
+
+
+import org.xml.sax.Attributes;
+
+/**
+ * <p> Interface for use with {@link FactoryCreateRule}.
+ * The rule calls {@link #createObject} to create an object
+ * to be pushed onto the <code>Digester</code> stack
+ * whenever it is matched.</p>
+ *
+ * <p> {@link AbstractObjectCreationFactory} is an abstract
+ * implementation suitable for creating anonymous
+ * <code>ObjectCreationFactory</code> implementations.
+ */
+public interface ObjectCreationFactory {
+
+    /**
+     * <p>Factory method called by {@link FactoryCreateRule} to supply an
+     * object based on the element's attributes.
+     *
+     * @param attributes the element's attributes
+     *
+     * @throws Exception any exception thrown will be propagated upwards
+     */
+    public Object createObject(Attributes attributes) throws Exception;
+
+    /**
+     * <p>Returns the {@link Digester} that was set by the
+     * {@link FactoryCreateRule} upon initialization.
+     */
+    public Digester getDigester();
+
+    /**
+     * <p>Set the {@link Digester} to allow the implementation to do logging,
+     * classloading based on the digester's classloader, etc.
+     *
+     * @param digester parent Digester object
+     */
+    public void setDigester(Digester digester);
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/digester/ObjectParamRule.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/digester/ObjectParamRule.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/digester/ObjectParamRule.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,124 @@
+/* $Id: ObjectParamRule.java 299475 2004-06-26 17:41:32Z remm $
+ *
+ * Copyright 2002-2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.digester;
+
+import org.xml.sax.Attributes;
+
+/**
+ * <p>Rule implementation that saves a parameter for use by a surrounding
+ * <code>CallMethodRule<code>.</p>
+ *
+ * <p>This parameter may be:
+ * <ul>
+ * <li>an arbitrary Object defined programatically, assigned when the element pattern associated with the Rule is matched
+ * See {@link #ObjectParamRule(int paramIndex, Object param)}
+ * <li>an arbitrary Object defined programatically, assigned if the element pattern AND specified attribute name are matched
+ * See {@link #ObjectParamRule(int paramIndex, String attributeName, Object param)}
+ * </ul>
+ * </p>
+ *
+ * @since 1.4
+ */
+
+public class ObjectParamRule extends Rule {
+    // ----------------------------------------------------------- Constructors
+    /**
+     * Construct a "call parameter" rule that will save the given Object as
+     * the parameter value.
+     *
+     * @param paramIndex The zero-relative parameter number
+     * @param param the parameter to pass along
+     */
+    public ObjectParamRule(int paramIndex, Object param) {
+        this(paramIndex, null, param);
+    }
+
+
+    /**
+     * Construct a "call parameter" rule that will save the given Object as
+     * the parameter value, provided that the specified attribute exists.
+     *
+     * @param paramIndex The zero-relative parameter number
+     * @param attributeName The name of the attribute to match
+     * @param param the parameter to pass along
+     */
+    public ObjectParamRule(int paramIndex, String attributeName, Object param) {
+        this.paramIndex = paramIndex;
+        this.attributeName = attributeName;
+        this.param = param;
+    }
+
+
+    // ----------------------------------------------------- Instance Variables
+
+    /**
+     * The attribute which we are attempting to match
+     */
+    protected String attributeName = null;
+
+    /**
+     * The zero-relative index of the parameter we are saving.
+     */
+    protected int paramIndex = 0;
+
+    /**
+     * The parameter we wish to pass to the method call
+     */
+    protected Object param = null;
+
+
+    // --------------------------------------------------------- Public Methods
+
+    /**
+     * Process the start of this element.
+     *
+     * @param attributes The attribute list for this element
+     */
+    public void begin(String namespace, String name,
+                      Attributes attributes) throws Exception {
+        Object anAttribute = null;
+        Object parameters[] = (Object[]) digester.peekParams();
+
+        if (attributeName != null) {
+            anAttribute = attributes.getValue(attributeName);
+            if(anAttribute != null) {
+                parameters[paramIndex] = param;
+            }
+            // note -- if attributeName != null and anAttribute == null, this rule
+            // will pass null as its parameter!
+        }else{
+            parameters[paramIndex] = param;
+        }
+    }
+
+    /**
+     * Render a printable version of this Rule.
+     */
+    public String toString() {
+        StringBuffer sb = new StringBuffer("ObjectParamRule[");
+        sb.append("paramIndex=");
+        sb.append(paramIndex);
+        sb.append(", attributeName=");
+        sb.append(attributeName);
+        sb.append(", param=");
+        sb.append(param);
+        sb.append("]");
+        return (sb.toString());
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/digester/ParserFeatureSetterFactory.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/digester/ParserFeatureSetterFactory.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/digester/ParserFeatureSetterFactory.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,74 @@
+/* $Id: ParserFeatureSetterFactory.java 299475 2004-06-26 17:41:32Z remm $
+ *
+ * Copyright 2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.digester;
+
+import java.util.Properties;
+
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.parsers.SAXParser;
+
+import org.xml.sax.SAXException;
+import org.xml.sax.SAXNotRecognizedException;
+import org.xml.sax.SAXNotSupportedException;
+
+/**
+ * Creates a <code>SAXParser</code> based on the underlying parser.
+ * Allows logical properties depending on logical parser versions
+ * to be set.
+ *
+ * @since 1.6
+ */
+public class ParserFeatureSetterFactory{
+
+    /**
+     * <code>true</code> is Xerces is used.
+     */
+    private static boolean isXercesUsed; 
+
+    static {
+        try{
+            // Use reflection to avoid a build dependency with Xerces.
+            Class versionClass = 
+                            Class.forName("org.apache.xerces.impl.Version");
+            isXercesUsed = true;
+        } catch (Exception ex){
+            isXercesUsed = false;
+        }
+    }
+
+    /**
+     * Create a new <code>SAXParser</code>
+     * @param properties (logical) properties to be set on parser
+     * @return a <code>SAXParser</code> configured based on the underlying
+     * parser implementation.
+     */
+    public static SAXParser newSAXParser(Properties properties)
+            throws ParserConfigurationException, 
+                   SAXException,
+                   SAXNotRecognizedException, 
+                   SAXNotSupportedException {
+
+        if (isXercesUsed){
+            return XercesParser.newSAXParser(properties);
+        } else {
+            return GenericParser.newSAXParser(properties);
+        }
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/digester/PathCallParamRule.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/digester/PathCallParamRule.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/digester/PathCallParamRule.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,93 @@
+/* $Id: PathCallParamRule.java 299475 2004-06-26 17:41:32Z remm $
+ *
+ * Copyright 2003-2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.digester;
+
+
+import org.xml.sax.Attributes;
+
+/**
+ * <p>Rule implementation that saves a parameter containing the 
+ * <code>Digester</code> matching path for use by a surrounding 
+ * <code>CallMethodRule</code>. This Rule is most useful when making 
+ * extensive use of wildcards in rule patterns.</p>
+ *
+ * @since 1.6
+ */
+
+public class PathCallParamRule extends Rule {
+
+    // ----------------------------------------------------------- Constructors
+
+    /**
+     * Construct a "call parameter" rule that will save the body text of this
+     * element as the parameter value.
+     *
+     * @param paramIndex The zero-relative parameter number
+     */
+    public PathCallParamRule(int paramIndex) {
+
+        this.paramIndex = paramIndex;
+
+    }
+ 
+    // ----------------------------------------------------- Instance Variables
+
+    /**
+     * The zero-relative index of the parameter we are saving.
+     */
+    protected int paramIndex = 0;
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Process the start 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 attributes The attribute list for this element
+
+     */
+    public void begin(String namespace, String name, Attributes attributes) throws Exception {
+
+        String param = getDigester().getMatch();
+        
+        if(param != null) {
+            Object parameters[] = (Object[]) digester.peekParams();
+            parameters[paramIndex] = param;
+        }
+        
+    }
+
+    /**
+     * Render a printable version of this Rule.
+     */
+    public String toString() {
+
+        StringBuffer sb = new StringBuffer("PathCallParamRule[");
+        sb.append("paramIndex=");
+        sb.append(paramIndex);
+        sb.append("]");
+        return (sb.toString());
+
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/digester/Rule.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/digester/Rule.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/digester/Rule.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,244 @@
+/* $Id: Rule.java 299475 2004-06-26 17:41:32Z remm $
+ *
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.digester;
+
+
+import org.xml.sax.Attributes;
+
+
+/**
+ * Concrete implementations of this class implement actions to be taken when
+ * a corresponding nested pattern of XML elements has been matched.
+ */
+
+public abstract class Rule {
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Constructor sets the associated Digester.
+     *
+     * @param digester The digester with which this rule is associated
+     * @deprecated The digester instance is now set in the {@link Digester#addRule} method. Use {@link #Rule()} instead.
+     */
+    public Rule(Digester digester) {
+
+        super();
+        setDigester(digester);
+
+    }
+    
+    /**
+     * <p>Base constructor.
+     * Now the digester will be set when the rule is added.</p>
+     */
+    public Rule() {}
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The Digester with which this Rule is associated.
+     */
+    protected Digester digester = null;
+
+
+    /**
+     * The namespace URI for which this Rule is relevant, if any.
+     */
+    protected String namespaceURI = null;
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * Return the Digester with which this Rule is associated.
+     */
+    public Digester getDigester() {
+
+        return (this.digester);
+
+    }
+    
+    /**
+     * Set the <code>Digester</code> with which this <code>Rule</code> is associated.
+     */
+    public void setDigester(Digester digester) {
+        
+        this.digester = digester;
+        
+    }
+
+    /**
+     * Return the namespace URI for which this Rule is relevant, if any.
+     */
+    public String getNamespaceURI() {
+
+        return (this.namespaceURI);
+
+    }
+
+
+    /**
+     * Set the namespace URI for which this Rule is relevant, if any.
+     *
+     * @param namespaceURI Namespace URI for which this Rule is relevant,
+     *  or <code>null</code> to match independent of namespace.
+     */
+    public void setNamespaceURI(String namespaceURI) {
+
+        this.namespaceURI = namespaceURI;
+
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * This method is called when the beginning of a matching XML element
+     * is encountered.
+     *
+     * @param attributes The attribute list of this element
+     * @deprecated Use the {@link #begin(String,String,Attributes) begin}
+     *   method with <code>namespace</code> and <code>name</code>
+     *   parameters instead.
+     */
+    public void begin(Attributes attributes) throws Exception {
+
+        ;	// The default implementation does nothing
+
+    }
+
+
+    /**
+     * This method is called when the beginning of a matching XML element
+     * is encountered. The default implementation delegates to the deprecated
+     * method {@link #begin(Attributes) begin} without the 
+     * <code>namespace</code> and <code>name</code> parameters, to retain 
+     * backwards compatibility.
+     *
+     * @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 attributes The attribute list of this element
+     * @since Digester 1.4
+     */
+    public void begin(String namespace, String name, Attributes attributes)
+        throws Exception {
+
+        begin(attributes);
+
+    }
+
+
+    /**
+     * This method is called when the body of a matching XML element
+     * is encountered.  If the element has no body, this method is
+     * not called at all.
+     *
+     * @param text The text of the body of this element
+     * @deprecated Use the {@link #body(String,String,String) body} method
+     *   with <code>namespace</code> and <code>name</code> parameters
+     *   instead.
+     */
+    public void body(String text) throws Exception {
+
+        ;	// The default implementation does nothing
+
+    }
+
+
+    /**
+     * This method is called when the body of a matching XML element is 
+     * encountered.  If the element has no body, this method is not called at 
+     * all. The default implementation delegates to the deprecated method 
+     * {@link #body(String) body} without the <code>namespace</code> and
+     * <code>name</code> parameters, to retain backwards compatibility.
+     *
+     * @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 text of the body of this element
+     * @since Digester 1.4
+     */
+    public void body(String namespace, String name, String text)
+        throws Exception {
+
+        body(text);
+
+    }
+
+
+    /**
+     * This method is called when the end of a matching XML element
+     * is encountered.
+     * 
+     * @deprecated Use the {@link #end(String,String) end} method with 
+     *   <code>namespace</code> and <code>name</code> parameters instead.
+     */
+    public void end() throws Exception {
+
+        ;	// The default implementation does nothing
+
+    }
+
+
+    /**
+     * This method is called when the end of a matching XML element
+     * is encountered. The default implementation delegates to the deprecated
+     * method {@link #end end} without the 
+     * <code>namespace</code> and <code>name</code> parameters, to retain 
+     * backwards compatibility.
+     *
+     * @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
+     * @since Digester 1.4
+     */
+    public void end(String namespace, String name)
+        throws Exception {
+
+        end();
+
+    }
+
+
+    /**
+     * This method is called after all parsing methods have been
+     * called, to allow Rules to remove temporary data.
+     */
+    public void finish() throws Exception {
+
+        ;	// The default implementation does nothing
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/digester/RuleSet.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/digester/RuleSet.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/digester/RuleSet.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,66 @@
+/* $Id: RuleSet.java 299475 2004-06-26 17:41:32Z remm $
+ *
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.digester;
+
+
+/**
+ * <p>Public interface defining a shorthand means of configuring a complete
+ * set of related <code>Rule</code> definitions, possibly associated with
+ * a particular namespace URI, in one operation.  To use an instance of a
+ * class that imlements this interface:</p>
+ * <ul>
+ * <li>Create a concrete implementation of this interface.</li>
+ * <li>Optionally, you can configure a <code>RuleSet</code> to be relevant
+ *     only for a particular namespace URI by configuring the value to be
+ *     returned by <code>getNamespaceURI()</code>.</li>
+ * <li>As you are configuring your Digester instance, call
+ *     <code>digester.addRuleSet()</code> and pass the RuleSet instance.</li>
+ * <li>Digester will call the <code>addRuleInstances()</code> method of
+ *     your RuleSet to configure the necessary rules.</li>
+ * </ul>
+ */
+
+public interface RuleSet {
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * Return the namespace URI that will be applied to all Rule instances
+     * created from this RuleSet.
+     */
+    public String getNamespaceURI();
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Add the set of Rule instances defined in this RuleSet to the
+     * specified <code>Digester</code> instance, associating them with
+     * our namespace URI (if any).  This method should only be called
+     * by a Digester instance.
+     *
+     * @param digester Digester instance to which the new Rule instances
+     *  should be added.
+     */
+    public void addRuleInstances(Digester digester);
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/digester/RuleSetBase.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/digester/RuleSetBase.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/digester/RuleSetBase.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,70 @@
+/* $Id: RuleSetBase.java 299475 2004-06-26 17:41:32Z remm $
+ *
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.digester;
+
+
+/**
+ * <p>Convenience base class that implements the {@link RuleSet} interface.
+ * Concrete implementations should list all of their actual rule creation
+ * logic in the <code>addRuleSet()</code> implementation.</p>
+ */
+
+public abstract class RuleSetBase implements RuleSet {
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The namespace URI that all Rule instances created by this RuleSet
+     * will be associated with.
+     */
+    protected String namespaceURI = null;
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * Return the namespace URI that will be applied to all Rule instances
+     * created from this RuleSet.
+     */
+    public String getNamespaceURI() {
+
+        return (this.namespaceURI);
+
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Add the set of Rule instances defined in this RuleSet to the
+     * specified <code>Digester</code> instance, associating them with
+     * our namespace URI (if any).  This method should only be called
+     * by a Digester instance.
+     *
+     * @param digester Digester instance to which the new Rule instances
+     *  should be added.
+     */
+    public abstract void addRuleInstances(Digester digester);
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/digester/Rules.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/digester/Rules.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/digester/Rules.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,127 @@
+/* $Id: Rules.java 299475 2004-06-26 17:41:32Z remm $
+ *
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.digester;
+
+
+import java.util.List;
+
+
+/**
+ * Public interface defining a collection of Rule instances (and corresponding
+ * matching patterns) plus an implementation of a matching policy that selects
+ * the rules that match a particular pattern of nested elements discovered
+ * during parsing.
+ */
+
+public interface Rules {
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * Return the Digester instance with which this Rules instance is
+     * associated.
+     */
+    public Digester getDigester();
+
+
+    /**
+     * Set the Digester instance with which this Rules instance is associated.
+     *
+     * @param digester The newly associated Digester instance
+     */
+    public void setDigester(Digester digester);
+
+
+    /**
+     * Return the namespace URI that will be applied to all subsequently
+     * added <code>Rule</code> objects.
+     */
+    public String getNamespaceURI();
+
+
+    /**
+     * Set the namespace URI that will be applied to all subsequently
+     * added <code>Rule</code> objects.
+     *
+     * @param namespaceURI Namespace URI that must match on all
+     *  subsequently added rules, or <code>null</code> for matching
+     *  regardless of the current namespace URI
+     */
+    public void setNamespaceURI(String namespaceURI);
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Register a new Rule instance matching the specified pattern.
+     *
+     * @param pattern Nesting pattern to be matched for this Rule
+     * @param rule Rule instance to be registered
+     */
+    public void add(String pattern, Rule rule);
+
+
+    /**
+     * Clear all existing Rule instance registrations.
+     */
+    public void clear();
+
+
+    /**
+     * Return a List of all registered Rule instances that match the specified
+     * nesting pattern, or a zero-length List if there are no matches.  If more
+     * than one Rule instance matches, they <strong>must</strong> be returned
+     * in the order originally registered through the <code>add()</code>
+     * method.
+     *
+     * @param pattern Nesting pattern to be matched
+     *
+     * @deprecated Call match(namespaceURI,pattern) instead.
+     */
+    public List match(String pattern);
+
+
+    /**
+     * Return a List of all registered Rule instances that match the specified
+     * nesting pattern, or a zero-length List if there are no matches.  If more
+     * than one Rule instance matches, they <strong>must</strong> be returned
+     * in the order originally registered through the <code>add()</code>
+     * method.
+     *
+     * @param namespaceURI Namespace URI for which to select matching rules,
+     *  or <code>null</code> to match regardless of namespace URI
+     * @param pattern Nesting pattern to be matched
+     */
+    public List match(String namespaceURI, String pattern);
+
+
+    /**
+     * Return a List of all registered Rule instances, or a zero-length List
+     * if there are no registered Rule instances.  If more than one Rule
+     * instance has been registered, they <strong>must</strong> be returned
+     * in the order originally registered through the <code>add()</code>
+     * method.
+     */
+    public List rules();
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/digester/RulesBase.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/digester/RulesBase.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/digester/RulesBase.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,293 @@
+/* $Id: RulesBase.java 299475 2004-06-26 17:41:32Z remm $
+ *
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.digester;
+
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+
+
+/**
+ * <p>Default implementation of the <code>Rules</code> interface that supports
+ * the standard rule matching behavior.  This class can also be used as a
+ * base class for specialized <code>Rules</code> implementations.</p>
+ *
+ * <p>The matching policies implemented by this class support two different
+ * types of pattern matching rules:</p>
+ * <ul>
+ * <li><em>Exact Match</em> - A pattern "a/b/c" exactly matches a
+ *     <code>&lt;c&gt;</code> element, nested inside a <code>&lt;b&gt;</code>
+ *     element, which is nested inside an <code>&lt;a&gt;</code> element.</li>
+ * <li><em>Tail Match</em> - A pattern "&#42;/a/b" matches a
+ *     <code>&lt;b&gt;</code> element, nested inside an <code>&lt;a&gt;</code>
+ *      element, no matter how deeply the pair is nested.</li>
+ * </ul>
+ */
+
+public class RulesBase implements Rules {
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The set of registered Rule instances, keyed by the matching pattern.
+     * Each value is a List containing the Rules for that pattern, in the
+     * order that they were orginally registered.
+     */
+    protected HashMap cache = new HashMap();
+
+
+    /**
+     * The Digester instance with which this Rules instance is associated.
+     */
+    protected Digester digester = null;
+
+
+    /**
+     * The namespace URI for which subsequently added <code>Rule</code>
+     * objects are relevant, or <code>null</code> for matching independent
+     * of namespaces.
+     */
+    protected String namespaceURI = null;
+
+
+    /**
+     * The set of registered Rule instances, in the order that they were
+     * originally registered.
+     */
+    protected ArrayList rules = new ArrayList();
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * Return the Digester instance with which this Rules instance is
+     * associated.
+     */
+    public Digester getDigester() {
+
+        return (this.digester);
+
+    }
+
+
+    /**
+     * Set the Digester instance with which this Rules instance is associated.
+     *
+     * @param digester The newly associated Digester instance
+     */
+    public void setDigester(Digester digester) {
+
+        this.digester = digester;
+        Iterator items = rules.iterator();
+        while (items.hasNext()) {
+            Rule item = (Rule) items.next();
+            item.setDigester(digester);
+        }
+
+    }
+
+
+    /**
+     * Return the namespace URI that will be applied to all subsequently
+     * added <code>Rule</code> objects.
+     */
+    public String getNamespaceURI() {
+
+        return (this.namespaceURI);
+
+    }
+
+
+    /**
+     * Set the namespace URI that will be applied to all subsequently
+     * added <code>Rule</code> objects.
+     *
+     * @param namespaceURI Namespace URI that must match on all
+     *  subsequently added rules, or <code>null</code> for matching
+     *  regardless of the current namespace URI
+     */
+    public void setNamespaceURI(String namespaceURI) {
+
+        this.namespaceURI = namespaceURI;
+
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Register a new Rule instance matching the specified pattern.
+     *
+     * @param pattern Nesting pattern to be matched for this Rule
+     * @param rule Rule instance to be registered
+     */
+    public void add(String pattern, Rule rule) {
+        // to help users who accidently add '/' to the end of their patterns
+        int patternLength = pattern.length();
+        if (patternLength>1 && pattern.endsWith("/")) {
+            pattern = pattern.substring(0, patternLength-1);
+        }
+        
+        
+        List list = (List) cache.get(pattern);
+        if (list == null) {
+            list = new ArrayList();
+            cache.put(pattern, list);
+        }
+        list.add(rule);
+        rules.add(rule);
+        if (this.digester != null) {
+            rule.setDigester(this.digester);
+        }
+        if (this.namespaceURI != null) {
+            rule.setNamespaceURI(this.namespaceURI);
+        }
+
+    }
+
+
+    /**
+     * Clear all existing Rule instance registrations.
+     */
+    public void clear() {
+
+        cache.clear();
+        rules.clear();
+
+    }
+
+
+    /**
+     * Return a List of all registered Rule instances that match the specified
+     * nesting pattern, or a zero-length List if there are no matches.  If more
+     * than one Rule instance matches, they <strong>must</strong> be returned
+     * in the order originally registered through the <code>add()</code>
+     * method.
+     *
+     * @param pattern Nesting pattern to be matched
+     *
+     * @deprecated Call match(namespaceURI,pattern) instead.
+     */
+    public List match(String pattern) {
+
+        return (match(null, pattern));
+
+    }
+
+
+    /**
+     * Return a List of all registered Rule instances that match the specified
+     * nesting pattern, or a zero-length List if there are no matches.  If more
+     * than one Rule instance matches, they <strong>must</strong> be returned
+     * in the order originally registered through the <code>add()</code>
+     * method.
+     *
+     * @param namespaceURI Namespace URI for which to select matching rules,
+     *  or <code>null</code> to match regardless of namespace URI
+     * @param pattern Nesting pattern to be matched
+     */
+    public List match(String namespaceURI, String pattern) {
+
+        // List rulesList = (List) this.cache.get(pattern);
+        List rulesList = lookup(namespaceURI, pattern);
+        if ((rulesList == null) || (rulesList.size() < 1)) {
+            // Find the longest key, ie more discriminant
+            String longKey = "";
+            Iterator keys = this.cache.keySet().iterator();
+            while (keys.hasNext()) {
+                String key = (String) keys.next();
+                if (key.startsWith("*/")) {
+                    if (pattern.equals(key.substring(2)) ||
+                        pattern.endsWith(key.substring(1))) {
+                        if (key.length() > longKey.length()) {
+                            // rulesList = (List) this.cache.get(key);
+                            rulesList = lookup(namespaceURI, key);
+                            longKey = key;
+                        }
+                    }
+                }
+            }
+        }
+        if (rulesList == null) {
+            rulesList = new ArrayList();
+        }
+        return (rulesList);
+
+    }
+
+
+    /**
+     * Return a List of all registered Rule instances, or a zero-length List
+     * if there are no registered Rule instances.  If more than one Rule
+     * instance has been registered, they <strong>must</strong> be returned
+     * in the order originally registered through the <code>add()</code>
+     * method.
+     */
+    public List rules() {
+
+        return (this.rules);
+
+    }
+
+
+    // ------------------------------------------------------ Protected Methods
+
+
+    /**
+     * Return a List of Rule instances for the specified pattern that also
+     * match the specified namespace URI (if any).  If there are no such
+     * rules, return <code>null</code>.
+     *
+     * @param namespaceURI Namespace URI to match, or <code>null</code> to
+     *  select matching rules regardless of namespace URI
+     * @param pattern Pattern to be matched
+     */
+    protected List lookup(String namespaceURI, String pattern) {
+
+        // Optimize when no namespace URI is specified
+        List list = (List) this.cache.get(pattern);
+        if (list == null) {
+            return (null);
+        }
+        if ((namespaceURI == null) || (namespaceURI.length() == 0)) {
+            return (list);
+        }
+
+        // Select only Rules that match on the specified namespace URI
+        ArrayList results = new ArrayList();
+        Iterator items = list.iterator();
+        while (items.hasNext()) {
+            Rule item = (Rule) items.next();
+            if ((namespaceURI.equals(item.getNamespaceURI())) ||
+                    (item.getNamespaceURI() == null)) {
+                results.add(item);
+            }
+        }
+        return (results);
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/digester/SetNextRule.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/digester/SetNextRule.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/digester/SetNextRule.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,214 @@
+/* $Id: SetNextRule.java 299475 2004-06-26 17:41:32Z remm $
+ *
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.digester;
+
+import org.apache.tomcat.util.IntrospectionUtils;
+
+
+/**
+ * <p>Rule implementation that calls a method on the (top-1) (parent)
+ * object, passing the top object (child) as an argument.  It is
+ * commonly used to establish parent-child relationships.</p>
+ *
+ * <p>This rule now supports more flexible method matching by default.
+ * It is possible that this may break (some) code 
+ * written against release 1.1.1 or earlier.
+ * See {@link #isExactMatch()} for more details.</p> 
+ */
+
+public class SetNextRule extends Rule {
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Construct a "set next" rule with the specified method name.  The
+     * method's argument type is assumed to be the class of the
+     * child object.
+     *
+     * @param digester The associated Digester
+     * @param methodName Method name of the parent method to call
+     *
+     * @deprecated The digester instance is now set in the {@link Digester#addRule} method. 
+     * Use {@link #SetNextRule(String methodName)} instead.
+     */
+    public SetNextRule(Digester digester, String methodName) {
+
+        this(methodName);
+
+    }
+
+
+    /**
+     * Construct a "set next" rule with the specified method name.
+     *
+     * @param digester The associated Digester
+     * @param methodName Method name of the parent method to call
+     * @param paramType Java class of the parent method's argument
+     *  (if you wish to use a primitive type, specify the corresonding
+     *  Java wrapper class instead, such as <code>java.lang.Boolean</code>
+     *  for a <code>boolean</code> parameter)
+     *
+     * @deprecated The digester instance is now set in the {@link Digester#addRule} method. 
+     * Use {@link #SetNextRule(String methodName,String paramType)} instead.
+     */
+    public SetNextRule(Digester digester, String methodName,
+                       String paramType) {
+
+        this(methodName, paramType);
+
+    }
+
+    /**
+     * Construct a "set next" rule with the specified method name.  The
+     * method's argument type is assumed to be the class of the
+     * child object.
+     *
+     * @param methodName Method name of the parent method to call
+     */
+    public SetNextRule(String methodName) {
+
+        this(methodName, null);
+
+    }
+
+
+    /**
+     * Construct a "set next" rule with the specified method name.
+     *
+     * @param methodName Method name of the parent method to call
+     * @param paramType Java class of the parent method's argument
+     *  (if you wish to use a primitive type, specify the corresonding
+     *  Java wrapper class instead, such as <code>java.lang.Boolean</code>
+     *  for a <code>boolean</code> parameter)
+     */
+    public SetNextRule(String methodName,
+                       String paramType) {
+
+        this.methodName = methodName;
+        this.paramType = paramType;
+
+    }
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The method name to call on the parent object.
+     */
+    protected String methodName = null;
+
+
+    /**
+     * The Java class name of the parameter type expected by the method.
+     */
+    protected String paramType = null;
+
+    /**
+     * Should we use exact matching. Default is no.
+     */
+    protected boolean useExactMatch = false;
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * <p>Is exact matching being used.</p>
+     *
+     * <p>This rule uses <code>org.apache.commons.beanutils.MethodUtils</code> 
+     * to introspect the relevent objects so that the right method can be called.
+     * Originally, <code>MethodUtils.invokeExactMethod</code> was used.
+     * This matches methods very strictly 
+     * and so may not find a matching method when one exists.
+     * This is still the behaviour when exact matching is enabled.</p>
+     *
+     * <p>When exact matching is disabled, <code>MethodUtils.invokeMethod</code> is used.
+     * This method finds more methods but is less precise when there are several methods 
+     * with correct signatures.
+     * So, if you want to choose an exact signature you might need to enable this property.</p>
+     *
+     * <p>The default setting is to disable exact matches.</p>
+     *
+     * @return true iff exact matching is enabled
+     * @since Digester Release 1.1.1
+     */
+    public boolean isExactMatch() {
+    
+        return useExactMatch;
+    }
+    
+    /**
+     * <p>Set whether exact matching is enabled.</p>
+     *
+     * <p>See {@link #isExactMatch()}.</p>
+     *
+     * @param useExactMatch should this rule use exact method matching
+     * @since Digester Release 1.1.1
+     */    
+    public void setExactMatch(boolean useExactMatch) {
+
+        this.useExactMatch = useExactMatch;
+    }
+
+    /**
+     * Process the end of this element.
+     */
+    public void end() throws Exception {
+
+        // Identify the objects to be used
+        Object child = digester.peek(0);
+        Object parent = digester.peek(1);
+        if (digester.log.isDebugEnabled()) {
+            if (parent == null) {
+                digester.log.debug("[SetNextRule]{" + digester.match +
+                        "} Call [NULL PARENT]." +
+                        methodName + "(" + child + ")");
+            } else {
+                digester.log.debug("[SetNextRule]{" + digester.match +
+                        "} Call " + parent.getClass().getName() + "." +
+                        methodName + "(" + child + ")");
+            }
+        }
+
+        // Call the specified method
+        IntrospectionUtils.callMethod1(parent, methodName,
+                child, paramType, digester.getClassLoader());
+                
+    }
+
+
+    /**
+     * Render a printable version of this Rule.
+     */
+    public String toString() {
+
+        StringBuffer sb = new StringBuffer("SetNextRule[");
+        sb.append("methodName=");
+        sb.append(methodName);
+        sb.append(", paramType=");
+        sb.append(paramType);
+        sb.append("]");
+        return (sb.toString());
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/digester/SetPropertiesRule.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/digester/SetPropertiesRule.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/digester/SetPropertiesRule.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,261 @@
+/* $Id: SetPropertiesRule.java 299475 2004-06-26 17:41:32Z remm $
+ *
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.digester;
+
+
+import org.apache.tomcat.util.IntrospectionUtils;
+import org.xml.sax.Attributes;
+
+
+/**
+ * <p>Rule implementation that sets properties on the object at the top of the
+ * stack, based on attributes with corresponding names.</p>
+ *
+ * <p>This rule supports custom mapping of attribute names to property names.
+ * The default mapping for particular attributes can be overridden by using 
+ * {@link #SetPropertiesRule(String[] attributeNames, String[] propertyNames)}.
+ * This allows attributes to be mapped to properties with different names.
+ * Certain attributes can also be marked to be ignored.</p>
+ */
+
+public class SetPropertiesRule extends Rule {
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Default constructor sets only the the associated Digester.
+     *
+     * @param digester The digester with which this rule is associated
+     *
+     * @deprecated The digester instance is now set in the {@link Digester#addRule} method. 
+     * Use {@link #SetPropertiesRule()} instead.
+     */
+    public SetPropertiesRule(Digester digester) {
+
+        this();
+
+    }
+    
+
+    /**
+     * Base constructor.
+     */
+    public SetPropertiesRule() {
+
+        // nothing to set up 
+
+    }
+    
+    /** 
+     * <p>Convenience constructor overrides the mapping for just one property.</p>
+     *
+     * <p>For details about how this works, see
+     * {@link #SetPropertiesRule(String[] attributeNames, String[] propertyNames)}.</p>
+     *
+     * @param attributeName map this attribute 
+     * @param propertyName to a property with this name
+     */
+    public SetPropertiesRule(String attributeName, String propertyName) {
+        
+        attributeNames = new String[1];
+        attributeNames[0] = attributeName;
+        propertyNames = new String[1];
+        propertyNames[0] = propertyName;
+    }
+    
+    /** 
+     * <p>Constructor allows attribute->property mapping to be overriden.</p>
+     *
+     * <p>Two arrays are passed in. 
+     * One contains the attribute names and the other the property names.
+     * The attribute name / property name pairs are match by position
+     * In order words, the first string in the attribute name list matches
+     * to the first string in the property name list and so on.</p>
+     *
+     * <p>If a property name is null or the attribute name has no matching
+     * property name, then this indicates that the attibute should be ignored.</p>
+     * 
+     * <h5>Example One</h5>
+     * <p> The following constructs a rule that maps the <code>alt-city</code>
+     * attribute to the <code>city</code> property and the <code>alt-state</code>
+     * to the <code>state</code> property. 
+     * All other attributes are mapped as usual using exact name matching.
+     * <code><pre>
+     *      SetPropertiesRule(
+     *                new String[] {"alt-city", "alt-state"}, 
+     *                new String[] {"city", "state"});
+     * </pre></code>
+     *
+     * <h5>Example Two</h5>
+     * <p> The following constructs a rule that maps the <code>class</code>
+     * attribute to the <code>className</code> property.
+     * The attribute <code>ignore-me</code> is not mapped.
+     * All other attributes are mapped as usual using exact name matching.
+     * <code><pre>
+     *      SetPropertiesRule(
+     *                new String[] {"class", "ignore-me"}, 
+     *                new String[] {"className"});
+     * </pre></code>
+     *
+     * @param attributeNames names of attributes to map
+     * @param propertyNames names of properties mapped to
+     */
+    public SetPropertiesRule(String[] attributeNames, String[] propertyNames) {
+        // create local copies
+        this.attributeNames = new String[attributeNames.length];
+        for (int i=0, size=attributeNames.length; i<size; i++) {
+            this.attributeNames[i] = attributeNames[i];
+        }
+        
+        this.propertyNames = new String[propertyNames.length];
+        for (int i=0, size=propertyNames.length; i<size; i++) {
+            this.propertyNames[i] = propertyNames[i];
+        } 
+    }
+        
+    // ----------------------------------------------------- Instance Variables
+    
+    /** 
+     * Attribute names used to override natural attribute->property mapping
+     */
+    private String [] attributeNames;
+    /** 
+     * Property names used to override natural attribute->property mapping
+     */    
+    private String [] propertyNames;
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Process the beginning of this element.
+     *
+     * @param attributes The attribute list of this element
+     */
+    public void begin(Attributes attributes) throws Exception {
+        
+        // Populate the corresponding properties of the top object
+        Object top = digester.peek();
+        if (digester.log.isDebugEnabled()) {
+            if (top != null) {
+                digester.log.debug("[SetPropertiesRule]{" + digester.match +
+                                   "} Set " + top.getClass().getName() +
+                                   " properties");
+            } else {
+                digester.log.debug("[SetPropertiesRule]{" + digester.match +
+                                   "} Set NULL properties");
+            }
+        }
+        
+        // set up variables for custom names mappings
+        int attNamesLength = 0;
+        if (attributeNames != null) {
+            attNamesLength = attributeNames.length;
+        }
+        int propNamesLength = 0;
+        if (propertyNames != null) {
+            propNamesLength = propertyNames.length;
+        }
+        
+        for (int i = 0; i < attributes.getLength(); i++) {
+            String name = attributes.getLocalName(i);
+            if ("".equals(name)) {
+                name = attributes.getQName(i);
+            }
+            String value = attributes.getValue(i);
+            
+            // we'll now check for custom mappings
+            for (int n = 0; n<attNamesLength; n++) {
+                if (name.equals(attributeNames[n])) {
+                    if (n < propNamesLength) {
+                        // set this to value from list
+                        name = propertyNames[n];
+                    
+                    } else {
+                        // set name to null
+                        // we'll check for this later
+                        name = null;
+                    }
+                    break;
+                }
+            } 
+            
+            if (digester.log.isDebugEnabled()) {
+                digester.log.debug("[SetPropertiesRule]{" + digester.match +
+                        "} Setting property '" + name + "' to '" +
+                        value + "'");
+            }
+            IntrospectionUtils.setProperty(top, name, value);
+        }
+
+    }
+
+
+    /**
+     * <p>Add an additional attribute name to property name mapping.
+     * This is intended to be used from the xml rules.
+     */
+    public void addAlias(String attributeName, String propertyName) {
+        
+        // this is a bit tricky.
+        // we'll need to resize the array.
+        // probably should be synchronized but digester's not thread safe anyway
+        if (attributeNames == null) {
+            
+            attributeNames = new String[1];
+            attributeNames[0] = attributeName;
+            propertyNames = new String[1];
+            propertyNames[0] = propertyName;        
+            
+        } else {
+            int length = attributeNames.length;
+            String [] tempAttributes = new String[length + 1];
+            for (int i=0; i<length; i++) {
+                tempAttributes[i] = attributeNames[i];
+            }
+            tempAttributes[length] = attributeName;
+            
+            String [] tempProperties = new String[length + 1];
+            for (int i=0; i<length && i< propertyNames.length; i++) {
+                tempProperties[i] = propertyNames[i];
+            }
+            tempProperties[length] = propertyName;
+            
+            propertyNames = tempProperties;
+            attributeNames = tempAttributes;
+        }        
+    }
+  
+
+    /**
+     * Render a printable version of this Rule.
+     */
+    public String toString() {
+
+        StringBuffer sb = new StringBuffer("SetPropertiesRule[");
+        sb.append("]");
+        return (sb.toString());
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/digester/SetPropertyRule.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/digester/SetPropertyRule.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/digester/SetPropertyRule.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,149 @@
+/* $Id: SetPropertyRule.java 299475 2004-06-26 17:41:32Z remm $
+ *
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.digester;
+
+
+import org.apache.tomcat.util.IntrospectionUtils;
+import org.xml.sax.Attributes;
+
+
+/**
+ * Rule implementation that sets an individual property on the object at the
+ * top of the stack, based on attributes with specified names.
+ */
+
+public class SetPropertyRule extends Rule {
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Construct a "set property" rule with the specified name and value
+     * attributes.
+     *
+     * @param digester The digester with which this rule is associated
+     * @param name Name of the attribute that will contain the name of the
+     *  property to be set
+     * @param value Name of the attribute that will contain the value to which
+     *  the property should be set
+     *
+     * @deprecated The digester instance is now set in the {@link Digester#addRule} method. 
+     * Use {@link #SetPropertyRule(String name, String value)} instead.
+     */
+    public SetPropertyRule(Digester digester, String name, String value) {
+
+        this(name, value);
+
+    }
+
+    /**
+     * Construct a "set property" rule with the specified name and value
+     * attributes.
+     *
+     * @param name Name of the attribute that will contain the name of the
+     *  property to be set
+     * @param value Name of the attribute that will contain the value to which
+     *  the property should be set
+     */
+    public SetPropertyRule(String name, String value) {
+
+        this.name = name;
+        this.value = value;
+
+    }
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The attribute that will contain the property name.
+     */
+    protected String name = null;
+
+
+    /**
+     * The attribute that will contain the property value.
+     */
+    protected String value = null;
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Process the beginning of this element.
+     *
+     * @param attributes The attribute list of this element
+     *
+     * @exception NoSuchMethodException if the bean does not
+     *  have a writeable property of the specified name
+     */
+    public void begin(Attributes attributes) throws Exception {
+
+        // Identify the actual property name and value to be used
+        String actualName = null;
+        String actualValue = null;
+        for (int i = 0; i < attributes.getLength(); i++) {
+            String name = attributes.getLocalName(i);
+            if ("".equals(name)) {
+                name = attributes.getQName(i);
+            }
+            String value = attributes.getValue(i);
+            if (name.equals(this.name)) {
+                actualName = value;
+            } else if (name.equals(this.value)) {
+                actualValue = value;
+            }
+        }
+
+        // Get a reference to the top object
+        Object top = digester.peek();
+
+        // Log some debugging information
+        if (digester.log.isDebugEnabled()) {
+            digester.log.debug("[SetPropertyRule]{" + digester.match +
+                    "} Set " + top.getClass().getName() + " property " +
+                    actualName + " to " + actualValue);
+        }
+
+        // Set the property (with conversion as necessary)
+        // FIXME: Exception if property doesn't exist ?
+        IntrospectionUtils.setProperty(top, actualName, actualValue);
+
+    }
+
+
+    /**
+     * Render a printable version of this Rule.
+     */
+    public String toString() {
+
+        StringBuffer sb = new StringBuffer("SetPropertyRule[");
+        sb.append("name=");
+        sb.append(name);
+        sb.append(", value=");
+        sb.append(value);
+        sb.append("]");
+        return (sb.toString());
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/digester/SetRootRule.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/digester/SetRootRule.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/digester/SetRootRule.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,215 @@
+/* $Id: SetRootRule.java 299475 2004-06-26 17:41:32Z remm $
+ *
+ * Copyright 2002-2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.digester;
+
+import org.apache.tomcat.util.IntrospectionUtils;
+
+
+/**
+ * <p>Rule implementation that calls a method on the root object on the stack,
+ * passing the top object (child) as an argument.
+ * It is important to remember that this rule acts on <code>end</code>.</p>
+ *
+ * <p>This rule now supports more flexible method matching by default.
+ * It is possible that this may break (some) code 
+ * written against release 1.1.1 or earlier.
+ * See {@link #isExactMatch()} for more details.</p>
+ */
+
+public class SetRootRule extends Rule {
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Construct a "set root" rule with the specified method name.  The
+     * method's argument type is assumed to be the class of the
+     * child object.
+     *
+     * @param digester The associated Digester
+     * @param methodName Method name of the parent method to call
+     *
+     * @deprecated The digester instance is now set in the {@link Digester#addRule} method. 
+     * Use {@link #SetRootRule(String methodName)} instead.
+     */
+    public SetRootRule(Digester digester, String methodName) {
+
+        this(methodName);
+
+    }
+
+
+    /**
+     * Construct a "set root" rule with the specified method name.
+     *
+     * @param digester The associated Digester
+     * @param methodName Method name of the parent method to call
+     * @param paramType Java class of the parent method's argument
+     *  (if you wish to use a primitive type, specify the corresonding
+     *  Java wrapper class instead, such as <code>java.lang.Boolean</code>
+     *  for a <code>boolean</code> parameter)
+     *
+     * @deprecated The digester instance is now set in the {@link Digester#addRule} method. 
+     * Use {@link #SetRootRule(String methodName,String paramType)} instead.
+     */
+    public SetRootRule(Digester digester, String methodName,
+                       String paramType) {
+
+        this(methodName, paramType);
+
+    }
+
+    /**
+     * Construct a "set root" rule with the specified method name.  The
+     * method's argument type is assumed to be the class of the
+     * child object.
+     *
+     * @param methodName Method name of the parent method to call
+     */
+    public SetRootRule(String methodName) {
+
+        this(methodName, null);
+
+    }
+
+
+    /**
+     * Construct a "set root" rule with the specified method name.
+     *
+     * @param methodName Method name of the parent method to call
+     * @param paramType Java class of the parent method's argument
+     *  (if you wish to use a primitive type, specify the corresonding
+     *  Java wrapper class instead, such as <code>java.lang.Boolean</code>
+     *  for a <code>boolean</code> parameter)
+     */
+    public SetRootRule(String methodName,
+                       String paramType) {
+
+        this.methodName = methodName;
+        this.paramType = paramType;
+
+    }
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The method name to call on the parent object.
+     */
+    protected String methodName = null;
+
+
+    /**
+     * The Java class name of the parameter type expected by the method.
+     */
+    protected String paramType = null;
+    
+    /**
+     * Should we use exact matching. Default is no.
+     */
+    protected boolean useExactMatch = false;
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * <p>Is exact matching being used.</p>
+     *
+     * <p>This rule uses <code>org.apache.commons.beanutils.MethodUtils</code> 
+     * to introspect the relevent objects so that the right method can be called.
+     * Originally, <code>MethodUtils.invokeExactMethod</code> was used.
+     * This matches methods very strictly 
+     * and so may not find a matching method when one exists.
+     * This is still the behaviour when exact matching is enabled.</p>
+     *
+     * <p>When exact matching is disabled, <code>MethodUtils.invokeMethod</code> is used.
+     * This method finds more methods but is less precise when there are several methods 
+     * with correct signatures.
+     * So, if you want to choose an exact signature you might need to enable this property.</p>
+     *
+     * <p>The default setting is to disable exact matches.</p>
+     *
+     * @return true iff exact matching is enabled
+     * @since Digester Release 1.1.1
+     */
+    public boolean isExactMatch() {
+    
+        return useExactMatch;
+    }
+    
+    
+    /**
+     * <p>Set whether exact matching is enabled.</p>
+     *
+     * <p>See {@link #isExactMatch()}.</p>
+     *
+     * @param useExactMatch should this rule use exact method matching
+     * @since Digester Release 1.1.1
+     */
+    public void setExactMatch(boolean useExactMatch) {
+
+        this.useExactMatch = useExactMatch;
+    }
+
+    /**
+     * Process the end of this element.
+     */
+    public void end() throws Exception {
+
+        // Identify the objects to be used
+        Object child = digester.peek(0);
+        Object parent = digester.root;
+        if (digester.log.isDebugEnabled()) {
+            if (parent == null) {
+                digester.log.debug("[SetRootRule]{" + digester.match +
+                        "} Call [NULL ROOT]." +
+                        methodName + "(" + child + ")");
+            } else {
+                digester.log.debug("[SetRootRule]{" + digester.match +
+                        "} Call " + parent.getClass().getName() + "." +
+                        methodName + "(" + child + ")");
+            }
+        }
+
+        // Call the specified method
+        IntrospectionUtils.callMethod1(parent, methodName,
+                child, paramType, digester.getClassLoader());
+
+    }
+
+
+    /**
+     * Render a printable version of this Rule.
+     */
+    public String toString() {
+
+        StringBuffer sb = new StringBuffer("SetRootRule[");
+        sb.append("methodName=");
+        sb.append(methodName);
+        sb.append(", paramType=");
+        sb.append(paramType);
+        sb.append("]");
+        return (sb.toString());
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/digester/SetTopRule.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/digester/SetTopRule.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/digester/SetTopRule.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,215 @@
+/* $Id: SetTopRule.java 299475 2004-06-26 17:41:32Z remm $
+ *
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.digester;
+
+
+import org.apache.tomcat.util.IntrospectionUtils;
+
+
+/**
+ * <p>Rule implementation that calls a "set parent" method on the top (child)
+ * object, passing the (top-1) (parent) object as an argument.</p>
+ *
+ * <p>This rule now supports more flexible method matching by default.
+ * It is possible that this may break (some) code 
+ * written against release 1.1.1 or earlier.
+ * See {@link #isExactMatch()} for more details.</p>
+ */
+
+public class SetTopRule extends Rule {
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Construct a "set parent" rule with the specified method name.  The
+     * "set parent" method's argument type is assumed to be the class of the
+     * parent object.
+     *
+     * @param digester The associated Digester
+     * @param methodName Method name of the "set parent" method to call
+     *
+     * @deprecated The digester instance is now set in the {@link Digester#addRule} method. 
+     * Use {@link #SetTopRule(String methodName)} instead.
+     */
+    public SetTopRule(Digester digester, String methodName) {
+
+        this(methodName);
+
+    }
+
+
+    /**
+     * Construct a "set parent" rule with the specified method name.
+     *
+     * @param digester The associated Digester
+     * @param methodName Method name of the "set parent" method to call
+     * @param paramType Java class of the "set parent" method's argument
+     *  (if you wish to use a primitive type, specify the corresonding
+     *  Java wrapper class instead, such as <code>java.lang.Boolean</code>
+     *  for a <code>boolean</code> parameter)
+     *
+     * @deprecated The digester instance is now set in the {@link Digester#addRule} method. 
+     * Use {@link #SetTopRule(String methodName, String paramType)} instead.
+     */
+    public SetTopRule(Digester digester, String methodName,
+                      String paramType) {
+
+        this(methodName, paramType);
+
+    }
+
+    /**
+     * Construct a "set parent" rule with the specified method name.  The
+     * "set parent" method's argument type is assumed to be the class of the
+     * parent object.
+     *
+     * @param methodName Method name of the "set parent" method to call
+     */
+    public SetTopRule(String methodName) {
+
+        this(methodName, null);
+
+    }
+
+
+    /**
+     * Construct a "set parent" rule with the specified method name.
+     *
+     * @param methodName Method name of the "set parent" method to call
+     * @param paramType Java class of the "set parent" method's argument
+     *  (if you wish to use a primitive type, specify the corresonding
+     *  Java wrapper class instead, such as <code>java.lang.Boolean</code>
+     *  for a <code>boolean</code> parameter)
+     */
+    public SetTopRule(String methodName,
+                      String paramType) {
+
+        this.methodName = methodName;
+        this.paramType = paramType;
+
+    }
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The method name to call on the child object.
+     */
+    protected String methodName = null;
+
+
+    /**
+     * The Java class name of the parameter type expected by the method.
+     */
+    protected String paramType = null;
+    
+    /**
+     * Should we use exact matching. Default is no.
+     */
+    protected boolean useExactMatch = false;
+
+
+    // --------------------------------------------------------- Public Methods
+
+    /**
+     * <p>Is exact matching being used.</p>
+     *
+     * <p>This rule uses <code>org.apache.commons.beanutils.MethodUtils</code> 
+     * to introspect the relevent objects so that the right method can be called.
+     * Originally, <code>MethodUtils.invokeExactMethod</code> was used.
+     * This matches methods very strictly 
+     * and so may not find a matching method when one exists.
+     * This is still the behaviour when exact matching is enabled.</p>
+     *
+     * <p>When exact matching is disabled, <code>MethodUtils.invokeMethod</code> is used.
+     * This method finds more methods but is less precise when there are several methods 
+     * with correct signatures.
+     * So, if you want to choose an exact signature you might need to enable this property.</p>
+     *
+     * <p>The default setting is to disable exact matches.</p>
+     *
+     * @return true iff exact matching is enabled
+     * @since Digester Release 1.1.1
+     */
+    public boolean isExactMatch() {
+    
+        return useExactMatch;
+    }
+    
+    /**
+     * <p>Set whether exact matching is enabled.</p>
+     *
+     * <p>See {@link #isExactMatch()}.</p>
+     *
+     * @param useExactMatch should this rule use exact method matching
+     * @since Digester Release 1.1.1
+     */
+    public void setExactMatch(boolean useExactMatch) {
+
+        this.useExactMatch = useExactMatch;
+    }
+    
+    /**
+     * Process the end of this element.
+     */
+    public void end() throws Exception {
+
+        // Identify the objects to be used
+        Object child = digester.peek(0);
+        Object parent = digester.peek(1);
+        
+        if (digester.log.isDebugEnabled()) {
+            if (child == null) {
+                digester.log.debug("[SetTopRule]{" + digester.match +
+                        "} Call [NULL CHILD]." +
+                        methodName + "(" + parent + ")");
+            } else {
+                digester.log.debug("[SetTopRule]{" + digester.match +
+                        "} Call " + child.getClass().getName() + "." +
+                        methodName + "(" + parent + ")");
+            }
+        }
+
+        // Call the specified method
+        IntrospectionUtils.callMethod1(child, methodName,
+                parent, paramType, digester.getClassLoader());
+
+    }
+
+
+    /**
+     * Render a printable version of this Rule.
+     */
+    public String toString() {
+
+        StringBuffer sb = new StringBuffer("SetTopRule[");
+        sb.append("methodName=");
+        sb.append(methodName);
+        sb.append(", paramType=");
+        sb.append(paramType);
+        sb.append("]");
+        return (sb.toString());
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/digester/WithDefaultsRulesWrapper.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/digester/WithDefaultsRulesWrapper.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/digester/WithDefaultsRulesWrapper.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,163 @@
+/* $Id: WithDefaultsRulesWrapper.java 299475 2004-06-26 17:41:32Z remm $
+ *
+ * Copyright 2003-2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.digester;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * <p><code>Rules</code> <em>Decorator</em> that returns default rules 
+ * when no matches are returned by the wrapped implementation.</p>
+ *
+ * <p>This allows default <code>Rule</code> instances to be added to any 
+ * existing <code>Rules</code> implementation. These default <code>Rule</code> 
+ * instances will be returned for any match for which the wrapped 
+ * implementation does not return any matches.</p>
+ * <p> For example,
+ * <pre>
+ *   Rule alpha;
+ *   ...
+ *   WithDefaultsRulesWrapper rules = new WithDefaultsRulesWrapper(new BaseRules());
+ *   rules.addDefault(alpha);
+ *   ...
+ *   digester.setRules(rules);
+ *   ...
+ * </pre>
+ * when a pattern does not match any other rule, then rule alpha will be called.
+ * </p>
+ * <p><code>WithDefaultsRulesWrapper</code> follows the <em>Decorator</em> pattern.</p>
+ *
+ * @since 1.6
+ */
+
+public class WithDefaultsRulesWrapper implements Rules {
+
+    // --------------------------------------------------------- Fields
+    
+    /** The Rules implementation that this class wraps. */
+    private Rules wrappedRules;
+    /** Rules to be fired when the wrapped implementations returns none. */
+    private List defaultRules = new ArrayList();
+    /** All rules (preserves order in which they were originally added) */
+    private List allRules = new ArrayList();
+    
+    // --------------------------------------------------------- Constructor
+    
+    /** 
+     * Base constructor.
+     *
+     * @param wrappedRules the wrapped <code>Rules</code> implementation, not null
+     * @throws IllegalArgumentException when <code>wrappedRules</code> is null
+     */
+    public WithDefaultsRulesWrapper(Rules wrappedRules) {
+        if (wrappedRules == null) {
+            throw new IllegalArgumentException("Wrapped rules must not be null");
+        }
+        this.wrappedRules = wrappedRules;
+    }
+
+    // --------------------------------------------------------- Properties
+    
+    /** Gets digester using these Rules */
+    public Digester getDigester() {
+        return wrappedRules.getDigester();
+    }
+    
+    /** Sets digeseter using these Rules */
+    public void setDigester(Digester digester) {
+        wrappedRules.setDigester(digester);
+        Iterator it = defaultRules.iterator();
+        while (it.hasNext()) {
+            Rule rule = (Rule) it.next();
+            rule.setDigester(digester);
+        }
+    }
+    
+    /** Gets namespace to apply to Rule's added */
+    public String getNamespaceURI() {
+        return wrappedRules.getNamespaceURI();
+    }
+    
+    /** Sets namespace to apply to Rule's added subsequently */
+    public void setNamespaceURI(String namespaceURI) {
+        wrappedRules.setNamespaceURI(namespaceURI);
+    }
+    
+    /** Gets Rule's which will be fired when the wrapped implementation returns no matches */
+    public List getDefaults() {
+        return defaultRules;
+    }	
+    
+    // --------------------------------------------------------- Public Methods
+    
+    public List match(String pattern) {
+        return match("", pattern);
+    }	
+    
+    /**
+     * Return list of rules matching given pattern.
+     * If wrapped implementation returns any matches return those.
+     * Otherwise, return default matches.
+     */
+    public List match(String namespaceURI, String pattern) {
+        List matches = wrappedRules.match(namespaceURI, pattern);
+        if (matches ==  null || matches.isEmpty()) {	
+            // a little bit of defensive programming
+            return new ArrayList(defaultRules);
+        }
+        // otherwise
+        return matches;
+    }
+    
+    /** Adds a rule to be fired when wrapped implementation returns no matches */
+    public void addDefault(Rule rule) {
+        // set up rule
+        if (wrappedRules.getDigester() != null) {
+            rule.setDigester(wrappedRules.getDigester());
+        }
+        
+        if (wrappedRules.getNamespaceURI() != null) {
+            rule.setNamespaceURI(wrappedRules.getNamespaceURI());
+        }
+        
+        defaultRules.add(rule);
+        allRules.add(rule);
+    }
+    
+    /** Gets all rules */
+    public List rules() {
+        return allRules;
+    }
+    
+    /** Clears all Rule's */
+    public void clear() {
+        wrappedRules.clear();
+        allRules.clear();
+        defaultRules.clear();
+    }
+    
+    /** 
+     * Adds a Rule to be fired on given pattern.
+     * Pattern matching is delegated to wrapped implementation.
+     */
+    public void add(String pattern, Rule rule) {
+        wrappedRules.add(pattern, rule);
+        allRules.add(rule);
+    }	
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/digester/XercesParser.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/digester/XercesParser.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/digester/XercesParser.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,189 @@
+/* $Id: XercesParser.java 299768 2004-09-02 00:48:12Z yoavs $
+ *
+ * Copyright 2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.digester;
+
+import java.lang.reflect.Method;
+import java.util.Properties;
+
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.parsers.SAXParser;
+import javax.xml.parsers.SAXParserFactory;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.xml.sax.SAXException;
+import org.xml.sax.SAXNotRecognizedException;
+import org.xml.sax.SAXNotSupportedException;
+
+/**
+ * Create a <code>SAXParser</code> based on the underlying Xerces version.
+ * Currently, Xerces 2.3 and up doesn't implement schema validation the same way
+ * 2.1 was. In other to support schema validation in a portable way between 
+ * parser, some features/properties need to be set.
+ *
+ * @since 1.6
+ */
+
+public class XercesParser{
+
+    /**
+     * The Log to which all SAX event related logging calls will be made.
+     */
+    protected static Log log =
+        LogFactory.getLog("org.apache.commons.digester.Digester.sax");
+
+
+    /**
+     * The JAXP 1.2 property required to set up the schema location.
+     */
+    private static final String JAXP_SCHEMA_SOURCE =
+        "http://java.sun.com/xml/jaxp/properties/schemaSource";
+
+
+    /**
+     * The JAXP 1.2 property to set up the schemaLanguage used.
+     */
+    protected static String JAXP_SCHEMA_LANGUAGE =
+        "http://java.sun.com/xml/jaxp/properties/schemaLanguage";
+
+
+    /**
+     * Xerces dynamic validation property
+     */
+    protected static String XERCES_DYNAMIC = 
+        "http://apache.org/xml/features/validation/dynamic";
+
+
+    /**
+     * Xerces schema validation property
+     */
+    protected static String XERCES_SCHEMA =
+        "http://apache.org/xml/features/validation/schema";
+
+
+    /**
+     * A <code>float</code> representing the underlying Xerces version
+     */
+    protected static float version;
+
+
+    /**
+     * The current Xerces version.
+     */
+    protected static String versionNumber = null;
+
+
+    /**
+     * Return the current Xerces version.
+     * @return the current Xerces version.
+     */
+    private static String getXercesVersion() {
+        // If for some reason we can't get the version, set it to 1.0.
+        String versionNumber = "1.0";
+        try{
+            // Use reflection to avoid a build dependency with Xerces.
+            Class versionClass = 
+                            Class.forName("org.apache.xerces.impl.Version");
+            // Will return Xerces-J 2.x.0
+            Method method = 
+                versionClass.getMethod("getVersion", (Class[]) null); 
+            String version = (String)method.invoke(null, (Object[]) null);
+            versionNumber = version.substring( "Xerces-J".length() , 
+                                               version.lastIndexOf(".") ); 
+        } catch (Exception ex){
+            // Do nothing.
+        }
+        return versionNumber;
+    }
+
+
+    /**
+     * Create a <code>SAXParser</code> based on the underlying
+     * <code>Xerces</code> version.
+     * @param properties parser specific properties/features
+     * @return an XML Schema/DTD enabled <code>SAXParser</code>
+     */
+    public static SAXParser newSAXParser(Properties properties) 
+            throws ParserConfigurationException, 
+                   SAXException,
+                   SAXNotSupportedException {
+
+        SAXParserFactory factory =  
+                        (SAXParserFactory)properties.get("SAXParserFactory");
+
+        if (versionNumber == null){
+            versionNumber = getXercesVersion();
+            version = new Float( versionNumber ).floatValue();
+        }
+
+        // Note: 2.2 is completely broken (with XML Schema). 
+        if (version > 2.1) {
+
+            configureXerces(factory);
+            return factory.newSAXParser();
+        } else {
+            SAXParser parser = factory.newSAXParser();
+            configureOldXerces(parser,properties);
+            return parser;
+        }
+    }
+
+
+    /**
+     * Configure schema validation as recommended by the JAXP 1.2 spec.
+     * The <code>properties</code> object may contains information about
+     * the schema local and language. 
+     * @param properties parser optional info
+     */
+    private static void configureOldXerces(SAXParser parser, 
+                                           Properties properties) 
+            throws ParserConfigurationException, 
+                   SAXNotSupportedException {
+
+        String schemaLocation = (String)properties.get("schemaLocation");
+        String schemaLanguage = (String)properties.get("schemaLanguage");
+
+        try{
+            if (schemaLocation != null) {
+                parser.setProperty(JAXP_SCHEMA_LANGUAGE, schemaLanguage);
+                parser.setProperty(JAXP_SCHEMA_SOURCE, schemaLocation);
+            }
+        } catch (SAXNotRecognizedException e){
+            log.info(parser.getClass().getName() + ": " 
+                                        + e.getMessage() + " not supported."); 
+        }
+
+    }
+
+
+    /**
+     * Configure schema validation as recommended by the Xerces spec. 
+     * Both DTD and Schema validation will be enabled simultaneously.
+     * @param factory SAXParserFactory to be configured
+     */
+    private static void configureXerces(SAXParserFactory factory)
+            throws ParserConfigurationException, 
+                   SAXNotRecognizedException, 
+                   SAXNotSupportedException {
+
+        factory.setFeature(XERCES_DYNAMIC, true);
+        factory.setFeature(XERCES_SCHEMA, true);
+
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/digester/package.html
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/digester/package.html	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/digester/package.html	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,1275 @@
+<html>
+<head>
+<title>Package Documentation for org.apache.commons.digester Package</title>
+</head>
+<body bgcolor="white">
+The Digester package provides for rules-based processing of arbitrary
+XML documents.
+<br><br>
+<a name="doc.Description"></a>
+<div align="center">
+<a href="#doc.Depend">[Dependencies]</a>
+<a href="#doc.Intro">[Introduction]</a>
+<a href="#doc.Properties">[Configuration Properties]</a>
+<a href="#doc.Stack">[The Object Stack]</a>
+<a href="#doc.Patterns">[Element Matching Patterns]</a>
+<a href="#doc.Rules">[Processing Rules]</a>
+<a href="#doc.Logging">[Logging]</a>
+<a href="#doc.Usage">[Usage Example]</a>
+<a href="#doc.Namespace">[Namespace Aware Parsing]</a>
+<a href="#doc.Pluggable">[Pluggable Rules Processing]</a>
+<a href="#doc.RuleSets">[Encapsulated Rule Sets]</a>
+<a href="#doc.NamedStacks">[Using Named Stacks For Inter-Rule Communication]</a>
+<a href="#doc.RegisteringDTDs">[Registering DTDs]</a>
+<a href="#doc.troubleshooting">[Troubleshooting]</a>
+<a href="#doc.FAQ">[FAQ]</a>
+<a href="#doc.Limits">[Known Limitations]</a>
+</div>
+
+<a name="doc.Depend"></a>
+<h3>External Dependencies</h3>
+
+<ul>
+  <li>An XML parser conforming to
+    <a href="http://java.sun.com/products/xml">JAXP
+    </a>, version 1.1 or later (the first one to support SAX 2.0)
+  </li>
+  <li>
+    <a href="http://jakarta.apache.org/builds/jakarta-commons/release/commons-beanutils">
+Beanutils Package (Jakarta Commons)</a>, version 1.5 or later
+  </li>
+  <li>
+    <a href="http://jakarta.apache.org/builds/jakarta-commons/release/commons-collections">
+Collections Package (Jakarta Commons)</a>, version 2.1 or later
+  </li>
+  <li>
+    <a href="http://jakarta.apache.org/builds/jakarta-commons/release/commons-logging">
+Commons Logging Package (Jakarta Commons)</a>, version 1.0.2 or later
+  </li>
+</ul>
+
+<a name="doc.Intro"></a>
+<h3>Introduction</h3>
+
+<p>In many application environments that deal with XML-formatted data, it is
+useful to be able to process an XML document in an "event driven" manner,
+where particular Java objects are created (or methods of existing objects
+are invoked) when particular patterns of nested XML elements have been
+recognized.  Developers familiar with the Simple API for XML Parsing (SAX)
+approach to processing XML documents will recognize that the Digester provides
+a higher level, more developer-friendly interface to SAX events, because most
+of the details of navigating the XML element hierarchy are hidden -- allowing
+the developer to focus on the processing to be performed.</p>
+
+<p>In order to use a Digester, the following basic steps are required:</p>
+<ul>
+<li>Create a new instance of the
+    <code>org.apache.commons.digester.Digester</code> class.  Previously
+    created Digester instances may be safely reused, as long as you have
+    completed any previously requested parse, and you do not try to utilize
+    a particular Digester instance from more than one thread at a time.</li>
+<li>Set any desired <a href="#doc.Properties">configuration properties</a>
+    that will customize the operation of the Digester when you next initiate
+    a parse operation.</li>
+<li>Optionally, push any desired initial object(s) onto the Digester's
+    <a href="#doc.Stack">object stack</a>.</li>
+<li>Register all of the <a href="#doc.Patterns">element matching patterns</a>
+    for which you wish to have <a href="#doc.Rules">processing rules</a>
+    fired when this pattern is recognized in an input document.  You may
+    register as many rules as you like for any particular pattern.  If there
+    is more than one rule for a given pattern, the rules will be executed in
+    the order that they were listed.</li>
+<li>Call the <code>digester.parse()</code> method, passing a reference to the
+    XML document to be parsed in one of a variety of forms.  See the
+    <a href="Digester.html#parse(java.io.File)">Digester.parse()</a>
+    documentation for details.  Note that you will need to be prepared to
+    catch any <code>IOException</code> or <code>SAXException</code> that is
+    thrown by the parser, or any runtime expression that is thrown by one of
+    the processing rules.</li>
+</ul>
+
+<p>For example code, see <a href="#doc.Usage"> the usage 
+examples</a>, and <a href="#doc.FAQ.Examples"> the FAQ </a>. </p>
+
+<a name="doc.Properties"></a>
+<h3>Digester Configuration Properties</h3>
+
+<p>A <code>org.apache.commons.digester.Digester</code> instance contains several
+configuration properties that can be used to customize its operation.  These
+properties <strong>must</strong> be configured before you call one of the
+<code>parse()</code> variants, in order for them to take effect on that
+parse.</p>
+
+<blockquote>
+  <table border="1">
+    <tr>
+      <th width="15%">Property</th>
+      <th width="85%">Description</th>
+    </tr>
+    <tr>
+      <td align="center">classLoader</td>
+      <td>You can optionally specify the class loader that will be used to
+          load classes when required by the <code>ObjectCreateRule</code>
+          and <code>FactoryCreateRule</code> rules.  If not specified,
+          application classes will be loaded from the thread's context
+          class loader (if the <code>useContextClassLoader</code> property
+          is set to <code>true</code>) or the same class loader that was
+          used to load the <code>Digester</code> class itself.</td>
+    </tr>
+    <tr>
+      <td align="center">errorHandler</td>
+      <td>You can optionally specify a SAX <code>ErrorHandler</code> that
+          is notified when parsing errors occur.  By default, any parsing
+          errors that are encountered are logged, but Digester will continue
+          processing as well.</td>
+    </tr>
+    <tr>
+      <td align="center">namespaceAware</td>
+      <td>A boolean that is set to <code>true</code> to perform parsing in a
+          manner that is aware of XML namespaces.  Among other things, this
+          setting affects how elements are matched to processing rules.  See
+          <a href="#doc.Namespace">Namespace Aware Parsing</a> for more
+          information.</td>
+    </tr>
+    <tr>
+      <td align="center">ruleNamespaceURI</td>
+      <td>The public URI of the namespace for which all subsequently added
+          rules are associated, or <code>null</code> for adding rules that
+          are not associated with any namespace.  See
+          <a href="#doc.Namespace">Namespace Aware Parsing</a> for more
+          information.</td>
+    </tr>
+    <tr>
+      <td align="center">rules</td>
+      <td>The <code>Rules</code> component that actually performs matching of
+          <code>Rule</code> instances against the current element nesting
+          pattern is pluggable.  By default, Digester includes a
+          <code>Rules</code> implementation that behaves as described in this
+          document.  See
+          <a href="#doc.Pluggable">Pluggable Rules Processing</a> for
+          more information.</td>
+    </tr>
+    <tr>
+      <td align="center">useContextClassLoader</code>
+      <td>A boolean that is set to <code>true</code> if you want application
+          classes required by <code>FactoryCreateRule</code> and
+          <code>ObjectCreateRule</code> to be loaded from the context class
+          loader of the current thread.  By default, classes will be loaded
+          from the class loader that loaded this <code>Digester</code> class.
+          <strong>NOTE</strong> - This property is ignored if you set a
+          value for the <code>classLoader</code> property; that class loader
+          will be used unconditionally.</td>
+    </tr>
+    <tr>
+      <td align="center">validating</td>
+      <td>A boolean that is set to <code>true</code> if you wish to validate
+          the XML document against a Document Type Definition (DTD) that is
+          specified in its <code>DOCTYPE</code> declaration.  The default
+          value of <code>false</code> requests a parse that only detects
+          "well formed" XML documents, rather than "valid" ones.</td>
+    </tr>
+  </table>
+</blockquote>
+
+<p>In addition to the scalar properties defined above, you can also register
+a local copy of a Document Type Definition (DTD) that is referenced in a
+<code>DOCTYPE</code> declaration.  Such a registration tells the XML parser
+that, whenever it encounters a <code>DOCTYPE</code> declaration with the
+specified public identifier, it should utilize the actual DTD content at the
+registered system identifier (a URL), rather than the one in the
+<code>DOCTYPE</code> declaration.</p>
+
+<p>For example, the Struts framework controller servlet uses the following
+registration in order to tell Struts to use a local copy of the DTD for the
+Struts configuration file.  This allows usage of Struts in environments that
+are not connected to the Internet, and speeds up processing even at Internet
+connected sites (because it avoids the need to go across the network).</p>
+
+<pre>
+    URL url = new URL("/org/apache/struts/resources/struts-config_1_0.dtd");
+    digester.register
+      ("-//Apache Software Foundation//DTD Struts Configuration 1.0//EN",
+       url.toString());
+</pre>
+
+<p>As a side note, the system identifier used in this example is the path
+that would be passed to <code>java.lang.ClassLoader.getResource()</code>
+or <code>java.lang.ClassLoader.getResourceAsStream()</code>.  The actual DTD
+resource is loaded through the same class loader that loads all of the Struts
+classes -- typically from the <code>struts.jar</code> file.</p>
+
+<a name="doc.Stack"></a>
+<h3>The Object Stack</h3>
+
+<p>One very common use of <code>org.apache.commons.digester.Digester</code>
+technology is to dynamically construct a tree of Java objects, whose internal
+organization, as well as the details of property settings on these objects,
+are configured based on the contents of the XML document.  In fact, the
+primary reason that the Digester package was created (it was originally part
+of Struts, and then moved to the Commons project because it was recognized
+as being generally useful) was to facilitate the
+way that the Struts controller servlet configures itself based on the contents
+of your application's <code>struts-config.xml</code> file.</p>
+
+<p>To facilitate this usage, the Digester exposes a stack that can be
+manipulated by processing rules that are fired when element matching patterns
+are satisfied.  The usual stack-related operations are made available,
+including the following:</p>
+<ul>
+<li><a href="Digester.html#clear()">clear()</a> - Clear the current contents
+    of the object stack.</li>
+<li><a href="Digester.html#peek()">peek()</a> - Return a reference to the top
+    object on the stack, without removing it.</li>
+<li><a href="Digester.html#pop()">pop()</a> - Remove the top object from the
+    stack and return it.</li>
+<li><a href="Digester.html#push(java.lang.Object)">push()</a> - Push a new
+    object onto the top of the stack.</li>
+</ul>
+
+<p>A typical design pattern, then, is to fire a rule that creates a new object
+and pushes it on the stack when the beginning of a particular XML element is
+encountered. The object will remain there while the nested content of this
+element is processed, and it will be popped off when the end of the element
+is encountered.  As we will see, the standard "object create" processing rule
+supports exactly this functionalility in a very convenient way.</p>
+
+<p>Several potential issues with this design pattern are addressed by other
+features of the Digester functionality:</p>
+<ul>
+<li><em>How do I relate the objects being created to each other?</em> - The
+    Digester supports standard processing rules that pass the top object on
+    the stack as an argument to a named method on the next-to-top object on
+    the stack (or vice versa).  This rule makes it easy to establish
+    parent-child relationships between these objects.  One-to-one and
+    one-to-many relationships are both easy to construct.</li>
+<li><em>How do I retain a reference to the first object that was created?</em>
+    As you review the description of what the "object create" processing rule
+    does, it would appear that the first object you create (i.e. the object
+    created by the outermost XML element you process) will disappear from the
+    stack by the time that XML parsing is completed, because the end of the
+    element would have been encountered.  However, Digester will maintain a
+    reference to the very first object ever pushed onto the object stack,
+    and will return it to you
+    as the return value from the <code>parse()</code> call.  Alternatively,
+    you can push a reference to some application object onto the stack before
+    calling <code>parse()</code>, and arrange that a parent-child relationship
+    be created (by appropriate processing rules) between this manually pushed
+    object and the ones that are dynamically created.  In this way,
+    the pushed object will retain a reference to the dynamically created objects
+    (and therefore all of their children), and will be returned to you after
+    the parse finishes as well.</li>
+</ul>
+
+<a name="doc.Patterns"></a>
+<h3>Element Matching Patterns</h3>
+
+<p>A primary feature of the <code>org.apache.commons.digester.Digester</code>
+parser is that the Digester automatically navigates the element hierarchy of
+the XML document you are parsing for you, without requiring any developer
+attention to this process.  Instead, you focus on deciding what functions you
+would like to have performed whenver a certain arrangement of nested elements
+is encountered in the XML document being parsed.  The mechanism for specifying
+such arrangements are called <em>element matching patterns</em>.
+
+<p>A very simple element matching pattern is a simple string like "a".  This
+pattern is matched whenever an <code>&lt;a&gt;</code> top-level element is
+encountered in the XML document, no matter how many times it occurs.  Note that
+nested <code>&lt;a&gt;</code> elements will <strong>not</strong> match this
+pattern -- we will describe means to support this kind of matching later.</li>
+
+<p>The next step up in matching pattern complexity is "a/b".  This pattern will
+be matched when a <code>&lt;b&gt;</code> element is found nested inside a
+top-level <code>&lt;a&gt;</code> element.  Again, this match can occur as many
+times as desired, depending on the content of the XML document being parsed.
+You can use multiple slashes to define a hierarchy of any desired depth that
+will be matched appropriately.</p>
+
+<p>For example, assume you have registered processing rules that match patterns
+"a", "a/b", and "a/b/c".  For an input XML document with the following
+contents, the indicated patterns will be matched when the corresponding element
+is parsed:</p>
+<pre>
+  &lt;a&gt;         -- Matches pattern "a"
+    &lt;b&gt;       -- Matches pattern "a/b"
+      &lt;c/&gt;    -- Matches pattern "a/b/c"
+      &lt;c/&gt;    -- Matches pattern "a/b/c"
+    &lt;/b&gt;
+    &lt;b&gt;       -- Matches pattern "a/b"
+      &lt;c/&gt;    -- Matches pattern "a/b/c"
+      &lt;c/&gt;    -- Matches pattern "a/b/c"
+      &lt;c/&gt;    -- Matches pattern "a/b/c"
+    &lt;/b&gt;
+  &lt;/a&gt;
+</pre>
+
+<p>It is also possible to match a particular XML element, no matter how it is
+nested (or not nested) in the XML document, by using the "*" wildcard character
+in your matching pattern strings.  For example, an element matching pattern
+of "*/a" will match an <code>&lt;a&gt;</code> element at any nesting position
+within the document.</p>
+
+<p>It is quite possible that, when a particular XML element is being parsed,
+the pattern for more than one registered processing rule will be matched
+ either because you registered more than one processing rule with the same
+matching pattern, or because one more more exact pattern matches and wildcard
+pattern matches are satisfied by the same element.</p>
+
+<p>When this occurs, the corresponding processing rules will all be fired in order. 
+<code>begin</code> (and <code>body</code>) method calls are executed in the 
+order that the <code>Rules</code> where initially registered with the 
+<code>Digester</code>, whilst <code>end</code> method calls are execute in 
+reverse order. In other words - the order is first in, last out.</p>
+
+<a name="doc.Rules"></a>
+<h3>Processing Rules</h3>
+
+<p>The <a href="#doc.Patterns">previous section</a> documented how you identify
+<strong>when</strong> you wish to have certain actions take place.  The purpose
+of processing rules is to define <strong>what</strong> should happen when the
+patterns are matched.</p>
+
+<p>Formally, a processing rule is a Java class that subclasses the
+<a href="Rule.html">org.apache.commons.digester.Rule</a> interface.  Each Rule
+implements one or more of the following event methods that are called at
+well-defined times when the matching patterns corresponding to this rule
+trigger it:</p>
+<ul>
+<li><a href="Rule.html#begin(org.xml.sax.AttributeList)">begin()</a> -
+    Called when the beginning of the matched XML element is encountered.  A
+    data structure containing all of the attributes corresponding to this
+    element are passed as well.</li>
+<li><a href="Rule.html#body(java.lang.String)">body()</a> -
+    Called when nested content (that is not itself XML elements) of the
+    matched element is encountered.  Any leading or trailing whitespace will
+    have been removed as part of the parsing process.</li>
+<li><a href="Rule.html#end()">end()</a> - Called when the ending of the matched
+    XML element is encountered.  If nested XML elements that matched other
+    processing rules was included in the body of this element, the appropriate
+    processing rules for the matched rules will have already been completed
+    before this method is called.</li>
+<li><a href="Rule.html#finish()">finish()</a> - Called when the parse has
+    been completed, to give each rule a chance to clean up any temporary data
+    they might have created and cached.</li>
+</ul>
+
+<p>As you are configuring your digester, you can call the
+<code>addRule()</code> method to register a specific element matching pattern,
+along with an instance of a <code>Rule</code> class that will have its event
+handling methods called at the appropriate times, as described above.  This
+mechanism allows you to create <code>Rule</code> implementation classes
+dynamically, to implement any desired application specific functionality.</p>
+
+<p>In addition, a set of processing rule implementation classes are provided,
+which deal with many common programming scenarios.  These classes include the
+following:</p>
+<ul>
+<li><a href="ObjectCreateRule.html">ObjectCreateRule</a> - When the
+    <code>begin()</code> method is called, this rule instantiates a new
+    instance of a specified Java class, and pushes it on the stack.  The
+    class name to be used is defaulted according to a parameter passed to
+    this rule's constructor, but can optionally be overridden by a classname
+    passed via the specified attribute to the XML element being processed.
+    When the <code>end()</code> method is called, the top object on the stack
+    (presumably, the one we added in the <code>begin()</code> method) will
+    be popped, and any reference to it (within the Digester) will be
+    discarded.</li>
+<li><a href="FactoryCreateRule.html">FactoryCreateRule</a> - A variation of
+    <code>ObjectCreateRule</code> that is useful when the Java class with
+    which you wish to create an object instance does not have a no-arguments
+    constructor, or where you wish to perform other setup processing before
+    the object is handed over to the Digester.</li>
+<li><a href="SetPropertiesRule.html">SetPropertiesRule</a> - When the
+    <code>begin()</code> method is called, the digester uses the standard
+    Java Reflection API to identify any JavaBeans property setter methods
+    (on the object at the top of the digester's stack)
+    who have property names that match the attributes specified on this XML
+    element, and then call them individually, passing the corresponding
+    attribute values. These natural mappings can be overridden. This allows
+    (for example) a <code>class</code> attribute to be mapped correctly.
+    It is recommended that this feature should not be overused - in most cases,
+    it's better to use the standard <code>BeanInfo</code> mechanism.
+    A very common idiom is to define an object create
+    rule, followed by a set properties rule, with the same element matching
+    pattern.  This causes the creation of a new Java object, followed by
+    "configuration" of that object's properties based on the attributes
+    of the same XML element that created this object.</li>
+<li><a href="SetPropertyRule.html">SetPropertyRule</a> - When the
+    <code>begin()</code> method is called, the digester calls a specified
+    property setter (where the property itself is named by an attribute)
+    with a specified value (where the value is named by another attribute),
+    on the object at the top of the digester's stack.
+    This is useful when your XML file conforms to a particular DTD, and
+    you wish to configure a particular property that does not have a
+    corresponding attribute in the DTD.</li>
+<li><a href="SetNextRule.html">SetNextRule</a> - When the
+    <code>end()</code> method is called, the digester analyzes the
+    next-to-top element on the stack, looking for a property setter method
+    for a specified property.  It then calls this method, passing the object
+    at the top of the stack as an argument.  This rule is commonly used to
+    establish one-to-many relationships between the two objects, with the
+    method name commonly being something like "addChild".</li>
+<li><a href="SetTopRule.html">SetTopRule</a> - When the
+    <code>end()</code> method is called, the digester analyzes the
+    top element on the stack, looking for a property setter method for a
+    specified property.  It then calls this method, passing the next-to-top
+    object on the stack as an argument.  This rule would be used as an
+    alternative to a SetNextRule, with a typical method name "setParent",
+    if the API supported by your object classes prefers this approach.</li>
+<li><a href="CallMethodRule.html">CallMethodRule</a> - This rule sets up a
+    method call to a named method of the top object on the digester's stack,
+    which will actually take place when the <code>end()</code> method is
+    called.  You configure this rule by specifying the name of the method
+    to be called, the number of arguments it takes, and (optionally) the
+    Java class name(s) defining the type(s) of the method's arguments.
+    The actual parameter values, if any, will typically be accumulated from
+    the body content of nested elements within the element that triggered
+    this rule, using the CallParamRule discussed next.</li>
+<li><a href="CallParamRule.html">CallParamRule</a> - This rule identifies
+    the source of a particular numbered (zero-relative) parameter for a
+    CallMethodRule within which we are nested.  You can specify that the
+    parameter value be taken from a particular named attribute, or from the
+    nested body content of this element.</li>
+<li><a href="NodeCreateRule.html">NodeCreateRule</a> - A specialized rule
+    that converts part of the tree into a <code>DOM Node</code> and then
+    pushes it onto the stack.</li>
+</ul>
+
+<p>You can create instances of the standard <code>Rule</code> classes and
+register them by calling <code>digester.addRule()</code>, as described above.
+However, because their usage is so common, shorthand registration methods are
+defined for each of the standard rules, directly on the <code>Digester</code>
+class.  For example, the following code sequence:</p>
+<pre>
+    Rule rule = new SetNextRule(digester, "addChild",
+                                "com.mycompany.mypackage.MyChildClass");
+    digester.addRule("a/b/c", rule);
+</pre>
+<p>can be replaced by:</p>
+<pre>
+    digester.addSetNext("a/b/c", "addChild",
+                        "com.mycompany.mypackage.MyChildClass");
+</pre>
+
+<a name="doc.Logging"></a>
+<h3>Logging</h3>
+
+<p>Logging is a vital tool for debugging Digester rulesets. Digester can log
+copious amounts of debugging information. So, you need to know how logging
+works before you start using Digester seriously.</p>
+
+<p>Digester uses
+<a href="http://jakarta.apache.org/commons/logging.html">Jakarta Commons
+Logging</a>.  This component is not really a logging framework - rather
+an extensible, configurable bridge. It can be configured to swallow all log 
+messages, to provide very basic logging by itself or to pass logging messages
+on to more sophisticated logging frameworks. Commons-Logging comes with
+connectors for many popular logging frameworks. Consult the commons-logging
+documentation for more information.</p>
+
+<p>Two main logs are used by Digester:</p>
+<ul>
+<li>SAX-related messages are logged to
+    <strong><code>org.apache.commons.digester.Digester.sax</code></strong>.
+    This log gives information about the basic SAX events received by
+    Digester.</li>
+<li><strong><code>org.apache.commons.digester.Digester</code></strong> is used
+    for everything else. You'll probably want to have this log turned up during
+    debugging but turned down during production due to the high message
+    volume.</li>
+</ul>
+
+<p>Complete documentation of how to configure Commons-Logging can be found
+in the Commons Logging package documentation.  However, as a simple example,
+let's assume that you want to use the <code>SimpleLog</code> implementation
+that is included in Commons-Logging, and set up Digester to log events from
+the <code>Digester</code> logger at the DEBUG level, while you want to log
+events from the <code>Digester.log</code> logger at the INFO level.  You can
+accomplish this by creating a <code>commons-logging.properties</code> file
+in your classpath (or setting corresponding system properties on the command
+line that starts your application) with the following contents:</p>
+<pre>
+  org.apache.commons.logging.Log=org.apache.commons.logging.impl.SimpleLog
+  org.apache.commons.logging.simplelog.log.org.apache.commons.digester.Digester=debug
+  org.apache.commons.logging.simplelog.log.org.apache.commons.digester.Digester.sax=info
+</pre>
+
+<a name="doc.Usage"></a>
+<h3>Usage Examples</h3>
+
+
+<h5>Creating a Simple Object Tree</h5>
+
+<p>Let's assume that you have two simple JavaBeans, <code>Foo</code> and
+<code>Bar</code>, with the following method signatures:</p>
+<pre>
+  package mypackage;
+  public class Foo {
+    public void addBar(Bar bar);
+    public Bar findBar(int id);
+    public Iterator getBars();
+    public String getName();
+    public void setName(String name);
+  }
+
+  public mypackage;
+  public class Bar {
+    public int getId();
+    public void setId(int id);
+    public String getTitle();
+    public void setTitle(String title);
+  }
+</pre>
+
+<p>and you wish to use Digester to parse the following XML document:</p>
+
+<pre>
+  &lt;foo name="The Parent"&gt;
+    &lt;bar id="123" title="The First Child"/&gt;
+    &lt;bar id="456" title="The Second Child"/&gt;
+  &lt;/foo&gt;
+</pre>
+
+<p>A simple approach will be to use the following Digester in the following way
+to set up the parsing rules, and then process an input file containing this
+document:</p>
+
+<pre>
+  Digester digester = new Digester();
+  digester.setValidating(false);
+  digester.addObjectCreate("foo", "mypackage.Foo");
+  digester.addSetProperties("foo");
+  digester.addObjectCreate("foo/bar", "mypackage.Bar");
+  digester.addSetProperties("foo/bar");
+  digester.addSetNext("foo/bar", "addBar", "mypackage.Bar");
+  Foo foo = (Foo) digester.parse();
+</pre>
+
+<p>In order, these rules do the following tasks:</p>
+<ol>
+<li>When the outermost <code>&lt;foo&gt;</code> element is encountered,
+    create a new instance of <code>mypackage.Foo</code> and push it
+    on to the object stack.  At the end of the <code>&lt;foo&gt;</code>
+    element, this object will be popped off of the stack.</li>
+<li>Cause properties of the top object on the stack (i.e. the <code>Foo</code>
+    object that was just created and pushed) to be set based on the values
+    of the attributes of this XML element.</li>
+<li>When a nested <code>&lt;bar&gt;</code> element is encountered,
+    create a new instance of <code>mypackage.Bar</code> and push it
+    on to the object stack.  At the end of the <code>&lt;bar&gt;</code>
+    element, this object will be popped off of the stack (i.e. after the
+    remaining rules matching <code>foo/bar</code> are processed).</li>
+<li>Cause properties of the top object on the stack (i.e. the <code>Bar</code>
+    object that was just created and pushed) to be set based on the values
+    of the attributes of this XML element.  Note that type conversions
+    are automatically performed (such as String to int for the <code>id</code>
+    property), for all converters registered with the <code>ConvertUtils</code>
+    class from <code>commons-beanutils</code> package.</li>
+<li>Cause the <code>addBar</code> method of the next-to-top element on the
+    object stack (which is why this is called the "set <em>next</em>" rule)
+    to be called, passing the element that is on the top of the stack, which
+    must be of type <code>mypackage.Bar</code>.  This is the rule that causes
+    the parent/child relationship to be created.</li>
+</ol>
+
+<p>Once the parse is completed, the first object that was ever pushed on to the
+stack (the <code>Foo</code> object in this case) is returned to you.  It will
+have had its properties set, and all of its child <code>Bar</code> objects
+created for you.</p>
+
+
+<h5>Processing A Struts Configuration File</h5>
+
+<p>As stated earlier, the primary reason that the
+<code>Digester</code> package was created is because the
+Struts controller servlet itself needed a robust, flexible, easy to extend
+mechanism for processing the contents of the <code>struts-config.xml</code>
+configuration that describes nearly every aspect of a Struts-based application.
+Because of this, the controller servlet contains a comprehensive, real world,
+example of how the Digester can be employed for this type of a use case.
+See the <code>initDigester()</code> method of class
+<code>org.apache.struts.action.ActionServlet</code> for the code that creates
+and configures the Digester to be used, and the <code>initMapping()</code>
+method for where the parsing actually takes place.</p>
+
+<p>(Struts binary and source distributions can be acquired at
+<a href="http://jakarta.apache.org/struts/">http://jakarta.apache.org/struts/</a>.)</p>
+
+<p>The following discussion highlights a few of the matching patterns and
+processing rules that are configured, to illustrate the use of some of the
+Digester features.  First, let's look at how the Digester instance is
+created and initialized:</p>
+<pre>
+    Digester digester = new Digester();
+    digester.push(this); // Push controller servlet onto the stack
+    digester.setValidating(true);
+</pre>
+
+<p>We see that a new Digester instance is created, and is configured to use
+a validating parser.  Validation will occur against the struts-config_1_0.dtd
+DTD that is included with Struts (as discussed earlier).  In order to provide
+a means of tracking the configured objects, the controller servlet instance
+itself will be added to the digester's stack.</p>
+
+<pre>
+    digester.addObjectCreate("struts-config/global-forwards/forward",
+                             forwardClass, "className");
+    digester.addSetProperties("struts-config/global-forwards/forward");
+    digester.addSetNext("struts-config/global-forwards/forward",
+                        "addForward",
+                        "org.apache.struts.action.ActionForward");
+    digester.addSetProperty
+      ("struts-config/global-forwards/forward/set-property",
+       "property", "value");
+</pre>
+
+<p>The rules created by these lines are used to process the global forward
+declarations.  When a <code>&lt;forward&gt;</code> element is encountered,
+the following actions take place:</p>
+<ul>
+<li>A new object instance is created -- the <code>ActionForward</code>
+    instance that will represent this definition.  The Java class name
+    defaults to that specified as an initialization parameter (which
+    we have stored in the String variable <code>forwardClass</code>), but can
+    be overridden by using the "className" attribute (if it is present in the
+    XML element we are currently parsing).  The new <code>ActionForward</code>
+    instance is pushed onto the stack.</li>
+<li>The properties of the <code>ActionForward</code> instance (at the top of
+    the stack) are configured based on the attributes of the
+    <code>&lt;forward&gt;</code> element.</li>
+<li>Nested occurrences of the <code>&lt;set-property&gt;</code> element
+    cause calls to additional property setter methods to occur.  This is
+    required only if you have provided a custom implementation of the
+    <code>ActionForward</code> class with additional properties that are
+    not included in the DTD.</li>
+<li>The <code>addForward()</code> method of the next-to-top object on
+    the stack (i.e. the controller servlet itself) will be called, passing
+    the object at the top of the stack (i.e. the <code>ActionForward</code>
+    instance) as an argument.  This causes the global forward to be
+    registered, and as a result of this it will be remembered even after
+    the stack is popped.</li>
+<li>At the end of the <code>&lt;forward&gt;</code> element, the top element
+    (i.e. the <code>ActionForward</code> instance) will be popped off the
+    stack.</li>
+</ul>
+
+<p>Later on, the digester is actually executed as follows:</p>
+<pre>
+    InputStream input =
+      getServletContext().getResourceAsStream(config);
+    ...
+    try {
+        digester.parse(input);
+        input.close();
+    } catch (SAXException e) {
+        ... deal with the problem ...
+    }
+</pre>
+
+<p>As a result of the call to <code>parse()</code>, all of the configuration
+information that was defined in the <code>struts-config.xml</code> file is
+now represented as collections of objects cached within the Struts controller
+servlet, as well as being exposed as servlet context attributes.</p>
+
+
+<h5>Parsing Body Text In XML Files</h5>
+
+<p>The Digester module also allows you to process the nested body text in an
+XML file, not just the elements and attributes that are encountered.  The
+following example is based on an assumed need to parse the web application
+deployment descriptor (<code>/WEB-INF/web.xml</code>) for the current web
+application, and record the configuration information for a particular
+servlet.  To record this information, assume the existence of a bean class
+with the following method signatures (among others):</p>
+<pre>
+  package com.mycompany;
+  public class ServletBean {
+    public void setServletName(String servletName);
+    public void setServletClass(String servletClass);
+    public void addInitParam(String name, String value);
+  }
+</pre>
+
+<p>We are going to process the <code>web.xml</code> file that declares the
+controller servlet in a typical Struts-based application (abridged for
+brevity in this example):</p>
+<pre>
+  &lt;web-app&gt;
+    ...
+    &lt;servlet&gt;
+      &lt;servlet-name&gt;action&lt;/servlet-name&gt;
+      &lt;servlet-class&gt;org.apache.struts.action.ActionServlet&lt;servlet-class&gt;
+      &lt;init-param&gt;
+        &lt;param-name&gt;application&lt;/param-name&gt;
+        &lt;param-value&gt;org.apache.struts.example.ApplicationResources&lt;param-value&gt;
+      &lt;/init-param&gt;
+      &lt;init-param&gt;
+        &lt;param-name&gt;config&lt;/param-name&gt;
+        &lt;param-value&gt;/WEB-INF/struts-config.xml&lt;param-value&gt;
+      &lt;/init-param&gt;
+    &lt;/servlet&gt;
+    ...
+  &lt;/web-app&gt;
+</pre>
+
+<p>Next, lets define some Digester processing rules for this input file:</p>
+<pre>
+  digester.addObjectCreate("web-app/servlet",
+                           "com.mycompany.ServletBean");
+  digester.addCallMethod("web-app/servlet/servlet-name", "setServletName", 0);
+  digester.addCallMethod("web-app/servlet/servlet-class",
+                         "setServletClass", 0);
+  digester.addCallMethod("web-app/servlet/init-param",
+                         "addInitParam", 2);
+  digester.addCallParam("web-app/servlet/init-param/param-name", 0);
+  digester.addCallParam("web-app/servlet/init-param/param-value", 1);
+</pre>
+
+<p>Now, as elements are parsed, the following processing occurs:</p>
+<ul>
+<li><em>&lt;servlet&gt;</em> - A new <code>com.mycompany.ServletBean</code>
+    object is created, and pushed on to the object stack.</li>
+<li><em>&lt;servlet-name&gt;</em> - The <code>setServletName()</code> method
+    of the top object on the stack (our <code>ServletBean</code>) is called,
+    passing the body content of this element as a single parameter.</li>
+<li><em>&lt;servlet-class&gt;</em> - The <code>setServletClass()</code> method
+    of the top object on the stack (our <code>ServletBean</code>) is called,
+    passing the body content of this element as a single parameter.</li>
+<li><em>&lt;init-param&gt;</em> - A call to the <code>addInitParam</code>
+    method of the top object on the stack (our <code>ServletBean</code>) is
+    set up, but it is <strong>not</strong> called yet.  The call will be
+    expecting two <code>String</code> parameters, which must be set up by
+    subsequent call parameter rules.</li>
+<li><em>&lt;param-name&gt;</em> - The body content of this element is assigned
+    as the first (zero-relative) argument to the call we are setting up.</li>
+<li><em>&lt;param-value&gt;</em> - The body content of this element is assigned
+    as the second (zero-relative) argument to the call we are setting up.</li>
+<li><em>&lt;/init-param&gt;</em> - The call to <code>addInitParam()</code>
+    that we have set up is now executed, which will cause a new name-value
+    combination to be recorded in our bean.</li>
+<li><em>&lt;init-param&gt;</em> - The same set of processing rules are fired
+    again, causing a second call to <code>addInitParam()</code> with the
+    second parameter's name and value.</li>
+<li><em>&lt;/servlet&gt;</em> - The element on the top of the object stack
+    (which should be the <code>ServletBean</code> we pushed earlier) is
+    popped off the object stack.</li>
+</ul>
+
+
+<a name="doc.Namespace"></a>
+<h3>Namespace Aware Parsing</h3>
+
+<p>For digesting XML documents that do not use XML namespaces, the default
+behavior of <code>Digester</code>, as described above, is generally sufficient.
+However, if the document you are processing uses namespaces, it is often
+convenient to have sets of <code>Rule</code> instances that are <em>only</em>
+matched on elements that use the prefix of a particular namespace.  This
+approach, for example, makes it possible to deal with element names that are 
+the same in different namespaces, but where you want to perform different 
+processing for each namespace. </p>
+
+<p>Digester does not provide full support for namespaces, but does provide
+sufficient to accomplish most tasks. Enabling digester's namespace support
+is done by following these steps:</p>
+
+<ol>
+<li>Tell <code>Digester</code> that you will be doing namespace
+    aware parsing, by adding this statement in your initalization
+    of the Digester's properties:
+    <pre>
+    digester.setNamespaceAware(true);
+    </pre></li>
+<li>Declare the public namespace URI of the namespace with which
+    following rules will be associated.  Note that you do <em>not</em>
+    make any assumptions about the prefix - the XML document author
+    is free to pick whatever prefix they want:
+    <pre>
+    digester.setRuleNamespaceURI("http://www.mycompany.com/MyNamespace");
+    </pre></li>
+<li>Add the rules that correspond to this namespace, in the usual way,
+    by calling methods like <code>addObjectCreate()</code> or
+    <code>addSetProperties()</code>.  In the matching patterns you specify,
+    use only the <em>local name</em> portion of the elements (i.e. the
+    part after the prefix and associated colon (":") character:
+    <pre>
+    digester.addObjectCreate("foo/bar", "com.mycompany.MyFoo");
+    digester.addSetProperties("foo/bar");
+    </pre></li>
+<li>Repeat the previous two steps for each additional public namespace URI
+    that should be recognized on this <code>Digester</code> run.</li>
+</ol>
+
+<p>Now, consider that you might wish to digest the following document, using
+the rules that were set up in the steps above:</p>
+<pre>
+&lt;m:foo
+   xmlns:m="http://www.mycompany.com/MyNamespace"
+   xmlns:y="http://www.yourcompany.com/YourNamespace"&gt;
+
+  &lt;m:bar name="My Name" value="My Value"/&gt;
+
+  &lt;y:bar id="123" product="Product Description"/&gt;L
+
+&lt;/x:foo&gt;
+</pre>
+
+<p>Note that your object create and set properties rules will be fired for the
+<em>first</em> occurrence of the <code>bar</code> element, but not the
+<em>second</em> one.  This is because we declared that our rules only matched
+for the particular namespace we are interested in.  Any elements in the
+document that are associated with other namespaces (or no namespaces at all)
+will not be processed.  In this way, you can easily create rules that digest
+only the portions of a compound document that they understand, without placing
+any restrictions on what other content is present in the document.</p>
+
+<p>You might also want to look at <a href="#doc.RuleSets">Encapsulated
+Rule Sets</a> if you wish to reuse a particular set of rules, associated
+with a particular namespace, in more than one application context.</p>
+
+<h4>Using Namespace Prefixes In Pattern Matching</h4>
+
+<p>Using rules with namespaces is very useful when you have orthogonal rulesets. 
+One ruleset applies to a namespace and is independent of other rulesets applying
+to other namespaces. However, if your rule logic requires mixed namespaces, then 
+matching namespace prefix patterns might be a better strategy.</p>
+
+<p>When you set the <code>NamespaceAware</code> property to false, digester uses
+the qualified element name (which includes the namespace prefix) rather than the
+local name as the patten component for the element. This means that your pattern
+matches can include namespace prefixes as well as element names. So, rather than
+create namespace-aware rules, create pattern matches including the namespace
+prefixes.</p>
+
+<p>For example, (with <code>NamespaceAware</code> false), the pattern <code>
+'foo:bar'</code> will match a top level element named <code>'bar'</code> in the 
+namespace with (local) prefix <code>'foo'</code>.</p>
+
+<h4>Limitations of Digester Namespace support</h4>
+<p>Digester does not provide general "xpath-compliant" matching;
+only the namespace attached to the <i>last</i> element in the match path
+is involved in the matching process. Namespaces attached to parent
+elements are ignored for matching purposes.</p>
+
+
+<a name="doc.Pluggable"></a>
+<h3>Pluggable Rules Processing</h3>
+
+<p>By default, <code>Digester</code> selects the rules that match a particular
+pattern of nested elements as described under
+<a href="#doc.Patterns">Element Matching Patterns</a>.  If you prefer to use
+different selection policies, however, you can create your own implementation
+of the <a href="Rules.html">org.apache.commons.digester.Rules</a> interface,
+or subclass the corresponding convenience base class
+<a href="RulesBase.html">org.apache.commons.digester.RulesBase</a>.
+Your implementation of the <code>match()</code> method will be called when the
+processing for a particular element is started or ended, and you must return
+a <code>List</code> of the rules that are relevant for the current nesting
+pattern.  The order of the rules you return <strong>is</strong> significant,
+and should match the order in which rules were initally added.</p>
+
+<p>Your policy for rule selection should generally be sensitive to whether
+<a href="#doc.Namespace">Namespace Aware Parsing</a> is taking place.  In
+general, if <code>namespaceAware</code> is true, you should select only rules
+that:</p>
+<ul>
+<li>Are registered for the public namespace URI that corresponds to the
+    prefix being used on this element.</li>
+<li>Match on the "local name" portion of the element (so that the document
+    creator can use any prefix that they like).</li>
+</ul>
+
+<h4>ExtendedBaseRules</h4>
+<p><a href="ExtendedBaseRules.html">ExtendedBaseRules</a>,
+adds some additional expression syntax for pattern matching
+to the default mechanism, but it also executes more slowly.  See the
+JavaDocs for more details on the new pattern matching syntax, and suggestions
+on when this implementation should be used.  To use it, simply do the
+following as part of your Digester initialization:</p>
+
+<pre>
+  Digester digester = ...
+  ...
+  digester.setRules(new ExtendedBaseRules());
+  ...
+</pre>
+
+<h4>RegexRules</h4>
+<p><a href="RegexRules.html">RegexRules</a> is an advanced <code>Rules</code> 
+implementation which does not build on the default pattern matching rules.
+It uses a pluggable <a href="RegexMatcher.html">RegexMatcher</a> implementation to test 
+if a path matches the pattern for a Rule. All matching rules are returned 
+(note that this behaviour differs from longest matching rule of the default
+ pattern matching rules). See the Java Docs for more details.
+</p>
+<p>
+Example usage:
+</p>
+
+<pre>
+  Digester digester = ...
+  ...
+  digester.setRules(new RegexRules(new SimpleRegexMatcher()));
+  ...
+</pre>
+<h5>RegexMatchers</h5>
+<p>
+<code>Digester</code> ships only with one <code>RegexMatcher</code>
+implementation: <a href='SimpleRegexMatcher.html'>SimpleRegexMatcher</a>.
+This implementation is unsophisticated and lacks many good features
+lacking in more power Regex libraries. There are some good reasons
+why this approach was adopted. The first is that <code>SimpleRegexMatcher</code>
+is simple, it is easy to write and runs quickly. The second has to do with 
+the way that <code>RegexRules</code> is intended to be used.
+</p>
+<p>
+There are many good regex libraries available. (For example 
+<a href='http://jakarta.apache.org/oro/index.html'>Jakarta ORO</a>,
+<a href='http://jakarta.apache.org/regexp/index.html'>Jakarta Regex</a>,
+<a href='http://www.cacas.org/java/gnu/regexp/'>GNU Regex</a> and
+<a href='http://java.sun.com/j2se/1.4.2/docs/api/java/util/regex/package-summary.html'>
+Java 1.4 Regex</a>)
+Not only do different people have different personal tastes when it comes to
+regular expression matching but these products all offer different functionality
+and different strengths.
+</p>
+<p>
+The pluggable <code>RegexMatcher</code> is a thin bridge
+designed to adapt other Regex systems. This allows any Regex library the user
+desires to be plugged in and used just by creating one class.
+<code>Digester</code> does not (currently) ship with bridges to the major
+regex (to allow the dependencies required by <code>Digester</code>
+to be kept to a minimum).
+</p>
+
+<h4>WithDefaultsRulesWrapper</h4>
+<p>
+<a href="WithDefaultsRulesWrapper.html"> WithDefaultsRulesWrapper</a> allows 
+default <code>Rule</code> instances to be added to any existing 
+<code>Rules</code> implementation. These default <code>Rule</code> instances 
+will be returned for any match for which the wrapped implementation does not 
+return any matches. 
+</p>
+<p>
+For example,
+<pre>
+    Rule alpha;
+    ...
+    WithDefaultsRulesWrapper rules = new WithDefaultsRulesWrapper(new BaseRules());
+    rules.addDefault(alpha);
+    ...
+    digester.setRules(rules);
+    ...
+</pre>
+when a pattern does not match any other rule, then rule alpha will be called.
+</p>
+<p>
+<code>WithDefaultsRulesWrapper</code> follows the <em>Decorator</em> pattern.
+</p>
+
+<a name="doc.RuleSets"></a>
+<h3>Encapsulated Rule Sets</h3>
+
+<p>All of the examples above have described a scenario where the rules to be
+processed are registered with a <code>Digester</code> instance immediately
+after it is created.  However, this approach makes it difficult to reuse the
+same set of rules in more than one application environment.  Ideally, one
+could package a set of rules into a single class, which could be easily
+loaded and registered with a <code>Digester</code> instance in one easy step.
+</p>
+
+<p>The <a href="RuleSet.html">RuleSet</a> interface (and the convenience base
+class <a href="RuleSetBase.html">RuleSetBase</a>) make it possible to do this.
+In addition, the rule instances registered with a particular
+<code>RuleSet</code> can optionally be associated with a particular namespace,
+as described under <a href="#doc.Namespace">Namespace Aware Processing</a>.</p>
+
+<p>An example of creating a <code>RuleSet</code> might be something like this:
+</p>
+<pre>
+public class MyRuleSet extends RuleSetBase {
+
+  public MyRuleSet() {
+    this("");
+  }
+
+  public MyRuleSet(String prefix) {
+    super();
+    this.prefix = prefix;
+    this.namespaceURI = "http://www.mycompany.com/MyNamespace";
+  }
+
+  protected String prefix = null;
+
+  public void addRuleInstances(Digester digester) {
+    digester.addObjectCreate(prefix + "foo/bar",
+      "com.mycompany.MyFoo");
+    digester.addSetProperties(prefix + "foo/bar");
+  }
+
+}
+</pre>
+
+<p>You might use this <code>RuleSet</code> as follow to initialize a
+<code>Digester</code> instance:</p>
+<pre>
+  Digester digester = new Digester();
+  ... configure Digester properties ...
+  digester.addRuleSet(new MyRuleSet("baz/"));
+</pre>
+
+<p>A couple of interesting notes about this approach:</p>
+<ul>
+<li>The application that is using these rules does not need to know anything
+    about the fact that the <code>RuleSet</code> being used is associated
+    with a particular namespace URI.  That knowledge is emedded inside the
+    <code>RuleSet</code> class itself.</li>
+<li>If desired, you could make a set of rules work for more than one
+    namespace URI by providing constructors on the <code>RuleSet</code> to
+    allow this to be specified dynamically.</li>
+<li>The <code>MyRuleSet</code> example above illustrates another technique
+    that increases reusability -- you can specify (as an argument to the
+    constructor) the leading portion of the matching pattern to be used.
+    In this way, you can construct a <code>Digester</code> that recognizes
+    the same set of nested elements at different nesting levels within an
+    XML document.</li>
+</ul>
+<a name="doc.NamedStacks"></a>
+<h3>Using Named Stacks For Inter-Rule Communication</h3>
+<p>
+<code>Digester</code> is based on <code>Rule</code> instances working together 
+to process xml. For anything other than the most trival processing, 
+communication between <code>Rule</code> instances is necessary. Since <code>Rule</code>
+instances are processed in sequence, this usually means storing an Object 
+somewhere where later instances can retrieve it.
+</p>
+<p>
+<code>Digester</code> is based on SAX. The most natural data structure to use with 
+SAX based xml processing is the stack. This allows more powerful processes to be
+specified more simply since the pushing and popping of objects can mimic the 
+nested structure of the xml. 
+</p>
+<p>
+<code>Digester</code> uses two basic stacks: one for the main beans and the other 
+for parameters for method calls. These are inadequate for complex processing 
+where many different <code>Rule</code> instances need to communicate through 
+different channels.
+</p>
+<p>
+In this case, it is recommended that named stacks are used. In addition to the
+two basic stacks, <code>Digester</code> allows rules to use an unlimited number
+of other stacks referred two by an identifying string (the name). (That's where
+the term <em>named stack</em> comes from.) These stacks are 
+accessed through calls to:
+</p>
+<ul>
+    <li><a href='Digester.html#push(java.lang.String, java.lang.Object)'>
+        void push(String stackName, Object value)</a></li>
+    <li><a href='Digester.html#pop(java.lang.String)'>
+        Object pop(String stackName)</a></li>
+    <li><a href='Digester.html#peek(java.lang.String)'>
+        Object peek(String stackName)</a></li>
+</ul>
+<p>
+<strong>Note:</strong> all stack names beginning with <code>org.apache.commons.digester</code>
+are reserved for future use by the <code>Digester</code> component. It is also recommended
+that users choose stack names perfixed by the name of their own domain to avoid conflicts
+with other <code>Rule</code> implementations.
+</p>
+<a name="doc.RegisteringDTDs"></a>
+<h3>Registering DTDs</h3>
+
+<h4>Brief (But Still Too Long) Introduction To System and Public Identifiers</h4>
+<p>A definition for an external entity comes in one of two forms:
+</p>
+<ol>
+    <li><code>SYSTEM <em>system-identifier</em></code></li>
+    <li><code>PUBLIC <em>public-identifier</em> <em>system-identifier</em></code></li>
+</ol>
+<p>
+The <code><em>system-identifier</em></code> is an URI from which the resource can be obtained
+(either directly or indirectly). Many valid URIs may identify the same resource.
+The <code><em>public-identifier</em></code> is an additional free identifier which may be used
+(by the parser) to locate the resource. 
+</p>
+<p>
+In practice, the weakness with a <code><em>system-identifier</em></code> is that most parsers
+will attempt to interprete this URI as an URL, try to download the resource directly
+from the URL and stop the parsing if this download fails. So, this means that 
+almost always the URI will have to be an URL from which the declaration
+can be downloaded.
+</p>
+<p>
+URLs may be local or remote but if the URL is chosen to be local, it is likely only
+to function correctly on a small number of machines (which are configured precisely
+to allow the xml to be parsed). This is usually unsatisfactory and so a universally
+accessable URL is preferred. This usually means an internet URL.
+</p>
+<p>
+To recap, in practice the <code><em>system-identifier</em></code> will (most likely) be an 
+internet URL. Unfortunately downloading from an internet URL is not only slow
+but unreliable (since successfully downloading a document from the internet 
+relies on the client being connect to the internet and the server being
+able to satisfy the request).
+</p>
+<p>
+The <code><em>public-identifier</em></code> is a freely defined name but (in practice) it is 
+strongly recommended that a unique, readable and open format is used (for reasons
+that should become clear later). A Formal Public Identifier (FPI) is a very
+common choice. This public identifier is often used to provide a unique and location
+independent key which can be used to subsistute local resources for remote ones 
+(hint: this is why ;).
+</p>
+<p>
+By using the second (<code>PUBLIC</code>) form combined with some form of local
+catalog (which matches <code><em>public-identifiers</em></code> to local resources) and where
+the <code><em>public-identifier</em></code> is a unique name and the <code><em>system-identifier</em></code> 
+is an internet URL, the practical disadvantages of specifying just a 
+<code><em>system-identifier</em></code> can be avoided. Those external entities which have been 
+store locally (on the machine parsing the document) can be identified and used.
+Only when no local copy exists is it necessary to download the document
+from the internet URL. This naming scheme is recommended when using <code>Digester</code>.
+</p>
+
+<h4>External Entity Resolution Using Digester</h4>
+<p>
+SAX factors out the resolution of external entities into an <code>EntityResolver</code>.
+<code>Digester</code> supports the use of custom <code>EntityResolver</code> 
+but ships with a simple internal implementation. This implementation allows local URLs
+to be easily associated with <code><em>public-identifiers</em></code>. 
+</p>
+<p>For example:</p>
+<code><pre>
+    digester.register("-//Example Dot Com //DTD Sample Example//EN", "assets/sample.dtd");
+</pre></code>
+<p>
+will make digester return the relative file path <code>assets/sample.dtd</code> 
+whenever an external entity with public id 
+<code>-//Example Dot Com //DTD Sample Example//EN</code> is needed.
+</p>
+<p><strong>Note:</strong> This is a simple (but useful) implementation. 
+Greater sophistication requires a custom <code>EntityResolver</code>.</p>
+    
+<a name="doc.troubleshooting"></a>
+<h3>Troubleshooting</h3>
+<h4>Debugging Exceptions</h4>
+<p>
+<code>Digester</code> is based on <a href='http://www.saxproject.org'>SAX</a>.
+Digestion throws two kinds of <code>Exception</code>:
+</p>
+<ul>
+    <li><code>java.io.IOException</code></li>
+    <li><code>org.xml.sax.SAXException</code></li>
+</ul>
+<p>
+The first is rarely thrown and indicates the kind of fundemental IO exception
+that developers know all about. The second is thrown by SAX parsers when the processing
+of the XML cannot be completed. So, to diagnose the cause a certain familiarity with 
+the way that SAX error handling works is very useful. 
+</p>
+<h5>Diagnosing SAX Exceptions</h5>
+<p>
+This is a short, potted guide to SAX error handling strategies. It's not intended as a
+proper guide to error handling in SAX.
+</p>
+<p>
+When a SAX parser encounters a problem with the xml (well, ok - sometime after it 
+encounters a problem) it will throw a 
+<a href='http://www.saxproject.org/apidoc/org/xml/sax/SAXParseException.html'>
+SAXParseException</a>. This is a subclass of <code>SAXException</code> and contains
+a bit of extra information about what exactly when wrong - and more importantly,
+where it went wrong. If you catch an exception of this sort, you can be sure that
+the problem is with the XML and not <code>Digester</code> or your rules.
+It is usually a good idea to catch this exception and log the extra information
+to help with diagnosing the reason for the failure.
+</p>
+<p>
+General <a href='http://www.saxproject.org/apidoc/org/xml/sax/SAXException.html'>
+SAXException</a> instances may wrap a causal exception. When exceptions are
+throw by <code>Digester</code> each of these will be wrapped into a 
+<code>SAXException</code> and rethrown. So, catch these and examine the wrapped
+exception to diagnose what went wrong.
+</p>
+<a name="doc.FAQ"></a>
+<h3>Frequently Asked Questions</h3>
+<p><ul>
+<li><strong>Why do I get warnings when using a JAXP 1.1 parser?</strong>
+<p>If you're using a JAXP 1.1 parser, you might see the following warning (in your log):
+<code><pre>
+[WARN] Digester - -Error: JAXP SAXParser property not recognized: http://java.sun.com/xml/jaxp/properties/schemaLanguage
+</pre></code>
+This property is needed for JAXP 1.2 (XML Schema support) as required
+for the Servlet Spec. 2.4 but is not recognized by JAXP 1.1 parsers.
+This warning is harmless.</p>
+<p>
+</li>
+<li><strong>Why Doesn't Schema Validation Work With Parser XXX Out Of The Box?</strong>
+<p>
+Schema location and language settings are often need for validation using schemas.
+Unfortunately, there isn't a single standard approach to how these properties are
+configured on a parser.
+Digester tries to guess the parser being used and configure it appropriately
+but it's not infallible.
+You might need to grab an instance, configure it and pass it to Digester.
+</p>
+<p>
+If you want to support more than one parser in a portable manner, 
+then you'll probably want to take a look at the 
+<code>org.apache.commons.digester.parsers</code> package
+and add a new class to support the particular parser that's causing problems.
+</p>
+</li>
+<li><strong>Help! 
+I'm Validating Against Schema But Digester Ignores Errors!</strong>
+<p>
+Digester is based on <a href='http://www.saxproject.org'>SAX</a>. The convention for
+SAX parsers is that all errors are reported (to any registered 
+<code>ErrorHandler</code>) but processing continues. Digester (by default) 
+registers its own <code>ErrorHandler</code> implementation. This logs details 
+but does not stop the processing (following the usual convention for SAX 
+based processors). 
+</p>
+<p>
+This means that the errors reported by the validation of the schema will appear in the
+Digester logs but the processing will continue. To change this behaviour, call
+<code>digester.setErrorHandler</code> with a more suitable implementation.
+</p>
+
+<li><strong>Where Can I Find Example Code?</strong>
+<a name="doc.FAQ.Examples">
+<p>Digester ships with a sample application: a mapping for the <em>Rich Site 
+Summary</em> format used by many newsfeeds. Download the source distribution 
+to see how it works.</p>
+<p>Digester also ships with a set of examples demonstrating most of the 
+features described in this document. See the "src/examples" subdirectory 
+of the source distribution.</p>
+</li>
+<li><strong>When Are You Going To Support <em>Rich Site Summary</em> Version x.y.z?</strong>
+<p>
+The <em>Rich Site Summary</em> application is intended to be a sample application. 
+It works but we have no plans to add support for other versions of the format.
+</p>
+<p>
+We would consider donations of standard digester applications but it's unlikely that
+these would ever be shipped with the base digester distribution.
+If you want to discuss this, please post to <a href='http://jakarta.apache.org/site/mail.html'>
+common-dev mailing list</a>
+</p>
+</li>
+</ul>
+<a name="doc.Limits"></a>
+<h3>Known Limitations</h3>
+<h4>Accessing Public Methods In A Default Access Superclass</h4>
+<p>There is an issue when invoking public methods contained in a default access superclass.
+Reflection locates these methods fine and correctly assigns them as public.
+However, an <code>IllegalAccessException</code> is thrown if the method is invoked.</p>
+
+<p><code>MethodUtils</code> contains a workaround for this situation. 
+It will attempt to call <code>setAccessible</code> on this method.
+If this call succeeds, then the method can be invoked as normal.
+This call will only succeed when the application has sufficient security privilages. 
+If this call fails then a warning will be logged and the method may fail.</p>
+
+<p><code>Digester</code> uses <code>MethodUtils</code> and so there may be an issue accessing methods
+of this kind from a high security environment. If you think that you might be experiencing this 
+problem, please ask on the mailing list.</p>
+</body>
+</html>

Added: branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/http/AcceptLanguage.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/http/AcceptLanguage.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/http/AcceptLanguage.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,147 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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;
+
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Locale;
+import java.util.StringTokenizer;
+import java.util.Vector;
+
+/**
+ * Util to process the "Accept-Language" header. Used by facade to implement
+ * getLocale() and by StaticInterceptor.
+ *
+ * Not optimized - it's very slow.
+ * 
+ * @author James Duncan Davidson [duncan at eng.sun.com]
+ * @author James Todd [gonzo at eng.sun.com]
+ * @author Jason Hunter [jch at eng.sun.com]
+ * @author Harish Prabandham
+ * @author costin at eng.sun.com
+ */
+public class AcceptLanguage {
+
+    public static Locale getLocale(String acceptLanguage) {
+	if( acceptLanguage == null ) return Locale.getDefault();
+
+        Hashtable languages = new Hashtable();
+        Vector quality=new Vector();
+        processAcceptLanguage(acceptLanguage, languages,quality);
+
+        if (languages.size() == 0) return Locale.getDefault();
+
+        Vector l = new Vector();
+        extractLocales( languages,quality, l);
+
+        return (Locale)l.elementAt(0);
+    }
+
+    public static Enumeration getLocales(String acceptLanguage) {
+    	// Short circuit with an empty enumeration if null header
+        if (acceptLanguage == null) {
+            Vector v = new Vector();
+            v.addElement(Locale.getDefault());
+            return v.elements();
+        }
+	
+        Hashtable languages = new Hashtable();
+        Vector quality=new Vector();
+    	processAcceptLanguage(acceptLanguage, languages , quality);
+
+        if (languages.size() == 0) {
+            Vector v = new Vector();
+            v.addElement(Locale.getDefault());
+            return v.elements();
+        }
+    	Vector l = new Vector();
+    	extractLocales( languages, quality , l);
+    	return l.elements();
+    }
+
+    private static void processAcceptLanguage( String acceptLanguage,
+					      Hashtable languages, Vector q)
+    {
+        StringTokenizer languageTokenizer =
+            new StringTokenizer(acceptLanguage, ",");
+
+        while (languageTokenizer.hasMoreTokens()) {
+            String language = languageTokenizer.nextToken().trim();
+            int qValueIndex = language.indexOf(';');
+            int qIndex = language.indexOf('q');
+            int equalIndex = language.indexOf('=');
+            Double qValue = new Double(1);
+
+            if (qValueIndex > -1 &&
+                    qValueIndex < qIndex &&
+                    qIndex < equalIndex) {
+    	        String qValueStr = language.substring(qValueIndex + 1);
+                language = language.substring(0, qValueIndex);
+                qValueStr = qValueStr.trim().toLowerCase();
+                qValueIndex = qValueStr.indexOf('=');
+                qValue = new Double(0);
+                if (qValueStr.startsWith("q") &&
+                    qValueIndex > -1) {
+                    qValueStr = qValueStr.substring(qValueIndex + 1);
+                    try {
+                        qValue = new Double(qValueStr.trim());
+                    } catch (NumberFormatException nfe) {
+                    }
+                }
+            }
+
+            // XXX
+            // may need to handle "*" at some point in time
+
+            if (! language.equals("*")) {
+                String key = qValue.toString();
+                Vector v;
+                if (languages.containsKey(key)) {
+                    v = (Vector)languages.get(key) ;
+                } else {
+                    v= new Vector();
+                    q.addElement(qValue);
+                }
+                v.addElement(language);
+                languages.put(key, v);
+            }
+        }
+    }
+
+    private static void extractLocales(Hashtable languages, Vector q,Vector l)
+    {
+        // XXX We will need to order by q value Vector in the Future ?
+        Enumeration e = q.elements();
+        while (e.hasMoreElements()) {
+            Vector v =
+                (Vector)languages.get(((Double)e.nextElement()).toString());
+            Enumeration le = v.elements();
+            while (le.hasMoreElements()) {
+    	        String language = (String)le.nextElement();
+	        	String country = "";
+        		int countryIndex = language.indexOf("-");
+                if (countryIndex > -1) {
+                    country = language.substring(countryIndex + 1).trim();
+                    language = language.substring(0, countryIndex).trim();
+                }
+                l.addElement(new Locale(language, country));
+            }
+        }
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/http/BaseRequest.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/http/BaseRequest.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/http/BaseRequest.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,345 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.
+ */
+
+/***************************************************************************
+ * Description: Base http request object.                                  *
+ * Author:      Keving Seguin [seguin at apache.org]                          *
+ * Version:     $Revision: 299484 $                                           *
+ ***************************************************************************/
+
+package org.apache.tomcat.util.http;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+import java.util.HashMap;
+import java.util.Iterator;
+
+import org.apache.tomcat.util.buf.MessageBytes;
+
+/**
+ * A general-purpose object for representing an HTTP
+ * request.
+ */
+public class BaseRequest {
+
+    // scheme constants
+    public static final String SCHEME_HTTP = "http";
+    public static final String SCHEME_HTTPS = "https";
+
+    // request attributes
+    MessageBytes method = MessageBytes.newInstance();
+    MessageBytes protocol = MessageBytes.newInstance();
+    MessageBytes requestURI = MessageBytes.newInstance();
+    MessageBytes remoteAddr = MessageBytes.newInstance();
+    MessageBytes remoteHost = MessageBytes.newInstance();
+    MessageBytes serverName = MessageBytes.newInstance();
+    int serverPort = 80;
+    MessageBytes remoteUser = MessageBytes.newInstance();
+    MessageBytes authType = MessageBytes.newInstance();
+    MessageBytes queryString = MessageBytes.newInstance();
+    MessageBytes authorization = MessageBytes.newInstance();
+    String scheme = SCHEME_HTTP;
+    boolean secure = false;
+    int contentLength = 0;
+    MessageBytes contentType = MessageBytes.newInstance();
+    MimeHeaders headers = new MimeHeaders();
+    Cookies cookies = new Cookies();
+    HashMap attributes = new HashMap();
+
+    MessageBytes tomcatInstanceId = MessageBytes.newInstance();
+    
+    /**
+     * Recycles this object and readies it further use.
+     */
+    public void recycle() {
+        method.recycle();
+        protocol.recycle();
+        requestURI.recycle();
+        remoteAddr.recycle();
+        remoteHost.recycle();
+        serverName.recycle();
+        serverPort = 80;
+        remoteUser.recycle();
+        authType.recycle();
+        queryString.recycle();
+        authorization.recycle();
+        scheme = SCHEME_HTTP;
+        secure = false;
+        contentLength = 0;
+        contentType.recycle();
+        headers.recycle();
+        cookies.recycle();
+        attributes.clear();
+        tomcatInstanceId.recycle();
+    }
+
+    /**
+     * Get the method.
+     * @return the method
+     */
+    public MessageBytes method() {
+        return method;
+    }
+
+    /**
+     * Get the protocol
+     * @return the protocol
+     */
+    public MessageBytes protocol() {
+        return protocol;
+    }
+
+    /**
+     * Get the request uri
+     * @return the request uri
+     */
+    public MessageBytes requestURI() {
+        return requestURI;
+    }
+
+    /**
+     * Get the remote address
+     * @return the remote address
+     */
+    public MessageBytes remoteAddr() {
+        return remoteAddr;
+    }
+
+    /**
+     * Get the remote host
+     * @return the remote host
+     */
+    public MessageBytes remoteHost() {
+        return remoteHost;
+    }
+
+    /**
+     * Get the server name
+     * @return the server name
+     */
+    public MessageBytes serverName() {
+        return serverName;
+    }
+
+    /**
+     * Get the server port
+     * @return the server port
+     */
+    public int getServerPort() {
+        return serverPort;
+    }
+
+    /**
+     * Set the server port
+     * @param i the server port
+     */
+    public void setServerPort(int i) {
+        serverPort = i;
+    }
+
+    /**
+     * Get the remote user
+     * @return the remote user
+     */
+    public MessageBytes remoteUser() {
+        return remoteUser;
+    }
+
+    /**
+     * Get the auth type
+     * @return the auth type
+     */
+    public MessageBytes authType() {
+        return authType;
+    }
+
+    /**
+     * Get the query string
+     * @return the query string
+     */
+    public MessageBytes queryString() {
+        return queryString;
+    }
+
+    /**
+     * Get the authorization credentials
+     * @return the authorization credentials
+     */
+    public MessageBytes authorization() {
+        return authorization;
+    }
+
+    /**
+     * Get the scheme
+     * @return the scheme
+     */
+    public String getScheme() {
+        return scheme;
+    }
+
+    /**
+     * Set the scheme.
+     * @param s the scheme
+     */
+    public void setScheme(String s) {
+        scheme = s;
+    }
+
+    /**
+     * Get whether the request is secure or not.
+     * @return <code>true</code> if the request is secure.
+     */
+    public boolean getSecure() {
+        return secure;
+    }
+
+    /**
+     * Set whether the request is secure or not.
+     * @param b <code>true</code> if the request is secure.
+     */
+    public void setSecure(boolean b) {
+        secure = b;
+    }
+
+    /**
+     * Get the content length
+     * @return the content length
+     */
+    public int getContentLength() {
+        return contentLength;
+    }
+
+    /**
+     * Set the content length
+     * @param i the content length
+     */
+    public void setContentLength(int i) {
+        contentLength = i;
+    }
+
+    /**
+     * Get the content type
+     * @return the content type
+     */
+    public MessageBytes contentType() {
+        return contentType;
+    }
+
+    /**
+     * Get this request's headers
+     * @return request headers
+     */
+    public MimeHeaders headers() {
+        return headers;
+    }
+
+    /**
+     * Get cookies.
+     * @return request cookies.
+     */
+    public Cookies cookies() {
+        return cookies;
+    }
+
+    /**
+     * Set an attribute on the request
+     * @param name attribute name
+     * @param value attribute value
+     */
+    public void setAttribute(String name, Object value) {
+        if (name == null || value == null) {
+            return;
+        }
+        attributes.put(name, value);
+    }
+
+    /**
+     * Get an attribute on the request
+     * @param name attribute name
+     * @return attribute value
+     */
+    public Object getAttribute(String name) {
+        if (name == null) {
+            return null;
+        }
+
+        return attributes.get(name);
+    }
+
+    /**
+     * Get iterator over attribute names
+     * @return iterator over attribute names
+     */
+    public Iterator getAttributeNames() {
+        return attributes.keySet().iterator();
+    }
+
+    /**
+     * Get the host id ( or jvmRoute )
+     * @return the jvm route
+     */
+    public MessageBytes instanceId() {
+        return tomcatInstanceId;
+    }
+
+    // backward compat - jvmRoute is the id of this tomcat instance,
+    // used by a load balancer on the server side to implement sticky
+    // sessions, and on the tomcat side to format the session ids.
+    public MessageBytes jvmRoute() {
+        return tomcatInstanceId;
+    }
+
+    private Object notes[]=new Object[16];
+    
+    public final Object getNote(int id) {
+        return notes[id];
+    }
+
+    public final void setNote(int id, Object cr) {
+        notes[id]=cr;
+    }
+    
+    /**
+     * ** SLOW ** for debugging only!
+     */
+    public String toString() {
+        StringWriter sw = new StringWriter();
+        PrintWriter pw = new PrintWriter(sw);
+
+        pw.println("=== BaseRequest ===");
+        pw.println("method          = " + method.toString());
+        pw.println("protocol        = " + protocol.toString());
+        pw.println("requestURI      = " + requestURI.toString());
+        pw.println("remoteAddr      = " + remoteAddr.toString());
+        pw.println("remoteHost      = " + remoteHost.toString());
+        pw.println("serverName      = " + serverName.toString());
+        pw.println("serverPort      = " + serverPort);
+        pw.println("remoteUser      = " + remoteUser.toString());
+        pw.println("authType        = " + authType.toString());
+        pw.println("queryString     = " + queryString.toString());
+        pw.println("scheme          = " + scheme.toString());
+        pw.println("secure          = " + secure);
+        pw.println("contentLength   = " + contentLength);
+        pw.println("contentType     = " + contentType);
+        pw.println("attributes      = " + attributes.toString());
+        pw.println("headers         = " + headers.toString());
+        pw.println("cookies         = " + cookies.toString());
+        pw.println("jvmRoute        = " + tomcatInstanceId.toString());
+        return sw.toString();
+    }
+    
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/http/ContentType.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/http/ContentType.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/http/ContentType.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,92 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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;
+
+
+/**
+ * Usefull methods for Content-Type processing
+ * 
+ * @author James Duncan Davidson [duncan at eng.sun.com]
+ * @author James Todd [gonzo at eng.sun.com]
+ * @author Jason Hunter [jch at eng.sun.com]
+ * @author Harish Prabandham
+ * @author costin at eng.sun.com
+ */
+public class ContentType {
+
+    // Basically return everything after ";charset="
+    // If no charset specified, use the HTTP default (ASCII) character set.
+    public static String getCharsetFromContentType(String type) {
+        if (type == null) {
+            return null;
+        }
+        int semi = type.indexOf(";");
+        if (semi == -1) {
+            return null;
+        }
+        int charsetLocation = type.indexOf("charset=", semi);
+        if (charsetLocation == -1) {
+            return null;
+        }
+	String afterCharset = type.substring(charsetLocation + 8);
+        // The charset value in a Content-Type header is allowed to be quoted
+        // and charset values can't contain quotes.  Just convert any quote
+        // chars into spaces and let trim clean things up.
+        afterCharset = afterCharset.replace('"', ' ');
+        String encoding = afterCharset.trim();
+        return encoding;
+    }
+
+
+    /**
+     * Returns true if the given content type contains a charset component,
+     * false otherwise.
+     *
+     * @param type Content type
+     * @return true if the given content type contains a charset component,
+     * false otherwise
+     */
+    public static boolean hasCharset(String type) {
+
+        boolean hasCharset = false;
+
+        int len = type.length();
+        int index = type.indexOf(';');
+        while (index != -1) {
+            index++;
+            while (index < len && Character.isSpace(type.charAt(index))) {
+                index++;
+            }
+            if (index+8 < len
+                    && type.charAt(index) == 'c'
+                    && type.charAt(index+1) == 'h'
+                    && type.charAt(index+2) == 'a'
+                    && type.charAt(index+3) == 'r'
+                    && type.charAt(index+4) == 's'
+                    && type.charAt(index+5) == 'e'
+                    && type.charAt(index+6) == 't'
+                    && type.charAt(index+7) == '=') {
+                hasCharset = true;
+                break;
+            }
+            index = type.indexOf(';', index);
+        }
+
+        return hasCharset;
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/http/Cookies.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/http/Cookies.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/http/Cookies.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,481 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.StringTokenizer;
+
+import org.apache.tomcat.util.buf.ByteChunk;
+import org.apache.tomcat.util.buf.MessageBytes;
+
+/**
+ * A collection of cookies - reusable and tuned for server side performance.
+ * Based on RFC2965 ( and 2109 )
+ *
+ * This class is not synchronized.
+ *
+ * @author Costin Manolache
+ * @author kevin seguin
+ */
+public final class Cookies { // extends MultiMap {
+
+    private static org.apache.commons.logging.Log log=
+        org.apache.commons.logging.LogFactory.getLog(Cookies.class );
+    
+    // expected average number of cookies per request
+    public static final int INITIAL_SIZE=4; 
+    ServerCookie scookies[]=new ServerCookie[INITIAL_SIZE];
+    int cookieCount=0;
+    boolean unprocessed=true;
+
+    MimeHeaders headers;
+    
+    /**
+     *  Construct a new cookie collection, that will extract
+     *  the information from headers.
+     *
+     * @param headers Cookies are lazy-evaluated and will extract the
+     *     information from the provided headers.
+     */
+    public Cookies(MimeHeaders headers) {
+        this.headers=headers;
+    }
+
+    /**
+     * Construct a new uninitialized cookie collection.
+     * Use {@link #setHeaders} to initialize.
+     */
+    // [seguin] added so that an empty Cookies object could be
+    // created, have headers set, then recycled.
+    public Cookies() {
+    }
+
+    /**
+     * Set the headers from which cookies will be pulled.
+     * This has the side effect of recycling the object.
+     *
+     * @param headers Cookies are lazy-evaluated and will extract the
+     *     information from the provided headers.
+     */
+    // [seguin] added so that an empty Cookies object could be
+    // created, have headers set, then recycled.
+    public void setHeaders(MimeHeaders headers) {
+        recycle();
+        this.headers=headers;
+    }
+
+    /**
+     * Recycle.
+     */
+    public void recycle() {
+            for( int i=0; i< cookieCount; i++ ) {
+            if( scookies[i]!=null )
+                scookies[i].recycle();
+        }
+        cookieCount=0;
+        unprocessed=true;
+    }
+
+    /**
+     * EXPENSIVE!!!  only for debugging.
+     */
+    public String toString() {
+        StringWriter sw = new StringWriter();
+        PrintWriter pw = new PrintWriter(sw);
+        pw.println("=== Cookies ===");
+        int count = getCookieCount();
+        for (int i = 0; i < count; ++i) {
+            pw.println(getCookie(i).toString());
+        }
+        return sw.toString();
+    }
+
+    // -------------------- Indexed access --------------------
+    
+    public ServerCookie getCookie( int idx ) {
+        if( unprocessed ) {
+            getCookieCount(); // will also update the cookies
+        }
+        return scookies[idx];
+    }
+
+    public int getCookieCount() {
+        if( unprocessed ) {
+            unprocessed=false;
+            processCookies(headers);
+        }
+        return cookieCount;
+    }
+
+    // -------------------- Adding cookies --------------------
+
+    /** Register a new, unitialized cookie. Cookies are recycled, and
+     *  most of the time an existing ServerCookie object is returned.
+     *  The caller can set the name/value and attributes for the cookie
+     */
+    public ServerCookie addCookie() {
+        if( cookieCount >= scookies.length  ) {
+            ServerCookie scookiesTmp[]=new ServerCookie[2*cookieCount];
+            System.arraycopy( scookies, 0, scookiesTmp, 0, cookieCount);
+            scookies=scookiesTmp;
+        }
+        
+        ServerCookie c = scookies[cookieCount];
+        if( c==null ) {
+            c= new ServerCookie();
+            scookies[cookieCount]=c;
+        }
+        cookieCount++;
+        return c;
+    }
+
+
+    // code from CookieTools 
+
+    /** Add all Cookie found in the headers of a request.
+     */
+    public  void processCookies( MimeHeaders headers ) {
+        if( headers==null )
+            return;// nothing to process
+        // process each "cookie" header
+        int pos=0;
+        while( pos>=0 ) {
+            // Cookie2: version ? not needed
+            pos=headers.findHeader( "Cookie", pos );
+            // no more cookie headers headers
+            if( pos<0 ) break;
+
+            MessageBytes cookieValue=headers.getValue( pos );
+            if( cookieValue==null || cookieValue.isNull() ) {
+                pos++;
+                continue;
+            }
+
+            // Uncomment to test the new parsing code
+            if( cookieValue.getType() == MessageBytes.T_BYTES ) {
+                if( dbg>0 ) log( "Parsing b[]: " + cookieValue.toString());
+                ByteChunk bc=cookieValue.getByteChunk();
+                processCookieHeader( bc.getBytes(),
+                                     bc.getOffset(),
+                                     bc.getLength());
+            } else {
+                if( dbg>0 ) log( "Parsing S: " + cookieValue.toString());
+                processCookieHeader( cookieValue.toString() );
+            }
+            pos++;// search from the next position
+        }
+    }
+
+    /** Process a byte[] header - allowing fast processing of the
+     *  raw data
+     */
+    void processCookieHeader(  byte bytes[], int off, int len )
+    {
+        if( len<=0 || bytes==null ) return;
+        int end=off+len;
+        int pos=off;
+        
+        int version=0; //sticky
+        ServerCookie sc=null;
+        
+
+        while( pos<end ) {
+            byte cc;
+            // [ skip_spaces name skip_spaces "=" skip_spaces value EXTRA ; ] *
+            if( dbg>0 ) log( "Start: " + pos + " " + end );
+            
+            pos=skipSpaces(bytes, pos, end);
+            if( pos>=end )
+                return; // only spaces
+            int startName=pos;
+            if( dbg>0 ) log( "SN: " + pos );
+            
+            // Version should be the first token
+            boolean isSpecial=false;
+            if(bytes[pos]=='$') { pos++; isSpecial=true; }
+
+            pos= findDelim1( bytes, startName, end); // " =;,"
+            int endName=pos;
+            // current = "=" or " " or DELIM
+            pos= skipSpaces( bytes, endName, end ); 
+            if( dbg>0 ) log( "DELIM: " + endName + " " + (char)bytes[pos]);
+
+            if(pos >= end ) {
+                // it's a name-only cookie ( valid in RFC2109 )
+                if( ! isSpecial ) {
+                    sc=addCookie();
+                    sc.getName().setBytes( bytes, startName,
+                                           endName-startName );
+                    sc.getValue().setString("");
+                    sc.setVersion( version );
+                    if( dbg>0 ) log( "Name only, end: " + startName + " " +
+                                     endName);
+                }
+                return;
+            }
+
+            cc=bytes[pos];
+            pos++;
+            if( cc==';' || cc==',' || pos>=end ) {
+                if( ! isSpecial && startName!= endName ) {
+                    sc=addCookie();
+                    sc.getName().setBytes( bytes, startName,
+                                           endName-startName );
+                    sc.getValue().setString("");
+                    sc.setVersion( version );
+                    if( dbg>0 ) log( "Name only: " + startName + " " + endName);
+                }
+                continue;
+            }
+            
+            // we should have "=" ( tested all other alternatives )
+            int startValue=skipSpaces( bytes, pos, end);
+            int endValue=startValue;
+            
+            cc=bytes[pos];
+            if(  cc== '\'' || cc=='"' ) {
+                startValue++;
+                endValue=indexOf( bytes, startValue, end, cc );
+                pos=endValue+1; // to skip to next cookie
+             } else {
+                endValue=findDelim2( bytes, startValue, end );
+                pos=endValue+1;
+            }
+            
+            // if not $Version, etc
+            if( ! isSpecial ) {
+                sc=addCookie();
+                sc.getName().setBytes( bytes, startName, endName-startName );
+                sc.getValue().setBytes( bytes, startValue, endValue-startValue);
+                sc.setVersion( version );
+                if( dbg>0 ) {
+                    log( "New: " + sc.getName() + "X=X" + sc.getValue());
+                }
+                continue;
+            }
+            
+            // special - Path, Version, Domain, Port
+            if( dbg>0 ) log( "Special: " + startName + " " + endName);
+            // XXX TODO
+            if( equals( "$Version", bytes, startName, endName ) ) {
+                if(dbg>0 ) log( "Found version " );
+                if( bytes[startValue]=='1' && endValue==startValue+1 ) {
+                    version=1;
+                    if(dbg>0 ) log( "Found version=1" );
+                }
+                continue;
+            }
+            if( sc==null ) {
+                // Path, etc without a previous cookie
+                continue;
+            }
+            if( equals( "$Path", bytes, startName, endName ) ) {
+                sc.getPath().setBytes( bytes,
+                                       startValue,
+                                       endValue-startValue );
+            }
+            if( equals( "$Domain", bytes, startName, endName ) ) {
+                sc.getDomain().setBytes( bytes,
+                                         startValue,
+                                         endValue-startValue );
+            }
+            if( equals( "$Port", bytes, startName, endName ) ) {
+                // sc.getPort().setBytes( bytes,
+                //                        startValue,
+                //                        endValue-startValue );
+            }
+        }
+    }
+
+    // -------------------- Utils --------------------
+    public static int skipSpaces(  byte bytes[], int off, int end ) {
+        while( off < end ) {
+            byte b=bytes[off];
+            if( b!= ' ' ) return off;
+            off ++;
+        }
+        return off;
+    }
+
+    public static int findDelim1( byte bytes[], int off, int end )
+    {
+        while( off < end ) {
+            byte b=bytes[off];
+            if( b==' ' || b=='=' || b==';' || b==',' )
+                return off;
+            off++;
+        }
+        return off;
+    }
+
+    public static int findDelim2( byte bytes[], int off, int end )
+    {
+        while( off < end ) {
+            byte b=bytes[off];
+            if( b==';' || b==',' )
+                return off;
+            off++;
+        }
+        return off;
+    }
+
+    public static int indexOf( byte bytes[], int off, int end, byte qq )
+    {
+        while( off < end ) {
+            byte b=bytes[off];
+            if( b==qq )
+                return off;
+            off++;
+        }
+        return off;
+    }
+
+    public static int indexOf( byte bytes[], int off, int end, char qq )
+    {
+        while( off < end ) {
+            byte b=bytes[off];
+            if( b==qq )
+                return off;
+            off++;
+        }
+        return off;
+    }
+    
+    // XXX will be refactored soon!
+    public static boolean equals( String s, byte b[], int start, int end) {
+        int blen = end-start;
+        if (b == null || blen != s.length()) {
+            return false;
+        }
+        int boff = start;
+        for (int i = 0; i < blen; i++) {
+            if (b[boff++] != s.charAt(i)) {
+                return false;
+            }
+        }
+        return true;
+    }
+    
+
+    // ---------------------------------------------------------
+    // -------------------- DEPRECATED, OLD --------------------
+    
+    private void processCookieHeader(  String cookieString )
+    {
+        if( dbg>0 ) log( "Parsing cookie header " + cookieString );
+        // normal cookie, with a string value.
+        // This is the original code, un-optimized - it shouldn't
+        // happen in normal case
+
+        StringTokenizer tok = new StringTokenizer(cookieString,
+                                                  ";", false);
+        while (tok.hasMoreTokens()) {
+            String token = tok.nextToken();
+            int i = token.indexOf("=");
+            if (i > -1) {
+                
+                // XXX
+                // the trims here are a *hack* -- this should
+                // be more properly fixed to be spec compliant
+                
+                String name = token.substring(0, i).trim();
+                String value = token.substring(i+1, token.length()).trim();
+                // RFC 2109 and bug 
+                value=stripQuote( value );
+                ServerCookie cookie = addCookie();
+                
+                cookie.getName().setString(name);
+                cookie.getValue().setString(value);
+                if( dbg > 0 ) log( "Add cookie " + name + "=" + value);
+            } else {
+                // we have a bad cookie.... just let it go
+            }
+        }
+    }
+
+    /**
+     *
+     * Strips quotes from the start and end of the cookie string
+     * This conforms to RFC 2109
+     * 
+     * @param value            a <code>String</code> specifying the cookie 
+     *                         value (possibly quoted).
+     *
+     * @see #setValue
+     *
+     */
+    private static String stripQuote( String value )
+    {
+        //        log("Strip quote from " + value );
+        if (((value.startsWith("\"")) && (value.endsWith("\""))) ||
+            ((value.startsWith("'") && (value.endsWith("'"))))) {
+            try {
+                return value.substring(1,value.length()-1);
+            } catch (Exception ex) { 
+            }
+        }
+        return value;
+    }  
+
+
+    // log
+    static final int dbg=0;
+    public void log(String s ) {
+        if (log.isDebugEnabled())
+            log.debug("Cookies: " + s);
+    }
+
+    /*
+    public static void main( String args[] ) {
+        test("foo=bar; a=b");
+        test("foo=bar;a=b");
+        test("foo=bar;a=b;");
+        test("foo=bar;a=b; ");
+        test("foo=bar;a=b; ;");
+        test("foo=;a=b; ;");
+        test("foo;a=b; ;");
+        // v1 
+        test("$Version=1; foo=bar;a=b"); 
+        test("$Version=\"1\"; foo='bar'; $Path=/path; $Domain=\"localhost\"");
+        test("$Version=1;foo=bar;a=b; ; ");
+        test("$Version=1;foo=;a=b; ; ");
+        test("$Version=1;foo= ;a=b; ; ");
+        test("$Version=1;foo;a=b; ; ");
+        test("$Version=1;foo=\"bar\";a=b; ; ");
+        test("$Version=1;foo=\"bar\";$Path=/examples;a=b; ; ");
+        test("$Version=1;foo=\"bar\";$Domain=apache.org;a=b");
+        test("$Version=1;foo=\"bar\";$Domain=apache.org;a=b;$Domain=yahoo.com");
+        // rfc2965
+        test("$Version=1;foo=\"bar\";$Domain=apache.org;$Port=8080;a=b");
+
+        // wrong
+        test("$Version=1;foo=\"bar\";$Domain=apache.org;$Port=8080;a=b");
+    }
+
+    public static void test( String s ) {
+        System.out.println("Processing " + s );
+        Cookies cs=new Cookies(null);
+        cs.processCookieHeader( s.getBytes(), 0, s.length());
+        for( int i=0; i< cs.getCookieCount() ; i++ ) {
+            System.out.println("Cookie: " + cs.getCookie( i ));
+        }
+            
+    }
+    */
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/http/FastHttpDateFormat.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/http/FastHttpDateFormat.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/http/FastHttpDateFormat.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,223 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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;
+
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.TimeZone;
+import java.text.DateFormat;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+
+/**
+ * Utility class to generate HTTP dates.
+ * 
+ * @author Remy Maucherat
+ */
+public final class FastHttpDateFormat {
+
+
+    // -------------------------------------------------------------- Variables
+
+
+    /**
+     * HTTP date format.
+     */
+    protected static final SimpleDateFormat format = 
+        new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US);
+
+
+    /**
+     * The set of SimpleDateFormat formats to use in getDateHeader().
+     */
+    protected static final SimpleDateFormat formats[] = {
+        new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US),
+        new SimpleDateFormat("EEEEEE, dd-MMM-yy HH:mm:ss zzz", Locale.US),
+        new SimpleDateFormat("EEE MMMM d HH:mm:ss yyyy", Locale.US)
+    };
+
+
+    protected final static TimeZone gmtZone = TimeZone.getTimeZone("GMT");
+
+
+    /**
+     * GMT timezone - all HTTP dates are on GMT
+     */
+    static {
+
+        format.setTimeZone(gmtZone);
+
+        formats[0].setTimeZone(gmtZone);
+        formats[1].setTimeZone(gmtZone);
+        formats[2].setTimeZone(gmtZone);
+
+    }
+
+
+    /**
+     * Instant on which the currentDate object was generated.
+     */
+    protected static long currentDateGenerated = 0L;
+
+
+    /**
+     * Current formatted date.
+     */
+    protected static String currentDate = null;
+
+
+    /**
+     * Formatter cache.
+     */
+    protected static final HashMap formatCache = new HashMap();
+
+
+    /**
+     * Parser cache.
+     */
+    protected static final HashMap parseCache = new HashMap();
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Get the current date in HTTP format.
+     */
+    public static final String getCurrentDate() {
+
+        long now = System.currentTimeMillis();
+        if ((now - currentDateGenerated) > 1000) {
+            synchronized (format) {
+                if ((now - currentDateGenerated) > 1000) {
+                    currentDateGenerated = now;
+                    currentDate = format.format(new Date(now));
+                }
+            }
+        }
+        return currentDate;
+
+    }
+
+
+    /**
+     * Get the HTTP format of the specified date.
+     */
+    public static final String formatDate
+        (long value, DateFormat threadLocalformat) {
+
+        String cachedDate = null;
+        Long longValue = new Long(value);
+        try {
+            cachedDate = (String) formatCache.get(longValue);
+        } catch (Exception e) {
+        }
+        if (cachedDate != null)
+            return cachedDate;
+
+        String newDate = null;
+        Date dateValue = new Date(value);
+        if (threadLocalformat != null) {
+            newDate = threadLocalformat.format(dateValue);
+            synchronized (formatCache) {
+                updateCache(formatCache, longValue, newDate);
+            }
+        } else {
+            synchronized (formatCache) {
+                synchronized (format) {
+                    newDate = format.format(dateValue);
+                }
+                updateCache(formatCache, longValue, newDate);
+            }
+        }
+        return newDate;
+
+    }
+
+
+    /**
+     * Try to parse the given date as a HTTP date.
+     */
+    public static final long parseDate(String value, 
+                                       DateFormat[] threadLocalformats) {
+
+        Long cachedDate = null;
+        try {
+            cachedDate = (Long) parseCache.get(value);
+        } catch (Exception e) {
+        }
+        if (cachedDate != null)
+            return cachedDate.longValue();
+
+        Long date = null;
+        if (threadLocalformats != null) {
+            date = internalParseDate(value, threadLocalformats);
+            synchronized (parseCache) {
+                updateCache(parseCache, value, date);
+            }
+        } else {
+            synchronized (parseCache) {
+                date = internalParseDate(value, formats);
+                updateCache(parseCache, value, date);
+            }
+        }
+        if (date == null) {
+            return (-1L);
+        } else {
+            return date.longValue();
+        }
+
+    }
+
+
+    /**
+     * Parse date with given formatters.
+     */
+    private static final Long internalParseDate
+        (String value, DateFormat[] formats) {
+        Date date = null;
+        for (int i = 0; (date == null) && (i < formats.length); i++) {
+            try {
+                date = formats[i].parse(value);
+            } catch (ParseException e) {
+                ;
+            }
+        }
+        if (date == null) {
+            return null;
+        }
+        return new Long(date.getTime());
+    }
+
+
+    /**
+     * Update cache.
+     */
+    private static final void updateCache(HashMap cache, Object key, 
+                                          Object value) {
+        if (value == null) {
+            return;
+        }
+        if (cache.size() > 1000) {
+            cache.clear();
+        }
+        cache.put(key, value);
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/http/HttpMessages.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/http/HttpMessages.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/http/HttpMessages.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,106 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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;
+
+import org.apache.tomcat.util.res.StringManager;
+
+/**
+ * Handle (internationalized) HTTP messages.
+ * 
+ * @author James Duncan Davidson [duncan at eng.sun.com]
+ * @author James Todd [gonzo at eng.sun.com]
+ * @author Jason Hunter [jch at eng.sun.com]
+ * @author Harish Prabandham
+ * @author costin at eng.sun.com
+ */
+public class HttpMessages {
+    // XXX move message resources in this package
+    protected static StringManager sm =
+        StringManager.getManager("org.apache.tomcat.util.http.res");
+	
+    static String st_200=null;
+    static String st_302=null;
+    static String st_400=null;
+    static String st_404=null;
+    
+    /** Get the status string associated with a status code.
+     *  No I18N - return the messages defined in the HTTP spec.
+     *  ( the user isn't supposed to see them, this is the last
+     *  thing to translate)
+     *
+     *  Common messages are cached.
+     *
+     */
+    public static String getMessage( int status ) {
+	// method from Response.
+	
+	// Does HTTP requires/allow international messages or
+	// are pre-defined? The user doesn't see them most of the time
+	switch( status ) {
+	case 200:
+	    if( st_200==null ) st_200=sm.getString( "sc.200");
+	    return st_200;
+	case 302:
+	    if( st_302==null ) st_302=sm.getString( "sc.302");
+	    return st_302;
+	case 400:
+	    if( st_400==null ) st_400=sm.getString( "sc.400");
+	    return st_400;
+	case 404:
+	    if( st_404==null ) st_404=sm.getString( "sc.404");
+	    return st_404;
+	}
+	return sm.getString("sc."+ status);
+    }
+
+    /**
+     * Filter the specified message string for characters that are sensitive
+     * in HTML.  This avoids potential attacks caused by including JavaScript
+     * codes in the request URL that is often reported in error messages.
+     *
+     * @param message The message string to be filtered
+     */
+    public static String filter(String message) {
+
+	if (message == null)
+	    return (null);
+
+	char content[] = new char[message.length()];
+	message.getChars(0, message.length(), content, 0);
+	StringBuffer result = new StringBuffer(content.length + 50);
+	for (int i = 0; i < content.length; i++) {
+	    switch (content[i]) {
+	    case '<':
+		result.append("&lt;");
+		break;
+	    case '>':
+		result.append("&gt;");
+		break;
+	    case '&':
+		result.append("&amp;");
+		break;
+	    case '"':
+		result.append("&quot;");
+		break;
+	    default:
+		result.append(content[i]);
+	    }
+	}
+	return (result.toString());
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/http/MimeHeaders.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/http/MimeHeaders.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/http/MimeHeaders.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,456 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.Enumeration;
+
+import org.apache.tomcat.util.buf.MessageBytes;
+
+/* XXX XXX XXX Need a major rewrite  !!!!
+ */
+
+/**
+ * This class is used to contain standard internet message headers,
+ * used for SMTP (RFC822) and HTTP (RFC2068) messages as well as for
+ * MIME (RFC 2045) applications such as transferring typed data and
+ * grouping related items in multipart message bodies.
+ *
+ * <P> Message headers, as specified in RFC822, include a field name
+ * and a field body.  Order has no semantic significance, and several
+ * fields with the same name may exist.  However, most fields do not
+ * (and should not) exist more than once in a header.
+ *
+ * <P> Many kinds of field body must conform to a specified syntax,
+ * including the standard parenthesized comment syntax.  This class
+ * supports only two simple syntaxes, for dates and integers.
+ *
+ * <P> When processing headers, care must be taken to handle the case of
+ * multiple same-name fields correctly.  The values of such fields are
+ * only available as strings.  They may be accessed by index (treating
+ * the header as an array of fields), or by name (returning an array
+ * of string values).
+ */
+
+/* Headers are first parsed and stored in the order they are
+   received. This is based on the fact that most servlets will not
+   directly access all headers, and most headers are single-valued.
+   ( the alternative - a hash or similar data structure - will add
+   an overhead that is not needed in most cases )
+   
+   Apache seems to be using a similar method for storing and manipulating
+   headers.
+       
+   Future enhancements:
+   - hash the headers the first time a header is requested ( i.e. if the
+   servlet needs direct access to headers).
+   - scan "common" values ( length, cookies, etc ) during the parse
+   ( addHeader hook )
+   
+*/
+    
+
+
+/**
+ *  Memory-efficient repository for Mime Headers. When the object is recycled, it
+ *  will keep the allocated headers[] and all the MimeHeaderField - no GC is generated.
+ *
+ *  For input headers it is possible to use the MessageByte for Fileds - so no GC
+ *  will be generated.
+ *
+ *  The only garbage is generated when using the String for header names/values -
+ *  this can't be avoided when the servlet calls header methods, but is easy
+ *  to avoid inside tomcat. The goal is to use _only_ MessageByte-based Fields,
+ *  and reduce to 0 the memory overhead of tomcat.
+ *
+ *  TODO:
+ *  XXX one-buffer parsing - for http ( other protocols don't need that )
+ *  XXX remove unused methods
+ *  XXX External enumerations, with 0 GC.
+ *  XXX use HeaderName ID
+ *  
+ * 
+ * @author dac at eng.sun.com
+ * @author James Todd [gonzo at eng.sun.com]
+ * @author Costin Manolache
+ * @author kevin seguin
+ */
+public class MimeHeaders {
+    /** Initial size - should be == average number of headers per request
+     *  XXX  make it configurable ( fine-tuning of web-apps )
+     */
+    public static final int DEFAULT_HEADER_SIZE=8;
+    
+    /**
+     * The header fields.
+     */
+    private MimeHeaderField[] headers = new
+	MimeHeaderField[DEFAULT_HEADER_SIZE];
+
+    /**
+     * The current number of header fields.
+     */
+    private int count;
+
+    /**
+     * Creates a new MimeHeaders object using a default buffer size.
+     */
+    public MimeHeaders() {
+    }
+
+    /**
+     * Clears all header fields.
+     */
+    // [seguin] added for consistency -- most other objects have recycle().
+    public void recycle() {
+        clear();
+    }
+
+    /**
+     * Clears all header fields.
+     */
+    public void clear() {
+	for (int i = 0; i < count; i++) {
+	    headers[i].recycle();
+	}
+	count = 0;
+    }
+
+    /**
+     * EXPENSIVE!!!  only for debugging.
+     */
+    public String toString() {
+        StringWriter sw = new StringWriter();
+        PrintWriter pw = new PrintWriter(sw);
+        pw.println("=== MimeHeaders ===");
+        Enumeration e = names();
+        while (e.hasMoreElements()) {
+            String n = (String)e.nextElement();
+            pw.println(n + " = " + getHeader(n));
+        }
+        return sw.toString();
+    }
+
+    // -------------------- Idx access to headers ----------
+    
+    /**
+     * Returns the current number of header fields.
+     */
+    public int size() {
+	return count;
+    }
+
+    /**
+     * Returns the Nth header name, or null if there is no such header.
+     * This may be used to iterate through all header fields.
+     */
+    public MessageBytes getName(int n) {
+	return n >= 0 && n < count ? headers[n].getName() : null;
+    }
+
+    /**
+     * Returns the Nth header value, or null if there is no such header.
+     * This may be used to iterate through all header fields.
+     */
+    public MessageBytes getValue(int n) {
+	return n >= 0 && n < count ? headers[n].getValue() : null;
+    }
+
+    /** Find the index of a header with the given name.
+     */
+    public int findHeader( String name, int starting ) {
+	// We can use a hash - but it's not clear how much
+	// benefit you can get - there is an  overhead 
+	// and the number of headers is small (4-5 ?)
+	// Another problem is that we'll pay the overhead
+	// of constructing the hashtable
+
+	// A custom search tree may be better
+        for (int i = starting; i < count; i++) {
+	    if (headers[i].getName().equalsIgnoreCase(name)) {
+                return i;
+            }
+        }
+        return -1;
+    }
+    
+    // -------------------- --------------------
+
+    /**
+     * Returns an enumeration of strings representing the header field names.
+     * Field names may appear multiple times in this enumeration, indicating
+     * that multiple fields with that name exist in this header.
+     */
+    public Enumeration names() {
+	return new NamesEnumerator(this);
+    }
+
+    public Enumeration values(String name) {
+	return new ValuesEnumerator(this, name);
+    }
+
+    // -------------------- Adding headers --------------------
+    
+
+    /**
+     * Adds a partially constructed field to the header.  This
+     * field has not had its name or value initialized.
+     */
+    private MimeHeaderField createHeader() {
+	MimeHeaderField mh;
+	int len = headers.length;
+	if (count >= len) {
+	    // expand header list array
+	    MimeHeaderField tmp[] = new MimeHeaderField[count * 2];
+	    System.arraycopy(headers, 0, tmp, 0, len);
+	    headers = tmp;
+	}
+	if ((mh = headers[count]) == null) {
+	    headers[count] = mh = new MimeHeaderField();
+	}
+	count++;
+	return mh;
+    }
+
+    /** Create a new named header , return the MessageBytes
+	container for the new value
+    */
+    public MessageBytes addValue( String name ) {
+ 	MimeHeaderField mh = createHeader();
+	mh.getName().setString(name);
+	return mh.getValue();
+    }
+
+    /** Create a new named header using un-translated byte[].
+	The conversion to chars can be delayed until
+	encoding is known.
+     */
+    public MessageBytes addValue(byte b[], int startN, int len)
+    {
+	MimeHeaderField mhf=createHeader();
+	mhf.getName().setBytes(b, startN, len);
+	return mhf.getValue();
+    }
+
+    /** Create a new named header using translated char[].
+     */
+    public MessageBytes addValue(char c[], int startN, int len)
+    {
+	MimeHeaderField mhf=createHeader();
+	mhf.getName().setChars(c, startN, len);
+	return mhf.getValue();
+    }
+
+    /** Allow "set" operations - 
+        return a MessageBytes container for the
+	header value ( existing header or new
+	if this .
+    */
+    public MessageBytes setValue( String name ) {
+        for ( int i = 0; i < count; i++ ) {
+            if(headers[i].getName().equalsIgnoreCase(name)) {
+                for ( int j=i+1; j < count; j++ ) {
+                    if(headers[j].getName().equalsIgnoreCase(name)) {
+                        removeHeader(j--);
+                    }
+                }
+                return headers[i].getValue();
+            }
+        }
+        MimeHeaderField mh = createHeader();
+        mh.getName().setString(name);
+        return mh.getValue();
+    }
+
+    //-------------------- Getting headers --------------------
+    /**
+     * Finds and returns a header field with the given name.  If no such
+     * field exists, null is returned.  If more than one such field is
+     * in the header, an arbitrary one is returned.
+     */
+    public MessageBytes getValue(String name) {
+        for (int i = 0; i < count; i++) {
+	    if (headers[i].getName().equalsIgnoreCase(name)) {
+                return headers[i].getValue();
+            }
+        }
+        return null;
+    }
+
+    // bad shortcut - it'll convert to string ( too early probably,
+    // encoding is guessed very late )
+    public String getHeader(String name) {
+	MessageBytes mh = getValue(name);
+	return mh != null ? mh.toString() : null;
+    }
+
+    // -------------------- Removing --------------------
+    /**
+     * Removes a header field with the specified name.  Does nothing
+     * if such a field could not be found.
+     * @param name the name of the header field to be removed
+     */
+    public void removeHeader(String name) {
+        // XXX
+        // warning: rather sticky code; heavily tuned
+
+        for (int i = 0; i < count; i++) {
+            if (headers[i].getName().equalsIgnoreCase(name)) {
+                removeHeader(i--);
+            }
+        }
+    }
+
+    /**
+     * reset and swap with last header
+     * @param idx the index of the header to remove.
+     */
+    private void removeHeader(int idx) {
+        MimeHeaderField mh = headers[idx];
+        
+        mh.recycle();
+        headers[idx] = headers[count - 1];
+        headers[count - 1] = mh;
+        count--;
+    }
+
+}
+
+/** Enumerate the distinct header names.
+    Each nextElement() is O(n) ( a comparation is
+    done with all previous elements ).
+
+    This is less frequesnt than add() -
+    we want to keep add O(1).
+*/
+class NamesEnumerator implements Enumeration {
+    int pos;
+    int size;
+    String next;
+    MimeHeaders headers;
+
+    NamesEnumerator(MimeHeaders headers) {
+	this.headers=headers;
+	pos=0;
+	size = headers.size();
+	findNext();
+    }
+
+    private void findNext() {
+	next=null;
+	for(  ; pos< size; pos++ ) {
+	    next=headers.getName( pos ).toString();
+	    for( int j=0; j<pos ; j++ ) {
+		if( headers.getName( j ).equalsIgnoreCase( next )) {
+		    // duplicate.
+		    next=null;
+		    break;
+		}
+	    }
+	    if( next!=null ) {
+		// it's not a duplicate
+		break;
+	    }
+	}
+	// next time findNext is called it will try the
+	// next element
+	pos++;
+    }
+    
+    public boolean hasMoreElements() {
+	return next!=null;
+    }
+
+    public Object nextElement() {
+	String current=next;
+	findNext();
+	return current;
+    }
+}
+
+/** Enumerate the values for a (possibly ) multiple
+    value element.
+*/
+class ValuesEnumerator implements Enumeration {
+    int pos;
+    int size;
+    MessageBytes next;
+    MimeHeaders headers;
+    String name;
+
+    ValuesEnumerator(MimeHeaders headers, String name) {
+        this.name=name;
+	this.headers=headers;
+	pos=0;
+	size = headers.size();
+	findNext();
+    }
+
+    private void findNext() {
+	next=null;
+	for( ; pos< size; pos++ ) {
+	    MessageBytes n1=headers.getName( pos );
+	    if( n1.equalsIgnoreCase( name )) {
+		next=headers.getValue( pos );
+		break;
+	    }
+	}
+	pos++;
+    }
+    
+    public boolean hasMoreElements() {
+	return next!=null;
+    }
+
+    public Object nextElement() {
+	MessageBytes current=next;
+	findNext();
+	return current.toString();
+    }
+}
+
+class MimeHeaderField {
+    // multiple headers with same name - a linked list will
+    // speed up name enumerations and search ( both cpu and
+    // GC)
+    MimeHeaderField next;
+    MimeHeaderField prev; 
+    
+    protected final MessageBytes nameB = MessageBytes.newInstance();
+    protected final MessageBytes valueB = MessageBytes.newInstance();
+
+    /**
+     * Creates a new, uninitialized header field.
+     */
+    public MimeHeaderField() {
+    }
+
+    public void recycle() {
+	nameB.recycle();
+	valueB.recycle();
+	next=null;
+    }
+
+    public MessageBytes getName() {
+	return nameB;
+    }
+
+    public MessageBytes getValue() {
+	return valueB;
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/http/MimeMap.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/http/MimeMap.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/http/MimeMap.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,187 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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;
+
+import java.net.*;
+import java.util.*;
+
+
+/**
+ * A mime type map that implements the java.net.FileNameMap interface.
+ *
+ * @author James Duncan Davidson [duncan at eng.sun.com]
+ * @author Jason Hunter [jch at eng.sun.com]
+ */
+public class MimeMap implements FileNameMap {
+
+    // Defaults - all of them are "well-known" types,
+    // you can add using normal web.xml.
+    
+    public static Hashtable defaultMap=new Hashtable(101);
+    static {
+        defaultMap.put("txt", "text/plain");
+        defaultMap.put("html","text/html");
+        defaultMap.put("htm", "text/html");
+        defaultMap.put("gif", "image/gif");
+        defaultMap.put("jpg", "image/jpeg");
+        defaultMap.put("jpe", "image/jpeg");
+        defaultMap.put("jpeg", "image/jpeg");
+        defaultMap.put("png", "image/png");
+		defaultMap.put("java", "text/plain");
+        defaultMap.put("body", "text/html");
+        defaultMap.put("rtx", "text/richtext");
+        defaultMap.put("tsv", "text/tab-separated-values");
+        defaultMap.put("etx", "text/x-setext");
+        defaultMap.put("ps", "application/x-postscript");
+        defaultMap.put("class", "application/java");
+        defaultMap.put("csh", "application/x-csh");
+        defaultMap.put("sh", "application/x-sh");
+        defaultMap.put("tcl", "application/x-tcl");
+        defaultMap.put("tex", "application/x-tex");
+        defaultMap.put("texinfo", "application/x-texinfo");
+        defaultMap.put("texi", "application/x-texinfo");
+        defaultMap.put("t", "application/x-troff");
+        defaultMap.put("tr", "application/x-troff");
+        defaultMap.put("roff", "application/x-troff");
+        defaultMap.put("man", "application/x-troff-man");
+        defaultMap.put("me", "application/x-troff-me");
+        defaultMap.put("ms", "application/x-wais-source");
+        defaultMap.put("src", "application/x-wais-source");
+        defaultMap.put("zip", "application/zip");
+        defaultMap.put("bcpio", "application/x-bcpio");
+        defaultMap.put("cpio", "application/x-cpio");
+        defaultMap.put("gtar", "application/x-gtar");
+        defaultMap.put("shar", "application/x-shar");
+        defaultMap.put("sv4cpio", "application/x-sv4cpio");
+        defaultMap.put("sv4crc", "application/x-sv4crc");
+        defaultMap.put("tar", "application/x-tar");
+        defaultMap.put("ustar", "application/x-ustar");
+        defaultMap.put("dvi", "application/x-dvi");
+        defaultMap.put("hdf", "application/x-hdf");
+        defaultMap.put("latex", "application/x-latex");
+        defaultMap.put("bin", "application/octet-stream");
+        defaultMap.put("oda", "application/oda");
+        defaultMap.put("pdf", "application/pdf");
+        defaultMap.put("ps", "application/postscript");
+        defaultMap.put("eps", "application/postscript");
+        defaultMap.put("ai", "application/postscript");
+        defaultMap.put("rtf", "application/rtf");
+        defaultMap.put("nc", "application/x-netcdf");
+        defaultMap.put("cdf", "application/x-netcdf");
+        defaultMap.put("cer", "application/x-x509-ca-cert");
+        defaultMap.put("exe", "application/octet-stream");
+        defaultMap.put("gz", "application/x-gzip");
+        defaultMap.put("Z", "application/x-compress");
+        defaultMap.put("z", "application/x-compress");
+        defaultMap.put("hqx", "application/mac-binhex40");
+        defaultMap.put("mif", "application/x-mif");
+        defaultMap.put("ief", "image/ief");
+        defaultMap.put("tiff", "image/tiff");
+        defaultMap.put("tif", "image/tiff");
+        defaultMap.put("ras", "image/x-cmu-raster");
+        defaultMap.put("pnm", "image/x-portable-anymap");
+        defaultMap.put("pbm", "image/x-portable-bitmap");
+        defaultMap.put("pgm", "image/x-portable-graymap");
+        defaultMap.put("ppm", "image/x-portable-pixmap");
+        defaultMap.put("rgb", "image/x-rgb");
+        defaultMap.put("xbm", "image/x-xbitmap");
+        defaultMap.put("xpm", "image/x-xpixmap");
+        defaultMap.put("xwd", "image/x-xwindowdump");
+        defaultMap.put("au", "audio/basic");
+        defaultMap.put("snd", "audio/basic");
+        defaultMap.put("aif", "audio/x-aiff");
+        defaultMap.put("aiff", "audio/x-aiff");
+        defaultMap.put("aifc", "audio/x-aiff");
+        defaultMap.put("wav", "audio/x-wav");
+        defaultMap.put("mpeg", "video/mpeg");
+        defaultMap.put("mpg", "video/mpeg");
+        defaultMap.put("mpe", "video/mpeg");
+        defaultMap.put("qt", "video/quicktime");
+        defaultMap.put("mov", "video/quicktime");
+        defaultMap.put("avi", "video/x-msvideo");
+        defaultMap.put("movie", "video/x-sgi-movie");
+        defaultMap.put("avx", "video/x-rad-screenplay");
+        defaultMap.put("wrl", "x-world/x-vrml");
+        defaultMap.put("mpv2", "video/mpeg2");
+        
+        /* Add XML related MIMEs */
+        
+        defaultMap.put("xml", "text/xml");
+        defaultMap.put("xsl", "text/xml");        
+        defaultMap.put("svg", "image/svg+xml");
+        defaultMap.put("svgz", "image/svg+xml");
+        defaultMap.put("wbmp", "image/vnd.wap.wbmp");
+        defaultMap.put("wml", "text/vnd.wap.wml");
+        defaultMap.put("wmlc", "application/vnd.wap.wmlc");
+        defaultMap.put("wmls", "text/vnd.wap.wmlscript");
+        defaultMap.put("wmlscriptc", "application/vnd.wap.wmlscriptc");
+    }
+    
+
+    private Hashtable map = new Hashtable();
+
+    public void addContentType(String extn, String type) {
+        map.put(extn, type.toLowerCase());
+    }
+
+    public Enumeration getExtensions() {
+        return map.keys();
+    }
+
+    public String getContentType(String extn) {
+        String type = (String)map.get(extn.toLowerCase());
+	if( type == null ) type=(String)defaultMap.get( extn );
+	return type;
+    }
+
+    public void removeContentType(String extn) {
+        map.remove(extn.toLowerCase());
+    }
+
+    /** Get extension of file, without fragment id
+     */
+    public static String getExtension( String fileName ) {
+        // play it safe and get rid of any fragment id
+        // that might be there
+	int length=fileName.length();
+	
+        int newEnd = fileName.lastIndexOf('#');
+	if( newEnd== -1 ) newEnd=length;
+	// Instead of creating a new string.
+	//         if (i != -1) {
+	//             fileName = fileName.substring(0, i);
+	//         }
+        int i = fileName.lastIndexOf('.', newEnd );
+        if (i != -1) {
+             return  fileName.substring(i + 1, newEnd );
+        } else {
+            // no extension, no content type
+            return null;
+        }
+    }
+    
+    public String getContentTypeFor(String fileName) {
+	String extn=getExtension( fileName );
+        if (extn!=null) {
+            return getContentType(extn);
+        } else {
+            // no extension, no content type
+            return null;
+        }
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/http/Parameters.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/http/Parameters.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/http/Parameters.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,611 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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;
+
+import java.io.IOException;
+import java.util.Enumeration;
+import java.util.Hashtable;
+
+import org.apache.tomcat.util.buf.ByteChunk;
+import org.apache.tomcat.util.buf.CharChunk;
+import org.apache.tomcat.util.buf.MessageBytes;
+import org.apache.tomcat.util.buf.UDecoder;
+import org.apache.tomcat.util.collections.MultiMap;
+
+/**
+ * 
+ * @author Costin Manolache
+ */
+public final class Parameters extends MultiMap {
+
+    
+    private static org.apache.commons.logging.Log log=
+        org.apache.commons.logging.LogFactory.getLog(Parameters.class );
+    
+    // Transition: we'll use the same Hashtable( String->String[] )
+    // for the beginning. When we are sure all accesses happen through
+    // this class - we can switch to MultiMap
+    private Hashtable paramHashStringArray=new Hashtable();
+    private boolean didQueryParameters=false;
+    private boolean didMerge=false;
+    
+    MessageBytes queryMB;
+    MimeHeaders  headers;
+
+    UDecoder urlDec;
+    MessageBytes decodedQuery=MessageBytes.newInstance();
+    
+    public static final int INITIAL_SIZE=4;
+
+    // Garbage-less parameter merging.
+    // In a sub-request with parameters, the new parameters
+    // will be stored in child. When a getParameter happens,
+    // the 2 are merged togheter. The child will be altered
+    // to contain the merged values - the parent is allways the
+    // original request.
+    private Parameters child=null;
+    private Parameters parent=null;
+    private Parameters currentChild=null;
+
+    String encoding=null;
+    String queryStringEncoding=null;
+    
+    /**
+     * 
+     */
+    public Parameters() {
+	super( INITIAL_SIZE );
+    }
+
+    public void setQuery( MessageBytes queryMB ) {
+	this.queryMB=queryMB;
+    }
+
+    public void setHeaders( MimeHeaders headers ) {
+	this.headers=headers;
+    }
+
+    public void setEncoding( String s ) {
+	encoding=s;
+	if(debug>0) log( "Set encoding to " + s );
+    }
+
+    public void setQueryStringEncoding( String s ) {
+	queryStringEncoding=s;
+	if(debug>0) log( "Set query string encoding to " + s );
+    }
+
+    public void recycle() {
+	super.recycle();
+	paramHashStringArray.clear();
+	didQueryParameters=false;
+	currentChild=null;
+	didMerge=false;
+	encoding=null;
+	decodedQuery.recycle();
+    }
+    
+    // -------------------- Sub-request support --------------------
+
+    public Parameters getCurrentSet() {
+	if( currentChild==null )
+	    return this;
+	return currentChild;
+    }
+    
+    /** Create ( or reuse ) a child that will be used during a sub-request.
+	All future changes ( setting query string, adding parameters )
+	will affect the child ( the parent request is never changed ).
+	Both setters and getters will return the data from the deepest
+	child, merged with data from parents.
+    */
+    public void push() {
+	// We maintain a linked list, that will grow to the size of the
+	// longest include chain.
+	// The list has 2 points of interest:
+	// - request.parameters() is the original request and head,
+	// - request.parameters().currentChild() is the current set.
+	// The ->child and parent<- links are preserved ( currentChild is not
+	// the last in the list )
+	
+	// create a new element in the linked list
+	// note that we reuse the child, if any - pop will not
+	// set child to null !
+	if( currentChild==null ) {
+	    currentChild=new Parameters();
+	    currentChild.setURLDecoder( urlDec );
+	    currentChild.parent=this;
+	    return;
+	}
+	if( currentChild.child==null ) {
+	    currentChild.child=new Parameters();
+	    currentChild.setURLDecoder( urlDec );
+	    currentChild.child.parent=currentChild;
+	} // it is not null if this object already had a child
+	// i.e. a deeper include() ( we keep it )
+
+	// the head will be the new element.
+	currentChild=currentChild.child;
+	currentChild.setEncoding( encoding );
+    }
+
+    /** Discard the last child. This happens when we return from a
+	sub-request and the parameters are locally modified.
+     */
+    public void pop() {
+	if( currentChild==null ) {
+	    throw new RuntimeException( "Attempt to pop without a push" );
+	}
+	currentChild.recycle();
+	currentChild=currentChild.parent;
+	// don't remove the top.
+    }
+    
+    // -------------------- Data access --------------------
+    // Access to the current name/values, no side effect ( processing ).
+    // You must explicitely call handleQueryParameters and the post methods.
+    
+    // This is the original data representation ( hash of String->String[])
+
+    public void addParameterValues( String key, String[] newValues) {
+        if ( key==null ) return;
+        String values[];
+        if (paramHashStringArray.containsKey(key)) {
+            String oldValues[] = (String[])paramHashStringArray.get(key);
+            values = new String[oldValues.length + newValues.length];
+            for (int i = 0; i < oldValues.length; i++) {
+                values[i] = oldValues[i];
+            }
+            for (int i = 0; i < newValues.length; i++) {
+                values[i+ oldValues.length] = newValues[i];
+            }
+        } else {
+            values = newValues;
+        }
+
+        paramHashStringArray.put(key, values);
+    }
+
+    public String[] getParameterValues(String name) {
+	handleQueryParameters();
+	// sub-request
+	if( currentChild!=null ) {
+	    currentChild.merge();
+	    return (String[])currentChild.paramHashStringArray.get(name);
+	}
+
+	// no "facade"
+	String values[]=(String[])paramHashStringArray.get(name);
+	return values;
+    }
+ 
+    public Enumeration getParameterNames() {
+	handleQueryParameters();
+	// Slow - the original code
+	if( currentChild!=null ) {
+	    currentChild.merge();
+	    return currentChild.paramHashStringArray.keys();
+	}
+
+	// merge in child
+        return paramHashStringArray.keys();
+    }
+
+    /** Combine the parameters from parent with our local ones
+     */
+    private void merge() {
+	// recursive
+	if( debug > 0 ) {
+	    log("Before merging " + this + " " + parent + " " + didMerge );
+	    log(  paramsAsString());
+	}
+	// Local parameters first - they take precedence as in spec.
+	handleQueryParameters();
+
+	// we already merged with the parent
+	if( didMerge ) return;
+
+	// we are the top level
+	if( parent==null ) return;
+
+	// Add the parent props to the child ( lower precedence )
+	parent.merge();
+	Hashtable parentProps=parent.paramHashStringArray;
+	merge2( paramHashStringArray , parentProps);
+	didMerge=true;
+	if(debug > 0 )
+	    log("After " + paramsAsString());
+    }
+
+
+    // Shortcut.
+    public String getParameter(String name ) {
+	String[] values = getParameterValues(name);
+        if (values != null) {
+	    if( values.length==0 ) return "";
+            return values[0];
+        } else {
+	    return null;
+        }
+    }
+    // -------------------- Processing --------------------
+    /** Process the query string into parameters
+     */
+    public void handleQueryParameters() {
+	if( didQueryParameters ) return;
+
+	didQueryParameters=true;
+
+	if( queryMB==null || queryMB.isNull() )
+	    return;
+	
+	if( debug > 0  )
+	    log( "Decoding query " + decodedQuery + " " + queryStringEncoding);
+
+        try {
+            decodedQuery.duplicate( queryMB );
+        } catch (IOException e) {
+            // Can't happen, as decodedQuery can't overflow
+            e.printStackTrace();
+        }
+        processParameters( decodedQuery, queryStringEncoding );
+    }
+
+    // --------------------
+    
+    /** Combine 2 hashtables into a new one.
+     *  ( two will be added to one ).
+     *  Used to combine child parameters ( RequestDispatcher's query )
+     *  with parent parameters ( original query or parent dispatcher )
+     */
+    private static void merge2(Hashtable one, Hashtable two ) {
+        Enumeration e = two.keys();
+
+	while (e.hasMoreElements()) {
+	    String name = (String) e.nextElement();
+	    String[] oneValue = (String[]) one.get(name);
+	    String[] twoValue = (String[]) two.get(name);
+	    String[] combinedValue;
+
+	    if (twoValue == null) {
+		continue;
+	    } else {
+		if( oneValue==null ) {
+		    combinedValue = new String[twoValue.length];
+		    System.arraycopy(twoValue, 0, combinedValue,
+				     0, twoValue.length);
+		} else {
+		    combinedValue = new String[oneValue.length +
+					       twoValue.length];
+		    System.arraycopy(oneValue, 0, combinedValue, 0,
+				     oneValue.length);
+		    System.arraycopy(twoValue, 0, combinedValue,
+				     oneValue.length, twoValue.length);
+		}
+		one.put(name, combinedValue);
+	    }
+	}
+    }
+
+    // incredibly inefficient data representation for parameters,
+    // until we test the new one
+    private void addParam( String key, String value ) {
+	if( key==null ) return;
+	String values[];
+	if (paramHashStringArray.containsKey(key)) {
+	    String oldValues[] = (String[])paramHashStringArray.
+		get(key);
+	    values = new String[oldValues.length + 1];
+	    for (int i = 0; i < oldValues.length; i++) {
+		values[i] = oldValues[i];
+	    }
+	    values[oldValues.length] = value;
+	} else {
+	    values = new String[1];
+	    values[0] = value;
+	}
+	
+	
+	paramHashStringArray.put(key, values);
+    }
+
+    public void setURLDecoder( UDecoder u ) {
+	urlDec=u;
+    }
+
+    // -------------------- Parameter parsing --------------------
+
+    // This code is not used right now - it's the optimized version
+    // of the above.
+
+    // we are called from a single thread - we can do it the hard way
+    // if needed
+    ByteChunk tmpName=new ByteChunk();
+    ByteChunk tmpValue=new ByteChunk();
+    CharChunk tmpNameC=new CharChunk(1024);
+    CharChunk tmpValueC=new CharChunk(1024);
+    
+    public void processParameters( byte bytes[], int start, int len ) {
+        processParameters(bytes, start, len, encoding);
+    }
+
+    public void processParameters( byte bytes[], int start, int len, 
+                                   String enc ) {
+	int end=start+len;
+	int pos=start;
+	
+	if( debug>0 ) 
+	    log( "Bytes: " + new String( bytes, start, len ));
+
+        do {
+	    boolean noEq=false;
+	    int valStart=-1;
+	    int valEnd=-1;
+	    
+	    int nameStart=pos;
+	    int nameEnd=ByteChunk.indexOf(bytes, nameStart, end, '=' );
+	    // Workaround for a&b&c encoding
+	    int nameEnd2=ByteChunk.indexOf(bytes, nameStart, end, '&' );
+	    if( (nameEnd2!=-1 ) &&
+		( nameEnd==-1 || nameEnd > nameEnd2) ) {
+		nameEnd=nameEnd2;
+		noEq=true;
+		valStart=nameEnd;
+		valEnd=nameEnd;
+		if( debug>0) log("no equal " + nameStart + " " + nameEnd + " " + new String(bytes, nameStart, nameEnd-nameStart) );
+	    }
+	    if( nameEnd== -1 ) 
+		nameEnd=end;
+
+	    if( ! noEq ) {
+		valStart= (nameEnd < end) ? nameEnd+1 : end;
+		valEnd=ByteChunk.indexOf(bytes, valStart, end, '&');
+		if( valEnd== -1 ) valEnd = (valStart < end) ? end : valStart;
+	    }
+	    
+	    pos=valEnd+1;
+	    
+	    if( nameEnd<=nameStart ) {
+		continue;
+		// invalid chunk - it's better to ignore
+		// XXX log it ?
+	    }
+	    tmpName.setBytes( bytes, nameStart, nameEnd-nameStart );
+	    tmpValue.setBytes( bytes, valStart, valEnd-valStart );
+
+            try {
+                addParam( urlDecode(tmpName, enc), urlDecode(tmpValue, enc) );
+            } catch (IOException e) {
+                // Exception during character decoding: skip parameter
+            }
+
+	    tmpName.recycle();
+	    tmpValue.recycle();
+
+	} while( pos<end );
+    }
+
+    private String urlDecode(ByteChunk bc, String enc)
+        throws IOException {
+        if( urlDec==null ) {
+            urlDec=new UDecoder();   
+        }
+        urlDec.convert(bc);
+        String result = null;
+        if (enc != null) {
+            bc.setEncoding(enc);
+            result = bc.toString();
+        } else {
+            CharChunk cc = tmpNameC;
+            cc.allocate(bc.getLength(), -1);
+            // Default encoding: fast conversion
+            byte[] bbuf = bc.getBuffer();
+            char[] cbuf = cc.getBuffer();
+            int start = bc.getStart();
+            for (int i = 0; i < bc.getLength(); i++) {
+                cbuf[i] = (char) (bbuf[i + start] & 0xff);
+            }
+            cc.setChars(cbuf, 0, bc.getLength());
+            result = cc.toString();
+            cc.recycle();
+        }
+        return result;
+    }
+
+    public void processParameters( char chars[], int start, int len ) {
+	int end=start+len;
+	int pos=start;
+	
+	if( debug>0 ) 
+	    log( "Chars: " + new String( chars, start, len ));
+        do {
+	    boolean noEq=false;
+	    int nameStart=pos;
+	    int valStart=-1;
+	    int valEnd=-1;
+	    
+	    int nameEnd=CharChunk.indexOf(chars, nameStart, end, '=' );
+	    int nameEnd2=CharChunk.indexOf(chars, nameStart, end, '&' );
+	    if( (nameEnd2!=-1 ) &&
+		( nameEnd==-1 || nameEnd > nameEnd2) ) {
+		nameEnd=nameEnd2;
+		noEq=true;
+		valStart=nameEnd;
+		valEnd=nameEnd;
+		if( debug>0) log("no equal " + nameStart + " " + nameEnd + " " + new String(chars, nameStart, nameEnd-nameStart) );
+	    }
+	    if( nameEnd== -1 ) nameEnd=end;
+	    
+	    if( ! noEq ) {
+		valStart= (nameEnd < end) ? nameEnd+1 : end;
+		valEnd=CharChunk.indexOf(chars, valStart, end, '&');
+		if( valEnd== -1 ) valEnd = (valStart < end) ? end : valStart;
+	    }
+	    
+	    pos=valEnd+1;
+	    
+	    if( nameEnd<=nameStart ) {
+		continue;
+		// invalid chunk - no name, it's better to ignore
+		// XXX log it ?
+	    }
+	    
+	    try {
+		tmpNameC.append( chars, nameStart, nameEnd-nameStart );
+		tmpValueC.append( chars, valStart, valEnd-valStart );
+
+		if( debug > 0 )
+		    log( tmpNameC + "= " + tmpValueC);
+
+		if( urlDec==null ) {
+		    urlDec=new UDecoder();   
+		}
+
+		urlDec.convert( tmpNameC );
+		urlDec.convert( tmpValueC );
+
+		if( debug > 0 )
+		    log( tmpNameC + "= " + tmpValueC);
+		
+		addParam( tmpNameC.toString(), tmpValueC.toString() );
+	    } catch( IOException ex ) {
+		ex.printStackTrace();
+	    }
+
+	    tmpNameC.recycle();
+	    tmpValueC.recycle();
+
+	} while( pos<end );
+    }
+    
+    public void processParameters( MessageBytes data ) {
+        processParameters(data, encoding);
+    }
+
+    public void processParameters( MessageBytes data, String encoding ) {
+	if( data==null || data.isNull() || data.getLength() <= 0 ) return;
+
+	if( data.getType() == MessageBytes.T_BYTES ) {
+	    ByteChunk bc=data.getByteChunk();
+	    processParameters( bc.getBytes(), bc.getOffset(),
+			       bc.getLength(), encoding);
+	} else {
+	    if (data.getType()!= MessageBytes.T_CHARS ) 
+		data.toChars();
+	    CharChunk cc=data.getCharChunk();
+	    processParameters( cc.getChars(), cc.getOffset(),
+			       cc.getLength());
+	}
+    }
+
+    /** Debug purpose
+     */
+    public String paramsAsString() {
+	StringBuffer sb=new StringBuffer();
+	Enumeration en= paramHashStringArray.keys();
+	while( en.hasMoreElements() ) {
+	    String k=(String)en.nextElement();
+	    sb.append( k ).append("=");
+	    String v[]=(String[])paramHashStringArray.get( k );
+	    for( int i=0; i<v.length; i++ )
+		sb.append( v[i] ).append(",");
+	    sb.append("\n");
+	}
+	return sb.toString();
+    }
+
+    private static int debug=0;
+    private void log(String s ) {
+        if (log.isDebugEnabled())
+            log.debug("Parameters: " + s );
+    }
+   
+    // -------------------- Old code, needs rewrite --------------------
+    
+    /** Used by RequestDispatcher
+     */
+    public void processParameters( String str ) {
+	int end=str.length();
+	int pos=0;
+	if( debug > 0)
+	    log("String: " + str );
+	
+        do {
+	    boolean noEq=false;
+	    int valStart=-1;
+	    int valEnd=-1;
+	    
+	    int nameStart=pos;
+	    int nameEnd=str.indexOf('=', nameStart );
+	    int nameEnd2=str.indexOf('&', nameStart );
+	    if( nameEnd2== -1 ) nameEnd2=end;
+	    if( (nameEnd2!=-1 ) &&
+		( nameEnd==-1 || nameEnd > nameEnd2) ) {
+		nameEnd=nameEnd2;
+		noEq=true;
+		valStart=nameEnd;
+		valEnd=nameEnd;
+		if( debug>0) log("no equal " + nameStart + " " + nameEnd + " " + str.substring(nameStart, nameEnd) );
+	    }
+
+	    if( nameEnd== -1 ) nameEnd=end;
+
+	    if( ! noEq ) {
+		valStart=nameEnd+1;
+		valEnd=str.indexOf('&', valStart);
+		if( valEnd== -1 ) valEnd = (valStart < end) ? end : valStart;
+	    }
+	    
+	    pos=valEnd+1;
+	    
+	    if( nameEnd<=nameStart ) {
+		continue;
+	    }
+	    if( debug>0)
+		log( "XXX " + nameStart + " " + nameEnd + " "
+		     + valStart + " " + valEnd );
+	    
+	    try {
+		tmpNameC.append(str, nameStart, nameEnd-nameStart );
+		tmpValueC.append(str, valStart, valEnd-valStart );
+	    
+		if( debug > 0 )
+		    log( tmpNameC + "= " + tmpValueC);
+
+		if( urlDec==null ) {
+		    urlDec=new UDecoder();   
+		}
+
+		urlDec.convert( tmpNameC );
+		urlDec.convert( tmpValueC );
+
+		if( debug > 0 )
+		    log( tmpNameC + "= " + tmpValueC);
+		
+		addParam( tmpNameC.toString(), tmpValueC.toString() );
+	    } catch( IOException ex ) {
+		ex.printStackTrace();
+	    }
+
+	    tmpNameC.recycle();
+	    tmpValueC.recycle();
+
+	} while( pos<end );
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/http/ServerCookie.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/http/ServerCookie.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/http/ServerCookie.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,320 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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;
+
+import java.io.Serializable;
+import java.text.FieldPosition;
+import java.util.Date;
+
+import org.apache.tomcat.util.buf.DateTool;
+import org.apache.tomcat.util.buf.MessageBytes;
+
+
+/**
+ *  Server-side cookie representation.
+ *   Allows recycling and uses MessageBytes as low-level
+ *  representation ( and thus the byte-> char conversion can be delayed
+ *  until we know the charset ).
+ *
+ *  Tomcat.core uses this recyclable object to represent cookies,
+ *  and the facade will convert it to the external representation.
+ */
+public class ServerCookie implements Serializable {
+    
+    
+    private static org.apache.commons.logging.Log log=
+        org.apache.commons.logging.LogFactory.getLog(ServerCookie.class );
+    
+    private MessageBytes name=MessageBytes.newInstance();
+    private MessageBytes value=MessageBytes.newInstance();
+
+    private MessageBytes comment=MessageBytes.newInstance();    // ;Comment=VALUE
+    private MessageBytes domain=MessageBytes.newInstance();    // ;Domain=VALUE ...
+
+    private int maxAge = -1;	// ;Max-Age=VALUE
+				// ;Discard ... implied by maxAge < 0
+    // RFC2109: maxAge=0 will end a session
+    private MessageBytes path=MessageBytes.newInstance();	// ;Path=VALUE .
+    private boolean secure;	// ;Secure
+    private int version = 0;	// ;Version=1
+
+    //XXX CommentURL, Port -> use notes ?
+    
+    public ServerCookie() {
+
+    }
+
+    public void recycle() {
+        path.recycle();
+    	name.recycle();
+    	value.recycle();
+    	comment.recycle();
+    	maxAge=-1;
+    	path.recycle();
+        domain.recycle();
+    	version=0;
+    	secure=false;
+    }
+
+    public MessageBytes getComment() {
+	return comment;
+    }
+
+    public MessageBytes getDomain() {
+	return domain;
+    }
+
+    public void setMaxAge(int expiry) {
+	maxAge = expiry;
+    }
+
+    public int getMaxAge() {
+	return maxAge;
+    }
+
+
+    public MessageBytes getPath() {
+	return path;
+    }
+
+    public void setSecure(boolean flag) {
+	secure = flag;
+    }
+
+    public boolean getSecure() {
+	return secure;
+    }
+
+    public MessageBytes getName() {
+	return name;
+    }
+
+    public MessageBytes getValue() {
+	return value;
+    }
+
+    public int getVersion() {
+	return version;
+    }
+
+
+    public void setVersion(int v) {
+	version = v;
+    }
+
+
+    // -------------------- utils --------------------
+
+    public String toString() {
+	return "Cookie " + getName() + "=" + getValue() + " ; "
+	    + getVersion() + " " + getPath() + " " + getDomain();
+    }
+    
+    // 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 = ",; ";
+
+    /*
+     * Tests a string and returns true if the string counts as a
+     * reserved token in the Java language.
+     *
+     * @param value		the <code>String</code> to be tested
+     *
+     * @return			<code>true</code> if the <code>String</code> is
+     *				a reserved token; <code>false</code>
+     *				if it is not
+     */
+    public static boolean isToken(String value) {
+	if( value==null) return true;
+	int len = value.length();
+
+	for (int i = 0; i < len; i++) {
+	    char c = value.charAt(i);
+
+	    if (c < 0x20 || c >= 0x7f || tspecials.indexOf(c) != -1)
+		return false;
+	}
+	return true;
+    }
+
+    public static boolean checkName( String name ) {
+	if (!isToken(name)
+		|| name.equalsIgnoreCase("Comment")	// rfc2019
+		|| name.equalsIgnoreCase("Discard")	// 2019++
+		|| name.equalsIgnoreCase("Domain")
+		|| name.equalsIgnoreCase("Expires")	// (old cookies)
+		|| name.equalsIgnoreCase("Max-Age")	// rfc2019
+		|| name.equalsIgnoreCase("Path")
+		|| name.equalsIgnoreCase("Secure")
+		|| name.equalsIgnoreCase("Version")
+	    ) {
+	    return false;
+	}
+	return true;
+    }
+
+    // -------------------- Cookie parsing tools
+
+    
+    /** Return the header name to set the cookie, based on cookie
+     *  version
+     */
+    public String getCookieHeaderName() {
+	return getCookieHeaderName(version);
+    }
+
+    /** Return the header name to set the cookie, based on cookie
+     *  version
+     */
+    public static String getCookieHeaderName(int version) {
+	if( dbg>0 ) log( (version==1) ? "Set-Cookie2" : "Set-Cookie");
+        if (version == 1) {
+	    // RFC2109
+	    return "Set-Cookie";
+	    // XXX RFC2965 is not standard yet, and Set-Cookie2
+	    // is not supported by Netscape 4, 6, IE 3, 5 .
+	    // It is supported by Lynx, and there is hope 
+	    //	    return "Set-Cookie2";
+        } else {
+	    // Old Netscape
+	    return "Set-Cookie";
+        }
+    }
+
+    private static final String ancientDate=DateTool.formatOldCookie(new Date(10000));
+
+    public static void appendCookieValue( StringBuffer buf,
+					  int version,
+					  String name,
+					  String value,
+					  String path,
+					  String domain,
+					  String comment,
+					  int maxAge,
+					  boolean isSecure )
+    {
+        // this part is the same for all cookies
+	buf.append( name );
+        buf.append("=");
+        maybeQuote(version, buf, value);
+
+	// XXX Netscape cookie: "; "
+ 	// add version 1 specific information
+	if (version == 1) {
+	    // Version=1 ... required
+	    buf.append ("; Version=1");
+
+	    // Comment=comment
+	    if ( comment!=null ) {
+		buf.append ("; Comment=");
+		maybeQuote (version, buf, comment);
+	    }
+	}
+	
+	// add domain information, if present
+
+	if (domain!=null) {
+	    buf.append("; Domain=");
+	    maybeQuote (version, buf, domain);
+	}
+
+	// Max-Age=secs/Discard ... or use old "Expires" format
+	if (maxAge >= 0) {
+	    if (version == 0) {
+		// XXX XXX XXX We need to send both, for
+		// interoperatibility (long word )
+		buf.append ("; Expires=");
+		// Wdy, DD-Mon-YY HH:MM:SS GMT ( Expires netscape format )
+		// To expire we need to set the time back in future
+		// ( pfrieden at dChain.com )
+                if (maxAge == 0)
+		    buf.append( ancientDate );
+		else
+                    DateTool.formatOldCookie
+                        (new Date( System.currentTimeMillis() +
+                                   maxAge *1000L), buf,
+                         new FieldPosition(0));
+
+	    } else {
+		buf.append ("; Max-Age=");
+		buf.append (maxAge);
+	    }
+	}
+
+	// Path=path
+	if (path!=null) {
+	    buf.append ("; Path=");
+	    maybeQuote (version, buf, path);
+	}
+
+	// Secure
+	if (isSecure) {
+	  buf.append ("; Secure");
+	}
+	
+	
+    }
+
+    public static void maybeQuote (int version, StringBuffer buf,
+            String value) {
+        // special case - a \n or \r  shouldn't happen in any case
+        if (isToken(value)) {
+            buf.append(value);
+        } else {
+            buf.append('"');
+            buf.append(escapeDoubleQuotes(value));
+            buf.append('"');
+        }
+    }
+
+    // log
+    static final int dbg=1;
+    public static void log(String s ) {
+        if (log.isDebugEnabled())
+            log.debug("ServerCookie: " + s);
+    }
+
+
+    /**
+     * Escapes any double quotes in the given string.
+     *
+     * @param s the input string
+     *
+     * @return The (possibly) escaped string
+     */
+    private static String escapeDoubleQuotes(String s) {
+
+        if (s == null || s.length() == 0 || s.indexOf('"') == -1) {
+            return s;
+        }
+
+        StringBuffer b = new StringBuffer();
+        for (int i = 0; i < s.length(); i++) {
+            char c = s.charAt(i);
+            if (c == '"')
+                b.append('\\').append('"');
+            else
+                b.append(c);
+        }
+
+        return b.toString();
+    }
+
+}
+

Added: branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/http/mapper/Mapper.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/http/mapper/Mapper.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/http/mapper/Mapper.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,1396 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.mapper;
+
+import javax.naming.NamingException;
+import javax.naming.directory.DirContext;
+
+import org.apache.tomcat.util.buf.CharChunk;
+import org.apache.tomcat.util.buf.MessageBytes;
+import org.apache.tomcat.util.buf.Ascii;
+import java.util.List;
+import java.util.ArrayList;
+
+/**
+ * Mapper, which implements the servlet API mapping rules (which are derived
+ * from the HTTP rules).
+ *
+ * @author Remy Maucherat
+ */
+public final class Mapper {
+
+
+    private static org.apache.commons.logging.Log logger =
+        org.apache.commons.logging.LogFactory.getLog(Mapper.class);
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * Array containing the virtual hosts definitions.
+     */
+    protected Host[] hosts = new Host[0];
+
+
+    /**
+     * Default host name.
+     */
+    protected String defaultHostName = null;
+
+    /**
+     * Context associated with this wrapper, used for wrapper mapping.
+     */
+    protected Context context = new Context();
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Get default host.
+     *
+     * @return Default host name
+     */
+    public String getDefaultHostName() {
+        return defaultHostName;
+    }
+
+
+    /**
+     * Set default host.
+     *
+     * @param defaultHostName Default host name
+     */
+    public void setDefaultHostName(String defaultHostName) {
+        this.defaultHostName = defaultHostName;
+    }
+
+    /**
+     * Add a new host to the mapper.
+     *
+     * @param name Virtual host name
+     * @param host Host object
+     */
+    public synchronized void addHost(String name, String[] aliases,
+                                     Object host) {
+        Host[] newHosts = new Host[hosts.length + 1];
+        Host newHost = new Host();
+        ContextList contextList = new ContextList();
+        newHost.name = name;
+        newHost.contextList = contextList;
+        newHost.object = host;
+        if (insertMap(hosts, newHosts, newHost)) {
+            hosts = newHosts;
+        }
+        for (int i = 0; i < aliases.length; i++) {
+            newHosts = new Host[hosts.length + 1];
+            newHost = new Host();
+            newHost.name = aliases[i];
+            newHost.contextList = contextList;
+            newHost.object = host;
+            if (insertMap(hosts, newHosts, newHost)) {
+                hosts = newHosts;
+            }
+        }
+    }
+
+
+    /**
+     * Remove a host from the mapper.
+     *
+     * @param name Virtual host name
+     */
+    public synchronized void removeHost(String name) {
+        // Find and remove the old host
+        int pos = find(hosts, name);
+        if (pos < 0) {
+            return;
+        }
+        Object host = hosts[pos].object;
+        Host[] newHosts = new Host[hosts.length - 1];
+        if (removeMap(hosts, newHosts, name)) {
+            hosts = newHosts;
+        }
+        // Remove all aliases (they will map to the same host object)
+        for (int i = 0; i < newHosts.length; i++) {
+            if (newHosts[i].object == host) {
+                Host[] newHosts2 = new Host[hosts.length - 1];
+                if (removeMap(hosts, newHosts2, newHosts[i].name)) {
+                    hosts = newHosts2;
+                }
+            }
+        }
+    }
+
+    public String[] getHosts() {
+        String hostN[] = new String[hosts.length];
+        for( int i = 0; i < hosts.length; i++ ) {
+            hostN[i] = hosts[i].name;
+        }
+        return hostN;
+    }
+
+
+    /**
+     * Set context, used for wrapper mapping (request dispatcher).
+     *
+     * @param welcomeResources Welcome files defined for this context
+     * @param resources Static resources of the context
+     */
+    public void setContext(String path, String[] welcomeResources,
+                           javax.naming.Context resources) {
+        context.name = path;
+        context.welcomeResources = welcomeResources;
+        context.resources = resources;
+    }
+
+
+    /**
+     * Add a new Context to an existing Host.
+     *
+     * @param hostName Virtual host name this context belongs to
+     * @param path Context path
+     * @param context Context object
+     * @param welcomeResources Welcome files defined for this context
+     * @param resources Static resources of the context
+     */
+    public void addContext
+        (String hostName, String path, Object context,
+         String[] welcomeResources, javax.naming.Context resources) {
+
+        Host[] hosts = this.hosts;
+        int pos = find(hosts, hostName);
+        if( pos <0 ) {
+            addHost(hostName, new String[0], "");
+            hosts = this.hosts;
+            pos = find(hosts, hostName);
+        }
+        if (pos < 0) {
+            logger.error("No host found: " + hostName);
+        }
+        Host host = hosts[pos];
+        if (host.name.equals(hostName)) {
+            int slashCount = slashCount(path);
+            synchronized (host) {
+                Context[] contexts = host.contextList.contexts;
+                // Update nesting
+                if (slashCount > host.contextList.nesting) {
+                    host.contextList.nesting = slashCount;
+                }
+                Context[] newContexts = new Context[contexts.length + 1];
+                Context newContext = new Context();
+                newContext.name = path;
+                newContext.object = context;
+                newContext.welcomeResources = welcomeResources;
+                newContext.resources = resources;
+                if (insertMap(contexts, newContexts, newContext)) {
+                    host.contextList.contexts = newContexts;
+                }
+            }
+        }
+
+    }
+
+
+    /**
+     * Remove a context from an existing host.
+     *
+     * @param hostName Virtual host name this context belongs to
+     * @param path Context path
+     */
+    public void removeContext(String hostName, String path) {
+        Host[] hosts = this.hosts;
+        int pos = find(hosts, hostName);
+        if (pos < 0) {
+            return;
+        }
+        Host host = hosts[pos];
+        if (host.name.equals(hostName)) {
+            synchronized (host) {
+                Context[] contexts = host.contextList.contexts;
+                if( contexts.length == 0 ){
+                    return;
+                }
+                Context[] newContexts = new Context[contexts.length - 1];
+                if (removeMap(contexts, newContexts, path)) {
+                    host.contextList.contexts = newContexts;
+                    // Recalculate nesting
+                    host.contextList.nesting = 0;
+                    for (int i = 0; i < newContexts.length; i++) {
+                        int slashCount = slashCount(newContexts[i].name);
+                        if (slashCount > host.contextList.nesting) {
+                            host.contextList.nesting = slashCount;
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+
+    /**
+     * Return all contexts, in //HOST/PATH form
+     *
+     * @return The context names
+     */
+    public String[] getContextNames() {
+        List list=new ArrayList();
+        for( int i=0; i<hosts.length; i++ ) {
+            for( int j=0; j<hosts[i].contextList.contexts.length; j++ ) {
+                String cname=hosts[i].contextList.contexts[j].name;
+                list.add("//" + hosts[i].name +
+                        (cname.startsWith("/") ? cname : "/"));
+            }
+        }
+        String res[] = new String[list.size()];
+        return (String[])list.toArray(res);
+    }
+
+
+    /**
+     * Add a new Wrapper to an existing Context.
+     *
+     * @param hostName Virtual host name this wrapper belongs to
+     * @param contextPath Context path this wrapper belongs to
+     * @param path Wrapper mapping
+     * @param wrapper Wrapper object
+     */
+    public void addWrapper(String hostName, String contextPath, String path,
+                           Object wrapper) {
+        addWrapper(hostName, contextPath, path, wrapper, false);
+    }
+
+
+    public void addWrapper(String hostName, String contextPath, String path,
+                           Object wrapper, boolean jspWildCard) {
+        Host[] hosts = this.hosts;
+        int pos = find(hosts, hostName);
+        if (pos < 0) {
+            return;
+        }
+        Host host = hosts[pos];
+        if (host.name.equals(hostName)) {
+            Context[] contexts = host.contextList.contexts;
+            int pos2 = find(contexts, contextPath);
+            if( pos2<0 ) {
+                logger.error("No context found: " + contextPath );
+                return;
+            }
+            Context context = contexts[pos2];
+            if (context.name.equals(contextPath)) {
+                addWrapper(context, path, wrapper, jspWildCard);
+            }
+        }
+    }
+
+
+    /**
+     * Add a wrapper to the context associated with this wrapper.
+     *
+     * @param path Wrapper mapping
+     * @param wrapper The Wrapper object
+     */
+    public void addWrapper(String path, Object wrapper) {
+        addWrapper(context, path, wrapper);
+    }
+
+
+    public void addWrapper(String path, Object wrapper, boolean jspWildCard) {
+        addWrapper(context, path, wrapper, jspWildCard);
+    }
+
+
+    protected void addWrapper(Context context, String path, Object wrapper) {
+        addWrapper(context, path, wrapper, false);
+    }
+
+
+    /**
+     * Adds a wrapper to the given context.
+     *
+     * @param context The context to which to add the wrapper
+     * @param path Wrapper mapping
+     * @param wrapper The Wrapper object
+     * @param jspWildCard true if the wrapper corresponds to the JspServlet
+     * and the mapping path contains a wildcard; false otherwise
+     */
+    protected void addWrapper(Context context, String path, Object wrapper,
+                              boolean jspWildCard) {
+
+        synchronized (context) {
+            Wrapper newWrapper = new Wrapper();
+            newWrapper.object = wrapper;
+            newWrapper.jspWildCard = jspWildCard;
+            if (path.endsWith("/*")) {
+                // Wildcard wrapper
+                newWrapper.name = path.substring(0, path.length() - 2);
+                Wrapper[] oldWrappers = context.wildcardWrappers;
+                Wrapper[] newWrappers =
+                    new Wrapper[oldWrappers.length + 1];
+                if (insertMap(oldWrappers, newWrappers, newWrapper)) {
+                    context.wildcardWrappers = newWrappers;
+                    int slashCount = slashCount(newWrapper.name);
+                    if (slashCount > context.nesting) {
+                        context.nesting = slashCount;
+                    }
+                }
+            } else if (path.startsWith("*.")) {
+                // Extension wrapper
+                newWrapper.name = path.substring(2);
+                Wrapper[] oldWrappers = context.extensionWrappers;
+                Wrapper[] newWrappers =
+                    new Wrapper[oldWrappers.length + 1];
+                if (insertMap(oldWrappers, newWrappers, newWrapper)) {
+                    context.extensionWrappers = newWrappers;
+                }
+            } else if (path.equals("/")) {
+                // Default wrapper
+                newWrapper.name = "";
+                context.defaultWrapper = newWrapper;
+            } else {
+                // Exact wrapper
+                newWrapper.name = path;
+                Wrapper[] oldWrappers = context.exactWrappers;
+                Wrapper[] newWrappers =
+                    new Wrapper[oldWrappers.length + 1];
+                if (insertMap(oldWrappers, newWrappers, newWrapper)) {
+                    context.exactWrappers = newWrappers;
+                }
+            }
+        }
+    }
+
+
+    /**
+     * Remove a wrapper from the context associated with this wrapper.
+     *
+     * @param path Wrapper mapping
+     */
+    public void removeWrapper(String path) {
+        removeWrapper(context, path);
+    }
+
+
+    /**
+     * Remove a wrapper from an existing context.
+     *
+     * @param hostName Virtual host name this wrapper belongs to
+     * @param contextPath Context path this wrapper belongs to
+     * @param path Wrapper mapping
+     */
+    public void removeWrapper
+        (String hostName, String contextPath, String path) {
+        Host[] hosts = this.hosts;
+        int pos = find(hosts, hostName);
+        if (pos < 0) {
+            return;
+        }
+        Host host = hosts[pos];
+        if (host.name.equals(hostName)) {
+            Context[] contexts = host.contextList.contexts;
+            int pos2 = find(contexts, contextPath);
+            if (pos2 < 0) {
+                return;
+            }
+            Context context = contexts[pos2];
+            if (context.name.equals(contextPath)) {
+                removeWrapper(context, path);
+            }
+        }
+    }
+
+    protected void removeWrapper(Context context, String path) {
+        synchronized (context) {
+            if (path.endsWith("/*")) {
+                // Wildcard wrapper
+                String name = path.substring(0, path.length() - 2);
+                Wrapper[] oldWrappers = context.wildcardWrappers;
+                Wrapper[] newWrappers =
+                    new Wrapper[oldWrappers.length - 1];
+                if (removeMap(oldWrappers, newWrappers, name)) {
+                    // Recalculate nesting
+                    context.nesting = 0;
+                    for (int i = 0; i < newWrappers.length; i++) {
+                        int slashCount = slashCount(newWrappers[i].name);
+                        if (slashCount > context.nesting) {
+                            context.nesting = slashCount;
+                        }
+                    }
+                    context.wildcardWrappers = newWrappers;
+                }
+            } else if (path.startsWith("*.")) {
+                // Extension wrapper
+                String name = path.substring(2);
+                Wrapper[] oldWrappers = context.extensionWrappers;
+                Wrapper[] newWrappers =
+                    new Wrapper[oldWrappers.length - 1];
+                if (removeMap(oldWrappers, newWrappers, name)) {
+                    context.extensionWrappers = newWrappers;
+                }
+            } else if (path.equals("/")) {
+                // Default wrapper
+                context.defaultWrapper = null;
+            } else {
+                // Exact wrapper
+                String name = path;
+                Wrapper[] oldWrappers = context.exactWrappers;
+                Wrapper[] newWrappers =
+                    new Wrapper[oldWrappers.length - 1];
+                if (removeMap(oldWrappers, newWrappers, name)) {
+                    context.exactWrappers = newWrappers;
+                }
+            }
+        }
+    }
+
+    public String getWrappersString( String host, String context ) {
+        String names[]=getWrapperNames(host, context);
+        StringBuffer sb=new StringBuffer();
+        for( int i=0; i<names.length; i++ ) {
+            sb.append(names[i]).append(":");
+        }
+        return sb.toString();
+    }
+
+    public String[] getWrapperNames( String host, String context ) {
+        List list=new ArrayList();
+        if( host==null ) host="";
+        if( context==null ) context="";
+        for( int i=0; i<hosts.length; i++ ) {
+            if( ! host.equals( hosts[i].name ))
+                continue;
+            for( int j=0; j<hosts[i].contextList.contexts.length; j++ ) {
+                if( ! context.equals( hosts[i].contextList.contexts[j].name))
+                    continue;
+                // found the context
+                Context ctx=hosts[i].contextList.contexts[j];
+                list.add( ctx.defaultWrapper.path);
+                for( int k=0; k<ctx.exactWrappers.length; k++ ) {
+                    list.add( ctx.exactWrappers[k].path);
+                }
+                for( int k=0; k<ctx.wildcardWrappers.length; k++ ) {
+                    list.add( ctx.wildcardWrappers[k].path + "*");
+                }
+                for( int k=0; k<ctx.extensionWrappers.length; k++ ) {
+                    list.add( "*." + ctx.extensionWrappers[k].path);
+                }
+            }
+        }
+        String res[]=new String[list.size()];
+        return (String[])list.toArray(res);
+    }
+
+
+
+    /**
+     * Map the specified host name and URI, mutating the given mapping data.
+     *
+     * @param host Virtual host name
+     * @param uri URI
+     * @param mappingData This structure will contain the result of the mapping
+     *                    operation
+     */
+    public void map(MessageBytes host, MessageBytes uri,
+                    MappingData mappingData)
+        throws Exception {
+
+        if (host.isNull()) {
+            host.getCharChunk().append(defaultHostName);
+        }
+        host.toChars();
+        uri.toChars();
+        internalMap(host.getCharChunk(), uri.getCharChunk(), mappingData);
+
+    }
+
+
+    /**
+     * Map the specified URI relative to the context,
+     * mutating the given mapping data.
+     *
+     * @param uri URI
+     * @param mappingData This structure will contain the result of the mapping
+     *                    operation
+     */
+    public void map(MessageBytes uri, MappingData mappingData)
+        throws Exception {
+
+        uri.toChars();
+        CharChunk uricc = uri.getCharChunk();
+        uricc.setLimit(-1);
+        internalMapWrapper(context, uricc, mappingData);
+
+    }
+
+
+    // -------------------------------------------------------- Private Methods
+
+
+    /**
+     * Map the specified URI.
+     */
+    private final void internalMap(CharChunk host, CharChunk uri,
+                                   MappingData mappingData)
+        throws Exception {
+
+        uri.setLimit(-1);
+
+        Context[] contexts = null;
+        Context context = null;
+        int nesting = 0;
+
+        // Virtual host mapping
+        if (mappingData.host == null) {
+            Host[] hosts = this.hosts;
+            int pos = findIgnoreCase(hosts, host);
+            if ((pos != -1) && (host.equalsIgnoreCase(hosts[pos].name))) {
+                mappingData.host = hosts[pos].object;
+                contexts = hosts[pos].contextList.contexts;
+                nesting = hosts[pos].contextList.nesting;
+            } else {
+                if (defaultHostName == null) {
+                    return;
+                }
+                pos = find(hosts, defaultHostName);
+                if ((pos != -1) && (defaultHostName.equals(hosts[pos].name))) {
+                    mappingData.host = hosts[pos].object;
+                    contexts = hosts[pos].contextList.contexts;
+                    nesting = hosts[pos].contextList.nesting;
+                } else {
+                    return;
+                }
+            }
+        }
+
+        // Context mapping
+        if (mappingData.context == null) {
+            int pos = find(contexts, uri);
+            if (pos == -1) {
+                return;
+            }
+
+            int lastSlash = -1;
+            int uriEnd = uri.getEnd();
+            int length = -1;
+            boolean found = false;
+            while (pos >= 0) {
+                if (uri.startsWith(contexts[pos].name)) {
+                    length = contexts[pos].name.length();
+                    if (uri.getLength() == length) {
+                        found = true;
+                        break;
+                    } else if (uri.startsWithIgnoreCase("/", length)) {
+                        found = true;
+                        break;
+                    }
+                }
+                if (lastSlash == -1) {
+                    lastSlash = nthSlash(uri, nesting + 1);
+                } else {
+                    lastSlash = lastSlash(uri);
+                }
+                uri.setEnd(lastSlash);
+                pos = find(contexts, uri);
+            }
+            uri.setEnd(uriEnd);
+
+            if (!found) {
+                if (contexts[0].name.equals("")) {
+                    context = contexts[0];
+                }
+            } else {
+                context = contexts[pos];
+            }
+            if (context != null) {
+                mappingData.context = context.object;
+                mappingData.contextPath.setString(context.name);
+            }
+        }
+
+        // Wrapper mapping
+        if ((context != null) && (mappingData.wrapper == null)) {
+            internalMapWrapper(context, uri, mappingData);
+        }
+
+    }
+
+
+    /**
+     * Wrapper mapping.
+     */
+    private final void internalMapWrapper(Context context, CharChunk path,
+                                          MappingData mappingData)
+        throws Exception {
+
+        int pathOffset = path.getOffset();
+        int pathEnd = path.getEnd();
+        int servletPath = pathOffset;
+        boolean noServletPath = false;
+
+        int length = context.name.length();
+        if (length != (pathEnd - pathOffset)) {
+            servletPath = pathOffset + length;
+        } else {
+            noServletPath = true;
+            path.append('/');
+            pathOffset = path.getOffset();
+            pathEnd = path.getEnd();
+            servletPath = pathOffset+length;
+        }
+
+        path.setOffset(servletPath);
+
+        // Rule 1 -- Exact Match
+        Wrapper[] exactWrappers = context.exactWrappers;
+        internalMapExactWrapper(exactWrappers, path, mappingData);
+
+        // Rule 2 -- Prefix Match
+        boolean checkJspWelcomeFiles = false;
+        Wrapper[] wildcardWrappers = context.wildcardWrappers;
+        if (mappingData.wrapper == null) {
+            internalMapWildcardWrapper(wildcardWrappers, context.nesting, 
+                                       path, mappingData);
+            if (mappingData.wrapper != null && mappingData.jspWildCard) {
+                char[] buf = path.getBuffer();
+                if (buf[pathEnd - 1] == '/') {
+                    /*
+                     * Path ending in '/' was mapped to JSP servlet based on
+                     * wildcard match (e.g., as specified in url-pattern of a
+                     * jsp-property-group.
+                     * Force the context's welcome files, which are interpreted
+                     * as JSP files (since they match the url-pattern), to be
+                     * considered. See Bugzilla 27664.
+                     */ 
+                    mappingData.wrapper = null;
+                    checkJspWelcomeFiles = true;
+                } else {
+                    // See Bugzilla 27704
+                    mappingData.wrapperPath.setChars(buf, path.getStart(),
+                                                     path.getLength());
+                    mappingData.pathInfo.recycle();
+                }
+            }
+        }
+
+        if(mappingData.wrapper == null && noServletPath) {
+            // The path is empty, redirect to "/"
+            mappingData.redirectPath.setChars
+                (path.getBuffer(), pathOffset, pathEnd);
+            path.setEnd(pathEnd - 1);
+            return;
+        }
+
+        // Rule 3 -- Extension Match
+        Wrapper[] extensionWrappers = context.extensionWrappers;
+        if (mappingData.wrapper == null && !checkJspWelcomeFiles) {
+            internalMapExtensionWrapper(extensionWrappers, path, mappingData);
+        }
+
+        // Rule 4 -- Welcome resources processing for servlets
+        if (mappingData.wrapper == null) {
+            boolean checkWelcomeFiles = checkJspWelcomeFiles;
+            if (!checkWelcomeFiles) {
+                char[] buf = path.getBuffer();
+                checkWelcomeFiles = (buf[pathEnd - 1] == '/');
+            }
+            if (checkWelcomeFiles) {
+                for (int i = 0; (i < context.welcomeResources.length)
+                         && (mappingData.wrapper == null); i++) {
+                    path.setOffset(pathOffset);
+                    path.setEnd(pathEnd);
+                    path.append(context.welcomeResources[i], 0,
+                                context.welcomeResources[i].length());
+                    path.setOffset(servletPath);
+
+                    // Rule 4a -- Welcome resources processing for exact macth
+                    internalMapExactWrapper(exactWrappers, path, mappingData);
+
+                    // Rule 4b -- Welcome resources processing for prefix match
+                    if (mappingData.wrapper == null) {
+                        internalMapWildcardWrapper
+                            (wildcardWrappers, context.nesting, 
+                             path, mappingData);
+                    }
+
+                    // Rule 4c -- Welcome resources processing
+                    //            for physical folder
+                    if (mappingData.wrapper == null
+                        && context.resources != null) {
+                        Object file = null;
+                        String pathStr = path.toString();
+                        try {
+                            file = context.resources.lookup(pathStr);
+                        } catch(NamingException nex) {
+                            // Swallow not found, since this is normal
+                        }
+                        if (file != null && !(file instanceof DirContext) ) {
+                            internalMapExtensionWrapper(extensionWrappers,
+                                                        path, mappingData);
+                            if (mappingData.wrapper == null
+                                && context.defaultWrapper != null) {
+                                mappingData.wrapper =
+                                    context.defaultWrapper.object;
+                                mappingData.requestPath.setChars
+                                    (path.getBuffer(), path.getStart(), 
+                                     path.getLength());
+                                mappingData.wrapperPath.setChars
+                                    (path.getBuffer(), path.getStart(), 
+                                     path.getLength());
+                                mappingData.requestPath.setString(pathStr);
+                                mappingData.wrapperPath.setString(pathStr);
+                            }
+                        }
+                    }
+                }
+
+                path.setOffset(servletPath);
+                path.setEnd(pathEnd);
+            }
+                                        
+        }
+
+
+        // Rule 7 -- Default servlet
+        if (mappingData.wrapper == null && !checkJspWelcomeFiles) {
+            if (context.defaultWrapper != null) {
+                mappingData.wrapper = context.defaultWrapper.object;
+                mappingData.requestPath.setChars
+                    (path.getBuffer(), path.getStart(), path.getLength());
+                mappingData.wrapperPath.setChars
+                    (path.getBuffer(), path.getStart(), path.getLength());
+            }
+            // Redirection to a folder
+            char[] buf = path.getBuffer();
+            if (context.resources != null && buf[pathEnd -1 ] != '/') {
+                Object file = null;
+                String pathStr = path.toString();
+                try {
+                    file = context.resources.lookup(pathStr);
+                } catch(NamingException nex) {
+                    // Swallow, since someone else handles the 404
+                }
+                if (file != null && file instanceof DirContext) {
+                    // Note: this mutates the path: do not do any processing 
+                    // after this (since we set the redirectPath, there 
+                    // shouldn't be any)
+                    path.setOffset(pathOffset);
+                    path.append('/');
+                    mappingData.redirectPath.setChars
+                        (path.getBuffer(), path.getStart(), path.getLength());
+                } else {
+                    mappingData.requestPath.setString(pathStr);
+                    mappingData.wrapperPath.setString(pathStr);
+                }
+            }
+        }
+
+        path.setOffset(pathOffset);
+        path.setEnd(pathEnd);
+
+    }
+
+
+    /**
+     * Exact mapping.
+     */
+    private final void internalMapExactWrapper
+        (Wrapper[] wrappers, CharChunk path, MappingData mappingData) {
+        int pos = find(wrappers, path);
+        if ((pos != -1) && (path.equals(wrappers[pos].name))) {
+            mappingData.requestPath.setString(wrappers[pos].name);
+            mappingData.wrapperPath.setString(wrappers[pos].name);
+            mappingData.wrapper = wrappers[pos].object;
+        }
+    }
+
+
+    /**
+     * Wildcard mapping.
+     */
+    private final void internalMapWildcardWrapper
+        (Wrapper[] wrappers, int nesting, CharChunk path, 
+         MappingData mappingData) {
+
+        int pathEnd = path.getEnd();
+        int pathOffset = path.getOffset();
+
+        int lastSlash = -1;
+        int length = -1;
+        int pos = find(wrappers, path);
+        if (pos != -1) {
+            boolean found = false;
+            while (pos >= 0) {
+                if (path.startsWith(wrappers[pos].name)) {
+                    length = wrappers[pos].name.length();
+                    if (path.getLength() == length) {
+                        found = true;
+                        break;
+                    } else if (path.startsWithIgnoreCase("/", length)) {
+                        found = true;
+                        break;
+                    }
+                }
+                if (lastSlash == -1) {
+                    lastSlash = nthSlash(path, nesting + 1);
+                } else {
+                    lastSlash = lastSlash(path);
+                }
+                path.setEnd(lastSlash);
+                pos = find(wrappers, path);
+            }
+            path.setEnd(pathEnd);
+            if (found) {
+                mappingData.wrapperPath.setString(wrappers[pos].name);
+                if (path.getLength() > length) {
+                    mappingData.pathInfo.setChars
+                        (path.getBuffer(),
+                         path.getOffset() + length,
+                         path.getLength() - length);
+                }
+                mappingData.requestPath.setChars
+                    (path.getBuffer(), path.getOffset(), path.getLength());
+                mappingData.wrapper = wrappers[pos].object;
+                mappingData.jspWildCard = wrappers[pos].jspWildCard;
+            }
+        }
+    }
+
+
+    /**
+     * Extension mappings.
+     */
+    private final void internalMapExtensionWrapper
+        (Wrapper[] wrappers, CharChunk path, MappingData mappingData) {
+        char[] buf = path.getBuffer();
+        int pathEnd = path.getEnd();
+        int servletPath = path.getOffset();
+        int slash = -1;
+        for (int i = pathEnd - 1; i >= servletPath; i--) {
+            if (buf[i] == '/') {
+                slash = i;
+                break;
+            }
+        }
+        if (slash >= 0) {
+            int period = -1;
+            for (int i = pathEnd - 1; i > slash; i--) {
+                if (buf[i] == '.') {
+                    period = i;
+                    break;
+                }
+            }
+            if (period >= 0) {
+                path.setOffset(period + 1);
+                path.setEnd(pathEnd);
+                int pos = find(wrappers, path);
+                if ((pos != -1)
+                    && (path.equals(wrappers[pos].name))) {
+                    mappingData.wrapperPath.setChars
+                        (buf, servletPath, pathEnd - servletPath);
+                    mappingData.requestPath.setChars
+                        (buf, servletPath, pathEnd - servletPath);
+                    mappingData.wrapper = wrappers[pos].object;
+                }
+                path.setOffset(servletPath);
+                path.setEnd(pathEnd);
+            }
+        }
+    }
+
+
+    /**
+     * Find a map elemnt given its name in a sorted array of map elements.
+     * This will return the index for the closest inferior or equal item in the
+     * given array.
+     */
+    private static final int find(MapElement[] map, CharChunk name) {
+        return find(map, name, name.getStart(), name.getEnd());
+    }
+
+
+    /**
+     * Find a map elemnt given its name in a sorted array of map elements.
+     * This will return the index for the closest inferior or equal item in the
+     * given array.
+     */
+    private static final int find(MapElement[] map, CharChunk name,
+                                  int start, int end) {
+
+        int a = 0;
+        int b = map.length - 1;
+
+        // Special cases: -1 and 0
+        if (b == -1) {
+            return -1;
+        }
+        
+        if (compare(name, start, end, map[0].name) < 0 ) {
+            return -1;
+        }         
+        if (b == 0) {
+            return 0;
+        }
+
+        int i = 0;
+        while (true) {
+            i = (b + a) / 2;
+            int result = compare(name, start, end, map[i].name);
+            if (result == 1) {
+                a = i;
+            } else if (result == 0) {
+                return i;
+            } else {
+                b = i;
+            }
+            if ((b - a) == 1) {
+                int result2 = compare(name, start, end, map[b].name);
+                if (result2 < 0) {
+                    return a;
+                } else {
+                    return b;
+                }
+            }
+        }
+
+    }
+
+    /**
+     * Find a map elemnt given its name in a sorted array of map elements.
+     * This will return the index for the closest inferior or equal item in the
+     * given array.
+     */
+    private static final int findIgnoreCase(MapElement[] map, CharChunk name) {
+        return findIgnoreCase(map, name, name.getStart(), name.getEnd());
+    }
+
+
+    /**
+     * Find a map elemnt given its name in a sorted array of map elements.
+     * This will return the index for the closest inferior or equal item in the
+     * given array.
+     */
+    private static final int findIgnoreCase(MapElement[] map, CharChunk name,
+                                  int start, int end) {
+
+        int a = 0;
+        int b = map.length - 1;
+
+        // Special cases: -1 and 0
+        if (b == -1) {
+            return -1;
+        }
+        if (compareIgnoreCase(name, start, end, map[0].name) < 0 ) {
+            return -1;
+        }         
+        if (b == 0) {
+            return 0;
+        }
+
+        int i = 0;
+        while (true) {
+            i = (b + a) / 2;
+            int result = compareIgnoreCase(name, start, end, map[i].name);
+            if (result == 1) {
+                a = i;
+            } else if (result == 0) {
+                return i;
+            } else {
+                b = i;
+            }
+            if ((b - a) == 1) {
+                int result2 = compareIgnoreCase(name, start, end, map[b].name);
+                if (result2 < 0) {
+                    return a;
+                } else {
+                    return b;
+                }
+            }
+        }
+
+    }
+
+
+    /**
+     * Find a map elemnt given its name in a sorted array of map elements.
+     * This will return the index for the closest inferior or equal item in the
+     * given array.
+     */
+    private static final int find(MapElement[] map, String name) {
+
+        int a = 0;
+        int b = map.length - 1;
+
+        // Special cases: -1 and 0
+        if (b == -1) {
+            return -1;
+        }
+        
+        if (name.compareTo(map[0].name) < 0) {
+            return -1;
+        } 
+        if (b == 0) {
+            return 0;
+        }
+
+        int i = 0;
+        while (true) {
+            i = (b + a) / 2;
+            int result = name.compareTo(map[i].name);
+            if (result > 0) {
+                a = i;
+            } else if (result == 0) {
+                return i;
+            } else {
+                b = i;
+            }
+            if ((b - a) == 1) {
+                int result2 = name.compareTo(map[b].name);
+                if (result2 < 0) {
+                    return a;
+                } else {
+                    return b;
+                }
+            }
+        }
+
+    }
+
+
+    /**
+     * Compare given char chunk with String.
+     * Return -1, 0 or +1 if inferior, equal, or superior to the String.
+     */
+    private static final int compare(CharChunk name, int start, int end,
+                                     String compareTo) {
+        int result = 0;
+        char[] c = name.getBuffer();
+        int len = compareTo.length();
+        if ((end - start) < len) {
+            len = end - start;
+        }
+        for (int i = 0; (i < len) && (result == 0); i++) {
+            if (c[i + start] > compareTo.charAt(i)) {
+                result = 1;
+            } else if (c[i + start] < compareTo.charAt(i)) {
+                result = -1;
+            }
+        }
+        if (result == 0) {
+            if (compareTo.length() > (end - start)) {
+                result = -1;
+            } else if (compareTo.length() < (end - start)) {
+                result = 1;
+            }
+        }
+        return result;
+    }
+
+
+    /**
+     * Compare given char chunk with String ignoring case.
+     * Return -1, 0 or +1 if inferior, equal, or superior to the String.
+     */
+    private static final int compareIgnoreCase(CharChunk name, int start, int end,
+                                     String compareTo) {
+        int result = 0;
+        char[] c = name.getBuffer();
+        int len = compareTo.length();
+        if ((end - start) < len) {
+            len = end - start;
+        }
+        for (int i = 0; (i < len) && (result == 0); i++) {
+            if (Ascii.toLower(c[i + start]) > Ascii.toLower(compareTo.charAt(i))) {
+                result = 1;
+            } else if (Ascii.toLower(c[i + start]) < Ascii.toLower(compareTo.charAt(i))) {
+                result = -1;
+            }
+        }
+        if (result == 0) {
+            if (compareTo.length() > (end - start)) {
+                result = -1;
+            } else if (compareTo.length() < (end - start)) {
+                result = 1;
+            }
+        }
+        return result;
+    }
+
+
+    /**
+     * Find the position of the last slash in the given char chunk.
+     */
+    private static final int lastSlash(CharChunk name) {
+
+        char[] c = name.getBuffer();
+        int end = name.getEnd();
+        int start = name.getStart();
+        int pos = end;
+
+        while (pos > start) {
+            if (c[--pos] == '/') {
+                break;
+            }
+        }
+
+        return (pos);
+
+    }
+
+
+    /**
+     * Find the position of the nth slash, in the given char chunk.
+     */
+    private static final int nthSlash(CharChunk name, int n) {
+
+        char[] c = name.getBuffer();
+        int end = name.getEnd();
+        int start = name.getStart();
+        int pos = start;
+        int count = 0;
+
+        while (pos < end) {
+            if ((c[pos++] == '/') && ((++count) == n)) {
+                pos--;
+                break;
+            }
+        }
+
+        return (pos);
+
+    }
+
+
+    /**
+     * Return the slash count in a given string.
+     */
+    private static final int slashCount(String name) {
+        int pos = -1;
+        int count = 0;
+        while ((pos = name.indexOf('/', pos + 1)) != -1) {
+            count++;
+        }
+        return count;
+    }
+
+
+    /**
+     * Insert into the right place in a sorted MapElement array, and prevent
+     * duplicates.
+     */
+    private static final boolean insertMap
+        (MapElement[] oldMap, MapElement[] newMap, MapElement newElement) {
+        int pos = find(oldMap, newElement.name);
+        if ((pos != -1) && (newElement.name.equals(oldMap[pos].name))) {
+            return false;
+        }
+        System.arraycopy(oldMap, 0, newMap, 0, pos + 1);
+        newMap[pos + 1] = newElement;
+        System.arraycopy
+            (oldMap, pos + 1, newMap, pos + 2, oldMap.length - pos - 1);
+        return true;
+    }
+
+
+    /**
+     * Insert into the right place in a sorted MapElement array.
+     */
+    private static final boolean removeMap
+        (MapElement[] oldMap, MapElement[] newMap, String name) {
+        int pos = find(oldMap, name);
+        if ((pos != -1) && (name.equals(oldMap[pos].name))) {
+            System.arraycopy(oldMap, 0, newMap, 0, pos);
+            System.arraycopy(oldMap, pos + 1, newMap, pos,
+                             oldMap.length - pos - 1);
+            return true;
+        }
+        return false;
+    }
+
+
+    // ------------------------------------------------- MapElement Inner Class
+
+
+    protected static abstract class MapElement {
+
+        public String name = null;
+        public Object object = null;
+
+    }
+
+
+    // ------------------------------------------------------- Host Inner Class
+
+
+    protected static final class Host
+        extends MapElement {
+
+        public ContextList contextList = null;
+
+    }
+
+
+    // ------------------------------------------------ ContextList Inner Class
+
+
+    protected static final class ContextList {
+
+        public Context[] contexts = new Context[0];
+        public int nesting = 0;
+
+    }
+
+
+    // ---------------------------------------------------- Context Inner Class
+
+
+    protected static final class Context
+        extends MapElement {
+
+        public String path = null;
+        public String[] welcomeResources = new String[0];
+        public javax.naming.Context resources = null;
+        public Wrapper defaultWrapper = null;
+        public Wrapper[] exactWrappers = new Wrapper[0];
+        public Wrapper[] wildcardWrappers = new Wrapper[0];
+        public Wrapper[] extensionWrappers = new Wrapper[0];
+        public int nesting = 0;
+
+    }
+
+
+    // ---------------------------------------------------- Wrapper Inner Class
+
+
+    protected static class Wrapper
+        extends MapElement {
+
+        public String path = null;
+        public boolean jspWildCard = false;
+    }
+
+
+    // -------------------------------------------------------- Testing Methods
+
+    // FIXME: Externalize this
+    /*
+    public static void main(String args[]) {
+
+        try {
+
+        Mapper mapper = new Mapper();
+        System.out.println("Start");
+
+        mapper.addHost("sjbjdvwsbvhrb", new String[0], "blah1");
+        mapper.addHost("sjbjdvwsbvhr/", new String[0], "blah1");
+        mapper.addHost("wekhfewuifweuibf", new String[0], "blah2");
+        mapper.addHost("ylwrehirkuewh", new String[0], "blah3");
+        mapper.addHost("iohgeoihro", new String[0], "blah4");
+        mapper.addHost("fwehoihoihwfeo", new String[0], "blah5");
+        mapper.addHost("owefojiwefoi", new String[0], "blah6");
+        mapper.addHost("iowejoiejfoiew", new String[0], "blah7");
+        mapper.addHost("iowejoiejfoiew", new String[0], "blah17");
+        mapper.addHost("ohewoihfewoih", new String[0], "blah8");
+        mapper.addHost("fewohfoweoih", new String[0], "blah9");
+        mapper.addHost("ttthtiuhwoih", new String[0], "blah10");
+        mapper.addHost("lkwefjwojweffewoih", new String[0], "blah11");
+        mapper.addHost("zzzuyopjvewpovewjhfewoih", new String[0], "blah12");
+        mapper.addHost("xxxxgqwiwoih", new String[0], "blah13");
+        mapper.addHost("qwigqwiwoih", new String[0], "blah14");
+
+        System.out.println("Map:");
+        for (int i = 0; i < mapper.hosts.length; i++) {
+            System.out.println(mapper.hosts[i].name);
+        }
+
+        mapper.setDefaultHostName("ylwrehirkuewh");
+
+        String[] welcomes = new String[2];
+        welcomes[0] = "boo/baba";
+        welcomes[1] = "bobou";
+
+        mapper.addContext("iowejoiejfoiew", "", "context0", new String[0], null);
+        mapper.addContext("iowejoiejfoiew", "/foo", "context1", new String[0], null);
+        mapper.addContext("iowejoiejfoiew", "/foo/bar", "context2", welcomes, null);
+        mapper.addContext("iowejoiejfoiew", "/foo/bar/bla", "context3", new String[0], null);
+
+        mapper.addWrapper("iowejoiejfoiew", "/foo/bar", "/fo/*", "wrapper0");
+        mapper.addWrapper("iowejoiejfoiew", "/foo/bar", "/", "wrapper1");
+        mapper.addWrapper("iowejoiejfoiew", "/foo/bar", "/blh", "wrapper2");
+        mapper.addWrapper("iowejoiejfoiew", "/foo/bar", "*.jsp", "wrapper3");
+        mapper.addWrapper("iowejoiejfoiew", "/foo/bar", "/blah/bou/*", "wrapper4");
+        mapper.addWrapper("iowejoiejfoiew", "/foo/bar", "/blah/bobou/*", "wrapper5");
+        mapper.addWrapper("iowejoiejfoiew", "/foo/bar", "*.htm", "wrapper6");
+
+        MappingData mappingData = new MappingData();
+        MessageBytes host = MessageBytes.newInstance();
+        host.setString("iowejoiejfoiew");
+        MessageBytes uri = MessageBytes.newInstance();
+        uri.setString("/foo/bar/blah/bobou/foo");
+        uri.toChars();
+        uri.getCharChunk().setLimit(-1);
+
+        mapper.map(host, uri, mappingData);
+        System.out.println("MD Host:" + mappingData.host);
+        System.out.println("MD Context:" + mappingData.context);
+        System.out.println("MD Wrapper:" + mappingData.wrapper);
+
+        System.out.println("contextPath:" + mappingData.contextPath);
+        System.out.println("wrapperPath:" + mappingData.wrapperPath);
+        System.out.println("pathInfo:" + mappingData.pathInfo);
+        System.out.println("redirectPath:" + mappingData.redirectPath);
+
+        mappingData.recycle();
+        mapper.map(host, uri, mappingData);
+        System.out.println("MD Host:" + mappingData.host);
+        System.out.println("MD Context:" + mappingData.context);
+        System.out.println("MD Wrapper:" + mappingData.wrapper);
+
+        System.out.println("contextPath:" + mappingData.contextPath);
+        System.out.println("wrapperPath:" + mappingData.wrapperPath);
+        System.out.println("pathInfo:" + mappingData.pathInfo);
+        System.out.println("redirectPath:" + mappingData.redirectPath);
+
+        for (int i = 0; i < 1000000; i++) {
+            mappingData.recycle();
+            mapper.map(host, uri, mappingData);
+        }
+
+        long time = System.currentTimeMillis();
+        for (int i = 0; i < 1000000; i++) {
+            mappingData.recycle();
+            mapper.map(host, uri, mappingData);
+        }
+        System.out.println("Elapsed:" + (System.currentTimeMillis() - time));
+
+        System.out.println("MD Host:" + mappingData.host);
+        System.out.println("MD Context:" + mappingData.context);
+        System.out.println("MD Wrapper:" + mappingData.wrapper);
+
+        System.out.println("contextPath:" + mappingData.contextPath);
+        System.out.println("wrapperPath:" + mappingData.wrapperPath);
+        System.out.println("requestPath:" + mappingData.requestPath);
+        System.out.println("pathInfo:" + mappingData.pathInfo);
+        System.out.println("redirectPath:" + mappingData.redirectPath);
+
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+
+    }
+    */
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/http/mapper/MappingData.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/http/mapper/MappingData.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/http/mapper/MappingData.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,52 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.mapper;
+
+import org.apache.tomcat.util.buf.MessageBytes;
+
+/**
+ * Mapping data.
+ *
+ * @author Remy Maucherat
+ */
+public class MappingData {
+
+    public Object host = null;
+    public Object context = null;
+    public Object wrapper = null;
+    public boolean jspWildCard = false;
+
+    public MessageBytes contextPath = MessageBytes.newInstance();
+    public MessageBytes requestPath = MessageBytes.newInstance();
+    public MessageBytes wrapperPath = MessageBytes.newInstance();
+    public MessageBytes pathInfo = MessageBytes.newInstance();
+
+    public MessageBytes redirectPath = MessageBytes.newInstance();
+
+    public void recycle() {
+        host = null;
+        context = null;
+        wrapper = null;
+        pathInfo.recycle();
+        requestPath.recycle();
+        wrapperPath.recycle();
+        contextPath.recycle();
+        redirectPath.recycle();
+        jspWildCard = false;
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/http/package.html
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/http/package.html	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/http/package.html	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,14 @@
+<html>
+<head>
+<title>util.http</title>
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+</head>
+
+<body bgcolor="#FFFFFF">
+Special utils for handling HTTP-specific entities - headers, parameters,
+cookies, etc.
+
+The utils are not specific to tomcat, but use util.MessageBytes.
+
+</body>
+</html>

Added: branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/http/res/LocalStrings.properties
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/http/res/LocalStrings.properties	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/http/res/LocalStrings.properties	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,46 @@
+# HttpMessages
+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

Added: branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/http/res/LocalStrings_es.properties
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/http/res/LocalStrings_es.properties	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/http/res/LocalStrings_es.properties	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,47 @@
+# HttpMessages
+sc.100=Continuar
+sc.101=Cambiando Protocolos
+sc.200=OK
+sc.201=Creado
+sc.202=Aceptado
+sc.203=Información No-Autorizativa
+sc.204=Sin Contenido
+sc.205=Reset Contenido
+sc.206=Contenido Parcial
+sc.207=Multi-Estado
+sc.300=Múltiples Elecciones
+sc.301=Movido permanentemente
+sc.302=Movido temporálmente
+sc.303=Mirar Otro
+sc.304=No Modificado
+sc.305=Usar Proxy
+sc.307=Redirección Temporal
+sc.400=Petición incorrecta
+sc.401=No Autorizado
+sc.402=Pago requerido
+sc.403=Prohibido
+sc.404=No Encontrado
+sc.405=Método No Permitido
+sc.406=No Aceptable
+sc.407=Autentificación Proxy Requerida
+sc.408=Request Caducada
+sc.409=Conflicto
+sc.410=Ido
+sc.411=Longitud Requerida
+sc.412=Precondición Fallada
+sc.413=Entidad de Request Demasiado Grande
+sc.414=Request-URI Demasiado Larga
+sc.415=Tipo de Medio No Soportado
+sc.416=El Rango Pedido No Ser Satisfecho
+sc.417=Expectativa Fallada
+sc.422=Entidad Improcesable
+sc.423=Bloqueado
+sc.424=Dependencia Fallida
+sc.500=Error Interno del Servidor
+sc.501=No Implementado
+sc.502=Pasarela Incorrecta
+sc.503=Servicio no Disponible
+sc.504=Pasarela Caducada
+sc.505=Versión de HTTP No Soportada
+sc.507=Almacenaje Insuficiente
+

Added: branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/http/res/LocalStrings_fr.properties
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/http/res/LocalStrings_fr.properties	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/http/res/LocalStrings_fr.properties	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,44 @@
+sc.100=Continuer
+sc.101=Changement de Protocols
+sc.200=OK
+sc.201=Crée
+sc.202=Accepté
+sc.203=Information Sans-Autorité
+sc.204=Pas de Contenu
+sc.205=Remise à Zéro de Contenu
+sc.206=Contenu Partiel
+sc.207=Etat Multiple
+sc.300=Choix Multiples
+sc.301=Déplacé de façon Permanente
+sc.302=Déplacé Temporairement
+sc.303=Voir Autre
+sc.304=Non Modifié
+sc.305=Utilisation de Relais
+sc.307=Redirection Temporaire
+sc.400=Mauvaise Requête
+sc.401=Non-Autorisé
+sc.402=Paiement Nécessaire
+sc.403=Interdit
+sc.404=Introuvable
+sc.405=Méthode Non Autorisée
+sc.406=Inacceptable
+sc.407=Authentification de Relais Nécessaire
+sc.408=Dépassement de Délais pour la Requête
+sc.409=Conflit
+sc.410=Parti
+sc.411=Taille Demandée
+sc.412=Echec de Pré-condition
+sc.413=Entité de Requête Trop Grande
+sc.414=URI de Requête Trop Grande
+sc.415=Type de Support Non Supporté
+sc.416=Etendue de Requête Irréalisable
+sc.417=Echec d'Attente
+sc.422=Entité Ingérable
+sc.424=Echec de Dépendance
+sc.500=Erreur Interne de Servlet
+sc.501=Non Implémenté
+sc.502=Mauvaise Passerelle
+sc.503=Service Indisponible
+sc.504=Dépassement de Délais pour la Passerelle
+sc.505=Version HTTP Non Supportée
+sc.507=Stockage Insuffisant

Added: branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/log/CaptureLog.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/log/CaptureLog.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/log/CaptureLog.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,49 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.log;
+
+import java.io.ByteArrayOutputStream;
+import java.io.PrintStream;
+
+/**
+ * Per Thread System.err and System.out log capture data.
+ *
+ * @author Glenn L. Nielsen
+ */
+
+class CaptureLog {
+
+    protected CaptureLog() {
+        baos = new ByteArrayOutputStream();
+        ps = new PrintStream(baos);
+    }
+
+    private ByteArrayOutputStream baos;
+    private PrintStream ps;
+
+    protected PrintStream getStream() {
+        return ps;
+    }
+
+    protected void reset() {
+        baos.reset();
+    }
+
+    protected String getCapture() {
+        return baos.toString();
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/log/SystemLogHandler.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/log/SystemLogHandler.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/log/SystemLogHandler.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,244 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.log;
+
+import java.io.IOException;
+import java.io.PrintStream;
+import java.util.EmptyStackException;
+import java.util.Stack;
+
+/**
+ * This helper class may be used to do sophisticated redirection of 
+ * System.out and System.err on a per Thread basis.
+ * 
+ * A stack is implemented per Thread so that nested startCapture
+ * and stopCapture can be used.
+ *
+ * @author Remy Maucherat
+ * @author Glenn L. Nielsen
+ */
+public class SystemLogHandler extends PrintStream {
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Construct the handler to capture the output of the given steam.
+     */
+    public SystemLogHandler(PrintStream wrapped) {
+        super(wrapped);
+        out = wrapped;
+    }
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * Wrapped PrintStream.
+     */
+    protected PrintStream out = null;
+
+
+    /**
+     * Thread <-> CaptureLog associations.
+     */
+    protected static ThreadLocal logs = new ThreadLocal();
+
+
+    /**
+     * Spare CaptureLog ready for reuse.
+     */
+    protected static Stack reuse = new Stack();
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Start capturing thread's output.
+     */
+    public static void startCapture() {
+        CaptureLog log = null;
+        if (!reuse.isEmpty()) {
+            try {
+                log = (CaptureLog)reuse.pop();
+            } catch (EmptyStackException e) {
+                log = new CaptureLog();
+            }
+        } else {
+            log = new CaptureLog();
+        }
+        Stack stack = (Stack)logs.get();
+        if (stack == null) {
+            stack = new Stack();
+            logs.set(stack);
+        }
+        stack.push(log);
+    }
+
+
+    /**
+     * Stop capturing thread's output and return captured data as a String.
+     */
+    public static String stopCapture() {
+        Stack stack = (Stack)logs.get();
+        if (stack == null || stack.isEmpty()) {
+            return null;
+        }
+        CaptureLog log = (CaptureLog)stack.pop();
+        if (log == null) {
+            return null;
+        }
+        String capture = log.getCapture();
+        log.reset();
+        reuse.push(log);
+        return capture;
+    }
+
+
+    // ------------------------------------------------------ Protected Methods
+
+
+    /**
+     * Find PrintStream to which the output must be written to.
+     */
+    protected PrintStream findStream() {
+        Stack stack = (Stack)logs.get();
+        if (stack != null && !stack.isEmpty()) {
+            CaptureLog log = (CaptureLog)stack.peek();
+            if (log != null) {
+                PrintStream ps = log.getStream();
+                if (ps != null) {
+                    return ps;
+                }
+            }
+        }
+        return out;
+    }
+
+
+    // ---------------------------------------------------- PrintStream Methods
+
+
+    public void flush() {
+        findStream().flush();
+    }
+
+    public void close() {
+        findStream().close();
+    }
+
+    public boolean checkError() {
+        return findStream().checkError();
+    }
+
+    protected void setError() {
+        //findStream().setError();
+    }
+
+    public void write(int b) {
+        findStream().write(b);
+    }
+
+    public void write(byte[] b)
+        throws IOException {
+        findStream().write(b);
+    }
+
+    public void write(byte[] buf, int off, int len) {
+        findStream().write(buf, off, len);
+    }
+
+    public void print(boolean b) {
+        findStream().print(b);
+    }
+
+    public void print(char c) {
+        findStream().print(c);
+    }
+
+    public void print(int i) {
+        findStream().print(i);
+    }
+
+    public void print(long l) {
+        findStream().print(l);
+    }
+
+    public void print(float f) {
+        findStream().print(f);
+    }
+
+    public void print(double d) {
+        findStream().print(d);
+    }
+
+    public void print(char[] s) {
+        findStream().print(s);
+    }
+
+    public void print(String s) {
+        findStream().print(s);
+    }
+
+    public void print(Object obj) {
+        findStream().print(obj);
+    }
+
+    public void println() {
+        findStream().println();
+    }
+
+    public void println(boolean x) {
+        findStream().println(x);
+    }
+
+    public void println(char x) {
+        findStream().println(x);
+    }
+
+    public void println(int x) {
+        findStream().println(x);
+    }
+
+    public void println(long x) {
+        findStream().println(x);
+    }
+
+    public void println(float x) {
+        findStream().println(x);
+    }
+
+    public void println(double x) {
+        findStream().println(x);
+    }
+
+    public void println(char[] x) {
+        findStream().println(x);
+    }
+
+    public void println(String x) {
+        findStream().println(x);
+    }
+
+    public void println(Object x) {
+        findStream().println(x);
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/net/AprEndpoint.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/net/AprEndpoint.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/net/AprEndpoint.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,1654 @@
+/*
+ *  Copyright 2005 The Apache Software Foundation
+ *
+ *  Licensed 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.net;
+
+import java.net.InetAddress;
+import java.util.ArrayList;
+import java.util.HashMap;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.tomcat.jni.OS;
+import org.apache.tomcat.jni.Address;
+import org.apache.tomcat.jni.Error;
+import org.apache.tomcat.jni.File;
+import org.apache.tomcat.jni.Library;
+import org.apache.tomcat.jni.Poll;
+import org.apache.tomcat.jni.Pool;
+import org.apache.tomcat.jni.Socket;
+import org.apache.tomcat.jni.Status;
+import org.apache.tomcat.jni.SSL;
+import org.apache.tomcat.jni.SSLContext;
+import org.apache.tomcat.jni.SSLSocket;
+import org.apache.tomcat.util.res.StringManager;
+import org.apache.tomcat.util.threads.ThreadWithAttributes;
+
+/**
+ * APR tailored thread pool, providing the following services:
+ * <ul>
+ * <li>Socket acceptor thread</li>
+ * <li>Socket poller thread</li>
+ * <li>Sendfile thread</li>
+ * <li>Worker threads pool</li>
+ * </ul>
+ *
+ * When switching to Java 5, there's an opportunity to use the virtual
+ * machine's thread pool.
+ *
+ * @author Mladen Turk
+ * @author Remy Maucherat
+ */
+public class AprEndpoint {
+
+
+    // -------------------------------------------------------------- Constants
+
+
+    protected static Log log = LogFactory.getLog(AprEndpoint.class);
+
+    protected static StringManager sm =
+        StringManager.getManager("org.apache.tomcat.util.net.res");
+
+
+    /**
+     * The Request attribute key for the cipher suite.
+     */
+    public static final String CIPHER_SUITE_KEY = "javax.servlet.request.cipher_suite";
+
+    /**
+     * The Request attribute key for the key size.
+     */
+    public static final String KEY_SIZE_KEY = "javax.servlet.request.key_size";
+
+    /**
+     * The Request attribute key for the client certificate chain.
+     */
+    public static final String CERTIFICATE_KEY = "javax.servlet.request.X509Certificate";
+
+    /**
+     * The Request attribute key for the session id.
+     * This one is a Tomcat extension to the Servlet spec.
+     */
+    public static final String SESSION_ID_KEY = "javax.servlet.request.ssl_session";
+
+
+    // ----------------------------------------------------------------- Fields
+
+
+    /**
+     * Available workers.
+     */
+    protected WorkerStack workers = null;
+
+
+    /**
+     * Running state of the endpoint.
+     */
+    protected volatile boolean running = false;
+
+
+    /**
+     * Will be set to true whenever the endpoint is paused.
+     */
+    protected volatile boolean paused = false;
+
+
+    /**
+     * Track the initialization state of the endpoint.
+     */
+    protected boolean initialized = false;
+
+
+    /**
+     * Current worker threads busy count.
+     */
+    protected int curThreadsBusy = 0;
+
+
+    /**
+     * Current worker threads count.
+     */
+    protected int curThreads = 0;
+
+
+    /**
+     * Sequence number used to generate thread names.
+     */
+    protected int sequence = 0;
+
+
+    /**
+     * Root APR memory pool.
+     */
+    protected long rootPool = 0;
+
+
+    /**
+     * Server socket "pointer".
+     */
+    protected long serverSock = 0;
+
+
+    /**
+     * APR memory pool for the server socket.
+     */
+    protected long serverSockPool = 0;
+
+
+    /**
+     * SSL context.
+     */
+    protected long sslContext = 0;
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * Maximum amount of worker threads.
+     */
+    protected int maxThreads = 40;
+    public void setMaxThreads(int maxThreads) { this.maxThreads = maxThreads; }
+    public int getMaxThreads() { return maxThreads; }
+
+
+    /**
+     * Priority of the acceptor and poller threads.
+     */
+    protected int threadPriority = Thread.NORM_PRIORITY;
+    public void setThreadPriority(int threadPriority) { this.threadPriority = threadPriority; }
+    public int getThreadPriority() { return threadPriority; }
+
+
+    /**
+     * Size of the socket poller.
+     */
+    protected int pollerSize = 8 * 1024;
+    public void setPollerSize(int pollerSize) { this.pollerSize = pollerSize; }
+    public int getPollerSize() { return pollerSize; }
+
+
+    /**
+     * Size of the sendfile (= concurrent files which can be served).
+     */
+    protected int sendfileSize = 1 * 1024;
+    public void setSendfileSize(int sendfileSize) { this.sendfileSize = sendfileSize; }
+    public int getSendfileSize() { return sendfileSize; }
+
+
+    /**
+     * Server socket port.
+     */
+    protected int port;
+    public int getPort() { return port; }
+    public void setPort(int port ) { this.port=port; }
+
+
+    /**
+     * Address for the server socket.
+     */
+    protected InetAddress address;
+    public InetAddress getAddress() { return address; }
+    public void setAddress(InetAddress address) { this.address = address; }
+
+
+    /**
+     * Handling of accepted sockets.
+     */
+    protected Handler handler = null;
+    public void setHandler(Handler handler ) { this.handler = handler; }
+    public Handler getHandler() { return handler; }
+
+
+    /**
+     * Allows the server developer to specify the backlog that
+     * should be used for server sockets. By default, this value
+     * is 100.
+     */
+    protected int backlog = 100;
+    public void setBacklog(int backlog) { if (backlog > 0) this.backlog = backlog; }
+    public int getBacklog() { return backlog; }
+
+
+    /**
+     * Socket TCP no delay.
+     */
+    protected boolean tcpNoDelay = false;
+    public boolean getTcpNoDelay() { return tcpNoDelay; }
+    public void setTcpNoDelay(boolean tcpNoDelay) { this.tcpNoDelay = tcpNoDelay; }
+
+
+    /**
+     * Socket linger.
+     */
+    protected int soLinger = 100;
+    public int getSoLinger() { return soLinger; }
+    public void setSoLinger(int soLinger) { this.soLinger = soLinger; }
+
+
+    /**
+     * Socket timeout.
+     */
+    protected int soTimeout = -1;
+    public int getSoTimeout() { return soTimeout; }
+    public void setSoTimeout(int soTimeout) { this.soTimeout = soTimeout; }
+
+
+    /**
+     * Timeout on first request read before going to the poller, in ms.
+     */
+    protected int firstReadTimeout = -1;
+    public int getFirstReadTimeout() { return firstReadTimeout; }
+    public void setFirstReadTimeout(int firstReadTimeout) { this.firstReadTimeout = firstReadTimeout; }
+
+
+    /**
+     * Poll interval, in microseconds. The smaller the value, the more CPU the poller
+     * will use, but the more responsive to activity it will be.
+     */
+    protected int pollTime = 2000;
+    public int getPollTime() { return pollTime; }
+    public void setPollTime(int pollTime) { if (pollTime > 0) { this.pollTime = pollTime; } }
+
+
+    /**
+     * The default is true - the created threads will be
+     *  in daemon mode. If set to false, the control thread
+     *  will not be daemon - and will keep the process alive.
+     */
+    protected boolean daemon = true;
+    public void setDaemon(boolean b) { daemon = b; }
+    public boolean getDaemon() { return daemon; }
+
+
+    /**
+     * Name of the thread pool, which will be used for naming child threads.
+     */
+    protected String name = "TP";
+    public void setName(String name) { this.name = name; }
+    public String getName() { return name; }
+
+
+    /**
+     * Use endfile for sending static files.
+     */
+    protected boolean useSendfile = Library.APR_HAS_SENDFILE;
+    public void setUseSendfile(boolean useSendfile) { this.useSendfile = useSendfile; }
+    public boolean getUseSendfile() { return useSendfile; }
+
+
+    /**
+     * Acceptor thread count.
+     */
+    protected int acceptorThreadCount = 0;
+    public void setAcceptorThreadCount(int acceptorThreadCount) { this.acceptorThreadCount = acceptorThreadCount; }
+    public int getAcceptorThreadCount() { return acceptorThreadCount; }
+
+
+    /**
+     * Sendfile thread count.
+     */
+    protected int sendfileThreadCount = 0;
+    public void setSendfileThreadCount(int sendfileThreadCount) { this.sendfileThreadCount = sendfileThreadCount; }
+    public int getSendfileThreadCount() { return sendfileThreadCount; }
+
+
+    /**
+     * Poller thread count.
+     */
+    protected int pollerThreadCount = 0;
+    public void setPollerThreadCount(int pollerThreadCount) { this.pollerThreadCount = pollerThreadCount; }
+    public int getPollerThreadCount() { return pollerThreadCount; }
+
+
+    /**
+     * The socket poller.
+     */
+    protected Poller[] pollers = null;
+    protected int pollerRoundRobin = 0;
+    public Poller getPoller() {
+        pollerRoundRobin = (pollerRoundRobin + 1) % pollers.length;
+        return pollers[pollerRoundRobin];
+    }
+
+
+    /**
+     * The static file sender.
+     */
+    protected Sendfile[] sendfiles = null;
+    protected int sendfileRoundRobin = 0;
+    public Sendfile getSendfile() {
+        sendfileRoundRobin = (sendfileRoundRobin + 1) % sendfiles.length;
+        return sendfiles[sendfileRoundRobin];
+    }
+
+
+    /**
+     * Dummy maxSpareThreads property.
+     */
+    public int getMaxSpareThreads() { return 0; }
+
+
+    /**
+     * Dummy minSpareThreads property.
+     */
+    public int getMinSpareThreads() { return 0; }
+
+
+    /**
+     * SSL engine.
+     */
+    protected String SSLEngine = "off";
+    public String getSSLEngine() { return SSLEngine; }
+    public void setSSLEngine(String SSLEngine) { this.SSLEngine = SSLEngine; }
+
+
+    /**
+     * SSL protocols.
+     */
+    protected String SSLProtocol = "all";
+    public String getSSLProtocol() { return SSLProtocol; }
+    public void setSSLProtocol(String SSLProtocol) { this.SSLProtocol = SSLProtocol; }
+
+
+    /**
+     * SSL password (if a cert is encrypted, and no password has been provided, a callback
+     * will ask for a password).
+     */
+    protected String SSLPassword = null;
+    public String getSSLPassword() { return SSLPassword; }
+    public void setSSLPassword(String SSLPassword) { this.SSLPassword = SSLPassword; }
+
+
+    /**
+     * SSL cipher suite.
+     */
+    protected String SSLCipherSuite = "ALL";
+    public String getSSLCipherSuite() { return SSLCipherSuite; }
+    public void setSSLCipherSuite(String SSLCipherSuite) { this.SSLCipherSuite = SSLCipherSuite; }
+
+
+    /**
+     * SSL certificate file.
+     */
+    protected String SSLCertificateFile = null;
+    public String getSSLCertificateFile() { return SSLCertificateFile; }
+    public void setSSLCertificateFile(String SSLCertificateFile) { this.SSLCertificateFile = SSLCertificateFile; }
+
+
+    /**
+     * SSL certificate key file.
+     */
+    protected String SSLCertificateKeyFile = null;
+    public String getSSLCertificateKeyFile() { return SSLCertificateKeyFile; }
+    public void setSSLCertificateKeyFile(String SSLCertificateKeyFile) { this.SSLCertificateKeyFile = SSLCertificateKeyFile; }
+
+
+    /**
+     * SSL certificate chain file.
+     */
+    protected String SSLCertificateChainFile = null;
+    public String getSSLCertificateChainFile() { return SSLCertificateChainFile; }
+    public void setSSLCertificateChainFile(String SSLCertificateChainFile) { this.SSLCertificateChainFile = SSLCertificateChainFile; }
+
+
+    /**
+     * SSL CA certificate path.
+     */
+    protected String SSLCACertificatePath = null;
+    public String getSSLCACertificatePath() { return SSLCACertificatePath; }
+    public void setSSLCACertificatePath(String SSLCACertificatePath) { this.SSLCACertificatePath = SSLCACertificatePath; }
+
+
+    /**
+     * SSL CA certificate file.
+     */
+    protected String SSLCACertificateFile = null;
+    public String getSSLCACertificateFile() { return SSLCACertificateFile; }
+    public void setSSLCACertificateFile(String SSLCACertificateFile) { this.SSLCACertificateFile = SSLCACertificateFile; }
+
+
+    /**
+     * SSL CA revocation path.
+     */
+    protected String SSLCARevocationPath = null;
+    public String getSSLCARevocationPath() { return SSLCARevocationPath; }
+    public void setSSLCARevocationPath(String SSLCARevocationPath) { this.SSLCARevocationPath = SSLCARevocationPath; }
+
+
+    /**
+     * SSL CA revocation file.
+     */
+    protected String SSLCARevocationFile = null;
+    public String getSSLCARevocationFile() { return SSLCARevocationFile; }
+    public void setSSLCARevocationFile(String SSLCARevocationFile) { this.SSLCARevocationFile = SSLCARevocationFile; }
+
+
+    /**
+     * SSL verify client.
+     */
+    protected String SSLVerifyClient = "none";
+    public String getSSLVerifyClient() { return SSLVerifyClient; }
+    public void setSSLVerifyClient(String SSLVerifyClient) { this.SSLVerifyClient = SSLVerifyClient; }
+
+
+    /**
+     * SSL verify depth.
+     */
+    protected int SSLVerifyDepth = 10;
+    public int getSSLVerifyDepth() { return SSLVerifyDepth; }
+    public void setSSLVerifyDepth(int SSLVerifyDepth) { this.SSLVerifyDepth = SSLVerifyDepth; }
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Number of keepalive sockets.
+     */
+    public int getKeepAliveCount() {
+        if (pollers == null) {
+            return 0;
+        } else {
+            int keepAliveCount = 0;
+            for (int i = 0; i < pollers.length; i++) {
+                keepAliveCount += pollers[i].getKeepAliveCount();
+            }
+            return keepAliveCount;
+        }
+    }
+
+
+    /**
+     * Number of sendfile sockets.
+     */
+    public int getSendfileCount() {
+        if (sendfiles == null) {
+            return 0;
+        } else {
+            int sendfileCount = 0;
+            for (int i = 0; i < sendfiles.length; i++) {
+                sendfileCount += sendfiles[i].getSendfileCount();
+            }
+            return sendfileCount;
+        }
+    }
+
+
+    /**
+     * Return the amount of threads that are managed by the pool.
+     *
+     * @return the amount of threads that are managed by the pool
+     */
+    public int getCurrentThreadCount() {
+        return curThreads;
+    }
+
+
+    /**
+     * Return the amount of threads currently busy.
+     *
+     * @return the amount of threads currently busy
+     */
+    public int getCurrentThreadsBusy() {
+        return curThreadsBusy;
+    }
+
+
+    /**
+     * Return the state of the endpoint.
+     *
+     * @return true if the endpoint is running, false otherwise
+     */
+    public boolean isRunning() {
+        return running;
+    }
+
+
+    /**
+     * Return the state of the endpoint.
+     *
+     * @return true if the endpoint is paused, false otherwise
+     */
+    public boolean isPaused() {
+        return paused;
+    }
+
+
+    // ----------------------------------------------- Public Lifecycle Methods
+
+
+    /**
+     * Initialize the endpoint.
+     */
+    public void init()
+        throws Exception {
+
+        if (initialized)
+            return;
+        
+        // Create the root APR memory pool
+        rootPool = Pool.create(0);
+        // Create the pool for the server socket
+        serverSockPool = Pool.create(rootPool);
+        // Create the APR address that will be bound
+        String addressStr = null;
+        if (address == null) {
+            addressStr = null;
+        } else {
+            addressStr = address.getHostAddress();
+        }
+        int family = Socket.APR_INET;
+        if (Library.APR_HAVE_IPV6) {
+            if (addressStr == null)
+                family = Socket.APR_UNSPEC;
+            else if (addressStr.indexOf(':') >= 0)
+                family = Socket.APR_UNSPEC;
+        }
+        long inetAddress = Address.info(addressStr, family,
+                port, 0, rootPool);
+        // Create the APR server socket
+        serverSock = Socket.create(family, Socket.SOCK_STREAM,
+                Socket.APR_PROTO_TCP, rootPool);
+        if (OS.IS_UNIX) {
+            Socket.optSet(serverSock, Socket.APR_SO_REUSEADDR, 1);
+        }
+        // Deal with the firewalls that tend to drop the inactive sockets
+        Socket.optSet(serverSock, Socket.APR_SO_KEEPALIVE, 1);
+        // Bind the server socket
+        int ret = Socket.bind(serverSock, inetAddress);
+        if (ret != 0) {
+            throw new Exception(sm.getString("endpoint.init.bind", "" + ret, Error.strerror(ret)));
+        }
+        // Start listening on the server socket
+        ret = Socket.listen(serverSock, backlog);
+        if (ret != 0) {
+            throw new Exception(sm.getString("endpoint.init.listen", "" + ret, Error.strerror(ret)));
+        }
+        if (OS.IS_WIN32 || OS.IS_WIN64) {
+            // On Windows set the reuseaddr flag after the bind/listen
+            Socket.optSet(serverSock, Socket.APR_SO_REUSEADDR, 1);
+        }
+
+        // Sendfile usage on systems which don't support it cause major problems
+        if (useSendfile && !Library.APR_HAS_SENDFILE) {
+            log.warn(sm.getString("endpoint.sendfile.nosupport"));
+            useSendfile = false;
+        }
+
+        // Initialize thread count defaults for acceptor, poller and sendfile
+        if (acceptorThreadCount == 0) {
+            // FIXME: Doesn't seem to work that well with multiple accept threads
+            acceptorThreadCount = 1;
+        }
+        if (pollerThreadCount == 0) {
+            if ((OS.IS_WIN32 || OS.IS_WIN64) && (pollerSize > 1024)) {
+                // The maximum per poller to get reasonable performance is 1024
+                pollerThreadCount = pollerSize / 1024;
+                // Adjust poller size so that it won't reach the limit
+                pollerSize = pollerSize - (pollerSize % 1024);
+            } else {
+                // No explicit poller size limitation
+                pollerThreadCount = 1;
+            }
+        }
+        if (sendfileThreadCount == 0) {
+            if ((OS.IS_WIN32 || OS.IS_WIN64) && (sendfileSize > 1024)) {
+                // The maximum per poller to get reasonable performance is 1024
+                sendfileThreadCount = sendfileSize / 1024;
+                // Adjust poller size so that it won't reach the limit
+                sendfileSize = sendfileSize - (sendfileSize % 1024);
+            } else {
+                // No explicit poller size limitation
+                // FIXME: Default to one per CPU ?
+                sendfileThreadCount = 1;
+            }
+        }
+        
+        // Delay accepting of new connections until data is available
+        // Only Linux kernels 2.4 + have that implemented
+        // on other platforms this call is noop and will return APR_ENOTIMPL.
+        Socket.optSet(serverSock, Socket.APR_TCP_DEFER_ACCEPT, 1);
+
+        // Initialize SSL if needed
+        if (!"off".equalsIgnoreCase(SSLEngine)) {
+            // Initialize SSL
+            // FIXME: one per VM call ?
+            if ("on".equalsIgnoreCase(SSLEngine)) {
+                SSL.initialize(null);
+            } else {
+                SSL.initialize(SSLEngine);
+            }
+            // SSL protocol
+            int value = SSL.SSL_PROTOCOL_ALL;
+            if ("SSLv2".equalsIgnoreCase(SSLProtocol)) {
+                value = SSL.SSL_PROTOCOL_SSLV2;
+            } else if ("SSLv3".equalsIgnoreCase(SSLProtocol)) {
+                value = SSL.SSL_PROTOCOL_SSLV3;
+            } else if ("TLSv1".equalsIgnoreCase(SSLProtocol)) {
+                value = SSL.SSL_PROTOCOL_TLSV1;
+            } else if ("SSLv2+SSLv3".equalsIgnoreCase(SSLProtocol)) {
+                value = SSL.SSL_PROTOCOL_SSLV2 | SSL.SSL_PROTOCOL_SSLV3;
+            }
+            // Create SSL Context
+            sslContext = SSLContext.make(rootPool, value, SSL.SSL_MODE_SERVER);
+            // List the ciphers that the client is permitted to negotiate
+            SSLContext.setCipherSuite(sslContext, SSLCipherSuite);
+            // Load Server key and certificate
+            SSLContext.setCertificate(sslContext, SSLCertificateFile, SSLCertificateKeyFile, SSLPassword, SSL.SSL_AIDX_RSA);
+            // Set certificate chain file
+            SSLContext.setCertificateChainFile(sslContext, SSLCertificateChainFile, false);
+            // Support Client Certificates
+            SSLContext.setCACertificate(sslContext, SSLCACertificateFile, SSLCACertificatePath);
+            // Set revocation
+            SSLContext.setCARevocation(sslContext, SSLCARevocationFile, SSLCARevocationPath);
+            // Client certificate verification
+            value = SSL.SSL_CVERIFY_NONE;
+            if ("optional".equalsIgnoreCase(SSLVerifyClient)) {
+                value = SSL.SSL_CVERIFY_OPTIONAL;
+            } else if ("require".equalsIgnoreCase(SSLVerifyClient)) {
+                value = SSL.SSL_CVERIFY_REQUIRE;
+            } else if ("optionalNoCA".equalsIgnoreCase(SSLVerifyClient)) {
+                value = SSL.SSL_CVERIFY_OPTIONAL_NO_CA;
+            }
+            SSLContext.setVerify(sslContext, value, SSLVerifyDepth);
+            // For now, sendfile is not supported with SSL
+            useSendfile = false;
+        }
+
+        initialized = true;
+
+    }
+
+
+    /**
+     * Start the APR endpoint, creating acceptor, poller and sendfile threads.
+     */
+    public void start()
+        throws Exception {
+        // Initialize socket if not done before
+        if (!initialized) {
+            init();
+        }
+        if (!running) {
+            running = true;
+            paused = false;
+
+            // Create worker collection
+            workers = new WorkerStack(maxThreads);
+
+            // Start acceptor thread
+            for (int i = 0; i < acceptorThreadCount; i++) {
+                Thread acceptorThread = new Thread(new Acceptor(), getName() + "-Acceptor-" + i);
+                acceptorThread.setPriority(threadPriority);
+                acceptorThread.setDaemon(daemon);
+                acceptorThread.start();
+            }
+
+            // Start poller thread
+            pollers = new Poller[pollerThreadCount];
+            for (int i = 0; i < pollerThreadCount; i++) {
+                pollers[i] = new Poller();
+                pollers[i].init();
+                Thread pollerThread = new Thread(pollers[i], getName() + "-Poller-" + i);
+                pollerThread.setPriority(threadPriority);
+                pollerThread.setDaemon(true);
+                pollerThread.start();
+            }
+
+            // Start sendfile thread
+            if (useSendfile) {
+                sendfiles = new Sendfile[sendfileThreadCount];
+                for (int i = 0; i < sendfileThreadCount; i++) {
+                    sendfiles[i] = new Sendfile();
+                    sendfiles[i].init();
+                    Thread sendfileThread = new Thread(sendfiles[i], getName() + "-Sendfile-" + i);
+                    sendfileThread.setPriority(threadPriority);
+                    sendfileThread.setDaemon(true);
+                    sendfileThread.start();
+                }
+            }
+        }
+    }
+
+
+    /**
+     * Pause the endpoint, which will make it stop accepting new sockets.
+     */
+    public void pause() {
+        if (running && !paused) {
+            paused = true;
+            unlockAccept();
+        }
+    }
+
+
+    /**
+     * Resume the endpoint, which will make it start accepting new sockets
+     * again.
+     */
+    public void resume() {
+        if (running) {
+            paused = false;
+        }
+    }
+
+
+    /**
+     * Stop the endpoint. This will cause all processing threads to stop.
+     */
+    public void stop() {
+        if (running) {
+            running = false;
+            unlockAccept();
+            for (int i = 0; i < pollers.length; i++) {
+                pollers[i].destroy();
+            }
+            pollers = null;
+            if (useSendfile) {
+                for (int i = 0; i < sendfiles.length; i++) {
+                    sendfiles[i].destroy();
+                }
+                sendfiles = null;
+            }
+        }
+    }
+
+
+    /**
+     * Deallocate APR memory pools, and close server socket.
+     */
+    public void destroy() throws Exception {
+        if (running) {
+            stop();
+        }
+        Pool.destroy(serverSockPool);
+        serverSockPool = 0;
+        // Close server socket
+        Socket.close(serverSock);
+        serverSock = 0;
+        sslContext = 0;
+        // Close all APR memory pools and resources
+        Pool.destroy(rootPool);
+        rootPool = 0;
+        initialized = false ;
+    }
+
+
+    // ------------------------------------------------------ Protected Methods
+
+
+    /**
+     * Get a sequence number used for thread naming.
+     */
+    protected int getSequence() {
+        return sequence++;
+    }
+
+
+    /**
+     * Unlock the server socket accept using a bugus connection.
+     */
+    protected void unlockAccept() {
+        java.net.Socket s = null;
+        try {
+            // Need to create a connection to unlock the accept();
+            if (address == null) {
+                s = new java.net.Socket("127.0.0.1", port);
+            } else {
+                s = new java.net.Socket(address, port);
+                // setting soLinger to a small value will help shutdown the
+                // connection quicker
+                s.setSoLinger(true, 0);
+            }
+        } catch(Exception e) {
+            if (log.isDebugEnabled()) {
+                log.debug(sm.getString("endpoint.debug.unlock", "" + port), e);
+            }
+        } finally {
+            if (s != null) {
+                try {
+                    s.close();
+                } catch (Exception e) {
+                    // Ignore
+                }
+            }
+        }
+    }
+
+
+    /**
+     * Process the specified connection.
+     */
+    protected boolean setSocketOptions(long socket) {
+        // Process the connection
+        int step = 1;
+        try {
+
+            // 1: Set socket options: timeout, linger, etc
+            if (soLinger >= 0)
+                Socket.optSet(socket, Socket.APR_SO_LINGER, soLinger);
+            if (tcpNoDelay)
+                Socket.optSet(socket, Socket.APR_TCP_NODELAY, (tcpNoDelay ? 1 : 0));
+            if (soTimeout > 0)
+                Socket.timeoutSet(socket, soTimeout * 1000);
+
+            // 2: SSL handshake
+            step = 2;
+            if (sslContext != 0) {
+                SSLSocket.attach(sslContext, socket);
+                if (SSLSocket.handshake(socket) != 0) {
+                    if (log.isDebugEnabled()) {
+                        log.debug(sm.getString("endpoint.err.handshake") + ": " + SSL.getLastError());
+                    }
+                    return false;
+                }
+            }
+
+        } catch (Throwable t) {
+            if (log.isDebugEnabled()) {
+                if (step == 2) {
+                    log.debug(sm.getString("endpoint.err.handshake"), t);
+                } else {
+                    log.debug(sm.getString("endpoint.err.unexpected"), t);
+                }
+            }
+            // Tell to close the socket
+            return false;
+        }
+        return true;
+    }
+
+
+    /**
+     * Create (or allocate) and return an available processor for use in
+     * processing a specific HTTP request, if possible.  If the maximum
+     * allowed processors have already been created and are in use, return
+     * <code>null</code> instead.
+     */
+    protected Worker createWorkerThread() {
+
+        synchronized (workers) {
+            if (workers.size() > 0) {
+                curThreadsBusy++;
+                return (workers.pop());
+            }
+            if ((maxThreads > 0) && (curThreads < maxThreads)) {
+                curThreadsBusy++;
+                return (newWorkerThread());
+            } else {
+                if (maxThreads < 0) {
+                    curThreadsBusy++;
+                    return (newWorkerThread());
+                } else {
+                    return (null);
+                }
+            }
+        }
+
+    }
+
+
+    /**
+     * Create and return a new processor suitable for processing HTTP
+     * requests and returning the corresponding responses.
+     */
+    protected Worker newWorkerThread() {
+
+        Worker workerThread = new Worker();
+        workerThread.start();
+        return (workerThread);
+
+    }
+
+
+    /**
+     * Return a new worker thread, and block while to worker is available.
+     */
+    protected Worker getWorkerThread() {
+        // Allocate a new worker thread
+        Worker workerThread = createWorkerThread();
+        while (workerThread == null) {
+            try {
+                synchronized (workers) {
+                    workers.wait();
+                }
+            } catch (InterruptedException e) {
+                // Ignore
+            }
+            workerThread = createWorkerThread();
+        }
+        return workerThread;
+    }
+
+
+    /**
+     * Recycle the specified Processor so that it can be used again.
+     *
+     * @param workerThread The processor to be recycled
+     */
+    protected void recycleWorkerThread(Worker workerThread) {
+        synchronized (workers) {
+            workers.push(workerThread);
+            curThreadsBusy--;
+            workers.notify();
+        }
+    }
+
+    
+    /**
+     * Allocate a new poller of the specified size.
+     */
+    protected long allocatePoller(int size, long pool, int timeout) {
+        try {
+            return Poll.create(size, pool, 0, timeout * 1000);
+        } catch (Error e) {
+            if (Status.APR_STATUS_IS_EINVAL(e.getError())) {
+                log.info(sm.getString("endpoint.poll.limitedpollsize", "" + size));
+                return 0;
+            } else {
+                log.error(sm.getString("endpoint.poll.initfail"), e);
+                return -1;
+            }
+        }
+    }
+    
+    
+
+    // --------------------------------------------------- Acceptor Inner Class
+
+
+    /**
+     * Server socket acceptor thread.
+     */
+    protected class Acceptor implements Runnable {
+
+
+        /**
+         * The background thread that listens for incoming TCP/IP connections and
+         * hands them off to an appropriate processor.
+         */
+        public void run() {
+
+            // Loop until we receive a shutdown command
+            while (running) {
+
+                // Loop if endpoint is paused
+                while (paused) {
+                    try {
+                        Thread.sleep(1000);
+                    } catch (InterruptedException e) {
+                        // Ignore
+                    }
+                }
+
+                try {
+                    // Accept the next incoming connection from the server socket
+                    long socket = Socket.accept(serverSock);
+                    // Allocate a new worker thread
+                    // Hand this socket off to an appropriate processor
+                    getWorkerThread().assign(socket, true);
+                } catch (Throwable t) {
+                    log.error(sm.getString("endpoint.accept.fail"), t);
+                }
+
+                // The processor will recycle itself when it finishes
+
+            }
+
+        }
+
+    }
+
+
+    // ----------------------------------------------------- Poller Inner Class
+
+
+    /**
+     * Poller class.
+     */
+    public class Poller implements Runnable {
+
+        protected long serverPollset = 0;
+        protected long pool = 0;
+        protected long[] desc;
+
+        protected long[] addS;
+        protected int addCount = 0;
+        
+        protected int keepAliveCount = 0;
+        public int getKeepAliveCount() { return keepAliveCount; }
+
+        /**
+         * Create the poller. With some versions of APR, the maximum poller size will
+         * be 62 (reocmpiling APR is necessary to remove this limitation).
+         */
+        protected void init() {
+            pool = Pool.create(serverSockPool);
+            int size = pollerSize / pollerThreadCount;
+            serverPollset = allocatePoller(size, pool, soTimeout);
+            if (serverPollset == 0 && size > 1024) {
+                size = 1024;
+                serverPollset = allocatePoller(size, pool, soTimeout);
+            }
+            if (serverPollset == 0) {
+                size = 62;
+                serverPollset = allocatePoller(size, pool, soTimeout);
+            }
+            desc = new long[size * 2];
+            keepAliveCount = 0;
+            addS = new long[size];
+            addCount = 0;
+        }
+
+        /**
+         * Destroy the poller.
+         */
+        protected void destroy() {
+            // Close all sockets in the add queue
+            for (int i = 0; i < addCount; i++) {
+                Socket.destroy(addS[i]);
+            }
+            // Close all sockets still in the poller
+            int rv = Poll.pollset(serverPollset, desc);
+            if (rv > 0) {
+                for (int n = 0; n < rv; n++) {
+                    Socket.destroy(desc[n*2+1]);
+                }
+            }
+            Pool.destroy(pool);
+            keepAliveCount = 0;
+            addCount = 0;
+        }
+
+        /**
+         * Add specified socket and associated pool to the poller. The socket will
+         * be added to a temporary array, and polled first after a maximum amount
+         * of time equal to pollTime (in most cases, latency will be much lower,
+         * however).
+         *
+         * @param socket to add to the poller
+         */
+        public void add(long socket) {
+            synchronized (this) {
+                // Add socket to the list. Newly added sockets will wait
+                // at most for pollTime before being polled
+                if (addCount >= addS.length) {
+                    // Can't do anything: close the socket right away
+                    Socket.destroy(socket);
+                    return;
+                }
+                addS[addCount] = socket;
+                addCount++;
+                this.notify();
+            }
+        }
+
+        /**
+         * The background thread that listens for incoming TCP/IP connections and
+         * hands them off to an appropriate processor.
+         */
+        public void run() {
+
+            long maintainTime = 0;
+            // Loop until we receive a shutdown command
+            while (running) {
+                // Loop if endpoint is paused
+                while (paused) {
+                    try {
+                        // TODO: We can easly do the maintenance here
+                        Thread.sleep(1000);
+                    } catch (InterruptedException e) {
+                        // Ignore
+                    }
+                }
+
+                while (keepAliveCount < 1 && addCount < 1) {
+                    // Reset maintain time.
+                    maintainTime = 0;
+                    try {
+                        synchronized (this) {
+                            this.wait();
+                        }
+                    } catch (InterruptedException e) {
+                        // Ignore
+                    }
+                }
+
+                try {
+                    // Add sockets which are waiting to the poller
+                    if (addCount > 0) {
+                        synchronized (this) {
+                            for (int i = (addCount - 1); i >= 0; i--) {
+                                int rv = Poll.add
+                                    (serverPollset, addS[i], Poll.APR_POLLIN);
+                                if (rv == Status.APR_SUCCESS) {
+                                    keepAliveCount++;
+                                } else {
+                                    // Can't do anything: close the socket right away
+                                    Socket.destroy(addS[i]);
+                                }
+                            }
+                            addCount = 0;
+                        }
+                    }
+                    maintainTime += pollTime;
+                    // Pool for the specified interval
+                    int rv = Poll.poll(serverPollset, pollTime, desc, true);
+                    if (rv > 0) {
+                        keepAliveCount -= rv;
+                        for (int n = 0; n < rv; n++) {
+                            // Check for failed sockets
+                            if (((desc[n*2] & Poll.APR_POLLHUP) == Poll.APR_POLLHUP)
+                                    || ((desc[n*2] & Poll.APR_POLLERR) == Poll.APR_POLLERR)) {
+                                // Close socket and clear pool
+                                Socket.destroy(desc[n*2+1]);
+                                continue;
+                            }
+                            // Hand this socket off to a worker
+                            getWorkerThread().assign(desc[n*2+1], false);
+                        }
+                    } else if (rv < 0) {
+                        int errn = -rv;
+                        /* Any non timeup or interrupted error is critical */
+                        if ((errn != Status.TIMEUP) && (errn != Status.EINTR)) {
+                            if (errn >  Status.APR_OS_START_USERERR) {
+                                errn -=  Status.APR_OS_START_USERERR;
+                            }
+                            log.error(sm.getString("endpoint.poll.fail", "" + errn, Error.strerror(errn)));
+                            // Handle poll critical failure
+                            synchronized (this) {
+                                destroy();
+                                init();
+                            }
+                            continue;
+                        }
+                    }
+                    if (soTimeout > 0 && maintainTime > 1000000L) {
+                        rv = Poll.maintain(serverPollset, desc, true);
+                        maintainTime = 0;
+                        if (rv > 0) {
+                            keepAliveCount -= rv;
+                            for (int n = 0; n < rv; n++) {
+                                // Close socket and clear pool
+                                Socket.destroy(desc[n]);
+                            }
+                        }
+                    }
+                } catch (Throwable t) {
+                    log.error(sm.getString("endpoint.poll.error"), t);
+                }
+
+            }
+
+        }
+
+    }
+
+
+    // ----------------------------------------------------- Worker Inner Class
+
+
+    /**
+     * Server processor class.
+     */
+    protected class Worker implements Runnable {
+
+
+        protected Thread thread = null;
+        protected boolean available = false;
+        protected long socket = 0;
+        protected boolean options = false;
+
+
+        /**
+         * Process an incoming TCP/IP connection on the specified socket.  Any
+         * exception that occurs during processing must be logged and swallowed.
+         * <b>NOTE</b>:  This method is called from our Connector's thread.  We
+         * must assign it to our own thread so that multiple simultaneous
+         * requests can be handled.
+         *
+         * @param socket TCP socket to process
+         */
+        protected synchronized void assign(long socket, boolean options) {
+
+            // Wait for the Processor to get the previous Socket
+            while (available) {
+                try {
+                    wait();
+                } catch (InterruptedException e) {
+                }
+            }
+
+            // Store the newly available Socket and notify our thread
+            this.socket = socket;
+            this.options = options;
+            available = true;
+            notifyAll();
+
+        }
+
+
+        /**
+         * Await a newly assigned Socket from our Connector, or <code>null</code>
+         * if we are supposed to shut down.
+         */
+        protected synchronized long await() {
+
+            // Wait for the Connector to provide a new Socket
+            while (!available) {
+                try {
+                    wait();
+                } catch (InterruptedException e) {
+                }
+            }
+
+            // Notify the Connector that we have received this Socket
+            long socket = this.socket;
+            available = false;
+            notifyAll();
+
+            return (socket);
+
+        }
+
+
+        /**
+         * The background thread that listens for incoming TCP/IP connections and
+         * hands them off to an appropriate processor.
+         */
+        public void run() {
+
+            // Process requests until we receive a shutdown signal
+            while (running) {
+
+                // Wait for the next socket to be assigned
+                long socket = await();
+                if (socket == 0)
+                    continue;
+
+                // Process the request from this socket
+                if ((options && !setSocketOptions(socket)) || !handler.process(socket)) {
+                    // Close socket and pool
+                    Socket.destroy(socket);
+                    socket = 0;
+                }
+
+                // Finish up this request
+                recycleWorkerThread(this);
+
+            }
+
+        }
+
+
+        /**
+         * Start the background processing thread.
+         */
+        public void start() {
+            thread = new ThreadWithAttributes(AprEndpoint.this, this);
+            thread.setName(getName() + "-" + (++curThreads));
+            thread.setDaemon(true);
+            thread.start();
+        }
+
+
+    }
+
+
+    // ----------------------------------------------- SendfileData Inner Class
+
+
+    /**
+     * SendfileData class.
+     */
+    public static class SendfileData {
+        // File
+        public String fileName;
+        public long fd;
+        public long fdpool;
+        // Range information
+        public long start;
+        public long end;
+        // Socket and socket pool
+        public long socket;
+        // Position
+        public long pos;
+        // KeepAlive flag
+        public boolean keepAlive;
+    }
+
+
+    // --------------------------------------------------- Sendfile Inner Class
+
+
+    /**
+     * Sendfile class.
+     */
+    public class Sendfile implements Runnable {
+
+        protected long sendfilePollset = 0;
+        protected long pool = 0;
+        protected long[] desc;
+        protected HashMap sendfileData;
+        
+        protected int sendfileCount;
+        public int getSendfileCount() { return sendfileCount; }
+
+        protected ArrayList addS;
+
+        /**
+         * Create the sendfile poller. With some versions of APR, the maximum poller size will
+         * be 62 (reocmpiling APR is necessary to remove this limitation).
+         */
+        protected void init() {
+            pool = Pool.create(serverSockPool);
+            int size = sendfileSize / sendfileThreadCount;
+            sendfilePollset = allocatePoller(size, pool, soTimeout);
+            if (sendfilePollset == 0 && size > 1024) {
+                size = 1024;
+                sendfilePollset = allocatePoller(size, pool, soTimeout);
+            }
+            if (sendfilePollset == 0) {
+                size = 62;
+                sendfilePollset = allocatePoller(size, pool, soTimeout);
+            }
+            desc = new long[size * 2];
+            sendfileData = new HashMap(size);
+            addS = new ArrayList();
+        }
+
+        /**
+         * Destroy the poller.
+         */
+        protected void destroy() {
+            // Close any socket remaining in the add queue
+            for (int i = (addS.size() - 1); i >= 0; i--) {
+                SendfileData data = (SendfileData) addS.get(i);
+                Socket.destroy(data.socket);
+            }
+            // Close all sockets still in the poller
+            int rv = Poll.pollset(sendfilePollset, desc);
+            if (rv > 0) {
+                for (int n = 0; n < rv; n++) {
+                    Socket.destroy(desc[n*2+1]);
+                }
+            }
+            Pool.destroy(pool);
+            sendfileData.clear();
+        }
+
+        /**
+         * Add the sendfile data to the sendfile poller. Note that in most cases,
+         * the initial non blocking calls to sendfile will return right away, and
+         * will be handled asynchronously inside the kernel. As a result,
+         * the poller will never be used.
+         *
+         * @param data containing the reference to the data which should be snet
+         * @return true if all the data has been sent right away, and false
+         *              otherwise
+         */
+        public boolean add(SendfileData data) {
+            // Initialize fd from data given
+            try {
+                data.fdpool = Socket.pool(data.socket);
+                data.fd = File.open
+                    (data.fileName, File.APR_FOPEN_READ
+                     | File.APR_FOPEN_SENDFILE_ENABLED | File.APR_FOPEN_BINARY,
+                     0, data.fdpool);
+                data.pos = data.start;
+                // Set the socket to nonblocking mode
+                Socket.timeoutSet(data.socket, 0);
+                while (true) {
+                    long nw = Socket.sendfilen(data.socket, data.fd,
+                                               data.pos, data.end - data.pos, 0);
+                    if (nw < 0) {
+                        if (!(-nw == Status.EAGAIN)) {
+                            Socket.destroy(data.socket);
+                            data.socket = 0;
+                            return false;
+                        } else {
+                            // Break the loop and add the socket to poller.
+                            break;
+                        }
+                    } else {
+                        data.pos = data.pos + nw;
+                        if (data.pos >= data.end) {
+                            // Entire file has been sent
+                            Pool.destroy(data.fdpool);
+                            // Set back socket to blocking mode
+                            Socket.timeoutSet(data.socket, soTimeout * 1000);
+                            return true;
+                        }
+                    }
+                }
+            } catch (Exception e) {
+                log.error(sm.getString("endpoint.sendfile.error"), e);
+                return false;
+            }
+            // Add socket to the list. Newly added sockets will wait
+            // at most for pollTime before being polled
+            synchronized (this) {
+                addS.add(data);
+                this.notify();
+            }
+            return false;
+        }
+
+        /**
+         * Remove socket from the poller.
+         *
+         * @param data the sendfile data which should be removed
+         */
+        protected void remove(SendfileData data) {
+            int rv = Poll.remove(sendfilePollset, data.socket);
+            if (rv == Status.APR_SUCCESS) {
+                sendfileCount--;
+            }
+            sendfileData.remove(data);
+        }
+
+        /**
+         * The background thread that listens for incoming TCP/IP connections and
+         * hands them off to an appropriate processor.
+         */
+        public void run() {
+
+            // Loop until we receive a shutdown command
+            while (running) {
+
+                // Loop if endpoint is paused
+                while (paused) {
+                    try {
+                        Thread.sleep(1000);
+                    } catch (InterruptedException e) {
+                        // Ignore
+                    }
+                }
+
+                while (sendfileCount < 1 && addS.size() < 1) {
+                    try {
+                        synchronized (this) {
+                            this.wait();
+                        }
+                    } catch (InterruptedException e) {
+                        // Ignore
+                    }
+                }
+
+                try {
+                    // Add socket to the poller
+                    if (addS.size() > 0) {
+                        synchronized (this) {
+                            for (int i = (addS.size() - 1); i >= 0; i--) {
+                                SendfileData data = (SendfileData) addS.get(i);
+                                int rv = Poll.add(sendfilePollset, data.socket, Poll.APR_POLLOUT);
+                                if (rv == Status.APR_SUCCESS) {
+                                    sendfileData.put(new Long(data.socket), data);
+                                    sendfileCount++;
+                                } else {
+                                    log.warn(sm.getString("endpoint.sendfile.addfail", "" + rv, Error.strerror(rv)));
+                                    // Can't do anything: close the socket right away
+                                    Socket.destroy(data.socket);
+                                }
+                            }
+                            addS.clear();
+                        }
+                    }
+                    // Pool for the specified interval
+                    int rv = Poll.poll(sendfilePollset, pollTime, desc, false);
+                    if (rv > 0) {
+                        for (int n = 0; n < rv; n++) {
+                            // Get the sendfile state
+                            SendfileData state =
+                                (SendfileData) sendfileData.get(new Long(desc[n*2+1]));
+                            // Problem events
+                            if (((desc[n*2] & Poll.APR_POLLHUP) == Poll.APR_POLLHUP)
+                                    || ((desc[n*2] & Poll.APR_POLLERR) == Poll.APR_POLLERR)) {
+                                // Close socket and clear pool
+                                remove(state);
+                                // Destroy file descriptor pool, which should close the file
+                                // Close the socket, as the reponse would be incomplete
+                                Socket.destroy(state.socket);
+                                continue;
+                            }
+                            // Write some data using sendfile
+                            long nw = Socket.sendfilen(state.socket, state.fd,
+                                                       state.pos,
+                                                       state.end - state.pos, 0);
+                            if (nw < 0) {
+                                // Close socket and clear pool
+                                remove(state);
+                                // Close the socket, as the reponse would be incomplete
+                                // This will close the file too.
+                                Socket.destroy(state.socket);
+                                continue;
+                            }
+
+                            state.pos = state.pos + nw;
+                            if (state.pos >= state.end) {
+                                remove(state);
+                                if (state.keepAlive) {
+                                    // Destroy file descriptor pool, which should close the file
+                                    Pool.destroy(state.fdpool);
+                                    Socket.timeoutSet(state.socket, soTimeout * 1000);
+                                    // If all done hand this socket off to a worker for
+                                    // processing of further requests
+                                    getWorkerThread().assign(state.socket, false);
+                                } else {
+                                    // Close the socket since this is
+                                    // the end of not keep-alive request.
+                                    Socket.destroy(state.socket);
+                                }
+                            }
+                        }
+                    } else if (rv < 0) {
+                        int errn = -rv;
+                        /* Any non timeup or interrupted error is critical */
+                        if ((errn != Status.TIMEUP) && (errn != Status.EINTR)) {
+                            if (errn >  Status.APR_OS_START_USERERR) {
+                                errn -=  Status.APR_OS_START_USERERR;
+                            }
+                            log.error(sm.getString("endpoint.poll.fail", "" + errn, Error.strerror(errn)));
+                            // Handle poll critical failure
+                            synchronized (this) {
+                                destroy();
+                                init();
+                            }
+                            continue;
+                        }
+                    }
+                    /* TODO: See if we need to call the maintain for sendfile poller */
+                } catch (Throwable t) {
+                    log.error(sm.getString("endpoint.poll.error"), t);
+                }
+            }
+
+        }
+
+    }
+
+
+    // ------------------------------------------------ Handler Inner Interface
+
+
+    /**
+     * Bare bones interface used for socket processing. Per thread data is to be
+     * stored in the ThreadWithAttributes extra folders, or alternately in
+     * thread local fields.
+     */
+    public interface Handler {
+        public boolean process(long socket);
+    }
+
+
+    // ------------------------------------------------- WorkerStack Inner Class
+
+
+    public class WorkerStack {
+        
+        protected Worker[] workers = null;
+        protected int end = 0;
+        
+        public WorkerStack(int size) {
+            workers = new Worker[size];
+        }
+        
+        /** 
+         * Put the object into the queue.
+         * 
+         * @param   object      the object to be appended to the queue (first element). 
+         */
+        public void push(Worker worker) {
+            workers[end++] = worker;
+        }
+        
+        /**
+         * Get the first object out of the queue. Return null if the queue
+         * is empty. 
+         */
+        public Worker pop() {
+            if (end > 0) {
+                return workers[--end];
+            }
+            return null;
+        }
+        
+        /**
+         * Get the first object out of the queue, Return null if the queue
+         * is empty.
+         */
+        public Worker peek() {
+            return workers[end];
+        }
+        
+        /**
+         * Is the queue empty?
+         */
+        public boolean isEmpty() {
+            return (end == 0);
+        }
+        
+        /**
+         * How many elements are there in this queue?
+         */
+        public int size() {
+            return (end);
+        }
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/net/DefaultServerSocketFactory.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/net/DefaultServerSocketFactory.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/net/DefaultServerSocketFactory.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,69 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.net;
+
+import java.io.*;
+import java.net.*;
+
+/**
+ * Default server socket factory. Doesn't do much except give us
+ * plain ol' server sockets.
+ *
+ * @author db at eng.sun.com
+ * @author Harish Prabandham
+ */
+
+// Default implementation of server sockets.
+
+//
+// WARNING: Some of the APIs in this class are used by J2EE. 
+// Please talk to harishp at eng.sun.com before making any changes.
+//
+class DefaultServerSocketFactory extends ServerSocketFactory {
+
+    DefaultServerSocketFactory () {
+        /* NOTHING */
+    }
+
+    public ServerSocket createSocket (int port)
+    throws IOException {
+        return  new ServerSocket (port);
+    }
+
+    public ServerSocket createSocket (int port, int backlog)
+    throws IOException {
+        return new ServerSocket (port, backlog);
+    }
+
+    public ServerSocket createSocket (int port, int backlog,
+        InetAddress ifAddress)
+    throws IOException {
+        return new ServerSocket (port, backlog, ifAddress);
+    }
+ 
+    public Socket acceptSocket(ServerSocket socket)
+ 	throws IOException {
+ 	return socket.accept();
+    }
+ 
+    public void handshake(Socket sock)
+ 	throws IOException {
+ 	; // NOOP
+    }
+ 	    
+        
+ }

Added: branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/net/LeaderFollowerWorkerThread.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/net/LeaderFollowerWorkerThread.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/net/LeaderFollowerWorkerThread.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,86 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.net;
+
+import java.net.Socket;
+import org.apache.tomcat.util.threads.ThreadPoolRunnable;
+
+/*
+ * I switched the threading model here.
+ *
+ * We used to have a "listener" thread and a "connection"
+ * thread, this results in code simplicity but also a needless
+ * thread switch.
+ *
+ * Instead I am now using a pool of threads, all the threads are
+ * simmetric in their execution and no thread switch is needed.
+ */
+class LeaderFollowerWorkerThread implements ThreadPoolRunnable {
+    /* This is not a normal Runnable - it gets attached to an existing
+       thread, runs and when run() ends - the thread keeps running.
+
+       It's better to keep the name ThreadPoolRunnable - avoid confusion.
+       We also want to use per/thread data and avoid sync wherever possible.
+    */
+    PoolTcpEndpoint endpoint;
+    
+    public LeaderFollowerWorkerThread(PoolTcpEndpoint endpoint) {
+        this.endpoint = endpoint;
+    }
+
+    public Object[] getInitData() {
+        // no synchronization overhead, but 2 array access 
+        Object obj[]=new Object[2];
+        obj[1]= endpoint.getConnectionHandler().init();
+        obj[0]=new TcpConnection();
+        return obj;
+    }
+    
+    public void runIt(Object perThrData[]) {
+
+        // Create per-thread cache
+        if (endpoint.isRunning()) {
+
+            // Loop if endpoint is paused
+            while (endpoint.isPaused()) {
+                try {
+                    Thread.sleep(1000);
+                } catch (InterruptedException e) {
+                    // Ignore
+                }
+            }
+
+            // Accept a new connection
+            Socket s = null;
+            try {
+                s = endpoint.acceptSocket();
+            } finally {
+                // Continue accepting on another thread...
+                if (endpoint.isRunning()) {
+                    endpoint.tp.runIt(this);
+                }
+            }
+
+            // Process the connection
+            if (null != s) {
+                endpoint.processSocket(s, (TcpConnection) perThrData[0], (Object[]) perThrData[1]);
+            }
+
+        }
+    }
+    
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/net/MasterSlaveWorkerThread.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/net/MasterSlaveWorkerThread.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/net/MasterSlaveWorkerThread.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,150 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.net;
+
+import java.net.Socket;
+
+import org.apache.tomcat.util.threads.ThreadWithAttributes;
+
+/**
+ * Regular master slave thread pool. Slave threads will wait for work.
+ */
+class MasterSlaveWorkerThread implements Runnable {
+
+    protected PoolTcpEndpoint endpoint;
+    protected String threadName;
+    protected boolean stopped = false;
+    private Object threadSync = new Object();
+    private Thread thread = null;
+    private boolean available = false;
+    private Socket socket = null;
+    private TcpConnection con = new TcpConnection();
+    private Object[] threadData = null;
+
+    
+    public MasterSlaveWorkerThread(PoolTcpEndpoint endpoint, String threadName) {
+        this.endpoint = endpoint;
+        this.threadName = threadName;
+    }
+
+
+    /**
+     * Process an incoming TCP/IP connection on the specified socket.  Any
+     * exception that occurs during processing must be logged and swallowed.
+     * <b>NOTE</b>:  This method is called from our Connector's thread.  We
+     * must assign it to our own thread so that multiple simultaneous
+     * requests can be handled.
+     *
+     * @param socket TCP socket to process
+     */
+    synchronized void assign(Socket socket) {
+
+        // Wait for the Processor to get the previous Socket
+        while (available) {
+            try {
+                wait();
+            } catch (InterruptedException e) {
+            }
+        }
+
+        // Store the newly available Socket and notify our thread
+        this.socket = socket;
+        available = true;
+        notifyAll();
+
+    }
+
+    
+    /**
+     * Await a newly assigned Socket from our Connector, or <code>null</code>
+     * if we are supposed to shut down.
+     */
+    private synchronized Socket await() {
+
+        // Wait for the Connector to provide a new Socket
+        while (!available) {
+            try {
+                wait();
+            } catch (InterruptedException e) {
+            }
+        }
+
+        // Notify the Connector that we have received this Socket
+        Socket socket = this.socket;
+        available = false;
+        notifyAll();
+
+        return (socket);
+
+    }
+
+
+
+    /**
+     * The background thread that listens for incoming TCP/IP connections and
+     * hands them off to an appropriate processor.
+     */
+    public void run() {
+
+        // Process requests until we receive a shutdown signal
+        while (!stopped) {
+
+            // Wait for the next socket to be assigned
+            Socket socket = await();
+            if (socket == null)
+                continue;
+
+            // Process the request from this socket
+            endpoint.processSocket(socket, con, threadData);
+
+            // Finish up this request
+            endpoint.recycleWorkerThread(this);
+
+        }
+
+        // Tell threadStop() we have shut ourselves down successfully
+        synchronized (threadSync) {
+            threadSync.notifyAll();
+        }
+
+    }
+
+
+    /**
+     * Start the background processing thread.
+     */
+    public void start() {
+        threadData = endpoint.getConnectionHandler().init();
+        thread = new ThreadWithAttributes(null, this);
+        thread.setName(threadName);
+        thread.setDaemon(true);
+        thread.start();
+    }
+
+
+    /**
+     * Stop the background processing thread.
+     */
+    public void stop() {
+        stopped = true;
+        assign(null);
+        thread = null;
+        threadData = null;
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/net/PoolTcpEndpoint.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/net/PoolTcpEndpoint.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/net/PoolTcpEndpoint.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,683 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.net;
+
+import java.io.IOException;
+import java.io.InterruptedIOException;
+import java.net.BindException;
+import java.net.InetAddress;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.net.SocketException;
+import java.security.AccessControlException;
+import java.util.Stack;
+import java.util.Vector;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.tomcat.util.res.StringManager;
+import org.apache.tomcat.util.threads.ThreadPool;
+import org.apache.tomcat.util.threads.ThreadPoolRunnable;
+
+/* Similar with MPM module in Apache2.0. Handles all the details related with
+   "tcp server" functionality - thread management, accept policy, etc.
+   It should do nothing more - as soon as it get a socket ( and all socket options
+   are set, etc), it just handle the stream to ConnectionHandler.processConnection. (costin)
+*/
+
+
+
+/**
+ * Handle incoming TCP connections.
+ *
+ * This class implement a simple server model: one listener thread accepts on a socket and
+ * creates a new worker thread for each incoming connection.
+ *
+ * More advanced Endpoints will reuse the threads, use queues, etc.
+ *
+ * @author James Duncan Davidson [duncan at eng.sun.com]
+ * @author Jason Hunter [jch at eng.sun.com]
+ * @author James Todd [gonzo at eng.sun.com]
+ * @author Costin at eng.sun.com
+ * @author Gal Shachor [shachor at il.ibm.com]
+ * @author Yoav Shapira <yoavs at apache.org>
+ */
+public class PoolTcpEndpoint implements Runnable { // implements Endpoint {
+
+    static Log log=LogFactory.getLog(PoolTcpEndpoint.class );
+
+    private StringManager sm = 
+        StringManager.getManager("org.apache.tomcat.util.net.res");
+
+    private static final int BACKLOG = 100;
+    private static final int TIMEOUT = 1000;
+
+    private final Object threadSync = new Object();
+
+    private int backlog = BACKLOG;
+    private int serverTimeout = TIMEOUT;
+
+    private InetAddress inet;
+    private int port;
+
+    private ServerSocketFactory factory;
+    private ServerSocket serverSocket;
+
+    private volatile boolean running = false;
+    private volatile boolean paused = false;
+    private boolean initialized = false;
+    private boolean reinitializing = false;
+    static final int debug=0;
+
+    protected boolean tcpNoDelay=false;
+    protected int linger=100;
+    protected int socketTimeout=-1;
+    private boolean lf = true;
+
+    
+    // ------ Leader follower fields
+
+    
+    TcpConnectionHandler handler;
+    ThreadPoolRunnable listener;
+    ThreadPool tp;
+
+    
+    // ------ Master slave fields
+
+    /* The background thread. */
+    private Thread thread = null;
+    /* Available processors. */
+    private Stack workerThreads = new Stack();
+    private int curThreads = 0;
+    private int maxThreads = 20;
+    /* All processors which have been created. */
+    private Vector created = new Vector();
+
+    
+    public PoolTcpEndpoint() {
+	tp = new ThreadPool();
+    }
+
+    public PoolTcpEndpoint( ThreadPool tp ) {
+        this.tp=tp;
+    }
+
+    // -------------------- Configuration --------------------
+
+    public void setMaxThreads(int maxThreads) {
+	if( maxThreads > 0)
+	    tp.setMaxThreads(maxThreads);
+    }
+
+    public int getMaxThreads() {
+        return tp.getMaxThreads();
+    }
+
+    public void setMaxSpareThreads(int maxThreads) {
+	if(maxThreads > 0) 
+	    tp.setMaxSpareThreads(maxThreads);
+    }
+
+    public int getMaxSpareThreads() {
+        return tp.getMaxSpareThreads();
+    }
+
+    public void setMinSpareThreads(int minThreads) {
+	if(minThreads > 0) 
+	    tp.setMinSpareThreads(minThreads);
+    }
+
+    public int getMinSpareThreads() {
+        return tp.getMinSpareThreads();
+    }
+
+    public void setThreadPriority(int threadPriority) {
+      tp.setThreadPriority(threadPriority);
+    }
+
+    public int getThreadPriority() {
+      return tp.getThreadPriority();
+    }
+
+    public int getPort() {
+        return port;
+    }
+
+    public void setPort(int port ) {
+        this.port=port;
+    }
+
+    public InetAddress getAddress() {
+	    return inet;
+    }
+
+    public void setAddress(InetAddress inet) {
+	    this.inet=inet;
+    }
+
+    public void setServerSocket(ServerSocket ss) {
+	    serverSocket = ss;
+    }
+
+    public void setServerSocketFactory(  ServerSocketFactory factory ) {
+	    this.factory=factory;
+    }
+
+   ServerSocketFactory getServerSocketFactory() {
+ 	    return factory;
+   }
+
+    public void setConnectionHandler( TcpConnectionHandler handler ) {
+    	this.handler=handler;
+    }
+
+    public TcpConnectionHandler getConnectionHandler() {
+	    return handler;
+    }
+
+    public boolean isRunning() {
+	return running;
+    }
+    
+    public boolean isPaused() {
+	return paused;
+    }
+    
+    /**
+     * Allows the server developer to specify the backlog that
+     * should be used for server sockets. By default, this value
+     * is 100.
+     */
+    public void setBacklog(int backlog) {
+	if( backlog>0)
+	    this.backlog = backlog;
+    }
+
+    public int getBacklog() {
+        return backlog;
+    }
+
+    /**
+     * Sets the timeout in ms of the server sockets created by this
+     * server. This method allows the developer to make servers
+     * more or less responsive to having their server sockets
+     * shut down.
+     *
+     * <p>By default this value is 1000ms.
+     */
+    public void setServerTimeout(int timeout) {
+	this.serverTimeout = timeout;
+    }
+
+    public boolean getTcpNoDelay() {
+        return tcpNoDelay;
+    }
+    
+    public void setTcpNoDelay( boolean b ) {
+	tcpNoDelay=b;
+    }
+
+    public int getSoLinger() {
+        return linger;
+    }
+    
+    public void setSoLinger( int i ) {
+	linger=i;
+    }
+
+    public int getSoTimeout() {
+        return socketTimeout;
+    }
+    
+    public void setSoTimeout( int i ) {
+	socketTimeout=i;
+    }
+    
+    public int getServerSoTimeout() {
+        return serverTimeout;
+    }  
+    
+    public void setServerSoTimeout( int i ) {
+	serverTimeout=i;
+    }
+
+    public String getStrategy() {
+        if (lf) {
+            return "lf";
+        } else {
+            return "ms";
+        }
+    }
+    
+    public void setStrategy(String strategy) {
+        if ("ms".equals(strategy)) {
+            lf = false;
+        } else {
+            lf = true;
+        }
+    }
+
+    public int getCurrentThreadCount() {
+        return curThreads;
+    }
+    
+    public int getCurrentThreadsBusy() {
+        return curThreads - workerThreads.size();
+    }
+    
+    // -------------------- Public methods --------------------
+
+    public void initEndpoint() throws IOException, InstantiationException {
+        try {
+            if(factory==null)
+                factory=ServerSocketFactory.getDefault();
+            if(serverSocket==null) {
+                try {
+                    if (inet == null) {
+                        serverSocket = factory.createSocket(port, backlog);
+                    } else {
+                        serverSocket = factory.createSocket(port, backlog, inet);
+                    }
+                } catch ( BindException be ) {
+                    throw new BindException(be.getMessage() + ":" + port);
+                }
+            }
+            if( serverTimeout >= 0 )
+                serverSocket.setSoTimeout( serverTimeout );
+        } catch( IOException ex ) {
+            throw ex;
+        } catch( InstantiationException ex1 ) {
+            throw ex1;
+        }
+        initialized = true;
+    }
+    
+    public void startEndpoint() throws IOException, InstantiationException {
+        if (!initialized) {
+            initEndpoint();
+        }
+        if (lf) {
+            tp.start();
+        }
+        running = true;
+        paused = false;
+        if (lf) {
+            listener = new LeaderFollowerWorkerThread(this);
+            tp.runIt(listener);
+        } else {
+            maxThreads = getMaxThreads();
+            threadStart();
+        }
+    }
+
+    public void pauseEndpoint() {
+        if (running && !paused) {
+            paused = true;
+            unlockAccept();
+        }
+    }
+
+    public void resumeEndpoint() {
+        if (running) {
+            paused = false;
+        }
+    }
+
+    public void stopEndpoint() {
+        if (running) {
+            if (lf) {
+                tp.shutdown();
+            }
+            running = false;
+            if (serverSocket != null) {
+                closeServerSocket();
+            }
+            if (!lf) {
+                threadStop();
+            }
+            initialized=false ;
+        }
+    }
+
+    protected void closeServerSocket() {
+        if (!paused)
+            unlockAccept();
+        try {
+            if( serverSocket!=null)
+                serverSocket.close();
+        } catch(Exception e) {
+            log.error(sm.getString("endpoint.err.close"), e);
+        }
+        serverSocket = null;
+    }
+
+    protected void unlockAccept() {
+        Socket s = null;
+        try {
+            // Need to create a connection to unlock the accept();
+            if (inet == null) {
+                s = new Socket("127.0.0.1", port);
+            } else {
+                s = new Socket(inet, port);
+                    // setting soLinger to a small value will help shutdown the
+                    // connection quicker
+                s.setSoLinger(true, 0);
+            }
+        } catch(Exception e) {
+            if (log.isDebugEnabled()) {
+                log.debug(sm.getString("endpoint.debug.unlock", "" + port), e);
+            }
+        } finally {
+            if (s != null) {
+                try {
+                    s.close();
+                } catch (Exception e) {
+                    // Ignore
+                }
+            }
+        }
+    }
+
+    // -------------------- Private methods
+
+    Socket acceptSocket() {
+        if( !running || serverSocket==null ) return null;
+
+        Socket accepted = null;
+
+    	try {
+            if(factory==null) {
+                accepted = serverSocket.accept();
+            } else {
+                accepted = factory.acceptSocket(serverSocket);
+            }
+            if (null == accepted) {
+                log.warn(sm.getString("endpoint.warn.nullSocket"));
+            } else {
+                if (!running) {
+                    accepted.close();  // rude, but unlikely!
+                    accepted = null;
+                } else if (factory != null) {
+                    factory.initSocket( accepted );
+                }
+            }
+        }
+        catch(InterruptedIOException iioe) {
+            // normal part -- should happen regularly so
+            // that the endpoint can release if the server
+            // is shutdown.
+        }
+        catch (AccessControlException ace) {
+            // When using the Java SecurityManager this exception
+            // can be thrown if you are restricting access to the
+            // socket with SocketPermission's.
+            // Log the unauthorized access and continue
+            String msg = sm.getString("endpoint.warn.security",
+                                      serverSocket, ace);
+            log.warn(msg);
+        }
+        catch (IOException e) {
+
+            String msg = null;
+
+            if (running) {
+                msg = sm.getString("endpoint.err.nonfatal",
+                        serverSocket, e);
+                log.error(msg, e);
+            }
+
+            if (accepted != null) {
+                try {
+                    accepted.close();
+                } catch(Throwable ex) {
+                    msg = sm.getString("endpoint.err.nonfatal",
+                                       accepted, ex);
+                    log.warn(msg, ex);
+                }
+                accepted = null;
+            }
+
+            if( ! running ) return null;
+            reinitializing = true;
+            // Restart endpoint when getting an IOException during accept
+            synchronized (threadSync) {
+                if (reinitializing) {
+                    reinitializing = false;
+                    // 1) Attempt to close server socket
+                    closeServerSocket();
+                    initialized = false;
+                    // 2) Reinit endpoint (recreate server socket)
+                    try {
+                        msg = sm.getString("endpoint.warn.reinit");
+                        log.warn(msg);
+                        initEndpoint();
+                    } catch (Throwable t) {
+                        msg = sm.getString("endpoint.err.nonfatal",
+                                           serverSocket, t);
+                        log.error(msg, t);
+                    }
+                    // 3) If failed, attempt to restart endpoint
+                    if (!initialized) {
+                        msg = sm.getString("endpoint.warn.restart");
+                        log.warn(msg);
+                        try {
+                            stopEndpoint();
+                            initEndpoint();
+                            startEndpoint();
+                        } catch (Throwable t) {
+                            msg = sm.getString("endpoint.err.fatal",
+                                               serverSocket, t);
+                            log.error(msg, t);
+                        }
+                        // Current thread is now invalid: kill it
+                        throw new ThreadDeath();
+                    }
+                }
+            }
+
+        }
+
+        return accepted;
+    }
+
+    void setSocketOptions(Socket socket)
+        throws SocketException {
+        if(linger >= 0 ) 
+            socket.setSoLinger( true, linger);
+        if( tcpNoDelay )
+            socket.setTcpNoDelay(tcpNoDelay);
+        if( socketTimeout > 0 )
+            socket.setSoTimeout( socketTimeout );
+    }
+
+    
+    void processSocket(Socket s, TcpConnection con, Object[] threadData) {
+        // Process the connection
+        int step = 1;
+        try {
+            
+            // 1: Set socket options: timeout, linger, etc
+            setSocketOptions(s);
+            
+            // 2: SSL handshake
+            step = 2;
+            if (getServerSocketFactory() != null) {
+                getServerSocketFactory().handshake(s);
+            }
+            
+            // 3: Process the connection
+            step = 3;
+            con.setEndpoint(this);
+            con.setSocket(s);
+            getConnectionHandler().processConnection(con, threadData);
+            
+        } catch (SocketException se) {
+            log.debug(sm.getString("endpoint.err.socket", s.getInetAddress()),
+                    se);
+            // Try to close the socket
+            try {
+                s.close();
+            } catch (IOException e) {
+            }
+        } catch (Throwable t) {
+            if (step == 2) {
+                if (log.isDebugEnabled()) {
+                    log.debug(sm.getString("endpoint.err.handshake"), t);
+                }
+            } else {
+                log.error(sm.getString("endpoint.err.unexpected"), t);
+            }
+            // Try to close the socket
+            try {
+                s.close();
+            } catch (IOException e) {
+            }
+        } finally {
+            if (con != null) {
+                con.recycle();
+            }
+        }
+    }
+    
+
+    // -------------------------------------------------- Master Slave Methods
+
+
+    /**
+     * Create (or allocate) and return an available processor for use in
+     * processing a specific HTTP request, if possible.  If the maximum
+     * allowed processors have already been created and are in use, return
+     * <code>null</code> instead.
+     */
+    private MasterSlaveWorkerThread createWorkerThread() {
+
+        synchronized (workerThreads) {
+            if (workerThreads.size() > 0) {
+                return ((MasterSlaveWorkerThread) workerThreads.pop());
+            }
+            if ((maxThreads > 0) && (curThreads < maxThreads)) {
+                return (newWorkerThread());
+            } else {
+                if (maxThreads < 0) {
+                    return (newWorkerThread());
+                } else {
+                    return (null);
+                }
+            }
+        }
+
+    }
+
+    
+    /**
+     * Create and return a new processor suitable for processing HTTP
+     * requests and returning the corresponding responses.
+     */
+    private MasterSlaveWorkerThread newWorkerThread() {
+
+        MasterSlaveWorkerThread workerThread = 
+            new MasterSlaveWorkerThread(this, tp.getName() + "-" + (++curThreads));
+        workerThread.start();
+        created.addElement(workerThread);
+        return (workerThread);
+
+    }
+
+
+    /**
+     * Recycle the specified Processor so that it can be used again.
+     *
+     * @param processor The processor to be recycled
+     */
+    void recycleWorkerThread(MasterSlaveWorkerThread workerThread) {
+        workerThreads.push(workerThread);
+    }
+
+    
+    /**
+     * The background thread that listens for incoming TCP/IP connections and
+     * hands them off to an appropriate processor.
+     */
+    public void run() {
+
+        // Loop until we receive a shutdown command
+        while (running) {
+
+            // Loop if endpoint is paused
+            while (paused) {
+                try {
+                    Thread.sleep(1000);
+                } catch (InterruptedException e) {
+                    // Ignore
+                }
+            }
+
+            // Allocate a new worker thread
+            MasterSlaveWorkerThread workerThread = createWorkerThread();
+            if (workerThread == null) {
+                try {
+                    // Wait a little for load to go down: as a result, 
+                    // no accept will be made until the concurrency is
+                    // lower than the specified maxThreads, and current
+                    // connections will wait for a little bit instead of
+                    // failing right away.
+                    Thread.sleep(100);
+                } catch (InterruptedException e) {
+                    // Ignore
+                }
+                continue;
+            }
+            
+            // Accept the next incoming connection from the server socket
+            Socket socket = acceptSocket();
+
+            // Hand this socket off to an appropriate processor
+            workerThread.assign(socket);
+
+            // The processor will recycle itself when it finishes
+
+        }
+
+        // Notify the threadStop() method that we have shut ourselves down
+        synchronized (threadSync) {
+            threadSync.notifyAll();
+        }
+
+    }
+
+
+    /**
+     * Start the background processing thread.
+     */
+    private void threadStart() {
+        thread = new Thread(this, tp.getName());
+        thread.setPriority(getThreadPriority());
+        thread.setDaemon(true);
+        thread.start();
+    }
+
+
+    /**
+     * Stop the background processing thread.
+     */
+    private void threadStop() {
+        thread = null;
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/net/SSLImplementation.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/net/SSLImplementation.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/net/SSLImplementation.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,86 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.net;
+
+import java.net.Socket;
+
+/* SSLImplementation:
+
+   Abstract factory and base class for all SSL implementations.
+
+   @author EKR
+*/
+abstract public class SSLImplementation {
+    private static org.apache.commons.logging.Log logger =
+        org.apache.commons.logging.LogFactory.getLog(SSLImplementation.class);
+
+    // The default implementations in our search path
+    private static final String PureTLSImplementationClass=
+	"org.apache.tomcat.util.net.puretls.PureTLSImplementation";
+    private static final String JSSEImplementationClass=
+	"org.apache.tomcat.util.net.jsse.JSSEImplementation";
+    
+    private static final String[] implementations=
+    {
+        PureTLSImplementationClass,
+        JSSEImplementationClass
+    };
+
+    public static SSLImplementation getInstance() throws ClassNotFoundException
+    {
+	for(int i=0;i<implementations.length;i++){
+	    try {
+               SSLImplementation impl=
+		    getInstance(implementations[i]);
+		return impl;
+	    } catch (Exception e) {
+		if(logger.isTraceEnabled()) 
+		    logger.trace("Error creating " + implementations[i],e);
+	    }
+	}
+
+	// If we can't instantiate any of these
+	throw new ClassNotFoundException("Can't find any SSL implementation");
+    }
+
+    public static SSLImplementation getInstance(String className)
+	throws ClassNotFoundException
+    {
+	if(className==null) return getInstance();
+
+	try {
+	    // Workaround for the J2SE 1.4.x classloading problem (under Solaris).
+	    // Class.forName(..) fails without creating class using new.
+	    // This is an ugly workaround. 
+	    if( JSSEImplementationClass.equals(className) ) {
+		return new org.apache.tomcat.util.net.jsse.JSSEImplementation();
+	    }
+	    Class clazz=Class.forName(className);
+	    return (SSLImplementation)clazz.newInstance();
+	} catch (Exception e){
+	    if(logger.isDebugEnabled())
+		logger.debug("Error loading SSL Implementation "
+			     +className, e);
+	    throw new ClassNotFoundException("Error loading SSL Implementation "
+				      +className+ " :" +e.toString());
+	}
+    }
+
+    abstract public String getImplementationName();
+    abstract public ServerSocketFactory getServerSocketFactory();
+    abstract public SSLSupport getSSLSupport(Socket sock);
+}    

Added: branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/net/SSLSupport.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/net/SSLSupport.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/net/SSLSupport.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,127 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.net;
+
+import java.io.IOException;
+
+/* SSLSupport
+
+   Interface for SSL-specific functions
+
+   @author EKR
+*/
+
+public interface SSLSupport {
+    /**
+     * The Request attribute key for the cipher suite.
+     */
+    public static final String CIPHER_SUITE_KEY = "javax.servlet.request.cipher_suite";
+
+    /**
+     * The Request attribute key for the key size.
+     */
+    public static final String KEY_SIZE_KEY = "javax.servlet.request.key_size";
+
+    /**
+     * The Request attribute key for the client certificate chain.
+     */
+    public static final String CERTIFICATE_KEY = "javax.servlet.request.X509Certificate";
+
+    /**
+     * The Request attribute key for the session id.
+     * This one is a Tomcat extension to the Servlet spec.
+     */
+    public static final String SESSION_ID_KEY = "javax.servlet.request.ssl_session";
+
+    /**
+     * A mapping table to determine the number of effective bits in the key
+     * when using a cipher suite containing the specified cipher name.  The
+     * underlying data came from the TLS Specification (RFC 2246), Appendix C.
+     */
+     static final CipherData ciphers[] = {
+        new CipherData("_WITH_NULL_", 0),
+        new CipherData("_WITH_IDEA_CBC_", 128),
+        new CipherData("_WITH_RC2_CBC_40_", 40),
+        new CipherData("_WITH_RC4_40_", 40),
+        new CipherData("_WITH_RC4_128_", 128),
+        new CipherData("_WITH_DES40_CBC_", 40),
+        new CipherData("_WITH_DES_CBC_", 56),
+        new CipherData("_WITH_3DES_EDE_CBC_", 168)
+    };
+
+    /**
+     * The cipher suite being used on this connection.
+     */
+    public String getCipherSuite() throws IOException;
+
+    /**
+     * The client certificate chain (if any).
+     */
+    public Object[] getPeerCertificateChain()
+        throws IOException;
+
+    /**
+     * The client certificate chain (if any).
+     * @param force If <code>true</code>, then re-negotiate the 
+     *              connection if necessary.
+     */
+    public Object[] getPeerCertificateChain(boolean force)
+        throws IOException;
+
+    /**
+     * Get the keysize.
+     *
+     * What we're supposed to put here is ill-defined by the
+     * Servlet spec (S 4.7 again). There are at least 4 potential
+     * values that might go here:
+     *
+     * (a) The size of the encryption key
+     * (b) The size of the MAC key
+     * (c) The size of the key-exchange key
+     * (d) The size of the signature key used by the server
+     *
+     * Unfortunately, all of these values are nonsensical.
+     **/
+    public Integer getKeySize()
+        throws IOException;
+
+    /**
+     * The current session Id.
+     */
+    public String getSessionId()
+        throws IOException;
+    /**
+     * Simple data class that represents the cipher being used, along with the
+     * corresponding effective key size.  The specified phrase must appear in the
+     * name of the cipher suite to be recognized.
+     */
+    
+    final class CipherData {
+    
+        public String phrase = null;
+    
+        public int keySize = 0;
+    
+        public CipherData(String phrase, int keySize) {
+            this.phrase = phrase;
+            this.keySize = keySize;
+        }
+    
+    }
+    
+}
+

Added: branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/net/ServerSocketFactory.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/net/ServerSocketFactory.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/net/ServerSocketFactory.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,172 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.net;
+
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.util.Hashtable;
+
+/**
+ * This class creates server sockets.  It may be subclassed by other
+ * factories, which create particular types of server sockets.  This
+ * provides a general framework for the addition of public socket-level
+ * functionality.  It it is the server side analogue of a socket factory,
+ * and similarly provides a way to capture a variety of policies related
+ * to the sockets being constructed.
+ *
+ * <P> Like socket factories, Server Socket factory instances have two
+ * categories of methods.  First are methods used to create sockets.
+ * Second are methods which set properties used in the production of
+ * sockets, such as networking options.  There is also an environment
+ * specific default server socket factory; frameworks will often use
+ * their own customized factory.
+ * 
+ * <P><hr><em> It may be desirable to move this interface into the
+ * <b>java.net</b> package, so that is not an extension but the preferred
+ * interface.  Should this be serializable, making it a JavaBean which can
+ * be saved along with its networking configuration?
+ * </em>   
+ *
+ * @author db at eng.sun.com
+ * @author Harish Prabandham
+ */
+public abstract class ServerSocketFactory implements Cloneable {
+
+    //
+    // NOTE:  JDK 1.1 bug in class GC, this can get collected
+    // even though it's always accessible via getDefault().
+    //
+
+    private static ServerSocketFactory theFactory;
+    protected Hashtable attributes=new Hashtable();
+
+    /**
+     * Constructor is used only by subclasses.
+     */
+
+    protected ServerSocketFactory () {
+        /* NOTHING */
+    }
+
+    /** General mechanism to pass attributes from the
+     *  ServerConnector to the socket factory.
+     *
+     *  Note that the "prefered" mechanism is to
+     *  use bean setters and explicit methods, but
+     *  this allows easy configuration via server.xml
+     *  or simple Properties
+     */
+    public void setAttribute( String name, Object value ) {
+	if( name!=null && value !=null)
+	    attributes.put( name, value );
+    }
+    
+    /**
+     * Returns a copy of the environment's default socket factory.
+     */
+    public static synchronized ServerSocketFactory getDefault () {
+        //
+        // optimize typical case:  no synch needed
+        //
+
+        if (theFactory == null) {
+            //
+            // Different implementations of this method could
+            // work rather differently.  For example, driving
+            // this from a system property, or using a different
+            // implementation than JavaSoft's.
+            //
+
+            theFactory = new DefaultServerSocketFactory ();
+        }
+
+        try {
+            return (ServerSocketFactory) theFactory.clone ();
+        } catch (CloneNotSupportedException e) {
+            throw new RuntimeException (e.getMessage ());
+        }
+    }
+
+    /**
+     * Returns a server socket which uses all network interfaces on
+     * the host, and is bound to a the specified port.  The socket is
+     * configured with the socket options (such as accept timeout)
+     * given to this factory.
+     *
+     * @param port the port to listen to
+     * @exception IOException for networking errors
+     * @exception InstantiationException for construction errors
+     */
+    public abstract ServerSocket createSocket (int port)
+    throws IOException, InstantiationException;
+
+    /**
+     * Returns a server socket which uses all network interfaces on
+     * the host, is bound to a the specified port, and uses the 
+     * specified connection backlog.  The socket is configured with
+     * the socket options (such as accept timeout) given to this factory.
+     *
+     * @param port the port to listen to
+     * @param backlog how many connections are queued
+     * @exception IOException for networking errors
+     * @exception InstantiationException for construction errors
+     */
+
+    public abstract ServerSocket createSocket (int port, int backlog)
+    throws IOException, InstantiationException;
+
+    /**
+     * Returns a server socket which uses only the specified network
+     * interface on the local host, is bound to a the specified port,
+     * and uses the specified connection backlog.  The socket is configured
+     * with the socket options (such as accept timeout) given to this factory.
+     *
+     * @param port the port to listen to
+     * @param backlog how many connections are queued
+     * @param ifAddress the network interface address to use
+     * @exception IOException for networking errors
+     * @exception InstantiationException for construction errors
+     */
+
+    public abstract ServerSocket createSocket (int port,
+        int backlog, InetAddress ifAddress)
+    throws IOException, InstantiationException;
+
+    public void initSocket( Socket s ) {
+    }
+ 
+     /**
+       Wrapper function for accept(). This allows us to trap and
+       translate exceptions if necessary
+ 
+       @exception IOException;
+     */ 
+     public abstract Socket acceptSocket(ServerSocket socket)
+ 	throws IOException;
+ 
+     /**
+       Extra function to initiate the handshake. Sometimes necessary
+       for SSL
+ 
+       @exception IOException;
+     */ 
+     public abstract void handshake(Socket sock)
+ 	throws IOException;
+}
+

Added: branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/net/TcpConnection.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/net/TcpConnection.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/net/TcpConnection.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,109 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.net;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.Socket;
+
+/**
+ *
+ */
+public class TcpConnection  { // implements Endpoint {
+    /**
+     * Maxium number of times to clear the socket input buffer.
+     */
+    static  int MAX_SHUTDOWN_TRIES=20;
+
+    public TcpConnection() {
+    }
+
+    // -------------------- Properties --------------------
+
+    PoolTcpEndpoint endpoint;
+    Socket socket;
+
+    public static void setMaxShutdownTries(int mst) {
+	MAX_SHUTDOWN_TRIES = mst;
+    }
+    public void setEndpoint(PoolTcpEndpoint endpoint) {
+	this.endpoint = endpoint;
+    }
+
+    public PoolTcpEndpoint getEndpoint() {
+	return endpoint;
+    }
+
+    public void setSocket(Socket socket) {
+	this.socket=socket;
+    }
+
+    public Socket getSocket() {
+	return socket;
+    }
+
+    public void recycle() {
+        endpoint = null;
+        socket = null;
+    }
+
+    // Another frequent repetition
+    public static int readLine(InputStream in, byte[] b, int off, int len)
+	throws IOException
+    {
+	if (len <= 0) {
+	    return 0;
+	}
+	int count = 0, c;
+
+	while ((c = in.read()) != -1) {
+	    b[off++] = (byte)c;
+	    count++;
+	    if (c == '\n' || count == len) {
+		break;
+	    }
+	}
+	return count > 0 ? count : -1;
+    }
+
+    
+    // Usefull stuff - avoid having it replicated everywhere
+    public static void shutdownInput(Socket socket)
+	throws IOException
+    {
+	try {
+	    InputStream is = socket.getInputStream();
+	    int available = is.available ();
+	    int count=0;
+	    
+	    // XXX on JDK 1.3 just socket.shutdownInput () which
+	    // was added just to deal with such issues.
+	    
+	    // skip any unread (bogus) bytes
+	    while (available > 0 && count++ < MAX_SHUTDOWN_TRIES) {
+		is.skip (available);
+		available = is.available();
+	    }
+	}catch(NullPointerException npe) {
+	    // do nothing - we are just cleaning up, this is
+	    // a workaround for Netscape \n\r in POST - it is supposed
+	    // to be ignored
+	}
+    }
+}
+
+

Added: branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/net/TcpConnectionHandler.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/net/TcpConnectionHandler.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/net/TcpConnectionHandler.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,65 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.net;
+
+
+/**
+ * This interface will be implemented by any object that
+ * uses TcpConnections. It is supported by the pool tcp
+ * connection manager and should be supported by future
+ * managers.
+ * The goal is to decouple the connection handler from
+ * the thread, socket and pooling complexity.
+ */
+public interface TcpConnectionHandler {
+    
+    /** Add informations about the a "controler" object
+     *  specific to the server. In tomcat it will be a
+     *  ContextManager.
+     *  @deprecated This has nothing to do with TcpHandling,
+     *  was used as a workaround
+     */
+    public void setServer(Object manager);
+
+    
+    /** Used to pass config informations to the handler.
+     *
+     *  @deprecated This has nothing to do with Tcp,
+     *    was used as a workaround.
+     */
+    public void setAttribute(String name, Object value );
+    
+    /** Called before the call to processConnection.
+     *  If the thread is reused, init() should be called once per thread.
+     *
+     *  It may look strange, but it's a _very_ good way to avoid synchronized
+     *  methods and keep per thread data.
+     *
+     *  Assert: the object returned from init() will be passed to
+     *  all processConnection() methods happening in the same thread.
+     * 
+     */
+    public Object[] init( );
+
+    /**
+     *  Assert: connection!=null
+     *  Assert: connection.getSocket() != null
+     *  Assert: thData != null and is the result of calling init()
+     *  Assert: thData is preserved per Thread.
+     */
+    public void processConnection(TcpConnection connection, Object thData[]);    
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/net/URL.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/net/URL.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/net/URL.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,731 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.net;
+
+
+import java.io.Serializable;
+import java.net.MalformedURLException;
+
+
+/**
+ * <p><strong>URL</strong> is designed to provide public APIs for parsing
+ * and synthesizing Uniform Resource Locators as similar as possible to the
+ * APIs of <code>java.net.URL</code>, but without the ability to open a
+ * stream or connection.  One of the consequences of this is that you can
+ * construct URLs for protocols for which a URLStreamHandler is not
+ * available (such as an "https" URL when JSSE is not installed).</p>
+ *
+ * <p><strong>WARNING</strong> - This class assumes that the string
+ * representation of a URL conforms to the <code>spec</code> argument
+ * as described in RFC 2396 "Uniform Resource Identifiers: Generic Syntax":
+ * <pre>
+ *   &lt;scheme&gt;//&lt;authority&gt;&lt;path&gt;?&lt;query&gt;#&lt;fragment&gt;
+ * </pre></p>
+ *
+ * <p><strong>FIXME</strong> - This class really ought to end up in a Commons
+ * package someplace.</p>
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 299472 $ $Date: 2004-06-19 19:08:15 -0500 (Sat, 19 Jun 2004) $
+ */
+
+public final class URL implements Serializable {
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Create a URL object from the specified String representation.
+     *
+     * @param spec String representation of the URL
+     *
+     * @exception MalformedURLException if the string representation
+     *  cannot be parsed successfully
+     */
+    public URL(String spec) throws MalformedURLException {
+
+        this(null, spec);
+
+    }
+
+
+    /**
+     * Create a URL object by parsing a string representation relative
+     * to a specified context.  Based on logic from JDK 1.3.1's
+     * <code>java.net.URL</code>.
+     *
+     * @param context URL against which the relative representation
+     *  is resolved
+     * @param spec String representation of the URL (usually relative)
+     *
+     * @exception MalformedURLException if the string representation
+     *  cannot be parsed successfully
+     */
+    public URL(URL context, String spec) throws MalformedURLException {
+
+        String original = spec;
+        int i, limit, c;
+        int start = 0;
+        String newProtocol = null;
+        boolean aRef = false;
+
+        try {
+
+            // Eliminate leading and trailing whitespace
+            limit = spec.length();
+            while ((limit > 0) && (spec.charAt(limit - 1) <= ' ')) {
+                limit--;
+            }
+            while ((start < limit) && (spec.charAt(start) <= ' ')) {
+                start++;
+            }
+
+            // If the string representation starts with "url:", skip it
+            if (spec.regionMatches(true, start, "url:", 0, 4)) {
+                start += 4;
+            }
+
+            // Is this a ref relative to the context URL?
+            if ((start < spec.length()) && (spec.charAt(start) == '#')) {
+                aRef = true;
+            }
+
+            // Parse out the new protocol
+            for (i = start; !aRef && (i < limit) ; i++) { 
+                c = spec.charAt(i);
+                if (c == ':') {
+                    String s = spec.substring(start, i).toLowerCase();
+                    // Assume all protocols are valid
+                    newProtocol = s;
+                    start = i + 1;
+                    break;
+                } else if( c == '#' ) {
+                    aRef = true;
+                } else if( !isSchemeChar((char)c) ) {
+                    break;
+                }
+            }
+
+            // Only use our context if the protocols match
+            protocol = newProtocol;
+            if ((context != null) && ((newProtocol == null) ||
+                 newProtocol.equalsIgnoreCase(context.getProtocol()))) {
+                // If the context is a hierarchical URL scheme and the spec
+                // contains a matching scheme then maintain backwards
+                // compatibility and treat it as if the spec didn't contain
+                // the scheme; see 5.2.3 of RFC2396
+                if ((context.getPath() != null) &&
+                    (context.getPath().startsWith("/")))
+                    newProtocol = null;
+                if (newProtocol == null) {
+                    protocol = context.getProtocol();
+                    authority = context.getAuthority();
+                    userInfo = context.getUserInfo();
+                    host = context.getHost();
+                    port = context.getPort();
+                    file = context.getFile();
+                    int question = file.lastIndexOf("?");
+                    if (question < 0)
+                        path = file;
+                    else
+                        path = file.substring(0, question);
+                }
+            }
+
+            if (protocol == null)
+                throw new MalformedURLException("no protocol: " + original);
+
+            // Parse out any ref portion of the spec
+            i = spec.indexOf('#', start);
+            if (i >= 0) {
+                ref = spec.substring(i + 1, limit);
+                limit = i;
+            }
+
+            // Parse the remainder of the spec in a protocol-specific fashion
+            parse(spec, start, limit);
+            if (context != null)
+                normalize();
+
+
+        } catch (MalformedURLException e) {
+            throw e;
+        } catch (Exception e) {
+            throw new MalformedURLException(e.toString());
+        }
+
+    }
+
+
+
+
+
+    /**
+     * Create a URL object from the specified components.  The default port
+     * number for the specified protocol will be used.
+     *
+     * @param protocol Name of the protocol to use
+     * @param host Name of the host addressed by this protocol
+     * @param file Filename on the specified host
+     *
+     * @exception MalformedURLException is never thrown, but present for
+     *  compatible APIs
+     */
+    public URL(String protocol, String host, String file)
+        throws MalformedURLException {
+
+        this(protocol, host, -1, file);
+
+    }
+
+
+    /**
+     * Create a URL object from the specified components.  Specifying a port
+     * number of -1 indicates that the URL should use the default port for
+     * that protocol.  Based on logic from JDK 1.3.1's
+     * <code>java.net.URL</code>.
+     *
+     * @param protocol Name of the protocol to use
+     * @param host Name of the host addressed by this protocol
+     * @param port Port number, or -1 for the default port for this protocol
+     * @param file Filename on the specified host
+     *
+     * @exception MalformedURLException is never thrown, but present for
+     *  compatible APIs
+     */
+    public URL(String protocol, String host, int port, String file)
+        throws MalformedURLException {
+
+        this.protocol = protocol;
+        this.host = host;
+        this.port = port;
+
+        int hash = file.indexOf('#');
+        this.file = hash < 0 ? file : file.substring(0, hash);
+        this.ref = hash < 0 ? null : file.substring(hash + 1);
+        int question = file.lastIndexOf('?');
+        if (question >= 0) {
+            query = file.substring(question + 1);
+            path = file.substring(0, question);
+        } else
+            path = file;
+
+        if ((host != null) && (host.length() > 0))
+            authority = (port == -1) ? host : host + ":" + port;
+
+    }
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The authority part of the URL.
+     */
+    private String authority = null;
+
+
+    /**
+     * The filename part of the URL.
+     */
+    private String file = null;
+
+
+    /**
+     * The host name part of the URL.
+     */
+    private String host = null;
+
+
+    /**
+     * The path part of the URL.
+     */
+    private String path = null;
+
+
+    /**
+     * The port number part of the URL.
+     */
+    private int port = -1;
+
+
+    /**
+     * The protocol name part of the URL.
+     */
+    private String protocol = null;
+
+
+    /**
+     * The query part of the URL.
+     */
+    private String query = null;
+
+
+    /**
+     * The reference part of the URL.
+     */
+    private String ref = null;
+
+
+    /**
+     * The user info part of the URL.
+     */
+    private String userInfo = null;
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Compare two URLs for equality.  The result is <code>true</code> if and
+     * only if the argument is not null, and is a <code>URL</code> object
+     * that represents the same <code>URL</code> as this object.  Two
+     * <code>URLs</code> are equal if they have the same protocol and
+     * reference the same host, the same port number on the host,
+     * and the same file and anchor on the host.
+     *
+     * @param obj The URL to compare against
+     */
+    public boolean equals(Object obj) {
+
+        if (obj == null)
+            return (false);
+        if (!(obj instanceof URL))
+            return (false);
+        URL other = (URL) obj;
+        if (!sameFile(other))
+            return (false);
+        return (compare(ref, other.getRef()));
+
+    }
+
+
+    /**
+     * Return the authority part of the URL.
+     */
+    public String getAuthority() {
+
+        return (this.authority);
+
+    }
+
+
+    /**
+     * Return the filename part of the URL.  <strong>NOTE</strong> - For
+     * compatibility with <code>java.net.URL</code>, this value includes
+     * the query string if there was one.  For just the path portion,
+     * call <code>getPath()</code> instead.
+     */
+    public String getFile() {
+
+        if (file == null)
+            return ("");
+        return (this.file);
+
+    }
+
+
+    /**
+     * Return the host name part of the URL.
+     */
+    public String getHost() {
+
+        return (this.host);
+
+    }
+
+
+    /**
+     * Return the path part of the URL.
+     */
+    public String getPath() {
+
+        if (this.path == null)
+            return ("");
+        return (this.path);
+
+    }
+
+
+    /**
+     * Return the port number part of the URL.
+     */
+    public int getPort() {
+
+        return (this.port);
+
+    }
+
+
+    /**
+     * Return the protocol name part of the URL.
+     */
+    public String getProtocol() {
+
+        return (this.protocol);
+
+    }
+
+
+    /**
+     * Return the query part of the URL.
+     */
+    public String getQuery() {
+
+        return (this.query);
+
+    }
+
+
+    /**
+     * Return the reference part of the URL.
+     */
+    public String getRef() {
+
+        return (this.ref);
+
+    }
+
+
+    /**
+     * Return the user info part of the URL.
+     */
+    public String getUserInfo() {
+
+        return (this.userInfo);
+
+    }
+
+
+    /**
+     * Normalize the <code>path</code> (and therefore <code>file</code>)
+     * portions of this URL.
+     * <p>
+     * <strong>NOTE</strong> - This method is not part of the public API
+     * of <code>java.net.URL</code>, but is provided as a value added
+     * service of this implementation.
+     *
+     * @exception MalformedURLException if a normalization error occurs,
+     *  such as trying to move about the hierarchical root
+     */
+    public void normalize() throws MalformedURLException {
+
+        // Special case for null path
+        if (path == null) {
+            if (query != null)
+                file = "?" + query;
+            else
+                file = "";
+            return;
+        }
+
+        // Create a place for the normalized path
+        String normalized = path;
+        if (normalized.equals("/.")) {
+            path = "/";
+            if (query != null)
+                file = path + "?" + query;
+            else
+                file = path;
+            return;
+        }
+
+        // Normalize the slashes and add leading slash if necessary
+        if (normalized.indexOf('\\') >= 0)
+            normalized = normalized.replace('\\', '/');
+        if (!normalized.startsWith("/"))
+            normalized = "/" + normalized;
+
+        // Resolve occurrences of "//" in the normalized path
+        while (true) {
+            int index = normalized.indexOf("//");
+            if (index < 0)
+                break;
+            normalized = normalized.substring(0, index) +
+                normalized.substring(index + 1);
+        }
+
+        // Resolve occurrences of "/./" in the normalized path
+        while (true) {
+            int index = normalized.indexOf("/./");
+            if (index < 0)
+                break;
+            normalized = normalized.substring(0, index) +
+                normalized.substring(index + 2);
+        }
+
+        // Resolve occurrences of "/../" in the normalized path
+        while (true) {
+            int index = normalized.indexOf("/../");
+            if (index < 0)
+                break;
+            if (index == 0)
+                throw new MalformedURLException
+                    ("Invalid relative URL reference");
+            int index2 = normalized.lastIndexOf('/', index - 1);
+            normalized = normalized.substring(0, index2) +
+                normalized.substring(index + 3);
+        }
+
+        // Resolve occurrences of "/." at the end of the normalized path
+        if (normalized.endsWith("/."))
+            normalized = normalized.substring(0, normalized.length() - 1);
+
+        // Resolve occurrences of "/.." at the end of the normalized path
+        if (normalized.endsWith("/..")) {
+            int index = normalized.length() - 3;
+            int index2 = normalized.lastIndexOf('/', index - 1);
+            if (index2 < 0)
+                throw new MalformedURLException
+                    ("Invalid relative URL reference");
+            normalized = normalized.substring(0, index2 + 1);
+        }
+
+        // Return the normalized path that we have completed
+        path = normalized;
+        if (query != null)
+            file = path + "?" + query;
+        else
+            file = path;
+
+    }
+
+
+    /**
+     * Compare two URLs, excluding the "ref" fields.  Returns <code>true</code>
+     * if this <code>URL</code> and the <code>other</code> argument both refer
+     * to the same resource.  The two <code>URLs</code> might not both contain
+     * the same anchor.
+     */
+    public boolean sameFile(URL other) {
+
+        if (!compare(protocol, other.getProtocol()))
+            return (false);
+        if (!compare(host, other.getHost()))
+            return (false);
+        if (port != other.getPort())
+            return (false);
+        if (!compare(file, other.getFile()))
+            return (false);
+        return (true);
+
+    }
+
+
+    /**
+     * Return a string representation of this URL.  This follow the rules in
+     * RFC 2396, Section 5.2, Step 7.
+     */
+    public String toExternalForm() {
+
+        StringBuffer sb = new StringBuffer();
+        if (protocol != null) {
+            sb.append(protocol);
+            sb.append(":");
+        }
+        if (authority != null) {
+            sb.append("//");
+            sb.append(authority);
+        }
+        if (path != null)
+            sb.append(path);
+        if (query != null) {
+            sb.append('?');
+            sb.append(query);
+        }
+        if (ref != null) {
+            sb.append('#');
+            sb.append(ref);
+        }
+        return (sb.toString());
+
+    }
+
+
+    /**
+     * Return a string representation of this object.
+     */
+    public String toString() {
+
+        StringBuffer sb = new StringBuffer("URL[");
+        sb.append("authority=");
+        sb.append(authority);
+        sb.append(", file=");
+        sb.append(file);
+        sb.append(", host=");
+        sb.append(host);
+        sb.append(", port=");
+        sb.append(port);
+        sb.append(", protocol=");
+        sb.append(protocol);
+        sb.append(", query=");
+        sb.append(query);
+        sb.append(", ref=");
+        sb.append(ref);
+        sb.append(", userInfo=");
+        sb.append(userInfo);
+        sb.append("]");
+        return (sb.toString());
+
+        //        return (toExternalForm());
+
+    }
+
+
+    // -------------------------------------------------------- Private Methods
+
+
+    /**
+     * Compare to String values for equality, taking appropriate care if one
+     * or both of the values are <code>null</code>.
+     *
+     * @param first First string
+     * @param second Second string
+     */
+    private boolean compare(String first, String second) {
+
+        if (first == null) {
+            if (second == null)
+                return (true);
+            else
+                return (false);
+        } else {
+            if (second == null)
+                return (false);
+            else
+                return (first.equals(second));
+        }
+
+    }
+
+
+    /**
+     * Parse the specified portion of the string representation of a URL,
+     * assuming that it has a format similar to that for <code>http</code>.
+     *
+     * <p><strong>FIXME</strong> - This algorithm can undoubtedly be optimized
+     * for performance.  However, that needs to wait until after sufficient
+     * unit tests are implemented to guarantee correct behavior with no
+     * regressions.</p>
+     *
+     * @param spec String representation being parsed
+     * @param start Starting offset, which will be just after the ':' (if
+     *  there is one) that determined the protocol name
+     * @param limit Ending position, which will be the position of the '#'
+     *  (if there is one) that delimited the anchor
+     *
+     * @exception MalformedURLException if a parsing error occurs
+     */
+    private void parse(String spec, int start, int limit)
+        throws MalformedURLException {
+
+        // Trim the query string (if any) off the tail end
+        int question = spec.lastIndexOf('?', limit - 1);
+        if ((question >= 0) && (question < limit)) {
+            query = spec.substring(question + 1, limit);
+            limit = question;
+        } else {
+            query = null;
+        }
+
+        // Parse the authority section
+        if (spec.indexOf("//", start) == start) {
+            int pathStart = spec.indexOf("/", start + 2);
+            if ((pathStart >= 0) && (pathStart < limit)) {
+                authority = spec.substring(start + 2, pathStart);
+                start = pathStart;
+            } else {
+                authority = spec.substring(start + 2, limit);
+                start = limit;
+            }
+            if (authority.length() > 0) {
+                int at = authority.indexOf('@');
+                if( at >= 0 ) {
+                    userInfo = authority.substring(0,at);
+                }
+                int ipv6 = authority.indexOf('[',at+1);
+                int hStart = at+1;
+                if( ipv6 >= 0 ) {
+                    hStart = ipv6;
+                    ipv6 = authority.indexOf(']', ipv6);
+                    if( ipv6 < 0 ) {
+                        throw new MalformedURLException(
+                                                        "Closing ']' not found in IPV6 address: " + authority);
+                    } else {
+                        at = ipv6-1;
+                    }
+                }
+                                                        
+                int colon = authority.indexOf(':', at+1);
+                if (colon >= 0) {
+                    try {
+                        port =
+                            Integer.parseInt(authority.substring(colon + 1));
+                    } catch (NumberFormatException e) {
+                        throw new MalformedURLException(e.toString());
+                    }
+                    host = authority.substring(hStart, colon);
+                } else {
+                    host = authority.substring(hStart);
+                    port = -1;
+                }
+            }
+        }
+
+        // Parse the path section
+        if (spec.indexOf("/", start) == start) {     // Absolute path
+            path = spec.substring(start, limit);
+            if (query != null)
+                file = path + "?" + query;
+            else
+                file = path;
+            return;
+        }
+
+        // Resolve relative path against our context's file
+        if (path == null) {
+            if (query != null)
+                file = "?" + query;
+            else
+                file = null;
+            return;
+        }
+        if (!path.startsWith("/"))
+            throw new MalformedURLException
+                ("Base path does not start with '/'");
+        if (!path.endsWith("/"))
+            path += "/../";
+        path += spec.substring(start, limit);
+        if (query != null)
+            file = path + "?" + query;
+        else
+            file = path;
+        return;
+
+    }
+
+    /**
+     * Determine if the character is allowed in the scheme of a URI.
+     * See RFC 2396, Section 3.1
+     */
+    public static boolean isSchemeChar(char c) {
+        return Character.isLetterOrDigit(c) ||
+            c == '+' || c == '-' || c == '.';
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/net/jsse/JSSE13Factory.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/net/jsse/JSSE13Factory.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/net/jsse/JSSE13Factory.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,43 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.net.jsse;
+
+import java.net.Socket;
+import javax.net.ssl.SSLSocket;
+import org.apache.tomcat.util.net.SSLSupport;
+import org.apache.tomcat.util.net.ServerSocketFactory;
+
+/**
+ * Implementation class for JSSEFactory for JSSE 1.0.x (that is an extension
+ * to the 1.3 JVM).
+ *
+ * @author Bill Barker
+ */
+
+class JSSE13Factory implements JSSEFactory {
+
+    JSSE13Factory() {
+    }
+
+    public ServerSocketFactory getSocketFactory() {
+        return new JSSE13SocketFactory();
+    }
+
+    public SSLSupport getSSLSupport(Socket socket) {
+        return new JSSESupport((SSLSocket)socket);
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/net/jsse/JSSE13SocketFactory.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/net/jsse/JSSE13SocketFactory.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/net/jsse/JSSE13SocketFactory.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,156 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.net.jsse;
+
+import java.io.IOException;
+import java.security.KeyStore;
+import java.security.SecureRandom;
+import java.security.Security;
+import java.security.Provider;
+
+import javax.net.ssl.SSLServerSocket;
+import javax.net.ssl.SSLSocket;
+
+/*
+  1. Make the JSSE's jars available, either as an installed
+     extension (copy them into jre/lib/ext) or by adding
+     them to the Tomcat classpath.
+  2. keytool -genkey -alias tomcat -keyalg RSA
+     Use "changeit" as password ( this is the default we use )
+ */
+
+/**
+ * SSL server socket factory. It _requires_ a valid RSA key and
+ * JSSE. 
+ *
+ * @author Harish Prabandham
+ * @author Costin Manolache
+ * @author Stefan Freyr Stefansson
+ * @author EKR -- renamed to JSSESocketFactory
+ * @author Bill Barker
+ */
+public class JSSE13SocketFactory extends JSSESocketFactory
+{
+    /**
+     * Flag for client authentication
+     */
+    protected boolean clientAuth = false;
+
+    public JSSE13SocketFactory () {
+        super();
+    }
+
+    /**
+     * Reads the keystore and initializes the SSL socket factory.
+     *
+     * NOTE: This method is identical in functionality to the method of the
+     * same name in JSSE14SocketFactory, except that this method is used with
+     * JSSE 1.0.x (which is an extension to the 1.3 JVM), whereas the other is
+     * used with JSSE 1.1.x (which ships with the 1.4 JVM). Therefore, this
+     * method uses classes in com.sun.net.ssl, which have since moved to
+     * javax.net.ssl, and explicitly registers the required security providers,
+     * which come standard in a 1.4 JVM.
+     */
+     void init() throws IOException {
+        try {
+            try {
+                Class ssps = Class.forName("sun.security.provider.Sun");
+                Security.addProvider ((Provider)ssps.newInstance());
+            }catch(Exception cnfe) {
+                //Ignore, since this is a non-Sun JVM
+            }
+            Security.addProvider (new com.sun.net.ssl.internal.ssl.Provider());
+
+            String clientAuthStr = (String)attributes.get("clientauth");
+            if("true".equalsIgnoreCase(clientAuthStr) || 
+               "yes".equalsIgnoreCase(clientAuthStr)  ||
+               "want".equalsIgnoreCase(clientAuthStr)) {
+                clientAuth = true;
+            }
+            
+            // SSL protocol variant (e.g., TLS, SSL v3, etc.)
+            String protocol = (String)attributes.get("protocol");
+            if (protocol == null) protocol = defaultProtocol;
+            
+            // Certificate encoding algorithm (e.g., SunX509)
+            String algorithm = (String)attributes.get("algorithm");
+            if (algorithm == null) algorithm = defaultAlgorithm;
+
+            // Set up KeyManager, which will extract server key
+            com.sun.net.ssl.KeyManagerFactory kmf = 
+                com.sun.net.ssl.KeyManagerFactory.getInstance(algorithm);
+            String keystoreType = (String)attributes.get("keystoreType");
+            if (keystoreType == null) {
+                keystoreType = defaultKeystoreType;
+            }
+            String keystorePass = getKeystorePassword();
+            kmf.init(getKeystore(keystoreType, keystorePass),
+                     keystorePass.toCharArray());
+
+            // Set up TrustManager
+            com.sun.net.ssl.TrustManager[] tm = null;
+            String truststoreType = (String)attributes.get("truststoreType");
+            if(truststoreType == null) {
+                truststoreType = keystoreType;
+            }
+            KeyStore trustStore = getTrustStore(truststoreType);
+            if (trustStore != null) {
+                com.sun.net.ssl.TrustManagerFactory tmf =
+                    com.sun.net.ssl.TrustManagerFactory.getInstance("SunX509");
+                tmf.init(trustStore);
+                tm = tmf.getTrustManagers();
+            }
+
+            // Create and init SSLContext
+            com.sun.net.ssl.SSLContext context = 
+                com.sun.net.ssl.SSLContext.getInstance(protocol); 
+            context.init(kmf.getKeyManagers(), tm, new SecureRandom());
+
+            // Create proxy
+            sslProxy = context.getServerSocketFactory();
+
+            // Determine which cipher suites to enable
+            String requestedCiphers = (String)attributes.get("ciphers");
+            enabledCiphers = getEnabledCiphers(requestedCiphers,
+                     sslProxy.getSupportedCipherSuites());
+
+        } catch(Exception e) {
+            if( e instanceof IOException )
+                throw (IOException)e;
+            throw new IOException(e.getMessage());
+        }
+    }
+    protected String[] getEnabledProtocols(SSLServerSocket socket,
+                                           String requestedProtocols){
+        return null;
+    }
+    protected void setEnabledProtocols(SSLServerSocket socket, 
+                                             String [] protocols){
+    }
+
+    protected void configureClientAuth(SSLServerSocket socket){
+        socket.setNeedClientAuth(clientAuth);
+    }
+
+    protected void configureClientAuth(SSLSocket socket){
+        // In JSSE 1.0.2 docs it does not explicitly
+        // state whether SSLSockets returned from 
+        // SSLServerSocket.accept() inherit this setting.
+        socket.setNeedClientAuth(clientAuth);
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/net/jsse/JSSE14Factory.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/net/jsse/JSSE14Factory.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/net/jsse/JSSE14Factory.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,43 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.net.jsse;
+
+import java.net.Socket;
+import javax.net.ssl.SSLSocket;
+import org.apache.tomcat.util.net.SSLSupport;
+import org.apache.tomcat.util.net.ServerSocketFactory;
+
+/**
+ * Implementation class for JSSEFactory for JSSE 1.1.x (that ships with the
+ * 1.4 JVM).
+ *
+ * @author Bill Barker
+ */
+
+class JSSE14Factory implements JSSEFactory {
+
+    JSSE14Factory() {
+    }
+
+    public ServerSocketFactory getSocketFactory() {
+	return new JSSE14SocketFactory();
+    }
+
+    public SSLSupport getSSLSupport(Socket socket) {
+	return new JSSE14Support((SSLSocket)socket);
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/net/jsse/JSSE14SocketFactory.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/net/jsse/JSSE14SocketFactory.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/net/jsse/JSSE14SocketFactory.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,267 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.net.jsse;
+
+import java.io.IOException;
+import java.security.KeyStore;
+import java.security.SecureRandom;
+import java.util.Vector;
+
+import javax.net.ssl.KeyManager;
+import javax.net.ssl.KeyManagerFactory;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLServerSocket;
+import javax.net.ssl.SSLSocket;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.TrustManagerFactory;
+import javax.net.ssl.X509KeyManager;
+
+import org.apache.tomcat.util.res.StringManager;
+
+/*
+  1. Make the JSSE's jars available, either as an installed
+     extension (copy them into jre/lib/ext) or by adding
+     them to the Tomcat classpath.
+  2. keytool -genkey -alias tomcat -keyalg RSA
+     Use "changeit" as password ( this is the default we use )
+ */
+
+/**
+ * SSL server socket factory. It _requires_ a valid RSA key and
+ * JSSE. 
+ *
+ * @author Harish Prabandham
+ * @author Costin Manolache
+ * @author Stefan Freyr Stefansson
+ * @author EKR -- renamed to JSSESocketFactory
+ * @author Jan Luehe
+ */
+public class JSSE14SocketFactory  extends JSSESocketFactory {
+
+    private static StringManager sm =
+        StringManager.getManager("org.apache.tomcat.util.net.jsse.res");
+
+    /**
+     * Flag to state that we require client authentication.
+     */
+    protected boolean requireClientAuth = false;
+
+    /**
+     * Flag to state that we would like client authentication.
+     */
+    protected boolean wantClientAuth    = false;
+
+    public JSSE14SocketFactory () {
+        super();
+    }
+
+    /**
+     * Reads the keystore and initializes the SSL socket factory.
+     */
+    void init() throws IOException {
+        try {
+
+            String clientAuthStr = (String) attributes.get("clientauth");
+            if("true".equalsIgnoreCase(clientAuthStr) ||
+               "yes".equalsIgnoreCase(clientAuthStr)) {
+                requireClientAuth = true;
+            } else if("want".equalsIgnoreCase(clientAuthStr)) {
+                wantClientAuth = true;
+            }
+
+            // SSL protocol variant (e.g., TLS, SSL v3, etc.)
+            String protocol = (String) attributes.get("protocol");
+            if (protocol == null) {
+                protocol = defaultProtocol;
+            }
+
+            // Certificate encoding algorithm (e.g., SunX509)
+            String algorithm = (String) attributes.get("algorithm");
+            if (algorithm == null) {
+                algorithm = defaultAlgorithm;
+            }
+
+            String keystoreType = (String) attributes.get("keystoreType");
+            if (keystoreType == null) {
+                keystoreType = defaultKeystoreType;
+            }
+
+	    String trustAlgorithm = (String)attributes.get("truststoreAlgorithm");
+	    if( trustAlgorithm == null ) {
+		trustAlgorithm = algorithm;
+	    }
+            // Create and init SSLContext
+            SSLContext context = SSLContext.getInstance(protocol); 
+            context.init(getKeyManagers(keystoreType, algorithm,
+                                        (String) attributes.get("keyAlias")),
+                         getTrustManagers(keystoreType, trustAlgorithm),
+                         new SecureRandom());
+
+            // create proxy
+            sslProxy = context.getServerSocketFactory();
+
+            // Determine which cipher suites to enable
+            String requestedCiphers = (String)attributes.get("ciphers");
+            enabledCiphers = getEnabledCiphers(requestedCiphers,
+                                               sslProxy.getSupportedCipherSuites());
+
+        } catch(Exception e) {
+            if( e instanceof IOException )
+                throw (IOException)e;
+            throw new IOException(e.getMessage());
+        }
+    }
+
+    /**
+     * Gets the initialized key managers.
+     */
+    protected KeyManager[] getKeyManagers(String keystoreType,
+                                          String algorithm,
+                                          String keyAlias)
+                throws Exception {
+
+        KeyManager[] kms = null;
+
+        String keystorePass = getKeystorePassword();
+
+        KeyStore ks = getKeystore(keystoreType, keystorePass);
+        if (keyAlias != null && !ks.isKeyEntry(keyAlias)) {
+            throw new IOException(sm.getString("jsse.alias_no_key_entry", keyAlias));
+        }
+
+        KeyManagerFactory kmf = KeyManagerFactory.getInstance(algorithm);
+        kmf.init(ks, keystorePass.toCharArray());
+
+        kms = kmf.getKeyManagers();
+        if (keyAlias != null) {
+            if (JSSESocketFactory.defaultKeystoreType.equals(keystoreType)) {
+                keyAlias = keyAlias.toLowerCase();
+            }
+            for(int i=0; i<kms.length; i++) {
+                kms[i] = new JSSEKeyManager((X509KeyManager)kms[i], keyAlias);
+            }
+        }
+
+        return kms;
+    }
+
+    /**
+     * Gets the intialized trust managers.
+     */
+    protected TrustManager[] getTrustManagers(String keystoreType, String algorithm)
+                throws Exception {
+
+        TrustManager[] tms = null;
+
+        String truststoreType = (String)attributes.get("truststoreType");
+        if(truststoreType == null) {
+            truststoreType = keystoreType;
+        }
+        KeyStore trustStore = getTrustStore(truststoreType);
+        if (trustStore != null) {
+            TrustManagerFactory tmf = TrustManagerFactory.getInstance(algorithm);
+            tmf.init(trustStore);
+            tms = tmf.getTrustManagers();
+        }
+
+        return tms;
+    }
+    protected void setEnabledProtocols(SSLServerSocket socket, String []protocols){
+        if (protocols != null) {
+            socket.setEnabledProtocols(protocols);
+        }
+    }
+
+    protected String[] getEnabledProtocols(SSLServerSocket socket,
+                                           String requestedProtocols){
+        String[] supportedProtocols = socket.getSupportedProtocols();
+
+        String[] enabledProtocols = null;
+
+        if (requestedProtocols != null) {
+            Vector vec = null;
+            String protocol = requestedProtocols;
+            int index = requestedProtocols.indexOf(',');
+            if (index != -1) {
+                int fromIndex = 0;
+                while (index != -1) {
+                    protocol = requestedProtocols.substring(fromIndex, index).trim();
+                    if (protocol.length() > 0) {
+                        /*
+                         * Check to see if the requested protocol is among the
+                         * supported protocols, i.e., may be enabled
+                         */
+                        for (int i=0; supportedProtocols != null
+                                     && i<supportedProtocols.length; i++) {
+                            if (supportedProtocols[i].equals(protocol)) {
+                                if (vec == null) {
+                                    vec = new Vector();
+                                }
+                                vec.addElement(protocol);
+                                break;
+                            }
+                        }
+                    }
+                    fromIndex = index+1;
+                    index = requestedProtocols.indexOf(',', fromIndex);
+                } // while
+                protocol = requestedProtocols.substring(fromIndex);
+            }
+
+            if (protocol != null) {
+                protocol = protocol.trim();
+                if (protocol.length() > 0) {
+                    /*
+                     * Check to see if the requested protocol is among the
+                     * supported protocols, i.e., may be enabled
+                     */
+                    for (int i=0; supportedProtocols != null
+                                 && i<supportedProtocols.length; i++) {
+                        if (supportedProtocols[i].equals(protocol)) {
+                            if (vec == null) {
+                                vec = new Vector();
+                            }
+                            vec.addElement(protocol);
+                            break;
+                        }
+                    }
+                }
+            }           
+
+            if (vec != null) {
+                enabledProtocols = new String[vec.size()];
+                vec.copyInto(enabledProtocols);
+            }
+        }
+
+        return enabledProtocols;
+    }
+
+    protected void configureClientAuth(SSLServerSocket socket){
+        if (wantClientAuth){
+            socket.setWantClientAuth(wantClientAuth);
+        } else {
+            socket.setNeedClientAuth(requireClientAuth);
+        }
+    }
+
+    protected void configureClientAuth(SSLSocket socket){
+        // Per JavaDocs: SSLSockets returned from 
+        // SSLServerSocket.accept() inherit this setting.
+    }
+    
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/net/jsse/JSSE14Support.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/net/jsse/JSSE14Support.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/net/jsse/JSSE14Support.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,158 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.net.jsse;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.SocketException;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+
+import javax.net.ssl.HandshakeCompletedEvent;
+import javax.net.ssl.HandshakeCompletedListener;
+import javax.net.ssl.SSLException;
+import javax.net.ssl.SSLSession;
+import javax.net.ssl.SSLSocket;
+
+
+/* JSSESupport
+
+   Concrete implementation class for JSSE
+   Support classes.
+
+   This will only work with JDK 1.2 and up since it
+   depends on JDK 1.2's certificate support
+
+   @author EKR
+   @author Craig R. McClanahan
+   Parts cribbed from JSSECertCompat       
+   Parts cribbed from CertificatesValve
+*/
+
+class JSSE14Support extends JSSESupport {
+
+    private static org.apache.commons.logging.Log logger =
+        org.apache.commons.logging.LogFactory.getLog(JSSE14Support.class);
+
+    Listener listener = new Listener();
+
+    public JSSE14Support(SSLSocket sock){
+        super(sock);
+        sock.addHandshakeCompletedListener(listener);
+    }
+
+    protected void handShake() throws IOException {
+        if( ssl.getWantClientAuth() ) {
+            logger.debug("No client cert sent for want");
+        } else {
+            ssl.setNeedClientAuth(true);
+        }
+        synchronousHandshake(ssl);
+    }
+
+    /**
+     * JSSE in JDK 1.4 has an issue/feature that requires us to do a
+     * read() to get the client-cert.  As suggested by Andreas
+     * Sterbenz
+     */
+    private  void synchronousHandshake(SSLSocket socket) 
+        throws IOException {
+        InputStream in = socket.getInputStream();
+        int oldTimeout = socket.getSoTimeout();
+        socket.setSoTimeout(1000);
+        byte[] b = new byte[0];
+        listener.reset();
+        socket.startHandshake();
+        int maxTries = 60; // 60 * 1000 = example 1 minute time out
+        for (int i = 0; i < maxTries; i++) {
+	    if(logger.isTraceEnabled())
+		logger.trace("Reading for try #" +i);
+            try {
+                int x = in.read(b);
+            } catch(SSLException sslex) {
+                logger.info("SSL Error getting client Certs",sslex);
+                throw sslex;
+            } catch (IOException e) {
+                // ignore - presumably the timeout
+            }
+            if (listener.completed) {
+                break;
+            }
+        }
+        socket.setSoTimeout(oldTimeout);
+        if (listener.completed == false) {
+            throw new SocketException("SSL Cert handshake timeout");
+        }
+    }
+
+    /** Return the X509certificates or null if we can't get them.
+     *  XXX We should allow unverified certificates 
+     */ 
+    protected X509Certificate [] getX509Certificates(SSLSession session) 
+	throws IOException 
+    {
+        Certificate [] certs=null;
+        try {
+	    certs = session.getPeerCertificates();
+        } catch( Throwable t ) {
+            logger.debug("Error getting client certs",t);
+            return null;
+        }
+        if( certs==null ) return null;
+        
+        X509Certificate [] x509Certs = new X509Certificate[certs.length];
+	for(int i=0; i < certs.length; i++) {
+	    if( certs[i] instanceof X509Certificate ) {
+		// always currently true with the JSSE 1.1.x
+		x509Certs[i] = (X509Certificate)certs[i];
+	    } else {
+		try {
+		    byte [] buffer = certs[i].getEncoded();
+		    CertificateFactory cf =
+			CertificateFactory.getInstance("X.509");
+		    ByteArrayInputStream stream =
+			new ByteArrayInputStream(buffer);
+		    x509Certs[i] = (X509Certificate)
+			cf.generateCertificate(stream);
+		} catch(Exception ex) { 
+		    logger.info("Error translating cert " + certs[i], ex);
+		    return null;
+		}
+	    }
+	    if(logger.isTraceEnabled())
+		logger.trace("Cert #" + i + " = " + x509Certs[i]);
+	}
+	if(x509Certs.length < 1)
+	    return null;
+	return x509Certs;
+    }
+
+
+    private static class Listener implements HandshakeCompletedListener {
+        volatile boolean completed = false;
+        public void handshakeCompleted(HandshakeCompletedEvent event) {
+            completed = true;
+        }
+        void reset() {
+            completed = false;
+        }
+    }
+
+}
+

Added: branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/net/jsse/JSSE15Factory.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/net/jsse/JSSE15Factory.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/net/jsse/JSSE15Factory.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,41 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.net.jsse;
+
+import java.net.Socket;
+import javax.net.ssl.SSLSocket;
+import org.apache.tomcat.util.net.SSLSupport;
+import org.apache.tomcat.util.net.ServerSocketFactory;
+
+/**
+ * Implementation class for JSSEFactory for JSSE 1.1.x (that ships with the
+ * 1.5 JVM).
+ *
+ * @author Bill Barker
+ */
+
+class JSSE15Factory extends JSSE14Factory {
+
+    JSSE15Factory() {
+        super();
+    }
+
+    public ServerSocketFactory getSocketFactory() {
+        return new JSSE15SocketFactory();
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/net/jsse/JSSE15SocketFactory.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/net/jsse/JSSE15SocketFactory.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/net/jsse/JSSE15SocketFactory.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,163 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.net.jsse;
+
+import java.io.IOException;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.InputStream;
+import java.util.Collection;
+import java.security.KeyStore;
+import java.security.cert.PKIXBuilderParameters;
+import java.security.cert.X509CertSelector;
+import java.security.cert.CRL;
+import java.security.cert.CollectionCertStoreParameters;
+import java.security.cert.CertStoreParameters;
+import java.security.cert.CertPathParameters;
+import java.security.cert.CertStore;
+import java.security.cert.CertificateFactory;
+import java.security.cert.CRLException;
+import java.security.cert.CertificateException;
+
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.TrustManagerFactory;
+import javax.net.ssl.X509KeyManager;
+import javax.net.ssl.ManagerFactoryParameters;
+import javax.net.ssl.CertPathTrustManagerParameters;
+
+/**
+ * SSL Socket Factory for JDK 1.5
+ *
+ * @author Bill Barker
+ */
+public class JSSE15SocketFactory  extends JSSE14SocketFactory {
+
+    private static org.apache.commons.logging.Log log =
+        org.apache.commons.logging.LogFactory.getLog(JSSE15SocketFactory.class);
+
+    public JSSE15SocketFactory() {
+        super();
+    }
+
+
+    /**
+     * Gets the intialized trust managers.
+     */
+    protected TrustManager[] getTrustManagers(String keystoreType, String algorithm)
+        throws Exception {
+        if(attributes.get("truststoreAlgorithm") == null) {
+            // in 1.5, the Trust default isn't the same as the Key default.
+            algorithm = TrustManagerFactory.getDefaultAlgorithm();
+        }
+        String crlf = (String)attributes.get("crlFile");
+        if(crlf == null) {
+            return super.getTrustManagers(keystoreType, algorithm);
+        }
+
+        TrustManager[] tms = null;
+
+        String truststoreType = (String)attributes.get("truststoreType");
+        if(truststoreType == null) {
+            truststoreType = keystoreType;
+        }
+        KeyStore trustStore = getTrustStore(truststoreType);
+        if (trustStore != null) {
+            TrustManagerFactory tmf = TrustManagerFactory.getInstance(algorithm);
+            CertPathParameters params = getParameters(algorithm, crlf, trustStore);
+            ManagerFactoryParameters mfp = new CertPathTrustManagerParameters(params);
+            tmf.init(mfp);
+            tms = tmf.getTrustManagers();
+        }
+
+        return tms;
+    }
+
+
+    /**
+     * Return the initialization parameters for the TrustManager.
+     * Currently, only the default <code>PKIX</code> is supported.
+     * 
+     * @param algorithm The algorithm to get parameters for.
+     * @param crlf The path to the CRL file.
+     * @param trustStore The configured TrustStore.
+     * @return The parameters including the CRLs and TrustStore.
+     */
+    protected CertPathParameters getParameters(String algorithm, 
+                                                String crlf, 
+                                                KeyStore trustStore)
+        throws Exception {
+        CertPathParameters params = null;
+        if("PKIX".equalsIgnoreCase(algorithm)) {
+            PKIXBuilderParameters xparams = new PKIXBuilderParameters(trustStore, 
+                                                                     new X509CertSelector());
+            Collection crls = getCRLs(crlf);
+            CertStoreParameters csp = new CollectionCertStoreParameters(crls);
+            CertStore store = CertStore.getInstance("Collection", csp);
+            xparams.addCertStore(store);
+            xparams.setRevocationEnabled(true);
+            String trustLength = (String)attributes.get("trustMaxCertLength");
+            if(trustLength != null) {
+                try {
+                    xparams.setMaxPathLength(Integer.parseInt(trustLength));
+                } catch(Exception ex) {
+                    log.warn("Bad maxCertLength: "+trustLength);
+                }
+            }
+
+            params = xparams;
+        } else {
+            throw new CRLException("CRLs not supported for type: "+algorithm);
+        }
+        return params;
+    }
+
+
+    /**
+     * Load the collection of CRLs.
+     * 
+     */
+    protected Collection<? extends CRL> getCRLs(String crlf) 
+        throws IOException, CRLException, CertificateException {
+
+        File crlFile = new File(crlf);
+        if( !crlFile.isAbsolute() ) {
+            crlFile = new File(System.getProperty("catalina.base"), crlf);
+        }
+        Collection<? extends CRL> crls = null;
+        InputStream is = null;
+        try {
+            CertificateFactory cf = CertificateFactory.getInstance("X.509");
+            is = new FileInputStream(crlFile);
+            crls = cf.generateCRLs(is);
+        } catch(IOException iex) {
+            throw iex;
+        } catch(CRLException crle) {
+            throw crle;
+        } catch(CertificateException ce) {
+            throw ce;
+        } finally { 
+            if(is != null) {
+                try{
+                    is.close();
+                } catch(Exception ex) {
+                }
+            }
+        }
+        return crls;
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/net/jsse/JSSEFactory.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/net/jsse/JSSEFactory.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/net/jsse/JSSEFactory.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,42 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.net.jsse;
+
+import java.net.Socket;
+import org.apache.tomcat.util.net.SSLSupport;
+import org.apache.tomcat.util.net.ServerSocketFactory;
+
+/** 
+ * Factory interface to construct components based on the JSSE version
+ * in use.
+ *
+ * @author Bill Barker
+ */
+
+interface JSSEFactory {
+
+    /**
+     * Returns the ServerSocketFactory to use.
+     */
+    public ServerSocketFactory getSocketFactory();
+
+    /**
+     * returns the SSLSupport attached to this socket.
+     */
+    public SSLSupport getSSLSupport(Socket socket);
+
+};

Added: branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/net/jsse/JSSEImplementation.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/net/jsse/JSSEImplementation.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/net/jsse/JSSEImplementation.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,88 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.net.jsse;
+
+import java.net.Socket;
+
+import org.apache.tomcat.util.compat.JdkCompat;
+import org.apache.tomcat.util.net.SSLImplementation;
+import org.apache.tomcat.util.net.SSLSupport;
+import org.apache.tomcat.util.net.ServerSocketFactory;
+
+/* JSSEImplementation:
+
+   Concrete implementation class for JSSE
+
+   @author EKR
+*/
+        
+public class JSSEImplementation extends SSLImplementation
+{
+    static final String JSSE15Factory =
+	"org.apache.tomcat.util.net.jsse.JSSE15Factory";
+    static final String JSSE14Factory = 
+        "org.apache.tomcat.util.net.jsse.JSSE14Factory";
+    static final String JSSE13Factory = 
+        "org.apache.tomcat.util.net.jsse.JSSE13Factory";
+    static final String SSLSocketClass = "javax.net.ssl.SSLSocket";
+
+    static org.apache.commons.logging.Log logger = 
+        org.apache.commons.logging.LogFactory.getLog(JSSEImplementation.class);
+
+    private JSSEFactory factory = null;
+
+    public JSSEImplementation() throws ClassNotFoundException {
+        // Check to see if JSSE is floating around somewhere
+        Class.forName(SSLSocketClass);
+        if( JdkCompat.isJava15() ) {
+            try {
+                Class factcl = Class.forName(JSSE15Factory);
+                factory = (JSSEFactory)factcl.newInstance();
+            } catch(Exception ex) {
+                if(logger.isDebugEnabled())
+                    logger.debug("Error getting factory: " + JSSE15Factory, ex);
+            }
+        }
+        if(factory == null && JdkCompat.isJava14() ) {
+            try {
+                Class factcl = Class.forName(JSSE14Factory);
+                factory = (JSSEFactory)factcl.newInstance();
+            } catch(Exception ex) {
+                if(logger.isDebugEnabled()) {
+                    logger.debug("Error getting factory: " + JSSE14Factory, ex);
+                }
+            }
+        } if(factory == null) {
+            factory = new JSSE13Factory();
+        }
+    }
+
+
+    public String getImplementationName(){
+      return "JSSE";
+    }
+      
+    public ServerSocketFactory getServerSocketFactory()  {
+        ServerSocketFactory ssf = factory.getSocketFactory();
+        return ssf;
+    } 
+
+    public SSLSupport getSSLSupport(Socket s) {
+        SSLSupport ssls = factory.getSSLSupport(s);
+        return ssls;
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/net/jsse/JSSEKeyManager.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/net/jsse/JSSEKeyManager.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/net/jsse/JSSEKeyManager.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,143 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.net.jsse;
+
+import java.net.Socket;
+import java.security.Principal;
+import java.security.PrivateKey;
+import java.security.cert.X509Certificate;
+import javax.net.ssl.X509KeyManager;
+
+/**
+ * X509KeyManager which allows selection of a specific keypair and certificate
+ * chain (identified by their keystore alias name) to be used by the server to
+ * authenticate itself to SSL clients.
+ *
+ * @author Jan Luehe
+ */
+public final class JSSEKeyManager implements X509KeyManager {
+
+    private X509KeyManager delegate;
+    private String serverKeyAlias;
+
+    /**
+     * Constructor.
+     *
+     * @param mgr The X509KeyManager used as a delegate
+     * @param serverKeyAlias The alias name of the server's keypair and
+     * supporting certificate chain
+     */
+    public JSSEKeyManager(X509KeyManager mgr, String serverKeyAlias) {
+        this.delegate = mgr;
+        this.serverKeyAlias = serverKeyAlias;
+    }
+
+    /**
+     * Choose an alias to authenticate the client side of a secure socket,
+     * given the public key type and the list of certificate issuer authorities
+     * recognized by the peer (if any).
+     *
+     * @param keyType The key algorithm type name(s), ordered with the
+     * most-preferred key type first
+     * @param issuers The list of acceptable CA issuer subject names, or null
+     * if it does not matter which issuers are used
+     * @param socket The socket to be used for this connection. This parameter
+     * can be null, in which case this method will return the most generic
+     * alias to use
+     *
+     * @return The alias name for the desired key, or null if there are no
+     * matches
+     */
+    public String chooseClientAlias(String[] keyType, Principal[] issuers,
+                                    Socket socket) {
+        return delegate.chooseClientAlias(keyType, issuers, socket);
+    }
+
+    /**
+     * Returns this key manager's server key alias that was provided in the
+     * constructor.
+     *
+     * @param keyType The key algorithm type name (ignored)
+     * @param issuers The list of acceptable CA issuer subject names, or null
+     * if it does not matter which issuers are used (ignored)
+     * @param socket The socket to be used for this connection. This parameter
+     * can be null, in which case this method will return the most generic
+     * alias to use (ignored)
+     *
+     * @return Alias name for the desired key
+     */
+    public String chooseServerAlias(String keyType, Principal[] issuers,
+                                    Socket socket) {
+        return serverKeyAlias;
+    }
+
+    /**
+     * Returns the certificate chain associated with the given alias.
+     *
+     * @param alias The alias name
+     *
+     * @return Certificate chain (ordered with the user's certificate first
+     * and the root certificate authority last), or null if the alias can't be
+     * found
+     */
+    public X509Certificate[] getCertificateChain(String alias) {
+        return delegate.getCertificateChain(alias); 
+    }
+
+    /**
+     * Get the matching aliases for authenticating the client side of a secure
+     * socket, given the public key type and the list of certificate issuer
+     * authorities recognized by the peer (if any).
+     *
+     * @param keyType The key algorithm type name
+     * @param issuers The list of acceptable CA issuer subject names, or null
+     * if it does not matter which issuers are used
+     *
+     * @return Array of the matching alias names, or null if there were no
+     * matches
+     */
+    public String[] getClientAliases(String keyType, Principal[] issuers) {
+        return delegate.getClientAliases(keyType, issuers);
+    }
+
+    /**
+     * Get the matching aliases for authenticating the server side of a secure
+     * socket, given the public key type and the list of certificate issuer
+     * authorities recognized by the peer (if any).
+     *
+     * @param keyType The key algorithm type name
+     * @param issuers The list of acceptable CA issuer subject names, or null
+     * if it does not matter which issuers are used
+     *
+     * @return Array of the matching alias names, or null if there were no
+     * matches
+     */
+    public String[] getServerAliases(String keyType, Principal[] issuers) {
+        return delegate.getServerAliases(keyType, issuers);
+    }
+
+    /**
+     * Returns the key associated with the given alias.
+     *
+     * @param alias The alias name
+     *
+     * @return The requested key, or null if the alias can't be found
+     */
+    public PrivateKey getPrivateKey(String alias) {
+        return delegate.getPrivateKey(alias);
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/net/jsse/JSSESocketFactory.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/net/jsse/JSSESocketFactory.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/net/jsse/JSSESocketFactory.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,369 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.net.jsse;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.InetAddress;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.net.SocketException;
+import java.security.KeyStore;
+import java.util.Vector;
+
+import javax.net.ssl.SSLException;
+import javax.net.ssl.SSLServerSocket;
+import javax.net.ssl.SSLServerSocketFactory;
+import javax.net.ssl.SSLSocket;
+
+/*
+  1. Make the JSSE's jars available, either as an installed
+     extension (copy them into jre/lib/ext) or by adding
+     them to the Tomcat classpath.
+  2. keytool -genkey -alias tomcat -keyalg RSA
+     Use "changeit" as password ( this is the default we use )
+ */
+
+/**
+ * SSL server socket factory. It _requires_ a valid RSA key and
+ * JSSE. 
+ *
+ * @author Harish Prabandham
+ * @author Costin Manolache
+ * @author Stefan Freyr Stefansson
+ * @author EKR -- renamed to JSSESocketFactory
+ */
+public abstract class JSSESocketFactory
+    extends org.apache.tomcat.util.net.ServerSocketFactory
+{
+    // defaults
+    static String defaultProtocol = "TLS";
+    static String defaultAlgorithm = "SunX509";
+    static boolean defaultClientAuth = false;
+    static String defaultKeystoreType = "JKS";
+    private static final String defaultKeystoreFile
+        = System.getProperty("user.home") + "/.keystore";
+    private static final String defaultKeyPass = "changeit";
+    static org.apache.commons.logging.Log log =
+        org.apache.commons.logging.LogFactory.getLog(JSSESocketFactory.class);
+
+    protected boolean initialized;
+    protected String clientAuth = "false";
+    protected SSLServerSocketFactory sslProxy = null;
+    protected String[] enabledCiphers;
+   
+
+    public JSSESocketFactory () {
+    }
+
+    public ServerSocket createSocket (int port)
+        throws IOException
+    {
+        if (!initialized) init();
+        ServerSocket socket = sslProxy.createServerSocket(port);
+        initServerSocket(socket);
+        return socket;
+    }
+    
+    public ServerSocket createSocket (int port, int backlog)
+        throws IOException
+    {
+        if (!initialized) init();
+        ServerSocket socket = sslProxy.createServerSocket(port, backlog);
+        initServerSocket(socket);
+        return socket;
+    }
+    
+    public ServerSocket createSocket (int port, int backlog,
+                                      InetAddress ifAddress)
+        throws IOException
+    {   
+        if (!initialized) init();
+        ServerSocket socket = sslProxy.createServerSocket(port, backlog,
+                                                          ifAddress);
+        initServerSocket(socket);
+        return socket;
+    }
+    
+    public Socket acceptSocket(ServerSocket socket)
+        throws IOException
+    {
+        SSLSocket asock = null;
+        try {
+             asock = (SSLSocket)socket.accept();
+             configureClientAuth(asock);
+        } catch (SSLException e){
+          throw new SocketException("SSL handshake error" + e.toString());
+        }
+        return asock;
+    }
+
+    public void handshake(Socket sock) throws IOException {
+        ((SSLSocket)sock).startHandshake();
+    }
+
+    /*
+     * Determines the SSL cipher suites to be enabled.
+     *
+     * @param requestedCiphers Comma-separated list of requested ciphers
+     * @param supportedCiphers Array of supported ciphers
+     *
+     * @return Array of SSL cipher suites to be enabled, or null if none of the
+     * requested ciphers are supported
+     */
+    protected String[] getEnabledCiphers(String requestedCiphers,
+                                         String[] supportedCiphers) {
+
+        String[] enabledCiphers = null;
+
+        if (requestedCiphers != null) {
+            Vector vec = null;
+            String cipher = requestedCiphers;
+            int index = requestedCiphers.indexOf(',');
+            if (index != -1) {
+                int fromIndex = 0;
+                while (index != -1) {
+                    cipher = requestedCiphers.substring(fromIndex, index).trim();
+                    if (cipher.length() > 0) {
+                        /*
+                         * Check to see if the requested cipher is among the
+                         * supported ciphers, i.e., may be enabled
+                         */
+                        for (int i=0; supportedCiphers != null
+                                     && i<supportedCiphers.length; i++) {
+                            if (supportedCiphers[i].equals(cipher)) {
+                                if (vec == null) {
+                                    vec = new Vector();
+                                }
+                                vec.addElement(cipher);
+                                break;
+                            }
+                        }
+                    }
+                    fromIndex = index+1;
+                    index = requestedCiphers.indexOf(',', fromIndex);
+                } // while
+                cipher = requestedCiphers.substring(fromIndex);
+            }
+
+            if (cipher != null) {
+                cipher = cipher.trim();
+                if (cipher.length() > 0) {
+                    /*
+                     * Check to see if the requested cipher is among the
+                     * supported ciphers, i.e., may be enabled
+                     */
+                    for (int i=0; supportedCiphers != null
+                                 && i<supportedCiphers.length; i++) {
+                        if (supportedCiphers[i].equals(cipher)) {
+                            if (vec == null) {
+                                vec = new Vector();
+                            }
+                            vec.addElement(cipher);
+                            break;
+                        }
+                    }
+                }
+            }           
+
+            if (vec != null) {
+                enabledCiphers = new String[vec.size()];
+                vec.copyInto(enabledCiphers);
+            }
+        } else {
+            enabledCiphers = sslProxy.getDefaultCipherSuites();
+        }
+
+        return enabledCiphers;
+    }
+     
+    /*
+     * Gets the SSL server's keystore password.
+     */
+    protected String getKeystorePassword() {
+        String keyPass = (String)attributes.get("keypass");
+        if (keyPass == null) {
+            keyPass = defaultKeyPass;
+        }
+        String keystorePass = (String)attributes.get("keystorePass");
+        if (keystorePass == null) {
+            keystorePass = keyPass;
+        }
+        return keystorePass;
+    }
+
+    /*
+     * Gets the SSL server's keystore.
+     */
+    protected KeyStore getKeystore(String type, String pass)
+            throws IOException {
+
+        String keystoreFile = (String)attributes.get("keystore");
+        if (keystoreFile == null)
+            keystoreFile = defaultKeystoreFile;
+
+        return getStore(type, keystoreFile, pass);
+    }
+
+    /*
+     * Gets the SSL server's truststore.
+     */
+    protected KeyStore getTrustStore(String keystoreType) throws IOException {
+        KeyStore trustStore = null;
+
+        String trustStoreFile = (String)attributes.get("truststoreFile");
+        if(trustStoreFile == null) {
+            trustStoreFile = System.getProperty("javax.net.ssl.trustStore");
+        }
+        if(log.isDebugEnabled()) {
+            log.debug("Truststore = " + trustStoreFile);
+        }
+        String trustStorePassword = (String)attributes.get("truststorePass");
+        if( trustStorePassword == null) {
+            trustStorePassword = System.getProperty("javax.net.ssl.trustStorePassword");
+        }
+        if( trustStorePassword == null ) {
+            trustStorePassword = getKeystorePassword();
+        }
+        if(log.isDebugEnabled()) {
+            log.debug("TrustPass = " + trustStorePassword);
+        }
+        String truststoreType = (String)attributes.get("truststoreType");
+        if(truststoreType == null) {
+            truststoreType = keystoreType;
+        }
+        if(log.isDebugEnabled()) {
+            log.debug("trustType = " + truststoreType);
+        }
+        if (trustStoreFile != null && trustStorePassword != null){
+            trustStore = getStore(truststoreType, trustStoreFile,
+                                  trustStorePassword);
+        }
+
+        return trustStore;
+    }
+
+    /*
+     * Gets the key- or truststore with the specified type, path, and password.
+     */
+    private KeyStore getStore(String type, String path, String pass)
+            throws IOException {
+
+        KeyStore ks = null;
+        InputStream istream = null;
+        try {
+            ks = KeyStore.getInstance(type);
+            if(! "PKCS11".equalsIgnoreCase(type) ) {
+                File keyStoreFile = new File(path);
+                if (!keyStoreFile.isAbsolute()) {
+                    keyStoreFile = new File(System.getProperty("catalina.base"),
+                                            path);
+                }
+                istream = new FileInputStream(keyStoreFile);
+            }
+
+            ks.load(istream, pass.toCharArray());
+        } catch (FileNotFoundException fnfe) {
+            throw fnfe;
+        } catch (IOException ioe) {
+            throw ioe;      
+        } catch(Exception ex) {
+            log.error("Exception trying to load keystore " +path,ex);
+            throw new IOException("Exception trying to load keystore " +
+                                  path + ": " + ex.getMessage() );
+        } finally {
+            if (istream != null) {
+                try {
+                    istream.close();
+                } catch (IOException ioe) {
+                    // Do nothing
+                }
+            }
+        }
+
+        return ks;
+    }
+
+    /**
+     * Reads the keystore and initializes the SSL socket factory.
+     *
+     * Place holder method to initialize the KeyStore, etc.
+     */
+    abstract void init() throws IOException ;
+
+    /*
+     * Determines the SSL protocol variants to be enabled.
+     *
+     * @param socket The socket to get supported list from.
+     * @param requestedProtocols Comma-separated list of requested SSL
+     * protocol variants
+     *
+     * @return Array of SSL protocol variants to be enabled, or null if none of
+     * the requested protocol variants are supported
+     */
+    abstract protected String[] getEnabledProtocols(SSLServerSocket socket,
+                                                    String requestedProtocols);
+
+    /**
+     * Set the SSL protocol variants to be enabled.
+     * @param socket the SSLServerSocket.
+     * @param protocols the protocols to use.
+     */
+    abstract protected void setEnabledProtocols(SSLServerSocket socket, 
+                                            String [] protocols);
+
+    /**
+     * Configure Client authentication for this version of JSSE.  The
+     * JSSE included in Java 1.4 supports the 'want' value.  Prior
+     * versions of JSSE will treat 'want' as 'false'.
+     * @param socket the SSLServerSocket
+     */
+    abstract protected void configureClientAuth(SSLServerSocket socket);
+
+    /**
+     * Configure Client authentication for this version of JSSE.  The
+     * JSSE included in Java 1.4 supports the 'want' value.  Prior
+     * versions of JSSE will treat 'want' as 'false'.
+     * @param socket the SSLSocket
+     */
+    abstract protected void configureClientAuth(SSLSocket socket);
+    
+    /**
+     * Configures the given SSL server socket with the requested cipher suites,
+     * protocol versions, and need for client authentication
+     */
+    private void initServerSocket(ServerSocket ssocket) {
+
+        SSLServerSocket socket = (SSLServerSocket) ssocket;
+
+        if (enabledCiphers != null) {
+            socket.setEnabledCipherSuites(enabledCiphers);
+        }
+
+        String requestedProtocols = (String) attributes.get("protocols");
+        setEnabledProtocols(socket, getEnabledProtocols(socket, 
+                                                         requestedProtocols));
+
+        // we don't know if client auth is needed -
+        // after parsing the request we may re-handshake
+        configureClientAuth(socket);
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/net/jsse/JSSESupport.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/net/jsse/JSSESupport.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/net/jsse/JSSESupport.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,178 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.net.jsse;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.security.cert.CertificateFactory;
+
+import javax.net.ssl.SSLSession;
+import javax.net.ssl.SSLSocket;
+import javax.security.cert.X509Certificate;
+
+import org.apache.tomcat.util.net.SSLSupport;
+
+/* JSSESupport
+
+   Concrete implementation class for JSSE
+   Support classes.
+
+   This will only work with JDK 1.2 and up since it
+   depends on JDK 1.2's certificate support
+
+   @author EKR
+   @author Craig R. McClanahan
+   Parts cribbed from JSSECertCompat       
+   Parts cribbed from CertificatesValve
+*/
+
+class JSSESupport implements SSLSupport {
+    private static org.apache.commons.logging.Log log =
+	org.apache.commons.logging.LogFactory.getLog(JSSESupport.class);
+
+    protected SSLSocket ssl;
+
+
+    JSSESupport(SSLSocket sock){
+        ssl=sock;
+    }
+
+    public String getCipherSuite() throws IOException {
+        // Look up the current SSLSession
+        SSLSession session = ssl.getSession();
+        if (session == null)
+            return null;
+        return session.getCipherSuite();
+    }
+
+    public Object[] getPeerCertificateChain() 
+        throws IOException {
+        return getPeerCertificateChain(false);
+    }
+
+    protected java.security.cert.X509Certificate [] 
+	getX509Certificates(SSLSession session) throws IOException {
+        X509Certificate jsseCerts[] = null;
+    try{
+	    jsseCerts = session.getPeerCertificateChain();
+    } catch (Throwable ex){
+       // Get rid of the warning in the logs when no Client-Cert is
+       // available
+    }
+
+	if(jsseCerts == null)
+	    jsseCerts = new X509Certificate[0];
+	java.security.cert.X509Certificate [] x509Certs =
+	    new java.security.cert.X509Certificate[jsseCerts.length];
+	for (int i = 0; i < x509Certs.length; i++) {
+	    try {
+		byte buffer[] = jsseCerts[i].getEncoded();
+		CertificateFactory cf =
+		    CertificateFactory.getInstance("X.509");
+		ByteArrayInputStream stream =
+		    new ByteArrayInputStream(buffer);
+		x509Certs[i] = (java.security.cert.X509Certificate)
+		    cf.generateCertificate(stream);
+		if(log.isTraceEnabled())
+		    log.trace("Cert #" + i + " = " + x509Certs[i]);
+	    } catch(Exception ex) {
+		log.info("Error translating " + jsseCerts[i], ex);
+		return null;
+	    }
+	}
+	
+	if ( x509Certs.length < 1 )
+	    return null;
+	return x509Certs;
+    }
+    public Object[] getPeerCertificateChain(boolean force)
+        throws IOException {
+        // Look up the current SSLSession
+	SSLSession session = ssl.getSession();
+        if (session == null)
+            return null;
+
+        // Convert JSSE's certificate format to the ones we need
+	X509Certificate [] jsseCerts = null;
+	try {
+	    jsseCerts = session.getPeerCertificateChain();
+	} catch(Exception bex) {
+	    // ignore.
+	}
+	if (jsseCerts == null)
+	    jsseCerts = new X509Certificate[0];
+	if(jsseCerts.length <= 0 && force) {
+	    session.invalidate();
+	    handShake();
+	    session = ssl.getSession();
+	}
+        return getX509Certificates(session);
+    }
+
+    protected void handShake() throws IOException {
+        ssl.setNeedClientAuth(true);
+        ssl.startHandshake();
+    }
+    /**
+     * Copied from <code>org.apache.catalina.valves.CertificateValve</code>
+     */
+    public Integer getKeySize() 
+        throws IOException {
+        // Look up the current SSLSession
+        SSLSession session = ssl.getSession();
+        SSLSupport.CipherData c_aux[]=ciphers;
+        if (session == null)
+            return null;
+        Integer keySize = (Integer) session.getValue(KEY_SIZE_KEY);
+        if (keySize == null) {
+            int size = 0;
+            String cipherSuite = session.getCipherSuite();
+            for (int i = 0; i < c_aux.length; i++) {
+                if (cipherSuite.indexOf(c_aux[i].phrase) >= 0) {
+                    size = c_aux[i].keySize;
+                    break;
+                }
+            }
+            keySize = new Integer(size);
+            session.putValue(KEY_SIZE_KEY, keySize);
+        }
+        return keySize;
+    }
+
+    public String getSessionId()
+        throws IOException {
+        // Look up the current SSLSession
+        SSLSession session = ssl.getSession();
+        if (session == null)
+            return null;
+        // Expose ssl_session (getId)
+        byte [] ssl_session = session.getId();
+        if ( ssl_session == null) 
+            return null;
+        StringBuffer buf=new StringBuffer("");
+        for(int x=0; x<ssl_session.length; x++) {
+            String digit=Integer.toHexString((int)ssl_session[x]);
+            if (digit.length()<2) buf.append('0');
+            if (digit.length()>2) digit=digit.substring(digit.length()-2);
+            buf.append(digit);
+        }
+        return buf.toString();
+    }
+
+
+}
+

Added: branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/net/jsse/res/LocalStrings.properties
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/net/jsse/res/LocalStrings.properties	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/net/jsse/res/LocalStrings.properties	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1 @@
+jsse.alias_no_key_entry=Alias name {0} does not identify a key entry

Added: branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/net/jsse/res/LocalStrings_es.properties
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/net/jsse/res/LocalStrings_es.properties	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/net/jsse/res/LocalStrings_es.properties	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1 @@
+jsse.alias_no_key_entry=El nombre de Alias {0} no identifica una entrada de clave

Added: branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/net/jsse/res/LocalStrings_fr.properties
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/net/jsse/res/LocalStrings_fr.properties	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/net/jsse/res/LocalStrings_fr.properties	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1 @@
+jsse.alias_no_key_entry=Le nom alias {0} n''identifie pas une entrée de clef

Added: branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/net/jsse/res/LocalStrings_ja.properties
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/net/jsse/res/LocalStrings_ja.properties	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/net/jsse/res/LocalStrings_ja.properties	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,2 @@
+jsse.alias_no_key_entry=\u5225\u540d {0} \u306f\u30ad\u30fc\u30a8\u30f3\u30c8\u30ea\u3092\u767a\u898b\u3067\u304d\u307e\u305b\u3093
+

Added: branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/net/puretls/PureTLSImplementation.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/net/puretls/PureTLSImplementation.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/net/puretls/PureTLSImplementation.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,57 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.net.puretls;
+
+import java.net.Socket;
+
+import org.apache.tomcat.util.net.SSLImplementation;
+import org.apache.tomcat.util.net.SSLSupport;
+import org.apache.tomcat.util.net.ServerSocketFactory;
+
+import COM.claymoresystems.ptls.SSLSocket;
+
+/* PureTLSImplementation:
+
+   Concrete implementation class for PureTLS
+
+   @author EKR
+*/
+
+public class PureTLSImplementation extends SSLImplementation
+{
+    public PureTLSImplementation() throws ClassNotFoundException {
+	// Check to see if PureTLS is floating around somewhere
+	Class.forName("COM.claymoresystems.ptls.SSLContext");
+    }
+
+    public String getImplementationName(){
+      return "PureTLS";
+    }
+      
+    public ServerSocketFactory getServerSocketFactory()
+    {
+	return new PureTLSSocketFactory();
+    } 
+
+    public SSLSupport getSSLSupport(Socket s)
+    {
+	return new PureTLSSupport((SSLSocket)s);
+    }
+
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/net/puretls/PureTLSSocket.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/net/puretls/PureTLSSocket.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/net/puretls/PureTLSSocket.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,42 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.net.puretls;
+
+import java.io.IOException;
+
+/*
+ * PureTLSSocket.java
+ *
+ * Wraps COM.claymoresystems.ptls.SSLSocket
+ *
+ * This class translates PureTLS's interfaces into those
+ * expected by Tomcat
+ *
+ * @author Eric Rescorla
+ *
+ */
+
+public class PureTLSSocket extends COM.claymoresystems.ptls.SSLSocket
+{
+    // The only constructor we need here is the no-arg
+    // constructor since this class is only used with
+    // implAccept
+    public PureTLSSocket() throws IOException {
+	super();
+    }
+}
+ 

Added: branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/net/puretls/PureTLSSocketFactory.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/net/puretls/PureTLSSocketFactory.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/net/puretls/PureTLSSocketFactory.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,229 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.net.puretls;
+
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.net.SocketException;
+import java.util.Vector;
+
+import COM.claymoresystems.ptls.SSLContext;
+import COM.claymoresystems.ptls.SSLException;
+import COM.claymoresystems.ptls.SSLServerSocket;
+import COM.claymoresystems.ptls.SSLSocket;
+import COM.claymoresystems.sslg.SSLPolicyInt;
+
+/**
+ * SSL server socket factory--wraps PureTLS
+ *
+ * @author Eric Rescorla
+ *
+ * some sections of this file cribbed from SSLSocketFactory
+ * (the JSSE socket factory)
+ *
+ */
+ 
+public class PureTLSSocketFactory
+    extends org.apache.tomcat.util.net.ServerSocketFactory
+{
+    static org.apache.commons.logging.Log logger =
+	org.apache.commons.logging.LogFactory.getLog(PureTLSSocketFactory.class);
+    static String defaultProtocol = "TLS";
+    static boolean defaultClientAuth = false;
+    static String defaultKeyStoreFile = "server.pem";
+    static String defaultKeyPass = "password";    
+    static String defaultRootFile = "root.pem";
+    static String defaultRandomFile = "random.pem";
+    
+    private COM.claymoresystems.ptls.SSLContext context=null;
+    
+    public PureTLSSocketFactory() {
+    }
+
+    public ServerSocket createSocket(int port)
+	throws IOException
+    {
+	init();
+	return new SSLServerSocket(context,port);
+    }
+
+    public ServerSocket createSocket(int port, int backlog)
+	throws IOException
+    {
+	init();
+	ServerSocket tmp;
+	
+	try {
+	    tmp=new SSLServerSocket(context,port,backlog);
+	}
+	catch (IOException e){
+	    throw e;
+	}
+	return tmp;
+    }
+
+    public ServerSocket createSocket(int port, int backlog,
+				     InetAddress ifAddress)
+	throws IOException
+    {
+	init();
+	return new SSLServerSocket(context,port,backlog,ifAddress);
+    }
+
+    private void init()
+	throws IOException
+    {
+	if(context!=null)
+	    return;
+	
+	boolean clientAuth=defaultClientAuth;
+
+	try {
+	    String keyStoreFile=(String)attributes.get("keystore");
+	    if(keyStoreFile==null) keyStoreFile=defaultKeyStoreFile;
+	    
+	    String keyPass=(String)attributes.get("keypass");
+	    if(keyPass==null) keyPass=defaultKeyPass;
+	    
+	    String rootFile=(String)attributes.get("rootfile");
+	    if(rootFile==null) rootFile=defaultRootFile;
+
+	    String randomFile=(String)attributes.get("randomfile");
+	    if(randomFile==null) randomFile=defaultRandomFile;
+	    
+	    String protocol=(String)attributes.get("protocol");
+	    if(protocol==null) protocol=defaultProtocol;
+
+	    String clientAuthStr=(String)attributes.get("clientauth");
+	    if(clientAuthStr != null){
+		if(clientAuthStr.equals("true")){
+		    clientAuth=true;
+		} else if(clientAuthStr.equals("false")) {
+		    clientAuth=false;
+		} else {
+		    throw new IOException("Invalid value '" +
+					  clientAuthStr + 
+					  "' for 'clientauth' parameter:");
+		}
+	    }
+
+            SSLContext tmpContext=new SSLContext();
+            try {
+                tmpContext.loadRootCertificates(rootFile);
+            } catch(IOException iex) {
+                if(logger.isDebugEnabled())
+                    logger.debug("Error loading Client Root Store: " + 
+                                 rootFile,iex);
+            }
+            tmpContext.loadEAYKeyFile(keyStoreFile,keyPass);
+	    tmpContext.useRandomnessFile(randomFile,keyPass);
+	    
+	    SSLPolicyInt policy=new SSLPolicyInt();
+	    policy.requireClientAuth(clientAuth);
+            policy.handshakeOnConnect(false);
+            policy.waitOnClose(false);
+            short [] enabledCiphers = getEnabledCiphers(policy.getCipherSuites());
+            if( enabledCiphers != null ) {
+                policy.setCipherSuites(enabledCiphers);
+            }
+            tmpContext.setPolicy(policy);
+	    context=tmpContext;
+	} catch (Exception e){
+	    logger.info("Error initializing SocketFactory",e);
+	    throw new IOException(e.getMessage());
+	}
+    }
+
+    /*
+     * Determines the SSL cipher suites to be enabled.
+     *
+     * @return Array of SSL cipher suites to be enabled, or null if the
+     * cipherSuites property was not specified (meaning that all supported
+     * cipher suites are to be enabled)
+     */
+    private short [] getEnabledCiphers(short [] supportedCiphers) {
+
+        short [] enabledCiphers = null;
+
+        String attrValue = (String)attributes.get("ciphers");
+        if (attrValue != null) {
+            Vector vec = null;
+            int fromIndex = 0;
+            int index = attrValue.indexOf(',', fromIndex);
+            while (index != -1) {
+                String cipher = attrValue.substring(fromIndex, index).trim();
+                int cipherValue = SSLPolicyInt.getCipherSuiteNumber(cipher);                
+                /*
+                 * Check to see if the requested cipher is among the supported
+                 * ciphers, i.e., may be enabled
+                 */
+                if( cipherValue >= 0) {
+                    for (int i=0; supportedCiphers != null
+                             && i<supportedCiphers.length; i++) {
+
+                        if (cipherValue == supportedCiphers[i]) {
+                            if (vec == null) {
+                                vec = new Vector();
+                            }
+                            vec.addElement(new Integer(cipherValue));
+                            break;
+                        }
+                    }
+                }
+                fromIndex = index+1;
+                index = attrValue.indexOf(',', fromIndex);
+            }
+
+            if (vec != null) {
+                int nCipher = vec.size();
+                enabledCiphers = new short[nCipher];
+                for(int i=0; i < nCipher; i++) {
+                    Integer value = (Integer)vec.elementAt(i);
+                    enabledCiphers[i] = value.shortValue();
+                }
+            }
+        }
+
+        return enabledCiphers;
+
+    }
+
+    public Socket acceptSocket(ServerSocket socket)
+	throws IOException
+    {
+	try {
+	    Socket sock=socket.accept();
+	    return sock;
+	} catch (SSLException e){
+            logger.debug("SSL handshake error",e);
+            throw new SocketException("SSL handshake error" + e.toString());
+	}
+    }
+
+    public void handshake(Socket sock)
+	 throws IOException
+    {
+	((SSLSocket)sock).handshake();
+    }
+}
+
+    
+    
+
+

Added: branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/net/puretls/PureTLSSupport.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/net/puretls/PureTLSSupport.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/net/puretls/PureTLSSupport.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,143 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.net.puretls;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+import java.util.Vector;
+
+import org.apache.tomcat.util.buf.HexUtils;
+import org.apache.tomcat.util.net.SSLSupport;
+
+import COM.claymoresystems.cert.X509Cert;
+import COM.claymoresystems.ptls.SSLSocket;
+import COM.claymoresystems.sslg.SSLPolicyInt;
+
+
+/* PureTLSSupport
+
+   Concrete implementation class for PureTLS
+   Support classes.
+
+   This will only work with JDK 1.2 and up since it
+   depends on JDK 1.2's certificate support
+
+   @author EKR
+*/
+
+class PureTLSSupport implements SSLSupport {
+    static org.apache.commons.logging.Log logger =
+	org.apache.commons.logging.LogFactory.getLog(PureTLSSupport.class);
+
+    private COM.claymoresystems.ptls.SSLSocket ssl;
+
+    PureTLSSupport(SSLSocket sock){
+        ssl=sock;
+    }
+
+    public String getCipherSuite() throws IOException {
+        int cs=ssl.getCipherSuite();
+        return SSLPolicyInt.getCipherSuiteName(cs);
+    }
+
+    public Object[] getPeerCertificateChain()
+        throws IOException {
+	return getPeerCertificateChain(false);
+    }
+
+    public Object[] getPeerCertificateChain(boolean force)
+        throws IOException {
+        Vector v=ssl.getCertificateChain();
+
+	if(v == null && force) {
+	    SSLPolicyInt policy=new SSLPolicyInt();
+	    policy.requireClientAuth(true);
+	    policy.handshakeOnConnect(false);
+	    policy.waitOnClose(false);
+	    ssl.renegotiate(policy);
+	    v = ssl.getCertificateChain();
+	}
+
+        if(v==null)
+            return null;
+        
+        java.security.cert.X509Certificate[] chain=
+            new java.security.cert.X509Certificate[v.size()];
+
+        try {
+          for(int i=1;i<=v.size();i++){
+            // PureTLS provides cert chains with the peer
+            // cert last but the Servlet 2.3 spec (S 4.7) requires
+            // the opposite order so we reverse the chain as we go
+            byte buffer[]=((X509Cert)v.elementAt(
+                 v.size()-i)).getDER();
+            
+            CertificateFactory cf =
+              CertificateFactory.getInstance("X.509");
+            ByteArrayInputStream stream =
+              new ByteArrayInputStream(buffer);
+
+            X509Certificate xCert = (X509Certificate)cf.generateCertificate(stream);
+            chain[i-1]= xCert;
+            if(logger.isTraceEnabled()) {
+		logger.trace("Cert # " + i + " = " + xCert);
+	    }
+          }
+        } catch (java.security.cert.CertificateException e) {
+	    logger.info("JDK's broken cert handling can't parse this certificate (which PureTLS likes)",e);
+            throw new IOException("JDK's broken cert handling can't parse this certificate (which PureTLS likes)");
+        }
+        return chain;
+    }
+
+    /**
+     * Lookup the symmetric key size.
+     */
+    public Integer getKeySize() 
+        throws IOException {
+
+        int cs=ssl.getCipherSuite();
+        String cipherSuite = SSLPolicyInt.getCipherSuiteName(cs);
+        int size = 0;
+        for (int i = 0; i < ciphers.length; i++) {
+            if (cipherSuite.indexOf(ciphers[i].phrase) >= 0) {
+                size = ciphers[i].keySize;
+                break;
+            }
+        }
+        Integer keySize = new Integer(size);
+        return keySize;
+    }
+
+    public String getSessionId()
+        throws IOException {
+        byte [] ssl_session = ssl.getSessionID();
+        if(ssl_session == null)
+            return null;
+        return HexUtils.convert(ssl_session);
+    }
+
+}
+
+
+
+
+
+
+

Added: branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/net/res/LocalStrings.properties
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/net/res/LocalStrings.properties	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/net/res/LocalStrings.properties	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,24 @@
+# net resources
+endpoint.err.fatal=Endpoint {0} shutdown due to exception: {1}
+endpoint.err.nonfatal=Endpoint {0} ignored exception: {1}
+endpoint.warn.reinit=Reinitializing ServerSocket
+endpoint.warn.restart=Restarting endpoint
+endpoint.warn.security=Endpoint {0} security exception: {1}
+endpoint.err.socket=Socket error caused by remote host {0}
+endpoint.err.handshake=Handshake failed
+endpoint.err.unexpected=Unexpected error processing socket
+endpoint.warn.nullSocket=Null socket returned by accept
+endpoint.debug.unlock=Caught exception trying to unlock accept on port {0}
+endpoint.err.close=Caught exception trying to close socket
+endpoint.noProcessor=No Processors - worker thread dead!
+
+endpoint.init.bind=Socket bind failed: [{0}] {1}
+endpoint.init.listen=Socket listen failed: [{0}] {1}
+endpoint.accept.fail=Socket accept failed
+endpoint.poll.limitedpollsize=Failed to create poller with specified size of {0}
+endpoint.poll.initfail=Poller creation failed
+endpoint.poll.fail=Critical poller failure (restarting poller): [{0}] {1}
+endpoint.poll.error=Unexpected poller error
+endpoint.sendfile.error=Unexpected sendfile error
+endpoint.sendfile.addfail=Sednfile failure: [{0}] {1}
+endpoint.sendfile.nosupport=Disabling sendfile, since either the APR version or the system doesn't support it

Added: branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/net/res/LocalStrings_es.properties
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/net/res/LocalStrings_es.properties	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/net/res/LocalStrings_es.properties	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,6 @@
+# net resources
+endpoint.err.fatal=Punto Final (Endpoint) {0} parado debido a excepción: {1}
+endpoint.err.nonfatal=El Punto Final (Endpoint) {0} ignoró excepción: {1}
+endpoint.warn.reinit=Reinicializando ServerSocket
+endpoint.warn.restart=Rearrancando punto final (endpoint)
+endpoint.warn.security=Punto Final (Endpoint) {0} con excepción de seguridad: {1}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/net/res/LocalStrings_fr.properties
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/net/res/LocalStrings_fr.properties	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/net/res/LocalStrings_fr.properties	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,6 @@
+# net resources
+endpoint.err.fatal=Le point de contact {0} a été éteint suite à l''exception{1}
+endpoint.err.nonfatal=Le point de contact {0} a ignoré l''exception: {1}
+endpoint.warn.reinit=Réinitialisation du ServerSocket
+endpoint.warn.restart=Redémarrage du point de contact
+

Added: branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/net/res/LocalStrings_ja.properties
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/net/res/LocalStrings_ja.properties	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/net/res/LocalStrings_ja.properties	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,6 @@
+# net resources
+endpoint.err.fatal=\u4f8b\u5916\u306e\u305f\u3081\u306b\u30a8\u30f3\u30c9\u30dd\u30a4\u30f3\u30c8 {0} \u306f\u30b7\u30e3\u30c3\u30c8\u30c0\u30a6\u30f3\u3057\u307e\u3059: {1}
+endpoint.err.nonfatal=\u30a8\u30f3\u30c9\u30dd\u30a4\u30f3\u30c8 {0} \u306f\u4f8b\u5916\u3092\u7121\u8996\u3057\u307e\u3057\u305f: {1}
+endpoint.warn.reinit=ServerSocket\u3092\u518d\u521d\u671f\u5316\u3057\u307e\u3059
+endpoint.warn.restart=\u30a8\u30f3\u30c9\u30dd\u30a4\u30f3\u30c8\u3092\u518d\u8d77\u52d5\u3057\u307e\u3059
+endpoint.warn.security=\u30a8\u30f3\u30c9\u30dd\u30a4\u30f3\u30c8 {0} \u306e\u30bb\u30ad\u30e5\u30ea\u30c6\u30a3\u4f8b\u5916\u3067\u3059: {1}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/res/StringManager.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/res/StringManager.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/res/StringManager.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,285 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.res;
+
+import java.text.MessageFormat;
+import java.util.Hashtable;
+import java.util.Locale;
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+
+/**
+ * An internationalization / localization helper class which reduces
+ * the bother of handling ResourceBundles and takes care of the
+ * common cases of message formating which otherwise require the
+ * creation of Object arrays and such.
+ *
+ * <p>The StringManager operates on a package basis. One StringManager
+ * per package can be created and accessed via the getManager method
+ * call.
+ *
+ * <p>The StringManager will look for a ResourceBundle named by
+ * the package name given plus the suffix of "LocalStrings". In
+ * practice, this means that the localized information will be contained
+ * in a LocalStrings.properties file located in the package
+ * directory of the classpath.
+ *
+ * <p>Please see the documentation for java.util.ResourceBundle for
+ * more information.
+ *
+ * @version $Revision: 299753 $ $Date: 2004-08-29 12:14:42 -0500 (Sun, 29 Aug 2004) $
+ *
+ * @author James Duncan Davidson [duncan at eng.sun.com]
+ * @author James Todd [gonzo at eng.sun.com]
+ * @author Mel Martinez [mmartinez at g1440.com]
+ * @see java.util.ResourceBundle
+ */
+
+public class StringManager {
+
+    /**
+     * The ResourceBundle for this StringManager.
+     */
+
+    private ResourceBundle bundle;
+    private Locale locale;
+
+    /**
+     * Creates a new StringManager for a given package. This is a
+     * private method and all access to it is arbitrated by the
+     * static getManager method call so that only one StringManager
+     * per package will be created.
+     *
+     * @param packageName Name of package to create StringManager for.
+     */
+
+    private StringManager(String packageName) {
+	this( packageName, Locale.getDefault() );
+    }
+
+    private StringManager(String packageName, Locale loc) {
+        String bundleName = packageName + ".LocalStrings";
+        bundle = ResourceBundle.getBundle(bundleName, loc);
+        // Get the actual locale, which may be different from the requested one
+        locale = bundle.getLocale();
+    }
+
+    private StringManager(ResourceBundle bundle )
+    {
+	this.bundle=bundle;
+        locale = bundle.getLocale();
+    }
+
+    /**
+        Get a string from the underlying resource bundle or return
+        null if the String is not found.
+     
+        @param key to desired resource String
+        @return resource String matching <i>key</i> from underlying
+                bundle or null if not found.
+        @throws IllegalArgumentException if <i>key</i> is null.        
+     */
+
+    public String getString(String key) {
+        if(key == null){
+            String msg = "key may not have a null value";
+
+            throw new IllegalArgumentException(msg);
+        }
+
+        String str = null;
+
+        try{
+	        str = bundle.getString(key);
+        }catch(MissingResourceException mre){
+            //bad: shouldn't mask an exception the following way:
+            //   str = "[cannot find message associated with key '" + key + "' due to " + mre + "]";
+	        //     because it hides the fact that the String was missing
+	        //     from the calling code.
+	        //good: could just throw the exception (or wrap it in another)
+	        //      but that would probably cause much havoc on existing
+	        //      code.
+	        //better: consistent with container pattern to
+	        //      simply return null.  Calling code can then do
+	        //      a null check.
+	        str = null;
+        }
+
+        return str;
+    }
+
+    /**
+     * Get a string from the underlying resource bundle and format
+     * it with the given set of arguments.
+     *
+     * @param key
+     * @param args
+     */
+
+    public String getString(String key, Object[] args) {
+        String iString = null;
+        String value = getString(key);
+
+        // this check for the runtime exception is some pre 1.1.6
+        // VM's don't do an automatic toString() on the passed in
+        // objects and barf out
+
+        try {
+            // ensure the arguments are not null so pre 1.2 VM's don't barf
+            if(args==null){
+                args = new Object[1];
+            }
+            
+            Object[] nonNullArgs = args;
+            for (int i=0; i<args.length; i++) {
+                if (args[i] == null) {
+                    if (nonNullArgs==args){
+                        nonNullArgs=(Object[])args.clone();
+                    }
+                    nonNullArgs[i] = "null";
+                }
+            }
+            if( value==null ) value=key;
+	    MessageFormat mf = new MessageFormat(value);
+            mf.setLocale(locale);
+            iString = mf.format(nonNullArgs, new StringBuffer(), null).toString();
+        } catch (IllegalArgumentException iae) {
+            StringBuffer buf = new StringBuffer();
+            buf.append(value);
+            for (int i = 0; i < args.length; i++) {
+                buf.append(" arg[" + i + "]=" + args[i]);
+            }
+            iString = buf.toString();
+        }
+        return iString;
+    }
+
+    /**
+     * Get a string from the underlying resource bundle and format it
+     * with the given object argument. This argument can of course be
+     * a String object.
+     *
+     * @param key
+     * @param arg
+     */
+
+    public String getString(String key, Object arg) {
+	Object[] args = new Object[] {arg};
+	return getString(key, args);
+    }
+
+    /**
+     * Get a string from the underlying resource bundle and format it
+     * with the given object arguments. These arguments can of course
+     * be String objects.
+     *
+     * @param key
+     * @param arg1
+     * @param arg2
+     */
+
+    public String getString(String key, Object arg1, Object arg2) {
+	Object[] args = new Object[] {arg1, arg2};
+	return getString(key, args);
+    }
+    
+    /**
+     * Get a string from the underlying resource bundle and format it
+     * with the given object arguments. These arguments can of course
+     * be String objects.
+     *
+     * @param key
+     * @param arg1
+     * @param arg2
+     * @param arg3
+     */
+
+    public String getString(String key, Object arg1, Object arg2,
+			    Object arg3) {
+	Object[] args = new Object[] {arg1, arg2, arg3};
+	return getString(key, args);
+    }
+
+    /**
+     * Get a string from the underlying resource bundle and format it
+     * with the given object arguments. These arguments can of course
+     * be String objects.
+     *
+     * @param key
+     * @param arg1
+     * @param arg2
+     * @param arg3
+     * @param arg4
+     */
+
+    public String getString(String key, Object arg1, Object arg2,
+			    Object arg3, Object arg4) {
+	Object[] args = new Object[] {arg1, arg2, arg3, arg4};
+	return getString(key, args);
+    }
+    // --------------------------------------------------------------
+    // STATIC SUPPORT METHODS
+    // --------------------------------------------------------------
+
+    private static Hashtable managers = new Hashtable();
+
+    /**
+     * Get the StringManager for a particular package. If a manager for
+     * a package already exists, it will be reused, else a new
+     * StringManager will be created and returned.
+     *
+     * @param packageName The package name
+     */
+    public synchronized static StringManager getManager(String packageName) {
+      StringManager mgr = (StringManager)managers.get(packageName);
+      if (mgr == null) {
+          mgr = new StringManager(packageName);
+          managers.put(packageName, mgr);
+      }
+      return mgr;
+    }
+
+    /**
+     * Get the StringManager for a particular package. If a manager for
+     * a package already exists, it will be reused, else a new
+     * StringManager will be created and returned.
+     *
+     * @param bundle The resource bundle
+     */
+    public synchronized static StringManager getManager(ResourceBundle bundle) {
+      return new StringManager( bundle );
+    }
+
+    /**
+     * Get the StringManager for a particular package and Locale. If a manager for
+     * a package already exists, it will be reused, else a new
+     * StringManager will be created for that Locale and returned.
+     *
+     * @param packageName The package name
+     * @param loc The locale
+     */
+
+   public synchronized static StringManager getManager(String packageName,Locale loc) {
+      StringManager mgr = (StringManager)managers.get(packageName+"_"+loc.toString());
+      if (mgr == null) {
+          mgr = new StringManager(packageName,loc);
+          managers.put(packageName+"_"+loc.toString(), mgr);
+      }
+      return mgr;
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/threads/Expirer.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/threads/Expirer.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/threads/Expirer.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,155 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.threads;
+
+import org.apache.tomcat.util.buf.TimeStamp;
+
+/**
+ * Expire unused objects. 
+ * 
+ */
+public final class Expirer  implements ThreadPoolRunnable
+{
+    
+    private static org.apache.commons.logging.Log log=
+        org.apache.commons.logging.LogFactory.getLog(Expirer.class );
+    
+    // We can use Event/Listener, but this is probably simpler
+    // and more efficient
+    public static interface ExpireCallback {
+	public void expired( TimeStamp o );
+    }
+    
+    private int checkInterval = 60;
+    private Reaper reaper;
+    ExpireCallback expireCallback;
+
+    public Expirer() {
+    }
+
+    // ------------------------------------------------------------- Properties
+    public int getCheckInterval() {
+	return checkInterval;
+    }
+
+    public void setCheckInterval(int checkInterval) {
+	this.checkInterval = checkInterval;
+    }
+
+    public void setExpireCallback( ExpireCallback cb ) {
+	expireCallback=cb;
+    }
+    
+    // -------------------- Managed objects --------------------
+    static final int INITIAL_SIZE=8;
+    TimeStamp managedObjs[]=new TimeStamp[INITIAL_SIZE];
+    TimeStamp checkedObjs[]=new TimeStamp[INITIAL_SIZE];
+    int managedLen=managedObjs.length;
+    int managedCount=0;
+    
+    public void addManagedObject( TimeStamp ts ) {
+	synchronized( managedObjs ) {
+	    if( managedCount >= managedLen ) {
+		// What happens if expire is on the way ? Nothing,
+		// expire will do it's job on the old array ( GC magic )
+		// and the expired object will be marked as such
+		// Same thing would happen ( and did ) with Hashtable
+		TimeStamp newA[]=new TimeStamp[ 2 * managedLen ];
+		System.arraycopy( managedObjs, 0, newA, 0, managedLen);
+		managedObjs = newA;
+		managedLen = 2 * managedLen;
+	    }
+	    managedObjs[managedCount]=ts;
+	    managedCount++;
+	}
+    }
+
+    public void removeManagedObject( TimeStamp ts ) {
+	for( int i=0; i< managedCount; i++ ) {
+	    if( ts == managedObjs[i] ) {
+		synchronized( managedObjs ) {
+		    managedCount--;
+		    managedObjs[ i ] = managedObjs[managedCount];
+                    managedObjs[managedCount] = null;
+		}
+		return;
+	    }
+	}
+    }
+    
+    // --------------------------------------------------------- Public Methods
+
+    public void start() {
+	// Start the background reaper thread
+	if( reaper==null) {
+	    reaper=new Reaper("Expirer");
+	    reaper.addCallback( this, checkInterval * 1000 );
+	}
+	
+	reaper.startReaper();
+    }
+
+    public void stop() {
+	reaper.stopReaper();
+    }
+
+
+    // -------------------------------------------------------- Private Methods
+
+    // ThreadPoolRunnable impl
+
+    public Object[] getInitData() {
+	return null;
+    }
+
+    public void runIt( Object td[] ) {
+	long timeNow = System.currentTimeMillis();
+	if( log.isTraceEnabled() ) log.trace( "Checking " + timeNow );
+	int checkedCount;
+	synchronized( managedObjs ) {
+	    checkedCount=managedCount;
+	    if(checkedObjs.length < checkedCount)
+		checkedObjs = new TimeStamp[managedLen];
+	    System.arraycopy( managedObjs, 0, checkedObjs, 0, checkedCount);
+	}
+	for( int i=0; i< checkedCount; i++ ) {
+	    TimeStamp ts=checkedObjs[i];
+	    checkedObjs[i] = null;
+	    
+	    if (ts==null || !ts.isValid())
+		continue;
+	    
+	    long maxInactiveInterval = ts.getMaxInactiveInterval();
+	    if( log.isTraceEnabled() ) log.trace( "TS: " + maxInactiveInterval + " " +
+				ts.getLastAccessedTime());
+	    if (maxInactiveInterval < 0)
+		continue;
+	    
+	    long timeIdle = timeNow - ts.getThisAccessedTime();
+	    
+	    if (timeIdle >= maxInactiveInterval) {
+		if( expireCallback != null ) {
+		    if( log.isDebugEnabled() )
+			log.debug( ts + " " + timeIdle + " " +
+			       maxInactiveInterval );
+		    expireCallback.expired( ts );
+		}
+	    }
+	}
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/threads/Reaper.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/threads/Reaper.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/threads/Reaper.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,125 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.threads;
+
+
+/**
+ * The reaper is a background thread with which ticks every minute
+ * and calls registered objects to allow reaping of old session
+ * data.
+ * 
+ * @author James Duncan Davidson [duncan at eng.sun.com]
+ * @author Costin Manolache
+ */
+public class Reaper extends Thread {
+    
+    
+    private static org.apache.commons.logging.Log log=
+        org.apache.commons.logging.LogFactory.getLog(Reaper.class );
+    
+    private boolean daemon = false;
+
+    public Reaper() {
+        if (daemon)
+            this.setDaemon(true);
+        this.setName("TomcatReaper");
+    }
+
+    public Reaper(String name) {
+        if (daemon)
+            this.setDaemon(true);
+        this.setName(name);
+    }
+
+    private long interval = 1000 * 60; //ms
+
+    // XXX TODO Allow per/callback interval, find next, etc
+    // Right now the "interval" is used for all callbacks
+    // and it represent a sleep between runs.
+
+    ThreadPoolRunnable cbacks[] = new ThreadPoolRunnable[30]; // XXX max
+    Object tdata[][] = new Object[30][]; // XXX max
+    int count = 0;
+
+    /** Adding and removing callbacks is synchronized
+     */
+    Object lock = new Object();
+    static boolean running = true;
+
+    // XXX Should be called 'interval' not defaultInterval
+
+    public void setDefaultInterval(long t) {
+        interval = t;
+    }
+
+    public long getDefaultIntervale() {
+        return interval;
+    }
+
+    public int addCallback(ThreadPoolRunnable c, int interval) {
+        synchronized (lock) {
+            cbacks[count] = c;
+            count++;
+            return count - 1;
+        }
+    }
+
+    public void removeCallback(int idx) {
+        synchronized (lock) {
+            count--;
+            cbacks[idx] = cbacks[count];
+            cbacks[count] = null;
+        }
+    }
+
+    public void startReaper() {
+        running = true;
+        this.start();
+    }
+
+    public synchronized void stopReaper() {
+        running = false;
+        if (log.isDebugEnabled())
+            log.debug("Stop reaper ");
+        this.interrupt(); // notify() doesn't stop sleep
+    }
+
+    public void run() {
+        while (running) {
+            if (!running)
+                break;
+            try {
+                Thread.sleep(interval);
+            } catch (InterruptedException ie) {
+                // sometimes will happen
+            }
+
+            if (!running)
+                break;
+            for (int i = 0; i < count; i++) {
+                ThreadPoolRunnable callB = cbacks[i];
+                // it may be null if a callback is removed.
+                //  I think the code is correct
+                if (callB != null) {
+                    callB.runIt(tdata[i]);
+                }
+                if (!running)
+                    break;
+            }
+        }
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/threads/ThreadPool.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/threads/ThreadPool.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/threads/ThreadPool.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,838 @@
+/*
+ *  Copyright 1999-2005 The Apache Software Foundation
+ *
+ *  Licensed 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.threads;
+
+import java.util.*;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.tomcat.util.res.StringManager;
+
+/**
+ * A thread pool that is trying to copy the apache process management.
+ *
+ * Should we remove this in favor of Doug Lea's thread package?
+ *
+ * @author Gal Shachor
+ * @author Yoav Shapira <yoavs at apache.org>
+ */
+public class ThreadPool  {
+
+    private static Log log = LogFactory.getLog(ThreadPool.class);
+
+    private static StringManager sm =
+        StringManager.getManager("org.apache.tomcat.util.threads.res");
+
+    private static boolean logfull=true;
+
+    /*
+     * Default values ...
+     */
+    public static final int MAX_THREADS = 200;
+    public static final int MAX_THREADS_MIN = 10;
+    public static final int MAX_SPARE_THREADS = 50;
+    public static final int MIN_SPARE_THREADS = 4;
+    public static final int WORK_WAIT_TIMEOUT = 60*1000;
+
+    /*
+     * Where the threads are held.
+     */
+    protected ControlRunnable[] pool = null;
+
+    /*
+     * A monitor thread that monitors the pool for idel threads.
+     */
+    protected MonitorRunnable monitor;
+
+
+    /*
+     * Max number of threads that you can open in the pool.
+     */
+    protected int maxThreads;
+
+    /*
+     * Min number of idel threads that you can leave in the pool.
+     */
+    protected int minSpareThreads;
+
+    /*
+     * Max number of idel threads that you can leave in the pool.
+     */
+    protected int maxSpareThreads;
+
+    /*
+     * Number of threads in the pool.
+     */
+    protected int currentThreadCount;
+
+    /*
+     * Number of busy threads in the pool.
+     */
+    protected int currentThreadsBusy;
+
+    /*
+     * Flag that the pool should terminate all the threads and stop.
+     */
+    protected boolean stopThePool;
+
+    /* Flag to control if the main thread is 'daemon' */
+    protected boolean isDaemon=true;
+
+    /** The threads that are part of the pool.
+     * Key is Thread, value is the ControlRunnable
+     */
+    protected Hashtable threads=new Hashtable();
+
+    protected Vector listeners=new Vector();
+
+    /** Name of the threadpool
+     */
+    protected String name = "TP";
+
+    /**
+     * Sequence.
+     */
+    protected int sequence = 1;
+
+    /**
+     * Thread priority.
+     */
+    protected int threadPriority = Thread.NORM_PRIORITY;
+
+
+    /**
+     * Constructor.
+     */    
+    public ThreadPool() {
+        maxThreads = MAX_THREADS;
+        maxSpareThreads = MAX_SPARE_THREADS;
+        minSpareThreads = MIN_SPARE_THREADS;
+        currentThreadCount = 0;
+        currentThreadsBusy = 0;
+        stopThePool = false;
+    }
+
+
+    /** Create a ThreadPool instance.
+     *
+     * @param jmx UNUSED 
+     * @return ThreadPool instance. If JMX support is requested, you need to
+     *   call register() in order to set a name.
+     */
+    public static ThreadPool createThreadPool(boolean jmx) {
+        return new ThreadPool();
+    }
+
+    public synchronized void start() {
+	stopThePool=false;
+        currentThreadCount  = 0;
+        currentThreadsBusy  = 0;
+
+        adjustLimits();
+
+        pool = new ControlRunnable[maxThreads];
+
+        openThreads(minSpareThreads);
+        if (maxSpareThreads < maxThreads) {
+            monitor = new MonitorRunnable(this);
+        }
+    }
+
+    public MonitorRunnable getMonitor() {
+        return monitor;
+    }
+  
+    /**
+     * Sets the thread priority for current
+     * and future threads in this pool.
+     *
+     * @param threadPriority The new priority
+     * @throws IllegalArgumentException If the specified
+     *  priority is less than Thread.MIN_PRIORITY or
+     *  more than Thread.MAX_PRIORITY 
+     */
+    public synchronized void setThreadPriority(int threadPriority) {
+        if(log.isDebugEnabled())
+            log.debug(getClass().getName() +
+                      ": setPriority(" + threadPriority + "): here.");
+
+      if (threadPriority < Thread.MIN_PRIORITY) {
+        throw new IllegalArgumentException("new priority < MIN_PRIORITY");
+      } else if (threadPriority > Thread.MAX_PRIORITY) {
+        throw new IllegalArgumentException("new priority > MAX_PRIORITY");
+      }
+
+      // Set for future threads
+      this.threadPriority = threadPriority;
+
+      Enumeration currentThreads = getThreads();
+      Thread t = null;
+      while(currentThreads.hasMoreElements()) {
+        t = (Thread) currentThreads.nextElement();
+        t.setPriority(threadPriority);
+      } 
+    }
+
+    /**
+     * Returns the priority level of current and
+     * future threads in this pool.
+     *
+     * @return The priority
+     */
+    public int getThreadPriority() {
+      return threadPriority;
+    }   
+     
+
+    public void setMaxThreads(int maxThreads) {
+        this.maxThreads = maxThreads;
+    }
+
+    public int getMaxThreads() {
+        return maxThreads;
+    }
+
+    public void setMinSpareThreads(int minSpareThreads) {
+        this.minSpareThreads = minSpareThreads;
+    }
+
+    public int getMinSpareThreads() {
+        return minSpareThreads;
+    }
+
+    public void setMaxSpareThreads(int maxSpareThreads) {
+        this.maxSpareThreads = maxSpareThreads;
+    }
+
+    public int getMaxSpareThreads() {
+        return maxSpareThreads;
+    }
+
+    public int getCurrentThreadCount() {
+        return currentThreadCount;
+    }
+
+    public int getCurrentThreadsBusy() {
+        return currentThreadsBusy;
+    }
+
+    public boolean isDaemon() {
+        return isDaemon;
+    }
+
+    public static int getDebug() {
+        return 0;
+    }
+
+    /** The default is true - the created threads will be
+     *  in daemon mode. If set to false, the control thread
+     *  will not be daemon - and will keep the process alive.
+     */
+    public void setDaemon( boolean b ) {
+        isDaemon=b;
+    }
+    
+    public boolean getDaemon() {
+        return isDaemon;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public int getSequence() {
+        return sequence++;
+    }
+
+    public void addThread( Thread t, ControlRunnable cr ) {
+        threads.put( t, cr );
+        for( int i=0; i<listeners.size(); i++ ) {
+            ThreadPoolListener tpl=(ThreadPoolListener)listeners.elementAt(i);
+            tpl.threadStart(this, t);
+        }
+    }
+
+    public void removeThread( Thread t ) {
+        threads.remove(t);
+        for( int i=0; i<listeners.size(); i++ ) {
+            ThreadPoolListener tpl=(ThreadPoolListener)listeners.elementAt(i);
+            tpl.threadEnd(this, t);
+        }
+    }
+
+    public void addThreadPoolListener( ThreadPoolListener tpl ) {
+        listeners.addElement( tpl );
+    }
+
+    public Enumeration getThreads(){
+        return threads.keys();
+    }
+
+    public void run(Runnable r) {
+        ControlRunnable c = findControlRunnable();
+        c.runIt(r);
+    }    
+    
+    //
+    // You may wonder what you see here ... basically I am trying
+    // to maintain a stack of threads. This way locality in time
+    // is kept and there is a better chance to find residues of the
+    // thread in memory next time it runs.
+    //
+
+    /**
+     * Executes a given Runnable on a thread in the pool, block if needed.
+     */
+    public void runIt(ThreadPoolRunnable r) {
+        if(null == r) {
+            throw new NullPointerException();
+        }
+
+        ControlRunnable c = findControlRunnable();
+        c.runIt(r);
+    }
+
+    private ControlRunnable findControlRunnable() {
+        ControlRunnable c=null;
+
+        if ( stopThePool ) {
+            throw new IllegalStateException();
+        }
+
+        // Obtain a free thread from the pool.
+        synchronized(this) {
+
+            while (currentThreadsBusy == currentThreadCount) {
+                 // All threads are busy
+                if (currentThreadCount < maxThreads) {
+                    // Not all threads were open,
+                    // Open new threads up to the max number of idel threads
+                    int toOpen = currentThreadCount + minSpareThreads;
+                    openThreads(toOpen);
+                } else {
+                    logFull(log, currentThreadCount, maxThreads);
+                    // Wait for a thread to become idel.
+                    try {
+                        this.wait();
+                    }
+                    // was just catch Throwable -- but no other
+                    // exceptions can be thrown by wait, right?
+                    // So we catch and ignore this one, since
+                    // it'll never actually happen, since nowhere
+                    // do we say pool.interrupt().
+                    catch(InterruptedException e) {
+                        log.error("Unexpected exception", e);
+                    }
+		    if( log.isDebugEnabled() ) {
+			log.debug("Finished waiting: CTC="+currentThreadCount +
+				  ", CTB=" + currentThreadsBusy);
+                    }
+                    // Pool was stopped. Get away of the pool.
+                    if( stopThePool) {
+                        break;
+                    }
+                }
+            }
+            // Pool was stopped. Get away of the pool.
+            if(0 == currentThreadCount || stopThePool) {
+                throw new IllegalStateException();
+            }
+                    
+            // If we are here it means that there is a free thread. Take it.
+            int pos = currentThreadCount - currentThreadsBusy - 1;
+            c = pool[pos];
+            pool[pos] = null;
+            currentThreadsBusy++;
+
+        }
+        return c;
+    }
+
+    private static void logFull(Log loghelper, int currentThreadCount,
+                                int maxThreads) {
+	if( logfull ) {
+            log.error(sm.getString("threadpool.busy",
+                                   new Integer(currentThreadCount),
+                                   new Integer(maxThreads)));
+            logfull=false;
+        } else if( log.isDebugEnabled() ) {
+            log.debug("All threads are busy " + currentThreadCount + " " +
+                      maxThreads );
+        }
+    }
+
+    /**
+     * Stop the thread pool
+     */
+    public synchronized void shutdown() {
+        if(!stopThePool) {
+            stopThePool = true;
+            if (monitor != null) {
+                monitor.terminate();
+                monitor = null;
+            }
+            for(int i = 0; i < currentThreadCount - currentThreadsBusy; i++) {
+                try {
+                    pool[i].terminate();
+                } catch(Throwable t) {
+                    /*
+		     * Do nothing... The show must go on, we are shutting
+		     * down the pool and nothing should stop that.
+		     */
+		    log.error("Ignored exception while shutting down thread pool", t);
+                }
+            }
+            currentThreadsBusy = currentThreadCount = 0;
+            pool = null;
+            notifyAll();
+        }
+    }
+
+    /**
+     * Called by the monitor thread to harvest idle threads.
+     */
+    protected synchronized void checkSpareControllers() {
+
+        if(stopThePool) {
+            return;
+        }
+
+        if((currentThreadCount - currentThreadsBusy) > maxSpareThreads) {
+            int toFree = currentThreadCount -
+                         currentThreadsBusy -
+                         maxSpareThreads;
+
+            for(int i = 0 ; i < toFree ; i++) {
+                ControlRunnable c = pool[currentThreadCount - currentThreadsBusy - 1];
+                c.terminate();
+                pool[currentThreadCount - currentThreadsBusy - 1] = null;
+                currentThreadCount --;
+            }
+
+        }
+
+    }
+
+    /**
+     * Returns the thread to the pool.
+     * Called by threads as they are becoming idel.
+     */
+    protected synchronized void returnController(ControlRunnable c) {
+
+        if(0 == currentThreadCount || stopThePool) {
+            c.terminate();
+            return;
+        }
+
+        // atomic
+        currentThreadsBusy--;
+
+        pool[currentThreadCount - currentThreadsBusy - 1] = c;
+        notify();
+    }
+
+    /**
+     * Inform the pool that the specific thread finish.
+     *
+     * Called by the ControlRunnable.run() when the runnable
+     * throws an exception.
+     */
+    protected synchronized void notifyThreadEnd(ControlRunnable c) {
+        currentThreadsBusy--;
+        currentThreadCount --;
+        notify();
+    }
+
+
+    /*
+     * Checks for problematic configuration and fix it.
+     * The fix provides reasonable settings for a single CPU
+     * with medium load.
+     */
+    protected void adjustLimits() {
+        if(maxThreads <= 0) {
+            maxThreads = MAX_THREADS;
+        } else if (maxThreads < MAX_THREADS_MIN) {
+            log.warn(sm.getString("threadpool.max_threads_too_low",
+                                  new Integer(maxThreads),
+                                  new Integer(MAX_THREADS_MIN)));
+            maxThreads = MAX_THREADS_MIN;
+        }
+
+        if(maxSpareThreads >= maxThreads) {
+            maxSpareThreads = maxThreads;
+        }
+
+        if(maxSpareThreads <= 0) {
+            if(1 == maxThreads) {
+                maxSpareThreads = 1;
+            } else {
+                maxSpareThreads = maxThreads/2;
+            }
+        }
+
+        if(minSpareThreads >  maxSpareThreads) {
+            minSpareThreads =  maxSpareThreads;
+        }
+
+        if(minSpareThreads <= 0) {
+            if(1 == maxSpareThreads) {
+                minSpareThreads = 1;
+            } else {
+                minSpareThreads = maxSpareThreads/2;
+            }
+        }
+    }
+
+    /** Create missing threads.
+     *
+     * @param toOpen Total number of threads we'll have open
+     */
+    protected void openThreads(int toOpen) {
+
+        if(toOpen > maxThreads) {
+            toOpen = maxThreads;
+        }
+
+        for(int i = currentThreadCount ; i < toOpen ; i++) {
+            pool[i - currentThreadsBusy] = new ControlRunnable(this);
+        }
+
+        currentThreadCount = toOpen;
+    }
+
+    /** @deprecated */
+    void log( String s ) {
+	log.info(s);
+	//loghelper.flush();
+    }
+    
+    /** 
+     * Periodically execute an action - cleanup in this case
+     */
+    public static class MonitorRunnable implements Runnable {
+        ThreadPool p;
+        Thread     t;
+        int interval=WORK_WAIT_TIMEOUT;
+        boolean    shouldTerminate;
+
+        MonitorRunnable(ThreadPool p) {
+            this.p=p;
+            this.start();
+        }
+
+        public void start() {
+            shouldTerminate = false;
+            t = new Thread(this);
+            t.setDaemon(p.getDaemon() );
+	    t.setName(p.getName() + "-Monitor");
+            t.start();
+        }
+
+        public void setInterval(int i ) {
+            this.interval=i;
+        }
+
+        public void run() {
+            while(true) {
+                try {
+
+                    // Sleep for a while.
+                    synchronized(this) {
+                        this.wait(interval);
+                    }
+
+                    // Check if should terminate.
+                    // termination happens when the pool is shutting down.
+                    if(shouldTerminate) {
+                        break;
+                    }
+
+                    // Harvest idle threads.
+                    p.checkSpareControllers();
+
+                } catch(Throwable t) {
+		    ThreadPool.log.error("Unexpected exception", t);
+                }
+            }
+        }
+
+        public void stop() {
+            this.terminate();
+        }
+
+	/** Stop the monitor
+	 */
+        public synchronized void terminate() {
+            shouldTerminate = true;
+            this.notify();
+        }
+    }
+
+    /**
+     * A Thread object that executes various actions ( ThreadPoolRunnable )
+     *  under control of ThreadPool
+     */
+    public static class ControlRunnable implements Runnable {
+        /**
+	 * ThreadPool where this thread will be returned
+	 */
+        private ThreadPool p;
+
+	/**
+	 * The thread that executes the actions
+	 */
+        private ThreadWithAttributes     t;
+
+	/**
+	 * The method that is executed in this thread
+	 */
+        
+        private ThreadPoolRunnable   toRun;
+        private Runnable toRunRunnable;
+
+	/**
+	 * Stop this thread
+	 */
+	private boolean    shouldTerminate;
+
+	/**
+	 * Activate the execution of the action
+	 */
+        private boolean    shouldRun;
+
+	/**
+	 * Per thread data - can be used only if all actions are
+	 *  of the same type.
+	 *  A better mechanism is possible ( that would allow association of
+	 *  thread data with action type ), but right now it's enough.
+	 */
+	private boolean noThData;
+
+	/**
+	 * Start a new thread, with no method in it
+	 */
+        ControlRunnable(ThreadPool p) {
+            toRun = null;
+            shouldTerminate = false;
+            shouldRun = false;
+            this.p = p;
+            t = new ThreadWithAttributes(p, this);
+            t.setDaemon(true);
+            t.setName(p.getName() + "-Processor" + p.getSequence());
+            t.setPriority(p.getThreadPriority());
+            p.addThread( t, this );
+	    noThData=true;
+            t.start();
+        }
+
+        public void run() {
+            boolean _shouldRun = false;
+            boolean _shouldTerminate = false;
+            ThreadPoolRunnable _toRun = null;
+            try {
+                while (true) {
+                    try {
+                        /* Wait for work. */
+                        synchronized (this) {
+                            while (!shouldRun && !shouldTerminate) {
+                                this.wait();
+                            }
+                            _shouldRun = shouldRun;
+                            _shouldTerminate = shouldTerminate;
+                            _toRun = toRun;
+                        }
+
+                        if (_shouldTerminate) {
+                            if (ThreadPool.log.isDebugEnabled())
+                                ThreadPool.log.debug("Terminate");
+                            break;
+                        }
+
+                        /* Check if should execute a runnable.  */
+                        try {
+                            if (noThData) {
+                                if (_toRun != null) {
+                                    Object thData[] = _toRun.getInitData();
+                                    t.setThreadData(p, thData);
+                                    if (ThreadPool.log.isDebugEnabled())
+                                        ThreadPool.log.debug(
+                                            "Getting new thread data");
+                                }
+                                noThData = false;
+                            }
+
+                            if (_shouldRun) {
+                                if (_toRun != null) {
+                                    _toRun.runIt(t.getThreadData(p));
+                                } else if (toRunRunnable != null) {
+                                    toRunRunnable.run();
+                                } else {
+                                    if (ThreadPool.log.isDebugEnabled())
+                                    ThreadPool.log.debug("No toRun ???");
+                                }
+                            }
+                        } catch (Throwable t) {
+                            ThreadPool.log.error(sm.getString
+                                ("threadpool.thread_error", t, toRun.toString()));
+                            /*
+                             * The runnable throw an exception (can be even a ThreadDeath),
+                             * signalling that the thread die.
+                             *
+                            * The meaning is that we should release the thread from
+                            * the pool.
+                            */
+                            _shouldTerminate = true;
+                            _shouldRun = false;
+                            p.notifyThreadEnd(this);
+                        } finally {
+                            if (_shouldRun) {
+                                shouldRun = false;
+                                /*
+                                * Notify the pool that the thread is now idle.
+                                 */
+                                p.returnController(this);
+                            }
+                        }
+
+                        /*
+                        * Check if should terminate.
+                        * termination happens when the pool is shutting down.
+                        */
+                        if (_shouldTerminate) {
+                            break;
+                        }
+                    } catch (InterruptedException ie) { /* for the wait operation */
+                        // can never happen, since we don't call interrupt
+                        ThreadPool.log.error("Unexpected exception", ie);
+                    }
+                }
+            } finally {
+                p.removeThread(Thread.currentThread());
+            }
+        }
+        /** Run a task
+         *
+         * @param toRun
+         */
+        public synchronized void runIt(Runnable toRun) {
+	    this.toRunRunnable = toRun;
+	    // Do not re-init, the whole idea is to run init only once per
+	    // thread - the pool is supposed to run a single task, that is
+	    // initialized once.
+            // noThData = true;
+            shouldRun = true;
+            this.notify();
+        }
+
+        /** Run a task
+         *
+         * @param toRun
+         */
+        public synchronized void runIt(ThreadPoolRunnable toRun) {
+	    this.toRun = toRun;
+	    // Do not re-init, the whole idea is to run init only once per
+	    // thread - the pool is supposed to run a single task, that is
+	    // initialized once.
+            // noThData = true;
+            shouldRun = true;
+            this.notify();
+        }
+
+        public void stop() {
+            this.terminate();
+        }
+
+        public void kill() {
+            t.stop();
+        }
+
+        public synchronized void terminate() {
+            shouldTerminate = true;
+            this.notify();
+        }
+    }
+
+    /** 
+     * Debug display of the stage of each thread. The return is html style,
+     * for display in the console ( it can be easily parsed too ).
+     *
+     * @return The thread status display
+     */
+    public String threadStatusString() {
+        StringBuffer sb=new StringBuffer();
+        Iterator it=threads.keySet().iterator();
+        sb.append("<ul>");
+        while( it.hasNext()) {
+            sb.append("<li>");
+            ThreadWithAttributes twa=(ThreadWithAttributes)
+                    it.next();
+            sb.append(twa.getCurrentStage(this) ).append(" ");
+            sb.append( twa.getParam(this));
+            sb.append( "</li>\n");
+        }
+        sb.append("</ul>");
+        return sb.toString();
+    }
+
+    /** Return an array with the status of each thread. The status
+     * indicates the current request processing stage ( for tomcat ) or
+     * whatever the thread is doing ( if the application using TP provide
+     * this info )
+     *
+     * @return The status of all threads
+     */
+    public String[] getThreadStatus() {
+        String status[]=new String[ threads.size()];
+        Iterator it=threads.keySet().iterator();
+        for( int i=0; ( i<status.length && it.hasNext()); i++ ) {
+            ThreadWithAttributes twa=(ThreadWithAttributes)
+                    it.next();
+            status[i]=twa.getCurrentStage(this);
+        }
+        return status;
+    }
+
+    /** Return an array with the current "param" ( XXX better name ? )
+     * of each thread. This is typically the last request.
+     *
+     * @return The params of all threads
+     */
+    public String[] getThreadParam() {
+        String status[]=new String[ threads.size()];
+        Iterator it=threads.keySet().iterator();
+        for( int i=0; ( i<status.length && it.hasNext()); i++ ) {
+            ThreadWithAttributes twa=(ThreadWithAttributes)
+                    it.next();
+            Object o=twa.getParam(this);
+            status[i]=(o==null)? null : o.toString();
+        }
+        return status;
+    }
+    
+    /** Interface to allow applications to be notified when
+     * a threads are created and stopped.
+     */
+    public static interface ThreadPoolListener {
+        public void threadStart( ThreadPool tp, Thread t);
+
+        public void threadEnd( ThreadPool tp, Thread t);
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/threads/ThreadPoolRunnable.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/threads/ThreadPoolRunnable.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/threads/ThreadPoolRunnable.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,38 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.threads;
+
+
+/** Implemented if you want to run a piece of code inside a thread pool.
+ */
+public interface ThreadPoolRunnable {
+    // XXX use notes or a hashtable-like
+    // Important: ThreadData in JDK1.2 is implemented as a Hashtable( Thread -> object ),
+    // expensive.
+    
+    /** Called when this object is first loaded in the thread pool.
+     *  Important: all workers in a pool must be of the same type,
+     *  otherwise the mechanism becomes more complex.
+     */
+    public Object[] getInitData();
+
+    /** This method will be executed in one of the pool's threads. The
+     *  thread will be returned to the pool.
+     */
+    public void runIt(Object thData[]);
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/threads/ThreadWithAttributes.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/threads/ThreadWithAttributes.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/threads/ThreadWithAttributes.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,100 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.threads;
+
+import java.util.Hashtable;
+
+/** Special thread that allows storing of attributes and notes.
+ *  A guard is used to prevent untrusted code from accessing the
+ *  attributes.
+ *
+ *  This avoids hash lookups and provide something very similar
+ * with ThreadLocal ( but compatible with JDK1.1 and faster on
+ * JDK < 1.4 ).
+ *
+ * The main use is to store 'state' for monitoring ( like "processing
+ * request 'GET /' ").
+ */
+public class ThreadWithAttributes extends Thread {
+    
+    private Object control;
+    public static int MAX_NOTES=16;
+    private Object notes[]=new Object[MAX_NOTES];
+    private Hashtable attributes=new Hashtable();
+    private String currentStage;
+    private Object param;
+    
+    private Object thData[];
+
+    public ThreadWithAttributes(Object control, Runnable r) {
+        super(r);
+        this.control=control;
+    }
+    
+    public final Object[] getThreadData(Object control ) {
+        return thData;
+    }
+    
+    public final void setThreadData(Object control, Object thData[] ) {
+        this.thData=thData;
+    }
+
+    /** Notes - for attributes that need fast access ( array )
+     * The application is responsible for id management
+     */
+    public final void setNote( Object control, int id, Object value ) {
+        if( this.control != control ) return;
+        notes[id]=value;
+    }
+
+    /** Information about the curent performed operation
+     */
+    public final String getCurrentStage(Object control) {
+        if( this.control != control ) return null;
+        return currentStage;
+    }
+
+    /** Information about the current request ( or the main object
+     * we are processing )
+     */
+    public final Object getParam(Object control) {
+        if( this.control != control ) return null;
+        return param;
+    }
+
+    public final void setCurrentStage(Object control, String currentStage) {
+        if( this.control != control ) return;
+        this.currentStage = currentStage;
+    }
+
+    public final void setParam( Object control, Object param ) {
+        if( this.control != control ) return;
+        this.param=param;
+    }
+
+    public final Object getNote(Object control, int id ) {
+        if( this.control != control ) return null;
+        return notes[id];
+    }
+
+    /** Generic attributes. You'll need a hashtable lookup -
+     * you can use notes for array access.
+     */
+    public final Hashtable getAttributes(Object control) {
+        return attributes;
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/threads/res/LocalStrings.properties
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/threads/res/LocalStrings.properties	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/threads/res/LocalStrings.properties	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,3 @@
+threadpool.busy=All threads ({0}) are currently busy, waiting. Increase maxThreads ({1}) or check the servlet status
+threadpool.max_threads_too_low=maxThreads setting ({0}) too low, set to {1}
+threadpool.thread_error=Caught exception ({0}) executing {1}, terminating thread

Added: branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/threads/res/LocalStrings_es.properties
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/threads/res/LocalStrings_es.properties	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/threads/res/LocalStrings_es.properties	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,3 @@
+threadpool.busy=Todos los hilos ({0}) están ahora ocupados, esperando. Incremente maxThreads ({1}) o revise el estado del servlet
+threadpool.max_threads_too_low=valor de maxThreads ({0}) demasiado bajo, puesto a {1}
+threadpool.thread_error=Cogida excepción ({0}) ejecutando {1}, terminando hilo

Added: branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/threads/res/LocalStrings_fr.properties
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/threads/res/LocalStrings_fr.properties	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/threads/res/LocalStrings_fr.properties	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,3 @@
+threadpool.busy=Tous les threads ({0}) sont actuellement occupés, attente. Augmentez maxThreads ({1}) ou vérifiez le servlet status
+threadpool.max_threads_too_low=le réglage maxThreads ({0}) est trop bas, mis à {1}
+threadpool.thread_error=Réception d''une exception ({0}) en exécutant {1}, arrêt du thread

Added: branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/threads/res/LocalStrings_ja.properties
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/threads/res/LocalStrings_ja.properties	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/util/java/org/apache/tomcat/util/threads/res/LocalStrings_ja.properties	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,3 @@
+threadpool.busy=\u3059\u3079\u3066\u306e\u30b9\u30ec\u30c3\u30c9 ({0}) \u304c\u73fe\u5728\u7a3c\u50cd\u4e2d\u3067\u5f85\u6a5f\u3057\u3066\u3044\u307e\u3059\u3002maxThreads ({1}) \u3092\u5897\u3084\u3059\u304b\u3001\u305d\u306e\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8\u306e\u30b9\u30c6\u30fc\u30bf\u30b9\u3092\u30c1\u30a7\u30c3\u30af\u3057\u3066\u304f\u3060\u3055\u3044
+threadpool.max_threads_too_low=maxThreads\u306e\u8a2d\u5b9a ({0}) \u304c\u5c0f\u3055\u3059\u304e\u308b\u306e\u3067\u3001{1}\u306b\u8a2d\u5b9a\u3057\u3066\u304f\u3060\u3055\u3044
+threadpool.thread_error={1} \u3092\u5b9f\u884c\u4e2d\u306b\u4f8b\u5916 ({0}) \u3092\u30ad\u30e3\u30c3\u30c1\u3057\u305f\u306e\u3067\u3001\u30b9\u30ec\u30c3\u30c9\u3092\u7d42\u4e86\u3057\u307e\u3059

Added: branches/tomcat5.5/upstream/5.5.20/connectors/util/java/tomcat-util.manifest
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/util/java/tomcat-util.manifest	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/util/java/tomcat-util.manifest	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,7 @@
+Manifest-version: 1.0
+Extension-Name: org.apache.tomcat.util
+Specification-Vendor: Apache Software Foundation
+Specification-Version: 3.0
+Implementation-Vendor-Id: org.apache
+Implementation-Vendor: Apache Software Foundation
+Implementation-Version: 5.1

Added: branches/tomcat5.5/upstream/5.5.20/connectors/util/loader/loader.properties
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/util/loader/loader.properties	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/util/loader/loader.properties	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,110 @@
+catalina.home=/opt/50
+
+loader.auto-startup=org.apache.tomcat.util.jmx.JmxRemoteLoader,\
+             org.apache.catalina.startup.CatalinaModuleListener
+
+#
+# List of comma-separated packages that start with or equal this string
+# will cause a security exception to be thrown when
+# passed to checkPackageAccess unless the
+# corresponding RuntimePermission ("accessClassInPackage."+package) has
+# been granted.
+loader.package.access=sun.,org.apache.catalina.,org.apache.coyote.,org.apache.tomcat.,org.apache.jasper.,sun.beans.
+#
+# List of comma-separated packages that start with or equal this string
+# will cause a security exception to be thrown when
+# passed to checkPackageDefinition unless the
+# corresponding RuntimePermission ("defineClassInPackage."+package) has
+# been granted.
+#
+# by default, no packages are restricted for definition, and none of
+# the class loaders supplied with the JDK call checkPackageDefinition.
+#
+loader.package.definition=sun.,java.,org.apache.catalina.,org.apache.coyote.,org.apache.tomcat.,org.apache.jasper.
+
+#
+#
+# List of comma-separated paths defining the contents of the "common" 
+# classloader. Prefixes should be used to define what is the repository type.
+# Path may be relative to the CATALINA_HOME or CATALINA_BASE path or absolute.
+# If left as blank,the JVM system loader will be used as Catalina's "common" 
+# loader.
+# Examples:
+#     "foo": Add this folder as a class repository
+#     "foo/*.jar": Add all the JARs of the specified folder as class 
+#                  repositories
+#     "foo/bar.jar": Add bar.jar as a class repository
+common.loader=${catalina.home}/bin/jmx.jar,\
+    ${catalina.home}/common/classes,\
+    ${catalina.home}/common/i18n/tomcat-i18n-en.jar,${catalina.home}/common/endorsed/*.jar,${catalina.home}/common/lib/*.jar
+
+#
+# List of comma-separated paths defining the contents of the "server" 
+# classloader. Prefixes should be used to define what is the repository type.
+# Path may be relative to the CATALINA_HOME or CATALINA_BASE path or absolute.
+# If left as blank, the "common" loader will be used as Catalina's "server" 
+# loader.
+# Examples:
+#     "foo": Add this folder as a class repository
+#     "foo/*.jar": Add all the JARs of the specified folder as class 
+#                  repositories
+#     "foo/bar.jar": Add bar.jar as a class repository
+server.loader=/ws/apache/jakarta-tomcat-connectors/util/build/classes,/ws/apache/jakarta-tomcat-catalina/build/classes,/ws/apache/jakarta-tomcat-connectors/build/classes,${catalina.home}/server/lib/commons-modeler.jar
+
+#
+# List of comma-separated paths defining the contents of the "shared" 
+# classloader. Prefixes should be used to define what is the repository type.
+# Path may be relative to the CATALINA_BASE path or absolute. If left as blank,
+# the "common" loader will be used as Catalina's "shared" loader.
+# Examples:
+#     "foo": Add this folder as a class repository
+#     "foo/*.jar": Add all the JARs of the specified folder as class 
+#                  repositories
+#     "foo/bar.jar": Add bar.jar as a class repository 
+shared.loader=${catalina.base}/shared/classes,${catalina.base}/shared/lib/*.jar
+
+# Classes to preload to avoid security exceptions
+loader.security.preload=\
+             org.apache.catalina.core.ApplicationContextFacade$1,\
+             org.apache.catalina.core.ApplicationDispatcher$PrivilegedForward,\
+             org.apache.catalina.core.ApplicationDispatcher$PrivilegedInclude,\
+             org.apache.catalina.core.ContainerBase$PrivilegedAddChild,\
+             org.apache.catalina.core.StandardWrapper$1,\
+             org.apache.catalina.loader.WebappClassLoader$PrivilegedFindResource,\
+             org.apache.catalina.session.StandardSession,\
+             org.apache.catalina.session.StandardSession$1,\
+             org.apache.catalina.session.StandardManager$PrivilegedDoUnload,\
+             org.apache.catalina.util.URL,\
+             org.apache.catalina.util.Enumerator,\
+             javax.servlet.http.Cookie,\
+            org.apache.coyote.http11Http11Processor$1,\
+            org.apache.coyote.http11InternalOutputBuffer$1,\
+            org.apache.coyote.http11InternalOutputBuffer$2,\
+             org.apache.catalina.connector.RequestFacade$GetAttributePrivilegedAction,\
+             org.apache.catalina.connector.RequestFacade$GetParameterMapPrivilegedAction,\
+             org.apache.catalina.connector.RequestFacade$GetRequestDispatcherPrivilegedAction,\
+             org.apache.catalina.connector.RequestFacade$GetParameterPrivilegedAction,\
+             org.apache.catalina.connector.RequestFacade$GetParameterNamesPrivilegedAction,\
+             org.apache.catalina.connector.RequestFacade$GetParameterValuePrivilegedAction,\
+             org.apache.catalina.connector.RequestFacade$GetCharacterEncodingPrivilegedAction,\
+             org.apache.catalina.connector.RequestFacade$GetHeadersPrivilegedAction,\
+             org.apache.catalina.connector.RequestFacade$GetHeaderNamesPrivilegedAction,\  
+             org.apache.catalina.connector.RequestFacade$GetCookiesPrivilegedAction,\
+             org.apache.catalina.connector.RequestFacade$GetLocalePrivilegedAction,\
+             org.apache.catalina.connector.RequestFacade$GetLocalesPrivilegedAction,\
+             org.apache.catalina.connector.ResponseFacade$SetContentTypePrivilegedAction,\
+             org.apache.catalina.connector.ResponseFacade$DateHeaderPrivilegedAction,\
+             org.apache.catalina.connector.RequestFacade$GetSessionPrivilegedAction,\
+             org.apache.catalina.connector.ResponseFacade$1,\
+             org.apache.catalina.connector.OutputBuffer$1,\
+             org.apache.catalina.connector.CoyoteInputStream$1,\
+             org.apache.catalina.connector.CoyoteInputStream$2,\
+             org.apache.catalina.connector.CoyoteInputStream$3,\
+             org.apache.catalina.connector.CoyoteInputStream$4,\
+             org.apache.catalina.connector.CoyoteInputStream$5,\
+             org.apache.catalina.connector.InputBuffer$1,\
+             org.apache.catalina.connector.Response$1,\
+             org.apache.catalina.connector.Response$2,\
+             org.apache.catalina.connector.Response$3,\
+             org.apache.jk.server.JkCoyoteHandler$1,\
+             org.apache.jk.server.JkCoyoteHandler$StatusLinePrivilegedAction

Added: branches/tomcat5.5/upstream/5.5.20/connectors/util/loader/org/apache/tomcat/util/loader/Loader.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/util/loader/org/apache/tomcat/util/loader/Loader.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/util/loader/org/apache/tomcat/util/loader/Loader.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,881 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.loader;
+
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.InputStream;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Properties;
+import java.util.StringTokenizer;
+import java.util.Vector;
+
+
+/**
+ * Boostrap loader for Catalina or other java apps. 
+ * 
+ * This application constructs a class loader
+ * for use in loading the Catalina internal classes (by accumulating all of the
+ * JAR files found in the "server" directory under "catalina.home"), and
+ * starts the regular execution of the container.  The purpose of this
+ * roundabout approach is to keep the Catalina internal classes (and any
+ * other classes they depend on, such as an XML parser) out of the system
+ * class path and therefore not visible to application level classes.
+ *
+ *
+ * Merged with CatalinaProperties:
+ * Load a properties file describing the modules and startup sequence.
+ * This is responsible for configuration of the loader. 
+ * TODO: support jmx-style configuration, including persistence.
+ * TODO: better separate legacy config and the new style
+ * 
+ * The properties file will be named "loader.properties" or 
+ * "catalina.properties" ( for backwad compatibility ) and
+ * will be searched in:
+ *  - TODO 
+ * 
+ * Properties used:
+ *  - TODO
+ *
+ * loader.* and *.loader properties are used internally by the loader ( 
+ *  *.loader is for backward compat with catalina ).
+ * All other properties in the config file are set as System properties.
+ * 
+ * Based on o.a.catalina.bootstrap.CatalinaProperties - utility class to read 
+ * the bootstrap Catalina configuration.
+
+ *
+ * @author Craig R. McClanahan
+ * @author Remy Maucherat
+ * @author Costin Manolache
+ */ 
+public final class Loader  {
+
+    private static final boolean DEBUG=true; //LoaderProperties.getProperty("loader.debug.Loader") != null;
+    // If flat, only one loader is created. If false - one loader per jar/dir
+    private static final boolean FLAT=false;//LoaderProperties.getProperty("loader.Loader.flat") != null;
+    
+    // -------------------------------------------------------------- Constants
+
+
+    private static final String CATALINA_HOME_TOKEN = "${catalina.home}";
+    private static final String CATALINA_BASE_TOKEN = "${catalina.base}";
+
+
+    // ------------------------------------------------------- Static Variables
+
+
+    /**
+     * Daemon object used by main.
+     */
+    private static Loader daemon = null;
+
+    // one should be enough
+    ModuleListener listener;
+
+
+    // -------------------------------------------------------------- Variables
+
+    protected Repository commonRepository = null;
+    protected Repository catalinaRepository = null;
+    protected Repository sharedRepository = null;
+
+    protected ClassLoader catalinaLoader = null;
+    private String[] args;
+    private Hashtable repositories=new Hashtable();
+    private ClassLoader parentClassLoader;
+    
+    private static Properties properties = null;
+
+
+    private static String propFile;
+
+    // -------------------------------------------------------- Private Methods
+    
+    /** Set the parent class loader - can be used instead of setParent, 
+     * in case this is the top loader and needs to delagate to embedding app.
+     * The common loader will delegate to this loader
+     * 
+     * @param myL
+     */
+    public void setParentClassLoader(ClassLoader myL) {
+        this.parentClassLoader=myL;
+    }
+
+
+
+    /** Initialize the loader, creating all repositories.
+     *  Will create common, server, shared. 
+     *  
+     *  TODO: create additional repos.
+     *
+     */
+    public void init() {
+        try {
+            commonRepository = initRepository("common", null, parentClassLoader);
+            catalinaRepository = initRepository("server", commonRepository,null);
+            catalinaLoader = catalinaRepository.getClassLoader();
+            sharedRepository = initRepository("shared", commonRepository,null);
+        } catch (Throwable t) {
+            log("Class loader creation threw exception", t);
+            System.exit(1);
+        }
+    }
+
+    /** Create a new repository. 
+     *  No Module is added ( currently )
+     *  TODO: use props to prepopulate, if any is present.
+     * 
+     * @param name
+     * @param parent
+     * @return
+     */
+    public Repository createRepository(String name, Repository parent) {
+        Repository lg=new Repository(this);
+
+        lg.setName(name);
+       
+        lg.setParent( parent );
+        
+        repositories.put(name, lg);
+        
+        if( listener != null ) {
+            listener.repositoryAdd(lg);
+        }
+        return lg;
+    }
+
+    public Enumeration getRepositoryNames() {
+        return repositories.keys();
+    }
+    
+    /** Create a module using the NAME.loader property to construct the 
+     *  classpath.
+     * 
+     * @param name
+     * @param parent
+     * @return
+     * @throws Exception
+     */
+    private Repository initRepository(String name, Repository parent, ClassLoader pcl)
+        throws Exception 
+    {
+        String value = getProperty(name + ".loader");
+
+        Repository lg=createRepository(name, parent );
+        if( pcl != null )
+            lg.setParentClassLoader( pcl );
+        if( DEBUG ) log( "Creating loading group " + name + " - " + value + " " + pcl);
+        
+        if ((value == null) || (value.equals("")))
+            return lg;
+
+        ArrayList unpackedList = new ArrayList();
+        ArrayList packedList = new ArrayList();
+        ArrayList urlList = new ArrayList();
+
+        Vector repo=split( value );
+        Enumeration elems=repo.elements();
+        while (elems.hasMoreElements()) {
+            String repository = (String)elems.nextElement();
+
+            // Local repository
+            boolean packed = false;
+            
+            if (repository.startsWith(CATALINA_HOME_TOKEN)) {
+                repository = getCatalinaHome()
+                    + repository.substring(CATALINA_HOME_TOKEN.length());
+            } else if (repository.startsWith(CATALINA_BASE_TOKEN)) {
+                repository = getCatalinaBase()
+                    + repository.substring(CATALINA_BASE_TOKEN.length());
+            }
+
+            // Check for a JAR URL repository
+            try {
+                urlList.add(new URL(repository));
+                continue;
+            } catch (MalformedURLException e) {
+                // Ignore
+            }
+
+            if (repository.endsWith("*.jar")) {
+                packed = true;
+                repository = repository.substring
+                    (0, repository.length() - "*.jar".length());
+            }
+            if (packed) {
+                packedList.add(new File(repository));
+            } else {
+                unpackedList.add(new File(repository));
+            }
+        }
+
+        File[] unpacked = (File[]) unpackedList.toArray(new File[0]);
+        File[] packed = (File[]) packedList.toArray(new File[0]);
+        URL[] urls = (URL[]) urlList.toArray(new URL[0]);
+
+        // previously: ClassLoaderFactory.createClassLoader
+        initRepository(lg, unpacked, packed, urls, parent); //new ModuleGroup();
+        
+        
+        // TODO: JMX registration for the group loader 
+        /*
+        // Register the server classloader
+        ObjectName objectName =
+            new ObjectName("Catalina:type=ServerClassLoader,name=" + name);
+        mBeanServer.registerMBean(classLoader, objectName);
+        */
+        
+        return lg; // classLoader;
+
+    }
+
+    /** Small hack to allow a loader.properties file to be passed in CLI, to
+     * allow a more convenient method to start with different params from 
+     * explorer/kde/etc.
+     * 
+     * If the first arg ends with ".loader", it is used as loader.properties
+     * file and removed from args[].  
+     */
+    private void processCLI() {
+        if( args!=null && args.length > 0 &&
+                (args[0].toLowerCase().endsWith(".tomcat") ||
+                        args[0].toLowerCase().endsWith(".loader") ||
+                        args[0].toLowerCase().endsWith("loader.properties") )) {
+            String props=args[0];
+            String args2[]=new String[args.length-1];
+            System.arraycopy(args, 1, args2, 0, args2.length);
+            args=args2;
+            setPropertiesFile(props);
+        } else {
+            loadProperties();
+        }
+    }
+    
+    /**
+     * Initialize:
+     *  - detect the home/base directories
+     *  - init the loaders / modules
+     *  - instantiate the "startup" class(es)
+     * 
+     */
+    public void main()
+        throws Exception
+    {
+        processCLI();
+        
+        // Set Catalina path
+        setCatalinaHome();
+        setCatalinaBase();
+
+        init();
+        
+        Thread.currentThread().setContextClassLoader(catalinaLoader);
+
+        securityPreload(catalinaLoader);
+
+        autostart();
+    }
+
+    private void autostart() throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
+        // Load our startup classes and call its process() method
+        /* Why multiple classes ? 
+         * - maybe you want to start more "servers" ( tomcat ,something else )
+         * - easy hook for other load on startup modules ( like a jmx hook )
+         * - maybe split the loader-specific code from catalina 
+         */
+        String startupClasses=getProperty("loader.auto-startup",
+                "org.apache.catalina.startup.CatalinaModuleListener");
+        Vector v=split( startupClasses ); 
+        
+        for( int i=0; i<v.size(); i++ ) {
+            String startupCls=(String)v.elementAt(i);
+        
+            if (DEBUG)
+                log("Loading startup class " + startupCls);
+            
+            Class startupClass =
+                catalinaLoader.loadClass(startupCls);
+            
+            Object startupInstance = startupClass.newInstance();
+            
+            if( startupInstance instanceof ModuleListener ) {
+                addModuleListener((ModuleListener)startupInstance);
+
+                // it can get args[] and properties from Loader
+                listener.setLoader(this);
+                
+                // all arg processing moved there. Maybe we can make it consistent
+                // for all startup schemes
+                listener.start();
+            } else if ( startupInstance instanceof Runnable ) {
+                ((Runnable)startupInstance).run();
+            } else {
+                Class paramTypes[] = new Class[0];
+                Object paramValues[] = new Object[0];
+                Method method =
+                    startupInstance.getClass().getMethod("execute", paramTypes);
+                if( method==null ) 
+                    method = startupInstance.getClass().getMethod("start", paramTypes);
+                if( method!=null )
+                    method.invoke(startupInstance, paramValues);
+            }
+
+        }
+    }
+
+    /** Returns one of the repositories. 
+     * 
+     *  Typically at startup we create at least: "common", "shared" and "server", with 
+     *  same meaning as in tomcat. 
+     * 
+     * @param name
+     * @return
+     */
+    public Repository getRepository( String name ) {
+        return (Repository)repositories.get(name);
+    }
+    
+    private  static void securityPreload(ClassLoader loader)
+        throws Exception {
+
+        if( System.getSecurityManager() == null ){
+            return;
+        }
+
+        String value=getProperty("security.preload");
+        Vector repo=split( value );
+        Enumeration elems=repo.elements();
+        while (elems.hasMoreElements()) {
+            String classN = (String)elems.nextElement();
+            try {
+                loader.loadClass( classN);
+            } catch( Throwable t ) {
+                // ignore
+            }
+        }
+    }
+
+
+    // ----------------------------------------------------------- Main Program
+
+    /** Access to the command line arguments, when Loader is used to launc an app.
+     */
+    public String[] getArgs() {
+        return args;
+    }
+
+    /**
+     * Main method.
+     *
+     * @param args Command line arguments to be processed
+     */
+    public static void main(String args[]) {
+        
+        try {
+            if (daemon == null) {
+                daemon = new Loader();
+                daemon.args=args;
+
+                try {
+                    daemon.main();
+                } catch (Throwable t) {
+                    t.printStackTrace();
+                    return;
+                }
+            }
+        } catch (Throwable t) {
+            t.printStackTrace();
+        }
+
+    }
+
+
+    /**
+     * Initialize the loader properties explicitely. 
+     * 
+     * TODO: add setPropertiesRes
+     * 
+     * @param props
+     */
+    public void setPropertiesFile(String props) {
+        propFile=props;
+        loadProperties();
+    }
+
+    /**
+     * Return specified property value.
+     */
+    static String getProperty(String name) {
+        if( properties==null ) loadProperties();
+        return properties.getProperty(name);
+    }
+
+
+    /**
+     * Return specified property value.
+     */
+    static String getProperty(String name, String defaultValue) {
+        if( properties==null ) loadProperties();
+        return properties.getProperty(name, defaultValue);
+    }
+
+    /**
+     * Load properties.
+     * Will try: 
+     * - "catalina.config" system property ( a URL )
+     * - "catalina.base", "catalina.home", "user.dir" system properties +
+     *    "/conf/" "../conf" "/" +  "loader.properties" or "catalina.properties"
+     * - /org/apache/catalina/startup/catalina.properties
+     * 
+     * Properties will be loaded as system properties. 
+     * 
+     * loader.properties was added to allow coexistence with bootstrap.jar ( the 
+     * current scheme ), since the classpaths are slightly different. 
+     */
+    static void loadProperties() {
+        properties = new Properties();
+        
+        InputStream is = null;
+        Throwable error = null;
+
+        // TODO: paste the code to do ${} substitution 
+        // TODO: add the code to detect where tomcat-properties is loaded from
+        if( propFile != null ) {
+            try {
+                File properties = new File(propFile);
+                is = new FileInputStream(properties);
+                if( is!=null && DEBUG ) {
+                    log("Loaded from loader.properties " + properties );
+                }
+            } catch( Throwable t) {
+                System.err.println("Can't find " + propFile);
+                return;
+            }
+        }
+        
+        if( is == null ) {
+            try {
+                // "catalina.config" system property
+                String configUrl = System.getProperty("catalina.config");
+                if (configUrl != null) {
+                    is = (new URL(configUrl)).openStream();
+                    if( is!=null && DEBUG ) {
+                        log("Loaded from catalina.config " + configUrl );
+                    }
+                }
+            } catch (Throwable t) {
+                // Ignore
+            }
+        }
+
+        if( is == null ) {
+            try {
+                // "loader.config" system property
+                String configUrl = System.getProperty("loader.config");
+                if (configUrl != null) {
+                    is = (new URL(configUrl)).openStream();
+                    if( is!=null && DEBUG ) {
+                        log("Loaded from catalina.config " + configUrl );
+                    }
+                }
+            } catch (Throwable t) {
+                // Ignore
+            }
+        }
+
+        if (is == null) {
+            try {
+                setCatalinaBase(); // use system properties, then user.dir
+                File home = new File(getCatalinaBase());
+                File conf = new File(home, "conf");
+                
+                // use conf if exists, or the base directory otherwise
+                if( ! conf.exists() ) conf = new File(home, "../conf");
+                if( ! conf.exists() ) conf = home;
+                File propertiesF=null;
+                if(  conf.exists() )  
+                     propertiesF= new File(conf, "loader.properties");
+                if( ! propertiesF.exists() ) {
+                    propertiesF= new File( home, "loader.properties");
+                }
+                if( propertiesF.exists() )
+                    is = new FileInputStream(propertiesF);
+                if( is!=null && DEBUG ) {
+                    log("Loaded from loader.properties " + properties );
+                }
+            } catch (Throwable t) {
+                // Ignore
+            }
+        }
+
+        if (is == null) {
+            try {
+                File home = new File(getCatalinaBase());
+                File conf = new File(home, "conf");
+                File properties = new File(conf, "catalina.properties");
+                is = new FileInputStream(properties);
+                if( is!=null && DEBUG ) {
+                    log("Loaded from catalina.properties " + properties );
+                }
+            } catch (Throwable t) {
+                // Ignore
+            }
+        }
+
+        if (is == null) {
+            try {
+                is = Loader.class.getResourceAsStream
+                    ("/org/apache/catalina/startup/catalina.properties");
+                if( is!=null && DEBUG ) {
+                    log("Loaded from o/a/c/startup/catalina.properties " );
+                }
+
+            } catch (Throwable t) {
+                // Ignore
+            }
+        }
+
+        if (is == null) {
+            try {
+                is = Loader.class.getResourceAsStream
+                    ("loader.properties");
+                if( is!=null && DEBUG ) {
+                    log("Loaded from res loader.properties " );
+                }
+            } catch (Throwable t) {
+                // Ignore
+            }
+        }
+        
+        if (is != null) {
+            try {
+                properties.load(is);
+                is.close();
+            } catch (Throwable t) {
+                error = t;
+            }
+        }
+
+//        if ((is == null) || (error != null)) {
+//            // Do something
+//            log("Error: no properties found !!!");
+//        }
+
+        // Register the _unused_ properties as system properties
+        if( properties != null ) {
+            Enumeration enumeration = properties.propertyNames();
+            while (enumeration.hasMoreElements()) {
+                String name = (String) enumeration.nextElement();
+                String value = properties.getProperty(name);
+                if( "security.preload".equals( name )) continue;
+                if( "package.access".equals( name )) continue;
+                if( "package.definition".equals( name )) continue;
+                if( name.endsWith(".loader")) continue;
+                if( name.startsWith("loader.")) continue;
+                if (value != null) {
+                    System.setProperty(name, value);
+                }
+            }
+        }
+
+    }
+
+    static void setCatalinaHome(String s) {
+        System.setProperty( "catalina.home", s );
+    }
+
+    static void setCatalinaBase(String s) {
+        System.setProperty( "catalina.base", s );
+    }
+
+
+    /**
+     * Get the value of the catalina.home environment variable.
+     * 
+     * @deprecated
+     */
+    static String getCatalinaHome() {
+        if( properties==null ) loadProperties();
+        return System.getProperty("catalina.home",
+                                  System.getProperty("user.dir"));
+    }
+    
+    
+    /**
+     * Get the value of the catalina.base environment variable.
+     * 
+     * @deprecated
+     */
+    static String getCatalinaBase() {
+        if( properties==null ) loadProperties();
+        return System.getProperty("catalina.base", getCatalinaHome());
+    }
+
+    
+    /**
+     * Set the <code>catalina.base</code> System property to the current
+     * working directory if it has not been set.
+     */
+    static void setCatalinaBase() {
+        if( properties==null ) loadProperties();
+
+        if (System.getProperty("catalina.base") != null)
+            return;
+        if (System.getProperty("catalina.home") != null)
+            System.setProperty("catalina.base",
+                               System.getProperty("catalina.home"));
+        else
+            System.setProperty("catalina.base",
+                               System.getProperty("user.dir"));
+
+    }
+
+
+    /**
+     * Set the <code>catalina.home</code> System property to the current
+     * working directory if it has not been set.
+     */
+    static void setCatalinaHome() {
+
+        if (System.getProperty("catalina.home") != null)
+            return;
+        File bootstrapJar = 
+            new File(System.getProperty("user.dir"), "bootstrap.jar");
+        File tloaderJar = 
+            new File(System.getProperty("user.dir"), "tomcat-loader.jar");
+        if (bootstrapJar.exists() || tloaderJar.exists()) {
+            try {
+                System.setProperty
+                    ("catalina.home", 
+                     (new File(System.getProperty("user.dir"), ".."))
+                     .getCanonicalPath());
+            } catch (Exception e) {
+                // Ignore
+                System.setProperty("catalina.home",
+                                   System.getProperty("user.dir"));
+            }
+        } else {
+            System.setProperty("catalina.home",
+                               System.getProperty("user.dir"));
+        }
+
+    }
+
+
+    
+    /**
+     * Get the module from the classloader. Works only for classloaders created by
+     * this package - or extending ModuleClassLoader.
+     * 
+     * This shold be the only public method that allows this - Loader acts as a 
+     * guard, only if you have the loader instance you can access the internals.
+     * 
+     * 
+     * @param cl
+     * @return
+     */
+    public Module getModule(ClassLoader cl ) {
+        if( cl instanceof ModuleClassLoader ) {
+            return ((ModuleClassLoader)cl).getModule();
+        }
+        return null;
+    }
+    
+    /**
+     * Create and return a new class loader, based on the configuration
+     * defaults and the specified directory paths:
+     *
+     * @param unpacked Array of pathnames to unpacked directories that should
+     *  be added to the repositories of the class loader, or <code>null</code> 
+     * for no unpacked directories to be considered
+     * @param packed Array of pathnames to directories containing JAR files
+     *  that should be added to the repositories of the class loader, 
+     * or <code>null</code> for no directories of JAR files to be considered
+     * @param urls Array of URLs to remote repositories, designing either JAR 
+     *  resources or uncompressed directories that should be added to 
+     *  the repositories of the class loader, or <code>null</code> for no 
+     *  directories of JAR files to be considered
+     * @param parent Parent class loader for the new class loader, or
+     *  <code>null</code> for the system class loader.
+     *
+     * @exception Exception if an error occurs constructing the class loader
+     */
+    private void initRepository(Repository lg, File unpacked[],
+            File packed[],  URL urls[],  Repository parent)
+        throws Exception 
+    {
+        StringBuffer sb=new StringBuffer();
+
+        // Construct the "class path" for this class loader
+        ArrayList list = new ArrayList();
+        
+        // Add unpacked directories
+        if (unpacked != null) {
+            for (int i = 0; i < unpacked.length; i++)  {
+                File file = unpacked[i];
+                if (!file.exists() || !file.canRead()) {
+                    if (DEBUG)
+                        log("  Not found:  "+ file.getAbsolutePath());
+                    continue;
+                }
+//                String cPath=file.getCanonicalPath();
+//                URL url=null;
+//                
+//                if( cPath.toLowerCase().endsWith(".jar") ||
+//                        cPath.toLowerCase().endsWith(".zip") ) {
+//                    url = new URL("file", null, cPath);
+//                } else {
+//                    url = new URL("file", null, cPath + File.separator);
+//                }
+                URL url=file.toURL();
+                if (DEBUG)
+                    sb.append(" : "+ url);
+                if( ! FLAT ) {
+                    addLoader(lg, parent, new URL[] { url });
+                } else {
+                    list.add(url);
+                }
+            }
+        }
+        
+        // Add packed directory JAR files
+        if (packed != null) {
+            for (int i = 0; i < packed.length; i++) {
+                File directory = packed[i];
+                if (!directory.isDirectory() || !directory.exists() ||
+                        !directory.canRead()) {
+                    if (DEBUG)
+                        log("  Not found:  "+ directory.getAbsolutePath());
+                    continue;
+                }
+                String filenames[] = directory.list();
+                for (int j = 0; j < filenames.length; j++) {
+                    String filename = filenames[j].toLowerCase();
+                    if (!filename.endsWith(".jar"))
+                        continue;
+                    File file = new File(directory, filenames[j]);
+//                    if (DEBUG)
+//                        sb.append(" [pak]="+ file.getCanonicalPath());
+//                    URL url = new URL("file", null,
+//                            file.getCanonicalPath());
+                    URL url=file.toURL();
+                    if (DEBUG)
+                        sb.append(" pk="+ url);
+
+                    if( ! FLAT ) {
+                        addLoader(lg, parent, new URL[] { url });
+                    } else {
+                        list.add(url);
+                    }
+                }
+            }
+        }
+        
+        // Add URLs
+        if (urls != null) {
+            for (int i = 0; i < urls.length; i++) {
+                if( ! FLAT ) {
+                    addLoader(lg, parent, new URL[] { urls[i] });
+                } else {
+                    list.add(urls[i]);
+                }
+                if (DEBUG)
+                    sb.append(" "+ urls[i]);
+            }
+        }
+        
+        // Construct the class loader itself
+        
+        // TODO: experiment with loading each jar in a separate loader.
+        if (DEBUG)
+            log("Creating new class loader " + lg.getName() + " " + sb.toString());
+        
+        
+        URL[] array = (URL[]) list.toArray(new URL[list.size()]);
+        if( array.length > 0 ) {
+            addLoader(lg, parent, array);
+        }
+    }
+    
+    /**
+     * @param lg
+     * @param parent
+     * @param list
+     */
+    private void addLoader(Repository lg, Repository parent, URL array[]) 
+        throws Exception
+    {
+        Module module=new Module();
+        
+        module.setParent( parent );
+        module.setClasspath( array );
+        
+        lg.addModule(module);
+        
+    }
+
+    private static Vector split( String value ) {
+        Vector result=new Vector();
+        StringTokenizer tokenizer = new StringTokenizer(value, ",");
+        while (tokenizer.hasMoreElements()) {
+            String repository = tokenizer.nextToken();
+            repository.trim();
+            if( ! "".equals(repository) )
+                result.addElement(repository);
+        }
+        return result;
+    }
+
+    void notifyModuleStart(Module module) {
+        if(listener!=null) listener.moduleStart(module);
+    }
+
+    void notifyModuleStop(Module module) {
+        if( listener!=null ) listener.moduleStop(module);
+    }
+    
+    /** Add a module listener. 
+     * 
+     * To keep the dependencies minimal, the loader package only implements the
+     * basic class loading mechanism - but any advanced feature ( management, 
+     * policy, etc ) should be implemented by a module.
+     * 
+     * @param listener
+     */
+    public void addModuleListener(ModuleListener listener) {
+        this.listener=listener;
+    }
+
+    private static void log(String s) {
+        System.err.println("Main: " + s);
+    }
+    
+    private static void log( String msg, Throwable t ) {
+        System.err.println("Main: " + msg);
+        t.printStackTrace();
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/util/loader/org/apache/tomcat/util/loader/Module.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/util/loader/org/apache/tomcat/util/loader/Module.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/util/loader/org/apache/tomcat/util/loader/Module.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,370 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.loader;
+
+
+import java.io.File;
+import java.io.Serializable;
+import java.lang.reflect.Constructor;
+import java.net.MalformedURLException;
+import java.net.URL;
+
+// Based on org.apache.catalina.Loader - removed most of the catalina-specific
+
+/**
+ * Represent one unit of code - jar, webapp, etc. Modules can be reloaded independently,
+ * and may be part of a flat structure or a hierarchy.
+ * 
+ * @author Costin Manolache
+ * @author Craig R. McClanahan
+ * @author Remy Maucherat
+ */
+public class Module implements Serializable {
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * 
+     */
+    public Module() {
+    }
+
+
+    // ----------------------------------------------------- Instance Variables
+
+    private static final boolean DEBUG=false; //LoaderProperties.getProperty("loader.Module.debug") != null;
+
+    /**
+     * The class loader being managed by this Loader component.
+     */
+    private transient ModuleClassLoader classLoader = null;
+
+    /**
+     * The "follow standard delegation model" flag that will be used to
+     * configure our ClassLoader.
+     */
+    private boolean delegate = false;
+
+    private Class classLoaderClass;
+
+    /**
+     * The Java class name of the ClassLoader implementation to be used.
+     * This class should extend ModuleClassLoader, otherwise, a different 
+     * loader implementation must be used.
+     */
+    private String loaderClass = null;
+//        "org.apache.catalina.loader.WebappClassLoader";
+
+    /**
+     * The parent class loader of the class loader we will create.
+     * Use Repository if the parent is also a repository, otherwise set 
+     * the ClassLoader
+     */
+    private transient ClassLoader parentClassLoader = null;
+    private Repository parent;
+
+    private Repository repository;
+
+    /**
+     * The set of repositories associated with this class loader.
+     */
+    private String repositories[] = new String[0];
+    private URL classpath[] ;
+
+    private File workDir;
+
+    /**
+     * Has this component been started?
+     */
+    private boolean started = false;
+
+    boolean hasIndex=false;
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * Return the Java class loader to be used by this Container.
+     */
+    public ClassLoader getClassLoader() {
+        return classLoader;
+    }
+
+
+    /**
+     * Return the "follow standard delegation model" flag used to configure
+     * our ClassLoader.
+     */
+    public boolean getDelegate() {
+        return (this.delegate);
+    }
+
+
+    /**
+     * Set the "follow standard delegation model" flag used to configure
+     * our ClassLoader.
+     *
+     * @param delegate The new flag
+     */
+    public void setDelegate(boolean delegate) {
+        boolean oldDelegate = this.delegate;
+        this.delegate = delegate;
+        if( classLoader != null ) classLoader.setDelegate(delegate);
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+    /**
+     * Has the internal repository associated with this Loader been modified,
+     * such that the loaded classes should be reloaded?
+     */
+    public boolean modified() {
+        return (classLoader.modified());
+    }
+    
+    public boolean isStarted() {
+        return started;
+    }
+
+    public String getClasspathString() {
+        if(classpath==null ) {
+            return null;
+        }
+        StringBuffer sb=new StringBuffer();
+        for( int i=0; i<classpath.length; i++ ) {
+            if( i>0 ) sb.append(":");
+            sb.append( classpath[i].getFile() );
+        }
+        return sb.toString();
+    }
+    
+    /**
+     * Start this component, initializing our associated class loader.
+     *
+     * @exception LifecycleException if a lifecycle error occurs
+     */
+    public void start()  {
+        // Validate and update our current component state
+        if (started)
+            throw new RuntimeException
+                ("Already started");
+        started = true;
+
+        log("start()");
+
+        // Construct a class loader based on our current repositories list
+        try {
+
+            classLoader = createClassLoader();
+
+            //classLoader.setResources(container.getResources());
+            classLoader.setDelegate(this.delegate);
+
+            for (int i = 0; i < repositories.length; i++) {
+                classLoader.addRepository(repositories[i]);
+            }
+
+            classLoader.start();
+
+            getRepository().getLoader().notifyModuleStart(this);
+
+        } catch (Throwable t) {
+            log( "LifecycleException ", t );
+            throw new RuntimeException("start: ", t);
+        }
+
+    }
+
+
+    /**
+     * Stop this component, finalizing our associated class loader.
+     *
+     * @exception LifecycleException if a lifecycle error occurs
+     */
+    public void stop() {
+        if (!started)
+            throw new RuntimeException("stop: started=false");
+        
+        //if (DEBUG) 
+        log("stop()", null);
+        
+        getRepository().getLoader().notifyModuleStop(this);
+        
+        started = false;
+
+        // unregister this classloader in the server group
+        if( repository != null ) repository.removeClassLoader(classLoader);
+
+        // Throw away our current class loader
+        classLoader.stop();
+
+        classLoader = null;
+
+    }
+
+    // ------------------------------------------------------- Private Methods
+
+    /** 
+     * Experiment for basic lifecycle driven by higher layer.
+     * start() and stop() methods will be called on the class when the
+     * module is stopped and started.
+     * 
+     */
+    //public void addModuleClass(String s) {
+        
+    //}
+    
+    /** Set the class used to construct the class loader.
+     * 
+     * The alternative is to set the context class loader to allow loaderClass
+     * to be created. 
+     * 
+     * @param c
+     */
+    public void setClassLoaderClass( Class c ) {
+        classLoaderClass=c;
+    }
+
+    /**
+     * Create associated classLoader.
+     */
+    ModuleClassLoader createClassLoader()
+        throws Exception 
+    {
+
+        if( classLoader != null ) return classLoader;
+        if( classLoaderClass==null && loaderClass!=null) {
+            classLoaderClass = Class.forName(loaderClass);
+        }
+        
+        ModuleClassLoader classLoader = null;
+
+        if (parentClassLoader == null) {
+            if( parent != null ) {
+                parentClassLoader = parent.getClassLoader();
+            }
+        }
+        if (parentClassLoader == null) {
+            parentClassLoader = Thread.currentThread().getContextClassLoader();
+        }
+        
+        if( classLoaderClass != null ) {
+            Class[] argTypes = { URL[].class, ClassLoader.class };
+            Object[] args = { classpath, parentClassLoader };
+            Constructor constr = classLoaderClass.getConstructor(argTypes);
+            classLoader = (ModuleClassLoader) constr.newInstance(args);
+        } else {
+            classLoader=new ModuleClassLoader( classpath, parentClassLoader);
+        }
+        System.err.println("---- Created class loader " + classpath + " " + parentClassLoader + " repo=" + repository.getName() + " " + parent);
+        
+        classLoader.setModule(this);
+        classLoader.setDelegate( delegate );
+        
+        classLoader.start();
+        repository.addClassLoader(classLoader);
+        
+        return classLoader;
+    }
+
+
+    /**
+     * @param parent
+     */
+    public void setParent(Repository parent) {
+        this.parent=parent;
+    }
+
+    /**
+     * @param array
+     */
+    public void setClasspath(URL[] array) {
+        this.classpath=array;
+    }
+    
+    /** Set the path to the module.
+     * In normal use, each module will be associated with one jar or 
+     * classpath dir.
+     * 
+     * @param name
+     */
+    public void setPath(String name) {
+        this.classpath=new URL[1];
+        try {
+            classpath[0]=new URL(name);
+        } catch (MalformedURLException e) {
+            // TODO Auto-generated catch block
+            e.printStackTrace();
+        }
+    }
+
+
+    /**
+     * @param lg
+     */
+    public void setRepository(Repository lg) {
+        this.repository=lg;
+    }
+
+    /**
+     * Return a String representation of this component.
+     */
+    public String toString() {
+
+        StringBuffer sb = new StringBuffer("ModuleLoader[");
+        sb.append(getClasspathString());
+        sb.append("]");
+        return (sb.toString());
+
+    }
+
+    private void log( String s ) {
+        log(s,null);
+    }
+    
+    private void log(String s, Throwable t ) {
+        System.err.println("Module: " + s );
+        if( t!=null)
+            t.printStackTrace();
+    }
+
+
+    /**
+     * @return
+     */
+    public Repository getRepository() {
+        return repository;
+    }
+
+
+    /**
+     * @return
+     */
+    public String getName() {
+        return classpath[0].getFile(); // this.toString();
+    }
+
+
+    public void setParentClassLoader(ClassLoader parentClassLoader2) {
+        this.parentClassLoader=parentClassLoader2;
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/util/loader/org/apache/tomcat/util/loader/ModuleClassLoader.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/util/loader/org/apache/tomcat/util/loader/ModuleClassLoader.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/util/loader/org/apache/tomcat/util/loader/ModuleClassLoader.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,692 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.loader;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.Enumeration;
+import java.util.Vector;
+
+/*
+ * Initially, I started with WebappClassLoader attempting to clean up and
+ * refactor it. Because of complexity and very weird ( and likely buggy ) 
+ * behavior, I moved the other way, starting with URLClassLoader and adding
+ * the functionality from WebappClassLoader. 
+ * 
+ * The current version has a lot of unimplemented WebappClassLoader features and
+ * TODOs - all of them are needed in order to support a single/consistent loader
+ * for webapps and server/modules. 
+ * 
+ * - all ordering options and tricks
+ * - local loading - in case it can be made more efficient than URLCL
+ * - hook to plugin JNDI finder
+ * - ability to add extra permissions to loaded classes
+ * - ability to use work dir for anti-jar locking and generated classes ( incl getURLs)
+ * 
+ * 
+ * Things better kept out:
+ *  - negative cache - it'll waste space with little benefit, most not found classes
+ *  will not be asked multiple times, and most will be in other loaders
+ *  - binaryContent cache - it's unlikely same resource will be loaded multiple
+ * times, and some may be large  
+ * 
+ */
+
+/**
+ * Simple module class loader. Will search the repository if the class is not
+ * found locally.
+ * 
+ * TODO: findResources() - merge all responses from the repo and parent. 
+ *
+ * Based on StandardClassLoader and WebappClassLoader.
+ *   
+ * @author Costin Manolache
+ * @author Remy Maucherat
+ * @author Craig R. McClanahan
+ */
+public class ModuleClassLoader
+    extends URLClassLoader
+{
+    // Don't use commons logging or configs to debug loading - logging is dependent
+    // on loaders and drags a lot of stuff in the classpath 
+    //
+    private static final boolean DEBUG=false; //LoaderProperties.getProperty("loader.debug.ModuleClassLoader") != null;
+    private static final boolean DEBUGNF=false;//LoaderProperties.getProperty("loader.debug.ModuleClassLoaderNF") != null;
+    
+    // ----------------------------------------------------------- Constructors
+
+
+    public ModuleClassLoader(URL repositories[], ClassLoader parent) {
+        super(repositories, parent);
+        if(DEBUG) log( "NEW ModuleClassLoader  " + parent + " " + repositories.length);
+        updateStamp();
+    }
+    
+
+    public ModuleClassLoader(URL repositories[]) {
+        super(repositories);
+        if(DEBUG) log( "NEW ModuleClassLoader  -null-"+ " " + repositories.length);
+        updateStamp();
+    }
+
+
+    // ----------------------------------------------------- Instance Variables
+
+    protected Repository repository;
+
+    /**
+     * Should this class loader delegate to the parent class loader
+     * <strong>before</strong> searching its own repositories (i.e. the
+     * usual Java2 delegation model)?  If set to <code>false</code>,
+     * this class loader will search its own repositories first, and
+     * delegate to the parent only if the class or resource is not
+     * found locally.
+     */
+    protected boolean delegate = false;
+
+    /**
+     * Last time a JAR was accessed. 
+     * TODO: change to last time the loader was accessed
+     */
+    protected long lastJarAccessed = 0L;
+
+    protected long lastModified=0L;
+    
+    /**
+     * Has this component been started?
+     */
+    protected boolean started = false;
+
+    protected Module module;
+
+    // ------------------------------------------------------------- Properties
+
+    /**
+     * Set the "delegate first" flag for this class loader.
+     *
+     * @param delegate The new "delegate first" flag
+     */
+    void setDelegate(boolean delegate) {
+        this.delegate = delegate;
+    }
+
+    void setRepository(Repository lg ) {
+        this.repository=lg;
+    }
+
+    void setModule(Module webappLoader) {
+        this.module=webappLoader;
+    }
+
+    /** Not public - his can only be called from package.
+     *  To get the module from a ClassLoader you need access to the Loader
+     * instance.
+     * 
+     * @return
+     */
+    Module getModule() {
+        return module;
+    }
+
+    void setWorkDir(File s) {
+        // TODO
+    }
+
+    /**
+     * Add a new repository to the set of places this ClassLoader can look for
+     * classes to be loaded.
+     *
+     * @param repository Name of a source of classes to be loaded, such as a
+     *  directory pathname, a JAR file pathname, or a ZIP file pathname
+     *
+     * @exception IllegalArgumentException if the specified repository is
+     *  invalid or does not exist
+     */
+    void addRepository(String repository) {
+        // Add this repository to our underlying class loader
+        try {
+            boolean mod=modified();
+            URL url = new URL(repository);
+            super.addURL(url);
+            if( ! mod ) {
+                // don't check if it is modified, so it works
+                updateStamp();
+            }
+        } catch (MalformedURLException e) {
+            IllegalArgumentException iae = new IllegalArgumentException
+                ("Invalid repository: " + repository); 
+            iae.initCause(e);
+            //jdkCompat.chainException(iae, e);
+            throw iae;
+        }
+    }
+
+    void updateStamp() {
+        URL cp[]=super.getURLs();
+        if (cp != null ) {
+            for (int i = 0; i <cp.length; i++) {
+                File f=new File(cp[i].getFile());
+                long lm=f.lastModified();
+                if( lm > lastModified ) lastModified=lm;
+            }
+        }
+    }
+    
+    private boolean dirCheck(File dir ) {
+        //log("Checking " + dir );
+        File subd[]=dir.listFiles();
+        for( int i=0; i< subd.length; i++ ) {
+            long lm=subd[i].lastModified();
+            if( lm > lastModified ) {
+                log("Modified file: " + dir + " " + subd[i] + " " + lm + " " + lastModified);
+                return true;
+            }
+            if( subd[i].isDirectory() ) {
+                return  dirCheck(subd[i]);
+            }
+        }
+        return false;
+    }
+    
+    /**
+     * Have one or more classes or resources been modified so that a reload
+     * is appropriate?
+     * 
+     * Not public - call it via Module
+     */
+    boolean modified() {
+        URL cp[]=super.getURLs();
+        if (cp != null ) {
+            for (int i = 0; i <cp.length; i++) {
+                File f=new File(cp[i].getFile());
+                long lm=f.lastModified();
+                if( lm > lastModified ) {
+                    log( "Modified file: " + f + " " + lm + " " + lastModified);
+                    return true;
+                }
+                // assume dirs are used only for debug and small
+                if( f.isDirectory() ) {
+                    return dirCheck(f);
+                }
+            }
+        }
+
+        if (DEBUG)
+            log("modified() false");
+
+        // TODO - check at least the jars 
+        return (false);
+    }
+
+    // ---------------------------------------------------- ClassLoader Methods
+
+
+    /**
+     * Find the specified class in our local repositories, if possible.  If
+     * not found, throw <code>ClassNotFoundException</code>.
+     *
+     * @param name Name of the class to be loaded
+     *
+     * @exception ClassNotFoundException if the class was not found
+     */
+    public Class findClass(String name) throws ClassNotFoundException {
+        return findClass2(name, true);
+    }
+    
+    public Class findClass2(String name, boolean del2repo) throws ClassNotFoundException {
+        if( del2repo ) {
+            return ((RepositoryClassLoader)repository.getClassLoader()).findClass(name);            
+        } // else 
+ 
+        Class clazz = null;
+            
+        try {
+            clazz = super.findClass(name);
+        } catch (RuntimeException e) {
+            if (DEBUG)
+                log("findClass() -->RuntimeException " + name, e);
+            throw e;
+        } catch( ClassNotFoundException ex ) {
+            URL cp[]=this.getURLs();
+            if (DEBUGNF)
+                log("findClass() NOTFOUND  " + name + " " + (( cp.length > 0 ) ? cp[0].toString() : "") );
+            throw ex;
+        }
+            
+        if (clazz == null) { // does it ever happen ? 
+            if (DEBUGNF)
+                log("findClass() NOTFOUND throw CNFE " + name);
+            throw new ClassNotFoundException(name);
+        }
+
+        // Return the class we have located
+        if (DEBUG) {
+            if( clazz.getClassLoader() != this ) 
+                log("findClass() FOUND " + clazz + " Loaded by " + clazz.getClassLoader());
+            else 
+                log("findClass() FOUND " + clazz );
+        }
+        return (clazz);
+    }
+    
+    /** Same as findClass, but also checks if the class has been previously 
+     * loaded.
+     * 
+     * In most implementations, findClass() doesn't check with findLoadedClass().
+     * In order to implement repository, we need to ask each loader in the group
+     * to load only from it's local resources - however this will lead to errors
+     * ( duplicated definition ) if findClass() is used.
+     *
+     * @param name
+     * @return
+     * @throws ClassNotFoundException
+     */
+    public Class findLocalClass(String name) throws ClassNotFoundException
+    {
+        Class clazz = findLoadedClass(name);
+        if (clazz != null) {
+            if (DEBUG)
+                log("findLocalClass() - FOUND " + name);
+            return (clazz);
+        }
+        
+        return findClass(name);
+    }
+
+
+
+    
+    /**
+     * Find the specified resource in our local repository, and return a
+     * <code>URL</code> refering to it, or <code>null</code> if this resource
+     * cannot be found.
+     *
+     * @param name Name of the resource to be found
+     */
+    public URL findResource(final String name) {
+        return findResource2( name, true);
+    }
+        
+    public URL findResource2(final String name, boolean del2repo ) {
+        if( del2repo ) {
+            return ((RepositoryClassLoader)repository.getClassLoader()).findResource(name);
+        } // else:
+
+        URL url = null;
+
+        url = super.findResource(name);
+        
+        if(url==null) {
+            // try the repository
+            // TODO
+        }
+        
+        if (url==null && DEBUG) {
+            if (DEBUGNF) log("findResource() NOTFOUND " + name );
+            return null;
+        }
+
+        if (DEBUG) log("findResource() found " + name + " " + url );
+        return (url);
+    }
+
+
+    /**
+     * Return an enumeration of <code>URLs</code> representing all of the
+     * resources with the given name.  If no resources with this name are
+     * found, return an empty enumeration.
+     *
+     * @param name Name of the resources to be found
+     *
+     * @exception IOException if an input/output error occurs
+     */
+    public Enumeration findResources(String name) throws IOException {
+        return findResources2(name, true);
+    }
+    
+    Enumeration findResources2(String name, boolean del2repo) throws IOException {
+        if( del2repo ) {
+            return ((RepositoryClassLoader)repository.getClassLoader()).findResources(name);
+        } else {
+            return super.findResources(name);
+        }
+    }
+
+    // Next methods implement the search alghoritm - parent, repo, delegation, etc 
+
+    /** getResource() - modified to implement the search alghoritm 
+     * 
+     */
+    public URL getResource(String name) {
+        return getResource2( name, null, true);
+    }
+
+    /** getResource() - same thing, but don't delegate to repo if called 
+     * from repo 
+     * 
+     */
+    URL getResource2(String name, ClassLoader originator, boolean delegate2repo ) {
+
+        URL url = null;
+
+        // (1) Delegate to parent if requested
+        if (delegate) {
+            url=getResourceParentDelegate(name);
+            if(url!=null ) return url;
+        }
+
+        // (2) Search local repositories
+        url = findResource(name);
+        if (url != null) {
+            // TODO: antijar locking - WebappClassLoader is making a copy ( is it ??)
+            if (DEBUG)
+                log("getResource() found locally " + delegate + " " + name + " " + url);
+            return (url);
+        }
+
+        // Finally, try the group loaders ( via super() in StandardClassLoader ).
+        // not found using normal loading mechanism. load from one of the classes in the group
+        if( delegate2repo && repository!=null ) {
+            url=repository.findResource(this, name);
+            if(url!=null ) {
+                if( DEBUG )
+                    log("getResource() FOUND from group " + repository.getName() + " " + name + " " + url);
+                return url;
+            }
+        }
+
+        // (3) Delegate to parent unconditionally if not already attempted
+        if( !delegate ) {
+            url=getResourceParentDelegate(name);
+            if(url!=null ) return url;
+        }
+
+        
+        // (4) Resource was not found
+        if (DEBUGNF)
+            log("getResource() NOTFOUND  " + delegate + " " + name + " " + url);
+        return (null);
+
+    }
+
+    
+    // to avoid duplication - get resource from parent, when delegating
+    private URL getResourceParentDelegate(String name) {
+        URL url=null;
+        ClassLoader loader = getParent();
+        
+        if (loader == null) {
+            loader = getSystemClassLoader();
+            if (url != null) {
+                if (DEBUG)
+                    log("getResource() found by system " +  delegate + " " + name + " " + url);
+                return (url);
+            }
+        } else {
+            url = loader.getResource(name);
+            if (url != null) {
+                if (DEBUG)
+                    log("getResource() found by parent " +  delegate + " " + name + " " + url);
+                return (url);
+            }
+        }
+        if( DEBUG ) log("getResource not found by parent " + loader);
+
+        return url;
+    }
+    
+    /**
+     * Load the class with the specified name, searching using the following
+     * algorithm until it finds and returns the class.  If the class cannot
+     * be found, returns <code>ClassNotFoundException</code>.
+     * <ul>
+     * <li>Call <code>findLoadedClass(String)</code> to check if the
+     *     class has already been loaded.  If it has, the same
+     *     <code>Class</code> object is returned.</li>
+     * <li>If the <code>delegate</code> property is set to <code>true</code>,
+     *     call the <code>loadClass()</code> method of the parent class
+     *     loader, if any.</li>
+     * <li>Call <code>findClass()</code> to find this class in our locally
+     *     defined repositories.</li>
+     * <li>Call the <code>loadClass()</code> method of our parent
+     *     class loader, if any.</li>
+     * </ul>
+     * If the class was found using the above steps, and the
+     * <code>resolve</code> flag is <code>true</code>, this method will then
+     * call <code>resolveClass(Class)</code> on the resulting Class object.
+     *
+     * @param name Name of the class to be loaded
+     * @param resolve If <code>true</code> then resolve the class
+     *
+     * @exception ClassNotFoundException if the class was not found
+     */
+    public Class loadClass(String name, boolean resolve)
+        throws ClassNotFoundException
+    {
+        return loadClass2( name, resolve, true );
+    }
+    
+    public Class loadClass2(String name, boolean resolve, boolean del2repo)
+        throws ClassNotFoundException
+    {
+
+        Class clazz = null;
+
+        // Don't load classes if class loader is stopped
+        if (!started) {
+            log("Not started " + this + " " + module);
+            //throw new ThreadDeath();
+            start();
+        }
+
+        // (0) Check our previously loaded local class cache
+        clazz = findLoadedClass(name);
+        if (clazz != null) {
+            if (DEBUG)
+                log("loadClass() FOUND findLoadedClass " + name + " , " + resolve);
+            if (resolve) resolveClass(clazz);
+            return (clazz);
+        }
+
+        // (0.2) Try loading the class with the system class loader, to prevent
+        //       the webapp from overriding J2SE classes
+        try {
+            clazz = getSystemClassLoader().loadClass(name);
+            if (clazz != null) {
+                // enabling this can result in ClassCircularityException
+//                if (DEBUG)
+//                    log("loadClass() FOUND system " + name + " , " + resolve);
+                if (resolve) resolveClass(clazz);
+                return (clazz);
+            }
+        } catch (ClassNotFoundException e) {
+            // Ignore
+        }
+
+        // TODO: delegate based on filter
+        boolean delegateLoad = delegate;// || filter(name);
+
+        // (1) Delegate to our parent if requested
+        if (delegateLoad) {
+
+            ClassLoader loader = getParent();
+            if( loader != null ) {
+                try {
+                    clazz = loader.loadClass(name);
+                    if (clazz != null) {
+                        if (DEBUG)
+                            log("loadClass() FOUND by parent " + delegate + " " + name + " , " + resolve);
+                        if (resolve)
+                            resolveClass(clazz);
+                        return (clazz);
+                    }
+                } catch (ClassNotFoundException e) {
+                    ;
+                }
+            }
+        }
+
+        // (2) Search local repositories
+        try {
+            clazz = findClass(name);
+            if (clazz != null) {
+                if (DEBUG)
+                    log("loadClass - FOUND findClass " + delegate + " " + name + " , " + resolve);
+                if (resolve) resolveClass(clazz);
+                return (clazz);
+            }
+        } catch (ClassNotFoundException e) {
+            ;
+        }
+
+        // Finally, try the group loaders ( via super() in StandardClassLoader ).
+        // not found using normal loading mechanism. load from one of the classes in the group
+        if( del2repo && repository!=null ) {
+            Class cls=repository.findClass(this, name);
+            if(cls!=null ) {
+                if( DEBUG )
+                    log("loadClass(): FOUND from group " + repository.getName() + " " + name);
+                if (resolve) resolveClass(clazz);
+                return cls;
+            }
+        }
+
+        // (3) Delegate to parent unconditionally
+        if (!delegateLoad) {
+            ClassLoader loader = getParent();
+            if( loader != null ) {
+                try {
+                    clazz = loader.loadClass(name);
+                    if (clazz != null) {
+                        if (DEBUG)
+                            log("loadClass() FOUND parent " + delegate + " " + name + " , " + resolve);
+                        if (resolve) resolveClass(clazz);
+                        return (clazz);
+                    }
+                } catch (ClassNotFoundException e) {
+                    ;
+                }
+            }
+        }
+
+        if( DEBUGNF ) log("loadClass(): NOTFOUND " + name + " xxx " + getParent() +  " " + repository.getName() );
+        throw new ClassNotFoundException(name);
+    }
+
+
+    // ------------------------------------------------------ Lifecycle Methods
+
+
+
+    /**
+     * Start the class loader.
+     *
+     * @exception LifecycleException if a lifecycle error occurs
+     */
+    void start()  {
+
+        started = true;
+
+    }
+
+    /** Support for "disabled" state.
+    *
+    * @return
+    */
+    boolean isStarted() {
+        return started;
+    }
+
+
+    /**
+     * Stop the class loader.
+     *
+     * @exception LifecycleException if a lifecycle error occurs
+     */
+    void stop() {
+
+        started = false;
+
+    }
+
+
+
+
+    /**
+     * Validate a classname. As per SRV.9.7.2, we must restict loading of 
+     * classes from J2SE (java.*) and classes of the servlet API 
+     * (javax.servlet.*). That should enhance robustness and prevent a number
+     * of user error (where an older version of servlet.jar would be present
+     * in /WEB-INF/lib).
+     * 
+     * @param name class name
+     * @return true if the name is valid
+     */
+    protected boolean validate(String name) {
+
+        if (name == null)
+            return false;
+        if (name.startsWith("java."))
+            return false;
+
+        return true;
+
+    }
+
+
+    // ------------------ Local methods ------------------------
+
+    private void log(String s ) {
+        System.err.println("ModuleClassLoader: " + s);
+    }
+    private void log(String s, Throwable t ) {
+        System.err.println("ModuleClassLoader: " + s);
+        t.printStackTrace();
+    }
+    
+    Object debugObj=new Object();
+
+    /**
+     * Render a String representation of this object.
+     */
+    public String toString() {
+
+        StringBuffer sb = new StringBuffer("ModuleCL ");
+        sb.append(debugObj).append(" delegate: ");
+        sb.append(delegate);
+        //sb.append("\r\n");
+        sb.append(" cp: ");
+        URL cp[]=super.getURLs();
+        if (cp != null ) {
+            for (int i = 0; i <cp.length; i++) {
+                sb.append("  ");
+                sb.append(cp[i].getFile());
+            }
+        }
+        if (getParent() != null) {
+            sb.append("\r\n----------> Parent: ");
+            sb.append(getParent().toString());
+            sb.append("\r\n");
+        }
+        return (sb.toString());
+    }
+}
+

Added: branches/tomcat5.5/upstream/5.5.20/connectors/util/loader/org/apache/tomcat/util/loader/ModuleListener.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/util/loader/org/apache/tomcat/util/loader/ModuleListener.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/util/loader/org/apache/tomcat/util/loader/ModuleListener.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,105 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.loader;
+
+/**
+ * Interface providing notifications on Module events.
+ * 
+ * @author Costin Manolache
+ */
+public interface ModuleListener {
+    
+    /** Called when a module group is created. This is only called when a new group
+     * is added to a running engine - we may cache a the list of groups and reuse 
+     * it on restarts. 
+     * 
+     * @param manager
+     */
+    public void repositoryAdd( Repository manager );
+    
+    /** Notification that a module has been added. You can get the group
+     * with getGroup().
+     * 
+     * Adding a module doesn't imply that the module is started or the class loader
+     * created - this happens only on start() ( TODO: or when a class is accessed ? ).
+     * 
+     * This callback is only called for new modules, deployed while the engine is 
+     * running, or in some cases when the module engine is reseting the cache. For
+     * old modules - you need to get a list from the ModuleGroup.
+     * 
+     * 
+     * @param module
+     */
+    public void moduleAdd( Module module );
+    
+    /** Notification that a module has been removed.
+     * 
+     * @param module
+     */
+    public void moduleRemove( Module module );
+    
+    /** Module reload - whenever reload happens, a reload notification will be generated.
+     * Sometimes a remove/add will do the same.
+     * 
+     * @param module
+     */
+    public void moduleReload( Module module );
+    
+    /** Called when a module is started. 
+     * 
+     * This is called after the class loader is created, to allow listeners to use classes
+     * from the module to initialize.
+     * 
+     * I think it would be good to have the module 'started' on first class loaded
+     * and 'stopped' explicitely.
+     * 
+     * @param module
+     */
+    public void moduleStart(Module module);
+    
+    /** 
+     *  Called when a module is stopped. Stoping a module will stop the class
+     * loader and remove all references to it. When a module is stopped, all attempts
+     * to load classes will result in exceptions. 
+     * 
+     * The callback is called before the class loader is stopped - this allows listeners
+     * to use classes from the module to deinitialize.
+     * 
+     * @param module
+     */
+    public void moduleStop(Module module);
+    
+    /** Pass a reference to the loader. 
+     * 
+     * This is the only supported way to get it - no static methods are 
+     * provided. From loader you can control all repositories and modules.
+     * 
+     * Note that ModuleClassLoader does not provide a way to retrieve the Module -
+     * you need to have a reference to the Loader to get the Module for a 
+     * ClassLoader. 
+     * @param main
+     */
+    public void setLoader(Loader main);
+
+    /** Start the listener.
+     * TODO: this is only used by Loader to pass control to the listener - 
+     * instead of introspection for main()
+     */
+    public void start();
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/util/loader/org/apache/tomcat/util/loader/Repository.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/util/loader/org/apache/tomcat/util/loader/Repository.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/util/loader/org/apache/tomcat/util/loader/Repository.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,480 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.loader;
+
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.net.URL;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Vector;
+
+
+/**
+ * A group of modules and libraries. 
+ * 
+ * Modules can have one or more jars and class dirs. Classloaders are created 
+ * from modules when the module is started are be disposed when the module is stopped.
+ * 
+ * The module will delegate to the associated repository in addition to the 
+ * normal delegation rules. The repository will search on all sibling modules.
+ * This mechanism is defined in the MLetClassLoader and is also used by JBoss and
+ * few other servers. 
+ * 
+ * TODO: explain more ( or point to the right jboss/mlet pages )
+ * TODO: explain how this can be used for webapps to support better partitioning 
+ *
+ * @author Costin Manolache
+ */
+public class Repository {
+   
+    private static final boolean DEBUG=Loader.getProperty("loader.debug.Repository") != null;
+    
+    // Allows the (experimental) use of jar indexes
+    // Right now ( for small set of jars, incomplete build ) it's a tiny 3.5 -> 3.4 sec dif.
+    private static final boolean USE_IDX=Loader.getProperty("loader.Repository.noIndex") == null;
+    
+    private Vector loaders=new Vector();
+    private String name;
+    private Vector grpModules=new Vector();
+    private transient Loader loader;
+    
+    private transient RepositoryClassLoader groupClassLoader;
+    private Hashtable prefixes=new Hashtable();
+
+    // For delegation
+    private ClassLoader parentClassLoader;
+    private Repository parent;
+
+
+    private Repository() {
+    }
+
+    public Repository(Loader loader) {
+        if( loader== null ) throw new NullPointerException();
+        this.loader=loader;
+    }
+
+    public Loader getLoader() {
+        return loader;
+    }
+    
+    void addModule(  Module mod ) {
+        mod.setRepository( this );
+
+        grpModules.addElement(mod);
+        if( loader.listener!=null ) {
+            loader.listener.moduleAdd(mod);
+        }
+        
+        if( parentClassLoader != null ) 
+            mod.setParentClassLoader( parentClassLoader );
+
+        if(! mod.isStarted()) {
+            mod.start();
+            //log("started " + mod);
+        } else {
+            //log("already started " + mod);
+        }
+        
+        try {
+            if( USE_IDX ) {
+                processJarIndex(mod);
+                // TODO: if we are in the initial starting, write cache only once
+                // TODO: write it only if there is a change in the timestamp
+                writeCacheIdx();
+            }
+        } catch (Exception e) {
+            // TODO Auto-generated catch block
+            e.printStackTrace();
+        }
+        
+    }
+    
+    public void newModule( String path ) {
+        Module m=new Module();
+        m.setPath( path );
+        addModule( m );
+    }
+    
+    public Enumeration getModules() {
+        return grpModules.elements();
+    }
+    
+    /** Reload any module that is modified
+     */
+    public void checkReload() {
+        try {
+        Enumeration mE=grpModules.elements();
+        while( mE.hasMoreElements() ) {
+            Module m=(Module)mE.nextElement();
+            boolean modif=m.modified();
+            log("Modified " + m + " " + modif);
+            
+            if( modif ) {
+                m.stop();
+                m.start();
+            }
+        }
+        } catch( Throwable t ) {
+            t.printStackTrace();
+        }
+    }
+
+    /** Verify if any module is modified. This is a deep search, including dirs.
+     *  Expensive operation.
+     *  
+     * @return
+     */
+    public boolean isModified() {
+        try {
+            Enumeration mE=grpModules.elements();
+            while( mE.hasMoreElements() ) {
+                Module m=(Module)mE.nextElement();
+                boolean modif=m.modified();
+                log("Modified " + m + " " + modif);
+                if( modif ) return true;
+            }
+        } catch( Throwable t ) {
+            t.printStackTrace();
+        }
+        return false;
+    }
+    
+    Repository getParent() {
+        return parent;
+    }
+    
+    public String toString() {
+        return "Repository " + name + "(" + getClasspathString() + ")";
+    }
+
+    private String getClasspathString() {
+        StringBuffer sb=new StringBuffer();
+        Enumeration mE=grpModules.elements();
+        while( mE.hasMoreElements() ) {
+            Module m=(Module)mE.nextElement();
+            sb.append( m.getClasspathString() + ":");
+        }
+        return sb.toString();
+    }
+
+    /**
+     * 
+     * @param parent The parent group
+     */
+    public void setParent(Repository parent) {
+        this.parent = parent;
+    }
+    
+    /** Set the parent class loader - can be used instead of setParent, 
+     * in case this is the top loader and needs to delagate to embedding app
+     * 
+     * @param myL
+     */
+    public void setParentClassLoader(ClassLoader myL) {
+        this.parentClassLoader=myL;
+    }
+
+
+    /** Add a class loder to the group.
+     *
+     *  If this is a StandardClassLoader instance, it will be able to delegate
+     * to the group.
+     *
+     *  If it's a regular ClassLoader - it'll be searched for classes, but
+     * it will not be able to delegate to peers.
+     *
+     * In future we may fine tune this by using manifests.
+     */
+    void addClassLoader(ClassLoader cl ) {
+        if( ( cl instanceof ModuleClassLoader )) {
+            ((ModuleClassLoader)cl).setRepository(this);
+        }
+        loaders.addElement(cl);
+        //    log("Adding classloader " + cl);
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void removeClassLoader(ClassLoader cl) {
+        int oldSize=loaders.size();
+        loaders.removeElement(cl);
+
+        if(DEBUG) log("removed " + loaders.size() + "/" + oldSize + ": "  + cl);
+        // TODO: remove from index
+    }
+
+    /** Return a class loader associated with the group.
+     *  This will delegate to all modules in the group, then to parent.
+     * 
+     * @return
+     */
+    public ClassLoader getClassLoader() {
+        if( groupClassLoader==null ) {
+            
+            ClassLoader pcl=parentClassLoader;
+            if( pcl==null && parent!=null ) {
+                pcl=parent.getClassLoader();
+            } 
+            if( pcl==null ) {
+                pcl=Thread.currentThread().getContextClassLoader();
+             }
+
+            if( pcl == null ) {
+                // allow delegation to embedding app
+                groupClassLoader=new RepositoryClassLoader(new URL[0], this);
+            } else {
+                groupClassLoader=new RepositoryClassLoader(new URL[0], pcl, this);
+            }
+            if( DEBUG ) log("---------- Created repository loader " + pcl );
+        }
+        return groupClassLoader;
+    }
+    
+    /** 
+     * Find a class in the group. It'll iterate over each loader
+     * and try to find the class - using only the method that
+     * search locally or on parent ( i.e. not in group, to avoid
+     * recursivity ).
+     *
+     *
+     * @param classN
+     * @return
+     */
+    Class findClass(ClassLoader caller, String classN ) {
+        Class clazz=null;
+        
+        // do we have it in index ?
+        if( USE_IDX ) {
+            int lastIdx=classN.lastIndexOf(".");
+            String prefix=(lastIdx>0) ? classN.substring(0, lastIdx) : classN;
+            Object mO=prefixes.get(prefix.replace('.', '/'));
+            if( mO!=null ) {
+                if( mO instanceof Module ) {
+                    Module m=(Module)mO;
+                    try {
+                        Class c=((ModuleClassLoader)m.getClassLoader()).findLocalClass(classN);
+                        //log("Prefix: " +prefix + " " + classN  + " " + m);
+                        return c;
+                    } catch (Exception e) {
+                        //log("Prefix err: " +prefix + " " + classN  + " " + m + " " + e);
+                        //return null;
+                    }
+                } else {
+                    Module mA[]=(Module[])mO;
+                    for( int i=0; i<mA.length; i++ ) {
+                        Module m=mA[i];
+                        try {
+                            Class c=((ModuleClassLoader)m.getClassLoader()).findLocalClass(classN);
+                            //log("Prefix: " +prefix + " " + classN  + " " + m);
+                            return c;
+                        } catch (Exception e) {
+                            //log("Prefix err: " +prefix + " " + classN  + " " + m + " " + e);
+                            //return null;
+                        }
+                    }
+                }
+            }
+        }
+
+        // TODO: move the vector to a []
+        for( int i=loaders.size()-1; i>=0; i-- ) {
+            
+            // TODO: for regular CL, just use loadClass, they'll not recurse
+            // The behavior for non-SCL or not in the group loader is the same as for parent loader
+            ModuleClassLoader cl=(ModuleClassLoader)loaders.elementAt(i);
+            // TODO: move loaders with index in separate vector
+            //if( cl.getModule().hasIndex ) continue;
+            if( cl== caller ) continue;
+            //if( classN.indexOf("SmtpCoyoteProtocolHandler") > 0 ) {
+            //log("try " + cl.debugObj + " " + name + " " + classN + " " + loaders.size());
+            //}
+            try {
+                if( cl instanceof ModuleClassLoader ) {
+                    clazz=((ModuleClassLoader)cl).findLocalClass(classN );
+                } else {
+                    clazz=cl.findClass(classN);
+                }
+
+                //System.err.println("GRPLD: " + classN + " from " + info.get(cl));
+                return clazz;
+            } catch (ClassNotFoundException e) {
+                //System.err.println("CNF: " + classN + " " + info.get(cl) );
+                //if( classN.indexOf("smtp") > 0 ) e.printStackTrace();
+            }
+        }
+        return null;
+    }
+    
+    /**
+     * @param loader
+     * @param name2
+     * @return
+     */
+    URL findResource(ModuleClassLoader caller, String classN) {
+        URL url=null;
+        if( DEBUG ) log("Repository.findResource " + classN + " " + caller );
+        for( int i=loaders.size()-1; i>=0; i-- ) {
+            // TODO: for regular CL, just use loadClass, they'll not recurse
+            // The behavior for non-SCL or not in the group loader is the same as for parent loader
+            ModuleClassLoader cl=(ModuleClassLoader)loaders.elementAt(i);
+            if( cl== caller ) continue;
+            url=((ModuleClassLoader)cl).findResource(classN );
+            if( url!=null )
+                return url;
+        }
+        return null;
+    }
+
+    private void log(String s) {
+        System.err.println("Repository (" + name + "): " + s );
+    }
+
+    /**
+     * @param name2
+     */
+    public void setName(String name2) {
+        this.name=name2;
+    }
+
+    /*
+     * Work in progress: 
+     * 
+     * -use the INDEX.LIST to get prefixes to avoid linear
+     * search in repositories.
+     * 
+     * - serialize the state ( including timestamps ) to improve startup time
+     * ( avoids the need to open all jars - if INDEX.LIST is ok)
+     */
+    
+    /**
+     * Read the index. The index contain packages and top level resources
+     * 
+     * @param cl
+     * @throws Exception
+     */
+    private void processJarIndex(Module m) throws Exception {
+        ModuleClassLoader cl=(ModuleClassLoader)m.createClassLoader();
+        // only support index for modules with a single jar in CP
+        String cp=m.getClasspathString();
+        if( ! cp.endsWith(".jar")) return;
+        URL urlIdx=cl.findResource("META-INF/INDEX.LIST");
+        if( urlIdx == null ) {
+            log("INDEX.LIST not found, run: jar -i " + m.getClasspathString());
+            return;
+        }
+        try {
+            InputStream is=urlIdx.openStream();
+            if( is==null ) {
+                log("Can't read " + urlIdx + " " + m.getClasspathString());
+                return;
+            }
+            BufferedReader br=new BufferedReader( new InputStreamReader(is) );
+            String line=br.readLine();
+            if( line==null ) return;
+            if( ! line.startsWith( "JarIndex-Version:") ||  
+                    ! line.endsWith("1.0")) {
+                log("Invalid signature " + line + " " + m.getClasspathString());
+            }
+            br.readLine(); // ""
+            
+            while( readSection(br, m) ) {
+            }
+           
+            m.hasIndex=true;
+        } catch (IOException e) {
+            // TODO Auto-generated catch block
+            e.printStackTrace();
+        }
+    }
+    
+    private boolean readSection( BufferedReader br, Module m) throws IOException {
+        String jarName=br.readLine();
+        if( jarName==null ) return false; // done
+        if( "".equals( jarName )) {
+            log("Invalid jarName " + jarName + " " + m.getClasspathString() );
+            return false;
+        }
+        //log("Index " + jarName + " " + m.getClasspathString());
+        String prefix=null;
+        while( ((prefix=br.readLine()) != null ) && 
+                (! "".equals( prefix )) ) {
+            //log("found " + prefix + " " + m);
+            Object o=prefixes.get(prefix);
+            if( o == null ) {
+                prefixes.put(prefix, m);
+            } else {
+                Module mA[]=null;
+                if( o instanceof Module ) {
+                    mA=new Module[2];
+                    mA[0]=(Module)o;
+                    mA[1]=m;
+                } else {
+                    Object oldA[]=(Module[])o;
+                    mA=new Module[oldA.length + 1];
+                    System.arraycopy(oldA, 0, mA, 0, oldA.length);
+                    mA[oldA.length]=m;
+                }
+                prefixes.put( prefix, mA);
+                //log("Multiple prefixes: " + prefix + " " + mA);
+                
+            }
+        }
+        
+        return prefix!=null;
+    }
+
+
+    /** Read loader.REPO.cache from work dir
+     * 
+     * This file will hold timestamps for each module/jar and cache the INDEX -
+     * to avoid opening the jars/modules that are not used 
+     * 
+     * @throws IOException
+     */
+    private void readCachedIdx() throws IOException {
+        
+    }
+    
+    /** Check the index and verify that:
+     * - all jars are older than timestamp and still exist
+     * - there are no new jars 
+     * 
+     * @throws IOException
+     */
+    private void checkCacheIdx() throws IOException {
+        
+    }
+    
+    
+    private void writeCacheIdx() throws IOException {
+        // For each module we write the timestamp, filename then the index
+        // The idea is to load this single file to avoid scanning many jars
+
+        // we'll use the cache 
+        
+        
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/connectors/util/loader/org/apache/tomcat/util/loader/RepositoryClassLoader.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/util/loader/org/apache/tomcat/util/loader/RepositoryClassLoader.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/util/loader/org/apache/tomcat/util/loader/RepositoryClassLoader.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,253 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.loader;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.Enumeration;
+import java.util.Vector;
+
+/**
+ * Class loader associated with a repository ( common, shared, server, etc ). 
+ *
+ * This class loader will never load any class by itself ( since it has no repository ),
+ * it will just delegate to modules. 
+ * 
+ * Refactored as a separate class to make the code cleaner.
+ * Based on catalina loader.
+ *   
+ * @author Costin Manolache
+ * @author Remy Maucherat
+ * @author Craig R. McClanahan
+ */
+public class RepositoryClassLoader
+    extends URLClassLoader
+{
+    private static final boolean DEBUG=false; //LoaderProperties.getProperty("loader.debug.ModuleClassLoader") != null;
+    private static final boolean DEBUGNF=false;//LoaderProperties.getProperty("loader.debug.ModuleClassLoaderNF") != null;
+    
+    // ----------------------------------------------------------- Constructors
+
+    public RepositoryClassLoader(URL repositories[], ClassLoader parent, Repository lg) {
+        super(repositories, parent);
+        this.repository=lg;
+    }
+    
+
+    public RepositoryClassLoader(URL repositories[], Repository lg) {
+        super(repositories);
+        this.repository=lg;
+    }
+
+
+    // ----------------------------------------------------- Instance Variables
+
+    private Repository repository;
+
+    // ---------------------------------------------------- ClassLoader Methods
+
+
+    /**
+     * Find the specified class in our local repositories, if possible.  If
+     * not found, throw <code>ClassNotFoundException</code>.
+     *
+     * @param name Name of the class to be loaded
+     *
+     * @exception ClassNotFoundException if the class was not found
+     */
+    public Class findClass(String name) throws ClassNotFoundException {
+
+        Class clazz = null;
+        
+        Enumeration modulesE=repository.getModules();
+        while( modulesE.hasMoreElements() ) {
+            try {
+                Module m=(Module)modulesE.nextElement();
+                return ((ModuleClassLoader)m.getClassLoader()).findClass2(name, false);
+            } catch( ClassNotFoundException ex ) {
+                // ignore
+            }
+        }
+        throw new ClassNotFoundException( name );
+
+    }
+    
+    /** Same as findClass, but also checks if the class has been previously 
+     * loaded.
+     * 
+     * In most implementations, findClass() doesn't check with findLoadedClass().
+     * In order to implement repository, we need to ask each loader in the group
+     * to load only from it's local resources - however this will lead to errors
+     * ( duplicated definition ) if findClass() is used.
+     *
+     * @param name
+     * @return
+     * @throws ClassNotFoundException
+     */
+    public Class findLocalClass(String name) throws ClassNotFoundException
+    {
+        Enumeration modulesE=repository.getModules();
+        while( modulesE.hasMoreElements() ) {
+            try {
+                Module m=(Module)modulesE.nextElement();
+                return ((ModuleClassLoader)m.getClassLoader()).findLocalClass(name);
+            } catch( ClassNotFoundException ex ) {
+                // ignore
+            }
+        }
+        throw new ClassNotFoundException( name );
+    }
+
+
+
+    
+    /**
+     * Find the specified resource in our local repository, and return a
+     * <code>URL</code> refering to it, or <code>null</code> if this resource
+     * cannot be found.
+     *
+     * @param name Name of the resource to be found
+     */
+    public URL findResource(final String name) {
+        URL url = null;
+        Enumeration modulesE=repository.getModules();
+        while( modulesE.hasMoreElements() ) {
+                Module m=(Module)modulesE.nextElement();
+                url=((ModuleClassLoader)m.getClassLoader()).findResource2(name, false);
+                if( url!= null ) {
+                    return url;
+                }
+        }
+        
+        if (url==null && DEBUG) {
+            if (DEBUGNF) log("findResource() NOTFOUND " + name );
+        }
+
+        return null;
+    }
+
+
+    /**
+     * Return an enumeration of <code>URLs</code> representing all of the
+     * resources with the given name.  If no resources with this name are
+     * found, return an empty enumeration.
+     *
+     * @param name Name of the resources to be found
+     *
+     * @exception IOException if an input/output error occurs
+     */
+    public Enumeration findResources(String name) throws IOException {
+        Vector result=new Vector();
+        
+        Enumeration modulesE=repository.getModules();
+        while( modulesE.hasMoreElements() ) {
+                Module m=(Module)modulesE.nextElement();
+                Enumeration myRes=((ModuleClassLoader)m.getClassLoader()).findResources2(name,false);
+                if( myRes!=null ) {
+                    while( myRes.hasMoreElements() ) {
+                        result.addElement(myRes.nextElement());
+                    }
+                }
+        }
+        
+        return result.elements();
+
+    }
+
+    // Next methods implement the search alghoritm - parent, repo, delegation, etc 
+
+    /** getResource() - modified to implement the search alghoritm 
+     * 
+     */
+    public URL getResource(String name) {
+        URL url = null;
+        Enumeration modulesE=repository.getModules();
+        while( modulesE.hasMoreElements() ) {
+                Module m=(Module)modulesE.nextElement();
+                url=((ModuleClassLoader)m.getClassLoader()).getResource2(name, null, false);
+                if( url!= null ) {
+                    return url;
+                }
+        }
+        
+        if (url==null && DEBUG) {
+            if (DEBUGNF) log("findResource() NOTFOUND " + name );
+        }
+
+        return null;
+    }
+    
+    /**
+     * Load the class with the specified name, searching using the following
+     * algorithm until it finds and returns the class.  If the class cannot
+     * be found, returns <code>ClassNotFoundException</code>.
+     * <ul>
+     * <li>Call <code>findLoadedClass(String)</code> to check if the
+     *     class has already been loaded.  If it has, the same
+     *     <code>Class</code> object is returned.</li>
+     * <li>If the <code>delegate</code> property is set to <code>true</code>,
+     *     call the <code>loadClass()</code> method of the parent class
+     *     loader, if any.</li>
+     * <li>Call <code>findClass()</code> to find this class in our locally
+     *     defined repositories.</li>
+     * <li>Call the <code>loadClass()</code> method of our parent
+     *     class loader, if any.</li>
+     * </ul>
+     * If the class was found using the above steps, and the
+     * <code>resolve</code> flag is <code>true</code>, this method will then
+     * call <code>resolveClass(Class)</code> on the resulting Class object.
+     *
+     * @param name Name of the class to be loaded
+     * @param resolve If <code>true</code> then resolve the class
+     *
+     * @exception ClassNotFoundException if the class was not found
+     */
+    public Class loadClass(String name, boolean resolve)
+        throws ClassNotFoundException
+    {
+
+        Class clazz = null;
+        Enumeration modulesE=repository.getModules();
+        while( modulesE.hasMoreElements() ) {
+            try {
+                Module m=(Module)modulesE.nextElement();
+                return ((ModuleClassLoader)m.getClassLoader()).loadClass2(name, resolve, false);
+            } catch( ClassNotFoundException ex ) {
+                // ignore
+            }
+        }
+        throw new ClassNotFoundException( name );
+
+    }
+
+
+    // ------------------ Local methods ------------------------
+
+    private void log(String s ) {
+        System.err.println("RepositoryClassLoader: " + s);
+    }
+    private void log(String s, Throwable t ) {
+        System.err.println("RepositoryClassLoader: " + s);
+        t.printStackTrace();
+    }
+
+}
+

Added: branches/tomcat5.5/upstream/5.5.20/connectors/util/loader/org/apache/tomcat/util/loader/package.html
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/util/loader/org/apache/tomcat/util/loader/package.html	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/util/loader/org/apache/tomcat/util/loader/package.html	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,32 @@
+<html>
+<body>
+
+The goal of this package is to provide class loading functionality, similar in behavior with Jboss and MLET loaders. There 
+is no specific policy, just a mechanism - how it is used depends on the application. It is based on the tomcat5.x class
+loader, with additional support for the 'repository' delegation.
+
+The main class is Loader - it controls a hierarchy of Repositories, each consisting of one or more Modules. Each Module corresponds to one jar file 
+or directory - and will have a ModuleClassLoader that answers only for that file. The Repository is associated with a ModuleClassLoader that delegates to 
+each Module. It is possible to add/remove/replace Modules at runtime - just like in JMX and JBoss. In normal tomcat, only webapps can be reloaded - this also allow connectors, valves, and any internal server jar to be reloaded.
+
+The package only deals with class loading, with minimal the dependencies. Currently there is no dependency except bare JDK1.3. 
+
+The modules and loaders can be registered with JMX by a module using the ModuleListener, after jmx class loader is created. Note that JMX is not a dependency and doesn't have to be in the classpath - it can be loaded in a Repository, and then something like Modeler will do the mapping. 
+
+Configuration uses a simple properties file describing the classpaths and the classes to launch - i.e. all a class loader needs to know, and similar with the old catalina.properties. 
+
+To implement a good module system on top of this we need lifecycle ( already present in tomcat ) and discipline in making sure there are no stale references to  objects in a module after its death. 
+
+An OSGI-like system may seem to deal with the second problem - but it doesn't solve anything, it just makes 
+the references more visible and requires major changes in how you code, as well as rewriting of most apis and implementations - and in the end it still 
+doesn't solve the problem. JBoss and JMX are actually on the right track in this, as oposed to OSGI. 
+
+The loader is also trying to stick to the minimal classloading-related functionality - unlike OSGI wich is reinventing all weels. I started working on the loader after trying to see how OSGI would fit, and realizing that it is a wrong design.
+
+
+<h2>Using loader for launching</h2>
+
+Loader has a main(), and will look up the loader.properties file, create the class loaders, and then launch any 'auto-startup' classes. The must important part of launching an app is setting the classpath, and using Loader allows the app to use more advanced features than using simple CLASSPATH.
+
+</body>
+</html>

Added: branches/tomcat5.5/upstream/5.5.20/connectors/util/loader/tomcat-loader.manifest
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/connectors/util/loader/tomcat-loader.manifest	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/connectors/util/loader/tomcat-loader.manifest	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,8 @@
+Manifest-version: 1.0
+Extension-Name: org.apache.tomcat.util.loader
+Specification-Vendor: Apache Software Foundation
+Specification-Version: 1.0
+Implementation-Vendor-Id: org.apache
+Implementation-Vendor: Apache Software Foundation
+Implementation-Version: 1.0
+Main-Class: org.apache.tomcat.util.loader.Loader

Added: branches/tomcat5.5/upstream/5.5.20/container/.classpath
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/.classpath	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/.classpath	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+	<classpathentry excluding="org/apache/naming/factory/MailSessionFactory.java|org/apache/naming/factory/SendMailFactory.java" kind="src" path="catalina/src/share"/>
+	<classpathentry kind="src" path="modules/cluster/src/share"/>
+	<classpathentry kind="src" path="modules/storeconfig/src/share"/>
+	<classpathentry kind="src" path="webapps/admin/WEB-INF/classes"/>
+	<classpathentry kind="src" path="webapps/balancer/WEB-INF/classes"/>
+	<classpathentry kind="src" path="webapps/docs/appdev/sample/src"/>
+	<classpathentry kind="src" path="webapps/host-manager/WEB-INF/classes"/>
+	<classpathentry kind="src" path="webapps/jmxremote/WEB-INF/src"/>
+	<classpathentry kind="src" path="webapps/manager/WEB-INF/classes"/>
+	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
+	<classpathentry kind="var" path="ANT_HOME/lib/ant.jar"/>
+	<classpathentry kind="var" path="TOMCAT_LIBS_BASE/commons-logging-1.0.4/commons-logging-api.jar"/>
+	<classpathentry kind="var" path="TOMCAT_LIBS_BASE/commons-modeler-1.1/commons-modeler.jar"/>
+	<classpathentry kind="var" path="TOMCAT_LIBS_BASE/mx4j-3.0.1/lib/mx4j.jar"/>
+	<classpathentry kind="var" path="TOMCAT_LIBS_BASE/commons-launcher-0.9/bin/commons-launcher.jar"/>
+	<classpathentry kind="var" path="TOMCAT_LIBS_BASE/struts-1.2.7/lib/antlr.jar"/>
+	<classpathentry kind="var" path="TOMCAT_LIBS_BASE/struts-1.2.7/lib/commons-beanutils.jar"/>
+	<classpathentry kind="var" path="TOMCAT_LIBS_BASE/struts-1.2.7/lib/commons-digester.jar"/>
+	<classpathentry kind="var" path="TOMCAT_LIBS_BASE/struts-1.2.7/lib/commons-fileupload.jar"/>
+	<classpathentry kind="var" path="TOMCAT_LIBS_BASE/struts-1.2.7/lib/commons-logging.jar"/>
+	<classpathentry kind="var" path="TOMCAT_LIBS_BASE/struts-1.2.7/lib/commons-validator.jar"/>
+	<classpathentry kind="var" path="TOMCAT_LIBS_BASE/struts-1.2.7/lib/jakarta-oro.jar"/>
+	<classpathentry kind="var" path="TOMCAT_LIBS_BASE/struts-1.2.7/lib/struts.jar"/>
+	<classpathentry combineaccessrules="false" kind="src" path="/connectors"/>
+	<classpathentry combineaccessrules="false" kind="src" path="/build"/>
+	<classpathentry kind="var" path="TOMCAT_LIBS_BASE/servlet-api-2.4/lib/servlet-api.jar"/>
+	<classpathentry kind="var" path="TOMCAT_LIBS_BASE/jsp-api-2.0/lib/jsp-api.jar"/>
+	<classpathentry kind="output" path="bin"/>
+</classpath>

Added: branches/tomcat5.5/upstream/5.5.20/container/.project
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/.project	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/.project	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>container</name>
+	<comment></comment>
+	<projects>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>org.eclipse.jdt.core.javabuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>org.eclipse.jdt.core.javanature</nature>
+	</natures>
+</projectDescription>

Added: branches/tomcat5.5/upstream/5.5.20/container/LICENSE
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/LICENSE	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/LICENSE	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,202 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed 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.

Added: branches/tomcat5.5/upstream/5.5.20/container/NOTICE
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/NOTICE	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/NOTICE	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,2 @@
+This product includes software developed by
+The Apache Software Foundation (http://www.apache.org/).

Added: branches/tomcat5.5/upstream/5.5.20/container/Tomcat5.5.launch
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/Tomcat5.5.launch	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/Tomcat5.5.launch	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<launchConfiguration type="org.eclipse.jdt.launching.localJavaApplication">
+<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="org.apache.catalina.startup.Catalina"/>
+<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="start"/>
+<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="container"/>
+<listAttribute key="org.eclipse.debug.ui.favoriteGroups">
+<listEntry value="org.eclipse.debug.ui.launchGroup.run"/>
+<listEntry value="org.eclipse.debug.ui.launchGroup.debug"/>
+</listAttribute>
+<stringAttribute key="org.eclipse.jdt.launching.WORKING_DIRECTORY" value="${workspace_loc:container}"/>
+<booleanAttribute key="org.eclipse.debug.core.appendEnvironmentVariables" value="true"/>
+</launchConfiguration>

Added: branches/tomcat5.5/upstream/5.5.20/container/build.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/build.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/build.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,188 @@
+<project name="Catalina 2.0" default="deploy" basedir=".">
+
+
+  <!-- ===================== Initialize Property Values =================== -->
+
+  <!-- See "build.properties.sample" in the top level directory for all     -->
+  <!-- property values you must customize for successful building!!!        -->
+  <!--property file="build.properties"/>
+  <property file="${user.home}/build.properties"/-->
+
+  <!-- Build Defaults -->
+  <!--property name="catalina.build"   value="${basedir}/catalina/build"/-->
+
+  <!-- Source dependencies -->
+  <property name="api.home"
+           value="${basedir}/../jakarta-servletapi-5"/>
+  <property name="jtc.home"
+           value="${basedir}/../jakarta-tomcat-connectors"/>
+
+
+  <!-- =================== DETECT: Display configuration ================== -->
+  <target name="flags.display"
+   description="Display configuration and conditional compilation flags">
+
+    <ant dir="${basedir}/catalina" target="flags.display"/>
+    <ant dir="${basedir}/webapps/admin" target="flags.display"/>
+
+  </target>
+
+
+  <!-- ===================== DEPLOY: Create Directories =================== -->
+  <target name="deploy-prepare">
+    <mkdir dir="${tomcat.build}"/>
+  </target>
+
+
+  <!-- ====================== DEPLOY: Copy Static Files =================== -->
+  <target name="deploy-static" depends="deploy-prepare"/>
+
+
+  <!-- ====================== DEPLOY: Deploy Components =================== -->
+  <target name="deploy" depends="deploy-static"
+   description="Build and deploy all components">
+    <echo>Target: Catalina - Deploy ...</echo>
+    <ant dir="${basedir}/catalina" target="deploy"/>
+    <echo>Target: Webapps - Deploy ...</echo>
+    <ant dir="${basedir}/webapps"  target="deploy"/>
+  </target>
+
+  <!-- ====================== DEPLOY: Deploy Core Components =================== -->
+  <!-- used by gump to build just catalina and not the j-t-connectors -->
+  <target name="deploy-catalina" depends="deploy-static"
+   description="Build and deploy all components">
+    <echo>Target: Catalina - Deploy ...</echo>
+    <ant dir="${basedir}/catalina" target="deploy-catalina"/>
+    <echo>Target: Webapps - Deploy ...</echo>
+    <ant dir="${basedir}/webapps"  target="deploy"/>
+  </target>
+
+
+  <!-- ====================== COMBO: Clean All Directories ================ -->
+  <target name="clean"
+   description="Clean all components">
+    <delete dir="${tomcat.build}"/>
+    <echo>Target: Catalina - Clean ...</echo>
+    <ant dir="${basedir}/catalina" target="clean"/>
+    <echo>Target: Webapps - Clean ...</echo>
+    <ant dir="${basedir}/webapps"  target="clean"/>
+    <delete dir="${tomcat.dist}"/>
+  </target>
+
+
+  <!-- ======================= COMBO: Build All Components ================ -->
+  <target name="all"
+   description="Clean, build, and deploy all components">
+    <echo>Target: Catalina - All ...</echo>
+    <ant dir="${basedir}/catalina" target="all"/>
+    <echo>Target: Webapps - All ...</echo>
+    <ant dir="${basedir}/webapps"  target="all"/>
+  </target>
+
+
+  <!-- ======================= COMBO: Test All Components ================= -->
+  <target name="test"
+   description="Unit tests on all components">
+    <echo>Target: Catalina - Test ...</echo>
+    <ant dir="${basedir}/catalina" target="test"/>
+    <echo>Target: Webapps - Test ...</echo>
+    <ant dir="${basedir}/webapps"  target="test"/>
+  </target>
+
+
+  <!-- ====================== DIST: Create Directories ==================== -->
+  <target name="dist-prepare">
+    <mkdir dir="${tomcat.dist}"/>
+    <mkdir dir="${tomcat.dist}/bin"/>
+    <mkdir dir="${tomcat.dist}/common"/>
+    <mkdir dir="${tomcat.dist}/common/classes"/>
+    <mkdir dir="${tomcat.dist}/common/endorsed"/>
+    <mkdir dir="${tomcat.dist}/common/lib"/>
+    <mkdir dir="${tomcat.dist}/conf"/>
+    <mkdir dir="${tomcat.dist}/logs"/>
+    <mkdir dir="${tomcat.dist}/server"/>
+    <mkdir dir="${tomcat.dist}/server/classes"/>
+    <mkdir dir="${tomcat.dist}/server/lib"/>
+    <mkdir dir="${tomcat.dist}/shared/classes"/>
+    <mkdir dir="${tomcat.dist}/shared/lib"/>
+    <mkdir dir="${tomcat.dist}/webapps"/>
+    <mkdir dir="${tomcat.dist}/work"/>
+    <mkdir dir="${tomcat.dist}/temp"/>
+  </target>
+
+
+  <!-- ====================== DIST: Copy Static Files ===================== -->
+  <target name="dist-static" depends="dist-prepare">
+
+    <!-- Copy the top-level documentation files -->
+    <copy todir="${tomcat.dist}">
+      <fileset dir=".">
+        <include name="LICENSE"/>
+        <include name="INSTALLING.txt"/>
+        <include name="BUILDING.txt"/>
+        <include name="README.txt"/>
+        <include name="RELEASE*"/>
+        <include name="RUNNING.txt"/>
+      </fileset>
+    </copy>
+
+    <!-- Copy the contents of each "build" directory -->
+    <copy todir="${tomcat.dist}/bin">
+      <fileset dir="${tomcat.build}/bin" />
+    </copy>
+    <copy todir="${tomcat.dist}/common/classes">
+      <fileset dir="${tomcat.build}/common/classes" />
+    </copy>
+    <copy todir="${tomcat.dist}/common/endorsed">
+      <fileset dir="${tomcat.build}/common/endorsed" />
+    </copy>
+    <copy todir="${tomcat.dist}/common/lib">
+      <fileset dir="${tomcat.build}/common/lib" />
+    </copy>
+    <copy todir="${tomcat.dist}/conf">
+      <fileset dir="${tomcat.build}/conf" />
+    </copy>
+    <copy todir="${tomcat.dist}/server/classes">
+      <fileset dir="${tomcat.build}/server/classes" />
+    </copy>
+    <copy todir="${tomcat.dist}/server/lib">
+      <fileset dir="${tomcat.build}/server/lib" />
+    </copy>
+    <copy todir="${tomcat.dist}/server/webapps">
+      <fileset dir="${tomcat.build}/server/webapps" />
+    </copy>
+    <copy todir="${tomcat.dist}/shared/classes">
+      <fileset dir="${tomcat.build}/shared/classes" />
+    </copy>
+    <copy todir="${tomcat.dist}/shared/lib">
+      <fileset dir="${tomcat.build}/shared/lib" />
+    </copy>
+    <copy todir="${tomcat.dist}/webapps">
+      <fileset dir="${tomcat.build}/webapps" />
+    </copy>
+
+    <!-- Correct permissions and line endings on "bin" scripts -->
+    <fixcrlf srcdir="${tomcat.dist}/bin"   includes="*.sh"  eol="lf"/>
+    <fixcrlf srcdir="${tomcat.dist}/bin"   includes="*.bat" eol="crlf"/>
+    <chmod      dir="${tomcat.dist}/bin"   includes="*.sh"  perm="+x"/>
+
+  </target>
+
+
+  <!-- ====================== DIST: Create Javadoc ======================== -->
+  <target name="dist-javadoc">
+    <ant dir="${basedir}/catalina" target="javadoc"/>
+    <mkdir  dir="${tomcat.dist}/webapps/tomcat-docs/catalina/docs/api"/>
+    <copy todir="${tomcat.dist}/webapps/tomcat-docs/catalina/docs/api">
+      <fileset dir="${catalina.build}/javadoc" />
+    </copy>
+  </target>
+
+
+  <!-- ====================== DIST: Create Archives ======================= -->
+  <target name="dist" depends="deploy,dist-static,dist-javadoc"
+   description="Create binary distribution">
+  </target>
+
+
+</project>

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/build.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/build.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/build.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,1213 @@
+<project name="Catalina" default="deploy" basedir=".">
+
+
+  <!-- ===================== Initialize Property Values =================== -->
+
+  <!-- See "build.properties.sample" in the top level directory for all     -->
+  <!-- property values you must customize for successful building!!!        -->
+  <!--property file="build.properties"/>
+  <property file="../build.properties"/>
+  <property file="${user.home}/build.properties"/-->
+
+  <!-- Build Defaults -->
+  <property name="catalina.home"     location=".."/>
+  <property name="catalina.build"    value="${catalina.home}/catalina/build"/>
+  <property name="classes.dir" value="${catalina.build}/server/classes" />
+  <property name="catalina.deploy"   value="${catalina.home}/build"/>
+  <property name="catalina.dist"     value="${catalina.home}/dist"/>
+  <property name="test.failonerror"  value="true"/>
+  <property name="test.runner"       value="junit.textui.TestRunner"/>
+  <property name="test.webapp"       value="../webapps/build/ROOT"/>
+  <property name="test.webapp.war"   value="${java.io.tmpdir}/webapp.war"/>
+
+  <!-- Source dependencies -->
+  <property name="tomcat-util.home"       value="${jtc.home}/util"/>
+  <property name="tomcat-coyote.home"     value="${jtc.home}/coyote"/>
+  <property name="tomcat-jk.home"         value="${jtc.home}/jk"/>
+  <property name="tomcat-http11.home"     value="${jtc.home}/http11"/>
+
+  <!-- Dependent JARs and files -->
+  <property name="ant.jar" value="${ant.home}/lib/ant.jar"/>
+  <property name="servlet-api.jar" value="${api.home}/jsr154/dist/lib/servlet-api.jar"/>
+  <property name="tomcat-util.jar"
+           value="${tomcat-util.home}/build/lib/tomcat-util.jar"/>
+  <property name="tomcat-coyote.jar"
+           value="${tomcat-coyote.home}/build/lib/tomcat-coyote.jar"/>
+  <property name="tomcat-jk2.jar"
+           value="${tomcat-jk.home}/build/lib/tomcat-jk2.jar"/>
+  <property name="tomcat-jni.jar"
+           value="${tomcat-jk.home}/build/lib/tomcat-jni.jar"/>
+  <property name="jk2.properties"
+           value="${tomcat-jk.home}/build/conf/jk2.properties"/>
+  <property name="tomcat-http11.jar"
+           value="${tomcat-http11.home}/build/lib/tomcat-http11.jar"/>
+  <property name="tomcat-dbcp.jar" 
+           value="${base.path}/tomcat-deps/naming-factory-dbcp.jar"/>
+  <!-- Construct Catalina classpath -->
+  <path id="catalina.classpath">
+    <pathelement location="${activation.jar}"/>
+    <pathelement location="${ant.jar}"/>
+    <pathelement location="${commons-beanutils.jar}"/>
+    <pathelement location="${commons-collections.jar}"/>
+    <pathelement location="${tomcat-dbcp.jar}"/>
+    <pathelement location="${commons-digester.jar}"/>
+    <pathelement location="${commons-fileupload.jar}"/>
+    <pathelement location="${commons-launcher.jar}"/>
+    <pathelement location="${commons-logging.jar}"/>
+    <pathelement location="${commons-modeler.jar}"/>
+    <pathelement location="${tomcat-util.jar}"/>
+    <pathelement location="${tomcat-coyote.jar}"/>
+    <pathelement location="${jaas.jar}"/>
+    <pathelement location="${javagroups.jar}"/>
+    <pathelement location="${jcert.jar}"/>
+    <pathelement location="${jmx.jar}"/>
+    <pathelement location="${jmx-remote.jar}"/>
+    <pathelement location="${jndi.jar}"/>
+    <pathelement location="${jnet.jar}"/>
+    <pathelement location="${jsse.jar}"/>
+    <pathelement location="${java.home}/lib/jsse.jar"/>
+    <pathelement location="${jta.jar}"/>
+    <pathelement location="${ldap.jar}"/>
+    <pathelement location="${mail.jar}"/>
+    <pathelement location="${regexp.jar}"/>
+    <pathelement location="${servlet-api.jar}"/>
+    <pathelement location="${xercesImpl.jar}"/>
+    <pathelement location="${xml-apis.jar}"/>
+    <pathelement location="${classes.dir}"/>
+  </path>
+
+  <!-- Construct unit tests classpath -->
+  <path id="test.classpath">
+    <pathelement location="${junit.jar}"/>
+    <pathelement location="${activation.jar}"/>
+    <pathelement location="${ant.jar}"/>
+    <pathelement location="${commons-beanutils.jar}"/>
+    <pathelement location="${commons-collections.jar}"/>
+    <pathelement location="${tomcat-dbcp.jar}"/>
+    <pathelement location="${commons-digester.jar}"/>
+    <pathelement location="${commons-fileupload.jar}"/>
+    <pathelement location="${commons-launcher.jar}"/>
+    <pathelement location="${commons-logging.jar}"/>
+    <pathelement location="${commons-modeler.jar}"/>
+    <pathelement location="${jaas.jar}"/>
+    <pathelement location="${jcert.jar}"/>
+    <pathelement location="${jmx.jar}"/>
+    <pathelement location="${jndi.jar}"/>
+    <pathelement location="${jnet.jar}"/>
+    <pathelement location="${jsse.jar}"/>
+    <pathelement location="${jta.jar}"/>
+    <pathelement location="${ldap.jar}"/>
+    <pathelement location="${mail.jar}"/>
+    <pathelement location="${regexp.jar}"/>
+    <pathelement location="${servlet-api.jar}"/>
+    <pathelement location="${xercesImpl.jar}"/>
+    <pathelement location="${xml-apis.jar}"/>
+    <pathelement location="${classes.dir}"/>
+    <pathelement location="${catalina.build}/tests"/>
+  </path>
+
+  <!-- Source path -->
+  <path id="javadoc.sourcepath">
+    <pathelement location="src/share"/>
+    <pathelement location="${tomcat-util.home}/java"/>
+    <pathelement location="${tomcat-coyote.home}/src/java"/>
+    <pathelement location="${tomcat-jk.home}/java"/>
+    <pathelement location="${tomcat-http11.home}/src/java"/>
+    <pathelement location="../modules/cluster/src/share"/>
+    <pathelement location="../modules/storeconfig/src/share"/>
+  </path>
+
+
+  <!-- =================== BUILD: Set compile flags ======================= -->
+  <target name="flags">
+
+    <!-- JDK flags -->
+    <available property="jdk.1.2.present" classname="java.util.HashMap" />
+    <available property="jdk.1.3.present" 
+     classname="java.lang.reflect.Proxy" />
+    <available property="jdk.1.4.present" classname="java.nio.Buffer" />
+    <available property="jdk.1.5.present" 
+     classname="java.util.concurrent.Semaphore" />
+
+    <!-- Ant flags -->
+    <available property="style.available"
+     classname="org.apache.tools.ant.taskdefs.optional.TraXLiaison" />
+
+    <!-- Source path -->
+    <available property="jtc.home.present" file="${jtc.home}" />
+
+    <!-- Class availability flags -->
+    <available property="beanutils.present"
+     classname="org.apache.commons.beanutils.BeanUtils"
+     classpath="${commons-beanutils.jar}"/>
+    <available property="collections.present"
+     classname="org.apache.commons.collections.FastHashMap"
+     classpath="${commons-collections.jar}"/>
+    <available property="dbcp.present"
+     classname="org.apache.tomcat.dbcp.dbcp.ConnectionFactory"
+     classpath="${tomcat-dbcp.jar}"/>
+    <available property="digester.present"
+     classname="org.apache.commons.digester.Digester"
+     classpath="${commons-digester.jar}"/>
+    <available property="fileupload.present"
+     classname="org.apache.commons.fileupload.FileUpload"
+     classpath="${commons-fileupload.jar}"/>
+    <available property="launcher.present"
+     classname="org.apache.commons.launcher.Launcher"
+     classpath="${commons-launcher.jar}"/>
+    <available property="launcher.bootstrap.present"
+     file="${commons-launcher.bootstrap.class}"/>
+    <available property="logging.present"
+     classname="org.apache.commons.logging.Log"
+     classpath="${commons-logging.jar}"/>
+    <available property="modeler.present"
+     classname="org.apache.commons.modeler.Registry"
+     classpath="${commons-modeler.jar}:${jmx.jar}"/>
+    <available property="jaas.present"
+     classname="javax.security.auth.Subject"
+     classpath="${jaas.jar}" />
+    <condition property="jaxp.present">
+      <and>
+        <available classname="javax.xml.parsers.SAXParser"
+         classpath="${xml-apis.jar}" />
+        <available classname="org.xml.sax.ContentHandler"
+         classpath="${xml-apis.jar}" />
+      </and>
+    </condition>
+    <condition property="javamail.present">
+      <and>
+        <available classname="javax.activation.DataSource"
+         classpath="${activation.jar}" />
+        <available classname="javax.mail.Service"
+         classpath="${mail.jar}" />
+      </and>
+    </condition>
+    <available property="jmx.present"
+     classname="javax.management.MBeanServer"
+     classpath="${jmx.jar}" />
+    <available property="jndi.present"
+     classname="javax.naming.Context"
+     classpath="${jndi.jar}" />
+    <condition property="jsse.present">
+      <and>
+        <available classname="javax.security.cert.Certificate"
+         classpath="${jcert.jar}" />
+        <available classname="javax.net.SocketFactory"
+         classpath="${jnet.jar}" />
+        <available classname="javax.net.ssl.SSLSocket"
+         classpath="${jsse.jar}" />
+      </and>
+    </condition>
+    <available property="jta.present"
+      classname="javax.transaction.UserTransaction"
+      classpath="${jta.jar}" />
+    <available property="junit.present"
+     classname="junit.framework.TestCase"
+     classpath="${junit.jar}" />
+    <available property="ldap.present"
+     classname="com.sun.jndi.ldap.LdapClient"
+     classpath="${ldap.jar}" />
+    <available property="pool.present"
+     classname="org.apache.tomcat.dbcp.pool.ObjectPool"
+     classpath="${tomcat-dbcp.jar}"/>
+    <available property="regexp.present"
+     classname="org.apache.regexp.RE"
+     classpath="${regexp.jar}" />
+    <available property="xerces.present"
+     classname="org.apache.xerces.parsers.SAXParser"
+     classpath="${xercesImpl.jar}" />
+
+    <!-- JAR files availability flags -->
+    <available property="dbcp.jar.present" file="${tomcat-dbcp.jar}" />
+    <available property="fileupload.jar.present" file="${commons-fileupload.jar}" />
+    <available property="jaas.jar.present" file="${jaas.jar}" />
+    <condition property="javamail.jar.present">
+      <and>
+        <available file="${activation.jar}" />
+        <available file="${mail.jar}" />
+      </and>
+    </condition>
+    <available property="jmx.jar.present" file="${jmx.jar}" />
+    <available property="jcert.jar.present" file="${jcert.jar}" />
+    <available property="jndi.jar.present" file="${jndi.jar}" />
+    <available property="jnet.jar.present" file="${jnet.jar}" />
+    <available property="jsse.jar.present" file="${jsse.jar}" />
+    <available property="jta.jar.present" file="${jta.jar}" />
+    <available property="junit.jar.present" file="${junit.jar}" />
+    <condition property="launcher.jars.present">
+      <and>
+        <equals arg1="${launcher.present}" arg2="true"/>
+        <equals arg1="${launcher.bootstrap.present}" arg2="true"/>
+      </and>
+    </condition>
+    <available property="ldap.jar.present" file="${ldap.jar}" />
+    <available property="logging.jar.present" file="${commons-logging.jar}" />
+    <available property="modeler.jar.present" file="${commons-modeler.jar}" />
+    <available property="pool.jar.present" file="${tomcat-dbcp.jar}" />
+    <available property="regexp.jar.present" file="${regexp.jar}" />
+    <available property="servlet-api.jar.present" file="${servlet-api.jar}" />
+    <available property="tomcat-util.jar.present" file="${tomcat-util.jar}" />
+    <available property="xercesImpl.jar.present" file="${xercesImpl.jar}"/>
+    <available property="xml-apis.jar.present" file="${xml-apis.jar}"/>
+    <condition property="xerces2.jars.present">
+      <and>
+        <equals arg1="${xercesImpl.jar.present}" arg2="true"/>
+        <equals arg1="${xml-apis.jar.present}" arg2="true"/>
+      </and>
+    </condition>
+
+    <!-- Conditional compilation flags (determined from the flags above) -->
+    <condition property="compile.dbcp">
+      <or>
+        <equals arg1="${full.dist}" arg2="on" />
+        <and>
+          <equals arg1="${dbcp.present}" arg2="true" />
+          <equals arg1="${pool.present}" arg2="true" />
+        </and>
+      </or>
+    </condition>
+    <condition property="compile.jaas">
+      <or>
+        <equals arg1="${full.dist}" arg2="on" />
+        <equals arg1="${jaas.present}" arg2="true" />
+      </or>
+    </condition>
+    <condition property="compile.javamail">
+      <or>
+        <equals arg1="${full.dist}" arg2="on" />
+        <equals arg1="${javamail.present}" arg2="true" />
+      </or>
+    </condition>
+    <condition property="compile.jmx">
+      <or>
+        <equals arg1="${full.dist}" arg2="on" />
+        <and>
+          <equals arg1="${jmx.present}" arg2="true" />
+          <equals arg1="${modeler.present}" arg2="true" />
+        </and>
+      </or>
+    </condition>
+    <condition property="compile.jndi">
+      <or>
+        <equals arg1="${full.dist}" arg2="on" />
+        <equals arg1="${jndi.present}" arg2="true" />
+        <equals arg1="${jdk.1.3.present}" arg2="true" />
+      </or>
+    </condition>
+    <condition property="compile.jsse">
+      <or>
+        <equals arg1="${full.dist}" arg2="on" />
+        <equals arg1="${jsse.present}" arg2="true" />
+        <equals arg1="${jdk.1.4.present}" arg2="true" />
+      </or>
+    </condition>
+    <condition property="compile.jta">
+      <or>
+        <equals arg1="${full.dist}" arg2="on" />
+        <equals arg1="${jta.present}" arg2="true" />
+      </or>
+    </condition>
+    <condition property="compile.junit">
+      <or>
+        <equals arg1="${full.dist}" arg2="on" />
+        <equals arg1="${junit.present}" arg2="true" />
+      </or>
+    </condition>
+    <condition property="compile.launcher">
+      <or>
+        <equals arg1="${full.dist}" arg2="on" />
+        <and>
+          <equals arg1="${launcher.present}" arg2="true" />
+          <equals arg1="${launcher.bootstrap.present}" arg2="true" />
+        </and>
+      </or>
+    </condition>
+    <condition property="compile.ldap">
+      <or>
+        <equals arg1="${full.dist}" arg2="on" />
+        <equals arg1="${ldap.present}" arg2="true" />
+        <equals arg1="${jdk.1.3.present}" arg2="true" />
+      </or>
+    </condition>
+    <property name="compile.ssi" value="true"/>
+
+
+    <!-- Conditional copy flags (determined from the flags above) -->
+    <condition property="copy.dbcp.jar">
+      <or>
+        <equals arg1="${full.dist}" arg2="on" />
+        <equals arg1="${dbcp.present}" arg2="true" />
+      </or>
+    </condition>
+    <condition property="copy.jmx.jar">
+      <or>
+        <equals arg1="${full.dist}" arg2="on" />
+        <equals arg1="${jmx.jar.present}" arg2="true" />
+      </or>
+    </condition>
+    <condition property="copy.lang.jar">
+      <or>
+        <equals arg1="${full.dist}" arg2="on" />
+        <equals arg1="${lang.present}" arg2="true" />
+      </or>
+    </condition>
+    <condition property="copy.launcher.jars">
+      <or>
+        <equals arg1="${full.dist}" arg2="on" />
+        <equals arg1="${launcher.jars.present}" arg2="true" />
+      </or>
+    </condition>
+    <condition property="copy.modeler.jar">
+      <or>
+        <equals arg1="${full.dist}" arg2="on" />
+        <equals arg1="${modeler.present}" arg2="true" />
+      </or>
+    </condition>
+    <condition property="copy.logging.jar">
+      <or>
+        <equals arg1="${full.dist}" arg2="on" />
+        <equals arg1="${logging.present}" arg2="true" />
+      </or>
+    </condition>
+    <condition property="copy.pool.jar">
+      <or>
+        <equals arg1="${full.dist}" arg2="on" />
+        <equals arg1="${pool.present}" arg2="true" />
+      </or>
+    </condition>
+
+  </target>
+
+
+  <!-- =================== BUILD: Set compile flags ======================= -->
+  <target name="flags.display" depends="flags" unless="flags.hide">
+
+    <echo message="--- Build environment for Catalina ---" />
+
+    <echo message="If ${property_name} is displayed, then the property is not set)" />
+
+    <echo message="--- Build options ---" />
+    <echo message="full.dist=${full.dist}" />
+    <echo message="build.sysclasspath=${build.sysclasspath}" />
+    <echo message="compile.debug=${compile.debug}" />
+    <echo message="compile.deprecation=${compile.deprecation}" />
+    <echo message="compile.optimize=${compile.optimize}" />
+
+    <echo message="--- Ant Flags ---" />
+    <echo message="&lt;style&gt; task available (required)=${style.available}" />
+
+    <echo message="--- JDK ---" />
+    <echo message="jdk.1.2.present=${jdk.1.2.present}" />
+    <echo message="jdk.1.3.present=${jdk.1.3.present}" />
+    <echo message="jdk.1.4.present=${jdk.1.4.present}" />
+
+    <echo message="--- Source Dependencies ---" />
+    <echo message="jtc.home.present=${jtc.home.present}" />
+
+    <echo message="--- Required Libraries ---" />
+    <echo message="beanutils.present=${beanutils.present}" />
+    <echo message="collections.present=${collections.present}" />
+    <echo message="digester.present=${digester.present}" />
+    <echo message="jaxp.present=${jaxp.present}" />
+    <echo message="jndi.present=${jndi.present}" />
+    <echo message="logging.present=${logging.present}" />
+    <echo message="regexp.present=${regexp.present}" />
+
+    <echo message="--- Optional Libraries ---" />
+    <echo message="dbcp.present=${dbcp.present}" />
+    <echo message="fileupload.present=${fileupload.present}" />
+    <echo message="jaas.present=${jaas.present}" />
+    <echo message="javamail.present=${javamail.present}" />
+    <echo message="jmx.present=${jmx.present}" />
+    <echo message="jsse.present=${jsse.present}" />
+    <echo message="jta.present=${jta.present}" />
+    <echo message="junit.present=${junit.present}" />
+    <echo message="lang.present=${lang.present}" />
+    <echo message="launcher.present=${launcher.present}" />
+    <echo message="launcher.bootstrap.present=${launcher.bootstrap.present}" />
+    <echo message="ldap.present=${ldap.present}" />
+    <echo message="modeler.present=${modeler.present}"  />
+    <echo message="pool.present=${pool.present}" />
+
+    <echo message="--- Required JARs ---" />
+    <echo message="jndi.jar.present(except JDK 1.3+)=${jndi.jar.present}" />
+    <echo message="regexp.jar.present=${regexp.jar.present}" />
+    <echo message="servlet-api.jar.present=${servlet-api.jar.present}" />
+    <echo message="xerces2.jars.present(except JDK 1.4+)=${xerces2.jars.present}" />
+
+    <echo message="--- Optional JARs ---" />
+    <echo message="dbcp.jar.present=${dbcp.jar.present}" />
+    <echo message="fileupload.jar.present=${fileupload.jar.present}" />
+    <echo message="jaas.jar.present=${jaas.jar.present}" />
+    <echo message="javamail.jar.present=${javamail.jar.present}" />
+    <echo message="jmx.jar.present=${jmx.jar.present}" />
+    <echo message="jta.jar.present=${jta.jar.present}" />
+    <echo message="junit.jar.present=${junit.jar.present}" />
+    <echo message="modeler.jar.present=${modeler.jar.present}" />
+    <echo message="pool.jar.present=${pool.jar.present}" />
+
+    <echo message="--- Conditional compilation flags ---" />
+    <echo message="compile.dbcp=${compile.dbcp}" />
+    <echo message="compile.jaas=${compile.jaas}" />
+    <echo message="compile.javamail=${compile.javamail}" />
+    <echo message="compile.jmx=${compile.jmx}" />
+    <echo message="compile.jndi=${compile.jndi}" />
+    <echo message="compile.jsse=${compile.jsse}" />
+    <echo message="compile.jta=${compile.jta}" />
+    <echo message="compile.junit=${compile.junit}" />
+    <echo message="compile.ldap=${compile.ldap}" />
+    <echo message="compile.ssi=${compile.ssi}" />
+
+    <echo message="--- Distribution flags ---" />
+    <echo message="copy.dbcp.jar=${copy.dbcp.jar}" />
+    <echo message="copy.jmx.jar=${copy.jmx.jar}" />
+    <echo message="copy.launcher.jars=${copy.launcher.jars}" />
+    <echo message="copy.logging.jar=${copy.logging.jar}" />
+    <echo message="copy.modeler.jar=${copy.modeler.jar}" />
+    <echo message="copy.pool.jar=${copy.pool.jar}" />
+
+  </target>
+
+  <!-- =================== BUILD: Create Directories ====================== -->
+  <target name="build-prepare">
+
+    <mkdir dir="${catalina.build}"/>
+    <mkdir dir="${catalina.build}/bin"/>
+    <mkdir dir="${catalina.build}/common/classes"/>
+    <mkdir dir="${catalina.build}/common/lib"/>
+    <mkdir dir="${catalina.build}/common/endorsed"/>
+    <mkdir dir="${catalina.build}/conf"/>
+    <mkdir dir="${catalina.build}/logs"/>
+    <mkdir dir="${classes.dir}"/>
+    <mkdir dir="${catalina.build}/server/lib"/>
+    <mkdir dir="${catalina.build}/shared/classes"/>
+    <mkdir dir="${catalina.build}/shared/lib"/>
+    <mkdir dir="${catalina.build}/work"/>
+    <mkdir dir="${catalina.build}/temp"/>
+
+  </target>
+
+
+  <!-- ======================== BUILD: Copy JARs ========================== -->
+  <target name="copy-dbcp.jar" if="copy.dbcp.jar">
+    <copy todir="${catalina.build}/common/lib" file="${commons-dbcp.jar}"/>
+  </target>
+  <target name="copy-fileupload.jar" if="fileupload.jar.present">
+  </target>
+  <target name="copy-jmx.jar" if="copy.jmx.jar">
+    <copy tofile="${catalina.build}/bin/jmx.jar" file="${jmx.jar}"/>
+  </target>
+  <target name="copy-launcher.jars" if="copy.launcher.jars">
+    <!-- <copy todir="${catalina.build}/common/lib" file="${ant.jar}"/> -->
+    <copy todir="${catalina.build}/bin" file="${commons-launcher.jar}"/>
+    <copy todir="${catalina.build}/bin" file="${commons-launcher.bootstrap.class}"/>
+    <copy todir="${catalina.build}/bin">
+      <fileset dir="src/bin" includes="*-using-launcher.*,launcher.properties,catalina.xml" />
+    </copy>
+  </target>
+  <target name="copy-modeler.jar" if="copy.modeler.jar">
+    <copy todir="${catalina.build}/server/lib" file="${commons-modeler.jar}"/>
+  </target>
+  <target name="copy-pool.jar" if="copy.pool.jar">
+    <copy todir="${catalina.build}/common/lib" file="${commons-pool.jar}"/>
+  </target>
+  <target name="copy-tomcat-util.jar">
+  	<!--
+    <copy todir="${catalina.build}/server/lib" file="${tomcat-util.jar}"/>
+    -->
+	<jar jarfile="${tomcat-util.jar}"
+             index="true">
+      <fileset dir="${catalina.build}/classes">
+        <include name="org/apache/tomcat/util/**"/>
+        <!-- Javadoc and i18n exclusions -->
+        <exclude name="**/package.html" />
+        <exclude name="**/LocalStrings_*" />
+     </fileset>
+    </jar>
+  </target>
+  <target name="copy-xerces2.jars">
+    <copy todir="${catalina.build}/common/endorsed" file="${xercesImpl.jar}"/>
+    <copy todir="${catalina.build}/common/endorsed" file="${xml-apis.jar}"/>
+  </target>
+
+
+  <!-- =================== BUILD: Copy Static Files ======================= -->
+  <target name="build-static" depends="flags,flags.display,build-prepare,copy-fileupload.jar,copy-launcher.jars,copy-modeler.jar">
+
+    <!-- Executable Commands -->
+    <copy todir="${catalina.build}/bin">
+      <fileset dir="src/bin" excludes="*-using-launcher.*,launcher.properties,catalina.xml,*-tasks.xml" />
+    </copy>
+    <fixcrlf srcdir="${catalina.build}/bin" includes="*.sh" eol="lf"/>
+    <fixcrlf srcdir="${catalina.build}/bin" includes="*.bat" eol="crlf"/>
+    <chmod perm="+x" dir="${catalina.build}/bin" includes="*.sh"/>
+
+    <!-- Common Extensions -->
+    <copy todir="${catalina.build}/bin"
+           file="${commons-logging-api.jar}"/>
+<!--
+    <copy todir="${catalina.build}/common/lib" file="${servlet-api.jar}"/>
+-->
+    <copy todir="${catalina.build}/common/lib"
+           file="${tomcat-dbcp.jar}" />
+
+    <!-- Configuration Files -->
+    <copy todir="${catalina.build}/conf">
+      <fileset dir="src/conf">
+        <exclude name="catalina.conf.xml" />
+      </fileset>
+    </copy>
+
+    <!-- JVM Temporary Directory README -->
+    <copy todir="${catalina.build}/temp"
+          file="src/temp/README.txt"/>
+
+    <!-- Catalina Server Libraries -->
+  	<!--
+    <copy todir="${catalina.build}/server/lib" file="${regexp.jar}"/>
+    -->
+
+  </target>
+
+
+  <!-- =================== BUILD: Build tomcat-util ======================= -->
+  <target name="build-tomcat-util">
+
+    <ant dir="${tomcat-util.home}" target="build-main">
+       <property name="jmx.jar" value="${jmx.jar}" />
+       <property name="puretls.jar" value="${puretls.jar}" />
+       <property name="jsse.lib" value="${jsse.lib}" />
+    </ant>
+
+    <copy todir="${catalina.build}/server/lib"
+           file="${tomcat-util.jar}"/>
+
+  </target>
+
+
+  <!-- ================ BUILD: Compile Catalina Components ================ -->
+  <target name="build-catalina" depends="build-catalina-core,build-catalina-optional"/>
+
+  <target name="build-catalina-core">
+    <!-- Compile internal server components -->
+    <javac srcdir="src/share" destdir="${classes.dir}"
+           debug="${compile.debug}"
+           deprecation="${compile.deprecation}"
+           source="${compile.source}"
+           optimize="${compile.optimize}"
+           excludes="**/CVS/**">
+      <classpath refid="catalina.classpath" />
+
+      <exclude name="org/apache/catalina/util/ProcessHelper.java" 
+               unless="jdk.1.3.present"/>
+      <exclude name="org/apache/catalina/valves/CertificatesValve.java"
+               unless="compile.jsse"/>
+
+      <exclude name="org/apache/catalina/servlets/CGIServlet.java" />
+      <exclude name="org/apache/catalina/servlets/HTMLManagerServlet.java" />
+      <exclude name="org/apache/naming/factory/DbcpDataSourceFactory.java" />
+      <exclude name="org/apache/catalina/ssi/**"/>
+      <exclude name="org/apache/catalina/cluster/**"/>
+      <exclude name="org/apache/naming/factory/MailSessionFactory.java"/>
+      <exclude name="org/apache/naming/factory/SendMailFactory.java"/>
+      <exclude name="org/apache/catalina/launcher/**"/>
+      <exclude name="org/apache/catalina/valves/SemaphoreValve.java"/>
+    </javac>
+    <tstamp>
+        <format property="TODAY" pattern="MMM d yyyy" locale="en"/>
+        <format property="TSTAMP" pattern="hh:mm:ss"/>        
+    </tstamp>    
+    <!-- Copy static resource files -->
+    <filter token="VERSION" value="${version}"/>
+    <filter token="VERSION_NUMBER" value="${version.number}"/>
+    <filter token="VERSION_BUILT" value="${TODAY} ${TSTAMP}"/>
+    <copy todir="${classes.dir}" filtering="true" encoding="ISO-8859-1">
+      <fileset dir="src/share">
+        <exclude name="**/*.java"/>
+        <exclude name="**/*.ser"/>
+      </fileset>
+    </copy>
+    <copy todir="${classes.dir}">
+      <fileset dir="src/share">
+        <include name="**/*.ser"/>
+      </fileset>
+    </copy>
+
+  </target>
+
+	
+
+	
+  <target name="build-catalina-optional" unless="build.tomcat.base">
+    <!-- Compile internal server components -->
+    <javac srcdir="src/share" destdir="${classes.dir}"
+           debug="${compile.debug}"
+           deprecation="${compile.deprecation}"
+           optimize="${compile.optimize}"
+           source="${compile.source}"
+           excludes="**/CVS/**">
+      <classpath refid="catalina.classpath" />
+      <exclude name="org/apache/naming/factory/MailSessionFactory.java"
+       unless="compile.javamail"/>
+      <exclude name="org/apache/naming/factory/SendMailFactory.java"
+       unless="compile.javamail"/>
+      <exclude name="org/apache/catalina/valves/CertificatesValve.java"
+       unless="compile.jsse"/>
+      <exclude name="org/apache/catalina/valves/SemaphoreValve.java" 
+       unless="jdk.1.5.present"/>
+    </javac>
+
+    <!-- Copy static resource files -->
+    <filter token="VERSION" value="${version}"/>
+    <copy todir="${classes.dir}" filtering="true">
+      <fileset dir="src/share">
+        <exclude name="**/*.java"/>
+      </fileset>
+    </copy>
+  </target>
+
+  <!-- ================== BUILD: Build tomcat-coyote ====================== -->
+  <target name="build-tomcat-coyote">
+
+    <ant dir="${tomcat-coyote.home}" target="compile">
+      <property name="catalina.home" value="${catalina.deploy}"/>
+      <property name="servlet.jar"   value="${servlet-api.jar}"/>
+      <property name="commons-logging.jar" value="${commons-logging.jar}"/>
+      <property name="commons-modeler.jar" value="${commons-modeler.jar}"/>
+      <property name="jmx.jar" value="${jmx.jar}"/>
+    </ant>
+
+  	<!--
+    <copy todir="${catalina.deploy}/server/lib"
+           file="${tomcat-coyote.jar}"/>
+    -->
+
+  </target>
+
+
+  <!-- ==================== BUILD: Build tomcat-jk ======================== -->
+  <target name="build-tomcat-jk">
+
+    <ant dir="${tomcat-jk.home}" target="build-main">
+      <property name="tomcat5.home" value="${catalina.deploy}"/>
+      <property name="commons-logging.jar" value="${commons-logging.jar}"/>
+      <property name="commons-modeler.jar" value="${commons-modeler.jar}"/>
+      <property name="jmx.jar" value="${jmx.jar}"/>
+    </ant>
+
+  	<!--
+    <copy tofile="${catalina.deploy}/server/lib/tomcat-ajp.jar"
+            file="${tomcat-jk2.jar}"/>
+    -->
+  	<!--
+    <copy todir="${catalina.deploy}/conf"
+           file="${jk2.properties}"/>
+    -->
+
+  </target>
+
+
+  <!-- ============== BUILD: Build tomcat-coyote-http11 =================== -->
+  <target name="build-tomcat-http11">
+
+    <ant dir="${tomcat-http11.home}" target="compile">
+      <property name="commons-logging.jar" value="${commons-logging.jar}"/>
+      <property name="commons-modeler.jar" value="${commons-modeler.jar}"/>
+      <property name="jmx.jar" value="${jmx.jar}"/>
+    </ant>
+  	<!--
+    <copy todir="${catalina.deploy}/server/lib"
+           file="${tomcat-http11.jar}"/>
+    -->
+
+  </target>
+
+
+  <!-- ================= BUILD: Compile All Server Components ============= -->
+  <target name="build-main" depends="build-static,build-tomcat-util,build-catalina">
+  </target>
+
+
+  <!-- ================ BUILD: Create Catalina Javadocs =================== -->
+  <target name="javadoc" unless="docs.uptodate" >
+    <delete dir="${catalina.build}/javadoc"/>
+    <mkdir dir="${catalina.build}/javadoc"/>
+
+    <!-- To fix Bugzilla 35880, we need to ensure files that use J2SE 5.0
+         syntax are not JavaDoc'ed.  Even though no other target uses
+         javadoc.sourcepath and I could rewrite the javadoc target below,
+         that might impact users who use javadoc.sourcepath in their own
+         build scripts.  Accordingly, let's try this ugly temporary
+         fix.  When we start building Tomcat with J2SE 5.0, we can remove
+         this ugliness.
+    -->
+    <move file="${jtc.home}/util/java/org/apache/tomcat/util/net/jsse/JSSE15SocketFactory.java"
+          tofile="${jtc.home}/util/java/org/apache/tomcat/util/net/jsse/JSSE15SocketFactory.temp" />
+
+    <javadoc packagenames="org.apache.*"
+      classpathref="catalina.classpath"
+      sourcepathref="javadoc.sourcepath"
+      destdir="${catalina.build}/javadoc"
+      author="true"
+      version="true"
+      windowtitle="Tomcat API Documentation"
+      doctitle="Tomcat API"
+      bottom="Copyright &#169; 2000-2005 Apache Software Foundation.  All Rights Reserved."
+      additionalparam="-breakiterator">
+    	<excludepackage name="org.apache.ajp.*" />
+    	<excludepackage name="org.apache.coyote.tomcat3" />
+    	<excludepackage name="org.apache.coyote.tomcat4" />
+    	<excludepackage name="org.apache.jk.apr" />
+
+    </javadoc>
+
+    <move file="${jtc.home}/util/java/org/apache/tomcat/util/net/jsse/JSSE15SocketFactory.temp"
+          tofile="${jtc.home}/util/java/org/apache/tomcat/util/net/jsse/JSSE15SocketFactory.java" />
+  </target>
+
+
+  <!-- ======================= BUILD: Clean Directory ===================== -->
+  <target name="build-clean">
+
+    <delete dir="${catalina.build}"/>
+
+    <ant dir="${tomcat-util.home}" target="clean"/>
+    <ant dir="${tomcat-coyote.home}" target="clean"/>
+    <ant dir="${tomcat-jk.home}" target="clean"/>
+    <ant dir="${tomcat-http11.home}" target="clean"/>
+
+  </target>
+
+
+  <!-- ==================== BUILD: Rebuild Everything ===================== -->
+  <target name="all" depends="build-clean,build-main"
+   description="Clean, build, and deploy Catalina component"/>
+
+
+  <!-- ================ TEST: Compile Unit Tests ========================== -->
+  <target name="build-tests" depends="build-main" if="junit.present">
+    <mkdir      dir="${catalina.build}/tests"/>
+    <!-- Compile unit test classes -->
+    <javac srcdir="src/test" destdir="${catalina.build}/tests"
+           deprecation="${compile.deprecation}"
+           debug="${compile.debug}"
+           optimize="off"
+           source="${compile.source}"
+           excludes="**/CVS/**">
+      <classpath refid="test.classpath"/>
+    </javac>
+  </target>
+
+
+  <!-- ==================== TEST: Execute Unit Tests ====================== -->
+  <target name="test" if="junit.present"
+   description="Run all unit test cases"
+   depends="build-tests,test-dir-context,test-util">
+  </target>
+
+  <target name="test-dir-context" if="junit.present">
+
+    <echo message="Running FileDirContext tests"/>
+    <java classname="${test.runner}" fork="yes"
+        failonerror="${test.failonerror}">
+      <sysproperty key="doc.base" value="${test.webapp}"/>
+      <arg value="org.apache.naming.resources.FileDirContextTestCase"/>
+      <classpath refid="test.classpath"/>
+    </java>
+
+    <echo message="Running WARDirContext tests"/>
+    <jar jarfile="${test.webapp.war}">
+      <fileset dir="${test.webapp}"/>
+    </jar>
+    <java classname="${test.runner}" fork="yes"
+        failonerror="${test.failonerror}">
+      <sysproperty key="doc.base" value="${test.webapp.war}"/>
+      <arg value="org.apache.naming.resources.WARDirContextTestCase"/>
+      <classpath refid="test.classpath"/>
+    </java>
+    <delete file="${test.webapp.war}"/>
+
+  </target>
+
+  <target name="test-util" if="junit.present">
+
+    <echo message="Running CookieTools tests"/>
+    <java classname="${test.runner}" fork="yes"
+        failonerror="${test.failonerror}">
+      <arg value="org.apache.catalina.util.CookieToolsTestCase"/>
+      <classpath refid="test.classpath"/>
+    </java>
+
+    <echo message="Running URL tests"/>
+    <java classname="${test.runner}" fork="yes"
+        failonerror="${test.failonerror}">
+      <arg value="org.apache.catalina.util.URLTestCase"/>
+      <classpath refid="test.classpath"/>
+    </java>
+
+  </target>
+
+
+  <!-- ====================== DEPLOY: Create Directories ================== -->
+  <target name="deploy-prepare">
+    <mkdir dir="${catalina.deploy}"/>
+    <mkdir dir="${catalina.deploy}/bin"/>
+    <mkdir dir="${catalina.deploy}/conf"/>
+    <mkdir dir="${catalina.deploy}/logs"/>
+    <mkdir dir="${catalina.deploy}/common/classes"/>
+    <mkdir dir="${catalina.deploy}/common/endorsed"/>
+    <mkdir dir="${catalina.deploy}/common/i18n"/>
+    <mkdir dir="${catalina.deploy}/common/lib"/>
+    <mkdir dir="${catalina.deploy}/server/classes"/>
+    <mkdir dir="${catalina.deploy}/server/lib"/>
+    <mkdir dir="${catalina.deploy}/work"/>
+    <mkdir dir="${catalina.deploy}/temp"/>
+  </target>
+
+
+  <!-- ====================== DEPLOY: Copy Static Files =================== -->
+  <target name="deploy-static" depends="build-main,deploy-prepare,deploy-static-only,deploy-libs"/>
+
+  <target name="deploy-static-only" depends="deploy-prepare">
+
+    <!-- Executable Commands -->
+    <copy todir="${catalina.deploy}/bin">
+      <fileset dir="src/bin" excludes="*-using-launcher.*,launcher.properties,catalina.xml" />
+    </copy>
+    <fixcrlf srcdir="${catalina.deploy}/bin" includes="*.sh"  eol="lf"/>
+    <fixcrlf srcdir="${catalina.deploy}/bin" includes="*.bat" eol="crlf"/>
+    <chmod perm="+x" dir="${catalina.build}/bin" includes="*.sh"/>
+
+    <!-- Configuration Files -->
+    <copy todir="${catalina.deploy}/conf">
+      <fileset dir="${catalina.build}/conf" />
+    </copy>
+
+  </target>
+
+  <target name="deploy-libs">
+
+    <!-- Common Extensions -->
+    <copy todir="${catalina.deploy}/common/endorsed">
+      <fileset dir="${catalina.build}/common/endorsed" />
+    </copy>
+
+    <copy todir="${catalina.deploy}/common/lib">
+      <fileset dir="${catalina.build}/common/lib" />
+    </copy>
+
+    <!-- Server Components -->
+    <copy todir="${catalina.deploy}/server/lib">
+      <fileset dir="${catalina.build}/server/lib" />
+    </copy>
+
+    <!-- Shared Extensions -->
+<!--
+    <copy todir="${catalina.deploy}/shared/lib">
+      <fileset dir="${catalina.build}/shared/lib" />
+    </copy>
+-->
+  </target>
+
+
+  <!-- ====================== DEPLOY: Create Catalina JARs ================ -->
+  <target name="catalina-jars" depends="build-static,deploy-prepare,flags,flags.display,build-catalina"
+          description="Build catalina jars">
+
+    <!-- Catalina Bootstrap JAR File. It is a very wrong idea to split packages in multiple jars !!! -->
+    <jar jarfile="${catalina.deploy}/bin/bootstrap.jar" 
+         manifest="etc/bootstrap.MF">
+      <fileset dir="${classes.dir}">
+        <include name="org/apache/catalina/startup/Bootstrap.class" />
+        <include name="org/apache/catalina/startup/catalina.properties" />
+        <include name="org/apache/catalina/startup/CatalinaProperties.class" />
+        <include name="org/apache/catalina/startup/ClassLoaderFactory.class" />
+        <include name="org/apache/catalina/startup/Tool.class" />
+        <include name="org/apache/catalina/loader/StandardClassLoader*.class" />
+        <include name="org/apache/catalina/loader/Extension.class" />
+        <include name="org/apache/catalina/loader/Reloader.class" />
+        <include name="org/apache/catalina/security/SecurityClassLoad.class" />
+        <include name="org/apache/catalina/launcher/CatalinaLaunchFilter.class" />
+        <include name="org/apache/naming/JndiPermission.class" />
+        <include name="org/apache/tomcat/util/compat/*" />
+
+      	<!-- Javadoc and i18n exclusions -->
+        <exclude name="**/package.html" />
+        <exclude name="**/LocalStrings_*" />
+      </fileset>
+    </jar>
+
+    <!-- Catalina Main JAR File -->
+    <!-- Excluding files from here is worse than duplicating them - a loader that uses the
+         package name as index and includes both bootstrap and catalina will be confused -->
+
+    <jar jarfile="${catalina.deploy}/server/lib/catalina.jar">
+      <fileset dir="${classes.dir}">
+
+        <include name="org/apache/catalina/**" />
+
+        <!-- Javadoc and i18n exclusions -->
+        <exclude name="**/package.html" />
+        <exclude name="**/LocalStrings_*" />
+
+        <!-- Modules -->
+        <exclude name="org/apache/catalina/ant/**" />
+        <exclude name="org/apache/catalina/cluster/**" />
+        <exclude name="org/apache/catalina/launcher/**" />
+        <exclude name="org/apache/catalina/servlets/**" />
+        <exclude name="org/apache/catalina/startup/Bootstrap.class" />
+        <exclude name="org/apache/catalina/storeconfig/**" />
+        <exclude name="org/apache/catalina/ssi/**" />
+        <exclude name="org/apache/naming/**" />
+
+        <!-- Catalina-optional classes -->
+        <exclude name="org/apache/catalina/realm/DataSourceRealm.class" />
+        <exclude name="org/apache/catalina/realm/JAAS*" />
+        <exclude name="org/apache/catalina/realm/JDBC*" />
+        <exclude name="org/apache/catalina/realm/JNDI*" />
+        <exclude name="org/apache/catalina/realm/Memory*" />
+        <exclude name="org/apache/catalina/session/StoreBase.class" />
+        <exclude name="org/apache/catalina/session/*Store.class" />
+        <exclude name="org/apache/catalina/session/PersistentManager*" />
+        <exclude name="org/apache/catalina/util/CGIProcessEnvironment.class" />
+        <exclude name="org/apache/catalina/util/CookieTools.class" />
+        <exclude name="org/apache/catalina/util/DateTool.class" />
+        <exclude name="org/apache/catalina/util/DOMWriter.class" />
+        <exclude name="org/apache/catalina/util/FastDateFormat.class" />
+        <exclude name="org/apache/catalina/util/IOTools.class" />
+        <exclude name="org/apache/catalina/util/MIME2Java.class" />
+        <exclude name="org/apache/catalina/util/Process*" />
+        <exclude name="org/apache/catalina/util/Queue.class" />
+        <exclude name="org/apache/catalina/util/Strftime.class" />
+        <exclude name="org/apache/catalina/util/XMLWriter.class" />
+        <exclude name="org/apache/catalina/valves/ExtendedAccessLogValve.class" />
+        <exclude name="org/apache/catalina/valves/FastCommonAccessLogValve.class" />
+        <exclude name="org/apache/catalina/valves/FieldInfo.class" />
+        <exclude name="org/apache/catalina/valves/JDBCAccessLogValve.class" />
+        <exclude name="org/apache/catalina/valves/PersistentValve.class" />
+        <exclude name="org/apache/catalina/valves/Remote*" />
+        <exclude name="org/apache/catalina/valves/RequestDumperValve.class" />
+        <exclude name="org/apache/catalina/valves/RequestFilterValve.class" />
+        <exclude name="org/apache/catalina/valves/SemaphoreValve.class" />
+
+      </fileset>
+    </jar>
+
+    <jar jarfile="${catalina.deploy}/server/lib/catalina-optional.jar">
+      <fileset dir="${classes.dir}">
+
+        <include name="org/apache/catalina/realm/DataSourceRealm.class" />
+        <include name="org/apache/catalina/realm/JAAS*" />
+        <include name="org/apache/catalina/realm/JDBC*" />
+        <include name="org/apache/catalina/realm/JNDI*" />
+        <include name="org/apache/catalina/realm/Memory*" />
+        <include name="org/apache/catalina/session/StoreBase.class" />
+        <include name="org/apache/catalina/session/*Store.class" />
+        <include name="org/apache/catalina/session/PersistentManager*" />
+        <include name="org/apache/catalina/util/CGIProcessEnvironment.class" />
+        <include name="org/apache/catalina/util/CookieTools.class" />
+        <include name="org/apache/catalina/util/DateTool.class" />
+        <include name="org/apache/catalina/util/DOMWriter.class" />
+        <include name="org/apache/catalina/util/FastDateFormat.class" />
+        <include name="org/apache/catalina/util/IOTools.class" />
+        <include name="org/apache/catalina/util/MIME2Java.class" />
+        <include name="org/apache/catalina/util/Process*" />
+        <include name="org/apache/catalina/util/Queue.class" />
+        <include name="org/apache/catalina/util/Strftime.class" />
+        <include name="org/apache/catalina/util/XMLWriter.class" />
+        <include name="org/apache/catalina/valves/ExtendedAccessLogValve.class" />
+        <include name="org/apache/catalina/valves/FastCommonAccessLogValve.class" />
+        <include name="org/apache/catalina/valves/FieldInfo.class" />
+        <include name="org/apache/catalina/valves/JDBCAccessLogValve.class" />
+        <include name="org/apache/catalina/valves/PersistentValve.class" />
+        <include name="org/apache/catalina/valves/Remote*" />
+        <include name="org/apache/catalina/valves/RequestDumperValve.class" />
+        <include name="org/apache/catalina/valves/RequestFilterValve.class" />
+        <include name="org/apache/catalina/valves/SemaphoreValve.class" />
+
+        <!-- Javadoc and i18n exclusions -->
+        <exclude name="**/package.html" />
+        <exclude name="**/LocalStrings_*" />
+
+      </fileset>
+    </jar>
+
+    <!-- Catalina Ant Tasks JAR File -->
+    <jar jarfile="${catalina.deploy}/server/lib/catalina-ant.jar">
+      <fileset dir="${classes.dir}">
+        
+      	<include name="org/apache/catalina/ant/*" />
+        <include name="org/apache/catalina/util/Base64.class" />
+
+      	<!-- Javadoc and i18n exclusions -->
+        <exclude name="**/package.html" />
+        <exclude name="**/LocalStrings_*" />
+      	
+      </fileset>
+    </jar>
+
+  	<!-- Catalina JMX Accessor Ant Tasks JAR File -->
+    <jar jarfile="${catalina.deploy}/server/lib/catalina-ant-jmx.jar">
+      <fileset dir="${classes.dir}">
+        
+      	<include name="org/apache/catalina/ant/jmx/*" />
+
+      	<!-- Javadoc and i18n exclusions -->
+        <exclude name="**/package.html" />
+        <exclude name="**/LocalStrings_*" />
+      	
+      </fileset>
+    </jar>
+
+  	<!-- Naming - Factory JAR File -->
+    <jar jarfile="${catalina.deploy}/common/lib/naming-factory.jar" index="true">
+      <fileset dir="${classes.dir}">
+        <include name="org/apache/naming/**" />
+        <exclude name="org/apache/naming/resources/**" />
+        <exclude name="org/apache/naming/JndiPermission.class" />
+      	<exclude name="org/apache/naming/NameParserImpl.class" />
+      	<exclude name="org/apache/naming/NamingContextBindingsEnumeration.class" />
+      	<exclude name="org/apache/naming/NamingContextEnumeration.class" />
+      	<exclude name="org/apache/naming/NamingEntry.class" />
+      	<exclude name="org/apache/naming/StringManager.class" />
+        <!-- Javadoc and i18n exclusions -->
+        <exclude name="**/package.html" />
+        <exclude name="**/LocalStrings_*" />
+      </fileset>
+    </jar>
+
+    <!-- Naming - Resources JAR File -->
+    <jar jarfile="${catalina.deploy}/common/lib/naming-resources.jar" index="true">
+      <fileset dir="${classes.dir}">
+        <include name="org/apache/naming/JndiPermission.class" />
+      	<include name="org/apache/naming/NameParserImpl.class" />
+      	<include name="org/apache/naming/NamingContextBindingsEnumeration.class" />
+      	<include name="org/apache/naming/NamingContextEnumeration.class" />
+      	<include name="org/apache/naming/NamingEntry.class" />
+      	<include name="org/apache/naming/StringManager.class" />
+        <include name="org/apache/naming/resources/**" />
+        <!-- Javadoc and i18n exclusions -->
+        <exclude name="**/package.html" />
+        <exclude name="**/LocalStrings_*" />
+      </fileset>
+    </jar>
+
+    <!-- Servlets - CGI Servlet -->
+    <jar jarfile="${catalina.deploy}/server/lib/servlets-cgi.renametojar" index="true">
+      <fileset dir="${classes.dir}">
+        <include name="org/apache/catalina/servlets/CGI*" />
+      </fileset>
+    </jar>
+
+    <!-- Servlets - Default File-Serving Servlet -->
+    <jar jarfile="${catalina.deploy}/server/lib/servlets-default.jar" index="true">
+      <fileset dir="${classes.dir}">
+        <include name="org/apache/catalina/servlets/Default*" />
+        <include name="org/apache/catalina/servlets/Constants.class" />
+        <include name="org/apache/catalina/servlets/LocalStrings.properties" />
+      </fileset>
+    </jar>
+
+    <!-- Servlets - Invoker Servlet -->
+    <jar jarfile="${catalina.deploy}/server/lib/servlets-invoker.jar" index="true">
+      <fileset dir="${classes.dir}">
+        <include name="org/apache/catalina/servlets/Invoker*" />
+      </fileset>
+    </jar>
+
+    <!-- Servlets - SSI Servlet -->
+    <jar jarfile="${catalina.deploy}/server/lib/servlets-ssi.renametojar" index="true">
+      <fileset dir="${classes.dir}">
+        <include name="org/apache/catalina/ssi/**" />
+        <!-- Javadoc and i18n exclusions -->
+        <exclude name="**/package.html" />
+        <exclude name="**/LocalStrings_*" />
+      </fileset>
+    </jar>
+
+    <!-- Servlets - Webdav Servlet -->
+    <jar jarfile="${catalina.deploy}/server/lib/servlets-webdav.jar" index="true">
+      <fileset dir="${classes.dir}">
+        <include name="org/apache/catalina/servlets/Webdav*" />
+      </fileset>
+    </jar>
+
+  </target>
+
+  <target name="deploy-catalina" depends="deploy-static,build-main,catalina-jars"
+   description="Build and deploy Catalina component">
+  </target>
+
+
+  <!-- ====================== DEPLOY: Create Catalina JARs ================ -->
+  <target name="deploy" depends="deploy-catalina,build-tomcat-coyote,build-tomcat-jk,build-tomcat-http11"
+   description="Build and deploy Catalina">
+  </target>
+
+
+  <!-- ================ DIST: Create Distribution ========================= -->
+  <target name="dist" depends="build-main"
+   description="Create binary distribution">
+
+    <!-- Executable Commands -->
+    <mkdir dir="${catalina.dist}/bin"/>
+    <copy todir="${catalina.dist}/bin">
+      <fileset dir="src/bin" excludes="*-using-launcher.*,launcher.properties,catalina.xml" />
+    </copy>
+    <fixcrlf srcdir="${catalina.dist}/bin" includes="*.sh" eol="lf"/>
+    <fixcrlf srcdir="${catalina.dist}/bin" includes="*.bat" eol="crlf"/>
+    <chmod perm="+x" dir="${catalina.build}/bin" includes="*.sh"/>
+
+    <!-- Common Extensions -->    
+    <mkdir dir="${catalina.dist}/common/classes"/>
+    <copy todir="${catalina.dist}/common/classes">
+      <fileset dir="${catalina.build}/common/classes" />
+    </copy>
+    <mkdir dir="${catalina.dist}/common/lib"/>
+    <copy todir="${catalina.dist}/common/lib">
+      <fileset dir="${catalina.build}/common/lib" />
+    </copy>
+
+    <!-- Configuration Files -->
+    <mkdir dir="${catalina.dist}/conf"/>
+    <copy todir="${catalina.dist}/conf">
+      <fileset dir="${catalina.build}/conf" />
+    </copy>
+
+    <!-- Server Components -->
+    <mkdir dir="${catalina.dist}/server/classes"/>
+    <!-- Do we want to copy the classes ? 
+    <copy todir="${catalina.dist}/server/classes">
+      <fileset dir="${classes.dir}" />
+    </copy>
+    -->
+    <mkdir dir="${catalina.dist}/server/lib"/>
+    <copy todir="${catalina.dist}/server/lib">
+      <fileset dir="${catalina.build}/server/lib" />
+    </copy>
+
+    <!-- Shared Extensions -->
+    <mkdir dir="${catalina.dist}/shared/classes"/>
+    <copy todir="${catalina.dist}/shared/classes">
+      <fileset dir="${catalina.build}/shared/classes" />
+    </copy>
+    <mkdir dir="${catalina.dist}/shared/lib"/>
+    <copy todir="${catalina.dist}/shared/lib">
+      <fileset dir="${catalina.build}/shared/lib" />
+    </copy>
+
+  </target>
+
+
+  <!-- ======================== DIST: Clean Directory ===================== -->
+  <target name="dist-clean">
+    <delete dir="${catalina.dist}"/>
+  </target>
+
+
+  <!-- ====================== Convenient Synonyms ========================= -->
+  <target name="clean" depends="build-clean, dist-clean"
+   description="Clean build and dist directories"/>
+
+
+</project>

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/etc/bootstrap.MF
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/etc/bootstrap.MF	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/etc/bootstrap.MF	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,5 @@
+Manifest-Version: 1.0
+Main-Class: org.apache.catalina.startup.Bootstrap
+Class-Path: jmx.jar commons-daemon.jar commons-logging-api.jar tomcat-juli.jar
+Specification-Title: Catalina
+Specification-Version: 1.0

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/bin/catalina-tasks.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/bin/catalina-tasks.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/bin/catalina-tasks.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,20 @@
+<!--
+  XML file for importing Catalina ant tasks.
+  <import file="${catalina.home}/bin/catalina-tasks.xml"/>
+-->
+
+<project name="catalina-tasks">
+  <description>Catalina Ant Manager and JSPC Tasks</description>
+  <!-- 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">
+    <classpath>
+      <fileset file="${catalina.home}/bin/commons-logging-api.jar"/>
+      <fileset file="${catalina.home}/common/lib/jasper-compiler.jar"/>
+      <fileset file="${catalina.home}/common/lib/jasper-runtime.jar"/>
+      <fileset file="${catalina.home}/common/lib/servlet-api.jar"/>
+      <fileset file="${catalina.home}/server/lib/catalina-ant.jar"/>
+    </classpath>
+  </taskdef>
+</project>

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/bin/catalina.bat
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/bin/catalina.bat	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/bin/catalina.bat	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,206 @@
+ at echo off
+if "%OS%" == "Windows_NT" setlocal
+rem ---------------------------------------------------------------------------
+rem Start/Stop Script for the CATALINA Server
+rem
+rem Environment Variable Prequisites
+rem
+rem   CATALINA_HOME   May point at your Catalina "build" directory.
+rem
+rem   CATALINA_BASE   (Optional) Base directory for resolving dynamic portions
+rem                   of a Catalina installation.  If not present, resolves to
+rem                   the same directory that CATALINA_HOME points to.
+rem
+rem   CATALINA_OPTS   (Optional) Java runtime options used when the "start",
+rem                   "stop", or "run" command is executed.
+rem
+rem   CATALINA_TMPDIR (Optional) Directory path location of temporary directory
+rem                   the JVM should use (java.io.tmpdir).  Defaults to
+rem                   %CATALINA_BASE%\temp.
+rem
+rem   JAVA_HOME       Must point at your Java Development Kit installation.
+rem                   Required to run the with the "debug" argument.
+rem
+rem   JRE_HOME        Must point at your Java Development Kit installation.
+rem                   Defaults to JAVA_HOME if empty.
+rem
+rem   JAVA_OPTS       (Optional) Java runtime options used when the "start",
+rem                   "stop", or "run" command is executed.
+rem
+rem   JSSE_HOME       (Optional) May point at your Java Secure Sockets Extension
+rem                   (JSSE) installation, whose JAR files will be added to the
+rem                   system class path used to start Tomcat.
+rem
+rem   JPDA_TRANSPORT  (Optional) JPDA transport used when the "jpda start"
+rem                   command is executed. The default is "dt_shmem".
+rem
+rem   JPDA_ADDRESS    (Optional) Java runtime options used when the "jpda start"
+rem                   command is executed. The default is "jdbconn".
+rem
+rem $Id: catalina.bat 355227 2005-12-08 21:44:16Z keith $
+rem ---------------------------------------------------------------------------
+
+rem Guess CATALINA_HOME if not defined
+set CURRENT_DIR=%cd%
+if not "%CATALINA_HOME%" == "" goto gotHome
+set CATALINA_HOME=%CURRENT_DIR%
+if exist "%CATALINA_HOME%\bin\catalina.bat" goto okHome
+cd ..
+set CATALINA_HOME=%cd%
+cd %CURRENT_DIR%
+:gotHome
+if exist "%CATALINA_HOME%\bin\catalina.bat" goto okHome
+echo The CATALINA_HOME environment variable is not defined correctly
+echo This environment variable is needed to run this program
+goto end
+:okHome
+
+rem Get standard environment variables
+if exist "%CATALINA_HOME%\bin\setenv.bat" call "%CATALINA_HOME%\bin\setenv.bat"
+
+rem Get standard Java environment variables
+if exist "%CATALINA_HOME%\bin\setclasspath.bat" goto okSetclasspath
+echo Cannot find %CATALINA_HOME%\bin\setclasspath.bat
+echo This file is needed to run this program
+goto end
+:okSetclasspath
+set BASEDIR=%CATALINA_HOME%
+call "%CATALINA_HOME%\bin\setclasspath.bat" %1
+if errorlevel 1 goto end
+
+rem Add on extra jar files to CLASSPATH
+if "%JSSE_HOME%" == "" goto noJsse
+set CLASSPATH=%CLASSPATH%;%JSSE_HOME%\lib\jcert.jar;%JSSE_HOME%\lib\jnet.jar;%JSSE_HOME%\lib\jsse.jar
+:noJsse
+set CLASSPATH=%CLASSPATH%;%CATALINA_HOME%\bin\bootstrap.jar
+
+if not "%CATALINA_BASE%" == "" goto gotBase
+set CATALINA_BASE=%CATALINA_HOME%
+:gotBase
+
+if not "%CATALINA_TMPDIR%" == "" goto gotTmpdir
+set CATALINA_TMPDIR=%CATALINA_BASE%\temp
+:gotTmpdir
+
+if not exist "%CATALINA_HOME%\bin\tomcat-juli.jar" goto noJuli
+set JAVA_OPTS=%JAVA_OPTS% -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -Djava.util.logging.config.file="%CATALINA_BASE%\conf\logging.properties"
+:noJuli
+
+rem ----- Execute The Requested Command ---------------------------------------
+
+echo Using CATALINA_BASE:   %CATALINA_BASE%
+echo Using CATALINA_HOME:   %CATALINA_HOME%
+echo Using CATALINA_TMPDIR: %CATALINA_TMPDIR%
+if ""%1"" == ""debug"" goto use_jdk
+echo Using JRE_HOME:        %JRE_HOME%
+goto java_dir_displayed
+:use_jdk
+echo Using JAVA_HOME:       %JAVA_HOME%
+:java_dir_displayed
+
+set _EXECJAVA=%_RUNJAVA%
+set MAINCLASS=org.apache.catalina.startup.Bootstrap
+set ACTION=start
+set SECURITY_POLICY_FILE=
+set DEBUG_OPTS=
+set JPDA=
+
+if not ""%1"" == ""jpda"" goto noJpda
+set JPDA=jpda
+if not "%JPDA_TRANSPORT%" == "" goto gotJpdaTransport
+set JPDA_TRANSPORT=dt_shmem
+:gotJpdaTransport
+if not "%JPDA_ADDRESS%" == "" goto gotJpdaAddress
+set JPDA_ADDRESS=jdbconn
+:gotJpdaAddress
+shift
+:noJpda
+
+if ""%1"" == ""debug"" goto doDebug
+if ""%1"" == ""run"" goto doRun
+if ""%1"" == ""start"" goto doStart
+if ""%1"" == ""stop"" goto doStop
+if ""%1"" == ""version"" goto doVersion
+
+echo Usage:  catalina ( commands ... )
+echo commands:
+echo   debug             Start Catalina in a debugger
+echo   debug -security   Debug Catalina with a security manager
+echo   jpda start        Start Catalina under JPDA debugger
+echo   run               Start Catalina in the current window
+echo   run -security     Start in the current window with security manager
+echo   start             Start Catalina in a separate window
+echo   start -security   Start in a separate window with security manager
+echo   stop              Stop Catalina
+echo   version           What version of tomcat are you running?
+goto end
+
+:doDebug
+shift
+set _EXECJAVA=%_RUNJDB%
+set DEBUG_OPTS=-sourcepath "%CATALINA_HOME%\..\..\jakarta-tomcat-catalina\catalina\src\share"
+if not ""%1"" == ""-security"" goto execCmd
+shift
+echo Using Security Manager
+set SECURITY_POLICY_FILE=%CATALINA_BASE%\conf\catalina.policy
+goto execCmd
+
+:doRun
+shift
+if not ""%1"" == ""-security"" goto execCmd
+shift
+echo Using Security Manager
+set SECURITY_POLICY_FILE=%CATALINA_BASE%\conf\catalina.policy
+goto execCmd
+
+:doStart
+shift
+if not "%OS%" == "Windows_NT" goto noTitle
+set _EXECJAVA=start "Tomcat" %_RUNJAVA%
+goto gotTitle
+:noTitle
+set _EXECJAVA=start %_RUNJAVA%
+:gotTitle
+if not ""%1"" == ""-security"" goto execCmd
+shift
+echo Using Security Manager
+set SECURITY_POLICY_FILE=%CATALINA_BASE%\conf\catalina.policy
+goto execCmd
+
+:doStop
+shift
+set ACTION=stop
+goto execCmd
+
+:doVersion
+%_EXECJAVA% -classpath "%CATALINA_HOME%\server\lib\catalina.jar" org.apache.catalina.util.ServerInfo
+goto end
+
+
+:execCmd
+rem Get remaining unshifted command line arguments and save them in the
+set CMD_LINE_ARGS=
+:setArgs
+if ""%1""=="""" goto doneSetArgs
+set CMD_LINE_ARGS=%CMD_LINE_ARGS% %1
+shift
+goto setArgs
+:doneSetArgs
+
+rem Execute Java with the applicable properties
+if not "%JPDA%" == "" goto doJpda
+if not "%SECURITY_POLICY_FILE%" == "" goto doSecurity
+%_EXECJAVA% %JAVA_OPTS% %CATALINA_OPTS% %DEBUG_OPTS% -Djava.endorsed.dirs="%JAVA_ENDORSED_DIRS%" -classpath "%CLASSPATH%" -Dcatalina.base="%CATALINA_BASE%" -Dcatalina.home="%CATALINA_HOME%" -Djava.io.tmpdir="%CATALINA_TMPDIR%" %MAINCLASS% %CMD_LINE_ARGS% %ACTION%
+goto end
+:doSecurity
+%_EXECJAVA% %JAVA_OPTS% %CATALINA_OPTS% %DEBUG_OPTS% -Djava.endorsed.dirs="%JAVA_ENDORSED_DIRS%" -classpath "%CLASSPATH%" -Djava.security.manager -Djava.security.policy=="%SECURITY_POLICY_FILE%" -Dcatalina.base="%CATALINA_BASE%" -Dcatalina.home="%CATALINA_HOME%" -Djava.io.tmpdir="%CATALINA_TMPDIR%" %MAINCLASS% %CMD_LINE_ARGS% %ACTION%
+goto end
+:doJpda
+if not "%SECURITY_POLICY_FILE%" == "" goto doSecurityJpda
+%_EXECJAVA% %JAVA_OPTS% %CATALINA_OPTS% -Xdebug -Xrunjdwp:transport=%JPDA_TRANSPORT%,address=%JPDA_ADDRESS%,server=y,suspend=n %DEBUG_OPTS% -Djava.endorsed.dirs="%JAVA_ENDORSED_DIRS%" -classpath "%CLASSPATH%" -Dcatalina.base="%CATALINA_BASE%" -Dcatalina.home="%CATALINA_HOME%" -Djava.io.tmpdir="%CATALINA_TMPDIR%" %MAINCLASS% %CMD_LINE_ARGS% %ACTION%
+goto end
+:doSecurityJpda
+%_EXECJAVA% %JAVA_OPTS% %CATALINA_OPTS% -Xdebug -Xrunjdwp:transport=%JPDA_TRANSPORT%,address=%JPDA_ADDRESS%,server=y,suspend=n %DEBUG_OPTS% -Djava.endorsed.dirs="%JAVA_ENDORSED_DIRS%" -classpath "%CLASSPATH%" -Djava.security.manager -Djava.security.policy=="%SECURITY_POLICY_FILE%" -Dcatalina.base="%CATALINA_BASE%" -Dcatalina.home="%CATALINA_HOME%" -Djava.io.tmpdir="%CATALINA_TMPDIR%" %MAINCLASS% %CMD_LINE_ARGS% %ACTION%
+goto end
+
+:end

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/bin/catalina.sh
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/bin/catalina.sh	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/bin/catalina.sh	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,323 @@
+#!/bin/sh
+# -----------------------------------------------------------------------------
+# Start/Stop Script for the CATALINA Server
+#
+# Environment Variable Prequisites
+#
+#   CATALINA_HOME   May point at your Catalina "build" directory.
+#
+#   CATALINA_BASE   (Optional) Base directory for resolving dynamic portions
+#                   of a Catalina installation.  If not present, resolves to
+#                   the same directory that CATALINA_HOME points to.
+#
+#   CATALINA_OPTS   (Optional) Java runtime options used when the "start",
+#                   "stop", or "run" command is executed.
+#
+#   CATALINA_TMPDIR (Optional) Directory path location of temporary directory
+#                   the JVM should use (java.io.tmpdir).  Defaults to
+#                   $CATALINA_BASE/temp.
+#
+#   JAVA_HOME       Must point at your Java Development Kit installation.
+#                   Required to run the with the "debug" or "javac" argument.
+#
+#   JRE_HOME        Must point at your Java Development Kit installation.
+#                   Defaults to JAVA_HOME if empty.
+#
+#   JAVA_OPTS       (Optional) Java runtime options used when the "start",
+#                   "stop", or "run" command is executed.
+#
+#   JPDA_TRANSPORT  (Optional) JPDA transport used when the "jpda start"
+#                   command is executed. The default is "dt_socket".
+#
+#   JPDA_ADDRESS    (Optional) Java runtime options used when the "jpda start"
+#                   command is executed. The default is 8000.
+#
+#   JSSE_HOME       (Optional) May point at your Java Secure Sockets Extension
+#                   (JSSE) installation, whose JAR files will be added to the
+#                   system class path used to start Tomcat.
+#
+#   CATALINA_PID    (Optional) Path of the file which should contains the pid
+#                   of catalina startup java process, when start (fork) is used
+#
+# $Id: catalina.sh 394120 2006-04-14 15:25:07Z yoavs $
+# -----------------------------------------------------------------------------
+
+# OS specific support.  $var _must_ be set to either true or false.
+cygwin=false
+os400=false
+darwin=false
+case "`uname`" in
+CYGWIN*) cygwin=true;;
+OS400*) os400=true;;
+Darwin*) darwin=true;;
+esac
+
+# resolve links - $0 may be a softlink
+PRG="$0"
+
+while [ -h "$PRG" ]; do
+  ls=`ls -ld "$PRG"`
+  link=`expr "$ls" : '.*-> \(.*\)$'`
+  if expr "$link" : '/.*' > /dev/null; then
+    PRG="$link"
+  else
+    PRG=`dirname "$PRG"`/"$link"
+  fi
+done
+
+# Get standard environment variables
+PRGDIR=`dirname "$PRG"`
+
+# Only set CATALINA_HOME if not already set
+[ -z "$CATALINA_HOME" ] && CATALINA_HOME=`cd "$PRGDIR/.." ; pwd`
+
+if [ -r "$CATALINA_HOME"/bin/setenv.sh ]; then
+  . "$CATALINA_HOME"/bin/setenv.sh
+fi
+
+# For Cygwin, ensure paths are in UNIX format before anything is touched
+if $cygwin; then
+  [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
+  [ -n "$JRE_HOME" ] && JRE_HOME=`cygpath --unix "$JRE_HOME"`
+  [ -n "$CATALINA_HOME" ] && CATALINA_HOME=`cygpath --unix "$CATALINA_HOME"`
+  [ -n "$CATALINA_BASE" ] && CATALINA_BASE=`cygpath --unix "$CATALINA_BASE"`
+  [ -n "$CLASSPATH" ] && CLASSPATH=`cygpath --path --unix "$CLASSPATH"`
+  [ -n "$JSSE_HOME" ] && JSSE_HOME=`cygpath --absolute --unix "$JSSE_HOME"`
+fi
+
+# For OS400
+if $os400; then
+  # Set job priority to standard for interactive (interactive - 6) by using
+  # the interactive priority - 6, the helper threads that respond to requests
+  # will be running at the same priority as interactive jobs.
+  COMMAND='chgjob job('$JOBNAME') runpty(6)'
+  system $COMMAND
+
+  # Enable multi threading
+  export QIBM_MULTI_THREADED=Y
+fi
+
+# Get standard Java environment variables
+if $os400; then
+  # -r will Only work on the os400 if the files are:
+  # 1. owned by the user
+  # 2. owned by the PRIMARY group of the user
+  # this will not work if the user belongs in secondary groups
+  BASEDIR="$CATALINA_HOME"
+  . "$CATALINA_HOME"/bin/setclasspath.sh 
+else
+  if [ -r "$CATALINA_HOME"/bin/setclasspath.sh ]; then
+    BASEDIR="$CATALINA_HOME"
+    . "$CATALINA_HOME"/bin/setclasspath.sh
+  else
+    echo "Cannot find $CATALINA_HOME/bin/setclasspath.sh"
+    echo "This file is needed to run this program"
+    exit 1
+  fi
+fi
+
+# Add on extra jar files to CLASSPATH
+if [ -n "$JSSE_HOME" ]; then
+  CLASSPATH="$CLASSPATH":"$JSSE_HOME"/lib/jcert.jar:"$JSSE_HOME"/lib/jnet.jar:"$JSSE_HOME"/lib/jsse.jar
+fi
+CLASSPATH="$CLASSPATH":"$CATALINA_HOME"/bin/bootstrap.jar:"$CATALINA_HOME"/bin/commons-logging-api.jar
+
+if [ -z "$CATALINA_BASE" ] ; then
+  CATALINA_BASE="$CATALINA_HOME"
+fi
+
+if [ -z "$CATALINA_TMPDIR" ] ; then
+  # Define the java.io.tmpdir to use for Catalina
+  CATALINA_TMPDIR="$CATALINA_BASE"/temp
+fi
+
+# Bugzilla 37848: When no TTY is available, don't output to console
+have_tty=0
+if [ "`tty`" != "not a tty" ]; then
+    have_tty=1
+fi
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin; then
+  JAVA_HOME=`cygpath --absolute --windows "$JAVA_HOME"`
+  JRE_HOME=`cygpath --absolute --windows "$JRE_HOME"`
+  CATALINA_HOME=`cygpath --absolute --windows "$CATALINA_HOME"`
+  CATALINA_BASE=`cygpath --absolute --windows "$CATALINA_BASE"`
+  CATALINA_TMPDIR=`cygpath --absolute --windows "$CATALINA_TMPDIR"`
+  CLASSPATH=`cygpath --path --windows "$CLASSPATH"`
+  [ -n "$JSSE_HOME" ] && JSSE_HOME=`cygpath --absolute --windows "$JSSE_HOME"`
+  JAVA_ENDORSED_DIRS=`cygpath --path --windows "$JAVA_ENDORSED_DIRS"`
+fi
+
+# Set juli LogManager if it is present
+if [ -r "$CATALINA_HOME"/bin/tomcat-juli.jar ]; then
+  JAVA_OPTS="$JAVA_OPTS "-Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager" "-Djava.util.logging.config.file="$CATALINA_BASE/conf/logging.properties"
+fi
+
+# ----- Execute The Requested Command -----------------------------------------
+
+# Bugzilla 37848: only output this if we have a TTY
+if [ $have_tty -eq 1 ]; then
+  echo "Using CATALINA_BASE:   $CATALINA_BASE"
+  echo "Using CATALINA_HOME:   $CATALINA_HOME"
+  echo "Using CATALINA_TMPDIR: $CATALINA_TMPDIR"
+  if [ "$1" = "debug" -o "$1" = "javac" ] ; then
+    echo "Using JAVA_HOME:       $JAVA_HOME"
+  else
+    echo "Using JRE_HOME:       $JRE_HOME"
+  fi
+fi
+
+if [ "$1" = "jpda" ] ; then
+  if [ -z "$JPDA_TRANSPORT" ]; then
+    JPDA_TRANSPORT="dt_socket"
+  fi
+  if [ -z "$JPDA_ADDRESS" ]; then
+    JPDA_ADDRESS="8000"
+  fi
+  if [ -z "$JPDA_OPTS" ]; then
+    JPDA_OPTS="-Xdebug -Xrunjdwp:transport=$JPDA_TRANSPORT,address=$JPDA_ADDRESS,server=y,suspend=n"
+  fi
+  CATALINA_OPTS="$CATALINA_OPTS $JPDA_OPTS"
+  shift
+fi
+
+if [ "$1" = "debug" ] ; then
+  if $os400; then
+    echo "Debug command not available on OS400"
+    exit 1
+  else
+    shift
+    if [ "$1" = "-security" ] ; then
+      echo "Using Security Manager"
+      shift
+      exec "$_RUNJDB" $JAVA_OPTS $CATALINA_OPTS \
+        -Djava.endorsed.dirs="$JAVA_ENDORSED_DIRS" -classpath "$CLASSPATH" \
+        -sourcepath "$CATALINA_HOME"/../../jakarta-tomcat-catalina/catalina/src/share \
+        -Djava.security.manager \
+        -Djava.security.policy=="$CATALINA_BASE"/conf/catalina.policy \
+        -Dcatalina.base="$CATALINA_BASE" \
+        -Dcatalina.home="$CATALINA_HOME" \
+        -Djava.io.tmpdir="$CATALINA_TMPDIR" \
+        org.apache.catalina.startup.Bootstrap "$@" start
+    else
+      exec "$_RUNJDB" $JAVA_OPTS $CATALINA_OPTS \
+        -Djava.endorsed.dirs="$JAVA_ENDORSED_DIRS" -classpath "$CLASSPATH" \
+        -sourcepath "$CATALINA_HOME"/../../jakarta-tomcat-catalina/catalina/src/share \
+        -Dcatalina.base="$CATALINA_BASE" \
+        -Dcatalina.home="$CATALINA_HOME" \
+        -Djava.io.tmpdir="$CATALINA_TMPDIR" \
+        org.apache.catalina.startup.Bootstrap "$@" start
+    fi
+  fi
+
+elif [ "$1" = "run" ]; then
+
+  shift
+  if [ "$1" = "-security" ] ; then
+    echo "Using Security Manager"
+    shift
+    exec "$_RUNJAVA" $JAVA_OPTS $CATALINA_OPTS \
+      -Djava.endorsed.dirs="$JAVA_ENDORSED_DIRS" -classpath "$CLASSPATH" \
+      -Djava.security.manager \
+      -Djava.security.policy=="$CATALINA_BASE"/conf/catalina.policy \
+      -Dcatalina.base="$CATALINA_BASE" \
+      -Dcatalina.home="$CATALINA_HOME" \
+      -Djava.io.tmpdir="$CATALINA_TMPDIR" \
+      org.apache.catalina.startup.Bootstrap "$@" start
+  else
+    exec "$_RUNJAVA" $JAVA_OPTS $CATALINA_OPTS \
+      -Djava.endorsed.dirs="$JAVA_ENDORSED_DIRS" -classpath "$CLASSPATH" \
+      -Dcatalina.base="$CATALINA_BASE" \
+      -Dcatalina.home="$CATALINA_HOME" \
+      -Djava.io.tmpdir="$CATALINA_TMPDIR" \
+      org.apache.catalina.startup.Bootstrap "$@" start
+  fi
+
+elif [ "$1" = "start" ] ; then
+
+  shift
+  touch "$CATALINA_BASE"/logs/catalina.out
+  if [ "$1" = "-security" ] ; then
+    echo "Using Security Manager"
+    shift
+    "$_RUNJAVA" $JAVA_OPTS $CATALINA_OPTS \
+      -Djava.endorsed.dirs="$JAVA_ENDORSED_DIRS" -classpath "$CLASSPATH" \
+      -Djava.security.manager \
+      -Djava.security.policy=="$CATALINA_BASE"/conf/catalina.policy \
+      -Dcatalina.base="$CATALINA_BASE" \
+      -Dcatalina.home="$CATALINA_HOME" \
+      -Djava.io.tmpdir="$CATALINA_TMPDIR" \
+      org.apache.catalina.startup.Bootstrap "$@" start \
+      >> "$CATALINA_BASE"/logs/catalina.out 2>&1 &
+
+      if [ ! -z "$CATALINA_PID" ]; then
+        echo $! > $CATALINA_PID
+      fi
+  else
+    "$_RUNJAVA" $JAVA_OPTS $CATALINA_OPTS \
+      -Djava.endorsed.dirs="$JAVA_ENDORSED_DIRS" -classpath "$CLASSPATH" \
+      -Dcatalina.base="$CATALINA_BASE" \
+      -Dcatalina.home="$CATALINA_HOME" \
+      -Djava.io.tmpdir="$CATALINA_TMPDIR" \
+      org.apache.catalina.startup.Bootstrap "$@" start \
+      >> "$CATALINA_BASE"/logs/catalina.out 2>&1 &
+
+      if [ ! -z "$CATALINA_PID" ]; then
+        echo $! > $CATALINA_PID
+      fi
+  fi
+
+elif [ "$1" = "stop" ] ; then
+
+  shift
+  FORCE=0
+  if [ "$1" = "-force" ]; then
+    shift
+    FORCE=1
+  fi
+
+  "$_RUNJAVA" $JAVA_OPTS $CATALINA_OPTS \
+    -Djava.endorsed.dirs="$JAVA_ENDORSED_DIRS" -classpath "$CLASSPATH" \
+    -Dcatalina.base="$CATALINA_BASE" \
+    -Dcatalina.home="$CATALINA_HOME" \
+    -Djava.io.tmpdir="$CATALINA_TMPDIR" \
+    org.apache.catalina.startup.Bootstrap "$@" stop
+
+  if [ $FORCE -eq 1 ]; then
+    if [ ! -z "$CATALINA_PID" ]; then
+       echo "Killing: `cat $CATALINA_PID`"
+       kill -9 `cat $CATALINA_PID`
+    else
+       echo "Kill failed: \$CATALINA_PID not set"
+    fi
+  fi
+
+elif [ "$1" = "version" ] ; then
+
+    "$_RUNJAVA"   \
+      -classpath "$CATALINA_HOME/server/lib/catalina.jar" \
+      org.apache.catalina.util.ServerInfo
+
+else
+
+  echo "Usage: catalina.sh ( commands ... )"
+  echo "commands:"
+  if $os400; then
+    echo "  debug             Start Catalina in a debugger (not available on OS400)"
+    echo "  debug -security   Debug Catalina with a security manager (not available on OS400)"
+  else
+    echo "  debug             Start Catalina in a debugger"
+    echo "  debug -security   Debug Catalina with a security manager"
+  fi
+  echo "  jpda start        Start Catalina under JPDA debugger"
+  echo "  run               Start Catalina in the current window"
+  echo "  run -security     Start in the current window with security manager"
+  echo "  start             Start Catalina in a separate window"
+  echo "  start -security   Start in a separate window with security manager"
+  echo "  stop              Stop Catalina"
+  echo "  stop -force       Stop Catalina (followed by kill -KILL)"
+  echo "  version           What version of tomcat are you running?"
+  exit 1
+
+fi

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/bin/catalina.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/bin/catalina.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/bin/catalina.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,234 @@
+<!--
+  XML file for launching Catalina applications using ant.
+-->
+
+<project name="Catalina Launcher" default="catalina" basedir=".">
+  <property file="${user.home}/.tomcat5.properties"/>
+
+  <!-- Set the application home to the parent directory of this directory -->
+  <property name="catalina.home" location="${basedir}/.."/>
+  <property name="bootstrap.jar" location="${catalina.home}/bin/bootstrap.jar"/>
+
+  <!-- Import the user's custom properties -->
+  <property file="${catalina.home}/bin/catalina.properties"/> <!-- XXX shold it be conf ?? -->
+  <property file="${catalina.home}/conf/catalina.properties"/> <!-- XXX shold it be conf ?? -->
+
+
+  <!-- Set user configurable properties -->
+  <property name="jsse.home" location="${catalina.home}"/>
+  <property name="catalina.base" location="${catalina.home}"/>
+  <property name="catalina.tmpdir" location="${catalina.base}/temp"/>
+  <property name="catalina.out" location="${catalina.base}/logs/catalina.out"/>
+  <property name="catalina.policy" location="${catalina.base}/conf/catalina.policy"/>
+  <property name="catalina.jvm.args" value="-Dsun.io.useCanonCaches=false"/>
+
+  <property name="catalina.source.path" value="${catalina.home}/../../jakarta-servletapi-5/src/share:${catalina.home}/../../jakarta-tomcat-jasper/jasper2/src/share:${catalina.home}/../../jakarta-tomcat-connectors/coyote/src/java:${catalina.home}/../../jakarta-tomcat-catalina/catalina/src/share"/>
+
+
+  <!-- Build the classpath relative to the application home -->
+  <path id="base.class.path">
+    <pathelement location="${bootstrap.jar}"/>
+    <pathelement path="${jsse.home}/lib/jsse.jar:${jsse.home}/lib/jcert.jar:${jsse.home}/lib/jnet.jar"/>
+  </path>
+
+  <property name="basedir" location="."/>
+  
+  <property name="tools.jar" location="${java.home}/../lib/tools.jar" />
+
+  <path id="tomcatcp" >
+    <pathelement location="${catalina.home}/bin/bootstrap.jar"/>
+    <!-- 
+    <fileset dir="${catalina.home}/common/lib" includes="*.jar"/>
+    <fileset dir="${catalina.home}/server/lib" includes="*.jar"/>
+    <pathelement location="${catalina.home}/common/classes"/>
+    -->
+    <!-- 
+       <pathelement location="${ant.home}/lib/xercesImpl.jar" />
+       <pathelement location="${ant.home}/lib/xml-apis.jar" />
+    -->
+    <pathelement location="${ant.home}/lib/ant.jar" />
+    <pathelement location="${tools.jar}" />
+  </path>
+ 
+
+  <!-- =================== Initialization/helpers ================== -->
+
+
+  <target name="init"
+          description="Display configuration and conditional compilation flags">
+  </target>
+
+  <target name="init-launcher" >
+    <!-- Build the sysproperties relative to the application home -->
+    <syspropertyset id="base.sys.properties">
+      <sysproperty key="java.endorsed.dirs" file="${catalina.home}/common/endorsed"/>
+      <sysproperty key="java.io.tmpdir" file="${catalina.tmpdir}"/>
+      <sysproperty key="catalina.home" file="${catalina.home}"/>
+      <sysproperty key="catalina.base" file="${catalina.base}"/>
+    </syspropertyset>
+
+    <!-- Build the standard jvmargs -->
+    <jvmargset id="base.jvm.args">
+      <jvmarg line="${catalina.jvm.args}"/>
+      <jvmarg value="-Xdebug" if="jpda.settings"/>
+      <jvmarg value="-Xrunjdwp:${jpda.settings}" if="jpda.settings"/>
+      <jvmarg value="-sourcepath" if="jdb"/>
+      <jvmarg path="${catalina.source.path}" if="jdb"/>
+    </jvmargset>
+  </target>
+
+  <target name="echo-config" >
+    <echo>TOMCAT_HOME=${catalina.home}</echo>
+    <echo>CLASSPATH=${toString:tomcatcp}</echo>
+  </target>
+
+  <target name="help" >
+    <echo>
+  To run any of the applications in the JDB debugger, execute the Launcher with
+  a "-Ddebug=true" argument.
+
+  To run any of the applications in JPDA mode, execute the Launcher with a
+  "-Djpda=true" argument.
+   </echo>
+  </target>
+
+  <!-- Target that sets JDB properties when the "debug" property is set -->
+  <target name="setjdb" description="Set JDB properties" if="debug">
+    <property name="jdb" value="true"/>
+  </target>
+
+  <!-- Target that sets JPDA properties when the "jpda" property is set -->
+  <target name="setjpda" description="Set JPDA properties" if="jpda">
+    <condition property="jpda.transport" value="dt_shmem">
+      <os family="windows"/>
+    </condition>
+    <condition property="jpda.transport" value="dt_socket">
+      <not>
+        <os family="windows"/>
+      </not>
+    </condition>
+    <condition property="jpda.address" value="jdbconn">
+      <equals arg1="${jpda.transport}" arg2="dt_shmem"/>
+    </condition>
+    <condition property="jpda.address" value="8000">
+      <not>
+        <equals arg1="${jpda.transport}" arg2="dt_shmem"/>
+      </not>
+    </condition>
+    <property name="jpda.suspend" value="y"/>
+    <property name="jpda.settings" value="transport=${jpda.transport},address=${jpda.address},server=y,suspend=${jpda.suspend}"/>
+  </target>
+
+  <!-- =================== Launcher-based ================== -->
+
+  <!-- Target that executes Catalina -->
+  <target name="catalina" description="Execute Catalina"
+    depends="init-launcher,setjdb,setjpda" >
+
+    <!-- Set default title for minimized window -->
+    <property name="catalina.window.title" value="Catalina"/>
+
+    <!--
+      Launch Catalina. Note that the "filterclassname" attribute will force
+      the "waitforchild" attribute to "true" if any invalid arguments are
+      used or if "start" is not the last argument.
+    -->
+    <launch classname="org.apache.catalina.startup.Bootstrap"
+      waitforchild="${wait}"
+      debug="${jdb}"
+      print="${print}"
+      filterclassname="org.apache.catalina.launcher.CatalinaLaunchFilter"
+      filterclasspath="${bootstrap.jar}"
+      usesystemin="false"
+      requiretools="true"
+      redirectoutput="true"
+      output="${catalina.out}"
+      displayMinimizedWindow="true"
+      minimizedWindowTitle="${catalina.window.title}">
+        <jvmargset refid="base.jvm.args"/>
+        <syspropertyset refid="base.sys.properties"/>
+        <sysproperty key="java.security.manager" value="" if="security"/>
+        <sysproperty key="java.security.policy" value="=${catalina.policy}" if="security"/>
+        <classpath refid="base.class.path"/>
+    </launch>
+
+  </target>
+
+  <!-- Target that executes the Catalina tool wrapper -->
+  <target name="tool-wrapper" description="Execute Catalina tool wrapper"
+    depends="setjdb,setjpda" >
+
+    <!-- Launch Catalina tool wrapper -->
+    <launch classname="org.apache.catalina.startup.Tool"
+      debug="${jdb}"
+      print="${print}"
+      usesystemin="false"
+      requiretools="true">
+        <jvmargset refid="base.jvm.args"/>
+        <syspropertyset refid="base.sys.properties"/>
+        <classpath refid="base.class.path"/>
+    </launch>
+
+  </target>
+
+  <!-- ======================= Ant/JMX based ================ -->
+
+  <target name="taskdef" >
+    <property name="tomcat.home" location=".." />
+
+    <path id="jmx.test.classpath">
+      <pathelement location="${commons-modeler.jar}" />
+      <fileset dir="${tomcat.home}/common/lib" includes="*.jar"/>
+      <fileset dir="${tomcat.home}/server/lib" includes="*.jar"/>
+      <fileset dir="${tomcat.home}/bin" includes="*.jar"/>
+    </path>
+
+    <!-- part of modeler -->
+    <taskdef resource="META-INF/ant.properties"
+             classpathref="jmx.test.classpath" />
+  </target>
+
+
+  <target name="run" depends="echo-config,taskdef"
+        description="Start tomcat as a task and return">
+   
+    <MLET code="org.apache.commons.modeler.BaseModelMBean"
+          name="catalina:type=server" >
+       <arg value="org.apache.catalina.startup.Catalina" />
+    </MLET>
+
+    <jmxSet name="catalina:type=server"
+            attribute="catalinaHome"
+            value="${tomcat.home}"/>
+  
+    <!-- We could also call init and set other properties - 
+         init should load the modules -->
+
+    <jmx name="catalina:type=server"
+         method="start" />
+    
+    <echo message="Tomcat5 running"/>
+
+  </target>
+
+
+  <!-- ======================= Exec/java  ================ -->
+
+  <target name="java-start" depends="echo-config" 
+        description="Run tomcat in-process and wait for it to end, using java task" >
+
+    <property name="tomcat.fork" value="false" />
+
+    <java classname="org.apache.catalina.startup.Bootstrap" fork="${tomcat.fork}">
+      <classpath refid="tomcatcp" />
+      <arg value="startd" />
+      <sysproperty key="catalina.home" value="${catalina.home}"/>
+      <sysproperty key="build.compiler" value="jikes"/>
+      <sysproperty key="java.endorsed.dirs" value="${ant.home}/lib:${java.home}/lib"/>
+    </java>
+
+    <echo message="Tomcat5 running"/>
+
+  </target>
+
+</project>

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/bin/cpappend.bat
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/bin/cpappend.bat	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/bin/cpappend.bat	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,19 @@
+rem ---------------------------------------------------------------------------
+rem Append to CLASSPATH
+rem
+rem $Id: cpappend.bat 301115 2002-08-04 18:19:43Z patrickl $
+rem ---------------------------------------------------------------------------
+
+rem Process the first argument
+if ""%1"" == """" goto end
+set CLASSPATH=%CLASSPATH%;%1
+shift
+
+rem Process the remaining arguments
+:setArgs
+if ""%1"" == """" goto doneSetArgs
+set CLASSPATH=%CLASSPATH% %1
+shift
+goto setArgs
+:doneSetArgs
+:end

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/bin/digest.bat
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/bin/digest.bat	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/bin/digest.bat	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,41 @@
+ at echo off
+if "%OS%" == "Windows_NT" setlocal
+rem ---------------------------------------------------------------------------
+rem Script to digest password using the algorithm specified
+rem
+rem $Id: digest.bat 301115 2002-08-04 18:19:43Z patrickl $
+rem ---------------------------------------------------------------------------
+
+rem Guess CATALINA_HOME if not defined
+if not "%CATALINA_HOME%" == "" goto gotHome
+set CATALINA_HOME=.
+if exist "%CATALINA_HOME%\bin\tool-wrapper.bat" goto okHome
+set CATALINA_HOME=..
+:gotHome
+if exist "%CATALINA_HOME%\bin\tool-wrapper.bat" goto okHome
+echo The CATALINA_HOME environment variable is not defined correctly
+echo This environment variable is needed to run this program
+goto end
+:okHome
+
+set EXECUTABLE=%CATALINA_HOME%\bin\tool-wrapper.bat
+
+rem Check that target executable exists
+if exist "%EXECUTABLE%" goto okExec
+echo Cannot find %EXECUTABLE%
+echo This file is needed to run this program
+goto end
+:okExec
+
+rem Get remaining unshifted command line arguments and save them in the
+set CMD_LINE_ARGS=
+:setArgs
+if ""%1""=="""" goto doneSetArgs
+set CMD_LINE_ARGS=%CMD_LINE_ARGS% %1
+shift
+goto setArgs
+:doneSetArgs
+
+call "%EXECUTABLE%" -server org.apache.catalina.realm.RealmBase %CMD_LINE_ARGS%
+
+:end

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/bin/digest.sh
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/bin/digest.sh	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/bin/digest.sh	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,31 @@
+#!/bin/sh
+# -----------------------------------------------------------------------------
+# Script to digest password using the algorithm specified
+#
+# $Id: digest.sh 385888 2006-03-14 21:04:40Z keith $
+# -----------------------------------------------------------------------------
+
+# resolve links - $0 may be a softlink
+PRG="$0"
+
+while [ -h "$PRG" ] ; do
+  ls=`ls -ld "$PRG"`
+  link=`expr "$ls" : '.*-> \(.*\)$'`
+  if expr "$link" : '/.*' > /dev/null; then
+    PRG="$link"
+  else
+    PRG=`dirname "$PRG"`/"$link"
+  fi
+done
+ 
+PRGDIR=`dirname "$PRG"`
+EXECUTABLE=tool-wrapper.sh
+
+# Check that target executable exists
+if [ ! -x "$PRGDIR"/"$EXECUTABLE" ]; then
+  echo "Cannot find $PRGDIR/$EXECUTABLE"
+  echo "This file is needed to run this program"
+  exit 1
+fi
+
+exec "$PRGDIR"/"$EXECUTABLE" -server org.apache.catalina.realm.RealmBase "$@"

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/bin/jmxaccessor-tasks.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/bin/jmxaccessor-tasks.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/bin/jmxaccessor-tasks.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,34 @@
+<!--
+  XML file for importing Catalina jmx ant tasks.
+  <import file="${catalina.home}/bin/jmxaccessor-tasks.xml"/>
+-->
+
+<project name="jmxaccessor-tasks" >
+  <description>Catalina Ant JMX Accessor Tasks</description>
+  <!-- set catalina.home if it's not already set -->
+  <dirname property="catalina.home.bin.dir" file="${ant.file.jmxaccessor-tasks}"/>
+  <property name="catalina.home" value="${catalina.home.bin.dir}/.."/>
+  <taskdef resource="org/apache/catalina/ant/jmx/jmxaccessor.tasks">
+    <classpath>
+      <fileset file="${catalina.home}/server/lib/catalina-ant.jar"/>
+      <fileset file="${catalina.home}/server/lib/catalina-ant-jmx.jar"/>
+    </classpath>
+  </taskdef>
+  <typedef
+        name="jmxEquals"
+        classname="org.apache.catalina.ant.jmx.JMXAccessorEqualsCondition">
+    <classpath>
+      <fileset file="${catalina.home}/server/lib/catalina-ant.jar"/>
+      <fileset file="${catalina.home}/server/lib/catalina-ant-jmx.jar"/>
+    </classpath>
+  </typedef>
+  <typedef
+        name="jmxCondition"
+        classname="org.apache.catalina.ant.jmx.JMXAccessorCondition">
+    <classpath>
+      <fileset file="${catalina.home}/server/lib/catalina-ant.jar"/>
+      <fileset file="${catalina.home}/server/lib/catalina-ant-jmx.jar"/>
+    </classpath>
+  </typedef>
+
+</project>

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/bin/launcher.properties
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/bin/launcher.properties	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/bin/launcher.properties	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,23 @@
+#
+# Properties for the LauncherBootstrap class
+#
+# This file contains the following configurable properties:
+# - ant.class.path - This property is a ":" separated list of the URL file
+#   fragments where the Ant classes are located. The list must include a JAXP
+#   compliant XML parser if you are not using Java(TM) SE 1.4 or higher.
+#
+# Important notes:
+# - Relative URL file fragments, such as "../lib", are supported and strongly
+#   encouraged as absolute files prevent cross platform distribution.
+# - URL file fragments are the portions of a URL after the "file:" string.
+#   This means that you must use "/" characters as directory separators on
+#   all platforms. Also, ":" characters in a file fragment, such as in drive
+#   portion of absolute Windows files, must be URL encoded as "%3A". Lastly,
+#   directories must have a "/" character at the end.
+# - All relative URL file fragments in the above properties will be resolved
+#   using the URL of the directory that the LauncherBootstrap class was
+#   loaded from, not the current working directory. This ensures that the
+#   LauncherBootstrap class can properly resolve the files without regard to
+#   the current working directory.
+#
+ant.class.path=../common/lib/ant.jar:../common/lib/ant-launcher.jar:../common/endorsed/xercesImpl.jar:../common/endorsed/xml-apis.jar

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/bin/service.bat
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/bin/service.bat	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/bin/service.bat	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,117 @@
+ at echo off
+if "%OS%" == "Windows_NT" setlocal
+rem ---------------------------------------------------------------------------
+rem NT Service Install/Uninstall script
+rem
+rem Options
+rem install                Install the service using Tomcat5 as service name.
+rem                        Service is installed using default settings.
+rem remove                 Remove the service from the System.
+rem
+rem name        (optional) If the second argument is present it is considered
+rem                        to be new service name                                           
+rem
+rem $Id: service.bat 414655 2006-06-15 18:56:42Z yoavs $
+rem ---------------------------------------------------------------------------
+
+rem Guess CATALINA_HOME if not defined
+set CURRENT_DIR=%cd%
+if not "%CATALINA_HOME%" == "" goto gotHome
+set CATALINA_HOME=%cd%
+if exist "%CATALINA_HOME%\bin\tomcat5.exe" goto okHome
+rem CD to the upper dir
+cd ..
+set CATALINA_HOME=%cd%
+:gotHome
+if exist "%CATALINA_HOME%\bin\tomcat5.exe" goto okHome
+echo The tomcat.exe was not found...
+echo The CATALINA_HOME environment variable is not defined correctly.
+echo This environment variable is needed to run this program
+goto end
+rem Make sure prerequisite environment variables are set
+if not "%JAVA_HOME%" == "" goto okHome
+echo The JAVA_HOME environment variable is not defined
+echo This environment variable is needed to run this program
+goto end 
+:okHome
+if not "%CATALINA_BASE%" == "" goto gotBase
+set CATALINA_BASE=%CATALINA_HOME%
+:gotBase
+ 
+set EXECUTABLE=%CATALINA_HOME%\bin\tomcat5.exe
+
+rem Set default Service name
+set SERVICE_NAME=Tomcat5
+set PR_DISPLAYNAME=Apache Tomcat
+
+if "%1" == "" goto displayUsage
+if "%2" == "" goto setServiceName
+set SERVICE_NAME=%2
+set PR_DISPLAYNAME=Apache Tomcat %2
+:setServiceName
+if %1 == install goto doInstall
+if %1 == remove goto doRemove
+if %1 == uninstall goto doRemove
+echo Unknown parameter "%1"
+:displayUsage
+echo.
+echo Usage: service.bat install/remove [service_name]
+goto end
+
+:doRemove
+rem Remove the service
+"%EXECUTABLE%" //DS//%SERVICE_NAME%
+echo The service '%SERVICE_NAME%' has been removed
+goto end
+
+:doInstall
+rem Install the service
+echo Installing the service '%SERVICE_NAME%' ...
+echo Using CATALINA_HOME:    %CATALINA_HOME%
+echo Using CATALINA_BASE:    %CATALINA_BASE%
+echo Using JAVA_HOME:        %JAVA_HOME%
+
+rem Use the environment variables as an example
+rem Each command line option is prefixed with PR_
+
+set PR_DESCRIPTION=Apache Tomcat Server - http://tomcat.apache.org
+set PR_INSTALL=%EXECUTABLE%
+set PR_LOGPATH=%CATALINA_BASE%\logs
+set PR_CLASSPATH=%CATALINA_HOME%\bin\bootstrap.jar
+
+rem Set the server jvm from JAVA_HOME
+set PR_JVM=%JAVA_HOME%\jre\bin\server\jvm.dll
+if exist "%PR_JVM%" goto foundJvm
+rem Set the client jvm from JAVA_HOME
+set PR_JVM=%JAVA_HOME%\jre\bin\client\jvm.dll
+if exist "%PR_JVM%" goto foundJvm
+rem Check for JRockit JVM: Bugzilla 39674
+set PR_JVM=%JAVA_HOME%\jre\bin\jrockit\jvm.dll
+if exist "%PR_JVM%" goto foundJvm
+set PR_JVM=auto
+
+:foundJvm
+echo Using JVM:              %PR_JVM%
+"%EXECUTABLE%" //IS//%SERVICE_NAME% --StartClass org.apache.catalina.startup.Bootstrap --StopClass org.apache.catalina.startup.Bootstrap --StartParams start --StopParams stop
+if not errorlevel 1 goto installed
+echo Failed installing '%SERVICE_NAME%' service
+goto end
+:installed
+rem Clear the environment variables. They are not needed any more.
+set PR_DISPLAYNAME=
+set PR_DESCRIPTION=
+set PR_INSTALL=
+set PR_LOGPATH=
+set PR_CLASSPATH=
+set PR_JVM=
+rem Set extra parameters
+"%EXECUTABLE%" //US//%SERVICE_NAME% --JvmOptions "-Dcatalina.base=%CATALINA_BASE%;-Dcatalina.home=%CATALINA_HOME%;-Djava.endorsed.dirs=%CATALINA_HOME%\common\endorsed" --StartMode jvm --StopMode jvm
+rem More extra parameters
+set PR_LOGPATH=%CATALINA_BASE%\logs
+set PR_STDOUTPUT=auto
+set PR_STDERROR=auto
+"%EXECUTABLE%" //US//%SERVICE_NAME% ++JvmOptions "-Djava.io.tmpdir=%CATALINA_BASE%\temp" --JvmMs 128 --JvmMx 256
+echo The service '%SERVICE_NAME%' has been installed.
+
+:end
+cd %CURRENT_DIR%

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/bin/setclasspath.bat
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/bin/setclasspath.bat	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/bin/setclasspath.bat	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,69 @@
+rem ---------------------------------------------------------------------------
+rem Set CLASSPATH and Java options
+rem
+rem $Id: setclasspath.bat 355227 2005-12-08 21:44:16Z keith $
+rem ---------------------------------------------------------------------------
+
+rem Make sure prerequisite environment variables are set
+if not "%JAVA_HOME%" == "" goto gotJdkHome
+if not "%JRE_HOME%" == "" goto gotJreHome
+echo Neither the JAVA_HOME nor the JRE_HOME environment variable is defined
+echo At least one of these environment variable is needed to run this program
+goto exit
+
+:gotJreHome
+if not exist "%JRE_HOME%\bin\java.exe" goto noJavaHome
+if not exist "%JRE_HOME%\bin\javaw.exe" goto noJavaHome
+if not ""%1"" == ""debug"" goto okJavaHome
+echo JAVA_HOME should point to a JDK in order to run in debug mode.
+goto exit
+
+:gotJdkHome
+if not exist "%JAVA_HOME%\bin\java.exe" goto noJavaHome
+if not exist "%JAVA_HOME%\bin\javaw.exe" goto noJavaHome
+if not exist "%JAVA_HOME%\bin\jdb.exe" goto noJavaHome
+if not exist "%JAVA_HOME%\bin\javac.exe" goto noJavaHome
+if not "%JRE_HOME%" == "" goto okJavaHome
+set JRE_HOME=%JAVA_HOME%
+goto okJavaHome
+
+:noJavaHome
+echo The JAVA_HOME environment variable is not defined correctly
+echo This environment variable is needed to run this program
+echo NB: JAVA_HOME should point to a JDK not a JRE
+goto exit
+:okJavaHome
+
+if not "%BASEDIR%" == "" goto gotBasedir
+echo The BASEDIR environment variable is not defined
+echo This environment variable is needed to run this program
+goto exit
+:gotBasedir
+if exist "%BASEDIR%\bin\setclasspath.bat" goto okBasedir
+echo The BASEDIR environment variable is not defined correctly
+echo This environment variable is needed to run this program
+goto exit
+:okBasedir
+
+rem Set the default -Djava.endorsed.dirs argument
+set JAVA_ENDORSED_DIRS=%BASEDIR%\common\endorsed
+
+rem Set standard CLASSPATH
+rem Note that there are no quotes as we do not want to introduce random
+rem quotes into the CLASSPATH
+set CLASSPATH=%JAVA_HOME%\lib\tools.jar
+
+rem Set standard command for invoking Java.
+rem Note that NT requires a window name argument when using start.
+rem Also note the quoting as JAVA_HOME may contain spaces.
+set _RUNJAVA="%JRE_HOME%\bin\java"
+set _RUNJAVAW="%JRE_HOME%\bin\javaw"
+set _RUNJDB="%JAVA_HOME%\bin\jdb"
+set _RUNJAVAC="%JAVA_HOME%\bin\javac"
+
+goto end
+
+:exit
+exit /b 1
+
+:end

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/bin/setclasspath.sh
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/bin/setclasspath.sh	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/bin/setclasspath.sh	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,91 @@
+#!/bin/sh
+# -----------------------------------------------------------------------------
+#  Set CLASSPATH and Java options
+#
+#  $Id: setclasspath.sh 345508 2005-11-18 15:54:56Z yoavs $
+# -----------------------------------------------------------------------------
+
+# First clear out the user classpath
+CLASSPATH=
+
+# Make sure prerequisite environment variables are set
+if [ -z "$JAVA_HOME" -a -z "$JRE_HOME" ]; then
+  # Bugzilla 37284
+  if $darwin && [ -d "/System/Library/Frameworks/JavaVM.framework/Versions/1.5/Home" ]; then
+    export JAVA_HOME="/System/Library/Frameworks/JavaVM.framework/Versions/1.5/Home"
+  else
+    echo "Neither the JAVA_HOME nor the JRE_HOME environment variable is defined"
+    echo "At least one of these environment variable is needed to run this program"
+    exit 1
+  fi
+fi
+if [ -z "$JAVA_HOME" -a "$1" = "debug" ]; then
+  echo "JAVA_HOME should point to a JDK in order to run in debug mode."
+  exit 1
+fi
+if [ -z "$JRE_HOME" ]; then
+  JRE_HOME="$JAVA_HOME"
+fi
+
+# If we're running under jdb, we need a full jdk.
+if [ "$1" = "debug" -o "$1" = "javac" ] ; then
+  if [ "$os400" = "true" ]; then
+    if [ ! -x "$JAVA_HOME"/bin/java -o ! -x "$JAVA_HOME"/bin/javac ]; then
+      echo "The JAVA_HOME environment variable is not defined correctly"
+      echo "This environment variable is needed to run this program"
+      echo "NB: JAVA_HOME should point to a JDK not a JRE"
+      exit 1
+    fi
+  else
+    if [ ! -x "$JAVA_HOME"/bin/java -o ! -x "$JAVA_HOME"/bin/jdb -o ! -x "$JAVA_HOME"/bin/javac ]; then
+      echo "The JAVA_HOME environment variable is not defined correctly"
+      echo "This environment variable is needed to run this program"
+      echo "NB: JAVA_HOME should point to a JDK not a JRE"
+      exit 1
+    fi
+  fi
+fi
+if [ -z "$BASEDIR" ]; then
+  echo "The BASEDIR environment variable is not defined"
+  echo "This environment variable is needed to run this program"
+  exit 1
+fi
+if [ ! -x "$BASEDIR"/bin/setclasspath.sh ]; then
+  if $os400; then
+    # -x will Only work on the os400 if the files are:
+    # 1. owned by the user
+    # 2. owned by the PRIMARY group of the user
+    # this will not work if the user belongs in secondary groups
+    eval
+  else
+    echo "The BASEDIR environment variable is not defined correctly"
+    echo "This environment variable is needed to run this program"
+    exit 1
+  fi
+fi
+
+# Set the default -Djava.endorsed.dirs argument
+JAVA_ENDORSED_DIRS="$BASEDIR"/common/endorsed
+
+# Set standard CLASSPATH
+if [ "$1" = "debug" -o "$1" = "javac" ] ; then
+  CLASSPATH="$JAVA_HOME"/lib/tools.jar
+fi
+
+# OSX hack to CLASSPATH
+JIKESPATH=
+if [ `uname -s` = "Darwin" ]; then
+  OSXHACK="/System/Library/Frameworks/JavaVM.framework/Versions/CurrentJDK/Classes"
+  if [ -d "$OSXHACK" ]; then
+    for i in "$OSXHACK"/*.jar; do
+      JIKESPATH="$JIKESPATH":"$i"
+    done
+  fi
+fi
+
+# Set standard commands for invoking Java.
+  _RUNJAVA="$JRE_HOME"/bin/java
+if [ "$os400" != "true" ]; then
+  _RUNJDB="$JAVA_HOME"/bin/jdb
+fi
+_RUNJAVAC="$JAVA_HOME"/bin/javac

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/bin/shutdown-using-launcher.bat
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/bin/shutdown-using-launcher.bat	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/bin/shutdown-using-launcher.bat	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,39 @@
+ at echo off
+if "%OS%" == "Windows_NT" setlocal
+
+rem ---------------------------------------------------------------------------
+rem
+rem Script for shutting down Catalina using the Launcher
+rem
+rem ---------------------------------------------------------------------------
+
+rem Get standard environment variables
+set PRG=%0
+if exist %PRG%\..\setenv.bat goto gotCmdPath
+rem %0 must have been found by DOS using the %PATH% so we assume that
+rem setenv.bat will also be found in the %PATH%
+goto doneSetenv
+:gotCmdPath
+call %PRG%\..\setenv.bat
+:doneSetenv
+
+rem Make sure prerequisite environment variables are set
+if not "%JAVA_HOME%" == "" goto gotJavaHome
+echo The JAVA_HOME environment variable is not defined
+echo This environment variable is needed to run this program
+goto end
+:gotJavaHome
+
+rem Get command line arguments and save them with the proper quoting
+set CMD_LINE_ARGS=
+:setArgs
+if ""%1""=="""" goto doneSetArgs
+set CMD_LINE_ARGS=%CMD_LINE_ARGS% %1
+shift
+goto setArgs
+:doneSetArgs
+
+rem Execute the Launcher using the "catalina" target
+"%JAVA_HOME%\bin\java.exe" -classpath %PRG%\..;"%PATH%";. LauncherBootstrap -launchfile catalina.xml -verbose catalina %CMD_LINE_ARGS% stop
+
+:end

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/bin/shutdown-using-launcher.sh
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/bin/shutdown-using-launcher.sh	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/bin/shutdown-using-launcher.sh	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,29 @@
+#!/bin/sh
+
+# -----------------------------------------------------------------------------
+#
+# Script for shutting down Catalina using the Launcher
+#
+# -----------------------------------------------------------------------------
+
+# Resolve links - $0 may be a softlink
+PRG="$0"
+
+while [ -h "$PRG" ]; do
+  ls=`ls -ld "$PRG"`
+  link=`expr "$ls" : '.*-> \(.*\)$'`
+  if expr "$link" : '.*/.*' > /dev/null; then
+    PRG="$link"
+  else
+    PRG=`dirname "$PRG"`/"$link"
+  fi
+done
+
+# Get standard environment variables
+PRGDIR=`dirname "$PRG"`
+if [ -r "$PRGDIR"/setenv.sh ]; then
+  . "$PRGDIR"/setenv.sh
+fi
+
+# Execute the Launcher using the "catalina" target
+exec "$JAVA_HOME"/bin/java -classpath "$PRGDIR" LauncherBootstrap -launchfile catalina.xml -verbose catalina "$@" stop

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/bin/shutdown.bat
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/bin/shutdown.bat	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/bin/shutdown.bat	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,44 @@
+ at echo off
+if "%OS%" == "Windows_NT" setlocal
+rem ---------------------------------------------------------------------------
+rem Stop script for the CATALINA Server
+rem
+rem $Id: shutdown.bat 302913 2004-05-27 15:05:01Z yoavs $
+rem ---------------------------------------------------------------------------
+
+rem Guess CATALINA_HOME if not defined
+set CURRENT_DIR=%cd%
+if not "%CATALINA_HOME%" == "" goto gotHome
+set CATALINA_HOME=%CURRENT_DIR%
+if exist "%CATALINA_HOME%\bin\catalina.bat" goto okHome
+cd ..
+set CATALINA_HOME=%cd%
+cd %CURRENT_DIR%
+:gotHome
+if exist "%CATALINA_HOME%\bin\catalina.bat" goto okHome
+echo The CATALINA_HOME environment variable is not defined correctly
+echo This environment variable is needed to run this program
+goto end
+:okHome
+
+set EXECUTABLE=%CATALINA_HOME%\bin\catalina.bat
+
+rem Check that target executable exists
+if exist "%EXECUTABLE%" goto okExec
+echo Cannot find %EXECUTABLE%
+echo This file is needed to run this program
+goto end
+:okExec
+
+rem Get remaining unshifted command line arguments and save them in the
+set CMD_LINE_ARGS=
+:setArgs
+if ""%1""=="""" goto doneSetArgs
+set CMD_LINE_ARGS=%CMD_LINE_ARGS% %1
+shift
+goto setArgs
+:doneSetArgs
+
+call "%EXECUTABLE%" stop %CMD_LINE_ARGS%
+
+:end

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/bin/shutdown.sh
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/bin/shutdown.sh	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/bin/shutdown.sh	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,31 @@
+#!/bin/sh
+# -----------------------------------------------------------------------------
+# Stop script for the CATALINA Server
+#
+# $Id: shutdown.sh 385888 2006-03-14 21:04:40Z keith $
+# -----------------------------------------------------------------------------
+
+# resolve links - $0 may be a softlink
+PRG="$0"
+
+while [ -h "$PRG" ] ; do
+  ls=`ls -ld "$PRG"`
+  link=`expr "$ls" : '.*-> \(.*\)$'`
+  if expr "$link" : '/.*' > /dev/null; then
+    PRG="$link"
+  else
+    PRG=`dirname "$PRG"`/"$link"
+  fi
+done
+ 
+PRGDIR=`dirname "$PRG"`
+EXECUTABLE=catalina.sh
+
+# Check that target executable exists
+if [ ! -x "$PRGDIR"/"$EXECUTABLE" ]; then
+  echo "Cannot find $PRGDIR/$EXECUTABLE"
+  echo "This file is needed to run this program"
+  exit 1
+fi
+
+exec "$PRGDIR"/"$EXECUTABLE" stop "$@"

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/bin/startup-using-launcher.bat
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/bin/startup-using-launcher.bat	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/bin/startup-using-launcher.bat	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,39 @@
+ at echo off
+if "%OS%" == "Windows_NT" setlocal
+
+rem ---------------------------------------------------------------------------
+rem
+rem Script for starting Catalina using the Launcher
+rem
+rem ---------------------------------------------------------------------------
+
+rem Get standard environment variables
+set PRG=%0
+if exist %PRG%\..\setenv.bat goto gotCmdPath
+rem %0 must have been found by DOS using the %PATH% so we assume that
+rem setenv.bat will also be found in the %PATH%
+goto doneSetenv
+:gotCmdPath
+call %PRG%\..\setenv.bat
+:doneSetenv
+
+rem Make sure prerequisite environment variables are set
+if not "%JAVA_HOME%" == "" goto gotJavaHome
+echo The JAVA_HOME environment variable is not defined
+echo This environment variable is needed to run this program
+goto end
+:gotJavaHome
+
+rem Get command line arguments and save them with the proper quoting
+set CMD_LINE_ARGS=
+:setArgs
+if ""%1""=="""" goto doneSetArgs
+set CMD_LINE_ARGS=%CMD_LINE_ARGS% %1
+shift
+goto setArgs
+:doneSetArgs
+
+rem Execute the Launcher using the "catalina" target
+"%JAVA_HOME%\bin\java.exe" -classpath %PRG%\..;"%PATH%";. LauncherBootstrap -launchfile catalina.xml -verbose catalina %CMD_LINE_ARGS% start
+
+:end

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/bin/startup-using-launcher.sh
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/bin/startup-using-launcher.sh	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/bin/startup-using-launcher.sh	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,29 @@
+#!/bin/sh
+
+# -----------------------------------------------------------------------------
+#
+# Script for starting Catalina using the Launcher
+#
+# -----------------------------------------------------------------------------
+
+# Resolve links - $0 may be a softlink
+PRG="$0"
+
+while [ -h "$PRG" ]; do
+  ls=`ls -ld "$PRG"`
+  link=`expr "$ls" : '.*-> \(.*\)$'`
+  if expr "$link" : '.*/.*' > /dev/null; then
+    PRG="$link"
+  else
+    PRG=`dirname "$PRG"`/"$link"
+  fi
+done
+
+# Get standard environment variables
+PRGDIR=`dirname "$PRG"`
+if [ -r "$PRGDIR"/setenv.sh ]; then
+  . "$PRGDIR"/setenv.sh
+fi
+
+# Execute the Launcher using the "catalina" target
+exec "$JAVA_HOME"/bin/java -classpath "$PRGDIR" LauncherBootstrap -launchfile catalina.xml -verbose catalina "$@" start

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/bin/startup.bat
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/bin/startup.bat	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/bin/startup.bat	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,44 @@
+ at echo off
+if "%OS%" == "Windows_NT" setlocal
+rem ---------------------------------------------------------------------------
+rem Start script for the CATALINA Server
+rem
+rem $Id: startup.bat 302918 2004-05-27 18:25:11Z yoavs $
+rem ---------------------------------------------------------------------------
+
+rem Guess CATALINA_HOME if not defined
+set CURRENT_DIR=%cd%
+if not "%CATALINA_HOME%" == "" goto gotHome
+set CATALINA_HOME=%CURRENT_DIR%
+if exist "%CATALINA_HOME%\bin\catalina.bat" goto okHome
+cd ..
+set CATALINA_HOME=%cd%
+cd %CURRENT_DIR%
+:gotHome
+if exist "%CATALINA_HOME%\bin\catalina.bat" goto okHome
+echo The CATALINA_HOME environment variable is not defined correctly
+echo This environment variable is needed to run this program
+goto end
+:okHome
+
+set EXECUTABLE=%CATALINA_HOME%\bin\catalina.bat
+
+rem Check that target executable exists
+if exist "%EXECUTABLE%" goto okExec
+echo Cannot find %EXECUTABLE%
+echo This file is needed to run this program
+goto end
+:okExec
+
+rem Get remaining unshifted command line arguments and save them in the
+set CMD_LINE_ARGS=
+:setArgs
+if ""%1""=="""" goto doneSetArgs
+set CMD_LINE_ARGS=%CMD_LINE_ARGS% %1
+shift
+goto setArgs
+:doneSetArgs
+
+call "%EXECUTABLE%" start %CMD_LINE_ARGS%
+
+:end

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/bin/startup.sh
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/bin/startup.sh	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/bin/startup.sh	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,48 @@
+#!/bin/sh
+# -----------------------------------------------------------------------------
+# Start Script for the CATALINA Server
+#
+# $Id: startup.sh 385888 2006-03-14 21:04:40Z keith $
+# -----------------------------------------------------------------------------
+
+# Better OS/400 detection: see Bugzilla 31132
+os400=false
+darwin=false
+case "`uname`" in
+CYGWIN*) cygwin=true;;
+OS400*) os400=true;;
+Darwin*) darwin=true;;
+esac
+
+# resolve links - $0 may be a softlink
+PRG="$0"
+
+while [ -h "$PRG" ] ; do
+  ls=`ls -ld "$PRG"`
+  link=`expr "$ls" : '.*-> \(.*\)$'`
+  if expr "$link" : '/.*' > /dev/null; then
+    PRG="$link"
+  else
+    PRG=`dirname "$PRG"`/"$link"
+  fi
+done
+ 
+PRGDIR=`dirname "$PRG"`
+EXECUTABLE=catalina.sh
+
+# Check that target executable exists
+if $os400; then
+  # -x will Only work on the os400 if the files are: 
+  # 1. owned by the user
+  # 2. owned by the PRIMARY group of the user
+  # this will not work if the user belongs in secondary groups
+  eval
+else
+  if [ ! -x "$PRGDIR"/"$EXECUTABLE" ]; then
+    echo "Cannot find $PRGDIR/$EXECUTABLE"
+    echo "This file is needed to run this program"
+    exit 1
+  fi
+fi 
+
+exec "$PRGDIR"/"$EXECUTABLE" start "$@"

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/bin/tool-wrapper-using-launcher.bat
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/bin/tool-wrapper-using-launcher.bat	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/bin/tool-wrapper-using-launcher.bat	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,39 @@
+ at echo off
+if "%OS%" == "Windows_NT" setlocal
+
+rem ---------------------------------------------------------------------------
+rem
+rem Script for running the Catalina tool wrapper using the Launcher
+rem
+rem ---------------------------------------------------------------------------
+
+rem Get standard environment variables
+set PRG=%0
+if exist %PRG%\..\setenv.bat goto gotCmdPath
+rem %0 must have been found by DOS using the %PATH% so we assume that
+rem setenv.bat will also be found in the %PATH%
+goto doneSetenv
+:gotCmdPath
+call %PRG%\..\setenv.bat
+:doneSetenv
+
+rem Make sure prerequisite environment variables are set
+if not "%JAVA_HOME%" == "" goto gotJavaHome
+echo The JAVA_HOME environment variable is not defined
+echo This environment variable is needed to run this program
+goto end
+:gotJavaHome
+
+rem Get command line arguments and save them with the proper quoting
+set CMD_LINE_ARGS=
+:setArgs
+if ""%1""=="""" goto doneSetArgs
+set CMD_LINE_ARGS=%CMD_LINE_ARGS% %1
+shift
+goto setArgs
+:doneSetArgs
+
+rem Execute the Launcher using the "tool-wrapper" target
+"%JAVA_HOME%\bin\java.exe" -classpath %PRG%\..;"%PATH%";. LauncherBootstrap -launchfile catalina.xml -verbose tool-wrapper %CMD_LINE_ARGS%
+
+:end

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/bin/tool-wrapper-using-launcher.sh
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/bin/tool-wrapper-using-launcher.sh	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/bin/tool-wrapper-using-launcher.sh	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,29 @@
+#!/bin/sh
+
+# -----------------------------------------------------------------------------
+#
+# Script for running the Catalina tool wrapper using the Launcher
+#
+# -----------------------------------------------------------------------------
+
+# Resolve links - $0 may be a softlink
+PRG="$0"
+
+while [ -h "$PRG" ]; do
+  ls=`ls -ld "$PRG"`
+  link=`expr "$ls" : '.*-> \(.*\)$'`
+  if expr "$link" : '.*/.*' > /dev/null; then
+    PRG="$link"
+  else
+    PRG=`dirname "$PRG"`/"$link"
+  fi
+done
+
+# Get standard environment variables
+PRGDIR=`dirname "$PRG"`
+if [ -r "$PRGDIR"/setenv.sh ]; then
+  . "$PRGDIR"/setenv.sh
+fi
+
+# Execute the Launcher using the "tool-wrapper" target
+exec "$JAVA_HOME"/bin/java -classpath "$PRGDIR" LauncherBootstrap -launchfile catalina.xml -verbose tool-wrapper "$@"

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/bin/tool-wrapper.bat
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/bin/tool-wrapper.bat	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/bin/tool-wrapper.bat	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,59 @@
+ at echo off
+if "%OS%" == "Windows_NT" setlocal
+rem ---------------------------------------------------------------------------
+rem Wrapper script for command line tools
+rem
+rem Environment Variable Prequisites
+rem
+rem   CATALINA_HOME May point at your Catalina "build" directory.
+rem
+rem   TOOL_OPTS     (Optional) Java runtime options used when the "start",
+rem                 "stop", or "run" command is executed.
+rem
+rem   JAVA_HOME     Must point at your Java Development Kit installation.
+rem
+rem   JAVA_OPTS     (Optional) Java runtime options used when the "start",
+rem                 "stop", or "run" command is executed.
+rem
+rem $Id: tool-wrapper.bat 303419 2004-10-25 18:08:08Z markt $
+rem ---------------------------------------------------------------------------
+
+rem Guess CATALINA_HOME if not defined
+if not "%CATALINA_HOME%" == "" goto gotHome
+set CATALINA_HOME=.
+if exist "%CATALINA_HOME%\bin\tool-wrapper.bat" goto okHome
+set CATALINA_HOME=..
+:gotHome
+if exist "%CATALINA_HOME%\bin\tool-wrapper.bat" goto okHome
+echo The CATALINA_HOME environment variable is not defined correctly
+echo This environment variable is needed to run this program
+goto end
+:okHome
+
+rem Get standard environment variables
+if exist "%CATALINA_HOME%\bin\setenv.bat" call "%CATALINA_HOME%\bin\setenv.bat"
+
+rem Get standard Java environment variables
+if exist "%CATALINA_HOME%\bin\setclasspath.bat" goto okSetclasspath
+echo Cannot find %CATALINA_HOME%\bin\setclasspath.bat
+echo This file is needed to run this program
+goto end
+:okSetclasspath
+set BASEDIR=%CATALINA_HOME%
+call "%CATALINA_HOME%\bin\setclasspath.bat"
+
+rem Add on extra jar files to CLASSPATH
+set CLASSPATH=%CLASSPATH%;%CATALINA_HOME%\bin\bootstrap.jar;"%BASEDIR%"\common\lib\jmx.jar;"%BASEDIR%"\common\lib\servlet-api.jar
+
+rem Get remaining unshifted command line arguments and save them in the
+set CMD_LINE_ARGS=
+:setArgs
+if ""%1""=="""" goto doneSetArgs
+set CMD_LINE_ARGS=%CMD_LINE_ARGS% %1
+shift
+goto setArgs
+:doneSetArgs
+
+%_RUNJAVA% %JAVA_OPTS% %TOOL_OPTS% -Djava.endorsed.dirs="%JAVA_ENDORSED_DIRS%" -classpath "%CLASSPATH%" -Dcatalina.home="%CATALINA_HOME%" org.apache.catalina.startup.Tool %CMD_LINE_ARGS%
+
+:end

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/bin/tool-wrapper.sh
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/bin/tool-wrapper.sh	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/bin/tool-wrapper.sh	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,78 @@
+#!/bin/sh
+# -----------------------------------------------------------------------------
+# Wrapper script for command line tools
+#
+# Environment Variable Prequisites
+#
+#   CATALINA_HOME May point at your Catalina "build" directory.
+#
+#   TOOL_OPTS     (Optional) Java runtime options used when the "start",
+#                 "stop", or "run" command is executed.
+#
+#   JAVA_HOME     Must point at your Java Development Kit installation.
+#
+#   JAVA_OPTS     (Optional) Java runtime options used when the "start",
+#                 "stop", or "run" command is executed.
+#
+# $Id: tool-wrapper.sh 385888 2006-03-14 21:04:40Z keith $
+# -----------------------------------------------------------------------------
+
+# OS specific support.  $var _must_ be set to either true or false.
+cygwin=false
+case "`uname`" in
+CYGWIN*) cygwin=true;;
+esac
+
+# resolve links - $0 may be a softlink
+PRG="$0"
+
+while [ -h "$PRG" ]; do
+  ls=`ls -ld "$PRG"`
+  link=`expr "$ls" : '.*-> \(.*\)$'`
+  if expr "$link" : '/.*' > /dev/null; then
+    PRG="$link"
+  else
+    PRG=`dirname "$PRG"`/"$link"
+  fi
+done
+
+# Get standard environment variables
+PRGDIR=`dirname "$PRG"`
+CATALINA_HOME=`cd "$PRGDIR/.." ; pwd`
+if [ -r "$CATALINA_HOME"/bin/setenv.sh ]; then
+  . "$CATALINA_HOME"/bin/setenv.sh
+fi
+
+# For Cygwin, ensure paths are in UNIX format before anything is touched
+if $cygwin; then
+  [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
+  [ -n "$CATALINA_HOME" ] && CATALINA_HOME=`cygpath --unix "$CATALINA_HOME"`
+  [ -n "$CLASSPATH" ] && CLASSPATH=`cygpath --path --unix "$CLASSPATH"`
+fi
+
+# Get standard Java environment variables
+if [ -r "$CATALINA_HOME"/bin/setclasspath.sh ]; then
+  BASEDIR="$CATALINA_HOME"
+  . "$CATALINA_HOME"/bin/setclasspath.sh
+else
+  echo "Cannot find $CATALINA_HOME/bin/setclasspath.sh"
+  echo "This file is needed to run this program"
+  exit 1
+fi
+
+# Add on extra jar files to CLASSPATH
+CLASSPATH="$CLASSPATH":"$CATALINA_HOME"/bin/bootstrap.jar:"$BASEDIR"/common/lib/jmx.jar:"$BASEDIR"/common/lib/servlet-api.jar
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin; then
+  JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"`
+  CATALINA_HOME=`cygpath --path --windows "$CATALINA_HOME"`
+  CLASSPATH=`cygpath --path --windows "$CLASSPATH"`
+fi
+
+# ----- Execute The Requested Command -----------------------------------------
+
+exec "$_RUNJAVA" $JAVA_OPTS $TOOL_OPTS \
+  -Djava.endorsed.dirs="$JAVA_ENDORSED_DIRS" -classpath "$CLASSPATH" \
+  -Dcatalina.home="$CATALINA_HOME" \
+  org.apache.catalina.startup.Tool "$@"

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/bin/version.bat
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/bin/version.bat	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/bin/version.bat	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,44 @@
+ at echo off
+if "%OS%" == "Windows_NT" setlocal
+rem ---------------------------------------------------------------------------
+rem Version script for the CATALINA Server
+rem
+rem $Id: version.bat 302987 2004-06-30 15:25:31Z funkman $
+rem ---------------------------------------------------------------------------
+
+rem Guess CATALINA_HOME if not defined
+set CURRENT_DIR=%cd%
+if not "%CATALINA_HOME%" == "" goto gotHome
+set CATALINA_HOME=%CURRENT_DIR%
+if exist "%CATALINA_HOME%\bin\catalina.bat" goto okHome
+cd ..
+set CATALINA_HOME=%cd%
+cd %CURRENT_DIR%
+:gotHome
+if exist "%CATALINA_HOME%\bin\catalina.bat" goto okHome
+echo The CATALINA_HOME environment variable is not defined correctly
+echo This environment variable is needed to run this program
+goto end
+:okHome
+
+set EXECUTABLE=%CATALINA_HOME%\bin\catalina.bat
+
+rem Check that target executable exists
+if exist "%EXECUTABLE%" goto okExec
+echo Cannot find %EXECUTABLE%
+echo This file is needed to run this program
+goto end
+:okExec
+
+rem Get remaining unshifted command line arguments and save them in the
+set CMD_LINE_ARGS=
+:setArgs
+if ""%1""=="""" goto doneSetArgs
+set CMD_LINE_ARGS=%CMD_LINE_ARGS% %1
+shift
+goto setArgs
+:doneSetArgs
+
+call "%EXECUTABLE%" version %CMD_LINE_ARGS%
+
+:end

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/bin/version.sh
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/bin/version.sh	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/bin/version.sh	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,31 @@
+#!/bin/sh
+# -----------------------------------------------------------------------------
+# Version Script for the CATALINA Server
+#
+# $Id: version.sh 385888 2006-03-14 21:04:40Z keith $
+# -----------------------------------------------------------------------------
+
+# resolve links - $0 may be a softlink
+PRG="$0"
+
+while [ -h "$PRG" ] ; do
+  ls=`ls -ld "$PRG"`
+  link=`expr "$ls" : '.*-> \(.*\)$'`
+  if expr "$link" : '/.*' > /dev/null; then
+    PRG="$link"
+  else
+    PRG=`dirname "$PRG"`/"$link"
+  fi
+done
+
+PRGDIR=`dirname "$PRG"`
+EXECUTABLE=catalina.sh
+
+# Check that target executable exists
+if [ ! -x "$PRGDIR"/"$EXECUTABLE" ]; then
+  echo "Cannot find $PRGDIR/$EXECUTABLE"
+  echo "This file is needed to run this program"
+  exit 1
+fi
+
+exec "$PRGDIR"/"$EXECUTABLE" version "$@"

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/conf/catalina.policy
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/conf/catalina.policy	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/conf/catalina.policy	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,172 @@
+// ============================================================================
+// catalina.corepolicy - Security Policy Permissions for Tomcat 5
+//
+// This file contains a default set of security policies to be enforced (by the
+// JVM) when Catalina is executed with the "-security" option.  In addition
+// to the permissions granted here, the following additional permissions are
+// granted to the codebase specific to each web application:
+//
+// * Read access to the document root directory
+//
+// $Id: catalina.policy 393732 2006-04-13 06:32:25Z pero $
+// ============================================================================
+
+
+// ========== SYSTEM CODE PERMISSIONS =========================================
+
+
+// These permissions apply to javac
+grant codeBase "file:${java.home}/lib/-" {
+        permission java.security.AllPermission;
+};
+
+// These permissions apply to all shared system extensions
+grant codeBase "file:${java.home}/jre/lib/ext/-" {
+        permission java.security.AllPermission;
+};
+
+// These permissions apply to javac when ${java.home] points at $JAVA_HOME/jre
+grant codeBase "file:${java.home}/../lib/-" {
+        permission java.security.AllPermission;
+};
+
+// These permissions apply to all shared system extensions when
+// ${java.home} points at $JAVA_HOME/jre
+grant codeBase "file:${java.home}/lib/ext/-" {
+        permission java.security.AllPermission;
+};
+
+
+// ========== CATALINA CODE PERMISSIONS =======================================
+
+
+// These permissions apply to the launcher code
+grant codeBase "file:${catalina.home}/bin/commons-launcher.jar" {
+        permission java.security.AllPermission;
+};
+
+// These permissions apply to the daemon code
+grant codeBase "file:${catalina.home}/bin/commons-daemon.jar" {
+        permission java.security.AllPermission;
+};
+
+// These permissions apply to the commons-logging API
+grant codeBase "file:${catalina.home}/bin/commons-logging-api.jar" {
+        permission java.security.AllPermission;
+};
+
+// These permissions apply to the server startup code
+grant codeBase "file:${catalina.home}/bin/bootstrap.jar" {
+        permission java.security.AllPermission;
+};
+
+// These permissions apply to the JMX server
+grant codeBase "file:${catalina.home}/bin/jmx.jar" {
+        permission java.security.AllPermission;
+};
+
+// These permissions apply to JULI
+grant codeBase "file:${catalina.home}/bin/tomcat-juli.jar" {
+        permission java.security.AllPermission;
+};
+
+// These permissions apply to the servlet API classes
+// and those that are shared across all class loaders
+// located in the "common" directory
+grant codeBase "file:${catalina.home}/common/-" {
+        permission java.security.AllPermission;
+};
+
+// These permissions apply to the container's core code, plus any additional
+// libraries installed in the "server" directory
+grant codeBase "file:${catalina.home}/server/-" {
+        permission java.security.AllPermission;
+};
+
+// The permissions granted to the balancer WEB-INF/classes and WEB-INF/lib directory
+grant codeBase "file:${catalina.home}/webapps/balancer/-" {
+        permission java.lang.RuntimePermission "accessClassInPackage.org.apache.tomcat.util.digester";
+        permission java.lang.RuntimePermission "accessClassInPackage.org.apache.tomcat.util.digester.*";
+};
+// ========== WEB APPLICATION PERMISSIONS =====================================
+
+
+// These permissions are granted by default to all web applications
+// In addition, a web application will be given a read FilePermission
+// and JndiPermission for all files and directories in its document root.
+grant { 
+    // Required for JNDI lookup of named JDBC DataSource's and
+    // javamail named MimePart DataSource used to send mail
+    permission java.util.PropertyPermission "java.home", "read";
+    permission java.util.PropertyPermission "java.naming.*", "read";
+    permission java.util.PropertyPermission "javax.sql.*", "read";
+
+    // OS Specific properties to allow read access
+    permission java.util.PropertyPermission "os.name", "read";
+    permission java.util.PropertyPermission "os.version", "read";
+    permission java.util.PropertyPermission "os.arch", "read";
+    permission java.util.PropertyPermission "file.separator", "read";
+    permission java.util.PropertyPermission "path.separator", "read";
+    permission java.util.PropertyPermission "line.separator", "read";
+
+    // JVM properties to allow read access
+    permission java.util.PropertyPermission "java.version", "read";
+    permission java.util.PropertyPermission "java.vendor", "read";
+    permission java.util.PropertyPermission "java.vendor.url", "read";
+    permission java.util.PropertyPermission "java.class.version", "read";
+	permission java.util.PropertyPermission "java.specification.version", "read";
+	permission java.util.PropertyPermission "java.specification.vendor", "read";
+	permission java.util.PropertyPermission "java.specification.name", "read";
+
+	permission java.util.PropertyPermission "java.vm.specification.version", "read";
+	permission java.util.PropertyPermission "java.vm.specification.vendor", "read";
+	permission java.util.PropertyPermission "java.vm.specification.name", "read";
+	permission java.util.PropertyPermission "java.vm.version", "read";
+	permission java.util.PropertyPermission "java.vm.vendor", "read";
+	permission java.util.PropertyPermission "java.vm.name", "read";
+
+    // Required for OpenJMX
+    permission java.lang.RuntimePermission "getAttribute";
+
+	// Allow read of JAXP compliant XML parser debug
+	permission java.util.PropertyPermission "jaxp.debug", "read";
+
+    // Precompiled JSPs need access to this package.
+    permission java.lang.RuntimePermission "accessClassInPackage.org.apache.jasper.runtime";
+    permission java.lang.RuntimePermission "accessClassInPackage.org.apache.jasper.runtime.*";
+    
+};
+
+
+// You can assign additional permissions to particular web applications by
+// adding additional "grant" entries here, based on the code base for that
+// application, /WEB-INF/classes/, or /WEB-INF/lib/ jar files.
+//
+// Different permissions can be granted to JSP pages, classes loaded from
+// the /WEB-INF/classes/ directory, all jar files in the /WEB-INF/lib/
+// directory, or even to individual jar files in the /WEB-INF/lib/ directory.
+//
+// For instance, assume that the standard "examples" application
+// included a JDBC driver that needed to establish a network connection to the
+// corresponding database and used the scrape taglib to get the weather from
+// the NOAA web server.  You might create a "grant" entries like this:
+//
+// The permissions granted to the context root directory apply to JSP pages.
+// grant codeBase "file:${catalina.home}/webapps/examples/-" {
+//      permission java.net.SocketPermission "dbhost.mycompany.com:5432", "connect";
+//      permission java.net.SocketPermission "*.noaa.gov:80", "connect";
+// };
+//
+// The permissions granted to the context WEB-INF/classes directory
+// grant codeBase "file:${catalina.home}/webapps/examples/WEB-INF/classes/-" {
+// };
+//
+// The permission granted to your JDBC driver
+// grant codeBase "jar:file:${catalina.home}/webapps/examples/WEB-INF/lib/driver.jar!/-" {
+//      permission java.net.SocketPermission "dbhost.mycompany.com:5432", "connect";
+// };
+// The permission granted to the scrape taglib
+// grant codeBase "jar:file:${catalina.home}/webapps/examples/WEB-INF/lib/scrape.jar!/-" {
+//      permission java.net.SocketPermission "*.noaa.gov:80", "connect";
+// };
+

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/conf/catalina.properties
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/conf/catalina.properties	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/conf/catalina.properties	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,66 @@
+#
+# List of comma-separated packages that start with or equal this string
+# will cause a security exception to be thrown when
+# passed to checkPackageAccess unless the
+# corresponding RuntimePermission ("accessClassInPackage."+package) has
+# been granted.
+package.access=sun.,org.apache.catalina.,org.apache.coyote.,org.apache.tomcat.,org.apache.jasper.,sun.beans.
+#
+# List of comma-separated packages that start with or equal this string
+# will cause a security exception to be thrown when
+# passed to checkPackageDefinition unless the
+# corresponding RuntimePermission ("defineClassInPackage."+package) has
+# been granted.
+#
+# by default, no packages are restricted for definition, and none of
+# the class loaders supplied with the JDK call checkPackageDefinition.
+#
+package.definition=sun.,java.,org.apache.catalina.,org.apache.coyote.,org.apache.tomcat.,org.apache.jasper.
+
+#
+#
+# List of comma-separated paths defining the contents of the "common" 
+# classloader. Prefixes should be used to define what is the repository type.
+# Path may be relative to the CATALINA_HOME or CATALINA_BASE path or absolute.
+# If left as blank,the JVM system loader will be used as Catalina's "common" 
+# loader.
+# Examples:
+#     "foo": Add this folder as a class repository
+#     "foo/*.jar": Add all the JARs of the specified folder as class 
+#                  repositories
+#     "foo/bar.jar": Add bar.jar as a class repository
+common.loader=${catalina.home}/common/classes,${catalina.home}/common/i18n/*.jar,${catalina.home}/common/endorsed/*.jar,${catalina.home}/common/lib/*.jar
+
+#
+# List of comma-separated paths defining the contents of the "server" 
+# classloader. Prefixes should be used to define what is the repository type.
+# Path may be relative to the CATALINA_HOME or CATALINA_BASE path or absolute.
+# If left as blank, the "common" loader will be used as Catalina's "server" 
+# loader.
+# Examples:
+#     "foo": Add this folder as a class repository
+#     "foo/*.jar": Add all the JARs of the specified folder as class 
+#                  repositories
+#     "foo/bar.jar": Add bar.jar as a class repository
+server.loader=${catalina.home}/server/classes,${catalina.home}/server/lib/*.jar
+
+#
+# List of comma-separated paths defining the contents of the "shared" 
+# classloader. Prefixes should be used to define what is the repository type.
+# Path may be relative to the CATALINA_BASE path or absolute. If left as blank,
+# the "common" loader will be used as Catalina's "shared" loader.
+# Examples:
+#     "foo": Add this folder as a class repository
+#     "foo/*.jar": Add all the JARs of the specified folder as class 
+#                  repositories
+#     "foo/bar.jar": Add bar.jar as a class repository 
+# Please note that for individual jar files, e.g. bar.jar, you need the URL form
+# starting with file:.
+shared.loader=${catalina.base}/shared/classes,${catalina.base}/shared/lib/*.jar
+
+#
+# String cache configuration.
+tomcat.util.buf.StringCache.byte.enabled=true
+#tomcat.util.buf.StringCache.char.enabled=true
+#tomcat.util.buf.StringCache.trainThreshold=500000
+#tomcat.util.buf.StringCache.cacheSize=5000

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/conf/context.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/conf/context.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/conf/context.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,12 @@
+<!-- The contents of this file will be loaded for each web application -->
+<Context>
+
+    <!-- Default set of monitored resources -->
+    <WatchedResource>WEB-INF/web.xml</WatchedResource>
+	
+    <!-- Uncomment this to disable session persistence across Tomcat restarts -->
+    <!--
+    <Manager pathname="" />
+    -->
+
+</Context>

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/conf/server-minimal.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/conf/server-minimal.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/conf/server-minimal.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,25 @@
+<Server port="8005" shutdown="SHUTDOWN">
+
+  <GlobalNamingResources>
+    <!-- Used by Manager webapp -->
+    <Resource name="UserDatabase" auth="Container"
+              type="org.apache.catalina.UserDatabase"
+       description="User database that can be updated and saved"
+           factory="org.apache.catalina.users.MemoryUserDatabaseFactory"
+          pathname="conf/tomcat-users.xml" />
+  </GlobalNamingResources>
+
+  <Service name="Catalina">
+    <Connector port="8080" />
+
+    <!-- This is here for compatibility only, not required -->
+    <Connector port="8009" protocol="AJP/1.3" />
+
+    <Engine name="Catalina" defaultHost="localhost">
+      <Realm className="org.apache.catalina.realm.UserDatabaseRealm"
+             resourceName="UserDatabase" />
+      <Host name="localhost" appBase="webapps" />
+    </Engine>
+    
+  </Service>
+</Server>

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/conf/server.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/conf/server.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/conf/server.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,366 @@
+<!-- Example Server Configuration File -->
+<!-- Note that component elements are nested corresponding to their
+     parent-child relationships with each other -->
+
+<!-- A "Server" is a singleton element that represents the entire JVM,
+     which may contain one or more "Service" instances.  The Server
+     listens for a shutdown command on the indicated port.
+
+     Note:  A "Server" is not itself a "Container", so you may not
+     define subcomponents such as "Valves" or "Loggers" at this level.
+ -->
+
+<Server port="8005" shutdown="SHUTDOWN">
+
+  <!-- Comment these entries out to disable JMX MBeans support used for the 
+       administration web application -->
+  <Listener className="org.apache.catalina.core.AprLifecycleListener" />
+  <Listener className="org.apache.catalina.mbeans.ServerLifecycleListener" />
+  <Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" />
+  <Listener className="org.apache.catalina.storeconfig.StoreConfigLifecycleListener"/>
+
+  <!-- Global JNDI resources -->
+  <GlobalNamingResources>
+
+    <!-- Test entry for demonstration purposes -->
+    <Environment name="simpleValue" type="java.lang.Integer" value="30"/>
+
+    <!-- Editable user database that can also be used by
+         UserDatabaseRealm to authenticate users -->
+    <Resource name="UserDatabase" auth="Container"
+              type="org.apache.catalina.UserDatabase"
+       description="User database that can be updated and saved"
+           factory="org.apache.catalina.users.MemoryUserDatabaseFactory"
+          pathname="conf/tomcat-users.xml" />
+
+  </GlobalNamingResources>
+
+  <!-- A "Service" is a collection of one or more "Connectors" that share
+       a single "Container" (and therefore the web applications visible
+       within that Container).  Normally, that Container is an "Engine",
+       but this is not required.
+
+       Note:  A "Service" is not itself a "Container", so you may not
+       define subcomponents such as "Valves" or "Loggers" at this level.
+   -->
+
+  <!-- Define the Tomcat Stand-Alone Service -->
+  <Service name="Catalina">
+
+    <!-- A "Connector" represents an endpoint by which requests are received
+         and responses are returned.  Each Connector passes requests on to the
+         associated "Container" (normally an Engine) for processing.
+
+         By default, a non-SSL HTTP/1.1 Connector is established on port 8080.
+         You can also enable an SSL HTTP/1.1 Connector on port 8443 by
+         following the instructions below and uncommenting the second Connector
+         entry.  SSL support requires the following steps (see the SSL Config
+         HOWTO in the Tomcat 5 documentation bundle for more detailed
+         instructions):
+         * If your JDK version 1.3 or prior, download and install JSSE 1.0.2 or
+           later, and put the JAR files into "$JAVA_HOME/jre/lib/ext".
+         * Execute:
+             %JAVA_HOME%\bin\keytool -genkey -alias tomcat -keyalg RSA (Windows)
+             $JAVA_HOME/bin/keytool -genkey -alias tomcat -keyalg RSA  (Unix)
+           with a password value of "changeit" for both the certificate and
+           the keystore itself.
+
+         By default, DNS lookups are enabled when a web application calls
+         request.getRemoteHost().  This can have an adverse impact on
+         performance, so you can disable it by setting the
+         "enableLookups" attribute to "false".  When DNS lookups are disabled,
+         request.getRemoteHost() will return the String version of the
+         IP address of the remote client.
+    -->
+
+    <!-- Define a non-SSL HTTP/1.1 Connector on port 8080 -->
+    <Connector port="8080" maxHttpHeaderSize="8192"
+               maxThreads="150" minSpareThreads="25" maxSpareThreads="75"
+               enableLookups="false" redirectPort="8443" acceptCount="100"
+               connectionTimeout="20000" disableUploadTimeout="true" />
+    <!-- Note : To disable connection timeouts, set connectionTimeout value
+     to 0 -->
+	
+	<!-- Note : To use gzip compression you could set the following properties :
+	
+			   compression="on" 
+			   compressionMinSize="2048" 
+			   noCompressionUserAgents="gozilla, traviata" 
+			   compressableMimeType="text/html,text/xml"
+	-->
+
+    <!-- Define a SSL HTTP/1.1 Connector on port 8443 -->
+    <!--
+    <Connector port="8443" maxHttpHeaderSize="8192"
+               maxThreads="150" minSpareThreads="25" maxSpareThreads="75"
+               enableLookups="false" disableUploadTimeout="true"
+               acceptCount="100" scheme="https" secure="true"
+               clientAuth="false" sslProtocol="TLS" />
+    -->
+
+    <!-- Define an AJP 1.3 Connector on port 8009 -->
+    <Connector port="8009" 
+               enableLookups="false" redirectPort="8443" protocol="AJP/1.3" />
+
+    <!-- Define a Proxied HTTP/1.1 Connector on port 8082 -->
+    <!-- See proxy documentation for more information about using this. -->
+    <!--
+    <Connector port="8082" 
+               maxThreads="150" minSpareThreads="25" maxSpareThreads="75"
+               enableLookups="false" acceptCount="100" connectionTimeout="20000"
+               proxyPort="80" disableUploadTimeout="true" />
+    -->
+
+    <!-- An Engine represents the entry point (within Catalina) that processes
+         every request.  The Engine implementation for Tomcat stand alone
+         analyzes the HTTP headers included with the request, and passes them
+         on to the appropriate Host (virtual host). -->
+
+    <!-- You should set jvmRoute to support load-balancing via AJP ie :
+    <Engine name="Standalone" defaultHost="localhost" jvmRoute="jvm1">         
+    --> 
+         
+    <!-- Define the top level container in our container hierarchy -->
+    <Engine name="Catalina" defaultHost="localhost">
+
+      <!-- The request dumper valve dumps useful debugging information about
+           the request headers and cookies that were received, and the response
+           headers and cookies that were sent, for all requests received by
+           this instance of Tomcat.  If you care only about requests to a
+           particular virtual host, or a particular application, nest this
+           element inside the corresponding <Host> or <Context> entry instead.
+
+           For a similar mechanism that is portable to all Servlet 2.4
+           containers, check out the "RequestDumperFilter" Filter in the
+           example application (the source for this filter may be found in
+           "$CATALINA_HOME/webapps/examples/WEB-INF/classes/filters").
+
+           Request dumping is disabled by default.  Uncomment the following
+           element to enable it. -->
+      <!--
+      <Valve className="org.apache.catalina.valves.RequestDumperValve"/>
+      -->
+
+      <!-- Because this Realm is here, an instance will be shared globally -->
+
+      <!-- This Realm uses the UserDatabase configured in the global JNDI
+           resources under the key "UserDatabase".  Any edits
+           that are performed against this UserDatabase are immediately
+           available for use by the Realm.  -->
+      <Realm className="org.apache.catalina.realm.UserDatabaseRealm"
+             resourceName="UserDatabase"/>
+
+      <!-- Comment out the old realm but leave here for now in case we
+           need to go back quickly -->
+      <!--
+      <Realm className="org.apache.catalina.realm.MemoryRealm" />
+      -->
+
+      <!-- Replace the above Realm with one of the following to get a Realm
+           stored in a database and accessed via JDBC -->
+
+      <!--
+      <Realm  className="org.apache.catalina.realm.JDBCRealm"
+             driverName="org.gjt.mm.mysql.Driver"
+          connectionURL="jdbc:mysql://localhost/authority"
+         connectionName="test" connectionPassword="test"
+              userTable="users" userNameCol="user_name" userCredCol="user_pass"
+          userRoleTable="user_roles" roleNameCol="role_name" />
+      -->
+
+      <!--
+      <Realm  className="org.apache.catalina.realm.JDBCRealm"
+             driverName="oracle.jdbc.driver.OracleDriver"
+          connectionURL="jdbc:oracle:thin:@ntserver:1521:ORCL"
+         connectionName="scott" connectionPassword="tiger"
+              userTable="users" userNameCol="user_name" userCredCol="user_pass"
+          userRoleTable="user_roles" roleNameCol="role_name" />
+      -->
+
+      <!--
+      <Realm  className="org.apache.catalina.realm.JDBCRealm"
+             driverName="sun.jdbc.odbc.JdbcOdbcDriver"
+          connectionURL="jdbc:odbc:CATALINA"
+              userTable="users" userNameCol="user_name" userCredCol="user_pass"
+          userRoleTable="user_roles" roleNameCol="role_name" />
+      -->
+
+      <!-- Define the default virtual host
+           Note: XML Schema validation will not work with Xerces 2.2.
+       -->
+      <Host name="localhost" appBase="webapps"
+       unpackWARs="true" autoDeploy="true"
+       xmlValidation="false" xmlNamespaceAware="false">
+
+        <!-- Defines a cluster for this node,
+             By defining this element, means that every manager will be changed.
+             So when running a cluster, only make sure that you have webapps in there
+             that need to be clustered and remove the other ones.
+             A cluster has the following parameters:
+
+             className = the fully qualified name of the cluster class
+
+             clusterName = a descriptive name for your cluster, can be anything
+
+             mcastAddr = the multicast address, has to be the same for all the nodes
+
+             mcastPort = the multicast port, has to be the same for all the nodes
+             
+             mcastBindAddress = bind the multicast socket to a specific address
+             
+             mcastTTL = the multicast TTL if you want to limit your broadcast
+             
+             mcastSoTimeout = the multicast readtimeout 
+
+             mcastFrequency = the number of milliseconds in between sending a "I'm alive" heartbeat
+
+             mcastDropTime = the number a milliseconds before a node is considered "dead" if no heartbeat is received
+
+             tcpThreadCount = the number of threads to handle incoming replication requests, optimal would be the same amount of threads as nodes 
+
+             tcpListenAddress = the listen address (bind address) for TCP cluster request on this host, 
+                                in case of multiple ethernet cards.
+                                auto means that address becomes
+                                InetAddress.getLocalHost().getHostAddress()
+
+             tcpListenPort = the tcp listen port
+
+             tcpSelectorTimeout = the timeout (ms) for the Selector.select() method in case the OS
+                                  has a wakup bug in java.nio. Set to 0 for no timeout
+
+             printToScreen = true means that managers will also print to std.out
+
+             expireSessionsOnShutdown = true means that 
+
+             useDirtyFlag = true means that we only replicate a session after setAttribute,removeAttribute has been called.
+                            false means to replicate the session after each request.
+                            false means that replication would work for the following piece of code: (only for SimpleTcpReplicationManager)
+                            <%
+                            HashMap map = (HashMap)session.getAttribute("map");
+                            map.put("key","value");
+                            %>
+             replicationMode = can be either 'pooled', 'synchronous' or 'asynchronous'.
+                               * Pooled means that the replication happens using several sockets in a synchronous way. Ie, the data gets replicated, then the request return. This is the same as the 'synchronous' setting except it uses a pool of sockets, hence it is multithreaded. This is the fastest and safest configuration. To use this, also increase the nr of tcp threads that you have dealing with replication.
+                               * Synchronous means that the thread that executes the request, is also the
+                               thread the replicates the data to the other nodes, and will not return until all
+                               nodes have received the information.
+                               * Asynchronous means that there is a specific 'sender' thread for each cluster node,
+                               so the request thread will queue the replication request into a "smart" queue,
+                               and then return to the client.
+                               The "smart" queue is a queue where when a session is added to the queue, and the same session
+                               already exists in the queue from a previous request, that session will be replaced
+                               in the queue instead of replicating two requests. This almost never happens, unless there is a 
+                               large network delay.
+        -->             
+        <!--
+            When configuring for clustering, you also add in a valve to catch all the requests
+            coming in, at the end of the request, the session may or may not be replicated.
+            A session is replicated if and only if all the conditions are met:
+            1. useDirtyFlag is true or setAttribute or removeAttribute has been called AND
+            2. a session exists (has been created)
+            3. the request is not trapped by the "filter" attribute
+
+            The filter attribute is to filter out requests that could not modify the session,
+            hence we don't replicate the session after the end of this request.
+            The filter is negative, ie, anything you put in the filter, you mean to filter out,
+            ie, no replication will be done on requests that match one of the filters.
+            The filter attribute is delimited by ;, so you can't escape out ; even if you wanted to.
+
+            filter=".*\.gif;.*\.js;" means that we will not replicate the session after requests with the URI
+            ending with .gif and .js are intercepted.
+            
+            The deployer element can be used to deploy apps cluster wide.
+            Currently the deployment only deploys/undeploys to working members in the cluster
+            so no WARs are copied upons startup of a broken node.
+            The deployer watches a directory (watchDir) for WAR files when watchEnabled="true"
+            When a new war file is added the war gets deployed to the local instance,
+            and then deployed to the other instances in the cluster.
+            When a war file is deleted from the watchDir the war is undeployed locally 
+            and cluster wide
+        -->
+        
+        <!--
+        <Cluster className="org.apache.catalina.cluster.tcp.SimpleTcpCluster"
+                 managerClassName="org.apache.catalina.cluster.session.DeltaManager"
+                 expireSessionsOnShutdown="false"
+                 useDirtyFlag="true"
+                 notifyListenersOnReplication="true">
+
+            <Membership 
+                className="org.apache.catalina.cluster.mcast.McastService"
+                mcastAddr="228.0.0.4"
+                mcastPort="45564"
+                mcastFrequency="500"
+                mcastDropTime="3000"/>
+
+            <Receiver 
+                className="org.apache.catalina.cluster.tcp.ReplicationListener"
+                tcpListenAddress="auto"
+                tcpListenPort="4001"
+                tcpSelectorTimeout="100"
+                tcpThreadCount="6"/>
+
+            <Sender
+                className="org.apache.catalina.cluster.tcp.ReplicationTransmitter"
+                replicationMode="pooled"
+                ackTimeout="15000"
+                waitForAck="true"/>
+
+            <Valve className="org.apache.catalina.cluster.tcp.ReplicationValve"
+                   filter=".*\.gif;.*\.js;.*\.jpg;.*\.png;.*\.htm;.*\.html;.*\.css;.*\.txt;"/>
+                   
+            <Deployer className="org.apache.catalina.cluster.deploy.FarmWarDeployer"
+                      tempDir="/tmp/war-temp/"
+                      deployDir="/tmp/war-deploy/"
+                      watchDir="/tmp/war-listen/"
+                      watchEnabled="false"/>
+                      
+            <ClusterListener className="org.apache.catalina.cluster.session.ClusterSessionListener"/>
+        </Cluster>
+        -->        
+
+
+
+        <!-- Normally, users must authenticate themselves to each web app
+             individually.  Uncomment the following entry if you would like
+             a user to be authenticated the first time they encounter a
+             resource protected by a security constraint, and then have that
+             user identity maintained across *all* web applications contained
+             in this virtual host. -->
+        <!--
+        <Valve className="org.apache.catalina.authenticator.SingleSignOn" />
+        -->
+
+        <!-- Access log processes all requests for this virtual host.  By
+             default, log files are created in the "logs" directory relative to
+             $CATALINA_HOME.  If you wish, you can specify a different
+             directory with the "directory" attribute.  Specify either a relative
+             (to $CATALINA_HOME) or absolute path to the desired directory.
+        -->
+        <!--
+        <Valve className="org.apache.catalina.valves.AccessLogValve"
+                 directory="logs"  prefix="localhost_access_log." suffix=".txt"
+                 pattern="common" resolveHosts="false"/>
+        -->
+
+        <!-- Access log processes all requests for this virtual host.  By
+             default, log files are created in the "logs" directory relative to
+             $CATALINA_HOME.  If you wish, you can specify a different
+             directory with the "directory" attribute.  Specify either a relative
+             (to $CATALINA_HOME) or absolute path to the desired directory.
+             This access log implementation is optimized for maximum performance,
+             but is hardcoded to support only the "common" and "combined" patterns.
+        -->
+        <!--
+        <Valve className="org.apache.catalina.valves.FastCommonAccessLogValve"
+                 directory="logs"  prefix="localhost_access_log." suffix=".txt"
+                 pattern="common" resolveHosts="false"/>
+        -->
+
+      </Host>
+
+    </Engine>
+
+  </Service>
+
+</Server>

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/conf/tomcat-users.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/conf/tomcat-users.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/conf/tomcat-users.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,10 @@
+<!--
+  NOTE:  By default, no user is included in the "manager" role required
+  to operate the "/manager" web application.  If you wish to use this app,
+  you must define such a user - the username and password are arbitrary.
+-->
+<tomcat-users>
+  <user name="tomcat" password="tomcat" roles="tomcat" />
+  <user name="role1"  password="tomcat" roles="role1"  />
+  <user name="both"   password="tomcat" roles="tomcat,role1" />
+</tomcat-users>

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/conf/web.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/conf/web.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/conf/web.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,1164 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<web-app 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-app_2_4.xsd"
+    version="2.4">
+
+  <!-- ======================== Introduction ============================== -->
+  <!-- This document defines default values for *all* web applications      -->
+  <!-- loaded into this instance of Tomcat.  As each application is         -->
+  <!-- deployed, this file is processed, followed by the                    -->
+  <!-- "/WEB-INF/web.xml" deployment descriptor from your own               -->
+  <!-- applications.                                                        -->
+  <!--                                                                      -->
+  <!-- WARNING:  Do not configure application-specific resources here!      -->
+  <!-- They should go in the "/WEB-INF/web.xml" file in your application.   -->
+
+
+  <!-- ================== Built In Servlet Definitions ==================== -->
+
+
+  <!-- The default servlet for all web applications, that serves static     -->
+  <!-- resources.  It processes all requests that are not mapped to other   -->
+  <!-- servlets with servlet mappings (defined either here or in your own   -->
+  <!-- web.xml file.  This servlet supports the following initialization    -->
+  <!-- parameters (default values are in square brackets):                  -->
+  <!--                                                                      -->
+  <!--   debug               Debugging detail level for messages logged     -->
+  <!--                       by this servlet.  [0]                          -->
+  <!--                                                                      -->
+  <!--   fileEncoding        Encoding to be used to read static resources   -->
+  <!--                       [platform default]                             -->
+  <!--                                                                      -->
+  <!--   input               Input buffer size (in bytes) when reading      -->
+  <!--                       resources to be served.  [2048]                -->
+  <!--                                                                      -->
+  <!--   listings            Should directory listings be produced if there -->
+  <!--                       is no welcome file in this directory?  [false] -->
+  <!--                       WARNING: Listings for directories with many    -->
+  <!--                       entries can be slow and may consume            -->
+  <!--                       significant proportions of server resources.   -->
+  <!--                                                                      -->
+  <!--   output              Output buffer size (in bytes) when writing     -->
+  <!--                       resources to be served.  [2048]                -->
+  <!--                                                                      -->
+  <!--   readonly            Is this context "read only", so HTTP           -->
+  <!--                       commands like PUT and DELETE are               -->
+  <!--                       rejected?  [true]                              -->
+  <!--                                                                      -->
+  <!--   readmeFile          File name to display with the directory        -->
+  <!--                       contents. [null]                               -->
+  <!--                                                                      -->
+  <!--   sendfileSize        If the connector used supports sendfile, this  -->
+  <!--                       represents the minimal file size in KB for     -->
+  <!--                       which sendfile will be used. Use a negative    -->
+  <!--                       value to always disable sendfile.  [48]        -->
+  <!--                                                                      -->
+  <!--  For directory listing customization. Checks localXsltFile, then     -->
+  <!--  globalXsltFile, then defaults to original behavior.                 -->
+  <!--                                                                      -->
+  <!--   localXsltFile       Make directory listings an XML doc and         -->
+  <!--                       pass the result to this style sheet residing   -->
+  <!--                       in that directory. This overrides              -->
+  <!--                        globalXsltFile[null]                          -->
+  <!--                                                                      -->
+  <!--   globalXsltFile      Site wide configuration version of             -->
+  <!--                       localXsltFile This argument is expected        -->
+  <!--                       to be a physical file. [null]                  -->
+  <!--                                                                      -->
+  <!--                                                                      -->
+
+    <servlet>
+        <servlet-name>default</servlet-name>
+        <servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class>
+        <init-param>
+            <param-name>debug</param-name>
+            <param-value>0</param-value>
+        </init-param>
+        <init-param>
+            <param-name>listings</param-name>
+            <param-value>false</param-value>
+        </init-param>
+        <load-on-startup>1</load-on-startup>
+    </servlet>
+
+
+  <!-- The "invoker" servlet, which executes anonymous servlet classes      -->
+  <!-- that have not been defined in a web.xml file.  Traditionally, this   -->
+  <!-- servlet is mapped to the URL pattern "/servlet/*", but you can map   -->
+  <!-- it to other patterns as well.  The extra path info portion of such a -->
+  <!-- request must be the fully qualified class name of a Java class that  -->
+  <!-- implements Servlet (or extends HttpServlet), or the servlet name     -->
+  <!-- of an existing servlet definition.     This servlet supports the     -->
+  <!-- following initialization parameters (default values are in square    -->
+  <!-- brackets):                                                           -->
+  <!--                                                                      -->
+  <!--   debug               Debugging detail level for messages logged     -->
+  <!--                       by this servlet.  [0]                          -->
+
+<!--
+    <servlet>
+        <servlet-name>invoker</servlet-name>
+        <servlet-class>
+          org.apache.catalina.servlets.InvokerServlet
+        </servlet-class>
+        <init-param>
+            <param-name>debug</param-name>
+            <param-value>0</param-value>
+        </init-param>
+        <load-on-startup>2</load-on-startup>
+    </servlet>
+-->
+
+
+  <!-- The JSP page compiler and execution servlet, which is the mechanism  -->
+  <!-- used by Tomcat to support JSP pages.  Traditionally, this servlet    -->
+  <!-- is mapped to the URL pattern "*.jsp".  This servlet supports the     -->
+  <!-- following initialization parameters (default values are in square    -->
+  <!-- brackets):                                                           -->
+  <!--                                                                      -->
+  <!--   checkInterval       If development is false and checkInterval is   -->
+  <!--                       greater than zero, background compilations are -->
+  <!--                       enabled. checkInterval is the time in seconds  -->
+  <!--                       between checks to see if a JSP page needs to   -->
+  <!--                       be recompiled. [0]                             -->
+  <!--                                                                      -->
+  <!--   modificationTestInterval                                           -->
+  <!--                       Causes a JSP (and its dependent files) to not  -->
+  <!--                       be checked for modification during the         -->
+  <!--                       specified time interval (in seconds) from the  -->
+  <!--                       last time the JSP was checked for              -->
+  <!--                       modification. A value of 0 will cause the JSP  -->
+  <!--                       to be checked on every access.                 -->
+  <!--                       Used in development mode only. [4]             -->
+  <!--                                                                      -->
+  <!--   compiler            Which compiler Ant should use to compile JSP   -->
+  <!--                       pages.  See the Ant documentation for more     -->
+  <!--                       information. [javac]                           -->
+  <!--                                                                      -->
+  <!--   classdebuginfo      Should the class file be compiled with         -->
+  <!--                       debugging information?  [true]                 -->
+  <!--                                                                      -->
+  <!--   classpath           What class path should I use while compiling   -->
+  <!--                       generated servlets?  [Created dynamically      -->
+  <!--                       based on the current web application]          -->
+  <!--                                                                      -->
+  <!--   development         Is Jasper used in development mode? If true,   -->
+  <!--                       the frequency at which JSPs are checked for    -->
+  <!--                       modification may be specified via the          -->
+  <!--                       modificationTestInterval parameter. [true]     -->
+  <!--                                                                      -->
+  <!--   enablePooling       Determines whether tag handler pooling is      -->
+  <!--                       enabled  [true]                                -->
+  <!--                                                                      -->
+  <!--   fork                Tell Ant to fork compiles of JSP pages so that -->
+  <!--                       a separate JVM is used for JSP page compiles   -->
+  <!--                       from the one Tomcat is running in. [true]      -->
+  <!--                                                                      -->
+  <!--   ieClassId           The class-id value to be sent to Internet      -->
+  <!--                       Explorer when using <jsp:plugin> tags.         -->
+  <!--                       [clsid:8AD9C840-044E-11D1-B3E9-00805F499D93]   -->
+  <!--                                                                      -->
+  <!--   javaEncoding        Java file encoding to use for generating java  -->
+  <!--                       source files. [UTF8]                           -->
+  <!--                                                                      -->
+  <!--   keepgenerated       Should we keep the generated Java source code  -->
+  <!--                       for each page instead of deleting it? [true]   -->
+  <!--                                                                      -->
+  <!--   mappedfile          Should we generate static content with one     -->
+  <!--                       print statement per input line, to ease        -->
+  <!--                       debugging?  [true]                             -->
+  <!--                                                                      -->
+  <!--   trimSpaces          Should white spaces in template text between   -->
+  <!--                       actions or directives be trimmed?  [false]     -->
+  <!--                                                                      -->
+  <!--   suppressSmap        Should the generation of SMAP info for JSR45   -->
+  <!--                       debugging be suppressed?  [false]              -->
+  <!--                                                                      -->
+  <!--   dumpSmap            Should the SMAP info for JSR45 debugging be    -->
+  <!--                       dumped to a file? [false]                      -->
+  <!--                       False if suppressSmap is true                  -->
+  <!--                                                                      -->
+  <!--   genStrAsCharArray   Should text strings be generated as char       -->
+  <!--                       arrays, to improve performance in some cases?  -->
+  <!--                       [false]                                        -->
+  <!--                                                                      -->
+  <!--   errorOnUseBeanInvalidClassAttribute                                -->
+  <!--                       Should Jasper issue an error when the value of -->
+  <!--                       the class attribute in an useBean action is    -->
+  <!--                       not a valid bean class?  [true]                -->
+  <!--                                                                      -->
+  <!--   scratchdir          What scratch directory should we use when      -->
+  <!--                       compiling JSP pages?  [default work directory  -->
+  <!--                       for the current web application]               -->
+  <!--                                                                      -->
+  <!--   xpoweredBy          Determines whether X-Powered-By response       -->
+  <!--                       header is added by generated servlet  [false]  -->
+  <!--                                                                      -->
+  <!--   compilerTargetVM    Compiler target VM                             -->  
+  <!--                       default is System.properties                   -->
+  <!--                        java.specification.version > 1.4              -->
+  <!--                        [1.5] else [1.4]                              -->
+  <!--                                                                      -->
+  <!--   compilerSourceVM    Compiler source VM                             -->
+  <!--                       default is System.properties                   -->
+  <!--                        java.specification.version > 1.4              -->
+  <!--                        [1.5] else [1.4]                              -->
+  <!--                                                                      -->
+  <!-- If you wish to use Jikes to compile JSP pages:                       -->
+  <!--   Please see the "Using Jikes" section of the Jasper-HowTo           -->
+  <!--   page in the Tomcat documentation.                                  -->
+
+    <servlet>
+        <servlet-name>jsp</servlet-name>
+        <servlet-class>org.apache.jasper.servlet.JspServlet</servlet-class>
+        <init-param>
+            <param-name>fork</param-name>
+            <param-value>false</param-value>
+        </init-param>
+        <init-param>
+            <param-name>xpoweredBy</param-name>
+            <param-value>false</param-value>
+        </init-param>
+        <load-on-startup>3</load-on-startup>
+    </servlet>
+
+
+  <!-- NOTE: An SSI Filter is also available as an alternative SSI          -->
+  <!-- implementation. Use either the Servlet or the Filter but NOT both.   -->
+  <!--                                                                      -->
+  <!-- Server Side Includes processing servlet, which processes SSI         -->
+  <!-- directives in HTML pages consistent with similar support in web      -->
+  <!-- servers like Apache.  Traditionally, this servlet is mapped to the   -->
+  <!-- URL pattern "*.shtml".  This servlet supports the following          -->
+  <!-- initialization parameters (default values are in square brackets):   -->
+  <!--                                                                      -->
+  <!--   buffered            Should output from this servlet be buffered?   -->
+  <!--                       (0=false, 1=true)  [0]                         -->
+  <!--                                                                      -->
+  <!--   debug               Debugging detail level for messages logged     -->
+  <!--                       by this servlet.  [0]                          -->
+  <!--                                                                      -->
+  <!--   expires             The number of seconds before a page with SSI   -->
+  <!--                       directives will expire.  [No default]          -->
+  <!--                                                                      -->
+  <!--   isVirtualWebappRelative                                            -->
+  <!--                       Should "virtual" paths be interpreted as       -->
+  <!--                       relative to the context root, instead of       -->
+  <!--                       the server root?  (0=false, 1=true) [0]        -->
+  <!--                                                                      -->
+  <!--   inputEncoding       The encoding to assume for SSI resources if    -->
+  <!--                       one is not available from the resource.        -->
+  <!--                       [Platform default]                             -->
+  <!--                                                                      -->
+  <!--   outputEncoding      The encoding to use for the page that results  -->
+  <!--                       from the SSI processing. [UTF-8]               -->
+  <!--                                                                      -->
+  <!--                                                                      -->
+  <!-- IMPORTANT: To use the SSI servlet, you also need to rename the       -->
+  <!--            $CATALINA_HOME/server/lib/servlets-ssi.renametojar file   -->
+  <!--            to $CATALINA_HOME/server/lib/servlets-ssi.jar             -->
+
+<!--
+    <servlet>
+        <servlet-name>ssi</servlet-name>
+        <servlet-class>
+          org.apache.catalina.ssi.SSIServlet
+        </servlet-class>
+        <init-param>
+          <param-name>buffered</param-name>
+          <param-value>1</param-value>
+        </init-param>
+        <init-param>
+          <param-name>debug</param-name>
+          <param-value>0</param-value>
+        </init-param>
+        <init-param>
+          <param-name>expires</param-name>
+          <param-value>666</param-value>
+        </init-param>
+        <init-param>
+          <param-name>isVirtualWebappRelative</param-name>
+          <param-value>0</param-value>
+        </init-param>
+        <load-on-startup>4</load-on-startup>
+    </servlet>
+-->
+
+
+  <!-- Common Gateway Includes (CGI) processing servlet, which supports     -->
+  <!-- execution of external applications that conform to the CGI spec      -->
+  <!-- requirements.  Typically, this servlet is mapped to the URL pattern  -->
+  <!-- "/cgi-bin/*", which means that any CGI applications that are         -->
+  <!-- executed must be present within the web application.  This servlet   -->
+  <!-- supports the following initialization parameters (default values     -->
+  <!-- are in square brackets):                                             -->
+  <!--                                                                      -->
+  <!--   cgiPathPrefix        The CGI search path will start at             -->
+  <!--                        webAppRootDir + File.separator + this prefix. -->
+  <!--                        [WEB-INF/cgi]                                 -->
+  <!--                                                                      -->
+  <!--   debug                Debugging detail level for messages logged    -->
+  <!--                        by this servlet.  [0]                         -->
+  <!--                                                                      -->
+  <!--   executable           Name of the exectuable used to run the        -->
+  <!--                        script. [perl]                                -->
+  <!--                                                                      -->
+  <!--   parameterEncoding    Name of parameter encoding to be used with    -->
+  <!--                        CGI servlet.                                  -->
+  <!--                        [System.getProperty("file.encoding","UTF-8")] -->
+  <!--                                                                      -->
+  <!--   passShellEnvironment Should the shell environment variables (if    -->
+  <!--                        any) be passed to the CGI script? [false]     -->
+  <!--                                                                      -->
+  <!-- IMPORTANT: To use the CGI servlet, you also need to rename the       -->
+  <!--            $CATALINA_HOME/server/lib/servlets-cgi.renametojar file   -->
+  <!--            to $CATALINA_HOME/server/lib/servlets-cgi.jar             -->
+
+<!--
+    <servlet>
+        <servlet-name>cgi</servlet-name>
+        <servlet-class>org.apache.catalina.servlets.CGIServlet</servlet-class>
+        <init-param>
+          <param-name>debug</param-name>
+          <param-value>0</param-value>
+        </init-param>
+        <init-param>
+          <param-name>cgiPathPrefix</param-name>
+          <param-value>WEB-INF/cgi</param-value>
+        </init-param>
+         <load-on-startup>5</load-on-startup>
+    </servlet>
+-->
+
+
+  <!-- ================ Built In Servlet Mappings ========================= -->
+
+
+  <!-- The servlet mappings for the built in servlets defined above.  Note  -->
+  <!-- that, by default, the CGI and SSI servlets are *not* mapped.  You    -->
+  <!-- must uncomment these mappings (or add them to your application's own -->
+  <!-- web.xml deployment descriptor) to enable these services              -->
+
+    <!-- The mapping for the default servlet -->
+    <servlet-mapping>
+        <servlet-name>default</servlet-name>
+        <url-pattern>/</url-pattern>
+    </servlet-mapping>
+
+    <!-- The mapping for the invoker servlet -->
+<!--
+    <servlet-mapping>
+        <servlet-name>invoker</servlet-name>
+        <url-pattern>/servlet/*</url-pattern>
+    </servlet-mapping>
+-->
+
+    <!-- The mapping for the JSP servlet -->
+    <servlet-mapping>
+        <servlet-name>jsp</servlet-name>
+        <url-pattern>*.jsp</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>jsp</servlet-name>
+        <url-pattern>*.jspx</url-pattern>
+    </servlet-mapping>
+
+    <!-- The mapping for the SSI servlet -->
+<!--
+    <servlet-mapping>
+        <servlet-name>ssi</servlet-name>
+        <url-pattern>*.shtml</url-pattern>
+    </servlet-mapping>
+-->
+
+    <!-- The mapping for the CGI Gateway servlet -->
+
+<!--
+    <servlet-mapping>
+        <servlet-name>cgi</servlet-name>
+        <url-pattern>/cgi-bin/*</url-pattern>
+    </servlet-mapping>
+-->
+
+
+  <!-- ================== Built In Filter Definitions ===================== -->
+
+  <!-- NOTE: An SSI Servlet is also available as an alternative SSI         -->
+  <!-- implementation. Use either the Servlet or the Filter but NOT both.   -->
+  <!--                                                                      -->
+  <!-- Server Side Includes processing filter, which processes SSI          -->
+  <!-- directives in HTML pages consistent with similar support in web      -->
+  <!-- servers like Apache.  Traditionally, this filter is mapped to the    -->
+  <!-- URL pattern "*.shtml", though it can be mapped to "*" as it will     -->
+  <!-- selectively enable/disable SSI processing based on mime types. For   -->
+  <!-- this to work you will need to uncomment the .shtml mime type         -->
+  <!-- definition towards the bottom of this file.                          -->
+  <!-- The contentType init param allows you to apply SSI processing to JSP -->
+  <!-- pages, javascript, or any other content you wish.  This filter       -->
+  <!-- supports the following initialization parameters (default values are -->
+  <!-- in square brackets):                                                 -->
+  <!--                                                                      -->
+  <!--   contentType         A regex pattern that must be matched before    -->
+  <!--                       SSI processing is applied.                     -->
+  <!--                       [text/x-server-parsed-html(;.*)?]              -->
+  <!--                                                                      -->
+  <!--   debug               Debugging detail level for messages logged     -->
+  <!--                       by this servlet.  [0]                          -->
+  <!--                                                                      -->
+  <!--   expires             The number of seconds before a page with SSI   -->
+  <!--                       directives will expire.  [No default]          -->
+  <!--                                                                      -->
+  <!--   isVirtualWebappRelative                                            -->
+  <!--                       Should "virtual" paths be interpreted as       -->
+  <!--                       relative to the context root, instead of       -->
+  <!--                       the server root?  (0=false, 1=true) [0]        -->
+  <!--                                                                      -->
+  <!--                                                                      -->
+  <!-- IMPORTANT: To use the SSI filter, you also need to rename the        -->
+  <!--            $CATALINA_HOME/server/lib/servlets-ssi.renametojar file   -->
+  <!--            to $CATALINA_HOME/server/lib/servlets-ssi.jar             -->
+
+<!--
+    <filter>
+        <filter-name>ssi</filter-name>
+        <filter-class>
+          org.apache.catalina.ssi.SSIFilter
+        </filter-class>
+        <init-param>
+          <param-name>contentType</param-name>
+          <param-value>text/x-server-parsed-html(;.*)?</param-value>
+        </init-param>
+        <init-param>
+          <param-name>debug</param-name>
+          <param-value>0</param-value>
+        </init-param>
+        <init-param>
+          <param-name>expires</param-name>
+          <param-value>666</param-value>
+        </init-param>
+        <init-param>
+          <param-name>isVirtualWebappRelative</param-name>
+          <param-value>0</param-value>
+        </init-param>
+    </filter>
+-->
+
+
+  <!-- ==================== Built In Filter Mappings ====================== -->
+
+  <!-- The mapping for the SSI Filter -->
+<!--
+    <filter-mapping>
+        <filter-name>ssi</filter-name>
+        <url-pattern>*.shtml</url-pattern>
+    </filter-mapping>
+-->
+
+
+  <!-- ==================== Default Session Configuration ================= -->
+  <!-- You can set the default session timeout (in minutes) for all newly   -->
+  <!-- created sessions by modifying the value below.                       -->
+
+    <session-config>
+        <session-timeout>30</session-timeout>
+    </session-config>
+
+
+  <!-- ===================== Default MIME Type Mappings =================== -->
+  <!-- When serving static resources, Tomcat will automatically generate    -->
+  <!-- a "Content-Type" header based on the resource's filename extension,  -->
+  <!-- based on these mappings.  Additional mappings can be added here (to  -->
+  <!-- apply to all web applications), or in your own application's web.xml -->
+  <!-- deployment descriptor.                                               -->
+
+    <mime-mapping>
+        <extension>abs</extension>
+        <mime-type>audio/x-mpeg</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>ai</extension>
+        <mime-type>application/postscript</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>aif</extension>
+        <mime-type>audio/x-aiff</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>aifc</extension>
+        <mime-type>audio/x-aiff</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>aiff</extension>
+        <mime-type>audio/x-aiff</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>aim</extension>
+        <mime-type>application/x-aim</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>art</extension>
+        <mime-type>image/x-jg</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>asf</extension>
+        <mime-type>video/x-ms-asf</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>asx</extension>
+        <mime-type>video/x-ms-asf</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>au</extension>
+        <mime-type>audio/basic</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>avi</extension>
+        <mime-type>video/x-msvideo</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>avx</extension>
+        <mime-type>video/x-rad-screenplay</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>bcpio</extension>
+        <mime-type>application/x-bcpio</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>bin</extension>
+        <mime-type>application/octet-stream</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>bmp</extension>
+        <mime-type>image/bmp</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>body</extension>
+        <mime-type>text/html</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>cdf</extension>
+        <mime-type>application/x-netcdf</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>cer</extension>
+        <mime-type>application/x-x509-ca-cert</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>class</extension>
+        <mime-type>application/java</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>cpio</extension>
+        <mime-type>application/x-cpio</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>csh</extension>
+        <mime-type>application/x-csh</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>css</extension>
+        <mime-type>text/css</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>dib</extension>
+        <mime-type>image/bmp</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>doc</extension>
+        <mime-type>application/msword</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>dtd</extension>
+        <mime-type>application/xml-dtd</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>dv</extension>
+        <mime-type>video/x-dv</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>dvi</extension>
+        <mime-type>application/x-dvi</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>eps</extension>
+        <mime-type>application/postscript</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>etx</extension>
+        <mime-type>text/x-setext</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>exe</extension>
+        <mime-type>application/octet-stream</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>gif</extension>
+        <mime-type>image/gif</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>gtar</extension>
+        <mime-type>application/x-gtar</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>gz</extension>
+        <mime-type>application/x-gzip</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>hdf</extension>
+        <mime-type>application/x-hdf</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>htc</extension>
+        <mime-type>text/x-component</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>htm</extension>
+        <mime-type>text/html</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>html</extension>
+        <mime-type>text/html</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>hqx</extension>
+        <mime-type>application/mac-binhex40</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>ico</extension>
+        <mime-type>image/x-icon</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>ief</extension>
+        <mime-type>image/ief</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>jad</extension>
+        <mime-type>text/vnd.sun.j2me.app-descriptor</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>jar</extension>
+        <mime-type>application/java-archive</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>java</extension>
+        <mime-type>text/plain</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>jnlp</extension>
+        <mime-type>application/x-java-jnlp-file</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>jpe</extension>
+        <mime-type>image/jpeg</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>jpeg</extension>
+        <mime-type>image/jpeg</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>jpg</extension>
+        <mime-type>image/jpeg</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>js</extension>
+        <mime-type>text/javascript</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>jsf</extension>
+        <mime-type>text/plain</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>jspf</extension>
+        <mime-type>text/plain</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>kar</extension>
+        <mime-type>audio/midi</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>latex</extension>
+        <mime-type>application/x-latex</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>m3u</extension>
+        <mime-type>audio/x-mpegurl</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>mac</extension>
+        <mime-type>image/x-macpaint</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>man</extension>
+        <mime-type>application/x-troff-man</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>mathml</extension>
+        <mime-type>application/mathml+xml</mime-type> 
+    </mime-mapping>
+    <mime-mapping>
+        <extension>me</extension>
+        <mime-type>application/x-troff-me</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>mid</extension>
+        <mime-type>audio/midi</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>midi</extension>
+        <mime-type>audio/midi</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>mif</extension>
+        <mime-type>application/vnd.mif</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>mov</extension>
+        <mime-type>video/quicktime</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>movie</extension>
+        <mime-type>video/x-sgi-movie</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>mp1</extension>
+        <mime-type>audio/x-mpeg</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>mp2</extension>
+        <mime-type>audio/mpeg</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>mp3</extension>
+        <mime-type>audio/mpeg</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>mpa</extension>
+        <mime-type>audio/x-mpeg</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>mpe</extension>
+        <mime-type>video/mpeg</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>mpeg</extension>
+        <mime-type>video/mpeg</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>mpega</extension>
+        <mime-type>audio/x-mpeg</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>mpg</extension>
+        <mime-type>video/mpeg</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>mpv2</extension>
+        <mime-type>video/mpeg2</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>ms</extension>
+        <mime-type>application/x-troff-ms</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>nc</extension>
+        <mime-type>application/x-netcdf</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>oda</extension>
+        <mime-type>application/oda</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <!-- OpenDocument Database -->
+        <extension>odb</extension>
+        <mime-type>application/vnd.oasis.opendocument.database</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <!-- OpenDocument Chart -->
+        <extension>odc</extension>
+        <mime-type>application/vnd.oasis.opendocument.chart</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <!-- OpenDocument Formula -->
+        <extension>odf</extension>
+        <mime-type>application/vnd.oasis.opendocument.formula</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <!-- OpenDocument Drawing -->
+        <extension>odg</extension>
+        <mime-type>application/vnd.oasis.opendocument.graphics</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <!-- OpenDocument Image -->
+        <extension>odi</extension>
+        <mime-type>application/vnd.oasis.opendocument.image</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <!-- OpenDocument Master Document -->
+        <extension>odm</extension>
+        <mime-type>application/vnd.oasis.opendocument.text-master</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <!-- OpenDocument Presentation -->
+        <extension>odp</extension>
+        <mime-type>application/vnd.oasis.opendocument.presentation</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <!-- OpenDocument Spreadsheet -->
+        <extension>ods</extension>
+        <mime-type>application/vnd.oasis.opendocument.spreadsheet</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <!-- OpenDocument Text -->
+        <extension>odt</extension>
+        <mime-type>application/vnd.oasis.opendocument.text</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>ogg</extension>
+        <mime-type>application/ogg</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <!-- OpenDocument Drawing Template -->
+        <extension>otg </extension>
+        <mime-type>application/vnd.oasis.opendocument.graphics-template</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <!-- HTML Document Template -->
+        <extension>oth</extension>
+        <mime-type>application/vnd.oasis.opendocument.text-web</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <!-- OpenDocument Presentation Template -->
+        <extension>otp</extension>
+        <mime-type>application/vnd.oasis.opendocument.presentation-template</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <!-- OpenDocument Spreadsheet Template -->
+        <extension>ots</extension>
+        <mime-type>application/vnd.oasis.opendocument.spreadsheet-template </mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <!-- OpenDocument Text Template -->
+        <extension>ott</extension>
+        <mime-type>application/vnd.oasis.opendocument.text-template</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>pbm</extension>
+        <mime-type>image/x-portable-bitmap</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>pct</extension>
+        <mime-type>image/pict</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>pdf</extension>
+        <mime-type>application/pdf</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>pgm</extension>
+        <mime-type>image/x-portable-graymap</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>pic</extension>
+        <mime-type>image/pict</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>pict</extension>
+        <mime-type>image/pict</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>pls</extension>
+        <mime-type>audio/x-scpls</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>png</extension>
+        <mime-type>image/png</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>pnm</extension>
+        <mime-type>image/x-portable-anymap</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>pnt</extension>
+        <mime-type>image/x-macpaint</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>ppm</extension>
+        <mime-type>image/x-portable-pixmap</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>pps</extension>
+        <mime-type>application/vnd.ms-powerpoint</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>ppt</extension>
+        <mime-type>application/vnd.ms-powerpoint</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>ps</extension>
+        <mime-type>application/postscript</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>psd</extension>
+        <mime-type>image/x-photoshop</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>qt</extension>
+        <mime-type>video/quicktime</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>qti</extension>
+        <mime-type>image/x-quicktime</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>qtif</extension>
+        <mime-type>image/x-quicktime</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>ras</extension>
+        <mime-type>image/x-cmu-raster</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>rdf</extension>
+        <mime-type>application/rdf+xml</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>rgb</extension>
+        <mime-type>image/x-rgb</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>rm</extension>
+        <mime-type>application/vnd.rn-realmedia</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>roff</extension>
+        <mime-type>application/x-troff</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>rtf</extension>
+        <mime-type>text/rtf</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>rtx</extension>
+        <mime-type>text/richtext</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>sh</extension>
+        <mime-type>application/x-sh</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>shar</extension>
+        <mime-type>application/x-shar</mime-type>
+    </mime-mapping>
+<!--
+    <mime-mapping>
+        <extension>shtml</extension>
+        <mime-type>text/x-server-parsed-html</mime-type>
+    </mime-mapping>
+-->
+    <mime-mapping>
+        <extension>smf</extension>
+        <mime-type>audio/x-midi</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>sit</extension>
+        <mime-type>application/x-stuffit</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>snd</extension>
+        <mime-type>audio/basic</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>src</extension>
+        <mime-type>application/x-wais-source</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>sv4cpio</extension>
+        <mime-type>application/x-sv4cpio</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>sv4crc</extension>
+        <mime-type>application/x-sv4crc</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>svg</extension>
+        <mime-type>image/svg+xml</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>svgz</extension>
+        <mime-type>image/svg</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>swf</extension>
+        <mime-type>application/x-shockwave-flash</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>t</extension>
+        <mime-type>application/x-troff</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>tar</extension>
+        <mime-type>application/x-tar</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>tcl</extension>
+        <mime-type>application/x-tcl</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>tex</extension>
+        <mime-type>application/x-tex</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>texi</extension>
+        <mime-type>application/x-texinfo</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>texinfo</extension>
+        <mime-type>application/x-texinfo</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>tif</extension>
+        <mime-type>image/tiff</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>tiff</extension>
+        <mime-type>image/tiff</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>tr</extension>
+        <mime-type>application/x-troff</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>tsv</extension>
+        <mime-type>text/tab-separated-values</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>txt</extension>
+        <mime-type>text/plain</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>ulw</extension>
+        <mime-type>audio/basic</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>ustar</extension>
+        <mime-type>application/x-ustar</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>vrml</extension>
+        <mime-type>model/vrml</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>vsd</extension>
+        <mime-type>application/x-visio</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>vxml</extension>
+        <mime-type>application/voicexml+xml</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>wav</extension>
+        <mime-type>audio/x-wav</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <!-- Wireless Bitmap -->
+        <extension>wbmp</extension>
+        <mime-type>image/vnd.wap.wbmp</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <!-- WML Source -->
+        <extension>wml</extension>
+        <mime-type>text/vnd.wap.wml</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <!-- Compiled WML -->
+        <extension>wmlc</extension>
+        <mime-type>application/vnd.wap.wmlc</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <!-- WML Script Source -->
+        <extension>wmls</extension>
+        <mime-type>text/vnd.wap.wmlscript</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <!-- Compiled WML Script -->
+        <extension>wmlscriptc</extension>
+        <mime-type>application/vnd.wap.wmlscriptc</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>wrl</extension>
+        <mime-type>model/vrml</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>xbm</extension>
+        <mime-type>image/x-xbitmap</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>xht</extension>
+        <mime-type>application/xhtml+xml</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>xhtml</extension>
+        <mime-type>application/xhtml+xml</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>xls</extension>
+        <mime-type>application/vnd.ms-excel</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>xml</extension>
+        <mime-type>application/xml</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>xpm</extension>
+        <mime-type>image/x-xpixmap</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>xsl</extension>
+        <mime-type>application/xml</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>xslt</extension>
+        <mime-type>application/xslt+xml</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>xul</extension>
+        <mime-type>application/vnd.mozilla.xul+xml</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>xwd</extension>
+        <mime-type>image/x-xwindowdump</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>Z</extension>
+        <mime-type>application/x-compress</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>z</extension>
+        <mime-type>application/x-compress</mime-type>
+    </mime-mapping>
+    <mime-mapping>
+        <extension>zip</extension>
+        <mime-type>application/zip</mime-type>
+    </mime-mapping>
+
+  <!-- ==================== Default Welcome File List ===================== -->
+  <!-- When a request URI refers to a directory, the default servlet looks  -->
+  <!-- for a "welcome file" within that directory and, if present,          -->
+  <!-- to the corresponding resource URI for display.  If no welcome file   -->
+  <!-- is present, the default servlet either serves a directory listing,   -->
+  <!-- or returns a 404 status, depending on how it is configured.          -->
+  <!--                                                                      -->
+  <!-- If you define welcome files in your own application's web.xml        -->
+  <!-- deployment descriptor, that list *replaces* the list configured      -->
+  <!-- here, so be sure that you include any of the default values that     -->
+  <!-- you wish to include.                                                 -->
+
+    <welcome-file-list>
+        <welcome-file>index.html</welcome-file>
+        <welcome-file>index.htm</welcome-file>
+        <welcome-file>index.jsp</welcome-file>
+    </welcome-file-list>
+
+</web-app>

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/Authenticator.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/Authenticator.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/Authenticator.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,35 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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;
+
+
+/**
+ * An <b>Authenticator</b> is a component (usually a Valve or Container) that
+ * provides some sort of authentication service.  The interface itself has no
+ * functional significance,  but is used as a tagging mechanism so that other
+ * components can detect the presence (via an "instanceof Authenticator" test)
+ * of an already configured authentication service.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public interface Authenticator {
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/Cluster.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/Cluster.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/Cluster.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,178 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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 java.net.URL;
+/**
+ * A <b>Cluster</b> works as a Cluster client/server for the local host
+ * Different Cluster implementations can be used to support different
+ * ways to communicate within the Cluster. A Cluster implementation is
+ * responsible for setting up a way to communicate within the Cluster
+ * and also supply "ClientApplications" with <code>ClusterSender</code>
+ * used when sending information in the Cluster and
+ * <code>ClusterInfo</code> used for receiving information in the Cluster.
+ *
+ * @author Bip Thelin
+ * @author Remy Maucherat
+ * @author Filip Hanik
+ * @version $Revision: 303857 $, $Date: 2005-04-15 15:15:45 -0500 (Fri, 15 Apr 2005) $
+ */
+
+public interface Cluster {
+
+    // ------------------------------------------------------------- Properties
+
+    /**
+     * Return descriptive information about this Cluster implementation and
+     * the corresponding version number, in the format
+     * <code>&lt;description&gt;/&lt;version&gt;</code>.
+     */
+    public String getInfo();
+
+    /**
+     * Return the name of the cluster that this Server is currently
+     * configured to operate within.
+     *
+     * @return The name of the cluster associated with this server
+     */
+    public String getClusterName();
+
+    /**
+     * Set the name of the cluster to join, if no cluster with
+     * this name is present create one.
+     *
+     * @param clusterName The clustername to join
+     */
+    public void setClusterName(String clusterName);
+
+    /**
+     * Set the Container associated with our Cluster
+     *
+     * @param container The Container to use
+     */
+    public void setContainer(Container container);
+
+    /**
+     * Get the Container associated with our Cluster
+     *
+     * @return The Container associated with our Cluster
+     */
+    public Container getContainer();
+
+    /**
+     * Set the protocol parameters.
+     *
+     * @param protocol The protocol used by the cluster
+     * @deprecated
+     */
+    public void setProtocol(String protocol);
+
+    /**
+     * Get the protocol used by the cluster.
+     *
+     * @return The protocol
+     * @deprecated
+     */
+    public String getProtocol();
+
+    // --------------------------------------------------------- Public Methods
+
+    /**
+     * Create a new manager which will use this cluster to replicate its
+     * sessions.
+     *
+     * @param name Name (key) of the application with which the manager is
+     * associated
+     */
+    public Manager createManager(String name);
+
+    // --------------------------------------------------------- Cluster Wide Deployments
+    
+    
+    /**
+     * Execute a periodic task, such as reloading, etc. This method will be
+     * invoked inside the classloading context of this container. Unexpected
+     * throwables will be caught and logged.
+     */
+    public void backgroundProcess();
+
+
+    /**
+     * Start an existing web application, attached to the specified context
+     * path in all the other nodes in the cluster.
+     * Only starts a web application if it is not running.
+     *
+     * @param contextPath The context path of the application to be started
+     *
+     * @exception IllegalArgumentException if the specified context path
+     *  is malformed (it must be "" or start with a slash)
+     * @exception IllegalArgumentException if the specified context path does
+     *  not identify a currently installed web application
+     * @exception IOException if an input/output error occurs during
+     *  startup
+     * @deprecated
+     */
+    public void startContext(String contextPath) throws IOException;
+
+
+    /**
+     * Install a new web application, whose web application archive is at the
+     * specified URL, into this container with the specified context path.
+     * A context path of "" (the empty string) should be used for the root
+     * application for this container.  Otherwise, the context path must
+     * start with a slash.
+     * <p>
+     * If this application is successfully installed, a ContainerEvent of type
+     * <code>PRE_INSTALL_EVENT</code> will be sent to registered listeners
+     * before the associated Context is started, and a ContainerEvent of type
+     * <code>INSTALL_EVENT</code> will be sent to all registered listeners
+     * after the associated Context is started, with the newly created
+     * <code>Context</code> as an argument.
+     *
+     * @param contextPath The context path to which this application should
+     *  be installed (must be unique)
+     * @param war A URL of type "jar:" that points to a WAR file, or type
+     *  "file:" that points to an unpacked directory structure containing
+     *  the web application to be installed
+     *
+     * @exception IllegalArgumentException if the specified context path
+     *  is malformed (it must be "" or start with a slash)
+     * @exception IllegalStateException if the specified context path
+     *  is already attached to an existing web application
+     * @deprecated
+     */
+    public void installContext(String contextPath, URL war);
+
+    /**
+     * Stop an existing web application, attached to the specified context
+     * path.  Only stops a web application if it is running.
+     *
+     * @param contextPath The context path of the application to be stopped
+     *
+     * @exception IllegalArgumentException if the specified context path
+     *  is malformed (it must be "" or start with a slash)
+     * @exception IllegalArgumentException if the specified context path does
+     *  not identify a currently installed web application
+     * @exception IOException if an input/output error occurs while stopping
+     *  the web application
+     * @deprecated
+     */
+    public void stop(String contextPath) throws IOException;
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/Contained.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/Contained.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/Contained.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,53 @@
+/*
+ * Copyright 1999-2001,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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;
+
+
+/**
+ * <p>Decoupling interface which specifies that an implementing class is
+ * associated with at most one <strong>Container</strong> instance.</p>
+ *
+ * @author Craig R. McClanahan
+ * @author Peter Donald
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public interface Contained {
+
+
+    //-------------------------------------------------------------- Properties
+
+
+    /**
+     * Return the <code>Container</code> with which this instance is associated
+     * (if any); otherwise return <code>null</code>.
+     */
+    public Container getContainer();
+
+
+    /**
+     * Set the <code>Container</code> with which this instance is associated.
+     *
+     * @param container The Container instance with which this instance is to
+     *  be associated, or <code>null</code> to disassociate this instance
+     *  from any Container
+     */
+    public void setContainer(Container container);
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/Container.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/Container.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/Container.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,442 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.beans.PropertyChangeListener;
+import java.io.IOException;
+import javax.servlet.ServletException;
+import javax.naming.directory.DirContext;
+
+import org.apache.commons.logging.Log;
+import org.apache.catalina.connector.Request;
+import org.apache.catalina.connector.Response;
+
+
+/**
+ * A <b>Container</b> is an object that can execute requests received from
+ * a client, and return responses based on those requests.  A Container may
+ * optionally support a pipeline of Valves that process the request in an
+ * order configured at runtime, by implementing the <b>Pipeline</b> interface
+ * as well.
+ * <p>
+ * Containers will exist at several conceptual levels within Catalina.  The
+ * following examples represent common cases:
+ * <ul>
+ * <li><b>Engine</b> - Representation of the entire Catalina servlet engine,
+ *     most likely containing one or more subcontainers that are either Host
+ *     or Context implementations, or other custom groups.
+ * <li><b>Host</b> - Representation of a virtual host containing a number
+ *     of Contexts.
+ * <li><b>Context</b> - Representation of a single ServletContext, which will
+ *     typically contain one or more Wrappers for the supported servlets.
+ * <li><b>Wrapper</b> - Representation of an individual servlet definition
+ *     (which may support multiple servlet instances if the servlet itself
+ *     implements SingleThreadModel).
+ * </ul>
+ * A given deployment of Catalina need not include Containers at all of the
+ * levels described above.  For example, an administration application
+ * embedded within a network device (such as a router) might only contain
+ * a single Context and a few Wrappers, or even a single Wrapper if the
+ * application is relatively small.  Therefore, Container implementations
+ * need to be designed so that they will operate correctly in the absence
+ * of parent Containers in a given deployment.
+ * <p>
+ * A Container may also be associated with a number of support components
+ * that provide functionality which might be shared (by attaching it to a
+ * parent Container) or individually customized.  The following support
+ * components are currently recognized:
+ * <ul>
+ * <li><b>Loader</b> - Class loader to use for integrating new Java classes
+ *     for this Container into the JVM in which Catalina is running.
+ * <li><b>Logger</b> - Implementation of the <code>log()</code> method
+ *     signatures of the <code>ServletContext</code> interface.
+ * <li><b>Manager</b> - Manager for the pool of Sessions associated with
+ *     this Container.
+ * <li><b>Realm</b> - Read-only interface to a security domain, for
+ *     authenticating user identities and their corresponding roles.
+ * <li><b>Resources</b> - JNDI directory context enabling access to static
+ *     resources, enabling custom linkages to existing server components when
+ *     Catalina is embedded in a larger server.
+ * </ul>
+ *
+ * @author Craig R. McClanahan
+ * @author Remy Maucherat
+ * @version $Revision: 303037 $ $Date: 2004-07-27 02:17:21 -0500 (Tue, 27 Jul 2004) $
+ */
+
+public interface Container {
+
+
+    // ----------------------------------------------------- Manifest Constants
+
+
+    /**
+     * The ContainerEvent event type sent when a child container is added
+     * by <code>addChild()</code>.
+     */
+    public static final String ADD_CHILD_EVENT = "addChild";
+
+
+    /**
+     * The ContainerEvent event type sent when a Mapper is added
+     * by <code>addMapper()</code>.
+     */
+    public static final String ADD_MAPPER_EVENT = "addMapper";
+
+
+    /**
+     * The ContainerEvent event type sent when a valve is added
+     * by <code>addValve()</code>, if this Container supports pipelines.
+     */
+    public static final String ADD_VALVE_EVENT = "addValve";
+
+
+    /**
+     * The ContainerEvent event type sent when a child container is removed
+     * by <code>removeChild()</code>.
+     */
+    public static final String REMOVE_CHILD_EVENT = "removeChild";
+
+
+    /**
+     * The ContainerEvent event type sent when a Mapper is removed
+     * by <code>removeMapper()</code>.
+     */
+    public static final String REMOVE_MAPPER_EVENT = "removeMapper";
+
+
+    /**
+     * The ContainerEvent event type sent when a valve is removed
+     * by <code>removeValve()</code>, if this Container supports pipelines.
+     */
+    public static final String REMOVE_VALVE_EVENT = "removeValve";
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * Return descriptive information about this Container implementation and
+     * the corresponding version number, in the format
+     * <code>&lt;description&gt;/&lt;version&gt;</code>.
+     */
+    public String getInfo();
+
+
+    /**
+     * Return the Loader with which this Container is associated.  If there is
+     * no associated Loader, return the Loader associated with our parent
+     * Container (if any); otherwise, return <code>null</code>.
+     */
+    public Loader getLoader();
+
+
+    /**
+     * Set the Loader with which this Container is associated.
+     *
+     * @param loader The newly associated loader
+     */
+    public void setLoader(Loader loader);
+
+
+    /**
+     * Return the Logger with which this Container is associated.  If there is
+     * no associated Logger, return the Logger associated with our parent
+     * Container (if any); otherwise return <code>null</code>.
+     */
+    public Log getLogger();
+
+
+    /**
+     * Return the Manager with which this Container is associated.  If there is
+     * no associated Manager, return the Manager associated with our parent
+     * Container (if any); otherwise return <code>null</code>.
+     */
+    public Manager getManager();
+
+
+    /**
+     * Set the Manager with which this Container is associated.
+     *
+     * @param manager The newly associated Manager
+     */
+    public void setManager(Manager manager);
+
+
+    /**
+     * Return an object which may be utilized for mapping to this component.
+     */
+    public Object getMappingObject();
+
+    
+    /**
+     * Return the JMX name associated with this container.
+     */
+    public String getObjectName();    
+
+    /**
+     * Return the Pipeline object that manages the Valves associated with
+     * this Container.
+     */
+    public Pipeline getPipeline();
+
+
+    /**
+     * Return the Cluster with which this Container is associated.  If there is
+     * no associated Cluster, return the Cluster associated with our parent
+     * Container (if any); otherwise return <code>null</code>.
+     */
+    public Cluster getCluster();
+
+
+    /**
+     * Set the Cluster with which this Container is associated.
+     *
+     * @param cluster the Cluster with which this Container is associated.
+     */
+    public void setCluster(Cluster cluster);
+
+
+    /**
+     * Get the delay between the invocation of the backgroundProcess method on
+     * this container and its children. Child containers will not be invoked
+     * if their delay value is not negative (which would mean they are using 
+     * their own thread). Setting this to a positive value will cause 
+     * a thread to be spawn. After waiting the specified amount of time, 
+     * the thread will invoke the executePeriodic method on this container 
+     * and all its children.
+     */
+    public int getBackgroundProcessorDelay();
+
+
+    /**
+     * Set the delay between the invocation of the execute method on this
+     * container and its children.
+     * 
+     * @param delay The delay in seconds between the invocation of 
+     *              backgroundProcess methods
+     */
+    public void setBackgroundProcessorDelay(int delay);
+
+
+    /**
+     * Return a name string (suitable for use by humans) that describes this
+     * Container.  Within the set of child containers belonging to a particular
+     * parent, Container names must be unique.
+     */
+    public String getName();
+
+
+    /**
+     * Set a name string (suitable for use by humans) that describes this
+     * Container.  Within the set of child containers belonging to a particular
+     * parent, Container names must be unique.
+     *
+     * @param name New name of this container
+     *
+     * @exception IllegalStateException if this Container has already been
+     *  added to the children of a parent Container (after which the name
+     *  may not be changed)
+     */
+    public void setName(String name);
+
+
+    /**
+     * Return the Container for which this Container is a child, if there is
+     * one.  If there is no defined parent, return <code>null</code>.
+     */
+    public Container getParent();
+
+
+    /**
+     * Set the parent Container to which this Container is being added as a
+     * child.  This Container may refuse to become attached to the specified
+     * Container by throwing an exception.
+     *
+     * @param container Container to which this Container is being added
+     *  as a child
+     *
+     * @exception IllegalArgumentException if this Container refuses to become
+     *  attached to the specified Container
+     */
+    public void setParent(Container container);
+
+
+    /**
+     * Return the parent class loader (if any) for web applications.
+     */
+    public ClassLoader getParentClassLoader();
+
+
+    /**
+     * Set the parent class loader (if any) for web applications.
+     * This call is meaningful only <strong>before</strong> a Loader has
+     * been configured, and the specified value (if non-null) should be
+     * passed as an argument to the class loader constructor.
+     *
+     * @param parent The new parent class loader
+     */
+    public void setParentClassLoader(ClassLoader parent);
+
+
+    /**
+     * Return the Realm with which this Container is associated.  If there is
+     * no associated Realm, return the Realm associated with our parent
+     * Container (if any); otherwise return <code>null</code>.
+     */
+    public Realm getRealm();
+
+
+    /**
+     * Set the Realm with which this Container is associated.
+     *
+     * @param realm The newly associated Realm
+     */
+    public void setRealm(Realm realm);
+
+
+    /**
+     * Return the Resources with which this Container is associated.  If there
+     * is no associated Resources object, return the Resources associated with
+     * our parent Container (if any); otherwise return <code>null</code>.
+     */
+    public DirContext getResources();
+
+
+    /**
+     * Set the Resources object with which this Container is associated.
+     *
+     * @param resources The newly associated Resources
+     */
+    public void setResources(DirContext resources);
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Execute a periodic task, such as reloading, etc. This method will be
+     * invoked inside the classloading context of this container. Unexpected
+     * throwables will be caught and logged.
+     */
+    public void backgroundProcess();
+
+
+    /**
+     * Add a new child Container to those associated with this Container,
+     * if supported.  Prior to adding this Container to the set of children,
+     * the child's <code>setParent()</code> method must be called, with this
+     * Container as an argument.  This method may thrown an
+     * <code>IllegalArgumentException</code> if this Container chooses not
+     * to be attached to the specified Container, in which case it is not added
+     *
+     * @param child New child Container to be added
+     *
+     * @exception IllegalArgumentException if this exception is thrown by
+     *  the <code>setParent()</code> method of the child Container
+     * @exception IllegalArgumentException if the new child does not have
+     *  a name unique from that of existing children of this Container
+     * @exception IllegalStateException if this Container does not support
+     *  child Containers
+     */
+    public void addChild(Container child);
+
+
+    /**
+     * Add a container event listener to this component.
+     *
+     * @param listener The listener to add
+     */
+    public void addContainerListener(ContainerListener listener);
+
+
+    /**
+     * Add a property change listener to this component.
+     *
+     * @param listener The listener to add
+     */
+    public void addPropertyChangeListener(PropertyChangeListener listener);
+
+
+    /**
+     * Return the child Container, associated with this Container, with
+     * the specified name (if any); otherwise, return <code>null</code>
+     *
+     * @param name Name of the child Container to be retrieved
+     */
+    public Container findChild(String name);
+
+
+    /**
+     * Return the set of children Containers associated with this Container.
+     * If this Container has no children, a zero-length array is returned.
+     */
+    public Container[] findChildren();
+
+
+    /**
+     * Return the set of container listeners associated with this Container.
+     * If this Container has no registered container listeners, a zero-length
+     * array is returned.
+     */
+    public ContainerListener[] findContainerListeners();
+
+
+    /**
+     * Process the specified Request, and generate the corresponding Response,
+     * according to the design of this particular Container.
+     *
+     * @param request Request to be processed
+     * @param response Response to be produced
+     *
+     * @exception IOException if an input/output error occurred while
+     *  processing
+     * @exception ServletException if a ServletException was thrown
+     *  while processing this request
+     */
+    public void invoke(Request request, Response response)
+        throws IOException, ServletException;
+
+
+    /**
+     * Remove an existing child Container from association with this parent
+     * Container.
+     *
+     * @param child Existing child Container to be removed
+     */
+    public void removeChild(Container child);
+
+
+    /**
+     * Remove a container event listener from this component.
+     *
+     * @param listener The listener to remove
+     */
+    public void removeContainerListener(ContainerListener listener);
+
+
+    /**
+     * Remove a property change listener from this component.
+     *
+     * @param listener The listener to remove
+     */
+    public void removePropertyChangeListener(PropertyChangeListener listener);
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ContainerEvent.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ContainerEvent.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ContainerEvent.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,111 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.util.EventObject;
+
+
+/**
+ * General event for notifying listeners of significant changes on a Container.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public final class ContainerEvent
+    extends EventObject {
+
+
+    /**
+     * The Container on which this event occurred.
+     */
+    private Container container = null;
+
+
+    /**
+     * The event data associated with this event.
+     */
+    private Object data = null;
+
+
+    /**
+     * The event type this instance represents.
+     */
+    private String type = null;
+
+
+    /**
+     * Construct a new ContainerEvent with the specified parameters.
+     *
+     * @param container Container on which this event occurred
+     * @param type Event type
+     * @param data Event data
+     */
+    public ContainerEvent(Container container, String type, Object data) {
+
+        super(container);
+        this.container = container;
+        this.type = type;
+        this.data = data;
+
+    }
+
+
+    /**
+     * Return the event data of this event.
+     */
+    public Object getData() {
+
+        return (this.data);
+
+    }
+
+
+    /**
+     * Return the Container on which this event occurred.
+     */
+    public Container getContainer() {
+
+        return (this.container);
+
+    }
+
+
+    /**
+     * Return the event type of this event.
+     */
+    public String getType() {
+
+        return (this.type);
+
+    }
+
+
+    /**
+     * Return a string representation of this event.
+     */
+    public String toString() {
+
+        return ("ContainerEvent['" + getContainer() + "','" +
+                getType() + "','" + getData() + "']");
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ContainerListener.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ContainerListener.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ContainerListener.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,43 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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;
+
+
+
+
+/**
+ * Interface defining a listener for significant Container generated events.
+ * Note that "container start" and "container stop" events are normally
+ * LifecycleEvents, not ContainerEvents.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public interface ContainerListener {
+
+
+    /**
+     * Acknowledge the occurrence of the specified event.
+     *
+     * @param event ContainerEvent that has occurred
+     */
+    public void containerEvent(ContainerEvent event);
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ContainerServlet.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ContainerServlet.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ContainerServlet.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,52 @@
+/*
+ * Copyright 1999-2001,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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;
+
+
+/**
+ * A <b>ContainerServlet</b> is a servlet that has access to Catalina
+ * internal functionality, and is loaded from the Catalina class loader
+ * instead of the web application class loader.  The property setter
+ * methods must be called by the container whenever a new instance of
+ * this servlet is put into service.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public interface ContainerServlet {
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * Return the Wrapper with which this Servlet is associated.
+     */
+    public Wrapper getWrapper();
+
+
+    /**
+     * Set the Wrapper with which this Servlet is associated.
+     *
+     * @param wrapper The new associated Wrapper
+     */
+    public void setWrapper(Wrapper wrapper);
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/Context.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/Context.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/Context.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,1046 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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 javax.servlet.ServletContext;
+
+import org.apache.tomcat.util.http.mapper.Mapper;
+
+import org.apache.catalina.deploy.ApplicationParameter;
+import org.apache.catalina.deploy.ErrorPage;
+import org.apache.catalina.deploy.FilterDef;
+import org.apache.catalina.deploy.FilterMap;
+import org.apache.catalina.deploy.LoginConfig;
+import org.apache.catalina.deploy.NamingResources;
+import org.apache.catalina.deploy.SecurityConstraint;
+import org.apache.catalina.util.CharsetMapper;
+
+
+/**
+ * A <b>Context</b> is a Container that represents a servlet context, and
+ * therefore an individual web application, in the Catalina servlet engine.
+ * It is therefore useful in almost every deployment of Catalina (even if a
+ * Connector attached to a web server (such as Apache) uses the web server's
+ * facilities to identify the appropriate Wrapper to handle this request.
+ * It also provides a convenient mechanism to use Interceptors that see
+ * every request processed by this particular web application.
+ * <p>
+ * The parent Container attached to a Context is generally a Host, but may
+ * be some other implementation, or may be omitted if it is not necessary.
+ * <p>
+ * The child containers attached to a Context are generally implementations
+ * of Wrapper (representing individual servlet definitions).
+ * <p>
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 303431 $ $Date: 2004-10-26 10:42:05 -0500 (Tue, 26 Oct 2004) $
+ */
+
+public interface Context extends Container {
+
+
+    // ----------------------------------------------------- Manifest Constants
+
+
+    /**
+     * The LifecycleEvent type sent when a context is reloaded.
+     */
+    public static final String RELOAD_EVENT = "reload";
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * Return the set of initialized application event listener objects,
+     * in the order they were specified in the web application deployment
+     * descriptor, for this application.
+     *
+     * @exception IllegalStateException if this method is called before
+     *  this application has started, or after it has been stopped
+     */
+    public Object[] getApplicationEventListeners();
+
+
+    /**
+     * Store the set of initialized application event listener objects,
+     * in the order they were specified in the web application deployment
+     * descriptor, for this application.
+     *
+     * @param listeners The set of instantiated listener objects.
+     */
+    public void setApplicationEventListeners(Object listeners[]);
+
+
+    /**
+     * Return the set of initialized application lifecycle listener objects,
+     * in the order they were specified in the web application deployment
+     * descriptor, for this application.
+     *
+     * @exception IllegalStateException if this method is called before
+     *  this application has started, or after it has been stopped
+     */
+    public Object[] getApplicationLifecycleListeners();
+
+
+    /**
+     * Store the set of initialized application lifecycle listener objects,
+     * in the order they were specified in the web application deployment
+     * descriptor, for this application.
+     *
+     * @param listeners The set of instantiated listener objects.
+     */
+    public void setApplicationLifecycleListeners(Object listeners[]);
+
+
+    /**
+     * Return the application available flag for this Context.
+     */
+    public boolean getAvailable();
+
+
+    /**
+     * Set the application available flag for this Context.
+     *
+     * @param available The new application available flag
+     */
+    public void setAvailable(boolean available);
+
+
+    /**
+     * Return the Locale to character set mapper for this Context.
+     */
+    public CharsetMapper getCharsetMapper();
+
+
+    /**
+     * Set the Locale to character set mapper for this Context.
+     *
+     * @param mapper The new mapper
+     */
+    public void setCharsetMapper(CharsetMapper mapper);
+
+
+    /**
+     * Return the path to a file to save this Context information.
+     */
+    public String getConfigFile();
+
+
+    /**
+     * Set the path to a file to save this Context information.
+     *
+     * @param configFile The path to a file to save this Context information.
+     */
+    public void setConfigFile(String configFile);
+
+
+    /**
+     * Return the "correctly configured" flag for this Context.
+     */
+    public boolean getConfigured();
+
+
+    /**
+     * Set the "correctly configured" flag for this Context.  This can be
+     * set to false by startup listeners that detect a fatal configuration
+     * error to avoid the application from being made available.
+     *
+     * @param configured The new correctly configured flag
+     */
+    public void setConfigured(boolean configured);
+
+
+    /**
+     * Return the "use cookies for session ids" flag.
+     */
+    public boolean getCookies();
+
+
+    /**
+     * Set the "use cookies for session ids" flag.
+     *
+     * @param cookies The new flag
+     */
+    public void setCookies(boolean cookies);
+
+
+    /**
+     * Return the "allow crossing servlet contexts" flag.
+     */
+    public boolean getCrossContext();
+
+
+    
+    /**
+     * Return the alternate Deployment Descriptor name.
+     */
+    public String getAltDDName();
+    
+    
+    /**
+     * Set an alternate Deployment Descriptor name.
+     */
+    public void setAltDDName(String altDDName) ;
+    
+    
+    /**
+     * Set the "allow crossing servlet contexts" flag.
+     *
+     * @param crossContext The new cross contexts flag
+     */
+    public void setCrossContext(boolean crossContext);
+
+
+    /**
+     * Return the display name of this web application.
+     */
+    public String getDisplayName();
+
+
+    /**
+     * Set the display name of this web application.
+     *
+     * @param displayName The new display name
+     */
+    public void setDisplayName(String displayName);
+
+
+    /**
+     * Return the distributable flag for this web application.
+     */
+    public boolean getDistributable();
+
+
+    /**
+     * Set the distributable flag for this web application.
+     *
+     * @param distributable The new distributable flag
+     */
+    public void setDistributable(boolean distributable);
+
+
+    /**
+     * Return the document root for this Context.  This can be an absolute
+     * pathname, a relative pathname, or a URL.
+     */
+    public String getDocBase();
+
+
+    /**
+     * Set the document root for this Context.  This can be an absolute
+     * pathname, a relative pathname, or a URL.
+     *
+     * @param docBase The new document root
+     */
+    public void setDocBase(String docBase);
+
+
+    /**
+     * Return the URL encoded context path, using UTF-8.
+     */
+    public String getEncodedPath();
+
+
+    /**
+     * Return the login configuration descriptor for this web application.
+     */
+    public LoginConfig getLoginConfig();
+
+
+    /**
+     * Set the login configuration descriptor for this web application.
+     *
+     * @param config The new login configuration
+     */
+    public void setLoginConfig(LoginConfig config);
+
+
+    /**
+     * Get the request dispatcher mapper.
+     */
+    public Mapper getMapper();
+
+
+    /**
+     * Return the naming resources associated with this web application.
+     */
+    public NamingResources getNamingResources();
+
+
+    /**
+     * Set the naming resources for this web application.
+     *
+     * @param namingResources The new naming resources
+     */
+    public void setNamingResources(NamingResources namingResources);
+
+
+    /**
+     * Return the context path for this web application.
+     */
+    public String getPath();
+
+
+    /**
+     * Set the context path for this web application.
+     *
+     * @param path The new context path
+     */
+    public void setPath(String path);
+
+
+    /**
+     * Return the public identifier of the deployment descriptor DTD that is
+     * currently being parsed.
+     */
+    public String getPublicId();
+
+
+    /**
+     * Set the public identifier of the deployment descriptor DTD that is
+     * currently being parsed.
+     *
+     * @param publicId The public identifier
+     */
+    public void setPublicId(String publicId);
+
+
+    /**
+     * Return the reloadable flag for this web application.
+     */
+    public boolean getReloadable();
+
+
+    /**
+     * Set the reloadable flag for this web application.
+     *
+     * @param reloadable The new reloadable flag
+     */
+    public void setReloadable(boolean reloadable);
+
+
+    /**
+     * Return the override flag for this web application.
+     */
+    public boolean getOverride();
+
+
+    /**
+     * Set the override flag for this web application.
+     *
+     * @param override The new override flag
+     */
+    public void setOverride(boolean override);
+
+
+    /**
+     * Return the privileged flag for this web application.
+     */
+    public boolean getPrivileged();
+
+
+    /**
+     * Set the privileged flag for this web application.
+     *
+     * @param privileged The new privileged flag
+     */
+    public void setPrivileged(boolean privileged);
+
+
+    /**
+     * Return the servlet context for which this Context is a facade.
+     */
+    public ServletContext getServletContext();
+
+
+    /**
+     * Return the default session timeout (in minutes) for this
+     * web application.
+     */
+    public int getSessionTimeout();
+
+
+    /**
+     * Set the default session timeout (in minutes) for this
+     * web application.
+     *
+     * @param timeout The new default session timeout
+     */
+    public void setSessionTimeout(int timeout);
+
+
+    /**
+     * Return the value of the swallowOutput flag.
+     */
+    public boolean getSwallowOutput();
+
+
+    /**
+     * Set the value of the swallowOutput flag. If set to true, the system.out
+     * and system.err will be redirected to the logger during a servlet
+     * execution.
+     *
+     * @param swallowOutput The new value
+     */
+    public void setSwallowOutput(boolean swallowOutput);
+
+
+    /**
+     * Return the Java class name of the Wrapper implementation used
+     * for servlets registered in this Context.
+     */
+    public String getWrapperClass();
+
+
+    /**
+     * Set the Java class name of the Wrapper implementation used
+     * for servlets registered in this Context.
+     *
+     * @param wrapperClass The new wrapper class
+     */
+    public void setWrapperClass(String wrapperClass);
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Add a new Listener class name to the set of Listeners
+     * configured for this application.
+     *
+     * @param listener Java class name of a listener class
+     */
+    public void addApplicationListener(String listener);
+
+
+    /**
+     * Add a new application parameter for this application.
+     *
+     * @param parameter The new application parameter
+     */
+    public void addApplicationParameter(ApplicationParameter parameter);
+
+
+    /**
+     * Add a security constraint to the set for this web application.
+     */
+    public void addConstraint(SecurityConstraint constraint);
+
+
+    /**
+     * Add an error page for the specified error or Java exception.
+     *
+     * @param errorPage The error page definition to be added
+     */
+    public void addErrorPage(ErrorPage errorPage);
+
+
+    /**
+     * Add a filter definition to this Context.
+     *
+     * @param filterDef The filter definition to be added
+     */
+    public void addFilterDef(FilterDef filterDef);
+
+
+    /**
+     * Add a filter mapping to this Context.
+     *
+     * @param filterMap The filter mapping to be added
+     */
+    public void addFilterMap(FilterMap filterMap);
+
+
+    /**
+     * Add the classname of an InstanceListener to be added to each
+     * Wrapper appended to this Context.
+     *
+     * @param listener Java class name of an InstanceListener class
+     */
+    public void addInstanceListener(String listener);
+
+
+    /**
+     * Add the given URL pattern as a jsp-property-group.  This maps
+     * resources that match the given pattern so they will be passed
+     * to the JSP container.  Though there are other elements in the
+     * property group, we only care about the URL pattern here.  The
+     * JSP container will parse the rest.
+     *
+     * @param pattern URL pattern to be mapped 
+     */
+    public void addJspMapping(String pattern);
+
+
+    /**
+     * Add a Locale Encoding Mapping (see Sec 5.4 of Servlet spec 2.4)
+     *
+     * @param locale locale to map an encoding for
+     * @param encoding encoding to be used for a give locale
+     */
+    public void addLocaleEncodingMappingParameter(String locale, String encoding);
+
+
+    /**
+     * Add a new MIME mapping, replacing any existing mapping for
+     * the specified extension.
+     *
+     * @param extension Filename extension being mapped
+     * @param mimeType Corresponding MIME type
+     */
+    public void addMimeMapping(String extension, String mimeType);
+
+
+    /**
+     * Add a new context initialization parameter, replacing any existing
+     * value for the specified name.
+     *
+     * @param name Name of the new parameter
+     * @param value Value of the new  parameter
+     */
+    public void addParameter(String name, String value);
+
+
+    /**
+     * Add a security role reference for this web application.
+     *
+     * @param role Security role used in the application
+     * @param link Actual security role to check for
+     */
+    public void addRoleMapping(String role, String link);
+
+
+    /**
+     * Add a new security role for this web application.
+     *
+     * @param role New security role
+     */
+    public void addSecurityRole(String role);
+
+
+    /**
+     * Add a new servlet mapping, replacing any existing mapping for
+     * the specified pattern.
+     *
+     * @param pattern URL pattern to be mapped
+     * @param name Name of the corresponding servlet to execute
+     */
+    public void addServletMapping(String pattern, String name);
+
+
+    /**
+     * Add a JSP tag library for the specified URI.
+     *
+     * @param uri URI, relative to the web.xml file, of this tag library
+     * @param location Location of the tag library descriptor
+     */
+    public void addTaglib(String uri, String location);
+
+    
+    /**
+     * Add a resource which will be watched for reloading by the host auto
+     * deployer. Note: this will not be used in embedded mode.
+     * 
+     * @param name Path to the resource, relative to docBase
+     */
+    public void addWatchedResource(String name);
+    
+
+    /**
+     * Add a new welcome file to the set recognized by this Context.
+     *
+     * @param name New welcome file name
+     */
+    public void addWelcomeFile(String name);
+
+
+    /**
+     * Add the classname of a LifecycleListener to be added to each
+     * Wrapper appended to this Context.
+     *
+     * @param listener Java class name of a LifecycleListener class
+     */
+    public void addWrapperLifecycle(String listener);
+
+
+    /**
+     * Add the classname of a ContainerListener to be added to each
+     * Wrapper appended to this Context.
+     *
+     * @param listener Java class name of a ContainerListener class
+     */
+    public void addWrapperListener(String listener);
+
+
+    /**
+     * Factory method to create and return a new Wrapper instance, of
+     * the Java implementation class appropriate for this Context
+     * implementation.  The constructor of the instantiated Wrapper
+     * will have been called, but no properties will have been set.
+     */
+    public Wrapper createWrapper();
+
+
+    /**
+     * Return the set of application listener class names configured
+     * for this application.
+     */
+    public String[] findApplicationListeners();
+
+
+    /**
+     * Return the set of application parameters for this application.
+     */
+    public ApplicationParameter[] findApplicationParameters();
+
+
+    /**
+     * Return the set of security constraints for this web application.
+     * If there are none, a zero-length array is returned.
+     */
+    public SecurityConstraint[] findConstraints();
+
+
+    /**
+     * Return the error page entry for the specified HTTP error code,
+     * if any; otherwise return <code>null</code>.
+     *
+     * @param errorCode Error code to look up
+     */
+    public ErrorPage findErrorPage(int errorCode);
+
+
+    /**
+     * Return the error page entry for the specified Java exception type,
+     * if any; otherwise return <code>null</code>.
+     *
+     * @param exceptionType Exception type to look up
+     */
+    public ErrorPage findErrorPage(String exceptionType);
+
+
+
+    /**
+     * Return the set of defined error pages for all specified error codes
+     * and exception types.
+     */
+    public ErrorPage[] findErrorPages();
+
+
+    /**
+     * Return the filter definition for the specified filter name, if any;
+     * otherwise return <code>null</code>.
+     *
+     * @param filterName Filter name to look up
+     */
+    public FilterDef findFilterDef(String filterName);
+
+
+    /**
+     * Return the set of defined filters for this Context.
+     */
+    public FilterDef[] findFilterDefs();
+
+
+    /**
+     * Return the set of filter mappings for this Context.
+     */
+    public FilterMap[] findFilterMaps();
+
+
+    /**
+     * Return the set of InstanceListener classes that will be added to
+     * newly created Wrappers automatically.
+     */
+    public String[] findInstanceListeners();
+
+
+    /**
+     * Return the MIME type to which the specified extension is mapped,
+     * if any; otherwise return <code>null</code>.
+     *
+     * @param extension Extension to map to a MIME type
+     */
+    public String findMimeMapping(String extension);
+
+
+    /**
+     * Return the extensions for which MIME mappings are defined.  If there
+     * are none, a zero-length array is returned.
+     */
+    public String[] findMimeMappings();
+
+
+    /**
+     * Return the value for the specified context initialization
+     * parameter name, if any; otherwise return <code>null</code>.
+     *
+     * @param name Name of the parameter to return
+     */
+    public String findParameter(String name);
+
+
+    /**
+     * Return the names of all defined context initialization parameters
+     * for this Context.  If no parameters are defined, a zero-length
+     * array is returned.
+     */
+    public String[] findParameters();
+
+
+    /**
+     * For the given security role (as used by an application), return the
+     * corresponding role name (as defined by the underlying Realm) if there
+     * is one.  Otherwise, return the specified role unchanged.
+     *
+     * @param role Security role to map
+     */
+    public String findRoleMapping(String role);
+
+
+    /**
+     * Return <code>true</code> if the specified security role is defined
+     * for this application; otherwise return <code>false</code>.
+     *
+     * @param role Security role to verify
+     */
+    public boolean findSecurityRole(String role);
+
+
+    /**
+     * Return the security roles defined for this application.  If none
+     * have been defined, a zero-length array is returned.
+     */
+    public String[] findSecurityRoles();
+
+
+    /**
+     * Return the servlet name mapped by the specified pattern (if any);
+     * otherwise return <code>null</code>.
+     *
+     * @param pattern Pattern for which a mapping is requested
+     */
+    public String findServletMapping(String pattern);
+
+
+    /**
+     * Return the patterns of all defined servlet mappings for this
+     * Context.  If no mappings are defined, a zero-length array is returned.
+     */
+    public String[] findServletMappings();
+
+
+    /**
+     * Return the context-relative URI of the error page for the specified
+     * HTTP status code, if any; otherwise return <code>null</code>.
+     *
+     * @param status HTTP status code to look up
+     */
+    public String findStatusPage(int status);
+
+
+    /**
+     * Return the set of HTTP status codes for which error pages have
+     * been specified.  If none are specified, a zero-length array
+     * is returned.
+     */
+    public int[] findStatusPages();
+
+
+    /**
+     * Return the tag library descriptor location for the specified taglib
+     * URI, if any; otherwise, return <code>null</code>.
+     *
+     * @param uri URI, relative to the web.xml file
+     */
+    public String findTaglib(String uri);
+
+
+    /**
+     * Return the URIs of all tag libraries for which a tag library
+     * descriptor location has been specified.  If none are specified,
+     * a zero-length array is returned.
+     */
+    public String[] findTaglibs();
+
+
+    /**
+     * Return the set of watched resources for this Context. If none are 
+     * defined, a zero length array will be returned.
+     */
+    public String[] findWatchedResources();
+    
+
+    /**
+     * Return <code>true</code> if the specified welcome file is defined
+     * for this Context; otherwise return <code>false</code>.
+     *
+     * @param name Welcome file to verify
+     */
+    public boolean findWelcomeFile(String name);
+
+    
+    /**
+     * Return the set of welcome files defined for this Context.  If none are
+     * defined, a zero-length array is returned.
+     */
+    public String[] findWelcomeFiles();
+
+
+    /**
+     * Return the set of LifecycleListener classes that will be added to
+     * newly created Wrappers automatically.
+     */
+    public String[] findWrapperLifecycles();
+
+
+    /**
+     * Return the set of ContainerListener classes that will be added to
+     * newly created Wrappers automatically.
+     */
+    public String[] findWrapperListeners();
+
+
+    /**
+     * Reload this web application, if reloading is supported.
+     *
+     * @exception IllegalStateException if the <code>reloadable</code>
+     *  property is set to <code>false</code>.
+     */
+    public void reload();
+
+
+    /**
+     * Remove the specified application listener class from the set of
+     * listeners for this application.
+     *
+     * @param listener Java class name of the listener to be removed
+     */
+    public void removeApplicationListener(String listener);
+
+
+    /**
+     * Remove the application parameter with the specified name from
+     * the set for this application.
+     *
+     * @param name Name of the application parameter to remove
+     */
+    public void removeApplicationParameter(String name);
+
+
+    /**
+     * Remove the specified security constraint from this web application.
+     *
+     * @param constraint Constraint to be removed
+     */
+    public void removeConstraint(SecurityConstraint constraint);
+
+
+    /**
+     * Remove the error page for the specified error code or
+     * Java language exception, if it exists; otherwise, no action is taken.
+     *
+     * @param errorPage The error page definition to be removed
+     */
+    public void removeErrorPage(ErrorPage errorPage);
+
+
+    /**
+     * Remove the specified filter definition from this Context, if it exists;
+     * otherwise, no action is taken.
+     *
+     * @param filterDef Filter definition to be removed
+     */
+    public void removeFilterDef(FilterDef filterDef);
+
+
+    /**
+     * Remove a filter mapping from this Context.
+     *
+     * @param filterMap The filter mapping to be removed
+     */
+    public void removeFilterMap(FilterMap filterMap);
+
+
+    /**
+     * Remove a class name from the set of InstanceListener classes that
+     * will be added to newly created Wrappers.
+     *
+     * @param listener Class name of an InstanceListener class to be removed
+     */
+    public void removeInstanceListener(String listener);
+
+
+    /**
+     * Remove the MIME mapping for the specified extension, if it exists;
+     * otherwise, no action is taken.
+     *
+     * @param extension Extension to remove the mapping for
+     */
+    public void removeMimeMapping(String extension);
+
+
+    /**
+     * Remove the context initialization parameter with the specified
+     * name, if it exists; otherwise, no action is taken.
+     *
+     * @param name Name of the parameter to remove
+     */
+    public void removeParameter(String name);
+
+
+    /**
+     * Remove any security role reference for the specified name
+     *
+     * @param role Security role (as used in the application) to remove
+     */
+    public void removeRoleMapping(String role);
+
+
+    /**
+     * Remove any security role with the specified name.
+     *
+     * @param role Security role to remove
+     */
+    public void removeSecurityRole(String role);
+
+
+    /**
+     * Remove any servlet mapping for the specified pattern, if it exists;
+     * otherwise, no action is taken.
+     *
+     * @param pattern URL pattern of the mapping to remove
+     */
+    public void removeServletMapping(String pattern);
+
+
+    /**
+     * Remove the tag library location forthe specified tag library URI.
+     *
+     * @param uri URI, relative to the web.xml file
+     */
+    public void removeTaglib(String uri);
+
+    
+    /**
+     * Remove the specified watched resource name from the list associated
+     * with this Context.
+     * 
+     * @param name Name of the watched resource to be removed
+     */
+    public void removeWatchedResource(String name);
+    
+
+    /**
+     * Remove the specified welcome file name from the list recognized
+     * by this Context.
+     *
+     * @param name Name of the welcome file to be removed
+     */
+    public void removeWelcomeFile(String name);
+
+
+    /**
+     * Remove a class name from the set of LifecycleListener classes that
+     * will be added to newly created Wrappers.
+     *
+     * @param listener Class name of a LifecycleListener class to be removed
+     */
+    public void removeWrapperLifecycle(String listener);
+
+
+    /**
+     * Remove a class name from the set of ContainerListener classes that
+     * will be added to newly created Wrappers.
+     *
+     * @param listener Class name of a ContainerListener class to be removed
+     */
+    public void removeWrapperListener(String listener);
+
+
+    /**
+     * Get the server.xml <context> attribute's xmlNamespaceAware.
+     * @return true if namespace awarenes is enabled.
+     *
+     */
+    public boolean getXmlNamespaceAware();
+
+
+    /**
+     * Get the server.xml <context> attribute's xmlValidation.
+     * @return true if validation is enabled.
+     *
+     */
+    public boolean getXmlValidation();
+
+
+    /**
+     * Set the validation feature of the XML parser used when
+     * parsing xml instances.
+     * @param xmlValidation true to enable xml instance validation
+     */
+    public void setXmlValidation(boolean xmlValidation);
+
+
+   /**
+     * Set the namespace aware feature of the XML parser used when
+     * parsing xml instances.
+     * @param xmlNamespaceAware true to enable namespace awareness
+     */
+    public void setXmlNamespaceAware(boolean xmlNamespaceAware);
+    /**
+     * Get the server.xml <context> attribute's xmlValidation.
+     * @return true if validation is enabled.
+     */
+     
+
+    /**
+     * Set the validation feature of the XML parser used when
+     * parsing tlds files. 
+     * @param tldValidation true to enable xml instance validation
+     */
+    public void setTldValidation(boolean tldValidation);
+
+
+    /**
+     * Get the server.xml <context> attribute's webXmlValidation.
+     * @return true if validation is enabled.
+     *
+     */
+    public boolean getTldValidation();
+
+
+    /**
+     * Get the server.xml <host> attribute's xmlNamespaceAware.
+     * @return true if namespace awarenes is enabled.
+     */
+    public boolean getTldNamespaceAware();
+
+
+    /**
+     * Set the namespace aware feature of the XML parser used when
+     * parsing xml instances.
+     * @param tldNamespaceAware true to enable namespace awareness
+     */
+    public void setTldNamespaceAware(boolean tldNamespaceAware);
+
+
+}
+

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/Engine.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/Engine.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/Engine.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,95 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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;
+
+/**
+ * An <b>Engine</b> is a Container that represents the entire Catalina servlet
+ * engine.  It is useful in the following types of scenarios:
+ * <ul>
+ * <li>You wish to use Interceptors that see every single request processed
+ *     by the entire engine.
+ * <li>You wish to run Catalina in with a standalone HTTP connector, but still
+ *     want support for multiple virtual hosts.
+ * </ul>
+ * In general, you would not use an Engine when deploying Catalina connected
+ * to a web server (such as Apache), because the Connector will have
+ * utilized the web server's facilities to determine which Context (or
+ * perhaps even which Wrapper) should be utilized to process this request.
+ * <p>
+ * The child containers attached to an Engine are generally implementations
+ * of Host (representing a virtual host) or Context (representing individual
+ * an individual servlet context), depending upon the Engine implementation.
+ * <p>
+ * If used, an Engine is always the top level Container in a Catalina
+ * hierarchy. Therefore, the implementation's <code>setParent()</code> method
+ * should throw <code>IllegalArgumentException</code>.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 303092 $ $Date: 2004-08-16 04:31:09 -0500 (Mon, 16 Aug 2004) $
+ */
+
+public interface Engine extends Container {
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * Return the default hostname for this Engine.
+     */
+    public String getDefaultHost();
+
+
+    /**
+     * Set the default hostname for this Engine.
+     *
+     * @param defaultHost The new default host
+     */
+    public void setDefaultHost(String defaultHost);
+
+
+    /**
+     * Retrieve the JvmRouteId for this engine.
+     */
+    public String getJvmRoute();
+
+
+    /**
+     * Set the JvmRouteId for this engine.
+     *
+     * @param jvmRouteId the (new) JVM Route ID. Each Engine within a cluster
+     *        must have a unique JVM Route ID.
+     */
+    public void setJvmRoute(String jvmRouteId);
+
+
+    /**
+     * Return the <code>Service</code> with which we are associated (if any).
+     */
+    public Service getService();
+
+
+    /**
+     * Set the <code>Service</code> with which we are associated (if any).
+     *
+     * @param service The service that owns this Engine
+     */
+    public void setService(Service service);
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/Globals.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/Globals.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/Globals.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,324 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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;
+
+
+/**
+ * Global constants that are applicable to multiple packages within Catalina.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 303495 $ $Date: 2004-11-19 00:07:56 -0600 (Fri, 19 Nov 2004) $
+ */
+
+public final class Globals {
+
+    /**
+     * The servlet context attribute under which we store the alternate
+     * deployment descriptor for this web application 
+     */
+    public static final String ALT_DD_ATTR = 
+        "org.apache.catalina.deploy.alt_dd";
+
+    /**
+     * The request attribute under which we store the array of X509Certificate
+     * objects representing the certificate chain presented by our client,
+     * if any.
+     */
+    public static final String CERTIFICATES_ATTR =
+        "javax.servlet.request.X509Certificate";
+
+    /**
+     * The request attribute under which we store the name of the cipher suite
+     * being used on an SSL connection (as an object of type
+     * java.lang.String).
+     */
+    public static final String CIPHER_SUITE_ATTR =
+        "javax.servlet.request.cipher_suite";
+
+
+    /**
+     * The servlet context attribute under which we store the class loader
+     * used for loading servlets (as an object of type java.lang.ClassLoader).
+     */
+    public static final String CLASS_LOADER_ATTR =
+        "org.apache.catalina.classloader";
+
+    /**
+     * Request dispatcher state.
+     */
+    public static final String DISPATCHER_TYPE_ATTR = 
+        "org.apache.catalina.core.DISPATCHER_TYPE";
+
+    /**
+     * Request dispatcher path.
+     */
+    public static final String DISPATCHER_REQUEST_PATH_ATTR = 
+        "org.apache.catalina.core.DISPATCHER_REQUEST_PATH";
+
+    /**
+     * The JNDI directory context which is associated with the context. This
+     * context can be used to manipulate static files.
+     */
+    public static final String RESOURCES_ATTR =
+        "org.apache.catalina.resources";
+
+
+    /**
+     * The servlet context attribute under which we store the class path
+     * for our application class loader (as an object of type String),
+     * delimited with the appropriate path delimiter for this platform.
+     */
+    public static final String CLASS_PATH_ATTR =
+        "org.apache.catalina.jsp_classpath";
+
+
+    /**
+     * The request attribute under which we forward a Java exception
+     * (as an object of type Throwable) to an error page.
+     */
+    public static final String EXCEPTION_ATTR =
+        "javax.servlet.error.exception";
+
+
+    /**
+     * The request attribute under which we forward the request URI
+     * (as an object of type String) of the page on which an error occurred.
+     */
+    public static final String EXCEPTION_PAGE_ATTR =
+        "javax.servlet.error.request_uri";
+
+
+    /**
+     * The request attribute under which we forward a Java exception type
+     * (as an object of type Class) to an error page.
+     */
+    public static final String EXCEPTION_TYPE_ATTR =
+        "javax.servlet.error.exception_type";
+
+
+    /**
+     * The request attribute under which we forward an HTTP status message
+     * (as an object of type STring) to an error page.
+     */
+    public static final String ERROR_MESSAGE_ATTR =
+        "javax.servlet.error.message";
+
+
+    /**
+     * The request attribute under which the Invoker servlet will store
+     * the invoking servlet path, if it was used to execute a servlet
+     * indirectly instead of through a servlet mapping.
+     */
+    public static final String INVOKED_ATTR =
+        "org.apache.catalina.INVOKED";
+
+
+    /**
+     * The request attribute under which we expose the value of the
+     * <code>&lt;jsp-file&gt;</code> value associated with this servlet,
+     * if any.
+     */
+    public static final String JSP_FILE_ATTR =
+        "org.apache.catalina.jsp_file";
+
+
+    /**
+     * The request attribute under which we store the key size being used for
+     * this SSL connection (as an object of type java.lang.Integer).
+     */
+    public static final String KEY_SIZE_ATTR =
+        "javax.servlet.request.key_size";
+
+    /**
+     * The request attribute under which we store the session id being used
+     * for this SSL connection (as an object of type java.lang.String).
+     */
+    public static final String SSL_SESSION_ID_ATTR =
+        "javax.servlet.request.ssl_session";
+
+
+    /**
+     * The servlet context attribute under which the managed bean Registry
+     * will be stored for privileged contexts (if enabled).
+     */
+    public static final String MBEAN_REGISTRY_ATTR =
+        "org.apache.catalina.Registry";
+
+
+    /**
+     * The servlet context attribute under which the MBeanServer will be stored
+     * for privileged contexts (if enabled).
+     */
+    public static final String MBEAN_SERVER_ATTR =
+        "org.apache.catalina.MBeanServer";
+
+
+    /**
+     * The request attribute under which we store the servlet name on a
+     * named dispatcher request.
+     */
+    public static final String NAMED_DISPATCHER_ATTR =
+        "org.apache.catalina.NAMED";
+
+
+    /**
+     * The request attribute under which the request URI of the included
+     * servlet is stored on an included dispatcher request.
+     */
+    public static final String INCLUDE_REQUEST_URI_ATTR =
+        "javax.servlet.include.request_uri";
+
+
+    /**
+     * The request attribute under which the context path of the included
+     * servlet is stored on an included dispatcher request.
+     */
+    public static final String INCLUDE_CONTEXT_PATH_ATTR =
+        "javax.servlet.include.context_path";
+
+
+    /**
+     * The request attribute under which the path info of the included
+     * servlet is stored on an included dispatcher request.
+     */
+    public static final String INCLUDE_PATH_INFO_ATTR =
+        "javax.servlet.include.path_info";
+
+
+    /**
+     * The request attribute under which the servlet path of the included
+     * servlet is stored on an included dispatcher request.
+     */
+    public static final String INCLUDE_SERVLET_PATH_ATTR =
+        "javax.servlet.include.servlet_path";
+
+
+    /**
+     * The request attribute under which the query string of the included
+     * servlet is stored on an included dispatcher request.
+     */
+    public static final String INCLUDE_QUERY_STRING_ATTR =
+        "javax.servlet.include.query_string";
+
+
+    /**
+     * The request attribute under which the original request URI is stored
+     * on an forwarded dispatcher request.
+     */
+    public static final String FORWARD_REQUEST_URI_ATTR =
+        "javax.servlet.forward.request_uri";
+    
+    
+    /**
+     * The request attribute under which the original context path is stored
+     * on an forwarded dispatcher request.
+     */
+    public static final String FORWARD_CONTEXT_PATH_ATTR =
+        "javax.servlet.forward.context_path";
+
+
+    /**
+     * The request attribute under which the original path info is stored
+     * on an forwarded dispatcher request.
+     */
+    public static final String FORWARD_PATH_INFO_ATTR =
+        "javax.servlet.forward.path_info";
+
+
+    /**
+     * The request attribute under which the original servlet path is stored
+     * on an forwarded dispatcher request.
+     */
+    public static final String FORWARD_SERVLET_PATH_ATTR =
+        "javax.servlet.forward.servlet_path";
+
+
+    /**
+     * The request attribute under which the original query string is stored
+     * on an forwarded dispatcher request.
+     */
+    public static final String FORWARD_QUERY_STRING_ATTR =
+        "javax.servlet.forward.query_string";
+
+
+    /**
+     * The request attribute under which we forward a servlet name to
+     * an error page.
+     */
+    public static final String SERVLET_NAME_ATTR =
+        "javax.servlet.error.servlet_name";
+
+    
+    /**
+     * The name of the cookie used to pass the session identifier back
+     * and forth with the client.
+     */
+    public static final String SESSION_COOKIE_NAME = "JSESSIONID";
+
+
+    /**
+     * The name of the path parameter used to pass the session identifier
+     * back and forth with the client.
+     */
+    public static final String SESSION_PARAMETER_NAME = "jsessionid";
+
+
+    /**
+     * The servlet context attribute under which we store a flag used
+     * to mark this request as having been processed by the SSIServlet.
+     * We do this because of the pathInfo mangling happening when using
+     * the CGIServlet in conjunction with the SSI servlet. (value stored
+     * as an object of type String)
+     */
+     public static final String SSI_FLAG_ATTR =
+         "org.apache.catalina.ssi.SSIServlet";
+
+
+    /**
+     * The request attribute under which we forward an HTTP status code
+     * (as an object of type Integer) to an error page.
+     */
+    public static final String STATUS_CODE_ATTR =
+        "javax.servlet.error.status_code";
+
+
+    /**
+     * The subject under which the AccessControlContext is running.
+     */
+    public static final String SUBJECT_ATTR =
+        "javax.security.auth.subject";
+
+    
+    /**
+     * The servlet context attribute under which we record the set of
+     * welcome files (as an object of type String[]) for this application.
+     */
+    public static final String WELCOME_FILES_ATTR =
+        "org.apache.catalina.WELCOME_FILES";
+
+
+    /**
+     * The servlet context attribute under which we store a temporary
+     * working directory (as an object of type File) for use by servlets
+     * within this web application.
+     */
+    public static final String WORK_DIR_ATTR =
+        "javax.servlet.context.tempdir";
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/Group.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/Group.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/Group.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,122 @@
+/*
+ * Copyright 2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.security.Principal;
+import java.util.Iterator;
+
+
+/**
+ * <p>Abstract representation of a group of {@link User}s in a
+ * {@link UserDatabase}.  Each user that is a member of this group
+ * inherits the {@link Role}s assigned to the group.</p>
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ * @since 4.1
+ */
+
+public interface Group extends Principal {
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * Return the description of this group.
+     */
+    public String getDescription();
+
+
+    /**
+     * Set the description of this group.
+     *
+     * @param description The new description
+     */
+    public void setDescription(String description);
+
+
+    /**
+     * Return the group name of this group, which must be unique
+     * within the scope of a {@link UserDatabase}.
+     */
+    public String getGroupname();
+
+
+    /**
+     * Set the group name of this group, which must be unique
+     * within the scope of a {@link UserDatabase}.
+     *
+     * @param groupname The new group name
+     */
+    public void setGroupname(String groupname);
+
+
+    /**
+     * Return the set of {@link Role}s assigned specifically to this group.
+     */
+    public Iterator getRoles();
+
+
+    /**
+     * Return the {@link UserDatabase} within which this Group is defined.
+     */
+    public UserDatabase getUserDatabase();
+
+
+    /**
+     * Return the set of {@link User}s that are members of this group.
+     */
+    public Iterator getUsers();
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Add a new {@link Role} to those assigned specifically to this group.
+     *
+     * @param role The new role
+     */
+    public void addRole(Role role);
+
+
+    /**
+     * Is this group specifically assigned the specified {@link Role}?
+     *
+     * @param role The role to check
+     */
+    public boolean isInRole(Role role);
+
+
+    /**
+     * Remove a {@link Role} from those assigned to this group.
+     *
+     * @param role The old role
+     */
+    public void removeRole(Role role);
+
+
+    /**
+     * Remove all {@link Role}s from those assigned to this group.
+     */
+    public void removeRoles();
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/Host.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/Host.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/Host.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,218 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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;
+
+
+
+/**
+ * A <b>Host</b> is a Container that represents a virtual host in the
+ * Catalina servlet engine.  It is useful in the following types of scenarios:
+ * <ul>
+ * <li>You wish to use Interceptors that see every single request processed
+ *     by this particular virtual host.
+ * <li>You wish to run Catalina in with a standalone HTTP connector, but still
+ *     want support for multiple virtual hosts.
+ * </ul>
+ * In general, you would not use a Host when deploying Catalina connected
+ * to a web server (such as Apache), because the Connector will have
+ * utilized the web server's facilities to determine which Context (or
+ * perhaps even which Wrapper) should be utilized to process this request.
+ * <p>
+ * The parent Container attached to a Host is generally an Engine, but may
+ * be some other implementation, or may be omitted if it is not necessary.
+ * <p>
+ * The child containers attached to a Host are generally implementations
+ * of Context (representing an individual servlet context).
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 303092 $ $Date: 2004-08-16 04:31:09 -0500 (Mon, 16 Aug 2004) $
+ */
+
+public interface Host extends Container {
+
+
+    // ----------------------------------------------------- Manifest Constants
+
+
+    /**
+     * The ContainerEvent event type sent when a new alias is added
+     * by <code>addAlias()</code>.
+     */
+    public static final String ADD_ALIAS_EVENT = "addAlias";
+
+
+    /**
+     * The ContainerEvent event type sent when an old alias is removed
+     * by <code>removeAlias()</code>.
+     */
+    public static final String REMOVE_ALIAS_EVENT = "removeAlias";
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * Return the application root for this Host.  This can be an absolute
+     * pathname, a relative pathname, or a URL.
+     */
+    public String getAppBase();
+
+
+    /**
+     * Set the application root for this Host.  This can be an absolute
+     * pathname, a relative pathname, or a URL.
+     *
+     * @param appBase The new application root
+     */
+    public void setAppBase(String appBase);
+
+
+    /**
+     * Return the value of the auto deploy flag.  If true, it indicates that 
+     * this host's child webapps should be discovred and automatically 
+     * deployed dynamically.
+     */
+    public boolean getAutoDeploy();
+
+
+    /**
+     * Set the auto deploy flag value for this host.
+     * 
+     * @param autoDeploy The new auto deploy flag
+     */
+    public void setAutoDeploy(boolean autoDeploy);
+
+
+    /**
+     * Return the Java class name of the context configuration class
+     * for new web applications.
+     */
+    public String getConfigClass();
+
+    
+    /**
+     * Set the Java class name of the context configuration class
+     * for new web applications.
+     *
+     * @param configClass The new context configuration class
+     */
+    public void setConfigClass(String configClass);
+
+        
+    /**
+     * Return the value of the deploy on startup flag.  If true, it indicates 
+     * that this host's child webapps should be discovred and automatically 
+     * deployed.
+     */
+    public boolean getDeployOnStartup();
+
+
+    /**
+     * Set the deploy on startup flag value for this host.
+     * 
+     * @param deployOnStartup The new deploy on startup flag
+     */
+    public void setDeployOnStartup(boolean deployOnStartup);
+
+
+    /**
+     * Return the canonical, fully qualified, name of the virtual host
+     * this Container represents.
+     */
+    public String getName();
+
+
+    /**
+     * Set the canonical, fully qualified, name of the virtual host
+     * this Container represents.
+     *
+     * @param name Virtual host name
+     *
+     * @exception IllegalArgumentException if name is null
+     */
+    public void setName(String name);
+
+
+    /**
+     * Get the server.xml <host> attribute's xmlNamespaceAware.
+     * @return true if namespace awarenes is enabled.
+     *
+     */
+    public boolean getXmlNamespaceAware();
+
+
+    /**
+     * Get the server.xml <host> attribute's xmlValidation.
+     * @return true if validation is enabled.
+     *
+     */
+    public boolean getXmlValidation();
+
+
+    /**
+     * Set the validation feature of the XML parser used when
+     * parsing xml instances.
+     * @param xmlValidation true to enable xml instance validation
+     */
+    public void setXmlValidation(boolean xmlValidation);
+
+
+   /**
+     * Set the namespace aware feature of the XML parser used when
+     * parsing xml instances.
+     * @param xmlNamespaceAware true to enable namespace awareness
+     */
+    public void setXmlNamespaceAware(boolean xmlNamespaceAware);
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Add an alias name that should be mapped to this same Host.
+     *
+     * @param alias The alias to be added
+     */
+    public void addAlias(String alias);
+
+
+    /**
+     * Return the set of alias names for this Host.  If none are defined,
+     * a zero length array is returned.
+     */
+    public String[] findAliases();
+
+
+    /**
+     * Return the Context that would be used to process the specified
+     * host-relative request URI, if any; otherwise return <code>null</code>.
+     *
+     * @param uri Request URI to be mapped
+     */
+    public Context map(String uri);
+
+
+    /**
+     * Remove the specified alias name from the aliases for this Host.
+     *
+     * @param alias Alias name to be removed
+     */
+    public void removeAlias(String alias);
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/InstanceEvent.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/InstanceEvent.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/InstanceEvent.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,448 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.util.EventObject;
+import javax.servlet.Filter;
+import javax.servlet.Servlet;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+
+
+/**
+ * General event for notifying listeners of significant events related to
+ * a specific instance of a Servlet, or a specific instance of a Filter,
+ * as opposed to the Wrapper component that manages it.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public final class InstanceEvent
+    extends EventObject {
+
+
+    // ----------------------------------------------------- Manifest Constants
+
+
+    /**
+     * The event indicating that the <code>init()</code> method is about
+     * to be called for this instance.
+     */
+    public static final String BEFORE_INIT_EVENT = "beforeInit";
+
+
+    /**
+     * The event indicating that the <code>init()</code> method has returned.
+     */
+    public static final String AFTER_INIT_EVENT = "afterInit";
+
+
+    /**
+     * The event indicating that the <code>service()</code> method is about
+     * to be called on a servlet.  The <code>servlet</code> property contains
+     * the servlet being called, and the <code>request</code> and
+     * <code>response</code> properties contain the current request and
+     * response being processed.
+     */
+    public static final String BEFORE_SERVICE_EVENT = "beforeService";
+
+
+    /**
+     * The event indicating that the <code>service()</code> method has
+     * returned.  The <code>servlet</code> property contains the servlet
+     * that was called, and the <code>request</code> and
+     * <code>response</code> properties contain the current request and
+     * response being processed.
+     */
+    public static final String AFTER_SERVICE_EVENT = "afterService";
+
+
+    /**
+     * The event indicating that the <code>destroy</code> method is about
+     * to be called for this instance.
+     */
+    public static final String BEFORE_DESTROY_EVENT = "beforeDestroy";
+
+
+    /**
+     * The event indicating that the <code>destroy()</code> method has
+     * returned.
+     */
+    public static final String AFTER_DESTROY_EVENT = "afterDestroy";
+
+
+    /**
+     * The event indicating that the <code>service()</code> method of a
+     * servlet accessed via a request dispatcher is about to be called.
+     * The <code>servlet</code> property contains a reference to the
+     * dispatched-to servlet instance, and the <code>request</code> and
+     * <code>response</code> properties contain the current request and
+     * response being processed.  The <code>wrapper</code> property will
+     * contain a reference to the dispatched-to Wrapper.
+     */
+    public static final String BEFORE_DISPATCH_EVENT = "beforeDispatch";
+
+
+    /**
+     * The event indicating that the <code>service()</code> method of a
+     * servlet accessed via a request dispatcher has returned.  The
+     * <code>servlet</code> property contains a reference to the
+     * dispatched-to servlet instance, and the <code>request</code> and
+     * <code>response</code> properties contain the current request and
+     * response being processed.  The <code>wrapper</code> property will
+     * contain a reference to the dispatched-to Wrapper.
+     */
+    public static final String AFTER_DISPATCH_EVENT = "afterDispatch";
+
+
+    /**
+     * The event indicating that the <code>doFilter()</code> method of a
+     * Filter is about to be called.  The <code>filter</code> property
+     * contains a reference to the relevant filter instance, and the
+     * <code>request</code> and <code>response</code> properties contain
+     * the current request and response being processed.
+     */
+    public static final String BEFORE_FILTER_EVENT = "beforeFilter";
+
+
+    /**
+     * The event indicating that the <code>doFilter()</code> method of a
+     * Filter has returned.  The <code>filter</code> property contains
+     * a reference to the relevant filter instance, and the
+     * <code>request</code> and <code>response</code> properties contain
+     * the current request and response being processed.
+     */
+    public static final String AFTER_FILTER_EVENT = "afterFilter";
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Construct a new InstanceEvent with the specified parameters.  This
+     * constructor is used for filter lifecycle events.
+     *
+     * @param wrapper Wrapper managing this servlet instance
+     * @param filter Filter instance for which this event occurred
+     * @param type Event type (required)
+     */
+    public InstanceEvent(Wrapper wrapper, Filter filter, String type) {
+
+      super(wrapper);
+      this.wrapper = wrapper;
+      this.filter = filter;
+      this.servlet = null;
+      this.type = type;
+
+    }
+
+
+    /**
+     * Construct a new InstanceEvent with the specified parameters.  This
+     * constructor is used for filter lifecycle events.
+     *
+     * @param wrapper Wrapper managing this servlet instance
+     * @param filter Filter instance for which this event occurred
+     * @param type Event type (required)
+     * @param exception Exception that occurred
+     */
+    public InstanceEvent(Wrapper wrapper, Filter filter, String type,
+                         Throwable exception) {
+
+      super(wrapper);
+      this.wrapper = wrapper;
+      this.filter = filter;
+      this.servlet = null;
+      this.type = type;
+      this.exception = exception;
+
+    }
+
+
+    /**
+     * Construct a new InstanceEvent with the specified parameters.  This
+     * constructor is used for filter processing events.
+     *
+     * @param wrapper Wrapper managing this servlet instance
+     * @param filter Filter instance for which this event occurred
+     * @param type Event type (required)
+     * @param request Servlet request we are processing
+     * @param response Servlet response we are processing
+     */
+    public InstanceEvent(Wrapper wrapper, Filter filter, String type,
+                         ServletRequest request, ServletResponse response) {
+
+      super(wrapper);
+      this.wrapper = wrapper;
+      this.filter = filter;
+      this.servlet = null;
+      this.type = type;
+      this.request = request;
+      this.response = response;
+
+    }
+
+
+    /**
+     * Construct a new InstanceEvent with the specified parameters.  This
+     * constructor is used for filter processing events.
+     *
+     * @param wrapper Wrapper managing this servlet instance
+     * @param filter Filter instance for which this event occurred
+     * @param type Event type (required)
+     * @param request Servlet request we are processing
+     * @param response Servlet response we are processing
+     * @param exception Exception that occurred
+     */
+    public InstanceEvent(Wrapper wrapper, Filter filter, String type,
+                         ServletRequest request, ServletResponse response,
+                         Throwable exception) {
+
+      super(wrapper);
+      this.wrapper = wrapper;
+      this.filter = filter;
+      this.servlet = null;
+      this.type = type;
+      this.request = request;
+      this.response = response;
+      this.exception = exception;
+
+    }
+
+
+    /**
+     * Construct a new InstanceEvent with the specified parameters.  This
+     * constructor is used for processing servlet lifecycle events.
+     *
+     * @param wrapper Wrapper managing this servlet instance
+     * @param servlet Servlet instance for which this event occurred
+     * @param type Event type (required)
+     */
+    public InstanceEvent(Wrapper wrapper, Servlet servlet, String type) {
+
+      super(wrapper);
+      this.wrapper = wrapper;
+      this.filter = null;
+      this.servlet = servlet;
+      this.type = type;
+
+    }
+
+
+    /**
+     * Construct a new InstanceEvent with the specified parameters.  This
+     * constructor is used for processing servlet lifecycle events.
+     *
+     * @param wrapper Wrapper managing this servlet instance
+     * @param servlet Servlet instance for which this event occurred
+     * @param type Event type (required)
+     * @param exception Exception that occurred
+     */
+    public InstanceEvent(Wrapper wrapper, Servlet servlet, String type,
+                         Throwable exception) {
+
+      super(wrapper);
+      this.wrapper = wrapper;
+      this.filter = null;
+      this.servlet = servlet;
+      this.type = type;
+      this.exception = exception;
+
+    }
+
+
+    /**
+     * Construct a new InstanceEvent with the specified parameters.  This
+     * constructor is used for processing servlet processing events.
+     *
+     * @param wrapper Wrapper managing this servlet instance
+     * @param servlet Servlet instance for which this event occurred
+     * @param type Event type (required)
+     * @param request Servlet request we are processing
+     * @param response Servlet response we are processing
+     */
+    public InstanceEvent(Wrapper wrapper, Servlet servlet, String type,
+                         ServletRequest request, ServletResponse response) {
+
+      super(wrapper);
+      this.wrapper = wrapper;
+      this.filter = null;
+      this.servlet = servlet;
+      this.type = type;
+      this.request = request;
+      this.response = response;
+
+    }
+
+
+    /**
+     * Construct a new InstanceEvent with the specified parameters.  This
+     * constructor is used for processing servlet processing events.
+     *
+     * @param wrapper Wrapper managing this servlet instance
+     * @param servlet Servlet instance for which this event occurred
+     * @param type Event type (required)
+     * @param request Servlet request we are processing
+     * @param response Servlet response we are processing
+     * @param exception Exception that occurred
+     */
+    public InstanceEvent(Wrapper wrapper, Servlet servlet, String type,
+                         ServletRequest request, ServletResponse response,
+                         Throwable exception) {
+
+      super(wrapper);
+      this.wrapper = wrapper;
+      this.filter = null;
+      this.servlet = servlet;
+      this.type = type;
+      this.request = request;
+      this.response = response;
+      this.exception = exception;
+
+    }
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The exception that was thrown during the processing being reported
+     * by this event (AFTER_INIT_EVENT, AFTER_SERVICE_EVENT, 
+     * AFTER_DESTROY_EVENT, AFTER_DISPATCH_EVENT, and AFTER_FILTER_EVENT only).
+     */
+    private Throwable exception = null;
+
+
+    /**
+     * The Filter instance for which this event occurred (BEFORE_FILTER_EVENT
+     * and AFTER_FILTER_EVENT only).
+     */
+    private Filter filter = null;
+
+
+    /**
+     * The servlet request being processed (BEFORE_FILTER_EVENT,
+     * AFTER_FILTER_EVENT, BEFORE_SERVICE_EVENT, and AFTER_SERVICE_EVENT).
+     */
+    private ServletRequest request = null;
+
+
+    /**
+     * The servlet response being processed (BEFORE_FILTER_EVENT,
+     * AFTER_FILTER_EVENT, BEFORE_SERVICE_EVENT, and AFTER_SERVICE_EVENT).
+     */
+    private ServletResponse response = null;
+
+
+    /**
+     * The Servlet instance for which this event occurred (not present on
+     * BEFORE_FILTER_EVENT or AFTER_FILTER_EVENT events).
+     */
+    private Servlet servlet = null;
+
+
+    /**
+     * The event type this instance represents.
+     */
+    private String type = null;
+
+
+    /**
+     * The Wrapper managing the servlet instance for which this event occurred.
+     */
+    private Wrapper wrapper = null;
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * Return the exception that occurred during the processing
+     * that was reported by this event.
+     */
+    public Throwable getException() {
+
+        return (this.exception);
+
+    }
+
+
+    /**
+     * Return the filter instance for which this event occurred.
+     */
+    public Filter getFilter() {
+
+        return (this.filter);
+
+    }
+
+
+    /**
+     * Return the servlet request for which this event occurred.
+     */
+    public ServletRequest getRequest() {
+
+        return (this.request);
+
+    }
+
+
+    /**
+     * Return the servlet response for which this event occurred.
+     */
+    public ServletResponse getResponse() {
+
+        return (this.response);
+
+    }
+
+
+    /**
+     * Return the servlet instance for which this event occurred.
+     */
+    public Servlet getServlet() {
+
+        return (this.servlet);
+
+    }
+
+
+    /**
+     * Return the event type of this event.
+     */
+    public String getType() {
+
+        return (this.type);
+
+    }
+
+
+    /**
+     * Return the Wrapper managing the servlet instance for which this
+     * event occurred.
+     */
+    public Wrapper getWrapper() {
+
+        return (this.wrapper);
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/InstanceListener.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/InstanceListener.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/InstanceListener.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,41 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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;
+
+
+/**
+ * Interface defining a listener for significant events related to a
+ * specific servlet instance, rather than to the Wrapper component that
+ * is managing that instance.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public interface InstanceListener {
+
+
+    /**
+     * Acknowledge the occurrence of the specified event.
+     *
+     * @param event InstanceEvent that has occurred
+     */
+    public void instanceEvent(InstanceEvent event);
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/Lifecycle.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/Lifecycle.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/Lifecycle.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,141 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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;
+
+
+/**
+ * Common interface for component life cycle methods.  Catalina components
+ * may, but are not required to, implement this interface (as well as the
+ * appropriate interface(s) for the functionality they support) in order to
+ * provide a consistent mechanism to start and stop the component.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 303352 $ $Date: 2004-10-05 12:12:52 -0500 (Tue, 05 Oct 2004) $
+ */
+
+public interface Lifecycle {
+
+
+    // ----------------------------------------------------- Manifest Constants
+
+
+    /**
+     * The LifecycleEvent type for the "component init" event.
+     */
+    public static final String INIT_EVENT = "init";
+
+
+    /**
+     * The LifecycleEvent type for the "component start" event.
+     */
+    public static final String START_EVENT = "start";
+
+
+    /**
+     * The LifecycleEvent type for the "component before start" event.
+     */
+    public static final String BEFORE_START_EVENT = "before_start";
+
+
+    /**
+     * The LifecycleEvent type for the "component after start" event.
+     */
+    public static final String AFTER_START_EVENT = "after_start";
+
+
+    /**
+     * The LifecycleEvent type for the "component stop" event.
+     */
+    public static final String STOP_EVENT = "stop";
+
+
+    /**
+     * The LifecycleEvent type for the "component before stop" event.
+     */
+    public static final String BEFORE_STOP_EVENT = "before_stop";
+
+
+    /**
+     * The LifecycleEvent type for the "component after stop" event.
+     */
+    public static final String AFTER_STOP_EVENT = "after_stop";
+
+
+    /**
+     * The LifecycleEvent type for the "component destroy" event.
+     */
+    public static final String DESTROY_EVENT = "destroy";
+
+
+    /**
+     * The LifecycleEvent type for the "periodic" event.
+     */
+    public static final String PERIODIC_EVENT = "periodic";
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Add a LifecycleEvent listener to this component.
+     *
+     * @param listener The listener to add
+     */
+    public void addLifecycleListener(LifecycleListener listener);
+
+
+    /**
+     * Get the lifecycle listeners associated with this lifecycle. If this 
+     * Lifecycle has no listeners registered, a zero-length array is returned.
+     */
+    public LifecycleListener[] findLifecycleListeners();
+
+
+    /**
+     * Remove a LifecycleEvent listener from this component.
+     *
+     * @param listener The listener to remove
+     */
+    public void removeLifecycleListener(LifecycleListener listener);
+
+
+    /**
+     * Prepare for the beginning of active use of the public methods of this
+     * component.  This method should be called before any of the public
+     * methods of this component are utilized.  It should also send a
+     * LifecycleEvent of type START_EVENT to any registered listeners.
+     *
+     * @exception LifecycleException if this component detects a fatal error
+     *  that prevents this component from being used
+     */
+    public void start() throws LifecycleException;
+
+
+    /**
+     * Gracefully terminate the active use of the public methods of this
+     * component.  This method should be the last one called on a given
+     * instance of this component.  It should also send a LifecycleEvent
+     * of type STOP_EVENT to any registered listeners.
+     *
+     * @exception LifecycleException if this component detects a fatal error
+     *  that needs to be reported
+     */
+    public void stop() throws LifecycleException;
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/LifecycleEvent.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/LifecycleEvent.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/LifecycleEvent.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,125 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.util.EventObject;
+
+
+/**
+ * General event for notifying listeners of significant changes on a component
+ * that implements the Lifecycle interface.  In particular, this will be useful
+ * on Containers, where these events replace the ContextInterceptor concept in
+ * Tomcat 3.x.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public final class LifecycleEvent
+    extends EventObject {
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Construct a new LifecycleEvent with the specified parameters.
+     *
+     * @param lifecycle Component on which this event occurred
+     * @param type Event type (required)
+     */
+    public LifecycleEvent(Lifecycle lifecycle, String type) {
+
+        this(lifecycle, type, null);
+
+    }
+
+
+    /**
+     * Construct a new LifecycleEvent with the specified parameters.
+     *
+     * @param lifecycle Component on which this event occurred
+     * @param type Event type (required)
+     * @param data Event data (if any)
+     */
+    public LifecycleEvent(Lifecycle lifecycle, String type, Object data) {
+
+        super(lifecycle);
+        this.lifecycle = lifecycle;
+        this.type = type;
+        this.data = data;
+
+    }
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The event data associated with this event.
+     */
+    private Object data = null;
+
+
+    /**
+     * The Lifecycle on which this event occurred.
+     */
+    private Lifecycle lifecycle = null;
+
+
+    /**
+     * The event type this instance represents.
+     */
+    private String type = null;
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * Return the event data of this event.
+     */
+    public Object getData() {
+
+        return (this.data);
+
+    }
+
+
+    /**
+     * Return the Lifecycle on which this event occurred.
+     */
+    public Lifecycle getLifecycle() {
+
+        return (this.lifecycle);
+
+    }
+
+
+    /**
+     * Return the event type of this event.
+     */
+    public String getType() {
+
+        return (this.type);
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/LifecycleException.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/LifecycleException.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/LifecycleException.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,144 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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;
+
+
+/**
+ * General purpose exception that is thrown to indicate a lifecycle related
+ * problem.  Such exceptions should generally be considered fatal to the
+ * operation of the application containing this component.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public final class LifecycleException extends Exception {
+
+
+    //------------------------------------------------------------ Constructors
+
+
+    /**
+     * Construct a new LifecycleException with no other information.
+     */
+    public LifecycleException() {
+
+        this(null, null);
+
+    }
+
+
+    /**
+     * Construct a new LifecycleException for the specified message.
+     *
+     * @param message Message describing this exception
+     */
+    public LifecycleException(String message) {
+
+        this(message, null);
+
+    }
+
+
+    /**
+     * Construct a new LifecycleException for the specified throwable.
+     *
+     * @param throwable Throwable that caused this exception
+     */
+    public LifecycleException(Throwable throwable) {
+
+        this(null, throwable);
+
+    }
+
+
+    /**
+     * Construct a new LifecycleException for the specified message
+     * and throwable.
+     *
+     * @param message Message describing this exception
+     * @param throwable Throwable that caused this exception
+     */
+    public LifecycleException(String message, Throwable throwable) {
+
+        super();
+        this.message = message;
+        this.throwable = throwable;
+
+    }
+
+
+    //------------------------------------------------------ Instance Variables
+
+
+    /**
+     * The error message passed to our constructor (if any)
+     */
+    protected String message = null;
+
+
+    /**
+     * The underlying exception or error passed to our constructor (if any)
+     */
+    protected Throwable throwable = null;
+
+
+    //---------------------------------------------------------- Public Methods
+
+
+    /**
+     * Returns the message associated with this exception, if any.
+     */
+    public String getMessage() {
+
+        return (message);
+
+    }
+
+
+    /**
+     * Returns the throwable that caused this exception, if any.
+     */
+    public Throwable getThrowable() {
+
+        return (throwable);
+
+    }
+
+
+    /**
+     * Return a formatted string that describes this exception.
+     */
+    public String toString() {
+
+        StringBuffer sb = new StringBuffer("LifecycleException:  ");
+        if (message != null) {
+            sb.append(message);
+            if (throwable != null) {
+                sb.append(":  ");
+            }
+        }
+        if (throwable != null) {
+            sb.append(throwable.toString());
+        }
+        return (sb.toString());
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/LifecycleListener.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/LifecycleListener.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/LifecycleListener.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,43 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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;
+
+
+
+
+/**
+ * Interface defining a listener for significant events (including "component
+ * start" and "component stop" generated by a component that implements the
+ * Lifecycle interface.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public interface LifecycleListener {
+
+
+    /**
+     * Acknowledge the occurrence of the specified event.
+     *
+     * @param event LifecycleEvent that has occurred
+     */
+    public void lifecycleEvent(LifecycleEvent event);
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/Loader.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/Loader.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/Loader.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,168 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.beans.PropertyChangeListener;
+
+
+/**
+ * A <b>Loader</b> represents a Java ClassLoader implementation that can
+ * be used by a Container to load class files (within a repository associated
+ * with the Loader) that are designed to be reloaded upon request, as well as
+ * a mechanism to detect whether changes have occurred in the underlying
+ * repository.
+ * <p>
+ * In order for a <code>Loader</code> implementation to successfully operate
+ * with a <code>Context</code> implementation that implements reloading, it
+ * must obey the following constraints:
+ * <ul>
+ * <li>Must implement <code>Lifecycle</code> so that the Context can indicate
+ *     that a new class loader is required.
+ * <li>The <code>start()</code> method must unconditionally create a new
+ *     <code>ClassLoader</code> implementation.
+ * <li>The <code>stop()</code> method must throw away its reference to the
+ *     <code>ClassLoader</code> previously utilized, so that the class loader,
+ *     all classes loaded by it, and all objects of those classes, can be
+ *     garbage collected.
+ * <li>Must allow a call to <code>stop()</code> to be followed by a call to
+ *     <code>start()</code> on the same <code>Loader</code> instance.
+ * <li>Based on a policy chosen by the implementation, must call the
+ *     <code>Context.reload()</code> method on the owning <code>Context</code>
+ *     when a change to one or more of the class files loaded by this class
+ *     loader is detected.
+ * </ul>
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 303352 $ $Date: 2004-10-05 12:12:52 -0500 (Tue, 05 Oct 2004) $
+ */
+
+public interface Loader {
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * Execute a periodic task, such as reloading, etc. This method will be
+     * invoked inside the classloading context of this container. Unexpected
+     * throwables will be caught and logged.
+     */
+    public void backgroundProcess();
+
+
+    /**
+     * Return the Java class loader to be used by this Container.
+     */
+    public ClassLoader getClassLoader();
+
+
+    /**
+     * Return the Container with which this Loader has been associated.
+     */
+    public Container getContainer();
+
+
+    /**
+     * Set the Container with which this Loader has been associated.
+     *
+     * @param container The associated Container
+     */
+    public void setContainer(Container container);
+
+
+    /**
+     * Return the "follow standard delegation model" flag used to configure
+     * our ClassLoader.
+     */
+    public boolean getDelegate();
+
+
+    /**
+     * Set the "follow standard delegation model" flag used to configure
+     * our ClassLoader.
+     *
+     * @param delegate The new flag
+     */
+    public void setDelegate(boolean delegate);
+
+
+    /**
+     * Return descriptive information about this Loader implementation and
+     * the corresponding version number, in the format
+     * <code>&lt;description&gt;/&lt;version&gt;</code>.
+     */
+    public String getInfo();
+
+
+    /**
+     * Return the reloadable flag for this Loader.
+     */
+    public boolean getReloadable();
+
+
+    /**
+     * Set the reloadable flag for this Loader.
+     *
+     * @param reloadable The new reloadable flag
+     */
+    public void setReloadable(boolean reloadable);
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Add a property change listener to this component.
+     *
+     * @param listener The listener to add
+     */
+    public void addPropertyChangeListener(PropertyChangeListener listener);
+
+
+    /**
+     * Add a new repository to the set of repositories for this class loader.
+     *
+     * @param repository Repository to be added
+     */
+    public void addRepository(String repository);
+
+
+    /**
+     * Return the set of repositories defined for this class loader.
+     * If none are defined, a zero-length array is returned.
+     */
+    public String[] findRepositories();
+
+
+    /**
+     * Has the internal repository associated with this Loader been modified,
+     * such that the loaded classes should be reloaded?
+     */
+    public boolean modified();
+
+
+    /**
+     * Remove a property change listener from this component.
+     *
+     * @param listener The listener to remove
+     */
+    public void removePropertyChangeListener(PropertyChangeListener listener);
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/Manager.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/Manager.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/Manager.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,365 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.beans.PropertyChangeListener;
+import java.io.IOException;
+
+
+/**
+ * A <b>Manager</b> manages the pool of Sessions that are associated with a
+ * particular Container.  Different Manager implementations may support
+ * value-added features such as the persistent storage of session data,
+ * as well as migrating sessions for distributable web applications.
+ * <p>
+ * In order for a <code>Manager</code> implementation to successfully operate
+ * with a <code>Context</code> implementation that implements reloading, it
+ * must obey the following constraints:
+ * <ul>
+ * <li>Must implement <code>Lifecycle</code> so that the Context can indicate
+ *     that a restart is required.
+ * <li>Must allow a call to <code>stop()</code> to be followed by a call to
+ *     <code>start()</code> on the same <code>Manager</code> instance.
+ * </ul>
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 303682 $ $Date: 2005-02-07 15:56:32 -0600 (Mon, 07 Feb 2005) $
+ */
+
+public interface Manager {
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * Return the Container with which this Manager is associated.
+     */
+    public Container getContainer();
+
+
+    /**
+     * Set the Container with which this Manager is associated.
+     *
+     * @param container The newly associated Container
+     */
+    public void setContainer(Container container);
+
+
+    /**
+     * Return the distributable flag for the sessions supported by
+     * this Manager.
+     */
+    public boolean getDistributable();
+
+
+    /**
+     * Set the distributable flag for the sessions supported by this
+     * Manager.  If this flag is set, all user data objects added to
+     * sessions associated with this manager must implement Serializable.
+     *
+     * @param distributable The new distributable flag
+     */
+    public void setDistributable(boolean distributable);
+
+
+    /**
+     * Return descriptive information about this Manager implementation and
+     * the corresponding version number, in the format
+     * <code>&lt;description&gt;/&lt;version&gt;</code>.
+     */
+    public String getInfo();
+
+
+    /**
+     * Return the default maximum inactive interval (in seconds)
+     * for Sessions created by this Manager.
+     */
+    public int getMaxInactiveInterval();
+
+
+    /**
+     * Set the default maximum inactive interval (in seconds)
+     * for Sessions created by this Manager.
+     *
+     * @param interval The new default value
+     */
+    public void setMaxInactiveInterval(int interval);
+
+
+    /**
+     * Gets the session id length (in bytes) of Sessions created by
+     * this Manager.
+     *
+     * @return The session id length
+     */
+    public int getSessionIdLength();
+
+
+    /**
+     * Sets the session id length (in bytes) for Sessions created by this
+     * Manager.
+     *
+     * @param idLength The session id length
+     */
+    public void setSessionIdLength(int idLength);
+
+
+    /** 
+     * Returns the total number of sessions created by this manager.
+     *
+     * @return Total number of sessions created by this manager.
+     */
+    public int getSessionCounter();
+
+
+    /** 
+     * Sets the total number of sessions created by this manager.
+     *
+     * @param sessionCounter Total number of sessions created by this manager.
+     */
+    public void setSessionCounter(int sessionCounter);
+
+
+    /**
+     * Gets the maximum number of sessions that have been active at the same
+     * time.
+     *
+     * @return Maximum number of sessions that have been active at the same
+     * time
+     */
+    public int getMaxActive();
+
+
+    /**
+     * (Re)sets the maximum number of sessions that have been active at the
+     * same time.
+     *
+     * @param maxActive Maximum number of sessions that have been active at
+     * the same time.
+     */
+    public void setMaxActive(int maxActive);
+
+
+    /** 
+     * Gets the number of currently active sessions.
+     *
+     * @return Number of currently active sessions
+     */
+    public int getActiveSessions();
+
+
+    /**
+     * Gets the number of sessions that have expired.
+     *
+     * @return Number of sessions that have expired
+     */
+    public int getExpiredSessions();
+
+
+    /**
+     * Sets the number of sessions that have expired.
+     *
+     * @param expiredSessions Number of sessions that have expired
+     */
+    public void setExpiredSessions(int expiredSessions);
+
+
+    /**
+     * Gets the number of sessions that were not created because the maximum
+     * number of active sessions was reached.
+     *
+     * @return Number of rejected sessions
+     */
+    public int getRejectedSessions();
+
+
+    /**
+     * Sets the number of sessions that were not created because the maximum
+     * number of active sessions was reached.
+     *
+     * @param rejectedSessions Number of rejected sessions
+     */
+    public void setRejectedSessions(int rejectedSessions);
+
+
+    /**
+     * Gets the longest time (in seconds) that an expired session had been
+     * alive.
+     *
+     * @return Longest time (in seconds) that an expired session had been
+     * alive.
+     */
+    public int getSessionMaxAliveTime();
+
+
+    /**
+     * Sets the longest time (in seconds) that an expired session had been
+     * alive.
+     *
+     * @param sessionMaxAliveTime Longest time (in seconds) that an expired
+     * session had been alive.
+     */
+    public void setSessionMaxAliveTime(int sessionMaxAliveTime);
+
+
+    /**
+     * Gets the average time (in seconds) that expired sessions had been
+     * alive.
+     *
+     * @return Average time (in seconds) that expired sessions had been
+     * alive.
+     */
+    public int getSessionAverageAliveTime();
+
+
+    /**
+     * Sets the average time (in seconds) that expired sessions had been
+     * alive.
+     *
+     * @param sessionAverageAliveTime Average time (in seconds) that expired
+     * sessions had been alive.
+     */
+    public void setSessionAverageAliveTime(int sessionAverageAliveTime);
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Add this Session to the set of active Sessions for this Manager.
+     *
+     * @param session Session to be added
+     */
+    public void add(Session session);
+
+
+    /**
+     * Add a property change listener to this component.
+     *
+     * @param listener The listener to add
+     */
+    public void addPropertyChangeListener(PropertyChangeListener listener);
+
+
+    /**
+     * Get a session from the recycled ones or create a new empty one.
+     * The PersistentManager manager does not need to create session data
+     * because it reads it from the Store.
+     */                                                                         
+    public Session createEmptySession();
+
+
+    /**
+     * Construct and return a new session object, based on the default
+     * settings specified by this Manager's properties.  The session
+     * id will be assigned by this method, and available via the getId()
+     * method of the returned session.  If a new session cannot be created
+     * for any reason, return <code>null</code>.
+     * 
+     * @exception IllegalStateException if a new session cannot be
+     *  instantiated for any reason
+     * @deprecated
+     */
+    public Session createSession();
+
+
+    /**
+     * Construct and return a new session object, based on the default
+     * settings specified by this Manager's properties.  The session
+     * id specified will be used as the session id.
+     * If a new session cannot be created for any reason, return 
+     * <code>null</code>.
+     * 
+     * @param sessionId The session id which should be used to create the
+     *  new session; if <code>null</code>, the session
+     *  id will be assigned by this method, and available via the getId()
+     *  method of the returned session.
+     * @exception IllegalStateException if a new session cannot be
+     *  instantiated for any reason
+     */
+    public Session createSession(String sessionId);
+
+
+    /**
+     * Return the active Session, associated with this Manager, with the
+     * specified session id (if any); otherwise return <code>null</code>.
+     *
+     * @param id The session id for the session to be returned
+     *
+     * @exception IllegalStateException if a new session cannot be
+     *  instantiated for any reason
+     * @exception IOException if an input/output error occurs while
+     *  processing this request
+     */
+    public Session findSession(String id) throws IOException;
+
+
+    /**
+     * Return the set of active Sessions associated with this Manager.
+     * If this Manager has no active Sessions, a zero-length array is returned.
+     */
+    public Session[] findSessions();
+
+
+    /**
+     * Load any currently active sessions that were previously unloaded
+     * to the appropriate persistence mechanism, if any.  If persistence is not
+     * supported, this method returns without doing anything.
+     *
+     * @exception ClassNotFoundException if a serialized class cannot be
+     *  found during the reload
+     * @exception IOException if an input/output error occurs
+     */
+    public void load() throws ClassNotFoundException, IOException;
+
+
+    /**
+     * Remove this Session from the active Sessions for this Manager.
+     *
+     * @param session Session to be removed
+     */
+    public void remove(Session session);
+
+
+    /**
+     * Remove a property change listener from this component.
+     *
+     * @param listener The listener to remove
+     */
+    public void removePropertyChangeListener(PropertyChangeListener listener);
+
+
+    /**
+     * Save any currently active sessions in the appropriate persistence
+     * mechanism, if any.  If persistence is not supported, this method
+     * returns without doing anything.
+     *
+     * @exception IOException if an input/output error occurs
+     */
+    public void unload() throws IOException;
+    
+     /**
+      * This method will be invoked by the context/container on a periodic
+      * basis and allows the manager to implement
+      * a method that executes periodic tasks, such as expiring sessions etc.
+      */
+     public void backgroundProcess();
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/Pipeline.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/Pipeline.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/Pipeline.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,120 @@
+/*
+ * Copyright 1999-2001,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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;
+
+
+/**
+ * <p>Interface describing a collection of Valves that should be executed
+ * in sequence when the <code>invoke()</code> method is invoked.  It is
+ * required that a Valve somewhere in the pipeline (usually the last one)
+ * must process the request and create the corresponding response, rather
+ * than trying to pass the request on.</p>
+ *
+ * <p>There is generally a single Pipeline instance associated with each
+ * Container.  The container's normal request processing functionality is
+ * generally encapsulated in a container-specific Valve, which should always
+ * be executed at the end of a pipeline.  To facilitate this, the
+ * <code>setBasic()</code> method is provided to set the Valve instance that
+ * will always be executed last.  Other Valves will be executed in the order
+ * that they were added, before the basic Valve is executed.</p>
+ *
+ * @author Craig R. McClanahan
+ * @author Peter Donald
+ * @version $Revision: 302978 $ $Date: 2004-06-23 11:59:42 -0500 (Wed, 23 Jun 2004) $
+ */
+
+public interface Pipeline {
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * <p>Return the Valve instance that has been distinguished as the basic
+     * Valve for this Pipeline (if any).
+     */
+    public Valve getBasic();
+
+
+    /**
+     * <p>Set the Valve instance that has been distinguished as the basic
+     * Valve for this Pipeline (if any).  Prioer to setting the basic Valve,
+     * the Valve's <code>setContainer()</code> will be called, if it
+     * implements <code>Contained</code>, with the owning Container as an
+     * argument.  The method may throw an <code>IllegalArgumentException</code>
+     * if this Valve chooses not to be associated with this Container, or
+     * <code>IllegalStateException</code> if it is already associated with
+     * a different Container.</p>
+     *
+     * @param valve Valve to be distinguished as the basic Valve
+     */
+    public void setBasic(Valve valve);
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * <p>Add a new Valve to the end of the pipeline associated with this
+     * Container.  Prior to adding the Valve, the Valve's
+     * <code>setContainer()</code> method will be called, if it implements
+     * <code>Contained</code>, with the owning Container as an argument.
+     * The method may throw an
+     * <code>IllegalArgumentException</code> if this Valve chooses not to
+     * be associated with this Container, or <code>IllegalStateException</code>
+     * if it is already associated with a different Container.</p>
+     *
+     * @param valve Valve to be added
+     *
+     * @exception IllegalArgumentException if this Container refused to
+     *  accept the specified Valve
+     * @exception IllegalArgumentException if the specifie Valve refuses to be
+     *  associated with this Container
+     * @exception IllegalStateException if the specified Valve is already
+     *  associated with a different Container
+     */
+    public void addValve(Valve valve);
+
+
+    /**
+     * Return the set of Valves in the pipeline associated with this
+     * Container, including the basic Valve (if any).  If there are no
+     * such Valves, a zero-length array is returned.
+     */
+    public Valve[] getValves();
+
+
+    /**
+     * Remove the specified Valve from the pipeline associated with this
+     * Container, if it is found; otherwise, do nothing.  If the Valve is
+     * found and removed, the Valve's <code>setContainer(null)</code> method
+     * will be called if it implements <code>Contained</code>.
+     *
+     * @param valve Valve to be removed
+     */
+    public void removeValve(Valve valve);
+
+
+    /**
+     * <p>Return the Valve instance that has been distinguished as the basic
+     * Valve for this Pipeline (if any).
+     */
+    public Valve getFirst();
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/Realm.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/Realm.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/Realm.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,201 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.beans.PropertyChangeListener;
+import java.io.IOException;
+import java.security.Principal;
+import java.security.cert.X509Certificate;
+
+import org.apache.catalina.connector.Request;
+import org.apache.catalina.connector.Response;
+import org.apache.catalina.deploy.SecurityConstraint;
+/**
+ * A <b>Realm</b> is a read-only facade for an underlying security realm
+ * used to authenticate individual users, and identify the security roles
+ * associated with those users.  Realms can be attached at any Container
+ * level, but will typically only be attached to a Context, or higher level,
+ * Container.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 303352 $ $Date: 2004-10-05 12:12:52 -0500 (Tue, 05 Oct 2004) $
+ */
+
+public interface Realm {
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * Return the Container with which this Realm has been associated.
+     */
+    public Container getContainer();
+
+
+    /**
+     * Set the Container with which this Realm has been associated.
+     *
+     * @param container The associated Container
+     */
+    public void setContainer(Container container);
+
+
+    /**
+     * Return descriptive information about this Realm implementation and
+     * the corresponding version number, in the format
+     * <code>&lt;description&gt;/&lt;version&gt;</code>.
+     */
+    public String getInfo();
+
+
+    // --------------------------------------------------------- Public Methods
+
+    
+    /**
+     * Add a property change listener to this component.
+     *
+     * @param listener The listener to add
+     */
+    public void addPropertyChangeListener(PropertyChangeListener listener);
+
+
+    /**
+     * Return the Principal associated with the specified username and
+     * credentials, if there is one; otherwise return <code>null</code>.
+     *
+     * @param username Username of the Principal to look up
+     * @param credentials Password or other credentials to use in
+     *  authenticating this username
+     */
+    public Principal authenticate(String username, String credentials);
+
+
+    /**
+     * Return the Principal associated with the specified username and
+     * credentials, if there is one; otherwise return <code>null</code>.
+     *
+     * @param username Username of the Principal to look up
+     * @param credentials Password or other credentials to use in
+     *  authenticating this username
+     */
+    public Principal authenticate(String username, byte[] credentials);
+
+
+    /**
+     * Return the Principal associated with the specified username, which
+     * matches the digest calculated using the given parameters using the
+     * method described in RFC 2069; otherwise return <code>null</code>.
+     *
+     * @param username Username of the Principal to look up
+     * @param digest Digest which has been submitted by the client
+     * @param nonce Unique (or supposedly unique) token which has been used
+     * for this request
+     * @param realm Realm name
+     * @param md5a2 Second MD5 digest used to calculate the digest :
+     * MD5(Method + ":" + uri)
+     */
+    public Principal authenticate(String username, String digest,
+                                  String nonce, String nc, String cnonce,
+                                  String qop, String realm,
+                                  String md5a2);
+
+
+    /**
+     * Return the Principal associated with the specified chain of X509
+     * client certificates.  If there is none, return <code>null</code>.
+     *
+     * @param certs Array of client certificates, with the first one in
+     *  the array being the certificate of the client itself.
+     */
+    public Principal authenticate(X509Certificate certs[]);
+    
+    
+    /**
+     * Execute a periodic task, such as reloading, etc. This method will be
+     * invoked inside the classloading context of this container. Unexpected
+     * throwables will be caught and logged.
+     */
+    public void backgroundProcess();
+
+
+    /**
+     * Return the SecurityConstraints configured to guard the request URI for
+     * this request, or <code>null</code> if there is no such constraint.
+     *
+     * @param request Request we are processing
+     */
+    public SecurityConstraint [] findSecurityConstraints(Request request,
+                                                     Context context);
+    
+    
+    /**
+     * Perform access control based on the specified authorization constraint.
+     * Return <code>true</code> if this constraint is satisfied and processing
+     * should continue, or <code>false</code> otherwise.
+     *
+     * @param request Request we are processing
+     * @param response Response we are creating
+     * @param constraint Security constraint we are enforcing
+     * @param context The Context to which client of this class is attached.
+     *
+     * @exception IOException if an input/output error occurs
+     */
+    public boolean hasResourcePermission(Request request,
+                                         Response response,
+                                         SecurityConstraint [] constraint,
+                                         Context context)
+        throws IOException;
+    
+    
+    /**
+     * Return <code>true</code> if the specified Principal has the specified
+     * security role, within the context of this Realm; otherwise return
+     * <code>false</code>.
+     *
+     * @param principal Principal for whom the role is to be checked
+     * @param role Security role to be checked
+     */
+    public boolean hasRole(Principal principal, String role);
+
+        /**
+     * Enforce any user data constraint required by the security constraint
+     * guarding this request URI.  Return <code>true</code> if this constraint
+     * was not violated and processing should continue, or <code>false</code>
+     * if we have created a response already.
+     *
+     * @param request Request we are processing
+     * @param response Response we are creating
+     * @param constraint Security constraint being checked
+     *
+     * @exception IOException if an input/output error occurs
+     */
+    public boolean hasUserDataPermission(Request request,
+                                         Response response,
+                                         SecurityConstraint []constraint)
+        throws IOException;
+    
+    /**
+     * Remove a property change listener from this component.
+     *
+     * @param listener The listener to remove
+     */
+    public void removePropertyChangeListener(PropertyChangeListener listener);
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/Role.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/Role.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/Role.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.security.Principal;
+
+
+/**
+ * <p>Abstract representation of a security role, suitable for use in
+ * environments like JAAS that want to deal with <code>Principals</code>.</p>
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ * @since 4.1
+ */
+
+public interface Role extends Principal {
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * Return the description of this role.
+     */
+    public String getDescription();
+
+
+    /**
+     * Set the description of this role.
+     *
+     * @param description The new description
+     */
+    public void setDescription(String description);
+
+
+    /**
+     * Return the role name of this role, which must be unique
+     * within the scope of a {@link UserDatabase}.
+     */
+    public String getRolename();
+
+
+    /**
+     * Set the role name of this role, which must be unique
+     * within the scope of a {@link UserDatabase}.
+     *
+     * @param rolename The new role name
+     */
+    public void setRolename(String rolename);
+
+
+    /**
+     * Return the {@link UserDatabase} within which this Role is defined.
+     */
+    public UserDatabase getUserDatabase();
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/Server.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/Server.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/Server.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,152 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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 org.apache.catalina.deploy.NamingResources;
+
+/**
+ * A <code>Server</code> element represents the entire Catalina
+ * servlet container.  Its attributes represent the characteristics of
+ * the servlet container as a whole.  A <code>Server</code> may contain
+ * one or more <code>Services</code>, and the top level set of naming
+ * resources.
+ * <p>
+ * Normally, an implementation of this interface will also implement
+ * <code>Lifecycle</code>, such that when the <code>start()</code> and
+ * <code>stop()</code> methods are called, all of the defined
+ * <code>Services</code> are also started or stopped.
+ * <p>
+ * In between, the implementation must open a server socket on the port number
+ * specified by the <code>port</code> property.  When a connection is accepted,
+ * the first line is read and compared with the specified shutdown command.
+ * If the command matches, shutdown of the server is initiated.
+ * <p>
+ * <strong>NOTE</strong> - The concrete implementation of this class should
+ * register the (singleton) instance with the <code>ServerFactory</code>
+ * class in its constructor(s).
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302899 $ $Date: 2004-05-26 10:29:30 -0500 (Wed, 26 May 2004) $
+ */
+
+public interface Server {
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * Return descriptive information about this Server implementation and
+     * the corresponding version number, in the format
+     * <code>&lt;description&gt;/&lt;version&gt;</code>.
+     */
+    public String getInfo();
+
+
+    /**
+     * Return the global naming resources.
+     */
+    public NamingResources getGlobalNamingResources();
+
+
+    /**
+     * Set the global naming resources.
+     * 
+     * @param globalNamingResources The new global naming resources
+     */
+    public void setGlobalNamingResources
+        (NamingResources globalNamingResources);
+
+
+    /**
+     * Return the port number we listen to for shutdown commands.
+     */
+    public int getPort();
+
+
+    /**
+     * Set the port number we listen to for shutdown commands.
+     *
+     * @param port The new port number
+     */
+    public void setPort(int port);
+
+
+    /**
+     * Return the shutdown command string we are waiting for.
+     */
+    public String getShutdown();
+
+
+    /**
+     * Set the shutdown command we are waiting for.
+     *
+     * @param shutdown The new shutdown command
+     */
+    public void setShutdown(String shutdown);
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Add a new Service to the set of defined Services.
+     *
+     * @param service The Service to be added
+     */
+    public void addService(Service service);
+
+
+    /**
+     * Wait until a proper shutdown command is received, then return.
+     */
+    public void await();
+
+
+    /**
+     * Return the specified Service (if it exists); otherwise return
+     * <code>null</code>.
+     *
+     * @param name Name of the Service to be returned
+     */
+    public Service findService(String name);
+
+
+    /**
+     * Return the set of Services defined within this Server.
+     */
+    public Service[] findServices();
+
+
+    /**
+     * Remove the specified Service from the set associated from this
+     * Server.
+     *
+     * @param service The Service to be removed
+     */
+    public void removeService(Service service);
+
+    /**
+     * Invoke a pre-startup initialization. This is used to allow connectors
+     * to bind to restricted ports under Unix operating environments.
+     *
+     * @exception LifecycleException If this server was already initialized.
+     */
+    public void initialize()
+    throws LifecycleException;
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ServerFactory.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ServerFactory.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ServerFactory.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,76 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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 org.apache.catalina.core.StandardServer;
+
+
+/**
+ * <p><strong>ServerFactory</strong> allows the registration of the
+ * (singleton) <code>Server</code> instance for this JVM, so that it
+ * can be accessed independently of any existing reference to the
+ * component hierarchy.  This is important for administration tools
+ * that are built around the internal component implementation classes.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class ServerFactory {
+
+
+    // ------------------------------------------------------- Static Variables
+
+
+    /**
+     * The singleton <code>Server</code> instance for this JVM.
+     */
+    private static Server server = null;
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Return the singleton <code>Server</code> instance for this JVM.
+     */
+    public static Server getServer() {
+        if( server==null )
+            server=new StandardServer();
+        return (server);
+
+    }
+
+
+    /**
+     * Set the singleton <code>Server</code> instance for this JVM.  This
+     * method must <strong>only</strong> be called from a constructor of
+     * the (singleton) <code>Server</code> instance that is created for
+     * this execution of Catalina.
+     *
+     * @param theServer The new singleton instance
+     */
+    public static void setServer(Server theServer) {
+
+        if (server == null)
+            server = theServer;
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/Service.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/Service.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/Service.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,131 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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 org.apache.catalina.connector.Connector;
+
+
+/**
+ * A <strong>Service</strong> is a group of one or more
+ * <strong>Connectors</strong> that share a single <strong>Container</strong>
+ * to process their incoming requests.  This arrangement allows, for example,
+ * a non-SSL and SSL connector to share the same population of web apps.
+ * <p>
+ * A given JVM can contain any number of Service instances; however, they are
+ * completely independent of each other and share only the basic JVM facilities
+ * and classes on the system class path.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302975 $ $Date: 2004-06-23 03:25:04 -0500 (Wed, 23 Jun 2004) $
+ */
+
+public interface Service {
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * Return the <code>Container</code> that handles requests for all
+     * <code>Connectors</code> associated with this Service.
+     */
+    public Container getContainer();
+
+
+    /**
+     * Set the <code>Container</code> that handles requests for all
+     * <code>Connectors</code> associated with this Service.
+     *
+     * @param container The new Container
+     */
+    public void setContainer(Container container);
+
+
+    /**
+     * Return descriptive information about this Service implementation and
+     * the corresponding version number, in the format
+     * <code>&lt;description&gt;/&lt;version&gt;</code>.
+     */
+    public String getInfo();
+
+
+    /**
+     * Return the name of this Service.
+     */
+    public String getName();
+
+
+    /**
+     * Set the name of this Service.
+     *
+     * @param name The new service name
+     */
+    public void setName(String name);
+
+
+    /**
+     * Return the <code>Server</code> with which we are associated (if any).
+     */
+    public Server getServer();
+
+
+    /**
+     * Set the <code>Server</code> with which we are associated (if any).
+     *
+     * @param server The server that owns this Service
+     */
+    public void setServer(Server server);
+
+    
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Add a new Connector to the set of defined Connectors, and associate it
+     * with this Service's Container.
+     *
+     * @param connector The Connector to be added
+     */
+    public void addConnector(Connector connector);
+
+
+    /**
+     * Find and return the set of Connectors associated with this Service.
+     */
+    public Connector[] findConnectors();
+
+
+    /**
+     * Remove the specified Connector from the set associated from this
+     * Service.  The removed Connector will also be disassociated from our
+     * Container.
+     *
+     * @param connector The Connector to be removed
+     */
+    public void removeConnector(Connector connector);
+
+    /**
+     * Invoke a pre-startup initialization. This is used to allow connectors
+     * to bind to restricted ports under Unix operating environments.
+     *
+     * @exception LifecycleException If this server was already initialized.
+     */
+    public void initialize()
+    throws LifecycleException;
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/Session.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/Session.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/Session.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,302 @@
+/*
+ * Copyright 1999-2001,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.security.Principal;
+import java.util.Iterator;
+
+import javax.servlet.http.HttpSession;
+
+
+/**
+ * A <b>Session</b> is the Catalina-internal facade for an
+ * <code>HttpSession</code> that is used to maintain state information
+ * between requests for a particular user of a web application.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 384817 $ $Date: 2006-03-10 09:27:43 -0600 (Fri, 10 Mar 2006) $
+ */
+
+public interface Session {
+
+
+    // ----------------------------------------------------- Manifest Constants
+
+
+    /**
+     * The SessionEvent event type when a session is created.
+     */
+    public static final String SESSION_CREATED_EVENT = "createSession";
+
+
+    /**
+     * The SessionEvent event type when a session is destroyed.
+     */
+    public static final String SESSION_DESTROYED_EVENT = "destroySession";
+
+
+    /**
+     * The SessionEvent event type when a session is activated.
+     */
+    public static final String SESSION_ACTIVATED_EVENT = "activateSession";
+
+
+    /**
+     * The SessionEvent event type when a session is passivated.
+     */
+    public static final String SESSION_PASSIVATED_EVENT = "passivateSession";
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * Return the authentication type used to authenticate our cached
+     * Principal, if any.
+     */
+    public String getAuthType();
+
+
+    /**
+     * Set the authentication type used to authenticate our cached
+     * Principal, if any.
+     *
+     * @param authType The new cached authentication type
+     */
+    public void setAuthType(String authType);
+
+
+    /**
+     * Return the creation time for this session.
+     */
+    public long getCreationTime();
+
+
+    /**
+     * Set the creation time for this session.  This method is called by the
+     * Manager when an existing Session instance is reused.
+     *
+     * @param time The new creation time
+     */
+    public void setCreationTime(long time);
+
+
+    /**
+     * Return the session identifier for this session.
+     */
+    public String getId();
+
+
+    /**
+     * Return the session identifier for this session.
+     */
+    public String getIdInternal();
+
+
+    /**
+     * Set the session identifier for this session.
+     *
+     * @param id The new session identifier
+     */
+    public void setId(String id);
+
+
+    /**
+     * Return descriptive information about this Session implementation and
+     * the corresponding version number, in the format
+     * <code>&lt;description&gt;/&lt;version&gt;</code>.
+     */
+    public String getInfo();
+
+
+    /**
+     * Return the last time the client sent a request associated with this
+     * session, as the number of milliseconds since midnight, January 1, 1970
+     * GMT.  Actions that your application takes, such as getting or setting
+     * a value associated with the session, do not affect the access time.
+     */
+    public long getLastAccessedTime();
+
+    /**
+     * Return the last client access time without invalidation check
+     * @see #getLastAccessedTime().
+     */
+    public long getLastAccessedTimeInternal();
+
+    /**
+     * Return the Manager within which this Session is valid.
+     */
+    public Manager getManager();
+
+
+    /**
+     * Set the Manager within which this Session is valid.
+     *
+     * @param manager The new Manager
+     */
+    public void setManager(Manager manager);
+
+
+    /**
+     * Return the maximum time interval, in seconds, between client requests
+     * before the servlet container will invalidate the session.  A negative
+     * time indicates that the session should never time out.
+     */
+    public int getMaxInactiveInterval();
+
+
+    /**
+     * Set the maximum time interval, in seconds, between client requests
+     * before the servlet container will invalidate the session.  A negative
+     * time indicates that the session should never time out.
+     *
+     * @param interval The new maximum interval
+     */
+    public void setMaxInactiveInterval(int interval);
+
+
+    /**
+     * Set the <code>isNew</code> flag for this session.
+     *
+     * @param isNew The new value for the <code>isNew</code> flag
+     */
+    public void setNew(boolean isNew);
+
+
+    /**
+     * Return the authenticated Principal that is associated with this Session.
+     * This provides an <code>Authenticator</code> with a means to cache a
+     * previously authenticated Principal, and avoid potentially expensive
+     * <code>Realm.authenticate()</code> calls on every request.  If there
+     * is no current associated Principal, return <code>null</code>.
+     */
+    public Principal getPrincipal();
+
+
+    /**
+     * Set the authenticated Principal that is associated with this Session.
+     * This provides an <code>Authenticator</code> with a means to cache a
+     * previously authenticated Principal, and avoid potentially expensive
+     * <code>Realm.authenticate()</code> calls on every request.
+     *
+     * @param principal The new Principal, or <code>null</code> if none
+     */
+    public void setPrincipal(Principal principal);
+
+
+    /**
+     * Return the <code>HttpSession</code> for which this object
+     * is the facade.
+     */
+    public HttpSession getSession();
+
+
+    /**
+     * Set the <code>isValid</code> flag for this session.
+     *
+     * @param isValid The new value for the <code>isValid</code> flag
+     */
+    public void setValid(boolean isValid);
+
+
+    /**
+     * Return the <code>isValid</code> flag for this session.
+     */
+    public boolean isValid();
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Update the accessed time information for this session.  This method
+     * should be called by the context when a request comes in for a particular
+     * session, even if the application does not reference it.
+     */
+    public void access();
+
+
+    /**
+     * Add a session event listener to this component.
+     */
+    public void addSessionListener(SessionListener listener);
+
+
+    /**
+     * End access to the session.
+     */
+    public void endAccess();
+
+
+    /**
+     * Perform the internal processing required to invalidate this session,
+     * without triggering an exception if the session has already expired.
+     */
+    public void expire();
+
+
+    /**
+     * Return the object bound with the specified name to the internal notes
+     * for this session, or <code>null</code> if no such binding exists.
+     *
+     * @param name Name of the note to be returned
+     */
+    public Object getNote(String name);
+
+
+    /**
+     * Return an Iterator containing the String names of all notes bindings
+     * that exist for this session.
+     */
+    public Iterator getNoteNames();
+
+
+    /**
+     * Release all object references, and initialize instance variables, in
+     * preparation for reuse of this object.
+     */
+    public void recycle();
+
+
+    /**
+     * Remove any object bound to the specified name in the internal notes
+     * for this session.
+     *
+     * @param name Name of the note to be removed
+     */
+    public void removeNote(String name);
+
+
+    /**
+     * Remove a session event listener from this component.
+     */
+    public void removeSessionListener(SessionListener listener);
+
+
+    /**
+     * Bind an object to a specified name in the internal notes associated
+     * with this session, replacing any existing binding for this name.
+     *
+     * @param name Name to which the object should be bound
+     * @param value Object to be bound to the specified name
+     */
+    public void setNote(String name, Object value);
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/SessionEvent.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/SessionEvent.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/SessionEvent.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,111 @@
+/*
+ * Copyright 1999-2001,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.util.EventObject;
+
+
+/**
+ * General event for notifying listeners of significant changes on a Session.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public final class SessionEvent
+    extends EventObject {
+
+
+    /**
+     * The event data associated with this event.
+     */
+    private Object data = null;
+
+
+    /**
+     * The Session on which this event occurred.
+     */
+    private Session session = null;
+
+
+    /**
+     * The event type this instance represents.
+     */
+    private String type = null;
+
+
+    /**
+     * Construct a new SessionEvent with the specified parameters.
+     *
+     * @param session Session on which this event occurred
+     * @param type Event type
+     * @param data Event data
+     */
+    public SessionEvent(Session session, String type, Object data) {
+
+        super(session);
+        this.session = session;
+        this.type = type;
+        this.data = data;
+
+    }
+
+
+    /**
+     * Return the event data of this event.
+     */
+    public Object getData() {
+
+        return (this.data);
+
+    }
+
+
+    /**
+     * Return the Session on which this event occurred.
+     */
+    public Session getSession() {
+
+        return (this.session);
+
+    }
+
+
+    /**
+     * Return the event type of this event.
+     */
+    public String getType() {
+
+        return (this.type);
+
+    }
+
+
+    /**
+     * Return a string representation of this event.
+     */
+    public String toString() {
+
+        return ("SessionEvent['" + getSession() + "','" +
+                getType() + "']");
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/SessionListener.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/SessionListener.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/SessionListener.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,41 @@
+/*
+ * Copyright 1999-2001,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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;
+
+
+
+
+/**
+ * Interface defining a listener for significant Session generated events.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public interface SessionListener {
+
+
+    /**
+     * Acknowledge the occurrence of the specified event.
+     *
+     * @param event SessionEvent that has occurred
+     */
+    public void sessionEvent(SessionEvent event);
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/Store.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/Store.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/Store.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,144 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.beans.PropertyChangeListener;
+import java.io.IOException;
+
+
+/**
+ * A <b>Store</b> is the abstraction of a Catalina component that provides
+ * persistent storage and loading of Sessions and their associated user data.
+ * Implementations are free to save and load the Sessions to any media they
+ * wish, but it is assumed that saved Sessions are persistent across
+ * server or context restarts.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public interface Store {
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * Return descriptive information about this Store implementation and
+     * the corresponding version number, in the format
+     * <code>&lt;description&gt;/&lt;version&gt;</code>.
+     */
+    public String getInfo();
+
+
+    /**
+     * Return the Manager instance associated with this Store.
+     */
+    public Manager getManager();
+
+
+    /**
+     * Set the Manager associated with this Store.
+     *
+     * @param manager The Manager which will use this Store.
+     */
+    public void setManager(Manager manager);
+
+
+    /**
+     * Return the number of Sessions present in this Store.
+     *
+     * @exception IOException if an input/output error occurs
+     */
+    public int getSize() throws IOException;
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Add a property change listener to this component.
+     *
+     * @param listener The listener to add
+     */
+    public void addPropertyChangeListener(PropertyChangeListener listener);
+
+
+    /**
+     * Return an array containing the session identifiers of all Sessions
+     * currently saved in this Store.  If there are no such Sessions, a
+     * zero-length array is returned.
+     *
+     * @exception IOException if an input/output error occurred
+     */
+    public String[] keys() throws IOException;
+
+
+    /**
+     * Load and return the Session associated with the specified session
+     * identifier from this Store, without removing it.  If there is no
+     * such stored Session, return <code>null</code>.
+     *
+     * @param id Session identifier of the session to load
+     *
+     * @exception ClassNotFoundException if a deserialization error occurs
+     * @exception IOException if an input/output error occurs
+     */
+    public Session load(String id)
+        throws ClassNotFoundException, IOException;
+
+
+    /**
+     * Remove the Session with the specified session identifier from
+     * this Store, if present.  If no such Session is present, this method
+     * takes no action.
+     *
+     * @param id Session identifier of the Session to be removed
+     *
+     * @exception IOException if an input/output error occurs
+     */
+    public void remove(String id) throws IOException;
+
+
+    /**
+     * Remove all Sessions from this Store.
+     */
+    public void clear() throws IOException;
+
+
+    /**
+     * Remove a property change listener from this component.
+     *
+     * @param listener The listener to remove
+     */
+    public void removePropertyChangeListener(PropertyChangeListener listener);
+
+
+    /**
+     * Save the specified Session into this Store.  Any previously saved
+     * information for the associated session identifier is replaced.
+     *
+     * @param session Session to be saved
+     *
+     * @exception IOException if an input/output error occurs
+     */
+    public void save(Session session) throws IOException;
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/User.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/User.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/User.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,173 @@
+/*
+ * Copyright 2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.security.Principal;
+import java.util.Iterator;
+
+
+/**
+ * <p>Abstract representation of a user in a {@link UserDatabase}.  Each user
+ * is optionally associated with a set of {@link Group}s through which he or
+ * she inherits additional security roles, and is optionally assigned a set
+ * of specific {@link Role}s.</p>
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ * @since 4.1
+ */
+
+public interface User extends Principal {
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * Return the full name of this user.
+     */
+    public String getFullName();
+
+
+    /**
+     * Set the full name of this user.
+     *
+     * @param fullName The new full name
+     */
+    public void setFullName(String fullName);
+
+
+    /**
+     * Return the set of {@link Group}s to which this user belongs.
+     */
+    public Iterator getGroups();
+
+
+    /**
+     * Return the logon password of this user, optionally prefixed with the
+     * identifier of an encoding scheme surrounded by curly braces, such as
+     * <code>{md5}xxxxx</code>.
+     */
+    public String getPassword();
+
+
+    /**
+     * Set the logon password of this user, optionally prefixed with the
+     * identifier of an encoding scheme surrounded by curly braces, such as
+     * <code>{md5}xxxxx</code>.
+     *
+     * @param password The new logon password
+     */
+    public void setPassword(String password);
+
+
+    /**
+     * Return the set of {@link Role}s assigned specifically to this user.
+     */
+    public Iterator getRoles();
+
+
+    /**
+     * Return the {@link UserDatabase} within which this User is defined.
+     */
+    public UserDatabase getUserDatabase();
+
+
+    /**
+     * Return the logon username of this user, which must be unique
+     * within the scope of a {@link UserDatabase}.
+     */
+    public String getUsername();
+
+
+    /**
+     * Set the logon username of this user, which must be unique within
+     * the scope of a {@link UserDatabase}.
+     *
+     * @param username The new logon username
+     */
+    public void setUsername(String username);
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Add a new {@link Group} to those this user belongs to.
+     *
+     * @param group The new group
+     */
+    public void addGroup(Group group);
+
+
+    /**
+     * Add a {@link Role} to those assigned specifically to this user.
+     *
+     * @param role The new role
+     */
+    public void addRole(Role role);
+
+
+    /**
+     * Is this user in the specified {@link Group}?
+     *
+     * @param group The group to check
+     */
+    public boolean isInGroup(Group group);
+
+
+    /**
+     * Is this user specifically assigned the specified {@link Role}?  This
+     * method does <strong>NOT</strong> check for roles inherited based on
+     * {@link Group} membership.
+     *
+     * @param role The role to check
+     */
+    public boolean isInRole(Role role);
+
+
+    /**
+     * Remove a {@link Group} from those this user belongs to.
+     *
+     * @param group The old group
+     */
+    public void removeGroup(Group group);
+
+
+    /**
+     * Remove all {@link Group}s from those this user belongs to.
+     */
+    public void removeGroups();
+
+
+    /**
+     * Remove a {@link Role} from those assigned to this user.
+     *
+     * @param role The old role
+     */
+    public void removeRole(Role role);
+
+
+    /**
+     * Remove all {@link Role}s from those assigned to this user.
+     */
+    public void removeRoles();
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/UserDatabase.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/UserDatabase.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/UserDatabase.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,173 @@
+/*
+ * Copyright 2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.util.Iterator;
+
+
+/**
+ * <p>Abstract representation of a database of {@link User}s and
+ * {@link Group}s that can be maintained by an application,
+ * along with definitions of corresponding {@link Role}s, and
+ * referenced by a {@link Realm} for authentication and access control.</p>
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ * @since 4.1
+ */
+
+public interface UserDatabase {
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * Return the set of {@link Group}s defined in this user database.
+     */
+    public Iterator getGroups();
+
+
+    /**
+     * Return the unique global identifier of this user database.
+     */
+    public String getId();
+
+
+    /**
+     * Return the set of {@link Role}s defined in this user database.
+     */
+    public Iterator getRoles();
+
+
+    /**
+     * Return the set of {@link User}s defined in this user database.
+     */
+    public Iterator getUsers();
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Finalize access to this user database.
+     *
+     * @exception Exception if any exception is thrown during closing
+     */
+    public void close() throws Exception;
+
+
+    /**
+     * Create and return a new {@link Group} defined in this user database.
+     *
+     * @param groupname The group name of the new group (must be unique)
+     * @param description The description of this group
+     */
+    public Group createGroup(String groupname, String description);
+
+
+    /**
+     * Create and return a new {@link Role} defined in this user database.
+     *
+     * @param rolename The role name of the new role (must be unique)
+     * @param description The description of this role
+     */
+    public Role createRole(String rolename, String description);
+
+
+    /**
+     * Create and return a new {@link User} defined in this user database.
+     *
+     * @param username The logon username of the new user (must be unique)
+     * @param password The logon password of the new user
+     * @param fullName The full name of the new user
+     */
+    public User createUser(String username, String password,
+                           String fullName);
+
+
+    /**
+     * Return the {@link Group} with the specified group name, if any;
+     * otherwise return <code>null</code>.
+     *
+     * @param groupname Name of the group to return
+     */
+    public Group findGroup(String groupname);
+
+
+    /**
+     * Return the {@link Role} with the specified role name, if any;
+     * otherwise return <code>null</code>.
+     *
+     * @param rolename Name of the role to return
+     */
+    public Role findRole(String rolename);
+
+
+    /**
+     * Return the {@link User} with the specified user name, if any;
+     * otherwise return <code>null</code>.
+     *
+     * @param username Name of the user to return
+     */
+    public User findUser(String username);
+
+
+    /**
+     * Initialize access to this user database.
+     *
+     * @exception Exception if any exception is thrown during opening
+     */
+    public void open() throws Exception;
+
+
+    /**
+     * Remove the specified {@link Group} from this user database.
+     *
+     * @param group The group to be removed
+     */
+    public void removeGroup(Group group);
+
+
+    /**
+     * Remove the specified {@link Role} from this user database.
+     *
+     * @param role The role to be removed
+     */
+    public void removeRole(Role role);
+
+
+    /**
+     * Remove the specified {@link User} from this user database.
+     *
+     * @param user The user to be removed
+     */
+    public void removeUser(User user);
+
+
+    /**
+     * Save any updated information to the persistent storage location for
+     * this user database.
+     *
+     * @exception Exception if any exception is thrown during saving
+     */
+    public void save() throws Exception;
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/Valve.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/Valve.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/Valve.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,132 @@
+/*
+ * Copyright 1999-2001,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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 org.apache.catalina.connector.Request;
+import org.apache.catalina.connector.Response;
+
+
+/**
+ * <p>A <b>Valve</b> is a request processing component associated with a
+ * particular Container.  A series of Valves are generally associated with
+ * each other into a Pipeline.  The detailed contract for a Valve is included
+ * in the description of the <code>invoke()</code> method below.</p>
+ *
+ * <b>HISTORICAL NOTE</b>:  The "Valve" name was assigned to this concept
+ * because a valve is what you use in a real world pipeline to control and/or
+ * modify flows through it.
+ *
+ * @author Craig R. McClanahan
+ * @author Gunnar Rjnning
+ * @author Peter Donald
+ * @version $Revision: 303352 $ $Date: 2004-10-05 12:12:52 -0500 (Tue, 05 Oct 2004) $
+ */
+
+public interface Valve {
+
+
+    //-------------------------------------------------------------- Properties
+
+
+    /**
+     * Return descriptive information about this Valve implementation.
+     */
+    public String getInfo();
+
+
+    /**
+     * Return the next Valve in the pipeline containing this Valve, if any.
+     */
+    public Valve getNext();
+
+
+    /**
+     * Set the next Valve in the pipeline containing this Valve.
+     *
+     * @param valve The new next valve, or <code>null</code> if none
+     */
+    public void setNext(Valve valve);
+
+
+    //---------------------------------------------------------- Public Methods
+
+
+    /**
+     * Execute a periodic task, such as reloading, etc. This method will be
+     * invoked inside the classloading context of this container. Unexpected
+     * throwables will be caught and logged.
+     */
+    public void backgroundProcess();
+
+
+    /**
+     * <p>Perform request processing as required by this Valve.</p>
+     *
+     * <p>An individual Valve <b>MAY</b> perform the following actions, in
+     * the specified order:</p>
+     * <ul>
+     * <li>Examine and/or modify the properties of the specified Request and
+     *     Response.
+     * <li>Examine the properties of the specified Request, completely generate
+     *     the corresponding Response, and return control to the caller.
+     * <li>Examine the properties of the specified Request and Response, wrap
+     *     either or both of these objects to supplement their functionality,
+     *     and pass them on.
+     * <li>If the corresponding Response was not generated (and control was not
+     *     returned, call the next Valve in the pipeline (if there is one) by
+     *     executing <code>context.invokeNext()</code>.
+     * <li>Examine, but not modify, the properties of the resulting Response
+     *     (which was created by a subsequently invoked Valve or Container).
+     * </ul>
+     *
+     * <p>A Valve <b>MUST NOT</b> do any of the following things:</p>
+     * <ul>
+     * <li>Change request properties that have already been used to direct
+     *     the flow of processing control for this request (for instance,
+     *     trying to change the virtual host to which a Request should be
+     *     sent from a pipeline attached to a Host or Context in the
+     *     standard implementation).
+     * <li>Create a completed Response <strong>AND</strong> pass this
+     *     Request and Response on to the next Valve in the pipeline.
+     * <li>Consume bytes from the input stream associated with the Request,
+     *     unless it is completely generating the response, or wrapping the
+     *     request before passing it on.
+     * <li>Modify the HTTP headers included with the Response after the
+     *     <code>invokeNext()</code> method has returned.
+     * <li>Perform any actions on the output stream associated with the
+     *     specified Response after the <code>invokeNext()</code> method has
+     *     returned.
+     * </ul>
+     *
+     * @param request The servlet request to be processed
+     * @param response The servlet response to be created
+     *
+     * @exception IOException if an input/output error occurs, or is thrown
+     *  by a subsequently invoked Valve, Filter, or Servlet
+     * @exception ServletException if a servlet error occurs, or is thrown
+     *  by a subsequently invoked Valve, Filter, or Servlet
+     */
+    public void invoke(Request request, Response response)
+        throws IOException, ServletException;
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/Wrapper.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/Wrapper.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/Wrapper.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,330 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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 javax.servlet.Servlet;
+import javax.servlet.ServletException;
+import javax.servlet.UnavailableException;
+
+
+/**
+ * A <b>Wrapper</b> is a Container that represents an individual servlet
+ * definition from the deployment descriptor of the web application.  It
+ * provides a convenient mechanism to use Interceptors that see every single
+ * request to the servlet represented by this definition.
+ * <p>
+ * Implementations of Wrapper are responsible for managing the servlet life
+ * cycle for their underlying servlet class, including calling init() and
+ * destroy() at appropriate times, as well as respecting the existence of
+ * the SingleThreadModel declaration on the servlet class itself.
+ * <p>
+ * The parent Container attached to a Wrapper will generally be an
+ * implementation of Context, representing the servlet context (and
+ * therefore the web application) within which this servlet executes.
+ * <p>
+ * Child Containers are not allowed on Wrapper implementations, so the
+ * <code>addChild()</code> method should throw an
+ * <code>IllegalArgumentException</code>.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 303442 $ $Date: 2004-10-27 17:58:17 -0500 (Wed, 27 Oct 2004) $
+ */
+
+public interface Wrapper extends Container {
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * Return the available date/time for this servlet, in milliseconds since
+     * the epoch.  If this date/time is in the future, any request for this
+     * servlet will return an SC_SERVICE_UNAVAILABLE error.  If it is zero,
+     * the servlet is currently available.  A value equal to Long.MAX_VALUE
+     * is considered to mean that unavailability is permanent.
+     */
+    public long getAvailable();
+
+
+    /**
+     * Set the available date/time for this servlet, in milliseconds since the
+     * epoch.  If this date/time is in the future, any request for this servlet
+     * will return an SC_SERVICE_UNAVAILABLE error.  A value equal to
+     * Long.MAX_VALUE is considered to mean that unavailability is permanent.
+     *
+     * @param available The new available date/time
+     */
+    public void setAvailable(long available);
+
+
+    /**
+     * Return the context-relative URI of the JSP file for this servlet.
+     */
+    public String getJspFile();
+
+
+    /**
+     * Set the context-relative URI of the JSP file for this servlet.
+     *
+     * @param jspFile JSP file URI
+     */
+    public void setJspFile(String jspFile);
+
+
+    /**
+     * Return the load-on-startup order value (negative value means
+     * load on first call).
+     */
+    public int getLoadOnStartup();
+
+
+    /**
+     * Set the load-on-startup order value (negative value means
+     * load on first call).
+     *
+     * @param value New load-on-startup value
+     */
+    public void setLoadOnStartup(int value);
+
+
+    /**
+     * Return the run-as identity for this servlet.
+     */
+    public String getRunAs();
+
+
+    /**
+     * Set the run-as identity for this servlet.
+     *
+     * @param runAs New run-as identity value
+     */
+    public void setRunAs(String runAs);
+
+
+    /**
+     * Return the fully qualified servlet class name for this servlet.
+     */
+    public String getServletClass();
+
+
+    /**
+     * Set the fully qualified servlet class name for this servlet.
+     *
+     * @param servletClass Servlet class name
+     */
+    public void setServletClass(String servletClass);
+
+
+    /**
+     * Gets the names of the methods supported by the underlying servlet.
+     *
+     * This is the same set of methods included in the Allow response header
+     * in response to an OPTIONS request method processed by the underlying
+     * servlet.
+     *
+     * @return Array of names of the methods supported by the underlying
+     * servlet
+     */
+    public String[] getServletMethods() throws ServletException;
+
+
+    /**
+     * Is this servlet currently unavailable?
+     */
+    public boolean isUnavailable();
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Add a new servlet initialization parameter for this servlet.
+     *
+     * @param name Name of this initialization parameter to add
+     * @param value Value of this initialization parameter to add
+     */
+    public void addInitParameter(String name, String value);
+
+
+    /**
+     * Add a new listener interested in InstanceEvents.
+     *
+     * @param listener The new listener
+     */
+    public void addInstanceListener(InstanceListener listener);
+
+
+    /**
+     * Add a mapping associated with the Wrapper.
+     * 
+     * @param mapping The new wrapper mapping
+     */
+    public void addMapping(String mapping);
+
+
+    /**
+     * Add a new security role reference record to the set of records for
+     * this servlet.
+     *
+     * @param name Role name used within this servlet
+     * @param link Role name used within the web application
+     */
+    public void addSecurityReference(String name, String link);
+
+
+    /**
+     * Allocate an initialized instance of this Servlet that is ready to have
+     * its <code>service()</code> method called.  If the servlet class does
+     * not implement <code>SingleThreadModel</code>, the (only) initialized
+     * instance may be returned immediately.  If the servlet class implements
+     * <code>SingleThreadModel</code>, the Wrapper implementation must ensure
+     * that this instance is not allocated again until it is deallocated by a
+     * call to <code>deallocate()</code>.
+     *
+     * @exception ServletException if the servlet init() method threw
+     *  an exception
+     * @exception ServletException if a loading error occurs
+     */
+    public Servlet allocate() throws ServletException;
+
+
+    /**
+     * Return this previously allocated servlet to the pool of available
+     * instances.  If this servlet class does not implement SingleThreadModel,
+     * no action is actually required.
+     *
+     * @param servlet The servlet to be returned
+     *
+     * @exception ServletException if a deallocation error occurs
+     */
+    public void deallocate(Servlet servlet) throws ServletException;
+
+
+    /**
+     * Return the value for the specified initialization parameter name,
+     * if any; otherwise return <code>null</code>.
+     *
+     * @param name Name of the requested initialization parameter
+     */
+    public String findInitParameter(String name);
+
+
+    /**
+     * Return the names of all defined initialization parameters for this
+     * servlet.
+     */
+    public String[] findInitParameters();
+
+
+    /**
+     * Return the mappings associated with this wrapper.
+     */
+    public String[] findMappings();
+
+
+    /**
+     * Return the security role link for the specified security role
+     * reference name, if any; otherwise return <code>null</code>.
+     *
+     * @param name Security role reference used within this servlet
+     */
+    public String findSecurityReference(String name);
+
+
+    /**
+     * Return the set of security role reference names associated with
+     * this servlet, if any; otherwise return a zero-length array.
+     */
+    public String[] findSecurityReferences();
+
+
+    /**
+     * Increment the error count value used when monitoring.
+     */
+    public void incrementErrorCount();
+
+
+    /**
+     * Load and initialize an instance of this servlet, if there is not already
+     * at least one initialized instance.  This can be used, for example, to
+     * load servlets that are marked in the deployment descriptor to be loaded
+     * at server startup time.
+     *
+     * @exception ServletException if the servlet init() method threw
+     *  an exception
+     * @exception ServletException if some other loading problem occurs
+     */
+    public void load() throws ServletException;
+
+
+    /**
+     * Remove the specified initialization parameter from this servlet.
+     *
+     * @param name Name of the initialization parameter to remove
+     */
+    public void removeInitParameter(String name);
+
+
+    /**
+     * Remove a listener no longer interested in InstanceEvents.
+     *
+     * @param listener The listener to remove
+     */
+    public void removeInstanceListener(InstanceListener listener);
+
+
+    /**
+     * Remove a mapping associated with the wrapper.
+     *
+     * @param mapping The pattern to remove
+     */
+    public void removeMapping(String mapping);
+
+
+    /**
+     * Remove any security role reference for the specified role name.
+     *
+     * @param name Security role used within this servlet to be removed
+     */
+    public void removeSecurityReference(String name);
+
+
+    /**
+     * Process an UnavailableException, marking this servlet as unavailable
+     * for the specified amount of time.
+     *
+     * @param unavailable The exception that occurred, or <code>null</code>
+     *  to mark this servlet as permanently unavailable
+     */
+    public void unavailable(UnavailableException unavailable);
+
+
+    /**
+     * Unload all initialized instances of this servlet, after calling the
+     * <code>destroy()</code> method for each instance.  This can be used,
+     * for example, prior to shutting down the entire servlet engine, or
+     * prior to reloading all of the classes from the Loader associated with
+     * our Loader's repository.
+     *
+     * @exception ServletException if an unload error occurs
+     */
+    public void unload() throws ServletException;
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ant/AbstractCatalinaTask.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ant/AbstractCatalinaTask.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ant/AbstractCatalinaTask.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,288 @@
+/*
+ * Copyright 2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.ant;
+
+
+import java.io.BufferedOutputStream;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.net.URLConnection;
+import org.apache.catalina.util.Base64;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+
+
+/**
+ * Abstract base class for Ant tasks that interact with the
+ * <em>Manager</em> web application for dynamically deploying and
+ * undeploying applications.  These tasks require Ant 1.4 or later.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 303657 $ $Date: 2005-01-22 10:34:47 -0600 (Sat, 22 Jan 2005) $
+ * @since 4.1
+ */
+
+public abstract class AbstractCatalinaTask extends BaseRedirectorHelperTask {
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * manager webapp's encoding.
+     */ 
+    private static String CHARSET = "utf-8";
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * The charset used during URL encoding.
+     */
+    protected String charset = "ISO-8859-1";
+
+    public String getCharset() {
+        return (this.charset);
+    }
+
+    public void setCharset(String charset) {
+        this.charset = charset;
+    }
+
+
+    /**
+     * The login password for the <code>Manager</code> application.
+     */
+    protected String password = null;
+
+    public String getPassword() {
+        return (this.password);
+    }
+
+    public void setPassword(String password) {
+        this.password = password;
+    }
+
+
+    /**
+     * The URL of the <code>Manager</code> application to be used.
+     */
+    protected String url = "http://localhost:8080/manager";
+
+    public String getUrl() {
+        return (this.url);
+    }
+
+    public void setUrl(String url) {
+        this.url = url;
+    }
+
+
+    /**
+     * The login username for the <code>Manager</code> application.
+     */
+    protected String username = null;
+
+    public String getUsername() {
+        return (this.username);
+    }
+
+    public void setUsername(String username) {
+        this.username = username;
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Execute the specified command.  This logic only performs the common
+     * attribute validation required by all subclasses; it does not perform
+     * any functional logic directly.
+     *
+     * @exception BuildException if a validation error occurs
+     */
+    public void execute() throws BuildException {
+
+        if ((username == null) || (password == null) || (url == null)) {
+            throw new BuildException
+                ("Must specify all of 'username', 'password', and 'url'");
+        }
+
+    }
+
+
+    // ------------------------------------------------------ Protected Methods
+
+
+    /**
+     * Execute the specified command, based on the configured properties.
+     *
+     * @param command Command to be executed
+     *
+     * @exception BuildException if an error occurs
+     */
+    public void execute(String command) throws BuildException {
+
+        execute(command, null, null, -1);
+
+    }
+
+
+    /**
+     * Execute the specified command, based on the configured properties.
+     * The input stream will be closed upon completion of this task, whether
+     * it was executed successfully or not.
+     *
+     * @param command Command to be executed
+     * @param istream InputStream to include in an HTTP PUT, if any
+     * @param contentType Content type to specify for the input, if any
+     * @param contentLength Content length to specify for the input, if any
+     *
+     * @exception BuildException if an error occurs
+     */
+    public void execute(String command, InputStream istream,
+                        String contentType, int contentLength)
+        throws BuildException {
+
+        URLConnection conn = null;
+        InputStreamReader reader = null;
+        try {
+
+            // Create a connection for this command
+            conn = (new URL(url + command)).openConnection();
+            HttpURLConnection hconn = (HttpURLConnection) conn;
+
+            // Set up standard connection characteristics
+            hconn.setAllowUserInteraction(false);
+            hconn.setDoInput(true);
+            hconn.setUseCaches(false);
+            if (istream != null) {
+                hconn.setDoOutput(true);
+                hconn.setRequestMethod("PUT");
+                if (contentType != null) {
+                    hconn.setRequestProperty("Content-Type", contentType);
+                }
+                if (contentLength >= 0) {
+                    hconn.setRequestProperty("Content-Length",
+                                             "" + contentLength);
+                }
+            } else {
+                hconn.setDoOutput(false);
+                hconn.setRequestMethod("GET");
+            }
+            hconn.setRequestProperty("User-Agent",
+                                     "Catalina-Ant-Task/1.0");
+
+            // Set up an authorization header with our credentials
+            String input = username + ":" + password;
+            String output = new String(Base64.encode(input.getBytes()));
+            hconn.setRequestProperty("Authorization",
+                                     "Basic " + output);
+
+            // Establish the connection with the server
+            hconn.connect();
+
+            // Send the request data (if any)
+            if (istream != null) {
+                BufferedOutputStream ostream =
+                    new BufferedOutputStream(hconn.getOutputStream(), 1024);
+                byte buffer[] = new byte[1024];
+                while (true) {
+                    int n = istream.read(buffer);
+                    if (n < 0) {
+                        break;
+                    }
+                    ostream.write(buffer, 0, n);
+                }
+                ostream.flush();
+                ostream.close();
+                istream.close();
+            }
+
+            // Process the response message
+            reader = new InputStreamReader(hconn.getInputStream(), CHARSET);
+            StringBuffer buff = new StringBuffer();
+            String error = null;
+            int msgPriority = Project.MSG_INFO;
+            boolean first = true;
+            while (true) {
+                int ch = reader.read();
+                if (ch < 0) {
+                    break;
+                } else if ((ch == '\r') || (ch == '\n')) {
+                    // in Win \r\n would cause handleOutput() to be called
+                    // twice, the second time with an empty string,
+                    // producing blank lines
+                    if (buff.length() > 0) {
+                        String line = buff.toString();
+                        buff.setLength(0);
+                        if (first) {
+                            if (!line.startsWith("OK -")) {
+                                error = line;
+                                msgPriority = Project.MSG_ERR;
+                            }
+                            first = false;
+                        }
+                        handleOutput(line, msgPriority);
+                    }
+                } else {
+                    buff.append((char) ch);
+                }
+            }
+            if (buff.length() > 0) {
+                handleOutput(buff.toString(), msgPriority);
+            }
+            if (error != null && isFailOnError()) {
+                // exception should be thrown only if failOnError == true
+                // or error line will be logged twice
+                throw new BuildException(error);
+            }
+        } catch (Throwable t) {
+            if (isFailOnError()) {
+                throw new BuildException(t);
+            } else {
+                handleErrorOutput(t.getMessage());
+            }
+        } finally {
+            closeRedirector();
+            if (reader != null) {
+                try {
+                    reader.close();
+                } catch (Throwable u) {
+                    ;
+                }
+                reader = null;
+            }
+            if (istream != null) {
+                try {
+                    istream.close();
+                } catch (Throwable u) {
+                    ;
+                }
+                istream = null;
+            }
+        }
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ant/BaseRedirectorHelperTask.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ant/BaseRedirectorHelperTask.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ant/BaseRedirectorHelperTask.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,370 @@
+/*
+ * Copyright 2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.ant;
+
+
+import java.io.File;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.PrintStream;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.taskdefs.Redirector;
+import org.apache.tools.ant.types.RedirectorElement;
+
+
+/**
+ * Abstract base class to add output redirection support for Catalina
+ * Ant tasks. These tasks require Ant 1.5 or later.
+ * <br>
+ * <strong>WARNING:</strong> due to depends chain, Ant could call a Task 
+ * more than once and this can affect the output redirection when configured.
+ * If you are collecting the output in a property, it will collect the output
+ * of only the first run, since Ant properties are immutable and once created
+ * they cannot be changed.
+ * <br>
+ * If you are collecting output in a file the file will be overwritten with the
+ * output of the last run, unless you set append="true", in which case each run 
+ * will append it's output to the file.
+ * 
+ *
+ * @author Gabriele Garuglieri
+ * @version $Revision: 303609 $ $Date: 2005-01-03 10:21:21 -0600 (Mon, 03 Jan 2005) $
+ * @since 5.5
+ */
+
+public abstract class BaseRedirectorHelperTask extends Task {
+
+    // ------------------------------------------------------------- Properties
+
+    /** Redirector helper */
+    protected Redirector redirector = new Redirector(this);
+    //protected Redirector redirector = null;
+    /** Redirector element for this task */
+    protected RedirectorElement redirectorElement = null;
+    /** The stream for info output */
+    protected OutputStream redirectOutStream = null;
+    /** The stream for error output */
+    protected OutputStream redirectErrStream = null;
+    /** The print stream for info output */
+    PrintStream redirectOutPrintStream = null;
+    /** The print stream for error output */
+    PrintStream redirectErrPrintStream = null;
+        
+   /**
+     * Whether to fail (with a BuildException) if
+     * ManagerServlet returns an error. The default behavior is
+     * to do so.
+     * <b>
+     * This flag does not control parameters checking. If the task is called
+     * with wrong or invalid parameters, it will throw BuildException
+     * independently from the setting of this flag.
+     */    
+    protected boolean failOnError = true;
+    
+    /** 
+      * <code>true</code> true when output redirection is requested for this task .
+      * Default is to log on Ant log.
+      */    
+    protected boolean redirectOutput = false;
+ 
+    /** 
+      * will be set to <code>true</code> when the configuration of the Redirector is
+      * complete.
+      */    
+    protected boolean redirectorConfigured = false;
+
+    /** 
+     * Flag which indicates that, if redirected, output should also be 
+     * always sent to the log. Default is that otput is sent only to
+     * redirected streams.
+     */
+    protected boolean alwaysLog = false;
+
+    /**
+     * Whether to fail (with a BuildException) if
+     * ManagerServlet returns an error.  The default behavior is
+     * to do so.
+     */
+    public void setFailonerror(boolean fail) {
+        failOnError = fail;
+    }
+
+    /**
+     * Returns the value of the failOnError
+     * property.
+     */
+    public boolean isFailOnError() {
+      return failOnError;
+    }
+        
+
+    /**
+     * File the output of the task is redirected to.
+     *
+     * @param out name of the output file
+     */
+    public void setOutput(File out) {
+        redirector.setOutput(out);
+        redirectOutput = true;
+    }
+
+    /**
+     * File the error output of the task is redirected to.
+     *
+     * @param error name of the error file
+     *
+     */
+    public void setError(File error) {
+        redirector.setError(error);
+        redirectOutput = true;
+    }
+
+    /**
+     * Controls whether error output is logged. This is only useful
+     * when output is being redirected and error output is desired in the
+     * Ant log
+     *
+     * @param logError if true the standard error is sent to the Ant log system
+     *        and not sent to output stream.
+     */
+    public void setLogError(boolean logError) {
+        redirector.setLogError(logError);
+        redirectOutput = true;
+    }
+
+    /**
+     * Property name whose value should be set to the output of
+     * the task.
+     *
+     * @param outputProperty property name
+     *
+     */
+    public void setOutputproperty(String outputProperty) {
+        redirector.setOutputProperty(outputProperty);
+        redirectOutput = true;
+    }
+
+    /**
+     * Property name whose value should be set to the error of
+     * the task..
+     *
+     * @param errorProperty property name
+     *
+     */
+    public void setErrorProperty(String errorProperty) {
+        redirector.setErrorProperty(errorProperty);
+        redirectOutput = true;
+    }
+
+    /**
+     * If true, append output to existing file.
+     *
+     * @param append if true, append output to existing file
+     *
+     */
+    public void setAppend(boolean append) {
+        redirector.setAppend(append);
+        redirectOutput = true;
+    }
+
+    /**
+     * If true, (error and non-error) output will be redirected
+     * as specified while being sent to Ant's logging mechanism as if no
+     * redirection had taken place.  Defaults to false.
+     * <br>
+     * Actually handled internally, with Ant 1.6.3 it will be handled by
+     * the <code>Redirector</code> itself.
+     * @param alwaysLog <code>boolean</code>
+     */
+    public void setAlwaysLog(boolean alwaysLog) {
+        this.alwaysLog = alwaysLog;
+        //redirector.setAlwaysLog(alwaysLog);
+        redirectOutput = true;
+    }
+
+    /**
+     * Whether output and error files should be created even when empty.
+     * Defaults to true.
+     * @param createEmptyFiles <CODE>boolean</CODE>.
+     */
+    public void setCreateEmptyFiles(boolean createEmptyFiles) {
+        redirector.setCreateEmptyFiles(createEmptyFiles);
+        redirectOutput = true;
+    }
+
+    /**
+     * Add a <CODE>RedirectorElement</CODE> to this task.
+     * @param redirectorElement   <CODE>RedirectorElement</CODE>.
+     */
+    public void addConfiguredRedirector(RedirectorElement redirectorElement) {
+        if (this.redirectorElement != null) {
+            throw new BuildException("Cannot have > 1 nested <redirector>s");
+        } else {
+            this.redirectorElement = redirectorElement;
+        }
+    }
+
+    /**
+     * Set up properties on the Redirector from RedirectorElement if present.
+     */
+    private void configureRedirector() {
+        if (redirectorElement != null) {
+            redirectorElement.configure(redirector);
+            redirectOutput = true;
+        }
+        /*
+         * Due to depends chain, Ant could call the Task more than once,
+         * this is to prevent that we attempt to configure uselessly
+         * more than once the Redirector.
+         */
+        redirectorConfigured = true;
+    }
+
+    /**
+     * Set up properties on the Redirector and create output streams.
+     */
+    protected void openRedirector() {
+        if (! redirectorConfigured) {
+            configureRedirector();
+        }
+        if (redirectOutput) {
+            redirector.createStreams();
+            redirectOutStream = redirector.getOutputStream();
+            redirectOutPrintStream = new PrintStream(redirectOutStream);
+            redirectErrStream = redirector.getErrorStream();
+            redirectErrPrintStream = new PrintStream(redirectErrStream);
+        }
+   }
+
+    /**
+     * Ask redirector to close all the streams. It is necessary to call this method
+     * before leaving the Task to have the Streams flush their contents. If you are 
+     * collecting output in a property, it will be created only if this method is
+     * called, otherwise you'll find it unset.
+     */
+    protected void closeRedirector() {
+        try {
+            if (redirectOutput) {
+                redirector.complete();
+            }
+        } catch (IOException ioe) {
+            log("Error closing redirector: "
+                + ioe.getMessage(), Project.MSG_ERR);
+        }
+        /*
+         * Due to depends chain, Ant could call the Task more than once,
+         * this is to prevent that we attempt to reuse the previuosly 
+         * closed Streams.
+         */
+        redirectOutStream = null;
+        redirectOutPrintStream = null;
+        redirectErrStream = null;
+        redirectErrPrintStream = null;
+    }
+    
+    /**
+     * Handles output with the INFO priority.
+     *
+     * @param output The output to log. Should not be <code>null</code>.
+     */
+    protected void handleOutput(String output) {
+        if (redirectOutput) {
+            if (redirectOutPrintStream == null) {
+                openRedirector();
+            }
+            redirectOutPrintStream.println(output);
+            if (alwaysLog) {
+                log(output, Project.MSG_INFO);
+            }
+        } else { 
+            log(output, Project.MSG_INFO);
+        }
+    }
+
+    /**
+     * Handles output with the INFO priority and flushes the stream.
+     *
+     * @param output The output to log. Should not be <code>null</code>.
+     *
+     */
+    protected void handleFlush(String output) {
+        handleOutput(output);
+        redirectOutPrintStream.flush();
+    }
+
+    /**
+     * Handles error output with the ERR priority.
+     *
+     * @param output The error output to log. Should not be <code>null</code>.
+     */
+    protected void handleErrorOutput(String output) {
+        if (redirectOutput) {
+            if (redirectErrPrintStream == null) {
+                openRedirector();
+            }
+            redirectErrPrintStream.println(output);
+            if (alwaysLog) {
+                log(output, Project.MSG_ERR);
+            }
+        } else { 
+            log(output, Project.MSG_ERR);
+        }
+    }
+
+    /**
+     * Handles error output with the ERR priority and flushes the stream.
+     *
+     * @param output The error output to log. Should not be <code>null</code>.
+     *
+     */
+    protected void handleErrorFlush(String output) {
+        handleErrorOutput(output);
+        redirectErrPrintStream.flush();
+    }
+  
+    /**
+     * Handles output with ERR priority to error stream and all other
+     * pritorities to output stream.
+     *
+     * @param output The output to log. Should not be <code>null</code>.
+     */
+    protected void handleOutput(String output, int priority) {
+        if (priority == Project.MSG_ERR) {
+            handleErrorOutput(output);
+        } else {
+            handleOutput(output);
+        }
+    }
+  
+    /**
+     * Handles output with ERR priority to error stream and all other
+     * pritorities to output stream, then flushes the stream.
+     *
+     * @param output The output to log. Should not be <code>null</code>.
+     */
+    protected void handleFlush(String output, int priority) {
+        if (priority == Project.MSG_ERR) {
+            handleErrorFlush(output);
+        } else {
+            handleFlush(output);
+        }
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ant/DeployTask.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ant/DeployTask.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ant/DeployTask.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,205 @@
+/*
+ * Copyright 2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.ant;
+
+
+import java.io.BufferedInputStream;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.net.URL;
+import java.net.URLConnection;
+import java.net.URLEncoder;
+
+import org.apache.tools.ant.BuildException;
+
+
+/**
+ * Ant task that implements the <code>/deploy</code> command, supported by
+ * the Tomcat manager application.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 303657 $ $Date: 2005-01-22 10:34:47 -0600 (Sat, 22 Jan 2005) $
+ * @since 4.1
+ */
+public class DeployTask extends AbstractCatalinaTask {
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * URL of the context configuration file for this application, if any.
+     */
+    protected String config = null;
+
+    public String getConfig() {
+        return (this.config);
+    }
+
+    public void setConfig(String config) {
+        this.config = config;
+    }
+
+
+    /**
+     * URL of the server local web application archive (WAR) file 
+     * to be deployed.
+     */
+    protected String localWar = null;
+
+    public String getLocalWar() {
+        return (this.localWar);
+    }
+
+    public void setLocalWar(String localWar) {
+        this.localWar = localWar;
+    }
+
+
+    /**
+     * The context path of the web application we are managing.
+     */
+    protected String path = null;
+
+    public String getPath() {
+        return (this.path);
+    }
+
+    public void setPath(String path) {
+        this.path = path;
+    }
+
+
+    /**
+     * Tag to associate with this to be deployed webapp.
+     */
+    protected String tag = null;
+
+    public String getTag() {
+        return (this.tag);
+    }
+
+    public void setTag(String tag) {
+        this.tag = tag;
+    }
+
+
+    /**
+     * Update existing webapps.
+     */
+    protected boolean update = false;
+
+    public boolean getUpdate() {
+        return (this.update);
+    }
+
+    public void setUpdate(boolean update) {
+        this.update = update;
+    }
+
+
+    /**
+     * URL of the web application archive (WAR) file to be deployed.
+     */
+    protected String war = null;
+
+    public String getWar() {
+        return (this.war);
+    }
+
+    public void setWar(String war) {
+        this.war = war;
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Execute the requested operation.
+     *
+     * @exception BuildException if an error occurs
+     */
+    public void execute() throws BuildException {
+
+        super.execute();
+        if (path == null) {
+            throw new BuildException
+                ("Must specify 'path' attribute");
+        }
+        if ((war == null) && (localWar == null) && (config == null) && (tag == null)) {
+            throw new BuildException
+                ("Must specify either 'war', 'localWar', 'config', or 'tag' attribute");
+        }
+
+        // Building an input stream on the WAR to upload, if any
+        BufferedInputStream stream = null;
+        String contentType = null;
+        int contentLength = -1;
+        if (war != null) {
+            if (war.startsWith("file:")) {
+                try {
+                    URL url = new URL(war);
+                    URLConnection conn = url.openConnection();
+                    contentLength = conn.getContentLength();
+                    stream = new BufferedInputStream
+                        (conn.getInputStream(), 1024);
+                } catch (IOException e) {
+                    throw new BuildException(e);
+                }
+            } else {
+                try {
+                    stream = new BufferedInputStream
+                        (new FileInputStream(war), 1024);
+                } catch (IOException e) {
+                    throw new BuildException(e);
+                }
+            }
+            contentType = "application/octet-stream";
+        }
+
+        // Building URL
+        StringBuffer sb = new StringBuffer("/deploy?path=");
+        try {
+            sb.append(URLEncoder.encode(this.path, getCharset()));
+            if ((war == null) && (config != null)) {
+                sb.append("&config=");
+                sb.append(URLEncoder.encode(config, getCharset()));
+            }
+            if ((war == null) && (localWar != null)) {
+                sb.append("&war=");
+                sb.append(URLEncoder.encode(localWar, getCharset()));
+            }
+            if (update) {
+                sb.append("&update=true");
+            }
+            if (tag != null) {
+                sb.append("&tag=");
+                sb.append(URLEncoder.encode(tag, getCharset()));
+            }
+        } catch (UnsupportedEncodingException e) {
+            throw new BuildException("Invalid 'charset' attribute: " + getCharset());
+        }
+
+        execute(sb.toString(), stream, contentType, contentLength);
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ant/InstallTask.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ant/InstallTask.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ant/InstallTask.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,118 @@
+/*
+ * Copyright 2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.ant;
+
+
+import java.net.URLEncoder;
+
+import org.apache.tools.ant.BuildException;
+
+
+/**
+ * Ant task that implements the <code>/install</code> command, supported by the
+ * Tomcat manager application.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ * @since 4.1
+ * @deprecated Replaced by DeployTask
+ */
+public class InstallTask extends AbstractCatalinaTask {
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * URL of the context configuration file for this application, if any.
+     */
+    protected String config = null;
+
+    public String getConfig() {
+        return (this.config);
+    }
+
+    public void setConfig(String config) {
+        this.config = config;
+    }
+
+
+    /**
+     * The context path of the web application we are managing.
+     */
+    protected String path = null;
+
+    public String getPath() {
+        return (this.path);
+    }
+
+    public void setPath(String path) {
+        this.path = path;
+    }
+
+
+    /**
+     * URL of the web application archive (WAR) file, or the unpacked directory
+     * containing this application, if any.
+     */
+    protected String war = null;
+
+    public String getWar() {
+        return (this.war);
+    }
+
+    public void setWar(String war) {
+        this.war = war;
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Execute the requested operation.
+     *
+     * @exception BuildException if an error occurs
+     */
+    public void execute() throws BuildException {
+
+        super.execute();
+        if (path == null) {
+            throw new BuildException
+                ("Must specify 'path' attribute");
+        }
+        if ((config == null) && (war == null)) {
+            throw new BuildException
+                ("Must specify at least one of 'config' and 'war'");
+        }
+        StringBuffer sb = new StringBuffer("/install?path=");
+        sb.append(URLEncoder.encode(this.path));
+        if (config != null) {
+            sb.append("&config=");
+            sb.append(URLEncoder.encode(config));
+        }
+        if (war != null) {
+            sb.append("&war=");
+            sb.append(URLEncoder.encode(war));
+        }
+        execute(sb.toString());
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ant/JKStatusUpdateTask.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ant/JKStatusUpdateTask.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ant/JKStatusUpdateTask.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,415 @@
+/*
+ * Copyright 2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.ant;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URLEncoder;
+
+import org.apache.tools.ant.BuildException;
+
+/**
+ * Ant task that implements the <code>/status</code> command, supported by the
+ * mod_jk status (1.2.9) application.
+ * 
+ * @author Peter Rossbach
+ * @version $Revision: 303886 $
+ * @since 5.5.9
+ */
+public class JKStatusUpdateTask extends AbstractCatalinaTask {
+
+    private String worker = "lb";
+
+    private String workerType = "lb";
+
+    private int internalid = 0;
+
+    private Integer lbRetries;
+
+    private Integer lbRecovertime;
+
+    private Boolean lbStickySession = Boolean.TRUE;
+
+    private Boolean lbForceSession = Boolean.FALSE;
+
+    private Integer workerLoadFactor;
+
+    private String workerRedirect;
+
+    private String workerClusterDomain;
+
+    private Boolean workerDisabled = Boolean.FALSE;
+
+    private Boolean workerStopped = Boolean.FALSE;
+    
+    private boolean isLBMode = true;
+
+    private String workerLb;
+
+    /**
+     *  
+     */
+    public JKStatusUpdateTask() {
+        super();
+        setUrl("http://localhost/status");
+    }
+
+    /**
+     * @return Returns the internalid.
+     */
+    public int getInternalid() {
+        return internalid;
+    }
+
+    /**
+     * @param internalid
+     *            The internalid to set.
+     */
+    public void setInternalid(int internalid) {
+        this.internalid = internalid;
+    }
+
+    /**
+     * @return Returns the lbForceSession.
+     */
+    public Boolean getLbForceSession() {
+        return lbForceSession;
+    }
+
+    /**
+     * @param lbForceSession
+     *            The lbForceSession to set.
+     */
+    public void setLbForceSession(Boolean lbForceSession) {
+        this.lbForceSession = lbForceSession;
+    }
+
+    /**
+     * @return Returns the lbRecovertime.
+     */
+    public Integer getLbRecovertime() {
+        return lbRecovertime;
+    }
+
+    /**
+     * @param lbRecovertime
+     *            The lbRecovertime to set.
+     */
+    public void setLbRecovertime(Integer lbRecovertime) {
+        this.lbRecovertime = lbRecovertime;
+    }
+
+    /**
+     * @return Returns the lbRetries.
+     */
+    public Integer getLbRetries() {
+        return lbRetries;
+    }
+
+    /**
+     * @param lbRetries
+     *            The lbRetries to set.
+     */
+    public void setLbRetries(Integer lbRetries) {
+        this.lbRetries = lbRetries;
+    }
+
+    /**
+     * @return Returns the lbStickySession.
+     */
+    public Boolean getLbStickySession() {
+        return lbStickySession;
+    }
+
+    /**
+     * @param lbStickySession
+     *            The lbStickySession to set.
+     */
+    public void setLbStickySession(Boolean lbStickySession) {
+        this.lbStickySession = lbStickySession;
+    }
+
+    /**
+     * @return Returns the worker.
+     */
+    public String getWorker() {
+        return worker;
+    }
+
+    /**
+     * @param worker
+     *            The worker to set.
+     */
+    public void setWorker(String worker) {
+        this.worker = worker;
+    }
+
+    /**
+     * @return Returns the workerType.
+     */
+    public String getWorkerType() {
+        return workerType;
+    }
+
+    /**
+     * @param workerType
+     *            The workerType to set.
+     */
+    public void setWorkerType(String workerType) {
+        this.workerType = workerType;
+    }
+
+    /**
+     * @return Returns the workerLb.
+     */
+    public String getWorkerLb() {
+        return workerLb;
+    }
+
+    /**
+     * @param workerLb
+     *            The workerLb to set.
+     */
+    public void setWorkerLb(String workerLb) {
+        this.workerLb = workerLb;
+    }
+
+    /**
+     * @return Returns the workerClusterDomain.
+     */
+    public String getWorkerClusterDomain() {
+        return workerClusterDomain;
+    }
+
+    /**
+     * @param workerClusterDomain
+     *            The workerClusterDomain to set.
+     */
+    public void setWorkerClusterDomain(String workerClusterDomain) {
+        this.workerClusterDomain = workerClusterDomain;
+    }
+
+    /**
+     * @return Returns the workerDisabled.
+     */
+    public Boolean getWorkerDisabled() {
+        return workerDisabled;
+    }
+
+    /**
+     * @param workerDisabled
+     *            The workerDisabled to set.
+     */
+    public void setWorkerDisabled(Boolean workerDisabled) {
+        this.workerDisabled = workerDisabled;
+    }
+
+    /**
+     * @return Returns the workerStopped.
+     */
+    public Boolean getWorkerStopped() {
+        return workerStopped;
+    }
+    
+    /**
+     * @param workerStopped The workerStopped to set.
+     */
+    public void setWorkerStopped(Boolean workerStopped) {
+        this.workerStopped = workerStopped;
+    }
+    
+    /**
+     * @return Returns the workerLoadFactor.
+     */
+    public Integer getWorkerLoadFactor() {
+        return workerLoadFactor;
+    }
+
+    /**
+     * @param workerLoadFactor
+     *            The workerLoadFactor to set.
+     */
+    public void setWorkerLoadFactor(Integer workerLoadFactor) {
+        this.workerLoadFactor = workerLoadFactor;
+    }
+
+    /**
+     * @return Returns the workerRedirect.
+     */
+    public String getWorkerRedirect() {
+        return workerRedirect;
+    }
+
+    /**
+     * @param workerRedirect
+     *            The workerRedirect to set.
+     */
+    public void setWorkerRedirect(String workerRedirect) {
+        this.workerRedirect = workerRedirect;
+    }
+
+    /**
+     * Execute the requested operation.
+     * 
+     * @exception BuildException
+     *                if an error occurs
+     */
+    public void execute() throws BuildException {
+
+        super.execute();
+        checkParameter();
+        StringBuffer sb = createLink();
+        execute(sb.toString(), null, null, -1);
+
+    }
+
+    /**
+     * Create JkStatus link
+     * <ul>
+     * <li><b>load balance example:
+     * </b>http://localhost/status?cmd=update&mime=txt&w=lb&lf=false&ls=true</li>
+     * <li><b>worker example:
+     * </b>http://localhost/status?cmd=update&mime=txt&w=node1&l=lb&wf=1&wd=false&ws=false
+     * </li>
+     * </ul>
+     * 
+     * @return create jkstatus link
+     */
+    private StringBuffer createLink() {
+        // Building URL
+        StringBuffer sb = new StringBuffer();
+        try {
+            sb.append("?cmd=update&mime=txt");
+            sb.append("&w=");
+            sb.append(URLEncoder.encode(worker, getCharset()));
+
+            if (isLBMode) {
+                //http://localhost/status?cmd=update&mime=txt&w=lb&lf=false&ls=true
+                if ((lbRetries != null)) { // > 0
+                    sb.append("&lr=");
+                    sb.append(lbRetries);
+                }
+                if ((lbRecovertime != null)) { // > 59
+                    sb.append("&lt=");
+                    sb.append(lbRecovertime);
+                }
+                if ((lbStickySession != null)) {
+                    sb.append("&ls=");
+                    sb.append(lbStickySession);
+                }
+                if ((lbForceSession != null)) {
+                    sb.append("&lf=");
+                    sb.append(lbForceSession);
+                }
+            } else {
+                //http://localhost/status?cmd=update&mime=txt&w=node1&l=lb&wf=1&wd=false&ws=false
+                if ((workerLb != null)) { // must be configured
+                    sb.append("&l=");
+                    sb.append(URLEncoder.encode(workerLb, getCharset()));
+                }
+                if ((workerLoadFactor != null)) { // >= 1
+                    sb.append("&wf=");
+                    sb.append(workerLoadFactor);
+                }
+                if ((workerDisabled != null)) {
+                    sb.append("&wd=");
+                    sb.append(workerDisabled);
+                }
+                if ((workerStopped != null)) {
+                    sb.append("&ws=");
+                    sb.append(workerStopped);
+                }
+                if ((workerRedirect != null)) { // other worker conrecte lb's
+                    sb.append("&wr=");
+                }
+                if ((workerClusterDomain != null)) {
+                    sb.append("&wc=");
+                    sb.append(URLEncoder.encode(workerClusterDomain,
+                            getCharset()));
+                }
+            }
+
+        } catch (UnsupportedEncodingException e) {
+            throw new BuildException("Invalid 'charset' attribute: "
+                    + getCharset());
+        }
+        return sb;
+    }
+
+    /**
+     * check correct lb and worker pararmeter
+     */
+    protected void checkParameter() {
+        if (worker == null) {
+            throw new BuildException("Must specify 'worker' attribute");
+        }
+        if (workerType == null) {
+            throw new BuildException("Must specify 'workerType' attribute");
+        }
+        if ("lb".equals(workerType)) {
+            if (lbRecovertime == null && lbRetries == null) {
+                throw new BuildException(
+                        "Must specify at a lb worker either 'lbRecovertime' or"
+                                + "'lbRetries' attribute");
+            }
+            if (lbStickySession == null || lbForceSession == null) {
+                throw new BuildException("Must specify at a lb worker either"
+                        + "'lbStickySession' and 'lbForceSession' attribute");
+            }
+            if (null != lbRecovertime && 60 < lbRecovertime.intValue()) {
+                throw new BuildException(
+                        "The 'lbRecovertime' must be greater than 59");
+            }
+            if (null != lbRetries && 1 < lbRetries.intValue()) {
+                throw new BuildException(
+                        "The 'lbRetries' must be greater than 1");
+            }
+            isLBMode = true;
+        } else if ("worker".equals(workerType)) {
+            if (workerDisabled == null) {
+                throw new BuildException(
+                        "Must specify at a node worker 'workerDisabled' attribute");
+            }
+            if (workerStopped == null) {
+                throw new BuildException(
+                        "Must specify at a node worker 'workerStopped' attribute");
+            }
+            if (workerLoadFactor == null ) {
+                throw new BuildException(
+                        "Must specify at a node worker 'workerLoadFactor' attribute");
+            }
+            if (workerClusterDomain == null) {
+                throw new BuildException(
+                        "Must specify at a node worker 'workerClusterDomain' attribute");
+            }
+            if (workerRedirect == null) {
+                throw new BuildException(
+                        "Must specify at a node worker 'workerRedirect' attribute");
+            }
+            if (workerLb == null) {
+                throw new BuildException("Must specify 'workerLb' attribute");
+            }
+            if (workerLoadFactor.intValue() < 1) {
+                throw new BuildException(
+                        "The 'workerLoadFactor' must be greater or equal 1");
+            }
+            isLBMode = false;
+        } else {
+            throw new BuildException(
+                    "Only 'lb' and 'worker' supported as workerType attribute");
+        }
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ant/JMXGetTask.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ant/JMXGetTask.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ant/JMXGetTask.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.ant;
+
+
+import org.apache.tools.ant.BuildException;
+
+
+/**
+ * Ant task that implements the JMX Get command (<code>/jmxproxy/?get</code>)
+ * supported by the Tomcat manager application.
+ *
+ * @author Peter Rossbach
+ * @version $Revision: 303880 $
+ */
+public class JMXGetTask extends AbstractCatalinaTask {
+
+    // Properties
+
+    /**
+     * The full bean name
+     */
+    protected String bean      = null;
+
+    /**
+     * The attribute you wish to alter
+     */
+    protected String attribute = null;
+
+    // Public Methods
+    
+    /**
+     * Get method for the bean name
+     * @return Bean name
+     */
+    public String getBean () {
+        return this.bean;
+    }
+
+    /**
+     * Set method for the bean name
+     * @param bean Bean name
+     */
+    public void setBean (String bean) {
+        this.bean = bean;
+    }
+
+    /**
+     * Get method for the attribute name
+     * @return Attribute name
+     */
+    public String getAttribute () {
+        return this.attribute;
+    }
+
+    /**
+     * Set method for the attribute name
+     * @param attribute Attribute name
+     */
+    public void setAttribute (String attribute) {
+        this.attribute = attribute;
+    }
+
+    /**
+     * Execute the requested operation.
+     *
+     * @exception BuildException if an error occurs
+     */
+    public void execute() throws BuildException {
+        super.execute();
+        if (bean == null || attribute == null) {
+            throw new BuildException
+                ("Must specify 'bean' and 'attribute' attributes");
+        }
+        log("Getting attribute " + attribute +
+                " in bean " + bean ); 
+        execute("/jmxproxy/?get=" + bean 
+                + "&att=" + attribute );
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ant/JMXQueryTask.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ant/JMXQueryTask.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ant/JMXQueryTask.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.ant;
+
+
+import org.apache.tools.ant.BuildException;
+
+
+/**
+ * Ant task that implements the JMX Query command 
+ * (<code>/jmxproxy/?qry</code>) supported by the Tomcat manager application.
+ *
+ * @author Vivek Chopra
+ * @version $Revision: 303236 $
+ */
+public class JMXQueryTask extends AbstractCatalinaTask {
+
+    // Properties
+
+    /**
+     * The JMX query string 
+     * @see #setQuery(String)
+     */
+    protected String query      = null;
+
+    // Public Methods
+    
+    /**
+     * Get method for the JMX query string
+     * @return Query string
+     */
+    public String getQuery () {
+        return this.query;
+    }
+
+    /**
+     * Set method for the JMX query string.
+    * <P>Examples of query format:
+     * <UL>
+     * <LI>*:*</LI>
+     * <LI>*:type=RequestProcessor,*</LI>
+     * <LI>*:j2eeType=Servlet,*</LI>
+     * <LI>Catalina:type=Environment,resourcetype=Global,name=simpleValue</LI>
+     * </UL>
+     * </P> 
+     * @param query JMX Query string
+     */
+    public void setQuery (String query) {
+        this.query = query;
+    }
+
+    /**
+     * Execute the requested operation.
+     *
+     * @exception BuildException if an error occurs
+     */
+    public void execute() throws BuildException {
+        super.execute();
+        String queryString = (query == null) ? "":("?qry="+query);
+        log("Query string is " + queryString); 
+        execute ("/jmxproxy/" + queryString);
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ant/JMXSetTask.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ant/JMXSetTask.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ant/JMXSetTask.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,118 @@
+/*
+ * Copyright 2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.ant;
+
+
+import org.apache.tools.ant.BuildException;
+
+
+/**
+ * Ant task that implements the JMX Set command (<code>/jmxproxy/?set</code>)
+ * supported by the Tomcat manager application.
+ *
+ * @author Vivek Chopra
+ * @version $Revision: 303236 $
+ */
+public class JMXSetTask extends AbstractCatalinaTask {
+
+    // Properties
+
+    /**
+     * The full bean name
+     */
+    protected String bean      = null;
+
+    /**
+     * The attribute you wish to alter
+     */
+    protected String attribute = null;
+
+    /**
+     * The new value for the attribute
+     */
+    protected String value     = null;
+
+    // Public Methods
+    
+    /**
+     * Get method for the bean name
+     * @return Bean name
+     */
+    public String getBean () {
+        return this.bean;
+    }
+
+    /**
+     * Set method for the bean name
+     * @param bean Bean name
+     */
+    public void setBean (String bean) {
+        this.bean = bean;
+    }
+
+    /**
+     * Get method for the attribute name
+     * @return Attribute name
+     */
+    public String getAttribute () {
+        return this.attribute;
+    }
+
+    /**
+     * Set method for the attribute name
+     * @param attribute Attribute name
+     */
+    public void setAttribute (String attribute) {
+        this.attribute = attribute;
+    }
+
+    /**
+     * Get method for the attribute value
+     * @return Attribute value
+     */
+    public String getValue () {
+        return this.value;
+    }
+
+    /**
+     * Set method for the attribute value.
+     * @param value Attribute value
+     */
+    public void setValue (String value) {
+        this.value = value;
+    }
+
+    /**
+     * Execute the requested operation.
+     *
+     * @exception BuildException if an error occurs
+     */
+    public void execute() throws BuildException {
+        super.execute();
+        if (bean == null || attribute == null || value == null) {
+            throw new BuildException
+                ("Must specify 'bean', 'attribute' and 'value' attributes");
+        }
+        log("Setting attribute " + attribute +
+                            " in bean " + bean +
+                            " to " + value); 
+        execute("/jmxproxy/?set=" + bean 
+                + "&att=" + attribute 
+                + "&val=" + value);
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ant/ListTask.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ant/ListTask.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ant/ListTask.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.ant;
+
+
+import org.apache.tools.ant.BuildException;
+
+
+/**
+ * Ant task that implements the <code>/list</code> command, supported by the
+ * Tomcat manager application.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ * @since 4.1
+ */
+public class ListTask extends AbstractCatalinaTask {
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Execute the requested operation.
+     *
+     * @exception BuildException if an error occurs
+     */
+    public void execute() throws BuildException {
+
+        super.execute();
+        execute("/list");
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ant/ReloadTask.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ant/ReloadTask.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ant/ReloadTask.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.ant;
+
+
+import java.io.UnsupportedEncodingException;
+import java.net.URLEncoder;
+
+import org.apache.tools.ant.BuildException;
+
+
+/**
+ * Ant task that implements the <code>/reload</code> command, supported by the
+ * Tomcat manager application.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 303657 $ $Date: 2005-01-22 10:34:47 -0600 (Sat, 22 Jan 2005) $
+ * @since 4.1
+ */
+public class ReloadTask extends AbstractCatalinaTask {
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * The context path of the web application we are managing.
+     */
+    protected String path = null;
+
+    public String getPath() {
+        return (this.path);
+    }
+
+    public void setPath(String path) {
+        this.path = path;
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Execute the requested operation.
+     *
+     * @exception BuildException if an error occurs
+     */
+    public void execute() throws BuildException {
+
+        super.execute();
+        if (path == null) {
+            throw new BuildException
+                ("Must specify 'path' attribute");
+        }
+        try {
+            execute("/reload?path=" + URLEncoder.encode(this.path, getCharset()));
+        } catch (UnsupportedEncodingException e) {
+            throw new BuildException
+                ("Invalid 'charset' attribute: " + getCharset());
+        }
+
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ant/RemoveTask.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ant/RemoveTask.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ant/RemoveTask.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.ant;
+
+
+import java.net.URLEncoder;
+
+import org.apache.tools.ant.BuildException;
+
+
+/**
+ * Ant task that implements the <code>/remove</code> command, supported by the
+ * Tomcat manager application.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ * @deprecated Replaced by UndeployTask
+ */
+public class RemoveTask extends AbstractCatalinaTask {
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * The context path of the web application we are managing.
+     */
+    protected String path = null;
+
+    public String getPath() {
+        return (this.path);
+    }
+
+    public void setPath(String path) {
+        this.path = path;
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Execute the requested operation.
+     *
+     * @exception BuildException if an error occurs
+     */
+    public void execute() throws BuildException {
+
+        super.execute();
+        if (path == null) {
+            throw new BuildException
+                ("Must specify 'path' attribute");
+        }
+        execute("/remove?path=" + URLEncoder.encode(this.path));
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ant/ResourcesTask.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ant/ResourcesTask.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ant/ResourcesTask.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.ant;
+
+
+import org.apache.tools.ant.BuildException;
+
+
+/**
+ * Ant task that implements the <code>/resources</code> command, supported by
+ * the Tomcat manager application.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ * @since 4.1
+ */
+public class ResourcesTask extends AbstractCatalinaTask {
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * The fully qualified class name of the resource type being requested
+     * (if any).
+     */
+    protected String type = null;
+
+    public String getType() {
+        return (this.type);
+    }
+
+    public void setType(String type) {
+        this.type = type;
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Execute the requested operation.
+     *
+     * @exception BuildException if an error occurs
+     */
+    public void execute() throws BuildException {
+
+        super.execute();
+        if (type != null) {
+            execute("/resources?type=" + type);
+        } else {
+            execute("/resources");
+        }
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ant/RolesTask.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ant/RolesTask.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ant/RolesTask.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.ant;
+
+
+import org.apache.tools.ant.BuildException;
+
+
+/**
+ * Ant task that implements the <code>/roles</code> command, supported by the
+ * Tomcat manager application.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ * @since 4.1
+ */
+public class RolesTask extends AbstractCatalinaTask {
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Execute the requested operation.
+     *
+     * @exception BuildException if an error occurs
+     */
+    public void execute() throws BuildException {
+
+        super.execute();
+        execute("/roles");
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ant/ServerinfoTask.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ant/ServerinfoTask.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ant/ServerinfoTask.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.ant;
+
+
+import org.apache.tools.ant.BuildException;
+
+
+/**
+ * Ant task that implements the <code>/serverinfo</code> command
+ * supported by the Tomcat manager application.
+ *
+ * @author Vivek Chopra
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+public class ServerinfoTask extends AbstractCatalinaTask {
+
+    // Public Methods
+
+    /**
+     * Execute the requested operation.
+     *
+     * @exception BuildException if an error occurs
+     */
+    public void execute() throws BuildException {
+
+        super.execute();
+        execute("/serverinfo");
+
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ant/SessionsTask.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ant/SessionsTask.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ant/SessionsTask.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.ant;
+
+
+import java.io.UnsupportedEncodingException;
+import java.net.URLEncoder;
+
+import org.apache.tools.ant.BuildException;
+
+
+/**
+ * Ant task that implements the <code>/sessions</code> command
+ * supported by the Tomcat manager application.
+ *
+ * @author Vivek Chopra
+ * @version $Revision: 303657 $
+ */
+public class SessionsTask extends AbstractCatalinaTask {
+
+    // Properties
+
+    /**
+     * The context path of the web application we are managing.
+     */
+    protected String path = null;
+
+    public String getPath() {
+        return (this.path);
+    }
+
+    public void setPath(String path) {
+        this.path = path;
+    }
+
+    // Public Methods
+
+    /**
+     * Execute the requested operation.
+     *
+     * @exception BuildException if an error occurs
+     */
+    public void execute() throws BuildException {
+
+        super.execute();
+        if (path == null) {
+            throw new BuildException
+                ("Must specify 'path' attribute");
+        }
+        
+        try {
+            execute("/sessions?path=" + URLEncoder.encode(this.path, getCharset()));
+        } catch (UnsupportedEncodingException e) {
+            throw new BuildException
+                ("Invalid 'charset' attribute: " + getCharset());
+        }
+        
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ant/StartTask.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ant/StartTask.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ant/StartTask.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.ant;
+
+
+import java.io.UnsupportedEncodingException;
+import java.net.URLEncoder;
+
+import org.apache.tools.ant.BuildException;
+
+
+/**
+ * Ant task that implements the <code>/start</code> command, supported by the
+ * Tomcat manager application.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 303657 $ $Date: 2005-01-22 10:34:47 -0600 (Sat, 22 Jan 2005) $
+ * @since 4.1
+ */
+public class StartTask extends AbstractCatalinaTask {
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * The context path of the web application we are managing.
+     */
+    protected String path = null;
+
+    public String getPath() {
+        return (this.path);
+    }
+
+    public void setPath(String path) {
+        this.path = path;
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Execute the requested operation.
+     *
+     * @exception BuildException if an error occurs
+     */
+    public void execute() throws BuildException {
+
+        super.execute();
+        if (path == null) {
+            throw new BuildException
+                ("Must specify 'path' attribute");
+        }
+        try {
+            execute("/start?path=" + URLEncoder.encode(this.path, getCharset()));
+        } catch (UnsupportedEncodingException e) {
+            throw new BuildException
+                ("Invalid 'charset' attribute: " + getCharset());
+        }
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ant/StopTask.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ant/StopTask.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ant/StopTask.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.ant;
+
+
+import java.io.UnsupportedEncodingException;
+import java.net.URLEncoder;
+
+import org.apache.tools.ant.BuildException;
+
+
+/**
+ * Ant task that implements the <code>/stop</code> command, supported by the
+ * Tomcat manager application.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 303657 $ $Date: 2005-01-22 10:34:47 -0600 (Sat, 22 Jan 2005) $
+ * @since 4.1
+ */
+public class StopTask extends AbstractCatalinaTask {
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * The context path of the web application we are managing.
+     */
+    protected String path = null;
+
+    public String getPath() {
+        return (this.path);
+    }
+
+    public void setPath(String path) {
+        this.path = path;
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Execute the requested operation.
+     *
+     * @exception BuildException if an error occurs
+     */
+    public void execute() throws BuildException {
+
+        super.execute();
+        if (path == null) {
+            throw new BuildException
+                ("Must specify 'path' attribute");
+        }
+        try {
+            execute("/stop?path=" + URLEncoder.encode(this.path, getCharset()));
+        } catch (UnsupportedEncodingException e) {
+            throw new BuildException
+                ("Invalid 'charset' attribute: " + getCharset());
+        }
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ant/UndeployTask.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ant/UndeployTask.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ant/UndeployTask.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.ant;
+
+
+import org.apache.tools.ant.BuildException;
+
+
+/**
+ * Ant task that implements the <code>/undeploy</code> command, supported by
+ * the Tomcat manager application.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 303609 $ $Date: 2005-01-03 10:21:21 -0600 (Mon, 03 Jan 2005) $
+ * @since 4.1
+ */
+public class UndeployTask extends AbstractCatalinaTask {
+
+
+    // ------------------------------------------------------------- Properties
+
+    /**
+     * The context path of the web application we are managing.
+     */
+    protected String path = null;
+
+    public String getPath() {
+        return (this.path);
+    }
+
+    public void setPath(String path) {
+        this.path = path;
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Execute the requested operation.
+     *
+     * @exception BuildException if an error occurs
+     */
+    public void execute() throws BuildException {
+
+        super.execute();
+        if (path == null) {
+            throw new BuildException
+                ("Must specify 'path' attribute");
+        }
+
+        execute("/undeploy?path=" + this.path);
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ant/ValidatorTask.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ant/ValidatorTask.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ant/ValidatorTask.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,114 @@
+/*
+ * Copyright 2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.ant;
+
+
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.InputStream;
+
+import org.apache.catalina.startup.Constants;
+import org.apache.catalina.startup.DigesterFactory;
+import org.apache.tomcat.util.digester.Digester;
+import org.apache.tools.ant.BuildException;
+import org.xml.sax.InputSource;
+
+
+/**
+ * Task for validating a web application deployment descriptor, using XML 
+ * schema validation.
+ *
+ * @author Remy Maucherat
+ * @version $Revision: 303609 $ $Date: 2005-01-03 10:21:21 -0600 (Mon, 03 Jan 2005) $
+ * @since 5.0
+ */
+
+public class ValidatorTask extends BaseRedirectorHelperTask {
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * The path to the webapp directory.
+     */
+    protected String path = null;
+
+    public String getPath() {
+        return (this.path);
+    }
+
+    public void setPath(String path) {
+        this.path = path;
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Execute the specified command.  This logic only performs the common
+     * attribute validation required by all subclasses; it does not perform
+     * any functional logic directly.
+     *
+     * @exception BuildException if a validation error occurs
+     */
+    public void execute() throws BuildException {
+
+        if (path == null) {
+            throw new BuildException("Must specify 'path'");
+        }
+
+        File file = new File(path, Constants.ApplicationWebXml);
+        if ((!file.exists()) || (!file.canRead())) {
+            throw new BuildException("Cannot find web.xml");
+        }
+
+        // Commons-logging likes having the context classloader set
+        ClassLoader oldCL = Thread.currentThread().getContextClassLoader();
+        Thread.currentThread().setContextClassLoader
+            (ValidatorTask.class.getClassLoader());
+
+        Digester digester = DigesterFactory.newDigester(true, true, null);
+        try {
+            file = file.getCanonicalFile();
+            InputStream stream = 
+                new BufferedInputStream(new FileInputStream(file));
+            InputSource is = new InputSource(file.toURL().toExternalForm());
+            is.setByteStream(stream);
+            digester.parse(is);
+            handleOutput("web.xml validated");
+        } catch (Throwable t) {
+            if (isFailOnError()) {
+                throw new BuildException("Validation failure", t);
+            } else {
+                handleErrorOutput("Validation failure: " + t);
+            }
+        } finally {
+            Thread.currentThread().setContextClassLoader(oldCL);
+            closeRedirector();
+        }
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ant/antlib.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ant/antlib.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ant/antlib.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<antlib>
+  <typedef
+        name="list"
+        classname="org.apache.catalina.ant.ListTask" />
+  <typedef
+        name="deploy"
+        classname="org.apache.catalina.ant.DeployTask" />
+  <typedef
+        name="start"
+        classname="org.apache.catalina.ant.StartTask" />
+  <typedef
+        name="reload"
+        classname="org.apache.catalina.ant.ReloadTask" />
+  <typedef
+        name="stop"
+        classname="org.apache.catalina.ant.StopTask" />        
+  <typedef
+        name="undeploy"
+        classname="org.apache.catalina.ant.UndeployTask" />
+  <typedef
+        name="roles"
+        classname="org.apache.catalina.ant.RolesTask" />
+  <typedef
+        name="resources"
+        classname="org.apache.catalina.ant.ResourcesTask" />
+  <typedef
+        name="sessions"
+        classname="org.apache.catalina.ant.SessionsTask" />
+  <typedef
+        name="jkupdate"
+        classname="org.apache.catalina.ant.JKStatusUpdateTask" />
+  <typedef
+        name="jmxManagerSet"
+        classname="org.apache.catalina.ant.JMXSetTask" />
+  <typedef
+        name="jmxManagerGet"
+        classname="org.apache.catalina.ant.JMXGetTask" />
+  <typedef
+        name="jmxManagerQuery"
+        classname="org.apache.catalina.ant.JMXQueryTask" />
+</antlib>

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ant/catalina.tasks
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ant/catalina.tasks	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ant/catalina.tasks	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,22 @@
+# Pure catalina tasks
+deploy=org.apache.catalina.ant.DeployTask
+list=org.apache.catalina.ant.ListTask
+reload=org.apache.catalina.ant.ReloadTask
+sessions=org.apache.catalina.ant.SessionsTask
+resources=org.apache.catalina.ant.ResourcesTask
+roles=org.apache.catalina.ant.RolesTask
+start=org.apache.catalina.ant.StartTask
+stop=org.apache.catalina.ant.StopTask
+undeploy=org.apache.catalina.ant.UndeployTask
+validator=org.apache.catalina.ant.ValidatorTask
+
+#Jk Task
+jkstatus=org.apache.catalina.ant.JKStatusUpdateTask
+
+# Manager JMX
+jmxManagerSet=org.apache.catalina.ant.JMXSetTask
+jmxManagerGet=org.apache.catalina.ant.JMXGetTask
+jmxManagerQuery=org.apache.catalina.ant.JMXQueryTask
+
+# Jasper tasks
+jasper2=org.apache.jasper.JspC

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ant/jmx/Arg.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ant/jmx/Arg.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ant/jmx/Arg.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.ant.jmx;
+
+/**
+ *
+ * @author Peter Rossbach
+ * @version $Revision: 441172 $ $Date: 2006-09-07 13:38:07 -0500 (Thu, 07 Sep 2006) $
+ * @since 5.5.10
+ */
+public class Arg {
+    String name;
+    String type;
+    String value;
+
+    public void setName( String name) {
+        this.name=name;
+    }
+    public void setType( String type) {
+        this.type=type;
+    }
+    public void setValue( String value ) {
+        this.value=value;
+    }
+    public void addText( String text ) {
+        this.value=text;
+    }
+    public String getName() {
+        return name;
+    }
+    public String getValue() {
+        return value;
+    }
+    public String getType() {
+        return type;
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ant/jmx/JMXAccessorCondition.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ant/jmx/JMXAccessorCondition.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ant/jmx/JMXAccessorCondition.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,400 @@
+/*
+ * Copyright 2002,2004-2005 The Apache Software Foundation.
+ * 
+ * Licensed 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.ant.jmx;
+
+import java.io.IOException;
+import java.net.MalformedURLException;
+
+import javax.management.MBeanServerConnection;
+import javax.management.ObjectName;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.ProjectComponent;
+import org.apache.tools.ant.taskdefs.condition.Condition;
+
+/**
+ *
+ * <b>Definition</b>:
+ * <pre> 
+ *   &lt;path id="catalina_ant">
+ *       &lt;fileset dir="${catalina.home}/server/lib">
+ *           &lt;include name="catalina-ant.jar"/>
+ *           &lt;include name="catalina-ant-jmx.jar"/>
+ *       &lt;/fileset>
+ *   &lt;/path>
+ *
+ *   &lt;typedef
+ *       name="jmxCondition"
+ *       classname="org.apache.catalina.ant.jmx.JMXAccessorCondition"
+ *       classpathref="catalina_ant"/>
+ *   &lt;taskdef
+ *       name="jmxOpen"
+ *       classname="org.apache.catalina.ant.jmx.JMXAccessorTask"
+ *       classpathref="catalina_ant"/>
+ * </pre>
+ * 
+ * <b>Usage</b>: Wait for start backup node
+ * <pre>
+ *     &lt;target name="wait"&gt;
+ *       &lt;jmxOpen
+ *               host="${jmx.host}" port="${jmx.port}" username="${jmx.username}" password="${jmx.password}" /&gt;
+ *        &lt;waitfor maxwait="${maxwait}" maxwaitunit="second" timeoutproperty="server.timeout" &gt;
+ *           &lt;and&gt;
+ *               &lt;socket server="${server.name}" port="${server.port}"/&gt;
+ *               &lt;http url="${url}"/&gt;
+ *               &lt;jmxCondition
+ *                   name="Catalina:type=IDataSender,host=localhost,senderAddress=192.168.111.1,senderPort=9025"
+ *                   operation="==" 
+ *                   attribute="connected" value="true"
+ *               /&gt;
+ *               &lt;jmxCondition
+ *                   operation="&amp;lt;"
+ *                   name="Catalina:j2eeType=WebModule,name=//${tomcat.application.host}${tomcat.application.path},J2EEApplication=none,J2EEServer=none"
+ *                   attribute="startupTime" value="250"
+ *               /&gt;
+ *           &lt;/and&gt;
+ *       &lt;/waitfor&gt;
+ *       &lt;fail if="server.timeout" message="Server ${url} don't answer inside ${maxwait} sec" /&gt;
+ *       &lt;echo message="Server ${url} alive" /&gt;
+ *   &lt;/target&gt;
+ *
+ * </pre>
+ * Allowed operation between jmx attribute and reference value:
+ * <ul>
+ * <li>==  equals</li>
+ * <li>!=  not equals</li>
+ * <li>&gt; greater than (&amp;gt;)</li>
+ * <li>&gt;= greater than or equals (&amp;gt;=)</li>
+ * <li>&lt; lesser than (&amp;lt;)</li>
+ * <li>&lt;= lesser than or equals (&amp;lt;=)</li>
+ * </ul> 
+ * <b>NOTE</b>:  For numeric expressions the type must be set and use xml entities as operations.<br/>
+ * As type we currently support <em>long</em> and <em>double</em>.
+ * @author Peter Rossbach
+ * @version $Revision: 304032 $ $Date: 2005-07-27 10:11:55 -0500 (Wed, 27 Jul 2005) $
+ * @since 5.5.10
+ *
+ */
+public class JMXAccessorCondition extends ProjectComponent implements Condition {
+
+    // ----------------------------------------------------- Instance Variables
+
+    private String url = null;
+    private String host = "localhost";
+    private String port = "8050";
+    private String password = null;
+    private String username = null;
+    private String name = null;
+    private String attribute;
+    private String value;
+    private String operation = "==" ;
+    private String type = "long" ;
+    private String ref = "jmx.server";
+    private String unlessCondition;
+    private String ifCondition;
+     
+    // ----------------------------------------------------- Instance Info
+
+    /**
+     * Descriptive information describing this implementation.
+     */
+    private static final String info = "org.apache.catalina.ant.JMXAccessorCondition/1.1";
+
+    /**
+     * Return descriptive information about this implementation and the
+     * corresponding version number, in the format
+     * <code>&lt;description&gt;/&lt;version&gt;</code>.
+     */
+    public String getInfo() {
+
+        return (info);
+
+    }
+    // ----------------------------------------------------- Properties
+
+    /**
+     * @return Returns the operation.
+     */
+    public String getOperation() {
+        return operation;
+    }
+    /**
+     * @param operation The operation to set.
+     */
+    public void setOperation(String operation) {
+        this.operation = operation;
+    }
+
+    /**
+     * @return Returns the type.
+     */
+    public String getType() {
+        return type;
+    }
+    /**
+     * @param type The type to set.
+     */
+    public void setType(String type) {
+        this.type = type;
+    }
+    /**
+     * @return Returns the attribute.
+     */
+    public String getAttribute() {
+        return attribute;
+    }
+    /**
+     * @param attribute The attribute to set.
+     */
+    public void setAttribute(String attribute) {
+        this.attribute = attribute;
+    }
+    /**
+     * @return Returns the host.
+     */
+    public String getHost() {
+        return host;
+    }
+    /**
+     * @param host The host to set.
+     */
+    public void setHost(String host) {
+        this.host = host;
+    }
+    /**
+     * @return Returns the name.
+     */
+    public String getName() {
+        return name;
+    }
+    /**
+     * @param objectName The name to set.
+     */
+    public void setName(String objectName) {
+        this.name = objectName;
+    }
+    /**
+     * @return Returns the password.
+     */
+    public String getPassword() {
+        return password;
+    }
+    /**
+     * @param password The password to set.
+     */
+    public void setPassword(String password) {
+        this.password = password;
+    }
+    /**
+     * @return Returns the port.
+     */
+    public String getPort() {
+        return port;
+    }
+    /**
+     * @param port The port to set.
+     */
+    public void setPort(String port) {
+        this.port = port;
+    }
+    /**
+     * @return Returns the url.
+     */
+    public String getUrl() {
+        return url;
+    }
+    /**
+     * @param url The url to set.
+     */
+    public void setUrl(String url) {
+        this.url = url;
+    }
+    /**
+     * @return Returns the username.
+     */
+    public String getUsername() {
+        return username;
+    }
+    /**
+     * @param username The username to set.
+     */
+    public void setUsername(String username) {
+        this.username = username;
+    }
+    /**
+     * @return Returns the value.
+     */
+    public String getValue() {
+        return value;
+    }
+    // The setter for the "value" attribute
+    public void setValue(String value) {
+        this.value = value;
+    }
+ 
+    /**
+     * @return Returns the ref.
+     */
+    public String getRef() {
+        return ref;
+    }
+    /**
+     * @param refId The ref to set.
+     */
+    public void setRef(String refId) {
+        this.ref = refId;
+    }
+    /**
+     * @return Returns the ifCondition.
+     */
+    public String getIf() {
+        return ifCondition;
+    }
+    /**
+     * Only execute if a property of the given name exists in the current project.
+     * @param c property name
+     */
+    public void setIf(String c) {
+        ifCondition = c;
+    }
+   /**
+     * @return Returns the unlessCondition.
+     */
+    public String getUnless() {
+        return unlessCondition;
+    }
+ 
+    /**
+     * Only execute if a property of the given name does not
+     * exist in the current project.
+     * @param c property name
+     */
+    public void setUnless(String c) {
+        unlessCondition = c;
+    }
+
+    /**
+     * Get JMXConnection (default look at <em>jmx.server</em> project reference from jmxOpen Task)
+     * @return active JMXConnection
+     * @throws MalformedURLException
+     * @throws IOException
+     */
+    protected MBeanServerConnection getJMXConnection()
+            throws MalformedURLException, IOException {
+        return JMXAccessorTask.accessJMXConnection(
+                getProject(),
+                getUrl(), getHost(),
+                getPort(), getUsername(), getPassword(), ref);
+    }
+
+    /**
+     * Get value from MBeans attribute 
+     * @return The value
+     */
+    protected String accessJMXValue() {
+        try {
+            Object result = getJMXConnection().getAttribute(
+                    new ObjectName(name), attribute);
+            if(result != null)
+                return result.toString();
+        } catch (Exception e) {
+            // ignore access or connection open errors
+        }
+        return null;
+    }
+
+    /**
+     * test the if condition
+     * @return true if there is no if condition, or the named property exists
+     */
+    protected boolean testIfCondition() {
+        if (ifCondition == null || "".equals(ifCondition)) {
+            return true;
+        }
+        return getProject().getProperty(ifCondition) != null;
+    }
+
+    /**
+     * test the unless condition
+     * @return true if there is no unless condition,
+     *  or there is a named property but it doesn't exist
+     */
+    protected boolean testUnlessCondition() {
+        if (unlessCondition == null || "".equals(unlessCondition)) {
+            return true;
+        }
+        return getProject().getProperty(unlessCondition) == null;
+    }
+
+    /**
+     * This method evaluates the condition
+     * It support for operation ">,>=,<,<=" the types <code>long</code> and <code>double</code>.
+     * @return expression <em>jmxValue</em> <em>operation</em> <em>value</em>
+     */
+    public boolean eval() {
+        if (operation == null) {
+            throw new BuildException("operation attribute is not set");
+        }
+        if (value == null) {
+            throw new BuildException("value attribute is not set");
+        }
+        if ((name == null || attribute == null)) {
+            throw new BuildException(
+                    "Must specify a 'attribute', name for equals condition");
+        }
+        if (testIfCondition() && testUnlessCondition()) {
+            String jmxValue = accessJMXValue();
+            if (jmxValue != null) {
+                String op = getOperation();
+                if ("==".equals(op)) {
+                    return jmxValue.equals(value);
+                } else if ("!=".equals(op)) {
+                    return !jmxValue.equals(value);
+                } else {
+                    if ("long".equals(type)) {
+                        long jvalue = Long.parseLong(jmxValue);
+                        long lvalue = Long.parseLong(value);
+                        if (">".equals(op)) {
+                            return jvalue > lvalue;
+                        } else if (">=".equals(op)) {
+                            return jvalue >= lvalue;
+                        } else if ("<".equals(op)) {
+                            return jvalue < lvalue;
+                        } else if ("<=".equals(op)) {
+                            return jvalue <= lvalue;
+                        }
+                    } else if ("double".equals(type)) {
+                        double jvalue = Double.parseDouble(jmxValue);
+                        double dvalue = Double.parseDouble(value);
+                        if (">".equals(op)) {
+                            return jvalue > dvalue;
+                        } else if (">=".equals(op)) {
+                            return jvalue >= dvalue;
+                        } else if ("<".equals(op)) {
+                            return jvalue < dvalue;
+                        } else if ("<=".equals(op)) {
+                            return jvalue <= dvalue;
+                        }
+                    }
+                }
+            }
+            return false;
+        }
+        return true;
+    }
+ }
+

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ant/jmx/JMXAccessorCreateTask.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ant/jmx/JMXAccessorCreateTask.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ant/jmx/JMXAccessorCreateTask.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,206 @@
+/*
+ * Copyright 2002,2004-2005 The Apache Software Foundation.
+ * 
+ * Licensed 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.ant.jmx;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.management.MBeanServerConnection;
+import javax.management.ObjectName;
+
+import org.apache.tools.ant.BuildException;
+
+/**
+ * Create new MBean at <em>JMX</em> JSR 160 MBeans Server. 
+ * <ul>
+ * <li>Create Mbeans</li>
+ * <li>Create Mbeans with parameter</li>
+ * <li>Create remote Mbeans with different classloader</li>
+ * </ul>
+ * <p>
+ * Examples:
+ * <br/>
+ * create a new Mbean at jmx.server connection 
+ * <pre>
+ *   &lt;jmx:create
+ *           ref="jmx.server"
+ *           name="Catalina:type=MBeanFactory"
+ *           className="org.apache.catalina.mbeans.MBeanFactory"
+ *           classLoader="Catalina:type=ServerClassLoader,name=server"&gt;
+ *            &lt;Arg value="org.apache.catalina.mbeans.MBeanFactory" /&gt;
+ *   &lt;/jmxCreate/&gt;
+ * </pre>
+ * </p>
+ * <p>
+ * <b>WARNING</b>Not all Tomcat MBeans can create remotely and autoregister by its parents!
+ * Please, use the MBeanFactory operation to generate valves and realms.
+ * </p>
+ * <p>
+ * First call to a remote MBeanserver save the JMXConnection a reference <em>jmx.server</em>
+ * </p>
+ * These tasks require Ant 1.6 or later interface.
+ *
+ * @author Peter Rossbach
+ * @version $Revision: 304089 $
+ * @since 5.5.12
+ */
+public class JMXAccessorCreateTask extends JMXAccessorTask {
+    // ----------------------------------------------------- Instance Variables
+
+    private String className;
+    private String classLoader;
+    private List args=new ArrayList();
+
+    // ----------------------------------------------------- Instance Info
+
+    /**
+     * Descriptive information describing this implementation.
+     */
+    private static final String info = "org.apache.catalina.ant.JMXAccessorCreateTask/1.0";
+
+    /**
+     * Return descriptive information about this implementation and the
+     * corresponding version number, in the format
+     * <code>&lt;description&gt;/&lt;version&gt;</code>.
+     * @return Returns the class info.
+     */
+    public String getInfo() {
+
+        return (info);
+
+    }
+
+    // ------------------------------------------------------------- Properties
+
+    /**
+     * @return Returns the classLoader.
+     */
+    public String getClassLoader() {
+        return classLoader;
+    }
+    
+    /**
+     * @param classLoader The classLoader to set.
+     */
+    public void setClassLoader(String classLoaderName) {
+        this.classLoader = classLoaderName;
+    }
+    
+    /**
+     * @return Returns the className.
+     */
+    public String getClassName() {
+        return className;
+    }
+    
+    /**
+     * @param className The className to set.
+     */
+    public void setClassName(String className) {
+        this.className = className;
+    }
+    
+    public void addArg(Arg arg ) {
+        args.add(arg);
+    }
+
+    /**
+     * @return Returns the args.
+     */
+    public List getArgs() {
+        return args;
+    }
+    /**
+     * @param args The args to set.
+     */
+    public void setArgs(List args) {
+        this.args = args;
+    }
+
+    // ------------------------------------------------------ protected Methods
+    
+    /**
+     * Execute the specified command, based on the configured properties. The
+     * input stream will be closed upon completion of this task, whether it was
+     * executed successfully or not.
+     * 
+     * @exception Exception
+     *                if an error occurs
+     */
+    public String jmxExecute(MBeanServerConnection jmxServerConnection)
+        throws Exception {
+
+        if (getName() == null) {
+            throw new BuildException("Must specify a 'name'");
+        }
+        if ((className == null)) {
+            throw new BuildException(
+                    "Must specify a 'className' for get");
+        }
+        return jmxCreate(jmxServerConnection, getName());
+     }
+    
+    /**
+     * create new Mbean and when set from ClassLoader Objectname
+     * @param jmxServerConnection
+     * @param name
+     * @return The value of the given named attribute
+     * @throws Exception
+     */
+    protected String jmxCreate(MBeanServerConnection jmxServerConnection,
+            String name) throws Exception {
+        String error = null;
+        Object argsA[] = null;
+        String sigA[] = null;
+        if (args != null) {
+           argsA = new Object[ args.size()];
+           sigA = new String[args.size()];
+           for( int i=0; i<args.size(); i++ ) {
+               Arg arg=(Arg)args.get(i);
+               if( arg.type==null) {
+                   arg.type="java.lang.String";
+                   sigA[i]=arg.getType();
+                   argsA[i]=arg.getValue();
+               } else {
+                   sigA[i]=arg.getType();
+                   argsA[i]=convertStringToType(arg.getValue(),arg.getType());
+               }                
+           }
+        }
+        if (classLoader != null && !"".equals(classLoader)) {
+            if (isEcho()) {
+                handleOutput("create MBean " + name + " from class "
+                        + className + " with classLoader " + classLoader);
+            }
+            if(args == null)
+                jmxServerConnection.createMBean(className, new ObjectName(name), new ObjectName(classLoader));
+            else
+                jmxServerConnection.createMBean(className, new ObjectName(name), new ObjectName(classLoader),argsA,sigA);
+                
+        } else {
+            if (isEcho()) {
+                handleOutput("create MBean " + name + " from class "
+                        + className);
+            }
+            if(args == null)
+                jmxServerConnection.createMBean(className, new ObjectName(name));
+            else
+                jmxServerConnection.createMBean(className, new ObjectName(name),argsA,sigA);
+        }
+        return error;
+    }
+    
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ant/jmx/JMXAccessorEqualsCondition.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ant/jmx/JMXAccessorEqualsCondition.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ant/jmx/JMXAccessorEqualsCondition.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,250 @@
+/*
+ * Copyright 2002,2004-2005 The Apache Software Foundation.
+ * 
+ * Licensed 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.ant.jmx;
+
+import java.io.IOException;
+import java.net.MalformedURLException;
+
+import javax.management.MBeanServerConnection;
+import javax.management.ObjectName;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.ProjectComponent;
+import org.apache.tools.ant.taskdefs.condition.Condition;
+
+/**
+ *
+ * Definition
+ * <pre> 
+ *   &lt;path id="catalina_ant">
+ *       &lt;fileset dir="${catalina.home}/server/lib">
+ *           &lt;include name="catalina-ant.jar"/>
+ *           &lt;include name="catalina-ant-jmx.jar"/>
+ *       &lt;/fileset>
+ *   &lt;/path>
+ *
+ *   &lt;typedef
+ *       name="jmxEquals"
+ *       classname="org.apache.catalina.ant.jmx.JMXAccessorEqualsCondition"
+ *       classpathref="catalina_ant"/>
+ * </pre>
+ * 
+ * usage: Wait for start backup node
+ * <pre>
+ *     &lt;target name="wait"&gt;
+ *        &lt;waitfor maxwait="${maxwait}" maxwaitunit="second" timeoutproperty="server.timeout" &gt;
+ *           &lt;and&gt;
+ *               &lt;socket server="${server.name}" port="${server.port}"/&gt;
+ *               &lt;http url="${url}"/&gt;
+ *               &lt;jmxEquals 
+ *                   host="localhost" port="9014" username="controlRole" password="tomcat"
+ *                   name="Catalina:type=IDataSender,host=localhost,senderAddress=192.168.111.1,senderPort=9025"
+ *                   attribute="connected" value="true"
+ *               /&gt;
+ *           &lt;/and&gt;
+ *       &lt;/waitfor&gt;
+ *       &lt;fail if="server.timeout" message="Server ${url} don't answer inside ${maxwait} sec" /&gt;
+ *       &lt;echo message="Server ${url} alive" /&gt;
+ *   &lt;/target&gt;
+ *
+ * </pre>
+ * 
+ * @author Peter Rossbach
+ * @version $Revision: 304032 $ $Date: 2005-07-27 10:11:55 -0500 (Wed, 27 Jul 2005) $
+ * @since 5.5.10
+ *
+ */
+public class JMXAccessorEqualsCondition  extends ProjectComponent  implements Condition {
+
+    // ----------------------------------------------------- Instance Variables
+
+    private String url = null;
+    private String host = "localhost";
+    private String port = "8050";
+    private String password = null;
+    private String username = null;
+    private String name = null;
+    private String attribute;
+    private String value;
+    private String ref = "jmx.server" ;
+    // ----------------------------------------------------- Instance Info
+
+    /**
+     * Descriptive information describing this implementation.
+     */
+    private static final String info = "org.apache.catalina.ant.JMXAccessorEqualsCondition/1.1";
+
+    /**
+     * Return descriptive information about this implementation and the
+     * corresponding version number, in the format
+     * <code>&lt;description&gt;/&lt;version&gt;</code>.
+     */
+    public String getInfo() {
+
+        return (info);
+
+    }
+    // ----------------------------------------------------- Properties
+
+    /**
+     * @return Returns the attribute.
+     */
+    public String getAttribute() {
+        return attribute;
+    }
+    /**
+     * @param attribute The attribute to set.
+     */
+    public void setAttribute(String attribute) {
+        this.attribute = attribute;
+    }
+    /**
+     * @return Returns the host.
+     */
+    public String getHost() {
+        return host;
+    }
+    /**
+     * @param host The host to set.
+     */
+    public void setHost(String host) {
+        this.host = host;
+    }
+    /**
+     * @return Returns the name.
+     */
+    public String getName() {
+        return name;
+    }
+    /**
+     * @param objectName The name to set.
+     */
+    public void setName(String objectName) {
+        this.name = objectName;
+    }
+    /**
+     * @return Returns the password.
+     */
+    public String getPassword() {
+        return password;
+    }
+    /**
+     * @param password The password to set.
+     */
+    public void setPassword(String password) {
+        this.password = password;
+    }
+    /**
+     * @return Returns the port.
+     */
+    public String getPort() {
+        return port;
+    }
+    /**
+     * @param port The port to set.
+     */
+    public void setPort(String port) {
+        this.port = port;
+    }
+    /**
+     * @return Returns the url.
+     */
+    public String getUrl() {
+        return url;
+    }
+    /**
+     * @param url The url to set.
+     */
+    public void setUrl(String url) {
+        this.url = url;
+    }
+    /**
+     * @return Returns the username.
+     */
+    public String getUsername() {
+        return username;
+    }
+    /**
+     * @param username The username to set.
+     */
+    public void setUsername(String username) {
+        this.username = username;
+    }
+    /**
+     * @return Returns the value.
+     */
+    public String getValue() {
+        return value;
+    }
+    // The setter for the "value" attribute
+    public void setValue(String value) {
+        this.value = value;
+    }
+
+    /**
+     * @return Returns the ref.
+     */
+    public String getRef() {
+        return ref;
+    }
+    /**
+     * @param refId The ref to set.
+     */
+    public void setRef(String refId) {
+        this.ref = refId;
+    }
+    
+    protected MBeanServerConnection getJMXConnection()
+            throws MalformedURLException, IOException {
+        return JMXAccessorTask.accessJMXConnection(
+                getProject(),
+                getUrl(), getHost(),
+                getPort(), getUsername(), getPassword(), ref);
+    }
+
+    /**
+     * @return The value
+     */
+    protected String accessJMXValue() {
+        try {
+            Object result = getJMXConnection().getAttribute(
+                    new ObjectName(name), attribute);
+            if(result != null)
+                return result.toString();
+        } catch (Exception e) {
+            // ignore access or connection open errors
+        }
+        return null;
+    }
+
+    // This method evaluates the condition
+    public boolean eval() {
+        if (value == null) {
+            throw new BuildException("value attribute is not set");
+        }
+        if ((name == null || attribute == null)) {
+            throw new BuildException(
+                    "Must specify a 'attribute', name for equals condition");
+        }
+        //FIXME check url or host/parameter
+        String jmxValue = accessJMXValue();
+        if(jmxValue != null)
+            return jmxValue.equals(value);
+        return false;
+    }
+}
+

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ant/jmx/JMXAccessorGetTask.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ant/jmx/JMXAccessorGetTask.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ant/jmx/JMXAccessorGetTask.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,144 @@
+/*
+ * Copyright 2002,2004-2005 The Apache Software Foundation.
+ * 
+ * Licensed 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.ant.jmx;
+
+
+import javax.management.MBeanServerConnection;
+import javax.management.ObjectName;
+
+import org.apache.tools.ant.BuildException;
+
+
+/**
+ * Access <em>JMX</em> JSR 160 MBeans Server. 
+ * <ul>
+ * <li>Get Mbeans attributes</li>
+ * <li>Show Get result as Ant console log</li>
+ * <li>Bind Get result as Ant properties</li>
+ * </ul>
+ * <p>
+ * Examples:
+ * <br/>
+ * Get a Mbean IDataSender attribute nrOfRequests and create a new ant property <em>IDataSender.9025.nrOfRequests</em> 
+ * <pre>
+ *   &lt;jmx:get
+ *           ref="jmx.server"
+ *           name="Catalina:type=IDataSender,host=localhost,senderAddress=192.168.1.2,senderPort=9025" 
+ *           attribute="nrOfRequests"
+ *           resultproperty="IDataSender.9025.nrOfRequests"
+ *           echo="false"&gt;
+ *       /&gt;
+ * </pre>
+ * </p>
+ * <p>
+ * First call to a remote MBeanserver save the JMXConnection a referenz <em>jmx.server</em>
+ * </p>
+ * These tasks require Ant 1.6 or later interface.
+ *
+ * @author Peter Rossbach
+ * @version $Revision: 304032 $ $Date: 2005-07-27 10:11:55 -0500 (Wed, 27 Jul 2005) $
+ * @since 5.5.10
+ */
+
+public class JMXAccessorGetTask extends JMXAccessorTask {
+
+
+    // ----------------------------------------------------- Instance Variables
+
+    private String attribute;
+
+    // ----------------------------------------------------- Instance Info
+
+    /**
+     * Descriptive information describing this implementation.
+     */
+    private static final String info = "org.apache.catalina.ant.JMXAccessorGetTask/1.0";
+
+    /**
+     * Return descriptive information about this implementation and the
+     * corresponding version number, in the format
+     * <code>&lt;description&gt;/&lt;version&gt;</code>.
+     */
+    public String getInfo() {
+
+        return (info);
+
+    }
+
+    // ------------------------------------------------------------- Properties
+    
+    /**
+     * @return Returns the attribute.
+     */
+    public String getAttribute() {
+        return attribute;
+    }
+    
+    /**
+     * @param attribute The attribute to set.
+     */
+    public void setAttribute(String attribute) {
+        this.attribute = attribute;
+    }
+    
+  
+    // ------------------------------------------------------ protected Methods
+    
+    /**
+     * Execute the specified command, based on the configured properties. The
+     * input stream will be closed upon completion of this task, whether it was
+     * executed successfully or not.
+     * 
+     * @exception BuildException
+     *                if an error occurs
+     */
+    public String jmxExecute(MBeanServerConnection jmxServerConnection)
+        throws Exception {
+
+        if (getName() == null) {
+            throw new BuildException("Must specify a 'name'");
+        }
+        if ((attribute == null)) {
+            throw new BuildException(
+                    "Must specify a 'attribute' for get");
+        }
+        return  jmxGet(jmxServerConnection, getName());
+     }
+
+
+    /**
+     * @param jmxServerConnection
+     * @param name
+     * @return The value of the given named attribute
+     * @throws Exception
+     */
+    protected String jmxGet(MBeanServerConnection jmxServerConnection,String name) throws Exception {
+        String error = null;
+        if(isEcho()) {
+            handleOutput("MBean " + name + " get attribute " + attribute );
+        }
+        Object result = jmxServerConnection.getAttribute(
+                new ObjectName(name), attribute);
+        if (result != null) {
+            echoResult(attribute,result);
+            createProperty(result);
+        } else
+            error = "Attribute " + attribute + " is empty";
+        return error;
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ant/jmx/JMXAccessorInvokeTask.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ant/jmx/JMXAccessorInvokeTask.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ant/jmx/JMXAccessorInvokeTask.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,206 @@
+/*
+ * Copyright 2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.ant.jmx;
+
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.management.MBeanServerConnection;
+import javax.management.ObjectName;
+
+import org.apache.tools.ant.BuildException;
+
+
+/**
+ * Access <em>JMX</em> JSR 160 MBeans Server. 
+ * <ul>
+ * <li>open more then one JSR 160 rmi connection</li>
+ * <li>Get/Set Mbeans attributes</li>
+ * <li>Call Mbean Operation with arguments</li>
+ * <li>Argument values can be converted from string to int,long,float,double,boolean,ObjectName or InetAddress </li>
+ * <li>Query Mbeans</li>
+ * <li>Show Get, Call, Query result at Ant console log</li>
+ * <li>Bind Get, Call, Query result at Ant properties</li>
+ * </ul>
+ *
+ * Examples:
+ * <ul>
+ * <li>
+ * Get a session attribute hello from session with ref <em>${sessionid.0}</em> form 
+ * app <em>Catalina:type=Manager,path=/ClusterTest,host=localhost</em> 
+ * <pre>
+ *   &lt;jmx:invoke
+ *           name="Catalina:type=Manager,path=/ClusterTest,host=localhost" 
+ *           operation="getSessionAttribute"
+ *           resultproperty="hello"&gt;
+ *         &lt;arg value="${sessionid.0}"/&gt;
+ *         &lt;arg value="Hello"/&gt;
+ *   &lt;/jmx:invoke&gt;
+ * </pre>
+ * </li>
+ * <li>
+ * Create new AccessLogger at localhost 
+ * <code>
+ *   &lt;jmx:invoke
+ *           name="Catalina:type=MBeanFactory" 
+ *           operation="createAcccesLoggerValve"
+ *           resultproperty="acccesLoggerObjectName"
+ *       &gt;
+ *         &lt;arg value="Catalina:type=Host,host=localhost"/&gt;
+ *   &lt;/jmx:invoke&gt;
+ *
+ * </code>
+ * </li>
+ * <li>
+ * Remove existing AccessLogger at localhost 
+ * <code>
+ *   &lt;jmx:invoke
+ *           name="Catalina:type=MBeanFactory" 
+ *           operation="removeValve"
+ *       &gt;
+ *         &lt;arg value="Catalina:type=Valve,name=AccessLogValve,host=localhost"/&gt;
+ *   &lt;/jmx:invoke&gt;
+ *
+ * </code>
+ * </li>
+ * </ul>
+ * <p>
+ * First call to a remote MBeanserver save the JMXConnection a referenz <em>jmx.server</em>
+ * </p>
+ * These tasks require Ant 1.6 or later interface.
+ *
+ * @author Peter Rossbach
+ * @version $Revision: 304013 $ $Date: 2005-07-22 06:39:08 -0500 (Fri, 22 Jul 2005) $
+ * @since 5.5.10
+ */
+
+public class JMXAccessorInvokeTask extends JMXAccessorTask {
+
+
+    // ----------------------------------------------------- Instance Variables
+
+    private String operation ;
+    private List args=new ArrayList();
+
+    // ----------------------------------------------------- Instance Info
+
+    /**
+     * Descriptive information describing this implementation.
+     */
+    private static final String info = "org.apache.catalina.ant.JMXAccessorInvokeTask/1.0";
+
+    /**
+     * Return descriptive information about this implementation and the
+     * corresponding version number, in the format
+     * <code>&lt;description&gt;/&lt;version&gt;</code>.
+     */
+    public String getInfo() {
+
+        return (info);
+
+    }
+
+    // ------------------------------------------------------------- Properties
+    
+    /**
+     * @return Returns the operation.
+     */
+    public String getOperation() {
+        return operation;
+    }
+    /**
+     * @param operation The operation to set.
+     */
+    public void setOperation(String operation) {
+        this.operation = operation;
+    }
+
+    public void addArg(Arg arg ) {
+        args.add(arg);
+    }
+
+    /**
+     * @return Returns the args.
+     */
+    public List getArgs() {
+        return args;
+    }
+    /**
+     * @param args The args to set.
+     */
+    public void setArgs(List args) {
+        this.args = args;
+    }
+    
+    // ------------------------------------------------------ protected Methods
+    
+    /**
+     * Execute the specified command, based on the configured properties. The
+     * input stream will be closed upon completion of this task, whether it was
+     * executed successfully or not.
+     * 
+     * @exception BuildException
+     *                if an error occurs
+     */
+    public String jmxExecute(MBeanServerConnection jmxServerConnection)
+        throws Exception {
+
+        if (getName() == null) {
+            throw new BuildException("Must specify a 'name'");
+        }
+        if ((operation == null)) {
+            throw new BuildException(
+                    "Must specify a 'operation' for call");
+        }
+        return  jmxInvoke(jmxServerConnection, getName());
+     }
+
+    /**
+     * @param jmxServerConnection
+     * @throws Exception
+     */
+    protected String jmxInvoke(MBeanServerConnection jmxServerConnection, String name) throws Exception {
+        Object result ;
+        if (args == null) {
+             result = jmxServerConnection.invoke(new ObjectName(name),
+                    operation, null, null);
+        } else {
+            Object argsA[]=new Object[ args.size()];
+            String sigA[]=new String[args.size()];
+            for( int i=0; i<args.size(); i++ ) {
+                Arg arg=(Arg)args.get(i);
+                if( arg.type==null) {
+                    arg.type="java.lang.String";
+                    sigA[i]=arg.getType();
+                    argsA[i]=arg.getValue();
+                } else {
+                    sigA[i]=arg.getType();
+                    argsA[i]=convertStringToType(arg.getValue(),arg.getType());
+                }                
+            }
+            result = jmxServerConnection.invoke(new ObjectName(name), operation, argsA, sigA);
+        }
+        if(result != null) {
+            echoResult(operation,result);
+            createProperty(result);
+        }
+        return null;
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ant/jmx/JMXAccessorQueryTask.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ant/jmx/JMXAccessorQueryTask.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ant/jmx/JMXAccessorQueryTask.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,214 @@
+/*
+ * Copyright 2002,2004-2005 The Apache Software Foundation.
+ * 
+ * Licensed 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.ant.jmx;
+
+
+import java.util.Iterator;
+import java.util.Set;
+
+import javax.management.MBeanAttributeInfo;
+import javax.management.MBeanInfo;
+import javax.management.MBeanServerConnection;
+import javax.management.ObjectName;
+
+import org.apache.tools.ant.BuildException;
+
+
+/**
+ * Query for Mbeans. 
+ * <ul>
+ * <li>open no existing JSR 160 rmi jmx connection</li>
+ * <li>Get all Mbeans attributes</li>
+ * <li>Get only the Query Mbeans ObjectNames</li>
+ * <li>Show query result as Ant console log</li>
+ * <li>Bind query result as Ant properties</li>
+ * </ul>
+ * <br/>
+ * Query a list of Mbeans.
+ * <pre>
+ *   &lt;jmxQuery
+ *           host="127.0.0.1"
+ *           port="9014"
+ *           name="Catalina:type=Manager,* 
+ *           resultproperty="manager" /&gt;
+ * </pre>
+ * with attribute <em>attributebinding="true"</em> you can get 
+ * all attributes also from result objects.<br/>
+ * The poperty manager.lenght show the size of the result 
+ * and with manager.[0..lenght].name the 
+ * resulted ObjectNames are saved. 
+ * These tasks require Ant 1.6 or later interface.
+ *
+ * @author Peter Rossbach
+ * @version $Revision: 304089 $ $Date: 2005-09-14 08:28:29 -0500 (Wed, 14 Sep 2005) $
+ * @since 5.5.10
+ */
+
+public class JMXAccessorQueryTask extends JMXAccessorTask {
+
+    // ----------------------------------------------------- Instance Variables
+
+    private boolean attributebinding = false;
+
+    // ----------------------------------------------------- Instance Info
+
+    /**
+     * Descriptive information describing this implementation.
+     */
+    private static final String info = "org.apache.catalina.ant.JMXAccessorQueryTask/1.0";
+
+    /**
+     * Return descriptive information about this implementation and the
+     * corresponding version number, in the format
+     * <code>&lt;description&gt;/&lt;version&gt;</code>.
+     */
+    public String getInfo() {
+
+        return (info);
+
+    }
+
+    // ------------------------------------------------------------- Properties
+    
+    /**
+     * @return Returns the attributebinding.
+     */
+    public boolean isAttributebinding() {
+        return attributebinding;
+    }
+    /**
+     * @param attributeBinding The attributebinding to set.
+     */
+    public void setAttributebinding(boolean attributeBinding) {
+        this.attributebinding = attributeBinding;
+    }
+  
+    // ------------------------------------------------------ protected Methods
+
+    
+    /**
+     * Execute the specified command, based on the configured properties. The
+     * input stream will be closed upon completion of this task, whether it was
+     * executed successfully or not.
+     * 
+     * @exception Exception
+     *                if an error occurs
+     */
+    public String jmxExecute(MBeanServerConnection jmxServerConnection)
+        throws Exception {
+
+        if (getName() == null) {
+            throw new BuildException("Must specify a 'name'");
+        }
+        return jmxQuery(jmxServerConnection, getName());
+
+    }
+
+       
+    /**
+     * Call Mbean server for some mbeans with same domain, attributes.
+     *  with <em>attributebindung=true</em> you can save all attributes from all found objects
+     * as your ant properties
+     * @param jmxServerConnection
+     * @param qry
+     * @return The query result
+     */
+    protected String jmxQuery(MBeanServerConnection jmxServerConnection,
+            String qry) {
+        String isError = null;
+        Set names = null;
+        String resultproperty = getResultproperty();
+        try {
+            names = jmxServerConnection.queryNames(new ObjectName(qry), null);
+            if (resultproperty != null) {
+                setProperty(resultproperty + ".Length",Integer.toString(names.size()));
+            }
+        } catch (Exception e) {
+            if (isEcho())
+                handleErrorOutput(e.getMessage());
+            return "Can't query mbeans " + qry;
+        }
+
+        if (resultproperty != null) {
+            Iterator it = names.iterator();
+            int oindex = 0;
+            String pname = null;
+            while (it.hasNext()) {
+                ObjectName oname = (ObjectName) it.next();
+                pname = resultproperty + "." + Integer.toString(oindex) + ".";
+                oindex++;
+                    setProperty(pname + "Name", oname.toString());
+                    if (isAttributebinding()) {
+                        bindAttributes(jmxServerConnection, resultproperty, pname, oname);
+                
+                    }
+                }
+        }
+        return isError;
+    }
+
+    /**
+     * @param jmxServerConnection
+     * @param resultproperty
+     * @param pname
+     * @param oname
+     */
+    protected void bindAttributes(MBeanServerConnection jmxServerConnection, String resultproperty, String pname, ObjectName oname) {
+        if (jmxServerConnection != null  && resultproperty != null 
+            && pname != null && oname != null ) {
+            try {
+                MBeanInfo minfo = jmxServerConnection.getMBeanInfo(oname);
+                String code = minfo.getClassName();
+                if ("org.apache.commons.modeler.BaseModelMBean".equals(code)) {
+                    code = (String) jmxServerConnection.getAttribute(oname,
+                            "modelerType");
+                }
+                MBeanAttributeInfo attrs[] = minfo.getAttributes();
+                Object value = null;
+
+                for (int i = 0; i < attrs.length; i++) {
+                    if (!attrs[i].isReadable())
+                        continue;
+                    String attName = attrs[i].getName();
+                    if (attName.indexOf("=") >= 0 || attName.indexOf(":") >= 0
+                            || attName.indexOf(" ") >= 0) {
+                        continue;
+                    }
+
+                    try {
+                        value = jmxServerConnection
+                                .getAttribute(oname, attName);
+                    } catch (Throwable t) {
+                        if (isEcho())
+                            handleErrorOutput("Error getting attribute "
+                                    + oname + " " + pname + attName + " "
+                                    + t.toString());
+                        continue;
+                    }
+                    if (value == null)
+                        continue;
+                    if ("modelerType".equals(attName))
+                        continue;
+                    createProperty(pname + attName, value);
+                }
+            } catch (Exception e) {
+                // Ignore
+            }
+        }
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ant/jmx/JMXAccessorSetTask.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ant/jmx/JMXAccessorSetTask.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ant/jmx/JMXAccessorSetTask.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,350 @@
+/*
+ * Copyright 2002,2004-2006 The Apache Software Foundation.
+ * 
+ * Licensed 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.ant.jmx;
+
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import javax.management.Attribute;
+import javax.management.AttributeList;
+import javax.management.MBeanAttributeInfo;
+import javax.management.MBeanInfo;
+import javax.management.MBeanServerConnection;
+import javax.management.ObjectName;
+
+import org.apache.tools.ant.BuildException;
+
+
+/**
+ * Access <em>JMX</em> JSR 160 MBeans Server. 
+ * <ul>
+ * <li>Set Mbeans attributes</li>
+ * </ul>
+ * <p>
+ * Examples:
+ * Set a Mbean Manager attribute maxActiveSessions.
+ * Set this attribute with fresh jmx connection without save reference 
+ * <pre>
+ *   &lt;jmx:set
+ *           host="127.0.0.1"
+ *           port="9014"
+ *           name="Catalina:type=Manager,path="/ClusterTest",host=localhost" 
+ *           attribute="maxActiveSessions"
+ *           value="100"
+ *           type="int"
+ *           echo="false"&gt;
+ *       /&gt;
+ * </pre>
+ *
+ * or 
+ * 
+ * <pre>
+ *   &lt;jmx:set
+ *           host="127.0.0.1"
+ *           port="9014"
+ *           name="Catalina:type=Manager,path="/ClusterTest",host=localhost" 
+ *           echo="false"&gt;
+ *       &gt;
+ *       
+ *        &lt;arg name="notifyListenersOnReplication"
+ *                value="true"
+ *                type="boolean"/&gt;
+ *        &lt;arg name="notifySessionListenersOnReplication"
+ *                value="true"
+ *                type="boolean"/&gt;
+ *   &lt;/jmx:set&gt;
+ *
+ * </pre>
+ * </p>
+ * <p>
+ * First call to a remote MBeanserver save the JMXConnection a referenz <em>jmx.server</em>
+ * </p>
+ * These tasks require Ant 1.6 or later interface.
+ *
+ * @author Peter Rossbach
+ * @version $Revision: 441172 $ $Date: 2006-09-07 13:38:07 -0500 (Thu, 07 Sep 2006) $
+ * @since 5.5.10
+ */
+
+public class JMXAccessorSetTask extends JMXAccessorTask {
+
+    // ----------------------------------------------------- Instance Variables
+
+    private String attribute;
+    private String value;
+    private String type;
+    private boolean convert = false ;
+    private List args=new ArrayList();
+
+    // ----------------------------------------------------- Instance Info
+
+    /**
+     * Descriptive information describing this implementation.
+     */
+    private static final String info = "org.apache.catalina.ant.JMXAccessorSetTask/1.1";
+
+    /**
+     * Return descriptive information about this implementation and the
+     * corresponding version number, in the format
+     * <code>&lt;description&gt;/&lt;version&gt;</code>.
+     */
+    public String getInfo() {
+
+        return (info);
+
+    }
+
+    // ------------------------------------------------------------- Properties
+
+    public void addArg(Arg attribute) {
+        args.add(attribute);
+    }
+
+    public List getArgs() {
+        return args;
+    }
+
+
+    /**
+     * @return Returns the attribute.
+     */
+    public String getAttribute() {
+        return attribute;
+    }
+
+    /**
+     * @param attribute The attribute to set.
+     */
+    public void setAttribute(String attribute) {
+        this.attribute = attribute;
+    }
+
+    /**
+     * @return Returns the value.
+     */
+    public String getValue() {
+        return value;
+    }
+    /**
+     * @param value The value to set.
+     */
+    public void setValue(String value) {
+        this.value = value;
+    }
+
+
+    /**
+     * @return Returns the type.
+     */
+    public String getType() {
+        return type;
+    }
+
+    /**
+     * @param valueType The type to set.
+     */
+    public void setType(String valueType) {
+        this.type = valueType;
+    }
+
+
+    /**
+     * @return Returns the convert.
+     */
+    public boolean isConvert() {
+        return convert;
+    }
+    /**
+     * @param convert The convert to set.
+     */
+    public void setConvert(boolean convert) {
+        this.convert = convert;
+    }
+    // ------------------------------------------------------ protected Methods
+
+    /**
+     * Execute the specified command, based on the configured properties. The
+     * input stream will be closed upon completion of this task, whether it was
+     * executed successfully or not.
+     * 
+     * @exception Exception
+     *                if an error occurs
+     */
+    public String jmxExecute(MBeanServerConnection jmxServerConnection)
+            throws Exception {
+
+        if (getName() == null) {
+            throw new BuildException("Must specify a 'name'");
+        }
+
+        if ((attribute == null || value == null) && args.isEmpty()) {
+            throw new BuildException(
+                    "Must specify a 'attribute' and 'value' or 'attribute' elements for set with args");
+        }
+        if (args.isEmpty()) {
+            return jmxSet(jmxServerConnection, getName());
+        } else {
+            if ((attribute != null && value != null)) {
+                Arg a = new Arg();
+                a.setName(attribute);
+                a.setValue(value);
+                a.setType(type);
+                args.add(a);
+            }
+            return jmxSetWithAttributList(jmxServerConnection, getName());
+        }
+    }
+
+    /**
+     * @param jmxServerConnection
+     * @param name
+     * @throws Exception
+     */
+    protected String jmxSet(MBeanServerConnection jmxServerConnection,
+            String name) throws Exception {
+        Object realValue;
+        if (type != null) {
+            realValue = convertStringToType(value, type);
+        } else {
+            if (isConvert()) {
+                String mType = getMBeanAttributeType(jmxServerConnection, name,
+                        attribute);
+                realValue = convertStringToType(value, mType);
+            } else
+                realValue = value;
+        }
+        jmxServerConnection.setAttribute(new ObjectName(name), new Attribute(
+                attribute, realValue));
+        return null;
+    }
+
+    /**
+     * set several attributes in one invocation to the server
+     * @param jmxServerConnection
+     * @param name
+     * @throws Exception
+     */
+    protected String jmxSetWithAttributList(MBeanServerConnection jmxServerConnection,
+            String name) throws Exception {
+
+        AttributeList attributeList = new AttributeList();
+        MBeanInfo minfo = null;
+
+        for (Iterator iter = args.iterator(); iter.hasNext();) {
+            Arg element = (Arg) iter.next();
+            Object realValue;
+            if (element.getType() != null) {
+                realValue = convertStringToType(element.getValue(), element
+                        .getType());
+            } else {
+                if (isConvert()) {
+                    if (minfo == null)
+                        minfo = getMBeanInfo(jmxServerConnection, name);
+                    String mType = getMBeanAttributeType(minfo, element
+                            .getName());
+                    realValue = convertStringToType(element.getValue(), mType);
+                } else
+                    realValue = element.getValue();
+            }
+            Attribute a = new Attribute(element.getName(), realValue);
+            attributeList.add(a);
+        }
+
+        AttributeList settedAttributes = jmxServerConnection.setAttributes(
+                new ObjectName(name), attributeList);
+        if (isEcho())
+            if (settedAttributes.isEmpty()) {
+                getProject().log("No setted attributes!");
+            } else {
+                StringBuffer sb = new StringBuffer();
+                sb.append("Attributes");
+                for (Iterator iter = settedAttributes.iterator(); iter
+                        .hasNext();) {
+                    Attribute element = (Attribute) iter.next();
+                    sb.append(' ').append(element.getName());
+                }
+                sb.append(" were setted");
+                getProject().log(sb.toString());
+            }
+        return null;
+    }
+
+    /**
+     * Get MBean Attribute from the MBeanInfo
+     * @param minfo
+     * @param attribute
+     * @return The type
+     * @throws Exception
+     */
+    protected String getMBeanAttributeType(
+            MBeanInfo minfo,
+            String attribute) throws Exception {
+        String mattrType = null;
+        MBeanAttributeInfo attrs[] = minfo.getAttributes();
+        if (attrs != null) {
+            for (int i = 0; mattrType == null && i < attrs.length; i++) {
+                if (attribute.equals(attrs[i].getName()))
+                    mattrType = attrs[i].getType();
+            }
+        }
+        return mattrType;
+    }
+
+
+    /**
+     * Get the MBeanInfo from Mbean Server
+     * @param jmxServerConnection
+     * @param name
+     * @return The mbean info
+     * @throws Exception
+     */
+    protected MBeanInfo getMBeanInfo(
+            MBeanServerConnection jmxServerConnection,
+            String name) throws Exception {
+        ObjectName oname = new ObjectName(name);
+        MBeanInfo minfo = jmxServerConnection.getMBeanInfo(oname);
+        return minfo;
+    }
+
+    /**
+     * Get MBean Attriute from Mbean Server
+     * @param jmxServerConnection
+     * @param name
+     * @param attribute
+     * @return The type
+     * @throws Exception
+     */
+    protected String getMBeanAttributeType(
+            MBeanServerConnection jmxServerConnection,
+            String name,
+            String attribute) throws Exception {
+        ObjectName oname = new ObjectName(name);
+        String mattrType = null;
+        MBeanInfo minfo = jmxServerConnection.getMBeanInfo(oname);
+        MBeanAttributeInfo attrs[] = minfo.getAttributes();
+        if (attrs != null) {
+            for (int i = 0; mattrType == null && i < attrs.length; i++) {
+                if (attribute.equals(attrs[i].getName()))
+                    mattrType = attrs[i].getType();
+            }
+        }
+        return mattrType;
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ant/jmx/JMXAccessorTask.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ant/jmx/JMXAccessorTask.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ant/jmx/JMXAccessorTask.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,731 @@
+/*
+ * Copyright 2002,2004-2005 The Apache Software Foundation.
+ * 
+ * Licensed 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.ant.jmx;
+
+import java.io.IOException;
+import java.lang.reflect.Array;
+import java.net.InetAddress;
+import java.net.MalformedURLException;
+import java.net.UnknownHostException;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+import java.util.StringTokenizer;
+
+import javax.management.MBeanServerConnection;
+import javax.management.MalformedObjectNameException;
+import javax.management.ObjectName;
+import javax.management.openmbean.CompositeData;
+import javax.management.openmbean.CompositeDataSupport;
+import javax.management.openmbean.CompositeType;
+import javax.management.openmbean.OpenType;
+import javax.management.openmbean.SimpleType;
+import javax.management.openmbean.TabularDataSupport;
+import javax.management.remote.JMXConnector;
+import javax.management.remote.JMXConnectorFactory;
+import javax.management.remote.JMXServiceURL;
+
+import org.apache.catalina.ant.BaseRedirectorHelperTask;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+
+/**
+ * Access <em>JMX</em> JSR 160 MBeans Server.
+ * <ul>
+ * <li>open more then one JSR 160 rmi connection</li>
+ * <li>Get/Set Mbeans attributes</li>
+ * <li>Call Mbean Operation with arguments</li>
+ * <li>Argument values can be converted from string to
+ * int,long,float,double,boolean,ObjectName or InetAddress</li>
+ * <li>Query Mbeans</li>
+ * <li>Show Get, Call, Query result at Ant console log</li>
+ * <li>Bind Get, Call, Query result at Ant properties</li>
+ * </ul>
+ * 
+ * Examples: open server with reference and autorisation
+ * 
+ * <pre>
+ * 
+ *    &lt;jmxOpen
+ *            host=&quot;127.0.0.1&quot;
+ *            port=&quot;9014&quot;
+ *            username=&quot;monitorRole&quot;
+ *            password=&quot;mysecret&quot;
+ *            ref=&quot;jmx.myserver&quot; 
+ *        /&gt;
+ *  
+ * </pre>
+ * 
+ * All calls after opening with same refid reuse the connection.
+ * <p>
+ * First call to a remote MBeanserver save the JMXConnection a referenz
+ * <em>jmx.server</em>
+ * </p>
+ * All JMXAccessorXXXTask support the attribute <em>if</em> and
+ * <em>unless</em>. With <em>if</em> the task is only execute when property
+ * exist and with <em>unless</em> when property not exists. <br/><b>NOTE
+ * </b>: These tasks require Ant 1.6 or later interface.
+ * 
+ * @author Peter Rossbach
+ * @version $Revision: 304089 $ $Date: 2005-09-14 08:28:29 -0500 (Wed, 14 Sep 2005) $
+ * @since 5.5.10
+ */
+
+public class JMXAccessorTask extends BaseRedirectorHelperTask {
+
+    // ----------------------------------------------------- Instance Variables
+
+    public static String JMX_SERVICE_PREFIX = "service:jmx:rmi:///jndi/rmi://";
+
+    public static String JMX_SERVICE_SUFFIX = "/jmxrmi";
+
+    private String name = null;
+
+    private String resultproperty;
+
+    private String url = null;
+
+    private String host = "localhost";
+
+    private String port = "8050";
+
+    private String password = null;
+
+    private String username = null;
+
+    private String ref = "jmx.server";
+
+    private boolean echo = false;
+
+    private boolean separatearrayresults = true;
+
+    private String delimiter;
+
+    private String unlessCondition;
+
+    private String ifCondition;
+
+    private Properties properties = new Properties();
+
+    // ----------------------------------------------------- Instance Info
+
+    /**
+     * Descriptive information describing this implementation.
+     */
+    private static final String info = "org.apache.catalina.ant.JMXAccessorTask/1.1";
+
+    /**
+     * Return descriptive information about this implementation and the
+     * corresponding version number, in the format
+     * <code>&lt;description&gt;/&lt;version&gt;</code>.
+     */
+    public String getInfo() {
+
+        return (info);
+
+    }
+
+    // ------------------------------------------------------------- Properties
+
+    /**
+     * The name used at remote MbeanServer
+     */
+
+    public String getName() {
+        return (this.name);
+    }
+
+    public void setName(String objectName) {
+        this.name = objectName;
+    }
+
+    /**
+     * @return Returns the resultproperty.
+     */
+    public String getResultproperty() {
+        return resultproperty;
+    }
+
+    /**
+     * @param propertyName The resultproperty to set.
+     */
+    public void setResultproperty(String propertyName) {
+        this.resultproperty = propertyName;
+    }
+
+    /**
+     * @return Returns the delimiter.
+     */
+    public String getDelimiter() {
+        return delimiter;
+    }
+
+    /**
+     * @param separator The delimiter to set.
+     */
+    public void setDelimiter(String separator) {
+        this.delimiter = separator;
+    }
+
+    /**
+     * @return Returns the echo.
+     */
+    public boolean isEcho() {
+        return echo;
+    }
+
+    /**
+     * @param echo
+     *            The echo to set.
+     */
+    public void setEcho(boolean echo) {
+        this.echo = echo;
+    }
+
+    /**
+     * @return Returns the separatearrayresults.
+     */
+    public boolean isSeparatearrayresults() {
+        return separatearrayresults;
+    }
+
+    /**
+     * @param separateArrayResults
+     *            The separatearrayresults to set.
+     */
+    public void setSeparatearrayresults(boolean separateArrayResults) {
+        this.separatearrayresults = separateArrayResults;
+    }
+
+    /**
+     * The login password for the <code>Manager</code> application.
+     */
+    public String getPassword() {
+        return (this.password);
+    }
+
+    public void setPassword(String password) {
+        this.password = password;
+    }
+
+    /**
+     * The login username for the <code>JMX</code> MBeanServer.
+     */
+    public String getUsername() {
+        return (this.username);
+    }
+
+    public void setUsername(String username) {
+        this.username = username;
+    }
+
+    /**
+     * The URL of the <code>JMX JSR 160</code> MBeanServer to be used.
+     */
+
+    public String getUrl() {
+        return (this.url);
+    }
+
+    public void setUrl(String url) {
+        this.url = url;
+    }
+
+    /**
+     * The Host of the <code>JMX JSR 160</code> MBeanServer to be used.
+     */
+
+    public String getHost() {
+        return (this.host);
+    }
+
+    public void setHost(String host) {
+        this.host = host;
+    }
+
+    /**
+     * The Port of the <code>JMX JSR 160</code> MBeanServer to be used.
+     */
+
+    public String getPort() {
+        return (this.port);
+    }
+
+    public void setPort(String port) {
+        this.port = port;
+    }
+
+    /**
+     * @return Returns the useRef.
+     */
+    public boolean isUseRef() {
+        return ref != null && !"".equals(ref);
+    }
+
+    /**
+     * @return Returns the ref.
+     */
+    public String getRef() {
+        return ref;
+    }
+
+    /**
+     * @param refId The ref to set.
+     */
+    public void setRef(String refId) {
+        this.ref = refId;
+    }
+
+    /**
+     * @return Returns the ifCondition.
+     */
+    public String getIf() {
+        return ifCondition;
+    }
+
+    /**
+     * Only execute if a property of the given name exists in the current
+     * project.
+     * 
+     * @param c property name
+     */
+    public void setIf(String c) {
+        ifCondition = c;
+    }
+
+    /**
+     * @return Returns the unlessCondition.
+     */
+    public String getUnless() {
+        return unlessCondition;
+    }
+
+    /**
+     * Only execute if a property of the given name does not exist in the
+     * current project.
+     * 
+     * @param c property name
+     */
+    public void setUnless(String c) {
+        unlessCondition = c;
+    }
+
+    // --------------------------------------------------------- Public Methods
+
+    /**
+     * Execute the specified command. This logic only performs the common
+     * attribute validation required by all subclasses; it does not perform any
+     * functional logic directly.
+     * 
+     * @exception BuildException
+     *                if a validation error occurs
+     */
+    public void execute() throws BuildException {
+        if (testIfCondition() && testUnlessCondition()) {
+            try {
+                String error = null;
+
+                MBeanServerConnection jmxServerConnection = getJMXConnection();
+                error = jmxExecute(jmxServerConnection);
+                if (error != null && isFailOnError()) {
+                    // exception should be thrown only if failOnError == true
+                    // or error line will be logged twice
+                    throw new BuildException(error);
+                }
+            } catch (Throwable t) {
+                if (isFailOnError()) {
+                    throw new BuildException(t);
+                } else {
+                    handleErrorOutput(t.getMessage());
+                }
+            } finally {
+                closeRedirector();
+            }
+        }
+    }
+
+    /**
+     * create a new JMX Connection with auth when username and password is set.
+     */
+    public static MBeanServerConnection createJMXConnection(String url,
+            String host, String port, String username, String password)
+            throws MalformedURLException, IOException {
+        String urlForJMX;
+        if (url != null)
+            urlForJMX = url;
+        else
+            urlForJMX = JMX_SERVICE_PREFIX + host + ":" + port
+                    + JMX_SERVICE_SUFFIX;
+        Map environment = null;
+        if (username != null && password != null) {
+            String[] credentials = new String[2];
+            credentials[0] = username;
+            credentials[1] = password;
+            environment = new HashMap();
+            environment.put(JMXConnector.CREDENTIALS, credentials);
+        }
+        return JMXConnectorFactory.connect(new JMXServiceURL(urlForJMX),
+                environment).getMBeanServerConnection();
+
+    }
+
+    /**
+     * test the if condition
+     * 
+     * @return true if there is no if condition, or the named property exists
+     */
+    protected boolean testIfCondition() {
+        if (ifCondition == null || "".equals(ifCondition)) {
+            return true;
+        }
+        return getProperty(ifCondition) != null;
+    }
+
+    /**
+     * test the unless condition
+     * 
+     * @return true if there is no unless condition, or there is a named
+     *         property but it doesn't exist
+     */
+    protected boolean testUnlessCondition() {
+        if (unlessCondition == null || "".equals(unlessCondition)) {
+            return true;
+        }
+        return getProperty(unlessCondition) == null;
+    }
+
+    /**
+     * Get Current Connection from <em>ref</em> parameter or create a new one!
+     * 
+     * @return The server connection
+     * @throws MalformedURLException
+     * @throws IOException
+     */
+    public static MBeanServerConnection accessJMXConnection(Project project,
+            String url, String host, String port, String username,
+            String password, String refId) throws MalformedURLException,
+            IOException {
+        MBeanServerConnection jmxServerConnection = null;
+        boolean isRef = project != null && refId != null && refId.length() > 0;
+        if (isRef) {
+            Object pref = project.getReference(refId);
+            try {
+                jmxServerConnection = (MBeanServerConnection) pref;
+            } catch (ClassCastException cce) {
+                if (project != null) {
+                    project.log("wrong object reference " + refId + " - "
+                            + pref.getClass());
+                }
+                return null;
+            }
+        }
+        if (jmxServerConnection == null) {
+            jmxServerConnection = createJMXConnection(url, host, port,
+                    username, password);
+        }
+        if (isRef && jmxServerConnection != null) {
+            project.addReference(refId, jmxServerConnection);
+        }
+        return jmxServerConnection;
+    }
+
+    // ------------------------------------------------------ protected Methods
+
+    /**
+     * get JMXConnection
+     * 
+     * @return The connection
+     * @throws MalformedURLException
+     * @throws IOException
+     */
+    protected MBeanServerConnection getJMXConnection()
+            throws MalformedURLException, IOException {
+
+        MBeanServerConnection jmxServerConnection = null;
+        if (isUseRef()) {
+            Object pref = null ;
+            if(getProject() != null) {
+                pref = getProject().getReference(getRef());
+                if (pref != null) {
+                    try {
+                        jmxServerConnection = (MBeanServerConnection) pref;
+                    } catch (ClassCastException cce) {
+                        getProject().log(
+                            "Wrong object reference " + getRef() + " - "
+                                    + pref.getClass());
+                        return null;
+                    }
+                }
+            }
+            if (jmxServerConnection == null) {
+                jmxServerConnection = accessJMXConnection(getProject(),
+                        getUrl(), getHost(), getPort(), getUsername(),
+                        getPassword(), getRef());
+            }
+        } else {
+            jmxServerConnection = accessJMXConnection(getProject(), getUrl(),
+                    getHost(), getPort(), getUsername(), getPassword(), null);
+        }
+        return jmxServerConnection;
+    }
+
+    /**
+     * Execute the specified command, based on the configured properties. The
+     * input stream will be closed upon completion of this task, whether it was
+     * executed successfully or not.
+     * 
+     * @exception Exception
+     *                if an error occurs
+     */
+    public String jmxExecute(MBeanServerConnection jmxServerConnection)
+            throws Exception {
+
+        if ((jmxServerConnection == null)) {
+            throw new BuildException("Must open a connection!");
+        } else if (isEcho()) {
+            handleOutput("JMX Connection ref=" + ref + " is open!");
+        }
+        return null;
+    }
+
+    /**
+     * Convert string to datatype FIXME How we can transfer values from ant
+     * project reference store (ref)?
+     * 
+     * @param value The value
+     * @param valueType The type
+     * @return The converted object
+     */
+    protected Object convertStringToType(String value, String valueType) {
+        if ("java.lang.String".equals(valueType))
+            return value;
+
+        Object convertValue = value;
+        if ("java.lang.Integer".equals(valueType) || "int".equals(valueType)) {
+            try {
+                convertValue = new Integer(value);
+            } catch (NumberFormatException ex) {
+                if (isEcho())
+                    handleErrorOutput("Unable to convert to integer:" + value);
+            }
+        } else if ("java.lang.Long".equals(valueType)
+                || "long".equals(valueType)) {
+            try {
+                convertValue = new Long(value);
+            } catch (NumberFormatException ex) {
+                if (isEcho())
+                    handleErrorOutput("Unable to convert to long:" + value);
+            }
+        } else if ("java.lang.Boolean".equals(valueType)
+                || "boolean".equals(valueType)) {
+            convertValue = new Boolean(value);
+        } else if ("java.lang.Float".equals(valueType)
+                || "float".equals(valueType)) {
+            try {
+                convertValue = new Float(value);
+            } catch (NumberFormatException ex) {
+                if (isEcho())
+                    handleErrorOutput("Unable to convert to float:" + value);
+            }
+        } else if ("java.lang.Double".equals(valueType)
+                || "double".equals(valueType)) {
+            try {
+                convertValue = new Double(value);
+            } catch (NumberFormatException ex) {
+                if (isEcho())
+                    handleErrorOutput("Unable to convert to double:" + value);
+            }
+        } else if ("javax.management.ObjectName".equals(valueType)
+                || "name".equals(valueType)) {
+            try {
+                convertValue = new ObjectName(value);
+            } catch (MalformedObjectNameException e) {
+                if (isEcho())
+                    handleErrorOutput("Unable to convert to ObjectName:"
+                            + value);
+            }
+        } else if ("java.net.InetAddress".equals(valueType)) {
+            try {
+                convertValue = InetAddress.getByName(value);
+            } catch (UnknownHostException exc) {
+                if (isEcho())
+                    handleErrorOutput("Unable to resolve host name:" + value);
+            }
+        }
+        return convertValue;
+    }
+
+    /**
+     * @param name context of result
+     * @param result
+     */
+    protected void echoResult(String name, Object result) {
+        if (isEcho()) {
+            if (result.getClass().isArray()) {
+                for (int i = 0; i < Array.getLength(result); i++) {
+                    handleOutput(name + "." + i + "=" + Array.get(result, i));
+                }
+            } else
+                handleOutput(name + "=" + result);
+        }
+    }
+
+    /**
+     * create result as property with name from attribute resultproperty
+     * 
+     * @param result The result
+     * @see #createProperty(String, Object)
+     */
+    protected void createProperty(Object result) {
+        if (resultproperty != null) {
+            createProperty(resultproperty, result);
+        }
+    }
+
+    /**
+     * create result as property with name from property prefix When result is
+     * an array and isSeparateArrayResults is true, resultproperty used as
+     * prefix (<code>resultproperty.0-array.length</code> and store the
+     * result array length at <code>resultproperty.length</code>. Other
+     * option is that you delemit your result with a delimiter
+     * (java.util.StringTokenizer is used).
+     * 
+     * @param propertyPrefix
+     * @param result
+     */
+    protected void createProperty(String propertyPrefix, Object result) {
+        if (propertyPrefix == null)
+            propertyPrefix = "";
+        if (result instanceof CompositeDataSupport) {
+            CompositeDataSupport data = (CompositeDataSupport) result;
+            CompositeType compositeType = data.getCompositeType();
+            Set keys = compositeType.keySet();
+            for (Iterator iter = keys.iterator(); iter.hasNext();) {
+                String key = (String) iter.next();
+                Object value = data.get(key);
+                OpenType type = compositeType.getType(key);
+                if (type instanceof SimpleType) {
+                    setProperty(propertyPrefix + "." + key, value);
+                } else {
+                    createProperty(propertyPrefix + "." + key, value);
+                }
+            }
+        } else if (result instanceof TabularDataSupport) {
+            TabularDataSupport data = (TabularDataSupport) result;
+            for (Iterator iter = data.keySet().iterator(); iter.hasNext();) {
+                Object key = iter.next();
+                for (Iterator iter1 = ((List) key).iterator(); iter1.hasNext();) {
+                    Object key1 = iter1.next();
+                    CompositeData valuedata = data.get(new Object[] { key1 });
+                    Object value = valuedata.get("value");
+                    OpenType type = valuedata.getCompositeType().getType(
+                            "value");
+                    if (type instanceof SimpleType) {
+                        setProperty(propertyPrefix + "." + key1, value);
+                    } else {
+                        createProperty(propertyPrefix + "." + key1, value);
+                    }
+                }
+            }
+        } else if (result.getClass().isArray()) {
+            if (isSeparatearrayresults()) {
+                int size = 0;
+                for (int i = 0; i < Array.getLength(result); i++) {
+                    if (setProperty(propertyPrefix + "." + size, Array.get(
+                            result, i))) {
+                        size++;
+                    }
+                }
+                if (size > 0) {
+                    setProperty(propertyPrefix + ".Length", Integer
+                            .toString(size));
+                }
+            }
+        } else {
+            String delim = getDelimiter();
+            if (delim != null) {
+                StringTokenizer tokenizer = new StringTokenizer(result
+                        .toString(), delim);
+                int size = 0;
+                for (; tokenizer.hasMoreTokens();) {
+                    String token = tokenizer.nextToken();
+                    if (setProperty(propertyPrefix + "." + size, token)) {
+                        size++;
+                    }
+                }
+                if (size > 0)
+                    setProperty(propertyPrefix + ".Length", Integer
+                            .toString(size));
+            } else {
+                setProperty(propertyPrefix, result.toString());
+            }
+        }
+    }
+
+    /**
+     * get all properties, when project is there got all project Properties
+     * @return properties
+     */
+    public Map getProperties() {
+        Project currentProject = getProject();
+        if (currentProject != null) {
+            return currentProject.getProperties();
+        } else {
+            return properties;
+        }        
+    }
+    
+    /**
+     * get all Properties
+     * @param property
+     * @return The property
+     */
+    public String getProperty(String property) {
+        Project currentProject = getProject();
+        if (currentProject != null) {
+            return currentProject.getProperty(property);
+        } else {
+            return properties.getProperty(property);
+        }
+    }
+
+    /**
+     * @param property The property
+     * @param value The value
+     * @return True if successful
+     */
+    public boolean setProperty(String property, Object value) {
+        if (property != null) {
+            if (value == null)
+                value = "";
+            if (isEcho()) {
+                handleOutput(property + "=" + value.toString());
+            }
+            Project currentProject = getProject();
+            if (currentProject != null) {
+                currentProject.setNewProperty(property, value.toString());
+            } else {
+                properties.setProperty(property, value.toString());
+            }
+            return true;
+        }
+        return false;
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ant/jmx/JMXAccessorUnregisterTask.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ant/jmx/JMXAccessorUnregisterTask.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ant/jmx/JMXAccessorUnregisterTask.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,112 @@
+/*
+ * Copyright 2002,2004-2005 The Apache Software Foundation.
+ * 
+ * Licensed 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.ant.jmx;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.management.MBeanServerConnection;
+import javax.management.ObjectName;
+
+import org.apache.tools.ant.BuildException;
+
+/**
+ * unregister a MBean at <em>JMX</em> JSR 160 MBeans Server. 
+ * <ul>
+ * <li>unregister Mbeans</li>
+ * </ul>
+ * <p>
+ * Examples:
+ * <br/>
+ * unregister an existing Mbean at jmx.server connection 
+ * <pre>
+ *   &lt;jmx:unregister
+ *           ref="jmx.server"
+ *           name="Catalina:type=MBeanFactory" /&gt;
+ * </pre>
+ * </p>
+ * <p>
+ * <b>WARNING</b>Not all Tomcat MBeans can successfully unregister remotely. The mbean
+ * unregistration don't remove valves, realm, .. from parent class.
+ * Please, use the MBeanFactory operation to remove valves and realms.
+ * </p>
+ * <p>
+ * First call to a remote MBeanserver save the JMXConnection a reference <em>jmx.server</em>
+ * </p>
+ * These tasks require Ant 1.6 or later interface.
+ *
+ * @author Peter Rossbach
+ * @version $Revision: 304089 $
+ * @since 5.5.12
+ */
+public class JMXAccessorUnregisterTask extends JMXAccessorTask {
+
+    // ----------------------------------------------------- Instance Info
+
+    /**
+     * Descriptive information describing this implementation.
+     */
+    private static final String info = "org.apache.catalina.ant.JMXAccessorUnregisterTask/1.0";
+
+    /**
+     * Return descriptive information about this implementation and the
+     * corresponding version number, in the format
+     * <code>&lt;description&gt;/&lt;version&gt;</code>.
+     * @return Returns the class info.
+     */
+    public String getInfo() {
+
+        return (info);
+
+    }
+    // ------------------------------------------------------ protected Methods
+    
+    /**
+     * Execute the specified command, based on the configured properties. The
+     * input stream will be closed upon completion of this task, whether it was
+     * executed successfully or not.
+     * 
+     * @exception Exception
+     *                if an error occurs
+     */
+    public String jmxExecute(MBeanServerConnection jmxServerConnection)
+        throws Exception {
+
+        if (getName() == null) {
+            throw new BuildException("Must specify a 'name'");
+        }
+        return  jmxUuregister(jmxServerConnection, getName());
+     }
+
+
+    /**
+     * Unregister Mbean
+     * @param jmxServerConnection
+     * @param name
+     * @return The value of the given named attribute
+     * @throws Exception
+     */
+    protected String jmxUuregister(MBeanServerConnection jmxServerConnection,String name) throws Exception {
+        String error = null;
+        if(isEcho()) {
+            handleOutput("Unregister MBean " + name  );
+        }
+        jmxServerConnection.unregisterMBean(
+                new ObjectName(name));
+        return error;
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ant/jmx/antlib.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ant/jmx/antlib.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ant/jmx/antlib.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<antlib>
+  <typedef
+        name="open"
+        classname="org.apache.catalina.ant.jmx.JMXAccessorTask" />
+  <typedef
+        name="set"
+        classname="org.apache.catalina.ant.jmx.JMXAccessorSetTask" />
+  <typedef
+        name="get"
+        classname="org.apache.catalina.ant.jmx.JMXAccessorGetTask" />
+  <typedef
+        name="invoke"
+        classname="org.apache.catalina.ant.jmx.JMXAccessorInvokeTask" />
+  <typedef
+        name="query"
+        classname="org.apache.catalina.ant.jmx.JMXAccessorQueryTask" />
+  <typedef
+        name="create"
+        classname="org.apache.catalina.ant.jmx.JMXAccessorCreateTask" />
+  <typedef
+        name="unregister"
+        classname="org.apache.catalina.ant.jmx.JMXAccessorUnregisterTask" />
+  <typedef
+        name="equals"
+        classname="org.apache.catalina.ant.jmx.JMXAccessorEqualsCondition" />
+  <typedef
+        name="condition"
+        classname="org.apache.catalina.ant.jmx.JMXAccessorCondition" />
+</antlib>

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ant/jmx/jmxaccessor.tasks
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ant/jmx/jmxaccessor.tasks	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ant/jmx/jmxaccessor.tasks	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,8 @@
+# JMX
+jmxOpen=org.apache.catalina.ant.jmx.JMXAccessorTask
+jmxSet=org.apache.catalina.ant.jmx.JMXAccessorSetTask
+jmxGet=org.apache.catalina.ant.jmx.JMXAccessorGetTask
+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

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ant/jmx/package.html
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ant/jmx/package.html	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ant/jmx/package.html	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,61 @@
+<body>
+
+<p>This package contains a set of <code>JMX Task</code> implementations for
+<em>Ant (version 1.6 or later)</em> that can be used to interact with the
+Remote JMX JSR 160 RMI Adaptor to get/set attributes, invoke MBean operations
+and query for Mbeans inside a running instance of Tomcat.  For more information, see
+<a href="http://jakarta.apache.org/tomcat/tomcat-5.5-doc/monitoring.html">
+http://jakarta.apache.org/tomcat/tomcat-5.5-doc/monitoring.html</a>.</p>
+
+<p>Each task element can open a new jmx connection or reference an
+	existing one. The following attribute are exists in every tasks:
+</p>
+
+<table>
+  <tr>
+    <th align="center" width="15%">Attribute</th>
+    <th align="center" width="85%">Description</th>
+  </tr>
+  <tr>
+    <td align="center">url</td>
+    <td>
+      The JMX Connection URL of the remote Tomcat MBeansServer.
+    </td>
+  </tr>
+  <tr>
+    <td align="center">username</td>
+    <td>
+      The username of a MBeanServer auth, when configured.
+    </td>
+  </tr>
+  <tr>
+    <td align="center">password</td>
+    <td>
+      The password of a MBeanServer auth, when configured.
+    </td>
+  </tr>
+  <tr>
+    <td align="center">host</td>
+    <td>
+      The JMX Connection host.
+    </td>
+  </tr>
+  <tr>
+    <td align="center">port</td>
+    <td>
+      The JMX Connection port.
+    </td>
+  </tr>
+  <tr>
+    <td align="center">ref</td>
+    <td>
+      The name of the ant internal reference for a jmx connection.
+    </td>
+  </tr>
+
+</table>
+
+<p><strong>NOTE</strong> - This Tasks only work, 
+	when JSR 160 MBean Adaptor as remote jvm is configured.</p>
+
+</body>

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ant/package.html
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ant/package.html	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ant/package.html	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,86 @@
+<body>
+
+<p>This package contains a set of <code>Task</code> implementations for
+<em>Ant (version 1.6.x or later)</em> that can be used to interact with the
+Manager application to deploy, undeploy, list, reload, start and stop web applications 
+from a running instance of Tomcat.  For more information, see
+<a href="http://jakarta.apache.org/tomcat/tomcat-5.5-doc/manager-howto.html">
+http://jakarta.apache.org/tomcat/tomcat-5.5-doc/manager-howto.html</a>.</p>
+
+<p>The attributes of each task element correspond
+exactly to the request parameters that are included with an HTTP request
+sent directly to the Manager application.  They are summarized as follows:
+</p>
+
+<table>
+  <tr>
+    <th align="center" width="15%">Attribute</th>
+    <th align="center" width="85%">Description</th>
+  </tr>
+  <tr>
+    <td align="center">url</td>
+    <td>
+      The URL of the Manager web application you will use to
+      perform the requested operations.  If not specified, defaults to
+      <code>http://localhost:8080/manager</code> (which corresponds
+      to a standard installation of Tomcat 5).
+    </td>
+  </tr>
+  <tr>
+    <td align="center">username</td>
+    <td>
+      The username of a Tomcat user that has been configured with the
+      <code>manager</code> role, as required to execute Manager
+      application commands.  This attribute is required.
+    </td>
+  </tr>
+  <tr>
+    <td align="center">password</td>
+    <td>
+      The password of a Tomcat user that has been configured with the
+      <code>manager</code> role, as required to execute Manager
+      application commands.  This attribute is required.
+    </td>
+  </tr>
+  <tr>
+    <td align="center">config</td>
+    <td>
+      A URL pointing at the context configuration file (i.e. a file
+      containing only the <code>&lt;Context&gt;</code> element, and
+      its nested elements, from <code>server.xml</code> for a particular
+      web application).  This attribute is supported only on the
+      <code>install</code> target, and is required only if you wish to
+      install an application with non-default configuration characteristics.
+    </td>
+  </tr>
+  <tr>
+    <td align="center">path</td>
+    <td>
+      The context path (including the leading slash) of the web application
+      this command is intended to manage, or a zero-length string for the
+      ROOT web application.  This attribute is valid for the
+      <code>install</code>, <code>reload</code>, <code>remove</code>,
+      <code>start</code>, and <code>stop</code> tasks only, and is
+      required in all of those cases.
+    </td>
+  </tr>
+  <tr>
+    <td align="center">war</td>
+    <td>
+      A <code>jar:</code> URL that points at a web application archive (WAR)
+      file, or a <code>file:</code> URL that points at an unpacked directory
+      containing the web application.  This attribute is supported only on
+      the <code>install</code> target.  You must specify at least one of the
+      <code>config</code> and <code>war</code> attributes; if you specify
+      both, the <code>war</code> attribute overrides the <code>docBase</code>
+      attribute in the context configuration file.
+    </td>
+  </tr>
+</table>
+
+<p><strong>NOTE</strong> - Commands executed through the <em>Manager</em>
+application are <strong>NOT</strong> reflected in updates to the Tomcat
+<code>server.xml</code> configuration file, so they do not persist past the
+next time you restart the entire Tomcat container.</p>
+
+</body>

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/authenticator/AuthenticatorBase.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/authenticator/AuthenticatorBase.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/authenticator/AuthenticatorBase.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,880 @@
+/*
+ * Copyright 1999-2001,2004-2005 The Apache Software Foundation.
+ * 
+ * Licensed 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.authenticator;
+
+
+import java.io.IOException;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.Principal;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Locale;
+import java.util.Random;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.Cookie;
+
+import org.apache.catalina.Authenticator;
+import org.apache.catalina.Container;
+import org.apache.catalina.Context;
+import org.apache.catalina.Lifecycle;
+import org.apache.catalina.LifecycleException;
+import org.apache.catalina.LifecycleListener;
+import org.apache.catalina.Pipeline;
+import org.apache.catalina.Realm;
+import org.apache.catalina.Session;
+import org.apache.catalina.Valve;
+import org.apache.catalina.connector.Request;
+import org.apache.catalina.connector.Response;
+import org.apache.catalina.deploy.LoginConfig;
+import org.apache.catalina.deploy.SecurityConstraint;
+import org.apache.catalina.util.DateTool;
+import org.apache.catalina.util.LifecycleSupport;
+import org.apache.catalina.util.StringManager;
+import org.apache.catalina.valves.ValveBase;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+
+/**
+ * Basic implementation of the <b>Valve</b> interface that enforces the
+ * <code>&lt;security-constraint&gt;</code> elements in the web application
+ * deployment descriptor.  This functionality is implemented as a Valve
+ * so that it can be ommitted in environments that do not require these
+ * features.  Individual implementations of each supported authentication
+ * method can subclass this base class as required.
+ * <p>
+ * <b>USAGE CONSTRAINT</b>:  When this class is utilized, the Context to
+ * which it is attached (or a parent Container in a hierarchy) must have an
+ * associated Realm that can be used for authenticating users and enumerating
+ * the roles to which they have been assigned.
+ * <p>
+ * <b>USAGE CONSTRAINT</b>:  This Valve is only useful when processing HTTP
+ * requests.  Requests of any other type will simply be passed through.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 357143 $ $Date: 2005-12-16 02:13:19 -0600 (Fri, 16 Dec 2005) $
+ */
+
+
+public abstract class AuthenticatorBase
+    extends ValveBase
+    implements Authenticator, Lifecycle {
+    private static Log log = LogFactory.getLog(AuthenticatorBase.class);
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The default message digest algorithm to use if we cannot use
+     * the requested one.
+     */
+    protected static final String DEFAULT_ALGORITHM = "MD5";
+
+
+    /**
+     * The number of random bytes to include when generating a
+     * session identifier.
+     */
+    protected static final int SESSION_ID_BYTES = 16;
+
+
+    /**
+     * The message digest algorithm to be used when generating session
+     * identifiers.  This must be an algorithm supported by the
+     * <code>java.security.MessageDigest</code> class on your platform.
+     */
+    protected String algorithm = DEFAULT_ALGORITHM;
+
+
+    /**
+     * Should we cache authenticated Principals if the request is part of
+     * an HTTP session?
+     */
+    protected boolean cache = true;
+
+
+    /**
+     * The Context to which this Valve is attached.
+     */
+    protected Context context = null;
+
+
+    /**
+     * Return the MessageDigest implementation to be used when
+     * creating session identifiers.
+     */
+    protected MessageDigest digest = null;
+
+
+    /**
+     * A String initialization parameter used to increase the entropy of
+     * the initialization of our random number generator.
+     */
+    protected String entropy = null;
+
+
+    /**
+     * Descriptive information about this implementation.
+     */
+    protected static final String info =
+        "org.apache.catalina.authenticator.AuthenticatorBase/1.0";
+
+    /**
+     * Flag to determine if we disable proxy caching, or leave the issue
+     * up to the webapp developer.
+     */
+    protected boolean disableProxyCaching = true;
+
+    /**
+     * Flag to determine if we disable proxy caching with headers incompatible
+     * with IE 
+     */
+    protected boolean securePagesWithPragma = true;
+    
+    /**
+     * The lifecycle event support for this component.
+     */
+    protected LifecycleSupport lifecycle = new LifecycleSupport(this);
+
+
+    /**
+     * A random number generator to use when generating session identifiers.
+     */
+    protected Random random = null;
+
+
+    /**
+     * The Java class name of the random number generator class to be used
+     * when generating session identifiers.
+     */
+    protected String randomClass = "java.security.SecureRandom";
+
+
+    /**
+     * The string manager for this package.
+     */
+    protected static final StringManager sm =
+        StringManager.getManager(Constants.Package);
+
+
+    /**
+     * The SingleSignOn implementation in our request processing chain,
+     * if there is one.
+     */
+    protected SingleSignOn sso = null;
+
+
+    /**
+     * Has this component been started?
+     */
+    protected boolean started = false;
+
+
+    /**
+     * "Expires" header always set to Date(1), so generate once only
+     */
+    private static final String DATE_ONE =
+        (new SimpleDateFormat(DateTool.HTTP_RESPONSE_DATE_HEADER,
+                              Locale.US)).format(new Date(1));
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * Return the message digest algorithm for this Manager.
+     */
+    public String getAlgorithm() {
+
+        return (this.algorithm);
+
+    }
+
+
+    /**
+     * Set the message digest algorithm for this Manager.
+     *
+     * @param algorithm The new message digest algorithm
+     */
+    public void setAlgorithm(String algorithm) {
+
+        this.algorithm = algorithm;
+
+    }
+
+
+    /**
+     * Return the cache authenticated Principals flag.
+     */
+    public boolean getCache() {
+
+        return (this.cache);
+
+    }
+
+
+    /**
+     * Set the cache authenticated Principals flag.
+     *
+     * @param cache The new cache flag
+     */
+    public void setCache(boolean cache) {
+
+        this.cache = cache;
+
+    }
+
+
+    /**
+     * Return the Container to which this Valve is attached.
+     */
+    public Container getContainer() {
+
+        return (this.context);
+
+    }
+
+
+    /**
+     * Set the Container to which this Valve is attached.
+     *
+     * @param container The container to which we are attached
+     */
+    public void setContainer(Container container) {
+
+        if (!(container instanceof Context))
+            throw new IllegalArgumentException
+                (sm.getString("authenticator.notContext"));
+
+        super.setContainer(container);
+        this.context = (Context) container;
+
+    }
+
+
+    /**
+     * Return the entropy increaser value, or compute a semi-useful value
+     * if this String has not yet been set.
+     */
+    public String getEntropy() {
+
+        // Calculate a semi-useful value if this has not been set
+        if (this.entropy == null)
+            setEntropy(this.toString());
+
+        return (this.entropy);
+
+    }
+
+
+    /**
+     * Set the entropy increaser value.
+     *
+     * @param entropy The new entropy increaser value
+     */
+    public void setEntropy(String entropy) {
+
+        this.entropy = entropy;
+
+    }
+
+
+    /**
+     * Return descriptive information about this Valve implementation.
+     */
+    public String getInfo() {
+
+        return (info);
+
+    }
+
+
+    /**
+     * Return the random number generator class name.
+     */
+    public String getRandomClass() {
+
+        return (this.randomClass);
+
+    }
+
+
+    /**
+     * Set the random number generator class name.
+     *
+     * @param randomClass The new random number generator class name
+     */
+    public void setRandomClass(String randomClass) {
+
+        this.randomClass = randomClass;
+
+    }
+
+    /**
+     * Return the flag that states if we add headers to disable caching by
+     * proxies.
+     */
+    public boolean getDisableProxyCaching() {
+        return disableProxyCaching;
+    }
+
+    /**
+     * Set the value of the flag that states if we add headers to disable
+     * caching by proxies.
+     * @param nocache <code>true</code> if we add headers to disable proxy 
+     *              caching, <code>false</code> if we leave the headers alone.
+     */
+    public void setDisableProxyCaching(boolean nocache) {
+        disableProxyCaching = nocache;
+    }
+    
+    /**
+     * Return the flag that states, if proxy caching is disabled, what headers
+     * we add to disable the caching.
+     */
+    public boolean getSecurePagesWithPragma() {
+        return securePagesWithPragma;
+    }
+
+    /**
+     * Set the value of the flag that states what headers we add to disable
+     * proxy caching.
+     * @param securePagesWithPragma <code>true</code> if we add headers which 
+     * are incompatible with downloading office documents in IE under SSL but
+     * which fix a caching problem in Mozilla.
+     */
+    public void setSecurePagesWithPragma(boolean securePagesWithPragma) {
+        this.securePagesWithPragma = securePagesWithPragma;
+    }    
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Enforce the security restrictions in the web application deployment
+     * descriptor of our associated Context.
+     *
+     * @param request Request to be processed
+     * @param response Response to be processed
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception ServletException if thrown by a processing element
+     */
+    public void invoke(Request request, Response response)
+        throws IOException, ServletException {
+
+        if (log.isDebugEnabled())
+            log.debug("Security checking request " +
+                request.getMethod() + " " + request.getRequestURI());
+        LoginConfig config = this.context.getLoginConfig();
+
+        // Have we got a cached authenticated Principal to record?
+        if (cache) {
+            Principal principal = request.getUserPrincipal();
+            if (principal == null) {
+                Session session = request.getSessionInternal(false);
+                if (session != null) {
+                    principal = session.getPrincipal();
+                    if (principal != null) {
+                        if (log.isDebugEnabled())
+                            log.debug("We have cached auth type " +
+                                session.getAuthType() +
+                                " for principal " +
+                                session.getPrincipal());
+                        request.setAuthType(session.getAuthType());
+                        request.setUserPrincipal(principal);
+                    }
+                }
+            }
+        }
+
+        // Special handling for form-based logins to deal with the case
+        // where the login form (and therefore the "j_security_check" URI
+        // to which it submits) might be outside the secured area
+        String contextPath = this.context.getPath();
+        String requestURI = request.getDecodedRequestURI();
+        if (requestURI.startsWith(contextPath) &&
+            requestURI.endsWith(Constants.FORM_ACTION)) {
+            if (!authenticate(request, response, config)) {
+                if (log.isDebugEnabled())
+                    log.debug(" Failed authenticate() test ??" + requestURI );
+                return;
+            }
+        }
+
+        Realm realm = this.context.getRealm();
+        // Is this request URI subject to a security constraint?
+        SecurityConstraint [] constraints
+            = realm.findSecurityConstraints(request, this.context);
+       
+        if ((constraints == null) /* &&
+            (!Constants.FORM_METHOD.equals(config.getAuthMethod())) */ ) {
+            if (log.isDebugEnabled())
+                log.debug(" Not subject to any constraint");
+            getNext().invoke(request, response);
+            return;
+        }
+
+        // Make sure that constrained resources are not cached by web proxies
+        // or browsers as caching can provide a security hole
+        if (disableProxyCaching && 
+            // FIXME: Disabled for Mozilla FORM support over SSL 
+            // (improper caching issue)
+            //!request.isSecure() &&
+            !"POST".equalsIgnoreCase(request.getMethod())) {
+            if (securePagesWithPragma) {
+                // FIXME: These cause problems with downloading office docs
+                // from IE under SSL and may not be needed for newer Mozilla
+                // clients.
+                response.setHeader("Pragma", "No-cache");
+                response.setHeader("Cache-Control", "no-cache");
+            } else {
+                response.setHeader("Cache-Control", "private");
+            }
+            response.setHeader("Expires", DATE_ONE);
+        }
+
+        int i;
+        // Enforce any user data constraint for this security constraint
+        if (log.isDebugEnabled()) {
+            log.debug(" Calling hasUserDataPermission()");
+        }
+        if (!realm.hasUserDataPermission(request, response,
+                                         constraints)) {
+            if (log.isDebugEnabled()) {
+                log.debug(" Failed hasUserDataPermission() test");
+            }
+            /*
+             * ASSERT: Authenticator already set the appropriate
+             * HTTP status code, so we do not have to do anything special
+             */
+            return;
+        }
+
+        // Since authenticate modifies the response on failure,
+        // we have to check for allow-from-all first.
+        boolean authRequired = true;
+        for(i=0; i < constraints.length && authRequired; i++) {
+            if(!constraints[i].getAuthConstraint()) {
+                authRequired = false;
+            } else if(!constraints[i].getAllRoles()) {
+                String [] roles = constraints[i].findAuthRoles();
+                if(roles == null || roles.length == 0) {
+                    authRequired = false;
+                }
+            }
+        }
+             
+        if(authRequired) {  
+            if (log.isDebugEnabled()) {
+                log.debug(" Calling authenticate()");
+            }
+            if (!authenticate(request, response, config)) {
+                if (log.isDebugEnabled()) {
+                    log.debug(" Failed authenticate() test");
+                }
+                /*
+                 * ASSERT: Authenticator already set the appropriate
+                 * HTTP status code, so we do not have to do anything
+                 * special
+                 */
+                return;
+            } 
+        }
+    
+        if (log.isDebugEnabled()) {
+            log.debug(" Calling accessControl()");
+        }
+        if (!realm.hasResourcePermission(request, response,
+                                         constraints,
+                                         this.context)) {
+            if (log.isDebugEnabled()) {
+                log.debug(" Failed accessControl() test");
+            }
+            /*
+             * ASSERT: AccessControl method has already set the
+             * appropriate HTTP status code, so we do not have to do
+             * anything special
+             */
+            return;
+        }
+    
+        // Any and all specified constraints have been satisfied
+        if (log.isDebugEnabled()) {
+            log.debug(" Successfully passed all security constraints");
+        }
+        getNext().invoke(request, response);
+
+    }
+
+
+    // ------------------------------------------------------ Protected Methods
+
+
+
+
+    /**
+     * Associate the specified single sign on identifier with the
+     * specified Session.
+     *
+     * @param ssoId Single sign on identifier
+     * @param session Session to be associated
+     */
+    protected void associate(String ssoId, Session session) {
+
+        if (sso == null)
+            return;
+        sso.associate(ssoId, session);
+
+    }
+
+
+    /**
+     * Authenticate the user making this request, based on the specified
+     * login configuration.  Return <code>true</code> if any specified
+     * constraint has been satisfied, or <code>false</code> if we have
+     * created a response challenge already.
+     *
+     * @param request Request we are processing
+     * @param response Response we are creating
+     * @param config    Login configuration describing how authentication
+     *              should be performed
+     *
+     * @exception IOException if an input/output error occurs
+     */
+    protected abstract boolean authenticate(Request request,
+                                            Response response,
+                                            LoginConfig config)
+        throws IOException;
+
+
+    /**
+     * Generate and return a new session identifier for the cookie that
+     * identifies an SSO principal.
+     */
+    protected synchronized String generateSessionId() {
+
+        // Generate a byte array containing a session identifier
+        byte bytes[] = new byte[SESSION_ID_BYTES];
+        getRandom().nextBytes(bytes);
+        bytes = getDigest().digest(bytes);
+
+        // Render the result as a String of hexadecimal digits
+        StringBuffer result = new StringBuffer();
+        for (int i = 0; i < bytes.length; i++) {
+            byte b1 = (byte) ((bytes[i] & 0xf0) >> 4);
+            byte b2 = (byte) (bytes[i] & 0x0f);
+            if (b1 < 10)
+                result.append((char) ('0' + b1));
+            else
+                result.append((char) ('A' + (b1 - 10)));
+            if (b2 < 10)
+                result.append((char) ('0' + b2));
+            else
+                result.append((char) ('A' + (b2 - 10)));
+        }
+        return (result.toString());
+
+    }
+
+
+    /**
+     * Return the MessageDigest object to be used for calculating
+     * session identifiers.  If none has been created yet, initialize
+     * one the first time this method is called.
+     */
+    protected synchronized MessageDigest getDigest() {
+
+        if (this.digest == null) {
+            try {
+                this.digest = MessageDigest.getInstance(algorithm);
+            } catch (NoSuchAlgorithmException e) {
+                try {
+                    this.digest = MessageDigest.getInstance(DEFAULT_ALGORITHM);
+                } catch (NoSuchAlgorithmException f) {
+                    this.digest = null;
+                }
+            }
+        }
+
+        return (this.digest);
+
+    }
+
+
+    /**
+     * Return the random number generator instance we should use for
+     * generating session identifiers.  If there is no such generator
+     * currently defined, construct and seed a new one.
+     */
+    protected synchronized Random getRandom() {
+
+        if (this.random == null) {
+            try {
+                Class clazz = Class.forName(randomClass);
+                this.random = (Random) clazz.newInstance();
+                long seed = System.currentTimeMillis();
+                char entropy[] = getEntropy().toCharArray();
+                for (int i = 0; i < entropy.length; i++) {
+                    long update = ((byte) entropy[i]) << ((i % 8) * 8);
+                    seed ^= update;
+                }
+                this.random.setSeed(seed);
+            } catch (Exception e) {
+                this.random = new java.util.Random();
+            }
+        }
+
+        return (this.random);
+
+    }
+
+
+    /**
+     * Attempts reauthentication to the <code>Realm</code> using
+     * the credentials included in argument <code>entry</code>.
+     *
+     * @param ssoId identifier of SingleSignOn session with which the
+     *              caller is associated
+     * @param request   the request that needs to be authenticated
+     */
+    protected boolean reauthenticateFromSSO(String ssoId, Request request) {
+
+        if (sso == null || ssoId == null)
+            return false;
+
+        boolean reauthenticated = false;
+
+        Container parent = getContainer();
+        if (parent != null) {
+            Realm realm = parent.getRealm();
+            if (realm != null) {
+                reauthenticated = sso.reauthenticate(ssoId, realm, request);
+            }
+        }
+
+        if (reauthenticated) {
+            associate(ssoId, request.getSessionInternal(true));
+
+            if (log.isDebugEnabled()) {
+                log.debug(" Reauthenticated cached principal '" +
+                          request.getUserPrincipal().getName() +
+                          "' with auth type '" +  request.getAuthType() + "'");
+            }
+        }
+
+        return reauthenticated;
+    }
+
+
+    /**
+     * Register an authenticated Principal and authentication type in our
+     * request, in the current session (if there is one), and with our
+     * SingleSignOn valve, if there is one.  Set the appropriate cookie
+     * to be returned.
+     *
+     * @param request The servlet request we are processing
+     * @param response The servlet response we are generating
+     * @param principal The authenticated Principal to be registered
+     * @param authType The authentication type to be registered
+     * @param username Username used to authenticate (if any)
+     * @param password Password used to authenticate (if any)
+     */
+    protected void register(Request request, Response response,
+                            Principal principal, String authType,
+                            String username, String password) {
+
+        if (log.isDebugEnabled())
+            log.debug("Authenticated '" + principal.getName() + "' with type '"
+                + authType + "'");
+
+        // Cache the authentication information in our request
+        request.setAuthType(authType);
+        request.setUserPrincipal(principal);
+
+        Session session = request.getSessionInternal(false);
+        // Cache the authentication information in our session, if any
+        if (cache) {
+            if (session != null) {
+                session.setAuthType(authType);
+                session.setPrincipal(principal);
+                if (username != null)
+                    session.setNote(Constants.SESS_USERNAME_NOTE, username);
+                else
+                    session.removeNote(Constants.SESS_USERNAME_NOTE);
+                if (password != null)
+                    session.setNote(Constants.SESS_PASSWORD_NOTE, password);
+                else
+                    session.removeNote(Constants.SESS_PASSWORD_NOTE);
+            }
+        }
+
+        // Construct a cookie to be returned to the client
+        if (sso == null)
+            return;
+
+        // Only create a new SSO entry if the SSO did not already set a note
+        // for an existing entry (as it would do with subsequent requests
+        // for DIGEST and SSL authenticated contexts)
+        String ssoId = (String) request.getNote(Constants.REQ_SSOID_NOTE);
+        if (ssoId == null) {
+            // Construct a cookie to be returned to the client
+            ssoId = generateSessionId();
+            Cookie cookie = new Cookie(Constants.SINGLE_SIGN_ON_COOKIE, ssoId);
+            cookie.setMaxAge(-1);
+            cookie.setPath("/");
+            
+            // Bugzilla 34724
+            String ssoDomain = sso.getCookieDomain();
+            if(ssoDomain != null) {
+                cookie.setDomain(ssoDomain);
+            }
+
+            response.addCookie(cookie);
+
+            // Register this principal with our SSO valve
+            sso.register(ssoId, principal, authType, username, password);
+            request.setNote(Constants.REQ_SSOID_NOTE, ssoId);
+
+        } else {
+            // Update the SSO session with the latest authentication data
+            sso.update(ssoId, principal, authType, username, password);
+        }
+
+        // Fix for Bug 10040
+        // Always associate a session with a new SSO reqistration.
+        // SSO entries are only removed from the SSO registry map when
+        // associated sessions are destroyed; if a new SSO entry is created
+        // above for this request and the user never revisits the context, the
+        // SSO entry will never be cleared if we don't associate the session
+        if (session == null)
+            session = request.getSessionInternal(true);
+        sso.associate(ssoId, session);
+
+    }
+
+
+    // ------------------------------------------------------ Lifecycle Methods
+
+
+    /**
+     * Add a lifecycle event listener to this component.
+     *
+     * @param listener The listener to add
+     */
+    public void addLifecycleListener(LifecycleListener listener) {
+
+        lifecycle.addLifecycleListener(listener);
+
+    }
+
+
+    /**
+     * Get the lifecycle listeners associated with this lifecycle. If this 
+     * Lifecycle has no listeners registered, a zero-length array is returned.
+     */
+    public LifecycleListener[] findLifecycleListeners() {
+
+        return lifecycle.findLifecycleListeners();
+
+    }
+
+
+    /**
+     * Remove a lifecycle event listener from this component.
+     *
+     * @param listener The listener to remove
+     */
+    public void removeLifecycleListener(LifecycleListener listener) {
+
+        lifecycle.removeLifecycleListener(listener);
+
+    }
+
+
+    /**
+     * Prepare for the beginning of active use of the public methods of this
+     * component.  This method should be called after <code>configure()</code>,
+     * and before any of the public methods of the component are utilized.
+     *
+     * @exception LifecycleException if this component detects a fatal error
+     *  that prevents this component from being used
+     */
+    public void start() throws LifecycleException {
+
+        // Validate and update our current component state
+        if (started)
+            throw new LifecycleException
+                (sm.getString("authenticator.alreadyStarted"));
+        lifecycle.fireLifecycleEvent(START_EVENT, null);
+        started = true;
+
+        // Look up the SingleSignOn implementation in our request processing
+        // path, if there is one
+        Container parent = context.getParent();
+        while ((sso == null) && (parent != null)) {
+            if (!(parent instanceof Pipeline)) {
+                parent = parent.getParent();
+                continue;
+            }
+            Valve valves[] = ((Pipeline) parent).getValves();
+            for (int i = 0; i < valves.length; i++) {
+                if (valves[i] instanceof SingleSignOn) {
+                    sso = (SingleSignOn) valves[i];
+                    break;
+                }
+            }
+            if (sso == null)
+                parent = parent.getParent();
+        }
+        if (log.isDebugEnabled()) {
+            if (sso != null)
+                log.debug("Found SingleSignOn Valve at " + sso);
+            else
+                log.debug("No SingleSignOn Valve is present");
+        }
+
+    }
+
+
+    /**
+     * Gracefully terminate the active use of the public methods of this
+     * component.  This method should be the last one called on a given
+     * instance of this component.
+     *
+     * @exception LifecycleException if this component detects a fatal error
+     *  that needs to be reported
+     */
+    public void stop() throws LifecycleException {
+
+        // Validate and update our current component state
+        if (!started)
+            throw new LifecycleException
+                (sm.getString("authenticator.notStarted"));
+        lifecycle.fireLifecycleEvent(STOP_EVENT, null);
+        started = false;
+
+        sso = null;
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/authenticator/BasicAuthenticator.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/authenticator/BasicAuthenticator.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/authenticator/BasicAuthenticator.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,211 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.authenticator;
+
+
+import java.io.IOException;
+import java.security.Principal;
+
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.catalina.connector.Request;
+import org.apache.catalina.connector.Response;
+import org.apache.catalina.deploy.LoginConfig;
+import org.apache.catalina.util.Base64;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.tomcat.util.buf.ByteChunk;
+import org.apache.tomcat.util.buf.CharChunk;
+import org.apache.tomcat.util.buf.MessageBytes;
+
+
+
+/**
+ * An <b>Authenticator</b> and <b>Valve</b> implementation of HTTP BASIC
+ * Authentication, as outlined in RFC 2617:  "HTTP Authentication: Basic
+ * and Digest Access Authentication."
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 370985 $ $Date: 2006-01-20 23:21:15 -0600 (Fri, 20 Jan 2006) $
+ */
+
+public class BasicAuthenticator
+    extends AuthenticatorBase {
+    private static Log log = LogFactory.getLog(BasicAuthenticator.class);
+
+
+
+    /**
+     * Authenticate bytes.
+     */
+    public static final byte[] AUTHENTICATE_BYTES = {
+        (byte) 'W',
+        (byte) 'W',
+        (byte) 'W',
+        (byte) '-',
+        (byte) 'A',
+        (byte) 'u',
+        (byte) 't',
+        (byte) 'h',
+        (byte) 'e',
+        (byte) 'n',
+        (byte) 't',
+        (byte) 'i',
+        (byte) 'c',
+        (byte) 'a',
+        (byte) 't',
+        (byte) 'e'
+    };
+
+
+   // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * Descriptive information about this implementation.
+     */
+    protected static final String info =
+        "org.apache.catalina.authenticator.BasicAuthenticator/1.0";
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * Return descriptive information about this Valve implementation.
+     */
+    public String getInfo() {
+
+        return (info);
+
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Authenticate the user making this request, based on the specified
+     * login configuration.  Return <code>true</code> if any specified
+     * constraint has been satisfied, or <code>false</code> if we have
+     * created a response challenge already.
+     *
+     * @param request Request we are processing
+     * @param response Response we are creating
+     * @param config    Login configuration describing how authentication
+     *              should be performed
+     *
+     * @exception IOException if an input/output error occurs
+     */
+    public boolean authenticate(Request request,
+                                Response response,
+                                LoginConfig config)
+        throws IOException {
+
+        // Have we already authenticated someone?
+        Principal principal = request.getUserPrincipal();
+        String ssoId = (String) request.getNote(Constants.REQ_SSOID_NOTE);
+        if (principal != null) {
+            if (log.isDebugEnabled())
+                log.debug("Already authenticated '" + principal.getName() + "'");
+            // Associate the session with any existing SSO session
+            if (ssoId != null)
+                associate(ssoId, request.getSessionInternal(true));
+            return (true);
+        }
+
+        // Is there an SSO session against which we can try to reauthenticate?
+        if (ssoId != null) {
+            if (log.isDebugEnabled())
+                log.debug("SSO Id " + ssoId + " set; attempting " +
+                          "reauthentication");
+            /* Try to reauthenticate using data cached by SSO.  If this fails,
+               either the original SSO logon was of DIGEST or SSL (which
+               we can't reauthenticate ourselves because there is no
+               cached username and password), or the realm denied
+               the user's reauthentication for some reason.
+               In either case we have to prompt the user for a logon */
+            if (reauthenticateFromSSO(ssoId, request))
+                return true;
+        }
+
+        // Validate any credentials already included with this request
+        String username = null;
+        String password = null;
+
+        MessageBytes authorization = 
+            request.getCoyoteRequest().getMimeHeaders()
+            .getValue("authorization");
+        
+        if (authorization != null) {
+            authorization.toBytes();
+            ByteChunk authorizationBC = authorization.getByteChunk();
+            if (authorizationBC.startsWithIgnoreCase("basic ", 0)) {
+                authorizationBC.setOffset(authorizationBC.getOffset() + 6);
+                // FIXME: Add trimming
+                // authorizationBC.trim();
+                
+                CharChunk authorizationCC = authorization.getCharChunk();
+                Base64.decode(authorizationBC, authorizationCC);
+                
+                // Get username and password
+                int colon = authorizationCC.indexOf(':');
+                if (colon < 0) {
+                    username = authorizationCC.toString();
+                } else {
+                    char[] buf = authorizationCC.getBuffer();
+                    username = new String(buf, 0, colon);
+                    password = new String(buf, colon + 1, 
+                            authorizationCC.getEnd() - colon - 1);
+                }
+                
+                authorizationBC.setOffset(authorizationBC.getOffset() - 6);
+            }
+
+            principal = context.getRealm().authenticate(username, password);
+            if (principal != null) {
+                register(request, response, principal, Constants.BASIC_METHOD,
+                         username, password);
+                return (true);
+            }
+        }
+        
+
+        // Send an "unauthorized" response and an appropriate challenge
+        MessageBytes authenticate = 
+            response.getCoyoteResponse().getMimeHeaders()
+            .addValue(AUTHENTICATE_BYTES, 0, AUTHENTICATE_BYTES.length);
+        CharChunk authenticateCC = authenticate.getCharChunk();
+        authenticateCC.append("Basic realm=\"");
+        if (config.getRealmName() == null) {
+            authenticateCC.append(request.getServerName());
+            authenticateCC.append(':');
+            authenticateCC.append(Integer.toString(request.getServerPort()));
+        } else {
+            authenticateCC.append(config.getRealmName());
+        }
+        authenticateCC.append('\"');        
+        authenticate.toChars();
+        response.sendError(HttpServletResponse.SC_UNAUTHORIZED);
+        //response.flushBuffer();
+        return (false);
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/authenticator/Constants.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/authenticator/Constants.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/authenticator/Constants.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,137 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.authenticator;
+
+
+public class Constants {
+
+    public static final String Package = "org.apache.catalina.authenticator";
+
+    // Authentication methods for login configuration
+    public static final String BASIC_METHOD = "BASIC";
+    public static final String CERT_METHOD = "CLIENT-CERT";
+    public static final String DIGEST_METHOD = "DIGEST";
+    public static final String FORM_METHOD = "FORM";
+
+    // User data constraints for transport guarantee
+    public static final String NONE_TRANSPORT = "NONE";
+    public static final String INTEGRAL_TRANSPORT = "INTEGRAL";
+    public static final String CONFIDENTIAL_TRANSPORT = "CONFIDENTIAL";
+
+    // Form based authentication constants
+    public static final String FORM_ACTION = "/j_security_check";
+    public static final String FORM_PASSWORD = "j_password";
+    public static final String FORM_USERNAME = "j_username";
+
+    // Cookie name for single sign on support
+    public static final String SINGLE_SIGN_ON_COOKIE = "JSESSIONIDSSO";
+
+
+    // --------------------------------------------------------- Request Notes
+
+
+    /**
+     * <p>If a user has been authenticated by the web layer, by means of a
+     * login method other than CLIENT_CERT, the username and password
+     * used to authenticate the user will be attached to the request as
+     * Notes for use by other server components.  A server component can
+     * also call several existing methods on Request to determine whether
+     * or not any user has been authenticated:</p>
+     * <ul>
+     * <li><strong>request.getAuthType()</strong>
+     *     will return BASIC, CLIENT-CERT, DIGEST, FORM, or <code>null</code>
+     *     if there is no authenticated user.</li>
+     * <li><strong>request.getUserPrincipal()</strong>
+     *     will return the authenticated <code>Principal</code> returned by the
+     *     <code>Realm</code> that authenticated this user.</li>
+     * </ul>
+     * <p>If CLIENT_CERT authentication was performed, the certificate chain
+     * will be available as a request attribute, as defined in the
+     * servlet specification.</p>
+     */
+
+
+    /**
+     * The notes key for the password used to authenticate this user.
+     */
+    public static final String REQ_PASSWORD_NOTE =
+      "org.apache.catalina.request.PASSWORD";
+
+
+    /**
+     * The notes key for the username used to authenticate this user.
+     */
+    public static final String REQ_USERNAME_NOTE =
+      "org.apache.catalina.request.USERNAME";
+
+
+    /**
+     * The notes key to track the single-sign-on identity with which this
+     * request is associated.
+     */
+    public static final String REQ_SSOID_NOTE =
+      "org.apache.catalina.request.SSOID";
+
+
+    // ---------------------------------------------------------- Session Notes
+
+
+    /**
+     * If the <code>cache</code> property of our authenticator is set, and
+     * the current request is part of a session, authentication information
+     * will be cached to avoid the need for repeated calls to
+     * <code>Realm.authenticate()</code>, under the following keys:
+     */
+
+
+    /**
+     * The notes key for the password used to authenticate this user.
+     */
+    public static final String SESS_PASSWORD_NOTE =
+      "org.apache.catalina.session.PASSWORD";
+
+
+    /**
+     * The notes key for the username used to authenticate this user.
+     */
+    public static final String SESS_USERNAME_NOTE =
+      "org.apache.catalina.session.USERNAME";
+
+
+    /**
+     * The following note keys are used during form login processing to
+     * cache required information prior to the completion of authentication.
+     */
+
+
+    /**
+     * The previously authenticated principal (if caching is disabled).
+     */
+    public static final String FORM_PRINCIPAL_NOTE =
+        "org.apache.catalina.authenticator.PRINCIPAL";
+
+
+    /**
+     * The original request information, to which the user will be
+     * redirected if authentication succeeds.
+     */
+    public static final String FORM_REQUEST_NOTE =
+        "org.apache.catalina.authenticator.REQUEST";
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/authenticator/DigestAuthenticator.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/authenticator/DigestAuthenticator.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/authenticator/DigestAuthenticator.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,424 @@
+/*
+ * Copyright 1999,2004-2005 The Apache Software Foundation.
+ * 
+ * Licensed 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.authenticator;
+
+
+import java.io.IOException;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.Principal;
+import java.util.StringTokenizer;
+
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.apache.catalina.Realm;
+import org.apache.catalina.connector.Request;
+import org.apache.catalina.connector.Response;
+import org.apache.catalina.deploy.LoginConfig;
+import org.apache.catalina.util.MD5Encoder;
+
+
+
+/**
+ * An <b>Authenticator</b> and <b>Valve</b> implementation of HTTP DIGEST
+ * Authentication (see RFC 2069).
+ *
+ * @author Craig R. McClanahan
+ * @author Remy Maucherat
+ * @version $Revision: 370985 $ $Date: 2006-01-20 23:21:15 -0600 (Fri, 20 Jan 2006) $
+ */
+
+public class DigestAuthenticator
+    extends AuthenticatorBase {
+    private static Log log = LogFactory.getLog(DigestAuthenticator.class);
+
+
+    // -------------------------------------------------------------- Constants
+
+    /**
+     * The MD5 helper object for this class.
+     */
+    protected static final MD5Encoder md5Encoder = new MD5Encoder();
+
+
+    /**
+     * Descriptive information about this implementation.
+     */
+    protected static final String info =
+        "org.apache.catalina.authenticator.DigestAuthenticator/1.0";
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    public DigestAuthenticator() {
+        super();
+        try {
+            if (md5Helper == null)
+                md5Helper = MessageDigest.getInstance("MD5");
+        } catch (NoSuchAlgorithmException e) {
+            e.printStackTrace();
+            throw new IllegalStateException();
+        }
+    }
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * MD5 message digest provider.
+     */
+    protected static MessageDigest md5Helper;
+
+
+    /**
+     * Private key.
+     */
+    protected String key = "Catalina";
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * Return descriptive information about this Valve implementation.
+     */
+    public String getInfo() {
+
+        return (info);
+
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Authenticate the user making this request, based on the specified
+     * login configuration.  Return <code>true</code> if any specified
+     * constraint has been satisfied, or <code>false</code> if we have
+     * created a response challenge already.
+     *
+     * @param request Request we are processing
+     * @param response Response we are creating
+     * @param config    Login configuration describing how authentication
+     *              should be performed
+     *
+     * @exception IOException if an input/output error occurs
+     */
+    public boolean authenticate(Request request,
+                                Response response,
+                                LoginConfig config)
+        throws IOException {
+
+        // Have we already authenticated someone?
+        Principal principal = request.getUserPrincipal();
+        //String ssoId = (String) request.getNote(Constants.REQ_SSOID_NOTE);
+        if (principal != null) {
+            if (log.isDebugEnabled())
+                log.debug("Already authenticated '" + principal.getName() + "'");
+            // Associate the session with any existing SSO session in order
+            // to get coordinated session invalidation at logout
+            String ssoId = (String) request.getNote(Constants.REQ_SSOID_NOTE);
+            if (ssoId != null)
+                associate(ssoId, request.getSessionInternal(true));
+            return (true);
+        }
+
+        // NOTE: We don't try to reauthenticate using any existing SSO session,
+        // because that will only work if the original authentication was
+        // BASIC or FORM, which are less secure than the DIGEST auth-type
+        // specified for this webapp
+        //
+        // Uncomment below to allow previous FORM or BASIC authentications
+        // to authenticate users for this webapp
+        // TODO make this a configurable attribute (in SingleSignOn??)
+        /*
+        // Is there an SSO session against which we can try to reauthenticate?
+        if (ssoId != null) {
+            if (log.isDebugEnabled())
+                log.debug("SSO Id " + ssoId + " set; attempting " +
+                          "reauthentication");
+            // Try to reauthenticate using data cached by SSO.  If this fails,
+            // either the original SSO logon was of DIGEST or SSL (which
+            // we can't reauthenticate ourselves because there is no
+            // cached username and password), or the realm denied
+            // the user's reauthentication for some reason.
+            // In either case we have to prompt the user for a logon
+            if (reauthenticateFromSSO(ssoId, request))
+                return true;
+        }
+        */
+
+        // Validate any credentials already included with this request
+        String authorization = request.getHeader("authorization");
+        if (authorization != null) {
+            principal = findPrincipal(request, authorization, context.getRealm());
+            if (principal != null) {
+                String username = parseUsername(authorization);
+                register(request, response, principal,
+                         Constants.DIGEST_METHOD,
+                         username, null);
+                return (true);
+            }
+        }
+
+        // Send an "unauthorized" response and an appropriate challenge
+
+        // Next, generate a nOnce token (that is a token which is supposed
+        // to be unique).
+        String nOnce = generateNOnce(request);
+
+        setAuthenticateHeader(request, response, config, nOnce);
+        response.sendError(HttpServletResponse.SC_UNAUTHORIZED);
+        //      hres.flushBuffer();
+        return (false);
+
+    }
+
+
+    // ------------------------------------------------------ Protected Methods
+
+
+    /**
+     * Parse the specified authorization credentials, and return the
+     * associated Principal that these credentials authenticate (if any)
+     * from the specified Realm.  If there is no such Principal, return
+     * <code>null</code>.
+     *
+     * @param request HTTP servlet request
+     * @param authorization Authorization credentials from this request
+     * @param realm Realm used to authenticate Principals
+     */
+    protected static Principal findPrincipal(Request request,
+                                             String authorization,
+                                             Realm realm) {
+
+        //System.out.println("Authorization token : " + authorization);
+        // Validate the authorization credentials format
+        if (authorization == null)
+            return (null);
+        if (!authorization.startsWith("Digest "))
+            return (null);
+        authorization = authorization.substring(7).trim();
+
+        // Bugzilla 37132: http://issues.apache.org/bugzilla/show_bug.cgi?id=37132
+        String[] tokens = authorization.split(",(?=(?:[^\"]*\"[^\"]*\")+$)");
+
+        String userName = null;
+        String realmName = null;
+        String nOnce = null;
+        String nc = null;
+        String cnonce = null;
+        String qop = null;
+        String uri = null;
+        String response = null;
+        String method = request.getMethod();
+
+        for (int i = 0; i < tokens.length; i++) {
+            String currentToken = tokens[i];
+            if (currentToken.length() == 0)
+                continue;
+
+            int equalSign = currentToken.indexOf('=');
+            if (equalSign < 0)
+                return null;
+            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 ( (userName == null) || (realmName == null) || (nOnce == null)
+             || (uri == null) || (response == null) )
+            return null;
+
+        // Second MD5 digest used to calculate the digest :
+        // MD5(Method + ":" + uri)
+        String a2 = method + ":" + uri;
+        //System.out.println("A2:" + a2);
+
+        byte[] buffer = null;
+        synchronized (md5Helper) {
+            buffer = md5Helper.digest(a2.getBytes());
+        }
+        String md5a2 = md5Encoder.encode(buffer);
+
+        return (realm.authenticate(userName, response, nOnce, nc, cnonce, qop,
+                                   realmName, md5a2));
+
+    }
+
+
+    /**
+     * Parse the username from the specified authorization string.  If none
+     * can be identified, return <code>null</code>
+     *
+     * @param authorization Authorization string to be parsed
+     */
+    protected String parseUsername(String authorization) {
+
+        //System.out.println("Authorization token : " + authorization);
+        // Validate the authorization credentials format
+        if (authorization == null)
+            return (null);
+        if (!authorization.startsWith("Digest "))
+            return (null);
+        authorization = authorization.substring(7).trim();
+
+        StringTokenizer commaTokenizer =
+            new StringTokenizer(authorization, ",");
+
+        while (commaTokenizer.hasMoreTokens()) {
+            String currentToken = commaTokenizer.nextToken();
+            int equalSign = currentToken.indexOf('=');
+            if (equalSign < 0)
+                return null;
+            String currentTokenName =
+                currentToken.substring(0, equalSign).trim();
+            String currentTokenValue =
+                currentToken.substring(equalSign + 1).trim();
+            if ("username".equals(currentTokenName))
+                return (removeQuotes(currentTokenValue));
+        }
+
+        return (null);
+
+    }
+
+
+    /**
+     * Removes the quotes on a string. RFC2617 states quotes are optional for
+     * all parameters except realm.
+     */
+    protected static String removeQuotes(String quotedString,
+                                         boolean quotesRequired) {
+        //support both quoted and non-quoted
+        if (quotedString.length() > 0 && quotedString.charAt(0) != '"' &&
+                !quotesRequired) {
+            return quotedString;
+        } else if (quotedString.length() > 2) {
+            return quotedString.substring(1, quotedString.length() - 1);
+        } else {
+            return new String();
+        }
+    }
+
+    /**
+     * Removes the quotes on a string.
+     */
+    protected static String removeQuotes(String quotedString) {
+        return removeQuotes(quotedString, false);
+    }
+
+    /**
+     * Generate a unique token. The token is generated according to the
+     * following pattern. NOnceToken = Base64 ( MD5 ( client-IP ":"
+     * time-stamp ":" private-key ) ).
+     *
+     * @param request HTTP Servlet request
+     */
+    protected String generateNOnce(Request request) {
+
+        long currentTime = System.currentTimeMillis();
+
+        String nOnceValue = request.getRemoteAddr() + ":" +
+            currentTime + ":" + key;
+
+        byte[] buffer = null;
+        synchronized (md5Helper) {
+            buffer = md5Helper.digest(nOnceValue.getBytes());
+        }
+        nOnceValue = md5Encoder.encode(buffer);
+
+        return nOnceValue;
+    }
+
+
+    /**
+     * Generates the WWW-Authenticate header.
+     * <p>
+     * The header MUST follow this template :
+     * <pre>
+     *      WWW-Authenticate    = "WWW-Authenticate" ":" "Digest"
+     *                            digest-challenge
+     *
+     *      digest-challenge    = 1#( realm | [ domain ] | nOnce |
+     *                  [ digest-opaque ] |[ stale ] | [ algorithm ] )
+     *
+     *      realm               = "realm" "=" realm-value
+     *      realm-value         = quoted-string
+     *      domain              = "domain" "=" <"> 1#URI <">
+     *      nonce               = "nonce" "=" nonce-value
+     *      nonce-value         = quoted-string
+     *      opaque              = "opaque" "=" quoted-string
+     *      stale               = "stale" "=" ( "true" | "false" )
+     *      algorithm           = "algorithm" "=" ( "MD5" | token )
+     * </pre>
+     *
+     * @param request HTTP Servlet request
+     * @param response HTTP Servlet response
+     * @param config    Login configuration describing how authentication
+     *              should be performed
+     * @param nOnce nonce token
+     */
+    protected void setAuthenticateHeader(Request request,
+                                         Response response,
+                                         LoginConfig config,
+                                         String nOnce) {
+
+        // Get the realm name
+        String realmName = config.getRealmName();
+        if (realmName == null)
+            realmName = request.getServerName() + ":"
+                + request.getServerPort();
+
+        byte[] buffer = null;
+        synchronized (md5Helper) {
+            buffer = md5Helper.digest(nOnce.getBytes());
+        }
+
+        String authenticateHeader = "Digest realm=\"" + realmName + "\", "
+            +  "qop=\"auth\", nonce=\"" + nOnce + "\", " + "opaque=\""
+            + md5Encoder.encode(buffer) + "\"";
+        response.setHeader("WWW-Authenticate", authenticateHeader);
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/authenticator/FormAuthenticator.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/authenticator/FormAuthenticator.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/authenticator/FormAuthenticator.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,524 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.authenticator;
+
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.Principal;
+import java.util.Enumeration;
+import java.util.Iterator;
+import java.util.Locale;
+
+import javax.servlet.RequestDispatcher;
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.catalina.Realm;
+import org.apache.catalina.Session;
+import org.apache.catalina.connector.Request;
+import org.apache.catalina.connector.Response;
+import org.apache.catalina.deploy.LoginConfig;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.coyote.ActionCode;
+import org.apache.tomcat.util.buf.ByteChunk;
+import org.apache.tomcat.util.buf.CharChunk;
+import org.apache.tomcat.util.buf.MessageBytes;
+import org.apache.tomcat.util.http.MimeHeaders;
+
+
+/**
+ * An <b>Authenticator</b> and <b>Valve</b> implementation of FORM BASED
+ * Authentication, as described in the Servlet API Specification, Version 2.2.
+ *
+ * @author Craig R. McClanahan
+ * @author Remy Maucherat
+ * @version $Revision: 320670 $ $Date: 2005-10-13 00:39:55 -0500 (Thu, 13 Oct 2005) $
+ */
+
+public class FormAuthenticator
+    extends AuthenticatorBase {
+    
+    private static Log log = LogFactory.getLog(FormAuthenticator.class);
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * Descriptive information about this implementation.
+     */
+    protected static final String info =
+        "org.apache.catalina.authenticator.FormAuthenticator/1.0";
+
+    /**
+     * Character encoding to use to read the username and password parameters
+     * from the request. If not set, the encoding of the request body will be
+     * used.
+     */
+    protected String characterEncoding = null;
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * Return descriptive information about this Valve implementation.
+     */
+    public String getInfo() {
+
+        return (info);
+
+    }
+
+
+    /**
+     * Return the character encoding to use to read the username and password.
+     */
+    public String getCharacterEncoding() {
+        return characterEncoding;
+    }
+
+    
+    /**
+     * Set the character encoding to be used to read the username and password. 
+     */
+    public void setCharacterEncoding(String encoding) {
+        characterEncoding = encoding;
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Authenticate the user making this request, based on the specified
+     * login configuration.  Return <code>true</code> if any specified
+     * constraint has been satisfied, or <code>false</code> if we have
+     * created a response challenge already.
+     *
+     * @param request Request we are processing
+     * @param response Response we are creating
+     * @param config    Login configuration describing how authentication
+     *              should be performed
+     *
+     * @exception IOException if an input/output error occurs
+     */
+    public boolean authenticate(Request request,
+                                Response response,
+                                LoginConfig config)
+        throws IOException {
+
+        // References to objects we will need later
+        Session session = null;
+
+        // Have we already authenticated someone?
+        Principal principal = request.getUserPrincipal();
+        String ssoId = (String) request.getNote(Constants.REQ_SSOID_NOTE);
+        if (principal != null) {
+            if (log.isDebugEnabled())
+                log.debug("Already authenticated '" +
+                    principal.getName() + "'");
+            // Associate the session with any existing SSO session
+            if (ssoId != null)
+                associate(ssoId, request.getSessionInternal(true));
+            return (true);
+        }
+
+        // Is there an SSO session against which we can try to reauthenticate?
+        if (ssoId != null) {
+            if (log.isDebugEnabled())
+                log.debug("SSO Id " + ssoId + " set; attempting " +
+                          "reauthentication");
+            // Try to reauthenticate using data cached by SSO.  If this fails,
+            // either the original SSO logon was of DIGEST or SSL (which
+            // we can't reauthenticate ourselves because there is no
+            // cached username and password), or the realm denied
+            // the user's reauthentication for some reason.
+            // In either case we have to prompt the user for a logon */
+            if (reauthenticateFromSSO(ssoId, request))
+                return true;
+        }
+
+        // Have we authenticated this user before but have caching disabled?
+        if (!cache) {
+            session = request.getSessionInternal(true);
+            if (log.isDebugEnabled())
+                log.debug("Checking for reauthenticate in session " + session);
+            String username =
+                (String) session.getNote(Constants.SESS_USERNAME_NOTE);
+            String password =
+                (String) session.getNote(Constants.SESS_PASSWORD_NOTE);
+            if ((username != null) && (password != null)) {
+                if (log.isDebugEnabled())
+                    log.debug("Reauthenticating username '" + username + "'");
+                principal =
+                    context.getRealm().authenticate(username, password);
+                if (principal != null) {
+                    session.setNote(Constants.FORM_PRINCIPAL_NOTE, principal);
+                    if (!matchRequest(request)) {
+                        register(request, response, principal,
+                                 Constants.FORM_METHOD,
+                                 username, password);
+                        return (true);
+                    }
+                }
+                if (log.isDebugEnabled())
+                    log.debug("Reauthentication failed, proceed normally");
+            }
+        }
+
+        // Is this the re-submit of the original request URI after successful
+        // authentication?  If so, forward the *original* request instead.
+        if (matchRequest(request)) {
+            session = request.getSessionInternal(true);
+            if (log.isDebugEnabled())
+                log.debug("Restore request from session '"
+                          + session.getIdInternal() 
+                          + "'");
+            principal = (Principal)
+                session.getNote(Constants.FORM_PRINCIPAL_NOTE);
+            register(request, response, principal, Constants.FORM_METHOD,
+                     (String) session.getNote(Constants.SESS_USERNAME_NOTE),
+                     (String) session.getNote(Constants.SESS_PASSWORD_NOTE));
+            // If we're caching principals we no longer need the username
+            // and password in the session, so remove them
+            if (cache) {
+                session.removeNote(Constants.SESS_USERNAME_NOTE);
+                session.removeNote(Constants.SESS_PASSWORD_NOTE);
+            }
+            if (restoreRequest(request, session)) {
+                if (log.isDebugEnabled())
+                    log.debug("Proceed to restored request");
+                return (true);
+            } else {
+                if (log.isDebugEnabled())
+                    log.debug("Restore of original request failed");
+                response.sendError(HttpServletResponse.SC_BAD_REQUEST);
+                return (false);
+            }
+        }
+
+        // Acquire references to objects we will need to evaluate
+        MessageBytes uriMB = MessageBytes.newInstance();
+        CharChunk uriCC = uriMB.getCharChunk();
+        uriCC.setLimit(-1);
+        String contextPath = request.getContextPath();
+        String requestURI = request.getDecodedRequestURI();
+        response.setContext(request.getContext());
+
+        // Is this the action request from the login page?
+        boolean loginAction =
+            requestURI.startsWith(contextPath) &&
+            requestURI.endsWith(Constants.FORM_ACTION);
+
+        // No -- Save this request and redirect to the form login page
+        if (!loginAction) {
+            session = request.getSessionInternal(true);
+            if (log.isDebugEnabled())
+                log.debug("Save request in session '" + session.getIdInternal() + "'");
+            try {
+                saveRequest(request, session);
+            } catch (IOException ioe) {
+                log.debug("Request body too big to save during authentication");
+                response.sendError(HttpServletResponse.SC_FORBIDDEN,
+                        sm.getString("authenticator.requestBodyTooBig"));
+                return (false);
+            }
+            forwardToLoginPage(request, response, config);
+            return (false);
+        }
+
+        // Yes -- Validate the specified credentials and redirect
+        // to the error page if they are not correct
+        Realm realm = context.getRealm();
+        if (characterEncoding != null) {
+            request.setCharacterEncoding(characterEncoding);
+        }
+        String username = request.getParameter(Constants.FORM_USERNAME);
+        String password = request.getParameter(Constants.FORM_PASSWORD);
+        if (log.isDebugEnabled())
+            log.debug("Authenticating username '" + username + "'");
+        principal = realm.authenticate(username, password);
+        if (principal == null) {
+            forwardToErrorPage(request, response, config);
+            return (false);
+        }
+
+        if (log.isDebugEnabled())
+            log.debug("Authentication of '" + username + "' was successful");
+
+        if (session == null)
+            session = request.getSessionInternal(false);
+        if (session == null) {
+            if (containerLog.isDebugEnabled())
+                containerLog.debug
+                    ("User took so long to log on the session expired");
+            response.sendError(HttpServletResponse.SC_REQUEST_TIMEOUT,
+                               sm.getString("authenticator.sessionExpired"));
+            return (false);
+        }
+
+        // Save the authenticated Principal in our session
+        session.setNote(Constants.FORM_PRINCIPAL_NOTE, principal);
+
+        // Save the username and password as well
+        session.setNote(Constants.SESS_USERNAME_NOTE, username);
+        session.setNote(Constants.SESS_PASSWORD_NOTE, password);
+
+        // Redirect the user to the original request URI (which will cause
+        // the original request to be restored)
+        requestURI = savedRequestURL(session);
+        if (log.isDebugEnabled())
+            log.debug("Redirecting to original '" + requestURI + "'");
+        if (requestURI == null)
+            response.sendError(HttpServletResponse.SC_BAD_REQUEST,
+                               sm.getString("authenticator.formlogin"));
+        else
+            response.sendRedirect(response.encodeRedirectURL(requestURI));
+        return (false);
+
+    }
+
+
+    // ------------------------------------------------------ Protected Methods
+
+
+    /**
+     * Called to forward to the login page
+     * 
+     * @param request Request we are processing
+     * @param response Response we are creating
+     * @param config    Login configuration describing how authentication
+     *              should be performed
+     */
+    protected void forwardToLoginPage(Request request, Response response, LoginConfig config) {
+        RequestDispatcher disp =
+            context.getServletContext().getRequestDispatcher
+            (config.getLoginPage());
+        try {
+            disp.forward(request.getRequest(), response.getResponse());
+            response.finishResponse();
+        } catch (Throwable t) {
+            log.warn("Unexpected error forwarding to login page", t);
+        }
+    }
+
+
+    /**
+     * Called to forward to the error page
+     * 
+     * @param request Request we are processing
+     * @param response Response we are creating
+     * @param config    Login configuration describing how authentication
+     *              should be performed
+     */
+    protected void forwardToErrorPage(Request request, Response response, LoginConfig config) {
+        RequestDispatcher disp =
+            context.getServletContext().getRequestDispatcher
+            (config.getErrorPage());
+        try {
+            disp.forward(request.getRequest(), response.getResponse());
+        } catch (Throwable t) {
+            log.warn("Unexpected error forwarding to error page", t);
+        }
+    }
+
+
+    /**
+     * Does this request match the saved one (so that it must be the redirect
+     * we signalled after successful authentication?
+     *
+     * @param request The request to be verified
+     */
+    protected boolean matchRequest(Request request) {
+
+      // Has a session been created?
+      Session session = request.getSessionInternal(false);
+      if (session == null)
+          return (false);
+
+      // Is there a saved request?
+      SavedRequest sreq = (SavedRequest)
+          session.getNote(Constants.FORM_REQUEST_NOTE);
+      if (sreq == null)
+          return (false);
+
+      // Is there a saved principal?
+      if (session.getNote(Constants.FORM_PRINCIPAL_NOTE) == null)
+          return (false);
+
+      // Does the request URI match?
+      String requestURI = request.getRequestURI();
+      if (requestURI == null)
+          return (false);
+      return (requestURI.equals(request.getRequestURI()));
+
+    }
+
+
+    /**
+     * Restore the original request from information stored in our session.
+     * If the original request is no longer present (because the session
+     * timed out), return <code>false</code>; otherwise, return
+     * <code>true</code>.
+     *
+     * @param request The request to be restored
+     * @param session The session containing the saved information
+     */
+    protected boolean restoreRequest(Request request, Session session)
+        throws IOException {
+
+        // Retrieve and remove the SavedRequest object from our session
+        SavedRequest saved = (SavedRequest)
+            session.getNote(Constants.FORM_REQUEST_NOTE);
+        session.removeNote(Constants.FORM_REQUEST_NOTE);
+        session.removeNote(Constants.FORM_PRINCIPAL_NOTE);
+        if (saved == null)
+            return (false);
+
+        // Modify our current request to reflect the original one
+        request.clearCookies();
+        Iterator cookies = saved.getCookies();
+        while (cookies.hasNext()) {
+            request.addCookie((Cookie) cookies.next());
+        }
+
+        MimeHeaders rmh = request.getCoyoteRequest().getMimeHeaders();
+        rmh.recycle();
+        Iterator names = saved.getHeaderNames();
+        while (names.hasNext()) {
+            String name = (String) names.next();
+            Iterator values = saved.getHeaderValues(name);
+            while (values.hasNext()) {
+                rmh.addValue(name).setString( (String)values.next() );
+            }
+        }
+        
+        request.clearLocales();
+        Iterator locales = saved.getLocales();
+        while (locales.hasNext()) {
+            request.addLocale((Locale) locales.next());
+        }
+        
+        request.getCoyoteRequest().getParameters().recycle();
+        
+        if ("POST".equalsIgnoreCase(saved.getMethod())) {
+            ByteChunk body = saved.getBody();
+            
+            if (body != null) {
+                request.getCoyoteRequest().action
+                    (ActionCode.ACTION_REQ_SET_BODY_REPLAY, body);
+    
+                // Set content type
+                MessageBytes contentType = MessageBytes.newInstance();
+                contentType.setString("application/x-www-form-urlencoded");
+                request.getCoyoteRequest().setContentType(contentType);
+            }
+        }
+        request.getCoyoteRequest().method().setString(saved.getMethod());
+
+        request.getCoyoteRequest().queryString().setString
+            (saved.getQueryString());
+
+        request.getCoyoteRequest().requestURI().setString
+            (saved.getRequestURI());
+        return (true);
+
+    }
+
+
+    /**
+     * Save the original request information into our session.
+     *
+     * @param request The request to be saved
+     * @param session The session to contain the saved information
+     * @throws IOException
+     */
+    protected void saveRequest(Request request, Session session)
+        throws IOException {
+
+        // Create and populate a SavedRequest object for this request
+        SavedRequest saved = new SavedRequest();
+        Cookie cookies[] = request.getCookies();
+        if (cookies != null) {
+            for (int i = 0; i < cookies.length; i++)
+                saved.addCookie(cookies[i]);
+        }
+        Enumeration names = request.getHeaderNames();
+        while (names.hasMoreElements()) {
+            String name = (String) names.nextElement();
+            Enumeration values = request.getHeaders(name);
+            while (values.hasMoreElements()) {
+                String value = (String) values.nextElement();
+                saved.addHeader(name, value);
+            }
+        }
+        Enumeration locales = request.getLocales();
+        while (locales.hasMoreElements()) {
+            Locale locale = (Locale) locales.nextElement();
+            saved.addLocale(locale);
+        }
+
+        if ("POST".equalsIgnoreCase(request.getMethod())) {
+            ByteChunk body = new ByteChunk();
+            body.setLimit(request.getConnector().getMaxSavePostSize());
+
+            byte[] buffer = new byte[4096];
+            int bytesRead;
+            InputStream is = request.getInputStream();
+        
+            while ( (bytesRead = is.read(buffer) ) >= 0) {
+                body.append(buffer, 0, bytesRead);
+            }
+            saved.setBody(body);
+        }
+
+        saved.setMethod(request.getMethod());
+        saved.setQueryString(request.getQueryString());
+        saved.setRequestURI(request.getRequestURI());
+
+        // Stash the SavedRequest in our session for later use
+        session.setNote(Constants.FORM_REQUEST_NOTE, saved);
+
+    }
+
+
+    /**
+     * Return the request URI (with the corresponding query string, if any)
+     * from the saved request so that we can redirect to it.
+     *
+     * @param session Our current session
+     */
+    protected String savedRequestURL(Session session) {
+
+        SavedRequest saved =
+            (SavedRequest) session.getNote(Constants.FORM_REQUEST_NOTE);
+        if (saved == null)
+            return (null);
+        StringBuffer sb = new StringBuffer(saved.getRequestURI());
+        if (saved.getQueryString() != null) {
+            sb.append('?');
+            sb.append(saved.getQueryString());
+        }
+        return (sb.toString());
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/authenticator/LocalStrings.properties
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/authenticator/LocalStrings.properties	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/authenticator/LocalStrings.properties	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,14 @@
+authenticator.alreadyStarted=Security Interceptor has already been started
+authenticator.certificates=No client certificate chain in this request
+authenticator.forbidden=Access to the requested resource has been denied
+authenticator.formlogin=Invalid direct reference to form login page
+authenticator.invalid=Invalid client certificate chain in this request
+authenticator.keystore=Exception loading key store
+authenticator.manager=Exception initializing trust managers
+authenticator.notAuthenticated=Configuration error:  Cannot perform access control without an authenticated principal
+authenticator.notContext=Configuration error:  Must be attached to a Context
+authenticator.notStarted=Security Interceptor has not yet been started
+authenticator.requestBodyTooBig=The request body was too large to be cached during the authentication process
+authenticator.sessionExpired=The time allowed for the login process has been exceeded. If you wish to continue you must either click back twice and re-click the link you requested or close and re-open your browser
+authenticator.unauthorized=Cannot authenticate with the provided credentials
+authenticator.userDataConstraint=This request violates a User Data constraint for this application

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/authenticator/LocalStrings_es.properties
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/authenticator/LocalStrings_es.properties	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/authenticator/LocalStrings_es.properties	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,12 @@
+authenticator.alreadyStarted=El interceptor de seguridad ya ha sido arrancado
+authenticator.certificates=No hay cadena de certificados del cliente en esta petición
+authenticator.forbidden=El acceso al recurso pedido ha sido denegado
+authenticator.formlogin=Referencia directa al formulario de conexión (página de formulario de login) inválida
+authenticator.invalid=No es válida la cadena de certificados del cliente en esta petición
+authenticator.keystore=Excepción cargando el almacén de claves
+authenticator.manager=Excepción inicializando administradores de confianza
+authenticator.notAuthenticated=Error de Configuración: No se pueden realizar funciones de control de acceso sin un principal autenticado
+authenticator.notContext=Error de Configuración: Debe de estar unido a un Contexto
+authenticator.notStarted=El Interceptor de seguridad no sido aún iniciado
+authenticator.unauthorized=Imposible autenticar mediante las credenciales suministradas
+authenticator.userDataConstraint=Esta petición viola una Restrición de Datos de usuario para esta aplicación

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/authenticator/LocalStrings_fr.properties
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/authenticator/LocalStrings_fr.properties	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/authenticator/LocalStrings_fr.properties	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,12 @@
+authenticator.alreadyStarted=L''intercepteur de sécurité (security interceptor) a déjà été démarré
+authenticator.certificates=Aucune chaîne de certificat client (client certificate chain) dans cette requête
+authenticator.forbidden=L''accès à la ressource demandée a été interdit
+authenticator.formlogin=Référence directe à la form de connexion (form login page) invalide
+authenticator.invalid=Chaîne de certificat client invalide dans cette requête
+authenticator.keystore=Exception lors du chargement du référentiel de clefs (key store)
+authenticator.manager=Exception lors de l''initialisation des gestionnaires d''authentification (trust managers)
+authenticator.notAuthenticated=Erreur de configuration:  Impossible de procéder à un contrôle d''accès sans un principal authentifié (authenticated principal)
+authenticator.notContext=Erreur de configuration:  Doit être attaché à un contexte
+authenticator.notStarted=L''intercepteur de sécurité (security interceptor) n''a pas encore été démarré
+authenticator.unauthorized=Impossible d''authentifier avec les crédits fournis (provided credentials)
+authenticator.userDataConstraint=Cette requête viole une contrainte donnée utilisateur (user data constraint) pour cette application

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/authenticator/LocalStrings_ja.properties
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/authenticator/LocalStrings_ja.properties	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/authenticator/LocalStrings_ja.properties	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,13 @@
+authenticator.alreadyStarted=\u30bb\u30ad\u30e5\u30ea\u30c6\u30a3\u30a4\u30f3\u30bf\u30fc\u30bb\u30d7\u30bf\u306f\u65e2\u306b\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u3059
+authenticator.certificates=\u3053\u306e\u30ea\u30af\u30a8\u30b9\u30c8\u306b\u306f\u30af\u30e9\u30a4\u30a2\u30f3\u30c8\u8a8d\u8a3c\u30c1\u30a7\u30fc\u30f3\u304c\u3042\u308a\u307e\u305b\u3093
+authenticator.forbidden=\u30ea\u30af\u30a8\u30b9\u30c8\u3055\u308c\u305f\u30ea\u30bd\u30fc\u30b9\u3078\u306e\u30a2\u30af\u30bb\u30b9\u304c\u62d2\u5426\u3055\u308c\u307e\u3057\u305f
+authenticator.formlogin=\u30d5\u30a9\u30fc\u30e0\u30ed\u30b0\u30a4\u30f3\u30da\u30fc\u30b8\u3078\u306e\u7121\u52b9\u306a\u76f4\u63a5\u53c2\u7167\u3067\u3059
+authenticator.invalid=\u3053\u306e\u30ea\u30af\u30a8\u30b9\u30c8\u306b\u7121\u52b9\u306a\u30af\u30e9\u30a4\u30a2\u30f3\u30c8\u8a8d\u8a3c\u30c1\u30a7\u30fc\u30f3\u304c\u3042\u308a\u307e\u3059
+authenticator.keystore=\u30ad\u30fc\u30b9\u30c8\u30a2\u3092\u30ed\u30fc\u30c9\u4e2d\u306e\u4f8b\u5916\u3067\u3059
+authenticator.manager=\u30c8\u30e9\u30b9\u30c8\u30de\u30cd\u30fc\u30b8\u30e3\u3092\u521d\u671f\u5316\u4e2d\u306e\u4f8b\u5916\u3067\u3059
+authenticator.notAuthenticated=\u8a2d\u5b9a\u30a8\u30e9\u30fc: \u8a8d\u8a3c\u3055\u308c\u305f\u4e3b\u4f53\u306a\u3057\u306b\u30a2\u30af\u30bb\u30b9\u5236\u5fa1\u3092\u5b9f\u884c\u3067\u304d\u307e\u305b\u3093
+authenticator.notContext=\u8a2d\u5b9a\u30a8\u30e9\u30fc: \u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u306b\u6307\u5b9a\u3057\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093
+authenticator.notStarted=\u30bb\u30ad\u30e5\u30ea\u30c6\u30a3\u30a4\u30f3\u30bf\u30fc\u30bb\u30d7\u30bf\u306f\u307e\u3060\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u305b\u3093
+authenticator.sessionExpired=\u30ed\u30b0\u30a4\u30f3\u30d7\u30ed\u30bb\u30b9\u306b\u8a8d\u3081\u3089\u308c\u3066\u3044\u305f\u6642\u9593\u304c\u904e\u304e\u307e\u3057\u305f\u3002\u7d99\u7d9a\u3057\u305f\u3044\u306a\u3089\u3070\uff0c\u30d0\u30c3\u30af\u30dc\u30bf\u30f3\u30922\u5ea6\u62bc\u3057\u3066\u304b\u3089\u518d\u5ea6\u30ea\u30f3\u30af\u3092\u62bc\u3059\u304b\uff0c\u30d6\u30e9\u30a6\u30b6\u3092\u7acb\u3061\u4e0a\u3052\u76f4\u3057\u3066\u304f\u3060\u3055\u3044
+authenticator.unauthorized=\u7528\u610f\u3055\u308c\u305f\u8a3c\u660e\u66f8\u3067\u8a8d\u8a3c\u3067\u304d\u307e\u305b\u3093
+authenticator.userDataConstraint=\u3053\u306e\u30ea\u30af\u30a8\u30b9\u30c8\u306f\u3001\u3053\u306e\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u306e\u30e6\u30fc\u30b6\u30c7\u30fc\u30bf\u306e\u5236\u9650\u306b\u9055\u53cd\u3057\u3066\u3044\u307e\u3059

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/authenticator/NonLoginAuthenticator.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/authenticator/NonLoginAuthenticator.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/authenticator/NonLoginAuthenticator.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,102 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.authenticator;
+
+
+import java.io.IOException;
+
+import org.apache.catalina.connector.Request;
+import org.apache.catalina.connector.Response;
+import org.apache.catalina.deploy.LoginConfig;
+
+
+
+/**
+ * An <b>Authenticator</b> and <b>Valve</b> implementation that checks
+ * only security constraints not involving user authentication.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 303721 $ $Date: 2005-02-23 13:27:56 -0600 (Wed, 23 Feb 2005) $
+ */
+
+public final class NonLoginAuthenticator
+    extends AuthenticatorBase {
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * Descriptive information about this implementation.
+     */
+    private static final String info =
+        "org.apache.catalina.authenticator.NonLoginAuthenticator/1.0";
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * Return descriptive information about this Valve implementation.
+     */
+    public String getInfo() {
+
+        return (info);
+
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Authenticate the user making this request, based on the specified
+     * login configuration.  Return <code>true</code> if any specified
+     * constraint has been satisfied, or <code>false</code> if we have
+     * created a response challenge already.
+     *
+     * @param request Request we are processing
+     * @param response Response we are creating
+     * @param config    Login configuration describing how authentication
+     *              should be performed
+     *
+     * @exception IOException if an input/output error occurs
+     */
+    public boolean authenticate(Request request,
+                                Response response,
+                                LoginConfig config)
+        throws IOException {
+
+        /*  Associating this request's session with an SSO would allow
+            coordinated session invalidation, but should the session for
+            a webapp that the user didn't log into be invalidated when
+            another session is logged out?
+        String ssoId = (String) request.getNote(Constants.REQ_SSOID_NOTE);
+        if (ssoId != null)
+            associate(ssoId, getSession(request, true));
+        */
+        
+        if (containerLog.isDebugEnabled())
+            containerLog.debug("User authentication is not required");
+        return (true);
+
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/authenticator/SSLAuthenticator.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/authenticator/SSLAuthenticator.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/authenticator/SSLAuthenticator.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,196 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.authenticator;
+
+
+import java.io.IOException;
+import java.security.Principal;
+import java.security.cert.X509Certificate;
+
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.coyote.ActionCode;
+import org.apache.catalina.Globals;
+import org.apache.catalina.LifecycleException;
+import org.apache.catalina.connector.Request;
+import org.apache.catalina.connector.Response;
+import org.apache.catalina.deploy.LoginConfig;
+
+
+
+/**
+ * An <b>Authenticator</b> and <b>Valve</b> implementation of authentication
+ * that utilizes SSL certificates to identify client users.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 303721 $ $Date: 2005-02-23 13:27:56 -0600 (Wed, 23 Feb 2005) $
+ */
+
+public class SSLAuthenticator
+    extends AuthenticatorBase {
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * Descriptive information about this implementation.
+     */
+    protected static final String info =
+        "org.apache.catalina.authenticator.SSLAuthenticator/1.0";
+
+
+    /**
+     * Return descriptive information about this Valve implementation.
+     */
+    public String getInfo() {
+
+        return (info);
+
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Authenticate the user by checking for the existence of a certificate
+     * chain, and optionally asking a trust manager to validate that we trust
+     * this user.
+     *
+     * @param request Request we are processing
+     * @param response Response we are creating
+     * @param config    Login configuration describing how authentication
+     *              should be performed
+     *
+     * @exception IOException if an input/output error occurs
+     */
+    public boolean authenticate(Request request,
+                                Response response,
+                                LoginConfig config)
+        throws IOException {
+
+        // Have we already authenticated someone?
+        Principal principal = request.getUserPrincipal();
+        //String ssoId = (String) request.getNote(Constants.REQ_SSOID_NOTE);
+        if (principal != null) {
+            if (containerLog.isDebugEnabled())
+                containerLog.debug("Already authenticated '" + principal.getName() + "'");
+            // Associate the session with any existing SSO session in order
+            // to get coordinated session invalidation at logout
+            String ssoId = (String) request.getNote(Constants.REQ_SSOID_NOTE);
+            if (ssoId != null)
+                associate(ssoId, request.getSessionInternal(true));
+            return (true);
+        }
+
+        // NOTE: We don't try to reauthenticate using any existing SSO session,
+        // because that will only work if the original authentication was
+        // BASIC or FORM, which are less secure than the CLIENT-CERT auth-type
+        // specified for this webapp
+        //
+        // Uncomment below to allow previous FORM or BASIC authentications
+        // to authenticate users for this webapp
+        // TODO make this a configurable attribute (in SingleSignOn??)
+        /*
+        // Is there an SSO session against which we can try to reauthenticate?
+        if (ssoId != null) {
+            if (log.isDebugEnabled())
+                log.debug("SSO Id " + ssoId + " set; attempting " +
+                          "reauthentication");
+            // Try to reauthenticate using data cached by SSO.  If this fails,
+            // either the original SSO logon was of DIGEST or SSL (which
+            // we can't reauthenticate ourselves because there is no
+            // cached username and password), or the realm denied
+            // the user's reauthentication for some reason.
+            // In either case we have to prompt the user for a logon
+            if (reauthenticateFromSSO(ssoId, request))
+                return true;
+        }
+        */
+
+        // Retrieve the certificate chain for this client
+        if (containerLog.isDebugEnabled())
+            containerLog.debug(" Looking up certificates");
+
+        X509Certificate certs[] = (X509Certificate[])
+            request.getAttribute(Globals.CERTIFICATES_ATTR);
+        if ((certs == null) || (certs.length < 1)) {
+            request.getCoyoteRequest().action
+                              (ActionCode.ACTION_REQ_SSL_CERTIFICATE, null);
+            certs = (X509Certificate[])
+                request.getAttribute(Globals.CERTIFICATES_ATTR);
+        }
+        if ((certs == null) || (certs.length < 1)) {
+            if (containerLog.isDebugEnabled())
+                containerLog.debug("  No certificates included with this request");
+            response.sendError(HttpServletResponse.SC_BAD_REQUEST,
+                               sm.getString("authenticator.certificates"));
+            return (false);
+        }
+
+        // Authenticate the specified certificate chain
+        principal = context.getRealm().authenticate(certs);
+        if (principal == null) {
+            if (containerLog.isDebugEnabled())
+                containerLog.debug("  Realm.authenticate() returned false");
+            response.sendError(HttpServletResponse.SC_UNAUTHORIZED,
+                               sm.getString("authenticator.unauthorized"));
+            return (false);
+        }
+
+        // Cache the principal (if requested) and record this authentication
+        register(request, response, principal, Constants.CERT_METHOD,
+                 null, null);
+        return (true);
+
+    }
+
+
+    // ------------------------------------------------------ Lifecycle Methods
+
+
+    /**
+     * Initialize the database we will be using for client verification
+     * and certificate validation (if any).
+     *
+     * @exception LifecycleException if this component detects a fatal error
+     *  that prevents this component from being used
+     */
+    public void start() throws LifecycleException {
+
+        super.start();
+
+    }
+
+
+    /**
+     * Finalize the database we used for client verification and
+     * certificate validation (if any).
+     *
+     * @exception LifecycleException if this component detects a fatal error
+     *  that prevents this component from being used
+     */
+    public void stop() throws LifecycleException {
+
+        super.stop();
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/authenticator/SavedRequest.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/authenticator/SavedRequest.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/authenticator/SavedRequest.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,180 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.authenticator;
+
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Locale;
+
+import javax.servlet.http.Cookie;
+
+import org.apache.tomcat.util.buf.ByteChunk;
+
+
+/**
+ * Object that saves the critical information from a request so that
+ * form-based authentication can reproduce it once the user has been
+ * authenticated.
+ * <p>
+ * <b>IMPLEMENTATION NOTE</b> - It is assumed that this object is accessed
+ * only from the context of a single thread, so no synchronization around
+ * internal collection classes is performed.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 303925 $ $Date: 2005-05-11 16:39:41 -0500 (Wed, 11 May 2005) $
+ */
+
+public final class SavedRequest {
+
+
+    /**
+     * The set of Cookies associated with this Request.
+     */
+    private ArrayList cookies = new ArrayList();
+
+    public void addCookie(Cookie cookie) {
+        cookies.add(cookie);
+    }
+
+    public Iterator getCookies() {
+        return (cookies.iterator());
+    }
+
+
+    /**
+     * The set of Headers associated with this Request.  Each key is a header
+     * name, while the value is a ArrayList containing one or more actual
+     * values for this header.  The values are returned as an Iterator when
+     * you ask for them.
+     */
+    private HashMap headers = new HashMap();
+
+    public void addHeader(String name, String value) {
+        ArrayList values = (ArrayList) headers.get(name);
+        if (values == null) {
+            values = new ArrayList();
+            headers.put(name, values);
+        }
+        values.add(value);
+    }
+
+    public Iterator getHeaderNames() {
+        return (headers.keySet().iterator());
+    }
+
+    public Iterator getHeaderValues(String name) {
+        ArrayList values = (ArrayList) headers.get(name);
+        if (values == null)
+            return ((new ArrayList()).iterator());
+        else
+            return (values.iterator());
+    }
+
+
+    /**
+     * The set of Locales associated with this Request.
+     */
+    private ArrayList locales = new ArrayList();
+
+    public void addLocale(Locale locale) {
+        locales.add(locale);
+    }
+
+    public Iterator getLocales() {
+        return (locales.iterator());
+    }
+
+
+    /**
+     * The request method used on this Request.
+     */
+    private String method = null;
+
+    public String getMethod() {
+        return (this.method);
+    }
+
+    public void setMethod(String method) {
+        this.method = method;
+    }
+
+
+
+    /**
+     * The set of request parameters associated with this Request.  Each
+     * entry is keyed by the parameter name, pointing at a String array of
+     * the corresponding values.
+     */
+    private HashMap parameters = new HashMap();
+
+    public void addParameter(String name, String values[]) {
+        parameters.put(name, values);
+    }
+
+    public Iterator getParameterNames() {
+        return (parameters.keySet().iterator());
+    }
+
+    public String[] getParameterValues(String name) {
+        return ((String[]) parameters.get(name));
+    }
+
+
+    /**
+     * The query string associated with this Request.
+     */
+    private String queryString = null;
+
+    public String getQueryString() {
+        return (this.queryString);
+    }
+
+    public void setQueryString(String queryString) {
+        this.queryString = queryString;
+    }
+
+
+    /**
+     * The request URI associated with this Request.
+     */
+    private String requestURI = null;
+
+    public String getRequestURI() {
+        return (this.requestURI);
+    }
+
+    public void setRequestURI(String requestURI) {
+        this.requestURI = requestURI;
+    }
+
+    
+    /**
+     * The body of this request.
+     */
+    private ByteChunk body = null;
+    
+    public ByteChunk getBody() {
+        return (this.body);
+    }
+
+    public void setBody(ByteChunk body) {
+        this.body = body;
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/authenticator/SingleSignOn.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/authenticator/SingleSignOn.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/authenticator/SingleSignOn.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,701 @@
+/*
+ * Copyright 1999-2001,2004-2005 The Apache Software Foundation.
+ * 
+ * Licensed 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.authenticator;
+
+
+import java.io.IOException;
+import java.security.Principal;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.Cookie;
+
+import org.apache.catalina.Lifecycle;
+import org.apache.catalina.LifecycleException;
+import org.apache.catalina.LifecycleListener;
+import org.apache.catalina.Realm;
+import org.apache.catalina.Session;
+import org.apache.catalina.SessionEvent;
+import org.apache.catalina.SessionListener;
+import org.apache.catalina.connector.Request;
+import org.apache.catalina.connector.Response;
+import org.apache.catalina.util.LifecycleSupport;
+import org.apache.catalina.util.StringManager;
+import org.apache.catalina.valves.ValveBase;
+
+
+/**
+ * A <strong>Valve</strong> that supports a "single sign on" user experience,
+ * where the security identity of a user who successfully authenticates to one
+ * web application is propogated to other web applications in the same
+ * security domain.  For successful use, the following requirements must
+ * be met:
+ * <ul>
+ * <li>This Valve must be configured on the Container that represents a
+ *     virtual host (typically an implementation of <code>Host</code>).</li>
+ * <li>The <code>Realm</code> that contains the shared user and role
+ *     information must be configured on the same Container (or a higher
+ *     one), and not overridden at the web application level.</li>
+ * <li>The web applications themselves must use one of the standard
+ *     Authenticators found in the
+ *     <code>org.apache.catalina.authenticator</code> package.</li>
+ * </ul>
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 384817 $ $Date: 2006-03-10 09:27:43 -0600 (Fri, 10 Mar 2006) $
+ */
+
+public class SingleSignOn
+    extends ValveBase
+    implements Lifecycle, SessionListener {
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The cache of SingleSignOnEntry instances for authenticated Principals,
+     * keyed by the cookie value that is used to select them.
+     */
+    protected Map cache = new HashMap();
+
+
+    /**
+     * Descriptive information about this Valve implementation.
+     */
+    protected static String info =
+        "org.apache.catalina.authenticator.SingleSignOn";
+
+
+    /**
+     * The lifecycle event support for this component.
+     */
+    protected LifecycleSupport lifecycle = new LifecycleSupport(this);
+
+    /**
+     * Indicates whether this valve should require a downstream Authenticator to
+     * reauthenticate each request, or if it itself can bind a UserPrincipal
+     * and AuthType object to the request.
+     */
+    private boolean requireReauthentication = false;
+
+    /**
+     * The cache of single sign on identifiers, keyed by the Session that is
+     * associated with them.
+     */
+    protected Map reverse = new HashMap();
+
+
+    /**
+     * The string manager for this package.
+     */
+    protected final static StringManager sm =
+        StringManager.getManager(Constants.Package);
+
+
+    /**
+     * Component started flag.
+     */
+    protected boolean started = false;
+
+    /**
+     * Optional SSO cookie domain.
+     */
+    private String cookieDomain;
+
+    // ------------------------------------------------------------- Properties
+
+    /**
+     * Returns the optional cookie domain.
+     * May return null.
+     *
+     * @return The cookie domain
+     */
+    public String getCookieDomain() {
+        return cookieDomain;
+    }
+    /**
+     * Sets the domain to be used for sso cookies.
+     *
+     * @param cookieDomain cookie domain name
+     */
+    public void setCookieDomain(String cookieDomain) {
+        if (cookieDomain != null && cookieDomain.trim().length() == 0) {
+            cookieDomain = null;
+        }
+        this.cookieDomain = cookieDomain;
+    }
+
+    /**
+     * Gets whether each request needs to be reauthenticated (by an
+     * Authenticator downstream in the pipeline) to the security
+     * <code>Realm</code>, or if this Valve can itself bind security info
+     * to the request based on the presence of a valid SSO entry without
+     * rechecking with the <code>Realm</code..
+     *
+     * @return  <code>true</code> if it is required that a downstream
+     *          Authenticator reauthenticate each request before calls to
+     *          <code>HttpServletRequest.setUserPrincipal()</code>
+     *          and <code>HttpServletRequest.setAuthType()</code> are made;
+     *          <code>false</code> if the <code>Valve</code> can itself make
+     *          those calls relying on the presence of a valid SingleSignOn
+     *          entry associated with the request.
+     *
+     * @see #setRequireReauthentication
+     */
+    public boolean getRequireReauthentication()
+    {
+        return requireReauthentication;
+    }
+
+
+    /**
+     * Sets whether each request needs to be reauthenticated (by an
+     * Authenticator downstream in the pipeline) to the security
+     * <code>Realm</code>, or if this Valve can itself bind security info
+     * to the request, based on the presence of a valid SSO entry, without
+     * rechecking with the <code>Realm</code.
+     * <p>
+     * If this property is <code>false</code> (the default), this
+     * <code>Valve</code> will bind a UserPrincipal and AuthType to the request
+     * if a valid SSO entry is associated with the request.  It will not notify
+     * the security <code>Realm</code> of the incoming request.
+     * <p>
+     * This property should be set to <code>true</code> if the overall server
+     * configuration requires that the <code>Realm</code> reauthenticate each
+     * request thread.  An example of such a configuration would be one where
+     * the <code>Realm</code> implementation provides security for both a
+     * web tier and an associated EJB tier, and needs to set security
+     * credentials on each request thread in order to support EJB access.
+     * <p>
+     * If this property is set to <code>true</code>, this Valve will set flags
+     * on the request notifying the downstream Authenticator that the request
+     * is associated with an SSO session.  The Authenticator will then call its
+     * {@link AuthenticatorBase#reauthenticateFromSSO reauthenticateFromSSO}
+     * method to attempt to reauthenticate the request to the
+     * <code>Realm</code>, using any credentials that were cached with this
+     * Valve.
+     * <p>
+     * The default value of this property is <code>false</code>, in order
+     * to maintain backward compatibility with previous versions of Tomcat.
+     *
+     * @param required  <code>true</code> if it is required that a downstream
+     *                  Authenticator reauthenticate each request before calls
+     *                  to  <code>HttpServletRequest.setUserPrincipal()</code>
+     *                  and <code>HttpServletRequest.setAuthType()</code> are
+     *                  made; <code>false</code> if the <code>Valve</code> can
+     *                  itself make those calls relying on the presence of a
+     *                  valid SingleSignOn entry associated with the request.
+     *
+     * @see AuthenticatorBase#reauthenticateFromSSO
+     */
+    public void setRequireReauthentication(boolean required)
+    {
+        this.requireReauthentication = required;
+    }
+
+
+    // ------------------------------------------------------ Lifecycle Methods
+
+
+    /**
+     * Add a lifecycle event listener to this component.
+     *
+     * @param listener The listener to add
+     */
+    public void addLifecycleListener(LifecycleListener listener) {
+
+        lifecycle.addLifecycleListener(listener);
+
+    }
+
+
+    /**
+     * Get the lifecycle listeners associated with this lifecycle. If this 
+     * Lifecycle has no listeners registered, a zero-length array is returned.
+     */
+    public LifecycleListener[] findLifecycleListeners() {
+
+        return lifecycle.findLifecycleListeners();
+
+    }
+
+
+    /**
+     * Remove a lifecycle event listener from this component.
+     *
+     * @param listener The listener to remove
+     */
+    public void removeLifecycleListener(LifecycleListener listener) {
+
+        lifecycle.removeLifecycleListener(listener);
+
+    }
+
+
+    /**
+     * Prepare for the beginning of active use of the public methods of this
+     * component.  This method should be called after <code>configure()</code>,
+     * and before any of the public methods of the component are utilized.
+     *
+     * @exception LifecycleException if this component detects a fatal error
+     *  that prevents this component from being used
+     */
+    public void start() throws LifecycleException {
+
+        // Validate and update our current component state
+        if (started)
+            throw new LifecycleException
+                (sm.getString("authenticator.alreadyStarted"));
+        lifecycle.fireLifecycleEvent(START_EVENT, null);
+        started = true;
+
+    }
+
+
+    /**
+     * Gracefully terminate the active use of the public methods of this
+     * component.  This method should be the last one called on a given
+     * instance of this component.
+     *
+     * @exception LifecycleException if this component detects a fatal error
+     *  that needs to be reported
+     */
+    public void stop() throws LifecycleException {
+
+        // Validate and update our current component state
+        if (!started)
+            throw new LifecycleException
+                (sm.getString("authenticator.notStarted"));
+        lifecycle.fireLifecycleEvent(STOP_EVENT, null);
+        started = false;
+
+    }
+
+
+    // ------------------------------------------------ SessionListener Methods
+
+
+    /**
+     * Acknowledge the occurrence of the specified event.
+     *
+     * @param event SessionEvent that has occurred
+     */
+    public void sessionEvent(SessionEvent event) {
+
+        // We only care about session destroyed events
+        if (!Session.SESSION_DESTROYED_EVENT.equals(event.getType())
+                && (!Session.SESSION_PASSIVATED_EVENT.equals(event.getType())))
+            return;
+
+        // Look up the single session id associated with this session (if any)
+        Session session = event.getSession();
+        if (containerLog.isDebugEnabled())
+            containerLog.debug("Process session destroyed on " + session);
+
+        String ssoId = null;
+        synchronized (reverse) {
+            ssoId = (String) reverse.get(session);
+        }
+        if (ssoId == null)
+            return;
+
+        // Was the session destroyed as the result of a timeout?
+        // If so, we'll just remove the expired session from the
+        // SSO.  If the session was logged out, we'll log out
+        // of all session associated with the SSO.
+        if (((session.getMaxInactiveInterval() > 0)
+            && (System.currentTimeMillis() - session.getLastAccessedTimeInternal() >=
+                session.getMaxInactiveInterval() * 1000)) 
+            || (Session.SESSION_PASSIVATED_EVENT.equals(event.getType()))) {
+            removeSession(ssoId, session);
+        } else {
+            // The session was logged out.
+            // Deregister this single session id, invalidating 
+            // associated sessions
+            deregister(ssoId);
+        }
+
+    }
+
+
+    // ---------------------------------------------------------- Valve Methods
+
+
+    /**
+     * Return descriptive information about this Valve implementation.
+     */
+    public String getInfo() {
+
+        return (info);
+
+    }
+
+
+    /**
+     * Perform single-sign-on support processing for this request.
+     *
+     * @param request The servlet request we are processing
+     * @param response The servlet response we are creating
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception ServletException if a servlet error occurs
+     */
+    public void invoke(Request request, Response response)
+        throws IOException, ServletException {
+
+        request.removeNote(Constants.REQ_SSOID_NOTE);
+
+        // Has a valid user already been authenticated?
+        if (containerLog.isDebugEnabled())
+            containerLog.debug("Process request for '" + request.getRequestURI() + "'");
+        if (request.getUserPrincipal() != null) {
+            if (containerLog.isDebugEnabled())
+                containerLog.debug(" Principal '" + request.getUserPrincipal().getName() +
+                    "' has already been authenticated");
+            getNext().invoke(request, response);
+            return;
+        }
+
+        // Check for the single sign on cookie
+        if (containerLog.isDebugEnabled())
+            containerLog.debug(" Checking for SSO cookie");
+        Cookie cookie = null;
+        Cookie cookies[] = request.getCookies();
+        if (cookies == null)
+            cookies = new Cookie[0];
+        for (int i = 0; i < cookies.length; i++) {
+            if (Constants.SINGLE_SIGN_ON_COOKIE.equals(cookies[i].getName())) {
+                cookie = cookies[i];
+                break;
+            }
+        }
+        if (cookie == null) {
+            if (containerLog.isDebugEnabled())
+                containerLog.debug(" SSO cookie is not present");
+            getNext().invoke(request, response);
+            return;
+        }
+
+        // Look up the cached Principal associated with this cookie value
+        if (containerLog.isDebugEnabled())
+            containerLog.debug(" Checking for cached principal for " + cookie.getValue());
+        SingleSignOnEntry entry = lookup(cookie.getValue());
+        if (entry != null) {
+            if (containerLog.isDebugEnabled())
+                containerLog.debug(" Found cached principal '" +
+                    entry.getPrincipal().getName() + "' with auth type '" +
+                    entry.getAuthType() + "'");
+            request.setNote(Constants.REQ_SSOID_NOTE, cookie.getValue());
+            // Only set security elements if reauthentication is not required
+            if (!getRequireReauthentication()) {
+                request.setAuthType(entry.getAuthType());
+                request.setUserPrincipal(entry.getPrincipal());
+            }
+        } else {
+            if (containerLog.isDebugEnabled())
+                containerLog.debug(" No cached principal found, erasing SSO cookie");
+            cookie.setMaxAge(0);
+            response.addCookie(cookie);
+        }
+
+        // Invoke the next Valve in our pipeline
+        getNext().invoke(request, response);
+
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Return a String rendering of this object.
+     */
+    public String toString() {
+
+        StringBuffer sb = new StringBuffer("SingleSignOn[");
+        if (container == null )
+            sb.append("Container is null");
+        else
+            sb.append(container.getName());
+        sb.append("]");
+        return (sb.toString());
+
+    }
+
+
+    // ------------------------------------------------------ Protected Methods
+
+
+    /**
+     * Associate the specified single sign on identifier with the
+     * specified Session.
+     *
+     * @param ssoId Single sign on identifier
+     * @param session Session to be associated
+     */
+    protected void associate(String ssoId, Session session) {
+
+        if (containerLog.isDebugEnabled())
+            containerLog.debug("Associate sso id " + ssoId + " with session " + session);
+
+        SingleSignOnEntry sso = lookup(ssoId);
+        if (sso != null)
+            sso.addSession(this, session);
+        synchronized (reverse) {
+            reverse.put(session, ssoId);
+        }
+
+    }
+
+    /**
+     * Deregister the specified session.  If it is the last session,
+     * then also get rid of the single sign on identifier
+     *
+     * @param ssoId Single sign on identifier
+     * @param session Session to be deregistered
+     */
+    protected void deregister(String ssoId, Session session) {
+
+        synchronized (reverse) {
+            reverse.remove(session);
+        }
+
+        SingleSignOnEntry sso = lookup(ssoId);
+        if ( sso == null )
+            return;
+
+        sso.removeSession( session );
+
+        // see if we are the last session, if so blow away ssoId
+        Session sessions[] = sso.findSessions();
+        if ( sessions == null || sessions.length == 0 ) {
+            synchronized (cache) {
+                sso = (SingleSignOnEntry) cache.remove(ssoId);
+            }
+        }
+
+    }
+
+
+    /**
+     * Deregister the specified single sign on identifier, and invalidate
+     * any associated sessions.
+     *
+     * @param ssoId Single sign on identifier to deregister
+     */
+    protected void deregister(String ssoId) {
+
+        if (containerLog.isDebugEnabled())
+            containerLog.debug("Deregistering sso id '" + ssoId + "'");
+
+        // Look up and remove the corresponding SingleSignOnEntry
+        SingleSignOnEntry sso = null;
+        synchronized (cache) {
+            sso = (SingleSignOnEntry) cache.remove(ssoId);
+        }
+
+        if (sso == null)
+            return;
+
+        // Expire any associated sessions
+        Session sessions[] = sso.findSessions();
+        for (int i = 0; i < sessions.length; i++) {
+            if (containerLog.isTraceEnabled())
+                containerLog.trace(" Invalidating session " + sessions[i]);
+            // Remove from reverse cache first to avoid recursion
+            synchronized (reverse) {
+                reverse.remove(sessions[i]);
+            }
+            // Invalidate this session
+            sessions[i].expire();
+        }
+
+        // NOTE:  Clients may still possess the old single sign on cookie,
+        // but it will be removed on the next request since it is no longer
+        // in the cache
+
+    }
+
+
+    /**
+     * Attempts reauthentication to the given <code>Realm</code> using
+     * the credentials associated with the single sign-on session
+     * identified by argument <code>ssoId</code>.
+     * <p>
+     * If reauthentication is successful, the <code>Principal</code> and
+     * authorization type associated with the SSO session will be bound
+     * to the given <code>Request</code> object via calls to 
+     * {@link Request#setAuthType Request.setAuthType()} and 
+     * {@link Request#setUserPrincipal Request.setUserPrincipal()}
+     * </p>
+     *
+     * @param ssoId     identifier of SingleSignOn session with which the
+     *                  caller is associated
+     * @param realm     Realm implementation against which the caller is to
+     *                  be authenticated
+     * @param request   the request that needs to be authenticated
+     * 
+     * @return  <code>true</code> if reauthentication was successful,
+     *          <code>false</code> otherwise.
+     */
+    protected boolean reauthenticate(String ssoId, Realm realm,
+                                     Request request) {
+
+        if (ssoId == null || realm == null)
+            return false;
+
+        boolean reauthenticated = false;
+
+        SingleSignOnEntry entry = lookup(ssoId);
+        if (entry != null && entry.getCanReauthenticate()) {
+            
+            String username = entry.getUsername();
+            if (username != null) {
+                Principal reauthPrincipal =
+                        realm.authenticate(username, entry.getPassword());                
+                if (reauthPrincipal != null) {                    
+                    reauthenticated = true;                    
+                    // Bind the authorization credentials to the request
+                    request.setAuthType(entry.getAuthType());
+                    request.setUserPrincipal(reauthPrincipal);
+                }
+            }
+        }
+
+        return reauthenticated;
+    }
+
+
+    /**
+     * Register the specified Principal as being associated with the specified
+     * value for the single sign on identifier.
+     *
+     * @param ssoId Single sign on identifier to register
+     * @param principal Associated user principal that is identified
+     * @param authType Authentication type used to authenticate this
+     *  user principal
+     * @param username Username used to authenticate this user
+     * @param password Password used to authenticate this user
+     */
+    protected void register(String ssoId, Principal principal, String authType,
+                  String username, String password) {
+
+        if (containerLog.isDebugEnabled())
+            containerLog.debug("Registering sso id '" + ssoId + "' for user '" +
+                principal.getName() + "' with auth type '" + authType + "'");
+
+        synchronized (cache) {
+            cache.put(ssoId, new SingleSignOnEntry(principal, authType,
+                                                   username, password));
+        }
+
+    }
+
+
+    /**
+     * Updates any <code>SingleSignOnEntry</code> found under key
+     * <code>ssoId</code> with the given authentication data.
+     * <p>
+     * The purpose of this method is to allow an SSO entry that was
+     * established without a username/password combination (i.e. established
+     * following DIGEST or CLIENT-CERT authentication) to be updated with
+     * a username and password if one becomes available through a subsequent
+     * BASIC or FORM authentication.  The SSO entry will then be usable for
+     * reauthentication.
+     * <p>
+     * <b>NOTE:</b> Only updates the SSO entry if a call to
+     * <code>SingleSignOnEntry.getCanReauthenticate()</code> returns
+     * <code>false</code>; otherwise, it is assumed that the SSO entry already
+     * has sufficient information to allow reauthentication and that no update
+     * is needed.
+     *
+     * @param ssoId     identifier of Single sign to be updated
+     * @param principal the <code>Principal</code> returned by the latest
+     *                  call to <code>Realm.authenticate</code>.
+     * @param authType  the type of authenticator used (BASIC, CLIENT-CERT,
+     *                  DIGEST or FORM)
+     * @param username  the username (if any) used for the authentication
+     * @param password  the password (if any) used for the authentication
+     */
+    protected void update(String ssoId, Principal principal, String authType,
+                          String username, String password) {
+
+        SingleSignOnEntry sso = lookup(ssoId);
+        if (sso != null && !sso.getCanReauthenticate()) {
+            if (containerLog.isDebugEnabled())
+                containerLog.debug("Update sso id " + ssoId + " to auth type " + authType);
+
+            synchronized(sso) {
+                sso.updateCredentials(principal, authType, username, password);
+            }
+
+        }
+    }
+
+
+    /**
+     * Look up and return the cached SingleSignOn entry associated with this
+     * sso id value, if there is one; otherwise return <code>null</code>.
+     *
+     * @param ssoId Single sign on identifier to look up
+     */
+    protected SingleSignOnEntry lookup(String ssoId) {
+
+        synchronized (cache) {
+            return ((SingleSignOnEntry) cache.get(ssoId));
+        }
+
+    }
+
+    
+    /**
+     * Remove a single Session from a SingleSignOn.  Called when
+     * a session is timed out and no longer active.
+     *
+     * @param ssoId Single sign on identifier from which to remove the session.
+     * @param session the session to be removed.
+     */
+    protected void removeSession(String ssoId, Session session) {
+
+        if (containerLog.isDebugEnabled())
+            containerLog.debug("Removing session " + session.toString() + " from sso id " + 
+                ssoId );
+
+        // Get a reference to the SingleSignOn
+        SingleSignOnEntry entry = lookup(ssoId);
+        if (entry == null)
+            return;
+
+        // Remove the inactive session from SingleSignOnEntry
+        entry.removeSession(session);
+
+        // Remove the inactive session from the 'reverse' Map.
+        synchronized(reverse) {
+            reverse.remove(session);
+        }
+
+        // If there are not sessions left in the SingleSignOnEntry,
+        // deregister the entry.
+        if (entry.findSessions().length == 0) {
+            deregister(ssoId);
+        }
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/authenticator/SingleSignOnEntry.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/authenticator/SingleSignOnEntry.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/authenticator/SingleSignOnEntry.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,189 @@
+/*
+ * Copyright 1999-2001,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.authenticator;
+
+import java.security.Principal;
+
+import org.apache.catalina.Session;
+import org.apache.catalina.authenticator.Constants;
+
+/**
+ * A class that represents entries in the cache of authenticated users.
+ * This is necessary to make it available to
+ * <code>AuthenticatorBase</code> subclasses that need it in order to perform
+ * reauthentications when SingleSignOn is in use.
+ *
+ * @author  B Stansberry, based on work by Craig R. McClanahan
+ * @version $Revision: 302885 $
+ *
+ * @see SingleSignOn
+ * @see AuthenticatorBase#reauthenticateFromSSO
+ */
+public class SingleSignOnEntry
+{
+    // ------------------------------------------------------  Instance Fields
+
+    protected String authType = null;
+
+    protected String password = null;
+
+    protected Principal principal = null;
+
+    protected Session sessions[] = new Session[0];
+
+    protected String username = null;
+
+    protected boolean canReauthenticate = false;
+
+    // ---------------------------------------------------------  Constructors
+
+    /**
+     * Creates a new SingleSignOnEntry
+     *
+     * @param principal the <code>Principal</code> returned by the latest
+     *                  call to <code>Realm.authenticate</code>.
+     * @param authType  the type of authenticator used (BASIC, CLIENT-CERT,
+     *                  DIGEST or FORM)
+     * @param username  the username (if any) used for the authentication
+     * @param password  the password (if any) used for the authentication
+     */
+    public SingleSignOnEntry(Principal principal, String authType,
+                             String username, String password) {
+        super();
+        updateCredentials(principal, authType, username, password);
+    }
+
+    public SingleSignOnEntry() {
+    }
+
+    // ------------------------------------------------------- Package Methods
+
+    /**
+     * Adds a <code>Session</code> to the list of those associated with
+     * this SSO.
+     *
+     * @param sso       The <code>SingleSignOn</code> valve that is managing
+     *                  the SSO session.
+     * @param session   The <code>Session</code> being associated with the SSO.
+     */
+    public synchronized void addSession(SingleSignOn sso, Session session) {
+        for (int i = 0; i < sessions.length; i++) {
+            if (session == sessions[i])
+                return;
+        }
+        Session results[] = new Session[sessions.length + 1];
+        System.arraycopy(sessions, 0, results, 0, sessions.length);
+        results[sessions.length] = session;
+        sessions = results;
+        session.addSessionListener(sso);
+    }
+
+    /**
+     * Removes the given <code>Session</code> from the list of those
+     * associated with this SSO.
+     *
+     * @param session  the <code>Session</code> to remove.
+     */
+    public synchronized void removeSession(Session session) {
+        Session[] nsessions = new Session[sessions.length - 1];
+        for (int i = 0, j = 0; i < sessions.length; i++) {
+            if (session == sessions[i])
+                continue;
+            nsessions[j++] = sessions[i];
+        }
+        sessions = nsessions;
+    }
+
+    /**
+     * Returns the <code>Session</code>s associated with this SSO.
+     */
+    public synchronized Session[] findSessions() {
+        return (this.sessions);
+    }
+
+    /**
+     * Gets the name of the authentication type originally used to authenticate
+     * the user associated with the SSO.
+     *
+     * @return "BASIC", "CLIENT-CERT", "DIGEST", "FORM" or "NONE"
+     */
+    public String getAuthType() {
+        return (this.authType);
+    }
+
+    /**
+     * Gets whether the authentication type associated with the original
+     * authentication supports reauthentication.
+     *
+     * @return  <code>true</code> if <code>getAuthType</code> returns
+     *          "BASIC" or "FORM", <code>false</code> otherwise.
+     */
+    public boolean getCanReauthenticate() {
+        return (this.canReauthenticate);
+    }
+
+    /**
+     * Gets the password credential (if any) associated with the SSO.
+     *
+     * @return  the password credential associated with the SSO, or
+     *          <code>null</code> if the original authentication type
+     *          does not involve a password.
+     */
+    public String getPassword() {
+        return (this.password);
+    }
+
+    /**
+     * Gets the <code>Principal</code> that has been authenticated by
+     * the SSO.
+     */
+    public Principal getPrincipal() {
+        return (this.principal);
+    }
+
+    /**
+     * Gets the username provided by the user as part of the authentication
+     * process.
+     */
+    public String getUsername() {
+        return (this.username);
+    }
+
+
+    /**
+     * Updates the SingleSignOnEntry to reflect the latest security
+     * information associated with the caller.
+     *
+     * @param principal the <code>Principal</code> returned by the latest
+     *                  call to <code>Realm.authenticate</code>.
+     * @param authType  the type of authenticator used (BASIC, CLIENT-CERT,
+     *                  DIGEST or FORM)
+     * @param username  the username (if any) used for the authentication
+     * @param password  the password (if any) used for the authentication
+     */
+    public void updateCredentials(Principal principal, String authType,
+                                  String username, String password) {
+
+        this.principal = principal;
+        this.authType = authType;
+        this.username = username;
+        this.password = password;
+        this.canReauthenticate =
+            (Constants.BASIC_METHOD.equals(authType)
+                || Constants.FORM_METHOD.equals(authType));
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/authenticator/mbeans-descriptors.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/authenticator/mbeans-descriptors.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/authenticator/mbeans-descriptors.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,148 @@
+<?xml version="1.0"?>
+<mbeans-descriptors>
+
+  <mbean name="BasicAuthenticator"
+         description="An Authenticator and Valve implementation of HTTP BASIC Authentication"
+         domain="Catalina"
+         group="Valve"
+         type="org.apache.catalina.authenticator.BasicAuthenticator">
+    
+    <attribute   name="algorithm"
+               description="The message digest algorithm to be used when generating session identifiers"
+               type="java.lang.String"/>
+      
+    <attribute name="cache"
+               description="Should we cache authenticated Principals if the request is part of an HTTP session?"
+               type="boolean"/>
+      
+    <attribute   name="className"
+               description="Fully qualified class name of the managed object"
+               type="java.lang.String"
+               writeable="false"/>
+      
+    <attribute name="entropy"
+               description="A String initialization parameter used to increase the  entropy of the initialization of our random number generator"
+               type="java.lang.String"/>
+  </mbean>
+  
+  
+  <mbean name="DigestAuthenticator"
+         description="An Authenticator and Valve implementation of HTTP DIGEST Authentication"
+         domain="Catalina"
+         group="Valve"
+         type="org.apache.catalina.authenticator.DigestAuthenticator">
+    
+    <attribute name="algorithm"
+               description="The message digest algorithm to be used when generating session identifiers"
+               type="java.lang.String"/>
+      
+    <attribute name="cache"
+               description="Should we cache authenticated Principals if the request is part of an HTTP session?"
+               type="boolean"/>
+
+    <attribute   name="className"
+               description="Fully qualified class name of the managed object"
+               type="java.lang.String"
+               writeable="false"/>
+      
+    <attribute   name="entropy"
+               description="A String initialization parameter used to increase the  entropy of the initialization of our random number generator"
+               type="java.lang.String"/>
+  </mbean>
+  
+  <mbean name="FormAuthenticator"
+         description="An Authenticator and Valve implementation of FORM BASED Authentication"
+         domain="Catalina"
+         group="Valve"
+         type="org.apache.catalina.authenticator.FormAuthenticator">
+    
+    <attribute   name="algorithm"
+               description="The message digest algorithm to be used when generating session identifiers"
+               type="java.lang.String"/>
+      
+    <attribute   name="cache"
+               description="Should we cache authenticated Principals if the request is part of an HTTP session?"
+               type="boolean"/>
+
+    <attribute   name="className"
+               description="Fully qualified class name of the managed object"
+               type="java.lang.String"
+               writeable="false"/>
+
+    <attribute   name="entropy"
+               description="A String initialization parameter used to increase the entropy of the initialization of our random number generator"
+               type="java.lang.String"/>
+  </mbean>
+  
+  <mbean name="NonLoginAuthenticator"
+         description="An Authenticator and Valve implementation that checks only security constraints not involving user authentication"
+         domain="Catalina"
+         group="Valve"
+         type="org.apache.catalina.authenticator.NonLoginAuthenticator">
+    
+    <attribute name="algorithm"
+               description="The message digest algorithm to be used when generating session identifiers"
+               type="java.lang.String"/>
+      
+    <attribute name="cache"
+               description="Should we cache authenticated Principals if the request is part of an HTTP session?"
+               type="boolean"/>
+      
+    <attribute name="className"
+               description="Fully qualified class name of the managed object"
+               type="java.lang.String"
+               writeable="false"/>
+
+    <attribute name="entropy"
+               description="A String initialization parameter used to increase the entropy of the initialization of our random number generator"
+               type="java.lang.String"/>
+  </mbean>
+  
+  
+  <mbean name="SingleSignOn"
+         description="A Valve that supports a 'single signon' user experience"
+         domain="Catalina"
+         group="Valve"
+         type="org.apache.catalina.authenticator.SingleSignOn">
+    
+    <attribute   name="className"
+               description="Fully qualified class name of the managed object"
+               type="java.lang.String"
+               writeable="false"/>
+      
+    <attribute name="requireReauthentication"
+               description="Should we attempt to reauthenticate each request against the security Realm?"
+               type="boolean"/>
+
+    <attribute name="cookieDomain"
+               description="(Optiona) Domain to be used by sso cookies"
+               type="java.lang.String" />
+      
+  </mbean>
+
+
+  <mbean name="SSLAuthenticator"
+         description="An Authenticator and Valve implementation of authentication that utilizes SSL certificates to identify client users"
+         domain="Catalina"
+         group="Valve"
+         type="org.apache.catalina.authenticator.SSLAuthenticator">
+
+    <attribute name="algorithm"
+               description="The message digest algorithm to be used when generating session identifiers"
+               type="java.lang.String"/>
+      
+    <attribute name="cache"
+               description="Should we cache authenticated Principals if the request is part of an HTTP session?"
+               type="boolean"/>
+
+    <attribute name="className"
+               description="Fully qualified class name of the managed object"
+               type="java.lang.String"
+               writeable="false"/>
+
+    <attribute name="entropy"
+               description="A String initialization parameter used to increase the entropy of the initialization of our random number generator"
+               type="java.lang.String"/>
+  </mbean>
+  
+</mbeans-descriptors>

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/authenticator/package.html
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/authenticator/package.html	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/authenticator/package.html	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,38 @@
+<body>
+
+<p>This package contains <code>Authenticator</code> implementations for the
+various supported authentication methods (BASIC, DIGEST, and FORM).  In
+addition, there is a convenience base class,
+<code>AuthenticatorBase</code>, for customized <code>Authenticator</code>
+implementations.</p>
+
+<p>If you are using the standard context configuration class
+(<code>org.apache.catalina.startup.ContextConfig</code>) to configure the
+Authenticator associated with a particular context, you can register the Java
+class to be used for each possible authentication method by modifying the
+following Properties file:</p>
+<pre>
+    src/share/org/apache/catalina/startup/Authenticators.properties
+</pre>
+
+<p>Each of the standard implementations extends a common base class
+(<code>AuthenticatorBase</code>), which is configured by setting the
+following JavaBeans properties (with default values in square brackets):</p>
+<ul>
+<li><b>cache</b> - Should we cache authenticated Principals (thus avoiding
+    per-request lookups in our underyling <code>Realm</code>) if this request
+    is part of an HTTP session?  [true]</li>
+<li><b>debug</b> - Debugging detail level for this component.  [0]</li>
+</ul>
+
+<p>The standard authentication methods that are currently provided include:</p>
+<ul>
+<li><b>BasicAuthenticator</b> - Implements HTTP BASIC authentication, as
+    described in RFC 2617.</li>
+<li><b>DigestAuthenticator</b> - Implements HTTP DIGEST authentication, as
+    described in RFC 2617.</li>
+<li><b>FormAuthenticator</b> - Implements FORM-BASED authentication, as
+    described in the Servlet API Specification, version 2.2.</li>
+</ul>
+
+</body>

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/connector/ClientAbortException.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/connector/ClientAbortException.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/connector/ClientAbortException.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,144 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.connector;
+
+import java.io.IOException;
+
+/**
+ * Wrap an IOException identifying it as being caused by an abort
+ * of a request by a remote client.
+ *
+ * @author Glenn L. Nielsen
+ * @version $Revision: 304063 $ $Date: 2005-08-18 08:25:18 -0500 (Thu, 18 Aug 2005) $
+ */
+
+public final class ClientAbortException extends IOException {
+
+
+    //------------------------------------------------------------ Constructors
+
+
+    /**
+     * Construct a new ClientAbortException with no other information.
+     */
+    public ClientAbortException() {
+
+        this(null, null);
+
+    }
+
+
+    /**
+     * Construct a new ClientAbortException for the specified message.
+     *
+     * @param message Message describing this exception
+     */
+    public ClientAbortException(String message) {
+
+        this(message, null);
+
+    }
+
+
+    /**
+     * Construct a new ClientAbortException for the specified throwable.
+     *
+     * @param throwable Throwable that caused this exception
+     */
+    public ClientAbortException(Throwable throwable) {
+
+        this(null, throwable);
+
+    }
+
+
+    /**
+     * Construct a new ClientAbortException for the specified message
+     * and throwable.
+     *
+     * @param message Message describing this exception
+     * @param throwable Throwable that caused this exception
+     */
+    public ClientAbortException(String message, Throwable throwable) {
+
+        super();
+        this.message = message;
+        this.throwable = throwable;
+
+    }
+
+
+    //------------------------------------------------------ Instance Variables
+
+
+    /**
+     * The error message passed to our constructor (if any)
+     */
+    protected String message = null;
+
+
+    /**
+     * The underlying exception or error passed to our constructor (if any)
+     */
+    protected Throwable throwable = null;
+
+
+    //---------------------------------------------------------- Public Methods
+
+
+    /**
+     * Returns the message associated with this exception, if any.
+     */
+    public String getMessage() {
+
+        return (message);
+
+    }
+
+
+    /**
+     * Returns the cause that caused this exception, if any.
+     */
+    public Throwable getCause() {
+        
+        return (throwable);
+        
+    }
+
+    
+    /**
+     * Return a formatted string that describes this exception.
+     */
+    public String toString() {
+
+        StringBuffer sb = new StringBuffer("ClientAbortException:  ");
+        if (message != null) {
+            sb.append(message);
+            if (throwable != null) {
+                sb.append(":  ");
+            }
+        }
+        if (throwable != null) {
+            sb.append(throwable.toString());
+        }
+        return (sb.toString());
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/connector/Connector.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/connector/Connector.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/connector/Connector.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,1264 @@
+/*
+ * Copyright 1999,2004-2005 The Apache Software Foundation.
+ * 
+ * Licensed 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.connector;
+
+import java.lang.reflect.Method;
+import java.net.URLEncoder;
+import java.util.HashMap;
+
+import javax.management.MBeanRegistration;
+import javax.management.MBeanServer;
+import javax.management.MalformedObjectNameException;
+import javax.management.ObjectName;
+
+import org.apache.catalina.Container;
+import org.apache.catalina.Lifecycle;
+import org.apache.catalina.LifecycleException;
+import org.apache.catalina.LifecycleListener;
+import org.apache.catalina.Service;
+import org.apache.catalina.core.StandardEngine;
+import org.apache.catalina.util.LifecycleSupport;
+import org.apache.catalina.util.StringManager;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.commons.modeler.Registry;
+import org.apache.coyote.Adapter;
+import org.apache.coyote.ProtocolHandler;
+import org.apache.tomcat.util.IntrospectionUtils;
+import org.apache.tomcat.util.http.mapper.Mapper;
+
+
+/**
+ * Implementation of a Coyote connector for Tomcat 5.x.
+ *
+ * @author Craig R. McClanahan
+ * @author Remy Maucherat
+ * @version $Revision: 349505 $ $Date: 2005-11-28 15:14:21 -0600 (Mon, 28 Nov 2005) $
+ */
+
+
+public class Connector
+    implements Lifecycle, MBeanRegistration
+{
+    private static Log log = LogFactory.getLog(Connector.class);
+
+
+    // ------------------------------------------------------------ Constructor
+
+
+    public Connector()
+        throws Exception {
+        this(null);
+    }
+    
+    public Connector(String protocol) 
+        throws Exception {
+        setProtocol(protocol);
+        // Instantiate protocol handler
+        try {
+            Class clazz = Class.forName(protocolHandlerClassName);
+            this.protocolHandler = (ProtocolHandler) clazz.newInstance();
+        } catch (Exception e) {
+            log.error
+                (sm.getString
+                 ("coyoteConnector.protocolHandlerInstantiationFailed", e));
+        }
+    }
+    
+    
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The <code>Service</code> we are associated with (if any).
+     */
+    protected Service service = null;
+
+
+    /**
+     * Do we allow TRACE ?
+     */
+    protected boolean allowTrace = false;
+
+
+    /**
+     * The Container used for processing requests received by this Connector.
+     */
+    protected Container container = null;
+
+
+    /**
+     * Use "/" as path for session cookies ?
+     */
+    protected boolean emptySessionPath = false;
+
+
+    /**
+     * The "enable DNS lookups" flag for this Connector.
+     */
+    protected boolean enableLookups = false;
+
+
+    /*
+     * Is generation of X-Powered-By response header enabled/disabled?
+     */
+    protected boolean xpoweredBy = false;
+
+
+    /**
+     * Descriptive information about this Connector implementation.
+     */
+    protected static final String info =
+        "org.apache.catalina.connector.Connector/2.1";
+
+
+    /**
+     * The lifecycle event support for this component.
+     */
+    protected LifecycleSupport lifecycle = new LifecycleSupport(this);
+
+
+    /**
+     * The port number on which we listen for requests.
+     */
+    protected int port = 0;
+
+
+    /**
+     * The server name to which we should pretend requests to this Connector
+     * were directed.  This is useful when operating Tomcat behind a proxy
+     * server, so that redirects get constructed accurately.  If not specified,
+     * the server name included in the <code>Host</code> header is used.
+     */
+    protected String proxyName = null;
+
+
+    /**
+     * The server port to which we should pretent requests to this Connector
+     * were directed.  This is useful when operating Tomcat behind a proxy
+     * server, so that redirects get constructed accurately.  If not specified,
+     * the port number specified by the <code>port</code> property is used.
+     */
+    protected int proxyPort = 0;
+
+
+    /**
+     * The redirect port for non-SSL to SSL redirects.
+     */
+    protected int redirectPort = 443;
+
+
+    /**
+     * The request scheme that will be set on all requests received
+     * through this connector.
+     */
+    protected String scheme = "http";
+
+
+    /**
+     * The secure connection flag that will be set on all requests received
+     * through this connector.
+     */
+    protected boolean secure = false;
+
+
+    /**
+     * The string manager for this package.
+     */
+    protected StringManager sm =
+        StringManager.getManager(Constants.Package);
+
+
+    /**
+     * Maximum size of a POST which will be automatically parsed by the 
+     * container. 2MB by default.
+     */
+    protected int maxPostSize = 2 * 1024 * 1024;
+
+
+    /**
+     * Maximum size of a POST which will be saved by the container
+     * during authentication. 4kB by default
+     */
+    protected int maxSavePostSize = 4 * 1024;
+
+
+    /**
+     * Has this component been initialized yet?
+     */
+    protected boolean initialized = false;
+
+
+    /**
+     * Has this component been started yet?
+     */
+    protected boolean started = false;
+
+
+    /**
+     * The shutdown signal to our background thread
+     */
+    protected boolean stopped = false;
+
+    /**
+     * Flag to use IP-based virtual hosting.
+     */
+    protected boolean useIPVHosts = false;
+
+    /**
+     * The background thread.
+     */
+    protected Thread thread = null;
+
+
+    /**
+     * Coyote Protocol handler class name.
+     * Defaults to the Coyote HTTP/1.1 protocolHandler.
+     */
+    protected String protocolHandlerClassName =
+        "org.apache.coyote.http11.Http11Protocol";
+
+
+    /**
+     * Coyote protocol handler.
+     */
+    protected ProtocolHandler protocolHandler = null;
+
+
+    /**
+     * Coyote adapter.
+     */
+    protected Adapter adapter = null;
+
+
+     /**
+      * Mapper.
+      */
+     protected Mapper mapper = new Mapper();
+
+
+     /**
+      * Mapper listener.
+      */
+     protected MapperListener mapperListener = new MapperListener(mapper);
+
+
+     /**
+      * URI encoding.
+      */
+     protected String URIEncoding = null;
+
+
+     /**
+      * URI encoding as body.
+      */
+     protected boolean useBodyEncodingForURI = false;
+
+
+     protected static HashMap replacements = new HashMap();
+     static {
+         replacements.put("acceptCount", "backlog");
+         replacements.put("connectionLinger", "soLinger");
+         replacements.put("connectionTimeout", "soTimeout");
+         replacements.put("connectionUploadTimeout", "timeout");
+         replacements.put("clientAuth", "clientauth");
+         replacements.put("keystoreFile", "keystore");
+         replacements.put("randomFile", "randomfile");
+         replacements.put("rootFile", "rootfile");
+         replacements.put("keystorePass", "keypass");
+         replacements.put("keystoreType", "keytype");
+         replacements.put("sslProtocol", "protocol");
+         replacements.put("sslProtocols", "protocols");
+     }
+     
+     
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * Return a configured property.
+     */
+    public Object getProperty(String name) {
+        String repl = name;
+        if (replacements.get(name) != null) {
+            repl = (String) replacements.get(name);
+        }
+        return IntrospectionUtils.getProperty(protocolHandler, repl);
+    }
+
+    
+    /**
+     * Set a configured property.
+     */
+    public void setProperty(String name, String value) {
+        String repl = name;
+        if (replacements.get(name) != null) {
+            repl = (String) replacements.get(name);
+        }
+        IntrospectionUtils.setProperty(protocolHandler, repl, value);
+    }
+
+    
+    /**
+     * Return a configured property.
+     */
+    public Object getAttribute(String name) {
+        return getProperty(name);
+    }
+
+    
+    /**
+     * Set a configured property.
+     */
+    public void setAttribute(String name, Object value) {
+        setProperty(name, String.valueOf(value));
+    }
+
+    
+    /** 
+     * remove a configured property.
+     */
+    public void removeProperty(String name) {
+        // FIXME !
+        //protocolHandler.removeAttribute(name);
+    }
+
+    
+    /**
+     * Return the <code>Service</code> with which we are associated (if any).
+     */
+    public Service getService() {
+
+        return (this.service);
+
+    }
+
+
+    /**
+     * Set the <code>Service</code> with which we are associated (if any).
+     *
+     * @param service The service that owns this Engine
+     */
+    public void setService(Service service) {
+
+        this.service = service;
+        // FIXME: setProperty("service", service);
+
+    }
+
+
+    /**
+     * True if the TRACE method is allowed.  Default value is "false".
+     */
+    public boolean getAllowTrace() {
+
+        return (this.allowTrace);
+
+    }
+
+
+    /**
+     * Set the allowTrace flag, to disable or enable the TRACE HTTP method.
+     *
+     * @param allowTrace The new allowTrace flag
+     */
+    public void setAllowTrace(boolean allowTrace) {
+
+        this.allowTrace = allowTrace;
+        setProperty("allowTrace", String.valueOf(allowTrace));
+
+    }
+
+    /**
+     * Is this connector available for processing requests?
+     */
+    public boolean isAvailable() {
+
+        return (started);
+
+    }
+
+
+    /**
+     * Return the input buffer size for this Connector.
+     * 
+     * @deprecated
+     */
+    public int getBufferSize() {
+        return 2048;
+    }
+
+    /**
+     * Set the input buffer size for this Connector.
+     *
+     * @param bufferSize The new input buffer size.
+     * @deprecated
+     */
+    public void setBufferSize(int bufferSize) {
+    }
+
+    
+    /**
+     * Return the Container used for processing requests received by this
+     * Connector.
+     */
+    public Container getContainer() {
+        if( container==null ) {
+            // Lazy - maybe it was added later
+            findContainer();     
+        }
+        return (container);
+
+    }
+
+
+    /**
+     * Set the Container used for processing requests received by this
+     * Connector.
+     *
+     * @param container The new Container to use
+     */
+    public void setContainer(Container container) {
+
+        this.container = container;
+
+    }
+
+
+    /**
+     * Return the "empty session path" flag.
+     */
+    public boolean getEmptySessionPath() {
+
+        return (this.emptySessionPath);
+
+    }
+
+
+    /**
+     * Set the "empty session path" flag.
+     *
+     * @param emptySessionPath The new "empty session path" flag value
+     */
+    public void setEmptySessionPath(boolean emptySessionPath) {
+
+        this.emptySessionPath = emptySessionPath;
+        setProperty("emptySessionPath", String.valueOf(emptySessionPath));
+
+    }
+
+
+    /**
+     * Return the "enable DNS lookups" flag.
+     */
+    public boolean getEnableLookups() {
+
+        return (this.enableLookups);
+
+    }
+
+
+    /**
+     * Set the "enable DNS lookups" flag.
+     *
+     * @param enableLookups The new "enable DNS lookups" flag value
+     */
+    public void setEnableLookups(boolean enableLookups) {
+
+        this.enableLookups = enableLookups;
+        setProperty("enableLookups", String.valueOf(enableLookups));
+
+    }
+
+
+    /**
+     * Return descriptive information about this Connector implementation.
+     */
+    public String getInfo() {
+
+        return (info);
+
+    }
+
+
+     /**
+      * Return the mapper.
+      */
+     public Mapper getMapper() {
+
+         return (mapper);
+
+     }
+
+
+    /**
+     * Return the maximum size of a POST which will be automatically
+     * parsed by the container.
+     */
+    public int getMaxPostSize() {
+
+        return (maxPostSize);
+
+    }
+
+
+    /**
+     * Set the maximum size of a POST which will be automatically
+     * parsed by the container.
+     *
+     * @param maxPostSize The new maximum size in bytes of a POST which will 
+     * be automatically parsed by the container
+     */
+    public void setMaxPostSize(int maxPostSize) {
+
+        this.maxPostSize = maxPostSize;
+    }
+
+
+    /**
+     * Return the maximum size of a POST which will be saved by the container
+     * during authentication.
+     */
+    public int getMaxSavePostSize() {
+
+        return (maxSavePostSize);
+
+    }
+
+
+    /**
+     * Set the maximum size of a POST which will be saved by the container
+     * during authentication.
+     *
+     * @param maxSavePostSize The new maximum size in bytes of a POST which will
+     * be saved by the container during authentication.
+     */
+    public void setMaxSavePostSize(int maxSavePostSize) {
+
+        this.maxSavePostSize = maxSavePostSize;
+        setProperty("maxSavePostSize", String.valueOf(maxSavePostSize));
+    }
+
+
+    /**
+     * Return the port number on which we listen for requests.
+     */
+    public int getPort() {
+
+        return (this.port);
+
+    }
+
+
+    /**
+     * Set the port number on which we listen for requests.
+     *
+     * @param port The new port number
+     */
+    public void setPort(int port) {
+
+        this.port = port;
+        setProperty("port", String.valueOf(port));
+
+    }
+
+
+    /**
+     * Return the Coyote protocol handler in use.
+     */
+    public String getProtocol() {
+
+        if ("org.apache.coyote.http11.Http11Protocol".equals
+            (getProtocolHandlerClassName())
+            || "org.apache.coyote.http11.Http11AprProtocol".equals
+            (getProtocolHandlerClassName())) {
+            return "HTTP/1.1";
+        } else if ("org.apache.jk.server.JkCoyoteHandler".equals
+                   (getProtocolHandlerClassName())
+                   || "org.apache.coyote.ajp.AjpAprProtocol".equals
+                   (getProtocolHandlerClassName())) {
+            return "AJP/1.3";
+        }
+        return getProtocolHandlerClassName();
+
+    }
+
+
+    /**
+     * Set the Coyote protocol which will be used by the connector.
+     *
+     * @param protocol The Coyote protocol name
+     */
+    public void setProtocol(String protocol) {
+
+        // Test APR support
+        boolean apr = false;
+        try {
+            String methodName = "initialize";
+            Class paramTypes[] = new Class[1];
+            paramTypes[0] = String.class;
+            Object paramValues[] = new Object[1];
+            paramValues[0] = null;
+            Method method = Class.forName("org.apache.tomcat.jni.Library")
+                .getMethod(methodName, paramTypes);
+            method.invoke(null, paramValues);
+            apr = true;
+        } catch (Throwable t) {
+            // Ignore
+        }
+
+        if (apr) {
+            if ("HTTP/1.1".equals(protocol)) {
+                setProtocolHandlerClassName
+                    ("org.apache.coyote.http11.Http11AprProtocol");
+            } else if ("AJP/1.3".equals(protocol)) {
+                setProtocolHandlerClassName
+                    ("org.apache.coyote.ajp.AjpAprProtocol");
+            } else if (protocol != null) {
+                setProtocolHandlerClassName(protocol);
+            } else {
+                setProtocolHandlerClassName
+                    ("org.apache.coyote.http11.Http11AprProtocol");
+            }
+        } else {
+            if ("HTTP/1.1".equals(protocol)) {
+                setProtocolHandlerClassName
+                    ("org.apache.coyote.http11.Http11Protocol");
+            } else if ("AJP/1.3".equals(protocol)) {
+                setProtocolHandlerClassName
+                    ("org.apache.jk.server.JkCoyoteHandler");
+            } else if (protocol != null) {
+                setProtocolHandlerClassName(protocol);
+            }
+        }
+
+    }
+
+
+    /**
+     * Return the class name of the Coyote protocol handler in use.
+     */
+    public String getProtocolHandlerClassName() {
+
+        return (this.protocolHandlerClassName);
+
+    }
+
+
+    /**
+     * Set the class name of the Coyote protocol handler which will be used
+     * by the connector.
+     *
+     * @param protocolHandlerClassName The new class name
+     */
+    public void setProtocolHandlerClassName(String protocolHandlerClassName) {
+
+        this.protocolHandlerClassName = protocolHandlerClassName;
+
+    }
+
+
+    /**
+     * Return the protocol handler associated with the connector.
+     */
+    public ProtocolHandler getProtocolHandler() {
+
+        return (this.protocolHandler);
+
+    }
+
+
+    /**
+     * Return the proxy server name for this Connector.
+     */
+    public String getProxyName() {
+
+        return (this.proxyName);
+
+    }
+
+
+    /**
+     * Set the proxy server name for this Connector.
+     *
+     * @param proxyName The new proxy server name
+     */
+    public void setProxyName(String proxyName) {
+
+        if(proxyName != null && proxyName.length() > 0) {
+            this.proxyName = proxyName;
+            setProperty("proxyName", proxyName);
+        } else {
+            this.proxyName = null;
+            removeProperty("proxyName");
+        }
+
+    }
+
+
+    /**
+     * Return the proxy server port for this Connector.
+     */
+    public int getProxyPort() {
+
+        return (this.proxyPort);
+
+    }
+
+
+    /**
+     * Set the proxy server port for this Connector.
+     *
+     * @param proxyPort The new proxy server port
+     */
+    public void setProxyPort(int proxyPort) {
+
+        this.proxyPort = proxyPort;
+        setProperty("proxyPort", String.valueOf(proxyPort));
+
+    }
+
+
+    /**
+     * Return the port number to which a request should be redirected if
+     * it comes in on a non-SSL port and is subject to a security constraint
+     * with a transport guarantee that requires SSL.
+     */
+    public int getRedirectPort() {
+
+        return (this.redirectPort);
+
+    }
+
+
+    /**
+     * Set the redirect port number.
+     *
+     * @param redirectPort The redirect port number (non-SSL to SSL)
+     */
+    public void setRedirectPort(int redirectPort) {
+
+        this.redirectPort = redirectPort;
+        setProperty("redirectPort", String.valueOf(redirectPort));
+
+    }
+
+    
+    /**
+     * Return the scheme that will be assigned to requests received
+     * through this connector.  Default value is "http".
+     */
+    public String getScheme() {
+
+        return (this.scheme);
+
+    }
+
+
+    /**
+     * Set the scheme that will be assigned to requests received through
+     * this connector.
+     *
+     * @param scheme The new scheme
+     */
+    public void setScheme(String scheme) {
+
+        this.scheme = scheme;
+
+    }
+
+
+    /**
+     * Return the secure connection flag that will be assigned to requests
+     * received through this connector.  Default value is "false".
+     */
+    public boolean getSecure() {
+
+        return (this.secure);
+
+    }
+
+
+    /**
+     * Set the secure connection flag that will be assigned to requests
+     * received through this connector.
+     *
+     * @param secure The new secure connection flag
+     */
+    public void setSecure(boolean secure) {
+
+        this.secure = secure;
+        setProperty("secure", Boolean.toString(secure));
+    }
+
+     /**
+      * Return the character encoding to be used for the URI.
+      */
+     public String getURIEncoding() {
+
+         return (this.URIEncoding);
+
+     }
+
+
+     /**
+      * Set the URI encoding to be used for the URI.
+      *
+      * @param URIEncoding The new URI character encoding.
+      */
+     public void setURIEncoding(String URIEncoding) {
+
+         this.URIEncoding = URIEncoding;
+         setProperty("uRIEncoding", URIEncoding);
+
+     }
+
+
+     /**
+      * Return the true if the entity body encoding should be used for the URI.
+      */
+     public boolean getUseBodyEncodingForURI() {
+
+         return (this.useBodyEncodingForURI);
+
+     }
+
+
+     /**
+      * Set if the entity body encoding should be used for the URI.
+      *
+      * @param useBodyEncodingForURI The new value for the flag.
+      */
+     public void setUseBodyEncodingForURI(boolean useBodyEncodingForURI) {
+
+         this.useBodyEncodingForURI = useBodyEncodingForURI;
+         setProperty
+             ("useBodyEncodingForURI", String.valueOf(useBodyEncodingForURI));
+
+     }
+
+
+    /**
+     * Indicates whether the generation of an X-Powered-By response header for
+     * servlet-generated responses is enabled or disabled for this Connector.
+     *
+     * @return true if generation of X-Powered-By response header is enabled,
+     * false otherwise
+     */
+    public boolean getXpoweredBy() {
+        return xpoweredBy;
+    }
+
+
+    /**
+     * Enables or disables the generation of an X-Powered-By header (with value
+     * Servlet/2.4) for all servlet-generated responses returned by this
+     * Connector.
+     *
+     * @param xpoweredBy true if generation of X-Powered-By response header is
+     * to be enabled, false otherwise
+     */
+    public void setXpoweredBy(boolean xpoweredBy) {
+        this.xpoweredBy = xpoweredBy;
+        setProperty("xpoweredBy", String.valueOf(xpoweredBy));
+    }
+
+    /**
+     * Enable the use of IP-based virtual hosting.
+     *
+     * @param useIPVHosts <code>true</code> if Hosts are identified by IP,
+     *                    <code>false/code> if Hosts are identified by name.
+     */
+    public void setUseIPVHosts(boolean useIPVHosts) {
+        this.useIPVHosts = useIPVHosts;
+        setProperty("useIPVHosts", String.valueOf(useIPVHosts));
+    }
+
+    /**
+     * Test if IP-based virtual hosting is enabled.
+     */
+    public boolean getUseIPVHosts() {
+        return useIPVHosts;
+    }
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Create (or allocate) and return a Request object suitable for
+     * specifying the contents of a Request to the responsible Container.
+     */
+    public Request createRequest() {
+
+        Request request = new Request();
+        request.setConnector(this);
+        return (request);
+
+    }
+
+
+    /**
+     * Create (or allocate) and return a Response object suitable for
+     * receiving the contents of a Response from the responsible Container.
+     */
+    public Response createResponse() {
+
+        Response response = new Response();
+        response.setConnector(this);
+        return (response);
+
+    }
+
+
+    // ------------------------------------------------------ Lifecycle Methods
+
+
+    /**
+     * Add a lifecycle event listener to this component.
+     *
+     * @param listener The listener to add
+     */
+    public void addLifecycleListener(LifecycleListener listener) {
+
+        lifecycle.addLifecycleListener(listener);
+
+    }
+
+
+    /**
+     * Get the lifecycle listeners associated with this lifecycle. If this
+     * Lifecycle has no listeners registered, a zero-length array is returned.
+     */
+    public LifecycleListener[] findLifecycleListeners() {
+
+        return lifecycle.findLifecycleListeners();
+
+    }
+
+
+    /**
+     * Remove a lifecycle event listener from this component.
+     *
+     * @param listener The listener to add
+     */
+    public void removeLifecycleListener(LifecycleListener listener) {
+
+        lifecycle.removeLifecycleListener(listener);
+
+    }
+
+    
+    protected ObjectName createObjectName(String domain, String type)
+            throws MalformedObjectNameException {
+        String encodedAddr = null;
+        if (getProperty("address") != null) {
+            encodedAddr = URLEncoder.encode(getProperty("address").toString());
+        }
+        String addSuffix = (getProperty("address") == null) ? "" : ",address="
+                + encodedAddr;
+        ObjectName _oname = new ObjectName(domain + ":type=" + type + ",port="
+                + getPort() + addSuffix);
+        return _oname;
+    }
+    
+    /**
+     * Initialize this connector (create ServerSocket here!)
+     */
+    public void initialize()
+        throws LifecycleException
+    {
+        if (initialized) {
+            if(log.isInfoEnabled())
+                log.info(sm.getString("coyoteConnector.alreadyInitialized"));
+           return;
+        }
+
+        this.initialized = true;
+
+        if( oname == null && (container instanceof StandardEngine)) {
+            try {
+                // we are loaded directly, via API - and no name was given to us
+                StandardEngine cb=(StandardEngine)container;
+                oname = createObjectName(cb.getName(), "Connector");
+                Registry.getRegistry(null, null)
+                    .registerComponent(this, oname, null);
+                controller=oname;
+            } catch (Exception e) {
+                log.error( "Error registering connector ", e);
+            }
+            if(log.isDebugEnabled())
+                log.debug("Creating name for connector " + oname);
+        }
+
+        // Initializa adapter
+        adapter = new CoyoteAdapter(this);
+        protocolHandler.setAdapter(adapter);
+
+        IntrospectionUtils.setProperty(protocolHandler, "jkHome",
+                                       System.getProperty("catalina.base"));
+
+        try {
+            protocolHandler.init();
+        } catch (Exception e) {
+            throw new LifecycleException
+                (sm.getString
+                 ("coyoteConnector.protocolHandlerInitializationFailed", e));
+        }
+    }
+
+
+    /**
+     * Pause the connector.
+     */
+    public void pause()
+        throws LifecycleException {
+        try {
+            protocolHandler.pause();
+        } catch (Exception e) {
+            log.error(sm.getString
+                      ("coyoteConnector.protocolHandlerPauseFailed"), e);
+        }
+    }
+
+
+    /**
+     * Pause the connector.
+     */
+    public void resume()
+        throws LifecycleException {
+        try {
+            protocolHandler.resume();
+        } catch (Exception e) {
+            log.error(sm.getString
+                      ("coyoteConnector.protocolHandlerResumeFailed"), e);
+        }
+    }
+
+
+    /**
+     * Begin processing requests via this Connector.
+     *
+     * @exception LifecycleException if a fatal startup error occurs
+     */
+    public void start() throws LifecycleException {
+        if( !initialized )
+            initialize();
+
+        // Validate and update our current state
+        if (started ) {
+            if(log.isInfoEnabled())
+                log.info(sm.getString("coyoteConnector.alreadyStarted"));
+            return;
+        }
+        lifecycle.fireLifecycleEvent(START_EVENT, null);
+        started = true;
+
+        // We can't register earlier - the JMX registration of this happens
+        // in Server.start callback
+        if ( this.oname != null ) {
+            // We are registred - register the adapter as well.
+            try {
+                Registry.getRegistry(null, null).registerComponent
+                    (protocolHandler, createObjectName(this.domain,"ProtocolHandler"), null);
+            } catch (Exception ex) {
+                log.error(sm.getString
+                          ("coyoteConnector.protocolRegistrationFailed"), ex);
+            }
+        } else {
+            if(log.isInfoEnabled())
+                log.info(sm.getString
+                     ("coyoteConnector.cannotRegisterProtocol"));
+        }
+
+        try {
+            protocolHandler.start();
+        } catch (Exception e) {
+            String errPrefix = "";
+            if(this.service != null) {
+                errPrefix += "service.getName(): \"" + this.service.getName() + "\"; ";
+            }
+
+            throw new LifecycleException
+                (errPrefix + " " + sm.getString
+                 ("coyoteConnector.protocolHandlerStartFailed", e));
+        }
+
+        if( this.domain != null ) {
+            mapperListener.setDomain( domain );
+            //mapperListener.setEngine( service.getContainer().getName() );
+            mapperListener.init();
+            try {
+                ObjectName mapperOname = createObjectName(this.domain,"Mapper");
+                if (log.isDebugEnabled())
+                    log.debug(sm.getString(
+                            "coyoteConnector.MapperRegistration", mapperOname));
+                Registry.getRegistry(null, null).registerComponent
+                    (mapper, mapperOname, "Mapper");
+            } catch (Exception ex) {
+                log.error(sm.getString
+                        ("coyoteConnector.protocolRegistrationFailed"), ex);
+            }
+        }
+    }
+
+
+    /**
+     * Terminate processing requests via this Connector.
+     *
+     * @exception LifecycleException if a fatal shutdown error occurs
+     */
+    public void stop() throws LifecycleException {
+
+        // Validate and update our current state
+        if (!started) {
+            log.error(sm.getString("coyoteConnector.notStarted"));
+            return;
+
+        }
+        lifecycle.fireLifecycleEvent(STOP_EVENT, null);
+        started = false;
+
+        try {
+            mapperListener.destroy();
+            Registry.getRegistry(null, null).unregisterComponent
+                (createObjectName(this.domain,"Mapper"));
+            Registry.getRegistry(null, null).unregisterComponent
+                (createObjectName(this.domain,"ProtocolHandler"));
+        } catch (MalformedObjectNameException e) {
+            log.error( sm.getString
+                    ("coyoteConnector.protocolUnregistrationFailed"), e);
+        }
+        try {
+            protocolHandler.destroy();
+        } catch (Exception e) {
+            throw new LifecycleException
+                (sm.getString
+                 ("coyoteConnector.protocolHandlerDestroyFailed", e));
+        }
+
+    }
+
+
+    // -------------------- JMX registration  --------------------
+    protected String domain;
+    protected ObjectName oname;
+    protected MBeanServer mserver;
+    ObjectName controller;
+
+    public ObjectName getController() {
+        return controller;
+    }
+
+    public void setController(ObjectName controller) {
+        this.controller = controller;
+    }
+
+    public ObjectName getObjectName() {
+        return oname;
+    }
+
+    public String getDomain() {
+        return domain;
+    }
+
+    public ObjectName preRegister(MBeanServer server,
+                                  ObjectName name) throws Exception {
+        oname=name;
+        mserver=server;
+        domain=name.getDomain();
+        return name;
+    }
+
+    public void postRegister(Boolean registrationDone) {
+    }
+
+    public void preDeregister() throws Exception {
+    }
+
+    public void postDeregister() {
+        try {
+            if( started ) {
+                stop();
+            }
+        } catch( Throwable t ) {
+            log.error( "Unregistering - can't stop", t);
+        }
+    }
+    
+    protected void findContainer() {
+        try {
+            // Register to the service
+            ObjectName parentName=new ObjectName( domain + ":" +
+                    "type=Service");
+            
+            if(log.isDebugEnabled())
+                log.debug("Adding to " + parentName );
+            if( mserver.isRegistered(parentName )) {
+                mserver.invoke(parentName, "addConnector", new Object[] { this },
+                        new String[] {"org.apache.catalina.connector.Connector"});
+                // As a side effect we'll get the container field set
+                // Also initialize will be called
+                //return;
+            }
+            // XXX Go directly to the Engine
+            // initialize(); - is called by addConnector
+            ObjectName engName=new ObjectName( domain + ":" + "type=Engine");
+            if( mserver.isRegistered(engName )) {
+                Object obj=mserver.getAttribute(engName, "managedResource");
+                if(log.isDebugEnabled())
+                      log.debug("Found engine " + obj + " " + obj.getClass());
+                container=(Container)obj;
+                
+                // Internal initialize - we now have the Engine
+                initialize();
+                
+                if(log.isDebugEnabled())
+                    log.debug("Initialized");
+                // As a side effect we'll get the container field set
+                // Also initialize will be called
+                return;
+            }
+        } catch( Exception ex ) {
+            log.error( "Error finding container " + ex);
+        }
+    }
+
+    public void init() throws Exception {
+
+        if( this.getService() != null ) {
+            if(log.isDebugEnabled())
+                 log.debug( "Already configured" );
+            return;
+        }
+        if( container==null ) {
+            findContainer();
+        }
+    }
+
+    public void destroy() throws Exception {
+        if( oname!=null && controller==oname ) {
+            if(log.isDebugEnabled())
+                 log.debug("Unregister itself " + oname );
+            Registry.getRegistry(null, null).unregisterComponent(oname);
+        }
+        if( getService() == null)
+            return;
+        getService().removeConnector(this);
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/connector/Constants.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/connector/Constants.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/connector/Constants.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,48 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.connector;
+
+
+/**
+ * Static constants for this package.
+ */
+
+public final class Constants {
+
+	
+    // -------------------------------------------------------------- Constants
+
+
+    public static final String Package = "org.apache.catalina.connector";
+
+    public static final int DEFAULT_CONNECTION_LINGER = -1;
+    public static final int DEFAULT_CONNECTION_TIMEOUT = 60000;
+    public static final int DEFAULT_CONNECTION_UPLOAD_TIMEOUT = 300000;
+    public static final int DEFAULT_SERVER_SOCKET_TIMEOUT = 0;
+
+    public static final int PROCESSOR_IDLE = 0;
+    public static final int PROCESSOR_ACTIVE = 1;
+
+    /**
+     * Security flag.
+     */
+    public static final boolean SECURITY = 
+        (System.getSecurityManager() != null);
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/connector/CoyoteAdapter.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/connector/CoyoteAdapter.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/connector/CoyoteAdapter.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,609 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.connector;
+
+import java.io.IOException;
+
+import org.apache.catalina.Context;
+import org.apache.catalina.Globals;
+import org.apache.catalina.Wrapper;
+import org.apache.catalina.util.StringManager;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.coyote.ActionCode;
+import org.apache.coyote.Adapter;
+import org.apache.tomcat.util.buf.B2CConverter;
+import org.apache.tomcat.util.buf.ByteChunk;
+import org.apache.tomcat.util.buf.CharChunk;
+import org.apache.tomcat.util.buf.MessageBytes;
+import org.apache.tomcat.util.http.Cookies;
+import org.apache.tomcat.util.http.ServerCookie;
+
+
+/**
+ * Implementation of a request processor which delegates the processing to a
+ * Coyote processor.
+ *
+ * @author Craig R. McClanahan
+ * @author Remy Maucherat
+ * @version $Revision: 426355 $ $Date: 2006-07-27 20:32:57 -0500 (Thu, 27 Jul 2006) $
+ */
+
+public class CoyoteAdapter
+    implements Adapter 
+ {
+    private static Log log = LogFactory.getLog(CoyoteAdapter.class);
+
+    // -------------------------------------------------------------- Constants
+
+
+    public static final int ADAPTER_NOTES = 1;
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Construct a new CoyoteProcessor associated with the specified connector.
+     *
+     * @param connector CoyoteConnector that owns this processor
+     */
+    public CoyoteAdapter(Connector connector) {
+
+        super();
+        this.connector = connector;
+
+    }
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The CoyoteConnector with which this processor is associated.
+     */
+    private Connector connector = null;
+
+
+    /**
+     * The match string for identifying a session ID parameter.
+     */
+    private static final String match =
+        ";" + Globals.SESSION_PARAMETER_NAME + "=";
+
+
+    /**
+     * The match string for identifying a session ID parameter.
+     */
+    private static final char[] SESSION_ID = match.toCharArray();
+
+
+    /**
+     * The string manager for this package.
+     */
+    protected StringManager sm =
+        StringManager.getManager(Constants.Package);
+
+
+    // -------------------------------------------------------- Adapter Methods
+
+
+    /**
+     * Service method.
+     */
+    public void service(org.apache.coyote.Request req, 
+    	                org.apache.coyote.Response res)
+        throws Exception {
+
+        Request request = (Request) req.getNote(ADAPTER_NOTES);
+        Response response = (Response) res.getNote(ADAPTER_NOTES);
+
+        if (request == null) {
+
+            // Create objects
+            request = (Request) connector.createRequest();
+            request.setCoyoteRequest(req);
+            response = (Response) connector.createResponse();
+            response.setCoyoteResponse(res);
+
+            // Link objects
+            request.setResponse(response);
+            response.setRequest(request);
+
+            // Set as notes
+            req.setNote(ADAPTER_NOTES, request);
+            res.setNote(ADAPTER_NOTES, response);
+
+            // Set query string encoding
+            req.getParameters().setQueryStringEncoding
+                (connector.getURIEncoding());
+
+        }
+
+        if (connector.getXpoweredBy()) {
+            response.addHeader("X-Powered-By", "Servlet/2.4");
+        }
+
+        try {
+
+            // Parse and set Catalina and configuration specific 
+            // request parameters
+            if ( postParseRequest(req, request, res, response) ) {
+                // Calling the container
+                connector.getContainer().getPipeline().getFirst().invoke(request, response);
+            }
+
+            response.finishResponse();
+            req.action( ActionCode.ACTION_POST_REQUEST , null);
+
+        } catch (IOException e) {
+            ;
+        } catch (Throwable t) {
+            log.error(sm.getString("coyoteAdapter.service"), t);
+        } finally {
+            // Recycle the wrapper request and response
+            request.recycle();
+            response.recycle();
+        }
+
+    }
+
+
+    // ------------------------------------------------------ Protected Methods
+
+
+    /**
+     * Parse additional request parameters.
+     */
+    protected boolean postParseRequest(org.apache.coyote.Request req, 
+                                       Request request,
+    		                       org.apache.coyote.Response res, 
+                                       Response response)
+            throws Exception {
+
+        // XXX the processor needs to set a correct scheme and port prior to this point, 
+        // in ajp13 protocols dont make sense to get the port from the connector..
+        // XXX the processor may have set a correct scheme and port prior to this point, 
+        // in ajp13 protocols dont make sense to get the port from the connector...
+        // otherwise, use connector configuration
+        if (! req.scheme().isNull()) {
+            // use processor specified scheme to determine secure state
+            request.setSecure(req.scheme().equals("https"));
+        } else {
+            // use connector scheme and secure configuration, (defaults to
+            // "http" and false respectively)
+            req.scheme().setString(connector.getScheme());
+            request.setSecure(connector.getSecure());
+        }
+
+        // FIXME: the code below doesnt belongs to here, 
+        // this is only have sense 
+        // in Http11, not in ajp13..
+        // At this point the Host header has been processed.
+        // Override if the proxyPort/proxyHost are set 
+        String proxyName = connector.getProxyName();
+        int proxyPort = connector.getProxyPort();
+        if (proxyPort != 0) {
+            req.setServerPort(proxyPort);
+        }
+        if (proxyName != null) {
+            req.serverName().setString(proxyName);
+        }
+
+        // Parse session Id
+        parseSessionId(req, request);
+
+        // URI decoding
+        MessageBytes decodedURI = req.decodedURI();
+        decodedURI.duplicate(req.requestURI());
+
+        if (decodedURI.getType() == MessageBytes.T_BYTES) {
+            // Remove any path parameters
+            ByteChunk uriBB = decodedURI.getByteChunk();
+            int semicolon = uriBB.indexOf(';', 0);
+            if (semicolon > 0) {
+                decodedURI.setBytes
+                (uriBB.getBuffer(), uriBB.getStart(), semicolon);
+            }
+            // %xx decoding of the URL
+            try {
+                req.getURLDecoder().convert(decodedURI, false);
+            } catch (IOException ioe) {
+                res.setStatus(400);
+                res.setMessage("Invalid URI");
+                throw ioe;
+            }
+            // Normalization
+            if (!normalize(req.decodedURI())) {
+                res.setStatus(400);
+                res.setMessage("Invalid URI");
+                return false;
+            }
+            // Character decoding
+            convertURI(decodedURI, request);
+        } else {
+            // The URL is chars or String, and has been sent using an in-memory
+            // protocol handler, we have to assume the URL has been properly
+            // decoded already
+            decodedURI.toChars();
+            // Remove any path parameters
+            CharChunk uriCC = decodedURI.getCharChunk();
+            int semicolon = uriCC.indexOf(';');
+            if (semicolon > 0) {
+                decodedURI.setChars
+                (uriCC.getBuffer(), uriCC.getStart(), semicolon);
+            }
+        }
+
+        // Set the remote principal
+        String principal = req.getRemoteUser().toString();
+        if (principal != null) {
+            request.setUserPrincipal(new CoyotePrincipal(principal));
+        }
+
+        // Set the authorization type
+        String authtype = req.getAuthType().toString();
+        if (authtype != null) {
+            request.setAuthType(authtype);
+        }
+
+        // Request mapping.
+        MessageBytes serverName;
+        if (connector.getUseIPVHosts()) {
+            serverName = req.localName();
+            if (serverName.isNull()) {
+                // well, they did ask for it
+                res.action(ActionCode.ACTION_REQ_LOCAL_NAME_ATTRIBUTE, null);
+            }
+        } else {
+            serverName = req.serverName();
+        }
+        connector.getMapper().map(serverName, decodedURI, 
+                                  request.getMappingData());
+        request.setContext((Context) request.getMappingData().context);
+        request.setWrapper((Wrapper) request.getMappingData().wrapper);
+
+        // Filter trace method
+        if (!connector.getAllowTrace() 
+                && req.method().equalsIgnoreCase("TRACE")) {
+            Wrapper wrapper = request.getWrapper();
+            String header = null;
+            if (wrapper != null) {
+                String[] methods = wrapper.getServletMethods();
+                if (methods != null) {
+                    for (int i=0; i<methods.length; i++) {
+                        if ("TRACE".equals(methods[i])) {
+                            continue;
+                        }
+                        if (header == null) {
+                            header = methods[i];
+                        } else {
+                            header += ", " + methods[i];
+                        }
+                    }
+                }
+            }                               
+            res.setStatus(405);
+            res.addHeader("Allow", header);
+            res.setMessage("TRACE method is not allowed");
+            return false;
+        }
+
+        // Possible redirect
+        MessageBytes redirectPathMB = request.getMappingData().redirectPath;
+        if (!redirectPathMB.isNull()) {
+            String redirectPath = redirectPathMB.toString();
+            String query = request.getQueryString();
+            if (request.isRequestedSessionIdFromURL()) {
+                // This is not optimal, but as this is not very common, it
+                // shouldn't matter
+                redirectPath = redirectPath + ";jsessionid=" 
+                    + request.getRequestedSessionId();
+            }
+            if (query != null) {
+                // This is not optimal, but as this is not very common, it
+                // shouldn't matter
+                redirectPath = redirectPath + "?" + query;
+            }
+            response.sendRedirect(redirectPath);
+            return false;
+        }
+
+        // Parse session Id
+        parseSessionCookiesId(req, request);
+
+        return true;
+    }
+
+
+    /**
+     * Parse session id in URL.
+     */
+    protected void parseSessionId(org.apache.coyote.Request req, Request request) {
+
+        ByteChunk uriBC = req.requestURI().getByteChunk();
+        int semicolon = uriBC.indexOf(match, 0, match.length(), 0);
+
+        if (semicolon > 0) {
+
+            // Parse session ID, and extract it from the decoded request URI
+            int start = uriBC.getStart();
+            int end = uriBC.getEnd();
+
+            int sessionIdStart = semicolon + match.length();
+            int semicolon2 = uriBC.indexOf(';', sessionIdStart);
+            if (semicolon2 >= 0) {
+                request.setRequestedSessionId
+                    (new String(uriBC.getBuffer(), start + sessionIdStart, 
+                            semicolon2 - sessionIdStart));
+                // Extract session ID from request URI
+                byte[] buf = uriBC.getBuffer();
+                for (int i = 0; i < end - start - semicolon2; i++) {
+                    buf[start + semicolon + i] 
+                        = buf[start + i + semicolon2];
+                }
+                uriBC.setBytes(buf, start, end - start - semicolon2 + semicolon);
+            } else {
+                request.setRequestedSessionId
+                    (new String(uriBC.getBuffer(), start + sessionIdStart, 
+                            (end - start) - sessionIdStart));
+                uriBC.setEnd(start + semicolon);
+            }
+            request.setRequestedSessionURL(true);
+
+        } else {
+            request.setRequestedSessionId(null);
+            request.setRequestedSessionURL(false);
+        }
+
+    }
+
+
+    /**
+     * Parse session id in URL.
+     */
+    protected void parseSessionCookiesId(org.apache.coyote.Request req, Request request) {
+
+        // Parse session id from cookies
+        Cookies serverCookies = req.getCookies();
+        int count = serverCookies.getCookieCount();
+        if (count <= 0)
+            return;
+
+        for (int i = 0; i < count; i++) {
+            ServerCookie scookie = serverCookies.getCookie(i);
+            if (scookie.getName().equals(Globals.SESSION_COOKIE_NAME)) {
+                // Override anything requested in the URL
+                if (!request.isRequestedSessionIdFromCookie()) {
+                    // Accept only the first session id cookie
+                    convertMB(scookie.getValue());
+                    request.setRequestedSessionId
+                        (scookie.getValue().toString());
+                    request.setRequestedSessionCookie(true);
+                    request.setRequestedSessionURL(false);
+                    if (log.isDebugEnabled())
+                        log.debug(" Requested cookie session id is " +
+                            request.getRequestedSessionId());
+                } else {
+                    if (!request.isRequestedSessionIdValid()) {
+                        // Replace the session id until one is valid
+                        convertMB(scookie.getValue());
+                        request.setRequestedSessionId
+                            (scookie.getValue().toString());
+                    }
+                }
+            }
+        }
+
+    }
+
+
+    /**
+     * Character conversion of the URI.
+     */
+    protected void convertURI(MessageBytes uri, Request request) 
+        throws Exception {
+
+        ByteChunk bc = uri.getByteChunk();
+        CharChunk cc = uri.getCharChunk();
+        cc.allocate(bc.getLength(), -1);
+
+        String enc = connector.getURIEncoding();
+        if (enc != null) {
+            B2CConverter conv = request.getURIConverter();
+            try {
+                if (conv == null) {
+                    conv = new B2CConverter(enc);
+                    request.setURIConverter(conv);
+                } else {
+                    conv.recycle();
+                }
+            } catch (IOException e) {
+                // Ignore
+                log.error("Invalid URI encoding; using HTTP default");
+                connector.setURIEncoding(null);
+            }
+            if (conv != null) {
+                try {
+                    conv.convert(bc, cc);
+                    uri.setChars(cc.getBuffer(), cc.getStart(), 
+                                 cc.getLength());
+                    return;
+                } catch (IOException e) {
+                    log.error("Invalid URI character encoding; trying ascii");
+                    cc.recycle();
+                }
+            }
+        }
+
+        // Default encoding: fast conversion
+        byte[] bbuf = bc.getBuffer();
+        char[] cbuf = cc.getBuffer();
+        int start = bc.getStart();
+        for (int i = 0; i < bc.getLength(); i++) {
+            cbuf[i] = (char) (bbuf[i + start] & 0xff);
+        }
+        uri.setChars(cbuf, 0, bc.getLength());
+
+    }
+
+
+    /**
+     * Character conversion of the a US-ASCII MessageBytes.
+     */
+    protected void convertMB(MessageBytes mb) {
+
+        // This is of course only meaningful for bytes
+        if (mb.getType() != MessageBytes.T_BYTES)
+            return;
+        
+        ByteChunk bc = mb.getByteChunk();
+        CharChunk cc = mb.getCharChunk();
+        cc.allocate(bc.getLength(), -1);
+
+        // Default encoding: fast conversion
+        byte[] bbuf = bc.getBuffer();
+        char[] cbuf = cc.getBuffer();
+        int start = bc.getStart();
+        for (int i = 0; i < bc.getLength(); i++) {
+            cbuf[i] = (char) (bbuf[i + start] & 0xff);
+        }
+        mb.setChars(cbuf, 0, bc.getLength());
+
+    }
+
+
+    /**
+     * Normalize URI.
+     * <p>
+     * This method normalizes "\", "//", "/./" and "/../". This method will
+     * return false when trying to go above the root, or if the URI contains
+     * a null byte.
+     * 
+     * @param uriMB URI to be normalized
+     */
+    public static boolean normalize(MessageBytes uriMB) {
+
+        ByteChunk uriBC = uriMB.getByteChunk();
+        byte[] b = uriBC.getBytes();
+        int start = uriBC.getStart();
+        int end = uriBC.getEnd();
+
+        // URL * is acceptable
+        if ((end - start == 1) && b[start] == (byte) '*')
+          return true;
+
+        int pos = 0;
+        int index = 0;
+
+        // Replace '\' with '/'
+        // Check for null byte
+        for (pos = start; pos < end; pos++) {
+            if (b[pos] == (byte) '\\')
+                b[pos] = (byte) '/';
+            if (b[pos] == (byte) 0)
+                return false;
+        }
+
+        // The URL must start with '/'
+        if (b[start] != (byte) '/') {
+            return false;
+        }
+
+        // Replace "//" with "/"
+        for (pos = start; pos < (end - 1); pos++) {
+            if (b[pos] == (byte) '/') {
+                while ((pos + 1 < end) && (b[pos + 1] == (byte) '/')) {
+                    copyBytes(b, pos, pos + 1, end - pos - 1);
+                    end--;
+                }
+            }
+        }
+
+        // If the URI ends with "/." or "/..", then we append an extra "/"
+        // Note: It is possible to extend the URI by 1 without any side effect
+        // as the next character is a non-significant WS.
+        if (((end - start) >= 2) && (b[end - 1] == (byte) '.')) {
+            if ((b[end - 2] == (byte) '/') 
+                || ((b[end - 2] == (byte) '.') 
+                    && (b[end - 3] == (byte) '/'))) {
+                b[end] = (byte) '/';
+                end++;
+            }
+        }
+
+        uriBC.setEnd(end);
+
+        index = 0;
+
+        // Resolve occurrences of "/./" in the normalized path
+        while (true) {
+            index = uriBC.indexOf("/./", 0, 3, index);
+            if (index < 0)
+                break;
+            copyBytes(b, start + index, start + index + 2, 
+                      end - start - index - 2);
+            end = end - 2;
+            uriBC.setEnd(end);
+        }
+
+        index = 0;
+
+        // Resolve occurrences of "/../" in the normalized path
+        while (true) {
+            index = uriBC.indexOf("/../", 0, 4, index);
+            if (index < 0)
+                break;
+            // Prevent from going outside our context
+            if (index == 0)
+                return false;
+            int index2 = -1;
+            for (pos = start + index - 1; (pos >= 0) && (index2 < 0); pos --) {
+                if (b[pos] == (byte) '/') {
+                    index2 = pos;
+                }
+            }
+            copyBytes(b, start + index2, start + index + 3,
+                      end - start - index - 3);
+            end = end + index2 - index - 3;
+            uriBC.setEnd(end);
+            index = index2;
+        }
+
+        uriBC.setBytes(b, start, end);
+
+        return true;
+
+    }
+
+
+    // ------------------------------------------------------ Protected Methods
+
+
+    /**
+     * Copy an array of bytes to a different position. Used during 
+     * normalization.
+     */
+    protected static void copyBytes(byte[] b, int dest, int src, int len) {
+        for (int pos = 0; pos < len; pos++) {
+            b[pos + dest] = b[pos + src];
+        }
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/connector/CoyoteInputStream.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/connector/CoyoteInputStream.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/connector/CoyoteInputStream.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,233 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.connector;
+
+import java.io.IOException;
+import java.security.AccessController;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
+
+import javax.servlet.ServletInputStream;
+
+import org.apache.catalina.security.SecurityUtil;
+
+/**
+ * This class handles reading bytes.
+ * 
+ * @author Remy Maucherat
+ * @author Jean-Francois Arcand
+ */
+public class CoyoteInputStream
+    extends ServletInputStream {
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    protected InputBuffer ib;
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    protected CoyoteInputStream(InputBuffer ib) {
+        this.ib = ib;
+    }
+
+
+    // -------------------------------------------------------- Package Methods
+
+
+    /**
+     * Clear facade.
+     */
+    void clear() {
+        ib = null;
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Prevent cloning the facade.
+     */
+    protected Object clone()
+        throws CloneNotSupportedException {
+        throw new CloneNotSupportedException();
+    }
+
+
+    // --------------------------------------------- ServletInputStream Methods
+
+
+    public int read()
+        throws IOException {    
+        if (SecurityUtil.isPackageProtectionEnabled()){
+            
+            try{
+                Integer result = 
+                    (Integer)AccessController.doPrivileged(
+                        new PrivilegedExceptionAction(){
+
+                            public Object run() throws IOException{
+                                Integer integer = new Integer(ib.readByte());
+                                return integer;
+                            }
+
+                });
+                return result.intValue();
+            } catch(PrivilegedActionException pae){
+                Exception e = pae.getException();
+                if (e instanceof IOException){
+                    throw (IOException)e;
+                } else {
+                    throw new RuntimeException(e.getMessage());
+                }
+            }
+        } else {
+            return ib.readByte();
+        }
+    }
+
+    public int available() throws IOException {
+        
+        if (SecurityUtil.isPackageProtectionEnabled()){
+            try{
+                Integer result = 
+                    (Integer)AccessController.doPrivileged(
+                        new PrivilegedExceptionAction(){
+
+                            public Object run() throws IOException{
+                                Integer integer = new Integer(ib.available());
+                                return integer;
+                            }
+
+                });
+                return result.intValue();
+            } catch(PrivilegedActionException pae){
+                Exception e = pae.getException();
+                if (e instanceof IOException){
+                    throw (IOException)e;
+                } else {
+                    throw new RuntimeException(e.getMessage());
+                }
+            }
+        } else {
+           return ib.available();
+        }    
+    }
+
+    public int read(final byte[] b) throws IOException {
+        
+        if (SecurityUtil.isPackageProtectionEnabled()){
+            try{
+                Integer result = 
+                    (Integer)AccessController.doPrivileged(
+                        new PrivilegedExceptionAction(){
+
+                            public Object run() throws IOException{
+                                Integer integer = 
+                                    new Integer(ib.read(b, 0, b.length));
+                                return integer;
+                            }
+
+                });
+                return result.intValue();
+            } catch(PrivilegedActionException pae){
+                Exception e = pae.getException();
+                if (e instanceof IOException){
+                    throw (IOException)e;
+                } else {
+                    throw new RuntimeException(e.getMessage());
+                }
+            }
+        } else {
+            return ib.read(b, 0, b.length);
+         }        
+    }
+
+
+    public int read(final byte[] b, final int off, final int len)
+        throws IOException {
+            
+        if (SecurityUtil.isPackageProtectionEnabled()){
+            try{
+                Integer result = 
+                    (Integer)AccessController.doPrivileged(
+                        new PrivilegedExceptionAction(){
+
+                            public Object run() throws IOException{
+                                Integer integer = 
+                                    new Integer(ib.read(b, off, len));
+                                return integer;
+                            }
+
+                });
+                return result.intValue();
+            } catch(PrivilegedActionException pae){
+                Exception e = pae.getException();
+                if (e instanceof IOException){
+                    throw (IOException)e;
+                } else {
+                    throw new RuntimeException(e.getMessage());
+                }
+            }
+        } else {
+            return ib.read(b, off, len);
+        }            
+    }
+
+
+    public int readLine(byte[] b, int off, int len) throws IOException {
+        return super.readLine(b, off, len);
+    }
+
+
+    /** 
+     * Close the stream
+     * Since we re-cycle, we can't allow the call to super.close()
+     * which would permantely disable us.
+     */
+    public void close() throws IOException {
+        
+        if (SecurityUtil.isPackageProtectionEnabled()){
+            try{
+                AccessController.doPrivileged(
+                    new PrivilegedExceptionAction(){
+
+                        public Object run() throws IOException{
+                            ib.close();
+                            return null;
+                        }
+
+                });
+            } catch(PrivilegedActionException pae){
+                Exception e = pae.getException();
+                if (e instanceof IOException){
+                    throw (IOException)e;
+                } else {
+                    throw new RuntimeException(e.getMessage());
+                }
+            }
+        } else {
+             ib.close();
+        }            
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/connector/CoyoteOutputStream.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/connector/CoyoteOutputStream.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/connector/CoyoteOutputStream.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,117 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.connector;
+
+import java.io.IOException;
+
+import javax.servlet.ServletOutputStream;
+
+/**
+ * Coyote implementation of the servlet output stream.
+ * 
+ * @author Costin Manolache
+ * @author Remy Maucherat
+ */
+public class CoyoteOutputStream 
+    extends ServletOutputStream {
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    protected OutputBuffer ob;
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    protected CoyoteOutputStream(OutputBuffer ob) {
+        this.ob = ob;
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Prevent cloning the facade.
+     */
+    protected Object clone()
+        throws CloneNotSupportedException {
+        throw new CloneNotSupportedException();
+    }
+
+
+    // -------------------------------------------------------- Package Methods
+
+
+    /**
+     * Clear facade.
+     */
+    void clear() {
+        ob = null;
+    }
+
+
+    // --------------------------------------------------- OutputStream Methods
+
+
+    public void write(int i)
+        throws IOException {
+        ob.writeByte(i);
+    }
+
+
+    public void write(byte[] b)
+        throws IOException {
+        write(b, 0, b.length);
+    }
+
+
+    public void write(byte[] b, int off, int len)
+        throws IOException {
+        ob.write(b, off, len);
+    }
+
+
+    /**
+     * Will send the buffer to the client.
+     */
+    public void flush()
+        throws IOException {
+        ob.flush();
+    }
+
+
+    public void close()
+        throws IOException {
+        ob.close();
+    }
+
+
+    // -------------------------------------------- ServletOutputStream Methods
+
+
+    public void print(String s)
+        throws IOException {
+        ob.write(s);
+    }
+
+
+}
+

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/connector/CoyotePrincipal.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/connector/CoyotePrincipal.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/connector/CoyotePrincipal.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,74 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.connector;
+
+import java.security.Principal;
+
+/**
+ * Generic implementation of <strong>java.security.Principal</strong> that
+ * is used to represent principals authenticated at the protocol handler level.
+ *
+ * @author Remy Maucherat
+ * @version $Revision: 302975 $ $Date: 2004-06-23 03:25:04 -0500 (Wed, 23 Jun 2004) $
+ */
+
+public class CoyotePrincipal 
+    implements Principal {
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    public CoyotePrincipal(String name) {
+
+        this.name = name;
+
+    }
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * The username of the user represented by this Principal.
+     */
+    protected String name = null;
+
+    public String getName() {
+        return (this.name);
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Return a String representation of this object, which exposes only
+     * information that should be public.
+     */
+    public String toString() {
+
+        StringBuffer sb = new StringBuffer("CoyotePrincipal[");
+        sb.append(this.name);
+        sb.append("]");
+        return (sb.toString());
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/connector/CoyoteReader.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/connector/CoyoteReader.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/connector/CoyoteReader.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,207 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.connector;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+
+
+/**
+ * Coyote implementation of the buffred reader.
+ * 
+ * @author Remy Maucherat
+ */
+public class CoyoteReader
+    extends BufferedReader {
+
+
+    // -------------------------------------------------------------- Constants
+
+
+    private static final char[] LINE_SEP = { '\r', '\n' };
+    private static final int MAX_LINE_LENGTH = 4096;
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    protected InputBuffer ib;
+
+
+    protected char[] lineBuffer = null;
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    public CoyoteReader(InputBuffer ib) {
+        super(ib, 1);
+        this.ib = ib;
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Prevent cloning the facade.
+     */
+    protected Object clone()
+        throws CloneNotSupportedException {
+        throw new CloneNotSupportedException();
+    }
+
+
+    // -------------------------------------------------------- Package Methods
+
+
+    /**
+     * Clear facade.
+     */
+    void clear() {
+        ib = null;
+    }
+
+
+    // --------------------------------------------------------- Reader Methods
+
+
+    public void close()
+        throws IOException {
+        ib.close();
+    }
+
+
+    public int read()
+        throws IOException {
+        return ib.read();
+    }
+
+
+    public int read(char[] cbuf)
+        throws IOException {
+        return ib.read(cbuf, 0, cbuf.length);
+    }
+
+
+    public int read(char[] cbuf, int off, int len)
+        throws IOException {
+        return ib.read(cbuf, off, len);
+    }
+
+
+    public long skip(long n)
+        throws IOException {
+        return ib.skip(n);
+    }
+
+
+    public boolean ready()
+        throws IOException {
+        return ib.ready();
+    }
+
+
+    public boolean markSupported() {
+        return true;
+    }
+
+
+    public void mark(int readAheadLimit)
+        throws IOException {
+        ib.mark(readAheadLimit);
+    }
+
+
+    public void reset()
+        throws IOException {
+        ib.reset();
+    }
+
+
+    public String readLine()
+        throws IOException {
+
+        if (lineBuffer == null) {
+            lineBuffer = new char[MAX_LINE_LENGTH];
+       }
+
+        String result = null;
+
+        int pos = 0;
+        int end = -1;
+        int skip = -1;
+        StringBuffer aggregator = null;
+        while (end < 0) {
+            mark(MAX_LINE_LENGTH);
+            while ((pos < MAX_LINE_LENGTH) && (end < 0)) {
+                int nRead = read(lineBuffer, pos, MAX_LINE_LENGTH - pos);
+                if (nRead < 0) {
+                    if (pos == 0) {
+                        return null;
+                    }
+                    end = pos;
+                    skip = pos;
+                }
+                for (int i = pos; (i < (pos + nRead)) && (end < 0); i++) {
+                    if (lineBuffer[i] == LINE_SEP[0]) {
+                        end = i;
+                        skip = i + 1;
+                        char nextchar;
+                        if (i == (pos + nRead - 1)) {
+                            nextchar = (char) read();
+                        } else {
+                            nextchar = lineBuffer[i+1];
+                        }
+                        if (nextchar == LINE_SEP[1]) {
+                            skip++;
+                        }
+                    } else if (lineBuffer[i] == LINE_SEP[1]) {
+                        end = i;
+                        skip = i + 1;
+                    }
+                }
+                if (nRead > 0) {
+                    pos += nRead;
+                }
+            }
+            if (end < 0) {
+                if (aggregator == null) {
+                    aggregator = new StringBuffer();
+                }
+                aggregator.append(lineBuffer);
+                pos = 0;
+            } else {
+                reset();
+                skip(skip);
+            }
+        }
+
+        if (aggregator == null) {
+            result = new String(lineBuffer, 0, end);
+        } else {
+            aggregator.append(lineBuffer, 0, end);
+            result = aggregator.toString();
+        }
+
+        return result;
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/connector/CoyoteWriter.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/connector/CoyoteWriter.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/connector/CoyoteWriter.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,288 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.connector;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+
+/**
+ * Coyote implementation of the servlet writer.
+ * 
+ * @author Remy Maucherat
+ */
+public class CoyoteWriter
+    extends PrintWriter {
+
+
+    // -------------------------------------------------------------- Constants
+
+
+    private static final char[] LINE_SEP = { '\r', '\n' };
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    protected OutputBuffer ob;
+    protected boolean error = false;
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    public CoyoteWriter(OutputBuffer ob) {
+        super(ob);
+        this.ob = ob;
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Prevent cloning the facade.
+     */
+    protected Object clone()
+        throws CloneNotSupportedException {
+        throw new CloneNotSupportedException();
+    }
+
+
+    // -------------------------------------------------------- Package Methods
+
+
+    /**
+     * Clear facade.
+     */
+    void clear() {
+        ob = null;
+    }
+
+
+    /**
+     * Recycle.
+     */
+    void recycle() {
+        error = false;
+    }
+
+
+    // --------------------------------------------------------- Writer Methods
+
+
+    public void flush() {
+
+        if (error)
+            return;
+
+        try {
+            ob.flush();
+        } catch (IOException e) {
+            error = true;
+        }
+
+    }
+
+
+    public void close() {
+
+        // We don't close the PrintWriter - super() is not called,
+        // so the stream can be reused. We close ob.
+        try {
+            ob.close();
+        } catch (IOException ex ) {
+            ;
+        }
+        error = false;
+
+    }
+
+
+    public boolean checkError() {
+        flush();
+        return error;
+    }
+
+
+    public void write(int c) {
+
+        if (error)
+            return;
+
+        try {
+            ob.write(c);
+        } catch (IOException e) {
+            error = true;
+        }
+
+    }
+
+
+    public void write(char buf[], int off, int len) {
+
+        if (error)
+            return;
+
+        try {
+            ob.write(buf, off, len);
+        } catch (IOException e) {
+            error = true;
+        }
+
+    }
+
+
+    public void write(char buf[]) {
+	write(buf, 0, buf.length);
+    }
+
+
+    public void write(String s, int off, int len) {
+
+        if (error)
+            return;
+
+        try {
+            ob.write(s, off, len);
+        } catch (IOException e) {
+            error = true;
+        }
+
+    }
+
+
+    public void write(String s) {
+        write(s, 0, s.length());
+    }
+
+
+    // ---------------------------------------------------- PrintWriter Methods
+
+
+    public void print(boolean b) {
+        if (b) {
+            write("true");
+        } else {
+            write("false");
+        }
+    }
+
+
+    public void print(char c) {
+        write(c);
+    }
+
+
+    public void print(int i) {
+        write(String.valueOf(i));
+    }
+
+
+    public void print(long l) {
+        write(String.valueOf(l));
+    }
+
+
+    public void print(float f) {
+        write(String.valueOf(f));
+    }
+
+
+    public void print(double d) {
+        write(String.valueOf(d));
+    }
+
+
+    public void print(char s[]) {
+        write(s);
+    }
+
+
+    public void print(String s) {
+        if (s == null) {
+            s = "null";
+        }
+        write(s);
+    }
+
+
+    public void print(Object obj) {
+        write(String.valueOf(obj));
+    }
+
+
+    public void println() {
+        write(LINE_SEP);
+    }
+
+
+    public void println(boolean b) {
+        print(b);
+        println();
+    }
+
+
+    public void println(char c) {
+        print(c);
+        println();
+    }
+
+
+    public void println(int i) {
+        print(i);
+        println();
+    }
+
+
+    public void println(long l) {
+        print(l);
+        println();
+    }
+
+
+    public void println(float f) {
+        print(f);
+        println();
+    }
+
+
+    public void println(double d) {
+        print(d);
+        println();
+    }
+
+
+    public void println(char c[]) {
+        print(c);
+        println();
+    }
+
+
+    public void println(String s) {
+        print(s);
+        println();
+    }
+
+
+    public void println(Object o) {
+        print(o);
+        println();
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/connector/InputBuffer.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/connector/InputBuffer.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/connector/InputBuffer.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,498 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.connector;
+
+import java.io.IOException;
+import java.io.Reader;
+import java.security.AccessController;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
+import java.util.HashMap;
+
+import org.apache.catalina.security.SecurityUtil;
+import org.apache.coyote.Request;
+import org.apache.tomcat.util.buf.B2CConverter;
+import org.apache.tomcat.util.buf.ByteChunk;
+import org.apache.tomcat.util.buf.CharChunk;
+
+
+/**
+ * The buffer used by Tomcat request. This is a derivative of the Tomcat 3.3
+ * OutputBuffer, adapted to handle input instead of output. This allows 
+ * complete recycling of the facade objects (the ServletInputStream and the
+ * BufferedReader).
+ *
+ * @author Remy Maucherat
+ */
+public class InputBuffer extends Reader
+    implements ByteChunk.ByteInputChannel, CharChunk.CharInputChannel,
+               CharChunk.CharOutputChannel {
+
+
+    // -------------------------------------------------------------- Constants
+
+
+    public static final String DEFAULT_ENCODING = 
+        org.apache.coyote.Constants.DEFAULT_CHARACTER_ENCODING;
+    public static final int DEFAULT_BUFFER_SIZE = 8*1024;
+
+    // The buffer can be used for byte[] and char[] reading
+    // ( this is needed to support ServletInputStream and BufferedReader )
+    public final int INITIAL_STATE = 0;
+    public final int CHAR_STATE = 1;
+    public final int BYTE_STATE = 2;
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The byte buffer.
+     */
+    private ByteChunk bb;
+
+
+    /**
+     * The chunk buffer.
+     */
+    private CharChunk cb;
+
+
+    /**
+     * State of the output buffer.
+     */
+    private int state = 0;
+
+
+    /**
+     * Number of bytes read.
+     */
+    private int bytesRead = 0;
+
+
+    /**
+     * Number of chars read.
+     */
+    private int charsRead = 0;
+
+
+    /**
+     * Flag which indicates if the input buffer is closed.
+     */
+    private boolean closed = false;
+
+
+    /**
+     * Byte chunk used to input bytes.
+     */
+    private ByteChunk inputChunk = new ByteChunk();
+
+
+    /**
+     * Encoding to use.
+     */
+    private String enc;
+
+
+    /**
+     * Encoder is set.
+     */
+    private boolean gotEnc = false;
+
+
+    /**
+     * List of encoders.
+     */
+    protected HashMap encoders = new HashMap();
+
+
+    /**
+     * Current byte to char converter.
+     */
+    protected B2CConverter conv;
+
+
+    /**
+     * Associated Coyote request.
+     */
+    private Request coyoteRequest;
+
+
+    /**
+     * Buffer position.
+     */
+    private int markPos = -1;
+
+
+    /**
+     * Buffer size.
+     */
+    private int size = -1;
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Default constructor. Allocate the buffer with the default buffer size.
+     */
+    public InputBuffer() {
+
+        this(DEFAULT_BUFFER_SIZE);
+
+    }
+
+
+    /**
+     * Alternate constructor which allows specifying the initial buffer size.
+     * 
+     * @param size Buffer size to use
+     */
+    public InputBuffer(int size) {
+
+        this.size = size;
+        bb = new ByteChunk(size);
+        bb.setLimit(size);
+        bb.setByteInputChannel(this);
+        cb = new CharChunk(size);
+        cb.setLimit(size);
+        cb.setOptimizedWrite(false);
+        cb.setCharInputChannel(this);
+        cb.setCharOutputChannel(this);
+
+    }
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * Associated Coyote request.
+     * 
+     * @param coyoteRequest Associated Coyote request
+     */
+    public void setRequest(Request coyoteRequest) {
+	this.coyoteRequest = coyoteRequest;
+    }
+
+
+    /**
+     * Get associated Coyote request.
+     * 
+     * @return the associated Coyote request
+     */
+    public Request getRequest() {
+        return this.coyoteRequest;
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Recycle the output buffer.
+     */
+    public void recycle() {
+        
+        state = INITIAL_STATE;
+        bytesRead = 0;
+        charsRead = 0;
+        
+        // If usage of mark made the buffer too big, reallocate it
+        if (cb.getChars().length > size) {
+            cb = new CharChunk(size);
+            cb.setLimit(size);
+            cb.setOptimizedWrite(false);
+            cb.setCharInputChannel(this);
+            cb.setCharOutputChannel(this);
+        } else {
+            cb.recycle();
+        }
+        markPos = -1;
+        bb.recycle(); 
+        closed = false;
+        
+        if (conv != null) {
+            conv.recycle();
+        }
+        
+        gotEnc = false;
+        enc = null;
+        
+    }
+
+
+    /**
+     * Close the input buffer.
+     * 
+     * @throws IOException An underlying IOException occurred
+     */
+    public void close()
+        throws IOException {
+        closed = true;
+    }
+
+
+    public int available()
+        throws IOException {
+        if (state == BYTE_STATE) {
+            return bb.getLength();
+        } else if (state == CHAR_STATE) {
+            return cb.getLength();
+        } else {
+            return 0;
+        }
+    }
+
+
+    // ------------------------------------------------- Bytes Handling Methods
+
+
+    /** 
+     * Reads new bytes in the byte chunk.
+     * 
+     * @param cbuf Byte buffer to be written to the response
+     * @param off Offset
+     * @param len Length
+     * 
+     * @throws IOException An underlying IOException occurred
+     */
+    public int realReadBytes(byte cbuf[], int off, int len)
+	throws IOException {
+
+        if (closed)
+            return -1;
+        if (coyoteRequest == null)
+            return -1;
+
+        state = BYTE_STATE;
+
+        int result = coyoteRequest.doRead(bb);
+
+        return result;
+
+    }
+
+
+    public int readByte()
+        throws IOException {
+        return bb.substract();
+    }
+
+
+    public int read(byte[] b, int off, int len)
+        throws IOException {
+        return bb.substract(b, off, len);
+    }
+
+
+    // ------------------------------------------------- Chars Handling Methods
+
+
+    /**
+     * Since the converter will use append, it is possible to get chars to
+     * be removed from the buffer for "writing". Since the chars have already
+     * been read before, they are ignored. If a mark was set, then the
+     * mark is lost.
+     */
+    public void realWriteChars(char c[], int off, int len) 
+        throws IOException {
+        markPos = -1;
+    }
+
+
+    public void setEncoding(String s) {
+        enc = s;
+    }
+
+
+    public int realReadChars(char cbuf[], int off, int len)
+        throws IOException {
+
+        if (!gotEnc)
+            setConverter();
+
+        if (bb.getLength() <= 0) {
+            int nRead = realReadBytes(bb.getBytes(), 0, bb.getBytes().length);
+            if (nRead < 0) {
+                return -1;
+            }
+        }
+
+        if (markPos == -1) {
+            cb.setOffset(0);
+            cb.setEnd(0);
+        }
+
+        int limit = bb.getLength()+cb.getStart();
+        if( cb.getLimit() < limit ) 
+	    cb.setLimit(limit);
+        conv.convert(bb, cb);
+        bb.setOffset(bb.getEnd());
+        state = CHAR_STATE;
+
+        return cb.getLength();
+
+    }
+
+
+    public int read()
+        throws IOException {
+        return cb.substract();
+    }
+
+
+    public int read(char[] cbuf)
+        throws IOException {
+        return read(cbuf, 0, cbuf.length);
+    }
+
+
+    public int read(char[] cbuf, int off, int len)
+        throws IOException {
+        return cb.substract(cbuf, off, len);
+    }
+
+
+    public long skip(long n)
+        throws IOException {
+
+        if (n < 0) {
+            throw new IllegalArgumentException();
+        }
+
+        long nRead = 0;
+        while (nRead < n) {
+            if (cb.getLength() >= n) {
+                cb.setOffset(cb.getStart() + (int) n);
+                nRead = n;
+            } else {
+                nRead += cb.getLength();
+                cb.setOffset(cb.getEnd());
+                int toRead = 0;
+                if (cb.getChars().length < (n - nRead)) {
+                    toRead = cb.getChars().length;
+                } else {
+                    toRead = (int) (n - nRead);
+                }
+                int nb = realReadChars(cb.getChars(), 0, toRead);
+                if (nb < 0)
+                    break;
+            }
+        }
+
+        return nRead;
+
+    }
+
+
+    public boolean ready()
+        throws IOException {
+        return (cb.getLength() > 0);
+    }
+
+
+    public boolean markSupported() {
+        return true;
+    }
+
+
+    public void mark(int readAheadLimit)
+        throws IOException {
+        if (cb.getLength() <= 0) {
+            cb.setOffset(0);
+            cb.setEnd(0);
+        } else {
+            if ((cb.getBuffer().length > (2 * size)) 
+                && (cb.getLength()) < (cb.getStart())) {
+                System.arraycopy(cb.getBuffer(), cb.getStart(), 
+                                 cb.getBuffer(), 0, cb.getLength());
+                cb.setEnd(cb.getLength());
+                cb.setOffset(0);
+            }
+        }
+        int offset = readAheadLimit;
+        if (offset < size) {
+            offset = size;
+        }
+        cb.setLimit(cb.getStart() + offset);
+        markPos = cb.getStart();
+    }
+
+
+    public void reset()
+        throws IOException {
+        if (state == CHAR_STATE) {
+            if (markPos < 0) {
+                cb.recycle();
+                markPos = -1;
+                throw new IOException();
+            } else {
+                cb.setOffset(markPos);
+            }
+        } else {
+            bb.recycle();
+        }
+    }
+
+
+    public void checkConverter() 
+        throws IOException {
+
+        if (!gotEnc)
+            setConverter();
+
+    }
+
+
+    protected void setConverter()
+        throws IOException {
+
+        if (coyoteRequest != null)
+            enc = coyoteRequest.getCharacterEncoding();
+
+        gotEnc = true;
+        if (enc == null)
+            enc = DEFAULT_ENCODING;
+        conv = (B2CConverter) encoders.get(enc);
+        if (conv == null) {
+            if (SecurityUtil.isPackageProtectionEnabled()){
+                try{
+                    conv = (B2CConverter)AccessController.doPrivileged(
+                            new PrivilegedExceptionAction(){
+
+                                public Object run() throws IOException{
+                                    return new B2CConverter(enc);
+                                }
+
+                            }
+                    );              
+                }catch(PrivilegedActionException ex){
+                    Exception e = ex.getException();
+                    if (e instanceof IOException)
+                        throw (IOException)e; 
+                }
+            } else {
+                conv = new B2CConverter(enc);
+            }
+            encoders.put(enc, conv);
+        }
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/connector/LocalStrings.properties
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/connector/LocalStrings.properties	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/connector/LocalStrings.properties	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,64 @@
+
+#
+# CoyoteConnector
+#
+
+coyoteConnector.alreadyInitialized=The connector has already been initialized
+coyoteConnector.alreadyStarted=The connector has already been started
+coyoteConnector.cannotRegisterProtocol=Cannot register MBean for the Protocol
+coyoteConnector.notStarted=Coyote connector has not been started
+coyoteConnector.protocolHandlerDestroyFailed=Protocol handler destroy failed: {0}
+coyoteConnector.protocolHandlerInitializationFailed=Protocol handler initialization failed: {0}
+coyoteConnector.protocolHandlerInstantiationFailed=Protocol handler instantiation failed: {0}
+coyoteConnector.protocolHandlerStartFailed=Protocol handler start failed: {0}
+coyoteConnector.protocolRegistrationFailed=Protocol JMX registration failed
+coyoteConnector.protocolHandlerPauseFailed=Protocol handler pause failed
+coyoteConnector.protocolHandlerResumeFailed=Protocol handler resume failed
+coyoteConnector.MapperRegistration=register Mapper: {0}
+coyoteConnector.protocolUnregistrationFailed=Protocol handler stop failed
+
+
+#
+# CoyoteAdapter
+#
+
+coyoteAdapter.service=An exception or error occurred in the container during the request processing
+
+#
+# CoyoteResponse
+#
+
+coyoteResponse.getOutputStream.ise=getWriter() has already been called for this response
+coyoteResponse.getWriter.ise=getOutputStream() has already been called for this response
+coyoteResponse.resetBuffer.ise=Cannot reset buffer after response has been committed
+coyoteResponse.sendError.ise=Cannot call sendError() after the response has been committed
+coyoteResponse.sendRedirect.ise=Cannot call sendRedirect() after the response has been committed
+coyoteResponse.setBufferSize.ise=Cannot change buffer size after data has been written
+
+#
+# CoyoteRequest
+#
+
+coyoteRequest.getInputStream.ise=getReader() has already been called for this request
+coyoteRequest.getReader.ise=getInputStream() has already been called for this request
+coyoteRequest.sessionCreateCommitted=Cannot create a session after the response has been committed
+coyoteRequest.setAttribute.namenull=Cannot call setAttribute with a null name
+coyoteRequest.listenerStart=Exception sending context initialized event to listener instance of class {0}
+coyoteRequest.listenerStop=Exception sending context destroyed event to listener instance of class {0}
+coyoteRequest.attributeEvent=Exception thrown by attributes event listener
+coyoteRequest.postTooLarge=Parameters were not parsed because the size of the posted data was too big. Use the maxPostSize attribute of the connector to resolve this if the application should accept large POSTs.
+requestFacade.nullRequest=Null request object
+responseFacade.nullResponse=Null response object
+
+#
+# MapperListener
+#
+mapperListener.unknownDefaultHost=Unknown default host: {0}
+mapperListener.registerHost=Register host {0} at domain {1}
+mapperListener.unregisterHost=Unregister host {0} at domain {1}
+mapperListener.registerContext=Register Context {0} 
+mapperListener.unregisterContext=Unregister Context {0}
+mapperListener.registerWrapper=Register Wrapper {0} in Context {1}
+
+
+

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/connector/LocalStrings_es.properties
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/connector/LocalStrings_es.properties	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/connector/LocalStrings_es.properties	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,56 @@
+
+#
+# CoyoteConnector
+#
+
+coyoteConnector.alreadyInitialized=Ya ha sido inicializado el conector
+coyoteConnector.alreadyStarted=Ya ha sido arrancado el conector
+coyoteConnector.cannotRegisterProtocol=No puedo registrar MBean para el Protocolo
+coyoteConnector.notStarted=El conector Coyote no ha sido arrancado
+coyoteConnector.protocolHandlerDestroyFailed=Falló la destrucción del manejador de protocolo: {0}
+coyoteConnector.protocolHandlerInitializationFailed=Falló la inicialización del manejador de protocolo: {0}
+coyoteConnector.protocolHandlerInstantiationFailed=Falló la instanciación del manejador de protocolo: {0}
+coyoteConnector.protocolHandlerStartFailed=Falló el arranque del manejador de protocolo: {0}
+coyoteConnector.protocolRegistrationFailed=Falló el registro de JMX
+
+#
+# CoyoteAdapter
+#
+
+coyoteAdapter.service=Ha tenido lugar una excepción o error en el contenedor durante el procesamiento del requerimiento
+
+#
+# CoyoteResponse
+#
+
+coyoteResponse.getOutputStream.ise=getWriter() ya ha sido llamado para esta respuesta
+coyoteResponse.getWriter.ise=getOutputStream() ya ha sido llamado para esta respuesta
+coyoteResponse.resetBuffer.ise=No puedo limpiar el búfer después de que la repuesta ha sido llevada a cabo
+coyoteResponse.sendError.ise=No puedo llamar a sendError() tras llevar a cabo la respuesta
+coyoteResponse.sendRedirect.ise=No puedo llamar a sendRedirect() tras llevar a cabo la respuesta
+coyoteResponse.setBufferSize.ise=No puedo cambiar la medida del búfer tras escribir los datos
+
+#
+# CoyoteRequest
+#
+
+coyoteRequest.getInputStream.ise=getReader() ya ha sido llamado para este requerimiento
+coyoteRequest.getReader.ise=getInputStream() ya ha sido llamado para este requerimiento
+coyoteRequest.sessionCreateCommitted=No puedo crear una sesión después de llevar a cabo la respueta
+coyoteRequest.setAttribute.namenull=No pudeo llamar a setAttribute con un nombre nulo
+coyoteRequest.listenerStart=Excepción enviando evento inicializado de contexto a instancia de escuchador de clase {0}
+coyoteRequest.listenerStop=Excepción enviando evento destruído de contexto a instancia de escuchador de clase {0}
+coyoteRequest.attributeEvent=Excepción lanzada mediante el escuchador de eventos de atributos
+coyoteRequest.postTooLarge=No se analizaron los parámetros porque la medida de los datos enviados era demasiado grande. Usa el atributo maxPostSize del conector para resolver esto en caso de que la aplicación debiera de aceptar POSTs más grandes.
+
+
+#
+# MapperListener
+#
+
+mapperListener.registerContext=Registrar Contexto {0}
+mapperListener.unregisterContext=Desregistrar Contexto {0}
+mapperListener.registerWrapper=Registrar Arropador (Wrapper) {0} en Contexto {1}
+
+
+

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/connector/LocalStrings_fr.properties
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/connector/LocalStrings_fr.properties	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/connector/LocalStrings_fr.properties	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,58 @@
+
+#
+# CoyoteConnector
+#
+
+coyoteConnector.alreadyInitialized=Le connecteur a déjà été initialisé
+coyoteConnector.alreadyStarted=Le connecteur a déjà été démarré
+coyoteConnector.cannotRegisterProtocol=Impossible d''enregistrer le MBean pour le Protocol
+coyoteConnector.notStarted=Le connecteur Coyote n''a pas été démarré
+coyoteConnector.protocolHandlerDestroyFailed=La destruction du gestionnaire de protocole a échouée: {0}
+coyoteConnector.protocolHandlerInitializationFailed=L''initialisation du gestionnaire de protocole a échoué: {0}
+coyoteConnector.protocolHandlerInstantiationFailed=L''instantiation du gestionnaire de protocole a échoué: {0}
+coyoteConnector.protocolHandlerStartFailed=Le démarrage du gestionnaire de protocole a échoué: {0}
+coyoteConnector.protocolRegistrationFailed=L''enregistrement du protocol JMX a échoué
+coyoteConnector.protocolHandlerPauseFailed=La suspension du gestionnaire de protocole a échouée
+coyoteConnector.protocolHandlerResumeFailed=Le redémarrage du gestionnaire de protocole a échoué
+
+#
+# CoyoteAdapter
+#
+
+coyoteAdapter.service=Une exception ou une erreur s''est produite dans le conteneur durant le traitement de la requête
+
+#
+# CoyoteResponse
+#
+
+coyoteResponse.getOutputStream.ise="getWriter()" a déjà été appelé pour cette réponse
+coyoteResponse.getWriter.ise="getOutputStream()" a déjà été appelé pour cette réponse
+coyoteResponse.resetBuffer.ise=Impossible de remettre à zéro le tampon après que la réponse ait été envoyée
+coyoteResponse.sendError.ise=Impossible d''appeler "sendError()" après que la réponse ait été envoyée
+coyoteResponse.sendRedirect.ise=Impossible d''appeler "sendRedirect()" après que la réponse ait été envoyée
+coyoteResponse.setBufferSize.ise=Impossible de changer la taille du tampon après que les données aient été écrites
+
+#
+# CoyoteRequest
+#
+
+coyoteRequest.getInputStream.ise="getReader()" a déjà été appelé pour cette requête
+coyoteRequest.getReader.ise="getInputStream()" a déjà été appelé pour cette requête
+coyoteRequest.sessionCreateCommitted=Impossible de créer une sessionaprès que la réponse ait été envoyée
+coyoteRequest.setAttribute.namenull=Impossible d''appeler "setAttribute" avec un nom nul
+coyoteRequest.listenerStart=Une exception s''est produite lors de l''envoi de l''évènement contexte initialisé à l''instance de classe d''écoute {0}
+coyoteRequest.listenerStop=Une exception s''est produite lors de l''envoi de l''évènement contexte détruit à l''instance de classe d''écoute {0}
+coyoteRequest.attributeEvent=Une exception a été lancée par l''instance d''écoute pour l''évènement attributs (attributes)
+coyoteRequest.postTooLarge=Les paramètres n''ont pas été évalué car la taille des données postées est trop important. Utilisez l''attribut maxPostSize du connecteur pour corriger ce problème si votre application doit accepter des POSTs importants.
+
+
+#
+# MapperListener
+#
+
+mapperListener.registerContext=Enregistrement du contexte {0}
+mapperListener.unregisterContext=Désenregistrement du contexte {0}
+mapperListener.registerWrapper=Enregistrement de l''enrobeur (wrapper) {0} dans le contexte {1}
+
+
+

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/connector/LocalStrings_ja.properties
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/connector/LocalStrings_ja.properties	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/connector/LocalStrings_ja.properties	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,58 @@
+
+#
+# CoyoteConnector
+#
+
+coyoteConnector.alreadyInitialized=\u30b3\u30cd\u30af\u30bf\u306f\u65e2\u306b\u521d\u671f\u5316\u3055\u308c\u3066\u3044\u307e\u3059
+coyoteConnector.alreadyStarted=\u30b3\u30cd\u30af\u30bf\u306f\u65e2\u306b\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u3059
+coyoteConnector.cannotRegisterProtocol=\u305d\u306e\u30d7\u30ed\u30c8\u30b3\u30eb\u306bMBean\u3092\u767b\u9332\u3067\u304d\u307e\u305b\u3093
+coyoteConnector.notStarted=Coyote\u30b3\u30cd\u30af\u30bf\u306f\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u305b\u3093
+coyoteConnector.protocolHandlerDestroyFailed=\u30d7\u30ed\u30c8\u30b3\u30eb\u30cf\u30f3\u30c9\u30e9\u306e\u5ec3\u68c4\u306b\u5931\u6557\u3057\u307e\u3057\u305f: {0}
+coyoteConnector.protocolHandlerInitializationFailed=\u30d7\u30ed\u30c8\u30b3\u30eb\u30cf\u30f3\u30c9\u30e9\u306e\u521d\u671f\u5316\u306b\u5931\u6557\u3057\u307e\u3057\u305f: {0}
+coyoteConnector.protocolHandlerInstantiationFailed=\u30d7\u30ed\u30c8\u30b3\u30eb\u30cf\u30f3\u30c9\u30e9\u306e\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u5316\u306b\u5931\u6557\u3057\u307e\u3057\u305f: {0}
+coyoteConnector.protocolHandlerStartFailed=\u30d7\u30ed\u30c8\u30b3\u30eb\u30cf\u30f3\u30c9\u30e9\u306e\u8d77\u52d5\u306b\u5931\u6557\u3057\u307e\u3057\u305f: {0}
+coyoteConnector.protocolRegistrationFailed=\u30d7\u30ed\u30c8\u30b3\u30ebJMX\u306e\u767b\u9332\u306b\u5931\u6557\u3057\u307e\u3057\u305f
+coyoteConnector.protocolHandlerPauseFailed=\u30d7\u30ed\u30c8\u30b3\u30eb\u30cf\u30f3\u30c9\u30e9\u306e\u4e00\u6642\u505c\u6b62\u306b\u5931\u6557\u3057\u307e\u3057\u305f
+coyoteConnector.protocolHandlerResumeFailed=\u30d7\u30ed\u30c8\u30b3\u30eb\u30cf\u30f3\u30c9\u30e9\u306e\u518d\u958b\u306b\u5931\u6557\u3057\u307e\u3057\u305f
+
+#
+# CoyoteAdapter
+#
+
+coyoteAdapter.service=\u30ea\u30af\u30a8\u30b9\u30c8\u306e\u51e6\u7406\u4e2d\u306b\u30b3\u30cd\u30af\u30bf\u3067\u4f8b\u5916\u307e\u305f\u306f\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f
+
+#
+# CoyoteResponse
+#
+
+coyoteResponse.getOutputStream.ise=getWriter()\u306f\u3053\u306e\u30ec\u30b9\u30dd\u30f3\u30b9\u306b\u5bfe\u3057\u3066\u65e2\u306b\u547c\u3073\u51fa\u3055\u308c\u3066\u3044\u307e\u3059
+coyoteResponse.getWriter.ise=getOutputStream()\u306f\u3053\u306e\u30ec\u30b9\u30dd\u30f3\u30b9\u306b\u5bfe\u3057\u3066\u65e2\u306b\u547c\u3073\u51fa\u3055\u308c\u3066\u3044\u307e\u3059
+coyoteResponse.resetBuffer.ise=\u30ec\u30b9\u30dd\u30f3\u30b9\u304c\u30b3\u30df\u30c3\u30c8\u3055\u308c\u305f\u5f8c\u3067\u30d0\u30c3\u30d5\u30a1\u3092\u30ea\u30bb\u30c3\u30c8\u3059\u308b\u3053\u3068\u306f\u3067\u304d\u307e\u305b\u3093
+coyoteResponse.sendError.ise=\u30ec\u30b9\u30dd\u30f3\u30b9\u304c\u30b3\u30df\u30c3\u30c8\u3055\u308c\u305f\u5f8c\u3067sendError()\u3092\u547c\u3073\u51fa\u3059\u3053\u3068\u306f\u3067\u304d\u307e\u305b\u3093
+coyoteResponse.sendRedirect.ise=\u30ec\u30b9\u30dd\u30f3\u30b9\u304c\u30b3\u30df\u30c3\u30c8\u3055\u308c\u305f\u5f8c\u3067sendRedirect()\u3092\u547c\u3073\u51fa\u3059\u3053\u3068\u306f\u3067\u304d\u307e\u305b\u3093
+coyoteResponse.setBufferSize.ise=\u30c7\u30fc\u30bf\u304c\u65e2\u306b\u66f8\u304d\u8fbc\u307e\u308c\u305f\u5f8c\u3067\u30d0\u30c3\u30d5\u30a1\u30b5\u30a4\u30ba\u3092\u5909\u66f4\u3059\u308b\u3053\u3068\u306f\u3067\u304d\u307e\u305b\u3093
+
+#
+# CoyoteRequest
+#
+
+coyoteRequest.getInputStream.ise=getReader()\u306f\u3053\u306e\u30ea\u30af\u30a8\u30b9\u30c8\u306b\u5bfe\u3057\u3066\u65e2\u306b\u547c\u3073\u51fa\u3055\u308c\u3066\u3044\u307e\u3059
+coyoteRequest.getReader.ise=getInputStream()\u306f\u3053\u306e\u30ea\u30af\u30a8\u30b9\u30c8\u306b\u5bfe\u3057\u3066\u65e2\u306b\u547c\u3073\u51fa\u3055\u308c\u3066\u3044\u307e\u3059
+coyoteRequest.sessionCreateCommitted=\u30ec\u30b9\u30dd\u30f3\u30b9\u3092\u30b3\u30df\u30c3\u30c8\u3057\u305f\u5f8c\u3067\u30bb\u30c3\u30b7\u30e7\u30f3\u3092\u4f5c\u6210\u3067\u304d\u307e\u305b\u3093
+coyoteRequest.setAttribute.namenull=setAttribute\u3092\u540d\u524d\u3092\u6307\u5b9a\u305b\u305a\u306b\u547c\u3073\u51fa\u3059\u3053\u3068\u306f\u3067\u304d\u307e\u305b\u3093
+coyoteRequest.listenerStart=\u30af\u30e9\u30b9 {0} \u306e\u30ea\u30b9\u30ca\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u306b\u521d\u671f\u5316\u30a4\u30d9\u30f3\u30c8\u3092\u9001\u4fe1\u4e2d\u306b\u4f8b\u5916\u304c\u6295\u3052\u3089\u308c\u307e\u3057\u305f
+coyoteRequest.listenerStop=\u30af\u30e9\u30b9 {0} \u306e\u30ea\u30b9\u30ca\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u306b\u5ec3\u68c4\u30a4\u30d9\u30f3\u30c8\u3092\u9001\u4fe1\u4e2d\u306b\u4f8b\u5916\u304c\u6295\u3052\u3089\u308c\u307e\u3057\u305f
+coyoteRequest.attributeEvent=\u5c5e\u6027\u30a4\u30d9\u30f3\u30c8\u30ea\u30b9\u30ca\u306b\u3088\u3063\u3066\u4f8b\u5916\u304c\u6295\u3052\u3089\u308c\u307e\u3057\u305f
+coyoteRequest.postTooLarge=POST\u3055\u308c\u305f\u30c7\u30fc\u30bf\u304c\u5927\u304d\u3059\u304e\u305f\u306e\u3067\u3001\u30d1\u30e9\u30e1\u30fc\u30bf\u304c\u69cb\u6587\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u305d\u306e\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u304c\u5de8\u5927\u306aPOST\u3092\u53d7\u3051\u4ed8\u3051\u306d\u3070\u306a\u3089\u306a\u3044\u5834\u5408\u306b\u306f\u3001\u3053\u308c\u3092\u89e3\u6c7a\u3059\u308b\u305f\u3081\u306b\u30b3\u30cd\u30af\u30bf\u306emaxPostSize\u5c5e\u6027\u3092\u4f7f\u7528\u3057\u3066\u304f\u3060\u3055\u3044\u3002
+
+
+#
+# MapperListener
+#
+
+mapperListener.registerContext=\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8 {0}\u3000\u3092\u767b\u9332\u3057\u307e\u3059
+mapperListener.unregisterContext=\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8 {0} \u306e\u767b\u9332\u3092\u62b9\u6d88\u3057\u307e\u3059
+mapperListener.registerWrapper=\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8 {1} \u306b\u30e9\u30c3\u30d1 {0} \u3092\u767b\u9332\u3057\u307e\u3059
+
+
+

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/connector/MapperListener.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/connector/MapperListener.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/connector/MapperListener.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,504 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.connector;
+
+import java.util.Iterator;
+import java.util.Set;
+
+import javax.management.MBeanServer;
+import javax.management.MBeanServerNotification;
+import javax.management.Notification;
+import javax.management.NotificationListener;
+import javax.management.ObjectInstance;
+import javax.management.ObjectName;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.apache.commons.modeler.Registry;
+
+import org.apache.tomcat.util.http.mapper.Mapper;
+
+import org.apache.tomcat.util.res.StringManager;
+
+
+/**
+ * Mapper listener.
+ *
+ * @author Remy Maucherat
+ * @author Costin Manolache
+ */
+public class MapperListener
+    implements NotificationListener 
+ {
+    private static Log log = LogFactory.getLog(MapperListener.class);
+
+
+    // ----------------------------------------------------- Instance Variables
+    /**
+     * Associated mapper.
+     */
+    protected Mapper mapper = null;
+
+    /**
+     * MBean server.
+     */
+    protected MBeanServer mBeanServer = null;
+
+
+    /**
+     * The string manager for this package.
+     */
+    private StringManager sm =
+        StringManager.getManager(Constants.Package);
+
+    // It should be null - and fail if not set
+    private String domain="*";
+    private String engine="*";
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Create mapper listener.
+     */
+    public MapperListener(Mapper mapper) {
+        this.mapper = mapper;
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+    public String getDomain() {
+        return domain;
+    }
+
+    public void setDomain(String domain) {
+        this.domain = domain;
+    }
+
+    public String getEngine() {
+        return engine;
+    }
+
+    public void setEngine(String engine) {
+        this.engine = engine;
+    }
+
+    /**
+     * Initialize associated mapper.
+     */
+    public void init() {
+
+        try {
+
+            mBeanServer = Registry.getRegistry(null, null).getMBeanServer();
+
+            registerEngine();
+
+            // Query hosts
+            String onStr = domain + ":type=Host,*";
+            ObjectName objectName = new ObjectName(onStr);
+            Set set = mBeanServer.queryMBeans(objectName, null);
+            Iterator iterator = set.iterator();
+            while (iterator.hasNext()) {
+                ObjectInstance oi = (ObjectInstance) iterator.next();
+                registerHost(oi.getObjectName());
+            }
+
+
+            // Query contexts
+            onStr = "*:j2eeType=WebModule,*";
+            objectName = new ObjectName(onStr);
+            set = mBeanServer.queryMBeans(objectName, null);
+            iterator = set.iterator();
+            while (iterator.hasNext()) {
+                ObjectInstance oi = (ObjectInstance) iterator.next();
+                registerContext(oi.getObjectName());
+            }
+
+            // Query wrappers
+            onStr = "*:j2eeType=Servlet,*";
+            objectName = new ObjectName(onStr);
+            set = mBeanServer.queryMBeans(objectName, null);
+            iterator = set.iterator();
+            while (iterator.hasNext()) {
+                ObjectInstance oi = (ObjectInstance) iterator.next();
+                registerWrapper(oi.getObjectName());
+            }
+
+            onStr = "JMImplementation:type=MBeanServerDelegate";
+            objectName = new ObjectName(onStr);
+            mBeanServer.addNotificationListener(objectName, this, null, null);
+
+        } catch (Exception e) {
+            log.warn("Error registering contexts",e);
+        }
+
+    }
+
+    /**
+     * unregister this from JMImplementation:type=MBeanServerDelegate
+     */
+    public void destroy() {
+        try {
+
+            ObjectName objectName = new ObjectName(
+                    "JMImplementation:type=MBeanServerDelegate");
+            mBeanServer.removeNotificationListener(objectName, this);
+        } catch (Exception e) {
+            log.warn("Error unregistering MBeanServerDelegate", e);
+        }
+    }
+
+    // ------------------------------------------- NotificationListener Methods
+
+
+    public void handleNotification(Notification notification,
+                                   java.lang.Object handback) {
+
+        if (notification instanceof MBeanServerNotification) {
+            ObjectName objectName = 
+                ((MBeanServerNotification) notification).getMBeanName();
+            String j2eeType = objectName.getKeyProperty("j2eeType");
+            String engineName = null;
+            if (j2eeType != null) {
+                if ((j2eeType.equals("WebModule")) || 
+                    (j2eeType.equals("Servlet"))) {
+                    if (mBeanServer.isRegistered(objectName)) {
+                        try {
+                            engineName = (String)
+                                mBeanServer.getAttribute(objectName, "engineName");
+                        } catch (Exception e) {
+                            // Ignore  
+                        }
+                    }
+                }
+            }
+
+            // At deployment time, engineName is always = null.
+            if ( (!"*".equals(domain)) &&
+                 ( !domain.equals(objectName.getDomain()) ) &&
+                 ( (!domain.equals(engineName) ) &&
+                   (engineName != null) ) )  {
+                return;
+            }
+            if(log.isDebugEnabled())
+                log.debug( "Handle " + objectName  + " type : " + notification.getType());    
+            if (notification.getType().equals
+                (MBeanServerNotification.REGISTRATION_NOTIFICATION)) {
+                String type=objectName.getKeyProperty("type");
+                if( "Host".equals( type ) && domain.equals(objectName.getDomain())) {
+                    try {
+                        registerHost(objectName);
+                    } catch (Exception e) {
+                        log.warn("Error registering Host " + objectName, e);  
+                    }
+                }
+    
+                if (j2eeType != null) {
+                    if (j2eeType.equals("WebModule")) {
+                        try {
+                            registerContext(objectName);
+                        } catch (Throwable t) {
+                            log.warn("Error registering Context " + objectName,t);
+                        }
+                    } else if (j2eeType.equals("Servlet")) {
+                        try {
+                            registerWrapper(objectName);
+                        } catch (Throwable t) {
+                            log.warn("Error registering Wrapper " + objectName,t);
+                        }
+                    }
+                }
+            } else if (notification.getType().equals
+                       (MBeanServerNotification.UNREGISTRATION_NOTIFICATION)) {
+                String type=objectName.getKeyProperty("type");
+                if( "Host".equals( type )&& domain.equals(objectName.getDomain())) {
+                    try {
+                        unregisterHost(objectName);
+                    } catch (Exception e) {
+                        log.warn("Error unregistering Host " + objectName,e);  
+                    }
+                }
+ 
+                if (j2eeType != null) {
+                    if (j2eeType.equals("WebModule")) {
+                        try {
+                            unregisterContext(objectName);
+                        } catch (Throwable t) {
+                            log.warn("Error unregistering webapp " + objectName,t);
+                        }
+                    }
+                }
+            }
+        }
+
+    }
+
+
+    // ------------------------------------------------------ Protected Methods
+
+    private void registerEngine()
+        throws Exception
+    {
+        ObjectName engineName = new ObjectName
+            (domain + ":type=Engine");
+        if ( ! mBeanServer.isRegistered(engineName)) return;
+        String defaultHost = 
+            (String) mBeanServer.getAttribute(engineName, "defaultHost");
+        ObjectName hostName = new ObjectName
+            (domain + ":type=Host," + "host=" + defaultHost);
+        if (!mBeanServer.isRegistered(hostName)) {
+
+            // Get the hosts' list
+            String onStr = domain + ":type=Host,*";
+            ObjectName objectName = new ObjectName(onStr);
+            Set set = mBeanServer.queryMBeans(objectName, null);
+            Iterator iterator = set.iterator();
+            String[] aliases;
+            boolean isRegisteredWithAlias = false;
+            
+            while (iterator.hasNext()) {
+
+                if (isRegisteredWithAlias) break;
+            
+                ObjectInstance oi = (ObjectInstance) iterator.next();
+                hostName = oi.getObjectName();
+                aliases = (String[])
+                    mBeanServer.invoke(hostName, "findAliases", null, null);
+
+                for (int i=0; i < aliases.length; i++){
+                    if (aliases[i].equalsIgnoreCase(defaultHost)){
+                        isRegisteredWithAlias = true;
+                        break;
+                    }
+                }
+            }
+            
+            if (!isRegisteredWithAlias && log.isWarnEnabled())
+                log.warn(sm.getString("mapperListener.unknownDefaultHost", defaultHost));
+        }
+        // This should probablt be called later 
+        if( defaultHost != null ) {
+            mapper.setDefaultHostName(defaultHost);
+        }
+    }
+
+    /**
+     * Register host.
+     */
+    private void registerHost(ObjectName objectName)
+        throws Exception {
+        String name=objectName.getKeyProperty("host");
+        if( name != null ) {        
+            String[] aliases = (String[])
+                mBeanServer.invoke(objectName, "findAliases", null, null);
+            mapper.addHost(name, aliases, objectName);
+            if(log.isDebugEnabled())
+                log.debug(sm.getString
+                     ("mapperListener.registerHost", name, domain));
+
+        }
+    }
+
+
+    /**
+     * Unregister host.
+     */
+    private void unregisterHost(ObjectName objectName)
+        throws Exception {
+        String name=objectName.getKeyProperty("host");
+        mapper.removeHost(name);
+        if(log.isDebugEnabled())
+            log.debug(sm.getString
+                 ("mapperListener.unregisterHost", name, domain));
+    }
+
+
+    /**
+     * Register context.
+     */
+    private void registerContext(ObjectName objectName)
+        throws Exception {
+
+        String name = objectName.getKeyProperty("name");
+        
+        // If the domain is the same with ours or the engine 
+        // name attribute is the same... - then it's ours
+        String targetDomain=objectName.getDomain();
+        if( ! domain.equals( targetDomain )) {
+            try {
+                targetDomain = (String) mBeanServer.getAttribute
+                    (objectName, "engineName");
+            } catch (Exception e) {
+                // Ignore
+            }
+            if( ! domain.equals( targetDomain )) {
+                // not ours
+                return;
+            }
+        }
+
+        String hostName = null;
+        String contextName = null;
+        if (name.startsWith("//")) {
+            name = name.substring(2);
+        }
+        int slash = name.indexOf("/");
+        if (slash != -1) {
+            hostName = name.substring(0, slash);
+            contextName = name.substring(slash);
+        } else {
+            return;
+        }
+        // Special case for the root context
+        if (contextName.equals("/")) {
+            contextName = "";
+        }
+
+        if(log.isDebugEnabled())
+             log.debug(sm.getString
+                  ("mapperListener.registerContext", contextName));
+
+        Object context = 
+            mBeanServer.invoke(objectName, "findMappingObject", null, null);
+            //mBeanServer.getAttribute(objectName, "mappingObject");
+        javax.naming.Context resources = (javax.naming.Context)
+            mBeanServer.invoke(objectName, "findStaticResources", null, null);
+            //mBeanServer.getAttribute(objectName, "staticResources");
+        String[] welcomeFiles = (String[])
+            mBeanServer.getAttribute(objectName, "welcomeFiles");
+
+        mapper.addContext(hostName, contextName, context, 
+                          welcomeFiles, resources);
+
+    }
+
+
+    /**
+     * Unregister context.
+     */
+    private void unregisterContext(ObjectName objectName)
+        throws Exception {
+
+        String name = objectName.getKeyProperty("name");
+
+        // If the domain is the same with ours or the engine 
+        // name attribute is the same... - then it's ours
+        String targetDomain=objectName.getDomain();
+        if( ! domain.equals( targetDomain )) {
+            try {
+                targetDomain = (String) mBeanServer.getAttribute
+                    (objectName, "engineName");
+            } catch (Exception e) {
+                // Ignore
+            }
+            if( ! domain.equals( targetDomain )) {
+                // not ours
+                return;
+            }
+        }
+
+        String hostName = null;
+        String contextName = null;
+        if (name.startsWith("//")) {
+            name = name.substring(2);
+        }
+        int slash = name.indexOf("/");
+        if (slash != -1) {
+            hostName = name.substring(0, slash);
+            contextName = name.substring(slash);
+        } else {
+            return;
+        }
+        // Special case for the root context
+        if (contextName.equals("/")) {
+            contextName = "";
+        }
+        if(log.isDebugEnabled())
+            log.debug(sm.getString
+                  ("mapperListener.unregisterContext", contextName));
+
+        mapper.removeContext(hostName, contextName);
+
+    }
+
+
+    /**
+     * Register wrapper.
+     */
+    private void registerWrapper(ObjectName objectName)
+        throws Exception {
+    
+        // If the domain is the same with ours or the engine 
+        // name attribute is the same... - then it's ours
+        String targetDomain=objectName.getDomain();
+        if( ! domain.equals( targetDomain )) {
+            try {
+                targetDomain=(String) mBeanServer.getAttribute(objectName, "engineName");
+            } catch (Exception e) {
+                // Ignore
+            }
+            if( ! domain.equals( targetDomain )) {
+                // not ours
+                return;
+            }
+            
+        }
+
+        String wrapperName = objectName.getKeyProperty("name");
+        String name = objectName.getKeyProperty("WebModule");
+
+        String hostName = null;
+        String contextName = null;
+        if (name.startsWith("//")) {
+            name = name.substring(2);
+        }
+        int slash = name.indexOf("/");
+        if (slash != -1) {
+            hostName = name.substring(0, slash);
+            contextName = name.substring(slash);
+        } else {
+            return;
+        }
+        // Special case for the root context
+        if (contextName.equals("/")) {
+            contextName = "";
+        }
+        if(log.isDebugEnabled())
+            log.debug(sm.getString
+                  ("mapperListener.registerWrapper", 
+                   wrapperName, contextName));
+
+        String[] mappings = (String[])
+            mBeanServer.invoke(objectName, "findMappings", null, null);
+        Object wrapper = 
+            mBeanServer.invoke(objectName, "findMappingObject", null, null);
+
+        for (int i = 0; i < mappings.length; i++) {
+            boolean jspWildCard = (wrapperName.equals("jsp")
+                                   && mappings[i].endsWith("/*"));
+            mapper.addWrapper(hostName, contextName, mappings[i], wrapper,
+                              jspWildCard);
+        }
+
+    }
+
+
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/connector/OutputBuffer.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/connector/OutputBuffer.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/connector/OutputBuffer.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,651 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.connector;
+
+
+import java.io.IOException;
+import java.io.Writer;
+import java.security.AccessController;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
+import java.util.HashMap;
+
+import org.apache.catalina.security.SecurityUtil;
+import org.apache.coyote.ActionCode;
+import org.apache.coyote.Response;
+import org.apache.tomcat.util.buf.ByteChunk;
+import org.apache.tomcat.util.buf.C2BConverter;
+import org.apache.tomcat.util.buf.CharChunk;
+
+
+/**
+ * The buffer used by Tomcat response. This is a derivative of the Tomcat 3.3
+ * OutputBuffer, with the removal of some of the state handling (which in 
+ * Coyote is mostly the Processor's responsability).
+ *
+ * @author Costin Manolache
+ * @author Remy Maucherat
+ */
+public class OutputBuffer extends Writer
+    implements ByteChunk.ByteOutputChannel, CharChunk.CharOutputChannel {
+
+
+    // -------------------------------------------------------------- Constants
+
+
+    public static final String DEFAULT_ENCODING = 
+        org.apache.coyote.Constants.DEFAULT_CHARACTER_ENCODING;
+    public static final int DEFAULT_BUFFER_SIZE = 8*1024;
+
+
+    // The buffer can be used for byte[] and char[] writing
+    // ( this is needed to support ServletOutputStream and for
+    // efficient implementations of templating systems )
+    public final int INITIAL_STATE = 0;
+    public final int CHAR_STATE = 1;
+    public final int BYTE_STATE = 2;
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The byte buffer.
+     */
+    private ByteChunk bb;
+
+
+    /**
+     * The chunk buffer.
+     */
+    private CharChunk cb;
+
+
+    /**
+     * State of the output buffer.
+     */
+    private int state = 0;
+
+
+    /**
+     * Number of bytes written.
+     */
+    private int bytesWritten = 0;
+
+
+    /**
+     * Number of chars written.
+     */
+    private int charsWritten = 0;
+
+
+    /**
+     * Flag which indicates if the output buffer is closed.
+     */
+    private boolean closed = false;
+
+
+    /**
+     * Do a flush on the next operation.
+     */
+    private boolean doFlush = false;
+
+
+    /**
+     * Byte chunk used to output bytes.
+     */
+    private ByteChunk outputChunk = new ByteChunk();
+
+
+    /**
+     * Encoding to use.
+     */
+    private String enc;
+
+
+    /**
+     * Encoder is set.
+     */
+    private boolean gotEnc = false;
+
+
+    /**
+     * List of encoders.
+     */
+    protected HashMap encoders = new HashMap();
+
+
+    /**
+     * Current char to byte converter.
+     */
+    protected C2BConverter conv;
+
+
+    /**
+     * Associated Coyote response.
+     */
+    private Response coyoteResponse;
+
+
+    /**
+     * Suspended flag. All output bytes will be swallowed if this is true.
+     */
+    private boolean suspended = false;
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Default constructor. Allocate the buffer with the default buffer size.
+     */
+    public OutputBuffer() {
+
+        this(DEFAULT_BUFFER_SIZE);
+
+    }
+
+
+    /**
+     * Alternate constructor which allows specifying the initial buffer size.
+     * 
+     * @param size Buffer size to use
+     */
+    public OutputBuffer(int size) {
+
+        bb = new ByteChunk(size);
+        bb.setLimit(size);
+        bb.setByteOutputChannel(this);
+        cb = new CharChunk(size);
+        cb.setCharOutputChannel(this);
+        cb.setLimit(size);
+
+    }
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * Associated Coyote response.
+     * 
+     * @param coyoteResponse Associated Coyote response
+     */
+    public void setResponse(Response coyoteResponse) {
+	this.coyoteResponse = coyoteResponse;
+    }
+
+
+    /**
+     * Get associated Coyote response.
+     * 
+     * @return the associated Coyote response
+     */
+    public Response getResponse() {
+        return this.coyoteResponse;
+    }
+
+
+    /**
+     * Is the response output suspended ?
+     * 
+     * @return suspended flag value
+     */
+    public boolean isSuspended() {
+        return this.suspended;
+    }
+
+
+    /**
+     * Set the suspended flag.
+     * 
+     * @param suspended New suspended flag value
+     */
+    public void setSuspended(boolean suspended) {
+        this.suspended = suspended;
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Recycle the output buffer.
+     */
+    public void recycle() {
+        
+        state = INITIAL_STATE;
+        bytesWritten = 0;
+        charsWritten = 0;
+        
+        cb.recycle();
+        bb.recycle(); 
+        closed = false;
+        suspended = false;
+        
+        if (conv!= null) {
+            conv.recycle();
+        }
+        
+        gotEnc = false;
+        enc = null;
+        
+    }
+
+
+    /**
+     * Close the output buffer. This tries to calculate the response size if 
+     * the response has not been committed yet.
+     * 
+     * @throws IOException An underlying IOException occurred
+     */
+    public void close()
+        throws IOException {
+
+        if (closed)
+            return;
+        if (suspended)
+            return;
+
+        if ((!coyoteResponse.isCommitted()) 
+            && (coyoteResponse.getContentLengthLong() == -1)) {
+            // Flushing the char buffer
+            if (state == CHAR_STATE) {
+                cb.flushBuffer();
+                state = BYTE_STATE;
+            }
+            // If this didn't cause a commit of the response, the final content
+            // length can be calculated
+            if (!coyoteResponse.isCommitted()) {
+                coyoteResponse.setContentLength(bb.getLength());
+            }
+        }
+
+        doFlush(false);
+        closed = true;
+
+        coyoteResponse.finish();
+
+    }
+
+
+    /**
+     * Flush bytes or chars contained in the buffer.
+     * 
+     * @throws IOException An underlying IOException occurred
+     */
+    public void flush()
+        throws IOException {
+        doFlush(true);
+    }
+
+
+    /**
+     * Flush bytes or chars contained in the buffer.
+     * 
+     * @throws IOException An underlying IOException occurred
+     */
+    protected void doFlush(boolean realFlush)
+        throws IOException {
+
+        if (suspended)
+            return;
+
+        doFlush = true;
+        if (state == CHAR_STATE) {
+            cb.flushBuffer();
+            bb.flushBuffer();
+            state = BYTE_STATE;
+        } else if (state == BYTE_STATE) {
+            bb.flushBuffer();
+        } else if (state == INITIAL_STATE) {
+            // If the buffers are empty, commit the response header
+            coyoteResponse.sendHeaders();
+        }
+        doFlush = false;
+
+        if (realFlush) {
+            coyoteResponse.action(ActionCode.ACTION_CLIENT_FLUSH, 
+                                  coyoteResponse);
+            // If some exception occurred earlier, or if some IOE occurred
+            // here, notify the servlet with an IOE
+            if (coyoteResponse.isExceptionPresent()) {
+                throw new ClientAbortException
+                    (coyoteResponse.getErrorException());
+            }
+        }
+
+    }
+
+
+    // ------------------------------------------------- Bytes Handling Methods
+
+
+    /** 
+     * Sends the buffer data to the client output, checking the
+     * state of Response and calling the right interceptors.
+     * 
+     * @param buf Byte buffer to be written to the response
+     * @param off Offset
+     * @param cnt Length
+     * 
+     * @throws IOException An underlying IOException occurred
+     */
+    public void realWriteBytes(byte buf[], int off, int cnt)
+	throws IOException {
+
+        if (closed)
+            return;
+        if (coyoteResponse == null)
+            return;
+
+        // If we really have something to write
+        if (cnt > 0) {
+            // real write to the adapter
+            outputChunk.setBytes(buf, off, cnt);
+            try {
+                coyoteResponse.doWrite(outputChunk);
+            } catch (IOException e) {
+                // An IOException on a write is almost always due to
+                // the remote client aborting the request.  Wrap this
+                // so that it can be handled better by the error dispatcher.
+                throw new ClientAbortException(e);
+            }
+        }
+
+    }
+
+
+    public void write(byte b[], int off, int len) throws IOException {
+
+        if (suspended)
+            return;
+
+        if (state == CHAR_STATE)
+            cb.flushBuffer();
+        state = BYTE_STATE;
+        writeBytes(b, off, len);
+
+    }
+
+
+    private void writeBytes(byte b[], int off, int len) 
+        throws IOException {
+
+        if (closed)
+            return;
+
+        bb.append(b, off, len);
+        bytesWritten += len;
+
+        // if called from within flush(), then immediately flush
+        // remaining bytes
+        if (doFlush) {
+            bb.flushBuffer();
+        }
+
+    }
+
+
+    public void writeByte(int b)
+        throws IOException {
+
+        if (suspended)
+            return;
+
+        if (state == CHAR_STATE)
+            cb.flushBuffer();
+        state = BYTE_STATE;
+
+        bb.append( (byte)b );
+        bytesWritten++;
+
+    }
+
+
+    // ------------------------------------------------- Chars Handling Methods
+
+
+    public void write(int c)
+        throws IOException {
+
+        if (suspended)
+            return;
+
+        state = CHAR_STATE;
+
+        cb.append((char) c);
+        charsWritten++;
+
+    }
+
+
+    public void write(char c[])
+        throws IOException {
+
+        if (suspended)
+            return;
+
+        write(c, 0, c.length);
+
+    }
+
+
+    public void write(char c[], int off, int len)
+        throws IOException {
+
+        if (suspended)
+            return;
+
+        state = CHAR_STATE;
+
+        cb.append(c, off, len);
+        charsWritten += len;
+
+    }
+
+
+    public void write(StringBuffer sb)
+        throws IOException {
+
+        if (suspended)
+            return;
+
+        state = CHAR_STATE;
+
+        int len = sb.length();
+        charsWritten += len;
+        cb.append(sb);
+
+    }
+
+
+    /**
+     * Append a string to the buffer
+     */
+    public void write(String s, int off, int len)
+        throws IOException {
+
+        if (suspended)
+            return;
+
+        state=CHAR_STATE;
+
+        charsWritten += len;
+        if (s==null)
+            s="null";
+        cb.append( s, off, len );
+
+    }
+
+
+    public void write(String s)
+        throws IOException {
+
+        if (suspended)
+            return;
+
+        state = CHAR_STATE;
+        if (s==null)
+            s="null";
+        write(s, 0, s.length());
+
+    } 
+
+
+    public void flushChars()
+        throws IOException {
+
+        cb.flushBuffer();
+        state = BYTE_STATE;
+
+    }
+
+
+    public boolean flushCharsNeeded() {
+        return state == CHAR_STATE;
+    }
+
+
+    public void setEncoding(String s) {
+        enc = s;
+    }
+
+
+    public void realWriteChars(char c[], int off, int len) 
+        throws IOException {
+
+        if (!gotEnc)
+            setConverter();
+
+        conv.convert(c, off, len);
+        conv.flushBuffer();	// ???
+
+    }
+
+
+    public void checkConverter() 
+        throws IOException {
+
+        if (!gotEnc)
+            setConverter();
+
+    }
+
+
+    protected void setConverter() 
+        throws IOException {
+
+        if (coyoteResponse != null)
+            enc = coyoteResponse.getCharacterEncoding();
+
+        gotEnc = true;
+        if (enc == null)
+            enc = DEFAULT_ENCODING;
+        conv = (C2BConverter) encoders.get(enc);
+        if (conv == null) {
+            
+            if (System.getSecurityManager() != null){
+                try{
+                    conv = (C2BConverter)AccessController.doPrivileged(
+                            new PrivilegedExceptionAction(){
+
+                                public Object run() throws IOException{
+                                    return new C2BConverter(bb, enc);
+                                }
+
+                            }
+                    );              
+                }catch(PrivilegedActionException ex){
+                    Exception e = ex.getException();
+                    if (e instanceof IOException)
+                        throw (IOException)e; 
+                }
+            } else {
+                conv = new C2BConverter(bb, enc);
+            }
+            
+            encoders.put(enc, conv);
+
+        }
+    }
+
+    
+    // --------------------  BufferedOutputStream compatibility
+
+
+    /**
+     * Real write - this buffer will be sent to the client
+     */
+    public void flushBytes()
+        throws IOException {
+
+        bb.flushBuffer();
+
+    }
+
+
+    public int getBytesWritten() {
+        return bytesWritten;
+    }
+
+
+    public int getCharsWritten() {
+        return charsWritten;
+    }
+
+
+    public int getContentWritten() {
+        return bytesWritten + charsWritten;
+    }
+
+
+    /** 
+     * True if this buffer hasn't been used ( since recycle() ) -
+     * i.e. no chars or bytes have been added to the buffer.  
+     */
+    public boolean isNew() {
+        return (bytesWritten == 0) && (charsWritten == 0);
+    }
+
+
+    public void setBufferSize(int size) {
+        if (size > bb.getLimit()) {// ??????
+	    bb.setLimit(size);
+	}
+    }
+
+
+    public void reset() {
+
+        //count=0;
+        bb.recycle();
+        bytesWritten = 0;
+        cb.recycle();
+        charsWritten = 0;
+        gotEnc = false;
+        enc = null;
+        state = INITIAL_STATE;
+    }
+
+
+    public int getBufferSize() {
+	return bb.getLimit();
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/connector/Request.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/connector/Request.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/connector/Request.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,2527 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.connector;
+
+
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.BufferedReader;
+import java.io.UnsupportedEncodingException;
+import java.security.Principal;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Locale;
+import java.util.Map;
+import java.util.TimeZone;
+import java.util.TreeMap;
+
+import javax.security.auth.Subject;
+import javax.servlet.FilterChain;
+import javax.servlet.RequestDispatcher;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletInputStream;
+import javax.servlet.ServletRequestAttributeEvent;
+import javax.servlet.ServletRequestAttributeListener;
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpSession;
+
+import org.apache.tomcat.util.buf.B2CConverter;
+import org.apache.tomcat.util.buf.MessageBytes;
+import org.apache.tomcat.util.buf.StringCache;
+import org.apache.tomcat.util.http.Cookies;
+import org.apache.tomcat.util.http.FastHttpDateFormat;
+import org.apache.tomcat.util.http.Parameters;
+import org.apache.tomcat.util.http.ServerCookie;
+import org.apache.tomcat.util.http.mapper.MappingData;
+
+import org.apache.coyote.ActionCode;
+
+import org.apache.catalina.Context;
+import org.apache.catalina.Globals;
+import org.apache.catalina.Host;
+import org.apache.catalina.Manager;
+import org.apache.catalina.Realm;
+import org.apache.catalina.Session;
+import org.apache.catalina.Wrapper;
+import org.apache.catalina.core.ApplicationFilterFactory;
+import org.apache.catalina.realm.GenericPrincipal;
+import org.apache.catalina.util.Enumerator;
+import org.apache.catalina.util.ParameterMap;
+import org.apache.catalina.util.RequestUtil;
+import org.apache.catalina.util.StringManager;
+import org.apache.catalina.util.StringParser;
+
+
+/**
+ * Wrapper object for the Coyote request.
+ *
+ * @author Remy Maucherat
+ * @author Craig R. McClanahan
+ * @version $Revision: 390187 $ $Date: 2006-03-30 11:40:57 -0600 (Thu, 30 Mar 2006) $
+ */
+
+public class Request
+    implements HttpServletRequest {
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    static {
+        // Ensure that classes are loaded for SM
+        new StringCache.ByteEntry();
+        new StringCache.CharEntry();
+    }
+
+    public Request() {
+
+        formats[0].setTimeZone(GMT_ZONE);
+        formats[1].setTimeZone(GMT_ZONE);
+        formats[2].setTimeZone(GMT_ZONE);
+
+    }
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * Coyote request.
+     */
+    protected org.apache.coyote.Request coyoteRequest;
+
+    /**
+     * Set the Coyote request.
+     * 
+     * @param coyoteRequest The Coyote request
+     */
+    public void setCoyoteRequest(org.apache.coyote.Request coyoteRequest) {
+        this.coyoteRequest = coyoteRequest;
+        inputBuffer.setRequest(coyoteRequest);
+    }
+
+    /**
+     * Get the Coyote request.
+     */
+    public org.apache.coyote.Request getCoyoteRequest() {
+        return (this.coyoteRequest);
+    }
+
+
+    // ----------------------------------------------------- Variables
+
+
+    protected static final TimeZone GMT_ZONE = TimeZone.getTimeZone("GMT");
+
+
+    /**
+     * The string manager for this package.
+     */
+    protected static StringManager sm =
+        StringManager.getManager(Constants.Package);
+
+
+    /**
+     * The set of cookies associated with this Request.
+     */
+    protected Cookie[] cookies = null;
+
+
+    /**
+     * The set of SimpleDateFormat formats to use in getDateHeader().
+     *
+     * Notice that because SimpleDateFormat is not thread-safe, we can't
+     * declare formats[] as a static variable.
+     */
+    protected SimpleDateFormat formats[] = {
+        new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US),
+        new SimpleDateFormat("EEEEEE, dd-MMM-yy HH:mm:ss zzz", Locale.US),
+        new SimpleDateFormat("EEE MMMM d HH:mm:ss yyyy", Locale.US)
+    };
+
+
+    /**
+     * The default Locale if none are specified.
+     */
+    protected static Locale defaultLocale = Locale.getDefault();
+
+
+    /**
+     * The attributes associated with this Request, keyed by attribute name.
+     */
+    protected HashMap attributes = new HashMap();
+
+
+    /**
+     * List of read only attributes for this Request.
+     */
+    private HashMap readOnlyAttributes = new HashMap();
+
+
+    /**
+     * The preferred Locales assocaited with this Request.
+     */
+    protected ArrayList locales = new ArrayList();
+
+
+    /**
+     * Internal notes associated with this request by Catalina components
+     * and event listeners.
+     */
+    private transient HashMap notes = new HashMap();
+
+
+    /**
+     * Authentication type.
+     */
+    protected String authType = null;
+
+
+    /**
+     * The current dispatcher type.
+     */
+    protected Object dispatcherType = null;
+
+
+    /**
+     * The associated input buffer.
+     */
+    protected InputBuffer inputBuffer = new InputBuffer();
+
+
+    /**
+     * ServletInputStream.
+     */
+    protected CoyoteInputStream inputStream = 
+        new CoyoteInputStream(inputBuffer);
+
+
+    /**
+     * Reader.
+     */
+    protected CoyoteReader reader = new CoyoteReader(inputBuffer);
+
+
+    /**
+     * Using stream flag.
+     */
+    protected boolean usingInputStream = false;
+
+
+    /**
+     * Using writer flag.
+     */
+    protected boolean usingReader = false;
+
+
+    /**
+     * User principal.
+     */
+    protected Principal userPrincipal = null;
+
+
+    /**
+     * Session parsed flag.
+     */
+    protected boolean sessionParsed = false;
+
+
+    /**
+     * Request parameters parsed flag.
+     */
+    protected boolean parametersParsed = false;
+
+
+    /**
+     * Cookies parsed flag.
+     */
+    protected boolean cookiesParsed = false;
+
+
+    /**
+     * Secure flag.
+     */
+    protected boolean secure = false;
+
+    
+    /**
+     * The Subject associated with the current AccessControllerContext
+     */
+    protected transient Subject subject = null;
+
+
+    /**
+     * Post data buffer.
+     */
+    protected static int CACHED_POST_LEN = 8192;
+    protected byte[] postData = null;
+
+
+    /**
+     * Hash map used in the getParametersMap method.
+     */
+    protected ParameterMap parameterMap = new ParameterMap();
+
+
+    /**
+     * The currently active session for this request.
+     */
+    protected Session session = null;
+
+
+    /**
+     * The current request dispatcher path.
+     */
+    protected Object requestDispatcherPath = null;
+
+
+    /**
+     * Was the requested session ID received in a cookie?
+     */
+    protected boolean requestedSessionCookie = false;
+
+
+    /**
+     * The requested session ID (if any) for this request.
+     */
+    protected String requestedSessionId = null;
+
+
+    /**
+     * Was the requested session ID received in a URL?
+     */
+    protected boolean requestedSessionURL = false;
+
+
+    /**
+     * Parse locales.
+     */
+    protected boolean localesParsed = false;
+
+
+    /**
+     * The string parser we will use for parsing request lines.
+     */
+    private StringParser parser = new StringParser();
+
+
+    /**
+     * Local port
+     */
+    protected int localPort = -1;
+
+    /**
+     * Remote address.
+     */
+    protected String remoteAddr = null;
+
+
+    /**
+     * Remote host.
+     */
+    protected String remoteHost = null;
+
+    
+    /**
+     * Remote port
+     */
+    protected int remotePort = -1;
+    
+    /**
+     * Local address
+     */
+    protected String localAddr = null;
+
+    
+    /**
+     * Local address
+     */
+    protected String localName = null;
+
+    // --------------------------------------------------------- Public Methods
+
+    /**
+     * Release all object references, and initialize instance variables, in
+     * preparation for reuse of this object.
+     */
+    public void recycle() {
+
+        context = null;
+        wrapper = null;
+
+        dispatcherType = null;
+        requestDispatcherPath = null;
+
+        authType = null;
+        inputBuffer.recycle();
+        usingInputStream = false;
+        usingReader = false;
+        userPrincipal = null;
+        subject = null;
+        sessionParsed = false;
+        parametersParsed = false;
+        cookiesParsed = false;
+        locales.clear();
+        localesParsed = false;
+        secure = false;
+        remoteAddr = null;
+        remoteHost = null;
+        remotePort = -1;
+        localPort = -1;
+        localAddr = null;
+        localName = null;
+
+        attributes.clear();
+        notes.clear();
+        cookies = null;
+
+        if (session != null) {
+            session.endAccess();
+        }
+        session = null;
+        requestedSessionCookie = false;
+        requestedSessionId = null;
+        requestedSessionURL = false;
+
+        parameterMap.setLocked(false);
+        parameterMap.clear();
+
+        mappingData.recycle();
+
+        if (Constants.SECURITY) {
+            if (facade != null) {
+                facade.clear();
+                facade = null;
+            }
+            if (inputStream != null) {
+                inputStream.clear();
+                inputStream = null;
+            }
+            if (reader != null) {
+                reader.clear();
+                reader = null;
+            }
+        }
+
+    }
+
+
+    // -------------------------------------------------------- Request Methods
+
+
+    /**
+     * Associated Catalina connector.
+     */
+    protected Connector connector;
+
+    /**
+     * Return the Connector through which this Request was received.
+     */
+    public Connector getConnector() {
+        return (this.connector);
+    }
+
+    /**
+     * Set the Connector through which this Request was received.
+     *
+     * @param connector The new connector
+     */
+    public void setConnector(Connector connector) {
+        this.connector = connector;
+    }
+
+
+    /**
+     * Associated context.
+     */
+    protected Context context = null;
+
+    /**
+     * Return the Context within which this Request is being processed.
+     */
+    public Context getContext() {
+        return (this.context);
+    }
+
+
+    /**
+     * Set the Context within which this Request is being processed.  This
+     * must be called as soon as the appropriate Context is identified, because
+     * it identifies the value to be returned by <code>getContextPath()</code>,
+     * and thus enables parsing of the request URI.
+     *
+     * @param context The newly associated Context
+     */
+    public void setContext(Context context) {
+        this.context = context;
+    }
+
+
+    /**
+     * Filter chain associated with the request.
+     */
+    protected FilterChain filterChain = null;
+
+    /**
+     * Get filter chain associated with the request.
+     */
+    public FilterChain getFilterChain() {
+        return (this.filterChain);
+    }
+
+    /**
+     * Set filter chain associated with the request.
+     * 
+     * @param filterChain new filter chain
+     */
+    public void setFilterChain(FilterChain filterChain) {
+        this.filterChain = filterChain;
+    }
+
+
+    /**
+     * Return the Host within which this Request is being processed.
+     */
+    public Host getHost() {
+        if (getContext() == null)
+            return null;
+        return (Host) getContext().getParent();
+        //return ((Host) mappingData.host);
+    }
+
+
+    /**
+     * Set the Host within which this Request is being processed.  This
+     * must be called as soon as the appropriate Host is identified, and
+     * before the Request is passed to a context.
+     *
+     * @param host The newly associated Host
+     */
+    public void setHost(Host host) {
+        mappingData.host = host;
+    }
+
+
+    /**
+     * Descriptive information about this Request implementation.
+     */
+    protected static final String info =
+        "org.apache.coyote.catalina.CoyoteRequest/1.0";
+
+    /**
+     * Return descriptive information about this Request implementation and
+     * the corresponding version number, in the format
+     * <code>&lt;description&gt;/&lt;version&gt;</code>.
+     */
+    public String getInfo() {
+        return (info);
+    }
+
+
+    /**
+     * Mapping data.
+     */
+    protected MappingData mappingData = new MappingData();
+
+    /**
+     * Return mapping data.
+     */
+    public MappingData getMappingData() {
+        return (mappingData);
+    }
+
+
+    /**
+     * The facade associated with this request.
+     */
+    protected RequestFacade facade = null;
+
+    /**
+     * Return the <code>ServletRequest</code> for which this object
+     * is the facade.  This method must be implemented by a subclass.
+     */
+    public HttpServletRequest getRequest() {
+        if (facade == null) {
+            facade = new RequestFacade(this);
+        } 
+        return (facade);
+    }
+
+
+    /**
+     * The response with which this request is associated.
+     */
+    protected org.apache.catalina.connector.Response response = null;
+
+    /**
+     * Return the Response with which this Request is associated.
+     */
+    public org.apache.catalina.connector.Response getResponse() {
+        return (this.response);
+    }
+
+    /**
+     * Set the Response with which this Request is associated.
+     *
+     * @param response The new associated response
+     */
+    public void setResponse(org.apache.catalina.connector.Response response) {
+        this.response = response;
+    }
+
+    /**
+     * Return the input stream associated with this Request.
+     */
+    public InputStream getStream() {
+        if (inputStream == null) {
+            inputStream = new CoyoteInputStream(inputBuffer);
+        }
+        return inputStream;
+    }
+
+    /**
+     * Set the input stream associated with this Request.
+     *
+     * @param stream The new input stream
+     */
+    public void setStream(InputStream stream) {
+        // Ignore
+    }
+
+
+    /**
+     * URI byte to char converter (not recycled).
+     */
+    protected B2CConverter URIConverter = null;
+
+    /**
+     * Return the URI converter.
+     */
+    protected B2CConverter getURIConverter() {
+        return URIConverter;
+    }
+
+    /**
+     * Set the URI converter.
+     * 
+     * @param URIConverter the new URI connverter
+     */
+    protected void setURIConverter(B2CConverter URIConverter) {
+        this.URIConverter = URIConverter;
+    }
+
+
+    /**
+     * Associated wrapper.
+     */
+    protected Wrapper wrapper = null;
+
+    /**
+     * Return the Wrapper within which this Request is being processed.
+     */
+    public Wrapper getWrapper() {
+        return (this.wrapper);
+    }
+
+
+    /**
+     * Set the Wrapper within which this Request is being processed.  This
+     * must be called as soon as the appropriate Wrapper is identified, and
+     * before the Request is ultimately passed to an application servlet.
+     * @param wrapper The newly associated Wrapper
+     */
+    public void setWrapper(Wrapper wrapper) {
+        this.wrapper = wrapper;
+    }
+
+
+    // ------------------------------------------------- Request Public Methods
+
+
+    /**
+     * Create and return a ServletInputStream to read the content
+     * associated with this Request.
+     *
+     * @exception IOException if an input/output error occurs
+     */
+    public ServletInputStream createInputStream() 
+        throws IOException {
+        if (inputStream == null) {
+            inputStream = new CoyoteInputStream(inputBuffer);
+        }
+        return inputStream;
+    }
+
+
+    /**
+     * Perform whatever actions are required to flush and close the input
+     * stream or reader, in a single operation.
+     *
+     * @exception IOException if an input/output error occurs
+     */
+    public void finishRequest() throws IOException {
+        // The reader and input stream don't need to be closed
+    }
+
+
+    /**
+     * Return the object bound with the specified name to the internal notes
+     * for this request, or <code>null</code> if no such binding exists.
+     *
+     * @param name Name of the note to be returned
+     */
+    public Object getNote(String name) {
+        return (notes.get(name));
+    }
+
+
+    /**
+     * Return an Iterator containing the String names of all notes bindings
+     * that exist for this request.
+     */
+    public Iterator getNoteNames() {
+        return (notes.keySet().iterator());
+    }
+
+
+    /**
+     * Remove any object bound to the specified name in the internal notes
+     * for this request.
+     *
+     * @param name Name of the note to be removed
+     */
+    public void removeNote(String name) {
+        notes.remove(name);
+    }
+
+
+    /**
+     * Bind an object to a specified name in the internal notes associated
+     * with this request, replacing any existing binding for this name.
+     *
+     * @param name Name to which the object should be bound
+     * @param value Object to be bound to the specified name
+     */
+    public void setNote(String name, Object value) {
+        notes.put(name, value);
+    }
+
+
+    /**
+     * Set the content length associated with this Request.
+     *
+     * @param length The new content length
+     */
+    public void setContentLength(int length) {
+        // Not used
+    }
+
+
+    /**
+     * Set the content type (and optionally the character encoding)
+     * associated with this Request.  For example,
+     * <code>text/html; charset=ISO-8859-4</code>.
+     *
+     * @param type The new content type
+     */
+    public void setContentType(String type) {
+        // Not used
+    }
+
+
+    /**
+     * Set the protocol name and version associated with this Request.
+     *
+     * @param protocol Protocol name and version
+     */
+    public void setProtocol(String protocol) {
+        // Not used
+    }
+
+
+    /**
+     * Set the IP address of the remote client associated with this Request.
+     *
+     * @param remoteAddr The remote IP address
+     */
+    public void setRemoteAddr(String remoteAddr) {
+        // Not used
+    }
+
+
+    /**
+     * Set the fully qualified name of the remote client associated with this
+     * Request.
+     *
+     * @param remoteHost The remote host name
+     */
+    public void setRemoteHost(String remoteHost) {
+        // Not used
+    }
+
+
+    /**
+     * Set the name of the scheme associated with this request.  Typical values
+     * are <code>http</code>, <code>https</code>, and <code>ftp</code>.
+     *
+     * @param scheme The scheme
+     */
+    public void setScheme(String scheme) {
+        // Not used
+    }
+
+
+    /**
+     * Set the value to be returned by <code>isSecure()</code>
+     * for this Request.
+     *
+     * @param secure The new isSecure value
+     */
+    public void setSecure(boolean secure) {
+        this.secure = secure;
+    }
+
+
+    /**
+     * Set the name of the server (virtual host) to process this request.
+     *
+     * @param name The server name
+     */
+    public void setServerName(String name) {
+        coyoteRequest.serverName().setString(name);
+    }
+
+
+    /**
+     * Set the port number of the server to process this request.
+     *
+     * @param port The server port
+     */
+    public void setServerPort(int port) {
+        coyoteRequest.setServerPort(port);
+    }
+
+
+    // ------------------------------------------------- ServletRequest Methods
+
+
+    /**
+     * Return the specified request attribute if it exists; otherwise, return
+     * <code>null</code>.
+     *
+     * @param name Name of the request attribute to return
+     */
+    public Object getAttribute(String name) {
+
+        if (name.equals(Globals.DISPATCHER_TYPE_ATTR)) {
+            return (dispatcherType == null) 
+                ? ApplicationFilterFactory.REQUEST_INTEGER
+                : dispatcherType;
+        } else if (name.equals(Globals.DISPATCHER_REQUEST_PATH_ATTR)) {
+            return (requestDispatcherPath == null) 
+                ? getRequestPathMB().toString()
+                : requestDispatcherPath.toString();
+        }
+
+        Object attr=attributes.get(name);
+
+        if(attr!=null)
+            return(attr);
+
+        attr =  coyoteRequest.getAttribute(name);
+        if(attr != null)
+            return attr;
+        if( isSSLAttribute(name) ) {
+            coyoteRequest.action(ActionCode.ACTION_REQ_SSL_ATTRIBUTE, 
+                                 coyoteRequest);
+            attr = coyoteRequest.getAttribute(Globals.CERTIFICATES_ATTR);
+            if( attr != null) {
+                attributes.put(Globals.CERTIFICATES_ATTR, attr);
+            }
+            attr = coyoteRequest.getAttribute(Globals.CIPHER_SUITE_ATTR);
+            if(attr != null) {
+                attributes.put(Globals.CIPHER_SUITE_ATTR, attr);
+            }
+            attr = coyoteRequest.getAttribute(Globals.KEY_SIZE_ATTR);
+            if(attr != null) {
+                attributes.put(Globals.KEY_SIZE_ATTR, attr);
+            }
+            attr = coyoteRequest.getAttribute(Globals.SSL_SESSION_ID_ATTR);
+            if(attr != null) {
+                attributes.put(Globals.SSL_SESSION_ID_ATTR, attr);
+            }
+            attr = attributes.get(name);
+        }
+        return attr;
+    }
+
+
+    /**
+     * Test if a given name is one of the special Servlet-spec SSL attributes.
+     */
+    static boolean isSSLAttribute(String name) {
+        return Globals.CERTIFICATES_ATTR.equals(name) ||
+            Globals.CIPHER_SUITE_ATTR.equals(name) ||
+            Globals.KEY_SIZE_ATTR.equals(name)  ||
+            Globals.SSL_SESSION_ID_ATTR.equals(name);
+    }
+
+    /**
+     * Return the names of all request attributes for this Request, or an
+     * empty <code>Enumeration</code> if there are none.
+     */
+    public Enumeration getAttributeNames() {
+        if (isSecure()) {
+            getAttribute(Globals.CERTIFICATES_ATTR);
+        }
+        return new Enumerator(attributes.keySet(), true);
+    }
+
+
+    /**
+     * Return the character encoding for this Request.
+     */
+    public String getCharacterEncoding() {
+      return (coyoteRequest.getCharacterEncoding());
+    }
+
+
+    /**
+     * Return the content length for this Request.
+     */
+    public int getContentLength() {
+        return (coyoteRequest.getContentLength());
+    }
+
+
+    /**
+     * Return the content type for this Request.
+     */
+    public String getContentType() {
+        return (coyoteRequest.getContentType());
+    }
+
+
+    /**
+     * Return the servlet input stream for this Request.  The default
+     * implementation returns a servlet input stream created by
+     * <code>createInputStream()</code>.
+     *
+     * @exception IllegalStateException if <code>getReader()</code> has
+     *  already been called for this request
+     * @exception IOException if an input/output error occurs
+     */
+    public ServletInputStream getInputStream() throws IOException {
+
+        if (usingReader)
+            throw new IllegalStateException
+                (sm.getString("coyoteRequest.getInputStream.ise"));
+
+        usingInputStream = true;
+        if (inputStream == null) {
+            inputStream = new CoyoteInputStream(inputBuffer);
+        }
+        return inputStream;
+
+    }
+
+
+    /**
+     * Return the preferred Locale that the client will accept content in,
+     * based on the value for the first <code>Accept-Language</code> header
+     * that was encountered.  If the request did not specify a preferred
+     * language, the server's default Locale is returned.
+     */
+    public Locale getLocale() {
+
+        if (!localesParsed)
+            parseLocales();
+
+        if (locales.size() > 0) {
+            return ((Locale) locales.get(0));
+        } else {
+            return (defaultLocale);
+        }
+
+    }
+
+
+    /**
+     * Return the set of preferred Locales that the client will accept
+     * content in, based on the values for any <code>Accept-Language</code>
+     * headers that were encountered.  If the request did not specify a
+     * preferred language, the server's default Locale is returned.
+     */
+    public Enumeration getLocales() {
+
+        if (!localesParsed)
+            parseLocales();
+
+        if (locales.size() > 0)
+            return (new Enumerator(locales));
+        ArrayList results = new ArrayList();
+        results.add(defaultLocale);
+        return (new Enumerator(results));
+
+    }
+
+
+    /**
+     * Return the value of the specified request parameter, if any; otherwise,
+     * return <code>null</code>.  If there is more than one value defined,
+     * return only the first one.
+     *
+     * @param name Name of the desired request parameter
+     */
+    public String getParameter(String name) {
+
+        if (!parametersParsed)
+            parseParameters();
+
+        return coyoteRequest.getParameters().getParameter(name);
+
+    }
+
+
+
+    /**
+     * Returns a <code>Map</code> of the parameters of this request.
+     * Request parameters are extra information sent with the request.
+     * For HTTP servlets, parameters are contained in the query string
+     * or posted form data.
+     *
+     * @return A <code>Map</code> containing parameter names as keys
+     *  and parameter values as map values.
+     */
+    public Map getParameterMap() {
+
+        if (parameterMap.isLocked())
+            return parameterMap;
+
+        Enumeration enumeration = getParameterNames();
+        while (enumeration.hasMoreElements()) {
+            String name = enumeration.nextElement().toString();
+            String[] values = getParameterValues(name);
+            parameterMap.put(name, values);
+        }
+
+        parameterMap.setLocked(true);
+
+        return parameterMap;
+
+    }
+
+
+    /**
+     * Return the names of all defined request parameters for this request.
+     */
+    public Enumeration getParameterNames() {
+
+        if (!parametersParsed)
+            parseParameters();
+
+        return coyoteRequest.getParameters().getParameterNames();
+
+    }
+
+
+    /**
+     * Return the defined values for the specified request parameter, if any;
+     * otherwise, return <code>null</code>.
+     *
+     * @param name Name of the desired request parameter
+     */
+    public String[] getParameterValues(String name) {
+
+        if (!parametersParsed)
+            parseParameters();
+
+        return coyoteRequest.getParameters().getParameterValues(name);
+
+    }
+
+
+    /**
+     * Return the protocol and version used to make this Request.
+     */
+    public String getProtocol() {
+        return coyoteRequest.protocol().toString();
+    }
+
+
+    /**
+     * Read the Reader wrapping the input stream for this Request.  The
+     * default implementation wraps a <code>BufferedReader</code> around the
+     * servlet input stream returned by <code>createInputStream()</code>.
+     *
+     * @exception IllegalStateException if <code>getInputStream()</code>
+     *  has already been called for this request
+     * @exception IOException if an input/output error occurs
+     */
+    public BufferedReader getReader() throws IOException {
+
+        if (usingInputStream)
+            throw new IllegalStateException
+                (sm.getString("coyoteRequest.getReader.ise"));
+
+        usingReader = true;
+        inputBuffer.checkConverter();
+        if (reader == null) {
+            reader = new CoyoteReader(inputBuffer);
+        }
+        return reader;
+
+    }
+
+
+    /**
+     * Return the real path of the specified virtual path.
+     *
+     * @param path Path to be translated
+     *
+     * @deprecated As of version 2.1 of the Java Servlet API, use
+     *  <code>ServletContext.getRealPath()</code>.
+     */
+    public String getRealPath(String path) {
+
+        if (context == null)
+            return (null);
+        ServletContext servletContext = context.getServletContext();
+        if (servletContext == null)
+            return (null);
+        else {
+            try {
+                return (servletContext.getRealPath(path));
+            } catch (IllegalArgumentException e) {
+                return (null);
+            }
+        }
+
+    }
+
+
+    /**
+     * Return the remote IP address making this Request.
+     */
+    public String getRemoteAddr() {
+        if (remoteAddr == null) {
+            coyoteRequest.action
+                (ActionCode.ACTION_REQ_HOST_ADDR_ATTRIBUTE, coyoteRequest);
+            remoteAddr = coyoteRequest.remoteAddr().toString();
+        }
+        return remoteAddr;
+    }
+
+
+    /**
+     * Return the remote host name making this Request.
+     */
+    public String getRemoteHost() {
+        if (remoteHost == null) {
+            if (!connector.getEnableLookups()) {
+                remoteHost = getRemoteAddr();
+            } else {
+                coyoteRequest.action
+                    (ActionCode.ACTION_REQ_HOST_ATTRIBUTE, coyoteRequest);
+                remoteHost = coyoteRequest.remoteHost().toString();
+            }
+        }
+        return remoteHost;
+    }
+
+    /**
+     * Returns the Internet Protocol (IP) source port of the client
+     * or last proxy that sent the request.
+     */    
+    public int getRemotePort(){
+        if (remotePort == -1) {
+            coyoteRequest.action
+                (ActionCode.ACTION_REQ_REMOTEPORT_ATTRIBUTE, coyoteRequest);
+            remotePort = coyoteRequest.getRemotePort();
+        }
+        return remotePort;    
+    }
+
+    /**
+     * Returns the host name of the Internet Protocol (IP) interface on
+     * which the request was received.
+     */
+    public String getLocalName(){
+        if (localName == null) {
+            coyoteRequest.action
+                (ActionCode.ACTION_REQ_LOCAL_NAME_ATTRIBUTE, coyoteRequest);
+            localName = coyoteRequest.localName().toString();
+        }
+        return localName;
+    }
+
+    /**
+     * Returns the Internet Protocol (IP) address of the interface on
+     * which the request  was received.
+     */       
+    public String getLocalAddr(){
+        if (localAddr == null) {
+            coyoteRequest.action
+                (ActionCode.ACTION_REQ_LOCAL_ADDR_ATTRIBUTE, coyoteRequest);
+            localAddr = coyoteRequest.localAddr().toString();
+        }
+        return localAddr;    
+    }
+
+
+    /**
+     * Returns the Internet Protocol (IP) port number of the interface
+     * on which the request was received.
+     */
+    public int getLocalPort(){
+        if (localPort == -1){
+            coyoteRequest.action
+                (ActionCode.ACTION_REQ_LOCALPORT_ATTRIBUTE, coyoteRequest);
+            localPort = coyoteRequest.getLocalPort();
+        }
+        return localPort;
+    }
+    
+    /**
+     * Return a RequestDispatcher that wraps the resource at the specified
+     * path, which may be interpreted as relative to the current request path.
+     *
+     * @param path Path of the resource to be wrapped
+     */
+    public RequestDispatcher getRequestDispatcher(String path) {
+
+        if (context == null)
+            return (null);
+
+        // If the path is already context-relative, just pass it through
+        if (path == null)
+            return (null);
+        else if (path.startsWith("/"))
+            return (context.getServletContext().getRequestDispatcher(path));
+
+        // Convert a request-relative path to a context-relative one
+        String servletPath = (String) getAttribute(Globals.INCLUDE_SERVLET_PATH_ATTR);
+        if (servletPath == null)
+            servletPath = getServletPath();
+
+        // Add the path info, if there is any
+        String pathInfo = getPathInfo();
+        String requestPath = null;
+
+        if (pathInfo == null) {
+            requestPath = servletPath;
+        } else {
+            requestPath = servletPath + pathInfo;
+        }
+
+        int pos = requestPath.lastIndexOf('/');
+        String relative = null;
+        if (pos >= 0) {
+            relative = RequestUtil.normalize
+                (requestPath.substring(0, pos + 1) + path);
+        } else {
+            relative = RequestUtil.normalize(requestPath + path);
+        }
+
+        return (context.getServletContext().getRequestDispatcher(relative));
+
+    }
+
+
+    /**
+     * Return the scheme used to make this Request.
+     */
+    public String getScheme() {
+        return (coyoteRequest.scheme().toString());
+    }
+
+
+    /**
+     * Return the server name responding to this Request.
+     */
+    public String getServerName() {
+        return (coyoteRequest.serverName().toString());
+    }
+
+
+    /**
+     * Return the server port responding to this Request.
+     */
+    public int getServerPort() {
+        return (coyoteRequest.getServerPort());
+    }
+
+
+    /**
+     * Was this request received on a secure connection?
+     */
+    public boolean isSecure() {
+        return (secure);
+    }
+
+
+    /**
+     * Remove the specified request attribute if it exists.
+     *
+     * @param name Name of the request attribute to remove
+     */
+    public void removeAttribute(String name) {
+        Object value = null;
+        boolean found = false;
+
+        // Remove the specified attribute
+        // Check for read only attribute
+        // requests are per thread so synchronization unnecessary
+        if (readOnlyAttributes.containsKey(name)) {
+            return;
+        }
+        found = attributes.containsKey(name);
+        if (found) {
+            value = attributes.get(name);
+            attributes.remove(name);
+        } else {
+            return;
+        }
+
+        // Notify interested application event listeners
+        Object listeners[] = context.getApplicationEventListeners();
+        if ((listeners == null) || (listeners.length == 0))
+            return;
+        ServletRequestAttributeEvent event =
+          new ServletRequestAttributeEvent(context.getServletContext(),
+                                           getRequest(), name, value);
+        for (int i = 0; i < listeners.length; i++) {
+            if (!(listeners[i] instanceof ServletRequestAttributeListener))
+                continue;
+            ServletRequestAttributeListener listener =
+                (ServletRequestAttributeListener) listeners[i];
+            try {
+                listener.attributeRemoved(event);
+            } catch (Throwable t) {
+                context.getLogger().error(sm.getString("coyoteRequest.attributeEvent"), t);
+                // Error valve will pick this execption up and display it to user
+                attributes.put( Globals.EXCEPTION_ATTR, t );
+            }
+        }
+    }
+
+
+    /**
+     * Set the specified request attribute to the specified value.
+     *
+     * @param name Name of the request attribute to set
+     * @param value The associated value
+     */
+    public void setAttribute(String name, Object value) {
+	
+        // Name cannot be null
+        if (name == null)
+            throw new IllegalArgumentException
+                (sm.getString("coyoteRequest.setAttribute.namenull"));
+
+        // Null value is the same as removeAttribute()
+        if (value == null) {
+            removeAttribute(name);
+            return;
+        }
+
+        if (name.equals(Globals.DISPATCHER_TYPE_ATTR)) {
+            dispatcherType = value;
+            return;
+        } else if (name.equals(Globals.DISPATCHER_REQUEST_PATH_ATTR)) {
+            requestDispatcherPath = value;
+            return;
+        }
+
+        Object oldValue = null;
+        boolean replaced = false;
+
+        // Add or replace the specified attribute
+        // Check for read only attribute
+        // requests are per thread so synchronization unnecessary
+        if (readOnlyAttributes.containsKey(name)) {
+            return;
+        }
+
+        oldValue = attributes.put(name, value);
+        if (oldValue != null) {
+            replaced = true;
+        }
+
+        // Pass special attributes to the native layer
+        if (name.startsWith("org.apache.tomcat.")) {
+            coyoteRequest.setAttribute(name, value);
+        }
+        
+        // Notify interested application event listeners
+        Object listeners[] = context.getApplicationEventListeners();
+        if ((listeners == null) || (listeners.length == 0))
+            return;
+        ServletRequestAttributeEvent event = null;
+        if (replaced)
+            event =
+                new ServletRequestAttributeEvent(context.getServletContext(),
+                                                 getRequest(), name, oldValue);
+        else
+            event =
+                new ServletRequestAttributeEvent(context.getServletContext(),
+                                                 getRequest(), name, value);
+
+        for (int i = 0; i < listeners.length; i++) {
+            if (!(listeners[i] instanceof ServletRequestAttributeListener))
+                continue;
+            ServletRequestAttributeListener listener =
+                (ServletRequestAttributeListener) listeners[i];
+            try {
+                if (replaced) {
+                    listener.attributeReplaced(event);
+                } else {
+                    listener.attributeAdded(event);
+                }
+            } catch (Throwable t) {
+                context.getLogger().error(sm.getString("coyoteRequest.attributeEvent"), t);
+                // Error valve will pick this execption up and display it to user
+                attributes.put( Globals.EXCEPTION_ATTR, t );
+            }
+        }
+    }
+
+
+    /**
+     * Overrides the name of the character encoding used in the body of
+     * this request.  This method must be called prior to reading request
+     * parameters or reading input using <code>getReader()</code>.
+     *
+     * @param enc The character encoding to be used
+     *
+     * @exception UnsupportedEncodingException if the specified encoding
+     *  is not supported
+     *
+     * @since Servlet 2.3
+     */
+    public void setCharacterEncoding(String enc)
+        throws UnsupportedEncodingException {
+
+        // Ensure that the specified encoding is valid
+        byte buffer[] = new byte[1];
+        buffer[0] = (byte) 'a';
+        String dummy = new String(buffer, enc);
+
+        // Save the validated encoding
+        coyoteRequest.setCharacterEncoding(enc);
+
+    }
+
+
+    // ---------------------------------------------------- HttpRequest Methods
+
+
+    /**
+     * Add a Cookie to the set of Cookies associated with this Request.
+     *
+     * @param cookie The new cookie
+     */
+    public void addCookie(Cookie cookie) {
+
+        if (!cookiesParsed)
+            parseCookies();
+
+        int size = 0;
+        if (cookies != null) {
+            size = cookies.length;
+        }
+
+        Cookie[] newCookies = new Cookie[size + 1];
+        for (int i = 0; i < size; i++) {
+            newCookies[i] = cookies[i];
+        }
+        newCookies[size] = cookie;
+
+        cookies = newCookies;
+
+    }
+
+
+    /**
+     * Add a Header to the set of Headers associated with this Request.
+     *
+     * @param name The new header name
+     * @param value The new header value
+     */
+    public void addHeader(String name, String value) {
+        // Not used
+    }
+
+
+    /**
+     * Add a Locale to the set of preferred Locales for this Request.  The
+     * first added Locale will be the first one returned by getLocales().
+     *
+     * @param locale The new preferred Locale
+     */
+    public void addLocale(Locale locale) {
+        locales.add(locale);
+    }
+
+
+    /**
+     * Add a parameter name and corresponding set of values to this Request.
+     * (This is used when restoring the original request on a form based
+     * login).
+     *
+     * @param name Name of this request parameter
+     * @param values Corresponding values for this request parameter
+     */
+    public void addParameter(String name, String values[]) {
+        coyoteRequest.getParameters().addParameterValues(name, values);
+    }
+
+
+    /**
+     * Clear the collection of Cookies associated with this Request.
+     */
+    public void clearCookies() {
+        cookiesParsed = true;
+        cookies = null;
+    }
+
+
+    /**
+     * Clear the collection of Headers associated with this Request.
+     */
+    public void clearHeaders() {
+        // Not used
+    }
+
+
+    /**
+     * Clear the collection of Locales associated with this Request.
+     */
+    public void clearLocales() {
+        locales.clear();
+    }
+
+
+    /**
+     * Clear the collection of parameters associated with this Request.
+     */
+    public void clearParameters() {
+        // Not used
+    }
+
+
+    /**
+     * Set the authentication type used for this request, if any; otherwise
+     * set the type to <code>null</code>.  Typical values are "BASIC",
+     * "DIGEST", or "SSL".
+     *
+     * @param type The authentication type used
+     */
+    public void setAuthType(String type) {
+        this.authType = type;
+    }
+
+
+    /**
+     * Set the context path for this Request.  This will normally be called
+     * when the associated Context is mapping the Request to a particular
+     * Wrapper.
+     *
+     * @param path The context path
+     */
+    public void setContextPath(String path) {
+
+        if (path == null) {
+            mappingData.contextPath.setString("");
+        } else {
+            mappingData.contextPath.setString(path);
+        }
+
+    }
+
+
+    /**
+     * Set the HTTP request method used for this Request.
+     *
+     * @param method The request method
+     */
+    public void setMethod(String method) {
+        // Not used
+    }
+
+
+    /**
+     * Set the query string for this Request.  This will normally be called
+     * by the HTTP Connector, when it parses the request headers.
+     *
+     * @param query The query string
+     */
+    public void setQueryString(String query) {
+        // Not used
+    }
+
+
+    /**
+     * Set the path information for this Request.  This will normally be called
+     * when the associated Context is mapping the Request to a particular
+     * Wrapper.
+     *
+     * @param path The path information
+     */
+    public void setPathInfo(String path) {
+        mappingData.pathInfo.setString(path);
+    }
+
+
+    /**
+     * Set a flag indicating whether or not the requested session ID for this
+     * request came in through a cookie.  This is normally called by the
+     * HTTP Connector, when it parses the request headers.
+     *
+     * @param flag The new flag
+     */
+    public void setRequestedSessionCookie(boolean flag) {
+
+        this.requestedSessionCookie = flag;
+
+    }
+
+
+    /**
+     * Set the requested session ID for this request.  This is normally called
+     * by the HTTP Connector, when it parses the request headers.
+     *
+     * @param id The new session id
+     */
+    public void setRequestedSessionId(String id) {
+
+        this.requestedSessionId = id;
+
+    }
+
+
+    /**
+     * Set a flag indicating whether or not the requested session ID for this
+     * request came in through a URL.  This is normally called by the
+     * HTTP Connector, when it parses the request headers.
+     *
+     * @param flag The new flag
+     */
+    public void setRequestedSessionURL(boolean flag) {
+
+        this.requestedSessionURL = flag;
+
+    }
+
+
+    /**
+     * Set the unparsed request URI for this Request.  This will normally be
+     * called by the HTTP Connector, when it parses the request headers.
+     *
+     * @param uri The request URI
+     */
+    public void setRequestURI(String uri) {
+        // Not used
+    }
+
+
+    /**
+     * Set the decoded request URI.
+     * 
+     * @param uri The decoded request URI
+     */
+    public void setDecodedRequestURI(String uri) {
+        // Not used
+    }
+
+
+    /**
+     * Get the decoded request URI.
+     * 
+     * @return the URL decoded request URI
+     */
+    public String getDecodedRequestURI() {
+        return (coyoteRequest.decodedURI().toString());
+    }
+
+
+    /**
+     * Get the decoded request URI.
+     * 
+     * @return the URL decoded request URI
+     */
+    public MessageBytes getDecodedRequestURIMB() {
+        return (coyoteRequest.decodedURI());
+    }
+
+
+    /**
+     * Set the servlet path for this Request.  This will normally be called
+     * when the associated Context is mapping the Request to a particular
+     * Wrapper.
+     *
+     * @param path The servlet path
+     */
+    public void setServletPath(String path) {
+        if (path != null)
+            mappingData.wrapperPath.setString(path);
+    }
+
+
+    /**
+     * Set the Principal who has been authenticated for this Request.  This
+     * value is also used to calculate the value to be returned by the
+     * <code>getRemoteUser()</code> method.
+     *
+     * @param principal The user Principal
+     */
+    public void setUserPrincipal(Principal principal) {
+
+        if (System.getSecurityManager() != null){
+            HttpSession session = getSession(false);
+            if ( (subject != null) && 
+                 (!subject.getPrincipals().contains(principal)) ){
+                subject.getPrincipals().add(principal);         
+            } else if (session != null &&
+                        session.getAttribute(Globals.SUBJECT_ATTR) == null) {
+                subject = new Subject();
+                subject.getPrincipals().add(principal);         
+            }
+            if (session != null){
+                session.setAttribute(Globals.SUBJECT_ATTR, subject);
+            }
+        } 
+
+        this.userPrincipal = principal;
+    }
+
+
+    // --------------------------------------------- HttpServletRequest Methods
+
+
+    /**
+     * Return the authentication type used for this Request.
+     */
+    public String getAuthType() {
+        return (authType);
+    }
+
+
+    /**
+     * Return the portion of the request URI used to select the Context
+     * of the Request.
+     */
+    public String getContextPath() {
+        return (mappingData.contextPath.toString());
+    }
+
+
+    /**
+     * Get the context path.
+     * 
+     * @return the context path
+     */
+    public MessageBytes getContextPathMB() {
+        return (mappingData.contextPath);
+    }
+
+
+    /**
+     * Return the set of Cookies received with this Request.
+     */
+    public Cookie[] getCookies() {
+
+        if (!cookiesParsed)
+            parseCookies();
+
+        return cookies;
+
+    }
+
+
+    /**
+     * Set the set of cookies recieved with this Request.
+     */
+    public void setCookies(Cookie[] cookies) {
+
+        this.cookies = cookies;
+
+    }
+
+
+    /**
+     * Return the value of the specified date header, if any; otherwise
+     * return -1.
+     *
+     * @param name Name of the requested date header
+     *
+     * @exception IllegalArgumentException if the specified header value
+     *  cannot be converted to a date
+     */
+    public long getDateHeader(String name) {
+
+        String value = getHeader(name);
+        if (value == null)
+            return (-1L);
+
+        // Attempt to convert the date header in a variety of formats
+        long result = FastHttpDateFormat.parseDate(value, formats);
+        if (result != (-1L)) {
+            return result;
+        }
+        throw new IllegalArgumentException(value);
+
+    }
+
+
+    /**
+     * Return the first value of the specified header, if any; otherwise,
+     * return <code>null</code>
+     *
+     * @param name Name of the requested header
+     */
+    public String getHeader(String name) {
+        return coyoteRequest.getHeader(name);
+    }
+
+
+    /**
+     * Return all of the values of the specified header, if any; otherwise,
+     * return an empty enumeration.
+     *
+     * @param name Name of the requested header
+     */
+    public Enumeration getHeaders(String name) {
+        return coyoteRequest.getMimeHeaders().values(name);
+    }
+
+
+    /**
+     * Return the names of all headers received with this request.
+     */
+    public Enumeration getHeaderNames() {
+        return coyoteRequest.getMimeHeaders().names();
+    }
+
+
+    /**
+     * Return the value of the specified header as an integer, or -1 if there
+     * is no such header for this request.
+     *
+     * @param name Name of the requested header
+     *
+     * @exception IllegalArgumentException if the specified header value
+     *  cannot be converted to an integer
+     */
+    public int getIntHeader(String name) {
+
+        String value = getHeader(name);
+        if (value == null) {
+            return (-1);
+        } else {
+            return (Integer.parseInt(value));
+        }
+
+    }
+
+
+    /**
+     * Return the HTTP request method used in this Request.
+     */
+    public String getMethod() {
+        return coyoteRequest.method().toString();
+    }
+
+
+    /**
+     * Return the path information associated with this Request.
+     */
+    public String getPathInfo() {
+        return (mappingData.pathInfo.toString());
+    }
+
+
+    /**
+     * Get the path info.
+     * 
+     * @return the path info
+     */
+    public MessageBytes getPathInfoMB() {
+        return (mappingData.pathInfo);
+    }
+
+
+    /**
+     * Return the extra path information for this request, translated
+     * to a real path.
+     */
+    public String getPathTranslated() {
+
+        if (context == null)
+            return (null);
+
+        if (getPathInfo() == null) {
+            return (null);
+        } else {
+            return (context.getServletContext().getRealPath(getPathInfo()));
+        }
+
+    }
+
+
+    /**
+     * Return the query string associated with this request.
+     */
+    public String getQueryString() {
+        String queryString = coyoteRequest.queryString().toString();
+        if (queryString == null || queryString.equals("")) {
+            return (null);
+        } else {
+            return queryString;
+        }
+    }
+
+
+    /**
+     * Return the name of the remote user that has been authenticated
+     * for this Request.
+     */
+    public String getRemoteUser() {
+
+        if (userPrincipal != null) {
+            return (userPrincipal.getName());
+        } else {
+            return (null);
+        }
+
+    }
+
+
+    /**
+     * Get the request path.
+     * 
+     * @return the request path
+     */
+    public MessageBytes getRequestPathMB() {
+        return (mappingData.requestPath);
+    }
+
+
+    /**
+     * Return the session identifier included in this request, if any.
+     */
+    public String getRequestedSessionId() {
+        return (requestedSessionId);
+    }
+
+
+    /**
+     * Return the request URI for this request.
+     */
+    public String getRequestURI() {
+        return coyoteRequest.requestURI().toString();
+    }
+
+
+    /**
+     * Reconstructs the URL the client used to make the request.
+     * The returned URL contains a protocol, server name, port
+     * number, and server path, but it does not include query
+     * string parameters.
+     * <p>
+     * Because this method returns a <code>StringBuffer</code>,
+     * not a <code>String</code>, you can modify the URL easily,
+     * for example, to append query parameters.
+     * <p>
+     * This method is useful for creating redirect messages and
+     * for reporting errors.
+     *
+     * @return A <code>StringBuffer</code> object containing the
+     *  reconstructed URL
+     */
+    public StringBuffer getRequestURL() {
+
+        StringBuffer url = new StringBuffer();
+        String scheme = getScheme();
+        int port = getServerPort();
+        if (port < 0)
+            port = 80; // Work around java.net.URL bug
+
+        url.append(scheme);
+        url.append("://");
+        url.append(getServerName());
+        if ((scheme.equals("http") && (port != 80))
+            || (scheme.equals("https") && (port != 443))) {
+            url.append(':');
+            url.append(port);
+        }
+        url.append(getRequestURI());
+
+        return (url);
+
+    }
+
+
+    /**
+     * Return the portion of the request URI used to select the servlet
+     * that will process this request.
+     */
+    public String getServletPath() {
+        return (mappingData.wrapperPath.toString());
+    }
+
+
+    /**
+     * Get the servlet path.
+     * 
+     * @return the servlet path
+     */
+    public MessageBytes getServletPathMB() {
+        return (mappingData.wrapperPath);
+    }
+
+
+    /**
+     * Return the session associated with this Request, creating one
+     * if necessary.
+     */
+    public HttpSession getSession() {
+        Session session = doGetSession(true);
+        if (session != null) {
+            return session.getSession();
+        } else {
+            return null;
+        }
+    }
+
+
+    /**
+     * Return the session associated with this Request, creating one
+     * if necessary and requested.
+     *
+     * @param create Create a new session if one does not exist
+     */
+    public HttpSession getSession(boolean create) {
+        Session session = doGetSession(create);
+        if (session != null) {
+            return session.getSession();
+        } else {
+            return null;
+        }
+    }
+
+
+    /**
+     * Return <code>true</code> if the session identifier included in this
+     * request came from a cookie.
+     */
+    public boolean isRequestedSessionIdFromCookie() {
+
+        if (requestedSessionId != null)
+            return (requestedSessionCookie);
+        else
+            return (false);
+
+    }
+
+
+    /**
+     * Return <code>true</code> if the session identifier included in this
+     * request came from the request URI.
+     */
+    public boolean isRequestedSessionIdFromURL() {
+
+        if (requestedSessionId != null)
+            return (requestedSessionURL);
+        else
+            return (false);
+
+    }
+
+
+    /**
+     * Return <code>true</code> if the session identifier included in this
+     * request came from the request URI.
+     *
+     * @deprecated As of Version 2.1 of the Java Servlet API, use
+     *  <code>isRequestedSessionIdFromURL()</code> instead.
+     */
+    public boolean isRequestedSessionIdFromUrl() {
+        return (isRequestedSessionIdFromURL());
+    }
+
+
+    /**
+     * Return <code>true</code> if the session identifier included in this
+     * request identifies a valid session.
+     */
+    public boolean isRequestedSessionIdValid() {
+
+        if (requestedSessionId == null)
+            return (false);
+        if (context == null)
+            return (false);
+        Manager manager = context.getManager();
+        if (manager == null)
+            return (false);
+        Session session = null;
+        try {
+            session = manager.findSession(requestedSessionId);
+        } catch (IOException e) {
+            session = null;
+        }
+        if ((session != null) && session.isValid())
+            return (true);
+        else
+            return (false);
+
+    }
+
+
+    /**
+     * Return <code>true</code> if the authenticated user principal
+     * possesses the specified role name.
+     *
+     * @param role Role name to be validated
+     */
+    public boolean isUserInRole(String role) {
+
+        // Have we got an authenticated principal at all?
+        if (userPrincipal == null)
+            return (false);
+
+        // Identify the Realm we will use for checking role assignmenets
+        if (context == null)
+            return (false);
+        Realm realm = context.getRealm();
+        if (realm == null)
+            return (false);
+
+        // Check for a role alias defined in a <security-role-ref> element
+        if (wrapper != null) {
+            String realRole = wrapper.findSecurityReference(role);
+            if ((realRole != null) &&
+                realm.hasRole(userPrincipal, realRole))
+                return (true);
+        }
+
+        // Check for a role defined directly as a <security-role>
+        return (realm.hasRole(userPrincipal, role));
+
+    }
+
+
+    /**
+     * Return the principal that has been authenticated for this Request.
+     */
+    public Principal getPrincipal() {
+        return (userPrincipal);
+    }
+
+
+    /**
+     * Return the principal that has been authenticated for this Request.
+     */
+    public Principal getUserPrincipal() {
+        if (userPrincipal instanceof GenericPrincipal) {
+            return ((GenericPrincipal) userPrincipal).getUserPrincipal();
+        } else {
+            return (userPrincipal);
+        }
+    }
+
+
+    /**
+     * Return the session associated with this Request, creating one
+     * if necessary.
+     */
+    public Session getSessionInternal() {
+        return doGetSession(true);
+    }
+
+
+    /**
+     * Return the session associated with this Request, creating one
+     * if necessary and requested.
+     *
+     * @param create Create a new session if one does not exist
+     */
+    public Session getSessionInternal(boolean create) {
+        return doGetSession(create);
+    }
+
+
+    // ------------------------------------------------------ Protected Methods
+
+
+    protected Session doGetSession(boolean create) {
+
+        // There cannot be a session if no context has been assigned yet
+        if (context == null)
+            return (null);
+
+        // Return the current session if it exists and is valid
+        if ((session != null) && !session.isValid())
+            session = null;
+        if (session != null)
+            return (session);
+
+        // Return the requested session if it exists and is valid
+        Manager manager = null;
+        if (context != null)
+            manager = context.getManager();
+        if (manager == null)
+            return (null);      // Sessions are not supported
+        if (requestedSessionId != null) {
+            try {
+                session = manager.findSession(requestedSessionId);
+            } catch (IOException e) {
+                session = null;
+            }
+            if ((session != null) && !session.isValid())
+                session = null;
+            if (session != null) {
+                session.access();
+                return (session);
+            }
+        }
+
+        // Create a new session if requested and the response is not committed
+        if (!create)
+            return (null);
+        if ((context != null) && (response != null) &&
+            context.getCookies() &&
+            response.getResponse().isCommitted()) {
+            throw new IllegalStateException
+              (sm.getString("coyoteRequest.sessionCreateCommitted"));
+        }
+
+        // Attempt to reuse session id if one was submitted in a cookie
+        // Do not reuse the session id if it is from a URL, to prevent possible
+        // phishing attacks
+        if (connector.getEmptySessionPath() 
+                && isRequestedSessionIdFromCookie()) {
+            session = manager.createSession(getRequestedSessionId());
+        } else {
+            session = manager.createSession(null);
+        }
+
+        // Creating a new session cookie based on that session
+        if ((session != null) && (getContext() != null)
+               && getContext().getCookies()) {
+            Cookie cookie = new Cookie(Globals.SESSION_COOKIE_NAME,
+                                       session.getIdInternal());
+            configureSessionCookie(cookie);
+            response.addCookie(cookie);
+        }
+
+        if (session != null) {
+            session.access();
+            return (session);
+        } else {
+            return (null);
+        }
+
+    }
+
+    /**
+     * Configures the given JSESSIONID cookie.
+     *
+     * @param cookie The JSESSIONID cookie to be configured
+     */
+    protected void configureSessionCookie(Cookie cookie) {
+        cookie.setMaxAge(-1);
+        String contextPath = null;
+        if (!connector.getEmptySessionPath() && (getContext() != null)) {
+            contextPath = getContext().getEncodedPath();
+        }
+        if ((contextPath != null) && (contextPath.length() > 0)) {
+            cookie.setPath(contextPath);
+        } else {
+            cookie.setPath("/");
+        }
+        if (isSecure()) {
+            cookie.setSecure(true);
+        }
+    }
+
+    /**
+     * Parse cookies.
+     */
+    protected void parseCookies() {
+
+        cookiesParsed = true;
+
+        Cookies serverCookies = coyoteRequest.getCookies();
+        int count = serverCookies.getCookieCount();
+        if (count <= 0)
+            return;
+
+        cookies = new Cookie[count];
+
+        int idx=0;
+        for (int i = 0; i < count; i++) {
+            ServerCookie scookie = serverCookies.getCookie(i);
+            try {
+                Cookie cookie = new Cookie(scookie.getName().toString(),
+                                           scookie.getValue().toString());
+                cookie.setPath(scookie.getPath().toString());
+                cookie.setVersion(scookie.getVersion());
+                String domain = scookie.getDomain().toString();
+                if (domain != null) {
+                    cookie.setDomain(scookie.getDomain().toString());
+                }
+                cookies[idx++] = cookie;
+            } catch(IllegalArgumentException e) {
+                // Ignore bad cookie
+            }
+        }
+        if( idx < count ) {
+            Cookie [] ncookies = new Cookie[idx];
+            System.arraycopy(cookies, 0, ncookies, 0, idx);
+            cookies = ncookies;
+        }
+
+    }
+
+    /**
+     * Parse request parameters.
+     */
+    protected void parseParameters() {
+
+        parametersParsed = true;
+
+        Parameters parameters = coyoteRequest.getParameters();
+
+        // getCharacterEncoding() may have been overridden to search for
+        // hidden form field containing request encoding
+        String enc = getCharacterEncoding();
+
+        boolean useBodyEncodingForURI = connector.getUseBodyEncodingForURI();
+        if (enc != null) {
+            parameters.setEncoding(enc);
+            if (useBodyEncodingForURI) {
+                parameters.setQueryStringEncoding(enc);
+            }
+        } else {
+            parameters.setEncoding
+                (org.apache.coyote.Constants.DEFAULT_CHARACTER_ENCODING);
+            if (useBodyEncodingForURI) {
+                parameters.setQueryStringEncoding
+                    (org.apache.coyote.Constants.DEFAULT_CHARACTER_ENCODING);
+            }
+        }
+
+        parameters.handleQueryParameters();
+
+        if (usingInputStream || usingReader)
+            return;
+
+        if (!getMethod().equalsIgnoreCase("POST"))
+            return;
+
+        String contentType = getContentType();
+        if (contentType == null)
+            contentType = "";
+        int semicolon = contentType.indexOf(';');
+        if (semicolon >= 0) {
+            contentType = contentType.substring(0, semicolon).trim();
+        } else {
+            contentType = contentType.trim();
+        }
+        if (!("application/x-www-form-urlencoded".equals(contentType)))
+            return;
+
+        int len = getContentLength();
+
+        if (len > 0) {
+            int maxPostSize = connector.getMaxPostSize();
+            if ((maxPostSize > 0) && (len > maxPostSize)) {
+                context.getLogger().info
+                    (sm.getString("coyoteRequest.postTooLarge"));
+                throw new IllegalStateException("Post too large");
+            }
+            try {
+                byte[] formData = null;
+                if (len < CACHED_POST_LEN) {
+                    if (postData == null)
+                        postData = new byte[CACHED_POST_LEN];
+                    formData = postData;
+                } else {
+                    formData = new byte[len];
+                }
+                int actualLen = readPostBody(formData, len);
+                if (actualLen == len) {
+                    parameters.processParameters(formData, 0, len);
+                }
+            } catch (Throwable t) {
+                ; // Ignore
+            }
+        }
+
+    }
+
+
+    /**
+     * Read post body in an array.
+     */
+    protected int readPostBody(byte body[], int len)
+        throws IOException {
+
+        int offset = 0;
+        do {
+            int inputLen = getStream().read(body, offset, len - offset);
+            if (inputLen <= 0) {
+                return offset;
+            }
+            offset += inputLen;
+        } while ((len - offset) > 0);
+        return len;
+
+    }
+
+
+    /**
+     * Parse request locales.
+     */
+    protected void parseLocales() {
+
+        localesParsed = true;
+
+        Enumeration values = getHeaders("accept-language");
+
+        while (values.hasMoreElements()) {
+            String value = values.nextElement().toString();
+            parseLocalesHeader(value);
+        }
+
+    }
+
+
+    /**
+     * Parse accept-language header value.
+     */
+    protected void parseLocalesHeader(String value) {
+
+        // Store the accumulated languages that have been requested in
+        // a local collection, sorted by the quality value (so we can
+        // add Locales in descending order).  The values will be ArrayLists
+        // containing the corresponding Locales to be added
+        TreeMap locales = new TreeMap();
+
+        // Preprocess the value to remove all whitespace
+        int white = value.indexOf(' ');
+        if (white < 0)
+            white = value.indexOf('\t');
+        if (white >= 0) {
+            StringBuffer sb = new StringBuffer();
+            int len = value.length();
+            for (int i = 0; i < len; i++) {
+                char ch = value.charAt(i);
+                if ((ch != ' ') && (ch != '\t'))
+                    sb.append(ch);
+            }
+            value = sb.toString();
+        }
+
+        // Process each comma-delimited language specification
+        parser.setString(value);        // ASSERT: parser is available to us
+        int length = parser.getLength();
+        while (true) {
+
+            // Extract the next comma-delimited entry
+            int start = parser.getIndex();
+            if (start >= length)
+                break;
+            int end = parser.findChar(',');
+            String entry = parser.extract(start, end).trim();
+            parser.advance();   // For the following entry
+
+            // Extract the quality factor for this entry
+            double quality = 1.0;
+            int semi = entry.indexOf(";q=");
+            if (semi >= 0) {
+                try {
+                    quality = Double.parseDouble(entry.substring(semi + 3));
+                } catch (NumberFormatException e) {
+                    quality = 0.0;
+                }
+                entry = entry.substring(0, semi);
+            }
+
+            // Skip entries we are not going to keep track of
+            if (quality < 0.00005)
+                continue;       // Zero (or effectively zero) quality factors
+            if ("*".equals(entry))
+                continue;       // FIXME - "*" entries are not handled
+
+            // Extract the language and country for this entry
+            String language = null;
+            String country = null;
+            String variant = null;
+            int dash = entry.indexOf('-');
+            if (dash < 0) {
+                language = entry;
+                country = "";
+                variant = "";
+            } else {
+                language = entry.substring(0, dash);
+                country = entry.substring(dash + 1);
+                int vDash = country.indexOf('-');
+                if (vDash > 0) {
+                    String cTemp = country.substring(0, vDash);
+                    variant = country.substring(vDash + 1);
+                    country = cTemp;
+                } else {
+                    variant = "";
+                }
+            }
+
+            // Add a new Locale to the list of Locales for this quality level
+            Locale locale = new Locale(language, country, variant);
+            Double key = new Double(-quality);  // Reverse the order
+            ArrayList values = (ArrayList) locales.get(key);
+            if (values == null) {
+                values = new ArrayList();
+                locales.put(key, values);
+            }
+            values.add(locale);
+
+        }
+
+        // Process the quality values in highest->lowest order (due to
+        // negating the Double value when creating the key)
+        Iterator keys = locales.keySet().iterator();
+        while (keys.hasNext()) {
+            Double key = (Double) keys.next();
+            ArrayList list = (ArrayList) locales.get(key);
+            Iterator values = list.iterator();
+            while (values.hasNext()) {
+                Locale locale = (Locale) values.next();
+                addLocale(locale);
+            }
+        }
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/connector/RequestFacade.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/connector/RequestFacade.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/connector/RequestFacade.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,933 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.connector;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.Enumeration;
+import java.util.Locale;
+import java.util.Map;
+
+import javax.servlet.RequestDispatcher;
+import javax.servlet.ServletInputStream;
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpSession;
+
+import org.apache.catalina.util.StringManager;
+
+
+import org.apache.catalina.security.SecurityUtil;
+
+/**
+ * Facade class that wraps a Coyote request object.  
+ * All methods are delegated to the wrapped request.
+ *
+ * @author Craig R. McClanahan
+ * @author Remy Maucherat
+ * @author Jean-Francois Arcand
+ * @version $Revision: 303900 $ $Date: 2005-04-29 17:22:29 -0500 (Fri, 29 Apr 2005) $
+ */
+
+public class RequestFacade implements HttpServletRequest {
+        
+        
+    // ----------------------------------------------------------- DoPrivileged
+    
+    private final class GetAttributePrivilegedAction
+            implements PrivilegedAction {
+        
+        public Object run() {
+            return request.getAttributeNames();
+        }            
+    }
+     
+    
+    private final class GetParameterMapPrivilegedAction
+            implements PrivilegedAction {
+        
+        public Object run() {
+            return request.getParameterMap();
+        }        
+    }    
+    
+    
+    private final class GetRequestDispatcherPrivilegedAction
+            implements PrivilegedAction {
+
+        private String path;
+
+        public GetRequestDispatcherPrivilegedAction(String path){
+            this.path = path;
+        }
+        
+        public Object run() {   
+            return request.getRequestDispatcher(path);
+        }           
+    }    
+    
+    
+    private final class GetParameterPrivilegedAction
+            implements PrivilegedAction {
+
+        public String name;
+
+        public GetParameterPrivilegedAction(String name){
+            this.name = name;
+        }
+
+        public Object run() {       
+            return request.getParameter(name);
+        }           
+    }    
+    
+     
+    private final class GetParameterNamesPrivilegedAction
+            implements PrivilegedAction {
+        
+        public Object run() {          
+            return request.getParameterNames();
+        }           
+    } 
+    
+    
+    private final class GetParameterValuePrivilegedAction
+            implements PrivilegedAction {
+
+        public String name;
+
+        public GetParameterValuePrivilegedAction(String name){
+            this.name = name;
+        }
+
+        public Object run() {       
+            return request.getParameterValues(name);
+        }           
+    }    
+  
+    
+    private final class GetCookiesPrivilegedAction
+            implements PrivilegedAction {
+        
+        public Object run() {       
+            return request.getCookies();
+        }           
+    }      
+    
+    
+    private final class GetCharacterEncodingPrivilegedAction
+            implements PrivilegedAction {
+        
+        public Object run() {       
+            return request.getCharacterEncoding();
+        }           
+    }   
+        
+    
+    private final class GetHeadersPrivilegedAction
+            implements PrivilegedAction {
+
+        private String name;
+
+        public GetHeadersPrivilegedAction(String name){
+            this.name = name;
+        }
+        
+        public Object run() {       
+            return request.getHeaders(name);
+        }           
+    }    
+        
+    
+    private final class GetHeaderNamesPrivilegedAction
+            implements PrivilegedAction {
+
+        public Object run() {       
+            return request.getHeaderNames();
+        }           
+    }  
+            
+    
+    private final class GetLocalePrivilegedAction
+            implements PrivilegedAction {
+
+        public Object run() {       
+            return request.getLocale();
+        }           
+    }    
+            
+    
+    private final class GetLocalesPrivilegedAction
+            implements PrivilegedAction {
+
+        public Object run() {       
+            return request.getLocales();
+        }           
+    }    
+    
+    private final class GetSessionPrivilegedAction
+            implements PrivilegedAction {
+
+        private boolean create;
+        
+        public GetSessionPrivilegedAction(boolean create){
+            this.create = create;
+        }
+                
+        public Object run() {  
+            return request.getSession(create);
+        }           
+    }
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Construct a wrapper for the specified request.
+     *
+     * @param request The request to be wrapped
+     */
+    public RequestFacade(Request request) {
+
+        this.request = request;
+
+    }
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The wrapped request.
+     */
+    protected Request request = null;
+
+
+    /**
+     * The string manager for this package.
+     */
+    protected static StringManager sm =
+        StringManager.getManager(Constants.Package);
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Clear facade.
+     */
+    public void clear() {
+        request = null;
+    }
+
+    
+    /**
+     * Prevent cloning the facade.
+     */
+    protected Object clone()
+        throws CloneNotSupportedException {
+        throw new CloneNotSupportedException();
+    }
+
+
+    // ------------------------------------------------- ServletRequest Methods
+
+
+    public Object getAttribute(String name) {
+
+        if (request == null) {
+            throw new IllegalStateException(
+                            sm.getString("requestFacade.nullRequest"));
+        }
+
+        return request.getAttribute(name);
+    }
+
+
+    public Enumeration getAttributeNames() {
+
+        if (request == null) {
+            throw new IllegalStateException(
+                            sm.getString("requestFacade.nullRequest"));
+        }
+
+        if (System.getSecurityManager() != null){
+            return (Enumeration)AccessController.doPrivileged(
+                new GetAttributePrivilegedAction());        
+        } else {
+            return request.getAttributeNames();
+        }
+    }
+
+
+    public String getCharacterEncoding() {
+
+        if (request == null) {
+            throw new IllegalStateException(
+                            sm.getString("requestFacade.nullRequest"));
+        }
+
+        if (System.getSecurityManager() != null){
+            return (String)AccessController.doPrivileged(
+                new GetCharacterEncodingPrivilegedAction());
+        } else {
+            return request.getCharacterEncoding();
+        }         
+    }
+
+
+    public void setCharacterEncoding(String env)
+            throws java.io.UnsupportedEncodingException {
+
+        if (request == null) {
+            throw new IllegalStateException(
+                            sm.getString("requestFacade.nullRequest"));
+        }
+
+        request.setCharacterEncoding(env);
+    }
+
+
+    public int getContentLength() {
+
+        if (request == null) {
+            throw new IllegalStateException(
+                            sm.getString("requestFacade.nullRequest"));
+        }
+
+        return request.getContentLength();
+    }
+
+
+    public String getContentType() {
+
+        if (request == null) {
+            throw new IllegalStateException(
+                            sm.getString("requestFacade.nullRequest"));
+        }
+
+        return request.getContentType();
+    }
+
+
+    public ServletInputStream getInputStream() throws IOException {
+
+        if (request == null) {
+            throw new IllegalStateException(
+                            sm.getString("requestFacade.nullRequest"));
+        }
+
+        return request.getInputStream();
+    }
+
+
+    public String getParameter(String name) {
+
+        if (request == null) {
+            throw new IllegalStateException(
+                            sm.getString("requestFacade.nullRequest"));
+        }
+
+        if (System.getSecurityManager() != null){
+            return (String)AccessController.doPrivileged(
+                new GetParameterPrivilegedAction(name));
+        } else {
+            return request.getParameter(name);
+        }
+    }
+
+
+    public Enumeration getParameterNames() {
+
+        if (request == null) {
+            throw new IllegalStateException(
+                            sm.getString("requestFacade.nullRequest"));
+        }
+
+        if (System.getSecurityManager() != null){
+            return (Enumeration)AccessController.doPrivileged(
+                new GetParameterNamesPrivilegedAction());
+        } else {
+            return request.getParameterNames();
+        }
+    }
+
+
+    public String[] getParameterValues(String name) {
+
+        if (request == null) {
+            throw new IllegalStateException(
+                            sm.getString("requestFacade.nullRequest"));
+        }
+
+        String[] ret = null;
+
+        /*
+         * Clone the returned array only if there is a security manager
+         * in place, so that performance won't suffer in the nonsecure case
+         */
+        if (SecurityUtil.isPackageProtectionEnabled()){
+            ret = (String[]) AccessController.doPrivileged(
+                new GetParameterValuePrivilegedAction(name));
+            if (ret != null) {
+                ret = (String[]) ret.clone();
+            }
+        } else {
+            ret = request.getParameterValues(name);
+        }
+
+        return ret;
+    }
+
+
+    public Map getParameterMap() {
+
+        if (request == null) {
+            throw new IllegalStateException(
+                            sm.getString("requestFacade.nullRequest"));
+        }
+
+        if (System.getSecurityManager() != null){
+            return (Map)AccessController.doPrivileged(
+                new GetParameterMapPrivilegedAction());        
+        } else {
+            return request.getParameterMap();
+        }
+    }
+
+
+    public String getProtocol() {
+
+        if (request == null) {
+            throw new IllegalStateException(
+                            sm.getString("requestFacade.nullRequest"));
+        }
+
+        return request.getProtocol();
+    }
+
+
+    public String getScheme() {
+
+        if (request == null) {
+            throw new IllegalStateException(
+                            sm.getString("requestFacade.nullRequest"));
+        }
+
+        return request.getScheme();
+    }
+
+
+    public String getServerName() {
+
+        if (request == null) {
+            throw new IllegalStateException(
+                            sm.getString("requestFacade.nullRequest"));
+        }
+
+        return request.getServerName();
+    }
+
+
+    public int getServerPort() {
+
+        if (request == null) {
+            throw new IllegalStateException(
+                            sm.getString("requestFacade.nullRequest"));
+        }
+
+        return request.getServerPort();
+    }
+
+
+    public BufferedReader getReader() throws IOException {
+
+        if (request == null) {
+            throw new IllegalStateException(
+                            sm.getString("requestFacade.nullRequest"));
+        }
+
+        return request.getReader();
+    }
+
+
+    public String getRemoteAddr() {
+
+        if (request == null) {
+            throw new IllegalStateException(
+                            sm.getString("requestFacade.nullRequest"));
+        }
+
+        return request.getRemoteAddr();
+    }
+
+
+    public String getRemoteHost() {
+
+        if (request == null) {
+            throw new IllegalStateException(
+                            sm.getString("requestFacade.nullRequest"));
+        }
+
+        return request.getRemoteHost();
+    }
+
+
+    public void setAttribute(String name, Object o) {
+
+        if (request == null) {
+            throw new IllegalStateException(
+                            sm.getString("requestFacade.nullRequest"));
+        }
+
+        request.setAttribute(name, o);
+    }
+
+
+    public void removeAttribute(String name) {
+
+        if (request == null) {
+            throw new IllegalStateException(
+                            sm.getString("requestFacade.nullRequest"));
+        }
+
+        request.removeAttribute(name);
+    }
+
+
+    public Locale getLocale() {
+
+        if (request == null) {
+            throw new IllegalStateException(
+                            sm.getString("requestFacade.nullRequest"));
+        }
+
+        if (System.getSecurityManager() != null){
+            return (Locale)AccessController.doPrivileged(
+                new GetLocalePrivilegedAction());
+        } else {
+            return request.getLocale();
+        }        
+    }
+
+
+    public Enumeration getLocales() {
+
+        if (request == null) {
+            throw new IllegalStateException(
+                            sm.getString("requestFacade.nullRequest"));
+        }
+
+        if (System.getSecurityManager() != null){
+            return (Enumeration)AccessController.doPrivileged(
+                new GetLocalesPrivilegedAction());
+        } else {
+            return request.getLocales();
+        }        
+    }
+
+
+    public boolean isSecure() {
+
+        if (request == null) {
+            throw new IllegalStateException(
+                            sm.getString("requestFacade.nullRequest"));
+        }
+
+        return request.isSecure();
+    }
+
+
+    public RequestDispatcher getRequestDispatcher(String path) {
+
+        if (request == null) {
+            throw new IllegalStateException(
+                            sm.getString("requestFacade.nullRequest"));
+        }
+
+        if (System.getSecurityManager() != null){
+            return (RequestDispatcher)AccessController.doPrivileged(
+                new GetRequestDispatcherPrivilegedAction(path));
+        } else {
+            return request.getRequestDispatcher(path);
+        }
+    }
+
+
+    public String getRealPath(String path) {
+
+        if (request == null) {
+            throw new IllegalStateException(
+                            sm.getString("requestFacade.nullRequest"));
+        }
+
+        return request.getRealPath(path);
+    }
+
+
+    public String getAuthType() {
+
+        if (request == null) {
+            throw new IllegalStateException(
+                            sm.getString("requestFacade.nullRequest"));
+        }
+
+        return request.getAuthType();
+    }
+
+
+    public Cookie[] getCookies() {
+
+        if (request == null) {
+            throw new IllegalStateException(
+                            sm.getString("requestFacade.nullRequest"));
+        }
+
+        Cookie[] ret = null;
+
+        /*
+         * Clone the returned array only if there is a security manager
+         * in place, so that performance won't suffer in the nonsecure case
+         */
+        if (SecurityUtil.isPackageProtectionEnabled()){
+            ret = (Cookie[])AccessController.doPrivileged(
+                new GetCookiesPrivilegedAction());
+            if (ret != null) {
+                ret = (Cookie[]) ret.clone();
+            }
+        } else {
+            ret = request.getCookies();
+        }
+
+        return ret;
+    }
+
+
+    public long getDateHeader(String name) {
+
+        if (request == null) {
+            throw new IllegalStateException(
+                            sm.getString("requestFacade.nullRequest"));
+        }
+
+        return request.getDateHeader(name);
+    }
+
+
+    public String getHeader(String name) {
+
+        if (request == null) {
+            throw new IllegalStateException(
+                            sm.getString("requestFacade.nullRequest"));
+        }
+
+        return request.getHeader(name);
+    }
+
+
+    public Enumeration getHeaders(String name) {
+
+        if (request == null) {
+            throw new IllegalStateException(
+                            sm.getString("requestFacade.nullRequest"));
+        }
+
+        if (System.getSecurityManager() != null){
+            return (Enumeration)AccessController.doPrivileged(
+                new GetHeadersPrivilegedAction(name));
+        } else {
+            return request.getHeaders(name);
+        }         
+    }
+
+
+    public Enumeration getHeaderNames() {
+
+        if (request == null) {
+            throw new IllegalStateException(
+                            sm.getString("requestFacade.nullRequest"));
+        }
+
+        if (System.getSecurityManager() != null){
+            return (Enumeration)AccessController.doPrivileged(
+                new GetHeaderNamesPrivilegedAction());
+        } else {
+            return request.getHeaderNames();
+        }             
+    }
+
+
+    public int getIntHeader(String name) {
+
+        if (request == null) {
+            throw new IllegalStateException(
+                            sm.getString("requestFacade.nullRequest"));
+        }
+
+        return request.getIntHeader(name);
+    }
+
+
+    public String getMethod() {
+
+        if (request == null) {
+            throw new IllegalStateException(
+                            sm.getString("requestFacade.nullRequest"));
+        }
+
+        return request.getMethod();
+    }
+
+
+    public String getPathInfo() {
+
+        if (request == null) {
+            throw new IllegalStateException(
+                            sm.getString("requestFacade.nullRequest"));
+        }
+
+        return request.getPathInfo();
+    }
+
+
+    public String getPathTranslated() {
+
+        if (request == null) {
+            throw new IllegalStateException(
+                            sm.getString("requestFacade.nullRequest"));
+        }
+
+        return request.getPathTranslated();
+    }
+
+
+    public String getContextPath() {
+
+        if (request == null) {
+            throw new IllegalStateException(
+                            sm.getString("requestFacade.nullRequest"));
+        }
+
+        return request.getContextPath();
+    }
+
+
+    public String getQueryString() {
+
+        if (request == null) {
+            throw new IllegalStateException(
+                            sm.getString("requestFacade.nullRequest"));
+        }
+
+        return request.getQueryString();
+    }
+
+
+    public String getRemoteUser() {
+
+        if (request == null) {
+            throw new IllegalStateException(
+                            sm.getString("requestFacade.nullRequest"));
+        }
+
+        return request.getRemoteUser();
+    }
+
+
+    public boolean isUserInRole(String role) {
+
+        if (request == null) {
+            throw new IllegalStateException(
+                            sm.getString("requestFacade.nullRequest"));
+        }
+
+        return request.isUserInRole(role);
+    }
+
+
+    public java.security.Principal getUserPrincipal() {
+
+        if (request == null) {
+            throw new IllegalStateException(
+                            sm.getString("requestFacade.nullRequest"));
+        }
+
+        return request.getUserPrincipal();
+    }
+
+
+    public String getRequestedSessionId() {
+
+        if (request == null) {
+            throw new IllegalStateException(
+                            sm.getString("requestFacade.nullRequest"));
+        }
+
+        return request.getRequestedSessionId();
+    }
+
+
+    public String getRequestURI() {
+
+        if (request == null) {
+            throw new IllegalStateException(
+                            sm.getString("requestFacade.nullRequest"));
+        }
+
+        return request.getRequestURI();
+    }
+
+
+    public StringBuffer getRequestURL() {
+
+        if (request == null) {
+            throw new IllegalStateException(
+                            sm.getString("requestFacade.nullRequest"));
+        }
+
+        return request.getRequestURL();
+    }
+
+
+    public String getServletPath() {
+
+        if (request == null) {
+            throw new IllegalStateException(
+                            sm.getString("requestFacade.nullRequest"));
+        }
+
+        return request.getServletPath();
+    }
+
+
+    public HttpSession getSession(boolean create) {
+
+        if (request == null) {
+            throw new IllegalStateException(
+                            sm.getString("requestFacade.nullRequest"));
+        }
+
+        if (SecurityUtil.isPackageProtectionEnabled()){
+            return (HttpSession)AccessController.
+                doPrivileged(new GetSessionPrivilegedAction(create));
+        } else {
+            return request.getSession(create);
+        }
+    }
+
+    public HttpSession getSession() {
+
+        if (request == null) {
+            throw new IllegalStateException(
+                            sm.getString("requestFacade.nullRequest"));
+        }
+
+        return getSession(true);
+    }
+
+
+    public boolean isRequestedSessionIdValid() {
+
+        if (request == null) {
+            throw new IllegalStateException(
+                            sm.getString("requestFacade.nullRequest"));
+        }
+
+        return request.isRequestedSessionIdValid();
+    }
+
+
+    public boolean isRequestedSessionIdFromCookie() {
+
+        if (request == null) {
+            throw new IllegalStateException(
+                            sm.getString("requestFacade.nullRequest"));
+        }
+
+        return request.isRequestedSessionIdFromCookie();
+    }
+
+
+    public boolean isRequestedSessionIdFromURL() {
+
+        if (request == null) {
+            throw new IllegalStateException(
+                            sm.getString("requestFacade.nullRequest"));
+        }
+
+        return request.isRequestedSessionIdFromURL();
+    }
+
+
+    public boolean isRequestedSessionIdFromUrl() {
+
+        if (request == null) {
+            throw new IllegalStateException(
+                            sm.getString("requestFacade.nullRequest"));
+        }
+
+        return request.isRequestedSessionIdFromURL();
+    }
+
+
+    public String getLocalAddr() {
+
+        if (request == null) {
+            throw new IllegalStateException(
+                            sm.getString("requestFacade.nullRequest"));
+        }
+
+        return request.getLocalAddr();
+    }
+
+
+    public String getLocalName() {
+
+        if (request == null) {
+            throw new IllegalStateException(
+                            sm.getString("requestFacade.nullRequest"));
+        }
+
+        return request.getLocalName();
+    }
+
+
+    public int getLocalPort() {
+
+        if (request == null) {
+            throw new IllegalStateException(
+                            sm.getString("requestFacade.nullRequest"));
+        }
+
+        return request.getLocalPort();
+    }
+
+
+    public int getRemotePort() {
+
+        if (request == null) {
+            throw new IllegalStateException(
+                            sm.getString("requestFacade.nullRequest"));
+        }
+
+        return request.getRemotePort();
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/connector/Response.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/connector/Response.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/connector/Response.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,1563 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.connector;
+
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.PrintWriter;
+import java.net.MalformedURLException;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.Locale;
+import java.util.TimeZone;
+import java.util.Vector;
+
+import javax.servlet.ServletOutputStream;
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.catalina.Context;
+import org.apache.catalina.Session;
+import org.apache.catalina.Wrapper;
+import org.apache.catalina.util.CharsetMapper;
+import org.apache.catalina.util.DateTool;
+import org.apache.catalina.util.StringManager;
+import org.apache.catalina.security.SecurityUtil;
+import org.apache.tomcat.util.buf.CharChunk;
+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.net.URL;
+import org.apache.tomcat.util.compat.JdkCompat;
+
+/**
+ * Wrapper object for the Coyote response.
+ *
+ * @author Remy Maucherat
+ * @author Craig R. McClanahan
+ * @version $Revision: 371866 $ $Date: 2006-01-24 02:52:54 -0600 (Tue, 24 Jan 2006) $
+ */
+
+public class Response
+    implements HttpServletResponse {
+
+
+    // ----------------------------------------------------------- Constructors
+
+    static {
+        // Ensure that URL is loaded for SM
+        URL.isSchemeChar('c');
+    }
+
+    public Response() {
+        urlEncoder.addSafeCharacter('/');
+    }
+
+
+    // ----------------------------------------------------- Class Variables
+
+
+    /**
+     * JDK compatibility support
+     */
+    private static final JdkCompat jdkCompat = JdkCompat.getJdkCompat();
+
+
+    /**
+     * Descriptive information about this Response implementation.
+     */
+    protected static final String info =
+        "org.apache.coyote.tomcat5.CoyoteResponse/1.0";
+
+
+    /**
+     * The string manager for this package.
+     */
+    protected static StringManager sm =
+        StringManager.getManager(Constants.Package);
+
+
+    // ----------------------------------------------------- Instance Variables
+
+    /**
+     * The date format we will use for creating date headers.
+     */
+    protected SimpleDateFormat format = null;
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * Associated Catalina connector.
+     */
+    protected Connector connector;
+
+    /**
+     * Return the Connector through which this Request was received.
+     */
+    public Connector getConnector() {
+        return (this.connector);
+    }
+
+    /**
+     * Set the Connector through which this Request was received.
+     *
+     * @param connector The new connector
+     */
+    public void setConnector(Connector connector) {
+        this.connector = connector;
+        if("AJP/1.3".equals(connector.getProtocol())) {
+            // default size to size of one ajp-packet
+            outputBuffer = new OutputBuffer(8184);
+        } else {
+            outputBuffer = new OutputBuffer();
+        }
+        outputStream = new CoyoteOutputStream(outputBuffer);
+        writer = new CoyoteWriter(outputBuffer);
+    }
+
+
+    /**
+     * Coyote response.
+     */
+    protected org.apache.coyote.Response coyoteResponse;
+
+    /**
+     * Set the Coyote response.
+     * 
+     * @param coyoteResponse The Coyote response
+     */
+    public void setCoyoteResponse(org.apache.coyote.Response coyoteResponse) {
+        this.coyoteResponse = coyoteResponse;
+        outputBuffer.setResponse(coyoteResponse);
+    }
+
+    /**
+     * Get the Coyote response.
+     */
+    public org.apache.coyote.Response getCoyoteResponse() {
+        return (coyoteResponse);
+    }
+
+
+    /**
+     * Return the Context within which this Request is being processed.
+     */
+    public Context getContext() {
+        return (request.getContext());
+    }
+
+    /**
+     * Set the Context within which this Request is being processed.  This
+     * must be called as soon as the appropriate Context is identified, because
+     * it identifies the value to be returned by <code>getContextPath()</code>,
+     * and thus enables parsing of the request URI.
+     *
+     * @param context The newly associated Context
+     */
+    public void setContext(Context context) {
+        request.setContext(context);
+    }
+
+
+    /**
+     * The associated output buffer.
+     */
+    protected OutputBuffer outputBuffer;
+
+
+    /**
+     * The associated output stream.
+     */
+    protected CoyoteOutputStream outputStream;
+
+
+    /**
+     * The associated writer.
+     */
+    protected CoyoteWriter writer;
+
+
+    /**
+     * The application commit flag.
+     */
+    protected boolean appCommitted = false;
+
+
+    /**
+     * The included flag.
+     */
+    protected boolean included = false;
+
+    
+    /**
+     * The characterEncoding flag
+     */
+    private boolean isCharacterEncodingSet = false;
+    
+    /**
+     * The error flag.
+     */
+    protected boolean error = false;
+
+
+    /**
+     * The set of Cookies associated with this Response.
+     */
+    protected ArrayList cookies = new ArrayList();
+
+
+    /**
+     * Using output stream flag.
+     */
+    protected boolean usingOutputStream = false;
+
+
+    /**
+     * Using writer flag.
+     */
+    protected boolean usingWriter = false;
+
+
+    /**
+     * URL encoder.
+     */
+    protected UEncoder urlEncoder = new UEncoder();
+
+
+    /**
+     * Recyclable buffer to hold the redirect URL.
+     */
+    protected CharChunk redirectURLCC = new CharChunk();
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Release all object references, and initialize instance variables, in
+     * preparation for reuse of this object.
+     */
+    public void recycle() {
+
+        outputBuffer.recycle();
+        usingOutputStream = false;
+        usingWriter = false;
+        appCommitted = false;
+        included = false;
+        error = false;
+        isCharacterEncodingSet = false;
+        
+        cookies.clear();
+
+        if (Constants.SECURITY) {
+            if (facade != null) {
+                facade.clear();
+                facade = null;
+            }
+            if (outputStream != null) {
+                outputStream.clear();
+                outputStream = null;
+            }
+            if (writer != null) {
+                writer.clear();
+                writer = null;
+            }
+        } else {
+            writer.recycle();
+        }
+
+    }
+
+
+    // ------------------------------------------------------- Response Methods
+
+
+    /**
+     * Return the number of bytes actually written to the output stream.
+     */
+    public int getContentCount() {
+        return outputBuffer.getContentWritten();
+    }
+
+
+    /**
+     * Set the application commit flag.
+     * 
+     * @param appCommitted The new application committed flag value
+     */
+    public void setAppCommitted(boolean appCommitted) {
+        this.appCommitted = appCommitted;
+    }
+
+
+    /**
+     * Application commit flag accessor.
+     */
+    public boolean isAppCommitted() {
+        return (this.appCommitted || isCommitted() || isSuspended()
+                || ((getContentLength() > 0) 
+                    && (getContentCount() >= getContentLength())));
+    }
+
+
+    /**
+     * Return the "processing inside an include" flag.
+     */
+    public boolean getIncluded() {
+        return included;
+    }
+
+
+    /**
+     * Set the "processing inside an include" flag.
+     *
+     * @param included <code>true</code> if we are currently inside a
+     *  RequestDispatcher.include(), else <code>false</code>
+     */
+    public void setIncluded(boolean included) {
+        this.included = included;
+    }
+
+
+    /**
+     * Return descriptive information about this Response implementation and
+     * the corresponding version number, in the format
+     * <code>&lt;description&gt;/&lt;version&gt;</code>.
+     */
+    public String getInfo() {
+        return (info);
+    }
+
+
+    /**
+     * The request with which this response is associated.
+     */
+    protected Request request = null;
+
+    /**
+     * Return the Request with which this Response is associated.
+     */
+    public org.apache.catalina.connector.Request getRequest() {
+        return (this.request);
+    }
+
+    /**
+     * Set the Request with which this Response is associated.
+     *
+     * @param request The new associated request
+     */
+    public void setRequest(org.apache.catalina.connector.Request request) {
+        this.request = (Request) request;
+    }
+
+
+    /**
+     * The facade associated with this response.
+     */
+    protected ResponseFacade facade = null;
+
+    /**
+     * Return the <code>ServletResponse</code> for which this object
+     * is the facade.
+     */
+    public HttpServletResponse getResponse() {
+        if (facade == null) {
+            facade = new ResponseFacade(this);
+        }
+        return (facade);
+    }
+
+
+    /**
+     * Return the output stream associated with this Response.
+     */
+    public OutputStream getStream() {
+        if (outputStream == null) {
+            outputStream = new CoyoteOutputStream(outputBuffer);
+        }
+        return outputStream;
+    }
+
+
+    /**
+     * Set the output stream associated with this Response.
+     *
+     * @param stream The new output stream
+     */
+    public void setStream(OutputStream stream) {
+        // This method is evil
+    }
+
+
+    /**
+     * Set the suspended flag.
+     * 
+     * @param suspended The new suspended flag value
+     */
+    public void setSuspended(boolean suspended) {
+        outputBuffer.setSuspended(suspended);
+    }
+
+
+    /**
+     * Suspended flag accessor.
+     */
+    public boolean isSuspended() {
+        return outputBuffer.isSuspended();
+    }
+
+
+    /**
+     * Set the error flag.
+     */
+    public void setError() {
+        error = true;
+    }
+
+
+    /**
+     * Error flag accessor.
+     */
+    public boolean isError() {
+        return error;
+    }
+
+
+    /**
+     * Create and return a ServletOutputStream to write the content
+     * associated with this Response.
+     *
+     * @exception IOException if an input/output error occurs
+     */
+    public ServletOutputStream createOutputStream() 
+        throws IOException {
+        // Probably useless
+        if (outputStream == null) {
+            outputStream = new CoyoteOutputStream(outputBuffer);
+        }
+        return outputStream;
+    }
+
+
+    /**
+     * Perform whatever actions are required to flush and close the output
+     * stream or writer, in a single operation.
+     *
+     * @exception IOException if an input/output error occurs
+     */
+    public void finishResponse() 
+        throws IOException {
+        // Writing leftover bytes
+        try {
+            outputBuffer.close();
+        } catch(IOException e) {
+	    ;
+        } catch(Throwable t) {
+	    t.printStackTrace();
+        }
+    }
+
+
+    /**
+     * Return the content length that was set or calculated for this Response.
+     */
+    public int getContentLength() {
+        return (coyoteResponse.getContentLength());
+    }
+
+
+    /**
+     * Return the content type that was set or calculated for this response,
+     * or <code>null</code> if no content type was set.
+     */
+    public String getContentType() {
+        return (coyoteResponse.getContentType());
+    }
+
+
+    /**
+     * Return a PrintWriter that can be used to render error messages,
+     * regardless of whether a stream or writer has already been acquired.
+     *
+     * @return Writer which can be used for error reports. If the response is
+     * not an error report returned using sendError or triggered by an
+     * unexpected exception thrown during the servlet processing
+     * (and only in that case), null will be returned if the response stream
+     * has already been used.
+     *
+     * @exception IOException if an input/output error occurs
+     */
+    public PrintWriter getReporter() throws IOException {
+        if (outputBuffer.isNew()) {
+            outputBuffer.checkConverter();
+            if (writer == null) {
+                writer = new CoyoteWriter(outputBuffer);
+            }
+            return writer;
+        } else {
+            return null;
+        }
+    }
+
+
+    // ------------------------------------------------ ServletResponse Methods
+
+
+    /**
+     * Flush the buffer and commit this response.
+     *
+     * @exception IOException if an input/output error occurs
+     */
+    public void flushBuffer() 
+        throws IOException {
+        outputBuffer.flush();
+    }
+
+
+    /**
+     * Return the actual buffer size used for this Response.
+     */
+    public int getBufferSize() {
+        return outputBuffer.getBufferSize();
+    }
+
+
+    /**
+     * Return the character encoding used for this Response.
+     */
+    public String getCharacterEncoding() {
+        return (coyoteResponse.getCharacterEncoding());
+    }
+
+
+    /**
+     * Return the servlet output stream associated with this Response.
+     *
+     * @exception IllegalStateException if <code>getWriter</code> has
+     *  already been called for this response
+     * @exception IOException if an input/output error occurs
+     */
+    public ServletOutputStream getOutputStream() 
+        throws IOException {
+
+        if (usingWriter)
+            throw new IllegalStateException
+                (sm.getString("coyoteResponse.getOutputStream.ise"));
+
+        usingOutputStream = true;
+        if (outputStream == null) {
+            outputStream = new CoyoteOutputStream(outputBuffer);
+        }
+        return outputStream;
+
+    }
+
+
+    /**
+     * Return the Locale assigned to this response.
+     */
+    public Locale getLocale() {
+        return (coyoteResponse.getLocale());
+    }
+
+
+    /**
+     * Return the writer associated with this Response.
+     *
+     * @exception IllegalStateException if <code>getOutputStream</code> has
+     *  already been called for this response
+     * @exception IOException if an input/output error occurs
+     */
+    public PrintWriter getWriter() 
+        throws IOException {
+
+        if (usingOutputStream)
+            throw new IllegalStateException
+                (sm.getString("coyoteResponse.getWriter.ise"));
+
+        /*
+         * If the response's character encoding has not been specified as
+         * described in <code>getCharacterEncoding</code> (i.e., the method
+         * just returns the default value <code>ISO-8859-1</code>),
+         * <code>getWriter</code> updates it to <code>ISO-8859-1</code>
+         * (with the effect that a subsequent call to getContentType() will
+         * include a charset=ISO-8859-1 component which will also be
+         * reflected in the Content-Type response header, thereby satisfying
+         * the Servlet spec requirement that containers must communicate the
+         * character encoding used for the servlet response's writer to the
+         * client).
+         */
+        setCharacterEncoding(getCharacterEncoding());
+
+        usingWriter = true;
+        outputBuffer.checkConverter();
+        if (writer == null) {
+            writer = new CoyoteWriter(outputBuffer);
+        }
+        return writer;
+
+    }
+
+
+    /**
+     * Has the output of this response already been committed?
+     */
+    public boolean isCommitted() {
+        return (coyoteResponse.isCommitted());
+    }
+
+
+    /**
+     * Clear any content written to the buffer.
+     *
+     * @exception IllegalStateException if this response has already
+     *  been committed
+     */
+    public void reset() {
+
+        if (included)
+            return;     // Ignore any call from an included servlet
+
+        coyoteResponse.reset();
+        outputBuffer.reset();
+    }
+
+
+    /**
+     * Reset the data buffer but not any status or header information.
+     *
+     * @exception IllegalStateException if the response has already
+     *  been committed
+     */
+    public void resetBuffer() {
+
+        if (isCommitted())
+            throw new IllegalStateException
+                (sm.getString("coyoteResponse.resetBuffer.ise"));
+
+        outputBuffer.reset();
+
+    }
+
+
+    /**
+     * Set the buffer size to be used for this Response.
+     *
+     * @param size The new buffer size
+     *
+     * @exception IllegalStateException if this method is called after
+     *  output has been committed for this response
+     */
+    public void setBufferSize(int size) {
+
+        if (isCommitted() || !outputBuffer.isNew())
+            throw new IllegalStateException
+                (sm.getString("coyoteResponse.setBufferSize.ise"));
+
+        outputBuffer.setBufferSize(size);
+
+    }
+
+
+    /**
+     * Set the content length (in bytes) for this Response.
+     *
+     * @param length The new content length
+     */
+    public void setContentLength(int length) {
+
+        if (isCommitted())
+            return;
+
+        // Ignore any call from an included servlet
+        if (included)
+            return;
+        
+        if (usingWriter)
+            return;
+        
+        coyoteResponse.setContentLength(length);
+
+    }
+
+
+    /**
+     * Set the content type for this Response.
+     *
+     * @param type The new content type
+     */
+    public void setContentType(String type) {
+
+        if (isCommitted())
+            return;
+
+        // Ignore any call from an included servlet
+        if (included)
+            return;
+
+        // Ignore charset if getWriter() has already been called
+        if (usingWriter) {
+            if (type != null) {
+                int index = type.indexOf(";");
+                if (index != -1) {
+                    type = type.substring(0, index);
+                }
+            }
+        }
+
+        coyoteResponse.setContentType(type);
+
+        // Check to see if content type contains charset
+        if (type != null) {
+            int index = type.indexOf(";");
+            if (index != -1) {
+                int len = type.length();
+                index++;
+                while (index < len && Character.isSpace(type.charAt(index))) {
+                    index++;
+                }
+                if (index+7 < len
+                        && type.charAt(index) == 'c'
+                        && type.charAt(index+1) == 'h'
+                        && type.charAt(index+2) == 'a'
+                        && type.charAt(index+3) == 'r'
+                        && type.charAt(index+4) == 's'
+                        && type.charAt(index+5) == 'e'
+                        && type.charAt(index+6) == 't'
+                        && type.charAt(index+7) == '=') {
+                    isCharacterEncodingSet = true;
+                }
+            }
+        }
+    }
+
+
+    /*
+     * Overrides the name of the character encoding used in the body
+     * of the request. This method must be called prior to reading
+     * request parameters or reading input using getReader().
+     *
+     * @param charset String containing the name of the chararacter encoding.
+     */
+    public void setCharacterEncoding(String charset) {
+
+        if (isCommitted())
+            return;
+        
+        // Ignore any call from an included servlet
+        if (included)
+            return;     
+        
+        // Ignore any call made after the getWriter has been invoked
+        // The default should be used
+        if (usingWriter)
+            return;
+
+        coyoteResponse.setCharacterEncoding(charset);
+        isCharacterEncodingSet = true;
+    }
+
+    
+    
+    /**
+     * Set the Locale that is appropriate for this response, including
+     * setting the appropriate character encoding.
+     *
+     * @param locale The new locale
+     */
+    public void setLocale(Locale locale) {
+
+        if (isCommitted())
+            return;
+
+        // Ignore any call from an included servlet
+        if (included)
+            return;
+
+        coyoteResponse.setLocale(locale);
+
+        // Ignore any call made after the getWriter has been invoked.
+        // The default should be used
+        if (usingWriter)
+            return;
+
+        if (isCharacterEncodingSet) {
+            return;
+        }
+
+        CharsetMapper cm = getContext().getCharsetMapper();
+        String charset = cm.getCharset( locale );
+        if ( charset != null ){
+            coyoteResponse.setCharacterEncoding(charset);
+        }
+
+    }
+
+
+    // --------------------------------------------------- HttpResponse Methods
+
+
+    /**
+     * Return an array of all cookies set for this response, or
+     * a zero-length array if no cookies have been set.
+     */
+    public Cookie[] getCookies() {
+        return ((Cookie[]) cookies.toArray(new Cookie[cookies.size()]));
+    }
+
+
+    /**
+     * 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 getHeaderValues() to retrieve all
+     * of them.
+     *
+     * @param name Header name to look up
+     */
+    public String getHeader(String name) {
+        return coyoteResponse.getMimeHeaders().getHeader(name);
+    }
+
+
+    /**
+     * Return an array of all the header names set for this response, or
+     * a zero-length array if no headers have been set.
+     */
+    public String[] getHeaderNames() {
+
+        MimeHeaders headers = coyoteResponse.getMimeHeaders();
+        int n = headers.size();
+        String[] result = new String[n];
+        for (int i = 0; i < n; i++) {
+            result[i] = headers.getName(i).toString();
+        }
+        return result;
+
+    }
+
+
+    /**
+     * Return an array of all the header values associated with the
+     * specified header name, or an zero-length array if there are no such
+     * header values.
+     *
+     * @param name Header name to look up
+     */
+    public String[] getHeaderValues(String name) {
+
+        Enumeration enumeration = coyoteResponse.getMimeHeaders().values(name);
+        Vector result = new Vector();
+        while (enumeration.hasMoreElements()) {
+            result.addElement(enumeration.nextElement());
+        }
+        String[] resultArray = new String[result.size()];
+        result.copyInto(resultArray);
+        return resultArray;
+
+    }
+
+
+    /**
+     * Return the error message that was set with <code>sendError()</code>
+     * for this Response.
+     */
+    public String getMessage() {
+        return coyoteResponse.getMessage();
+    }
+
+
+    /**
+     * Return the HTTP status code associated with this Response.
+     */
+    public int getStatus() {
+        return coyoteResponse.getStatus();
+    }
+
+
+    /**
+     * Reset this response, and specify the values for the HTTP status code
+     * and corresponding message.
+     *
+     * @exception IllegalStateException if this response has already been
+     *  committed
+     */
+    public void reset(int status, String message) {
+        reset();
+        setStatus(status, message);
+    }
+
+
+    // -------------------------------------------- HttpServletResponse Methods
+
+
+    /**
+     * Add the specified Cookie to those that will be included with
+     * this Response.
+     *
+     * @param cookie Cookie to be added
+     */
+    public void addCookie(final Cookie cookie) {
+
+        if (isCommitted())
+            return;
+
+        // Ignore any call from an included servlet
+        if (included)
+            return;
+
+        cookies.add(cookie);
+
+        final StringBuffer sb = new StringBuffer();
+        if (SecurityUtil.isPackageProtectionEnabled()) {
+            AccessController.doPrivileged(new PrivilegedAction() {
+                public Object run(){
+                    ServerCookie.appendCookieValue
+                        (sb, cookie.getVersion(), cookie.getName(), 
+                         cookie.getValue(), cookie.getPath(), 
+                         cookie.getDomain(), cookie.getComment(), 
+                         cookie.getMaxAge(), cookie.getSecure());
+                    return null;
+                }
+            });
+        } else {
+            ServerCookie.appendCookieValue
+                (sb, cookie.getVersion(), cookie.getName(), cookie.getValue(),
+                     cookie.getPath(), cookie.getDomain(), cookie.getComment(), 
+                     cookie.getMaxAge(), cookie.getSecure());
+        }
+
+        // the header name is Set-Cookie for both "old" and v.1 ( RFC2109 )
+        // RFC2965 is not supported by browsers and the Servlet spec
+        // asks for 2109.
+        addHeader("Set-Cookie", sb.toString());
+
+    }
+
+
+    /**
+     * Add the specified date header to the specified value.
+     *
+     * @param name Name of the header to set
+     * @param value Date value to be set
+     */
+    public void addDateHeader(String name, long value) {
+
+        if (isCommitted())
+            return;
+
+        // Ignore any call from an included servlet
+        if (included) {
+            return;
+        }
+
+        if (format == null) {
+            format = new SimpleDateFormat(DateTool.HTTP_RESPONSE_DATE_HEADER,
+                                          Locale.US);
+            format.setTimeZone(TimeZone.getTimeZone("GMT"));
+        }
+
+        addHeader(name, FastHttpDateFormat.formatDate(value, format));
+
+    }
+
+
+    /**
+     * Add the specified header to the specified value.
+     *
+     * @param name Name of the header to set
+     * @param value Value to be set
+     */
+    public void addHeader(String name, String value) {
+
+        if (isCommitted())
+            return;
+
+        // Ignore any call from an included servlet
+        if (included)
+            return;
+
+        coyoteResponse.addHeader(name, value);
+
+    }
+
+
+    /**
+     * Add the specified integer header to the specified value.
+     *
+     * @param name Name of the header to set
+     * @param value Integer value to be set
+     */
+    public void addIntHeader(String name, int value) {
+
+        if (isCommitted())
+            return;
+
+        // Ignore any call from an included servlet
+        if (included)
+            return;
+
+        addHeader(name, "" + value);
+
+    }
+
+
+    /**
+     * Has the specified header been set already in this response?
+     *
+     * @param name Name of the header to check
+     */
+    public boolean containsHeader(String name) {
+        // Need special handling for Content-Type and Content-Length due to
+        // special handling of these in coyoteResponse
+        char cc=name.charAt(0);
+        if(cc=='C' || cc=='c') {
+            if(name.equalsIgnoreCase("Content-Type")) {
+                // Will return null if this has not been set
+                return (coyoteResponse.getContentType() != null);
+            }
+            if(name.equalsIgnoreCase("Content-Length")) {
+                // -1 means not known and is not sent to client
+                return (coyoteResponse.getContentLengthLong() != -1);
+            }
+        }
+
+        return coyoteResponse.containsHeader(name);
+    }
+
+
+    /**
+     * Encode the session identifier associated with this response
+     * into the specified redirect URL, if necessary.
+     *
+     * @param url URL to be encoded
+     */
+    public String encodeRedirectURL(String url) {
+
+        if (isEncodeable(toAbsolute(url))) {
+            return (toEncoded(url, request.getSessionInternal().getIdInternal()));
+        } else {
+            return (url);
+        }
+
+    }
+
+
+    /**
+     * Encode the session identifier associated with this response
+     * into the specified redirect URL, if necessary.
+     *
+     * @param url URL to be encoded
+     *
+     * @deprecated As of Version 2.1 of the Java Servlet API, use
+     *  <code>encodeRedirectURL()</code> instead.
+     */
+    public String encodeRedirectUrl(String url) {
+        return (encodeRedirectURL(url));
+    }
+
+
+    /**
+     * Encode the session identifier associated with this response
+     * into the specified URL, if necessary.
+     *
+     * @param url URL to be encoded
+     */
+    public String encodeURL(String url) {
+        
+        String absolute = toAbsolute(url);
+        if (isEncodeable(absolute)) {
+            // W3c spec clearly said 
+            if (url.equalsIgnoreCase("")){
+                url = absolute;
+            }
+            return (toEncoded(url, request.getSessionInternal().getIdInternal()));
+        } else {
+            return (url);
+        }
+
+    }
+
+
+    /**
+     * Encode the session identifier associated with this response
+     * into the specified URL, if necessary.
+     *
+     * @param url URL to be encoded
+     *
+     * @deprecated As of Version 2.1 of the Java Servlet API, use
+     *  <code>encodeURL()</code> instead.
+     */
+    public String encodeUrl(String url) {
+        return (encodeURL(url));
+    }
+
+
+    /**
+     * Send an acknowledgment of a request.
+     * 
+     * @exception IOException if an input/output error occurs
+     */
+    public void sendAcknowledgement()
+        throws IOException {
+
+        if (isCommitted())
+            return;
+
+        // Ignore any call from an included servlet
+        if (included)
+            return; 
+
+        coyoteResponse.acknowledge();
+
+    }
+
+
+    /**
+     * Send an error response with the specified status and a
+     * default message.
+     *
+     * @param status HTTP status code to send
+     *
+     * @exception IllegalStateException if this response has
+     *  already been committed
+     * @exception IOException if an input/output error occurs
+     */
+    public void sendError(int status) 
+        throws IOException {
+        sendError(status, null);
+    }
+
+
+    /**
+     * Send an error response with the specified status and message.
+     *
+     * @param status HTTP status code to send
+     * @param message Corresponding message to send
+     *
+     * @exception IllegalStateException if this response has
+     *  already been committed
+     * @exception IOException if an input/output error occurs
+     */
+    public void sendError(int status, String message) 
+        throws IOException {
+
+        if (isCommitted())
+            throw new IllegalStateException
+                (sm.getString("coyoteResponse.sendError.ise"));
+
+        // Ignore any call from an included servlet
+        if (included)
+            return; 
+
+        Wrapper wrapper = getRequest().getWrapper();
+        if (wrapper != null) {
+            wrapper.incrementErrorCount();
+        } 
+
+        setError();
+
+        coyoteResponse.setStatus(status);
+        coyoteResponse.setMessage(message);
+
+        // Clear any data content that has been buffered
+        resetBuffer();
+
+        // Cause the response to be finished (from the application perspective)
+        setSuspended(true);
+
+    }
+
+
+    /**
+     * Send a temporary redirect to the specified redirect location URL.
+     *
+     * @param location Location URL to redirect to
+     *
+     * @exception IllegalStateException if this response has
+     *  already been committed
+     * @exception IOException if an input/output error occurs
+     */
+    public void sendRedirect(String location) 
+        throws IOException {
+
+        if (isCommitted())
+            throw new IllegalStateException
+                (sm.getString("coyoteResponse.sendRedirect.ise"));
+
+        // Ignore any call from an included servlet
+        if (included)
+            return; 
+
+        // Clear any data content that has been buffered
+        resetBuffer();
+
+        // Generate a temporary redirect to the specified location
+        try {
+            String absolute = toAbsolute(location);
+            setStatus(SC_FOUND);
+            setHeader("Location", absolute);
+        } catch (IllegalArgumentException e) {
+            setStatus(SC_NOT_FOUND);
+        }
+
+        // Cause the response to be finished (from the application perspective)
+        setSuspended(true);
+
+    }
+
+
+    /**
+     * Set the specified date header to the specified value.
+     *
+     * @param name Name of the header to set
+     * @param value Date value to be set
+     */
+    public void setDateHeader(String name, long value) {
+
+        if (isCommitted())
+            return;
+
+        // Ignore any call from an included servlet
+        if (included) {
+            return;
+        }
+
+        if (format == null) {
+            format = new SimpleDateFormat(DateTool.HTTP_RESPONSE_DATE_HEADER,
+                                          Locale.US);
+            format.setTimeZone(TimeZone.getTimeZone("GMT"));
+        }
+
+        setHeader(name, FastHttpDateFormat.formatDate(value, format));
+
+    }
+
+
+    /**
+     * Set the specified header to the specified value.
+     *
+     * @param name Name of the header to set
+     * @param value Value to be set
+     */
+    public void setHeader(String name, String value) {
+
+        if (isCommitted())
+            return;
+
+        // Ignore any call from an included servlet
+        if (included)
+            return;
+
+        coyoteResponse.setHeader(name, value);
+
+    }
+
+
+    /**
+     * Set the specified integer header to the specified value.
+     *
+     * @param name Name of the header to set
+     * @param value Integer value to be set
+     */
+    public void setIntHeader(String name, int value) {
+
+        if (isCommitted())
+            return;
+
+        // Ignore any call from an included servlet
+        if (included)
+            return;
+
+        setHeader(name, "" + value);
+
+    }
+
+
+    /**
+     * Set the HTTP status to be returned with this response.
+     *
+     * @param status The new HTTP status
+     */
+    public void setStatus(int status) {
+        setStatus(status, null);
+    }
+
+
+    /**
+     * Set the HTTP status and message to be returned with this response.
+     *
+     * @param status The new HTTP status
+     * @param message The associated text message
+     *
+     * @deprecated As of Version 2.1 of the Java Servlet API, this method
+     *  has been deprecated due to the ambiguous meaning of the message
+     *  parameter.
+     */
+    public void setStatus(int status, String message) {
+
+        if (isCommitted())
+            return;
+
+        // Ignore any call from an included servlet
+        if (included)
+            return;
+
+        coyoteResponse.setStatus(status);
+        coyoteResponse.setMessage(message);
+
+    }
+
+
+    // ------------------------------------------------------ Protected Methods
+
+
+    /**
+     * Return <code>true</code> if the specified URL should be encoded with
+     * a session identifier.  This will be true if all of the following
+     * conditions are met:
+     * <ul>
+     * <li>The request we are responding to asked for a valid session
+     * <li>The requested session ID was not received via a cookie
+     * <li>The specified URL points back to somewhere within the web
+     *     application that is responding to this request
+     * </ul>
+     *
+     * @param location Absolute URL to be validated
+     */
+    protected boolean isEncodeable(final String location) {
+
+        if (location == null)
+            return (false);
+
+        // Is this an intra-document reference?
+        if (location.startsWith("#"))
+            return (false);
+
+        // Are we in a valid session that is not using cookies?
+        final Request hreq = request;
+        final Session session = hreq.getSessionInternal(false);
+        if (session == null)
+            return (false);
+        if (hreq.isRequestedSessionIdFromCookie())
+            return (false);
+        
+        if (SecurityUtil.isPackageProtectionEnabled()) {
+            return ((Boolean)
+                AccessController.doPrivileged(new PrivilegedAction() {
+
+                public Object run(){
+                    return new Boolean(doIsEncodeable(hreq, session, location));
+                }
+            })).booleanValue();
+        } else {
+            return doIsEncodeable(hreq, session, location);
+        }
+    }
+
+    private boolean doIsEncodeable(Request hreq, Session session, 
+                                   String location) {
+        // Is this a valid absolute URL?
+        URL url = null;
+        try {
+            url = new URL(location);
+        } catch (MalformedURLException e) {
+            return (false);
+        }
+
+        // Does this URL match down to (and including) the context path?
+        if (!hreq.getScheme().equalsIgnoreCase(url.getProtocol()))
+            return (false);
+        if (!hreq.getServerName().equalsIgnoreCase(url.getHost()))
+            return (false);
+        int serverPort = hreq.getServerPort();
+        if (serverPort == -1) {
+            if ("https".equals(hreq.getScheme()))
+                serverPort = 443;
+            else
+                serverPort = 80;
+        }
+        int urlPort = url.getPort();
+        if (urlPort == -1) {
+            if ("https".equals(url.getProtocol()))
+                urlPort = 443;
+            else
+                urlPort = 80;
+        }
+        if (serverPort != urlPort)
+            return (false);
+
+        String contextPath = getContext().getPath();
+        if (contextPath != null) {
+            String file = url.getFile();
+            if ((file == null) || !file.startsWith(contextPath))
+                return (false);
+            if( file.indexOf(";jsessionid=" + session.getIdInternal()) >= 0 )
+                return (false);
+        }
+
+        // This URL belongs to our web application, so it is encodeable
+        return (true);
+
+    }
+
+
+    /**
+     * Convert (if necessary) and return the absolute URL that represents the
+     * resource referenced by this possibly relative URL.  If this URL is
+     * already absolute, return it unchanged.
+     *
+     * @param location URL to be (possibly) converted and then returned
+     *
+     * @exception IllegalArgumentException if a MalformedURLException is
+     *  thrown when converting the relative URL to an absolute one
+     */
+    private String toAbsolute(String location) {
+
+        if (location == null)
+            return (location);
+
+        boolean leadingSlash = location.startsWith("/");
+
+        if (leadingSlash || !hasScheme(location)) {
+
+            redirectURLCC.recycle();
+
+            String scheme = request.getScheme();
+            String name = request.getServerName();
+            int port = request.getServerPort();
+
+            try {
+                redirectURLCC.append(scheme, 0, scheme.length());
+                redirectURLCC.append("://", 0, 3);
+                redirectURLCC.append(name, 0, name.length());
+                if ((scheme.equals("http") && port != 80)
+                    || (scheme.equals("https") && port != 443)) {
+                    redirectURLCC.append(':');
+                    String portS = port + "";
+                    redirectURLCC.append(portS, 0, portS.length());
+                }
+                if (!leadingSlash) {
+                    String relativePath = request.getDecodedRequestURI();
+                    int pos = relativePath.lastIndexOf('/');
+                    relativePath = relativePath.substring(0, pos);
+                    
+                    String encodedURI = null;
+                    final String frelativePath = relativePath;
+                    if (SecurityUtil.isPackageProtectionEnabled() ){
+                        try{
+                            encodedURI = (String)AccessController.doPrivileged( 
+                                new PrivilegedExceptionAction(){                                
+                                    public Object run() throws IOException{
+                                        return urlEncoder.encodeURL(frelativePath);
+                                    }
+                           });   
+                        } catch (PrivilegedActionException pae){
+                            IllegalArgumentException iae =
+                                new IllegalArgumentException(location);
+                            jdkCompat.chainException(iae, pae.getException());
+                            throw iae;
+                        }
+                    } else {
+                        encodedURI = urlEncoder.encodeURL(relativePath);
+                    }
+                    redirectURLCC.append(encodedURI, 0, encodedURI.length());
+                    redirectURLCC.append('/');
+                }
+                redirectURLCC.append(location, 0, location.length());
+            } catch (IOException e) {
+                IllegalArgumentException iae =
+                    new IllegalArgumentException(location);
+                jdkCompat.chainException(iae, e);
+                throw iae;
+            }
+
+            return redirectURLCC.toString();
+
+        } else {
+
+            return (location);
+
+        }
+
+    }
+
+
+    /**
+     * Determine if a URI string has a <code>scheme</code> component.
+     */
+    private boolean hasScheme(String uri) {
+        int len = uri.length();
+        for(int i=0; i < len ; i++) {
+            char c = uri.charAt(i);
+            if(c == ':') {
+                return i > 0;
+            } else if(!URL.isSchemeChar(c)) {
+                return false;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Return the specified URL with the specified session identifier
+     * suitably encoded.
+     *
+     * @param url URL to be encoded with the session id
+     * @param sessionId Session id to be included in the encoded URL
+     */
+    protected String toEncoded(String url, String sessionId) {
+
+        if ((url == null) || (sessionId == null))
+            return (url);
+
+        String path = url;
+        String query = "";
+        String anchor = "";
+        int question = url.indexOf('?');
+        if (question >= 0) {
+            path = url.substring(0, question);
+            query = url.substring(question);
+        }
+        int pound = path.indexOf('#');
+        if (pound >= 0) {
+            anchor = path.substring(pound);
+            path = path.substring(0, pound);
+        }
+        StringBuffer sb = new StringBuffer(path);
+        if( sb.length() > 0 ) { // jsessionid can't be first.
+            sb.append(";jsessionid=");
+            sb.append(sessionId);
+        }
+        sb.append(anchor);
+        sb.append(query);
+        return (sb.toString());
+
+    }
+
+
+}
+

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/connector/ResponseFacade.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/connector/ResponseFacade.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/connector/ResponseFacade.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,552 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.connector;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
+import java.util.Locale;
+
+import javax.servlet.ServletOutputStream;
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.catalina.util.StringManager;
+import org.apache.catalina.security.SecurityUtil;
+
+/**
+ * Facade class that wraps a Coyote response object. 
+ * All methods are delegated to the wrapped response.
+ *
+ * @author Remy Maucherat
+ * @author Jean-Francois Arcand
+ * @version $Revision: 303900 $ $Date: 2005-04-29 17:22:29 -0500 (Fri, 29 Apr 2005) $
+ */
+public class ResponseFacade 
+    implements HttpServletResponse {
+
+
+    // ----------------------------------------------------------- DoPrivileged
+    
+    private final class SetContentTypePrivilegedAction
+            implements PrivilegedAction {
+
+        private String contentType;
+
+        public SetContentTypePrivilegedAction(String contentType){
+            this.contentType = contentType;
+        }
+        
+        public Object run() {
+            response.setContentType(contentType);
+            return null;
+        }            
+    }
+
+    private final class DateHeaderPrivilegedAction
+            implements PrivilegedAction {
+
+        private String name;
+        private long value;
+        private boolean add;
+
+        DateHeaderPrivilegedAction(String name, long value, boolean add) {
+            this.name = name;
+            this.value = value;
+            this.add = add;
+        }
+
+        public Object run() {
+            if(add) {
+                response.addDateHeader(name, value);
+            } else {
+                response.setDateHeader(name, value);
+            }
+            return null;
+        }
+    }
+    
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Construct a wrapper for the specified response.
+     *
+     * @param response The response to be wrapped
+     */
+    public ResponseFacade(Response response) {
+
+         this.response = response;
+    }
+
+
+    // ----------------------------------------------- Class/Instance Variables
+
+
+    /**
+     * The string manager for this package.
+     */
+    protected static StringManager sm =
+        StringManager.getManager(Constants.Package);
+
+
+    /**
+     * The wrapped response.
+     */
+    protected Response response = null;
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Clear facade.
+     */
+    public void clear() {
+        response = null;
+    }
+
+
+    /**
+     * Prevent cloning the facade.
+     */
+    protected Object clone()
+        throws CloneNotSupportedException {
+        throw new CloneNotSupportedException();
+    }
+
+
+    public void finish() {
+
+        if (response == null) {
+            throw new IllegalStateException(
+                            sm.getString("responseFacade.nullResponse"));
+        }
+
+        response.setSuspended(true);
+    }
+
+
+    public boolean isFinished() {
+
+        if (response == null) {
+            throw new IllegalStateException(
+                            sm.getString("responseFacade.nullResponse"));
+        }
+
+        return response.isSuspended();
+    }
+
+
+    // ------------------------------------------------ ServletResponse Methods
+
+
+    public String getCharacterEncoding() {
+
+        if (response == null) {
+            throw new IllegalStateException(
+                            sm.getString("responseFacade.nullResponse"));
+        }
+
+        return response.getCharacterEncoding();
+    }
+
+
+    public ServletOutputStream getOutputStream()
+        throws IOException {
+
+        //        if (isFinished())
+        //            throw new IllegalStateException
+        //                (/*sm.getString("responseFacade.finished")*/);
+
+        ServletOutputStream sos = response.getOutputStream();
+        if (isFinished())
+            response.setSuspended(true);
+        return (sos);
+
+    }
+
+
+    public PrintWriter getWriter()
+        throws IOException {
+
+        //        if (isFinished())
+        //            throw new IllegalStateException
+        //                (/*sm.getString("responseFacade.finished")*/);
+
+        PrintWriter writer = response.getWriter();
+        if (isFinished())
+            response.setSuspended(true);
+        return (writer);
+
+    }
+
+
+    public void setContentLength(int len) {
+
+        if (isCommitted())
+            return;
+
+        response.setContentLength(len);
+
+    }
+
+
+    public void setContentType(String type) {
+
+        if (isCommitted())
+            return;
+        
+        if (SecurityUtil.isPackageProtectionEnabled()){
+            AccessController.doPrivileged(new SetContentTypePrivilegedAction(type));
+        } else {
+            response.setContentType(type);            
+        }
+    }
+
+
+    public void setBufferSize(int size) {
+
+        if (isCommitted())
+            throw new IllegalStateException
+                (/*sm.getString("responseBase.reset.ise")*/);
+
+        response.setBufferSize(size);
+
+    }
+
+
+    public int getBufferSize() {
+
+        if (response == null) {
+            throw new IllegalStateException(
+                            sm.getString("responseFacade.nullResponse"));
+        }
+
+        return response.getBufferSize();
+    }
+
+
+    public void flushBuffer()
+        throws IOException {
+
+        if (isFinished())
+            //            throw new IllegalStateException
+            //                (/*sm.getString("responseFacade.finished")*/);
+            return;
+
+        if (SecurityUtil.isPackageProtectionEnabled()){
+            try{
+                AccessController.doPrivileged(new PrivilegedExceptionAction(){
+
+                    public Object run() throws IOException{
+                        response.setAppCommitted(true);
+
+                        response.flushBuffer();
+                        return null;
+                    }
+                });
+            } catch(PrivilegedActionException e){
+                Exception ex = e.getException();
+                if (ex instanceof IOException){
+                    throw (IOException)ex;
+                }
+            }
+        } else {
+            response.setAppCommitted(true);
+
+            response.flushBuffer();            
+        }
+
+    }
+
+
+    public void resetBuffer() {
+
+        if (isCommitted())
+            throw new IllegalStateException
+                (/*sm.getString("responseBase.reset.ise")*/);
+
+        response.resetBuffer();
+
+    }
+
+
+    public boolean isCommitted() {
+
+        if (response == null) {
+            throw new IllegalStateException(
+                            sm.getString("responseFacade.nullResponse"));
+        }
+
+        return (response.isAppCommitted());
+    }
+
+
+    public void reset() {
+
+        if (isCommitted())
+            throw new IllegalStateException
+                (/*sm.getString("responseBase.reset.ise")*/);
+
+        response.reset();
+
+    }
+
+
+    public void setLocale(Locale loc) {
+
+        if (isCommitted())
+            return;
+
+        response.setLocale(loc);
+    }
+
+
+    public Locale getLocale() {
+
+        if (response == null) {
+            throw new IllegalStateException(
+                            sm.getString("responseFacade.nullResponse"));
+        }
+
+        return response.getLocale();
+    }
+
+
+    public void addCookie(Cookie cookie) {
+
+        if (isCommitted())
+            return;
+
+        response.addCookie(cookie);
+
+    }
+
+
+    public boolean containsHeader(String name) {
+
+        if (response == null) {
+            throw new IllegalStateException(
+                            sm.getString("responseFacade.nullResponse"));
+        }
+
+        return response.containsHeader(name);
+    }
+
+
+    public String encodeURL(String url) {
+
+        if (response == null) {
+            throw new IllegalStateException(
+                            sm.getString("responseFacade.nullResponse"));
+        }
+
+        return response.encodeURL(url);
+    }
+
+
+    public String encodeRedirectURL(String url) {
+
+        if (response == null) {
+            throw new IllegalStateException(
+                            sm.getString("responseFacade.nullResponse"));
+        }
+
+        return response.encodeRedirectURL(url);
+    }
+
+
+    public String encodeUrl(String url) {
+
+        if (response == null) {
+            throw new IllegalStateException(
+                            sm.getString("responseFacade.nullResponse"));
+        }
+
+        return response.encodeURL(url);
+    }
+
+
+    public String encodeRedirectUrl(String url) {
+
+        if (response == null) {
+            throw new IllegalStateException(
+                            sm.getString("responseFacade.nullResponse"));
+        }
+
+        return response.encodeRedirectURL(url);
+    }
+
+
+    public void sendError(int sc, String msg)
+        throws IOException {
+
+        if (isCommitted())
+            throw new IllegalStateException
+                (/*sm.getString("responseBase.reset.ise")*/);
+
+        response.setAppCommitted(true);
+
+        response.sendError(sc, msg);
+
+    }
+
+
+    public void sendError(int sc)
+        throws IOException {
+
+        if (isCommitted())
+            throw new IllegalStateException
+                (/*sm.getString("responseBase.reset.ise")*/);
+
+        response.setAppCommitted(true);
+
+        response.sendError(sc);
+
+    }
+
+
+    public void sendRedirect(String location)
+        throws IOException {
+
+        if (isCommitted())
+            throw new IllegalStateException
+                (/*sm.getString("responseBase.reset.ise")*/);
+
+        response.setAppCommitted(true);
+
+        response.sendRedirect(location);
+
+    }
+
+
+    public void setDateHeader(String name, long date) {
+
+        if (isCommitted())
+            return;
+
+        if(System.getSecurityManager() != null) {
+            AccessController.doPrivileged(new DateHeaderPrivilegedAction
+                                             (name, date, false));
+        } else {
+            response.setDateHeader(name, date);
+        }
+
+    }
+
+
+    public void addDateHeader(String name, long date) {
+
+        if (isCommitted())
+            return;
+
+        if(System.getSecurityManager() != null) {
+            AccessController.doPrivileged(new DateHeaderPrivilegedAction
+                                             (name, date, true));
+        } else {
+            response.addDateHeader(name, date);
+        }
+
+    }
+
+
+    public void setHeader(String name, String value) {
+
+        if (isCommitted())
+            return;
+
+        response.setHeader(name, value);
+
+    }
+
+
+    public void addHeader(String name, String value) {
+
+        if (isCommitted())
+            return;
+
+        response.addHeader(name, value);
+
+    }
+
+
+    public void setIntHeader(String name, int value) {
+
+        if (isCommitted())
+            return;
+
+        response.setIntHeader(name, value);
+
+    }
+
+
+    public void addIntHeader(String name, int value) {
+
+        if (isCommitted())
+            return;
+
+        response.addIntHeader(name, value);
+
+    }
+
+
+    public void setStatus(int sc) {
+
+        if (isCommitted())
+            return;
+
+        response.setStatus(sc);
+
+    }
+
+
+    public void setStatus(int sc, String sm) {
+
+        if (isCommitted())
+            return;
+
+        response.setStatus(sc, sm);
+    }
+
+
+    public String getContentType() {
+
+        if (response == null) {
+            throw new IllegalStateException(
+                            sm.getString("responseFacade.nullResponse"));
+        }
+
+        return response.getContentType();
+    }
+
+
+    public void setCharacterEncoding(String arg0) {
+
+        if (response == null) {
+            throw new IllegalStateException(
+                            sm.getString("responseFacade.nullResponse"));
+        }
+
+        response.setCharacterEncoding(arg0);
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/connector/mbeans-descriptors.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/connector/mbeans-descriptors.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/connector/mbeans-descriptors.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,198 @@
+<?xml version="1.0"?>
+<mbeans-descriptors>
+
+  <mbean         name="CoyoteConnector"
+            className="org.apache.catalina.mbeans.ConnectorMBean"
+          description="Implementation of a Coyote connector"
+               domain="Catalina"
+                group="Connector"
+                 type="org.apache.catalina.connector.Connector">
+
+    <attribute   name="acceptCount"
+          description="The accept count for this Connector"
+                 type="int"/>
+
+    <attribute   name="address"
+          description="The IP address on which to bind"
+                 type="java.lang.String"/>
+
+    <attribute   name="algorithm"
+          description="The certificate encoding algorithm to be used"
+                 type="java.lang.String"/>
+
+    <attribute   name="allowTrace"
+          description="Allow disabling TRACE method"
+                 type="boolean"/>
+
+    <attribute   name="bufferSize"
+          description="The input buffer size we should create on input streams"
+                 type="int"/>
+
+    <attribute   name="className"
+          description="Fully qualified class name of the managed object"
+                 type="java.lang.String"
+            writeable="false"/>
+
+    <attribute   name="clientAuth"
+          description="Should we require client authentication?"
+                 type="java.lang.String"/>
+
+    <attribute   name="ciphers"
+          description="Comma-separated list of SSL cipher suites to be enabled"
+                 type="java.lang.String"/>
+
+    <attribute   name="compression"
+          description="Compression value"
+                 type="java.lang.String"/>
+
+    <attribute   name="connectionLinger"
+          description="Linger value on the incoming connection"
+                 type="int"/>
+
+    <attribute   name="connectionTimeout"
+          description="Timeout value on the incoming connection"
+                 type="int"/>
+
+    <attribute   name="connectionUploadTimeout"
+          description="Timeout value on the incoming connection during request processing"
+                 type="int"/>
+
+    <attribute    name="disableUploadTimeout"
+           description="Should Tomcat ignore setting a timeout for uploads?" 
+                  type="boolean"/>
+
+    <attribute   name="emptySessionPath"
+          description="The 'empty session path' flag for this Connector"
+                 type="boolean"/>
+
+    <attribute   name="enableLookups"
+          description="The 'enable DNS lookups' flag for this Connector"
+                 type="boolean"/>
+
+    <attribute   name="keystoreFile"
+          description="Pathname to the key store file to be used"
+                 type="java.lang.String"/>
+
+    <attribute   name="keystorePass"
+          description="Password for accessing the key store file"
+                 type="java.lang.String"/>
+
+    <attribute   name="keystoreType"
+          description="Type of keystore file to be used for the server certificate"
+                 type="java.lang.String"/>
+
+    <attribute   name="keyAlias"
+          description="Alias name of this connector's keypair and supporting certificate chain"
+                 type="java.lang.String"/>
+
+    <attribute   name="maxHttpHeaderSize"
+          description="Maximum size in bytes of the HTTP header"
+                 type="int"/>
+
+    <attribute   name="maxKeepAliveRequests"
+          description="Maximum number of Keep-Alive requests to honor per connection"
+                 type="int"/>
+
+    <attribute   name="maxPostSize"
+          description="Maximum size in bytes of a POST which will be handled by the servlet API provided features"
+                 type="int"/>
+
+    <attribute   name="maxSpareThreads"
+          description="The maximum number of unused request processing threads"
+                 type="int"/>
+
+    <attribute   name="maxThreads"
+          description="The maximum number of request processing threads to be created"
+                 type="int"/>
+
+    <attribute   name="minSpareThreads"
+          description="The number of request processing threads that will be created"
+                 type="int"/>
+
+    <attribute   name="port"
+          description="The port number on which we listen for ajp13 requests"
+                type="int"/>
+
+    <attribute   name="protocol"
+          description="Coyote protocol handler in use"
+                 type="java.lang.String"/>
+
+    <attribute   name="protocolHandlerClassName"
+          description="Coyote Protocol handler class name"
+                 type="java.lang.String"
+            writeable="false"/>
+
+    <attribute   name="proxyName"
+          description="Ther Server name to which we should pretend requests to this Connector"
+                 type="java.lang.String"/>
+
+    <attribute   name="proxyPort"
+          description="Ther Server port to which we should pretend requests to this Connector"
+                 type="int"/>
+
+    <attribute   name="redirectPort"
+          description="The redirect port for non-SSL to SSL redirects"
+                 type="int"/>
+
+    <attribute   name="scheme"
+          description="Protocol name for this Connector (http, https)"
+                 type="java.lang.String"/>
+
+    <attribute   name="secret"
+          description="Authentication secret (I guess ... not in Javadocs)"
+            readable = "false" 
+                 type="java.lang.String"/>
+
+    <attribute   name="secure"
+          description="Is this a secure (SSL) Connector?"
+                 type="boolean"/>
+
+    <attribute   name="sslProtocol"
+          description="SSL protocol variant to be used"
+                 type="java.lang.String"/>
+
+    <attribute   name="sslProtocols"
+          description="Comma-separated list of SSL protocol variants to be enabled"
+                 type="java.lang.String"/>
+
+    <attribute   name="strategy"
+          description="Thread pool strategy"
+                 type="java.lang.String"/>
+
+    <attribute   name="tcpNoDelay"
+          description="Should we use TCP no delay?"
+                 type="boolean"/>
+
+    <attribute    name="tomcatAuthentication"
+           description="Should Tomcat perform all authentications?"
+                  type="boolean"/>
+
+    <attribute    name="threadPriority"
+           description="The thread priority for processors"
+                  type="int"/>
+
+    <attribute   name="URIEncoding"
+          description="Character encoding used to decode the URI"
+                 type="java.lang.String"/>
+
+    <attribute   name="useBodyEncodingForURI"
+          description="Should the body encoding be used for URI query parameters"
+                 type="boolean"/>
+
+    <attribute    name="xpoweredBy"
+           description="Is generation of X-Powered-By response header enabled/disabled?"
+                  type="boolean"/>
+
+    <operation name="start" description="Start" impact="ACTION" returnType="void" />
+    <operation name="stop" description="Stop" impact="ACTION" returnType="void" />
+    <operation name="pause" description="Start" impact="ACTION" returnType="void" />
+    <operation name="resume" description="Stop" impact="ACTION" returnType="void" />
+    <operation name="init" description="Init" impact="ACTION" returnType="void" />
+    <operation name="destroy" description="Destroy" impact="ACTION" returnType="void" />
+
+  </mbean>
+
+
+</mbeans-descriptors>
+
+

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/core/ApplicationContext.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/core/ApplicationContext.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/core/ApplicationContext.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,974 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.InputStream;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Set;
+
+import javax.naming.Binding;
+import javax.naming.NamingException;
+import javax.naming.directory.DirContext;
+import javax.servlet.RequestDispatcher;
+import javax.servlet.Servlet;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletContextAttributeEvent;
+import javax.servlet.ServletContextAttributeListener;
+
+import org.apache.catalina.Context;
+import org.apache.catalina.Host;
+import org.apache.catalina.Wrapper;
+import org.apache.catalina.deploy.ApplicationParameter;
+import org.apache.catalina.util.Enumerator;
+import org.apache.catalina.util.ResourceSet;
+import org.apache.catalina.util.ServerInfo;
+import org.apache.catalina.util.StringManager;
+import org.apache.naming.resources.DirContextURLStreamHandler;
+import org.apache.naming.resources.Resource;
+import org.apache.tomcat.util.buf.CharChunk;
+import org.apache.tomcat.util.buf.MessageBytes;
+import org.apache.tomcat.util.http.mapper.MappingData;
+
+
+/**
+ * Standard implementation of <code>ServletContext</code> that represents
+ * a web application's execution environment.  An instance of this class is
+ * associated with each instance of <code>StandardContext</code>.
+ *
+ * @author Craig R. McClanahan
+ * @author Remy Maucherat
+ * @version $Revision: 391138 $ $Date: 2006-04-03 15:18:47 -0500 (Mon, 03 Apr 2006) $
+ */
+
+public class ApplicationContext
+    implements ServletContext {
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Construct a new instance of this class, associated with the specified
+     * Context instance.
+     *
+     * @param context The associated Context instance
+     */
+    public ApplicationContext(String basePath, StandardContext context) {
+        super();
+        this.context = context;
+        this.basePath = basePath;
+    }
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The context attributes for this context.
+     */
+    protected HashMap attributes = new HashMap();
+
+
+    /**
+     * List of read only attributes for this context.
+     */
+    private HashMap readOnlyAttributes = new HashMap();
+
+
+    /**
+     * The Context instance with which we are associated.
+     */
+    private StandardContext context = null;
+
+
+    /**
+     * Empty collection to serve as the basis for empty enumerations.
+     * <strong>DO NOT ADD ANY ELEMENTS TO THIS COLLECTION!</strong>
+     */
+    private static final ArrayList empty = new ArrayList();
+
+
+    /**
+     * The facade around this object.
+     */
+    private ServletContext facade = new ApplicationContextFacade(this);
+
+
+    /**
+     * The merged context initialization parameters for this Context.
+     */
+    private HashMap parameters = null;
+
+
+    /**
+     * The string manager for this package.
+     */
+    private static final StringManager sm =
+      StringManager.getManager(Constants.Package);
+
+
+    /**
+     * Base path.
+     */
+    private String basePath = null;
+
+
+    /**
+     * Thread local mapping data.
+     */
+    private ThreadLocal localMappingData = new ThreadLocal();
+
+
+    /**
+     * Thread local URI message bytes.
+     */
+    private ThreadLocal localUriMB = new ThreadLocal();
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Return the resources object that is mapped to a specified path.
+     * The path must begin with a "/" and is interpreted as relative to the
+     * current context root.
+     */
+    public DirContext getResources() {
+
+        return context.getResources();
+
+    }
+
+
+    // ------------------------------------------------- ServletContext Methods
+
+
+    /**
+     * Return the value of the specified context attribute, if any;
+     * otherwise return <code>null</code>.
+     *
+     * @param name Name of the context attribute to return
+     */
+    public Object getAttribute(String name) {
+
+        synchronized (attributes) {
+            return (attributes.get(name));
+        }
+
+    }
+
+
+    /**
+     * Return an enumeration of the names of the context attributes
+     * associated with this context.
+     */
+    public Enumeration getAttributeNames() {
+
+        synchronized (attributes) {
+            return new Enumerator(attributes.keySet(), true);
+        }
+
+    }
+
+
+    /**
+     * Return a <code>ServletContext</code> object that corresponds to a
+     * specified URI on the server.  This method allows servlets to gain
+     * access to the context for various parts of the server, and as needed
+     * obtain <code>RequestDispatcher</code> objects or resources from the
+     * context.  The given path must be absolute (beginning with a "/"),
+     * and is interpreted based on our virtual host's document root.
+     *
+     * @param uri Absolute URI of a resource on the server
+     */
+    public ServletContext getContext(String uri) {
+
+        // Validate the format of the specified argument
+        if ((uri == null) || (!uri.startsWith("/")))
+            return (null);
+
+        Context child = null;
+        try {
+            Host host = (Host) context.getParent();
+            String mapuri = uri;
+            while (true) {
+                child = (Context) host.findChild(mapuri);
+                if (child != null)
+                    break;
+                int slash = mapuri.lastIndexOf('/');
+                if (slash < 0)
+                    break;
+                mapuri = mapuri.substring(0, slash);
+            }
+        } catch (Throwable t) {
+            return (null);
+        }
+
+        if (child == null)
+            return (null);
+
+        if (context.getCrossContext()) {
+            // If crossContext is enabled, can always return the context
+            return child.getServletContext();
+        } else if (child == context) {
+            // Can still return the current context
+            return context.getServletContext();
+        } else {
+            // Nothing to return
+            return (null);
+        }
+    }
+
+    
+    /**
+     * Return the main path associated with this context.
+     */
+    public String getContextPath() {
+        return context.getPath();
+    }
+    
+
+    /**
+     * Return the value of the specified initialization parameter, or
+     * <code>null</code> if this parameter does not exist.
+     *
+     * @param name Name of the initialization parameter to retrieve
+     */
+    public String getInitParameter(final String name) {
+
+        mergeParameters();
+        synchronized (parameters) {
+            return ((String) parameters.get(name));
+        }
+    }
+
+
+    /**
+     * Return the names of the context's initialization parameters, or an
+     * empty enumeration if the context has no initialization parameters.
+     */
+    public Enumeration getInitParameterNames() {
+
+        mergeParameters();
+        synchronized (parameters) {
+           return (new Enumerator(parameters.keySet()));
+        }
+
+    }
+
+
+    /**
+     * Return the major version of the Java Servlet API that we implement.
+     */
+    public int getMajorVersion() {
+
+        return (Constants.MAJOR_VERSION);
+
+    }
+
+
+    /**
+     * Return the minor version of the Java Servlet API that we implement.
+     */
+    public int getMinorVersion() {
+
+        return (Constants.MINOR_VERSION);
+
+    }
+
+
+    /**
+     * Return the MIME type of the specified file, or <code>null</code> if
+     * the MIME type cannot be determined.
+     *
+     * @param file Filename for which to identify a MIME type
+     */
+    public String getMimeType(String file) {
+
+        if (file == null)
+            return (null);
+        int period = file.lastIndexOf(".");
+        if (period < 0)
+            return (null);
+        String extension = file.substring(period + 1);
+        if (extension.length() < 1)
+            return (null);
+        return (context.findMimeMapping(extension));
+
+    }
+
+
+    /**
+     * Return a <code>RequestDispatcher</code> object that acts as a
+     * wrapper for the named servlet.
+     *
+     * @param name Name of the servlet for which a dispatcher is requested
+     */
+    public RequestDispatcher getNamedDispatcher(String name) {
+
+        // Validate the name argument
+        if (name == null)
+            return (null);
+
+        // Create and return a corresponding request dispatcher
+        Wrapper wrapper = (Wrapper) context.findChild(name);
+        if (wrapper == null)
+            return (null);
+        
+        return new ApplicationDispatcher(wrapper, null, null, null, null, name);
+
+    }
+
+
+    /**
+     * Return the real path for a given virtual path, if possible; otherwise
+     * return <code>null</code>.
+     *
+     * @param path The path to the desired resource
+     */
+    public String getRealPath(String path) {
+
+        if (!context.isFilesystemBased())
+            return null;
+
+        if (path == null) {
+            return null;
+        }
+
+        File file = new File(basePath, path);
+        return (file.getAbsolutePath());
+
+    }
+
+
+    /**
+     * Return a <code>RequestDispatcher</code> instance that acts as a
+     * wrapper for the resource at the given path.  The path must begin
+     * with a "/" and is interpreted as relative to the current context root.
+     *
+     * @param path The path to the desired resource.
+     */
+    public RequestDispatcher getRequestDispatcher(String path) {
+
+        // Validate the path argument
+        if (path == null)
+            return (null);
+        if (!path.startsWith("/"))
+            throw new IllegalArgumentException
+                (sm.getString
+                 ("applicationContext.requestDispatcher.iae", path));
+        path = normalize(path);
+        if (path == null)
+            return (null);
+
+        // Retrieve the thread local URI
+        MessageBytes uriMB = (MessageBytes) localUriMB.get();
+        if (uriMB == null) {
+            uriMB = MessageBytes.newInstance();
+            CharChunk uriCC = uriMB.getCharChunk();
+            uriCC.setLimit(-1);
+            localUriMB.set(uriMB);
+        } else {
+            uriMB.recycle();
+        }
+
+        // Get query string
+        String queryString = null;
+        int pos = path.indexOf('?');
+        if (pos >= 0) {
+            queryString = path.substring(pos + 1);
+        } else {
+            pos = path.length();
+        }
+ 
+        // Retrieve the thread local mapping data
+        MappingData mappingData = (MappingData) localMappingData.get();
+        if (mappingData == null) {
+            mappingData = new MappingData();
+            localMappingData.set(mappingData);
+        }
+
+        // Map the URI
+        CharChunk uriCC = uriMB.getCharChunk();
+        try {
+            uriCC.append(context.getPath(), 0, context.getPath().length());
+            /*
+             * Ignore any trailing path params (separated by ';') for mapping
+             * purposes
+             */
+            int semicolon = path.indexOf(';');
+            if (pos >= 0 && semicolon > pos) {
+                semicolon = -1;
+            }
+            uriCC.append(path, 0, semicolon > 0 ? semicolon : pos);
+            context.getMapper().map(uriMB, mappingData);
+            if (mappingData.wrapper == null) {
+                return (null);
+            }
+            /*
+             * Append any trailing path params (separated by ';') that were
+             * ignored for mapping purposes, so that they're reflected in the
+             * RequestDispatcher's requestURI
+             */
+            if (semicolon > 0) {
+                uriCC.append(path, semicolon, pos - semicolon);
+            }
+        } catch (Exception e) {
+            // Should never happen
+            log(sm.getString("applicationContext.mapping.error"), e);
+            return (null);
+        }
+
+        Wrapper wrapper = (Wrapper) mappingData.wrapper;
+        String wrapperPath = mappingData.wrapperPath.toString();
+        String pathInfo = mappingData.pathInfo.toString();
+
+        mappingData.recycle();
+        
+        // Construct a RequestDispatcher to process this request
+        return new ApplicationDispatcher
+            (wrapper, uriCC.toString(), wrapperPath, pathInfo, 
+             queryString, null);
+
+    }
+
+
+
+    /**
+     * Return the URL to the resource that is mapped to a specified path.
+     * The path must begin with a "/" and is interpreted as relative to the
+     * current context root.
+     *
+     * @param path The path to the desired resource
+     *
+     * @exception MalformedURLException if the path is not given
+     *  in the correct form
+     */
+    public URL getResource(String path)
+        throws MalformedURLException {
+
+        if (path == null || !path.startsWith("/")) {
+            throw new MalformedURLException(sm.getString("applicationContext.requestDispatcher.iae", path));
+        }
+        
+        path = normalize(path);
+        if (path == null)
+            return (null);
+
+        String libPath = "/WEB-INF/lib/";
+        if ((path.startsWith(libPath)) && (path.endsWith(".jar"))) {
+            File jarFile = null;
+            if (context.isFilesystemBased()) {
+                jarFile = new File(basePath, path);
+            } else {
+                jarFile = new File(context.getWorkPath(), path);
+            }
+            if (jarFile.exists()) {
+                return jarFile.toURL();
+            } else {
+                return null;
+            }
+        } else {
+
+            DirContext resources = context.getResources();
+            if (resources != null) {
+                String fullPath = context.getName() + path;
+                String hostName = context.getParent().getName();
+                try {
+                    resources.lookup(path);
+                    return new URL
+                        ("jndi", "", 0, getJNDIUri(hostName, fullPath),
+                         new DirContextURLStreamHandler(resources));
+                } catch (Exception e) {
+                    // Ignore
+                }
+            }
+        }
+
+        return (null);
+
+    }
+
+
+    /**
+     * Return the requested resource as an <code>InputStream</code>.  The
+     * path must be specified according to the rules described under
+     * <code>getResource</code>.  If no such resource can be identified,
+     * return <code>null</code>.
+     *
+     * @param path The path to the desired resource.
+     */
+    public InputStream getResourceAsStream(String path) {
+
+        path = normalize(path);
+        if (path == null)
+            return (null);
+
+        DirContext resources = context.getResources();
+        if (resources != null) {
+            try {
+                Object resource = resources.lookup(path);
+                if (resource instanceof Resource)
+                    return (((Resource) resource).streamContent());
+            } catch (Exception e) {
+            }
+        }
+        return (null);
+
+    }
+
+
+    /**
+     * Return a Set containing the resource paths of resources member of the
+     * specified collection. Each path will be a String starting with
+     * a "/" character. The returned set is immutable.
+     *
+     * @param path Collection path
+     */
+    public Set getResourcePaths(String path) {
+
+        // Validate the path argument
+        if (path == null) {
+            return null;
+        }
+        if (!path.startsWith("/")) {
+            throw new IllegalArgumentException
+                (sm.getString("applicationContext.resourcePaths.iae", path));
+        }
+
+        path = normalize(path);
+        if (path == null)
+            return (null);
+
+        DirContext resources = context.getResources();
+        if (resources != null) {
+            return (getResourcePathsInternal(resources, path));
+        }
+        return (null);
+
+    }
+
+
+    /**
+     * Internal implementation of getResourcesPath() logic.
+     *
+     * @param resources Directory context to search
+     * @param path Collection path
+     */
+    private Set getResourcePathsInternal(DirContext resources, String path) {
+
+        ResourceSet set = new ResourceSet();
+        try {
+            listCollectionPaths(set, resources, path);
+        } catch (NamingException e) {
+            return (null);
+        }
+        set.setLocked(true);
+        return (set);
+
+    }
+
+
+    /**
+     * Return the name and version of the servlet container.
+     */
+    public String getServerInfo() {
+
+        return (ServerInfo.getServerInfo());
+
+    }
+
+
+    /**
+     * @deprecated As of Java Servlet API 2.1, with no direct replacement.
+     */
+    public Servlet getServlet(String name) {
+
+        return (null);
+
+    }
+
+
+    /**
+     * Return the display name of this web application.
+     */
+    public String getServletContextName() {
+
+        return (context.getDisplayName());
+
+    }
+
+
+    /**
+     * @deprecated As of Java Servlet API 2.1, with no direct replacement.
+     */
+    public Enumeration getServletNames() {
+        return (new Enumerator(empty));
+    }
+
+
+    /**
+     * @deprecated As of Java Servlet API 2.1, with no direct replacement.
+     */
+    public Enumeration getServlets() {
+        return (new Enumerator(empty));
+    }
+
+
+    /**
+     * Writes the specified message to a servlet log file.
+     *
+     * @param message Message to be written
+     */
+    public void log(String message) {
+
+        context.getLogger().info(message);
+
+    }
+
+
+    /**
+     * Writes the specified exception and message to a servlet log file.
+     *
+     * @param exception Exception to be reported
+     * @param message Message to be written
+     *
+     * @deprecated As of Java Servlet API 2.1, use
+     *  <code>log(String, Throwable)</code> instead
+     */
+    public void log(Exception exception, String message) {
+        
+        context.getLogger().error(message, exception);
+
+    }
+
+
+    /**
+     * Writes the specified message and exception to a servlet log file.
+     *
+     * @param message Message to be written
+     * @param throwable Exception to be reported
+     */
+    public void log(String message, Throwable throwable) {
+        
+        context.getLogger().error(message, throwable);
+
+    }
+
+
+    /**
+     * Remove the context attribute with the specified name, if any.
+     *
+     * @param name Name of the context attribute to be removed
+     */
+    public void removeAttribute(String name) {
+
+        Object value = null;
+        boolean found = false;
+
+        // Remove the specified attribute
+        synchronized (attributes) {
+            // Check for read only attribute
+           if (readOnlyAttributes.containsKey(name))
+                return;
+            found = attributes.containsKey(name);
+            if (found) {
+                value = attributes.get(name);
+                attributes.remove(name);
+            } else {
+                return;
+            }
+        }
+
+        // Notify interested application event listeners
+        Object listeners[] = context.getApplicationEventListeners();
+        if ((listeners == null) || (listeners.length == 0))
+            return;
+        ServletContextAttributeEvent event =
+          new ServletContextAttributeEvent(context.getServletContext(),
+                                            name, value);
+        for (int i = 0; i < listeners.length; i++) {
+            if (!(listeners[i] instanceof ServletContextAttributeListener))
+                continue;
+            ServletContextAttributeListener listener =
+                (ServletContextAttributeListener) listeners[i];
+            try {
+                context.fireContainerEvent("beforeContextAttributeRemoved",
+                                           listener);
+                listener.attributeRemoved(event);
+                context.fireContainerEvent("afterContextAttributeRemoved",
+                                           listener);
+            } catch (Throwable t) {
+                context.fireContainerEvent("afterContextAttributeRemoved",
+                                           listener);
+                // FIXME - should we do anything besides log these?
+                log(sm.getString("applicationContext.attributeEvent"), t);
+            }
+        }
+
+    }
+
+
+    /**
+     * Bind the specified value with the specified context attribute name,
+     * replacing any existing value for that name.
+     *
+     * @param name Attribute name to be bound
+     * @param value New attribute value to be bound
+     */
+    public void setAttribute(String name, Object value) {
+
+        // Name cannot be null
+        if (name == null)
+            throw new IllegalArgumentException
+                (sm.getString("applicationContext.setAttribute.namenull"));
+
+        // Null value is the same as removeAttribute()
+        if (value == null) {
+            removeAttribute(name);
+            return;
+        }
+
+        Object oldValue = null;
+        boolean replaced = false;
+
+        // Add or replace the specified attribute
+        synchronized (attributes) {
+            // Check for read only attribute
+            if (readOnlyAttributes.containsKey(name))
+                return;
+            oldValue = attributes.get(name);
+            if (oldValue != null)
+                replaced = true;
+            attributes.put(name, value);
+        }
+
+        // Notify interested application event listeners
+        Object listeners[] = context.getApplicationEventListeners();
+        if ((listeners == null) || (listeners.length == 0))
+            return;
+        ServletContextAttributeEvent event = null;
+        if (replaced)
+            event =
+                new ServletContextAttributeEvent(context.getServletContext(),
+                                                 name, oldValue);
+        else
+            event =
+                new ServletContextAttributeEvent(context.getServletContext(),
+                                                 name, value);
+
+        for (int i = 0; i < listeners.length; i++) {
+            if (!(listeners[i] instanceof ServletContextAttributeListener))
+                continue;
+            ServletContextAttributeListener listener =
+                (ServletContextAttributeListener) listeners[i];
+            try {
+                if (replaced) {
+                    context.fireContainerEvent
+                        ("beforeContextAttributeReplaced", listener);
+                    listener.attributeReplaced(event);
+                    context.fireContainerEvent("afterContextAttributeReplaced",
+                                               listener);
+                } else {
+                    context.fireContainerEvent("beforeContextAttributeAdded",
+                                               listener);
+                    listener.attributeAdded(event);
+                    context.fireContainerEvent("afterContextAttributeAdded",
+                                               listener);
+                }
+            } catch (Throwable t) {
+                if (replaced)
+                    context.fireContainerEvent("afterContextAttributeReplaced",
+                                               listener);
+                else
+                    context.fireContainerEvent("afterContextAttributeAdded",
+                                               listener);
+                // FIXME - should we do anything besides log these?
+                log(sm.getString("applicationContext.attributeEvent"), t);
+            }
+        }
+
+    }
+
+
+    // -------------------------------------------------------- Package Methods
+
+
+    /**
+     * Clear all application-created attributes.
+     */
+    void clearAttributes() {
+
+        // Create list of attributes to be removed
+        ArrayList list = new ArrayList();
+        synchronized (attributes) {
+            Iterator iter = attributes.keySet().iterator();
+            while (iter.hasNext()) {
+                list.add(iter.next());
+            }
+        }
+
+        // Remove application originated attributes
+        // (read only attributes will be left in place)
+        Iterator keys = list.iterator();
+        while (keys.hasNext()) {
+            String key = (String) keys.next();
+            removeAttribute(key);
+        }
+        
+    }
+    
+    
+    /**
+     * Return the facade associated with this ApplicationContext.
+     */
+    protected ServletContext getFacade() {
+
+        return (this.facade);
+
+    }
+
+
+    /**
+     * Set an attribute as read only.
+     */
+    void setAttributeReadOnly(String name) {
+
+        synchronized (attributes) {
+            if (attributes.containsKey(name))
+                readOnlyAttributes.put(name, name);
+        }
+
+    }
+
+
+    // -------------------------------------------------------- Private Methods
+
+
+    /**
+     * Return a context-relative path, beginning with a "/", that represents
+     * the canonical version of the specified path after ".." and "." elements
+     * are resolved out.  If the specified path attempts to go outside the
+     * boundaries of the current context (i.e. too many ".." path elements
+     * are present), return <code>null</code> instead.
+     *
+     * @param path Path to be normalized
+     */
+    private String normalize(String path) {
+
+        if (path == null) {
+            return null;
+        }
+
+        String normalized = path;
+
+        // Normalize the slashes and add leading slash if necessary
+        if (normalized.indexOf('\\') >= 0)
+            normalized = normalized.replace('\\', '/');
+
+        // Resolve occurrences of "/../" in the normalized path
+        while (true) {
+            int index = normalized.indexOf("/../");
+            if (index < 0)
+                break;
+            if (index == 0)
+                return (null);  // Trying to go outside our context
+            int index2 = normalized.lastIndexOf('/', index - 1);
+            normalized = normalized.substring(0, index2) +
+                normalized.substring(index + 3);
+        }
+
+        // Return the normalized path that we have completed
+        return (normalized);
+
+    }
+
+
+    /**
+     * Merge the context initialization parameters specified in the application
+     * deployment descriptor with the application parameters described in the
+     * server configuration, respecting the <code>override</code> property of
+     * the application parameters appropriately.
+     */
+    private void mergeParameters() {
+
+        if (parameters != null)
+            return;
+        HashMap results = new HashMap();
+        String names[] = context.findParameters();
+        for (int i = 0; i < names.length; i++)
+            results.put(names[i], context.findParameter(names[i]));
+        ApplicationParameter params[] =
+            context.findApplicationParameters();
+        for (int i = 0; i < params.length; i++) {
+            if (params[i].getOverride()) {
+                if (results.get(params[i].getName()) == null)
+                    results.put(params[i].getName(), params[i].getValue());
+            } else {
+                results.put(params[i].getName(), params[i].getValue());
+            }
+        }
+        parameters = results;
+
+    }
+
+
+    /**
+     * List resource paths (recursively), and store all of them in the given
+     * Set.
+     */
+    private static void listCollectionPaths
+        (Set set, DirContext resources, String path)
+        throws NamingException {
+
+        Enumeration childPaths = resources.listBindings(path);
+        while (childPaths.hasMoreElements()) {
+            Binding binding = (Binding) childPaths.nextElement();
+            String name = binding.getName();
+            StringBuffer childPath = new StringBuffer(path);
+            if (!"/".equals(path) && !path.endsWith("/"))
+                childPath.append("/");
+            childPath.append(name);
+            Object object = binding.getObject();
+            if (object instanceof DirContext) {
+                childPath.append("/");
+            }
+            set.add(childPath.toString());
+        }
+
+    }
+
+
+    /**
+     * Get full path, based on the host name and the context path.
+     */
+    private static String getJNDIUri(String hostName, String path) {
+        if (!path.startsWith("/"))
+            return "/" + hostName + "/" + path;
+        else
+            return "/" + hostName + path;
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/core/ApplicationContextFacade.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/core/ApplicationContextFacade.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/core/ApplicationContextFacade.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,508 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.InputStream;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.security.AccessController;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Set;
+
+import javax.servlet.RequestDispatcher;
+import javax.servlet.Servlet;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+
+import org.apache.catalina.security.SecurityUtil;
+
+
+/**
+ * Facade object which masks the internal <code>ApplicationContext</code>
+ * object from the web application.
+ *
+ * @author Remy Maucherat
+ * @author Jean-Francois Arcand
+ * @version $Revision: 377994 $ $Date: 2006-02-15 06:37:28 -0600 (Wed, 15 Feb 2006) $
+ */
+
+public final class ApplicationContextFacade
+    implements ServletContext {
+        
+    // ---------------------------------------------------------- Attributes
+    /**
+     * Cache Class object used for reflection.
+     */
+    private HashMap classCache;
+    
+    
+    /**
+     * Cache method object.
+     */
+    private HashMap objectCache;
+    
+    
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Construct a new instance of this class, associated with the specified
+     * Context instance.
+     *
+     * @param context The associated Context instance
+     */
+    public ApplicationContextFacade(ApplicationContext context) {
+        super();
+        this.context = context;
+        
+        classCache = new HashMap();
+        objectCache = new HashMap();
+        initClassCache();
+    }
+    
+    
+    private void initClassCache(){
+        Class[] clazz = new Class[]{String.class};
+        classCache.put("getContext", clazz);
+        classCache.put("getMimeType", clazz);
+        classCache.put("getResourcePaths", clazz);
+        classCache.put("getResource", clazz);
+        classCache.put("getResourceAsStream", clazz);
+        classCache.put("getRequestDispatcher", clazz);
+        classCache.put("getNamedDispatcher", clazz);
+        classCache.put("getServlet", clazz);
+        classCache.put("getInitParameter", clazz);
+        classCache.put("setAttribute", new Class[]{String.class, Object.class});
+        classCache.put("removeAttribute", clazz);
+        classCache.put("getRealPath", clazz);
+        classCache.put("getAttribute", clazz);
+        classCache.put("log", clazz);
+    }
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * Wrapped application context.
+     */
+    private ApplicationContext context = null;
+    
+
+
+    // ------------------------------------------------- ServletContext Methods
+
+
+    public ServletContext getContext(String uripath) {
+        ServletContext theContext = null;
+        if (SecurityUtil.isPackageProtectionEnabled()) {
+            theContext = (ServletContext)
+                doPrivileged("getContext", new Object[]{uripath});
+        } else {
+            theContext = context.getContext(uripath);
+        }
+        if ((theContext != null) &&
+            (theContext instanceof ApplicationContext)){
+            theContext = ((ApplicationContext)theContext).getFacade();
+        }
+        return (theContext);
+    }
+
+
+    public int getMajorVersion() {
+        return context.getMajorVersion();
+    }
+
+
+    public int getMinorVersion() {
+        return context.getMinorVersion();
+    }
+
+
+    public String getMimeType(String file) {
+        if (SecurityUtil.isPackageProtectionEnabled()) {
+            return (String)doPrivileged("getMimeType", new Object[]{file});
+        } else {
+            return context.getMimeType(file);
+        }
+    }
+
+
+    public Set getResourcePaths(String path) {
+        if (SecurityUtil.isPackageProtectionEnabled()){
+            return (Set)doPrivileged("getResourcePaths", new Object[]{path});
+        } else {
+            return context.getResourcePaths(path);
+        }
+    }
+
+
+    public URL getResource(String path)
+        throws MalformedURLException {
+        if (System.getSecurityManager() != null) {
+            try {
+                return (URL) invokeMethod(context, "getResource", 
+                                          new Object[]{path});
+            } catch(Throwable t) {
+                if (t instanceof MalformedURLException){
+                    throw (MalformedURLException)t;
+                }
+                return null;
+            }
+        } else {
+            return context.getResource(path);
+        }
+    }
+
+
+    public InputStream getResourceAsStream(String path) {
+        if (SecurityUtil.isPackageProtectionEnabled()) {
+            return (InputStream) doPrivileged("getResourceAsStream", 
+                                              new Object[]{path});
+        } else {
+            return context.getResourceAsStream(path);
+        }
+    }
+
+
+    public RequestDispatcher getRequestDispatcher(final String path) {
+        if (SecurityUtil.isPackageProtectionEnabled()) {
+            return (RequestDispatcher) doPrivileged("getRequestDispatcher", 
+                                                    new Object[]{path});
+        } else {
+            return context.getRequestDispatcher(path);
+        }
+    }
+
+
+    public RequestDispatcher getNamedDispatcher(String name) {
+        if (SecurityUtil.isPackageProtectionEnabled()) {
+            return (RequestDispatcher) doPrivileged("getNamedDispatcher", 
+                                                    new Object[]{name});
+        } else {
+            return context.getNamedDispatcher(name);
+        }
+    }
+
+
+    public Servlet getServlet(String name)
+        throws ServletException {
+        if (SecurityUtil.isPackageProtectionEnabled()) {
+            try {
+                return (Servlet) invokeMethod(context, "getServlet", 
+                                              new Object[]{name});
+            } catch (Throwable t) {
+                if (t instanceof ServletException) {
+                    throw (ServletException) t;
+                }
+                return null;
+            }
+        } else {
+            return context.getServlet(name);
+        }
+    }
+
+
+    public Enumeration getServlets() {
+        if (SecurityUtil.isPackageProtectionEnabled()) {
+            return (Enumeration) doPrivileged("getServlets", null);
+        } else {
+            return context.getServlets();
+        }
+    }
+
+
+    public Enumeration getServletNames() {
+        if (SecurityUtil.isPackageProtectionEnabled()) {
+            return (Enumeration) doPrivileged("getServletNames", null);
+        } else {
+            return context.getServletNames();
+        }
+   }
+
+
+    public void log(String msg) {
+        if (SecurityUtil.isPackageProtectionEnabled()) {
+            doPrivileged("log", new Object[]{msg} );
+        } else {
+            context.log(msg);
+        }
+    }
+
+
+    public void log(Exception exception, String msg) {
+        if (SecurityUtil.isPackageProtectionEnabled()) {
+            doPrivileged("log", new Class[]{Exception.class, String.class}, 
+                         new Object[]{exception,msg});
+        } else {
+            context.log(exception, msg);
+        }
+    }
+
+
+    public void log(String message, Throwable throwable) {
+        if (SecurityUtil.isPackageProtectionEnabled()) {
+            doPrivileged("log", new Class[]{String.class, Throwable.class}, 
+                         new Object[]{message, throwable});
+        } else {
+            context.log(message, throwable);
+        }
+    }
+
+
+    public String getRealPath(String path) {
+        if (SecurityUtil.isPackageProtectionEnabled()) {
+            return (String) doPrivileged("getRealPath", new Object[]{path});
+        } else {
+            return context.getRealPath(path);
+        }
+    }
+
+
+    public String getServerInfo() {
+        if (SecurityUtil.isPackageProtectionEnabled()) {
+            return (String) doPrivileged("getServerInfo", null);
+        } else {
+            return context.getServerInfo();
+        }
+    }
+
+
+    public String getInitParameter(String name) {
+        if (SecurityUtil.isPackageProtectionEnabled()) {
+            return (String) doPrivileged("getInitParameter", 
+                                         new Object[]{name});
+        } else {
+            return context.getInitParameter(name);
+        }
+    }
+
+
+    public Enumeration getInitParameterNames() {
+        if (SecurityUtil.isPackageProtectionEnabled()) {
+            return (Enumeration) doPrivileged("getInitParameterNames", null);
+        } else {
+            return context.getInitParameterNames();
+        }
+    }
+
+
+    public Object getAttribute(String name) {
+        if (SecurityUtil.isPackageProtectionEnabled()) {
+            return doPrivileged("getAttribute", new Object[]{name});
+        } else {
+            return context.getAttribute(name);
+        }
+     }
+
+
+    public Enumeration getAttributeNames() {
+        if (SecurityUtil.isPackageProtectionEnabled()) {
+            return (Enumeration) doPrivileged("getAttributeNames", null);
+        } else {
+            return context.getAttributeNames();
+        }
+    }
+
+
+    public void setAttribute(String name, Object object) {
+        if (SecurityUtil.isPackageProtectionEnabled()) {
+            doPrivileged("setAttribute", new Object[]{name,object});
+        } else {
+            context.setAttribute(name, object);
+        }
+    }
+
+
+    public void removeAttribute(String name) {
+        if (SecurityUtil.isPackageProtectionEnabled()) {
+            doPrivileged("removeAttribute", new Object[]{name});
+        } else {
+            context.removeAttribute(name);
+        }
+    }
+
+
+    public String getServletContextName() {
+        if (SecurityUtil.isPackageProtectionEnabled()) {
+            return (String) doPrivileged("getServletContextName", null);
+        } else {
+            return context.getServletContextName();
+        }
+    }
+
+       
+    public String getContextPath() {
+        if (SecurityUtil.isPackageProtectionEnabled()) {
+            return (String) doPrivileged("getContextPath", null);
+        } else {
+            return context.getContextPath();
+        }
+    }
+
+       
+    /**
+     * Use reflection to invoke the requested method. Cache the method object 
+     * to speed up the process
+     * @param appContext The AppliationContext object on which the method
+     *                   will be invoked
+     * @param methodName The method to call.
+     * @param params The arguments passed to the called method.
+     */
+    private Object doPrivileged(ApplicationContext appContext,
+                                final String methodName, 
+                                final Object[] params) {
+        try{
+            return invokeMethod(appContext, methodName, params );
+        } catch (Throwable t){
+            throw new RuntimeException(t.getMessage());
+        }
+
+    }
+
+
+    /**
+     * Use reflection to invoke the requested method. Cache the method object 
+     * to speed up the process
+     *                   will be invoked
+     * @param methodName The method to call.
+     * @param params The arguments passed to the called method.
+     */
+    private Object doPrivileged(final String methodName, final Object[] params){
+        try{
+            return invokeMethod(context, methodName, params);
+        }catch(Throwable t){
+            throw new RuntimeException(t.getMessage());
+        }
+    }
+
+    
+    /**
+     * Use reflection to invoke the requested method. Cache the method object 
+     * to speed up the process
+     * @param appContext The AppliationContext object on which the method
+     *                   will be invoked
+     * @param methodName The method to call.
+     * @param params The arguments passed to the called method.
+     */
+    private Object invokeMethod(ApplicationContext appContext,
+                                final String methodName, 
+                                Object[] params) 
+        throws Throwable{
+
+        try{
+            Method method = (Method)objectCache.get(methodName);
+            if (method == null){
+                method = appContext.getClass()
+                    .getMethod(methodName, (Class[])classCache.get(methodName));
+                objectCache.put(methodName, method);
+            }
+            
+            return executeMethod(method,appContext,params);
+        } catch (Exception ex){
+            handleException(ex, methodName);
+            return null;
+        } finally {
+            params = null;
+        }
+    }
+    
+    /**
+     * Use reflection to invoke the requested method. Cache the method object 
+     * to speed up the process
+     * @param methodName The method to invoke.
+     * @param clazz The class where the method is.
+     * @param params The arguments passed to the called method.
+     */    
+    private Object doPrivileged(final String methodName, 
+                                final Class[] clazz,
+                                Object[] params){
+
+        try{
+            Method method = context.getClass()
+                    .getMethod(methodName, (Class[])clazz);
+            return executeMethod(method,context,params);
+        } catch (Exception ex){
+            try{
+                handleException(ex, methodName);
+            }catch (Throwable t){
+                throw new RuntimeException(t.getMessage());
+            }
+            return null;
+        } finally {
+            params = null;
+        }
+    }
+    
+    
+    /**
+     * Executes the method of the specified <code>ApplicationContext</code>
+     * @param method The method object to be invoked.
+     * @param context The AppliationContext object on which the method
+     *                   will be invoked
+     * @param params The arguments passed to the called method.
+     */
+    private Object executeMethod(final Method method, 
+                                 final ApplicationContext context,
+                                 final Object[] params) 
+            throws PrivilegedActionException, 
+                   IllegalAccessException,
+                   InvocationTargetException {
+                                     
+        if (SecurityUtil.isPackageProtectionEnabled()){
+           return AccessController.doPrivileged(new PrivilegedExceptionAction(){
+                public Object run() throws IllegalAccessException, InvocationTargetException{
+                    return method.invoke(context,  params);
+                }
+            });
+        } else {
+            return method.invoke(context, params);
+        }        
+    }
+
+    
+    /**
+     *
+     * Throw the real exception.
+     * @param ex The current exception
+     */
+    private void handleException(Exception ex, String methodName)
+	    throws Throwable {
+
+        Throwable realException;
+        
+        if (ex instanceof PrivilegedActionException) {
+            ex = ((PrivilegedActionException) ex).getException();
+        }
+        
+        if (ex instanceof InvocationTargetException) {
+            realException =
+                ((InvocationTargetException) ex).getTargetException();
+        } else {
+            realException = ex;
+        }   
+        
+        throw realException;
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/core/ApplicationDispatcher.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/core/ApplicationDispatcher.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/core/ApplicationDispatcher.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,961 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.IOException;
+import java.io.PrintWriter;
+import java.security.AccessController;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
+
+import javax.servlet.RequestDispatcher;
+import javax.servlet.Servlet;
+import javax.servlet.ServletException;
+import javax.servlet.ServletOutputStream;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletRequestWrapper;
+import javax.servlet.ServletResponse;
+import javax.servlet.ServletResponseWrapper;
+import javax.servlet.UnavailableException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.catalina.Context;
+import org.apache.catalina.Globals;
+import org.apache.catalina.InstanceEvent;
+import org.apache.catalina.Wrapper;
+import org.apache.catalina.connector.ClientAbortException;
+import org.apache.catalina.connector.Request;
+import org.apache.catalina.connector.RequestFacade;
+import org.apache.catalina.connector.Response;
+import org.apache.catalina.connector.ResponseFacade;
+import org.apache.catalina.util.InstanceSupport;
+import org.apache.catalina.util.StringManager;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * Standard implementation of <code>RequestDispatcher</code> that allows a
+ * request to be forwarded to a different resource to create the ultimate
+ * response, or to include the output of another resource in the response
+ * from this resource.  This implementation allows application level servlets
+ * to wrap the request and/or response objects that are passed on to the
+ * called resource, as long as the wrapping classes extend
+ * <code>javax.servlet.ServletRequestWrapper</code> and
+ * <code>javax.servlet.ServletResponseWrapper</code>.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 303947 $ $Date: 2005-06-09 00:50:26 -0500 (Thu, 09 Jun 2005) $
+ */
+
+final class ApplicationDispatcher
+    implements RequestDispatcher {
+
+
+    protected class PrivilegedForward implements PrivilegedExceptionAction {
+        private ServletRequest request;
+        private ServletResponse response;
+
+        PrivilegedForward(ServletRequest request, ServletResponse response)
+        {
+            this.request = request;
+            this.response = response;
+        }
+
+        public Object run() throws java.lang.Exception {
+            doForward(request,response);
+            return null;
+        }
+    }
+
+    protected class PrivilegedInclude implements PrivilegedExceptionAction {
+        private ServletRequest request;
+        private ServletResponse response;
+
+        PrivilegedInclude(ServletRequest request, ServletResponse response)
+        {
+            this.request = request;
+            this.response = response;
+        }
+
+        public Object run() throws ServletException, IOException {
+            doInclude(request,response);
+            return null;
+        }
+    }
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Construct a new instance of this class, configured according to the
+     * specified parameters.  If both servletPath and pathInfo are
+     * <code>null</code>, it will be assumed that this RequestDispatcher
+     * was acquired by name, rather than by path.
+     *
+     * @param wrapper The Wrapper associated with the resource that will
+     *  be forwarded to or included (required)
+     * @param requestURI The request URI to this resource (if any)
+     * @param servletPath The revised servlet path to this resource (if any)
+     * @param pathInfo The revised extra path information to this resource
+     *  (if any)
+     * @param queryString Query string parameters included with this request
+     *  (if any)
+     * @param name Servlet name (if a named dispatcher was created)
+     *  else <code>null</code>
+     */
+    public ApplicationDispatcher
+        (Wrapper wrapper, String requestURI, String servletPath,
+         String pathInfo, String queryString, String name) {
+
+        super();
+
+        // Save all of our configuration parameters
+        this.wrapper = wrapper;
+        this.context = (Context) wrapper.getParent();
+        this.requestURI = requestURI;
+        this.servletPath = servletPath;
+        this.origServletPath = servletPath;
+        this.pathInfo = pathInfo;
+        this.queryString = queryString;
+        this.name = name;
+        if (wrapper instanceof StandardWrapper)
+            this.support = ((StandardWrapper) wrapper).getInstanceSupport();
+        else
+            this.support = new InstanceSupport(wrapper);
+
+        if ( log.isDebugEnabled() )
+            log.debug("servletPath=" + this.servletPath + ", pathInfo=" +
+                this.pathInfo + ", queryString=" + queryString +
+                ", name=" + this.name);
+
+    }
+
+
+    // ----------------------------------------------------- Instance Variables
+
+    private static Log log = LogFactory.getLog(ApplicationDispatcher.class);
+
+    /**
+     * The request specified by the dispatching application.
+     */
+    private ServletRequest appRequest = null;
+
+
+    /**
+     * The response specified by the dispatching application.
+     */
+    private ServletResponse appResponse = null;
+
+
+    /**
+     * The Context this RequestDispatcher is associated with.
+     */
+    private Context context = null;
+
+
+    /**
+     * Are we performing an include() instead of a forward()?
+     */
+    private boolean including = false;
+
+
+    /**
+     * Descriptive information about this implementation.
+     */
+    private static final String info =
+        "org.apache.catalina.core.ApplicationDispatcher/1.0";
+
+
+    /**
+     * The servlet name for a named dispatcher.
+     */
+    private String name = null;
+
+
+    /**
+     * The outermost request that will be passed on to the invoked servlet.
+     */
+    private ServletRequest outerRequest = null;
+
+
+    /**
+     * The outermost response that will be passed on to the invoked servlet.
+     */
+    private ServletResponse outerResponse = null;
+
+
+    /**
+     * The extra path information for this RequestDispatcher.
+     */
+    private String pathInfo = null;
+
+
+    /**
+     * The query string parameters for this RequestDispatcher.
+     */
+    private String queryString = null;
+
+
+    /**
+     * The request URI for this RequestDispatcher.
+     */
+    private String requestURI = null;
+
+    /**
+     * The servlet path for this RequestDispatcher.
+     */
+    private String servletPath = null;
+
+    private String origServletPath = null;
+    
+    /**
+     * The StringManager for this package.
+     */
+    private static final StringManager sm =
+      StringManager.getManager(Constants.Package);
+
+
+    /**
+     * The InstanceSupport instance associated with our Wrapper (used to
+     * send "before dispatch" and "after dispatch" events.
+     */
+    private InstanceSupport support = null;
+
+
+    /**
+     * The Wrapper associated with the resource that will be forwarded to
+     * or included.
+     */
+    private Wrapper wrapper = null;
+
+
+    /**
+     * The request wrapper we have created and installed (if any).
+     */
+    private ServletRequest wrapRequest = null;
+
+
+    /**
+     * The response wrapper we have created and installed (if any).
+     */
+    private ServletResponse wrapResponse = null;
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * Return the descriptive information about this implementation.
+     */
+    public String getInfo() {
+
+        return (info);
+
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Forward this request and response to another resource for processing.
+     * Any runtime exception, IOException, or ServletException thrown by the
+     * called servlet will be propogated to the caller.
+     *
+     * @param request The servlet request to be forwarded
+     * @param response The servlet response to be forwarded
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception ServletException if a servlet exception occurs
+     */
+    public void forward(ServletRequest request, ServletResponse response)
+        throws ServletException, IOException
+    {
+        if (System.getSecurityManager() != null) {
+            try {
+                PrivilegedForward dp = new PrivilegedForward(request,response);
+                AccessController.doPrivileged(dp);
+            } catch (PrivilegedActionException pe) {
+                Exception e = pe.getException();
+                if (e instanceof ServletException)
+                    throw (ServletException) e;
+                throw (IOException) e;
+            }
+        } else {
+            doForward(request,response);
+        }
+    }
+
+    private void doForward(ServletRequest request, ServletResponse response)
+        throws ServletException, IOException
+    {
+        
+        // Reset any output that has been buffered, but keep headers/cookies
+        if (response.isCommitted()) {
+            if ( log.isDebugEnabled() )
+                log.debug("  Forward on committed response --> ISE");
+            throw new IllegalStateException
+                (sm.getString("applicationDispatcher.forward.ise"));
+        }
+        try {
+            response.resetBuffer();
+        } catch (IllegalStateException e) {
+            if ( log.isDebugEnabled() )
+                log.debug("  Forward resetBuffer() returned ISE: " + e);
+            throw e;
+        }
+
+        // Set up to handle the specified request and response
+        setup(request, response, false);
+
+        // Identify the HTTP-specific request and response objects (if any)
+        HttpServletRequest hrequest = null;
+        if (request instanceof HttpServletRequest)
+            hrequest = (HttpServletRequest) request;
+        HttpServletResponse hresponse = null;
+        if (response instanceof HttpServletResponse)
+            hresponse = (HttpServletResponse) response;
+
+        // Handle a non-HTTP forward by passing the existing request/response
+        if ((hrequest == null) || (hresponse == null)) {
+
+            if ( log.isDebugEnabled() )
+                log.debug(" Non-HTTP Forward");
+            
+            processRequest(hrequest,hresponse);
+
+        }
+
+        // Handle an HTTP named dispatcher forward
+        else if ((servletPath == null) && (pathInfo == null)) {
+
+            if ( log.isDebugEnabled() )
+                log.debug(" Named Dispatcher Forward");
+            
+            ApplicationHttpRequest wrequest =
+                (ApplicationHttpRequest) wrapRequest();
+            wrequest.setRequestURI(hrequest.getRequestURI());
+            wrequest.setContextPath(hrequest.getContextPath());
+            wrequest.setServletPath(hrequest.getServletPath());
+            wrequest.setPathInfo(hrequest.getPathInfo());
+            wrequest.setQueryString(hrequest.getQueryString());
+
+            processRequest(request,response);
+
+            wrequest.recycle();
+            unwrapRequest();
+
+        }
+
+        // Handle an HTTP path-based forward
+        else {
+
+            if ( log.isDebugEnabled() )
+                log.debug(" Path Based Forward");
+
+            ApplicationHttpRequest wrequest =
+                (ApplicationHttpRequest) wrapRequest();
+            String contextPath = context.getPath();
+
+            if (hrequest.getAttribute(Globals.FORWARD_REQUEST_URI_ATTR) == null) {
+                wrequest.setAttribute(Globals.FORWARD_REQUEST_URI_ATTR,
+                                      hrequest.getRequestURI());
+                wrequest.setAttribute(Globals.FORWARD_CONTEXT_PATH_ATTR,
+                                      hrequest.getContextPath());
+                wrequest.setAttribute(Globals.FORWARD_SERVLET_PATH_ATTR,
+                                      hrequest.getServletPath());
+                wrequest.setAttribute(Globals.FORWARD_PATH_INFO_ATTR,
+                                      hrequest.getPathInfo());
+                wrequest.setAttribute(Globals.FORWARD_QUERY_STRING_ATTR,
+                                      hrequest.getQueryString());
+            }
+ 
+            wrequest.setContextPath(contextPath);
+            wrequest.setRequestURI(requestURI);
+            wrequest.setServletPath(servletPath);
+            wrequest.setPathInfo(pathInfo);
+            if (queryString != null) {
+                wrequest.setQueryString(queryString);
+                wrequest.setQueryParams(queryString);
+            }
+
+            processRequest(request,response);
+
+            wrequest.recycle();
+            unwrapRequest();
+
+        }
+
+        // This is not a real close in order to support error processing
+        if ( log.isDebugEnabled() )
+            log.debug(" Disabling the response for futher output");
+
+        if  (response instanceof ResponseFacade) {
+            ((ResponseFacade) response).finish();
+        } else {
+            // Servlet SRV.6.2.2. The Resquest/Response may have been wrapped
+            // and may no longer be instance of RequestFacade 
+            if (log.isDebugEnabled()){
+                log.debug( " The Response is vehiculed using a wrapper: " 
+                           + response.getClass().getName() );
+            }
+
+            // Close anyway
+            try {
+                PrintWriter writer = response.getWriter();
+                writer.close();
+            } catch (IllegalStateException e) {
+                try {
+                    ServletOutputStream stream = response.getOutputStream();
+                    stream.close();
+                } catch (IllegalStateException f) {
+                    ;
+                } catch (IOException f) {
+                    ;
+                }
+            } catch (IOException e) {
+                ;
+            }
+        }
+
+    }
+
+    
+
+    /**
+     * Prepare the request based on the filter configuration.
+     * @param request The servlet request we are processing
+     * @param response The servlet response we are creating
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception ServletException if a servlet error occurs
+     */
+    private void processRequest(ServletRequest request, 
+                                ServletResponse response)
+        throws IOException, ServletException {
+                
+        Integer disInt = (Integer) request.getAttribute
+            (ApplicationFilterFactory.DISPATCHER_TYPE_ATTR);
+        if (disInt != null) {
+            if (disInt.intValue() != ApplicationFilterFactory.ERROR) {
+                outerRequest.setAttribute
+                    (ApplicationFilterFactory.DISPATCHER_REQUEST_PATH_ATTR,
+                     origServletPath);
+                outerRequest.setAttribute
+                    (ApplicationFilterFactory.DISPATCHER_TYPE_ATTR,
+                     new Integer(ApplicationFilterFactory.FORWARD));
+                invoke(outerRequest, response);
+            } else {
+                invoke(outerRequest, response);
+            }
+        }
+
+    }
+    
+    
+    
+    /**
+     * Include the response from another resource in the current response.
+     * Any runtime exception, IOException, or ServletException thrown by the
+     * called servlet will be propogated to the caller.
+     *
+     * @param request The servlet request that is including this one
+     * @param response The servlet response to be appended to
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception ServletException if a servlet exception occurs
+     */
+    public void include(ServletRequest request, ServletResponse response)
+        throws ServletException, IOException
+    {
+        if (System.getSecurityManager() != null) {
+            try {
+                PrivilegedInclude dp = new PrivilegedInclude(request,response);
+                AccessController.doPrivileged(dp);
+            } catch (PrivilegedActionException pe) {
+                Exception e = pe.getException();
+
+                if (e instanceof ServletException)
+                    throw (ServletException) e;
+                throw (IOException) e;
+            }
+        } else {
+            doInclude(request,response);
+        }
+    }
+
+    private void doInclude(ServletRequest request, ServletResponse response)
+        throws ServletException, IOException
+    {
+        // Set up to handle the specified request and response
+        setup(request, response, true);
+
+        // Create a wrapped response to use for this request
+        // ServletResponse wresponse = null;
+        ServletResponse wresponse = wrapResponse();
+
+        // Handle a non-HTTP include
+        if (!(request instanceof HttpServletRequest) ||
+            !(response instanceof HttpServletResponse)) {
+
+            if ( log.isDebugEnabled() )
+                log.debug(" Non-HTTP Include");
+            request.setAttribute(ApplicationFilterFactory.DISPATCHER_TYPE_ATTR,
+                                             new Integer(ApplicationFilterFactory.INCLUDE));
+            request.setAttribute(ApplicationFilterFactory.DISPATCHER_REQUEST_PATH_ATTR, origServletPath);
+            invoke(request, outerResponse);
+        }
+
+        // Handle an HTTP named dispatcher include
+        else if (name != null) {
+
+            if ( log.isDebugEnabled() )
+                log.debug(" Named Dispatcher Include");
+
+            ApplicationHttpRequest wrequest =
+                (ApplicationHttpRequest) wrapRequest();
+            wrequest.setAttribute(Globals.NAMED_DISPATCHER_ATTR, name);
+            if (servletPath != null)
+                wrequest.setServletPath(servletPath);
+            wrequest.setAttribute(ApplicationFilterFactory.DISPATCHER_TYPE_ATTR,
+                                             new Integer(ApplicationFilterFactory.INCLUDE));
+            wrequest.setAttribute(ApplicationFilterFactory.DISPATCHER_REQUEST_PATH_ATTR, origServletPath);
+            invoke(outerRequest, outerResponse);
+
+            wrequest.recycle();
+        }
+
+        // Handle an HTTP path based include
+        else {
+
+            if ( log.isDebugEnabled() )
+                log.debug(" Path Based Include");
+
+            ApplicationHttpRequest wrequest =
+                (ApplicationHttpRequest) wrapRequest();
+            String contextPath = context.getPath();
+            if (requestURI != null)
+                wrequest.setAttribute(Globals.INCLUDE_REQUEST_URI_ATTR,
+                                      requestURI);
+            if (contextPath != null)
+                wrequest.setAttribute(Globals.INCLUDE_CONTEXT_PATH_ATTR,
+                                      contextPath);
+            if (servletPath != null)
+                wrequest.setAttribute(Globals.INCLUDE_SERVLET_PATH_ATTR,
+                                      servletPath);
+            if (pathInfo != null)
+                wrequest.setAttribute(Globals.INCLUDE_PATH_INFO_ATTR,
+                                      pathInfo);
+            if (queryString != null) {
+                wrequest.setAttribute(Globals.INCLUDE_QUERY_STRING_ATTR,
+                                      queryString);
+                wrequest.setQueryParams(queryString);
+            }
+            
+            wrequest.setAttribute(ApplicationFilterFactory.DISPATCHER_TYPE_ATTR,
+                                             new Integer(ApplicationFilterFactory.INCLUDE));
+            wrequest.setAttribute(ApplicationFilterFactory.DISPATCHER_REQUEST_PATH_ATTR, origServletPath);
+            invoke(outerRequest, outerResponse);
+
+            wrequest.recycle();
+        }
+
+    }
+
+
+    // -------------------------------------------------------- Private Methods
+
+
+    /**
+     * Ask the resource represented by this RequestDispatcher to process
+     * the associated request, and create (or append to) the associated
+     * response.
+     * <p>
+     * <strong>IMPLEMENTATION NOTE</strong>: This implementation assumes
+     * that no filters are applied to a forwarded or included resource,
+     * because they were already done for the original request.
+     *
+     * @param request The servlet request we are processing
+     * @param response The servlet response we are creating
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception ServletException if a servlet error occurs
+     */
+    private void invoke(ServletRequest request, ServletResponse response)
+            throws IOException, ServletException {
+
+        // Checking to see if the context classloader is the current context
+        // classloader. If it's not, we're saving it, and setting the context
+        // classloader to the Context classloader
+        ClassLoader oldCCL = Thread.currentThread().getContextClassLoader();
+        ClassLoader contextClassLoader = context.getLoader().getClassLoader();
+
+        if (oldCCL != contextClassLoader) {
+            Thread.currentThread().setContextClassLoader(contextClassLoader);
+        } else {
+            oldCCL = null;
+        }
+
+        // Initialize local variables we may need
+        HttpServletRequest hrequest = (HttpServletRequest) request;
+        HttpServletResponse hresponse = (HttpServletResponse) response;
+        Servlet servlet = null;
+        IOException ioException = null;
+        ServletException servletException = null;
+        RuntimeException runtimeException = null;
+        boolean unavailable = false;
+
+        // Check for the servlet being marked unavailable
+        if (wrapper.isUnavailable()) {
+            wrapper.getLogger().warn(
+                    sm.getString("applicationDispatcher.isUnavailable", 
+                    wrapper.getName()));
+            long available = wrapper.getAvailable();
+            if ((available > 0L) && (available < Long.MAX_VALUE))
+                hresponse.setDateHeader("Retry-After", available);
+            hresponse.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE, sm
+                    .getString("applicationDispatcher.isUnavailable", wrapper
+                            .getName()));
+            unavailable = true;
+        }
+
+        // Allocate a servlet instance to process this request
+        try {
+            if (!unavailable) {
+                servlet = wrapper.allocate();
+            }
+        } catch (ServletException e) {
+            wrapper.getLogger().error(sm.getString("applicationDispatcher.allocateException",
+                             wrapper.getName()), StandardWrapper.getRootCause(e));
+            servletException = e;
+            servlet = null;
+        } catch (Throwable e) {
+            wrapper.getLogger().error(sm.getString("applicationDispatcher.allocateException",
+                             wrapper.getName()), e);
+            servletException = new ServletException
+                (sm.getString("applicationDispatcher.allocateException",
+                              wrapper.getName()), e);
+            servlet = null;
+        }
+                
+        // Get the FilterChain Here
+        ApplicationFilterFactory factory = ApplicationFilterFactory.getInstance();
+        ApplicationFilterChain filterChain = factory.createFilterChain(request,
+                                                                wrapper,servlet);
+        // Call the service() method for the allocated servlet instance
+        try {
+            String jspFile = wrapper.getJspFile();
+            if (jspFile != null)
+                request.setAttribute(Globals.JSP_FILE_ATTR, jspFile);
+            else
+                request.removeAttribute(Globals.JSP_FILE_ATTR);
+            support.fireInstanceEvent(InstanceEvent.BEFORE_DISPATCH_EVENT,
+                                      servlet, request, response);
+            // for includes/forwards
+            if ((servlet != null) && (filterChain != null)) {
+               filterChain.doFilter(request, response);
+             }
+            // Servlet Service Method is called by the FilterChain
+            request.removeAttribute(Globals.JSP_FILE_ATTR);
+            support.fireInstanceEvent(InstanceEvent.AFTER_DISPATCH_EVENT,
+                                      servlet, request, response);
+        } catch (ClientAbortException e) {
+            request.removeAttribute(Globals.JSP_FILE_ATTR);
+            support.fireInstanceEvent(InstanceEvent.AFTER_DISPATCH_EVENT,
+                                      servlet, request, response);
+            ioException = e;
+        } catch (IOException e) {
+            request.removeAttribute(Globals.JSP_FILE_ATTR);
+            support.fireInstanceEvent(InstanceEvent.AFTER_DISPATCH_EVENT,
+                                      servlet, request, response);
+            wrapper.getLogger().error(sm.getString("applicationDispatcher.serviceException",
+                             wrapper.getName()), e);
+            ioException = e;
+        } catch (UnavailableException e) {
+            request.removeAttribute(Globals.JSP_FILE_ATTR);
+            support.fireInstanceEvent(InstanceEvent.AFTER_DISPATCH_EVENT,
+                                      servlet, request, response);
+            wrapper.getLogger().error(sm.getString("applicationDispatcher.serviceException",
+                             wrapper.getName()), e);
+            servletException = e;
+            wrapper.unavailable(e);
+        } catch (ServletException e) {
+            request.removeAttribute(Globals.JSP_FILE_ATTR);
+            support.fireInstanceEvent(InstanceEvent.AFTER_DISPATCH_EVENT,
+                                      servlet, request, response);
+            Throwable rootCause = StandardWrapper.getRootCause(e);
+            if (!(rootCause instanceof ClientAbortException)) {
+                wrapper.getLogger().error(sm.getString("applicationDispatcher.serviceException",
+                        wrapper.getName()), rootCause);
+            }
+            servletException = e;
+        } catch (RuntimeException e) {
+            request.removeAttribute(Globals.JSP_FILE_ATTR);
+            support.fireInstanceEvent(InstanceEvent.AFTER_DISPATCH_EVENT,
+                                      servlet, request, response);
+            wrapper.getLogger().error(sm.getString("applicationDispatcher.serviceException",
+                             wrapper.getName()), e);
+            runtimeException = e;
+        }
+
+        // Release the filter chain (if any) for this request
+        try {
+            if (filterChain != null)
+                filterChain.release();
+        } catch (Throwable e) {
+            log.error(sm.getString("standardWrapper.releaseFilters",
+                             wrapper.getName()), e);
+          //FIXME Exception handling needs to be simpiler to what is in the StandardWrapperValue
+        }
+
+        // Deallocate the allocated servlet instance
+        try {
+            if (servlet != null) {
+                wrapper.deallocate(servlet);
+            }
+        } catch (ServletException e) {
+            wrapper.getLogger().error(sm.getString("applicationDispatcher.deallocateException",
+                             wrapper.getName()), e);
+            servletException = e;
+        } catch (Throwable e) {
+            wrapper.getLogger().error(sm.getString("applicationDispatcher.deallocateException",
+                             wrapper.getName()), e);
+            servletException = new ServletException
+                (sm.getString("applicationDispatcher.deallocateException",
+                              wrapper.getName()), e);
+        }
+
+        // Reset the old context class loader
+        if (oldCCL != null)
+            Thread.currentThread().setContextClassLoader(oldCCL);
+        
+        // Unwrap request/response if needed
+        // See Bugzilla 30949
+        unwrapRequest();
+        unwrapResponse();
+
+        // Rethrow an exception if one was thrown by the invoked servlet
+        if (ioException != null)
+            throw ioException;
+        if (servletException != null)
+            throw servletException;
+        if (runtimeException != null)
+            throw runtimeException;
+
+    }
+
+
+    /**
+     * Set up to handle the specified request and response
+     *
+     * @param request The servlet request specified by the caller
+     * @param response The servlet response specified by the caller
+     * @param including Are we performing an include() as opposed to
+     *  a forward()?
+     */
+    private void setup(ServletRequest request, ServletResponse response,
+                       boolean including) {
+
+        this.appRequest = request;
+        this.appResponse = response;
+        this.outerRequest = request;
+        this.outerResponse = response;
+        this.including = including;
+
+    }
+
+
+    /**
+     * Unwrap the request if we have wrapped it.
+     */
+    private void unwrapRequest() {
+
+        if (wrapRequest == null)
+            return;
+
+        ServletRequest previous = null;
+        ServletRequest current = outerRequest;
+        while (current != null) {
+
+            // If we run into the container request we are done
+            if ((current instanceof Request)
+                || (current instanceof RequestFacade))
+                break;
+
+            // Remove the current request if it is our wrapper
+            if (current == wrapRequest) {
+                ServletRequest next =
+                  ((ServletRequestWrapper) current).getRequest();
+                if (previous == null)
+                    outerRequest = next;
+                else
+                    ((ServletRequestWrapper) previous).setRequest(next);
+                break;
+            }
+
+            // Advance to the next request in the chain
+            previous = current;
+            current = ((ServletRequestWrapper) current).getRequest();
+
+        }
+
+    }
+
+
+    /**
+     * Unwrap the response if we have wrapped it.
+     */
+    private void unwrapResponse() {
+
+        if (wrapResponse == null)
+            return;
+
+        ServletResponse previous = null;
+        ServletResponse current = outerResponse;
+        while (current != null) {
+
+            // If we run into the container response we are done
+            if ((current instanceof Response)
+                || (current instanceof ResponseFacade))
+                break;
+
+            // Remove the current response if it is our wrapper
+            if (current == wrapResponse) {
+                ServletResponse next =
+                  ((ServletResponseWrapper) current).getResponse();
+                if (previous == null)
+                    outerResponse = next;
+                else
+                    ((ServletResponseWrapper) previous).setResponse(next);
+                break;
+            }
+
+            // Advance to the next response in the chain
+            previous = current;
+            current = ((ServletResponseWrapper) current).getResponse();
+
+        }
+
+    }
+
+
+    /**
+     * Create and return a request wrapper that has been inserted in the
+     * appropriate spot in the request chain.
+     */
+    private ServletRequest wrapRequest() {
+
+        // Locate the request we should insert in front of
+        ServletRequest previous = null;
+        ServletRequest current = outerRequest;
+        while (current != null) {
+            if ("org.apache.catalina.servlets.InvokerHttpRequest".
+                equals(current.getClass().getName()))
+                break; // KLUDGE - Make nested RD.forward() using invoker work
+            if (!(current instanceof ServletRequestWrapper))
+                break;
+            if (current instanceof ApplicationHttpRequest)
+                break;
+            if (current instanceof ApplicationRequest)
+                break;
+            if (current instanceof Request)
+                break;
+            previous = current;
+            current = ((ServletRequestWrapper) current).getRequest();
+        }
+
+        // Instantiate a new wrapper at this point and insert it in the chain
+        ServletRequest wrapper = null;
+        if ((current instanceof ApplicationHttpRequest) ||
+            (current instanceof Request) ||
+            (current instanceof HttpServletRequest)) {
+            // Compute a crossContext flag
+            HttpServletRequest hcurrent = (HttpServletRequest) current;
+            boolean crossContext = false;
+            if ((outerRequest instanceof ApplicationHttpRequest) ||
+                (outerRequest instanceof Request) ||
+                (outerRequest instanceof HttpServletRequest)) {
+                HttpServletRequest houterRequest = 
+                    (HttpServletRequest) outerRequest;
+                Object contextPath = houterRequest.getAttribute
+                    (Globals.INCLUDE_CONTEXT_PATH_ATTR);
+                if (contextPath == null) {
+                    // Forward
+                    contextPath = houterRequest.getContextPath();
+                }
+                crossContext = !(context.getPath().equals(contextPath));
+            }
+            wrapper = new ApplicationHttpRequest
+                (hcurrent, context, crossContext);
+        } else {
+            wrapper = new ApplicationRequest(current);
+        }
+        if (previous == null)
+            outerRequest = wrapper;
+        else
+            ((ServletRequestWrapper) previous).setRequest(wrapper);
+        wrapRequest = wrapper;
+        return (wrapper);
+
+    }
+
+
+    /**
+     * Create and return a response wrapper that has been inserted in the
+     * appropriate spot in the response chain.
+     */
+    private ServletResponse wrapResponse() {
+
+        // Locate the response we should insert in front of
+        ServletResponse previous = null;
+        ServletResponse current = outerResponse;
+        while (current != null) {
+            if (!(current instanceof ServletResponseWrapper))
+                break;
+            if (current instanceof ApplicationHttpResponse)
+                break;
+            if (current instanceof ApplicationResponse)
+                break;
+            if (current instanceof Response)
+                break;
+            previous = current;
+            current = ((ServletResponseWrapper) current).getResponse();
+        }
+
+        // Instantiate a new wrapper at this point and insert it in the chain
+        ServletResponse wrapper = null;
+        if ((current instanceof ApplicationHttpResponse) ||
+            (current instanceof Response) ||
+            (current instanceof HttpServletResponse))
+            wrapper =
+                new ApplicationHttpResponse((HttpServletResponse) current,
+                                            including);
+        else
+            wrapper = new ApplicationResponse(current, including);
+        if (previous == null)
+            outerResponse = wrapper;
+        else
+            ((ServletResponseWrapper) previous).setResponse(wrapper);
+        wrapResponse = wrapper;
+        return (wrapper);
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/core/ApplicationFilterChain.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/core/ApplicationFilterChain.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/core/ApplicationFilterChain.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,342 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.IOException;
+import java.security.Principal;
+import java.security.PrivilegedActionException;
+
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.Servlet;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.catalina.InstanceEvent;
+import org.apache.catalina.security.SecurityUtil;
+import org.apache.catalina.util.InstanceSupport;
+import org.apache.catalina.util.StringManager;
+
+/**
+ * Implementation of <code>javax.servlet.FilterChain</code> used to manage
+ * the execution of a set of filters for a particular request.  When the
+ * set of defined filters has all been executed, the next call to
+ * <code>doFilter()</code> will execute the servlet's <code>service()</code>
+ * method itself.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 303523 $ $Date: 2004-11-22 10:35:18 -0600 (Mon, 22 Nov 2004) $
+ */
+
+final class ApplicationFilterChain implements FilterChain {
+
+
+    // -------------------------------------------------------------- Constants
+
+
+    public static final int INCREMENT = 10;
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Construct a new chain instance with no defined filters.
+     */
+    public ApplicationFilterChain() {
+
+        super();
+
+    }
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * Filters.
+     */
+    private ApplicationFilterConfig[] filters = 
+        new ApplicationFilterConfig[0];
+
+
+    /**
+     * The int which is used to maintain the current position 
+     * in the filter chain.
+     */
+    private int pos = 0;
+
+
+    /**
+     * The int which gives the current number of filters in the chain.
+     */
+    private int n = 0;
+
+
+    /**
+     * The servlet instance to be executed by this chain.
+     */
+    private Servlet servlet = null;
+
+
+    /**
+     * The string manager for our package.
+     */
+    private static final StringManager sm =
+      StringManager.getManager(Constants.Package);
+
+
+    /**
+     * The InstanceSupport instance associated with our Wrapper (used to
+     * send "before filter" and "after filter" events.
+     */
+    private InstanceSupport support = null;
+
+    
+    /**
+     * Static class array used when the SecurityManager is turned on and 
+     * <code>doFilter</code is invoked.
+     */
+    private static Class[] classType = new Class[]{ServletRequest.class, 
+                                                   ServletResponse.class,
+                                                   FilterChain.class};
+                                                   
+    /**
+     * Static class array used when the SecurityManager is turned on and 
+     * <code>service</code is invoked.
+     */                                                 
+    private static Class[] classTypeUsedInService = new Class[]{
+                                                         ServletRequest.class,
+                                                         ServletResponse.class};
+
+    // ---------------------------------------------------- FilterChain Methods
+
+
+    /**
+     * Invoke the next filter in this chain, passing the specified request
+     * and response.  If there are no more filters in this chain, invoke
+     * the <code>service()</code> method of the servlet itself.
+     *
+     * @param request The servlet request we are processing
+     * @param response The servlet response we are creating
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception ServletException if a servlet exception occurs
+     */
+    public void doFilter(ServletRequest request, ServletResponse response)
+        throws IOException, ServletException {
+
+        if( System.getSecurityManager() != null ) {
+            final ServletRequest req = request;
+            final ServletResponse res = response;
+            try {
+                java.security.AccessController.doPrivileged(
+                    new java.security.PrivilegedExceptionAction() {
+                        public Object run() 
+                            throws ServletException, IOException {
+                            internalDoFilter(req,res);
+                            return null;
+                        }
+                    }
+                );
+            } catch( PrivilegedActionException pe) {
+                Exception e = pe.getException();
+                if (e instanceof ServletException)
+                    throw (ServletException) e;
+                else if (e instanceof IOException)
+                    throw (IOException) e;
+                else if (e instanceof RuntimeException)
+                    throw (RuntimeException) e;
+                else
+                    throw new ServletException(e.getMessage(), e);
+            }
+        } else {
+            internalDoFilter(request,response);
+        }
+    }
+
+    private void internalDoFilter(ServletRequest request, 
+                                  ServletResponse response)
+        throws IOException, ServletException {
+
+        // Call the next filter if there is one
+        if (pos < n) {
+            ApplicationFilterConfig filterConfig = filters[pos++];
+            Filter filter = null;
+            try {
+                filter = filterConfig.getFilter();
+                support.fireInstanceEvent(InstanceEvent.BEFORE_FILTER_EVENT,
+                                          filter, request, response);
+                
+                if( System.getSecurityManager() != null ) {
+                    final ServletRequest req = request;
+                    final ServletResponse res = response;
+                    Principal principal = 
+                        ((HttpServletRequest) req).getUserPrincipal();
+
+                    Object[] args = new Object[]{req, res, this};
+                    SecurityUtil.doAsPrivilege
+                        ("doFilter", filter, classType, args);
+                    
+                    args = null;
+                } else {  
+                    filter.doFilter(request, response, this);
+                }
+
+                support.fireInstanceEvent(InstanceEvent.AFTER_FILTER_EVENT,
+                                          filter, request, response);
+            } catch (IOException e) {
+                if (filter != null)
+                    support.fireInstanceEvent(InstanceEvent.AFTER_FILTER_EVENT,
+                                              filter, request, response, e);
+                throw e;
+            } catch (ServletException e) {
+                if (filter != null)
+                    support.fireInstanceEvent(InstanceEvent.AFTER_FILTER_EVENT,
+                                              filter, request, response, e);
+                throw e;
+            } catch (RuntimeException e) {
+                if (filter != null)
+                    support.fireInstanceEvent(InstanceEvent.AFTER_FILTER_EVENT,
+                                              filter, request, response, e);
+                throw e;
+            } catch (Throwable e) {
+                if (filter != null)
+                    support.fireInstanceEvent(InstanceEvent.AFTER_FILTER_EVENT,
+                                              filter, request, response, e);
+                throw new ServletException
+                  (sm.getString("filterChain.filter"), e);
+            }
+            return;
+        }
+
+        // We fell off the end of the chain -- call the servlet instance
+        try {
+            support.fireInstanceEvent(InstanceEvent.BEFORE_SERVICE_EVENT,
+                                      servlet, request, response);
+            if ((request instanceof HttpServletRequest) &&
+                (response instanceof HttpServletResponse)) {
+                    
+                if( System.getSecurityManager() != null ) {
+                    final ServletRequest req = request;
+                    final ServletResponse res = response;
+                    Principal principal = 
+                        ((HttpServletRequest) req).getUserPrincipal();
+                    Object[] args = new Object[]{req, res};
+                    SecurityUtil.doAsPrivilege("service",
+                                               servlet,
+                                               classTypeUsedInService, 
+                                               args,
+                                               principal);   
+                    args = null;
+                } else {  
+                    servlet.service((HttpServletRequest) request,
+                                    (HttpServletResponse) response);
+                }
+            } else {
+                servlet.service(request, response);
+            }
+            support.fireInstanceEvent(InstanceEvent.AFTER_SERVICE_EVENT,
+                                      servlet, request, response);
+        } catch (IOException e) {
+            support.fireInstanceEvent(InstanceEvent.AFTER_SERVICE_EVENT,
+                                      servlet, request, response, e);
+            throw e;
+        } catch (ServletException e) {
+            support.fireInstanceEvent(InstanceEvent.AFTER_SERVICE_EVENT,
+                                      servlet, request, response, e);
+            throw e;
+        } catch (RuntimeException e) {
+            support.fireInstanceEvent(InstanceEvent.AFTER_SERVICE_EVENT,
+                                      servlet, request, response, e);
+            throw e;
+        } catch (Throwable e) {
+            support.fireInstanceEvent(InstanceEvent.AFTER_SERVICE_EVENT,
+                                      servlet, request, response, e);
+            throw new ServletException
+              (sm.getString("filterChain.servlet"), e);
+        }
+
+    }
+
+
+    // -------------------------------------------------------- Package Methods
+
+
+
+    /**
+     * Add a filter to the set of filters that will be executed in this chain.
+     *
+     * @param filterConfig The FilterConfig for the servlet to be executed
+     */
+    void addFilter(ApplicationFilterConfig filterConfig) {
+
+        if (n == filters.length) {
+            ApplicationFilterConfig[] newFilters =
+                new ApplicationFilterConfig[n + INCREMENT];
+            System.arraycopy(filters, 0, newFilters, 0, n);
+            filters = newFilters;
+        }
+        filters[n++] = filterConfig;
+
+    }
+
+
+    /**
+     * Release references to the filters and wrapper executed by this chain.
+     */
+    void release() {
+
+        n = 0;
+        pos = 0;
+        servlet = null;
+        support = null;
+
+    }
+
+
+    /**
+     * Set the servlet that will be executed at the end of this chain.
+     *
+     * @param servlet The Wrapper for the servlet to be executed
+     */
+    void setServlet(Servlet servlet) {
+
+        this.servlet = servlet;
+
+    }
+
+
+    /**
+     * Set the InstanceSupport object used for event notifications
+     * for this filter chain.
+     *
+     * @param support The InstanceSupport object for our Wrapper
+     */
+    void setSupport(InstanceSupport support) {
+
+        this.support = support;
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/core/ApplicationFilterConfig.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/core/ApplicationFilterConfig.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/core/ApplicationFilterConfig.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,314 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.Serializable;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.Map;
+
+import javax.servlet.Filter;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+
+import org.apache.catalina.Context;
+import org.apache.catalina.deploy.FilterDef;
+import org.apache.catalina.security.SecurityUtil;
+import org.apache.catalina.util.Enumerator;
+import org.apache.tomcat.util.log.SystemLogHandler;
+
+
+/**
+ * Implementation of a <code>javax.servlet.FilterConfig</code> useful in
+ * managing the filter instances instantiated when a web application
+ * is first started.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 355530 $ $Date: 2005-12-09 10:42:23 -0600 (Fri, 09 Dec 2005) $
+ */
+
+final class ApplicationFilterConfig implements FilterConfig, Serializable {
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Construct a new ApplicationFilterConfig for the specified filter
+     * definition.
+     *
+     * @param context The context with which we are associated
+     * @param filterDef Filter definition for which a FilterConfig is to be
+     *  constructed
+     *
+     * @exception ClassCastException if the specified class does not implement
+     *  the <code>javax.servlet.Filter</code> interface
+     * @exception ClassNotFoundException if the filter class cannot be found
+     * @exception IllegalAccessException if the filter class cannot be
+     *  publicly instantiated
+     * @exception InstantiationException if an exception occurs while
+     *  instantiating the filter object
+     * @exception ServletException if thrown by the filter's init() method
+     */
+    public ApplicationFilterConfig(Context context, FilterDef filterDef)
+        throws ClassCastException, ClassNotFoundException,
+               IllegalAccessException, InstantiationException,
+               ServletException {
+
+        super();
+        this.context = context;
+        setFilterDef(filterDef);
+
+    }
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The Context with which we are associated.
+     */
+    private Context context = null;
+
+
+    /**
+     * The application Filter we are configured for.
+     */
+    private transient Filter filter = null;
+
+
+    /**
+     * The <code>FilterDef</code> that defines our associated Filter.
+     */
+    private FilterDef filterDef = null;
+
+
+    // --------------------------------------------------- FilterConfig Methods
+
+
+    /**
+     * Return the name of the filter we are configuring.
+     */
+    public String getFilterName() {
+
+        return (filterDef.getFilterName());
+
+    }
+
+
+    /**
+     * Return a <code>String</code> containing the value of the named
+     * initialization parameter, or <code>null</code> if the parameter
+     * does not exist.
+     *
+     * @param name Name of the requested initialization parameter
+     */
+    public String getInitParameter(String name) {
+
+        Map map = filterDef.getParameterMap();
+        if (map == null)
+            return (null);
+        else
+            return ((String) map.get(name));
+
+    }
+
+
+    /**
+     * Return an <code>Enumeration</code> of the names of the initialization
+     * parameters for this Filter.
+     */
+    public Enumeration getInitParameterNames() {
+
+        Map map = filterDef.getParameterMap();
+        if (map == null)
+            return (new Enumerator(new ArrayList()));
+        else
+            return (new Enumerator(map.keySet()));
+
+    }
+
+
+    /**
+     * Return the ServletContext of our associated web application.
+     */
+    public ServletContext getServletContext() {
+
+        return (this.context.getServletContext());
+
+    }
+
+
+    /**
+     * Return a String representation of this object.
+     */
+    public String toString() {
+
+        StringBuffer sb = new StringBuffer("ApplicationFilterConfig[");
+        sb.append("name=");
+        sb.append(filterDef.getFilterName());
+        sb.append(", filterClass=");
+        sb.append(filterDef.getFilterClass());
+        sb.append("]");
+        return (sb.toString());
+
+    }
+
+
+    // -------------------------------------------------------- Package Methods
+
+
+    /**
+     * Return the application Filter we are configured for.
+     *
+     * @exception ClassCastException if the specified class does not implement
+     *  the <code>javax.servlet.Filter</code> interface
+     * @exception ClassNotFoundException if the filter class cannot be found
+     * @exception IllegalAccessException if the filter class cannot be
+     *  publicly instantiated
+     * @exception InstantiationException if an exception occurs while
+     *  instantiating the filter object
+     * @exception ServletException if thrown by the filter's init() method
+     */
+    Filter getFilter() throws ClassCastException, ClassNotFoundException,
+        IllegalAccessException, InstantiationException, ServletException {
+
+        // Return the existing filter instance, if any
+        if (this.filter != null)
+            return (this.filter);
+
+        // Identify the class loader we will be using
+        String filterClass = filterDef.getFilterClass();
+        ClassLoader classLoader = null;
+        if (filterClass.startsWith("org.apache.catalina."))
+            classLoader = this.getClass().getClassLoader();
+        else
+            classLoader = context.getLoader().getClassLoader();
+
+        ClassLoader oldCtxClassLoader =
+            Thread.currentThread().getContextClassLoader();
+
+        // Instantiate a new instance of this filter and return it
+        Class clazz = classLoader.loadClass(filterClass);
+        this.filter = (Filter) clazz.newInstance();
+        if (context instanceof StandardContext &&
+            ((StandardContext)context).getSwallowOutput()) {
+            try {
+                SystemLogHandler.startCapture();
+                filter.init(this);
+            } finally {
+                String log = SystemLogHandler.stopCapture();
+                if (log != null && log.length() > 0) {
+                    getServletContext().log(log);
+                }
+            }
+        } else {
+            filter.init(this);
+        }
+        return (this.filter);
+
+    }
+
+
+    /**
+     * Return the filter definition we are configured for.
+     */
+    FilterDef getFilterDef() {
+
+        return (this.filterDef);
+
+    }
+
+
+    /**
+     * Release the Filter instance associated with this FilterConfig,
+     * if there is one.
+     */
+    void release() {
+
+        if (this.filter != null){
+             if( System.getSecurityManager() != null) {
+                try{
+                    SecurityUtil.doAsPrivilege("destroy", filter); 
+                } catch(java.lang.Exception ex){                    
+                    context.getLogger().error("ApplicationFilterConfig.doAsPrivilege", ex);
+                }
+                SecurityUtil.remove(filter);
+            } else { 
+                filter.destroy();
+            }
+        }
+        this.filter = null;
+
+     }
+
+
+    /**
+     * Set the filter definition we are configured for.  This has the side
+     * effect of instantiating an instance of the corresponding filter class.
+     *
+     * @param filterDef The new filter definition
+     *
+     * @exception ClassCastException if the specified class does not implement
+     *  the <code>javax.servlet.Filter</code> interface
+     * @exception ClassNotFoundException if the filter class cannot be found
+     * @exception IllegalAccessException if the filter class cannot be
+     *  publicly instantiated
+     * @exception InstantiationException if an exception occurs while
+     *  instantiating the filter object
+     * @exception ServletException if thrown by the filter's init() method
+     */
+    void setFilterDef(FilterDef filterDef)
+        throws ClassCastException, ClassNotFoundException,
+               IllegalAccessException, InstantiationException,
+               ServletException {
+
+        this.filterDef = filterDef;
+        if (filterDef == null) {
+
+            // Release any previously allocated filter instance
+            if (this.filter != null){
+                 if( System.getSecurityManager() != null) {
+                    try{
+                        SecurityUtil.doAsPrivilege("destroy", filter);  
+                    } catch(java.lang.Exception ex){    
+                        context.getLogger().error("ApplicationFilterConfig.doAsPrivilege", ex);
+                    }
+                    SecurityUtil.remove(filter);
+                } else { 
+                    filter.destroy();
+                }
+            }
+            this.filter = null;
+
+        } else {
+
+            // Allocate a new filter instance
+            Filter filter = getFilter();
+
+        }
+
+    }
+
+
+    // -------------------------------------------------------- Private Methods
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/core/ApplicationFilterFactory.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/core/ApplicationFilterFactory.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/core/ApplicationFilterFactory.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,339 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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 javax.servlet.Servlet;
+import javax.servlet.ServletRequest;
+import javax.servlet.http.HttpServletRequest;
+
+import org.apache.catalina.Globals;
+import org.apache.catalina.Wrapper;
+import org.apache.catalina.connector.Request;
+import org.apache.catalina.deploy.FilterMap;
+
+/**
+ * Factory for the creation and caching of Filters and creationg 
+ * of Filter Chains.
+ *
+ * @author Greg Murray
+ * @author Remy Maucherat
+ * @version $Revision: 1.0
+ */
+
+public final class ApplicationFilterFactory {
+
+
+    // -------------------------------------------------------------- Constants
+
+
+    public static final int ERROR = 1;
+    public static final Integer ERROR_INTEGER = new Integer(ERROR);
+    public static final int FORWARD = 2;
+    public static final Integer FORWARD_INTEGER = new Integer(FORWARD);
+    public static final int INCLUDE = 4;
+    public static final Integer INCLUDE_INTEGER = new Integer(INCLUDE);
+    public static final int REQUEST = 8;
+    public static final Integer REQUEST_INTEGER = new Integer(REQUEST);
+
+    public static final String DISPATCHER_TYPE_ATTR = 
+        Globals.DISPATCHER_TYPE_ATTR;
+    public static final String DISPATCHER_REQUEST_PATH_ATTR = 
+        Globals.DISPATCHER_REQUEST_PATH_ATTR;
+
+    private static final SecurityManager securityManager = 
+        System.getSecurityManager();
+
+    private static ApplicationFilterFactory factory = null;;
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /*
+     * Prevent instanciation outside of the getInstanceMethod().
+     */
+    private ApplicationFilterFactory() {
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Return the fqctory instance.
+     */
+    public static ApplicationFilterFactory getInstance() {
+        if (factory == null) {
+            factory = new ApplicationFilterFactory();
+        }
+        return factory;
+    }
+
+
+    /**
+     * Construct and return a FilterChain implementation that will wrap the
+     * execution of the specified servlet instance.  If we should not execute
+     * a filter chain at all, return <code>null</code>.
+     *
+     * @param request The servlet request we are processing
+     * @param servlet The servlet instance to be wrapped
+     */
+    public ApplicationFilterChain createFilterChain
+        (ServletRequest request, Wrapper wrapper, Servlet servlet) {
+
+        // get the dispatcher type
+        int dispatcher = -1; 
+        if (request.getAttribute(DISPATCHER_TYPE_ATTR) != null) {
+            Integer dispatcherInt = 
+                (Integer) request.getAttribute(DISPATCHER_TYPE_ATTR);
+            dispatcher = dispatcherInt.intValue();
+        }
+        String requestPath = null;
+        Object attribute = request.getAttribute(DISPATCHER_REQUEST_PATH_ATTR);
+        
+        if (attribute != null){
+            requestPath = attribute.toString();
+        }
+        
+        HttpServletRequest hreq = null;
+        if (request instanceof HttpServletRequest) 
+            hreq = (HttpServletRequest)request;
+        // If there is no servlet to execute, return null
+        if (servlet == null)
+            return (null);
+
+        // Create and initialize a filter chain object
+        ApplicationFilterChain filterChain = null;
+        if ((securityManager == null) && (request instanceof Request)) {
+            Request req = (Request) request;
+            filterChain = (ApplicationFilterChain) req.getFilterChain();
+            if (filterChain == null) {
+                filterChain = new ApplicationFilterChain();
+                req.setFilterChain(filterChain);
+            }
+        } else {
+            // Security: Do not recycle
+            filterChain = new ApplicationFilterChain();
+        }
+
+        filterChain.setServlet(servlet);
+
+        filterChain.setSupport
+            (((StandardWrapper)wrapper).getInstanceSupport());
+
+        // Acquire the filter mappings for this Context
+        StandardContext context = (StandardContext) wrapper.getParent();
+        FilterMap filterMaps[] = context.findFilterMaps();
+
+        // If there are no filter mappings, we are done
+        if ((filterMaps == null) || (filterMaps.length == 0))
+            return (filterChain);
+
+        // Acquire the information we will need to match filter mappings
+        String servletName = wrapper.getName();
+
+        int n = 0;
+
+        // Add the relevant path-mapped filters to this filter chain
+        for (int i = 0; i < filterMaps.length; i++) {
+            if (!matchDispatcher(filterMaps[i] ,dispatcher)) {
+                continue;
+            }
+            if (!matchFiltersURL(filterMaps[i], requestPath))
+                continue;
+            ApplicationFilterConfig filterConfig = (ApplicationFilterConfig)
+                context.findFilterConfig(filterMaps[i].getFilterName());
+            if (filterConfig == null) {
+                ;       // FIXME - log configuration problem
+                continue;
+            }
+            filterChain.addFilter(filterConfig);
+            n++;
+        }
+
+        // Add filters that match on servlet name second
+        for (int i = 0; i < filterMaps.length; i++) {
+            if (!matchDispatcher(filterMaps[i] ,dispatcher)) {
+                continue;
+            }
+            if (!matchFiltersServlet(filterMaps[i], servletName))
+                continue;
+            ApplicationFilterConfig filterConfig = (ApplicationFilterConfig)
+                context.findFilterConfig(filterMaps[i].getFilterName());
+            if (filterConfig == null) {
+                ;       // FIXME - log configuration problem
+                continue;
+            }
+            filterChain.addFilter(filterConfig);
+            n++;
+        }
+
+        // Return the completed filter chain
+        return (filterChain);
+
+    }
+
+
+    // -------------------------------------------------------- Private Methods
+
+
+    /**
+     * Return <code>true</code> if the context-relative request path
+     * matches the requirements of the specified filter mapping;
+     * otherwise, return <code>null</code>.
+     *
+     * @param filterMap Filter mapping being checked
+     * @param requestPath Context-relative request path of this request
+     */
+    private boolean matchFiltersURL(FilterMap filterMap, String requestPath) {
+
+        if (requestPath == null)
+            return (false);
+
+        // Match on context relative request path
+        String testPath = filterMap.getURLPattern();
+        if (testPath == null)
+            return (false);
+
+        // Case 1 - Exact Match
+        if (testPath.equals(requestPath))
+            return (true);
+
+        // Case 2 - Path Match ("/.../*")
+        if (testPath.equals("/*"))
+            return (true);
+        if (testPath.endsWith("/*")) {
+            if (testPath.regionMatches(0, requestPath, 0, 
+                                       testPath.length() - 2)) {
+                if (requestPath.length() == (testPath.length() - 2)) {
+                    return (true);
+                } else if ('/' == requestPath.charAt(testPath.length() - 2)) {
+                    return (true);
+                }
+            }
+            return (false);
+        }
+
+        // Case 3 - Extension Match
+        if (testPath.startsWith("*.")) {
+            int slash = requestPath.lastIndexOf('/');
+            int period = requestPath.lastIndexOf('.');
+            if ((slash >= 0) && (period > slash) 
+                && (period != requestPath.length() - 1)
+                && ((requestPath.length() - period) 
+                    == (testPath.length() - 1))) {
+                return (testPath.regionMatches(2, requestPath, period + 1,
+                                               testPath.length() - 2));
+            }
+        }
+
+        // Case 4 - "Default" Match
+        return (false); // NOTE - Not relevant for selecting filters
+
+    }
+
+
+    /**
+     * Return <code>true</code> if the specified servlet name matches
+     * the requirements of the specified filter mapping; otherwise
+     * return <code>false</code>.
+     *
+     * @param filterMap Filter mapping being checked
+     * @param servletName Servlet name being checked
+     */
+    private boolean matchFiltersServlet(FilterMap filterMap, 
+                                        String servletName) {
+
+        if (servletName == null) {
+            return (false);
+        } else {
+            if (servletName.equals(filterMap.getServletName())) {
+                return (true);
+            } else {
+                return false;
+            }
+        }
+
+    }
+
+
+    /**
+     * Convienience method which returns true if  the dispatcher type
+     * matches the dispatcher types specified in the FilterMap
+     */
+    private boolean matchDispatcher(FilterMap filterMap, int dispatcher) {
+        switch (dispatcher) {
+            case FORWARD : {
+                if (filterMap.getDispatcherMapping() == FilterMap.FORWARD ||
+                    filterMap.getDispatcherMapping() == FilterMap.FORWARD_ERROR ||
+                    filterMap.getDispatcherMapping() == FilterMap.INCLUDE_FORWARD ||
+                    filterMap.getDispatcherMapping() == FilterMap.INCLUDE_ERROR_FORWARD ||
+                    filterMap.getDispatcherMapping() == FilterMap.REQUEST_FORWARD ||
+                    filterMap.getDispatcherMapping() == FilterMap.REQUEST_ERROR_FORWARD ||
+                    filterMap.getDispatcherMapping() == FilterMap.REQUEST_ERROR_FORWARD_INCLUDE ||
+                    filterMap.getDispatcherMapping() == FilterMap.REQUEST_FORWARD_INCLUDE) {
+                        return true;
+                }
+                break;
+            }
+            case INCLUDE : {
+                if (filterMap.getDispatcherMapping() == FilterMap.INCLUDE ||
+                    filterMap.getDispatcherMapping() == FilterMap.INCLUDE_ERROR ||
+                    filterMap.getDispatcherMapping() == FilterMap.INCLUDE_FORWARD ||
+                    filterMap.getDispatcherMapping() == FilterMap.INCLUDE_ERROR_FORWARD ||
+                    filterMap.getDispatcherMapping() == FilterMap.REQUEST_INCLUDE ||
+                    filterMap.getDispatcherMapping() == FilterMap.REQUEST_ERROR_INCLUDE ||
+                    filterMap.getDispatcherMapping() == FilterMap.REQUEST_ERROR_FORWARD_INCLUDE ||
+                    filterMap.getDispatcherMapping() == FilterMap.REQUEST_FORWARD_INCLUDE) {
+                        return true;
+                }
+                break;
+            }
+            case REQUEST : {
+                if (filterMap.getDispatcherMapping() == FilterMap.REQUEST ||
+                    filterMap.getDispatcherMapping() == FilterMap.REQUEST_ERROR ||
+                    filterMap.getDispatcherMapping() == FilterMap.REQUEST_INCLUDE ||
+                    filterMap.getDispatcherMapping() == FilterMap.REQUEST_ERROR_INCLUDE ||
+                    filterMap.getDispatcherMapping() == FilterMap.REQUEST_FORWARD ||
+                    filterMap.getDispatcherMapping() == FilterMap.REQUEST_ERROR_FORWARD ||
+                    filterMap.getDispatcherMapping() == FilterMap.REQUEST_FORWARD_INCLUDE ||
+                    filterMap.getDispatcherMapping() == FilterMap.REQUEST_ERROR_FORWARD_INCLUDE) {
+                        return true;
+                }
+                break;
+            }
+            case ERROR : {
+                if (filterMap.getDispatcherMapping() == FilterMap.ERROR ||
+                    filterMap.getDispatcherMapping() == FilterMap.FORWARD_ERROR || 
+                    filterMap.getDispatcherMapping() == FilterMap.INCLUDE_ERROR || 
+                    filterMap.getDispatcherMapping() == FilterMap.INCLUDE_ERROR_FORWARD || 
+                    filterMap.getDispatcherMapping() == FilterMap.REQUEST_ERROR ||
+                    filterMap.getDispatcherMapping() == FilterMap.REQUEST_ERROR_FORWARD ||
+                    filterMap.getDispatcherMapping() == FilterMap.REQUEST_ERROR_FORWARD_INCLUDE ||
+                    filterMap.getDispatcherMapping() == FilterMap.REQUEST_ERROR_INCLUDE) {
+                        return true;
+                }
+                break;
+            }
+        }
+        return false;
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/core/ApplicationHttpRequest.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/core/ApplicationHttpRequest.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/core/ApplicationHttpRequest.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,950 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.IOException;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.NoSuchElementException;
+
+import javax.servlet.RequestDispatcher;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletRequestWrapper;
+import javax.servlet.http.HttpSession;
+
+import org.apache.catalina.Context;
+import org.apache.catalina.Globals;
+import org.apache.catalina.Session;
+import org.apache.catalina.Manager;
+import org.apache.catalina.util.Enumerator;
+import org.apache.catalina.util.RequestUtil;
+import org.apache.catalina.util.StringManager;
+
+
+/**
+ * Wrapper around a <code>javax.servlet.http.HttpServletRequest</code>
+ * that transforms an application request object (which might be the original
+ * one passed to a servlet, or might be based on the 2.3
+ * <code>javax.servlet.http.HttpServletRequestWrapper</code> class)
+ * back into an internal <code>org.apache.catalina.HttpRequest</code>.
+ * <p>
+ * <strong>WARNING</strong>:  Due to Java's lack of support for multiple
+ * inheritance, all of the logic in <code>ApplicationRequest</code> is
+ * duplicated in <code>ApplicationHttpRequest</code>.  Make sure that you
+ * keep these two classes in synchronization when making changes!
+ *
+ * @author Craig R. McClanahan
+ * @author Remy Maucherat
+ * @version $Revision: 303799 $ $Date: 2005-03-25 02:41:23 -0600 (Fri, 25 Mar 2005) $
+ */
+
+class ApplicationHttpRequest extends HttpServletRequestWrapper {
+
+
+    // ------------------------------------------------------- Static Variables
+
+
+    /**
+     * The set of attribute names that are special for request dispatchers.
+     */
+    protected static final String specials[] =
+    { Globals.INCLUDE_REQUEST_URI_ATTR, Globals.INCLUDE_CONTEXT_PATH_ATTR,
+      Globals.INCLUDE_SERVLET_PATH_ATTR, Globals.INCLUDE_PATH_INFO_ATTR,
+      Globals.INCLUDE_QUERY_STRING_ATTR, Globals.FORWARD_REQUEST_URI_ATTR, 
+      Globals.FORWARD_CONTEXT_PATH_ATTR, Globals.FORWARD_SERVLET_PATH_ATTR, 
+      Globals.FORWARD_PATH_INFO_ATTR, Globals.FORWARD_QUERY_STRING_ATTR };
+
+
+    /**
+     * The string manager for this package.
+     */
+    protected static StringManager sm =
+        StringManager.getManager(Constants.Package);
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Construct a new wrapped request around the specified servlet request.
+     *
+     * @param request The servlet request being wrapped
+     */
+    public ApplicationHttpRequest(HttpServletRequest request, Context context,
+                                  boolean crossContext) {
+
+        super(request);
+        this.context = context;
+        this.crossContext = crossContext;
+        setRequest(request);
+
+    }
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The context for this request.
+     */
+    protected Context context = null;
+
+
+    /**
+     * The context path for this request.
+     */
+    protected String contextPath = null;
+
+
+    /**
+     * If this request is cross context, since this changes session accesss
+     * behavior.
+     */
+    protected boolean crossContext = false;
+
+
+    /**
+     * The current dispatcher type.
+     */
+    protected Object dispatcherType = null;
+
+
+    /**
+     * Descriptive information about this implementation.
+     */
+    protected static final String info =
+        "org.apache.catalina.core.ApplicationHttpRequest/1.0";
+
+
+    /**
+     * The request parameters for this request.  This is initialized from the
+     * wrapped request, but updates are allowed.
+     */
+    protected Map parameters = null;
+
+
+    /**
+     * Have the parameters for this request already been parsed?
+     */
+    private boolean parsedParams = false;
+
+
+    /**
+     * The path information for this request.
+     */
+    protected String pathInfo = null;
+
+
+    /**
+     * The query parameters for the current request.
+     */
+    private String queryParamString = null;
+
+
+    /**
+     * The query string for this request.
+     */
+    protected String queryString = null;
+
+
+    /**
+     * The current request dispatcher path.
+     */
+    protected Object requestDispatcherPath = null;
+
+
+    /**
+     * The request URI for this request.
+     */
+    protected String requestURI = null;
+
+
+    /**
+     * The servlet path for this request.
+     */
+    protected String servletPath = null;
+
+
+    /**
+     * The currently active session for this request.
+     */
+    protected Session session = null;
+
+
+    /**
+     * Special attributes.
+     */
+    protected Object[] specialAttributes = new Object[specials.length];
+
+
+    // ------------------------------------------------- ServletRequest Methods
+
+
+    /**
+     * Override the <code>getAttribute()</code> method of the wrapped request.
+     *
+     * @param name Name of the attribute to retrieve
+     */
+    public Object getAttribute(String name) {
+
+        if (name.equals(Globals.DISPATCHER_TYPE_ATTR)) {
+            return dispatcherType;
+        } else if (name.equals(Globals.DISPATCHER_REQUEST_PATH_ATTR)) {
+            if ( requestDispatcherPath != null ){
+                return requestDispatcherPath.toString();
+            } else {
+                return null;   
+            }
+        }
+
+        int pos = getSpecial(name);
+        if (pos == -1) {
+            return getRequest().getAttribute(name);
+        } else {
+            if ((specialAttributes[pos] == null) 
+                && (specialAttributes[5] == null) && (pos >= 5)) {
+                // If it's a forward special attribute, and null, it means this
+                // is an include, so we check the wrapped request since 
+                // the request could have been forwarded before the include
+                return getRequest().getAttribute(name);
+            } else {
+                return specialAttributes[pos];
+            }
+        }
+
+    }
+
+
+    /**
+     * Override the <code>getAttributeNames()</code> method of the wrapped
+     * request.
+     */
+    public Enumeration getAttributeNames() {
+        return (new AttributeNamesEnumerator());
+    }
+
+
+    /**
+     * Override the <code>removeAttribute()</code> method of the
+     * wrapped request.
+     *
+     * @param name Name of the attribute to remove
+     */
+    public void removeAttribute(String name) {
+
+        if (!removeSpecial(name))
+            getRequest().removeAttribute(name);
+
+    }
+
+
+    /**
+     * Override the <code>setAttribute()</code> method of the
+     * wrapped request.
+     *
+     * @param name Name of the attribute to set
+     * @param value Value of the attribute to set
+     */
+    public void setAttribute(String name, Object value) {
+
+        if (name.equals(Globals.DISPATCHER_TYPE_ATTR)) {
+            dispatcherType = value;
+            return;
+        } else if (name.equals(Globals.DISPATCHER_REQUEST_PATH_ATTR)) {
+            requestDispatcherPath = value;
+            return;
+        }
+
+        if (!setSpecial(name, value)) {
+            getRequest().setAttribute(name, value);
+        }
+
+    }
+
+
+    /**
+     * Return a RequestDispatcher that wraps the resource at the specified
+     * path, which may be interpreted as relative to the current request path.
+     *
+     * @param path Path of the resource to be wrapped
+     */
+    public RequestDispatcher getRequestDispatcher(String path) {
+
+        if (context == null)
+            return (null);
+
+        // If the path is already context-relative, just pass it through
+        if (path == null)
+            return (null);
+        else if (path.startsWith("/"))
+            return (context.getServletContext().getRequestDispatcher(path));
+
+        // Convert a request-relative path to a context-relative one
+        String servletPath = 
+            (String) getAttribute(Globals.INCLUDE_SERVLET_PATH_ATTR);
+        if (servletPath == null)
+            servletPath = getServletPath();
+
+        // Add the path info, if there is any
+        String pathInfo = getPathInfo();
+        String requestPath = null;
+
+        if (pathInfo == null) {
+            requestPath = servletPath;
+        } else {
+            requestPath = servletPath + pathInfo;
+        }
+
+        int pos = requestPath.lastIndexOf('/');
+        String relative = null;
+        if (pos >= 0) {
+            relative = RequestUtil.normalize
+                (requestPath.substring(0, pos + 1) + path);
+        } else {
+            relative = RequestUtil.normalize(requestPath + path);
+        }
+
+        return (context.getServletContext().getRequestDispatcher(relative));
+
+    }
+
+
+    // --------------------------------------------- HttpServletRequest Methods
+
+
+    /**
+     * Override the <code>getContextPath()</code> method of the wrapped
+     * request.
+     */
+    public String getContextPath() {
+
+        return (this.contextPath);
+
+    }
+
+
+    /**
+     * Override the <code>getParameter()</code> method of the wrapped request.
+     *
+     * @param name Name of the requested parameter
+     */
+    public String getParameter(String name) {
+
+	parseParameters();
+
+        Object value = parameters.get(name);
+        if (value == null)
+            return (null);
+        else if (value instanceof String[])
+            return (((String[]) value)[0]);
+        else if (value instanceof String)
+            return ((String) value);
+        else
+            return (value.toString());
+
+    }
+
+
+    /**
+     * Override the <code>getParameterMap()</code> method of the
+     * wrapped request.
+     */
+    public Map getParameterMap() {
+
+	parseParameters();
+        return (parameters);
+
+    }
+
+
+    /**
+     * Override the <code>getParameterNames()</code> method of the
+     * wrapped request.
+     */
+    public Enumeration getParameterNames() {
+
+	parseParameters();
+        return (new Enumerator(parameters.keySet()));
+
+    }
+
+
+    /**
+     * Override the <code>getParameterValues()</code> method of the
+     * wrapped request.
+     *
+     * @param name Name of the requested parameter
+     */
+    public String[] getParameterValues(String name) {
+
+	parseParameters();
+        Object value = parameters.get(name);
+        if (value == null)
+            return ((String[]) null);
+        else if (value instanceof String[])
+            return ((String[]) value);
+        else if (value instanceof String) {
+            String values[] = new String[1];
+            values[0] = (String) value;
+            return (values);
+        } else {
+            String values[] = new String[1];
+            values[0] = value.toString();
+            return (values);
+        }
+
+    }
+
+
+    /**
+     * Override the <code>getPathInfo()</code> method of the wrapped request.
+     */
+    public String getPathInfo() {
+
+        return (this.pathInfo);
+
+    }
+
+
+    /**
+     * Override the <code>getQueryString()</code> method of the wrapped
+     * request.
+     */
+    public String getQueryString() {
+
+        return (this.queryString);
+
+    }
+
+
+    /**
+     * Override the <code>getRequestURI()</code> method of the wrapped
+     * request.
+     */
+    public String getRequestURI() {
+
+        return (this.requestURI);
+
+    }
+
+
+    /**
+     * Override the <code>getRequestURL()</code> method of the wrapped
+     * request.
+     */
+    public StringBuffer getRequestURL() {
+
+        StringBuffer url = new StringBuffer();
+        String scheme = getScheme();
+        int port = getServerPort();
+        if (port < 0)
+            port = 80; // Work around java.net.URL bug
+
+        url.append(scheme);
+        url.append("://");
+        url.append(getServerName());
+        if ((scheme.equals("http") && (port != 80))
+            || (scheme.equals("https") && (port != 443))) {
+            url.append(':');
+            url.append(port);
+        }
+        url.append(getRequestURI());
+
+        return (url);
+
+    }
+
+
+    /**
+     * Override the <code>getServletPath()</code> method of the wrapped
+     * request.
+     */
+    public String getServletPath() {
+
+        return (this.servletPath);
+
+    }
+
+
+    /**
+     * Return the session associated with this Request, creating one
+     * if necessary.
+     */
+    public HttpSession getSession() {
+        return (getSession(true));
+    }
+
+
+    /**
+     * Return the session associated with this Request, creating one
+     * if necessary and requested.
+     *
+     * @param create Create a new session if one does not exist
+     */
+    public HttpSession getSession(boolean create) {
+
+        if (crossContext) {
+            
+            // There cannot be a session if no context has been assigned yet
+            if (context == null)
+                return (null);
+
+            // Return the current session if it exists and is valid
+            if (session != null && session.isValid()) {
+                return (session.getSession());
+            }
+
+            HttpSession other = super.getSession(false);
+            if (create && (other == null)) {
+                // First create a session in the first context: the problem is
+                // that the top level request is the only one which can 
+                // create the cookie safely
+                other = super.getSession(true);
+            }
+            if (other != null) {
+                Session localSession = null;
+                try {
+                    localSession =
+                        context.getManager().findSession(other.getId());
+                } catch (IOException e) {
+                    // Ignore
+                }
+                if (localSession == null && create) {
+                    localSession = 
+                        context.getManager().createSession(other.getId());
+                }
+                if (localSession != null) {
+                    localSession.access();
+                    session = localSession;
+                    return session.getSession();
+                }
+            }
+            return null;
+
+        } else {
+            return super.getSession(create);
+        }
+
+    }
+
+
+    /**
+     * Returns true if the request specifies a JSESSIONID that is valid within
+     * the context of this ApplicationHttpRequest, false otherwise.
+     *
+     * @return true if the request specifies a JSESSIONID that is valid within
+     * the context of this ApplicationHttpRequest, false otherwise.
+     */
+    public boolean isRequestedSessionIdValid() {
+
+        if (crossContext) {
+
+            String requestedSessionId = getRequestedSessionId();
+            if (requestedSessionId == null)
+                return (false);
+            if (context == null)
+                return (false);
+            Manager manager = context.getManager();
+            if (manager == null)
+                return (false);
+            Session session = null;
+            try {
+                session = manager.findSession(requestedSessionId);
+            } catch (IOException e) {
+                session = null;
+            }
+            if ((session != null) && session.isValid()) {
+                return (true);
+            } else {
+                return (false);
+            }
+
+        } else {
+            return super.isRequestedSessionIdValid();
+        }
+    }
+
+
+    // -------------------------------------------------------- Package Methods
+
+
+    /**
+     * Recycle this request
+     */
+    public void recycle() {
+        if (session != null) {
+            session.endAccess();
+        }
+    }
+
+
+    /**
+     * Return descriptive information about this implementation.
+     */
+    public String getInfo() {
+
+        return (info);
+
+    }
+
+
+    /**
+     * Perform a shallow copy of the specified Map, and return the result.
+     *
+     * @param orig Origin Map to be copied
+     */
+    Map copyMap(Map orig) {
+
+        if (orig == null)
+            return (new HashMap());
+        HashMap dest = new HashMap();
+        Iterator keys = orig.keySet().iterator();
+        while (keys.hasNext()) {
+            String key = (String) keys.next();
+            dest.put(key, orig.get(key));
+        }
+        return (dest);
+
+    }
+
+
+    /**
+     * Set the context path for this request.
+     *
+     * @param contextPath The new context path
+     */
+    void setContextPath(String contextPath) {
+
+        this.contextPath = contextPath;
+
+    }
+
+
+    /**
+     * Set the path information for this request.
+     *
+     * @param pathInfo The new path info
+     */
+    void setPathInfo(String pathInfo) {
+
+        this.pathInfo = pathInfo;
+
+    }
+
+
+    /**
+     * Set the query string for this request.
+     *
+     * @param queryString The new query string
+     */
+    void setQueryString(String queryString) {
+
+        this.queryString = queryString;
+
+    }
+
+
+    /**
+     * Set the request that we are wrapping.
+     *
+     * @param request The new wrapped request
+     */
+    void setRequest(HttpServletRequest request) {
+
+        super.setRequest(request);
+
+        // Initialize the attributes for this request
+        dispatcherType = request.getAttribute(Globals.DISPATCHER_TYPE_ATTR);
+        requestDispatcherPath = 
+            request.getAttribute(Globals.DISPATCHER_REQUEST_PATH_ATTR);
+
+        // Initialize the path elements for this request
+        contextPath = request.getContextPath();
+        pathInfo = request.getPathInfo();
+        queryString = request.getQueryString();
+        requestURI = request.getRequestURI();
+        servletPath = request.getServletPath();
+
+    }
+
+
+    /**
+     * Set the request URI for this request.
+     *
+     * @param requestURI The new request URI
+     */
+    void setRequestURI(String requestURI) {
+
+        this.requestURI = requestURI;
+
+    }
+
+
+    /**
+     * Set the servlet path for this request.
+     *
+     * @param servletPath The new servlet path
+     */
+    void setServletPath(String servletPath) {
+
+        this.servletPath = servletPath;
+
+    }
+
+
+    /**
+     * Parses the parameters of this request.
+     *
+     * If parameters are present in both the query string and the request
+     * content, they are merged.
+     */
+    void parseParameters() {
+
+	if (parsedParams) {
+	    return;
+	}
+
+        parameters = new HashMap();
+        parameters = copyMap(getRequest().getParameterMap());
+        mergeParameters();
+        parsedParams = true;
+    }
+
+
+    /**
+     * Save query parameters for this request.
+     *
+     * @param queryString The query string containing parameters for this
+     *                    request
+     */
+    void setQueryParams(String queryString) {
+        this.queryParamString = queryString;
+    }
+
+
+    // ------------------------------------------------------ Protected Methods
+
+
+    /**
+     * Is this attribute name one of the special ones that is added only for
+     * included servlets?
+     *
+     * @param name Attribute name to be tested
+     */
+    protected boolean isSpecial(String name) {
+
+        for (int i = 0; i < specials.length; i++) {
+            if (specials[i].equals(name))
+                return (true);
+        }
+        return (false);
+
+    }
+
+
+    /**
+     * Get a special attribute.
+     *
+     * @return the special attribute pos, or -1 if it is not a special 
+     *         attribute
+     */
+    protected int getSpecial(String name) {
+        for (int i = 0; i < specials.length; i++) {
+            if (specials[i].equals(name)) {
+                return (i);
+            }
+        }
+        return (-1);
+    }
+
+
+    /**
+     * Set a special attribute.
+     * 
+     * @return true if the attribute was a special attribute, false otherwise
+     */
+    protected boolean setSpecial(String name, Object value) {
+        for (int i = 0; i < specials.length; i++) {
+            if (specials[i].equals(name)) {
+                specialAttributes[i] = value;
+                return (true);
+            }
+        }
+        return (false);
+    }
+
+
+    /**
+     * Remove a special attribute.
+     * 
+     * @return true if the attribute was a special attribute, false otherwise
+     */
+    protected boolean removeSpecial(String name) {
+        for (int i = 0; i < specials.length; i++) {
+            if (specials[i].equals(name)) {
+                specialAttributes[i] = null;
+                return (true);
+            }
+        }
+        return (false);
+    }
+
+
+    /**
+     * Merge the two sets of parameter values into a single String array.
+     *
+     * @param values1 First set of values
+     * @param values2 Second set of values
+     */
+    protected String[] mergeValues(Object values1, Object values2) {
+
+        ArrayList results = new ArrayList();
+
+        if (values1 == null)
+            ;
+        else if (values1 instanceof String)
+            results.add(values1);
+        else if (values1 instanceof String[]) {
+            String values[] = (String[]) values1;
+            for (int i = 0; i < values.length; i++)
+                results.add(values[i]);
+        } else
+            results.add(values1.toString());
+
+        if (values2 == null)
+            ;
+        else if (values2 instanceof String)
+            results.add(values2);
+        else if (values2 instanceof String[]) {
+            String values[] = (String[]) values2;
+            for (int i = 0; i < values.length; i++)
+                results.add(values[i]);
+        } else
+            results.add(values2.toString());
+
+        String values[] = new String[results.size()];
+        return ((String[]) results.toArray(values));
+
+    }
+
+
+    // ------------------------------------------------------ Private Methods
+
+
+    /**
+     * Merge the parameters from the saved query parameter string (if any), and
+     * the parameters already present on this request (if any), such that the
+     * parameter values from the query string show up first if there are
+     * duplicate parameter names.
+     */
+    private void mergeParameters() {
+
+        if ((queryParamString == null) || (queryParamString.length() < 1))
+            return;
+
+        HashMap queryParameters = new HashMap();
+        String encoding = getCharacterEncoding();
+        if (encoding == null)
+            encoding = "ISO-8859-1";
+        try {
+            RequestUtil.parseParameters
+                (queryParameters, queryParamString, encoding);
+        } catch (Exception e) {
+            ;
+        }
+        Iterator keys = parameters.keySet().iterator();
+        while (keys.hasNext()) {
+            String key = (String) keys.next();
+            Object value = queryParameters.get(key);
+            if (value == null) {
+                queryParameters.put(key, parameters.get(key));
+                continue;
+            }
+            queryParameters.put
+                (key, mergeValues(value, parameters.get(key)));
+        }
+        parameters = queryParameters;
+
+    }
+
+
+    // ----------------------------------- AttributeNamesEnumerator Inner Class
+
+
+    /**
+     * Utility class used to expose the special attributes as being available
+     * as request attributes.
+     */
+    protected class AttributeNamesEnumerator implements Enumeration {
+
+        protected int pos = -1;
+        protected int last = -1;
+        protected Enumeration parentEnumeration = null;
+        protected String next = null;
+
+        public AttributeNamesEnumerator() {
+            parentEnumeration = getRequest().getAttributeNames();
+            for (int i = 0; i < specialAttributes.length; i++) {
+                if (getAttribute(specials[i]) != null) {
+                    last = i;
+                }
+            }
+        }
+
+        public boolean hasMoreElements() {
+            return ((pos != last) || (next != null) 
+                    || ((next = findNext()) != null));
+        }
+
+        public Object nextElement() {
+            if (pos != last) {
+                for (int i = pos + 1; i <= last; i++) {
+                    if (getAttribute(specials[i]) != null) {
+                        pos = i;
+                        return (specials[i]);
+                    }
+                }
+            }
+            String result = next;
+            if (next != null) {
+                next = findNext();
+            } else {
+                throw new NoSuchElementException();
+            }
+            return result;
+        }
+
+        protected String findNext() {
+            String result = null;
+            while ((result == null) && (parentEnumeration.hasMoreElements())) {
+                String current = (String) parentEnumeration.nextElement();
+                if (!isSpecial(current)) {
+                    result = current;
+                }
+            }
+            return result;
+        }
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/core/ApplicationHttpResponse.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/core/ApplicationHttpResponse.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/core/ApplicationHttpResponse.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,393 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.IOException;
+import java.util.Locale;
+
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpServletResponseWrapper;
+
+import org.apache.catalina.util.StringManager;
+
+
+/**
+ * Wrapper around a <code>javax.servlet.http.HttpServletResponse</code>
+ * that transforms an application response object (which might be the original
+ * one passed to a servlet, or might be based on the 2.3
+ * <code>javax.servlet.http.HttpServletResponseWrapper</code> class)
+ * back into an internal <code>org.apache.catalina.HttpResponse</code>.
+ * <p>
+ * <strong>WARNING</strong>:  Due to Java's lack of support for multiple
+ * inheritance, all of the logic in <code>ApplicationResponse</code> is
+ * duplicated in <code>ApplicationHttpResponse</code>.  Make sure that you
+ * keep these two classes in synchronization when making changes!
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 303387 $ $Date: 2004-10-15 11:09:27 -0500 (Fri, 15 Oct 2004) $
+ */
+
+class ApplicationHttpResponse extends HttpServletResponseWrapper {
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Construct a new wrapped response around the specified servlet response.
+     *
+     * @param response The servlet response being wrapped
+     */
+    public ApplicationHttpResponse(HttpServletResponse response) {
+
+        this(response, false);
+
+    }
+
+
+    /**
+     * Construct a new wrapped response around the specified servlet response.
+     *
+     * @param response The servlet response being wrapped
+     * @param included <code>true</code> if this response is being processed
+     *  by a <code>RequestDispatcher.include()</code> call
+     */
+    public ApplicationHttpResponse(HttpServletResponse response,
+                                   boolean included) {
+
+        super(response);
+        setIncluded(included);
+
+    }
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * Is this wrapped response the subject of an <code>include()</code>
+     * call?
+     */
+    protected boolean included = false;
+
+
+    /**
+     * Descriptive information about this implementation.
+     */
+    protected static final String info =
+        "org.apache.catalina.core.ApplicationHttpResponse/1.0";
+
+
+    /**
+     * The string manager for this package.
+     */
+    protected static StringManager sm =
+        StringManager.getManager(Constants.Package);
+
+
+    // ------------------------------------------------ ServletResponse Methods
+
+
+    /**
+     * Disallow <code>reset()</code> calls on a included response.
+     *
+     * @exception IllegalStateException if the response has already
+     *  been committed
+     */
+    public void reset() {
+
+        // If already committed, the wrapped response will throw ISE
+        if (!included || getResponse().isCommitted())
+            getResponse().reset();
+
+    }
+
+
+    /**
+     * Disallow <code>setContentLength()</code> calls on an included response.
+     *
+     * @param len The new content length
+     */
+    public void setContentLength(int len) {
+
+        if (!included)
+            getResponse().setContentLength(len);
+
+    }
+
+
+    /**
+     * Disallow <code>setContentType()</code> calls on an included response.
+     *
+     * @param type The new content type
+     */
+    public void setContentType(String type) {
+
+        if (!included)
+            getResponse().setContentType(type);
+
+    }
+
+
+    /**
+     * Disallow <code>setLocale()</code> calls on an included response.
+     *
+     * @param loc The new locale
+     */
+    public void setLocale(Locale loc) {
+
+        if (!included)
+            getResponse().setLocale(loc);
+
+    }
+
+
+    /**
+     * Ignore <code>setBufferSize()</code> calls on an included response.
+     *
+     * @param size The buffer size
+     */
+    public void setBufferSize(int size) {
+        if (!included)
+            getResponse().setBufferSize(size);
+    }
+
+
+    // -------------------------------------------- HttpServletResponse Methods
+
+
+    /**
+     * Disallow <code>addCookie()</code> calls on an included response.
+     *
+     * @param cookie The new cookie
+     */
+    public void addCookie(Cookie cookie) {
+
+        if (!included)
+            ((HttpServletResponse) getResponse()).addCookie(cookie);
+
+    }
+
+
+    /**
+     * Disallow <code>addDateHeader()</code> calls on an included response.
+     *
+     * @param name The new header name
+     * @param value The new header value
+     */
+    public void addDateHeader(String name, long value) {
+
+        if (!included)
+            ((HttpServletResponse) getResponse()).addDateHeader(name, value);
+
+    }
+
+
+    /**
+     * Disallow <code>addHeader()</code> calls on an included response.
+     *
+     * @param name The new header name
+     * @param value The new header value
+     */
+    public void addHeader(String name, String value) {
+
+        if (!included)
+            ((HttpServletResponse) getResponse()).addHeader(name, value);
+
+    }
+
+
+    /**
+     * Disallow <code>addIntHeader()</code> calls on an included response.
+     *
+     * @param name The new header name
+     * @param value The new header value
+     */
+    public void addIntHeader(String name, int value) {
+
+        if (!included)
+            ((HttpServletResponse) getResponse()).addIntHeader(name, value);
+
+    }
+
+
+    /**
+     * Disallow <code>sendError()</code> calls on an included response.
+     *
+     * @param sc The new status code
+     *
+     * @exception IOException if an input/output error occurs
+     */
+    public void sendError(int sc) throws IOException {
+
+        if (!included)
+            ((HttpServletResponse) getResponse()).sendError(sc);
+
+    }
+
+
+    /**
+     * Disallow <code>sendError()</code> calls on an included response.
+     *
+     * @param sc The new status code
+     * @param msg The new message
+     *
+     * @exception IOException if an input/output error occurs
+     */
+    public void sendError(int sc, String msg) throws IOException {
+
+        if (!included)
+            ((HttpServletResponse) getResponse()).sendError(sc, msg);
+
+    }
+
+
+    /**
+     * Disallow <code>sendRedirect()</code> calls on an included response.
+     *
+     * @param location The new location
+     *
+     * @exception IOException if an input/output error occurs
+     */
+    public void sendRedirect(String location) throws IOException {
+
+        if (!included)
+            ((HttpServletResponse) getResponse()).sendRedirect(location);
+
+    }
+
+
+    /**
+     * Disallow <code>setDateHeader()</code> calls on an included response.
+     *
+     * @param name The new header name
+     * @param value The new header value
+     */
+    public void setDateHeader(String name, long value) {
+
+        if (!included)
+            ((HttpServletResponse) getResponse()).setDateHeader(name, value);
+
+    }
+
+
+    /**
+     * Disallow <code>setHeader()</code> calls on an included response.
+     *
+     * @param name The new header name
+     * @param value The new header value
+     */
+    public void setHeader(String name, String value) {
+
+        if (!included)
+            ((HttpServletResponse) getResponse()).setHeader(name, value);
+
+    }
+
+
+    /**
+     * Disallow <code>setIntHeader()</code> calls on an included response.
+     *
+     * @param name The new header name
+     * @param value The new header value
+     */
+    public void setIntHeader(String name, int value) {
+
+        if (!included)
+            ((HttpServletResponse) getResponse()).setIntHeader(name, value);
+
+    }
+
+
+    /**
+     * Disallow <code>setStatus()</code> calls on an included response.
+     *
+     * @param sc The new status code
+     */
+    public void setStatus(int sc) {
+
+        if (!included)
+            ((HttpServletResponse) getResponse()).setStatus(sc);
+
+    }
+
+
+    /**
+     * Disallow <code>setStatus()</code> calls on an included response.
+     *
+     * @param sc The new status code
+     * @param msg The new message
+     */
+    public void setStatus(int sc, String msg) {
+
+        if (!included)
+            ((HttpServletResponse) getResponse()).setStatus(sc, msg);
+
+    }
+
+
+    // -------------------------------------------------------- Package Methods
+
+
+    /**
+     * Return descriptive information about this implementation.
+     */
+    public String getInfo() {
+
+        return (info);
+
+    }
+
+
+    /**
+     * Return the included flag for this response.
+     */
+    boolean isIncluded() {
+
+        return (this.included);
+
+    }
+
+
+    /**
+     * Set the included flag for this response.
+     *
+     * @param included The new included flag
+     */
+    void setIncluded(boolean included) {
+
+        this.included = included;
+
+    }
+
+
+    /**
+     * Set the response that we are wrapping.
+     *
+     * @param response The new wrapped response
+     */
+    void setResponse(HttpServletResponse response) {
+
+        super.setResponse(response);
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/core/ApplicationRequest.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/core/ApplicationRequest.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/core/ApplicationRequest.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,209 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.util.Enumeration;
+import java.util.HashMap;
+
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletRequestWrapper;
+
+import org.apache.catalina.Globals;
+import org.apache.catalina.util.Enumerator;
+import org.apache.catalina.util.StringManager;
+
+
+/**
+ * Wrapper around a <code>javax.servlet.ServletRequest</code>
+ * that transforms an application request object (which might be the original
+ * one passed to a servlet, or might be based on the 2.3
+ * <code>javax.servlet.ServletRequestWrapper</code> class)
+ * back into an internal <code>org.apache.catalina.Request</code>.
+ * <p>
+ * <strong>WARNING</strong>:  Due to Java's lack of support for multiple
+ * inheritance, all of the logic in <code>ApplicationRequest</code> is
+ * duplicated in <code>ApplicationHttpRequest</code>.  Make sure that you
+ * keep these two classes in synchronization when making changes!
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+class ApplicationRequest extends ServletRequestWrapper {
+
+
+    // ------------------------------------------------------- Static Variables
+
+
+    /**
+     * The set of attribute names that are special for request dispatchers.
+     */
+    protected static final String specials[] =
+    { Globals.INCLUDE_REQUEST_URI_ATTR, Globals.INCLUDE_CONTEXT_PATH_ATTR,
+      Globals.INCLUDE_SERVLET_PATH_ATTR, Globals.INCLUDE_PATH_INFO_ATTR,
+      Globals.INCLUDE_QUERY_STRING_ATTR, Globals.FORWARD_REQUEST_URI_ATTR, 
+      Globals.FORWARD_CONTEXT_PATH_ATTR, Globals.FORWARD_SERVLET_PATH_ATTR, 
+      Globals.FORWARD_PATH_INFO_ATTR, Globals.FORWARD_QUERY_STRING_ATTR };
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Construct a new wrapped request around the specified servlet request.
+     *
+     * @param request The servlet request being wrapped
+     */
+    public ApplicationRequest(ServletRequest request) {
+
+        super(request);
+        setRequest(request);
+
+    }
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The request attributes for this request.  This is initialized from the
+     * wrapped request, but updates are allowed.
+     */
+    protected HashMap attributes = new HashMap();
+
+
+    /**
+     * The string manager for this package.
+     */
+    protected static StringManager sm =
+        StringManager.getManager(Constants.Package);
+
+
+    // ------------------------------------------------- ServletRequest Methods
+
+
+    /**
+     * Override the <code>getAttribute()</code> method of the wrapped request.
+     *
+     * @param name Name of the attribute to retrieve
+     */
+    public Object getAttribute(String name) {
+
+        synchronized (attributes) {
+            return (attributes.get(name));
+        }
+
+    }
+
+
+    /**
+     * Override the <code>getAttributeNames()</code> method of the wrapped
+     * request.
+     */
+    public Enumeration getAttributeNames() {
+
+        synchronized (attributes) {
+            return (new Enumerator(attributes.keySet()));
+        }
+
+    }
+
+
+    /**
+     * Override the <code>removeAttribute()</code> method of the
+     * wrapped request.
+     *
+     * @param name Name of the attribute to remove
+     */
+    public void removeAttribute(String name) {
+
+        synchronized (attributes) {
+            attributes.remove(name);
+            if (!isSpecial(name))
+                getRequest().removeAttribute(name);
+        }
+
+    }
+
+
+    /**
+     * Override the <code>setAttribute()</code> method of the
+     * wrapped request.
+     *
+     * @param name Name of the attribute to set
+     * @param value Value of the attribute to set
+     */
+    public void setAttribute(String name, Object value) {
+
+        synchronized (attributes) {
+            attributes.put(name, value);
+            if (!isSpecial(name))
+                getRequest().setAttribute(name, value);
+        }
+
+    }
+
+
+    // ------------------------------------------ ServletRequestWrapper Methods
+
+
+    /**
+     * Set the request that we are wrapping.
+     *
+     * @param request The new wrapped request
+     */
+    public void setRequest(ServletRequest request) {
+
+        super.setRequest(request);
+
+        // Initialize the attributes for this request
+        synchronized (attributes) {
+            attributes.clear();
+            Enumeration names = request.getAttributeNames();
+            while (names.hasMoreElements()) {
+                String name = (String) names.nextElement();
+                Object value = request.getAttribute(name);
+                attributes.put(name, value);
+            }
+        }
+
+    }
+
+
+    // ------------------------------------------------------ Protected Methods
+
+
+    /**
+     * Is this attribute name one of the special ones that is added only for
+     * included servlets?
+     *
+     * @param name Attribute name to be tested
+     */
+    protected boolean isSpecial(String name) {
+
+        for (int i = 0; i < specials.length; i++) {
+            if (specials[i].equals(name))
+                return (true);
+        }
+        return (false);
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/core/ApplicationResponse.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/core/ApplicationResponse.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/core/ApplicationResponse.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,201 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.util.Locale;
+
+import javax.servlet.ServletResponse;
+import javax.servlet.ServletResponseWrapper;
+
+import org.apache.catalina.util.StringManager;
+
+
+/**
+ * Wrapper around a <code>javax.servlet.ServletResponse</code>
+ * that transforms an application response object (which might be the original
+ * one passed to a servlet, or might be based on the 2.3
+ * <code>javax.servlet.ServletResponseWrapper</code> class)
+ * back into an internal <code>org.apache.catalina.Response</code>.
+ * <p>
+ * <strong>WARNING</strong>:  Due to Java's lack of support for multiple
+ * inheritance, all of the logic in <code>ApplicationResponse</code> is
+ * duplicated in <code>ApplicationHttpResponse</code>.  Make sure that you
+ * keep these two classes in synchronization when making changes!
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+class ApplicationResponse extends ServletResponseWrapper {
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Construct a new wrapped response around the specified servlet response.
+     *
+     * @param response The servlet response being wrapped
+     */
+    public ApplicationResponse(ServletResponse response) {
+
+        this(response, false);
+
+    }
+
+
+    /**
+     * Construct a new wrapped response around the specified servlet response.
+     *
+     * @param response The servlet response being wrapped
+     * @param included <code>true</code> if this response is being processed
+     *  by a <code>RequestDispatcher.include()</code> call
+     */
+    public ApplicationResponse(ServletResponse response, boolean included) {
+
+        super(response);
+        setIncluded(included);
+
+    }
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * Is this wrapped response the subject of an <code>include()</code>
+     * call?
+     */
+    protected boolean included = false;
+
+
+    /**
+     * The string manager for this package.
+     */
+    protected static StringManager sm =
+        StringManager.getManager(Constants.Package);
+
+
+    // ------------------------------------------------ ServletResponse Methods
+
+
+    /**
+     * Disallow <code>reset()</code> calls on a included response.
+     *
+     * @exception IllegalStateException if the response has already
+     *  been committed
+     */
+    public void reset() {
+
+        // If already committed, the wrapped response will throw ISE
+        if (!included || getResponse().isCommitted())
+            getResponse().reset();
+
+    }
+
+
+    /**
+     * Disallow <code>setContentLength()</code> calls on an included response.
+     *
+     * @param len The new content length
+     */
+    public void setContentLength(int len) {
+
+        if (!included)
+            getResponse().setContentLength(len);
+
+    }
+
+
+    /**
+     * Disallow <code>setContentType()</code> calls on an included response.
+     *
+     * @param type The new content type
+     */
+    public void setContentType(String type) {
+
+        if (!included)
+            getResponse().setContentType(type);
+
+    }
+
+
+    /**
+     * Ignore <code>setLocale()</code> calls on an included response.
+     *
+     * @param loc The new locale
+     */
+    public void setLocale(Locale loc) {
+        if (!included)
+            getResponse().setLocale(loc);
+    }
+
+
+    /**
+     * Ignore <code>setBufferSize()</code> calls on an included response.
+     *
+     * @param size The buffer size
+     */
+    public void setBufferSize(int size) {
+        if (!included)
+            getResponse().setBufferSize(size);
+    }
+
+
+    // ----------------------------------------- ServletResponseWrapper Methods
+
+
+    /**
+     * Set the response that we are wrapping.
+     *
+     * @param response The new wrapped response
+     */
+    public void setResponse(ServletResponse response) {
+
+        super.setResponse(response);
+
+    }
+
+
+    // -------------------------------------------------------- Package Methods
+
+
+    /**
+     * Return the included flag for this response.
+     */
+    boolean isIncluded() {
+
+        return (this.included);
+
+    }
+
+
+    /**
+     * Set the included flag for this response.
+     *
+     * @param included The new included flag
+     */
+    void setIncluded(boolean included) {
+
+        this.included = included;
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/core/AprLifecycleListener.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/core/AprLifecycleListener.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/core/AprLifecycleListener.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,134 @@
+/*
+ * Copyright 2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.lang.reflect.Method;
+import org.apache.catalina.Lifecycle;
+import org.apache.catalina.LifecycleEvent;
+import org.apache.catalina.LifecycleListener;
+import org.apache.catalina.util.StringManager;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+
+/**
+ * Implementation of <code>LifecycleListener</code> that will init and
+ * and destroy APR.
+ *
+ * @author Remy Maucherat
+ * @version $Revision: 441786 $ $Date: 2006-09-09 07:26:11 -0500 (Sat, 09 Sep 2006) $
+ * @since 4.1
+ */
+
+public class AprLifecycleListener
+    implements LifecycleListener {
+
+    private static Log log = LogFactory.getLog(AprLifecycleListener.class);
+
+    /**
+     * The string manager for this package.
+     */
+    protected StringManager sm =
+        StringManager.getManager(Constants.Package);
+
+    
+    // -------------------------------------------------------------- Constants
+
+
+    protected static final int REQUIRED_MAJOR = 1;
+    protected static final int REQUIRED_MINOR = 1;
+    protected static final int REQUIRED_PATCH = 3;
+    protected static final int RECOMMENDED_PV = 4;
+
+
+    // ---------------------------------------------- LifecycleListener Methods
+
+
+    /**
+     * Primary entry point for startup and shutdown events.
+     *
+     * @param event The event that has occurred
+     */
+    public void lifecycleEvent(LifecycleEvent event) {
+
+        if (Lifecycle.INIT_EVENT.equals(event.getType())) {
+            int major = 0;
+            int minor = 0;
+            int patch = 0;
+            try {
+                String methodName = "initialize";
+                Class paramTypes[] = new Class[1];
+                paramTypes[0] = String.class;
+                Object paramValues[] = new Object[1];
+                paramValues[0] = null;
+                Class clazz = Class.forName("org.apache.tomcat.jni.Library");
+                Method method = clazz.getMethod(methodName, paramTypes);
+                method.invoke(null, paramValues);
+                major = clazz.getField("TCN_MAJOR_VERSION").getInt(null);
+                minor = clazz.getField("TCN_MINOR_VERSION").getInt(null);
+                patch = clazz.getField("TCN_PATCH_VERSION").getInt(null);
+            } catch (Throwable t) {
+                if (!log.isDebugEnabled()) {
+                    log.info(sm.getString("aprListener.aprInit", 
+                            System.getProperty("java.library.path")));
+                } else {
+                    log.debug(sm.getString("aprListener.aprInit", 
+                            System.getProperty("java.library.path")), t);
+                }
+                return;
+            }
+            if ((major != REQUIRED_MAJOR) || (minor != REQUIRED_MINOR)
+                    || (patch < REQUIRED_PATCH)) {
+                log.error(sm.getString("aprListener.tcnInvalid", major + "." 
+                        + minor + "." + patch, REQUIRED_MAJOR + "." 
+                        + REQUIRED_MINOR + "." + REQUIRED_PATCH));
+            }
+            if (patch < RECOMMENDED_PV) {
+                /* The version is lower then recommended.
+                 * Instruct the user to consider upgrading the native
+                 * to the current stable version.
+                 */
+                if (!log.isDebugEnabled()) {
+                    log.info(sm.getString("aprListener.tcnVersion", major + "." 
+                            + minor + "." + patch, REQUIRED_MAJOR + "." 
+                            + REQUIRED_MINOR + "." + RECOMMENDED_PV));
+                } else {
+                    log.debug(sm.getString("aprListener.tcnVersion", major + "." 
+                            + minor + "." + patch, REQUIRED_MAJOR + "." 
+                            + REQUIRED_MINOR + "." + RECOMMENDED_PV));
+                }                
+            }
+        } else if (Lifecycle.AFTER_STOP_EVENT.equals(event.getType())) {
+            try {
+                String methodName = "terminate";
+                Method method = Class.forName("org.apache.tomcat.jni.Library")
+                    .getMethod(methodName, (Class [])null);
+                method.invoke(null, (Object []) null);
+            } catch (Throwable t) {
+                if (!log.isDebugEnabled()) {
+                    log.info(sm.getString("aprListener.aprDestroy"));
+                } else {
+                    log.debug(sm.getString("aprListener.aprDestroy"), t);
+                }
+            }
+        }
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/core/Constants.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/core/Constants.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/core/Constants.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,31 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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;
+
+
+public class Constants {
+
+    public static final String Package = "org.apache.catalina.core";
+    public static final int MAJOR_VERSION = 2;
+    public static final int MINOR_VERSION = 4;
+
+    public static final String JSP_SERVLET_CLASS =
+        "org.apache.jasper.servlet.JspServlet";
+    public static final String JSP_SERVLET_NAME = "jsp";
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/core/ContainerBase.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/core/ContainerBase.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/core/ContainerBase.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,1586 @@
+/*
+ * Copyright 1999-2001,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.beans.PropertyChangeListener;
+import java.beans.PropertyChangeSupport;
+import java.io.IOException;
+import java.io.Serializable;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.Iterator;
+
+import javax.management.MBeanRegistration;
+import javax.management.MBeanServer;
+import javax.management.MalformedObjectNameException;
+import javax.management.ObjectName;
+import javax.naming.directory.DirContext;
+import javax.servlet.ServletException;
+
+import org.apache.catalina.Cluster;
+import org.apache.catalina.Container;
+import org.apache.catalina.ContainerEvent;
+import org.apache.catalina.ContainerListener;
+import org.apache.catalina.Lifecycle;
+import org.apache.catalina.LifecycleException;
+import org.apache.catalina.LifecycleListener;
+import org.apache.catalina.Loader;
+import org.apache.catalina.Manager;
+import org.apache.catalina.Pipeline;
+import org.apache.catalina.Realm;
+import org.apache.catalina.Valve;
+import org.apache.catalina.connector.Request;
+import org.apache.catalina.connector.Response;
+import org.apache.catalina.util.LifecycleSupport;
+import org.apache.catalina.util.StringManager;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.commons.modeler.Registry;
+import org.apache.naming.resources.ProxyDirContext;
+
+
+/**
+ * Abstract implementation of the <b>Container</b> interface, providing common
+ * functionality required by nearly every implementation.  Classes extending
+ * this base class must implement <code>getInfo()</code>, and may implement
+ * a replacement for <code>invoke()</code>.
+ * <p>
+ * All subclasses of this abstract base class will include support for a
+ * Pipeline object that defines the processing to be performed for each request
+ * received by the <code>invoke()</code> method of this class, utilizing the
+ * "Chain of Responsibility" design pattern.  A subclass should encapsulate its
+ * own processing functionality as a <code>Valve</code>, and configure this
+ * Valve into the pipeline by calling <code>setBasic()</code>.
+ * <p>
+ * This implementation fires property change events, per the JavaBeans design
+ * pattern, for changes in singleton properties.  In addition, it fires the
+ * following <code>ContainerEvent</code> events to listeners who register
+ * themselves with <code>addContainerListener()</code>:
+ * <table border=1>
+ *   <tr>
+ *     <th>Type</th>
+ *     <th>Data</th>
+ *     <th>Description</th>
+ *   </tr>
+ *   <tr>
+ *     <td align=center><code>addChild</code></td>
+ *     <td align=center><code>Container</code></td>
+ *     <td>Child container added to this Container.</td>
+ *   </tr>
+ *   <tr>
+ *     <td align=center><code>addValve</code></td>
+ *     <td align=center><code>Valve</code></td>
+ *     <td>Valve added to this Container.</td>
+ *   </tr>
+ *   <tr>
+ *     <td align=center><code>removeChild</code></td>
+ *     <td align=center><code>Container</code></td>
+ *     <td>Child container removed from this Container.</td>
+ *   </tr>
+ *   <tr>
+ *     <td align=center><code>removeValve</code></td>
+ *     <td align=center><code>Valve</code></td>
+ *     <td>Valve removed from this Container.</td>
+ *   </tr>
+ *   <tr>
+ *     <td align=center><code>start</code></td>
+ *     <td align=center><code>null</code></td>
+ *     <td>Container was started.</td>
+ *   </tr>
+ *   <tr>
+ *     <td align=center><code>stop</code></td>
+ *     <td align=center><code>null</code></td>
+ *     <td>Container was stopped.</td>
+ *   </tr>
+ * </table>
+ * Subclasses that fire additional events should document them in the
+ * class comments of the implementation class.
+ *
+ * @author Craig R. McClanahan
+ */
+
+public abstract class ContainerBase
+    implements Container, Lifecycle, Pipeline, MBeanRegistration, Serializable {
+
+    private static org.apache.commons.logging.Log log=
+        org.apache.commons.logging.LogFactory.getLog( ContainerBase.class );
+
+    /**
+     * Perform addChild with the permissions of this class.
+     * addChild can be called with the XML parser on the stack,
+     * this allows the XML parser to have fewer privileges than
+     * Tomcat.
+     */
+    protected class PrivilegedAddChild
+        implements PrivilegedAction {
+
+        private Container child;
+
+        PrivilegedAddChild(Container child) {
+            this.child = child;
+        }
+
+        public Object run() {
+            addChildInternal(child);
+            return null;
+        }
+
+    }
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The child Containers belonging to this Container, keyed by name.
+     */
+    protected HashMap children = new HashMap();
+
+
+    /**
+     * The processor delay for this component.
+     */
+    protected int backgroundProcessorDelay = -1;
+
+
+    /**
+     * The lifecycle event support for this component.
+     */
+    protected LifecycleSupport lifecycle = new LifecycleSupport(this);
+
+
+    /**
+     * The container event listeners for this Container.
+     */
+    protected ArrayList listeners = new ArrayList();
+
+
+    /**
+     * The Loader implementation with which this Container is associated.
+     */
+    protected Loader loader = null;
+
+
+    /**
+     * The Logger implementation with which this Container is associated.
+     */
+    protected Log logger = null;
+
+
+    /**
+     * Associated logger name.
+     */
+    protected String logName = null;
+    
+
+    /**
+     * The Manager implementation with which this Container is associated.
+     */
+    protected Manager manager = null;
+
+
+    /**
+     * The cluster with which this Container is associated.
+     */
+    protected Cluster cluster = null;
+
+    
+    /**
+     * The human-readable name of this Container.
+     */
+    protected String name = null;
+
+
+    /**
+     * The parent Container to which this Container is a child.
+     */
+    protected Container parent = null;
+
+
+    /**
+     * The parent class loader to be configured when we install a Loader.
+     */
+    protected ClassLoader parentClassLoader = null;
+
+
+    /**
+     * The Pipeline object with which this Container is associated.
+     */
+    protected Pipeline pipeline = new StandardPipeline(this);
+
+
+    /**
+     * The Realm with which this Container is associated.
+     */
+    protected Realm realm = null;
+
+
+    /**
+     * The resources DirContext object with which this Container is associated.
+     */
+    protected DirContext resources = null;
+
+
+    /**
+     * The string manager for this package.
+     */
+    protected static StringManager sm =
+        StringManager.getManager(Constants.Package);
+
+
+    /**
+     * Has this component been started?
+     */
+    protected boolean started = false;
+
+    protected boolean initialized=false;
+
+    /**
+     * The property change support for this component.
+     */
+    protected PropertyChangeSupport support = new PropertyChangeSupport(this);
+
+
+    /**
+     * The background thread.
+     */
+    private Thread thread = null;
+
+
+    /**
+     * The background thread completion semaphore.
+     */
+    private boolean threadDone = false;
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * Get the delay between the invocation of the backgroundProcess method on
+     * this container and its children. Child containers will not be invoked
+     * if their delay value is not negative (which would mean they are using 
+     * their own thread). Setting this to a positive value will cause 
+     * a thread to be spawn. After waiting the specified amount of time, 
+     * the thread will invoke the executePeriodic method on this container 
+     * and all its children.
+     */
+    public int getBackgroundProcessorDelay() {
+        return backgroundProcessorDelay;
+    }
+
+
+    /**
+     * Set the delay between the invocation of the execute method on this
+     * container and its children.
+     * 
+     * @param delay The delay in seconds between the invocation of 
+     *              backgroundProcess methods
+     */
+    public void setBackgroundProcessorDelay(int delay) {
+        backgroundProcessorDelay = delay;
+    }
+
+
+    /**
+     * Return descriptive information about this Container implementation and
+     * the corresponding version number, in the format
+     * <code>&lt;description&gt;/&lt;version&gt;</code>.
+     */
+    public String getInfo() {
+        return this.getClass().getName();
+    }
+
+
+    /**
+     * Return the Loader with which this Container is associated.  If there is
+     * no associated Loader, return the Loader associated with our parent
+     * Container (if any); otherwise, return <code>null</code>.
+     */
+    public Loader getLoader() {
+
+        if (loader != null)
+            return (loader);
+        if (parent != null)
+            return (parent.getLoader());
+        return (null);
+
+    }
+
+
+    /**
+     * Set the Loader with which this Container is associated.
+     *
+     * @param loader The newly associated loader
+     */
+    public synchronized void setLoader(Loader loader) {
+
+        // Change components if necessary
+        Loader oldLoader = this.loader;
+        if (oldLoader == loader)
+            return;
+        this.loader = loader;
+
+        // Stop the old component if necessary
+        if (started && (oldLoader != null) &&
+            (oldLoader instanceof Lifecycle)) {
+            try {
+                ((Lifecycle) oldLoader).stop();
+            } catch (LifecycleException e) {
+                log.error("ContainerBase.setLoader: stop: ", e);
+            }
+        }
+
+        // Start the new component if necessary
+        if (loader != null)
+            loader.setContainer(this);
+        if (started && (loader != null) &&
+            (loader instanceof Lifecycle)) {
+            try {
+                ((Lifecycle) loader).start();
+            } catch (LifecycleException e) {
+                log.error("ContainerBase.setLoader: start: ", e);
+            }
+        }
+
+        // Report this property change to interested listeners
+        support.firePropertyChange("loader", oldLoader, this.loader);
+
+    }
+
+
+    /**
+     * Return the Logger with which this Container is associated.  If there is
+     * no associated Logger, return the Logger associated with our parent
+     * Container (if any); otherwise return <code>null</code>.
+     */
+    public Log getLogger() {
+
+        if (logger != null)
+            return (logger);
+        logger = LogFactory.getLog(logName());
+        return (logger);
+
+    }
+
+
+    /**
+     * Return the Manager with which this Container is associated.  If there is
+     * no associated Manager, return the Manager associated with our parent
+     * Container (if any); otherwise return <code>null</code>.
+     */
+    public Manager getManager() {
+
+        if (manager != null)
+            return (manager);
+        if (parent != null)
+            return (parent.getManager());
+        return (null);
+
+    }
+
+
+    /**
+     * Set the Manager with which this Container is associated.
+     *
+     * @param manager The newly associated Manager
+     */
+    public synchronized void setManager(Manager manager) {
+
+        // Change components if necessary
+        Manager oldManager = this.manager;
+        if (oldManager == manager)
+            return;
+        this.manager = manager;
+
+        // Stop the old component if necessary
+        if (started && (oldManager != null) &&
+            (oldManager instanceof Lifecycle)) {
+            try {
+                ((Lifecycle) oldManager).stop();
+            } catch (LifecycleException e) {
+                log.error("ContainerBase.setManager: stop: ", e);
+            }
+        }
+
+        // Start the new component if necessary
+        if (manager != null)
+            manager.setContainer(this);
+        if (started && (manager != null) &&
+            (manager instanceof Lifecycle)) {
+            try {
+                ((Lifecycle) manager).start();
+            } catch (LifecycleException e) {
+                log.error("ContainerBase.setManager: start: ", e);
+            }
+        }
+
+        // Report this property change to interested listeners
+        support.firePropertyChange("manager", oldManager, this.manager);
+
+    }
+
+
+    /**
+     * Return an object which may be utilized for mapping to this component.
+     */
+    public Object getMappingObject() {
+        return this;
+    }
+
+
+    /**
+     * Return the Cluster with which this Container is associated.  If there is
+     * no associated Cluster, return the Cluster associated with our parent
+     * Container (if any); otherwise return <code>null</code>.
+     */
+    public Cluster getCluster() {
+        if (cluster != null)
+            return (cluster);
+
+        if (parent != null)
+            return (parent.getCluster());
+
+        return (null);
+    }
+
+
+    /**
+     * Set the Cluster with which this Container is associated.
+     *
+     * @param cluster The newly associated Cluster
+     */
+    public synchronized void setCluster(Cluster cluster) {
+        // Change components if necessary
+        Cluster oldCluster = this.cluster;
+        if (oldCluster == cluster)
+            return;
+        this.cluster = cluster;
+
+        // Stop the old component if necessary
+        if (started && (oldCluster != null) &&
+            (oldCluster instanceof Lifecycle)) {
+            try {
+                ((Lifecycle) oldCluster).stop();
+            } catch (LifecycleException e) {
+                log.error("ContainerBase.setCluster: stop: ", e);
+            }
+        }
+
+        // Start the new component if necessary
+        if (cluster != null)
+            cluster.setContainer(this);
+
+        if (started && (cluster != null) &&
+            (cluster instanceof Lifecycle)) {
+            try {
+                ((Lifecycle) cluster).start();
+            } catch (LifecycleException e) {
+                log.error("ContainerBase.setCluster: start: ", e);
+            }
+        }
+
+        // Report this property change to interested listeners
+        support.firePropertyChange("cluster", oldCluster, this.cluster);
+    }
+
+
+    /**
+     * Return a name string (suitable for use by humans) that describes this
+     * Container.  Within the set of child containers belonging to a particular
+     * parent, Container names must be unique.
+     */
+    public String getName() {
+
+        return (name);
+
+    }
+
+
+    /**
+     * Set a name string (suitable for use by humans) that describes this
+     * Container.  Within the set of child containers belonging to a particular
+     * parent, Container names must be unique.
+     *
+     * @param name New name of this container
+     *
+     * @exception IllegalStateException if this Container has already been
+     *  added to the children of a parent Container (after which the name
+     *  may not be changed)
+     */
+    public void setName(String name) {
+
+        String oldName = this.name;
+        this.name = name;
+        support.firePropertyChange("name", oldName, this.name);
+    }
+
+
+    /**
+     * Return the Container for which this Container is a child, if there is
+     * one.  If there is no defined parent, return <code>null</code>.
+     */
+    public Container getParent() {
+
+        return (parent);
+
+    }
+
+
+    /**
+     * Set the parent Container to which this Container is being added as a
+     * child.  This Container may refuse to become attached to the specified
+     * Container by throwing an exception.
+     *
+     * @param container Container to which this Container is being added
+     *  as a child
+     *
+     * @exception IllegalArgumentException if this Container refuses to become
+     *  attached to the specified Container
+     */
+    public void setParent(Container container) {
+
+        Container oldParent = this.parent;
+        this.parent = container;
+        support.firePropertyChange("parent", oldParent, this.parent);
+
+    }
+
+
+    /**
+     * Return the parent class loader (if any) for this web application.
+     * This call is meaningful only <strong>after</strong> a Loader has
+     * been configured.
+     */
+    public ClassLoader getParentClassLoader() {
+        if (parentClassLoader != null)
+            return (parentClassLoader);
+        if (parent != null) {
+            return (parent.getParentClassLoader());
+        }
+        return (ClassLoader.getSystemClassLoader());
+
+    }
+
+
+    /**
+     * Set the parent class loader (if any) for this web application.
+     * This call is meaningful only <strong>before</strong> a Loader has
+     * been configured, and the specified value (if non-null) should be
+     * passed as an argument to the class loader constructor.
+     *
+     *
+     * @param parent The new parent class loader
+     */
+    public void setParentClassLoader(ClassLoader parent) {
+        ClassLoader oldParentClassLoader = this.parentClassLoader;
+        this.parentClassLoader = parent;
+        support.firePropertyChange("parentClassLoader", oldParentClassLoader,
+                                   this.parentClassLoader);
+
+    }
+
+
+    /**
+     * Return the Pipeline object that manages the Valves associated with
+     * this Container.
+     */
+    public Pipeline getPipeline() {
+
+        return (this.pipeline);
+
+    }
+
+
+    /**
+     * Return the Realm with which this Container is associated.  If there is
+     * no associated Realm, return the Realm associated with our parent
+     * Container (if any); otherwise return <code>null</code>.
+     */
+    public Realm getRealm() {
+
+        if (realm != null)
+            return (realm);
+        if (parent != null)
+            return (parent.getRealm());
+        return (null);
+
+    }
+
+
+    /**
+     * Set the Realm with which this Container is associated.
+     *
+     * @param realm The newly associated Realm
+     */
+    public synchronized void setRealm(Realm realm) {
+
+        // Change components if necessary
+        Realm oldRealm = this.realm;
+        if (oldRealm == realm)
+            return;
+        this.realm = realm;
+
+        // Stop the old component if necessary
+        if (started && (oldRealm != null) &&
+            (oldRealm instanceof Lifecycle)) {
+            try {
+                ((Lifecycle) oldRealm).stop();
+            } catch (LifecycleException e) {
+                log.error("ContainerBase.setRealm: stop: ", e);
+            }
+        }
+
+        // Start the new component if necessary
+        if (realm != null)
+            realm.setContainer(this);
+        if (started && (realm != null) &&
+            (realm instanceof Lifecycle)) {
+            try {
+                ((Lifecycle) realm).start();
+            } catch (LifecycleException e) {
+                log.error("ContainerBase.setRealm: start: ", e);
+            }
+        }
+
+        // Report this property change to interested listeners
+        support.firePropertyChange("realm", oldRealm, this.realm);
+
+    }
+
+
+    /**
+      * Return the resources DirContext object with which this Container is
+      * associated.  If there is no associated resources object, return the
+      * resources associated with our parent Container (if any); otherwise
+      * return <code>null</code>.
+     */
+    public DirContext getResources() {
+        if (resources != null)
+            return (resources);
+        if (parent != null)
+            return (parent.getResources());
+        return (null);
+
+    }
+
+
+    /**
+     * Set the resources DirContext object with which this Container is
+     * associated.
+     *
+     * @param resources The newly associated DirContext
+     */
+    public synchronized void setResources(DirContext resources) {
+        // Called from StandardContext.setResources()
+        //              <- StandardContext.start() 
+        //              <- ContainerBase.addChildInternal() 
+
+        // Change components if necessary
+        DirContext oldResources = this.resources;
+        if (oldResources == resources)
+            return;
+        Hashtable env = new Hashtable();
+        if (getParent() != null)
+            env.put(ProxyDirContext.HOST, getParent().getName());
+        env.put(ProxyDirContext.CONTEXT, getName());
+        this.resources = new ProxyDirContext(env, resources);
+        // Report this property change to interested listeners
+        support.firePropertyChange("resources", oldResources, this.resources);
+
+    }
+
+
+    // ------------------------------------------------------ Container Methods
+
+
+    /**
+     * Add a new child Container to those associated with this Container,
+     * if supported.  Prior to adding this Container to the set of children,
+     * the child's <code>setParent()</code> method must be called, with this
+     * Container as an argument.  This method may thrown an
+     * <code>IllegalArgumentException</code> if this Container chooses not
+     * to be attached to the specified Container, in which case it is not added
+     *
+     * @param child New child Container to be added
+     *
+     * @exception IllegalArgumentException if this exception is thrown by
+     *  the <code>setParent()</code> method of the child Container
+     * @exception IllegalArgumentException if the new child does not have
+     *  a name unique from that of existing children of this Container
+     * @exception IllegalStateException if this Container does not support
+     *  child Containers
+     */
+    public void addChild(Container child) {
+        if (System.getSecurityManager() != null) {
+            PrivilegedAction dp =
+                new PrivilegedAddChild(child);
+            AccessController.doPrivileged(dp);
+        } else {
+            addChildInternal(child);
+        }
+    }
+
+    private void addChildInternal(Container child) {
+
+        if( log.isDebugEnabled() )
+            log.debug("Add child " + child + " " + this);
+        synchronized(children) {
+            if (children.get(child.getName()) != null)
+                throw new IllegalArgumentException("addChild:  Child name '" +
+                                                   child.getName() +
+                                                   "' is not unique");
+            child.setParent(this);  // May throw IAE
+            children.put(child.getName(), child);
+
+            // Start child
+            if (started && (child instanceof Lifecycle)) {
+                boolean success = false;
+                try {
+                    ((Lifecycle) child).start();
+                    success = true;
+                } catch (LifecycleException e) {
+                    log.error("ContainerBase.addChild: start: ", e);
+                    throw new IllegalStateException
+                        ("ContainerBase.addChild: start: " + e);
+                } finally {
+                    if (!success) {
+                        children.remove(child.getName());
+                    }
+                }
+            }
+
+            fireContainerEvent(ADD_CHILD_EVENT, child);
+        }
+
+    }
+
+
+    /**
+     * Add a container event listener to this component.
+     *
+     * @param listener The listener to add
+     */
+    public void addContainerListener(ContainerListener listener) {
+
+        synchronized (listeners) {
+            listeners.add(listener);
+        }
+
+    }
+
+
+    /**
+     * Add a property change listener to this component.
+     *
+     * @param listener The listener to add
+     */
+    public void addPropertyChangeListener(PropertyChangeListener listener) {
+
+        support.addPropertyChangeListener(listener);
+
+    }
+
+
+    /**
+     * Return the child Container, associated with this Container, with
+     * the specified name (if any); otherwise, return <code>null</code>
+     *
+     * @param name Name of the child Container to be retrieved
+     */
+    public Container findChild(String name) {
+
+        if (name == null)
+            return (null);
+        synchronized (children) {       // Required by post-start changes
+            return ((Container) children.get(name));
+        }
+
+    }
+
+
+    /**
+     * Return the set of children Containers associated with this Container.
+     * If this Container has no children, a zero-length array is returned.
+     */
+    public Container[] findChildren() {
+
+        synchronized (children) {
+            Container results[] = new Container[children.size()];
+            return ((Container[]) children.values().toArray(results));
+        }
+
+    }
+
+
+    /**
+     * Return the set of container listeners associated with this Container.
+     * If this Container has no registered container listeners, a zero-length
+     * array is returned.
+     */
+    public ContainerListener[] findContainerListeners() {
+
+        synchronized (listeners) {
+            ContainerListener[] results = 
+                new ContainerListener[listeners.size()];
+            return ((ContainerListener[]) listeners.toArray(results));
+        }
+
+    }
+
+
+    /**
+     * Process the specified Request, to produce the corresponding Response,
+     * by invoking the first Valve in our pipeline (if any), or the basic
+     * Valve otherwise.
+     *
+     * @param request Request to be processed
+     * @param response Response to be produced
+     *
+     * @exception IllegalStateException if neither a pipeline or a basic
+     *  Valve have been configured for this Container
+     * @exception IOException if an input/output error occurred while
+     *  processing
+     * @exception ServletException if a ServletException was thrown
+     *  while processing this request
+     */
+    public void invoke(Request request, Response response)
+        throws IOException, ServletException {
+
+        pipeline.getFirst().invoke(request, response);
+
+    }
+
+
+    /**
+     * Remove an existing child Container from association with this parent
+     * Container.
+     *
+     * @param child Existing child Container to be removed
+     */
+    public void removeChild(Container child) {
+
+        synchronized(children) {
+            if (children.get(child.getName()) == null)
+                return;
+            children.remove(child.getName());
+        }
+        
+        if (started && (child instanceof Lifecycle)) {
+            try {
+                if( child instanceof ContainerBase ) {
+                    if( ((ContainerBase)child).started ) {
+                        ((Lifecycle) child).stop();
+                    }
+                } else {
+                    ((Lifecycle) child).stop();
+                }
+            } catch (LifecycleException e) {
+                log.error("ContainerBase.removeChild: stop: ", e);
+            }
+        }
+        
+        fireContainerEvent(REMOVE_CHILD_EVENT, child);
+        
+        // child.setParent(null);
+
+    }
+
+
+    /**
+     * Remove a container event listener from this component.
+     *
+     * @param listener The listener to remove
+     */
+    public void removeContainerListener(ContainerListener listener) {
+
+        synchronized (listeners) {
+            listeners.remove(listener);
+        }
+
+    }
+
+
+    /**
+     * Remove a property change listener from this component.
+     *
+     * @param listener The listener to remove
+     */
+    public void removePropertyChangeListener(PropertyChangeListener listener) {
+
+        support.removePropertyChangeListener(listener);
+
+    }
+
+
+    // ------------------------------------------------------ Lifecycle Methods
+
+
+    /**
+     * Add a lifecycle event listener to this component.
+     *
+     * @param listener The listener to add
+     */
+    public void addLifecycleListener(LifecycleListener listener) {
+
+        lifecycle.addLifecycleListener(listener);
+
+    }
+
+
+    /**
+     * Get the lifecycle listeners associated with this lifecycle. If this 
+     * Lifecycle has no listeners registered, a zero-length array is returned.
+     */
+    public LifecycleListener[] findLifecycleListeners() {
+
+        return lifecycle.findLifecycleListeners();
+
+    }
+
+
+    /**
+     * Remove a lifecycle event listener from this component.
+     *
+     * @param listener The listener to remove
+     */
+    public void removeLifecycleListener(LifecycleListener listener) {
+
+        lifecycle.removeLifecycleListener(listener);
+
+    }
+
+
+    /**
+     * Prepare for active use of the public methods of this Component.
+     *
+     * @exception LifecycleException if this component detects a fatal error
+     *  that prevents it from being started
+     */
+    public synchronized void start() throws LifecycleException {
+
+        // Validate and update our current component state
+        if (started) {
+            if(log.isInfoEnabled())
+                log.info(sm.getString("containerBase.alreadyStarted", logName()));
+            return;
+        }
+        
+        // Notify our interested LifecycleListeners
+        lifecycle.fireLifecycleEvent(BEFORE_START_EVENT, null);
+
+        started = true;
+
+        // Start our subordinate components, if any
+        if ((loader != null) && (loader instanceof Lifecycle))
+            ((Lifecycle) loader).start();
+        logger = null;
+        getLogger();
+        if ((logger != null) && (logger instanceof Lifecycle))
+            ((Lifecycle) logger).start();
+        if ((manager != null) && (manager instanceof Lifecycle))
+            ((Lifecycle) manager).start();
+        if ((cluster != null) && (cluster instanceof Lifecycle))
+            ((Lifecycle) cluster).start();
+        if ((realm != null) && (realm instanceof Lifecycle))
+            ((Lifecycle) realm).start();
+        if ((resources != null) && (resources instanceof Lifecycle))
+            ((Lifecycle) resources).start();
+
+        // Start our child containers, if any
+        Container children[] = findChildren();
+        for (int i = 0; i < children.length; i++) {
+            if (children[i] instanceof Lifecycle)
+                ((Lifecycle) children[i]).start();
+        }
+
+        // Start the Valves in our pipeline (including the basic), if any
+        if (pipeline instanceof Lifecycle)
+            ((Lifecycle) pipeline).start();
+
+        // Notify our interested LifecycleListeners
+        lifecycle.fireLifecycleEvent(START_EVENT, null);
+
+        // Start our thread
+        threadStart();
+
+        // Notify our interested LifecycleListeners
+        lifecycle.fireLifecycleEvent(AFTER_START_EVENT, null);
+
+    }
+
+
+    /**
+     * Gracefully shut down active use of the public methods of this Component.
+     *
+     * @exception LifecycleException if this component detects a fatal error
+     *  that needs to be reported
+     */
+    public synchronized void stop() throws LifecycleException {
+
+        // Validate and update our current component state
+        if (!started) {
+            if(log.isInfoEnabled())
+                log.info(sm.getString("containerBase.notStarted", logName()));
+            return;
+        }
+
+        // Notify our interested LifecycleListeners
+        lifecycle.fireLifecycleEvent(BEFORE_STOP_EVENT, null);
+
+        // Stop our thread
+        threadStop();
+
+        // Notify our interested LifecycleListeners
+        lifecycle.fireLifecycleEvent(STOP_EVENT, null);
+        started = false;
+
+        // Stop the Valves in our pipeline (including the basic), if any
+        if (pipeline instanceof Lifecycle) {
+            ((Lifecycle) pipeline).stop();
+        }
+
+        // Stop our child containers, if any
+        Container children[] = findChildren();
+        for (int i = 0; i < children.length; i++) {
+            if (children[i] instanceof Lifecycle)
+                ((Lifecycle) children[i]).stop();
+        }
+        // Remove children - so next start can work
+        children = findChildren();
+        for (int i = 0; i < children.length; i++) {
+            removeChild(children[i]);
+        }
+
+        // Stop our subordinate components, if any
+        if ((resources != null) && (resources instanceof Lifecycle)) {
+            ((Lifecycle) resources).stop();
+        }
+        if ((realm != null) && (realm instanceof Lifecycle)) {
+            ((Lifecycle) realm).stop();
+        }
+        if ((cluster != null) && (cluster instanceof Lifecycle)) {
+            ((Lifecycle) cluster).stop();
+        }
+        if ((manager != null) && (manager instanceof Lifecycle)) {
+            ((Lifecycle) manager).stop();
+        }
+        if ((logger != null) && (logger instanceof Lifecycle)) {
+            ((Lifecycle) logger).stop();
+        }
+        if ((loader != null) && (loader instanceof Lifecycle)) {
+            ((Lifecycle) loader).stop();
+        }
+
+        // Notify our interested LifecycleListeners
+        lifecycle.fireLifecycleEvent(AFTER_STOP_EVENT, null);
+
+    }
+
+    /** Init method, part of the MBean lifecycle.
+     *  If the container was added via JMX, it'll register itself with the 
+     * parent, using the ObjectName conventions to locate the parent.
+     * 
+     *  If the container was added directly and it doesn't have an ObjectName,
+     * it'll create a name and register itself with the JMX console. On destroy(), 
+     * the object will unregister.
+     * 
+     * @throws Exception
+     */ 
+    public void init() throws Exception {
+
+        if( this.getParent() == null ) {
+            // "Life" update
+            ObjectName parentName=getParentName();
+
+            //log.info("Register " + parentName );
+            if( parentName != null && 
+                    mserver.isRegistered(parentName)) 
+            {
+                mserver.invoke(parentName, "addChild", new Object[] { this },
+                        new String[] {"org.apache.catalina.Container"});
+            }
+        }
+        initialized=true;
+    }
+    
+    public ObjectName getParentName() throws MalformedObjectNameException {
+        return null;
+    }
+    
+    public void destroy() throws Exception {
+        if( started ) {
+            stop();
+        }
+        initialized=false;
+
+        // unregister this component
+        if ( oname != null ) {
+            try {
+                if( controller == oname ) {
+                    Registry.getRegistry(null, null)
+                        .unregisterComponent(oname);
+                    if(log.isDebugEnabled())
+                        log.debug("unregistering " + oname);
+                }
+            } catch( Throwable t ) {
+                log.error("Error unregistering ", t );
+            }
+        }
+
+        if (parent != null) {
+            parent.removeChild(this);
+        }
+
+        // Stop our child containers, if any
+        Container children[] = findChildren();
+        for (int i = 0; i < children.length; i++) {
+            removeChild(children[i]);
+        }
+                
+    }
+
+    // ------------------------------------------------------- Pipeline Methods
+
+
+    /**
+     * Add a new Valve to the end of the pipeline associated with this
+     * Container.  Prior to adding the Valve, the Valve's
+     * <code>setContainer</code> method must be called, with this Container
+     * as an argument.  The method may throw an
+     * <code>IllegalArgumentException</code> if this Valve chooses not to
+     * be associated with this Container, or <code>IllegalStateException</code>
+     * if it is already associated with a different Container.
+     *
+     * @param valve Valve to be added
+     *
+     * @exception IllegalArgumentException if this Container refused to
+     *  accept the specified Valve
+     * @exception IllegalArgumentException if the specifie Valve refuses to be
+     *  associated with this Container
+     * @exception IllegalStateException if the specified Valve is already
+     *  associated with a different Container
+     */
+    public synchronized void addValve(Valve valve) {
+
+        pipeline.addValve(valve);
+        fireContainerEvent(ADD_VALVE_EVENT, valve);
+    }
+
+    public ObjectName[] getValveObjectNames() {
+        return ((StandardPipeline)pipeline).getValveObjectNames();
+    }
+    
+    /**
+     * <p>Return the Valve instance that has been distinguished as the basic
+     * Valve for this Pipeline (if any).
+     */
+    public Valve getBasic() {
+
+        return (pipeline.getBasic());
+
+    }
+
+
+    /**
+     * Return the first valve in the pipeline.
+     */
+    public Valve getFirst() {
+
+        return (pipeline.getFirst());
+
+    }
+
+
+    /**
+     * Return the set of Valves in the pipeline associated with this
+     * Container, including the basic Valve (if any).  If there are no
+     * such Valves, a zero-length array is returned.
+     */
+    public Valve[] getValves() {
+
+        return (pipeline.getValves());
+
+    }
+
+
+    /**
+     * Remove the specified Valve from the pipeline associated with this
+     * Container, if it is found; otherwise, do nothing.
+     *
+     * @param valve Valve to be removed
+     */
+    public synchronized void removeValve(Valve valve) {
+
+        pipeline.removeValve(valve);
+        fireContainerEvent(REMOVE_VALVE_EVENT, valve);
+    }
+
+
+    /**
+     * <p>Set the Valve instance that has been distinguished as the basic
+     * Valve for this Pipeline (if any).  Prioer to setting the basic Valve,
+     * the Valve's <code>setContainer()</code> will be called, if it
+     * implements <code>Contained</code>, with the owning Container as an
+     * argument.  The method may throw an <code>IllegalArgumentException</code>
+     * if this Valve chooses not to be associated with this Container, or
+     * <code>IllegalStateException</code> if it is already associated with
+     * a different Container.</p>
+     *
+     * @param valve Valve to be distinguished as the basic Valve
+     */
+    public void setBasic(Valve valve) {
+
+        pipeline.setBasic(valve);
+
+    }
+
+
+    /**
+     * Execute a periodic task, such as reloading, etc. This method will be
+     * invoked inside the classloading context of this container. Unexpected
+     * throwables will be caught and logged.
+     */
+    public void backgroundProcess() {
+        
+        if (!started)
+            return;
+
+        if (cluster != null) {
+            try {
+                cluster.backgroundProcess();
+            } catch (Exception e) {
+                log.warn(sm.getString("containerBase.backgroundProcess.cluster", cluster), e);                
+            }
+        }
+        if (loader != null) {
+            try {
+                loader.backgroundProcess();
+            } catch (Exception e) {
+                log.warn(sm.getString("containerBase.backgroundProcess.loader", loader), e);                
+            }
+        }
+        if (manager != null) {
+            try {
+                manager.backgroundProcess();
+            } catch (Exception e) {
+                log.warn(sm.getString("containerBase.backgroundProcess.manager", manager), e);                
+            }
+        }
+        if (realm != null) {
+            try {
+                realm.backgroundProcess();
+            } catch (Exception e) {
+                log.warn(sm.getString("containerBase.backgroundProcess.realm", realm), e);                
+            }
+        }
+        Valve current = pipeline.getFirst();
+        while (current != null) {
+            try {
+                current.backgroundProcess();
+            } catch (Exception e) {
+                log.warn(sm.getString("containerBase.backgroundProcess.valve", current), e);                
+            }
+            current = current.getNext();
+        }
+        lifecycle.fireLifecycleEvent(Lifecycle.PERIODIC_EVENT, null);
+    }
+
+
+    // ------------------------------------------------------ Protected Methods
+
+
+    /**
+     * Notify all container event listeners that a particular event has
+     * occurred for this Container.  The default implementation performs
+     * this notification synchronously using the calling thread.
+     *
+     * @param type Event type
+     * @param data Event data
+     */
+    public void fireContainerEvent(String type, Object data) {
+
+        if (listeners.size() < 1)
+            return;
+        ContainerEvent event = new ContainerEvent(this, type, data);
+        ContainerListener list[] = new ContainerListener[0];
+        synchronized (listeners) {
+            list = (ContainerListener[]) listeners.toArray(list);
+        }
+        for (int i = 0; i < list.length; i++)
+            ((ContainerListener) list[i]).containerEvent(event);
+
+    }
+
+
+    /**
+     * Return the abbreviated name of this container for logging messsages
+     */
+    protected String logName() {
+
+        if (logName != null) {
+            return logName;
+        }
+        String loggerName = null;
+        Container current = this;
+        while (current != null) {
+            String name = current.getName();
+            if ((name == null) || (name.equals(""))) {
+                name = "/";
+            }
+            loggerName = "[" + name + "]" 
+                + ((loggerName != null) ? ("." + loggerName) : "");
+            current = current.getParent();
+        }
+        logName = ContainerBase.class.getName() + "." + loggerName;
+        return logName;
+        
+    }
+
+    
+    // -------------------- JMX and Registration  --------------------
+    protected String type;
+    protected String domain;
+    protected String suffix;
+    protected ObjectName oname;
+    protected ObjectName controller;
+    protected transient MBeanServer mserver;
+
+    public ObjectName getJmxName() {
+        return oname;
+    }
+    
+    public String getObjectName() {
+        if (oname != null) {
+            return oname.toString();
+        } else return null;
+    }
+
+    public String getDomain() {
+        if( domain==null ) {
+            Container parent=this;
+            while( parent != null &&
+                    !( parent instanceof StandardEngine) ) {
+                parent=parent.getParent();
+            }
+            if( parent instanceof StandardEngine ) {
+                domain=((StandardEngine)parent).getDomain();
+            } 
+        }
+        return domain;
+    }
+
+    public void setDomain(String domain) {
+        this.domain=domain;
+    }
+    
+    public String getType() {
+        return type;
+    }
+
+    protected String getJSR77Suffix() {
+        return suffix;
+    }
+
+    public ObjectName preRegister(MBeanServer server,
+                                  ObjectName name) throws Exception {
+        oname=name;
+        mserver=server;
+        if (name == null ){
+            return null;
+        }
+
+        domain=name.getDomain();
+
+        type=name.getKeyProperty("type");
+        if( type==null ) {
+            type=name.getKeyProperty("j2eeType");
+        }
+
+        String j2eeApp=name.getKeyProperty("J2EEApplication");
+        String j2eeServer=name.getKeyProperty("J2EEServer");
+        if( j2eeApp==null ) {
+            j2eeApp="none";
+        }
+        if( j2eeServer==null ) {
+            j2eeServer="none";
+        }
+        suffix=",J2EEApplication=" + j2eeApp + ",J2EEServer=" + j2eeServer;
+        return name;
+    }
+
+    public void postRegister(Boolean registrationDone) {
+    }
+
+    public void preDeregister() throws Exception {
+    }
+
+    public void postDeregister() {
+    }
+
+    public ObjectName[] getChildren() {
+        ObjectName result[]=new ObjectName[children.size()];
+        Iterator it=children.values().iterator();
+        int i=0;
+        while( it.hasNext() ) {
+            Object next=it.next();
+            if( next instanceof ContainerBase ) {
+                result[i++]=((ContainerBase)next).getJmxName();
+            }
+        }
+        return result;
+    }
+
+    public ObjectName createObjectName(String domain, ObjectName parent)
+        throws Exception
+    {
+        if( log.isDebugEnabled())
+            log.debug("Create ObjectName " + domain + " " + parent );
+        return null;
+    }
+
+    public String getContainerSuffix() {
+        Container container=this;
+        Container context=null;
+        Container host=null;
+        Container servlet=null;
+        
+        StringBuffer suffix=new StringBuffer();
+        
+        if( container instanceof StandardHost ) {
+            host=container;
+        } else if( container instanceof StandardContext ) {
+            host=container.getParent();
+            context=container;
+        } else if( container instanceof StandardWrapper ) {
+            context=container.getParent();
+            host=context.getParent();
+            servlet=container;
+        }
+        if( context!=null ) {
+            String path=((StandardContext)context).getPath();
+            suffix.append(",path=").append((path.equals("")) ? "/" : path);
+        } 
+        if( host!=null ) suffix.append(",host=").append( host.getName() );
+        if( servlet != null ) {
+            String name=container.getName();
+            suffix.append(",servlet=");
+            suffix.append((name=="") ? "/" : name);
+        }
+        return suffix.toString();
+    }
+
+
+    /**
+     * Start the background thread that will periodically check for
+     * session timeouts.
+     */
+    protected void threadStart() {
+
+        if (thread != null)
+            return;
+        if (backgroundProcessorDelay <= 0)
+            return;
+
+        threadDone = false;
+        String threadName = "ContainerBackgroundProcessor[" + toString() + "]";
+        thread = new Thread(new ContainerBackgroundProcessor(), threadName);
+        thread.setDaemon(true);
+        thread.start();
+
+    }
+
+
+    /**
+     * Stop the background thread that is periodically checking for
+     * session timeouts.
+     */
+    protected void threadStop() {
+
+        if (thread == null)
+            return;
+
+        threadDone = true;
+        thread.interrupt();
+        try {
+            thread.join();
+        } catch (InterruptedException e) {
+            ;
+        }
+
+        thread = null;
+
+    }
+
+
+    // -------------------------------------- ContainerExecuteDelay Inner Class
+
+
+    /**
+     * Private thread class to invoke the backgroundProcess method 
+     * of this container and its children after a fixed delay.
+     */
+    protected class ContainerBackgroundProcessor implements Runnable {
+
+        public void run() {
+            while (!threadDone) {
+                try {
+                    Thread.sleep(backgroundProcessorDelay * 1000L);
+                } catch (InterruptedException e) {
+                    ;
+                }
+                if (!threadDone) {
+                    Container parent = (Container) getMappingObject();
+                    ClassLoader cl = 
+                        Thread.currentThread().getContextClassLoader();
+                    if (parent.getLoader() != null) {
+                        cl = parent.getLoader().getClassLoader();
+                    }
+                    processChildren(parent, cl);
+                }
+            }
+        }
+
+        protected void processChildren(Container container, ClassLoader cl) {
+            try {
+                if (container.getLoader() != null) {
+                    Thread.currentThread().setContextClassLoader
+                        (container.getLoader().getClassLoader());
+                }
+                container.backgroundProcess();
+            } catch (Throwable t) {
+                log.error("Exception invoking periodic operation: ", t);
+            } finally {
+                Thread.currentThread().setContextClassLoader(cl);
+            }
+            Container[] children = container.findChildren();
+            for (int i = 0; i < children.length; i++) {
+                if (children[i].getBackgroundProcessorDelay() <= 0) {
+                    processChildren(children[i], cl);
+                }
+            }
+        }
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/core/DummyRequest.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/core/DummyRequest.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/core/DummyRequest.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,267 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.UnsupportedEncodingException;
+import java.net.Socket;
+import java.security.Principal;
+import java.util.Enumeration;
+import java.util.Iterator;
+import java.util.Locale;
+import java.util.Map;
+
+import javax.servlet.FilterChain;
+import javax.servlet.RequestDispatcher;
+import javax.servlet.ServletInputStream;
+import javax.servlet.ServletRequest;
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpSession;
+
+import org.apache.catalina.Context;
+import org.apache.catalina.Host;
+import org.apache.catalina.Wrapper;
+import org.apache.catalina.connector.Connector;
+import org.apache.catalina.connector.Response;
+import org.apache.tomcat.util.buf.MessageBytes;
+
+
+/**
+ * Dummy request object, used for request dispatcher mapping, as well as
+ * JSP precompilation.
+ *
+ * @author Remy Maucherat
+ * @version $Revision: 302975 $ $Date: 2004-06-23 03:25:04 -0500 (Wed, 23 Jun 2004) $
+ */
+
+public class DummyRequest
+    implements HttpServletRequest {
+
+    public DummyRequest() {
+    }
+
+    public DummyRequest(String contextPath, String decodedURI,
+                        String queryString) {
+        this.contextPath = contextPath;
+        this.decodedURI = decodedURI;
+        this.queryString = queryString;
+    }
+
+    protected String contextPath = null;
+    protected String decodedURI = null;
+    protected String queryString = null;
+
+    protected String pathInfo = null;
+    protected String servletPath = null;
+    protected Wrapper wrapper = null;
+
+    protected FilterChain filterChain = null;
+    
+    private static Enumeration dummyEnum = new Enumeration(){
+        public boolean hasMoreElements(){
+            return false;
+        }
+        public Object nextElement(){
+            return null;
+        }
+    };
+
+    public String getContextPath() {
+        return (contextPath);
+    }
+
+    public MessageBytes getContextPathMB() {
+        return null;
+    }
+
+    public ServletRequest getRequest() {
+        return (this);
+    }
+
+    public String getDecodedRequestURI() {
+        return decodedURI;
+    }
+
+    public MessageBytes getDecodedRequestURIMB() {
+        return null;
+    }
+
+    public FilterChain getFilterChain() {
+        return (this.filterChain);
+    }
+
+    public void setFilterChain(FilterChain filterChain) {
+        this.filterChain = filterChain;
+    }
+
+    public String getQueryString() {
+        return queryString;
+    }
+
+    public void setQueryString(String query) {
+        queryString = query;
+    }
+
+    public String getPathInfo() {
+        return pathInfo;
+    }
+
+    public void setPathInfo(String path) {
+        pathInfo = path;
+    }
+
+    public MessageBytes getPathInfoMB() {
+        return null;
+    }
+
+    public MessageBytes getRequestPathMB() {
+        return null;
+    }
+
+    public String getServletPath() {
+        return servletPath;
+    }
+
+    public void setServletPath(String path) {
+        servletPath = path;
+    }
+
+    public MessageBytes getServletPathMB() {
+        return null;
+    }
+
+    public Wrapper getWrapper() {
+        return (this.wrapper);
+    }
+
+    public void setWrapper(Wrapper wrapper) {
+        this.wrapper = wrapper;
+    }
+
+    public String getAuthorization() { return null; }
+    public void setAuthorization(String authorization) {}
+    public Connector getConnector() { return null; }
+    public void setConnector(Connector connector) {}
+    public Context getContext() { return null; }
+    public void setContext(Context context) {}
+    public Host getHost() { return null; }
+    public void setHost(Host host) {}
+    public String getInfo() { return null; }
+    public Response getResponse() { return null; }
+    public void setResponse(Response response) {}
+    public Socket getSocket() { return null; }
+    public void setSocket(Socket socket) {}
+    public InputStream getStream() { return null; }
+    public void setStream(InputStream input) {}
+    public void addLocale(Locale locale) {}
+    public ServletInputStream createInputStream() throws IOException {
+        return null;
+    }
+    public void finishRequest() throws IOException {}
+    public Object getNote(String name) { return null; }
+    public Iterator getNoteNames() { return null; }
+    public void removeNote(String name) {}
+    public void setContentType(String type) {}
+    public void setNote(String name, Object value) {}
+    public void setProtocol(String protocol) {}
+    public void setRemoteAddr(String remoteAddr) {}
+    public void setRemoteHost(String remoteHost) {}
+    public void setScheme(String scheme) {}
+    public void setServerName(String name) {}
+    public void setServerPort(int port) {}
+    public Object getAttribute(String name) { return null; }
+    public Enumeration getAttributeNames() { return null; }
+    public String getCharacterEncoding() { return null; }
+    public int getContentLength() { return -1; }
+    public void setContentLength(int length) {}
+    public String getContentType() { return null; }
+    public ServletInputStream getInputStream() throws IOException {
+        return null;
+    }
+    public Locale getLocale() { return null; }
+    public Enumeration getLocales() { return null; }
+    public String getProtocol() { return null; }
+    public BufferedReader getReader() throws IOException { return null; }
+    public String getRealPath(String path) { return null; }
+    public String getRemoteAddr() { return null; }
+    public String getRemoteHost() { return null; }
+    public String getScheme() { return null; }
+    public String getServerName() { return null; }
+    public int getServerPort() { return -1; }
+    public boolean isSecure() { return false; }
+    public void removeAttribute(String name) {}
+    public void setAttribute(String name, Object value) {}
+    public void setCharacterEncoding(String enc)
+        throws UnsupportedEncodingException {}
+    public void addCookie(Cookie cookie) {}
+    public void addHeader(String name, String value) {}
+    public void addParameter(String name, String values[]) {}
+    public void clearCookies() {}
+    public void clearHeaders() {}
+    public void clearLocales() {}
+    public void clearParameters() {}
+    public void recycle() {}
+    public void setAuthType(String authType) {}
+    public void setContextPath(String path) {}
+    public void setMethod(String method) {}
+    public void setRequestedSessionCookie(boolean flag) {}
+    public void setRequestedSessionId(String id) {}
+    public void setRequestedSessionURL(boolean flag) {}
+    public void setRequestURI(String uri) {}
+    public void setSecure(boolean secure) {}
+    public void setUserPrincipal(Principal principal) {}
+    public String getParameter(String name) { return null; }
+    public Map getParameterMap() { return null; }
+    public Enumeration getParameterNames() { return dummyEnum; }
+    public String[] getParameterValues(String name) { return null; }
+    public RequestDispatcher getRequestDispatcher(String path) {
+        return null;
+    }
+    public String getAuthType() { return null; }
+    public Cookie[] getCookies() { return null; }
+    public long getDateHeader(String name) { return -1; }
+    public String getHeader(String name) { return null; }
+    public Enumeration getHeaders(String name) { return null; }
+    public Enumeration getHeaderNames() { return null; }
+    public int getIntHeader(String name) { return -1; }
+    public String getMethod() { return null; }
+    public String getPathTranslated() { return null; }
+    public String getRemoteUser() { return null; }
+    public String getRequestedSessionId() { return null; }
+    public String getRequestURI() { return null; }
+    public void setDecodedRequestURI(String uri) {}
+    public StringBuffer getRequestURL() { return null; }
+    public HttpSession getSession() { return null; }
+    public HttpSession getSession(boolean create) { return null; }
+    public boolean isRequestedSessionIdFromCookie() { return false; }
+    public boolean isRequestedSessionIdFromURL() { return false; }
+    public boolean isRequestedSessionIdFromUrl() { return false; }
+    public boolean isRequestedSessionIdValid() { return false; }
+    public boolean isUserInRole(String role) { return false; }
+    public Principal getUserPrincipal() { return null; }
+    public String getLocalAddr() { return null; }    
+    public String getLocalName() { return null; }
+    public int getLocalPort() { return -1; }
+    public int getRemotePort() { return -1; }
+    
+}
+

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/core/DummyResponse.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/core/DummyResponse.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/core/DummyResponse.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,124 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.IOException;
+import java.io.OutputStream;
+import java.io.PrintWriter;
+import java.util.Locale;
+
+import javax.servlet.ServletOutputStream;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.catalina.Context;
+import org.apache.catalina.connector.Connector;
+import org.apache.catalina.connector.Request;
+
+
+/**
+ * Dummy response object, used for JSP precompilation.
+ *
+ * @author Remy Maucherat
+ * @version $Revision: 302975 $ $Date: 2004-06-23 03:25:04 -0500 (Wed, 23 Jun 2004) $
+ */
+
+public class DummyResponse
+    implements HttpServletResponse {
+
+    public DummyResponse() {
+    }
+
+
+    public void setAppCommitted(boolean appCommitted) {}
+    public boolean isAppCommitted() { return false; }
+    public Connector getConnector() { return null; }
+    public void setConnector(Connector connector) {}
+    public int getContentCount() { return -1; }
+    public Context getContext() { return null; }
+    public void setContext(Context context) {}
+    public boolean getIncluded() { return false; }
+    public void setIncluded(boolean included) {}
+    public String getInfo() { return null; }
+    public Request getRequest() { return null; }
+    public void setRequest(Request request) {}
+    public ServletResponse getResponse() { return null; }
+    public OutputStream getStream() { return null; }
+    public void setStream(OutputStream stream) {}
+    public void setSuspended(boolean suspended) {}
+    public boolean isSuspended() { return false; }
+    public void setError() {}
+    public boolean isError() { return false; }
+    public ServletOutputStream createOutputStream() throws IOException {
+        return null;
+    }
+    public void finishResponse() throws IOException {}
+    public int getContentLength() { return -1; }
+    public String getContentType() { return null; }
+    public PrintWriter getReporter() { return null; }
+    public void recycle() {}
+    public void write(int b) throws IOException {}
+    public void write(byte b[]) throws IOException {}
+    public void write(byte b[], int off, int len) throws IOException {}
+    public void flushBuffer() throws IOException {}
+    public int getBufferSize() { return -1; }
+    public String getCharacterEncoding() { return null; }
+    public void setCharacterEncoding(String charEncoding) {}
+    public ServletOutputStream getOutputStream() throws IOException {
+        return null;
+    }
+    public Locale getLocale() { return null; }
+    public PrintWriter getWriter() throws IOException { return null; }
+    public boolean isCommitted() { return false; }
+    public void reset() {}
+    public void resetBuffer() {}
+    public void setBufferSize(int size) {}
+    public void setContentLength(int length) {}
+    public void setContentType(String type) {}
+    public void setLocale(Locale locale) {}
+
+    public Cookie[] getCookies() { return null; }
+    public String getHeader(String name) { return null; }
+    public String[] getHeaderNames() { return null; }
+    public String[] getHeaderValues(String name) { return null; }
+    public String getMessage() { return null; }
+    public int getStatus() { return -1; }
+    public void reset(int status, String message) {}
+    public void addCookie(Cookie cookie) {}
+    public void addDateHeader(String name, long value) {}
+    public void addHeader(String name, String value) {}
+    public void addIntHeader(String name, int value) {}
+    public boolean containsHeader(String name) { return false; }
+    public String encodeRedirectURL(String url) { return null; }
+    public String encodeRedirectUrl(String url) { return null; }
+    public String encodeURL(String url) { return null; }
+    public String encodeUrl(String url) { return null; }
+    public void sendAcknowledgement() throws IOException {}
+    public void sendError(int status) throws IOException {}
+    public void sendError(int status, String message) throws IOException {}
+    public void sendRedirect(String location) throws IOException {}
+    public void setDateHeader(String name, long value) {}
+    public void setHeader(String name, String value) {}
+    public void setIntHeader(String name, int value) {}
+    public void setStatus(int status) {}
+    public void setStatus(int status, String message) {}
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/core/LocalStrings.properties
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/core/LocalStrings.properties	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/core/LocalStrings.properties	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,188 @@
+applicationContext.attributeEvent=Exception thrown by attributes event listener
+applicationContext.mapping.error=Error during mapping
+applicationContext.requestDispatcher.iae=Path {0} does not start with a "/" character
+applicationContext.resourcePaths.iae=Path {0} does not start with a "/" character
+applicationContext.setAttribute.namenull=Name cannot be null
+applicationDispatcher.allocateException=Allocate exception for servlet {0}
+applicationDispatcher.deallocateException=Deallocate exception for servlet {0}
+applicationDispatcher.forward.ise=Cannot forward after response has been committed
+applicationDispatcher.forward.throw=Forwarded resource threw an exception
+applicationDispatcher.include.throw=Included resource threw an exception
+applicationDispatcher.isUnavailable=Servlet {0} is currently unavailable
+applicationDispatcher.serviceException=Servlet.service() for servlet {0} threw exception
+applicationRequest.badParent=Cannot locate parent Request implementation
+applicationRequest.badRequest=Request is not a javax.servlet.ServletRequestWrapper
+applicationResponse.badParent=Cannot locate parent Response implementation
+applicationResponse.badResponse=Response is not a javax.servlet.ServletResponseWrapper
+aprListener.aprInit=The Apache Tomcat Native library which allows optimal performance in production environments was not found on the java.library.path: {0}
+aprListener.tcnInvalid=An incompatible version {0} of the Apache Tomcat Native library is installed, while Tomcat requires version {1} 
+aprListener.tcnVersion=An older version {0} of the Apache Tomcat Native library is installed, while Tomcat recommends version greater than {1}
+aprListener.aprDestroy=Failed shutdown of Apache Portable Runtime
+containerBase.addDefaultMapper=Exception configuring default mapper of class {0}
+containerBase.alreadyStarted=Container {0} has already been started
+containerBase.notConfigured=No basic Valve has been configured
+containerBase.notStarted=Container {0} has not been started
+containerBase.backgroundProcess.cluster=Exception processing cluster {0} background process
+containerBase.backgroundProcess.loader=Exception processing loader {0} background process
+containerBase.backgroundProcess.manager=Exception processing manager {0} background process
+containerBase.backgroundProcess.realm=Exception processing realm {0} background process
+containerBase.backgroundProcess.valve=Exception processing valve {0} background process
+fastEngineMapper.alreadyStarted=FastEngineMapper {0} has already been started
+fastEngineMapper.notStarted=FastEngineMapper {0} has not yet been started
+filterChain.filter=Filter execution threw an exception
+filterChain.servlet=Servlet execution threw an exception
+httpContextMapper.container=This container is not a StandardContext
+httpEngineMapper.container=This container is not a StandardEngine
+httpHostMapper.container=This container is not a StandardHost
+interceptorValve.alreadyStarted=InterceptorValve has already been started
+interceptorValve.notStarted=InterceptorValve has not yet been started
+naming.bindFailed=Failed to bind object: {0}
+naming.jmxRegistrationFailed=Failed to register in JMX: {0}
+naming.unbindFailed=Failed to unbind object: {0}
+naming.invalidEnvEntryType=Environment entry {0} has an invalid type
+naming.invalidEnvEntryValue=Environment entry {0} has an invalid value
+naming.namingContextCreationFailed=Creation of the naming context failed: {0}
+standardContext.invalidWrapperClass={0} is not a subclass of StandardWrapper
+standardContext.alreadyStarted=Context has already been started
+standardContext.applicationListener=Error configuring application listener of class {0}
+standardContext.applicationSkipped=Skipped installing application listeners due to previous error(s)
+standardContext.badRequest=Invalid request path ({0}).
+standardContext.crlfinurl=The URL pattern "{0}" contains a CR or LF and so can never be matched.
+standardContext.errorPage.error=Error page location {0} must start with a ''/''
+standardContext.errorPage.required=ErrorPage cannot be null
+standardContext.errorPage.warning=WARNING: Error page location {0} must start with a ''/'' in Servlet 2.4
+standardContext.filterMap.either=Filter mapping must specify either a <url-pattern> or a <servlet-name>
+standardContext.filterMap.name=Filter mapping specifies an unknown filter name {0}
+standardContext.filterMap.pattern=Invalid <url-pattern> {0} in filter mapping
+standardContext.filterStart=Exception starting filter {0}
+standardContext.filterStartFailed=Failed to start application Filters successfully
+standardContext.requestListenerStartFailed=Failed to start request listener valve successfully
+standardContext.requestListenerConfig.added=Added request listener Valve
+standardContext.requestListenerConfig.error=Exception adding request listener Valve: {0}
+standardContext.isUnavailable=This application is not currently available
+standardContext.listenerStart=Exception sending context initialized event to listener instance of class {0}
+standardContext.listenerStartFailed=Failed to start application Listeners successfully
+standardContext.listenerStop=Exception sending context destroyed event to listener instance of class {0}
+standardContext.loginConfig.errorPage=Form error page {0} must start with a ''/'
+standardContext.loginConfig.errorWarning=WARNING: Form error page {0} must start with a ''/'' in Servlet 2.4
+standardContext.loginConfig.loginPage=Form login page {0} must start with a ''/'
+standardContext.loginConfig.loginWarning=WARNING: Form login page {0} must start with a ''/'' in Servlet 2.4
+standardContext.loginConfig.required=LoginConfig cannot be null
+standardContext.mappingError=MAPPING configuration error for relative URI {0}
+standardContext.notFound=The requested resource ({0}) is not available.
+standardContext.notReloadable=Reloading is disabled on this Context
+standardContext.notStarted=Context has not yet been started
+standardContext.notWrapper=Child of a Context must be a Wrapper
+standardContext.parameter.duplicate=Duplicate context initialization parameter {0}
+standardContext.parameter.required=Both parameter name and parameter value are required
+standardContext.reloadingCompleted=Reloading this Context is completed
+standardContext.reloadingFailed=Reloading this Context failed due to previous errors
+standardContext.reloadingStarted=Reloading this Context has started
+standardContext.resourcesStart=Error starting static Resources
+standardContext.securityConstraint.pattern=Invalid <url-pattern> {0} in security constraint
+standardContext.servletMap.name=Servlet mapping specifies an unknown servlet name {0}
+standardContext.servletMap.pattern=Invalid <url-pattern> {0} in servlet mapping
+standardContext.startCleanup=Exception during cleanup after start failed
+standardContext.startFailed=Context [{0}] startup failed due to previous errors
+standardContext.startingLoader=Exception starting Loader
+standardContext.startingManager=Exception starting Manager
+standardContext.startingWrapper=Exception starting Wrapper for servlet {0}
+standardContext.stoppingContext=Exception stopping Context
+standardContext.stoppingLoader=Exception stopping Loader
+standardContext.stoppingManager=Exception stopping Manager
+standardContext.stoppingWrapper=Exception stopping Wrapper for servlet {0}
+standardContext.urlDecode=Cannot URL decode request path {0}
+standardContext.urlPattern.patternWarning=WARNING: URL pattern {0} must start with a ''/'' in Servlet 2.4
+standardContext.urlValidate=Cannot validate URL decoded request path {0}
+standardContext.wrapper.error=JSP file {0} must start with a ''/'
+standardContext.wrapper.warning=WARNING: JSP file {0} must start with a ''/'' in Servlet 2.4
+standardEngine.alreadyStarted=Engine has already been started
+standardEngine.mappingError=MAPPING configuration error for server name {0}
+standardEngine.noHost=No Host matches server name {0}
+standardEngine.noHostHeader=HTTP/1.1 request with no Host: header
+standardEngine.notHost=Child of an Engine must be a Host
+standardEngine.notParent=Engine cannot have a parent Container
+standardEngine.notStarted=Engine has not yet been started
+standardEngine.unfoundHost=Virtual host {0} not found
+standardEngine.unknownHost=No server host specified in this request
+standardEngine.unregister.mbeans.failed=Error in destroy() for mbean file {0}
+standardHost.accessBase=Cannot access document base directory {0}
+standardHost.alreadyStarted=Host has already been started
+standardHost.appBase=Application base directory {0} does not exist
+standardHost.clientAbort=Remote Client Aborted Request, IOException: {0}
+standardHost.configRequired=URL to configuration file is required
+standardHost.configNotAllowed=Use of configuration file is not allowed
+standardHost.installBase=Only web applications in the Host web application directory can be installed
+standardHost.installing=Installing web application at context path {0} from URL {1}
+standardHost.installingWAR=Installing web application from URL {0}
+standardHost.installingXML=Processing Context configuration file URL {0}
+standardHost.installError=Error deploying application at context path {0}
+standardHost.invalidErrorReportValveClass=Couldn''t load specified error report valve class: {0}
+standardHost.docBase=Document base directory {0} already exists
+standardHost.mappingError=MAPPING configuration error for request URI {0}
+standardHost.noContext=No Context configured to process this request
+standardHost.noHost=No Host configured to process this request
+standardHost.notContext=Child of a Host must be a Context
+standardHost.notStarted=Host has not yet been started
+standardHost.nullName=Host name is required
+standardHost.pathFormat=Invalid context path: {0}
+standardHost.pathMatch=Context path {0} must match the directory or WAR file name: {1}
+standardHost.pathMissing=Context path {0} is not currently in use
+standardHost.pathRequired=Context path is required
+standardHost.pathUsed=Context path {0} is already in use
+standardHost.removing=Removing web application at context path {0}
+standardHost.removeError=Error removing application at context path {0}
+standardHost.start=Starting web application at context path {0}
+standardHost.stop=Stopping web application at context path {0}
+standardHost.unfoundContext=Cannot find context for request URI {0}
+standardHost.warRequired=URL to web application archive is required
+standardHost.warURL=Invalid URL for web application archive: {0}
+standardHost.validationEnabled=XML validation enabled
+standardHost.validationDisabled=XML validation disabled
+standardPipeline.alreadyStarted=Pipeline has already been started
+standardPipeline.notStarted=Pipeline has not been started
+standardPipeline.noValve=No more Valves in the Pipeline processing this request
+standardServer.addContainer.ise=No connectors available to associate this container with
+standardServer.initialize.initialized=This server has already been initialized
+standardServer.start.connectors=At least one connector is not associated with any container
+standardServer.start.started=This server has already been started
+standardServer.stop.notStarted=This server has not yet been started
+standardService.initialize.initialized=This service has already been initialized
+standardService.initialize.failed=Service initializing at {0} failed
+standardService.register.failed=Error registering Service at domain {0}
+standardService.start.name=Starting service {0}
+standardService.start.started=This service has already been started
+standardService.stop.name=Stopping service {0}
+standardService.stop.notStarted=This service has not yet been started
+standardWrapper.allocate=Error allocating a servlet instance
+standardWrapper.allocateException=Allocate exception for servlet {0}
+standardWrapper.containerServlet=Loading container servlet {0}
+standardWrapper.createFilters=Create filters exception for servlet {0}
+standardWrapper.deallocateException=Deallocate exception for servlet {0}
+standardWrapper.destroyException=Servlet.destroy() for servlet {0} threw exception
+standardWrapper.exception0=Tomcat Exception Report
+standardWrapper.exception1=A Servlet Exception Has Occurred
+standardWrapper.exception2=Exception Report:
+standardWrapper.exception3=Root Cause:
+standardWrapper.initException=Servlet.init() for servlet {0} threw exception
+standardWrapper.instantiate=Error instantiating servlet class {0}
+standardWrapper.isUnavailable=Servlet {0} is currently unavailable
+standardWrapper.jasperLoader=Using Jasper classloader for servlet {0}
+standardWrapper.jspFile.format=JSP file {0} does not start with a ''/'' character
+standardWrapper.loadException=Servlet {0} threw load() exception
+standardWrapper.missingClass=Wrapper cannot find servlet class {0} or a class it depends on
+standardWrapper.missingLoader=Wrapper cannot find Loader for servlet {0}
+standardWrapper.notChild=Wrapper container may not have child containers
+standardWrapper.notClass=No servlet class has been specified for servlet {0}
+standardWrapper.notContext=Parent container of a Wrapper must be a Context
+standardWrapper.notFound=Servlet {0} is not available
+standardWrapper.notServlet=Class {0} is not a Servlet
+standardWrapper.privilegedServlet=Servlet of class {0} is privileged and cannot be loaded by this web application
+standardWrapper.releaseFilters=Release filters exception for servlet {0}
+standardWrapper.serviceException=Servlet.service() for servlet {0} threw exception
+standardWrapper.statusHeader=HTTP Status {0} - {1}
+standardWrapper.statusTitle=Tomcat Error Report
+standardWrapper.unavailable=Marking servlet {0} as unavailable
+standardWrapper.unloadException=Servlet {0} threw unload() exception
+standardWrapper.unloading=Cannot allocate servlet {0} because it is being unloaded
+standardWrapper.waiting=Waiting for {0} instance(s) to be deallocated

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/core/LocalStrings_es.properties
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/core/LocalStrings_es.properties	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/core/LocalStrings_es.properties	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,172 @@
+applicationContext.attributeEvent=Excepción lanzada por escuchador de eventos de atributos
+applicationContext.mapping.error=Error durante mapeo
+applicationContext.requestDispatcher.iae=La Trayectoria {0} no comienza con carácter "/"
+applicationContext.setAttribute.namenull=El nombre no puede ser nulo
+applicationDispatcher.allocateException=Excepción de reserva de espacio para servlet {0}
+applicationDispatcher.deallocateException=Excepción de recuperación de espacio para servlet {0}
+applicationDispatcher.forward.ise=No puedo reenviar después de que la respuesta se haya llevado a cabo.
+applicationDispatcher.forward.throw=El recurso reenviado lanzó un excepción
+applicationDispatcher.include.throw=El recurso incluído lanzó una excepción
+applicationDispatcher.isUnavailable=El Servlet {0} no está disponible en este momento
+applicationDispatcher.serviceException=El Servlet.service() para servlet {0} lanzó una excepción
+applicationRequest.badParent=No puedo localizar la implementación de Requerimiento padre
+applicationRequest.badRequest=El requerimiento no es un javax.servlet.ServletRequestWrapper
+applicationResponse.badParent=No puedo localizar implementación de Respuesta padre
+applicationResponse.badResponse=La Respuesta no es un javax.servlet.ServletResponseWrapper
+containerBase.addDefaultMapper=Excepción configurando mapeador por defecto de clase {0}
+containerBase.alreadyStarted=Ya ha sido arrancado el Contenedor {0}
+containerBase.notConfigured=No se ha configurado Válvula básica
+containerBase.notStarted=No se ha arrancado el Contenedor {0}
+fastEngineMapper.alreadyStarted=Ya se ha arrancado el FastEngineMapper {0}
+fastEngineMapper.notStarted=No se ha arrancado aún el FastEngineMapper {0}
+filterChain.filter=La ejecución del Filtro lanzó una excepción
+filterChain.servlet=La ejecución del Servlet lanzó una excepción
+httpContextMapper.container=Este Contenedor no es un StandardContext
+httpEngineMapper.container=Este Contenedor no es un StandardEngine
+httpHostMapper.container=Esta Contenedor no es una StandardHost
+interceptorValve.alreadyStarted=Ya ha sido arrancada la InterceptorValve
+interceptorValve.notStarted=Aún no ha sido arrancada la InterceptorValve
+naming.bindFailed=No pude cambiar (bind) objeto: {0}
+naming.unbindFailed=No pude descambiar (unbind) objecto: {0}
+naming.invalidEnvEntryType=La entrada de Entorno {0} tiene un tipo inválido
+naming.invalidEnvEntryValue=La entrada de Entorno {0} tiene un valor inválido
+naming.namingContextCreationFailed=Falló la creación del contexto de nombres (naming): {0}
+standardContext.alreadyStarted=Ya se ha arrancado el Contexto
+standardContext.applicationListener=Error configurando escuchador de aplicación de clase {0}
+standardContext.applicationSkipped=Se ha saltado la instalación de escuchadores de aplicación debido a error(es) previo(s)
+standardContext.badRequest=Trayectoria de requerimiento inválida ({0}).
+standardContext.errorPage.error=La localización de la página de error 0} debe de comenzar con ''/''
+standardContext.errorPage.required=ErrorPage no puede ser nulo
+standardContext.errorPage.warning=AVISO: La localización de la página de error {0} debe de comenzar con ''/'' en Servlet 2.4
+standardContext.filterMap.either=El mapeo de filtro debe de especificar o un <url-pattern> o un <servlet-name>
+standardContext.filterMap.name=El mapeo de filtro especifica un nombre desconocido de filtro {0}
+standardContext.filterMap.pattern=<url-pattern> {0} inválido en mapeo de filtro
+standardContext.filterStart=Excepción arrancando filtro {0}
+standardContext.filterStartFailed=No pude arrancar Filtros de aplicación con éxito
+standardContext.requestListenerStartFailed=No pude arrancar válvula de escuchador de requerimiento con exito
+standardContext.requestListenerConfig.added=Añadida Válvula de escuchador de requerimiento
+standardContext.requestListenerConfig.error=Excepción añadiendo Válvula de escuchador de requerimiento: {0}
+standardContext.isUnavailable=Esta aplicación no está disponible en este momento
+standardContext.listenerStart=Excepción enviando evento inicializado de contexto a instancia de escuchador de clase {0}
+standardContext.listenerStartFailed=No pude arrancar Escuchadores de aplicación con éxito
+standardContext.listenerStop=Excepción enviando evento de contexto destruído a instancia de escuchador de clase {0}
+standardContext.loginConfig.errorPage=La Página de error de Formulario {0} debe de comenzar con ''/'
+standardContext.loginConfig.errorWarning=AVISO: La página de error de Formulario {0} debe de comenzar con ''/'' en Servlet 2.4
+standardContext.loginConfig.loginPage=La página de login de Formulario {0} debe de comenzar con ''/'
+standardContext.loginConfig.loginWarning=AVISO: La página de login de Formulario {0} debe de comenzar con ''/'' en Servlet 2.4
+standardContext.loginConfig.required=LoginConfig no puede ser nula
+standardContext.mappingError=Error de configuración de MAPEO para URI relativa {0}
+standardContext.notFound=El recurso requerido ({0}) no se encuentra disponible
+standardContext.notReloadable=Está desactivada la recarga en este Contexto
+standardContext.notStarted=Aún no se ha arrancado el Contexto
+standardContext.notWrapper=El Hijo de un Contexto debe de ser un Arropador (Wrapper)
+standardContext.parameter.duplicate=Duplicado parámetro de inicialización de contexto {0}
+standardContext.parameter.required=Es necesario poner nombre de parámetro y valor de parámetro
+standardContext.reloadingCompleted=Se ha completado la Regarga de este Contexto
+standardContext.reloadingFailed=Falló la recarga de este Contexto debido a errores previos
+standardContext.reloadingStarted=Ha comenzado la recarga de este Contexto
+standardContext.resourcesStart=Error arrancando Recursos estáticos
+standardContext.securityConstraint.pattern=<url-pattern> {0} inválida en restricción de seguridad
+standardContext.servletMap.name=El mapeo de Servlet especifica un nombre de servlet desconocido {0}
+standardContext.servletMap.pattern=<url-pattern> {0} inválida en mapeo de servlet
+standardContext.startCleanup=Excepción durante la limpieza tras no poder arrancar
+standardContext.startFailed=Falló en arranque del Contexto [{0}] debido a errores previos
+standardContext.startingLoader=Excepción arrancando Cargador
+standardContext.startingManager=Excepción arrancando Gestor
+standardContext.startingWrapper=Excepción arrancando Arropador (Wrapper) para servlet {0}
+standardContext.stoppingContext=Excepci?n parando Context
+standardContext.stoppingLoader=Excepción parando Cargador
+standardContext.stoppingManager=Excepción parando Gestor
+standardContext.stoppingWrapper=Excepción parando Arropador (Wrapper) para servlet {0}
+standardContext.urlDecode=No puedo decodificar URL de trayectoria de requerimiento {0}
+standardContext.urlPattern.patternWarning=AVISO: el patrón URL {0} debe de comenzar con ''/'' en Servlet 2.4
+standardContext.urlValidate=No puedo validar trayectoria de requerimiento de URL decodificada {0}
+standardContext.wrapper.error=El archivo JSP {0} debe de comenzar con ''/'
+standardContext.wrapper.warning=AVISO: El archivo JSP {0} debe de comenzar con ''/'' en Servlet 2.4
+standardEngine.alreadyStarted=Ya ha sido arrancado el Motor
+standardEngine.mappingError=Error de configuración de MAPEO para nombre de servidor {0}
+standardEngine.noHost=No hay Máquina que coincida con nombre de servidor {0}
+standardEngine.noHostHeader=Requerimiento HTTP/1.1 sin Máquina: cabecera
+standardEngine.notHost=El Hijo de un Motor debe de ser un Máquina
+standardEngine.notParent=El Motor no puede tener un Contenedor padre
+standardEngine.notStarted=Aún no se ha arrancado el Motor
+standardEngine.unfoundHost=Máquina virtual {0} no hallada
+standardEngine.unknownHost=No se ha especificado máquina servidora en este requerimiento
+standardHost.accessBase=No puedo acceder a directorio base de documento {0}
+standardHost.alreadyStarted=Ya ha sido arrancada la Máquina
+standardHost.appBase=No existe el directorio base de aplicación {0}
+standardHost.clientAbort=El Cliente Remoto Abortó el Requerimiento, IOException: {0}
+standardHost.configRequired=Es necesario poner la URL a archivo de configuración
+standardHost.configNotAllowed=No se permite el uso del archivo de configuración
+standardHost.installBase=Sólo se pueden instalar aplicaciones web en el directorio de aplicaciones web de Máquina
+standardHost.installing=Instalando aplicaciones web en trayectoria de contexto {0} desde URL {1}
+standardHost.installingWAR=Instalando aplicación web desde URL {0}
+standardHost.installingXML=Procesando URL de archivo de configuración de Contexto {0}
+standardHost.installError=Error desplegando aplicación en trayectoria de contexto {0}
+standardHost.invalidErrorReportValveClass=No pude cargar clase especifiada de válvula de informe de error: {0}
+standardHost.docBase=Ya existe el directorio base de documento {0}
+standardHost.mappingError=Error de configuración de MAPEO para URI de requerimiento {0}
+standardHost.noContext=No se ha configurado Contexto para procesar este requerimiento
+standardHost.noHost=No se ha configurado Máquina para procesar este requerimiento
+standardHost.notContext=El Hijo de una Máquina debe de ser un Contexto
+standardHost.notStarted=Aún no se ha arrancado la Máquina
+standardHost.nullName=Es necesario poner el nombre de Máquina
+standardHost.pathFormat=Trayectoria de contexto inválida: {0}
+standardHost.pathMatch=La trayectoria de Contexto {0} debe de coincidir con el nombre de directorio o de archivo WAR: {1}
+standardHost.pathMissing=La trayectoria de Contexto {0} no está en uso en este momento
+standardHost.pathRequired=Es necesario poner la trayectoria de Contexto
+standardHost.pathUsed=Ya está en uso la trayectoria de Contexto {0}
+standardHost.removing=Quitando aplicación web en trayectoria de contexto {0}
+standardHost.removeError=Error quitando aplicación en trayectoria de contexto {0}
+standardHost.start=Arrancando aplicación web en trayectoria de contexto {0}
+standardHost.stop=Parando aplicación web en trayectoria de contexto {0}
+standardHost.unfoundContext=No puedo hallar contexto para URI de requerimiento {0}
+standardHost.warRequired=Es necesario poner la URL a archivo de aplicación web
+standardHost.warURL=URL inválida para archivo de aplicación web: {0}
+standardHost.validationEnabled=Activada la validación XML
+standardHost.validationDisabled=Desactivada la validación XML
+standardPipeline.alreadyStarted=Ya se ha arrancado la Tubería (Pipeline)
+standardPipeline.notStarted=No se ha arrancado la Tubería (Pipeline)
+standardPipeline.noValve=No hay más Válvulas en la Tubería (Pipeline) procesando este requerimiento
+standardServer.addContainer.ise=No hay conectores disponibles para ser asociados con este contenedor
+standardServer.initialize.initialized=Ya se ha inicializado este servidor
+standardServer.start.connectors=Al menos un conector no está asociado con cualquier contenedor
+standardServer.start.started=Ya ha sido arrancado este servidor
+standardServer.stop.notStarted=Aún no ha sido arrancado este servidor
+standardService.initialize.initialized=Ya ha sido inicializado este servicio
+standardService.start.name=Arrancando servicio {0}
+standardService.start.started=Ya ha sido arrancado este sercicio
+standardService.stop.name=Parando servicio {0}
+standardService.stop.notStarted=Aún no se ha arrancado este servicio
+standardWrapper.allocate=Error reservando espacio para una instancia de servlet
+standardWrapper.allocateException=Excepción de reserva de espacio para servlet {0}
+standardWrapper.containerServlet=Cargando servlet de contenedor {0}
+standardWrapper.createFilters=Excepción de creación de filtros para servlet {0}
+standardWrapper.deallocateException=Excepción de recuperación de espacio para servlet {0}
+standardWrapper.destroyException=Servlet.destroy() para servlet {0} lanzó excepción
+standardWrapper.exception0=Informe de Excepción de Tomcat
+standardWrapper.exception1=Ha tenido lugar una Excepción de Servlet
+standardWrapper.exception2=Informe de Excepción:
+standardWrapper.exception3=Causa Raíz:
+standardWrapper.initException=Servlet.init() para servlet {0} lanzó excepción
+standardWrapper.instantiate=Error instanciando clase de servlet {0}
+standardWrapper.isUnavailable=El Servlet {0} no está disponible en este momento
+standardWrapper.jasperLoader=Usando cargador de clases (classloader) de Jasper para servlet {0}
+standardWrapper.jspFile.format=El archivo JSP {0} no comienza con carácter ''/''
+standardWrapper.loadException=El Servlet {0} lanzó excepción de load()
+standardWrapper.missingClass=El Arropador (Wrapper) no puede hallar clase de servlet {0} o una clase de la que depende
+standardWrapper.missingLoader=El Arropador (Wrapper) no puede hallar Cargador para servlet {0}
+standardWrapper.notChild=El contenedor de Arropador (Wrapper) no puede tener contenedores hijo
+standardWrapper.notClass=No se ha especificado clase de servlet para servlet {0}
+standardWrapper.notContext=El contenedor padre para un Arropador (Wrapper) debe de ser un Contexto
+standardWrapper.notFound=No está disponible el Servlet {0}
+standardWrapper.notServlet=La Clase {0} no es un Servlet
+standardWrapper.privilegedServlet=El Servlet de clase {0} es privilegiado y no puede ser cargado mediante esta aplicación web
+standardWrapper.releaseFilters=Excepción de Liberación de filtros para servlet {0}
+standardWrapper.serviceException=Servlet.service() para servlet {0} lanzó excepción
+standardWrapper.statusHeader=HTTP Estado {0} - {1}
+standardWrapper.statusTitle=Informe de Error de Tomcat
+standardWrapper.unavailable=Marcando el servlet {0} como no disponible
+standardWrapper.unloadException=El Servlet {0} lanzó excepción unload()
+standardWrapper.unloading=No puedo reservar espacio para servlet {0} porque está siendo descargado
+standardWrapper.waiting=Esperando por {0} instancia(s) para recuperar su espacio reservado

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/core/LocalStrings_fr.properties
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/core/LocalStrings_fr.properties	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/core/LocalStrings_fr.properties	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,164 @@
+applicationContext.attributeEvent=Exception lancée par l''écouteur (listener) d''évènement attributs
+applicationContext.requestDispatcher.iae=Le chemin {0} ne commence pas par le caractère "/"
+applicationContext.setAttribute.namenull=le nom ne peut être nul
+applicationDispatcher.allocateException=Exception d''allocation pour la servlet {0}
+applicationDispatcher.deallocateException=Exception de désallocation pour la servlet {0}
+applicationDispatcher.forward.ise=Impossible d''utiliser faire-suivre (forward) après que la réponse ait été envoyée
+applicationDispatcher.forward.throw=La ressource faire-suivre (forwarded) a lancé une exception
+applicationDispatcher.include.throw=La ressource incluse (included) a lancé une exception
+applicationDispatcher.isUnavailable=La servlet {0} est actuellement indisponible
+applicationDispatcher.serviceException="Servlet.service()" pour la servlet {0} a lancé une exception
+applicationRequest.badParent=Impossible de trouver l''implementation requête apparentée (parent request)
+applicationRequest.badRequest=La requête n''est pas une "javax.servlet.ServletRequestWrapper"
+applicationResponse.badParent=Impossible de trouver une implémentation réponse apparentée (parent response)
+applicationResponse.badResponse=La réponse n''est pas une "javax.servlet.ServletResponseWrapper"
+containerBase.addDefaultMapper=Exception lors de la configuration du routeur par défaut (default mapper) pour la classe {0}
+containerBase.alreadyStarted=Le conteneur {0} a déjà été démarré
+containerBase.notConfigured=Aucune Valve basique (basic valve) n''a été configurée
+containerBase.notStarted=Le conteneur {0} n''a pas été démarré
+fastEngineMapper.alreadyStarted=le "FastEngineMapper" {0} a déjà été démarré
+fastEngineMapper.notStarted=Le "FastEngineMapper" {0} n''a pas encore été démarré
+filterChain.filter=L''exécution du filtre (Filter) a lancé une exception
+filterChain.servlet=L''exécution de la servlet a lancé une exception
+httpContextMapper.container=Ce conteneur n''est pas un "StandardContext"
+httpEngineMapper.container=Ce conteneur n''est pas un "StandardEngine"
+httpHostMapper.container=Ce conteneur n''est pas un "StandardHost"
+interceptorValve.alreadyStarted=La valve d''interception (InterceptorValve) a déjà été démarrée
+interceptorValve.notStarted=La valve d''interception (InterceptorValve) n''a pas encore été démarrée
+naming.bindFailed=Echec lors du liage à l''objet: {0}
+naming.unbindFailed=Echec lors du déliage à l''objet : {0}
+naming.invalidEnvEntryType=L''entrée environnement {0} a un type invalide
+naming.invalidEnvEntryValue=L''entrée environnement {0} a une valeur invalide
+naming.namingContextCreationFailed=La création du context de nommage (naming context) a échoué : {0}
+standardContext.alreadyStarted=Le contexte a déjà été démarré
+standardContext.applicationListener=Erreur lors de la configuration de la classe d''écoute de l''application (application listener) {0}
+standardContext.applicationSkipped=L''installation des écouteurs (listeners) de l''application a été sautée suite aux erreurs précédentes
+standardContext.badRequest=Chemin de requête invalide ({0}).
+standardContext.errorPage.error=La position de la page d''erreur (ErrorPage) {0} doit commencer par un ''/'
+standardContext.errorPage.required=La page d''erreur (ErrorPage) ne peut être nulle
+standardContext.errorPage.warning=ATTENTION: La position de la page d''erreur (ErrorPage) {0} doit commencer par un ''/'' dans l''API Servlet 2.4
+standardContext.filterMap.either=L''association de filtre (filter mapping) doit indiqué soit une <url-pattern> ou une <servlet-name>
+standardContext.filterMap.name=L''association de filtre (filter mapping) indique un nom de filtre inconnu {0}
+standardContext.filterMap.pattern=<url-pattern> {0} invalide dans l''association de filtre (filter mapping)
+standardContext.filterStart=Exception au démarrage du filtre {0}
+standardContext.filterStartFailed=Echec du démarrage des filtres d''application
+standardContext.requestListenerStartFailed=Echec démarrage des Valves d''écoute
+standardContext.requestListenerConfig.added=Ajout de la valve d''écoute
+standardContext.requestListenerConfig.error=Exception lors de l''ajout de la valve d''écoute de requête: {0}
+standardContext.isUnavailable=Cette application n''est pas disponible actuellement
+standardContext.listenerStart=Exception lors de l''envoi de l''évènement contexte initialisé (context initialized) à l''instance de classe d''écoute (listener) {0}
+standardContext.listenerStartFailed=Echec du démarrage des écouteurs (listeners) d''application
+standardContext.listenerStop=Exception lors de l''envoi de l''évènement contexte détruit (context destroyed) à l''instance de classe d''écoute {0}
+standardContext.loginConfig.errorPage=La forme de page d''erreur (form error page) {0} doit commencer par un ''/''
+standardContext.loginConfig.errorWarning=ATTENTION: La forme de page d''erreur (form error page) {0} doit commencer par un ''/'' dans l''API Servlet 2.4
+standardContext.loginConfig.loginPage=La forme de page de connexion (form login page) {0} doit commencer par un ''/''
+standardContext.loginConfig.loginWarning=ATTENTION: La forme de page de connexion (form login page) {0} doit commencer par un ''/'' dans l''API Servlet 2.4
+standardContext.loginConfig.required="LoginConfig" ne peut être nul
+standardContext.mappingError=Erreur dans la configuration d''association (mapping configuration) pour l''URI relative {0}
+standardContext.notFound=La ressource demandée ({0}) n''est pas disponible.
+standardContext.notReloadable=Le rechargement est désactivé pour ce contexte
+standardContext.notStarted=Le contexte n''a pas encore été démarré
+standardContext.notWrapper=Le fils du contexte (child of context) doit être un enrobeur (wrapper)
+standardContext.parameter.duplicate=Paramètre d''initialisation de contexte dupliqué {0}
+standardContext.parameter.required=Le nom de paramètre ainsi que la valeur du paramètre sont requis
+standardContext.reloadingCompleted=Le rechargement de ce contexte est terminé
+standardContext.reloadingFailed=Le rechargement de ce contexte a échoué suite à une erreur précédente
+standardContext.reloadingStarted=Le rechargement de ce contexte a démarré
+standardContext.securityConstraint.pattern=<url-pattern> {0} invalide d''après les contraintes de sécurité (security constraint)
+standardContext.servletMap.name=L''association de servlet (servlet mapping) indique un nom de servlet inconnu {0}
+standardContext.servletMap.pattern=<url-pattern> {0} invalide dans l''association de servlet (servlet mapping)
+standardContext.startCleanup=Exception lors du nettoyage après que le démarrage ait échoué
+standardContext.startFailed=Erreur de démarrage du contexte [{0}] suite aux erreurs précédentes
+standardContext.startingLoader=Exception an démarrage du "Loader"
+standardContext.startingManager=Exception an démarrage du "Manager"
+standardContext.startingWrapper=Exception an démarrage de l''enrobeur (wrapper) de la servlet {0}
+standardContext.stoppingContext=Exception ? l''arr?t du "Context"
+standardContext.stoppingLoader=Exception à l''arrêt du "Loader"
+standardContext.stoppingManager=Exception à l''arrêt du "Manager"
+standardContext.stoppingWrapper=Exception à l''arrêt de l''enrobeur (wrapper) de la servlet {0}
+standardContext.resourcesStart=Erreur lors du démarrage des Resources statiques
+standardContext.urlDecode=Impossible de décoder le chemin de requête encodé dans l''URL {0}
+standardContext.urlPattern.patternWarning=ATTENTION: Le modèle (pattern) URL {0} doit commencer par un ''/'' dans l''API Servlet 2.4
+standardContext.urlValidate=Impossible de valider le chemin de requête encodé dans l''URL {0}
+standardContext.wrapper.error=Le fichier JSP {0} doit commencer par un ''/''
+standardContext.wrapper.warning=ATTENTION: Le fichier JSP {0} doit commencer par un  ''/'' dans l''API Servlet 2.4
+standardEngine.alreadyStarted=Le moteur a déjà été démarré
+standardEngine.mappingError=Erreur de configuration d''association (mapping configuration) pour le serveur {0}
+standardEngine.noHost=Aucune hôte (host) ne correspond au nom de serveur {0}
+standardEngine.noHostHeader=requête HTTP/1.1 sans entête Host: 
+standardEngine.notHost=Le fils d''un moteur (child of an Engine) doit être un hôte
+standardEngine.notParent=Les moteurs (engine) ne peuvent avoir de parent conteneur (container)
+standardEngine.notStarted=Le moteur n''a pas encore été démarré
+standardEngine.unfoundHost=L''hôte virtuel (virtual host) {0} est introuvable
+standardEngine.unknownHost=Aucun serveur hôte n''est indiqué pour cette requête
+standardHost.accessBase=Impossible d''accéder le répertoire "document base" {0}
+standardHost.alreadyStarted=L''hôte a déjà été démarré
+standardHost.appBase=Le répertoire de base de l''application {0} n''existe pas
+standardHost.configRequired=Une URL vers le fichier de configuration est obligatoire
+standardHost.configNotAllowed=L''utilisation d''un fichier de configuration file n''est pas autorisé
+standardHost.installing=Installation d''une application pour le chemin de contexte {0} depuis l''URL {1}
+standardHost.installingWAR=Installation d''une application depuis l''URL {0}
+standardHost.installError=Erreur lors du déploiement de l''application pour le chemin de contexte {0}
+standardHost.invalidErrorReportValveClass=Impossible de charger la classe valve de rapport d''erreur: {0}
+standardHost.docBase=Le répertoire "document base" {0} existe déjà
+standardHost.mappingError=Erreur d''association de configuration (mapping configuration) pour l''URI demandée {0}
+standardHost.noContext=Aucune contexte n''est configuré pour traiter cette requête
+standardHost.noHost=Aucun hôte n''est configuré pour traiter cette requête
+standardHost.notContext=Le fils d''un hôte (child of a Host) doit être un contexte
+standardHost.notStarted=l''hôte n''a pas encore été démarré
+standardHost.nullName=Le nom d''hôte est requis
+standardHost.pathFormat=Chemin de contexte invalide: {0}
+standardHost.pathMissing=Le chemin de contexte {0} n''est pas utilisé actuellement
+standardHost.pathRequired=Le chemin de contexte est requis
+standardHost.pathUsed=Le chemin de contexte {0} est déjà utilisé
+standardHost.removing=Retrait de l''application web pour le chemin de contexte {0}
+standardHost.removeError=Erreur lors du retrait de l''application web pour le chemin de contexte {0}
+standardHost.start=Démarrage de l''application web application pour le chemin de contexte {0}
+standardHost.stop=Arrét de l''application web application pour le chemin de contexte {0}
+standardHost.unfoundContext=Impossible de trouver un contexte pour l''URI {0} demandée
+standardHost.warRequired=Une URL vers l''archive d''application web (war) est nécessaire 
+standardHost.warURL=URL vers l''archive d''application web (war) invalide: {0}
+standardPipeline.alreadyStarted=Le "Pipeline" a déjà été démarré
+standardPipeline.notStarted=le "Pipeline" n''a pas été démarré
+standardPipeline.noValve=Plus aucune Valves dans le "Pipeline" traitant cette requête
+standardServer.addContainer.ise=Aucun connecteur disponible à associer avec ce conteneur (container)
+standardServer.initialize.initialized=Ce serveur a déjà été initialisé
+standardServer.start.connectors=Au moins un connecteur n''est pas associé à aucun conteneur (container)
+standardServer.start.started=Ce serveur a déjà été démarré
+standardServer.stop.notStarted=Ce serveur n''a pas encore été démarré
+standardService.initialize.initialized=Ce service a déjà été initialisé
+standardService.start.name=Démarrage du service {0}
+standardService.start.started=Ce service a déjà été démarré
+standardService.stop.name=Arrêt du service {0}
+standardService.stop.notStarted=Ce service n''a pas encore été démarré
+standardWrapper.allocate=Erreur d''allocation à une instance de servlet
+standardWrapper.allocateException=Exception lors de l''allocation pour la servlet {0}
+standardWrapper.containerServlet=Chargement du conteneur (container) de servlet {0}
+standardWrapper.createFilters=Exception à la création de filtres pour la servlet {0}
+standardWrapper.deallocateException=Exception à la désallocation pour la servlet {0}
+standardWrapper.destroyException="Servlet.destroy()" de la servlet {0} a généré une exception
+standardWrapper.exception0=Rapport d''exception Tomcat
+standardWrapper.exception1=Une exception Servlet s''est produite
+standardWrapper.exception2=Rapport d''exception:
+standardWrapper.exception3=Cause mère:
+standardWrapper.initException="Servlet.init()" pour la servlet {0} a généré une exception
+standardWrapper.instantiate=Erreur à l''instantiation de la classe servlet {0}
+standardWrapper.isUnavailable=La servlet {0} est actuellement indisponible
+standardWrapper.jasperLoader=Utilisation du chargeur de classe Jasper (classloader) pour la servlet {0}
+standardWrapper.jspFile.format=Le fichier JSP {0} ne commence par par un caractère ''/''
+standardWrapper.loadException=La servlet {0} a généré une exception "load()"
+standardWrapper.missingClass=L''enrobeur (wrapper) ne peut trouver la classe servlet {0} ou une classe dont elle dépend
+standardWrapper.missingLoader=L''enrobeur (wrapper) ne peut trouver de chargeur (loader) pour la servlet {0}
+standardWrapper.notChild=L''enrobeur de conteneur (wrapper container) peut ne pas avoir de conteneurs fils
+standardWrapper.notClass=Aucune classe servlet n''a été spécifiée pour la servlet {0}
+standardWrapper.notContext=Le conteneur parent d''un enrobeur (wrapper) doit être un contexte
+standardWrapper.notFound=Servlet {0} n''est pas disponible.
+standardWrapper.notServlet=La classe {0} n''est pas une servlet
+standardWrapper.privilegedServlet=La servlet de classe {0} est privilégiée (privileged) et ne peut être chargé par cette application web
+standardWrapper.releaseFilters=Exception des filtres de sortie (release filters) pour la servlet {0}
+standardWrapper.serviceException="Servlet.service()" pour la servlet {0} a généré une exception
+standardWrapper.statusHeader=Etat HTTP {0} - {1}
+standardWrapper.statusTitle=Rapport d''erreur Tomcat
+standardWrapper.unavailable=La servlet {0} est marqué comme indisponible
+standardWrapper.unloadException=La servlet {0} a généré une exception "unload()"
+standardWrapper.unloading=Impossible d''allouer la servlet {0} car elle a été déchargée

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/core/LocalStrings_ja.properties
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/core/LocalStrings_ja.properties	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/core/LocalStrings_ja.properties	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,172 @@
+applicationContext.attributeEvent=\u5c5e\u6027\u30a4\u30d9\u30f3\u30c8\u30ea\u30b9\u30ca\u306b\u3088\u3063\u3066\u4f8b\u5916\u304c\u6295\u3052\u3089\u308c\u307e\u3057\u305f
+applicationContext.mapping.error=\u30de\u30c3\u30d4\u30f3\u30b0\u4e2d\u306e\u30a8\u30e9\u30fc\u3067\u3059
+applicationContext.requestDispatcher.iae=\u30d1\u30b9 {0} \u304c"/"\u6587\u5b57\u3067\u59cb\u307e\u308a\u307e\u305b\u3093
+applicationContext.setAttribute.namenull=name\u304cnull\u3067\u306f\u3044\u3051\u307e\u305b\u3093
+applicationDispatcher.allocateException=\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8 {0} \u306b\u4f8b\u5916\u3092\u5272\u308a\u5f53\u3066\u307e\u3059
+applicationDispatcher.deallocateException=\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8 {0} \u306e\u4f8b\u5916\u3092\u89e3\u9664\u3057\u307e\u3059
+applicationDispatcher.forward.ise=\u30ec\u30b9\u30dd\u30f3\u30b9\u3092\u30b3\u30df\u30c3\u30c8\u3057\u305f\u5f8c\u3067\u30d5\u30a9\u30ef\u30fc\u30c9\u3067\u304d\u307e\u305b\u3093
+applicationDispatcher.forward.throw=\u30d5\u30a9\u30ef\u30fc\u30c9\u3057\u305f\u30ea\u30bd\u30fc\u30b9\u304c\u4f8b\u5916\u3092\u6295\u3052\u307e\u3057\u305f
+applicationDispatcher.include.throw=\u30a4\u30f3\u30af\u30eb\u30fc\u30c9\u3057\u305f\u30ea\u30bd\u30fc\u30b9\u304c\u4f8b\u5916\u3092\u6295\u3052\u307e\u3057\u305f
+applicationDispatcher.isUnavailable=\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8 {0} \u306f\u73fe\u5728\u5229\u7528\u3067\u304d\u307e\u305b\u3093
+applicationDispatcher.serviceException=\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8 {0} \u306eServlet.service()\u304c\u4f8b\u5916\u3092\u6295\u3052\u307e\u3057\u305f
+applicationRequest.badParent=\u89aa\u306e\u30ea\u30af\u30a8\u30b9\u30c8\u5b9f\u88c5\u3092\u914d\u7f6e\u3067\u304d\u307e\u305b\u3093
+applicationRequest.badRequest=\u30ea\u30af\u30a8\u30b9\u30c8\u304cjavax.servlet.ServletRequestWrapper\u3067\u306f\u3042\u308a\u307e\u305b\u3093
+applicationResponse.badParent=\u89aa\u306e\u30ec\u30b9\u30dd\u30f3\u30b9\u5b9f\u88c5\u3092\u914d\u7f6e\u3067\u304d\u307e\u305b\u3093
+applicationResponse.badResponse=\u30ec\u30b9\u30dd\u30f3\u30b9\u304cjavax.servlet.ServletResponseWrapper\u3067\u306f\u3042\u308a\u307e\u305b\u3093
+containerBase.addDefaultMapper=\u30af\u30e9\u30b9 {0} \u306e\u30c7\u30d5\u30a9\u30eb\u30c8\u306e\u30de\u30c3\u30d1\u3092\u8a2d\u5b9a\u4e2d\u306b\u4f8b\u5916\u304c\u767a\u751f\u3057\u307e\u3057\u305f
+containerBase.alreadyStarted=\u30b3\u30f3\u30c6\u30ca {0} \u306f\u65e2\u306b\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u3059
+containerBase.notConfigured=\u57fa\u672c\u30d0\u30eb\u30d6\u304c\u8a2d\u5b9a\u3055\u308c\u3066\u3044\u307e\u305b\u3093
+containerBase.notStarted=\u30b3\u30f3\u30c6\u30ca {0} \u306f\u307e\u3060\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u305b\u3093
+fastEngineMapper.alreadyStarted=FastEngineMapper {0} \u306f\u65e2\u306b\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u3059
+fastEngineMapper.notStarted=FastEngineMapper {0} \u306f\u307e\u3060\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u305b\u3093
+filterChain.filter=\u30d5\u30a3\u30eb\u30bf\u306e\u5b9f\u884c\u306b\u3088\u308a\u4f8b\u5916\u3092\u6295\u3052\u307e\u3057\u305f
+filterChain.servlet=\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8\u306e\u5b9f\u884c\u306b\u3088\u308a\u4f8b\u5916\u3092\u6295\u3052\u307e\u3057\u305f
+httpContextMapper.container=\u3053\u306e\u30b3\u30f3\u30c6\u30ca\u306fStandardContext\u3067\u306f\u3042\u308a\u307e\u305b\u3093
+httpEngineMapper.container=\u3053\u306e\u30b3\u30f3\u30c6\u30ca\u306fStandardEngine\u3067\u306f\u3042\u308a\u307e\u305b\u3093
+httpHostMapper.container=\u3053\u306e\u30b3\u30f3\u30c6\u30ca\u306fStandardHost\u3067\u306f\u3042\u308a\u307e\u305b\u3093
+interceptorValve.alreadyStarted=InterceptorValve\u306f\u65e2\u306b\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u3059
+interceptorValve.notStarted=InterceptorValve\u306f\u307e\u3060\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u305b\u3093
+naming.bindFailed=\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u306e\u30d0\u30a4\u30f3\u30c9\u306b\u5931\u6557\u3057\u307e\u3057\u305f: {0}
+naming.unbindFailed=\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u306e\u30a2\u30f3\u30d0\u30a4\u30f3\u30c9\u306b\u5931\u6557\u3057\u307e\u3057\u305f: {0}
+naming.invalidEnvEntryType=\u74b0\u5883\u30a8\u30f3\u30c8\u30ea {0} \u306f\u7121\u52b9\u306a\u578b\u3092\u6301\u3063\u3066\u3044\u307e\u3059
+naming.invalidEnvEntryValue=\u74b0\u5883\u30a8\u30f3\u30c8\u30ea {0} \u306f\u7121\u52b9\u306a\u5024\u3092\u6301\u3063\u3066\u3044\u307e\u3059
+naming.namingContextCreationFailed=\u540d\u524d\u4ed8\u304d\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u306e\u751f\u6210\u306b\u5931\u6557\u3057\u307e\u3057\u305f: {0}
+standardContext.alreadyStarted=\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u306f\u65e2\u306b\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u3059
+standardContext.applicationListener=\u30af\u30e9\u30b9 {0} \u306e\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u30ea\u30b9\u30ca\u306e\u8a2d\u5b9a\u4e2d\u306b\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f
+standardContext.applicationSkipped=\u524d\u306e\u30a8\u30e9\u30fc\u306e\u305f\u3081\u306b\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u30ea\u30b9\u30ca\u306e\u30a4\u30f3\u30b9\u30c8\u30fc\u30eb\u3092\u30b9\u30ad\u30c3\u30d7\u3057\u307e\u3059
+standardContext.badRequest=\u7121\u52b9\u306a\u30ea\u30af\u30a8\u30b9\u30c8\u30d1\u30b9\u3067\u3059 ({0})\u3002
+standardContext.errorPage.error=\u30a8\u30e9\u30fc\u30da\u30fc\u30b8\u306e\u4f4d\u7f6e {0} \u306f''/''\u3067\u59cb\u307e\u3089\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093
+standardContext.errorPage.required=ErrorPage\u304cnull\u3067\u306f\u3044\u3051\u307e\u305b\u3093
+standardContext.errorPage.warning=\u8b66\u544a: Servlet 2.4\u3067\u306f\u30a8\u30e9\u30fc\u30da\u30fc\u30b8\u306e\u4f4d\u7f6e {0} \u306f''/''\u3067\u59cb\u307e\u3089\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093
+standardContext.filterMap.either=\u30d5\u30a3\u30eb\u30bf\u30de\u30c3\u30d4\u30f3\u30b0\u306f<url-pattern>\u53c8\u306f<servlet-name>\u306e\u3069\u3061\u3089\u304b\u3092\u6307\u5b9a\u3057\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093
+standardContext.filterMap.name=\u30d5\u30a3\u30eb\u30bf\u30de\u30c3\u30d4\u30f3\u30b0\u306f\u672a\u77e5\u306e\u30d5\u30a3\u30eb\u30bf\u540d {0} \u3092\u6307\u5b9a\u3057\u307e\u3057\u305f
+standardContext.filterMap.pattern=\u30d5\u30a3\u30eb\u30bf\u30de\u30c3\u30d4\u30f3\u30b0\u4e2d\u306b\u7121\u52b9\u306a <url-pattern> {0} \u304c\u3042\u308a\u307e\u3059
+standardContext.filterStart=\u30d5\u30a3\u30eb\u30bf {0} \u306e\u8d77\u52d5\u4e2d\u306e\u4f8b\u5916\u3067\u3059
+standardContext.filterStartFailed=\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u30d5\u30a3\u30eb\u30bf\u306e\u8d77\u52d5\u306b\u5931\u6557\u3057\u307e\u3057\u305f
+standardContext.requestListenerStartFailed=\u30ea\u30af\u30a8\u30b9\u30c8\u30ea\u30b9\u30ca\u30d0\u30eb\u30d6\u306e\u8d77\u52d5\u306b\u5931\u6557\u3057\u307e\u3057\u305f
+standardContext.requestListenerConfig.added=\u30ea\u30af\u30a8\u30b9\u30c8\u30ea\u30b9\u30ca\u30d0\u30eb\u30d6\u3092\u8ffd\u52a0\u3057\u307e\u3057\u305f
+standardContext.requestListenerConfig.error=\u30ea\u30af\u30a8\u30b9\u30c8\u30ea\u30b9\u30ca\u30d0\u30eb\u30d6\u8ffd\u52a0\u4e2d\u306e\u4f8b\u5916\u3067\u3059: {0}
+standardContext.isUnavailable=\u3053\u306e\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u306f\u73fe\u5728\u5229\u7528\u3067\u304d\u307e\u305b\u3093
+standardContext.listenerStart=\u30af\u30e9\u30b9 {0} \u306e\u30ea\u30b9\u30ca\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u306b\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u521d\u671f\u5316\u30a4\u30d9\u30f3\u30c8\u3092\u9001\u4fe1\u4e2d\u306e\u4f8b\u5916\u3067\u3059
+standardContext.listenerStartFailed=\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u30ea\u30b9\u30ca\u306e\u8d77\u52d5\u306b\u5931\u6557\u3057\u307e\u3057\u305f
+standardContext.listenerStop=\u30af\u30e9\u30b9 {0} \u306e\u30ea\u30b9\u30ca\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u306b\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u7834\u68c4\u30a4\u30d9\u30f3\u30c8\u3092\u9001\u4fe1\u4e2d\u306e\u4f8b\u5916\u3067\u3059
+standardContext.loginConfig.errorPage=\u30d5\u30a9\u30fc\u30e0\u306e\u30a8\u30e9\u30fc\u30da\u30fc\u30b8 {0} \u306f''/''\u3067\u59cb\u307e\u3089\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093
+standardContext.loginConfig.errorWarning=\u8b66\u544a: Servlet 2.4\u3067\u306f\u30d5\u30a9\u30fc\u30e0\u306e\u30a8\u30e9\u30fc\u30da\u30fc\u30b8 {0} \u306f''/''\u3067\u59cb\u307e\u3089\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093
+standardContext.loginConfig.loginPage=\u30d5\u30a9\u30fc\u30e0\u306e\u30ed\u30b0\u30a4\u30f3\u30da\u30fc\u30b8 {0} \u306f''/''\u3067\u59cb\u307e\u3089\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093
+standardContext.loginConfig.loginWarning=\u8b66\u544a: Servlet 2.4\u3067\u306f\u30d5\u30a9\u30fc\u30e0\u306e\u30ed\u30b0\u30a4\u30f3\u30da\u30fc\u30b8 {0} \u306f''/''\u3067\u59cb\u307e\u3089\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093
+standardContext.loginConfig.required=LoginConfig\u306fnull\u3067\u306f\u3044\u3051\u307e\u305b\u3093
+standardContext.mappingError=\u76f8\u5bfeURI {0} \u306e\u30de\u30c3\u30d4\u30f3\u30b0\u8a2d\u5b9a\u30a8\u30e9\u30fc\u3067\u3059
+standardContext.notFound=\u30ea\u30af\u30a8\u30b9\u30c8\u3055\u308c\u305f\u30ea\u30bd\u30fc\u30b9 ({0}) \u306f\u5229\u7528\u3067\u304d\u307e\u305b\u3093\u3002
+standardContext.notReloadable=\u3053\u306e\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u3067\u306f\u518d\u30ed\u30fc\u30c9\u306f\u7121\u52b9\u3067\u3059
+standardContext.notStarted=\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u306f\u307e\u3060\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u305b\u3093
+standardContext.notWrapper=\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u306e\u5b50\u4f9b\u306f\u30e9\u30c3\u30d1\u3067\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093
+standardContext.parameter.duplicate=\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u521d\u671f\u5316\u30d1\u30e9\u30e1\u30bf {0} \u304c\u91cd\u8907\u3057\u3066\u3044\u307e\u3059
+standardContext.parameter.required=\u30d1\u30e9\u30e1\u30bf\u540d\u3068\u30d1\u30e9\u30e1\u30bf\u5024\u306e\u4e21\u65b9\u304c\u5fc5\u8981\u3067\u3059
+standardContext.reloadingCompleted=\u3053\u306e\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u306e\u518d\u30ed\u30fc\u30c9\u304c\u5b8c\u4e86\u3057\u307e\u3057\u305f
+standardContext.reloadingFailed=\u4ee5\u524d\u306e\u30a8\u30e9\u30fc\u306e\u305f\u3081\u306b\u3053\u306e\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u306e\u518d\u30ed\u30fc\u30c9\u304c\u5931\u6557\u3057\u307e\u3057\u305f
+standardContext.reloadingStarted=\u3053\u306e\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u306e\u518d\u30ed\u30fc\u30c9\u3092\u958b\u59cb\u3057\u307e\u3057\u305f
+standardContext.resourcesStart=\u9759\u7684\u30ea\u30bd\u30fc\u30b9\u306e\u8d77\u52d5\u4e2d\u306e\u30a8\u30e9\u30fc\u3067\u3059
+standardContext.securityConstraint.pattern=\u30bb\u30ad\u30e5\u30ea\u30c6\u30a3\u306e\u5236\u7d04\u306e\u4e2d\u306b\u7121\u52b9\u306a <url-pattern> {0} \u304c\u3042\u308a\u307e\u3059
+standardContext.servletMap.name=\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8\u30de\u30c3\u30d4\u30f3\u30b0\u306f\u672a\u77e5\u306e\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8\u540d {0} \u3092\u6307\u5b9a\u3057\u3066\u3044\u307e\u3059
+standardContext.servletMap.pattern=\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8\u30de\u30c3\u30d4\u30f3\u30b0\u4e2d\u306b\u7121\u52b9\u306a <url-pattern> {0} \u304c\u3042\u308a\u307e\u3059
+standardContext.startCleanup=\u8d77\u52d5\u304c\u5931\u6557\u3057\u305f\u5f8c\u306e\u30af\u30ea\u30fc\u30f3\u30ca\u30c3\u30d7\u4e2d\u306b\u4f8b\u5916\u304c\u767a\u751f\u3057\u307e\u3057\u305f
+standardContext.startFailed=\u4ee5\u524d\u306e\u30a8\u30e9\u30fc\u306e\u305f\u3081\u306b\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u306e\u8d77\u52d5\u304c\u5931\u6557\u3057\u307e\u3057\u305f [{0}]
+standardContext.startingLoader=\u30ed\u30fc\u30c0\u3092\u8d77\u52d5\u4e2d\u306e\u4f8b\u5916\u3067\u3059
+standardContext.startingManager=\u30de\u30cd\u30fc\u30b8\u30e3\u3092\u8d77\u52d5\u4e2d\u306e\u4f8b\u5916\u3067\u3059
+standardContext.startingWrapper=\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8 {0} \u306e\u30e9\u30c3\u30d1\u3092\u8d77\u52d5\u4e2d\u306e\u4f8b\u5916\u3067\u3059
+standardContext.stoppingContext=\u30ed\u30fc\u30c0\u3092\u505c\u6b62\u4e2d\u306e\u4f8b\u5916\u3067\u3059
+standardContext.stoppingLoader=\u30ed\u30fc\u30c0\u3092\u505c\u6b62\u4e2d\u306e\u4f8b\u5916\u3067\u3059
+standardContext.stoppingManager=\u30de\u30cd\u30fc\u30b8\u30e3\u3092\u505c\u6b62\u4e2d\u306e\u4f8b\u5916\u3067\u3059
+standardContext.stoppingWrapper=\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8 {0} \u306e\u30e9\u30c3\u30d1\u3092\u505c\u6b62\u4e2d\u306e\u4f8b\u5916\u3067\u3059
+standardContext.urlDecode=\u30ea\u30af\u30a8\u30b9\u30c8\u30d1\u30b9 {0} \u306eURL\u30c7\u30b3\u30fc\u30c9\u304c\u3067\u304d\u307e\u305b\u3093
+standardContext.urlPattern.patternWarning=\u8b66\u544a: Servlet 2.4\u3067\u306fURL\u30d1\u30bf\u30fc\u30f3 {0} \u306f''/''\u3067\u59cb\u307e\u3089\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093
+standardContext.urlValidate=URL\u30c7\u30b3\u30fc\u30c9\u3055\u308c\u305f\u30ea\u30af\u30a8\u30b9\u30c8\u30d1\u30b9 {0} \u3092\u691c\u8a3c\u3067\u304d\u307e\u305b\u3093
+standardContext.wrapper.error=JSP\u30d5\u30a1\u30a4\u30eb {0} \u306f''/''\u3067\u59cb\u307e\u3089\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093
+standardContext.wrapper.warning=\u8b66\u544a: Servlet 2.4\u3067\u306fJSP\u30d5\u30a1\u30a4\u30eb {0} \u306f''/''\u3067\u59cb\u307e\u3089\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093
+standardEngine.alreadyStarted=\u30a8\u30f3\u30b8\u30f3\u306f\u65e2\u306b\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u3059
+standardEngine.mappingError=\u30b5\u30fc\u30d0\u540d {0} \u306e\u30de\u30c3\u30d4\u30f3\u30b0\u8a2d\u5b9a\u30a8\u30e9\u30fc\u3067\u3059
+standardEngine.noHost=\u30b5\u30fc\u30d0\u540d {0} \u306b\u4e00\u81f4\u3059\u308b\u30db\u30b9\u30c8\u304c\u5b58\u5728\u3057\u307e\u305b\u3093
+standardEngine.noHostHeader=Host:\u30d8\u30c3\u30c0\u3092\u6301\u305f\u306a\u3044 HTTP/1.1 \u30ea\u30af\u30a8\u30b9\u30c8\u3067\u3059
+standardEngine.notHost=\u30a8\u30f3\u30b8\u30f3\u306e\u5b50\u4f9b\u306f\u30db\u30b9\u30c8\u3067\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093
+standardEngine.notParent=\u30a8\u30f3\u30b8\u30f3\u306f\u89aa\u306e\u30b3\u30f3\u30c6\u30ca\u3092\u6301\u3064\u3053\u3068\u306f\u3067\u304d\u307e\u305b\u3093
+standardEngine.notStarted=\u30a8\u30f3\u30b8\u30f3\u306f\u307e\u3060\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u305b\u3093
+standardEngine.unfoundHost=\u30d0\u30fc\u30c1\u30e3\u30eb\u30db\u30b9\u30c8 {0} \u304c\u898b\u3064\u304b\u308a\u307e\u305b\u3093
+standardEngine.unknownHost=\u3053\u306e\u30ea\u30af\u30a8\u30b9\u30c8\u4e2d\u306b\u30b5\u30fc\u30d0\u30db\u30b9\u30c8\u304c\u6307\u5b9a\u3055\u308c\u3066\u3044\u307e\u305b\u3093
+standardHost.accessBase=\u30c9\u30ad\u30e5\u30e1\u30f3\u30c8\u30d9\u30fc\u30b9\u30c7\u30a3\u30ec\u30af\u30c8\u30ea {0} \u306b\u30a2\u30af\u30bb\u30b9\u3067\u304d\u307e\u305b\u3093
+standardHost.alreadyStarted=\u30db\u30b9\u30c8\u306f\u65e2\u306b\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u3059
+standardHost.appBase=\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u30d9\u30fc\u30b9\u30c7\u30a3\u30ec\u30af\u30c8\u30ea {0} \u304c\u5b58\u5728\u3057\u307e\u305b\u3093
+standardHost.clientAbort=\u30ea\u30e2\u30fc\u30c8\u30af\u30e9\u30a4\u30a2\u30f3\u30c8\u304c\u30ea\u30af\u30a8\u30b9\u30c8\u3092\u4e2d\u6b62\u3057\u307e\u3057\u305f, IOException: {0}
+standardHost.configRequired=\u8a2d\u5b9a\u30d5\u30a1\u30a4\u30eb\u3078\u306eURL\u304c\u5fc5\u8981\u3067\u3059
+standardHost.configNotAllowed=\u8a2d\u5b9a\u30d5\u30a1\u30a4\u30eb\u304c\u4f7f\u7528\u3067\u304d\u307e\u305b\u3093
+standardHost.installBase=\u30db\u30b9\u30c8Web\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u4e2d\u306eWeb\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u3060\u3051\u304c\u30a4\u30f3\u30b9\u30c8\u30fc\u30eb\u3067\u304d\u307e\u3059
+standardHost.installing=URL {1} \u304b\u3089\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u30d1\u30b9 {0} \u306bWeb\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u3092\u30a4\u30f3\u30b9\u30c8\u30fc\u30eb\u3057\u307e\u3059
+standardHost.installingWAR=URL {0} \u304b\u3089Web\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u3092\u30a4\u30f3\u30b9\u30c8\u30fc\u30eb\u3057\u307e\u3059
+standardHost.installingXML=\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u8a2d\u5b9a\u30d5\u30a1\u30a4\u30eb\u306eURL {0} \u3092\u51e6\u7406\u3057\u3066\u3044\u307e\u3059
+standardHost.installError=\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u30d1\u30b9 {0} \u306b\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u3092\u914d\u5099\u4e2d\u306e\u30a8\u30e9\u30fc\u3067\u3059
+standardHost.invalidErrorReportValveClass=\u6307\u5b9a\u3055\u308c\u305f\u30a8\u30e9\u30fc\u30ea\u30dd\u30fc\u30c8\u30d0\u30eb\u30d6\u30af\u30e9\u30b9\u3092\u30ed\u30fc\u30c9\u3067\u304d\u307e\u305b\u3093: {0}
+standardHost.docBase=\u30c9\u30ad\u30e5\u30e1\u30f3\u30c8\u30d9\u30fc\u30b9\u30c7\u30a3\u30ec\u30af\u30c8\u30ea {0} \u304c\u65e2\u306b\u5b58\u5728\u3057\u307e\u3059
+standardHost.mappingError=\u30ea\u30af\u30a8\u30b9\u30c8URI {0} \u306e\u30de\u30c3\u30d4\u30f3\u30b0\u8a2d\u5b9a\u30a8\u30e9\u30fc\u3067\u3059
+standardHost.noContext=\u3053\u306e\u30ea\u30af\u30a8\u30b9\u30c8\u3092\u51e6\u7406\u3059\u308b\u305f\u3081\u306b\u8a2d\u5b9a\u3055\u308c\u305f\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u304c\u3042\u308a\u307e\u305b\u3093
+standardHost.noHost=\u3053\u306e\u30ea\u30af\u30a8\u30b9\u30c8\u3092\u51e6\u7406\u3059\u308b\u305f\u3081\u306b\u8a2d\u5b9a\u3055\u308c\u305f\u30db\u30b9\u30c8\u304c\u3042\u308a\u307e\u305b\u3093
+standardHost.notContext=\u30db\u30b9\u30c8\u306e\u5b50\u4f9b\u306f\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u3067\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093
+standardHost.notStarted=\u30db\u30b9\u30c8\u304c\u307e\u3060\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u305b\u3093
+standardHost.nullName=\u30db\u30b9\u30c8\u540d\u304c\u5fc5\u8981\u3067\u3059
+standardHost.pathFormat=\u7121\u52b9\u306a\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u30d1\u30b9\u3067\u3059: {0}
+standardHost.pathMatch=\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u30d1\u30b9 {0} \u306f\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u53c8\u306fWAR\u30d5\u30a1\u30a4\u30eb\u540d\u306b\u4e00\u81f4\u3057\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093: {1}
+standardHost.pathMissing=\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u30d1\u30b9 {0} \u306f\u73fe\u5728\u4f7f\u7528\u3055\u308c\u3066\u3044\u307e\u305b\u3093
+standardHost.pathRequired=\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u30d1\u30b9\u304c\u5fc5\u8981\u3067\u3059
+standardHost.pathUsed=\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u30d1\u30b9 {0} \u306f\u65e2\u306b\u4f7f\u7528\u3055\u308c\u3066\u3044\u307e\u3059
+standardHost.removing=\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u30d1\u30b9 {0} \u306eWeb\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u3092\u524a\u9664\u3057\u307e\u3059
+standardHost.removeError=\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u30d1\u30b9 {0} \u306e\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u3092\u524a\u9664\u4e2d\u306b\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f
+standardHost.start=\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u30d1\u30b9 {0} \u306eWeb\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u3092\u8d77\u52d5\u3057\u307e\u3059
+standardHost.stop=\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u30d1\u30b9 {0} \u306eWeb\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u3092\u505c\u6b62\u3057\u307e\u3059
+standardHost.unfoundContext=\u30ea\u30af\u30a8\u30b9\u30c8URI {0} \u306e\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u3092\u898b\u3064\u3051\u308b\u3053\u3068\u304c\u3067\u304d\u307e\u305b\u3093
+standardHost.warRequired=Web\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u30a2\u30fc\u30ab\u30a4\u30d6\u306eURL\u304c\u5fc5\u8981\u3067\u3059
+standardHost.warURL=Web\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u30a2\u30fc\u30ab\u30a4\u30d6\u306b\u5bfe\u3059\u308b\u7121\u52b9\u306aURL\u3067\u3059: {0}
+standardHost.validationEnabled=XML\u691c\u8a3c\u306f\u6709\u52b9\u3067\u3059
+standardHost.validationDisabled=XML\u691c\u8a3c\u306f\u7121\u52b9\u3067\u3059
+standardPipeline.alreadyStarted=\u30d1\u30a4\u30d7\u30e9\u30a4\u30f3\u306f\u65e2\u306b\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u3059
+standardPipeline.notStarted=\u30d1\u30a4\u30d7\u30e9\u30a4\u30f3\u306f\u307e\u3060\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u305b\u3093
+standardPipeline.noValve=\u3053\u306e\u30ea\u30af\u30a8\u30b9\u30c8\u3092\u51e6\u7406\u3059\u308b\u30d1\u30a4\u30d7\u30e9\u30a4\u30f3\u4e2d\u306b\u3053\u308c\u4ee5\u4e0a\u306e\u30d0\u30eb\u30d6\u306f\u3042\u308a\u307e\u305b\u3093
+standardServer.addContainer.ise=\u3053\u306e\u30b3\u30f3\u30c6\u30ca\u3092\u95a2\u9023\u3065\u3051\u308b\u305f\u3081\u306e\u30b3\u30cd\u30af\u30bf\u304c\u5229\u7528\u3067\u304d\u307e\u305b\u3093
+standardServer.initialize.initialized=\u3053\u306e\u30b5\u30fc\u30d0\u306f\u65e2\u306b\u521d\u671f\u5316\u3055\u308c\u3066\u3044\u307e\u3059
+standardServer.start.connectors=\u30b3\u30f3\u30c6\u30ca\u306b\u4e00\u3064\u3082\u30b3\u30cd\u30af\u30bf\u304c\u95a2\u9023\u3065\u3051\u3089\u308c\u3066\u3044\u307e\u305b\u3093
+standardServer.start.started=\u3053\u306e\u30b5\u30fc\u30d0\u306f\u65e2\u306b\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u3059
+standardServer.stop.notStarted=\u3053\u306e\u30b5\u30fc\u30d0\u306f\u307e\u3060\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u305b\u3093
+standardService.initialize.initialized=\u3053\u306e\u30b5\u30fc\u30d3\u30b9\u306f\u65e2\u306b\u521d\u671f\u5316\u3055\u308c\u3066\u3044\u307e\u3059
+standardService.start.name=\u30b5\u30fc\u30d3\u30b9 {0} \u3092\u8d77\u52d5\u3057\u307e\u3059
+standardService.start.started=\u3053\u306e\u30b5\u30fc\u30d3\u30b9\u306f\u65e2\u306b\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u3059
+standardService.stop.name=\u30b5\u30fc\u30d3\u30b9 {0} \u3092\u505c\u6b62\u3057\u307e\u3059
+standardService.stop.notStarted=\u3053\u306e\u30b5\u30fc\u30d3\u30b9\u306f\u307e\u3060\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u305b\u3093
+standardWrapper.allocate=\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u3092\u5272\u308a\u5f53\u3066\u4e2d\u306e\u30a8\u30e9\u30fc\u3067\u3059
+standardWrapper.allocateException=\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8 {0} \u306b\u4f8b\u5916\u3092\u5272\u308a\u5f53\u3066\u307e\u3059
+standardWrapper.containerServlet=\u30b3\u30f3\u30c6\u30ca\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8 {0} \u3092\u30ed\u30fc\u30c9\u3057\u307e\u3059
+standardWrapper.createFilters=\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8 {0}\u306b\u5bfe\u3059\u308b\u30d5\u30a3\u30eb\u30bf\u4f8b\u5916\u3092\u4f5c\u6210\u3057\u307e\u3059
+standardWrapper.deallocateException=\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8 {0} \u306b\u5bfe\u3059\u308b\u4f8b\u5916\u306e\u5272\u308a\u5f53\u3066\u3092\u89e3\u9664\u3057\u307e\u3059
+standardWrapper.destroyException=\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8 {0} \u306eServlet.destroy()\u304c\u4f8b\u5916\u3092\u6295\u3052\u307e\u3057\u305f
+standardWrapper.exception0=Tomcat\u306e\u4f8b\u5916\u306e\u5831\u544a
+standardWrapper.exception1=\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8\u4f8b\u5916\u304c\u767a\u751f\u3057\u307e\u3057\u305f
+standardWrapper.exception2=\u4f8b\u5916\u306e\u5831\u544a:
+standardWrapper.exception3=\u6839\u672c\u306e\u539f\u56e0:
+standardWrapper.initException=\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8 {0} \u306eServlet.init()\u304c\u4f8b\u5916\u3092\u6295\u3052\u307e\u3057\u305f
+standardWrapper.instantiate=\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8\u30af\u30e9\u30b9 {0} \u3092\u521d\u671f\u5316\u4e2d\u306b\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f
+standardWrapper.isUnavailable=\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8 {0} \u306f\u73fe\u5728\u5229\u7528\u3067\u304d\u307e\u305b\u3093
+standardWrapper.jasperLoader=\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8 {0} \u306bJasper\u30af\u30e9\u30b9\u30ed\u30fc\u30c0\u3092\u4f7f\u7528\u3057\u307e\u3059
+standardWrapper.jspFile.format=JSP\u30d5\u30a1\u30a4\u30eb {0} \u304c''/''\u6587\u5b57\u3067\u59cb\u307e\u3063\u3066\u3044\u307e\u305b\u3093
+standardWrapper.loadException=\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8 {0} \u304cload()\u4f8b\u5916\u3092\u6295\u3052\u307e\u3057\u305f
+standardWrapper.missingClass=\u30e9\u30c3\u30d1\u304c\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8\u30af\u30e9\u30b9 {0} \u53c8\u306f\u305d\u308c\u304c\u4f9d\u5b58\u3059\u308b\u30af\u30e9\u30b9\u3092\u898b\u3064\u3051\u308b\u3053\u3068\u304c\u3067\u304d\u307e\u305b\u3093
+standardWrapper.missingLoader=\u30e9\u30c3\u30d1\u304c\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8 {0} \u306e\u30ed\u30fc\u30c0\u3092\u898b\u3064\u3051\u308b\u3053\u3068\u304c\u3067\u304d\u307e\u305b\u3093
+standardWrapper.notChild=\u30e9\u30c3\u30d1\u30b3\u30f3\u30c6\u30ca\u306f\u5b50\u4f9b\u306e\u30b3\u30f3\u30c6\u30ca\u3092\u6301\u3064\u3053\u3068\u306f\u3067\u304d\u307e\u305b\u3093
+standardWrapper.notClass=\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8 {0} \u306b\u6307\u5b9a\u3055\u308c\u305f\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8\u30af\u30e9\u30b9\u304c\u3042\u308a\u307e\u305b\u3093
+standardWrapper.notContext=\u30e9\u30c3\u30d1\u306e\u89aa\u306e\u30b3\u30f3\u30c6\u30ca\u306f\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u3067\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093
+standardWrapper.notFound=\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8 {0} \u304c\u5229\u7528\u3067\u304d\u307e\u305b\u3093
+standardWrapper.notServlet=\u30af\u30e9\u30b9 {0} \u306f\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8\u3067\u306f\u3042\u308a\u307e\u305b\u3093
+standardWrapper.privilegedServlet=\u30af\u30e9\u30b9 {0} \u306e\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8\u306f\u7279\u6a29\u3092\u4e0e\u3048\u3089\u308c\u3066\u3044\u308b\u306e\u3067\u3001\u3053\u306eWeb\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u306b\u3088\u3063\u3066\u30ed\u30fc\u30c9\u3067\u304d\u307e\u305b\u3093
+standardWrapper.releaseFilters=\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8 {0} \u306e\u30d5\u30a3\u30eb\u30bf\u4f8b\u5916\u3092\u89e3\u9664\u3057\u307e\u3059
+standardWrapper.serviceException=\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8 {0} \u306eServlet.service()\u304c\u4f8b\u5916\u3092\u6295\u3052\u307e\u3057\u305f
+standardWrapper.statusHeader=HTTP\u30b9\u30c6\u30fc\u30bf\u30b9 {0} - {1}
+standardWrapper.statusTitle=Tomcat\u306e\u30a8\u30e9\u30fc\u306e\u5831\u544a
+standardWrapper.unavailable=\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8 {0} \u3092\u5229\u7528\u4e0d\u53ef\u80fd\u306b\u30de\u30fc\u30af\u3057\u307e\u3059
+standardWrapper.unloadException=\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8 {0} \u304cunload()\u4f8b\u5916\u3092\u6295\u3052\u307e\u3057\u305f
+standardWrapper.unloading=\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8 {0} \u304c\u30ed\u30fc\u30c9\u3055\u308c\u3066\u3044\u306a\u3044\u306e\u3067\u3001\u5272\u308a\u5f53\u3066\u308b\u3053\u3068\u304c\u3067\u304d\u307e\u305b\u3093
+standardWrapper.waiting={0} \u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u304c\u5272\u308a\u5f53\u3066\u89e3\u9664\u3055\u308c\u308b\u306e\u3092\u5f85\u3063\u3066\u3044\u307e\u3059

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/core/NamingContextListener.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/core/NamingContextListener.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/core/NamingContextListener.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,1016 @@
+/*
+ * Copyright 1999,2004-2005 The Apache Software Foundation.
+ * 
+ * Licensed 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.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.StringTokenizer;
+
+import javax.management.MalformedObjectNameException;
+import javax.management.ObjectName;
+import javax.naming.NameAlreadyBoundException;
+import javax.naming.NamingException;
+import javax.naming.Reference;
+import javax.naming.StringRefAddr;
+
+import org.apache.catalina.Container;
+import org.apache.catalina.ContainerEvent;
+import org.apache.catalina.ContainerListener;
+import org.apache.catalina.Context;
+import org.apache.catalina.Engine;
+import org.apache.catalina.Host;
+import org.apache.catalina.Lifecycle;
+import org.apache.catalina.LifecycleEvent;
+import org.apache.catalina.LifecycleListener;
+import org.apache.catalina.Server;
+import org.apache.catalina.Service;
+import org.apache.catalina.deploy.ContextEjb;
+import org.apache.catalina.deploy.ContextEnvironment;
+import org.apache.catalina.deploy.ContextLocalEjb;
+import org.apache.catalina.deploy.ContextResource;
+import org.apache.catalina.deploy.ContextResourceEnvRef;
+import org.apache.catalina.deploy.ContextResourceLink;
+import org.apache.catalina.deploy.ContextTransaction;
+import org.apache.catalina.deploy.NamingResources;
+import org.apache.catalina.util.StringManager;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.commons.modeler.Registry;
+import org.apache.naming.ContextAccessController;
+import org.apache.naming.ContextBindings;
+import org.apache.naming.EjbRef;
+import org.apache.naming.NamingContext;
+import org.apache.naming.ResourceEnvRef;
+import org.apache.naming.ResourceLinkRef;
+import org.apache.naming.ResourceRef;
+import org.apache.naming.TransactionRef;
+
+
+/**
+ * Helper class used to initialize and populate the JNDI context associated
+ * with each context and server.
+ *
+ * @author Remy Maucherat
+ * @version $Revision: 304032 $ $Date: 2005-07-27 10:11:55 -0500 (Wed, 27 Jul 2005) $
+ */
+
+public class NamingContextListener
+    implements LifecycleListener, ContainerListener, PropertyChangeListener {
+
+    private static Log log = LogFactory.getLog(NamingContextListener.class);
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    protected Log logger = log;
+    
+    
+    /**
+     * Name of the associated naming context.
+     */
+    protected String name = "/";
+
+
+    /**
+     * Associated container.
+     */
+    protected Object container = null;
+
+
+    /**
+     * Initialized flag.
+     */
+    protected boolean initialized = false;
+
+
+    /**
+     * Associated naming resources.
+     */
+    protected NamingResources namingResources = null;
+
+
+    /**
+     * Associated JNDI context.
+     */
+    protected NamingContext namingContext = null;
+
+
+    /**
+     * Comp context.
+     */
+    protected javax.naming.Context compCtx = null;
+
+
+    /**
+     * Env context.
+     */
+    protected javax.naming.Context envCtx = null;
+
+    
+    /**
+     * Objectnames hashtable.
+     */
+    protected HashMap objectNames = new HashMap();
+    
+
+    /**
+     * The string manager for this package.
+     */
+    protected static StringManager sm =
+        StringManager.getManager(Constants.Package);
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * Return the "name" property.
+     */
+    public String getName() {
+
+        return (this.name);
+
+    }
+
+
+    /**
+     * Set the "name" property.
+     *
+     * @param name The new name
+     */
+    public void setName(String name) {
+
+        this.name = name;
+        if( log.isDebugEnabled() )
+            log.debug( "setName " + name);
+    }
+
+
+    /**
+     * Return the associated naming context.
+     */
+    public NamingContext getNamingContext() {
+
+        return (this.namingContext);
+
+    }
+
+
+    // ---------------------------------------------- LifecycleListener Methods
+
+
+    /**
+     * Acknowledge the occurrence of the specified event.
+     *
+     * @param event LifecycleEvent that has occurred
+     */
+    public void lifecycleEvent(LifecycleEvent event) {
+
+        container = event.getLifecycle();
+
+        if (container instanceof Context) {
+            namingResources = ((Context) container).getNamingResources();
+            logger = log;
+        } else if (container instanceof Server) {
+            namingResources = ((Server) container).getGlobalNamingResources();
+        } else {
+            return;
+        }
+
+        if (event.getType() == Lifecycle.START_EVENT) {
+
+            if (initialized)
+                return;
+
+            Hashtable contextEnv = new Hashtable();
+            try {
+                namingContext = new NamingContext(contextEnv, getName());
+            } catch (NamingException e) {
+                // Never happens
+            }
+            ContextAccessController.setSecurityToken(getName(), container);
+            ContextBindings.bindContext(container, namingContext, container);
+            if( log.isDebugEnabled() ) {
+                log.debug("Bound " + container );
+            }
+
+            // Setting the context in read/write mode
+            ContextAccessController.setWritable(getName(), container);
+
+            try {
+                createNamingContext();
+            } catch (NamingException e) {
+                logger.error
+                    (sm.getString("naming.namingContextCreationFailed", e));
+            }
+
+            // Binding the naming context to the class loader
+            if (container instanceof Context) {
+                // Setting the context in read only mode
+                ContextAccessController.setReadOnly(getName());
+                try {
+                    ContextBindings.bindClassLoader
+                        (container, container, 
+                         ((Container) container).getLoader().getClassLoader());
+                } catch (NamingException e) {
+                    logger.error(sm.getString("naming.bindFailed", e));
+                }
+            }
+
+            if (container instanceof Server) {
+                namingResources.addPropertyChangeListener(this);
+                org.apache.naming.factory.ResourceLinkFactory.setGlobalContext
+                    (namingContext);
+                try {
+                    ContextBindings.bindClassLoader
+                        (container, container, 
+                         this.getClass().getClassLoader());
+                } catch (NamingException e) {
+                    logger.error(sm.getString("naming.bindFailed", e));
+                }
+                if (container instanceof StandardServer) {
+                    ((StandardServer) container).setGlobalNamingContext
+                        (namingContext);
+                }
+            }
+
+            initialized = true;
+
+        } else if (event.getType() == Lifecycle.STOP_EVENT) {
+
+            if (!initialized)
+                return;
+
+            // Setting the context in read/write mode
+            ContextAccessController.setWritable(getName(), container);
+            ContextBindings.unbindContext(container, container);
+
+            if (container instanceof Context) {
+                ContextBindings.unbindClassLoader
+                    (container, container, 
+                     ((Container) container).getLoader().getClassLoader());
+            }
+
+            if (container instanceof Server) {
+                namingResources.removePropertyChangeListener(this);
+                ContextBindings.unbindClassLoader
+                    (container, container, 
+                     this.getClass().getClassLoader());
+            }
+
+            ContextAccessController.unsetSecurityToken(getName(), container);
+
+            namingContext = null;
+            envCtx = null;
+            compCtx = null;
+            initialized = false;
+
+        }
+
+    }
+
+
+    // ---------------------------------------------- ContainerListener Methods
+
+
+    /**
+     * Acknowledge the occurrence of the specified event.
+     * Note: Will never be called when the listener is associated to a Server,
+     * since it is not a Container.
+     *
+     * @param event ContainerEvent that has occurred
+     */
+    public void containerEvent(ContainerEvent event) {
+
+        if (!initialized)
+            return;
+
+        // Setting the context in read/write mode
+        ContextAccessController.setWritable(getName(), container);
+
+        String type = event.getType();
+
+        if (type.equals("addEjb")) {
+
+            String ejbName = (String) event.getData();
+            if (ejbName != null) {
+                ContextEjb ejb = namingResources.findEjb(ejbName);
+                addEjb(ejb);
+            }
+
+        } else if (type.equals("addEnvironment")) {
+
+            String environmentName = (String) event.getData();
+            if (environmentName != null) {
+                ContextEnvironment env = 
+                    namingResources.findEnvironment(environmentName);
+                addEnvironment(env);
+            }
+
+        } else if (type.equals("addLocalEjb")) {
+
+            String localEjbName = (String) event.getData();
+            if (localEjbName != null) {
+                ContextLocalEjb localEjb = 
+                    namingResources.findLocalEjb(localEjbName);
+                addLocalEjb(localEjb);
+            }
+
+        } else if (type.equals("addResource")) {
+
+            String resourceName = (String) event.getData();
+            if (resourceName != null) {
+                ContextResource resource = 
+                    namingResources.findResource(resourceName);
+                addResource(resource);
+            }
+
+        } else if (type.equals("addResourceLink")) {
+
+            String resourceLinkName = (String) event.getData();
+            if (resourceLinkName != null) {
+                ContextResourceLink resourceLink = 
+                    namingResources.findResourceLink(resourceLinkName);
+                addResourceLink(resourceLink);
+            }
+
+        } else if (type.equals("addResourceEnvRef")) {
+
+            String resourceEnvRefName = (String) event.getData();
+            if (resourceEnvRefName != null) {
+                ContextResourceEnvRef resourceEnvRef = 
+                    namingResources.findResourceEnvRef(resourceEnvRefName);
+                addResourceEnvRef(resourceEnvRef);
+            }
+
+        } else if (type.equals("removeEjb")) {
+
+            String ejbName = (String) event.getData();
+            if (ejbName != null) {
+                removeEjb(ejbName);
+            }
+
+        } else if (type.equals("removeEnvironment")) {
+
+            String environmentName = (String) event.getData();
+            if (environmentName != null) {
+                removeEnvironment(environmentName);
+            }
+
+        } else if (type.equals("removeLocalEjb")) {
+
+            String localEjbName = (String) event.getData();
+            if (localEjbName != null) {
+                removeLocalEjb(localEjbName);
+            }
+
+        } else if (type.equals("removeResource")) {
+
+            String resourceName = (String) event.getData();
+            if (resourceName != null) {
+                removeResource(resourceName);
+            }
+
+        } else if (type.equals("removeResourceLink")) {
+
+            String resourceLinkName = (String) event.getData();
+            if (resourceLinkName != null) {
+                removeResourceLink(resourceLinkName);
+            }
+
+        } else if (type.equals("removeResourceEnvRef")) {
+
+            String resourceEnvRefName = (String) event.getData();
+            if (resourceEnvRefName != null) {
+                removeResourceEnvRef(resourceEnvRefName);
+            }
+
+        }
+
+        // Setting the context in read only mode
+        ContextAccessController.setReadOnly(getName());
+
+    }
+
+
+    // ----------------------------------------- PropertyChangeListener Methods
+
+
+    /**
+     * Process property change events.  Currently, only listens to such events
+     * on the <code>NamingResources</code> instance for the global naming
+     * resources.
+     *
+     * @param event The property change event that has occurred
+     */
+    public void propertyChange(PropertyChangeEvent event) {
+
+        if (!initialized)
+            return;
+
+        Object source = event.getSource();
+        if (source == namingResources) {
+
+            // Setting the context in read/write mode
+            ContextAccessController.setWritable(getName(), container);
+
+            processGlobalResourcesChange(event.getPropertyName(),
+                                         event.getOldValue(),
+                                         event.getNewValue());
+
+            // Setting the context in read only mode
+            ContextAccessController.setReadOnly(getName());
+
+        }
+
+    }
+
+
+    // -------------------------------------------------------- Private Methods
+
+
+    /**
+     * Process a property change on the global naming resources, by making the
+     * corresponding addition or removal to the associated JNDI context.
+     *
+     * @param name Property name of the change to be processed
+     * @param oldValue The old value (or <code>null</code> if adding)
+     * @param newValue The new value (or <code>null</code> if removing)
+     */
+    private void processGlobalResourcesChange(String name,
+                                              Object oldValue,
+                                              Object newValue) {
+
+        // NOTE - It seems that the Context for global JNDI resources
+        // is left in read-write mode, so we do not have to change it here
+
+        if (name.equals("ejb")) {
+            if (oldValue != null) {
+                ContextEjb ejb = (ContextEjb) oldValue;
+                if (ejb.getName() != null) {
+                    removeEjb(ejb.getName());
+                }
+            }
+            if (newValue != null) {
+                ContextEjb ejb = (ContextEjb) newValue;
+                if (ejb.getName() != null) {
+                    addEjb(ejb);
+                }
+            }
+        } else if (name.equals("environment")) {
+            if (oldValue != null) {
+                ContextEnvironment env = (ContextEnvironment) oldValue;
+                if (env.getName() != null) {
+                    removeEnvironment(env.getName());
+                }
+            }
+            if (newValue != null) {
+                ContextEnvironment env = (ContextEnvironment) newValue;
+                if (env.getName() != null) {
+                    addEnvironment(env);
+                }
+            }
+        } else if (name.equals("localEjb")) {
+            if (oldValue != null) {
+                ContextLocalEjb ejb = (ContextLocalEjb) oldValue;
+                if (ejb.getName() != null) {
+                    removeLocalEjb(ejb.getName());
+                }
+            }
+            if (newValue != null) {
+                ContextLocalEjb ejb = (ContextLocalEjb) newValue;
+                if (ejb.getName() != null) {
+                    addLocalEjb(ejb);
+                }
+            }
+        } else if (name.equals("resource")) {
+            if (oldValue != null) {
+                ContextResource resource = (ContextResource) oldValue;
+                if (resource.getName() != null) {
+                    removeResource(resource.getName());
+                }
+            }
+            if (newValue != null) {
+                ContextResource resource = (ContextResource) newValue;
+                if (resource.getName() != null) {
+                    addResource(resource);
+                }
+            }
+        } else if (name.equals("resourceEnvRef")) {
+            if (oldValue != null) {
+                ContextResourceEnvRef resourceEnvRef = 
+                    (ContextResourceEnvRef) oldValue;
+                if (resourceEnvRef.getName() != null) {
+                    removeResourceEnvRef(resourceEnvRef.getName());
+                }
+            }
+            if (newValue != null) {
+                ContextResourceEnvRef resourceEnvRef = 
+                    (ContextResourceEnvRef) newValue;
+                if (resourceEnvRef.getName() != null) {
+                    addResourceEnvRef(resourceEnvRef);
+                }
+            }
+        } else if (name.equals("resourceLink")) {
+            if (oldValue != null) {
+                ContextResourceLink rl = (ContextResourceLink) oldValue;
+                if (rl.getName() != null) {
+                    removeResourceLink(rl.getName());
+                }
+            }
+            if (newValue != null) {
+                ContextResourceLink rl = (ContextResourceLink) newValue;
+                if (rl.getName() != null) {
+                    addResourceLink(rl);
+                }
+            }
+        }
+
+
+    }
+
+
+    /**
+     * Create and initialize the JNDI naming context.
+     */
+    private void createNamingContext()
+        throws NamingException {
+
+        // Creating the comp subcontext
+        if (container instanceof Server) {
+            compCtx = namingContext;
+            envCtx = namingContext;
+        } else {
+            compCtx = namingContext.createSubcontext("comp");
+            envCtx = compCtx.createSubcontext("env");
+        }
+
+        int i;
+
+        if (log.isDebugEnabled())
+            log.debug("Creating JNDI naming context");
+
+        if (namingResources == null) {
+            namingResources = new NamingResources();
+            namingResources.setContainer(container);
+        }
+
+        // Resource links
+        ContextResourceLink[] resourceLinks = 
+            namingResources.findResourceLinks();
+        for (i = 0; i < resourceLinks.length; i++) {
+            addResourceLink(resourceLinks[i]);
+        }
+
+        // Resources
+        ContextResource[] resources = namingResources.findResources();
+        for (i = 0; i < resources.length; i++) {
+            addResource(resources[i]);
+        }
+
+        // Resources Env
+        ContextResourceEnvRef[] resourceEnvRefs = namingResources.findResourceEnvRefs();
+        for (i = 0; i < resourceEnvRefs.length; i++) {
+            addResourceEnvRef(resourceEnvRefs[i]);
+        }
+
+        // Environment entries
+        ContextEnvironment[] contextEnvironments = 
+            namingResources.findEnvironments();
+        for (i = 0; i < contextEnvironments.length; i++) {
+            addEnvironment(contextEnvironments[i]);
+        }
+
+        // EJB references
+        ContextEjb[] ejbs = namingResources.findEjbs();
+        for (i = 0; i < ejbs.length; i++) {
+            addEjb(ejbs[i]);
+        }
+
+        // Binding a User Transaction reference
+        if (container instanceof Context) {
+            try {
+                Reference ref = new TransactionRef();
+                compCtx.bind("UserTransaction", ref);
+                ContextTransaction transaction = namingResources.getTransaction();
+                if (transaction != null) {
+                    Iterator params = transaction.listProperties();
+                    while (params.hasNext()) {
+                        String paramName = (String) params.next();
+                        String paramValue = (String) transaction.getProperty(paramName);
+                        StringRefAddr refAddr = new StringRefAddr(paramName, paramValue);
+                        ref.add(refAddr);
+                    }
+                }
+            } catch (NameAlreadyBoundException e) {
+                // Ignore because UserTransaction was obviously 
+                // added via ResourceLink
+            } catch (NamingException e) {
+                logger.error(sm.getString("naming.bindFailed", e));
+            }
+        }
+
+        // Binding the resources directory context
+        if (container instanceof Context) {
+            try {
+                compCtx.bind("Resources", 
+                             ((Container) container).getResources());
+            } catch (NamingException e) {
+                logger.error(sm.getString("naming.bindFailed", e));
+            }
+        }
+
+    }
+
+
+    /**
+     * Create an <code>ObjectName</code> for this
+     * <code>ContextResource</code> object.
+     *
+     * @param resource The resource
+     * @return ObjectName The object name
+     * @exception MalformedObjectNameException if a name cannot be created
+     */
+    protected ObjectName createObjectName(ContextResource resource)
+        throws MalformedObjectNameException {
+
+        String domain = null;
+        if (container instanceof StandardServer) {
+            domain = ((StandardServer) container).getDomain();
+        } else if (container instanceof ContainerBase) {
+            domain = ((ContainerBase) container).getDomain();
+        }
+        if (domain == null) {
+            domain = "Catalina";
+        }
+        
+        ObjectName name = null;
+        String quotedResourceName = ObjectName.quote(resource.getName());
+        if (container instanceof Server) {        
+            name = new ObjectName(domain + ":type=DataSource" +
+                        ",class=" + resource.getType() + 
+                        ",name=" + quotedResourceName);
+        } else if (container instanceof Context) {                    
+            String path = ((Context)container).getPath();
+            if (path.length() < 1)
+                path = "/";
+            Host host = (Host) ((Context)container).getParent();
+            Engine engine = (Engine) host.getParent();
+            Service service = engine.getService();
+            name = new ObjectName(domain + ":type=DataSource" +
+                        ",path=" + path + 
+                        ",host=" + host.getName() +
+                        ",class=" + resource.getType() +
+                        ",name=" + quotedResourceName);
+        }
+        
+        return (name);
+
+    }
+
+    
+    /**
+     * Set the specified EJBs in the naming context.
+     */
+    public void addEjb(ContextEjb ejb) {
+
+        // Create a reference to the EJB.
+        Reference ref = new EjbRef
+            (ejb.getType(), ejb.getHome(), ejb.getRemote(), ejb.getLink());
+        // Adding the additional parameters, if any
+        Iterator params = ejb.listProperties();
+        while (params.hasNext()) {
+            String paramName = (String) params.next();
+            String paramValue = (String) ejb.getProperty(paramName);
+            StringRefAddr refAddr = new StringRefAddr(paramName, paramValue);
+            ref.add(refAddr);
+        }
+        try {
+            createSubcontexts(envCtx, ejb.getName());
+            envCtx.bind(ejb.getName(), ref);
+        } catch (NamingException e) {
+            logger.error(sm.getString("naming.bindFailed", e));
+        }
+
+    }
+
+
+    /**
+     * Set the specified environment entries in the naming context.
+     */
+    public void addEnvironment(ContextEnvironment env) {
+
+        Object value = null;
+        // Instantiating a new instance of the correct object type, and
+        // initializing it.
+        String type = env.getType();
+        try {
+            if (type.equals("java.lang.String")) {
+                value = env.getValue();
+            } else if (type.equals("java.lang.Byte")) {
+                if (env.getValue() == null) {
+                    value = new Byte((byte) 0);
+                } else {
+                    value = Byte.decode(env.getValue());
+                }
+            } else if (type.equals("java.lang.Short")) {
+                if (env.getValue() == null) {
+                    value = new Short((short) 0);
+                } else {
+                    value = Short.decode(env.getValue());
+                }
+            } else if (type.equals("java.lang.Integer")) {
+                if (env.getValue() == null) {
+                    value = new Integer(0);
+                } else {
+                    value = Integer.decode(env.getValue());
+                }
+            } else if (type.equals("java.lang.Long")) {
+                if (env.getValue() == null) {
+                    value = new Long(0);
+                } else {
+                    value = Long.decode(env.getValue());
+                }
+            } else if (type.equals("java.lang.Boolean")) {
+                value = Boolean.valueOf(env.getValue());
+            } else if (type.equals("java.lang.Double")) {
+                if (env.getValue() == null) {
+                    value = new Double(0);
+                } else {
+                    value = Double.valueOf(env.getValue());
+                }
+            } else if (type.equals("java.lang.Float")) {
+                if (env.getValue() == null) {
+                    value = new Float(0);
+                } else {
+                    value = Float.valueOf(env.getValue());
+                }
+            } else if (type.equals("java.lang.Character")) {
+                if (env.getValue() == null) {
+                    value = new Character((char) 0);
+                } else {
+                    if (env.getValue().length() == 1) {
+                        value = new Character(env.getValue().charAt(0));
+                    } else {
+                        throw new IllegalArgumentException();
+                    }
+                }
+            } else {
+                logger.error(sm.getString("naming.invalidEnvEntryType", env.getName()));
+            }
+        } catch (NumberFormatException e) {
+            logger.error(sm.getString("naming.invalidEnvEntryValue", env.getName()));
+        } catch (IllegalArgumentException e) {
+            logger.error(sm.getString("naming.invalidEnvEntryValue", env.getName()));
+        }
+
+        // Binding the object to the appropriate name
+        if (value != null) {
+            try {
+                if (logger.isDebugEnabled())
+                    logger.debug("  Adding environment entry " + env.getName());
+                createSubcontexts(envCtx, env.getName());
+                envCtx.bind(env.getName(), value);
+            } catch (NamingException e) {
+                logger.error(sm.getString("naming.invalidEnvEntryValue", e));
+            }
+        }
+
+    }
+
+
+    /**
+     * Set the specified local EJBs in the naming context.
+     */
+    public void addLocalEjb(ContextLocalEjb localEjb) {
+
+
+
+    }
+
+
+    /**
+     * Set the specified resources in the naming context.
+     */
+    public void addResource(ContextResource resource) {
+
+        // Create a reference to the resource.
+        Reference ref = new ResourceRef
+            (resource.getType(), resource.getDescription(),
+             resource.getScope(), resource.getAuth());
+        // Adding the additional parameters, if any
+        Iterator params = resource.listProperties();
+        while (params.hasNext()) {
+            String paramName = (String) params.next();
+            String paramValue = (String) resource.getProperty(paramName);
+            StringRefAddr refAddr = new StringRefAddr(paramName, paramValue);
+            ref.add(refAddr);
+        }
+        try {
+            if (logger.isDebugEnabled()) {
+                logger.debug("  Adding resource ref " 
+                             + resource.getName() + "  " + ref);
+            }
+            createSubcontexts(envCtx, resource.getName());
+            envCtx.bind(resource.getName(), ref);
+        } catch (NamingException e) {
+            logger.error(sm.getString("naming.bindFailed", e));
+        }
+
+        if ("javax.sql.DataSource".equals(ref.getClassName())) {
+            try {
+                ObjectName on = createObjectName(resource);
+                Object actualResource = envCtx.lookup(resource.getName());
+                Registry.getRegistry(null, null).registerComponent(actualResource, on, null);
+                objectNames.put(resource.getName(), on);
+            } catch (Exception e) {
+                logger.warn(sm.getString("naming.jmxRegistrationFailed", e));
+            }
+        }
+        
+    }
+
+
+    /**
+     * Set the specified resources in the naming context.
+     */
+    public void addResourceEnvRef(ContextResourceEnvRef resourceEnvRef) {
+
+        // Create a reference to the resource env.
+        Reference ref = new ResourceEnvRef(resourceEnvRef.getType());
+        // Adding the additional parameters, if any
+        Iterator params = resourceEnvRef.listProperties();
+        while (params.hasNext()) {
+            String paramName = (String) params.next();
+            String paramValue = (String) resourceEnvRef.getProperty(paramName);
+            StringRefAddr refAddr = new StringRefAddr(paramName, paramValue);
+            ref.add(refAddr);
+        }
+        try {
+            if (logger.isDebugEnabled())
+                log.debug("  Adding resource env ref " + resourceEnvRef.getName());
+            createSubcontexts(envCtx, resourceEnvRef.getName());
+            envCtx.bind(resourceEnvRef.getName(), ref);
+        } catch (NamingException e) {
+            logger.error(sm.getString("naming.bindFailed", e));
+        }
+
+    }
+
+
+    /**
+     * Set the specified resource link in the naming context.
+     */
+    public void addResourceLink(ContextResourceLink resourceLink) {
+
+        // Create a reference to the resource.
+        Reference ref = new ResourceLinkRef
+            (resourceLink.getType(), resourceLink.getGlobal());
+        javax.naming.Context ctx = 
+            "UserTransaction".equals(resourceLink.getName()) 
+            ? compCtx : envCtx;
+        try {
+            if (logger.isDebugEnabled())
+                log.debug("  Adding resource link " + resourceLink.getName());
+            createSubcontexts(envCtx, resourceLink.getName());
+            ctx.bind(resourceLink.getName(), ref);
+        } catch (NamingException e) {
+            logger.error(sm.getString("naming.bindFailed", e));
+        }
+
+    }
+
+
+    /**
+     * Set the specified EJBs in the naming context.
+     */
+    public void removeEjb(String name) {
+
+        try {
+            envCtx.unbind(name);
+        } catch (NamingException e) {
+            logger.error(sm.getString("naming.unbindFailed", e));
+        }
+
+    }
+
+
+    /**
+     * Set the specified environment entries in the naming context.
+     */
+    public void removeEnvironment(String name) {
+
+        try {
+            envCtx.unbind(name);
+        } catch (NamingException e) {
+            logger.error(sm.getString("naming.unbindFailed", e));
+        }
+
+    }
+
+
+    /**
+     * Set the specified local EJBs in the naming context.
+     */
+    public void removeLocalEjb(String name) {
+
+        try {
+            envCtx.unbind(name);
+        } catch (NamingException e) {
+            logger.error(sm.getString("naming.unbindFailed", e));
+        }
+
+    }
+
+
+    /**
+     * Set the specified resources in the naming context.
+     */
+    public void removeResource(String name) {
+
+        try {
+            envCtx.unbind(name);
+        } catch (NamingException e) {
+            logger.error(sm.getString("naming.unbindFailed", e));
+        }
+
+        ObjectName on = (ObjectName) objectNames.get(name);
+        if (on != null) {
+            Registry.getRegistry(null, null).unregisterComponent(on);
+        }
+
+    }
+
+
+    /**
+     * Set the specified resources in the naming context.
+     */
+    public void removeResourceEnvRef(String name) {
+
+        try {
+            envCtx.unbind(name);
+        } catch (NamingException e) {
+            logger.error(sm.getString("naming.unbindFailed", e));
+        }
+
+    }
+
+
+    /**
+     * Set the specified resources in the naming context.
+     */
+    public void removeResourceLink(String name) {
+
+        try {
+            envCtx.unbind(name);
+        } catch (NamingException e) {
+            logger.error(sm.getString("naming.unbindFailed", e));
+        }
+
+    }
+
+
+    /**
+     * Create all intermediate subcontexts.
+     */
+    private void createSubcontexts(javax.naming.Context ctx, String name)
+        throws NamingException {
+        javax.naming.Context currentContext = ctx;
+        StringTokenizer tokenizer = new StringTokenizer(name, "/");
+        while (tokenizer.hasMoreTokens()) {
+            String token = tokenizer.nextToken();
+            if ((!token.equals("")) && (tokenizer.hasMoreTokens())) {
+                try {
+                    currentContext = currentContext.createSubcontext(token);
+                } catch (NamingException e) {
+                    // Silent catch. Probably an object is already bound in
+                    // the context.
+                    currentContext =
+                        (javax.naming.Context) currentContext.lookup(token);
+                }
+            }
+        }
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/core/StandardContext.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/core/StandardContext.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/core/StandardContext.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,5393 @@
+/*
+ * Copyright 1999,2004-2005 The Apache Software Foundation.
+ * 
+ * Licensed 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.BufferedReader;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.Stack;
+import java.util.TreeMap;
+
+import javax.management.AttributeNotFoundException;
+import javax.management.ListenerNotFoundException;
+import javax.management.MBeanNotificationInfo;
+import javax.management.MBeanRegistrationException;
+import javax.management.MBeanServer;
+import javax.management.MalformedObjectNameException;
+import javax.management.Notification;
+import javax.management.NotificationBroadcasterSupport;
+import javax.management.NotificationEmitter;
+import javax.management.NotificationFilter;
+import javax.management.NotificationListener;
+import javax.management.ObjectName;
+import javax.naming.NamingException;
+import javax.naming.directory.DirContext;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletContextAttributeListener;
+import javax.servlet.ServletContextEvent;
+import javax.servlet.ServletContextListener;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequestAttributeListener;
+import javax.servlet.ServletRequestListener;
+import javax.servlet.http.HttpSessionAttributeListener;
+import javax.servlet.http.HttpSessionListener;
+
+import org.apache.catalina.Container;
+import org.apache.catalina.ContainerListener;
+import org.apache.catalina.Context;
+import org.apache.catalina.Engine;
+import org.apache.catalina.Globals;
+import org.apache.catalina.Host;
+import org.apache.catalina.InstanceListener;
+import org.apache.catalina.Lifecycle;
+import org.apache.catalina.LifecycleException;
+import org.apache.catalina.LifecycleListener;
+import org.apache.catalina.Loader;
+import org.apache.catalina.Wrapper;
+import org.apache.catalina.deploy.ApplicationParameter;
+import org.apache.catalina.deploy.ErrorPage;
+import org.apache.catalina.deploy.FilterDef;
+import org.apache.catalina.deploy.FilterMap;
+import org.apache.catalina.deploy.LoginConfig;
+import org.apache.catalina.deploy.MessageDestination;
+import org.apache.catalina.deploy.MessageDestinationRef;
+import org.apache.catalina.deploy.NamingResources;
+import org.apache.catalina.deploy.SecurityCollection;
+import org.apache.catalina.deploy.SecurityConstraint;
+import org.apache.catalina.loader.WebappLoader;
+import org.apache.catalina.session.StandardManager;
+import org.apache.catalina.startup.ContextConfig;
+import org.apache.catalina.startup.TldConfig;
+import org.apache.catalina.util.CharsetMapper;
+import org.apache.catalina.util.ExtensionValidator;
+import org.apache.catalina.util.RequestUtil;
+import org.apache.catalina.util.URLEncoder;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.commons.modeler.Registry;
+import org.apache.naming.ContextBindings;
+import org.apache.naming.resources.BaseDirContext;
+import org.apache.naming.resources.DirContextURLStreamHandler;
+import org.apache.naming.resources.FileDirContext;
+import org.apache.naming.resources.ProxyDirContext;
+import org.apache.naming.resources.WARDirContext;
+
+/**
+ * Standard implementation of the <b>Context</b> interface.  Each
+ * child container must be a Wrapper implementation to process the
+ * requests directed to a particular servlet.
+ *
+ * @author Craig R. McClanahan
+ * @author Remy Maucherat
+ * @version $Revision: 440946 $ $Date: 2006-09-06 21:10:10 -0500 (Wed, 06 Sep 2006) $
+ */
+
+public class StandardContext
+    extends ContainerBase
+    implements Context, Serializable, NotificationEmitter
+{
+    private static transient Log log = LogFactory.getLog(StandardContext.class);
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Create a new StandardContext component with the default basic Valve.
+     */
+    public StandardContext() {
+
+        super();
+        pipeline.setBasic(new StandardContextValve());
+        broadcaster = new NotificationBroadcasterSupport();
+
+    }
+
+
+    // ----------------------------------------------------- Class Variables
+
+
+    /**
+     * The descriptive information string for this implementation.
+     */
+    private static final String info =
+        "org.apache.catalina.core.StandardContext/1.0";
+
+
+    /**
+     * Array containing the safe characters set.
+     */
+    protected static URLEncoder urlEncoder;
+
+
+    /**
+     * GMT timezone - all HTTP dates are on GMT
+     */
+    static {
+        urlEncoder = new URLEncoder();
+        urlEncoder.addSafeCharacter('~');
+        urlEncoder.addSafeCharacter('-');
+        urlEncoder.addSafeCharacter('_');
+        urlEncoder.addSafeCharacter('.');
+        urlEncoder.addSafeCharacter('*');
+        urlEncoder.addSafeCharacter('/');
+    }
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The alternate deployment descriptor name.
+     */
+    private String altDDName = null;
+
+
+    /**
+     * Associated host name.
+     */
+    private String hostName;
+
+
+    /**
+     * The antiJARLocking flag for this Context.
+     */
+    private boolean antiJARLocking = false;
+
+    
+    /**
+     * The antiResourceLocking flag for this Context.
+     */
+    private boolean antiResourceLocking = false;
+
+    
+    /**
+     * The set of application listener class names configured for this
+     * application, in the order they were encountered in the web.xml file.
+     */
+    private String applicationListeners[] = new String[0];
+
+
+    /**
+     * The set of instantiated application event listener objects</code>.
+     */
+    private transient Object applicationEventListenersObjects[] = 
+        new Object[0];
+
+
+    /**
+     * The set of instantiated application lifecycle listener objects</code>.
+     */
+    private transient Object applicationLifecycleListenersObjects[] = 
+        new Object[0];
+
+
+    /**
+     * The set of application parameters defined for this application.
+     */
+    private ApplicationParameter applicationParameters[] =
+        new ApplicationParameter[0];
+
+
+    /**
+     * The application available flag for this Context.
+     */
+    private boolean available = false;
+    
+    /**
+     * The broadcaster that sends j2ee notifications. 
+     */
+    private NotificationBroadcasterSupport broadcaster = null;
+    
+    /**
+     * The Locale to character set mapper for this application.
+     */
+    private transient CharsetMapper charsetMapper = null;
+
+
+    /**
+     * The Java class name of the CharsetMapper class to be created.
+     */
+    private String charsetMapperClass =
+      "org.apache.catalina.util.CharsetMapper";
+
+
+    /**
+     * The path to a file to save this Context information.
+     */
+    private String configFile = null;
+
+
+    /**
+     * The "correctly configured" flag for this Context.
+     */
+    private boolean configured = false;
+
+
+    /**
+     * The security constraints for this web application.
+     */
+    private SecurityConstraint constraints[] = new SecurityConstraint[0];
+
+
+    /**
+     * The ServletContext implementation associated with this Context.
+     */
+    protected transient ApplicationContext context = null;
+
+
+    /**
+     * Compiler classpath to use.
+     */
+    private String compilerClasspath = null;
+
+
+    /**
+     * Should we attempt to use cookies for session id communication?
+     */
+    private boolean cookies = true;
+
+
+    /**
+     * Should we allow the <code>ServletContext.getContext()</code> method
+     * to access the context of other web applications in this server?
+     */
+    private boolean crossContext = false;
+
+    
+    /**
+     * Encoded path.
+     */
+    private String encodedPath = null;
+    
+
+    /**
+     * The "follow standard delegation model" flag that will be used to
+     * configure our ClassLoader.
+     */
+    private boolean delegate = false;
+
+
+     /**
+     * The display name of this web application.
+     */
+    private String displayName = null;
+
+
+    /** 
+     * Override the default context xml location.
+     */
+    private String defaultContextXml;
+
+
+    /** 
+     * Override the default web xml location.
+     */
+    private String defaultWebXml;
+
+
+    /**
+     * The distributable flag for this web application.
+     */
+    private boolean distributable = false;
+
+
+    /**
+     * The document root for this web application.
+     */
+    private String docBase = null;
+
+
+    /**
+     * The original document root for this web application.
+     */
+    private String originalDocBase = null;
+
+    /**
+     * The exception pages for this web application, keyed by fully qualified
+     * class name of the Java exception.
+     */
+    private HashMap exceptionPages = new HashMap();
+
+
+    /**
+     * The set of filter configurations (and associated filter instances) we
+     * have initialized, keyed by filter name.
+     */
+    private HashMap filterConfigs = new HashMap();
+
+
+    /**
+     * The set of filter definitions for this application, keyed by
+     * filter name.
+     */
+    private HashMap filterDefs = new HashMap();
+
+
+    /**
+     * The set of filter mappings for this application, in the order
+     * they were defined in the deployment descriptor.
+     */
+    private FilterMap filterMaps[] = new FilterMap[0];
+
+
+    /**
+     * The set of classnames of InstanceListeners that will be added
+     * to each newly created Wrapper by <code>createWrapper()</code>.
+     */
+    private String instanceListeners[] = new String[0];
+
+
+    /**
+     * The login configuration descriptor for this web application.
+     */
+    private LoginConfig loginConfig = null;
+
+
+    /**
+     * The mapper associated with this context.
+     */
+    private org.apache.tomcat.util.http.mapper.Mapper mapper = 
+        new org.apache.tomcat.util.http.mapper.Mapper();
+
+
+    /**
+     * The naming context listener for this web application.
+     */
+    private transient NamingContextListener namingContextListener = null;
+
+
+    /**
+     * The naming resources for this web application.
+     */
+    private NamingResources namingResources = null;
+
+
+    /**
+     * The message destinations for this web application.
+     */
+    private HashMap messageDestinations = new HashMap();
+
+
+    /**
+     * The MIME mappings for this web application, keyed by extension.
+     */
+    private HashMap mimeMappings = new HashMap();
+
+
+     /**
+      * Special case: error page for status 200.
+      */
+     private ErrorPage okErrorPage = null;
+
+
+    /**
+     * The context initialization parameters for this web application,
+     * keyed by name.
+     */
+    private HashMap parameters = new HashMap();
+
+
+    /**
+     * The request processing pause flag (while reloading occurs)
+     */
+    private boolean paused = false;
+
+
+    /**
+     * The public identifier of the DTD for the web application deployment
+     * descriptor version we are currently parsing.  This is used to support
+     * relaxed validation rules when processing version 2.2 web.xml files.
+     */
+    private String publicId = null;
+
+
+    /**
+     * The reloadable flag for this web application.
+     */
+    private boolean reloadable = false;
+
+
+    /**
+     * Unpack WAR property.
+     */
+    private boolean unpackWAR = true;
+
+
+    /**
+     * The DefaultContext override flag for this web application.
+     */
+    private boolean override = false;
+
+
+    /**
+     * The privileged flag for this web application.
+     */
+    private boolean privileged = false;
+
+
+    /**
+     * Should the next call to <code>addWelcomeFile()</code> cause replacement
+     * of any existing welcome files?  This will be set before processing the
+     * web application's deployment descriptor, so that application specified
+     * choices <strong>replace</strong>, rather than append to, those defined
+     * in the global descriptor.
+     */
+    private boolean replaceWelcomeFiles = false;
+
+
+    /**
+     * The security role mappings for this application, keyed by role
+     * name (as used within the application).
+     */
+    private HashMap roleMappings = new HashMap();
+
+
+    /**
+     * The security roles for this application, keyed by role name.
+     */
+    private String securityRoles[] = new String[0];
+
+
+    /**
+     * The servlet mappings for this web application, keyed by
+     * matching pattern.
+     */
+    private HashMap servletMappings = new HashMap();
+
+
+    /**
+     * The session timeout (in minutes) for this web application.
+     */
+    private int sessionTimeout = 30;
+
+    /**
+     * The notification sequence number.
+     */
+    private long sequenceNumber = 0;
+    
+    /**
+     * The status code error pages for this web application, keyed by
+     * HTTP status code (as an Integer).
+     */
+    private HashMap statusPages = new HashMap();
+
+
+    /**
+     * Set flag to true to cause the system.out and system.err to be redirected
+     * to the logger when executing a servlet.
+     */
+    private boolean swallowOutput = false;
+
+
+    /**
+     * The JSP tag libraries for this web application, keyed by URI
+     */
+    private HashMap taglibs = new HashMap();
+
+
+    /**
+     * Amount of ms that the container will wait for servlets to unload.
+     */
+    private long unloadDelay = 2000;
+
+
+    /**
+     * The watched resources for this application.
+     */
+    private String watchedResources[] = new String[0];
+
+
+    /**
+     * The welcome files for this application.
+     */
+    private String welcomeFiles[] = new String[0];
+
+
+    /**
+     * The set of classnames of LifecycleListeners that will be added
+     * to each newly created Wrapper by <code>createWrapper()</code>.
+     */
+    private String wrapperLifecycles[] = new String[0];
+
+
+    /**
+     * The set of classnames of ContainerListeners that will be added
+     * to each newly created Wrapper by <code>createWrapper()</code>.
+     */
+    private String wrapperListeners[] = new String[0];
+
+
+    /**
+     * The pathname to the work directory for this context (relative to
+     * the server's home if not absolute).
+     */
+    private String workDir = null;
+
+
+    /**
+     * Java class name of the Wrapper class implementation we use.
+     */
+    private String wrapperClassName = StandardWrapper.class.getName();
+    private Class wrapperClass = null;
+
+
+    /**
+     * JNDI use flag.
+     */
+    private boolean useNaming = true;
+
+
+    /**
+     * Filesystem based flag.
+     */
+    private boolean filesystemBased = false;
+
+
+    /**
+     * Name of the associated naming context.
+     */
+    private String namingContextName = null;
+
+
+    /**
+     * Caching allowed flag.
+     */
+    private boolean cachingAllowed = true;
+
+
+    /**
+     * Case sensitivity.
+     */
+    protected boolean caseSensitive = true;
+
+
+    /**
+     * Allow linking.
+     */
+    protected boolean allowLinking = false;
+
+
+    /**
+     * Cache max size in KB.
+     */
+    protected int cacheMaxSize = 10240; // 10 MB
+
+
+    /**
+     * Cache TTL in ms.
+     */
+    protected int cacheTTL = 5000;
+
+
+    private boolean lazy=true;
+
+    /**
+     * Non proxied resources.
+     */
+    private transient DirContext webappResources = null;
+
+    private long startupTime;
+    private long startTime;
+    private long tldScanTime;
+
+    /** 
+     * Name of the engine. If null, the domain is used.
+     */ 
+    private String engineName = null;
+    private String j2EEApplication="none";
+    private String j2EEServer="none";
+
+
+    /**
+     * Attribute value used to turn on/off XML validation
+     */
+     private boolean webXmlValidation = false;
+
+
+    /**
+     * Attribute value used to turn on/off XML namespace validation
+     */
+     private boolean webXmlNamespaceAware = false;
+
+    /**
+     * Attribute value used to turn on/off TLD processing
+     */
+    private boolean processTlds = true;
+
+    /**
+     * Attribute value used to turn on/off XML validation
+     */
+     private boolean tldValidation = false;
+
+
+    /**
+     * Attribute value used to turn on/off TLD XML namespace validation
+     */
+     private boolean tldNamespaceAware = false;
+
+
+    /**
+     * Should we save the configuration.
+     */
+    private boolean saveConfig = true;
+
+
+    // ----------------------------------------------------- Context Properties
+
+
+    public String getEncodedPath() {
+        return encodedPath;
+    }
+
+
+    public void setName( String name ) {
+        super.setName( name );
+        encodedPath = urlEncoder.encode(name);
+    }
+
+
+    /**
+     * Is caching allowed ?
+     */
+    public boolean isCachingAllowed() {
+        return cachingAllowed;
+    }
+
+
+    /**
+     * Set caching allowed flag.
+     */
+    public void setCachingAllowed(boolean cachingAllowed) {
+        this.cachingAllowed = cachingAllowed;
+    }
+
+
+    /**
+     * Set case sensitivity.
+     */
+    public void setCaseSensitive(boolean caseSensitive) {
+        this.caseSensitive = caseSensitive;
+    }
+
+
+    /**
+     * Is case sensitive ?
+     */
+    public boolean isCaseSensitive() {
+        return caseSensitive;
+    }
+
+
+    /**
+     * Set allow linking.
+     */
+    public void setAllowLinking(boolean allowLinking) {
+        this.allowLinking = allowLinking;
+    }
+
+
+    /**
+     * Is linking allowed.
+     */
+    public boolean isAllowLinking() {
+        return allowLinking;
+    }
+
+
+    /**
+     * Set cache TTL.
+     */
+    public void setCacheTTL(int cacheTTL) {
+        this.cacheTTL = cacheTTL;
+    }
+
+
+    /**
+     * Get cache TTL.
+     */
+    public int getCacheTTL() {
+        return cacheTTL;
+    }
+
+
+    /**
+     * Return the maximum size of the cache in KB.
+     */
+    public int getCacheMaxSize() {
+        return cacheMaxSize;
+    }
+
+
+    /**
+     * Set the maximum size of the cache in KB.
+     */
+    public void setCacheMaxSize(int cacheMaxSize) {
+        this.cacheMaxSize = cacheMaxSize;
+    }
+
+
+    /**
+     * Return the "follow standard delegation model" flag used to configure
+     * our ClassLoader.
+     */
+    public boolean getDelegate() {
+
+        return (this.delegate);
+
+    }
+
+
+    /**
+     * Set the "follow standard delegation model" flag used to configure
+     * our ClassLoader.
+     *
+     * @param delegate The new flag
+     */
+    public void setDelegate(boolean delegate) {
+
+        boolean oldDelegate = this.delegate;
+        this.delegate = delegate;
+        support.firePropertyChange("delegate", new Boolean(oldDelegate),
+                                   new Boolean(this.delegate));
+
+    }
+
+
+    /**
+     * Returns true if the internal naming support is used.
+     */
+    public boolean isUseNaming() {
+
+        return (useNaming);
+
+    }
+
+
+    /**
+     * Enables or disables naming.
+     */
+    public void setUseNaming(boolean useNaming) {
+        this.useNaming = useNaming;
+    }
+
+
+    /**
+     * Returns true if the resources associated with this context are
+     * filesystem based.
+     */
+    public boolean isFilesystemBased() {
+
+        return (filesystemBased);
+
+    }
+
+
+    /**
+     * Return the set of initialized application event listener objects,
+     * in the order they were specified in the web application deployment
+     * descriptor, for this application.
+     *
+     * @exception IllegalStateException if this method is called before
+     *  this application has started, or after it has been stopped
+     */
+    public Object[] getApplicationEventListeners() {
+        return (applicationEventListenersObjects);
+    }
+
+
+    /**
+     * Store the set of initialized application event listener objects,
+     * in the order they were specified in the web application deployment
+     * descriptor, for this application.
+     *
+     * @param listeners The set of instantiated listener objects.
+     */
+    public void setApplicationEventListeners(Object listeners[]) {
+        applicationEventListenersObjects = listeners;
+    }
+
+
+    /**
+     * Return the set of initialized application lifecycle listener objects,
+     * in the order they were specified in the web application deployment
+     * descriptor, for this application.
+     *
+     * @exception IllegalStateException if this method is called before
+     *  this application has started, or after it has been stopped
+     */
+    public Object[] getApplicationLifecycleListeners() {
+        return (applicationLifecycleListenersObjects);
+    }
+
+
+    /**
+     * Store the set of initialized application lifecycle listener objects,
+     * in the order they were specified in the web application deployment
+     * descriptor, for this application.
+     *
+     * @param listeners The set of instantiated listener objects.
+     */
+    public void setApplicationLifecycleListeners(Object listeners[]) {
+        applicationLifecycleListenersObjects = listeners;
+    }
+
+
+    /**
+     * Return the antiJARLocking flag for this Context.
+     */
+    public boolean getAntiJARLocking() {
+
+        return (this.antiJARLocking);
+
+    }
+
+
+    /**
+     * Return the antiResourceLocking flag for this Context.
+     */
+    public boolean getAntiResourceLocking() {
+
+        return (this.antiResourceLocking);
+
+    }
+
+
+    /**
+     * Set the antiJARLocking feature for this Context.
+     *
+     * @param antiJARLocking The new flag value
+     */
+    public void setAntiJARLocking(boolean antiJARLocking) {
+
+        boolean oldAntiJARLocking = this.antiJARLocking;
+        this.antiJARLocking = antiJARLocking;
+        support.firePropertyChange("antiJARLocking",
+                                   new Boolean(oldAntiJARLocking),
+                                   new Boolean(this.antiJARLocking));
+
+    }
+
+
+    /**
+     * Set the antiResourceLocking feature for this Context.
+     *
+     * @param antiResourceLocking The new flag value
+     */
+    public void setAntiResourceLocking(boolean antiResourceLocking) {
+
+        boolean oldAntiResourceLocking = this.antiResourceLocking;
+        this.antiResourceLocking = antiResourceLocking;
+        support.firePropertyChange("antiResourceLocking",
+                                   new Boolean(oldAntiResourceLocking),
+                                   new Boolean(this.antiResourceLocking));
+
+    }
+
+
+    /**
+     * Return the application available flag for this Context.
+     */
+    public boolean getAvailable() {
+
+        return (this.available);
+
+    }
+
+
+    /**
+     * Set the application available flag for this Context.
+     *
+     * @param available The new application available flag
+     */
+    public void setAvailable(boolean available) {
+
+        boolean oldAvailable = this.available;
+        this.available = available;
+        support.firePropertyChange("available",
+                                   new Boolean(oldAvailable),
+                                   new Boolean(this.available));
+
+    }
+
+
+    /**
+     * Return the Locale to character set mapper for this Context.
+     */
+    public CharsetMapper getCharsetMapper() {
+
+        // Create a mapper the first time it is requested
+        if (this.charsetMapper == null) {
+            try {
+                Class clazz = Class.forName(charsetMapperClass);
+                this.charsetMapper =
+                  (CharsetMapper) clazz.newInstance();
+            } catch (Throwable t) {
+                this.charsetMapper = new CharsetMapper();
+            }
+        }
+
+        return (this.charsetMapper);
+
+    }
+
+
+    /**
+     * Set the Locale to character set mapper for this Context.
+     *
+     * @param mapper The new mapper
+     */
+    public void setCharsetMapper(CharsetMapper mapper) {
+
+        CharsetMapper oldCharsetMapper = this.charsetMapper;
+        this.charsetMapper = mapper;
+        if( mapper != null )
+            this.charsetMapperClass= mapper.getClass().getName();
+        support.firePropertyChange("charsetMapper", oldCharsetMapper,
+                                   this.charsetMapper);
+
+    }
+
+    /**
+     * Return the path to a file to save this Context information.
+     */
+    public String getConfigFile() {
+
+        return (this.configFile);
+
+    }
+
+
+    /**
+     * Set the path to a file to save this Context information.
+     *
+     * @param configFile The path to a file to save this Context information.
+     */
+    public void setConfigFile(String configFile) {
+
+        this.configFile = configFile;
+    }
+
+
+    /**
+     * Return the "correctly configured" flag for this Context.
+     */
+    public boolean getConfigured() {
+
+        return (this.configured);
+
+    }
+
+
+    /**
+     * Set the "correctly configured" flag for this Context.  This can be
+     * set to false by startup listeners that detect a fatal configuration
+     * error to avoid the application from being made available.
+     *
+     * @param configured The new correctly configured flag
+     */
+    public void setConfigured(boolean configured) {
+
+        boolean oldConfigured = this.configured;
+        this.configured = configured;
+        support.firePropertyChange("configured",
+                                   new Boolean(oldConfigured),
+                                   new Boolean(this.configured));
+
+    }
+
+
+    /**
+     * Return the "use cookies for session ids" flag.
+     */
+    public boolean getCookies() {
+
+        return (this.cookies);
+
+    }
+
+
+    /**
+     * Set the "use cookies for session ids" flag.
+     *
+     * @param cookies The new flag
+     */
+    public void setCookies(boolean cookies) {
+
+        boolean oldCookies = this.cookies;
+        this.cookies = cookies;
+        support.firePropertyChange("cookies",
+                                   new Boolean(oldCookies),
+                                   new Boolean(this.cookies));
+
+    }
+
+
+    /**
+     * Return the "allow crossing servlet contexts" flag.
+     */
+    public boolean getCrossContext() {
+
+        return (this.crossContext);
+
+    }
+
+
+    /**
+     * Set the "allow crossing servlet contexts" flag.
+     *
+     * @param crossContext The new cross contexts flag
+     */
+    public void setCrossContext(boolean crossContext) {
+
+        boolean oldCrossContext = this.crossContext;
+        this.crossContext = crossContext;
+        support.firePropertyChange("crossContext",
+                                   new Boolean(oldCrossContext),
+                                   new Boolean(this.crossContext));
+
+    }
+
+    public String getDefaultContextXml() {
+        return defaultContextXml;
+    }
+
+    /** 
+     * Set the location of the default context xml that will be used.
+     * If not absolute, it'll be made relative to the engine's base dir
+     * ( which defaults to catalina.base system property ).
+     *
+     * @param defaultContextXml The default web xml 
+     */
+    public void setDefaultContextXml(String defaultContextXml) {
+        this.defaultContextXml = defaultContextXml;
+    }
+
+    public String getDefaultWebXml() {
+        return defaultWebXml;
+    }
+
+    /** 
+     * Set the location of the default web xml that will be used.
+     * If not absolute, it'll be made relative to the engine's base dir
+     * ( which defaults to catalina.base system property ).
+     *
+     * @param defaultWebXml The default web xml 
+     */
+    public void setDefaultWebXml(String defaultWebXml) {
+        this.defaultWebXml = defaultWebXml;
+    }
+
+    /**
+     * Gets the time (in milliseconds) it took to start this context.
+     *
+     * @return Time (in milliseconds) it took to start this context.
+     */
+    public long getStartupTime() {
+        return startupTime;
+    }
+
+    public void setStartupTime(long startupTime) {
+        this.startupTime = startupTime;
+    }
+
+    public long getTldScanTime() {
+        return tldScanTime;
+    }
+
+    public void setTldScanTime(long tldScanTime) {
+        this.tldScanTime = tldScanTime;
+    }
+
+    /**
+     * Return the display name of this web application.
+     */
+    public String getDisplayName() {
+
+        return (this.displayName);
+
+    }
+
+
+    /**
+     * Return the alternate Deployment Descriptor name.
+     */
+    public String getAltDDName(){
+        return altDDName;
+    }
+
+
+    /**
+     * Set an alternate Deployment Descriptor name.
+     */
+    public void setAltDDName(String altDDName) {
+        this.altDDName = altDDName;
+        if (context != null) {
+            context.setAttribute(Globals.ALT_DD_ATTR,altDDName);
+        }
+    }
+
+
+    /**
+     * Return the compiler classpath.
+     */
+    public String getCompilerClasspath(){
+        return compilerClasspath;
+    }
+
+
+    /**
+     * Set the compiler classpath.
+     */
+    public void setCompilerClasspath(String compilerClasspath) {
+        this.compilerClasspath = compilerClasspath;
+    }
+
+
+    /**
+     * Set the display name of this web application.
+     *
+     * @param displayName The new display name
+     */
+    public void setDisplayName(String displayName) {
+
+        String oldDisplayName = this.displayName;
+        this.displayName = displayName;
+        support.firePropertyChange("displayName", oldDisplayName,
+                                   this.displayName);
+    }
+
+
+    /**
+     * Return the distributable flag for this web application.
+     */
+    public boolean getDistributable() {
+
+        return (this.distributable);
+
+    }
+
+    /**
+     * Set the distributable flag for this web application.
+     *
+     * @param distributable The new distributable flag
+     */
+    public void setDistributable(boolean distributable) {
+        boolean oldDistributable = this.distributable;
+        this.distributable = distributable;
+        support.firePropertyChange("distributable",
+                                   new Boolean(oldDistributable),
+                                   new Boolean(this.distributable));
+
+        // Bugzilla 32866
+        if(getManager() != null) {
+            if(log.isDebugEnabled()) {
+                log.debug("Propagating distributable=" + distributable
+                          + " to manager");
+            }
+            getManager().setDistributable(distributable);
+        }
+    }
+
+
+    /**
+     * Return the document root for this Context.  This can be an absolute
+     * pathname, a relative pathname, or a URL.
+     */
+    public String getDocBase() {
+
+        return (this.docBase);
+
+    }
+
+
+    /**
+     * Set the document root for this Context.  This can be an absolute
+     * pathname, a relative pathname, or a URL.
+     *
+     * @param docBase The new document root
+     */
+    public void setDocBase(String docBase) {
+
+        this.docBase = docBase;
+
+    }
+
+    /**
+     * Return the original document root for this Context.  This can be an absolute
+     * pathname, a relative pathname, or a URL.
+     * Is only set as deployment has change docRoot!
+     */
+    public String getOriginalDocBase() {
+
+        return (this.originalDocBase);
+
+    }
+
+    /**
+     * Set the original document root for this Context.  This can be an absolute
+     * pathname, a relative pathname, or a URL.
+     *
+     * @param docBase The orginal document root
+     */
+    public void setOriginalDocBase(String docBase) {
+
+        this.originalDocBase = docBase;
+    }
+    
+    // experimental
+    public boolean isLazy() {
+        return lazy;
+    }
+
+    public void setLazy(boolean lazy) {
+        this.lazy = lazy;
+    }
+
+
+    /**
+     * Return descriptive information about this Container implementation and
+     * the corresponding version number, in the format
+     * <code>&lt;description&gt;/&lt;version&gt;</code>.
+     */
+    public String getInfo() {
+
+        return (info);
+
+    }
+
+    public String getEngineName() {
+        if( engineName != null ) return engineName;
+        return domain;
+    }
+
+    public void setEngineName(String engineName) {
+        this.engineName = engineName;
+    }
+
+    public String getJ2EEApplication() {
+        return j2EEApplication;
+    }
+
+    public void setJ2EEApplication(String j2EEApplication) {
+        this.j2EEApplication = j2EEApplication;
+    }
+
+    public String getJ2EEServer() {
+        return j2EEServer;
+    }
+
+    public void setJ2EEServer(String j2EEServer) {
+        this.j2EEServer = j2EEServer;
+    }
+
+
+    /**
+     * Set the Loader with which this Context is associated.
+     *
+     * @param loader The newly associated loader
+     */
+    public synchronized void setLoader(Loader loader) {
+
+        super.setLoader(loader);
+
+    }
+
+
+    /**
+     * Return the login configuration descriptor for this web application.
+     */
+    public LoginConfig getLoginConfig() {
+
+        return (this.loginConfig);
+
+    }
+
+
+    /**
+     * Set the login configuration descriptor for this web application.
+     *
+     * @param config The new login configuration
+     */
+    public void setLoginConfig(LoginConfig config) {
+
+        // Validate the incoming property value
+        if (config == null)
+            throw new IllegalArgumentException
+                (sm.getString("standardContext.loginConfig.required"));
+        String loginPage = config.getLoginPage();
+        if ((loginPage != null) && !loginPage.startsWith("/")) {
+            if (isServlet22()) {
+                if(log.isDebugEnabled())
+                    log.debug(sm.getString("standardContext.loginConfig.loginWarning",
+                                 loginPage));
+                config.setLoginPage("/" + loginPage);
+            } else {
+                throw new IllegalArgumentException
+                    (sm.getString("standardContext.loginConfig.loginPage",
+                                  loginPage));
+            }
+        }
+        String errorPage = config.getErrorPage();
+        if ((errorPage != null) && !errorPage.startsWith("/")) {
+            if (isServlet22()) {
+                if(log.isDebugEnabled())
+                    log.debug(sm.getString("standardContext.loginConfig.errorWarning",
+                                 errorPage));
+                config.setErrorPage("/" + errorPage);
+            } else {
+                throw new IllegalArgumentException
+                    (sm.getString("standardContext.loginConfig.errorPage",
+                                  errorPage));
+            }
+        }
+
+        // Process the property setting change
+        LoginConfig oldLoginConfig = this.loginConfig;
+        this.loginConfig = config;
+        support.firePropertyChange("loginConfig",
+                                   oldLoginConfig, this.loginConfig);
+
+    }
+
+
+    /**
+     * Get the mapper associated with the context.
+     */
+    public org.apache.tomcat.util.http.mapper.Mapper getMapper() {
+        return (mapper);
+    }
+
+
+    /**
+     * Return the naming resources associated with this web application.
+     */
+    public NamingResources getNamingResources() {
+
+        if (namingResources == null) {
+            setNamingResources(new NamingResources());
+        }
+        return (namingResources);
+
+    }
+
+
+    /**
+     * Set the naming resources for this web application.
+     *
+     * @param namingResources The new naming resources
+     */
+    public void setNamingResources(NamingResources namingResources) {
+
+        // Process the property setting change
+        NamingResources oldNamingResources = this.namingResources;
+        this.namingResources = namingResources;
+        namingResources.setContainer(this);
+        support.firePropertyChange("namingResources",
+                                   oldNamingResources, this.namingResources);
+
+    }
+
+
+    /**
+     * Return the parent class loader (if any) for this web application.
+     * This call is meaningful only <strong>after</strong> a Loader has
+     * been configured.
+     */
+    public ClassLoader getParentClassLoader() {
+        if (parentClassLoader != null)
+            return (parentClassLoader);
+        if (getPrivileged()) {
+            return this.getClass().getClassLoader();
+        } else if (parent != null) {
+            return (parent.getParentClassLoader());
+        }
+        return (ClassLoader.getSystemClassLoader());
+    }
+
+
+    /**
+     * Return the context path for this Context.
+     */
+    public String getPath() {
+
+        return (getName());
+
+    }
+
+    
+    /**
+     * Set the context path for this Context.
+     * <p>
+     * <b>IMPLEMENTATION NOTE</b>:  The context path is used as the "name" of
+     * a Context, because it must be unique.
+     *
+     * @param path The new context path
+     */
+    public void setPath(String path) {
+        // XXX Use host in name
+        setName(RequestUtil.URLDecode(path));
+
+    }
+
+
+    /**
+     * Return the public identifier of the deployment descriptor DTD that is
+     * currently being parsed.
+     */
+    public String getPublicId() {
+
+        return (this.publicId);
+
+    }
+
+
+    /**
+     * Set the public identifier of the deployment descriptor DTD that is
+     * currently being parsed.
+     *
+     * @param publicId The public identifier
+     */
+    public void setPublicId(String publicId) {
+
+        if (log.isDebugEnabled())
+            log.debug("Setting deployment descriptor public ID to '" +
+                publicId + "'");
+
+        String oldPublicId = this.publicId;
+        this.publicId = publicId;
+        support.firePropertyChange("publicId", oldPublicId, publicId);
+
+    }
+
+
+    /**
+     * Return the reloadable flag for this web application.
+     */
+    public boolean getReloadable() {
+
+        return (this.reloadable);
+
+    }
+
+
+    /**
+     * Return the DefaultContext override flag for this web application.
+     */
+    public boolean getOverride() {
+
+        return (this.override);
+
+    }
+
+
+    /**
+     * Return the privileged flag for this web application.
+     */
+    public boolean getPrivileged() {
+
+        return (this.privileged);
+
+    }
+
+
+    /**
+     * Set the privileged flag for this web application.
+     *
+     * @param privileged The new privileged flag
+     */
+    public void setPrivileged(boolean privileged) {
+
+        boolean oldPrivileged = this.privileged;
+        this.privileged = privileged;
+        support.firePropertyChange("privileged",
+                                   new Boolean(oldPrivileged),
+                                   new Boolean(this.privileged));
+
+    }
+
+
+    /**
+     * Set the reloadable flag for this web application.
+     *
+     * @param reloadable The new reloadable flag
+     */
+    public void setReloadable(boolean reloadable) {
+
+        boolean oldReloadable = this.reloadable;
+        this.reloadable = reloadable;
+        support.firePropertyChange("reloadable",
+                                   new Boolean(oldReloadable),
+                                   new Boolean(this.reloadable));
+
+    }
+
+
+    /**
+     * Set the DefaultContext override flag for this web application.
+     *
+     * @param override The new override flag
+     */
+    public void setOverride(boolean override) {
+
+        boolean oldOverride = this.override;
+        this.override = override;
+        support.firePropertyChange("override",
+                                   new Boolean(oldOverride),
+                                   new Boolean(this.override));
+
+    }
+
+
+    /**
+     * Return the "replace welcome files" property.
+     */
+    public boolean isReplaceWelcomeFiles() {
+
+        return (this.replaceWelcomeFiles);
+
+    }
+
+
+    /**
+     * Set the "replace welcome files" property.
+     *
+     * @param replaceWelcomeFiles The new property value
+     */
+    public void setReplaceWelcomeFiles(boolean replaceWelcomeFiles) {
+
+        boolean oldReplaceWelcomeFiles = this.replaceWelcomeFiles;
+        this.replaceWelcomeFiles = replaceWelcomeFiles;
+        support.firePropertyChange("replaceWelcomeFiles",
+                                   new Boolean(oldReplaceWelcomeFiles),
+                                   new Boolean(this.replaceWelcomeFiles));
+
+    }
+
+
+    /**
+     * Return the servlet context for which this Context is a facade.
+     */
+    public ServletContext getServletContext() {
+
+        if (context == null) {
+            context = new ApplicationContext(getBasePath(), this);
+            if (altDDName != null)
+                context.setAttribute(Globals.ALT_DD_ATTR,altDDName);
+        }
+        return (context.getFacade());
+
+    }
+
+
+    /**
+     * Return the default session timeout (in minutes) for this
+     * web application.
+     */
+    public int getSessionTimeout() {
+
+        return (this.sessionTimeout);
+
+    }
+
+
+    /**
+     * Set the default session timeout (in minutes) for this
+     * web application.
+     *
+     * @param timeout The new default session timeout
+     */
+    public void setSessionTimeout(int timeout) {
+
+        int oldSessionTimeout = this.sessionTimeout;
+        /*
+         * SRV.13.4 ("Deployment Descriptor"):
+         * If the timeout is 0 or less, the container ensures the default
+         * behaviour of sessions is never to time out.
+         */
+        this.sessionTimeout = (timeout == 0) ? -1 : timeout;
+        support.firePropertyChange("sessionTimeout",
+                                   new Integer(oldSessionTimeout),
+                                   new Integer(this.sessionTimeout));
+
+    }
+
+
+    /**
+     * Return the value of the swallowOutput flag.
+     */
+    public boolean getSwallowOutput() {
+
+        return (this.swallowOutput);
+
+    }
+
+
+    /**
+     * Set the value of the swallowOutput flag. If set to true, the system.out
+     * and system.err will be redirected to the logger during a servlet
+     * execution.
+     *
+     * @param swallowOutput The new value
+     */
+    public void setSwallowOutput(boolean swallowOutput) {
+
+        boolean oldSwallowOutput = this.swallowOutput;
+        this.swallowOutput = swallowOutput;
+        support.firePropertyChange("swallowOutput",
+                                   new Boolean(oldSwallowOutput),
+                                   new Boolean(this.swallowOutput));
+
+    }
+
+
+    /**
+     * Return the value of the unloadDelay flag.
+     */
+    public long getUnloadDelay() {
+
+        return (this.unloadDelay);
+
+    }
+
+
+    /**
+     * Set the value of the unloadDelay flag, which represents the amount
+     * of ms that the container will wait when unloading servlets.
+     * Setting this to a small value may cause more requests to fail 
+     * to complete when stopping a web application.
+     *
+     * @param unloadDelay The new value
+     */
+    public void setUnloadDelay(long unloadDelay) {
+
+        long oldUnloadDelay = this.unloadDelay;
+        this.unloadDelay = unloadDelay;
+        support.firePropertyChange("unloadDelay",
+                                   new Long(oldUnloadDelay),
+                                   new Long(this.unloadDelay));
+
+    }
+
+
+    /**
+     * Unpack WAR flag accessor.
+     */
+    public boolean getUnpackWAR() {
+
+        return (unpackWAR);
+
+    }
+
+
+    /**
+     * Unpack WAR flag mutator.
+     */
+    public void setUnpackWAR(boolean unpackWAR) {
+
+        this.unpackWAR = unpackWAR;
+
+    }
+
+    /**
+     * Return the Java class name of the Wrapper implementation used
+     * for servlets registered in this Context.
+     */
+    public String getWrapperClass() {
+
+        return (this.wrapperClassName);
+
+    }
+
+
+    /**
+     * Set the Java class name of the Wrapper implementation used
+     * for servlets registered in this Context.
+     *
+     * @param wrapperClassName The new wrapper class name
+     *
+     * @throws IllegalArgumentException if the specified wrapper class
+     * cannot be found or is not a subclass of StandardWrapper
+     */
+    public void setWrapperClass(String wrapperClassName) {
+
+        this.wrapperClassName = wrapperClassName;
+
+        try {
+            wrapperClass = Class.forName(wrapperClassName);         
+            if (!StandardWrapper.class.isAssignableFrom(wrapperClass)) {
+                throw new IllegalArgumentException(
+                    sm.getString("standardContext.invalidWrapperClass",
+                                 wrapperClassName));
+            }
+        } catch (ClassNotFoundException cnfe) {
+            throw new IllegalArgumentException(cnfe.getMessage());
+        }
+    }
+
+
+    /**
+     * Set the resources DirContext object with which this Container is
+     * associated.
+     *
+     * @param resources The newly associated DirContext
+     */
+    public synchronized void setResources(DirContext resources) {
+
+        if (started) {
+            throw new IllegalStateException
+                (sm.getString("standardContext.resources.started"));
+        }
+
+        DirContext oldResources = this.webappResources;
+        if (oldResources == resources)
+            return;
+
+        if (resources instanceof BaseDirContext) {
+            ((BaseDirContext) resources).setCached(isCachingAllowed());
+            ((BaseDirContext) resources).setCacheTTL(getCacheTTL());
+            ((BaseDirContext) resources).setCacheMaxSize(getCacheMaxSize());
+        }
+        if (resources instanceof FileDirContext) {
+            filesystemBased = true;
+            ((FileDirContext) resources).setCaseSensitive(isCaseSensitive());
+            ((FileDirContext) resources).setAllowLinking(isAllowLinking());
+        }
+        this.webappResources = resources;
+
+        // The proxied resources will be refreshed on start
+        this.resources = null;
+
+        support.firePropertyChange("resources", oldResources,
+                                   this.webappResources);
+
+    }
+
+
+    // ------------------------------------------------------ Public Properties
+
+
+    /**
+     * Return the Locale to character set mapper class for this Context.
+     */
+    public String getCharsetMapperClass() {
+
+        return (this.charsetMapperClass);
+
+    }
+
+
+    /**
+     * Set the Locale to character set mapper class for this Context.
+     *
+     * @param mapper The new mapper class
+     */
+    public void setCharsetMapperClass(String mapper) {
+
+        String oldCharsetMapperClass = this.charsetMapperClass;
+        this.charsetMapperClass = mapper;
+        support.firePropertyChange("charsetMapperClass",
+                                   oldCharsetMapperClass,
+                                   this.charsetMapperClass);
+
+    }
+
+
+    /** Get the absolute path to the work dir.
+     *  To avoid duplication.
+     * 
+     * @return The work path
+     */ 
+    public String getWorkPath() {
+        File workDir = new File(getWorkDir());
+        if (!workDir.isAbsolute()) {
+            File catalinaHome = engineBase();
+            String catalinaHomePath = null;
+            try {
+                catalinaHomePath = catalinaHome.getCanonicalPath();
+                workDir = new File(catalinaHomePath,
+                        getWorkDir());
+            } catch (IOException e) {
+                log.warn("Exception obtaining work path for " + getPath());
+            }
+        }
+        return workDir.getAbsolutePath();
+    }
+    
+    /**
+     * Return the work directory for this Context.
+     */
+    public String getWorkDir() {
+
+        return (this.workDir);
+
+    }
+
+
+    /**
+     * Set the work directory for this Context.
+     *
+     * @param workDir The new work directory
+     */
+    public void setWorkDir(String workDir) {
+
+        this.workDir = workDir;
+
+        if (started) {
+            postWorkDirectory();
+        }
+    }
+
+
+    /**
+     * Save config ?
+     */
+    public boolean isSaveConfig() {
+        return saveConfig;
+    }
+
+
+    /**
+     * Set save config flag.
+     */
+    public void setSaveConfig(boolean saveConfig) {
+        this.saveConfig = saveConfig;
+    }
+
+
+    // -------------------------------------------------------- Context Methods
+
+
+    /**
+     * Add a new Listener class name to the set of Listeners
+     * configured for this application.
+     *
+     * @param listener Java class name of a listener class
+     */
+    public void addApplicationListener(String listener) {
+
+        synchronized (applicationListeners) {
+            String results[] =new String[applicationListeners.length + 1];
+            for (int i = 0; i < applicationListeners.length; i++) {
+                if (listener.equals(applicationListeners[i]))
+                    return;
+                results[i] = applicationListeners[i];
+            }
+            results[applicationListeners.length] = listener;
+            applicationListeners = results;
+        }
+        fireContainerEvent("addApplicationListener", listener);
+
+        // FIXME - add instance if already started?
+
+    }
+
+
+    /**
+     * Add a new application parameter for this application.
+     *
+     * @param parameter The new application parameter
+     */
+    public void addApplicationParameter(ApplicationParameter parameter) {
+
+        synchronized (applicationParameters) {
+            String newName = parameter.getName();
+            for (int i = 0; i < applicationParameters.length; i++) {
+                if (newName.equals(applicationParameters[i].getName()) &&
+                    !applicationParameters[i].getOverride())
+                    return;
+            }
+            ApplicationParameter results[] =
+                new ApplicationParameter[applicationParameters.length + 1];
+            System.arraycopy(applicationParameters, 0, results, 0,
+                             applicationParameters.length);
+            results[applicationParameters.length] = parameter;
+            applicationParameters = results;
+        }
+        fireContainerEvent("addApplicationParameter", parameter);
+
+    }
+
+
+    /**
+     * Add a child Container, only if the proposed child is an implementation
+     * of Wrapper.
+     *
+     * @param child Child container to be added
+     *
+     * @exception IllegalArgumentException if the proposed container is
+     *  not an implementation of Wrapper
+     */
+    public void addChild(Container child) {
+
+        // Global JspServlet
+        Wrapper oldJspServlet = null;
+
+        if (!(child instanceof Wrapper)) {
+            throw new IllegalArgumentException
+                (sm.getString("standardContext.notWrapper"));
+        }
+
+        Wrapper wrapper = (Wrapper) child;
+        boolean isJspServlet = "jsp".equals(child.getName());
+
+        // Allow webapp to override JspServlet inherited from global web.xml.
+        if (isJspServlet) {
+            oldJspServlet = (Wrapper) findChild("jsp");
+            if (oldJspServlet != null) {
+                removeChild(oldJspServlet);
+            }
+        }
+
+        String jspFile = wrapper.getJspFile();
+        if ((jspFile != null) && !jspFile.startsWith("/")) {
+            if (isServlet22()) {
+                if(log.isDebugEnabled())
+                    log.debug(sm.getString("standardContext.wrapper.warning", 
+                                       jspFile));
+                wrapper.setJspFile("/" + jspFile);
+            } else {
+                throw new IllegalArgumentException
+                    (sm.getString("standardContext.wrapper.error", jspFile));
+            }
+        }
+
+        super.addChild(child);
+
+        if (isJspServlet && oldJspServlet != null) {
+            /*
+             * The webapp-specific JspServlet inherits all the mappings
+             * specified in the global web.xml, and may add additional ones.
+             */
+            String[] jspMappings = oldJspServlet.findMappings();
+            for (int i=0; jspMappings!=null && i<jspMappings.length; i++) {
+                addServletMapping(jspMappings[i], child.getName());
+            }
+        }
+    }
+
+
+    /**
+     * Add a security constraint to the set for this web application.
+     */
+    public void addConstraint(SecurityConstraint constraint) {
+
+        // Validate the proposed constraint
+        SecurityCollection collections[] = constraint.findCollections();
+        for (int i = 0; i < collections.length; i++) {
+            String patterns[] = collections[i].findPatterns();
+            for (int j = 0; j < patterns.length; j++) {
+                patterns[j] = adjustURLPattern(patterns[j]);
+                if (!validateURLPattern(patterns[j]))
+                    throw new IllegalArgumentException
+                        (sm.getString
+                         ("standardContext.securityConstraint.pattern",
+                          patterns[j]));
+            }
+        }
+
+        // Add this constraint to the set for our web application
+        synchronized (constraints) {
+            SecurityConstraint results[] =
+                new SecurityConstraint[constraints.length + 1];
+            for (int i = 0; i < constraints.length; i++)
+                results[i] = constraints[i];
+            results[constraints.length] = constraint;
+            constraints = results;
+        }
+
+    }
+
+
+
+    /**
+     * Add an error page for the specified error or Java exception.
+     *
+     * @param errorPage The error page definition to be added
+     */
+    public void addErrorPage(ErrorPage errorPage) {
+        // Validate the input parameters
+        if (errorPage == null)
+            throw new IllegalArgumentException
+                (sm.getString("standardContext.errorPage.required"));
+        String location = errorPage.getLocation();
+        if ((location != null) && !location.startsWith("/")) {
+            if (isServlet22()) {
+                if(log.isDebugEnabled())
+                    log.debug(sm.getString("standardContext.errorPage.warning",
+                                 location));
+                errorPage.setLocation("/" + location);
+            } else {
+                throw new IllegalArgumentException
+                    (sm.getString("standardContext.errorPage.error",
+                                  location));
+            }
+        }
+
+        // Add the specified error page to our internal collections
+        String exceptionType = errorPage.getExceptionType();
+        if (exceptionType != null) {
+            synchronized (exceptionPages) {
+                exceptionPages.put(exceptionType, errorPage);
+            }
+        } else {
+            synchronized (statusPages) {
+                if (errorPage.getErrorCode() == 200) {
+                    this.okErrorPage = errorPage;
+                }
+                statusPages.put(new Integer(errorPage.getErrorCode()),
+                                errorPage);
+            }
+        }
+        fireContainerEvent("addErrorPage", errorPage);
+
+    }
+
+
+    /**
+     * Add a filter definition to this Context.
+     *
+     * @param filterDef The filter definition to be added
+     */
+    public void addFilterDef(FilterDef filterDef) {
+
+        synchronized (filterDefs) {
+            filterDefs.put(filterDef.getFilterName(), filterDef);
+        }
+        fireContainerEvent("addFilterDef", filterDef);
+
+    }
+
+
+    /**
+     * Add a filter mapping to this Context.
+     *
+     * @param filterMap The filter mapping to be added
+     *
+     * @exception IllegalArgumentException if the specified filter name
+     *  does not match an existing filter definition, or the filter mapping
+     *  is malformed
+     */
+    public void addFilterMap(FilterMap filterMap) {
+
+        // Validate the proposed filter mapping
+        String filterName = filterMap.getFilterName();
+        String servletName = filterMap.getServletName();
+        String urlPattern = filterMap.getURLPattern();
+        if (findFilterDef(filterName) == null)
+            throw new IllegalArgumentException
+                (sm.getString("standardContext.filterMap.name", filterName));
+        if ((servletName == null) && (urlPattern == null))
+            throw new IllegalArgumentException
+                (sm.getString("standardContext.filterMap.either"));
+        if ((servletName != null) && (urlPattern != null))
+            throw new IllegalArgumentException
+                (sm.getString("standardContext.filterMap.either"));
+        // Because filter-pattern is new in 2.3, no need to adjust
+        // for 2.2 backwards compatibility
+        if ((urlPattern != null) && !validateURLPattern(urlPattern))
+            throw new IllegalArgumentException
+                (sm.getString("standardContext.filterMap.pattern",
+                              urlPattern));
+
+        // Add this filter mapping to our registered set
+        synchronized (filterMaps) {
+            FilterMap results[] =new FilterMap[filterMaps.length + 1];
+            System.arraycopy(filterMaps, 0, results, 0, filterMaps.length);
+            results[filterMaps.length] = filterMap;
+            filterMaps = results;
+        }
+        fireContainerEvent("addFilterMap", filterMap);
+
+    }
+
+
+    /**
+     * Add the classname of an InstanceListener to be added to each
+     * Wrapper appended to this Context.
+     *
+     * @param listener Java class name of an InstanceListener class
+     */
+    public void addInstanceListener(String listener) {
+
+        synchronized (instanceListeners) {
+            String results[] =new String[instanceListeners.length + 1];
+            for (int i = 0; i < instanceListeners.length; i++)
+                results[i] = instanceListeners[i];
+            results[instanceListeners.length] = listener;
+            instanceListeners = results;
+        }
+        fireContainerEvent("addInstanceListener", listener);
+
+    }
+
+    /**
+     * Add the given URL pattern as a jsp-property-group.  This maps
+     * resources that match the given pattern so they will be passed
+     * to the JSP container.  Though there are other elements in the
+     * property group, we only care about the URL pattern here.  The
+     * JSP container will parse the rest.
+     *
+     * @param pattern URL pattern to be mapped
+     */
+    public void addJspMapping(String pattern) {
+        String servletName = findServletMapping("*.jsp");
+        if (servletName == null) {
+            servletName = "jsp";
+        }
+
+        if( findChild(servletName) != null) {
+            addServletMapping(pattern, servletName, true);
+        } else {
+            if(log.isDebugEnabled())
+                log.debug("Skiping " + pattern + " , no servlet " + servletName);
+        }
+    }
+
+
+    /**
+     * Add a Locale Encoding Mapping (see Sec 5.4 of Servlet spec 2.4)
+     *
+     * @param locale locale to map an encoding for
+     * @param encoding encoding to be used for a give locale
+     */
+    public void addLocaleEncodingMappingParameter(String locale, String encoding){
+        getCharsetMapper().addCharsetMappingFromDeploymentDescriptor(locale, encoding);
+    }
+
+
+    /**
+     * Add a message destination for this web application.
+     *
+     * @param md New message destination
+     */
+    public void addMessageDestination(MessageDestination md) {
+
+        synchronized (messageDestinations) {
+            messageDestinations.put(md.getName(), md);
+        }
+        fireContainerEvent("addMessageDestination", md.getName());
+
+    }
+
+
+    /**
+     * Add a message destination reference for this web application.
+     *
+     * @param mdr New message destination reference
+     */
+    public void addMessageDestinationRef
+        (MessageDestinationRef mdr) {
+
+        namingResources.addMessageDestinationRef(mdr);
+        fireContainerEvent("addMessageDestinationRef", mdr.getName());
+
+    }
+
+
+    /**
+     * Add a new MIME mapping, replacing any existing mapping for
+     * the specified extension.
+     *
+     * @param extension Filename extension being mapped
+     * @param mimeType Corresponding MIME type
+     */
+    public void addMimeMapping(String extension, String mimeType) {
+
+        synchronized (mimeMappings) {
+            mimeMappings.put(extension, mimeType);
+        }
+        fireContainerEvent("addMimeMapping", extension);
+
+    }
+
+
+    /**
+     * Add a new context initialization parameter.
+     *
+     * @param name Name of the new parameter
+     * @param value Value of the new  parameter
+     *
+     * @exception IllegalArgumentException if the name or value is missing,
+     *  or if this context initialization parameter has already been
+     *  registered
+     */
+    public void addParameter(String name, String value) {
+        // Validate the proposed context initialization parameter
+        if ((name == null) || (value == null))
+            throw new IllegalArgumentException
+                (sm.getString("standardContext.parameter.required"));
+        if (parameters.get(name) != null)
+            throw new IllegalArgumentException
+                (sm.getString("standardContext.parameter.duplicate", name));
+
+        // Add this parameter to our defined set
+        synchronized (parameters) {
+            parameters.put(name, value);
+        }
+        fireContainerEvent("addParameter", name);
+
+    }
+
+
+    /**
+     * Add a security role reference for this web application.
+     *
+     * @param role Security role used in the application
+     * @param link Actual security role to check for
+     */
+    public void addRoleMapping(String role, String link) {
+
+        synchronized (roleMappings) {
+            roleMappings.put(role, link);
+        }
+        fireContainerEvent("addRoleMapping", role);
+
+    }
+
+
+    /**
+     * Add a new security role for this web application.
+     *
+     * @param role New security role
+     */
+    public void addSecurityRole(String role) {
+
+        synchronized (securityRoles) {
+            String results[] =new String[securityRoles.length + 1];
+            for (int i = 0; i < securityRoles.length; i++)
+                results[i] = securityRoles[i];
+            results[securityRoles.length] = role;
+            securityRoles = results;
+        }
+        fireContainerEvent("addSecurityRole", role);
+
+    }
+
+
+    /**
+     * Add a new servlet mapping, replacing any existing mapping for
+     * the specified pattern.
+     *
+     * @param pattern URL pattern to be mapped
+     * @param name Name of the corresponding servlet to execute
+     *
+     * @exception IllegalArgumentException if the specified servlet name
+     *  is not known to this Context
+     */
+    public void addServletMapping(String pattern, String name) {
+        addServletMapping(pattern, name, false);
+    }
+
+
+    /**
+     * Add a new servlet mapping, replacing any existing mapping for
+     * the specified pattern.
+     *
+     * @param pattern URL pattern to be mapped
+     * @param name Name of the corresponding servlet to execute
+     * @param jspWildCard true if name identifies the JspServlet
+     * and pattern contains a wildcard; false otherwise
+     *
+     * @exception IllegalArgumentException if the specified servlet name
+     *  is not known to this Context
+     */
+    public void addServletMapping(String pattern, String name,
+                                  boolean jspWildCard) {
+        // Validate the proposed mapping
+        if (findChild(name) == null)
+            throw new IllegalArgumentException
+                (sm.getString("standardContext.servletMap.name", name));
+        pattern = adjustURLPattern(RequestUtil.URLDecode(pattern));
+        if (!validateURLPattern(pattern))
+            throw new IllegalArgumentException
+                (sm.getString("standardContext.servletMap.pattern", pattern));
+
+        // Add this mapping to our registered set
+        synchronized (servletMappings) {
+            String name2 = (String) servletMappings.get(pattern);
+            if (name2 != null) {
+                // Don't allow more than one servlet on the same pattern
+                Wrapper wrapper = (Wrapper) findChild(name2);
+                wrapper.removeMapping(pattern);
+                mapper.removeWrapper(pattern);
+            }
+            servletMappings.put(pattern, name);
+        }
+        Wrapper wrapper = (Wrapper) findChild(name);
+        wrapper.addMapping(pattern);
+
+        // Update context mapper
+        mapper.addWrapper(pattern, wrapper, jspWildCard);
+
+        fireContainerEvent("addServletMapping", pattern);
+
+    }
+
+
+    /**
+     * Add a JSP tag library for the specified URI.
+     *
+     * @param uri URI, relative to the web.xml file, of this tag library
+     * @param location Location of the tag library descriptor
+     */
+    public void addTaglib(String uri, String location) {
+
+        synchronized (taglibs) {
+            taglibs.put(uri, location);
+        }
+        fireContainerEvent("addTaglib", uri);
+
+    }
+
+
+    /**
+     * Add a new watched resource to the set recognized by this Context.
+     *
+     * @param name New watched resource file name
+     */
+    public void addWatchedResource(String name) {
+
+        synchronized (watchedResources) {
+            String results[] = new String[watchedResources.length + 1];
+            for (int i = 0; i < watchedResources.length; i++)
+                results[i] = watchedResources[i];
+            results[watchedResources.length] = name;
+            watchedResources = results;
+        }
+        fireContainerEvent("addWatchedResource", name);
+
+    }
+
+
+    /**
+     * Add a new welcome file to the set recognized by this Context.
+     *
+     * @param name New welcome file name
+     */
+    public void addWelcomeFile(String name) {
+
+        synchronized (welcomeFiles) {
+            // Welcome files from the application deployment descriptor
+            // completely replace those from the default conf/web.xml file
+            if (replaceWelcomeFiles) {
+                welcomeFiles = new String[0];
+                setReplaceWelcomeFiles(false);
+            }
+            String results[] =new String[welcomeFiles.length + 1];
+            for (int i = 0; i < welcomeFiles.length; i++)
+                results[i] = welcomeFiles[i];
+            results[welcomeFiles.length] = name;
+            welcomeFiles = results;
+        }
+        postWelcomeFiles();
+        fireContainerEvent("addWelcomeFile", name);
+
+    }
+
+
+    /**
+     * Add the classname of a LifecycleListener to be added to each
+     * Wrapper appended to this Context.
+     *
+     * @param listener Java class name of a LifecycleListener class
+     */
+    public void addWrapperLifecycle(String listener) {
+
+        synchronized (wrapperLifecycles) {
+            String results[] =new String[wrapperLifecycles.length + 1];
+            for (int i = 0; i < wrapperLifecycles.length; i++)
+                results[i] = wrapperLifecycles[i];
+            results[wrapperLifecycles.length] = listener;
+            wrapperLifecycles = results;
+        }
+        fireContainerEvent("addWrapperLifecycle", listener);
+
+    }
+
+
+    /**
+     * Add the classname of a ContainerListener to be added to each
+     * Wrapper appended to this Context.
+     *
+     * @param listener Java class name of a ContainerListener class
+     */
+    public void addWrapperListener(String listener) {
+
+        synchronized (wrapperListeners) {
+            String results[] =new String[wrapperListeners.length + 1];
+            for (int i = 0; i < wrapperListeners.length; i++)
+                results[i] = wrapperListeners[i];
+            results[wrapperListeners.length] = listener;
+            wrapperListeners = results;
+        }
+        fireContainerEvent("addWrapperListener", listener);
+
+    }
+
+
+    /**
+     * Factory method to create and return a new Wrapper instance, of
+     * the Java implementation class appropriate for this Context
+     * implementation.  The constructor of the instantiated Wrapper
+     * will have been called, but no properties will have been set.
+     */
+    public Wrapper createWrapper() {
+
+        Wrapper wrapper = null;
+        if (wrapperClass != null) {
+            try {
+                wrapper = (Wrapper) wrapperClass.newInstance();
+            } catch (Throwable t) {
+                log.error("createWrapper", t);
+                return (null);
+            }
+        } else {
+            wrapper = new StandardWrapper();
+        }
+
+        synchronized (instanceListeners) {
+            for (int i = 0; i < instanceListeners.length; i++) {
+                try {
+                    Class clazz = Class.forName(instanceListeners[i]);
+                    InstanceListener listener =
+                      (InstanceListener) clazz.newInstance();
+                    wrapper.addInstanceListener(listener);
+                } catch (Throwable t) {
+                    log.error("createWrapper", t);
+                    return (null);
+                }
+            }
+        }
+
+        synchronized (wrapperLifecycles) {
+            for (int i = 0; i < wrapperLifecycles.length; i++) {
+                try {
+                    Class clazz = Class.forName(wrapperLifecycles[i]);
+                    LifecycleListener listener =
+                      (LifecycleListener) clazz.newInstance();
+                    if (wrapper instanceof Lifecycle)
+                        ((Lifecycle) wrapper).addLifecycleListener(listener);
+                } catch (Throwable t) {
+                    log.error("createWrapper", t);
+                    return (null);
+                }
+            }
+        }
+
+        synchronized (wrapperListeners) {
+            for (int i = 0; i < wrapperListeners.length; i++) {
+                try {
+                    Class clazz = Class.forName(wrapperListeners[i]);
+                    ContainerListener listener =
+                      (ContainerListener) clazz.newInstance();
+                    wrapper.addContainerListener(listener);
+                } catch (Throwable t) {
+                    log.error("createWrapper", t);
+                    return (null);
+                }
+            }
+        }
+
+        return (wrapper);
+
+    }
+
+
+    /**
+     * Return the set of application listener class names configured
+     * for this application.
+     */
+    public String[] findApplicationListeners() {
+
+        return (applicationListeners);
+
+    }
+
+
+    /**
+     * Return the set of application parameters for this application.
+     */
+    public ApplicationParameter[] findApplicationParameters() {
+
+        return (applicationParameters);
+
+    }
+
+
+    /**
+     * Return the security constraints for this web application.
+     * If there are none, a zero-length array is returned.
+     */
+    public SecurityConstraint[] findConstraints() {
+
+        return (constraints);
+
+    }
+
+
+    /**
+     * Return the error page entry for the specified HTTP error code,
+     * if any; otherwise return <code>null</code>.
+     *
+     * @param errorCode Error code to look up
+     */
+    public ErrorPage findErrorPage(int errorCode) {
+        if (errorCode == 200) {
+            return (okErrorPage);
+        } else {
+            return ((ErrorPage) statusPages.get(new Integer(errorCode)));
+        }
+
+    }
+
+
+    /**
+     * Return the error page entry for the specified Java exception type,
+     * if any; otherwise return <code>null</code>.
+     *
+     * @param exceptionType Exception type to look up
+     */
+    public ErrorPage findErrorPage(String exceptionType) {
+
+        synchronized (exceptionPages) {
+            return ((ErrorPage) exceptionPages.get(exceptionType));
+        }
+
+    }
+
+
+    /**
+     * Return the set of defined error pages for all specified error codes
+     * and exception types.
+     */
+    public ErrorPage[] findErrorPages() {
+
+        synchronized(exceptionPages) {
+            synchronized(statusPages) {
+                ErrorPage results1[] = new ErrorPage[exceptionPages.size()];
+                results1 =
+                    (ErrorPage[]) exceptionPages.values().toArray(results1);
+                ErrorPage results2[] = new ErrorPage[statusPages.size()];
+                results2 =
+                    (ErrorPage[]) statusPages.values().toArray(results2);
+                ErrorPage results[] =
+                    new ErrorPage[results1.length + results2.length];
+                for (int i = 0; i < results1.length; i++)
+                    results[i] = results1[i];
+                for (int i = results1.length; i < results.length; i++)
+                    results[i] = results2[i - results1.length];
+                return (results);
+            }
+        }
+
+    }
+
+
+    /**
+     * Return the filter definition for the specified filter name, if any;
+     * otherwise return <code>null</code>.
+     *
+     * @param filterName Filter name to look up
+     */
+    public FilterDef findFilterDef(String filterName) {
+
+        synchronized (filterDefs) {
+            return ((FilterDef) filterDefs.get(filterName));
+        }
+
+    }
+
+
+    /**
+     * Return the set of defined filters for this Context.
+     */
+    public FilterDef[] findFilterDefs() {
+
+        synchronized (filterDefs) {
+            FilterDef results[] = new FilterDef[filterDefs.size()];
+            return ((FilterDef[]) filterDefs.values().toArray(results));
+        }
+
+    }
+
+
+    /**
+     * Return the set of filter mappings for this Context.
+     */
+    public FilterMap[] findFilterMaps() {
+
+        return (filterMaps);
+
+    }
+
+
+    /**
+     * Return the set of InstanceListener classes that will be added to
+     * newly created Wrappers automatically.
+     */
+    public String[] findInstanceListeners() {
+
+        return (instanceListeners);
+
+    }
+
+
+    /**
+     * FIXME: Fooling introspection ...
+     */
+    public Context findMappingObject() {
+        return (Context) getMappingObject();
+    }
+    
+    
+    /**
+     * Return the message destination with the specified name, if any;
+     * otherwise, return <code>null</code>.
+     *
+     * @param name Name of the desired message destination
+     */
+    public MessageDestination findMessageDestination(String name) {
+
+        synchronized (messageDestinations) {
+            return ((MessageDestination) messageDestinations.get(name));
+        }
+
+    }
+
+
+    /**
+     * Return the set of defined message destinations for this web
+     * application.  If none have been defined, a zero-length array
+     * is returned.
+     */
+    public MessageDestination[] findMessageDestinations() {
+
+        synchronized (messageDestinations) {
+            MessageDestination results[] =
+                new MessageDestination[messageDestinations.size()];
+            return ((MessageDestination[])
+                    messageDestinations.values().toArray(results));
+        }
+
+    }
+
+
+    /**
+     * Return the message destination ref with the specified name, if any;
+     * otherwise, return <code>null</code>.
+     *
+     * @param name Name of the desired message destination ref
+     */
+    public MessageDestinationRef
+        findMessageDestinationRef(String name) {
+
+        return namingResources.findMessageDestinationRef(name);
+
+    }
+
+
+    /**
+     * Return the set of defined message destination refs for this web
+     * application.  If none have been defined, a zero-length array
+     * is returned.
+     */
+    public MessageDestinationRef[]
+        findMessageDestinationRefs() {
+
+        return namingResources.findMessageDestinationRefs();
+
+    }
+
+
+    /**
+     * Return the MIME type to which the specified extension is mapped,
+     * if any; otherwise return <code>null</code>.
+     *
+     * @param extension Extension to map to a MIME type
+     */
+    public String findMimeMapping(String extension) {
+
+        return ((String) mimeMappings.get(extension));
+
+    }
+
+
+    /**
+     * Return the extensions for which MIME mappings are defined.  If there
+     * are none, a zero-length array is returned.
+     */
+    public String[] findMimeMappings() {
+
+        synchronized (mimeMappings) {
+            String results[] = new String[mimeMappings.size()];
+            return
+                ((String[]) mimeMappings.keySet().toArray(results));
+        }
+
+    }
+
+
+    /**
+     * Return the value for the specified context initialization
+     * parameter name, if any; otherwise return <code>null</code>.
+     *
+     * @param name Name of the parameter to return
+     */
+    public String findParameter(String name) {
+
+        synchronized (parameters) {
+            return ((String) parameters.get(name));
+        }
+
+    }
+
+
+    /**
+     * Return the names of all defined context initialization parameters
+     * for this Context.  If no parameters are defined, a zero-length
+     * array is returned.
+     */
+    public String[] findParameters() {
+
+        synchronized (parameters) {
+            String results[] = new String[parameters.size()];
+            return ((String[]) parameters.keySet().toArray(results));
+        }
+
+    }
+
+
+    /**
+     * For the given security role (as used by an application), return the
+     * corresponding role name (as defined by the underlying Realm) if there
+     * is one.  Otherwise, return the specified role unchanged.
+     *
+     * @param role Security role to map
+     */
+    public String findRoleMapping(String role) {
+
+        String realRole = null;
+        synchronized (roleMappings) {
+            realRole = (String) roleMappings.get(role);
+        }
+        if (realRole != null)
+            return (realRole);
+        else
+            return (role);
+
+    }
+
+
+    /**
+     * Return <code>true</code> if the specified security role is defined
+     * for this application; otherwise return <code>false</code>.
+     *
+     * @param role Security role to verify
+     */
+    public boolean findSecurityRole(String role) {
+
+        synchronized (securityRoles) {
+            for (int i = 0; i < securityRoles.length; i++) {
+                if (role.equals(securityRoles[i]))
+                    return (true);
+            }
+        }
+        return (false);
+
+    }
+
+
+    /**
+     * Return the security roles defined for this application.  If none
+     * have been defined, a zero-length array is returned.
+     */
+    public String[] findSecurityRoles() {
+
+        return (securityRoles);
+
+    }
+
+
+    /**
+     * Return the servlet name mapped by the specified pattern (if any);
+     * otherwise return <code>null</code>.
+     *
+     * @param pattern Pattern for which a mapping is requested
+     */
+    public String findServletMapping(String pattern) {
+
+        synchronized (servletMappings) {
+            return ((String) servletMappings.get(pattern));
+        }
+
+    }
+
+
+    /**
+     * Return the patterns of all defined servlet mappings for this
+     * Context.  If no mappings are defined, a zero-length array is returned.
+     */
+    public String[] findServletMappings() {
+
+        synchronized (servletMappings) {
+            String results[] = new String[servletMappings.size()];
+            return
+               ((String[]) servletMappings.keySet().toArray(results));
+        }
+
+    }
+
+
+    /**
+     * Return the context-relative URI of the error page for the specified
+     * HTTP status code, if any; otherwise return <code>null</code>.
+     *
+     * @param status HTTP status code to look up
+     */
+    public String findStatusPage(int status) {
+
+        return ((String) statusPages.get(new Integer(status)));
+
+    }
+
+
+    /**
+     * Return the set of HTTP status codes for which error pages have
+     * been specified.  If none are specified, a zero-length array
+     * is returned.
+     */
+    public int[] findStatusPages() {
+
+        synchronized (statusPages) {
+            int results[] = new int[statusPages.size()];
+            Iterator elements = statusPages.keySet().iterator();
+            int i = 0;
+            while (elements.hasNext())
+                results[i++] = ((Integer) elements.next()).intValue();
+            return (results);
+        }
+
+    }
+
+
+    /**
+     * Return the tag library descriptor location for the specified taglib
+     * URI, if any; otherwise, return <code>null</code>.
+     *
+     * @param uri URI, relative to the web.xml file
+     */
+    public String findTaglib(String uri) {
+
+        synchronized (taglibs) {
+            return ((String) taglibs.get(uri));
+        }
+
+    }
+
+
+    /**
+     * Return the URIs of all tag libraries for which a tag library
+     * descriptor location has been specified.  If none are specified,
+     * a zero-length array is returned.
+     */
+    public String[] findTaglibs() {
+
+        synchronized (taglibs) {
+            String results[] = new String[taglibs.size()];
+            return ((String[]) taglibs.keySet().toArray(results));
+        }
+
+    }
+
+
+    /**
+     * Return <code>true</code> if the specified welcome file is defined
+     * for this Context; otherwise return <code>false</code>.
+     *
+     * @param name Welcome file to verify
+     */
+    public boolean findWelcomeFile(String name) {
+
+        synchronized (welcomeFiles) {
+            for (int i = 0; i < welcomeFiles.length; i++) {
+                if (name.equals(welcomeFiles[i]))
+                    return (true);
+            }
+        }
+        return (false);
+
+    }
+
+
+    /**
+     * Return the set of watched resources for this Context. If none are 
+     * defined, a zero length array will be returned.
+     */
+    public String[] findWatchedResources() {
+        return watchedResources;
+    }
+    
+    
+    /**
+     * Return the set of welcome files defined for this Context.  If none are
+     * defined, a zero-length array is returned.
+     */
+    public String[] findWelcomeFiles() {
+
+        return (welcomeFiles);
+
+    }
+
+
+    /**
+     * Return the set of LifecycleListener classes that will be added to
+     * newly created Wrappers automatically.
+     */
+    public String[] findWrapperLifecycles() {
+
+        return (wrapperLifecycles);
+
+    }
+
+
+    /**
+     * Return the set of ContainerListener classes that will be added to
+     * newly created Wrappers automatically.
+     */
+    public String[] findWrapperListeners() {
+
+        return (wrapperListeners);
+
+    }
+
+
+    /**
+     * Reload this web application, if reloading is supported.
+     * <p>
+     * <b>IMPLEMENTATION NOTE</b>:  This method is designed to deal with
+     * reloads required by changes to classes in the underlying repositories
+     * of our class loader.  It does not handle changes to the web application
+     * deployment descriptor.  If that has occurred, you should stop this
+     * Context and create (and start) a new Context instance instead.
+     *
+     * @exception IllegalStateException if the <code>reloadable</code>
+     *  property is set to <code>false</code>.
+     */
+    public synchronized void reload() {
+
+        // Validate our current component state
+        if (!started)
+            throw new IllegalStateException
+                (sm.getString("containerBase.notStarted", logName()));
+
+        // Make sure reloading is enabled
+        //      if (!reloadable)
+        //          throw new IllegalStateException
+        //              (sm.getString("standardContext.notReloadable"));
+        if(log.isInfoEnabled())
+            log.info(sm.getString("standardContext.reloadingStarted"));
+
+        // Stop accepting requests temporarily
+        setPaused(true);
+
+        try {
+            stop();
+        } catch (LifecycleException e) {
+            log.error(sm.getString("standardContext.stoppingContext"), e);
+        }
+
+        try {
+            start();
+        } catch (LifecycleException e) {
+            log.error(sm.getString("standardContext.startingContext"), e);
+        }
+
+        setPaused(false);
+
+    }
+
+
+    /**
+     * Remove the specified application listener class from the set of
+     * listeners for this application.
+     *
+     * @param listener Java class name of the listener to be removed
+     */
+    public void removeApplicationListener(String listener) {
+
+        synchronized (applicationListeners) {
+
+            // Make sure this welcome file is currently present
+            int n = -1;
+            for (int i = 0; i < applicationListeners.length; i++) {
+                if (applicationListeners[i].equals(listener)) {
+                    n = i;
+                    break;
+                }
+            }
+            if (n < 0)
+                return;
+
+            // Remove the specified constraint
+            int j = 0;
+            String results[] = new String[applicationListeners.length - 1];
+            for (int i = 0; i < applicationListeners.length; i++) {
+                if (i != n)
+                    results[j++] = applicationListeners[i];
+            }
+            applicationListeners = results;
+
+        }
+
+        // Inform interested listeners
+        fireContainerEvent("removeApplicationListener", listener);
+
+        // FIXME - behavior if already started?
+
+    }
+
+
+    /**
+     * Remove the application parameter with the specified name from
+     * the set for this application.
+     *
+     * @param name Name of the application parameter to remove
+     */
+    public void removeApplicationParameter(String name) {
+
+        synchronized (applicationParameters) {
+
+            // Make sure this parameter is currently present
+            int n = -1;
+            for (int i = 0; i < applicationParameters.length; i++) {
+                if (name.equals(applicationParameters[i].getName())) {
+                    n = i;
+                    break;
+                }
+            }
+            if (n < 0)
+                return;
+
+            // Remove the specified parameter
+            int j = 0;
+            ApplicationParameter results[] =
+                new ApplicationParameter[applicationParameters.length - 1];
+            for (int i = 0; i < applicationParameters.length; i++) {
+                if (i != n)
+                    results[j++] = applicationParameters[i];
+            }
+            applicationParameters = results;
+
+        }
+
+        // Inform interested listeners
+        fireContainerEvent("removeApplicationParameter", name);
+
+    }
+
+
+    /**
+     * Add a child Container, only if the proposed child is an implementation
+     * of Wrapper.
+     *
+     * @param child Child container to be added
+     *
+     * @exception IllegalArgumentException if the proposed container is
+     *  not an implementation of Wrapper
+     */
+    public void removeChild(Container child) {
+
+        if (!(child instanceof Wrapper)) {
+            throw new IllegalArgumentException
+                (sm.getString("standardContext.notWrapper"));
+        }
+
+        super.removeChild(child);
+
+    }
+
+
+    /**
+     * Remove the specified security constraint from this web application.
+     *
+     * @param constraint Constraint to be removed
+     */
+    public void removeConstraint(SecurityConstraint constraint) {
+
+        synchronized (constraints) {
+
+            // Make sure this constraint is currently present
+            int n = -1;
+            for (int i = 0; i < constraints.length; i++) {
+                if (constraints[i].equals(constraint)) {
+                    n = i;
+                    break;
+                }
+            }
+            if (n < 0)
+                return;
+
+            // Remove the specified constraint
+            int j = 0;
+            SecurityConstraint results[] =
+                new SecurityConstraint[constraints.length - 1];
+            for (int i = 0; i < constraints.length; i++) {
+                if (i != n)
+                    results[j++] = constraints[i];
+            }
+            constraints = results;
+
+        }
+
+        // Inform interested listeners
+        fireContainerEvent("removeConstraint", constraint);
+
+    }
+
+
+    /**
+     * Remove the error page for the specified error code or
+     * Java language exception, if it exists; otherwise, no action is taken.
+     *
+     * @param errorPage The error page definition to be removed
+     */
+    public void removeErrorPage(ErrorPage errorPage) {
+
+        String exceptionType = errorPage.getExceptionType();
+        if (exceptionType != null) {
+            synchronized (exceptionPages) {
+                exceptionPages.remove(exceptionType);
+            }
+        } else {
+            synchronized (statusPages) {
+                if (errorPage.getErrorCode() == 200) {
+                    this.okErrorPage = null;
+                }
+                statusPages.remove(new Integer(errorPage.getErrorCode()));
+            }
+        }
+        fireContainerEvent("removeErrorPage", errorPage);
+
+    }
+
+
+    /**
+     * Remove the specified filter definition from this Context, if it exists;
+     * otherwise, no action is taken.
+     *
+     * @param filterDef Filter definition to be removed
+     */
+    public void removeFilterDef(FilterDef filterDef) {
+
+        synchronized (filterDefs) {
+            filterDefs.remove(filterDef.getFilterName());
+        }
+        fireContainerEvent("removeFilterDef", filterDef);
+
+    }
+
+
+    /**
+     * Remove a filter mapping from this Context.
+     *
+     * @param filterMap The filter mapping to be removed
+     */
+    public void removeFilterMap(FilterMap filterMap) {
+
+        synchronized (filterMaps) {
+
+            // Make sure this filter mapping is currently present
+            int n = -1;
+            for (int i = 0; i < filterMaps.length; i++) {
+                if (filterMaps[i] == filterMap) {
+                    n = i;
+                    break;
+                }
+            }
+            if (n < 0)
+                return;
+
+            // Remove the specified filter mapping
+            FilterMap results[] = new FilterMap[filterMaps.length - 1];
+            System.arraycopy(filterMaps, 0, results, 0, n);
+            System.arraycopy(filterMaps, n + 1, results, n,
+                             (filterMaps.length - 1) - n);
+            filterMaps = results;
+
+        }
+
+        // Inform interested listeners
+        fireContainerEvent("removeFilterMap", filterMap);
+
+    }
+
+
+    /**
+     * Remove a class name from the set of InstanceListener classes that
+     * will be added to newly created Wrappers.
+     *
+     * @param listener Class name of an InstanceListener class to be removed
+     */
+    public void removeInstanceListener(String listener) {
+
+        synchronized (instanceListeners) {
+
+            // Make sure this welcome file is currently present
+            int n = -1;
+            for (int i = 0; i < instanceListeners.length; i++) {
+                if (instanceListeners[i].equals(listener)) {
+                    n = i;
+                    break;
+                }
+            }
+            if (n < 0)
+                return;
+
+            // Remove the specified constraint
+            int j = 0;
+            String results[] = new String[instanceListeners.length - 1];
+            for (int i = 0; i < instanceListeners.length; i++) {
+                if (i != n)
+                    results[j++] = instanceListeners[i];
+            }
+            instanceListeners = results;
+
+        }
+
+        // Inform interested listeners
+        fireContainerEvent("removeInstanceListener", listener);
+
+    }
+
+
+    /**
+     * Remove any message destination with the specified name.
+     *
+     * @param name Name of the message destination to remove
+     */
+    public void removeMessageDestination(String name) {
+
+        synchronized (messageDestinations) {
+            messageDestinations.remove(name);
+        }
+        fireContainerEvent("removeMessageDestination", name);
+
+    }
+
+
+    /**
+     * Remove any message destination ref with the specified name.
+     *
+     * @param name Name of the message destination ref to remove
+     */
+    public void removeMessageDestinationRef(String name) {
+
+        namingResources.removeMessageDestinationRef(name);
+        fireContainerEvent("removeMessageDestinationRef", name);
+
+    }
+
+
+    /**
+     * Remove the MIME mapping for the specified extension, if it exists;
+     * otherwise, no action is taken.
+     *
+     * @param extension Extension to remove the mapping for
+     */
+    public void removeMimeMapping(String extension) {
+
+        synchronized (mimeMappings) {
+            mimeMappings.remove(extension);
+        }
+        fireContainerEvent("removeMimeMapping", extension);
+
+    }
+
+
+    /**
+     * Remove the context initialization parameter with the specified
+     * name, if it exists; otherwise, no action is taken.
+     *
+     * @param name Name of the parameter to remove
+     */
+    public void removeParameter(String name) {
+
+        synchronized (parameters) {
+            parameters.remove(name);
+        }
+        fireContainerEvent("removeParameter", name);
+
+    }
+
+
+    /**
+     * Remove any security role reference for the specified name
+     *
+     * @param role Security role (as used in the application) to remove
+     */
+    public void removeRoleMapping(String role) {
+
+        synchronized (roleMappings) {
+            roleMappings.remove(role);
+        }
+        fireContainerEvent("removeRoleMapping", role);
+
+    }
+
+
+    /**
+     * Remove any security role with the specified name.
+     *
+     * @param role Security role to remove
+     */
+    public void removeSecurityRole(String role) {
+
+        synchronized (securityRoles) {
+
+            // Make sure this security role is currently present
+            int n = -1;
+            for (int i = 0; i < securityRoles.length; i++) {
+                if (role.equals(securityRoles[i])) {
+                    n = i;
+                    break;
+                }
+            }
+            if (n < 0)
+                return;
+
+            // Remove the specified security role
+            int j = 0;
+            String results[] = new String[securityRoles.length - 1];
+            for (int i = 0; i < securityRoles.length; i++) {
+                if (i != n)
+                    results[j++] = securityRoles[i];
+            }
+            securityRoles = results;
+
+        }
+
+        // Inform interested listeners
+        fireContainerEvent("removeSecurityRole", role);
+
+    }
+
+
+    /**
+     * Remove any servlet mapping for the specified pattern, if it exists;
+     * otherwise, no action is taken.
+     *
+     * @param pattern URL pattern of the mapping to remove
+     */
+    public void removeServletMapping(String pattern) {
+
+        String name = null;
+        synchronized (servletMappings) {
+            name = (String) servletMappings.remove(pattern);
+        }
+        Wrapper wrapper = (Wrapper) findChild(name);
+        if( wrapper != null ) {
+            wrapper.removeMapping(pattern);
+        }
+        mapper.removeWrapper(pattern);
+        fireContainerEvent("removeServletMapping", pattern);
+
+    }
+
+
+    /**
+     * Remove the tag library location forthe specified tag library URI.
+     *
+     * @param uri URI, relative to the web.xml file
+     */
+    public void removeTaglib(String uri) {
+
+        synchronized (taglibs) {
+            taglibs.remove(uri);
+        }
+        fireContainerEvent("removeTaglib", uri);
+    }
+
+
+    /**
+     * Remove the specified watched resource name from the list associated
+     * with this Context.
+     * 
+     * @param name Name of the watched resource to be removed
+     */
+    public void removeWatchedResource(String name) {
+        
+        synchronized (watchedResources) {
+
+            // Make sure this watched resource is currently present
+            int n = -1;
+            for (int i = 0; i < watchedResources.length; i++) {
+                if (watchedResources[i].equals(name)) {
+                    n = i;
+                    break;
+                }
+            }
+            if (n < 0)
+                return;
+
+            // Remove the specified watched resource
+            int j = 0;
+            String results[] = new String[watchedResources.length - 1];
+            for (int i = 0; i < watchedResources.length; i++) {
+                if (i != n)
+                    results[j++] = watchedResources[i];
+            }
+            watchedResources = results;
+
+        }
+
+        fireContainerEvent("removeWatchedResource", name);
+
+    }
+    
+    
+    /**
+     * Remove the specified welcome file name from the list recognized
+     * by this Context.
+     *
+     * @param name Name of the welcome file to be removed
+     */
+    public void removeWelcomeFile(String name) {
+
+        synchronized (welcomeFiles) {
+
+            // Make sure this welcome file is currently present
+            int n = -1;
+            for (int i = 0; i < welcomeFiles.length; i++) {
+                if (welcomeFiles[i].equals(name)) {
+                    n = i;
+                    break;
+                }
+            }
+            if (n < 0)
+                return;
+
+            // Remove the specified constraint
+            int j = 0;
+            String results[] = new String[welcomeFiles.length - 1];
+            for (int i = 0; i < welcomeFiles.length; i++) {
+                if (i != n)
+                    results[j++] = welcomeFiles[i];
+            }
+            welcomeFiles = results;
+
+        }
+
+        // Inform interested listeners
+        postWelcomeFiles();
+        fireContainerEvent("removeWelcomeFile", name);
+
+    }
+
+
+    /**
+     * Remove a class name from the set of LifecycleListener classes that
+     * will be added to newly created Wrappers.
+     *
+     * @param listener Class name of a LifecycleListener class to be removed
+     */
+    public void removeWrapperLifecycle(String listener) {
+
+
+        synchronized (wrapperLifecycles) {
+
+            // Make sure this welcome file is currently present
+            int n = -1;
+            for (int i = 0; i < wrapperLifecycles.length; i++) {
+                if (wrapperLifecycles[i].equals(listener)) {
+                    n = i;
+                    break;
+                }
+            }
+            if (n < 0)
+                return;
+
+            // Remove the specified constraint
+            int j = 0;
+            String results[] = new String[wrapperLifecycles.length - 1];
+            for (int i = 0; i < wrapperLifecycles.length; i++) {
+                if (i != n)
+                    results[j++] = wrapperLifecycles[i];
+            }
+            wrapperLifecycles = results;
+
+        }
+
+        // Inform interested listeners
+        fireContainerEvent("removeWrapperLifecycle", listener);
+
+    }
+
+
+    /**
+     * Remove a class name from the set of ContainerListener classes that
+     * will be added to newly created Wrappers.
+     *
+     * @param listener Class name of a ContainerListener class to be removed
+     */
+    public void removeWrapperListener(String listener) {
+
+
+        synchronized (wrapperListeners) {
+
+            // Make sure this welcome file is currently present
+            int n = -1;
+            for (int i = 0; i < wrapperListeners.length; i++) {
+                if (wrapperListeners[i].equals(listener)) {
+                    n = i;
+                    break;
+                }
+            }
+            if (n < 0)
+                return;
+
+            // Remove the specified constraint
+            int j = 0;
+            String results[] = new String[wrapperListeners.length - 1];
+            for (int i = 0; i < wrapperListeners.length; i++) {
+                if (i != n)
+                    results[j++] = wrapperListeners[i];
+            }
+            wrapperListeners = results;
+
+        }
+
+        // Inform interested listeners
+        fireContainerEvent("removeWrapperListener", listener);
+
+    }
+
+
+    /**
+     * Gets the cumulative processing times of all servlets in this
+     * StandardContext.
+     *
+     * @return Cumulative processing times of all servlets in this
+     * StandardContext
+     */
+    public long getProcessingTime() {
+        
+        long result = 0;
+
+        Container[] children = findChildren();
+        if (children != null) {
+            for( int i=0; i< children.length; i++ ) {
+                result += ((StandardWrapper)children[i]).getProcessingTime();
+            }
+        }
+
+        return result;
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Configure and initialize the set of filters for this Context.
+     * Return <code>true</code> if all filter initialization completed
+     * successfully, or <code>false</code> otherwise.
+     */
+    public boolean filterStart() {
+
+        if (getLogger().isDebugEnabled())
+            getLogger().debug("Starting filters");
+        // Instantiate and record a FilterConfig for each defined filter
+        boolean ok = true;
+        synchronized (filterConfigs) {
+            filterConfigs.clear();
+            Iterator names = filterDefs.keySet().iterator();
+            while (names.hasNext()) {
+                String name = (String) names.next();
+                if (getLogger().isDebugEnabled())
+                    getLogger().debug(" Starting filter '" + name + "'");
+                ApplicationFilterConfig filterConfig = null;
+                try {
+                    filterConfig = new ApplicationFilterConfig
+                      (this, (FilterDef) filterDefs.get(name));
+                    filterConfigs.put(name, filterConfig);
+                } catch (Throwable t) {
+                    getLogger().error
+                        (sm.getString("standardContext.filterStart", name), t);
+                    ok = false;
+                }
+            }
+        }
+
+        return (ok);
+
+    }
+
+
+    /**
+     * Finalize and release the set of filters for this Context.
+     * Return <code>true</code> if all filter finalization completed
+     * successfully, or <code>false</code> otherwise.
+     */
+    public boolean filterStop() {
+
+        if (getLogger().isDebugEnabled())
+            getLogger().debug("Stopping filters");
+
+        // Release all Filter and FilterConfig instances
+        synchronized (filterConfigs) {
+            Iterator names = filterConfigs.keySet().iterator();
+            while (names.hasNext()) {
+                String name = (String) names.next();
+                if (getLogger().isDebugEnabled())
+                    getLogger().debug(" Stopping filter '" + name + "'");
+                ApplicationFilterConfig filterConfig =
+                  (ApplicationFilterConfig) filterConfigs.get(name);
+                filterConfig.release();
+            }
+            filterConfigs.clear();
+        }
+        return (true);
+
+    }
+
+
+    /**
+     * Find and return the initialized <code>FilterConfig</code> for the
+     * specified filter name, if any; otherwise return <code>null</code>.
+     *
+     * @param name Name of the desired filter
+     */
+    public FilterConfig findFilterConfig(String name) {
+
+        return ((FilterConfig) filterConfigs.get(name));
+
+    }
+
+
+    /**
+     * Configure the set of instantiated application event listeners
+     * for this Context.  Return <code>true</code> if all listeners wre
+     * initialized successfully, or <code>false</code> otherwise.
+     */
+    public boolean listenerStart() {
+
+        if (log.isDebugEnabled())
+            log.debug("Configuring application event listeners");
+
+        // Instantiate the required listeners
+        ClassLoader loader = getLoader().getClassLoader();
+        String listeners[] = findApplicationListeners();
+        Object results[] = new Object[listeners.length];
+        boolean ok = true;
+        for (int i = 0; i < results.length; i++) {
+            if (getLogger().isDebugEnabled())
+                getLogger().debug(" Configuring event listener class '" +
+                    listeners[i] + "'");
+            try {
+                Class clazz = loader.loadClass(listeners[i]);
+                results[i] = clazz.newInstance();
+            } catch (Throwable t) {
+                getLogger().error
+                    (sm.getString("standardContext.applicationListener",
+                                  listeners[i]), t);
+                ok = false;
+            }
+        }
+        if (!ok) {
+            getLogger().error(sm.getString("standardContext.applicationSkipped"));
+            return (false);
+        }
+
+        // Sort listeners in two arrays
+        ArrayList eventListeners = new ArrayList();
+        ArrayList lifecycleListeners = new ArrayList();
+        for (int i = 0; i < results.length; i++) {
+            if ((results[i] instanceof ServletContextAttributeListener)
+                || (results[i] instanceof ServletRequestAttributeListener)
+                || (results[i] instanceof ServletRequestListener)
+                || (results[i] instanceof HttpSessionAttributeListener)) {
+                eventListeners.add(results[i]);
+            }
+            if ((results[i] instanceof ServletContextListener)
+                || (results[i] instanceof HttpSessionListener)) {
+                lifecycleListeners.add(results[i]);
+            }
+        }
+
+        setApplicationEventListeners(eventListeners.toArray());
+        setApplicationLifecycleListeners(lifecycleListeners.toArray());
+
+        // Send application start events
+
+        if (getLogger().isDebugEnabled())
+            getLogger().debug("Sending application start events");
+
+        Object instances[] = getApplicationLifecycleListeners();
+        if (instances == null)
+            return (ok);
+        ServletContextEvent event =
+          new ServletContextEvent(getServletContext());
+        for (int i = 0; i < instances.length; i++) {
+            if (instances[i] == null)
+                continue;
+            if (!(instances[i] instanceof ServletContextListener))
+                continue;
+            ServletContextListener listener =
+                (ServletContextListener) instances[i];
+            try {
+                fireContainerEvent("beforeContextInitialized", listener);
+                listener.contextInitialized(event);
+                fireContainerEvent("afterContextInitialized", listener);
+            } catch (Throwable t) {
+                fireContainerEvent("afterContextInitialized", listener);
+                getLogger().error
+                    (sm.getString("standardContext.listenerStart",
+                                  instances[i].getClass().getName()), t);
+                ok = false;
+            }
+        }
+        return (ok);
+
+    }
+
+
+    /**
+     * Send an application stop event to all interested listeners.
+     * Return <code>true</code> if all events were sent successfully,
+     * or <code>false</code> otherwise.
+     */
+    public boolean listenerStop() {
+
+        if (log.isDebugEnabled())
+            log.debug("Sending application stop events");
+
+        boolean ok = true;
+        Object listeners[] = getApplicationLifecycleListeners();
+        if (listeners == null)
+            return (ok);
+        ServletContextEvent event =
+          new ServletContextEvent(getServletContext());
+        for (int i = 0; i < listeners.length; i++) {
+            int j = (listeners.length - 1) - i;
+            if (listeners[j] == null)
+                continue;
+            if (!(listeners[j] instanceof ServletContextListener))
+                continue;
+            ServletContextListener listener =
+                (ServletContextListener) listeners[j];
+            try {
+                fireContainerEvent("beforeContextDestroyed", listener);
+                listener.contextDestroyed(event);
+                fireContainerEvent("afterContextDestroyed", listener);
+            } catch (Throwable t) {
+                fireContainerEvent("afterContextDestroyed", listener);
+                getLogger().error
+                    (sm.getString("standardContext.listenerStop",
+                                  listeners[j].getClass().getName()), t);
+                ok = false;
+            }
+        }
+
+        setApplicationEventListeners(null);
+        setApplicationLifecycleListeners(null);
+
+        return (ok);
+
+    }
+
+
+    /**
+     * Allocate resources, including proxy.
+     * Return <code>true</code> if initialization was successfull,
+     * or <code>false</code> otherwise.
+     */
+    public boolean resourcesStart() {
+
+        boolean ok = true;
+
+        Hashtable env = new Hashtable();
+        if (getParent() != null)
+            env.put(ProxyDirContext.HOST, getParent().getName());
+        env.put(ProxyDirContext.CONTEXT, getName());
+
+        try {
+            ProxyDirContext proxyDirContext =
+                new ProxyDirContext(env, webappResources);
+            if (webappResources instanceof FileDirContext) {
+                filesystemBased = true;
+                ((FileDirContext) webappResources).setCaseSensitive
+                    (isCaseSensitive());
+                ((FileDirContext) webappResources).setAllowLinking
+                    (isAllowLinking());
+            }
+            if (webappResources instanceof BaseDirContext) {
+                ((BaseDirContext) webappResources).setDocBase(getBasePath());
+                ((BaseDirContext) webappResources).setCached
+                    (isCachingAllowed());
+                ((BaseDirContext) webappResources).setCacheTTL(getCacheTTL());
+                ((BaseDirContext) webappResources).setCacheMaxSize
+                    (getCacheMaxSize());
+                ((BaseDirContext) webappResources).allocate();
+            }
+            // Register the cache in JMX
+            if (isCachingAllowed()) {
+                ObjectName resourcesName = 
+                    new ObjectName(this.getDomain() + ":type=Cache,host=" 
+                                   + getHostname() + ",path=" 
+                                   + (("".equals(getPath()))?"/":getPath()));
+                Registry.getRegistry(null, null).registerComponent
+                    (proxyDirContext.getCache(), resourcesName, null);
+            }
+            this.resources = proxyDirContext;
+        } catch (Throwable t) {
+            log.error(sm.getString("standardContext.resourcesStart"), t);
+            ok = false;
+        }
+
+        return (ok);
+
+    }
+
+
+    /**
+     * Deallocate resources and destroy proxy.
+     */
+    public boolean resourcesStop() {
+
+        boolean ok = true;
+
+        try {
+            if (resources != null) {
+                if (resources instanceof Lifecycle) {
+                    ((Lifecycle) resources).stop();
+                }
+                if (webappResources instanceof BaseDirContext) {
+                    ((BaseDirContext) webappResources).release();
+                }
+                // Unregister the cache in JMX
+                if (isCachingAllowed()) {
+                    ObjectName resourcesName = 
+                        new ObjectName(this.getDomain()
+                                       + ":type=Cache,host=" 
+                                       + getHostname() + ",path=" 
+                                       + (("".equals(getPath()))?"/"
+                                          :getPath()));
+                    Registry.getRegistry(null, null)
+                        .unregisterComponent(resourcesName);
+                }
+            }
+        } catch (Throwable t) {
+            log.error(sm.getString("standardContext.resourcesStop"), t);
+            ok = false;
+        }
+
+        this.resources = null;
+
+        return (ok);
+
+    }
+
+
+    /**
+     * Load and initialize all servlets marked "load on startup" in the
+     * web application deployment descriptor.
+     *
+     * @param children Array of wrappers for all currently defined
+     *  servlets (including those not declared load on startup)
+     */
+    public void loadOnStartup(Container children[]) {
+
+        // Collect "load on startup" servlets that need to be initialized
+        TreeMap map = new TreeMap();
+        for (int i = 0; i < children.length; i++) {
+            Wrapper wrapper = (Wrapper) children[i];
+            int loadOnStartup = wrapper.getLoadOnStartup();
+            if (loadOnStartup < 0)
+                continue;
+            if (loadOnStartup == 0)     // Arbitrarily put them last
+                loadOnStartup = Integer.MAX_VALUE;
+            Integer key = new Integer(loadOnStartup);
+            ArrayList list = (ArrayList) map.get(key);
+            if (list == null) {
+                list = new ArrayList();
+                map.put(key, list);
+            }
+            list.add(wrapper);
+        }
+
+        // Load the collected "load on startup" servlets
+        Iterator keys = map.keySet().iterator();
+        while (keys.hasNext()) {
+            Integer key = (Integer) keys.next();
+            ArrayList list = (ArrayList) map.get(key);
+            Iterator wrappers = list.iterator();
+            while (wrappers.hasNext()) {
+                Wrapper wrapper = (Wrapper) wrappers.next();
+                try {
+                    wrapper.load();
+                } catch (ServletException e) {
+                    getLogger().error(sm.getString("standardWrapper.loadException",
+                                      getName()), StandardWrapper.getRootCause(e));
+                    // NOTE: load errors (including a servlet that throws
+                    // UnavailableException from tht init() method) are NOT
+                    // fatal to application startup
+                }
+            }
+        }
+
+    }
+
+
+    /**
+     * Start this Context component.
+     *
+     * @exception LifecycleException if a startup error occurs
+     */
+    public synchronized void start() throws LifecycleException {
+        //if (lazy ) return;
+        if (started) {
+            if(log.isInfoEnabled())
+                log.info(sm.getString("containerBase.alreadyStarted", logName()));
+            return;
+        }
+        if( !initialized ) { 
+            try {
+                init();
+            } catch( Exception ex ) {
+                throw new LifecycleException("Error initializaing ", ex);
+            }
+        }
+        if(log.isDebugEnabled())
+            log.debug("Starting " + ("".equals(getName()) ? "ROOT" : getName()));
+
+        // Set JMX object name for proper pipeline registration
+        preRegisterJMX();
+
+        if ((oname != null) && 
+            (Registry.getRegistry(null, null).getMBeanServer().isRegistered(oname))) {
+            // As things depend on the JMX registration, the context
+            // must be reregistered again once properly initialized
+            Registry.getRegistry(null, null).unregisterComponent(oname);
+        }
+
+        // Notify our interested LifecycleListeners
+        lifecycle.fireLifecycleEvent(BEFORE_START_EVENT, null);
+
+        setAvailable(false);
+        setConfigured(false);
+        boolean ok = true;
+
+        // Add missing components as necessary
+        if (webappResources == null) {   // (1) Required by Loader
+            if (log.isDebugEnabled())
+                log.debug("Configuring default Resources");
+            try {
+                if ((docBase != null) && (docBase.endsWith(".war")) && (!(new File(getBasePath())).isDirectory()))
+                    setResources(new WARDirContext());
+                else
+                    setResources(new FileDirContext());
+            } catch (IllegalArgumentException e) {
+                log.error("Error initializing resources: " + e.getMessage());
+                ok = false;
+            }
+        }
+        if (ok) {
+            if (!resourcesStart()) {
+                log.error( "Error in resourceStart()");
+                ok = false;
+            }
+        }
+
+        // Look for a realm - that may have been configured earlier. 
+        // If the realm is added after context - it'll set itself.
+        if( realm == null && mserver != null ) {
+            ObjectName realmName=null;
+            try {
+                realmName=new ObjectName( getEngineName() + ":type=Realm,host=" + 
+                        getHostname() + ",path=" + getPath());
+                if( mserver.isRegistered(realmName ) ) {
+                    mserver.invoke(realmName, "init", 
+                            new Object[] {},
+                            new String[] {}
+                    );            
+                }
+            } catch( Throwable t ) {
+                if(log.isDebugEnabled())
+                    log.debug("No realm for this host " + realmName);
+            }
+        }
+        
+        if (getLoader() == null) {
+            WebappLoader webappLoader = new WebappLoader(getParentClassLoader());
+            webappLoader.setDelegate(getDelegate());
+            setLoader(webappLoader);
+        }
+
+        // Initialize character set mapper
+        getCharsetMapper();
+
+        // Post work directory
+        postWorkDirectory();
+
+        // Validate required extensions
+        boolean dependencyCheck = true;
+        try {
+            dependencyCheck = ExtensionValidator.validateApplication
+                (getResources(), this);
+        } catch (IOException ioe) {
+            log.error("Error in dependencyCheck", ioe);
+            dependencyCheck = false;
+        }
+
+        if (!dependencyCheck) {
+            // do not make application available if depency check fails
+            ok = false;
+        }
+
+        // Reading the "catalina.useNaming" environment variable
+        String useNamingProperty = System.getProperty("catalina.useNaming");
+        if ((useNamingProperty != null)
+            && (useNamingProperty.equals("false"))) {
+            useNaming = false;
+        }
+
+        if (ok && isUseNaming()) {
+            if (namingContextListener == null) {
+                namingContextListener = new NamingContextListener();
+                namingContextListener.setName(getNamingContextName());
+                addLifecycleListener(namingContextListener);
+            }
+        }
+
+        // Standard container startup
+        if (log.isDebugEnabled())
+            log.debug("Processing standard container startup");
+
+        // Binding thread
+        ClassLoader oldCCL = bindThread();
+
+        boolean mainOk = false;
+
+        try {
+
+            if (ok) {
+                
+                started = true;
+
+                // Start our subordinate components, if any
+                if ((loader != null) && (loader instanceof Lifecycle))
+                    ((Lifecycle) loader).start();
+
+                // Unbinding thread
+                unbindThread(oldCCL);
+
+                // Binding thread
+                oldCCL = bindThread();
+
+                // Initialize logger again. Other components might have used it too early, 
+                // so it should be reset.
+                logger = null;
+                getLogger();
+                if ((logger != null) && (logger instanceof Lifecycle))
+                    ((Lifecycle) logger).start();
+                
+                if ((cluster != null) && (cluster instanceof Lifecycle))
+                    ((Lifecycle) cluster).start();
+                if ((realm != null) && (realm instanceof Lifecycle))
+                    ((Lifecycle) realm).start();
+                if ((resources != null) && (resources instanceof Lifecycle))
+                    ((Lifecycle) resources).start();
+
+                // Start our child containers, if any
+                Container children[] = findChildren();
+                for (int i = 0; i < children.length; i++) {
+                    if (children[i] instanceof Lifecycle)
+                        ((Lifecycle) children[i]).start();
+                }
+
+                // Start the Valves in our pipeline (including the basic),
+                // if any
+                if (pipeline instanceof Lifecycle) {
+                    ((Lifecycle) pipeline).start();
+                }
+                
+                if(getProcessTlds()) {
+                    processTlds();
+                }
+                
+                // Notify our interested LifecycleListeners
+                lifecycle.fireLifecycleEvent(START_EVENT, null);
+
+                // Configure default manager if none was specified
+                if (manager == null) {
+                    if ((getCluster() != null) && distributable) {
+                        try {
+                            setManager(getCluster().createManager(getName()));
+                        } catch (Exception ex) {
+                            log.error("standardContext.clusterFail", ex);
+                            ok = false;
+                        }
+                    } else {
+                        setManager(new StandardManager());
+                    }
+                }
+                
+                // Start manager
+                if ((manager != null) && (manager instanceof Lifecycle)) {
+                    ((Lifecycle) getManager()).start();
+                }
+
+                // Start ContainerBackgroundProcessor thread
+                super.threadStart();
+
+                mainOk = true;
+
+            }
+
+        } finally {
+            // Unbinding thread
+            unbindThread(oldCCL);
+            if (!mainOk) {
+                // An exception occurred
+                // Register with JMX anyway, to allow management
+                registerJMX();
+            }
+        }
+
+        if (!getConfigured()) {
+            log.error( "Error getConfigured");
+            ok = false;
+        }
+
+        // We put the resources into the servlet context
+        if (ok)
+            getServletContext().setAttribute
+                (Globals.RESOURCES_ATTR, getResources());
+
+        // Initialize associated mapper
+        mapper.setContext(getPath(), welcomeFiles, resources);
+
+        // Binding thread
+        oldCCL = bindThread();
+
+        try {
+            
+            // Create context attributes that will be required
+            if (ok) {
+                postWelcomeFiles();
+            }
+            
+            if (ok) {
+                // Notify our interested LifecycleListeners
+                lifecycle.fireLifecycleEvent(AFTER_START_EVENT, null);
+            }
+            
+            // Configure and call application event listeners and filters
+            if (ok) {
+                if (!listenerStart()) {
+                    log.error( "Error listenerStart");
+                    ok = false;
+                }
+            }
+            if (ok) {
+                if (!filterStart()) {
+                    log.error( "Error filterStart");
+                    ok = false;
+                }
+            }
+            
+            // Load and initialize all "load on startup" servlets
+            if (ok) {
+                loadOnStartup(findChildren());
+            }
+            
+        } finally {
+            // Unbinding thread
+            unbindThread(oldCCL);
+        }
+
+        // Set available status depending upon startup success
+        if (ok) {
+            if (log.isDebugEnabled())
+                log.debug("Starting completed");
+            setAvailable(true);
+        } else {
+            log.error(sm.getString("standardContext.startFailed", getName()));
+            try {
+                stop();
+            } catch (Throwable t) {
+                log.error(sm.getString("standardContext.startCleanup"), t);
+            }
+            setAvailable(false);
+        }
+
+        // JMX registration
+        registerJMX();
+
+        startTime=System.currentTimeMillis();
+        
+        // Send j2ee.state.running notification 
+        if (ok && (this.getObjectName() != null)) {
+            Notification notification = 
+                new Notification("j2ee.state.running", this.getObjectName(), 
+                                sequenceNumber++);
+            broadcaster.sendNotification(notification);
+        }
+
+        // Close all JARs right away to avoid always opening a peak number 
+        // of files on startup
+        if (getLoader() instanceof WebappLoader) {
+            ((WebappLoader) getLoader()).closeJARs(true);
+        }
+
+        // Reinitializing if something went wrong
+        if (!ok && started) {
+            stop();
+        }
+
+        //cacheContext();
+    }
+
+    /**
+     * Processes TLDs.
+     *
+     * @throws LifecycleException If an error occurs
+     */
+     protected void processTlds() throws LifecycleException {
+       TldConfig tldConfig = new TldConfig();
+       tldConfig.setContext(this);
+
+       // (1)  check if the attribute has been defined
+       //      on the context element.
+       tldConfig.setTldValidation(tldValidation);
+       tldConfig.setTldNamespaceAware(tldNamespaceAware);
+
+       // (2) if the attribute wasn't defined on the context
+       //     try the host.
+       if (!tldValidation) {
+         tldConfig.setTldValidation
+           (((StandardHost) getParent()).getXmlValidation());
+       }
+
+       if (!tldNamespaceAware) {
+         tldConfig.setTldNamespaceAware
+           (((StandardHost) getParent()).getXmlNamespaceAware());
+       }
+                    
+       try {
+         tldConfig.execute();
+       } catch (Exception ex) {
+         log.error("Error reading tld listeners " 
+                    + ex.toString(), ex); 
+       }
+     }
+    
+    /**
+     * Stop this Context component.
+     *
+     * @exception LifecycleException if a shutdown error occurs
+     */
+    public synchronized void stop() throws LifecycleException {
+
+        // Validate and update our current component state
+        if (!started) {
+            if(log.isInfoEnabled())
+                log.info(sm.getString("containerBase.notStarted", logName()));
+            return;
+        }
+
+        // Notify our interested LifecycleListeners
+        lifecycle.fireLifecycleEvent(BEFORE_STOP_EVENT, null);
+        
+        // Send j2ee.state.stopping notification 
+        if (this.getObjectName() != null) {
+            Notification notification = 
+                new Notification("j2ee.state.stopping", this.getObjectName(), 
+                                sequenceNumber++);
+            broadcaster.sendNotification(notification);
+        }
+        
+        // Mark this application as unavailable while we shut down
+        setAvailable(false);
+
+        // Binding thread
+        ClassLoader oldCCL = bindThread();
+
+        try {
+            // Stop our child containers, if any
+            Container[] children = findChildren();
+            for (int i = 0; i < children.length; i++) {
+                if (children[i] instanceof Lifecycle)
+                    ((Lifecycle) children[i]).stop();
+            }
+
+            // Stop our filters
+            filterStop();
+
+            // Stop our application listeners
+            listenerStop();
+
+            // Stop ContainerBackgroundProcessor thread
+            super.threadStop();
+
+            if ((manager != null) && (manager instanceof Lifecycle)) {
+                ((Lifecycle) manager).stop();
+            }
+
+            // Finalize our character set mapper
+            setCharsetMapper(null);
+
+            // Normal container shutdown processing
+            if (log.isDebugEnabled())
+                log.debug("Processing standard container shutdown");
+            // Notify our interested LifecycleListeners
+            lifecycle.fireLifecycleEvent(STOP_EVENT, null);
+            started = false;
+
+            // Stop the Valves in our pipeline (including the basic), if any
+            if (pipeline instanceof Lifecycle) {
+                ((Lifecycle) pipeline).stop();
+            }
+
+            // Clear all application-originated servlet context attributes
+            if (context != null)
+                context.clearAttributes();
+
+            // Stop resources
+            resourcesStop();
+
+            if ((realm != null) && (realm instanceof Lifecycle)) {
+                ((Lifecycle) realm).stop();
+            }
+            if ((cluster != null) && (cluster instanceof Lifecycle)) {
+                ((Lifecycle) cluster).stop();
+            }
+            if ((logger != null) && (logger instanceof Lifecycle)) {
+                ((Lifecycle) logger).stop();
+            }
+            if ((loader != null) && (loader instanceof Lifecycle)) {
+                ((Lifecycle) loader).stop();
+            }
+
+        } finally {
+
+            // Unbinding thread
+            unbindThread(oldCCL);
+
+        }
+
+        // Send j2ee.state.stopped notification 
+        if (this.getObjectName() != null) {
+            Notification notification = 
+                new Notification("j2ee.state.stopped", this.getObjectName(), 
+                                sequenceNumber++);
+            broadcaster.sendNotification(notification);
+        }
+        
+        // Reset application context
+        context = null;
+
+        // This object will no longer be visible or used. 
+        try {
+            resetContext();
+        } catch( Exception ex ) {
+            log.error( "Error reseting context " + this + " " + ex, ex );
+        }
+        
+        // Notify our interested LifecycleListeners
+        lifecycle.fireLifecycleEvent(AFTER_STOP_EVENT, null);
+
+        if (log.isDebugEnabled())
+            log.debug("Stopping complete");
+
+    }
+
+    /** Destroy needs to clean up the context completely.
+     * 
+     * The problem is that undoing all the config in start() and restoring 
+     * a 'fresh' state is impossible. After stop()/destroy()/init()/start()
+     * we should have the same state as if a fresh start was done - i.e
+     * read modified web.xml, etc. This can only be done by completely 
+     * removing the context object and remapping a new one, or by cleaning
+     * up everything.
+     * 
+     * XXX Should this be done in stop() ?
+     * 
+     */ 
+    public void destroy() throws Exception {
+        if( oname != null ) { 
+            // Send j2ee.object.deleted notification 
+            Notification notification = 
+                new Notification("j2ee.object.deleted", this.getObjectName(), 
+                                sequenceNumber++);
+            broadcaster.sendNotification(notification);
+        } 
+        super.destroy();
+
+        // Notify our interested LifecycleListeners
+        lifecycle.fireLifecycleEvent(DESTROY_EVENT, null);
+
+        instanceListeners = new String[0];
+    }
+    
+    private void resetContext() throws Exception, MBeanRegistrationException {
+        // Restore the original state ( pre reading web.xml in start )
+        // If you extend this - override this method and make sure to clean up
+        children=new HashMap();
+        startupTime = 0;
+        startTime = 0;
+        tldScanTime = 0;
+
+        // Bugzilla 32867
+        distributable = false;
+
+        applicationListeners = new String[0];
+        applicationEventListenersObjects = new Object[0];
+        applicationLifecycleListenersObjects = new Object[0];
+
+        if(log.isDebugEnabled())
+            log.debug("resetContext " + oname + " " + mserver);
+    }
+
+    /**
+     * Return a String representation of this component.
+     */
+    public String toString() {
+
+        StringBuffer sb = new StringBuffer();
+        if (getParent() != null) {
+            sb.append(getParent().toString());
+            sb.append(".");
+        }
+        sb.append("StandardContext[");
+        sb.append(getName());
+        sb.append("]");
+        return (sb.toString());
+
+    }
+
+
+    // ------------------------------------------------------ Protected Methods
+
+
+    /**
+     * Adjust the URL pattern to begin with a leading slash, if appropriate
+     * (i.e. we are running a servlet 2.2 application).  Otherwise, return
+     * the specified URL pattern unchanged.
+     *
+     * @param urlPattern The URL pattern to be adjusted (if needed)
+     *  and returned
+     */
+    protected String adjustURLPattern(String urlPattern) {
+
+        if (urlPattern == null)
+            return (urlPattern);
+        if (urlPattern.startsWith("/") || urlPattern.startsWith("*."))
+            return (urlPattern);
+        if (!isServlet22())
+            return (urlPattern);
+        if(log.isDebugEnabled())
+            log.debug(sm.getString("standardContext.urlPattern.patternWarning",
+                         urlPattern));
+        return ("/" + urlPattern);
+
+    }
+
+
+    /**
+     * Are we processing a version 2.2 deployment descriptor?
+     */
+    protected boolean isServlet22() {
+
+        if (this.publicId == null)
+            return (false);
+        if (this.publicId.equals
+            (org.apache.catalina.startup.Constants.WebDtdPublicId_22))
+            return (true);
+        else
+            return (false);
+
+    }
+
+
+    /**
+     * Return a File object representing the base directory for the
+     * entire servlet container (i.e. the Engine container if present).
+     */
+    protected File engineBase() {
+        String base=System.getProperty("catalina.base");
+        if( base == null ) {
+            StandardEngine eng=(StandardEngine)this.getParent().getParent();
+            base=eng.getBaseDir();
+        }
+        return (new File(base));
+    }
+
+
+    // -------------------------------------------------------- Private Methods
+
+
+    /**
+     * Bind current thread, both for CL purposes and for JNDI ENC support
+     * during : startup, shutdown and realoading of the context.
+     *
+     * @return the previous context class loader
+     */
+    private ClassLoader bindThread() {
+
+        ClassLoader oldContextClassLoader =
+            Thread.currentThread().getContextClassLoader();
+
+        if (getResources() == null)
+            return oldContextClassLoader;
+
+        if (getLoader().getClassLoader() != null) {
+            Thread.currentThread().setContextClassLoader
+                (getLoader().getClassLoader());
+        }
+
+        DirContextURLStreamHandler.bind(getResources());
+
+        if (isUseNaming()) {
+            try {
+                ContextBindings.bindThread(this, this);
+            } catch (NamingException e) {
+                // Silent catch, as this is a normal case during the early
+                // startup stages
+            }
+        }
+
+        return oldContextClassLoader;
+
+    }
+
+
+    /**
+     * Unbind thread.
+     */
+    private void unbindThread(ClassLoader oldContextClassLoader) {
+
+        Thread.currentThread().setContextClassLoader(oldContextClassLoader);
+
+        oldContextClassLoader = null;
+
+        if (isUseNaming()) {
+            ContextBindings.unbindThread(this, this);
+        }
+
+        DirContextURLStreamHandler.unbind();
+
+    }
+
+
+
+    /**
+     * Get base path.
+     */
+    protected String getBasePath() {
+        String docBase = null;
+        Container container = this;
+        while (container != null) {
+            if (container instanceof Host)
+                break;
+            container = container.getParent();
+        }
+        File file = new File(getDocBase());
+        if (!file.isAbsolute()) {
+            if (container == null) {
+                docBase = (new File(engineBase(), getDocBase())).getPath();
+            } else {
+                // Use the "appBase" property of this container
+                String appBase = ((Host) container).getAppBase();
+                file = new File(appBase);
+                if (!file.isAbsolute())
+                    file = new File(engineBase(), appBase);
+                docBase = (new File(file, getDocBase())).getPath();
+            }
+        } else {
+            docBase = file.getPath();
+        }
+        return docBase;
+    }
+
+
+    /**
+     * Get config base.
+     */
+    public File getConfigBase() {
+        File configBase = 
+            new File(System.getProperty("catalina.base"), "conf");
+        if (!configBase.exists()) {
+            return null;
+        }
+        Container container = this;
+        Container host = null;
+        Container engine = null;
+        while (container != null) {
+            if (container instanceof Host)
+                host = container;
+            if (container instanceof Engine)
+                engine = container;
+            container = container.getParent();
+        }
+        if (engine != null) {
+            configBase = new File(configBase, engine.getName());
+        }
+        if (host != null) {
+            configBase = new File(configBase, host.getName());
+        }
+        if (saveConfig) {
+            configBase.mkdirs();
+        }
+        return configBase;
+    }
+
+
+    /**
+     * Given a context path, get the config file name.
+     */
+    protected String getDefaultConfigFile() {
+        String basename = null;
+        String path = getPath();
+        if (path.equals("")) {
+            basename = "ROOT";
+        } else {
+            basename = path.substring(1).replace('/', '#');
+        }
+        return (basename + ".xml");
+    }
+
+
+    /**
+     * Get naming context full name.
+     */
+    private String getNamingContextName() {
+    if (namingContextName == null) {
+        Container parent = getParent();
+        if (parent == null) {
+        namingContextName = getName();
+        } else {
+        Stack stk = new Stack();
+        StringBuffer buff = new StringBuffer();
+        while (parent != null) {
+            stk.push(parent.getName());
+            parent = parent.getParent();
+        }
+        while (!stk.empty()) {
+            buff.append("/" + stk.pop());
+        }
+        buff.append(getName());
+        namingContextName = buff.toString();
+        }
+    }
+    return namingContextName;
+    }
+
+
+    /**
+     * Return the request processing paused flag for this Context.
+     */
+    public boolean getPaused() {
+
+        return (this.paused);
+
+    }
+
+
+    /**
+     * Post a copy of our current list of welcome files as a servlet context
+     * attribute, so that the default servlet can find them.
+     */
+    private void postWelcomeFiles() {
+
+        getServletContext().setAttribute("org.apache.catalina.WELCOME_FILES",
+                                         welcomeFiles);
+
+    }
+
+    public String getHostname() {
+        Container parentHost = getParent();
+        if (parentHost != null) {
+            hostName = parentHost.getName();
+        }
+        if ((hostName == null) || (hostName.length() < 1))
+            hostName = "_";
+        return hostName;
+    }
+
+    /**
+     * Set the appropriate context attribute for our work directory.
+     */
+    private void postWorkDirectory() {
+
+        // Acquire (or calculate) the work directory path
+        String workDir = getWorkDir();
+        if (workDir == null) {
+
+            // Retrieve our parent (normally a host) name
+            String hostName = null;
+            String engineName = null;
+            String hostWorkDir = null;
+            Container parentHost = getParent();
+            if (parentHost != null) {
+                hostName = parentHost.getName();
+                if (parentHost instanceof StandardHost) {
+                    hostWorkDir = ((StandardHost)parentHost).getWorkDir();
+                }
+                Container parentEngine = parentHost.getParent();
+                if (parentEngine != null) {
+                   engineName = parentEngine.getName();
+                }
+            }
+            if ((hostName == null) || (hostName.length() < 1))
+                hostName = "_";
+            if ((engineName == null) || (engineName.length() < 1))
+                engineName = "_";
+
+            String temp = getPath();
+            if (temp.startsWith("/"))
+                temp = temp.substring(1);
+            temp = temp.replace('/', '_');
+            temp = temp.replace('\\', '_');
+            if (temp.length() < 1)
+                temp = "_";
+            if (hostWorkDir != null ) {
+                workDir = hostWorkDir + File.separator + temp;
+            } else {
+                workDir = "work" + File.separator + engineName +
+                    File.separator + hostName + File.separator + temp;
+            }
+            setWorkDir(workDir);
+        }
+
+        // Create this directory if necessary
+        File dir = new File(workDir);
+        if (!dir.isAbsolute()) {
+            File catalinaHome = engineBase();
+            String catalinaHomePath = null;
+            try {
+                catalinaHomePath = catalinaHome.getCanonicalPath();
+                dir = new File(catalinaHomePath, workDir);
+            } catch (IOException e) {
+            }
+        }
+        dir.mkdirs();
+
+        // Set the appropriate servlet context attribute
+        getServletContext().setAttribute(Globals.WORK_DIR_ATTR, dir);
+        if (getServletContext() instanceof ApplicationContext)
+            ((ApplicationContext) getServletContext()).setAttributeReadOnly
+                (Globals.WORK_DIR_ATTR);
+
+    }
+
+
+    /**
+     * Set the request processing paused flag for this Context.
+     *
+     * @param paused The new request processing paused flag
+     */
+    private void setPaused(boolean paused) {
+
+        this.paused = paused;
+
+    }
+
+
+    /**
+     * Validate the syntax of a proposed <code>&lt;url-pattern&gt;</code>
+     * for conformance with specification requirements.
+     *
+     * @param urlPattern URL pattern to be validated
+     */
+    private boolean validateURLPattern(String urlPattern) {
+
+        if (urlPattern == null)
+            return (false);
+        if (urlPattern.indexOf('\n') >= 0 || urlPattern.indexOf('\r') >= 0) {
+            getLogger().warn(sm.getString("standardContext.crlfinurl",urlPattern));
+        }
+        if (urlPattern.startsWith("*.")) {
+            if (urlPattern.indexOf('/') < 0)
+                return (true);
+            else
+                return (false);
+        }
+        if ( (urlPattern.startsWith("/")) &&
+                (urlPattern.indexOf("*.") < 0))
+            return (true);
+        else
+            return (false);
+
+    }
+
+
+    // ------------------------------------------------------------- Operations
+
+
+    /**
+     * JSR77 deploymentDescriptor attribute
+     *
+     * @return string deployment descriptor 
+     */
+    public String getDeploymentDescriptor() {
+    
+        InputStream stream = null;
+        ServletContext servletContext = getServletContext();
+        if (servletContext != null) {
+            stream = servletContext.getResourceAsStream(
+                org.apache.catalina.startup.Constants.ApplicationWebXml);
+        }
+        if (stream == null) {
+            return "";
+        }
+        BufferedReader br = new BufferedReader(
+                                new InputStreamReader(stream));
+        StringBuffer sb = new StringBuffer();
+        String strRead = "";
+        try {
+            while (strRead != null) {
+                sb.append(strRead);
+                strRead = br.readLine();
+            }
+        } catch (IOException e) {
+            return "";
+        }
+
+        return sb.toString(); 
+    
+    }
+    
+    
+    /**
+     * JSR77 servlets attribute
+     *
+     * @return list of all servlets ( we know about )
+     */
+    public String[] getServlets() {
+        
+        String[] result = null;
+
+        Container[] children = findChildren();
+        if (children != null) {
+            result = new String[children.length];
+            for( int i=0; i< children.length; i++ ) {
+                result[i] = ((StandardWrapper)children[i]).getObjectName();
+            }
+        }
+
+        return result;
+    }
+    
+
+    public ObjectName createObjectName(String hostDomain, ObjectName parentName)
+            throws MalformedObjectNameException
+    {
+        String onameStr;
+        StandardHost hst=(StandardHost)getParent();
+        
+        String pathName=getName();
+        String hostName=getParent().getName();
+        String name= "//" + ((hostName==null)? "DEFAULT" : hostName) +
+                (("".equals(pathName))?"/":pathName );
+
+        String suffix=",J2EEApplication=" +
+                getJ2EEApplication() + ",J2EEServer=" +
+                getJ2EEServer();
+
+        onameStr="j2eeType=WebModule,name=" + name + suffix;
+        if( log.isDebugEnabled())
+            log.debug("Registering " + onameStr + " for " + oname);
+        
+        // default case - no domain explictely set.
+        if( getDomain() == null ) domain=hst.getDomain();
+
+        ObjectName oname=new ObjectName(getDomain() + ":" + onameStr);
+        return oname;        
+    }    
+    
+    private void preRegisterJMX() {
+        try {
+            StandardHost host = (StandardHost) getParent();
+            if ((oname == null) 
+                || (oname.getKeyProperty("j2eeType") == null)) {
+                oname = createObjectName(host.getDomain(), host.getJmxName());
+                controller = oname;
+            }
+        } catch(Exception ex) {
+            if(log.isInfoEnabled())
+                log.info("Error registering ctx with jmx " + this + " " +
+                     oname + " " + ex.toString(), ex );
+        }
+    }
+
+    private void registerJMX() {
+        try {
+            if (log.isDebugEnabled()) {
+                log.debug("Checking for " + oname );
+            }
+            if(! Registry.getRegistry(null, null)
+                .getMBeanServer().isRegistered(oname)) {
+                controller = oname;
+                Registry.getRegistry(null, null)
+                    .registerComponent(this, oname, null);
+                
+                // Send j2ee.object.created notification 
+                if (this.getObjectName() != null) {
+                    Notification notification = new Notification(
+                                                        "j2ee.object.created", 
+                                                        this.getObjectName(), 
+                                                        sequenceNumber++);
+                    broadcaster.sendNotification(notification);
+                }
+            }
+            Container children[] = findChildren();
+            for (int i=0; children!=null && i<children.length; i++) {
+                ((StandardWrapper)children[i]).registerJMX( this );
+            }
+        } catch (Exception ex) {
+            if(log.isInfoEnabled())
+                log.info("Error registering wrapper with jmx " + this + " " +
+                    oname + " " + ex.toString(), ex );
+        }
+    }
+
+    /** There are 2 cases:
+     *   1.The context is created and registered by internal APIS
+     *   2. The context is created by JMX, and it'll self-register.
+     *
+     * @param server The server
+     * @param name The object name
+     * @return ObjectName The name of the object
+     * @throws Exception If an error occurs
+     */
+    public ObjectName preRegister(MBeanServer server,
+                                  ObjectName name)
+            throws Exception
+    {
+        if( oname != null ) {
+            //log.info( "Already registered " + oname + " " + name);
+            // Temporary - /admin uses the old names
+            return name;
+        }
+        ObjectName result=super.preRegister(server,name);
+        return name;
+    }
+
+    public void preDeregister() throws Exception {
+        if( started ) {
+            try {
+                stop();
+            } catch( Exception ex ) {
+                log.error( "error stopping ", ex);
+            }
+        }
+    }
+
+    public void init() throws Exception {
+
+        if( this.getParent() == null ) {
+            ObjectName parentName=getParentName();
+            
+            if( ! mserver.isRegistered(parentName)) {
+                if(log.isDebugEnabled())
+                    log.debug("No host, creating one " + parentName);
+                StandardHost host=new StandardHost();
+                host.setName(hostName);
+                host.setAutoDeploy(false);
+                Registry.getRegistry(null, null)
+                    .registerComponent(host, parentName, null);
+                mserver.invoke(parentName, "init", new Object[] {}, new String[] {} );
+            }
+            
+            // Add the main configuration listener
+            LifecycleListener config = null;
+            try {
+                Object configClassname = null;
+                try {
+                    configClassname = mserver.getAttribute(parentName, "configClass");
+                } catch (AttributeNotFoundException e) {
+                    // Ignore, it's normal a host may not have this optional attribute
+                }
+                if (configClassname != null) {
+                    Class clazz = Class.forName(String.valueOf(configClassname));
+                    config = (LifecycleListener) clazz.newInstance();
+                } else {
+                    config = new ContextConfig();
+                }
+            } catch (Exception e) {
+                log.warn("Error creating ContextConfig for " + parentName, e);
+                throw e;
+            }
+            this.addLifecycleListener(config);
+
+            if (log.isDebugEnabled()) {
+                log.debug("AddChild " + parentName + " " + this);
+            }
+            try {
+                mserver.invoke(parentName, "addChild", new Object[] { this },
+                               new String[] {"org.apache.catalina.Container"});
+            } catch (Exception e) {
+                destroy();
+                throw e;
+            }
+            // It's possible that addChild may have started us
+            if( initialized ) {
+                return;
+            }
+        }
+        super.init();
+        
+        // Notify our interested LifecycleListeners
+        lifecycle.fireLifecycleEvent(INIT_EVENT, null);
+
+        // Send j2ee.state.starting notification 
+        if (this.getObjectName() != null) {
+            Notification notification = new Notification("j2ee.state.starting", 
+                                                        this.getObjectName(), 
+                                                        sequenceNumber++);
+            broadcaster.sendNotification(notification);
+        }
+        
+    }
+
+    public ObjectName getParentName() throws MalformedObjectNameException {
+        // "Life" update
+        String path=oname.getKeyProperty("name");
+        if( path == null ) {
+            log.error( "No name attribute " +name );
+            return null;
+        }
+        if( ! path.startsWith( "//")) {
+            log.error("Invalid name " + name);
+        }
+        path=path.substring(2);
+        int delim=path.indexOf( "/" );
+        hostName="localhost"; // Should be default...
+        if( delim > 0 ) {
+            hostName=path.substring(0, delim);
+            path = path.substring(delim);
+            if (path.equals("/")) {
+                this.setName("");
+            } else {
+                this.setName(path);
+            }
+        } else {
+            if(log.isDebugEnabled())
+                log.debug("Setting path " +  path );
+            this.setName( path );
+        }
+        // XXX The service and domain should be the same.
+        String parentDomain=getEngineName();
+        if( parentDomain == null ) parentDomain=domain;
+        ObjectName parentName=new ObjectName( parentDomain + ":" +
+                "type=Host,host=" + hostName);
+        return parentName;
+    }
+    
+    public void create() throws Exception{
+        init();
+    }
+
+    /* Remove a JMX notficationListener 
+     * @see javax.management.NotificationEmitter#removeNotificationListener(javax.management.NotificationListener, javax.management.NotificationFilter, java.lang.Object)
+     */
+    public void removeNotificationListener(NotificationListener listener, 
+            NotificationFilter filter, Object object) throws ListenerNotFoundException {
+    	broadcaster.removeNotificationListener(listener,filter,object);
+    	
+    }
+    
+    private MBeanNotificationInfo[] notificationInfo;
+    
+    /* Get JMX Broadcaster Info
+     * @TODO use StringManager for international support!
+     * @TODO This two events we not send j2ee.state.failed and j2ee.attribute.changed!
+     * @see javax.management.NotificationBroadcaster#getNotificationInfo()
+     */
+    public MBeanNotificationInfo[] getNotificationInfo() {
+    	// FIXME: i18n
+    	if(notificationInfo == null) {
+    		notificationInfo = new MBeanNotificationInfo[]{
+    				new MBeanNotificationInfo(new String[] {
+    				"j2ee.object.created"},
+					Notification.class.getName(),
+					"web application is created"
+    				), 
+					new MBeanNotificationInfo(new String[] {
+					"j2ee.state.starting"},
+					Notification.class.getName(),
+					"change web application is starting"
+					),
+					new MBeanNotificationInfo(new String[] {
+					"j2ee.state.running"},
+					Notification.class.getName(),
+					"web application is running"
+					),
+					new MBeanNotificationInfo(new String[] {
+					"j2ee.state.stopped"},
+					Notification.class.getName(),
+					"web application start to stopped"
+					),
+					new MBeanNotificationInfo(new String[] {
+					"j2ee.object.stopped"},
+					Notification.class.getName(),
+					"web application is stopped"
+					),
+					new MBeanNotificationInfo(new String[] {
+					"j2ee.object.deleted"},
+					Notification.class.getName(),
+					"web application is deleted"
+					)
+    		};
+    		
+    	}
+    	
+    	return notificationInfo;
+    }
+    
+    
+    /* Add a JMX-NotificationListener
+     * @see javax.management.NotificationBroadcaster#addNotificationListener(javax.management.NotificationListener, javax.management.NotificationFilter, java.lang.Object)
+     */
+    public void addNotificationListener(NotificationListener listener, 
+            NotificationFilter filter, Object object) throws IllegalArgumentException {
+    	broadcaster.addNotificationListener(listener,filter,object);
+    	
+    }
+    
+    
+    /**
+     * Remove a JMX-NotificationListener 
+     * @see javax.management.NotificationBroadcaster#removeNotificationListener(javax.management.NotificationListener)
+     */
+    public void removeNotificationListener(NotificationListener listener) 
+    throws ListenerNotFoundException {
+    	broadcaster.removeNotificationListener(listener);
+    	
+    }
+    
+    
+    // ------------------------------------------------------------- Attributes
+
+
+    /**
+     * Return the naming resources associated with this web application.
+     */
+    public javax.naming.directory.DirContext getStaticResources() {
+
+        return getResources();
+
+    }
+
+
+    /**
+     * Return the naming resources associated with this web application.
+     * FIXME: Fooling introspection ... 
+     */
+    public javax.naming.directory.DirContext findStaticResources() {
+
+        return getResources();
+
+    }
+
+
+    /**
+     * Return the naming resources associated with this web application.
+     */
+    public String[] getWelcomeFiles() {
+
+        return findWelcomeFiles();
+
+    }
+
+     /**
+     * Set the validation feature of the XML parser used when
+     * parsing xml instances.
+     * @param webXmlValidation true to enable xml instance validation
+     */
+    public void setXmlValidation(boolean webXmlValidation){
+        
+        this.webXmlValidation = webXmlValidation;
+
+    }
+
+    /**
+     * Get the server.xml <context> attribute's xmlValidation.
+     * @return true if validation is enabled.
+     *
+     */
+    public boolean getXmlValidation(){
+        return webXmlValidation;
+    }
+
+
+    /**
+     * Get the server.xml <context> attribute's xmlNamespaceAware.
+     * @return true if namespace awarenes is enabled.
+     */
+    public boolean getXmlNamespaceAware(){
+        return webXmlNamespaceAware;
+    }
+
+
+    /**
+     * Set the namespace aware feature of the XML parser used when
+     * parsing xml instances.
+     * @param webXmlNamespaceAware true to enable namespace awareness
+     */
+    public void setXmlNamespaceAware(boolean webXmlNamespaceAware){
+        this.webXmlNamespaceAware= webXmlNamespaceAware;
+    }    
+
+
+    /**
+     * Set the validation feature of the XML parser used when
+     * parsing tlds files. 
+     * @param tldValidation true to enable xml instance validation
+     */
+    public void setTldValidation(boolean tldValidation){
+        
+        this.tldValidation = tldValidation;
+
+    }
+
+    /**
+     * Get the server.xml <context> attribute's webXmlValidation.
+     * @return true if validation is enabled.
+     *
+     */
+    public boolean getTldValidation(){
+        return tldValidation;
+    }
+
+    /**
+     * Sets the process TLDs attribute.
+     *
+     * @param newProcessTlds The new value
+     */
+    public void setProcessTlds(boolean newProcessTlds) {
+	processTlds = newProcessTlds;
+    }
+
+    /**
+     * Returns the processTlds attribute value.
+     */
+    public boolean getProcessTlds() {
+	return processTlds;
+    }
+
+    /**
+     * Get the server.xml <host> attribute's xmlNamespaceAware.
+     * @return true if namespace awarenes is enabled.
+     */
+    public boolean getTldNamespaceAware(){
+        return tldNamespaceAware;
+    }
+
+
+    /**
+     * Set the namespace aware feature of the XML parser used when
+     * parsing xml instances.
+     * @param tldNamespaceAware true to enable namespace awareness
+     */
+    public void setTldNamespaceAware(boolean tldNamespaceAware){
+        this.tldNamespaceAware= tldNamespaceAware;
+    }    
+
+
+    /** 
+     * Support for "stateManageable" JSR77 
+     */
+    public boolean isStateManageable() {
+        return true;
+    }
+    
+    public void startRecursive() throws LifecycleException {
+        // nothing to start recursive, the servlets will be started by load-on-startup
+        start();
+    }
+    
+    public int getState() {
+        if( started ) {
+            return 1; // RUNNING
+        }
+        if( initialized ) {
+            return 0; // starting ? 
+        }
+        if( ! available ) { 
+            return 4; //FAILED
+        }
+        // 2 - STOPPING
+        return 3; // STOPPED
+    }
+    
+    /**
+     * The J2EE Server ObjectName this module is deployed on.
+     */     
+    private String server = null;
+    
+    /**
+     * The Java virtual machines on which this module is running.
+     */       
+    private String[] javaVMs = null;
+    
+    public String getServer() {
+        return server;
+    }
+        
+    public String setServer(String server) {
+        return this.server=server;
+    }
+        
+    public String[] getJavaVMs() {
+        return javaVMs;
+    }
+        
+    public String[] setJavaVMs(String[] javaVMs) {
+        return this.javaVMs = javaVMs;
+    }
+    
+    /**
+     * Gets the time this context was started.
+     *
+     * @return Time (in milliseconds since January 1, 1970, 00:00:00) when this
+     * context was started 
+     */
+    public long getStartTime() {
+        return startTime;
+    }
+    
+    public boolean isEventProvider() {
+        return false;
+    }
+    
+    public boolean isStatisticsProvider() {
+        return false;
+    }
+    
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/core/StandardContextValve.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/core/StandardContextValve.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/core/StandardContextValve.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,270 @@
+/*
+ * Copyright 1999-2001,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.IOException;
+
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletRequestEvent;
+import javax.servlet.ServletRequestListener;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.catalina.Container;
+import org.apache.catalina.Globals;
+import org.apache.catalina.Wrapper;
+import org.apache.catalina.connector.Request;
+import org.apache.catalina.connector.Response;
+import org.apache.catalina.util.StringManager;
+import org.apache.catalina.valves.ValveBase;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.tomcat.util.buf.MessageBytes;
+
+/**
+ * Valve that implements the default basic behavior for the
+ * <code>StandardContext</code> container implementation.
+ * <p>
+ * <b>USAGE CONSTRAINT</b>:  This implementation is likely to be useful only
+ * when processing HTTP requests.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302978 $ $Date: 2004-06-23 11:59:42 -0500 (Wed, 23 Jun 2004) $
+ */
+
+final class StandardContextValve
+    extends ValveBase {
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The descriptive information related to this implementation.
+     */
+    private static final String info =
+        "org.apache.catalina.core.StandardContextValve/1.0";
+
+
+    /**
+     * The string manager for this package.
+     */
+    private static final StringManager sm =
+        StringManager.getManager(Constants.Package);
+
+
+    private static Log log = LogFactory.getLog(StandardContextValve.class);
+
+    
+    private StandardContext context = null;
+    
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * Return descriptive information about this Valve implementation.
+     */
+    public String getInfo() {
+
+        return (info);
+
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Cast to a StandardContext right away, as it will be needed later.
+     * 
+     * @see org.apache.catalina.Contained#setContainer(org.apache.catalina.Container)
+     */
+    public void setContainer(Container container) {
+        super.setContainer(container);
+        context = (StandardContext) container;
+    }
+
+    
+    /**
+     * Select the appropriate child Wrapper to process this request,
+     * based on the specified request URI.  If no matching Wrapper can
+     * be found, return an appropriate HTTP error.
+     *
+     * @param request Request to be processed
+     * @param response Response to be produced
+     * @param valveContext Valve context used to forward to the next Valve
+     *
+     * @exception IOException if an input/output error occurred
+     * @exception ServletException if a servlet error occurred
+     */
+    public final void invoke(Request request, Response response)
+        throws IOException, ServletException {
+
+        // Disallow any direct access to resources under WEB-INF or META-INF
+        MessageBytes requestPathMB = request.getRequestPathMB();
+        if ((requestPathMB.startsWithIgnoreCase("/META-INF/", 0))
+            || (requestPathMB.equalsIgnoreCase("/META-INF"))
+            || (requestPathMB.startsWithIgnoreCase("/WEB-INF/", 0))
+            || (requestPathMB.equalsIgnoreCase("/WEB-INF"))) {
+            String requestURI = request.getDecodedRequestURI();
+            notFound(requestURI, response);
+            return;
+        }
+
+        // Wait if we are reloading
+        while (context.getPaused()) {
+            try {
+                Thread.sleep(1000);
+            } catch (InterruptedException e) {
+                ;
+            }
+        }
+
+        // Select the Wrapper to be used for this Request
+        Wrapper wrapper = request.getWrapper();
+        if (wrapper == null) {
+            String requestURI = request.getDecodedRequestURI();
+            notFound(requestURI, response);
+            return;
+        }
+
+        // Normal request processing
+        Object instances[] = context.getApplicationEventListeners();
+
+        ServletRequestEvent event = null;
+
+        if ((instances != null) 
+                && (instances.length > 0)) {
+            event = new ServletRequestEvent
+                (((StandardContext) container).getServletContext(), 
+                 request.getRequest());
+            // create pre-service event
+            for (int i = 0; i < instances.length; i++) {
+                if (instances[i] == null)
+                    continue;
+                if (!(instances[i] instanceof ServletRequestListener))
+                    continue;
+                ServletRequestListener listener =
+                    (ServletRequestListener) instances[i];
+                try {
+                    listener.requestInitialized(event);
+                } catch (Throwable t) {
+                    container.getLogger().error(sm.getString("requestListenerValve.requestInit",
+                                     instances[i].getClass().getName()), t);
+                    ServletRequest sreq = request.getRequest();
+                    sreq.setAttribute(Globals.EXCEPTION_ATTR,t);
+                    return;
+                }
+            }
+        }
+
+        wrapper.getPipeline().getFirst().invoke(request, response);
+
+        if ((instances !=null ) &&
+                (instances.length > 0)) {
+            // create post-service event
+            for (int i = 0; i < instances.length; i++) {
+                if (instances[i] == null)
+                    continue;
+                if (!(instances[i] instanceof ServletRequestListener))
+                    continue;
+                ServletRequestListener listener =
+                    (ServletRequestListener) instances[i];
+                try {
+                    listener.requestDestroyed(event);
+                } catch (Throwable t) {
+                    container.getLogger().error(sm.getString("requestListenerValve.requestDestroy",
+                                     instances[i].getClass().getName()), t);
+                    ServletRequest sreq = request.getRequest();
+                    sreq.setAttribute(Globals.EXCEPTION_ATTR,t);
+                }
+            }
+        }
+                
+    }
+
+
+    // -------------------------------------------------------- Private Methods
+
+
+    /**
+     * Report a "bad request" error for the specified resource.  FIXME:  We
+     * should really be using the error reporting settings for this web
+     * application, but currently that code runs at the wrapper level rather
+     * than the context level.
+     *
+     * @param requestURI The request URI for the requested resource
+     * @param response The response we are creating
+     */
+    private void badRequest(String requestURI, HttpServletResponse response) {
+
+        try {
+            response.sendError(HttpServletResponse.SC_BAD_REQUEST, requestURI);
+        } catch (IllegalStateException e) {
+            ;
+        } catch (IOException e) {
+            ;
+        }
+
+    }
+    
+    
+    /**
+     * Report a "forbidden" error for the specified resource. 
+     *
+     * @param requestURI The request URI for the requested resource
+     * @param response The response we are creating
+     */
+    private void forbidden(String requestURI, HttpServletResponse response) {
+
+        try {
+            response.sendError(HttpServletResponse.SC_FORBIDDEN, requestURI);
+        } catch (IllegalStateException e) {
+            ;
+        } catch (IOException e) {
+            ;
+        }
+
+    }
+
+
+    /**
+     * Report a "not found" error for the specified resource.  FIXME:  We
+     * should really be using the error reporting settings for this web
+     * application, but currently that code runs at the wrapper level rather
+     * than the context level.
+     *
+     * @param requestURI The request URI for the requested resource
+     * @param response The response we are creating
+     */
+    private void notFound(String requestURI, HttpServletResponse response) {
+
+        try {
+            response.sendError(HttpServletResponse.SC_NOT_FOUND, requestURI);
+        } catch (IllegalStateException e) {
+            ;
+        } catch (IOException e) {
+            ;
+        }
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/core/StandardEngine.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/core/StandardEngine.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/core/StandardEngine.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,537 @@
+/*
+ * Copyright 1999-2001,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.util.List;
+
+import javax.management.MBeanServer;
+import javax.management.MalformedObjectNameException;
+import javax.management.ObjectName;
+
+import org.apache.catalina.Container;
+import org.apache.catalina.Engine;
+import org.apache.catalina.Host;
+import org.apache.catalina.LifecycleException;
+import org.apache.catalina.Realm;
+import org.apache.catalina.Service;
+import org.apache.catalina.realm.JAASRealm;
+import org.apache.catalina.util.ServerInfo;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.commons.modeler.Registry;
+import org.apache.commons.modeler.modules.MbeansSource;
+
+/**
+ * Standard implementation of the <b>Engine</b> interface.  Each
+ * child container must be a Host implementation to process the specific
+ * fully qualified host name of that virtual host. <br/>
+ * You can set the jvmRoute direct or with the System.property <b>jvmRoute</b>.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 303667 $ $Date: 2005-01-29 13:41:16 -0600 (Sat, 29 Jan 2005) $
+ */
+
+public class StandardEngine
+    extends ContainerBase
+    implements Engine {
+
+    private static Log log = LogFactory.getLog(StandardEngine.class);
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Create a new StandardEngine component with the default basic Valve.
+     */
+    public StandardEngine() {
+
+        super();
+        pipeline.setBasic(new StandardEngineValve());
+        /* Set the jmvRoute using the system property jvmRoute */
+        try {
+            setJvmRoute(System.getProperty("jvmRoute"));
+        } catch(Exception ex) {
+        }
+        // By default, the engine will hold the reloading thread
+        backgroundProcessorDelay = 10;
+
+    }
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * Host name to use when no server host, or an unknown host,
+     * is specified in the request.
+     */
+    private String defaultHost = null;
+
+
+    /**
+     * The descriptive information string for this implementation.
+     */
+    private static final String info =
+        "org.apache.catalina.core.StandardEngine/1.0";
+
+
+    /**
+     * The <code>Service</code> that owns this Engine, if any.
+     */
+    private Service service = null;
+
+    /** Allow the base dir to be specified explicitely for
+     * each engine. In time we should stop using catalina.base property -
+     * otherwise we loose some flexibility.
+     */
+    private String baseDir = null;
+
+    /** Optional mbeans config file. This will replace the "hacks" in
+     * jk and ServerListener. The mbeans file will support (transparent) 
+     * persistence - soon. It'll probably replace jk2.properties and could
+     * replace server.xml. Of course - the same beans could be loaded and 
+     * managed by an external entity - like the embedding app - which
+     *  can use a different persistence mechanism.
+     */ 
+    private String mbeansFile = null;
+    
+    /** Mbeans loaded by the engine.  
+     */ 
+    private List mbeans;
+    
+
+    /**
+     * The JVM Route ID for this Tomcat instance. All Route ID's must be unique
+     * across the cluster.
+     */
+    private String jvmRouteId;
+
+
+    // ------------------------------------------------------------- Properties
+
+    /** Provide a default in case no explicit configuration is set
+     *
+     * @return configured realm, or a JAAS realm by default
+     */
+    public Realm getRealm() {
+        Realm configured=super.getRealm();
+        // If no set realm has been called - default to JAAS
+        // This can be overriden at engine, context and host level  
+        if( configured==null ) {
+            configured=new JAASRealm();
+            this.setRealm( configured );
+        }
+        return configured;
+    }
+
+
+    /**
+     * Return the default host.
+     */
+    public String getDefaultHost() {
+
+        return (defaultHost);
+
+    }
+
+
+    /**
+     * Set the default host.
+     *
+     * @param host The new default host
+     */
+    public void setDefaultHost(String host) {
+
+        String oldDefaultHost = this.defaultHost;
+        if (host == null) {
+            this.defaultHost = null;
+        } else {
+            this.defaultHost = host.toLowerCase();
+        }
+        support.firePropertyChange("defaultHost", oldDefaultHost,
+                                   this.defaultHost);
+
+    }
+    
+    public void setName(String name ) {
+        if( domain != null ) {
+            // keep name==domain, ignore override
+            // we are already registered
+            super.setName( domain );
+            return;
+        }
+        // The engine name is used as domain
+        domain=name; // XXX should we set it in init() ? It shouldn't matter
+        super.setName( name );
+    }
+
+
+    /**
+     * Set the cluster-wide unique identifier for this Engine.
+     * This value is only useful in a load-balancing scenario.
+     * <p>
+     * This property should not be changed once it is set.
+     */
+    public void setJvmRoute(String routeId) {
+        jvmRouteId = routeId;
+    }
+
+
+    /**
+     * Retrieve the cluster-wide unique identifier for this Engine.
+     * This value is only useful in a load-balancing scenario.
+     */
+    public String getJvmRoute() {
+        return jvmRouteId;
+    }
+
+
+    /**
+     * Return the <code>Service</code> with which we are associated (if any).
+     */
+    public Service getService() {
+
+        return (this.service);
+
+    }
+
+
+    /**
+     * Set the <code>Service</code> with which we are associated (if any).
+     *
+     * @param service The service that owns this Engine
+     */
+    public void setService(Service service) {
+        this.service = service;
+    }
+
+    public String getMbeansFile() {
+        return mbeansFile;
+    }
+
+    public void setMbeansFile(String mbeansFile) {
+        this.mbeansFile = mbeansFile;
+    }
+
+    public String getBaseDir() {
+        if( baseDir==null ) {
+            baseDir=System.getProperty("catalina.base");
+        }
+        if( baseDir==null ) {
+            baseDir=System.getProperty("catalina.home");
+        }
+        return baseDir;
+    }
+
+    public void setBaseDir(String baseDir) {
+        this.baseDir = baseDir;
+    }
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Add a child Container, only if the proposed child is an implementation
+     * of Host.
+     *
+     * @param child Child container to be added
+     */
+    public void addChild(Container child) {
+
+        if (!(child instanceof Host))
+            throw new IllegalArgumentException
+                (sm.getString("standardEngine.notHost"));
+        super.addChild(child);
+
+    }
+
+
+    /**
+     * Return descriptive information about this Container implementation and
+     * the corresponding version number, in the format
+     * <code>&lt;description&gt;/&lt;version&gt;</code>.
+     */
+    public String getInfo() {
+
+        return (info);
+
+    }
+
+    /**
+     * Disallow any attempt to set a parent for this Container, since an
+     * Engine is supposed to be at the top of the Container hierarchy.
+     *
+     * @param container Proposed parent Container
+     */
+    public void setParent(Container container) {
+
+        throw new IllegalArgumentException
+            (sm.getString("standardEngine.notParent"));
+
+    }
+
+
+    private boolean initialized=false;
+    
+    public void init() {
+        if( initialized ) return;
+        initialized=true;
+
+        if( oname==null ) {
+            // not registered in JMX yet - standalone mode
+            try {
+                if (domain==null) {
+                    domain=getName();
+                }
+                if(log.isDebugEnabled())
+                    log.debug( "Register " + domain );
+                oname=new ObjectName(domain + ":type=Engine");
+                controller=oname;
+                Registry.getRegistry(null, null)
+                    .registerComponent(this, oname, null);
+            } catch( Throwable t ) {
+                log.info("Error registering ", t );
+            }
+        }
+
+        if( mbeansFile == null ) {
+            String defaultMBeansFile=getBaseDir() + "/conf/tomcat5-mbeans.xml";
+            File f=new File( defaultMBeansFile );
+            if( f.exists() ) mbeansFile=f.getAbsolutePath();
+        }
+        if( mbeansFile != null ) {
+            readEngineMbeans();
+        }
+        if( mbeans != null ) {
+            try {
+                Registry.getRegistry(null, null).invoke(mbeans, "init", false);
+            } catch (Exception e) {
+                log.error("Error in init() for " + mbeansFile, e);
+            }
+        }
+        
+        // not needed since the following if statement does the same thing the right way
+        // remove later after checking
+        //if( service==null ) {
+        //    try {
+        //        ObjectName serviceName=getParentName();        
+        //        if( mserver.isRegistered( serviceName )) {
+        //            log.info("Registering with the service ");
+        //            try {
+        //                mserver.invoke( serviceName, "setContainer",
+        //                        new Object[] { this },
+        //                        new String[] { "org.apache.catalina.Container" } );
+        //            } catch( Exception ex ) {
+        //               ex.printStackTrace();
+        //            }
+        //        }
+        //    } catch( Exception ex ) {
+        //        log.error("Error registering with service ");
+        //    }
+        //}
+        
+        if( service==null ) {
+            // for consistency...: we are probably in embeded mode
+            try {
+                service=new StandardService();
+                service.setContainer( this );
+                service.initialize();
+            } catch( Throwable t ) {
+                log.error(t);
+            }
+        }
+        
+    }
+    
+    public void destroy() throws LifecycleException {
+        if( ! initialized ) return;
+        initialized=false;
+        
+        // if we created it, make sure it's also destroyed
+        // this call implizit this.stop()
+        ((StandardService)service).destroy();
+
+        if( mbeans != null ) {
+            try {
+                Registry.getRegistry(null, null)
+                    .invoke(mbeans, "destroy", false);
+            } catch (Exception e) {
+                log.error(sm.getString("standardEngine.unregister.mbeans.failed" ,mbeansFile), e);
+            }
+        }
+        // 
+        if( mbeans != null ) {
+            try {
+                for( int i=0; i<mbeans.size() ; i++ ) {
+                    Registry.getRegistry(null, null)
+                        .unregisterComponent((ObjectName)mbeans.get(i));
+                }
+            } catch (Exception e) {
+                log.error(sm.getString("standardEngine.unregister.mbeans.failed", mbeansFile), e);
+            }
+        }
+        
+        // force all metadata to be reloaded.
+        // That doesn't affect existing beans. We should make it per
+        // registry - and stop using the static.
+        Registry.getRegistry(null, null).resetMetadata();
+        
+    }
+    
+    /**
+     * Start this Engine component.
+     *
+     * @exception LifecycleException if a startup error occurs
+     */
+    public void start() throws LifecycleException {
+        if( started ) {
+            return;
+        }
+        if( !initialized ) {
+            init();
+        }
+
+        // Look for a realm - that may have been configured earlier. 
+        // If the realm is added after context - it'll set itself.
+        if( realm == null ) {
+            ObjectName realmName=null;
+            try {
+                realmName=new ObjectName( domain + ":type=Realm");
+                if( mserver.isRegistered(realmName ) ) {
+                    mserver.invoke(realmName, "init", 
+                            new Object[] {},
+                            new String[] {}
+                    );            
+                }
+            } catch( Throwable t ) {
+                log.debug("No realm for this engine " + realmName);
+            }
+        }
+            
+        // Log our server identification information
+        //System.out.println(ServerInfo.getServerInfo());
+        if(log.isInfoEnabled())
+            log.info( "Starting Servlet Engine: " + ServerInfo.getServerInfo());
+        if( mbeans != null ) {
+            try {
+                Registry.getRegistry(null, null)
+                    .invoke(mbeans, "start", false);
+            } catch (Exception e) {
+                log.error("Error in start() for " + mbeansFile, e);
+            }
+        }
+
+        // Standard container startup
+        super.start();
+
+    }
+    
+    public void stop() throws LifecycleException {
+        super.stop();
+        if( mbeans != null ) {
+            try {
+                Registry.getRegistry(null, null).invoke(mbeans, "stop", false);
+            } catch (Exception e) {
+                log.error("Error in stop() for " + mbeansFile, e);
+            }
+        }
+    }
+
+
+    /**
+     * Return a String representation of this component.
+     */
+    public String toString() {
+
+        StringBuffer sb = new StringBuffer("StandardEngine[");
+        sb.append(getName());
+        sb.append("]");
+        return (sb.toString());
+
+    }
+
+
+    // ------------------------------------------------------ Protected Methods
+
+
+    // -------------------- JMX registration  --------------------
+
+    public ObjectName preRegister(MBeanServer server,
+                                  ObjectName name) throws Exception
+    {
+        super.preRegister(server,name);
+
+        this.setName( name.getDomain());
+
+        return name;
+    }
+
+    // FIXME Remove -- not used 
+    public ObjectName getParentName() throws MalformedObjectNameException {
+        if (getService()==null) {
+            return null;
+        }
+        String name = getService().getName();
+        ObjectName serviceName=new ObjectName(domain +
+                        ":type=Service,serviceName="+name);
+        return serviceName;                
+    }
+    
+    public ObjectName createObjectName(String domain, ObjectName parent)
+        throws Exception
+    {
+        if( log.isDebugEnabled())
+            log.debug("Create ObjectName " + domain + " " + parent );
+        return new ObjectName( domain + ":type=Engine");
+    }
+
+    
+    private void readEngineMbeans() {
+        try {
+            MbeansSource mbeansMB=new MbeansSource();
+            File mbeansF=new File( mbeansFile );
+            mbeansMB.setSource(mbeansF);
+            
+            Registry.getRegistry(null, null).registerComponent
+                (mbeansMB, domain + ":type=MbeansFile", null);
+            mbeansMB.load();
+            mbeansMB.init();
+            mbeansMB.setRegistry(Registry.getRegistry(null, null));
+            mbeans=mbeansMB.getMBeans();
+            
+        } catch( Throwable t ) {
+            log.error( "Error loading " + mbeansFile, t );
+        }
+        
+    }
+    
+    public String getDomain() {
+        if (domain!=null) {
+            return domain;
+        } else { 
+            return getName();
+        }
+    }
+    
+    public void setDomain(String domain) {
+        this.domain = domain;
+    }
+    
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/core/StandardEngineValve.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/core/StandardEngineValve.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/core/StandardEngineValve.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,111 @@
+/*
+ * Copyright 1999-2001,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.IOException;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.catalina.Host;
+import org.apache.catalina.connector.Request;
+import org.apache.catalina.connector.Response;
+import org.apache.catalina.util.StringManager;
+import org.apache.catalina.valves.ValveBase;
+
+
+/**
+ * Valve that implements the default basic behavior for the
+ * <code>StandardEngine</code> container implementation.
+ * <p>
+ * <b>USAGE CONSTRAINT</b>:  This implementation is likely to be useful only
+ * when processing HTTP requests.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302978 $ $Date: 2004-06-23 11:59:42 -0500 (Wed, 23 Jun 2004) $
+ */
+
+final class StandardEngineValve
+    extends ValveBase {
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The descriptive information related to this implementation.
+     */
+    private static final String info =
+        "org.apache.catalina.core.StandardEngineValve/1.0";
+
+
+    /**
+     * The string manager for this package.
+     */
+    private static final StringManager sm =
+        StringManager.getManager(Constants.Package);
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * Return descriptive information about this Valve implementation.
+     */
+    public String getInfo() {
+
+        return (info);
+
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Select the appropriate child Host to process this request,
+     * based on the requested server name.  If no matching Host can
+     * be found, return an appropriate HTTP error.
+     *
+     * @param request Request to be processed
+     * @param response Response to be produced
+     * @param valveContext Valve context used to forward to the next Valve
+     *
+     * @exception IOException if an input/output error occurred
+     * @exception ServletException if a servlet error occurred
+     */
+    public final void invoke(Request request, Response response)
+        throws IOException, ServletException {
+
+        // Select the Host to be used for this Request
+        Host host = request.getHost();
+        if (host == null) {
+            response.sendError
+                (HttpServletResponse.SC_BAD_REQUEST,
+                 sm.getString("standardEngine.noHost", 
+                              request.getServerName()));
+            return;
+        }
+
+        // Ask this Host to process this request
+        host.getPipeline().getFirst().invoke(request, response);
+
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/core/StandardHost.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/core/StandardHost.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/core/StandardHost.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,822 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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 javax.management.MBeanServer;
+import javax.management.ObjectName;
+
+import org.apache.catalina.Container;
+import org.apache.catalina.Context;
+import org.apache.catalina.Host;
+import org.apache.catalina.LifecycleException;
+import org.apache.catalina.Valve;
+import org.apache.catalina.startup.HostConfig;
+import org.apache.catalina.valves.ValveBase;
+import org.apache.commons.modeler.Registry;
+
+
+/**
+ * Standard implementation of the <b>Host</b> interface.  Each
+ * child container must be a Context implementation to process the
+ * requests directed to a particular web application.
+ *
+ * @author Craig R. McClanahan
+ * @author Remy Maucherat
+ * @version $Revision: 303666 $ $Date: 2005-01-29 13:38:37 -0600 (Sat, 29 Jan 2005) $
+ */
+
+public class StandardHost
+    extends ContainerBase
+    implements Host  
+ {
+    /* Why do we implement deployer and delegate to deployer ??? */
+
+    private static org.apache.commons.logging.Log log=
+        org.apache.commons.logging.LogFactory.getLog( StandardHost.class );
+    
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Create a new StandardHost component with the default basic Valve.
+     */
+    public StandardHost() {
+
+        super();
+        pipeline.setBasic(new StandardHostValve());
+
+    }
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The set of aliases for this Host.
+     */
+    private String[] aliases = new String[0];
+
+
+    /**
+     * The application root for this Host.
+     */
+    private String appBase = ".";
+
+
+    /**
+     * The auto deploy flag for this Host.
+     */
+    private boolean autoDeploy = true;
+
+
+    /**
+     * The Java class name of the default context configuration class
+     * for deployed web applications.
+     */
+    private String configClass =
+        "org.apache.catalina.startup.ContextConfig";
+
+
+    /**
+     * The Java class name of the default Context implementation class for
+     * deployed web applications.
+     */
+    private String contextClass =
+        "org.apache.catalina.core.StandardContext";
+
+
+    /**
+     * The deploy on startup flag for this Host.
+     */
+    private boolean deployOnStartup = true;
+
+
+    /**
+     * deploy Context XML config files property.
+     */
+    private boolean deployXML = true;
+
+
+    /**
+     * The Java class name of the default error reporter implementation class 
+     * for deployed web applications.
+     */
+    private String errorReportValveClass =
+        "org.apache.catalina.valves.ErrorReportValve";
+
+    /**
+     * The object name for the errorReportValve.
+     */
+    private ObjectName errorReportValveObjectName = null;
+
+    /**
+     * The descriptive information string for this implementation.
+     */
+    private static final String info =
+        "org.apache.catalina.core.StandardHost/1.0";
+
+
+    /**
+     * The live deploy flag for this Host.
+     */
+    private boolean liveDeploy = true;
+
+
+    /**
+     * Unpack WARs property.
+     */
+    private boolean unpackWARs = true;
+
+
+    /**
+     * Work Directory base for applications.
+     */
+    private String workDir = null;
+
+
+    /**
+     * Attribute value used to turn on/off XML validation
+     */
+     private boolean xmlValidation = false;
+
+
+    /**
+     * Attribute value used to turn on/off XML namespace awarenes.
+     */
+     private boolean xmlNamespaceAware = false;
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * Return the application root for this Host.  This can be an absolute
+     * pathname, a relative pathname, or a URL.
+     */
+    public String getAppBase() {
+
+        return (this.appBase);
+
+    }
+
+
+    /**
+     * Set the application root for this Host.  This can be an absolute
+     * pathname, a relative pathname, or a URL.
+     *
+     * @param appBase The new application root
+     */
+    public void setAppBase(String appBase) {
+
+        String oldAppBase = this.appBase;
+        this.appBase = appBase;
+        support.firePropertyChange("appBase", oldAppBase, this.appBase);
+
+    }
+
+
+    /**
+     * Return the value of the auto deploy flag.  If true, it indicates that 
+     * this host's child webapps will be dynamically deployed.
+     */
+    public boolean getAutoDeploy() {
+
+        return (this.autoDeploy);
+
+    }
+
+
+    /**
+     * Set the auto deploy flag value for this host.
+     * 
+     * @param autoDeploy The new auto deploy flag
+     */
+    public void setAutoDeploy(boolean autoDeploy) {
+
+        boolean oldAutoDeploy = this.autoDeploy;
+        this.autoDeploy = autoDeploy;
+        support.firePropertyChange("autoDeploy", oldAutoDeploy, 
+                                   this.autoDeploy);
+
+    }
+
+
+    /**
+     * Return the Java class name of the context configuration class
+     * for new web applications.
+     */
+    public String getConfigClass() {
+
+        return (this.configClass);
+
+    }
+
+
+    /**
+     * Set the Java class name of the context configuration class
+     * for new web applications.
+     *
+     * @param configClass The new context configuration class
+     */
+    public void setConfigClass(String configClass) {
+
+        String oldConfigClass = this.configClass;
+        this.configClass = configClass;
+        support.firePropertyChange("configClass",
+                                   oldConfigClass, this.configClass);
+
+    }
+
+
+    /**
+     * Return the Java class name of the Context implementation class
+     * for new web applications.
+     */
+    public String getContextClass() {
+
+        return (this.contextClass);
+
+    }
+
+
+    /**
+     * Set the Java class name of the Context implementation class
+     * for new web applications.
+     *
+     * @param contextClass The new context implementation class
+     */
+    public void setContextClass(String contextClass) {
+
+        String oldContextClass = this.contextClass;
+        this.contextClass = contextClass;
+        support.firePropertyChange("contextClass",
+                                   oldContextClass, this.contextClass);
+
+    }
+
+
+    /**
+     * Return the value of the deploy on startup flag.  If true, it indicates 
+     * that this host's child webapps should be discovred and automatically 
+     * deployed at startup time.
+     */
+    public boolean getDeployOnStartup() {
+
+        return (this.deployOnStartup);
+
+    }
+
+
+    /**
+     * Set the deploy on startup flag value for this host.
+     * 
+     * @param deployOnStartup The new deploy on startup flag
+     */
+    public void setDeployOnStartup(boolean deployOnStartup) {
+
+        boolean oldDeployOnStartup = this.deployOnStartup;
+        this.deployOnStartup = deployOnStartup;
+        support.firePropertyChange("deployOnStartup", oldDeployOnStartup, 
+                                   this.deployOnStartup);
+
+    }
+
+
+    /**
+     * Deploy XML Context config files flag accessor.
+     */
+    public boolean isDeployXML() {
+
+        return (deployXML);
+
+    }
+
+
+    /**
+     * Deploy XML Context config files flag mutator.
+     */
+    public void setDeployXML(boolean deployXML) {
+
+        this.deployXML = deployXML;
+
+    }
+
+
+    /**
+     * Return the value of the live deploy flag.  If true, it indicates that 
+     * a background thread should be started that looks for web application
+     * context files, WAR files, or unpacked directories being dropped in to
+     * the <code>appBase</code> directory, and deploys new ones as they are
+     * encountered.
+     */
+    public boolean getLiveDeploy() {
+        return (this.autoDeploy);
+    }
+
+
+    /**
+     * Set the live deploy flag value for this host.
+     * 
+     * @param liveDeploy The new live deploy flag
+     */
+    public void setLiveDeploy(boolean liveDeploy) {
+        setAutoDeploy(liveDeploy);
+    }
+
+
+    /**
+     * Return the Java class name of the error report valve class
+     * for new web applications.
+     */
+    public String getErrorReportValveClass() {
+
+        return (this.errorReportValveClass);
+
+    }
+
+
+    /**
+     * Set the Java class name of the error report valve class
+     * for new web applications.
+     *
+     * @param errorReportValveClass The new error report valve class
+     */
+    public void setErrorReportValveClass(String errorReportValveClass) {
+
+        String oldErrorReportValveClassClass = this.errorReportValveClass;
+        this.errorReportValveClass = errorReportValveClass;
+        support.firePropertyChange("errorReportValveClass",
+                                   oldErrorReportValveClassClass, 
+                                   this.errorReportValveClass);
+
+    }
+
+
+    /**
+     * Return the canonical, fully qualified, name of the virtual host
+     * this Container represents.
+     */
+    public String getName() {
+
+        return (name);
+
+    }
+
+
+    /**
+     * Set the canonical, fully qualified, name of the virtual host
+     * this Container represents.
+     *
+     * @param name Virtual host name
+     *
+     * @exception IllegalArgumentException if name is null
+     */
+    public void setName(String name) {
+
+        if (name == null)
+            throw new IllegalArgumentException
+                (sm.getString("standardHost.nullName"));
+
+        name = name.toLowerCase();      // Internally all names are lower case
+
+        String oldName = this.name;
+        this.name = name;
+        support.firePropertyChange("name", oldName, this.name);
+
+    }
+
+
+    /**
+     * Unpack WARs flag accessor.
+     */
+    public boolean isUnpackWARs() {
+
+        return (unpackWARs);
+
+    }
+
+
+    /**
+     * Unpack WARs flag mutator.
+     */
+    public void setUnpackWARs(boolean unpackWARs) {
+
+        this.unpackWARs = unpackWARs;
+
+    }
+
+     /**
+     * Set the validation feature of the XML parser used when
+     * parsing xml instances.
+     * @param xmlValidation true to enable xml instance validation
+     */
+    public void setXmlValidation(boolean xmlValidation){
+        
+        this.xmlValidation = xmlValidation;
+
+    }
+
+    /**
+     * Get the server.xml <host> attribute's xmlValidation.
+     * @return true if validation is enabled.
+     *
+     */
+    public boolean getXmlValidation(){
+        return xmlValidation;
+    }
+
+    /**
+     * Get the server.xml <host> attribute's xmlNamespaceAware.
+     * @return true if namespace awarenes is enabled.
+     *
+     */
+    public boolean getXmlNamespaceAware(){
+        return xmlNamespaceAware;
+    }
+
+
+    /**
+     * Set the namespace aware feature of the XML parser used when
+     * parsing xml instances.
+     * @param xmlNamespaceAware true to enable namespace awareness
+     */
+    public void setXmlNamespaceAware(boolean xmlNamespaceAware){
+        this.xmlNamespaceAware=xmlNamespaceAware;
+    }    
+    
+    /**
+     * Host work directory base.
+     */
+    public String getWorkDir() {
+
+        return (workDir);
+    }
+
+
+    /**
+     * Host work directory base.
+     */
+    public void setWorkDir(String workDir) {
+
+        this.workDir = workDir;
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Add an alias name that should be mapped to this same Host.
+     *
+     * @param alias The alias to be added
+     */
+    public void addAlias(String alias) {
+
+        alias = alias.toLowerCase();
+
+        // Skip duplicate aliases
+        for (int i = 0; i < aliases.length; i++) {
+            if (aliases[i].equals(alias))
+                return;
+        }
+
+        // Add this alias to the list
+        String newAliases[] = new String[aliases.length + 1];
+        for (int i = 0; i < aliases.length; i++)
+            newAliases[i] = aliases[i];
+        newAliases[aliases.length] = alias;
+
+        aliases = newAliases;
+
+        // Inform interested listeners
+        fireContainerEvent(ADD_ALIAS_EVENT, alias);
+
+    }
+
+
+    /**
+     * Add a child Container, only if the proposed child is an implementation
+     * of Context.
+     *
+     * @param child Child container to be added
+     */
+    public void addChild(Container child) {
+
+        if (!(child instanceof Context))
+            throw new IllegalArgumentException
+                (sm.getString("standardHost.notContext"));
+        super.addChild(child);
+
+    }
+
+
+    /**
+     * Return the set of alias names for this Host.  If none are defined,
+     * a zero length array is returned.
+     */
+    public String[] findAliases() {
+
+        return (this.aliases);
+
+    }
+
+
+    /**
+     * Return descriptive information about this Container implementation and
+     * the corresponding version number, in the format
+     * <code>&lt;description&gt;/&lt;version&gt;</code>.
+     */
+    public String getInfo() {
+
+        return (info);
+
+    }
+
+
+    /**
+     * Return the Context that would be used to process the specified
+     * host-relative request URI, if any; otherwise return <code>null</code>.
+     *
+     * @param uri Request URI to be mapped
+     */
+    public Context map(String uri) {
+
+        if (log.isDebugEnabled())
+            log.debug("Mapping request URI '" + uri + "'");
+        if (uri == null)
+            return (null);
+
+        // Match on the longest possible context path prefix
+        if (log.isTraceEnabled())
+            log.trace("  Trying the longest context path prefix");
+        Context context = null;
+        String mapuri = uri;
+        while (true) {
+            context = (Context) findChild(mapuri);
+            if (context != null)
+                break;
+            int slash = mapuri.lastIndexOf('/');
+            if (slash < 0)
+                break;
+            mapuri = mapuri.substring(0, slash);
+        }
+
+        // If no Context matches, select the default Context
+        if (context == null) {
+            if (log.isTraceEnabled())
+                log.trace("  Trying the default context");
+            context = (Context) findChild("");
+        }
+
+        // Complain if no Context has been selected
+        if (context == null) {
+            log.error(sm.getString("standardHost.mappingError", uri));
+            return (null);
+        }
+
+        // Return the mapped Context (if any)
+        if (log.isDebugEnabled())
+            log.debug(" Mapped to context '" + context.getPath() + "'");
+        return (context);
+
+    }
+
+
+    /**
+     * Remove the specified alias name from the aliases for this Host.
+     *
+     * @param alias Alias name to be removed
+     */
+    public void removeAlias(String alias) {
+
+        alias = alias.toLowerCase();
+
+        synchronized (aliases) {
+
+            // Make sure this alias is currently present
+            int n = -1;
+            for (int i = 0; i < aliases.length; i++) {
+                if (aliases[i].equals(alias)) {
+                    n = i;
+                    break;
+                }
+            }
+            if (n < 0)
+                return;
+
+            // Remove the specified alias
+            int j = 0;
+            String results[] = new String[aliases.length - 1];
+            for (int i = 0; i < aliases.length; i++) {
+                if (i != n)
+                    results[j++] = aliases[i];
+            }
+            aliases = results;
+
+        }
+
+        // Inform interested listeners
+        fireContainerEvent(REMOVE_ALIAS_EVENT, alias);
+
+    }
+
+
+    /**
+     * Return a String representation of this component.
+     */
+    public String toString() {
+
+        StringBuffer sb = new StringBuffer();
+        if (getParent() != null) {
+            sb.append(getParent().toString());
+            sb.append(".");
+        }
+        sb.append("StandardHost[");
+        sb.append(getName());
+        sb.append("]");
+        return (sb.toString());
+
+    }
+
+
+    /**
+     * Start this host.
+     *
+     * @exception LifecycleException if this component detects a fatal error
+     *  that prevents it from being started
+     */
+    public synchronized void start() throws LifecycleException {
+        if( started ) {
+            return;
+        }
+        if( ! initialized )
+            init();
+
+        // Look for a realm - that may have been configured earlier. 
+        // If the realm is added after context - it'll set itself.
+        if( realm == null ) {
+            ObjectName realmName=null;
+            try {
+                realmName=new ObjectName( domain + ":type=Realm,host=" + getName());
+                if( mserver.isRegistered(realmName ) ) {
+                    mserver.invoke(realmName, "init", 
+                            new Object[] {},
+                            new String[] {}
+                    );            
+                }
+            } catch( Throwable t ) {
+                log.debug("No realm for this host " + realmName);
+            }
+        }
+            
+        // Set error report valve
+        if ((errorReportValveClass != null)
+            && (!errorReportValveClass.equals(""))) {
+            try {
+                boolean found = false;
+                if(errorReportValveObjectName != null) {
+                    ObjectName[] names = 
+                        ((StandardPipeline)pipeline).getValveObjectNames();
+                    for (int i=0; !found && i<names.length; i++)
+                        if(errorReportValveObjectName.equals(names[i]))
+                            found = true ;
+                    }
+                    if(!found) {          	
+                        Valve valve = (Valve) Class.forName(errorReportValveClass)
+                        .newInstance();
+                        addValve(valve);
+                        errorReportValveObjectName = ((ValveBase)valve).getObjectName() ;
+                    }
+            } catch (Throwable t) {
+                log.error(sm.getString
+                    ("standardHost.invalidErrorReportValveClass", 
+                     errorReportValveClass));
+            }
+        }
+        if(log.isInfoEnabled()) {
+            if (xmlValidation)
+                log.info( sm.getString("standardHost.validationEnabled"));
+            else
+                log.info( sm.getString("standardHost.validationDisabled"));
+        }
+        super.start();
+
+    }
+
+
+    // -------------------- JMX  --------------------
+    /**
+      * Return the MBean Names of the Valves assoicated with this Host
+      *
+      * @exception Exception if an MBean cannot be created or registered
+      */
+     public String [] getValveNames()
+         throws Exception
+    {
+         Valve [] valves = this.getValves();
+         String [] mbeanNames = new String[valves.length];
+         for (int i = 0; i < valves.length; i++) {
+             if( valves[i] == null ) continue;
+             if( ((ValveBase)valves[i]).getObjectName() == null ) continue;
+             mbeanNames[i] = ((ValveBase)valves[i]).getObjectName().toString();
+         }
+
+         return mbeanNames;
+
+     }
+
+    public String[] getAliases() {
+        return aliases;
+    }
+
+    private boolean initialized=false;
+    
+    public void init() {
+        if( initialized ) return;
+        initialized=true;
+        
+        // already registered.
+        if( getParent() == null ) {
+            try {
+                // Register with the Engine
+                ObjectName serviceName=new ObjectName(domain + 
+                                        ":type=Engine");
+
+                HostConfig deployer = new HostConfig();
+                addLifecycleListener(deployer);                
+                if( mserver.isRegistered( serviceName )) {
+                    if(log.isDebugEnabled())
+                        log.debug("Registering "+ serviceName +" with the Engine");
+                    mserver.invoke( serviceName, "addChild",
+                            new Object[] { this },
+                            new String[] { "org.apache.catalina.Container" } );
+                }
+            } catch( Exception ex ) {
+                log.error("Host registering failed!",ex);
+            }
+        }
+        
+        if( oname==null ) {
+            // not registered in JMX yet - standalone mode
+            try {
+                StandardEngine engine=(StandardEngine)parent;
+                domain=engine.getName();
+                if(log.isDebugEnabled())
+                    log.debug( "Register host " + getName() + " with domain "+ domain );
+                oname=new ObjectName(domain + ":type=Host,host=" +
+                        this.getName());
+                controller = oname;
+                Registry.getRegistry(null, null)
+                    .registerComponent(this, oname, null);
+            } catch( Throwable t ) {
+                log.error("Host registering failed!", t );
+            }
+        }
+    }
+
+    public void destroy() throws Exception {
+        // destroy our child containers, if any
+        Container children[] = findChildren();
+        super.destroy();
+        for (int i = 0; i < children.length; i++) {
+            if(children[i] instanceof StandardContext)
+                ((StandardContext)children[i]).destroy();
+        }
+      
+    }
+    
+    public ObjectName preRegister(MBeanServer server, ObjectName oname ) 
+        throws Exception
+    {
+        ObjectName res=super.preRegister(server, oname);
+        String name=oname.getKeyProperty("host");
+        if( name != null )
+            setName( name );
+        return res;        
+    }
+    
+    public ObjectName createObjectName(String domain, ObjectName parent)
+        throws Exception
+    {
+        if( log.isDebugEnabled())
+            log.debug("Create ObjectName " + domain + " " + parent );
+        return new ObjectName( domain + ":type=Host,host=" + getName());
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/core/StandardHostValve.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/core/StandardHostValve.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/core/StandardHostValve.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,382 @@
+/*
+ * Copyright 1999-2001,2004 The Apache Software Foundation.
+ *
+ * Licensed 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.IOException;
+
+import javax.servlet.RequestDispatcher;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.catalina.Context;
+import org.apache.catalina.Globals;
+import org.apache.catalina.Wrapper;
+import org.apache.catalina.connector.ClientAbortException;
+import org.apache.catalina.connector.Request;
+import org.apache.catalina.connector.Response;
+import org.apache.catalina.deploy.ErrorPage;
+import org.apache.catalina.util.RequestUtil;
+import org.apache.catalina.util.StringManager;
+import org.apache.catalina.valves.ValveBase;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+
+/**
+ * Valve that implements the default basic behavior for the
+ * <code>StandardHost</code> container implementation.
+ * <p>
+ * <b>USAGE CONSTRAINT</b>:  This implementation is likely to be useful only
+ * when processing HTTP requests.
+ *
+ * @author Craig R. McClanahan
+ * @author Remy Maucherat
+ * @version $Revision: 304105 $ $Date: 2005-09-27 14:20:54 -0500 (Tue, 27 Sep 2005) $
+ */
+
+final class StandardHostValve
+    extends ValveBase {
+
+
+    private static Log log = LogFactory.getLog(StandardHostValve.class);
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The descriptive information related to this implementation.
+     */
+    private static final String info =
+        "org.apache.catalina.core.StandardHostValve/1.0";
+
+
+    /**
+     * The string manager for this package.
+     */
+    private static final StringManager sm =
+        StringManager.getManager(Constants.Package);
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * Return descriptive information about this Valve implementation.
+     */
+    public String getInfo() {
+
+        return (info);
+
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Select the appropriate child Context to process this request,
+     * based on the specified request URI.  If no matching Context can
+     * be found, return an appropriate HTTP error.
+     *
+     * @param request Request to be processed
+     * @param response Response to be produced
+     * @param valveContext Valve context used to forward to the next Valve
+     *
+     * @exception IOException if an input/output error occurred
+     * @exception ServletException if a servlet error occurred
+     */
+    public final void invoke(Request request, Response response)
+        throws IOException, ServletException {
+
+        // Select the Context to be used for this Request
+        Context context = request.getContext();
+        if (context == null) {
+            response.sendError
+                (HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
+                 sm.getString("standardHost.noContext"));
+            return;
+        }
+
+        // Bind the context CL to the current thread
+        if( context.getLoader() != null ) {
+            // Not started - it should check for availability first
+            // This should eventually move to Engine, it's generic.
+            Thread.currentThread().setContextClassLoader
+                    (context.getLoader().getClassLoader());
+        }
+
+        // Ask this Context to process this request
+        context.getPipeline().getFirst().invoke(request, response);
+
+        // Error page processing
+        response.setSuspended(false);
+
+        Throwable t = (Throwable) request.getAttribute(Globals.EXCEPTION_ATTR);
+
+        if (t != null) {
+            throwable(request, response, t);
+        } else {
+            status(request, response);
+        }
+
+        // Restore the context classloader
+        Thread.currentThread().setContextClassLoader
+            (StandardHostValve.class.getClassLoader());
+
+    }
+
+
+    // ------------------------------------------------------ Protected Methods
+
+
+    /**
+     * Handle the specified Throwable encountered while processing
+     * the specified Request to produce the specified Response.  Any
+     * exceptions that occur during generation of the exception report are
+     * logged and swallowed.
+     *
+     * @param request The request being processed
+     * @param response The response being generated
+     * @param throwable The exception that occurred (which possibly wraps
+     *  a root cause exception
+     */
+    protected void throwable(Request request, Response response,
+                             Throwable throwable) {
+        Context context = request.getContext();
+        if (context == null)
+            return;
+
+        Throwable realError = throwable;
+
+        if (realError instanceof ServletException) {
+            realError = ((ServletException) realError).getRootCause();
+            if (realError == null) {
+                realError = throwable;
+            }
+        }
+
+        // If this is an aborted request from a client just log it and return
+        if (realError instanceof ClientAbortException ) {
+            if (log.isDebugEnabled()) {
+                log.debug
+                    (sm.getString("standardHost.clientAbort",
+                        realError.getCause().getMessage()));
+            }
+            return;
+        }
+
+        ErrorPage errorPage = findErrorPage(context, throwable);
+        if ((errorPage == null) && (realError != throwable)) {
+            errorPage = findErrorPage(context, realError);
+        }
+
+        if (errorPage != null) {
+            response.setAppCommitted(false);
+            request.setAttribute
+                (ApplicationFilterFactory.DISPATCHER_REQUEST_PATH_ATTR,
+                 errorPage.getLocation());
+            request.setAttribute(ApplicationFilterFactory.DISPATCHER_TYPE_ATTR,
+                              new Integer(ApplicationFilterFactory.ERROR));
+            request.setAttribute
+                (Globals.STATUS_CODE_ATTR,
+                 new Integer(HttpServletResponse.SC_INTERNAL_SERVER_ERROR));
+            request.setAttribute(Globals.ERROR_MESSAGE_ATTR,
+                              throwable.getMessage());
+            request.setAttribute(Globals.EXCEPTION_ATTR,
+                              realError);
+            Wrapper wrapper = request.getWrapper();
+            if (wrapper != null)
+                request.setAttribute(Globals.SERVLET_NAME_ATTR,
+                                  wrapper.getName());
+            request.setAttribute(Globals.EXCEPTION_PAGE_ATTR,
+                                 request.getRequestURI());
+            request.setAttribute(Globals.EXCEPTION_TYPE_ATTR,
+                              realError.getClass());
+            if (custom(request, response, errorPage)) {
+                try {
+                    response.flushBuffer();
+                } catch (IOException e) {
+                    container.getLogger().warn("Exception Processing " + errorPage, e);
+                }
+            }
+        } else {
+            // A custom error-page has not been defined for the exception
+            // that was thrown during request processing. Check if an
+            // error-page for error code 500 was specified and if so,
+            // send that page back as the response.
+            response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
+            // The response is an error
+            response.setError();
+
+            status(request, response);
+        }
+
+
+    }
+
+
+    /**
+     * Handle the HTTP status code (and corresponding message) generated
+     * while processing the specified Request to produce the specified
+     * Response.  Any exceptions that occur during generation of the error
+     * report are logged and swallowed.
+     *
+     * @param request The request being processed
+     * @param response The response being generated
+     */
+    protected void status(Request request, Response response) {
+
+        int statusCode = response.getStatus();
+
+        // Handle a custom error page for this status code
+        Context context = request.getContext();
+        if (context == null)
+            return;
+
+        /* Only look for error pages when isError() is set.
+         * isError() is set when response.sendError() is invoked. This
+         * allows custom error pages without relying on default from
+         * web.xml.
+         */
+        if (!response.isError())
+            return;
+
+        ErrorPage errorPage = context.findErrorPage(statusCode);
+        if (errorPage != null) {
+            response.setAppCommitted(false);
+            request.setAttribute(Globals.STATUS_CODE_ATTR,
+                              new Integer(statusCode));
+
+            String message = RequestUtil.filter(response.getMessage());
+            if (message == null)
+                message = "";
+            request.setAttribute(Globals.ERROR_MESSAGE_ATTR, message);
+            request.setAttribute
+                (ApplicationFilterFactory.DISPATCHER_REQUEST_PATH_ATTR,
+                 errorPage.getLocation());
+            request.setAttribute(ApplicationFilterFactory.DISPATCHER_TYPE_ATTR,
+                              new Integer(ApplicationFilterFactory.ERROR));
+
+
+            Wrapper wrapper = request.getWrapper();
+            if (wrapper != null)
+                request.setAttribute(Globals.SERVLET_NAME_ATTR,
+                                  wrapper.getName());
+            request.setAttribute(Globals.EXCEPTION_PAGE_ATTR,
+                                 request.getRequestURI());
+            if (custom(request, response, errorPage)) {
+                try {
+                    response.flushBuffer();
+                } catch (IOException e) {
+                    container.getLogger().warn("Exception Processing " + errorPage, e);
+                }
+            }
+        }
+
+    }
+
+
+    /**
+     * Find and return the ErrorPage instance for the specified exception's
+     * class, or an ErrorPage instance for the closest superclass for which
+     * there is such a definition.  If no associated ErrorPage instance is
+     * found, return <code>null</code>.
+     *
+     * @param context The Context in which to search
+     * @param exception The exception for which to find an ErrorPage
+     */
+    protected static ErrorPage findErrorPage
+        (Context context, Throwable exception) {
+
+        if (exception == null)
+            return (null);
+        Class clazz = exception.getClass();
+        String name = clazz.getName();
+        while (!Object.class.equals(clazz)) {
+            ErrorPage errorPage = context.findErrorPage(name);
+            if (errorPage != null)
+                return (errorPage);
+            clazz = clazz.getSuperclass();
+            if (clazz == null)
+                break;
+            name = clazz.getName();
+        }
+        return (null);
+
+    }
+
+
+    /**
+     * Handle an HTTP status code or Java exception by forwarding control
+     * to the location included in the specified errorPage object.  It is
+     * assumed that the caller has already recorded any request attributes
+     * that are to be forwarded to this page.  Return <code>true</code> if
+     * we successfully utilized the specified error page location, or
+     * <code>false</code> if the default error report should be rendered.
+     *
+     * @param request The request being processed
+     * @param response The response being generated
+     * @param errorPage The errorPage directive we are obeying
+     */
+    protected boolean custom(Request request, Response response,
+                             ErrorPage errorPage) {
+
+        if (container.getLogger().isDebugEnabled())
+            container.getLogger().debug("Processing " + errorPage);
+
+        request.setPathInfo(errorPage.getLocation());
+
+        try {
+
+            // Reset the response if possible (else IllegalStateException)
+            //hres.reset();
+            // Reset the response (keeping the real error code and message)
+            Integer statusCodeObj =
+                (Integer) request.getAttribute(Globals.STATUS_CODE_ATTR);
+            int statusCode = statusCodeObj.intValue();
+            String message =
+                (String) request.getAttribute(Globals.ERROR_MESSAGE_ATTR);
+            response.reset(statusCode, message);
+
+            // Forward control to the specified location
+            ServletContext servletContext =
+                request.getContext().getServletContext();
+            RequestDispatcher rd =
+                servletContext.getRequestDispatcher(errorPage.getLocation());
+            rd.forward(request.getRequest(), response.getResponse());
+
+            // If we forward, the response is suspended again
+            response.setSuspended(false);
+
+            // Indicate that we have successfully processed this custom page
+            return (true);
+
+        } catch (Throwable t) {
+
+            // Report our failure to process this custom page
+            container.getLogger().error("Exception Processing " + errorPage, t);
+            return (false);
+
+        }
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/core/StandardPipeline.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/core/StandardPipeline.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/core/StandardPipeline.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,561 @@
+/*
+ * Copyright 1999-2001,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.util.ArrayList;
+
+import javax.management.ObjectName;
+
+import org.apache.catalina.Contained;
+import org.apache.catalina.Container;
+import org.apache.catalina.Lifecycle;
+import org.apache.catalina.LifecycleException;
+import org.apache.catalina.LifecycleListener;
+import org.apache.catalina.Pipeline;
+import org.apache.catalina.Valve;
+import org.apache.catalina.util.LifecycleSupport;
+import org.apache.catalina.util.StringManager;
+import org.apache.catalina.valves.ValveBase;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.commons.modeler.Registry;
+
+
+/**
+ * Standard implementation of a processing <b>Pipeline</b> that will invoke
+ * a series of Valves that have been configured to be called in order.  This
+ * implementation can be used for any type of Container.
+ *
+ * <b>IMPLEMENTATION WARNING</b> - This implementation assumes that no
+ * calls to <code>addValve()</code> or <code>removeValve</code> are allowed
+ * while a request is currently being processed.  Otherwise, the mechanism
+ * by which per-thread state is maintained will need to be modified.
+ *
+ * @author Craig R. McClanahan
+ */
+
+public class StandardPipeline
+    implements Pipeline, Contained, Lifecycle 
+ {
+
+    private static Log log = LogFactory.getLog(StandardPipeline.class);
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Construct a new StandardPipeline instance with no associated Container.
+     */
+    public StandardPipeline() {
+
+        this(null);
+
+    }
+
+
+    /**
+     * Construct a new StandardPipeline instance that is associated with the
+     * specified Container.
+     *
+     * @param container The container we should be associated with
+     */
+    public StandardPipeline(Container container) {
+
+        super();
+        setContainer(container);
+
+    }
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The basic Valve (if any) associated with this Pipeline.
+     */
+    protected Valve basic = null;
+
+
+    /**
+     * The Container with which this Pipeline is associated.
+     */
+    protected Container container = null;
+
+
+    /**
+     * Descriptive information about this implementation.
+     */
+    protected String info = "org.apache.catalina.core.StandardPipeline/1.0";
+
+
+    /**
+     * The lifecycle event support for this component.
+     */
+    protected LifecycleSupport lifecycle = new LifecycleSupport(this);
+
+
+    /**
+     * The string manager for this package.
+     */
+    protected static StringManager sm =
+        StringManager.getManager(Constants.Package);
+
+
+    /**
+     * Has this component been started yet?
+     */
+    protected boolean started = false;
+
+
+    /**
+     * The first valve associated with this Pipeline.
+     */
+    protected Valve first = null;
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Return descriptive information about this implementation class.
+     */
+    public String getInfo() {
+
+        return (this.info);
+
+    }
+
+
+    // ------------------------------------------------------ Contained Methods
+
+
+    /**
+     * Return the Container with which this Pipeline is associated.
+     */
+    public Container getContainer() {
+
+        return (this.container);
+
+    }
+
+
+    /**
+     * Set the Container with which this Pipeline is associated.
+     *
+     * @param container The new associated container
+     */
+    public void setContainer(Container container) {
+
+        this.container = container;
+
+    }
+
+
+    // ------------------------------------------------------ Lifecycle Methods
+
+
+    /**
+     * Add a lifecycle event listener to this component.
+     *
+     * @param listener The listener to add
+     */
+    public void addLifecycleListener(LifecycleListener listener) {
+
+        lifecycle.addLifecycleListener(listener);
+
+    }
+
+
+    /**
+     * Get the lifecycle listeners associated with this lifecycle. If this 
+     * Lifecycle has no listeners registered, a zero-length array is returned.
+     */
+    public LifecycleListener[] findLifecycleListeners() {
+
+        return lifecycle.findLifecycleListeners();
+
+    }
+
+
+    /**
+     * Remove a lifecycle event listener from this component.
+     *
+     * @param listener The listener to remove
+     */
+    public void removeLifecycleListener(LifecycleListener listener) {
+
+        lifecycle.removeLifecycleListener(listener);
+
+    }
+
+    /**
+     * Prepare for active use of the public methods of this Component.
+     *
+     * @exception LifecycleException if this component detects a fatal error
+     *  that prevents it from being started
+     */
+    public synchronized void start() throws LifecycleException {
+
+        // Validate and update our current component state
+        if (started)
+            throw new LifecycleException
+                (sm.getString("standardPipeline.alreadyStarted"));
+
+        // Notify our interested LifecycleListeners
+        lifecycle.fireLifecycleEvent(BEFORE_START_EVENT, null);
+
+        started = true;
+
+        // Start the Valves in our pipeline (including the basic), if any
+        Valve current = first;
+        if (current == null) {
+        	current = basic;
+        }
+        while (current != null) {
+            if (current instanceof Lifecycle)
+                ((Lifecycle) current).start();
+            registerValve(current);
+        	current = current.getNext();
+        }
+
+        // Notify our interested LifecycleListeners
+        lifecycle.fireLifecycleEvent(START_EVENT, null);
+
+        // Notify our interested LifecycleListeners
+        lifecycle.fireLifecycleEvent(AFTER_START_EVENT, null);
+
+    }
+
+
+    /**
+     * Gracefully shut down active use of the public methods of this Component.
+     *
+     * @exception LifecycleException if this component detects a fatal error
+     *  that needs to be reported
+     */
+    public synchronized void stop() throws LifecycleException {
+
+        // Validate and update our current component state
+        if (!started)
+            throw new LifecycleException
+                (sm.getString("standardPipeline.notStarted"));
+
+        // Notify our interested LifecycleListeners
+        lifecycle.fireLifecycleEvent(BEFORE_STOP_EVENT, null);
+
+        // Notify our interested LifecycleListeners
+        lifecycle.fireLifecycleEvent(STOP_EVENT, null);
+        started = false;
+
+        // Stop the Valves in our pipeline (including the basic), if any
+        Valve current = first;
+        if (current == null) {
+        	current = basic;
+        }
+        while (current != null) {
+            if (current instanceof Lifecycle)
+                ((Lifecycle) current).stop();
+            unregisterValve(current);
+        	current = current.getNext();
+        }
+
+        // Notify our interested LifecycleListeners
+        lifecycle.fireLifecycleEvent(AFTER_STOP_EVENT, null);
+    }
+
+    private void registerValve(Valve valve) {
+
+        if( valve instanceof ValveBase &&
+                ((ValveBase)valve).getObjectName()==null ) {
+            try {
+                
+                String domain=((ContainerBase)container).getDomain();
+                if( container instanceof StandardContext ) {
+                    domain=((StandardContext)container).getEngineName();
+                }
+                if( container instanceof StandardWrapper) {
+                    Container ctx=((StandardWrapper)container).getParent();
+                    domain=((StandardContext)ctx).getEngineName();
+                }
+                ObjectName vname=((ValveBase)valve).createObjectName(
+                        domain,
+                        ((ContainerBase)container).getJmxName());
+                if( vname != null ) {
+                    ((ValveBase)valve).setObjectName(vname);
+                    Registry.getRegistry(null, null).registerComponent
+                        (valve, vname, valve.getClass().getName());
+                    ((ValveBase)valve).setController
+                        (((ContainerBase)container).getJmxName());
+                }
+            } catch( Throwable t ) {
+                log.info( "Can't register valve " + valve , t );
+            }
+        }
+    }
+    
+    private void unregisterValve(Valve valve) {
+        if( valve instanceof ValveBase ) {
+            try {
+                ValveBase vb=(ValveBase)valve;
+                if( vb.getController()!=null &&
+                        vb.getController() == 
+                        ((ContainerBase)container).getJmxName() ) {
+                    
+                    ObjectName vname=vb.getObjectName();
+                    Registry.getRegistry(null, null).getMBeanServer()
+                        .unregisterMBean(vname);
+                    ((ValveBase)valve).setObjectName(null);
+                }
+            } catch( Throwable t ) {
+                log.info( "Can't unregister valve " + valve , t );
+            }
+        }
+    }    
+
+    // ------------------------------------------------------- Pipeline Methods
+
+
+    /**
+     * <p>Return the Valve instance that has been distinguished as the basic
+     * Valve for this Pipeline (if any).
+     */
+    public Valve getBasic() {
+
+        return (this.basic);
+
+    }
+
+
+    /**
+     * <p>Set the Valve instance that has been distinguished as the basic
+     * Valve for this Pipeline (if any).  Prioer to setting the basic Valve,
+     * the Valve's <code>setContainer()</code> will be called, if it
+     * implements <code>Contained</code>, with the owning Container as an
+     * argument.  The method may throw an <code>IllegalArgumentException</code>
+     * if this Valve chooses not to be associated with this Container, or
+     * <code>IllegalStateException</code> if it is already associated with
+     * a different Container.</p>
+     *
+     * @param valve Valve to be distinguished as the basic Valve
+     */
+    public void setBasic(Valve valve) {
+
+        // Change components if necessary
+        Valve oldBasic = this.basic;
+        if (oldBasic == valve)
+            return;
+
+        // Stop the old component if necessary
+        if (oldBasic != null) {
+            if (started && (oldBasic instanceof Lifecycle)) {
+                try {
+                    ((Lifecycle) oldBasic).stop();
+                } catch (LifecycleException e) {
+                    log.error("StandardPipeline.setBasic: stop", e);
+                }
+            }
+            if (oldBasic instanceof Contained) {
+                try {
+                    ((Contained) oldBasic).setContainer(null);
+                } catch (Throwable t) {
+                    ;
+                }
+            }
+        }
+
+        // Start the new component if necessary
+        if (valve == null)
+            return;
+        if (valve instanceof Contained) {
+            ((Contained) valve).setContainer(this.container);
+        }
+        if (valve instanceof Lifecycle) {
+            try {
+                ((Lifecycle) valve).start();
+            } catch (LifecycleException e) {
+                log.error("StandardPipeline.setBasic: start", e);
+                return;
+            }
+        }
+
+        // Update the pipeline
+        Valve current = first;
+        while (current != null) {
+        	if (current.getNext() == oldBasic) {
+        		current.setNext(valve);
+        		break;
+        	}
+        	current = current.getNext();
+        }
+        
+        this.basic = valve;
+
+    }
+
+
+    /**
+     * <p>Add a new Valve to the end of the pipeline associated with this
+     * Container.  Prior to adding the Valve, the Valve's
+     * <code>setContainer()</code> method will be called, if it implements
+     * <code>Contained</code>, with the owning Container as an argument.
+     * The method may throw an
+     * <code>IllegalArgumentException</code> if this Valve chooses not to
+     * be associated with this Container, or <code>IllegalStateException</code>
+     * if it is already associated with a different Container.</p>
+     *
+     * @param valve Valve to be added
+     *
+     * @exception IllegalArgumentException if this Container refused to
+     *  accept the specified Valve
+     * @exception IllegalArgumentException if the specifie Valve refuses to be
+     *  associated with this Container
+     * @exception IllegalStateException if the specified Valve is already
+     *  associated with a different Container
+     */
+    public void addValve(Valve valve) {
+    
+        // Validate that we can add this Valve
+        if (valve instanceof Contained)
+            ((Contained) valve).setContainer(this.container);
+
+        // Start the new component if necessary
+        if (started) {
+            if (valve instanceof Lifecycle) {
+                try {
+                    ((Lifecycle) valve).start();
+                } catch (LifecycleException e) {
+                    log.error("StandardPipeline.addValve: start: ", e);
+                }
+            }
+            // Register the newly added valve
+            registerValve(valve);
+        }
+
+        // Add this Valve to the set associated with this Pipeline
+        if (first == null) {
+        	first = valve;
+        	valve.setNext(basic);
+        } else {
+            Valve current = first;
+            while (current != null) {
+				if (current.getNext() == basic) {
+					current.setNext(valve);
+					valve.setNext(basic);
+					break;
+				}
+				current = current.getNext();
+			}
+        }
+
+    }
+
+
+    /**
+     * Return the set of Valves in the pipeline associated with this
+     * Container, including the basic Valve (if any).  If there are no
+     * such Valves, a zero-length array is returned.
+     */
+    public Valve[] getValves() {
+
+    	ArrayList valveList = new ArrayList();
+        Valve current = first;
+        if (current == null) {
+        	current = basic;
+        }
+        while (current != null) {
+        	valveList.add(current);
+        	current = current.getNext();
+        }
+
+        return ((Valve[]) valveList.toArray(new Valve[0]));
+
+    }
+
+    public ObjectName[] getValveObjectNames() {
+
+    	ArrayList valveList = new ArrayList();
+        Valve current = first;
+        if (current == null) {
+        	current = basic;
+        }
+        while (current != null) {
+        	if (current instanceof ValveBase) {
+        		valveList.add(((ValveBase) current).getObjectName());
+        	}
+        	current = current.getNext();
+        }
+
+        return ((ObjectName[]) valveList.toArray(new ObjectName[0]));
+
+    }
+
+    /**
+     * Remove the specified Valve from the pipeline associated with this
+     * Container, if it is found; otherwise, do nothing.  If the Valve is
+     * found and removed, the Valve's <code>setContainer(null)</code> method
+     * will be called if it implements <code>Contained</code>.
+     *
+     * @param valve Valve to be removed
+     */
+    public void removeValve(Valve valve) {
+
+        Valve current;
+        if(first == valve) {
+            first = first.getNext();
+            current = null;
+        } else {
+            current = first;
+        }
+        while (current != null) {
+            if (current.getNext() == valve) {
+                current.setNext(valve.getNext());
+                break;
+            }
+            current = current.getNext();
+        }
+
+        if (valve instanceof Contained)
+            ((Contained) valve).setContainer(null);
+
+        // Stop this valve if necessary
+        if (started) {
+            if (valve instanceof Lifecycle) {
+                try {
+                    ((Lifecycle) valve).stop();
+                } catch (LifecycleException e) {
+                    log.error("StandardPipeline.removeValve: stop: ", e);
+                }
+            }
+            // Unregister the removed valave
+            unregisterValve(valve);
+        }
+    
+    }
+
+
+    public Valve getFirst() {
+        if (first != null) {
+            return first;
+        } else {
+            return basic;
+        }
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/core/StandardServer.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/core/StandardServer.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/core/StandardServer.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,826 @@
+/*
+ * Copyright 1999-2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.beans.PropertyChangeListener;
+import java.beans.PropertyChangeSupport;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.InetAddress;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.security.AccessControlException;
+import java.util.Random;
+
+import javax.management.MBeanRegistration;
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+
+import org.apache.catalina.Context;
+import org.apache.catalina.Lifecycle;
+import org.apache.catalina.LifecycleException;
+import org.apache.catalina.LifecycleListener;
+import org.apache.catalina.Server;
+import org.apache.catalina.ServerFactory;
+import org.apache.catalina.Service;
+import org.apache.catalina.deploy.NamingResources;
+import org.apache.catalina.util.LifecycleSupport;
+import org.apache.catalina.util.StringManager;
+import org.apache.catalina.util.ServerInfo;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.commons.modeler.Registry;
+import org.apache.tomcat.util.buf.StringCache;
+
+
+
+/**
+ * Standard implementation of the <b>Server</b> interface, available for use
+ * (but not required) when deploying and starting Catalina.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 370082 $ $Date: 2006-01-18 03:17:33 -0600 (Wed, 18 Jan 2006) $
+ */
+public final class StandardServer
+    implements Lifecycle, Server, MBeanRegistration 
+ {
+    private static Log log = LogFactory.getLog(StandardServer.class);
+   
+
+    // -------------------------------------------------------------- Constants
+
+
+    /**
+     * ServerLifecycleListener classname.
+     */
+    private static String SERVER_LISTENER_CLASS_NAME =
+        "org.apache.catalina.mbeans.ServerLifecycleListener";
+
+
+    // ------------------------------------------------------------ Constructor
+
+
+    /**
+     * Construct a default instance of this class.
+     */
+    public StandardServer() {
+
+        super();
+        ServerFactory.setServer(this);
+
+        globalNamingResources = new NamingResources();
+        globalNamingResources.setContainer(this);
+
+        if (isUseNaming()) {
+            if (namingContextListener == null) {
+                namingContextListener = new NamingContextListener();
+                addLifecycleListener(namingContextListener);
+            }
+        }
+
+    }
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * Global naming resources context.
+     */
+    private javax.naming.Context globalNamingContext = null;
+
+
+    /**
+     * Global naming resources.
+     */
+    private NamingResources globalNamingResources = null;
+
+
+    /**
+     * Descriptive information about this Server implementation.
+     */
+    private static final String info =
+        "org.apache.catalina.core.StandardServer/1.0";
+
+
+    /**
+     * The lifecycle event support for this component.
+     */
+    private LifecycleSupport lifecycle = new LifecycleSupport(this);
+
+
+    /**
+     * The naming context listener for this web application.
+     */
+    private NamingContextListener namingContextListener = null;
+
+
+    /**
+     * The port number on which we wait for shutdown commands.
+     */
+    private int port = 8005;
+
+
+    /**
+     * A random number generator that is <strong>only</strong> used if
+     * the shutdown command string is longer than 1024 characters.
+     */
+    private Random random = null;
+
+
+    /**
+     * The set of Services associated with this Server.
+     */
+    private Service services[] = new Service[0];
+
+
+    /**
+     * The shutdown command string we are looking for.
+     */
+    private String shutdown = "SHUTDOWN";
+
+
+    /**
+     * The string manager for this package.
+     */
+    private static final StringManager sm =
+        StringManager.getManager(Constants.Package);
+
+
+    /**
+     * Has this component been started?
+     */
+    private boolean started = false;
+
+
+    /**
+     * Has this component been initialized?
+     */
+    private boolean initialized = false;
+
+
+    /**
+     * The property change support for this component.
+     */
+    protected PropertyChangeSupport support = new PropertyChangeSupport(this);
+
+    private boolean stopAwait = false;
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * Return the global naming resources context.
+     */
+    public javax.naming.Context getGlobalNamingContext() {
+
+        return (this.globalNamingContext);
+
+    }
+
+
+    /**
+     * Set the global naming resources context.
+     *
+     * @param globalNamingContext The new global naming resource context
+     */
+    public void setGlobalNamingContext
+        (javax.naming.Context globalNamingContext) {
+
+        this.globalNamingContext = globalNamingContext;
+
+    }
+
+
+    /**
+     * Return the global naming resources.
+     */
+    public NamingResources getGlobalNamingResources() {
+
+        return (this.globalNamingResources);
+
+    }
+
+
+    /**
+     * Set the global naming resources.
+     *
+     * @param globalNamingResources The new global naming resources
+     */
+    public void setGlobalNamingResources
+        (NamingResources globalNamingResources) {
+
+        NamingResources oldGlobalNamingResources =
+            this.globalNamingResources;
+        this.globalNamingResources = globalNamingResources;
+        this.globalNamingResources.setContainer(this);
+        support.firePropertyChange("globalNamingResources",
+                                   oldGlobalNamingResources,
+                                   this.globalNamingResources);
+
+    }
+
+
+    /**
+     * Return descriptive information about this Server implementation and
+     * the corresponding version number, in the format
+     * <code>&lt;description&gt;/&lt;version&gt;</code>.
+     */
+    public String getInfo() {
+
+        return (info);
+
+    }
+
+    /**
+     * Report the current Tomcat Server Release number
+     * @return Tomcat release identifier
+     */
+    public String getServerInfo() {
+
+        return ServerInfo.getServerInfo();
+    }
+
+    /**
+     * Return the port number we listen to for shutdown commands.
+     */
+    public int getPort() {
+
+        return (this.port);
+
+    }
+
+
+    /**
+     * Set the port number we listen to for shutdown commands.
+     *
+     * @param port The new port number
+     */
+    public void setPort(int port) {
+
+        this.port = port;
+
+    }
+
+
+    /**
+     * Return the shutdown command string we are waiting for.
+     */
+    public String getShutdown() {
+
+        return (this.shutdown);
+
+    }
+
+
+    /**
+     * Set the shutdown command we are waiting for.
+     *
+     * @param shutdown The new shutdown command
+     */
+    public void setShutdown(String shutdown) {
+
+        this.shutdown = shutdown;
+
+    }
+
+
+    // --------------------------------------------------------- Server Methods
+
+
+    /**
+     * Add a new Service to the set of defined Services.
+     *
+     * @param service The Service to be added
+     */
+    public void addService(Service service) {
+
+        service.setServer(this);
+
+        synchronized (services) {
+            Service results[] = new Service[services.length + 1];
+            System.arraycopy(services, 0, results, 0, services.length);
+            results[services.length] = service;
+            services = results;
+
+            if (initialized) {
+                try {
+                    service.initialize();
+                } catch (LifecycleException e) {
+                    log.error(e);
+                }
+            }
+
+            if (started && (service instanceof Lifecycle)) {
+                try {
+                    ((Lifecycle) service).start();
+                } catch (LifecycleException e) {
+                    ;
+                }
+            }
+
+            // Report this property change to interested listeners
+            support.firePropertyChange("service", null, service);
+        }
+
+    }
+
+    public void stopAwait() {
+        stopAwait=true;
+    }
+
+    /**
+     * Wait until a proper shutdown command is received, then return.
+     * This keeps the main thread alive - the thread pool listening for http 
+     * connections is daemon threads.
+     */
+    public void await() {
+        // Negative values - don't wait on port - tomcat is embedded or we just don't like ports
+        if( port == -2 ) {
+            // undocumented yet - for embedding apps that are around, alive.
+            return;
+        }
+        if( port==-1 ) {
+            while( true ) {
+                try {
+                    Thread.sleep( 100000 );
+                } catch( InterruptedException ex ) {
+                }
+                if( stopAwait ) return;
+            }
+        }
+        
+        // Set up a server socket to wait on
+        ServerSocket serverSocket = null;
+        try {
+            serverSocket =
+                new ServerSocket(port, 1,
+                                 InetAddress.getByName("127.0.0.1"));
+        } catch (IOException e) {
+            log.error("StandardServer.await: create[" + port
+                               + "]: ", e);
+            System.exit(1);
+        }
+
+        // Loop waiting for a connection and a valid command
+        while (true) {
+
+            // Wait for the next connection
+            Socket socket = null;
+            InputStream stream = null;
+            try {
+                socket = serverSocket.accept();
+                socket.setSoTimeout(10 * 1000);  // Ten seconds
+                stream = socket.getInputStream();
+            } catch (AccessControlException ace) {
+                log.warn("StandardServer.accept security exception: "
+                                   + ace.getMessage(), ace);
+                continue;
+            } catch (IOException e) {
+                log.error("StandardServer.await: accept: ", e);
+                System.exit(1);
+            }
+
+            // Read a set of characters from the socket
+            StringBuffer command = new StringBuffer();
+            int expected = 1024; // Cut off to avoid DoS attack
+            while (expected < shutdown.length()) {
+                if (random == null)
+                    random = new Random(System.currentTimeMillis());
+                expected += (random.nextInt() % 1024);
+            }
+            while (expected > 0) {
+                int ch = -1;
+                try {
+                    ch = stream.read();
+                } catch (IOException e) {
+                    log.warn("StandardServer.await: read: ", e);
+                    ch = -1;
+                }
+                if (ch < 32)  // Control character or EOF terminates loop
+                    break;
+                command.append((char) ch);
+                expected--;
+            }
+
+            // Close the socket now that we are done with it
+            try {
+                socket.close();
+            } catch (IOException e) {
+                ;
+            }
+
+            // Match against our command string
+            boolean match = command.toString().equals(shutdown);
+            if (match) {
+                break;
+            } else
+                log.warn("StandardServer.await: Invalid command '" +
+                                   command.toString() + "' received");
+
+        }
+
+        // Close the server socket and return
+        try {
+            serverSocket.close();
+        } catch (IOException e) {
+            ;
+        }
+
+    }
+
+
+    /**
+     * Return the specified Service (if it exists); otherwise return
+     * <code>null</code>.
+     *
+     * @param name Name of the Service to be returned
+     */
+    public Service findService(String name) {
+
+        if (name == null) {
+            return (null);
+        }
+        synchronized (services) {
+            for (int i = 0; i < services.length; i++) {
+                if (name.equals(services[i].getName())) {
+                    return (services[i]);
+                }
+            }
+        }
+        return (null);
+
+    }
+
+
+    /**
+     * Return the set of Services defined within this Server.
+     */
+    public Service[] findServices() {
+
+        return (services);
+
+    }
+    
+    /** 
+     * Return the JMX service names.
+     */
+    public ObjectName[] getServiceNames() {
+        ObjectName onames[]=new ObjectName[ services.length ];
+        for( int i=0; i<services.length; i++ ) {
+            onames[i]=((StandardService)services[i]).getObjectName();
+        }
+        return onames;
+    }
+
+
+    /**
+     * Remove the specified Service from the set associated from this
+     * Server.
+     *
+     * @param service The Service to be removed
+     */
+    public void removeService(Service service) {
+
+        synchronized (services) {
+            int j = -1;
+            for (int i = 0; i < services.length; i++) {
+                if (service == services[i]) {
+                    j = i;
+                    break;
+                }
+            }
+            if (j < 0)
+                return;
+            if (services[j] instanceof Lifecycle) {
+                try {
+                    ((Lifecycle) services[j]).stop();
+                } catch (LifecycleException e) {
+                    ;
+                }
+            }
+            int k = 0;
+            Service results[] = new Service[services.length - 1];
+            for (int i = 0; i < services.length; i++) {
+                if (i != j)
+                    results[k++] = services[i];
+            }
+            services = results;
+
+            // Report this property change to interested listeners
+            support.firePropertyChange("service", service, null);
+        }
+
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Add a property change listener to this component.
+     *
+     * @param listener The listener to add
+     */
+    public void addPropertyChangeListener(PropertyChangeListener listener) {
+
+        support.addPropertyChangeListener(listener);
+
+    }
+
+
+    /**
+     * Remove a property change listener from this component.
+     *
+     * @param listener The listener to remove
+     */
+    public void removePropertyChangeListener(PropertyChangeListener listener) {
+
+        support.removePropertyChangeListener(listener);
+
+    }
+
+
+    /**
+     * Return a String representation of this component.
+     */
+    public String toString() {
+
+        StringBuffer sb = new StringBuffer("StandardServer[");
+        sb.append(getPort());
+        sb.append("]");
+        return (sb.toString());
+
+    }
+
+
+    /**
+     * Write the configuration information for this entire <code>Server</code>
+     * out to the server.xml configuration file.
+     *
+     * @exception javax.management.InstanceNotFoundException if the managed resource object
+     *  cannot be found
+     * @exception javax.management.MBeanException if the initializer of the object throws
+     *  an exception, or persistence is not supported
+     * @exception javax.management.RuntimeOperationsException if an exception is reported
+     *  by the persistence mechanism
+     */
+    public synchronized void storeConfig() throws Exception {
+
+        ObjectName sname = null;    
+        try {
+           sname = new ObjectName("Catalina:type=StoreConfig");
+           if(mserver.isRegistered(sname)) {
+               mserver.invoke(sname, "storeConfig", null, null);            
+           } else
+               log.error("StoreConfig mbean not registered" + sname);
+        } catch (Throwable t) {
+            log.error(t);
+        }
+
+    }
+
+
+    /**
+     * Write the configuration information for <code>Context</code>
+     * out to the specified configuration file.
+     *
+     * @exception javax.management.InstanceNotFoundException if the managed resource object
+     *  cannot be found
+     * @exception javax.management.MBeanException if the initializer of the object throws
+     *  an exception, or persistence is not supported
+     * @exception javax.management.RuntimeOperationsException if an exception is reported
+     *  by the persistence mechanism
+     */
+    public synchronized void storeContext(Context context) throws Exception {
+        
+        ObjectName sname = null;    
+        try {
+           sname = new ObjectName("Catalina:type=StoreConfig");
+           if(mserver.isRegistered(sname)) {
+               mserver.invoke(sname, "store",
+                   new Object[] {context}, 
+                   new String [] { "java.lang.String"});
+           } else
+               log.error("StoreConfig mbean not registered" + sname);
+        } catch (Throwable t) {
+            log.error(t);
+        }
+ 
+    }
+
+
+    /**
+     * Return true if naming should be used.
+     */
+    private boolean isUseNaming() {
+        boolean useNaming = true;
+        // Reading the "catalina.useNaming" environment variable
+        String useNamingProperty = System.getProperty("catalina.useNaming");
+        if ((useNamingProperty != null)
+            && (useNamingProperty.equals("false"))) {
+            useNaming = false;
+        }
+        return useNaming;
+    }
+
+
+    // ------------------------------------------------------ Lifecycle Methods
+
+
+    /**
+     * Add a LifecycleEvent listener to this component.
+     *
+     * @param listener The listener to add
+     */
+    public void addLifecycleListener(LifecycleListener listener) {
+
+        lifecycle.addLifecycleListener(listener);
+
+    }
+
+
+    /**
+     * Get the lifecycle listeners associated with this lifecycle. If this
+     * Lifecycle has no listeners registered, a zero-length array is returned.
+     */
+    public LifecycleListener[] findLifecycleListeners() {
+
+        return lifecycle.findLifecycleListeners();
+
+    }
+
+
+    /**
+     * Remove a LifecycleEvent listener from this component.
+     *
+     * @param listener The listener to remove
+     */
+    public void removeLifecycleListener(LifecycleListener listener) {
+
+        lifecycle.removeLifecycleListener(listener);
+
+    }
+
+
+    /**
+     * Prepare for the beginning of active use of the public methods of this
+     * component.  This method should be called before any of the public
+     * methods of this component are utilized.  It should also send a
+     * LifecycleEvent of type START_EVENT to any registered listeners.
+     *
+     * @exception LifecycleException if this component detects a fatal error
+     *  that prevents this component from being used
+     */
+    public void start() throws LifecycleException {
+
+        // Validate and update our current component state
+        if (started) {
+            log.debug(sm.getString("standardServer.start.started"));
+            return;
+        }
+
+        // Notify our interested LifecycleListeners
+        lifecycle.fireLifecycleEvent(BEFORE_START_EVENT, null);
+
+        lifecycle.fireLifecycleEvent(START_EVENT, null);
+        started = true;
+
+        // Start our defined Services
+        synchronized (services) {
+            for (int i = 0; i < services.length; i++) {
+                if (services[i] instanceof Lifecycle)
+                    ((Lifecycle) services[i]).start();
+            }
+        }
+
+        // Notify our interested LifecycleListeners
+        lifecycle.fireLifecycleEvent(AFTER_START_EVENT, null);
+
+    }
+
+
+    /**
+     * Gracefully terminate the active use of the public methods of this
+     * component.  This method should be the last one called on a given
+     * instance of this component.  It should also send a LifecycleEvent
+     * of type STOP_EVENT to any registered listeners.
+     *
+     * @exception LifecycleException if this component detects a fatal error
+     *  that needs to be reported
+     */
+    public void stop() throws LifecycleException {
+
+        // Validate and update our current component state
+        if (!started)
+            return;
+
+        // Notify our interested LifecycleListeners
+        lifecycle.fireLifecycleEvent(BEFORE_STOP_EVENT, null);
+
+        lifecycle.fireLifecycleEvent(STOP_EVENT, null);
+        started = false;
+
+        // Stop our defined Services
+        for (int i = 0; i < services.length; i++) {
+            if (services[i] instanceof Lifecycle)
+                ((Lifecycle) services[i]).stop();
+        }
+
+        // Notify our interested LifecycleListeners
+        lifecycle.fireLifecycleEvent(AFTER_STOP_EVENT, null);
+
+    }
+
+    public void init() throws Exception {
+        initialize();
+    }
+    
+    /**
+     * Invoke a pre-startup initialization. This is used to allow connectors
+     * to bind to restricted ports under Unix operating environments.
+     */
+    public void initialize()
+        throws LifecycleException 
+    {
+        if (initialized) {
+                log.info(sm.getString("standardServer.initialize.initialized"));
+            return;
+        }
+        lifecycle.fireLifecycleEvent(INIT_EVENT, null);
+        initialized = true;
+
+        if( oname==null ) {
+            try {
+                oname=new ObjectName( "Catalina:type=Server");
+                Registry.getRegistry(null, null)
+                    .registerComponent(this, oname, null );
+            } catch (Exception e) {
+                log.error("Error registering ",e);
+            }
+        }
+        
+        // Register global String cache
+        try {
+            ObjectName oname2 = 
+                new ObjectName(oname.getDomain() + ":type=StringCache");
+            Registry.getRegistry(null, null)
+                .registerComponent(new StringCache(), oname2, null );
+        } catch (Exception e) {
+            log.error("Error registering ",e);
+        }
+
+        // Initialize our defined Services
+        for (int i = 0; i < services.length; i++) {
+            services[i].initialize();
+        }
+    }
+    
+    protected String type;
+    protected String domain;
+    protected String suffix;
+    protected ObjectName oname;
+    protected MBeanServer mserver;
+
+    public ObjectName getObjectName() {
+        return oname;
+    }
+
+    public String getDomain() {
+        return domain;
+    }
+
+    public ObjectName preRegister(MBeanServer server,
+                                  ObjectName name) throws Exception {
+        oname=name;
+        mserver=server;
+        domain=name.getDomain();
+        return name;
+    }
+
+    public void postRegister(Boolean registrationDone) {
+    }
+
+    public void preDeregister() throws Exception {
+    }
+
+    public void postDeregister() {
+    }
+    
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/core/StandardService.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/core/StandardService.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/core/StandardService.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,630 @@
+/*
+ * Copyright 1999-2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.beans.PropertyChangeListener;
+import java.beans.PropertyChangeSupport;
+import javax.management.MBeanRegistration;
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+import org.apache.catalina.Container;
+import org.apache.catalina.Engine;
+import org.apache.catalina.Lifecycle;
+import org.apache.catalina.LifecycleException;
+import org.apache.catalina.LifecycleListener;
+import org.apache.catalina.Server;
+import org.apache.catalina.Service;
+import org.apache.catalina.ServerFactory;
+import org.apache.catalina.connector.Connector;
+import org.apache.catalina.util.LifecycleSupport;
+import org.apache.catalina.util.StringManager;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.commons.modeler.Registry;
+
+
+/**
+ * Standard implementation of the <code>Service</code> interface.  The
+ * associated Container is generally an instance of Engine, but this is
+ * not required.
+ *
+ * @author Craig R. McClanahan
+ */
+
+public class StandardService
+        implements Lifecycle, Service, MBeanRegistration 
+ {
+    private static Log log = LogFactory.getLog(StandardService.class);
+   
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * Descriptive information about this component implementation.
+     */
+    private static final String info =
+        "org.apache.catalina.core.StandardService/1.0";
+
+
+    /**
+     * The name of this service.
+     */
+    private String name = null;
+
+
+    /**
+     * The lifecycle event support for this component.
+     */
+    private LifecycleSupport lifecycle = new LifecycleSupport(this);
+
+
+    /**
+     * The string manager for this package.
+     */
+    private static final StringManager sm =
+        StringManager.getManager(Constants.Package);
+
+    /**
+     * The <code>Server</code> that owns this Service, if any.
+     */
+    private Server server = null;
+
+    /**
+     * Has this component been started?
+     */
+    private boolean started = false;
+
+
+    /**
+     * The property change support for this component.
+     */
+    protected PropertyChangeSupport support = new PropertyChangeSupport(this);
+
+
+    /**
+     * The set of Connectors associated with this Service.
+     */
+    protected Connector connectors[] = new Connector[0];
+
+
+    /**
+     * The Container associated with this Service. (In the case of the
+     * org.apache.catalina.startup.Embedded subclass, this holds the most
+     * recently added Engine.)
+     */
+    protected Container container = null;
+
+
+    /**
+     * Has this component been initialized?
+     */
+    protected boolean initialized = false;
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * Return the <code>Container</code> that handles requests for all
+     * <code>Connectors</code> associated with this Service.
+     */
+    public Container getContainer() {
+
+        return (this.container);
+
+    }
+
+
+    /**
+     * Set the <code>Container</code> that handles requests for all
+     * <code>Connectors</code> associated with this Service.
+     *
+     * @param container The new Container
+     */
+    public void setContainer(Container container) {
+
+        Container oldContainer = this.container;
+        if ((oldContainer != null) && (oldContainer instanceof Engine))
+            ((Engine) oldContainer).setService(null);
+        this.container = container;
+        if ((this.container != null) && (this.container instanceof Engine))
+            ((Engine) this.container).setService(this);
+        if (started && (this.container != null) &&
+            (this.container instanceof Lifecycle)) {
+            try {
+                ((Lifecycle) this.container).start();
+            } catch (LifecycleException e) {
+                ;
+            }
+        }
+        synchronized (connectors) {
+            for (int i = 0; i < connectors.length; i++)
+                connectors[i].setContainer(this.container);
+        }
+        if (started && (oldContainer != null) &&
+            (oldContainer instanceof Lifecycle)) {
+            try {
+                ((Lifecycle) oldContainer).stop();
+            } catch (LifecycleException e) {
+                ;
+            }
+        }
+
+        // Report this property change to interested listeners
+        support.firePropertyChange("container", oldContainer, this.container);
+
+    }
+
+    public ObjectName getContainerName() {
+        if( container instanceof ContainerBase ) {
+            return ((ContainerBase)container).getJmxName();
+        }
+        return null;
+    }
+
+
+    /**
+     * Return descriptive information about this Service implementation and
+     * the corresponding version number, in the format
+     * <code>&lt;description&gt;/&lt;version&gt;</code>.
+     */
+    public String getInfo() {
+
+        return (info);
+
+    }
+
+
+    /**
+     * Return the name of this Service.
+     */
+    public String getName() {
+
+        return (this.name);
+
+    }
+
+
+    /**
+     * Set the name of this Service.
+     *
+     * @param name The new service name
+     */
+    public void setName(String name) {
+
+        this.name = name;
+
+    }
+
+
+    /**
+     * Return the <code>Server</code> with which we are associated (if any).
+     */
+    public Server getServer() {
+
+        return (this.server);
+
+    }
+
+
+    /**
+     * Set the <code>Server</code> with which we are associated (if any).
+     *
+     * @param server The server that owns this Service
+     */
+    public void setServer(Server server) {
+
+        this.server = server;
+
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Add a new Connector to the set of defined Connectors, and associate it
+     * with this Service's Container.
+     *
+     * @param connector The Connector to be added
+     */
+    public void addConnector(Connector connector) {
+
+        synchronized (connectors) {
+            connector.setContainer(this.container);
+            connector.setService(this);
+            Connector results[] = new Connector[connectors.length + 1];
+            System.arraycopy(connectors, 0, results, 0, connectors.length);
+            results[connectors.length] = connector;
+            connectors = results;
+
+            if (initialized) {
+                try {
+                    connector.initialize();
+                } catch (LifecycleException e) {
+                    log.error("Connector.initialize", e);
+                }
+            }
+
+            if (started && (connector instanceof Lifecycle)) {
+                try {
+                    ((Lifecycle) connector).start();
+                } catch (LifecycleException e) {
+                    log.error("Connector.start", e);
+                }
+            }
+
+            // Report this property change to interested listeners
+            support.firePropertyChange("connector", null, connector);
+        }
+
+    }
+
+    public ObjectName[] getConnectorNames() {
+        ObjectName results[] = new ObjectName[connectors.length];
+        for( int i=0; i<results.length; i++ ) {
+            // if it's a coyote connector
+            //if( connectors[i] instanceof CoyoteConnector ) {
+            //    results[i]=((CoyoteConnector)connectors[i]).getJmxName();
+            //}
+        }
+        return results;
+    }
+
+
+    /**
+     * Add a property change listener to this component.
+     *
+     * @param listener The listener to add
+     */
+    public void addPropertyChangeListener(PropertyChangeListener listener) {
+
+        support.addPropertyChangeListener(listener);
+
+    }
+
+
+    /**
+     * Find and return the set of Connectors associated with this Service.
+     */
+    public Connector[] findConnectors() {
+
+        return (connectors);
+
+    }
+
+
+    /**
+     * Remove the specified Connector from the set associated from this
+     * Service.  The removed Connector will also be disassociated from our
+     * Container.
+     *
+     * @param connector The Connector to be removed
+     */
+    public void removeConnector(Connector connector) {
+
+        synchronized (connectors) {
+            int j = -1;
+            for (int i = 0; i < connectors.length; i++) {
+                if (connector == connectors[i]) {
+                    j = i;
+                    break;
+                }
+            }
+            if (j < 0)
+                return;
+            if (started && (connectors[j] instanceof Lifecycle)) {
+                try {
+                    ((Lifecycle) connectors[j]).stop();
+                } catch (LifecycleException e) {
+                    log.error("Connector.stop", e);
+                }
+            }
+            connectors[j].setContainer(null);
+            connector.setService(null);
+            int k = 0;
+            Connector results[] = new Connector[connectors.length - 1];
+            for (int i = 0; i < connectors.length; i++) {
+                if (i != j)
+                    results[k++] = connectors[i];
+            }
+            connectors = results;
+
+            // Report this property change to interested listeners
+            support.firePropertyChange("connector", connector, null);
+        }
+
+    }
+
+
+    /**
+     * Remove a property change listener from this component.
+     *
+     * @param listener The listener to remove
+     */
+    public void removePropertyChangeListener(PropertyChangeListener listener) {
+
+        support.removePropertyChangeListener(listener);
+
+    }
+
+
+    /**
+     * Return a String representation of this component.
+     */
+    public String toString() {
+
+        StringBuffer sb = new StringBuffer("StandardService[");
+        sb.append(getName());
+        sb.append("]");
+        return (sb.toString());
+
+    }
+
+
+    // ------------------------------------------------------ Lifecycle Methods
+
+
+    /**
+     * Add a LifecycleEvent listener to this component.
+     *
+     * @param listener The listener to add
+     */
+    public void addLifecycleListener(LifecycleListener listener) {
+
+        lifecycle.addLifecycleListener(listener);
+
+    }
+
+
+    /**
+     * Get the lifecycle listeners associated with this lifecycle. If this 
+     * Lifecycle has no listeners registered, a zero-length array is returned.
+     */
+    public LifecycleListener[] findLifecycleListeners() {
+
+        return lifecycle.findLifecycleListeners();
+
+    }
+
+
+    /**
+     * Remove a LifecycleEvent listener from this component.
+     *
+     * @param listener The listener to remove
+     */
+    public void removeLifecycleListener(LifecycleListener listener) {
+
+        lifecycle.removeLifecycleListener(listener);
+
+    }
+
+
+    /**
+     * Prepare for the beginning of active use of the public methods of this
+     * component.  This method should be called before any of the public
+     * methods of this component are utilized.  It should also send a
+     * LifecycleEvent of type START_EVENT to any registered listeners.
+     *
+     * @exception LifecycleException if this component detects a fatal error
+     *  that prevents this component from being used
+     */
+    public void start() throws LifecycleException {
+
+        // Validate and update our current component state
+        if (log.isInfoEnabled() && started) {
+            log.info(sm.getString("standardService.start.started"));
+        }
+        
+        if( ! initialized )
+            init(); 
+
+        // Notify our interested LifecycleListeners
+        lifecycle.fireLifecycleEvent(BEFORE_START_EVENT, null);
+        if(log.isInfoEnabled())
+            log.info(sm.getString("standardService.start.name", this.name));
+        lifecycle.fireLifecycleEvent(START_EVENT, null);
+        started = true;
+
+        // Start our defined Container first
+        if (container != null) {
+            synchronized (container) {
+                if (container instanceof Lifecycle) {
+                    ((Lifecycle) container).start();
+                }
+            }
+        }
+
+        // Start our defined Connectors second
+        synchronized (connectors) {
+            for (int i = 0; i < connectors.length; i++) {
+                if (connectors[i] instanceof Lifecycle)
+                    ((Lifecycle) connectors[i]).start();
+            }
+        }
+
+        // Notify our interested LifecycleListeners
+        lifecycle.fireLifecycleEvent(AFTER_START_EVENT, null);
+
+    }
+
+
+    /**
+     * Gracefully terminate the active use of the public methods of this
+     * component.  This method should be the last one called on a given
+     * instance of this component.  It should also send a LifecycleEvent
+     * of type STOP_EVENT to any registered listeners.
+     *
+     * @exception LifecycleException if this component detects a fatal error
+     *  that needs to be reported
+     */
+    public void stop() throws LifecycleException {
+
+        // Validate and update our current component state
+        if (!started) {
+            return;
+        }
+
+        // Notify our interested LifecycleListeners
+        lifecycle.fireLifecycleEvent(BEFORE_STOP_EVENT, null);
+
+        // Stop our defined Connectors first
+        synchronized (connectors) {
+            for (int i = 0; i < connectors.length; i++) {
+                connectors[i].pause();
+            }
+        }
+
+        // Heuristic: Sleep for a while to ensure pause of the connector
+        try {
+            Thread.sleep(1000);
+        } catch (InterruptedException e) {
+            // Ignore
+        }
+
+        lifecycle.fireLifecycleEvent(STOP_EVENT, null);
+        if(log.isInfoEnabled())
+            log.info
+                (sm.getString("standardService.stop.name", this.name));
+        started = false;
+
+        // Stop our defined Container second
+        if (container != null) {
+            synchronized (container) {
+                if (container instanceof Lifecycle) {
+                    ((Lifecycle) container).stop();
+                }
+            }
+        }
+        // FIXME pero -- Why container stop first? KeepAlive connetions can send request! 
+        // Stop our defined Connectors first
+        synchronized (connectors) {
+            for (int i = 0; i < connectors.length; i++) {
+                if (connectors[i] instanceof Lifecycle)
+                    ((Lifecycle) connectors[i]).stop();
+            }
+        }
+
+        if( oname==controller ) {
+            // we registered ourself on init().
+            // That should be the typical case - this object is just for
+            // backward compat, nobody should bother to load it explicitely
+            Registry.getRegistry(null, null).unregisterComponent(oname);
+        }
+        
+
+        // Notify our interested LifecycleListeners
+        lifecycle.fireLifecycleEvent(AFTER_STOP_EVENT, null);
+
+    }
+
+
+    /**
+     * Invoke a pre-startup initialization. This is used to allow connectors
+     * to bind to restricted ports under Unix operating environments.
+     */
+    public void initialize()
+            throws LifecycleException
+    {
+        // Service shouldn't be used with embeded, so it doesn't matter
+        if (initialized) {
+            if(log.isInfoEnabled())
+                log.info(sm.getString("standardService.initialize.initialized"));
+            return;
+        }
+        initialized = true;
+
+        if( oname==null ) {
+            try {
+                // Hack - Server should be deprecated...
+                Container engine=this.getContainer();
+                domain=engine.getName();
+                oname=new ObjectName(domain + ":type=Service,serviceName="+name);
+                this.controller=oname;
+                Registry.getRegistry(null, null)
+                    .registerComponent(this, oname, null);
+            } catch (Exception e) {
+                log.error(sm.getString("standardService.register.failed",domain),e);
+            }
+            
+            
+        }
+        if( server==null ) {
+            // Register with the server 
+            // HACK: ServerFactory should be removed...
+            
+            ServerFactory.getServer().addService(this);
+        }
+               
+
+        // Initialize our defined Connectors
+        synchronized (connectors) {
+                for (int i = 0; i < connectors.length; i++) {
+                    connectors[i].initialize();
+                }
+        }
+    }
+    
+    public void destroy() throws LifecycleException {
+        if( started ) stop();
+        // FIXME unregister should be here probably -- stop doing that ?
+    }
+
+    public void init() {
+        try {
+            initialize();
+        } catch( Throwable t ) {
+            log.error(sm.getString("standardService.initialize.failed",domain),t);
+        }
+    }
+
+    protected String type;
+    protected String domain;
+    protected String suffix;
+    protected ObjectName oname;
+    protected ObjectName controller;
+    protected MBeanServer mserver;
+
+    public ObjectName getObjectName() {
+        return oname;
+    }
+
+    public String getDomain() {
+        return domain;
+    }
+
+    public ObjectName preRegister(MBeanServer server,
+                                  ObjectName name) throws Exception {
+        oname=name;
+        mserver=server;
+        domain=name.getDomain();
+        return name;
+    }
+
+    public void postRegister(Boolean registrationDone) {
+    }
+
+    public void preDeregister() throws Exception {
+    }
+
+    public void postDeregister() {
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/core/StandardWrapper.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/core/StandardWrapper.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/core/StandardWrapper.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,1831 @@
+/*
+ * Copyright 1999-2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.lang.reflect.Method;
+import java.io.PrintStream;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Stack;
+import java.security.AccessController;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
+import javax.servlet.Servlet;
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.SingleThreadModel;
+import javax.servlet.UnavailableException;
+import javax.management.ListenerNotFoundException;
+import javax.management.MBeanNotificationInfo;
+import javax.management.Notification;
+import javax.management.NotificationBroadcasterSupport;
+import javax.management.NotificationEmitter;
+import javax.management.NotificationFilter;
+import javax.management.NotificationListener;
+import javax.management.ObjectName;
+
+import org.apache.catalina.Container;
+import org.apache.catalina.ContainerServlet;
+import org.apache.catalina.Context;
+import org.apache.catalina.InstanceEvent;
+import org.apache.catalina.InstanceListener;
+import org.apache.catalina.LifecycleException;
+import org.apache.catalina.Loader;
+import org.apache.catalina.Wrapper;
+import org.apache.catalina.security.SecurityUtil;
+import org.apache.catalina.util.Enumerator;
+import org.apache.catalina.util.InstanceSupport;
+import org.apache.tomcat.util.IntrospectionUtils;
+import org.apache.tomcat.util.log.SystemLogHandler;
+import org.apache.commons.modeler.Registry;
+
+/**
+ * Standard implementation of the <b>Wrapper</b> interface that represents
+ * an individual servlet definition.  No child Containers are allowed, and
+ * the parent Container must be a Context.
+ *
+ * @author Craig R. McClanahan
+ * @author Remy Maucherat
+ * @version $Revision: 413538 $ $Date: 2006-06-11 16:53:07 -0500 (Sun, 11 Jun 2006) $
+ */
+public class StandardWrapper
+    extends ContainerBase
+    implements ServletConfig, Wrapper, NotificationEmitter {
+
+    private static org.apache.commons.logging.Log log=
+        org.apache.commons.logging.LogFactory.getLog( StandardWrapper.class );
+
+    private static final String[] DEFAULT_SERVLET_METHODS = new String[] {
+                                                    "GET", "HEAD", "POST" };
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Create a new StandardWrapper component with the default basic Valve.
+     */
+    public StandardWrapper() {
+
+        super();
+        swValve=new StandardWrapperValve();
+        pipeline.setBasic(swValve);
+        broadcaster = new NotificationBroadcasterSupport();
+
+    }
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The date and time at which this servlet will become available (in
+     * milliseconds since the epoch), or zero if the servlet is available.
+     * If this value equals Long.MAX_VALUE, the unavailability of this
+     * servlet is considered permanent.
+     */
+    private long available = 0L;
+    
+    /**
+     * The broadcaster that sends j2ee notifications. 
+     */
+    private NotificationBroadcasterSupport broadcaster = null;
+    
+    /**
+     * The count of allocations that are currently active (even if they
+     * are for the same instance, as will be true on a non-STM servlet).
+     */
+    private int countAllocated = 0;
+
+
+    /**
+     * The facade associated with this wrapper.
+     */
+    private StandardWrapperFacade facade =
+        new StandardWrapperFacade(this);
+
+
+    /**
+     * The descriptive information string for this implementation.
+     */
+    private static final String info =
+        "org.apache.catalina.core.StandardWrapper/1.0";
+
+
+    /**
+     * The (single) initialized instance of this servlet.
+     */
+    private Servlet instance = null;
+
+
+    /**
+     * The support object for our instance listeners.
+     */
+    private InstanceSupport instanceSupport = new InstanceSupport(this);
+
+
+    /**
+     * The context-relative URI of the JSP file for this servlet.
+     */
+    private String jspFile = null;
+
+
+    /**
+     * The load-on-startup order value (negative value means load on
+     * first call) for this servlet.
+     */
+    private int loadOnStartup = -1;
+
+
+    /**
+     * Mappings associated with the wrapper.
+     */
+    private ArrayList mappings = new ArrayList();
+
+
+    /**
+     * The initialization parameters for this servlet, keyed by
+     * parameter name.
+     */
+    private HashMap parameters = new HashMap();
+
+
+    /**
+     * The security role references for this servlet, keyed by role name
+     * used in the servlet.  The corresponding value is the role name of
+     * the web application itself.
+     */
+    private HashMap references = new HashMap();
+
+
+    /**
+     * The run-as identity for this servlet.
+     */
+    private String runAs = null;
+
+    /**
+     * The notification sequence number.
+     */
+    private long sequenceNumber = 0;
+
+    /**
+     * The fully qualified servlet class name for this servlet.
+     */
+    private String servletClass = null;
+
+
+    /**
+     * Does this servlet implement the SingleThreadModel interface?
+     */
+    private boolean singleThreadModel = false;
+
+
+    /**
+     * Are we unloading our servlet instance at the moment?
+     */
+    private boolean unloading = false;
+
+
+    /**
+     * Maximum number of STM instances.
+     */
+    private int maxInstances = 20;
+
+
+    /**
+     * Number of instances currently loaded for a STM servlet.
+     */
+    private int nInstances = 0;
+
+
+    /**
+     * Stack containing the STM instances.
+     */
+    private Stack instancePool = null;
+
+    
+    /**
+     * Wait time for servlet unload in ms.
+     */
+    private long unloadDelay = 2000;
+    
+
+    /**
+     * True if this StandardWrapper is for the JspServlet
+     */
+    private boolean isJspServlet;
+
+
+    /**
+     * The ObjectName of the JSP monitoring mbean
+     */
+    private ObjectName jspMonitorON;
+
+
+    /**
+     * Should we swallow System.out
+     */
+    private boolean swallowOutput = false;
+
+    // To support jmx attributes
+    private StandardWrapperValve swValve;
+    private long loadTime=0;
+    private int classLoadTime=0;
+    
+    /**
+     * Static class array used when the SecurityManager is turned on and 
+     * <code>Servlet.init</code> is invoked.
+     */
+    private static Class[] classType = new Class[]{ServletConfig.class};
+    
+    
+    /**
+     * Static class array used when the SecurityManager is turned on and 
+     * <code>Servlet.service</code>  is invoked.
+     */                                                 
+    private static Class[] classTypeUsedInService = new Class[]{
+                                                         ServletRequest.class,
+                                                         ServletResponse.class};
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * Return the available date/time for this servlet, in milliseconds since
+     * the epoch.  If this date/time is Long.MAX_VALUE, it is considered to mean
+     * that unavailability is permanent and any request for this servlet will return
+     * an SC_NOT_FOUND error.  If this date/time is in the future, any request for
+     * this servlet will return an SC_SERVICE_UNAVAILABLE error.  If it is zero,
+     * the servlet is currently available.
+     */
+    public long getAvailable() {
+
+        return (this.available);
+
+    }
+
+
+    /**
+     * Set the available date/time for this servlet, in milliseconds since the
+     * epoch.  If this date/time is Long.MAX_VALUE, it is considered to mean
+     * that unavailability is permanent and any request for this servlet will return
+     * an SC_NOT_FOUND error. If this date/time is in the future, any request for
+     * this servlet will return an SC_SERVICE_UNAVAILABLE error.
+     *
+     * @param available The new available date/time
+     */
+    public void setAvailable(long available) {
+
+        long oldAvailable = this.available;
+        if (available > System.currentTimeMillis())
+            this.available = available;
+        else
+            this.available = 0L;
+        support.firePropertyChange("available", new Long(oldAvailable),
+                                   new Long(this.available));
+
+    }
+
+
+    /**
+     * Return the number of active allocations of this servlet, even if they
+     * are all for the same instance (as will be true for servlets that do
+     * not implement <code>SingleThreadModel</code>.
+     */
+    public int getCountAllocated() {
+
+        return (this.countAllocated);
+
+    }
+
+
+    public String getEngineName() {
+        return ((StandardContext)getParent()).getEngineName();
+    }
+
+
+    /**
+     * Return descriptive information about this Container implementation and
+     * the corresponding version number, in the format
+     * <code>&lt;description&gt;/&lt;version&gt;</code>.
+     */
+    public String getInfo() {
+
+        return (info);
+
+    }
+
+
+    /**
+     * Return the InstanceSupport object for this Wrapper instance.
+     */
+    public InstanceSupport getInstanceSupport() {
+
+        return (this.instanceSupport);
+
+    }
+
+
+    /**
+     * Return the context-relative URI of the JSP file for this servlet.
+     */
+    public String getJspFile() {
+
+        return (this.jspFile);
+
+    }
+
+
+    /**
+     * Set the context-relative URI of the JSP file for this servlet.
+     *
+     * @param jspFile JSP file URI
+     */
+    public void setJspFile(String jspFile) {
+
+        String oldJspFile = this.jspFile;
+        this.jspFile = jspFile;
+        support.firePropertyChange("jspFile", oldJspFile, this.jspFile);
+
+        // Each jsp-file needs to be represented by its own JspServlet and
+        // corresponding JspMonitoring mbean, because it may be initialized
+        // with its own init params
+        isJspServlet = true;
+
+    }
+
+
+    /**
+     * Return the load-on-startup order value (negative value means
+     * load on first call).
+     */
+    public int getLoadOnStartup() {
+
+        if (isJspServlet && loadOnStartup < 0) {
+            /*
+             * JspServlet must always be preloaded, because its instance is
+             * used during registerJMX (when registering the JSP
+             * monitoring mbean)
+             */
+             return Integer.MAX_VALUE;
+        } else {
+            return (this.loadOnStartup);
+        }
+    }
+
+
+    /**
+     * Set the load-on-startup order value (negative value means
+     * load on first call).
+     *
+     * @param value New load-on-startup value
+     */
+    public void setLoadOnStartup(int value) {
+
+        int oldLoadOnStartup = this.loadOnStartup;
+        this.loadOnStartup = value;
+        support.firePropertyChange("loadOnStartup",
+                                   new Integer(oldLoadOnStartup),
+                                   new Integer(this.loadOnStartup));
+
+    }
+
+
+
+    /**
+     * Set the load-on-startup order value from a (possibly null) string.
+     * Per the specification, any missing or non-numeric value is converted
+     * to a zero, so that this servlet will still be loaded at startup
+     * time, but in an arbitrary order.
+     *
+     * @param value New load-on-startup value
+     */
+    public void setLoadOnStartupString(String value) {
+
+        try {
+            setLoadOnStartup(Integer.parseInt(value));
+        } catch (NumberFormatException e) {
+            setLoadOnStartup(0);
+        }
+    }
+
+    public String getLoadOnStartupString() {
+        return Integer.toString( getLoadOnStartup());
+    }
+
+
+    /**
+     * Return maximum number of instances that will be allocated when a single
+     * thread model servlet is used.
+     */
+    public int getMaxInstances() {
+
+        return (this.maxInstances);
+
+    }
+
+
+    /**
+     * Set the maximum number of instances that will be allocated when a single
+     * thread model servlet is used.
+     *
+     * @param maxInstances New value of maxInstances
+     */
+    public void setMaxInstances(int maxInstances) {
+
+        int oldMaxInstances = this.maxInstances;
+        this.maxInstances = maxInstances;
+        support.firePropertyChange("maxInstances", oldMaxInstances,
+                                   this.maxInstances);
+
+    }
+
+
+    /**
+     * Set the parent Container of this Wrapper, but only if it is a Context.
+     *
+     * @param container Proposed parent Container
+     */
+    public void setParent(Container container) {
+
+        if ((container != null) &&
+            !(container instanceof Context))
+            throw new IllegalArgumentException
+                (sm.getString("standardWrapper.notContext"));
+        if (container instanceof StandardContext) {
+            swallowOutput = ((StandardContext)container).getSwallowOutput();
+            unloadDelay = ((StandardContext)container).getUnloadDelay();
+        }
+        super.setParent(container);
+
+    }
+
+
+    /**
+     * Return the run-as identity for this servlet.
+     */
+    public String getRunAs() {
+
+        return (this.runAs);
+
+    }
+
+
+    /**
+     * Set the run-as identity for this servlet.
+     *
+     * @param runAs New run-as identity value
+     */
+    public void setRunAs(String runAs) {
+
+        String oldRunAs = this.runAs;
+        this.runAs = runAs;
+        support.firePropertyChange("runAs", oldRunAs, this.runAs);
+
+    }
+
+
+    /**
+     * Return the fully qualified servlet class name for this servlet.
+     */
+    public String getServletClass() {
+
+        return (this.servletClass);
+
+    }
+
+
+    /**
+     * Set the fully qualified servlet class name for this servlet.
+     *
+     * @param servletClass Servlet class name
+     */
+    public void setServletClass(String servletClass) {
+
+        String oldServletClass = this.servletClass;
+        this.servletClass = servletClass;
+        support.firePropertyChange("servletClass", oldServletClass,
+                                   this.servletClass);
+        if (Constants.JSP_SERVLET_CLASS.equals(servletClass)) {
+            isJspServlet = true;
+        }
+    }
+
+
+
+    /**
+     * Set the name of this servlet.  This is an alias for the normal
+     * <code>Container.setName()</code> method, and complements the
+     * <code>getServletName()</code> method required by the
+     * <code>ServletConfig</code> interface.
+     *
+     * @param name The new name of this servlet
+     */
+    public void setServletName(String name) {
+
+        setName(name);
+
+    }
+
+
+    /**
+     * Return <code>true</code> if the servlet class represented by this
+     * component implements the <code>SingleThreadModel</code> interface.
+     */
+    public boolean isSingleThreadModel() {
+
+        try {
+            loadServlet();
+        } catch (Throwable t) {
+            ;
+        }
+        return (singleThreadModel);
+
+    }
+
+
+    /**
+     * Is this servlet currently unavailable?
+     */
+    public boolean isUnavailable() {
+
+        if (available == 0L)
+            return (false);
+        else if (available <= System.currentTimeMillis()) {
+            available = 0L;
+            return (false);
+        } else
+            return (true);
+
+    }
+
+
+    /**
+     * Gets the names of the methods supported by the underlying servlet.
+     *
+     * This is the same set of methods included in the Allow response header
+     * in response to an OPTIONS request method processed by the underlying
+     * servlet.
+     *
+     * @return Array of names of the methods supported by the underlying
+     * servlet
+     */
+    public String[] getServletMethods() throws ServletException {
+
+        Class servletClazz = loadServlet().getClass();
+        if (!javax.servlet.http.HttpServlet.class.isAssignableFrom(
+                                                        servletClazz)) {
+            return DEFAULT_SERVLET_METHODS;
+        }
+
+        HashSet allow = new HashSet();
+        allow.add("TRACE");
+        allow.add("OPTIONS");
+	
+        Method[] methods = getAllDeclaredMethods(servletClazz);
+        for (int i=0; methods != null && i<methods.length; i++) {
+            Method m = methods[i];
+	    
+            if (m.getName().equals("doGet")) {
+                allow.add("GET");
+                allow.add("HEAD");
+            } else if (m.getName().equals("doPost")) {
+                allow.add("POST");
+            } else if (m.getName().equals("doPut")) {
+                allow.add("PUT");
+            } else if (m.getName().equals("doDelete")) {
+                allow.add("DELETE");
+            }
+        }
+
+        String[] methodNames = new String[allow.size()];
+        return (String[]) allow.toArray(methodNames);
+
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Extract the root cause from a servlet exception.
+     * 
+     * @param e The servlet exception
+     */
+    public static Throwable getRootCause(ServletException e) {
+        Throwable rootCause = e;
+        Throwable rootCauseCheck = null;
+        // Extra aggressive rootCause finding
+        do {
+            try {
+                rootCauseCheck = (Throwable)IntrospectionUtils.getProperty
+                                            (rootCause, "rootCause");
+                if (rootCauseCheck!=null)
+                    rootCause = rootCauseCheck;
+
+            } catch (ClassCastException ex) {
+                rootCauseCheck = null;
+            }
+        } while (rootCauseCheck != null);
+        return rootCause;
+    }
+
+
+    /**
+     * Refuse to add a child Container, because Wrappers are the lowest level
+     * of the Container hierarchy.
+     *
+     * @param child Child container to be added
+     */
+    public void addChild(Container child) {
+
+        throw new IllegalStateException
+            (sm.getString("standardWrapper.notChild"));
+
+    }
+
+
+    /**
+     * Add a new servlet initialization parameter for this servlet.
+     *
+     * @param name Name of this initialization parameter to add
+     * @param value Value of this initialization parameter to add
+     */
+    public void addInitParameter(String name, String value) {
+
+        synchronized (parameters) {
+            parameters.put(name, value);
+        }
+        fireContainerEvent("addInitParameter", name);
+
+    }
+
+
+    /**
+     * Add a new listener interested in InstanceEvents.
+     *
+     * @param listener The new listener
+     */
+    public void addInstanceListener(InstanceListener listener) {
+
+        instanceSupport.addInstanceListener(listener);
+
+    }
+
+
+    /**
+     * Add a mapping associated with the Wrapper.
+     *
+     * @param mapping The new wrapper mapping
+     */
+    public void addMapping(String mapping) {
+
+        synchronized (mappings) {
+            mappings.add(mapping);
+        }
+        fireContainerEvent("addMapping", mapping);
+
+    }
+
+
+    /**
+     * Add a new security role reference record to the set of records for
+     * this servlet.
+     *
+     * @param name Role name used within this servlet
+     * @param link Role name used within the web application
+     */
+    public void addSecurityReference(String name, String link) {
+
+        synchronized (references) {
+            references.put(name, link);
+        }
+        fireContainerEvent("addSecurityReference", name);
+
+    }
+
+
+    /**
+     * Allocate an initialized instance of this Servlet that is ready to have
+     * its <code>service()</code> method called.  If the servlet class does
+     * not implement <code>SingleThreadModel</code>, the (only) initialized
+     * instance may be returned immediately.  If the servlet class implements
+     * <code>SingleThreadModel</code>, the Wrapper implementation must ensure
+     * that this instance is not allocated again until it is deallocated by a
+     * call to <code>deallocate()</code>.
+     *
+     * @exception ServletException if the servlet init() method threw
+     *  an exception
+     * @exception ServletException if a loading error occurs
+     */
+    public Servlet allocate() throws ServletException {
+
+        // If we are currently unloading this servlet, throw an exception
+        if (unloading)
+            throw new ServletException
+              (sm.getString("standardWrapper.unloading", getName()));
+
+        // If not SingleThreadedModel, return the same instance every time
+        if (!singleThreadModel) {
+
+            // Load and initialize our instance if necessary
+            if (instance == null) {
+                synchronized (this) {
+                    if (instance == null) {
+                        try {
+                            if (log.isDebugEnabled())
+                                log.debug("Allocating non-STM instance");
+
+                            instance = loadServlet();
+                        } catch (ServletException e) {
+                            throw e;
+                        } catch (Throwable e) {
+                            throw new ServletException
+                                (sm.getString("standardWrapper.allocate"), e);
+                        }
+                    }
+                }
+            }
+
+            if (!singleThreadModel) {
+                if (log.isTraceEnabled())
+                    log.trace("  Returning non-STM instance");
+                countAllocated++;
+                return (instance);
+            }
+
+        }
+
+        synchronized (instancePool) {
+
+            while (countAllocated >= nInstances) {
+                // Allocate a new instance if possible, or else wait
+                if (nInstances < maxInstances) {
+                    try {
+                        instancePool.push(loadServlet());
+                        nInstances++;
+                    } catch (ServletException e) {
+                        throw e;
+                    } catch (Throwable e) {
+                        throw new ServletException
+                            (sm.getString("standardWrapper.allocate"), e);
+                    }
+                } else {
+                    try {
+                        instancePool.wait();
+                    } catch (InterruptedException e) {
+                        ;
+                    }
+                }
+            }
+            if (log.isTraceEnabled())
+                log.trace("  Returning allocated STM instance");
+            countAllocated++;
+            return (Servlet) instancePool.pop();
+
+        }
+
+    }
+
+
+    /**
+     * Return this previously allocated servlet to the pool of available
+     * instances.  If this servlet class does not implement SingleThreadModel,
+     * no action is actually required.
+     *
+     * @param servlet The servlet to be returned
+     *
+     * @exception ServletException if a deallocation error occurs
+     */
+    public void deallocate(Servlet servlet) throws ServletException {
+
+        // If not SingleThreadModel, no action is required
+        if (!singleThreadModel) {
+            countAllocated--;
+            return;
+        }
+
+        // Unlock and free this instance
+        synchronized (instancePool) {
+            countAllocated--;
+            instancePool.push(servlet);
+            instancePool.notify();
+        }
+
+    }
+
+
+    /**
+     * Return the value for the specified initialization parameter name,
+     * if any; otherwise return <code>null</code>.
+     *
+     * @param name Name of the requested initialization parameter
+     */
+    public String findInitParameter(String name) {
+
+        synchronized (parameters) {
+            return ((String) parameters.get(name));
+        }
+
+    }
+
+
+    /**
+     * Return the names of all defined initialization parameters for this
+     * servlet.
+     */
+    public String[] findInitParameters() {
+
+        synchronized (parameters) {
+            String results[] = new String[parameters.size()];
+            return ((String[]) parameters.keySet().toArray(results));
+        }
+
+    }
+
+
+    /**
+     * Return the mappings associated with this wrapper.
+     */
+    public String[] findMappings() {
+
+        synchronized (mappings) {
+            return (String[]) mappings.toArray(new String[mappings.size()]);
+        }
+
+    }
+
+
+    /**
+     * Return the security role link for the specified security role
+     * reference name, if any; otherwise return <code>null</code>.
+     *
+     * @param name Security role reference used within this servlet
+     */
+    public String findSecurityReference(String name) {
+
+        synchronized (references) {
+            return ((String) references.get(name));
+        }
+
+    }
+
+
+    /**
+     * Return the set of security role reference names associated with
+     * this servlet, if any; otherwise return a zero-length array.
+     */
+    public String[] findSecurityReferences() {
+
+        synchronized (references) {
+            String results[] = new String[references.size()];
+            return ((String[]) references.keySet().toArray(results));
+        }
+
+    }
+
+
+    /**
+     * FIXME: Fooling introspection ...
+     */
+    public Wrapper findMappingObject() {
+        return (Wrapper) getMappingObject();
+    }
+
+
+    /**
+     * Load and initialize an instance of this servlet, if there is not already
+     * at least one initialized instance.  This can be used, for example, to
+     * load servlets that are marked in the deployment descriptor to be loaded
+     * at server startup time.
+     * <p>
+     * <b>IMPLEMENTATION NOTE</b>:  Servlets whose classnames begin with
+     * <code>org.apache.catalina.</code> (so-called "container" servlets)
+     * are loaded by the same classloader that loaded this class, rather than
+     * the classloader for the current web application.
+     * This gives such classes access to Catalina internals, which are
+     * prevented for classes loaded for web applications.
+     *
+     * @exception ServletException if the servlet init() method threw
+     *  an exception
+     * @exception ServletException if some other loading problem occurs
+     */
+    public synchronized void load() throws ServletException {
+        instance = loadServlet();
+    }
+
+
+    /**
+     * Load and initialize an instance of this servlet, if there is not already
+     * at least one initialized instance.  This can be used, for example, to
+     * load servlets that are marked in the deployment descriptor to be loaded
+     * at server startup time.
+     */
+    public synchronized Servlet loadServlet() throws ServletException {
+
+        // Nothing to do if we already have an instance or an instance pool
+        if (!singleThreadModel && (instance != null))
+            return instance;
+
+        PrintStream out = System.out;
+        if (swallowOutput) {
+            SystemLogHandler.startCapture();
+        }
+
+        Servlet servlet;
+        try {
+            long t1=System.currentTimeMillis();
+            // If this "servlet" is really a JSP file, get the right class.
+            // HOLD YOUR NOSE - this is a kludge that avoids having to do special
+            // case Catalina-specific code in Jasper - it also requires that the
+            // servlet path be replaced by the <jsp-file> element content in
+            // order to be completely effective
+            String actualClass = servletClass;
+            if ((actualClass == null) && (jspFile != null)) {
+                Wrapper jspWrapper = (Wrapper)
+                    ((Context) getParent()).findChild(Constants.JSP_SERVLET_NAME);
+                if (jspWrapper != null) {
+                    actualClass = jspWrapper.getServletClass();
+                    // Merge init parameters
+                    String paramNames[] = jspWrapper.findInitParameters();
+                    for (int i = 0; i < paramNames.length; i++) {
+                        if (parameters.get(paramNames[i]) == null) {
+                            parameters.put
+                                (paramNames[i], 
+                                 jspWrapper.findInitParameter(paramNames[i]));
+                        }
+                    }
+                }
+            }
+
+            // Complain if no servlet class has been specified
+            if (actualClass == null) {
+                unavailable(null);
+                throw new ServletException
+                    (sm.getString("standardWrapper.notClass", getName()));
+            }
+
+            // Acquire an instance of the class loader to be used
+            Loader loader = getLoader();
+            if (loader == null) {
+                unavailable(null);
+                throw new ServletException
+                    (sm.getString("standardWrapper.missingLoader", getName()));
+            }
+
+            ClassLoader classLoader = loader.getClassLoader();
+
+            // Special case class loader for a container provided servlet
+            //  
+            if (isContainerProvidedServlet(actualClass) && 
+                    ! ((Context)getParent()).getPrivileged() ) {
+                // If it is a priviledged context - using its own
+                // class loader will work, since it's a child of the container
+                // loader
+                classLoader = this.getClass().getClassLoader();
+            }
+
+            // Load the specified servlet class from the appropriate class loader
+            Class classClass = null;
+            try {
+                if (SecurityUtil.isPackageProtectionEnabled()){
+                    final ClassLoader fclassLoader = classLoader;
+                    final String factualClass = actualClass;
+                    try{
+                        classClass = (Class)AccessController.doPrivileged(
+                                new PrivilegedExceptionAction(){
+                                    public Object run() throws Exception{
+                                        if (fclassLoader != null) {
+                                            return fclassLoader.loadClass(factualClass);
+                                        } else {
+                                            return Class.forName(factualClass);
+                                        }
+                                    }
+                        });
+                    } catch(PrivilegedActionException pax){
+                        Exception ex = pax.getException();
+                        if (ex instanceof ClassNotFoundException){
+                            throw (ClassNotFoundException)ex;
+                        } else {
+                            getServletContext().log( "Error loading "
+                                + fclassLoader + " " + factualClass, ex );
+                        }
+                    }
+                } else {
+                    if (classLoader != null) {
+                        classClass = classLoader.loadClass(actualClass);
+                    } else {
+                        classClass = Class.forName(actualClass);
+                    }
+                }
+            } catch (ClassNotFoundException e) {
+                unavailable(null);
+                getServletContext().log( "Error loading " + classLoader + " " + actualClass, e );
+                throw new ServletException
+                    (sm.getString("standardWrapper.missingClass", actualClass),
+                     e);
+            }
+
+            if (classClass == null) {
+                unavailable(null);
+                throw new ServletException
+                    (sm.getString("standardWrapper.missingClass", actualClass));
+            }
+
+            // Instantiate and initialize an instance of the servlet class itself
+            try {
+                servlet = (Servlet) classClass.newInstance();
+            } catch (ClassCastException e) {
+                unavailable(null);
+                // Restore the context ClassLoader
+                throw new ServletException
+                    (sm.getString("standardWrapper.notServlet", actualClass), e);
+            } catch (Throwable e) {
+                unavailable(null);
+              
+                // Added extra log statement for Bugzilla 36630:
+                // http://issues.apache.org/bugzilla/show_bug.cgi?id=36630
+                if(log.isDebugEnabled()) {
+                    log.debug(sm.getString("standardWrapper.instantiate", actualClass), e);
+                }
+
+                // Restore the context ClassLoader
+                throw new ServletException
+                    (sm.getString("standardWrapper.instantiate", actualClass), e);
+            }
+
+            // Check if loading the servlet in this web application should be
+            // allowed
+            if (!isServletAllowed(servlet)) {
+                throw new SecurityException
+                    (sm.getString("standardWrapper.privilegedServlet",
+                                  actualClass));
+            }
+
+            // Special handling for ContainerServlet instances
+            if ((servlet instanceof ContainerServlet) &&
+                  (isContainerProvidedServlet(actualClass) ||
+                    ((Context)getParent()).getPrivileged() )) {
+                ((ContainerServlet) servlet).setWrapper(this);
+            }
+
+            classLoadTime=(int) (System.currentTimeMillis() -t1);
+            // Call the initialization method of this servlet
+            try {
+                instanceSupport.fireInstanceEvent(InstanceEvent.BEFORE_INIT_EVENT,
+                                                  servlet);
+
+                if( System.getSecurityManager() != null) {
+
+                    Object[] args = new Object[]{((ServletConfig)facade)};
+                    SecurityUtil.doAsPrivilege("init",
+                                               servlet,
+                                               classType,
+                                               args);
+                    args = null;
+                } else {
+                    servlet.init(facade);
+                }
+
+                // Invoke jspInit on JSP pages
+                if ((loadOnStartup >= 0) && (jspFile != null)) {
+                    // Invoking jspInit
+                    DummyRequest req = new DummyRequest();
+                    req.setServletPath(jspFile);
+                    req.setQueryString("jsp_precompile=true");
+                    DummyResponse res = new DummyResponse();
+
+                    if( System.getSecurityManager() != null) {
+                        Object[] args = new Object[]{req, res};
+                        SecurityUtil.doAsPrivilege("service",
+                                                   servlet,
+                                                   classTypeUsedInService,
+                                                   args);
+                        args = null;
+                    } else {
+                        servlet.service(req, res);
+                    }
+                }
+                instanceSupport.fireInstanceEvent(InstanceEvent.AFTER_INIT_EVENT,
+                                                  servlet);
+            } catch (UnavailableException f) {
+                instanceSupport.fireInstanceEvent(InstanceEvent.AFTER_INIT_EVENT,
+                                                  servlet, f);
+                unavailable(f);
+                throw f;
+            } catch (ServletException f) {
+                instanceSupport.fireInstanceEvent(InstanceEvent.AFTER_INIT_EVENT,
+                                                  servlet, f);
+                // If the servlet wanted to be unavailable it would have
+                // said so, so do not call unavailable(null).
+                throw f;
+            } catch (Throwable f) {
+                getServletContext().log("StandardWrapper.Throwable", f );
+                instanceSupport.fireInstanceEvent(InstanceEvent.AFTER_INIT_EVENT,
+                                                  servlet, f);
+                // If the servlet wanted to be unavailable it would have
+                // said so, so do not call unavailable(null).
+                throw new ServletException
+                    (sm.getString("standardWrapper.initException", getName()), f);
+            }
+
+            // Register our newly initialized instance
+            singleThreadModel = servlet instanceof SingleThreadModel;
+            if (singleThreadModel) {
+                if (instancePool == null)
+                    instancePool = new Stack();
+            }
+            fireContainerEvent("load", this);
+
+            loadTime=System.currentTimeMillis() -t1;
+        } finally {
+            if (swallowOutput) {
+                String log = SystemLogHandler.stopCapture();
+                if (log != null && log.length() > 0) {
+                    if (getServletContext() != null) {
+                        getServletContext().log(log);
+                    } else {
+                        out.println(log);
+                    }
+                }
+            }
+        }
+        return servlet;
+
+    }
+
+
+    /**
+     * Remove the specified initialization parameter from this servlet.
+     *
+     * @param name Name of the initialization parameter to remove
+     */
+    public void removeInitParameter(String name) {
+
+        synchronized (parameters) {
+            parameters.remove(name);
+        }
+        fireContainerEvent("removeInitParameter", name);
+
+    }
+
+
+    /**
+     * Remove a listener no longer interested in InstanceEvents.
+     *
+     * @param listener The listener to remove
+     */
+    public void removeInstanceListener(InstanceListener listener) {
+
+        instanceSupport.removeInstanceListener(listener);
+
+    }
+
+
+    /**
+     * Remove a mapping associated with the wrapper.
+     *
+     * @param mapping The pattern to remove
+     */
+    public void removeMapping(String mapping) {
+
+        synchronized (mappings) {
+            mappings.remove(mapping);
+        }
+        fireContainerEvent("removeMapping", mapping);
+
+    }
+
+
+    /**
+     * Remove any security role reference for the specified role name.
+     *
+     * @param name Security role used within this servlet to be removed
+     */
+    public void removeSecurityReference(String name) {
+
+        synchronized (references) {
+            references.remove(name);
+        }
+        fireContainerEvent("removeSecurityReference", name);
+
+    }
+
+
+    /**
+     * Return a String representation of this component.
+     */
+    public String toString() {
+
+        StringBuffer sb = new StringBuffer();
+        if (getParent() != null) {
+            sb.append(getParent().toString());
+            sb.append(".");
+        }
+        sb.append("StandardWrapper[");
+        sb.append(getName());
+        sb.append("]");
+        return (sb.toString());
+
+    }
+
+
+    /**
+     * Process an UnavailableException, marking this servlet as unavailable
+     * for the specified amount of time.
+     *
+     * @param unavailable The exception that occurred, or <code>null</code>
+     *  to mark this servlet as permanently unavailable
+     */
+    public void unavailable(UnavailableException unavailable) {
+        getServletContext().log(sm.getString("standardWrapper.unavailable", getName()));
+        if (unavailable == null)
+            setAvailable(Long.MAX_VALUE);
+        else if (unavailable.isPermanent())
+            setAvailable(Long.MAX_VALUE);
+        else {
+            int unavailableSeconds = unavailable.getUnavailableSeconds();
+            if (unavailableSeconds <= 0)
+                unavailableSeconds = 60;        // Arbitrary default
+            setAvailable(System.currentTimeMillis() +
+                         (unavailableSeconds * 1000L));
+        }
+
+    }
+
+
+    /**
+     * Unload all initialized instances of this servlet, after calling the
+     * <code>destroy()</code> method for each instance.  This can be used,
+     * for example, prior to shutting down the entire servlet engine, or
+     * prior to reloading all of the classes from the Loader associated with
+     * our Loader's repository.
+     *
+     * @exception ServletException if an exception is thrown by the
+     *  destroy() method
+     */
+    public synchronized void unload() throws ServletException {
+
+        // Nothing to do if we have never loaded the instance
+        if (!singleThreadModel && (instance == null))
+            return;
+        unloading = true;
+
+        // Loaf a while if the current instance is allocated
+        // (possibly more than once if non-STM)
+        if (countAllocated > 0) {
+            int nRetries = 0;
+            long delay = unloadDelay / 20;
+            while ((nRetries < 21) && (countAllocated > 0)) {
+                if ((nRetries % 10) == 0) {
+                    log.info(sm.getString("standardWrapper.waiting",
+                                          new Integer(countAllocated)));
+                }
+                try {
+                    Thread.sleep(delay);
+                } catch (InterruptedException e) {
+                    ;
+                }
+                nRetries++;
+            }
+        }
+
+        PrintStream out = System.out;
+        if (swallowOutput) {
+            SystemLogHandler.startCapture();
+        }
+
+        // Call the servlet destroy() method
+        try {
+            instanceSupport.fireInstanceEvent
+              (InstanceEvent.BEFORE_DESTROY_EVENT, instance);
+
+            if( System.getSecurityManager() != null) {
+                SecurityUtil.doAsPrivilege("destroy",
+                                           instance);
+                SecurityUtil.remove(instance);                           
+            } else {
+                instance.destroy();
+            }
+
+            instanceSupport.fireInstanceEvent
+              (InstanceEvent.AFTER_DESTROY_EVENT, instance);
+        } catch (Throwable t) {
+            instanceSupport.fireInstanceEvent
+              (InstanceEvent.AFTER_DESTROY_EVENT, instance, t);
+            instance = null;
+            instancePool = null;
+            nInstances = 0;
+            fireContainerEvent("unload", this);
+            unloading = false;
+            throw new ServletException
+                (sm.getString("standardWrapper.destroyException", getName()),
+                 t);
+        } finally {
+            // Write captured output
+            if (swallowOutput) {
+                String log = SystemLogHandler.stopCapture();
+                if (log != null && log.length() > 0) {
+                    if (getServletContext() != null) {
+                        getServletContext().log(log);
+                    } else {
+                        out.println(log);
+                    }
+                }
+            }
+        }
+
+        // Deregister the destroyed instance
+        instance = null;
+
+        if (singleThreadModel && (instancePool != null)) {
+            try {
+                while (!instancePool.isEmpty()) {
+                    if( System.getSecurityManager() != null) {
+                        SecurityUtil.doAsPrivilege("destroy",
+                                                   ((Servlet) instancePool.pop()));
+                        SecurityUtil.remove(instance);                           
+                    } else {
+                        ((Servlet) instancePool.pop()).destroy();
+                    }
+                }
+            } catch (Throwable t) {
+                instancePool = null;
+                nInstances = 0;
+                unloading = false;
+                fireContainerEvent("unload", this);
+                throw new ServletException
+                    (sm.getString("standardWrapper.destroyException",
+                                  getName()), t);
+            }
+            instancePool = null;
+            nInstances = 0;
+        }
+
+        singleThreadModel = false;
+
+        unloading = false;
+        fireContainerEvent("unload", this);
+
+    }
+
+
+    // -------------------------------------------------- ServletConfig Methods
+
+
+    /**
+     * Return the initialization parameter value for the specified name,
+     * if any; otherwise return <code>null</code>.
+     *
+     * @param name Name of the initialization parameter to retrieve
+     */
+    public String getInitParameter(String name) {
+
+        return (findInitParameter(name));
+
+    }
+
+
+    /**
+     * Return the set of initialization parameter names defined for this
+     * servlet.  If none are defined, an empty Enumeration is returned.
+     */
+    public Enumeration getInitParameterNames() {
+
+        synchronized (parameters) {
+            return (new Enumerator(parameters.keySet()));
+        }
+
+    }
+
+
+    /**
+     * Return the servlet context with which this servlet is associated.
+     */
+    public ServletContext getServletContext() {
+
+        if (parent == null)
+            return (null);
+        else if (!(parent instanceof Context))
+            return (null);
+        else
+            return (((Context) parent).getServletContext());
+
+    }
+
+
+    /**
+     * Return the name of this servlet.
+     */
+    public String getServletName() {
+
+        return (getName());
+
+    }
+
+    public long getProcessingTime() {
+        return swValve.getProcessingTime();
+    }
+
+    public void setProcessingTime(long processingTime) {
+        swValve.setProcessingTime(processingTime);
+    }
+
+    public long getMaxTime() {
+        return swValve.getMaxTime();
+    }
+
+    public void setMaxTime(long maxTime) {
+        swValve.setMaxTime(maxTime);
+    }
+
+    public long getMinTime() {
+        return swValve.getMinTime();
+    }
+
+    public void setMinTime(long minTime) {
+        swValve.setMinTime(minTime);
+    }
+
+    public int getRequestCount() {
+        return swValve.getRequestCount();
+    }
+
+    public void setRequestCount(int requestCount) {
+        swValve.setRequestCount(requestCount);
+    }
+
+    public int getErrorCount() {
+        return swValve.getErrorCount();
+    }
+
+    public void setErrorCount(int errorCount) {
+           swValve.setErrorCount(errorCount);
+    }
+
+    /**
+     * Increment the error count used for monitoring.
+     */
+    public void incrementErrorCount(){
+        swValve.setErrorCount(swValve.getErrorCount() + 1);
+    }
+
+    public long getLoadTime() {
+        return loadTime;
+    }
+
+    public void setLoadTime(long loadTime) {
+        this.loadTime = loadTime;
+    }
+
+    public int getClassLoadTime() {
+        return classLoadTime;
+    }
+
+    // -------------------------------------------------------- Package Methods
+
+
+    // -------------------------------------------------------- Private Methods
+
+
+    /**
+     * Add a default Mapper implementation if none have been configured
+     * explicitly.
+     *
+     * @param mapperClass Java class name of the default Mapper
+     */
+    protected void addDefaultMapper(String mapperClass) {
+
+        ;       // No need for a default Mapper on a Wrapper
+
+    }
+
+
+    /**
+     * Return <code>true</code> if the specified class name represents a
+     * container provided servlet class that should be loaded by the
+     * server class loader.
+     *
+     * @param classname Name of the class to be checked
+     */
+    private boolean isContainerProvidedServlet(String classname) {
+
+        if (classname.startsWith("org.apache.catalina.")) {
+            return (true);
+        }
+        try {
+            Class clazz =
+                this.getClass().getClassLoader().loadClass(classname);
+            return (ContainerServlet.class.isAssignableFrom(clazz));
+        } catch (Throwable t) {
+            return (false);
+        }
+
+    }
+
+
+    /**
+     * Return <code>true</code> if loading this servlet is allowed.
+     */
+    private boolean isServletAllowed(Object servlet) {
+
+        if (servlet instanceof ContainerServlet) {
+            if (((Context) getParent()).getPrivileged()
+                || (servlet.getClass().getName().equals
+                    ("org.apache.catalina.servlets.InvokerServlet"))) {
+                return (true);
+            } else {
+                return (false);
+            }
+        }
+
+        return (true);
+
+    }
+
+
+    private Method[] getAllDeclaredMethods(Class c) {
+
+        if (c.equals(javax.servlet.http.HttpServlet.class)) {
+            return null;
+        }
+
+        Method[] parentMethods = getAllDeclaredMethods(c.getSuperclass());
+
+        Method[] thisMethods = c.getDeclaredMethods();
+        if (thisMethods == null) {
+            return parentMethods;
+        }
+
+        if ((parentMethods != null) && (parentMethods.length > 0)) {
+            Method[] allMethods =
+                new Method[parentMethods.length + thisMethods.length];
+	    System.arraycopy(parentMethods, 0, allMethods, 0,
+                             parentMethods.length);
+	    System.arraycopy(thisMethods, 0, allMethods, parentMethods.length,
+                             thisMethods.length);
+
+	    thisMethods = allMethods;
+	}
+
+	return thisMethods;
+    }
+
+
+    // ------------------------------------------------------ Lifecycle Methods
+
+
+    /**
+     * Start this component, pre-loading the servlet if the load-on-startup
+     * value is set appropriately.
+     *
+     * @exception LifecycleException if a fatal error occurs during startup
+     */
+    public void start() throws LifecycleException {
+    
+        // Send j2ee.state.starting notification 
+        if (this.getObjectName() != null) {
+            Notification notification = new Notification("j2ee.state.starting", 
+                                                        this.getObjectName(), 
+                                                        sequenceNumber++);
+            broadcaster.sendNotification(notification);
+        }
+        
+        // Start up this component
+        super.start();
+
+        if( oname != null )
+            registerJMX((StandardContext)getParent());
+        
+        // Load and initialize an instance of this servlet if requested
+        // MOVED TO StandardContext START() METHOD
+
+        setAvailable(0L);
+        
+        // Send j2ee.state.running notification 
+        if (this.getObjectName() != null) {
+            Notification notification = 
+                new Notification("j2ee.state.running", this.getObjectName(), 
+                                sequenceNumber++);
+            broadcaster.sendNotification(notification);
+        }
+
+    }
+
+
+    /**
+     * Stop this component, gracefully shutting down the servlet if it has
+     * been initialized.
+     *
+     * @exception LifecycleException if a fatal error occurs during shutdown
+     */
+    public void stop() throws LifecycleException {
+
+        setAvailable(Long.MAX_VALUE);
+        
+        // Send j2ee.state.stopping notification 
+        if (this.getObjectName() != null) {
+            Notification notification = 
+                new Notification("j2ee.state.stopping", this.getObjectName(), 
+                                sequenceNumber++);
+            broadcaster.sendNotification(notification);
+        }
+        
+        // Shut down our servlet instance (if it has been initialized)
+        try {
+            unload();
+        } catch (ServletException e) {
+            getServletContext().log(sm.getString
+                      ("standardWrapper.unloadException", getName()), e);
+        }
+
+        // Shut down this component
+        super.stop();
+
+        // Send j2ee.state.stoppped notification 
+        if (this.getObjectName() != null) {
+            Notification notification = 
+                new Notification("j2ee.state.stopped", this.getObjectName(), 
+                                sequenceNumber++);
+            broadcaster.sendNotification(notification);
+        }
+        
+        if( oname != null ) {
+            Registry.getRegistry(null, null).unregisterComponent(oname);
+            
+            // Send j2ee.object.deleted notification 
+            Notification notification = 
+                new Notification("j2ee.object.deleted", this.getObjectName(), 
+                                sequenceNumber++);
+            broadcaster.sendNotification(notification);
+        }
+
+        if (isJspServlet && jspMonitorON != null ) {
+            Registry.getRegistry(null, null).unregisterComponent(jspMonitorON);
+        }
+
+    }
+
+    protected void registerJMX(StandardContext ctx) {
+
+        String parentName = ctx.getName();
+        parentName = ("".equals(parentName)) ? "/" : parentName;
+
+        String hostName = ctx.getParent().getName();
+        hostName = (hostName==null) ? "DEFAULT" : hostName;
+
+        String domain = ctx.getDomain();
+
+        String webMod= "//" + hostName + parentName;
+        String onameStr = domain + ":j2eeType=Servlet,name=" + getName() +
+                          ",WebModule=" + webMod + ",J2EEApplication=" +
+                          ctx.getJ2EEApplication() + ",J2EEServer=" +
+                          ctx.getJ2EEServer();
+        try {
+            oname=new ObjectName(onameStr);
+            controller=oname;
+            Registry.getRegistry(null, null)
+                .registerComponent(this, oname, null );
+            
+            // Send j2ee.object.created notification 
+            if (this.getObjectName() != null) {
+                Notification notification = new Notification(
+                                                "j2ee.object.created", 
+                                                this.getObjectName(), 
+                                                sequenceNumber++);
+                broadcaster.sendNotification(notification);
+            }
+        } catch( Exception ex ) {
+            log.info("Error registering servlet with jmx " + this);
+        }
+
+        if (isJspServlet) {
+            // Register JSP monitoring mbean
+            onameStr = domain + ":type=JspMonitor,name=" + getName()
+                       + ",WebModule=" + webMod
+                       + ",J2EEApplication=" + ctx.getJ2EEApplication()
+                       + ",J2EEServer=" + ctx.getJ2EEServer();
+            try {
+                jspMonitorON = new ObjectName(onameStr);
+                Registry.getRegistry(null, null)
+                    .registerComponent(instance, jspMonitorON, null);
+            } catch( Exception ex ) {
+                log.info("Error registering JSP monitoring with jmx " +
+                         instance);
+            }
+        }
+    }
+    
+
+    /* Remove a JMX notficationListener 
+     * @see javax.management.NotificationEmitter#removeNotificationListener(javax.management.NotificationListener, javax.management.NotificationFilter, java.lang.Object)
+     */
+    public void removeNotificationListener(NotificationListener listener, 
+    		NotificationFilter filter, Object object) throws ListenerNotFoundException {
+    	broadcaster.removeNotificationListener(listener,filter,object);
+    	
+    }
+    
+    private MBeanNotificationInfo[] notificationInfo;
+    
+    /* Get JMX Broadcaster Info
+     * @TODO use StringManager for international support!
+     * @TODO This two events we not send j2ee.state.failed and j2ee.attribute.changed!
+     * @see javax.management.NotificationBroadcaster#getNotificationInfo()
+     */
+    public MBeanNotificationInfo[] getNotificationInfo() {
+    	
+    	if(notificationInfo == null) {
+    		notificationInfo = new MBeanNotificationInfo[]{
+    				new MBeanNotificationInfo(new String[] {
+    				"j2ee.object.created"},
+					Notification.class.getName(),
+					"servlet is created"
+    				), 
+					new MBeanNotificationInfo(new String[] {
+					"j2ee.state.starting"},
+					Notification.class.getName(),
+					"servlet is starting"
+					),
+					new MBeanNotificationInfo(new String[] {
+					"j2ee.state.running"},
+					Notification.class.getName(),
+					"servlet is running"
+					),
+					new MBeanNotificationInfo(new String[] {
+					"j2ee.state.stopped"},
+					Notification.class.getName(),
+					"servlet start to stopped"
+					),
+					new MBeanNotificationInfo(new String[] {
+					"j2ee.object.stopped"},
+					Notification.class.getName(),
+					"servlet is stopped"
+					),
+					new MBeanNotificationInfo(new String[] {
+					"j2ee.object.deleted"},
+					Notification.class.getName(),
+					"servlet is deleted"
+					)
+    		};
+    		
+    	}
+    	
+    	return notificationInfo;
+    }
+    
+    
+    /* Add a JMX-NotificationListener
+     * @see javax.management.NotificationBroadcaster#addNotificationListener(javax.management.NotificationListener, javax.management.NotificationFilter, java.lang.Object)
+     */
+    public void addNotificationListener(NotificationListener listener, 
+            NotificationFilter filter, Object object) throws IllegalArgumentException {
+    	broadcaster.addNotificationListener(listener,filter,object);
+    }
+    
+    
+    /**
+     * Remove a JMX-NotificationListener 
+     * @see javax.management.NotificationBroadcaster#removeNotificationListener(javax.management.NotificationListener)
+     */
+    public void removeNotificationListener(NotificationListener listener) 
+        throws ListenerNotFoundException {
+    	broadcaster.removeNotificationListener(listener);
+    }
+    
+    
+     // ------------------------------------------------------------- Attributes
+        
+        
+    public boolean isEventProvider() {
+        return false;
+    }
+    
+    public boolean isStateManageable() {
+        return false;
+    }
+    
+    public boolean isStatisticsProvider() {
+        return false;
+    }
+        
+        
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/core/StandardWrapperFacade.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/core/StandardWrapperFacade.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/core/StandardWrapperFacade.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,88 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.util.Enumeration;
+
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletContext;
+
+
+/**
+ * Facade for the <b>StandardWrapper</b> object.
+ *
+ * @author Remy Maucharat
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public final class StandardWrapperFacade
+    implements ServletConfig {
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Create a new facede around a StandardWrapper.
+     */
+    public StandardWrapperFacade(StandardWrapper config) {
+
+        super();
+        this.config = (ServletConfig) config;
+
+    }
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * Wrapped config.
+     */
+    private ServletConfig config = null;
+
+
+    // -------------------------------------------------- ServletConfig Methods
+
+
+    public String getServletName() {
+        return config.getServletName();
+    }
+
+
+    public ServletContext getServletContext() {
+        ServletContext theContext = config.getServletContext();
+        if ((theContext != null) &&
+            (theContext instanceof ApplicationContext))
+            theContext = ((ApplicationContext) theContext).getFacade();
+        return (theContext);
+    }
+
+
+    public String getInitParameter(String name) {
+        return config.getInitParameter(name);
+    }
+
+
+    public Enumeration getInitParameterNames() {
+        return config.getInitParameterNames();
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/core/StandardWrapperValve.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/core/StandardWrapperValve.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/core/StandardWrapperValve.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,386 @@
+/*
+ * Copyright 1999-2001,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.IOException;
+
+import javax.management.MalformedObjectNameException;
+import javax.management.ObjectName;
+import javax.servlet.Servlet;
+import javax.servlet.ServletException;
+import javax.servlet.UnavailableException;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.catalina.Context;
+import org.apache.catalina.Globals;
+import org.apache.catalina.connector.ClientAbortException;
+import org.apache.catalina.connector.Request;
+import org.apache.catalina.connector.Response;
+import org.apache.catalina.util.StringManager;
+import org.apache.catalina.valves.ValveBase;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.tomcat.util.buf.MessageBytes;
+import org.apache.tomcat.util.log.SystemLogHandler;
+
+/**
+ * Valve that implements the default basic behavior for the
+ * <code>StandardWrapper</code> container implementation.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 303681 $ $Date: 2005-02-06 04:39:32 -0600 (Sun, 06 Feb 2005) $
+ */
+
+final class StandardWrapperValve
+    extends ValveBase {
+
+    private static Log log = LogFactory.getLog(StandardWrapperValve.class);
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    // Some JMX statistics. This vavle is associated with a StandardWrapper.
+    // We exponse the StandardWrapper as JMX ( j2eeType=Servlet ). The fields
+    // are here for performance.
+    private volatile long processingTime;
+    private volatile long maxTime;
+    private volatile long minTime = Long.MAX_VALUE;
+    private volatile int requestCount;
+    private volatile int errorCount;
+
+
+    /**
+     * The string manager for this package.
+     */
+    private static final StringManager sm =
+        StringManager.getManager(Constants.Package);
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Invoke the servlet we are managing, respecting the rules regarding
+     * servlet lifecycle and SingleThreadModel support.
+     *
+     * @param request Request to be processed
+     * @param response Response to be produced
+     * @param valveContext Valve context used to forward to the next Valve
+     *
+     * @exception IOException if an input/output error occurred
+     * @exception ServletException if a servlet error occurred
+     */
+    public final void invoke(Request request, Response response)
+        throws IOException, ServletException {
+
+        // Initialize local variables we may need
+        boolean unavailable = false;
+        Throwable throwable = null;
+        // This should be a Request attribute...
+        long t1=System.currentTimeMillis();
+        requestCount++;
+        StandardWrapper wrapper = (StandardWrapper) getContainer();
+        Servlet servlet = null;
+        Context context = (Context) wrapper.getParent();
+        
+        // Check for the application being marked unavailable
+        if (!context.getAvailable()) {
+        	response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE,
+                           sm.getString("standardContext.isUnavailable"));
+            unavailable = true;
+        }
+
+        // Check for the servlet being marked unavailable
+        if (!unavailable && wrapper.isUnavailable()) {
+            container.getLogger().info(sm.getString("standardWrapper.isUnavailable",
+                    wrapper.getName()));
+            long available = wrapper.getAvailable();
+            if ((available > 0L) && (available < Long.MAX_VALUE)) {
+                response.setDateHeader("Retry-After", available);
+                response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE,
+                        sm.getString("standardWrapper.isUnavailable",
+                                wrapper.getName()));
+            } else if (available == Long.MAX_VALUE) {
+                response.sendError(HttpServletResponse.SC_NOT_FOUND,
+                        sm.getString("standardWrapper.notFound",
+                                wrapper.getName()));
+            }
+            unavailable = true;
+        }
+
+        // Allocate a servlet instance to process this request
+        try {
+            if (!unavailable) {
+                servlet = wrapper.allocate();
+            }
+        } catch (UnavailableException e) {
+            long available = wrapper.getAvailable();
+            if ((available > 0L) && (available < Long.MAX_VALUE)) {
+            	response.setDateHeader("Retry-After", available);
+            	response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE,
+                           sm.getString("standardWrapper.isUnavailable",
+                                        wrapper.getName()));
+            } else if (available == Long.MAX_VALUE) {
+            	response.sendError(HttpServletResponse.SC_NOT_FOUND,
+                           sm.getString("standardWrapper.notFound",
+                                        wrapper.getName()));
+            }
+        } catch (ServletException e) {
+            container.getLogger().error(sm.getString("standardWrapper.allocateException",
+                             wrapper.getName()), StandardWrapper.getRootCause(e));
+            throwable = e;
+            exception(request, response, e);
+            servlet = null;
+        } catch (Throwable e) {
+            container.getLogger().error(sm.getString("standardWrapper.allocateException",
+                             wrapper.getName()), e);
+            throwable = e;
+            exception(request, response, e);
+            servlet = null;
+        }
+
+        // Acknowlege the request
+        try {
+            response.sendAcknowledgement();
+        } catch (IOException e) {
+        	request.removeAttribute(Globals.JSP_FILE_ATTR);
+            container.getLogger().warn(sm.getString("standardWrapper.acknowledgeException",
+                             wrapper.getName()), e);
+            throwable = e;
+            exception(request, response, e);
+        } catch (Throwable e) {
+            container.getLogger().error(sm.getString("standardWrapper.acknowledgeException",
+                             wrapper.getName()), e);
+            throwable = e;
+            exception(request, response, e);
+            servlet = null;
+        }
+        MessageBytes requestPathMB = null;
+        if (request != null) {
+            requestPathMB = request.getRequestPathMB();
+        }
+        request.setAttribute
+            (ApplicationFilterFactory.DISPATCHER_TYPE_ATTR,
+             ApplicationFilterFactory.REQUEST_INTEGER);
+        request.setAttribute
+            (ApplicationFilterFactory.DISPATCHER_REQUEST_PATH_ATTR,
+             requestPathMB);
+        // Create the filter chain for this request
+        ApplicationFilterFactory factory =
+            ApplicationFilterFactory.getInstance();
+        ApplicationFilterChain filterChain =
+            factory.createFilterChain(request, wrapper, servlet);
+
+        // Call the filter chain for this request
+        // NOTE: This also calls the servlet's service() method
+        try {
+            String jspFile = wrapper.getJspFile();
+            if (jspFile != null)
+            	request.setAttribute(Globals.JSP_FILE_ATTR, jspFile);
+            else
+            	request.removeAttribute(Globals.JSP_FILE_ATTR);
+            if ((servlet != null) && (filterChain != null)) {
+
+                // Swallow output if needed
+                if (context.getSwallowOutput()) {
+                    try {
+                        SystemLogHandler.startCapture();
+                        filterChain.doFilter(request.getRequest(), 
+                                response.getResponse());
+                    } finally {
+                        String log = SystemLogHandler.stopCapture();
+                        if (log != null && log.length() > 0) {
+                            context.getLogger().info(log);
+                        }
+                    }
+                } else {
+                    filterChain.doFilter
+                        (request.getRequest(), response.getResponse());
+                }
+
+            }
+            request.removeAttribute(Globals.JSP_FILE_ATTR);
+        } catch (ClientAbortException e) {
+        	request.removeAttribute(Globals.JSP_FILE_ATTR);
+            throwable = e;
+            exception(request, response, e);
+        } catch (IOException e) {
+        	request.removeAttribute(Globals.JSP_FILE_ATTR);
+            container.getLogger().warn(sm.getString("standardWrapper.serviceException",
+                             wrapper.getName()), e);
+            throwable = e;
+            exception(request, response, e);
+        } catch (UnavailableException e) {
+        	request.removeAttribute(Globals.JSP_FILE_ATTR);
+            container.getLogger().warn(sm.getString("standardWrapper.serviceException",
+                             wrapper.getName()), e);
+            //            throwable = e;
+            //            exception(request, response, e);
+            wrapper.unavailable(e);
+            long available = wrapper.getAvailable();
+            if ((available > 0L) && (available < Long.MAX_VALUE)) {
+                response.setDateHeader("Retry-After", available);
+                response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE,
+                           sm.getString("standardWrapper.isUnavailable",
+                                        wrapper.getName()));
+            } else if (available == Long.MAX_VALUE) {
+            	response.sendError(HttpServletResponse.SC_NOT_FOUND,
+                            sm.getString("standardWrapper.notFound",
+                                        wrapper.getName()));
+            }
+            // Do not save exception in 'throwable', because we
+            // do not want to do exception(request, response, e) processing
+        } catch (ServletException e) {
+        	request.removeAttribute(Globals.JSP_FILE_ATTR);
+            Throwable rootCause = StandardWrapper.getRootCause(e);
+            if (!(rootCause instanceof ClientAbortException)) {
+                container.getLogger().error(sm.getString("standardWrapper.serviceException",
+                                 wrapper.getName()), rootCause);
+            }
+            throwable = e;
+            exception(request, response, e);
+        } catch (Throwable e) {
+            request.removeAttribute(Globals.JSP_FILE_ATTR);
+            container.getLogger().error(sm.getString("standardWrapper.serviceException",
+                             wrapper.getName()), e);
+            throwable = e;
+            exception(request, response, e);
+        }
+
+        // Release the filter chain (if any) for this request
+        try {
+            if (filterChain != null)
+                filterChain.release();
+        } catch (Throwable e) {
+            container.getLogger().error(sm.getString("standardWrapper.releaseFilters",
+                             wrapper.getName()), e);
+            if (throwable == null) {
+                throwable = e;
+                exception(request, response, e);
+            }
+        }
+
+        // Deallocate the allocated servlet instance
+        try {
+            if (servlet != null) {
+                wrapper.deallocate(servlet);
+            }
+        } catch (Throwable e) {
+            container.getLogger().error(sm.getString("standardWrapper.deallocateException",
+                             wrapper.getName()), e);
+            if (throwable == null) {
+                throwable = e;
+                exception(request, response, e);
+            }
+        }
+
+        // If this servlet has been marked permanently unavailable,
+        // unload it and release this instance
+        try {
+            if ((servlet != null) &&
+                (wrapper.getAvailable() == Long.MAX_VALUE)) {
+                wrapper.unload();
+            }
+        } catch (Throwable e) {
+            container.getLogger().error(sm.getString("standardWrapper.unloadException",
+                             wrapper.getName()), e);
+            if (throwable == null) {
+                throwable = e;
+                exception(request, response, e);
+            }
+        }
+        long t2=System.currentTimeMillis();
+
+        long time=t2-t1;
+        processingTime += time;
+        if( time > maxTime) maxTime=time;
+        if( time < minTime) minTime=time;
+
+    }
+
+
+    // -------------------------------------------------------- Private Methods
+
+
+    /**
+     * Handle the specified ServletException encountered while processing
+     * the specified Request to produce the specified Response.  Any
+     * exceptions that occur during generation of the exception report are
+     * logged and swallowed.
+     *
+     * @param request The request being processed
+     * @param response The response being generated
+     * @param exception The exception that occurred (which possibly wraps
+     *  a root cause exception
+     */
+    private void exception(Request request, Response response,
+                           Throwable exception) {
+    	request.setAttribute(Globals.EXCEPTION_ATTR, exception);
+        response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
+
+    }
+
+    public long getProcessingTime() {
+        return processingTime;
+    }
+
+    public void setProcessingTime(long processingTime) {
+        this.processingTime = processingTime;
+    }
+
+    public long getMaxTime() {
+        return maxTime;
+    }
+
+    public void setMaxTime(long maxTime) {
+        this.maxTime = maxTime;
+    }
+
+    public long getMinTime() {
+        return minTime;
+    }
+
+    public void setMinTime(long minTime) {
+        this.minTime = minTime;
+    }
+
+    public int getRequestCount() {
+        return requestCount;
+    }
+
+    public void setRequestCount(int requestCount) {
+        this.requestCount = requestCount;
+    }
+
+    public int getErrorCount() {
+        return errorCount;
+    }
+
+    public void setErrorCount(int errorCount) {
+        this.errorCount = errorCount;
+    }
+
+    // Don't register in JMX
+
+    public ObjectName createObjectName(String domain, ObjectName parent)
+            throws MalformedObjectNameException
+    {
+        return null;
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/core/mbeans-descriptors.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/core/mbeans-descriptors.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/core/mbeans-descriptors.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,690 @@
+<?xml version="1.0"?>
+<mbeans-descriptors>
+
+  <mbean name="NamingContextListener"
+         description="Helper class used to initialize and populate the JNDI context associated with each context and server"
+         domain="Catalina"
+         group="Listener"
+         type="org.apache.catalina.core.NamingContextListener">
+    
+    <attribute name="className"
+               description="Fully qualified class name of the managed object"
+               type="java.lang.String"
+               writeable="false"/>
+      
+  </mbean>
+
+  <mbean name="StandardContext"
+         description="Standard Context Component"
+         domain="Catalina"
+         group="Context"
+         type="org.apache.catalina.core.StandardContext">
+    
+    <attribute name="allowLinking"
+               description="Allow symlinking to outside the webapp root directory, if the webapp is an exploded directory"
+               is="true"
+               type="boolean"/>
+      
+    <attribute name="antiJARLocking"
+               description="Take care to not lock jar files"
+               type="boolean" />
+
+    <attribute name="antiResourceLocking"
+               description="Take care to not lock resources"
+               type="boolean" />
+
+    <attribute name="cacheMaxSize"
+               description="Maximum cache size in KB"
+               type="int"/>
+      
+    <attribute name="cacheTTL"
+               description="Time interval in ms between cache refeshes"
+               type="int"/>
+      
+    <attribute name="cachingAllowed"
+               description="Should we cache static resources for this webapp"
+               is="true"
+               type="boolean"/>
+      
+    <attribute name="caseSensitive"
+               description="Should case sensitivity checks be performed"
+               is="true"
+               type="boolean"/>
+      
+    <attribute name="children"
+               description="Object names of all children"
+               type="[Ljavax.management.ObjectName;"/>
+               
+    <attribute name="configFile"
+               description="Location of the context.xml resource or file"
+               type="java.lang.String"/>
+               
+    <attribute   name="cookies"
+               description="Should we attempt to use cookies for session id
+               communication?"
+               type="boolean"/>
+      
+    <attribute name="compilerClasspath"
+               description="The compiler classpath to use"
+               type="java.lang.String"/>
+      
+    <attribute name="crossContext"
+               description="Should we allow the ServletContext.getContext() method to access the context of other web applications in this server?"
+               type="boolean"/>
+
+    <attribute name="defaultContextXml"
+               description="Location of the default context.xml resource or file"
+               type="java.lang.String"/>
+               
+    <attribute name="defaultWebXml"
+               description="Location of the default web.xml resource or file"
+               type="java.lang.String"/>
+               
+    <attribute name="delegate"
+               description=""
+               type="boolean"/>
+               
+    <attribute name="deploymentDescriptor"
+               description="String deployment descriptor "
+               type="java.lang.String"/>
+                     
+    <attribute name="docBase"
+               description="The document root for this web application"
+               type="java.lang.String"/>
+      
+    <attribute name="engineName"
+               description="Name of the engine domain, if different from the context domain"
+               type="java.lang.String"/>
+
+    <attribute name="eventProvider"
+               description="Event provider support for this managed object"
+               is="true"
+               type="boolean"/>
+                              
+    <attribute name="javaVMs"
+               description="The Java virtual machines on which this module is running"
+               type="[Ljava.lang.String;"/>
+
+    <attribute name="loader"
+               description="Associated loader."
+               type="org.apache.catalina.Loader" />
+      
+    <attribute name="logger"
+               description="Associated logger."
+               type="org.apache.commons.logging.Log" />
+      
+    <attribute name="managedResource"
+               description="The managed resource this MBean is associated with"
+               type="java.lang.Object"/>
+      
+    <attribute name="manager"
+               description="Associated manager."
+               type="org.apache.catalina.Manager" />
+      
+    <attribute name="mappingObject"
+               description="The object used for mapping"
+               type="java.lang.Object"/>
+      
+    <attribute name="objectName"
+               description="Name of the object"
+               type="java.lang.String"/>
+      
+    <attribute name="originalDocBase"
+               description="The original document root for this web application"
+               type="java.lang.String"/>
+
+    <attribute name="override"
+               description="The DefaultContext override flag for this web application"
+               type="boolean"/>
+      
+    <attribute name="parentClassLoader"
+               description="Parent class loader."
+               type="java.lang.ClassLoader" />
+      
+    <attribute name="path"
+               description="The context path for this Context"
+               type="java.lang.String"/>
+               
+    <attribute name="privileged"
+               description="Access to tomcat internals"
+               type="boolean"/>
+      
+    <attribute name="realm"
+               description="Associated realm."
+               type="org.apache.catalina.Realm" />
+      
+    <attribute name="reloadable"
+               description="The reloadable flag for this web application"
+               type="boolean"/>
+
+    <attribute name="saveConfig"
+               description="Should the configuration be written as needed on startup"
+               is="true"
+               type="boolean"/>
+      
+    <attribute name="server"
+               description="The J2EE Server this module is deployed on"
+               type="java.lang.String"/>
+                              
+    <attribute name="servlets"
+               description="JSR77 list of servlets"
+               type="[Ljava.lang.String;"
+               writeable="false"/>
+               
+    <attribute name="startupTime"
+               description="Time (in milliseconds) it took to start this context"
+               type="long"/>
+
+    <attribute name="startTime"
+               description="Time (in milliseconds since January 1, 1970, 00:00:00) when this context was started"
+               type="long"/>
+               
+    <attribute name="processingTime"
+               description="Cumulative execution times of all servlets in this context"
+               type="long"
+               writeable="false" />
+
+    <attribute name="state"
+               description="Current state of this component"
+               type="int"/>
+                     
+    <attribute name="stateManageable"
+               description="State management support for this managed object"
+               is="true"
+               type="boolean"/>
+               
+    <attribute name="statisticsProvider"
+               description="Performance statistics support for this managed object"
+               is="true"
+               type="boolean"/>
+               
+    <attribute name="staticResources"
+               description="Static resources associated with the context."
+               type="javax.naming.directory.DirContext"
+               writeable="false"/>
+      
+    <attribute   name="swallowOutput"
+               description="Flag to set to cause the system.out and system.err to be redirected to the logger when executing a servlet"
+               type="boolean"/>
+               
+    <attribute name="unloadDelay"
+               description="Amount of ms that the container will wait for servlets to unload"
+               type="long"/>
+               
+    <attribute name="tldScanTime"
+               description="Time spend scanning jars for TLDs for this context"
+               type="long"/>
+
+    <attribute name="useNaming"
+               description="Create a JNDI naming context for this application?"
+               is="true"
+               type="boolean"/>
+               
+    <attribute name="valveObjectNames"
+               description="ObjectNames for the valves associated with this container"
+               type="[Ljavax.management.ObjectName;"
+               writeable="false"/>
+
+    <attribute name="welcomeFiles"
+               description="The welcome files for this context"
+               type="[Ljava.lang.String;"
+               writeable="false"/>
+      
+    <attribute name="workDir"
+               description="The pathname to the work directory for this context"
+               type="java.lang.String"/>
+
+    <operation   name="addValve"
+               description="Add a valve to this Context"
+               impact="ACTION"
+               returnType="void">
+      <parameter name="valve"
+                 description="New valve to be added"
+                 type="org.apache.catalina.Valve"/>
+    </operation>
+    
+    <operation   name="removeValve"
+               description="Remove a valve from this Context"
+               impact="ACTION"
+               returnType="void">
+      <parameter name="valve"
+                 description="New valve to be removed"
+                 type="org.apache.catalina.Valve"/>
+    </operation>
+    
+    <operation   name="addLifecycleListener"
+               description="Add a lifecycle listener to this Context"
+               impact="ACTION"
+               returnType="void">
+      <parameter name="listener"
+                 description="New lifecycle listener to be added"
+                 type="org.apache.catalina.LifecycleListener"/>
+    </operation>
+    
+    <operation   name="removeLifecycleListener"
+               description="Remove a lifecycle listener from this Context"
+               impact="ACTION"
+               returnType="void">
+      <parameter name="listener"
+                 description="New lifecycle listener to be removed"
+                 type="org.apache.catalina.LifecycleListener"/>
+    </operation>
+    
+    <operation   name="reload"
+               description="Reload the webapplication"
+               impact="ACTION"
+               returnType="void">
+    </operation>
+    
+    <operation   name="init"
+               description="Register the context into the running server"
+               impact="ACTION"
+               returnType="void">
+    </operation>
+    
+    <operation   name="start"
+               description="Start the context"
+               impact="ACTION"
+               returnType="void">
+    </operation>
+    
+    <operation name="stop"
+               description="Stop the context"
+               impact="ACTION"
+               returnType="void">
+    </operation>
+    
+    <operation name="destroy"
+               description="Destroy the context"
+               impact="ACTION"
+               returnType="void">
+    </operation>
+    
+    <operation name="findMappingObject"
+               description="Return an object which may be utilized for mapping to this component"
+               impact="INFO"
+               returnType="org.apache.catalina.Context">    
+    </operation>    
+    
+    <operation name="findStaticResources"
+               description="Return the naming resources associated with this web application"
+               impact="INFO"
+               returnType="javax.naming.directory.DirContext">    
+    </operation>
+    
+  </mbean>
+  
+  <mbean name="StandardContextValve"
+         description="Valve that implements the default basic behavior for the
+         StandardContext container implementation"
+         domain="Catalina"
+         group="Valve"
+         type="org.apache.catalina.core.StandardContextValve">
+    
+    <attribute name="className"
+               description="Fully qualified class name of the managed object"
+               type="java.lang.String"
+               writeable="false"/>
+      
+  </mbean>
+  
+  <mbean name="StandardEngine"
+         type="org.apache.catalina.core.StandardEngine"
+         description="Standard Engine Component"
+         domain="Catalina"
+         group="Engine">
+    
+    <attribute name="defaultHost"
+               description="Name of the default Host for this Engine"
+               type="java.lang.String"/>
+      
+    <attribute   name="managedResource"
+               description="The managed resource this MBean is associated with"
+               type="java.lang.Object"/>
+      
+    <attribute   name="name"
+               description="Unique name of this Engine"
+               type="java.lang.String"/>
+      
+    <attribute   name="baseDir"
+               description="Base dir for this engine, typically same as catalina.base system property"
+               type="java.lang.String"/>
+      
+    <attribute   name="jvmRoute"
+               description="Route used for load balancing"
+               type="java.lang.String"/>
+      
+    <attribute name="realm"
+               description="Associated realm."
+               type="org.apache.catalina.Realm" />
+      
+    <attribute name="valveObjectNames"
+               description="ObjectNames for the valves associated with this container"
+               type="[Ljavax.management.ObjectName;"
+               writeable="false"/>
+
+    <operation name="addChild"
+               description="Add a virtual host"
+               impact="ACTION"
+               returnType="void">
+      <parameter name="child"
+                 description="Host object"
+                 type="org.apache.catalina.Container"/>
+    </operation>
+    
+    <operation name="start" description="Start" impact="ACTION" returnType="void" />
+    <operation name="stop" description="Stop" impact="ACTION" returnType="void" />
+      
+  </mbean>
+
+  
+  <mbean name="StandardEngineValve"
+         description="Valve that implements the default basic behavior for the
+         StandardEngine container implementation"
+         domain="Catalina"
+         group="Valve"
+         type="org.apache.catalina.core.StandardEngineValve">
+    
+    <attribute   name="className"
+               description="Fully qualified class name of the managed object"
+               type="java.lang.String"
+               writeable="false"/>
+      
+  </mbean>
+  
+  <mbean name="StandardHost"
+         description="Standard Host Component"
+         domain="Catalina"
+         group="Host"
+         type="org.apache.catalina.core.StandardHost">
+    
+    <attribute name="appBase"
+               description="The application root for this Host"
+               type="java.lang.String"/>
+      
+    <attribute name="autoDeploy"
+               description="The auto deploy flag for this Host"
+               type="boolean"/>
+                 
+    <attribute name="configClass"
+               description="The configuration class for contexts"
+               type="java.lang.String"/>
+      
+    <attribute name="deployOnStartup"
+               description="The deploy on startup flag for this Host"
+               type="boolean"/>
+
+    <attribute name="deployXML"
+               description="deploy Context XML config files property"
+               is="true"
+               type="boolean"/>
+      
+    <attribute name="managedResource"
+               description="The managed resource this MBean is associated with"
+               type="java.lang.Object"/>
+      
+    <attribute name="name"
+               description="Unique name of this Host"
+               type="java.lang.String"/>
+      
+    <attribute name="unpackWARs"
+               description="Unpack WARs property"
+               is="true"
+               type="boolean"/>
+      
+    <attribute name="xmlNamespaceAware"
+               description="Attribute value used to turn on/off XML namespace awareness"
+               type="boolean"/>
+      
+    <attribute name="xmlValidation"
+               description="Attribute value used to turn on/off XML validation"
+               type="boolean"/>
+
+    <attribute name="children"
+               description="Object names of all children"
+               type="[Ljavax.management.ObjectName;"/>
+      
+    <attribute name="aliases"
+               description="Host aliases"
+               type="[Ljava.lang.String;"/>
+      
+    <attribute name="realm"
+               description="Associated realm."
+               type="org.apache.catalina.Realm" />
+      
+    <attribute name="valveNames"
+               description="Return the MBean Names of the Valves associated with this Host"
+               type="[Ljava.lang.String;"/>
+      
+    <attribute name="valveObjectNames"
+               description="Return the MBean ObjectNames of the Valves associated with this Host"
+               type="[Ljavax.management.ObjectName;"/>
+      
+    <operation name="addAlias"
+               description="Add an alias name that should be mapped to this Host"
+               impact="ACTION"
+               returnType="void">
+      <parameter name="alias"
+                 description="The alias to be added"
+                 type="java.lang.String"/>
+    </operation>
+    
+    <operation name="findAliases"
+               description="Return the set of alias names for this Host"
+               impact="INFO"
+               returnType="[Ljava.lang.String;"/>
+
+    <operation name="addChild"
+               description="Add a context"
+               impact="ACTION">
+      <parameter name="child"
+                 description="Context to be added"
+                 type="org.apache.catalina.Container"/>
+    </operation>
+      
+    <operation   name="removeAlias"
+               description="Remove the specified alias name from the aliases for this  Host"
+               impact="ACTION"
+               returnType="void">
+      <parameter name="alias"
+                 description="Alias name to be removed"
+                 type="java.lang.String"/>
+    </operation>
+    
+    <operation name="start" description="Start" impact="ACTION" returnType="void" />
+    <operation name="stop" description="Stop" impact="ACTION" returnType="void" />
+    <operation name="init" description="Init" impact="ACTION" returnType="void" />
+    <operation name="destroy" description="Destroy" impact="ACTION" returnType="void" />
+  </mbean>
+  
+  <mbean name="StandardHostValve"
+         description="Valve that implements the default basic behavior for the
+         StandardHost container implementation"
+         domain="Catalina"
+         group="Valve"
+         type="org.apache.catalina.core.StandardHostValve">
+    
+    <attribute name="className"
+               description="Fully qualified class name of the managed object"
+               type="java.lang.String"
+               writeable="false"/>
+
+  </mbean>
+
+  <mbean name="StandardServer"
+         description="Standard Server Component"
+         domain="Catalina"
+         group="Server"
+         type="org.apache.catalina.core.StandardServer">
+    
+    <attribute name="managedResource"
+               description="The managed resource this MBean is associated with"
+               type="java.lang.Object"/>
+      
+    <attribute name="port"
+               description="TCP port for shutdown messages"
+               type="int"/>
+      
+    <attribute name="shutdown"
+               description="Shutdown password"
+               type="java.lang.String"/>
+      
+    <attribute name="serviceNames"
+               description="Object names of all services we know about"
+               type="[Ljavax.management.ObjectName;"/>
+
+    <attribute name="serverInfo"
+               description="Tomcat server release identifier"
+               type="java.lang.String"
+               writeable="false"/>
+      
+    <operation name="await"
+               description="Wait for the shutdown message"
+               impact="ACTION"
+               returnType="void" />
+
+    <operation name="storeConfig"
+               description="Save current state to server.xml file"
+               impact="ACTION"
+               returnType="void">
+
+    </operation>
+    
+  </mbean>
+
+  
+  <mbean name="StandardService"
+         description="Standard Service Component"
+         domain="Catalina"
+         group="Service"
+         type="org.apache.catalina.core.StandardService">
+    
+    <attribute name="managedResource"
+               description="The managed resource this MBean is associated with"
+               type="java.lang.Object"/>
+      
+    <attribute name="name"
+               description="Unique name of this Service"
+               type="java.lang.String"/>
+      
+    <attribute name="connectorNames"
+               description="ObjectNames of the connectors"
+               type="[Ljavax.management.ObjectName;"
+               writeable="false" />
+      
+    <attribute name="container"
+               description="Servlet engine that will process the requests"
+               type="org.apache.catalina.Container" />
+
+    <attribute name="containerName"
+               description="ObjectNames of the engine"
+               type="javax.management.ObjectName"
+               writeable="false" />
+
+    <operation name="addConnector"
+               description="Add a new connector"
+               impact="ACTION"
+               returnType="void">
+      <parameter name="connector"
+                 description="Connector object"
+                 type="org.apache.catalina.connector.Connector"/>
+    </operation>
+    
+    <operation name="start" description="Start" impact="ACTION" returnType="void" />
+    <operation name="stop" description="Stop" impact="ACTION" returnType="void" />
+  </mbean>
+
+  <mbean name="StandardWrapper"
+         description="Wrapper that represents an individual servlet definition"
+         domain="Catalina"
+         group="Wrapper"
+         type="org.apache.catalina.core.StandardWrapper">
+               
+    <attribute name="engineName"
+               description="Fully qualified class name of the managed object"
+               type="java.lang.String"
+               writeable="false"/>
+               
+    <attribute name="eventProvider"
+               description="Event provider support for this managed object"
+               is="true"
+               type="boolean"/>
+
+    <attribute name="objectName"
+               description="Name of the object"
+               type="java.lang.String"/>
+
+    <attribute name="stateManageable"
+               description="State management support for this managed object"
+               is="true"
+               type="boolean"/>
+
+    <attribute name="statisticsProvider"
+               description="Performance statistics support for this managed object"
+               is="true"
+               type="boolean"/>
+
+    <attribute name="processingTime"
+               description="Total execution time of the servlet's service method"
+               type="long"
+               writeable="false" />
+
+    <attribute name="maxTime"
+               description="Maximum processing time of a request"
+               type="long"
+               writeable="false" />
+
+    <attribute name="minTime"
+               description="Minimum processing time of a request"
+               type="long"
+               writeable="false" />
+
+    <attribute name="requestCount"
+               description="Number of requests processed by this wrapper"
+               type="int"
+               writeable="false" />
+
+    <attribute name="errorCount"
+               description="Error count"
+               type="int"
+               writeable="false" />
+
+    <attribute name="loadTime"
+               description="Load time"
+               type="long"
+               writeable="false" />
+
+    <attribute name="classLoadTime"
+               description="Class loading time"
+               type="int"
+               writeable="false" />
+
+    <operation name="findMappings"
+               description="Return the mappings associated with this wrapper"
+               impact="INFO"
+               returnType="[Ljava.lang.String;">
+    </operation>
+               
+    <operation name="findMappingObject"
+               description="Return an object which may be utilized for mapping to this component"
+               impact="INFO"
+               returnType="org.apache.catalina.Wrapper">
+    </operation>
+    
+  </mbean>
+  
+  <mbean name="StandardWrapperValve"
+         description="Valve that implements the default basic behavior for the
+         StandardWrapper container implementation"
+         domain="Catalina"
+         group="Valve"
+         type="org.apache.catalina.core.StandardWrapperValve">
+         
+     <attribute name="className"
+                description="Fully qualified class name of the managed object"
+                type="java.lang.String"
+                writeable="false"/>  
+                    
+  </mbean>
+
+</mbeans-descriptors>

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/deploy/ApplicationParameter.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/deploy/ApplicationParameter.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/deploy/ApplicationParameter.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,121 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.deploy;
+
+import java.io.Serializable;
+
+
+/**
+ * Representation of a context initialization parameter that is configured
+ * in the server configuration file, rather than the application deployment
+ * descriptor.  This is convenient for establishing default values (which
+ * may be configured to allow application overrides or not) without having
+ * to modify the application deployment descriptor itself.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302879 $ $Date: 2004-05-13 15:40:49 -0500 (Thu, 13 May 2004) $
+ */
+
+public class ApplicationParameter implements Serializable {
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * The description of this environment entry.
+     */
+    private String description = null;
+
+    public String getDescription() {
+        return (this.description);
+    }
+
+    public void setDescription(String description) {
+        this.description = description;
+    }
+
+
+    /**
+     * The name of this application parameter.
+     */
+    private String name = null;
+
+    public String getName() {
+        return (this.name);
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+
+    /**
+     * Does this application parameter allow overrides by the application
+     * deployment descriptor?
+     */
+    private boolean override = true;
+
+    public boolean getOverride() {
+        return (this.override);
+    }
+
+    public void setOverride(boolean override) {
+        this.override = override;
+    }
+
+
+    /**
+     * The value of this application parameter.
+     */
+    private String value = null;
+
+    public String getValue() {
+        return (this.value);
+    }
+
+    public void setValue(String value) {
+        this.value = value;
+    }
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Return a String representation of this object.
+     */
+    public String toString() {
+
+        StringBuffer sb = new StringBuffer("ApplicationParameter[");
+        sb.append("name=");
+        sb.append(name);
+        if (description != null) {
+            sb.append(", description=");
+            sb.append(description);
+        }
+        sb.append(", value=");
+        sb.append(value);
+        sb.append(", override=");
+        sb.append(override);
+        sb.append("]");
+        return (sb.toString());
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/deploy/ContextEjb.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/deploy/ContextEjb.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/deploy/ContextEjb.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,118 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.deploy;
+
+import java.io.Serializable;
+
+
+/**
+ * Representation of an EJB resource reference for a web application, as
+ * represented in a <code>&lt;ejb-ref&gt;</code> element in the
+ * deployment descriptor.
+ *
+ * @author Craig R. McClanahan
+ * @author Peter Rossbach (pero at apache.org)
+ * @version $Revision: 303342 $ $Date: 2004-10-05 02:56:49 -0500 (Tue, 05 Oct 2004) $
+ */
+
+public class ContextEjb extends ResourceBase implements Serializable {
+
+
+    // ------------------------------------------------------------- Properties
+
+
+
+    /**
+     * The name of the EJB home implementation class.
+     */
+    private String home = null;
+
+    public String getHome() {
+        return (this.home);
+    }
+
+    public void setHome(String home) {
+        this.home = home;
+    }
+
+
+    /**
+     * The link to a J2EE EJB definition.
+     */
+    private String link = null;
+
+    public String getLink() {
+        return (this.link);
+    }
+
+    public void setLink(String link) {
+        this.link = link;
+    }
+
+    /**
+     * The name of the EJB remote implementation class.
+     */
+    private String remote = null;
+
+    public String getRemote() {
+        return (this.remote);
+    }
+
+    public void setRemote(String remote) {
+        this.remote = remote;
+    }
+
+    
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Return a String representation of this object.
+     */
+    public String toString() {
+
+        StringBuffer sb = new StringBuffer("ContextEjb[");
+        sb.append("name=");
+        sb.append(getName());
+        if (getDescription() != null) {
+            sb.append(", description=");
+            sb.append(getDescription());
+        }
+        if (getType() != null) {
+            sb.append(", type=");
+            sb.append(getType());
+        }
+        if (home != null) {
+            sb.append(", home=");
+            sb.append(home);
+        }
+        if (remote != null) {
+            sb.append(", remote=");
+            sb.append(remote);
+        }
+        if (link != null) {
+            sb.append(", link=");
+            sb.append(link);
+        }
+        sb.append("]");
+        return (sb.toString());
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/deploy/ContextEnvironment.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/deploy/ContextEnvironment.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/deploy/ContextEnvironment.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,155 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.deploy;
+
+import java.io.Serializable;
+
+
+/**
+ * Representation of an application environment entry, as represented in
+ * an <code>&lt;env-entry&gt;</code> element in the deployment descriptor.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302879 $ $Date: 2004-05-13 15:40:49 -0500 (Thu, 13 May 2004) $
+ */
+
+public class ContextEnvironment implements Serializable {
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * The description of this environment entry.
+     */
+    private String description = null;
+
+    public String getDescription() {
+        return (this.description);
+    }
+
+    public void setDescription(String description) {
+        this.description = description;
+    }
+
+
+    /**
+     * The name of this environment entry.
+     */
+    private String name = null;
+
+    public String getName() {
+        return (this.name);
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+
+    /**
+     * Does this environment entry allow overrides by the application
+     * deployment descriptor?
+     */
+    private boolean override = true;
+
+    public boolean getOverride() {
+        return (this.override);
+    }
+
+    public void setOverride(boolean override) {
+        this.override = override;
+    }
+
+
+    /**
+     * The type of this environment entry.
+     */
+    private String type = null;
+
+    public String getType() {
+        return (this.type);
+    }
+
+    public void setType(String type) {
+        this.type = type;
+    }
+
+
+    /**
+     * The value of this environment entry.
+     */
+    private String value = null;
+
+    public String getValue() {
+        return (this.value);
+    }
+
+    public void setValue(String value) {
+        this.value = value;
+    }
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Return a String representation of this object.
+     */
+    public String toString() {
+
+        StringBuffer sb = new StringBuffer("ContextEnvironment[");
+        sb.append("name=");
+        sb.append(name);
+        if (description != null) {
+            sb.append(", description=");
+            sb.append(description);
+        }
+        if (type != null) {
+            sb.append(", type=");
+            sb.append(type);
+        }
+        if (value != null) {
+            sb.append(", value=");
+            sb.append(value);
+        }
+        sb.append(", override=");
+        sb.append(override);
+        sb.append("]");
+        return (sb.toString());
+
+    }
+
+
+    // -------------------------------------------------------- Package Methods
+
+
+    /**
+     * The NamingResources with which we are associated (if any).
+     */
+    protected NamingResources resources = null;
+
+    public NamingResources getNamingResources() {
+        return (this.resources);
+    }
+
+    void setNamingResources(NamingResources resources) {
+        this.resources = resources;
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/deploy/ContextLocalEjb.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/deploy/ContextLocalEjb.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/deploy/ContextLocalEjb.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,115 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.deploy;
+
+import java.io.Serializable;
+
+
+/**
+ * Representation of a local EJB resource reference for a web application, as
+ * represented in a <code>&lt;ejb-local-ref&gt;</code> element in the
+ * deployment descriptor.
+ *
+ * @author Craig R. McClanahan
+ * @author Peter Rossbach (pero at apache.org)
+ * @version $Revision: 303342 $ $Date: 2004-10-05 02:56:49 -0500 (Tue, 05 Oct 2004) $
+ */
+
+public class ContextLocalEjb extends ResourceBase implements Serializable {
+
+
+    // ------------------------------------------------------------- Properties
+
+    /**
+     * The name of the EJB home implementation class.
+     */
+    private String home = null;
+
+    public String getHome() {
+        return (this.home);
+    }
+
+    public void setHome(String home) {
+        this.home = home;
+    }
+
+
+    /**
+     * The link to a J2EE EJB definition.
+     */
+    private String link = null;
+
+    public String getLink() {
+        return (this.link);
+    }
+
+    public void setLink(String link) {
+        this.link = link;
+    }
+
+
+    /**
+     * The name of the EJB local implementation class.
+     */
+    private String local = null;
+
+    public String getLocal() {
+        return (this.local);
+    }
+
+    public void setLocal(String local) {
+        this.local = local;
+    }
+
+    
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Return a String representation of this object.
+     */
+    public String toString() {
+
+        StringBuffer sb = new StringBuffer("ContextLocalEjb[");
+        sb.append("name=");
+        sb.append(getName());
+        if (getDescription() != null) {
+            sb.append(", description=");
+            sb.append(getDescription());
+        }
+        if (getType() != null) {
+            sb.append(", type=");
+            sb.append(getType());
+        }
+        if (home != null) {
+            sb.append(", home=");
+            sb.append(home);
+        }
+        if (link != null) {
+            sb.append(", link=");
+            sb.append(link);
+        }
+        if (local != null) {
+            sb.append(", local=");
+            sb.append(local);
+        }
+        sb.append("]");
+        return (sb.toString());
+
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/deploy/ContextResource.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/deploy/ContextResource.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/deploy/ContextResource.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,99 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.deploy;
+
+import java.io.Serializable;
+
+/**
+ * Representation of a resource reference for a web application, as
+ * represented in a <code>&lt;resource-ref&gt;</code> element in the
+ * deployment descriptor.
+ *
+ * @author Craig R. McClanahan
+ * @author Peter Rossbach (pero at apache.org)
+ * @version $Revision: 303342 $ $Date: 2004-10-05 02:56:49 -0500 (Tue, 05 Oct 2004) $
+ */
+
+public class ContextResource extends ResourceBase implements Serializable {
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * The authorization requirement for this resource
+     * (<code>Application</code> or <code>Container</code>).
+     */
+    private String auth = null;
+
+    public String getAuth() {
+        return (this.auth);
+    }
+
+    public void setAuth(String auth) {
+        this.auth = auth;
+    }
+
+    /**
+     * The sharing scope of this resource factory (<code>Shareable</code>
+     * or <code>Unshareable</code>).
+     */
+    private String scope = "Shareable";
+
+    public String getScope() {
+        return (this.scope);
+    }
+
+    public void setScope(String scope) {
+        this.scope = scope;
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Return a String representation of this object.
+     */
+    public String toString() {
+
+        StringBuffer sb = new StringBuffer("ContextResource[");
+        sb.append("name=");
+        sb.append(getName());
+        if (getDescription() != null) {
+            sb.append(", description=");
+            sb.append(getDescription());
+        }
+        if (getType() != null) {
+            sb.append(", type=");
+            sb.append(getType());
+        }
+        if (auth != null) {
+            sb.append(", auth=");
+            sb.append(auth);
+        }
+        if (scope != null) {
+            sb.append(", scope=");
+            sb.append(scope);
+        }
+        sb.append("]");
+        return (sb.toString());
+
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/deploy/ContextResourceEnvRef.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/deploy/ContextResourceEnvRef.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/deploy/ContextResourceEnvRef.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,75 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.deploy;
+
+import java.io.Serializable;
+
+
+/**
+ * Representation of an application resource reference, as represented in
+ * an <code>&lt;res-env-refy&gt;</code> element in the deployment descriptor.
+ *
+ * @author Craig R. McClanahan
+ * @author Peter Rossbach (pero at apache.org)
+ * @version $Revision: 303342 $ $Date: 2004-10-05 02:56:49 -0500 (Tue, 05 Oct 2004) $
+ */
+
+public class ContextResourceEnvRef extends ResourceBase implements Serializable {
+
+
+    // ------------------------------------------------------------- Properties
+
+    /**
+     * Does this environment entry allow overrides by the application
+     * deployment descriptor?
+     */
+    private boolean override = true;
+
+    public boolean getOverride() {
+        return (this.override);
+    }
+
+    public void setOverride(boolean override) {
+        this.override = override;
+    }
+    
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Return a String representation of this object.
+     */
+    public String toString() {
+
+        StringBuffer sb = new StringBuffer("ContextResourceEnvRef[");
+        sb.append("name=");
+        sb.append(getName());
+        if (getType() != null) {
+            sb.append(", type=");
+            sb.append(getType());
+        }
+        sb.append(", override=");
+        sb.append(override);
+        sb.append("]");
+        return (sb.toString());
+
+    }
+
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/deploy/ContextResourceLink.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/deploy/ContextResourceLink.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/deploy/ContextResourceLink.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,76 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.deploy;
+
+import java.io.Serializable;
+
+
+/**
+ * Representation of a resource link for a web application, as
+ * represented in a <code>&lt;ResourceLink&gt;</code> element in the
+ * server configuration file.
+ *
+ * @author Remy Maucherat
+ * @author Peter Rossbach (Peter Rossbach (pero at apache.org))
+ * @version $Revision: 303342 $ $Date: 2004-10-05 02:56:49 -0500 (Tue, 05 Oct 2004) $
+ */
+
+public class ContextResourceLink extends ResourceBase implements Serializable {
+
+
+    // ------------------------------------------------------------- Properties
+
+   /**
+     * The global name of this resource.
+     */
+    private String global = null;
+
+    public String getGlobal() {
+        return (this.global);
+    }
+
+    public void setGlobal(String global) {
+        this.global = global;
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Return a String representation of this object.
+     */
+    public String toString() {
+
+        StringBuffer sb = new StringBuffer("ContextResourceLink[");
+        sb.append("name=");
+        sb.append(getName());
+        if (getType() != null) {
+            sb.append(", type=");
+            sb.append(getType());
+        }
+        if (getGlobal() != null) {
+            sb.append(", global=");
+            sb.append(getGlobal());
+        }
+        sb.append("]");
+        return (sb.toString());
+
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/deploy/ContextTransaction.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/deploy/ContextTransaction.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/deploy/ContextTransaction.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,105 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.deploy;
+
+import java.io.Serializable;
+import java.util.HashMap;
+import java.util.Iterator;
+
+
+/**
+ * Representation of an application resource reference, as represented in
+ * an <code>&lt;res-env-refy&gt;</code> element in the deployment descriptor.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 303032 $ $Date: 2004-07-26 11:04:02 -0500 (Mon, 26 Jul 2004) $
+ */
+
+public class ContextTransaction implements Serializable {
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * Holder for our configured properties.
+     */
+    private HashMap properties = new HashMap();
+
+    /**
+     * Return a configured property.
+     */
+    public Object getProperty(String name) {
+        return properties.get(name);
+    }
+
+    /**
+     * Set a configured property.
+     */
+    public void setProperty(String name, Object value) {
+        properties.put(name, value);
+    }
+
+    /** 
+     * remove a configured property.
+     */
+    public void removeProperty(String name) {
+        properties.remove(name);
+    }
+
+    /**
+     * List properties.
+     */
+    public Iterator listProperties() {
+        return properties.keySet().iterator();
+    }
+    
+    
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Return a String representation of this object.
+     */
+    public String toString() {
+
+        StringBuffer sb = new StringBuffer("Transaction[");
+        sb.append("]");
+        return (sb.toString());
+
+    }
+
+
+    // -------------------------------------------------------- Package Methods
+
+
+    /**
+     * The NamingResources with which we are associated (if any).
+     */
+    protected NamingResources resources = null;
+
+    public NamingResources getNamingResources() {
+        return (this.resources);
+    }
+
+    void setNamingResources(NamingResources resources) {
+        this.resources = resources;
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/deploy/ErrorPage.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/deploy/ErrorPage.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/deploy/ErrorPage.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,170 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.deploy;
+
+
+import org.apache.catalina.util.RequestUtil;
+import java.io.Serializable;
+
+
+/**
+ * Representation of an error page element for a web application,
+ * as represented in a <code>&lt;error-page&gt;</code> element in the
+ * deployment descriptor.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302879 $ $Date: 2004-05-13 15:40:49 -0500 (Thu, 13 May 2004) $
+ */
+
+public class ErrorPage implements Serializable {
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The error (status) code for which this error page is active.
+     */
+    private int errorCode = 0;
+
+
+    /**
+     * The exception type for which this error page is active.
+     */
+    private String exceptionType = null;
+
+
+    /**
+     * The context-relative location to handle this error or exception.
+     */
+    private String location = null;
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * Return the error code.
+     */
+    public int getErrorCode() {
+
+        return (this.errorCode);
+
+    }
+
+
+    /**
+     * Set the error code.
+     *
+     * @param errorCode The new error code
+     */
+    public void setErrorCode(int errorCode) {
+
+        this.errorCode = errorCode;
+
+    }
+
+
+    /**
+     * Set the error code (hack for default XmlMapper data type).
+     *
+     * @param errorCode The new error code
+     */
+    public void setErrorCode(String errorCode) {
+
+        try {
+            this.errorCode = Integer.parseInt(errorCode);
+        } catch (Throwable t) {
+            this.errorCode = 0;
+        }
+
+    }
+
+
+    /**
+     * Return the exception type.
+     */
+    public String getExceptionType() {
+
+        return (this.exceptionType);
+
+    }
+
+
+    /**
+     * Set the exception type.
+     *
+     * @param exceptionType The new exception type
+     */
+    public void setExceptionType(String exceptionType) {
+
+        this.exceptionType = exceptionType;
+
+    }
+
+
+    /**
+     * Return the location.
+     */
+    public String getLocation() {
+
+        return (this.location);
+
+    }
+
+
+    /**
+     * Set the location.
+     *
+     * @param location The new location
+     */
+    public void setLocation(String location) {
+
+        //        if ((location == null) || !location.startsWith("/"))
+        //            throw new IllegalArgumentException
+        //                ("Error Page Location must start with a '/'");
+        this.location = RequestUtil.URLDecode(location);
+
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Render a String representation of this object.
+     */
+    public String toString() {
+
+        StringBuffer sb = new StringBuffer("ErrorPage[");
+        if (exceptionType == null) {
+            sb.append("errorCode=");
+            sb.append(errorCode);
+        } else {
+            sb.append("exceptionType=");
+            sb.append(exceptionType);
+        }
+        sb.append(", location=");
+        sb.append(location);
+        sb.append("]");
+        return (sb.toString());
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/deploy/FilterDef.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/deploy/FilterDef.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/deploy/FilterDef.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,171 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.deploy;
+
+
+import java.util.HashMap;
+import java.util.Map;
+import java.io.Serializable;
+
+
+/**
+ * Representation of a filter definition for a web application, as represented
+ * in a <code>&lt;filter&gt;</code> element in the deployment descriptor.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302879 $ $Date: 2004-05-13 15:40:49 -0500 (Thu, 13 May 2004) $
+ */
+
+public class FilterDef implements Serializable {
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * The description of this filter.
+     */
+    private String description = null;
+
+    public String getDescription() {
+        return (this.description);
+    }
+
+    public void setDescription(String description) {
+        this.description = description;
+    }
+
+
+    /**
+     * The display name of this filter.
+     */
+    private String displayName = null;
+
+    public String getDisplayName() {
+        return (this.displayName);
+    }
+
+    public void setDisplayName(String displayName) {
+        this.displayName = displayName;
+    }
+
+
+    /**
+     * The fully qualified name of the Java class that implements this filter.
+     */
+    private String filterClass = null;
+
+    public String getFilterClass() {
+        return (this.filterClass);
+    }
+
+    public void setFilterClass(String filterClass) {
+        this.filterClass = filterClass;
+    }
+
+
+    /**
+     * The name of this filter, which must be unique among the filters
+     * defined for a particular web application.
+     */
+    private String filterName = null;
+
+    public String getFilterName() {
+        return (this.filterName);
+    }
+
+    public void setFilterName(String filterName) {
+        this.filterName = filterName;
+    }
+
+
+    /**
+     * The large icon associated with this filter.
+     */
+    private String largeIcon = null;
+
+    public String getLargeIcon() {
+        return (this.largeIcon);
+    }
+
+    public void setLargeIcon(String largeIcon) {
+        this.largeIcon = largeIcon;
+    }
+
+
+    /**
+     * The set of initialization parameters for this filter, keyed by
+     * parameter name.
+     */
+    private Map parameters = new HashMap();
+
+    public Map getParameterMap() {
+
+        return (this.parameters);
+
+    }
+
+
+    /**
+     * The small icon associated with this filter.
+     */
+    private String smallIcon = null;
+
+    public String getSmallIcon() {
+        return (this.smallIcon);
+    }
+
+    public void setSmallIcon(String smallIcon) {
+        this.smallIcon = smallIcon;
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Add an initialization parameter to the set of parameters associated
+     * with this filter.
+     *
+     * @param name The initialization parameter name
+     * @param value The initialization parameter value
+     */
+    public void addInitParameter(String name, String value) {
+
+        parameters.put(name, value);
+
+    }
+
+
+    /**
+     * Render a String representation of this object.
+     */
+    public String toString() {
+
+        StringBuffer sb = new StringBuffer("FilterDef[");
+        sb.append("filterName=");
+        sb.append(this.filterName);
+        sb.append(", filterClass=");
+        sb.append(this.filterClass);
+        sb.append("]");
+        return (sb.toString());
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/deploy/FilterMap.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/deploy/FilterMap.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/deploy/FilterMap.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,214 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.deploy;
+
+
+import org.apache.catalina.util.RequestUtil;
+import java.io.Serializable;
+
+
+/**
+ * Representation of a filter mapping for a web application, as represented
+ * in a <code>&lt;filter-mapping&gt;</code> element in the deployment
+ * descriptor.  Each filter mapping must contain a filter name plus either
+ * a URL pattern or a servlet name.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302879 $ $Date: 2004-05-13 15:40:49 -0500 (Thu, 13 May 2004) $
+ */
+
+public class FilterMap implements Serializable {
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * The name of this filter to be executed when this mapping matches
+     * a particular request.
+     */
+    
+    public static final int ERROR = 1;
+    public static final int FORWARD = 2;
+    public static final int FORWARD_ERROR =3;  
+    public static final int INCLUDE = 4;
+    public static final int INCLUDE_ERROR  = 5;
+    public static final int INCLUDE_ERROR_FORWARD  =6;
+    public static final int INCLUDE_FORWARD  = 7;
+    public static final int REQUEST = 8;
+    public static final int REQUEST_ERROR = 9;
+    public static final int REQUEST_ERROR_FORWARD = 10;
+    public static final int REQUEST_ERROR_FORWARD_INCLUDE = 11;
+    public static final int REQUEST_ERROR_INCLUDE = 12;
+    public static final int REQUEST_FORWARD = 13;
+    public static final int REQUEST_INCLUDE = 14;
+    public static final int REQUEST_FORWARD_INCLUDE= 15;
+    
+    // represents nothing having been set. This will be seen 
+    // as equal to a REQUEST
+    private static final int NOT_SET = -1;
+    
+    private int dispatcherMapping=NOT_SET;
+    
+    private String filterName = null;    
+
+    public String getFilterName() {
+        return (this.filterName);
+    }
+
+    public void setFilterName(String filterName) {
+        this.filterName = filterName;
+    }
+
+
+    /**
+     * The servlet name this mapping matches.
+     */
+    private String servletName = null;
+
+    public String getServletName() {
+        return (this.servletName);
+    }
+
+    public void setServletName(String servletName) {
+        this.servletName = servletName;
+    }
+
+
+    /**
+     * The URL pattern this mapping matches.
+     */
+    private String urlPattern = null;
+
+    public String getURLPattern() {
+        return (this.urlPattern);
+    }
+
+    public void setURLPattern(String urlPattern) {
+        this.urlPattern = RequestUtil.URLDecode(urlPattern);
+    }
+    
+    /**
+     *
+     * This method will be used to set the current state of the FilterMap
+     * representing the state of when filters should be applied:
+     *
+     *        ERROR
+     *        FORWARD
+     *        FORWARD_ERROR
+     *        INCLUDE
+     *        INCLUDE_ERROR
+     *        INCLUDE_ERROR_FORWARD
+     *        REQUEST
+     *        REQUEST_ERROR
+     *        REQUEST_ERROR_INCLUDE
+     *        REQUEST_ERROR_FORWARD_INCLUDE
+     *        REQUEST_INCLUDE
+     *        REQUEST_FORWARD,
+     *        REQUEST_FORWARD_INCLUDE
+     *
+     */
+    public void setDispatcher(String dispatcherString) {
+        String dispatcher = dispatcherString.toUpperCase();
+        
+        if (dispatcher.equals("FORWARD")) {
+
+            // apply FORWARD to the global dispatcherMapping.
+            switch (dispatcherMapping) {
+                case NOT_SET  :  dispatcherMapping = FORWARD; break;
+                case ERROR : dispatcherMapping = FORWARD_ERROR; break;
+                case INCLUDE  :  dispatcherMapping = INCLUDE_FORWARD; break;
+                case INCLUDE_ERROR  :  dispatcherMapping = INCLUDE_ERROR_FORWARD; break;
+                case REQUEST : dispatcherMapping = REQUEST_FORWARD; break;
+                case REQUEST_ERROR : dispatcherMapping = REQUEST_ERROR_FORWARD; break;
+                case REQUEST_ERROR_INCLUDE : dispatcherMapping = REQUEST_ERROR_FORWARD_INCLUDE; break;
+                case REQUEST_INCLUDE : dispatcherMapping = REQUEST_FORWARD_INCLUDE; break;
+            }
+        } else if (dispatcher.equals("INCLUDE")) {
+            // apply INCLUDE to the global dispatcherMapping.
+            switch (dispatcherMapping) {
+                case NOT_SET  :  dispatcherMapping = INCLUDE; break;
+                case ERROR : dispatcherMapping = INCLUDE_ERROR; break;
+                case FORWARD  :  dispatcherMapping = INCLUDE_FORWARD; break;
+                case FORWARD_ERROR  :  dispatcherMapping = INCLUDE_ERROR_FORWARD; break;
+                case REQUEST : dispatcherMapping = REQUEST_INCLUDE; break;
+                case REQUEST_ERROR : dispatcherMapping = REQUEST_ERROR_INCLUDE; break;
+                case REQUEST_ERROR_FORWARD : dispatcherMapping = REQUEST_ERROR_FORWARD_INCLUDE; break;
+                case REQUEST_FORWARD : dispatcherMapping = REQUEST_FORWARD_INCLUDE; break;
+            }
+        } else if (dispatcher.equals("REQUEST")) {
+            // apply REQUEST to the global dispatcherMapping.
+            switch (dispatcherMapping) {
+                case NOT_SET  :  dispatcherMapping = REQUEST; break;
+                case ERROR : dispatcherMapping = REQUEST_ERROR; break;
+                case FORWARD  :  dispatcherMapping = REQUEST_FORWARD; break;
+                case FORWARD_ERROR  :  dispatcherMapping = REQUEST_ERROR_FORWARD; break;
+                case INCLUDE  :  dispatcherMapping = REQUEST_INCLUDE; break;
+                case INCLUDE_ERROR  :  dispatcherMapping = REQUEST_ERROR_INCLUDE; break;
+                case INCLUDE_FORWARD : dispatcherMapping = REQUEST_FORWARD_INCLUDE; break;
+                case INCLUDE_ERROR_FORWARD : dispatcherMapping = REQUEST_ERROR_FORWARD_INCLUDE; break;
+            }
+        }  else if (dispatcher.equals("ERROR")) {
+            // apply ERROR to the global dispatcherMapping.
+            switch (dispatcherMapping) {
+                case NOT_SET  :  dispatcherMapping = ERROR; break;
+                case FORWARD  :  dispatcherMapping = FORWARD_ERROR; break;
+                case INCLUDE  :  dispatcherMapping = INCLUDE_ERROR; break;
+                case INCLUDE_FORWARD : dispatcherMapping = INCLUDE_ERROR_FORWARD; break;
+                case REQUEST : dispatcherMapping = REQUEST_ERROR; break;
+                case REQUEST_INCLUDE : dispatcherMapping = REQUEST_ERROR_INCLUDE; break;
+                case REQUEST_FORWARD : dispatcherMapping = REQUEST_ERROR_FORWARD; break;
+                case REQUEST_FORWARD_INCLUDE : dispatcherMapping = REQUEST_ERROR_FORWARD_INCLUDE; break;
+            }
+        }
+    }
+    
+    public int getDispatcherMapping() {
+        // per the SRV.6.2.5 absence of any dispatcher elements is
+        // equivelant to a REQUEST value
+        if (dispatcherMapping == NOT_SET) return REQUEST;
+        else return dispatcherMapping; 
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Render a String representation of this object.
+     */
+    public String toString() {
+
+        StringBuffer sb = new StringBuffer("FilterMap[");
+        sb.append("filterName=");
+        sb.append(this.filterName);
+        if (servletName != null) {
+            sb.append(", servletName=");
+            sb.append(servletName);
+        }
+        if (urlPattern != null) {
+            sb.append(", urlPattern=");
+            sb.append(urlPattern);
+        }
+        sb.append("]");
+        return (sb.toString());
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/deploy/LoginConfig.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/deploy/LoginConfig.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/deploy/LoginConfig.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,166 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.deploy;
+
+
+import org.apache.catalina.util.RequestUtil;
+import java.io.Serializable;
+
+
+/**
+ * Representation of a login configuration element for a web application,
+ * as represented in a <code>&lt;login-config&gt;</code> element in the
+ * deployment descriptor.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302879 $ $Date: 2004-05-13 15:40:49 -0500 (Thu, 13 May 2004) $
+ */
+
+public class LoginConfig implements Serializable {
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Construct a new LoginConfig with default properties.
+     */
+    public LoginConfig() {
+
+        super();
+
+    }
+
+
+    /**
+     * Construct a new LoginConfig with the specified properties.
+     *
+     * @param authMethod The authentication method
+     * @param realmName The realm name
+     * @param loginPage The login page URI
+     * @param errorPage The error page URI
+     */
+    public LoginConfig(String authMethod, String realmName,
+                       String loginPage, String errorPage) {
+
+        super();
+        setAuthMethod(authMethod);
+        setRealmName(realmName);
+        setLoginPage(loginPage);
+        setErrorPage(errorPage);
+
+    }
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * The authentication method to use for application login.  Must be
+     * BASIC, DIGEST, FORM, or CLIENT-CERT.
+     */
+    private String authMethod = null;
+
+    public String getAuthMethod() {
+        return (this.authMethod);
+    }
+
+    public void setAuthMethod(String authMethod) {
+        this.authMethod = authMethod;
+    }
+
+
+    /**
+     * The context-relative URI of the error page for form login.
+     */
+    private String errorPage = null;
+
+    public String getErrorPage() {
+        return (this.errorPage);
+    }
+
+    public void setErrorPage(String errorPage) {
+        //        if ((errorPage == null) || !errorPage.startsWith("/"))
+        //            throw new IllegalArgumentException
+        //                ("Error Page resource path must start with a '/'");
+        this.errorPage = RequestUtil.URLDecode(errorPage);
+    }
+
+
+    /**
+     * The context-relative URI of the login page for form login.
+     */
+    private String loginPage = null;
+
+    public String getLoginPage() {
+        return (this.loginPage);
+    }
+
+    public void setLoginPage(String loginPage) {
+        //        if ((loginPage == null) || !loginPage.startsWith("/"))
+        //            throw new IllegalArgumentException
+        //                ("Login Page resource path must start with a '/'");
+        this.loginPage = RequestUtil.URLDecode(loginPage);
+    }
+
+
+    /**
+     * The realm name used when challenging the user for authentication
+     * credentials.
+     */
+    private String realmName = null;
+
+    public String getRealmName() {
+        return (this.realmName);
+    }
+
+    public void setRealmName(String realmName) {
+        this.realmName = realmName;
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Return a String representation of this object.
+     */
+    public String toString() {
+
+        StringBuffer sb = new StringBuffer("LoginConfig[");
+        sb.append("authMethod=");
+        sb.append(authMethod);
+        if (realmName != null) {
+            sb.append(", realmName=");
+            sb.append(realmName);
+        }
+        if (loginPage != null) {
+            sb.append(", loginPage=");
+            sb.append(loginPage);
+        }
+        if (errorPage != null) {
+            sb.append(", errorPage=");
+            sb.append(errorPage);
+        }
+        sb.append("]");
+        return (sb.toString());
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/deploy/MessageDestination.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/deploy/MessageDestination.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/deploy/MessageDestination.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,140 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.deploy;
+
+
+/**
+ * <p>Representation of a message destination for a web application, as
+ * represented in a <code>&lt;message-destination&gt;</code> element
+ * in the deployment descriptor.</p>
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302879 $ $Date: 2004-05-13 15:40:49 -0500 (Thu, 13 May 2004) $
+ * @since Tomcat 5.0
+ */
+
+public class MessageDestination {
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * The description of this destination.
+     */
+    private String description = null;
+
+    public String getDescription() {
+        return (this.description);
+    }
+
+    public void setDescription(String description) {
+        this.description = description;
+    }
+
+
+    /**
+     * The display name of this destination.
+     */
+    private String displayName = null;
+
+    public String getDisplayName() {
+        return (this.displayName);
+    }
+
+    public void setDisplayName(String displayName) {
+        this.displayName = displayName;
+    }
+
+
+    /**
+     * The large icon of this destination.
+     */
+    private String largeIcon = null;
+
+    public String getLargeIcon() {
+        return (this.largeIcon);
+    }
+
+    public void setLargeIcon(String largeIcon) {
+        this.largeIcon = largeIcon;
+    }
+
+
+    /**
+     * The name of this destination.
+     */
+    private String name = null;
+
+    public String getName() {
+        return (this.name);
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+
+    /**
+     * The small icon of this destination.
+     */
+    private String smallIcon = null;
+
+    public String getSmallIcon() {
+        return (this.smallIcon);
+    }
+
+    public void setSmallIcon(String smallIcon) {
+        this.smallIcon = smallIcon;
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Return a String representation of this object.
+     */
+    public String toString() {
+
+        StringBuffer sb = new StringBuffer("MessageDestination[");
+        sb.append("name=");
+        sb.append(name);
+        if (displayName != null) {
+            sb.append(", displayName=");
+            sb.append(displayName);
+        }
+        if (largeIcon != null) {
+            sb.append(", largeIcon=");
+            sb.append(largeIcon);
+        }
+        if (smallIcon != null) {
+            sb.append(", smallIcon=");
+            sb.append(smallIcon);
+        }
+        if (description != null) {
+            sb.append(", description=");
+            sb.append(description);
+        }
+        sb.append("]");
+        return (sb.toString());
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/deploy/MessageDestinationRef.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/deploy/MessageDestinationRef.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/deploy/MessageDestinationRef.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,159 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.deploy;
+
+import java.io.Serializable;
+
+
+/**
+ * <p>Representation of a message destination reference for a web application,
+ * as represented in a <code>&lt;message-destination-ref&gt;</code> element
+ * in the deployment descriptor.</p>
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302879 $ $Date: 2004-05-13 15:40:49 -0500 (Thu, 13 May 2004) $
+ * @since Tomcat 5.0
+ */
+
+public class MessageDestinationRef implements Serializable {
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * The description of this destination ref.
+     */
+    private String description = null;
+
+    public String getDescription() {
+        return (this.description);
+    }
+
+    public void setDescription(String description) {
+        this.description = description;
+    }
+
+
+    /**
+     * The link of this destination ref.
+     */
+    private String link = null;
+
+    public String getLink() {
+        return (this.link);
+    }
+
+    public void setLink(String link) {
+        this.link = link;
+    }
+
+
+    /**
+     * The name of this destination ref.
+     */
+    private String name = null;
+
+    public String getName() {
+        return (this.name);
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+
+    /**
+     * The type of this destination ref.
+     */
+    private String type = null;
+
+    public String getType() {
+        return (this.type);
+    }
+
+    public void setType(String type) {
+        this.type = type;
+    }
+
+
+    /**
+     * The usage of this destination ref.
+     */
+    private String usage = null;
+
+    public String getUsage() {
+        return (this.usage);
+    }
+
+    public void setUsage(String usage) {
+        this.usage = usage;
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Return a String representation of this object.
+     */
+    public String toString() {
+
+        StringBuffer sb = new StringBuffer("MessageDestination[");
+        sb.append("name=");
+        sb.append(name);
+        if (link != null) {
+            sb.append(", link=");
+            sb.append(link);
+        }
+        if (type != null) {
+            sb.append(", type=");
+            sb.append(type);
+        }
+        if (usage != null) {
+            sb.append(", usage=");
+            sb.append(usage);
+        }
+        if (description != null) {
+            sb.append(", description=");
+            sb.append(description);
+        }
+        sb.append("]");
+        return (sb.toString());
+
+    }
+
+
+    // -------------------------------------------------------- Package Methods
+
+
+    /**
+     * The NamingResources with which we are associated (if any).
+     */
+    protected NamingResources resources = null;
+
+    public NamingResources getNamingResources() {
+        return (this.resources);
+    }
+
+    void setNamingResources(NamingResources resources) {
+        this.resources = resources;
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/deploy/NamingResources.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/deploy/NamingResources.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/deploy/NamingResources.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,705 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.deploy;
+
+
+import java.beans.PropertyChangeListener;
+import java.beans.PropertyChangeSupport;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.io.Serializable;
+
+
+/**
+ * Holds and manages the naming resources defined in the J2EE Enterprise 
+ * Naming Context and their associated JNDI context.
+ *
+ * @author Remy Maucherat
+ * @version $Revision: 303133 $ $Date: 2004-08-29 11:46:15 -0500 (Sun, 29 Aug 2004) $
+ */
+
+public class NamingResources implements Serializable {
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Create a new NamingResources instance.
+     */
+    public NamingResources() {
+    }
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * Associated container object.
+     */
+    private Object container = null;
+
+
+    /**
+     * List of naming entries, keyed by name. The value is the entry type, as
+     * declared by the user.
+     */
+    private Hashtable entries = new Hashtable();
+
+
+    /**
+     * The EJB resource references for this web application, keyed by name.
+     */
+    private HashMap ejbs = new HashMap();
+
+
+    /**
+     * The environment entries for this web application, keyed by name.
+     */
+    private HashMap envs = new HashMap();
+
+
+    /**
+     * The local  EJB resource references for this web application, keyed by
+     * name.
+     */
+    private HashMap localEjbs = new HashMap();
+
+
+    /**
+     * The message destination referencess for this web application,
+     * keyed by name.
+     */
+    private HashMap mdrs = new HashMap();
+
+
+    /**
+     * The resource environment references for this web application,
+     * keyed by name.
+     */
+    private HashMap resourceEnvRefs = new HashMap();
+
+
+    /**
+     * The resource references for this web application, keyed by name.
+     */
+    private HashMap resources = new HashMap();
+
+
+    /**
+     * The resource links for this web application, keyed by name.
+     */
+    private HashMap resourceLinks = new HashMap();
+
+
+    /**
+     * The transaction for this webapp.
+     */
+    private ContextTransaction transaction = null;
+    
+
+    /**
+     * The property change support for this component.
+     */
+    protected PropertyChangeSupport support = new PropertyChangeSupport(this);
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * Get the container with which the naming resources are associated.
+     */
+    public Object getContainer() {
+        return container;
+    }
+
+
+    /**
+     * Set the container with which the naming resources are associated.
+     */
+    public void setContainer(Object container) {
+        this.container = container;
+    }
+
+    
+    /**
+     * Set the transaction object.
+     */
+    public void setTransaction(ContextTransaction transaction) {
+        this.transaction = transaction;
+    }
+    
+
+    /**
+     * Get the transaction object.
+     */
+    public ContextTransaction getTransaction() {
+        return transaction;
+    }
+    
+
+    /**
+     * Add an EJB resource reference for this web application.
+     *
+     * @param ejb New EJB resource reference
+     */
+    public void addEjb(ContextEjb ejb) {
+
+        if (entries.containsKey(ejb.getName())) {
+            return;
+        } else {
+            entries.put(ejb.getName(), ejb.getType());
+        }
+
+        synchronized (ejbs) {
+            ejb.setNamingResources(this);
+            ejbs.put(ejb.getName(), ejb);
+        }
+        support.firePropertyChange("ejb", null, ejb);
+
+    }
+
+
+    /**
+     * Add an environment entry for this web application.
+     *
+     * @param environment New environment entry
+     */
+    public void addEnvironment(ContextEnvironment environment) {
+
+        if (entries.containsKey(environment.getName())) {
+            return;
+        } else {
+            entries.put(environment.getName(), environment.getType());
+        }
+
+        synchronized (envs) {
+            environment.setNamingResources(this);
+            envs.put(environment.getName(), environment);
+        }
+        support.firePropertyChange("environment", null, environment);
+
+    }
+
+
+    /**
+     * Add a local EJB resource reference for this web application.
+     *
+     * @param ejb New EJB resource reference
+     */
+    public void addLocalEjb(ContextLocalEjb ejb) {
+
+        if (entries.containsKey(ejb.getName())) {
+            return;
+        } else {
+            entries.put(ejb.getName(), ejb.getType());
+        }
+
+        synchronized (localEjbs) {
+            ejb.setNamingResources(this);
+            localEjbs.put(ejb.getName(), ejb);
+        }
+        support.firePropertyChange("localEjb", null, ejb);
+
+    }
+
+
+    /**
+     * Add a message destination reference for this web application.
+     *
+     * @param mdr New message destination reference
+     */
+    public void addMessageDestinationRef(MessageDestinationRef mdr) {
+
+        if (entries.containsKey(mdr.getName())) {
+            return;
+        } else {
+            entries.put(mdr.getName(), mdr.getType());
+        }
+
+        synchronized (mdrs) {
+            mdr.setNamingResources(this);
+            mdrs.put(mdr.getName(), mdr);
+        }
+        support.firePropertyChange("messageDestinationRef", null, mdr);
+
+    }
+
+
+    /**
+     * Add a property change listener to this component.
+     *
+     * @param listener The listener to add
+     */
+    public void addPropertyChangeListener(PropertyChangeListener listener) {
+
+        support.addPropertyChangeListener(listener);
+
+    }
+
+
+    /**
+     * Add a resource reference for this web application.
+     *
+     * @param resource New resource reference
+     */
+    public void addResource(ContextResource resource) {
+
+        if (entries.containsKey(resource.getName())) {
+            return;
+        } else {
+            entries.put(resource.getName(), resource.getType());
+        }
+
+        synchronized (resources) {
+            resource.setNamingResources(this);
+            resources.put(resource.getName(), resource);
+        }
+        support.firePropertyChange("resource", null, resource);
+
+    }
+
+
+    /**
+     * Add a resource environment reference for this web application.
+     *
+     * @param resource The resource
+     */
+    public void addResourceEnvRef(ContextResourceEnvRef resource) {
+
+        if (entries.containsKey(resource.getName())) {
+            return;
+        } else {
+            entries.put(resource.getName(), resource.getType());
+        }
+
+        synchronized (localEjbs) {
+            resource.setNamingResources(this);
+            resourceEnvRefs.put(resource.getName(), resource);
+        }
+        support.firePropertyChange("resourceEnvRef", null, resource);
+
+    }
+
+
+    /**
+     * Add a resource link for this web application.
+     *
+     * @param resourceLink New resource link
+     */
+    public void addResourceLink(ContextResourceLink resourceLink) {
+
+        if (entries.containsKey(resourceLink.getName())) {
+            return;
+        } else {
+            Object value = resourceLink.getType();
+            if (value == null) {
+                value = "";
+            }
+            entries.put(resourceLink.getName(), value);
+        }
+
+        synchronized (resourceLinks) {
+            resourceLink.setNamingResources(this);
+            resourceLinks.put(resourceLink.getName(), resourceLink);
+        }
+        support.firePropertyChange("resourceLink", null, resourceLink);
+
+    }
+
+
+    /**
+     * Return the EJB resource reference with the specified name, if any;
+     * otherwise, return <code>null</code>.
+     *
+     * @param name Name of the desired EJB resource reference
+     */
+    public ContextEjb findEjb(String name) {
+
+        synchronized (ejbs) {
+            return ((ContextEjb) ejbs.get(name));
+        }
+
+    }
+
+
+    /**
+     * Return the defined EJB resource references for this application.
+     * If there are none, a zero-length array is returned.
+     */
+    public ContextEjb[] findEjbs() {
+
+        synchronized (ejbs) {
+            ContextEjb results[] = new ContextEjb[ejbs.size()];
+            return ((ContextEjb[]) ejbs.values().toArray(results));
+        }
+
+    }
+
+
+    /**
+     * Return the environment entry with the specified name, if any;
+     * otherwise, return <code>null</code>.
+     *
+     * @param name Name of the desired environment entry
+     */
+    public ContextEnvironment findEnvironment(String name) {
+
+        synchronized (envs) {
+            return ((ContextEnvironment) envs.get(name));
+        }
+
+    }
+
+
+    /**
+     * Return the set of defined environment entries for this web
+     * application.  If none have been defined, a zero-length array
+     * is returned.
+     */
+    public ContextEnvironment[] findEnvironments() {
+
+        synchronized (envs) {
+            ContextEnvironment results[] = new ContextEnvironment[envs.size()];
+            return ((ContextEnvironment[]) envs.values().toArray(results));
+        }
+
+    }
+
+
+    /**
+     * Return the local EJB resource reference with the specified name, if any;
+     * otherwise, return <code>null</code>.
+     *
+     * @param name Name of the desired EJB resource reference
+     */
+    public ContextLocalEjb findLocalEjb(String name) {
+
+        synchronized (localEjbs) {
+            return ((ContextLocalEjb) localEjbs.get(name));
+        }
+
+    }
+
+
+    /**
+     * Return the defined local EJB resource references for this application.
+     * If there are none, a zero-length array is returned.
+     */
+    public ContextLocalEjb[] findLocalEjbs() {
+
+        synchronized (localEjbs) {
+            ContextLocalEjb results[] = new ContextLocalEjb[localEjbs.size()];
+            return ((ContextLocalEjb[]) localEjbs.values().toArray(results));
+        }
+
+    }
+
+
+    /**
+     * Return the message destination reference with the specified name,
+     * if any; otherwise, return <code>null</code>.
+     *
+     * @param name Name of the desired message destination reference
+     */
+    public MessageDestinationRef findMessageDestinationRef(String name) {
+
+        synchronized (mdrs) {
+            return ((MessageDestinationRef) mdrs.get(name));
+        }
+
+    }
+
+
+    /**
+     * Return the defined message destination references for this application.
+     * If there are none, a zero-length array is returned.
+     */
+    public MessageDestinationRef[] findMessageDestinationRefs() {
+
+        synchronized (mdrs) {
+            MessageDestinationRef results[] =
+                new MessageDestinationRef[mdrs.size()];
+            return ((MessageDestinationRef[]) mdrs.values().toArray(results));
+        }
+
+    }
+
+
+    /**
+     * Return the resource reference with the specified name, if any;
+     * otherwise return <code>null</code>.
+     *
+     * @param name Name of the desired resource reference
+     */
+    public ContextResource findResource(String name) {
+
+        synchronized (resources) {
+            return ((ContextResource) resources.get(name));
+        }
+
+    }
+
+
+    /**
+     * Return the resource link with the specified name, if any;
+     * otherwise return <code>null</code>.
+     *
+     * @param name Name of the desired resource link
+     */
+    public ContextResourceLink findResourceLink(String name) {
+
+        synchronized (resourceLinks) {
+            return ((ContextResourceLink) resourceLinks.get(name));
+        }
+
+    }
+
+
+    /**
+     * Return the defined resource links for this application.  If
+     * none have been defined, a zero-length array is returned.
+     */
+    public ContextResourceLink[] findResourceLinks() {
+
+        synchronized (resourceLinks) {
+            ContextResourceLink results[] = 
+                new ContextResourceLink[resourceLinks.size()];
+            return ((ContextResourceLink[]) resourceLinks.values()
+                    .toArray(results));
+        }
+
+    }
+
+
+    /**
+     * Return the defined resource references for this application.  If
+     * none have been defined, a zero-length array is returned.
+     */
+    public ContextResource[] findResources() {
+
+        synchronized (resources) {
+            ContextResource results[] = new ContextResource[resources.size()];
+            return ((ContextResource[]) resources.values().toArray(results));
+        }
+
+    }
+
+
+    /**
+     * Return the resource environment reference type for the specified
+     * name, if any; otherwise return <code>null</code>.
+     *
+     * @param name Name of the desired resource environment reference
+     */
+    public ContextResourceEnvRef findResourceEnvRef(String name) {
+
+        synchronized (resourceEnvRefs) {
+            return ((ContextResourceEnvRef) resourceEnvRefs.get(name));
+        }
+
+    }
+
+
+    /**
+     * Return the set of resource environment reference names for this
+     * web application.  If none have been specified, a zero-length
+     * array is returned.
+     */
+    public ContextResourceEnvRef[] findResourceEnvRefs() {
+
+        synchronized (resourceEnvRefs) {
+            ContextResourceEnvRef results[] = new ContextResourceEnvRef[resourceEnvRefs.size()];
+            return ((ContextResourceEnvRef[]) resourceEnvRefs.values().toArray(results));
+        }
+
+    }
+
+
+    /**
+     * Return true if the name specified already exists.
+     */
+    public boolean exists(String name) {
+
+        return (entries.containsKey(name));
+
+    }
+
+
+    /**
+     * Remove any EJB resource reference with the specified name.
+     *
+     * @param name Name of the EJB resource reference to remove
+     */
+    public void removeEjb(String name) {
+
+        entries.remove(name);
+
+        ContextEjb ejb = null;
+        synchronized (ejbs) {
+            ejb = (ContextEjb) ejbs.remove(name);
+        }
+        if (ejb != null) {
+            support.firePropertyChange("ejb", ejb, null);
+            ejb.setNamingResources(null);
+        }
+
+    }
+
+
+    /**
+     * Remove any environment entry with the specified name.
+     *
+     * @param name Name of the environment entry to remove
+     */
+    public void removeEnvironment(String name) {
+
+        entries.remove(name);
+
+        ContextEnvironment environment = null;
+        synchronized (envs) {
+            environment = (ContextEnvironment) envs.remove(name);
+        }
+        if (environment != null) {
+            support.firePropertyChange("environment", environment, null);
+            environment.setNamingResources(null);
+        }
+
+    }
+
+
+    /**
+     * Remove any local EJB resource reference with the specified name.
+     *
+     * @param name Name of the EJB resource reference to remove
+     */
+    public void removeLocalEjb(String name) {
+
+        entries.remove(name);
+
+        ContextLocalEjb localEjb = null;
+        synchronized (localEjbs) {
+            localEjb = (ContextLocalEjb) ejbs.remove(name);
+        }
+        if (localEjb != null) {
+            support.firePropertyChange("localEjb", localEjb, null);
+            localEjb.setNamingResources(null);
+        }
+
+    }
+
+
+    /**
+     * Remove any message destination reference with the specified name.
+     *
+     * @param name Name of the message destination resource reference to remove
+     */
+    public void removeMessageDestinationRef(String name) {
+
+        entries.remove(name);
+
+        MessageDestinationRef mdr = null;
+        synchronized (mdrs) {
+            mdr = (MessageDestinationRef) mdrs.remove(name);
+        }
+        if (mdr != null) {
+            support.firePropertyChange("messageDestinationRef",
+                                       mdr, null);
+            mdr.setNamingResources(null);
+        }
+
+    }
+
+
+    /**
+     * Remove a property change listener from this component.
+     *
+     * @param listener The listener to remove
+     */
+    public void removePropertyChangeListener(PropertyChangeListener listener) {
+
+        support.removePropertyChangeListener(listener);
+
+    }
+
+
+    /**
+     * Remove any resource reference with the specified name.
+     *
+     * @param name Name of the resource reference to remove
+     */
+    public void removeResource(String name) {
+
+        entries.remove(name);
+
+        ContextResource resource = null;
+        synchronized (resources) {
+            resource = (ContextResource) resources.remove(name);
+        }
+        if (resource != null) {
+            support.firePropertyChange("resource", resource, null);
+            resource.setNamingResources(null);
+        }
+
+    }
+
+
+    /**
+     * Remove any resource environment reference with the specified name.
+     *
+     * @param name Name of the resource environment reference to remove
+     */
+    public void removeResourceEnvRef(String name) {
+
+        entries.remove(name);
+
+        String type = null;
+        synchronized (resourceEnvRefs) {
+            type = (String) resourceEnvRefs.remove(name);
+        }
+        if (type != null) {
+            support.firePropertyChange("resourceEnvRef",
+                                       name + ":" + type, null);
+        }
+
+    }
+
+
+    /**
+     * Remove any resource link with the specified name.
+     *
+     * @param name Name of the resource link to remove
+     */
+    public void removeResourceLink(String name) {
+
+        entries.remove(name);
+
+        ContextResourceLink resourceLink = null;
+        synchronized (resourceLinks) {
+            resourceLink = (ContextResourceLink) resourceLinks.remove(name);
+        }
+        if (resourceLink != null) {
+            support.firePropertyChange("resourceLink", resourceLink, null);
+            resourceLink.setNamingResources(null);
+        }
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/deploy/ResourceBase.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/deploy/ResourceBase.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/deploy/ResourceBase.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,132 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.deploy;
+
+import java.io.Serializable;
+import java.util.Iterator;
+import java.util.HashMap;
+
+
+/**
+ * Representation of an Context element
+ *
+ * @author Peter Rossbach (pero at apache.org)
+ * @version $Revision: 303342 $ $Date: 2004-10-05 02:56:49 -0500 (Tue, 05 Oct 2004) $
+ */
+
+public class ResourceBase implements Serializable {
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * The description of this Context Element.
+     */
+    private String description = null;
+
+    public String getDescription() {
+        return (this.description);
+    }
+
+    public void setDescription(String description) {
+        this.description = description;
+    }
+
+
+
+    /**
+     * The name of this context Element.
+     */
+    private String name = null;
+
+    public String getName() {
+        return (this.name);
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+
+    /**
+     * The name of the EJB bean implementation class.
+     */
+    private String type = null;
+
+    public String getType() {
+        return (this.type);
+    }
+
+    public void setType(String type) {
+        this.type = type;
+    }
+
+
+    /**
+     * Holder for our configured properties.
+     */
+    private HashMap properties = new HashMap();
+
+    /**
+     * Return a configured property.
+     */
+    public Object getProperty(String name) {
+        return properties.get(name);
+    }
+
+    /**
+     * Set a configured property.
+     */
+    public void setProperty(String name, Object value) {
+        properties.put(name, value);
+    }
+
+    /** 
+     * remove a configured property.
+     */
+    public void removeProperty(String name) {
+        properties.remove(name);
+    }
+
+    /**
+     * List properties.
+     */
+    public Iterator listProperties() {
+        return properties.keySet().iterator();
+    }
+    
+    
+    // -------------------------------------------------------- Package Methods
+
+
+    /**
+     * The NamingResources with which we are associated (if any).
+     */
+    protected NamingResources resources = null;
+
+    public NamingResources getNamingResources() {
+        return (this.resources);
+    }
+
+    void setNamingResources(NamingResources resources) {
+        this.resources = resources;
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/deploy/SecurityCollection.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/deploy/SecurityCollection.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/deploy/SecurityCollection.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,348 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.deploy;
+
+
+import org.apache.catalina.util.RequestUtil;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import java.io.Serializable;
+
+
+/**
+ * Representation of a web resource collection for a web application's security
+ * constraint, as represented in a <code>&lt;web-resource-collection&gt;</code>
+ * element in the deployment descriptor.
+ * <p>
+ * <b>WARNING</b>:  It is assumed that instances of this class will be created
+ * and modified only within the context of a single thread, before the instance
+ * is made visible to the remainder of the application.  After that, only read
+ * access is expected.  Therefore, none of the read and write access within
+ * this class is synchronized.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 304007 $ $Date: 2005-07-21 15:14:57 -0500 (Thu, 21 Jul 2005) $
+ */
+
+public class SecurityCollection implements Serializable {
+
+    private static Log log = LogFactory.getLog(SecurityCollection.class);
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Construct a new security collection instance with default values.
+     */
+    public SecurityCollection() {
+
+        this(null, null);
+
+    }
+
+
+    /**
+     * Construct a new security collection instance with specified values.
+     *
+     * @param name Name of this security collection
+     */
+    public SecurityCollection(String name) {
+
+        this(name, null);
+
+    }
+
+
+    /**
+     * Construct a new security collection instance with specified values.
+     *
+     * @param name Name of this security collection
+     * @param description Description of this security collection
+     */
+    public SecurityCollection(String name, String description) {
+
+        super();
+        setName(name);
+        setDescription(description);
+
+    }
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * Description of this web resource collection.
+     */
+    private String description = null;
+
+
+    /**
+     * The HTTP methods covered by this web resource collection.
+     */
+    private String methods[] = new String[0];
+
+
+    /**
+     * The name of this web resource collection.
+     */
+    private String name = null;
+
+
+    /**
+     * The URL patterns protected by this security collection.
+     */
+    private String patterns[] = new String[0];
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * Return the description of this web resource collection.
+     */
+    public String getDescription() {
+
+        return (this.description);
+
+    }
+
+
+    /**
+     * Set the description of this web resource collection.
+     *
+     * @param description The new description
+     */
+    public void setDescription(String description) {
+
+        this.description = description;
+
+    }
+
+
+    /**
+     * Return the name of this web resource collection.
+     */
+    public String getName() {
+
+        return (this.name);
+
+    }
+
+
+    /**
+     * Set the name of this web resource collection
+     *
+     * @param name The new name
+     */
+    public void setName(String name) {
+
+        this.name = name;
+
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Add an HTTP request method to be part of this web resource collection.
+     */
+    public void addMethod(String method) {
+
+        if (method == null)
+            return;
+        String results[] = new String[methods.length + 1];
+        for (int i = 0; i < methods.length; i++)
+            results[i] = methods[i];
+        results[methods.length] = method;
+        methods = results;
+
+    }
+
+
+    /**
+     * Add a URL pattern to be part of this web resource collection.
+     */
+    public void addPattern(String pattern) {
+
+        if (pattern == null)
+            return;
+
+        // Bugzilla 34805: add friendly warning.
+        if(pattern.endsWith("*")) {
+          if (pattern.charAt(pattern.length()-1) != '/') {
+            if (log.isDebugEnabled()) {
+              log.warn("Suspicious url pattern: \"" + pattern + "\"" +
+                       " - see http://java.sun.com/aboutJava/communityprocess/first/jsr053/servlet23_PFD.pdf" +
+                       "  section 11.2" );
+            }
+          }
+        }
+
+        pattern = RequestUtil.URLDecode(pattern);
+        String results[] = new String[patterns.length + 1];
+        for (int i = 0; i < patterns.length; i++) {
+            results[i] = patterns[i];
+        }
+        results[patterns.length] = pattern;
+        patterns = results;
+
+    }
+
+
+    /**
+     * Return <code>true</code> if the specified HTTP request method is
+     * part of this web resource collection.
+     *
+     * @param method Request method to check
+     */
+    public boolean findMethod(String method) {
+
+        if (methods.length == 0)
+            return (true);
+        for (int i = 0; i < methods.length; i++) {
+            if (methods[i].equals(method))
+                return (true);
+        }
+        return (false);
+
+    }
+
+
+    /**
+     * Return the set of HTTP request methods that are part of this web
+     * resource collection, or a zero-length array if all request methods
+     * are included.
+     */
+    public String[] findMethods() {
+
+        return (methods);
+
+    }
+
+
+    /**
+     * Is the specified pattern part of this web resource collection?
+     *
+     * @param pattern Pattern to be compared
+     */
+    public boolean findPattern(String pattern) {
+
+        for (int i = 0; i < patterns.length; i++) {
+            if (patterns[i].equals(pattern))
+                return (true);
+        }
+        return (false);
+
+    }
+
+
+    /**
+     * Return the set of URL patterns that are part of this web resource
+     * collection.  If none have been specified, a zero-length array is
+     * returned.
+     */
+    public String[] findPatterns() {
+
+        return (patterns);
+
+    }
+
+
+    /**
+     * Remove the specified HTTP request method from those that are part
+     * of this web resource collection.
+     *
+     * @param method Request method to be removed
+     */
+    public void removeMethod(String method) {
+
+        if (method == null)
+            return;
+        int n = -1;
+        for (int i = 0; i < methods.length; i++) {
+            if (methods[i].equals(method)) {
+                n = i;
+                break;
+            }
+        }
+        if (n >= 0) {
+            int j = 0;
+            String results[] = new String[methods.length - 1];
+            for (int i = 0; i < methods.length; i++) {
+                if (i != n)
+                    results[j++] = methods[i];
+            }
+            methods = results;
+        }
+
+    }
+
+
+    /**
+     * Remove the specified URL pattern from those that are part of this
+     * web resource collection.
+     *
+     * @param pattern Pattern to be removed
+     */
+    public void removePattern(String pattern) {
+
+        if (pattern == null)
+            return;
+        int n = -1;
+        for (int i = 0; i < patterns.length; i++) {
+            if (patterns[i].equals(pattern)) {
+                n = i;
+                break;
+            }
+        }
+        if (n >= 0) {
+            int j = 0;
+            String results[] = new String[patterns.length - 1];
+            for (int i = 0; i < patterns.length; i++) {
+                if (i != n)
+                    results[j++] = patterns[i];
+            }
+            patterns = results;
+        }
+
+    }
+
+
+    /**
+     * Return a String representation of this security collection.
+     */
+    public String toString() {
+
+        StringBuffer sb = new StringBuffer("SecurityCollection[");
+        sb.append(name);
+        if (description != null) {
+            sb.append(", ");
+            sb.append(description);
+        }
+        sb.append("]");
+        return (sb.toString());
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/deploy/SecurityConstraint.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/deploy/SecurityConstraint.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/deploy/SecurityConstraint.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,459 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.deploy;
+
+import java.io.Serializable;
+
+
+/**
+ * Representation of a security constraint element for a web application,
+ * as represented in a <code>&lt;security-constraint&gt;</code> element in the
+ * deployment descriptor.
+ * <p>
+ * <b>WARNING</b>:  It is assumed that instances of this class will be created
+ * and modified only within the context of a single thread, before the instance
+ * is made visible to the remainder of the application.  After that, only read
+ * access is expected.  Therefore, none of the read and write access within
+ * this class is synchronized.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302879 $ $Date: 2004-05-13 15:40:49 -0500 (Thu, 13 May 2004) $
+ */
+
+public class SecurityConstraint implements Serializable {
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Construct a new security constraint instance with default values.
+     */
+    public SecurityConstraint() {
+
+        super();
+
+    }
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * Was the "all roles" wildcard included in the authorization constraints
+     * for this security constraint?
+     */
+    private boolean allRoles = false;
+
+
+    /**
+     * Was an authorization constraint included in this security constraint?
+     * This is necessary to distinguish the case where an auth-constraint with
+     * no roles (signifying no direct access at all) was requested, versus
+     * a lack of auth-constraint which implies no access control checking.
+     */
+    private boolean authConstraint = false;
+
+
+    /**
+     * The set of roles permitted to access resources protected by this
+     * security constraint.
+     */
+    private String authRoles[] = new String[0];
+
+
+    /**
+     * The set of web resource collections protected by this security
+     * constraint.
+     */
+    private SecurityCollection collections[] = new SecurityCollection[0];
+
+
+    /**
+     * The display name of this security constraint.
+     */
+    private String displayName = null;
+
+
+    /**
+     * The user data constraint for this security constraint.  Must be NONE,
+     * INTEGRAL, or CONFIDENTIAL.
+     */
+    private String userConstraint = "NONE";
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * Was the "all roles" wildcard included in this authentication
+     * constraint?
+     */
+    public boolean getAllRoles() {
+
+        return (this.allRoles);
+
+    }
+
+
+    /**
+     * Return the authorization constraint present flag for this security
+     * constraint.
+     */
+    public boolean getAuthConstraint() {
+
+        return (this.authConstraint);
+
+    }
+
+
+    /**
+     * Set the authorization constraint present flag for this security
+     * constraint.
+     */
+    public void setAuthConstraint(boolean authConstraint) {
+
+        this.authConstraint = authConstraint;
+
+    }
+
+
+    /**
+     * Return the display name of this security constraint.
+     */
+    public String getDisplayName() {
+
+        return (this.displayName);
+
+    }
+
+
+    /**
+     * Set the display name of this security constraint.
+     */
+    public void setDisplayName(String displayName) {
+
+        this.displayName = displayName;
+
+    }
+
+
+    /**
+     * Return the user data constraint for this security constraint.
+     */
+    public String getUserConstraint() {
+
+        return (userConstraint);
+
+    }
+
+
+    /**
+     * Set the user data constraint for this security constraint.
+     *
+     * @param userConstraint The new user data constraint
+     */
+    public void setUserConstraint(String userConstraint) {
+
+        if (userConstraint != null)
+            this.userConstraint = userConstraint;
+
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Add an authorization role, which is a role name that will be
+     * permitted access to the resources protected by this security constraint.
+     *
+     * @param authRole Role name to be added
+     */
+    public void addAuthRole(String authRole) {
+
+        if (authRole == null)
+            return;
+        if ("*".equals(authRole)) {
+            allRoles = true;
+            return;
+        }
+        String results[] = new String[authRoles.length + 1];
+        for (int i = 0; i < authRoles.length; i++)
+            results[i] = authRoles[i];
+        results[authRoles.length] = authRole;
+        authRoles = results;
+        authConstraint = true;
+
+    }
+
+
+    /**
+     * Add a new web resource collection to those protected by this
+     * security constraint.
+     *
+     * @param collection The new web resource collection
+     */
+    public void addCollection(SecurityCollection collection) {
+
+        if (collection == null)
+            return;
+        SecurityCollection results[] =
+            new SecurityCollection[collections.length + 1];
+        for (int i = 0; i < collections.length; i++)
+            results[i] = collections[i];
+        results[collections.length] = collection;
+        collections = results;
+
+    }
+
+
+    /**
+     * Return <code>true</code> if the specified role is permitted access to
+     * the resources protected by this security constraint.
+     *
+     * @param role Role name to be checked
+     */
+    public boolean findAuthRole(String role) {
+
+        if (role == null)
+            return (false);
+        for (int i = 0; i < authRoles.length; i++) {
+            if (role.equals(authRoles[i]))
+                return (true);
+        }
+        return (false);
+
+    }
+
+
+    /**
+     * Return the set of roles that are permitted access to the resources
+     * protected by this security constraint.  If none have been defined,
+     * a zero-length array is returned (which implies that all authenticated
+     * users are permitted access).
+     */
+    public String[] findAuthRoles() {
+
+        return (authRoles);
+
+    }
+
+
+    /**
+     * Return the web resource collection for the specified name, if any;
+     * otherwise, return <code>null</code>.
+     *
+     * @param name Web resource collection name to return
+     */
+    public SecurityCollection findCollection(String name) {
+
+        if (name == null)
+            return (null);
+        for (int i = 0; i < collections.length; i++) {
+            if (name.equals(collections[i].getName()))
+                return (collections[i]);
+        }
+        return (null);
+
+    }
+
+
+    /**
+     * Return all of the web resource collections protected by this
+     * security constraint.  If there are none, a zero-length array is
+     * returned.
+     */
+    public SecurityCollection[] findCollections() {
+
+        return (collections);
+
+    }
+
+
+    /**
+     * Return <code>true</code> if the specified context-relative URI (and
+     * associated HTTP method) are protected by this security constraint.
+     *
+     * @param uri Context-relative URI to check
+     * @param method Request method being used
+     */
+    public boolean included(String uri, String method) {
+
+        // We cannot match without a valid request method
+        if (method == null)
+            return (false);
+
+        // Check all of the collections included in this constraint
+        for (int i = 0; i < collections.length; i++) {
+            if (!collections[i].findMethod(method))
+                continue;
+            String patterns[] = collections[i].findPatterns();
+            for (int j = 0; j < patterns.length; j++) {
+                if (matchPattern(uri, patterns[j]))
+                    return (true);
+            }
+        }
+
+        // No collection included in this constraint matches this request
+        return (false);
+
+    }
+
+
+    /**
+     * Remove the specified role from the set of roles permitted to access
+     * the resources protected by this security constraint.
+     *
+     * @param authRole Role name to be removed
+     */
+    public void removeAuthRole(String authRole) {
+
+        if (authRole == null)
+            return;
+        int n = -1;
+        for (int i = 0; i < authRoles.length; i++) {
+            if (authRoles[i].equals(authRole)) {
+                n = i;
+                break;
+            }
+        }
+        if (n >= 0) {
+            int j = 0;
+            String results[] = new String[authRoles.length - 1];
+            for (int i = 0; i < authRoles.length; i++) {
+                if (i != n)
+                    results[j++] = authRoles[i];
+            }
+            authRoles = results;
+        }
+
+    }
+
+
+    /**
+     * Remove the specified web resource collection from those protected by
+     * this security constraint.
+     *
+     * @param collection Web resource collection to be removed
+     */
+    public void removeCollection(SecurityCollection collection) {
+
+        if (collection == null)
+            return;
+        int n = -1;
+        for (int i = 0; i < collections.length; i++) {
+            if (collections[i].equals(collection)) {
+                n = i;
+                break;
+            }
+        }
+        if (n >= 0) {
+            int j = 0;
+            SecurityCollection results[] =
+                new SecurityCollection[collections.length - 1];
+            for (int i = 0; i < collections.length; i++) {
+                if (i != n)
+                    results[j++] = collections[i];
+            }
+            collections = results;
+        }
+
+    }
+
+
+    /**
+     * Return a String representation of this security constraint.
+     */
+    public String toString() {
+
+        StringBuffer sb = new StringBuffer("SecurityConstraint[");
+        for (int i = 0; i < collections.length; i++) {
+            if (i > 0)
+                sb.append(", ");
+            sb.append(collections[i].getName());
+        }
+        sb.append("]");
+        return (sb.toString());
+
+    }
+
+
+    // -------------------------------------------------------- Private Methods
+
+
+    /**
+     * Does the specified request path match the specified URL pattern?
+     * This method follows the same rules (in the same order) as those used
+     * for mapping requests to servlets.
+     *
+     * @param path Context-relative request path to be checked
+     *  (must start with '/')
+     * @param pattern URL pattern to be compared against
+     */
+    private boolean matchPattern(String path, String pattern) {
+
+        // Normalize the argument strings
+        if ((path == null) || (path.length() == 0))
+            path = "/";
+        if ((pattern == null) || (pattern.length() == 0))
+            pattern = "/";
+
+        // Check for exact match
+        if (path.equals(pattern))
+            return (true);
+
+        // Check for path prefix matching
+        if (pattern.startsWith("/") && pattern.endsWith("/*")) {
+            pattern = pattern.substring(0, pattern.length() - 2);
+            if (pattern.length() == 0)
+                return (true);  // "/*" is the same as "/"
+            if (path.endsWith("/"))
+                path = path.substring(0, path.length() - 1);
+            while (true) {
+                if (pattern.equals(path))
+                    return (true);
+                int slash = path.lastIndexOf('/');
+                if (slash <= 0)
+                    break;
+                path = path.substring(0, slash);
+            }
+            return (false);
+        }
+
+        // Check for suffix matching
+        if (pattern.startsWith("*.")) {
+            int slash = path.lastIndexOf('/');
+            int period = path.lastIndexOf('.');
+            if ((slash >= 0) && (period > slash) &&
+                path.endsWith(pattern.substring(1))) {
+                return (true);
+            }
+            return (false);
+        }
+
+        // Check for universal mapping
+        if (pattern.equals("/"))
+            return (true);
+
+        return (false);
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/deploy/mbeans-descriptors.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/deploy/mbeans-descriptors.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/deploy/mbeans-descriptors.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,185 @@
+<?xml version="1.0"?>
+<mbeans-descriptors>
+
+  <mbean name="ContextEnvironment"
+         className="org.apache.catalina.mbeans.ContextEnvironmentMBean"
+         description="Representation of an application environment entry"
+         domain="Catalina"
+         group="Resources"
+         type="org.apache.catalina.deploy.ContextEnvironment">
+    
+    <attribute name="className"
+               description="Fully qualified class name of the managed object"
+               type="java.lang.String"
+               writeable="false"/>
+      
+    <attribute name="description"
+               description="The description of this environment entry"
+               type="java.lang.String"/>
+
+    <attribute name="name"
+               description="The name of this environment entry"
+               type="java.lang.String"/>
+      
+    <attribute name="override"
+               description="Does this environment entry allow overrides by the
+               application deployment descriptor"
+               type="boolean"/>
+
+    <attribute name="type"
+               description="The type of this environment entry"
+               type="java.lang.String"/>
+
+    <attribute name="value"
+               description="The value of this environment entry"
+               type="java.lang.String"/>
+  </mbean>
+
+
+  <mbean         name="ContextResource"
+         className="org.apache.catalina.mbeans.ContextResourceMBean"
+         description="Representation of a resource reference for a web application"
+         domain="Catalina"
+         group="Resources"
+         type="org.apache.catalina.deploy.ContextResource">
+    
+    <attribute   name="auth"
+               description="The authorization requirement for this resource"
+               type="java.lang.String"/>
+      
+    <attribute   name="description"
+               description="The description of this resource"
+               type="java.lang.String"/>
+      
+    <attribute   name="name"
+               description="The name of this resource"
+               type="java.lang.String"/>
+      
+    <attribute   name="scope"
+               description="The sharing scope of this resource factory"
+               type="java.lang.String"/>
+      
+    <attribute   name="type"
+               description="The type of this environment entry"
+               type="java.lang.String"/>
+  </mbean>
+  
+  
+   <mbean         name="ContextResourceLink"
+          className="org.apache.catalina.mbeans.ContextResourceLinkMBean"
+          description="Representation of a resource link for a web application"
+          domain="Catalina"
+          group="Resources"
+          type="org.apache.catalina.deploy.ContextResourceLink">
+    
+    <attribute   name="global"
+               description="The global name of this resource"
+               type="java.lang.String"/>
+      
+    <attribute   name="name"
+               description="The name of this resource"
+               type="java.lang.String"/>
+      
+    <attribute   name="type"
+               description="The type of this resource"
+               type="java.lang.String"/>
+      
+  </mbean>
+  
+  <mbean         name="NamingResources"
+            className="org.apache.catalina.mbeans.NamingResourcesMBean"
+          description="Holds and manages the naming resources defined in the
+                       J2EE Enterprise Naming Context and their associated 
+                       JNDI context"
+               domain="Catalina"
+                group="Resources"
+                 type="org.apache.catalina.deploy.NamingResources">
+
+    <attribute   name="environments"
+          description="MBean Names of the set of defined environment entries
+                       for this web application"
+                 type="[Ljava.lang.String;"
+            writeable="false"/>
+
+    <attribute   name="resources"
+          description="MBean Names of all the defined resource references
+                       for this application."
+                 type="[Ljava.lang.String;"
+            writeable="false"/>
+
+    <attribute   name="resourceLinks"
+          description="MBean Names of all the defined resource link references
+                       for this application."
+                 type="[Ljava.lang.String;"
+            writeable="false"/>
+
+    <operation   name="addEnvironment"
+          description="Add an environment entry for this web application"
+               impact="ACTION"
+           returnType="void">
+      <parameter name="envName"
+          description="New environment entry name"
+                 type="java.lang.String"/>
+      <parameter name="type"
+          description="New environment entry type"
+                 type="java.lang.String"/>
+      <parameter name="value"
+          description="New environment entry value"
+                 type="java.lang.String"/>
+    </operation>
+
+    <operation   name="addResource"
+          description="Add a resource reference for this web application"
+               impact="ACTION"
+           returnType="void">
+      <parameter name="resourceName"
+          description="New resource reference name"
+                 type="java.lang.String"/>
+      <parameter name="type"
+          description="New resource reference type"
+                 type="java.lang.String"/>
+    </operation>
+
+    <operation   name="addResourceLink"
+          description="Add a resource link reference for this web application"
+               impact="ACTION"
+           returnType="void">
+      <parameter name="resourceLinkName"
+          description="New resource reference name"
+                 type="java.lang.String"/>
+      <parameter name="type"
+          description="New resource reference type"
+                 type="java.lang.String"/>
+    </operation>
+
+    <operation   name="removeEnvironment"
+          description="Remove any environment entry with the specified name"
+               impact="ACTION"
+           returnType="void">
+      <parameter name="envName"
+          description="Name of the environment entry to remove"
+                 type="java.lang.String"/>
+    </operation>
+
+    <operation   name="removeResource"
+          description="Remove any resource reference with the specified name"
+               impact="ACTION"
+           returnType="void">
+      <parameter name="resourceName"
+          description="Name of the resource reference to remove"
+                 type="java.lang.String"/>
+    </operation>
+
+    <operation   name="removeResourceLink"
+          description="Remove any resource link reference with the specified name"
+               impact="ACTION"
+           returnType="void">
+      <parameter name="resourceLinkName"
+          description="Name of the resource reference to remove"
+                 type="java.lang.String"/>
+    </operation>
+
+  </mbean>
+
+
+</mbeans-descriptors>

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/deploy/package.html
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/deploy/package.html	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/deploy/package.html	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,10 @@
+<body>
+
+<p>This package contains Java objects that represent complex data structures
+from the web application deployment descriptor file (<code>web.xml</code>).
+It is assumed that these objects will be initialized within the context of
+a single thread, and then referenced in a read-only manner subsequent to that
+time.  Therefore, no multi-thread synchronization is utilized within the
+implementation classes.</p>
+
+</body>

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/launcher/CatalinaLaunchFilter.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/launcher/CatalinaLaunchFilter.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/launcher/CatalinaLaunchFilter.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,97 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.launcher;
+
+
+import java.util.ArrayList;
+import org.apache.commons.launcher.LaunchCommand;
+import org.apache.commons.launcher.LaunchFilter;
+import org.apache.tools.ant.BuildException;
+
+
+/**
+ * This class implements the LaunchFilter interface. This class is designed to
+ * unconditionally force the "waitforchild" attribute for certain Catalina
+ * applications to true.
+ *
+ * @author Patrick Luby
+ */
+public class CatalinaLaunchFilter implements LaunchFilter {
+
+    //----------------------------------------------------------- Static Fields
+
+    /**
+     * The Catalina bootstrap class name.
+     */
+    private static String CATALINA_BOOTSTRAP_CLASS_NAME = "org.apache.catalina.startup.Bootstrap";
+
+    //----------------------------------------------------------------- Methods
+
+    /**
+     * This method allows dynamic configuration and error checking of the
+     * attributes and nested elements in a "launch" task that is launching a
+     * Catalina application. This method evaluates the nested command line
+     * arguments and, depending on which class is specified in the task's
+     * "classname" attribute, may force the application to run
+     * in the foreground by forcing the "waitforchild" attribute to "true".
+     *
+     * @param launchCommand a configured instance of the {@link LaunchCommand}
+     *  class
+     * @throws BuildException if any errors occur
+     */
+    public void filter(LaunchCommand launchCommand) throws BuildException {
+
+        // Get attributes
+        String mainClassName = launchCommand.getClassname();
+        boolean waitForChild = launchCommand.getWaitforchild();
+        ArrayList argsList = launchCommand.getArgs();
+        String[] args = (String[])argsList.toArray(new String[argsList.size()]);
+
+        // Evaluate main class
+        if (CatalinaLaunchFilter.CATALINA_BOOTSTRAP_CLASS_NAME.equals(mainClassName)) {
+            // If "start" is not the last argument, make "waitforchild" true
+            if (args.length == 0 || !"start".equals(args[args.length - 1])) {
+                launchCommand.setWaitforchild(true);
+                return;
+            }
+
+            // If "start" is the last argument, make sure that all of the
+            // preceding arguments are OK for running in the background
+            for (int i = 0; i < args.length - 1; i++) {
+                if ("-config".equals(args[i])) {
+                    // Skip next argument since it should be a file
+                    if (args.length > i + 1) {
+                        i++;
+                    } else {
+                        launchCommand.setWaitforchild(true);
+                        return;
+                    }
+                } else if ("-debug".equals(args[i])) {
+                    // Do nothing
+                } else if ("-nonaming".equals(args[i])) {
+                    // Do nothing
+                } else {
+                     launchCommand.setWaitforchild(true);
+                     return;
+                }
+            }
+        }
+
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/loader/Constants.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/loader/Constants.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/loader/Constants.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,25 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.loader;
+
+
+public class Constants {
+
+    public static final String Package = "org.apache.catalina.loader";
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/loader/LocaStrings_fr.properties
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/loader/LocaStrings_fr.properties	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/loader/LocaStrings_fr.properties	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,30 @@
+fileClassLoader.canRead=Le réceptacle (repository) {0} ne peut être lu
+fileClassLoader.exists=Le réceptacle (repository) {0} n''existe pas
+fileClassLoader.jarFile=Impossible de lire le fichier JAR {0}
+fileClassLoader.restricted=Impossible de charger la classe restreinte (restricted class) {0}
+standardLoader.addRepository=Ajout du réceptacle (repository) {0}
+standardLoader.alreadyStarted=Le chargeur (loader) a déjà été démarré
+standardLoader.checkInterval=Impossible de régler l''interval de vérification de rechargement à {0} secondes
+standardLoader.notContext=Impossible d''auto-recharger sans que le conteneur ne soit un contexte
+standardLoader.notReloadabe=Propriété de rechargement (reloadable property) mise à faux
+standardLoader.notStarted=Le chargeur (loader) n''a pas encore été démarré
+standardLoader.reloadable=Impossible de mettre la propriété de rechargement (reloadable property) à {0}
+standardLoader.reloading=Les vérifications de rechargement sont activées pour ce contexte
+standardLoader.removeRepository=Retrait du réceptacle (repository) {0}
+standardLoader.starting=Démarrage de ce chargeur (loader)
+standardLoader.stopping=Arrêt de ce chargeur (loader)
+webappLoader.addRepository=Ajout du réceptacle (repository) {0}
+webappLoader.deploy=Déploiement des classes des réceptacles (class repositories) vers le dossier de travail (work directory) {0}
+webappLoader.jarDeploy=Déploiement du JAR {0} vers {1}
+webappLoader.classDeploy=Déploiement des fichiers classes {0} vers {1}
+webappLoader.alreadyStarted=Le chargeur (loader) a déjà été démarré
+webappLoader.checkInterval=Impossible de régler l''interval de vérification de rechargement à {0} secondes
+webappLoader.notContext=Impossible d''auto-recharger sans que le conteneur ne soit un contexte
+webappLoader.notReloadabe=Propriété de rechargement (reloadable property) mise à faux
+webappLoader.notStarted=Le chargeur (loader) n''a pas encore été démarré
+webappLoader.reloadable=Impossible de mettre la propriété de rechargement (reloadable property) à {0}
+webappLoader.reloading=Les vérifications de rechargement sont activées pour ce contexte
+webappLoader.removeRepository=Retrait du réceptacle (repository) {0}
+webappLoader.starting=Démarrage de ce chargeur (loader)
+webappLoader.stopping=Arrêt de ce chargeur (loader)
+webappLoader.failModifiedCheck=Erreur dans le suivi des modifications

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/loader/LocalStrings.properties
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/loader/LocalStrings.properties	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/loader/LocalStrings.properties	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,31 @@
+fileClassLoader.canRead=Repository {0} cannot be read
+fileClassLoader.exists=Repository {0} does not exist
+fileClassLoader.jarFile=Cannot read JAR file {0}
+fileClassLoader.restricted=Cannot load restricted class {0}
+standardLoader.addRepository=Adding repository {0}
+standardLoader.alreadyStarted=Loader has already been started
+standardLoader.checkInterval=Cannot set reload check interval to {0} seconds
+standardLoader.notContext=Cannot auto-reload unless our Container is a Context
+standardLoader.notReloadabe=Reloadable property is set to false
+standardLoader.notStarted=Loader has not yet been started
+standardLoader.reloadable=Cannot set reloadable property to {0}
+standardLoader.reloading=Reloading checks are enabled for this Context
+standardLoader.removeRepository=Removing repository {0}
+standardLoader.starting=Starting this Loader
+standardLoader.stopping=Stopping this Loader
+webappClassLoader.stopped=Illegal access: this web application instance has been stopped already.  Could not load {0}.  The eventual following stack trace is caused by an error thrown for debugging purposes as well as to attempt to terminate the thread which caused the illegal access, and has no functional impact.
+webappLoader.addRepository=Adding repository {0}
+webappLoader.deploy=Deploying class repositories to work directory {0}
+webappLoader.jarDeploy=Deploy JAR {0} to {1}
+webappLoader.classDeploy=Deploy class files {0} to {1}
+webappLoader.alreadyStarted=Loader has already been started
+webappLoader.checkInterval=Cannot set reload check interval to {0} seconds
+webappLoader.notContext=Cannot auto-reload unless our Container is a Context
+webappLoader.notReloadabe=Reloadable property is set to false
+webappLoader.notStarted=Loader has not yet been started
+webappLoader.reloadable=Cannot set reloadable property to {0}
+webappLoader.reloading=Reloading checks are enabled for this Context
+webappLoader.removeRepository=Removing repository {0}
+webappLoader.starting=Starting this Loader
+webappLoader.stopping=Stopping this Loader
+webappLoader.failModifiedCheck=Error tracking modifications

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/loader/LocalStrings_es.properties
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/loader/LocalStrings_es.properties	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/loader/LocalStrings_es.properties	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,31 @@
+fileClassLoader.canRead=No se puede leer el Repositorio {0}
+fileClassLoader.exists=No existe el Repositorio {0}
+fileClassLoader.jarFile=No puedo leer archivo JAR {0}
+fileClassLoader.restricted=No puedo cargar clase restringida {0}
+standardLoader.addRepository=Añadiendo repositorio {0}
+standardLoader.alreadyStarted=Ya ha sido arrancado el Cargador
+standardLoader.checkInterval=No puedo poner el intervalo de revisión de recarga a {0} segundos
+standardLoader.notContext=No puedo auto-recargar a menos que nuestro Contenedor sea un Contexto
+standardLoader.notReloadabe=La propiedad Recargable está puesta a falsa
+standardLoader.notStarted=Aún no se ha arrancado el Cargador
+standardLoader.reloadable=No puedo poner la propiedad recargable a {0}
+standardLoader.reloading=Se han activado las revisiones de Recarga para este Contexto
+standardLoader.removeRepository=Quitando repositorio {0}
+standardLoader.starting=Arrancando este Cargador
+standardLoader.stopping=Parando este Cargador
+webappClassLoader.stopped=Acceso ilegal: esta instancia de aplicación web ya ha sido parada.  Could not load {0}.  La eventual traza de pila que sigue ha sido motivada por un error lanzado con motivos de depuración así como para intentar terminar el hilo que motivó el acceso ilegal y no tiene impacto funcional.
+webappLoader.addRepository=Añadiendo repositorio {0}
+webappLoader.deploy=Desplegando repositorios de clase en directorio de trabajo {0}
+webappLoader.jarDeploy=Despliegue del JAR {0} en {1}
+webappLoader.classDeploy=Despliegue de archivos de clase {0} en {1}
+webappLoader.alreadyStarted=Ya se ha arrancado el Cargador
+webappLoader.checkInterval=No puedo poner el intervalo de revisión de recarga a {0} segundos
+webappLoader.notContext=No puedo auto-recargar a menos que nuestro Contenedor sea un Contexto
+webappLoader.notReloadabe=Se ha puesto la propiedad Recargable a falsa
+webappLoader.notStarted=Aún no se ha arrancado el Cargador
+webappLoader.reloadable=No puedo poner la propiedad recargable a {0}
+webappLoader.reloading=Se han activado los chequeos de Recarga para este Contexto
+webappLoader.removeRepository=Quitando repositorio {0}
+webappLoader.starting=Arrancando este Cargador
+webappLoader.stopping=Parando este Cargador
+webappLoader.failModifiedCheck=Modificaciones de pista de error

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/loader/LocalStrings_ja.properties
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/loader/LocalStrings_ja.properties	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/loader/LocalStrings_ja.properties	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,31 @@
+fileClassLoader.canRead=\u30ea\u30dd\u30b8\u30c8\u30ea {0} \u304c\u8aad\u3081\u307e\u305b\u3093
+fileClassLoader.exists=\u30ea\u30dd\u30b8\u30c8\u30ea {0} \u304c\u5b58\u5728\u3057\u307e\u305b\u3093
+fileClassLoader.jarFile=JAR\u30d5\u30a1\u30a4\u30eb {0} \u304c\u8aad\u3081\u307e\u305b\u3093
+fileClassLoader.restricted=\u5236\u9650\u3055\u308c\u305f\u30af\u30e9\u30b9 {0} \u3092\u30ed\u30fc\u30c9\u3067\u304d\u307e\u305b\u3093
+standardLoader.addRepository=\u30ea\u30dd\u30b8\u30c8\u30ea {0} \u3092\u8ffd\u52a0\u3057\u307e\u3059
+standardLoader.alreadyStarted=\u30ed\u30fc\u30c0\u306f\u65e2\u306b\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u3059
+standardLoader.checkInterval=\u518d\u30ed\u30fc\u30c9\u30c1\u30a7\u30c3\u30af\u9593\u9694\u3092{0}\u79d2\u306b\u8a2d\u5b9a\u3067\u304d\u307e\u305b\u3093
+standardLoader.notContext=\u3053\u306e\u30b3\u30f3\u30c6\u30ca\u304c\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u3067\u306a\u3051\u308c\u3070\u3001\u81ea\u52d5\u518d\u30ed\u30fc\u30c9\u306f\u3067\u304d\u307e\u305b\u3093
+standardLoader.notReloadabe=reloadable\u30d7\u30ed\u30d1\u30c6\u30a3\u304cfalse\u306b\u8a2d\u5b9a\u3055\u308c\u3066\u3044\u307e\u3059
+standardLoader.notStarted=\u30ed\u30fc\u30c0\u306f\u307e\u3060\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u305b\u3093
+standardLoader.reloadable=reloadable\u30d7\u30ed\u30d1\u30c6\u30a3\u3092 {0} \u306b\u8a2d\u5b9a\u3067\u304d\u307e\u305b\u3093
+standardLoader.reloading=\u3053\u306e\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u306e\u518d\u30ed\u30fc\u30c9\u30c1\u30a7\u30c3\u30af\u306f\u6709\u52b9\u3067\u3059
+standardLoader.removeRepository=\u30ea\u30dd\u30b8\u30c8\u30ea {0} \u3092\u524a\u9664\u3057\u307e\u3059
+standardLoader.starting=\u3053\u306e\u30ed\u30fc\u30c0\u3092\u8d77\u52d5\u3057\u307e\u3059
+standardLoader.stopping=\u3053\u306e\u30ed\u30fc\u30c0\u3092\u505c\u6b62\u3057\u307e\u3059
+webappClassLoader.stopped=\u4e0d\u6b63\u306a\u30a2\u30af\u30bb\u30b9: \u3053\u306eWeb\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u306e\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u306f\u65e2\u306b\u505c\u6b62\u3055\u308c\u3066\u3044\u307e\u3059  Could not load {0}. \u4e0d\u6b63\u306a\u30a2\u30af\u30bb\u30b9\u3092\u5f15\u304d\u8d77\u3053\u3057\u305f\u30b9\u30ec\u30c3\u30c9\u3092\u7d42\u4e86\u3055\u305b\u3001\u6295\u3052\u3089\u308c\u305f\u30a8\u30e9\u30fc\u306b\u3088\u308a\u30c7\u30d0\u30c3\u30b0\u7528\u306b\u6b21\u306e\u30b9\u30bf\u30c3\u30af\u30c8\u30ec\u30fc\u30b9\u304c\u751f\u6210\u3055\u308c\u307e\u3057\u305f\u304c\uff0c\u6a5f\u80fd\u306b\u5f71\u97ff\u306f\u3042\u308a\u307e\u305b\u3093
+webappLoader.addRepository=\u30ea\u30dd\u30b8\u30c8\u30ea {0} \u3092\u8ffd\u52a0\u3057\u307e\u3059
+webappLoader.deploy=\u30af\u30e9\u30b9\u30ea\u30dd\u30b8\u30c8\u30ea\u3092\u4f5c\u696d\u30c7\u30a3\u30ec\u30af\u30c8\u30ea {0} \u306b\u914d\u5099\u3057\u307e\u3059
+webappLoader.jarDeploy=JAR {0} \u3092 {1} \u306b\u914d\u5099\u3057\u307e\u3059
+webappLoader.classDeploy=\u30af\u30e9\u30b9\u30d5\u30a1\u30a4\u30eb {0} \u3092 {1} \u306b\u914d\u5099\u3057\u307e\u3059
+webappLoader.alreadyStarted=\u30ed\u30fc\u30c0\u306f\u65e2\u306b\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u3059
+webappLoader.checkInterval=\u518d\u30ed\u30fc\u30c9\u30c1\u30a7\u30c3\u30af\u9593\u9694\u3092{0}\u79d2\u306b\u8a2d\u5b9a\u3067\u304d\u307e\u305b\u3093
+webappLoader.notContext=\u3053\u306e\u30b3\u30f3\u30c6\u30ca\u304c\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u3067\u306a\u3051\u308c\u3070\u3001\u81ea\u52d5\u518d\u30ed\u30fc\u30c9\u306f\u3067\u304d\u307e\u305b\u3093
+webappLoader.notReloadabe=reloadable\u30d7\u30ed\u30d1\u30c6\u30a3\u304cfalse\u306b\u8a2d\u5b9a\u3055\u308c\u3066\u3044\u307e\u3059
+webappLoader.notStarted=\u30ed\u30fc\u30c0\u306f\u307e\u3060\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u305b\u3093
+webappLoader.reloadable=reloadable\u30d7\u30ed\u30d1\u30c6\u30a3\u3092 {0} \u306b\u8a2d\u5b9a\u3067\u304d\u307e\u305b\u3093
+webappLoader.reloading=\u3053\u306e\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u306e\u518d\u30ed\u30fc\u30c9\u30c1\u30a7\u30c3\u30af\u306f\u6709\u52b9\u3067\u3059
+webappLoader.removeRepository=\u30ea\u30dd\u30b8\u30c8\u30ea {0} \u3092\u524a\u9664\u3057\u307e\u3059
+webappLoader.starting=\u3053\u306e\u30ed\u30fc\u30c0\u3092\u8d77\u52d5\u3057\u307e\u3059
+webappLoader.stopping=\u3053\u306e\u30ed\u30fc\u30c0\u3092\u505c\u6b62\u3057\u307e\u3059
+webappLoader.failModifiedCheck=\u5909\u66f4\u8ffd\u8de1\u30a8\u30e9\u30fc\u3067\u3059

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/loader/Reloader.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/loader/Reloader.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/loader/Reloader.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,61 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.loader;
+
+
+/**
+ * Internal interface that <code>ClassLoader</code> implementations may
+ * optionally implement to support the auto-reload functionality of
+ * the classloader associated with the context.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public interface Reloader {
+
+
+    /**
+     * Add a new repository to the set of places this ClassLoader can look for
+     * classes to be loaded.
+     *
+     * @param repository Name of a source of classes to be loaded, such as a
+     *  directory pathname, a JAR file pathname, or a ZIP file pathname
+     *
+     * @exception IllegalArgumentException if the specified repository is
+     *  invalid or does not exist
+     */
+    public void addRepository(String repository);
+
+
+    /**
+     * Return a String array of the current repositories for this class
+     * loader.  If there are no repositories, a zero-length array is
+     * returned.
+     */
+    public String[] findRepositories();
+
+
+    /**
+     * Have one or more classes or resources been modified so that a reload
+     * is appropriate?
+     */
+    public boolean modified();
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/loader/ResourceEntry.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/loader/ResourceEntry.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/loader/ResourceEntry.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,77 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.loader;
+
+import java.net.URL;
+import java.security.cert.Certificate;
+import java.util.jar.Manifest;
+
+/**
+ * Resource entry.
+ *
+ * @author Remy Maucherat
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+public class ResourceEntry {
+
+
+    /**
+     * The "last modified" time of the origin file at the time this class
+     * was loaded, in milliseconds since the epoch.
+     */
+    public long lastModified = -1;
+
+
+    /**
+     * Binary content of the resource.
+     */
+    public byte[] binaryContent = null;
+
+
+    /**
+     * Loaded class.
+     */
+    public Class loadedClass = null;
+
+
+    /**
+     * URL source from where the object was loaded.
+     */
+    public URL source = null;
+
+
+    /**
+     * URL of the codebase from where the object was loaded.
+     */
+    public URL codeBase = null;
+
+
+    /**
+     * Manifest (if the resource was loaded from a JAR).
+     */
+    public Manifest manifest = null;
+
+
+    /**
+     * Certificates (if the resource was loaded from a JAR).
+     */
+    public Certificate[] certificates = null;
+
+
+}
+

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/loader/StandardClassLoader.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/loader/StandardClassLoader.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/loader/StandardClassLoader.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,60 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.loader;
+
+import java.net.URL;
+import java.net.URLClassLoader;
+
+/**
+ * Subclass implementation of <b>java.net.URLClassLoader</b> that knows how
+ * to load classes from disk directories, as well as local and remote JAR
+ * files.  It also implements the <code>Reloader</code> interface, to provide
+ * automatic reloading support to the associated loader.
+ * <p>
+ * In all cases, URLs must conform to the contract specified by
+ * <code>URLClassLoader</code> - any URL that ends with a "/" character is
+ * assumed to represent a directory; all other URLs are assumed to be the
+ * address of a JAR file.
+ * <p>
+ * <strong>IMPLEMENTATION NOTE</strong> - Local repositories are searched in
+ * the order they are added via the initial constructor and/or any subsequent
+ * calls to <code>addRepository()</code>.
+ * <p>
+ * <strong>IMPLEMENTATION NOTE</strong> - At present, there are no dependencies
+ * from this class to any other Catalina class, so that it could be used
+ * independently.
+ *
+ * @author Craig R. McClanahan
+ * @author Remy Maucherat
+ * @version $Revision: 303071 $ $Date: 2004-08-05 05:54:43 -0500 (Thu, 05 Aug 2004) $
+ */
+
+public class StandardClassLoader
+    extends URLClassLoader
+    implements StandardClassLoaderMBean {
+
+	public StandardClassLoader(URL repositories[]) {
+        super(repositories);
+    }
+
+    public StandardClassLoader(URL repositories[], ClassLoader parent) {
+        super(repositories, parent);
+    }
+
+}
+

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/loader/StandardClassLoaderMBean.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/loader/StandardClassLoaderMBean.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/loader/StandardClassLoaderMBean.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,28 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.loader;
+
+/**
+ * MBean interface for StandardClassLoader, to allow JMX remote management.
+ *
+ * @author Remy Maucherat
+ * @version $Revision: 302740 $ $Date: 2004-03-02 06:32:19 -0600 (Tue, 02 Mar 2004) $
+ */
+public interface StandardClassLoaderMBean {
+}
+

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/loader/WebappClassLoader.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/loader/WebappClassLoader.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/loader/WebappClassLoader.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,2341 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.loader;
+
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.FilePermission;
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.security.AccessControlException;
+import java.security.AccessController;
+import java.security.CodeSource;
+import java.security.Permission;
+import java.security.PermissionCollection;
+import java.security.Policy;
+import java.security.PrivilegedAction;
+import java.sql.Driver;
+import java.sql.DriverManager;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Vector;
+import java.util.jar.Attributes;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+import java.util.jar.Manifest;
+import java.util.jar.Attributes.Name;
+
+import javax.naming.NameClassPair;
+import javax.naming.NamingEnumeration;
+import javax.naming.NamingException;
+import javax.naming.directory.DirContext;
+
+import org.apache.catalina.Lifecycle;
+import org.apache.catalina.LifecycleException;
+import org.apache.catalina.LifecycleListener;
+import org.apache.catalina.util.StringManager;
+import org.apache.naming.JndiPermission;
+import org.apache.naming.resources.Resource;
+import org.apache.naming.resources.ResourceAttributes;
+import org.apache.tomcat.util.IntrospectionUtils;
+
+/**
+ * Specialized web application class loader.
+ * <p>
+ * This class loader is a full reimplementation of the 
+ * <code>URLClassLoader</code> from the JDK. It is desinged to be fully
+ * compatible with a normal <code>URLClassLoader</code>, although its internal
+ * behavior may be completely different.
+ * <p>
+ * <strong>IMPLEMENTATION NOTE</strong> - This class loader faithfully follows 
+ * the delegation model recommended in the specification. The system class 
+ * loader will be queried first, then the local repositories, and only then 
+ * delegation to the parent class loader will occur. This allows the web 
+ * application to override any shared class except the classes from J2SE.
+ * Special handling is provided from the JAXP XML parser interfaces, the JNDI
+ * interfaces, and the classes from the servlet API, which are never loaded 
+ * from the webapp repository.
+ * <p>
+ * <strong>IMPLEMENTATION NOTE</strong> - Due to limitations in Jasper 
+ * compilation technology, any repository which contains classes from 
+ * the servlet API will be ignored by the class loader.
+ * <p>
+ * <strong>IMPLEMENTATION NOTE</strong> - The class loader generates source
+ * URLs which include the full JAR URL when a class is loaded from a JAR file,
+ * which allows setting security permission at the class level, even when a
+ * class is contained inside a JAR.
+ * <p>
+ * <strong>IMPLEMENTATION NOTE</strong> - Local repositories are searched in
+ * the order they are added via the initial constructor and/or any subsequent
+ * calls to <code>addRepository()</code> or <code>addJar()</code>.
+ * <p>
+ * <strong>IMPLEMENTATION NOTE</strong> - No check for sealing violations or
+ * security is made unless a security manager is present.
+ *
+ * @author Remy Maucherat
+ * @author Craig R. McClanahan
+ * @version $Revision: 414654 $ $Date: 2006-06-15 13:51:57 -0500 (Thu, 15 Jun 2006) $
+ */
+public class WebappClassLoader
+    extends URLClassLoader
+    implements Reloader, Lifecycle
+ {
+
+    protected static org.apache.commons.logging.Log log=
+        org.apache.commons.logging.LogFactory.getLog( WebappClassLoader.class );
+
+    protected class PrivilegedFindResource
+        implements PrivilegedAction {
+
+        protected File file;
+        protected String path;
+
+        PrivilegedFindResource(File file, String path) {
+            this.file = file;
+            this.path = path;
+        }
+
+        public Object run() {
+            return findResourceInternal(file, path);
+        }
+
+    }
+
+
+    // ------------------------------------------------------- Static Variables
+
+
+    /**
+     * The set of trigger classes that will cause a proposed repository not
+     * to be added if this class is visible to the class loader that loaded
+     * this factory class.  Typically, trigger classes will be listed for
+     * components that have been integrated into the JDK for later versions,
+     * but where the corresponding JAR files are required to run on
+     * earlier versions.
+     */
+    protected static final String[] triggers = {
+        "javax.servlet.Servlet",                    // Servlet API
+        "javax.servlet.jsp.JspPage"                 // JSP API
+    };
+
+
+    /**
+     * Set of package names which are not allowed to be loaded from a webapp
+     * class loader without delegating first.
+     */
+    protected static final String[] packageTriggers = {
+    };
+
+
+    /**
+     * The string manager for this package.
+     */
+    protected static final StringManager sm =
+        StringManager.getManager(Constants.Package);
+
+    
+    /**
+     * Use anti JAR locking code, which does URL rerouting when accessing
+     * resources.
+     */
+    boolean antiJARLocking = false; 
+    
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Construct a new ClassLoader with no defined repositories and no
+     * parent ClassLoader.
+     */
+    public WebappClassLoader() {
+
+        super(new URL[0]);
+        this.parent = getParent();
+        system = getSystemClassLoader();
+        securityManager = System.getSecurityManager();
+
+        if (securityManager != null) {
+            refreshPolicy();
+        }
+
+    }
+
+
+    /**
+     * Construct a new ClassLoader with no defined repositories and no
+     * parent ClassLoader.
+     */
+    public WebappClassLoader(ClassLoader parent) {
+
+        super(new URL[0], parent);
+                
+        this.parent = getParent();
+        
+        system = getSystemClassLoader();
+        securityManager = System.getSecurityManager();
+
+        if (securityManager != null) {
+            refreshPolicy();
+        }
+    }
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * Associated directory context giving access to the resources in this
+     * webapp.
+     */
+    protected DirContext resources = null;
+
+
+    /**
+     * The cache of ResourceEntry for classes and resources we have loaded,
+     * keyed by resource name.
+     */
+    protected HashMap resourceEntries = new HashMap();
+
+
+    /**
+     * The list of not found resources.
+     */
+    protected HashMap notFoundResources = new HashMap();
+
+
+    /**
+     * Should this class loader delegate to the parent class loader
+     * <strong>before</strong> searching its own repositories (i.e. the
+     * usual Java2 delegation model)?  If set to <code>false</code>,
+     * this class loader will search its own repositories first, and
+     * delegate to the parent only if the class or resource is not
+     * found locally.
+     */
+    protected boolean delegate = false;
+
+
+    /**
+     * Last time a JAR was accessed.
+     */
+    protected long lastJarAccessed = 0L;
+
+
+    /**
+     * The list of local repositories, in the order they should be searched
+     * for locally loaded classes or resources.
+     */
+    protected String[] repositories = new String[0];
+
+
+     /**
+      * Repositories URLs, used to cache the result of getURLs.
+      */
+     protected URL[] repositoryURLs = null;
+
+
+    /**
+     * Repositories translated as path in the work directory (for Jasper
+     * originally), but which is used to generate fake URLs should getURLs be
+     * called.
+     */
+    protected File[] files = new File[0];
+
+
+    /**
+     * The list of JARs, in the order they should be searched
+     * for locally loaded classes or resources.
+     */
+    protected JarFile[] jarFiles = new JarFile[0];
+
+
+    /**
+     * The list of JARs, in the order they should be searched
+     * for locally loaded classes or resources.
+     */
+    protected File[] jarRealFiles = new File[0];
+
+
+    /**
+     * The path which will be monitored for added Jar files.
+     */
+    protected String jarPath = null;
+
+
+    /**
+     * The list of JARs, in the order they should be searched
+     * for locally loaded classes or resources.
+     */
+    protected String[] jarNames = new String[0];
+
+
+    /**
+     * The list of JARs last modified dates, in the order they should be
+     * searched for locally loaded classes or resources.
+     */
+    protected long[] lastModifiedDates = new long[0];
+
+
+    /**
+     * The list of resources which should be checked when checking for
+     * modifications.
+     */
+    protected String[] paths = new String[0];
+
+
+    /**
+     * A list of read File and Jndi Permission's required if this loader
+     * is for a web application context.
+     */
+    protected ArrayList permissionList = new ArrayList();
+
+
+    /**
+     * Path where resources loaded from JARs will be extracted.
+     */
+    protected File loaderDir = null;
+
+
+    /**
+     * The PermissionCollection for each CodeSource for a web
+     * application context.
+     */
+    protected HashMap loaderPC = new HashMap();
+
+
+    /**
+     * Instance of the SecurityManager installed.
+     */
+    protected SecurityManager securityManager = null;
+
+
+    /**
+     * The parent class loader.
+     */
+    protected ClassLoader parent = null;
+
+
+    /**
+     * The system class loader.
+     */
+    protected ClassLoader system = null;
+
+
+    /**
+     * Has this component been started?
+     */
+    protected boolean started = false;
+
+
+    /**
+     * Has external repositories.
+     */
+    protected boolean hasExternalRepositories = false;
+
+    /**
+     * need conversion for properties files
+     */
+    protected boolean needConvert = false;
+
+
+    /**
+     * All permission.
+     */
+    protected Permission allPermission = new java.security.AllPermission();
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * Get associated resources.
+     */
+    public DirContext getResources() {
+
+        return this.resources;
+
+    }
+
+
+    /**
+     * Set associated resources.
+     */
+    public void setResources(DirContext resources) {
+
+        this.resources = resources;
+
+    }
+
+
+    /**
+     * Return the "delegate first" flag for this class loader.
+     */
+    public boolean getDelegate() {
+
+        return (this.delegate);
+
+    }
+
+
+    /**
+     * Set the "delegate first" flag for this class loader.
+     *
+     * @param delegate The new "delegate first" flag
+     */
+    public void setDelegate(boolean delegate) {
+
+        this.delegate = delegate;
+
+    }
+
+
+    /**
+     * @return Returns the antiJARLocking.
+     */
+    public boolean getAntiJARLocking() {
+        return antiJARLocking;
+    }
+    
+    
+    /**
+     * @param antiJARLocking The antiJARLocking to set.
+     */
+    public void setAntiJARLocking(boolean antiJARLocking) {
+        this.antiJARLocking = antiJARLocking;
+    }
+
+    
+    /**
+     * If there is a Java SecurityManager create a read FilePermission
+     * or JndiPermission for the file directory path.
+     *
+     * @param path file directory path
+     */
+    public void addPermission(String path) {
+        if (path == null) {
+            return;
+        }
+
+        if (securityManager != null) {
+            Permission permission = null;
+            if( path.startsWith("jndi:") || path.startsWith("jar:jndi:") ) {
+                if (!path.endsWith("/")) {
+                    path = path + "/";
+                }
+                permission = new JndiPermission(path + "*");
+                addPermission(permission);
+            } else {
+                if (!path.endsWith(File.separator)) {
+                    permission = new FilePermission(path, "read");
+                    addPermission(permission);
+                    path = path + File.separator;
+                }
+                permission = new FilePermission(path + "-", "read");
+                addPermission(permission);
+            }
+        }
+    }
+
+
+    /**
+     * If there is a Java SecurityManager create a read FilePermission
+     * or JndiPermission for URL.
+     *
+     * @param url URL for a file or directory on local system
+     */
+    public void addPermission(URL url) {
+        if (url != null) {
+            addPermission(url.toString());
+        }
+    }
+
+
+    /**
+     * If there is a Java SecurityManager create a Permission.
+     *
+     * @param permission The permission
+     */
+    public void addPermission(Permission permission) {
+        if ((securityManager != null) && (permission != null)) {
+            permissionList.add(permission);
+        }
+    }
+
+
+    /**
+     * Return the JAR path.
+     */
+    public String getJarPath() {
+
+        return this.jarPath;
+
+    }
+
+
+    /**
+     * Change the Jar path.
+     */
+    public void setJarPath(String jarPath) {
+
+        this.jarPath = jarPath;
+
+    }
+
+
+    /**
+     * Change the work directory.
+     */
+    public void setWorkDir(File workDir) {
+        this.loaderDir = new File(workDir, "loader");
+    }
+
+     /**
+      * Utility method for use in subclasses.
+      * Must be called before Lifecycle methods to have any effect.
+      */
+     protected void setParentClassLoader(ClassLoader pcl) {
+         parent = pcl;
+     }
+
+    // ------------------------------------------------------- Reloader Methods
+
+
+    /**
+     * Add a new repository to the set of places this ClassLoader can look for
+     * classes to be loaded.
+     *
+     * @param repository Name of a source of classes to be loaded, such as a
+     *  directory pathname, a JAR file pathname, or a ZIP file pathname
+     *
+     * @exception IllegalArgumentException if the specified repository is
+     *  invalid or does not exist
+     */
+    public void addRepository(String repository) {
+
+        // Ignore any of the standard repositories, as they are set up using
+        // either addJar or addRepository
+        if (repository.startsWith("/WEB-INF/lib")
+            || repository.startsWith("/WEB-INF/classes"))
+            return;
+
+        // Add this repository to our underlying class loader
+        try {
+            URL url = new URL(repository);
+            super.addURL(url);
+            hasExternalRepositories = true;
+            repositoryURLs = null;
+        } catch (MalformedURLException e) {
+            IllegalArgumentException iae = new IllegalArgumentException
+                ("Invalid repository: " + repository); 
+            iae.initCause(e);
+            throw iae;
+        }
+
+    }
+
+
+    /**
+     * Add a new repository to the set of places this ClassLoader can look for
+     * classes to be loaded.
+     *
+     * @param repository Name of a source of classes to be loaded, such as a
+     *  directory pathname, a JAR file pathname, or a ZIP file pathname
+     *
+     * @exception IllegalArgumentException if the specified repository is
+     *  invalid or does not exist
+     */
+    synchronized void addRepository(String repository, File file) {
+
+        // Note : There should be only one (of course), but I think we should
+        // keep this a bit generic
+
+        if (repository == null)
+            return;
+
+        if (log.isDebugEnabled())
+            log.debug("addRepository(" + repository + ")");
+
+        int i;
+
+        // Add this repository to our internal list
+        String[] result = new String[repositories.length + 1];
+        for (i = 0; i < repositories.length; i++) {
+            result[i] = repositories[i];
+        }
+        result[repositories.length] = repository;
+        repositories = result;
+
+        // Add the file to the list
+        File[] result2 = new File[files.length + 1];
+        for (i = 0; i < files.length; i++) {
+            result2[i] = files[i];
+        }
+        result2[files.length] = file;
+        files = result2;
+
+    }
+
+
+    synchronized void addJar(String jar, JarFile jarFile, File file)
+        throws IOException {
+
+        if (jar == null)
+            return;
+        if (jarFile == null)
+            return;
+        if (file == null)
+            return;
+
+        if (log.isDebugEnabled())
+            log.debug("addJar(" + jar + ")");
+
+        int i;
+
+        if ((jarPath != null) && (jar.startsWith(jarPath))) {
+
+            String jarName = jar.substring(jarPath.length());
+            while (jarName.startsWith("/"))
+                jarName = jarName.substring(1);
+
+            String[] result = new String[jarNames.length + 1];
+            for (i = 0; i < jarNames.length; i++) {
+                result[i] = jarNames[i];
+            }
+            result[jarNames.length] = jarName;
+            jarNames = result;
+
+        }
+
+        try {
+
+            // Register the JAR for tracking
+
+            long lastModified =
+                ((ResourceAttributes) resources.getAttributes(jar))
+                .getLastModified();
+
+            String[] result = new String[paths.length + 1];
+            for (i = 0; i < paths.length; i++) {
+                result[i] = paths[i];
+            }
+            result[paths.length] = jar;
+            paths = result;
+
+            long[] result3 = new long[lastModifiedDates.length + 1];
+            for (i = 0; i < lastModifiedDates.length; i++) {
+                result3[i] = lastModifiedDates[i];
+            }
+            result3[lastModifiedDates.length] = lastModified;
+            lastModifiedDates = result3;
+
+        } catch (NamingException e) {
+            // Ignore
+        }
+
+        // If the JAR currently contains invalid classes, don't actually use it
+        // for classloading
+        if (!validateJarFile(file))
+            return;
+
+        JarFile[] result2 = new JarFile[jarFiles.length + 1];
+        for (i = 0; i < jarFiles.length; i++) {
+            result2[i] = jarFiles[i];
+        }
+        result2[jarFiles.length] = jarFile;
+        jarFiles = result2;
+
+        // Add the file to the list
+        File[] result4 = new File[jarRealFiles.length + 1];
+        for (i = 0; i < jarRealFiles.length; i++) {
+            result4[i] = jarRealFiles[i];
+        }
+        result4[jarRealFiles.length] = file;
+        jarRealFiles = result4;
+    }
+
+
+    /**
+     * Return a String array of the current repositories for this class
+     * loader.  If there are no repositories, a zero-length array is
+     * returned.For security reason, returns a clone of the Array (since 
+     * String are immutable).
+     */
+    public String[] findRepositories() {
+
+        return ((String[])repositories.clone());
+
+    }
+
+
+    /**
+     * Have one or more classes or resources been modified so that a reload
+     * is appropriate?
+     */
+    public boolean modified() {
+
+        if (log.isDebugEnabled())
+            log.debug("modified()");
+
+        // Checking for modified loaded resources
+        int length = paths.length;
+
+        // A rare race condition can occur in the updates of the two arrays
+        // It's totally ok if the latest class added is not checked (it will
+        // be checked the next time
+        int length2 = lastModifiedDates.length;
+        if (length > length2)
+            length = length2;
+
+        for (int i = 0; i < length; i++) {
+            try {
+                long lastModified =
+                    ((ResourceAttributes) resources.getAttributes(paths[i]))
+                    .getLastModified();
+                if (lastModified != lastModifiedDates[i]) {
+                    if( log.isDebugEnabled() ) 
+                        log.debug("  Resource '" + paths[i]
+                                  + "' was modified; Date is now: "
+                                  + new java.util.Date(lastModified) + " Was: "
+                                  + new java.util.Date(lastModifiedDates[i]));
+                    return (true);
+                }
+            } catch (NamingException e) {
+                log.error("    Resource '" + paths[i] + "' is missing");
+                return (true);
+            }
+        }
+
+        length = jarNames.length;
+
+        // Check if JARs have been added or removed
+        if (getJarPath() != null) {
+
+            try {
+                NamingEnumeration enumeration = resources.listBindings(getJarPath());
+                int i = 0;
+                while (enumeration.hasMoreElements() && (i < length)) {
+                    NameClassPair ncPair = (NameClassPair) enumeration.nextElement();
+                    String name = ncPair.getName();
+                    // Ignore non JARs present in the lib folder
+                    if (!name.endsWith(".jar"))
+                        continue;
+                    if (!name.equals(jarNames[i])) {
+                        // Missing JAR
+                        log.info("    Additional JARs have been added : '" 
+                                 + name + "'");
+                        return (true);
+                    }
+                    i++;
+                }
+                if (enumeration.hasMoreElements()) {
+                    while (enumeration.hasMoreElements()) {
+                        NameClassPair ncPair = 
+                            (NameClassPair) enumeration.nextElement();
+                        String name = ncPair.getName();
+                        // Additional non-JAR files are allowed
+                        if (name.endsWith(".jar")) {
+                            // There was more JARs
+                            log.info("    Additional JARs have been added");
+                            return (true);
+                        }
+                    }
+                } else if (i < jarNames.length) {
+                    // There was less JARs
+                    log.info("    Additional JARs have been added");
+                    return (true);
+                }
+            } catch (NamingException e) {
+                if (log.isDebugEnabled())
+                    log.debug("    Failed tracking modifications of '"
+                        + getJarPath() + "'");
+            } catch (ClassCastException e) {
+                log.error("    Failed tracking modifications of '"
+                          + getJarPath() + "' : " + e.getMessage());
+            }
+
+        }
+
+        // No classes have been modified
+        return (false);
+
+    }
+
+
+    /**
+     * Render a String representation of this object.
+     */
+    public String toString() {
+
+        StringBuffer sb = new StringBuffer("WebappClassLoader\r\n");
+        sb.append("  delegate: ");
+        sb.append(delegate);
+        sb.append("\r\n");
+        sb.append("  repositories:\r\n");
+        if (repositories != null) {
+            for (int i = 0; i < repositories.length; i++) {
+                sb.append("    ");
+                sb.append(repositories[i]);
+                sb.append("\r\n");
+            }
+        }
+        if (this.parent != null) {
+            sb.append("----------> Parent Classloader:\r\n");
+            sb.append(this.parent.toString());
+            sb.append("\r\n");
+        }
+        return (sb.toString());
+
+    }
+
+
+    // ---------------------------------------------------- ClassLoader Methods
+
+
+     /**
+      * Add the specified URL to the classloader.
+      */
+     protected void addURL(URL url) {
+         super.addURL(url);
+         hasExternalRepositories = true;
+         repositoryURLs = null;
+     }
+
+
+    /**
+     * Find the specified class in our local repositories, if possible.  If
+     * not found, throw <code>ClassNotFoundException</code>.
+     *
+     * @param name Name of the class to be loaded
+     *
+     * @exception ClassNotFoundException if the class was not found
+     */
+    public Class findClass(String name) throws ClassNotFoundException {
+
+        if (log.isDebugEnabled())
+            log.debug("    findClass(" + name + ")");
+
+        // Cannot load anything from local repositories if class loader is stopped
+        if (!started) {
+            throw new ClassNotFoundException(name);
+        }
+
+        // (1) Permission to define this class when using a SecurityManager
+        if (securityManager != null) {
+            int i = name.lastIndexOf('.');
+            if (i >= 0) {
+                try {
+                    if (log.isTraceEnabled())
+                        log.trace("      securityManager.checkPackageDefinition");
+                    securityManager.checkPackageDefinition(name.substring(0,i));
+                } catch (Exception se) {
+                    if (log.isTraceEnabled())
+                        log.trace("      -->Exception-->ClassNotFoundException", se);
+                    throw new ClassNotFoundException(name, se);
+                }
+            }
+        }
+
+        // Ask our superclass to locate this class, if possible
+        // (throws ClassNotFoundException if it is not found)
+        Class clazz = null;
+        try {
+            if (log.isTraceEnabled())
+                log.trace("      findClassInternal(" + name + ")");
+            try {
+                clazz = findClassInternal(name);
+            } catch(ClassNotFoundException cnfe) {
+                if (!hasExternalRepositories) {
+                    throw cnfe;
+                }
+            } catch(AccessControlException ace) {
+                throw new ClassNotFoundException(name, ace);
+            } catch (RuntimeException e) {
+                if (log.isTraceEnabled())
+                    log.trace("      -->RuntimeException Rethrown", e);
+                throw e;
+            }
+            if ((clazz == null) && hasExternalRepositories) {
+                try {
+                    clazz = super.findClass(name);
+                } catch(AccessControlException ace) {
+                    throw new ClassNotFoundException(name, ace);
+                } catch (RuntimeException e) {
+                    if (log.isTraceEnabled())
+                        log.trace("      -->RuntimeException Rethrown", e);
+                    throw e;
+                }
+            }
+            if (clazz == null) {
+                if (log.isDebugEnabled())
+                    log.debug("    --> Returning ClassNotFoundException");
+                throw new ClassNotFoundException(name);
+            }
+        } catch (ClassNotFoundException e) {
+            if (log.isTraceEnabled())
+                log.trace("    --> Passing on ClassNotFoundException");
+            throw e;
+        }
+
+        // Return the class we have located
+        if (log.isTraceEnabled())
+            log.debug("      Returning class " + clazz);
+        if ((log.isTraceEnabled()) && (clazz != null))
+            log.debug("      Loaded by " + clazz.getClassLoader());
+        return (clazz);
+
+    }
+
+
+    /**
+     * Find the specified resource in our local repository, and return a
+     * <code>URL</code> refering to it, or <code>null</code> if this resource
+     * cannot be found.
+     *
+     * @param name Name of the resource to be found
+     */
+    public URL findResource(final String name) {
+
+        if (log.isDebugEnabled())
+            log.debug("    findResource(" + name + ")");
+
+        URL url = null;
+
+        ResourceEntry entry = (ResourceEntry) resourceEntries.get(name);
+        if (entry == null) {
+            entry = findResourceInternal(name, name);
+        }
+        if (entry != null) {
+            url = entry.source;
+        }
+
+        if ((url == null) && hasExternalRepositories)
+            url = super.findResource(name);
+
+        if (log.isDebugEnabled()) {
+            if (url != null)
+                log.debug("    --> Returning '" + url.toString() + "'");
+            else
+                log.debug("    --> Resource not found, returning null");
+        }
+        return (url);
+
+    }
+
+
+    /**
+     * Return an enumeration of <code>URLs</code> representing all of the
+     * resources with the given name.  If no resources with this name are
+     * found, return an empty enumeration.
+     *
+     * @param name Name of the resources to be found
+     *
+     * @exception IOException if an input/output error occurs
+     */
+    public Enumeration findResources(String name) throws IOException {
+
+        if (log.isDebugEnabled())
+            log.debug("    findResources(" + name + ")");
+
+        Vector result = new Vector();
+
+        int jarFilesLength = jarFiles.length;
+        int repositoriesLength = repositories.length;
+
+        int i;
+
+        // Looking at the repositories
+        for (i = 0; i < repositoriesLength; i++) {
+            try {
+                String fullPath = repositories[i] + name;
+                resources.lookup(fullPath);
+                // Note : Not getting an exception here means the resource was
+                // found
+                try {
+                    result.addElement(getURI(new File(files[i], name)));
+                } catch (MalformedURLException e) {
+                    // Ignore
+                }
+            } catch (NamingException e) {
+            }
+        }
+
+        // Looking at the JAR files
+        synchronized (jarFiles) {
+            if (openJARs()) {
+                for (i = 0; i < jarFilesLength; i++) {
+                    JarEntry jarEntry = jarFiles[i].getJarEntry(name);
+                    if (jarEntry != null) {
+                        try {
+                            String jarFakeUrl = getURI(jarRealFiles[i]).toString();
+                            jarFakeUrl = "jar:" + jarFakeUrl + "!/" + name;
+                            result.addElement(new URL(jarFakeUrl));
+                        } catch (MalformedURLException e) {
+                            // Ignore
+                        }
+                    }
+                }
+            }
+        }
+
+        // Adding the results of a call to the superclass
+        if (hasExternalRepositories) {
+
+            Enumeration otherResourcePaths = super.findResources(name);
+
+            while (otherResourcePaths.hasMoreElements()) {
+                result.addElement(otherResourcePaths.nextElement());
+            }
+
+        }
+
+        return result.elements();
+
+    }
+
+
+    /**
+     * Find the resource with the given name.  A resource is some data
+     * (images, audio, text, etc.) that can be accessed by class code in a
+     * way that is independent of the location of the code.  The name of a
+     * resource is a "/"-separated path name that identifies the resource.
+     * If the resource cannot be found, return <code>null</code>.
+     * <p>
+     * This method searches according to the following algorithm, returning
+     * as soon as it finds the appropriate URL.  If the resource cannot be
+     * found, returns <code>null</code>.
+     * <ul>
+     * <li>If the <code>delegate</code> property is set to <code>true</code>,
+     *     call the <code>getResource()</code> method of the parent class
+     *     loader, if any.</li>
+     * <li>Call <code>findResource()</code> to find this resource in our
+     *     locally defined repositories.</li>
+     * <li>Call the <code>getResource()</code> method of the parent class
+     *     loader, if any.</li>
+     * </ul>
+     *
+     * @param name Name of the resource to return a URL for
+     */
+    public URL getResource(String name) {
+
+        if (log.isDebugEnabled())
+            log.debug("getResource(" + name + ")");
+        URL url = null;
+
+        // (1) Delegate to parent if requested
+        if (delegate) {
+            if (log.isDebugEnabled())
+                log.debug("  Delegating to parent classloader " + parent);
+            ClassLoader loader = parent;
+            if (loader == null)
+                loader = system;
+            url = loader.getResource(name);
+            if (url != null) {
+                if (log.isDebugEnabled())
+                    log.debug("  --> Returning '" + url.toString() + "'");
+                return (url);
+            }
+        }
+
+        // (2) Search local repositories
+        url = findResource(name);
+        if (url != null) {
+            // Locating the repository for special handling in the case 
+            // of a JAR
+            if (antiJARLocking) {
+                ResourceEntry entry = (ResourceEntry) resourceEntries.get(name);
+                try {
+                    String repository = entry.codeBase.toString();
+                    if ((repository.endsWith(".jar")) 
+                            && (!(name.endsWith(".class")))) {
+                        // Copy binary content to the work directory if not present
+                        File resourceFile = new File(loaderDir, name);
+                        url = getURI(resourceFile);
+                    }
+                } catch (Exception e) {
+                    // Ignore
+                }
+            }
+            if (log.isDebugEnabled())
+                log.debug("  --> Returning '" + url.toString() + "'");
+            return (url);
+        }
+
+        // (3) Delegate to parent unconditionally if not already attempted
+        if( !delegate ) {
+            ClassLoader loader = parent;
+            if (loader == null)
+                loader = system;
+            url = loader.getResource(name);
+            if (url != null) {
+                if (log.isDebugEnabled())
+                    log.debug("  --> Returning '" + url.toString() + "'");
+                return (url);
+            }
+        }
+
+        // (4) Resource was not found
+        if (log.isDebugEnabled())
+            log.debug("  --> Resource not found, returning null");
+        return (null);
+
+    }
+
+
+    /**
+     * Find the resource with the given name, and return an input stream
+     * that can be used for reading it.  The search order is as described
+     * for <code>getResource()</code>, after checking to see if the resource
+     * data has been previously cached.  If the resource cannot be found,
+     * return <code>null</code>.
+     *
+     * @param name Name of the resource to return an input stream for
+     */
+    public InputStream getResourceAsStream(String name) {
+
+        if (log.isDebugEnabled())
+            log.debug("getResourceAsStream(" + name + ")");
+        InputStream stream = null;
+
+        // (0) Check for a cached copy of this resource
+        stream = findLoadedResource(name);
+        if (stream != null) {
+            if (log.isDebugEnabled())
+                log.debug("  --> Returning stream from cache");
+            return (stream);
+        }
+
+        // (1) Delegate to parent if requested
+        if (delegate) {
+            if (log.isDebugEnabled())
+                log.debug("  Delegating to parent classloader " + parent);
+            ClassLoader loader = parent;
+            if (loader == null)
+                loader = system;
+            stream = loader.getResourceAsStream(name);
+            if (stream != null) {
+                // FIXME - cache???
+                if (log.isDebugEnabled())
+                    log.debug("  --> Returning stream from parent");
+                return (stream);
+            }
+        }
+
+        // (2) Search local repositories
+        if (log.isDebugEnabled())
+            log.debug("  Searching local repositories");
+        URL url = findResource(name);
+        if (url != null) {
+            // FIXME - cache???
+            if (log.isDebugEnabled())
+                log.debug("  --> Returning stream from local");
+            stream = findLoadedResource(name);
+            try {
+                if (hasExternalRepositories && (stream == null))
+                    stream = url.openStream();
+            } catch (IOException e) {
+                ; // Ignore
+            }
+            if (stream != null)
+                return (stream);
+        }
+
+        // (3) Delegate to parent unconditionally
+        if (!delegate) {
+            if (log.isDebugEnabled())
+                log.debug("  Delegating to parent classloader unconditionally " + parent);
+            ClassLoader loader = parent;
+            if (loader == null)
+                loader = system;
+            stream = loader.getResourceAsStream(name);
+            if (stream != null) {
+                // FIXME - cache???
+                if (log.isDebugEnabled())
+                    log.debug("  --> Returning stream from parent");
+                return (stream);
+            }
+        }
+
+        // (4) Resource was not found
+        if (log.isDebugEnabled())
+            log.debug("  --> Resource not found, returning null");
+        return (null);
+
+    }
+
+
+    /**
+     * Load the class with the specified name.  This method searches for
+     * classes in the same manner as <code>loadClass(String, boolean)</code>
+     * with <code>false</code> as the second argument.
+     *
+     * @param name Name of the class to be loaded
+     *
+     * @exception ClassNotFoundException if the class was not found
+     */
+    public Class loadClass(String name) throws ClassNotFoundException {
+
+        return (loadClass(name, false));
+
+    }
+
+
+    /**
+     * Load the class with the specified name, searching using the following
+     * algorithm until it finds and returns the class.  If the class cannot
+     * be found, returns <code>ClassNotFoundException</code>.
+     * <ul>
+     * <li>Call <code>findLoadedClass(String)</code> to check if the
+     *     class has already been loaded.  If it has, the same
+     *     <code>Class</code> object is returned.</li>
+     * <li>If the <code>delegate</code> property is set to <code>true</code>,
+     *     call the <code>loadClass()</code> method of the parent class
+     *     loader, if any.</li>
+     * <li>Call <code>findClass()</code> to find this class in our locally
+     *     defined repositories.</li>
+     * <li>Call the <code>loadClass()</code> method of our parent
+     *     class loader, if any.</li>
+     * </ul>
+     * If the class was found using the above steps, and the
+     * <code>resolve</code> flag is <code>true</code>, this method will then
+     * call <code>resolveClass(Class)</code> on the resulting Class object.
+     *
+     * @param name Name of the class to be loaded
+     * @param resolve If <code>true</code> then resolve the class
+     *
+     * @exception ClassNotFoundException if the class was not found
+     */
+    public Class loadClass(String name, boolean resolve)
+        throws ClassNotFoundException {
+
+        if (log.isDebugEnabled())
+            log.debug("loadClass(" + name + ", " + resolve + ")");
+        Class clazz = null;
+
+        // Log access to stopped classloader
+        if (!started) {
+            try {
+                throw new IllegalStateException();
+            } catch (IllegalStateException e) {
+                log.info(sm.getString("webappClassLoader.stopped", name), e);
+            }
+        }
+
+        // (0) Check our previously loaded local class cache
+        clazz = findLoadedClass0(name);
+        if (clazz != null) {
+            if (log.isDebugEnabled())
+                log.debug("  Returning class from cache");
+            if (resolve)
+                resolveClass(clazz);
+            return (clazz);
+        }
+
+        // (0.1) Check our previously loaded class cache
+        clazz = findLoadedClass(name);
+        if (clazz != null) {
+            if (log.isDebugEnabled())
+                log.debug("  Returning class from cache");
+            if (resolve)
+                resolveClass(clazz);
+            return (clazz);
+        }
+
+        // (0.2) Try loading the class with the system class loader, to prevent
+        //       the webapp from overriding J2SE classes
+        try {
+            clazz = system.loadClass(name);
+            if (clazz != null) {
+                if (resolve)
+                    resolveClass(clazz);
+                return (clazz);
+            }
+        } catch (ClassNotFoundException e) {
+            // Ignore
+        }
+
+        // (0.5) Permission to access this class when using a SecurityManager
+        if (securityManager != null) {
+            int i = name.lastIndexOf('.');
+            if (i >= 0) {
+                try {
+                    securityManager.checkPackageAccess(name.substring(0,i));
+                } catch (SecurityException se) {
+                    String error = "Security Violation, attempt to use " +
+                        "Restricted Class: " + name;
+                    log.info(error, se);
+                    throw new ClassNotFoundException(error, se);
+                }
+            }
+        }
+
+        boolean delegateLoad = delegate || filter(name);
+
+        // (1) Delegate to our parent if requested
+        if (delegateLoad) {
+            if (log.isDebugEnabled())
+                log.debug("  Delegating to parent classloader1 " + parent);
+            ClassLoader loader = parent;
+            if (loader == null)
+                loader = system;
+            try {
+                clazz = loader.loadClass(name);
+                if (clazz != null) {
+                    if (log.isDebugEnabled())
+                        log.debug("  Loading class from parent");
+                    if (resolve)
+                        resolveClass(clazz);
+                    return (clazz);
+                }
+            } catch (ClassNotFoundException e) {
+                ;
+            }
+        }
+
+        // (2) Search local repositories
+        if (log.isDebugEnabled())
+            log.debug("  Searching local repositories");
+        try {
+            clazz = findClass(name);
+            if (clazz != null) {
+                if (log.isDebugEnabled())
+                    log.debug("  Loading class from local repository");
+                if (resolve)
+                    resolveClass(clazz);
+                return (clazz);
+            }
+        } catch (ClassNotFoundException e) {
+            ;
+        }
+
+        // (3) Delegate to parent unconditionally
+        if (!delegateLoad) {
+            if (log.isDebugEnabled())
+                log.debug("  Delegating to parent classloader at end: " + parent);
+            ClassLoader loader = parent;
+            if (loader == null)
+                loader = system;
+            try {
+                clazz = loader.loadClass(name);
+                if (clazz != null) {
+                    if (log.isDebugEnabled())
+                        log.debug("  Loading class from parent");
+                    if (resolve)
+                        resolveClass(clazz);
+                    return (clazz);
+                }
+            } catch (ClassNotFoundException e) {
+                ;
+            }
+        }
+
+        throw new ClassNotFoundException(name);
+    }
+
+
+    /**
+     * Get the Permissions for a CodeSource.  If this instance
+     * of WebappClassLoader is for a web application context,
+     * add read FilePermission or JndiPermissions for the base
+     * directory (if unpacked),
+     * the context URL, and jar file resources.
+     *
+     * @param codeSource where the code was loaded from
+     * @return PermissionCollection for CodeSource
+     */
+    protected PermissionCollection getPermissions(CodeSource codeSource) {
+
+        String codeUrl = codeSource.getLocation().toString();
+        PermissionCollection pc;
+        if ((pc = (PermissionCollection)loaderPC.get(codeUrl)) == null) {
+            pc = super.getPermissions(codeSource);
+            if (pc != null) {
+                Iterator perms = permissionList.iterator();
+                while (perms.hasNext()) {
+                    Permission p = (Permission)perms.next();
+                    pc.add(p);
+                }
+                loaderPC.put(codeUrl,pc);
+            }
+        }
+        return (pc);
+
+    }
+
+
+    /**
+     * Returns the search path of URLs for loading classes and resources.
+     * This includes the original list of URLs specified to the constructor,
+     * along with any URLs subsequently appended by the addURL() method.
+     * @return the search path of URLs for loading classes and resources.
+     */
+    public URL[] getURLs() {
+
+        if (repositoryURLs != null) {
+            return repositoryURLs;
+        }
+
+        URL[] external = super.getURLs();
+
+        int filesLength = files.length;
+        int jarFilesLength = jarRealFiles.length;
+        int length = filesLength + jarFilesLength + external.length;
+        int i;
+
+        try {
+
+            URL[] urls = new URL[length];
+            for (i = 0; i < length; i++) {
+                if (i < filesLength) {
+                    urls[i] = getURL(files[i], true);
+                } else if (i < filesLength + jarFilesLength) {
+                    urls[i] = getURL(jarRealFiles[i - filesLength], true);
+                } else {
+                    urls[i] = external[i - filesLength - jarFilesLength];
+                }
+            }
+
+            repositoryURLs = urls;
+
+        } catch (MalformedURLException e) {
+            repositoryURLs = new URL[0];
+        }
+
+        return repositoryURLs;
+
+    }
+
+
+    // ------------------------------------------------------ Lifecycle Methods
+
+
+    /**
+     * Add a lifecycle event listener to this component.
+     *
+     * @param listener The listener to add
+     */
+    public void addLifecycleListener(LifecycleListener listener) {
+    }
+
+
+    /**
+     * Get the lifecycle listeners associated with this lifecycle. If this 
+     * Lifecycle has no listeners registered, a zero-length array is returned.
+     */
+    public LifecycleListener[] findLifecycleListeners() {
+        return new LifecycleListener[0];
+    }
+
+
+    /**
+     * Remove a lifecycle event listener from this component.
+     *
+     * @param listener The listener to remove
+     */
+    public void removeLifecycleListener(LifecycleListener listener) {
+    }
+
+
+    /**
+     * Start the class loader.
+     *
+     * @exception LifecycleException if a lifecycle error occurs
+     */
+    public void start() throws LifecycleException {
+
+        started = true;
+        String encoding = null;
+        try {
+            encoding = System.getProperty("file.encoding");
+        } catch (Exception e) {
+            return;
+        }
+        if (encoding.indexOf("EBCDIC")!=-1) {
+            needConvert = true;
+        }
+
+    }
+
+
+    /**
+     * Stop the class loader.
+     *
+     * @exception LifecycleException if a lifecycle error occurs
+     */
+    public void stop() throws LifecycleException {
+
+        // Clearing references should be done before setting started to
+        // false, due to possible side effects
+        clearReferences();
+
+        started = false;
+
+        int length = files.length;
+        for (int i = 0; i < length; i++) {
+            files[i] = null;
+        }
+
+        length = jarFiles.length;
+        for (int i = 0; i < length; i++) {
+            try {
+                if (jarFiles[i] != null) {
+                    jarFiles[i].close();
+                }
+            } catch (IOException e) {
+                // Ignore
+            }
+            jarFiles[i] = null;
+        }
+
+        notFoundResources.clear();
+        resourceEntries.clear();
+        resources = null;
+        repositories = null;
+        repositoryURLs = null;
+        files = null;
+        jarFiles = null;
+        jarRealFiles = null;
+        jarPath = null;
+        jarNames = null;
+        lastModifiedDates = null;
+        paths = null;
+        hasExternalRepositories = false;
+        parent = null;
+
+        permissionList.clear();
+        loaderPC.clear();
+
+        if (loaderDir != null) {
+            deleteDir(loaderDir);
+        }
+
+    }
+
+
+    /**
+     * Used to periodically signal to the classloader to release 
+     * JAR resources.
+     */
+    public void closeJARs(boolean force) {
+        if (jarFiles.length > 0) {
+                synchronized (jarFiles) {
+                    if (force || (System.currentTimeMillis() 
+                                  > (lastJarAccessed + 90000))) {
+                        for (int i = 0; i < jarFiles.length; i++) {
+                            try {
+                                if (jarFiles[i] != null) {
+                                    jarFiles[i].close();
+                                    jarFiles[i] = null;
+                                }
+                            } catch (IOException e) {
+                                if (log.isDebugEnabled()) {
+                                    log.debug("Failed to close JAR", e);
+                                }
+                            }
+                        }
+                    }
+                }
+        }
+    }
+
+
+    // ------------------------------------------------------ Protected Methods
+
+    
+    /**
+     * Clear references.
+     */
+    protected void clearReferences() {
+
+        // Unregister any JDBC drivers loaded by this classloader
+        Enumeration drivers = DriverManager.getDrivers();
+        while (drivers.hasMoreElements()) {
+            Driver driver = (Driver) drivers.nextElement();
+            if (driver.getClass().getClassLoader() == this) {
+                try {
+                    DriverManager.deregisterDriver(driver);
+                } catch (SQLException e) {
+                    log.warn("SQL driver deregistration failed", e);
+                }
+            }
+        }
+        
+        // Null out any static or final fields from loaded classes,
+        // as a workaround for apparent garbage collection bugs
+        Iterator loadedClasses = ((HashMap) resourceEntries.clone()).values().iterator();
+        while (loadedClasses.hasNext()) {
+            ResourceEntry entry = (ResourceEntry) loadedClasses.next();
+            if (entry.loadedClass != null) {
+                Class clazz = entry.loadedClass;
+                try {
+                    Field[] fields = clazz.getDeclaredFields();
+                    for (int i = 0; i < fields.length; i++) {
+                        Field field = fields[i];
+                        int mods = field.getModifiers();
+                        if (field.getType().isPrimitive() 
+                                || (field.getName().indexOf("$") != -1)) {
+                            continue;
+                        }
+                        if (Modifier.isStatic(mods)) {
+                            try {
+                                field.setAccessible(true);
+                                if (Modifier.isFinal(mods)) {
+                                    if (!((field.getType().getName().startsWith("java."))
+                                            || (field.getType().getName().startsWith("javax.")))) {
+                                        nullInstance(field.get(null));
+                                    }
+                                } else {
+                                    field.set(null, null);
+                                    if (log.isDebugEnabled()) {
+                                        log.debug("Set field " + field.getName() 
+                                                + " to null in class " + clazz.getName());
+                                    }
+                                }
+                            } catch (Throwable t) {
+                                if (log.isDebugEnabled()) {
+                                    log.debug("Could not set field " + field.getName() 
+                                            + " to null in class " + clazz.getName(), t);
+                                }
+                            }
+                        }
+                    }
+                } catch (Throwable t) {
+                    if (log.isDebugEnabled()) {
+                        log.debug("Could not clean fields for class " + clazz.getName(), t);
+                    }
+                }
+            }
+        }
+        
+         // Clear the IntrospectionUtils cache.
+        IntrospectionUtils.clear();
+        
+        // Clear the classloader reference in common-logging
+        org.apache.commons.logging.LogFactory.release(this);
+        
+        // Clear the classloader reference in the VM's bean introspector
+        java.beans.Introspector.flushCaches();
+
+    }
+
+
+    protected void nullInstance(Object instance) {
+        if (instance == null) {
+            return;
+        }
+        Field[] fields = instance.getClass().getDeclaredFields();
+        for (int i = 0; i < fields.length; i++) {
+            Field field = fields[i];
+            int mods = field.getModifiers();
+            if (field.getType().isPrimitive() 
+                    || (field.getName().indexOf("$") != -1)) {
+                continue;
+            }
+            try {
+                field.setAccessible(true);
+                if (Modifier.isStatic(mods) && Modifier.isFinal(mods)) {
+                    // Doing something recursively is too risky
+                    continue;
+                } else {
+                    Object value = field.get(instance);
+                    if (null != value) {
+                        Class valueClass = value.getClass();
+                        if (!loadedByThisOrChild(valueClass)) {
+                            if (log.isDebugEnabled()) {
+                                log.debug("Not setting field " + field.getName() +
+                                        " to null in object of class " + 
+                                        instance.getClass().getName() +
+                                        " because the referenced object was of type " +
+                                        valueClass.getName() + 
+                                        " which was not loaded by this WebappClassLoader.");
+                            }
+                        } else {
+                            field.set(instance, null);
+                            if (log.isDebugEnabled()) {
+                                log.debug("Set field " + field.getName() 
+                                        + " to null in class " + instance.getClass().getName());
+                            }
+                        }
+                    }
+                }
+            } catch (Throwable t) {
+                if (log.isDebugEnabled()) {
+                    log.debug("Could not set field " + field.getName() 
+                            + " to null in object instance of class " 
+                            + instance.getClass().getName(), t);
+                }
+            }
+        }
+    }
+
+
+    /**
+     * Determine whether a class was loaded by this class loader or one of
+     * its child class loaders.
+     */
+    protected boolean loadedByThisOrChild(Class clazz)
+    {
+        boolean result = false;
+        for (ClassLoader classLoader = clazz.getClassLoader();
+                null != classLoader; classLoader = classLoader.getParent()) {
+            if (classLoader.equals(this)) {
+                result = true;
+                break;
+            }
+        }
+        return result;
+    }    
+
+
+    /**
+     * Used to periodically signal to the classloader to release JAR resources.
+     */
+    protected boolean openJARs() {
+        if (started && (jarFiles.length > 0)) {
+            lastJarAccessed = System.currentTimeMillis();
+            if (jarFiles[0] == null) {
+                for (int i = 0; i < jarFiles.length; i++) {
+                    try {
+                        jarFiles[i] = new JarFile(jarRealFiles[i]);
+                    } catch (IOException e) {
+                        if (log.isDebugEnabled()) {
+                            log.debug("Failed to open JAR", e);
+                        }
+                        return false;
+                    }
+                }
+            }
+        }
+        return true;
+    }
+
+
+    /**
+     * Find specified class in local repositories.
+     *
+     * @return the loaded class, or null if the class isn't found
+     */
+    protected Class findClassInternal(String name)
+        throws ClassNotFoundException {
+
+        if (!validate(name))
+            throw new ClassNotFoundException(name);
+
+        String tempPath = name.replace('.', '/');
+        String classPath = tempPath + ".class";
+
+        ResourceEntry entry = null;
+
+        entry = findResourceInternal(name, classPath);
+
+        if (entry == null)
+            throw new ClassNotFoundException(name);
+
+        Class clazz = entry.loadedClass;
+        if (clazz != null)
+            return clazz;
+
+        synchronized (this) {
+            if (entry.binaryContent == null && entry.loadedClass == null)
+                throw new ClassNotFoundException(name);
+        }
+
+        // Looking up the package
+        String packageName = null;
+        int pos = name.lastIndexOf('.');
+        if (pos != -1)
+            packageName = name.substring(0, pos);
+
+        Package pkg = null;
+
+        if (packageName != null) {
+
+            pkg = getPackage(packageName);
+
+            // Define the package (if null)
+            if (pkg == null) {
+                if (entry.manifest == null) {
+                    definePackage(packageName, null, null, null, null, null,
+                                  null, null);
+                } else {
+                    definePackage(packageName, entry.manifest, entry.codeBase);
+                }
+            }
+
+        }
+
+        // Create the code source object
+        CodeSource codeSource =
+            new CodeSource(entry.codeBase, entry.certificates);
+
+        if (securityManager != null) {
+
+            // Checking sealing
+            if (pkg != null) {
+                boolean sealCheck = true;
+                if (pkg.isSealed()) {
+                    sealCheck = pkg.isSealed(entry.codeBase);
+                } else {
+                    sealCheck = (entry.manifest == null)
+                        || !isPackageSealed(packageName, entry.manifest);
+                }
+                if (!sealCheck)
+                    throw new SecurityException
+                        ("Sealing violation loading " + name + " : Package "
+                         + packageName + " is sealed.");
+            }
+
+        }
+
+        synchronized (this) {
+            if (entry.loadedClass == null) {
+                clazz = defineClass(name, entry.binaryContent, 0,
+                        entry.binaryContent.length, 
+                        codeSource);
+                entry.loadedClass = clazz;
+                entry.binaryContent = null;
+                entry.source = null;
+                entry.codeBase = null;
+                entry.manifest = null;
+                entry.certificates = null;
+            } else {
+                clazz = entry.loadedClass;
+            }
+        }
+        
+        return clazz;
+
+    }
+
+    /**
+     * Find specified resource in local repositories. This block
+     * will execute under an AccessControl.doPrivilege block.
+     *
+     * @return the loaded resource, or null if the resource isn't found
+     */
+    protected ResourceEntry findResourceInternal(File file, String path){
+        ResourceEntry entry = new ResourceEntry();
+        try {
+            entry.source = getURI(new File(file, path));
+            entry.codeBase = getURL(new File(file, path), false);
+        } catch (MalformedURLException e) {
+            return null;
+        }   
+        return entry;
+    }
+    
+
+    /**
+     * Find specified resource in local repositories.
+     *
+     * @return the loaded resource, or null if the resource isn't found
+     */
+    protected ResourceEntry findResourceInternal(String name, String path) {
+
+        if (!started) {
+            log.info(sm.getString("webappClassLoader.stopped", name));
+            return null;
+        }
+
+        if ((name == null) || (path == null))
+            return null;
+
+        ResourceEntry entry = (ResourceEntry) resourceEntries.get(name);
+        if (entry != null)
+            return entry;
+
+        int contentLength = -1;
+        InputStream binaryStream = null;
+
+        int jarFilesLength = jarFiles.length;
+        int repositoriesLength = repositories.length;
+
+        int i;
+
+        Resource resource = null;
+
+        boolean fileNeedConvert = false;
+
+        for (i = 0; (entry == null) && (i < repositoriesLength); i++) {
+            try {
+
+                String fullPath = repositories[i] + path;
+
+                Object lookupResult = resources.lookup(fullPath);
+                if (lookupResult instanceof Resource) {
+                    resource = (Resource) lookupResult;
+                }
+
+                // Note : Not getting an exception here means the resource was
+                // found
+                 if (securityManager != null) {
+                    PrivilegedAction dp =
+                        new PrivilegedFindResource(files[i], path);
+                    entry = (ResourceEntry)AccessController.doPrivileged(dp);
+                 } else {
+                    entry = findResourceInternal(files[i], path);
+                 }
+
+                ResourceAttributes attributes =
+                    (ResourceAttributes) resources.getAttributes(fullPath);
+                contentLength = (int) attributes.getContentLength();
+                entry.lastModified = attributes.getLastModified();
+
+                if (resource != null) {
+
+
+                    try {
+                        binaryStream = resource.streamContent();
+                    } catch (IOException e) {
+                        return null;
+                    }
+
+                    if (needConvert) {
+                        if (path.endsWith(".properties")) {
+                            fileNeedConvert = true;
+                        }
+                    }
+
+                    // Register the full path for modification checking
+                    // Note: Only syncing on a 'constant' object is needed
+                    synchronized (allPermission) {
+
+                        int j;
+
+                        long[] result2 = 
+                            new long[lastModifiedDates.length + 1];
+                        for (j = 0; j < lastModifiedDates.length; j++) {
+                            result2[j] = lastModifiedDates[j];
+                        }
+                        result2[lastModifiedDates.length] = entry.lastModified;
+                        lastModifiedDates = result2;
+
+                        String[] result = new String[paths.length + 1];
+                        for (j = 0; j < paths.length; j++) {
+                            result[j] = paths[j];
+                        }
+                        result[paths.length] = fullPath;
+                        paths = result;
+
+                    }
+
+                }
+
+            } catch (NamingException e) {
+            }
+        }
+
+        if ((entry == null) && (notFoundResources.containsKey(name)))
+            return null;
+
+        JarEntry jarEntry = null;
+
+        synchronized (jarFiles) {
+
+            if (!openJARs()) {
+                return null;
+            }
+            for (i = 0; (entry == null) && (i < jarFilesLength); i++) {
+
+                jarEntry = jarFiles[i].getJarEntry(path);
+
+                if (jarEntry != null) {
+
+                    entry = new ResourceEntry();
+                    try {
+                        entry.codeBase = getURL(jarRealFiles[i], false);
+                        String jarFakeUrl = getURI(jarRealFiles[i]).toString();
+                        jarFakeUrl = "jar:" + jarFakeUrl + "!/" + path;
+                        entry.source = new URL(jarFakeUrl);
+                        entry.lastModified = jarRealFiles[i].lastModified();
+                    } catch (MalformedURLException e) {
+                        return null;
+                    }
+                    contentLength = (int) jarEntry.getSize();
+                    try {
+                        entry.manifest = jarFiles[i].getManifest();
+                        binaryStream = jarFiles[i].getInputStream(jarEntry);
+                    } catch (IOException e) {
+                        return null;
+                    }
+
+                    // Extract resources contained in JAR to the workdir
+                    if (antiJARLocking && !(path.endsWith(".class"))) {
+                        byte[] buf = new byte[1024];
+                        File resourceFile = new File
+                            (loaderDir, jarEntry.getName());
+                        if (!resourceFile.exists()) {
+                            Enumeration entries = jarFiles[i].entries();
+                            while (entries.hasMoreElements()) {
+                                JarEntry jarEntry2 = 
+                                    (JarEntry) entries.nextElement();
+                                if (!(jarEntry2.isDirectory()) 
+                                    && (!jarEntry2.getName().endsWith
+                                        (".class"))) {
+                                    resourceFile = new File
+                                        (loaderDir, jarEntry2.getName());
+                                    resourceFile.getParentFile().mkdirs();
+                                    FileOutputStream os = null;
+                                    InputStream is = null;
+                                    try {
+                                        is = jarFiles[i].getInputStream
+                                            (jarEntry2);
+                                        os = new FileOutputStream
+                                            (resourceFile);
+                                        while (true) {
+                                            int n = is.read(buf);
+                                            if (n <= 0) {
+                                                break;
+                                            }
+                                            os.write(buf, 0, n);
+                                        }
+                                    } catch (IOException e) {
+                                        // Ignore
+                                    } finally {
+                                        try {
+                                            if (is != null) {
+                                                is.close();
+                                            }
+                                        } catch (IOException e) {
+                                        }
+                                        try {
+                                            if (os != null) {
+                                                os.close();
+                                            }
+                                        } catch (IOException e) {
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                    }
+
+                }
+
+            }
+
+            if (entry == null) {
+                synchronized (notFoundResources) {
+                    notFoundResources.put(name, name);
+                }
+                return null;
+            }
+
+            if (binaryStream != null) {
+
+                byte[] binaryContent = new byte[contentLength];
+
+                int pos = 0;
+                try {
+
+                    while (true) {
+                        int n = binaryStream.read(binaryContent, pos,
+                                                  binaryContent.length - pos);
+                        if (n <= 0)
+                            break;
+                        pos += n;
+                    }
+                    binaryStream.close();
+                } catch (IOException e) {
+                    e.printStackTrace();
+                    return null;
+                } catch (Exception e) {
+                    e.printStackTrace();
+                    return null;
+                }
+
+                if (fileNeedConvert) {
+                    String str = new String(binaryContent,0,pos);
+                    try {
+                        binaryContent = str.getBytes("UTF-8");
+                    } catch (Exception e) {
+                        return null;
+                    }
+                }
+                entry.binaryContent = binaryContent;
+
+                // The certificates are only available after the JarEntry 
+                // associated input stream has been fully read
+                if (jarEntry != null) {
+                    entry.certificates = jarEntry.getCertificates();
+                }
+
+            }
+
+        }
+
+        // Add the entry in the local resource repository
+        synchronized (resourceEntries) {
+            // Ensures that all the threads which may be in a race to load
+            // a particular class all end up with the same ResourceEntry
+            // instance
+            ResourceEntry entry2 = (ResourceEntry) resourceEntries.get(name);
+            if (entry2 == null) {
+                resourceEntries.put(name, entry);
+            } else {
+                entry = entry2;
+            }
+        }
+
+        return entry;
+
+    }
+
+
+    /**
+     * Returns true if the specified package name is sealed according to the
+     * given manifest.
+     */
+    protected boolean isPackageSealed(String name, Manifest man) {
+
+        String path = name.replace('.', '/') + '/';
+        Attributes attr = man.getAttributes(path); 
+        String sealed = null;
+        if (attr != null) {
+            sealed = attr.getValue(Name.SEALED);
+        }
+        if (sealed == null) {
+            if ((attr = man.getMainAttributes()) != null) {
+                sealed = attr.getValue(Name.SEALED);
+            }
+        }
+        return "true".equalsIgnoreCase(sealed);
+
+    }
+
+
+    /**
+     * Finds the resource with the given name if it has previously been
+     * loaded and cached by this class loader, and return an input stream
+     * to the resource data.  If this resource has not been cached, return
+     * <code>null</code>.
+     *
+     * @param name Name of the resource to return
+     */
+    protected InputStream findLoadedResource(String name) {
+
+        ResourceEntry entry = (ResourceEntry) resourceEntries.get(name);
+        if (entry != null) {
+            if (entry.binaryContent != null)
+                return new ByteArrayInputStream(entry.binaryContent);
+        }
+        return (null);
+
+    }
+
+
+    /**
+     * Finds the class with the given name if it has previously been
+     * loaded and cached by this class loader, and return the Class object.
+     * If this class has not been cached, return <code>null</code>.
+     *
+     * @param name Name of the resource to return
+     */
+    protected Class findLoadedClass0(String name) {
+
+        ResourceEntry entry = (ResourceEntry) resourceEntries.get(name);
+        if (entry != null) {
+            return entry.loadedClass;
+        }
+        return (null);  // FIXME - findLoadedResource()
+
+    }
+
+
+    /**
+     * Refresh the system policy file, to pick up eventual changes.
+     */
+    protected void refreshPolicy() {
+
+        try {
+            // The policy file may have been modified to adjust 
+            // permissions, so we're reloading it when loading or 
+            // reloading a Context
+            Policy policy = Policy.getPolicy();
+            policy.refresh();
+        } catch (AccessControlException e) {
+            // Some policy files may restrict this, even for the core,
+            // so this exception is ignored
+        }
+
+    }
+
+
+    /**
+     * Filter classes.
+     * 
+     * @param name class name
+     * @return true if the class should be filtered
+     */
+    protected boolean filter(String name) {
+
+        if (name == null)
+            return false;
+
+        // Looking up the package
+        String packageName = null;
+        int pos = name.lastIndexOf('.');
+        if (pos != -1)
+            packageName = name.substring(0, pos);
+        else
+            return false;
+
+        for (int i = 0; i < packageTriggers.length; i++) {
+            if (packageName.startsWith(packageTriggers[i]))
+                return true;
+        }
+
+        return false;
+
+    }
+
+
+    /**
+     * Validate a classname. As per SRV.9.7.2, we must restict loading of 
+     * classes from J2SE (java.*) and classes of the servlet API 
+     * (javax.servlet.*). That should enhance robustness and prevent a number
+     * of user error (where an older version of servlet.jar would be present
+     * in /WEB-INF/lib).
+     * 
+     * @param name class name
+     * @return true if the name is valid
+     */
+    protected boolean validate(String name) {
+
+        if (name == null)
+            return false;
+        if (name.startsWith("java."))
+            return false;
+
+        return true;
+
+    }
+
+
+    /**
+     * Check the specified JAR file, and return <code>true</code> if it does
+     * not contain any of the trigger classes.
+     *
+     * @param jarfile The JAR file to be checked
+     *
+     * @exception IOException if an input/output error occurs
+     */
+    protected boolean validateJarFile(File jarfile)
+        throws IOException {
+
+        if (triggers == null)
+            return (true);
+        JarFile jarFile = new JarFile(jarfile);
+        for (int i = 0; i < triggers.length; i++) {
+            Class clazz = null;
+            try {
+                if (parent != null) {
+                    clazz = parent.loadClass(triggers[i]);
+                } else {
+                    clazz = Class.forName(triggers[i]);
+                }
+            } catch (Throwable t) {
+                clazz = null;
+            }
+            if (clazz == null)
+                continue;
+            String name = triggers[i].replace('.', '/') + ".class";
+            if (log.isDebugEnabled())
+                log.debug(" Checking for " + name);
+            JarEntry jarEntry = jarFile.getJarEntry(name);
+            if (jarEntry != null) {
+                log.info("validateJarFile(" + jarfile + 
+                    ") - jar not loaded. See Servlet Spec 2.3, "
+                    + "section 9.7.2. Offending class: " + name);
+                jarFile.close();
+                return (false);
+            }
+        }
+        jarFile.close();
+        return (true);
+
+    }
+
+
+    /**
+     * Get URL.
+     */
+    protected URL getURL(File file, boolean encoded)
+        throws MalformedURLException {
+
+        File realFile = file;
+        try {
+            realFile = realFile.getCanonicalFile();
+        } catch (IOException e) {
+            // Ignore
+        }
+        if(encoded) {
+            return getURI(realFile);
+        } else {
+            return realFile.toURL();
+        }
+
+    }
+
+
+    /**
+     * Get URL.
+     */
+    protected URL getURI(File file)
+        throws MalformedURLException {
+
+        return file.toURI().toURL();
+
+    }
+
+
+    /**
+     * Delete the specified directory, including all of its contents and
+     * subdirectories recursively.
+     *
+     * @param dir File object representing the directory to be deleted
+     */
+    protected static void deleteDir(File dir) {
+
+        String files[] = dir.list();
+        if (files == null) {
+            files = new String[0];
+        }
+        for (int i = 0; i < files.length; i++) {
+            File file = new File(dir, files[i]);
+            if (file.isDirectory()) {
+                deleteDir(file);
+            } else {
+                file.delete();
+            }
+        }
+        dir.delete();
+
+    }
+
+
+}
+

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/loader/WebappLoader.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/loader/WebappLoader.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/loader/WebappLoader.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,1261 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.loader;
+
+
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+import java.beans.PropertyChangeSupport;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.FilePermission;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.net.URLStreamHandlerFactory;
+import java.util.ArrayList;
+import java.util.jar.JarFile;
+
+import javax.management.MBeanRegistration;
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+import javax.naming.Binding;
+import javax.naming.NameClassPair;
+import javax.naming.NamingEnumeration;
+import javax.naming.NamingException;
+import javax.naming.directory.DirContext;
+import javax.servlet.ServletContext;
+
+import org.apache.catalina.Container;
+import org.apache.catalina.Context;
+import org.apache.catalina.Engine;
+import org.apache.catalina.Globals;
+import org.apache.catalina.Lifecycle;
+import org.apache.catalina.LifecycleException;
+import org.apache.catalina.LifecycleListener;
+import org.apache.catalina.Loader;
+import org.apache.catalina.core.StandardContext;
+import org.apache.catalina.util.LifecycleSupport;
+import org.apache.catalina.util.StringManager;
+import org.apache.commons.modeler.Registry;
+import org.apache.naming.resources.DirContextURLStreamHandler;
+import org.apache.naming.resources.DirContextURLStreamHandlerFactory;
+import org.apache.naming.resources.Resource;
+
+
+/**
+ * Classloader implementation which is specialized for handling web
+ * applications in the most efficient way, while being Catalina aware (all
+ * accesses to resources are made through the DirContext interface).
+ * This class loader supports detection of modified
+ * Java classes, which can be used to implement auto-reload support.
+ * <p>
+ * This class loader is configured by adding the pathnames of directories,
+ * JAR files, and ZIP files with the <code>addRepository()</code> method,
+ * prior to calling <code>start()</code>.  When a new class is required,
+ * these repositories will be consulted first to locate the class.  If it
+ * is not present, the system class loader will be used instead.
+ *
+ * @author Craig R. McClanahan
+ * @author Remy Maucherat
+ * @version $Revision: 440936 $ $Date: 2006-09-06 20:51:28 -0500 (Wed, 06 Sep 2006) $
+ */
+
+public class WebappLoader
+    implements Lifecycle, Loader, PropertyChangeListener, MBeanRegistration  {
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Construct a new WebappLoader with no defined parent class loader
+     * (so that the actual parent will be the system class loader).
+     */
+    public WebappLoader() {
+
+        this(null);
+
+    }
+
+
+    /**
+     * Construct a new WebappLoader with the specified class loader
+     * to be defined as the parent of the ClassLoader we ultimately create.
+     *
+     * @param parent The parent class loader
+     */
+    public WebappLoader(ClassLoader parent) {
+        super();
+        this.parentClassLoader = parent;
+    }
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * First load of the class.
+     */
+    private static boolean first = true;
+
+
+    /**
+     * The class loader being managed by this Loader component.
+     */
+    private WebappClassLoader classLoader = null;
+
+
+    /**
+     * The Container with which this Loader has been associated.
+     */
+    private Container container = null;
+
+
+    /**
+     * The "follow standard delegation model" flag that will be used to
+     * configure our ClassLoader.
+     */
+    private boolean delegate = false;
+
+
+    /**
+     * The descriptive information about this Loader implementation.
+     */
+    private static final String info =
+        "org.apache.catalina.loader.WebappLoader/1.0";
+
+
+    /**
+     * The lifecycle event support for this component.
+     */
+    protected LifecycleSupport lifecycle = new LifecycleSupport(this);
+
+
+    /**
+     * If not specified, should the system class loader be used as the parent.
+     */
+    private boolean useSystemClassLoaderAsParent = true;
+
+
+    /**
+     * The Java class name of the ClassLoader implementation to be used.
+     * This class should extend WebappClassLoader, otherwise, a different 
+     * loader implementation must be used.
+     */
+    private String loaderClass =
+        "org.apache.catalina.loader.WebappClassLoader";
+
+
+    /**
+     * The parent class loader of the class loader we will create.
+     */
+    private ClassLoader parentClassLoader = null;
+
+
+    /**
+     * The reloadable flag for this Loader.
+     */
+    private boolean reloadable = false;
+
+
+    /**
+     * The set of repositories associated with this class loader.
+     */
+    private String repositories[] = new String[0];
+
+
+    /**
+     * The string manager for this package.
+     */
+    protected static final StringManager sm =
+        StringManager.getManager(Constants.Package);
+
+
+    /**
+     * Has this component been started?
+     */
+    private boolean started = false;
+
+
+    /**
+     * The property change support for this component.
+     */
+    protected PropertyChangeSupport support = new PropertyChangeSupport(this);
+
+
+    /**
+     * Classpath set in the loader.
+     */
+    private String classpath = null;
+
+
+    /**
+     * Repositories that are set in the loader, for JMX.
+     */
+    private ArrayList loaderRepositories = null;
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * Return the Java class loader to be used by this Container.
+     */
+    public ClassLoader getClassLoader() {
+
+        return ((ClassLoader) classLoader);
+
+    }
+
+
+    /**
+     * Return the Container with which this Logger has been associated.
+     */
+    public Container getContainer() {
+
+        return (container);
+
+    }
+
+
+    /**
+     * Set the Container with which this Logger has been associated.
+     *
+     * @param container The associated Container
+     */
+    public void setContainer(Container container) {
+
+        // Deregister from the old Container (if any)
+        if ((this.container != null) && (this.container instanceof Context))
+            ((Context) this.container).removePropertyChangeListener(this);
+
+        // Process this property change
+        Container oldContainer = this.container;
+        this.container = container;
+        support.firePropertyChange("container", oldContainer, this.container);
+
+        // Register with the new Container (if any)
+        if ((this.container != null) && (this.container instanceof Context)) {
+            setReloadable( ((Context) this.container).getReloadable() );
+            ((Context) this.container).addPropertyChangeListener(this);
+        }
+
+    }
+
+
+    /**
+     * Return the "follow standard delegation model" flag used to configure
+     * our ClassLoader.
+     */
+    public boolean getDelegate() {
+
+        return (this.delegate);
+
+    }
+
+
+    /**
+     * Set the "follow standard delegation model" flag used to configure
+     * our ClassLoader.
+     *
+     * @param delegate The new flag
+     */
+    public void setDelegate(boolean delegate) {
+
+        boolean oldDelegate = this.delegate;
+        this.delegate = delegate;
+        support.firePropertyChange("delegate", new Boolean(oldDelegate),
+                                   new Boolean(this.delegate));
+
+    }
+
+
+    /**
+     * Return descriptive information about this Loader implementation and
+     * the corresponding version number, in the format
+     * <code>&lt;description&gt;/&lt;version&gt;</code>.
+     */
+    public String getInfo() {
+
+        return (info);
+
+    }
+
+
+    /**
+     * Return the ClassLoader class name.
+     */
+    public String getLoaderClass() {
+
+        return (this.loaderClass);
+
+    }
+
+
+    /**
+     * Set the ClassLoader class name.
+     *
+     * @param loaderClass The new ClassLoader class name
+     */
+    public void setLoaderClass(String loaderClass) {
+
+        this.loaderClass = loaderClass;
+
+    }
+
+
+    /**
+     * Return the useSystemClassLoaderAsParent flag for this Loader.
+     */
+    public boolean getUseSystemClassLoaderAsParent() {
+        
+        return (this.useSystemClassLoaderAsParent);
+        
+    }
+    
+    /**
+     * Set the useSystemClassLoaderAsParent flag for this Loader.
+     * 
+     * @param useSystemClassLoaderAsParent The useSystemClassLoaderAsParent
+     *                                     flag.
+     */
+    public void setUseSystemClassLoaderAsParent(
+            boolean useSystemClassLoaderAsParent) {
+        
+        this.useSystemClassLoaderAsParent = useSystemClassLoaderAsParent;
+        
+    }
+    
+    
+    /**
+     * Return the reloadable flag for this Loader.
+     */
+    public boolean getReloadable() {
+
+        return (this.reloadable);
+
+    }
+
+
+    /**
+     * Set the reloadable flag for this Loader.
+     *
+     * @param reloadable The new reloadable flag
+     */
+    public void setReloadable(boolean reloadable) {
+
+        // Process this property change
+        boolean oldReloadable = this.reloadable;
+        this.reloadable = reloadable;
+        support.firePropertyChange("reloadable",
+                                   new Boolean(oldReloadable),
+                                   new Boolean(this.reloadable));
+
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Add a property change listener to this component.
+     *
+     * @param listener The listener to add
+     */
+    public void addPropertyChangeListener(PropertyChangeListener listener) {
+
+        support.addPropertyChangeListener(listener);
+
+    }
+
+
+    /**
+     * Add a new repository to the set of repositories for this class loader.
+     *
+     * @param repository Repository to be added
+     */
+    public void addRepository(String repository) {
+
+        if (log.isDebugEnabled())
+            log.debug(sm.getString("webappLoader.addRepository", repository));
+
+        for (int i = 0; i < repositories.length; i++) {
+            if (repository.equals(repositories[i]))
+                return;
+        }
+        String results[] = new String[repositories.length + 1];
+        for (int i = 0; i < repositories.length; i++)
+            results[i] = repositories[i];
+        results[repositories.length] = repository;
+        repositories = results;
+
+        if (started && (classLoader != null)) {
+            classLoader.addRepository(repository);
+            if( loaderRepositories != null ) loaderRepositories.add(repository);
+            setClassPath();
+        }
+
+    }
+
+
+    /**
+     * Execute a periodic task, such as reloading, etc. This method will be
+     * invoked inside the classloading context of this container. Unexpected
+     * throwables will be caught and logged.
+     */
+    public void backgroundProcess() {
+        if (reloadable && modified()) {
+            try {
+                Thread.currentThread().setContextClassLoader
+                    (WebappLoader.class.getClassLoader());
+                if (container instanceof StandardContext) {
+                    ((StandardContext) container).reload();
+                }
+            } finally {
+                if (container.getLoader() != null) {
+                    Thread.currentThread().setContextClassLoader
+                        (container.getLoader().getClassLoader());
+                }
+            }
+        } else {
+            closeJARs(false);
+        }
+    }
+
+
+    /**
+     * Return the set of repositories defined for this class loader.
+     * If none are defined, a zero-length array is returned.
+     * For security reason, returns a clone of the Array (since 
+     * String are immutable).
+     */
+    public String[] findRepositories() {
+
+        return ((String[])repositories.clone());
+
+    }
+
+    public String[] getRepositories() {
+        return ((String[])repositories.clone());
+    }
+
+    /** Extra repositories for this loader
+     */
+    public String getRepositoriesString() {
+        StringBuffer sb=new StringBuffer();
+        for( int i=0; i<repositories.length ; i++ ) {
+            sb.append( repositories[i]).append(":");
+        }
+        return sb.toString();
+    }
+
+    public String[] getLoaderRepositories() {
+        if( loaderRepositories==null ) return  null;
+        String res[]=new String[ loaderRepositories.size()];
+        loaderRepositories.toArray(res);
+        return res;
+    }
+
+    public String getLoaderRepositoriesString() {
+        String repositories[]=getLoaderRepositories();
+        StringBuffer sb=new StringBuffer();
+        for( int i=0; i<repositories.length ; i++ ) {
+            sb.append( repositories[i]).append(":");
+        }
+        return sb.toString();
+    }
+
+
+    /** 
+     * Classpath, as set in org.apache.catalina.jsp_classpath context
+     * property
+     *
+     * @return The classpath
+     */
+    public String getClasspath() {
+        return classpath;
+    }
+
+
+    /**
+     * Has the internal repository associated with this Loader been modified,
+     * such that the loaded classes should be reloaded?
+     */
+    public boolean modified() {
+
+        return (classLoader.modified());
+
+    }
+
+
+    /**
+     * Used to periodically signal to the classloader to release JAR resources.
+     */
+    public void closeJARs(boolean force) {
+        if (classLoader !=null){
+            classLoader.closeJARs(force);
+        }
+    }
+
+
+    /**
+     * Remove a property change listener from this component.
+     *
+     * @param listener The listener to remove
+     */
+    public void removePropertyChangeListener(PropertyChangeListener listener) {
+
+        support.removePropertyChangeListener(listener);
+
+    }
+
+
+    /**
+     * Return a String representation of this component.
+     */
+    public String toString() {
+
+        StringBuffer sb = new StringBuffer("WebappLoader[");
+        if (container != null)
+            sb.append(container.getName());
+        sb.append("]");
+        return (sb.toString());
+
+    }
+
+
+    // ------------------------------------------------------ Lifecycle Methods
+
+
+    /**
+     * Add a lifecycle event listener to this component.
+     *
+     * @param listener The listener to add
+     */
+    public void addLifecycleListener(LifecycleListener listener) {
+
+        lifecycle.addLifecycleListener(listener);
+
+    }
+
+
+    /**
+     * Get the lifecycle listeners associated with this lifecycle. If this 
+     * Lifecycle has no listeners registered, a zero-length array is returned.
+     */
+    public LifecycleListener[] findLifecycleListeners() {
+
+        return lifecycle.findLifecycleListeners();
+
+    }
+
+
+    /**
+     * Remove a lifecycle event listener from this component.
+     *
+     * @param listener The listener to remove
+     */
+    public void removeLifecycleListener(LifecycleListener listener) {
+
+        lifecycle.removeLifecycleListener(listener);
+
+    }
+
+    private boolean initialized=false;
+
+
+    public void init() {
+        initialized=true;
+
+        if( oname==null ) {
+            // not registered yet - standalone or API
+            if( container instanceof StandardContext) {
+                // Register ourself. The container must be a webapp
+                try {
+                    StandardContext ctx=(StandardContext)container;
+                    Engine eng=(Engine)ctx.getParent().getParent();
+                    String path = ctx.getPath();
+                    if (path.equals("")) {
+                        path = "/";
+                    }   
+                    oname=new ObjectName(ctx.getEngineName() + ":type=Loader,path=" +
+                                path + ",host=" + ctx.getParent().getName());
+                    Registry.getRegistry(null, null).registerComponent(this, oname, null);
+                    controller=oname;
+                } catch (Exception e) {
+                    log.error("Error registering loader", e );
+                }
+            }
+        }
+
+        if( container == null ) {
+            // JMX created the loader
+            // TODO
+
+        }
+    }
+
+    public void destroy() {
+        if( controller==oname ) {
+            // Self-registration, undo it
+            Registry.getRegistry(null, null).unregisterComponent(oname);
+            oname = null;
+        }
+        initialized = false;
+
+    }
+
+    /**
+     * Start this component, initializing our associated class loader.
+     *
+     * @exception LifecycleException if a lifecycle error occurs
+     */
+    public void start() throws LifecycleException {
+        // Validate and update our current component state
+        if( ! initialized ) init();
+        if (started)
+            throw new LifecycleException
+                (sm.getString("webappLoader.alreadyStarted"));
+        if (log.isDebugEnabled())
+            log.debug(sm.getString("webappLoader.starting"));
+        lifecycle.fireLifecycleEvent(START_EVENT, null);
+        started = true;
+
+        if (container.getResources() == null) {
+            log.info("No resources for " + container);
+            return;
+        }
+        // Register a stream handler factory for the JNDI protocol
+        URLStreamHandlerFactory streamHandlerFactory =
+            new DirContextURLStreamHandlerFactory();
+        if (first) {
+            first = false;
+            try {
+                URL.setURLStreamHandlerFactory(streamHandlerFactory);
+            } catch (Exception e) {
+                // Log and continue anyway, this is not critical
+                log.error("Error registering jndi stream handler", e);
+            } catch (Throwable t) {
+                // This is likely a dual registration
+                log.info("Dual registration of jndi stream handler: " 
+                         + t.getMessage());
+            }
+        }
+
+        // Construct a class loader based on our current repositories list
+        try {
+
+            classLoader = createClassLoader();
+            classLoader.setResources(container.getResources());
+            classLoader.setDelegate(this.delegate);
+            if (container instanceof StandardContext)
+                classLoader.setAntiJARLocking(((StandardContext) container).getAntiJARLocking());
+
+            for (int i = 0; i < repositories.length; i++) {
+                classLoader.addRepository(repositories[i]);
+            }
+
+            // Configure our repositories
+            setRepositories();
+            setClassPath();
+
+            setPermissions();
+
+            if (classLoader instanceof Lifecycle)
+                ((Lifecycle) classLoader).start();
+
+            // Binding the Webapp class loader to the directory context
+            DirContextURLStreamHandler.bind
+                ((ClassLoader) classLoader, this.container.getResources());
+
+            StandardContext ctx=(StandardContext)container;
+            Engine eng=(Engine)ctx.getParent().getParent();
+            String path = ctx.getPath();
+            if (path.equals("")) {
+                path = "/";
+            }   
+            ObjectName cloname = new ObjectName
+                (ctx.getEngineName() + ":type=WebappClassLoader,path="
+                 + path + ",host=" + ctx.getParent().getName());
+            Registry.getRegistry(null, null)
+                .registerComponent(classLoader, cloname, null);
+
+        } catch (Throwable t) {
+            log.error( "LifecycleException ", t );
+            throw new LifecycleException("start: ", t);
+        }
+
+    }
+
+
+    /**
+     * Stop this component, finalizing our associated class loader.
+     *
+     * @exception LifecycleException if a lifecycle error occurs
+     */
+    public void stop() throws LifecycleException {
+
+        // Validate and update our current component state
+        if (!started)
+            throw new LifecycleException
+                (sm.getString("webappLoader.notStarted"));
+        if (log.isDebugEnabled())
+            log.debug(sm.getString("webappLoader.stopping"));
+        lifecycle.fireLifecycleEvent(STOP_EVENT, null);
+        started = false;
+
+        // Remove context attributes as appropriate
+        if (container instanceof Context) {
+            ServletContext servletContext =
+                ((Context) container).getServletContext();
+            servletContext.removeAttribute(Globals.CLASS_PATH_ATTR);
+        }
+
+        // Throw away our current class loader
+        if (classLoader instanceof Lifecycle)
+            ((Lifecycle) classLoader).stop();
+        DirContextURLStreamHandler.unbind((ClassLoader) classLoader);
+
+        try {
+            StandardContext ctx=(StandardContext)container;
+            Engine eng=(Engine)ctx.getParent().getParent();
+            String path = ctx.getPath();
+            if (path.equals("")) {
+                path = "/";
+            }
+            ObjectName cloname = new ObjectName
+                (ctx.getEngineName() + ":type=WebappClassLoader,path="
+                 + path + ",host=" + ctx.getParent().getName());
+            Registry.getRegistry(null, null).unregisterComponent(cloname);
+        } catch (Throwable t) {
+            log.error( "LifecycleException ", t );
+        }
+
+        classLoader = null;
+
+        destroy();
+
+    }
+
+
+    // ----------------------------------------- PropertyChangeListener Methods
+
+
+    /**
+     * Process property change events from our associated Context.
+     *
+     * @param event The property change event that has occurred
+     */
+    public void propertyChange(PropertyChangeEvent event) {
+
+        // Validate the source of this event
+        if (!(event.getSource() instanceof Context))
+            return;
+        Context context = (Context) event.getSource();
+
+        // Process a relevant property change
+        if (event.getPropertyName().equals("reloadable")) {
+            try {
+                setReloadable
+                    ( ((Boolean) event.getNewValue()).booleanValue() );
+            } catch (NumberFormatException e) {
+                log.error(sm.getString("webappLoader.reloadable",
+                                 event.getNewValue().toString()));
+            }
+        }
+
+    }
+
+
+    // ------------------------------------------------------- Private Methods
+
+
+    /**
+     * Create associated classLoader.
+     */
+    private WebappClassLoader createClassLoader()
+        throws Exception {
+
+        Class clazz = Class.forName(loaderClass);
+        WebappClassLoader classLoader = null;
+
+        if (parentClassLoader == null) {
+            if (useSystemClassLoaderAsParent) {
+                parentClassLoader = ClassLoader.getSystemClassLoader();
+            } else {
+                parentClassLoader = container.getParentClassLoader();
+            }
+        }
+        Class[] argTypes = { ClassLoader.class };
+        Object[] args = { parentClassLoader };
+        Constructor constr = clazz.getConstructor(argTypes);
+        classLoader = (WebappClassLoader) constr.newInstance(args);
+
+        return classLoader;
+
+    }
+
+
+    /**
+     * Configure associated class loader permissions.
+     */
+    private void setPermissions() {
+
+        if (System.getSecurityManager() == null)
+            return;
+        if (!(container instanceof Context))
+            return;
+
+        // Tell the class loader the root of the context
+        ServletContext servletContext =
+            ((Context) container).getServletContext();
+
+        // Assigning permissions for the work directory
+        File workDir =
+            (File) servletContext.getAttribute(Globals.WORK_DIR_ATTR);
+        if (workDir != null) {
+            try {
+                String workDirPath = workDir.getCanonicalPath();
+                classLoader.addPermission
+                    (new FilePermission(workDirPath, "read,write"));
+                classLoader.addPermission
+                    (new FilePermission(workDirPath + File.separator + "-", 
+                                        "read,write,delete"));
+            } catch (IOException e) {
+                // Ignore
+            }
+        }
+
+        try {
+
+            URL rootURL = servletContext.getResource("/");
+            classLoader.addPermission(rootURL);
+
+            String contextRoot = servletContext.getRealPath("/");
+            if (contextRoot != null) {
+                try {
+                    contextRoot = (new File(contextRoot)).getCanonicalPath();
+                    classLoader.addPermission(contextRoot);
+                } catch (IOException e) {
+                    // Ignore
+                }
+            }
+
+            URL classesURL = servletContext.getResource("/WEB-INF/classes/");
+            classLoader.addPermission(classesURL);
+            URL libURL = servletContext.getResource("/WEB-INF/lib/");
+            classLoader.addPermission(libURL);
+
+            if (contextRoot != null) {
+
+                if (libURL != null) {
+                    File rootDir = new File(contextRoot);
+                    File libDir = new File(rootDir, "WEB-INF/lib/");
+                    try {
+                        String path = libDir.getCanonicalPath();
+                        classLoader.addPermission(path);
+                    } catch (IOException e) {
+                    }
+                }
+
+            } else {
+
+                if (workDir != null) {
+                    if (libURL != null) {
+                        File libDir = new File(workDir, "WEB-INF/lib/");
+                        try {
+                            String path = libDir.getCanonicalPath();
+                            classLoader.addPermission(path);
+                        } catch (IOException e) {
+                        }
+                    }
+                    if (classesURL != null) {
+                        File classesDir = new File(workDir, "WEB-INF/classes/");
+                        try {
+                            String path = classesDir.getCanonicalPath();
+                            classLoader.addPermission(path);
+                        } catch (IOException e) {
+                        }
+                    }
+                }
+
+            }
+
+        } catch (MalformedURLException e) {
+        }
+
+    }
+
+
+    /**
+     * Configure the repositories for our class loader, based on the
+     * associated Context.
+     */
+    private void setRepositories() {
+
+        if (!(container instanceof Context))
+            return;
+        ServletContext servletContext =
+            ((Context) container).getServletContext();
+        if (servletContext == null)
+            return;
+
+        loaderRepositories=new ArrayList();
+        // Loading the work directory
+        File workDir =
+            (File) servletContext.getAttribute(Globals.WORK_DIR_ATTR);
+        if (workDir == null) {
+            log.info("No work dir for " + servletContext);
+        }
+
+        if( log.isDebugEnabled()) 
+            log.debug(sm.getString("webappLoader.deploy", workDir.getAbsolutePath()));
+
+        classLoader.setWorkDir(workDir);
+
+        DirContext resources = container.getResources();
+
+        // Setting up the class repository (/WEB-INF/classes), if it exists
+
+        String classesPath = "/WEB-INF/classes";
+        DirContext classes = null;
+
+        try {
+            Object object = resources.lookup(classesPath);
+            if (object instanceof DirContext) {
+                classes = (DirContext) object;
+            }
+        } catch(NamingException e) {
+            // Silent catch: it's valid that no /WEB-INF/classes collection
+            // exists
+        }
+
+        if (classes != null) {
+
+            File classRepository = null;
+
+            String absoluteClassesPath =
+                servletContext.getRealPath(classesPath);
+
+            if (absoluteClassesPath != null) {
+
+                classRepository = new File(absoluteClassesPath);
+
+            } else {
+
+                classRepository = new File(workDir, classesPath);
+                classRepository.mkdirs();
+                copyDir(classes, classRepository);
+
+            }
+
+            if(log.isDebugEnabled())
+                log.debug(sm.getString("webappLoader.classDeploy", classesPath,
+                             classRepository.getAbsolutePath()));
+
+
+            // Adding the repository to the class loader
+            classLoader.addRepository(classesPath + "/", classRepository);
+            loaderRepositories.add(classesPath + "/" );
+
+        }
+
+        // Setting up the JAR repository (/WEB-INF/lib), if it exists
+
+        String libPath = "/WEB-INF/lib";
+
+        classLoader.setJarPath(libPath);
+
+        DirContext libDir = null;
+        // Looking up directory /WEB-INF/lib in the context
+        try {
+            Object object = resources.lookup(libPath);
+            if (object instanceof DirContext)
+                libDir = (DirContext) object;
+        } catch(NamingException e) {
+            // Silent catch: it's valid that no /WEB-INF/lib collection
+            // exists
+        }
+
+        if (libDir != null) {
+
+            boolean copyJars = false;
+            String absoluteLibPath = servletContext.getRealPath(libPath);
+
+            File destDir = null;
+
+            if (absoluteLibPath != null) {
+                destDir = new File(absoluteLibPath);
+            } else {
+                copyJars = true;
+                destDir = new File(workDir, libPath);
+                destDir.mkdirs();
+            }
+
+            // Looking up directory /WEB-INF/lib in the context
+            try {
+                NamingEnumeration enumeration = resources.listBindings(libPath);
+                while (enumeration.hasMoreElements()) {
+
+                    Binding binding = (Binding) enumeration.nextElement();
+                    String filename = libPath + "/" + binding.getName();
+                    if (!filename.endsWith(".jar"))
+                        continue;
+
+                    // Copy JAR in the work directory, always (the JAR file
+                    // would get locked otherwise, which would make it
+                    // impossible to update it or remove it at runtime)
+                    File destFile = new File(destDir, binding.getName());
+
+                    if( log.isDebugEnabled())
+                    log.debug(sm.getString("webappLoader.jarDeploy", filename,
+                                     destFile.getAbsolutePath()));
+
+                    Resource jarResource = (Resource) binding.getObject();
+                    if (copyJars) {
+                        if (!copy(jarResource.streamContent(),
+                                  new FileOutputStream(destFile)))
+                            continue;
+                    }
+
+                    try {
+                        JarFile jarFile = new JarFile(destFile);
+                        classLoader.addJar(filename, jarFile, destFile);
+                    } catch (Exception ex) {
+                        // Catch the exception if there is an empty jar file
+                        // Should ignore and continute loading other jar files 
+                        // in the dir
+                    }
+                    
+                    loaderRepositories.add( filename );
+
+                }
+            } catch (NamingException e) {
+                // Silent catch: it's valid that no /WEB-INF/lib directory
+                // exists
+            } catch (IOException e) {
+                e.printStackTrace();
+            }
+
+        }
+
+    }
+
+
+    /**
+     * Set the appropriate context attribute for our class path.  This
+     * is required only because Jasper depends on it.
+     */
+    private void setClassPath() {
+
+        // Validate our current state information
+        if (!(container instanceof Context))
+            return;
+        ServletContext servletContext =
+            ((Context) container).getServletContext();
+        if (servletContext == null)
+            return;
+
+        if (container instanceof StandardContext) {
+            String baseClasspath = 
+                ((StandardContext) container).getCompilerClasspath();
+            if (baseClasspath != null) {
+                servletContext.setAttribute(Globals.CLASS_PATH_ATTR,
+                                            baseClasspath);
+                return;
+            }
+        }
+
+        StringBuffer classpath = new StringBuffer();
+
+        // Assemble the class path information from our class loader chain
+        ClassLoader loader = getClassLoader();
+        int layers = 0;
+        int n = 0;
+        while (loader != null) {
+            if (!(loader instanceof URLClassLoader)) {
+                String cp=getClasspath( loader );
+                if( cp==null ) {
+                    log.info( "Unknown loader " + loader + " " + loader.getClass());
+                    break;
+                } else {
+                    if (n > 0) 
+                        classpath.append(File.pathSeparator);
+                    classpath.append(cp);
+                    n++;
+                }
+                break;
+                //continue;
+            }
+            URL repositories[] =
+                ((URLClassLoader) loader).getURLs();
+            for (int i = 0; i < repositories.length; i++) {
+                String repository = repositories[i].toString();
+                if (repository.startsWith("file://"))
+                    repository = repository.substring(7);
+                else if (repository.startsWith("file:"))
+                    repository = repository.substring(5);
+                else if (repository.startsWith("jndi:"))
+                    repository =
+                        servletContext.getRealPath(repository.substring(5));
+                else
+                    continue;
+                if (repository == null)
+                    continue;
+                if (n > 0)
+                    classpath.append(File.pathSeparator);
+                classpath.append(repository);
+                n++;
+            }
+            loader = loader.getParent();
+            layers++;
+        }
+
+        this.classpath=classpath.toString();
+
+        // Store the assembled class path as a servlet context attribute
+        servletContext.setAttribute(Globals.CLASS_PATH_ATTR,
+                                    classpath.toString());
+
+    }
+
+    // try to extract the classpath from a loader that is not URLClassLoader
+    private String getClasspath( ClassLoader loader ) {
+        try {
+            Method m=loader.getClass().getMethod("getClasspath", new Class[] {});
+            if( log.isTraceEnabled())
+                log.trace("getClasspath " + m );
+            if( m==null ) return null;
+            Object o=m.invoke( loader, new Object[] {} );
+            if( log.isDebugEnabled() )
+                log.debug("gotClasspath " + o);
+            if( o instanceof String )
+                return (String)o;
+            return null;
+        } catch( Exception ex ) {
+            if (log.isDebugEnabled())
+                log.debug("getClasspath ", ex);
+        }
+        return null;
+    }
+
+    /**
+     * Copy directory.
+     */
+    private boolean copyDir(DirContext srcDir, File destDir) {
+
+        try {
+
+            NamingEnumeration enumeration = srcDir.list("");
+            while (enumeration.hasMoreElements()) {
+                NameClassPair ncPair =
+                    (NameClassPair) enumeration.nextElement();
+                String name = ncPair.getName();
+                Object object = srcDir.lookup(name);
+                File currentFile = new File(destDir, name);
+                if (object instanceof Resource) {
+                    InputStream is = ((Resource) object).streamContent();
+                    OutputStream os = new FileOutputStream(currentFile);
+                    if (!copy(is, os))
+                        return false;
+                } else if (object instanceof InputStream) {
+                    OutputStream os = new FileOutputStream(currentFile);
+                    if (!copy((InputStream) object, os))
+                        return false;
+                } else if (object instanceof DirContext) {
+                    currentFile.mkdir();
+                    copyDir((DirContext) object, currentFile);
+                }
+            }
+
+        } catch (NamingException e) {
+            return false;
+        } catch (IOException e) {
+            return false;
+        }
+
+        return true;
+
+    }
+
+
+    /**
+     * Copy a file to the specified temp directory. This is required only
+     * because Jasper depends on it.
+     */
+    private boolean copy(InputStream is, OutputStream os) {
+
+        try {
+            byte[] buf = new byte[4096];
+            while (true) {
+                int len = is.read(buf);
+                if (len < 0)
+                    break;
+                os.write(buf, 0, len);
+            }
+            is.close();
+            os.close();
+        } catch (IOException e) {
+            return false;
+        }
+
+        return true;
+
+    }
+
+
+    private static org.apache.commons.logging.Log log=
+        org.apache.commons.logging.LogFactory.getLog( WebappLoader.class );
+
+    private ObjectName oname;
+    private MBeanServer mserver;
+    private String domain;
+    private ObjectName controller;
+
+    public ObjectName preRegister(MBeanServer server,
+                                  ObjectName name) throws Exception {
+        oname=name;
+        mserver=server;
+        domain=name.getDomain();
+
+        return name;
+    }
+
+    public void postRegister(Boolean registrationDone) {
+    }
+
+    public void preDeregister() throws Exception {
+    }
+
+    public void postDeregister() {
+    }
+
+    public ObjectName getController() {
+        return controller;
+    }
+
+    public void setController(ObjectName controller) {
+        this.controller = controller;
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/loader/mbeans-descriptors.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/loader/mbeans-descriptors.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/loader/mbeans-descriptors.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,59 @@
+<?xml version="1.0"?>
+<mbeans-descriptors>
+
+  <mbean         name="WebappLoader"
+          description="Classloader implementation which is specialized for
+                       handling web applications"
+               domain="Catalina"
+                group="Loader"
+                 type="org.apache.catalina.loader.WebappLoader">
+                 
+    <attribute   name="className"
+          description="Fully qualified class name of the managed object"
+                 type="java.lang.String"
+            writeable="false"/>
+
+    <attribute   name="delegate"
+          description="The 'follow standard delegation model' flag that will be
+                       used to configure our ClassLoader"
+                 type="boolean"/>
+
+    <attribute   name="reloadable"
+          description="The reloadable flag for this Loader"
+                 type="boolean"/>
+
+    <attribute   name="repositories"
+          description="Extra repositories managed by this loader"
+                 type="[Ljava.lang.String;"/>
+
+    <attribute   name="repositoriesString"
+          description="Extra repositories managed by this loader"
+             writeable="false" 
+                 type="java.lang.String"/>
+
+    <attribute   name="loaderRepositories"
+          description="Repositories set in the real loader"
+                 type="[Ljava.lang.String;"
+            writeable="false" />
+
+    <attribute   name="loaderRepositoriesString"
+          description="Repositories set in the real loader"
+                 type="java.lang.String"
+             writeable="false" />
+
+    <operation   name="toString"
+          description="Info about the loader"
+               impact="INFO"
+           returnType="String">
+    </operation>
+  </mbean>
+
+
+  <mbean         name="WebappClassLoader"
+          description="Classloader implementation which is specialized for
+                       handling web applications"
+               domain="Catalina"
+                group="Loader"
+                 type="org.apache.catalina.loader.WebappClassLoader" />
+
+</mbeans-descriptors>

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/mbeans/ClassNameMBean.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/mbeans/ClassNameMBean.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/mbeans/ClassNameMBean.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.mbeans;
+
+
+import javax.management.MBeanException;
+import javax.management.RuntimeOperationsException;
+import org.apache.commons.modeler.BaseModelMBean;
+
+
+/**
+ * <p>A convenience base class for <strong>ModelMBean</strong> implementations
+ * where the underlying base class (and therefore the set of supported
+ * properties) is different for varying implementations of a standard
+ * interface.  For Catalina, that includes at least the following:
+ * Connector, Logger, Realm, and Valve.  This class creates an artificial
+ * MBean attribute named <code>className</code>, which reports the fully
+ * qualified class name of the managed object as its value.</p>
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class ClassNameMBean extends BaseModelMBean {
+
+
+     // ---------------------------------------------------------- Constructors
+
+
+     /**
+      * Construct a <code>ModelMBean</code> with default
+      * <code>ModelMBeanInfo</code> information.
+      *
+      * @exception MBeanException if the initialize of an object
+      *  throws an exception
+      * @exception RuntimeOperationsException if an IllegalArgumentException
+      *  occurs
+      */
+     public ClassNameMBean()
+         throws MBeanException, RuntimeOperationsException {
+
+         super();
+
+     }
+
+
+     // ------------------------------------------------------------ Properties
+
+
+     /**
+      * Return the fully qualified Java class name of the managed object
+      * for this MBean.
+      */
+     public String getClassName() {
+
+         return (this.resource.getClass().getName());
+
+     }
+
+
+ }

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/mbeans/ConnectorMBean.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/mbeans/ConnectorMBean.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/mbeans/ConnectorMBean.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,139 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.mbeans;
+
+import javax.management.Attribute;
+import javax.management.AttributeNotFoundException;
+import javax.management.InstanceNotFoundException;
+import javax.management.MBeanException;
+import javax.management.ReflectionException;
+import javax.management.RuntimeOperationsException;
+import javax.management.modelmbean.InvalidTargetObjectTypeException;
+
+import org.apache.catalina.connector.Connector;
+import org.apache.tomcat.util.IntrospectionUtils;
+
+
+/**
+ * <p>A <strong>ModelMBean</strong> implementation for the
+ * <code>org.apache.coyote.tomcat5.CoyoteConnector</code> component.</p>
+ *
+ * @author Amy Roh
+ * @version $Revision: 394709 $ $Date: 2006-04-17 10:35:32 -0500 (Mon, 17 Apr 2006) $
+ */
+
+public class ConnectorMBean extends ClassNameMBean {
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Construct a <code>ModelMBean</code> with default
+     * <code>ModelMBeanInfo</code> information.
+     *
+     * @exception MBeanException if the initializer of an object
+     *  throws an exception
+     * @exception RuntimeOperationsException if an IllegalArgumentException
+     *  occurs
+     */
+    public ConnectorMBean()
+        throws MBeanException, RuntimeOperationsException {
+
+        super();
+
+    }
+
+
+    // ------------------------------------------------------------- Attributes
+
+
+    /**
+     * Obtain and return the value of a specific attribute of this MBean.
+     *
+     * @param name Name of the requested attribute
+     *
+     * @exception AttributeNotFoundException if this attribute is not
+     *  supported by this MBean
+     * @exception MBeanException if the initializer of an object
+     *  throws an exception
+     * @exception ReflectionException if a Java reflection exception
+     *  occurs when invoking the getter
+     */
+    public Object getAttribute(String name) throws AttributeNotFoundException,
+            MBeanException, ReflectionException {
+
+        // Validate the input parameters
+        if (name == null)
+            throw new RuntimeOperationsException(new IllegalArgumentException(
+                    "Attribute name is null"), "Attribute name is null");
+
+        Object result = null;
+        try {
+            Connector connector = (Connector) getManagedResource();
+            result = IntrospectionUtils.getProperty(connector, name);
+        } catch (InstanceNotFoundException e) {
+            throw new MBeanException(e);
+        } catch (InvalidTargetObjectTypeException e) {
+            throw new MBeanException(e);
+        }
+
+        return result;
+
+    }
+
+    
+    /**
+     * Set the value of a specific attribute of this MBean.
+     *
+     * @param attribute The identification of the attribute to be set
+     *  and the new value
+     *
+     * @exception AttributeNotFoundException if this attribute is not
+     *  supported by this MBean
+     * @exception MBeanException if the initializer of an object
+     *  throws an exception
+     * @exception ReflectionException if a Java reflection exception
+     *  occurs when invoking the getter
+     */
+     public void setAttribute(Attribute attribute)
+            throws AttributeNotFoundException, MBeanException,
+            ReflectionException {
+
+        // Validate the input parameters
+        if (attribute == null)
+            throw new RuntimeOperationsException(new IllegalArgumentException(
+                    "Attribute is null"), "Attribute is null");
+        String name = attribute.getName();
+        Object value = attribute.getValue();
+        if (name == null)
+            throw new RuntimeOperationsException(new IllegalArgumentException(
+                    "Attribute name is null"), "Attribute name is null");
+
+        try {
+            Connector connector = (Connector) getManagedResource();
+            IntrospectionUtils.setProperty(connector, name, String.valueOf(value));
+        } catch (InstanceNotFoundException e) {
+            throw new MBeanException(e);
+        } catch (InvalidTargetObjectTypeException e) {
+            throw new MBeanException(e);
+        }
+  
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/mbeans/ContextEnvironmentMBean.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/mbeans/ContextEnvironmentMBean.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/mbeans/ContextEnvironmentMBean.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,105 @@
+/*
+ * Copyright 2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.mbeans;
+
+
+import javax.management.Attribute;
+import javax.management.AttributeNotFoundException;
+import javax.management.InstanceNotFoundException;
+import javax.management.MBeanException;
+import javax.management.ReflectionException;
+import javax.management.RuntimeOperationsException;
+import javax.management.modelmbean.InvalidTargetObjectTypeException;
+
+import org.apache.catalina.deploy.ContextEnvironment;
+import org.apache.catalina.deploy.NamingResources;
+import org.apache.commons.modeler.BaseModelMBean;
+
+
+/**
+ * <p>A <strong>ModelMBean</strong> implementation for the
+ * <code>org.apache.catalina.deploy.ContextEnvironment</code> component.</p>
+ *
+ * @author Amy Roh
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class ContextEnvironmentMBean extends BaseModelMBean {
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Construct a <code>ModelMBean</code> with default
+     * <code>ModelMBeanInfo</code> information.
+     *
+     * @exception MBeanException if the initializer of an object
+     *  throws an exception
+     * @exception RuntimeOperationsException if an IllegalArgumentException
+     *  occurs
+     */
+    public ContextEnvironmentMBean()
+        throws MBeanException, RuntimeOperationsException {
+
+        super();
+
+    }
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    // ------------------------------------------------------------- Attributes
+
+    
+    /**
+     * Set the value of a specific attribute of this MBean.
+     *
+     * @param attribute The identification of the attribute to be set
+     *  and the new value
+     *
+     * @exception AttributeNotFoundException if this attribute is not
+     *  supported by this MBean
+     * @exception MBeanException if the initializer of an object
+     *  throws an exception
+     * @exception ReflectionException if a Java reflection exception
+     *  occurs when invoking the getter
+     */
+     public void setAttribute(Attribute attribute)
+        throws AttributeNotFoundException, MBeanException,
+        ReflectionException {
+
+        super.setAttribute(attribute);
+        
+        ContextEnvironment ce = null;
+        try {
+            ce = (ContextEnvironment) getManagedResource();
+        } catch (InstanceNotFoundException e) {
+            throw new MBeanException(e);
+        } catch (InvalidTargetObjectTypeException e) {
+             throw new MBeanException(e);
+        }
+        
+        // cannot use side-efects.  It's removed and added back each time 
+        // there is a modification in a resource.
+        NamingResources nr = ce.getNamingResources();
+        nr.removeEnvironment(ce.getName());
+        nr.addEnvironment(ce);
+    }
+    
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/mbeans/ContextResourceLinkMBean.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/mbeans/ContextResourceLinkMBean.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/mbeans/ContextResourceLinkMBean.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,105 @@
+/*
+ * Copyright 2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.mbeans;
+
+
+import javax.management.Attribute;
+import javax.management.AttributeNotFoundException;
+import javax.management.InstanceNotFoundException;
+import javax.management.MBeanException;
+import javax.management.ReflectionException;
+import javax.management.RuntimeOperationsException;
+import javax.management.modelmbean.InvalidTargetObjectTypeException;
+
+import org.apache.catalina.deploy.ContextResourceLink;
+import org.apache.catalina.deploy.NamingResources;
+import org.apache.commons.modeler.BaseModelMBean;
+
+
+/**
+ * <p>A <strong>ModelMBean</strong> implementation for the
+ * <code>org.apache.catalina.deploy.ContextResourceLink</code> component.</p>
+ *
+ * @author Amy Roh
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class ContextResourceLinkMBean extends BaseModelMBean {
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Construct a <code>ModelMBean</code> with default
+     * <code>ModelMBeanInfo</code> information.
+     *
+     * @exception MBeanException if the initializer of an object
+     *  throws an exception
+     * @exception RuntimeOperationsException if an IllegalArgumentException
+     *  occurs
+     */
+    public ContextResourceLinkMBean()
+        throws MBeanException, RuntimeOperationsException {
+
+        super();
+
+    }
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    // ------------------------------------------------------------- Attributes
+
+    
+    /**
+     * Set the value of a specific attribute of this MBean.
+     *
+     * @param attribute The identification of the attribute to be set
+     *  and the new value
+     *
+     * @exception AttributeNotFoundException if this attribute is not
+     *  supported by this MBean
+     * @exception MBeanException if the initializer of an object
+     *  throws an exception
+     * @exception ReflectionException if a Java reflection exception
+     *  occurs when invoking the getter
+     */
+     public void setAttribute(Attribute attribute)
+        throws AttributeNotFoundException, MBeanException,
+        ReflectionException {
+
+        super.setAttribute(attribute);
+        
+        ContextResourceLink crl = null;
+        try {
+            crl = (ContextResourceLink) getManagedResource();
+        } catch (InstanceNotFoundException e) {
+            throw new MBeanException(e);
+        } catch (InvalidTargetObjectTypeException e) {
+             throw new MBeanException(e);
+        }
+        
+        // cannot use side-efects.  It's removed and added back each time 
+        // there is a modification in a resource.
+        NamingResources nr = crl.getNamingResources();
+        nr.removeResourceLink(crl.getName());
+        nr.addResourceLink(crl);
+    }
+    
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/mbeans/ContextResourceMBean.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/mbeans/ContextResourceMBean.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/mbeans/ContextResourceMBean.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,184 @@
+/*
+ * Copyright 2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.mbeans;
+
+
+import javax.management.Attribute;
+import javax.management.AttributeNotFoundException;
+import javax.management.InstanceNotFoundException;
+import javax.management.MBeanException;
+import javax.management.ReflectionException;
+import javax.management.RuntimeOperationsException;
+import javax.management.modelmbean.InvalidTargetObjectTypeException;
+
+import org.apache.catalina.deploy.ContextResource;
+import org.apache.catalina.deploy.NamingResources;
+import org.apache.commons.modeler.BaseModelMBean;
+
+
+/**
+ * <p>A <strong>ModelMBean</strong> implementation for the
+ * <code>org.apache.catalina.deploy.ContextResource</code> component.</p>
+ *
+ * @author Amy Roh
+ * @version $Revision: 303032 $ $Date: 2004-07-26 11:04:02 -0500 (Mon, 26 Jul 2004) $
+ */
+
+public class ContextResourceMBean extends BaseModelMBean {
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Construct a <code>ModelMBean</code> with default
+     * <code>ModelMBeanInfo</code> information.
+     *
+     * @exception MBeanException if the initializer of an object
+     *  throws an exception
+     * @exception RuntimeOperationsException if an IllegalArgumentException
+     *  occurs
+     */
+    public ContextResourceMBean()
+        throws MBeanException, RuntimeOperationsException {
+
+        super();
+
+    }
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    // ------------------------------------------------------------- Attributes
+
+
+    /**
+     * Obtain and return the value of a specific attribute of this MBean.
+     *
+     * @param name Name of the requested attribute
+     *
+     * @exception AttributeNotFoundException if this attribute is not
+     *  supported by this MBean
+     * @exception MBeanException if the initializer of an object
+     *  throws an exception
+     * @exception ReflectionException if a Java reflection exception
+     *  occurs when invoking the getter
+     */
+    public Object getAttribute(String name)
+        throws AttributeNotFoundException, MBeanException,
+        ReflectionException {
+ 
+        // Validate the input parameters
+        if (name == null)
+            throw new RuntimeOperationsException
+                (new IllegalArgumentException("Attribute name is null"),
+                 "Attribute name is null");
+
+        ContextResource cr = null;
+        try {
+            cr = (ContextResource) getManagedResource();
+        } catch (InstanceNotFoundException e) {
+            throw new MBeanException(e);
+        } catch (InvalidTargetObjectTypeException e) {
+             throw new MBeanException(e);
+        }
+        
+        String value = null;
+        if ("auth".equals(name)) {
+            return (cr.getAuth());
+        } else if ("description".equals(name)) {
+            return (cr.getDescription());
+        } else if ("name".equals(name)) {
+            return (cr.getName());              
+        } else if ("scope".equals(name)) {
+            return (cr.getScope());  
+        } else if ("type".equals(name)) {
+            return (cr.getType());
+        } else {
+            value = (String) cr.getProperty(name);
+            if (value == null) {
+                throw new AttributeNotFoundException
+                    ("Cannot find attribute "+name);
+            }
+        }
+        
+        return value;
+        
+    }
+
+    
+    /**
+     * Set the value of a specific attribute of this MBean.
+     *
+     * @param attribute The identification of the attribute to be set
+     *  and the new value
+     *
+     * @exception AttributeNotFoundException if this attribute is not
+     *  supported by this MBean
+     * @exception MBeanException if the initializer of an object
+     *  throws an exception
+     * @exception ReflectionException if a Java reflection exception
+     *  occurs when invoking the getter
+     */
+     public void setAttribute(Attribute attribute)
+        throws AttributeNotFoundException, MBeanException,
+        ReflectionException {
+
+        // Validate the input parameters
+        if (attribute == null)
+            throw new RuntimeOperationsException
+                (new IllegalArgumentException("Attribute is null"),
+                 "Attribute is null");
+        String name = attribute.getName();
+        Object value = attribute.getValue();
+        if (name == null)
+            throw new RuntimeOperationsException
+                (new IllegalArgumentException("Attribute name is null"),
+                 "Attribute name is null"); 
+        
+        ContextResource cr = null;
+        try {
+            cr = (ContextResource) getManagedResource();
+        } catch (InstanceNotFoundException e) {
+            throw new MBeanException(e);
+        } catch (InvalidTargetObjectTypeException e) {
+             throw new MBeanException(e);
+        }
+        
+        if ("auth".equals(name)) {
+            cr.setAuth((String)value);
+        } else if ("description".equals(name)) {
+            cr.setDescription((String)value);
+        } else if ("name".equals(name)) {
+            cr.setName((String)value);              
+        } else if ("scope".equals(name)) {
+            cr.setScope((String)value);  
+        } else if ("type".equals(name)) {
+            cr.setType((String)value);
+        } else {
+            cr.setProperty(name, ""+value);
+        }
+        
+        // cannot use side-efects.  It's removed and added back each time 
+        // there is a modification in a resource.
+        NamingResources nr = cr.getNamingResources();
+        nr.removeResource(cr.getName());
+        nr.addResource(cr);
+    }
+    
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/mbeans/DefaultContextMBean.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/mbeans/DefaultContextMBean.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/mbeans/DefaultContextMBean.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,338 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.mbeans;
+
+import java.util.ArrayList;
+
+import javax.management.MBeanException;
+import javax.management.MalformedObjectNameException;
+import javax.management.ObjectName;
+import javax.management.RuntimeOperationsException;
+
+import org.apache.catalina.Context;
+import org.apache.catalina.deploy.ContextEnvironment;
+import org.apache.catalina.deploy.ContextResource;
+import org.apache.catalina.deploy.ContextResourceLink;
+import org.apache.catalina.deploy.NamingResources;
+import org.apache.commons.modeler.BaseModelMBean;
+import org.apache.commons.modeler.ManagedBean;
+import org.apache.commons.modeler.Registry;
+import org.apache.tomcat.util.compat.JdkCompat;
+
+/**
+ * <p>A <strong>ModelMBean</strong> implementation for the
+ * <code>org.apache.catalina.core.StandardDefaultContext</code> component.</p>
+ *
+ * @author Amy Roh
+ * @version $Revision: 303133 $ $Date: 2004-08-29 11:46:15 -0500 (Sun, 29 Aug 2004) $
+ */
+
+public class DefaultContextMBean extends BaseModelMBean {
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Construct a <code>ModelMBean</code> with default
+     * <code>ModelMBeanInfo</code> information.
+     *
+     * @exception MBeanException if the initializer of an object
+     *  throws an exception
+     * @exception RuntimeOperationsException if an IllegalArgumentException
+     *  occurs
+     */
+    public DefaultContextMBean()
+        throws MBeanException, RuntimeOperationsException {
+
+        super();
+
+    }
+    
+
+    // ----------------------------------------------------- Class Variables
+
+
+    /**
+     * JDK compatibility support
+     */
+    private static final JdkCompat jdkCompat = JdkCompat.getJdkCompat();
+
+
+    // ----------------------------------------------------- Instance Variables
+    
+    
+    /**
+     * The configuration information registry for our managed beans.
+     */
+    protected Registry registry = MBeanUtils.createRegistry();
+
+    /**
+     * The <code>ManagedBean</code> information describing this MBean.
+     */
+    protected ManagedBean managed =
+        registry.findManagedBean("DefaultContext");
+
+    
+    // ------------------------------------------------------------- Attributes
+
+    
+    /**
+     * Return the naming resources associated with this web application.
+     */
+    private NamingResources getNamingResources() {
+        
+        return ((Context)this.resource).getNamingResources();
+    
+    }
+    
+    
+    /**
+     * Return the MBean Names of the set of defined environment entries for  
+     * this web application
+     */
+    public String[] getEnvironments() {
+        ContextEnvironment[] envs = getNamingResources().findEnvironments();
+        ArrayList results = new ArrayList();
+        for (int i = 0; i < envs.length; i++) {
+            try {
+                ObjectName oname =
+                    MBeanUtils.createObjectName(managed.getDomain(), envs[i]);
+                results.add(oname.toString());
+            } catch (MalformedObjectNameException e) {
+                IllegalArgumentException iae = new IllegalArgumentException
+                    ("Cannot create object name for environment " + envs[i]);
+                jdkCompat.chainException(iae, e);
+                throw iae;
+            }
+        }
+        return ((String[]) results.toArray(new String[results.size()]));
+
+    }
+    
+    
+    /**
+     * Return the MBean Names of all the defined resource references for this
+     * application.
+     */
+    public String[] getResources() {
+        
+        ContextResource[] resources = getNamingResources().findResources();
+        ArrayList results = new ArrayList();
+        for (int i = 0; i < resources.length; i++) {
+            try {
+                ObjectName oname =
+                    MBeanUtils.createObjectName(managed.getDomain(), resources[i]);
+                results.add(oname.toString());
+            } catch (MalformedObjectNameException e) {
+                IllegalArgumentException iae = new IllegalArgumentException
+                    ("Cannot create object name for resource " + resources[i]);
+                jdkCompat.chainException(iae, e);
+                throw iae;
+            }
+        }
+        return ((String[]) results.toArray(new String[results.size()]));
+
+    }
+
+      
+    /**
+     * Return the MBean Names of all the defined resource links for this 
+     * application
+     */
+    public String[] getResourceLinks() {
+        
+        ContextResourceLink[] links = getNamingResources().findResourceLinks();
+        ArrayList results = new ArrayList();
+        for (int i = 0; i < links.length; i++) {
+            try {
+                ObjectName oname =
+                    MBeanUtils.createObjectName(managed.getDomain(), links[i]);
+                results.add(oname.toString());
+            } catch (MalformedObjectNameException e) {
+                IllegalArgumentException iae = new IllegalArgumentException
+                    ("Cannot create object name for resource " + links[i]);
+                jdkCompat.chainException(iae, e);
+                throw iae;
+            }
+        }
+        return ((String[]) results.toArray(new String[results.size()]));
+
+    }
+
+    // ------------------------------------------------------------- Operations
+
+
+    /**
+     * Add an environment entry for this web application.
+     *
+     * @param envName New environment entry name
+     */
+    public String addEnvironment(String envName, String type) 
+        throws MalformedObjectNameException {
+
+        NamingResources nresources = getNamingResources();
+        if (nresources == null) {
+            return null;
+        }
+        ContextEnvironment env = nresources.findEnvironment(envName);
+        if (env != null) {
+            throw new IllegalArgumentException
+                ("Invalid environment name - already exists '" + envName + "'");
+        }
+        env = new ContextEnvironment();
+        env.setName(envName);
+        env.setType(type);
+        nresources.addEnvironment(env);
+        
+        // Return the corresponding MBean name
+        ManagedBean managed = registry.findManagedBean("ContextEnvironment");
+        ObjectName oname =
+            MBeanUtils.createObjectName(managed.getDomain(), env);
+        return (oname.toString());
+        
+    }
+
+    
+    /**
+     * Add a resource reference for this web application.
+     *
+     * @param resourceName New resource reference name
+     */
+    public String addResource(String resourceName, String type) 
+        throws MalformedObjectNameException {
+        
+        NamingResources nresources = getNamingResources();
+        if (nresources == null) {
+            return null;
+        }
+        ContextResource resource = nresources.findResource(resourceName);
+        if (resource != null) {
+            throw new IllegalArgumentException
+                ("Invalid resource name - already exists'" + resourceName + "'");
+        }
+        resource = new ContextResource();
+        resource.setName(resourceName);
+        resource.setType(type);
+        nresources.addResource(resource);
+        
+        // Return the corresponding MBean name
+        ManagedBean managed = registry.findManagedBean("ContextResource");
+        ObjectName oname =
+            MBeanUtils.createObjectName(managed.getDomain(), resource);
+        
+        return (oname.toString());
+    }
+
+    
+    /**
+     * Add a resource link for this web application.
+     *
+     * @param resourceLinkName New resource link name
+     */
+    public String addResourceLink(String resourceLinkName, String global, 
+                String name, String type) throws MalformedObjectNameException {
+        
+        NamingResources nresources = getNamingResources();
+        if (nresources == null) {
+            return null;
+        }
+        ContextResourceLink resourceLink = 
+                                nresources.findResourceLink(resourceLinkName);
+        if (resourceLink != null) {
+            throw new IllegalArgumentException
+                ("Invalid resource link name - already exists'" + 
+                                                        resourceLinkName + "'");
+        }
+        resourceLink = new ContextResourceLink();
+        resourceLink.setGlobal(global);
+        resourceLink.setName(resourceLinkName);
+        resourceLink.setType(type);
+        nresources.addResourceLink(resourceLink);
+        
+        // Return the corresponding MBean name
+        ManagedBean managed = registry.findManagedBean("ContextResourceLink");
+        ObjectName oname =
+            MBeanUtils.createObjectName(managed.getDomain(), resourceLink);
+        return (oname.toString());
+    }    
+    
+    
+    /**
+     * Remove any environment entry with the specified name.
+     *
+     * @param envName Name of the environment entry to remove
+     */
+    public void removeEnvironment(String envName) {
+
+        NamingResources nresources = getNamingResources();
+        if (nresources == null) {
+            return;
+        }
+        ContextEnvironment env = nresources.findEnvironment(envName);
+        if (env == null) {
+            throw new IllegalArgumentException
+                ("Invalid environment name '" + envName + "'");
+        }
+        nresources.removeEnvironment(envName);
+
+    }
+    
+    
+    /**
+     * Remove any resource reference with the specified name.
+     *
+     * @param resourceName Name of the resource reference to remove
+     */
+    public void removeResource(String resourceName) {
+
+        resourceName = ObjectName.unquote(resourceName);
+        NamingResources nresources = getNamingResources();
+        if (nresources == null) {
+            return;
+        }
+        ContextResource resource = nresources.findResource(resourceName);
+        if (resource == null) {
+            throw new IllegalArgumentException
+                ("Invalid resource name '" + resourceName + "'");
+        }
+        nresources.removeResource(resourceName);
+    }
+    
+    
+    /**
+     * Remove any resource link with the specified name.
+     *
+     * @param resourceLinkName Name of the resource reference to remove
+     */
+    public void removeResourceLink(String resourceLinkName) {
+
+        resourceLinkName = ObjectName.unquote(resourceLinkName);
+        NamingResources nresources = getNamingResources();
+        if (nresources == null) {
+            return;
+        }
+        ContextResourceLink resource = nresources.findResourceLink(resourceLinkName);
+        if (resource == null) {
+            throw new IllegalArgumentException
+                ("Invalid resource name '" + resourceLinkName + "'");
+        }
+        nresources.removeResourceLink(resourceLinkName);
+    }
+ 
+    
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/mbeans/GlobalResourcesLifecycleListener.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/mbeans/GlobalResourcesLifecycleListener.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/mbeans/GlobalResourcesLifecycleListener.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,236 @@
+/*
+ * Copyright 2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.mbeans;
+
+
+import java.util.Iterator;
+import javax.naming.Binding;
+import javax.naming.Context;
+import javax.naming.InitialContext;
+import javax.naming.NamingEnumeration;
+import javax.naming.NamingException;
+import javax.naming.OperationNotSupportedException;
+import org.apache.catalina.Group;
+import org.apache.catalina.Lifecycle;
+import org.apache.catalina.LifecycleEvent;
+import org.apache.catalina.LifecycleListener;
+import org.apache.catalina.Role;
+import org.apache.catalina.User;
+import org.apache.catalina.UserDatabase;
+import org.apache.commons.modeler.Registry;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+
+/**
+ * Implementation of <code>LifecycleListener</code> that instantiates the
+ * set of MBeans associated with global JNDI resources that are subject to
+ * management.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302983 $ $Date: 2004-06-25 18:56:25 -0500 (Fri, 25 Jun 2004) $
+ * @since 4.1
+ */
+
+public class GlobalResourcesLifecycleListener
+    implements LifecycleListener {
+    private static Log log = LogFactory.getLog(GlobalResourcesLifecycleListener.class);
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The owning Catalina component that we are attached to.
+     */
+    protected Lifecycle component = null;
+
+
+    /**
+     * The configuration information registry for our managed beans.
+     */
+    protected static Registry registry = MBeanUtils.createRegistry();
+
+
+    // ---------------------------------------------- LifecycleListener Methods
+
+
+    /**
+     * Primary entry point for startup and shutdown events.
+     *
+     * @param event The event that has occurred
+     */
+    public void lifecycleEvent(LifecycleEvent event) {
+
+        if (Lifecycle.START_EVENT.equals(event.getType())) {
+            component = event.getLifecycle();
+            createMBeans();
+        } else if (Lifecycle.STOP_EVENT.equals(event.getType())) {
+            destroyMBeans();
+            component = null;
+        }
+
+    }
+
+
+    // ------------------------------------------------------ Protected Methods
+
+
+    /**
+     * Create the MBeans for the interesting global JNDI resources.
+     */
+    protected void createMBeans() {
+
+        // Look up our global naming context
+        Context context = null;
+        try {
+            context = (Context) (new InitialContext()).lookup("java:/");
+        } catch (NamingException e) {
+            log.error("No global naming context defined for server");
+            return;
+        }
+
+        // Recurse through the defined global JNDI resources context
+        try {
+            createMBeans("", context);
+        } catch (NamingException e) {
+            log.error("Exception processing Global JNDI Resources", e);
+        }
+
+    }
+
+
+    /**
+     * Create the MBeans for the interesting global JNDI resources in
+     * the specified naming context.
+     *
+     * @param prefix Prefix for complete object name paths
+     * @param context Context to be scanned
+     *
+     * @exception NamingException if a JNDI exception occurs
+     */
+    protected void createMBeans(String prefix, Context context)
+        throws NamingException {
+
+        if (log.isDebugEnabled()) {
+            log.debug("Creating MBeans for Global JNDI Resources in Context '" +
+                prefix + "'");
+        }
+
+        try {
+            NamingEnumeration bindings = context.listBindings("");
+            while (bindings.hasMore()) {
+                Binding binding = (Binding) bindings.next();
+                String name = prefix + binding.getName();
+                Object value = context.lookup(binding.getName());
+                if (log.isDebugEnabled()) {
+                    log.debug("Checking resource " + name);
+                }
+                if (value instanceof Context) {
+                    createMBeans(name + "/", (Context) value);
+                } else if (value instanceof UserDatabase) {
+                    try {
+                        createMBeans(name, (UserDatabase) value);
+                    } catch (Exception e) {
+                        log.error("Exception creating UserDatabase MBeans for " + name,
+                                e);
+                    }
+                }
+            }
+        } catch( RuntimeException ex) {
+            log.error("RuntimeException " + ex);
+        } catch( OperationNotSupportedException ex) {
+            log.error("Operation not supported " + ex);
+        }
+
+    }
+
+
+    /**
+     * Create the MBeans for the specified UserDatabase and its contents.
+     *
+     * @param name Complete resource name of this UserDatabase
+     * @param database The UserDatabase to be processed
+     *
+     * @exception Exception if an exception occurs while creating MBeans
+     */
+    protected void createMBeans(String name, UserDatabase database)
+        throws Exception {
+
+        // Create the MBean for the UserDatabase itself
+        if (log.isDebugEnabled()) {
+            log.debug("Creating UserDatabase MBeans for resource " + name);
+            log.debug("Database=" + database);
+        }
+        if (MBeanUtils.createMBean(database) == null) {
+            throw new IllegalArgumentException
+                ("Cannot create UserDatabase MBean for resource " + name);
+        }
+
+        // Create the MBeans for each defined Role
+        Iterator roles = database.getRoles();
+        while (roles.hasNext()) {
+            Role role = (Role) roles.next();
+            if (log.isDebugEnabled()) {
+                log.debug("  Creating Role MBean for role " + role);
+            }
+            if (MBeanUtils.createMBean(role) == null) {
+                throw new IllegalArgumentException
+                    ("Cannot create Role MBean for role " + role);
+            }
+        }
+
+        // Create the MBeans for each defined Group
+        Iterator groups = database.getGroups();
+        while (groups.hasNext()) {
+            Group group = (Group) groups.next();
+            if (log.isDebugEnabled()) {
+                log.debug("  Creating Group MBean for group " + group);
+            }
+            if (MBeanUtils.createMBean(group) == null) {
+                throw new IllegalArgumentException
+                    ("Cannot create Group MBean for group " + group);
+            }
+        }
+
+        // Create the MBeans for each defined User
+        Iterator users = database.getUsers();
+        while (users.hasNext()) {
+            User user = (User) users.next();
+            if (log.isDebugEnabled()) {
+                log.debug("  Creating User MBean for user " + user);
+            }
+            if (MBeanUtils.createMBean(user) == null) {
+                throw new IllegalArgumentException
+                    ("Cannot create User MBean for user " + user);
+            }
+        }
+
+    }
+
+
+    /**
+     * Destroy the MBeans for the interesting global JNDI resources.
+     */
+    protected void destroyMBeans() {
+
+        if (log.isDebugEnabled()) {
+            log.debug("Destroying MBeans for Global JNDI Resources");
+        }
+
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/mbeans/GroupMBean.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/mbeans/GroupMBean.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/mbeans/GroupMBean.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,201 @@
+/*
+ * Copyright 2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.mbeans;
+
+
+import java.util.ArrayList;
+import java.util.Iterator;
+
+import javax.management.MBeanException;
+import javax.management.MBeanServer;
+import javax.management.MalformedObjectNameException;
+import javax.management.ObjectName;
+import javax.management.RuntimeOperationsException;
+
+import org.apache.catalina.Group;
+import org.apache.catalina.Role;
+import org.apache.catalina.User;
+import org.apache.commons.modeler.BaseModelMBean;
+import org.apache.commons.modeler.ManagedBean;
+import org.apache.commons.modeler.Registry;
+import org.apache.tomcat.util.compat.JdkCompat;
+
+/**
+ * <p>A <strong>ModelMBean</strong> implementation for the
+ * <code>org.apache.catalina.Group</code> component.</p>
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302833 $ $Date: 2004-04-14 20:44:09 -0500 (Wed, 14 Apr 2004) $
+ */
+
+public class GroupMBean extends BaseModelMBean {
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Construct a <code>ModelMBean</code> with default
+     * <code>ModelMBeanInfo</code> information.
+     *
+     * @exception MBeanException if the initializer of an object
+     *  throws an exception
+     * @exception RuntimeOperationsException if an IllegalArgumentException
+     *  occurs
+     */
+    public GroupMBean()
+        throws MBeanException, RuntimeOperationsException {
+
+        super();
+
+    }
+
+
+    // ----------------------------------------------------- Class Variables
+
+
+    /**
+     * JDK compatibility support
+     */
+    private static final JdkCompat jdkCompat = JdkCompat.getJdkCompat();
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The configuration information registry for our managed beans.
+     */
+    protected Registry registry = MBeanUtils.createRegistry();
+
+
+    /**
+     * The <code>MBeanServer</code> in which we are registered.
+     */
+    protected MBeanServer mserver = MBeanUtils.createServer();
+
+
+    /**
+     * The <code>ManagedBean</code> information describing this MBean.
+     */
+    protected ManagedBean managed =
+        registry.findManagedBean("Group");
+
+
+    // ------------------------------------------------------------- Attributes
+
+
+    /**
+     * Return the MBean Names of all authorized roles for this group.
+     */
+    public String[] getRoles() {
+
+        Group group = (Group) this.resource;
+        ArrayList results = new ArrayList();
+        Iterator roles = group.getRoles();
+        while (roles.hasNext()) {
+            Role role = null;
+            try {
+                role = (Role) roles.next();
+                ObjectName oname =
+                    MBeanUtils.createObjectName(managed.getDomain(), role);
+                results.add(oname.toString());
+            } catch (MalformedObjectNameException e) {
+                IllegalArgumentException iae = new IllegalArgumentException
+                    ("Cannot create object name for role " + role);
+                jdkCompat.chainException(iae, e);
+                throw iae;
+            }
+        }
+        return ((String[]) results.toArray(new String[results.size()]));
+
+    }
+
+
+    /**
+     * Return the MBean Names of all users that are members of this group.
+     */
+    public String[] getUsers() {
+
+        Group group = (Group) this.resource;
+        ArrayList results = new ArrayList();
+        Iterator users = group.getUsers();
+        while (users.hasNext()) {
+            User user = null;
+            try {
+                user = (User) users.next();
+                ObjectName oname =
+                    MBeanUtils.createObjectName(managed.getDomain(), user);
+                results.add(oname.toString());
+            } catch (MalformedObjectNameException e) {
+                IllegalArgumentException iae = new IllegalArgumentException
+                    ("Cannot create object name for user " + user);
+                jdkCompat.chainException(iae, e);
+                throw iae;
+            }
+        }
+        return ((String[]) results.toArray(new String[results.size()]));
+
+    }
+
+
+    // ------------------------------------------------------------- Operations
+
+
+    /**
+     * Add a new {@link Role} to those this group belongs to.
+     *
+     * @param rolename Role name of the new role
+     */
+    public void addRole(String rolename) {
+
+        Group group = (Group) this.resource;
+        if (group == null) {
+            return;
+        }
+        Role role = group.getUserDatabase().findRole(rolename);
+        if (role == null) {
+            throw new IllegalArgumentException
+                ("Invalid role name '" + rolename + "'");
+        }
+        group.addRole(role);
+
+    }
+
+
+    /**
+     * Remove a {@link Role} from those this group belongs to.
+     *
+     * @param rolename Role name of the old role
+     */
+    public void removeRole(String rolename) {
+
+        Group group = (Group) this.resource;
+        if (group == null) {
+            return;
+        }
+        Role role = group.getUserDatabase().findRole(rolename);
+        if (role == null) {
+            throw new IllegalArgumentException
+                ("Invalid role name '" + rolename + "'");
+        }
+        group.removeRole(role);
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/mbeans/MBeanFactory.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/mbeans/MBeanFactory.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/mbeans/MBeanFactory.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,1116 @@
+/*
+ * Copyright 1999-2002,2004-2005 The Apache Software Foundation.
+ * 
+ * Licensed 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.mbeans;
+
+import java.io.File;
+import java.util.Vector;
+
+import javax.management.MBeanException;
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+import javax.management.RuntimeOperationsException;
+
+import org.apache.catalina.Context;
+import org.apache.catalina.Engine;
+import org.apache.catalina.Host;
+import org.apache.catalina.Server;
+import org.apache.catalina.ServerFactory;
+import org.apache.catalina.Service;
+import org.apache.catalina.Valve;
+import org.apache.catalina.authenticator.SingleSignOn;
+import org.apache.catalina.connector.Connector;
+import org.apache.catalina.core.ContainerBase;
+import org.apache.catalina.core.StandardContext;
+import org.apache.catalina.core.StandardEngine;
+import org.apache.catalina.core.StandardHost;
+import org.apache.catalina.core.StandardService;
+import org.apache.catalina.loader.WebappLoader;
+import org.apache.catalina.realm.DataSourceRealm;
+import org.apache.catalina.realm.JDBCRealm;
+import org.apache.catalina.realm.JNDIRealm;
+import org.apache.catalina.realm.JAASRealm;
+import org.apache.catalina.realm.MemoryRealm;
+import org.apache.catalina.realm.UserDatabaseRealm;
+import org.apache.catalina.session.StandardManager;
+import org.apache.catalina.startup.ContextConfig;
+import org.apache.catalina.startup.HostConfig;
+import org.apache.catalina.valves.AccessLogValve;
+import org.apache.catalina.valves.RemoteAddrValve;
+import org.apache.catalina.valves.RemoteHostValve;
+import org.apache.catalina.valves.RequestDumperValve;
+import org.apache.catalina.valves.ValveBase;
+import org.apache.commons.modeler.BaseModelMBean;
+import org.apache.commons.modeler.Registry;
+
+
+/**
+ * <p>A <strong>ModelMBean</strong> implementation for the
+ * <code>org.apache.catalina.core.StandardServer</code> component.</p>
+ *
+ * @author Amy Roh
+ * @version $Revision: 440749 $ $Date: 2006-09-06 11:06:18 -0500 (Wed, 06 Sep 2006) $
+ */
+
+public class MBeanFactory extends BaseModelMBean {
+
+    private static org.apache.commons.logging.Log log = 
+        org.apache.commons.logging.LogFactory.getLog(MBeanFactory.class);
+
+    /**
+     * The <code>MBeanServer</code> for this application.
+     */
+    private static MBeanServer mserver = MBeanUtils.createServer();
+
+    /**
+     * The configuration information registry for our managed beans.
+     */
+    private static Registry registry = MBeanUtils.createRegistry();
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Construct a <code>ModelMBean</code> with default
+     * <code>ModelMBeanInfo</code> information.
+     *
+     * @exception MBeanException if the initializer of an object
+     *  throws an exception
+     * @exception RuntimeOperationsException if an IllegalArgumentException
+     *  occurs
+     */
+    public MBeanFactory()
+        throws MBeanException, RuntimeOperationsException {
+
+        super();
+
+    }
+
+
+    // ------------------------------------------------------------- Attributes
+
+
+
+
+    // ------------------------------------------------------------- Operations
+
+
+    /**
+     * Return the managed bean definition for the specified bean type
+     *
+     * @param type MBean type
+     */
+    public String findObjectName(String type) {
+
+        if (type.equals("org.apache.catalina.core.StandardContext")) {
+            return "StandardContext";
+        } else if (type.equals("org.apache.catalina.core.StandardEngine")) {
+            return "Engine";
+        } else if (type.equals("org.apache.catalina.core.StandardHost")) {
+            return "Host";
+        } else {
+            return null;
+        }
+
+    }
+
+
+    /**
+     * Little convenience method to remove redundant code
+     * when retrieving the path string
+     *
+     * @param t path string
+     * @return empty string if t==null || t.equals("/")
+     */
+    private final String getPathStr(String t) {
+        if (t == null || t.equals("/")) {
+            return "";
+        }
+        return t;
+    }
+    
+   /**
+     * Get Parent ContainerBase to add its child component 
+     * from parent's ObjectName
+     */
+    private ContainerBase getParentContainerFromParent(ObjectName pname) 
+        throws Exception {
+        
+        String type = pname.getKeyProperty("type");
+        String j2eeType = pname.getKeyProperty("j2eeType");
+        Service service = getService(pname);
+        StandardEngine engine = (StandardEngine) service.getContainer();
+        if ((j2eeType!=null) && (j2eeType.equals("WebModule"))) {
+            String name = pname.getKeyProperty("name");
+            name = name.substring(2);
+            int i = name.indexOf("/");
+            String hostName = name.substring(0,i);
+            String path = name.substring(i);
+            Host host = (Host) engine.findChild(hostName);
+            String pathStr = getPathStr(path);
+            StandardContext context = (StandardContext)host.findChild(pathStr);
+            return context;
+        } else if (type != null) {
+            if (type.equals("Engine")) {
+                return engine;
+            } else if (type.equals("Host")) {
+                String hostName = pname.getKeyProperty("host");
+                StandardHost host = (StandardHost) engine.findChild(hostName);
+                return host;
+            }
+        }
+        return null;
+        
+    }
+
+
+    /**
+     * Get Parent ContainerBase to add its child component 
+     * from child component's ObjectName  as a String
+     */    
+    private ContainerBase getParentContainerFromChild(ObjectName oname) 
+        throws Exception {
+        
+        String hostName = oname.getKeyProperty("host");
+        String path = oname.getKeyProperty("path");
+        Service service = getService(oname);
+        StandardEngine engine = (StandardEngine) service.getContainer();
+        if (hostName == null) {             
+            // child's container is Engine
+            return engine;
+        } else if (path == null) {      
+            // child's container is Host
+            StandardHost host = (StandardHost) engine.findChild(hostName);
+            return host;
+        } else {                
+            // child's container is Context
+            StandardHost host = (StandardHost) engine.findChild(hostName);
+            path = getPathStr(path);
+            StandardContext context = (StandardContext) host.findChild(path);
+            return context;
+        }
+    }
+
+    
+    private Service getService(ObjectName oname) throws Exception {
+    
+        String domain = oname.getDomain();
+        Server server = ServerFactory.getServer();
+        Service[] services = server.findServices();
+        StandardService service = null;
+        for (int i = 0; i < services.length; i++) {
+            service = (StandardService) services[i];
+            if (domain.equals(service.getObjectName().getDomain())) {
+                break;
+            }
+        }
+        if (!service.getObjectName().getDomain().equals(domain)) {
+            throw new Exception("Service with the domain is not found");
+        }        
+        return service;
+
+    }
+    
+    
+    /**
+     * Create a new AccessLoggerValve.
+     *
+     * @param parent MBean Name of the associated parent component
+     *
+     * @exception Exception if an MBean cannot be created or registered
+     */
+    public String createAccessLoggerValve(String parent)
+        throws Exception {
+
+        ObjectName pname = new ObjectName(parent);
+        // Create a new AccessLogValve instance
+        AccessLogValve accessLogger = new AccessLogValve();
+        ContainerBase containerBase = getParentContainerFromParent(pname);
+        // Add the new instance to its parent component
+        containerBase.addValve(accessLogger);
+        ObjectName oname = accessLogger.getObjectName();
+        return (oname.toString());
+
+    }
+        
+
+    /**
+     * Create a new AjpConnector
+     *
+     * @param parent MBean Name of the associated parent component
+     * @param address The IP address on which to bind
+     * @param port TCP port number to listen on
+     *
+     * @exception Exception if an MBean cannot be created or registered
+     */
+    public String createAjpConnector(String parent, String address, int port)
+        throws Exception {
+
+        return createConnector(parent, address, port, true, false);
+    }
+    
+    /**
+     * Create a new DataSource Realm.
+     *
+     * @param parent MBean Name of the associated parent component
+     *
+     * @exception Exception if an MBean cannot be created or registered
+     */
+    public String createDataSourceRealm(String parent, String dataSourceName, 
+        String roleNameCol, String userCredCol, String userNameCol, 
+        String userRoleTable, String userTable) throws Exception {
+
+        // Create a new DataSourceRealm instance
+        DataSourceRealm realm = new DataSourceRealm();
+        realm.setDataSourceName(dataSourceName);
+        realm.setRoleNameCol(roleNameCol);
+        realm.setUserCredCol(userCredCol);
+        realm.setUserNameCol(userNameCol);
+        realm.setUserRoleTable(userRoleTable);
+        realm.setUserTable(userTable);
+
+        // Add the new instance to its parent component
+        ObjectName pname = new ObjectName(parent);
+        ContainerBase containerBase = getParentContainerFromParent(pname);
+        // Add the new instance to its parent component
+        containerBase.setRealm(realm);
+        // Return the corresponding MBean name
+        ObjectName oname = realm.getObjectName();
+        if (oname != null) {
+            return (oname.toString());
+        } else {
+            return null;
+        }   
+
+    }
+
+    /**
+     * Create a new HttpConnector
+     *
+     * @param parent MBean Name of the associated parent component
+     * @param address The IP address on which to bind
+     * @param port TCP port number to listen on
+     *
+     * @exception Exception if an MBean cannot be created or registered
+     */
+    public String createHttpConnector(String parent, String address, int port)
+        throws Exception {
+	return createConnector(parent, address, port, false, false);
+    }
+
+    /**
+     * Create a new Connector
+     *
+     * @param parent MBean Name of the associated parent component
+     * @param address The IP address on which to bind
+     * @param port TCP port number to listen on
+     * @param isAjp Create a AJP/1.3 Connector
+     * @param isSSL Create a secure Connector
+     *
+     * @exception Exception if an MBean cannot be created or registered
+     */
+    private String createConnector(String parent, String address, int port, boolean isAjp, boolean isSSL)
+        throws Exception {
+        Connector retobj = new Connector();
+        if ((address!=null) && (address.length()>0)) {
+            retobj.setProperty("address", address);
+        }
+        // Set port number
+        retobj.setPort(port);
+        // Set the protocol
+        retobj.setProtocol(isAjp ? "AJP/1.3" : "HTTP/1.1");
+        // Set SSL
+        retobj.setSecure(isSSL);
+        retobj.setScheme(isSSL ? "https" : "http");
+        // Add the new instance to its parent component
+        // FIX ME - addConnector will fail
+        ObjectName pname = new ObjectName(parent);
+        Service service = getService(pname);
+        service.addConnector(retobj);
+        
+        // Return the corresponding MBean name
+        ObjectName coname = retobj.getObjectName();
+        
+        return (coname.toString());
+    }
+
+
+    /**
+     * Create a new HttpsConnector
+     *
+     * @param parent MBean Name of the associated parent component
+     * @param address The IP address on which to bind
+     * @param port TCP port number to listen on
+     *
+     * @exception Exception if an MBean cannot be created or registered
+     */
+    public String createHttpsConnector(String parent, String address, int port)
+        throws Exception {
+        return createConnector(parent, address, port, false, true);
+    }
+
+    /**
+     * Create a new JDBC Realm.
+     *
+     * @param parent MBean Name of the associated parent component
+     *
+     * @exception Exception if an MBean cannot be created or registered
+     */
+    public String createJDBCRealm(String parent, String driverName, 
+    	String connectionName, String connectionPassword, String connectionURL)
+        throws Exception {
+
+        // Create a new JDBCRealm instance
+        JDBCRealm realm = new JDBCRealm();
+        realm.setDriverName(driverName);
+        realm.setConnectionName(connectionName);
+        realm.setConnectionPassword(connectionPassword);
+        realm.setConnectionURL(connectionURL);
+
+        // Add the new instance to its parent component
+        ObjectName pname = new ObjectName(parent);
+        ContainerBase containerBase = getParentContainerFromParent(pname);
+        // Add the new instance to its parent component
+        containerBase.setRealm(realm);
+        // Return the corresponding MBean name
+        ObjectName oname = realm.getObjectName();
+
+        if (oname != null) {
+            return (oname.toString());
+        } else {
+            return null;
+        }   
+
+    }
+
+
+    /**
+     * Create a new JNDI Realm.
+     *
+     * @param parent MBean Name of the associated parent component
+     *
+     * @exception Exception if an MBean cannot be created or registered
+     */
+    public String createJNDIRealm(String parent,String connectionURL,String connectionName,String connectionPassword)
+        throws Exception {
+
+         // Create a new JNDIRealm instance
+        JNDIRealm realm = new JNDIRealm();
+				realm.setConnectionURL(connectionURL);
+				realm.setConnectionName(connectionName);
+				realm.setConnectionPassword(connectionPassword);
+        // Add the new instance to its parent component
+        ObjectName pname = new ObjectName(parent);
+        ContainerBase containerBase = getParentContainerFromParent(pname);
+        // Add the new instance to its parent component
+        containerBase.setRealm(realm);
+        // Return the corresponding MBean name
+        ObjectName oname = realm.getObjectName();
+
+        if (oname != null) {
+            return (oname.toString());
+        } else {
+            return null;
+        }   
+
+
+    }
+		
+  /**
+     * Create a new JAAS Realm.
+     *
+     * @param parent MBean Name of the associated parent component
+     *
+     * @exception Exception if an MBean cannot be created or registered
+     */
+    public String createJAASRealm(String parent,String appName,String userClassNames,String roleClassNames,String useContextClassLoader)
+        throws Exception {
+
+         // Create a new JAASRealm instance
+        JAASRealm realm = new JAASRealm();
+				realm.setAppName(appName);
+				realm.setUserClassNames(userClassNames);
+				realm.setRoleClassNames(roleClassNames);
+				if("true".equals(useContextClassLoader)||"TRUE".equals(useContextClassLoader)){
+						realm.setUseContextClassLoader(true);
+				}
+				else{
+						realm.setUseContextClassLoader(false);
+				}
+        // Add the new instance to its parent component
+        ObjectName pname = new ObjectName(parent);
+        ContainerBase containerBase = getParentContainerFromParent(pname);
+        // Add the new instance to its parent component
+        containerBase.setRealm(realm);
+        // Return the corresponding MBean name
+        ObjectName oname = realm.getObjectName();
+
+        if (oname != null) {
+            return (oname.toString());
+        } else {
+            return null;
+        }   
+
+
+    }
+
+    /**
+     * Create a new Memory Realm.
+     *
+     * @param parent MBean Name of the associated parent component
+     *
+     * @exception Exception if an MBean cannot be created or registered
+     */
+    public String createMemoryRealm(String parent)
+        throws Exception {
+
+         // Create a new MemoryRealm instance
+        MemoryRealm realm = new MemoryRealm();
+
+        // Add the new instance to its parent component
+        ObjectName pname = new ObjectName(parent);
+        ContainerBase containerBase = getParentContainerFromParent(pname);
+        // Add the new instance to its parent component
+        containerBase.setRealm(realm);
+        // Return the corresponding MBean name
+        ObjectName oname = realm.getObjectName();
+        if (oname != null) {
+            return (oname.toString());
+        } else {
+            return null;
+        }   
+
+    }
+
+
+    /**
+     * Create a new Remote Address Filter Valve.
+     *
+     * @param parent MBean Name of the associated parent component
+     *
+     * @exception Exception if an MBean cannot be created or registered
+     */
+    public String createRemoteAddrValve(String parent)
+        throws Exception {
+
+        // Create a new RemoteAddrValve instance
+        RemoteAddrValve valve = new RemoteAddrValve();
+
+        // Add the new instance to its parent component
+        ObjectName pname = new ObjectName(parent);
+        ContainerBase containerBase = getParentContainerFromParent(pname);
+        containerBase.addValve(valve);
+        ObjectName oname = valve.getObjectName();
+        return (oname.toString());
+
+    }
+
+
+     /**
+     * Create a new Remote Host Filter Valve.
+     *
+     * @param parent MBean Name of the associated parent component
+     *
+     * @exception Exception if an MBean cannot be created or registered
+     */
+    public String createRemoteHostValve(String parent)
+        throws Exception {
+
+        // Create a new RemoteHostValve instance
+        RemoteHostValve valve = new RemoteHostValve();
+
+        // Add the new instance to its parent component
+        ObjectName pname = new ObjectName(parent);
+        ContainerBase containerBase = getParentContainerFromParent(pname);
+        containerBase.addValve(valve);
+        ObjectName oname = valve.getObjectName();
+        return (oname.toString());
+        
+    }
+
+
+    /**
+     * Create a new Request Dumper Valve.
+     *
+     * @param parent MBean Name of the associated parent component
+     *
+     * @exception Exception if an MBean cannot be created or registered
+     */
+    public String createRequestDumperValve(String parent)
+        throws Exception {
+
+        // Create a new RequestDumperValve instance
+        RequestDumperValve valve = new RequestDumperValve();
+
+        // Add the new instance to its parent component
+        ObjectName pname = new ObjectName(parent);
+        ContainerBase containerBase = getParentContainerFromParent(pname);
+        containerBase.addValve(valve);
+        ObjectName oname = valve.getObjectName();
+        return (oname.toString());
+
+    }
+
+
+    /**
+     * Create a new Single Sign On Valve.
+     *
+     * @param parent MBean Name of the associated parent component
+     *
+     * @exception Exception if an MBean cannot be created or registered
+     */
+    public String createSingleSignOn(String parent)
+        throws Exception {
+
+        // Create a new SingleSignOn instance
+        SingleSignOn valve = new SingleSignOn();
+
+        // Add the new instance to its parent component
+        ObjectName pname = new ObjectName(parent);
+        ContainerBase containerBase = getParentContainerFromParent(pname);
+        containerBase.addValve(valve);
+        ObjectName oname = valve.getObjectName();
+        return (oname.toString());
+
+    }
+    
+    
+   /**
+     * Create a new StandardContext.
+     *
+     * @param parent MBean Name of the associated parent component
+     * @param path The context path for this Context
+     * @param docBase Document base directory (or WAR) for this Context
+     *
+     * @exception Exception if an MBean cannot be created or registered
+     */
+    public String createStandardContext(String parent, 
+                                        String path,
+                                        String docBase)
+        throws Exception {
+                                            
+        // XXX for backward compatibility. Remove it once supported by the admin
+        return 
+            createStandardContext(parent,path,docBase,false,false,false,false);                                  
+    }
+
+    /**
+     * Given a context path, get the config file name.
+     */
+    private String getConfigFile(String path) {
+        String basename = null;
+        if (path.equals("")) {
+            basename = "ROOT";
+        } else {
+            basename = path.substring(1).replace('/', '#');
+        }
+        return (basename);
+    }
+
+   /**
+     * Create a new StandardContext.
+     *
+     * @param parent MBean Name of the associated parent component
+     * @param path The context path for this Context
+     * @param docBase Document base directory (or WAR) for this Context
+     *
+     * @exception Exception if an MBean cannot be created or registered
+     */
+    public String createStandardContext(String parent, 
+                                        String path,
+                                        String docBase,
+                                        boolean xmlValidation,
+                                        boolean xmlNamespaceAware,
+                                        boolean tldValidation,
+                                        boolean tldNamespaceAware)
+        throws Exception {
+
+        // Create a new StandardContext instance
+        StandardContext context = new StandardContext();
+        path = getPathStr(path);
+        context.setPath(path);
+        context.setDocBase(docBase);
+        context.setXmlValidation(xmlValidation);
+        context.setXmlNamespaceAware(xmlNamespaceAware);
+        context.setTldValidation(tldValidation);
+        context.setTldNamespaceAware(tldNamespaceAware);
+        
+        ContextConfig contextConfig = new ContextConfig();
+        context.addLifecycleListener(contextConfig);
+
+        // Add the new instance to its parent component
+        ObjectName pname = new ObjectName(parent);
+        ObjectName deployer = new ObjectName(pname.getDomain()+
+                                             ":type=Deployer,host="+
+                                             pname.getKeyProperty("host"));
+        if(mserver.isRegistered(deployer)) {
+            String contextPath = context.getPath();
+            mserver.invoke(deployer, "addServiced",
+                           new Object [] {contextPath},
+                           new String [] {"java.lang.String"});
+            String configPath = (String)mserver.getAttribute(deployer,
+                                                             "configBaseName");
+            String baseName = getConfigFile(contextPath);
+            File configFile = new File(new File(configPath), baseName+".xml");
+            context.setConfigFile(configFile.getAbsolutePath());
+            mserver.invoke(deployer, "manageApp",
+                           new Object[] {context},
+                           new String[] {"org.apache.catalina.Context"});
+            mserver.invoke(deployer, "removeServiced",
+                           new Object [] {contextPath},
+                           new String [] {"java.lang.String"});
+        } else {
+            log.warn("Deployer not found for "+pname.getKeyProperty("host"));
+            Service service = getService(pname);
+            Engine engine = (Engine) service.getContainer();
+            Host host = (Host) engine.findChild(pname.getKeyProperty("host"));
+            host.addChild(context);
+        }
+
+        // Return the corresponding MBean name
+        ObjectName oname = context.getJmxName();
+
+        return (oname.toString());
+
+    }
+
+
+   /**
+     * Create a new StandardEngine.
+     *
+     * @param parent MBean Name of the associated parent component
+     * @param engineName Unique name of this Engine
+     * @param defaultHost Default hostname of this Engine
+     * @param serviceName Unique name of this Service
+     *
+     * @exception Exception if an MBean cannot be created or registered
+     */
+
+    public Vector createStandardEngineService(String parent, 
+            String engineName, String defaultHost, String serviceName)
+        throws Exception {
+
+        // Create a new StandardService instance
+        StandardService service = new StandardService();
+        service.setName(serviceName);
+        // Create a new StandardEngine instance
+        StandardEngine engine = new StandardEngine();
+        engine.setName(engineName);
+        engine.setDefaultHost(defaultHost);
+        // Need to set engine before adding it to server in order to set domain
+        service.setContainer(engine);
+        // Add the new instance to its parent component
+        Server server = ServerFactory.getServer();
+        server.addService(service);
+        Vector onames = new Vector();
+        // FIXME service & engine.getObjectName
+        //ObjectName oname = engine.getObjectName();
+        ObjectName oname = 
+            MBeanUtils.createObjectName(engineName, engine);
+        onames.add(0, oname);
+        //oname = service.getObjectName();
+        oname = 
+            MBeanUtils.createObjectName(engineName, service);
+        onames.add(1, oname);
+        return (onames);
+
+    }
+
+
+    /**
+     * Create a new StandardHost.
+     *
+     * @param parent MBean Name of the associated parent component
+     * @param name Unique name of this Host
+     * @param appBase Application base directory name
+     * @param autoDeploy Should we auto deploy?
+     * @param deployOnStartup Deploy on server startup?
+     * @param deployXML Should we deploy Context XML config files property?
+     * @param unpackWARs Should we unpack WARs when auto deploying?
+     * @param xmlNamespaceAware Should we turn on/off XML namespace awareness?
+     * @param xmlValidation Should we turn on/off XML validation?        
+     *
+     * @exception Exception if an MBean cannot be created or registered
+     */
+    public String createStandardHost(String parent, String name,
+                                     String appBase,
+                                     boolean autoDeploy,
+                                     boolean deployOnStartup,
+                                     boolean deployXML,                                       
+                                     boolean unpackWARs,
+                                     boolean xmlNamespaceAware,
+                                     boolean xmlValidation)
+        throws Exception {
+
+        // Create a new StandardHost instance
+        StandardHost host = new StandardHost();
+        host.setName(name);
+        host.setAppBase(appBase);
+        host.setAutoDeploy(autoDeploy);
+        host.setDeployOnStartup(deployOnStartup);
+        host.setDeployXML(deployXML);
+        host.setUnpackWARs(unpackWARs);
+        host.setXmlNamespaceAware(xmlNamespaceAware);
+        host.setXmlValidation(xmlValidation);
+	
+        // add HostConfig for active reloading
+        HostConfig hostConfig = new HostConfig();
+        host.addLifecycleListener(hostConfig);
+
+        // Add the new instance to its parent component
+        ObjectName pname = new ObjectName(parent);
+        Service service = getService(pname);
+        Engine engine = (Engine) service.getContainer();
+        engine.addChild(host);
+
+        // Return the corresponding MBean name
+        return (host.getObjectName().toString());
+
+    }
+
+
+    /**
+     * Create a new StandardManager.
+     *
+     * @param parent MBean Name of the associated parent component
+     *
+     * @exception Exception if an MBean cannot be created or registered
+     */
+    public String createStandardManager(String parent)
+        throws Exception {
+
+        // Create a new StandardManager instance
+        StandardManager manager = new StandardManager();
+
+        // Add the new instance to its parent component
+        ObjectName pname = new ObjectName(parent);
+        ContainerBase containerBase = getParentContainerFromParent(pname);
+        if (containerBase != null) {
+            containerBase.setManager(manager);
+        } 
+        ObjectName oname = manager.getObjectName();
+        if (oname != null) {
+            return (oname.toString());
+        } else {
+            return null;
+        }
+        
+    }
+
+
+    /**
+     * Create a new StandardService.
+     *
+     * @param parent MBean Name of the associated parent component
+     * @param name Unique name of this StandardService
+     *
+     * @exception Exception if an MBean cannot be created or registered
+     */
+    public String createStandardService(String parent, String name, String domain)
+        throws Exception {
+
+        // Create a new StandardService instance
+        StandardService service = new StandardService();
+        service.setName(name);
+
+        // Add the new instance to its parent component
+        Server server = ServerFactory.getServer();
+        server.addService(service);
+
+        // Return the corresponding MBean name
+        return (service.getObjectName().toString());
+
+    }
+
+
+
+    /**
+     * Create a new  UserDatabaseRealm.
+     *
+     * @param parent MBean Name of the associated parent component
+     * @param resourceName Global JNDI resource name of the associated
+     *  UserDatabase
+     *
+     * @exception Exception if an MBean cannot be created or registered
+     */
+    public String createUserDatabaseRealm(String parent, String resourceName)
+        throws Exception {
+
+         // Create a new UserDatabaseRealm instance
+        UserDatabaseRealm realm = new UserDatabaseRealm();
+        realm.setResourceName(resourceName);
+        
+        // Add the new instance to its parent component
+        ObjectName pname = new ObjectName(parent);
+        ContainerBase containerBase = getParentContainerFromParent(pname);
+        // Add the new instance to its parent component
+        containerBase.setRealm(realm);
+        // Return the corresponding MBean name
+        ObjectName oname = realm.getObjectName();
+        // FIXME getObjectName() returns null
+        //ObjectName oname = 
+        //    MBeanUtils.createObjectName(pname.getDomain(), realm);
+        if (oname != null) {
+            return (oname.toString());
+        } else {
+            return null;
+        }   
+
+    }
+
+
+    /**
+     * Create a new Web Application Loader.
+     *
+     * @param parent MBean Name of the associated parent component
+     *
+     * @exception Exception if an MBean cannot be created or registered
+     */
+    public String createWebappLoader(String parent)
+        throws Exception {
+
+        // Create a new WebappLoader instance
+        WebappLoader loader = new WebappLoader();
+
+        // Add the new instance to its parent component
+        ObjectName pname = new ObjectName(parent);
+        ContainerBase containerBase = getParentContainerFromParent(pname);
+        if (containerBase != null) {
+            containerBase.setLoader(loader);
+        } 
+        // FIXME add Loader.getObjectName
+        //ObjectName oname = loader.getObjectName();
+        ObjectName oname = 
+            MBeanUtils.createObjectName(pname.getDomain(), loader);
+        return (oname.toString());
+        
+    }
+
+
+    /**
+     * Remove an existing Connector.
+     *
+     * @param name MBean Name of the component to remove
+     *
+     * @exception Exception if a component cannot be removed
+     */
+    public void removeConnector(String name) throws Exception {
+
+        // Acquire a reference to the component to be removed
+        ObjectName oname = new ObjectName(name);
+        Server server = ServerFactory.getServer();
+        Service service = getService(oname);
+        String port = oname.getKeyProperty("port");
+        //String address = oname.getKeyProperty("address");
+
+        Connector conns[] = (Connector[]) service.findConnectors();
+
+        for (int i = 0; i < conns.length; i++) {
+            String connAddress = String.valueOf(conns[i].getProperty("address"));
+            String connPort = ""+conns[i].getPort();
+
+            // if (((address.equals("null")) &&
+            if ((connAddress==null) && port.equals(connPort)) {
+                service.removeConnector(conns[i]);
+                conns[i].destroy();
+                break;
+            }
+            // } else if (address.equals(connAddress))
+            if (port.equals(connPort)) {
+                // Remove this component from its parent component
+                service.removeConnector(conns[i]);
+                conns[i].destroy();
+                break;
+            }
+        }
+
+    }
+
+
+    /**
+     * Remove an existing Context.
+     *
+     * @param contextName MBean Name of the comonent to remove
+     *
+     * @exception Exception if a component cannot be removed
+     */
+    public void removeContext(String contextName) throws Exception {
+
+        // Acquire a reference to the component to be removed
+        ObjectName oname = new ObjectName(contextName);
+        String domain = oname.getDomain();
+        StandardService service = (StandardService) getService(oname);
+
+        Engine engine = (Engine) service.getContainer();
+        String name = oname.getKeyProperty("name");
+        name = name.substring(2);
+        int i = name.indexOf("/");
+        String hostName = name.substring(0,i);
+        String path = name.substring(i);
+        ObjectName deployer = new ObjectName(domain+":type=Deployer,host="+
+                                             hostName);
+        String pathStr = getPathStr(path);
+        if(mserver.isRegistered(deployer)) {
+            mserver.invoke(deployer,"addServiced",
+                           new Object[]{pathStr},
+                           new String[] {"java.lang.String"});
+            mserver.invoke(deployer,"unmanageApp",
+                           new Object[] {pathStr},
+                           new String[] {"java.lang.String"});
+            mserver.invoke(deployer,"removeServiced",
+                           new Object[] {pathStr},
+                           new String[] {"java.lang.String"});
+        } else {
+            log.warn("Deployer not found for "+hostName);
+            Host host = (Host) engine.findChild(hostName);
+            Context context = (Context) host.findChild(pathStr);
+            // Remove this component from its parent component
+            host.removeChild(context);
+            if(context instanceof StandardContext)
+            try {
+                ((StandardContext)context).destroy();
+            } catch (Exception e) {
+                log.warn("Error during context [" + context.getName() + "] destroy ", e);
+           }
+   
+        }
+
+    }
+
+
+    /**
+     * Remove an existing Host.
+     *
+     * @param name MBean Name of the comonent to remove
+     *
+     * @exception Exception if a component cannot be removed
+     */
+    public void removeHost(String name) throws Exception {
+
+        // Acquire a reference to the component to be removed
+        ObjectName oname = new ObjectName(name);
+        String hostName = oname.getKeyProperty("host");
+        Service service = getService(oname);
+        Engine engine = (Engine) service.getContainer();
+        Host host = (Host) engine.findChild(hostName);
+
+        // Remove this component from its parent component
+        if(host!=null) {
+            if(host instanceof StandardHost)
+                ((StandardHost)host).destroy();
+            else
+                engine.removeChild(host);
+        }
+
+    }
+
+
+    /**
+     * Remove an existing Loader.
+     *
+     * @param name MBean Name of the comonent to remove
+     *
+     * @exception Exception if a component cannot be removed
+     */
+    public void removeLoader(String name) throws Exception {
+
+        ObjectName oname = new ObjectName(name);
+        // Acquire a reference to the component to be removed
+        ContainerBase container = getParentContainerFromChild(oname);    
+        container.setLoader(null);
+        
+    }
+
+
+    /**
+     * Remove an existing Manager.
+     *
+     * @param name MBean Name of the comonent to remove
+     *
+     * @exception Exception if a component cannot be removed
+     */
+    public void removeManager(String name) throws Exception {
+
+        ObjectName oname = new ObjectName(name);
+        // Acquire a reference to the component to be removed
+        ContainerBase container = getParentContainerFromChild(oname);    
+        container.setManager(null);
+
+    }
+
+
+    /**
+     * Remove an existing Realm.
+     *
+     * @param name MBean Name of the comonent to remove
+     *
+     * @exception Exception if a component cannot be removed
+     */
+    public void removeRealm(String name) throws Exception {
+
+        ObjectName oname = new ObjectName(name);
+        // Acquire a reference to the component to be removed
+        ContainerBase container = getParentContainerFromChild(oname); 
+        container.setRealm(null);
+    }
+
+
+    /**
+     * Remove an existing Service.
+     *
+     * @param name MBean Name of the component to remove
+     *
+     * @exception Exception if a component cannot be removed
+     */
+    public void removeService(String name) throws Exception {
+
+        // Acquire a reference to the component to be removed
+        ObjectName oname = new ObjectName(name);
+        String serviceName = oname.getKeyProperty("serviceName");
+        Server server = ServerFactory.getServer();
+        Service service = server.findService(serviceName);
+
+        // Remove this component from its parent component
+        server.removeService(service);
+
+    }
+
+
+    /**
+     * Remove an existing Valve.
+     *
+     * @param name MBean Name of the comonent to remove
+     *
+     * @exception Exception if a component cannot be removed
+     */
+    public void removeValve(String name) throws Exception {
+
+        // Acquire a reference to the component to be removed
+        ObjectName oname = new ObjectName(name);
+        ContainerBase container = getParentContainerFromChild(oname);
+        String sequence = oname.getKeyProperty("seq");
+        Valve[] valves = (Valve[])container.getValves();
+        for (int i = 0; i < valves.length; i++) {
+            ObjectName voname = ((ValveBase) valves[i]).getObjectName();
+            if (voname.equals(oname)) {
+                container.removeValve(valves[i]);
+            }
+        }
+    }
+
+}
+

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/mbeans/MBeanUtils.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/mbeans/MBeanUtils.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/mbeans/MBeanUtils.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,1872 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.mbeans;
+
+
+import java.util.Hashtable;
+
+import javax.management.MBeanException;
+import javax.management.MBeanServer;
+import javax.management.MalformedObjectNameException;
+import javax.management.ObjectName;
+import javax.management.modelmbean.ModelMBean;
+
+import org.apache.catalina.Contained;
+import org.apache.catalina.Container;
+import org.apache.catalina.Context;
+import org.apache.catalina.Engine;
+import org.apache.catalina.Group;
+import org.apache.catalina.Host;
+import org.apache.catalina.Loader;
+import org.apache.catalina.Manager;
+import org.apache.catalina.Realm;
+import org.apache.catalina.Role;
+import org.apache.catalina.Server;
+import org.apache.catalina.Service;
+import org.apache.catalina.User;
+import org.apache.catalina.UserDatabase;
+import org.apache.catalina.Valve;
+import org.apache.catalina.connector.Connector;
+import org.apache.catalina.deploy.ContextEnvironment;
+import org.apache.catalina.deploy.ContextResource;
+import org.apache.catalina.deploy.ContextResourceLink;
+import org.apache.catalina.deploy.NamingResources;
+import org.apache.catalina.valves.ValveBase;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.commons.modeler.ManagedBean;
+import org.apache.commons.modeler.Registry;
+import org.apache.tomcat.util.IntrospectionUtils;
+
+
+/**
+ * Public utility methods in support of the server side MBeans implementation.
+ *
+ * @author Craig R. McClanahan
+ * @author Amy Roh
+ * @version $Revision: 303558 $ $Date: 2004-12-01 05:17:34 -0600 (Wed, 01 Dec 2004) $
+ */
+
+public class MBeanUtils {
+    private static Log log = LogFactory.getLog(MBeanUtils.class);
+
+    // ------------------------------------------------------- Static Variables
+
+
+    /**
+     * The set of exceptions to the normal rules used by
+     * <code>createManagedBean()</code>.  The first element of each pair
+     * is a class name, and the second element is the managed bean name.
+     */
+    private static String exceptions[][] = {
+        { "org.apache.ajp.tomcat4.Ajp13Connector",
+          "Ajp13Connector" },
+        { "org.apache.coyote.tomcat4.Ajp13Connector",
+          "CoyoteConnector" },
+        { "org.apache.catalina.users.JDBCGroup",
+          "Group" },
+        { "org.apache.catalina.users.JDBCRole",
+          "Role" },
+        { "org.apache.catalina.users.JDBCUser",
+          "User" },
+        { "org.apache.catalina.users.MemoryGroup",
+          "Group" },
+        { "org.apache.catalina.users.MemoryRole",
+          "Role" },
+        { "org.apache.catalina.users.MemoryUser",
+          "User" },
+    };
+
+
+    /**
+     * The configuration information registry for our managed beans.
+     */
+    private static Registry registry = createRegistry();
+
+
+    /**
+     * The <code>MBeanServer</code> for this application.
+     */
+    private static MBeanServer mserver = createServer();
+
+
+    // --------------------------------------------------------- Static Methods
+
+    /**
+     * Create and return the name of the <code>ManagedBean</code> that
+     * corresponds to this Catalina component.
+     *
+     * @param component The component for which to create a name
+     */
+    static String createManagedName(Object component) {
+
+        // Deal with exceptions to the standard rule
+        String className = component.getClass().getName();
+        for (int i = 0; i < exceptions.length; i++) {
+            if (className.equals(exceptions[i][0])) {
+                return (exceptions[i][1]);
+            }
+        }
+
+        // Perform the standard transformation
+        int period = className.lastIndexOf('.');
+        if (period >= 0)
+            className = className.substring(period + 1);
+        return (className);
+
+    }
+
+
+    /**
+     * Create, register, and return an MBean for this
+     * <code>Connector</code> object.
+     *
+     * @param connector The Connector to be managed
+     *
+     * @exception Exception if an MBean cannot be created or registered
+     */
+    static ModelMBean createMBean(Connector connector)
+        throws Exception {
+
+        String mname = createManagedName(connector);
+        ManagedBean managed = registry.findManagedBean(mname);
+        if (managed == null) {
+            Exception e = new Exception("ManagedBean is not found with "+mname);
+            throw new MBeanException(e);
+        }
+        String domain = managed.getDomain();
+        if (domain == null)
+            domain = mserver.getDefaultDomain();
+        ModelMBean mbean = managed.createMBean(connector);
+        ObjectName oname = createObjectName(domain, connector);
+        if( mserver.isRegistered( oname ))  {
+            mserver.unregisterMBean(oname);
+        }
+        mserver.registerMBean(mbean, oname);
+        return (mbean);
+
+    }
+
+
+    /**
+     * Create, register, and return an MBean for this
+     * <code>Context</code> object.
+     *
+     * @param context The Context to be managed
+     *
+     * @exception Exception if an MBean cannot be created or registered
+     */
+    static ModelMBean createMBean(Context context)
+        throws Exception {
+
+        String mname = createManagedName(context);
+        ManagedBean managed = registry.findManagedBean(mname);
+        if (managed == null) {
+            Exception e = new Exception("ManagedBean is not found with "+mname);
+            throw new MBeanException(e);
+        }
+        String domain = managed.getDomain();
+        if (domain == null)
+            domain = mserver.getDefaultDomain();
+        ModelMBean mbean = managed.createMBean(context);
+        ObjectName oname = createObjectName(domain, context);
+        if( mserver.isRegistered(oname)) {
+            log.debug("Already registered " + oname);
+            mserver.unregisterMBean(oname);
+        }
+        mserver.registerMBean(mbean, oname);
+        return (mbean);
+
+    }
+
+    
+    /**
+     * Create, register, and return an MBean for this
+     * <code>ContextEnvironment</code> object.
+     *
+     * @param environment The ContextEnvironment to be managed
+     *
+     * @exception Exception if an MBean cannot be created or registered
+     */
+    static ModelMBean createMBean(ContextEnvironment environment)
+        throws Exception {
+
+        String mname = createManagedName(environment);
+        ManagedBean managed = registry.findManagedBean(mname);
+        if (managed == null) {
+            Exception e = new Exception("ManagedBean is not found with "+mname);
+            throw new MBeanException(e);
+        }
+        String domain = managed.getDomain();
+        if (domain == null)
+            domain = mserver.getDefaultDomain();
+        ModelMBean mbean = managed.createMBean(environment);
+        ObjectName oname = createObjectName(domain, environment);
+        if( mserver.isRegistered( oname ))  {
+            mserver.unregisterMBean(oname);
+        }
+        mserver.registerMBean(mbean, oname);
+        return (mbean);
+
+    }
+
+
+    /**
+     * Create, register, and return an MBean for this
+     * <code>ContextResource</code> object.
+     *
+     * @param resource The ContextResource to be managed
+     *
+     * @exception Exception if an MBean cannot be created or registered
+     */
+    static ModelMBean createMBean(ContextResource resource)
+        throws Exception {
+
+        String mname = createManagedName(resource);
+        ManagedBean managed = registry.findManagedBean(mname);
+        if (managed == null) {
+            Exception e = new Exception("ManagedBean is not found with "+mname);
+            throw new MBeanException(e);
+        }
+        String domain = managed.getDomain();
+        if (domain == null)
+            domain = mserver.getDefaultDomain();
+        ModelMBean mbean = managed.createMBean(resource);
+        ObjectName oname = createObjectName(domain, resource);
+        if( mserver.isRegistered( oname ))  {
+            mserver.unregisterMBean(oname);
+        }
+        mserver.registerMBean(mbean, oname);
+        return (mbean);
+
+    }
+
+
+    /**
+     * Create, register, and return an MBean for this
+     * <code>ContextResourceLink</code> object.
+     *
+     * @param resourceLink The ContextResourceLink to be managed
+     *
+     * @exception Exception if an MBean cannot be created or registered
+     */
+    static ModelMBean createMBean(ContextResourceLink resourceLink)
+        throws Exception {
+
+        String mname = createManagedName(resourceLink);
+        ManagedBean managed = registry.findManagedBean(mname);
+        if (managed == null) {
+            Exception e = new Exception("ManagedBean is not found with "+mname);
+            throw new MBeanException(e);
+        }
+        String domain = managed.getDomain();
+        if (domain == null)
+            domain = mserver.getDefaultDomain();
+        ModelMBean mbean = managed.createMBean(resourceLink);
+        ObjectName oname = createObjectName(domain, resourceLink);
+        if( mserver.isRegistered( oname ))  {
+            mserver.unregisterMBean(oname);
+        }
+        mserver.registerMBean(mbean, oname);
+        return (mbean);
+
+    }    
+ 
+    /**
+     * Create, register, and return an MBean for this
+     * <code>Engine</code> object.
+     *
+     * @param engine The Engine to be managed
+     *
+     * @exception Exception if an MBean cannot be created or registered
+     */
+    static ModelMBean createMBean(Engine engine)
+        throws Exception {
+
+        String mname = createManagedName(engine);
+        ManagedBean managed = registry.findManagedBean(mname);
+        if (managed == null) {
+            Exception e = new Exception("ManagedBean is not found with "+mname);
+            throw new MBeanException(e);
+        }
+        String domain = managed.getDomain();
+        if (domain == null)
+            domain = mserver.getDefaultDomain();
+        ModelMBean mbean = managed.createMBean(engine);
+        ObjectName oname = createObjectName(domain, engine);
+        if( mserver.isRegistered( oname ))  {
+            mserver.unregisterMBean(oname);
+        }
+        mserver.registerMBean(mbean, oname);
+        return (mbean);
+
+    }
+
+
+    /**
+     * Create, register, and return an MBean for this
+     * <code>Group</code> object.
+     *
+     * @param group The Group to be managed
+     *
+     * @exception Exception if an MBean cannot be created or registered
+     */
+    static ModelMBean createMBean(Group group)
+        throws Exception {
+
+        String mname = createManagedName(group);
+        ManagedBean managed = registry.findManagedBean(mname);
+        if (managed == null) {
+            Exception e = new Exception("ManagedBean is not found with "+mname);
+            throw new MBeanException(e);
+        }
+        String domain = managed.getDomain();
+        if (domain == null)
+            domain = mserver.getDefaultDomain();
+        ModelMBean mbean = managed.createMBean(group);
+        ObjectName oname = createObjectName(domain, group);
+        if( mserver.isRegistered( oname ))  {
+            mserver.unregisterMBean(oname);
+        }
+        mserver.registerMBean(mbean, oname);
+        return (mbean);
+
+    }
+
+
+    /**
+     * Create, register, and return an MBean for this
+     * <code>Host</code> object.
+     *
+     * @param host The Host to be managed
+     *
+     * @exception Exception if an MBean cannot be created or registered
+     */
+    static ModelMBean createMBean(Host host)
+        throws Exception {
+
+        String mname = createManagedName(host);
+        ManagedBean managed = registry.findManagedBean(mname);
+        if (managed == null) {
+            Exception e = new Exception("ManagedBean is not found with "+mname);
+            throw new MBeanException(e);
+        }
+        String domain = managed.getDomain();
+        if (domain == null)
+            domain = mserver.getDefaultDomain();
+        ModelMBean mbean = managed.createMBean(host);
+        ObjectName oname = createObjectName(domain, host);
+        if( mserver.isRegistered( oname ))  {
+            mserver.unregisterMBean(oname);
+        }
+        mserver.registerMBean(mbean, oname);
+        return (mbean);
+
+    }
+
+
+    /**
+     * Create, register, and return an MBean for this
+     * <code>Loader</code> object.
+     *
+     * @param loader The Loader to be managed
+     *
+     * @exception Exception if an MBean cannot be created or registered
+     */
+    static ModelMBean createMBean(Loader loader)
+        throws Exception {
+
+        String mname = createManagedName(loader);
+        ManagedBean managed = registry.findManagedBean(mname);
+        if (managed == null) {
+            Exception e = new Exception("ManagedBean is not found with "+mname);
+            throw new MBeanException(e);
+        }
+        String domain = managed.getDomain();
+        if (domain == null)
+            domain = mserver.getDefaultDomain();
+        ModelMBean mbean = managed.createMBean(loader);
+        ObjectName oname = createObjectName(domain, loader);
+        if( mserver.isRegistered( oname ))  {
+            // side effect: stop it
+            mserver.unregisterMBean( oname );
+        }
+        mserver.registerMBean(mbean, oname);
+        return (mbean);
+
+    }
+
+    /**
+     * Create, register, and return an MBean for this
+     * <code>Manager</code> object.
+     *
+     * @param manager The Manager to be managed
+     *
+     * @exception Exception if an MBean cannot be created or registered
+     */
+    static ModelMBean createMBean(Manager manager)
+        throws Exception {
+
+        String mname = createManagedName(manager);
+        ManagedBean managed = registry.findManagedBean(mname);
+        if (managed == null) {
+            Exception e = new Exception("ManagedBean is not found with "+mname);
+            throw new MBeanException(e);
+        }
+        String domain = managed.getDomain();
+        if (domain == null)
+            domain = mserver.getDefaultDomain();
+        ModelMBean mbean = managed.createMBean(manager);
+        ObjectName oname = createObjectName(domain, manager);
+        if( mserver.isRegistered( oname ))  {
+            mserver.unregisterMBean(oname);
+        }
+        mserver.registerMBean(mbean, oname);
+        return (mbean);
+
+    }
+
+
+    /**
+     * Create, register, and return an MBean for this
+     * <code>MBeanFactory</code> object.
+     *
+     * @param factory The MBeanFactory to be managed
+     *
+     * @exception Exception if an MBean cannot be created or registered
+     */
+    static ModelMBean createMBean(MBeanFactory factory)
+        throws Exception {
+
+        String mname = createManagedName(factory);
+        ManagedBean managed = registry.findManagedBean(mname);
+        if (managed == null) {
+            Exception e = new Exception("ManagedBean is not found with "+mname);
+            throw new MBeanException(e);
+        }
+        String domain = managed.getDomain();
+        if (domain == null)
+            domain = mserver.getDefaultDomain();
+        ModelMBean mbean = managed.createMBean(factory);
+        ObjectName oname = createObjectName(domain, factory);
+        if( mserver.isRegistered(oname )) {
+            mserver.unregisterMBean(oname);
+        }
+        mserver.registerMBean(mbean, oname);
+        return (mbean);
+
+    }
+
+
+    /**
+     * Create, register, and return an MBean for this
+     * <code>NamingResources</code> object.
+     *
+     * @param resource The NamingResources to be managed
+     *
+     * @exception Exception if an MBean cannot be created or registered
+     */
+    static ModelMBean createMBean(NamingResources resource)
+        throws Exception {
+
+        String mname = createManagedName(resource);
+        ManagedBean managed = registry.findManagedBean(mname);
+        if (managed == null) {
+            Exception e = new Exception("ManagedBean is not found with "+mname);
+            throw new MBeanException(e);
+        }
+        String domain = managed.getDomain();
+        if (domain == null)
+            domain = mserver.getDefaultDomain();
+        ModelMBean mbean = managed.createMBean(resource);
+        ObjectName oname = createObjectName(domain, resource);
+        if( mserver.isRegistered( oname ))  {
+            mserver.unregisterMBean(oname);
+        }
+        mserver.registerMBean(mbean, oname);
+        return (mbean);
+
+    }
+
+    
+    /**
+     * Create, register, and return an MBean for this
+     * <code>Realm</code> object.
+     *
+     * @param realm The Realm to be managed
+     *
+     * @exception Exception if an MBean cannot be created or registered
+     */
+    static ModelMBean createMBean(Realm realm)
+        throws Exception {
+
+        String mname = createManagedName(realm);
+        ManagedBean managed = registry.findManagedBean(mname);
+        if (managed == null) {
+            Exception e = new Exception("ManagedBean is not found with "+mname);
+            throw new MBeanException(e);
+        }
+        String domain = managed.getDomain();
+        if (domain == null)
+            domain = mserver.getDefaultDomain();
+        ModelMBean mbean = managed.createMBean(realm);
+        ObjectName oname = createObjectName(domain, realm);
+        if( mserver.isRegistered( oname ))  {
+            mserver.unregisterMBean(oname);
+        }
+        mserver.registerMBean(mbean, oname);
+        return (mbean);
+
+    }
+
+
+    /**
+     * Create, register, and return an MBean for this
+     * <code>Role</code> object.
+     *
+     * @param role The Role to be managed
+     *
+     * @exception Exception if an MBean cannot be created or registered
+     */
+    static ModelMBean createMBean(Role role)
+        throws Exception {
+
+        String mname = createManagedName(role);
+        ManagedBean managed = registry.findManagedBean(mname);
+        if (managed == null) {
+            Exception e = new Exception("ManagedBean is not found with "+mname);
+            throw new MBeanException(e);
+        }
+        String domain = managed.getDomain();
+        if (domain == null)
+            domain = mserver.getDefaultDomain();
+        ModelMBean mbean = managed.createMBean(role);
+        ObjectName oname = createObjectName(domain, role);
+        if( mserver.isRegistered( oname ))  {
+            mserver.unregisterMBean(oname);
+        }
+        mserver.registerMBean(mbean, oname);
+        return (mbean);
+
+    }
+
+
+    /**
+     * Create, register, and return an MBean for this
+     * <code>Server</code> object.
+     *
+     * @param server The Server to be managed
+     *
+     * @exception Exception if an MBean cannot be created or registered
+     */
+    static ModelMBean createMBean(Server server)
+        throws Exception {
+
+        String mname = createManagedName(server);
+        ManagedBean managed = registry.findManagedBean(mname);
+        if (managed == null) {
+            Exception e = new Exception("ManagedBean is not found with "+mname);
+            throw new MBeanException(e);
+        }
+        String domain = managed.getDomain();
+        if (domain == null)
+            domain = mserver.getDefaultDomain();
+        ModelMBean mbean = managed.createMBean(server);
+        ObjectName oname = createObjectName(domain, server);
+        if( mserver.isRegistered( oname ))  {
+            mserver.unregisterMBean(oname);
+        }
+        mserver.registerMBean(mbean, oname);
+        return (mbean);
+
+    }
+
+
+    /**
+     * Create, register, and return an MBean for this
+     * <code>Service</code> object.
+     *
+     * @param service The Service to be managed
+     *
+     * @exception Exception if an MBean cannot be created or registered
+     */
+    static ModelMBean createMBean(Service service)
+        throws Exception {
+
+        String mname = createManagedName(service);
+        ManagedBean managed = registry.findManagedBean(mname);
+        if (managed == null) {
+            Exception e = new Exception("ManagedBean is not found with "+mname);
+            throw new MBeanException(e);
+        }
+        String domain = managed.getDomain();
+        if (domain == null)
+            domain = mserver.getDefaultDomain();
+        ModelMBean mbean = managed.createMBean(service);
+        ObjectName oname = createObjectName(domain, service);
+        if( mserver.isRegistered( oname ))  {
+            mserver.unregisterMBean(oname);
+        }
+        mserver.registerMBean(mbean, oname);
+        return (mbean);
+
+    }
+
+
+    /**
+     * Create, register, and return an MBean for this
+     * <code>User</code> object.
+     *
+     * @param user The User to be managed
+     *
+     * @exception Exception if an MBean cannot be created or registered
+     */
+    static ModelMBean createMBean(User user)
+        throws Exception {
+
+        String mname = createManagedName(user);
+        ManagedBean managed = registry.findManagedBean(mname);
+        if (managed == null) {
+            Exception e = new Exception("ManagedBean is not found with "+mname);
+            throw new MBeanException(e);
+        }
+        String domain = managed.getDomain();
+        if (domain == null)
+            domain = mserver.getDefaultDomain();
+        ModelMBean mbean = managed.createMBean(user);
+        ObjectName oname = createObjectName(domain, user);
+        if( mserver.isRegistered( oname ))  {
+            mserver.unregisterMBean(oname);
+        }
+        mserver.registerMBean(mbean, oname);
+        return (mbean);
+
+    }
+
+
+    /**
+     * Create, register, and return an MBean for this
+     * <code>UserDatabase</code> object.
+     *
+     * @param userDatabase The UserDatabase to be managed
+     *
+     * @exception Exception if an MBean cannot be created or registered
+     */
+    static ModelMBean createMBean(UserDatabase userDatabase)
+        throws Exception {
+
+        String mname = createManagedName(userDatabase);
+        ManagedBean managed = registry.findManagedBean(mname);
+        if (managed == null) {
+            Exception e = new Exception("ManagedBean is not found with "+mname);
+            throw new MBeanException(e);
+        }
+        String domain = managed.getDomain();
+        if (domain == null)
+            domain = mserver.getDefaultDomain();
+        ModelMBean mbean = managed.createMBean(userDatabase);
+        ObjectName oname = createObjectName(domain, userDatabase);
+        if( mserver.isRegistered( oname ))  {
+            mserver.unregisterMBean(oname);
+        }
+        mserver.registerMBean(mbean, oname);
+        return (mbean);
+
+    }
+
+
+    /**
+     * Create, register, and return an MBean for this
+     * <code>Valve</code> object.
+     *
+     * @param valve The Valve to be managed
+     *
+     * @exception Exception if an MBean cannot be created or registered
+     */
+    static ModelMBean createMBean(Valve valve)
+        throws Exception {
+
+        String mname = createManagedName(valve);
+        ManagedBean managed = registry.findManagedBean(mname);
+        if (managed == null) {
+            Exception e = new Exception("ManagedBean is not found with "+mname);
+            throw new MBeanException(e);
+        }
+        String domain = managed.getDomain();
+        if (domain == null)
+            domain = mserver.getDefaultDomain();
+        ModelMBean mbean = managed.createMBean(valve);
+        ObjectName oname = createObjectName(domain, valve);
+        if( mserver.isRegistered( oname ))  {
+            mserver.unregisterMBean(oname);
+        }
+        mserver.registerMBean(mbean, oname);
+        return (mbean);
+
+    }
+
+    /**
+     * Create an <code>ObjectName</code> for this
+     * <code>Connector</code> object.
+     *
+     * @param domain Domain in which this name is to be created
+     * @param connector The Connector to be named
+     *
+     * @exception MalformedObjectNameException if a name cannot be created
+     */
+    static ObjectName createObjectName(String domain,
+                                        Connector connector)
+        throws MalformedObjectNameException {
+
+        ObjectName name = null;
+        if (connector.getClass().getName().indexOf("CoyoteConnector") >= 0 ) {
+            try {
+                String address = (String)
+                    IntrospectionUtils.getProperty(connector, "address");
+                Integer port = (Integer)
+                    IntrospectionUtils.getProperty(connector, "port");
+                Service service = connector.getService();
+                String serviceName = null;
+                if (service != null)
+                    serviceName = service.getName();
+                StringBuffer sb = new StringBuffer(domain);
+                sb.append(":type=Connector");
+                sb.append(",port=" + port);
+                if ((address != null) && (address.length()>0)) {
+                    sb.append(",address=" + address);
+                }
+                name = new ObjectName(sb.toString());
+                return (name);
+            } catch (Exception e) {
+                throw new MalformedObjectNameException
+                    ("Cannot create object name for " + connector+e);
+            }
+        } else {
+            throw new MalformedObjectNameException
+                ("Cannot create object name for " + connector);
+        }
+
+    }
+
+
+    /**
+     * Create an <code>ObjectName</code> for this
+     * <code>Context</code> object.
+     *
+     * @param domain Domain in which this name is to be created
+     * @param context The Context to be named
+     *
+     * @exception MalformedObjectNameException if a name cannot be created
+     */
+    static ObjectName createObjectName(String domain,
+                                              Context context)
+        throws MalformedObjectNameException {
+
+        ObjectName name = null;
+        Host host = (Host)context.getParent();
+        Service service = ((Engine)host.getParent()).getService();
+        String path = context.getPath();
+        if (path.length() < 1)
+            path = "/";
+        // FIXME 
+        name = new ObjectName(domain + ":j2eeType=WebModule,name=//" +
+                              host.getName()+ path +
+                              ",J2EEApplication=none,J2EEServer=none");
+    
+        return (name);
+
+    }
+
+    
+    /**
+     * Create an <code>ObjectName</code> for this
+     * <code>Service</code> object.
+     *
+     * @param domain Domain in which this name is to be created
+     * @param environment The ContextEnvironment to be named
+     *
+     * @exception MalformedObjectNameException if a name cannot be created
+     */
+    public static ObjectName createObjectName(String domain,
+                                              ContextEnvironment environment)
+        throws MalformedObjectNameException {
+
+        ObjectName name = null;
+        Object container = 
+                environment.getNamingResources().getContainer();
+        if (container instanceof Server) {
+            name = new ObjectName(domain + ":type=Environment" + 
+                        ",resourcetype=Global,name=" + environment.getName());
+        } else if (container instanceof Context) {        
+            String path = ((Context)container).getPath();
+            if (path.length() < 1)
+                path = "/";
+            Host host = (Host) ((Context)container).getParent();
+            Engine engine = (Engine) host.getParent();
+            Service service = engine.getService();
+            name = new ObjectName(domain + ":type=Environment" + 
+                        ",resourcetype=Context,path=" + path + 
+                        ",host=" + host.getName() +
+                        ",name=" + environment.getName());
+        }        
+        return (name);
+
+    }
+    
+    
+    /**
+     * Create an <code>ObjectName</code> for this
+     * <code>ContextResource</code> object.
+     *
+     * @param domain Domain in which this name is to be created
+     * @param resource The ContextResource to be named
+     *
+     * @exception MalformedObjectNameException if a name cannot be created
+     */
+    public static ObjectName createObjectName(String domain,
+                                              ContextResource resource)
+        throws MalformedObjectNameException {
+
+        ObjectName name = null;
+        String quotedResourceName = ObjectName.quote(resource.getName());
+        Object container = 
+                resource.getNamingResources().getContainer();
+        if (container instanceof Server) {        
+            name = new ObjectName(domain + ":type=Resource" +
+                        ",resourcetype=Global,class=" + resource.getType() + 
+                        ",name=" + quotedResourceName);
+        } else if (container instanceof Context) {                    
+            String path = ((Context)container).getPath();
+            if (path.length() < 1)
+                path = "/";
+            Host host = (Host) ((Context)container).getParent();
+            Engine engine = (Engine) host.getParent();
+            Service service = engine.getService();
+            name = new ObjectName(domain + ":type=Resource" +
+                        ",resourcetype=Context,path=" + path + 
+                        ",host=" + host.getName() +
+                        ",class=" + resource.getType() +
+                        ",name=" + quotedResourceName);
+        }
+        
+        return (name);
+
+    }
+  
+    
+     /**
+     * Create an <code>ObjectName</code> for this
+     * <code>ContextResourceLink</code> object.
+     *
+     * @param domain Domain in which this name is to be created
+     * @param resourceLink The ContextResourceLink to be named
+     *
+     * @exception MalformedObjectNameException if a name cannot be created
+     */
+    public static ObjectName createObjectName(String domain,
+                                              ContextResourceLink resourceLink)
+        throws MalformedObjectNameException {
+
+        ObjectName name = null;
+        String quotedResourceLinkName
+                = ObjectName.quote(resourceLink.getName());        
+        Object container = 
+                resourceLink.getNamingResources().getContainer();
+        if (container instanceof Server) {        
+            name = new ObjectName(domain + ":type=ResourceLink" +
+                        ",resourcetype=Global" + 
+                        ",name=" + quotedResourceLinkName);
+        } else if (container instanceof Context) {                    
+            String path = ((Context)container).getPath();
+            if (path.length() < 1)
+                path = "/";
+            Host host = (Host) ((Context)container).getParent();
+            Engine engine = (Engine) host.getParent();
+            Service service = engine.getService();
+            name = new ObjectName(domain + ":type=ResourceLink" +
+                        ",resourcetype=Context,path=" + path + 
+                        ",host=" + host.getName() +
+                        ",name=" + quotedResourceLinkName);
+        }
+        
+        return (name);
+
+    }
+    
+    
+ 
+    /**
+     * Create an <code>ObjectName</code> for this
+     * <code>Engine</code> object.
+     *
+     * @param domain Domain in which this name is to be created
+     * @param engine The Engine to be named
+     *
+     * @exception MalformedObjectNameException if a name cannot be created
+     */
+    static ObjectName createObjectName(String domain,
+                                              Engine engine)
+        throws MalformedObjectNameException {
+
+        ObjectName name = null;
+        name = new ObjectName(domain + ":type=Engine");
+        return (name);
+
+    }
+
+
+    /**
+     * Create an <code>ObjectName</code> for this
+     * <code>Group</code> object.
+     *
+     * @param domain Domain in which this name is to be created
+     * @param group The Group to be named
+     *
+     * @exception MalformedObjectNameException if a name cannot be created
+     */
+    static ObjectName createObjectName(String domain,
+                                              Group group)
+        throws MalformedObjectNameException {
+
+        ObjectName name = null;
+        name = new ObjectName(domain + ":type=Group,groupname=" +
+                              ObjectName.quote(group.getGroupname()) +
+                              ",database=" + group.getUserDatabase().getId());
+        return (name);
+
+    }
+
+
+    /**
+     * Create an <code>ObjectName</code> for this
+     * <code>Host</code> object.
+     *
+     * @param domain Domain in which this name is to be created
+     * @param host The Host to be named
+     *
+     * @exception MalformedObjectNameException if a name cannot be created
+     */
+    static ObjectName createObjectName(String domain,
+                                              Host host)
+        throws MalformedObjectNameException {
+
+        ObjectName name = null;
+        Engine engine = (Engine)host.getParent();
+        Service service = engine.getService();
+        name = new ObjectName(domain + ":type=Host,host=" +
+                              host.getName());
+        return (name);
+
+    }
+
+
+    /**
+     * Create an <code>ObjectName</code> for this
+     * <code>Loader</code> object.
+     *
+     * @param domain Domain in which this name is to be created
+     * @param loader The Loader to be named
+     *
+     * @exception MalformedObjectNameException if a name cannot be created
+     */
+    static ObjectName createObjectName(String domain,
+                                              Loader loader)
+        throws MalformedObjectNameException {
+
+        ObjectName name = null;
+        Container container = loader.getContainer();
+
+        if (container instanceof Engine) {
+            Service service = ((Engine)container).getService();
+            name = new ObjectName(domain + ":type=Loader");
+        } else if (container instanceof Host) {
+            Engine engine = (Engine) container.getParent();
+            Service service = engine.getService();
+            name = new ObjectName(domain + ":type=Loader,host=" +
+                              container.getName());
+        } else if (container instanceof Context) {
+            String path = ((Context)container).getPath();
+            if (path.length() < 1) {
+                path = "/";
+            }
+            Host host = (Host) container.getParent();
+            Engine engine = (Engine) host.getParent();
+            Service service = engine.getService();
+            name = new ObjectName(domain + ":type=Loader,path=" + path +
+                              ",host=" + host.getName());
+        }
+
+        return (name);
+
+    }
+
+
+    /**
+     * Create an <code>ObjectName</code> for this
+     * <code>Manager</code> object.
+     *
+     * @param domain Domain in which this name is to be created
+     * @param manager The Manager to be named
+     *
+     * @exception MalformedObjectNameException if a name cannot be created
+     */
+    static ObjectName createObjectName(String domain,
+                                              Manager manager)
+        throws MalformedObjectNameException {
+
+        ObjectName name = null;
+        Container container = manager.getContainer();
+
+        if (container instanceof Engine) {
+            Service service = ((Engine)container).getService();
+            name = new ObjectName(domain + ":type=Manager");
+        } else if (container instanceof Host) {
+            Engine engine = (Engine) container.getParent();
+            Service service = engine.getService();
+            name = new ObjectName(domain + ":type=Manager,host=" +
+                              container.getName());
+        } else if (container instanceof Context) {
+            String path = ((Context)container).getPath();
+            if (path.length() < 1) {
+                path = "/";
+            }
+            Host host = (Host) container.getParent();
+            Engine engine = (Engine) host.getParent();
+            Service service = engine.getService();
+            name = new ObjectName(domain + ":type=Manager,path=" + path +
+                              ",host=" + host.getName());
+        }
+
+        return (name);
+
+    }
+    
+    
+    /**
+     * Create an <code>ObjectName</code> for this
+     * <code>Server</code> object.
+     *
+     * @param domain Domain in which this name is to be created
+     * @param resources The NamingResources to be named
+     *
+     * @exception MalformedObjectNameException if a name cannot be created
+     */
+    static ObjectName createObjectName(String domain,
+                                              NamingResources resources)
+        throws MalformedObjectNameException {
+
+        ObjectName name = null;
+        Object container = resources.getContainer();        
+        if (container instanceof Server) {        
+            name = new ObjectName(domain + ":type=NamingResources" + 
+                        ",resourcetype=Global");
+        } else if (container instanceof Context) {        
+            String path = ((Context)container).getPath();
+            if (path.length() < 1)
+                path = "/";
+            Host host = (Host) ((Context)container).getParent();
+            Engine engine = (Engine) host.getParent();
+            Service service = engine.getService();
+            name = new ObjectName(domain + ":type=NamingResources" + 
+                        ",resourcetype=Context,path=" + path + 
+                        ",host=" + host.getName());
+        }
+        
+        return (name);
+
+    }
+
+
+    /**
+     * Create an <code>ObjectName</code> for this
+     * <code>MBeanFactory</code> object.
+     *
+     * @param domain Domain in which this name is to be created
+     * @param factory The MBeanFactory to be named
+     *
+     * @exception MalformedObjectNameException if a name cannot be created
+     */
+    static ObjectName createObjectName(String domain,
+                                              MBeanFactory factory)
+        throws MalformedObjectNameException {
+
+        ObjectName name = new ObjectName(domain + ":type=MBeanFactory");
+
+        return (name);
+
+    }
+
+    
+    /**
+     * Create an <code>ObjectName</code> for this
+     * <code>Realm</code> object.
+     *
+     * @param domain Domain in which this name is to be created
+     * @param realm The Realm to be named
+     *
+     * @exception MalformedObjectNameException if a name cannot be created
+     */
+    static ObjectName createObjectName(String domain,
+                                              Realm realm)
+        throws MalformedObjectNameException {
+
+        ObjectName name = null;
+        Container container = realm.getContainer();
+
+        if (container instanceof Engine) {
+            Service service = ((Engine)container).getService();
+            name = new ObjectName(domain + ":type=Realm");
+        } else if (container instanceof Host) {
+            Engine engine = (Engine) container.getParent();
+            Service service = engine.getService();
+            name = new ObjectName(domain + ":type=Realm,host=" +
+                              container.getName());
+        } else if (container instanceof Context) {
+            String path = ((Context)container).getPath();
+            if (path.length() < 1) {
+                path = "/";
+            }
+            Host host = (Host) container.getParent();
+            Engine engine = (Engine) host.getParent();
+            Service service = engine.getService();
+            name = new ObjectName(domain + ":type=Realm,path=" + path +
+                              ",host=" + host.getName());
+        }
+
+        return (name);
+
+    }
+
+
+    /**
+     * Create an <code>ObjectName</code> for this
+     * <code>Role</code> object.
+     *
+     * @param domain Domain in which this name is to be created
+     * @param role The Role to be named
+     *
+     * @exception MalformedObjectNameException if a name cannot be created
+     */
+    static ObjectName createObjectName(String domain,
+                                              Role role)
+        throws MalformedObjectNameException {
+
+        ObjectName name = null;
+        name = new ObjectName(domain + ":type=Role,rolename=" +
+                              role.getRolename() + ",database=" +
+                              role.getUserDatabase().getId());
+        return (name);
+
+    }
+
+
+    /**
+     * Create an <code>ObjectName</code> for this
+     * <code>Server</code> object.
+     *
+     * @param domain Domain in which this name is to be created
+     * @param server The Server to be named
+     *
+     * @exception MalformedObjectNameException if a name cannot be created
+     */
+    static ObjectName createObjectName(String domain,
+                                              Server server)
+        throws MalformedObjectNameException {
+
+        ObjectName name = null;
+        name = new ObjectName(domain + ":type=Server");
+        return (name);
+
+    }
+
+
+    /**
+     * Create an <code>ObjectName</code> for this
+     * <code>Service</code> object.
+     *
+     * @param domain Domain in which this name is to be created
+     * @param service The Service to be named
+     *
+     * @exception MalformedObjectNameException if a name cannot be created
+     */
+    static ObjectName createObjectName(String domain,
+                                              Service service)
+        throws MalformedObjectNameException {
+
+        ObjectName name = null;
+        name = new ObjectName(domain + ":type=Service,serviceName=" + 
+                            service.getName());
+        return (name);
+
+    }
+
+
+    /**
+     * Create an <code>ObjectName</code> for this
+     * <code>User</code> object.
+     *
+     * @param domain Domain in which this name is to be created
+     * @param user The User to be named
+     *
+     * @exception MalformedObjectNameException if a name cannot be created
+     */
+    static ObjectName createObjectName(String domain,
+                                              User user)
+        throws MalformedObjectNameException {
+
+        ObjectName name = null;
+        name = new ObjectName(domain + ":type=User,username=" +
+                              ObjectName.quote(user.getUsername())
+                              + ",database=" + user.getUserDatabase().getId());
+        return (name);
+
+    }
+
+
+    /**
+     * Create an <code>ObjectName</code> for this
+     * <code>UserDatabase</code> object.
+     *
+     * @param domain Domain in which this name is to be created
+     * @param userDatabase The UserDatabase to be named
+     *
+     * @exception MalformedObjectNameException if a name cannot be created
+     */
+    static ObjectName createObjectName(String domain,
+                                              UserDatabase userDatabase)
+        throws MalformedObjectNameException {
+
+        ObjectName name = null;
+        name = new ObjectName(domain + ":type=UserDatabase,database=" +
+                              userDatabase.getId());
+        return (name);
+
+    }
+
+
+    /**
+     * Create an <code>ObjectName</code> for this
+     * <code>Valve</code> object.
+     *
+     * @param domain Domain in which this name is to be created
+     * @param valve The Valve to be named
+     *
+     * @exception MalformedObjectNameException if a name cannot be created
+     */
+    static ObjectName createObjectName(String domain,
+                                       Valve valve)
+        throws MalformedObjectNameException {
+        if( valve instanceof ValveBase ) {
+            ObjectName name=((ValveBase)valve).getObjectName();
+            if( name != null )
+                return name;
+        }
+
+        ObjectName name = null;
+        Container container = null;
+        String className=valve.getClass().getName();
+        int period = className.lastIndexOf('.');
+        if (period >= 0)
+            className = className.substring(period + 1);
+        if( valve instanceof Contained ) {
+            container = ((Contained)valve).getContainer();
+        }
+        if( container == null ) {
+            throw new MalformedObjectNameException(
+                               "Cannot create mbean for non-contained valve " +
+                               valve);
+        }        
+        if (container instanceof Engine) {
+            Service service = ((Engine)container).getService();
+            String local="";
+            int seq = getSeq(local);
+            String ext="";
+            if( seq > 0 ) {
+                ext=",seq=" + seq;
+            }
+            name = new ObjectName(domain + ":type=Valve,name=" + className + 
+                                    ext + local );
+        } else if (container instanceof Host) {
+            Service service = ((Engine)container.getParent()).getService();
+            String local=",host=" +container.getName();
+            int seq = getSeq(local);
+            String ext="";
+            if( seq > 0 ) {
+                ext=",seq=" + seq;
+            }
+            name = new ObjectName(domain + ":type=Valve,name=" + className + 
+                                    ext + local );
+        } else if (container instanceof Context) {
+            String path = ((Context)container).getPath();
+            if (path.length() < 1) {
+                path = "/";
+            }
+            Host host = (Host) container.getParent();
+            Service service = ((Engine) host.getParent()).getService();
+            String local=",path=" + path + ",host=" +
+                    host.getName();
+            int seq = getSeq(local);
+            String ext="";
+            if( seq > 0 ) {
+                ext=",seq=" + seq;
+            }
+            name = new ObjectName(domain + ":type=Valve,name=" + className + 
+                                    ext + local );
+        }
+
+        return (name);
+
+    }
+
+    static Hashtable seq=new Hashtable();
+    static int getSeq( String key ) {
+        int i[]=(int [])seq.get( key );
+        if (i == null ) {
+            i=new int[1];
+            i[0]=0;
+            seq.put( key, i);
+        } else {
+            i[0]++;
+        }
+        return i[0];
+    }
+
+    /**
+     * Create and configure (if necessary) and return the registry of
+     * managed object descriptions.
+     */
+    public synchronized static Registry createRegistry() {
+
+        if (registry == null) {
+            registry = Registry.getRegistry(null, null);
+            ClassLoader cl=ServerLifecycleListener.class.getClassLoader();
+
+            registry.loadDescriptors("org.apache.catalina.mbeans",  cl);
+            registry.loadDescriptors("org.apache.catalina.authenticator", cl);
+            registry.loadDescriptors("org.apache.catalina.core", cl);
+            registry.loadDescriptors("org.apache.catalina", cl);
+            registry.loadDescriptors("org.apache.catalina.deploy", cl);
+            registry.loadDescriptors("org.apache.catalina.loader", cl);
+            registry.loadDescriptors("org.apache.catalina.realm", cl);
+            registry.loadDescriptors("org.apache.catalina.session", cl);
+            registry.loadDescriptors("org.apache.catalina.startup", cl);
+            registry.loadDescriptors("org.apache.catalina.users", cl);
+            registry.loadDescriptors("org.apache.catalina.cluster", cl);
+            registry.loadDescriptors("org.apache.catalina.connector", cl);
+            registry.loadDescriptors("org.apache.catalina.valves",  cl);
+        }
+        return (registry);
+
+    }
+
+
+    /**
+     * Create and configure (if necessary) and return the
+     * <code>MBeanServer</code> with which we will be
+     * registering our <code>ModelMBean</code> implementations.
+     */
+    public synchronized static MBeanServer createServer() {
+
+        if (mserver == null) {
+            try {
+                mserver = Registry.getRegistry(null, null).getMBeanServer();
+            } catch (Throwable t) {
+                t.printStackTrace(System.out);
+                System.exit(1);
+            }
+        }
+        return (mserver);
+
+    }
+
+
+    /**
+     * Deregister the MBean for this
+     * <code>Connector</code> object.
+     *
+     * @param connector The Connector to be managed
+     *
+     * @exception Exception if an MBean cannot be deregistered
+     */
+    static void destroyMBean(Connector connector, Service service)
+        throws Exception {
+
+        connector.setService(service);
+        String mname = createManagedName(connector);
+        ManagedBean managed = registry.findManagedBean(mname);
+        if (managed == null) {
+            return;
+        }
+        String domain = managed.getDomain();
+        if (domain == null)
+            domain = mserver.getDefaultDomain();
+        ObjectName oname = createObjectName(domain, connector);
+        connector.setService(null);
+        if( mserver.isRegistered( oname ))  {
+            mserver.unregisterMBean(oname);
+        }
+    }
+
+
+    /**
+     * Deregister the MBean for this
+     * <code>Context</code> object.
+     *
+     * @param context The Context to be managed
+     *
+     * @exception Exception if an MBean cannot be deregistered
+     */
+    static void destroyMBean(Context context)
+        throws Exception {
+
+        String mname = createManagedName(context);
+        ManagedBean managed = registry.findManagedBean(mname);
+        if (managed == null) {
+            return;
+        }
+        String domain = managed.getDomain();
+        if (domain == null)
+            domain = mserver.getDefaultDomain();
+        ObjectName oname = createObjectName(domain, context);
+        if( mserver.isRegistered(oname) )
+            mserver.unregisterMBean(oname);
+
+    }
+
+    
+    /**
+     * Deregister the MBean for this
+     * <code>ContextEnvironment</code> object.
+     *
+     * @param environment The ContextEnvironment to be managed
+     *
+     * @exception Exception if an MBean cannot be deregistered
+     */
+    static void destroyMBean(ContextEnvironment environment)
+        throws Exception {
+
+        String mname = createManagedName(environment);
+        ManagedBean managed = registry.findManagedBean(mname);
+        if (managed == null) {
+            return;
+        }
+        String domain = managed.getDomain();
+        if (domain == null)
+            domain = mserver.getDefaultDomain();
+        ObjectName oname = createObjectName(domain, environment);
+        if( mserver.isRegistered(oname) )
+            mserver.unregisterMBean(oname);
+
+    }
+    
+    
+    /**
+     * Deregister the MBean for this
+     * <code>ContextResource</code> object.
+     *
+     * @param resource The ContextResource to be managed
+     *
+     * @exception Exception if an MBean cannot be deregistered
+     */
+    static void destroyMBean(ContextResource resource)
+        throws Exception {
+
+        String mname = createManagedName(resource);
+        ManagedBean managed = registry.findManagedBean(mname);
+        if (managed == null) {
+            return;
+        }
+        String domain = managed.getDomain();
+        if (domain == null)
+            domain = mserver.getDefaultDomain();
+        ObjectName oname = createObjectName(domain, resource);
+        if( mserver.isRegistered(oname ))
+            mserver.unregisterMBean(oname);
+
+    }
+     
+    
+    /**
+     * Deregister the MBean for this
+     * <code>ContextResourceLink</code> object.
+     *
+     * @param resourceLink The ContextResourceLink to be managed
+     *
+     * @exception Exception if an MBean cannot be deregistered
+     */
+    static void destroyMBean(ContextResourceLink resourceLink)
+        throws Exception {
+
+        String mname = createManagedName(resourceLink);
+        ManagedBean managed = registry.findManagedBean(mname);
+        if (managed == null) {
+            return;
+        }
+        String domain = managed.getDomain();
+        if (domain == null)
+            domain = mserver.getDefaultDomain();
+        ObjectName oname = createObjectName(domain, resourceLink);
+        if( mserver.isRegistered(oname) )
+            mserver.unregisterMBean(oname);
+
+    }   
+    
+    /**
+     * Deregister the MBean for this
+     * <code>Engine</code> object.
+     *
+     * @param engine The Engine to be managed
+     *
+     * @exception Exception if an MBean cannot be deregistered
+     */
+    static void destroyMBean(Engine engine)
+        throws Exception {
+
+        String mname = createManagedName(engine);
+        ManagedBean managed = registry.findManagedBean(mname);
+        if (managed == null) {
+            return;
+        }
+        String domain = managed.getDomain();
+        if (domain == null)
+            domain = mserver.getDefaultDomain();
+        ObjectName oname = createObjectName(domain, engine);
+        if( mserver.isRegistered(oname) )
+            mserver.unregisterMBean(oname);
+
+    }
+
+
+    /**
+     * Deregister the MBean for this
+     * <code>Group</code> object.
+     *
+     * @param group The Group to be managed
+     *
+     * @exception Exception if an MBean cannot be deregistered
+     */
+    static void destroyMBean(Group group)
+        throws Exception {
+
+        String mname = createManagedName(group);
+        ManagedBean managed = registry.findManagedBean(mname);
+        if (managed == null) {
+            return;
+        }
+        String domain = managed.getDomain();
+        if (domain == null)
+            domain = mserver.getDefaultDomain();
+        ObjectName oname = createObjectName(domain, group);
+        if( mserver.isRegistered(oname) )
+            mserver.unregisterMBean(oname);
+
+    }
+
+
+    /**
+     * Deregister the MBean for this
+     * <code>Host</code> object.
+     *
+     * @param host The Host to be managed
+     *
+     * @exception Exception if an MBean cannot be deregistered
+     */
+    static void destroyMBean(Host host)
+        throws Exception {
+
+        String mname = createManagedName(host);
+        ManagedBean managed = registry.findManagedBean(mname);
+        if (managed == null) {
+            return;
+        }
+        String domain = managed.getDomain();
+        if (domain == null)
+            domain = mserver.getDefaultDomain();
+        ObjectName oname = createObjectName(domain, host);
+        if( mserver.isRegistered(oname) )
+            mserver.unregisterMBean(oname);
+
+    }
+
+
+    /**
+     * Deregister the MBean for this
+     * <code>Loader</code> object.
+     *
+     * @param loader The Loader to be managed
+     *
+     * @exception Exception if an MBean cannot be deregistered
+     */
+    static void destroyMBean(Loader loader)
+        throws Exception {
+
+        String mname = createManagedName(loader);
+        ManagedBean managed = registry.findManagedBean(mname);
+        if (managed == null) {
+            return;
+        }
+        String domain = managed.getDomain();
+        if (domain == null)
+            domain = mserver.getDefaultDomain();
+        ObjectName oname = createObjectName(domain, loader);
+        if( mserver.isRegistered(oname) )
+            mserver.unregisterMBean(oname);
+
+    }
+
+
+    /**
+     * Deregister the MBean for this
+     * <code>Manager</code> object.
+     *
+     * @param manager The Manager to be managed
+     *
+     * @exception Exception if an MBean cannot be deregistered
+     */
+    static void destroyMBean(Manager manager)
+        throws Exception {
+
+        String mname = createManagedName(manager);
+        ManagedBean managed = registry.findManagedBean(mname);
+        if (managed == null) {
+            return;
+        }
+        String domain = managed.getDomain();
+        if (domain == null)
+            domain = mserver.getDefaultDomain();
+        ObjectName oname = createObjectName(domain, manager);
+        if( mserver.isRegistered(oname) )
+            mserver.unregisterMBean(oname);
+
+    }
+    
+    
+   /**
+     * Deregister the MBean for this
+     * <code>NamingResources</code> object.
+     *
+     * @param resources The NamingResources to be managed
+     *
+     * @exception Exception if an MBean cannot be deregistered
+     */
+    static void destroyMBean(NamingResources resources)
+        throws Exception {
+
+        String mname = createManagedName(resources);
+        ManagedBean managed = registry.findManagedBean(mname);
+        if (managed == null) {
+            return;
+        }
+        String domain = managed.getDomain();
+        if (domain == null)
+            domain = mserver.getDefaultDomain();
+        ObjectName oname = createObjectName(domain, resources);
+       if( mserver.isRegistered(oname) )
+            mserver.unregisterMBean(oname);
+
+    }
+    
+    
+    /**
+     * Deregister the MBean for this
+     * <code>Realm</code> object.
+     *
+     * @param realm The Realm to be managed
+     *
+     * @exception Exception if an MBean cannot be deregistered
+     */
+    static void destroyMBean(Realm realm)
+        throws Exception {
+
+        String mname = createManagedName(realm);
+        ManagedBean managed = registry.findManagedBean(mname);
+        if (managed == null) {
+            return;
+        }
+        String domain = managed.getDomain();
+        if (domain == null)
+            domain = mserver.getDefaultDomain();
+        ObjectName oname = createObjectName(domain, realm);
+        if( mserver.isRegistered(oname) )
+            mserver.unregisterMBean(oname);
+
+    }
+
+
+    /**
+     * Deregister the MBean for this
+     * <code>Role</code> object.
+     *
+     * @param role The Role to be managed
+     *
+     * @exception Exception if an MBean cannot be deregistered
+     */
+    static void destroyMBean(Role role)
+        throws Exception {
+
+        String mname = createManagedName(role);
+        ManagedBean managed = registry.findManagedBean(mname);
+        if (managed == null) {
+            return;
+        }
+        String domain = managed.getDomain();
+        if (domain == null)
+            domain = mserver.getDefaultDomain();
+        ObjectName oname = createObjectName(domain, role);
+        if( mserver.isRegistered(oname) )
+            mserver.unregisterMBean(oname);
+
+    }
+
+
+    /**
+     * Deregister the MBean for this
+     * <code>Server</code> object.
+     *
+     * @param server The Server to be managed
+     *
+     * @exception Exception if an MBean cannot be deregistered
+     */
+    static void destroyMBean(Server server)
+        throws Exception {
+
+        String mname = createManagedName(server);
+        ManagedBean managed = registry.findManagedBean(mname);
+        if (managed == null) {
+            return;
+        }
+        String domain = managed.getDomain();
+        if (domain == null)
+            domain = mserver.getDefaultDomain();
+        ObjectName oname = createObjectName(domain, server);
+        if( mserver.isRegistered(oname) )
+            mserver.unregisterMBean(oname);
+
+    }
+
+
+    /**
+     * Deregister the MBean for this
+     * <code>Service</code> object.
+     *
+     * @param service The Service to be managed
+     *
+     * @exception Exception if an MBean cannot be deregistered
+     */
+    static void destroyMBean(Service service)
+        throws Exception {
+
+        String mname = createManagedName(service);
+        ManagedBean managed = registry.findManagedBean(mname);
+        if (managed == null) {
+            return;
+        }
+        String domain = managed.getDomain();
+        if (domain == null)
+            domain = mserver.getDefaultDomain();
+        ObjectName oname = createObjectName(domain, service);
+        if( mserver.isRegistered(oname) )
+            mserver.unregisterMBean(oname);
+
+    }
+
+
+    /**
+     * Deregister the MBean for this
+     * <code>User</code> object.
+     *
+     * @param user The User to be managed
+     *
+     * @exception Exception if an MBean cannot be deregistered
+     */
+    static void destroyMBean(User user)
+        throws Exception {
+
+        String mname = createManagedName(user);
+        ManagedBean managed = registry.findManagedBean(mname);
+        if (managed == null) {
+            return;
+        }
+        String domain = managed.getDomain();
+        if (domain == null)
+            domain = mserver.getDefaultDomain();
+        ObjectName oname = createObjectName(domain, user);
+        if( mserver.isRegistered(oname) )
+            mserver.unregisterMBean(oname);
+
+    }
+
+
+    /**
+     * Deregister the MBean for this
+     * <code>UserDatabase</code> object.
+     *
+     * @param userDatabase The UserDatabase to be managed
+     *
+     * @exception Exception if an MBean cannot be deregistered
+     */
+    static void destroyMBean(UserDatabase userDatabase)
+        throws Exception {
+
+        String mname = createManagedName(userDatabase);
+        ManagedBean managed = registry.findManagedBean(mname);
+        if (managed == null) {
+            return;
+        }
+        String domain = managed.getDomain();
+        if (domain == null)
+            domain = mserver.getDefaultDomain();
+        ObjectName oname = createObjectName(domain, userDatabase);
+        if( mserver.isRegistered(oname) )
+            mserver.unregisterMBean(oname);
+
+    }
+
+
+    /**
+     * Deregister the MBean for this
+     * <code>Valve</code> object.
+     *
+     * @param valve The Valve to be managed
+     *
+     * @exception Exception if an MBean cannot be deregistered
+     */
+    static void destroyMBean(Valve valve, Container container)
+        throws Exception {
+
+        ((Contained)valve).setContainer(container);
+        String mname = createManagedName(valve);
+        ManagedBean managed = registry.findManagedBean(mname);
+        if (managed == null) {
+            return;
+        }
+        String domain = managed.getDomain();
+        if (domain == null)
+            domain = mserver.getDefaultDomain();
+        ObjectName oname = createObjectName(domain, valve);
+        try {
+            ((Contained)valve).setContainer(null);
+        } catch (Throwable t) {
+        ;
+        }
+        if( mserver.isRegistered(oname) ) {
+            mserver.unregisterMBean(oname);
+        }
+
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/mbeans/MemoryUserDatabaseMBean.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/mbeans/MemoryUserDatabaseMBean.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/mbeans/MemoryUserDatabaseMBean.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,403 @@
+/*
+ * Copyright 2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.mbeans;
+
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import javax.management.MalformedObjectNameException;
+import javax.management.MBeanException;
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+import javax.management.RuntimeOperationsException;
+import org.apache.catalina.Group;
+import org.apache.catalina.Role;
+import org.apache.catalina.User;
+import org.apache.catalina.UserDatabase;
+import org.apache.commons.modeler.BaseModelMBean;
+import org.apache.commons.modeler.ManagedBean;
+import org.apache.commons.modeler.Registry;
+import org.apache.tomcat.util.compat.JdkCompat;
+
+/**
+ * <p>A <strong>ModelMBean</strong> implementation for the
+ * <code>org.apache.catalina.users.MemoryUserDatabase</code> component.</p>
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302833 $ $Date: 2004-04-14 20:44:09 -0500 (Wed, 14 Apr 2004) $
+ */
+
+public class MemoryUserDatabaseMBean extends BaseModelMBean {
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Construct a <code>ModelMBean</code> with default
+     * <code>ModelMBeanInfo</code> information.
+     *
+     * @exception MBeanException if the initializer of an object
+     *  throws an exception
+     * @exception RuntimeOperationsException if an IllegalArgumentException
+     *  occurs
+     */
+    public MemoryUserDatabaseMBean()
+        throws MBeanException, RuntimeOperationsException {
+
+        super();
+
+    }
+
+
+    // ----------------------------------------------------- Class Variables
+
+
+    /**
+     * JDK compatibility support
+     */
+    private static final JdkCompat jdkCompat = JdkCompat.getJdkCompat();
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The configuration information registry for our managed beans.
+     */
+    protected Registry registry = MBeanUtils.createRegistry();
+
+
+    /**
+     * The <code>MBeanServer</code> in which we are registered.
+     */
+    protected MBeanServer mserver = MBeanUtils.createServer();
+
+
+    /**
+     * The <code>ManagedBean</code> information describing this MBean.
+     */
+    protected ManagedBean managed =
+        registry.findManagedBean("MemoryUserDatabase");
+
+
+    /**
+     * The <code>ManagedBean</code> information describing Group MBeans.
+     */
+    protected ManagedBean managedGroup =
+        registry.findManagedBean("Group");
+
+
+    /**
+     * The <code>ManagedBean</code> information describing Group MBeans.
+     */
+    protected ManagedBean managedRole =
+        registry.findManagedBean("Role");
+
+
+    /**
+     * The <code>ManagedBean</code> information describing User MBeans.
+     */
+    protected ManagedBean managedUser =
+        registry.findManagedBean("User");
+
+
+    // ------------------------------------------------------------- Attributes
+
+
+    /**
+     * Return the MBean Names of all groups defined in this database.
+     */
+    public String[] getGroups() {
+
+        UserDatabase database = (UserDatabase) this.resource;
+        ArrayList results = new ArrayList();
+        Iterator groups = database.getGroups();
+        while (groups.hasNext()) {
+            Group group = (Group) groups.next();
+            results.add(findGroup(group.getGroupname()));
+        }
+        return ((String[]) results.toArray(new String[results.size()]));
+
+    }
+
+
+    /**
+     * Return the MBean Names of all roles defined in this database.
+     */
+    public String[] getRoles() {
+
+        UserDatabase database = (UserDatabase) this.resource;
+        ArrayList results = new ArrayList();
+        Iterator roles = database.getRoles();
+        while (roles.hasNext()) {
+            Role role = (Role) roles.next();
+            results.add(findRole(role.getRolename()));
+        }
+        return ((String[]) results.toArray(new String[results.size()]));
+
+    }
+
+
+    /**
+     * Return the MBean Names of all users defined in this database.
+     */
+    public String[] getUsers() {
+
+        UserDatabase database = (UserDatabase) this.resource;
+        ArrayList results = new ArrayList();
+        Iterator users = database.getUsers();
+        while (users.hasNext()) {
+            User user = (User) users.next();
+            results.add(findUser(user.getUsername()));
+        }
+        return ((String[]) results.toArray(new String[results.size()]));
+
+    }
+
+
+    // ------------------------------------------------------------- Operations
+
+
+    /**
+     * Create a new Group and return the corresponding MBean Name.
+     *
+     * @param groupname Group name of the new group
+     * @param description Description of the new group
+     */
+    public String createGroup(String groupname, String description) {
+
+        UserDatabase database = (UserDatabase) this.resource;
+        Group group = database.createGroup(groupname, description);
+        try {
+            MBeanUtils.createMBean(group);
+        } catch (Exception e) {
+            IllegalArgumentException iae = new IllegalArgumentException
+                ("Exception creating group " + group + " MBean");
+            jdkCompat.chainException(iae, e);
+            throw iae;
+        }
+        return (findGroup(groupname));
+
+    }
+
+
+    /**
+     * Create a new Role and return the corresponding MBean Name.
+     *
+     * @param rolename Group name of the new group
+     * @param description Description of the new group
+     */
+    public String createRole(String rolename, String description) {
+
+        UserDatabase database = (UserDatabase) this.resource;
+        Role role = database.createRole(rolename, description);
+        try {
+            MBeanUtils.createMBean(role);
+        } catch (Exception e) {
+            IllegalArgumentException iae = new IllegalArgumentException
+                ("Exception creating role " + role + " MBean");
+            jdkCompat.chainException(iae, e);
+            throw iae;
+        }
+        return (findRole(rolename));
+
+    }
+
+
+    /**
+     * Create a new User and return the corresponding MBean Name.
+     *
+     * @param username User name of the new user
+     * @param password Password for the new user
+     * @param fullName Full name for the new user
+     */
+    public String createUser(String username, String password,
+                             String fullName) {
+
+        UserDatabase database = (UserDatabase) this.resource;
+        User user = database.createUser(username, password, fullName);
+        try {
+            MBeanUtils.createMBean(user);
+        } catch (Exception e) {
+            IllegalArgumentException iae = new IllegalArgumentException
+                ("Exception creating user " + user + " MBean");
+            jdkCompat.chainException(iae, e);
+            throw iae;
+        }
+        return (findUser(username));
+
+    }
+
+
+    /**
+     * Return the MBean Name for the specified group name (if any);
+     * otherwise return <code>null</code>.
+     *
+     * @param groupname Group name to look up
+     */
+    public String findGroup(String groupname) {
+
+        UserDatabase database = (UserDatabase) this.resource;
+        Group group = database.findGroup(groupname);
+        if (group == null) {
+            return (null);
+        }
+        try {
+            ObjectName oname =
+                MBeanUtils.createObjectName(managedGroup.getDomain(), group);
+            return (oname.toString());
+        } catch (MalformedObjectNameException e) {
+            IllegalArgumentException iae = new IllegalArgumentException
+                ("Cannot create object name for group " + group);
+            jdkCompat.chainException(iae, e);
+            throw iae;
+        }
+
+    }
+
+
+    /**
+     * Return the MBean Name for the specified role name (if any);
+     * otherwise return <code>null</code>.
+     *
+     * @param rolename Role name to look up
+     */
+    public String findRole(String rolename) {
+
+        UserDatabase database = (UserDatabase) this.resource;
+        Role role = database.findRole(rolename);
+        if (role == null) {
+            return (null);
+        }
+        try {
+            ObjectName oname =
+                MBeanUtils.createObjectName(managedRole.getDomain(), role);
+            return (oname.toString());
+        } catch (MalformedObjectNameException e) {
+            IllegalArgumentException iae = new IllegalArgumentException
+                ("Cannot create object name for role " + role);
+            jdkCompat.chainException(iae, e);
+            throw iae;
+        }
+
+    }
+
+
+    /**
+     * Return the MBean Name for the specified user name (if any);
+     * otherwise return <code>null</code>.
+     *
+     * @param username User name to look up
+     */
+    public String findUser(String username) {
+
+        UserDatabase database = (UserDatabase) this.resource;
+        User user = database.findUser(username);
+        if (user == null) {
+            return (null);
+        }
+        try {
+            ObjectName oname =
+                MBeanUtils.createObjectName(managedUser.getDomain(), user);
+            return (oname.toString());
+        } catch (MalformedObjectNameException e) {
+            IllegalArgumentException iae = new IllegalArgumentException
+                ("Cannot create object name for user " + user);
+            jdkCompat.chainException(iae, e);
+            throw iae;
+        }
+
+    }
+
+
+    /**
+     * Remove an existing group and destroy the corresponding MBean.
+     *
+     * @param groupname Group name to remove
+     */
+    public void removeGroup(String groupname) {
+
+        UserDatabase database = (UserDatabase) this.resource;
+        Group group = database.findGroup(groupname);
+        if (group == null) {
+            return;
+        }
+        try {
+            MBeanUtils.destroyMBean(group);
+            database.removeGroup(group);
+        } catch (Exception e) {
+            IllegalArgumentException iae = new IllegalArgumentException
+                ("Exception destroying group " + group + " MBean");
+            jdkCompat.chainException(iae, e);
+            throw iae;
+        }
+
+    }
+
+
+    /**
+     * Remove an existing role and destroy the corresponding MBean.
+     *
+     * @param rolename Role name to remove
+     */
+    public void removeRole(String rolename) {
+
+        UserDatabase database = (UserDatabase) this.resource;
+        Role role = database.findRole(rolename);
+        if (role == null) {
+            return;
+        }
+        try {
+            MBeanUtils.destroyMBean(role);
+            database.removeRole(role);
+        } catch (Exception e) {
+            IllegalArgumentException iae = new IllegalArgumentException
+                ("Exception destroying role " + role + " MBean");
+            jdkCompat.chainException(iae, e);
+            throw iae;
+        }
+
+    }
+
+
+    /**
+     * Remove an existing user and destroy the corresponding MBean.
+     *
+     * @param username User name to remove
+     */
+    public void removeUser(String username) {
+
+        UserDatabase database = (UserDatabase) this.resource;
+        User user = database.findUser(username);
+        if (user == null) {
+            return;
+        }
+        try {
+            MBeanUtils.destroyMBean(user);
+            database.removeUser(user);
+        } catch (Exception e) {
+            IllegalArgumentException iae = new IllegalArgumentException
+                ("Exception destroying user " + user + " MBean");
+            jdkCompat.chainException(iae, e);
+            throw iae;
+        }
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/mbeans/NamingResourcesMBean.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/mbeans/NamingResourcesMBean.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/mbeans/NamingResourcesMBean.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,333 @@
+/*
+ * Copyright 2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.mbeans;
+
+import java.util.ArrayList;
+
+import javax.management.MBeanException;
+import javax.management.MalformedObjectNameException;
+import javax.management.ObjectName;
+import javax.management.RuntimeOperationsException;
+
+import org.apache.catalina.deploy.ContextEnvironment;
+import org.apache.catalina.deploy.ContextResource;
+import org.apache.catalina.deploy.ContextResourceLink;
+import org.apache.catalina.deploy.NamingResources;
+import org.apache.commons.modeler.BaseModelMBean;
+import org.apache.commons.modeler.ManagedBean;
+import org.apache.commons.modeler.Registry;
+import org.apache.tomcat.util.compat.JdkCompat;
+
+/**
+ * <p>A <strong>ModelMBean</strong> implementation for the
+ * <code>org.apache.catalina.deploy.NamingResources</code> component.</p>
+ *
+ * @author Amy Roh
+ * @version $Revision: 303133 $ $Date: 2004-08-29 11:46:15 -0500 (Sun, 29 Aug 2004) $
+ */
+
+public class NamingResourcesMBean extends BaseModelMBean {
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Construct a <code>ModelMBean</code> with default
+     * <code>ModelMBeanInfo</code> information.
+     *
+     * @exception MBeanException if the initializer of an object
+     *  throws an exception
+     * @exception RuntimeOperationsException if an IllegalArgumentException
+     *  occurs
+     */
+    public NamingResourcesMBean()
+        throws MBeanException, RuntimeOperationsException {
+
+        super();
+
+    }
+
+
+    // ----------------------------------------------------- Class Variables
+
+
+    /**
+     * JDK compatibility support
+     */
+    private static final JdkCompat jdkCompat = JdkCompat.getJdkCompat();
+
+
+    // ----------------------------------------------------- Instance Variables
+    
+    /**
+     * The configuration information registry for our managed beans.
+     */
+    protected Registry registry = MBeanUtils.createRegistry();
+
+
+    /**
+     * The <code>ManagedBean</code> information describing this MBean.
+     */
+    protected ManagedBean managed =
+        registry.findManagedBean("NamingResources");
+
+    // ------------------------------------------------------------- Attributes
+    
+
+    /**
+     * Return the MBean Names of the set of defined environment entries for  
+     * this web application
+     */
+    public String[] getEnvironments() {
+        ContextEnvironment[] envs = 
+                            ((NamingResources)this.resource).findEnvironments();
+        ArrayList results = new ArrayList();
+        for (int i = 0; i < envs.length; i++) {
+            try {
+                ObjectName oname =
+                    MBeanUtils.createObjectName(managed.getDomain(), envs[i]);
+                results.add(oname.toString());
+            } catch (MalformedObjectNameException e) {
+                IllegalArgumentException iae = new IllegalArgumentException
+                    ("Cannot create object name for environment " + envs[i]);
+                jdkCompat.chainException(iae, e);
+                throw iae;
+            }
+        }
+        return ((String[]) results.toArray(new String[results.size()]));
+
+    }
+    
+    
+    /**
+     * Return the MBean Names of all the defined resource references for this
+     * application.
+     */
+    public String[] getResources() {
+        
+        ContextResource[] resources = 
+                            ((NamingResources)this.resource).findResources();
+        ArrayList results = new ArrayList();
+        for (int i = 0; i < resources.length; i++) {
+            try {
+                ObjectName oname =
+                    MBeanUtils.createObjectName(managed.getDomain(), resources[i]);
+                results.add(oname.toString());
+            } catch (MalformedObjectNameException e) {
+                IllegalArgumentException iae = new IllegalArgumentException
+                    ("Cannot create object name for resource " + resources[i]);
+                jdkCompat.chainException(iae, e);
+                throw iae;
+            }
+        }
+        return ((String[]) results.toArray(new String[results.size()]));
+
+    }
+    
+    
+    /**
+     * Return the MBean Names of all the defined resource link references for 
+     * this application.
+     */
+    public String[] getResourceLinks() {
+        
+        ContextResourceLink[] resourceLinks = 
+                            ((NamingResources)this.resource).findResourceLinks();
+        ArrayList results = new ArrayList();
+        for (int i = 0; i < resourceLinks.length; i++) {
+            try {
+                ObjectName oname =
+                    MBeanUtils.createObjectName(managed.getDomain(), resourceLinks[i]);
+                results.add(oname.toString());
+            } catch (MalformedObjectNameException e) {
+                IllegalArgumentException iae = new IllegalArgumentException
+                    ("Cannot create object name for resource " + resourceLinks[i]);
+                jdkCompat.chainException(iae, e);
+                throw iae;
+            }
+        }
+        return ((String[]) results.toArray(new String[results.size()]));
+
+    }
+
+    // ------------------------------------------------------------- Operations
+
+
+    /**
+     * Add an environment entry for this web application.
+     *
+     * @param envName New environment entry name
+     * @param type The type of the new environment entry
+     * @param value The value of the new environment entry 
+     */
+    public String addEnvironment(String envName, String type, String value) 
+        throws MalformedObjectNameException {
+
+        NamingResources nresources = (NamingResources) this.resource;
+        if (nresources == null) {
+            return null;
+        }
+        ContextEnvironment env = nresources.findEnvironment(envName);
+        if (env != null) {
+            throw new IllegalArgumentException
+                ("Invalid environment name - already exists '" + envName + "'");
+        }
+        env = new ContextEnvironment();
+        env.setName(envName);
+        env.setType(type);
+        env.setValue(value);
+        nresources.addEnvironment(env);
+        
+        // Return the corresponding MBean name
+        ManagedBean managed = registry.findManagedBean("ContextEnvironment");
+        ObjectName oname =
+            MBeanUtils.createObjectName(managed.getDomain(), env);
+        return (oname.toString());
+        
+    }
+
+    
+    /**
+     * Add a resource reference for this web application.
+     *
+     * @param resourceName New resource reference name
+     * @param type New resource reference type
+     */
+    public String addResource(String resourceName, String type) 
+        throws MalformedObjectNameException {
+        
+        NamingResources nresources = (NamingResources) this.resource;
+        if (nresources == null) {
+            return null;
+        }
+        ContextResource resource = nresources.findResource(resourceName);
+        if (resource != null) {
+            throw new IllegalArgumentException
+                ("Invalid resource name - already exists'" + resourceName + "'");
+        }
+        resource = new ContextResource();
+        resource.setName(resourceName);
+        resource.setType(type);
+        nresources.addResource(resource);
+        
+        // Return the corresponding MBean name
+        ManagedBean managed = registry.findManagedBean("ContextResource");
+        ObjectName oname =
+            MBeanUtils.createObjectName(managed.getDomain(), resource);
+        return (oname.toString());
+    }
+
+    
+    /**
+     * Add a resource link reference for this web application.
+     *
+     * @param resourceLinkName New resource link reference name
+     * @param type New resource link reference type
+     */
+    public String addResourceLink(String resourceLinkName, String type)
+        throws MalformedObjectNameException {
+        
+        NamingResources nresources = (NamingResources) this.resource;
+        if (nresources == null) {
+            return null;
+        }
+        ContextResourceLink resourceLink = 
+                            nresources.findResourceLink(resourceLinkName);
+        if (resourceLink != null) {
+            throw new IllegalArgumentException
+                ("Invalid resource link name - already exists'" + 
+                resourceLinkName + "'");
+        }
+        resourceLink = new ContextResourceLink();
+        resourceLink.setName(resourceLinkName);
+        resourceLink.setType(type);
+        nresources.addResourceLink(resourceLink);
+        
+        // Return the corresponding MBean name
+        ManagedBean managed = registry.findManagedBean("ContextResourceLink");
+        ObjectName oname =
+            MBeanUtils.createObjectName(managed.getDomain(), resourceLink);
+        return (oname.toString());
+    }
+    
+    
+    /**
+     * Remove any environment entry with the specified name.
+     *
+     * @param envName Name of the environment entry to remove
+     */
+    public void removeEnvironment(String envName) {
+
+        NamingResources nresources = (NamingResources) this.resource;
+        if (nresources == null) {
+            return;
+        }
+        ContextEnvironment env = nresources.findEnvironment(envName);
+        if (env == null) {
+            throw new IllegalArgumentException
+                ("Invalid environment name '" + envName + "'");
+        }
+        nresources.removeEnvironment(envName);
+
+    }
+    
+    
+    /**
+     * Remove any resource reference with the specified name.
+     *
+     * @param resourceName Name of the resource reference to remove
+     */
+    public void removeResource(String resourceName) {
+
+        resourceName = ObjectName.unquote(resourceName);
+        NamingResources nresources = (NamingResources) this.resource;
+        if (nresources == null) {
+            return;
+        }
+        ContextResource resource = nresources.findResource(resourceName);
+        if (resource == null) {
+            throw new IllegalArgumentException
+                ("Invalid resource name '" + resourceName + "'");
+        }
+        nresources.removeResource(resourceName);
+    
+    }
+    
+    
+    /**
+     * Remove any resource link reference with the specified name.
+     *
+     * @param resourceLinkName Name of the resource link reference to remove
+     */
+    public void removeResourceLink(String resourceLinkName) {
+
+        resourceLinkName = ObjectName.unquote(resourceLinkName);
+        NamingResources nresources = (NamingResources) this.resource;
+        if (nresources == null) {
+            return;
+        }
+        ContextResourceLink resourceLink = 
+                            nresources.findResourceLink(resourceLinkName);
+        if (resourceLink == null) {
+            throw new IllegalArgumentException
+                ("Invalid resource Link name '" + resourceLinkName + "'");
+        }
+        nresources.removeResourceLink(resourceLinkName);
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/mbeans/RoleMBean.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/mbeans/RoleMBean.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/mbeans/RoleMBean.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.mbeans;
+
+
+import javax.management.MBeanException;
+import javax.management.MBeanServer;
+import javax.management.RuntimeOperationsException;
+
+import org.apache.commons.modeler.BaseModelMBean;
+import org.apache.commons.modeler.ManagedBean;
+import org.apache.commons.modeler.Registry;
+
+
+/**
+ * <p>A <strong>ModelMBean</strong> implementation for the
+ * <code>org.apache.catalina.Role</code> component.</p>
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class RoleMBean extends BaseModelMBean {
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Construct a <code>ModelMBean</code> with default
+     * <code>ModelMBeanInfo</code> information.
+     *
+     * @exception MBeanException if the initializer of an object
+     *  throws an exception
+     * @exception RuntimeOperationsException if an IllegalArgumentException
+     *  occurs
+     */
+    public RoleMBean()
+        throws MBeanException, RuntimeOperationsException {
+
+        super();
+
+    }
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The configuration information registry for our managed beans.
+     */
+    protected Registry registry = MBeanUtils.createRegistry();
+
+
+    /**
+     * The <code>MBeanServer</code> in which we are registered.
+     */
+    protected MBeanServer mserver = MBeanUtils.createServer();
+
+
+    /**
+     * The <code>ManagedBean</code> information describing this MBean.
+     */
+    protected ManagedBean managed =
+        registry.findManagedBean("Role");
+
+
+    // ------------------------------------------------------------- Attributes
+
+
+    // ------------------------------------------------------------- Operations
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/mbeans/ServerLifecycleListener.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/mbeans/ServerLifecycleListener.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/mbeans/ServerLifecycleListener.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,1411 @@
+/*
+ * Copyright 1999-2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.mbeans;
+
+
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+import javax.management.MBeanException;
+
+import org.apache.catalina.Container;
+import org.apache.catalina.ContainerEvent;
+import org.apache.catalina.ContainerListener;
+import org.apache.catalina.Context;
+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.Loader;
+import org.apache.catalina.Manager;
+import org.apache.catalina.Realm;
+import org.apache.catalina.Server;
+import org.apache.catalina.ServerFactory;
+import org.apache.catalina.Service;
+import org.apache.catalina.connector.Connector;
+import org.apache.catalina.core.StandardContext;
+import org.apache.catalina.core.StandardEngine;
+import org.apache.catalina.core.StandardHost;
+import org.apache.catalina.core.StandardServer;
+import org.apache.catalina.core.StandardService;
+import org.apache.catalina.deploy.ContextEnvironment;
+import org.apache.catalina.deploy.ContextResource;
+import org.apache.catalina.deploy.ContextResourceLink;
+import org.apache.catalina.deploy.NamingResources;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+
+/**
+ * Implementation of <code>LifecycleListener</code> that
+ * instantiates the set of MBeans associated with the components of a
+ * running instance of Catalina.
+ *
+ * @author Craig R. McClanahan
+ * @author Amy Roh
+ * @version $Revision: 303365 $ $Date: 2004-10-06 11:10:57 -0500 (Wed, 06 Oct 2004) $
+ */
+
+public class ServerLifecycleListener
+    implements ContainerListener, LifecycleListener, PropertyChangeListener {
+
+    private static Log log = LogFactory.getLog(ServerLifecycleListener.class);
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * Semicolon separated list of paths containing MBean desciptor resources.
+     */
+    protected String descriptors = null;
+
+    public String getDescriptors() {
+        return (this.descriptors);
+    }
+
+    public void setDescriptors(String descriptors) {
+        this.descriptors = descriptors;
+    }
+
+
+    // ---------------------------------------------- ContainerListener Methods
+
+
+    /**
+     * Handle a <code>ContainerEvent</code> from one of the Containers we are
+     * interested in.
+     *
+     * @param event The event that has occurred
+     */
+    public void containerEvent(ContainerEvent event) {
+
+        try {
+            String type = event.getType();
+            if (Container.ADD_CHILD_EVENT.equals(type)) {
+                processContainerAddChild(event.getContainer(),
+                                         (Container) event.getData());
+            } else if (Container.REMOVE_CHILD_EVENT.equals(type)) {
+                processContainerRemoveChild(event.getContainer(),
+                                            (Container) event.getData());
+            }
+        } catch (Exception e) {
+            log.error("Exception processing event " + event, e);
+        }
+
+    }
+
+
+    // ---------------------------------------------- LifecycleListener Methods
+
+
+    /**
+     * Primary entry point for startup and shutdown events.
+     *
+     * @param event The event that has occurred
+     */
+    public void lifecycleEvent(LifecycleEvent event) {
+
+        Lifecycle lifecycle = event.getLifecycle();
+        if (Lifecycle.START_EVENT.equals(event.getType())) {
+
+            if (lifecycle instanceof Server) {
+                createMBeans();
+            }
+
+            // We are embedded.
+            if( lifecycle instanceof Service ) {
+                try {
+                    MBeanFactory factory = new MBeanFactory();
+                    createMBeans(factory);
+                    createMBeans((Service)lifecycle);
+                } catch( Exception ex ) {
+                    log.error("Create mbean factory");
+                }
+            }
+
+            /*
+            // Ignore events from StandardContext objects to avoid
+            // reregistering the context
+            if (lifecycle instanceof StandardContext)
+                return;
+            createMBeans();
+            */
+
+        } else if (Lifecycle.STOP_EVENT.equals(event.getType())) {
+            try {
+                if (lifecycle instanceof Server) {
+                    destroyMBeans((Server)lifecycle);
+                }
+                if (lifecycle instanceof Service) {
+                    destroyMBeans((Service)lifecycle);
+                }
+            } catch (MBeanException t) {
+
+                Exception e = t.getTargetException();
+                if (e == null) {
+                    e = t;
+                }
+                log.error("destroyMBeans: MBeanException", e);
+
+            } catch (Throwable t) {
+
+                log.error("destroyMBeans: Throwable", t);
+
+            }
+            // FIXME: RMI adaptor should be stopped; however, this is
+            // undocumented in MX4J, and reports exist in the MX4J bug DB that
+            // this doesn't work
+
+        }
+
+        if ((Context.RELOAD_EVENT.equals(event.getType()))
+            || (Lifecycle.START_EVENT.equals(event.getType()))) {
+
+            // Give context a new handle to the MBean server if the
+            // context has been reloaded since reloading causes the
+            // context to lose its previous handle to the server
+            if (lifecycle instanceof StandardContext) {
+                // If the context is privileged, give a reference to it
+                // in a servlet context attribute
+                StandardContext context = (StandardContext)lifecycle;
+                if (context.getPrivileged()) {
+                    context.getServletContext().setAttribute
+                        (Globals.MBEAN_REGISTRY_ATTR,
+                         MBeanUtils.createRegistry());
+                    context.getServletContext().setAttribute
+                        (Globals.MBEAN_SERVER_ATTR,
+                         MBeanUtils.createServer());
+                }
+            }
+
+        }
+
+    }
+
+
+    // ----------------------------------------- PropertyChangeListener Methods
+
+
+    /**
+     * Handle a <code>PropertyChangeEvent</code> from one of the Containers
+     * we are interested in.
+     *
+     * @param event The event that has occurred
+     */
+    public void propertyChange(PropertyChangeEvent event) {
+
+        if (event.getSource() instanceof Container) {
+            try {
+                processContainerPropertyChange((Container) event.getSource(),
+                                               event.getPropertyName(),
+                                               event.getOldValue(),
+                                               event.getNewValue());
+            } catch (Exception e) {
+                log.error("Exception handling Container property change", e);
+            }
+        }/* else if (event.getSource() instanceof DefaultContext) {
+            try {
+                processDefaultContextPropertyChange
+                    ((DefaultContext) event.getSource(),
+                     event.getPropertyName(),
+                     event.getOldValue(),
+                     event.getNewValue());
+            } catch (Exception e) {
+                log.error("Exception handling DefaultContext property change", e);
+            }
+        }*/ else if (event.getSource() instanceof NamingResources) {
+            try {
+                processNamingResourcesPropertyChange
+                    ((NamingResources) event.getSource(),
+                     event.getPropertyName(),
+                     event.getOldValue(),
+                     event.getNewValue());
+            } catch (Exception e) {
+                log.error("Exception handling NamingResources property change", e);
+            }
+        } else if (event.getSource() instanceof Server) {
+            try {
+                processServerPropertyChange((Server) event.getSource(),
+                                            event.getPropertyName(),
+                                            event.getOldValue(),
+                                            event.getNewValue());
+            } catch (Exception e) {
+                log.error("Exception handing Server property change", e);
+            }
+        } else if (event.getSource() instanceof Service) {
+            try {
+                processServicePropertyChange((Service) event.getSource(),
+                                             event.getPropertyName(),
+                                             event.getOldValue(),
+                                             event.getNewValue());
+            } catch (Exception e) {
+                log.error("Exception handing Service property change", e);
+            }
+        }
+
+    }
+
+
+    // ------------------------------------------------------ Protected Methods
+
+
+    /**
+     * Create the MBeans that correspond to every existing node of our tree.
+     */
+    protected void createMBeans() {
+
+        try {
+
+            MBeanFactory factory = new MBeanFactory();
+            createMBeans(factory);
+            createMBeans(ServerFactory.getServer());
+
+        } catch (MBeanException t) {
+
+            Exception e = t.getTargetException();
+            if (e == null)
+                e = t;
+            log.error("createMBeans: MBeanException", e);
+
+        } catch (Throwable t) {
+
+            log.error("createMBeans: Throwable", t);
+
+        }
+
+    }
+
+
+    /**
+     * Create the MBeans for the specified Connector and its nested components.
+     *
+     * @param connector Connector for which to create MBeans
+     *
+     * @exception Exception if an exception is thrown during MBean creation
+     */
+    protected void createMBeans(Connector connector) throws Exception {
+
+        // Create the MBean for the Connnector itself
+//        if (log.isDebugEnabled())
+//            log.debug("Creating MBean for Connector " + connector);
+//        MBeanUtils.createMBean(connector);
+
+    }
+
+
+    /**
+     * Create the MBeans for the specified Context and its nested components.
+     *
+     * @param context Context for which to create MBeans
+     *
+     * @exception Exception if an exception is thrown during MBean creation
+     */
+    protected void createMBeans(Context context) throws Exception {
+
+        // Create the MBean for the Context itself
+//        if (log.isDebugEnabled())
+//            log.debug("Creating MBean for Context " + context);
+//        MBeanUtils.createMBean(context);
+        context.addContainerListener(this);
+        if (context instanceof StandardContext) {
+            ((StandardContext) context).addPropertyChangeListener(this);
+            ((StandardContext) context).addLifecycleListener(this);
+        }
+
+        // If the context is privileged, give a reference to it
+        // in a servlet context attribute
+        if (context.getPrivileged()) {
+            context.getServletContext().setAttribute
+                (Globals.MBEAN_REGISTRY_ATTR,
+                 MBeanUtils.createRegistry());
+            context.getServletContext().setAttribute
+                (Globals.MBEAN_SERVER_ATTR,
+                 MBeanUtils.createServer());
+        }
+
+        // Create the MBeans for the associated nested components
+        Loader cLoader = context.getLoader();
+        if (cLoader != null) {
+            if (log.isDebugEnabled())
+                log.debug("Creating MBean for Loader " + cLoader);
+            //MBeanUtils.createMBean(cLoader);
+        }
+        Manager cManager = context.getManager();
+        if (cManager != null) {
+            if (log.isDebugEnabled())
+                log.debug("Creating MBean for Manager " + cManager);
+            //MBeanUtils.createMBean(cManager);
+        }
+        Realm hRealm = context.getParent().getRealm();
+        Realm cRealm = context.getRealm();
+        if ((cRealm != null) && (cRealm != hRealm)) {
+            if (log.isDebugEnabled())
+                log.debug("Creating MBean for Realm " + cRealm);
+            //MBeanUtils.createMBean(cRealm);
+        }
+
+        // Create the MBeans for the NamingResources (if any)
+        NamingResources resources = context.getNamingResources();
+        createMBeans(resources);
+
+    }
+
+
+    /**
+     * Create the MBeans for the specified ContextEnvironment entry.
+     *
+     * @param environment ContextEnvironment for which to create MBeans
+     *
+     * @exception Exception if an exception is thrown during MBean creation
+     */
+    protected void createMBeans(ContextEnvironment environment)
+        throws Exception {
+
+        // Create the MBean for the ContextEnvironment itself
+        if (log.isDebugEnabled()) {
+            log.debug("Creating MBean for ContextEnvironment " + environment);
+        }
+        MBeanUtils.createMBean(environment);
+
+    }
+
+
+    /**
+     * Create the MBeans for the specified ContextResource entry.
+     *
+     * @param resource ContextResource for which to create MBeans
+     *
+     * @exception Exception if an exception is thrown during MBean creation
+     */
+    protected void createMBeans(ContextResource resource)
+        throws Exception {
+
+        // Create the MBean for the ContextResource itself
+        if (log.isDebugEnabled()) {
+            log.debug("Creating MBean for ContextResource " + resource);
+        }
+        MBeanUtils.createMBean(resource);
+
+    }
+
+
+    /**
+     * Create the MBeans for the specified ContextResourceLink entry.
+     *
+     * @param resourceLink ContextResourceLink for which to create MBeans
+     *
+     * @exception Exception if an exception is thrown during MBean creation
+     */
+    protected void createMBeans(ContextResourceLink resourceLink)
+        throws Exception {
+
+        // Create the MBean for the ContextResourceLink itself
+        if (log.isDebugEnabled()) {
+            log.debug("Creating MBean for ContextResourceLink " + resourceLink);
+        }
+        MBeanUtils.createMBean(resourceLink);
+
+    }
+
+
+    /**
+     * Create the MBeans for the specified DefaultContext and its nested components.
+     *
+     * @param dcontext DefaultContext for which to create MBeans
+     *
+     * @exception Exception if an exception is thrown during MBean creation
+     */
+    /*
+    protected void createMBeans(DefaultContext dcontext) throws Exception {
+
+        // Create the MBean for the DefaultContext itself
+        if (log.isDebugEnabled())
+            log.debug("Creating MBean for DefaultContext " + dcontext);
+        MBeanUtils.createMBean(dcontext);
+
+        dcontext.addPropertyChangeListener(this);
+
+        // Create the MBeans for the associated nested components
+        Loader dLoader = dcontext.getLoader();
+        if (dLoader != null) {
+            if (log.isDebugEnabled())
+                log.debug("Creating MBean for Loader " + dLoader);
+            //MBeanUtils.createMBean(dLoader);
+        }
+
+        Manager dManager = dcontext.getManager();
+        if (dManager != null) {
+            if (log.isDebugEnabled())
+                log.debug("Creating MBean for Manager " + dManager);
+            //MBeanUtils.createMBean(dManager);
+        }
+
+        // Create the MBeans for the NamingResources (if any)
+        NamingResources resources = dcontext.getNamingResources();
+        createMBeans(resources);
+
+    }
+    */
+
+
+    /**
+     * Create the MBeans for the specified Engine and its nested components.
+     *
+     * @param engine Engine for which to create MBeans
+     *
+     * @exception Exception if an exception is thrown during MBean creation
+     */
+    protected void createMBeans(Engine engine) throws Exception {
+
+        // Create the MBean for the Engine itself
+        if (log.isDebugEnabled()) {
+            log.debug("Creating MBean for Engine " + engine);
+        }
+        //MBeanUtils.createMBean(engine);
+        engine.addContainerListener(this);
+        if (engine instanceof StandardEngine) {
+            ((StandardEngine) engine).addPropertyChangeListener(this);
+        }
+
+        // Create the MBeans for the associated nested components
+        Realm eRealm = engine.getRealm();
+        if (eRealm != null) {
+            if (log.isDebugEnabled())
+                log.debug("Creating MBean for Realm " + eRealm);
+            //MBeanUtils.createMBean(eRealm);
+        }
+
+        // Create the MBeans for each child Host
+        Container hosts[] = engine.findChildren();
+        for (int j = 0; j < hosts.length; j++) {
+            createMBeans((Host) hosts[j]);
+        }
+
+    }
+
+
+    /**
+     * Create the MBeans for the specified Host and its nested components.
+     *
+     * @param host Host for which to create MBeans
+     *
+     * @exception Exception if an exception is thrown during MBean creation
+     */
+    protected void createMBeans(Host host) throws Exception {
+
+        // Create the MBean for the Host itself
+        if (log.isDebugEnabled()) {
+            log.debug("Creating MBean for Host " + host);
+        }
+        //MBeanUtils.createMBean(host);
+        host.addContainerListener(this);
+        if (host instanceof StandardHost) {
+            ((StandardHost) host).addPropertyChangeListener(this);
+        }
+
+        // Create the MBeans for the associated nested components
+        Realm eRealm = host.getParent().getRealm();
+        Realm hRealm = host.getRealm();
+        if ((hRealm != null) && (hRealm != eRealm)) {
+            if (log.isDebugEnabled())
+                log.debug("Creating MBean for Realm " + hRealm);
+            //MBeanUtils.createMBean(hRealm);
+        }
+
+        // Create the MBeans for each child Context
+        Container contexts[] = host.findChildren();
+        for (int k = 0; k < contexts.length; k++) {
+            createMBeans((Context) contexts[k]);
+        }
+
+    }
+
+
+    /**
+     * Create the MBeans for MBeanFactory.
+     *
+     * @param factory MBeanFactory for which to create MBean
+     *
+     * @exception Exception if an exception is thrown during MBean creation
+     */
+    protected void createMBeans(MBeanFactory factory) throws Exception {
+
+        // Create the MBean for the MBeanFactory
+        if (log.isDebugEnabled())
+            log.debug("Creating MBean for MBeanFactory " + factory);
+        MBeanUtils.createMBean(factory);
+
+    }
+
+
+    /**
+     * Create the MBeans for the specified NamingResources and its
+     * nested components.
+     *
+     * @param resources NamingResources for which to create MBeans
+     */
+    protected void createMBeans(NamingResources resources) throws Exception {
+
+        // Create the MBean for the NamingResources itself
+        if (log.isDebugEnabled()) {
+            log.debug("Creating MBean for NamingResources " + resources);
+        }
+        MBeanUtils.createMBean(resources);
+        resources.addPropertyChangeListener(this);
+
+        // Create the MBeans for each child environment entry
+        ContextEnvironment environments[] = resources.findEnvironments();
+        for (int i = 0; i < environments.length; i++) {
+            createMBeans(environments[i]);
+        }
+
+        // Create the MBeans for each child resource entry
+        ContextResource cresources[] = resources.findResources();
+        for (int i = 0; i < cresources.length; i++) {
+            createMBeans(cresources[i]);
+        }
+
+        // Create the MBeans for each child resource link entry
+        ContextResourceLink cresourcelinks[] = resources.findResourceLinks();
+        for (int i = 0; i < cresourcelinks.length; i++) {
+            createMBeans(cresourcelinks[i]);
+        }
+
+    }
+
+
+    /**
+     * Create the MBeans for the specified Server and its nested components.
+     *
+     * @param server Server for which to create MBeans
+     *
+     * @exception Exception if an exception is thrown during MBean creation
+     */
+    protected void createMBeans(Server server) throws Exception {
+
+        // Create the MBean for the Server itself
+        if (log.isDebugEnabled())
+            log.debug("Creating MBean for Server " + server);
+        //MBeanUtils.createMBean(server);
+        if (server instanceof StandardServer) {
+            ((StandardServer) server).addPropertyChangeListener(this);
+        }
+
+        // Create the MBeans for the global NamingResources (if any)
+        NamingResources resources = server.getGlobalNamingResources();
+        if (resources != null) {
+            createMBeans(resources);
+        }
+
+        // Create the MBeans for each child Service
+        Service services[] = server.findServices();
+        for (int i = 0; i < services.length; i++) {
+            // FIXME - Warp object hierarchy not currently supported
+            if (services[i].getContainer().getClass().getName().equals
+                ("org.apache.catalina.connector.warp.WarpEngine")) {
+                if (log.isDebugEnabled()) {
+                    log.debug("Skipping MBean for Service " + services[i]);
+                }
+                continue;
+            }
+            createMBeans(services[i]);
+        }
+
+    }
+
+
+    /**
+     * Create the MBeans for the specified Service and its nested components.
+     *
+     * @param service Service for which to create MBeans
+     *
+     * @exception Exception if an exception is thrown during MBean creation
+     */
+    protected void createMBeans(Service service) throws Exception {
+
+        // Create the MBean for the Service itself
+        if (log.isDebugEnabled())
+            log.debug("Creating MBean for Service " + service);
+        //MBeanUtils.createMBean(service);
+        if (service instanceof StandardService) {
+            ((StandardService) service).addPropertyChangeListener(this);
+        }
+
+        // Create the MBeans for the corresponding Connectors
+        Connector connectors[] = service.findConnectors();
+        for (int j = 0; j < connectors.length; j++) {
+            createMBeans(connectors[j]);
+        }
+
+        // Create the MBean for the associated Engine and friends
+        Engine engine = (Engine) service.getContainer();
+        if (engine != null) {
+            createMBeans(engine);
+        }
+
+    }
+
+
+
+
+    /**
+     * Deregister the MBeans for the specified Connector and its nested
+     * components.
+     *
+     * @param connector Connector for which to deregister MBeans
+     *
+     * @exception Exception if an exception is thrown during MBean destruction
+     */
+    protected void destroyMBeans(Connector connector, Service service)
+        throws Exception {
+
+//        // deregister the MBean for the Connector itself
+//        if (log.isDebugEnabled())
+//            log.debug("Destroying MBean for Connector " + connector);
+//        MBeanUtils.destroyMBean(connector, service);
+
+    }
+
+
+    /**
+     * Deregister the MBeans for the specified Context and its nested
+     * components.
+     *
+     * @param context Context for which to deregister MBeans
+     *
+     * @exception Exception if an exception is thrown during MBean destruction
+     */
+    protected void destroyMBeans(Context context) throws Exception {
+
+        // Deregister ourselves as a ContainerListener
+        context.removeContainerListener(this);
+
+        // Destroy the MBeans for the associated nested components
+        Realm hRealm = context.getParent().getRealm();
+        Realm cRealm = context.getRealm();
+        if ((cRealm != null) && (cRealm != hRealm)) {
+            if (log.isDebugEnabled())
+                log.debug("Destroying MBean for Realm " + cRealm);
+            //MBeanUtils.destroyMBean(cRealm);
+        }
+        Manager cManager = context.getManager();
+        if (cManager != null) {
+            if (log.isDebugEnabled())
+                log.debug("Destroying MBean for Manager " + cManager);
+            //MBeanUtils.destroyMBean(cManager);
+        }
+        Loader cLoader = context.getLoader();
+        if (cLoader != null) {
+            if (log.isDebugEnabled())
+                log.debug("Destroying MBean for Loader " + cLoader);
+            //MBeanUtils.destroyMBean(cLoader);
+        }
+
+        // Destroy the MBeans for the NamingResources (if any)
+        NamingResources resources = context.getNamingResources();
+        if (resources != null) {
+            destroyMBeans(resources);
+        }
+
+        // deregister the MBean for the Context itself
+        if (log.isDebugEnabled())
+            log.debug("Destroying MBean for Context " + context);
+        //MBeanUtils.destroyMBean(context);
+        if (context instanceof StandardContext) {
+            ((StandardContext) context).
+                removePropertyChangeListener(this);
+        }
+
+    }
+
+
+    /**
+     * Deregister the MBeans for the specified ContextEnvironment entry.
+     *
+     * @param environment ContextEnvironment for which to destroy MBeans
+     *
+     * @exception Exception if an exception is thrown during MBean destruction
+     */
+    protected void destroyMBeans(ContextEnvironment environment)
+        throws Exception {
+
+        // Destroy the MBean for the ContextEnvironment itself
+        if (log.isDebugEnabled()) {
+            log.debug("Destroying MBean for ContextEnvironment " + environment);
+        }
+        MBeanUtils.destroyMBean(environment);
+
+    }
+
+
+    /**
+     * Deregister the MBeans for the specified ContextResource entry.
+     *
+     * @param resource ContextResource for which to destroy MBeans
+     *
+     * @exception Exception if an exception is thrown during MBean destruction
+     */
+    protected void destroyMBeans(ContextResource resource)
+        throws Exception {
+
+        // Destroy the MBean for the ContextResource itself
+        if (log.isDebugEnabled()) {
+            log.debug("Destroying MBean for ContextResource " + resource);
+        }
+        MBeanUtils.destroyMBean(resource);
+
+    }
+
+
+    /**
+     * Deregister the MBeans for the specified ContextResourceLink entry.
+     *
+     * @param resourceLink ContextResourceLink for which to destroy MBeans
+     *
+     * @exception Exception if an exception is thrown during MBean destruction
+     */
+    protected void destroyMBeans(ContextResourceLink resourceLink)
+        throws Exception {
+
+        // Destroy the MBean for the ContextResourceLink itself
+        if (log.isDebugEnabled()) {
+            log.debug("Destroying MBean for ContextResourceLink " + resourceLink);
+        }
+        MBeanUtils.destroyMBean(resourceLink);
+
+    }
+
+
+    /**
+     * Deregister the MBeans for the specified DefaultContext and its nested
+     * components.
+     *
+     * @param dcontext DefaultContext for which to deregister MBeans
+     *
+     * @exception Exception if an exception is thrown during MBean destruction
+     */
+    /*
+    protected void destroyMBeans(DefaultContext dcontext) throws Exception {
+
+        Manager dManager = dcontext.getManager();
+        if (dManager != null) {
+            if (log.isDebugEnabled())
+                log.debug("Destroying MBean for Manager " + dManager);
+            //MBeanUtils.destroyMBean(dManager);
+        }
+
+        Loader dLoader = dcontext.getLoader();
+        if (dLoader != null) {
+            if (log.isDebugEnabled())
+                log.debug("Destroying MBean for Loader " + dLoader);
+            //MBeanUtils.destroyMBean(dLoader);
+        }
+
+        // Destroy the MBeans for the NamingResources (if any)
+        NamingResources resources = dcontext.getNamingResources();
+        if (resources != null) {
+            destroyMBeans(resources);
+        }
+
+        // deregister the MBean for the DefaultContext itself
+        if (log.isDebugEnabled())
+            log.debug("Destroying MBean for Context " + dcontext);
+        MBeanUtils.destroyMBean(dcontext);
+        dcontext.removePropertyChangeListener(this);
+
+    }
+    */
+
+
+    /**
+     * Deregister the MBeans for the specified Engine and its nested
+     * components.
+     *
+     * @param engine Engine for which to destroy MBeans
+     *
+     * @exception Exception if an exception is thrown during MBean destruction
+     */
+    protected void destroyMBeans(Engine engine) throws Exception {
+
+        // Deregister ourselves as a ContainerListener
+        engine.removeContainerListener(this);
+
+        // Deregister the MBeans for each child Host
+        Container hosts[] = engine.findChildren();
+        for (int k = 0; k < hosts.length; k++) {
+            destroyMBeans((Host) hosts[k]);
+        }
+
+        // Deregister the MBeans for the associated nested components
+        Realm eRealm = engine.getRealm();
+        if (eRealm != null) {
+            if (log.isDebugEnabled())
+                log.debug("Destroying MBean for Realm " + eRealm);
+            //MBeanUtils.destroyMBean(eRealm);
+        }
+
+        // Deregister the MBean for the Engine itself
+        if (log.isDebugEnabled()) {
+            log.debug("Destroying MBean for Engine " + engine);
+        }
+        //MBeanUtils.destroyMBean(engine);
+
+    }
+
+
+    /**
+     * Deregister the MBeans for the specified Host and its nested components.
+     *
+     * @param host Host for which to destroy MBeans
+     *
+     * @exception Exception if an exception is thrown during MBean destruction
+     */
+    protected void destroyMBeans(Host host) throws Exception {
+
+        // Deregister ourselves as a ContainerListener
+        host.removeContainerListener(this);
+
+        // Deregister the MBeans for each child Context
+        Container contexts[] = host.findChildren();
+        for (int k = 0; k < contexts.length; k++) {
+            destroyMBeans((Context) contexts[k]);
+        }
+
+
+        // Deregister the MBeans for the associated nested components
+        Realm eRealm = host.getParent().getRealm();
+        Realm hRealm = host.getRealm();
+        if ((hRealm != null) && (hRealm != eRealm)) {
+            if (log.isDebugEnabled())
+                log.debug("Destroying MBean for Realm " + hRealm);
+            //MBeanUtils.destroyMBean(hRealm);
+        }
+
+        // Deregister the MBean for the Host itself
+        if (log.isDebugEnabled()) {
+            log.debug("Destroying MBean for Host " + host);
+        }
+        //MBeanUtils.destroyMBean(host);
+
+    }
+
+
+    /**
+     * Deregister the MBeans for the specified NamingResources and its
+     * nested components.
+     *
+     * @param resources NamingResources for which to destroy MBeans
+     *
+     * @exception Exception if an exception is thrown during MBean destruction
+     */
+    protected void destroyMBeans(NamingResources resources) throws Exception {
+
+        // Destroy the MBeans for each child resource entry
+        ContextResource cresources[] = resources.findResources();
+        for (int i = 0; i < cresources.length; i++) {
+            destroyMBeans(cresources[i]);
+        }
+
+        // Destroy the MBeans for each child resource link entry
+        ContextResourceLink cresourcelinks[] = resources.findResourceLinks();
+        for (int i = 0; i < cresourcelinks.length; i++) {
+            destroyMBeans(cresourcelinks[i]);
+        }
+
+        // Destroy the MBeans for each child environment entry
+        ContextEnvironment environments[] = resources.findEnvironments();
+        for (int i = 0; i < environments.length; i++) {
+            destroyMBeans(environments[i]);
+        }
+
+        // Destroy the MBean for the NamingResources itself
+        if (log.isDebugEnabled()) {
+            log.debug("Destroying MBean for NamingResources " + resources);
+        }
+        MBeanUtils.destroyMBean(resources);
+        resources.removePropertyChangeListener(this);
+
+    }
+
+
+    /**
+     * Deregister the MBeans for the specified Server and its related
+     * components.
+     *
+     * @param server Server for which to destroy MBeans
+     *
+     * @exception Exception if an exception is thrown during MBean destruction
+     */
+    protected void destroyMBeans(Server server) throws Exception {
+
+        // Destroy the MBeans for the global NamingResources (if any)
+        NamingResources resources = server.getGlobalNamingResources();
+        if (resources != null) {
+            destroyMBeans(resources);
+        }
+
+        // Destroy the MBeans for each child Service
+        Service services[] = server.findServices();
+        for (int i = 0; i < services.length; i++) {
+            // FIXME - Warp object hierarchy not currently supported
+            if (services[i].getContainer().getClass().getName().equals
+                ("org.apache.catalina.connector.warp.WarpEngine")) {
+                if (log.isDebugEnabled()) {
+                    log.debug("Skipping MBean for Service " + services[i]);
+                }
+                continue;
+            }
+            destroyMBeans(services[i]);
+        }
+
+        // Destroy the MBean for the Server itself
+        if (log.isDebugEnabled()) {
+            log.debug("Destroying MBean for Server " + server);
+        }
+        //MBeanUtils.destroyMBean(server);
+        if (server instanceof StandardServer) {
+            ((StandardServer) server).removePropertyChangeListener(this);
+        }
+
+    }
+
+
+    /**
+     * Deregister the MBeans for the specified Service and its nested
+     * components.
+     *
+     * @param service Service for which to destroy MBeans
+     *
+     * @exception Exception if an exception is thrown during MBean destruction
+     */
+    protected void destroyMBeans(Service service) throws Exception {
+
+        // Deregister the MBeans for the associated Engine
+        Engine engine = (Engine) service.getContainer();
+        if (engine != null) {
+            //destroyMBeans(engine);
+        }
+
+//        // Deregister the MBeans for the corresponding Connectors
+//        Connector connectors[] = service.findConnectors();
+//        for (int j = 0; j < connectors.length; j++) {
+//            destroyMBeans(connectors[j], service);
+//        }
+
+        // Deregister the MBean for the Service itself
+        if (log.isDebugEnabled()) {
+            log.debug("Destroying MBean for Service " + service);
+        }
+        //MBeanUtils.destroyMBean(service);
+        if (service instanceof StandardService) {
+            ((StandardService) service).removePropertyChangeListener(this);
+        }
+
+    }
+
+
+    /**
+     * Process the addition of a new child Container to a parent Container.
+     *
+     * @param parent Parent container
+     * @param child Child container
+     */
+    protected void processContainerAddChild(Container parent,
+                                            Container child) {
+
+        if (log.isDebugEnabled())
+            log.debug("Process addChild[parent=" + parent + ",child=" + child + "]");
+
+        try {
+            if (child instanceof Context) {
+                createMBeans((Context) child);
+            } else if (child instanceof Engine) {
+                createMBeans((Engine) child);
+            } else if (child instanceof Host) {
+                createMBeans((Host) child);
+            }
+        } catch (MBeanException t) {
+            Exception e = t.getTargetException();
+            if (e == null)
+                e = t;
+            log.error("processContainerAddChild: MBeanException", e);
+        } catch (Throwable t) {
+            log.error("processContainerAddChild: Throwable", t);
+        }
+
+    }
+
+
+
+
+    /**
+     * Process a property change event on a Container.
+     *
+     * @param container The container on which this event occurred
+     * @param propertyName The name of the property that changed
+     * @param oldValue The previous value (may be <code>null</code>)
+     * @param newValue The new value (may be <code>null</code>)
+     *
+     * @exception Exception if an exception is thrown
+     */
+    protected void processContainerPropertyChange(Container container,
+                                                  String propertyName,
+                                                  Object oldValue,
+                                                  Object newValue)
+        throws Exception {
+
+        if (log.isTraceEnabled()) {
+            log.trace("propertyChange[container=" + container +
+                ",propertyName=" + propertyName +
+                ",oldValue=" + oldValue +
+                ",newValue=" + newValue + "]");
+        }
+        if ("loader".equals(propertyName)) {
+            if (oldValue != null) {
+                if (log.isDebugEnabled()) {
+                    log.debug("Removing MBean for Loader " + oldValue);
+                }
+                MBeanUtils.destroyMBean((Loader) oldValue);
+            }
+            if (newValue != null) {
+                if (log.isDebugEnabled()) {
+                    log.debug("Creating MBean for Loader " + newValue);
+                }
+                MBeanUtils.createMBean((Loader) newValue);
+            }
+        } else if ("logger".equals(propertyName)) {
+            if (oldValue != null) {
+                if (log.isDebugEnabled()) {
+                    log.debug("Removing MBean for Logger " + oldValue);
+                }
+               // MBeanUtils.destroyMBean((Logger) oldValue);
+            }
+            if (newValue != null) {
+                if (log.isDebugEnabled()) {
+                    log.debug("Creating MBean for Logger " + newValue);
+                }
+                //MBeanUtils.createMBean((Logger) newValue);
+            }
+        } else if ("manager".equals(propertyName)) {
+            if (oldValue != null) {
+                if (log.isDebugEnabled()) {
+                    log.debug("Removing MBean for Manager " + oldValue);
+                }
+                //MBeanUtils.destroyMBean((Manager) oldValue);
+            }
+            if (newValue != null) {
+                if (log.isDebugEnabled()) {
+                    log.debug("Creating MBean for Manager " + newValue);
+                }
+                //MBeanUtils.createMBean((Manager) newValue);
+            }
+        } else if ("realm".equals(propertyName)) {
+            if (oldValue != null) {
+                if (log.isDebugEnabled()) {
+                    log.debug("Removing MBean for Realm " + oldValue);
+                }
+                MBeanUtils.destroyMBean((Realm) oldValue);
+            }
+            if (newValue != null) {
+                if (log.isDebugEnabled()) {
+                    log.debug("Creating MBean for Realm " + newValue);
+                }
+                //MBeanUtils.createMBean((Realm) newValue);
+            }
+        } else if ("service".equals(propertyName)) {
+            if (oldValue != null) {
+                destroyMBeans((Service) oldValue);
+            }
+            if (newValue != null) {
+                createMBeans((Service) newValue);
+            }
+        }
+
+    }
+
+
+    /**
+     * Process a property change event on a DefaultContext.
+     *
+     * @param defaultContext The DefaultContext on which this event occurred
+     * @param propertyName The name of the property that changed
+     * @param oldValue The previous value (may be <code>null</code>)
+     * @param newValue The new value (may be <code>null</code>)
+     *
+     * @exception Exception if an exception is thrown
+     */
+    /*
+    protected void processDefaultContextPropertyChange(DefaultContext defaultContext,
+                                                  String propertyName,
+                                                  Object oldValue,
+                                                  Object newValue)
+        throws Exception {
+
+        if (log.isTraceEnabled()) {
+            log.trace("propertyChange[defaultContext=" + defaultContext +
+                ",propertyName=" + propertyName +
+                ",oldValue=" + oldValue +
+                ",newValue=" + newValue + "]");
+        }
+        if ("loader".equals(propertyName)) {
+            if (oldValue != null) {
+                if (log.isDebugEnabled()) {
+                    log.debug("Removing MBean for Loader " + oldValue);
+                }
+                MBeanUtils.destroyMBean((Loader) oldValue);
+            }
+            if (newValue != null) {
+                if (log.isDebugEnabled()) {
+                    log.debug("Creating MBean for Loader " + newValue);
+                }
+                MBeanUtils.createMBean((Loader) newValue);
+            }
+        } else if ("logger".equals(propertyName)) {
+            if (oldValue != null) {
+                if (log.isDebugEnabled()) {
+                    log.debug("Removing MBean for Logger " + oldValue);
+                }
+                //MBeanUtils.destroyMBean((Logger) oldValue);
+            }
+            if (newValue != null) {
+                if (log.isDebugEnabled()) {
+                    log.debug("Creating MBean for Logger " + newValue);
+                }
+                //MBeanUtils.createMBean((Logger) newValue);
+            }
+        } else if ("manager".equals(propertyName)) {
+            if (oldValue != null) {
+                if (log.isDebugEnabled()) {
+                    log.debug("Removing MBean for Manager " + oldValue);
+                }
+                MBeanUtils.destroyMBean((Manager) oldValue);
+            }
+            if (newValue != null) {
+                if (log.isDebugEnabled()) {
+                    log.debug("Creating MBean for Manager " + newValue);
+                }
+                MBeanUtils.createMBean((Manager) newValue);
+            }
+        } else if ("realm".equals(propertyName)) {
+            if (oldValue != null) {
+//                if (log.isDebugEnabled()) {
+//                    log.debug("Removing MBean for Realm " + oldValue);
+//                }
+//                //MBeanUtils.destroyMBean((Realm) oldValue);
+            }
+            if (newValue != null) {
+//                if (log.isDebugEnabled()) {
+//                    log.debug("Creating MBean for Realm " + newValue);
+//                }
+//                //MBeanUtils.createMBean((Realm) newValue);
+            }
+        } else if ("service".equals(propertyName)) {
+            if (oldValue != null) {
+                destroyMBeans((Service) oldValue);
+            }
+            if (newValue != null) {
+                createMBeans((Service) newValue);
+            }
+        }
+
+    }*/
+
+
+    /**
+     * Process the removal of a child Container from a parent Container.
+     *
+     * @param parent Parent container
+     * @param child Child container
+     */
+    protected void processContainerRemoveChild(Container parent,
+                                               Container child) {
+
+        if (log.isDebugEnabled())
+            log.debug("Process removeChild[parent=" + parent + ",child=" +
+                child + "]");
+
+        try {
+            if (child instanceof Context) {
+                Context context = (Context) child;
+                if (context.getPrivileged()) {
+                    context.getServletContext().removeAttribute
+                        (Globals.MBEAN_REGISTRY_ATTR);
+                    context.getServletContext().removeAttribute
+                        (Globals.MBEAN_SERVER_ATTR);
+                }
+                if (log.isDebugEnabled())
+                    log.debug("  Removing MBean for Context " + context);
+                destroyMBeans(context);
+                if (context instanceof StandardContext) {
+                    ((StandardContext) context).
+                        removePropertyChangeListener(this);
+                }
+            } else if (child instanceof Host) {
+                Host host = (Host) child;
+                destroyMBeans(host);
+                if (host instanceof StandardHost) {
+                    ((StandardHost) host).
+                        removePropertyChangeListener(this);
+                }
+            }
+        } catch (MBeanException t) {
+            Exception e = t.getTargetException();
+            if (e == null)
+                e = t;
+            log.error("processContainerRemoveChild: MBeanException", e);
+        } catch (Throwable t) {
+            log.error("processContainerRemoveChild: Throwable", t);
+        }
+
+    }
+
+
+    /**
+     * Process a property change event on a NamingResources.
+     *
+     * @param resources The global naming resources on which this
+     *  event occurred
+     * @param propertyName The name of the property that changed
+     * @param oldValue The previous value (may be <code>null</code>)
+     * @param newValue The new value (may be <code>null</code>)
+     *
+     * @exception Exception if an exception is thrown
+     */
+    protected void processNamingResourcesPropertyChange
+        (NamingResources resources, String propertyName,
+         Object oldValue, Object newValue)
+        throws Exception {
+
+        if (log.isTraceEnabled()) {
+            log.trace("propertyChange[namingResources=" + resources +
+                ",propertyName=" + propertyName +
+                ",oldValue=" + oldValue +
+                ",newValue=" + newValue + "]");
+        }
+
+        // FIXME - Add other resource types when supported by admin tool
+        if ("environment".equals(propertyName)) {
+            if (oldValue != null) {
+                destroyMBeans((ContextEnvironment) oldValue);
+            }
+            if (newValue != null) {
+                createMBeans((ContextEnvironment) newValue);
+            }
+        } else if ("resource".equals(propertyName)) {
+            if (oldValue != null) {
+                destroyMBeans((ContextResource) oldValue);
+            }
+            if (newValue != null) {
+                createMBeans((ContextResource) newValue);
+            }
+        } else if ("resourceLink".equals(propertyName)) {
+            if (oldValue != null) {
+                destroyMBeans((ContextResourceLink) oldValue);
+            }
+            if (newValue != null) {
+                createMBeans((ContextResourceLink) newValue);
+            }
+        }
+
+    }
+
+
+    /**
+     * Process a property change event on a Server.
+     *
+     * @param server The server on which this event occurred
+     * @param propertyName The name of the property that changed
+     * @param oldValue The previous value (may be <code>null</code>)
+     * @param newValue The new value (may be <code>null</code>)
+     *
+     * @exception Exception if an exception is thrown
+     */
+    protected void processServerPropertyChange(Server server,
+                                               String propertyName,
+                                               Object oldValue,
+                                               Object newValue)
+        throws Exception {
+
+        if (log.isTraceEnabled()) {
+            log.trace("propertyChange[server=" + server +
+                ",propertyName=" + propertyName +
+                ",oldValue=" + oldValue +
+                ",newValue=" + newValue + "]");
+        }
+        if ("globalNamingResources".equals(propertyName)) {
+            if (oldValue != null) {
+                destroyMBeans((NamingResources) oldValue);
+            }
+            if (newValue != null) {
+                createMBeans((NamingResources) newValue);
+            }
+        } else if ("service".equals(propertyName)) {
+            if (oldValue != null) {
+                destroyMBeans((Service) oldValue);
+            }
+            if (newValue != null) {
+                createMBeans((Service) newValue);
+            }
+        }
+
+    }
+
+
+    /**
+     * Process a property change event on a Service.
+     *
+     * @param service The service on which this event occurred
+     * @param propertyName The name of the property that changed
+     * @param oldValue The previous value (may be <code>null</code>)
+     * @param newValue The new value (may be <code>null</code>)
+     *
+     * @exception Exception if an exception is thrown
+     */
+    protected void processServicePropertyChange(Service service,
+                                                String propertyName,
+                                                Object oldValue,
+                                                Object newValue)
+        throws Exception {
+
+        if (log.isTraceEnabled()) {
+            log.trace("propertyChange[service=" + service +
+                ",propertyName=" + propertyName +
+                ",oldValue=" + oldValue +
+                ",newValue=" + newValue + "]");
+        }
+        if ("connector".equals(propertyName)) {
+            if (oldValue != null) {
+                destroyMBeans((Connector) oldValue, service);
+            }
+            if (newValue != null) {
+                createMBeans((Connector) newValue);
+            }
+        } else if ("container".equals(propertyName)) {
+            if (oldValue != null) {
+                destroyMBeans((Engine) oldValue);
+            }
+            if (newValue != null) {
+                createMBeans((Engine) newValue);
+            }
+        }
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/mbeans/StandardContextMBean.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/mbeans/StandardContextMBean.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/mbeans/StandardContextMBean.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,367 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.mbeans;
+
+import java.util.ArrayList;
+
+import javax.management.MBeanException;
+import javax.management.MalformedObjectNameException;
+import javax.management.ObjectName;
+import javax.management.RuntimeOperationsException;
+
+import org.apache.catalina.core.StandardContext;
+import org.apache.catalina.deploy.ContextEnvironment;
+import org.apache.catalina.deploy.ContextResource;
+import org.apache.catalina.deploy.ContextResourceLink;
+import org.apache.catalina.deploy.NamingResources;
+import org.apache.commons.modeler.BaseModelMBean;
+import org.apache.commons.modeler.ManagedBean;
+import org.apache.commons.modeler.Registry;
+import org.apache.tomcat.util.compat.JdkCompat;
+
+/**
+ * <p>A <strong>ModelMBean</strong> implementation for the
+ * <code>org.apache.catalina.core.StandardContext</code> component.</p>
+ *
+ * @author Amy Roh
+ * @version $Revision: 303133 $ $Date: 2004-08-29 11:46:15 -0500 (Sun, 29 Aug 2004) $
+ */
+
+public class StandardContextMBean extends BaseModelMBean {
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Construct a <code>ModelMBean</code> with default
+     * <code>ModelMBeanInfo</code> information.
+     *
+     * @exception MBeanException if the initializer of an object
+     *  throws an exception
+     * @exception RuntimeOperationsException if an IllegalArgumentException
+     *  occurs
+     */
+    public StandardContextMBean()
+        throws MBeanException, RuntimeOperationsException {
+
+        super();
+
+    }
+    
+
+    // ----------------------------------------------------- Class Variables
+
+
+    /**
+     * JDK compatibility support
+     */
+    private static final JdkCompat jdkCompat = JdkCompat.getJdkCompat();
+
+
+    // ----------------------------------------------------- Instance Variables
+    
+    
+    /**
+     * The configuration information registry for our managed beans.
+     */
+    protected Registry registry = MBeanUtils.createRegistry();
+
+    /**
+     * The <code>ManagedBean</code> information describing this MBean.
+     */
+    protected ManagedBean managed =
+        registry.findManagedBean("StandardContext");
+
+    
+    // ------------------------------------------------------------- Attributes
+
+    
+    /**
+     * Return the naming resources associated with this web application.
+     */
+    private NamingResources getNamingResources() {
+        
+        return ((StandardContext)this.resource).getNamingResources();
+    
+    }
+    
+    /**
+     * Return the naming resources associated with this web application.
+     */
+    public void reload() {
+        
+        ((StandardContext)this.resource).reload();
+    
+    }
+    
+    
+    /**
+     * Return the MBean Names of the set of defined environment entries for  
+     * this web application
+     */
+    public String[] getEnvironments() {
+        ContextEnvironment[] envs = getNamingResources().findEnvironments();
+        ArrayList results = new ArrayList();
+        for (int i = 0; i < envs.length; i++) {
+            try {
+                ObjectName oname =
+                    MBeanUtils.createObjectName(managed.getDomain(), envs[i]);
+                results.add(oname.toString());
+            } catch (MalformedObjectNameException e) {
+                IllegalArgumentException iae = new IllegalArgumentException
+                    ("Cannot create object name for environment " + envs[i]);
+                jdkCompat.chainException(iae, e);
+                throw iae;
+            }
+        }
+        return ((String[]) results.toArray(new String[results.size()]));
+
+    }
+    
+    
+    /**
+     * Return the MBean Names of all the defined resource references for this
+     * application.
+     */
+    public String[] getResources() {
+        
+        ContextResource[] resources = getNamingResources().findResources();
+        ArrayList results = new ArrayList();
+        for (int i = 0; i < resources.length; i++) {
+            try {
+                ObjectName oname =
+                    MBeanUtils.createObjectName(managed.getDomain(), resources[i]);
+                results.add(oname.toString());
+            } catch (MalformedObjectNameException e) {
+                IllegalArgumentException iae = new IllegalArgumentException
+                    ("Cannot create object name for resource " + resources[i]);
+                jdkCompat.chainException(iae, e);
+                throw iae;
+            }
+        }
+        return ((String[]) results.toArray(new String[results.size()]));
+
+    }
+
+      
+    /**
+     * Return the MBean Names of all the defined resource links for this 
+     * application
+     */
+    public String[] getResourceLinks() {
+        
+        ContextResourceLink[] links = getNamingResources().findResourceLinks();
+        ArrayList results = new ArrayList();
+        for (int i = 0; i < links.length; i++) {
+            try {
+                ObjectName oname =
+                    MBeanUtils.createObjectName(managed.getDomain(), links[i]);
+                results.add(oname.toString());
+            } catch (MalformedObjectNameException e) {
+                IllegalArgumentException iae = new IllegalArgumentException
+                    ("Cannot create object name for resource " + links[i]);
+                jdkCompat.chainException(iae, e);
+                throw iae;
+            }
+        }
+        return ((String[]) results.toArray(new String[results.size()]));
+
+    }
+
+
+    /**
+     * Return the naming resources associated with this web application.
+     */
+    public javax.naming.directory.DirContext getStaticResources() {
+
+        return ((StandardContext)this.resource).getResources();
+
+    }
+
+
+    /**
+     * Return the naming resources associated with this web application.
+     */
+    public String[] getWelcomeFiles() {
+
+        return ((StandardContext)this.resource).findWelcomeFiles();
+
+    }
+
+
+    // ------------------------------------------------------------- Operations
+
+
+    /**
+     * Add an environment entry for this web application.
+     *
+     * @param envName New environment entry name
+     */
+    public String addEnvironment(String envName, String type) 
+        throws MalformedObjectNameException {
+
+        NamingResources nresources = getNamingResources();
+        if (nresources == null) {
+            return null;
+        }
+        ContextEnvironment env = nresources.findEnvironment(envName);
+        if (env != null) {
+            throw new IllegalArgumentException
+                ("Invalid environment name - already exists '" + envName + "'");
+        }
+        env = new ContextEnvironment();
+        env.setName(envName);
+        env.setType(type);
+        nresources.addEnvironment(env);
+        
+        // Return the corresponding MBean name
+        ManagedBean managed = registry.findManagedBean("ContextEnvironment");
+        ObjectName oname =
+            MBeanUtils.createObjectName(managed.getDomain(), env);
+        return (oname.toString());
+        
+    }
+
+    
+    /**
+     * Add a resource reference for this web application.
+     *
+     * @param resourceName New resource reference name
+     */
+    public String addResource(String resourceName, String type) 
+        throws MalformedObjectNameException {
+        
+        NamingResources nresources = getNamingResources();
+        if (nresources == null) {
+            return null;
+        }
+        ContextResource resource = nresources.findResource(resourceName);
+        if (resource != null) {
+            throw new IllegalArgumentException
+                ("Invalid resource name - already exists'" + resourceName + "'");
+        }
+        resource = new ContextResource();
+        resource.setName(resourceName);
+        resource.setType(type);
+        nresources.addResource(resource);
+        
+        // Return the corresponding MBean name
+        ManagedBean managed = registry.findManagedBean("ContextResource");
+        ObjectName oname =
+            MBeanUtils.createObjectName(managed.getDomain(), resource);
+        return (oname.toString());
+    }
+
+    
+    /**
+     * Add a resource link for this web application.
+     *
+     * @param resourceLinkName New resource link name
+     */
+    public String addResourceLink(String resourceLinkName, String global, 
+                String name, String type) throws MalformedObjectNameException {
+        
+        NamingResources nresources = getNamingResources();
+        if (nresources == null) {
+            return null;
+        }
+        ContextResourceLink resourceLink = 
+                                nresources.findResourceLink(resourceLinkName);
+        if (resourceLink != null) {
+            throw new IllegalArgumentException
+                ("Invalid resource link name - already exists'" + 
+                                                        resourceLinkName + "'");
+        }
+        resourceLink = new ContextResourceLink();
+        resourceLink.setGlobal(global);
+        resourceLink.setName(resourceLinkName);
+        resourceLink.setType(type);
+        nresources.addResourceLink(resourceLink);
+        
+        // Return the corresponding MBean name
+        ManagedBean managed = registry.findManagedBean("ContextResourceLink");
+        ObjectName oname =
+            MBeanUtils.createObjectName(managed.getDomain(), resourceLink);
+        return (oname.toString());
+    }    
+    
+    
+    /**
+     * Remove any environment entry with the specified name.
+     *
+     * @param envName Name of the environment entry to remove
+     */
+    public void removeEnvironment(String envName) {
+
+        NamingResources nresources = getNamingResources();
+        if (nresources == null) {
+            return;
+        }
+        ContextEnvironment env = nresources.findEnvironment(envName);
+        if (env == null) {
+            throw new IllegalArgumentException
+                ("Invalid environment name '" + envName + "'");
+        }
+        nresources.removeEnvironment(envName);
+
+    }
+    
+    
+    /**
+     * Remove any resource reference with the specified name.
+     *
+     * @param resourceName Name of the resource reference to remove
+     */
+    public void removeResource(String resourceName) {
+
+        resourceName = ObjectName.unquote(resourceName);
+        NamingResources nresources = getNamingResources();
+        if (nresources == null) {
+            return;
+        }
+        ContextResource resource = nresources.findResource(resourceName);
+        if (resource == null) {
+            throw new IllegalArgumentException
+                ("Invalid resource name '" + resourceName + "'");
+        }
+        nresources.removeResource(resourceName);
+    }
+    
+    
+    /**
+     * Remove any resource link with the specified name.
+     *
+     * @param resourceLinkName Name of the resource reference to remove
+     */
+    public void removeResourceLink(String resourceLinkName) {
+
+        resourceLinkName = ObjectName.unquote(resourceLinkName);
+        NamingResources nresources = getNamingResources();
+        if (nresources == null) {
+            return;
+        }
+        ContextResourceLink resource = nresources.findResourceLink(resourceLinkName);
+        if (resource == null) {
+            throw new IllegalArgumentException
+                ("Invalid resource name '" + resourceLinkName + "'");
+        }
+        nresources.removeResourceLink(resourceLinkName);
+    }
+ 
+    
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/mbeans/StandardEngineMBean.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/mbeans/StandardEngineMBean.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/mbeans/StandardEngineMBean.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,69 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.mbeans;
+
+
+import javax.management.MBeanException;
+import javax.management.MBeanServer;
+import javax.management.RuntimeOperationsException;
+
+import org.apache.commons.modeler.BaseModelMBean;
+
+
+/**
+ * <p>A <strong>ModelMBean</strong> implementation for the
+ * <code>org.apache.catalina.core.StandardEngine</code> component.</p>
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class StandardEngineMBean extends BaseModelMBean {
+
+    /**
+     * The <code>MBeanServer</code> for this application.
+     */
+    private static MBeanServer mserver = MBeanUtils.createServer();
+    
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Construct a <code>ModelMBean</code> with default
+     * <code>ModelMBeanInfo</code> information.
+     *
+     * @exception MBeanException if the initializer of an object
+     *  throws an exception
+     * @exception RuntimeOperationsException if an IllegalArgumentException
+     *  occurs
+     */
+    public StandardEngineMBean()
+        throws MBeanException, RuntimeOperationsException {
+
+        super();
+
+    }
+
+
+    // ------------------------------------------------------------- Attributes
+
+
+
+    // ------------------------------------------------------------- Operations
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/mbeans/StandardHostMBean.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/mbeans/StandardHostMBean.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/mbeans/StandardHostMBean.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,149 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.mbeans;
+
+
+import javax.management.MBeanException;
+import javax.management.MBeanServer;
+import javax.management.RuntimeOperationsException;
+
+import org.apache.catalina.Valve;
+import org.apache.catalina.core.StandardHost;
+import org.apache.commons.modeler.BaseModelMBean;
+import org.apache.commons.modeler.ManagedBean;
+import org.apache.commons.modeler.Registry;
+
+
+/**
+ * <p>A <strong>ModelMBean</strong> implementation for the
+ * <code>org.apache.catalina.core.StandardHost</code> component.</p>
+ *
+ * @author Amy Roh
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class StandardHostMBean extends BaseModelMBean {
+
+    /**
+     * The <code>MBeanServer</code> for this application.
+     */
+    private static MBeanServer mserver = MBeanUtils.createServer();
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Construct a <code>ModelMBean</code> with default
+     * <code>ModelMBeanInfo</code> information.
+     *
+     * @exception MBeanException if the initializer of an object
+     *  throws an exception
+     * @exception RuntimeOperationsException if an IllegalArgumentException
+     *  occurs
+     */
+    public StandardHostMBean()
+        throws MBeanException, RuntimeOperationsException {
+
+        super();
+
+    }
+
+
+    // ------------------------------------------------------------- Attributes
+
+
+
+    // ------------------------------------------------------------- Operations
+
+
+   /**
+     * Add an alias name that should be mapped to this Host
+     *
+     * @param alias The alias to be added
+     *
+     * @exception Exception if an MBean cannot be created or registered
+     */
+    public void addAlias(String alias)
+        throws Exception {
+
+        StandardHost host = (StandardHost) this.resource;
+        host.addAlias(alias);
+
+    }
+
+
+   /**
+     * Return the set of alias names for this Host
+     *
+     * @exception Exception if an MBean cannot be created or registered
+     */
+    public String [] findAliases()
+        throws Exception {
+
+        StandardHost host = (StandardHost) this.resource;
+        return host.findAliases();
+
+    }
+
+
+   /**
+     * Return the MBean Names of the Valves assoicated with this Host
+     *
+     * @exception Exception if an MBean cannot be created or registered
+     */
+    public String [] getValves()
+        throws Exception {
+
+        Registry registry = MBeanUtils.createRegistry();
+        StandardHost host = (StandardHost) this.resource;
+        String mname = MBeanUtils.createManagedName(host);
+        ManagedBean managed = registry.findManagedBean(mname);
+        String domain = null;
+        if (managed != null) {
+            domain = managed.getDomain();
+        }
+        if (domain == null)
+            domain = mserver.getDefaultDomain();
+        Valve [] valves = host.getValves();
+        String [] mbeanNames = new String[valves.length];
+        for (int i = 0; i < valves.length; i++) {
+            mbeanNames[i] =
+                MBeanUtils.createObjectName(domain, valves[i]).toString();
+        }
+
+        return mbeanNames;
+
+    }
+
+
+   /**
+     * Return the specified alias name from the aliases for this Host
+     *
+     * @param alias Alias name to be removed
+     *
+     * @exception Exception if an MBean cannot be created or registered
+     */
+    public void removeAlias(String alias)
+        throws Exception {
+
+        StandardHost host = (StandardHost) this.resource;
+        host.removeAlias(alias);
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/mbeans/StandardServerMBean.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/mbeans/StandardServerMBean.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/mbeans/StandardServerMBean.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,102 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.mbeans;
+
+
+import javax.management.InstanceNotFoundException;
+import javax.management.MBeanException;
+import javax.management.MBeanServer;
+import javax.management.RuntimeOperationsException;
+import org.apache.catalina.Server;
+import org.apache.catalina.ServerFactory;
+import org.apache.catalina.core.StandardServer;
+import org.apache.commons.modeler.BaseModelMBean;
+
+
+/**
+ * <p>A <strong>ModelMBean</strong> implementation for the
+ * <code>org.apache.catalina.core.StandardServer</code> component.</p>
+ *
+ * @author Amy Roh
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class StandardServerMBean extends BaseModelMBean {
+
+
+    // ------------------------------------------------------- Static Variables
+
+
+    /**
+     * The <code>MBeanServer</code> for this application.
+     */
+    private static MBeanServer mserver = MBeanUtils.createServer();
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Construct a <code>ModelMBean</code> with default
+     * <code>ModelMBeanInfo</code> information.
+     *
+     * @exception MBeanException if the initializer of an object
+     *  throws an exception
+     * @exception RuntimeOperationsException if an IllegalArgumentException
+     *  occurs
+     */
+    public StandardServerMBean()
+        throws MBeanException, RuntimeOperationsException {
+
+        super();
+
+    }
+
+
+    // ------------------------------------------------------------- Attributes
+
+
+    // ------------------------------------------------------------- Operations
+
+
+    /**
+     * Write the configuration information for this entire <code>Server</code>
+     * out to the server.xml configuration file.
+     *
+     * @exception InstanceNotFoundException if the managed resource object
+     *  cannot be found
+     * @exception MBeanException if the initializer of the object throws
+     *  an exception, or persistence is not supported
+     * @exception RuntimeOperationsException if an exception is reported
+     *  by the persistence mechanism
+     */
+    public synchronized void store() throws InstanceNotFoundException,
+        MBeanException, RuntimeOperationsException {
+
+        Server server = ServerFactory.getServer();
+        if (server instanceof StandardServer) {
+            try {
+                ((StandardServer) server).storeConfig();
+            } catch (Exception e) {
+                throw new MBeanException(e, "Error updating conf/server.xml");
+            }
+        }
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/mbeans/StandardServiceMBean.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/mbeans/StandardServiceMBean.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/mbeans/StandardServiceMBean.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,69 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.mbeans;
+
+
+import javax.management.MBeanException;
+import javax.management.MBeanServer;
+import javax.management.RuntimeOperationsException;
+
+import org.apache.commons.modeler.BaseModelMBean;
+
+
+/**
+ * <p>A <strong>ModelMBean</strong> implementation for the
+ * <code>org.apache.catalina.core.StandardService</code> component.</p>
+ *
+ * @author Amy Roh
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class StandardServiceMBean extends BaseModelMBean {
+
+    /**
+     * The <code>MBeanServer</code> for this application.
+     */
+    private static MBeanServer mserver = MBeanUtils.createServer();
+    
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Construct a <code>ModelMBean</code> with default
+     * <code>ModelMBeanInfo</code> information.
+     *
+     * @exception MBeanException if the initializer of an object
+     *  throws an exception
+     * @exception RuntimeOperationsException if an IllegalArgumentException
+     *  occurs
+     */
+    public StandardServiceMBean()
+        throws MBeanException, RuntimeOperationsException {
+
+        super();
+
+    }
+
+
+    // ------------------------------------------------------------- Attributes
+
+
+
+    // ------------------------------------------------------------- Operations
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/mbeans/UserMBean.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/mbeans/UserMBean.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/mbeans/UserMBean.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,243 @@
+/*
+ * Copyright 2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.mbeans;
+
+
+import java.util.ArrayList;
+import java.util.Iterator;
+
+import javax.management.MBeanException;
+import javax.management.MBeanServer;
+import javax.management.MalformedObjectNameException;
+import javax.management.ObjectName;
+import javax.management.RuntimeOperationsException;
+
+import org.apache.catalina.Group;
+import org.apache.catalina.Role;
+import org.apache.catalina.User;
+import org.apache.commons.modeler.BaseModelMBean;
+import org.apache.commons.modeler.ManagedBean;
+import org.apache.commons.modeler.Registry;
+import org.apache.tomcat.util.compat.JdkCompat;
+
+/**
+ * <p>A <strong>ModelMBean</strong> implementation for the
+ * <code>org.apache.catalina.User</code> component.</p>
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302833 $ $Date: 2004-04-14 20:44:09 -0500 (Wed, 14 Apr 2004) $
+ */
+
+public class UserMBean extends BaseModelMBean {
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Construct a <code>ModelMBean</code> with default
+     * <code>ModelMBeanInfo</code> information.
+     *
+     * @exception MBeanException if the initializer of an object
+     *  throws an exception
+     * @exception RuntimeOperationsException if an IllegalArgumentException
+     *  occurs
+     */
+    public UserMBean()
+        throws MBeanException, RuntimeOperationsException {
+
+        super();
+
+    }
+
+
+    // ----------------------------------------------------- Class Variables
+
+
+    /**
+     * JDK compatibility support
+     */
+    private static final JdkCompat jdkCompat = JdkCompat.getJdkCompat();
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The configuration information registry for our managed beans.
+     */
+    protected Registry registry = MBeanUtils.createRegistry();
+
+
+    /**
+     * The <code>MBeanServer</code> in which we are registered.
+     */
+    protected MBeanServer mserver = MBeanUtils.createServer();
+
+
+    /**
+     * The <code>ManagedBean</code> information describing this MBean.
+     */
+    protected ManagedBean managed =
+        registry.findManagedBean("User");
+
+
+    // ------------------------------------------------------------- Attributes
+
+
+    /**
+     * Return the MBean Names of all groups this user is a member of.
+     */
+    public String[] getGroups() {
+
+        User user = (User) this.resource;
+        ArrayList results = new ArrayList();
+        Iterator groups = user.getGroups();
+        while (groups.hasNext()) {
+            Group group = null;
+            try {
+                group = (Group) groups.next();
+                ObjectName oname =
+                    MBeanUtils.createObjectName(managed.getDomain(), group);
+                results.add(oname.toString());
+            } catch (MalformedObjectNameException e) {
+                IllegalArgumentException iae = new IllegalArgumentException
+                    ("Cannot create object name for group " + group);
+                jdkCompat.chainException(iae, e);
+                throw iae;
+            }
+        }
+        return ((String[]) results.toArray(new String[results.size()]));
+
+    }
+
+
+    /**
+     * Return the MBean Names of all roles assigned to this user.
+     */
+    public String[] getRoles() {
+
+        User user = (User) this.resource;
+        ArrayList results = new ArrayList();
+        Iterator roles = user.getRoles();
+        while (roles.hasNext()) {
+            Role role = null;
+            try {
+                role = (Role) roles.next();
+                ObjectName oname =
+                    MBeanUtils.createObjectName(managed.getDomain(), role);
+                results.add(oname.toString());
+            } catch (MalformedObjectNameException e) {
+                IllegalArgumentException iae = new IllegalArgumentException
+                    ("Cannot create object name for role " + role);
+                jdkCompat.chainException(iae, e);
+                throw iae;
+            }
+        }
+        return ((String[]) results.toArray(new String[results.size()]));
+
+    }
+
+
+    // ------------------------------------------------------------- Operations
+
+
+    /**
+     * Add a new {@link Group} to those this user belongs to.
+     *
+     * @param groupname Group name of the new group
+     */
+    public void addGroup(String groupname) {
+
+        User user = (User) this.resource;
+        if (user == null) {
+            return;
+        }
+        Group group = user.getUserDatabase().findGroup(groupname);
+        if (group == null) {
+            throw new IllegalArgumentException
+                ("Invalid group name '" + groupname + "'");
+        }
+        user.addGroup(group);
+
+    }
+
+
+    /**
+     * Add a new {@link Role} to those this user belongs to.
+     *
+     * @param rolename Role name of the new role
+     */
+    public void addRole(String rolename) {
+
+        User user = (User) this.resource;
+        if (user == null) {
+            return;
+        }
+        Role role = user.getUserDatabase().findRole(rolename);
+        if (role == null) {
+            throw new IllegalArgumentException
+                ("Invalid role name '" + rolename + "'");
+        }
+        user.addRole(role);
+
+    }
+
+
+    /**
+     * Remove a {@link Group} from those this user belongs to.
+     *
+     * @param groupname Group name of the old group
+     */
+    public void removeGroup(String groupname) {
+
+        User user = (User) this.resource;
+        if (user == null) {
+            return;
+        }
+        Group group = user.getUserDatabase().findGroup(groupname);
+        if (group == null) {
+            throw new IllegalArgumentException
+                ("Invalid group name '" + groupname + "'");
+        }
+        user.removeGroup(group);
+
+    }
+
+
+    /**
+     * Remove a {@link Role} from those this user belongs to.
+     *
+     * @param rolename Role name of the old role
+     */
+    public void removeRole(String rolename) {
+
+        User user = (User) this.resource;
+        if (user == null) {
+            return;
+        }
+        Role role = user.getUserDatabase().findRole(rolename);
+        if (role == null) {
+            throw new IllegalArgumentException
+                ("Invalid role name '" + rolename + "'");
+        }
+        user.removeRole(role);
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/mbeans/mbeans-descriptors.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/mbeans/mbeans-descriptors.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/mbeans/mbeans-descriptors.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,434 @@
+<?xml version="1.0"?>
+<mbeans-descriptors>
+
+  <mbean         name="MBeanFactory"
+            className="org.apache.catalina.mbeans.MBeanFactory"
+          description="Factory for MBeans and corresponding components"
+               domain="Catalina">
+
+    <!-- IMPLEMENTATION NOTE - all of the createXxxxx methods create a new  -->
+    <!-- component and attach it to Catalina's component tree.  The return  -->
+    <!-- value is the object name of the corresponding MBean for the new    -->
+    <!-- component.                                                         -->
+
+    <operation   name="createAccessLoggerValve"
+          description="Create a new AccessLoggerValve"
+               impact="ACTION"
+           returnType="java.lang.String">
+      <parameter name="parent"
+          description="MBean Name of the associated parent component"
+                 type="java.lang.String"/>
+    </operation>
+
+    <operation   name="createAjpConnector"
+          description="Create a new AjpConnector"
+               impact="ACTION"
+           returnType="java.lang.String">
+      <parameter name="parent"
+          description="MBean Name of the associated parent component"
+                 type="java.lang.String"/>
+      <parameter name="address"
+          description="The IP address on which to bind"
+                 type="java.lang.String"/>
+      <parameter name="port"
+          description="TCP port number to listen on"
+                 type="int"/>
+    </operation>
+
+    <operation   name="createDataSourceRealm"
+          description="Create a new DataSource Realm"
+               impact="ACTION"
+           returnType="java.lang.String">
+      <parameter name="parent"
+          description="MBean Name of the associated parent component"
+                 type="java.lang.String"/>
+      <parameter name="dataSourceName"
+          description="The JNDI named JDBC DataSource"
+                 type="java.lang.String"/>
+      <parameter name="roleNameCol"
+          description="The column in the user role table that names a role"
+                 type="java.lang.String"/>
+      <parameter name="userCredCol"
+          description="The column in the user table that holds the user's
+                        credentials"
+                 type="java.lang.String"/>
+      <parameter name="userNameCol"
+          description="The column in the user table that holds the user's
+                        username"
+                 type="java.lang.String"/>
+      <parameter name="userRoleTable"
+          description="The table that holds the relation between user's and
+                        roles"
+                 type="java.lang.String"/>
+      <parameter name="userTable"
+          description="The table that holds user data"
+                 type="java.lang.String"/>
+    </operation>
+
+    <operation   name="createFileLogger"
+          description="Create a new FileLogger"
+               impact="ACTION"
+           returnType="java.lang.String">
+      <parameter name="parent"
+          description="MBean Name of the associated parent component"
+                 type="java.lang.String"/>
+    </operation>
+
+    <operation   name="createHttpConnector"
+          description="Create a new HttpConnector"
+               impact="ACTION"
+           returnType="java.lang.String">
+      <parameter name="parent"
+          description="MBean Name of the associated parent component"
+                 type="java.lang.String"/>
+     <parameter name="address"
+          description="The IP address on which to bind"
+                 type="java.lang.String"/>
+      <parameter name="port"
+          description="TCP port number to listen on"
+                 type="int"/>
+    </operation>
+
+    <operation   name="createHttpsConnector"
+          description="Create a new HttpsConnector"
+               impact="ACTION"
+           returnType="java.lang.String">
+      <parameter name="parent"
+          description="MBean Name of the associated parent component"
+                 type="java.lang.String"/>
+      <parameter name="address"
+          description="The IP address on which to bind"
+                 type="java.lang.String"/>
+      <parameter name="port"
+          description="TCP port number to listen on"
+                 type="int"/>
+    </operation>
+
+    <operation   name="createJDBCRealm"
+          description="Create a new JDBC Realm"
+               impact="ACTION"
+           returnType="java.lang.String">
+      <parameter name="parent"
+          description="MBean Name of the associated parent component"
+                 type="java.lang.String"/>
+    </operation>
+
+    <operation   name="createJNDIRealm"
+          description="Create a new JNDI Realm"
+               impact="ACTION"
+           returnType="java.lang.String">
+      <parameter name="parent"
+          description="MBean Name of the associated parent component"
+					type="java.lang.String"/>
+	    <parameter name="connectionURL"
+          description="Jndi Connection URL"
+					type="java.lang.String"/>
+	    <parameter name="connectionName"
+          description="Connection name"
+					type="java.lang.String"/>
+	    <parameter name="connectionPassword"
+          description="Connection password"
+					type="java.lang.String"/>
+    </operation>
+    <operation   name="createJAASRealm"
+          description="Create a new Jaas Realm"
+               impact="ACTION"
+           returnType="java.lang.String">
+      <parameter name="parent"
+          description="MBean Name of the associated parent component"
+					type="java.lang.String"/>
+	    <parameter name="appName"
+          description="App name"
+					type="java.lang.String"/>
+	    <parameter name="userClassNames"
+          description="Users class names."
+					type="java.lang.String"/>
+	    <parameter name="roleClassNames"
+          description="Role classNames"
+					type="java.lang.String"/>
+	    <parameter name="useContextClassLoader"
+          description="Whether use context classloader"
+					type="java.lang.String"/>
+    </operation>
+
+    <operation   name="createMemoryRealm"
+          description="Create a new Memory Realm"
+               impact="ACTION"
+           returnType="java.lang.String">
+      <parameter name="parent"
+          description="MBean Name of the associated parent component"
+                 type="java.lang.String"/>
+    </operation>
+
+    <operation   name="createRemoteAddrValve"
+          description="Create a new Remote Address Filter Valve"
+               impact="ACTION"
+           returnType="java.lang.String">
+      <parameter name="parent"
+          description="MBean Name of the associated parent component"
+                 type="java.lang.String"/>
+    </operation>
+
+    <operation   name="createRemoteHostValve"
+          description="Create a new Remote Host Filter Valve"
+               impact="ACTION"
+           returnType="java.lang.String">
+      <parameter name="parent"
+          description="MBean Name of the associated parent component"
+                 type="java.lang.String"/>
+    </operation>
+
+    <operation   name="createRequestDumperValve"
+          description="Create a new Request Dumper Valve"
+               impact="ACTION"
+           returnType="java.lang.String">
+      <parameter name="parent"
+          description="MBean Name of the associated parent component"
+                 type="java.lang.String"/>
+    </operation>
+
+    <operation   name="createSingleSignOn"
+          description="Create a new Single Sign On Valve"
+               impact="ACTION"
+           returnType="java.lang.String">
+      <parameter name="parent"
+          description="MBean Name of the associated parent component"
+                 type="java.lang.String"/>
+    </operation>
+
+    <operation   name="createStandardContext"
+          description="Create a new StandardContext"
+               impact="ACTION"
+           returnType="java.lang.String">
+      <parameter name="parent"
+          description="MBean Name of the associated parent component"
+                 type="java.lang.String"/>
+      <parameter name="path"
+          description="The context path for this Context"
+                 type="java.lang.String"/>
+      <parameter name="docBase"
+          description="Document base directory (or WAR) for ths Context"
+                 type="java.lang.String"/>
+    </operation>
+
+    <operation   name="createStandardEngine"
+          description="Create a new StandardEngine"
+               impact="ACTION"
+           returnType="java.lang.String">
+      <parameter name="parent"
+          description="MBean Name of the associated parent component"
+                 type="java.lang.String"/>
+      <parameter name="name"
+          description="Unique name of this Engine"
+                 type="java.lang.String"/>
+      <parameter name="defaultHost"
+          description="Default host name for this Engine"
+                 type="java.lang.String"/>
+    </operation>
+
+    <operation   name="createStandardEngineService"
+          description="Create a new StandardEngine and StandardService"
+               impact="ACTION"
+           returnType="java.lang.String">
+      <parameter name="parent"
+          description="MBean Name of the associated parent Service"
+                 type="java.lang.String"/>
+      <parameter name="engineName"
+          description="Unique name of this Engine"
+                 type="java.lang.String"/>
+      <parameter name="defaultHost"
+          description="Default host name for this Engine"
+                 type="java.lang.String"/>
+      <parameter name="serviceName"
+          description="Unique name of this Service"
+                 type="java.lang.String"/>
+    </operation>
+
+    <operation   name="createStandardHost"
+          description="Create a new StandardHost"
+               impact="ACTION"
+           returnType="java.lang.String">
+      <parameter name="parent"
+          description="MBean Name of the associated parent component"
+                 type="java.lang.String"/>
+      <parameter name="name"
+          description="Unique name of this Host"
+                 type="java.lang.String"/>
+      <parameter name="appBase"
+          description="set host deployment directory"
+                 type="java.lang.String"/>
+      <parameter name="autoDeploy"
+          description="The auto deploy flag for this Host"
+               type="boolean"/>           
+      <parameter name="deployOnStartup"
+          description="The deploy on startup flag for this Host"
+               type="boolean"/>
+      <parameter name="deployXML"
+          description="deploy Context XML config files property"
+               type="boolean"/> 
+      <parameter name="unpackWARs"
+          description="Unpack WARs property"
+               type="boolean"/>
+      <parameter name="xmlNamespaceAware"
+          description="Attribute value used to turn on/off XML namespace awareness"
+               type="boolean"/>
+      <parameter name="xmlValidation"
+               description="Attribute value used to turn on/off XML validation"
+               type="boolean"/>
+    </operation>
+
+
+
+
+    <operation   name="createStandardManager"
+          description="Create a new StandardManager"
+               impact="ACTION"
+           returnType="java.lang.String">
+      <parameter name="parent"
+          description="MBean Name of the associated parent component"
+                 type="java.lang.String"/>
+    </operation>
+
+    <operation   name="createStandardService"
+          description="Create a new StandardService"
+               impact="ACTION"
+           returnType="java.lang.String">
+      <parameter name="parent"
+          description="MBean Name of the associated parent component"
+                 type="java.lang.String"/>
+      <parameter name="name"
+          description="Unique name of this Service"
+                 type="java.lang.String"/>
+      <parameter name="domain"
+          description="The domain of this Service"
+                 type="java.lang.String"/>
+    </operation>
+
+    <operation   name="createSystemErrLogger"
+          description="Create a new System Error Logger"
+               impact="ACTION"
+           returnType="java.lang.String">
+      <parameter name="parent"
+          description="MBean Name of the associated parent component"
+                 type="java.lang.String"/>
+    </operation>
+
+    <operation   name="createSystemOutLogger"
+          description="Create a new System Output Logger"
+               impact="ACTION"
+           returnType="java.lang.String">
+      <parameter name="parent"
+          description="MBean Name of the associated parent component"
+                 type="java.lang.String"/>
+    </operation>
+
+    <operation   name="createUserDatabaseRealm"
+          description="Create a new UserDatabase Realm"
+               impact="ACTION"
+           returnType="java.lang.String">
+      <parameter name="parent"
+          description="MBean Name of the associated parent component"
+                 type="java.lang.String"/>
+      <parameter name="resourceName"
+          description="Global JNDI resource name of our UserDatabase instance"
+                 type="java.lang.String"/>
+    </operation>
+
+    <operation   name="createWebappLoader"
+          description="Create a new Web Application Loader"
+               impact="ACTION"
+           returnType="java.lang.String">
+      <parameter name="parent"
+          description="MBean Name of the associated parent component"
+                 type="java.lang.String"/>
+    </operation>
+
+    <!-- IMPLEMENTATION NOTE - all of the removeXxxxx methods cause the     -->
+    <!-- corresponding Catalina component (and any related child            -->
+    <!-- components to be stopped (if necessary) and removed, and the       -->
+    <!-- corresponding MBeans to be destroyed.                              -->
+
+    <operation   name="removeConnector"
+          description="Remove an existing Connector"
+               impact="ACTION"
+           returnType="void">
+      <parameter name="name"
+          description="MBean Name of the component to be removed"
+                 type="java.lang.String"/>
+    </operation>
+
+    <operation   name="removeContext"
+          description="Remove an existing Context"
+               impact="ACTION"
+           returnType="void">
+      <parameter name="name"
+          description="MBean Name of the component to be removed"
+                 type="java.lang.String"/>
+    </operation>
+
+    <operation   name="removeHost"
+          description="Remove an existing Host"
+               impact="ACTION"
+           returnType="void">
+      <parameter name="name"
+          description="MBean Name of the component to be removed"
+                 type="java.lang.String"/>
+    </operation>
+
+    <operation   name="removeLoader"
+          description="Remove an existing Loader"
+               impact="ACTION"
+           returnType="void">
+      <parameter name="name"
+          description="MBean Name of the component to be removed"
+                 type="java.lang.String"/>
+    </operation>
+
+    <operation   name="removeLogger"
+          description="Remove an existing Logger"
+               impact="ACTION"
+           returnType="void">
+      <parameter name="name"
+          description="MBean Name of the component to be removed"
+                 type="java.lang.String"/>
+    </operation>
+
+    <operation   name="removeManager"
+          description="Remove an existing Manager"
+               impact="ACTION"
+           returnType="void">
+      <parameter name="name"
+          description="MBean Name of the component to be removed"
+                 type="java.lang.String"/>
+    </operation>
+
+    <operation   name="removeRealm"
+          description="Remove an existing Realm"
+               impact="ACTION"
+           returnType="void">
+      <parameter name="name"
+          description="MBean Name of the component to be removed"
+                 type="java.lang.String"/>
+    </operation>
+
+    <operation   name="removeService"
+          description="Remove an existing Service"
+               impact="ACTION"
+           returnType="void">
+      <parameter name="name"
+          description="MBean Name of the component to be removed"
+                 type="java.lang.String"/>
+    </operation>
+
+    <operation   name="removeValve"
+          description="Remove an existing Valve"
+               impact="ACTION"
+           returnType="void">
+      <parameter name="name"
+          description="MBean Name of the component to be removed"
+                 type="java.lang.String"/>
+    </operation>
+
+  </mbean>
+
+</mbeans-descriptors>

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/mbeans-descriptors.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/mbeans-descriptors.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/mbeans-descriptors.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,150 @@
+<?xml version="1.0"?>
+<mbeans-descriptors>
+
+  <mbean name="Group"
+         className="org.apache.catalina.mbeans.GroupMBean"
+          description="Group from a user database"
+               domain="Users"
+                group="Group"
+                 type="org.apache.catalina.Group">
+
+    <attribute   name="description"
+          description="Description of this group"
+                 type="java.lang.String"/>
+
+    <attribute   name="groupname"
+          description="Group name of this group"
+                 type="java.lang.String"/>
+
+    <attribute   name="roles"
+          description="MBean Names of roles for this group"
+                 type="[Ljava.lang.String;"
+            writeable="false"/>
+
+    <attribute   name="users"
+          description="MBean Names of user members of this group"
+                 type="[Ljava.lang.String;"
+            writeable="false"/>
+
+    <operation   name="addRole"
+          description="Add a new authorized role for this group"
+               impact="ACTION"
+           returnType="void">
+      <parameter name="role"
+          description="Role to be added"
+                 type="java.lang.String"/>
+    </operation>
+
+    <operation   name="removeRole"
+          description="Remove an old authorized role for this group"
+               impact="ACTION"
+           returnType="void">
+      <parameter name="role"
+          description="Role to be removed"
+                 type="java.lang.String"/>
+    </operation>
+
+    <operation   name="removeRoles"
+          description="Remove all authorized roles for this group"
+               impact="ACTION"
+           returnType="void">
+    </operation>
+
+  </mbean>
+
+  <mbean         name="Role"
+            className="org.apache.catalina.mbeans.RoleMBean"
+          description="Security role from a user database"
+               domain="Users"
+                group="Role"
+                 type="org.apache.catalina.Role">
+
+    <attribute   name="description"
+          description="Description of this role"
+                 type="java.lang.String"/>
+
+    <attribute   name="rolename"
+          description="Role name of this role"
+                 type="java.lang.String"/>
+
+  </mbean>
+
+  <mbean         name="User"
+            className="org.apache.catalina.mbeans.UserMBean"
+          description="User from a user database"
+               domain="Users"
+                group="User"
+                 type="org.apache.catalina.User">
+
+    <attribute   name="fullName"
+          description="Full name of this user"
+                 type="java.lang.String"/>
+
+    <attribute   name="groups"
+          description="MBean Names of groups this user is a member of"
+                 type="[Ljava.lang.String;"/>
+
+    <attribute   name="password"
+          description="Password of this user"
+                 type="java.lang.String"/>
+
+    <attribute   name="roles"
+          description="MBean Names of roles for this user"
+                 type="[Ljava.lang.String;"
+            writeable="false"/>
+
+    <attribute   name="username"
+          description="User name of this user"
+                 type="java.lang.String"/>
+
+    <operation   name="addGroup"
+          description="Add a new group membership for this user"
+               impact="ACTION"
+           returnType="void">
+      <parameter name="groupname"
+          description="Group name of the new group"
+                 type="java.lang.String"/>
+    </operation>
+
+    <operation   name="addRole"
+          description="Add a new authorized role for this user"
+               impact="ACTION"
+           returnType="void">
+      <parameter name="role"
+          description="Role to be added"
+                 type="java.lang.String"/>
+    </operation>
+
+    <operation   name="removeGroup"
+          description="Remove an old group membership for this user"
+               impact="ACTION"
+           returnType="void">
+      <parameter name="groupname"
+          description="Group name of the old group"
+                 type="java.lang.String"/>
+    </operation>
+
+    <operation   name="removeGroups"
+          description="Remove all group memberships for this user"
+               impact="ACTION"
+           returnType="void">
+    </operation>
+
+    <operation   name="removeRole"
+          description="Remove an old authorized role for this user"
+               impact="ACTION"
+           returnType="void">
+      <parameter name="role"
+          description="Role to be removed"
+                 type="java.lang.String"/>
+    </operation>
+
+    <operation   name="removeRoles"
+          description="Remove all authorized roles for this user"
+               impact="ACTION"
+           returnType="void">
+    </operation>
+
+  </mbean>
+
+</mbeans-descriptors>

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/realm/Constants.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/realm/Constants.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/realm/Constants.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,44 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.realm;
+
+
+/**
+ * Manifest constants for this Java package.
+ *
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public final class Constants {
+
+    public static final String Package = "org.apache.catalina.realm";
+    
+        // Authentication methods for login configuration
+    public static final String FORM_METHOD = "FORM";
+
+    // Form based authentication constants
+    public static final String FORM_ACTION = "/j_security_check";
+
+    // User data constraints for transport guarantee
+    public static final String NONE_TRANSPORT = "NONE";
+    public static final String INTEGRAL_TRANSPORT = "INTEGRAL";
+    public static final String CONFIDENTIAL_TRANSPORT = "CONFIDENTIAL";
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/realm/DataSourceRealm.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/realm/DataSourceRealm.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/realm/DataSourceRealm.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,662 @@
+/*
+ * Copyright 1999,2004-2006 The Apache Software Foundation.
+ * 
+ * Licensed 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.realm;
+
+
+import java.security.Principal;
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.ArrayList;
+
+import javax.naming.Context;
+import javax.sql.DataSource;
+
+import org.apache.naming.ContextBindings;
+import org.apache.catalina.LifecycleException;
+import org.apache.catalina.ServerFactory;
+import org.apache.catalina.core.StandardServer;
+import org.apache.catalina.util.StringManager;
+
+/**
+*
+* Implmentation of <b>Realm</b> that works with any JDBC JNDI DataSource.
+* See the JDBCRealm.howto for more details on how to set up the database and
+* for configuration options.
+*
+* @author Glenn L. Nielsen
+* @author Craig R. McClanahan
+* @author Carson McDonald
+* @author Ignacio Ortega
+* @version $Revision: 394121 $
+*/
+
+public class DataSourceRealm
+    extends RealmBase {
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The generated string for the roles PreparedStatement
+     */
+    private String preparedRoles = null;
+
+
+    /**
+     * The generated string for the credentials PreparedStatement
+     */
+    private String preparedCredentials = null;
+
+
+    /**
+     * The name of the JNDI JDBC DataSource
+     */
+    protected String dataSourceName = null;
+
+
+    /**
+     * Descriptive information about this Realm implementation.
+     */
+    protected static final String info =
+        "org.apache.catalina.realm.DataSourceRealm/1.0";
+
+
+    /**
+     * Context local datasource.
+     */
+    protected boolean localDataSource = false;
+
+
+    /**
+     * Descriptive information about this Realm implementation.
+     */
+    protected static final String name = "DataSourceRealm";
+
+
+    /**
+     * The column in the user role table that names a role
+     */
+    protected String roleNameCol = null;
+
+
+    /**
+     * The string manager for this package.
+     */
+    protected static final StringManager sm =
+        StringManager.getManager(Constants.Package);
+
+
+    /**
+     * The column in the user table that holds the user's credintials
+     */
+    protected String userCredCol = null;
+
+
+    /**
+     * The column in the user table that holds the user's name
+     */
+    protected String userNameCol = null;
+
+
+    /**
+     * The table that holds the relation between user's and roles
+     */
+    protected String userRoleTable = null;
+
+
+    /**
+     * The table that holds user data.
+     */
+    protected String userTable = null;
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * Return the name of the JNDI JDBC DataSource.
+     *
+     */
+    public String getDataSourceName() {
+        return dataSourceName;
+    }
+
+    /**
+     * Set the name of the JNDI JDBC DataSource.
+     *
+     * @param dataSourceName the name of the JNDI JDBC DataSource
+     */
+    public void setDataSourceName( String dataSourceName) {
+      this.dataSourceName = dataSourceName;
+    }
+
+    /**
+     * Return if the datasource will be looked up in the webapp JNDI Context.
+     */
+    public boolean getLocalDataSource() {
+        return localDataSource;
+    }
+
+    /**
+     * Set to true to cause the datasource to be looked up in the webapp JNDI
+     * Context.
+     *
+     * @param localDataSource the new flag value
+     */
+    public void setLocalDataSource(boolean localDataSource) {
+      this.localDataSource = localDataSource;
+    }
+
+    /**
+     * Return the column in the user role table that names a role.
+     *
+     */
+    public String getRoleNameCol() {
+        return roleNameCol;
+    }
+
+    /**
+     * Set the column in the user role table that names a role.
+     *
+     * @param roleNameCol The column name
+     */
+    public void setRoleNameCol( String roleNameCol ) {
+        this.roleNameCol = roleNameCol;
+    }
+
+    /**
+     * Return the column in the user table that holds the user's credentials.
+     *
+     */
+    public String getUserCredCol() {
+        return userCredCol;
+    }
+
+    /**
+     * Set the column in the user table that holds the user's credentials.
+     *
+     * @param userCredCol The column name
+     */
+    public void setUserCredCol( String userCredCol ) {
+       this.userCredCol = userCredCol;
+    }
+
+    /**
+     * Return the column in the user table that holds the user's name.
+     *
+     */
+    public String getUserNameCol() {
+        return userNameCol;
+    }
+
+    /**
+     * Set the column in the user table that holds the user's name.
+     *
+     * @param userNameCol The column name
+     */
+    public void setUserNameCol( String userNameCol ) {
+       this.userNameCol = userNameCol;
+    }
+
+    /**
+     * Return the table that holds the relation between user's and roles.
+     *
+     */
+    public String getUserRoleTable() {
+        return userRoleTable;
+    }
+
+    /**
+     * Set the table that holds the relation between user's and roles.
+     *
+     * @param userRoleTable The table name
+     */
+    public void setUserRoleTable( String userRoleTable ) {
+        this.userRoleTable = userRoleTable;
+    }
+
+    /**
+     * Return the table that holds user data..
+     *
+     */
+    public String getUserTable() {
+        return userTable;
+    }
+
+    /**
+     * Set the table that holds user data.
+     *
+     * @param userTable The table name
+     */
+    public void setUserTable( String userTable ) {
+      this.userTable = userTable;
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Return the Principal associated with the specified username and
+     * credentials, if there is one; otherwise return <code>null</code>.
+     *
+     * If there are any errors with the JDBC connection, executing
+     * the query or anything we return null (don't authenticate). This
+     * event is also logged, and the connection will be closed so that
+     * a subsequent request will automatically re-open it.
+     *
+     * @param username Username of the Principal to look up
+     * @param credentials Password or other credentials to use in
+     *  authenticating this username
+     */
+    public Principal authenticate(String username, String credentials) {
+    	
+    	// No user - can't possibly authenticate, don't bother the database then
+    	if (username == null) {
+    		return null;
+    	}
+        
+    	Connection dbConnection = null;
+
+        try {
+
+            // Ensure that we have an open database connection
+            dbConnection = open();
+            if (dbConnection == null) {
+                // If the db connection open fails, return "not authenticated"
+                return null;
+            }
+            
+            // Acquire a Principal object for this user
+            return authenticate(dbConnection, username, credentials);
+            
+        } catch (SQLException e) {
+            // Log the problem for posterity
+            containerLog.error(sm.getString("dataSourceRealm.exception"), e);
+
+            // Return "not authenticated" for this request
+            return (null);
+
+        } finally {
+        	close(dbConnection);
+        }
+
+    }
+
+
+    // -------------------------------------------------------- Package Methods
+
+
+    // ------------------------------------------------------ Protected Methods
+
+
+    /**
+     * Return the Principal associated with the specified username and
+     * credentials, if there is one; otherwise return <code>null</code>.
+     *
+     * @param dbConnection The database connection to be used
+     * @param username Username of the Principal to look up
+     * @param credentials Password or other credentials to use in
+     *  authenticating this username
+     */
+    protected Principal authenticate(Connection dbConnection,
+                                               String username,
+                                               String credentials) throws SQLException{
+
+        String dbCredentials = getPassword(dbConnection, username);
+
+        // Validate the user's credentials
+        boolean validated = false;
+        if (hasMessageDigest()) {
+            // Hex hashes should be compared case-insensitive
+            validated = (digest(credentials).equalsIgnoreCase(dbCredentials));
+        } else
+            validated = (digest(credentials).equals(dbCredentials));
+
+        if (validated) {
+            if (containerLog.isTraceEnabled())
+                containerLog.trace(
+                    sm.getString("dataSourceRealm.authenticateSuccess",
+                                 username));
+        } else {
+            if (containerLog.isTraceEnabled())
+                containerLog.trace(
+                    sm.getString("dataSourceRealm.authenticateFailure",
+                                 username));
+            return (null);
+        }
+
+        ArrayList list = getRoles(dbConnection, username);
+
+        // Create and return a suitable Principal for this user
+        return (new GenericPrincipal(this, username, credentials, list));
+
+    }
+
+
+    /**
+     * Close the specified database connection.
+     *
+     * @param dbConnection The connection to be closed
+     */
+    protected void close(Connection dbConnection) {
+
+        // Do nothing if the database connection is already closed
+        if (dbConnection == null)
+            return;
+
+        // Commit if not auto committed
+        try {
+            if (!dbConnection.getAutoCommit()) {
+                dbConnection.commit();
+            }            
+        } catch (SQLException e) {
+            containerLog.error("Exception committing connection before closing:", e);
+        }
+
+        // Close this database connection, and log any errors
+        try {
+            dbConnection.close();
+        } catch (SQLException e) {
+            containerLog.error(sm.getString("dataSourceRealm.close"), e); // Just log it here
+        }
+
+    }
+
+    /**
+     * Open the specified database connection.
+     *
+     * @return Connection to the database
+     */
+    protected Connection open() {
+
+        try {
+            Context context = null;
+            if (localDataSource) {
+                context = ContextBindings.getClassLoader();
+                context = (Context) context.lookup("comp/env");
+            } else {
+                StandardServer server = 
+                    (StandardServer) ServerFactory.getServer();
+                context = server.getGlobalNamingContext();
+            }
+            DataSource dataSource = (DataSource)context.lookup(dataSourceName);
+	    return dataSource.getConnection();
+        } catch (Exception e) {
+            // Log the problem for posterity
+            containerLog.error(sm.getString("dataSourceRealm.exception"), e);
+        }  
+        return null;
+    }
+
+    /**
+     * Return a short name for this Realm implementation.
+     */
+    protected String getName() {
+
+        return (name);
+
+    }
+
+    /**
+     * Return the password associated with the given principal's user name.
+     */
+    protected String getPassword(String username) {
+
+        Connection dbConnection = null;
+
+        // Ensure that we have an open database connection
+        dbConnection = open();
+        if (dbConnection == null) {
+            return null;
+        }
+
+        try {
+        	return getPassword(dbConnection, username);        	
+        } finally {
+            close(dbConnection);
+        }
+    }
+    
+    /**
+     * Return the password associated with the given principal's user name.
+     * @param dbConnection The database connection to be used
+     * @param username Username for which password should be retrieved
+     */
+    protected String getPassword(Connection dbConnection, 
+								 String username) {
+
+        ResultSet rs = null;
+        PreparedStatement stmt = null;
+        String dbCredentials = null;
+
+        try {
+            stmt = credentials(dbConnection, username);
+            rs = stmt.executeQuery();
+            if (rs.next()) {
+                dbCredentials = rs.getString(1);
+            }
+
+            return (dbCredentials != null) ? dbCredentials.trim() : null;
+            
+        } catch(SQLException e) {
+            containerLog.error(
+                    sm.getString("dataSourceRealm.getPassword.exception",
+                                 username));
+        } finally {
+        	try {
+	            if (rs != null) {
+	                rs.close();
+	            }
+	            if (stmt != null) {
+	                stmt.close();
+	            }
+        	} catch (SQLException e) {
+                    containerLog.error(
+                        sm.getString("dataSourceRealm.getPassword.exception",
+        		             username));
+        		
+        	}
+        }
+        
+        return null;
+    }
+
+
+    /**
+     * Return the Principal associated with the given user name.
+     */
+    protected Principal getPrincipal(String username) {
+    	Connection dbConnection = open();
+        if (dbConnection == null) {
+            return new GenericPrincipal(this,username, null, null);
+        }
+        try {
+        	return (new GenericPrincipal(this,
+        			username,
+					getPassword(dbConnection, username),
+					getRoles(dbConnection, username)));
+        } finally {
+        	close(dbConnection);
+        }
+
+    }
+
+    /**
+     * Return the roles associated with the given user name.
+     * @param username Username for which roles should be retrieved
+     */
+    protected ArrayList getRoles(String username) {
+
+        Connection dbConnection = null;
+
+        // Ensure that we have an open database connection
+        dbConnection = open();
+        if (dbConnection == null) {
+            return null;
+        }
+
+        try {
+            return getRoles(dbConnection, username);
+        } finally {
+        	close(dbConnection);
+        }
+    }
+    
+    /**
+     * Return the roles associated with the given user name
+     * @param dbConnection The database connection to be used
+     * @param username Username for which roles should be retrieved
+     */
+    protected ArrayList getRoles(Connection dbConnection,
+                                     String username) {
+    	
+        ResultSet rs = null;
+        PreparedStatement stmt = null;
+        ArrayList list = null;
+    	
+        try {
+    		stmt = roles(dbConnection, username);
+    		rs = stmt.executeQuery();
+    		list = new ArrayList();
+    		
+    		while (rs.next()) {
+    			String role = rs.getString(1);
+    			if (role != null) {
+    				list.add(role.trim());
+    			}
+    		}
+    		return list;
+    	} catch(SQLException e) {
+            containerLog.error(
+                sm.getString("dataSourceRealm.getRoles.exception", username));
+        }
+    	finally {
+        	try {
+	            if (rs != null) {
+	                rs.close();
+	            }
+	            if (stmt != null) {
+	                stmt.close();
+	            }
+        	} catch (SQLException e) {
+                    containerLog.error(
+                        sm.getString("dataSourceRealm.getRoles.exception",
+                                     username));
+        	}
+        }
+    	
+    	return null;
+    }
+
+    /**
+     * Return a PreparedStatement configured to perform the SELECT required
+     * to retrieve user credentials for the specified username.
+     *
+     * @param dbConnection The database connection to be used
+     * @param username Username for which credentials should be retrieved
+     *
+     * @exception SQLException if a database error occurs
+     */
+    private PreparedStatement credentials(Connection dbConnection,
+                                            String username)
+        throws SQLException {
+
+        PreparedStatement credentials =
+            dbConnection.prepareStatement(preparedCredentials);
+
+        credentials.setString(1, username);
+        return (credentials);
+
+    }
+    
+    /**
+     * Return a PreparedStatement configured to perform the SELECT required
+     * to retrieve user roles for the specified username.
+     *
+     * @param dbConnection The database connection to be used
+     * @param username Username for which roles should be retrieved
+     *
+     * @exception SQLException if a database error occurs
+     */
+    private PreparedStatement roles(Connection dbConnection, String username)
+        throws SQLException {
+
+        PreparedStatement roles = 
+            dbConnection.prepareStatement(preparedRoles);
+
+        roles.setString(1, username);
+        return (roles);
+
+    }
+
+    // ------------------------------------------------------ Lifecycle Methods
+
+
+    /**
+     *
+     * Prepare for active use of the public methods of this Component.
+     *
+     * @exception LifecycleException if this component detects a fatal error
+     *  that prevents it from being started
+     */
+    public void start() throws LifecycleException {
+
+        // Perform normal superclass initialization
+        super.start();
+
+        // Create the roles PreparedStatement string
+        StringBuffer temp = new StringBuffer("SELECT ");
+        temp.append(roleNameCol);
+        temp.append(" FROM ");
+        temp.append(userRoleTable);
+        temp.append(" WHERE ");
+        temp.append(userNameCol);
+        temp.append(" = ?");
+        preparedRoles = temp.toString();
+
+        // Create the credentials PreparedStatement string
+        temp = new StringBuffer("SELECT ");
+        temp.append(userCredCol);
+        temp.append(" FROM ");
+        temp.append(userTable);
+        temp.append(" WHERE ");
+        temp.append(userNameCol);
+        temp.append(" = ?");
+        preparedCredentials = temp.toString();
+    }
+
+
+    /**
+     * Gracefully shut down active use of the public methods of this Component.
+     *
+     * @exception LifecycleException if this component detects a fatal error
+     *  that needs to be reported
+     */
+    public void stop() throws LifecycleException {
+
+        // Perform normal superclass finalization
+        super.stop();
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/realm/GenericPrincipal.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/realm/GenericPrincipal.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/realm/GenericPrincipal.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,199 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.realm;
+
+
+import java.security.Principal;
+import java.util.Arrays;
+import java.util.List;
+import org.apache.catalina.Realm;
+
+
+/**
+ * Generic implementation of <strong>java.security.Principal</strong> that
+ * is available for use by <code>Realm</code> implementations.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 303827 $ $Date: 2005-04-01 05:36:52 -0600 (Fri, 01 Apr 2005) $
+ */
+
+public class GenericPrincipal implements Principal {
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Construct a new Principal, associated with the specified Realm, for the
+     * specified username and password.
+     *
+     * @param realm The Realm that owns this Principal
+     * @param name The username of the user represented by this Principal
+     * @param password Credentials used to authenticate this user
+     */
+    public GenericPrincipal(Realm realm, String name, String password) {
+
+        this(realm, name, password, null);
+
+    }
+
+
+    /**
+     * Construct a new Principal, associated with the specified Realm, for the
+     * specified username and password, with the specified role names
+     * (as Strings).
+     *
+     * @param realm The Realm that owns this principal
+     * @param name The username of the user represented by this Principal
+     * @param password Credentials used to authenticate this user
+     * @param roles List of roles (must be Strings) possessed by this user
+     */
+    public GenericPrincipal(Realm realm, String name, String password,
+                            List roles) {
+        this(realm, name, password, roles, null);
+    }
+
+    /**
+     * Construct a new Principal, associated with the specified Realm, for the
+     * specified username and password, with the specified role names
+     * (as Strings).
+     *
+     * @param realm The Realm that owns this principal
+     * @param name The username of the user represented by this Principal
+     * @param password Credentials used to authenticate this user
+     * @param roles List of roles (must be Strings) possessed by this user
+     * @param userPrincipal - the principal to be returned from the request 
+     *        getUserPrincipal call if not null; if null, this will be returned
+     */
+    public GenericPrincipal(Realm realm, String name, String password,
+                            List roles, Principal userPrincipal) {
+
+        super();
+        this.realm = realm;
+        this.name = name;
+        this.password = password;
+        this.userPrincipal = userPrincipal;
+        if (roles != null) {
+            this.roles = new String[roles.size()];
+            this.roles = (String[]) roles.toArray(this.roles);
+            if (this.roles.length > 0)
+                Arrays.sort(this.roles);
+        }
+    }
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * The username of the user represented by this Principal.
+     */
+    protected String name = null;
+
+    public String getName() {
+        return (this.name);
+    }
+
+
+    /**
+     * The authentication credentials for the user represented by
+     * this Principal.
+     */
+    protected String password = null;
+
+    public String getPassword() {
+        return (this.password);
+    }
+
+
+    /**
+     * The Realm with which this Principal is associated.
+     */
+    protected Realm realm = null;
+
+    public Realm getRealm() {
+        return (this.realm);
+    }
+
+    void setRealm( Realm realm ) {
+        this.realm=realm;
+    }
+
+
+    /**
+     * The set of roles associated with this user.
+     */
+    protected String roles[] = new String[0];
+
+    public String[] getRoles() {
+        return (this.roles);
+    }
+
+
+    /**
+     * The authenticated Principal to be exposed to applications.
+     */
+    protected Principal userPrincipal = null;
+
+    public Principal getUserPrincipal() {
+        if (userPrincipal != null) {
+            return userPrincipal;
+        } else {
+            return this;
+        }
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Does the user represented by this Principal possess the specified role?
+     *
+     * @param role Role to be tested
+     */
+    public boolean hasRole(String role) {
+
+        if("*".equals(role)) // Special 2.4 role meaning everyone
+            return true;
+        if (role == null)
+            return (false);
+        return (Arrays.binarySearch(roles, role) >= 0);
+
+    }
+
+
+    /**
+     * Return a String representation of this object, which exposes only
+     * information that should be public.
+     */
+    public String toString() {
+
+        StringBuffer sb = new StringBuffer("GenericPrincipal[");
+        sb.append(this.name);
+        sb.append("(");
+        for( int i=0;i<roles.length; i++ ) {
+            sb.append( roles[i]).append(",");
+        }
+        sb.append(")]");
+        return (sb.toString());
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/realm/JAASCallbackHandler.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/realm/JAASCallbackHandler.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/realm/JAASCallbackHandler.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,144 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.realm;
+
+
+import java.io.IOException;
+import javax.security.auth.callback.Callback;
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.auth.callback.NameCallback;
+import javax.security.auth.callback.PasswordCallback;
+import javax.security.auth.callback.UnsupportedCallbackException;
+
+import org.apache.catalina.util.StringManager;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * <p>Implementation of the JAAS <code>CallbackHandler</code> interface,
+ * used to negotiate delivery of the username and credentials that were
+ * specified to our constructor.  No interaction with the user is required
+ * (or possible).</p>
+ *
+ * <p>This <code>CallbackHandler</code> will pre-digest the supplied
+ * password, if required by the <code>&lt;Realm&gt;</code> element in 
+ * <code>server.xml</code>.</p>
+ * <p>At present, <code>JAASCallbackHandler</code> knows how to handle callbacks of
+ * type <code>javax.security.auth.callback.NameCallback</code> and
+ * <code>javax.security.auth.callback.PasswordCallback</code>.</p>
+ *
+ * @author Craig R. McClanahan
+ * @author Andrew R. Jaquith
+ * @version $Revision: 303719 $ $Date: 2005-02-18 17:43:20 -0600 (Fri, 18 Feb 2005) $
+ */
+
+public class JAASCallbackHandler implements CallbackHandler {
+    private static Log log = LogFactory.getLog(JAASCallbackHandler.class);
+
+    // ------------------------------------------------------------ Constructor
+
+
+    /**
+     * Construct a callback handler configured with the specified values.
+     * Note that if the <code>JAASRealm</code> instance specifies digested passwords,
+     * the <code>password</code> parameter will be pre-digested here.
+     *
+     * @param realm Our associated JAASRealm instance
+     * @param username Username to be authenticated with
+     * @param password Password to be authenticated with
+     */
+    public JAASCallbackHandler(JAASRealm realm, String username,
+                               String password) {
+
+        super();
+        this.realm = realm;
+        this.username = username;
+
+        if (realm.hasMessageDigest()) {
+            this.password = realm.digest(password);
+        }
+        else {
+            this.password = password;
+        }
+    }
+
+
+    // ----------------------------------------------------- Instance Variables
+
+    /**
+     * The string manager for this package.
+     */
+    protected static final StringManager sm =
+        StringManager.getManager(Constants.Package);
+
+    /**
+     * The password to be authenticated with.
+     */
+    protected String password = null;
+
+
+    /**
+     * The associated <code>JAASRealm</code> instance.
+     */
+    protected JAASRealm realm = null;
+
+
+    /**
+     * The username to be authenticated with.
+     */
+    protected String username = null;
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Retrieve the information requested in the provided <code>Callbacks</code>.
+     * This implementation only recognizes <code>NameCallback</code> and
+     * <code>PasswordCallback</code> instances.
+     *
+     * @param callbacks The set of <code>Callback</code>s to be processed
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception UnsupportedCallbackException if the login method requests
+     *  an unsupported callback type
+     */
+    public void handle(Callback callbacks[])
+        throws IOException, UnsupportedCallbackException {
+
+        for (int i = 0; i < callbacks.length; i++) {
+
+            if (callbacks[i] instanceof NameCallback) {
+                if (realm.getContainer().getLogger().isTraceEnabled())
+                    realm.getContainer().getLogger().trace(sm.getString("jaasCallback.username", username));
+                ((NameCallback) callbacks[i]).setName(username);
+            } else if (callbacks[i] instanceof PasswordCallback) {
+                final char[] passwordcontents;
+                if (password != null) {
+                    passwordcontents = password.toCharArray();
+                } else {
+                    passwordcontents = new char[0];
+                }
+                ((PasswordCallback) callbacks[i]).setPassword
+                    (passwordcontents);
+            } else {
+                throw new UnsupportedCallbackException(callbacks[i]);
+            }
+        }
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/realm/JAASMemoryLoginModule.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/realm/JAASMemoryLoginModule.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/realm/JAASMemoryLoginModule.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,386 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.realm;
+
+
+import java.io.File;
+import java.io.IOException;
+import java.security.Principal;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.security.auth.Subject;
+import javax.security.auth.callback.Callback;
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.auth.callback.NameCallback;
+import javax.security.auth.callback.PasswordCallback;
+import javax.security.auth.callback.UnsupportedCallbackException;
+import javax.security.auth.login.FailedLoginException;
+import javax.security.auth.login.LoginException;
+import javax.security.auth.spi.LoginModule;
+
+import org.apache.catalina.Context;
+import org.apache.catalina.Realm;
+import org.apache.catalina.connector.Request;
+import org.apache.catalina.deploy.SecurityConstraint;
+import org.apache.catalina.util.RequestUtil;
+import org.apache.catalina.util.StringManager;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.tomcat.util.digester.Digester;
+
+
+/**
+ * <p>Implementation of the JAAS <strong>LoginModule</strong> interface,
+ * primarily for use in testing <code>JAASRealm</code>.  It utilizes an
+ * XML-format data file of username/password/role information identical to
+ * that supported by <code>org.apache.catalina.realm.MemoryRealm</code>
+ * (except that digested passwords are not supported).</p>
+ *
+ * <p>This class recognizes the following string-valued options, which are
+ * specified in the configuration file (and passed to our constructor in
+ * the <code>options</code> argument:</p>
+ * <ul>
+ * <li><strong>debug</strong> - Set to "true" to get debugging messages
+ *     generated to System.out.  The default value is <code>false</code>.</li>
+ * <li><strong>pathname</strong> - Relative (to the pathname specified by the
+ *     "catalina.base" system property) or absolute pahtname to the
+ *     XML file containing our user information, in the format supported by
+ *     {@link MemoryRealm}.  The default value matches the MemoryRealm
+ *     default.</li>
+ * </ul>
+ *
+ * <p><strong>IMPLEMENTATION NOTE</strong> - This class implements
+ * <code>Realm</code> only to satisfy the calling requirements of the
+ * <code>GenericPrincipal</code> constructor.  It does not actually perform
+ * the functionality required of a <code>Realm</code> implementation.</p>
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 303719 $ $Date: 2005-02-18 17:43:20 -0600 (Fri, 18 Feb 2005) $
+ */
+
+public class JAASMemoryLoginModule extends MemoryRealm implements LoginModule, Realm {
+    // We need to extend MemoryRealm to avoid class cast
+
+    private static Log log = LogFactory.getLog(JAASMemoryLoginModule.class);
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The callback handler responsible for answering our requests.
+     */
+    protected CallbackHandler callbackHandler = null;
+
+
+    /**
+     * Has our own <code>commit()</code> returned successfully?
+     */
+    protected boolean committed = false;
+
+
+    /**
+     * The configuration information for this <code>LoginModule</code>.
+     */
+    protected Map options = null;
+
+
+    /**
+     * The absolute or relative pathname to the XML configuration file.
+     */
+    protected String pathname = "conf/tomcat-users.xml";
+
+
+    /**
+     * The <code>Principal</code> identified by our validation, or
+     * <code>null</code> if validation falied.
+     */
+    protected Principal principal = null;
+
+
+    /**
+     * The set of <code>Principals</code> loaded from our configuration file.
+     */
+    protected HashMap principals = new HashMap();
+
+    /**
+     * The string manager for this package.
+     */
+    protected static StringManager sm =
+        StringManager.getManager(Constants.Package);
+
+    /**
+     * The state information that is shared with other configured
+     * <code>LoginModule</code> instances.
+     */
+    protected Map sharedState = null;
+
+
+    /**
+     * The subject for which we are performing authentication.
+     */
+    protected Subject subject = null;
+
+
+    // --------------------------------------------------------- Public Methods
+
+    public JAASMemoryLoginModule() {
+        log.debug("MEMORY LOGIN MODULE");
+    }
+
+    /**
+     * Phase 2 of authenticating a <code>Subject</code> when Phase 1
+     * fails.  This method is called if the <code>LoginContext</code>
+     * failed somewhere in the overall authentication chain.
+     *
+     * @return <code>true</code> if this method succeeded, or
+     *  <code>false</code> if this <code>LoginModule</code> should be
+     *  ignored
+     *
+     * @exception LoginException if the abort fails
+     */
+    public boolean abort() throws LoginException {
+
+        // If our authentication was not successful, just return false
+        if (principal == null)
+            return (false);
+
+        // Clean up if overall authentication failed
+        if (committed)
+            logout();
+        else {
+            committed = false;
+            principal = null;
+        }
+        log.debug("Abort");
+        return (true);
+
+    }
+
+
+    /**
+     * Phase 2 of authenticating a <code>Subject</code> when Phase 1
+     * was successful.  This method is called if the <code>LoginContext</code>
+     * succeeded in the overall authentication chain.
+     *
+     * @return <code>true</code> if the authentication succeeded, or
+     *  <code>false</code> if this <code>LoginModule</code> should be
+     *  ignored
+     *
+     * @exception LoginException if the commit fails
+     */
+    public boolean commit() throws LoginException {
+        log.debug("commit " + principal);
+
+        // If authentication was not successful, just return false
+        if (principal == null)
+            return (false);
+
+        // Add our Principal to the Subject if needed
+        if (!subject.getPrincipals().contains(principal))
+            subject.getPrincipals().add(principal);
+
+        committed = true;
+        return (true);
+
+    }
+
+    
+    /**
+     * Return the SecurityConstraints configured to guard the request URI for
+     * this request, or <code>null</code> if there is no such constraint.
+     *
+     * @param request Request we are processing
+     * @param context Context the Request is mapped to
+     */
+    public SecurityConstraint [] findSecurityConstraints(Request request,
+                                                     Context context) {
+        ArrayList results = null;
+        // Are there any defined security constraints?
+        SecurityConstraint constraints[] = context.findConstraints();
+        if ((constraints == null) || (constraints.length == 0)) {
+            if (context.getLogger().isDebugEnabled())
+                context.getLogger().debug("  No applicable constraints defined");
+            return (null);
+        }
+
+        // Check each defined security constraint
+        String uri = request.getDecodedRequestURI();
+        String contextPath = request.getContextPath();
+        if (contextPath.length() > 0)
+            uri = uri.substring(contextPath.length());
+        uri = RequestUtil.URLDecode(uri); // Before checking constraints
+        String method = request.getMethod();
+        for (int i = 0; i < constraints.length; i++) {
+            if (context.getLogger().isDebugEnabled())
+                context.getLogger().debug("  Checking constraint '" + constraints[i] +
+                    "' against " + method + " " + uri + " --> " +
+                    constraints[i].included(uri, method));
+            if (constraints[i].included(uri, method)) {
+                if(results == null) {
+                    results = new ArrayList();
+                }
+                results.add(constraints[i]);
+            }
+        }
+
+        // No applicable security constraint was found
+        if (context.getLogger().isDebugEnabled())
+            context.getLogger().debug("  No applicable constraint located");
+        if(results == null)
+            return null;
+        SecurityConstraint [] array = new SecurityConstraint[results.size()];
+        System.arraycopy(results.toArray(), 0, array, 0, array.length);
+        return array;
+    }
+    
+    
+    /**
+     * Initialize this <code>LoginModule</code> with the specified
+     * configuration information.
+     *
+     * @param subject The <code>Subject</code> to be authenticated
+     * @param callbackHandler A <code>CallbackHandler</code> for communicating
+     *  with the end user as necessary
+     * @param sharedState State information shared with other
+     *  <code>LoginModule</code> instances
+     * @param options Configuration information for this specific
+     *  <code>LoginModule</code> instance
+     */
+    public void initialize(Subject subject, CallbackHandler callbackHandler,
+                           Map sharedState, Map options) {
+        log.debug("Init");
+
+        // Save configuration values
+        this.subject = subject;
+        this.callbackHandler = callbackHandler;
+        this.sharedState = sharedState;
+        this.options = options;
+
+        // Perform instance-specific initialization
+        if (options.get("pathname") != null)
+            this.pathname = (String) options.get("pathname");
+
+        // Load our defined Principals
+        load();
+
+    }
+
+
+    /**
+     * Phase 1 of authenticating a <code>Subject</code>.
+     *
+     * @return <code>true</code> if the authentication succeeded, or
+     *  <code>false</code> if this <code>LoginModule</code> should be
+     *  ignored
+     *
+     * @exception LoginException if the authentication fails
+     */
+    public boolean login() throws LoginException {
+
+        // Set up our CallbackHandler requests
+        if (callbackHandler == null)
+            throw new LoginException("No CallbackHandler specified");
+        Callback callbacks[] = new Callback[2];
+        callbacks[0] = new NameCallback("Username: ");
+        callbacks[1] = new PasswordCallback("Password: ", false);
+
+        // Interact with the user to retrieve the username and password
+        String username = null;
+        String password = null;
+        try {
+            callbackHandler.handle(callbacks);
+            username = ((NameCallback) callbacks[0]).getName();
+            password =
+                new String(((PasswordCallback) callbacks[1]).getPassword());
+        } catch (IOException e) {
+            throw new LoginException(e.toString());
+        } catch (UnsupportedCallbackException e) {
+            throw new LoginException(e.toString());
+        }
+
+        // Validate the username and password we have received
+        principal = super.authenticate(username, password);
+
+        log.debug("login " + username + " " + principal);
+
+        // Report results based on success or failure
+        if (principal != null) {
+            return (true);
+        } else {
+            throw new
+                FailedLoginException("Username or password is incorrect");
+        }
+
+    }
+
+
+    /**
+     * Log out this user.
+     *
+     * @return <code>true</code> in all cases because thie
+     *  <code>LoginModule</code> should not be ignored
+     *
+     * @exception LoginException if logging out failed
+     */
+    public boolean logout() throws LoginException {
+
+        subject.getPrincipals().remove(principal);
+        committed = false;
+        principal = null;
+        return (true);
+
+    }
+
+
+    // ---------------------------------------------------------- Realm Methods
+    // ------------------------------------------------------ Protected Methods
+
+
+    /**
+     * Load the contents of our configuration file.
+     */
+    protected void load() {
+
+        // Validate the existence of our configuration file
+        File file = new File(pathname);
+        if (!file.isAbsolute())
+            file = new File(System.getProperty("catalina.base"), pathname);
+        if (!file.exists() || !file.canRead()) {
+            log.warn("Cannot load configuration file " + file.getAbsolutePath());
+            return;
+        }
+
+        // Load the contents of our configuration file
+        Digester digester = new Digester();
+        digester.setValidating(false);
+        digester.addRuleSet(new MemoryRuleSet());
+        try {
+            digester.push(this);
+            digester.parse(file);
+        } catch (Exception e) {
+            log.warn("Error processing configuration file " +
+                file.getAbsolutePath(), e);
+            return;
+        } finally {
+            digester.reset();
+        }
+
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/realm/JAASRealm.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/realm/JAASRealm.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/realm/JAASRealm.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,571 @@
+/*
+ * Copyright 2001-2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.realm;
+
+
+import java.security.Principal;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import javax.security.auth.Subject;
+import javax.security.auth.login.AccountExpiredException;
+import javax.security.auth.login.CredentialExpiredException;
+import javax.security.auth.login.FailedLoginException;
+import javax.security.auth.login.LoginContext;
+import javax.security.auth.login.LoginException;
+
+import org.apache.catalina.Container;
+import org.apache.catalina.LifecycleException;
+import org.apache.catalina.util.StringManager;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+
+/**
+ * <p>Implmentation of <b>Realm</b> that authenticates users via the <em>Java
+ * Authentication and Authorization Service</em> (JAAS).  JAAS support requires
+ * either JDK 1.4 (which includes it as part of the standard platform) or
+ * JDK 1.3 (with the plug-in <code>jaas.jar</code> file).</p>
+ *
+ * <p>The value configured for the <code>appName</code> property is passed to
+ * the <code>javax.security.auth.login.LoginContext</code> constructor, to
+ * specify the <em>application name</em> used to select the set of relevant
+ * <code>LoginModules</code> required.</p>
+ *
+ * <p>The JAAS Specification describes the result of a successful login as a
+ * <code>javax.security.auth.Subject</code> instance, which can contain zero
+ * or more <code>java.security.Principal</code> objects in the return value
+ * of the <code>Subject.getPrincipals()</code> method.  However, it provides
+ * no guidance on how to distinguish Principals that describe the individual
+ * user (and are thus appropriate to return as the value of
+ * request.getUserPrincipal() in a web application) from the Principal(s)
+ * that describe the authorized roles for this user.  To maintain as much
+ * independence as possible from the underlying <code>LoginMethod</code>
+ * implementation executed by JAAS, the following policy is implemented by
+ * this Realm:</p>
+ * <ul>
+ * <li>The JAAS <code>LoginModule</code> is assumed to return a
+ *     <code>Subject</code> with at least one <code>Principal</code> instance
+ *     representing the user himself or herself, and zero or more separate
+ *     <code>Principals</code> representing the security roles authorized
+ *     for this user.</li>
+ * <li>On the <code>Principal</code> representing the user, the Principal
+ *     name is an appropriate value to return via the Servlet API method
+ *     <code>HttpServletRequest.getRemoteUser()</code>.</li>
+ * <li>On the <code>Principals</code> representing the security roles, the
+ *     name is the name of the authorized security role.</li>
+ * <li>This Realm will be configured with two lists of fully qualified Java
+ *     class names of classes that implement
+ *     <code>java.security.Principal</code> - one that identifies class(es)
+ *     representing a user, and one that identifies class(es) representing
+ *     a security role.</li>
+ * <li>As this Realm iterates over the <code>Principals</code> returned by
+ *     <code>Subject.getPrincipals()</code>, it will identify the first
+ *     <code>Principal</code> that matches the "user classes" list as the
+ *     <code>Principal</code> for this user.</li>
+ * <li>As this Realm iterates over the <code>Princpals</code> returned by
+ *     <code>Subject.getPrincipals()</code>, it will accumulate the set of
+ *     all <code>Principals</code> matching the "role classes" list as
+ *     identifying the security roles for this user.</li>
+ * <li>It is a configuration error for the JAAS login method to return a
+ *     validated <code>Subject</code> without a <code>Principal</code> that
+ *     matches the "user classes" list.</li>
+ * <li>By default, the enclosing Container's name serves as the
+ *     application name used to obtain the JAAS LoginContext ("Catalina" in
+ *     a default installation). Tomcat must be able to find an application
+ *     with this name in the JAAS configuration file. Here is a hypothetical
+ *     JAAS configuration file entry for a database-oriented login module that uses 
+ *     a Tomcat-managed JNDI database resource:
+ *     <blockquote><pre>Catalina {
+org.foobar.auth.DatabaseLoginModule REQUIRED
+    JNDI_RESOURCE=jdbc/AuthDB
+  USER_TABLE=users
+  USER_ID_COLUMN=id
+  USER_NAME_COLUMN=name
+  USER_CREDENTIAL_COLUMN=password
+  ROLE_TABLE=roles
+  ROLE_NAME_COLUMN=name
+  PRINCIPAL_FACTORY=org.foobar.auth.impl.SimplePrincipalFactory;
+};</pre></blockquote></li>
+ * <li>To set the JAAS configuration file
+ *     location, set the <code>CATALINA_OPTS</code> environment variable
+ *     similar to the following:
+<blockquote><code>CATALINA_OPTS="-Djava.security.auth.login.config=$CATALINA_HOME/conf/jaas.config"</code></blockquote>
+ * </li>
+ * <li>As part of the login process, JAASRealm registers its own <code>CallbackHandler</code>,
+ *     called (unsurprisingly) <code>JAASCallbackHandler</code>. This handler supplies the 
+ *     HTTP requests's username and credentials to the user-supplied <code>LoginModule</code></li>
+ * <li>As with other <code>Realm</code> implementations, digested passwords are supported if
+ *     the <code>&lt;Realm&gt;</code> element in <code>server.xml</code> contains a 
+ *     <code>digest</code> attribute; <code>JAASCallbackHandler</code> will digest the password
+ *     prior to passing it back to the <code>LoginModule</code></li>  
+* </ul>
+*
+* @author Craig R. McClanahan
+* @author Yoav Shapira
+ * @version $Revision: 303827 $ $Date: 2005-04-01 05:36:52 -0600 (Fri, 01 Apr 2005) $
+ */
+
+public class JAASRealm
+    extends RealmBase
+ {
+    private static Log log = LogFactory.getLog(JAASRealm.class);
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The application name passed to the JAAS <code>LoginContext</code>,
+     * which uses it to select the set of relevant <code>LoginModule</code>s.
+     */
+    protected String appName = null;
+
+
+    /**
+     * Descriptive information about this <code>Realm</code> implementation.
+     */
+    protected static final String info =
+        "org.apache.catalina.realm.JAASRealm/1.0";
+
+
+    /**
+     * Descriptive information about this <code>Realm</code> implementation.
+     */
+    protected static final String name = "JAASRealm";
+
+
+    /**
+     * The list of role class names, split out for easy processing.
+     */
+    protected List roleClasses = new ArrayList();
+
+
+    /**
+     * The string manager for this package.
+     */
+    protected static final StringManager sm =
+        StringManager.getManager(Constants.Package);
+
+
+    /**
+     * The set of user class names, split out for easy processing.
+     */
+    protected List userClasses = new ArrayList();
+
+
+    /**
+     * Whether to use context ClassLoader or default ClassLoader.
+     * True means use context ClassLoader, and True is the default
+     * value.
+     */
+     protected boolean useContextClassLoader = true;
+
+
+    // ------------------------------------------------------------- Properties
+
+    
+    /**
+     * setter for the <code>appName</code> member variable
+     * @deprecated JAAS should use the <code>Engine</code> (domain) name and webpp/host overrides
+     */
+    public void setAppName(String name) {
+        appName = name;
+    }
+    
+    /**
+     * getter for the <code>appName</code> member variable
+     */
+    public String getAppName() {
+        return appName;
+    }
+
+    /**
+     * Sets whether to use the context or default ClassLoader.
+     * True means use context ClassLoader.
+     *
+     * @param useContext True means use context ClassLoader
+     */
+    public void setUseContextClassLoader(boolean useContext) {
+      useContextClassLoader = useContext;
+      log.info("Setting useContextClassLoader = " + useContext);
+    }
+
+    /**
+     * Returns whether to use the context or default ClassLoader.
+     * True means to use the context ClassLoader.
+     *
+     * @return The value of useContextClassLoader
+     */
+    public boolean isUseContextClassLoader() {
+	return useContextClassLoader;
+    } 
+
+    public void setContainer(Container container) {
+        super.setContainer(container);
+
+        if( appName==null  ) {
+            String name=container.getName();
+            name = makeLegalForJAAS(name);
+
+            appName=name;
+
+            log.info("Set JAAS app name " + appName);
+        }
+    }
+
+    /**
+     * Comma-delimited list of <code>java.security.Principal</code> classes
+     * that represent security roles.
+     */
+    protected String roleClassNames = null;
+
+    public String getRoleClassNames() {
+        return (this.roleClassNames);
+    }
+
+     /**
+      * Sets the list of comma-delimited classes that represent 
+      * roles. The classes in the list must implement <code>java.security.Principal</code>.
+      * When this accessor is called (for example, by a <code>Digester</code>
+      * instance parsing the
+      * configuration file), it will parse the class names and store the resulting
+      * string(s) into the <code>ArrayList</code> field </code>roleClasses</code>.
+      */
+     public void setRoleClassNames(String roleClassNames) {
+         this.roleClassNames = roleClassNames;
+        roleClasses.clear();
+        String temp = this.roleClassNames;
+        if (temp == null) {
+            return;
+        }
+        while (true) {
+            int comma = temp.indexOf(',');
+            if (comma < 0) {
+                break;
+            }
+            roleClasses.add(temp.substring(0, comma).trim());
+            temp = temp.substring(comma + 1);
+        }
+        temp = temp.trim();
+        if (temp.length() > 0) {
+            roleClasses.add(temp);
+        }
+    }
+
+
+    /**
+     * Comma-delimited list of <code>java.security.Principal</code> classes
+     * that represent individual users.
+     */
+    protected String userClassNames = null;
+
+    public String getUserClassNames() {
+        return (this.userClassNames);
+    }
+
+     /**
+     * Sets the list of comma-delimited classes that represent individual
+     * users. The classes in the list must implement <code>java.security.Principal</code>.
+     * When this accessor is called (for example, by a <code>Digester</code>
+     * instance parsing the
+     * configuration file), it will parse the class names and store the resulting
+     * string(s) into the <code>ArrayList</code> field </code>userClasses</code>.
+     */
+    public void setUserClassNames(String userClassNames) {
+        this.userClassNames = userClassNames;
+        userClasses.clear();
+        String temp = this.userClassNames;
+        if (temp == null) {
+            return;
+        }
+        while (true) {
+            int comma = temp.indexOf(',');
+            if (comma < 0) {
+                break;
+            }
+            userClasses.add(temp.substring(0, comma).trim());
+            temp = temp.substring(comma + 1);
+        }
+        temp = temp.trim();
+        if (temp.length() > 0) {
+            userClasses.add(temp);
+        }
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Return the <code>Principal</code> associated with the specified username and
+     * credentials, if there is one; otherwise return <code>null</code>.
+     *
+     * If there are any errors with the JDBC connection, executing
+     * the query or anything we return null (don't authenticate). This
+     * event is also logged, and the connection will be closed so that
+     * a subsequent request will automatically re-open it.
+     *
+     * @param username Username of the <code>Principal</code> to look up
+     * @param credentials Password or other credentials to use in
+     *  authenticating this username
+     */
+    public Principal authenticate(String username, String credentials) {
+
+        // Establish a LoginContext to use for authentication
+        try {
+        LoginContext loginContext = null;
+        if( appName==null ) appName="Tomcat";
+
+        if( log.isDebugEnabled())
+            log.debug(sm.getString("jaasRealm.beginLogin", username, appName));
+
+        // What if the LoginModule is in the container class loader ?
+        ClassLoader ocl = null;
+
+        if (isUseContextClassLoader()) {
+          ocl=Thread.currentThread().getContextClassLoader();
+          Thread.currentThread().setContextClassLoader(this.getClass().getClassLoader());
+        }
+
+        try {
+            loginContext = new LoginContext
+                (appName, new JAASCallbackHandler(this, username,
+                                                  credentials));
+        } catch (Throwable e) {
+            log.error(sm.getString("jaasRealm.unexpectedError"), e);
+            return (null);
+        } finally {
+            if( isUseContextClassLoader()) {
+              Thread.currentThread().setContextClassLoader(ocl);
+            }
+        }
+
+        if( log.isDebugEnabled())
+            log.debug("Login context created " + username);
+
+        // Negotiate a login via this LoginContext
+        Subject subject = null;
+        try {
+            loginContext.login();
+            subject = loginContext.getSubject();
+            if (subject == null) {
+                if( log.isDebugEnabled())
+                    log.debug(sm.getString("jaasRealm.failedLogin", username));
+                return (null);
+            }
+        } catch (AccountExpiredException e) {
+            if (log.isDebugEnabled())
+                log.debug(sm.getString("jaasRealm.accountExpired", username));
+            return (null);
+        } catch (CredentialExpiredException e) {
+            if (log.isDebugEnabled())
+                log.debug(sm.getString("jaasRealm.credentialExpired", username));
+            return (null);
+        } catch (FailedLoginException e) {
+            if (log.isDebugEnabled())
+                log.debug(sm.getString("jaasRealm.failedLogin", username));
+            return (null);
+        } catch (LoginException e) {
+            log.warn(sm.getString("jaasRealm.loginException", username), e);
+            return (null);
+        } catch (Throwable e) {
+            log.error(sm.getString("jaasRealm.unexpectedError"), e);
+            return (null);
+        }
+
+        if( log.isDebugEnabled())
+            log.debug(sm.getString("jaasRealm.loginContextCreated", username));
+
+        // Return the appropriate Principal for this authenticated Subject
+        Principal principal = createPrincipal(username, subject);
+        if (principal == null) {
+            log.debug(sm.getString("jaasRealm.authenticateFailure", username));
+            return (null);
+        }
+        if (log.isDebugEnabled()) {
+            log.debug(sm.getString("jaasRealm.authenticateSuccess", username));
+        }
+
+        return (principal);
+        } catch( Throwable t) {
+            log.error( "error ", t);
+            return null;
+        }
+    }
+     
+
+    // -------------------------------------------------------- Package Methods
+
+
+    // ------------------------------------------------------ Protected Methods
+
+
+    /**
+     * Return a short name for this <code>Realm</code> implementation.
+     */
+    protected String getName() {
+
+        return (name);
+
+    }
+
+
+    /**
+     * Return the password associated with the given principal's user name.
+     */
+    protected String getPassword(String username) {
+
+        return (null);
+
+    }
+
+
+    /**
+     * Return the <code>Principal</code> associated with the given user name.
+     */
+    protected Principal getPrincipal(String username) {
+
+        return (null);
+
+    }
+
+
+    /**
+     * Identify and return a <code>java.security.Principal</code> instance
+     * representing the authenticated user for the specified <code>Subject</code>.
+     * The Principal is constructed by scanning the list of Principals returned
+     * by the JAASLoginModule. The first <code>Principal</code> object that matches
+     * one of the class names supplied as a "user class" is the user Principal.
+     * This object is returned to tha caller.
+     * Any remaining principal objects returned by the LoginModules are mapped to  
+     * roles, but only if their respective classes match one of the "role class" classes. 
+     * If a user Principal cannot be constructed, return <code>null</code>.
+     * @param subject The <code>Subject</code> representing the logged-in user
+     */
+    protected Principal createPrincipal(String username, Subject subject) {
+        // Prepare to scan the Principals for this Subject
+        String password = null; // Will not be carried forward
+
+        List roles = new ArrayList();
+        Principal userPrincipal = null;
+
+        // Scan the Principals for this Subject
+        Iterator principals = subject.getPrincipals().iterator();
+        while (principals.hasNext()) {
+            Principal principal = (Principal) principals.next();
+
+            String principalClass = principal.getClass().getName();
+
+            if( log.isDebugEnabled() ) {
+                log.debug(sm.getString("jaasRealm.checkPrincipal", principal, principalClass));
+            }
+
+            if (userPrincipal == null && userClasses.contains(principalClass)) {
+                userPrincipal = principal;
+                if( log.isDebugEnabled() ) {
+                    log.debug(sm.getString("jaasRealm.userPrincipalSuccess", principal.getName()));
+                }
+            }
+            
+            if (roleClasses.contains(principalClass)) {
+                roles.add(principal.getName());
+                if( log.isDebugEnabled() ) {
+                    log.debug(sm.getString("jaasRealm.rolePrincipalAdd", principal.getName()));
+                }
+            }
+        }
+
+        // Print failure message if needed
+        if (userPrincipal == null) {
+            if (log.isDebugEnabled()) {
+                log.debug(sm.getString("jaasRealm.userPrincipalFailure"));
+                log.debug(sm.getString("jaasRealm.rolePrincipalFailure"));
+            }
+        } else {
+            if (roles.size() == 0) {
+                if (log.isDebugEnabled()) {
+                    log.debug(sm.getString("jaasRealm.rolePrincipalFailure"));
+                }
+            }
+        }
+
+        // Return the resulting Principal for our authenticated user
+        return new GenericPrincipal(this, username, null, roles, userPrincipal);
+    }
+
+     /**
+      * Ensure the given name is legal for JAAS configuration.
+      * Added for Bugzilla 30869, made protected for easy customization
+      * in case my implementation is insufficient, which I think is
+      * very likely.
+      *
+      * @param src The name to validate
+      * @return A string that's a valid JAAS realm name
+      */
+     protected String makeLegalForJAAS(final String src) {
+         String result = src;
+         
+         // Default name is "other" per JAAS spec
+         if(result == null) {
+             result = "other";
+         }
+
+         // Strip leading slash if present, as Sun JAAS impl
+         // barfs on it (see Bugzilla 30869 bug report).
+         if(result.startsWith("/")) {
+             result = result.substring(1);
+         }
+
+         return result;
+     }
+
+
+    // ------------------------------------------------------ Lifecycle Methods
+
+
+    /**
+     *
+     * Prepare for active use of the public methods of this <code>Component</code>.
+     *
+     * @exception LifecycleException if this component detects a fatal error
+     *  that prevents it from being started
+     */
+    public void start() throws LifecycleException {
+
+        // Perform normal superclass initialization
+        super.start();
+
+    }
+
+
+    /**
+     * Gracefully shut down active use of the public methods of this <code>Component</code>.
+     *
+     * @exception LifecycleException if this component detects a fatal error
+     *  that needs to be reported
+     */
+    public void stop() throws LifecycleException {
+
+        // Perform normal superclass finalization
+        super.stop();
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/realm/JDBCRealm.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/realm/JDBCRealm.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/realm/JDBCRealm.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,791 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.realm;
+
+
+import java.security.Principal;
+import java.sql.Connection;
+import java.sql.Driver;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.Properties;
+
+import org.apache.catalina.LifecycleException;
+import org.apache.catalina.util.StringManager;
+
+
+/**
+*
+* Implmentation of <b>Realm</b> that works with any JDBC supported database.
+* See the JDBCRealm.howto for more details on how to set up the database and
+* for configuration options.
+*
+* <p><strong>TODO</strong> - Support connection pooling (including message
+* format objects) so that <code>authenticate()</code> does not have to be
+* synchronized and would fix the ugly connection logic. </p>
+*
+* @author Craig R. McClanahan
+* @author Carson McDonald
+* @author Ignacio Ortega
+* @version $Revision: 373023 $ $Date: 2006-01-27 17:17:43 -0600 (Fri, 27 Jan 2006) $
+*/
+
+public class JDBCRealm
+    extends RealmBase {
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The connection username to use when trying to connect to the database.
+     */
+    protected String connectionName = null;
+
+
+    /**
+     * The connection URL to use when trying to connect to the database.
+     */
+    protected String connectionPassword = null;
+
+
+    /**
+     * The connection URL to use when trying to connect to the database.
+     */
+    protected String connectionURL = null;
+
+
+    /**
+     * The connection to the database.
+     */
+    protected Connection dbConnection = null;
+
+
+    /**
+     * Instance of the JDBC Driver class we use as a connection factory.
+     */
+    protected Driver driver = null;
+
+
+    /**
+     * The JDBC driver to use.
+     */
+    protected String driverName = null;
+
+
+    /**
+     * Descriptive information about this Realm implementation.
+     */
+    protected static final String info =
+        "org.apache.catalina.realm.JDBCRealm/1.0";
+
+
+    /**
+     * Descriptive information about this Realm implementation.
+     */
+    protected static final String name = "JDBCRealm";
+
+
+    /**
+     * The PreparedStatement to use for authenticating users.
+     */
+    protected PreparedStatement preparedCredentials = null;
+
+
+    /**
+     * The PreparedStatement to use for identifying the roles for
+     * a specified user.
+     */
+    protected PreparedStatement preparedRoles = null;
+
+
+    /**
+     * The column in the user role table that names a role
+     */
+    protected String roleNameCol = null;
+
+
+    /**
+     * The string manager for this package.
+     */
+    protected static final StringManager sm =
+        StringManager.getManager(Constants.Package);
+
+
+    /**
+     * The column in the user table that holds the user's credintials
+     */
+    protected String userCredCol = null;
+
+
+    /**
+     * The column in the user table that holds the user's name
+     */
+    protected String userNameCol = null;
+
+
+    /**
+     * The table that holds the relation between user's and roles
+     */
+    protected String userRoleTable = null;
+
+
+    /**
+     * The table that holds user data.
+     */
+    protected String userTable = null;
+
+
+    // ------------------------------------------------------------- Properties
+
+    /**
+     * Return the username to use to connect to the database.
+     *
+     */
+    public String getConnectionName() {
+        return connectionName;
+    }
+
+    /**
+     * Set the username to use to connect to the database.
+     *
+     * @param connectionName Username
+     */
+    public void setConnectionName(String connectionName) {
+        this.connectionName = connectionName;
+    }
+
+    /**
+     * Return the password to use to connect to the database.
+     *
+     */
+    public String getConnectionPassword() {
+        return connectionPassword;
+    }
+
+    /**
+     * Set the password to use to connect to the database.
+     *
+     * @param connectionPassword User password
+     */
+    public void setConnectionPassword(String connectionPassword) {
+        this.connectionPassword = connectionPassword;
+    }
+
+    /**
+     * Return the URL to use to connect to the database.
+     *
+     */
+    public String getConnectionURL() {
+        return connectionURL;
+    }
+
+    /**
+     * Set the URL to use to connect to the database.
+     *
+     * @param connectionURL The new connection URL
+     */
+    public void setConnectionURL( String connectionURL ) {
+      this.connectionURL = connectionURL;
+    }
+
+    /**
+     * Return the JDBC driver that will be used.
+     *
+     */
+    public String getDriverName() {
+        return driverName;
+    }
+
+    /**
+     * Set the JDBC driver that will be used.
+     *
+     * @param driverName The driver name
+     */
+    public void setDriverName( String driverName ) {
+      this.driverName = driverName;
+    }
+
+    /**
+     * Return the column in the user role table that names a role.
+     *
+     */
+    public String getRoleNameCol() {
+        return roleNameCol;
+    }
+
+    /**
+     * Set the column in the user role table that names a role.
+     *
+     * @param roleNameCol The column name
+     */
+    public void setRoleNameCol( String roleNameCol ) {
+        this.roleNameCol = roleNameCol;
+    }
+
+    /**
+     * Return the column in the user table that holds the user's credentials.
+     *
+     */
+    public String getUserCredCol() {
+        return userCredCol;
+    }
+
+    /**
+     * Set the column in the user table that holds the user's credentials.
+     *
+     * @param userCredCol The column name
+     */
+    public void setUserCredCol( String userCredCol ) {
+       this.userCredCol = userCredCol;
+    }
+
+    /**
+     * Return the column in the user table that holds the user's name.
+     *
+     */
+    public String getUserNameCol() {
+        return userNameCol;
+    }
+
+    /**
+     * Set the column in the user table that holds the user's name.
+     *
+     * @param userNameCol The column name
+     */
+    public void setUserNameCol( String userNameCol ) {
+       this.userNameCol = userNameCol;
+    }
+
+    /**
+     * Return the table that holds the relation between user's and roles.
+     *
+     */
+    public String getUserRoleTable() {
+        return userRoleTable;
+    }
+
+    /**
+     * Set the table that holds the relation between user's and roles.
+     *
+     * @param userRoleTable The table name
+     */
+    public void setUserRoleTable( String userRoleTable ) {
+        this.userRoleTable = userRoleTable;
+    }
+
+    /**
+     * Return the table that holds user data..
+     *
+     */
+    public String getUserTable() {
+        return userTable;
+    }
+
+    /**
+     * Set the table that holds user data.
+     *
+     * @param userTable The table name
+     */
+    public void setUserTable( String userTable ) {
+      this.userTable = userTable;
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Return the Principal associated with the specified username and
+     * credentials, if there is one; otherwise return <code>null</code>.
+     *
+     * If there are any errors with the JDBC connection, executing
+     * the query or anything we return null (don't authenticate). This
+     * event is also logged, and the connection will be closed so that
+     * a subsequent request will automatically re-open it.
+     *
+     *
+     * @param username Username of the Principal to look up
+     * @param credentials Password or other credentials to use in
+     *  authenticating this username
+     */
+    public synchronized Principal authenticate(String username, String credentials) {
+
+        // Number of tries is the numebr of attempts to connect to the database
+        // during this login attempt (if we need to open the database)
+        // This needs rewritten wuth better pooling support, the existing code
+        // needs signature changes since the Prepared statements needs cached
+        // with the connections.
+        // The code below will try twice if there is a SQLException so the
+        // connection may try to be opened again. On normal conditions (including
+        // invalid login - the above is only used once.
+        int numberOfTries = 2;
+        while (numberOfTries>0) {
+            try {
+
+                // Ensure that we have an open database connection
+                open();
+
+                // Acquire a Principal object for this user
+                Principal principal = authenticate(dbConnection,
+                                                   username, credentials);
+
+
+                // Return the Principal (if any)
+                return (principal);
+
+            } catch (SQLException e) {
+
+                // Log the problem for posterity
+                containerLog.error(sm.getString("jdbcRealm.exception"), e);
+
+                // Close the connection so that it gets reopened next time
+                if (dbConnection != null)
+                    close(dbConnection);
+
+            }
+
+            numberOfTries--;
+        }
+
+        // Worst case scenario
+        return null;
+
+    }
+
+
+    // -------------------------------------------------------- Package Methods
+
+
+    // ------------------------------------------------------ Protected Methods
+
+
+    /**
+     * Return the Principal associated with the specified username and
+     * credentials, if there is one; otherwise return <code>null</code>.
+     *
+     * @param dbConnection The database connection to be used
+     * @param username Username of the Principal to look up
+     * @param credentials Password or other credentials to use in
+     *  authenticating this username
+     */
+    public synchronized Principal authenticate(Connection dbConnection,
+                                               String username,
+                                               String credentials) {
+
+        // No user - can't possibly authenticate
+        if (username == null) {
+            return (null);
+        }
+
+        // Look up the user's credentials
+        String dbCredentials = getPassword(username);
+
+        // Validate the user's credentials
+        boolean validated = false;
+        if (hasMessageDigest()) {
+            // Hex hashes should be compared case-insensitive
+            validated = (digest(credentials).equalsIgnoreCase(dbCredentials));
+        } else {
+            validated = (digest(credentials).equals(dbCredentials));
+        }
+
+        if (validated) {
+            if (containerLog.isTraceEnabled())
+                containerLog.trace(sm.getString("jdbcRealm.authenticateSuccess",
+                                                username));
+        } else {
+            if (containerLog.isTraceEnabled())
+                containerLog.trace(sm.getString("jdbcRealm.authenticateFailure",
+                                                username));
+            return (null);
+        }
+
+        ArrayList roles = getRoles(username);
+        
+        // Create and return a suitable Principal for this user
+        return (new GenericPrincipal(this, username, credentials, roles));
+
+    }
+
+
+    /**
+     * Close the specified database connection.
+     *
+     * @param dbConnection The connection to be closed
+     */
+    protected void close(Connection dbConnection) {
+
+        // Do nothing if the database connection is already closed
+        if (dbConnection == null)
+            return;
+
+        // Close our prepared statements (if any)
+        try {
+            preparedCredentials.close();
+        } catch (Throwable f) {
+            ;
+        }
+        this.preparedCredentials = null;
+
+
+        try {
+            preparedRoles.close();
+        } catch (Throwable f) {
+            ;
+        }
+        this.preparedRoles = null;
+
+
+        // Close this database connection, and log any errors
+        try {
+            dbConnection.close();
+        } catch (SQLException e) {
+            containerLog.warn(sm.getString("jdbcRealm.close"), e); // Just log it here
+        } finally {
+           this.dbConnection = null;
+        }
+
+    }
+
+
+    /**
+     * Return a PreparedStatement configured to perform the SELECT required
+     * to retrieve user credentials for the specified username.
+     *
+     * @param dbConnection The database connection to be used
+     * @param username Username for which credentials should be retrieved
+     *
+     * @exception SQLException if a database error occurs
+     */
+    protected PreparedStatement credentials(Connection dbConnection,
+                                            String username)
+        throws SQLException {
+
+        if (preparedCredentials == null) {
+            StringBuffer sb = new StringBuffer("SELECT ");
+            sb.append(userCredCol);
+            sb.append(" FROM ");
+            sb.append(userTable);
+            sb.append(" WHERE ");
+            sb.append(userNameCol);
+            sb.append(" = ?");
+
+            if(containerLog.isDebugEnabled()) {
+                containerLog.debug("credentials query: " + sb.toString());
+            }
+
+            preparedCredentials =
+                dbConnection.prepareStatement(sb.toString());
+        }
+
+        if (username == null) {
+            preparedCredentials.setNull(1,java.sql.Types.VARCHAR);
+        } else {
+            preparedCredentials.setString(1, username);
+        }
+
+        return (preparedCredentials);
+    }
+
+
+    /**
+     * Return a short name for this Realm implementation.
+     */
+    protected String getName() {
+
+        return (name);
+
+    }
+
+
+    /**
+     * Return the password associated with the given principal's user name.
+     */
+    protected String getPassword(String username) {
+
+        // Look up the user's credentials
+        String dbCredentials = null;
+        PreparedStatement stmt = null;
+        ResultSet rs = null;
+
+        // Number of tries is the numebr of attempts to connect to the database
+        // during this login attempt (if we need to open the database)
+        // This needs rewritten wuth better pooling support, the existing code
+        // needs signature changes since the Prepared statements needs cached
+        // with the connections.
+        // The code below will try twice if there is a SQLException so the
+        // connection may try to be opened again. On normal conditions (including
+        // invalid login - the above is only used once.
+        int numberOfTries = 2;
+        while (numberOfTries>0) {
+            try {
+                
+                // Ensure that we have an open database connection
+                open();
+                
+                try {
+                    stmt = credentials(dbConnection, username);
+                    rs = stmt.executeQuery();
+                    
+                    if (rs.next()) {
+                        dbCredentials = rs.getString(1);
+                    }
+                    rs.close();
+                    rs = null;
+                    if (dbCredentials == null) {
+                        return (null);
+                    }
+                    
+                    dbCredentials = dbCredentials.trim();
+                    return dbCredentials;
+                    
+                } finally {
+                    if (rs!=null) {
+                        try {
+                            rs.close();
+                        } catch(SQLException e) {
+                            containerLog.warn(sm.getString("jdbcRealm.abnormalCloseResultSet"));
+                        }
+                    }
+                    dbConnection.commit();
+                }
+                
+            } catch (SQLException e) {
+                
+                // Log the problem for posterity
+                containerLog.error(sm.getString("jdbcRealm.exception"), e);
+                
+                // Close the connection so that it gets reopened next time
+                if (dbConnection != null)
+                    close(dbConnection);
+                
+            }
+            
+            numberOfTries--;
+        }
+        
+        return (null);
+    }
+
+
+    /**
+     * Return the Principal associated with the given user name.
+     */
+    protected Principal getPrincipal(String username) {
+
+        return (new GenericPrincipal(this,
+                                     username,
+                                     getPassword(username),
+                                     getRoles(username)));
+
+    }
+
+
+    /**
+     * Return the roles associated with the gven user name.
+     */
+    protected ArrayList getRoles(String username) {
+        
+        PreparedStatement stmt = null;
+        ResultSet rs = null;
+
+        // Number of tries is the numebr of attempts to connect to the database
+        // during this login attempt (if we need to open the database)
+        // This needs rewritten wuth better pooling support, the existing code
+        // needs signature changes since the Prepared statements needs cached
+        // with the connections.
+        // The code below will try twice if there is a SQLException so the
+        // connection may try to be opened again. On normal conditions (including
+        // invalid login - the above is only used once.
+        int numberOfTries = 2;
+        while (numberOfTries>0) {
+            try {
+                
+                // Ensure that we have an open database connection
+                open();
+                
+                try {
+                    // Accumulate the user's roles
+                    ArrayList roleList = new ArrayList();
+                    stmt = roles(dbConnection, username);
+                    rs = stmt.executeQuery();
+                    while (rs.next()) {
+                        String role = rs.getString(1);
+                        if (null!=role) {
+                            roleList.add(role.trim());
+                        }
+                    }
+                    rs.close();
+                    rs = null;
+                    
+                    return (roleList);
+                    
+                } finally {
+                    if (rs!=null) {
+                        try {
+                            rs.close();
+                        } catch(SQLException e) {
+                            containerLog.warn(sm.getString("jdbcRealm.abnormalCloseResultSet"));
+                        }
+                    }
+                    dbConnection.commit();
+                }
+                
+            } catch (SQLException e) {
+                
+                // Log the problem for posterity
+                containerLog.error(sm.getString("jdbcRealm.exception"), e);
+                
+                // Close the connection so that it gets reopened next time
+                if (dbConnection != null)
+                    close(dbConnection);
+                
+            }
+            
+            numberOfTries--;
+        }
+        
+        return (null);
+        
+    }
+    
+    
+    /**
+     * Open (if necessary) and return a database connection for use by
+     * this Realm.
+     *
+     * @exception SQLException if a database error occurs
+     */
+    protected Connection open() throws SQLException {
+
+        // Do nothing if there is a database connection already open
+        if (dbConnection != null)
+            return (dbConnection);
+
+        // Instantiate our database driver if necessary
+        if (driver == null) {
+            try {
+                Class clazz = Class.forName(driverName);
+                driver = (Driver) clazz.newInstance();
+            } catch (Throwable e) {
+                throw new SQLException(e.getMessage());
+            }
+        }
+
+        // Open a new connection
+        Properties props = new Properties();
+        if (connectionName != null)
+            props.put("user", connectionName);
+        if (connectionPassword != null)
+            props.put("password", connectionPassword);
+        dbConnection = driver.connect(connectionURL, props);
+        dbConnection.setAutoCommit(false);
+        return (dbConnection);
+
+    }
+
+
+    /**
+     * Release our use of this connection so that it can be recycled.
+     *
+     * @param dbConnection The connection to be released
+     */
+    protected void release(Connection dbConnection) {
+
+        ; // NO-OP since we are not pooling anything
+
+    }
+
+
+    /**
+     * Return a PreparedStatement configured to perform the SELECT required
+     * to retrieve user roles for the specified username.
+     *
+     * @param dbConnection The database connection to be used
+     * @param username Username for which roles should be retrieved
+     *
+     * @exception SQLException if a database error occurs
+     */
+    protected PreparedStatement roles(Connection dbConnection, String username)
+        throws SQLException {
+
+        if (preparedRoles == null) {
+            StringBuffer sb = new StringBuffer("SELECT ");
+            sb.append(roleNameCol);
+            sb.append(" FROM ");
+            sb.append(userRoleTable);
+            sb.append(" WHERE ");
+            sb.append(userNameCol);
+            sb.append(" = ?");
+            preparedRoles =
+                dbConnection.prepareStatement(sb.toString());
+        }
+
+        preparedRoles.setString(1, username);
+        return (preparedRoles);
+
+    }
+
+
+    // ------------------------------------------------------ Lifecycle Methods
+
+
+    /**
+     *
+     * Prepare for active use of the public methods of this Component.
+     *
+     * @exception LifecycleException if this component detects a fatal error
+     *  that prevents it from being started
+     */
+    public void start() throws LifecycleException {
+
+        // Perform normal superclass initialization
+        super.start();
+
+        // Validate that we can open our connection - but let tomcat
+        // startup in case the database is temporarily unavailable
+        try {
+            open();
+        } catch (SQLException e) {
+            containerLog.error(sm.getString("jdbcRealm.open"), e);
+        }
+
+    }
+
+
+    /**
+     * Gracefully shut down active use of the public methods of this Component.
+     *
+     * @exception LifecycleException if this component detects a fatal error
+     *  that needs to be reported
+     */
+    public void stop() throws LifecycleException {
+
+        // Perform normal superclass finalization
+        super.stop();
+
+        // Close any open DB connection
+        close(this.dbConnection);
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/realm/JNDIRealm.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/realm/JNDIRealm.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/realm/JNDIRealm.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,1797 @@
+/*
+ * Copyright 1999-2002,2004-2005 The Apache Software Foundation.
+ * 
+ * Licensed 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.realm;
+
+import java.io.IOException;
+import java.security.Principal;
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Hashtable;
+import java.util.List;
+
+import javax.naming.Context;
+import javax.naming.CommunicationException;
+import javax.naming.CompositeName;
+import javax.naming.InvalidNameException;
+import javax.naming.NameNotFoundException;
+import javax.naming.NamingEnumeration;
+import javax.naming.NamingException;
+import javax.naming.NameParser;
+import javax.naming.Name;
+import javax.naming.AuthenticationException;
+import javax.naming.directory.Attribute;
+import javax.naming.directory.Attributes;
+import javax.naming.directory.DirContext;
+import javax.naming.directory.InitialDirContext;
+import javax.naming.directory.SearchControls;
+import javax.naming.directory.SearchResult;
+import org.apache.catalina.LifecycleException;
+import org.apache.catalina.util.Base64;
+import org.apache.tomcat.util.buf.ByteChunk;
+import org.apache.tomcat.util.buf.CharChunk;
+
+/**
+ * <p>Implementation of <strong>Realm</strong> that works with a directory
+ * server accessed via the Java Naming and Directory Interface (JNDI) APIs.
+ * The following constraints are imposed on the data structure in the
+ * underlying directory server:</p>
+ * <ul>
+ *
+ * <li>Each user that can be authenticated is represented by an individual
+ *     element in the top level <code>DirContext</code> that is accessed
+ *     via the <code>connectionURL</code> property.</li>
+ *
+ * <li>If a socket connection can not be made to the <code>connectURL</code>
+ *     an attempt will be made to use the <code>alternateURL</code> if it
+ *     exists.</li>
+ *
+ * <li>Each user element has a distinguished name that can be formed by
+ *     substituting the presented username into a pattern configured by the
+ *     <code>userPattern</code> property.</li>
+ *
+ * <li>Alternatively, if the <code>userPattern</code> property is not
+ *     specified, a unique element can be located by searching the directory
+ *     context. In this case:
+ *     <ul>
+ *     <li>The <code>userSearch</code> pattern specifies the search filter
+ *         after substitution of the username.</li>
+ *     <li>The <code>userBase</code> property can be set to the element that
+ *         is the base of the subtree containing users.  If not specified,
+ *         the search base is the top-level context.</li>
+ *     <li>The <code>userSubtree</code> property can be set to
+ *         <code>true</code> if you wish to search the entire subtree of the
+ *         directory context.  The default value of <code>false</code>
+ *         requests a search of only the current level.</li>
+ *    </ul>
+ * </li>
+ *
+ * <li>The user may be authenticated by binding to the directory with the
+ *      username and password presented. This method is used when the
+ *      <code>userPassword</code> property is not specified.</li>
+ *
+ * <li>The user may be authenticated by retrieving the value of an attribute
+ *     from the directory and comparing it explicitly with the value presented
+ *     by the user. This method is used when the <code>userPassword</code>
+ *     property is specified, in which case:
+ *     <ul>
+ *     <li>The element for this user must contain an attribute named by the
+ *         <code>userPassword</code> property.
+ *     <li>The value of the user password attribute is either a cleartext
+ *         String, or the result of passing a cleartext String through the
+ *         <code>RealmBase.digest()</code> method (using the standard digest
+ *         support included in <code>RealmBase</code>).
+ *     <li>The user is considered to be authenticated if the presented
+ *         credentials (after being passed through
+ *         <code>RealmBase.digest()</code>) are equal to the retrieved value
+ *         for the user password attribute.</li>
+ *     </ul></li>
+ *
+ * <li>Each group of users that has been assigned a particular role may be
+ *     represented by an individual element in the top level
+ *     <code>DirContext</code> that is accessed via the
+ *     <code>connectionURL</code> property.  This element has the following
+ *     characteristics:
+ *     <ul>
+ *     <li>The set of all possible groups of interest can be selected by a
+ *         search pattern configured by the <code>roleSearch</code>
+ *         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>
+ *     <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>
+ *     <li>The <code>roleSubtree</code> property can be set to
+ *         <code>true</code> if you wish to search the entire subtree of the
+ *         directory context.  The default value of <code>false</code>
+ *         requests a search of only the current level.</li>
+ *     <li>The element includes an attribute (whose name is configured by
+ *         the <code>roleName</code> property) containing the name of the
+ *         role represented by this element.</li>
+ *     </ul></li>
+ *
+ * <li>In addition, roles may be represented by the values of an attribute
+ * in the user's element whose name is configured by the
+ * <code>userRoleName</code> property.</li>
+ *
+ * <li>Note that the standard <code>&lt;security-role-ref&gt;</code> element in
+ *     the web application deployment descriptor allows applications to refer
+ *     to roles programmatically by names other than those used in the
+ *     directory server itself.</li>
+ * </ul>
+ *
+ * <p><strong>TODO</strong> - Support connection pooling (including message
+ * format objects) so that <code>authenticate()</code> does not have to be
+ * synchronized.</p>
+ *
+ * <p><strong>WARNING</strong> - There is a reported bug against the Netscape
+ * provider code (com.netscape.jndi.ldap.LdapContextFactory) with respect to
+ * successfully authenticated a non-existing user. The
+ * report is here: http://issues.apache.org/bugzilla/show_bug.cgi?id=11210 .
+ * With luck, Netscape has updated their provider code and this is not an
+ * issue. </p>
+ *
+ * @author John Holman
+ * @author Craig R. McClanahan
+ * @version $Revision: 373029 $ $Date: 2006-01-27 17:27:16 -0600 (Fri, 27 Jan 2006) $
+ */
+
+public class JNDIRealm extends RealmBase {
+
+
+    // ----------------------------------------------------- Instance Variables
+
+    /**
+     *  The type of authentication to use
+     */
+    protected String authentication = null;
+
+    /**
+     * The connection username for the server we will contact.
+     */
+    protected String connectionName = null;
+
+
+    /**
+     * The connection password for the server we will contact.
+     */
+    protected String connectionPassword = null;
+
+
+    /**
+     * The connection URL for the server we will contact.
+     */
+    protected String connectionURL = null;
+
+
+    /**
+     * The directory context linking us to our directory server.
+     */
+    protected DirContext context = null;
+
+
+    /**
+     * The JNDI context factory used to acquire our InitialContext.  By
+     * default, assumes use of an LDAP server using the standard JNDI LDAP
+     * provider.
+     */
+    protected String contextFactory = "com.sun.jndi.ldap.LdapCtxFactory";
+
+    
+    /**
+     * How aliases should be dereferenced during search operations.
+     */
+    protected String derefAliases = null;
+
+    /**
+     * Constant that holds the name of the environment property for specifying 
+     * the manner in which aliases should be dereferenced.
+     */
+    public final static String DEREF_ALIASES = "java.naming.ldap.derefAliases";
+
+    /**
+     * Descriptive information about this Realm implementation.
+     */
+    protected static final String info =
+        "org.apache.catalina.realm.JNDIRealm/1.0";
+
+
+    /**
+     * Descriptive information about this Realm implementation.
+     */
+    protected static final String name = "JNDIRealm";
+
+
+    /**
+     * The protocol that will be used in the communication with the
+     * directory server.
+     */
+    protected String protocol = null;
+
+
+    /**
+     * How should we handle referrals?  Microsoft Active Directory can't handle
+     * the default case, so an application authenticating against AD must
+     * set referrals to "follow".
+     */
+    protected String referrals = null;
+
+
+    /**
+     * The base element for user searches.
+     */
+    protected String userBase = "";
+
+
+    /**
+     * The message format used to search for a user, with "{0}" marking
+     * the spot where the username goes.
+     */
+    protected String userSearch = null;
+
+
+    /**
+     * The MessageFormat object associated with the current
+     * <code>userSearch</code>.
+     */
+    protected MessageFormat userSearchFormat = null;
+
+
+    /**
+     * Should we search the entire subtree for matching users?
+     */
+    protected boolean userSubtree = false;
+
+
+    /**
+     * The attribute name used to retrieve the user password.
+     */
+    protected String userPassword = null;
+
+
+    /**
+     * A string of LDAP user patterns or paths, ":"-separated
+     * These will be used to form the distinguished name of a
+     * user, with "{0}" marking the spot where the specified username
+     * goes.
+     * This is similar to userPattern, but allows for multiple searches
+     * for a user.
+     */
+    protected String[] userPatternArray = null;
+
+
+    /**
+     * The message format used to form the distinguished name of a
+     * user, with "{0}" marking the spot where the specified username
+     * goes.
+     */
+    protected String userPattern = null;
+
+
+    /**
+     * An array of MessageFormat objects associated with the current
+     * <code>userPatternArray</code>.
+     */
+    protected MessageFormat[] userPatternFormatArray = null;
+
+
+    /**
+     * The base element for role searches.
+     */
+    protected String roleBase = "";
+
+
+    /**
+     * The MessageFormat object associated with the current
+     * <code>roleSearch</code>.
+     */
+    protected MessageFormat roleFormat = null;
+
+
+    /**
+     * The name of an attribute in the user's entry containing
+     * roles for that user
+     */
+    protected String userRoleName = null;
+
+
+    /**
+     * The name of the attribute containing roles held elsewhere
+     */
+    protected String roleName = null;
+
+
+    /**
+     * The message format used to select roles for a user, with "{0}" marking
+     * the spot where the distinguished name of the user goes.
+     */
+    protected String roleSearch = null;
+
+
+    /**
+     * Should we search the entire subtree for matching memberships?
+     */
+    protected boolean roleSubtree = false;
+
+    /**
+     * An alternate URL, to which, we should connect if connectionURL fails.
+     */
+    protected String alternateURL;
+
+    /**
+     * The number of connection attempts.  If greater than zero we use the
+     * alternate url.
+     */
+    protected int connectionAttempt = 0;
+
+    /**
+     * The current user pattern to be used for lookup and binding of a user.
+     */
+    protected int curUserPattern = 0;
+
+    // ------------------------------------------------------------- Properties
+
+    /**
+     * Return the type of authentication to use.
+     */
+    public String getAuthentication() {
+
+        return authentication;
+
+    }
+
+    /**
+     * Set the type of authentication to use.
+     *
+     * @param authentication The authentication
+     */
+    public void setAuthentication(String authentication) {
+
+        this.authentication = authentication;
+
+    }
+
+    /**
+     * Return the connection username for this Realm.
+     */
+    public String getConnectionName() {
+
+        return (this.connectionName);
+
+    }
+
+
+    /**
+     * Set the connection username for this Realm.
+     *
+     * @param connectionName The new connection username
+     */
+    public void setConnectionName(String connectionName) {
+
+        this.connectionName = connectionName;
+
+    }
+
+
+    /**
+     * Return the connection password for this Realm.
+     */
+    public String getConnectionPassword() {
+
+        return (this.connectionPassword);
+
+    }
+
+
+    /**
+     * Set the connection password for this Realm.
+     *
+     * @param connectionPassword The new connection password
+     */
+    public void setConnectionPassword(String connectionPassword) {
+
+        this.connectionPassword = connectionPassword;
+
+    }
+
+
+    /**
+     * Return the connection URL for this Realm.
+     */
+    public String getConnectionURL() {
+
+        return (this.connectionURL);
+
+    }
+
+
+    /**
+     * Set the connection URL for this Realm.
+     *
+     * @param connectionURL The new connection URL
+     */
+    public void setConnectionURL(String connectionURL) {
+
+        this.connectionURL = connectionURL;
+
+    }
+
+
+    /**
+     * Return the JNDI context factory for this Realm.
+     */
+    public String getContextFactory() {
+
+        return (this.contextFactory);
+
+    }
+
+
+    /**
+     * Set the JNDI context factory for this Realm.
+     *
+     * @param contextFactory The new context factory
+     */
+    public void setContextFactory(String contextFactory) {
+
+        this.contextFactory = contextFactory;
+
+    }
+
+    /**
+     * Return the derefAliases setting to be used.
+     */
+    public java.lang.String getDerefAliases() {
+        return derefAliases;
+    }  
+    
+    /**
+     * Set the value for derefAliases to be used when searching the directory.
+     * 
+     * @param derefAliases New value of property derefAliases.
+     */
+    public void setDerefAliases(java.lang.String derefAliases) {
+      this.derefAliases = derefAliases;
+    }
+
+    /**
+     * Return the protocol to be used.
+     */
+    public String getProtocol() {
+
+        return protocol;
+
+    }
+
+    /**
+     * Set the protocol for this Realm.
+     *
+     * @param protocol The new protocol.
+     */
+    public void setProtocol(String protocol) {
+
+        this.protocol = protocol;
+
+    }
+
+
+    /**
+     * Returns the current settings for handling JNDI referrals.
+     */
+    public String getReferrals () {
+        return referrals;
+    }
+
+
+    /**
+     * How do we handle JNDI referrals? ignore, follow, or throw
+     * (see javax.naming.Context.REFERRAL for more information).
+     */
+    public void setReferrals (String referrals) {
+        this.referrals = referrals;
+    }
+
+
+    /**
+     * Return the base element for user searches.
+     */
+    public String getUserBase() {
+
+        return (this.userBase);
+
+    }
+
+
+    /**
+     * Set the base element for user searches.
+     *
+     * @param userBase The new base element
+     */
+    public void setUserBase(String userBase) {
+
+        this.userBase = userBase;
+
+    }
+
+
+    /**
+     * Return the message format pattern for selecting users in this Realm.
+     */
+    public String getUserSearch() {
+
+        return (this.userSearch);
+
+    }
+
+
+    /**
+     * Set the message format pattern for selecting users in this Realm.
+     *
+     * @param userSearch The new user search pattern
+     */
+    public void setUserSearch(String userSearch) {
+
+        this.userSearch = userSearch;
+        if (userSearch == null)
+            userSearchFormat = null;
+        else
+            userSearchFormat = new MessageFormat(userSearch);
+
+    }
+
+
+    /**
+     * Return the "search subtree for users" flag.
+     */
+    public boolean getUserSubtree() {
+
+        return (this.userSubtree);
+
+    }
+
+
+    /**
+     * Set the "search subtree for users" flag.
+     *
+     * @param userSubtree The new search flag
+     */
+    public void setUserSubtree(boolean userSubtree) {
+
+        this.userSubtree = userSubtree;
+
+    }
+
+
+    /**
+     * Return the user role name attribute name for this Realm.
+     */
+    public String getUserRoleName() {
+
+        return userRoleName;
+    }
+
+
+    /**
+     * Set the user role name attribute name for this Realm.
+     *
+     * @param userRoleName The new userRole name attribute name
+     */
+    public void setUserRoleName(String userRoleName) {
+
+        this.userRoleName = userRoleName;
+
+    }
+
+
+    /**
+     * Return the base element for role searches.
+     */
+    public String getRoleBase() {
+
+        return (this.roleBase);
+
+    }
+
+
+    /**
+     * Set the base element for role searches.
+     *
+     * @param roleBase The new base element
+     */
+    public void setRoleBase(String roleBase) {
+
+        this.roleBase = roleBase;
+
+    }
+
+
+    /**
+     * Return the role name attribute name for this Realm.
+     */
+    public String getRoleName() {
+
+        return (this.roleName);
+
+    }
+
+
+    /**
+     * Set the role name attribute name for this Realm.
+     *
+     * @param roleName The new role name attribute name
+     */
+    public void setRoleName(String roleName) {
+
+        this.roleName = roleName;
+
+    }
+
+
+    /**
+     * Return the message format pattern for selecting roles in this Realm.
+     */
+    public String getRoleSearch() {
+
+        return (this.roleSearch);
+
+    }
+
+
+    /**
+     * Set the message format pattern for selecting roles in this Realm.
+     *
+     * @param roleSearch The new role search pattern
+     */
+    public void setRoleSearch(String roleSearch) {
+
+        this.roleSearch = roleSearch;
+        if (roleSearch == null)
+            roleFormat = null;
+        else
+            roleFormat = new MessageFormat(roleSearch);
+
+    }
+
+
+    /**
+     * Return the "search subtree for roles" flag.
+     */
+    public boolean getRoleSubtree() {
+
+        return (this.roleSubtree);
+
+    }
+
+
+    /**
+     * Set the "search subtree for roles" flag.
+     *
+     * @param roleSubtree The new search flag
+     */
+    public void setRoleSubtree(boolean roleSubtree) {
+
+        this.roleSubtree = roleSubtree;
+
+    }
+
+
+    /**
+     * Return the password attribute used to retrieve the user password.
+     */
+    public String getUserPassword() {
+
+        return (this.userPassword);
+
+    }
+
+
+    /**
+     * Set the password attribute used to retrieve the user password.
+     *
+     * @param userPassword The new password attribute
+     */
+    public void setUserPassword(String userPassword) {
+
+        this.userPassword = userPassword;
+
+    }
+
+
+    /**
+     * Return the message format pattern for selecting users in this Realm.
+     */
+    public String getUserPattern() {
+
+        return (this.userPattern);
+
+    }
+
+
+    /**
+     * Set the message format pattern for selecting users in this Realm.
+     * This may be one simple pattern, or multiple patterns to be tried,
+     * separated by parentheses. (for example, either "cn={0}", or
+     * "(cn={0})(cn={0},o=myorg)" Full LDAP search strings are also supported,
+     * but only the "OR", "|" syntax, so "(|(cn={0})(cn={0},o=myorg))" is
+     * also valid. Complex search strings with &, etc are NOT supported.
+     *
+     * @param userPattern The new user pattern
+     */
+    public void setUserPattern(String userPattern) {
+
+        this.userPattern = userPattern;
+        if (userPattern == null)
+            userPatternArray = null;
+        else {
+            userPatternArray = parseUserPatternString(userPattern);
+            int len = this.userPatternArray.length;
+            userPatternFormatArray = new MessageFormat[len];
+            for (int i=0; i < len; i++) {
+                userPatternFormatArray[i] =
+                    new MessageFormat(userPatternArray[i]);
+            }
+        }
+    }
+
+
+    /**
+     * Getter for property alternateURL.
+     *
+     * @return Value of property alternateURL.
+     */
+    public String getAlternateURL() {
+
+        return this.alternateURL;
+
+    }
+
+
+    /**
+     * Setter for property alternateURL.
+     *
+     * @param alternateURL New value of property alternateURL.
+     */
+    public void setAlternateURL(String alternateURL) {
+
+        this.alternateURL = alternateURL;
+
+    }
+
+
+    // ---------------------------------------------------------- Realm Methods
+
+
+    /**
+     * Return the Principal associated with the specified username and
+     * credentials, if there is one; otherwise return <code>null</code>.
+     *
+     * If there are any errors with the JDBC connection, executing
+     * the query or anything we return null (don't authenticate). This
+     * event is also logged, and the connection will be closed so that
+     * a subsequent request will automatically re-open it.
+     *
+     * @param username Username of the Principal to look up
+     * @param credentials Password or other credentials to use in
+     *  authenticating this username
+     */
+    public Principal authenticate(String username, String credentials) {
+
+        DirContext context = null;
+        Principal principal = null;
+
+        try {
+
+            // Ensure that we have a directory context available
+            context = open();
+
+            // Occassionally the directory context will timeout.  Try one more
+            // time before giving up.
+            try {
+
+                // Authenticate the specified username if possible
+                principal = authenticate(context, username, credentials);
+
+            } catch (CommunicationException e) {
+
+                // log the exception so we know it's there.
+                containerLog.warn(sm.getString("jndiRealm.exception"), e);
+
+                // close the connection so we know it will be reopened.
+                if (context != null)
+                    close(context);
+
+                // open a new directory context.
+                context = open();
+
+                // Try the authentication again.
+                principal = authenticate(context, username, credentials);
+
+            }
+
+
+            // Release this context
+            release(context);
+
+            // Return the authenticated Principal (if any)
+            return (principal);
+
+        } catch (NamingException e) {
+
+            // Log the problem for posterity
+            containerLog.error(sm.getString("jndiRealm.exception"), e);
+
+            // Close the connection so that it gets reopened next time
+            if (context != null)
+                close(context);
+
+            // Return "not authenticated" for this request
+            return (null);
+
+        }
+
+    }
+
+
+    // -------------------------------------------------------- Package Methods
+
+
+    // ------------------------------------------------------ Protected Methods
+
+
+    /**
+     * Return the Principal associated with the specified username and
+     * credentials, if there is one; otherwise return <code>null</code>.
+     *
+     * @param context The directory context
+     * @param username Username of the Principal to look up
+     * @param credentials Password or other credentials to use in
+     *  authenticating this username
+     *
+     * @exception NamingException if a directory server error occurs
+     */
+    public synchronized Principal authenticate(DirContext context,
+                                               String username,
+                                               String credentials)
+        throws NamingException {
+
+        if (username == null || username.equals("")
+            || credentials == null || credentials.equals(""))
+            return (null);
+
+        if (userPatternArray != null) {
+            for (curUserPattern = 0;
+                 curUserPattern < userPatternFormatArray.length;
+                 curUserPattern++) {
+                // Retrieve user information
+                User user = getUser(context, username);
+                if (user != null) {
+                    try {
+                        // Check the user's credentials
+                        if (checkCredentials(context, user, credentials)) {
+                            // Search for additional roles
+                            List roles = getRoles(context, user);
+                            return (new GenericPrincipal(this,
+                                                         username,
+                                                         credentials,
+                                                         roles));
+                        }
+                    } catch (InvalidNameException ine) {
+                        // Log the problem for posterity
+                        containerLog.warn(sm.getString("jndiRealm.exception"), ine);
+                        // ignore; this is probably due to a name not fitting
+                        // the search path format exactly, as in a fully-
+                        // qualified name being munged into a search path
+                        // that already contains cn= or vice-versa
+                    }
+                }
+            }
+            return null;
+        } else {
+            // Retrieve user information
+            User user = getUser(context, username);
+            if (user == null)
+                return (null);
+
+            // Check the user's credentials
+            if (!checkCredentials(context, user, credentials))
+                return (null);
+
+            // Search for additional roles
+            List roles = getRoles(context, user);
+
+            // Create and return a suitable Principal for this user
+            return (new GenericPrincipal(this, username, credentials, roles));
+        }
+    }
+
+
+    /**
+     * Return a User object containing information about the user
+     * with the specified username, if found in the directory;
+     * otherwise return <code>null</code>.
+     *
+     * If the <code>userPassword</code> configuration attribute is
+     * specified, the value of that attribute is retrieved from the
+     * user's directory entry. If the <code>userRoleName</code>
+     * configuration attribute is specified, all values of that
+     * attribute are retrieved from the directory entry.
+     *
+     * @param context The directory context
+     * @param username Username to be looked up
+     *
+     * @exception NamingException if a directory server error occurs
+     */
+    protected User getUser(DirContext context, String username)
+        throws NamingException {
+
+        User user = null;
+
+        // Get attributes to retrieve from user entry
+        ArrayList list = new ArrayList();
+        if (userPassword != null)
+            list.add(userPassword);
+        if (userRoleName != null)
+            list.add(userRoleName);
+        String[] attrIds = new String[list.size()];
+        list.toArray(attrIds);
+
+        // Use pattern or search for user entry
+        if (userPatternFormatArray != null) {
+            user = getUserByPattern(context, username, attrIds);
+        } else {
+            user = getUserBySearch(context, username, attrIds);
+        }
+
+        return user;
+    }
+
+
+    /**
+     * Use the <code>UserPattern</code> configuration attribute to
+     * locate the directory entry for the user with the specified
+     * username and return a User object; otherwise return
+     * <code>null</code>.
+     *
+     * @param context The directory context
+     * @param username The username
+     * @param attrIds String[]containing names of attributes to
+     * retrieve.
+     *
+     * @exception NamingException if a directory server error occurs
+     */
+    protected User getUserByPattern(DirContext context,
+                                              String username,
+                                              String[] attrIds)
+        throws NamingException {
+
+        if (username == null || userPatternFormatArray[curUserPattern] == null)
+            return (null);
+
+        // Form the dn from the user pattern
+        String dn = userPatternFormatArray[curUserPattern].format(new String[] { username });
+
+        // Get required attributes from user entry
+        Attributes attrs = null;
+        try {
+            attrs = context.getAttributes(dn, attrIds);
+        } catch (NameNotFoundException e) {
+            return (null);
+        }
+        if (attrs == null)
+            return (null);
+
+        // Retrieve value of userPassword
+        String password = null;
+        if (userPassword != null)
+            password = getAttributeValue(userPassword, attrs);
+
+        // Retrieve values of userRoleName attribute
+        ArrayList roles = null;
+        if (userRoleName != null)
+            roles = addAttributeValues(userRoleName, attrs, roles);
+
+        return new User(username, dn, password, roles);
+    }
+
+
+    /**
+     * Search the directory to return a User object containing
+     * information about the user with the specified username, if
+     * found in the directory; otherwise return <code>null</code>.
+     *
+     * @param context The directory context
+     * @param username The username
+     * @param attrIds String[]containing names of attributes to retrieve.
+     *
+     * @exception NamingException if a directory server error occurs
+     */
+    protected User getUserBySearch(DirContext context,
+                                           String username,
+                                           String[] attrIds)
+        throws NamingException {
+
+        if (username == null || userSearchFormat == null)
+            return (null);
+
+        // Form the search filter
+        String filter = userSearchFormat.format(new String[] { username });
+
+        // Set up the search controls
+        SearchControls constraints = new SearchControls();
+
+        if (userSubtree) {
+            constraints.setSearchScope(SearchControls.SUBTREE_SCOPE);
+        }
+        else {
+            constraints.setSearchScope(SearchControls.ONELEVEL_SCOPE);
+        }
+
+        // Specify the attributes to be retrieved
+        if (attrIds == null)
+            attrIds = new String[0];
+        constraints.setReturningAttributes(attrIds);
+
+        NamingEnumeration results =
+            context.search(userBase, filter, constraints);
+
+
+        // Fail if no entries found
+        if (results == null || !results.hasMore()) {
+            return (null);
+        }
+
+        // Get result for the first entry found
+        SearchResult result = (SearchResult)results.next();
+
+        // Check no further entries were found
+        if (results.hasMore()) {
+            if(containerLog.isInfoEnabled())
+                containerLog.info("username " + username + " has multiple entries");
+            return (null);
+        }
+
+        // Get the entry's distinguished name
+        NameParser parser = context.getNameParser("");
+        Name contextName = parser.parse(context.getNameInNamespace());
+        Name baseName = parser.parse(userBase);
+
+        // Bugzilla 32269
+        Name entryName = parser.parse(new CompositeName(result.getName()).get(0));
+
+        Name name = contextName.addAll(baseName);
+        name = name.addAll(entryName);
+        String dn = name.toString();
+
+        if (containerLog.isTraceEnabled())
+            containerLog.trace("  entry found for " + username + " with dn " + dn);
+
+        // Get the entry's attributes
+        Attributes attrs = result.getAttributes();
+        if (attrs == null)
+            return null;
+
+        // Retrieve value of userPassword
+        String password = null;
+        if (userPassword != null)
+            password = getAttributeValue(userPassword, attrs);
+
+        // Retrieve values of userRoleName attribute
+        ArrayList roles = null;
+        if (userRoleName != null)
+            roles = addAttributeValues(userRoleName, attrs, roles);
+
+        return new User(username, dn, password, roles);
+    }
+
+
+    /**
+     * Check whether the given User can be authenticated with the
+     * given credentials. If the <code>userPassword</code>
+     * configuration attribute is specified, the credentials
+     * previously retrieved from the directory are compared explicitly
+     * with those presented by the user. Otherwise the presented
+     * credentials are checked by binding to the directory as the
+     * user.
+     *
+     * @param context The directory context
+     * @param user The User to be authenticated
+     * @param credentials The credentials presented by the user
+     *
+     * @exception NamingException if a directory server error occurs
+     */
+    protected boolean checkCredentials(DirContext context,
+                                     User user,
+                                     String credentials)
+         throws NamingException {
+
+         boolean validated = false;
+
+         if (userPassword == null) {
+             validated = bindAsUser(context, user, credentials);
+         } else {
+             validated = compareCredentials(context, user, credentials);
+         }
+
+         if (containerLog.isTraceEnabled()) {
+             if (validated) {
+                 containerLog.trace(sm.getString("jndiRealm.authenticateSuccess",
+                                  user.username));
+             } else {
+                 containerLog.trace(sm.getString("jndiRealm.authenticateFailure",
+                                  user.username));
+             }
+         }
+         return (validated);
+     }
+
+
+
+    /**
+     * Check whether the credentials presented by the user match those
+     * retrieved from the directory.
+     *
+     * @param context The directory context
+     * @param info The User to be authenticated
+     * @param credentials Authentication credentials
+     *
+     * @exception NamingException if a directory server error occurs
+     */
+    protected boolean compareCredentials(DirContext context,
+                                         User info,
+                                         String credentials)
+        throws NamingException {
+
+        if (info == null || credentials == null)
+            return (false);
+
+        String password = info.password;
+        if (password == null)
+            return (false);
+
+        // Validate the credentials specified by the user
+        if (containerLog.isTraceEnabled())
+            containerLog.trace("  validating credentials");
+
+        boolean validated = false;
+        if (hasMessageDigest()) {
+            // iPlanet support if the values starts with {SHA1}
+            // The string is in a format compatible with Base64.encode not
+            // the Hex encoding of the parent class.
+            if (password.startsWith("{SHA}")) {
+                /* sync since super.digest() does this same thing */
+                synchronized (this) {
+                    password = password.substring(5);
+                    md.reset();
+                    md.update(credentials.getBytes());
+                    String digestedPassword =
+                        new String(Base64.encode(md.digest()));
+                    validated = password.equals(digestedPassword);
+                }
+            } else if (password.startsWith("{SSHA}")) {
+                // Bugzilla 32938
+                /* sync since super.digest() does this same thing */
+                synchronized (this) {
+                    password = password.substring(6);
+
+                    md.reset();
+                    md.update(credentials.getBytes());
+
+                    // Decode stored password.
+                    ByteChunk pwbc = new ByteChunk(password.length());
+                    try {
+                        pwbc.append(password.getBytes(), 0, password.length());
+                    } catch (IOException e) {
+                        // Should never happen
+                        containerLog.error("Could not append password bytes to chunk: ", e);
+                    }
+
+                    CharChunk decoded = new CharChunk();
+                    Base64.decode(pwbc, decoded);
+                    char[] pwarray = decoded.getBuffer();
+
+                    // Split decoded password into hash and salt.
+                    final int saltpos = 20;
+                    byte[] hash = new byte[saltpos];
+                    for (int i=0; i< hash.length; i++) {
+                        hash[i] = (byte) pwarray[i];
+                    }
+
+                    byte[] salt = new byte[pwarray.length - saltpos];
+                    for (int i=0; i< salt.length; i++)
+                        salt[i] = (byte)pwarray[i+saltpos];
+
+                    md.update(salt);
+                    byte[] dp = md.digest();
+
+                    validated = Arrays.equals(dp, hash);
+                } // End synchronized(this) block
+            } else {
+                // Hex hashes should be compared case-insensitive
+                validated = (digest(credentials).equalsIgnoreCase(password));
+            }
+        } else
+            validated = (digest(credentials).equals(password));
+        return (validated);
+
+    }
+
+
+
+    /**
+     * Check credentials by binding to the directory as the user
+     *
+     * @param context The directory context
+     * @param user The User to be authenticated
+     * @param credentials Authentication credentials
+     *
+     * @exception NamingException if a directory server error occurs
+     */
+     protected boolean bindAsUser(DirContext context,
+                                  User user,
+                                  String credentials)
+         throws NamingException {
+         Attributes attr;
+
+         if (credentials == null || user == null)
+             return (false);
+
+         String dn = user.dn;
+         if (dn == null)
+             return (false);
+
+         // Validate the credentials specified by the user
+         if (containerLog.isTraceEnabled()) {
+             containerLog.trace("  validating credentials by binding as the user");
+        }
+
+        // Set up security environment to bind as the user
+        context.addToEnvironment(Context.SECURITY_PRINCIPAL, dn);
+        context.addToEnvironment(Context.SECURITY_CREDENTIALS, credentials);
+
+        // Elicit an LDAP bind operation
+        boolean validated = false;
+        try {
+            if (containerLog.isTraceEnabled()) {
+                containerLog.trace("  binding as "  + dn);
+            }
+            attr = context.getAttributes("", null);
+            validated = true;
+        }
+        catch (AuthenticationException e) {
+            if (containerLog.isTraceEnabled()) {
+                containerLog.trace("  bind attempt failed");
+            }
+        }
+
+        // Restore the original security environment
+        if (connectionName != null) {
+            context.addToEnvironment(Context.SECURITY_PRINCIPAL,
+                                     connectionName);
+        } else {
+            context.removeFromEnvironment(Context.SECURITY_PRINCIPAL);
+        }
+
+        if (connectionPassword != null) {
+            context.addToEnvironment(Context.SECURITY_CREDENTIALS,
+                                     connectionPassword);
+        }
+        else {
+            context.removeFromEnvironment(Context.SECURITY_CREDENTIALS);
+        }
+
+        return (validated);
+     }
+
+
+    /**
+     * Return a List of roles associated with the given User.  Any
+     * roles present in the user's directory entry are supplemented by
+     * a directory search. If no roles are associated with this user,
+     * a zero-length List is returned.
+     *
+     * @param context The directory context we are searching
+     * @param user The User to be checked
+     *
+     * @exception NamingException if a directory server error occurs
+     */
+    protected List getRoles(DirContext context, User user)
+        throws NamingException {
+
+        if (user == null)
+            return (null);
+
+        String dn = user.dn;
+        String username = user.username;
+
+        if (dn == null || username == null)
+            return (null);
+
+        if (containerLog.isTraceEnabled())
+            containerLog.trace("  getRoles(" + dn + ")");
+
+        // Start with roles retrieved from the user entry
+        ArrayList list = user.roles;
+        if (list == null) {
+            list = new ArrayList();
+        }
+
+        // Are we configured to do role searches?
+        if ((roleFormat == null) || (roleName == null))
+            return (list);
+
+        // Set up parameters for an appropriate search
+        String filter = roleFormat.format(new String[] { doRFC2254Encoding(dn), username });
+        SearchControls controls = new SearchControls();
+        if (roleSubtree)
+            controls.setSearchScope(SearchControls.SUBTREE_SCOPE);
+        else
+            controls.setSearchScope(SearchControls.ONELEVEL_SCOPE);
+        controls.setReturningAttributes(new String[] {roleName});
+
+        // Perform the configured search and process the results
+        NamingEnumeration results =
+            context.search(roleBase, filter, controls);
+        if (results == null)
+            return (list);  // Should never happen, but just in case ...
+        while (results.hasMore()) {
+            SearchResult result = (SearchResult) results.next();
+            Attributes attrs = result.getAttributes();
+            if (attrs == null)
+                continue;
+            list = addAttributeValues(roleName, attrs, list);
+        }
+
+
+        if (containerLog.isTraceEnabled()) {
+            if (list != null) {
+                containerLog.trace("  Returning " + list.size() + " roles");
+                for (int i=0; i<list.size(); i++)
+                    containerLog.trace(  "  Found role " + list.get(i));
+            } else {
+                containerLog.trace("  getRoles about to return null ");
+            }
+        }
+
+        return (list);
+    }
+
+
+    /**
+     * Return a String representing the value of the specified attribute.
+     *
+     * @param attrId Attribute name
+     * @param attrs Attributes containing the required value
+     *
+     * @exception NamingException if a directory server error occurs
+     */
+    private String getAttributeValue(String attrId, Attributes attrs)
+        throws NamingException {
+
+        if (containerLog.isTraceEnabled())
+            containerLog.trace("  retrieving attribute " + attrId);
+
+        if (attrId == null || attrs == null)
+            return null;
+
+        Attribute attr = attrs.get(attrId);
+        if (attr == null)
+            return (null);
+        Object value = attr.get();
+        if (value == null)
+            return (null);
+        String valueString = null;
+        if (value instanceof byte[])
+            valueString = new String((byte[]) value);
+        else
+            valueString = value.toString();
+
+        return valueString;
+    }
+
+
+
+    /**
+     * Add values of a specified attribute to a list
+     *
+     * @param attrId Attribute name
+     * @param attrs Attributes containing the new values
+     * @param values ArrayList containing values found so far
+     *
+     * @exception NamingException if a directory server error occurs
+     */
+    private ArrayList addAttributeValues(String attrId,
+                                         Attributes attrs,
+                                         ArrayList values)
+        throws NamingException{
+
+        if (containerLog.isTraceEnabled())
+            containerLog.trace("  retrieving values for attribute " + attrId);
+        if (attrId == null || attrs == null)
+            return values;
+        if (values == null)
+            values = new ArrayList();
+        Attribute attr = attrs.get(attrId);
+        if (attr == null)
+            return (values);
+        NamingEnumeration e = attr.getAll();
+        while(e.hasMore()) {
+            String value = (String)e.next();
+            values.add(value);
+        }
+        return values;
+    }
+
+
+    /**
+     * Close any open connection to the directory server for this Realm.
+     *
+     * @param context The directory context to be closed
+     */
+    protected void close(DirContext context) {
+
+        // Do nothing if there is no opened connection
+        if (context == null)
+            return;
+
+        // Close our opened connection
+        try {
+            if (containerLog.isDebugEnabled())
+                containerLog.debug("Closing directory context");
+            context.close();
+        } catch (NamingException e) {
+            containerLog.error(sm.getString("jndiRealm.close"), e);
+        }
+        this.context = null;
+
+    }
+
+
+    /**
+     * Return a short name for this Realm implementation.
+     */
+    protected String getName() {
+
+        return (name);
+
+    }
+
+
+    /**
+     * Return the password associated with the given principal's user name.
+     */
+    protected String getPassword(String username) {
+
+        return (null);
+
+    }
+
+    /**
+     * Return the Principal associated with the given user name.
+     */
+    protected Principal getPrincipal(String username) {
+
+        DirContext context = null;
+        Principal principal = null;
+
+        try {
+
+            // Ensure that we have a directory context available
+            context = open();
+
+            // Occassionally the directory context will timeout.  Try one more
+            // time before giving up.
+            try {
+
+                // Authenticate the specified username if possible
+                principal = getPrincipal(context, username);
+
+            } catch (CommunicationException e) {
+
+                // log the exception so we know it's there.
+                containerLog.warn(sm.getString("jndiRealm.exception"), e);
+
+                // close the connection so we know it will be reopened.
+                if (context != null)
+                    close(context);
+
+                // open a new directory context.
+                context = open();
+
+                // Try the authentication again.
+                principal = getPrincipal(context, username);
+
+            }
+
+
+            // Release this context
+            release(context);
+
+            // Return the authenticated Principal (if any)
+            return (principal);
+
+        } catch (NamingException e) {
+
+            // Log the problem for posterity
+            containerLog.error(sm.getString("jndiRealm.exception"), e);
+
+            // Close the connection so that it gets reopened next time
+            if (context != null)
+                close(context);
+
+            // Return "not authenticated" for this request
+            return (null);
+
+        }
+
+
+    }
+
+
+    /**
+     * Return the Principal associated with the given user name.
+     */
+    protected synchronized Principal getPrincipal(DirContext context,
+                                                  String username)
+        throws NamingException {
+        
+        User user = getUser(context, username);
+        
+        return new GenericPrincipal(this, user.username, user.password ,
+                getRoles(context, user));
+    }
+
+    /**
+     * Open (if necessary) and return a connection to the configured
+     * directory server for this Realm.
+     *
+     * @exception NamingException if a directory server error occurs
+     */
+    protected DirContext open() throws NamingException {
+
+        // Do nothing if there is a directory server connection already open
+        if (context != null)
+            return (context);
+
+        try {
+
+            // Ensure that we have a directory context available
+            context = new InitialDirContext(getDirectoryContextEnvironment());
+
+        } catch (Exception e) {
+
+            connectionAttempt = 1;
+
+            // log the first exception.
+            containerLog.warn(sm.getString("jndiRealm.exception"), e);
+
+            // Try connecting to the alternate url.
+            context = new InitialDirContext(getDirectoryContextEnvironment());
+
+        } finally {
+
+            // reset it in case the connection times out.
+            // the primary may come back.
+            connectionAttempt = 0;
+
+        }
+
+        return (context);
+
+    }
+
+    /**
+     * Create our directory context configuration.
+     *
+     * @return java.util.Hashtable the configuration for the directory context.
+     */
+    protected Hashtable getDirectoryContextEnvironment() {
+
+        Hashtable env = new Hashtable();
+
+        // Configure our directory context environment.
+        if (containerLog.isDebugEnabled() && connectionAttempt == 0)
+            containerLog.debug("Connecting to URL " + connectionURL);
+        else if (containerLog.isDebugEnabled() && connectionAttempt > 0)
+            containerLog.debug("Connecting to URL " + alternateURL);
+        env.put(Context.INITIAL_CONTEXT_FACTORY, contextFactory);
+        if (connectionName != null)
+            env.put(Context.SECURITY_PRINCIPAL, connectionName);
+        if (connectionPassword != null)
+            env.put(Context.SECURITY_CREDENTIALS, connectionPassword);
+        if (connectionURL != null && connectionAttempt == 0)
+            env.put(Context.PROVIDER_URL, connectionURL);
+        else if (alternateURL != null && connectionAttempt > 0)
+            env.put(Context.PROVIDER_URL, alternateURL);
+        if (authentication != null)
+            env.put(Context.SECURITY_AUTHENTICATION, authentication);
+        if (protocol != null)
+            env.put(Context.SECURITY_PROTOCOL, protocol);
+        if (referrals != null)
+            env.put(Context.REFERRAL, referrals);
+        if (derefAliases != null)
+            env.put(JNDIRealm.DEREF_ALIASES, derefAliases);
+
+        return env;
+
+    }
+
+
+    /**
+     * Release our use of this connection so that it can be recycled.
+     *
+     * @param context The directory context to release
+     */
+    protected void release(DirContext context) {
+
+        ; // NO-OP since we are not pooling anything
+
+    }
+
+
+    // ------------------------------------------------------ Lifecycle Methods
+
+
+    /**
+     * Prepare for active use of the public methods of this Component.
+     *
+     * @exception LifecycleException if this component detects a fatal error
+     *  that prevents it from being started
+     */
+    public void start() throws LifecycleException {
+
+        // Perform normal superclass initialization
+        super.start();
+
+        // Validate that we can open our connection
+        try {
+            open();
+        } catch (NamingException e) {
+            throw new LifecycleException(sm.getString("jndiRealm.open"), e);
+        }
+
+    }
+
+
+    /**
+     * Gracefully shut down active use of the public methods of this Component.
+     *
+     * @exception LifecycleException if this component detects a fatal error
+     *  that needs to be reported
+     */
+    public void stop() throws LifecycleException {
+
+        // Perform normal superclass finalization
+        super.stop();
+
+        // Close any open directory server connection
+        close(this.context);
+
+    }
+
+    /**
+     * Given a string containing LDAP patterns for user locations (separated by
+     * parentheses in a pseudo-LDAP search string format -
+     * "(location1)(location2)", returns an array of those paths.  Real LDAP
+     * search strings are supported as well (though only the "|" "OR" type).
+     *
+     * @param userPatternString - a string LDAP search paths surrounded by
+     * parentheses
+     */
+    protected String[] parseUserPatternString(String userPatternString) {
+
+        if (userPatternString != null) {
+            ArrayList pathList = new ArrayList();
+            int startParenLoc = userPatternString.indexOf('(');
+            if (startParenLoc == -1) {
+                // no parens here; return whole thing
+                return new String[] {userPatternString};
+            }
+            int startingPoint = 0;
+            while (startParenLoc > -1) {
+                int endParenLoc = 0;
+                // weed out escaped open parens and parens enclosing the
+                // whole statement (in the case of valid LDAP search
+                // strings: (|(something)(somethingelse))
+                while ( (userPatternString.charAt(startParenLoc + 1) == '|') ||
+                        (startParenLoc != 0 && userPatternString.charAt(startParenLoc - 1) == '\\') ) {
+                    startParenLoc = userPatternString.indexOf("(", startParenLoc+1);
+                }
+                endParenLoc = userPatternString.indexOf(")", startParenLoc+1);
+                // weed out escaped end-parens
+                while (userPatternString.charAt(endParenLoc - 1) == '\\') {
+                    endParenLoc = userPatternString.indexOf(")", endParenLoc+1);
+                }
+                String nextPathPart = userPatternString.substring
+                    (startParenLoc+1, endParenLoc);
+                pathList.add(nextPathPart);
+                startingPoint = endParenLoc+1;
+                startParenLoc = userPatternString.indexOf('(', startingPoint);
+            }
+            return (String[])pathList.toArray(new String[] {});
+        }
+        return null;
+
+    }
+
+
+    /**
+     * Given an LDAP search string, returns the string with certain characters
+     * escaped according to RFC 2254 guidelines.
+     * The character mapping is as follows:
+     *     char ->  Replacement
+     *    ---------------------------
+     *     *  -> \2a
+     *     (  -> \28
+     *     )  -> \29
+     *     \  -> \5c
+     *     \0 -> \00
+     * @param inString string to escape according to RFC 2254 guidelines
+     * @return String the escaped/encoded result
+     */
+    protected String doRFC2254Encoding(String inString) {
+        StringBuffer buf = new StringBuffer(inString.length());
+        for (int i = 0; i < inString.length(); i++) {
+            char c = inString.charAt(i);
+            switch (c) {
+                case '\\':
+                    buf.append("\\5c");
+                    break;
+                case '*':
+                    buf.append("\\2a");
+                    break;
+                case '(':
+                    buf.append("\\28");
+                    break;
+                case ')':
+                    buf.append("\\29");
+                    break;
+                case '\0':
+                    buf.append("\\00");
+                    break;
+                default:
+                    buf.append(c);
+                    break;
+            }
+        }
+        return buf.toString();
+    }
+
+
+}
+
+// ------------------------------------------------------ Private Classes
+
+/**
+ * A private class representing a User
+ */
+class User {
+    String username = null;
+    String dn = null;
+    String password = null;
+    ArrayList roles = null;
+
+
+    User(String username, String dn, String password, ArrayList roles) {
+        this.username = username;
+        this.dn = dn;
+        this.password = password;
+        this.roles = roles;
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/realm/LocalStrings.properties
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/realm/LocalStrings.properties	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/realm/LocalStrings.properties	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,72 @@
+# $Id: LocalStrings.properties 303678 2005-02-03 15:14:34Z remm $
+
+# language
+
+# package org.apache.catalina.realm
+
+jaasRealm.beginLogin=JAASRealm login requested for username "{0}" using LoginContext for application "{1}"
+jaasRealm.accountExpired=Username "{0}" NOT authenticated due to expired account
+jaasRealm.authenticateFailure=Username "{0}" NOT successfully authenticated
+jaasRealm.authenticateSuccess=Username "{0}" successfully authenticated as Principal "{1}" -- Subject was created too
+jaasRealm.credentialExpired=Username "{0}" NOT authenticated due to expired credential
+jaasRealm.failedLogin=Username "{0}" NOT authenticated due to failed login
+jaasRealm.loginException=Login exception authenticating username "{0}"
+jaasRealm.unexpectedError=Unexpected error
+jaasRealm.loginContextCreated=JAAS LoginContext created for username "{0}"
+jaasRealm.userPrincipalSuccess=Subject for username "{0}" returned user Principal "{1}"
+jaasRealm.userPrincipalFailure=Subject for username "{0}" did not return a valid user Principal
+jaasRealm.cachePrincipal=User Principal "{0}" cached; has {1} role Principal(s)
+jaasRealm.checkPrincipal=Checking Principal "{0}" [{1}]
+jaasRealm.userPrincipalSuccess=Principal "{0}" is a valid user class. We will use this as the user Principal.
+jaasRealm.userPrincipalFailure=No valid user Principal found
+jaasRealm.rolePrincipalAdd=Adding role Principal "{0}" to this user Principal''s roles
+jaasRealm.rolePrincipalSuccess={0} role Principal(s) found
+jaasRealm.rolePrincipalFailure=No valid role Principals found.
+jaasRealm.isInRole.start=Checking if user Principal "{0}" possesses role "{1}"
+jaasRealm.isInRole.noPrincipalOrRole=No roles Principals found. User Principal or Subject is null, or user Principal not in cache
+jaasRealm.isInRole.principalCached=User Principal has {0} role Principal(s)
+jaasRealm.isInRole.possessesRole=User Principal has a role Principal called "{0}"
+jaasRealm.isInRole.match=Matching role Principal found.
+jaasRealm.isInRole.noMatch=Matching role Principal NOT found.
+jaasCallback.digestpassword=Digested password "{0}" as "{1}"
+jaasCallback.username=Returned username "{0}"
+jaasCallback.password=Returned password "{0}"
+jdbcRealm.authenticateFailure=Username {0} NOT successfully authenticated
+jdbcRealm.authenticateSuccess=Username {0} successfully authenticated
+jdbcRealm.close=Exception closing database connection
+jdbcRealm.exception=Exception performing authentication
+jdbcRealm.getPassword.exception=Exception retrieving password for "{0}"
+jdbcRealm.getRoles.exception=Exception retrieving roles for "{0}"
+jdbcRealm.open=Exception opening database connection
+jndiRealm.authenticateFailure=Username {0} NOT successfully authenticated
+jndiRealm.authenticateSuccess=Username {0} successfully authenticated
+jndiRealm.close=Exception closing directory server connection
+jndiRealm.exception=Exception performing authentication
+jndiRealm.open=Exception opening directory server connection
+memoryRealm.authenticateFailure=Username {0} NOT successfully authenticated
+memoryRealm.authenticateSuccess=Username {0} successfully authenticated
+memoryRealm.loadExist=Memory database file {0} cannot be read
+memoryRealm.loadPath=Loading users from memory database file {0}
+memoryRealm.readXml=Exception while reading memory database file
+realmBase.algorithm=Invalid message digest algorithm {0} specified
+realmBase.alreadyStarted=This Realm has already been started
+realmBase.digest=Error digesting user credentials
+realmBase.forbidden=Access to the requested resource has been denied
+realmBase.hasRoleFailure=Username {0} does NOT have role {1}
+realmBase.hasRoleSuccess=Username {0} has role {1}
+realmBase.notAuthenticated=Configuration error:  Cannot perform access control without an authenticated principal
+realmBase.notStarted=This Realm has not yet been started
+realmBase.authenticateFailure=Username {0} NOT successfully authenticated
+realmBase.authenticateSuccess=Username {0} successfully authenticated
+userDatabaseRealm.authenticateError=Login configuration error authenticating username {0}
+userDatabaseRealm.lookup=Exception looking up UserDatabase under key {0}
+userDatabaseRealm.noDatabase=No UserDatabase component found under key {0}
+userDatabaseRealm.noEngine=No Engine component found in container hierarchy
+userDatabaseRealm.noGlobal=No global JNDI resources context found
+dataSourceRealm.authenticateFailure=Username {0} NOT successfully authenticated
+dataSourceRealm.authenticateSuccess=Username {0} successfully authenticated
+dataSourceRealm.close=Exception closing database connection
+dataSourceRealm.exception=Exception performing authentication
+dataSourceRealm.getPassword.exception=Exception retrieving password for "{0}"
+dataSourceRealm.getRoles.exception=Exception retrieving roles for "{0}"
+dataSourceRealm.open=Exception opening database connection

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/realm/LocalStrings_es.properties
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/realm/LocalStrings_es.properties	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/realm/LocalStrings_es.properties	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,47 @@
+# $Id: LocalStrings_es.properties 302991 2004-07-03 04:16:41Z billbarker $
+
+# language es
+
+# package org.apache.catalina.realm
+
+jaasRealm.accountExpired=El usuario {0} NO ha sido autentificado porque ha expirado su cuenta
+jaasRealm.authenticatedSuccess=El usuario {0} ha sido autentificado con éxito
+jaasRealm.credentialExpired=El usuario {0} NO ha sido autentificado porque ha expirado su credencial
+jaasRealm.failedLogin=El usuario {0} NO ha sido autentificado porque ha fallado el login
+jaasRealm.loginException=Excepción de Login autenticando nombre de usuario {0}
+jaasRealm.unexpectedError=Error inesperado
+jdbcRealm.authenticateFailure=El usuario {0} NO ha sido autentificado correctamente
+jdbcRealm.authenticateSuccess=El usuario {0} ha sido autentificado correctamente
+jdbcRealm.close=Excepción al cerrar la conexión a la base de datos
+jdbcRealm.exception=Excepción al realizar la autentificación
+jdbcRealm.open=Excepción abriendo la conexión a la base de datos
+jndiRealm.authenticateFailure=Autentificación fallida para el usuario {0}
+jndiRealm.authenticateSuccess=Autentificación correcta para el usuario {0}
+jndiRealm.close=Excepción al cerrar la conexión al servidor de directorio
+jndiRealm.exception=Excepción al realizar la autentificación
+jndiRealm.open=Excepción al abrir la conexión al servidor de directorio
+memoryRealm.authenticateFailure=Autentificación fallida para el usuario {0}
+memoryRealm.authenticateSuccess=Autentificación correcta para el usuario {0}
+memoryRealm.loadExist=El fichero de usuarios {0} no ha podido ser leído
+memoryRealm.loadPath=Cargando los usuarios desde el fichero {0}
+memoryRealm.readXml=Excepción mientras se leía el fichero de usuarios
+realmBase.algorithm=El algoritmo resumen (digest) {0} es inválido
+realmBase.alreadyStarted=Este dominio ya ha sido inicializado
+realmBase.digest=Error procesando las credenciales del usuario
+realmBase.forbidden=El acceso al recurso pedido ha sido denegado
+realmBase.hasRoleFailure=El usuario {0} NO desempeña el papel de {1}
+realmBase.hasRoleSuccess=El usuario {0} desempeña el papel de {1}
+realmBase.notAuthenticated=Error de Configuración: No se pueden realizar funciones de control de acceso sin un principal autentificado
+realmBase.notStarted=Este dominio aún no ha sido inicializado
+realmBase.authenticateFailure=Nombre de usuario {0} NO autenticado con éxito
+realmBase.authenticateSuccess=Nombre de usuario {0} autenticado con éxito
+userDatabaseRealm.authenticateError=Error de configuración de Login autenticando nombre de usuario {0}
+userDatabaseRealm.lookup=Excepción buscando en Base de datos de Usuario mediante la clave {0}
+userDatabaseRealm.noDatabase=No se ha hallado componente de Base de datos de Usuario mediante la clave {0}
+userDatabaseRealm.noEngine=No se ha hallado componente de Motor en jerarquía de contenedor
+userDatabaseRealm.noGlobal=No se ha hallado contexto de recursos globales JNDI
+dataSourceRealm.authenticateFailure=Nombre de usuario {0} NO autenticado con éxito
+dataSourceRealm.authenticateSuccess=Nombre de usuario {0} autenticado con éxito
+dataSourceRealm.close=Excepción cerrando conexión a base de datos
+dataSourceRealm.exception=Excepción realizando autenticación
+dataSourceRealm.open=Excepción abriendo conexión a base de datos

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/realm/LocalStrings_fr.properties
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/realm/LocalStrings_fr.properties	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/realm/LocalStrings_fr.properties	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,41 @@
+# $Id: LocalStrings_fr.properties 302991 2004-07-03 04:16:41Z billbarker $
+
+# language
+
+# package org.apache.catalina.realm
+
+jaasRealm.accountExpired=le nom d''utilisateur {0} N''A PAS été authentifié car le compte a expiré
+jaasRealm.authenticateSuccess=le nom d''utilisateur {0} a été authentifié avec succès
+jaasRealm.credentialExpired=le nom d''utilisateur {0} N''A PAS été authentifié car son crédit a expiré (expired credential)
+jaasRealm.failedLogin=le nom d''utilisateur {0} N''A PAS été authentifié car son contrôle d''accès (login) a échoué
+jaasRealm.loginException=Exception lors de l''authentification par login du nom d''utilisateur {0}
+jdbcRealm.authenticateFailure=le nom d''utilisateur {0} N''A PAS été authentifié
+jdbcRealm.authenticateSuccess=le nom d''utilisateur {0} a été authentifié avec succès
+jdbcRealm.close=Exception lors de la fermeture de la connexion à la base de données
+jdbcRealm.exception=Exception pendant le traitement de l''authentification
+jdbcRealm.open=Exception lors de l''ouverture de la base de données
+jndiRealm.authenticateFailure=Le nom d''utilisateur {0} N''A PAS été authentifié
+jndiRealm.authenticateSuccess=Le nom d''utilisateur {0} a été authentifié avec succès
+jndiRealm.close=Exception lors de la fermeture de la connexion au serveur d''accès (directory server)
+jndiRealm.exception=Exception pendant le traitement de l''authentification
+jndiRealm.open=Exception lors de l''ouverture de la connexion au serveur d''accès (directory server)
+memoryRealm.authenticateFailure=le nom d''utilisateur {0} N''A PAS été authentifié
+memoryRealm.authenticateSuccess=le nom d''utilisateur {0} a été authentifié avec succès
+memoryRealm.loadExist=Le fichier base de données mémoire (memory database) {0} ne peut être lu
+memoryRealm.loadPath=Chargement des utilisateurs depuis le fichier base de données mémoire (memory database) {0}
+memoryRealm.readXml=Exception lors de la lecture du fichier base de données mémoire (memory database)
+realmBase.algorithm=L''algorithme d''empreinte de message (message digest) {0} indiqué est invalide
+realmBase.alreadyStarted=Ce royaume (Realm) a déjà été démarré
+realmBase.digest=Erreur lors du traitement des empreintes (digest) des crédits utilisateur (user credentials)
+realmBase.forbidden=L''accès à la ressource demandée a été interdit
+realmBase.hasRoleFailure=Le nom d''utilisateur {0} N''A PAS de rôle {1}
+realmBase.hasRoleSuccess=Le nom d''utilisateur {0} a pour rôle {1}
+realmBase.notAuthenticated=Erreur de configuration:  Impossible de conduire un contrôle d''accès sans un authentifié principal (authenticated principal)
+realmBase.notStarted=Ce royaume (Realm) n''a pas encore été démarré
+realmBase.authenticateFailure=Le nom d''utilisateur {0} N''A PAS été authentifié
+realmBase.authenticateSuccess=Le nom d''utilisateur {0} a été authentifié avec succès
+userDatabaseRealm.authenticateError=Erreur de configuration du contrôle d''accès (login) lors de l''authentification du nom d''utilisateur {0}
+userDatabaseRealm.lookup=Exception lors de la recherche dans la base de données utilisateurs avec la clef {0}
+userDatabaseRealm.noDatabase=Aucun composant base de données utilisateurs trouvé pour la clef {0}
+userDatabaseRealm.noEngine=Aucun composant moteur (engine component) trouvé dans la hiérarchie des conteneurs
+userDatabaseRealm.noGlobal=Aucune ressource globale JNDI trouvée

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/realm/LocalStrings_ja.properties
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/realm/LocalStrings_ja.properties	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/realm/LocalStrings_ja.properties	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,47 @@
+# $Id: LocalStrings_ja.properties 302991 2004-07-03 04:16:41Z billbarker $
+
+# language ja
+
+# package org.apache.catalina.realm
+
+jaasRealm.accountExpired=\u30e6\u30fc\u30b6\u540d {0} \u306f\u30a2\u30ab\u30a6\u30f3\u30c8\u306e\u671f\u9650\u304c\u5207\u308c\u3066\u3044\u308b\u305f\u3081\u306b\u8a8d\u8a3c\u3055\u308c\u307e\u305b\u3093
+jaasRealm.authenticateSuccess=\u30e6\u30fc\u30b6\u540d {0} \u306f\u8a8d\u8a3c\u306b\u6210\u529f\u3057\u307e\u3057\u305f
+jaasRealm.credentialExpired=\u30e6\u30fc\u30b6\u540d {0} \u306f\u8a3c\u660e\u66f8\u306e\u671f\u9650\u304c\u5207\u308c\u305f\u305f\u3081\u306b\u8a8d\u8a3c\u3055\u308c\u307e\u305b\u3093
+jaasRealm.failedLogin=\u30e6\u30fc\u30b6\u540d {0} \u306f\u30ed\u30b0\u30a4\u30f3\u306b\u5931\u6557\u3057\u305f\u305f\u3081\u306b\u8a8d\u8a3c\u3055\u308c\u307e\u305b\u3093\u3067\u3057\u305f
+jaasRealm.loginException=\u30e6\u30fc\u30b6\u540d {0} \u306e\u8a8d\u8a3c\u4e2d\u306b\u30ed\u30b0\u30a4\u30f3\u4f8b\u5916\u304c\u767a\u751f\u3057\u307e\u3057\u305f
+jaasRealm.unexpectedError=\u4e88\u6e2c\u3057\u306a\u3044\u30a8\u30e9\u30fc\u3067\u3059
+jdbcRealm.authenticateFailure=\u30e6\u30fc\u30b6\u540d {0} \u306f\u8a8d\u8a3c\u306b\u5931\u6557\u3057\u307e\u3057\u305f
+jdbcRealm.authenticateSuccess=\u30e6\u30fc\u30b6\u540d {0} \u306f\u8a8d\u8a3c\u306b\u6210\u529f\u3057\u307e\u3057\u305f
+jdbcRealm.close=\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u63a5\u7d9a\u30af\u30ed\u30fc\u30ba\u4e2d\u306e\u4f8b\u5916\u3067\u3059
+jdbcRealm.exception=\u8a8d\u8a3c\u5b9f\u884c\u4e2d\u306e\u4f8b\u5916\u3067\u3059
+jdbcRealm.open=\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u63a5\u7d9a\u30aa\u30fc\u30d7\u30f3\u4e2d\u306b\u4f8b\u5916\u304c\u767a\u751f\u3057\u307e\u3057\u305f
+jndiRealm.authenticateFailure=\u30e6\u30fc\u30b6\u540d {0} \u306f\u8a8d\u8a3c\u306b\u5931\u6557\u3057\u307e\u3057\u305f
+jndiRealm.authenticateSuccess=\u30e6\u30fc\u30b6\u540d {0} \u306f\u8a8d\u8a3c\u306b\u6210\u529f\u3057\u307e\u3057\u305f
+jndiRealm.close=\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u30b5\u30fc\u30d0\u63a5\u7d9a\u30af\u30ed\u30fc\u30ba\u4e2d\u306e\u4f8b\u5916\u3067\u3059
+jndiRealm.exception=\u8a8d\u8a3c\u5b9f\u884c\u4e2d\u306e\u4f8b\u5916\u3067\u3059
+jndiRealm.open=\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u30b5\u30fc\u30d0\u63a5\u7d9a\u30aa\u30fc\u30d7\u30f3\u4e2d\u306e\u4f8b\u5916\u3067\u3059
+memoryRealm.authenticateFailure=\u30e6\u30fc\u30b6\u540d {0} \u306f\u8a8d\u8a3c\u306b\u5931\u6557\u3057\u307e\u3057\u305f
+memoryRealm.authenticateSuccess=\u30e6\u30fc\u30b6\u540d {0} \u306f\u8a8d\u8a3c\u306b\u6210\u529f\u3057\u307e\u3057\u305f
+memoryRealm.loadExist=\u30e1\u30e2\u30ea\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u30d5\u30a1\u30a4\u30eb {0} \u3092\u8aad\u3080\u3053\u3068\u304c\u3067\u304d\u307e\u305b\u3093
+memoryRealm.loadPath=\u30e1\u30e2\u30ea\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u30d5\u30a1\u30a4\u30eb {0} \u304b\u3089\u30e6\u30fc\u30b6\u3092\u30ed\u30fc\u30c9\u3057\u307e\u3059
+memoryRealm.readXml=\u30e1\u30e2\u30ea\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u30d5\u30a1\u30a4\u30eb\u3092\u8aad\u307f\u8fbc\u307f\u4e2d\u306e\u4f8b\u5916\u3067\u3059
+realmBase.algorithm=\u7121\u52b9\u306a\u30e1\u30c3\u30bb\u30fc\u30b8\u30c0\u30a4\u30b8\u30a7\u30b9\u30c8\u30a2\u30eb\u30b4\u30ea\u30ba\u30e0 {0} \u304c\u6307\u5b9a\u3055\u308c\u3066\u3044\u307e\u3059
+realmBase.alreadyStarted=\u3053\u306e\u30ec\u30eb\u30e0\u306f\u65e2\u306b\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u3059
+realmBase.digest=\u30e6\u30fc\u30b6\u306e\u8a3c\u660e\u66f8\u306e\u30c0\u30a4\u30b8\u30a7\u30b9\u30c8\u30a8\u30e9\u30fc
+realmBase.forbidden=\u8981\u6c42\u3055\u308c\u305f\u30ea\u30bd\u30fc\u30b9\u3078\u306e\u30a2\u30af\u30bb\u30b9\u304c\u62d2\u5426\u3055\u308c\u307e\u3057\u305f
+realmBase.hasRoleFailure=\u30e6\u30fc\u30b6\u540d {0} \u306f\u30ed\u30fc\u30eb {1} \u3092\u6301\u3063\u3066\u3044\u307e\u305b\u3093
+realmBase.hasRoleSuccess=\u30e6\u30fc\u30b6\u540d {0} \u306f\u30ed\u30fc\u30eb {1} \u3092\u6301\u3063\u3066\u3044\u307e\u3059
+realmBase.notAuthenticated=\u8a2d\u5b9a\u30a8\u30e9\u30fc:  \u8a8d\u8a3c\u3055\u308c\u305f\u4e3b\u4f53\u306a\u3057\u3067\u306f\u30a2\u30af\u30bb\u30b9\u5236\u5fa1\u304c\u5b9f\u884c\u3067\u304d\u307e\u305b\u3093
+realmBase.notStarted=\u3053\u306e\u30ec\u30eb\u30e0\u306f\u307e\u3060\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u305b\u3093
+realmBase.authenticateFailure=\u30e6\u30fc\u30b6\u540d {0} \u306f\u8a8d\u8a3c\u306b\u5931\u6557\u3057\u307e\u3057\u305f
+realmBase.authenticateSuccess=\u30e6\u30fc\u30b6\u540d {0} \u306f\u8a8d\u8a3c\u306b\u6210\u529f\u3057\u307e\u3057\u305f
+userDatabaseRealm.authenticateError=\u30e6\u30fc\u30b6\u540d {0} \u3092\u8a8d\u8a3c\u4e2d\u306b\u30ed\u30b0\u30a4\u30f3\u8a2d\u5b9a\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f
+userDatabaseRealm.lookup=\u30ad\u30fc {0} \u3067\u30e6\u30fc\u30b6\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u3092\u691c\u7d22\u4e2d\u306e\u4f8b\u5916\u3067\u3059
+userDatabaseRealm.noDatabase=\u30ad\u30fc {0} \u3067\u30e6\u30fc\u30b6\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u30b3\u30f3\u30dd\u30fc\u30cd\u30f3\u30c8\u304c\u898b\u3064\u304b\u308a\u307e\u305b\u3093
+userDatabaseRealm.noEngine=\u30b3\u30f3\u30c6\u30ca\u968e\u5c64\u4e2d\u306b\u30a8\u30f3\u30b8\u30f3\u30b3\u30f3\u30dd\u30fc\u30cd\u30f3\u30c8\u304c\u898b\u3064\u304b\u308a\u307e\u305b\u3093
+userDatabaseRealm.noGlobal=\u30b0\u30ed\u30fc\u30d0\u30eb\u306aJNDI\u30ea\u30bd\u30fc\u30b9\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u304c\u898b\u3064\u304b\u308a\u307e\u305b\u3093
+dataSourceRealm.authenticateFailure=\u30e6\u30fc\u30b6\u540d {0} \u306f\u8a8d\u8a3c\u306b\u5931\u6557\u3057\u307e\u3057\u305f
+dataSourceRealm.authenticateSuccess=\u30e6\u30fc\u30b6\u540d {0} \u306f\u8a8d\u8a3c\u306b\u6210\u529f\u3057\u307e\u3057\u305f
+dataSourceRealm.close=\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u63a5\u7d9a\u3092\u30af\u30ed\u30fc\u30ba\u4e2d\u306e\u4f8b\u5916\u3067\u3059
+dataSourceRealm.exception=\u8a8d\u8a3c\u3092\u5b9f\u884c\u4e2d\u306e\u4f8b\u5916\u3067\u3059
+dataSourceRealm.open=\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u63a5\u7d9a\u3092\u30aa\u30fc\u30d7\u30f3\u4e2d\u306e\u4f8b\u5916\u3067\u3059

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/realm/MemoryRealm.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/realm/MemoryRealm.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/realm/MemoryRealm.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,340 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.realm;
+
+
+import java.security.Principal;
+import java.io.File;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Map;
+import org.apache.catalina.Container;
+import org.apache.catalina.LifecycleException;
+import org.apache.catalina.util.StringManager;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.tomcat.util.digester.Digester;
+
+
+/**
+ * Simple implementation of <b>Realm</b> that reads an XML file to configure
+ * the valid users, passwords, and roles.  The file format (and default file
+ * location) are identical to those currently supported by Tomcat 3.X.
+ * <p>
+ * <strong>IMPLEMENTATION NOTE</strong>: It is assumed that the in-memory
+ * collection representing our defined users (and their roles) is initialized
+ * at application startup and never modified again.  Therefore, no thread
+ * synchronization is performed around accesses to the principals collection.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 373023 $ $Date: 2006-01-27 17:17:43 -0600 (Fri, 27 Jan 2006) $
+ */
+
+public class MemoryRealm  extends RealmBase {
+
+    private static Log log = LogFactory.getLog(MemoryRealm.class);
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The Container with which this Realm is associated.
+     */
+    private Container container = null;
+
+
+    /**
+     * The Digester we will use to process in-memory database files.
+     */
+    private static Digester digester = null;
+
+
+    /**
+     * Descriptive information about this Realm implementation.
+     */
+    protected final String info =
+        "org.apache.catalina.realm.MemoryRealm/1.0";
+
+
+    /**
+     * Descriptive information about this Realm implementation.
+     */
+
+    protected static final String name = "MemoryRealm";
+
+
+    /**
+     * The pathname (absolute or relative to Catalina's current working
+     * directory) of the XML file containing our database information.
+     */
+    private String pathname = "conf/tomcat-users.xml";
+
+
+    /**
+     * The set of valid Principals for this Realm, keyed by user name.
+     */
+    private Map principals = new HashMap();
+
+
+    /**
+     * The string manager for this package.
+     */
+    private static StringManager sm =
+        StringManager.getManager(Constants.Package);
+
+
+    /**
+     * Has this component been started?
+     */
+    private boolean started = false;
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * Return descriptive information about this Realm implementation and
+     * the corresponding version number, in the format
+     * <code>&lt;description&gt;/&lt;version&gt;</code>.
+     */
+    public String getInfo() {
+
+        return info;
+
+    }
+
+
+    /**
+     * Return the pathname of our XML file containing user definitions.
+     */
+    public String getPathname() {
+
+        return pathname;
+
+    }
+
+
+    /**
+     * Set the pathname of our XML file containing user definitions.  If a
+     * relative pathname is specified, it is resolved against "catalina.base".
+     *
+     * @param pathname The new pathname
+     */
+    public void setPathname(String pathname) {
+
+        this.pathname = pathname;
+
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Return the Principal associated with the specified username and
+     * credentials, if there is one; otherwise return <code>null</code>.
+     *
+     * @param username Username of the Principal to look up
+     * @param credentials Password or other credentials to use in
+     *  authenticating this username
+     */
+    public Principal authenticate(String username, String credentials) {
+
+        GenericPrincipal principal =
+            (GenericPrincipal) principals.get(username);
+
+        boolean validated = false;
+        if (principal != null) {
+            if (hasMessageDigest()) {
+                // Hex hashes should be compared case-insensitive
+                validated = (digest(credentials)
+                             .equalsIgnoreCase(principal.getPassword()));
+            } else {
+                validated =
+                    (digest(credentials).equals(principal.getPassword()));
+            }
+        }
+
+        if (validated) {
+            if (log.isDebugEnabled())
+                log.debug(sm.getString("memoryRealm.authenticateSuccess", username));
+            return (principal);
+        } else {
+            if (log.isDebugEnabled())
+                log.debug(sm.getString("memoryRealm.authenticateFailure", username));
+            return (null);
+        }
+
+    }
+
+
+    // -------------------------------------------------------- Package Methods
+
+
+    /**
+     * Add a new user to the in-memory database.
+     *
+     * @param username User's username
+     * @param password User's password (clear text)
+     * @param roles Comma-delimited set of roles associated with this user
+     */
+    void addUser(String username, String password, String roles) {
+
+        // Accumulate the list of roles for this user
+        ArrayList list = new ArrayList();
+        roles += ",";
+        while (true) {
+            int comma = roles.indexOf(',');
+            if (comma < 0)
+                break;
+            String role = roles.substring(0, comma).trim();
+            list.add(role);
+            roles = roles.substring(comma + 1);
+        }
+
+        // Construct and cache the Principal for this user
+        GenericPrincipal principal =
+            new GenericPrincipal(this, username, password, list);
+        principals.put(username, principal);
+
+    }
+
+
+    // ------------------------------------------------------ Protected Methods
+
+
+    /**
+     * Return a configured <code>Digester</code> to use for processing
+     * the XML input file, creating a new one if necessary.
+     */
+    protected synchronized Digester getDigester() {
+
+        if (digester == null) {
+            digester = new Digester();
+            digester.setValidating(false);
+            digester.addRuleSet(new MemoryRuleSet());
+        }
+        return (digester);
+
+    }
+
+
+    /**
+     * Return a short name for this Realm implementation.
+     */
+    protected String getName() {
+
+        return (name);
+
+    }
+
+
+    /**
+     * Return the password associated with the given principal's user name.
+     */
+    protected String getPassword(String username) {
+
+        GenericPrincipal principal =
+            (GenericPrincipal) principals.get(username);
+        if (principal != null) {
+            return (principal.getPassword());
+        } else {
+            return (null);
+        }
+
+    }
+
+
+    /**
+     * Return the Principal associated with the given user name.
+     */
+    protected Principal getPrincipal(String username) {
+
+        return (Principal) principals.get(username);
+
+    }
+
+    /**
+     * Returns the principals for this realm.
+     *
+     * @return The principals, keyed by user name (a String)
+     */
+    protected Map getPrincipals() {
+        return principals;
+    }
+
+
+    // ------------------------------------------------------ Lifecycle Methods
+
+
+    /**
+     * Prepare for active use of the public methods of this Component.
+     *
+     * @exception LifecycleException if this component detects a fatal error
+     *  that prevents it from being started
+     */
+    public synchronized void start() throws LifecycleException {
+
+        // Perform normal superclass initialization
+        super.start();
+
+        // Validate the existence of our database file
+        File file = new File(pathname);
+        if (!file.isAbsolute())
+            file = new File(System.getProperty("catalina.base"), pathname);
+        if (!file.exists() || !file.canRead())
+            throw new LifecycleException
+                (sm.getString("memoryRealm.loadExist",
+                              file.getAbsolutePath()));
+
+        // Load the contents of the database file
+        if (log.isDebugEnabled())
+            log.debug(sm.getString("memoryRealm.loadPath",
+                             file.getAbsolutePath()));
+        Digester digester = getDigester();
+        try {
+            synchronized (digester) {
+                digester.push(this);
+                digester.parse(file);
+            }
+        } catch (Exception e) {
+            throw new LifecycleException("memoryRealm.readXml", e);
+        } finally {
+            digester.reset();
+        }
+
+    }
+
+
+    /**
+     * Gracefully shut down active use of the public methods of this Component.
+     *
+     * @exception LifecycleException if this component detects a fatal error
+     *  that needs to be reported
+     */
+    public synchronized void stop() throws LifecycleException {
+
+        // Perform normal superclass finalization
+        super.stop();
+
+        // No shutdown activities required
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/realm/MemoryRuleSet.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/realm/MemoryRuleSet.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/realm/MemoryRuleSet.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,134 @@
+/*
+ * Copyright 1999-2001,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.realm;
+
+
+import org.apache.tomcat.util.digester.Digester;
+import org.apache.tomcat.util.digester.Rule;
+import org.apache.tomcat.util.digester.RuleSetBase;
+import org.xml.sax.Attributes;
+
+
+/**
+ * <p><strong>RuleSet</strong> for recognizing the users defined in the
+ * XML file processed by <code>MemoryRealm</code>.</p>
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302984 $ $Date: 2004-06-26 12:41:33 -0500 (Sat, 26 Jun 2004) $
+ */
+
+public class MemoryRuleSet extends RuleSetBase {
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The matching pattern prefix to use for recognizing our elements.
+     */
+    protected String prefix = null;
+
+
+    // ------------------------------------------------------------ Constructor
+
+
+    /**
+     * Construct an instance of this <code>RuleSet</code> with the default
+     * matching pattern prefix.
+     */
+    public MemoryRuleSet() {
+
+        this("tomcat-users/");
+
+    }
+
+
+    /**
+     * Construct an instance of this <code>RuleSet</code> with the specified
+     * matching pattern prefix.
+     *
+     * @param prefix Prefix for matching pattern rules (including the
+     *  trailing slash character)
+     */
+    public MemoryRuleSet(String prefix) {
+
+        super();
+        this.namespaceURI = null;
+        this.prefix = prefix;
+
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * <p>Add the set of Rule instances defined in this RuleSet to the
+     * specified <code>Digester</code> instance, associating them with
+     * our namespace URI (if any).  This method should only be called
+     * by a Digester instance.</p>
+     *
+     * @param digester Digester instance to which the new Rule instances
+     *  should be added.
+     */
+    public void addRuleInstances(Digester digester) {
+
+        digester.addRule(prefix + "user", new MemoryUserRule());
+
+    }
+
+
+}
+
+
+/**
+ * Private class used when parsing the XML database file.
+ */
+final class MemoryUserRule extends Rule {
+
+
+    /**
+     * Construct a new instance of this <code>Rule</code>.
+     */
+    public MemoryUserRule() {
+    }
+
+
+    /**
+     * Process a <code>&lt;user&gt;</code> element from the XML database file.
+     *
+     * @param attributes The attribute list for this element
+     */
+    public void begin(String namespace, String name, Attributes attributes)
+        throws Exception {
+
+        String username = attributes.getValue("name");
+        if (username == null) {
+            username = attributes.getValue("username");
+        }
+        String password = attributes.getValue("password");
+        String roles = attributes.getValue("roles");
+
+        MemoryRealm realm =
+            (MemoryRealm) digester.peek(digester.getCount() - 1);
+        realm.addUser(username, password, roles);
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/realm/RealmBase.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/realm/RealmBase.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/realm/RealmBase.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,1426 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.realm;
+
+
+import java.beans.PropertyChangeListener;
+import java.beans.PropertyChangeSupport;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.Principal;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+
+import javax.management.Attribute;
+import javax.management.MBeanRegistration;
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.catalina.Container;
+import org.apache.catalina.Context;
+import org.apache.catalina.Lifecycle;
+import org.apache.catalina.LifecycleException;
+import org.apache.catalina.LifecycleListener;
+import org.apache.catalina.Realm;
+import org.apache.catalina.connector.Request;
+import org.apache.catalina.connector.Response;
+import org.apache.catalina.core.ContainerBase;
+import org.apache.catalina.deploy.LoginConfig;
+import org.apache.catalina.deploy.SecurityConstraint;
+import org.apache.catalina.deploy.SecurityCollection;
+import org.apache.catalina.util.HexUtils;
+import org.apache.catalina.util.LifecycleSupport;
+import org.apache.catalina.util.MD5Encoder;
+import org.apache.catalina.util.StringManager;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.commons.modeler.Registry;
+
+/**
+ * Simple implementation of <b>Realm</b> that reads an XML file to configure
+ * the valid users, passwords, and roles.  The file format (and default file
+ * location) are identical to those currently supported by Tomcat 3.X.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 388949 $ $Date: 2006-03-26 13:55:03 -0600 (Sun, 26 Mar 2006) $
+ */
+
+public abstract class RealmBase
+    implements Lifecycle, Realm, MBeanRegistration {
+
+    private static Log log = LogFactory.getLog(RealmBase.class);
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The Container with which this Realm is associated.
+     */
+    protected Container container = null;
+
+
+    /**
+     * Container log
+     */
+    protected Log containerLog = null;
+
+
+    /**
+     * Digest algorithm used in storing passwords in a non-plaintext format.
+     * Valid values are those accepted for the algorithm name by the
+     * MessageDigest class, or <code>null</code> if no digesting should
+     * be performed.
+     */
+    protected String digest = null;
+
+    /**
+     * The encoding charset for the digest.
+     */
+    protected String digestEncoding = null;
+
+
+    /**
+     * Descriptive information about this Realm implementation.
+     */
+    protected static final String info =
+        "org.apache.catalina.realm.RealmBase/1.0";
+
+
+    /**
+     * The lifecycle event support for this component.
+     */
+    protected LifecycleSupport lifecycle = new LifecycleSupport(this);
+
+
+    /**
+     * The MessageDigest object for digesting user credentials (passwords).
+     */
+    protected MessageDigest md = null;
+
+
+    /**
+     * The MD5 helper object for this class.
+     */
+    protected static final MD5Encoder md5Encoder = new MD5Encoder();
+
+
+    /**
+     * MD5 message digest provider.
+     */
+    protected static MessageDigest md5Helper;
+
+
+    /**
+     * The string manager for this package.
+     */
+    protected static StringManager sm =
+        StringManager.getManager(Constants.Package);
+
+
+    /**
+     * Has this component been started?
+     */
+    protected boolean started = false;
+
+
+    /**
+     * The property change support for this component.
+     */
+    protected PropertyChangeSupport support = new PropertyChangeSupport(this);
+
+
+    /**
+     * Should we validate client certificate chains when they are presented?
+     */
+    protected boolean validate = true;
+
+    
+    /**
+     * The all role mode.
+     */
+    protected AllRolesMode allRolesMode = AllRolesMode.STRICT_MODE;
+    
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * Return the Container with which this Realm has been associated.
+     */
+    public Container getContainer() {
+
+        return (container);
+
+    }
+
+
+    /**
+     * Set the Container with which this Realm has been associated.
+     *
+     * @param container The associated Container
+     */
+    public void setContainer(Container container) {
+
+        Container oldContainer = this.container;
+        this.container = container;
+        support.firePropertyChange("container", oldContainer, this.container);
+
+    }
+
+    /**
+     * Return the all roles mode.
+     */
+    public String getAllRolesMode() {
+
+        return allRolesMode.toString();
+
+    }
+
+
+    /**
+     * Set the all roles mode.
+     */
+    public void setAllRolesMode(String allRolesMode) {
+
+        this.allRolesMode = AllRolesMode.toMode(allRolesMode);
+
+    }
+
+    /**
+     * Return the digest algorithm  used for storing credentials.
+     */
+    public String getDigest() {
+
+        return digest;
+
+    }
+
+
+    /**
+     * Set the digest algorithm used for storing credentials.
+     *
+     * @param digest The new digest algorithm
+     */
+    public void setDigest(String digest) {
+
+        this.digest = digest;
+
+    }
+
+    /**
+     * Returns the digest encoding charset.
+     *
+     * @return The charset (may be null) for platform default
+     */
+    public String getDigestEncoding() {
+        return digestEncoding;
+    }
+
+    /**
+     * Sets the digest encoding charset.
+     *
+     * @param charset The charset (null for platform default)
+     */
+    public void setDigestEncoding(String charset) {
+        digestEncoding = charset;
+    }
+
+    /**
+     * Return descriptive information about this Realm implementation and
+     * the corresponding version number, in the format
+     * <code>&lt;description&gt;/&lt;version&gt;</code>.
+     */
+    public String getInfo() {
+
+        return info;
+
+    }
+
+
+    /**
+     * Return the "validate certificate chains" flag.
+     */
+    public boolean getValidate() {
+
+        return (this.validate);
+
+    }
+
+
+    /**
+     * Set the "validate certificate chains" flag.
+     *
+     * @param validate The new validate certificate chains flag
+     */
+    public void setValidate(boolean validate) {
+
+        this.validate = validate;
+
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    
+    /**
+     * Add a property change listener to this component.
+     *
+     * @param listener The listener to add
+     */
+    public void addPropertyChangeListener(PropertyChangeListener listener) {
+
+        support.addPropertyChangeListener(listener);
+
+    }
+
+
+    /**
+     * Return the Principal associated with the specified username and
+     * credentials, if there is one; otherwise return <code>null</code>.
+     *
+     * @param username Username of the Principal to look up
+     * @param credentials Password or other credentials to use in
+     *  authenticating this username
+     */
+    public Principal authenticate(String username, String credentials) {
+
+        String serverCredentials = getPassword(username);
+
+        boolean validated ;
+        if ( serverCredentials == null ) {
+            validated = false;
+        } else if(hasMessageDigest()) {
+            validated = serverCredentials.equalsIgnoreCase(digest(credentials));
+        } else {
+            validated = serverCredentials.equals(credentials);
+        }
+        if(! validated ) {
+            if (containerLog.isTraceEnabled()) {
+                containerLog.trace(sm.getString("realmBase.authenticateFailure",
+                                                username));
+            }
+            return null;
+        }
+        if (containerLog.isTraceEnabled()) {
+            containerLog.trace(sm.getString("realmBase.authenticateSuccess",
+                                            username));
+        }
+
+        return getPrincipal(username);
+    }
+
+
+    /**
+     * Return the Principal associated with the specified username and
+     * credentials, if there is one; otherwise return <code>null</code>.
+     *
+     * @param username Username of the Principal to look up
+     * @param credentials Password or other credentials to use in
+     *  authenticating this username
+     */
+    public Principal authenticate(String username, byte[] credentials) {
+
+        return (authenticate(username, credentials.toString()));
+
+    }
+
+
+    /**
+     * Return the Principal associated with the specified username, which
+     * matches the digest calculated using the given parameters using the
+     * method described in RFC 2069; otherwise return <code>null</code>.
+     *
+     * @param username Username of the Principal to look up
+     * @param clientDigest Digest which has been submitted by the client
+     * @param nOnce Unique (or supposedly unique) token which has been used
+     * for this request
+     * @param realm Realm name
+     * @param md5a2 Second MD5 digest used to calculate the digest :
+     * MD5(Method + ":" + uri)
+     */
+    public Principal authenticate(String username, String clientDigest,
+                                  String nOnce, String nc, String cnonce,
+                                  String qop, String realm,
+                                  String md5a2) {
+
+        String md5a1 = getDigest(username, realm);
+        if (md5a1 == null)
+            return null;
+        String serverDigestValue = md5a1 + ":" + nOnce + ":" + nc + ":"
+            + cnonce + ":" + qop + ":" + md5a2;
+
+        byte[] valueBytes = null;
+        if(getDigestEncoding() == null) {
+            valueBytes = serverDigestValue.getBytes();
+        } else {
+            try {
+                valueBytes = serverDigestValue.getBytes(getDigestEncoding());
+            } catch (UnsupportedEncodingException uee) {
+                log.error("Illegal digestEncoding: " + getDigestEncoding(), uee);
+                throw new IllegalArgumentException(uee.getMessage());
+            }
+        }
+
+        String serverDigest = null;
+        // Bugzilla 32137
+        synchronized(md5Helper) {
+            serverDigest = md5Encoder.encode(md5Helper.digest(valueBytes));
+        }
+
+        if (log.isDebugEnabled()) {
+            log.debug("Digest : " + clientDigest + " Username:" + username 
+                    + " ClientSigest:" + clientDigest + " nOnce:" + nOnce 
+                    + " nc:" + nc + " cnonce:" + cnonce + " qop:" + qop 
+                    + " realm:" + realm + "md5a2:" + md5a2 
+                    + " Server digest:" + serverDigest);
+        }
+        
+        if (serverDigest.equals(clientDigest))
+            return getPrincipal(username);
+        else
+            return null;
+    }
+
+
+
+    /**
+     * Return the Principal associated with the specified chain of X509
+     * client certificates.  If there is none, return <code>null</code>.
+     *
+     * @param certs Array of client certificates, with the first one in
+     *  the array being the certificate of the client itself.
+     */
+    public Principal authenticate(X509Certificate certs[]) {
+
+        if ((certs == null) || (certs.length < 1))
+            return (null);
+
+        // Check the validity of each certificate in the chain
+        if (log.isDebugEnabled())
+            log.debug("Authenticating client certificate chain");
+        if (validate) {
+            for (int i = 0; i < certs.length; i++) {
+                if (log.isDebugEnabled())
+                    log.debug(" Checking validity for '" +
+                        certs[i].getSubjectDN().getName() + "'");
+                try {
+                    certs[i].checkValidity();
+                } catch (Exception e) {
+                    if (log.isDebugEnabled())
+                        log.debug("  Validity exception", e);
+                    return (null);
+                }
+            }
+        }
+
+        // Check the existence of the client Principal in our database
+        return (getPrincipal(certs[0]));
+
+    }
+
+    
+    /**
+     * Execute a periodic task, such as reloading, etc. This method will be
+     * invoked inside the classloading context of this container. Unexpected
+     * throwables will be caught and logged.
+     */
+    public void backgroundProcess() {
+    }
+
+
+    /**
+     * Return the SecurityConstraints configured to guard the request URI for
+     * this request, or <code>null</code> if there is no such constraint.
+     *
+     * @param request Request we are processing
+     * @param context Context the Request is mapped to
+     */
+    public SecurityConstraint [] findSecurityConstraints(Request request,
+                                                         Context context) {
+
+        ArrayList results = null;
+        // Are there any defined security constraints?
+        SecurityConstraint constraints[] = context.findConstraints();
+        if ((constraints == null) || (constraints.length == 0)) {
+            if (log.isDebugEnabled())
+                log.debug("  No applicable constraints defined");
+            return (null);
+        }
+
+        // Check each defined security constraint
+        String uri = request.getRequestPathMB().toString();
+        
+        String method = request.getMethod();
+        int i;
+        boolean found = false;
+        for (i = 0; i < constraints.length; i++) {
+            SecurityCollection [] collection = constraints[i].findCollections();
+                     
+            // If collection is null, continue to avoid an NPE
+            // See Bugzilla 30624
+            if ( collection == null) {
+		continue;
+            }
+
+            if (log.isDebugEnabled()) {
+                log.debug("  Checking constraint '" + constraints[i] +
+                    "' against " + method + " " + uri + " --> " +
+                    constraints[i].included(uri, method));
+	    }
+
+            for(int j=0; j < collection.length; j++){
+                String [] patterns = collection[j].findPatterns();
+ 
+                // If patterns is null, continue to avoid an NPE
+                // See Bugzilla 30624
+                if ( patterns == null) {
+		    continue;
+                }
+
+                for(int k=0; k < patterns.length; k++) {
+                    if(uri.equals(patterns[k])) {
+                        found = true;
+                        if(collection[j].findMethod(method)) {
+                            if(results == null) {
+                                results = new ArrayList();
+                            }
+                            results.add(constraints[i]);
+                        }
+                    }
+                }
+            }
+        }
+
+        if(found) {
+            return resultsToArray(results);
+        }
+
+        int longest = -1;
+
+        for (i = 0; i < constraints.length; i++) {
+            SecurityCollection [] collection = constraints[i].findCollections();
+            
+            // If collection is null, continue to avoid an NPE
+            // See Bugzilla 30624
+            if ( collection == null) {
+		continue;
+            }
+
+            if (log.isDebugEnabled()) {
+                log.debug("  Checking constraint '" + constraints[i] +
+                    "' against " + method + " " + uri + " --> " +
+                    constraints[i].included(uri, method));
+	    }
+
+            for(int j=0; j < collection.length; j++){
+                String [] patterns = collection[j].findPatterns();
+
+                // If patterns is null, continue to avoid an NPE
+                // See Bugzilla 30624
+                if ( patterns == null) {
+		    continue;
+                }
+
+                boolean matched = false;
+                int length = -1;
+                for(int k=0; k < patterns.length; k++) {
+                    String pattern = patterns[k];
+                    if(pattern.startsWith("/") && pattern.endsWith("/*") && 
+                       pattern.length() >= longest) {
+                            
+                        if(pattern.length() == 2) {
+                            matched = true;
+                            length = pattern.length();
+                        } else if(pattern.regionMatches(0,uri,0,
+                                                        pattern.length()-1) ||
+                                  (pattern.length()-2 == uri.length() &&
+                                   pattern.regionMatches(0,uri,0,
+                                                        pattern.length()-2))) {
+                            matched = true;
+                            length = pattern.length();
+                        }
+                    }
+                }
+                if(matched) {
+                    found = true;
+                    if(length > longest) {
+                        if(results != null) {
+                            results.clear();
+                        }
+                        longest = length;
+                    }
+                    if(collection[j].findMethod(method)) {
+                        if(results == null) {
+                            results = new ArrayList();
+                        }
+                        results.add(constraints[i]);
+                    }
+                }
+            }
+        }
+
+        if(found) {
+            return  resultsToArray(results);
+        }
+
+        for (i = 0; i < constraints.length; i++) {
+            SecurityCollection [] collection = constraints[i].findCollections();
+
+            // If collection is null, continue to avoid an NPE
+            // See Bugzilla 30624
+            if ( collection == null) {
+		continue;
+            }
+            
+            if (log.isDebugEnabled()) {
+                log.debug("  Checking constraint '" + constraints[i] +
+                    "' against " + method + " " + uri + " --> " +
+                    constraints[i].included(uri, method));
+	    }
+
+            boolean matched = false;
+            int pos = -1;
+            for(int j=0; j < collection.length; j++){
+                String [] patterns = collection[j].findPatterns();
+
+                // If patterns is null, continue to avoid an NPE
+                // See Bugzilla 30624
+                if ( patterns == null) {
+		    continue;
+                }
+
+                for(int k=0; k < patterns.length && !matched; k++) {
+                    String pattern = patterns[k];
+                    if(pattern.startsWith("*.")){
+                        int slash = uri.lastIndexOf("/");
+                        int dot = uri.lastIndexOf(".");
+                        if(slash >= 0 && dot > slash &&
+                           dot != uri.length()-1 &&
+                           uri.length()-dot == pattern.length()-1) {
+                            if(pattern.regionMatches(1,uri,dot,uri.length()-dot)) {
+                                matched = true;
+                                pos = j;
+                            }
+                        }
+                    }
+                }
+            }
+            if(matched) {
+                found = true;
+                if(collection[pos].findMethod(method)) {
+                    if(results == null) {
+                        results = new ArrayList();
+                    }
+                    results.add(constraints[i]);
+                }
+            }
+        }
+
+        if(found) {
+            return resultsToArray(results);
+        }
+
+        for (i = 0; i < constraints.length; i++) {
+            SecurityCollection [] collection = constraints[i].findCollections();
+            
+            // If collection is null, continue to avoid an NPE
+            // See Bugzilla 30624
+            if ( collection == null) {
+		continue;
+            }
+
+            if (log.isDebugEnabled()) {
+                log.debug("  Checking constraint '" + constraints[i] +
+                    "' against " + method + " " + uri + " --> " +
+                    constraints[i].included(uri, method));
+	    }
+
+            for(int j=0; j < collection.length; j++){
+                String [] patterns = collection[j].findPatterns();
+
+                // If patterns is null, continue to avoid an NPE
+                // See Bugzilla 30624
+                if ( patterns == null) {
+		    continue;
+                }
+
+                boolean matched = false;
+                for(int k=0; k < patterns.length && !matched; k++) {
+                    String pattern = patterns[k];
+                    if(pattern.equals("/")){
+                        matched = true;
+                    }
+                }
+                if(matched) {
+                    if(results == null) {
+                        results = new ArrayList();
+                    }                    
+                    results.add(constraints[i]);
+                }
+            }
+        }
+
+        if(results == null) {
+            // No applicable security constraint was found
+            if (log.isDebugEnabled())
+                log.debug("  No applicable constraint located");
+        }
+        return resultsToArray(results);
+    }
+ 
+    /**
+     * Convert an ArrayList to a SecurityContraint [].
+     */
+    private SecurityConstraint [] resultsToArray(ArrayList results) {
+        if(results == null) {
+            return null;
+        }
+        SecurityConstraint [] array = new SecurityConstraint[results.size()];
+        results.toArray(array);
+        return array;
+    }
+
+    
+    /**
+     * Perform access control based on the specified authorization constraint.
+     * Return <code>true</code> if this constraint is satisfied and processing
+     * should continue, or <code>false</code> otherwise.
+     *
+     * @param request Request we are processing
+     * @param response Response we are creating
+     * @param constraints Security constraint we are enforcing
+     * @param context The Context to which client of this class is attached.
+     *
+     * @exception IOException if an input/output error occurs
+     */
+    public boolean hasResourcePermission(Request request,
+                                         Response response,
+                                         SecurityConstraint []constraints,
+                                         Context context)
+        throws IOException {
+
+        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;
+        boolean denyfromall = false;
+        for(int i=0; i < constraints.length; i++) {
+            SecurityConstraint constraint = constraints[i];
+
+            String roles[];
+            if (constraint.getAllRoles()) {
+                // * means all roles defined in web.xml
+                roles = request.getContext().findSecurityRoles();
+            } else {
+                roles = constraint.findAuthRoles();
+            }
+
+            if (roles == null)
+                roles = new String[0];
+
+            if (log.isDebugEnabled())
+                log.debug("  Checking roles " + principal);
+
+            if (roles.length == 0 && !constraint.getAllRoles()) {
+                if(constraint.getAuthConstraint()) {
+                    if( log.isDebugEnabled() )
+                        log.debug("No roles ");
+                    status = false; // No listed roles means no access at all
+                    denyfromall = true;
+                } else {
+                    if(log.isDebugEnabled())
+                        log.debug("Passing all access");
+                    return (true);
+                }
+            } else if (principal == null) {
+                if (log.isDebugEnabled())
+                    log.debug("  No user authenticated, cannot grant access");
+                status = false;
+            } else if(!denyfromall) {
+
+                for (int j = 0; j < roles.length; j++) {
+                    if (hasRole(principal, roles[j]))
+                        status = true;
+                    if( log.isDebugEnabled() )
+                        log.debug( "No role found:  " + roles[j]);
+                }
+            }
+        }
+
+        if (allRolesMode != AllRolesMode.STRICT_MODE && !status && principal != null) {
+            if (log.isDebugEnabled()) {
+                log.debug("Checking for all roles mode: " + allRolesMode);
+            }
+            // Check for an all roles(role-name="*")
+            for (int i = 0; i < constraints.length; i++) {
+                SecurityConstraint constraint = constraints[i];
+                String roles[];
+                // If the all roles mode exists, sets
+                if (constraint.getAllRoles()) {
+                    if (allRolesMode == AllRolesMode.AUTH_ONLY_MODE) {
+                        if (log.isDebugEnabled()) {
+                            log.debug("Granting access for role-name=*, auth-only");
+                        }
+                        status = true;
+                        break;
+                    }
+                    
+                    // For AllRolesMode.STRICT_AUTH_ONLY_MODE there must be zero roles
+                    roles = request.getContext().findSecurityRoles();
+                    if (roles.length == 0 && allRolesMode == AllRolesMode.STRICT_AUTH_ONLY_MODE) {
+                        if (log.isDebugEnabled()) {
+                            log.debug("Granting access for role-name=*, strict auth-only");
+                        }
+                        status = true;
+                        break;
+                    }
+                }
+            }
+        }
+        
+        // Return a "Forbidden" message denying access to this resource
+        if(!status) {
+            response.sendError
+                (HttpServletResponse.SC_FORBIDDEN,
+                 sm.getString("realmBase.forbidden"));
+        }
+        return status;
+
+    }
+    
+    
+    /**
+     * Return <code>true</code> if the specified Principal has the specified
+     * security role, within the context of this Realm; otherwise return
+     * <code>false</code>.  This method can be overridden by Realm
+     * implementations, but the default is adequate when an instance of
+     * <code>GenericPrincipal</code> is used to represent authenticated
+     * Principals from this Realm.
+     *
+     * @param principal Principal for whom the role is to be checked
+     * @param role Security role to be checked
+     */
+    public boolean hasRole(Principal principal, String role) {
+
+        // Should be overriten in JAASRealm - to avoid pretty inefficient conversions
+        if ((principal == null) || (role == null) ||
+            !(principal instanceof GenericPrincipal))
+            return (false);
+
+        GenericPrincipal gp = (GenericPrincipal) principal;
+        if (!(gp.getRealm() == this)) {
+            if(log.isDebugEnabled())
+                log.debug("Different realm " + this + " " + gp.getRealm());//    return (false);
+        }
+        boolean result = gp.hasRole(role);
+        if (log.isDebugEnabled()) {
+            String name = principal.getName();
+            if (result)
+                log.debug(sm.getString("realmBase.hasRoleSuccess", name, role));
+            else
+                log.debug(sm.getString("realmBase.hasRoleFailure", name, role));
+        }
+        return (result);
+
+    }
+
+    
+    /**
+     * Enforce any user data constraint required by the security constraint
+     * guarding this request URI.  Return <code>true</code> if this constraint
+     * was not violated and processing should continue, or <code>false</code>
+     * if we have created a response already.
+     *
+     * @param request Request we are processing
+     * @param response Response we are creating
+     * @param constraints Security constraint being checked
+     *
+     * @exception IOException if an input/output error occurs
+     */
+    public boolean hasUserDataPermission(Request request,
+                                         Response response,
+                                         SecurityConstraint []constraints)
+        throws IOException {
+
+        // Is there a relevant user data constraint?
+        if (constraints == null || constraints.length == 0) {
+            if (log.isDebugEnabled())
+                log.debug("  No applicable security constraint defined");
+            return (true);
+        }
+        for(int i=0; i < constraints.length; i++) {
+            SecurityConstraint constraint = constraints[i];
+            String userConstraint = constraint.getUserConstraint();
+            if (userConstraint == null) {
+                if (log.isDebugEnabled())
+                    log.debug("  No applicable user data constraint defined");
+                return (true);
+            }
+            if (userConstraint.equals(Constants.NONE_TRANSPORT)) {
+                if (log.isDebugEnabled())
+                    log.debug("  User data constraint has no restrictions");
+                return (true);
+            }
+
+        }
+        // Validate the request against the user data constraint
+        if (request.getRequest().isSecure()) {
+            if (log.isDebugEnabled())
+                log.debug("  User data constraint already satisfied");
+            return (true);
+        }
+        // Initialize variables we need to determine the appropriate action
+        int redirectPort = request.getConnector().getRedirectPort();
+
+        // Is redirecting disabled?
+        if (redirectPort <= 0) {
+            if (log.isDebugEnabled())
+                log.debug("  SSL redirect is disabled");
+            response.sendError
+                (HttpServletResponse.SC_FORBIDDEN,
+                 request.getRequestURI());
+            return (false);
+        }
+
+        // Redirect to the corresponding SSL port
+        StringBuffer file = new StringBuffer();
+        String protocol = "https";
+        String host = request.getServerName();
+        // Protocol
+        file.append(protocol).append("://").append(host);
+        // Host with port
+        if(redirectPort != 443) {
+            file.append(":").append(redirectPort);
+        }
+        // URI
+        file.append(request.getRequestURI());
+        String requestedSessionId = request.getRequestedSessionId();
+        if ((requestedSessionId != null) &&
+            request.isRequestedSessionIdFromURL()) {
+            file.append(";jsessionid=");
+            file.append(requestedSessionId);
+        }
+        String queryString = request.getQueryString();
+        if (queryString != null) {
+            file.append('?');
+            file.append(queryString);
+        }
+        if (log.isDebugEnabled())
+            log.debug("  Redirecting to " + file.toString());
+        response.sendRedirect(file.toString());
+        return (false);
+
+    }
+    
+    
+    /**
+     * Remove a property change listener from this component.
+     *
+     * @param listener The listener to remove
+     */
+    public void removePropertyChangeListener(PropertyChangeListener listener) {
+
+        support.removePropertyChangeListener(listener);
+
+    }
+
+
+    // ------------------------------------------------------ Lifecycle Methods
+
+
+    /**
+     * Add a lifecycle event listener to this component.
+     *
+     * @param listener The listener to add
+     */
+    public void addLifecycleListener(LifecycleListener listener) {
+
+        lifecycle.addLifecycleListener(listener);
+
+    }
+
+
+    /**
+     * Get the lifecycle listeners associated with this lifecycle. If this 
+     * Lifecycle has no listeners registered, a zero-length array is returned.
+     */
+    public LifecycleListener[] findLifecycleListeners() {
+
+        return lifecycle.findLifecycleListeners();
+
+    }
+
+
+    /**
+     * Remove a lifecycle event listener from this component.
+     *
+     * @param listener The listener to remove
+     */
+    public void removeLifecycleListener(LifecycleListener listener) {
+
+        lifecycle.removeLifecycleListener(listener);
+
+    }
+
+    /**
+     * Prepare for the beginning of active use of the public methods of this
+     * component.  This method should be called before any of the public
+     * methods of this component are utilized.  It should also send a
+     * LifecycleEvent of type START_EVENT to any registered listeners.
+     *
+     * @exception LifecycleException if this component detects a fatal error
+     *  that prevents this component from being used
+     */
+    public void start() throws LifecycleException {
+
+        // Validate and update our current component state
+        if (started) {
+            if(log.isInfoEnabled())
+                log.info(sm.getString("realmBase.alreadyStarted"));
+            return;
+        }
+        if( !initialized ) {
+            init();
+        }
+        lifecycle.fireLifecycleEvent(START_EVENT, null);
+        started = true;
+
+        // Create a MessageDigest instance for credentials, if desired
+        if (digest != null) {
+            try {
+                md = MessageDigest.getInstance(digest);
+            } catch (NoSuchAlgorithmException e) {
+                throw new LifecycleException
+                    (sm.getString("realmBase.algorithm", digest), e);
+            }
+        }
+
+    }
+
+
+    /**
+     * Gracefully terminate the active use of the public methods of this
+     * component.  This method should be the last one called on a given
+     * instance of this component.  It should also send a LifecycleEvent
+     * of type STOP_EVENT to any registered listeners.
+     *
+     * @exception LifecycleException if this component detects a fatal error
+     *  that needs to be reported
+     */
+    public void stop()
+        throws LifecycleException {
+
+        // Validate and update our current component state
+        if (!started) {
+            if(log.isInfoEnabled())
+                log.info(sm.getString("realmBase.notStarted"));
+            return;
+        }
+        lifecycle.fireLifecycleEvent(STOP_EVENT, null);
+        started = false;
+
+        // Clean up allocated resources
+        md = null;
+        
+        destroy();
+    
+    }
+    
+    public void destroy() {
+    
+        // unregister this realm
+        if ( oname!=null ) {   
+            try {   
+                Registry.getRegistry(null, null).unregisterComponent(oname); 
+                if(log.isDebugEnabled())
+                    log.debug( "unregistering realm " + oname );   
+            } catch( Exception ex ) {   
+                log.error( "Can't unregister realm " + oname, ex);   
+            }      
+        }
+          
+    }
+
+    // ------------------------------------------------------ Protected Methods
+
+
+    /**
+     * Digest the password using the specified algorithm and
+     * convert the result to a corresponding hexadecimal string.
+     * If exception, the plain credentials string is returned.
+     *
+     * @param credentials Password or other credentials to use in
+     *  authenticating this username
+     */
+    protected String digest(String credentials)  {
+
+        // If no MessageDigest instance is specified, return unchanged
+        if (hasMessageDigest() == false)
+            return (credentials);
+
+        // Digest the user credentials and return as hexadecimal
+        synchronized (this) {
+            try {
+                md.reset();
+    
+                byte[] bytes = null;
+                if(getDigestEncoding() == null) {
+                    bytes = credentials.getBytes();
+                } else {
+                    try {
+                        bytes = credentials.getBytes(getDigestEncoding());
+                    } catch (UnsupportedEncodingException uee) {
+                        log.error("Illegal digestEncoding: " + getDigestEncoding(), uee);
+                        throw new IllegalArgumentException(uee.getMessage());
+                    }
+                }
+                md.update(bytes);
+
+                return (HexUtils.convert(md.digest()));
+            } catch (Exception e) {
+                log.error(sm.getString("realmBase.digest"), e);
+                return (credentials);
+            }
+        }
+
+    }
+
+    protected boolean hasMessageDigest() {
+        return !(md == null);
+    }
+
+    /**
+     * Return the digest associated with given principal's user name.
+     */
+    protected String getDigest(String username, String realmName) {
+        if (md5Helper == null) {
+            try {
+                md5Helper = MessageDigest.getInstance("MD5");
+            } catch (NoSuchAlgorithmException e) {
+                log.error("Couldn't get MD5 digest: ", e);
+                throw new IllegalStateException(e.getMessage());
+            }
+        }
+
+    	if (hasMessageDigest()) {
+    		// Use pre-generated digest
+    		return getPassword(username);
+    	}
+    	
+        String digestValue = username + ":" + realmName + ":"
+            + getPassword(username);
+
+        byte[] valueBytes = null;
+        if(getDigestEncoding() == null) {
+            valueBytes = digestValue.getBytes();
+        } else {
+            try {
+                valueBytes = digestValue.getBytes(getDigestEncoding());
+            } catch (UnsupportedEncodingException uee) {
+                log.error("Illegal digestEncoding: " + getDigestEncoding(), uee);
+                throw new IllegalArgumentException(uee.getMessage());
+            }
+        }
+
+        byte[] digest = null;
+        // Bugzilla 32137
+        synchronized(md5Helper) {
+            digest = md5Helper.digest(valueBytes);
+        }
+
+        return md5Encoder.encode(digest);
+    }
+
+
+    /**
+     * Return a short name for this Realm implementation, for use in
+     * log messages.
+     */
+    protected abstract String getName();
+
+
+    /**
+     * Return the password associated with the given principal's user name.
+     */
+    protected abstract String getPassword(String username);
+
+
+    /**
+     * Return the Principal associated with the given certificate.
+     */
+    protected Principal getPrincipal(X509Certificate usercert) {
+        return(getPrincipal(usercert.getSubjectDN().getName()));
+    }
+    
+
+    /**
+     * Return the Principal associated with the given user name.
+     */
+    protected abstract Principal getPrincipal(String username);
+
+
+    // --------------------------------------------------------- Static Methods
+
+
+    /**
+     * Digest password using the algorithm especificied and
+     * convert the result to a corresponding hex string.
+     * If exception, the plain credentials string is returned
+     *
+     * @param credentials Password or other credentials to use in
+     *  authenticating this username
+     * @param algorithm Algorithm used to do the digest
+     * @param encoding Character encoding of the string to digest
+     */
+    public final static String Digest(String credentials, String algorithm,
+                                      String encoding) {
+
+        try {
+            // Obtain a new message digest with "digest" encryption
+            MessageDigest md =
+                (MessageDigest) MessageDigest.getInstance(algorithm).clone();
+
+            // encode the credentials
+            // Should use the digestEncoding, but that's not a static field
+            if (encoding == null) {
+                md.update(credentials.getBytes());
+            } else {
+                md.update(credentials.getBytes(encoding));                
+            }
+
+            // Digest the credentials and return as hexadecimal
+            return (HexUtils.convert(md.digest()));
+        } catch(Exception ex) {
+            log.error(ex);
+            return credentials;
+        }
+
+    }
+
+
+    /**
+     * Digest password using the algorithm especificied and
+     * convert the result to a corresponding hex string.
+     * If exception, the plain credentials string is returned
+     */
+    public static void main(String args[]) {
+
+        String encoding = null;
+        int firstCredentialArg = 2;
+        
+        if (args.length > 4 && args[2].equalsIgnoreCase("-e")) {
+            encoding = args[3];
+            firstCredentialArg = 4;
+        }
+        
+        if(args.length > firstCredentialArg && args[0].equalsIgnoreCase("-a")) {
+            for(int i=firstCredentialArg; i < args.length ; i++){
+                System.out.print(args[i]+":");
+                System.out.println(Digest(args[i], args[1], encoding));
+            }
+        } else {
+            System.out.println
+                ("Usage: RealmBase -a <algorithm> [-e <encoding>] <credentials>");
+        }
+
+    }
+
+
+    // -------------------- JMX and Registration  --------------------
+    protected String type;
+    protected String domain;
+    protected String host;
+    protected String path;
+    protected ObjectName oname;
+    protected ObjectName controller;
+    protected MBeanServer mserver;
+
+    public ObjectName getController() {
+        return controller;
+    }
+
+    public void setController(ObjectName controller) {
+        this.controller = controller;
+    }
+
+    public ObjectName getObjectName() {
+        return oname;
+    }
+
+    public String getDomain() {
+        return domain;
+    }
+
+    public String getType() {
+        return type;
+    }
+
+    public ObjectName preRegister(MBeanServer server,
+                                  ObjectName name) throws Exception {
+        oname=name;
+        mserver=server;
+        domain=name.getDomain();
+
+        type=name.getKeyProperty("type");
+        host=name.getKeyProperty("host");
+        path=name.getKeyProperty("path");
+
+        return name;
+    }
+
+    public void postRegister(Boolean registrationDone) {
+    }
+
+    public void preDeregister() throws Exception {
+    }
+
+    public void postDeregister() {
+    }
+
+    protected boolean initialized=false;
+    
+    public void init() {
+        this.containerLog = container.getLogger();
+        if( initialized && container != null ) return;
+        
+        initialized=true;
+        if( container== null ) {
+            ObjectName parent=null;
+            // Register with the parent
+            try {
+                if( host == null ) {
+                    // global
+                    parent=new ObjectName(domain +":type=Engine");
+                } else if( path==null ) {
+                    parent=new ObjectName(domain +
+                            ":type=Host,host=" + host);
+                } else {
+                    parent=new ObjectName(domain +":j2eeType=WebModule,name=//" +
+                            host + path);
+                }
+                if( mserver.isRegistered(parent ))  {
+                    if(log.isDebugEnabled())
+                        log.debug("Register with " + parent);
+                    mserver.setAttribute(parent, new Attribute("realm", this));
+                }
+            } catch (Exception e) {
+                log.error("Parent not available yet: " + parent);  
+            }
+        }
+        
+        if( oname==null ) {
+            // register
+            try {
+                ContainerBase cb=(ContainerBase)container;
+                oname=new ObjectName(cb.getDomain()+":type=Realm" + cb.getContainerSuffix());
+                Registry.getRegistry(null, null).registerComponent(this, oname, null );
+                if(log.isDebugEnabled())
+                    log.debug("Register Realm "+oname);
+            } catch (Throwable e) {
+                log.error( "Can't register " + oname, e);
+            }
+        }
+
+    }
+
+
+    protected static class AllRolesMode {
+        
+        private String name;
+        /** Use the strict servlet spec interpretation which requires that the user
+         * have one of the web-app/security-role/role-name 
+         */
+        public static final AllRolesMode STRICT_MODE = new AllRolesMode("strict");
+        /** Allow any authenticated user
+         */
+        public static final AllRolesMode AUTH_ONLY_MODE = new AllRolesMode("authOnly");
+        /** Allow any authenticated user only if there are no web-app/security-roles
+         */
+        public static final AllRolesMode STRICT_AUTH_ONLY_MODE = new AllRolesMode("strictAuthOnly");
+        
+        static AllRolesMode toMode(String name)
+        {
+            AllRolesMode mode;
+            if( name.equalsIgnoreCase(STRICT_MODE.name) )
+                mode = STRICT_MODE;
+            else if( name.equalsIgnoreCase(AUTH_ONLY_MODE.name) )
+                mode = AUTH_ONLY_MODE;
+            else if( name.equalsIgnoreCase(STRICT_AUTH_ONLY_MODE.name) )
+                mode = STRICT_AUTH_ONLY_MODE;
+            else
+                throw new IllegalStateException("Unknown mode, must be one of: strict, authOnly, strictAuthOnly");
+            return mode;
+        }
+        
+        private AllRolesMode(String name)
+        {
+            this.name = name;
+        }
+        
+        public boolean equals(Object o)
+        {
+            boolean equals = false;
+            if( o instanceof AllRolesMode )
+            {
+                AllRolesMode mode = (AllRolesMode) o;
+                equals = name.equals(mode.name);
+            }
+            return equals;
+        }
+        public int hashCode()
+        {
+            return name.hashCode();
+        }
+        public String toString()
+        {
+            return name;
+        }
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/realm/UserDatabaseRealm.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/realm/UserDatabaseRealm.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/realm/UserDatabaseRealm.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,284 @@
+/*
+ * Copyright 2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.realm;
+
+
+import java.security.Principal;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import javax.naming.Context;
+
+import org.apache.catalina.Group;
+import org.apache.catalina.LifecycleException;
+import org.apache.catalina.Role;
+import org.apache.catalina.ServerFactory;
+import org.apache.catalina.User;
+import org.apache.catalina.UserDatabase;
+import org.apache.catalina.core.StandardServer;
+import org.apache.catalina.util.StringManager;
+
+
+/**
+ * <p>Implementation of {@link org.apache.catalina.Realm} that is based on an implementation of
+ * {@link UserDatabase} made available through the global JNDI resources
+ * configured for this instance of Catalina.  Set the <code>resourceName</code>
+ * parameter to the global JNDI resources name for the configured instance
+ * of <code>UserDatabase</code> that we should consult.</p>
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 441855 $ $Date: 2006-09-09 16:09:49 -0500 (Sat, 09 Sep 2006) $
+ * @since 4.1
+ */
+
+public class UserDatabaseRealm
+    extends RealmBase {
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The <code>UserDatabase</code> we will use to authenticate users
+     * and identify associated roles.
+     */
+    protected UserDatabase database = null;
+
+
+    /**
+     * Descriptive information about this Realm implementation.
+     */
+    protected final String info =
+        "org.apache.catalina.realm.UserDatabaseRealm/1.0";
+
+
+    /**
+     * Descriptive information about this Realm implementation.
+     */
+    protected static final String name = "UserDatabaseRealm";
+
+
+    /**
+     * The global JNDI name of the <code>UserDatabase</code> resource
+     * we will be utilizing.
+     */
+    protected String resourceName = "UserDatabase";
+
+
+    /**
+     * The string manager for this package.
+     */
+    private static StringManager sm =
+        StringManager.getManager(Constants.Package);
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * Return descriptive information about this Realm implementation and
+     * the corresponding version number, in the format
+     * <code>&lt;description&gt;/&lt;version&gt;</code>.
+     */
+    public String getInfo() {
+
+        return info;
+
+    }
+
+
+    /**
+     * Return the global JNDI name of the <code>UserDatabase</code> resource
+     * we will be using.
+     */
+    public String getResourceName() {
+
+        return resourceName;
+
+    }
+
+
+    /**
+     * Set the global JNDI name of the <code>UserDatabase</code> resource
+     * we will be using.
+     *
+     * @param resourceName The new global JNDI name
+     */
+    public void setResourceName(String resourceName) {
+
+        this.resourceName = resourceName;
+
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Return <code>true</code> if the specified Principal has the specified
+     * security role, within the context of this Realm; otherwise return
+     * <code>false</code>. This implementation returns <code>true</code>
+     * if the <code>User</code> has the role, or if any <code>Group</code>
+     * that the <code>User</code> is a member of has the role. 
+     *
+     * @param principal Principal for whom the role is to be checked
+     * @param role Security role to be checked
+     */
+    public boolean hasRole(Principal principal, String role) {
+        if( principal instanceof GenericPrincipal) {
+            GenericPrincipal gp = (GenericPrincipal)principal;
+            if(gp.getUserPrincipal() instanceof User) {
+                principal = gp.getUserPrincipal();
+            }
+        }
+        if(! (principal instanceof User) ) {
+            //Play nice with SSO and mixed Realms
+            return super.hasRole(principal, role);
+        }
+        if("*".equals(role)) {
+            return true;
+        } else if(role == null) {
+            return false;
+        }
+        User user = (User)principal;
+        Role dbrole = database.findRole(role);
+        if(dbrole == null) {
+            return false; 
+        }
+        if(user.isInRole(dbrole)) {
+            return true;
+        }
+        Iterator groups = user.getGroups();
+        while(groups.hasNext()) {
+            Group group = (Group)groups.next();
+            if(group.isInRole(dbrole)) {
+                return true;
+            }
+        }
+        return false;
+    }
+		
+    // ------------------------------------------------------ Protected Methods
+
+
+    /**
+     * Return a short name for this Realm implementation.
+     */
+    protected String getName() {
+
+        return (name);
+
+    }
+
+
+    /**
+     * Return the password associated with the given principal's user name.
+     */
+    protected String getPassword(String username) {
+
+        User user = database.findUser(username);
+
+        if (user == null) {
+            return null;
+        } 
+
+        return (user.getPassword());
+
+    }
+
+
+    /**
+     * Return the Principal associated with the given user name.
+     */
+    protected Principal getPrincipal(String username) {
+
+        User user = database.findUser(username);
+        if(user == null) {
+            return null;
+        }
+
+        List roles = new ArrayList();
+        Iterator uroles = user.getRoles();
+        while(uroles.hasNext()) {
+            Role role = (Role)uroles.next();
+            roles.add(role.getName());
+        }
+        Iterator groups = user.getGroups();
+        while(groups.hasNext()) {
+            Group group = (Group)groups.next();
+            uroles = group.getRoles();
+            while(uroles.hasNext()) {
+                Role role = (Role)uroles.next();
+                roles.add(role.getName());
+            }
+        }
+        return new GenericPrincipal(this, username, user.getPassword(), roles, user);
+    }
+
+
+    // ------------------------------------------------------ Lifecycle Methods
+
+
+    /**
+     * Prepare for active use of the public methods of this Component.
+     *
+     * @exception LifecycleException if this component detects a fatal error
+     *  that prevents it from being started
+     */
+    public synchronized void start() throws LifecycleException {
+
+        // Perform normal superclass initialization
+        super.start();
+
+        try {
+            StandardServer server = (StandardServer) ServerFactory.getServer();
+            Context context = server.getGlobalNamingContext();
+            database = (UserDatabase) context.lookup(resourceName);
+        } catch (Throwable e) {
+            containerLog.error(sm.getString("userDatabaseRealm.lookup",
+                                            resourceName),
+                               e);
+            database = null;
+        }
+        if (database == null) {
+            throw new LifecycleException
+                (sm.getString("userDatabaseRealm.noDatabase", resourceName));
+        }
+
+    }
+
+
+    /**
+     * Gracefully shut down active use of the public methods of this Component.
+     *
+     * @exception LifecycleException if this component detects a fatal error
+     *  that needs to be reported
+     */
+    public synchronized void stop() throws LifecycleException {
+
+        // Perform normal superclass finalization
+        super.stop();
+
+        // Release reference to our user database
+        database = null;
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/realm/mbeans-descriptors.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/realm/mbeans-descriptors.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/realm/mbeans-descriptors.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,298 @@
+<?xml version="1.0"?>
+<mbeans-descriptors>
+
+  <mbean         name="DataSourceRealm"
+            className="org.apache.catalina.mbeans.ClassNameMBean"
+          description="Implementation of Realm that works with any JNDI configured DataSource"
+               domain="Catalina"
+                group="Realm"
+                 type="org.apache.catalina.realm.DataSourceRealm">
+
+    <attribute   name="className"
+          description="Fully qualified class name of the managed object"
+                 type="java.lang.String"
+            writeable="false"/>
+
+    <attribute   name="dataSourceName"
+          description="The JNDI named JDBC DataSource for your database"
+                 type="java.lang.String"/>
+
+    <attribute   name="digest"
+          description="Digest algorithm used in storing passwords in a
+                        non-plaintext format"
+                 type="java.lang.String"/>
+
+    <attribute   name="localDataSource"
+          description="Configures if the DataSource is local to the webapp"
+                 type="boolean"/>
+
+    <attribute   name="roleNameCol"
+          description="The column in the user role table that names a role"
+                 type="java.lang.String"/>
+
+    <attribute   name="userCredCol"
+          description="The column in the user table that holds the user's
+                        credentials"
+                 type="java.lang.String"/>
+
+    <attribute   name="userNameCol"
+          description="The column in the user table that holds the user's
+                        username"
+                 type="java.lang.String"/>
+
+    <attribute   name="userRoleTable"
+          description="The table that holds the relation between user's and
+                        roles"
+                 type="java.lang.String"/>
+
+    <attribute   name="userTable"
+          description="The table that holds user data"
+                 type="java.lang.String"/>
+
+
+    <operation name="start" description="Start" impact="ACTION" returnType="void" />
+    <operation name="stop" description="Stop" impact="ACTION" returnType="void" />
+    <operation name="init" description="Init" impact="ACTION" returnType="void" />
+    <operation name="destroy" description="Destroy" impact="ACTION" returnType="void" />
+
+  </mbean>
+
+  <mbean         name="JAASRealm"
+          description="Implmentation of Realm that authenticates users via the
+                       Java Authentication and Authorization Service (JAAS)"
+               domain="Catalina"
+                group="Realm"
+                 type="org.apache.catalina.realm.JAASRealm">
+
+    <attribute   name="appName"
+          description="The application name passed to the JAAS LoginContext,
+                       which uses it to select the set of relevant
+                       LoginModules"
+                 type="java.lang.String"/>
+
+    <attribute   name="className"
+          description="Fully qualified class name of the managed object"
+                 type="java.lang.String"
+            writeable="false"/>
+
+    <attribute   name="digest"
+          description="Digest algorithm used in storing passwords in a
+                       non-plaintext format"
+                 type="java.lang.String"/>
+
+    <attribute   name="roleClassNames"
+          description="Comma-delimited list of javax.security.Principal classes
+                       that represent security roles"
+                 type="java.lang.String"/>
+
+    <attribute   name="userClassNames"
+          description="Comma-delimited list of javax.security.Principal classes
+                       that represent individual users"
+                 type="java.lang.String"/>
+
+    <attribute   name="validate"
+          description="Should we validate client certificate chains when they
+                       are presented?"
+                 type="java.lang.String"/>
+
+
+    <operation name="start" description="Start" impact="ACTION" returnType="void" />
+    <operation name="stop" description="Stop" impact="ACTION" returnType="void" />
+    <operation name="init" description="Init" impact="ACTION" returnType="void" />
+    <operation name="destroy" description="Destroy" impact="ACTION" returnType="void" />
+  </mbean>
+
+
+  <mbean         name="JDBCRealm"
+          description="Implementation of Realm that works with any JDBC
+                       supported database"
+               domain="Catalina"
+                group="Realm"
+                 type="org.apache.catalina.realm.JDBCRealm">
+
+    <attribute   name="className"
+          description="Fully qualified class name of the managed object"
+                 type="java.lang.String"
+            writeable="false"/>
+
+    <attribute   name="connectionName"
+          description="The connection username to use when trying to connect to
+                       the database"
+                 type="java.lang.String"/>
+
+    <attribute   name="connectionPassword"
+          description="The connection URL to use when trying to connect to the
+                       database"
+                 type="java.lang.String"/>
+
+    <attribute   name="connectionURL"
+          description="The connection URL to use when trying to connect to the
+                       database"
+                 type="java.lang.String"/>
+
+    <attribute   name="digest"
+          description="Digest algorithm used in storing passwords in a
+                       non-plaintext format"
+                 type="java.lang.String"/>
+
+    <attribute   name="driverName"
+          description="The JDBC driver to use"
+                 type="java.lang.String"/>
+
+    <attribute   name="roleNameCol"
+          description="The column in the user role table that names a role"
+                 type="java.lang.String"/>
+
+    <attribute   name="userCredCol"
+          description="The column in the user table that holds the user's
+                       credentials"
+                 type="java.lang.String"/>
+
+    <attribute   name="userNameCol"
+          description="The column in the user table that holds the user's
+                       username"
+                 type="java.lang.String"/>
+
+    <attribute   name="userRoleTable"
+          description="The table that holds the relation between user's and
+                       roles"
+                 type="java.lang.String"/>
+
+    <attribute   name="userTable"
+          description="The table that holds user data"
+                 type="java.lang.String"/>
+
+
+    <operation name="start" description="Start" impact="ACTION" returnType="void" />
+    <operation name="stop" description="Stop" impact="ACTION" returnType="void" />
+    <operation name="init" description="Init" impact="ACTION" returnType="void" />
+    <operation name="destroy" description="Destroy" impact="ACTION" returnType="void" />
+  </mbean>
+
+  <mbean         name="JNDIRealm"
+          description="Implementation of Realm that works with a directory
+                       server accessed via the Java Naming and Directory
+                       Interface (JNDI) APIs"
+               domain="Catalina"
+                group="Realm"
+                 type="org.apache.catalina.realm.JNDIRealm">
+
+    <attribute   name="className"
+          description="Fully qualified class name of the managed object"
+                 type="java.lang.String"
+            writeable="false"/>
+
+    <attribute   name="connectionName"
+          description="The connection username for the server we will contact"
+                 type="java.lang.String"/>
+
+    <attribute   name="connectionPassword"
+          description="The connection password for the server we will contact"
+                 type="java.lang.String"/>
+
+    <attribute   name="connectionURL"
+          description="The connection URL for the server we will contact"
+                 type="java.lang.String"/>
+
+    <attribute   name="contextFactory"
+          description="The JNDI context factory for this Realm"
+                 type="java.lang.String"/>
+
+    <attribute   name="digest"
+          description="Digest algorithm used in storing passwords in a
+                       non-plaintext format"
+                 type="java.lang.String"/>
+
+    <attribute   name="roleBase"
+          description="The base element for role searches"
+                 type="java.lang.String"/>
+
+    <attribute   name="roleName"
+          description="The name of the attribute containing roles held elsewhere"
+                 type="java.lang.String"/>
+
+    <attribute   name="roleSearch"
+          description="The message format used to select roles for a user"
+                 type="java.lang.String"/>
+
+    <attribute   name="roleSubtree"
+          description="Should we search the entire subtree for matching
+                       memberships?"
+                 type="boolean"/>
+
+    <attribute   name="userBase"
+          description="The base element for user searches"
+                 type="java.lang.String"/>
+
+    <attribute   name="userPassword"
+          description="The attribute name used to retrieve the user password"
+                 type="java.lang.String"/>
+
+    <attribute   name="userPattern"
+          description="The message format used to select a user"
+                 type="java.lang.String"/>
+
+     <attribute   name="userRoleName"
+          description="The name of the attribute in the user's entry containing
+                       roles for that user"
+                 type="java.lang.String"/>
+
+   <attribute   name="userSearch"
+         description="The message format used to search for a user"
+                type="java.lang.String"/>
+
+    <attribute   name="userSubtree"
+          description="Should we search the entire subtree for matching
+                       users?"
+                 type="boolean"/>
+
+
+    <operation name="start" description="Start" impact="ACTION" returnType="void" />
+    <operation name="stop" description="Stop" impact="ACTION" returnType="void" />
+    <operation name="init" description="Init" impact="ACTION" returnType="void" />
+    <operation name="destroy" description="Destroy" impact="ACTION" returnType="void" />
+  </mbean>
+
+  <mbean         name="MemoryRealm"
+          description="Simple implementation of Realm that reads an XML file to
+                       configure the valid users, passwords, and roles"
+               domain="Catalina"
+                group="Realm"
+                 type="org.apache.catalina.realm.MemoryRealm">
+
+    <attribute   name="className"
+          description="Fully qualified class name of the managed object"
+                 type="java.lang.String"
+            writeable="false"/>
+
+    <attribute   name="pathname"
+          description="The pathname of the XML file containing our database
+                       information"
+                 type="java.lang.String"/>
+
+    <operation name="start" description="Start" impact="ACTION" returnType="void" />
+    <operation name="stop" description="Stop" impact="ACTION" returnType="void" />
+    <operation name="init" description="Init" impact="ACTION" returnType="void" />
+    <operation name="destroy" description="Destroy" impact="ACTION" returnType="void" />
+
+  </mbean>
+
+  <mbean         name="UserDatabaseRealm"
+          description="Realm connected to a UserDatabase as a global JNDI
+                       resource"
+               domain="Catalina"
+                group="Realm"
+                 type="org.apache.catalina.realm.UserDatabaseRealm">
+
+    <attribute   name="className"
+          description="Fully qualified class name of the managed object"
+                 type="java.lang.String"
+            writeable="false"/>
+
+    <attribute   name="resourceName"
+          description="The global JNDI name of the UserDatabase resource to use"
+                 type="java.lang.String"/>
+
+  </mbean>
+
+</mbeans-descriptors>

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/realm/package.html
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/realm/package.html	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/realm/package.html	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,64 @@
+<body>
+
+<p>This package contains <code>Realm</code> implementations for the
+various supported realm technologies for authenticating users and
+identifying their associated roles.  The <code>Realm</code> that is
+associated with a web application's <code>Context</code> (or a hierarchically
+superior Container) is used to resolve authentication and role presence
+questions when a web application uses container managed security as described
+in the Servlet API Specification, version 2.2.</p>
+
+<p>The implementations share a common base class that supports basic
+functionality for all of the standard <code>Realm</code> implementations,
+and can be configured by setting the following properties (default values
+are in square brackets):</p>
+<ul>
+<li><b>debug</b> - Debugging detail level for this component. [0]</li>
+</ul>
+
+<p>The standard <code>Realm</code> implementations that are currently
+available include the following (with additional configuration properties
+as specified):</p>
+<ul>
+<li><b>JDBCRealm</b> - Implementation of <code>Realm</code> that operates
+    from data stored in a relational database that is accessed via a JDBC
+    driver.  The name of the driver, database connection information, and
+    the names of the relevant tables and columns are configured with the
+    following additional properties:
+    <ul>
+    <li><b>connectionURL</b> - The URL to use when connecting to this database.
+        [REQUIRED - NO DEFAULT]</li>
+    <li><b>driverName</b> - Fully qualified Java class name of the JDBC driver
+        to be used.  [REQUIRED - NO DEFAULT]</li>
+    <li><b>roleNameCol</b> - Name of the database column that contains role
+        names.  [REQUIRED - NO DEFAULT]</li>
+    <li><b>userCredCol</b> - Name of the database column that contains the
+        user's credentials (i.e. password) in cleartext.  [REQUIRED -
+        NO DEFAULT]</li>
+    <li><b>userNameCol</b> - Name of the database column that contains the
+        user's logon username.  [REQUIRED - NO DEFAULT]</li>
+    <li><b>userRoleTable</b> - Name of the database table containing user
+        role information.  This table must include the columns specified by
+        the <code>userNameCol</code> and <code>roleNameCol</code> properties.
+        [REQUIRED - NO DEFAULT]</li>
+    <li><b>userTable</b> - Name of the database table containing user
+        information.  This table must include the columns specified by the
+        <code>userNameCol</code> and <code>userCredCol</code> properties.
+        [REQUIRED - NO DEFAULT]</li>
+    </ul>
+    </li>
+<li><b>MemoryRealm</b> - Implementation of <code>Realm</code> that uses the
+    contents of a simple XML file (<code>conf/tomcat-users.xml</code>) as the
+    list of valid users and their roles.  This implementation is primarily to
+    demonstrate that the authentication technology functions correctly, and is
+    not anticipated as adequate for general purpose use.  This component
+    supports the following additional properties:
+    <ul>
+    <li><b>pathname</b> - Pathname of the XML file containing our user and
+        role information.  If a relative pathname is specified, it is resolved
+        against the pathname specified by the "catalina.home" system property.
+        [conf/tomcat-users.xml]</li>
+    </ul>
+</ul>
+
+</body>

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/security/LocalStrings.properties
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/security/LocalStrings.properties	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/security/LocalStrings.properties	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,2 @@
+SecurityUtil.doAsPrivilege=An exception occurs when running the PrivilegedExceptionAction block.
+

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/security/LocalStrings_es.properties
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/security/LocalStrings_es.properties	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/security/LocalStrings_es.properties	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,2 @@
+SecurityUtil.doAsPrivilege=Ha tenido lugar una excepción al ejecutar el bloque PrivilegedExceptionAction.
+

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/security/LocalStrings_fr.properties
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/security/LocalStrings_fr.properties	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/security/LocalStrings_fr.properties	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,2 @@
+SecurityUtil.doAsPrivilege=Une exception s''est produite lors de l''exécution du bloc "PrivilegedExceptionAction".
+

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/security/LocalStrings_ja.properties
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/security/LocalStrings_ja.properties	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/security/LocalStrings_ja.properties	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,2 @@
+SecurityUtil.doAsPrivilege=PrivilegedExceptionAction\u30d6\u30ed\u30c3\u30af\u3092\u5b9f\u884c\u4e2d\u306b\u4f8b\u5916\u304c\u767a\u751f\u3057\u307e\u3057\u305f\u3002
+

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/security/SecurityClassLoad.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/security/SecurityClassLoad.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/security/SecurityClassLoad.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,201 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.security;
+
+/**
+ * Static class used to preload java classes when using the
+ * Java SecurityManager so that the defineClassInPackage
+ * RuntimePermission does not trigger an AccessControlException.
+ *
+ * @author Glenn L. Nielsen
+ * @author Jean-Francois Arcand
+ * @version $Revision: 304042 $ $Date: 2005-08-04 01:07:46 -0500 (Thu, 04 Aug 2005) $
+ */
+
+public final class SecurityClassLoad {
+
+    public static void securityClassLoad(ClassLoader loader)
+        throws Exception {
+
+        if( System.getSecurityManager() == null ){
+            return;
+        }
+        
+        loadCorePackage(loader);
+        loadLoaderPackage(loader);
+        loadSessionPackage(loader);
+        loadUtilPackage(loader);
+        loadJavaxPackage(loader);
+        loadCoyotePackage(loader);        
+        loadHttp11Package(loader);        
+    }
+    
+    
+    private final static void loadCorePackage(ClassLoader loader)
+        throws Exception {
+        String basePackage = "org.apache.catalina.";
+        loader.loadClass
+            (basePackage +
+             "core.ApplicationContextFacade$1");
+        loader.loadClass
+            (basePackage +
+             "core.ApplicationDispatcher$PrivilegedForward");
+        loader.loadClass
+            (basePackage +
+             "core.ApplicationDispatcher$PrivilegedInclude");
+        loader.loadClass
+            (basePackage +
+             "core.ContainerBase$PrivilegedAddChild");
+        loader.loadClass
+            (basePackage +
+             "core.StandardWrapper$1");
+    }
+    
+    
+    private final static void loadLoaderPackage(ClassLoader loader)
+        throws Exception {
+        String basePackage = "org.apache.catalina.";
+        loader.loadClass
+            (basePackage +
+             "loader.WebappClassLoader$PrivilegedFindResource");
+    }
+    
+    
+    private final static void loadSessionPackage(ClassLoader loader)
+        throws Exception {
+        String basePackage = "org.apache.catalina.";
+        loader.loadClass
+            (basePackage + "session.StandardSession");
+        loader.loadClass
+            (basePackage +
+             "session.StandardSession$1");
+        loader.loadClass
+            (basePackage +
+             "session.StandardManager$PrivilegedDoUnload");
+    }
+    
+    
+    private final static void loadUtilPackage(ClassLoader loader)
+        throws Exception {
+        String basePackage = "org.apache.catalina.";
+        loader.loadClass
+            (basePackage + "util.URL");
+        loader.loadClass(basePackage + "util.Enumerator");
+    }
+    
+    
+    private final static void loadJavaxPackage(ClassLoader loader)
+        throws Exception {
+        loader.loadClass("javax.servlet.http.Cookie");
+    }
+    
+
+    private final static void loadHttp11Package(ClassLoader loader)
+        throws Exception {
+        String basePackage = "org.apache.coyote.http11.";
+        loader.loadClass(basePackage + "Http11Processor$1");
+        loader.loadClass(basePackage + "InternalOutputBuffer$1");
+        loader.loadClass(basePackage + "InternalOutputBuffer$2");
+    }
+    
+    
+    private final static void loadCoyotePackage(ClassLoader loader)
+        throws Exception {
+        String basePackage = "org.apache.catalina.connector.";
+        loader.loadClass
+            (basePackage +
+             "RequestFacade$GetAttributePrivilegedAction");
+        loader.loadClass
+            (basePackage +
+             "RequestFacade$GetParameterMapPrivilegedAction");
+        loader.loadClass
+            (basePackage +
+             "RequestFacade$GetRequestDispatcherPrivilegedAction");
+        loader.loadClass
+            (basePackage +
+             "RequestFacade$GetParameterPrivilegedAction");
+        loader.loadClass
+            (basePackage +
+             "RequestFacade$GetParameterNamesPrivilegedAction");
+        loader.loadClass
+            (basePackage +
+             "RequestFacade$GetParameterValuePrivilegedAction");
+        loader.loadClass
+            (basePackage +
+             "RequestFacade$GetCharacterEncodingPrivilegedAction");
+        loader.loadClass
+            (basePackage +
+             "RequestFacade$GetHeadersPrivilegedAction");
+        loader.loadClass
+            (basePackage +
+             "RequestFacade$GetHeaderNamesPrivilegedAction");  
+        loader.loadClass
+            (basePackage +
+             "RequestFacade$GetCookiesPrivilegedAction");
+        loader.loadClass
+            (basePackage +
+             "RequestFacade$GetLocalePrivilegedAction");
+        loader.loadClass
+            (basePackage +
+             "RequestFacade$GetLocalesPrivilegedAction");
+        loader.loadClass
+            (basePackage +
+             "ResponseFacade$SetContentTypePrivilegedAction");
+        loader.loadClass
+            (basePackage + 
+             "ResponseFacade$DateHeaderPrivilegedAction");
+        loader.loadClass
+            (basePackage +
+             "RequestFacade$GetSessionPrivilegedAction");
+        loader.loadClass
+            (basePackage +
+             "ResponseFacade$1");
+        loader.loadClass
+            (basePackage +
+             "OutputBuffer$1");
+        loader.loadClass
+            (basePackage +
+             "CoyoteInputStream$1");
+        loader.loadClass
+            (basePackage +
+             "CoyoteInputStream$2");
+        loader.loadClass
+            (basePackage +
+             "CoyoteInputStream$3");
+        loader.loadClass
+            (basePackage +
+             "CoyoteInputStream$4");
+        loader.loadClass
+            (basePackage +
+             "CoyoteInputStream$5");
+        loader.loadClass
+            (basePackage +
+             "InputBuffer$1");
+        loader.loadClass
+            (basePackage +
+             "Response$1");
+        loader.loadClass
+            (basePackage +
+             "Response$2");
+        loader.loadClass
+            (basePackage +
+             "Response$3");
+    }
+
+}
+

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/security/SecurityConfig.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/security/SecurityConfig.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/security/SecurityConfig.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,133 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.security;
+
+import java.security.Security;
+import org.apache.catalina.startup.CatalinaProperties;
+
+/**
+ * Util class to protect Catalina against package access and insertion.
+ * The code are been moved from Catalina.java
+ * @author the Catalina.java authors
+ * @author Jean-Francois Arcand
+ */
+public final class SecurityConfig{
+    private static SecurityConfig singleton = null;
+
+    private static org.apache.commons.logging.Log log=
+        org.apache.commons.logging.LogFactory.getLog( SecurityConfig.class );
+
+    
+    private final static String PACKAGE_ACCESS =  "sun.,"
+                                                + "org.apache.catalina." 
+                                                + ",org.apache.jasper."
+                                                + ",org.apache.coyote."
+                                                + ",org.apache.tomcat.";
+    
+    private final static String PACKAGE_DEFINITION= "java.,sun."
+                                                + ",org.apache.catalina." 
+                                                + ",org.apache.coyote."
+                                                + ",org.apache.tomcat."
+                                                + ",org.apache.jasper.";
+    /**
+     * List of protected package from conf/catalina.properties
+     */
+    private String packageDefinition;
+    
+    
+    /**
+     * List of protected package from conf/catalina.properties
+     */
+    private String packageAccess; 
+    
+    
+    /**
+     * Create a single instance of this class.
+     */
+    private SecurityConfig(){  
+        try{
+            packageDefinition = CatalinaProperties.getProperty("package.definition");
+            packageAccess = CatalinaProperties.getProperty("package.access");
+        } catch (java.lang.Exception ex){
+            if (log.isDebugEnabled()){
+                log.debug("Unable to load properties using CatalinaProperties", ex); 
+            }            
+        }
+    }
+    
+    
+    /**
+     * Returns the singleton instance of that class.
+     * @return an instance of that class.
+     */
+    public static SecurityConfig newInstance(){
+        if (singleton == null){
+            singleton = new SecurityConfig();
+        }
+        return singleton;
+    }
+    
+    
+    /**
+     * Set the security package.access value.
+     */
+    public void setPackageAccess(){
+        // If catalina.properties is missing, protect all by default.
+        if (packageAccess == null){
+            setSecurityProperty("package.access", PACKAGE_ACCESS);   
+        } else {
+            setSecurityProperty("package.access", packageAccess);   
+        }
+    }
+    
+    
+    /**
+     * Set the security package.definition value.
+     */
+     public void setPackageDefinition(){
+        // If catalina.properties is missing, protect all by default.
+         if (packageDefinition == null){
+            setSecurityProperty("package.definition", PACKAGE_DEFINITION);
+         } else {
+            setSecurityProperty("package.definition", packageDefinition);
+         }
+    }
+     
+     
+    /**
+     * Set the proper security property
+     * @param properties the package.* property.
+     */
+    private final void setSecurityProperty(String properties, String packageList){
+        if (System.getSecurityManager() != null){
+            String definition = Security.getProperty(properties);
+            if( definition != null && definition.length() > 0 ){
+                definition += ",";
+            }
+
+            Security.setProperty(properties,
+                // FIX ME package "javax." was removed to prevent HotSpot
+                // fatal internal errors
+                definition + packageList);      
+        }
+    }
+    
+    
+}
+
+
+
+

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/security/SecurityUtil.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/security/SecurityUtil.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/security/SecurityUtil.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,384 @@
+/*
+ * Copyright 1999-2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.security;
+
+
+import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.security.Principal;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
+import java.util.HashMap;
+
+import javax.security.auth.Subject;
+import javax.servlet.Filter;
+import javax.servlet.Servlet;
+import javax.servlet.ServletException;
+import javax.servlet.UnavailableException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpSession;
+
+import org.apache.catalina.Globals;
+import org.apache.catalina.util.StringManager;
+/**
+ * This utility class associates a <code>Subject</code> to the current 
+ * <code>AccessControlContext</code>. When a <code>SecurityManager</code> is
+ * used, * the container will always associate the called thread with an 
+ * AccessControlContext * containing only the principal of the requested
+ * Servlet/Filter.
+ *
+ * This class uses reflection to invoke the invoke methods.
+ *
+ * @author Jean-Francois Arcand
+ */
+
+public final class SecurityUtil{
+    
+    private final static int INIT= 0;
+    private final static int SERVICE = 1;
+    private final static int DOFILTER = 1;
+    private final static int DESTROY = 2;
+    
+    private final static String INIT_METHOD = "init";
+    private final static String DOFILTER_METHOD = "doFilter";
+    private final static String SERVICE_METHOD = "service";
+    private final static String DESTROY_METHOD = "destroy";
+   
+    /**
+     * Cache every object for which we are creating method on it.
+     */
+    private static HashMap objectCache = new HashMap();
+        
+    private static org.apache.commons.logging.Log log=
+        org.apache.commons.logging.LogFactory.getLog( SecurityUtil.class );
+    
+    private static String PACKAGE = "org.apache.catalina.security";
+    
+    private static boolean packageDefinitionEnabled =  
+         (System.getProperty("package.definition") == null && 
+           System.getProperty("package.access")  == null) ? false : true;
+    
+    /**
+     * The string resources for this package.
+     */
+    private static final StringManager sm =
+        StringManager.getManager(PACKAGE);    
+    
+    
+    /**
+     * Perform work as a particular </code>Subject</code>. Here the work
+     * will be granted to a <code>null</code> subject. 
+     *
+     * @param methodName the method to apply the security restriction
+     * @param targetObject the <code>Servlet</code> on which the method will
+     * be called.
+     */
+    public static void doAsPrivilege(final String methodName, 
+                                     final Servlet targetObject) throws java.lang.Exception{
+         doAsPrivilege(methodName, targetObject, null, null, null);                                
+    }
+
+    
+    /**
+     * Perform work as a particular </code>Subject</code>. Here the work
+     * will be granted to a <code>null</code> subject. 
+     *
+     * @param methodName the method to apply the security restriction
+     * @param targetObject the <code>Servlet</code> on which the method will
+     * be called.
+     * @param targetType <code>Class</code> array used to instanciate a i
+     * <code>Method</code> object.
+     * @param targetArguments <code>Object</code> array contains the runtime 
+     * parameters instance.
+     */
+    public static void doAsPrivilege(final String methodName, 
+                                     final Servlet targetObject, 
+                                     final Class[] targetType,
+                                     final Object[] targetArguments) 
+        throws java.lang.Exception{    
+
+         doAsPrivilege(methodName, 
+                       targetObject, 
+                       targetType, 
+                       targetArguments, 
+                       null);                                
+    }
+    
+    
+    /**
+     * Perform work as a particular </code>Subject</code>. Here the work
+     * will be granted to a <code>null</code> subject. 
+     *
+     * @param methodName the method to apply the security restriction
+     * @param targetObject the <code>Servlet</code> on which the method will
+     * be called.
+     * @param targetType <code>Class</code> array used to instanciate a 
+     * <code>Method</code> object.
+     * @param targetArguments <code>Object</code> array contains the 
+     * runtime parameters instance.
+     * @param principal the <code>Principal</code> to which the security 
+     * privilege apply..
+     */    
+    public static void doAsPrivilege(final String methodName, 
+                                     final Servlet targetObject, 
+                                     final Class[] targetType,
+                                     final Object[] targetArguments,
+                                     Principal principal) 
+        throws java.lang.Exception{
+
+        Method method = null;
+        Method[] methodsCache = null;
+        if(objectCache.containsKey(targetObject)){
+            methodsCache = (Method[])objectCache.get(targetObject);
+            method = findMethod(methodsCache, methodName);
+            if (method == null){
+                method = createMethodAndCacheIt(methodsCache,
+                                                methodName,
+                                                targetObject,
+                                                targetType);
+            }
+        } else {
+            method = createMethodAndCacheIt(methodsCache,
+                                            methodName,
+                                            targetObject,
+                                            targetType);                     
+        }
+
+        execute(method, targetObject, targetArguments, principal);
+    }
+ 
+    
+    /**
+     * Perform work as a particular </code>Subject</code>. Here the work
+     * will be granted to a <code>null</code> subject. 
+     *
+     * @param methodName the method to apply the security restriction
+     * @param targetObject the <code>Filter</code> on which the method will 
+     * be called.
+     */    
+    public static void doAsPrivilege(final String methodName, 
+                                     final Filter targetObject) 
+        throws java.lang.Exception{
+
+         doAsPrivilege(methodName, targetObject, null, null);                                
+    }
+ 
+    
+    /**
+     * Perform work as a particular </code>Subject</code>. Here the work
+     * will be granted to a <code>null</code> subject. 
+     *
+     * @param methodName the method to apply the security restriction
+     * @param targetObject the <code>Filter</code> on which the method will 
+     * be called.
+     * @param targetType <code>Class</code> array used to instanciate a
+     * <code>Method</code> object.
+     * @param targetArguments <code>Object</code> array contains the 
+     * runtime parameters instance.
+     */    
+    public static void doAsPrivilege(final String methodName, 
+                                     final Filter targetObject, 
+                                     final Class[] targetType,
+                                     final Object[] targetArguments) 
+        throws java.lang.Exception{
+        Method method = null;
+
+        Method[] methodsCache = null;
+        if(objectCache.containsKey(targetObject)){
+            methodsCache = (Method[])objectCache.get(targetObject);
+            method = findMethod(methodsCache, methodName);
+            if (method == null){
+                method = createMethodAndCacheIt(methodsCache,
+                                                methodName,
+                                                targetObject,
+                                                targetType);
+            }
+        } else {
+            method = createMethodAndCacheIt(methodsCache,
+                                            methodName,
+                                            targetObject,
+                                            targetType);                     
+        }
+
+        execute(method, targetObject, targetArguments, null);
+    }
+    
+    
+    /**
+     * Perform work as a particular </code>Subject</code>. Here the work
+     * will be granted to a <code>null</code> subject. 
+     *
+     * @param methodName the method to apply the security restriction
+     * @param targetObject the <code>Servlet</code> on which the method will
+     * be called.
+     * @param targetArguments <code>Object</code> array contains the 
+     * runtime parameters instance.
+     * @param principal the <code>Principal</code> to which the security 
+     * privilege applies
+     */    
+    private static void execute(final Method method,
+                                final Object targetObject, 
+                                final Object[] targetArguments,
+                                Principal principal) 
+        throws java.lang.Exception{
+       
+        try{   
+            Subject subject = null;
+            PrivilegedExceptionAction pea = new PrivilegedExceptionAction(){
+                    public Object run() throws Exception{
+                       method.invoke(targetObject, targetArguments);
+                       return null;
+                    }
+            };
+
+            // The first argument is always the request object
+            if (targetArguments != null 
+                    && targetArguments[0] instanceof HttpServletRequest){
+                HttpServletRequest request = 
+                    (HttpServletRequest)targetArguments[0];
+
+                boolean hasSubject = false;
+                HttpSession session = request.getSession(false);
+                if (session != null){
+                    subject = 
+                        (Subject)session.getAttribute(Globals.SUBJECT_ATTR);
+                    hasSubject = (subject != null);
+                }
+
+                if (subject == null){
+                    subject = new Subject();
+                    
+                    if (principal != null){
+                        subject.getPrincipals().add(principal);
+                    }
+                }
+
+                if (session != null && !hasSubject) {
+                    session.setAttribute(Globals.SUBJECT_ATTR, subject);
+                }
+            }
+
+            Subject.doAsPrivileged(subject, pea, null);       
+       } catch( PrivilegedActionException pe) {
+            Throwable e = ((InvocationTargetException)pe.getException())
+                                .getTargetException();
+            
+            if (log.isDebugEnabled()){
+                log.debug(sm.getString("SecurityUtil.doAsPrivilege"), e); 
+            }
+            
+            if (e instanceof UnavailableException)
+                throw (UnavailableException) e;
+            else if (e instanceof ServletException)
+                throw (ServletException) e;
+            else if (e instanceof IOException)
+                throw (IOException) e;
+            else if (e instanceof RuntimeException)
+                throw (RuntimeException) e;
+            else
+                throw new ServletException(e.getMessage(), e);
+        }  
+    }
+    
+    
+    /**
+     * Find a method stored within the cache.
+     * @param methodsCache the cache used to store method instance
+     * @param methodName the method to apply the security restriction
+     * @return the method instance, null if not yet created.
+     */
+    private static Method findMethod(Method[] methodsCache,
+                                     String methodName){
+        if (methodName.equalsIgnoreCase(INIT_METHOD) 
+                && methodsCache[INIT] != null){
+            return methodsCache[INIT];
+        } else if (methodName.equalsIgnoreCase(DESTROY_METHOD) 
+                && methodsCache[DESTROY] != null){
+            return methodsCache[DESTROY];            
+        } else if (methodName.equalsIgnoreCase(SERVICE_METHOD) 
+                && methodsCache[SERVICE] != null){
+            return methodsCache[SERVICE];
+        } else if (methodName.equalsIgnoreCase(DOFILTER_METHOD) 
+                && methodsCache[DOFILTER] != null){
+            return methodsCache[DOFILTER];          
+        } 
+        return null;
+    }
+    
+    
+    /**
+     * Create the method and cache it for further re-use.
+     * @param methodsCache the cache used to store method instance
+     * @param methodName the method to apply the security restriction
+     * @param targetObject the <code>Servlet</code> on which the method will
+     * be called.
+     * @param targetType <code>Class</code> array used to instanciate a 
+     * <code>Method</code> object.
+     * @return the method instance.
+     */
+    private static Method createMethodAndCacheIt(Method[] methodsCache,
+                                                 String methodName,
+                                                 Object targetObject,
+                                                 Class[] targetType) 
+            throws Exception{
+        
+        if ( methodsCache == null){
+            methodsCache = new Method[3];
+        }               
+                
+        Method method = 
+            targetObject.getClass().getMethod(methodName, targetType); 
+
+        if (methodName.equalsIgnoreCase(INIT_METHOD)){
+            methodsCache[INIT] = method;
+        } else if (methodName.equalsIgnoreCase(DESTROY_METHOD)){
+            methodsCache[DESTROY] = method;
+        } else if (methodName.equalsIgnoreCase(SERVICE_METHOD)){
+            methodsCache[SERVICE] = method;
+        } else if (methodName.equalsIgnoreCase(DOFILTER_METHOD)){
+            methodsCache[DOFILTER] = method;
+        } 
+         
+        objectCache.put(targetObject, methodsCache );
+                                           
+        return method;
+    }
+
+    
+    /**
+     * Remove the object from the cache.
+     *
+     * @param cachedObject The object to remove
+     */
+    public static void remove(Object cachedObject){
+        objectCache.remove(cachedObject);
+    }
+    
+    
+    /**
+     * Return the <code>SecurityManager</code> only if Security is enabled AND
+     * package protection mechanism is enabled.
+     */
+    public static boolean isPackageProtectionEnabled(){
+        if (packageDefinitionEnabled && System.getSecurityManager() !=  null){
+            return true;
+        }
+        return false;
+    }
+    
+    
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/servlets/CGIServlet.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/servlets/CGIServlet.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/servlets/CGIServlet.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,1967 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.servlets;
+
+import java.io.BufferedOutputStream;
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.UnsupportedEncodingException;
+import java.net.URLDecoder;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Locale;
+import java.util.StringTokenizer;
+import java.util.Vector;
+
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+import javax.servlet.ServletOutputStream;
+import javax.servlet.UnavailableException;
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+
+import org.apache.catalina.Globals;
+import org.apache.catalina.util.IOTools;
+
+
+/**
+ *  CGI-invoking servlet for web applications, used to execute scripts which
+ *  comply to the Common Gateway Interface (CGI) specification and are named
+ *  in the path-info used to invoke this servlet.
+ *
+ * <p>
+ * <i>Note: This code compiles and even works for simple CGI cases.
+ *          Exhaustive testing has not been done.  Please consider it beta
+ *          quality.  Feedback is appreciated to the author (see below).</i>
+ * </p>
+ * <p>
+ *
+ * <b>Example</b>:<br>
+ * If an instance of this servlet was mapped (using
+ *       <code>&lt;web-app&gt;/WEB-INF/web.xml</code>) to:
+ * </p>
+ * <p>
+ * <code>
+ * &lt;web-app&gt;/cgi-bin/*
+ * </code>
+ * </p>
+ * <p>
+ * then the following request:
+ * </p>
+ * <p>
+ * <code>
+ * http://localhost:8080/&lt;web-app&gt;/cgi-bin/dir1/script/pathinfo1
+ * </code>
+ * </p>
+ * <p>
+ * would result in the execution of the script
+ * </p>
+ * <p>
+ * <code>
+ * &lt;web-app-root&gt;/WEB-INF/cgi/dir1/script
+ * </code>
+ * </p>
+ * <p>
+ * with the script's <code>PATH_INFO</code> set to <code>/pathinfo1</code>.
+ * </p>
+ * <p>
+ * Recommendation:  House all your CGI scripts under
+ * <code>&lt;webapp&gt;/WEB-INF/cgi</code>.  This will ensure that you do not
+ * accidentally expose your cgi scripts' code to the outside world and that
+ * your cgis will be cleanly ensconced underneath the WEB-INF (i.e.,
+ * non-content) area.
+ * </p>
+ * <p>
+ * The default CGI location is mentioned above.  You have the flexibility to
+ * put CGIs wherever you want, however:
+ * </p>
+ * <p>
+ *   The CGI search path will start at
+ *   webAppRootDir + File.separator + cgiPathPrefix
+ *   (or webAppRootDir alone if cgiPathPrefix is
+ *   null).
+ * </p>
+ * <p>
+ *   cgiPathPrefix is defined by setting
+ *   this servlet's cgiPathPrefix init parameter
+ * </p>
+ *
+ * <p>
+ *
+ * <B>CGI Specification</B>:<br> derived from
+ * <a href="http://cgi-spec.golux.com">http://cgi-spec.golux.com</a>.
+ * A work-in-progress & expired Internet Draft.  Note no actual RFC describing
+ * the CGI specification exists.  Where the behavior of this servlet differs
+ * from the specification cited above, it is either documented here, a bug,
+ * or an instance where the specification cited differs from Best
+ * Community Practice (BCP).
+ * Such instances should be well-documented here.  Please email the
+ * <a href="mailto:tomcat-dev at jakarta.apache.org">Jakarta Tomcat group [tomcat-dev at jakarta.apache.org]</a>
+ * with amendments.
+ *
+ * </p>
+ * <p>
+ *
+ * <b>Canonical metavariables</b>:<br>
+ * The CGI specification defines the following canonical metavariables:
+ * <br>
+ * [excerpt from CGI specification]
+ * <PRE>
+ *  AUTH_TYPE
+ *  CONTENT_LENGTH
+ *  CONTENT_TYPE
+ *  GATEWAY_INTERFACE
+ *  PATH_INFO
+ *  PATH_TRANSLATED
+ *  QUERY_STRING
+ *  REMOTE_ADDR
+ *  REMOTE_HOST
+ *  REMOTE_IDENT
+ *  REMOTE_USER
+ *  REQUEST_METHOD
+ *  SCRIPT_NAME
+ *  SERVER_NAME
+ *  SERVER_PORT
+ *  SERVER_PROTOCOL
+ *  SERVER_SOFTWARE
+ * </PRE>
+ * <p>
+ * Metavariables with names beginning with the protocol name (<EM>e.g.</EM>,
+ * "HTTP_ACCEPT") are also canonical in their description of request header
+ * fields.  The number and meaning of these fields may change independently
+ * of this specification.  (See also section 6.1.5 [of the CGI specification].)
+ * </p>
+ * [end excerpt]
+ *
+ * </p>
+ * <h2> Implementation notes</h2>
+ * <p>
+ *
+ * <b>standard input handling</b>: If your script accepts standard input,
+ * then the client must start sending input within a certain timeout period,
+ * otherwise the servlet will assume no input is coming and carry on running
+ * the script.  The script's the standard input will be closed and handling of
+ * any further input from the client is undefined.  Most likely it will be
+ * ignored.  If this behavior becomes undesirable, then this servlet needs
+ * to be enhanced to handle threading of the spawned process' stdin, stdout,
+ * and stderr (which should not be too hard).
+ * <br>
+ * If you find your cgi scripts are timing out receiving input, you can set
+ * the init parameter <code></code> of your webapps' cgi-handling servlet
+ * to be
+ * </p>
+ * <p>
+ *
+ * <b>Metavariable Values</b>: According to the CGI specificion,
+ * implementations may choose to represent both null or missing values in an
+ * implementation-specific manner, but must define that manner.  This
+ * implementation chooses to always define all required metavariables, but
+ * set the value to "" for all metavariables whose value is either null or
+ * undefined.  PATH_TRANSLATED is the sole exception to this rule, as per the
+ * CGI Specification.
+ *
+ * </p>
+ * <p>
+ *
+ * <b>NPH --  Non-parsed-header implementation</b>:  This implementation does
+ * not support the CGI NPH concept, whereby server ensures that the data
+ * supplied to the script are preceisely as supplied by the client and
+ * unaltered by the server.
+ * </p>
+ * <p>
+ * The function of a servlet container (including Tomcat) is specifically
+ * designed to parse and possible alter CGI-specific variables, and as
+ * such makes NPH functionality difficult to support.
+ * </p>
+ * <p>
+ * The CGI specification states that compliant servers MAY support NPH output.
+ * It does not state servers MUST support NPH output to be unconditionally
+ * compliant.  Thus, this implementation maintains unconditional compliance
+ * with the specification though NPH support is not present.
+ * </p>
+ * <p>
+ *
+ * The CGI specification is located at
+ * <a href="http://cgi-spec.golux.com">http://cgi-spec.golux.com</a>.
+ *
+ * </p>
+ * <p>
+ * <h3>TODO:</h3>
+ * <ul>
+ * <li> Support for setting headers (for example, Location headers don't work)
+ * <li> Support for collapsing multiple header lines (per RFC 2616)
+ * <li> Ensure handling of POST method does not interfere with 2.3 Filters
+ * <li> Refactor some debug code out of core
+ * <li> Ensure header handling preserves encoding
+ * <li> Possibly rewrite CGIRunner.run()?
+ * <li> Possibly refactor CGIRunner and CGIEnvironment as non-inner classes?
+ * <li> Document handling of cgi stdin when there is no stdin
+ * <li> Revisit IOException handling in CGIRunner.run()
+ * <li> Better documentation
+ * <li> Confirm use of ServletInputStream.available() in CGIRunner.run() is
+ *      not needed
+ * <li> Make checking for "." and ".." in servlet & cgi PATH_INFO less
+ *      draconian
+ * <li> [add more to this TODO list]
+ * </ul>
+ * </p>
+ *
+ * @author Martin T Dengler [root at martindengler.com]
+ * @author Amy Roh
+ * @version $Revision: 424503 $, $Date: 2006-07-21 19:19:37 -0500 (Fri, 21 Jul 2006) $
+ * @since Tomcat 4.0
+ *
+ */
+
+
+public final class CGIServlet extends HttpServlet {
+
+    /* some vars below copied from Craig R. McClanahan's InvokerServlet */
+
+    /** the debugging detail level for this servlet. */
+    private int debug = 0;
+
+    /**
+     *  The CGI search path will start at
+     *    webAppRootDir + File.separator + cgiPathPrefix
+     *    (or webAppRootDir alone if cgiPathPrefix is
+     *    null)
+     */
+    private String cgiPathPrefix = null;
+
+    /** the executable to use with the script */
+    private String cgiExecutable = "perl";
+    
+    /** the encoding to use for parameters */
+    private String parameterEncoding = System.getProperty("file.encoding",
+                                                          "UTF-8");
+
+    /** object used to ensure multiple threads don't try to expand same file */
+    static Object expandFileLock = new Object();
+
+    /** the shell environment variables to be passed to the CGI script */
+    static Hashtable shellEnv = new Hashtable();
+
+    /**
+     * Sets instance variables.
+     * <P>
+     * Modified from Craig R. McClanahan's InvokerServlet
+     * </P>
+     *
+     * @param config                    a <code>ServletConfig</code> object
+     *                                  containing the servlet's
+     *                                  configuration and initialization
+     *                                  parameters
+     *
+     * @exception ServletException      if an exception has occurred that
+     *                                  interferes with the servlet's normal
+     *                                  operation
+     */
+    public void init(ServletConfig config) throws ServletException {
+
+        super.init(config);
+
+        // Verify that we were not accessed using the invoker servlet
+        String servletName = getServletConfig().getServletName();
+        if (servletName == null)
+            servletName = "";
+        if (servletName.startsWith("org.apache.catalina.INVOKER."))
+            throw new UnavailableException
+                ("Cannot invoke CGIServlet through the invoker");
+
+        boolean passShellEnvironment = false;
+        
+        // Set our properties from the initialization parameters
+        String value = null;
+        try {
+            value = getServletConfig().getInitParameter("debug");
+            debug = Integer.parseInt(value);
+            cgiPathPrefix =
+                getServletConfig().getInitParameter("cgiPathPrefix");
+            value = getServletConfig().getInitParameter("passShellEnvironment");
+            passShellEnvironment = Boolean.valueOf(value).booleanValue();
+        } catch (Throwable t) {
+            //NOOP
+        }
+        log("init: loglevel set to " + debug);
+
+        if (passShellEnvironment) {
+            try {
+                shellEnv.putAll(getShellEnvironment());
+            } catch (IOException ioe) {
+                ServletException e = new ServletException(
+                        "Unable to read shell environment variables", ioe);
+                throw e;
+            }
+        }
+
+        value = getServletConfig().getInitParameter("executable");
+        if (value != null) {
+            cgiExecutable = value;
+        }
+
+        value = getServletConfig().getInitParameter("parameterEncoding");
+        if (value != null) {
+            parameterEncoding = value;
+        }
+
+    }
+
+
+
+    /**
+     * Prints out important Servlet API and container information
+     *
+     * <p>
+     * Copied from SnoopAllServlet by Craig R. McClanahan
+     * </p>
+     *
+     * @param  out    ServletOutputStream as target of the information
+     * @param  req    HttpServletRequest object used as source of information
+     * @param  res    HttpServletResponse object currently not used but could
+     *                provide future information
+     *
+     * @exception  IOException  if a write operation exception occurs
+     *
+     */
+    protected void printServletEnvironment(ServletOutputStream out,
+        HttpServletRequest req, HttpServletResponse res) throws IOException {
+
+        // Document the properties from ServletRequest
+        out.println("<h1>ServletRequest Properties</h1>");
+        out.println("<ul>");
+        Enumeration attrs = req.getAttributeNames();
+        while (attrs.hasMoreElements()) {
+            String attr = (String) attrs.nextElement();
+            out.println("<li><b>attribute</b> " + attr + " = " +
+                           req.getAttribute(attr));
+        }
+        out.println("<li><b>characterEncoding</b> = " +
+                       req.getCharacterEncoding());
+        out.println("<li><b>contentLength</b> = " +
+                       req.getContentLength());
+        out.println("<li><b>contentType</b> = " +
+                       req.getContentType());
+        Enumeration locales = req.getLocales();
+        while (locales.hasMoreElements()) {
+            Locale locale = (Locale) locales.nextElement();
+            out.println("<li><b>locale</b> = " + locale);
+        }
+        Enumeration params = req.getParameterNames();
+        while (params.hasMoreElements()) {
+            String param = (String) params.nextElement();
+            String values[] = req.getParameterValues(param);
+            for (int i = 0; i < values.length; i++)
+                out.println("<li><b>parameter</b> " + param + " = " +
+                               values[i]);
+        }
+        out.println("<li><b>protocol</b> = " + req.getProtocol());
+        out.println("<li><b>remoteAddr</b> = " + req.getRemoteAddr());
+        out.println("<li><b>remoteHost</b> = " + req.getRemoteHost());
+        out.println("<li><b>scheme</b> = " + req.getScheme());
+        out.println("<li><b>secure</b> = " + req.isSecure());
+        out.println("<li><b>serverName</b> = " + req.getServerName());
+        out.println("<li><b>serverPort</b> = " + req.getServerPort());
+        out.println("</ul>");
+        out.println("<hr>");
+
+        // Document the properties from HttpServletRequest
+        out.println("<h1>HttpServletRequest Properties</h1>");
+        out.println("<ul>");
+        out.println("<li><b>authType</b> = " + req.getAuthType());
+        out.println("<li><b>contextPath</b> = " +
+                       req.getContextPath());
+        Cookie cookies[] = req.getCookies();
+        if (cookies!=null) {
+            for (int i = 0; i < cookies.length; i++)
+                out.println("<li><b>cookie</b> " + cookies[i].getName() +" = " +cookies[i].getValue());
+        }
+        Enumeration headers = req.getHeaderNames();
+        while (headers.hasMoreElements()) {
+            String header = (String) headers.nextElement();
+            out.println("<li><b>header</b> " + header + " = " +
+                           req.getHeader(header));
+        }
+        out.println("<li><b>method</b> = " + req.getMethod());
+        out.println("<li><a name=\"pathInfo\"><b>pathInfo</b></a> = "
+                    + req.getPathInfo());
+        out.println("<li><b>pathTranslated</b> = " +
+                       req.getPathTranslated());
+        out.println("<li><b>queryString</b> = " +
+                       req.getQueryString());
+        out.println("<li><b>remoteUser</b> = " +
+                       req.getRemoteUser());
+        out.println("<li><b>requestedSessionId</b> = " +
+                       req.getRequestedSessionId());
+        out.println("<li><b>requestedSessionIdFromCookie</b> = " +
+                       req.isRequestedSessionIdFromCookie());
+        out.println("<li><b>requestedSessionIdFromURL</b> = " +
+                       req.isRequestedSessionIdFromURL());
+        out.println("<li><b>requestedSessionIdValid</b> = " +
+                       req.isRequestedSessionIdValid());
+        out.println("<li><b>requestURI</b> = " +
+                       req.getRequestURI());
+        out.println("<li><b>servletPath</b> = " +
+                       req.getServletPath());
+        out.println("<li><b>userPrincipal</b> = " +
+                       req.getUserPrincipal());
+        out.println("</ul>");
+        out.println("<hr>");
+
+        // Document the servlet request attributes
+        out.println("<h1>ServletRequest Attributes</h1>");
+        out.println("<ul>");
+        attrs = req.getAttributeNames();
+        while (attrs.hasMoreElements()) {
+            String attr = (String) attrs.nextElement();
+            out.println("<li><b>" + attr + "</b> = " +
+                           req.getAttribute(attr));
+        }
+        out.println("</ul>");
+        out.println("<hr>");
+
+        // Process the current session (if there is one)
+        HttpSession session = req.getSession(false);
+        if (session != null) {
+
+            // Document the session properties
+            out.println("<h1>HttpSession Properties</h1>");
+            out.println("<ul>");
+            out.println("<li><b>id</b> = " +
+                           session.getId());
+            out.println("<li><b>creationTime</b> = " +
+                           new Date(session.getCreationTime()));
+            out.println("<li><b>lastAccessedTime</b> = " +
+                           new Date(session.getLastAccessedTime()));
+            out.println("<li><b>maxInactiveInterval</b> = " +
+                           session.getMaxInactiveInterval());
+            out.println("</ul>");
+            out.println("<hr>");
+
+            // Document the session attributes
+            out.println("<h1>HttpSession Attributes</h1>");
+            out.println("<ul>");
+            attrs = session.getAttributeNames();
+            while (attrs.hasMoreElements()) {
+                String attr = (String) attrs.nextElement();
+                out.println("<li><b>" + attr + "</b> = " +
+                               session.getAttribute(attr));
+            }
+            out.println("</ul>");
+            out.println("<hr>");
+
+        }
+
+        // Document the servlet configuration properties
+        out.println("<h1>ServletConfig Properties</h1>");
+        out.println("<ul>");
+        out.println("<li><b>servletName</b> = " +
+                       getServletConfig().getServletName());
+        out.println("</ul>");
+        out.println("<hr>");
+
+        // Document the servlet configuration initialization parameters
+        out.println("<h1>ServletConfig Initialization Parameters</h1>");
+        out.println("<ul>");
+        params = getServletConfig().getInitParameterNames();
+        while (params.hasMoreElements()) {
+            String param = (String) params.nextElement();
+            String value = getServletConfig().getInitParameter(param);
+            out.println("<li><b>" + param + "</b> = " + value);
+        }
+        out.println("</ul>");
+        out.println("<hr>");
+
+        // Document the servlet context properties
+        out.println("<h1>ServletContext Properties</h1>");
+        out.println("<ul>");
+        out.println("<li><b>majorVersion</b> = " +
+                       getServletContext().getMajorVersion());
+        out.println("<li><b>minorVersion</b> = " +
+                       getServletContext().getMinorVersion());
+        out.println("<li><b>realPath('/')</b> = " +
+                       getServletContext().getRealPath("/"));
+        out.println("<li><b>serverInfo</b> = " +
+                       getServletContext().getServerInfo());
+        out.println("</ul>");
+        out.println("<hr>");
+
+        // Document the servlet context initialization parameters
+        out.println("<h1>ServletContext Initialization Parameters</h1>");
+        out.println("<ul>");
+        params = getServletContext().getInitParameterNames();
+        while (params.hasMoreElements()) {
+            String param = (String) params.nextElement();
+            String value = getServletContext().getInitParameter(param);
+            out.println("<li><b>" + param + "</b> = " + value);
+        }
+        out.println("</ul>");
+        out.println("<hr>");
+
+        // Document the servlet context attributes
+        out.println("<h1>ServletContext Attributes</h1>");
+        out.println("<ul>");
+        attrs = getServletContext().getAttributeNames();
+        while (attrs.hasMoreElements()) {
+            String attr = (String) attrs.nextElement();
+            out.println("<li><b>" + attr + "</b> = " +
+                           getServletContext().getAttribute(attr));
+        }
+        out.println("</ul>");
+        out.println("<hr>");
+
+
+
+    }
+
+
+
+    /**
+     * Provides CGI Gateway service -- delegates to <code>doGet</code>
+     *
+     * @param  req   HttpServletRequest passed in by servlet container
+     * @param  res   HttpServletResponse passed in by servlet container
+     *
+     * @exception  ServletException  if a servlet-specific exception occurs
+     * @exception  IOException  if a read/write exception occurs
+     *
+     * @see javax.servlet.http.HttpServlet
+     *
+     */
+    protected void doPost(HttpServletRequest req, HttpServletResponse res)
+        throws IOException, ServletException {
+        doGet(req, res);
+    }
+
+
+
+    /**
+     * Provides CGI Gateway service
+     *
+     * @param  req   HttpServletRequest passed in by servlet container
+     * @param  res   HttpServletResponse passed in by servlet container
+     *
+     * @exception  ServletException  if a servlet-specific exception occurs
+     * @exception  IOException  if a read/write exception occurs
+     *
+     * @see javax.servlet.http.HttpServlet
+     *
+     */
+    protected void doGet(HttpServletRequest req, HttpServletResponse res)
+        throws ServletException, IOException {
+
+        // Verify that we were not accessed using the invoker servlet
+        if (req.getAttribute(Globals.INVOKED_ATTR) != null)
+            throw new UnavailableException
+                ("Cannot invoke CGIServlet through the invoker");
+
+        CGIEnvironment cgiEnv = new CGIEnvironment(req, getServletContext());
+
+        if (cgiEnv.isValid()) {
+            CGIRunner cgi = new CGIRunner(cgiEnv.getCommand(),
+                                          cgiEnv.getEnvironment(),
+                                          cgiEnv.getWorkingDirectory(),
+                                          cgiEnv.getParameters());
+            //if POST, we need to cgi.setInput
+            //REMIND: how does this interact with Servlet API 2.3's Filters?!
+            if ("POST".equals(req.getMethod())) {
+                cgi.setInput(req.getInputStream());
+            }
+            cgi.setResponse(res);
+            cgi.run();
+        }
+
+        if (!cgiEnv.isValid()) {
+            res.setStatus(404);
+        }
+ 
+        if (debug >= 10) {
+            try {
+                ServletOutputStream out = res.getOutputStream();
+                out.println("<HTML><HEAD><TITLE>$Name$</TITLE></HEAD>");
+                out.println("<BODY>$Header$<p>");
+
+                if (cgiEnv.isValid()) {
+                    out.println(cgiEnv.toString());
+                } else {
+                    out.println("<H3>");
+                    out.println("CGI script not found or not specified.");
+                    out.println("</H3>");
+                    out.println("<H4>");
+                    out.println("Check the <b>HttpServletRequest ");
+                    out.println("<a href=\"#pathInfo\">pathInfo</a></b> ");
+                    out.println("property to see if it is what you meant ");
+                    out.println("it to be.  You must specify an existant ");
+                    out.println("and executable file as part of the ");
+                    out.println("path-info.");
+                    out.println("</H4>");
+                    out.println("<H4>");
+                    out.println("For a good discussion of how CGI scripts ");
+                    out.println("work and what their environment variables ");
+                    out.println("mean, please visit the <a ");
+                    out.println("href=\"http://cgi-spec.golux.com\">CGI ");
+                    out.println("Specification page</a>.");
+                    out.println("</H4>");
+
+                }
+
+                printServletEnvironment(out, req, res);
+
+                out.println("</BODY></HTML>");
+
+            } catch (IOException ignored) {
+            }
+
+        } //debugging
+
+
+    } //doGet
+
+
+
+    /** For future testing use only; does nothing right now */
+    public static void main(String[] args) {
+        System.out.println("$Header$");
+    }
+
+    /**
+     * Get all shell environment variables. Have to do it this rather ugly way
+     * as the API to obtain is not available in 1.4 and earlier APIs.
+     *
+     * See <a href="http://www.rgagnon.com/javadetails/java-0150.html">Read environment
+     * variables from an application</a> for original source and article.
+     */
+    private Hashtable getShellEnvironment() throws IOException {
+        Hashtable envVars = new Hashtable();
+        Process p = null;
+        Runtime r = Runtime.getRuntime();
+        String OS = System.getProperty("os.name").toLowerCase();
+        boolean ignoreCase;
+
+        if (OS.indexOf("windows 9") > -1) {
+            p = r.exec( "command.com /c set" );
+            ignoreCase = true;
+        } else if ( (OS.indexOf("nt") > -1)
+                || (OS.indexOf("windows 20") > -1)
+                || (OS.indexOf("windows xp") > -1) ) {
+            // thanks to JuanFran for the xp fix!
+            p = r.exec( "cmd.exe /c set" );
+            ignoreCase = true;
+        } else {
+            // our last hope, we assume Unix (thanks to H. Ware for the fix)
+            p = r.exec( "env" );
+            ignoreCase = false;
+        }
+
+        BufferedReader br = new BufferedReader
+            ( new InputStreamReader( p.getInputStream() ) );
+        String line;
+        while( (line = br.readLine()) != null ) {
+            int idx = line.indexOf( '=' );
+            String key = line.substring( 0, idx );
+            String value = line.substring( idx+1 );
+            if (ignoreCase) {
+                key = key.toUpperCase();
+            }
+            envVars.put(key, value);
+        }
+        return envVars;
+    }
+
+
+
+
+
+
+
+    /**
+     * Encapsulates the CGI environment and rules to derive
+     * that environment from the servlet container and request information.
+     *
+     * <p>
+     * </p>
+     *
+     * @version  $Revision: 424503 $, $Date: 2006-07-21 19:19:37 -0500 (Fri, 21 Jul 2006) $
+     * @since    Tomcat 4.0
+     *
+     */
+    protected class CGIEnvironment {
+
+
+        /** context of the enclosing servlet */
+        private ServletContext context = null;
+
+        /** context path of enclosing servlet */
+        private String contextPath = null;
+
+        /** servlet URI of the enclosing servlet */
+        private String servletPath = null;
+
+        /** pathInfo for the current request */
+        private String pathInfo = null;
+
+        /** real file system directory of the enclosing servlet's web app */
+        private String webAppRootDir = null;
+
+        /** tempdir for context - used to expand scripts in unexpanded wars */
+        private File tmpDir = null;
+
+        /** derived cgi environment */
+        private Hashtable env = null;
+
+        /** cgi command to be invoked */
+        private String command = null;
+
+        /** cgi command's desired working directory */
+        private File workingDirectory = null;
+
+        /** cgi command's command line parameters */
+        private ArrayList cmdLineParameters = new ArrayList();
+
+        /** whether or not this object is valid or not */
+        private boolean valid = false;
+
+
+        /**
+         * Creates a CGIEnvironment and derives the necessary environment,
+         * query parameters, working directory, cgi command, etc.
+         *
+         * @param  req       HttpServletRequest for information provided by
+         *                   the Servlet API
+         * @param  context   ServletContext for information provided by the
+         *                   Servlet API
+         *
+         */
+        protected CGIEnvironment(HttpServletRequest req,
+                                 ServletContext context) throws IOException {
+            setupFromContext(context);
+            setupFromRequest(req);
+
+            this.valid = setCGIEnvironment(req);
+
+            if (this.valid) {
+                workingDirectory = new File(command.substring(0,
+                      command.lastIndexOf(File.separator)));
+            }
+
+        }
+
+
+
+        /**
+         * Uses the ServletContext to set some CGI variables
+         *
+         * @param  context   ServletContext for information provided by the
+         *                   Servlet API
+         */
+        protected void setupFromContext(ServletContext context) {
+            this.context = context;
+            this.webAppRootDir = context.getRealPath("/");
+            this.tmpDir = (File) context.getAttribute(Globals.WORK_DIR_ATTR);
+        }
+
+
+
+        /**
+         * Uses the HttpServletRequest to set most CGI variables
+         *
+         * @param  req   HttpServletRequest for information provided by
+         *               the Servlet API
+         * @throws UnsupportedEncodingException 
+         */
+        protected void setupFromRequest(HttpServletRequest req)
+                throws UnsupportedEncodingException {
+            
+            this.contextPath = req.getContextPath();
+            this.servletPath = req.getServletPath();
+            this.pathInfo = req.getPathInfo();
+            // If getPathInfo() returns null, must be using extension mapping
+            // In this case, pathInfo should be same as servletPath
+            if (this.pathInfo == null) {
+                this.pathInfo = this.servletPath;
+            }
+            
+            // If request is HEAD or GET and Query String does not contain
+            // an unencoded "=" this is an indexed query. Parsed Query String
+            // forms command line parameters for cgi command.
+            if (!"GET".equals(req.getMethod()) &&
+                    !"HEAD".equals(req.getMethod()))
+                return;
+            
+            String qs = req.getQueryString();
+            
+            if (qs == null || qs.indexOf("=")>0)
+                return;
+            
+            int delimIndex = 0;
+            int lastDelimIndex = 0;
+            delimIndex = qs.indexOf("+");
+            
+            while (delimIndex >0) {
+                cmdLineParameters.add(URLDecoder.decode(qs.substring(
+                        lastDelimIndex,delimIndex),parameterEncoding));
+                lastDelimIndex = delimIndex + 1;
+                delimIndex = qs.indexOf("+",lastDelimIndex);
+            }
+            cmdLineParameters.add(URLDecoder.decode(qs.substring(
+                    lastDelimIndex),parameterEncoding));
+        }
+
+
+        /**
+         * Resolves core information about the cgi script.
+         *
+         * <p>
+         * Example URI:
+         * <PRE> /servlet/cgigateway/dir1/realCGIscript/pathinfo1 </PRE>
+         * <ul>
+         * <LI><b>path</b> = $CATALINA_HOME/mywebapp/dir1/realCGIscript
+         * <LI><b>scriptName</b> = /servlet/cgigateway/dir1/realCGIscript
+         * <LI><b>cgiName</b> = /dir1/realCGIscript
+         * <LI><b>name</b> = realCGIscript
+         * </ul>
+         * </p>
+         * <p>
+         * CGI search algorithm: search the real path below
+         *    &lt;my-webapp-root&gt; and find the first non-directory in
+         *    the getPathTranslated("/"), reading/searching from left-to-right.
+         *</p>
+         *<p>
+         *   The CGI search path will start at
+         *   webAppRootDir + File.separator + cgiPathPrefix
+         *   (or webAppRootDir alone if cgiPathPrefix is
+         *   null).
+         *</p>
+         *<p>
+         *   cgiPathPrefix is defined by setting
+         *   this servlet's cgiPathPrefix init parameter
+         *
+         *</p>
+         *
+         * @param pathInfo       String from HttpServletRequest.getPathInfo()
+         * @param webAppRootDir  String from context.getRealPath("/")
+         * @param contextPath    String as from
+         *                       HttpServletRequest.getContextPath()
+         * @param servletPath    String as from
+         *                       HttpServletRequest.getServletPath()
+         * @param cgiPathPrefix  subdirectory of webAppRootDir below which
+         *                       the web app's CGIs may be stored; can be null.
+         *                       The CGI search path will start at
+         *                       webAppRootDir + File.separator + cgiPathPrefix
+         *                       (or webAppRootDir alone if cgiPathPrefix is
+         *                       null).  cgiPathPrefix is defined by setting
+         *                       the servlet's cgiPathPrefix init parameter.
+         *
+         *
+         * @return
+         * <ul>
+         * <li>
+         * <code>path</code> -    full file-system path to valid cgi script,
+         *                        or null if no cgi was found
+         * <li>
+         * <code>scriptName</code> -
+         *                        CGI variable SCRIPT_NAME; the full URL path
+         *                        to valid cgi script or null if no cgi was
+         *                        found
+         * <li>
+         * <code>cgiName</code> - servlet pathInfo fragment corresponding to
+         *                        the cgi script itself, or null if not found
+         * <li>
+         * <code>name</code> -    simple name (no directories) of the
+         *                        cgi script, or null if no cgi was found
+         * </ul>
+         *
+         * @since Tomcat 4.0
+         */
+        protected String[] findCGI(String pathInfo, String webAppRootDir,
+                                   String contextPath, String servletPath,
+                                   String cgiPathPrefix) {
+            String path = null;
+            String name = null;
+            String scriptname = null;
+            String cginame = null;
+
+            if ((webAppRootDir != null)
+                && (webAppRootDir.lastIndexOf(File.separator) ==
+                    (webAppRootDir.length() - 1))) {
+                    //strip the trailing "/" from the webAppRootDir
+                    webAppRootDir =
+                    webAppRootDir.substring(0, (webAppRootDir.length() - 1));
+            }
+
+            if (cgiPathPrefix != null) {
+                webAppRootDir = webAppRootDir + File.separator
+                    + cgiPathPrefix;
+            }
+
+            if (debug >= 2) {
+                log("findCGI: path=" + pathInfo + ", " + webAppRootDir);
+            }
+
+            File currentLocation = new File(webAppRootDir);
+            StringTokenizer dirWalker =
+            new StringTokenizer(pathInfo, "/");
+            if (debug >= 3) {
+                log("findCGI: currentLoc=" + currentLocation);
+            }
+            while (!currentLocation.isFile() && dirWalker.hasMoreElements()) {
+                if (debug >= 3) {
+                    log("findCGI: currentLoc=" + currentLocation);
+                }
+                currentLocation = new File(currentLocation,
+                                           (String) dirWalker.nextElement());
+            }
+            if (!currentLocation.isFile()) {
+                return new String[] { null, null, null, null };
+            } else {
+                if (debug >= 2) {
+                    log("findCGI: FOUND cgi at " + currentLocation);
+                }
+                path = currentLocation.getAbsolutePath();
+                name = currentLocation.getName();
+                cginame =
+                currentLocation.getParent().substring(webAppRootDir.length())
+                + File.separator
+                + name;
+
+                if (".".equals(contextPath)) {
+                    scriptname = servletPath + cginame;
+                } else {
+                    scriptname = contextPath + servletPath + cginame;
+                }
+            }
+
+            if (debug >= 1) {
+                log("findCGI calc: name=" + name + ", path=" + path
+                    + ", scriptname=" + scriptname + ", cginame=" + cginame);
+            }
+            return new String[] { path, scriptname, cginame, name };
+        }
+
+        /**
+         * Constructs the CGI environment to be supplied to the invoked CGI
+         * script; relies heavliy on Servlet API methods and findCGI
+         *
+         * @param    req request associated with the CGI
+         *           invokation
+         *
+         * @return   true if environment was set OK, false if there
+         *           was a problem and no environment was set
+         */
+        protected boolean setCGIEnvironment(HttpServletRequest req) throws IOException {
+
+            /*
+             * This method is slightly ugly; c'est la vie.
+             * "You cannot stop [ugliness], you can only hope to contain [it]"
+             * (apologies to Marv Albert regarding MJ)
+             */
+
+            Hashtable envp = new Hashtable();
+
+            // Add the shell environment variables (if any)
+            envp.putAll(shellEnv);
+
+            // Add the CGI environment variables
+            String sPathInfoOrig = null;
+            String sPathTranslatedOrig = null;
+            String sPathInfoCGI = null;
+            String sPathTranslatedCGI = null;
+            String sCGIFullPath = null;
+            String sCGIScriptName = null;
+            String sCGIFullName = null;
+            String sCGIName = null;
+            String[] sCGINames;
+
+
+            sPathInfoOrig = this.pathInfo;
+            sPathInfoOrig = sPathInfoOrig == null ? "" : sPathInfoOrig;
+
+            sPathTranslatedOrig = req.getPathTranslated();
+            sPathTranslatedOrig =
+                sPathTranslatedOrig == null ? "" : sPathTranslatedOrig;
+
+            if (webAppRootDir == null ) {
+                // The app has not been deployed in exploded form
+                webAppRootDir = tmpDir.toString();
+                expandCGIScript();
+            } 
+            
+            sCGINames = findCGI(sPathInfoOrig,
+                                webAppRootDir,
+                                contextPath,
+                                servletPath,
+                                cgiPathPrefix);
+
+            sCGIFullPath = sCGINames[0];
+            sCGIScriptName = sCGINames[1];
+            sCGIFullName = sCGINames[2];
+            sCGIName = sCGINames[3];
+
+            if (sCGIFullPath == null
+                || sCGIScriptName == null
+                || sCGIFullName == null
+                || sCGIName == null) {
+                return false;
+            }
+
+            envp.put("SERVER_SOFTWARE", "TOMCAT");
+
+            envp.put("SERVER_NAME", nullsToBlanks(req.getServerName()));
+
+            envp.put("GATEWAY_INTERFACE", "CGI/1.1");
+
+            envp.put("SERVER_PROTOCOL", nullsToBlanks(req.getProtocol()));
+
+            int port = req.getServerPort();
+            Integer iPort = (port == 0 ? new Integer(-1) : new Integer(port));
+            envp.put("SERVER_PORT", iPort.toString());
+
+            envp.put("REQUEST_METHOD", nullsToBlanks(req.getMethod()));
+
+            envp.put("REQUEST_URI", nullsToBlanks(req.getRequestURI()));
+
+
+            /*-
+             * PATH_INFO should be determined by using sCGIFullName:
+             * 1) Let sCGIFullName not end in a "/" (see method findCGI)
+             * 2) Let sCGIFullName equal the pathInfo fragment which
+             *    corresponds to the actual cgi script.
+             * 3) Thus, PATH_INFO = request.getPathInfo().substring(
+             *                      sCGIFullName.length())
+             *
+             * (see method findCGI, where the real work is done)
+             *
+             */
+            if (pathInfo == null
+                || (pathInfo.substring(sCGIFullName.length()).length() <= 0)) {
+                sPathInfoCGI = "";
+            } else {
+                sPathInfoCGI = pathInfo.substring(sCGIFullName.length());
+            }
+            envp.put("PATH_INFO", sPathInfoCGI);
+
+
+            /*-
+             * PATH_TRANSLATED must be determined after PATH_INFO (and the
+             * implied real cgi-script) has been taken into account.
+             *
+             * The following example demonstrates:
+             *
+             * servlet info   = /servlet/cgigw/dir1/dir2/cgi1/trans1/trans2
+             * cgifullpath    = /servlet/cgigw/dir1/dir2/cgi1
+             * path_info      = /trans1/trans2
+             * webAppRootDir  = servletContext.getRealPath("/")
+             *
+             * path_translated = servletContext.getRealPath("/trans1/trans2")
+             *
+             * That is, PATH_TRANSLATED = webAppRootDir + sPathInfoCGI
+             * (unless sPathInfoCGI is null or blank, then the CGI
+             * specification dictates that the PATH_TRANSLATED metavariable
+             * SHOULD NOT be defined.
+             *
+             */
+            if (sPathInfoCGI != null && !("".equals(sPathInfoCGI))) {
+                sPathTranslatedCGI = context.getRealPath(sPathInfoCGI);
+            } else {
+                sPathTranslatedCGI = null;
+            }
+            if (sPathTranslatedCGI == null || "".equals(sPathTranslatedCGI)) {
+                //NOOP
+            } else {
+                envp.put("PATH_TRANSLATED", nullsToBlanks(sPathTranslatedCGI));
+            }
+
+
+            envp.put("SCRIPT_NAME", nullsToBlanks(sCGIScriptName));
+
+            envp.put("QUERY_STRING", nullsToBlanks(req.getQueryString()));
+
+            envp.put("REMOTE_HOST", nullsToBlanks(req.getRemoteHost()));
+
+            envp.put("REMOTE_ADDR", nullsToBlanks(req.getRemoteAddr()));
+
+            envp.put("AUTH_TYPE", nullsToBlanks(req.getAuthType()));
+
+            envp.put("REMOTE_USER", nullsToBlanks(req.getRemoteUser()));
+
+            envp.put("REMOTE_IDENT", ""); //not necessary for full compliance
+
+            envp.put("CONTENT_TYPE", nullsToBlanks(req.getContentType()));
+
+
+            /* Note CGI spec says CONTENT_LENGTH must be NULL ("") or undefined
+             * if there is no content, so we cannot put 0 or -1 in as per the
+             * Servlet API spec.
+             */
+            int contentLength = req.getContentLength();
+            String sContentLength = (contentLength <= 0 ? "" :
+                                     (new Integer(contentLength)).toString());
+            envp.put("CONTENT_LENGTH", sContentLength);
+
+
+            Enumeration headers = req.getHeaderNames();
+            String header = null;
+            while (headers.hasMoreElements()) {
+                header = null;
+                header = ((String) headers.nextElement()).toUpperCase();
+                //REMIND: rewrite multiple headers as if received as single
+                //REMIND: change character set
+                //REMIND: I forgot what the previous REMIND means
+                if ("AUTHORIZATION".equalsIgnoreCase(header) ||
+                    "PROXY_AUTHORIZATION".equalsIgnoreCase(header)) {
+                    //NOOP per CGI specification section 11.2
+                } else {
+                    envp.put("HTTP_" + header.replace('-', '_'),
+                             req.getHeader(header));
+                }
+            }
+
+            File fCGIFullPath = new File(sCGIFullPath);
+            command = fCGIFullPath.getCanonicalPath();
+
+            envp.put("X_TOMCAT_SCRIPT_PATH", command);  //for kicks
+
+            this.env = envp;
+
+            return true;
+
+        }
+
+        /**
+         * Extracts requested resource from web app archive to context work 
+         * directory to enable CGI script to be executed.
+         */
+        protected void expandCGIScript() {
+            StringBuffer srcPath = new StringBuffer();
+            StringBuffer destPath = new StringBuffer();
+            InputStream is = null;
+
+            // paths depend on mapping
+            if (cgiPathPrefix == null ) {
+                srcPath.append(pathInfo);
+                is = context.getResourceAsStream(srcPath.toString());
+                destPath.append(tmpDir);
+                destPath.append(pathInfo);
+            } else {
+                // essentially same search algorithm as findCGI()
+                srcPath.append(cgiPathPrefix);
+                StringTokenizer pathWalker =
+                        new StringTokenizer (pathInfo, "/");
+                // start with first element
+                while (pathWalker.hasMoreElements() && (is == null)) {
+                    srcPath.append("/");
+                    srcPath.append(pathWalker.nextElement());
+                    is = context.getResourceAsStream(srcPath.toString());
+                }
+                destPath.append(tmpDir);
+                destPath.append("/");
+                destPath.append(srcPath);
+            }
+
+            if (is == null) {
+                // didn't find anything, give up now
+                if (debug >= 2) {
+                    log("expandCGIScript: source '" + srcPath + "' not found");
+                }
+                 return;
+            }
+
+            File f = new File(destPath.toString());
+            if (f.exists()) {
+                // Don't need to expand if it already exists
+                return;
+            } 
+
+            // create directories
+            String dirPath = new String (destPath.toString().substring(
+                    0,destPath.toString().lastIndexOf("/")));
+            File dir = new File(dirPath);
+            dir.mkdirs();
+
+            try {
+                synchronized (expandFileLock) {
+                    // make sure file doesn't exist
+                    if (f.exists()) {
+                        return;
+                    }
+
+                    // create file
+                    if (!f.createNewFile()) {
+                        return;
+                    }
+                    FileOutputStream fos = new FileOutputStream(f);
+
+                    // copy data
+                    IOTools.flow(is, fos);
+                    is.close();
+                    fos.close();
+                    if (debug >= 2) {
+                        log("expandCGIScript: expanded '" + srcPath + "' to '" + destPath + "'");
+                    }
+                }
+            } catch (IOException ioe) {
+                // delete in case file is corrupted 
+                if (f.exists()) {
+                    f.delete();
+                }
+            }
+        }
+
+
+        /**
+         * Print important CGI environment information in a easy-to-read HTML
+         * table
+         *
+         * @return  HTML string containing CGI environment info
+         *
+         */
+        public String toString() {
+
+            StringBuffer sb = new StringBuffer();
+
+            sb.append("<TABLE border=2>");
+
+            sb.append("<tr><th colspan=2 bgcolor=grey>");
+            sb.append("CGIEnvironment Info</th></tr>");
+
+            sb.append("<tr><td>Debug Level</td><td>");
+            sb.append(debug);
+            sb.append("</td></tr>");
+
+            sb.append("<tr><td>Validity:</td><td>");
+            sb.append(isValid());
+            sb.append("</td></tr>");
+
+            if (isValid()) {
+                Enumeration envk = env.keys();
+                while (envk.hasMoreElements()) {
+                    String s = (String) envk.nextElement();
+                    sb.append("<tr><td>");
+                    sb.append(s);
+                    sb.append("</td><td>");
+                    sb.append(blanksToString((String) env.get(s),
+                                             "[will be set to blank]"));
+                    sb.append("</td></tr>");
+                }
+            }
+
+            sb.append("<tr><td colspan=2><HR></td></tr>");
+
+            sb.append("<tr><td>Derived Command</td><td>");
+            sb.append(nullsToBlanks(command));
+            sb.append("</td></tr>");
+
+            sb.append("<tr><td>Working Directory</td><td>");
+            if (workingDirectory != null) {
+                sb.append(workingDirectory.toString());
+            }
+            sb.append("</td></tr>");
+
+            sb.append("<tr><td>Command Line Params</td><td>");
+            for (int i=0; i < cmdLineParameters.size(); i++) {
+                String param = (String) cmdLineParameters.get(i);
+                sb.append("<p>");
+                sb.append(param);
+                sb.append("</p>");
+            }
+            sb.append("</td></tr>");
+
+            sb.append("</TABLE><p>end.");
+
+            return sb.toString();
+        }
+
+
+
+        /**
+         * Gets derived command string
+         *
+         * @return  command string
+         *
+         */
+        protected String getCommand() {
+            return command;
+        }
+
+
+
+        /**
+         * Gets derived CGI working directory
+         *
+         * @return  working directory
+         *
+         */
+        protected File getWorkingDirectory() {
+            return workingDirectory;
+        }
+
+
+
+        /**
+         * Gets derived CGI environment
+         *
+         * @return   CGI environment
+         *
+         */
+        protected Hashtable getEnvironment() {
+            return env;
+        }
+
+
+
+        /**
+         * Gets derived CGI query parameters
+         *
+         * @return   CGI query parameters
+         *
+         */
+        protected ArrayList getParameters() {
+            return cmdLineParameters;
+        }
+
+
+
+        /**
+         * Gets validity status
+         *
+         * @return   true if this environment is valid, false
+         *           otherwise
+         *
+         */
+        protected boolean isValid() {
+            return valid;
+        }
+
+
+
+        /**
+         * Converts null strings to blank strings ("")
+         *
+         * @param    s string to be converted if necessary
+         * @return   a non-null string, either the original or the empty string
+         *           ("") if the original was <code>null</code>
+         */
+        protected String nullsToBlanks(String s) {
+            return nullsToString(s, "");
+        }
+
+
+
+        /**
+         * Converts null strings to another string
+         *
+         * @param    couldBeNull string to be converted if necessary
+         * @param    subForNulls string to return instead of a null string
+         * @return   a non-null string, either the original or the substitute
+         *           string if the original was <code>null</code>
+         */
+        protected String nullsToString(String couldBeNull,
+                                       String subForNulls) {
+            return (couldBeNull == null ? subForNulls : couldBeNull);
+        }
+
+
+
+        /**
+         * Converts blank strings to another string
+         *
+         * @param    couldBeBlank string to be converted if necessary
+         * @param    subForBlanks string to return instead of a blank string
+         * @return   a non-null string, either the original or the substitute
+         *           string if the original was <code>null</code> or empty ("")
+         */
+        protected String blanksToString(String couldBeBlank,
+                                      String subForBlanks) {
+            return (("".equals(couldBeBlank) || couldBeBlank == null)
+                    ? subForBlanks
+                    : couldBeBlank);
+        }
+
+
+
+    } //class CGIEnvironment
+
+
+
+
+
+
+    /**
+     * Encapsulates the knowledge of how to run a CGI script, given the
+     * script's desired environment and (optionally) input/output streams
+     *
+     * <p>
+     *
+     * Exposes a <code>run</code> method used to actually invoke the
+     * CGI.
+     *
+     * </p>
+     * <p>
+     *
+     * The CGI environment and settings are derived from the information
+     * passed to the constuctor.
+     *
+     * </p>
+     * <p>
+     *
+     * The input and output streams can be set by the <code>setInput</code>
+     * and <code>setResponse</code> methods, respectively.
+     * </p>
+     *
+     * @version   $Revision: 424503 $, $Date: 2006-07-21 19:19:37 -0500 (Fri, 21 Jul 2006) $
+     */
+
+    protected class CGIRunner {
+
+        /** script/command to be executed */
+        private String command = null;
+
+        /** environment used when invoking the cgi script */
+        private Hashtable env = null;
+
+        /** working directory used when invoking the cgi script */
+        private File wd = null;
+
+        /** command line parameters to be passed to the invoked script */
+        private ArrayList params = null;
+
+        /** stdin to be passed to cgi script */
+        private InputStream stdin = null;
+
+        /** response object used to set headers & get output stream */
+        private HttpServletResponse response = null;
+
+        /** boolean tracking whether this object has enough info to run() */
+        private boolean readyToRun = false;
+
+
+
+
+        /**
+         *  Creates a CGIRunner and initializes its environment, working
+         *  directory, and query parameters.
+         *  <BR>
+         *  Input/output streams (optional) are set using the
+         *  <code>setInput</code> and <code>setResponse</code> methods,
+         *  respectively.
+         *
+         * @param  command  string full path to command to be executed
+         * @param  env      Hashtable with the desired script environment
+         * @param  wd       File with the script's desired working directory
+         * @param  params   ArrayList with the script's query command line
+         *                  paramters as strings
+         */
+        protected CGIRunner(String command, Hashtable env, File wd,
+                            ArrayList params) {
+            this.command = command;
+            this.env = env;
+            this.wd = wd;
+            this.params = params;
+            updateReadyStatus();
+        }
+
+
+
+        /**
+         * Checks & sets ready status
+         */
+        protected void updateReadyStatus() {
+            if (command != null
+                && env != null
+                && wd != null
+                && params != null
+                && response != null) {
+                readyToRun = true;
+            } else {
+                readyToRun = false;
+            }
+        }
+
+
+
+        /**
+         * Gets ready status
+         *
+         * @return   false if not ready (<code>run</code> will throw
+         *           an exception), true if ready
+         */
+        protected boolean isReady() {
+            return readyToRun;
+        }
+
+
+
+        /**
+         * Sets HttpServletResponse object used to set headers and send
+         * output to
+         *
+         * @param  response   HttpServletResponse to be used
+         *
+         */
+        protected void setResponse(HttpServletResponse response) {
+            this.response = response;
+            updateReadyStatus();
+        }
+
+
+
+        /**
+         * Sets standard input to be passed on to the invoked cgi script
+         *
+         * @param  stdin   InputStream to be used
+         *
+         */
+        protected void setInput(InputStream stdin) {
+            this.stdin = stdin;
+            updateReadyStatus();
+        }
+
+
+
+        /**
+         * Converts a Hashtable to a String array by converting each
+         * key/value pair in the Hashtable to a String in the form
+         * "key=value" (hashkey + "=" + hash.get(hashkey).toString())
+         *
+         * @param  h   Hashtable to convert
+         *
+         * @return     converted string array
+         *
+         * @exception  NullPointerException   if a hash key has a null value
+         *
+         */
+        protected String[] hashToStringArray(Hashtable h)
+            throws NullPointerException {
+            Vector v = new Vector();
+            Enumeration e = h.keys();
+            while (e.hasMoreElements()) {
+                String k = e.nextElement().toString();
+                v.add(k + "=" + h.get(k));
+            }
+            String[] strArr = new String[v.size()];
+            v.copyInto(strArr);
+            return strArr;
+        }
+
+
+
+        /**
+         * Executes a CGI script with the desired environment, current working
+         * directory, and input/output streams
+         *
+         * <p>
+         * This implements the following CGI specification recommedations:
+         * <UL>
+         * <LI> Servers SHOULD provide the "<code>query</code>" component of
+         *      the script-URI as command-line arguments to scripts if it
+         *      does not contain any unencoded "=" characters and the
+         *      command-line arguments can be generated in an unambiguous
+         *      manner.
+         * <LI> Servers SHOULD set the AUTH_TYPE metavariable to the value
+         *      of the "<code>auth-scheme</code>" token of the
+         *      "<code>Authorization</code>" if it was supplied as part of the
+         *      request header.  See <code>getCGIEnvironment</code> method.
+         * <LI> Where applicable, servers SHOULD set the current working
+         *      directory to the directory in which the script is located
+         *      before invoking it.
+         * <LI> Server implementations SHOULD define their behavior for the
+         *      following cases:
+         *     <ul>
+         *     <LI> <u>Allowed characters in pathInfo</u>:  This implementation
+         *             does not allow ASCII NUL nor any character which cannot
+         *             be URL-encoded according to internet standards;
+         *     <LI> <u>Allowed characters in path segments</u>: This
+         *             implementation does not allow non-terminal NULL
+         *             segments in the the path -- IOExceptions may be thrown;
+         *     <LI> <u>"<code>.</code>" and "<code>..</code>" path
+         *             segments</u>:
+         *             This implementation does not allow "<code>.</code>" and
+         *             "<code>..</code>" in the the path, and such characters
+         *             will result in an IOException being thrown;
+         *     <LI> <u>Implementation limitations</u>: This implementation
+         *             does not impose any limitations except as documented
+         *             above.  This implementation may be limited by the
+         *             servlet container used to house this implementation.
+         *             In particular, all the primary CGI variable values
+         *             are derived either directly or indirectly from the
+         *             container's implementation of the Servlet API methods.
+         *     </ul>
+         * </UL>
+         * </p>
+         *
+         * @exception IOException if problems during reading/writing occur
+         *
+         * @see    java.lang.Runtime#exec(String command, String[] envp,
+         *                                File dir)
+         */
+        protected void run() throws IOException {
+
+            /*
+             * REMIND:  this method feels too big; should it be re-written?
+             */
+
+            if (!isReady()) {
+                throw new IOException(this.getClass().getName()
+                                      + ": not ready to run.");
+            }
+
+            if (debug >= 1 ) {
+                log("runCGI(envp=[" + env + "], command=" + command + ")");
+            }
+
+            if ((command.indexOf(File.separator + "." + File.separator) >= 0)
+                || (command.indexOf(File.separator + "..") >= 0)
+                || (command.indexOf(".." + File.separator) >= 0)) {
+                throw new IOException(this.getClass().getName()
+                                      + "Illegal Character in CGI command "
+                                      + "path ('.' or '..') detected.  Not "
+                                      + "running CGI [" + command + "].");
+            }
+
+            /* original content/structure of this section taken from
+             * http://developer.java.sun.com/developer/
+             *                               bugParade/bugs/4216884.html
+             * with major modifications by Martin Dengler
+             */
+            Runtime rt = null;
+            InputStream cgiOutput = null;
+            BufferedReader commandsStdErr = null;
+            BufferedOutputStream commandsStdIn = null;
+            Process proc = null;
+            int bufRead = -1;
+
+            //create query arguments
+            StringBuffer cmdAndArgs = new StringBuffer();
+            if (command.indexOf(" ") < 0) {
+                cmdAndArgs.append(command);
+            } else {
+                // Spaces used as delimiter, so need to use quotes
+                cmdAndArgs.append("\"");
+                cmdAndArgs.append(command);
+                cmdAndArgs.append("\"");
+            }
+
+            for (int i=0; i < params.size(); i++) {
+                cmdAndArgs.append(" ");
+                String param = (String) params.get(i);
+                if (param.indexOf(" ") < 0) {
+                    cmdAndArgs.append(param);
+                } else {
+                    // Spaces used as delimiter, so need to use quotes
+                    cmdAndArgs.append("\"");
+                    cmdAndArgs.append(param);
+                    cmdAndArgs.append("\"");
+                }
+            }
+
+            StringBuffer command = new StringBuffer(cgiExecutable);
+            command.append(" ");
+            command.append(cmdAndArgs.toString());
+            cmdAndArgs = command;
+
+            try {
+                rt = Runtime.getRuntime();
+                proc = rt.exec(cmdAndArgs.toString(), hashToStringArray(env), wd);
+    
+                String sContentLength = (String) env.get("CONTENT_LENGTH");
+
+                if(!"".equals(sContentLength)) {
+                    commandsStdIn = new BufferedOutputStream(proc.getOutputStream());
+                    IOTools.flow(stdin, commandsStdIn);
+                    commandsStdIn.flush();
+                    commandsStdIn.close();
+                }
+
+                /* we want to wait for the process to exit,  Process.waitFor()
+                 * is useless in our situation; see
+                 * http://developer.java.sun.com/developer/
+                 *                               bugParade/bugs/4223650.html
+                 */
+
+                boolean isRunning = true;
+                commandsStdErr = new BufferedReader
+                    (new InputStreamReader(proc.getErrorStream()));
+                final BufferedReader stdErrRdr = commandsStdErr ;
+
+                new Thread() {
+                    public void run () {
+                        sendToLog(stdErrRdr) ;
+                    } ;
+                }.start() ;
+
+                InputStream cgiHeaderStream =
+                    new HTTPHeaderInputStream(proc.getInputStream());
+                BufferedReader cgiHeaderReader =
+                    new BufferedReader(new InputStreamReader(cgiHeaderStream));
+            
+                while (isRunning) {
+                    try {
+                        //set headers
+                        String line = null;
+                        while (((line = cgiHeaderReader.readLine()) != null)
+                               && !("".equals(line))) {
+                            if (debug >= 2) {
+                                log("runCGI: addHeader(\"" + line + "\")");
+                            }
+                            if (line.startsWith("HTTP")) {
+                                response.setStatus(getSCFromHttpStatusLine(line));
+                            } else if (line.indexOf(":") >= 0) {
+                                String header =
+                                    line.substring(0, line.indexOf(":")).trim();
+                                String value =
+                                    line.substring(line.indexOf(":") + 1).trim(); 
+                                if (header.equalsIgnoreCase("status")) {
+                                    response.setStatus(getSCFromCGIStatusHeader(value));
+                                } else {
+                                    response.addHeader(header , value);
+                                }
+                            } else {
+                                log("runCGI: bad header line \"" + line + "\"");
+                            }
+                        }
+    
+                        //write output
+                        byte[] bBuf = new byte[2048];
+    
+                        OutputStream out = response.getOutputStream();
+                        cgiOutput = proc.getInputStream();
+    
+                        try {
+                            while ((bufRead = cgiOutput.read(bBuf)) != -1) {
+                                if (debug >= 4) {
+                                    log("runCGI: output " + bufRead +
+                                        " bytes of data");
+                                }
+                                out.write(bBuf, 0, bufRead);
+                            }
+                        } finally {
+                            // Attempt to consume any leftover byte if something bad happens,
+                            // such as a socket disconnect on the servlet side; otherwise, the
+                            // external process could hang
+                            if (bufRead != -1) {
+                                while ((bufRead = cgiOutput.read(bBuf)) != -1) {}
+                            }
+                        }
+        
+                        proc.exitValue(); // Throws exception if alive
+    
+                        isRunning = false;
+    
+                    } catch (IllegalThreadStateException e) {
+                        try {
+                            Thread.sleep(500);
+                        } catch (InterruptedException ignored) {
+                        }
+                    }
+                } //replacement for Process.waitFor()
+    
+                // Close the output stream used
+                cgiOutput.close();
+            }
+            catch (IOException e){
+                log ("Caught exception " + e);
+                throw new IOException (e.toString());
+            }
+            finally{
+                if (debug > 4) {
+                    log ("Running finally block");
+                }
+                if (proc != null){
+                    proc.destroy();
+                    proc = null;
+                }
+            }
+        }
+
+        /**
+         * Parses the Status-Line and extracts the status code.
+         * 
+         * @param line The HTTP Status-Line (RFC2616, section 6.1)
+         * @return The extracted status code or the code representing an
+         * internal error if a valid status code cannot be extracted. 
+         */
+        private int getSCFromHttpStatusLine(String line) {
+            int statusStart = line.indexOf(' ') + 1;
+            
+            if (statusStart < 1 || line.length() < statusStart + 3) {
+                // Not a valid HTTP Status-Line
+                log ("runCGI: invalid HTTP Status-Line:" + line);
+                return HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
+            }
+            
+            String status = line.substring(statusStart, statusStart + 3);
+            
+            int statusCode;
+            try {
+                statusCode = Integer.parseInt(status);
+            } catch (NumberFormatException nfe) {
+                // Not a valid status code
+                log ("runCGI: invalid status code:" + status);
+                return HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
+            }
+            
+            return statusCode;
+        }
+
+        /**
+         * Parses the CGI Status Header value and extracts the status code.
+         * 
+         * @param value The CGI Status value of the form <code>
+         *             digit digit digit SP reason-phrase</code>
+         * @return The extracted status code or the code representing an
+         * internal error if a valid status code cannot be extracted. 
+         */
+        private int getSCFromCGIStatusHeader(String value) {
+            if (value.length() < 3) {
+                // Not a valid status value
+                log ("runCGI: invalid status value:" + value);
+                return HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
+            }
+            
+            String status = value.substring(0, 3);
+            
+            int statusCode;
+            try {
+                statusCode = Integer.parseInt(status);
+            } catch (NumberFormatException nfe) {
+                // Not a valid status code
+                log ("runCGI: invalid status code:" + status);
+                return HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
+            }
+            
+            return statusCode;
+        }
+        
+        private void sendToLog(BufferedReader rdr) {
+            String line = null;
+            int lineCount = 0 ;
+            try {
+                while ((line = rdr.readLine()) != null) {
+                    log("runCGI (stderr):" +  line) ;
+                    lineCount++ ;
+                }
+            } catch (IOException e) {
+                log("sendToLog error", e) ;
+            } finally {
+                try {
+                    rdr.close() ;
+                } catch (IOException ce) {
+                    log("sendToLog error", ce) ;
+                } ;
+            } ;
+            if ( lineCount > 0 && debug > 2) {
+                log("runCGI: " + lineCount + " lines received on stderr") ;
+            } ;
+        }
+    } //class CGIRunner
+
+    /**
+     * This is an input stream specifically for reading HTTP headers. It reads
+     * upto and including the two blank lines terminating the headers. It
+     * allows the content to be read using bytes or characters as appropriate.
+     */
+    protected class HTTPHeaderInputStream extends InputStream {
+        private static final int STATE_CHARACTER = 0;
+        private static final int STATE_FIRST_CR = 1;
+        private static final int STATE_FIRST_LF = 2;
+        private static final int STATE_SECOND_CR = 3;
+        private static final int STATE_HEADER_END = 4;
+        
+        private InputStream input;
+        private int state;
+        
+        HTTPHeaderInputStream(InputStream theInput) {
+            input = theInput;
+            state = STATE_CHARACTER;
+        }
+
+        /**
+         * @see java.io.InputStream#read()
+         */
+        public int read() throws IOException {
+            if (state == STATE_HEADER_END) {
+                return -1;
+            }
+
+            int i = input.read();
+
+            // Update the state
+            // State machine looks like this
+            //
+            //    -------->--------
+            //   |      (CR)       |
+            //   |                 |
+            //  CR1--->---         |
+            //   |        |        |
+            //   ^(CR)    |(LF)    |
+            //   |        |        |
+            // CHAR--->--LF1--->--EOH
+            //      (LF)  |  (LF)  |
+            //            |(CR)    ^(LF)
+            //            |        |
+            //          (CR2)-->---
+            
+            if (i == 10) {
+                // LF
+                switch(state) {
+                    case STATE_CHARACTER:
+                        state = STATE_FIRST_LF;
+                        break;
+                    case STATE_FIRST_CR:
+                        state = STATE_FIRST_LF;
+                        break;
+                    case STATE_FIRST_LF:
+                    case STATE_SECOND_CR:
+                        state = STATE_HEADER_END;
+                        break;
+                }
+
+            } else if (i == 13) {
+                // CR
+                switch(state) {
+                    case STATE_CHARACTER:
+                        state = STATE_FIRST_CR;
+                        break;
+                    case STATE_FIRST_CR:
+                        state = STATE_HEADER_END;
+                        break;
+                    case STATE_FIRST_LF:
+                        state = STATE_SECOND_CR;
+                        break;
+                }
+
+            } else {
+                state = STATE_CHARACTER;
+            }
+            
+            return i;            
+        }
+    }  // class HTTPHeaderInputStream
+
+} //class CGIServlet

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/servlets/Constants.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/servlets/Constants.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/servlets/Constants.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,26 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.servlets;
+
+
+public class Constants {
+
+    public static final String Package = "org.apache.catalina.servlets";
+
+}
+

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/servlets/DefaultServlet.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/servlets/DefaultServlet.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/servlets/DefaultServlet.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,2214 @@
+/*
+ * Copyright 1999,2004-2006 The Apache Software Foundation.
+ *
+ * Licensed 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.servlets;
+
+
+import java.io.BufferedInputStream;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+import java.io.RandomAccessFile;
+import java.io.Reader;
+import java.io.StringReader;
+import java.io.StringWriter;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.StringTokenizer;
+
+import javax.naming.InitialContext;
+import javax.naming.NameClassPair;
+import javax.naming.NamingEnumeration;
+import javax.naming.NamingException;
+import javax.naming.directory.DirContext;
+import javax.servlet.ServletException;
+import javax.servlet.ServletOutputStream;
+import javax.servlet.UnavailableException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.xml.transform.Source;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.stream.StreamResult;
+import javax.xml.transform.stream.StreamSource;
+
+import org.apache.catalina.Globals;
+import org.apache.catalina.util.ServerInfo;
+import org.apache.catalina.util.StringManager;
+import org.apache.catalina.util.URLEncoder;
+import org.apache.naming.resources.CacheEntry;
+import org.apache.naming.resources.ProxyDirContext;
+import org.apache.naming.resources.Resource;
+import org.apache.naming.resources.ResourceAttributes;
+
+
+/**
+ * The default resource-serving servlet for most web applications,
+ * used to serve static resources such as HTML pages and images.
+ *
+ * @author Craig R. McClanahan
+ * @author Remy Maucherat
+ * @version $Revision: 393784 $ $Date: 2006-04-13 06:19:06 -0500 (Thu, 13 Apr 2006) $
+ */
+
+public class DefaultServlet
+    extends HttpServlet {
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The debugging detail level for this servlet.
+     */
+    protected int debug = 0;
+
+
+    /**
+     * The input buffer size to use when serving resources.
+     */
+    protected int input = 2048;
+
+
+    /**
+     * Should we generate directory listings?
+     */
+    protected boolean listings = false;
+
+
+    /**
+     * Read only flag. By default, it's set to true.
+     */
+    protected boolean readOnly = true;
+
+
+    /**
+     * The output buffer size to use when serving resources.
+     */
+    protected int output = 2048;
+
+
+    /**
+     * Array containing the safe characters set.
+     */
+    protected static URLEncoder urlEncoder;
+
+
+    /**
+     * Allow customized directory listing per directory.
+     */
+    protected String  localXsltFile = null;
+
+
+    /**
+     * Allow customized directory listing per instance.
+     */
+    protected String  globalXsltFile = null;
+
+
+    /**
+     * Allow a readme file to be included.
+     */
+    protected String readmeFile = null;
+
+
+    /**
+     * Proxy directory context.
+     */
+    protected ProxyDirContext resources = null;
+
+
+    /**
+     * File encoding to be used when reading static files. If none is specified
+     * the platform default is used.
+     */
+    protected String fileEncoding = null;
+    
+    
+    /**
+     * Minimum size for sendfile usage in bytes.
+     */
+    protected int sendfileSize = 48 * 1024;
+    
+    
+    /**
+     * Full range marker.
+     */
+    protected static ArrayList FULL = new ArrayList();
+    
+    
+    // ----------------------------------------------------- Static Initializer
+
+
+    /**
+     * GMT timezone - all HTTP dates are on GMT
+     */
+    static {
+        urlEncoder = new URLEncoder();
+        urlEncoder.addSafeCharacter('-');
+        urlEncoder.addSafeCharacter('_');
+        urlEncoder.addSafeCharacter('.');
+        urlEncoder.addSafeCharacter('*');
+        urlEncoder.addSafeCharacter('/');
+    }
+
+
+    /**
+     * MIME multipart separation string
+     */
+    protected static final String mimeSeparation = "CATALINA_MIME_BOUNDARY";
+
+
+    /**
+     * JNDI resources name.
+     */
+    protected static final String RESOURCES_JNDI_NAME = "java:/comp/Resources";
+
+
+    /**
+     * The string manager for this package.
+     */
+    protected static StringManager sm =
+        StringManager.getManager(Constants.Package);
+
+
+    /**
+     * Size of file transfer buffer in bytes.
+     */
+    protected static final int BUFFER_SIZE = 4096;
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Finalize this servlet.
+     */
+    public void destroy() {
+    }
+
+
+    /**
+     * Initialize this servlet.
+     */
+    public void init() throws ServletException {
+
+        // Set our properties from the initialization parameters
+        String value = null;
+        try {
+            value = getServletConfig().getInitParameter("debug");
+            debug = Integer.parseInt(value);
+        } catch (Throwable t) {
+            ;
+        }
+        try {
+            value = getServletConfig().getInitParameter("input");
+            input = Integer.parseInt(value);
+        } catch (Throwable t) {
+            ;
+        }
+        try {
+            value = getServletConfig().getInitParameter("listings");
+            listings = (new Boolean(value)).booleanValue();
+        } catch (Throwable t) {
+            ;
+        }
+        try {
+            value = getServletConfig().getInitParameter("readonly");
+            if (value != null)
+                readOnly = (new Boolean(value)).booleanValue();
+        } catch (Throwable t) {
+            ;
+        }
+        try {
+            value = getServletConfig().getInitParameter("output");
+            output = Integer.parseInt(value);
+        } catch (Throwable t) {
+            ;
+        }
+        try {
+            value = getServletConfig().getInitParameter("sendfileSize");
+            sendfileSize = Integer.parseInt(value) * 1024;
+        } catch (Throwable t) {
+            ;
+        }
+        try {
+            value = getServletConfig().getInitParameter("fileEncoding");
+            fileEncoding = value;
+        } catch (Throwable t) {
+            ;
+        }
+
+        globalXsltFile = getServletConfig().getInitParameter("globalXsltFile");
+        localXsltFile = getServletConfig().getInitParameter("localXsltFile");
+        readmeFile = getServletConfig().getInitParameter("readmeFile");
+
+        // Sanity check on the specified buffer sizes
+        if (input < 256)
+            input = 256;
+        if (output < 256)
+            output = 256;
+
+        if (debug > 0) {
+            log("DefaultServlet.init:  input buffer size=" + input +
+                ", output buffer size=" + output);
+        }
+
+        // Load the proxy dir context.
+        try {
+            resources = (ProxyDirContext) getServletContext()
+                .getAttribute(Globals.RESOURCES_ATTR);
+        } catch(ClassCastException e) {
+            // Failed : Not the right type
+        }
+        if (resources == null) {
+            try {
+                resources =
+                    (ProxyDirContext) new InitialContext()
+                    .lookup(RESOURCES_JNDI_NAME);
+            } catch (NamingException e) {
+                // Failed
+            } catch (ClassCastException e) {
+                // Failed : Not the right type
+            }
+        }
+
+        if (resources == null) {
+            throw new UnavailableException("No resources");
+        }
+
+    }
+
+
+    // ------------------------------------------------------ Protected Methods
+
+
+    /**
+     * Return the relative path associated with this servlet.
+     *
+     * @param request The servlet request we are processing
+     */
+    protected String getRelativePath(HttpServletRequest request) {
+
+        // Are we being processed by a RequestDispatcher.include()?
+        if (request.getAttribute(Globals.INCLUDE_REQUEST_URI_ATTR) != null) {
+            String result = (String) request.getAttribute(
+                                            Globals.INCLUDE_PATH_INFO_ATTR);
+            if (result == null)
+                result = (String) request.getAttribute(
+                                            Globals.INCLUDE_SERVLET_PATH_ATTR);
+            if ((result == null) || (result.equals("")))
+                result = "/";
+            return (result);
+        }
+
+        // No, extract the desired path directly from the request
+        String result = request.getPathInfo();
+        if (result == null) {
+            result = request.getServletPath();
+        }
+        if ((result == null) || (result.equals(""))) {
+            result = "/";
+        }
+        return (result);
+
+    }
+
+
+    /**
+     * Process a GET request for the specified resource.
+     *
+     * @param request The servlet request we are processing
+     * @param response The servlet response we are creating
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception ServletException if a servlet-specified error occurs
+     */
+    protected void doGet(HttpServletRequest request,
+                         HttpServletResponse response)
+        throws IOException, ServletException {
+
+        // Serve the requested resource, including the data content
+        try {
+            serveResource(request, response, true);
+        } catch( IOException ex ) {
+            // we probably have this check somewhere else too.
+            if( ex.getMessage() != null
+                && ex.getMessage().indexOf("Broken pipe") >= 0 ) {
+                // ignore it.
+            }
+            throw ex;
+        }
+
+    }
+
+
+    /**
+     * Process a HEAD request for the specified resource.
+     *
+     * @param request The servlet request we are processing
+     * @param response The servlet response we are creating
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception ServletException if a servlet-specified error occurs
+     */
+    protected void doHead(HttpServletRequest request,
+                          HttpServletResponse response)
+        throws IOException, ServletException {
+
+        // Serve the requested resource, without the data content
+        serveResource(request, response, false);
+
+    }
+
+
+    /**
+     * Process a POST request for the specified resource.
+     *
+     * @param request The servlet request we are processing
+     * @param response The servlet response we are creating
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception ServletException if a servlet-specified error occurs
+     */
+    protected void doPost(HttpServletRequest request,
+                          HttpServletResponse response)
+        throws IOException, ServletException {
+        doGet(request, response);
+    }
+
+
+    /**
+     * Process a POST request for the specified resource.
+     *
+     * @param req The servlet request we are processing
+     * @param resp The servlet response we are creating
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception ServletException if a servlet-specified error occurs
+     */
+    protected void doPut(HttpServletRequest req, HttpServletResponse resp)
+        throws ServletException, IOException {
+
+        if (readOnly) {
+            resp.sendError(HttpServletResponse.SC_FORBIDDEN);
+            return;
+        }
+
+        String path = getRelativePath(req);
+
+        boolean exists = true;
+        try {
+            resources.lookup(path);
+        } catch (NamingException e) {
+            exists = false;
+        }
+
+        boolean result = true;
+
+        // Temp. content file used to support partial PUT
+        File contentFile = null;
+
+        Range range = parseContentRange(req, resp);
+
+        InputStream resourceInputStream = null;
+
+        // Append data specified in ranges to existing content for this
+        // resource - create a temp. file on the local filesystem to
+        // perform this operation
+        // Assume just one range is specified for now
+        if (range != null) {
+            contentFile = executePartialPut(req, range, path);
+            resourceInputStream = new FileInputStream(contentFile);
+        } else {
+            resourceInputStream = req.getInputStream();
+        }
+
+        try {
+            Resource newResource = new Resource(resourceInputStream);
+            // FIXME: Add attributes
+            if (exists) {
+                resources.rebind(path, newResource);
+            } else {
+                resources.bind(path, newResource);
+            }
+        } catch(NamingException e) {
+            result = false;
+        }
+
+        if (result) {
+            if (exists) {
+                resp.setStatus(HttpServletResponse.SC_NO_CONTENT);
+            } else {
+                resp.setStatus(HttpServletResponse.SC_CREATED);
+            }
+        } else {
+            resp.sendError(HttpServletResponse.SC_CONFLICT);
+        }
+
+    }
+
+
+    /**
+     * Handle a partial PUT.  New content specified in request is appended to
+     * existing content in oldRevisionContent (if present). This code does
+     * not support simultaneous partial updates to the same resource.
+     */
+    protected File executePartialPut(HttpServletRequest req, Range range,
+                                     String path)
+        throws IOException {
+
+        // Append data specified in ranges to existing content for this
+        // resource - create a temp. file on the local filesystem to
+        // perform this operation
+        File tempDir = (File) getServletContext().getAttribute
+            ("javax.servlet.context.tempdir");
+        // Convert all '/' characters to '.' in resourcePath
+        String convertedResourcePath = path.replace('/', '.');
+        File contentFile = new File(tempDir, convertedResourcePath);
+        if (contentFile.createNewFile()) {
+            // Clean up contentFile when Tomcat is terminated
+            contentFile.deleteOnExit();
+        }
+
+        RandomAccessFile randAccessContentFile =
+            new RandomAccessFile(contentFile, "rw");
+
+        Resource oldResource = null;
+        try {
+            Object obj = resources.lookup(path);
+            if (obj instanceof Resource)
+                oldResource = (Resource) obj;
+        } catch (NamingException e) {
+        }
+
+        // Copy data in oldRevisionContent to contentFile
+        if (oldResource != null) {
+            BufferedInputStream bufOldRevStream =
+                new BufferedInputStream(oldResource.streamContent(),
+                                        BUFFER_SIZE);
+
+            int numBytesRead;
+            byte[] copyBuffer = new byte[BUFFER_SIZE];
+            while ((numBytesRead = bufOldRevStream.read(copyBuffer)) != -1) {
+                randAccessContentFile.write(copyBuffer, 0, numBytesRead);
+            }
+
+            bufOldRevStream.close();
+        }
+
+        randAccessContentFile.setLength(range.length);
+
+        // Append data in request input stream to contentFile
+        randAccessContentFile.seek(range.start);
+        int numBytesRead;
+        byte[] transferBuffer = new byte[BUFFER_SIZE];
+        BufferedInputStream requestBufInStream =
+            new BufferedInputStream(req.getInputStream(), BUFFER_SIZE);
+        while ((numBytesRead = requestBufInStream.read(transferBuffer)) != -1) {
+            randAccessContentFile.write(transferBuffer, 0, numBytesRead);
+        }
+        randAccessContentFile.close();
+        requestBufInStream.close();
+
+        return contentFile;
+
+    }
+
+
+    /**
+     * Process a POST request for the specified resource.
+     *
+     * @param req The servlet request we are processing
+     * @param resp The servlet response we are creating
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception ServletException if a servlet-specified error occurs
+     */
+    protected void doDelete(HttpServletRequest req, HttpServletResponse resp)
+        throws ServletException, IOException {
+
+        if (readOnly) {
+            resp.sendError(HttpServletResponse.SC_FORBIDDEN);
+            return;
+        }
+
+        String path = getRelativePath(req);
+
+        boolean exists = true;
+        try {
+            resources.lookup(path);
+        } catch (NamingException e) {
+            exists = false;
+        }
+
+        if (exists) {
+            boolean result = true;
+            try {
+                resources.unbind(path);
+            } catch (NamingException e) {
+                result = false;
+            }
+            if (result) {
+                resp.setStatus(HttpServletResponse.SC_NO_CONTENT);
+            } else {
+                resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED);
+            }
+        } else {
+            resp.sendError(HttpServletResponse.SC_NOT_FOUND);
+        }
+
+    }
+
+
+    /**
+     * Check if the conditions specified in the optional If headers are
+     * satisfied.
+     *
+     * @param request The servlet request we are processing
+     * @param response The servlet response we are creating
+     * @param resourceAttributes The resource information
+     * @return boolean true if the resource meets all the specified conditions,
+     * and false if any of the conditions is not satisfied, in which case
+     * request processing is stopped
+     */
+    protected boolean checkIfHeaders(HttpServletRequest request,
+                                     HttpServletResponse response,
+                                     ResourceAttributes resourceAttributes)
+        throws IOException {
+
+        return checkIfMatch(request, response, resourceAttributes)
+            && checkIfModifiedSince(request, response, resourceAttributes)
+            && checkIfNoneMatch(request, response, resourceAttributes)
+            && checkIfUnmodifiedSince(request, response, resourceAttributes);
+
+    }
+
+
+    /**
+     * Get the ETag associated with a file.
+     *
+     * @param resourceAttributes The resource information
+     */
+    protected String getETag(ResourceAttributes resourceAttributes) {
+        String result = null;
+        if ((result = resourceAttributes.getETag(true)) != null) {
+            return result;
+        } else if ((result = resourceAttributes.getETag()) != null) {
+            return result;
+        } else {
+            return "W/\"" + resourceAttributes.getContentLength() + "-"
+                + resourceAttributes.getLastModified() + "\"";
+        }
+    }
+
+
+    /**
+     * URL rewriter.
+     *
+     * @param path Path which has to be rewiten
+     */
+    protected String rewriteUrl(String path) {
+        return urlEncoder.encode( path );
+    }
+
+
+    /**
+     * Display the size of a file.
+     */
+    protected void displaySize(StringBuffer buf, int filesize) {
+
+        int leftside = filesize / 1024;
+        int rightside = (filesize % 1024) / 103;  // makes 1 digit
+        // To avoid 0.0 for non-zero file, we bump to 0.1
+        if (leftside == 0 && rightside == 0 && filesize != 0)
+            rightside = 1;
+        buf.append(leftside).append(".").append(rightside);
+        buf.append(" KB");
+
+    }
+
+
+    /**
+     * Serve the specified resource, optionally including the data content.
+     *
+     * @param request The servlet request we are processing
+     * @param response The servlet response we are creating
+     * @param content Should the content be included?
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception ServletException if a servlet-specified error occurs
+     */
+    protected void serveResource(HttpServletRequest request,
+                                 HttpServletResponse response,
+                                 boolean content)
+        throws IOException, ServletException {
+
+        // Identify the requested resource path
+        String path = getRelativePath(request);
+        if (debug > 0) {
+            if (content)
+                log("DefaultServlet.serveResource:  Serving resource '" +
+                    path + "' headers and data");
+            else
+                log("DefaultServlet.serveResource:  Serving resource '" +
+                    path + "' headers only");
+        }
+
+        CacheEntry cacheEntry = resources.lookupCache(path);
+
+        if (!cacheEntry.exists) {
+            // Check if we're included so we can return the appropriate 
+            // missing resource name in the error
+            String requestUri = (String) request.getAttribute(
+                                            Globals.INCLUDE_REQUEST_URI_ATTR);
+            if (requestUri == null) {
+                requestUri = request.getRequestURI();
+            } else {
+                // We're included, and the response.sendError() below is going
+                // to be ignored by the resource that is including us.
+                // Therefore, the only way we can let the including resource
+                // know is by including warning message in response
+                response.getWriter().write(
+                    sm.getString("defaultServlet.missingResource",
+                    requestUri));
+            }
+
+            response.sendError(HttpServletResponse.SC_NOT_FOUND,
+                               requestUri);
+            return;
+        }
+
+        // If the resource is not a collection, and the resource path
+        // ends with "/" or "\", return NOT FOUND
+        if (cacheEntry.context == null) {
+            if (path.endsWith("/") || (path.endsWith("\\"))) {
+                // Check if we're included so we can return the appropriate 
+                // missing resource name in the error
+                String requestUri = (String) request.getAttribute(
+                                            Globals.INCLUDE_REQUEST_URI_ATTR);
+                if (requestUri == null) {
+                    requestUri = request.getRequestURI();
+                }
+                response.sendError(HttpServletResponse.SC_NOT_FOUND,
+                                   requestUri);
+                return;
+            }
+        }
+
+        // Check if the conditions specified in the optional If headers are
+        // satisfied.
+        if (cacheEntry.context == null) {
+
+            // Checking If headers
+            boolean included =
+                (request.getAttribute(Globals.INCLUDE_CONTEXT_PATH_ATTR) != null);
+            if (!included
+                && !checkIfHeaders(request, response, cacheEntry.attributes)) {
+                return;
+            }
+
+        }
+
+        // Find content type.
+        String contentType = cacheEntry.attributes.getMimeType();
+        if (contentType == null) {
+            contentType = getServletContext().getMimeType(cacheEntry.name);
+            cacheEntry.attributes.setMimeType(contentType);
+        }
+
+        ArrayList ranges = null;
+        long contentLength = -1L;
+
+        if (cacheEntry.context != null) {
+
+            // Skip directory listings if we have been configured to
+            // suppress them
+            if (!listings) {
+                response.sendError(HttpServletResponse.SC_NOT_FOUND,
+                                   request.getRequestURI());
+                return;
+            }
+            contentType = "text/html;charset=UTF-8";
+
+        } else {
+
+            // Parse range specifier
+
+            ranges = parseRange(request, response, cacheEntry.attributes);
+
+            // ETag header
+            response.setHeader("ETag", getETag(cacheEntry.attributes));
+
+            // Last-Modified header
+            response.setHeader("Last-Modified",
+                    cacheEntry.attributes.getLastModifiedHttp());
+
+            // Get content length
+            contentLength = cacheEntry.attributes.getContentLength();
+            // Special case for zero length files, which would cause a
+            // (silent) ISE when setting the output buffer size
+            if (contentLength == 0L) {
+                content = false;
+            }
+
+        }
+
+        ServletOutputStream ostream = null;
+        PrintWriter writer = null;
+
+        if (content) {
+
+            // Trying to retrieve the servlet output stream
+
+            try {
+                ostream = response.getOutputStream();
+            } catch (IllegalStateException e) {
+                // If it fails, we try to get a Writer instead if we're
+                // trying to serve a text file
+                if ( (contentType == null)
+                     || (contentType.startsWith("text")) ) {
+                    writer = response.getWriter();
+                } else {
+                    throw e;
+                }
+            }
+
+        }
+
+        if ( (cacheEntry.context != null) 
+                || ( ((ranges == null) || (ranges.isEmpty()))
+                        && (request.getHeader("Range") == null) )
+                || (ranges == FULL) ) {
+
+            // Set the appropriate output headers
+            if (contentType != null) {
+                if (debug > 0)
+                    log("DefaultServlet.serveFile:  contentType='" +
+                        contentType + "'");
+                response.setContentType(contentType);
+            }
+            if ((cacheEntry.resource != null) && (contentLength >= 0)) {
+                if (debug > 0)
+                    log("DefaultServlet.serveFile:  contentLength=" +
+                        contentLength);
+                if (contentLength < Integer.MAX_VALUE) {
+                    response.setContentLength((int) contentLength);
+                } else {
+                    // Set the content-length as String to be able to use a long
+                    response.setHeader("content-length", "" + contentLength);
+                }
+            }
+
+            InputStream renderResult = null;
+            if (cacheEntry.context != null) {
+
+                if (content) {
+                    // Serve the directory browser
+                    renderResult =
+                        render(request.getContextPath(), cacheEntry);
+                }
+
+            }
+
+            // Copy the input stream to our output stream (if requested)
+            if (content) {
+                try {
+                    response.setBufferSize(output);
+                } catch (IllegalStateException e) {
+                    // Silent catch
+                }
+                if (ostream != null) {
+                    if (!checkSendfile(request, response, cacheEntry, contentLength, null))
+                        copy(cacheEntry, renderResult, ostream);
+                } else {
+                    copy(cacheEntry, renderResult, writer);
+                }
+            }
+
+        } else {
+
+            if ((ranges == null) || (ranges.isEmpty()))
+                return;
+
+            // Partial content response.
+
+            response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);
+
+            if (ranges.size() == 1) {
+
+                Range range = (Range) ranges.get(0);
+                response.addHeader("Content-Range", "bytes "
+                                   + range.start
+                                   + "-" + range.end + "/"
+                                   + range.length);
+                long length = range.end - range.start + 1;
+                if (length < Integer.MAX_VALUE) {
+                    response.setContentLength((int) length);
+                } else {
+                    // Set the content-length as String to be able to use a long
+                    response.setHeader("content-length", "" + length);
+                }
+
+                if (contentType != null) {
+                    if (debug > 0)
+                        log("DefaultServlet.serveFile:  contentType='" +
+                            contentType + "'");
+                    response.setContentType(contentType);
+                }
+
+                if (content) {
+                    try {
+                        response.setBufferSize(output);
+                    } catch (IllegalStateException e) {
+                        // Silent catch
+                    }
+                    if (ostream != null) {
+                        if (!checkSendfile(request, response, cacheEntry, range.end - range.start + 1, range))
+                            copy(cacheEntry, ostream, range);
+                    } else {
+                        copy(cacheEntry, writer, range);
+                    }
+                }
+
+            } else {
+
+                response.setContentType("multipart/byteranges; boundary="
+                                        + mimeSeparation);
+
+                if (content) {
+                    try {
+                        response.setBufferSize(output);
+                    } catch (IllegalStateException e) {
+                        // Silent catch
+                    }
+                    if (ostream != null) {
+                        copy(cacheEntry, ostream, ranges.iterator(),
+                             contentType);
+                    } else {
+                        copy(cacheEntry, writer, ranges.iterator(),
+                             contentType);
+                    }
+                }
+
+            }
+
+        }
+
+    }
+
+
+    /**
+     * Parse the content-range header.
+     *
+     * @param request The servlet request we are processing
+     * @param response The servlet response we are creating
+     * @return Range
+     */
+    protected Range parseContentRange(HttpServletRequest request,
+                                      HttpServletResponse response)
+        throws IOException {
+
+        // Retrieving the content-range header (if any is specified
+        String rangeHeader = request.getHeader("Content-Range");
+
+        if (rangeHeader == null)
+            return null;
+
+        // bytes is the only range unit supported
+        if (!rangeHeader.startsWith("bytes")) {
+            response.sendError(HttpServletResponse.SC_BAD_REQUEST);
+            return null;
+        }
+
+        rangeHeader = rangeHeader.substring(6).trim();
+
+        int dashPos = rangeHeader.indexOf('-');
+        int slashPos = rangeHeader.indexOf('/');
+
+        if (dashPos == -1) {
+            response.sendError(HttpServletResponse.SC_BAD_REQUEST);
+            return null;
+        }
+
+        if (slashPos == -1) {
+            response.sendError(HttpServletResponse.SC_BAD_REQUEST);
+            return null;
+        }
+
+        Range range = new Range();
+
+        try {
+            range.start = Long.parseLong(rangeHeader.substring(0, dashPos));
+            range.end =
+                Long.parseLong(rangeHeader.substring(dashPos + 1, slashPos));
+            range.length = Long.parseLong
+                (rangeHeader.substring(slashPos + 1, rangeHeader.length()));
+        } catch (NumberFormatException e) {
+            response.sendError(HttpServletResponse.SC_BAD_REQUEST);
+            return null;
+        }
+
+        if (!range.validate()) {
+            response.sendError(HttpServletResponse.SC_BAD_REQUEST);
+            return null;
+        }
+
+        return range;
+
+    }
+
+
+    /**
+     * Parse the range header.
+     *
+     * @param request The servlet request we are processing
+     * @param response The servlet response we are creating
+     * @return Vector of ranges
+     */
+    protected ArrayList parseRange(HttpServletRequest request,
+                                HttpServletResponse response,
+                                ResourceAttributes resourceAttributes)
+        throws IOException {
+
+        // Checking If-Range
+        String headerValue = request.getHeader("If-Range");
+
+        if (headerValue != null) {
+
+            long headerValueTime = (-1L);
+            try {
+                headerValueTime = request.getDateHeader("If-Range");
+            } catch (Exception e) {
+                ;
+            }
+
+            String eTag = getETag(resourceAttributes);
+            long lastModified = resourceAttributes.getLastModified();
+
+            if (headerValueTime == (-1L)) {
+
+                // If the ETag the client gave does not match the entity
+                // etag, then the entire entity is returned.
+                if (!eTag.equals(headerValue.trim()))
+                    return FULL;
+
+            } else {
+
+                // If the timestamp of the entity the client got is older than
+                // the last modification date of the entity, the entire entity
+                // is returned.
+                if (lastModified > (headerValueTime + 1000))
+                    return FULL;
+
+            }
+
+        }
+
+        long fileLength = resourceAttributes.getContentLength();
+
+        if (fileLength == 0)
+            return null;
+
+        // Retrieving the range header (if any is specified
+        String rangeHeader = request.getHeader("Range");
+
+        if (rangeHeader == null)
+            return null;
+        // bytes is the only range unit supported (and I don't see the point
+        // of adding new ones).
+        if (!rangeHeader.startsWith("bytes")) {
+            response.addHeader("Content-Range", "bytes */" + fileLength);
+            response.sendError
+                (HttpServletResponse.SC_REQUESTED_RANGE_NOT_SATISFIABLE);
+            return null;
+        }
+
+        rangeHeader = rangeHeader.substring(6);
+
+        // Vector which will contain all the ranges which are successfully
+        // parsed.
+        ArrayList result = new ArrayList();
+        StringTokenizer commaTokenizer = new StringTokenizer(rangeHeader, ",");
+
+        // Parsing the range list
+        while (commaTokenizer.hasMoreTokens()) {
+            String rangeDefinition = commaTokenizer.nextToken().trim();
+
+            Range currentRange = new Range();
+            currentRange.length = fileLength;
+
+            int dashPos = rangeDefinition.indexOf('-');
+
+            if (dashPos == -1) {
+                response.addHeader("Content-Range", "bytes */" + fileLength);
+                response.sendError
+                    (HttpServletResponse.SC_REQUESTED_RANGE_NOT_SATISFIABLE);
+                return null;
+            }
+
+            if (dashPos == 0) {
+
+                try {
+                    long offset = Long.parseLong(rangeDefinition);
+                    currentRange.start = fileLength + offset;
+                    currentRange.end = fileLength - 1;
+                } catch (NumberFormatException e) {
+                    response.addHeader("Content-Range",
+                                       "bytes */" + fileLength);
+                    response.sendError
+                        (HttpServletResponse
+                         .SC_REQUESTED_RANGE_NOT_SATISFIABLE);
+                    return null;
+                }
+
+            } else {
+
+                try {
+                    currentRange.start = Long.parseLong
+                        (rangeDefinition.substring(0, dashPos));
+                    if (dashPos < rangeDefinition.length() - 1)
+                        currentRange.end = Long.parseLong
+                            (rangeDefinition.substring
+                             (dashPos + 1, rangeDefinition.length()));
+                    else
+                        currentRange.end = fileLength - 1;
+                } catch (NumberFormatException e) {
+                    response.addHeader("Content-Range",
+                                       "bytes */" + fileLength);
+                    response.sendError
+                        (HttpServletResponse
+                         .SC_REQUESTED_RANGE_NOT_SATISFIABLE);
+                    return null;
+                }
+
+            }
+
+            if (!currentRange.validate()) {
+                response.addHeader("Content-Range", "bytes */" + fileLength);
+                response.sendError
+                    (HttpServletResponse.SC_REQUESTED_RANGE_NOT_SATISFIABLE);
+                return null;
+            }
+
+            result.add(currentRange);
+        }
+
+        return result;
+    }
+
+
+
+    /**
+     *  Decide which way to render. HTML or XML.
+     */
+    protected InputStream render
+        (String contextPath, CacheEntry cacheEntry) {
+        InputStream xsltInputStream =
+            findXsltInputStream(cacheEntry.context);
+
+        if (xsltInputStream==null) {
+            return renderHtml(contextPath, cacheEntry);
+        } else {
+            return renderXml(contextPath, cacheEntry, xsltInputStream);
+        }
+
+    }
+
+    /**
+     * Return an InputStream to an HTML representation of the contents
+     * of this directory.
+     *
+     * @param contextPath Context path to which our internal paths are
+     *  relative
+     */
+    protected InputStream renderXml(String contextPath,
+                                    CacheEntry cacheEntry,
+                                    InputStream xsltInputStream) {
+
+        StringBuffer sb = new StringBuffer();
+
+        sb.append("<?xml version=\"1.0\"?>");
+        sb.append("<listing ");
+        sb.append(" contextPath='");
+        sb.append(contextPath);
+        sb.append("'");
+        sb.append(" directory='");
+        sb.append(cacheEntry.name);
+        sb.append("' ");
+        sb.append(" hasParent='").append(!cacheEntry.name.equals("/"));
+        sb.append("'>");
+
+        sb.append("<entries>");
+
+        try {
+
+            // Render the directory entries within this directory
+            NamingEnumeration enumeration = resources.list(cacheEntry.name);
+            
+            // rewriteUrl(contextPath) is expensive. cache result for later reuse
+            String rewrittenContextPath =  rewriteUrl(contextPath);
+
+            while (enumeration.hasMoreElements()) {
+
+                NameClassPair ncPair = (NameClassPair) enumeration.nextElement();
+                String resourceName = ncPair.getName();
+                String trimmed = resourceName/*.substring(trim)*/;
+                if (trimmed.equalsIgnoreCase("WEB-INF") ||
+                    trimmed.equalsIgnoreCase("META-INF") ||
+                    trimmed.equalsIgnoreCase(localXsltFile))
+                    continue;
+
+                CacheEntry childCacheEntry =
+                    resources.lookupCache(cacheEntry.name + resourceName);
+                if (!childCacheEntry.exists) {
+                    continue;
+                }
+
+                sb.append("<entry");
+                sb.append(" type='")
+                  .append((childCacheEntry.context != null)?"dir":"file")
+                  .append("'");
+                sb.append(" urlPath='")
+                  .append(rewrittenContextPath)
+                  .append(rewriteUrl(cacheEntry.name + resourceName))
+                  .append((childCacheEntry.context != null)?"/":"")
+                  .append("'");
+                if (childCacheEntry.resource != null) {
+                    sb.append(" size='")
+                      .append(renderSize(childCacheEntry.attributes.getContentLength()))
+                      .append("'");
+                }
+                sb.append(" date='")
+                  .append(childCacheEntry.attributes.getLastModifiedHttp())
+                  .append("'");
+
+                sb.append(">");
+                sb.append(trimmed);
+                if (childCacheEntry.context != null)
+                    sb.append("/");
+                sb.append("</entry>");
+
+            }
+
+        } catch (NamingException e) {
+            // Something went wrong
+            e.printStackTrace();
+        }
+
+        sb.append("</entries>");
+
+        String readme = getReadme(cacheEntry.context);
+
+        if (readme!=null) {
+            sb.append("<readme><![CDATA[");
+            sb.append(readme);
+            sb.append("]]></readme>");
+        }
+
+
+        sb.append("</listing>");
+
+
+        try {
+            TransformerFactory tFactory = TransformerFactory.newInstance();
+            Source xmlSource = new StreamSource(new StringReader(sb.toString()));
+            Source xslSource = new StreamSource(xsltInputStream);
+            Transformer transformer = tFactory.newTransformer(xslSource);
+
+            ByteArrayOutputStream stream = new ByteArrayOutputStream();
+            OutputStreamWriter osWriter = new OutputStreamWriter(stream, "UTF8");
+            StreamResult out = new StreamResult(osWriter);
+            transformer.transform(xmlSource, out);
+            osWriter.flush();
+            return (new ByteArrayInputStream(stream.toByteArray()));
+        } catch (Exception e) {
+            log("directory transform failure: " + e.getMessage());
+            return renderHtml(contextPath, cacheEntry);
+        }
+    }
+
+    /**
+     * Return an InputStream to an HTML representation of the contents
+     * of this directory.
+     *
+     * @param contextPath Context path to which our internal paths are
+     *  relative
+     */
+    protected InputStream renderHtml
+        (String contextPath, CacheEntry cacheEntry) {
+
+        String name = cacheEntry.name;
+
+        // Number of characters to trim from the beginnings of filenames
+        int trim = name.length();
+        if (!name.endsWith("/"))
+            trim += 1;
+        if (name.equals("/"))
+            trim = 1;
+
+        // Prepare a writer to a buffered area
+        ByteArrayOutputStream stream = new ByteArrayOutputStream();
+        OutputStreamWriter osWriter = null;
+        try {
+            osWriter = new OutputStreamWriter(stream, "UTF8");
+        } catch (Exception e) {
+            // Should never happen
+            osWriter = new OutputStreamWriter(stream);
+        }
+        PrintWriter writer = new PrintWriter(osWriter);
+
+        StringBuffer sb = new StringBuffer();
+        
+        // rewriteUrl(contextPath) is expensive. cache result for later reuse
+        String rewrittenContextPath =  rewriteUrl(contextPath);
+
+        // Render the page header
+        sb.append("<html>\r\n");
+        sb.append("<head>\r\n");
+        sb.append("<title>");
+        sb.append(sm.getString("directory.title", name));
+        sb.append("</title>\r\n");
+        sb.append("<STYLE><!--");
+        sb.append(org.apache.catalina.util.TomcatCSS.TOMCAT_CSS);
+        sb.append("--></STYLE> ");
+        sb.append("</head>\r\n");
+        sb.append("<body>");
+        sb.append("<h1>");
+        sb.append(sm.getString("directory.title", name));
+
+        // Render the link to our parent (if required)
+        String parentDirectory = name;
+        if (parentDirectory.endsWith("/")) {
+            parentDirectory =
+                parentDirectory.substring(0, parentDirectory.length() - 1);
+        }
+        int slash = parentDirectory.lastIndexOf('/');
+        if (slash >= 0) {
+            String parent = name.substring(0, slash);
+            sb.append(" - <a href=\"");
+            sb.append(rewrittenContextPath);
+            if (parent.equals(""))
+                parent = "/";
+            sb.append(rewriteUrl(parent));
+            if (!parent.endsWith("/"))
+                sb.append("/");
+            sb.append("\">");
+            sb.append("<b>");
+            sb.append(sm.getString("directory.parent", parent));
+            sb.append("</b>");
+            sb.append("</a>");
+        }
+
+        sb.append("</h1>");
+        sb.append("<HR size=\"1\" noshade=\"noshade\">");
+
+        sb.append("<table width=\"100%\" cellspacing=\"0\"" +
+                     " cellpadding=\"5\" align=\"center\">\r\n");
+
+        // Render the column headings
+        sb.append("<tr>\r\n");
+        sb.append("<td align=\"left\"><font size=\"+1\"><strong>");
+        sb.append(sm.getString("directory.filename"));
+        sb.append("</strong></font></td>\r\n");
+        sb.append("<td align=\"center\"><font size=\"+1\"><strong>");
+        sb.append(sm.getString("directory.size"));
+        sb.append("</strong></font></td>\r\n");
+        sb.append("<td align=\"right\"><font size=\"+1\"><strong>");
+        sb.append(sm.getString("directory.lastModified"));
+        sb.append("</strong></font></td>\r\n");
+        sb.append("</tr>");
+
+        try {
+
+            // Render the directory entries within this directory
+            NamingEnumeration enumeration = resources.list(cacheEntry.name);
+            boolean shade = false;
+            while (enumeration.hasMoreElements()) {
+
+                NameClassPair ncPair = (NameClassPair) enumeration.nextElement();
+                String resourceName = ncPair.getName();
+                String trimmed = resourceName/*.substring(trim)*/;
+                if (trimmed.equalsIgnoreCase("WEB-INF") ||
+                    trimmed.equalsIgnoreCase("META-INF"))
+                    continue;
+
+                CacheEntry childCacheEntry =
+                    resources.lookupCache(cacheEntry.name + resourceName);
+                if (!childCacheEntry.exists) {
+                    continue;
+                }
+
+                sb.append("<tr");
+                if (shade)
+                    sb.append(" bgcolor=\"#eeeeee\"");
+                sb.append(">\r\n");
+                shade = !shade;
+
+                sb.append("<td align=\"left\">&nbsp;&nbsp;\r\n");
+                sb.append("<a href=\"");
+                sb.append(rewrittenContextPath);
+                resourceName = rewriteUrl(name + resourceName);
+                sb.append(resourceName);
+                if (childCacheEntry.context != null)
+                    sb.append("/");
+                sb.append("\"><tt>");
+                sb.append(trimmed);
+                if (childCacheEntry.context != null)
+                    sb.append("/");
+                sb.append("</tt></a></td>\r\n");
+
+                sb.append("<td align=\"right\"><tt>");
+                if (childCacheEntry.context != null)
+                    sb.append("&nbsp;");
+                else
+                    sb.append(renderSize(childCacheEntry.attributes.getContentLength()));
+                sb.append("</tt></td>\r\n");
+
+                sb.append("<td align=\"right\"><tt>");
+                sb.append(childCacheEntry.attributes.getLastModifiedHttp());
+                sb.append("</tt></td>\r\n");
+
+                sb.append("</tr>\r\n");
+            }
+
+        } catch (NamingException e) {
+            // Something went wrong
+            e.printStackTrace();
+        }
+
+        // Render the page footer
+        sb.append("</table>\r\n");
+
+        sb.append("<HR size=\"1\" noshade=\"noshade\">");
+
+        String readme = getReadme(cacheEntry.context);
+        if (readme!=null) {
+            sb.append(readme);
+            sb.append("<HR size=\"1\" noshade=\"noshade\">");
+        }
+
+        sb.append("<h3>").append(ServerInfo.getServerInfo()).append("</h3>");
+        sb.append("</body>\r\n");
+        sb.append("</html>\r\n");
+
+        // Return an input stream to the underlying bytes
+        writer.write(sb.toString());
+        writer.flush();
+        return (new ByteArrayInputStream(stream.toByteArray()));
+
+    }
+
+
+    /**
+     * Render the specified file size (in bytes).
+     *
+     * @param size File size (in bytes)
+     */
+    protected String renderSize(long size) {
+
+        long leftSide = size / 1024;
+        long rightSide = (size % 1024) / 103;   // Makes 1 digit
+        if ((leftSide == 0) && (rightSide == 0) && (size > 0))
+            rightSide = 1;
+
+        return ("" + leftSide + "." + rightSide + " kb");
+
+    }
+
+
+    /**
+     * Get the readme file as a string.
+     */
+    protected String getReadme(DirContext directory) {
+        if (readmeFile!=null) {
+            try {
+                Object obj = directory.lookup(readmeFile);
+
+                if (obj!=null && obj instanceof Resource) {
+                    StringWriter buffer = new StringWriter();
+                    InputStream is = ((Resource)obj).streamContent();
+                    copyRange(new InputStreamReader(is),
+                              new PrintWriter(buffer));
+
+                    return buffer.toString();
+                 }
+             } catch(Throwable e) {
+                 ; /* Should only be IOException or NamingException
+                    * can be ignored
+                    */
+             }
+        }
+
+        return null;
+    }
+
+
+    /**
+     * Return the xsl template inputstream (if possible)
+     */
+    protected InputStream findXsltInputStream(DirContext directory) {
+
+        if (localXsltFile!=null) {
+            try {
+                Object obj = directory.lookup(localXsltFile);
+                if (obj!=null && obj instanceof Resource) {
+                    InputStream is = ((Resource)obj).streamContent();
+                    if (is!=null)
+                        return is;
+                }
+             } catch(Throwable e) {
+                 ; /* Should only be IOException or NamingException
+                    * can be ignored
+                    */
+             }
+        }
+
+        /*  Open and read in file in one fell swoop to reduce chance
+         *  chance of leaving handle open.
+         */
+        if (globalXsltFile!=null) {
+            FileInputStream fis = null;
+
+            try {
+                File f = new File(globalXsltFile);
+                if (f.exists()){
+                    fis =new FileInputStream(f);
+                    byte b[] = new byte[(int)f.length()]; /* danger! */
+                    fis.read(b);
+                    return new ByteArrayInputStream(b);
+                }
+            } catch(Throwable e) {
+                log("This shouldn't happen (?)...", e);
+                return null;
+            } finally {
+                try {
+                    if (fis!=null)
+                        fis.close();
+                } catch(Throwable e){
+                    ;
+                }
+            }
+        }
+
+        return null;
+
+    }
+
+
+    // -------------------------------------------------------- protected Methods
+
+
+    /**
+     * Check if sendfile can be used.
+     */
+    protected boolean checkSendfile(HttpServletRequest request,
+                                  HttpServletResponse response,
+                                  CacheEntry entry,
+                                  long length, Range range) {
+        if ((sendfileSize > 0)
+            && (entry.resource != null)
+            && ((length > sendfileSize) || (entry.resource.getContent() == null))
+            && (entry.attributes.getCanonicalPath() != null)
+            && (Boolean.TRUE == request.getAttribute("org.apache.tomcat.sendfile.support"))
+            && (request.getClass().getName().equals("org.apache.catalina.connector.RequestFacade"))
+            && (response.getClass().getName().equals("org.apache.catalina.connector.ResponseFacade"))) {
+            request.setAttribute("org.apache.tomcat.sendfile.filename", entry.attributes.getCanonicalPath());
+            if (range == null) {
+                request.setAttribute("org.apache.tomcat.sendfile.start", new Long(0L));
+                request.setAttribute("org.apache.tomcat.sendfile.end", new Long(length));
+            } else {
+                request.setAttribute("org.apache.tomcat.sendfile.start", new Long(range.start));
+                request.setAttribute("org.apache.tomcat.sendfile.end", new Long(range.end + 1));
+            }
+            request.setAttribute("org.apache.tomcat.sendfile.token", this);
+            return true;
+        } else {
+            return false;
+        }
+    }
+    
+    
+    /**
+     * Check if the if-match condition is satisfied.
+     *
+     * @param request The servlet request we are processing
+     * @param response The servlet response we are creating
+     * @param resourceInfo File object
+     * @return boolean true if the resource meets the specified condition,
+     * and false if the condition is not satisfied, in which case request
+     * processing is stopped
+     */
+    protected boolean checkIfMatch(HttpServletRequest request,
+                                 HttpServletResponse response,
+                                 ResourceAttributes resourceAttributes)
+        throws IOException {
+
+        String eTag = getETag(resourceAttributes);
+        String headerValue = request.getHeader("If-Match");
+        if (headerValue != null) {
+            if (headerValue.indexOf('*') == -1) {
+
+                StringTokenizer commaTokenizer = new StringTokenizer
+                    (headerValue, ",");
+                boolean conditionSatisfied = false;
+
+                while (!conditionSatisfied && commaTokenizer.hasMoreTokens()) {
+                    String currentToken = commaTokenizer.nextToken();
+                    if (currentToken.trim().equals(eTag))
+                        conditionSatisfied = true;
+                }
+
+                // If none of the given ETags match, 412 Precodition failed is
+                // sent back
+                if (!conditionSatisfied) {
+                    response.sendError
+                        (HttpServletResponse.SC_PRECONDITION_FAILED);
+                    return false;
+                }
+
+            }
+        }
+        return true;
+
+    }
+
+
+    /**
+     * Check if the if-modified-since condition is satisfied.
+     *
+     * @param request The servlet request we are processing
+     * @param response The servlet response we are creating
+     * @param resourceInfo File object
+     * @return boolean true if the resource meets the specified condition,
+     * and false if the condition is not satisfied, in which case request
+     * processing is stopped
+     */
+    protected boolean checkIfModifiedSince(HttpServletRequest request,
+                                         HttpServletResponse response,
+                                         ResourceAttributes resourceAttributes)
+        throws IOException {
+        try {
+            long headerValue = request.getDateHeader("If-Modified-Since");
+            long lastModified = resourceAttributes.getLastModified();
+            if (headerValue != -1) {
+
+                // If an If-None-Match header has been specified, if modified since
+                // is ignored.
+                if ((request.getHeader("If-None-Match") == null)
+                    && (lastModified <= headerValue + 1000)) {
+                    // The entity has not been modified since the date
+                    // specified by the client. This is not an error case.
+                    response.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
+                    return false;
+                }
+            }
+        } catch(IllegalArgumentException illegalArgument) {
+            return true;
+        }
+        return true;
+
+    }
+
+
+    /**
+     * Check if the if-none-match condition is satisfied.
+     *
+     * @param request The servlet request we are processing
+     * @param response The servlet response we are creating
+     * @param resourceInfo File object
+     * @return boolean true if the resource meets the specified condition,
+     * and false if the condition is not satisfied, in which case request
+     * processing is stopped
+     */
+    protected boolean checkIfNoneMatch(HttpServletRequest request,
+                                     HttpServletResponse response,
+                                     ResourceAttributes resourceAttributes)
+        throws IOException {
+
+        String eTag = getETag(resourceAttributes);
+        String headerValue = request.getHeader("If-None-Match");
+        if (headerValue != null) {
+
+            boolean conditionSatisfied = false;
+
+            if (!headerValue.equals("*")) {
+
+                StringTokenizer commaTokenizer =
+                    new StringTokenizer(headerValue, ",");
+
+                while (!conditionSatisfied && commaTokenizer.hasMoreTokens()) {
+                    String currentToken = commaTokenizer.nextToken();
+                    if (currentToken.trim().equals(eTag))
+                        conditionSatisfied = true;
+                }
+
+            } else {
+                conditionSatisfied = true;
+            }
+
+            if (conditionSatisfied) {
+
+                // For GET and HEAD, we should respond with
+                // 304 Not Modified.
+                // For every other method, 412 Precondition Failed is sent
+                // back.
+                if ( ("GET".equals(request.getMethod()))
+                     || ("HEAD".equals(request.getMethod())) ) {
+                    response.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
+                    return false;
+                } else {
+                    response.sendError
+                        (HttpServletResponse.SC_PRECONDITION_FAILED);
+                    return false;
+                }
+            }
+        }
+        return true;
+
+    }
+
+
+    /**
+     * Check if the if-unmodified-since condition is satisfied.
+     *
+     * @param request The servlet request we are processing
+     * @param response The servlet response we are creating
+     * @param resourceInfo File object
+     * @return boolean true if the resource meets the specified condition,
+     * and false if the condition is not satisfied, in which case request
+     * processing is stopped
+     */
+    protected boolean checkIfUnmodifiedSince(HttpServletRequest request,
+                                           HttpServletResponse response,
+                                           ResourceAttributes resourceAttributes)
+        throws IOException {
+        try {
+            long lastModified = resourceAttributes.getLastModified();
+            long headerValue = request.getDateHeader("If-Unmodified-Since");
+            if (headerValue != -1) {
+                if ( lastModified > (headerValue + 1000)) {
+                    // The entity has not been modified since the date
+                    // specified by the client. This is not an error case.
+                    response.sendError(HttpServletResponse.SC_PRECONDITION_FAILED);
+                    return false;
+                }
+            }
+        } catch(IllegalArgumentException illegalArgument) {
+            return true;
+        }
+        return true;
+
+    }
+
+
+    /**
+     * Copy the contents of the specified input stream to the specified
+     * output stream, and ensure that both streams are closed before returning
+     * (even in the face of an exception).
+     *
+     * @param resourceInfo The resource information
+     * @param ostream The output stream to write to
+     *
+     * @exception IOException if an input/output error occurs
+     */
+    protected void copy(CacheEntry cacheEntry, InputStream is,
+                      ServletOutputStream ostream)
+        throws IOException {
+
+        IOException exception = null;
+        InputStream resourceInputStream = null;
+
+        // Optimization: If the binary content has already been loaded, send
+        // it directly
+        if (cacheEntry.resource != null) {
+            byte buffer[] = cacheEntry.resource.getContent();
+            if (buffer != null) {
+                ostream.write(buffer, 0, buffer.length);
+                return;
+            }
+            resourceInputStream = cacheEntry.resource.streamContent();
+        } else {
+            resourceInputStream = is;
+        }
+
+        InputStream istream = new BufferedInputStream
+            (resourceInputStream, input);
+
+        // Copy the input stream to the output stream
+        exception = copyRange(istream, ostream);
+
+        // Clean up the input stream
+        try {
+            istream.close();
+        } catch (Throwable t) {
+            ;
+        }
+
+        // Rethrow any exception that has occurred
+        if (exception != null)
+            throw exception;
+
+    }
+
+
+    /**
+     * Copy the contents of the specified input stream to the specified
+     * output stream, and ensure that both streams are closed before returning
+     * (even in the face of an exception).
+     *
+     * @param resourceInfo The resource info
+     * @param writer The writer to write to
+     *
+     * @exception IOException if an input/output error occurs
+     */
+    protected void copy(CacheEntry cacheEntry, InputStream is, PrintWriter writer)
+        throws IOException {
+
+        IOException exception = null;
+
+        InputStream resourceInputStream = null;
+        if (cacheEntry.resource != null) {
+            resourceInputStream = cacheEntry.resource.streamContent();
+        } else {
+            resourceInputStream = is;
+        }
+
+        Reader reader;
+        if (fileEncoding == null) {
+            reader = new InputStreamReader(resourceInputStream);
+        } else {
+            reader = new InputStreamReader(resourceInputStream,
+                                           fileEncoding);
+        }
+
+        // Copy the input stream to the output stream
+        exception = copyRange(reader, writer);
+
+        // Clean up the reader
+        try {
+            reader.close();
+        } catch (Throwable t) {
+            ;
+        }
+
+        // Rethrow any exception that has occurred
+        if (exception != null)
+            throw exception;
+
+    }
+
+
+    /**
+     * Copy the contents of the specified input stream to the specified
+     * output stream, and ensure that both streams are closed before returning
+     * (even in the face of an exception).
+     *
+     * @param resourceInfo The ResourceInfo object
+     * @param ostream The output stream to write to
+     * @param range Range the client wanted to retrieve
+     * @exception IOException if an input/output error occurs
+     */
+    protected void copy(CacheEntry cacheEntry, ServletOutputStream ostream,
+                      Range range)
+        throws IOException {
+
+        IOException exception = null;
+
+        InputStream resourceInputStream = cacheEntry.resource.streamContent();
+        InputStream istream =
+            new BufferedInputStream(resourceInputStream, input);
+        exception = copyRange(istream, ostream, range.start, range.end);
+
+        // Clean up the input stream
+        try {
+            istream.close();
+        } catch (Throwable t) {
+            ;
+        }
+
+        // Rethrow any exception that has occurred
+        if (exception != null)
+            throw exception;
+
+    }
+
+
+    /**
+     * Copy the contents of the specified input stream to the specified
+     * output stream, and ensure that both streams are closed before returning
+     * (even in the face of an exception).
+     *
+     * @param resourceInfo The ResourceInfo object
+     * @param writer The writer to write to
+     * @param range Range the client wanted to retrieve
+     * @exception IOException if an input/output error occurs
+     */
+    protected void copy(CacheEntry cacheEntry, PrintWriter writer,
+                      Range range)
+        throws IOException {
+
+        IOException exception = null;
+
+        InputStream resourceInputStream = cacheEntry.resource.streamContent();
+
+        Reader reader;
+        if (fileEncoding == null) {
+            reader = new InputStreamReader(resourceInputStream);
+        } else {
+            reader = new InputStreamReader(resourceInputStream,
+                                           fileEncoding);
+        }
+
+        exception = copyRange(reader, writer, range.start, range.end);
+
+        // Clean up the input stream
+        try {
+            reader.close();
+        } catch (Throwable t) {
+            ;
+        }
+
+        // Rethrow any exception that has occurred
+        if (exception != null)
+            throw exception;
+
+    }
+
+
+    /**
+     * Copy the contents of the specified input stream to the specified
+     * output stream, and ensure that both streams are closed before returning
+     * (even in the face of an exception).
+     *
+     * @param resourceInfo The ResourceInfo object
+     * @param ostream The output stream to write to
+     * @param ranges Enumeration of the ranges the client wanted to retrieve
+     * @param contentType Content type of the resource
+     * @exception IOException if an input/output error occurs
+     */
+    protected void copy(CacheEntry cacheEntry, ServletOutputStream ostream,
+                      Iterator ranges, String contentType)
+        throws IOException {
+
+        IOException exception = null;
+
+        while ( (exception == null) && (ranges.hasNext()) ) {
+
+            InputStream resourceInputStream = cacheEntry.resource.streamContent();
+            InputStream istream =
+                new BufferedInputStream(resourceInputStream, input);
+
+            Range currentRange = (Range) ranges.next();
+
+            // Writing MIME header.
+            ostream.println();
+            ostream.println("--" + mimeSeparation);
+            if (contentType != null)
+                ostream.println("Content-Type: " + contentType);
+            ostream.println("Content-Range: bytes " + currentRange.start
+                           + "-" + currentRange.end + "/"
+                           + currentRange.length);
+            ostream.println();
+
+            // Printing content
+            exception = copyRange(istream, ostream, currentRange.start,
+                                  currentRange.end);
+
+            try {
+                istream.close();
+            } catch (Throwable t) {
+                ;
+            }
+
+        }
+
+        ostream.println();
+        ostream.print("--" + mimeSeparation + "--");
+
+        // Rethrow any exception that has occurred
+        if (exception != null)
+            throw exception;
+
+    }
+
+
+    /**
+     * Copy the contents of the specified input stream to the specified
+     * output stream, and ensure that both streams are closed before returning
+     * (even in the face of an exception).
+     *
+     * @param resourceInfo The ResourceInfo object
+     * @param writer The writer to write to
+     * @param ranges Enumeration of the ranges the client wanted to retrieve
+     * @param contentType Content type of the resource
+     * @exception IOException if an input/output error occurs
+     */
+    protected void copy(CacheEntry cacheEntry, PrintWriter writer,
+                      Iterator ranges, String contentType)
+        throws IOException {
+
+        IOException exception = null;
+
+        while ( (exception == null) && (ranges.hasNext()) ) {
+
+            InputStream resourceInputStream = cacheEntry.resource.streamContent();
+            
+            Reader reader;
+            if (fileEncoding == null) {
+                reader = new InputStreamReader(resourceInputStream);
+            } else {
+                reader = new InputStreamReader(resourceInputStream,
+                                               fileEncoding);
+            }
+
+            Range currentRange = (Range) ranges.next();
+
+            // Writing MIME header.
+            writer.println();
+            writer.println("--" + mimeSeparation);
+            if (contentType != null)
+                writer.println("Content-Type: " + contentType);
+            writer.println("Content-Range: bytes " + currentRange.start
+                           + "-" + currentRange.end + "/"
+                           + currentRange.length);
+            writer.println();
+
+            // Printing content
+            exception = copyRange(reader, writer, currentRange.start,
+                                  currentRange.end);
+
+            try {
+                reader.close();
+            } catch (Throwable t) {
+                ;
+            }
+
+        }
+
+        writer.println();
+        writer.print("--" + mimeSeparation + "--");
+
+        // Rethrow any exception that has occurred
+        if (exception != null)
+            throw exception;
+
+    }
+
+
+    /**
+     * Copy the contents of the specified input stream to the specified
+     * output stream, and ensure that both streams are closed before returning
+     * (even in the face of an exception).
+     *
+     * @param istream The input stream to read from
+     * @param ostream The output stream to write to
+     * @return Exception which occurred during processing
+     */
+    protected IOException copyRange(InputStream istream,
+                                  ServletOutputStream ostream) {
+
+        // Copy the input stream to the output stream
+        IOException exception = null;
+        byte buffer[] = new byte[input];
+        int len = buffer.length;
+        while (true) {
+            try {
+                len = istream.read(buffer);
+                if (len == -1)
+                    break;
+                ostream.write(buffer, 0, len);
+            } catch (IOException e) {
+                exception = e;
+                len = -1;
+                break;
+            }
+        }
+        return exception;
+
+    }
+
+
+    /**
+     * Copy the contents of the specified input stream to the specified
+     * output stream, and ensure that both streams are closed before returning
+     * (even in the face of an exception).
+     *
+     * @param reader The reader to read from
+     * @param writer The writer to write to
+     * @return Exception which occurred during processing
+     */
+    protected IOException copyRange(Reader reader, PrintWriter writer) {
+
+        // Copy the input stream to the output stream
+        IOException exception = null;
+        char buffer[] = new char[input];
+        int len = buffer.length;
+        while (true) {
+            try {
+                len = reader.read(buffer);
+                if (len == -1)
+                    break;
+                writer.write(buffer, 0, len);
+            } catch (IOException e) {
+                exception = e;
+                len = -1;
+                break;
+            }
+        }
+        return exception;
+
+    }
+
+
+    /**
+     * Copy the contents of the specified input stream to the specified
+     * output stream, and ensure that both streams are closed before returning
+     * (even in the face of an exception).
+     *
+     * @param istream The input stream to read from
+     * @param ostream The output stream to write to
+     * @param start Start of the range which will be copied
+     * @param end End of the range which will be copied
+     * @return Exception which occurred during processing
+     */
+    protected IOException copyRange(InputStream istream,
+                                  ServletOutputStream ostream,
+                                  long start, long end) {
+
+        if (debug > 10)
+            log("Serving bytes:" + start + "-" + end);
+
+        try {
+            istream.skip(start);
+        } catch (IOException e) {
+            return e;
+        }
+
+        IOException exception = null;
+        long bytesToRead = end - start + 1;
+
+        byte buffer[] = new byte[input];
+        int len = buffer.length;
+        while ( (bytesToRead > 0) && (len >= buffer.length)) {
+            try {
+                len = istream.read(buffer);
+                if (bytesToRead >= len) {
+                    ostream.write(buffer, 0, len);
+                    bytesToRead -= len;
+                } else {
+                    ostream.write(buffer, 0, (int) bytesToRead);
+                    bytesToRead = 0;
+                }
+            } catch (IOException e) {
+                exception = e;
+                len = -1;
+            }
+            if (len < buffer.length)
+                break;
+        }
+
+        return exception;
+
+    }
+
+
+    /**
+     * Copy the contents of the specified input stream to the specified
+     * output stream, and ensure that both streams are closed before returning
+     * (even in the face of an exception).
+     *
+     * @param reader The reader to read from
+     * @param writer The writer to write to
+     * @param start Start of the range which will be copied
+     * @param end End of the range which will be copied
+     * @return Exception which occurred during processing
+     */
+    protected IOException copyRange(Reader reader, PrintWriter writer,
+                                  long start, long end) {
+
+        try {
+            reader.skip(start);
+        } catch (IOException e) {
+            return e;
+        }
+
+        IOException exception = null;
+        long bytesToRead = end - start + 1;
+
+        char buffer[] = new char[input];
+        int len = buffer.length;
+        while ( (bytesToRead > 0) && (len >= buffer.length)) {
+            try {
+                len = reader.read(buffer);
+                if (bytesToRead >= len) {
+                    writer.write(buffer, 0, len);
+                    bytesToRead -= len;
+                } else {
+                    writer.write(buffer, 0, (int) bytesToRead);
+                    bytesToRead = 0;
+                }
+            } catch (IOException e) {
+                exception = e;
+                len = -1;
+            }
+            if (len < buffer.length)
+                break;
+        }
+
+        return exception;
+
+    }
+
+
+
+    // ------------------------------------------------------ Range Inner Class
+
+
+    protected class Range {
+
+        public long start;
+        public long end;
+        public long length;
+
+        /**
+         * Validate range.
+         */
+        public boolean validate() {
+            if (end >= length)
+                end = length - 1;
+            return ( (start >= 0) && (end >= 0) && (start <= end)
+                     && (length > 0) );
+        }
+
+        public void recycle() {
+            start = 0;
+            end = 0;
+            length = 0;
+        }
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/servlets/InvokerHttpRequest.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/servlets/InvokerHttpRequest.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/servlets/InvokerHttpRequest.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,198 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.servlets;
+
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletRequestWrapper;
+
+
+/**
+ * Wrapper around a <code>javax.servlet.http.HttpServletRequest</code>
+ * utilized when <code>InvokerServlet</code> processes the initial request
+ * for an invoked servlet.  Subsequent requests will be mapped directly
+ * to the servlet, because a new servlet mapping will have been created.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 303211 $ $Date: 2004-09-08 05:38:14 -0500 (Wed, 08 Sep 2004) $
+ */
+
+class InvokerHttpRequest extends HttpServletRequestWrapper {
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Construct a new wrapped request around the specified servlet request.
+     *
+     * @param request The servlet request being wrapped
+     */
+    public InvokerHttpRequest(HttpServletRequest request) {
+
+        super(request);
+        this.pathInfo = request.getPathInfo();
+        this.pathTranslated = request.getPathTranslated();
+        this.requestURI = request.getRequestURI();
+        this.servletPath = request.getServletPath();
+
+    }
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * Descriptive information about this implementation.
+     */
+    protected static final String info =
+        "org.apache.catalina.servlets.InvokerHttpRequest/1.0";
+
+
+    /**
+     * The path information for this request.
+     */
+    protected String pathInfo = null;
+
+
+    /**
+     * The translated path information for this request.
+     */
+    protected String pathTranslated = null;
+
+
+    /**
+     * The request URI for this request.
+     */
+    protected String requestURI = null;
+
+
+    /**
+     * The servlet path for this request.
+     */
+    protected String servletPath = null;
+
+
+    // --------------------------------------------- HttpServletRequest Methods
+
+
+    /**
+     * Override the <code>getPathInfo()</code> method of the wrapped request.
+     */
+    public String getPathInfo() {
+
+        return (this.pathInfo);
+
+    }
+
+
+    /**
+     * Override the <code>getPathTranslated()</code> method of the
+     * wrapped request.
+     */
+    public String getPathTranslated() {
+
+        return (this.pathTranslated);
+
+    }
+
+
+    /**
+     * Override the <code>getRequestURI()</code> method of the wrapped request.
+     */
+    public String getRequestURI() {
+
+        return (this.requestURI);
+
+    }
+
+
+    /**
+     * Override the <code>getServletPath()</code> method of the wrapped
+     * request.
+     */
+    public String getServletPath() {
+
+        return (this.servletPath);
+
+    }
+
+
+    // -------------------------------------------------------- Package Methods
+
+
+
+    /**
+     * Return descriptive information about this implementation.
+     */
+    public String getInfo() {
+
+        return (info);
+
+    }
+
+
+    /**
+     * Set the path information for this request.
+     *
+     * @param pathInfo The new path info
+     */
+    void setPathInfo(String pathInfo) {
+
+        this.pathInfo = pathInfo;
+
+    }
+
+
+    /**
+     * Set the translated path info for this request.
+     *
+     * @param pathTranslated The new translated path info
+     */
+    void setPathTranslated(String pathTranslated) {
+
+        this.pathTranslated = pathTranslated;
+
+    }
+
+
+    /**
+     * Set the request URI for this request.
+     *
+     * @param requestURI The new request URI
+     */
+    void setRequestURI(String requestURI) {
+
+        this.requestURI = requestURI;
+
+    }
+
+
+    /**
+     * Set the servlet path for this request.
+     *
+     * @param servletPath The new servlet path
+     */
+    void setServletPath(String servletPath) {
+
+        this.servletPath = servletPath;
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/servlets/InvokerServlet.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/servlets/InvokerServlet.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/servlets/InvokerServlet.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,497 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.servlets;
+
+
+import java.io.IOException;
+
+import javax.servlet.Servlet;
+import javax.servlet.ServletException;
+import javax.servlet.UnavailableException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.catalina.ContainerServlet;
+import org.apache.catalina.Context;
+import org.apache.catalina.Globals;
+import org.apache.catalina.Wrapper;
+import org.apache.catalina.util.StringManager;
+
+
+/**
+ * The default servlet-invoking servlet for most web applications,
+ * used to serve requests to servlets that have not been registered
+ * in the web application deployment descriptor.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public final class InvokerServlet
+    extends HttpServlet implements ContainerServlet {
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The Context container associated with our web application.
+     */
+    private Context context = null;
+
+
+    /**
+     * The debugging detail level for this servlet.
+     */
+    private int debug = 0;
+
+
+    /**
+     * The string manager for this package.
+     */
+    private static StringManager sm =
+        StringManager.getManager(Constants.Package);
+
+
+    /**
+     * The Wrapper container associated with this servlet.
+     */
+    private Wrapper wrapper = null;
+
+
+    // ----------------------------------------------- ContainerServlet Methods
+
+
+    /**
+     * Return the Wrapper with which we are associated.
+     */
+    public Wrapper getWrapper() {
+
+        return (this.wrapper);
+
+    }
+
+
+    /**
+     * Set the Wrapper with which we are associated.
+     *
+     * @param wrapper The new wrapper
+     */
+    public void setWrapper(Wrapper wrapper) {
+
+        this.wrapper = wrapper;
+        if (wrapper == null)
+            context = null;
+        else
+            context = (Context) wrapper.getParent();
+
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Finalize this servlet.
+     */
+    public void destroy() {
+
+        ;       // No actions necessary
+
+    }
+
+
+    /**
+     * Process a GET request for the specified resource.
+     *
+     * @param request The servlet request we are processing
+     * @param response The servlet response we are creating
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception ServletException if a servlet-specified error occurs
+     */
+    public void doGet(HttpServletRequest request,
+                      HttpServletResponse response)
+        throws IOException, ServletException {
+
+        serveRequest(request, response);
+
+    }
+
+
+    /**
+     * Process a HEAD request for the specified resource.
+     *
+     * @param request The servlet request we are processing
+     * @param response The servlet response we are creating
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception ServletException if a servlet-specified error occurs
+     */
+    public void doHead(HttpServletRequest request,
+                       HttpServletResponse response)
+        throws IOException, ServletException {
+
+        serveRequest(request, response);
+
+    }
+
+
+    /**
+     * Process a POST request for the specified resource.
+     *
+     * @param request The servlet request we are processing
+     * @param response The servlet response we are creating
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception ServletException if a servlet-specified error occurs
+     */
+    public void doPost(HttpServletRequest request,
+                       HttpServletResponse response)
+        throws IOException, ServletException {
+
+        serveRequest(request, response);
+
+    }
+
+
+    /**
+     * Initialize this servlet.
+     */
+    public void init() throws ServletException {
+
+        // Ensure that our ContainerServlet properties have been set
+        if ((wrapper == null) || (context == null))
+            throw new UnavailableException
+                (sm.getString("invokerServlet.noWrapper"));
+
+        // Set our properties from the initialization parameters
+        String value = null;
+        try {
+            value = getServletConfig().getInitParameter("debug");
+            debug = Integer.parseInt(value);
+        } catch (Throwable t) {
+            ;
+        }
+        if (debug >= 1)
+            log("init: Associated with Context '" + context.getPath() + "'");
+
+    }
+
+
+
+    // -------------------------------------------------------- Private Methods
+
+
+    /**
+     * Serve the specified request, creating the corresponding response.
+     * After the first time a particular servlet class is requested, it will
+     * be served directly (like any registered servlet) because it will have
+     * been registered and mapped in our associated Context.
+     *
+     * @param request The servlet request we are processing
+     * @param response The servlet response we are creating
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception ServletException if a servlet-specified error occurs
+     */
+    public void serveRequest(HttpServletRequest request,
+                             HttpServletResponse response)
+        throws IOException, ServletException {
+
+        // Disallow calling this servlet via a named dispatcher
+        if (request.getAttribute(Globals.NAMED_DISPATCHER_ATTR) != null)
+            throw new ServletException
+                (sm.getString("invokerServlet.notNamed"));
+
+        // Identify the input parameters and our "included" state
+        String inRequestURI = null;
+        String inServletPath = null;
+        String inPathInfo = null;
+        boolean included =
+            (request.getAttribute(Globals.INCLUDE_REQUEST_URI_ATTR) != null);
+
+        if (included) {
+            inRequestURI =
+                (String) request.getAttribute(Globals.INCLUDE_REQUEST_URI_ATTR);
+            inServletPath =
+                (String) request.getAttribute(Globals.INCLUDE_SERVLET_PATH_ATTR);
+            inPathInfo =
+                (String) request.getAttribute(Globals.INCLUDE_PATH_INFO_ATTR);
+        } else {
+            inRequestURI = request.getRequestURI();
+            inServletPath = request.getServletPath();
+            inPathInfo = request.getPathInfo();
+        }
+        if (debug >= 1) {
+            log("included='" + included + "', requestURI='" +
+                inRequestURI + "'");
+            log("  servletPath='" + inServletPath + "', pathInfo='" +
+                inPathInfo + "'");
+        }
+
+        // Make sure a servlet name or class name was specified
+        if (inPathInfo == null) {
+            if (debug >= 1)
+                log("Invalid pathInfo '" + inPathInfo + "'");
+            if (included)
+                throw new ServletException
+                    (sm.getString("invokerServlet.invalidPath", inRequestURI));
+            else {
+                response.sendError(HttpServletResponse.SC_NOT_FOUND,
+                                   inRequestURI);
+                return;
+            }
+        }
+
+        // Identify the outgoing servlet name or class, and outgoing path info
+        String pathInfo = inPathInfo;
+        String servletClass = pathInfo.substring(1);
+        int slash = servletClass.indexOf('/');
+        //        if (debug >= 2)
+        //            log("  Calculating with servletClass='" + servletClass +
+        //                "', pathInfo='" + pathInfo + "', slash=" + slash);
+        if (slash >= 0) {
+            pathInfo = servletClass.substring(slash);
+            servletClass = servletClass.substring(0, slash);
+        } else {
+            pathInfo = "";
+        }
+
+        if (servletClass.startsWith("org.apache.catalina")) {
+            response.sendError(HttpServletResponse.SC_NOT_FOUND,
+                               inRequestURI);
+            return;
+        }
+
+        if (debug >= 1)
+            log("Processing servlet '" + servletClass +
+                "' with path info '" + pathInfo + "'");
+        String name = "org.apache.catalina.INVOKER." + servletClass;
+        String pattern = inServletPath + "/" + servletClass + "/*";
+        Wrapper wrapper = null;
+
+        // Synchronize to avoid race conditions when multiple requests
+        // try to initialize the same servlet at the same time
+        synchronized (this) {
+
+            // Are we referencing an existing servlet class or name?
+            wrapper = (Wrapper) context.findChild(servletClass);
+            if (wrapper == null)
+                wrapper = (Wrapper) context.findChild(name);
+            if (wrapper != null) {
+                String actualServletClass = wrapper.getServletClass();
+                if ((actualServletClass != null)
+                    && (actualServletClass.startsWith
+                        ("org.apache.catalina"))) {
+                    response.sendError(HttpServletResponse.SC_NOT_FOUND,
+                                       inRequestURI);
+                    return;
+                }
+                if (debug >= 1)
+                    log("Using wrapper for servlet '" +
+                        wrapper.getName() + "' with mapping '" +
+                        pattern + "'");
+                context.addServletMapping(pattern, wrapper.getName());
+            }
+
+            // No, create a new wrapper for the specified servlet class
+            else {
+
+                if (debug >= 1)
+                    log("Creating wrapper for '" + servletClass +
+                        "' with mapping '" + pattern + "'");
+
+                try {
+                    wrapper = context.createWrapper();
+                    wrapper.setName(name);
+                    wrapper.setLoadOnStartup(1);
+                    wrapper.setServletClass(servletClass);
+                    context.addChild(wrapper);
+                    context.addServletMapping(pattern, name);
+                } catch (Throwable t) {
+                    log(sm.getString("invokerServlet.cannotCreate",
+                                     inRequestURI), t);
+                    context.removeServletMapping(pattern);
+                    context.removeChild(wrapper);
+                    if (included)
+                        throw new ServletException
+                            (sm.getString("invokerServlet.cannotCreate",
+                                          inRequestURI), t);
+                    else {
+                        response.sendError(HttpServletResponse.SC_NOT_FOUND,
+                                           inRequestURI);
+                        return;
+                    }
+                }
+            }
+
+        }
+
+        // Create a request wrapper to pass on to the invoked servlet
+        InvokerHttpRequest wrequest =
+            new InvokerHttpRequest(request);
+        wrequest.setRequestURI(inRequestURI);
+        StringBuffer sb = new StringBuffer(inServletPath);
+        sb.append("/");
+        sb.append(servletClass);
+        wrequest.setServletPath(sb.toString());
+        if ((pathInfo == null) || (pathInfo.length() < 1)) {
+            wrequest.setPathInfo(null);
+            wrequest.setPathTranslated(null);
+        } else {
+            wrequest.setPathInfo(pathInfo);
+            wrequest.setPathTranslated
+                (getServletContext().getRealPath(pathInfo));
+        }
+
+        // Allocate a servlet instance to perform this request
+        Servlet instance = null;
+        try {
+            //            if (debug >= 2)
+            //                log("  Allocating servlet instance");
+            instance = wrapper.allocate();
+        } catch (ServletException e) {
+            log(sm.getString("invokerServlet.allocate", inRequestURI), e);
+            context.removeServletMapping(pattern);
+            context.removeChild(wrapper);
+            Throwable rootCause = e.getRootCause();
+            if (rootCause == null)
+                rootCause = e;
+            if (rootCause instanceof ClassNotFoundException) {
+                response.sendError(HttpServletResponse.SC_NOT_FOUND,
+                                   inRequestURI);
+                return;
+            } else if (rootCause instanceof IOException) {
+                throw (IOException) rootCause;
+            } else if (rootCause instanceof RuntimeException) {
+                throw (RuntimeException) rootCause;
+            } else if (rootCause instanceof ServletException) {
+                throw (ServletException) rootCause;
+            } else {
+                throw new ServletException
+                    (sm.getString("invokerServlet.allocate", inRequestURI),
+                     rootCause);
+            }
+        } catch (Throwable e) {
+            log(sm.getString("invokerServlet.allocate", inRequestURI), e);
+            context.removeServletMapping(pattern);
+            context.removeChild(wrapper);
+            throw new ServletException
+                (sm.getString("invokerServlet.allocate", inRequestURI), e);
+        }
+
+        // After loading the wrapper, restore some of the fields when including
+        if (included) {
+            wrequest.setRequestURI(request.getRequestURI());
+            wrequest.setPathInfo(request.getPathInfo());
+            wrequest.setServletPath(request.getServletPath());
+        }
+
+        // Invoke the service() method of the allocated servlet
+        try {
+            String jspFile = wrapper.getJspFile();
+            if (jspFile != null)
+                request.setAttribute(Globals.JSP_FILE_ATTR, jspFile);
+            else
+                request.removeAttribute(Globals.JSP_FILE_ATTR);
+            request.setAttribute(Globals.INVOKED_ATTR,
+                                 request.getServletPath());
+            //            if (debug >= 2)
+            //                log("  Calling service() method, jspFile=" +
+            //                    jspFile);
+            instance.service(wrequest, response);
+            request.removeAttribute(Globals.INVOKED_ATTR);
+            request.removeAttribute(Globals.JSP_FILE_ATTR);
+        } catch (IOException e) {
+            //            if (debug >= 2)
+            //                log("  service() method IOException", e);
+            request.removeAttribute(Globals.INVOKED_ATTR);
+            request.removeAttribute(Globals.JSP_FILE_ATTR);
+            try {
+                wrapper.deallocate(instance);
+            } catch (Throwable f) {
+                ;
+            }
+            throw e;
+        } catch (UnavailableException e) {
+            //            if (debug >= 2)
+            //                log("  service() method UnavailableException", e);
+            context.removeServletMapping(pattern);
+            request.removeAttribute(Globals.INVOKED_ATTR);
+            request.removeAttribute(Globals.JSP_FILE_ATTR);
+            try {
+                wrapper.deallocate(instance);
+            } catch (Throwable f) {
+                ;
+            }
+            throw e;
+        } catch (ServletException e) {
+            //            if (debug >= 2)
+            //                log("  service() method ServletException", e);
+            request.removeAttribute(Globals.INVOKED_ATTR);
+            request.removeAttribute(Globals.JSP_FILE_ATTR);
+            try {
+                wrapper.deallocate(instance);
+            } catch (Throwable f) {
+                ;
+            }
+            throw e;
+        } catch (RuntimeException e) {
+            //            if (debug >= 2)
+            //                log("  service() method RuntimeException", e);
+            request.removeAttribute(Globals.INVOKED_ATTR);
+            request.removeAttribute(Globals.JSP_FILE_ATTR);
+            try {
+                wrapper.deallocate(instance);
+            } catch (Throwable f) {
+                ;
+            }
+            throw e;
+        } catch (Throwable e) {
+            //            if (debug >= 2)
+            //                log("  service() method Throwable", e);
+            request.removeAttribute(Globals.INVOKED_ATTR);
+            request.removeAttribute(Globals.JSP_FILE_ATTR);
+            try {
+                wrapper.deallocate(instance);
+            } catch (Throwable f) {
+                ;
+            }
+            throw new ServletException("Invoker service() exception", e);
+        }
+
+        // Deallocate the allocated servlet instance
+        try {
+            //            if (debug >= 2)
+            //                log("  deallocate servlet instance");
+            wrapper.deallocate(instance);
+        } catch (ServletException e) {
+            log(sm.getString("invokerServlet.deallocate", inRequestURI), e);
+            throw e;
+        } catch (Throwable e) {
+            log(sm.getString("invokerServlet.deallocate", inRequestURI), e);
+            throw new ServletException
+                (sm.getString("invokerServlet.deallocate", inRequestURI), e);
+        }
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/servlets/LocalStrings.properties
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/servlets/LocalStrings.properties	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/servlets/LocalStrings.properties	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,19 @@
+defaultServlet.missingResource=The requested resource ({0}) is not available
+defaultservlet.directorylistingfor=Directory Listing for:
+defaultservlet.upto=Up to:
+defaultservlet.subdirectories=Subdirectories:
+defaultservlet.files=Files:
+invokerServlet.allocate=Cannot allocate servlet instance for path {0}
+invokerServlet.cannotCreate=Cannot create servlet wrapper for path {0}
+invokerServlet.deallocate=Cannot deallocate servlet instance for path {0}
+invokerServlet.invalidPath=No servlet name or class was specified in path {0}
+invokerServlet.notNamed=Cannot call invoker servlet with a named dispatcher
+invokerServlet.noWrapper=Container has not called setWrapper() for this servlet
+webdavservlet.jaxpfailed=JAXP initialization failed
+directory.filename=Filename
+directory.lastModified=Last Modified
+directory.parent=Up To {0}
+directory.size=Size
+directory.title=Directory Listing For {0}
+directory.version=Tomcat Catalina version 4.0
+

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/servlets/LocalStrings_es.properties
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/servlets/LocalStrings_es.properties	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/servlets/LocalStrings_es.properties	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,18 @@
+defaultservlet.directorylistingfor=Listado de Directorio para:
+defaultservlet.upto=Atrás a:
+defaultservlet.subdirectories=Subdirectorios:
+defaultservlet.files=Archivos:
+invokerServlet.allocate=No puedo reservar espacio para instancia de servlet para trayectoria {0}
+invokerServlet.cannotCreate=No puedo crear arropador (wrapper) de servlet para trayectoria {0}
+invokerServlet.deallocate=No puedo recuperar instancia de servlet para trayectoria {0}
+invokerServlet.invalidPath=No se ha especificado nombre de servlet o clase en trayectoria {0}
+invokerServlet.notNamed=No puedo llamar a servlet invocador mediante un despachador nombrado (named)
+invokerServlet.noWrapper=El Contenedor no ha llamado a setWrapper() para este servlet
+webdavservlet.jaxpfailed=Falló la inicialización de JAXP
+directory.filename=Nombre de Archivo
+directory.lastModified=Última Modificación
+directory.parent=Atrás A {0}
+directory.size=Medida
+directory.title=Listado de Directorio Para {0}
+directory.version=Tomcat Catalina versión 4.0
+

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/servlets/LocalStrings_fr.properties
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/servlets/LocalStrings_fr.properties	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/servlets/LocalStrings_fr.properties	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,18 @@
+defaultservlet.directorylistingfor=Liste du répertoire pour :
+defaultservlet.upto=Jusqu''à:
+defaultservlet.subdirectories=Sous-répertoires:
+defaultservlet.files=Fichiers:
+invokerServlet.allocate=Impossible d''allouer une instance de servlet pour le chemin {0}
+invokerServlet.cannotCreate=Impossible de créer un enrobeur (wrapper) de servlet pour le chemin {0}
+invokerServlet.deallocate=Impossible de désallouer une instance de servlet pour le chemin {0}
+invokerServlet.invalidPath=Aucun nom de servlet ou de classe n''a été spécifié pour le chemin {0}
+invokerServlet.notNamed=Impossible d''appeler le délégué (invoker) de servlet avec un aiguilleur (dispatcher) nommé
+invokerServlet.noWrapper=Le conteneur n''a pas appelé "setWrapper()" pour cette servlet
+webdavservlet.jaxpfailed=Erreur d''initialisation de JAXP
+directory.filename=Nom de fichier
+directory.lastModified=Dernière modification
+directory.parent=Jusqu''à {0}
+directory.size=Taille
+directory.title=Liste du répertoire pour {0}
+directory.version=Tomcat Catalina version 4.0
+

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/servlets/LocalStrings_ja.properties
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/servlets/LocalStrings_ja.properties	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/servlets/LocalStrings_ja.properties	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,18 @@
+defaultservlet.directorylistingfor=\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u306e\u4e00\u89a7: 
+defaultservlet.upto=\u89aa\u30c7\u30a3\u30ec\u30af\u30c8\u30ea: 
+defaultservlet.subdirectories=\u30b5\u30d6\u30c7\u30a3\u30ec\u30af\u30c8\u30ea:
+defaultservlet.files=\u30d5\u30a1\u30a4\u30eb:
+invokerServlet.allocate=\u30d1\u30b9 {0} \u306b\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u3092\u5272\u308a\u5f53\u3066\u3089\u308c\u307e\u305b\u3093
+invokerServlet.cannotCreate=\u30d1\u30b9 {0} \u306b\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8\u30e9\u30c3\u30d1\u3092\u4f5c\u6210\u3067\u304d\u307e\u305b\u3093
+invokerServlet.deallocate=\u30d1\u30b9 {0} \u306e\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u306e\u5272\u308a\u5f53\u3066\u3092\u89e3\u9664\u3067\u304d\u307e\u305b\u3093
+invokerServlet.invalidPath=\u30d1\u30b9 {0} \u306b\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8\u540d\u53c8\u306f\u30af\u30e9\u30b9\u304c\u6307\u5b9a\u3055\u308c\u3066\u3044\u307e\u305b\u3093
+invokerServlet.notNamed=\u305d\u306e\u540d\u524d\u306e\u30c7\u30a3\u30b9\u30d1\u30c3\u30c1\u30e3\u3067\u30a4\u30f3\u30dc\u30fc\u30ab\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8\u3092\u547c\u3073\u51fa\u305b\u307e\u305b\u3093
+invokerServlet.noWrapper=\u30b3\u30f3\u30c6\u30ca\u306f\u3053\u306e\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8\u306b\u5bfe\u3057\u3066\u547c\u3073\u51fa\u3055\u308c\u305fsetWrapper()\u3092\u6301\u3063\u3066\u3044\u307e\u305b\u3093
+webdavservlet.jaxpfailed=JAXP\u306e\u521d\u671f\u5316\u306b\u5931\u6557\u3057\u307e\u3057\u305f
+directory.filename=\u30d5\u30a1\u30a4\u30eb\u540d
+directory.lastModified=\u6700\u7d42\u66f4\u65b0
+directory.parent={0} \u306b\u79fb\u52d5
+directory.size=\u30b5\u30a4\u30ba
+directory.title={0} \u306e\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u306e\u4e00\u89a7
+directory.version=Tomcat Catalina \u30d0\u30fc\u30b8\u30e7\u30f3 4.0
+

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/servlets/WebdavServlet.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/servlets/WebdavServlet.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/servlets/WebdavServlet.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,3082 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ *
+ * Licensed 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.servlets;
+
+
+import java.io.IOException;
+import java.io.StringWriter;
+import java.io.Writer;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Stack;
+import java.util.TimeZone;
+import java.util.Vector;
+
+import javax.naming.NameClassPair;
+import javax.naming.NamingEnumeration;
+import javax.naming.NamingException;
+import javax.naming.directory.DirContext;
+import javax.servlet.ServletException;
+import javax.servlet.UnavailableException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+
+import org.apache.catalina.util.DOMWriter;
+import org.apache.catalina.util.MD5Encoder;
+import org.apache.catalina.util.RequestUtil;
+import org.apache.catalina.util.XMLWriter;
+import org.apache.naming.resources.CacheEntry;
+import org.apache.naming.resources.Resource;
+import org.apache.naming.resources.ResourceAttributes;
+import org.apache.tomcat.util.http.FastHttpDateFormat;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+
+
+
+/**
+ * Servlet which adds support for WebDAV level 2. All the basic HTTP requests
+ * are handled by the DefaultServlet.
+ *
+ * @author Remy Maucherat
+ * @version $Revision: 303599 $ $Date: 2004-12-20 12:54:14 -0600 (Mon, 20 Dec 2004) $
+ */
+
+public class WebdavServlet
+    extends DefaultServlet {
+
+
+    // -------------------------------------------------------------- Constants
+
+
+    private static final String METHOD_HEAD = "HEAD";
+    private static final String METHOD_PROPFIND = "PROPFIND";
+    private static final String METHOD_PROPPATCH = "PROPPATCH";
+    private static final String METHOD_MKCOL = "MKCOL";
+    private static final String METHOD_COPY = "COPY";
+    private static final String METHOD_MOVE = "MOVE";
+    private static final String METHOD_LOCK = "LOCK";
+    private static final String METHOD_UNLOCK = "UNLOCK";
+
+
+    /**
+     * Default depth is infite.
+     */
+    private static final int INFINITY = 3; // To limit tree browsing a bit
+
+
+    /**
+     * PROPFIND - Specify a property mask.
+     */
+    private static final int FIND_BY_PROPERTY = 0;
+
+
+    /**
+     * PROPFIND - Display all properties.
+     */
+    private static final int FIND_ALL_PROP = 1;
+
+
+    /**
+     * PROPFIND - Return property names.
+     */
+    private static final int FIND_PROPERTY_NAMES = 2;
+
+
+    /**
+     * Create a new lock.
+     */
+    private static final int LOCK_CREATION = 0;
+
+
+    /**
+     * Refresh lock.
+     */
+    private static final int LOCK_REFRESH = 1;
+
+
+    /**
+     * Default lock timeout value.
+     */
+    private static final int DEFAULT_TIMEOUT = 3600;
+
+
+    /**
+     * Maximum lock timeout.
+     */
+    private static final int MAX_TIMEOUT = 604800;
+
+
+    /**
+     * Default namespace.
+     */
+    protected static final String DEFAULT_NAMESPACE = "DAV:";
+
+
+    /**
+     * Simple date format for the creation date ISO representation (partial).
+     */
+    protected static final SimpleDateFormat creationDateFormat =
+        new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
+
+
+     /**
+     * MD5 message digest provider.
+     */
+    protected static MessageDigest md5Helper;
+
+
+    /**
+     * The MD5 helper object for this class.
+     */
+    protected static final MD5Encoder md5Encoder = new MD5Encoder();
+
+
+
+    static {
+        creationDateFormat.setTimeZone(TimeZone.getTimeZone("GMT"));
+    }
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * Repository of the locks put on single resources.
+     * <p>
+     * Key : path <br>
+     * Value : LockInfo
+     */
+    private Hashtable resourceLocks = new Hashtable();
+
+
+    /**
+     * Repository of the lock-null resources.
+     * <p>
+     * Key : path of the collection containing the lock-null resource<br>
+     * Value : Vector of lock-null resource which are members of the
+     * collection. Each element of the Vector is the path associated with
+     * the lock-null resource.
+     */
+    private Hashtable lockNullResources = new Hashtable();
+
+
+    /**
+     * Vector of the heritable locks.
+     * <p>
+     * Key : path <br>
+     * Value : LockInfo
+     */
+    private Vector collectionLocks = new Vector();
+
+
+    /**
+     * Secret information used to generate reasonably secure lock ids.
+     */
+    private String secret = "catalina";
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Initialize this servlet.
+     */
+    public void init()
+        throws ServletException {
+
+        super.init();
+
+        String value = null;
+        try {
+            value = getServletConfig().getInitParameter("secret");
+            if (value != null)
+                secret = value;
+        } catch (Throwable t) {
+            ;
+        }
+
+
+        // Load the MD5 helper used to calculate signatures.
+        try {
+            md5Helper = MessageDigest.getInstance("MD5");
+        } catch (NoSuchAlgorithmException e) {
+            throw new UnavailableException("No MD5");
+        }
+
+    }
+
+
+    // ------------------------------------------------------ Protected Methods
+
+
+    /**
+     * Return JAXP document builder instance.
+     */
+    protected DocumentBuilder getDocumentBuilder()
+        throws ServletException {
+        DocumentBuilder documentBuilder = null;
+        DocumentBuilderFactory documentBuilderFactory = null;
+        try {
+            documentBuilderFactory = DocumentBuilderFactory.newInstance();
+            documentBuilderFactory.setNamespaceAware(true);
+            documentBuilder = documentBuilderFactory.newDocumentBuilder();
+        } catch(ParserConfigurationException e) {
+            throw new ServletException
+                (sm.getString("webdavservlet.jaxpfailed"));
+        }
+        return documentBuilder;
+    }
+
+
+    /**
+     * Handles the special WebDAV methods.
+     */
+    protected void service(HttpServletRequest req, HttpServletResponse resp)
+        throws ServletException, IOException {
+
+        String method = req.getMethod();
+
+        if (debug > 0) {
+            String path = getRelativePath(req);
+            log("[" + method + "] " + path);
+        }
+
+        if (method.equals(METHOD_PROPFIND)) {
+            doPropfind(req, resp);
+        } else if (method.equals(METHOD_PROPPATCH)) {
+            doProppatch(req, resp);
+        } else if (method.equals(METHOD_MKCOL)) {
+            doMkcol(req, resp);
+        } else if (method.equals(METHOD_COPY)) {
+            doCopy(req, resp);
+        } else if (method.equals(METHOD_MOVE)) {
+            doMove(req, resp);
+        } else if (method.equals(METHOD_LOCK)) {
+            doLock(req, resp);
+        } else if (method.equals(METHOD_UNLOCK)) {
+            doUnlock(req, resp);
+        } else {
+            // DefaultServlet processing
+            super.service(req, resp);
+        }
+
+    }
+
+
+    /**
+     * Check if the conditions specified in the optional If headers are
+     * satisfied.
+     *
+     * @param request The servlet request we are processing
+     * @param response The servlet response we are creating
+     * @param resourceAttributes The resource information
+     * @return boolean true if the resource meets all the specified conditions,
+     * and false if any of the conditions is not satisfied, in which case
+     * request processing is stopped
+     */
+    protected boolean checkIfHeaders(HttpServletRequest request,
+                                     HttpServletResponse response,
+                                     ResourceAttributes resourceAttributes)
+        throws IOException {
+
+        if (!super.checkIfHeaders(request, response, resourceAttributes))
+            return false;
+
+        // TODO : Checking the WebDAV If header
+        return true;
+
+    }
+
+
+    /**
+     * OPTIONS Method.
+     *
+     * @param req The request
+     * @param resp The response
+     * @throws ServletException If an error occurs
+     * @throws IOException If an IO error occurs
+     */
+    protected void doOptions(HttpServletRequest req, HttpServletResponse resp)
+        throws ServletException, IOException {
+
+        resp.addHeader("DAV", "1,2");
+
+        StringBuffer methodsAllowed = determineMethodsAllowed(resources,
+                                                              req);
+
+        resp.addHeader("Allow", methodsAllowed.toString());
+        resp.addHeader("MS-Author-Via", "DAV");
+
+    }
+
+
+    /**
+     * PROPFIND Method.
+     */
+    protected void doPropfind(HttpServletRequest req, HttpServletResponse resp)
+        throws ServletException, IOException {
+
+        if (!listings) {
+            // Get allowed methods
+            StringBuffer methodsAllowed = determineMethodsAllowed(resources,
+                                                                  req);
+
+            resp.addHeader("Allow", methodsAllowed.toString());
+            resp.sendError(WebdavStatus.SC_METHOD_NOT_ALLOWED);
+            return;
+        }
+
+        String path = getRelativePath(req);
+        if (path.endsWith("/"))
+            path = path.substring(0, path.length() - 1);
+
+        if ((path.toUpperCase().startsWith("/WEB-INF")) ||
+            (path.toUpperCase().startsWith("/META-INF"))) {
+            resp.sendError(WebdavStatus.SC_FORBIDDEN);
+            return;
+        }
+
+        // Properties which are to be displayed.
+        Vector properties = null;
+        // Propfind depth
+        int depth = INFINITY;
+        // Propfind type
+        int type = FIND_ALL_PROP;
+
+        String depthStr = req.getHeader("Depth");
+
+        if (depthStr == null) {
+            depth = INFINITY;
+        } else {
+            if (depthStr.equals("0")) {
+                depth = 0;
+            } else if (depthStr.equals("1")) {
+                depth = 1;
+            } else if (depthStr.equals("infinity")) {
+                depth = INFINITY;
+            }
+        }
+
+        Node propNode = null;
+
+        DocumentBuilder documentBuilder = getDocumentBuilder();
+
+        try {
+            Document document = documentBuilder.parse
+                (new InputSource(req.getInputStream()));
+
+            // Get the root element of the document
+            Element rootElement = document.getDocumentElement();
+            NodeList childList = rootElement.getChildNodes();
+
+            for (int i=0; i < childList.getLength(); i++) {
+                Node currentNode = childList.item(i);
+                switch (currentNode.getNodeType()) {
+                case Node.TEXT_NODE:
+                    break;
+                case Node.ELEMENT_NODE:
+                    if (currentNode.getNodeName().endsWith("prop")) {
+                        type = FIND_BY_PROPERTY;
+                        propNode = currentNode;
+                    }
+                    if (currentNode.getNodeName().endsWith("propname")) {
+                        type = FIND_PROPERTY_NAMES;
+                    }
+                    if (currentNode.getNodeName().endsWith("allprop")) {
+                        type = FIND_ALL_PROP;
+                    }
+                    break;
+                }
+            }
+        } catch(Exception e) {
+            // Most likely there was no content : we use the defaults.
+            // TODO : Enhance that !
+        }
+
+        if (type == FIND_BY_PROPERTY) {
+            properties = new Vector();
+            NodeList childList = propNode.getChildNodes();
+
+            for (int i=0; i < childList.getLength(); i++) {
+                Node currentNode = childList.item(i);
+                switch (currentNode.getNodeType()) {
+                case Node.TEXT_NODE:
+                    break;
+                case Node.ELEMENT_NODE:
+                    String nodeName = currentNode.getNodeName();
+                    String propertyName = null;
+                    if (nodeName.indexOf(':') != -1) {
+                        propertyName = nodeName.substring
+                            (nodeName.indexOf(':') + 1);
+                    } else {
+                        propertyName = nodeName;
+                    }
+                    // href is a live property which is handled differently
+                    properties.addElement(propertyName);
+                    break;
+                }
+            }
+
+        }
+
+        boolean exists = true;
+        Object object = null;
+        try {
+            object = resources.lookup(path);
+        } catch (NamingException e) {
+            exists = false;
+            int slash = path.lastIndexOf('/');
+            if (slash != -1) {
+                String parentPath = path.substring(0, slash);
+                Vector currentLockNullResources =
+                    (Vector) lockNullResources.get(parentPath);
+                if (currentLockNullResources != null) {
+                    Enumeration lockNullResourcesList =
+                        currentLockNullResources.elements();
+                    while (lockNullResourcesList.hasMoreElements()) {
+                        String lockNullPath = (String)
+                            lockNullResourcesList.nextElement();
+                        if (lockNullPath.equals(path)) {
+                            resp.setStatus(WebdavStatus.SC_MULTI_STATUS);
+                            resp.setContentType("text/xml; charset=UTF-8");
+                            // Create multistatus object
+                            XMLWriter generatedXML =
+                                new XMLWriter(resp.getWriter());
+                            generatedXML.writeXMLHeader();
+                            generatedXML.writeElement
+                                (null, "multistatus"
+                                 + generateNamespaceDeclarations(),
+                                 XMLWriter.OPENING);
+                            parseLockNullProperties
+                                (req, generatedXML, lockNullPath, type,
+                                 properties);
+                            generatedXML.writeElement(null, "multistatus",
+                                                      XMLWriter.CLOSING);
+                            generatedXML.sendData();
+                            return;
+                        }
+                    }
+                }
+            }
+        }
+
+        if (!exists) {
+            resp.sendError(HttpServletResponse.SC_NOT_FOUND, path);
+            return;
+        }
+
+        resp.setStatus(WebdavStatus.SC_MULTI_STATUS);
+
+        resp.setContentType("text/xml; charset=UTF-8");
+
+        // Create multistatus object
+        XMLWriter generatedXML = new XMLWriter(resp.getWriter());
+        generatedXML.writeXMLHeader();
+
+        generatedXML.writeElement(null, "multistatus"
+                                  + generateNamespaceDeclarations(),
+                                  XMLWriter.OPENING);
+
+        if (depth == 0) {
+            parseProperties(req, generatedXML, path, type,
+                            properties);
+        } else {
+            // The stack always contains the object of the current level
+            Stack stack = new Stack();
+            stack.push(path);
+
+            // Stack of the objects one level below
+            Stack stackBelow = new Stack();
+
+            while ((!stack.isEmpty()) && (depth >= 0)) {
+
+                String currentPath = (String) stack.pop();
+                parseProperties(req, generatedXML, currentPath,
+                                type, properties);
+
+                try {
+                    object = resources.lookup(currentPath);
+                } catch (NamingException e) {
+                    continue;
+                }
+
+                if ((object instanceof DirContext) && (depth > 0)) {
+
+                    try {
+                        NamingEnumeration enumeration = resources.list(currentPath);
+                        while (enumeration.hasMoreElements()) {
+                            NameClassPair ncPair =
+                                (NameClassPair) enumeration.nextElement();
+                            String newPath = currentPath;
+                            if (!(newPath.endsWith("/")))
+                                newPath += "/";
+                            newPath += ncPair.getName();
+                            stackBelow.push(newPath);
+                        }
+                    } catch (NamingException e) {
+                        resp.sendError
+                            (HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
+                             path);
+                        return;
+                    }
+
+                    // Displaying the lock-null resources present in that
+                    // collection
+                    String lockPath = currentPath;
+                    if (lockPath.endsWith("/"))
+                        lockPath =
+                            lockPath.substring(0, lockPath.length() - 1);
+                    Vector currentLockNullResources =
+                        (Vector) lockNullResources.get(lockPath);
+                    if (currentLockNullResources != null) {
+                        Enumeration lockNullResourcesList =
+                            currentLockNullResources.elements();
+                        while (lockNullResourcesList.hasMoreElements()) {
+                            String lockNullPath = (String)
+                                lockNullResourcesList.nextElement();
+                            parseLockNullProperties
+                                (req, generatedXML, lockNullPath, type,
+                                 properties);
+                        }
+                    }
+
+                }
+
+                if (stack.isEmpty()) {
+                    depth--;
+                    stack = stackBelow;
+                    stackBelow = new Stack();
+                }
+
+                generatedXML.sendData();
+
+            }
+        }
+
+        generatedXML.writeElement(null, "multistatus",
+                                  XMLWriter.CLOSING);
+
+        generatedXML.sendData();
+
+    }
+
+
+    /**
+     * PROPPATCH Method.
+     */
+    protected void doProppatch(HttpServletRequest req,
+                               HttpServletResponse resp)
+        throws ServletException, IOException {
+
+        if (readOnly) {
+            resp.sendError(WebdavStatus.SC_FORBIDDEN);
+            return;
+        }
+
+        if (isLocked(req)) {
+            resp.sendError(WebdavStatus.SC_LOCKED);
+            return;
+        }
+
+        resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED);
+
+    }
+
+
+    /**
+     * MKCOL Method.
+     */
+    protected void doMkcol(HttpServletRequest req, HttpServletResponse resp)
+        throws ServletException, IOException {
+
+        if (readOnly) {
+            resp.sendError(WebdavStatus.SC_FORBIDDEN);
+            return;
+        }
+
+        if (isLocked(req)) {
+            resp.sendError(WebdavStatus.SC_LOCKED);
+            return;
+        }
+
+        String path = getRelativePath(req);
+
+        if ((path.toUpperCase().startsWith("/WEB-INF")) ||
+            (path.toUpperCase().startsWith("/META-INF"))) {
+            resp.sendError(WebdavStatus.SC_FORBIDDEN);
+            return;
+        }
+
+        boolean exists = true;
+        Object object = null;
+        try {
+            object = resources.lookup(path);
+        } catch (NamingException e) {
+            exists = false;
+        }
+
+        // Can't create a collection if a resource already exists at the given
+        // path
+        if (exists) {
+            // Get allowed methods
+            StringBuffer methodsAllowed = determineMethodsAllowed(resources,
+                                                                  req);
+
+            resp.addHeader("Allow", methodsAllowed.toString());
+
+            resp.sendError(WebdavStatus.SC_METHOD_NOT_ALLOWED);
+            return;
+        }
+
+        if (req.getInputStream().available() > 0) {
+            DocumentBuilder documentBuilder = getDocumentBuilder();
+            try {
+                Document document = documentBuilder.parse
+                    (new InputSource(req.getInputStream()));
+                // TODO : Process this request body
+                resp.sendError(WebdavStatus.SC_NOT_IMPLEMENTED);
+                return;
+
+            } catch(SAXException saxe) {
+                // Parse error - assume invalid content
+                resp.sendError(WebdavStatus.SC_BAD_REQUEST);
+                return;
+            }
+        }
+
+        boolean result = true;
+        try {
+            resources.createSubcontext(path);
+        } catch (NamingException e) {
+            result = false;
+        }
+
+        if (!result) {
+            resp.sendError(WebdavStatus.SC_CONFLICT,
+                           WebdavStatus.getStatusText
+                           (WebdavStatus.SC_CONFLICT));
+        } else {
+            resp.setStatus(WebdavStatus.SC_CREATED);
+            // Removing any lock-null resource which would be present
+            lockNullResources.remove(path);
+        }
+
+    }
+
+
+    /**
+     * DELETE Method.
+     */
+    protected void doDelete(HttpServletRequest req, HttpServletResponse resp)
+        throws ServletException, IOException {
+
+        if (readOnly) {
+            resp.sendError(WebdavStatus.SC_FORBIDDEN);
+            return;
+        }
+
+        if (isLocked(req)) {
+            resp.sendError(WebdavStatus.SC_LOCKED);
+            return;
+        }
+
+        deleteResource(req, resp);
+
+    }
+
+
+    /**
+     * Process a POST request for the specified resource.
+     *
+     * @param req The servlet request we are processing
+     * @param resp The servlet response we are creating
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception ServletException if a servlet-specified error occurs
+     */
+    protected void doPut(HttpServletRequest req, HttpServletResponse resp)
+        throws ServletException, IOException {
+
+        if (isLocked(req)) {
+            resp.sendError(WebdavStatus.SC_LOCKED);
+            return;
+        }
+
+        super.doPut(req, resp);
+
+        String path = getRelativePath(req);
+
+        // Removing any lock-null resource which would be present
+        lockNullResources.remove(path);
+
+    }
+
+    /**
+     * COPY Method.
+     */
+    protected void doCopy(HttpServletRequest req, HttpServletResponse resp)
+        throws ServletException, IOException {
+
+        if (readOnly) {
+            resp.sendError(WebdavStatus.SC_FORBIDDEN);
+            return;
+        }
+
+        copyResource(req, resp);
+
+    }
+
+
+    /**
+     * MOVE Method.
+     */
+    protected void doMove(HttpServletRequest req, HttpServletResponse resp)
+        throws ServletException, IOException {
+
+        if (readOnly) {
+            resp.sendError(WebdavStatus.SC_FORBIDDEN);
+            return;
+        }
+
+        if (isLocked(req)) {
+            resp.sendError(WebdavStatus.SC_LOCKED);
+            return;
+        }
+
+        String path = getRelativePath(req);
+
+        if (copyResource(req, resp)) {
+            deleteResource(path, req, resp, false);
+        }
+
+    }
+
+
+    /**
+     * LOCK Method.
+     */
+    protected void doLock(HttpServletRequest req, HttpServletResponse resp)
+        throws ServletException, IOException {
+
+        if (readOnly) {
+            resp.sendError(WebdavStatus.SC_FORBIDDEN);
+            return;
+        }
+
+        if (isLocked(req)) {
+            resp.sendError(WebdavStatus.SC_LOCKED);
+            return;
+        }
+
+        LockInfo lock = new LockInfo();
+
+        // Parsing lock request
+
+        // Parsing depth header
+
+        String depthStr = req.getHeader("Depth");
+
+        if (depthStr == null) {
+            lock.depth = INFINITY;
+        } else {
+            if (depthStr.equals("0")) {
+                lock.depth = 0;
+            } else {
+                lock.depth = INFINITY;
+            }
+        }
+
+        // Parsing timeout header
+
+        int lockDuration = DEFAULT_TIMEOUT;
+        String lockDurationStr = req.getHeader("Timeout");
+        if (lockDurationStr == null) {
+            lockDuration = DEFAULT_TIMEOUT;
+        } else {
+            int commaPos = lockDurationStr.indexOf(",");
+            // If multiple timeouts, just use the first
+            if (commaPos != -1) {
+                lockDurationStr = lockDurationStr.substring(0,commaPos);
+            }
+            if (lockDurationStr.startsWith("Second-")) {
+                lockDuration =
+                    (new Integer(lockDurationStr.substring(7))).intValue();
+            } else {
+                if (lockDurationStr.equalsIgnoreCase("infinity")) {
+                    lockDuration = MAX_TIMEOUT;
+                } else {
+                    try {
+                        lockDuration =
+                            (new Integer(lockDurationStr)).intValue();
+                    } catch (NumberFormatException e) {
+                        lockDuration = MAX_TIMEOUT;
+                    }
+                }
+            }
+            if (lockDuration == 0) {
+                lockDuration = DEFAULT_TIMEOUT;
+            }
+            if (lockDuration > MAX_TIMEOUT) {
+                lockDuration = MAX_TIMEOUT;
+            }
+        }
+        lock.expiresAt = System.currentTimeMillis() + (lockDuration * 1000);
+
+        int lockRequestType = LOCK_CREATION;
+
+        Node lockInfoNode = null;
+
+        DocumentBuilder documentBuilder = getDocumentBuilder();
+
+        try {
+            Document document = documentBuilder.parse(new InputSource
+                (req.getInputStream()));
+
+            // Get the root element of the document
+            Element rootElement = document.getDocumentElement();
+            lockInfoNode = rootElement;
+        } catch(Exception e) {
+            lockRequestType = LOCK_REFRESH;
+        }
+
+        if (lockInfoNode != null) {
+
+            // Reading lock information
+
+            NodeList childList = lockInfoNode.getChildNodes();
+            StringWriter strWriter = null;
+            DOMWriter domWriter = null;
+
+            Node lockScopeNode = null;
+            Node lockTypeNode = null;
+            Node lockOwnerNode = null;
+
+            for (int i=0; i < childList.getLength(); i++) {
+                Node currentNode = childList.item(i);
+                switch (currentNode.getNodeType()) {
+                case Node.TEXT_NODE:
+                    break;
+                case Node.ELEMENT_NODE:
+                    String nodeName = currentNode.getNodeName();
+                    if (nodeName.endsWith("lockscope")) {
+                        lockScopeNode = currentNode;
+                    }
+                    if (nodeName.endsWith("locktype")) {
+                        lockTypeNode = currentNode;
+                    }
+                    if (nodeName.endsWith("owner")) {
+                        lockOwnerNode = currentNode;
+                    }
+                    break;
+                }
+            }
+
+            if (lockScopeNode != null) {
+
+                childList = lockScopeNode.getChildNodes();
+                for (int i=0; i < childList.getLength(); i++) {
+                    Node currentNode = childList.item(i);
+                    switch (currentNode.getNodeType()) {
+                    case Node.TEXT_NODE:
+                        break;
+                    case Node.ELEMENT_NODE:
+                        String tempScope = currentNode.getNodeName();
+                        if (tempScope.indexOf(':') != -1) {
+                            lock.scope = tempScope.substring
+                                (tempScope.indexOf(':') + 1);
+                        } else {
+                            lock.scope = tempScope;
+                        }
+                        break;
+                    }
+                }
+
+                if (lock.scope == null) {
+                    // Bad request
+                    resp.setStatus(WebdavStatus.SC_BAD_REQUEST);
+                }
+
+            } else {
+                // Bad request
+                resp.setStatus(WebdavStatus.SC_BAD_REQUEST);
+            }
+
+            if (lockTypeNode != null) {
+
+                childList = lockTypeNode.getChildNodes();
+                for (int i=0; i < childList.getLength(); i++) {
+                    Node currentNode = childList.item(i);
+                    switch (currentNode.getNodeType()) {
+                    case Node.TEXT_NODE:
+                        break;
+                    case Node.ELEMENT_NODE:
+                        String tempType = currentNode.getNodeName();
+                        if (tempType.indexOf(':') != -1) {
+                            lock.type =
+                                tempType.substring(tempType.indexOf(':') + 1);
+                        } else {
+                            lock.type = tempType;
+                        }
+                        break;
+                    }
+                }
+
+                if (lock.type == null) {
+                    // Bad request
+                    resp.setStatus(WebdavStatus.SC_BAD_REQUEST);
+                }
+
+            } else {
+                // Bad request
+                resp.setStatus(WebdavStatus.SC_BAD_REQUEST);
+            }
+
+            if (lockOwnerNode != null) {
+
+                childList = lockOwnerNode.getChildNodes();
+                for (int i=0; i < childList.getLength(); i++) {
+                    Node currentNode = childList.item(i);
+                    switch (currentNode.getNodeType()) {
+                    case Node.TEXT_NODE:
+                        lock.owner += currentNode.getNodeValue();
+                        break;
+                    case Node.ELEMENT_NODE:
+                        strWriter = new StringWriter();
+                        domWriter = new DOMWriter(strWriter, true);
+                        domWriter.setQualifiedNames(false);
+                        domWriter.print(currentNode);
+                        lock.owner += strWriter.toString();
+                        break;
+                    }
+                }
+
+                if (lock.owner == null) {
+                    // Bad request
+                    resp.setStatus(WebdavStatus.SC_BAD_REQUEST);
+                }
+
+            } else {
+                lock.owner = new String();
+            }
+
+        }
+
+        String path = getRelativePath(req);
+
+        lock.path = path;
+
+        boolean exists = true;
+        Object object = null;
+        try {
+            object = resources.lookup(path);
+        } catch (NamingException e) {
+            exists = false;
+        }
+
+        Enumeration locksList = null;
+
+        if (lockRequestType == LOCK_CREATION) {
+
+            // Generating lock id
+            String lockTokenStr = req.getServletPath() + "-" + lock.type + "-"
+                + lock.scope + "-" + req.getUserPrincipal() + "-"
+                + lock.depth + "-" + lock.owner + "-" + lock.tokens + "-"
+                + lock.expiresAt + "-" + System.currentTimeMillis() + "-"
+                + secret;
+            String lockToken =
+                md5Encoder.encode(md5Helper.digest(lockTokenStr.getBytes()));
+
+            if ( (exists) && (object instanceof DirContext) &&
+                 (lock.depth == INFINITY) ) {
+
+                // Locking a collection (and all its member resources)
+
+                // Checking if a child resource of this collection is
+                // already locked
+                Vector lockPaths = new Vector();
+                locksList = collectionLocks.elements();
+                while (locksList.hasMoreElements()) {
+                    LockInfo currentLock = (LockInfo) locksList.nextElement();
+                    if (currentLock.hasExpired()) {
+                        resourceLocks.remove(currentLock.path);
+                        continue;
+                    }
+                    if ( (currentLock.path.startsWith(lock.path)) &&
+                         ((currentLock.isExclusive()) ||
+                          (lock.isExclusive())) ) {
+                        // A child collection of this collection is locked
+                        lockPaths.addElement(currentLock.path);
+                    }
+                }
+                locksList = resourceLocks.elements();
+                while (locksList.hasMoreElements()) {
+                    LockInfo currentLock = (LockInfo) locksList.nextElement();
+                    if (currentLock.hasExpired()) {
+                        resourceLocks.remove(currentLock.path);
+                        continue;
+                    }
+                    if ( (currentLock.path.startsWith(lock.path)) &&
+                         ((currentLock.isExclusive()) ||
+                          (lock.isExclusive())) ) {
+                        // A child resource of this collection is locked
+                        lockPaths.addElement(currentLock.path);
+                    }
+                }
+
+                if (!lockPaths.isEmpty()) {
+
+                    // One of the child paths was locked
+                    // We generate a multistatus error report
+
+                    Enumeration lockPathsList = lockPaths.elements();
+
+                    resp.setStatus(WebdavStatus.SC_CONFLICT);
+
+                    XMLWriter generatedXML = new XMLWriter();
+                    generatedXML.writeXMLHeader();
+
+                    generatedXML.writeElement
+                        (null, "multistatus" + generateNamespaceDeclarations(),
+                         XMLWriter.OPENING);
+
+                    while (lockPathsList.hasMoreElements()) {
+                        generatedXML.writeElement(null, "response",
+                                                  XMLWriter.OPENING);
+                        generatedXML.writeElement(null, "href",
+                                                  XMLWriter.OPENING);
+                        generatedXML
+                            .writeText((String) lockPathsList.nextElement());
+                        generatedXML.writeElement(null, "href",
+                                                  XMLWriter.CLOSING);
+                        generatedXML.writeElement(null, "status",
+                                                  XMLWriter.OPENING);
+                        generatedXML
+                            .writeText("HTTP/1.1 " + WebdavStatus.SC_LOCKED
+                                       + " " + WebdavStatus
+                                       .getStatusText(WebdavStatus.SC_LOCKED));
+                        generatedXML.writeElement(null, "status",
+                                                  XMLWriter.CLOSING);
+
+                        generatedXML.writeElement(null, "response",
+                                                  XMLWriter.CLOSING);
+                    }
+
+                    generatedXML.writeElement(null, "multistatus",
+                                          XMLWriter.CLOSING);
+
+                    Writer writer = resp.getWriter();
+                    writer.write(generatedXML.toString());
+                    writer.close();
+
+                    return;
+
+                }
+
+                boolean addLock = true;
+
+                // Checking if there is already a shared lock on this path
+                locksList = collectionLocks.elements();
+                while (locksList.hasMoreElements()) {
+
+                    LockInfo currentLock = (LockInfo) locksList.nextElement();
+                    if (currentLock.path.equals(lock.path)) {
+
+                        if (currentLock.isExclusive()) {
+                            resp.sendError(WebdavStatus.SC_LOCKED);
+                            return;
+                        } else {
+                            if (lock.isExclusive()) {
+                                resp.sendError(WebdavStatus.SC_LOCKED);
+                                return;
+                            }
+                        }
+
+                        currentLock.tokens.addElement(lockToken);
+                        lock = currentLock;
+                        addLock = false;
+
+                    }
+
+                }
+
+                if (addLock) {
+                    lock.tokens.addElement(lockToken);
+                    collectionLocks.addElement(lock);
+                }
+
+            } else {
+
+                // Locking a single resource
+
+                // Retrieving an already existing lock on that resource
+                LockInfo presentLock = (LockInfo) resourceLocks.get(lock.path);
+                if (presentLock != null) {
+
+                    if ((presentLock.isExclusive()) || (lock.isExclusive())) {
+                        // If either lock is exclusive, the lock can't be
+                        // granted
+                        resp.sendError(WebdavStatus.SC_PRECONDITION_FAILED);
+                        return;
+                    } else {
+                        presentLock.tokens.addElement(lockToken);
+                        lock = presentLock;
+                    }
+
+                } else {
+
+                    lock.tokens.addElement(lockToken);
+                    resourceLocks.put(lock.path, lock);
+
+                    // Checking if a resource exists at this path
+                    exists = true;
+                    try {
+                        object = resources.lookup(path);
+                    } catch (NamingException e) {
+                        exists = false;
+                    }
+                    if (!exists) {
+
+                        // "Creating" a lock-null resource
+                        int slash = lock.path.lastIndexOf('/');
+                        String parentPath = lock.path.substring(0, slash);
+
+                        Vector lockNulls =
+                            (Vector) lockNullResources.get(parentPath);
+                        if (lockNulls == null) {
+                            lockNulls = new Vector();
+                            lockNullResources.put(parentPath, lockNulls);
+                        }
+
+                        lockNulls.addElement(lock.path);
+
+                    }
+                    // Add the Lock-Token header as by RFC 2518 8.10.1
+                    // - only do this for newly created locks
+                    resp.addHeader("Lock-Token", "<opaquelocktoken:"
+                                   + lockToken + ">");
+                }
+
+            }
+
+        }
+
+        if (lockRequestType == LOCK_REFRESH) {
+
+            String ifHeader = req.getHeader("If");
+            if (ifHeader == null)
+                ifHeader = "";
+
+            // Checking resource locks
+
+            LockInfo toRenew = (LockInfo) resourceLocks.get(path);
+            Enumeration tokenList = null;
+            if (lock != null) {
+
+                // At least one of the tokens of the locks must have been given
+
+                tokenList = toRenew.tokens.elements();
+                while (tokenList.hasMoreElements()) {
+                    String token = (String) tokenList.nextElement();
+                    if (ifHeader.indexOf(token) != -1) {
+                        toRenew.expiresAt = lock.expiresAt;
+                        lock = toRenew;
+                    }
+                }
+
+            }
+
+            // Checking inheritable collection locks
+
+            Enumeration collectionLocksList = collectionLocks.elements();
+            while (collectionLocksList.hasMoreElements()) {
+                toRenew = (LockInfo) collectionLocksList.nextElement();
+                if (path.equals(toRenew.path)) {
+
+                    tokenList = toRenew.tokens.elements();
+                    while (tokenList.hasMoreElements()) {
+                        String token = (String) tokenList.nextElement();
+                        if (ifHeader.indexOf(token) != -1) {
+                            toRenew.expiresAt = lock.expiresAt;
+                            lock = toRenew;
+                        }
+                    }
+
+                }
+            }
+
+        }
+
+        // Set the status, then generate the XML response containing
+        // the lock information
+        XMLWriter generatedXML = new XMLWriter();
+        generatedXML.writeXMLHeader();
+        generatedXML.writeElement(null, "prop"
+                                  + generateNamespaceDeclarations(),
+                                  XMLWriter.OPENING);
+
+        generatedXML.writeElement(null, "lockdiscovery",
+                                  XMLWriter.OPENING);
+
+        lock.toXML(generatedXML);
+
+        generatedXML.writeElement(null, "lockdiscovery",
+                                  XMLWriter.CLOSING);
+
+        generatedXML.writeElement(null, "prop", XMLWriter.CLOSING);
+
+        resp.setStatus(WebdavStatus.SC_OK);
+        resp.setContentType("text/xml; charset=UTF-8");
+        Writer writer = resp.getWriter();
+        writer.write(generatedXML.toString());
+        writer.close();
+
+    }
+
+
+    /**
+     * UNLOCK Method.
+     */
+    protected void doUnlock(HttpServletRequest req, HttpServletResponse resp)
+        throws ServletException, IOException {
+
+        if (readOnly) {
+            resp.sendError(WebdavStatus.SC_FORBIDDEN);
+            return;
+        }
+
+        if (isLocked(req)) {
+            resp.sendError(WebdavStatus.SC_LOCKED);
+            return;
+        }
+
+        String path = getRelativePath(req);
+
+        String lockTokenHeader = req.getHeader("Lock-Token");
+        if (lockTokenHeader == null)
+            lockTokenHeader = "";
+
+        // Checking resource locks
+
+        LockInfo lock = (LockInfo) resourceLocks.get(path);
+        Enumeration tokenList = null;
+        if (lock != null) {
+
+            // At least one of the tokens of the locks must have been given
+
+            tokenList = lock.tokens.elements();
+            while (tokenList.hasMoreElements()) {
+                String token = (String) tokenList.nextElement();
+                if (lockTokenHeader.indexOf(token) != -1) {
+                    lock.tokens.removeElement(token);
+                }
+            }
+
+            if (lock.tokens.isEmpty()) {
+                resourceLocks.remove(path);
+                // Removing any lock-null resource which would be present
+                lockNullResources.remove(path);
+            }
+
+        }
+
+        // Checking inheritable collection locks
+
+        Enumeration collectionLocksList = collectionLocks.elements();
+        while (collectionLocksList.hasMoreElements()) {
+            lock = (LockInfo) collectionLocksList.nextElement();
+            if (path.equals(lock.path)) {
+
+                tokenList = lock.tokens.elements();
+                while (tokenList.hasMoreElements()) {
+                    String token = (String) tokenList.nextElement();
+                    if (lockTokenHeader.indexOf(token) != -1) {
+                        lock.tokens.removeElement(token);
+                        break;
+                    }
+                }
+
+                if (lock.tokens.isEmpty()) {
+                    collectionLocks.removeElement(lock);
+                    // Removing any lock-null resource which would be present
+                    lockNullResources.remove(path);
+                }
+
+            }
+        }
+
+        resp.setStatus(WebdavStatus.SC_NO_CONTENT);
+
+    }
+
+    /**
+     * Return a context-relative path, beginning with a "/", that represents
+     * the canonical version of the specified path after ".." and "." elements
+     * are resolved out.  If the specified path attempts to go outside the
+     * boundaries of the current context (i.e. too many ".." path elements
+     * are present), return <code>null</code> instead.
+     *
+     * @param path Path to be normalized
+     */
+    protected String normalize(String path) {
+
+        if (path == null)
+            return null;
+
+        // Create a place for the normalized path
+        String normalized = path;
+
+        if (normalized == null)
+            return (null);
+
+        if (normalized.equals("/."))
+            return "/";
+
+        // Normalize the slashes and add leading slash if necessary
+        if (normalized.indexOf('\\') >= 0)
+            normalized = normalized.replace('\\', '/');
+        if (!normalized.startsWith("/"))
+            normalized = "/" + normalized;
+
+        // Resolve occurrences of "//" in the normalized path
+        while (true) {
+            int index = normalized.indexOf("//");
+            if (index < 0)
+                break;
+            normalized = normalized.substring(0, index) +
+                normalized.substring(index + 1);
+        }
+
+        // Resolve occurrences of "/./" in the normalized path
+        while (true) {
+            int index = normalized.indexOf("/./");
+            if (index < 0)
+                break;
+            normalized = normalized.substring(0, index) +
+                normalized.substring(index + 2);
+        }
+
+        // Resolve occurrences of "/../" in the normalized path
+        while (true) {
+            int index = normalized.indexOf("/../");
+            if (index < 0)
+                break;
+            if (index == 0)
+                return (null);  // Trying to go outside our context
+            int index2 = normalized.lastIndexOf('/', index - 1);
+            normalized = normalized.substring(0, index2) +
+                normalized.substring(index + 3);
+        }
+
+        // Return the normalized path that we have completed
+        return (normalized);
+
+    }
+
+
+    // -------------------------------------------------------- Private Methods
+
+    /**
+     * Generate the namespace declarations.
+     */
+    private String generateNamespaceDeclarations() {
+        return " xmlns=\"" + DEFAULT_NAMESPACE + "\"";
+    }
+
+
+    /**
+     * Check to see if a resource is currently write locked. The method
+     * will look at the "If" header to make sure the client
+     * has give the appropriate lock tokens.
+     *
+     * @param req Servlet request
+     * @return boolean true if the resource is locked (and no appropriate
+     * lock token has been found for at least one of the non-shared locks which
+     * are present on the resource).
+     */
+    private boolean isLocked(HttpServletRequest req) {
+
+        String path = getRelativePath(req);
+
+        String ifHeader = req.getHeader("If");
+        if (ifHeader == null)
+            ifHeader = "";
+
+        String lockTokenHeader = req.getHeader("Lock-Token");
+        if (lockTokenHeader == null)
+            lockTokenHeader = "";
+
+        return isLocked(path, ifHeader + lockTokenHeader);
+
+    }
+
+
+    /**
+     * Check to see if a resource is currently write locked.
+     *
+     * @param path Path of the resource
+     * @param ifHeader "If" HTTP header which was included in the request
+     * @return boolean true if the resource is locked (and no appropriate
+     * lock token has been found for at least one of the non-shared locks which
+     * are present on the resource).
+     */
+    private boolean isLocked(String path, String ifHeader) {
+
+        // Checking resource locks
+
+        LockInfo lock = (LockInfo) resourceLocks.get(path);
+        Enumeration tokenList = null;
+        if ((lock != null) && (lock.hasExpired())) {
+            resourceLocks.remove(path);
+        } else if (lock != null) {
+
+            // At least one of the tokens of the locks must have been given
+
+            tokenList = lock.tokens.elements();
+            boolean tokenMatch = false;
+            while (tokenList.hasMoreElements()) {
+                String token = (String) tokenList.nextElement();
+                if (ifHeader.indexOf(token) != -1)
+                    tokenMatch = true;
+            }
+            if (!tokenMatch)
+                return true;
+
+        }
+
+        // Checking inheritable collection locks
+
+        Enumeration collectionLocksList = collectionLocks.elements();
+        while (collectionLocksList.hasMoreElements()) {
+            lock = (LockInfo) collectionLocksList.nextElement();
+            if (lock.hasExpired()) {
+                collectionLocks.removeElement(lock);
+            } else if (path.startsWith(lock.path)) {
+
+                tokenList = lock.tokens.elements();
+                boolean tokenMatch = false;
+                while (tokenList.hasMoreElements()) {
+                    String token = (String) tokenList.nextElement();
+                    if (ifHeader.indexOf(token) != -1)
+                        tokenMatch = true;
+                }
+                if (!tokenMatch)
+                    return true;
+
+            }
+        }
+
+        return false;
+
+    }
+
+
+    /**
+     * Copy a resource.
+     *
+     * @param req Servlet request
+     * @param resp Servlet response
+     * @return boolean true if the copy is successful
+     */
+    private boolean copyResource(HttpServletRequest req,
+                                 HttpServletResponse resp)
+        throws ServletException, IOException {
+
+        // Parsing destination header
+
+        String destinationPath = req.getHeader("Destination");
+
+        if (destinationPath == null) {
+            resp.sendError(WebdavStatus.SC_BAD_REQUEST);
+            return false;
+        }
+
+        // Remove url encoding from destination
+        destinationPath = RequestUtil.URLDecode(destinationPath, "UTF8");
+
+        int protocolIndex = destinationPath.indexOf("://");
+        if (protocolIndex >= 0) {
+            // if the Destination URL contains the protocol, we can safely
+            // trim everything upto the first "/" character after "://"
+            int firstSeparator =
+                destinationPath.indexOf("/", protocolIndex + 4);
+            if (firstSeparator < 0) {
+                destinationPath = "/";
+            } else {
+                destinationPath = destinationPath.substring(firstSeparator);
+            }
+        } else {
+            String hostName = req.getServerName();
+            if ((hostName != null) && (destinationPath.startsWith(hostName))) {
+                destinationPath = destinationPath.substring(hostName.length());
+            }
+
+            int portIndex = destinationPath.indexOf(":");
+            if (portIndex >= 0) {
+                destinationPath = destinationPath.substring(portIndex);
+            }
+
+            if (destinationPath.startsWith(":")) {
+                int firstSeparator = destinationPath.indexOf("/");
+                if (firstSeparator < 0) {
+                    destinationPath = "/";
+                } else {
+                    destinationPath =
+                        destinationPath.substring(firstSeparator);
+                }
+            }
+        }
+
+        // Normalise destination path (remove '.' and '..')
+        destinationPath = normalize(destinationPath);
+
+        String contextPath = req.getContextPath();
+        if ((contextPath != null) &&
+            (destinationPath.startsWith(contextPath))) {
+            destinationPath = destinationPath.substring(contextPath.length());
+        }
+
+        String pathInfo = req.getPathInfo();
+        if (pathInfo != null) {
+            String servletPath = req.getServletPath();
+            if ((servletPath != null) &&
+                (destinationPath.startsWith(servletPath))) {
+                destinationPath = destinationPath
+                    .substring(servletPath.length());
+            }
+        }
+
+        if (debug > 0)
+            log("Dest path :" + destinationPath);
+
+        if ((destinationPath.toUpperCase().startsWith("/WEB-INF")) ||
+            (destinationPath.toUpperCase().startsWith("/META-INF"))) {
+            resp.sendError(WebdavStatus.SC_FORBIDDEN);
+            return false;
+        }
+
+        String path = getRelativePath(req);
+
+        if ((path.toUpperCase().startsWith("/WEB-INF")) ||
+            (path.toUpperCase().startsWith("/META-INF"))) {
+            resp.sendError(WebdavStatus.SC_FORBIDDEN);
+            return false;
+        }
+
+        if (destinationPath.equals(path)) {
+            resp.sendError(WebdavStatus.SC_FORBIDDEN);
+            return false;
+        }
+
+        // Parsing overwrite header
+
+        boolean overwrite = true;
+        String overwriteHeader = req.getHeader("Overwrite");
+
+        if (overwriteHeader != null) {
+            if (overwriteHeader.equalsIgnoreCase("T")) {
+                overwrite = true;
+            } else {
+                overwrite = false;
+            }
+        }
+
+        // Overwriting the destination
+
+        boolean exists = true;
+        try {
+            resources.lookup(destinationPath);
+        } catch (NamingException e) {
+            exists = false;
+        }
+
+        if (overwrite) {
+
+            // Delete destination resource, if it exists
+            if (exists) {
+                if (!deleteResource(destinationPath, req, resp, true)) {
+                    return false;
+                }
+            } else {
+                resp.setStatus(WebdavStatus.SC_CREATED);
+            }
+
+        } else {
+
+            // If the destination exists, then it's a conflict
+            if (exists) {
+                resp.sendError(WebdavStatus.SC_PRECONDITION_FAILED);
+                return false;
+            }
+
+        }
+
+        // Copying source to destination
+
+        Hashtable errorList = new Hashtable();
+
+        boolean result = copyResource(resources, errorList,
+                                      path, destinationPath);
+
+        if ((!result) || (!errorList.isEmpty())) {
+
+            sendReport(req, resp, errorList);
+            return false;
+
+        }
+
+        // Removing any lock-null resource which would be present at
+        // the destination path
+        lockNullResources.remove(destinationPath);
+
+        return true;
+
+    }
+
+
+    /**
+     * Copy a collection.
+     *
+     * @param resources Resources implementation to be used
+     * @param errorList Hashtable containing the list of errors which occurred
+     * during the copy operation
+     * @param source Path of the resource to be copied
+     * @param dest Destination path
+     */
+    private boolean copyResource(DirContext resources, Hashtable errorList,
+                                 String source, String dest) {
+
+        if (debug > 1)
+            log("Copy: " + source + " To: " + dest);
+
+        Object object = null;
+        try {
+            object = resources.lookup(source);
+        } catch (NamingException e) {
+        }
+
+        if (object instanceof DirContext) {
+
+            try {
+                resources.createSubcontext(dest);
+            } catch (NamingException e) {
+                errorList.put
+                    (dest, new Integer(WebdavStatus.SC_CONFLICT));
+                return false;
+            }
+
+            try {
+                NamingEnumeration enumeration = resources.list(source);
+                while (enumeration.hasMoreElements()) {
+                    NameClassPair ncPair = (NameClassPair) enumeration.nextElement();
+                    String childDest = dest;
+                    if (!childDest.equals("/"))
+                        childDest += "/";
+                    childDest += ncPair.getName();
+                    String childSrc = source;
+                    if (!childSrc.equals("/"))
+                        childSrc += "/";
+                    childSrc += ncPair.getName();
+                    copyResource(resources, errorList, childSrc, childDest);
+                }
+            } catch (NamingException e) {
+                errorList.put
+                    (dest, new Integer(WebdavStatus.SC_INTERNAL_SERVER_ERROR));
+                return false;
+            }
+
+        } else {
+
+            if (object instanceof Resource) {
+                try {
+                    resources.bind(dest, object);
+                } catch (NamingException e) {
+                    errorList.put
+                        (source,
+                         new Integer(WebdavStatus.SC_INTERNAL_SERVER_ERROR));
+                    return false;
+                }
+            } else {
+                errorList.put
+                    (source,
+                     new Integer(WebdavStatus.SC_INTERNAL_SERVER_ERROR));
+                return false;
+            }
+
+        }
+
+        return true;
+
+    }
+
+
+    /**
+     * Delete a resource.
+     *
+     * @param req Servlet request
+     * @param resp Servlet response
+     * @return boolean true if the copy is successful
+     */
+    private boolean deleteResource(HttpServletRequest req,
+                                   HttpServletResponse resp)
+        throws ServletException, IOException {
+
+        String path = getRelativePath(req);
+
+        return deleteResource(path, req, resp, true);
+
+    }
+
+
+    /**
+     * Delete a resource.
+     *
+     * @param path Path of the resource which is to be deleted
+     * @param req Servlet request
+     * @param resp Servlet response
+     * @param setStatus Should the response status be set on successful
+     *                  completion
+     */
+    private boolean deleteResource(String path, HttpServletRequest req,
+                                   HttpServletResponse resp, boolean setStatus)
+        throws ServletException, IOException {
+
+        if ((path.toUpperCase().startsWith("/WEB-INF")) ||
+            (path.toUpperCase().startsWith("/META-INF"))) {
+            resp.sendError(WebdavStatus.SC_FORBIDDEN);
+            return false;
+        }
+
+        String ifHeader = req.getHeader("If");
+        if (ifHeader == null)
+            ifHeader = "";
+
+        String lockTokenHeader = req.getHeader("Lock-Token");
+        if (lockTokenHeader == null)
+            lockTokenHeader = "";
+
+        if (isLocked(path, ifHeader + lockTokenHeader)) {
+            resp.sendError(WebdavStatus.SC_LOCKED);
+            return false;
+        }
+
+        boolean exists = true;
+        Object object = null;
+        try {
+            object = resources.lookup(path);
+        } catch (NamingException e) {
+            exists = false;
+        }
+
+        if (!exists) {
+            resp.sendError(WebdavStatus.SC_NOT_FOUND);
+            return false;
+        }
+
+        boolean collection = (object instanceof DirContext);
+
+        if (!collection) {
+            try {
+                resources.unbind(path);
+            } catch (NamingException e) {
+                resp.sendError(WebdavStatus.SC_INTERNAL_SERVER_ERROR);
+                return false;
+            }
+        } else {
+
+            Hashtable errorList = new Hashtable();
+
+            deleteCollection(req, resources, path, errorList);
+            try {
+                resources.unbind(path);
+            } catch (NamingException e) {
+                errorList.put(path, new Integer
+                    (WebdavStatus.SC_INTERNAL_SERVER_ERROR));
+            }
+
+            if (!errorList.isEmpty()) {
+
+                sendReport(req, resp, errorList);
+                return false;
+
+            }
+
+        }
+        if (setStatus) {
+            resp.setStatus(WebdavStatus.SC_NO_CONTENT);
+        }
+        return true;
+
+    }
+
+
+    /**
+     * Deletes a collection.
+     *
+     * @param resources Resources implementation associated with the context
+     * @param path Path to the collection to be deleted
+     * @param errorList Contains the list of the errors which occurred
+     */
+    private void deleteCollection(HttpServletRequest req,
+                                  DirContext resources,
+                                  String path, Hashtable errorList) {
+
+        if (debug > 1)
+            log("Delete:" + path);
+
+        if ((path.toUpperCase().startsWith("/WEB-INF")) ||
+            (path.toUpperCase().startsWith("/META-INF"))) {
+            errorList.put(path, new Integer(WebdavStatus.SC_FORBIDDEN));
+            return;
+        }
+
+        String ifHeader = req.getHeader("If");
+        if (ifHeader == null)
+            ifHeader = "";
+
+        String lockTokenHeader = req.getHeader("Lock-Token");
+        if (lockTokenHeader == null)
+            lockTokenHeader = "";
+
+        Enumeration enumeration = null;
+        try {
+            enumeration = resources.list(path);
+        } catch (NamingException e) {
+            errorList.put(path, new Integer
+                (WebdavStatus.SC_INTERNAL_SERVER_ERROR));
+            return;
+        }
+
+        while (enumeration.hasMoreElements()) {
+            NameClassPair ncPair = (NameClassPair) enumeration.nextElement();
+            String childName = path;
+            if (!childName.equals("/"))
+                childName += "/";
+            childName += ncPair.getName();
+
+            if (isLocked(childName, ifHeader + lockTokenHeader)) {
+
+                errorList.put(childName, new Integer(WebdavStatus.SC_LOCKED));
+
+            } else {
+
+                try {
+                    Object object = resources.lookup(childName);
+                    if (object instanceof DirContext) {
+                        deleteCollection(req, resources, childName, errorList);
+                    }
+
+                    try {
+                        resources.unbind(childName);
+                    } catch (NamingException e) {
+                        if (!(object instanceof DirContext)) {
+                            // If it's not a collection, then it's an unknown
+                            // error
+                            errorList.put
+                                (childName, new Integer
+                                    (WebdavStatus.SC_INTERNAL_SERVER_ERROR));
+                        }
+                    }
+                } catch (NamingException e) {
+                    errorList.put
+                        (childName, new Integer
+                            (WebdavStatus.SC_INTERNAL_SERVER_ERROR));
+                }
+            }
+
+        }
+
+    }
+
+
+    /**
+     * Send a multistatus element containing a complete error report to the
+     * client.
+     *
+     * @param req Servlet request
+     * @param resp Servlet response
+     * @param errorList List of error to be displayed
+     */
+    private void sendReport(HttpServletRequest req, HttpServletResponse resp,
+                            Hashtable errorList)
+        throws ServletException, IOException {
+
+        resp.setStatus(WebdavStatus.SC_MULTI_STATUS);
+
+        String absoluteUri = req.getRequestURI();
+        String relativePath = getRelativePath(req);
+
+        XMLWriter generatedXML = new XMLWriter();
+        generatedXML.writeXMLHeader();
+
+        generatedXML.writeElement(null, "multistatus"
+                                  + generateNamespaceDeclarations(),
+                                  XMLWriter.OPENING);
+
+        Enumeration pathList = errorList.keys();
+        while (pathList.hasMoreElements()) {
+
+            String errorPath = (String) pathList.nextElement();
+            int errorCode = ((Integer) errorList.get(errorPath)).intValue();
+
+            generatedXML.writeElement(null, "response", XMLWriter.OPENING);
+
+            generatedXML.writeElement(null, "href", XMLWriter.OPENING);
+            String toAppend = errorPath.substring(relativePath.length());
+            if (!toAppend.startsWith("/"))
+                toAppend = "/" + toAppend;
+            generatedXML.writeText(absoluteUri + toAppend);
+            generatedXML.writeElement(null, "href", XMLWriter.CLOSING);
+            generatedXML.writeElement(null, "status", XMLWriter.OPENING);
+            generatedXML
+                .writeText("HTTP/1.1 " + errorCode + " "
+                           + WebdavStatus.getStatusText(errorCode));
+            generatedXML.writeElement(null, "status", XMLWriter.CLOSING);
+
+            generatedXML.writeElement(null, "response", XMLWriter.CLOSING);
+
+        }
+
+        generatedXML.writeElement(null, "multistatus", XMLWriter.CLOSING);
+
+        Writer writer = resp.getWriter();
+        writer.write(generatedXML.toString());
+        writer.close();
+
+    }
+
+
+    /**
+     * Propfind helper method.
+     *
+     * @param req The servlet request
+     * @param resources Resources object associated with this context
+     * @param generatedXML XML response to the Propfind request
+     * @param path Path of the current resource
+     * @param type Propfind type
+     * @param propertiesVector If the propfind type is find properties by
+     * name, then this Vector contains those properties
+     */
+    private void parseProperties(HttpServletRequest req,
+                                 XMLWriter generatedXML,
+                                 String path, int type,
+                                 Vector propertiesVector) {
+
+        // Exclude any resource in the /WEB-INF and /META-INF subdirectories
+        // (the "toUpperCase()" avoids problems on Windows systems)
+        if (path.toUpperCase().startsWith("/WEB-INF") ||
+            path.toUpperCase().startsWith("/META-INF"))
+            return;
+
+        CacheEntry cacheEntry = resources.lookupCache(path);
+
+        generatedXML.writeElement(null, "response", XMLWriter.OPENING);
+        String status = new String("HTTP/1.1 " + WebdavStatus.SC_OK + " "
+                                   + WebdavStatus.getStatusText
+                                   (WebdavStatus.SC_OK));
+
+        // Generating href element
+        generatedXML.writeElement(null, "href", XMLWriter.OPENING);
+
+        String href = req.getContextPath() + req.getServletPath();
+        if ((href.endsWith("/")) && (path.startsWith("/")))
+            href += path.substring(1);
+        else
+            href += path;
+        if ((cacheEntry.context != null) && (!href.endsWith("/")))
+            href += "/";
+
+        generatedXML.writeText(rewriteUrl(href));
+
+        generatedXML.writeElement(null, "href", XMLWriter.CLOSING);
+
+        String resourceName = path;
+        int lastSlash = path.lastIndexOf('/');
+        if (lastSlash != -1)
+            resourceName = resourceName.substring(lastSlash + 1);
+
+        switch (type) {
+
+        case FIND_ALL_PROP :
+
+            generatedXML.writeElement(null, "propstat", XMLWriter.OPENING);
+            generatedXML.writeElement(null, "prop", XMLWriter.OPENING);
+
+            generatedXML.writeProperty
+                (null, "creationdate",
+                 getISOCreationDate(cacheEntry.attributes.getCreation()));
+            generatedXML.writeElement(null, "displayname", XMLWriter.OPENING);
+            generatedXML.writeData(resourceName);
+            generatedXML.writeElement(null, "displayname", XMLWriter.CLOSING);
+            if (cacheEntry.resource != null) {
+                generatedXML.writeProperty
+                    (null, "getlastmodified", FastHttpDateFormat.formatDate
+                           (cacheEntry.attributes.getLastModified(), null));
+                generatedXML.writeProperty
+                    (null, "getcontentlength",
+                     String.valueOf(cacheEntry.attributes.getContentLength()));
+                String contentType = getServletContext().getMimeType
+                    (cacheEntry.name);
+                if (contentType != null) {
+                    generatedXML.writeProperty(null, "getcontenttype",
+                                               contentType);
+                }
+                generatedXML.writeProperty(null, "getetag",
+                                           getETag(cacheEntry.attributes));
+                generatedXML.writeElement(null, "resourcetype",
+                                          XMLWriter.NO_CONTENT);
+            } else {
+                generatedXML.writeElement(null, "resourcetype",
+                                          XMLWriter.OPENING);
+                generatedXML.writeElement(null, "collection",
+                                          XMLWriter.NO_CONTENT);
+                generatedXML.writeElement(null, "resourcetype",
+                                          XMLWriter.CLOSING);
+            }
+
+            generatedXML.writeProperty(null, "source", "");
+
+            String supportedLocks = "<lockentry>"
+                + "<lockscope><exclusive/></lockscope>"
+                + "<locktype><write/></locktype>"
+                + "</lockentry>" + "<lockentry>"
+                + "<lockscope><shared/></lockscope>"
+                + "<locktype><write/></locktype>"
+                + "</lockentry>";
+            generatedXML.writeElement(null, "supportedlock",
+                                      XMLWriter.OPENING);
+            generatedXML.writeText(supportedLocks);
+            generatedXML.writeElement(null, "supportedlock",
+                                      XMLWriter.CLOSING);
+
+            generateLockDiscovery(path, generatedXML);
+
+            generatedXML.writeElement(null, "prop", XMLWriter.CLOSING);
+            generatedXML.writeElement(null, "status", XMLWriter.OPENING);
+            generatedXML.writeText(status);
+            generatedXML.writeElement(null, "status", XMLWriter.CLOSING);
+            generatedXML.writeElement(null, "propstat", XMLWriter.CLOSING);
+
+            break;
+
+        case FIND_PROPERTY_NAMES :
+
+            generatedXML.writeElement(null, "propstat", XMLWriter.OPENING);
+            generatedXML.writeElement(null, "prop", XMLWriter.OPENING);
+
+            generatedXML.writeElement(null, "creationdate",
+                                      XMLWriter.NO_CONTENT);
+            generatedXML.writeElement(null, "displayname",
+                                      XMLWriter.NO_CONTENT);
+            if (cacheEntry.resource != null) {
+                generatedXML.writeElement(null, "getcontentlanguage",
+                                          XMLWriter.NO_CONTENT);
+                generatedXML.writeElement(null, "getcontentlength",
+                                          XMLWriter.NO_CONTENT);
+                generatedXML.writeElement(null, "getcontenttype",
+                                          XMLWriter.NO_CONTENT);
+                generatedXML.writeElement(null, "getetag",
+                                          XMLWriter.NO_CONTENT);
+                generatedXML.writeElement(null, "getlastmodified",
+                                          XMLWriter.NO_CONTENT);
+            }
+            generatedXML.writeElement(null, "resourcetype",
+                                      XMLWriter.NO_CONTENT);
+            generatedXML.writeElement(null, "source", XMLWriter.NO_CONTENT);
+            generatedXML.writeElement(null, "lockdiscovery",
+                                      XMLWriter.NO_CONTENT);
+
+            generatedXML.writeElement(null, "prop", XMLWriter.CLOSING);
+            generatedXML.writeElement(null, "status", XMLWriter.OPENING);
+            generatedXML.writeText(status);
+            generatedXML.writeElement(null, "status", XMLWriter.CLOSING);
+            generatedXML.writeElement(null, "propstat", XMLWriter.CLOSING);
+
+            break;
+
+        case FIND_BY_PROPERTY :
+
+            Vector propertiesNotFound = new Vector();
+
+            // Parse the list of properties
+
+            generatedXML.writeElement(null, "propstat", XMLWriter.OPENING);
+            generatedXML.writeElement(null, "prop", XMLWriter.OPENING);
+
+            Enumeration properties = propertiesVector.elements();
+
+            while (properties.hasMoreElements()) {
+
+                String property = (String) properties.nextElement();
+
+                if (property.equals("creationdate")) {
+                    generatedXML.writeProperty
+                        (null, "creationdate",
+                         getISOCreationDate(cacheEntry.attributes.getCreation()));
+                } else if (property.equals("displayname")) {
+                    generatedXML.writeElement
+                        (null, "displayname", XMLWriter.OPENING);
+                    generatedXML.writeData(resourceName);
+                    generatedXML.writeElement
+                        (null, "displayname", XMLWriter.CLOSING);
+                } else if (property.equals("getcontentlanguage")) {
+                    if (cacheEntry.context != null) {
+                        propertiesNotFound.addElement(property);
+                    } else {
+                        generatedXML.writeElement(null, "getcontentlanguage",
+                                                  XMLWriter.NO_CONTENT);
+                    }
+                } else if (property.equals("getcontentlength")) {
+                    if (cacheEntry.context != null) {
+                        propertiesNotFound.addElement(property);
+                    } else {
+                        generatedXML.writeProperty
+                            (null, "getcontentlength",
+                             (String.valueOf(cacheEntry.attributes.getContentLength())));
+                    }
+                } else if (property.equals("getcontenttype")) {
+                    if (cacheEntry.context != null) {
+                        propertiesNotFound.addElement(property);
+                    } else {
+                        generatedXML.writeProperty
+                            (null, "getcontenttype",
+                             getServletContext().getMimeType
+                             (cacheEntry.name));
+                    }
+                } else if (property.equals("getetag")) {
+                    if (cacheEntry.context != null) {
+                        propertiesNotFound.addElement(property);
+                    } else {
+                        generatedXML.writeProperty
+                            (null, "getetag", getETag(cacheEntry.attributes));
+                    }
+                } else if (property.equals("getlastmodified")) {
+                    if (cacheEntry.context != null) {
+                        propertiesNotFound.addElement(property);
+                    } else {
+                        generatedXML.writeProperty
+                            (null, "getlastmodified", FastHttpDateFormat.formatDate
+                                    (cacheEntry.attributes.getLastModified(), null));
+                    }
+                } else if (property.equals("resourcetype")) {
+                    if (cacheEntry.context != null) {
+                        generatedXML.writeElement(null, "resourcetype",
+                                                  XMLWriter.OPENING);
+                        generatedXML.writeElement(null, "collection",
+                                                  XMLWriter.NO_CONTENT);
+                        generatedXML.writeElement(null, "resourcetype",
+                                                  XMLWriter.CLOSING);
+                    } else {
+                        generatedXML.writeElement(null, "resourcetype",
+                                                  XMLWriter.NO_CONTENT);
+                    }
+                } else if (property.equals("source")) {
+                    generatedXML.writeProperty(null, "source", "");
+                } else if (property.equals("supportedlock")) {
+                    supportedLocks = "<lockentry>"
+                        + "<lockscope><exclusive/></lockscope>"
+                        + "<locktype><write/></locktype>"
+                        + "</lockentry>" + "<lockentry>"
+                        + "<lockscope><shared/></lockscope>"
+                        + "<locktype><write/></locktype>"
+                        + "</lockentry>";
+                    generatedXML.writeElement(null, "supportedlock",
+                                              XMLWriter.OPENING);
+                    generatedXML.writeText(supportedLocks);
+                    generatedXML.writeElement(null, "supportedlock",
+                                              XMLWriter.CLOSING);
+                } else if (property.equals("lockdiscovery")) {
+                    if (!generateLockDiscovery(path, generatedXML))
+                        propertiesNotFound.addElement(property);
+                } else {
+                    propertiesNotFound.addElement(property);
+                }
+
+            }
+
+            generatedXML.writeElement(null, "prop", XMLWriter.CLOSING);
+            generatedXML.writeElement(null, "status", XMLWriter.OPENING);
+            generatedXML.writeText(status);
+            generatedXML.writeElement(null, "status", XMLWriter.CLOSING);
+            generatedXML.writeElement(null, "propstat", XMLWriter.CLOSING);
+
+            Enumeration propertiesNotFoundList = propertiesNotFound.elements();
+
+            if (propertiesNotFoundList.hasMoreElements()) {
+
+                status = new String("HTTP/1.1 " + WebdavStatus.SC_NOT_FOUND
+                                    + " " + WebdavStatus.getStatusText
+                                    (WebdavStatus.SC_NOT_FOUND));
+
+                generatedXML.writeElement(null, "propstat", XMLWriter.OPENING);
+                generatedXML.writeElement(null, "prop", XMLWriter.OPENING);
+
+                while (propertiesNotFoundList.hasMoreElements()) {
+                    generatedXML.writeElement
+                        (null, (String) propertiesNotFoundList.nextElement(),
+                         XMLWriter.NO_CONTENT);
+                }
+
+                generatedXML.writeElement(null, "prop", XMLWriter.CLOSING);
+                generatedXML.writeElement(null, "status", XMLWriter.OPENING);
+                generatedXML.writeText(status);
+                generatedXML.writeElement(null, "status", XMLWriter.CLOSING);
+                generatedXML.writeElement(null, "propstat", XMLWriter.CLOSING);
+
+            }
+
+            break;
+
+        }
+
+        generatedXML.writeElement(null, "response", XMLWriter.CLOSING);
+
+    }
+
+
+    /**
+     * Propfind helper method. Dispays the properties of a lock-null resource.
+     *
+     * @param resources Resources object associated with this context
+     * @param generatedXML XML response to the Propfind request
+     * @param path Path of the current resource
+     * @param type Propfind type
+     * @param propertiesVector If the propfind type is find properties by
+     * name, then this Vector contains those properties
+     */
+    private void parseLockNullProperties(HttpServletRequest req,
+                                         XMLWriter generatedXML,
+                                         String path, int type,
+                                         Vector propertiesVector) {
+
+        // Exclude any resource in the /WEB-INF and /META-INF subdirectories
+        // (the "toUpperCase()" avoids problems on Windows systems)
+        if (path.toUpperCase().startsWith("/WEB-INF") ||
+            path.toUpperCase().startsWith("/META-INF"))
+            return;
+
+        // Retrieving the lock associated with the lock-null resource
+        LockInfo lock = (LockInfo) resourceLocks.get(path);
+
+        if (lock == null)
+            return;
+
+        generatedXML.writeElement(null, "response", XMLWriter.OPENING);
+        String status = new String("HTTP/1.1 " + WebdavStatus.SC_OK + " "
+                                   + WebdavStatus.getStatusText
+                                   (WebdavStatus.SC_OK));
+
+        // Generating href element
+        generatedXML.writeElement(null, "href", XMLWriter.OPENING);
+
+        String absoluteUri = req.getRequestURI();
+        String relativePath = getRelativePath(req);
+        String toAppend = path.substring(relativePath.length());
+        if (!toAppend.startsWith("/"))
+            toAppend = "/" + toAppend;
+
+        generatedXML.writeText(rewriteUrl(normalize(absoluteUri + toAppend)));
+
+        generatedXML.writeElement(null, "href", XMLWriter.CLOSING);
+
+        String resourceName = path;
+        int lastSlash = path.lastIndexOf('/');
+        if (lastSlash != -1)
+            resourceName = resourceName.substring(lastSlash + 1);
+
+        switch (type) {
+
+        case FIND_ALL_PROP :
+
+            generatedXML.writeElement(null, "propstat", XMLWriter.OPENING);
+            generatedXML.writeElement(null, "prop", XMLWriter.OPENING);
+
+            generatedXML.writeProperty
+                (null, "creationdate",
+                 getISOCreationDate(lock.creationDate.getTime()));
+            generatedXML.writeElement
+                (null, "displayname", XMLWriter.OPENING);
+            generatedXML.writeData(resourceName);
+            generatedXML.writeElement
+                (null, "displayname", XMLWriter.CLOSING);
+            generatedXML.writeProperty(null, "getlastmodified",
+                                       FastHttpDateFormat.formatDate
+                                       (lock.creationDate.getTime(), null));
+            generatedXML.writeProperty
+                (null, "getcontentlength", String.valueOf(0));
+            generatedXML.writeProperty(null, "getcontenttype", "");
+            generatedXML.writeProperty(null, "getetag", "");
+            generatedXML.writeElement(null, "resourcetype",
+                                      XMLWriter.OPENING);
+            generatedXML.writeElement(null, "lock-null", XMLWriter.NO_CONTENT);
+            generatedXML.writeElement(null, "resourcetype",
+                                      XMLWriter.CLOSING);
+
+            generatedXML.writeProperty(null, "source", "");
+
+            String supportedLocks = "<lockentry>"
+                + "<lockscope><exclusive/></lockscope>"
+                + "<locktype><write/></locktype>"
+                + "</lockentry>" + "<lockentry>"
+                + "<lockscope><shared/></lockscope>"
+                + "<locktype><write/></locktype>"
+                + "</lockentry>";
+            generatedXML.writeElement(null, "supportedlock",
+                                      XMLWriter.OPENING);
+            generatedXML.writeText(supportedLocks);
+            generatedXML.writeElement(null, "supportedlock",
+                                      XMLWriter.CLOSING);
+
+            generateLockDiscovery(path, generatedXML);
+
+            generatedXML.writeElement(null, "prop", XMLWriter.CLOSING);
+            generatedXML.writeElement(null, "status", XMLWriter.OPENING);
+            generatedXML.writeText(status);
+            generatedXML.writeElement(null, "status", XMLWriter.CLOSING);
+            generatedXML.writeElement(null, "propstat", XMLWriter.CLOSING);
+
+            break;
+
+        case FIND_PROPERTY_NAMES :
+
+            generatedXML.writeElement(null, "propstat", XMLWriter.OPENING);
+            generatedXML.writeElement(null, "prop", XMLWriter.OPENING);
+
+            generatedXML.writeElement(null, "creationdate",
+                                      XMLWriter.NO_CONTENT);
+            generatedXML.writeElement(null, "displayname",
+                                      XMLWriter.NO_CONTENT);
+            generatedXML.writeElement(null, "getcontentlanguage",
+                                      XMLWriter.NO_CONTENT);
+            generatedXML.writeElement(null, "getcontentlength",
+                                      XMLWriter.NO_CONTENT);
+            generatedXML.writeElement(null, "getcontenttype",
+                                      XMLWriter.NO_CONTENT);
+            generatedXML.writeElement(null, "getetag",
+                                      XMLWriter.NO_CONTENT);
+            generatedXML.writeElement(null, "getlastmodified",
+                                      XMLWriter.NO_CONTENT);
+            generatedXML.writeElement(null, "resourcetype",
+                                      XMLWriter.NO_CONTENT);
+            generatedXML.writeElement(null, "source",
+                                      XMLWriter.NO_CONTENT);
+            generatedXML.writeElement(null, "lockdiscovery",
+                                      XMLWriter.NO_CONTENT);
+
+            generatedXML.writeElement(null, "prop", XMLWriter.CLOSING);
+            generatedXML.writeElement(null, "status", XMLWriter.OPENING);
+            generatedXML.writeText(status);
+            generatedXML.writeElement(null, "status", XMLWriter.CLOSING);
+            generatedXML.writeElement(null, "propstat", XMLWriter.CLOSING);
+
+            break;
+
+        case FIND_BY_PROPERTY :
+
+            Vector propertiesNotFound = new Vector();
+
+            // Parse the list of properties
+
+            generatedXML.writeElement(null, "propstat", XMLWriter.OPENING);
+            generatedXML.writeElement(null, "prop", XMLWriter.OPENING);
+
+            Enumeration properties = propertiesVector.elements();
+
+            while (properties.hasMoreElements()) {
+
+                String property = (String) properties.nextElement();
+
+                if (property.equals("creationdate")) {
+                    generatedXML.writeProperty
+                        (null, "creationdate",
+                         getISOCreationDate(lock.creationDate.getTime()));
+                } else if (property.equals("displayname")) {
+                    generatedXML.writeElement
+                        (null, "displayname", XMLWriter.OPENING);
+                    generatedXML.writeData(resourceName);
+                    generatedXML.writeElement
+                        (null, "displayname", XMLWriter.CLOSING);
+                } else if (property.equals("getcontentlanguage")) {
+                    generatedXML.writeElement(null, "getcontentlanguage",
+                                              XMLWriter.NO_CONTENT);
+                } else if (property.equals("getcontentlength")) {
+                    generatedXML.writeProperty
+                        (null, "getcontentlength", (String.valueOf(0)));
+                } else if (property.equals("getcontenttype")) {
+                    generatedXML.writeProperty
+                        (null, "getcontenttype", "");
+                } else if (property.equals("getetag")) {
+                    generatedXML.writeProperty(null, "getetag", "");
+                } else if (property.equals("getlastmodified")) {
+                    generatedXML.writeProperty
+                        (null, "getlastmodified",
+                          FastHttpDateFormat.formatDate
+                         (lock.creationDate.getTime(), null));
+                } else if (property.equals("resourcetype")) {
+                    generatedXML.writeElement(null, "resourcetype",
+                                              XMLWriter.OPENING);
+                    generatedXML.writeElement(null, "lock-null",
+                                              XMLWriter.NO_CONTENT);
+                    generatedXML.writeElement(null, "resourcetype",
+                                              XMLWriter.CLOSING);
+                } else if (property.equals("source")) {
+                    generatedXML.writeProperty(null, "source", "");
+                } else if (property.equals("supportedlock")) {
+                    supportedLocks = "<lockentry>"
+                        + "<lockscope><exclusive/></lockscope>"
+                        + "<locktype><write/></locktype>"
+                        + "</lockentry>" + "<lockentry>"
+                        + "<lockscope><shared/></lockscope>"
+                        + "<locktype><write/></locktype>"
+                        + "</lockentry>";
+                    generatedXML.writeElement(null, "supportedlock",
+                                              XMLWriter.OPENING);
+                    generatedXML.writeText(supportedLocks);
+                    generatedXML.writeElement(null, "supportedlock",
+                                              XMLWriter.CLOSING);
+                } else if (property.equals("lockdiscovery")) {
+                    if (!generateLockDiscovery(path, generatedXML))
+                        propertiesNotFound.addElement(property);
+                } else {
+                    propertiesNotFound.addElement(property);
+                }
+
+            }
+
+            generatedXML.writeElement(null, "prop", XMLWriter.CLOSING);
+            generatedXML.writeElement(null, "status", XMLWriter.OPENING);
+            generatedXML.writeText(status);
+            generatedXML.writeElement(null, "status", XMLWriter.CLOSING);
+            generatedXML.writeElement(null, "propstat", XMLWriter.CLOSING);
+
+            Enumeration propertiesNotFoundList = propertiesNotFound.elements();
+
+            if (propertiesNotFoundList.hasMoreElements()) {
+
+                status = new String("HTTP/1.1 " + WebdavStatus.SC_NOT_FOUND
+                                    + " " + WebdavStatus.getStatusText
+                                    (WebdavStatus.SC_NOT_FOUND));
+
+                generatedXML.writeElement(null, "propstat", XMLWriter.OPENING);
+                generatedXML.writeElement(null, "prop", XMLWriter.OPENING);
+
+                while (propertiesNotFoundList.hasMoreElements()) {
+                    generatedXML.writeElement
+                        (null, (String) propertiesNotFoundList.nextElement(),
+                         XMLWriter.NO_CONTENT);
+                }
+
+                generatedXML.writeElement(null, "prop", XMLWriter.CLOSING);
+                generatedXML.writeElement(null, "status", XMLWriter.OPENING);
+                generatedXML.writeText(status);
+                generatedXML.writeElement(null, "status", XMLWriter.CLOSING);
+                generatedXML.writeElement(null, "propstat", XMLWriter.CLOSING);
+
+            }
+
+            break;
+
+        }
+
+        generatedXML.writeElement(null, "response", XMLWriter.CLOSING);
+
+    }
+
+
+    /**
+     * Print the lock discovery information associated with a path.
+     *
+     * @param path Path
+     * @param generatedXML XML data to which the locks info will be appended
+     * @return true if at least one lock was displayed
+     */
+    private boolean generateLockDiscovery
+        (String path, XMLWriter generatedXML) {
+
+        LockInfo resourceLock = (LockInfo) resourceLocks.get(path);
+        Enumeration collectionLocksList = collectionLocks.elements();
+
+        boolean wroteStart = false;
+
+        if (resourceLock != null) {
+            wroteStart = true;
+            generatedXML.writeElement(null, "lockdiscovery",
+                                      XMLWriter.OPENING);
+            resourceLock.toXML(generatedXML);
+        }
+
+        while (collectionLocksList.hasMoreElements()) {
+            LockInfo currentLock =
+                (LockInfo) collectionLocksList.nextElement();
+            if (path.startsWith(currentLock.path)) {
+                if (!wroteStart) {
+                    wroteStart = true;
+                    generatedXML.writeElement(null, "lockdiscovery",
+                                              XMLWriter.OPENING);
+                }
+                currentLock.toXML(generatedXML);
+            }
+        }
+
+        if (wroteStart) {
+            generatedXML.writeElement(null, "lockdiscovery",
+                                      XMLWriter.CLOSING);
+        } else {
+            return false;
+        }
+
+        return true;
+
+    }
+
+
+    /**
+     * Get creation date in ISO format.
+     */
+    private String getISOCreationDate(long creationDate) {
+        StringBuffer creationDateValue = new StringBuffer
+            (creationDateFormat.format
+             (new Date(creationDate)));
+        /*
+        int offset = Calendar.getInstance().getTimeZone().getRawOffset()
+            / 3600000; // FIXME ?
+        if (offset < 0) {
+            creationDateValue.append("-");
+            offset = -offset;
+        } else if (offset > 0) {
+            creationDateValue.append("+");
+        }
+        if (offset != 0) {
+            if (offset < 10)
+                creationDateValue.append("0");
+            creationDateValue.append(offset + ":00");
+        } else {
+            creationDateValue.append("Z");
+        }
+        */
+        return creationDateValue.toString();
+    }
+
+    /**
+     * Determines the methods normally allowed for the resource.
+     *
+     */
+    private StringBuffer determineMethodsAllowed(DirContext resources,
+                                                 HttpServletRequest req) {
+
+        StringBuffer methodsAllowed = new StringBuffer();
+        boolean exists = true;
+        Object object = null;
+        try {
+            String path = getRelativePath(req);
+
+            object = resources.lookup(path);
+        } catch (NamingException e) {
+            exists = false;
+        }
+
+        if (!exists) {
+            methodsAllowed.append("OPTIONS, MKCOL, PUT, LOCK");
+            return methodsAllowed;
+        }
+
+        methodsAllowed.append("OPTIONS, GET, HEAD, POST, DELETE, TRACE");
+        methodsAllowed.append(", PROPPATCH, COPY, MOVE, LOCK, UNLOCK");
+
+        if (listings) {
+            methodsAllowed.append(", PROPFIND");
+        }
+
+        if (!(object instanceof DirContext)) {
+            methodsAllowed.append(", PUT");
+        }
+
+        return methodsAllowed;
+    }
+
+    // --------------------------------------------------  LockInfo Inner Class
+
+
+    /**
+     * Holds a lock information.
+     */
+    private class LockInfo {
+
+
+        // -------------------------------------------------------- Constructor
+
+
+        /**
+         * Constructor.
+         */
+        public LockInfo() {
+
+        }
+
+
+        // ------------------------------------------------- Instance Variables
+
+
+        String path = "/";
+        String type = "write";
+        String scope = "exclusive";
+        int depth = 0;
+        String owner = "";
+        Vector tokens = new Vector();
+        long expiresAt = 0;
+        Date creationDate = new Date();
+
+
+        // ----------------------------------------------------- Public Methods
+
+
+        /**
+         * Get a String representation of this lock token.
+         */
+        public String toString() {
+
+            String result =  "Type:" + type + "\n";
+            result += "Scope:" + scope + "\n";
+            result += "Depth:" + depth + "\n";
+            result += "Owner:" + owner + "\n";
+            result += "Expiration:"
+                + FastHttpDateFormat.formatDate(expiresAt, null) + "\n";
+            Enumeration tokensList = tokens.elements();
+            while (tokensList.hasMoreElements()) {
+                result += "Token:" + tokensList.nextElement() + "\n";
+            }
+            return result;
+
+        }
+
+
+        /**
+         * Return true if the lock has expired.
+         */
+        public boolean hasExpired() {
+            return (System.currentTimeMillis() > expiresAt);
+        }
+
+
+        /**
+         * Return true if the lock is exclusive.
+         */
+        public boolean isExclusive() {
+
+            return (scope.equals("exclusive"));
+
+        }
+
+
+        /**
+         * Get an XML representation of this lock token. This method will
+         * append an XML fragment to the given XML writer.
+         */
+        public void toXML(XMLWriter generatedXML) {
+
+            generatedXML.writeElement(null, "activelock", XMLWriter.OPENING);
+
+            generatedXML.writeElement(null, "locktype", XMLWriter.OPENING);
+            generatedXML.writeElement(null, type, XMLWriter.NO_CONTENT);
+            generatedXML.writeElement(null, "locktype", XMLWriter.CLOSING);
+
+            generatedXML.writeElement(null, "lockscope", XMLWriter.OPENING);
+            generatedXML.writeElement(null, scope, XMLWriter.NO_CONTENT);
+            generatedXML.writeElement(null, "lockscope", XMLWriter.CLOSING);
+
+            generatedXML.writeElement(null, "depth", XMLWriter.OPENING);
+            if (depth == INFINITY) {
+                generatedXML.writeText("Infinity");
+            } else {
+                generatedXML.writeText("0");
+            }
+            generatedXML.writeElement(null, "depth", XMLWriter.CLOSING);
+
+            generatedXML.writeElement(null, "owner", XMLWriter.OPENING);
+            generatedXML.writeText(owner);
+            generatedXML.writeElement(null, "owner", XMLWriter.CLOSING);
+
+            generatedXML.writeElement(null, "timeout", XMLWriter.OPENING);
+            long timeout = (expiresAt - System.currentTimeMillis()) / 1000;
+            generatedXML.writeText("Second-" + timeout);
+            generatedXML.writeElement(null, "timeout", XMLWriter.CLOSING);
+
+            generatedXML.writeElement(null, "locktoken", XMLWriter.OPENING);
+            Enumeration tokensList = tokens.elements();
+            while (tokensList.hasMoreElements()) {
+                generatedXML.writeElement(null, "href", XMLWriter.OPENING);
+                generatedXML.writeText("opaquelocktoken:"
+                                       + tokensList.nextElement());
+                generatedXML.writeElement(null, "href", XMLWriter.CLOSING);
+            }
+            generatedXML.writeElement(null, "locktoken", XMLWriter.CLOSING);
+
+            generatedXML.writeElement(null, "activelock", XMLWriter.CLOSING);
+
+        }
+
+
+    }
+
+
+    // --------------------------------------------------- Property Inner Class
+
+
+    private class Property {
+
+        public String name;
+        public String value;
+        public String namespace;
+        public String namespaceAbbrev;
+        public int status = WebdavStatus.SC_OK;
+
+    }
+
+
+};
+
+
+// --------------------------------------------------------  WebdavStatus Class
+
+
+/**
+ * Wraps the HttpServletResponse class to abstract the
+ * specific protocol used.  To support other protocols
+ * we would only need to modify this class and the
+ * WebDavRetCode classes.
+ *
+ * @author              Marc Eaddy
+ * @version             1.0, 16 Nov 1997
+ */
+class WebdavStatus {
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * This Hashtable contains the mapping of HTTP and WebDAV
+     * status codes to descriptive text.  This is a static
+     * variable.
+     */
+    private static Hashtable mapStatusCodes = new Hashtable();
+
+
+    // ------------------------------------------------------ HTTP Status Codes
+
+
+    /**
+     * Status code (200) indicating the request succeeded normally.
+     */
+    public static final int SC_OK = HttpServletResponse.SC_OK;
+
+
+    /**
+     * Status code (201) indicating the request succeeded and created
+     * a new resource on the server.
+     */
+    public static final int SC_CREATED = HttpServletResponse.SC_CREATED;
+
+
+    /**
+     * Status code (202) indicating that a request was accepted for
+     * processing, but was not completed.
+     */
+    public static final int SC_ACCEPTED = HttpServletResponse.SC_ACCEPTED;
+
+
+    /**
+     * Status code (204) indicating that the request succeeded but that
+     * there was no new information to return.
+     */
+    public static final int SC_NO_CONTENT = HttpServletResponse.SC_NO_CONTENT;
+
+
+    /**
+     * Status code (301) indicating that the resource has permanently
+     * moved to a new location, and that future references should use a
+     * new URI with their requests.
+     */
+    public static final int SC_MOVED_PERMANENTLY =
+        HttpServletResponse.SC_MOVED_PERMANENTLY;
+
+
+    /**
+     * Status code (302) indicating that the resource has temporarily
+     * moved to another location, but that future references should
+     * still use the original URI to access the resource.
+     */
+    public static final int SC_MOVED_TEMPORARILY =
+        HttpServletResponse.SC_MOVED_TEMPORARILY;
+
+
+    /**
+     * Status code (304) indicating that a conditional GET operation
+     * found that the resource was available and not modified.
+     */
+    public static final int SC_NOT_MODIFIED =
+        HttpServletResponse.SC_NOT_MODIFIED;
+
+
+    /**
+     * Status code (400) indicating the request sent by the client was
+     * syntactically incorrect.
+     */
+    public static final int SC_BAD_REQUEST =
+        HttpServletResponse.SC_BAD_REQUEST;
+
+
+    /**
+     * Status code (401) indicating that the request requires HTTP
+     * authentication.
+     */
+    public static final int SC_UNAUTHORIZED =
+        HttpServletResponse.SC_UNAUTHORIZED;
+
+
+    /**
+     * Status code (403) indicating the server understood the request
+     * but refused to fulfill it.
+     */
+    public static final int SC_FORBIDDEN = HttpServletResponse.SC_FORBIDDEN;
+
+
+    /**
+     * Status code (404) indicating that the requested resource is not
+     * available.
+     */
+    public static final int SC_NOT_FOUND = HttpServletResponse.SC_NOT_FOUND;
+
+
+    /**
+     * Status code (500) indicating an error inside the HTTP service
+     * which prevented it from fulfilling the request.
+     */
+    public static final int SC_INTERNAL_SERVER_ERROR =
+        HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
+
+
+    /**
+     * Status code (501) indicating the HTTP service does not support
+     * the functionality needed to fulfill the request.
+     */
+    public static final int SC_NOT_IMPLEMENTED =
+        HttpServletResponse.SC_NOT_IMPLEMENTED;
+
+
+    /**
+     * Status code (502) indicating that the HTTP server received an
+     * invalid response from a server it consulted when acting as a
+     * proxy or gateway.
+     */
+    public static final int SC_BAD_GATEWAY =
+        HttpServletResponse.SC_BAD_GATEWAY;
+
+
+    /**
+     * Status code (503) indicating that the HTTP service is
+     * temporarily overloaded, and unable to handle the request.
+     */
+    public static final int SC_SERVICE_UNAVAILABLE =
+        HttpServletResponse.SC_SERVICE_UNAVAILABLE;
+
+
+    /**
+     * Status code (100) indicating the client may continue with
+     * its request.  This interim response is used to inform the
+     * client that the initial part of the request has been
+     * received and has not yet been rejected by the server.
+     */
+    public static final int SC_CONTINUE = 100;
+
+
+    /**
+     * Status code (405) indicating the method specified is not
+     * allowed for the resource.
+     */
+    public static final int SC_METHOD_NOT_ALLOWED = 405;
+
+
+    /**
+     * Status code (409) indicating that the request could not be
+     * completed due to a conflict with the current state of the
+     * resource.
+     */
+    public static final int SC_CONFLICT = 409;
+
+
+    /**
+     * Status code (412) indicating the precondition given in one
+     * or more of the request-header fields evaluated to false
+     * when it was tested on the server.
+     */
+    public static final int SC_PRECONDITION_FAILED = 412;
+
+
+    /**
+     * Status code (413) indicating the server is refusing to
+     * process a request because the request entity is larger
+     * than the server is willing or able to process.
+     */
+    public static final int SC_REQUEST_TOO_LONG = 413;
+
+
+    /**
+     * Status code (415) indicating the server is refusing to service
+     * the request because the entity of the request is in a format
+     * not supported by the requested resource for the requested
+     * method.
+     */
+    public static final int SC_UNSUPPORTED_MEDIA_TYPE = 415;
+
+
+    // -------------------------------------------- Extended WebDav status code
+
+
+    /**
+     * Status code (207) indicating that the response requires
+     * providing status for multiple independent operations.
+     */
+    public static final int SC_MULTI_STATUS = 207;
+    // This one colides with HTTP 1.1
+    // "207 Parital Update OK"
+
+
+    /**
+     * Status code (418) indicating the entity body submitted with
+     * the PATCH method was not understood by the resource.
+     */
+    public static final int SC_UNPROCESSABLE_ENTITY = 418;
+    // This one colides with HTTP 1.1
+    // "418 Reauthentication Required"
+
+
+    /**
+     * Status code (419) indicating that the resource does not have
+     * sufficient space to record the state of the resource after the
+     * execution of this method.
+     */
+    public static final int SC_INSUFFICIENT_SPACE_ON_RESOURCE = 419;
+    // This one colides with HTTP 1.1
+    // "419 Proxy Reauthentication Required"
+
+
+    /**
+     * Status code (420) indicating the method was not executed on
+     * a particular resource within its scope because some part of
+     * the method's execution failed causing the entire method to be
+     * aborted.
+     */
+    public static final int SC_METHOD_FAILURE = 420;
+
+
+    /**
+     * Status code (423) indicating the destination resource of a
+     * method is locked, and either the request did not contain a
+     * valid Lock-Info header, or the Lock-Info header identifies
+     * a lock held by another principal.
+     */
+    public static final int SC_LOCKED = 423;
+
+
+    // ------------------------------------------------------------ Initializer
+
+
+    static {
+        // HTTP 1.0 tatus Code
+        addStatusCodeMap(SC_OK, "OK");
+        addStatusCodeMap(SC_CREATED, "Created");
+        addStatusCodeMap(SC_ACCEPTED, "Accepted");
+        addStatusCodeMap(SC_NO_CONTENT, "No Content");
+        addStatusCodeMap(SC_MOVED_PERMANENTLY, "Moved Permanently");
+        addStatusCodeMap(SC_MOVED_TEMPORARILY, "Moved Temporarily");
+        addStatusCodeMap(SC_NOT_MODIFIED, "Not Modified");
+        addStatusCodeMap(SC_BAD_REQUEST, "Bad Request");
+        addStatusCodeMap(SC_UNAUTHORIZED, "Unauthorized");
+        addStatusCodeMap(SC_FORBIDDEN, "Forbidden");
+        addStatusCodeMap(SC_NOT_FOUND, "Not Found");
+        addStatusCodeMap(SC_INTERNAL_SERVER_ERROR, "Internal Server Error");
+        addStatusCodeMap(SC_NOT_IMPLEMENTED, "Not Implemented");
+        addStatusCodeMap(SC_BAD_GATEWAY, "Bad Gateway");
+        addStatusCodeMap(SC_SERVICE_UNAVAILABLE, "Service Unavailable");
+        addStatusCodeMap(SC_CONTINUE, "Continue");
+        addStatusCodeMap(SC_METHOD_NOT_ALLOWED, "Method Not Allowed");
+        addStatusCodeMap(SC_CONFLICT, "Conflict");
+        addStatusCodeMap(SC_PRECONDITION_FAILED, "Precondition Failed");
+        addStatusCodeMap(SC_REQUEST_TOO_LONG, "Request Too Long");
+        addStatusCodeMap(SC_UNSUPPORTED_MEDIA_TYPE, "Unsupported Media Type");
+        // WebDav Status Codes
+        addStatusCodeMap(SC_MULTI_STATUS, "Multi-Status");
+        addStatusCodeMap(SC_UNPROCESSABLE_ENTITY, "Unprocessable Entity");
+        addStatusCodeMap(SC_INSUFFICIENT_SPACE_ON_RESOURCE,
+                         "Insufficient Space On Resource");
+        addStatusCodeMap(SC_METHOD_FAILURE, "Method Failure");
+        addStatusCodeMap(SC_LOCKED, "Locked");
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Returns the HTTP status text for the HTTP or WebDav status code
+     * specified by looking it up in the static mapping.  This is a
+     * static function.
+     *
+     * @param   nHttpStatusCode [IN] HTTP or WebDAV status code
+     * @return  A string with a short descriptive phrase for the
+     *                  HTTP status code (e.g., "OK").
+     */
+    public static String getStatusText(int nHttpStatusCode) {
+        Integer intKey = new Integer(nHttpStatusCode);
+
+        if (!mapStatusCodes.containsKey(intKey)) {
+            return "";
+        } else {
+            return (String) mapStatusCodes.get(intKey);
+        }
+    }
+
+
+    // -------------------------------------------------------- Private Methods
+
+
+    /**
+     * Adds a new status code -> status text mapping.  This is a static
+     * method because the mapping is a static variable.
+     *
+     * @param   nKey    [IN] HTTP or WebDAV status code
+     * @param   strVal  [IN] HTTP status text
+     */
+    private static void addStatusCodeMap(int nKey, String strVal) {
+        mapStatusCodes.put(new Integer(nKey), strVal);
+    }
+
+};
+

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/servlets/package.html
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/servlets/package.html	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/servlets/package.html	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,17 @@
+<body>
+
+<p>This package contains <code>Servlets</code> that implement some of the
+standard functionality provided by the Catalina servlet container.  Because
+these servlets are in the <code>org.apache.catalina</code> package hierarchy,
+they are in the privileged position of being able to reference internal server
+data structures, which application level servlets are prevented from
+accessing (by the application class loader implementation).</p>
+
+<p>To the extent that these servlets depend upon internal Catalina data
+structures, they are obviously not portable to other servlet container
+environments.  However, they can be used as models for creating application
+level servlets that provide similar capabilities -- most obviously the
+<a href="DefaultServlet.html">DefaultServlet</a> implementation, which
+serves static resources when Catalina runs stand-alone.</p>
+
+</body>

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/session/Constants.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/session/Constants.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/session/Constants.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,31 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.session;
+
+/**
+ * Manifest constants for the <code>org.apache.catalina.session</code>
+ * package.
+ *
+ * @author Craig R. McClanahan
+ */
+
+public class Constants {
+
+    public static final String Package = "org.apache.catalina.session";
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/session/FileStore.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/session/FileStore.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/session/FileStore.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,439 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.session;
+
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.util.ArrayList;
+
+import javax.servlet.ServletContext;
+
+import org.apache.catalina.Container;
+import org.apache.catalina.Context;
+import org.apache.catalina.Globals;
+import org.apache.catalina.Loader;
+import org.apache.catalina.Session;
+import org.apache.catalina.Store;
+import org.apache.catalina.util.CustomObjectInputStream;
+
+
+/**
+ * Concrete implementation of the <b>Store</b> interface that utilizes
+ * a file per saved Session in a configured directory.  Sessions that are
+ * saved are still subject to being expired based on inactivity.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 303826 $ $Date: 2005-03-31 04:31:54 -0600 (Thu, 31 Mar 2005) $
+ */
+
+public final class FileStore
+    extends StoreBase implements Store {
+
+
+    // ----------------------------------------------------- Constants
+
+
+    /**
+     * The extension to use for serialized session filenames.
+     */
+    private static final String FILE_EXT = ".session";
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The pathname of the directory in which Sessions are stored.
+     * This may be an absolute pathname, or a relative path that is
+     * resolved against the temporary work directory for this application.
+     */
+    private String directory = ".";
+
+
+    /**
+     * A File representing the directory in which Sessions are stored.
+     */
+    private File directoryFile = null;
+
+
+    /**
+     * The descriptive information about this implementation.
+     */
+    private static final String info = "FileStore/1.0";
+
+    /**
+     * Name to register for this Store, used for logging.
+     */
+    private static final String storeName = "fileStore";
+
+    /**
+     * Name to register for the background thread.
+     */
+    private static final String threadName = "FileStore";
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * Return the directory path for this Store.
+     */
+    public String getDirectory() {
+
+        return (directory);
+
+    }
+
+
+    /**
+     * Set the directory path for this Store.
+     *
+     * @param path The new directory path
+     */
+    public void setDirectory(String path) {
+
+        String oldDirectory = this.directory;
+        this.directory = path;
+        this.directoryFile = null;
+        support.firePropertyChange("directory", oldDirectory,
+                                   this.directory);
+
+    }
+
+
+    /**
+     * Return descriptive information about this Store implementation and
+     * the corresponding version number, in the format
+     * <code>&lt;description&gt;/&lt;version&gt;</code>.
+     */
+    public String getInfo() {
+
+        return (info);
+
+    }
+
+    /**
+     * Return the thread name for this Store.
+     */
+    public String getThreadName() {
+        return(threadName);
+    }
+
+    /**
+     * Return the name for this Store, used for logging.
+     */
+    public String getStoreName() {
+        return(storeName);
+    }
+
+
+    /**
+     * Return the number of Sessions present in this Store.
+     *
+     * @exception IOException if an input/output error occurs
+     */
+    public int getSize() throws IOException {
+
+        // Acquire the list of files in our storage directory
+        File file = directory();
+        if (file == null) {
+            return (0);
+        }
+        String files[] = file.list();
+
+        // Figure out which files are sessions
+        int keycount = 0;
+        for (int i = 0; i < files.length; i++) {
+            if (files[i].endsWith(FILE_EXT)) {
+                keycount++;
+            }
+        }
+        return (keycount);
+
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Remove all of the Sessions in this Store.
+     *
+     * @exception IOException if an input/output error occurs
+     */
+    public void clear()
+        throws IOException {
+
+        String[] keys = keys();
+        for (int i = 0; i < keys.length; i++) {
+            remove(keys[i]);
+        }
+
+    }
+
+
+    /**
+     * Return an array containing the session identifiers of all Sessions
+     * currently saved in this Store.  If there are no such Sessions, a
+     * zero-length array is returned.
+     *
+     * @exception IOException if an input/output error occurred
+     */
+    public String[] keys() throws IOException {
+
+        // Acquire the list of files in our storage directory
+        File file = directory();
+        if (file == null) {
+            return (new String[0]);
+        }
+
+        String files[] = file.list();
+        
+        // Bugzilla 32130
+        if((files == null) || (files.length < 1)) {
+            return (new String[0]);
+        }
+
+        // Build and return the list of session identifiers
+        ArrayList list = new ArrayList();
+        int n = FILE_EXT.length();
+        for (int i = 0; i < files.length; i++) {
+            if (files[i].endsWith(FILE_EXT)) {
+                list.add(files[i].substring(0, files[i].length() - n));
+            }
+        }
+        return ((String[]) list.toArray(new String[list.size()]));
+
+    }
+
+
+    /**
+     * Load and return the Session associated with the specified session
+     * identifier from this Store, without removing it.  If there is no
+     * such stored Session, return <code>null</code>.
+     *
+     * @param id Session identifier of the session to load
+     *
+     * @exception ClassNotFoundException if a deserialization error occurs
+     * @exception IOException if an input/output error occurs
+     */
+    public Session load(String id)
+        throws ClassNotFoundException, IOException {
+
+        // Open an input stream to the specified pathname, if any
+        File file = file(id);
+        if (file == null) {
+            return (null);
+        }
+
+        if (! file.exists()) {
+            return (null);
+        }
+        if (manager.getContainer().getLogger().isDebugEnabled()) {
+            manager.getContainer().getLogger().debug(sm.getString(getStoreName()+".loading",
+                             id, file.getAbsolutePath()));
+        }
+
+        FileInputStream fis = null;
+        ObjectInputStream ois = null;
+        Loader loader = null;
+        ClassLoader classLoader = null;
+        try {
+            fis = new FileInputStream(file.getAbsolutePath());
+            BufferedInputStream bis = new BufferedInputStream(fis);
+            Container container = manager.getContainer();
+            if (container != null)
+                loader = container.getLoader();
+            if (loader != null)
+                classLoader = loader.getClassLoader();
+            if (classLoader != null)
+                ois = new CustomObjectInputStream(bis, classLoader);
+            else
+                ois = new ObjectInputStream(bis);
+        } catch (FileNotFoundException e) {
+            if (manager.getContainer().getLogger().isDebugEnabled())
+                manager.getContainer().getLogger().debug("No persisted data file found");
+            return (null);
+        } catch (IOException e) {
+            if (ois != null) {
+                try {
+                    ois.close();
+                } catch (IOException f) {
+                    ;
+                }
+                ois = null;
+            }
+            throw e;
+        }
+
+        try {
+            StandardSession session =
+                (StandardSession) manager.createEmptySession();
+            session.readObjectData(ois);
+            session.setManager(manager);
+            return (session);
+        } finally {
+            // Close the input stream
+            if (ois != null) {
+                try {
+                    ois.close();
+                } catch (IOException f) {
+                    ;
+                }
+            }
+        }
+    }
+
+
+    /**
+     * Remove the Session with the specified session identifier from
+     * this Store, if present.  If no such Session is present, this method
+     * takes no action.
+     *
+     * @param id Session identifier of the Session to be removed
+     *
+     * @exception IOException if an input/output error occurs
+     */
+    public void remove(String id) throws IOException {
+
+        File file = file(id);
+        if (file == null) {
+            return;
+        }
+        if (manager.getContainer().getLogger().isDebugEnabled()) {
+            manager.getContainer().getLogger().debug(sm.getString(getStoreName()+".removing",
+                             id, file.getAbsolutePath()));
+        }
+        file.delete();
+
+    }
+
+
+    /**
+     * Save the specified Session into this Store.  Any previously saved
+     * information for the associated session identifier is replaced.
+     *
+     * @param session Session to be saved
+     *
+     * @exception IOException if an input/output error occurs
+     */
+    public void save(Session session) throws IOException {
+
+        // Open an output stream to the specified pathname, if any
+        File file = file(session.getIdInternal());
+        if (file == null) {
+            return;
+        }
+        if (manager.getContainer().getLogger().isDebugEnabled()) {
+            manager.getContainer().getLogger().debug(sm.getString(getStoreName()+".saving",
+                             session.getIdInternal(), file.getAbsolutePath()));
+        }
+        FileOutputStream fos = null;
+        ObjectOutputStream oos = null;
+        try {
+            fos = new FileOutputStream(file.getAbsolutePath());
+            oos = new ObjectOutputStream(new BufferedOutputStream(fos));
+        } catch (IOException e) {
+            if (oos != null) {
+                try {
+                    oos.close();
+                } catch (IOException f) {
+                    ;
+                }
+            }
+            throw e;
+        }
+
+        try {
+            ((StandardSession)session).writeObjectData(oos);
+        } finally {
+            oos.close();
+        }
+
+    }
+
+
+    // -------------------------------------------------------- Private Methods
+
+
+    /**
+     * Return a File object representing the pathname to our
+     * session persistence directory, if any.  The directory will be
+     * created if it does not already exist.
+     */
+    private File directory() {
+
+        if (this.directory == null) {
+            return (null);
+        }
+        if (this.directoryFile != null) {
+            // NOTE:  Race condition is harmless, so do not synchronize
+            return (this.directoryFile);
+        }
+        File file = new File(this.directory);
+        if (!file.isAbsolute()) {
+            Container container = manager.getContainer();
+            if (container instanceof Context) {
+                ServletContext servletContext =
+                    ((Context) container).getServletContext();
+                File work = (File)
+                    servletContext.getAttribute(Globals.WORK_DIR_ATTR);
+                file = new File(work, this.directory);
+            } else {
+                throw new IllegalArgumentException
+                    ("Parent Container is not a Context");
+            }
+        }
+        if (!file.exists() || !file.isDirectory()) {
+            file.delete();
+            file.mkdirs();
+        }
+        this.directoryFile = file;
+        return (file);
+
+    }
+
+
+    /**
+     * Return a File object representing the pathname to our
+     * session persistence file, if any.
+     *
+     * @param id The ID of the Session to be retrieved. This is
+     *    used in the file naming.
+     */
+    private File file(String id) {
+
+        if (this.directory == null) {
+            return (null);
+        }
+        String filename = id + FILE_EXT;
+        File file = new File(directory(), filename);
+        return (file);
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/session/JDBCStore.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/session/JDBCStore.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/session/JDBCStore.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,988 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.session;
+
+import org.apache.catalina.Container;
+import org.apache.catalina.LifecycleException;
+import org.apache.catalina.Loader;
+import org.apache.catalina.Session;
+import org.apache.catalina.Store;
+import org.apache.catalina.util.CustomObjectInputStream;
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.sql.Connection;
+import java.sql.Driver;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.Properties;
+
+/**
+ * Implementation of the <code>Store</code> interface that stores
+ * serialized session objects in a database.  Sessions that are
+ * saved are still subject to being expired based on inactivity.
+ *
+ * @author Bip Thelin
+ * @version $Revision: 303826 $, $Date: 2005-03-31 04:31:54 -0600 (Thu, 31 Mar 2005) $
+ */
+
+public class JDBCStore
+        extends StoreBase implements Store {
+
+    /**
+     * The descriptive information about this implementation.
+     */
+    protected static String info = "JDBCStore/1.0";
+
+    /**
+     * Context name associated with this Store
+     */
+    private String name = null;
+
+    /**
+     * Name to register for this Store, used for logging.
+     */
+    protected static String storeName = "JDBCStore";
+
+    /**
+     * Name to register for the background thread.
+     */
+    protected String threadName = "JDBCStore";
+
+    /**
+     * The connection username to use when trying to connect to the database.
+     */
+    protected String connectionName = null;
+
+
+    /**
+     * The connection URL to use when trying to connect to the database.
+     */
+    protected String connectionPassword = null;
+
+    /**
+     * Connection string to use when connecting to the DB.
+     */
+    protected String connectionURL = null;
+
+    /**
+     * The database connection.
+     */
+    private Connection dbConnection = null;
+
+    /**
+     * Instance of the JDBC Driver class we use as a connection factory.
+     */
+    protected Driver driver = null;
+
+    /**
+     * Driver to use.
+     */
+    protected String driverName = null;
+
+    // ------------------------------------------------------------- Table & cols
+
+    /**
+     * Table to use.
+     */
+    protected String sessionTable = "tomcat$sessions";
+
+    /**
+     * Column to use for /Engine/Host/Context name
+     */
+    protected String sessionAppCol = "app";
+
+    /**
+     * Id column to use.
+     */
+    protected String sessionIdCol = "id";
+
+    /**
+     * Data column to use.
+     */
+    protected String sessionDataCol = "data";
+
+    /**
+     * Is Valid column to use.
+     */
+    protected String sessionValidCol = "valid";
+
+    /**
+     * Max Inactive column to use.
+     */
+    protected String sessionMaxInactiveCol = "maxinactive";
+
+    /**
+     * Last Accessed column to use.
+     */
+    protected String sessionLastAccessedCol = "lastaccess";
+
+    // ------------------------------------------------------------- SQL Variables
+
+    /**
+     * Variable to hold the <code>getSize()</code> prepared statement.
+     */
+    protected PreparedStatement preparedSizeSql = null;
+
+    /**
+     * Variable to hold the <code>keys()</code> prepared statement.
+     */
+    protected PreparedStatement preparedKeysSql = null;
+
+    /**
+     * Variable to hold the <code>save()</code> prepared statement.
+     */
+    protected PreparedStatement preparedSaveSql = null;
+
+    /**
+     * Variable to hold the <code>clear()</code> prepared statement.
+     */
+    protected PreparedStatement preparedClearSql = null;
+
+    /**
+     * Variable to hold the <code>remove()</code> prepared statement.
+     */
+    protected PreparedStatement preparedRemoveSql = null;
+
+    /**
+     * Variable to hold the <code>load()</code> prepared statement.
+     */
+    protected PreparedStatement preparedLoadSql = null;
+
+    // ------------------------------------------------------------- Properties
+
+    /**
+     * Return the info for this Store.
+     */
+    public String getInfo() {
+        return (info);
+    }
+
+    /**
+     * Return the name for this instance (built from container name)
+     */
+    public String getName() {
+        if (name == null) {
+            Container container = manager.getContainer();
+            String contextName = container.getName();
+            String hostName = "";
+            String engineName = "";
+
+            if (container.getParent() != null) {
+                Container host = container.getParent();
+                hostName = host.getName();
+                if (host.getParent() != null) {
+                    engineName = host.getParent().getName();
+                }
+            }
+            name = "/" + engineName + "/" + hostName + contextName;
+        }
+        return name;
+    }
+
+    /**
+     * Return the thread name for this Store.
+     */
+    public String getThreadName() {
+        return (threadName);
+    }
+
+    /**
+     * Return the name for this Store, used for logging.
+     */
+    public String getStoreName() {
+        return (storeName);
+    }
+
+    /**
+     * Set the driver for this Store.
+     *
+     * @param driverName The new driver
+     */
+    public void setDriverName(String driverName) {
+        String oldDriverName = this.driverName;
+        this.driverName = driverName;
+        support.firePropertyChange("driverName",
+                oldDriverName,
+                this.driverName);
+        this.driverName = driverName;
+    }
+
+    /**
+     * Return the driver for this Store.
+     */
+    public String getDriverName() {
+        return (this.driverName);
+    }
+
+    /**
+     * Return the username to use to connect to the database.
+     *
+     */
+    public String getConnectionName() {
+        return connectionName;
+    }
+
+    /**
+     * Set the username to use to connect to the database.
+     *
+     * @param connectionName Username
+     */
+    public void setConnectionName(String connectionName) {
+        this.connectionName = connectionName;
+    }
+
+    /**
+     * Return the password to use to connect to the database.
+     *
+     */
+    public String getConnectionPassword() {
+        return connectionPassword;
+    }
+
+    /**
+     * Set the password to use to connect to the database.
+     *
+     * @param connectionPassword User password
+     */
+    public void setConnectionPassword(String connectionPassword) {
+        this.connectionPassword = connectionPassword;
+    }
+
+    /**
+     * Set the Connection URL for this Store.
+     *
+     * @param connectionURL The new Connection URL
+     */
+    public void setConnectionURL(String connectionURL) {
+        String oldConnString = this.connectionURL;
+        this.connectionURL = connectionURL;
+        support.firePropertyChange("connectionURL",
+                oldConnString,
+                this.connectionURL);
+    }
+
+    /**
+     * Return the Connection URL for this Store.
+     */
+    public String getConnectionURL() {
+        return (this.connectionURL);
+    }
+
+    /**
+     * Set the table for this Store.
+     *
+     * @param sessionTable The new table
+     */
+    public void setSessionTable(String sessionTable) {
+        String oldSessionTable = this.sessionTable;
+        this.sessionTable = sessionTable;
+        support.firePropertyChange("sessionTable",
+                oldSessionTable,
+                this.sessionTable);
+    }
+
+    /**
+     * Return the table for this Store.
+     */
+    public String getSessionTable() {
+        return (this.sessionTable);
+    }
+
+    /**
+     * Set the App column for the table.
+     *
+     * @param sessionAppCol the column name
+     */
+    public void setSessionAppCol(String sessionAppCol) {
+        String oldSessionAppCol = this.sessionAppCol;
+        this.sessionAppCol = sessionAppCol;
+        support.firePropertyChange("sessionAppCol",
+                oldSessionAppCol,
+                this.sessionAppCol);
+    }
+
+    /**
+     * Return the web application name column for the table.
+     */
+    public String getSessionAppCol() {
+        return (this.sessionAppCol);
+    }
+
+    /**
+     * Set the Id column for the table.
+     *
+     * @param sessionIdCol the column name
+     */
+    public void setSessionIdCol(String sessionIdCol) {
+        String oldSessionIdCol = this.sessionIdCol;
+        this.sessionIdCol = sessionIdCol;
+        support.firePropertyChange("sessionIdCol",
+                oldSessionIdCol,
+                this.sessionIdCol);
+    }
+
+    /**
+     * Return the Id column for the table.
+     */
+    public String getSessionIdCol() {
+        return (this.sessionIdCol);
+    }
+
+    /**
+     * Set the Data column for the table
+     *
+     * @param sessionDataCol the column name
+     */
+    public void setSessionDataCol(String sessionDataCol) {
+        String oldSessionDataCol = this.sessionDataCol;
+        this.sessionDataCol = sessionDataCol;
+        support.firePropertyChange("sessionDataCol",
+                oldSessionDataCol,
+                this.sessionDataCol);
+    }
+
+    /**
+     * Return the data column for the table
+     */
+    public String getSessionDataCol() {
+        return (this.sessionDataCol);
+    }
+
+    /**
+     * Set the Is Valid column for the table
+     *
+     * @param sessionValidCol The column name
+     */
+    public void setSessionValidCol(String sessionValidCol) {
+        String oldSessionValidCol = this.sessionValidCol;
+        this.sessionValidCol = sessionValidCol;
+        support.firePropertyChange("sessionValidCol",
+                oldSessionValidCol,
+                this.sessionValidCol);
+    }
+
+    /**
+     * Return the Is Valid column
+     */
+    public String getSessionValidCol() {
+        return (this.sessionValidCol);
+    }
+
+    /**
+     * Set the Max Inactive column for the table
+     *
+     * @param sessionMaxInactiveCol The column name
+     */
+    public void setSessionMaxInactiveCol(String sessionMaxInactiveCol) {
+        String oldSessionMaxInactiveCol = this.sessionMaxInactiveCol;
+        this.sessionMaxInactiveCol = sessionMaxInactiveCol;
+        support.firePropertyChange("sessionMaxInactiveCol",
+                oldSessionMaxInactiveCol,
+                this.sessionMaxInactiveCol);
+    }
+
+    /**
+     * Return the Max Inactive column
+     */
+    public String getSessionMaxInactiveCol() {
+        return (this.sessionMaxInactiveCol);
+    }
+
+    /**
+     * Set the Last Accessed column for the table
+     *
+     * @param sessionLastAccessedCol The column name
+     */
+    public void setSessionLastAccessedCol(String sessionLastAccessedCol) {
+        String oldSessionLastAccessedCol = this.sessionLastAccessedCol;
+        this.sessionLastAccessedCol = sessionLastAccessedCol;
+        support.firePropertyChange("sessionLastAccessedCol",
+                oldSessionLastAccessedCol,
+                this.sessionLastAccessedCol);
+    }
+
+    /**
+     * Return the Last Accessed column
+     */
+    public String getSessionLastAccessedCol() {
+        return (this.sessionLastAccessedCol);
+    }
+
+    // --------------------------------------------------------- Public Methods
+
+    /**
+     * Return an array containing the session identifiers of all Sessions
+     * currently saved in this Store.  If there are no such Sessions, a
+     * zero-length array is returned.
+     *
+     * @exception IOException if an input/output error occurred
+     */
+    public String[] keys() throws IOException {
+        ResultSet rst = null;
+        String keys[] = null;
+        synchronized (this) {
+            int numberOfTries = 2;
+            while (numberOfTries > 0) {
+
+                Connection _conn = getConnection();
+                if (_conn == null) {
+                    return (new String[0]);
+                }
+                try {
+                    if (preparedKeysSql == null) {
+                        String keysSql = "SELECT " + sessionIdCol + " FROM "
+                                + sessionTable + " WHERE " + sessionAppCol
+                                + " = ?";
+                        preparedKeysSql = _conn.prepareStatement(keysSql);
+					}
+
+                    preparedKeysSql.setString(1, getName());
+                    rst = preparedKeysSql.executeQuery();
+                    ArrayList tmpkeys = new ArrayList();
+                    if (rst != null) {
+                        while (rst.next()) {
+                            tmpkeys.add(rst.getString(1));
+                        }
+                    }
+                    keys = (String[]) tmpkeys.toArray(new String[tmpkeys.size()]);
+                    // Break out after the finally block
+                    numberOfTries = 0;
+                } catch (SQLException e) {
+                    manager.getContainer().getLogger().error(sm.getString(getStoreName() + ".SQLException", e));
+                    keys = new String[0];
+                    // Close the connection so that it gets reopened next time
+                    if (dbConnection != null)
+                        close(dbConnection);
+                } finally {
+                    try {
+                        if (rst != null) {
+                            rst.close();
+                        }
+                    } catch (SQLException e) {
+                        ;
+                    }
+
+                    release(_conn);
+                }
+                numberOfTries--;
+            }
+        }
+
+        return (keys);
+    }
+
+    /**
+     * Return an integer containing a count of all Sessions
+     * currently saved in this Store.  If there are no Sessions,
+     * <code>0</code> is returned.
+     *
+     * @exception IOException if an input/output error occurred
+     */
+    public int getSize() throws IOException {
+        int size = 0;
+        ResultSet rst = null;
+
+        synchronized (this) {
+            int numberOfTries = 2;
+            while (numberOfTries > 0) {
+                Connection _conn = getConnection();
+
+                if (_conn == null) {
+                    return (size);
+                }
+
+                try {
+                    if (preparedSizeSql == null) {
+                        String sizeSql = "SELECT COUNT(" + sessionIdCol
+                                + ") FROM " + sessionTable + " WHERE "
+                                + sessionAppCol + " = ?";
+                        preparedSizeSql = _conn.prepareStatement(sizeSql);
+					}
+
+                    preparedSizeSql.setString(1, getName());
+                    rst = preparedSizeSql.executeQuery();
+                    if (rst.next()) {
+                        size = rst.getInt(1);
+                    }
+                    // Break out after the finally block
+                    numberOfTries = 0;
+                } catch (SQLException e) {
+                    manager.getContainer().getLogger().error(sm.getString(getStoreName() + ".SQLException", e));
+                    if (dbConnection != null)
+                        close(dbConnection);
+                } finally {
+                    try {
+                        if (rst != null)
+                            rst.close();
+                    } catch (SQLException e) {
+                        ;
+                    }
+
+                    release(_conn);
+                }
+                numberOfTries--;
+            }
+        }
+        return (size);
+    }
+
+    /**
+     * Load the Session associated with the id <code>id</code>.
+     * If no such session is found <code>null</code> is returned.
+     *
+     * @param id a value of type <code>String</code>
+     * @return the stored <code>Session</code>
+     * @exception ClassNotFoundException if an error occurs
+     * @exception IOException if an input/output error occurred
+     */
+    public Session load(String id)
+            throws ClassNotFoundException, IOException {
+        ResultSet rst = null;
+        StandardSession _session = null;
+        Loader loader = null;
+        ClassLoader classLoader = null;
+        ObjectInputStream ois = null;
+        BufferedInputStream bis = null;
+        Container container = manager.getContainer();
+ 
+        synchronized (this) {
+            int numberOfTries = 2;
+            while (numberOfTries > 0) {
+                Connection _conn = getConnection();
+                if (_conn == null) {
+                    return (null);
+                }
+
+                try {
+                    if (preparedLoadSql == null) {
+                        String loadSql = "SELECT " + sessionIdCol + ", "
+                                + sessionDataCol + " FROM " + sessionTable
+                                + " WHERE " + sessionIdCol + " = ? AND "
+                                + sessionAppCol + " = ?";
+                        preparedLoadSql = _conn.prepareStatement(loadSql);
+                    }
+
+                    preparedLoadSql.setString(1, id);
+                    preparedLoadSql.setString(2, getName());
+                    rst = preparedLoadSql.executeQuery();
+                    if (rst.next()) {
+                        bis = new BufferedInputStream(rst.getBinaryStream(2));
+
+                        if (container != null) {
+                            loader = container.getLoader();
+                        }
+                        if (loader != null) {
+                            classLoader = loader.getClassLoader();
+                        }
+                        if (classLoader != null) {
+                            ois = new CustomObjectInputStream(bis,
+                                    classLoader);
+                        } else {
+                            ois = new ObjectInputStream(bis);
+                        }
+
+                        if (manager.getContainer().getLogger().isDebugEnabled()) {
+                            manager.getContainer().getLogger().debug(sm.getString(getStoreName() + ".loading",
+                                    id, sessionTable));
+                        }
+
+                        _session = (StandardSession) manager.createEmptySession();
+                        _session.readObjectData(ois);
+                        _session.setManager(manager);
+                      } else if (manager.getContainer().getLogger().isDebugEnabled()) {
+                        manager.getContainer().getLogger().debug(getStoreName() + ": No persisted data object found");
+                    }
+                    // Break out after the finally block
+                    numberOfTries = 0;
+                } catch (SQLException e) {
+                    manager.getContainer().getLogger().error(sm.getString(getStoreName() + ".SQLException", e));
+                    if (dbConnection != null)
+                        close(dbConnection);
+                } finally {
+                    try {
+                        if (rst != null) {
+                            rst.close();
+                        }
+                    } catch (SQLException e) {
+                        ;
+                    }
+                    if (ois != null) {
+                        try {
+                            ois.close();
+                        } catch (IOException e) {
+                            ;
+                        }
+                    }
+                    release(_conn);
+                }
+                numberOfTries--;
+            }
+        }
+
+        return (_session);
+    }
+
+    /**
+     * Remove the Session with the specified session identifier from
+     * this Store, if present.  If no such Session is present, this method
+     * takes no action.
+     *
+     * @param id Session identifier of the Session to be removed
+     *
+     * @exception IOException if an input/output error occurs
+     */
+    public void remove(String id) throws IOException {
+
+        synchronized (this) {
+            int numberOfTries = 2;
+            while (numberOfTries > 0) {
+                Connection _conn = getConnection();
+
+                if (_conn == null) {
+                    return;
+                }
+
+                try {
+                    if (preparedRemoveSql == null) {
+                        String removeSql = "DELETE FROM " + sessionTable
+                                + " WHERE " + sessionIdCol + " = ?  AND "
+                                + sessionAppCol + " = ?";
+                        preparedRemoveSql = _conn.prepareStatement(removeSql);
+                    }
+
+                    preparedRemoveSql.setString(1, id);
+                    preparedRemoveSql.setString(2, getName());
+                    preparedRemoveSql.execute();
+                    // Break out after the finally block
+                    numberOfTries = 0;
+                } catch (SQLException e) {
+                    manager.getContainer().getLogger().error(sm.getString(getStoreName() + ".SQLException", e));
+                    if (dbConnection != null)
+                        close(dbConnection);
+                } finally {
+                    release(_conn);
+                }
+                numberOfTries--;
+            }
+        }
+
+        if (manager.getContainer().getLogger().isDebugEnabled()) {
+            manager.getContainer().getLogger().debug(sm.getString(getStoreName() + ".removing", id, sessionTable));
+        }
+    }
+
+    /**
+     * Remove all of the Sessions in this Store.
+     *
+     * @exception IOException if an input/output error occurs
+     */
+    public void clear() throws IOException {
+
+        synchronized (this) {
+            int numberOfTries = 2;
+            while (numberOfTries > 0) {
+                Connection _conn = getConnection();
+                if (_conn == null) {
+                    return;
+                }
+
+                try {
+                    if (preparedClearSql == null) {
+                        String clearSql = "DELETE FROM " + sessionTable
+                             + " WHERE " + sessionAppCol + " = ?";
+                        preparedClearSql = _conn.prepareStatement(clearSql);
+                    }
+
+                    preparedClearSql.setString(1, getName());
+                    preparedClearSql.execute();
+                    // Break out after the finally block
+                    numberOfTries = 0;
+                } catch (SQLException e) {
+                    manager.getContainer().getLogger().error(sm.getString(getStoreName() + ".SQLException", e));
+                    if (dbConnection != null)
+                        close(dbConnection);
+                } finally {
+                    release(_conn);
+                }
+                numberOfTries--;
+            }
+        }
+    }
+
+    /**
+     * Save a session to the Store.
+     *
+     * @param session the session to be stored
+     * @exception IOException if an input/output error occurs
+     */
+    public void save(Session session) throws IOException {
+        ObjectOutputStream oos = null;
+        ByteArrayOutputStream bos = null;
+        ByteArrayInputStream bis = null;
+        InputStream in = null;
+
+        synchronized (this) {
+            int numberOfTries = 2;
+            while (numberOfTries > 0) {
+                Connection _conn = getConnection();
+                if (_conn == null) {
+                    return;
+                }
+
+                // If sessions already exist in DB, remove and insert again.
+                // TODO:
+                // * Check if ID exists in database and if so use UPDATE.
+                remove(session.getIdInternal());
+
+                try {
+                    bos = new ByteArrayOutputStream();
+                    oos = new ObjectOutputStream(new BufferedOutputStream(bos));
+
+                    ((StandardSession) session).writeObjectData(oos);
+                    oos.close();
+                    oos = null;
+                    byte[] obs = bos.toByteArray();
+                    int size = obs.length;
+                    bis = new ByteArrayInputStream(obs, 0, size);
+                    in = new BufferedInputStream(bis, size);
+
+                    if (preparedSaveSql == null) {
+                        String saveSql = "INSERT INTO " + sessionTable + " ("
+                           + sessionIdCol + ", " + sessionAppCol + ", "
+                           + sessionDataCol + ", " + sessionValidCol
+                           + ", " + sessionMaxInactiveCol + ", "
+                           + sessionLastAccessedCol
+                           + ") VALUES (?, ?, ?, ?, ?, ?)";
+                       preparedSaveSql = _conn.prepareStatement(saveSql);
+					}
+
+                    preparedSaveSql.setString(1, session.getIdInternal());
+                    preparedSaveSql.setString(2, getName());
+                    preparedSaveSql.setBinaryStream(3, in, size);
+                    preparedSaveSql.setString(4, session.isValid() ? "1" : "0");
+                    preparedSaveSql.setInt(5, session.getMaxInactiveInterval());
+                    preparedSaveSql.setLong(6, session.getLastAccessedTime());
+                    preparedSaveSql.execute();
+                    // Break out after the finally block
+                    numberOfTries = 0;
+                } catch (SQLException e) {
+                    manager.getContainer().getLogger().error(sm.getString(getStoreName() + ".SQLException", e));
+                    if (dbConnection != null)
+                        close(dbConnection);
+                } catch (IOException e) {
+                    ;
+                } finally {
+                    if (oos != null) {
+                        oos.close();
+                    }
+                    if (bis != null) {
+                        bis.close();
+                    }
+                    if (in != null) {
+                        in.close();
+                    }
+
+                    release(_conn);
+                }
+                numberOfTries--;
+            }
+        }
+
+        if (manager.getContainer().getLogger().isDebugEnabled()) {
+            manager.getContainer().getLogger().debug(sm.getString(getStoreName() + ".saving",
+                    session.getIdInternal(), sessionTable));
+        }
+    }
+
+    // --------------------------------------------------------- Protected Methods
+
+    /**
+     * Check the connection associated with this store, if it's
+     * <code>null</code> or closed try to reopen it.
+     * Returns <code>null</code> if the connection could not be established.
+     *
+     * @return <code>Connection</code> if the connection suceeded
+     */
+    protected Connection getConnection() {
+        try {
+            if (dbConnection == null || dbConnection.isClosed()) {
+                manager.getContainer().getLogger().info(sm.getString(getStoreName() + ".checkConnectionDBClosed"));
+                open();
+                if (dbConnection == null || dbConnection.isClosed()) {
+                    manager.getContainer().getLogger().info(sm.getString(getStoreName() + ".checkConnectionDBReOpenFail"));
+                }
+            }
+        } catch (SQLException ex) {
+            manager.getContainer().getLogger().error(sm.getString(getStoreName() + ".checkConnectionSQLException",
+                    ex.toString()));
+        }
+
+        return dbConnection;
+    }
+
+    /**
+     * Open (if necessary) and return a database connection for use by
+     * this Realm.
+     *
+     * @exception SQLException if a database error occurs
+     */
+    protected Connection open() throws SQLException {
+
+        // Do nothing if there is a database connection already open
+        if (dbConnection != null)
+            return (dbConnection);
+
+        // Instantiate our database driver if necessary
+        if (driver == null) {
+            try {
+                Class clazz = Class.forName(driverName);
+                driver = (Driver) clazz.newInstance();
+            } catch (ClassNotFoundException ex) {
+                manager.getContainer().getLogger().error(sm.getString(getStoreName() + ".checkConnectionClassNotFoundException",
+                        ex.toString()));
+            } catch (InstantiationException ex) {
+                manager.getContainer().getLogger().error(sm.getString(getStoreName() + ".checkConnectionClassNotFoundException",
+                        ex.toString()));
+            } catch (IllegalAccessException ex) {
+                manager.getContainer().getLogger().error(sm.getString(getStoreName() + ".checkConnectionClassNotFoundException",
+                        ex.toString()));
+            }
+        }
+
+        // Open a new connection
+        Properties props = new Properties();
+        if (connectionName != null)
+            props.put("user", connectionName);
+        if (connectionPassword != null)
+            props.put("password", connectionPassword);
+        dbConnection = driver.connect(connectionURL, props);
+        dbConnection.setAutoCommit(true);
+        return (dbConnection);
+
+    }
+
+    /**
+     * Close the specified database connection.
+     *
+     * @param dbConnection The connection to be closed
+     */
+    protected void close(Connection dbConnection) {
+
+        // Do nothing if the database connection is already closed
+        if (dbConnection == null)
+            return;
+
+        // Close our prepared statements (if any)
+        try {
+            preparedSizeSql.close();
+        } catch (Throwable f) {
+            ;
+        }
+        this.preparedSizeSql = null;
+
+        try {
+            preparedKeysSql.close();
+        } catch (Throwable f) {
+            ;
+        }
+        this.preparedKeysSql = null;
+
+        try {
+            preparedSaveSql.close();
+        } catch (Throwable f) {
+            ;
+        }
+        this.preparedSaveSql = null;
+
+        try {
+            preparedClearSql.close();
+        } catch (Throwable f) {
+            ;
+        }
+         
+		try {
+            preparedRemoveSql.close();
+        } catch (Throwable f) {
+            ;
+        }
+        this.preparedRemoveSql = null;
+
+        try {
+            preparedLoadSql.close();
+        } catch (Throwable f) {
+            ;
+        }
+        this.preparedLoadSql = null;
+
+        // Close this database connection, and log any errors
+        try {
+            dbConnection.close();
+        } catch (SQLException e) {
+            manager.getContainer().getLogger().error(sm.getString(getStoreName() + ".close", e.toString())); // Just log it here
+        } finally {
+            this.dbConnection = null;
+        }
+
+    }
+
+    /**
+     * Release the connection, not needed here since the
+     * connection is not associated with a connection pool.
+     *
+     * @param conn The connection to be released
+     */
+    protected void release(Connection conn) {
+        ;
+    }
+
+    /**
+     * Called once when this Store is first started.
+     */
+    public void start() throws LifecycleException {
+        super.start();
+
+        // Open connection to the database
+        this.dbConnection = getConnection();
+    }
+
+    /**
+     * Gracefully terminate everything associated with our db.
+     * Called once when this Store is stoping.
+     *
+     */
+    public void stop() throws LifecycleException {
+        super.stop();
+
+        // Close and release everything associated with our db.
+        if (dbConnection != null) {
+            try {
+                dbConnection.commit();
+            } catch (SQLException e) {
+                ;
+            }
+            close(dbConnection);
+        }
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/session/LocalStrings.properties
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/session/LocalStrings.properties	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/session/LocalStrings.properties	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,67 @@
+applicationSession.session.ise=invalid session state
+applicationSession.value.iae=null value
+fileStore.alreadyStarted=File Store has already been started
+fileStore.notStarted=File Store has not yet been started
+fileStore.saving=Saving Session {0} to file {1}
+fileStore.loading=Loading Session {0} from file {1}
+fileStore.removing=Removing Session {0} at file {1}
+JDBCStore.alreadyStarted=JDBC Store has already been started
+JDBCStore.close=Exception closing database connection {0}
+JDBCStore.notStarted=JDBC Store has not yet been started
+JDBCStore.saving=Saving Session {0} to database {1}
+JDBCStore.loading=Loading Session {0} from database {1}
+JDBCStore.removing=Removing Session {0} at database {1}
+JDBCStore.SQLException=SQL Error {0}
+JDBCStore.checkConnectionDBClosed=The database connection is null or was found to be closed. Trying to re-open it.
+JDBCStore.checkConnectionDBReOpenFail=The re-open on the database failed. The database could be down.
+JDBCStore.checkConnectionSQLException=A SQL exception occurred {0}
+JDBCStore.checkConnectionClassNotFoundException=JDBC driver class not found {0}
+managerBase.complete=Seeding of random number generator has been completed
+managerBase.getting=Getting message digest component for algorithm {0}
+managerBase.gotten=Completed getting message digest component
+managerBase.random=Exception initializing random number generator of class {0}
+managerBase.seeding=Seeding random number generator class {0}
+serverSession.value.iae=null value
+standardManager.alreadyStarted=Manager has already been started
+standardManager.createSession.ise=createSession: Too many active sessions
+standardManager.expireException=processsExpire:  Exception during session expiration
+standardManager.loading=Loading persisted sessions from {0}
+standardManager.loading.cnfe=ClassNotFoundException while loading persisted sessions: {0}
+standardManager.loading.ioe=IOException while loading persisted sessions: {0}
+standardManager.notStarted=Manager has not yet been started
+standardManager.sessionTimeout=Invalid session timeout setting {0}
+standardManager.unloading=Saving persisted sessions to {0}
+standardManager.unloading.ioe=IOException while saving persisted sessions: {0}
+standardManager.managerLoad=Exception loading sessions from persistent storage
+standardManager.managerUnload=Exception unloading sessions to persistent storage
+standardSession.attributeEvent=Session attribute event listener threw exception
+standardSession.bindingEvent=Session binding event listener threw exception
+standardSession.invalidate.ise=invalidate: Session already invalidated
+standardSession.isNew.ise=isNew: Session already invalidated
+standardSession.getAttribute.ise=getAttribute: Session already invalidated
+standardSession.getAttributeNames.ise=getAttributeNames: Session already invalidated
+standardSession.getCreationTime.ise=getCreationTime: Session already invalidated
+standardSession.getLastAccessedTime.ise=getLastAccessedTime: Session already invalidated
+standardSession.getId.ise=getId: Session already invalidated
+standardSession.getMaxInactiveInterval.ise=getMaxInactiveInterval: Session already invalidated
+standardSession.getValueNames.ise=getValueNames: Session already invalidated
+standardSession.notSerializable=Cannot serialize session attribute {0} for session {1}
+standardSession.removeAttribute.ise=removeAttribute: Session already invalidated
+standardSession.sessionEvent=Session event listener threw exception
+standardSession.setAttribute.iae=setAttribute: Non-serializable attribute
+standardSession.setAttribute.ise=setAttribute: Session already invalidated
+standardSession.setAttribute.namenull=setAttribute: name parameter cannot be null
+standardSession.sessionCreated=Created Session id = {0}
+persistentManager.loading=Loading {0} persisted sessions
+persistentManager.unloading=Saving {0} persisted sessions
+persistentManager.expiring=Expiring {0} sessions before saving them
+persistentManager.deserializeError=Error deserializing Session {0}: {1}
+persistentManager.serializeError=Error serializing Session {0}: {1}
+persistentManager.swapMaxIdle=Swapping session {0} to Store, idle for {1} seconds
+persistentManager.backupMaxIdle=Backing up session {0} to Store, idle for {1} seconds
+persistentManager.backupException=Exception occurred when backing up Session {0}: {1}
+persistentManager.tooManyActive=Too many active sessions, {0}, looking for idle sessions to swap out
+persistentManager.swapTooManyActive=Swapping out session {0}, idle for {1} seconds too many sessions active
+persistentManager.processSwaps=Checking for sessions to swap out, {0} active sessions in memory
+persistentManager.activeSession=Session {0} has been idle for {1} seconds
+persistentManager.swapIn=Swapping session {0} in from Store

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/session/LocalStrings_es.properties
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/session/LocalStrings_es.properties	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/session/LocalStrings_es.properties	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,66 @@
+applicationSession.session.ise=estado inválido de sesión
+applicationSession.value.iae=valor nulo
+fileStore.alreadyStarted=Ya ha sido arrancado el Almacén de Archivos
+fileStore.notStarted=Aún no se ha arrancado el Almacén de Archivos
+fileStore.saving=Salvando Sesión {0} en archivo {1}
+fileStore.loading=Cargando Sesión {0} desde archivo {1}
+fileStore.removing=Quitando Sesión {0} en archivo {1}
+JDBCStore.alreadyStarted=Ya ha sido arrancado el Almacén JDBC
+JDBCStore.close=Excepción cerrando conexión a base de datos {0}
+JDBCStore.notStarted=Aún no se ha arrancado el Almacén JDBC
+JDBCStore.saving=Salvando Sesión {0} en base de datos {1}
+JDBCStore.loading=Cargando Sesión {0} desde base de datos {1}
+JDBCStore.removing=Quitando Sesión {0} en base de datos {1}
+JDBCStore.SQLException=Error SQL {0}
+JDBCStore.checkConnectionDBClosed=La conexióna a base de datos es nula o está cerrada. Intentando reabrirla.
+JDBCStore.checkConnectionDBReOpenFail=Falló la reapertura de la base de datos. Puede que la base de datos esté caída.
+JDBCStore.checkConnectionSQLException=Ha tenido lugar una excepción SQL {0}
+JDBCStore.checkConnectionClassNotFoundException=No se ha hallado la clase del manejador (driver) JDBC {0}
+managerBase.complete=Se ha completado la siembra del generador de números aleatorios
+managerBase.getting=Obteniendo mensaje de componente de resumen (digest) para algoritmo {0}
+managerBase.gotten=Completada la obtención de mensaje de componente de resumen (digest)
+managerBase.random=Excepción inicializando generador de números aleatorios de clase {0}
+managerBase.seeding=Sembrando clase de generador de números aleatorios {0}
+serverSession.value.iae=valor nulo
+standardManager.alreadyStarted=Ya ha sido arrancado el Gestor
+standardManager.createSession.ise=createSession: Demasiadas sesiones activas
+standardManager.expireException=processsExpire: Excepción durante la expiración de sesión
+standardManager.loading=Cargando sesiones persistidas desde {0}
+standardManager.loading.cnfe=ClassNotFoundException al cargar sesiones persistidas: {0}
+standardManager.loading.ioe=IOException al cargar sesiones persistidas: {0}
+standardManager.notStarted=Aún no se ha arrancado el Gestor
+standardManager.sessionTimeout=Valor inválido de Tiempo Agotado de sesión {0}
+standardManager.unloading=Salvando sesiones persistidas a {0}
+standardManager.unloading.ioe=IOException al salvar sesiones persistidas: {0}
+standardManager.managerLoad=Excepción cargando sesiones desde almacenamiento persistente
+standardManager.managerUnload=Excepción descargando sesiones a almacenamiento persistente
+standardSession.attributeEvent=El escuchador de eventos de atributo de Sesión lanzó una excepción
+standardSession.invalidate.ise=invalidate: La Sesión ya ha sido invalidada
+standardSession.isNew.ise=isNew: La Sesión ya ha sido invalidada
+standardSession.getAttribute.ise=getAttribute: La Sesión ya ha sido invalidada
+standardSession.getAttributeNames.ise=getAttributeNames: La Sesión ya ha sido invalidada
+standardSession.getCreationTime.ise=getCreationTime: La Sesión ya ha sido invalidada
+standardSession.getLastAccessedTime.ise=getLastAccessedTime: La Sesión ya ha sido invalidada
+standardSession.getId.ise=getId: La Sesión ya ha sido invalidada
+standardSession.getMaxInactiveInterval.ise=getMaxInactiveInterval: La Sesión ya ha sido invalidada
+standardSession.getValueNames.ise=getValueNames: La Sesión ya ha sido invalidada
+standardSession.notSerializable=No puedo serializar atributo de sesión {0} para sesión {1}
+standardSession.removeAttribute.ise=removeAttribute: La Sesión ya ha sido invalidada
+standardSession.sessionEvent=El escuchador de evento de Sesión lanzó una execpción
+standardSession.setAttribute.iae=setAttribute: Atributo no serializable
+standardSession.setAttribute.ise=setAttribute: La Sesión ya ha sido invalidada
+standardSession.setAttribute.namenull=setAttribute: el nuevo parámetro no puede ser nulo
+standardSession.sessionCreated=Creada Sesión id = {0}
+persistentManager.loading=Cargando {0} sesiones persistidas
+persistentManager.unloading=Salvando {0} sesiones persistidas
+persistentManager.expiring=Expirando {0} sesiones antes de salvarlas
+persistentManager.deserializeError=Error des-serializando Sesión {0}: {1}
+persistentManager.serializeError=Error serializando Sesión {0}: {1}
+persistentManager.swapMaxIdle=Intercambiando sesión {0} a fuera a Almacén, ociosa durante {1} segundos
+persistentManager.backupMaxIdle=Respaldando sesión {0} a Almacén, ociosa durante {1} segundos
+persistentManager.backupException=Ha tenido lugar una excepción al respaldar la Sesión {0}: {1}
+persistentManager.tooManyActive=Demasiadas sesiones activas, {0}, buscando sesiones ociosas para intercambiar
+persistentManager.swapTooManyActive=Intercambiando sesión {0} a fuera, ociosa durante {1} segundos: Demasiadas sesiones activas
+persistentManager.processSwaps=Mirando qué sesiones intercambiar a fuera, {0} sesiones activas en memoria
+persistentManager.activeSession=La sesión {0} ha estado ociosa durante {1} segundos
+persistentManager.swapIn=Intercambiando sesión {0} a dentro desde Almacén

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/session/LocalStrings_fr.properties
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/session/LocalStrings_fr.properties	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/session/LocalStrings_fr.properties	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,65 @@
+applicationSession.session.ise=état de session invalide
+applicationSession.value.iae=valeur nulle
+fileStore.alreadyStarted=Le "File Store" a déjà été démarré
+fileStore.notStarted=Le "File Store" n''a pas encore été démarré
+fileStore.saving=Sauvegarde de la Session {0} vers le fichier {1}
+fileStore.loading=Chargement de la Session {0} depuis le fichier {1}
+fileStore.removing=Retrait de la Session {0} du fichier {1}
+JDBCStore.alreadyStarted=Le "JDBC Store" a déjà été démarré
+JDBCStore.notStarted=Le "JDBC Store" n''a pas encore été démarré
+JDBCStore.saving=Sauvegarde de la Session {0} vers la base de données {1}
+JDBCStore.loading=Chargement de la Session {0} depuis la base de données {1}
+JDBCStore.removing=Retrait de la Session {0} de la base de données {1}
+JDBCStore.SQLException=Erreur SQL {0}
+JDBCStore.checkConnectionDBClosed=La connexion à la base de données est nulle ou a été trouvé fermé. Tentative de réouverture.
+JDBCStore.checkConnectionDBReOpenFail=La tentative de réouverture re-open de la base de données a échoué. La base de données est peut être arrétée.
+JDBCStore.checkConnectionSQLException=Une exception SQL s''est produite {0}
+JDBCStore.checkConnectionClassNotFoundException=La classe du driver JDBC n''a pas été trouvée {0}
+managerBase.complete=L''alimentation du générateur de nombre aléatoire est terminé
+managerBase.getting=Prise du composant d''algorithme empreinte de message (message digest) pour l''algorithme {0}
+managerBase.gotten=Prise du composant d''algorithme empreinte de message (message digest) terminée
+managerBase.random=Exception durant l''initialisation de la classe du générateur de nombre aléatoire {0}
+managerBase.seeding=Alimentation de la classe du générateur de nombre aléatoire {0}
+serverSession.value.iae=valeur nulle
+standardManager.alreadyStarted=Le "Manager" a été démarré
+standardManager.createSession.ise="createSession": Trop de sessions actives
+standardManager.expireException="processsExpire":  Exception lors de l''expiration de la session
+standardManager.loading=Chargement des sessions qui ont persistés depuis {0}
+standardManager.loading.cnfe="ClassNotFoundException" lors du chargement de sessions persistantes: {0}
+standardManager.loading.ioe="IOException" lors du chargement des sessions persistantes: {0}
+standardManager.notStarted=Le "Manager" n''a pas encore été démarré
+standardManager.sessionTimeout=Réglage du délai d''inactivité (timeout) de session invalide {0}
+standardManager.unloading=Sauvegarde des sessions ayant persistées vers {0}
+standardManager.unloading.ioe="IOException" lors de la sauvegarde de sessions persistantes: {0}
+standardManager.managerLoad=Exception au chargement des sessions depuis le stockage persistant (persistent storage)
+standardManager.managerUnload=Exception au déchargement des sessions vers le stockage persistant (persistent storage)
+standardSession.attributeEvent=L''écouteur d''évènement Attribut de Session (attribute event listener) a généré une exception
+standardSession.invalidate.ise="invalidate": Session déjà invalidée
+standardSession.isNew.ise="isNew": Session déjà invalidée
+standardSession.getAttribute.ise="getAttribute": Session déjà invalidée
+standardSession.getAttributeNames.ise="getAttributeNames": Session déjà invalidée
+standardSession.getCreationTime.ise="getCreationTime": Session déjà invalidée
+standardSession.getLastAccessedTime.ise="getLastAccessedTime": Session d\u00E9j\u00E0 invalid\u00E9e
+standardSession.getId.ise=getId: Session déjà invalidée
+standardSession.getMaxInactiveInterval.ise="getMaxInactiveInterval": Session déjà invalidée
+standardSession.getValueNames.ise="getValueNames": Session déjà invalidée
+standardSession.notSerializable=Impossible de sérialiser l''attribut de session {0} pour la session {1}
+standardSession.removeAttribute.ise="removeAttribute": Session déjà invalidée
+standardSession.sessionEvent=L''écouteur d''évènement de session (session event listener) a généré une exception
+standardSession.setAttribute.iae="setAttribute": attribut non sérialisable
+standardSession.setAttribute.ise="setAttribute": Session déjà invalidée
+standardSession.setAttribute.namenull="setAttribute": le nom de paramètre ne peut être nul
+standardSession.sessionCreated=Création de l''Id de Session = {0}
+persistentManager.loading=Chargement de {0} sessions persistantes
+persistentManager.unloading=Sauvegarde de {0} sessions persistantes
+persistentManager.expiring=Expiration de {0} sessions avant leur sauvegarde
+persistentManager.deserializeError=Erreur lors de la désérialisation de la session {0}: {1}
+persistentManager.serializeError=Erreur lors de la sérialisation de la session {0}: {1}
+persistentManager.swapMaxIdle=Basculement de la session {0} vers le stockage (Store), en attente pour {1} secondes
+persistentManager.backupMaxIdle=Sauvegarde de la session {0} vers le stockage (Store), en attente pour {1} secondes
+persistentManager.backupException=Exception lors de la sauvegarde de la session {0}: {1}
+persistentManager.tooManyActive=Trop de sessions actives, {0}, à la recherche de sessions en attente pour basculement vers stockage (swap out)
+persistentManager.swapTooManyActive=Basculement vers stockage (swap out) de la session {0}, en attente pour {1} secondes trop de sessions actives
+persistentManager.processSwaps=Recherche de sessions à basculer vers stockage (swap out), {0} sessions actives en mémoire
+persistentManager.activeSession=La session {0} a été en attente durant {1} secondes
+persistentManager.swapIn=Basculement depuis le stockage (swap in) de la session {0}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/session/LocalStrings_ja.properties
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/session/LocalStrings_ja.properties	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/session/LocalStrings_ja.properties	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,67 @@
+applicationSession.session.ise=\u7121\u52b9\u306a\u30bb\u30c3\u30b7\u30e7\u30f3\u72b6\u614b\u3067\u3059
+applicationSession.value.iae=null\u5024\u3067\u3059
+fileStore.alreadyStarted=\u30d5\u30a1\u30a4\u30eb\u30b9\u30c8\u30a2\u304c\u65e2\u306b\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u3059
+fileStore.notStarted=\u30d5\u30a1\u30a4\u30eb\u30b9\u30c8\u30a2\u304c\u307e\u3060\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u305b\u3093
+fileStore.saving=\u30bb\u30c3\u30b7\u30e7\u30f3 {0} \u3092\u30d5\u30a1\u30a4\u30eb {1} \u306b\u4fdd\u5b58\u3057\u307e\u3059
+fileStore.loading=\u30bb\u30c3\u30b7\u30e7\u30f3 {0} \u3092\u30d5\u30a1\u30a4\u30eb {1} \u304b\u3089\u30ed\u30fc\u30c9\u3057\u307e\u3059
+fileStore.removing=\u30bb\u30c3\u30b7\u30e7\u30f3 {0} \u3092\u30d5\u30a1\u30a4\u30eb {1} \u304b\u3089\u524a\u9664\u3057\u307e\u3059
+JDBCStore.alreadyStarted=JDBC\u30b9\u30c8\u30a2\u306f\u65e2\u306b\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u3059
+JDBCStore.close=\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u63a5\u7d9a {0} \u3092\u30af\u30ed\u30fc\u30ba\u4e2d\u306e\u4f8b\u5916\u3067\u3059
+JDBCStore.notStarted=JDBC\u30b9\u30c8\u30a2\u306f\u307e\u3060\u8d77\u52d5\u3055\u308c\u3066\u307e\u305b\u3093
+JDBCStore.saving=\u30bb\u30c3\u30b7\u30e7\u30f3 {0} \u3092\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9 {1} \u306b\u4fdd\u5b58\u3057\u307e\u3059
+JDBCStore.loading=\u30bb\u30c3\u30b7\u30e7\u30f3 {0} \u3092\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9 {1} \u304b\u3089\u30ed\u30fc\u30c9\u3057\u307e\u3059
+JDBCStore.removing= \u30bb\u30c3\u30b7\u30e7\u30f3 {0} \u3092\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9 {1} \u304b\u3089\u524a\u9664\u3057\u307e\u3059
+JDBCStore.SQLException=SQL\u30a8\u30e9\u30fc {0}
+JDBCStore.checkConnectionDBClosed=\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u63a5\u7d9a\u304cnull\u3067\u3042\u308b\u304b\u3001\u30af\u30ed\u30fc\u30ba\u3055\u308c\u3066\u3044\u308b\u306e\u304c\u898b\u3064\u304b\u308a\u307e\u3057\u305f\u3002\u518d\u30aa\u30fc\u30d7\u30f3\u3057\u3066\u304f\u3060\u3055\u3044\u3002
+JDBCStore.checkConnectionDBReOpenFail=\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u306e\u518d\u30aa\u30fc\u30d7\u30f3\u304c\u5931\u6557\u3057\u307e\u3057\u305f\u3002\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u304c\u30c0\u30a6\u30f3\u3057\u3066\u3044\u308b\u304b\u3082\u3057\u308c\u307e\u305b\u3093\u3002
+JDBCStore.checkConnectionSQLException=SQL\u4f8b\u5916\u304c\u767a\u751f\u3057\u307e\u3057\u305f {0}
+JDBCStore.checkConnectionClassNotFoundException=JDBC\u30c9\u30e9\u30a4\u30d0\u30af\u30e9\u30b9\u304c\u898b\u3064\u304b\u308a\u307e\u305b\u3093 {0}
+managerBase.complete=\u4e71\u6570\u767a\u751f\u5668\u306e\u30b7\u30fc\u30c9\u306e\u751f\u6210\u304c\u5b8c\u4e86\u3057\u307e\u3057\u305f
+managerBase.getting=\u30a2\u30eb\u30b4\u30ea\u30ba\u30e0 {0} \u306e\u30e1\u30c3\u30bb\u30fc\u30b8\u30c0\u30a4\u30b8\u30a7\u30b9\u30c8\u30b3\u30f3\u30dd\u30fc\u30cd\u30f3\u30c8\u3092\u53d6\u5f97\u3057\u307e\u3059
+managerBase.gotten=\u30e1\u30c3\u30bb\u30fc\u30b8\u30c0\u30a4\u30b8\u30a7\u30b9\u30c8\u30b3\u30f3\u30dd\u30fc\u30cd\u30f3\u30c8\u306e\u53d6\u5f97\u3092\u5b8c\u4e86\u3057\u307e\u3057\u305f
+managerBase.random=\u30af\u30e9\u30b9 {0} \u306e\u4e71\u6570\u767a\u751f\u5668\u306e\u521d\u671f\u5316\u306e\u4f8b\u5916\u3067\u3059
+managerBase.seeding=\u4e71\u6570\u767a\u751f\u5668\u30af\u30e9\u30b9 {0} \u306e\u30b7\u30fc\u30c9\u3092\u751f\u6210\u3057\u3066\u3044\u307e\u3059
+serverSession.value.iae=null\u5024\u3067\u3059
+standardManager.alreadyStarted=\u30de\u30cd\u30fc\u30b8\u30e3\u306f\u65e2\u306b\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u3059
+standardManager.createSession.ise=createSession: \u30a2\u30af\u30c6\u30a3\u30d6\u30bb\u30c3\u30b7\u30e7\u30f3\u304c\u591a\u3059\u304e\u307e\u3059
+standardManager.expireException=processsExpire: \u30bb\u30c3\u30b7\u30e7\u30f3\u306e\u7d42\u4e86\u51e6\u7406\u4e2d\u306e\u4f8b\u5916\u3067\u3059
+standardManager.loading={0} \u304b\u3089\u6301\u7d9a\u3055\u308c\u305f\u30bb\u30c3\u30b7\u30e7\u30f3\u3092\u30ed\u30fc\u30c9\u3057\u3066\u3044\u307e\u3059
+standardManager.loading.cnfe=\u6301\u7d9a\u3055\u308c\u305f\u30bb\u30c3\u30b7\u30e7\u30f3\u3092\u30ed\u30fc\u30c9\u4e2d\u306bClassNotFoundException\u304c\u767a\u751f\u3057\u307e\u3057\u305f: {0}
+standardManager.loading.ioe=\u6301\u7d9a\u3055\u308c\u305f\u30bb\u30c3\u30b7\u30e7\u30f3\u3092\u30ed\u30fc\u30c9\u4e2d\u306eIOException\u3067\u3059: {0}
+standardManager.notStarted=\u30de\u30cd\u30fc\u30b8\u30e3\u306f\u307e\u3060\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u305b\u3093
+standardManager.sessionTimeout=\u7121\u52b9\u306a\u30bb\u30c3\u30b7\u30e7\u30f3\u30bf\u30a4\u30e0\u30a2\u30a6\u30c8\u8a2d\u5b9a\u3067\u3059 {0}
+standardManager.unloading=\u6301\u7d9a\u3055\u308c\u305f\u30bb\u30c3\u30b7\u30e7\u30f3\u3092 {0} \u306b\u4fdd\u5b58\u3057\u307e\u3059
+standardManager.unloading.ioe=\u6301\u7d9a\u3055\u308c\u305f\u30bb\u30c3\u30b7\u30e7\u30f3\u306e\u4fdd\u5b58\u4e2d\u306eIOException\u3067\u3059: {0}
+standardManager.managerLoad=\u6c38\u7d9a\u8a18\u61b6\u88c5\u7f6e\u304b\u3089\u30bb\u30c3\u30b7\u30e7\u30f3\u3092\u30ed\u30fc\u30c9\u4e2d\u306e\u4f8b\u5916\u3067\u3059
+standardManager.managerUnload=\u6c38\u7d9a\u8a18\u61b6\u88c5\u7f6e\u306b\u30bb\u30c3\u30b7\u30e7\u30f3\u3092\u30a2\u30f3\u30ed\u30fc\u30c9\u4e2d\u306e\u4f8b\u5916\u3067\u3059
+standardSession.attributeEvent=\u30bb\u30c3\u30b7\u30e7\u30f3\u5c5e\u6027\u30a4\u30d9\u30f3\u30c8\u30ea\u30b9\u30ca\u304c\u4f8b\u5916\u3092\u6295\u3052\u307e\u3057\u305f
+standardSession.bindingEvent=\u30bb\u30c3\u30b7\u30e7\u30f3\u30d0\u30a4\u30f3\u30c7\u30a3\u30f3\u30b0\u30a4\u30d9\u30f3\u30c8\u30ea\u30b9\u30ca\u304c\u4f8b\u5916\u3092\u6295\u3052\u307e\u3057\u305f
+standardSession.invalidate.ise=invalidate: \u30bb\u30c3\u30b7\u30e7\u30f3\u306f\u65e2\u306b\u7121\u52b9\u5316\u3055\u308c\u3066\u3044\u307e\u3059
+standardSession.isNew.ise=isNew: \u30bb\u30c3\u30b7\u30e7\u30f3\u306f\u65e2\u306b\u7121\u52b9\u5316\u3055\u308c\u3066\u3044\u307e\u3059
+standardSession.getAttribute.ise=getAttribute: \u30bb\u30c3\u30b7\u30e7\u30f3\u306f\u65e2\u306b\u7121\u52b9\u5316\u3055\u308c\u3066\u3044\u307e\u3059
+standardSession.getAttributeNames.ise=getAttributeNames: \u30bb\u30c3\u30b7\u30e7\u30f3\u306f\u65e2\u306b\u7121\u52b9\u5316\u3055\u308c\u3066\u3044\u307e\u3059
+standardSession.getCreationTime.ise=getCreationTime: \u30bb\u30c3\u30b7\u30e7\u30f3\u306f\u65e2\u306b\u7121\u52b9\u5316\u3055\u308c\u3066\u3044\u307e\u3059
+standardSession.getLastAccessedTime.ise=getLastAccessedTime: \u30bb\u30c3\u30b7\u30e7\u30f3\u306f\u65e2\u306b\u7121\u52b9\u5316\u3055\u308c\u3066\u3044\u307e\u3059
+standardSession.getId.ise=getId: \u30bb\u30c3\u30b7\u30e7\u30f3\u306f\u65e2\u306b\u7121\u52b9\u5316\u3055\u308c\u3066\u3044\u307e\u3059
+standardSession.getMaxInactiveInterval.ise=getMaxInactiveInterval: \u30bb\u30c3\u30b7\u30e7\u30f3\u306f\u65e2\u306b\u7121\u52b9\u5316\u3055\u308c\u3066\u3044\u307e\u3059
+standardSession.getValueNames.ise=getValueNames: \u30bb\u30c3\u30b7\u30e7\u30f3\u306f\u65e2\u306b\u7121\u52b9\u5316\u3055\u308c\u3066\u3044\u307e\u3059
+standardSession.notSerializable=\u30bb\u30c3\u30b7\u30e7\u30f3 {1} \u306e\u305f\u3081\u306b\u30bb\u30c3\u30b7\u30e7\u30f3\u5c5e\u6027 {0} \u3092\u30b7\u30ea\u30a2\u30e9\u30a4\u30ba\u3067\u304d\u307e\u305b\u3093
+standardSession.removeAttribute.ise=removeAttribute: \u30bb\u30c3\u30b7\u30e7\u30f3\u306f\u65e2\u306b\u7121\u52b9\u5316\u3055\u308c\u3066\u3044\u307e\u3059
+standardSession.sessionEvent=\u30bb\u30c3\u30b7\u30e7\u30f3\u30a4\u30d9\u30f3\u30c8\u30ea\u30b9\u30ca\u304c\u4f8b\u5916\u3092\u6295\u3052\u307e\u3057\u305f
+standardSession.setAttribute.iae=setAttribute: \u30b7\u30ea\u30a2\u30e9\u30a4\u30ba\u3067\u304d\u306a\u3044\u5c5e\u6027\u3067\u3059
+standardSession.setAttribute.ise=setAttribute: \u30bb\u30c3\u30b7\u30e7\u30f3\u306f\u65e2\u306b\u7121\u52b9\u5316\u3055\u308c\u3066\u3044\u307e\u3059
+standardSession.setAttribute.namenull=setAttribute: name\u30d1\u30e9\u30e1\u30bf\u306fnull\u3067\u3042\u3063\u3066\u306f\u3044\u3051\u307e\u305b\u3093
+standardSession.sessionCreated=\u30bb\u30c3\u30b7\u30e7\u30f3ID = {0} \u3092\u751f\u6210\u3057\u307e\u3057\u305f
+persistentManager.loading={0} \u306e\u6301\u7d9a\u3055\u308c\u305f\u30bb\u30c3\u30b7\u30e7\u30f3\u3092\u30ed\u30fc\u30c9\u3057\u307e\u3059
+persistentManager.unloading={0} \u306e\u6301\u7d9a\u3055\u308c\u305f\u30bb\u30c3\u30b7\u30e7\u30f3\u3092\u4fdd\u5b58\u3057\u307e\u3059
+persistentManager.expiring= {0} \u306e\u30bb\u30c3\u30b7\u30e7\u30f3\u3092\u4fdd\u5b58\u3059\u308b\u524d\u306b\u671f\u9650\u5207\u308c\u306b\u306a\u308a\u307e\u3057\u305f
+persistentManager.deserializeError=\u30bb\u30c3\u30b7\u30e7\u30f3 {0} \u3092\u30c7\u30b7\u30ea\u30a2\u30e9\u30a4\u30ba\u4e2d\u306e\u30a8\u30e9\u30fc\u3067\u3059: {1}
+persistentManager.serializeError=\u30bb\u30c3\u30b7\u30e7\u30f3 {0} \u3092\u30b7\u30ea\u30a2\u30e9\u30a4\u30ba\u4e2d\u306e\u30a8\u30e9\u30fc\u3067\u3059: {1}
+persistentManager.swapMaxIdle={1}\u79d2\u9593\u30a2\u30a4\u30c9\u30eb\u3057\u3066\u3044\u308b\u30bb\u30c3\u30b7\u30e7\u30f3 {0} \u3092\u4fdd\u5b58\u3059\u308b\u305f\u3081\u306b\u30b9\u30ef\u30c3\u30d7\u3057\u3066\u3044\u307e\u3059
+persistentManager.backupMaxIdle={1}\u79d2\u9593\u30a2\u30a4\u30c9\u30eb\u3057\u3066\u3044\u308b\u30bb\u30c3\u30b7\u30e7\u30f3 {0} \u3092\u4fdd\u5b58\u3059\u308b\u305f\u3081\u306b\u30d0\u30c3\u30af\u30a2\u30c3\u30d7\u3057\u3066\u3044\u307e\u3059
+persistentManager.backupException=\u30bb\u30c3\u30b7\u30e7\u30f3 {0} \u3092\u30d0\u30c3\u30af\u30a2\u30c3\u30d7\u3059\u308b\u6642\u306b\u4f8b\u5916\u304c\u767a\u751f\u3057\u307e\u3057\u305f: {1}
+persistentManager.tooManyActive=\u30a2\u30af\u30c6\u30a3\u30d6\u30bb\u30c3\u30b7\u30e7\u30f3\u304c\u591a\u3059\u304e\u307e\u3059\u3001{0}\u3001\u30b9\u30ef\u30c3\u30d7\u30a2\u30a6\u30c8\u3059\u308b\u305f\u3081\u306b\u30a2\u30a4\u30c9\u30eb\u30bb\u30c3\u30b7\u30e7\u30f3\u3092\u63a2\u3057\u3066\u3044\u307e\u3059
+persistentManager.swapTooManyActive=\u30bb\u30c3\u30b7\u30e7\u30f3\u304c\u591a\u3059\u304e\u308b\u306e\u3067\u3001{1}\u79d2\u30a2\u30a4\u30c9\u30eb\u3057\u3066\u3044\u308b\u30bb\u30c3\u30b7\u30e7\u30f3 {0} \u3092\u30b9\u30ef\u30c3\u30d7\u30a2\u30a6\u30c8\u3057\u307e\u3059
+persistentManager.processSwaps=\u30bb\u30c3\u30b7\u30e7\u30f3\u3092\u30b9\u30ef\u30c3\u30d7\u3059\u308b\u305f\u3081\u306b\u30c1\u30a7\u30c3\u30af\u3057\u3066\u3044\u307e\u3059, \u30e1\u30e2\u30ea\u4e2d\u306b {0} \u30a2\u30af\u30c6\u30a3\u30d6\u30bb\u30c3\u30b7\u30e7\u30f3\u304c\u5b58\u5728\u3057\u307e\u3059
+persistentManager.activeSession=\u30bb\u30c3\u30b7\u30e7\u30f3 {0} \u306f{1}\u79d2\u9593\u30a2\u30a4\u30c9\u30eb\u3057\u3066\u3044\u307e\u3059
+persistentManager.swapIn=\u30bb\u30c3\u30b7\u30e7\u30f3 {0} \u3092\u30b9\u30ef\u30c3\u30d7\u30a4\u30f3\u3057\u3066\u3044\u307e\u3059

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/session/ManagerBase.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/session/ManagerBase.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/session/ManagerBase.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,1252 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.session;
+
+
+import java.beans.PropertyChangeListener;
+import java.beans.PropertyChangeSupport;
+import java.io.DataInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.lang.reflect.Method;
+import java.security.AccessController;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivilegedAction;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Random;
+
+import javax.management.MBeanRegistration;
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+
+import org.apache.catalina.Container;
+import org.apache.catalina.Engine;
+import org.apache.catalina.Manager;
+import org.apache.catalina.Session;
+import org.apache.catalina.core.StandardContext;
+import org.apache.catalina.core.StandardHost;
+import org.apache.catalina.util.StringManager;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.commons.modeler.Registry;
+
+
+/**
+ * Minimal implementation of the <b>Manager</b> interface that supports
+ * no session persistence or distributable capabilities.  This class may
+ * be subclassed to create more sophisticated Manager implementations.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 395980 $ $Date: 2006-04-21 13:29:21 -0500 (Fri, 21 Apr 2006) $
+ */
+
+public abstract class ManagerBase implements Manager, MBeanRegistration {
+    protected Log log = LogFactory.getLog(ManagerBase.class);
+
+    // ----------------------------------------------------- Instance Variables
+
+    protected DataInputStream randomIS=null;
+    protected String devRandomSource="/dev/urandom";
+
+    /**
+     * The default message digest algorithm to use if we cannot use
+     * the requested one.
+     */
+    protected static final String DEFAULT_ALGORITHM = "MD5";
+
+
+    /**
+     * The message digest algorithm to be used when generating session
+     * identifiers.  This must be an algorithm supported by the
+     * <code>java.security.MessageDigest</code> class on your platform.
+     */
+    protected String algorithm = DEFAULT_ALGORITHM;
+
+
+    /**
+     * The Container with which this Manager is associated.
+     */
+    protected Container container;
+
+
+    /**
+     * Return the MessageDigest implementation to be used when
+     * creating session identifiers.
+     */
+    protected MessageDigest digest = null;
+
+
+    /**
+     * The distributable flag for Sessions created by this Manager.  If this
+     * flag is set to <code>true</code>, any user attributes added to a
+     * session controlled by this Manager must be Serializable.
+     */
+    protected boolean distributable;
+
+
+    /**
+     * A String initialization parameter used to increase the entropy of
+     * the initialization of our random number generator.
+     */
+    protected String entropy = null;
+
+
+    /**
+     * The descriptive information string for this implementation.
+     */
+    private static final String info = "ManagerBase/1.0";
+
+
+    /**
+     * The default maximum inactive interval for Sessions created by
+     * this Manager.
+     */
+    protected int maxInactiveInterval = 60;
+
+
+    /**
+     * The session id length of Sessions created by this Manager.
+     */
+    protected int sessionIdLength = 16;
+
+
+    /**
+     * The descriptive name of this Manager implementation (for logging).
+     */
+    protected static String name = "ManagerBase";
+
+
+    /**
+     * A random number generator to use when generating session identifiers.
+     */
+    protected Random random = null;
+
+
+    /**
+     * The Java class name of the random number generator class to be used
+     * when generating session identifiers.
+     */
+    protected String randomClass = "java.security.SecureRandom";
+
+
+    /**
+     * The longest time (in seconds) that an expired session had been alive.
+     */
+    protected int sessionMaxAliveTime;
+
+
+    /**
+     * Average time (in seconds) that expired sessions had been alive.
+     */
+    protected int sessionAverageAliveTime;
+
+
+    /**
+     * Number of sessions that have expired.
+     */
+    protected int expiredSessions = 0;
+
+
+    /**
+     * The set of currently active Sessions for this Manager, keyed by
+     * session identifier.
+     */
+    protected HashMap sessions = new HashMap();
+
+    // Number of sessions created by this manager
+    protected int sessionCounter=0;
+
+    protected int maxActive=0;
+
+    // number of duplicated session ids - anything >0 means we have problems
+    protected int duplicates=0;
+
+    protected boolean initialized=false;
+    
+    /**
+     * Processing time during session expiration.
+     */
+    protected long processingTime = 0;
+
+    /**
+     * Iteration count for background processing.
+     */
+    private int count = 0;
+
+
+    /**
+     * Frequency of the session expiration, and related manager operations.
+     * Manager operations will be done once for the specified amount of
+     * backgrondProcess calls (ie, the lower the amount, the most often the
+     * checks will occur).
+     */
+    protected int processExpiresFrequency = 6;
+
+    /**
+     * The string manager for this package.
+     */
+    protected static StringManager sm =
+        StringManager.getManager(Constants.Package);
+
+    /**
+     * The property change support for this component.
+     */
+    protected PropertyChangeSupport support = new PropertyChangeSupport(this);
+    
+    
+    // ------------------------------------------------------------- Security classes
+
+
+    private class PrivilegedSetRandomFile implements PrivilegedAction{
+        
+        public Object run(){               
+            try {
+                File f=new File( devRandomSource );
+                if( ! f.exists() ) return null;
+                randomIS= new DataInputStream( new FileInputStream(f));
+                randomIS.readLong();
+                if( log.isDebugEnabled() )
+                    log.debug( "Opening " + devRandomSource );
+                return randomIS;
+            } catch (IOException ex){
+                return null;
+            }
+        }
+    }
+
+
+    // ------------------------------------------------------------- Properties
+
+    /**
+     * Return the message digest algorithm for this Manager.
+     */
+    public String getAlgorithm() {
+
+        return (this.algorithm);
+
+    }
+
+
+    /**
+     * Set the message digest algorithm for this Manager.
+     *
+     * @param algorithm The new message digest algorithm
+     */
+    public void setAlgorithm(String algorithm) {
+
+        String oldAlgorithm = this.algorithm;
+        this.algorithm = algorithm;
+        support.firePropertyChange("algorithm", oldAlgorithm, this.algorithm);
+
+    }
+
+
+    /**
+     * Return the Container with which this Manager is associated.
+     */
+    public Container getContainer() {
+
+        return (this.container);
+
+    }
+
+
+    /**
+     * Set the Container with which this Manager is associated.
+     *
+     * @param container The newly associated Container
+     */
+    public void setContainer(Container container) {
+
+        Container oldContainer = this.container;
+        this.container = container;
+        support.firePropertyChange("container", oldContainer, this.container);
+    }
+
+
+    /** Returns the name of the implementation class.
+     */
+    public String getClassName() {
+        return this.getClass().getName();
+    }
+
+
+    /**
+     * Return the MessageDigest object to be used for calculating
+     * session identifiers.  If none has been created yet, initialize
+     * one the first time this method is called.
+     */
+    public synchronized MessageDigest getDigest() {
+
+        if (this.digest == null) {
+            long t1=System.currentTimeMillis();
+            if (log.isDebugEnabled())
+                log.debug(sm.getString("managerBase.getting", algorithm));
+            try {
+                this.digest = MessageDigest.getInstance(algorithm);
+            } catch (NoSuchAlgorithmException e) {
+                log.error(sm.getString("managerBase.digest", algorithm), e);
+                try {
+                    this.digest = MessageDigest.getInstance(DEFAULT_ALGORITHM);
+                } catch (NoSuchAlgorithmException f) {
+                    log.error(sm.getString("managerBase.digest",
+                                     DEFAULT_ALGORITHM), e);
+                    this.digest = null;
+                }
+            }
+            if (log.isDebugEnabled())
+                log.debug(sm.getString("managerBase.gotten"));
+            long t2=System.currentTimeMillis();
+            if( log.isDebugEnabled() )
+                log.debug("getDigest() " + (t2-t1));
+        }
+
+        return (this.digest);
+
+    }
+
+
+    /**
+     * Return the distributable flag for the sessions supported by
+     * this Manager.
+     */
+    public boolean getDistributable() {
+
+        return (this.distributable);
+
+    }
+
+
+    /**
+     * Set the distributable flag for the sessions supported by this
+     * Manager.  If this flag is set, all user data objects added to
+     * sessions associated with this manager must implement Serializable.
+     *
+     * @param distributable The new distributable flag
+     */
+    public void setDistributable(boolean distributable) {
+
+        boolean oldDistributable = this.distributable;
+        this.distributable = distributable;
+        support.firePropertyChange("distributable",
+                                   new Boolean(oldDistributable),
+                                   new Boolean(this.distributable));
+
+    }
+
+
+    /**
+     * Return the entropy increaser value, or compute a semi-useful value
+     * if this String has not yet been set.
+     */
+    public String getEntropy() {
+
+        // Calculate a semi-useful value if this has not been set
+        if (this.entropy == null) {
+            // Use APR to get a crypto secure entropy value
+            byte[] result = new byte[32];
+            boolean apr = false;
+            try {
+                String methodName = "random";
+                Class paramTypes[] = new Class[2];
+                paramTypes[0] = result.getClass();
+                paramTypes[1] = int.class;
+                Object paramValues[] = new Object[2];
+                paramValues[0] = result;
+                paramValues[1] = new Integer(32);
+                Method method = Class.forName("org.apache.tomcat.jni.OS")
+                    .getMethod(methodName, paramTypes);
+                method.invoke(null, paramValues);
+                apr = true;
+            } catch (Throwable t) {
+                // Ignore
+            }
+            if (apr) {
+                setEntropy(new String(result));
+            } else {
+                setEntropy(this.toString());
+            }
+        }
+
+        return (this.entropy);
+
+    }
+
+
+    /**
+     * Set the entropy increaser value.
+     *
+     * @param entropy The new entropy increaser value
+     */
+    public void setEntropy(String entropy) {
+
+        String oldEntropy = entropy;
+        this.entropy = entropy;
+        support.firePropertyChange("entropy", oldEntropy, this.entropy);
+
+    }
+
+
+    /**
+     * Return descriptive information about this Manager implementation and
+     * the corresponding version number, in the format
+     * <code>&lt;description&gt;/&lt;version&gt;</code>.
+     */
+    public String getInfo() {
+
+        return (info);
+
+    }
+
+
+    /**
+     * Return the default maximum inactive interval (in seconds)
+     * for Sessions created by this Manager.
+     */
+    public int getMaxInactiveInterval() {
+
+        return (this.maxInactiveInterval);
+
+    }
+
+
+    /**
+     * Set the default maximum inactive interval (in seconds)
+     * for Sessions created by this Manager.
+     *
+     * @param interval The new default value
+     */
+    public void setMaxInactiveInterval(int interval) {
+
+        int oldMaxInactiveInterval = this.maxInactiveInterval;
+        this.maxInactiveInterval = interval;
+        support.firePropertyChange("maxInactiveInterval",
+                                   new Integer(oldMaxInactiveInterval),
+                                   new Integer(this.maxInactiveInterval));
+
+    }
+
+
+    /**
+     * Gets the session id length (in bytes) of Sessions created by
+     * this Manager.
+     *
+     * @return The session id length
+     */
+    public int getSessionIdLength() {
+
+        return (this.sessionIdLength);
+
+    }
+
+
+    /**
+     * Sets the session id length (in bytes) for Sessions created by this
+     * Manager.
+     *
+     * @param idLength The session id length
+     */
+    public void setSessionIdLength(int idLength) {
+
+        int oldSessionIdLength = this.sessionIdLength;
+        this.sessionIdLength = idLength;
+        support.firePropertyChange("sessionIdLength",
+                                   new Integer(oldSessionIdLength),
+                                   new Integer(this.sessionIdLength));
+
+    }
+
+
+    /**
+     * Return the descriptive short name of this Manager implementation.
+     */
+    public String getName() {
+
+        return (name);
+
+    }
+
+    /** 
+     * Use /dev/random-type special device. This is new code, but may reduce
+     * the big delay in generating the random.
+     *
+     *  You must specify a path to a random generator file. Use /dev/urandom
+     *  for linux ( or similar ) systems. Use /dev/random for maximum security
+     *  ( it may block if not enough "random" exist ). You can also use
+     *  a pipe that generates random.
+     *
+     *  The code will check if the file exists, and default to java Random
+     *  if not found. There is a significant performance difference, very
+     *  visible on the first call to getSession ( like in the first JSP )
+     *  - so use it if available.
+     */
+    public void setRandomFile( String s ) {
+        // as a hack, you can use a static file - and genarate the same
+        // session ids ( good for strange debugging )
+        if (System.getSecurityManager() != null){
+            randomIS = (DataInputStream)AccessController.doPrivileged(new PrivilegedSetRandomFile());          
+        } else {
+            try{
+                devRandomSource=s;
+                File f=new File( devRandomSource );
+                if( ! f.exists() ) return;
+                randomIS= new DataInputStream( new FileInputStream(f));
+                randomIS.readLong();
+                if( log.isDebugEnabled() )
+                    log.debug( "Opening " + devRandomSource );
+            } catch( IOException ex ) {
+                try {
+                    randomIS.close();
+                } catch (Exception e) {
+                    log.warn("Failed to close randomIS.");
+                }
+                
+                randomIS=null;
+            }
+        }
+    }
+
+    public String getRandomFile() {
+        return devRandomSource;
+    }
+
+
+    /**
+     * Return the random number generator instance we should use for
+     * generating session identifiers.  If there is no such generator
+     * currently defined, construct and seed a new one.
+     */
+    public Random getRandom() {
+        if (this.random == null) {
+            // Calculate the new random number generator seed
+            long seed = System.currentTimeMillis();
+            long t1 = seed;
+            char entropy[] = getEntropy().toCharArray();
+            for (int i = 0; i < entropy.length; i++) {
+                long update = ((byte) entropy[i]) << ((i % 8) * 8);
+                seed ^= update;
+            }
+            try {
+                // Construct and seed a new random number generator
+                Class clazz = Class.forName(randomClass);
+                this.random = (Random) clazz.newInstance();
+                this.random.setSeed(seed);
+            } catch (Exception e) {
+                // Fall back to the simple case
+                log.error(sm.getString("managerBase.random", randomClass),
+                        e);
+                this.random = new java.util.Random();
+                this.random.setSeed(seed);
+            }
+            if(log.isDebugEnabled()) {
+                long t2=System.currentTimeMillis();
+                if( (t2-t1) > 100 )
+                    log.debug(sm.getString("managerBase.seeding", randomClass) + " " + (t2-t1));
+            }
+        }
+        
+        return (this.random);
+
+    }
+
+
+    /**
+     * Return the random number generator class name.
+     */
+    public String getRandomClass() {
+
+        return (this.randomClass);
+
+    }
+
+
+    /**
+     * Set the random number generator class name.
+     *
+     * @param randomClass The new random number generator class name
+     */
+    public void setRandomClass(String randomClass) {
+
+        String oldRandomClass = this.randomClass;
+        this.randomClass = randomClass;
+        support.firePropertyChange("randomClass", oldRandomClass,
+                                   this.randomClass);
+
+    }
+
+
+    /**
+     * Gets the number of sessions that have expired.
+     *
+     * @return Number of sessions that have expired
+     */
+    public int getExpiredSessions() {
+        return expiredSessions;
+    }
+
+
+    /**
+     * Sets the number of sessions that have expired.
+     *
+     * @param expiredSessions Number of sessions that have expired
+     */
+    public void setExpiredSessions(int expiredSessions) {
+        this.expiredSessions = expiredSessions;
+    }
+
+    public long getProcessingTime() {
+        return processingTime;
+    }
+
+
+    public void setProcessingTime(long processingTime) {
+        this.processingTime = processingTime;
+    }
+    
+    /**
+     * Return the frequency of manager checks.
+     */
+    public int getProcessExpiresFrequency() {
+
+        return (this.processExpiresFrequency);
+
+    }
+
+    /**
+     * Set the manager checks frequency.
+     *
+     * @param processExpiresFrequency the new manager checks frequency
+     */
+    public void setProcessExpiresFrequency(int processExpiresFrequency) {
+
+        if (processExpiresFrequency <= 0) {
+            return;
+        }
+
+        int oldProcessExpiresFrequency = this.processExpiresFrequency;
+        this.processExpiresFrequency = processExpiresFrequency;
+        support.firePropertyChange("processExpiresFrequency",
+                                   new Integer(oldProcessExpiresFrequency),
+                                   new Integer(this.processExpiresFrequency));
+
+    }
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Implements the Manager interface, direct call to processExpires
+     */
+    public void backgroundProcess() {
+        count = (count + 1) % processExpiresFrequency;
+        if (count == 0)
+            processExpires();
+    }
+
+    /**
+     * Invalidate all sessions that have expired.
+     */
+    public void processExpires() {
+
+        long timeNow = System.currentTimeMillis();
+        Session sessions[] = findSessions();
+        int expireHere = 0 ;
+        
+        if(log.isDebugEnabled())
+            log.debug("Start expire sessions " + getName() + " at " + timeNow + " sessioncount " + sessions.length);
+        for (int i = 0; i < sessions.length; i++) {
+            if (!sessions[i].isValid()) {
+                expireHere++;
+            }
+        }
+        long timeEnd = System.currentTimeMillis();
+        if(log.isDebugEnabled())
+             log.debug("End expire sessions " + getName() + " processingTime " + (timeEnd - timeNow) + " expired sessions: " + expireHere);
+        processingTime += ( timeEnd - timeNow );
+
+    }
+
+    public void destroy() {
+        if( oname != null )
+            Registry.getRegistry(null, null).unregisterComponent(oname);
+        initialized=false;
+        oname = null;
+    }
+    
+    public void init() {
+        if( initialized ) return;
+        initialized=true;        
+        
+        if( oname==null ) {
+            try {
+                StandardContext ctx=(StandardContext)this.getContainer();
+                Engine eng=(Engine)ctx.getParent().getParent();
+                domain=ctx.getEngineName();
+                distributable = ctx.getDistributable();
+                StandardHost hst=(StandardHost)ctx.getParent();
+                String path = ctx.getPath();
+                if (path.equals("")) {
+                    path = "/";
+                }   
+                oname=new ObjectName(domain + ":type=Manager,path="
+                + path + ",host=" + hst.getName());
+                Registry.getRegistry(null, null).registerComponent(this, oname, null );
+            } catch (Exception e) {
+                log.error("Error registering ",e);
+            }
+        }
+        
+        // Initialize random number generation
+        getRandomBytes(new byte[16]);
+        
+        if(log.isDebugEnabled())
+            log.debug("Registering " + oname );
+               
+    }
+
+    /**
+     * Add this Session to the set of active Sessions for this Manager.
+     *
+     * @param session Session to be added
+     */
+    public void add(Session session) {
+
+        synchronized (sessions) {
+            sessions.put(session.getIdInternal(), session);
+            if( sessions.size() > maxActive ) {
+                maxActive=sessions.size();
+            }
+        }
+    }
+
+
+    /**
+     * Add a property change listener to this component.
+     *
+     * @param listener The listener to add
+     */
+    public void addPropertyChangeListener(PropertyChangeListener listener) {
+
+        support.addPropertyChangeListener(listener);
+
+    }
+
+
+    /**
+     * Construct and return a new session object, based on the default
+     * settings specified by this Manager's properties.  The session
+     * id will be assigned by this method, and available via the getId()
+     * method of the returned session.  If a new session cannot be created
+     * for any reason, return <code>null</code>.
+     * 
+     * @exception IllegalStateException if a new session cannot be
+     *  instantiated for any reason
+     * @deprecated
+     */
+    public Session createSession() {
+        return createSession(null);
+    }
+    
+    
+    /**
+     * Construct and return a new session object, based on the default
+     * settings specified by this Manager's properties.  The session
+     * id specified will be used as the session id.  
+     * If a new session cannot be created for any reason, return 
+     * <code>null</code>.
+     * 
+     * @param sessionId The session id which should be used to create the
+     *  new session; if <code>null</code>, a new session id will be
+     *  generated
+     * @exception IllegalStateException if a new session cannot be
+     *  instantiated for any reason
+     */
+    public Session createSession(String sessionId) {
+        
+        // Recycle or create a Session instance
+        Session session = createEmptySession();
+
+        // Initialize the properties of the new session and return it
+        session.setNew(true);
+        session.setValid(true);
+        session.setCreationTime(System.currentTimeMillis());
+        session.setMaxInactiveInterval(this.maxInactiveInterval);
+        if (sessionId == null) {
+            sessionId = generateSessionId();
+        // FIXME WHy we need no duplication check?
+        /*         
+             synchronized (sessions) {
+                while (sessions.get(sessionId) != null) { // Guarantee
+                    // uniqueness
+                    duplicates++;
+                    sessionId = generateSessionId();
+                }
+            }
+        */
+            
+            // FIXME: Code to be used in case route replacement is needed
+            /*
+        } else {
+            String jvmRoute = getJvmRoute();
+            if (getJvmRoute() != null) {
+                String requestJvmRoute = null;
+                int index = sessionId.indexOf(".");
+                if (index > 0) {
+                    requestJvmRoute = sessionId
+                            .substring(index + 1, sessionId.length());
+                }
+                if (requestJvmRoute != null && !requestJvmRoute.equals(jvmRoute)) {
+                    sessionId = sessionId.substring(0, index) + "." + jvmRoute;
+                }
+            }
+            */
+        }
+        session.setId(sessionId);
+        sessionCounter++;
+
+        return (session);
+
+    }
+    
+    
+    /**
+     * Get a session from the recycled ones or create a new empty one.
+     * The PersistentManager manager does not need to create session data
+     * because it reads it from the Store.
+     */
+    public Session createEmptySession() {
+        return (getNewSession());
+    }
+
+
+    /**
+     * Return the active Session, associated with this Manager, with the
+     * specified session id (if any); otherwise return <code>null</code>.
+     *
+     * @param id The session id for the session to be returned
+     *
+     * @exception IllegalStateException if a new session cannot be
+     *  instantiated for any reason
+     * @exception IOException if an input/output error occurs while
+     *  processing this request
+     */
+    public Session findSession(String id) throws IOException {
+
+        if (id == null)
+            return (null);
+        synchronized (sessions) {
+            Session session = (Session) sessions.get(id);
+            return (session);
+        }
+
+    }
+
+
+    /**
+     * Return the set of active Sessions associated with this Manager.
+     * If this Manager has no active Sessions, a zero-length array is returned.
+     */
+    public Session[] findSessions() {
+
+        Session results[] = null;
+        synchronized (sessions) {
+            results = new Session[sessions.size()];
+            results = (Session[]) sessions.values().toArray(results);
+        }
+        return (results);
+
+    }
+
+
+    /**
+     * Remove this Session from the active Sessions for this Manager.
+     *
+     * @param session Session to be removed
+     */
+    public void remove(Session session) {
+
+        synchronized (sessions) {
+            sessions.remove(session.getIdInternal());
+        }
+
+    }
+
+
+    /**
+     * Remove a property change listener from this component.
+     *
+     * @param listener The listener to remove
+     */
+    public void removePropertyChangeListener(PropertyChangeListener listener) {
+
+        support.removePropertyChangeListener(listener);
+
+    }
+
+
+    // ------------------------------------------------------ Protected Methods
+
+
+    /**
+     * Get new session class to be used in the doLoad() method.
+     */
+    protected StandardSession getNewSession() {
+        return new StandardSession(this);
+    }
+
+
+    protected void getRandomBytes(byte bytes[]) {
+        // Generate a byte array containing a session identifier
+        if (devRandomSource != null && randomIS == null) {
+            setRandomFile(devRandomSource);
+        }
+        if (randomIS != null) {
+            try {
+                int len = randomIS.read(bytes);
+                if (len == bytes.length) {
+                    return;
+                }
+                if(log.isDebugEnabled())
+                    log.debug("Got " + len + " " + bytes.length );
+            } catch (Exception ex) {
+                // Ignore
+            }
+            devRandomSource = null;
+            
+            try {
+                randomIS.close();
+            } catch (Exception e) {
+                log.warn("Failed to close randomIS.");
+            }
+            
+            randomIS = null;
+        }
+        getRandom().nextBytes(bytes);
+    }
+
+
+    /**
+     * Generate and return a new session identifier.
+     */
+    protected synchronized String generateSessionId() {
+
+        byte random[] = new byte[16];
+        String jvmRoute = getJvmRoute();
+        String result = null;
+
+        // Render the result as a String of hexadecimal digits
+        StringBuffer buffer = new StringBuffer();
+        do {
+            int resultLenBytes = 0;
+            if (result != null) {
+                buffer = new StringBuffer();
+                duplicates++;
+            }
+
+            while (resultLenBytes < this.sessionIdLength) {
+                getRandomBytes(random);
+                random = getDigest().digest(random);
+                for (int j = 0;
+                j < random.length && resultLenBytes < this.sessionIdLength;
+                j++) {
+                    byte b1 = (byte) ((random[j] & 0xf0) >> 4);
+                    byte b2 = (byte) (random[j] & 0x0f);
+                    if (b1 < 10)
+                        buffer.append((char) ('0' + b1));
+                    else
+                        buffer.append((char) ('A' + (b1 - 10)));
+                    if (b2 < 10)
+                        buffer.append((char) ('0' + b2));
+                    else
+                        buffer.append((char) ('A' + (b2 - 10)));
+                    resultLenBytes++;
+                }
+            }
+            if (jvmRoute != null) {
+                buffer.append('.').append(jvmRoute);
+            }
+            result = buffer.toString();
+        } while (sessions.containsKey(result));
+        return (result);
+
+    }
+
+
+    // ------------------------------------------------------ Protected Methods
+
+
+    /**
+     * Retrieve the enclosing Engine for this Manager.
+     *
+     * @return an Engine object (or null).
+     */
+    public Engine getEngine() {
+        Engine e = null;
+        for (Container c = getContainer(); e == null && c != null ; c = c.getParent()) {
+            if (c != null && c instanceof Engine) {
+                e = (Engine)c;
+            }
+        }
+        return e;
+    }
+
+
+    /**
+     * Retrieve the JvmRoute for the enclosing Engine.
+     * @return the JvmRoute or null.
+     */
+    public String getJvmRoute() {
+        Engine e = getEngine();
+        return e == null ? null : e.getJvmRoute();
+    }
+
+
+    // -------------------------------------------------------- Package Methods
+
+
+    public void setSessionCounter(int sessionCounter) {
+        this.sessionCounter = sessionCounter;
+    }
+
+
+    /** 
+     * Total sessions created by this manager.
+     *
+     * @return sessions created
+     */
+    public int getSessionCounter() {
+        return sessionCounter;
+    }
+
+
+    /** 
+     * Number of duplicated session IDs generated by the random source.
+     * Anything bigger than 0 means problems.
+     *
+     * @return The count of duplicates
+     */
+    public int getDuplicates() {
+        return duplicates;
+    }
+
+
+    public void setDuplicates(int duplicates) {
+        this.duplicates = duplicates;
+    }
+
+
+    /** 
+     * Returns the number of active sessions
+     *
+     * @return number of sessions active
+     */
+    public int getActiveSessions() {
+        return sessions.size();
+    }
+
+
+    /**
+     * Max number of concurrent active sessions
+     *
+     * @return The highest number of concurrent active sessions
+     */
+    public int getMaxActive() {
+        return maxActive;
+    }
+
+
+    public void setMaxActive(int maxActive) {
+        this.maxActive = maxActive;
+    }
+
+
+    /**
+     * Gets the longest time (in seconds) that an expired session had been
+     * alive.
+     *
+     * @return Longest time (in seconds) that an expired session had been
+     * alive.
+     */
+    public int getSessionMaxAliveTime() {
+        return sessionMaxAliveTime;
+    }
+
+
+    /**
+     * Sets the longest time (in seconds) that an expired session had been
+     * alive.
+     *
+     * @param sessionMaxAliveTime Longest time (in seconds) that an expired
+     * session had been alive.
+     */
+    public void setSessionMaxAliveTime(int sessionMaxAliveTime) {
+        this.sessionMaxAliveTime = sessionMaxAliveTime;
+    }
+
+
+    /**
+     * Gets the average time (in seconds) that expired sessions had been
+     * alive.
+     *
+     * @return Average time (in seconds) that expired sessions had been
+     * alive.
+     */
+    public int getSessionAverageAliveTime() {
+        return sessionAverageAliveTime;
+    }
+
+
+    /**
+     * Sets the average time (in seconds) that expired sessions had been
+     * alive.
+     *
+     * @param sessionAverageAliveTime Average time (in seconds) that expired
+     * sessions had been alive.
+     */
+    public void setSessionAverageAliveTime(int sessionAverageAliveTime) {
+        this.sessionAverageAliveTime = sessionAverageAliveTime;
+    }
+
+
+    /** 
+     * For debugging: return a list of all session ids currently active
+     *
+     */
+    public String listSessionIds() {
+        StringBuffer sb=new StringBuffer();
+        Iterator keys=sessions.keySet().iterator();
+        while( keys.hasNext() ) {
+            sb.append(keys.next()).append(" ");
+        }
+        return sb.toString();
+    }
+
+
+    /** 
+     * For debugging: get a session attribute
+     *
+     * @param sessionId
+     * @param key
+     * @return The attribute value, if found, null otherwise
+     */
+    public String getSessionAttribute( String sessionId, String key ) {
+        Session s=(Session)sessions.get(sessionId);
+        if( s==null ) {
+            if(log.isInfoEnabled())
+                log.info("Session not found " + sessionId);
+            return null;
+        }
+        Object o=s.getSession().getAttribute(key);
+        if( o==null ) return null;
+        return o.toString();
+    }
+
+
+    /**
+     * Returns information about the session with the given session id.
+     * 
+     * <p>The session information is organized as a HashMap, mapping 
+     * session attribute names to the String representation of their values.
+     *
+     * @param sessionId Session id
+     * 
+     * @return HashMap mapping session attribute names to the String
+     * representation of their values, or null if no session with the
+     * specified id exists, or if the session does not have any attributes
+     */
+    public HashMap getSession(String sessionId) {
+        Session s = (Session) sessions.get(sessionId);
+        if (s == null) {
+            if (log.isInfoEnabled()) {
+                log.info("Session not found " + sessionId);
+            }
+            return null;
+        }
+
+        Enumeration ee = s.getSession().getAttributeNames();
+        if (ee == null || !ee.hasMoreElements()) {
+            return null;
+        }
+
+        HashMap map = new HashMap();
+        while (ee.hasMoreElements()) {
+            String attrName = (String) ee.nextElement();
+            map.put(attrName, getSessionAttribute(sessionId, attrName));
+        }
+
+        return map;
+    }
+
+
+    public void expireSession( String sessionId ) {
+        Session s=(Session)sessions.get(sessionId);
+        if( s==null ) {
+            if(log.isInfoEnabled())
+                log.info("Session not found " + sessionId);
+            return;
+        }
+        s.expire();
+    }
+
+
+    public String getLastAccessedTime( String sessionId ) {
+        Session s=(Session)sessions.get(sessionId);
+        if( s==null ) {
+            log.info("Session not found " + sessionId);
+            return "";
+        }
+        return new Date(s.getLastAccessedTime()).toString();
+    }
+
+
+    // -------------------- JMX and Registration  --------------------
+    protected String domain;
+    protected ObjectName oname;
+    protected MBeanServer mserver;
+
+    public ObjectName getObjectName() {
+        return oname;
+    }
+
+    public String getDomain() {
+        return domain;
+    }
+
+    public ObjectName preRegister(MBeanServer server,
+                                  ObjectName name) throws Exception {
+        oname=name;
+        mserver=server;
+        domain=name.getDomain();
+        return name;
+    }
+
+    public void postRegister(Boolean registrationDone) {
+    }
+
+    public void preDeregister() throws Exception {
+    }
+
+    public void postDeregister() {
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/session/PersistentManager.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/session/PersistentManager.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/session/PersistentManager.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,76 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.session;
+
+/**
+ * Implementation of the <b>Manager</b> interface that makes use of
+ * a Store to swap active Sessions to disk. It can be configured to
+ * achieve several different goals:
+ *
+ * <li>Persist sessions across restarts of the Container</li>
+ * <li>Fault tolerance, keep sessions backed up on disk to allow
+ *     recovery in the event of unplanned restarts.</li>
+ * <li>Limit the number of active sessions kept in memory by
+ *     swapping less active sessions out to disk.</li>
+ *
+ * @version $Revision: 302726 $
+ * @author Kief Morris (kief at kief.com)
+ */
+
+public final class PersistentManager extends PersistentManagerBase {
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The descriptive information about this implementation.
+     */
+    private static final String info = "PersistentManager/1.0";
+
+
+    /**
+     * The descriptive name of this Manager implementation (for logging).
+     */
+    protected static String name = "PersistentManager";
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * Return descriptive information about this Manager implementation and
+     * the corresponding version number, in the format
+     * <code>&lt;description&gt;/&lt;version&gt;</code>.
+     */
+    public String getInfo() {
+
+        return (info);
+
+    }
+
+    /**
+     * Return the descriptive short name of this Manager implementation.
+     */
+    public String getName() {
+
+        return (name);
+
+    }
+ }
+

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/session/PersistentManagerBase.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/session/PersistentManagerBase.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/session/PersistentManagerBase.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,1130 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.session;
+
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+import java.io.IOException;
+import java.security.AccessController;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
+import org.apache.catalina.Container;
+import org.apache.catalina.Context;
+import org.apache.catalina.Lifecycle;
+import org.apache.catalina.LifecycleException;
+import org.apache.catalina.LifecycleListener;
+import org.apache.catalina.Session;
+import org.apache.catalina.Store;
+import org.apache.catalina.util.LifecycleSupport;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.apache.catalina.security.SecurityUtil;
+/**
+ * Extends the <b>ManagerBase</b> class to implement most of the
+ * functionality required by a Manager which supports any kind of
+ * persistence, even if onlyfor  restarts.
+ * <p>
+ * <b>IMPLEMENTATION NOTE</b>:  Correct behavior of session storing and
+ * reloading depends upon external calls to the <code>start()</code> and
+ * <code>stop()</code> methods of this class at the correct times.
+ *
+ * @author Craig R. McClanahan
+ * @author Jean-Francois Arcand
+ * @version $Revision: 303826 $ $Date: 2005-03-31 04:31:54 -0600 (Thu, 31 Mar 2005) $
+ */
+
+public abstract class PersistentManagerBase
+    extends ManagerBase
+    implements Lifecycle, PropertyChangeListener {
+
+    private static Log log = LogFactory.getLog(PersistentManagerBase.class);
+
+    // ---------------------------------------------------- Security Classes
+
+    private class PrivilegedStoreClear
+        implements PrivilegedExceptionAction {
+
+        PrivilegedStoreClear() {            
+        }
+
+        public Object run() throws Exception{
+           store.clear();
+           return null;
+        }                       
+    }   
+     
+    private class PrivilegedStoreRemove
+        implements PrivilegedExceptionAction {
+
+        private String id;    
+            
+        PrivilegedStoreRemove(String id) {     
+            this.id = id;
+        }
+
+        public Object run() throws Exception{
+           store.remove(id);
+           return null;
+        }                       
+    }   
+     
+    private class PrivilegedStoreLoad
+        implements PrivilegedExceptionAction {
+
+        private String id;    
+            
+        PrivilegedStoreLoad(String id) {     
+            this.id = id;
+        }
+
+        public Object run() throws Exception{
+           return store.load(id);
+        }                       
+    }   
+          
+    private class PrivilegedStoreSave
+        implements PrivilegedExceptionAction {
+
+        private Session session;    
+            
+        PrivilegedStoreSave(Session session) {     
+            this.session = session;
+        }
+
+        public Object run() throws Exception{
+           store.save(session);
+           return null;
+        }                       
+    }   
+     
+    private class PrivilegedStoreKeys
+        implements PrivilegedExceptionAction {
+
+        PrivilegedStoreKeys() {     
+        }
+
+        public Object run() throws Exception{
+           return store.keys();
+        }                       
+    }
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The descriptive information about this implementation.
+     */
+    private static final String info = "PersistentManagerBase/1.1";
+
+
+    /**
+     * The lifecycle event support for this component.
+     */
+    protected LifecycleSupport lifecycle = new LifecycleSupport(this);
+
+
+    /**
+     * The maximum number of active Sessions allowed, or -1 for no limit.
+     */
+    protected int maxActiveSessions = -1;
+
+
+    /**
+     * The descriptive name of this Manager implementation (for logging).
+     */
+    private static String name = "PersistentManagerBase";
+
+
+    /**
+     * Has this component been started yet?
+     */
+    protected boolean started = false;
+
+
+    /**
+     * Store object which will manage the Session store.
+     */
+    protected Store store = null;
+
+
+    /**
+     * Whether to save and reload sessions when the Manager <code>unload</code>
+     * and <code>load</code> methods are called.
+     */
+    protected boolean saveOnRestart = true;
+
+
+    /**
+     * How long a session must be idle before it should be backed up.
+     * -1 means sessions won't be backed up.
+     */
+    protected int maxIdleBackup = -1;
+
+
+    /**
+     * Minimum time a session must be idle before it is swapped to disk.
+     * This overrides maxActiveSessions, to prevent thrashing if there are lots
+     * of active sessions. Setting to -1 means it's ignored.
+     */
+    protected int minIdleSwap = -1;
+
+    /**
+     * The maximum time a session may be idle before it should be swapped
+     * to file just on general principle. Setting this to -1 means sessions
+     * should not be forced out.
+     */
+    protected int maxIdleSwap = -1;
+
+
+    /**
+     * Number of session creations that failed due to maxActiveSessions.
+     */
+    protected int rejectedSessions = 0;
+
+
+    /**
+     * Processing time during session expiration and passivation.
+     */
+    protected long processingTime = 0;
+
+
+    // ------------------------------------------------------------- Properties
+
+    
+  
+
+
+    /**
+	 * Indicates how many seconds old a session can get, after its last use in a
+	 * request, before it should be backed up to the store. -1 means sessions
+	 * are not backed up.
+	 */
+    public int getMaxIdleBackup() {
+
+        return maxIdleBackup;
+
+    }
+
+
+    /**
+     * Sets the option to back sessions up to the Store after they
+     * are used in a request. Sessions remain available in memory
+     * after being backed up, so they are not passivated as they are
+     * when swapped out. The value set indicates how old a session
+     * may get (since its last use) before it must be backed up: -1
+     * means sessions are not backed up.
+     * <p>
+     * Note that this is not a hard limit: sessions are checked
+     * against this age limit periodically according to <b>processExpiresFrequency</b>.
+     * This value should be considered to indicate when a session is
+     * ripe for backing up.
+     * <p>
+     * So it is possible that a session may be idle for maxIdleBackup +
+     * processExpiresFrequency * engine.backgroundProcessorDelay seconds, plus the time it takes to handle other
+     * session expiration, swapping, etc. tasks.
+     *
+     * @param backup The number of seconds after their last accessed
+     * time when they should be written to the Store.
+     */
+    public void setMaxIdleBackup (int backup) {
+
+        if (backup == this.maxIdleBackup)
+            return;
+        int oldBackup = this.maxIdleBackup;
+        this.maxIdleBackup = backup;
+        support.firePropertyChange("maxIdleBackup",
+                                   new Integer(oldBackup),
+                                   new Integer(this.maxIdleBackup));
+
+    }
+
+
+    /**
+     * The time in seconds after which a session should be swapped out of
+     * memory to disk.
+     */
+    public int getMaxIdleSwap() {
+
+        return maxIdleSwap;
+
+    }
+
+
+    /**
+     * Sets the time in seconds after which a session should be swapped out of
+     * memory to disk.
+     */
+    public void setMaxIdleSwap(int max) {
+
+        if (max == this.maxIdleSwap)
+            return;
+        int oldMaxIdleSwap = this.maxIdleSwap;
+        this.maxIdleSwap = max;
+        support.firePropertyChange("maxIdleSwap",
+                                   new Integer(oldMaxIdleSwap),
+                                   new Integer(this.maxIdleSwap));
+
+    }
+
+
+    /**
+     * The minimum time in seconds that a session must be idle before
+     * it can be swapped out of memory, or -1 if it can be swapped out
+     * at any time.
+     */
+    public int getMinIdleSwap() {
+
+        return minIdleSwap;
+
+    }
+
+
+    /**
+     * Sets the minimum time in seconds that a session must be idle before
+     * it can be swapped out of memory due to maxActiveSession. Set it to -1
+     * if it can be swapped out at any time.
+     */
+    public void setMinIdleSwap(int min) {
+
+        if (this.minIdleSwap == min)
+            return;
+        int oldMinIdleSwap = this.minIdleSwap;
+        this.minIdleSwap = min;
+        support.firePropertyChange("minIdleSwap",
+                                   new Integer(oldMinIdleSwap),
+                                   new Integer(this.minIdleSwap));
+
+    }
+
+
+    /**
+	 * Set the Container with which this Manager has been associated. If it is a
+	 * Context (the usual case), listen for changes to the session timeout
+	 * property.
+	 * 
+	 * @param container
+	 *            The associated Container
+	 */
+    public void setContainer(Container container) {
+
+        // De-register from the old Container (if any)
+        if ((this.container != null) && (this.container instanceof Context))
+            ((Context) this.container).removePropertyChangeListener(this);
+
+        // Default processing provided by our superclass
+        super.setContainer(container);
+
+        // Register with the new Container (if any)
+        if ((this.container != null) && (this.container instanceof Context)) {
+            setMaxInactiveInterval
+                ( ((Context) this.container).getSessionTimeout()*60 );
+            ((Context) this.container).addPropertyChangeListener(this);
+        }
+
+    }
+
+
+    /**
+     * Return descriptive information about this Manager implementation and
+     * the corresponding version number, in the format
+     * <code>&lt;description&gt;/&lt;version&gt;</code>.
+     */
+    public String getInfo() {
+
+        return (info);
+
+    }
+
+
+    /**
+     * Return true, if the session id is loaded in memory
+     * otherwise false is returned
+     *
+     * @param id The session id for the session to be searched for
+     */
+    public boolean isLoaded( String id ){
+        try {
+            if ( super.findSession(id) != null )
+                return true;
+        } catch (IOException e) {
+            log.error("checking isLoaded for id, " + id + ", "+e.getMessage(), e);
+        }
+        return false;
+    }
+
+
+    /**
+     * Return the maximum number of active Sessions allowed, or -1 for
+     * no limit.
+     */
+    public int getMaxActiveSessions() {
+
+        return (this.maxActiveSessions);
+
+    }
+
+
+    /**
+     * Set the maximum number of actives Sessions allowed, or -1 for
+     * no limit.
+     *
+     * @param max The new maximum number of sessions
+     */
+    public void setMaxActiveSessions(int max) {
+
+        int oldMaxActiveSessions = this.maxActiveSessions;
+        this.maxActiveSessions = max;
+        support.firePropertyChange("maxActiveSessions",
+                                   new Integer(oldMaxActiveSessions),
+                                   new Integer(this.maxActiveSessions));
+
+    }
+
+
+    /** 
+     * Number of session creations that failed due to maxActiveSessions.
+     *
+     * @return The count
+     */
+    public int getRejectedSessions() {
+        return rejectedSessions;
+    }
+
+    
+    public void setRejectedSessions(int rejectedSessions) {
+        this.rejectedSessions = rejectedSessions;
+    }
+
+    /**
+     * Return the descriptive short name of this Manager implementation.
+     */
+    public String getName() {
+
+        return (name);
+
+    }
+
+
+    /**
+     * Get the started status.
+     */
+    protected boolean isStarted() {
+
+        return started;
+
+    }
+
+
+    /**
+     * Set the started flag
+     */
+    protected void setStarted(boolean started) {
+
+        this.started = started;
+
+    }
+
+
+    /**
+     * Set the Store object which will manage persistent Session
+     * storage for this Manager.
+     *
+     * @param store the associated Store
+     */
+    public void setStore(Store store) {
+        this.store = store;
+        store.setManager(this);
+
+    }
+
+
+    /**
+     * Return the Store object which manages persistent Session
+     * storage for this Manager.
+     */
+    public Store getStore() {
+
+        return (this.store);
+
+    }
+
+
+
+    /**
+     * Indicates whether sessions are saved when the Manager is shut down
+     * properly. This requires the unload() method to be called.
+     */
+    public boolean getSaveOnRestart() {
+
+        return saveOnRestart;
+
+    }
+
+
+    /**
+     * Set the option to save sessions to the Store when the Manager is
+     * shut down, then loaded when the Manager starts again. If set to
+     * false, any sessions found in the Store may still be picked up when
+     * the Manager is started again.
+     *
+     * @param saveOnRestart true if sessions should be saved on restart, false if
+     *     they should be ignored.
+     */
+    public void setSaveOnRestart(boolean saveOnRestart) {
+
+        if (saveOnRestart == this.saveOnRestart)
+            return;
+
+        boolean oldSaveOnRestart = this.saveOnRestart;
+        this.saveOnRestart = saveOnRestart;
+        support.firePropertyChange("saveOnRestart",
+                                   new Boolean(oldSaveOnRestart),
+                                   new Boolean(this.saveOnRestart));
+
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Clear all sessions from the Store.
+     */
+    public void clearStore() {
+
+        if (store == null)
+            return;
+
+        try {     
+            if (SecurityUtil.isPackageProtectionEnabled()){
+                try{
+                    AccessController.doPrivileged(new PrivilegedStoreClear());
+                }catch(PrivilegedActionException ex){
+                    Exception exception = ex.getException();
+                    log.error("Exception clearing the Store: " + exception);
+                    exception.printStackTrace();                        
+                }
+            } else {
+                store.clear();
+            }
+        } catch (IOException e) {
+            log.error("Exception clearing the Store: " + e);
+            e.printStackTrace();
+        }
+
+    }
+
+
+    /**
+     * Implements the Manager interface, direct call to processExpires and processPersistenceChecks
+     */
+	public void processExpires() {
+		
+        long timeNow = System.currentTimeMillis();
+        Session sessions[] = findSessions();
+        int expireHere = 0 ;
+        if(log.isDebugEnabled())
+             log.debug("Start expire sessions " + getName() + " at " + timeNow + " sessioncount " + sessions.length);
+        for (int i = 0; i < sessions.length; i++) {
+            if (!sessions[i].isValid()) {
+                expiredSessions++;
+                expireHere++;
+            }
+        }
+        processPersistenceChecks();
+        if ((getStore() != null) && (getStore() instanceof StoreBase)) {
+            ((StoreBase) getStore()).processExpires();
+        }
+        
+        long timeEnd = System.currentTimeMillis();
+        if(log.isDebugEnabled())
+             log.debug("End expire sessions " + getName() + " processingTime " + (timeEnd - timeNow) + " expired sessions: " + expireHere);
+        processingTime += (timeEnd - timeNow);
+ 		
+	}
+
+
+    /**
+     * Called by the background thread after active sessions have been checked
+     * for expiration, to allow sessions to be swapped out, backed up, etc.
+     */
+    public void processPersistenceChecks() {
+
+        processMaxIdleSwaps();
+        processMaxActiveSwaps();
+        processMaxIdleBackups();
+
+    }
+
+
+    /**
+     * Return the active Session, associated with this Manager, with the
+     * specified session id (if any); otherwise return <code>null</code>.
+     * This method checks the persistence store if persistence is enabled,
+     * otherwise just uses the functionality from ManagerBase.
+     *
+     * @param id The session id for the session to be returned
+     *
+     * @exception IllegalStateException if a new session cannot be
+     *  instantiated for any reason
+     * @exception IOException if an input/output error occurs while
+     *  processing this request
+     */
+    public Session findSession(String id) throws IOException {
+
+        Session session = super.findSession(id);
+        if (session != null)
+            return (session);
+
+        // See if the Session is in the Store
+        session = swapIn(id);
+        return (session);
+
+    }
+
+    /**
+     * Remove this Session from the active Sessions for this Manager,
+     * but not from the Store. (Used by the PersistentValve)
+     *
+     * @param session Session to be removed
+     */
+    public void removeSuper(Session session) {
+        super.remove (session);
+    }
+
+    /**
+     * Load all sessions found in the persistence mechanism, assuming
+     * they are marked as valid and have not passed their expiration
+     * limit. If persistence is not supported, this method returns
+     * without doing anything.
+     * <p>
+     * Note that by default, this method is not called by the MiddleManager
+     * class. In order to use it, a subclass must specifically call it,
+     * for example in the start() and/or processPersistenceChecks() methods.
+     */
+    public void load() {
+
+        // Initialize our internal data structures
+        sessions.clear();
+
+        if (store == null)
+            return;
+
+        String[] ids = null;
+        try {
+            if (SecurityUtil.isPackageProtectionEnabled()){
+                try{
+                    ids = (String[])
+                        AccessController.doPrivileged(new PrivilegedStoreKeys());
+                }catch(PrivilegedActionException ex){
+                    Exception exception = ex.getException();
+                    log.error("Exception in the Store during load: "
+                              + exception);
+                    exception.printStackTrace();                        
+                }
+            } else {
+                ids = store.keys();
+            }
+        } catch (IOException e) {
+            log.error("Can't load sessions from store, " + e.getMessage(), e);
+            return;
+        }
+
+        int n = ids.length;
+        if (n == 0)
+            return;
+
+        if (log.isDebugEnabled())
+            log.debug(sm.getString("persistentManager.loading", String.valueOf(n)));
+
+        for (int i = 0; i < n; i++)
+            try {
+                swapIn(ids[i]);
+            } catch (IOException e) {
+                log.error("Failed load session from store, " + e.getMessage(), e);
+            }
+
+    }
+
+
+    /**
+     * Remove this Session from the active Sessions for this Manager,
+     * and from the Store.
+     *
+     * @param session Session to be removed
+     */
+    public void remove(Session session) {
+
+        super.remove (session);
+
+        if (store != null){
+            removeSession(session.getIdInternal());
+        }
+    }
+
+    
+    /**
+     * Remove this Session from the active Sessions for this Manager,
+     * and from the Store.
+     *
+     * @param id Session's id to be removed
+     */    
+    protected void removeSession(String id){
+        try {
+            if (SecurityUtil.isPackageProtectionEnabled()){
+                try{
+                    AccessController.doPrivileged(new PrivilegedStoreRemove(id));
+                }catch(PrivilegedActionException ex){
+                    Exception exception = ex.getException();
+                    log.error("Exception in the Store during removeSession: "
+                              + exception);
+                    exception.printStackTrace();                        
+                }
+            } else {
+                 store.remove(id);
+            }               
+        } catch (IOException e) {
+            log.error("Exception removing session  " + e.getMessage());
+            e.printStackTrace();
+        }        
+    }
+
+    /**
+     * Save all currently active sessions in the appropriate persistence
+     * mechanism, if any.  If persistence is not supported, this method
+     * returns without doing anything.
+     * <p>
+     * Note that by default, this method is not called by the MiddleManager
+     * class. In order to use it, a subclass must specifically call it,
+     * for example in the stop() and/or processPersistenceChecks() methods.
+     */
+    public void unload() {
+
+        if (store == null)
+            return;
+
+        Session sessions[] = findSessions();
+        int n = sessions.length;
+        if (n == 0)
+            return;
+
+        if (log.isDebugEnabled())
+            log.debug(sm.getString("persistentManager.unloading",
+                             String.valueOf(n)));
+
+        for (int i = 0; i < n; i++)
+            try {
+                swapOut(sessions[i]);
+            } catch (IOException e) {
+                ;   // This is logged in writeSession()
+            }
+
+    }
+
+
+    // ------------------------------------------------------ Protected Methods
+
+
+    /**
+     * Look for a session in the Store and, if found, restore
+     * it in the Manager's list of active sessions if appropriate.
+     * The session will be removed from the Store after swapping
+     * in, but will not be added to the active session list if it
+     * is invalid or past its expiration.
+     */
+    protected Session swapIn(String id) throws IOException {
+
+        if (store == null)
+            return null;
+
+        Session session = null;
+        try {
+            if (SecurityUtil.isPackageProtectionEnabled()){
+                try{
+                    session = (Session) 
+                      AccessController.doPrivileged(new PrivilegedStoreLoad(id));
+                }catch(PrivilegedActionException ex){
+                    Exception exception = ex.getException();
+                    log.error("Exception in the Store during swapIn: "
+                              + exception);
+                    if (exception instanceof IOException){
+                        throw (IOException)exception;
+                    } else if (exception instanceof ClassNotFoundException) {
+                        throw (ClassNotFoundException)exception;
+                    }
+                }
+            } else {
+                 session = store.load(id);
+            }   
+        } catch (ClassNotFoundException e) {
+            log.error(sm.getString("persistentManager.deserializeError", id, e));
+            throw new IllegalStateException
+                (sm.getString("persistentManager.deserializeError", id, e));
+        }
+
+        if (session == null)
+            return (null);
+
+        if (!session.isValid()) {
+            log.error("session swapped in is invalid or expired");
+            session.expire();
+            removeSession(id);
+            return (null);
+        }
+
+        if(log.isDebugEnabled())
+            log.debug(sm.getString("persistentManager.swapIn", id));
+
+        session.setManager(this);
+        // make sure the listeners know about it.
+        ((StandardSession)session).tellNew();
+        add(session);
+        ((StandardSession)session).activate();
+        session.endAccess();
+
+        return (session);
+
+    }
+
+
+    /**
+     * Remove the session from the Manager's list of active
+     * sessions and write it out to the Store. If the session
+     * is past its expiration or invalid, this method does
+     * nothing.
+     *
+     * @param session The Session to write out.
+     */
+    protected void swapOut(Session session) throws IOException {
+
+        if (store == null || !session.isValid()) {
+            return;
+        }
+
+        ((StandardSession)session).passivate();
+        writeSession(session);
+        super.remove(session);
+        session.recycle();
+
+    }
+
+
+    /**
+     * Write the provided session to the Store without modifying
+     * the copy in memory or triggering passivation events. Does
+     * nothing if the session is invalid or past its expiration.
+     */
+    protected void writeSession(Session session) throws IOException {
+
+        if (store == null || !session.isValid()) {
+            return;
+        }
+
+        try {
+            if (SecurityUtil.isPackageProtectionEnabled()){
+                try{
+                    AccessController.doPrivileged(new PrivilegedStoreSave(session));
+                }catch(PrivilegedActionException ex){
+                    Exception exception = ex.getException();
+                    log.error("Exception in the Store during writeSession: "
+                              + exception);
+                    exception.printStackTrace();                        
+                }
+            } else {
+                 store.save(session);
+            }   
+        } catch (IOException e) {
+            log.error(sm.getString
+                ("persistentManager.serializeError", session.getIdInternal(), e));
+            throw e;
+        }
+
+    }
+
+
+    // ------------------------------------------------------ Lifecycle Methods
+
+
+    /**
+     * Add a lifecycle event listener to this component.
+     *
+     * @param listener The listener to add
+     */
+    public void addLifecycleListener(LifecycleListener listener) {
+
+        lifecycle.addLifecycleListener(listener);
+
+    }
+
+
+    /**
+     * Get the lifecycle listeners associated with this lifecycle. If this 
+     * Lifecycle has no listeners registered, a zero-length array is returned.
+     */
+    public LifecycleListener[] findLifecycleListeners() {
+
+        return lifecycle.findLifecycleListeners();
+
+    }
+
+
+    /**
+     * Remove a lifecycle event listener from this component.
+     *
+     * @param listener The listener to remove
+     */
+    public void removeLifecycleListener(LifecycleListener listener) {
+
+        lifecycle.removeLifecycleListener(listener);
+
+    }
+
+
+    /**
+     * Prepare for the beginning of active use of the public methods of this
+     * component.  This method should be called after <code>configure()</code>,
+     * and before any of the public methods of the component are utilized.
+     *
+     * @exception LifecycleException if this component detects a fatal error
+     *  that prevents this component from being used
+     */
+    public void start() throws LifecycleException {
+
+        // Validate and update our current component state
+        if (started) {
+            log.info(sm.getString("standardManager.alreadyStarted"));
+            return;
+        }
+        if( ! initialized )
+            init();
+        
+        lifecycle.fireLifecycleEvent(START_EVENT, null);
+        started = true;
+
+        // Force initialization of the random number generator
+        if (log.isDebugEnabled())
+            log.debug("Force random number initialization starting");
+        String dummy = generateSessionId();
+        if (log.isDebugEnabled())
+            log.debug("Force random number initialization completed");
+
+        if (store == null)
+            log.error("No Store configured, persistence disabled");
+        else if (store instanceof Lifecycle)
+            ((Lifecycle)store).start();
+
+    }
+
+
+    /**
+     * Gracefully terminate the active use of the public methods of this
+     * component.  This method should be the last one called on a given
+     * instance of this component.
+     *
+     * @exception LifecycleException if this component detects a fatal error
+     *  that needs to be reported
+     */
+   public void stop() throws LifecycleException {
+
+        if (log.isDebugEnabled())
+            log.debug("Stopping");
+
+        // Validate and update our current component state
+        if (!isStarted()) {
+            log.info(sm.getString("standardManager.notStarted"));
+            return;
+        }
+        
+        lifecycle.fireLifecycleEvent(STOP_EVENT, null);
+        setStarted(false);
+
+        if (getStore() != null && saveOnRestart) {
+            unload();
+        } else {
+            // Expire all active sessions
+            Session sessions[] = findSessions();
+            for (int i = 0; i < sessions.length; i++) {
+                StandardSession session = (StandardSession) sessions[i];
+                if (!session.isValid())
+                    continue;
+                session.expire();
+            }
+        }
+
+        if (getStore() != null && getStore() instanceof Lifecycle)
+            ((Lifecycle)getStore()).stop();
+
+        // Require a new random number generator if we are restarted
+        this.random = null;
+
+        if( initialized )
+            destroy();
+
+    }
+
+
+    // ----------------------------------------- PropertyChangeListener Methods
+
+
+    /**
+     * Process property change events from our associated Context.
+     *
+     * @param event The property change event that has occurred
+     */
+    public void propertyChange(PropertyChangeEvent event) {
+
+        // Validate the source of this event
+        if (!(event.getSource() instanceof Context))
+            return;
+        Context context = (Context) event.getSource();
+
+        // Process a relevant property change
+        if (event.getPropertyName().equals("sessionTimeout")) {
+            try {
+                setMaxInactiveInterval
+                    ( ((Integer) event.getNewValue()).intValue()*60 );
+            } catch (NumberFormatException e) {
+                log.error(sm.getString("standardManager.sessionTimeout",
+                                 event.getNewValue().toString()));
+            }
+        }
+
+    }
+
+
+    // ------------------------------------------------------ Protected Methods
+
+
+    /**
+     * Swap idle sessions out to Store if they are idle too long.
+     */
+    protected void processMaxIdleSwaps() {
+
+        if (!isStarted() || maxIdleSwap < 0)
+            return;
+
+        Session sessions[] = findSessions();
+        long timeNow = System.currentTimeMillis();
+
+        // Swap out all sessions idle longer than maxIdleSwap
+        // FIXME: What's preventing us from mangling a session during
+        // a request?
+        if (maxIdleSwap >= 0) {
+            for (int i = 0; i < sessions.length; i++) {
+                StandardSession session = (StandardSession) sessions[i];
+                if (!session.isValid())
+                    continue;
+                int timeIdle = // Truncate, do not round up
+                    (int) ((timeNow - session.getLastAccessedTime()) / 1000L);
+                if (timeIdle > maxIdleSwap && timeIdle > minIdleSwap) {
+                    if (log.isDebugEnabled())
+                        log.debug(sm.getString
+                            ("persistentManager.swapMaxIdle",
+                             session.getIdInternal(), new Integer(timeIdle)));
+                    try {
+                        swapOut(session);
+                    } catch (IOException e) {
+                        ;   // This is logged in writeSession()
+                    }
+                }
+            }
+        }
+
+    }
+
+
+    /**
+     * Swap idle sessions out to Store if too many are active
+     */
+    protected void processMaxActiveSwaps() {
+
+        if (!isStarted() || getMaxActiveSessions() < 0)
+            return;
+
+        Session sessions[] = findSessions();
+
+        // FIXME: Smarter algorithm (LRU)
+        if (getMaxActiveSessions() >= sessions.length)
+            return;
+
+        if(log.isDebugEnabled())
+            log.debug(sm.getString
+                ("persistentManager.tooManyActive",
+                 new Integer(sessions.length)));
+
+        int toswap = sessions.length - getMaxActiveSessions();
+        long timeNow = System.currentTimeMillis();
+
+        for (int i = 0; i < sessions.length && toswap > 0; i++) {
+            int timeIdle = // Truncate, do not round up
+                (int) ((timeNow - sessions[i].getLastAccessedTime()) / 1000L);
+            if (timeIdle > minIdleSwap) {
+                if(log.isDebugEnabled())
+                    log.debug(sm.getString
+                        ("persistentManager.swapTooManyActive",
+                         sessions[i].getIdInternal(), new Integer(timeIdle)));
+                try {
+                    swapOut(sessions[i]);
+                } catch (IOException e) {
+                    ;   // This is logged in writeSession()
+                }
+                toswap--;
+            }
+        }
+
+    }
+
+
+    /**
+     * Back up idle sessions.
+     */
+    protected void processMaxIdleBackups() {
+
+        if (!isStarted() || maxIdleBackup < 0)
+            return;
+
+        Session sessions[] = findSessions();
+        long timeNow = System.currentTimeMillis();
+
+        // Back up all sessions idle longer than maxIdleBackup
+        if (maxIdleBackup >= 0) {
+            for (int i = 0; i < sessions.length; i++) {
+                StandardSession session = (StandardSession) sessions[i];
+                if (!session.isValid())
+                    continue;
+                int timeIdle = // Truncate, do not round up
+                    (int) ((timeNow - session.getLastAccessedTime()) / 1000L);
+                if (timeIdle > maxIdleBackup) {
+                    if (log.isDebugEnabled())
+                        log.debug(sm.getString
+                            ("persistentManager.backupMaxIdle",
+                            session.getIdInternal(), new Integer(timeIdle)));
+
+                    try {
+                        writeSession(session);
+                    } catch (IOException e) {
+                        ;   // This is logged in writeSession()
+                    }
+                }
+            }
+        }
+
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/session/StandardManager.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/session/StandardManager.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/session/StandardManager.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,753 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.session;
+
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.security.AccessController;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
+import java.util.ArrayList;
+import java.util.Iterator;
+import javax.servlet.ServletContext;
+import org.apache.catalina.Container;
+import org.apache.catalina.Context;
+import org.apache.catalina.Globals;
+import org.apache.catalina.Lifecycle;
+import org.apache.catalina.LifecycleException;
+import org.apache.catalina.LifecycleListener;
+import org.apache.catalina.Loader;
+import org.apache.catalina.Session;
+import org.apache.catalina.util.CustomObjectInputStream;
+import org.apache.catalina.util.LifecycleSupport;
+
+import org.apache.catalina.security.SecurityUtil;
+/**
+ * Standard implementation of the <b>Manager</b> interface that provides
+ * simple session persistence across restarts of this component (such as
+ * when the entire server is shut down and restarted, or when a particular
+ * web application is reloaded.
+ * <p>
+ * <b>IMPLEMENTATION NOTE</b>:  Correct behavior of session storing and
+ * reloading depends upon external calls to the <code>start()</code> and
+ * <code>stop()</code> methods of this class at the correct times.
+ *
+ * @author Craig R. McClanahan
+ * @author Jean-Francois Arcand
+ * @version $Revision: 387590 $ $Date: 2006-03-21 11:55:07 -0600 (Tue, 21 Mar 2006) $
+ */
+
+public class StandardManager
+    extends ManagerBase
+    implements Lifecycle, PropertyChangeListener {
+
+    // ---------------------------------------------------- Security Classes
+    private class PrivilegedDoLoad
+        implements PrivilegedExceptionAction {
+
+        PrivilegedDoLoad() {
+        }
+
+        public Object run() throws Exception{
+           doLoad();
+           return null;
+        }
+    }
+
+    private class PrivilegedDoUnload
+        implements PrivilegedExceptionAction {
+
+        PrivilegedDoUnload() {
+        }
+
+        public Object run() throws Exception{
+            doUnload();
+            return null;
+        }
+
+    }
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The descriptive information about this implementation.
+     */
+    protected static final String info = "StandardManager/1.0";
+
+
+    /**
+     * The lifecycle event support for this component.
+     */
+    protected LifecycleSupport lifecycle = new LifecycleSupport(this);
+
+
+    /**
+     * The maximum number of active Sessions allowed, or -1 for no limit.
+     */
+    protected int maxActiveSessions = -1;
+
+
+    /**
+     * The descriptive name of this Manager implementation (for logging).
+     */
+    protected static String name = "StandardManager";
+
+
+    /**
+     * Path name of the disk file in which active sessions are saved
+     * when we stop, and from which these sessions are loaded when we start.
+     * A <code>null</code> value indicates that no persistence is desired.
+     * If this pathname is relative, it will be resolved against the
+     * temporary working directory provided by our context, available via
+     * the <code>javax.servlet.context.tempdir</code> context attribute.
+     */
+    protected String pathname = "SESSIONS.ser";
+
+
+    /**
+     * Has this component been started yet?
+     */
+    protected boolean started = false;
+
+
+    /**
+     * Number of session creations that failed due to maxActiveSessions.
+     */
+    protected int rejectedSessions = 0;
+
+
+    /**
+     * Processing time during session expiration.
+     */
+    protected long processingTime = 0;
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * Set the Container with which this Manager has been associated.  If
+     * it is a Context (the usual case), listen for changes to the session
+     * timeout property.
+     *
+     * @param container The associated Container
+     */
+    public void setContainer(Container container) {
+
+        // De-register from the old Container (if any)
+        if ((this.container != null) && (this.container instanceof Context))
+            ((Context) this.container).removePropertyChangeListener(this);
+
+        // Default processing provided by our superclass
+        super.setContainer(container);
+
+        // Register with the new Container (if any)
+        if ((this.container != null) && (this.container instanceof Context)) {
+            setMaxInactiveInterval
+                ( ((Context) this.container).getSessionTimeout()*60 );
+            ((Context) this.container).addPropertyChangeListener(this);
+        }
+
+    }
+
+
+    /**
+     * Return descriptive information about this Manager implementation and
+     * the corresponding version number, in the format
+     * <code>&lt;description&gt;/&lt;version&gt;</code>.
+     */
+    public String getInfo() {
+
+        return (info);
+
+    }
+
+
+    /**
+     * Return the maximum number of active Sessions allowed, or -1 for
+     * no limit.
+     */
+    public int getMaxActiveSessions() {
+
+        return (this.maxActiveSessions);
+
+    }
+
+
+    /** Number of session creations that failed due to maxActiveSessions
+     *
+     * @return The count
+     */
+    public int getRejectedSessions() {
+        return rejectedSessions;
+    }
+
+
+    public void setRejectedSessions(int rejectedSessions) {
+        this.rejectedSessions = rejectedSessions;
+    }
+
+
+    /**
+     * Set the maximum number of actives Sessions allowed, or -1 for
+     * no limit.
+     *
+     * @param max The new maximum number of sessions
+     */
+    public void setMaxActiveSessions(int max) {
+
+        int oldMaxActiveSessions = this.maxActiveSessions;
+        this.maxActiveSessions = max;
+        support.firePropertyChange("maxActiveSessions",
+                                   new Integer(oldMaxActiveSessions),
+                                   new Integer(this.maxActiveSessions));
+
+    }
+
+
+    /**
+     * Return the descriptive short name of this Manager implementation.
+     */
+    public String getName() {
+
+        return (name);
+
+    }
+
+
+    /**
+     * Return the session persistence pathname, if any.
+     */
+    public String getPathname() {
+
+        return (this.pathname);
+
+    }
+
+
+    /**
+     * Set the session persistence pathname to the specified value.  If no
+     * persistence support is desired, set the pathname to <code>null</code>.
+     *
+     * @param pathname New session persistence pathname
+     */
+    public void setPathname(String pathname) {
+
+        String oldPathname = this.pathname;
+        this.pathname = pathname;
+        support.firePropertyChange("pathname", oldPathname, this.pathname);
+
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+    /**
+     * Construct and return a new session object, based on the default
+     * settings specified by this Manager's properties.  The session
+     * id will be assigned by this method, and available via the getId()
+     * method of the returned session.  If a new session cannot be created
+     * for any reason, return <code>null</code>.
+     *
+     * @exception IllegalStateException if a new session cannot be
+     *  instantiated for any reason
+     */
+    public Session createSession(String sessionId) {
+
+        if ((maxActiveSessions >= 0) &&
+            (sessions.size() >= maxActiveSessions)) {
+            rejectedSessions++;
+            throw new IllegalStateException
+                (sm.getString("standardManager.createSession.ise"));
+        }
+
+        return (super.createSession(sessionId));
+
+    }
+
+
+    /**
+     * Load any currently active sessions that were previously unloaded
+     * to the appropriate persistence mechanism, if any.  If persistence is not
+     * supported, this method returns without doing anything.
+     *
+     * @exception ClassNotFoundException if a serialized class cannot be
+     *  found during the reload
+     * @exception IOException if an input/output error occurs
+     */
+    public void load() throws ClassNotFoundException, IOException {
+        if (SecurityUtil.isPackageProtectionEnabled()){
+            try{
+                AccessController.doPrivileged( new PrivilegedDoLoad() );
+            } catch (PrivilegedActionException ex){
+                Exception exception = ex.getException();
+                if (exception instanceof ClassNotFoundException){
+                    throw (ClassNotFoundException)exception;
+                } else if (exception instanceof IOException){
+                    throw (IOException)exception;
+                }
+                if (log.isDebugEnabled())
+                    log.debug("Unreported exception in load() "
+                        + exception);
+            }
+        } else {
+            doLoad();
+        }
+    }
+
+
+    /**
+     * Load any currently active sessions that were previously unloaded
+     * to the appropriate persistence mechanism, if any.  If persistence is not
+     * supported, this method returns without doing anything.
+     *
+     * @exception ClassNotFoundException if a serialized class cannot be
+     *  found during the reload
+     * @exception IOException if an input/output error occurs
+     */
+    protected void doLoad() throws ClassNotFoundException, IOException {
+        if (log.isDebugEnabled())
+            log.debug("Start: Loading persisted sessions");
+
+        // Initialize our internal data structures
+        sessions.clear();
+
+        // Open an input stream to the specified pathname, if any
+        File file = file();
+        if (file == null)
+            return;
+        if (log.isDebugEnabled())
+            log.debug(sm.getString("standardManager.loading", pathname));
+        FileInputStream fis = null;
+        ObjectInputStream ois = null;
+        Loader loader = null;
+        ClassLoader classLoader = null;
+        try {
+            fis = new FileInputStream(file.getAbsolutePath());
+            BufferedInputStream bis = new BufferedInputStream(fis);
+            if (container != null)
+                loader = container.getLoader();
+            if (loader != null)
+                classLoader = loader.getClassLoader();
+            if (classLoader != null) {
+                if (log.isDebugEnabled())
+                    log.debug("Creating custom object input stream for class loader ");
+                ois = new CustomObjectInputStream(bis, classLoader);
+            } else {
+                if (log.isDebugEnabled())
+                    log.debug("Creating standard object input stream");
+                ois = new ObjectInputStream(bis);
+            }
+        } catch (FileNotFoundException e) {
+            if (log.isDebugEnabled())
+                log.debug("No persisted data file found");
+            return;
+        } catch (IOException e) {
+            log.error(sm.getString("standardManager.loading.ioe", e), e);
+            if (ois != null) {
+                try {
+                    ois.close();
+                } catch (IOException f) {
+                    ;
+                }
+                ois = null;
+            }
+            throw e;
+        }
+
+        // Load the previously unloaded active sessions
+        synchronized (sessions) {
+            try {
+                Integer count = (Integer) ois.readObject();
+                int n = count.intValue();
+                if (log.isDebugEnabled())
+                    log.debug("Loading " + n + " persisted sessions");
+                for (int i = 0; i < n; i++) {
+                    StandardSession session = getNewSession();
+                    session.readObjectData(ois);
+                    session.setManager(this);
+                    sessions.put(session.getIdInternal(), session);
+                    session.activate();
+                    session.endAccess();
+                }
+            } catch (ClassNotFoundException e) {
+              log.error(sm.getString("standardManager.loading.cnfe", e), e);
+                if (ois != null) {
+                    try {
+                        ois.close();
+                    } catch (IOException f) {
+                        ;
+                    }
+                    ois = null;
+                }
+                throw e;
+            } catch (IOException e) {
+              log.error(sm.getString("standardManager.loading.ioe", e), e);
+                if (ois != null) {
+                    try {
+                        ois.close();
+                    } catch (IOException f) {
+                        ;
+                    }
+                    ois = null;
+                }
+                throw e;
+            } finally {
+                // Close the input stream
+                try {
+                    if (ois != null)
+                        ois.close();
+                } catch (IOException f) {
+                    // ignored
+                }
+
+                // Delete the persistent storage file
+                if (file != null && file.exists() )
+                    file.delete();
+            }
+        }
+
+        if (log.isDebugEnabled())
+            log.debug("Finish: Loading persisted sessions");
+    }
+
+
+    /**
+     * Save any currently active sessions in the appropriate persistence
+     * mechanism, if any.  If persistence is not supported, this method
+     * returns without doing anything.
+     *
+     * @exception IOException if an input/output error occurs
+     */
+    public void unload() throws IOException {
+        if (SecurityUtil.isPackageProtectionEnabled()){
+            try{
+                AccessController.doPrivileged( new PrivilegedDoUnload() );
+            } catch (PrivilegedActionException ex){
+                Exception exception = ex.getException();
+                if (exception instanceof IOException){
+                    throw (IOException)exception;
+                }
+                if (log.isDebugEnabled())
+                    log.debug("Unreported exception in unLoad() "
+                        + exception);
+            }
+        } else {
+            doUnload();
+        }
+    }
+
+
+    /**
+     * Save any currently active sessions in the appropriate persistence
+     * mechanism, if any.  If persistence is not supported, this method
+     * returns without doing anything.
+     *
+     * @exception IOException if an input/output error occurs
+     */
+    protected void doUnload() throws IOException {
+
+        if (log.isDebugEnabled())
+            log.debug("Unloading persisted sessions");
+
+        // Open an output stream to the specified pathname, if any
+        File file = file();
+        if (file == null)
+            return;
+        if (log.isDebugEnabled())
+            log.debug(sm.getString("standardManager.unloading", pathname));
+        FileOutputStream fos = null;
+        ObjectOutputStream oos = null;
+        try {
+            fos = new FileOutputStream(file.getAbsolutePath());
+            oos = new ObjectOutputStream(new BufferedOutputStream(fos));
+        } catch (IOException e) {
+            log.error(sm.getString("standardManager.unloading.ioe", e), e);
+            if (oos != null) {
+                try {
+                    oos.close();
+                } catch (IOException f) {
+                    ;
+                }
+                oos = null;
+            }
+            throw e;
+        }
+
+        // Write the number of active sessions, followed by the details
+        ArrayList list = new ArrayList();
+        synchronized (sessions) {
+            if (log.isDebugEnabled())
+                log.debug("Unloading " + sessions.size() + " sessions");
+            try {
+                oos.writeObject(new Integer(sessions.size()));
+                Iterator elements = sessions.values().iterator();
+                while (elements.hasNext()) {
+                    StandardSession session =
+                        (StandardSession) elements.next();
+                    list.add(session);
+                    ((StandardSession) session).passivate();
+                    session.writeObjectData(oos);
+                }
+            } catch (IOException e) {
+                log.error(sm.getString("standardManager.unloading.ioe", e), e);
+                if (oos != null) {
+                    try {
+                        oos.close();
+                    } catch (IOException f) {
+                        ;
+                    }
+                    oos = null;
+                }
+                throw e;
+            }
+        }
+
+        // Flush and close the output stream
+        try {
+            oos.flush();
+            oos.close();
+            oos = null;
+        } catch (IOException e) {
+            if (oos != null) {
+                try {
+                    oos.close();
+                } catch (IOException f) {
+                    ;
+                }
+                oos = null;
+            }
+            throw e;
+        }
+
+        // Expire all the sessions we just wrote
+        if (log.isDebugEnabled())
+            log.debug("Expiring " + list.size() + " persisted sessions");
+        Iterator expires = list.iterator();
+        while (expires.hasNext()) {
+            StandardSession session = (StandardSession) expires.next();
+            try {
+                session.expire(false);
+            } catch (Throwable t) {
+                ;
+            } finally {
+                session.recycle();
+            }
+        }
+
+        if (log.isDebugEnabled())
+            log.debug("Unloading complete");
+
+    }
+
+
+    // ------------------------------------------------------ Lifecycle Methods
+
+
+    /**
+     * Add a lifecycle event listener to this component.
+     *
+     * @param listener The listener to add
+     */
+    public void addLifecycleListener(LifecycleListener listener) {
+
+        lifecycle.addLifecycleListener(listener);
+
+    }
+
+
+    /**
+     * Get the lifecycle listeners associated with this lifecycle. If this
+     * Lifecycle has no listeners registered, a zero-length array is returned.
+     */
+    public LifecycleListener[] findLifecycleListeners() {
+
+        return lifecycle.findLifecycleListeners();
+
+    }
+
+
+    /**
+     * Remove a lifecycle event listener from this component.
+     *
+     * @param listener The listener to remove
+     */
+    public void removeLifecycleListener(LifecycleListener listener) {
+
+        lifecycle.removeLifecycleListener(listener);
+
+    }
+
+    /**
+     * Prepare for the beginning of active use of the public methods of this
+     * component.  This method should be called after <code>configure()</code>,
+     * and before any of the public methods of the component are utilized.
+     *
+     * @exception LifecycleException if this component detects a fatal error
+     *  that prevents this component from being used
+     */
+    public void start() throws LifecycleException {
+
+        if( ! initialized )
+            init();
+
+        // Validate and update our current component state
+        if (started) {
+            return;
+        }
+        lifecycle.fireLifecycleEvent(START_EVENT, null);
+        started = true;
+
+        // Force initialization of the random number generator
+        if (log.isDebugEnabled())
+            log.debug("Force random number initialization starting");
+        String dummy = generateSessionId();
+        if (log.isDebugEnabled())
+            log.debug("Force random number initialization completed");
+
+        // Load unloaded sessions, if any
+        try {
+            load();
+        } catch (Throwable t) {
+            log.error(sm.getString("standardManager.managerLoad"), t);
+        }
+
+    }
+
+
+    /**
+     * Gracefully terminate the active use of the public methods of this
+     * component.  This method should be the last one called on a given
+     * instance of this component.
+     *
+     * @exception LifecycleException if this component detects a fatal error
+     *  that needs to be reported
+     */
+    public void stop() throws LifecycleException {
+
+        if (log.isDebugEnabled())
+            log.debug("Stopping");
+
+        // Validate and update our current component state
+        if (!started)
+            throw new LifecycleException
+                (sm.getString("standardManager.notStarted"));
+        lifecycle.fireLifecycleEvent(STOP_EVENT, null);
+        started = false;
+
+        // Write out sessions
+        try {
+            unload();
+        } catch (Throwable t) {
+            log.error(sm.getString("standardManager.managerUnload"), t);
+        }
+
+        // Expire all active sessions
+        Session sessions[] = findSessions();
+        for (int i = 0; i < sessions.length; i++) {
+            Session session = sessions[i];
+            try {
+                if (session.isValid()) {
+                    session.expire();
+                }
+            } catch (Throwable t) {
+                ;
+            } finally {
+                // Measure against memory leaking if references to the session
+                // object are kept in a shared field somewhere
+                session.recycle();
+            }
+        }
+
+        // Require a new random number generator if we are restarted
+        this.random = null;
+
+        if( initialized ) {
+            destroy();
+        }
+    }
+
+
+    // ----------------------------------------- PropertyChangeListener Methods
+
+
+    /**
+     * Process property change events from our associated Context.
+     *
+     * @param event The property change event that has occurred
+     */
+    public void propertyChange(PropertyChangeEvent event) {
+
+        // Validate the source of this event
+        if (!(event.getSource() instanceof Context))
+            return;
+        Context context = (Context) event.getSource();
+
+        // Process a relevant property change
+        if (event.getPropertyName().equals("sessionTimeout")) {
+            try {
+                setMaxInactiveInterval
+                    ( ((Integer) event.getNewValue()).intValue()*60 );
+            } catch (NumberFormatException e) {
+                log.error(sm.getString("standardManager.sessionTimeout",
+                                 event.getNewValue().toString()));
+            }
+        }
+
+    }
+
+
+    // ------------------------------------------------------ Protected Methods
+
+
+    /**
+     * Return a File object representing the pathname to our
+     * persistence file, if any.
+     */
+    protected File file() {
+
+        if ((pathname == null) || (pathname.length() == 0))
+            return (null);
+        File file = new File(pathname);
+        if (!file.isAbsolute()) {
+            if (container instanceof Context) {
+                ServletContext servletContext =
+                    ((Context) container).getServletContext();
+                File tempdir = (File)
+                    servletContext.getAttribute(Globals.WORK_DIR_ATTR);
+                if (tempdir != null)
+                    file = new File(tempdir, pathname);
+            }
+        }
+//        if (!file.isAbsolute())
+//            return (null);
+        return (file);
+
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/session/StandardSession.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/session/StandardSession.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/session/StandardSession.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,1711 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.session;
+
+
+import java.beans.PropertyChangeSupport;
+import java.io.IOException;
+import java.io.NotSerializableException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+import java.lang.reflect.Method;
+import java.security.AccessController;
+import java.security.Principal;
+import java.security.PrivilegedAction;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.Map;
+
+import javax.servlet.ServletContext;
+import javax.servlet.http.HttpSession;
+import javax.servlet.http.HttpSessionActivationListener;
+import javax.servlet.http.HttpSessionAttributeListener;
+import javax.servlet.http.HttpSessionBindingEvent;
+import javax.servlet.http.HttpSessionBindingListener;
+import javax.servlet.http.HttpSessionContext;
+import javax.servlet.http.HttpSessionEvent;
+import javax.servlet.http.HttpSessionListener;
+
+import org.apache.catalina.Context;
+import org.apache.catalina.Globals;
+import org.apache.catalina.Manager;
+import org.apache.catalina.Session;
+import org.apache.catalina.SessionEvent;
+import org.apache.catalina.SessionListener;
+import org.apache.catalina.util.Enumerator;
+import org.apache.catalina.util.StringManager;
+
+import org.apache.catalina.security.SecurityUtil;
+
+/**
+ * Standard implementation of the <b>Session</b> interface.  This object is
+ * serializable, so that it can be stored in persistent storage or transferred
+ * to a different JVM for distributable session support.
+ * <p>
+ * <b>IMPLEMENTATION NOTE</b>:  An instance of this class represents both the
+ * internal (Session) and application level (HttpSession) view of the session.
+ * However, because the class itself is not declared public, Java logic outside
+ * of the <code>org.apache.catalina.session</code> package cannot cast an
+ * HttpSession view of this instance back to a Session view.
+ * <p>
+ * <b>IMPLEMENTATION NOTE</b>:  If you add fields to this class, you must
+ * make sure that you carry them over in the read/writeObject methods so
+ * that this class is properly serialized.
+ *
+ * @author Craig R. McClanahan
+ * @author Sean Legassick
+ * @author <a href="mailto:jon at latchkey.com">Jon S. Stevens</a>
+ * @version $Revision: 405097 $ $Date: 2006-05-08 12:22:55 -0500 (Mon, 08 May 2006) $
+ */
+
+public class StandardSession
+    implements HttpSession, Session, Serializable {
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Construct a new Session associated with the specified Manager.
+     *
+     * @param manager The manager with which this Session is associated
+     */
+    public StandardSession(Manager manager) {
+
+        super();
+        this.manager = manager;
+
+    }
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * Type array.
+     */
+    protected static final String EMPTY_ARRAY[] = new String[0];
+
+
+    /**
+     * The dummy attribute value serialized when a NotSerializableException is
+     * encountered in <code>writeObject()</code>.
+     */
+    protected static final String NOT_SERIALIZED =
+        "___NOT_SERIALIZABLE_EXCEPTION___";
+
+
+    /**
+     * The collection of user data attributes associated with this Session.
+     */
+    protected Map attributes = new Hashtable();
+
+
+    /**
+     * The authentication type used to authenticate our cached Principal,
+     * if any.  NOTE:  This value is not included in the serialized
+     * version of this object.
+     */
+    protected transient String authType = null;
+
+
+    /**
+     * The <code>java.lang.Method</code> for the
+     * <code>fireContainerEvent()</code> method of the
+     * <code>org.apache.catalina.core.StandardContext</code> method,
+     * if our Context implementation is of this class.  This value is
+     * computed dynamically the first time it is needed, or after
+     * a session reload (since it is declared transient).
+     */
+    protected transient Method containerEventMethod = null;
+
+
+    /**
+     * The method signature for the <code>fireContainerEvent</code> method.
+     */
+    protected static final Class containerEventTypes[] =
+    { String.class, Object.class };
+
+
+    /**
+     * The time this session was created, in milliseconds since midnight,
+     * January 1, 1970 GMT.
+     */
+    protected long creationTime = 0L;
+
+
+    /**
+     * Set of attribute names which are not allowed to be persisted.
+     */
+    private static final String[] excludedAttributes = {
+        Globals.SUBJECT_ATTR
+    };
+
+
+    /**
+     * We are currently processing a session expiration, so bypass
+     * certain IllegalStateException tests.  NOTE:  This value is not
+     * included in the serialized version of this object.
+     */
+    protected transient boolean expiring = false;
+
+
+    /**
+     * The facade associated with this session.  NOTE:  This value is not
+     * included in the serialized version of this object.
+     */
+    protected transient StandardSessionFacade facade = null;
+
+
+    /**
+     * The session identifier of this Session.
+     */
+    protected String id = null;
+
+
+    /**
+     * Descriptive information describing this Session implementation.
+     */
+    protected static final String info = "StandardSession/1.0";
+
+
+    /**
+     * The last accessed time for this Session.
+     */
+    protected long lastAccessedTime = creationTime;
+
+
+    /**
+     * The session event listeners for this Session.
+     */
+    protected transient ArrayList listeners = new ArrayList();
+
+
+    /**
+     * The Manager with which this Session is associated.
+     */
+    protected transient Manager manager = null;
+
+
+    /**
+     * The maximum time interval, in seconds, between client requests before
+     * the servlet container may invalidate this session.  A negative time
+     * indicates that the session should never time out.
+     */
+    protected int maxInactiveInterval = -1;
+
+
+    /**
+     * Flag indicating whether this session is new or not.
+     */
+    protected boolean isNew = false;
+
+
+    /**
+     * Flag indicating whether this session is valid or not.
+     */
+    protected boolean isValid = false;
+
+    
+    /**
+     * Internal notes associated with this session by Catalina components
+     * and event listeners.  <b>IMPLEMENTATION NOTE:</b> This object is
+     * <em>not</em> saved and restored across session serializations!
+     */
+    protected transient Map notes = new Hashtable();
+
+
+    /**
+     * The authenticated Principal associated with this session, if any.
+     * <b>IMPLEMENTATION NOTE:</b>  This object is <i>not</i> saved and
+     * restored across session serializations!
+     */
+    protected transient Principal principal = null;
+
+
+    /**
+     * The string manager for this package.
+     */
+    protected static StringManager sm =
+        StringManager.getManager(Constants.Package);
+
+
+    /**
+     * The HTTP session context associated with this session.
+     */
+    protected static HttpSessionContext sessionContext = null;
+
+
+    /**
+     * The property change support for this component.  NOTE:  This value
+     * is not included in the serialized version of this object.
+     */
+    protected transient PropertyChangeSupport support =
+        new PropertyChangeSupport(this);
+
+
+    /**
+     * The current accessed time for this session.
+     */
+    protected long thisAccessedTime = creationTime;
+
+
+    /**
+     * The access count for this session.
+     */
+    protected transient int accessCount = 0;
+
+
+    // ----------------------------------------------------- Session Properties
+
+
+    /**
+     * Return the authentication type used to authenticate our cached
+     * Principal, if any.
+     */
+    public String getAuthType() {
+
+        return (this.authType);
+
+    }
+
+
+    /**
+     * Set the authentication type used to authenticate our cached
+     * Principal, if any.
+     *
+     * @param authType The new cached authentication type
+     */
+    public void setAuthType(String authType) {
+
+        String oldAuthType = this.authType;
+        this.authType = authType;
+        support.firePropertyChange("authType", oldAuthType, this.authType);
+
+    }
+
+
+    /**
+     * Set the creation time for this session.  This method is called by the
+     * Manager when an existing Session instance is reused.
+     *
+     * @param time The new creation time
+     */
+    public void setCreationTime(long time) {
+
+        this.creationTime = time;
+        this.lastAccessedTime = time;
+        this.thisAccessedTime = time;
+
+    }
+
+
+    /**
+     * Return the session identifier for this session.
+     */
+    public String getId() {
+
+        return (this.id);
+
+    }
+
+
+    /**
+     * Return the session identifier for this session.
+     */
+    public String getIdInternal() {
+
+        return (this.id);
+
+    }
+
+
+    /**
+     * Set the session identifier for this session.
+     *
+     * @param id The new session identifier
+     */
+    public void setId(String id) {
+
+        if ((this.id != null) && (manager != null))
+            manager.remove(this);
+
+        this.id = id;
+
+        if (manager != null)
+            manager.add(this);
+        tellNew();
+    }
+
+
+    /**
+     * Inform the listeners about the new session.
+     *
+     */
+    public void tellNew() {
+
+        // Notify interested session event listeners
+        fireSessionEvent(Session.SESSION_CREATED_EVENT, null);
+
+        // Notify interested application event listeners
+        Context context = (Context) manager.getContainer();
+        Object listeners[] = context.getApplicationLifecycleListeners();
+        if (listeners != null) {
+            HttpSessionEvent event =
+                new HttpSessionEvent(getSession());
+            for (int i = 0; i < listeners.length; i++) {
+                if (!(listeners[i] instanceof HttpSessionListener))
+                    continue;
+                HttpSessionListener listener =
+                    (HttpSessionListener) listeners[i];
+                try {
+                    fireContainerEvent(context,
+                                       "beforeSessionCreated",
+                                       listener);
+                    listener.sessionCreated(event);
+                    fireContainerEvent(context,
+                                       "afterSessionCreated",
+                                       listener);
+                } catch (Throwable t) {
+                    try {
+                        fireContainerEvent(context,
+                                           "afterSessionCreated",
+                                           listener);
+                    } catch (Exception e) {
+                        ;
+                    }
+                    manager.getContainer().getLogger().error
+                        (sm.getString("standardSession.sessionEvent"), t);
+                }
+            }
+        }
+
+    }
+
+
+    /**
+     * Return descriptive information about this Session implementation and
+     * the corresponding version number, in the format
+     * <code>&lt;description&gt;/&lt;version&gt;</code>.
+     */
+    public String getInfo() {
+
+        return (info);
+
+    }
+
+
+    /**
+     * Return the last time the client sent a request associated with this
+     * session, as the number of milliseconds since midnight, January 1, 1970
+     * GMT.  Actions that your application takes, such as getting or setting
+     * a value associated with the session, do not affect the access time.
+     */
+    public long getLastAccessedTime() {
+
+        if ( !isValid() ) {
+            throw new IllegalStateException
+            (sm.getString("standardSession.getLastAccessedTime.ise"));
+        }
+
+        return (this.lastAccessedTime);
+    }
+
+    /**
+     * Return the last client access time without invalidation check
+     * @see #getLastAccessedTime().
+     */
+    public long getLastAccessedTimeInternal() {
+        return (this.lastAccessedTime);
+    }
+
+    /**
+     * Return the Manager within which this Session is valid.
+     */
+    public Manager getManager() {
+
+        return (this.manager);
+
+    }
+
+
+    /**
+     * Set the Manager within which this Session is valid.
+     *
+     * @param manager The new Manager
+     */
+    public void setManager(Manager manager) {
+
+        this.manager = manager;
+
+    }
+
+
+    /**
+     * Return the maximum time interval, in seconds, between client requests
+     * before the servlet container will invalidate the session.  A negative
+     * time indicates that the session should never time out.
+     */
+    public int getMaxInactiveInterval() {
+
+        return (this.maxInactiveInterval);
+
+    }
+
+
+    /**
+     * Set the maximum time interval, in seconds, between client requests
+     * before the servlet container will invalidate the session.  A negative
+     * time indicates that the session should never time out.
+     *
+     * @param interval The new maximum interval
+     */
+    public void setMaxInactiveInterval(int interval) {
+
+        this.maxInactiveInterval = interval;
+        if (isValid && interval == 0) {
+            expire();
+        }
+
+    }
+
+
+    /**
+     * Set the <code>isNew</code> flag for this session.
+     *
+     * @param isNew The new value for the <code>isNew</code> flag
+     */
+    public void setNew(boolean isNew) {
+
+        this.isNew = isNew;
+
+    }
+
+
+    /**
+     * Return the authenticated Principal that is associated with this Session.
+     * This provides an <code>Authenticator</code> with a means to cache a
+     * previously authenticated Principal, and avoid potentially expensive
+     * <code>Realm.authenticate()</code> calls on every request.  If there
+     * is no current associated Principal, return <code>null</code>.
+     */
+    public Principal getPrincipal() {
+
+        return (this.principal);
+
+    }
+
+
+    /**
+     * Set the authenticated Principal that is associated with this Session.
+     * This provides an <code>Authenticator</code> with a means to cache a
+     * previously authenticated Principal, and avoid potentially expensive
+     * <code>Realm.authenticate()</code> calls on every request.
+     *
+     * @param principal The new Principal, or <code>null</code> if none
+     */
+    public void setPrincipal(Principal principal) {
+
+        Principal oldPrincipal = this.principal;
+        this.principal = principal;
+        support.firePropertyChange("principal", oldPrincipal, this.principal);
+
+    }
+
+
+    /**
+     * Return the <code>HttpSession</code> for which this object
+     * is the facade.
+     */
+    public HttpSession getSession() {
+
+        if (facade == null){
+            if (SecurityUtil.isPackageProtectionEnabled()){
+                final StandardSession fsession = this;
+                facade = (StandardSessionFacade)AccessController.doPrivileged(new PrivilegedAction(){
+                    public Object run(){
+                        return new StandardSessionFacade(fsession);
+                    }
+                });
+            } else {
+                facade = new StandardSessionFacade(this);
+            }
+        }
+        return (facade);
+
+    }
+
+
+    /**
+     * Return the <code>isValid</code> flag for this session.
+     */
+    public boolean isValid() {
+
+        if (this.expiring) {
+            return true;
+        }
+
+        if (!this.isValid ) {
+            return false;
+        }
+
+        if (accessCount > 0) {
+            return true;
+        }
+
+        if (maxInactiveInterval >= 0) { 
+            long timeNow = System.currentTimeMillis();
+            int timeIdle = (int) ((timeNow - thisAccessedTime) / 1000L);
+            if (timeIdle >= maxInactiveInterval) {
+                expire(true);
+            }
+        }
+
+        return (this.isValid);
+    }
+
+
+    /**
+     * Set the <code>isValid</code> flag for this session.
+     *
+     * @param isValid The new value for the <code>isValid</code> flag
+     */
+    public void setValid(boolean isValid) {
+
+        this.isValid = isValid;
+    }
+
+
+    // ------------------------------------------------- Session Public Methods
+
+
+    /**
+     * Update the accessed time information for this session.  This method
+     * should be called by the context when a request comes in for a particular
+     * session, even if the application does not reference it.
+     */
+    public void access() {
+
+        this.lastAccessedTime = this.thisAccessedTime;
+        this.thisAccessedTime = System.currentTimeMillis();
+
+        evaluateIfValid();
+
+        accessCount++;
+
+    }
+
+
+    /**
+     * End the access.
+     */
+    public void endAccess() {
+
+        isNew = false;
+        accessCount--;
+
+    }
+
+
+    /**
+     * Add a session event listener to this component.
+     */
+    public void addSessionListener(SessionListener listener) {
+
+        listeners.add(listener);
+
+    }
+
+
+    /**
+     * Perform the internal processing required to invalidate this session,
+     * without triggering an exception if the session has already expired.
+     */
+    public void expire() {
+
+        expire(true);
+
+    }
+
+
+    /**
+     * Perform the internal processing required to invalidate this session,
+     * without triggering an exception if the session has already expired.
+     *
+     * @param notify Should we notify listeners about the demise of
+     *  this session?
+     */
+    public void expire(boolean notify) {
+
+        // Mark this session as "being expired" if needed
+        if (expiring)
+            return;
+
+        synchronized (this) {
+
+            if (manager == null)
+                return;
+
+            expiring = true;
+        
+            // Notify interested application event listeners
+            // FIXME - Assumes we call listeners in reverse order
+            Context context = (Context) manager.getContainer();
+            Object listeners[] = context.getApplicationLifecycleListeners();
+            if (notify && (listeners != null)) {
+                HttpSessionEvent event =
+                    new HttpSessionEvent(getSession());
+                for (int i = 0; i < listeners.length; i++) {
+                    int j = (listeners.length - 1) - i;
+                    if (!(listeners[j] instanceof HttpSessionListener))
+                        continue;
+                    HttpSessionListener listener =
+                        (HttpSessionListener) listeners[j];
+                    try {
+                        fireContainerEvent(context,
+                                           "beforeSessionDestroyed",
+                                           listener);
+                        listener.sessionDestroyed(event);
+                        fireContainerEvent(context,
+                                           "afterSessionDestroyed",
+                                           listener);
+                    } catch (Throwable t) {
+                        try {
+                            fireContainerEvent(context,
+                                               "afterSessionDestroyed",
+                                               listener);
+                        } catch (Exception e) {
+                            ;
+                        }
+                        manager.getContainer().getLogger().error
+                            (sm.getString("standardSession.sessionEvent"), t);
+                    }
+                }
+            }
+            accessCount = 0;
+            setValid(false);
+
+            /*
+             * Compute how long this session has been alive, and update
+             * session manager's related properties accordingly
+             */
+            long timeNow = System.currentTimeMillis();
+            int timeAlive = (int) ((timeNow - creationTime)/1000);
+            synchronized (manager) {
+                if (timeAlive > manager.getSessionMaxAliveTime()) {
+                    manager.setSessionMaxAliveTime(timeAlive);
+                }
+                int numExpired = manager.getExpiredSessions();
+                numExpired++;
+                manager.setExpiredSessions(numExpired);
+                int average = manager.getSessionAverageAliveTime();
+                average = ((average * (numExpired-1)) + timeAlive)/numExpired;
+                manager.setSessionAverageAliveTime(average);
+            }
+
+            // Remove this session from our manager's active sessions
+            manager.remove(this);
+
+            // Notify interested session event listeners
+            if (notify) {
+                fireSessionEvent(Session.SESSION_DESTROYED_EVENT, null);
+            }
+
+            // We have completed expire of this session
+            expiring = false;
+
+            // Unbind any objects associated with this session
+            String keys[] = keys();
+            for (int i = 0; i < keys.length; i++)
+                removeAttributeInternal(keys[i], notify);
+
+        }
+
+    }
+
+
+    /**
+     * Perform the internal processing required to passivate
+     * this session.
+     */
+    public void passivate() {
+
+        // Notify interested session event listeners
+        fireSessionEvent(Session.SESSION_PASSIVATED_EVENT, null);
+
+        // Notify ActivationListeners
+        HttpSessionEvent event = null;
+        String keys[] = keys();
+        for (int i = 0; i < keys.length; i++) {
+            Object attribute = attributes.get(keys[i]);
+            if (attribute instanceof HttpSessionActivationListener) {
+                if (event == null)
+                    event = new HttpSessionEvent(getSession());
+                try {
+                    ((HttpSessionActivationListener)attribute)
+                        .sessionWillPassivate(event);
+                } catch (Throwable t) {
+                    manager.getContainer().getLogger().error
+                        (sm.getString("standardSession.attributeEvent"), t);
+                }
+            }
+        }
+
+    }
+
+
+    /**
+     * Perform internal processing required to activate this
+     * session.
+     */
+    public void activate() {
+
+        // Notify interested session event listeners
+        fireSessionEvent(Session.SESSION_ACTIVATED_EVENT, null);
+
+        // Notify ActivationListeners
+        HttpSessionEvent event = null;
+        String keys[] = keys();
+        for (int i = 0; i < keys.length; i++) {
+            Object attribute = attributes.get(keys[i]);
+            if (attribute instanceof HttpSessionActivationListener) {
+                if (event == null)
+                    event = new HttpSessionEvent(getSession());
+                try {
+                    ((HttpSessionActivationListener)attribute)
+                        .sessionDidActivate(event);
+                } catch (Throwable t) {
+                    manager.getContainer().getLogger().error
+                        (sm.getString("standardSession.attributeEvent"), t);
+                }
+            }
+        }
+
+    }
+
+
+    /**
+     * Return the object bound with the specified name to the internal notes
+     * for this session, or <code>null</code> if no such binding exists.
+     *
+     * @param name Name of the note to be returned
+     */
+    public Object getNote(String name) {
+
+        return (notes.get(name));
+
+    }
+
+
+    /**
+     * Return an Iterator containing the String names of all notes bindings
+     * that exist for this session.
+     */
+    public Iterator getNoteNames() {
+
+        return (notes.keySet().iterator());
+
+    }
+
+
+    /**
+     * Release all object references, and initialize instance variables, in
+     * preparation for reuse of this object.
+     */
+    public void recycle() {
+
+        // Reset the instance variables associated with this Session
+        attributes.clear();
+        setAuthType(null);
+        creationTime = 0L;
+        expiring = false;
+        id = null;
+        lastAccessedTime = 0L;
+        maxInactiveInterval = -1;
+        accessCount = 0;
+        notes.clear();
+        setPrincipal(null);
+        isNew = false;
+        isValid = false;
+        manager = null;
+
+    }
+
+
+    /**
+     * Remove any object bound to the specified name in the internal notes
+     * for this session.
+     *
+     * @param name Name of the note to be removed
+     */
+    public void removeNote(String name) {
+
+        notes.remove(name);
+
+    }
+
+
+    /**
+     * Remove a session event listener from this component.
+     */
+    public void removeSessionListener(SessionListener listener) {
+
+        listeners.remove(listener);
+
+    }
+
+
+    /**
+     * Bind an object to a specified name in the internal notes associated
+     * with this session, replacing any existing binding for this name.
+     *
+     * @param name Name to which the object should be bound
+     * @param value Object to be bound to the specified name
+     */
+    public void setNote(String name, Object value) {
+
+        notes.put(name, value);
+
+    }
+
+
+    /**
+     * Return a string representation of this object.
+     */
+    public String toString() {
+
+        StringBuffer sb = new StringBuffer();
+        sb.append("StandardSession[");
+        sb.append(id);
+        sb.append("]");
+        return (sb.toString());
+
+    }
+
+
+    // ------------------------------------------------ Session Package Methods
+
+
+    /**
+     * Read a serialized version of the contents of this session object from
+     * the specified object input stream, without requiring that the
+     * StandardSession itself have been serialized.
+     *
+     * @param stream The object input stream to read from
+     *
+     * @exception ClassNotFoundException if an unknown class is specified
+     * @exception IOException if an input/output error occurs
+     */
+    public void readObjectData(ObjectInputStream stream)
+        throws ClassNotFoundException, IOException {
+
+        readObject(stream);
+
+    }
+
+
+    /**
+     * Write a serialized version of the contents of this session object to
+     * the specified object output stream, without requiring that the
+     * StandardSession itself have been serialized.
+     *
+     * @param stream The object output stream to write to
+     *
+     * @exception IOException if an input/output error occurs
+     */
+    public void writeObjectData(ObjectOutputStream stream)
+        throws IOException {
+
+        writeObject(stream);
+
+    }
+
+
+    // ------------------------------------------------- HttpSession Properties
+
+
+    /**
+     * Return the time when this session was created, in milliseconds since
+     * midnight, January 1, 1970 GMT.
+     *
+     * @exception IllegalStateException if this method is called on an
+     *  invalidated session
+     */
+    public long getCreationTime() {
+
+        if (!isValid())
+            throw new IllegalStateException
+                (sm.getString("standardSession.getCreationTime.ise"));
+
+        return (this.creationTime);
+
+    }
+
+
+    /**
+     * Return the ServletContext to which this session belongs.
+     */
+    public ServletContext getServletContext() {
+
+        if (manager == null)
+            return (null);
+        Context context = (Context) manager.getContainer();
+        if (context == null)
+            return (null);
+        else
+            return (context.getServletContext());
+
+    }
+
+
+    /**
+     * Return the session context with which this session is associated.
+     *
+     * @deprecated As of Version 2.1, this method is deprecated and has no
+     *  replacement.  It will be removed in a future version of the
+     *  Java Servlet API.
+     */
+    public HttpSessionContext getSessionContext() {
+
+        if (sessionContext == null)
+            sessionContext = new StandardSessionContext();
+        return (sessionContext);
+
+    }
+
+
+    // ----------------------------------------------HttpSession Public Methods
+
+
+    /**
+     * Return the object bound with the specified name in this session, or
+     * <code>null</code> if no object is bound with that name.
+     *
+     * @param name Name of the attribute to be returned
+     *
+     * @exception IllegalStateException if this method is called on an
+     *  invalidated session
+     */
+    public Object getAttribute(String name) {
+
+        if (!isValid())
+            throw new IllegalStateException
+                (sm.getString("standardSession.getAttribute.ise"));
+
+        return (attributes.get(name));
+
+    }
+
+
+    /**
+     * Return an <code>Enumeration</code> of <code>String</code> objects
+     * containing the names of the objects bound to this session.
+     *
+     * @exception IllegalStateException if this method is called on an
+     *  invalidated session
+     */
+    public Enumeration getAttributeNames() {
+
+        if (!isValid())
+            throw new IllegalStateException
+                (sm.getString("standardSession.getAttributeNames.ise"));
+
+        return (new Enumerator(attributes.keySet(), true));
+
+    }
+
+
+    /**
+     * Return the object bound with the specified name in this session, or
+     * <code>null</code> if no object is bound with that name.
+     *
+     * @param name Name of the value to be returned
+     *
+     * @exception IllegalStateException if this method is called on an
+     *  invalidated session
+     *
+     * @deprecated As of Version 2.2, this method is replaced by
+     *  <code>getAttribute()</code>
+     */
+    public Object getValue(String name) {
+
+        return (getAttribute(name));
+
+    }
+
+
+    /**
+     * Return the set of names of objects bound to this session.  If there
+     * are no such objects, a zero-length array is returned.
+     *
+     * @exception IllegalStateException if this method is called on an
+     *  invalidated session
+     *
+     * @deprecated As of Version 2.2, this method is replaced by
+     *  <code>getAttributeNames()</code>
+     */
+    public String[] getValueNames() {
+
+        if (!isValid())
+            throw new IllegalStateException
+                (sm.getString("standardSession.getValueNames.ise"));
+
+        return (keys());
+
+    }
+
+
+    /**
+     * Invalidates this session and unbinds any objects bound to it.
+     *
+     * @exception IllegalStateException if this method is called on
+     *  an invalidated session
+     */
+    public void invalidate() {
+
+        if (!isValid())
+            throw new IllegalStateException
+                (sm.getString("standardSession.invalidate.ise"));
+
+        // Cause this session to expire
+        expire();
+
+    }
+
+
+    /**
+     * Return <code>true</code> if the client does not yet know about the
+     * session, or if the client chooses not to join the session.  For
+     * example, if the server used only cookie-based sessions, and the client
+     * has disabled the use of cookies, then a session would be new on each
+     * request.
+     *
+     * @exception IllegalStateException if this method is called on an
+     *  invalidated session
+     */
+    public boolean isNew() {
+
+        if (!isValid())
+            throw new IllegalStateException
+                (sm.getString("standardSession.isNew.ise"));
+
+        return (this.isNew);
+
+    }
+
+
+
+    /**
+     * Bind an object to this session, using the specified name.  If an object
+     * of the same name is already bound to this session, the object is
+     * replaced.
+     * <p>
+     * After this method executes, and if the object implements
+     * <code>HttpSessionBindingListener</code>, the container calls
+     * <code>valueBound()</code> on the object.
+     *
+     * @param name Name to which the object is bound, cannot be null
+     * @param value Object to be bound, cannot be null
+     *
+     * @exception IllegalStateException if this method is called on an
+     *  invalidated session
+     *
+     * @deprecated As of Version 2.2, this method is replaced by
+     *  <code>setAttribute()</code>
+     */
+    public void putValue(String name, Object value) {
+
+        setAttribute(name, value);
+
+    }
+
+
+    /**
+     * Remove the object bound with the specified name from this session.  If
+     * the session does not have an object bound with this name, this method
+     * does nothing.
+     * <p>
+     * After this method executes, and if the object implements
+     * <code>HttpSessionBindingListener</code>, the container calls
+     * <code>valueUnbound()</code> on the object.
+     *
+     * @param name Name of the object to remove from this session.
+     *
+     * @exception IllegalStateException if this method is called on an
+     *  invalidated session
+     */
+    public void removeAttribute(String name) {
+
+        removeAttribute(name, true);
+
+    }
+
+
+    /**
+     * Remove the object bound with the specified name from this session.  If
+     * the session does not have an object bound with this name, this method
+     * does nothing.
+     * <p>
+     * After this method executes, and if the object implements
+     * <code>HttpSessionBindingListener</code>, the container calls
+     * <code>valueUnbound()</code> on the object.
+     *
+     * @param name Name of the object to remove from this session.
+     * @param notify Should we notify interested listeners that this
+     *  attribute is being removed?
+     *
+     * @exception IllegalStateException if this method is called on an
+     *  invalidated session
+     */
+    public void removeAttribute(String name, boolean notify) {
+
+        // Validate our current state
+        if (!isValid())
+            throw new IllegalStateException
+                (sm.getString("standardSession.removeAttribute.ise"));
+
+        removeAttributeInternal(name, notify);
+
+    }
+
+
+    /**
+     * Remove the object bound with the specified name from this session.  If
+     * the session does not have an object bound with this name, this method
+     * does nothing.
+     * <p>
+     * After this method executes, and if the object implements
+     * <code>HttpSessionBindingListener</code>, the container calls
+     * <code>valueUnbound()</code> on the object.
+     *
+     * @param name Name of the object to remove from this session.
+     *
+     * @exception IllegalStateException if this method is called on an
+     *  invalidated session
+     *
+     * @deprecated As of Version 2.2, this method is replaced by
+     *  <code>removeAttribute()</code>
+     */
+    public void removeValue(String name) {
+
+        removeAttribute(name);
+
+    }
+
+
+    /**
+     * Bind an object to this session, using the specified name.  If an object
+     * of the same name is already bound to this session, the object is
+     * replaced.
+     * <p>
+     * After this method executes, and if the object implements
+     * <code>HttpSessionBindingListener</code>, the container calls
+     * <code>valueBound()</code> on the object.
+     *
+     * @param name Name to which the object is bound, cannot be null
+     * @param value Object to be bound, cannot be null
+     *
+     * @exception IllegalArgumentException if an attempt is made to add a
+     *  non-serializable object in an environment marked distributable.
+     * @exception IllegalStateException if this method is called on an
+     *  invalidated session
+     */
+    public void setAttribute(String name, Object value) {
+        setAttribute(name,value,true);
+    }
+
+    public void setAttribute(String name, Object value, boolean notify) {
+
+        // Name cannot be null
+        if (name == null)
+            throw new IllegalArgumentException
+                (sm.getString("standardSession.setAttribute.namenull"));
+
+        // Null value is the same as removeAttribute()
+        if (value == null) {
+            removeAttribute(name);
+            return;
+        }
+
+        // Validate our current state
+        if (!isValid())
+            throw new IllegalStateException
+                (sm.getString("standardSession.setAttribute.ise"));
+        if ((manager != null) && manager.getDistributable() &&
+          !(value instanceof Serializable))
+            throw new IllegalArgumentException
+                (sm.getString("standardSession.setAttribute.iae"));
+
+        // Construct an event with the new value
+        HttpSessionBindingEvent event = null;
+
+        // Call the valueBound() method if necessary
+        if (value instanceof HttpSessionBindingListener && notify) {
+            // Don't call any notification if replacing with the same value
+            Object oldValue = attributes.get(name);
+            if (value != oldValue) {
+                event = new HttpSessionBindingEvent(getSession(), name, value);
+                try {
+                    ((HttpSessionBindingListener) value).valueBound(event);
+                } catch (Throwable t){
+                    manager.getContainer().getLogger().error
+                    (sm.getString("standardSession.bindingEvent"), t); 
+                }
+            }
+        }
+
+        // Replace or add this attribute
+        Object unbound = attributes.put(name, value);
+
+        // Call the valueUnbound() method if necessary
+        if ((unbound != null) && (unbound != value) &&
+            (unbound instanceof HttpSessionBindingListener)  && notify) {
+            try {
+                ((HttpSessionBindingListener) unbound).valueUnbound
+                    (new HttpSessionBindingEvent(getSession(), name));
+            } catch (Throwable t) {
+                manager.getContainer().getLogger().error
+                    (sm.getString("standardSession.bindingEvent"), t);
+            }
+        }
+        
+        if ( !notify ) return;
+
+        // Notify interested application event listeners
+        Context context = (Context) manager.getContainer();
+        Object listeners[] = context.getApplicationEventListeners();
+        if (listeners == null)
+            return;
+        for (int i = 0; i < listeners.length; i++) {
+            if (!(listeners[i] instanceof HttpSessionAttributeListener))
+                continue;
+            HttpSessionAttributeListener listener =
+                (HttpSessionAttributeListener) listeners[i];
+            try {
+                if (unbound != null) {
+                    fireContainerEvent(context,
+                                       "beforeSessionAttributeReplaced",
+                                       listener);
+                    if (event == null) {
+                        event = new HttpSessionBindingEvent
+                            (getSession(), name, unbound);
+                    }
+                    listener.attributeReplaced(event);
+                    fireContainerEvent(context,
+                                       "afterSessionAttributeReplaced",
+                                       listener);
+                } else {
+                    fireContainerEvent(context,
+                                       "beforeSessionAttributeAdded",
+                                       listener);
+                    if (event == null) {
+                        event = new HttpSessionBindingEvent
+                            (getSession(), name, value);
+                    }
+                    listener.attributeAdded(event);
+                    fireContainerEvent(context,
+                                       "afterSessionAttributeAdded",
+                                       listener);
+                }
+            } catch (Throwable t) {
+                try {
+                    if (unbound != null) {
+                        fireContainerEvent(context,
+                                           "afterSessionAttributeReplaced",
+                                           listener);
+                    } else {
+                        fireContainerEvent(context,
+                                           "afterSessionAttributeAdded",
+                                           listener);
+                    }
+                } catch (Exception e) {
+                    ;
+                }
+                manager.getContainer().getLogger().error
+                    (sm.getString("standardSession.attributeEvent"), t);
+            }
+        }
+
+    }
+
+
+    // ------------------------------------------ HttpSession Protected Methods
+
+
+    /**
+     * Read a serialized version of this session object from the specified
+     * object input stream.
+     * <p>
+     * <b>IMPLEMENTATION NOTE</b>:  The reference to the owning Manager
+     * is not restored by this method, and must be set explicitly.
+     *
+     * @param stream The input stream to read from
+     *
+     * @exception ClassNotFoundException if an unknown class is specified
+     * @exception IOException if an input/output error occurs
+     */
+    private void readObject(ObjectInputStream stream)
+        throws ClassNotFoundException, IOException {
+
+        // Deserialize the scalar instance variables (except Manager)
+        authType = null;        // Transient only
+        creationTime = ((Long) stream.readObject()).longValue();
+        lastAccessedTime = ((Long) stream.readObject()).longValue();
+        maxInactiveInterval = ((Integer) stream.readObject()).intValue();
+        isNew = ((Boolean) stream.readObject()).booleanValue();
+        isValid = ((Boolean) stream.readObject()).booleanValue();
+        thisAccessedTime = ((Long) stream.readObject()).longValue();
+        principal = null;        // Transient only
+        //        setId((String) stream.readObject());
+        id = (String) stream.readObject();
+        if (manager.getContainer().getLogger().isDebugEnabled())
+            manager.getContainer().getLogger().debug
+                ("readObject() loading session " + id);
+
+        // Deserialize the attribute count and attribute values
+        if (attributes == null)
+            attributes = new Hashtable();
+        int n = ((Integer) stream.readObject()).intValue();
+        boolean isValidSave = isValid;
+        isValid = true;
+        for (int i = 0; i < n; i++) {
+            String name = (String) stream.readObject();
+            Object value = (Object) stream.readObject();
+            if ((value instanceof String) && (value.equals(NOT_SERIALIZED)))
+                continue;
+            if (manager.getContainer().getLogger().isDebugEnabled())
+                manager.getContainer().getLogger().debug("  loading attribute '" + name +
+                    "' with value '" + value + "'");
+            attributes.put(name, value);
+        }
+        isValid = isValidSave;
+
+        if (listeners == null) {
+            listeners = new ArrayList();
+        }
+
+        if (notes == null) {
+            notes = new Hashtable();
+        }
+    }
+
+
+    /**
+     * Write a serialized version of this session object to the specified
+     * object output stream.
+     * <p>
+     * <b>IMPLEMENTATION NOTE</b>:  The owning Manager will not be stored
+     * in the serialized representation of this Session.  After calling
+     * <code>readObject()</code>, you must set the associated Manager
+     * explicitly.
+     * <p>
+     * <b>IMPLEMENTATION NOTE</b>:  Any attribute that is not Serializable
+     * will be unbound from the session, with appropriate actions if it
+     * implements HttpSessionBindingListener.  If you do not want any such
+     * attributes, be sure the <code>distributable</code> property of the
+     * associated Manager is set to <code>true</code>.
+     *
+     * @param stream The output stream to write to
+     *
+     * @exception IOException if an input/output error occurs
+     */
+    private void writeObject(ObjectOutputStream stream) throws IOException {
+
+        // Write the scalar instance variables (except Manager)
+        stream.writeObject(new Long(creationTime));
+        stream.writeObject(new Long(lastAccessedTime));
+        stream.writeObject(new Integer(maxInactiveInterval));
+        stream.writeObject(new Boolean(isNew));
+        stream.writeObject(new Boolean(isValid));
+        stream.writeObject(new Long(thisAccessedTime));
+        stream.writeObject(id);
+        if (manager.getContainer().getLogger().isDebugEnabled())
+            manager.getContainer().getLogger().debug
+                ("writeObject() storing session " + id);
+
+        // Accumulate the names of serializable and non-serializable attributes
+        String keys[] = keys();
+        ArrayList saveNames = new ArrayList();
+        ArrayList saveValues = new ArrayList();
+        for (int i = 0; i < keys.length; i++) {
+            Object value = attributes.get(keys[i]);
+            if (value == null)
+                continue;
+            else if ( (value instanceof Serializable) 
+                    && (!exclude(keys[i]) )) {
+                saveNames.add(keys[i]);
+                saveValues.add(value);
+            } else {
+                removeAttributeInternal(keys[i], true);
+            }
+        }
+
+        // Serialize the attribute count and the Serializable attributes
+        int n = saveNames.size();
+        stream.writeObject(new Integer(n));
+        for (int i = 0; i < n; i++) {
+            stream.writeObject((String) saveNames.get(i));
+            try {
+                stream.writeObject(saveValues.get(i));
+                if (manager.getContainer().getLogger().isDebugEnabled())
+                    manager.getContainer().getLogger().debug
+                        ("  storing attribute '" + saveNames.get(i) +
+                        "' with value '" + saveValues.get(i) + "'");
+            } catch (NotSerializableException e) {
+                manager.getContainer().getLogger().warn
+                    (sm.getString("standardSession.notSerializable",
+                     saveNames.get(i), id), e);
+                stream.writeObject(NOT_SERIALIZED);
+                if (manager.getContainer().getLogger().isDebugEnabled())
+                    manager.getContainer().getLogger().debug
+                       ("  storing attribute '" + saveNames.get(i) +
+                        "' with value NOT_SERIALIZED");
+            }
+        }
+
+    }
+
+
+    /**
+     * Exclude attribute that cannot be serialized.
+     * @param name the attribute's name
+     */
+    protected boolean exclude(String name){
+
+        for (int i = 0; i < excludedAttributes.length; i++) {
+            if (name.equalsIgnoreCase(excludedAttributes[i]))
+                return true;
+        }
+
+        return false;
+    }
+
+
+    protected void evaluateIfValid() {
+        /*
+     * If this session has expired or is in the process of expiring or
+     * will never expire, return
+     */
+        if (!this.isValid || expiring || maxInactiveInterval < 0)
+            return;
+
+        isValid();
+
+    }
+
+
+    // ------------------------------------------------------ Protected Methods
+
+
+    /**
+     * Fire container events if the Context implementation is the
+     * <code>org.apache.catalina.core.StandardContext</code>.
+     *
+     * @param context Context for which to fire events
+     * @param type Event type
+     * @param data Event data
+     *
+     * @exception Exception occurred during event firing
+     */
+    protected void fireContainerEvent(Context context,
+                                    String type, Object data)
+        throws Exception {
+
+        if (!"org.apache.catalina.core.StandardContext".equals
+            (context.getClass().getName())) {
+            return; // Container events are not supported
+        }
+        // NOTE:  Race condition is harmless, so do not synchronize
+        if (containerEventMethod == null) {
+            containerEventMethod =
+                context.getClass().getMethod("fireContainerEvent",
+                                             containerEventTypes);
+        }
+        Object containerEventParams[] = new Object[2];
+        containerEventParams[0] = type;
+        containerEventParams[1] = data;
+        containerEventMethod.invoke(context, containerEventParams);
+
+    }
+                                      
+
+
+    /**
+     * Notify all session event listeners that a particular event has
+     * occurred for this Session.  The default implementation performs
+     * this notification synchronously using the calling thread.
+     *
+     * @param type Event type
+     * @param data Event data
+     */
+    public void fireSessionEvent(String type, Object data) {
+        if (listeners.size() < 1)
+            return;
+        SessionEvent event = new SessionEvent(this, type, data);
+        SessionListener list[] = new SessionListener[0];
+        synchronized (listeners) {
+            list = (SessionListener[]) listeners.toArray(list);
+        }
+
+        for (int i = 0; i < list.length; i++){
+            ((SessionListener) list[i]).sessionEvent(event);
+        }
+
+    }
+
+
+    /**
+     * Return the names of all currently defined session attributes
+     * as an array of Strings.  If there are no defined attributes, a
+     * zero-length array is returned.
+     */
+    protected String[] keys() {
+
+        return ((String[]) attributes.keySet().toArray(EMPTY_ARRAY));
+
+    }
+
+
+    /**
+     * Remove the object bound with the specified name from this session.  If
+     * the session does not have an object bound with this name, this method
+     * does nothing.
+     * <p>
+     * After this method executes, and if the object implements
+     * <code>HttpSessionBindingListener</code>, the container calls
+     * <code>valueUnbound()</code> on the object.
+     *
+     * @param name Name of the object to remove from this session.
+     * @param notify Should we notify interested listeners that this
+     *  attribute is being removed?
+     */
+    protected void removeAttributeInternal(String name, boolean notify) {
+
+        // Remove this attribute from our collection
+        Object value = attributes.remove(name);
+
+        // Do we need to do valueUnbound() and attributeRemoved() notification?
+        if (!notify || (value == null)) {
+            return;
+        }
+
+        // Call the valueUnbound() method if necessary
+        HttpSessionBindingEvent event = null;
+        if (value instanceof HttpSessionBindingListener) {
+            event = new HttpSessionBindingEvent(getSession(), name, value);
+            ((HttpSessionBindingListener) value).valueUnbound(event);
+        }
+
+        // Notify interested application event listeners
+        Context context = (Context) manager.getContainer();
+        Object listeners[] = context.getApplicationEventListeners();
+        if (listeners == null)
+            return;
+        for (int i = 0; i < listeners.length; i++) {
+            if (!(listeners[i] instanceof HttpSessionAttributeListener))
+                continue;
+            HttpSessionAttributeListener listener =
+                (HttpSessionAttributeListener) listeners[i];
+            try {
+                fireContainerEvent(context,
+                                   "beforeSessionAttributeRemoved",
+                                   listener);
+                if (event == null) {
+                    event = new HttpSessionBindingEvent
+                        (getSession(), name, value);
+                }
+                listener.attributeRemoved(event);
+                fireContainerEvent(context,
+                                   "afterSessionAttributeRemoved",
+                                   listener);
+            } catch (Throwable t) {
+                try {
+                    fireContainerEvent(context,
+                                       "afterSessionAttributeRemoved",
+                                       listener);
+                } catch (Exception e) {
+                    ;
+                }
+                manager.getContainer().getLogger().error
+                    (sm.getString("standardSession.attributeEvent"), t);
+            }
+        }
+
+    }
+
+
+}
+
+
+// ------------------------------------------------------------ Protected Class
+
+
+/**
+ * This class is a dummy implementation of the <code>HttpSessionContext</code>
+ * interface, to conform to the requirement that such an object be returned
+ * when <code>HttpSession.getSessionContext()</code> is called.
+ *
+ * @author Craig R. McClanahan
+ *
+ * @deprecated As of Java Servlet API 2.1 with no replacement.  The
+ *  interface will be removed in a future version of this API.
+ */
+
+final class StandardSessionContext implements HttpSessionContext {
+
+
+    protected HashMap dummy = new HashMap();
+
+    /**
+     * Return the session identifiers of all sessions defined
+     * within this context.
+     *
+     * @deprecated As of Java Servlet API 2.1 with no replacement.
+     *  This method must return an empty <code>Enumeration</code>
+     *  and will be removed in a future version of the API.
+     */
+    public Enumeration getIds() {
+
+        return (new Enumerator(dummy));
+
+    }
+
+
+    /**
+     * Return the <code>HttpSession</code> associated with the
+     * specified session identifier.
+     *
+     * @param id Session identifier for which to look up a session
+     *
+     * @deprecated As of Java Servlet API 2.1 with no replacement.
+     *  This method must return null and will be removed in a
+     *  future version of the API.
+     */
+    public HttpSession getSession(String id) {
+
+        return (null);
+
+    }
+
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/session/StandardSessionFacade.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/session/StandardSessionFacade.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/session/StandardSessionFacade.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,158 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.session;
+
+
+import java.util.Enumeration;
+
+import javax.servlet.ServletContext;
+import javax.servlet.http.HttpSession;
+import javax.servlet.http.HttpSessionContext;
+
+
+/**
+ * Facade for the StandardSession object.
+ *
+ * @author Remy Maucherat
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class StandardSessionFacade
+    implements HttpSession {
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Construct a new session facade.
+     */
+    public StandardSessionFacade(StandardSession session) {
+        super();
+        this.session = (HttpSession) session;
+    }
+
+
+    /**
+     * Construct a new session facade.
+     */
+    public StandardSessionFacade(HttpSession session) {
+        super();
+        this.session = session;
+    }
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * Wrapped session object.
+     */
+    private HttpSession session = null;
+
+
+    // ---------------------------------------------------- HttpSession Methods
+
+
+    public long getCreationTime() {
+        return session.getCreationTime();
+    }
+
+
+    public String getId() {
+        return session.getId();
+    }
+
+
+    public long getLastAccessedTime() {
+        return session.getLastAccessedTime();
+    }
+
+
+    public ServletContext getServletContext() {
+        // FIXME : Facade this object ?
+        return session.getServletContext();
+    }
+
+
+    public void setMaxInactiveInterval(int interval) {
+        session.setMaxInactiveInterval(interval);
+    }
+
+
+    public int getMaxInactiveInterval() {
+        return session.getMaxInactiveInterval();
+    }
+
+
+    public HttpSessionContext getSessionContext() {
+        return session.getSessionContext();
+    }
+
+
+    public Object getAttribute(String name) {
+        return session.getAttribute(name);
+    }
+
+
+    public Object getValue(String name) {
+        return session.getAttribute(name);
+    }
+
+
+    public Enumeration getAttributeNames() {
+        return session.getAttributeNames();
+    }
+
+
+    public String[] getValueNames() {
+        return session.getValueNames();
+    }
+
+
+    public void setAttribute(String name, Object value) {
+        session.setAttribute(name, value);
+    }
+
+
+    public void putValue(String name, Object value) {
+        session.setAttribute(name, value);
+    }
+
+
+    public void removeAttribute(String name) {
+        session.removeAttribute(name);
+    }
+
+
+    public void removeValue(String name) {
+        session.removeAttribute(name);
+    }
+
+
+    public void invalidate() {
+        session.invalidate();
+    }
+
+
+    public boolean isNew() {
+        return session.isNew();
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/session/StoreBase.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/session/StoreBase.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/session/StoreBase.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,265 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.session;
+
+import java.beans.PropertyChangeListener;
+import java.beans.PropertyChangeSupport;
+import java.io.IOException;
+
+import org.apache.catalina.Lifecycle;
+import org.apache.catalina.LifecycleException;
+import org.apache.catalina.LifecycleListener;
+import org.apache.catalina.Manager;
+import org.apache.catalina.Store;
+import org.apache.catalina.util.LifecycleSupport;
+import org.apache.catalina.util.StringManager;
+
+/**
+ * Abstract implementation of the Store interface to
+ * support most of the functionality required by a Store.
+ *
+ * @author Bip Thelin
+ * @version $Revision: 303826 $, $Date: 2005-03-31 04:31:54 -0600 (Thu, 31 Mar 2005) $
+ */
+
+public abstract class StoreBase
+    implements Lifecycle, Store {
+
+    // ----------------------------------------------------- Instance Variables
+
+    /**
+     * The descriptive information about this implementation.
+     */
+    protected static String info = "StoreBase/1.0";
+
+    /**
+     * Name to register for this Store, used for logging.
+     */
+    protected static String storeName = "StoreBase";
+
+    /**
+     * Has this component been started yet?
+     */
+    protected boolean started = false;
+
+    /**
+     * The lifecycle event support for this component.
+     */
+    protected LifecycleSupport lifecycle = new LifecycleSupport(this);
+
+    /**
+     * The property change support for this component.
+     */
+    protected PropertyChangeSupport support = new PropertyChangeSupport(this);
+
+    /**
+     * The string manager for this package.
+     */
+    protected StringManager sm = StringManager.getManager(Constants.Package);
+
+    /**
+     * The Manager with which this JDBCStore is associated.
+     */
+    protected Manager manager;
+
+    // ------------------------------------------------------------- Properties
+
+    /**
+     * Return the info for this Store.
+     */
+    public String getInfo() {
+        return(info);
+    }
+
+
+    /**
+     * Return the name for this Store, used for logging.
+     */
+    public String getStoreName() {
+        return(storeName);
+    }
+
+
+    /**
+     * Set the Manager with which this Store is associated.
+     *
+     * @param manager The newly associated Manager
+     */
+    public void setManager(Manager manager) {
+        Manager oldManager = this.manager;
+        this.manager = manager;
+        support.firePropertyChange("manager", oldManager, this.manager);
+    }
+
+    /**
+     * Return the Manager with which the Store is associated.
+     */
+    public Manager getManager() {
+        return(this.manager);
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+    /**
+     * Add a lifecycle event listener to this component.
+     *
+     * @param listener The listener to add
+     */
+    public void addLifecycleListener(LifecycleListener listener) {
+        lifecycle.addLifecycleListener(listener);
+    }
+
+
+    /**
+     * Get the lifecycle listeners associated with this lifecycle. If this 
+     * Lifecycle has no listeners registered, a zero-length array is returned.
+     */
+    public LifecycleListener[] findLifecycleListeners() {
+
+        return lifecycle.findLifecycleListeners();
+
+    }
+
+
+    /**
+     * Remove a lifecycle event listener from this component.
+     *
+     * @param listener The listener to add
+     */
+    public void removeLifecycleListener(LifecycleListener listener) {
+        lifecycle.removeLifecycleListener(listener);
+    }
+
+    /**
+     * Add a property change listener to this component.
+     *
+     * @param listener a value of type 'PropertyChangeListener'
+     */
+    public void addPropertyChangeListener(PropertyChangeListener listener) {
+        support.addPropertyChangeListener(listener);
+    }
+
+    /**
+     * Remove a property change listener from this component.
+     *
+     * @param listener The listener to remove
+     */
+    public void removePropertyChangeListener(PropertyChangeListener listener) {
+        support.removePropertyChangeListener(listener);
+    }
+
+    // --------------------------------------------------------- Protected Methods
+
+    /**
+     * Called by our background reaper thread to check if Sessions
+     * saved in our store are subject of being expired. If so expire
+     * the Session and remove it from the Store.
+     *
+     */
+    public void processExpires() {
+        long timeNow = System.currentTimeMillis();
+        String[] keys = null;
+
+         if(!started) {
+            return;
+        }
+
+        try {
+            keys = keys();
+        } catch (IOException e) {
+            manager.getContainer().getLogger().error("Error getting keys", e);
+            return;
+        }
+        if (manager.getContainer().getLogger().isDebugEnabled()) {
+            manager.getContainer().getLogger().debug(getStoreName()+ ": processExpires check number of " + keys.length + " sessions" );
+        }
+    
+        for (int i = 0; i < keys.length; i++) {
+            try {
+                StandardSession session = (StandardSession) load(keys[i]);
+                if (session == null) {
+                    continue;
+                }
+                if (session.isValid()) {
+                    continue;
+                }
+                if (manager.getContainer().getLogger().isDebugEnabled()) {
+                    manager.getContainer().getLogger().debug(getStoreName()+ ": processExpires expire store session " + keys[i] );
+                }
+                if ( ( (PersistentManagerBase) manager).isLoaded( keys[i] )) {
+                    // recycle old backup session
+                    session.recycle();
+                } else {
+                    // expire swapped out session
+                    session.expire();
+                }
+                remove(session.getIdInternal());
+            } catch (Exception e) {
+                manager.getContainer().getLogger().error("Session: "+keys[i]+"; ", e);
+                try {
+                    remove(keys[i]);
+                } catch (IOException e2) {
+                    manager.getContainer().getLogger().error("Error removing key", e2);
+                }
+            }
+        }
+    }
+
+
+    // --------------------------------------------------------- Thread Methods
+
+
+    /**
+     * Prepare for the beginning of active use of the public methods of this
+     * component.  This method should be called after <code>configure()</code>,
+     * and before any of the public methods of the component are utilized.
+     *
+     * @exception LifecycleException if this component detects a fatal error
+     *  that prevents this component from being used
+     */
+    public void start() throws LifecycleException {
+        // Validate and update our current component state
+        if (started)
+            throw new LifecycleException
+                (sm.getString(getStoreName()+".alreadyStarted"));
+        lifecycle.fireLifecycleEvent(START_EVENT, null);
+        started = true;
+
+    }
+
+
+    /**
+     * Gracefully terminate the active use of the public methods of this
+     * component.  This method should be the last one called on a given
+     * instance of this component.
+     *
+     * @exception LifecycleException if this component detects a fatal error
+     *  that needs to be reported
+     */
+    public void stop() throws LifecycleException {
+        // Validate and update our current component state
+        if (!started)
+            throw new LifecycleException
+                (sm.getString(getStoreName()+".notStarted"));
+        lifecycle.fireLifecycleEvent(STOP_EVENT, null);
+        started = false;
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/session/mbeans-descriptors.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/session/mbeans-descriptors.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/session/mbeans-descriptors.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,292 @@
+<?xml version="1.0"?>
+<mbeans-descriptors>
+
+  <mbean         name="StandardManager"
+          description="Standard implementation of the Manager interface"
+               domain="Catalina"
+                group="Manager"
+                 type="org.apache.catalina.session.StandardManager">
+
+    <attribute   name="algorithm"
+          description="The message digest algorithm to be used when generating
+                       session identifiers"
+                 type="java.lang.String"/>
+
+
+    <attribute   name="randomFile"
+          description="File source of random - /dev/urandom or a pipe"
+                 type="java.lang.String"/>
+
+    <attribute   name="className"
+          description="Fully qualified class name of the managed object"
+                 type="java.lang.String"
+            writeable="false"/>
+
+    <attribute   name="distributable"
+          description="The distributable flag for Sessions created by this
+                       Manager"
+                 type="boolean"/>
+
+    <attribute   name="entropy"
+          description="A String initialization parameter used to increase the
+                       entropy of the initialization of our random number
+                       generator"
+                 type="java.lang.String"/>
+
+    <attribute   name="maxActiveSessions"
+          description="The maximum number of active Sessions allowed, or -1
+                       for no limit"
+                 type="int"/>
+
+    <attribute   name="maxInactiveInterval"
+          description="The default maximum inactive interval for Sessions
+                       created by this Manager"
+                 type="int"/>
+
+    <attribute name="processExpiresFrequency"
+               description="The frequency of the manager checks (expiration and passivation)"
+               type="int"/>
+               
+    <attribute   name="sessionIdLength"
+          description="The session id length (in bytes) of Sessions
+                       created by this Manager"
+                 type="int"/>
+
+    <attribute   name="name"
+          description="The descriptive name of this Manager implementation
+                       (for logging)"
+                 type="java.lang.String"
+            writeable="false"/>
+
+    <attribute   name="pathname"
+          description="Path name of the disk file in which active sessions"
+                 type="java.lang.String"/>
+
+    <attribute   name="activeSessions"
+          description="Number of active sessions at this moment"
+                 type="int" 
+            writeable="false"/>
+
+    <attribute   name="sessionCounter"
+          description="Total number of sessions created by this manager"
+                 type="int" />
+
+    <attribute   name="maxActive"
+          description="Maximum number of active sessions so far"
+                 type="int" />
+
+    <attribute   name="sessionMaxAliveTime"
+          description="Longest time an expired session had been alive"
+                 type="int" />
+
+    <attribute   name="sessionAverageAliveTime"
+          description="Average time an expired session had been alive"
+                 type="int" />
+
+    <attribute   name="rejectedSessions"
+          description="Number of sessions we rejected due to maxActive beeing reached"
+                 type="int" />
+
+    <attribute   name="expiredSessions"
+          description="Number of sessions that expired ( doesn't include explicit invalidations )"
+                 type="int" />
+
+    <attribute   name="processingTime"
+          description="Time spent doing housekeeping and expiration"
+                 type="long" />
+
+    <attribute   name="duplicates"
+          description="Number of duplicated session ids generated"
+                 type="int" />
+
+    <operation   name="listSessionIds"
+          description="Return the list of active session ids"
+               impact="ACTION"
+           returnType="java.lang.String">
+    </operation>
+
+    <operation   name="getSessionAttribute"
+          description="Return a session attribute"
+               impact="ACTION"
+           returnType="java.lang.String">
+      <parameter name="sessionId"
+          description="Id of the session"
+                 type="java.lang.String"/>
+      <parameter name="key"
+          description="key of the attribute"
+                 type="java.lang.String"/>
+    </operation>
+
+    <operation   name="expireSession"
+          description="Expire a session"
+               impact="ACTION"
+           returnType="void">
+      <parameter name="sessionId"
+          description="Id of the session"
+                 type="java.lang.String"/>
+    </operation>
+
+    <operation   name="getLastAccessedTime"
+          description="Get the last access time"
+               impact="ACTION"
+           returnType="java.lang.String">
+      <parameter name="sessionId"
+          description="Id of the session"
+                 type="java.lang.String"/>
+    </operation>
+
+  </mbean>
+
+  <mbean         name="PersistentManager"
+          description="Persistent Manager"
+               domain="Catalina"
+                group="Manager"
+                 type="org.apache.catalina.session.PersistentManager">
+
+    <attribute   name="algorithm"
+          description="The message digest algorithm to be used when generating
+                       session identifiers"
+                 type="java.lang.String"/>
+
+    <attribute   name="randomFile"
+          description="File source of random - /dev/urandom or a pipe"
+                 type="java.lang.String"/>
+
+    <attribute   name="className"
+          description="Fully qualified class name of the managed object"
+                 type="java.lang.String"
+            writeable="false"/>
+
+    <attribute   name="distributable"
+          description="The distributable flag for Sessions created by this
+                       Manager"
+                 type="boolean"/>
+
+    <attribute   name="entropy"
+          description="A String initialization parameter used to increase the
+                       entropy of the initialization of our random number
+                       generator"
+                 type="java.lang.String"/>
+ 
+    <attribute   name="managedResource"
+          description="The managed resource this MBean is associated with"
+                 type="java.lang.Object"/>
+
+    <attribute   name="maxActiveSessions"
+          description="The maximum number of active Sessions allowed, or -1
+                       for no limit"
+                 type="int"/>
+
+    <attribute   name="maxInactiveInterval"
+          description="The default maximum inactive interval for Sessions
+                       created by this Manager"
+                 type="int"/>
+                 
+    <attribute name="processExpiresFrequency"
+               description="The frequency of the manager checks (expiration and passivation)"
+               type="int"/>
+               
+    <attribute   name="sessionIdLength"
+          description="The session id length (in bytes) of Sessions
+                       created by this Manager"
+                 type="int"/>
+
+    <attribute   name="name"
+          description="The descriptive name of this Manager implementation
+                       (for logging)"
+                 type="java.lang.String"
+            writeable="false"/>
+
+    <attribute   name="pathname"
+          description="Path name of the disk file in which active sessions"
+                 type="java.lang.String"/>
+
+    <attribute   name="activeSessions"
+          description="Number of active sessions at this moment"
+                 type="int" 
+            writeable="false"/>
+
+    <attribute   name="sessionCounter"
+          description="Total number of sessions created by this manager"
+                 type="int" />
+
+    <attribute   name="maxActive"
+          description="Maximum number of active sessions so far"
+                 type="int" />
+
+    <attribute   name="maxIdleBackup"
+          description="How long a session must be idle before it should be backed up"
+                 type="int" />
+
+    <attribute   name="minIdleSwap"
+          description="Minimum time a session must be idle before it is swapped to disk"
+                 type="int" />
+
+    <attribute   name="maxIdleSwap"
+          description="The maximum time a session may be idle before it should be swapped to file just on general principle"
+                 type="int" />
+
+    <attribute   name="rejectedSessions"
+          description="Number of sessions we rejected due to maxActive beeing reached"
+                 type="int" />
+
+    <attribute   name="expiredSessions"
+          description="Number of sessions that expired ( doesn't include explicit invalidations )"
+                 type="int" />
+
+    <attribute   name="processingTime"
+          description="Time spent doing housekeeping and expiration"
+                 type="long" />
+
+    <attribute   name="duplicates"
+          description="Number of duplicated session ids generated"
+                 type="int" />
+
+    <operation   name="listSessionIds"
+          description="Return the list of active session ids"
+               impact="ACTION"
+           returnType="java.lang.String">
+    </operation>
+
+    <operation   name="getSessionAttribute"
+          description="Return a session attribute"
+               impact="ACTION"
+           returnType="java.lang.String">
+      <parameter name="sessionId"
+          description="Id of the session"
+                 type="java.lang.String"/>
+      <parameter name="key"
+          description="key of the attribute"
+                 type="java.lang.String"/>
+    </operation>
+
+    <operation   name="getSession"
+          description="Get information about a session"
+               impact="ACTION"
+           returnType="java.util.HashMap">
+      <parameter name="sessionId"
+          description="Id of the session"
+                 type="java.lang.String"/>
+    </operation>
+
+    <operation   name="expireSession"
+          description="Expire a session"
+               impact="ACTION"
+           returnType="void">
+      <parameter name="sessionId"
+          description="Id of the session"
+                 type="java.lang.String"/>
+    </operation>
+
+    <operation   name="getLastAccessedTime"
+          description="Get the last access time"
+               impact="ACTION"
+           returnType="java.lang.String">
+      <parameter name="sessionId"
+          description="Id of the session"
+                 type="java.lang.String"/>
+    </operation>
+
+  </mbean>
+
+</mbeans-descriptors>

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/session/package.html
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/session/package.html	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/session/package.html	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,52 @@
+<body>
+
+<p>This package contains the standard <code>Manager</code> and
+<code>Session</code> implementations that represent the collection of
+active sessions and the individual sessions themselves, respectively,
+that are associated with a <code>Context</code>.  Additional implementations
+of the <code>Manager</code> interface can be based upon the supplied
+convenience base class (<code>ManagerBase</code>), if desired.  Different
+implementations of <code>Session</code> are possible, but a need for
+functionality beyond what is provided by the standard implementation
+(<code>StandardSession</code>) is not expected.</p>
+
+<p>The convenience <code>ManagerBase</code> base class is configured by
+setting the following properties:</p>
+<ul>
+<li><b>algorithm</b> - Message digest algorithm to be used when
+    generating session identifiers.  This must be the name of an
+    algorithm supported by the <code>java.security.MessageDigest</code>
+    class on your platform.  [DEFAULT_ALGORITHM]</li>
+<li><b>debug</b> - Debugging detail level for this component. [0]</li>
+<li><b>distributable</b> - Has the web application we are associated with
+    been marked as "distributable"?  If it has, attempts to add or replace
+    a session attribute object that does not implement the
+    <code>java.io.Serializable</code> interface will be rejected.
+    [false]</li>
+<li><b>entropy</b> - A string initialization parameter that is used to
+    increase the entropy of the seeding of the random number generator
+    used in creation of session identifiers.  [NONE]</li>
+<li><b>maxInactiveInterval</b> - The default maximum inactive interval,
+    in minutes, for sessions created by this Manager.  The standard
+    implementation automatically updates this value based on the configuration
+    settings in the web application deployment descriptor.  [60]</li>
+<li><b>randomClass</b> - The Java class name of the random number generator
+    to be used when creating session identifiers for this Manager.
+    [java.security.SecureRandom]</li>
+</ul>
+
+<p>The standard implementation of the <code>Manager</code> interface
+(<code>StandardManager</code>) supports the following additional configuration
+properties:</p>
+<ul>
+<li><b>checkInterval</b> - The interval, in seconds, between checks for
+    sessions that have expired and should be invalidated.  [60]</li>
+<li><b>maxActiveSessions</b> - The maximum number of active sessions that
+    will be allowed, or -1 for no limit.  [-1]</li>
+<li><b>pathname</b> - Pathname to the file that is used to store session
+    data persistently across container restarts.  If this pathname is relative,
+    it is resolved against the temporary working directory provided by our
+    associated Context, if any.  ["sessions.ser"]</li>
+</ul>
+
+</body>

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ssi/ByteArrayServletOutputStream.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ssi/ByteArrayServletOutputStream.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ssi/ByteArrayServletOutputStream.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,62 @@
+/*
+ * Copyright 1999-2002,2004-2005 The Apache Software Foundation.
+ * 
+ * Licensed 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.ssi;
+
+import java.io.ByteArrayOutputStream;
+import javax.servlet.ServletOutputStream;
+
+
+/**
+ * Class that extends ServletOuputStream, used as a wrapper from within
+ * <code>SsiInclude</code>
+ *
+ * @author Bip Thelin
+ * @version $Revision: 304045 $, $Date: 2005-08-04 07:18:30 -0500 (Thu, 04 Aug 2005) $
+ * @see ServletOutputStream and ByteArrayOutputStream
+ */
+public class ByteArrayServletOutputStream extends ServletOutputStream {
+    /**
+     * Our buffer to hold the stream.
+     */
+    protected ByteArrayOutputStream buf = null;
+
+
+    /**
+     * Construct a new ServletOutputStream.
+     */
+    public ByteArrayServletOutputStream() {
+        buf = new ByteArrayOutputStream();
+    }
+
+
+    /**
+     * @return the byte array.
+     */
+    public byte[] toByteArray() {
+        return buf.toByteArray();
+    }
+
+
+    /**
+     * Write to our buffer.
+     *
+     * @param b The parameter to write
+     */
+    public void write(int b) {
+        buf.write(b);
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ssi/ExpressionParseTree.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ssi/ExpressionParseTree.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ssi/ExpressionParseTree.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,383 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation. Licensed 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.ssi;
+
+
+import java.text.ParseException;
+import java.util.LinkedList;
+import java.util.List;
+/**
+ * Represents a parsed expression.
+ * 
+ * @version $Revision: 303166 $
+ * @author Paul Speed
+ */
+public class ExpressionParseTree {
+    /**
+     * Contains the current set of completed nodes. This is a workspace for the
+     * parser.
+     */
+    private LinkedList nodeStack = new LinkedList();
+    /**
+     * Contains operator nodes that don't yet have values. This is a workspace
+     * for the parser.
+     */
+    private LinkedList oppStack = new LinkedList();
+    /**
+     * The root node after the expression has been parsed.
+     */
+    private Node root;
+    /**
+     * The SSIMediator to use when evaluating the expressions.
+     */
+    private SSIMediator ssiMediator;
+
+
+    /**
+     * Creates a new parse tree for the specified expression.
+     */
+    public ExpressionParseTree(String expr, SSIMediator ssiMediator)
+            throws ParseException {
+        this.ssiMediator = ssiMediator;
+        parseExpression(expr);
+    }
+
+
+    /**
+     * Evaluates the tree and returns true or false. The specified SSIMediator
+     * is used to resolve variable references.
+     */
+    public boolean evaluateTree() {
+        return root.evaluate();
+    }
+
+
+    /**
+     * Pushes a new operator onto the opp stack, resolving existing opps as
+     * needed.
+     */
+    private void pushOpp(OppNode node) {
+        // If node is null then it's just a group marker
+        if (node == null) {
+            oppStack.add(0, node);
+            return;
+        }
+        while (true) {
+            if (oppStack.size() == 0) break;
+            OppNode top = (OppNode)oppStack.get(0);
+            // If the top is a spacer then don't pop
+            // anything
+            if (top == null) break;
+            // If the top node has a lower precedence then
+            // let it stay
+            if (top.getPrecedence() < node.getPrecedence()) break;
+            // Remove the top node
+            oppStack.remove(0);
+            // Let it fill its branches
+            top.popValues(nodeStack);
+            // Stick it on the resolved node stack
+            nodeStack.add(0, top);
+        }
+        // Add the new node to the opp stack
+        oppStack.add(0, node);
+    }
+
+
+    /**
+     * Resolves all pending opp nodes on the stack until the next group marker
+     * is reached.
+     */
+    private void resolveGroup() {
+        OppNode top = null;
+        while ((top = (OppNode)oppStack.remove(0)) != null) {
+            // Let it fill its branches
+            top.popValues(nodeStack);
+            // Stick it on the resolved node stack
+            nodeStack.add(0, top);
+        }
+    }
+
+
+    /**
+     * Parses the specified expression into a tree of parse nodes.
+     */
+    private void parseExpression(String expr) throws ParseException {
+        StringNode currStringNode = null;
+        // We cheat a little and start an artificial
+        // group right away. It makes finishing easier.
+        pushOpp(null);
+        ExpressionTokenizer et = new ExpressionTokenizer(expr);
+        while (et.hasMoreTokens()) {
+            int token = et.nextToken();
+            if (token != ExpressionTokenizer.TOKEN_STRING)
+                currStringNode = null;
+            switch (token) {
+                case ExpressionTokenizer.TOKEN_STRING :
+                    if (currStringNode == null) {
+                        currStringNode = new StringNode(et.getTokenValue());
+                        nodeStack.add(0, currStringNode);
+                    } else {
+                        // Add to the existing
+                        currStringNode.value.append(" ");
+                        currStringNode.value.append(et.getTokenValue());
+                    }
+                    break;
+                case ExpressionTokenizer.TOKEN_AND :
+                    pushOpp(new AndNode());
+                    break;
+                case ExpressionTokenizer.TOKEN_OR :
+                    pushOpp(new OrNode());
+                    break;
+                case ExpressionTokenizer.TOKEN_NOT :
+                    pushOpp(new NotNode());
+                    break;
+                case ExpressionTokenizer.TOKEN_EQ :
+                    pushOpp(new EqualNode());
+                    break;
+                case ExpressionTokenizer.TOKEN_NOT_EQ :
+                    pushOpp(new NotNode());
+                    // Sneak the regular node in. The NOT will
+                    // be resolved when the next opp comes along.
+                    oppStack.add(0, new EqualNode());
+                    break;
+                case ExpressionTokenizer.TOKEN_RBRACE :
+                    // Closeout the current group
+                    resolveGroup();
+                    break;
+                case ExpressionTokenizer.TOKEN_LBRACE :
+                    // Push a group marker
+                    pushOpp(null);
+                    break;
+                case ExpressionTokenizer.TOKEN_GE :
+                    pushOpp(new NotNode());
+                    // Similar stategy to NOT_EQ above, except this
+                    // is NOT less than
+                    oppStack.add(0, new LessThanNode());
+                    break;
+                case ExpressionTokenizer.TOKEN_LE :
+                    pushOpp(new NotNode());
+                    // Similar stategy to NOT_EQ above, except this
+                    // is NOT greater than
+                    oppStack.add(0, new GreaterThanNode());
+                    break;
+                case ExpressionTokenizer.TOKEN_GT :
+                    pushOpp(new GreaterThanNode());
+                    break;
+                case ExpressionTokenizer.TOKEN_LT :
+                    pushOpp(new LessThanNode());
+                    break;
+                case ExpressionTokenizer.TOKEN_END :
+                    break;
+            }
+        }
+        // Finish off the rest of the opps
+        resolveGroup();
+        if (nodeStack.size() == 0) {
+            throw new ParseException("No nodes created.", et.getIndex());
+        }
+        if (nodeStack.size() > 1) {
+            throw new ParseException("Extra nodes created.", et.getIndex());
+        }
+        if (oppStack.size() != 0) {
+            throw new ParseException("Unused opp nodes exist.", et.getIndex());
+        }
+        root = (Node)nodeStack.get(0);
+    }
+
+    /**
+     * A node in the expression parse tree.
+     */
+    private abstract class Node {
+        /**
+         * Return true if the node evaluates to true.
+         */
+        public abstract boolean evaluate();
+    }
+    /**
+     * A node the represents a String value
+     */
+    private class StringNode extends Node {
+        StringBuffer value;
+        String resolved = null;
+
+
+        public StringNode(String value) {
+            this.value = new StringBuffer(value);
+        }
+
+
+        /**
+         * Resolves any variable references and returns the value string.
+         */
+        public String getValue() {
+            if (resolved == null)
+                resolved = ssiMediator.substituteVariables(value.toString());
+            return resolved;
+        }
+
+
+        /**
+         * Returns true if the string is not empty.
+         */
+        public boolean evaluate() {
+            return !(getValue().length() == 0);
+        }
+
+
+        public String toString() {
+            return value.toString();
+        }
+    }
+
+    private static final int PRECEDENCE_NOT = 5;
+    private static final int PRECEDENCE_COMPARE = 4;
+    private static final int PRECEDENCE_LOGICAL = 1;
+
+    /**
+     * A node implementation that represents an operation.
+     */
+    private abstract class OppNode extends Node {
+        /**
+         * The left branch.
+         */
+        Node left;
+        /**
+         * The right branch.
+         */
+        Node right;
+
+
+        /**
+         * Returns a preference level suitable for comparison to other OppNode
+         * preference levels.
+         */
+        public abstract int getPrecedence();
+
+
+        /**
+         * Lets the node pop its own branch nodes off the front of the
+         * specified list. The default pulls two.
+         */
+        public void popValues(List values) {
+            right = (Node)values.remove(0);
+            left = (Node)values.remove(0);
+        }
+    }
+    private final class NotNode extends OppNode {
+        public boolean evaluate() {
+            return !left.evaluate();
+        }
+
+
+        public int getPrecedence() {
+            return PRECEDENCE_NOT;
+        }
+
+
+        /**
+         * Overridden to pop only one value.
+         */
+        public void popValues(List values) {
+            left = (Node)values.remove(0);
+        }
+
+
+        public String toString() {
+            return left + " NOT";
+        }
+    }
+    private final class AndNode extends OppNode {
+        public boolean evaluate() {
+            if (!left.evaluate()) // Short circuit
+                return false;
+            return right.evaluate();
+        }
+
+
+        public int getPrecedence() {
+            return PRECEDENCE_LOGICAL;
+        }
+
+
+        public String toString() {
+            return left + " " + right + " AND";
+        }
+    }
+    private final class OrNode extends OppNode {
+        public boolean evaluate() {
+            if (left.evaluate()) // Short circuit
+                return true;
+            return right.evaluate();
+        }
+
+
+        public int getPrecedence() {
+            return PRECEDENCE_LOGICAL;
+        }
+
+
+        public String toString() {
+            return left + " " + right + " OR";
+        }
+    }
+    private abstract class CompareNode extends OppNode {
+        protected int compareBranches() {
+            String val1 = ((StringNode)left).getValue();
+            String val2 = ((StringNode)right).getValue();
+            return val1.compareTo(val2);
+        }
+    }
+    private final class EqualNode extends CompareNode {
+        public boolean evaluate() {
+            return (compareBranches() == 0);
+        }
+
+
+        public int getPrecedence() {
+            return PRECEDENCE_COMPARE;
+        }
+
+
+        public String toString() {
+            return left + " " + right + " EQ";
+        }
+    }
+    private final class GreaterThanNode extends CompareNode {
+        public boolean evaluate() {
+            return (compareBranches() > 0);
+        }
+
+
+        public int getPrecedence() {
+            return PRECEDENCE_COMPARE;
+        }
+
+
+        public String toString() {
+            return left + " " + right + " GT";
+        }
+    }
+    private final class LessThanNode extends CompareNode {
+        public boolean evaluate() {
+            return (compareBranches() < 0);
+        }
+
+
+        public int getPrecedence() {
+            return PRECEDENCE_COMPARE;
+        }
+
+
+        public String toString() {
+            return left + " " + right + " LT";
+        }
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ssi/ExpressionTokenizer.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ssi/ExpressionTokenizer.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ssi/ExpressionTokenizer.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,170 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation. Licensed 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.ssi;
+
+
+/**
+ * Parses an expression string to return the individual tokens. This is
+ * patterned similar to the StreamTokenizer in the JDK but customized for SSI
+ * conditional expression parsing.
+ * 
+ * @version $Revision: 304061 $
+ * @author Paul Speed
+ */
+public class ExpressionTokenizer {
+    public static final int TOKEN_STRING = 0;
+    public static final int TOKEN_AND = 1;
+    public static final int TOKEN_OR = 2;
+    public static final int TOKEN_NOT = 3;
+    public static final int TOKEN_EQ = 4;
+    public static final int TOKEN_NOT_EQ = 5;
+    public static final int TOKEN_RBRACE = 6;
+    public static final int TOKEN_LBRACE = 7;
+    public static final int TOKEN_GE = 8;
+    public static final int TOKEN_LE = 9;
+    public static final int TOKEN_GT = 10;
+    public static final int TOKEN_LT = 11;
+    public static final int TOKEN_END = 12;
+    private char[] expr;
+    private String tokenVal = null;
+    private int index;
+    private int length;
+
+
+    /**
+     * Creates a new parser for the specified expression.
+     */
+    public ExpressionTokenizer(String expr) {
+        this.expr = expr.trim().toCharArray();
+        this.length = this.expr.length;
+    }
+
+
+    /**
+     * Returns true if there are more tokens.
+     */
+    public boolean hasMoreTokens() {
+        return index < length;
+    }
+
+
+    /**
+     * Returns the current index for error reporting purposes.
+     */
+    public int getIndex() {
+        return index;
+    }
+
+
+    protected boolean isMetaChar(char c) {
+        return Character.isWhitespace(c) || c == '(' || c == ')' || c == '!'
+                || c == '<' || c == '>' || c == '|' || c == '&' || c == '=';
+    }
+
+
+    /**
+     * Returns the next token type and initializes any state variables
+     * accordingly.
+     */
+    public int nextToken() {
+        // Skip any leading white space
+        while (index < length && Character.isWhitespace(expr[index]))
+            index++;
+        // Clear the current token val
+        tokenVal = null;
+        if (index == length) return TOKEN_END; // End of string
+        int start = index;
+        char currentChar = expr[index];
+        char nextChar = (char)0;
+        index++;
+        if (index < length) nextChar = expr[index];
+        // Check for a known token start
+        switch (currentChar) {
+            case '(' :
+                return TOKEN_LBRACE;
+            case ')' :
+                return TOKEN_RBRACE;
+            case '=' :
+                return TOKEN_EQ;
+            case '!' :
+                if (nextChar == '=') {
+                    index++;
+                    return TOKEN_NOT_EQ;
+                } else {
+                    return TOKEN_NOT;
+                }
+            case '|' :
+                if (nextChar == '|') {
+                    index++;
+                    return TOKEN_OR;
+                }
+                break;
+            case '&' :
+                if (nextChar == '&') {
+                    index++;
+                    return TOKEN_AND;
+                }
+                break;
+            case '>' :
+                if (nextChar == '=') {
+                    index++;
+                    return TOKEN_GE; // Greater than or equal
+                } else {
+                    return TOKEN_GT; // Greater than
+                }
+            case '<' :
+                if (nextChar == '=') {
+                    index++;
+                    return TOKEN_LE; // Less than or equal
+                } else {
+                    return TOKEN_LT; // Less than
+                }
+            default :
+                // Otherwise it's a string
+                break;
+        }
+        int end = index;
+        // If it's a quoted string then end is the next unescaped quote
+        if (currentChar == '"' || currentChar == '\'') {
+            char endChar = currentChar;
+            boolean escaped = false;
+            start++;
+            for (; index < length; index++) {
+                if (expr[index] == '\\' && !escaped) {
+                    escaped = true;
+                    continue;
+                }
+                if (expr[index] == endChar && !escaped) break;
+                escaped = false;
+            }
+            end = index;
+            index++; // Skip the end quote
+        } else {
+            // End is the next whitespace character
+            for (; index < length; index++) {
+                if (isMetaChar(expr[index])) break;
+            }
+            end = index;
+        }
+        // Extract the string from the array
+        this.tokenVal = new String(expr, start, end - start);
+        return TOKEN_STRING;
+    }
+
+
+    /**
+     * Returns the String value of the token if it was type TOKEN_STRING.
+     * Otherwise null is returned.
+     */
+    public String getTokenValue() {
+        return tokenVal;
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ssi/ResponseIncludeWrapper.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ssi/ResponseIncludeWrapper.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ssi/ResponseIncludeWrapper.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,238 @@
+/*
+ * Copyright 1999-2002,2004-2005 The Apache Software Foundation.
+ * 
+ * Licensed 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.ssi;
+
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+
+import javax.servlet.ServletContext;
+import javax.servlet.ServletOutputStream;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpServletResponseWrapper;
+
+import org.apache.catalina.util.DateTool;
+/**
+ * A HttpServletResponseWrapper, used from
+ * <code>SSIServletExternalResolver</code>
+ * 
+ * @author Bip Thelin
+ * @author David Becker
+ * @version $Revision: 304032 $, $Date: 2005-07-27 10:11:55 -0500 (Wed, 27 Jul 2005) $
+ */
+public class ResponseIncludeWrapper extends HttpServletResponseWrapper {
+    /**
+     * The names of some headers we want to capture.
+     */
+    private static final String CONTENT_TYPE = "content-type";
+    private static final String LAST_MODIFIED = "last-modified";
+    protected long lastModified = -1;
+    private String contentType = null;
+
+    /**
+     * Our ServletOutputStream
+     */
+    protected ServletOutputStream captureServletOutputStream;
+    protected ServletOutputStream servletOutputStream;
+    protected PrintWriter printWriter;
+    
+    private ServletContext context;
+    private HttpServletRequest request;
+
+
+    /**
+     * Initialize our wrapper with the current HttpServletResponse and
+     * ServletOutputStream.
+     * 
+     * @param context The servlet context
+     * @param request The HttpServletResponse to use
+     * @param response The response to use
+     * @param captureServletOutputStream The ServletOutputStream to use
+     */
+    public ResponseIncludeWrapper(ServletContext context, 
+    		HttpServletRequest request, HttpServletResponse response,
+           ServletOutputStream captureServletOutputStream) {
+        super(response);
+        this.context = context;
+        this.request = request;
+        this.captureServletOutputStream = captureServletOutputStream;
+    }
+
+
+    /**
+     * Flush the servletOutputStream or printWriter ( only one will be non-null )
+     * This must be called after a requestDispatcher.include, since we can't
+     * assume that the included servlet flushed its stream.
+     */
+    public void flushOutputStreamOrWriter() throws IOException {
+        if (servletOutputStream != null) {
+            servletOutputStream.flush();
+        }
+        if (printWriter != null) {
+            printWriter.flush();
+        }
+    }
+
+
+    /**
+     * Return a printwriter, throws and exception if a OutputStream already
+     * been returned.
+     * 
+     * @return a PrintWriter object
+     * @exception java.io.IOException
+     *                if the outputstream already been called
+     */
+    public PrintWriter getWriter() throws java.io.IOException {
+        if (servletOutputStream == null) {
+            if (printWriter == null) {
+                setCharacterEncoding(getCharacterEncoding());
+                printWriter = new PrintWriter(
+                        new OutputStreamWriter(captureServletOutputStream,
+                                               getCharacterEncoding()));
+            }
+            return printWriter;
+        }
+        throw new IllegalStateException();
+    }
+
+
+    /**
+     * Return a OutputStream, throws and exception if a printwriter already
+     * been returned.
+     * 
+     * @return a OutputStream object
+     * @exception java.io.IOException
+     *                if the printwriter already been called
+     */
+    public ServletOutputStream getOutputStream() throws java.io.IOException {
+        if (printWriter == null) {
+            if (servletOutputStream == null) {
+                servletOutputStream = captureServletOutputStream;
+            }
+            return servletOutputStream;
+        }
+        throw new IllegalStateException();
+    }
+    
+    
+    /**
+     * Returns the value of the <code>last-modified</code> header field. The
+     * result is the number of milliseconds since January 1, 1970 GMT.
+     *
+     * @return the date the resource referenced by this
+     *   <code>ResponseIncludeWrapper</code> was last modified, or -1 if not
+     *   known.                                                             
+     */
+    public long getLastModified() {                                                                                                                                                           
+        if (lastModified == -1) {
+            // javadocs say to return -1 if date not known, if you want another
+            // default, put it here
+            return -1;
+        }
+        return lastModified;
+    }
+
+    /**
+     * Sets the value of the <code>last-modified</code> header field.
+     *
+     * @param lastModified The number of milliseconds since January 1, 1970 GMT.
+     */
+    public void setLastModified(long lastModified) {
+        this.lastModified = lastModified;
+        ((HttpServletResponse) getResponse()).setDateHeader(LAST_MODIFIED,
+                lastModified);
+    }
+
+    /**
+     * Returns the value of the <code>content-type</code> header field.
+     *
+     * @return the content type of the resource referenced by this
+     *   <code>ResponseIncludeWrapper</code>, or <code>null</code> if not known.
+     */
+    public String getContentType() {
+        if (contentType == null) {
+            String url = request.getRequestURI();
+            String mime = context.getMimeType(url);
+            if (mime != null)
+            {
+                setContentType(mime);
+            }
+            else
+            {
+            	// return a safe value
+               setContentType("application/x-octet-stream");
+            }
+        }
+        return contentType;
+    }
+    
+    /**
+     * Sets the value of the <code>content-type</code> header field.
+     *
+     * @param mime a mime type
+     */
+    public void setContentType(String mime) {
+        contentType = mime;
+        if (contentType != null) {
+            getResponse().setContentType(contentType);
+        }
+    }
+
+
+    public void addDateHeader(String name, long value) {
+        super.addDateHeader(name, value);
+        String lname = name.toLowerCase();
+        if (lname.equals(LAST_MODIFIED)) {
+            lastModified = value;
+        }
+    }
+
+    public void addHeader(String name, String value) {
+        super.addHeader(name, value);
+        String lname = name.toLowerCase();
+        if (lname.equals(LAST_MODIFIED)) {
+            try {
+                lastModified = DateTool.rfc1123Format.parse(value).getTime();
+            } catch (Throwable ignore) { }
+        } else if (lname.equals(CONTENT_TYPE)) {
+            contentType = value;
+        }
+    }
+
+    public void setDateHeader(String name, long value) {
+        super.setDateHeader(name, value);
+        String lname = name.toLowerCase();
+        if (lname.equals(LAST_MODIFIED)) {
+            lastModified = value;
+        }
+    }
+
+    public void setHeader(String name, String value) {
+        super.setHeader(name, value);
+        String lname = name.toLowerCase();
+        if (lname.equals(LAST_MODIFIED)) {
+            try {
+                lastModified = DateTool.rfc1123Format.parse(value).getTime();
+            } catch (Throwable ignore) { }
+        }
+        else if (lname.equals(CONTENT_TYPE))
+        {
+            contentType = value;
+        }
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ssi/SSICommand.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ssi/SSICommand.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ssi/SSICommand.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,45 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation. Licensed 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.ssi;
+
+
+import java.io.PrintWriter;
+/**
+ * The interface that all SSI commands ( SSIEcho, SSIInclude, ...) must
+ * implement.
+ * 
+ * @author Bip Thelin
+ * @author Dan Sandberg
+ * @author David Becker
+ * @version $Revision: 303882 $, $Date: 2005-04-23 05:22:37 -0500 (Sat, 23 Apr 2005) $
+ */
+public interface SSICommand {
+    /**
+     * Write the output of the command to the writer.
+     * 
+     * @param ssiMediator
+     *            the ssi mediator
+     * @param commandName
+     *            the name of the actual command ( ie. echo )
+     * @param paramNames
+     *            The parameter names
+     * @param paramValues
+     *            The parameter values
+     * @param writer
+     *            the writer to output to
+     * @return the most current modified date resulting from any SSI commands
+     * @throws SSIStopProcessingException
+     *             if SSI processing should be aborted
+     */
+	public long process(SSIMediator ssiMediator, String commandName,
+            String[] paramNames, String[] paramValues, PrintWriter writer)
+            throws SSIStopProcessingException;
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ssi/SSIConditional.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ssi/SSIConditional.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ssi/SSIConditional.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,133 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation. Licensed 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.ssi;
+
+
+import java.io.PrintWriter;
+import java.text.ParseException;
+/**
+ * SSI command that handles all conditional directives.
+ * 
+ * @version $Revision: 303882 $
+ * @author Paul Speed
+ * @author David Becker
+ */
+public class SSIConditional implements SSICommand {
+    /**
+     * @see SSICommand
+     */
+    public long process(SSIMediator ssiMediator, String commandName,
+            String[] paramNames, String[] paramValues, PrintWriter writer)
+            throws SSIStopProcessingException {
+    	// Assume anything using conditionals was modified by it
+    	long lastModified = System.currentTimeMillis();
+        // Retrieve the current state information
+        SSIConditionalState state = ssiMediator.getConditionalState();
+        if ("if".equalsIgnoreCase(commandName)) {
+            // Do nothing if we are nested in a false branch
+            // except count it
+            if (state.processConditionalCommandsOnly) {
+                state.nestingCount++;
+                return lastModified;
+            }
+            state.nestingCount = 0;
+            // Evaluate the expression
+            if (evaluateArguments(paramNames, paramValues, ssiMediator)) {
+                // No more branches can be taken for this if block
+                state.branchTaken = true;
+            } else {
+                // Do not process this branch
+                state.processConditionalCommandsOnly = true;
+                state.branchTaken = false;
+            }
+        } else if ("elif".equalsIgnoreCase(commandName)) {
+            // No need to even execute if we are nested in
+            // a false branch
+            if (state.nestingCount > 0) return lastModified;
+            // If a branch was already taken in this if block
+            // then disable output and return
+            if (state.branchTaken) {
+                state.processConditionalCommandsOnly = true;
+                return lastModified;
+            }
+            // Evaluate the expression
+            if (evaluateArguments(paramNames, paramValues, ssiMediator)) {
+                // Turn back on output and mark the branch
+                state.processConditionalCommandsOnly = false;
+                state.branchTaken = true;
+            } else {
+                // Do not process this branch
+                state.processConditionalCommandsOnly = true;
+                state.branchTaken = false;
+            }
+        } else if ("else".equalsIgnoreCase(commandName)) {
+            // No need to even execute if we are nested in
+            // a false branch
+            if (state.nestingCount > 0) return lastModified;
+            // If we've already taken another branch then
+            // disable output otherwise enable it.
+            state.processConditionalCommandsOnly = state.branchTaken;
+            // And in any case, it's safe to say a branch
+            // has been taken.
+            state.branchTaken = true;
+        } else if ("endif".equalsIgnoreCase(commandName)) {
+            // If we are nested inside a false branch then pop out
+            // one level on the nesting count
+            if (state.nestingCount > 0) {
+                state.nestingCount--;
+                return lastModified;
+            }
+            // Turn output back on
+            state.processConditionalCommandsOnly = false;
+            // Reset the branch status for any outer if blocks,
+            // since clearly we took a branch to have gotten here
+            // in the first place.
+            state.branchTaken = true;
+        } else {
+            throw new SSIStopProcessingException();
+            //throw new SsiCommandException( "Not a conditional command:" +
+            // cmdName );
+        }
+        return lastModified;
+    }
+
+
+    /**
+     * Retrieves the expression from the specified arguments and peforms the
+     * necessary evaluation steps.
+     */
+    private boolean evaluateArguments(String[] names, String[] values,
+            SSIMediator ssiMediator) throws SSIStopProcessingException {
+        String expr = getExpression(names, values);
+        if (expr == null) {
+            throw new SSIStopProcessingException();
+            //throw new SsiCommandException( "No expression specified." );
+        }
+        try {
+            ExpressionParseTree tree = new ExpressionParseTree(expr,
+                    ssiMediator);
+            return tree.evaluateTree();
+        } catch (ParseException e) {
+            //throw new SsiCommandException( "Error parsing expression." );
+            throw new SSIStopProcessingException();
+        }
+    }
+
+
+    /**
+     * Returns the "expr" if the arg name is appropriate, otherwise returns
+     * null.
+     */
+    private String getExpression(String[] paramNames, String[] paramValues) {
+        if ("expr".equalsIgnoreCase(paramNames[0])) return paramValues[0];
+        return null;
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ssi/SSIConditionalState.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ssi/SSIConditionalState.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ssi/SSIConditionalState.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,38 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation. Licensed 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.ssi;
+
+
+/**
+ * This class is used by SSIMediator and SSIConditional to keep track of state
+ * information necessary to process the nested conditional commands ( if, elif,
+ * else, endif ).
+ * 
+ * @version $Revision: 303166 $
+ * @author Dan Sandberg
+ * @author Paul Speed
+ */
+class SSIConditionalState {
+    /**
+     * Set to true if the current conditional has already been completed, i.e.:
+     * a branch was taken.
+     */
+    boolean branchTaken = false;
+    /**
+     * Counts the number of nested false branches.
+     */
+    int nestingCount = 0;
+    /**
+     * Set to true if only conditional commands ( if, elif, else, endif )
+     * should be processed.
+     */
+    boolean processConditionalCommandsOnly = false;
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ssi/SSIConfig.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ssi/SSIConfig.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ssi/SSIConfig.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,53 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation. Licensed 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.ssi;
+
+
+import java.io.PrintWriter;
+/**
+ * Implements the Server-side #exec command
+ * 
+ * @author Bip Thelin
+ * @author Paul Speed
+ * @author Dan Sandberg
+ * @author David Becker
+ * @version $Revision: 303882 $, $Date: 2005-04-23 05:22:37 -0500 (Sat, 23 Apr 2005) $
+ */
+public final class SSIConfig implements SSICommand {
+    /**
+     * @see SSICommand
+     */
+    public long process(SSIMediator ssiMediator, String commandName,
+            String[] paramNames, String[] paramValues, PrintWriter writer) {
+        for (int i = 0; i < paramNames.length; i++) {
+            String paramName = paramNames[i];
+            String paramValue = paramValues[i];
+            String substitutedValue = ssiMediator
+                    .substituteVariables(paramValue);
+            if (paramName.equalsIgnoreCase("errmsg")) {
+                ssiMediator.setConfigErrMsg(substitutedValue);
+            } else if (paramName.equalsIgnoreCase("sizefmt")) {
+                ssiMediator.setConfigSizeFmt(substitutedValue);
+            } else if (paramName.equalsIgnoreCase("timefmt")) {
+                ssiMediator.setConfigTimeFmt(substitutedValue);
+            } else {
+                ssiMediator.log("#config--Invalid attribute: " + paramName);
+                //We need to fetch this value each time, since it may change
+                // during the
+                // loop
+                String configErrMsg = ssiMediator.getConfigErrMsg();
+                writer.write(configErrMsg);
+            }
+        }
+        // Setting config options doesn't really change the page
+        return 0;
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ssi/SSIEcho.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ssi/SSIEcho.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ssi/SSIEcho.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,69 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation. Licensed 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.ssi;
+
+
+import java.io.PrintWriter;
+/**
+ * Return the result associated with the supplied Server Variable.
+ * 
+ * @author Bip Thelin
+ * @author Paul Speed
+ * @author Dan Sandberg
+ * @author David Becker
+ * @version $Revision: 303882 $, $Date: 2005-04-23 05:22:37 -0500 (Sat, 23 Apr 2005) $
+ */
+public class SSIEcho implements SSICommand {
+    protected final static String DEFAULT_ENCODING = "entity";
+    protected final static String MISSING_VARIABLE_VALUE = "(none)";
+
+
+    /**
+     * @see SSICommand
+     */
+    public long process(SSIMediator ssiMediator, String commandName,
+            String[] paramNames, String[] paramValues, PrintWriter writer) {
+    	long lastModified = 0;
+        String encoding = DEFAULT_ENCODING;
+        String errorMessage = ssiMediator.getConfigErrMsg();
+        for (int i = 0; i < paramNames.length; i++) {
+            String paramName = paramNames[i];
+            String paramValue = paramValues[i];
+            if (paramName.equalsIgnoreCase("var")) {
+                String variableValue = ssiMediator.getVariableValue(
+                        paramValue, encoding);
+                if (variableValue == null) {
+                    variableValue = MISSING_VARIABLE_VALUE;
+                }
+                writer.write(variableValue);
+                lastModified = System.currentTimeMillis();
+            } else if (paramName.equalsIgnoreCase("encoding")) {
+                if (isValidEncoding(paramValue)) {
+                    encoding = paramValue;
+                } else {
+                    ssiMediator.log("#echo--Invalid encoding: " + paramValue);
+                    writer.write(errorMessage);
+                }
+            } else {
+                ssiMediator.log("#echo--Invalid attribute: " + paramName);
+                writer.write(errorMessage);
+            }
+        }
+        return lastModified;
+    }
+
+
+    protected boolean isValidEncoding(String encoding) {
+        return encoding.equalsIgnoreCase("url")
+                || encoding.equalsIgnoreCase("entity")
+                || encoding.equalsIgnoreCase("none");
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ssi/SSIExec.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ssi/SSIExec.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ssi/SSIExec.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,76 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation. Licensed 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.ssi;
+
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.PrintWriter;
+import org.apache.catalina.util.IOTools;
+/**
+ * Implements the Server-side #exec command
+ * 
+ * @author Bip Thelin
+ * @author Amy Roh
+ * @author Paul Speed
+ * @author Dan Sandberg
+ * @author David Becker
+ * @version $Revision: 303882 $, $Date: 2005-04-23 05:22:37 -0500 (Sat, 23 Apr 2005) $
+ */
+public class SSIExec implements SSICommand {
+    protected SSIInclude ssiInclude = new SSIInclude();
+    protected final static int BUFFER_SIZE = 1024;
+
+
+    /**
+     * @see SSICommand
+     */
+    public long process(SSIMediator ssiMediator, String commandName,
+            String[] paramNames, String[] paramValues, PrintWriter writer) {
+        long lastModified = 0;
+        String configErrMsg = ssiMediator.getConfigErrMsg();
+        String paramName = paramNames[0];
+        String paramValue = paramValues[0];
+        String substitutedValue = ssiMediator.substituteVariables(paramValue);
+        if (paramName.equalsIgnoreCase("cgi")) {
+            lastModified = ssiInclude.process(ssiMediator, "include",
+                    			new String[]{"virtual"}, new String[]{substitutedValue},
+								writer);
+        } else if (paramName.equalsIgnoreCase("cmd")) {
+            boolean foundProgram = false;
+            try {
+                Runtime rt = Runtime.getRuntime();
+                Process proc = rt.exec(substitutedValue);
+                foundProgram = true;
+                BufferedReader stdOutReader = new BufferedReader(
+                        new InputStreamReader(proc.getInputStream()));
+                BufferedReader stdErrReader = new BufferedReader(
+                        new InputStreamReader(proc.getErrorStream()));
+                char[] buf = new char[BUFFER_SIZE];
+                IOTools.flow(stdErrReader, writer, buf);
+                IOTools.flow(stdOutReader, writer, buf);
+                proc.waitFor();
+                lastModified = System.currentTimeMillis();                
+            } catch (InterruptedException e) {
+                ssiMediator.log("Couldn't exec file: " + substitutedValue, e);
+                writer.write(configErrMsg);
+            } catch (IOException e) {
+                if (!foundProgram) {
+                    //apache doesn't output an error message if it can't find
+                    // a program
+                }
+                ssiMediator.log("Couldn't exec file: " + substitutedValue, e);
+            }
+        }
+        return lastModified;
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ssi/SSIExternalResolver.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ssi/SSIExternalResolver.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ssi/SSIExternalResolver.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,71 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation. Licensed 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.ssi;
+
+
+import java.io.IOException;
+import java.util.Collection;
+import java.util.Date;
+/**
+ * Interface used by SSIMediator to talk to the 'outside world' ( usually a
+ * servlet )
+ * 
+ * @author Dan Sandberg
+ * @version $Revision: 303166 $, $Date: 2004-09-01 13:33:33 -0500 (Wed, 01 Sep 2004) $
+ */
+public interface SSIExternalResolver {
+    /**
+     * Adds any external variables to the variableNames collection.
+     * 
+     * @param variableNames
+     *            the collection to add to
+     */
+    public void addVariableNames(Collection variableNames);
+
+
+    public String getVariableValue(String name);
+
+
+    /**
+     * Set the named variable to the specified value. If value is null, then
+     * the variable will be removed ( ie. a call to getVariableValue will
+     * return null )
+     * 
+     * @param name
+     *            of the variable
+     * @param value
+     *            of the variable
+     */
+    public void setVariableValue(String name, String value);
+
+
+    /**
+     * Returns the current date. This is useful for putting the SSI stuff in a
+     * regression test. Since you can make the current date a constant, it
+     * makes testing easier since the output won't change.
+     * 
+     * @return the data
+     */
+    public Date getCurrentDate();
+
+
+    public long getFileSize(String path, boolean virtual) throws IOException;
+
+
+    public long getFileLastModified(String path, boolean virtual)
+            throws IOException;
+
+
+    public String getFileText(String path, boolean virtual) throws IOException;
+
+
+    public void log(String message, Throwable throwable);
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ssi/SSIFilter.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ssi/SSIFilter.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ssi/SSIFilter.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,192 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation. Licensed 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.ssi;
+
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+import java.io.Reader;
+import java.io.Writer;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.catalina.Globals;
+/**
+ * Filter to process SSI requests within a webpage. Mapped to a content types
+ * from within web.xml.
+ * 
+ * @author David Becker
+ * @version $Revision: 303920 $, $Date: 2005-05-05 15:52:37 -0500 (Thu, 05 May 2005) $
+ * @see org.apache.catalina.ssi.SSIServlet
+ */
+public class SSIFilter implements Filter {
+	protected FilterConfig config = null;
+    /** Debug level for this servlet. */
+    protected int debug = 0;
+    /** Expiration time in seconds for the doc. */
+    protected Long expires = null;
+    /** virtual path can be webapp-relative */
+    protected boolean isVirtualWebappRelative = false;
+    /** regex pattern to match when evaluating content types */
+	protected Pattern contentTypeRegEx = null;
+	/** default pattern for ssi filter content type matching */
+	protected Pattern shtmlRegEx =
+        Pattern.compile("text/x-server-parsed-html(;.*)?");
+
+
+    //----------------- Public methods.
+    /**
+     * Initialize this servlet.
+     * 
+     * @exception ServletException
+     *                if an error occurs
+     */
+    public void init(FilterConfig config) throws ServletException {
+    	this.config = config;
+    	
+        String value = null;
+        try {
+            value = config.getInitParameter("debug");
+            debug = Integer.parseInt(value);
+        } catch (Throwable t) {
+            ;
+        }
+        try {
+            value = config.getInitParameter("contentType");
+            contentTypeRegEx = Pattern.compile(value);
+        } catch (Throwable t) {
+            contentTypeRegEx = shtmlRegEx;
+            StringBuffer msg = new StringBuffer();
+            msg.append("Invalid format or no contentType initParam; ");
+            msg.append("expected regular expression; defaulting to ");
+            msg.append(shtmlRegEx.pattern());
+            config.getServletContext().log(msg.toString());
+        }
+        try {
+            value = config.getInitParameter(
+                    "isVirtualWebappRelative");
+            isVirtualWebappRelative = Integer.parseInt(value) > 0?true:false;
+        } catch (Throwable t) {
+            ;
+        }
+        try {
+            value = config.getInitParameter("expires");
+            expires = Long.valueOf(value);
+        } catch (NumberFormatException e) {
+            expires = null;
+            config.getServletContext().log(
+                "Invalid format for expires initParam; expected integer (seconds)"
+            );
+        } catch (Throwable t) {
+            ;
+        }
+        if (debug > 0)
+            config.getServletContext().log(
+                    "SSIFilter.init() SSI invoker started with 'debug'=" + debug);
+    }
+
+    public void doFilter(ServletRequest request, ServletResponse response,
+            FilterChain chain) throws IOException, ServletException {
+        // cast once
+        HttpServletRequest req = (HttpServletRequest)request;
+        HttpServletResponse res = (HttpServletResponse)response;
+        
+        // indicate that we're in SSI processing
+        req.setAttribute(Globals.SSI_FLAG_ATTR, "true");           
+
+        // setup to capture output
+        ByteArrayServletOutputStream basos = new ByteArrayServletOutputStream();
+        ResponseIncludeWrapper responseIncludeWrapper =
+            new ResponseIncludeWrapper(config.getServletContext(),req, res, basos);
+
+        // process remainder of filter chain
+        chain.doFilter(req, responseIncludeWrapper);
+
+        // we can't assume the chain flushed its output
+        responseIncludeWrapper.flushOutputStreamOrWriter();
+        byte[] bytes = basos.toByteArray();
+
+        // get content type
+        String contentType = responseIncludeWrapper.getContentType();
+
+        // is this an allowed type for SSI processing?
+        if (contentTypeRegEx.matcher(contentType).matches()) {
+            String encoding = res.getCharacterEncoding();
+
+            // set up SSI processing 
+            SSIExternalResolver ssiExternalResolver =
+                new SSIServletExternalResolver(config.getServletContext(), req,
+                        res, isVirtualWebappRelative, debug, encoding);
+            SSIProcessor ssiProcessor = new SSIProcessor(ssiExternalResolver,
+                    debug);
+            
+            // prepare readers/writers
+            Reader reader =
+                new InputStreamReader(new ByteArrayInputStream(bytes), encoding);
+            ByteArrayOutputStream ssiout = new ByteArrayOutputStream();
+            PrintWriter writer =
+                new PrintWriter(new OutputStreamWriter(ssiout, encoding));
+            
+            // do SSI processing  
+            long lastModified = ssiProcessor.process(reader,
+                    responseIncludeWrapper.getLastModified(), writer);
+            
+            // set output bytes
+            writer.flush();
+            bytes = ssiout.toByteArray();
+            
+            // override headers
+            if (expires != null) {
+                res.setDateHeader("expires", (new java.util.Date()).getTime()
+                        + expires.longValue() * 1000);
+            }
+            if (lastModified > 0) {
+                res.setDateHeader("last-modified", lastModified);
+            }
+            res.setContentLength(bytes.length);
+            
+            Matcher shtmlMatcher =
+                shtmlRegEx.matcher(responseIncludeWrapper.getContentType());
+            if (shtmlMatcher.matches()) {
+            	// Convert shtml mime type to ordinary html mime type but preserve
+                // encoding, if any.
+            	String enc = shtmlMatcher.group(1);
+            	res.setContentType("text/html" + ((enc != null) ? enc : ""));
+            }
+        }
+
+        // write output
+        try {
+            OutputStream out = res.getOutputStream();
+            out.write(bytes);
+        } catch (Throwable t) {
+            Writer out = res.getWriter();
+            out.write(new String(bytes));
+        }
+    }
+
+    public void destroy() {
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ssi/SSIFlastmod.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ssi/SSIFlastmod.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ssi/SSIFlastmod.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,70 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation. Licensed 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.ssi;
+
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.Date;
+import org.apache.catalina.util.DateTool;
+import org.apache.catalina.util.Strftime;
+/**
+ * Implements the Server-side #flastmod command
+ * 
+ * @author Bip Thelin
+ * @author Paul Speed
+ * @author Dan Sandberg
+ * @author David Becker
+ * @version $Revision: 304061 $, $Date: 2005-08-17 16:21:37 -0500 (Wed, 17 Aug 2005) $
+ */
+public final class SSIFlastmod implements SSICommand {
+    /**
+     * @see SSICommand
+     */
+    public long process(SSIMediator ssiMediator, String commandName,
+            String[] paramNames, String[] paramValues, PrintWriter writer) {
+    	long lastModified = 0;
+        String configErrMsg = ssiMediator.getConfigErrMsg();
+        for (int i = 0; i < paramNames.length; i++) {
+            String paramName = paramNames[i];
+            String paramValue = paramValues[i];
+            String substitutedValue = ssiMediator
+                    .substituteVariables(paramValue);
+            try {
+                if (paramName.equalsIgnoreCase("file")
+                        || paramName.equalsIgnoreCase("virtual")) {
+                    boolean virtual = paramName.equalsIgnoreCase("virtual");
+                    lastModified = ssiMediator.getFileLastModified(
+                            substitutedValue, virtual);
+                    Date date = new Date(lastModified);
+                    String configTimeFmt = ssiMediator.getConfigTimeFmt();
+                    writer.write(formatDate(date, configTimeFmt));
+                } else {
+                    ssiMediator.log("#flastmod--Invalid attribute: "
+                            + paramName);
+                    writer.write(configErrMsg);
+                }
+            } catch (IOException e) {
+                ssiMediator.log(
+                        "#flastmod--Couldn't get last modified for file: "
+                                + substitutedValue, e);
+                writer.write(configErrMsg);
+            }
+        }
+        return lastModified;
+    }
+
+
+    protected String formatDate(Date date, String configTimeFmt) {
+        Strftime strftime = new Strftime(configTimeFmt, DateTool.LOCALE_US);
+        return strftime.format(date);
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ssi/SSIFsize.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ssi/SSIFsize.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ssi/SSIFsize.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,116 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation. Licensed 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.ssi;
+
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.text.DecimalFormat;
+/**
+ * Implements the Server-side #fsize command
+ * 
+ * @author Bip Thelin
+ * @author Paul Speed
+ * @author Dan Sandberg
+ * @author David Becker
+ * @version $Revision: 303882 $, $Date: 2005-04-23 05:22:37 -0500 (Sat, 23 Apr 2005) $
+ */
+public final class SSIFsize implements SSICommand {
+    protected final static int ONE_KILOBYTE = 1024;
+    protected final static int ONE_MEGABYTE = 1024 * 1024;
+
+
+    /**
+     * @see SSICommand
+     */
+    public long process(SSIMediator ssiMediator, String commandName,
+            String[] paramNames, String[] paramValues, PrintWriter writer) {
+        long lastModified = 0;
+        String configErrMsg = ssiMediator.getConfigErrMsg();
+        for (int i = 0; i < paramNames.length; i++) {
+            String paramName = paramNames[i];
+            String paramValue = paramValues[i];
+            String substitutedValue = ssiMediator
+                    .substituteVariables(paramValue);
+            try {
+                if (paramName.equalsIgnoreCase("file")
+                        || paramName.equalsIgnoreCase("virtual")) {
+                    boolean virtual = paramName.equalsIgnoreCase("virtual");
+                    lastModified = ssiMediator.getFileLastModified(
+                            substitutedValue, virtual);
+                    long size = ssiMediator.getFileSize(substitutedValue,
+                            virtual);
+                    String configSizeFmt = ssiMediator.getConfigSizeFmt();
+                    writer.write(formatSize(size, configSizeFmt));
+                } else {
+                    ssiMediator.log("#fsize--Invalid attribute: " + paramName);
+                    writer.write(configErrMsg);
+                }
+            } catch (IOException e) {
+                ssiMediator.log("#fsize--Couldn't get size for file: "
+                        + substitutedValue, e);
+                writer.write(configErrMsg);
+            }
+        }
+        return lastModified;
+    }
+
+
+    public String repeat(char aChar, int numChars) {
+        if (numChars < 0) {
+            throw new IllegalArgumentException("Num chars can't be negative");
+        }
+        StringBuffer buf = new StringBuffer();
+        for (int i = 0; i < numChars; i++) {
+            buf.append(aChar);
+        }
+        return buf.toString();
+    }
+
+
+    public String padLeft(String str, int maxChars) {
+        String result = str;
+        int charsToAdd = maxChars - str.length();
+        if (charsToAdd > 0) {
+            result = repeat(' ', charsToAdd) + str;
+        }
+        return result;
+    }
+
+
+    //We try to mimick Apache here, as we do everywhere
+    //All the 'magic' numbers are from the util_script.c Apache source file.
+    protected String formatSize(long size, String format) {
+        String retString = "";
+        if (format.equalsIgnoreCase("bytes")) {
+            DecimalFormat decimalFormat = new DecimalFormat("#,##0");
+            retString = decimalFormat.format(size);
+        } else {
+            if (size == 0) {
+                retString = "0k";
+            } else if (size < ONE_KILOBYTE) {
+                retString = "1k";
+            } else if (size < ONE_MEGABYTE) {
+                retString = Long.toString((size + 512) / ONE_KILOBYTE);
+                retString += "k";
+            } else if (size < 99 * ONE_MEGABYTE) {
+                DecimalFormat decimalFormat = new DecimalFormat("0.0M");
+                retString = decimalFormat.format(size / (double)ONE_MEGABYTE);
+            } else {
+                retString = Long.toString((size + (529 * ONE_KILOBYTE))
+                        / ONE_MEGABYTE);
+                retString += "M";
+            }
+            retString = padLeft(retString, 5);
+        }
+        return retString;
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ssi/SSIInclude.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ssi/SSIInclude.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ssi/SSIInclude.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,60 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation. Licensed 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.ssi;
+
+
+import java.io.IOException;
+import java.io.PrintWriter;
+/**
+ * Implements the Server-side #include command
+ * 
+ * @author Bip Thelin
+ * @author Paul Speed
+ * @author Dan Sandberg
+ * @author David Becker
+ * @version $Revision: 303882 $, $Date: 2005-04-23 05:22:37 -0500 (Sat, 23 Apr 2005) $
+ */
+public final class SSIInclude implements SSICommand {
+    /**
+     * @see SSICommand
+     */
+    public long process(SSIMediator ssiMediator, String commandName,
+            String[] paramNames, String[] paramValues, PrintWriter writer) {
+        long lastModified = 0;
+        String configErrMsg = ssiMediator.getConfigErrMsg();
+        for (int i = 0; i < paramNames.length; i++) {
+            String paramName = paramNames[i];
+            String paramValue = paramValues[i];
+            String substitutedValue = ssiMediator
+                    .substituteVariables(paramValue);
+            try {
+                if (paramName.equalsIgnoreCase("file")
+                        || paramName.equalsIgnoreCase("virtual")) {
+                    boolean virtual = paramName.equalsIgnoreCase("virtual");
+                    lastModified = ssiMediator.getFileLastModified(
+                    		 substitutedValue, virtual);
+                    String text = ssiMediator.getFileText(substitutedValue,
+                            virtual);
+                    writer.write(text);
+                } else {
+                    ssiMediator.log("#include--Invalid attribute: "
+                            + paramName);
+                    writer.write(configErrMsg);
+                }
+            } catch (IOException e) {
+                ssiMediator.log("#include--Couldn't include file: "
+                        + substitutedValue, e);
+                writer.write(configErrMsg);
+            }
+        }
+        return lastModified;
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ssi/SSIMediator.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ssi/SSIMediator.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ssi/SSIMediator.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,325 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation. Licensed 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.ssi;
+
+
+import java.io.IOException;
+import java.util.Collection;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+import java.util.TimeZone;
+import org.apache.catalina.util.DateTool;
+import org.apache.catalina.util.Strftime;
+import org.apache.catalina.util.URLEncoder;
+/**
+ * Allows the different SSICommand implementations to share data/talk to each
+ * other
+ * 
+ * @author Bip Thelin
+ * @author Amy Roh
+ * @author Paul Speed
+ * @author Dan Sandberg
+ * @author David Becker
+ * @version $Revision: 303882 $, $Date: 2005-04-23 05:22:37 -0500 (Sat, 23 Apr 2005) $
+ */
+public class SSIMediator {
+    protected final static String DEFAULT_CONFIG_ERR_MSG = "[an error occurred while processing this directive]";
+    protected final static String DEFAULT_CONFIG_TIME_FMT = "%A, %d-%b-%Y %T %Z";
+    protected final static String DEFAULT_CONFIG_SIZE_FMT = "abbrev";
+    protected static URLEncoder urlEncoder;
+    protected String configErrMsg = DEFAULT_CONFIG_ERR_MSG;
+    protected String configTimeFmt = DEFAULT_CONFIG_TIME_FMT;
+    protected String configSizeFmt = DEFAULT_CONFIG_SIZE_FMT;
+    protected String className = getClass().getName();
+    protected SSIExternalResolver ssiExternalResolver;
+    protected long lastModifiedDate;
+    protected int debug;
+    protected Strftime strftime;
+    protected SSIConditionalState conditionalState = new SSIConditionalState();
+    static {
+        //We try to encode only the same characters that apache does
+        urlEncoder = new URLEncoder();
+        urlEncoder.addSafeCharacter(',');
+        urlEncoder.addSafeCharacter(':');
+        urlEncoder.addSafeCharacter('-');
+        urlEncoder.addSafeCharacter('_');
+        urlEncoder.addSafeCharacter('.');
+        urlEncoder.addSafeCharacter('*');
+        urlEncoder.addSafeCharacter('/');
+        urlEncoder.addSafeCharacter('!');
+        urlEncoder.addSafeCharacter('~');
+        urlEncoder.addSafeCharacter('\'');
+        urlEncoder.addSafeCharacter('(');
+        urlEncoder.addSafeCharacter(')');
+    }
+
+
+    public SSIMediator(SSIExternalResolver ssiExternalResolver,
+            long lastModifiedDate, int debug) {
+        this.ssiExternalResolver = ssiExternalResolver;
+        this.lastModifiedDate = lastModifiedDate;
+        this.debug = debug;
+        setConfigTimeFmt(DEFAULT_CONFIG_TIME_FMT, true);
+    }
+
+
+    public void setConfigErrMsg(String configErrMsg) {
+        this.configErrMsg = configErrMsg;
+    }
+
+
+    public void setConfigTimeFmt(String configTimeFmt) {
+        setConfigTimeFmt(configTimeFmt, false);
+    }
+
+
+    public void setConfigTimeFmt(String configTimeFmt, boolean fromConstructor) {
+        this.configTimeFmt = configTimeFmt;
+        //What's the story here with DateTool.LOCALE_US?? Why??
+        this.strftime = new Strftime(configTimeFmt, DateTool.LOCALE_US);
+        //Variables like DATE_LOCAL, DATE_GMT, and LAST_MODIFIED need to be
+        // updated when
+        //the timefmt changes. This is what Apache SSI does.
+        setDateVariables(fromConstructor);
+    }
+
+
+    public void setConfigSizeFmt(String configSizeFmt) {
+        this.configSizeFmt = configSizeFmt;
+    }
+
+
+    public String getConfigErrMsg() {
+        return configErrMsg;
+    }
+
+
+    public String getConfigTimeFmt() {
+        return configTimeFmt;
+    }
+
+
+    public String getConfigSizeFmt() {
+        return configSizeFmt;
+    }
+
+
+    public SSIConditionalState getConditionalState() {
+        return conditionalState;
+    }
+
+
+    public Collection getVariableNames() {
+        Set variableNames = new HashSet();
+        //These built-in variables are supplied by the mediator ( if not
+        // over-written by
+        // the user ) and always exist
+        variableNames.add("DATE_GMT");
+        variableNames.add("DATE_LOCAL");
+        variableNames.add("LAST_MODIFIED");
+        ssiExternalResolver.addVariableNames(variableNames);
+        //Remove any variables that are reserved by this class
+        Iterator iter = variableNames.iterator();
+        while (iter.hasNext()) {
+            String name = (String)iter.next();
+            if (isNameReserved(name)) {
+                iter.remove();
+            }
+        }
+        return variableNames;
+    }
+
+
+    public long getFileSize(String path, boolean virtual) throws IOException {
+        return ssiExternalResolver.getFileSize(path, virtual);
+    }
+
+
+    public long getFileLastModified(String path, boolean virtual)
+            throws IOException {
+        return ssiExternalResolver.getFileLastModified(path, virtual);
+    }
+
+
+    public String getFileText(String path, boolean virtual) throws IOException {
+        return ssiExternalResolver.getFileText(path, virtual);
+    }
+
+
+    protected boolean isNameReserved(String name) {
+        return name.startsWith(className + ".");
+    }
+
+
+    public String getVariableValue(String variableName) {
+        return getVariableValue(variableName, "none");
+    }
+
+
+    public void setVariableValue(String variableName, String variableValue) {
+        if (!isNameReserved(variableName)) {
+            ssiExternalResolver.setVariableValue(variableName, variableValue);
+        }
+    }
+
+
+    public String getVariableValue(String variableName, String encoding) {
+        String lowerCaseVariableName = variableName.toLowerCase();
+        String variableValue = null;
+        if (!isNameReserved(lowerCaseVariableName)) {
+            //Try getting it externally first, if it fails, try getting the
+            // 'built-in'
+            // value
+            variableValue = ssiExternalResolver.getVariableValue(variableName);
+            if (variableValue == null) {
+                variableName = variableName.toUpperCase();
+                variableValue = (String)ssiExternalResolver
+                        .getVariableValue(className + "." + variableName);
+            }
+            if (variableValue != null) {
+                variableValue = encode(variableValue, encoding);
+            }
+        }
+        return variableValue;
+    }
+
+
+    /**
+     * Applies variable substitution to the specified String and returns the
+     * new resolved string.
+     */
+    public String substituteVariables(String val) {
+        // If it has no variable references then no work
+        // need to be done
+        if (val.indexOf('$') < 0) return val;
+        StringBuffer sb = new StringBuffer(val);
+        for (int i = 0; i < sb.length();) {
+            // Find the next $
+            for (; i < sb.length(); i++) {
+                if (sb.charAt(i) == '$') {
+                    i++;
+                    break;
+                }
+            }
+            if (i == sb.length()) break;
+            // Check to see if the $ is escaped
+            if (i > 1 && sb.charAt(i - 2) == '\\') {
+                sb.deleteCharAt(i - 2);
+                i--;
+                continue;
+            }
+            int nameStart = i;
+            int start = i - 1;
+            int end = -1;
+            int nameEnd = -1;
+            char endChar = ' ';
+            // Check for {} wrapped var
+            if (sb.charAt(i) == '{') {
+                nameStart++;
+                endChar = '}';
+            }
+            // Find the end of the var reference
+            for (; i < sb.length(); i++) {
+                if (sb.charAt(i) == endChar) break;
+            }
+            end = i;
+            nameEnd = end;
+            if (endChar == '}') end++;
+            // We should now have enough to extract the var name
+            String varName = sb.substring(nameStart, nameEnd);
+            String value = getVariableValue(varName);
+            if (value == null) value = "";
+            // Replace the var name with its value
+            sb.replace(start, end, value);
+            // Start searching for the next $ after the value
+            // that was just substituted.
+            i = start + value.length();
+        }
+        return sb.toString();
+    }
+
+
+    protected String formatDate(Date date, TimeZone timeZone) {
+        String retVal;
+        if (timeZone != null) {
+            //we temporarily change strftime. Since SSIMediator is inherently
+            // single-threaded, this
+            //isn't a problem
+            TimeZone oldTimeZone = strftime.getTimeZone();
+            strftime.setTimeZone(timeZone);
+            retVal = strftime.format(date);
+            strftime.setTimeZone(oldTimeZone);
+        } else {
+            retVal = strftime.format(date);
+        }
+        return retVal;
+    }
+
+
+    protected String encode(String value, String encoding) {
+        String retVal = null;
+        if (encoding.equalsIgnoreCase("url")) {
+            retVal = urlEncoder.encode(value);
+        } else if (encoding.equalsIgnoreCase("none")) {
+            retVal = value;
+        } else if (encoding.equalsIgnoreCase("entity")) {
+            //Not sure how this is really different than none
+            retVal = value;
+        } else {
+            //This shouldn't be possible
+            throw new IllegalArgumentException("Unknown encoding: " + encoding);
+        }
+        return retVal;
+    }
+
+
+    public void log(String message) {
+        ssiExternalResolver.log(message, null);
+    }
+
+
+    public void log(String message, Throwable throwable) {
+        ssiExternalResolver.log(message, throwable);
+    }
+
+
+    protected void setDateVariables(boolean fromConstructor) {
+        boolean alreadySet = ssiExternalResolver.getVariableValue(className
+                + ".alreadyset") != null;
+        //skip this if we are being called from the constructor, and this has
+        // already
+        // been set
+        if (!(fromConstructor && alreadySet)) {
+            ssiExternalResolver.setVariableValue(className + ".alreadyset",
+                    "true");
+            Date date = new Date();
+            TimeZone timeZone = TimeZone.getTimeZone("GMT");
+            String retVal = formatDate(date, timeZone);
+            //If we are setting on of the date variables, we want to remove
+            // them from the
+            // user
+            //defined list of variables, because this is what Apache does
+            setVariableValue("DATE_GMT", null);
+            ssiExternalResolver.setVariableValue(className + ".DATE_GMT",
+                    retVal);
+            retVal = formatDate(date, null);
+            setVariableValue("DATE_LOCAL", null);
+            ssiExternalResolver.setVariableValue(className + ".DATE_LOCAL",
+                    retVal);
+            retVal = formatDate(new Date(lastModifiedDate), null);
+            setVariableValue("LAST_MODIFIED", null);
+            ssiExternalResolver.setVariableValue(className + ".LAST_MODIFIED",
+                    retVal);
+        }
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ssi/SSIPrintenv.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ssi/SSIPrintenv.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ssi/SSIPrintenv.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,56 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation. Licensed 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.ssi;
+
+
+import java.io.PrintWriter;
+import java.util.Collection;
+import java.util.Iterator;
+/**
+ * Implements the Server-side #printenv command
+ * 
+ * @author Dan Sandberg
+ * @author David Becker
+ * @version $Revision: 303882 $, $Date: 2005-04-23 05:22:37 -0500 (Sat, 23 Apr 2005) $
+ */
+public class SSIPrintenv implements SSICommand {
+    /**
+     * @see SSICommand
+     */
+    public long process(SSIMediator ssiMediator, String commandName,
+            String[] paramNames, String[] paramValues, PrintWriter writer) {
+    	long lastModified = 0;
+        //any arguments should produce an error
+        if (paramNames.length > 0) {
+            String errorMessage = ssiMediator.getConfigErrMsg();
+            writer.write(errorMessage);
+        } else {
+            Collection variableNames = ssiMediator.getVariableNames();
+            Iterator iter = variableNames.iterator();
+            while (iter.hasNext()) {
+                String variableName = (String)iter.next();
+                String variableValue = ssiMediator
+                        .getVariableValue(variableName);
+                //This shouldn't happen, since all the variable names must
+                // have values
+                if (variableValue == null) {
+                    variableValue = "(none)";
+                }
+                writer.write(variableName);
+                writer.write('=');
+                writer.write(variableValue);
+                writer.write('\n');
+                lastModified = System.currentTimeMillis();
+            }
+        }
+        return lastModified;
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ssi/SSIProcessor.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ssi/SSIProcessor.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ssi/SSIProcessor.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,319 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation. Licensed 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.ssi;
+
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.Reader;
+import java.io.StringWriter;
+import java.util.HashMap;
+import java.util.StringTokenizer;
+import org.apache.catalina.util.IOTools;
+/**
+ * The entry point to SSI processing. This class does the actual parsing,
+ * delegating to the SSIMediator, SSICommand, and SSIExternalResolver as
+ * necessary[
+ * 
+ * @author Dan Sandberg
+ * @author David Becker
+ * @version $Revision: 424634 $, $Date: 2006-07-22 16:48:38 -0500 (Sat, 22 Jul 2006) $
+ */
+public class SSIProcessor {
+    /** The start pattern */
+    protected final static String COMMAND_START = "<!--#";
+    /** The end pattern */
+    protected final static String COMMAND_END = "-->";
+    protected final static int BUFFER_SIZE = 4096;
+    protected SSIExternalResolver ssiExternalResolver;
+    protected HashMap commands = new HashMap();
+    protected int debug;
+
+
+    public SSIProcessor(SSIExternalResolver ssiExternalResolver, int debug) {
+        this.ssiExternalResolver = ssiExternalResolver;
+        this.debug = debug;
+        addBuiltinCommands();
+    }
+
+
+    protected void addBuiltinCommands() {
+        addCommand("config", new SSIConfig());
+        addCommand("echo", new SSIEcho());
+        addCommand("exec", new SSIExec());
+        addCommand("include", new SSIInclude());
+        addCommand("flastmod", new SSIFlastmod());
+        addCommand("fsize", new SSIFsize());
+        addCommand("printenv", new SSIPrintenv());
+        addCommand("set", new SSISet());
+        SSIConditional ssiConditional = new SSIConditional();
+        addCommand("if", ssiConditional);
+        addCommand("elif", ssiConditional);
+        addCommand("endif", ssiConditional);
+        addCommand("else", ssiConditional);
+    }
+
+
+    public void addCommand(String name, SSICommand command) {
+        commands.put(name, command);
+    }
+
+
+    /**
+     * Process a file with server-side commands, reading from reader and
+     * writing the processed version to writer. NOTE: We really should be doing
+     * this in a streaming way rather than converting it to an array first.
+     * 
+     * @param reader
+     *            the reader to read the file containing SSIs from
+     * @param writer
+     *            the writer to write the file with the SSIs processed.
+     * @return the most current modified date resulting from any SSI commands
+     * @throws IOException
+     *             when things go horribly awry. Should be unlikely since the
+     *             SSICommand usually catches 'normal' IOExceptions.
+     */
+    public long process(Reader reader, long lastModifiedDate,
+            PrintWriter writer) throws IOException {
+        SSIMediator ssiMediator = new SSIMediator(ssiExternalResolver,
+                lastModifiedDate, debug);
+        StringWriter stringWriter = new StringWriter();
+        IOTools.flow(reader, stringWriter);
+        String fileContents = stringWriter.toString();
+        stringWriter = null;
+        int index = 0;
+        boolean inside = false;
+        StringBuffer command = new StringBuffer();
+        try {
+            while (index < fileContents.length()) {
+                char c = fileContents.charAt(index);
+                if (!inside) {
+                    if (c == COMMAND_START.charAt(0)
+                            && charCmp(fileContents, index, COMMAND_START)) {
+                        inside = true;
+                        index += COMMAND_START.length();
+                        command.setLength(0); //clear the command string
+                    } else {
+                        if (!ssiMediator.getConditionalState().processConditionalCommandsOnly) {
+                            writer.write(c);
+                        }
+                        index++;
+                    }
+                } else {
+                    if (c == COMMAND_END.charAt(0)
+                            && charCmp(fileContents, index, COMMAND_END)) {
+                        inside = false;
+                        index += COMMAND_END.length();
+                        String strCmd = parseCmd(command);
+                        if (debug > 0) {
+                            ssiExternalResolver.log(
+                                    "SSIProcessor.process -- processing command: "
+                                            + strCmd, null);
+                        }
+                        String[] paramNames = parseParamNames(command, strCmd
+                                .length());
+                        String[] paramValues = parseParamValues(command,
+                                strCmd.length(), paramNames.length);
+                        //We need to fetch this value each time, since it may
+                        // change
+                        // during the loop
+                        String configErrMsg = ssiMediator.getConfigErrMsg();
+                        SSICommand ssiCommand = (SSICommand)commands
+                                .get(strCmd.toLowerCase());
+                        String errorMessage = null;
+                        if (ssiCommand == null) {
+                            errorMessage = "Unknown command: " + strCmd;
+                        } else if (paramValues == null) {
+                            errorMessage = "Error parsing directive parameters.";
+                        } else if (paramNames.length != paramValues.length) {
+                            errorMessage = "Parameter names count does not match parameter values count on command: "
+                                    + strCmd;
+                        } else {
+                            // don't process the command if we are processing
+                            // conditional
+                            // commands only and the
+                            // command is not conditional
+                            if (!ssiMediator.getConditionalState().processConditionalCommandsOnly
+                                    || ssiCommand instanceof SSIConditional) {
+                                long lmd = ssiCommand.process(ssiMediator, strCmd,
+                                               paramNames, paramValues, writer);
+                                if (lmd > lastModifiedDate) {
+                                    lastModifiedDate = lmd;
+                                }                                    
+                            }
+                        }
+                        if (errorMessage != null) {
+                            ssiExternalResolver.log(errorMessage, null);
+                            writer.write(configErrMsg);
+                        }
+                    } else {
+                        command.append(c);
+                        index++;
+                    }
+                }
+            }
+        } catch (SSIStopProcessingException e) {
+            //If we are here, then we have already stopped processing, so all
+            // is good
+        }
+        return lastModifiedDate;
+    }
+
+
+    /**
+     * Parse a StringBuffer and take out the param type token. Called from
+     * <code>requestHandler</code>
+     * 
+     * @param cmd
+     *            a value of type 'StringBuffer'
+     * @return a value of type 'String[]'
+     */
+    protected String[] parseParamNames(StringBuffer cmd, int start) {
+        int bIdx = start;
+        int i = 0;
+        int quotes = 0;
+        boolean inside = false;
+        StringBuffer retBuf = new StringBuffer();
+        while (bIdx < cmd.length()) {
+            if (!inside) {
+                while (bIdx < cmd.length() && isSpace(cmd.charAt(bIdx)))
+                    bIdx++;
+                if (bIdx >= cmd.length()) break;
+                inside = !inside;
+            } else {
+                while (bIdx < cmd.length() && cmd.charAt(bIdx) != '=') {
+                    retBuf.append(cmd.charAt(bIdx));
+                    bIdx++;
+                }
+                retBuf.append('=');
+                inside = !inside;
+                quotes = 0;
+                boolean escaped = false;
+                for (; bIdx < cmd.length() && quotes != 2; bIdx++) {
+                    char c = cmd.charAt(bIdx);
+                    // Need to skip escaped characters
+                    if (c == '\\' && !escaped) {
+                        escaped = true;
+                        bIdx++;
+                        continue;
+                    }
+                    escaped = false;
+                    if (c == '"') quotes++;
+                }
+            }
+        }
+        StringTokenizer str = new StringTokenizer(retBuf.toString(), "=");
+        String[] retString = new String[str.countTokens()];
+        while (str.hasMoreTokens()) {
+            retString[i++] = str.nextToken().trim();
+        }
+        return retString;
+    }
+
+
+    /**
+     * Parse a StringBuffer and take out the param token. Called from
+     * <code>requestHandler</code>
+     * 
+     * @param cmd
+     *            a value of type 'StringBuffer'
+     * @return a value of type 'String[]'
+     */
+    protected String[] parseParamValues(StringBuffer cmd, int start, int count) {
+        int valIndex = 0;
+        boolean inside = false;
+        String[] vals = new String[count];
+        StringBuffer sb = new StringBuffer();
+        char endQuote = 0;
+        for (int bIdx = start; bIdx < cmd.length(); bIdx++) {
+            if (!inside) {
+                while (bIdx < cmd.length() && !isQuote(cmd.charAt(bIdx)))
+                    bIdx++;
+                if (bIdx >= cmd.length()) break;
+                inside = !inside;
+                endQuote = cmd.charAt(bIdx);
+            } else {
+                boolean escaped = false;
+                for (; bIdx < cmd.length(); bIdx++) {
+                    char c = cmd.charAt(bIdx);
+                    // Check for escapes
+                    if (c == '\\' && !escaped) {
+                        escaped = true;
+                        continue;
+                    }
+                    // If we reach the other " then stop
+                    if (c == endQuote && !escaped) break;
+                    // Since parsing of attributes and var
+                    // substitution is done in separate places,
+                    // we need to leave escape in the string
+                    if (c == '$' && escaped) sb.append('\\');
+                    escaped = false;
+                    sb.append(c);
+                }
+                // If we hit the end without seeing a quote
+                // the signal an error
+                if (bIdx == cmd.length()) return null;
+                vals[valIndex++] = sb.toString();
+                sb.delete(0, sb.length()); // clear the buffer
+                inside = !inside;
+            }
+        }
+        return vals;
+    }
+
+
+    /**
+     * Parse a StringBuffer and take out the command token. Called from
+     * <code>requestHandler</code>
+     * 
+     * @param cmd
+     *            a value of type 'StringBuffer'
+     * @return a value of type 'String', or null if there is none
+     */
+    private String parseCmd(StringBuffer cmd) {
+        int firstLetter = -1;
+        int lastLetter = -1;
+        for (int i = 0; i < cmd.length(); i++) {
+            char c = cmd.charAt(i);
+            if (Character.isLetter(c)) {
+                if (firstLetter == -1) {
+                    firstLetter = i;
+                }
+                lastLetter = i;
+            } else if (isSpace(c)) {
+                if (lastLetter > -1) {
+                    break;
+                }
+            } else {
+                break;
+            }
+        }
+        String command = null;
+        if (firstLetter != -1) {
+            command = cmd.substring(firstLetter, lastLetter + 1);
+        }
+        return command;
+    }
+
+
+    protected boolean charCmp(String buf, int index, String command) {
+        return buf.regionMatches(index, command, 0, command.length());
+    }
+
+
+    protected boolean isSpace(char c) {
+        return c == ' ' || c == '\n' || c == '\t' || c == '\r';
+    }
+    
+    protected boolean isQuote(char c) {
+        return c == '\'' || c == '\"' || c == '`';
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ssi/SSIServlet.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ssi/SSIServlet.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ssi/SSIServlet.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,232 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation. Licensed 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.ssi;
+
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.net.URL;
+import java.net.URLConnection;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import org.apache.catalina.Globals;
+/**
+ * Servlet to process SSI requests within a webpage. Mapped to a path from
+ * within web.xml.
+ * 
+ * @author Bip Thelin
+ * @author Amy Roh
+ * @author Dan Sandberg
+ * @author David Becker
+ * @version $Revision: 303882 $, $Date: 2005-04-23 05:22:37 -0500 (Sat, 23 Apr 2005) $
+ */
+public class SSIServlet extends HttpServlet {
+    /** Debug level for this servlet. */
+    protected int debug = 0;
+    /** Should the output be buffered. */
+    protected boolean buffered = false;
+    /** Expiration time in seconds for the doc. */
+    protected Long expires = null;
+    /** virtual path can be webapp-relative */
+    protected boolean isVirtualWebappRelative = false;
+    /** Input encoding. If not specified, uses platform default */
+    protected String inputEncoding = null;
+    /** Output encoding. If not specified, uses platform default */
+    protected String outputEncoding = "UTF-8";
+
+
+    //----------------- Public methods.
+    /**
+     * Initialize this servlet.
+     * 
+     * @exception ServletException
+     *                if an error occurs
+     */
+    public void init() throws ServletException {
+        String value = null;
+        try {
+            value = getServletConfig().getInitParameter("debug");
+            debug = Integer.parseInt(value);
+        } catch (Throwable t) {
+            ;
+        }
+        try {
+            value = getServletConfig().getInitParameter(
+                    "isVirtualWebappRelative");
+            isVirtualWebappRelative = Integer.parseInt(value) > 0?true:false;
+        } catch (Throwable t) {
+            ;
+        }
+        try {
+            value = getServletConfig().getInitParameter("expires");
+            expires = Long.valueOf(value);
+        } catch (NumberFormatException e) {
+            expires = null;
+            log("Invalid format for expires initParam; expected integer (seconds)");
+        } catch (Throwable t) {
+            ;
+        }
+        try {
+            value = getServletConfig().getInitParameter("buffered");
+            buffered = Integer.parseInt(value) > 0?true:false;
+        } catch (Throwable t) {
+            ;
+        }
+        try {
+            inputEncoding = getServletConfig().getInitParameter("inputEncoding");
+        } catch (Throwable t) {
+            ;
+        }
+        try {
+            value = getServletConfig().getInitParameter("outputEncoding");
+            if (value != null) {
+                outputEncoding = value;
+            }
+        } catch (Throwable t) {
+            ;
+        }
+        if (debug > 0)
+            log("SSIServlet.init() SSI invoker started with 'debug'=" + debug);
+    }
+
+
+    /**
+     * Process and forward the GET request to our <code>requestHandler()</code>*
+     * 
+     * @param req
+     *            a value of type 'HttpServletRequest'
+     * @param res
+     *            a value of type 'HttpServletResponse'
+     * @exception IOException
+     *                if an error occurs
+     * @exception ServletException
+     *                if an error occurs
+     */
+    public void doGet(HttpServletRequest req, HttpServletResponse res)
+            throws IOException, ServletException {
+        if (debug > 0) log("SSIServlet.doGet()");
+        requestHandler(req, res);
+    }
+
+
+    /**
+     * Process and forward the POST request to our
+     * <code>requestHandler()</code>.
+     * 
+     * @param req
+     *            a value of type 'HttpServletRequest'
+     * @param res
+     *            a value of type 'HttpServletResponse'
+     * @exception IOException
+     *                if an error occurs
+     * @exception ServletException
+     *                if an error occurs
+     */
+    public void doPost(HttpServletRequest req, HttpServletResponse res)
+            throws IOException, ServletException {
+        if (debug > 0) log("SSIServlet.doPost()");
+        requestHandler(req, res);
+    }
+
+
+    /**
+     * Process our request and locate right SSI command.
+     * 
+     * @param req
+     *            a value of type 'HttpServletRequest'
+     * @param res
+     *            a value of type 'HttpServletResponse'
+     */
+    protected void requestHandler(HttpServletRequest req,
+            HttpServletResponse res) throws IOException, ServletException {
+        ServletContext servletContext = getServletContext();
+        String path = SSIServletRequestUtil.getRelativePath(req);
+        if (debug > 0)
+            log("SSIServlet.requestHandler()\n" + "Serving "
+                    + (buffered?"buffered ":"unbuffered ") + "resource '"
+                    + path + "'");
+        // Exclude any resource in the /WEB-INF and /META-INF subdirectories
+        // (the "toUpperCase()" avoids problems on Windows systems)
+        if (path == null || path.toUpperCase().startsWith("/WEB-INF")
+                || path.toUpperCase().startsWith("/META-INF")) {
+            res.sendError(HttpServletResponse.SC_NOT_FOUND, path);
+            log("Can't serve file: " + path);
+            return;
+        }
+        URL resource = servletContext.getResource(path);
+        if (resource == null) {
+            res.sendError(HttpServletResponse.SC_NOT_FOUND, path);
+            log("Can't find file: " + path);
+            return;
+        }
+        String resourceMimeType = servletContext.getMimeType(path);
+        if (resourceMimeType == null) {
+            resourceMimeType = "text/html";
+        }
+        res.setContentType(resourceMimeType + ";charset=" + outputEncoding);
+        if (expires != null) {
+            res.setDateHeader("Expires", (new java.util.Date()).getTime()
+                    + expires.longValue() * 1000);
+        }
+        req.setAttribute(Globals.SSI_FLAG_ATTR, "true");
+        processSSI(req, res, resource);
+    }
+
+
+    protected void processSSI(HttpServletRequest req, HttpServletResponse res,
+            URL resource) throws IOException {
+        SSIExternalResolver ssiExternalResolver =
+            new SSIServletExternalResolver(getServletContext(), req, res,
+                    isVirtualWebappRelative, debug, inputEncoding);
+        SSIProcessor ssiProcessor = new SSIProcessor(ssiExternalResolver,
+                debug);
+        PrintWriter printWriter = null;
+        StringWriter stringWriter = null;
+        if (buffered) {
+            stringWriter = new StringWriter();
+            printWriter = new PrintWriter(stringWriter);
+        } else {
+            printWriter = res.getWriter();
+        }
+
+        URLConnection resourceInfo = resource.openConnection();
+        InputStream resourceInputStream = resourceInfo.getInputStream();
+        String encoding = resourceInfo.getContentEncoding();
+        if (encoding == null) {
+            encoding = inputEncoding;
+        }
+        InputStreamReader isr;
+        if (encoding == null) {
+            isr = new InputStreamReader(resourceInputStream);
+        } else {
+            isr = new InputStreamReader(resourceInputStream, encoding);
+        }
+        BufferedReader bufferedReader = new BufferedReader(isr);
+
+        long lastModified = ssiProcessor.process(bufferedReader,
+                resourceInfo.getLastModified(), printWriter);
+        if (lastModified > 0) {
+            res.setDateHeader("last-modified", lastModified);
+        }
+        if (buffered) {
+            printWriter.flush();
+            String text = stringWriter.toString();
+            res.getWriter().write(text);
+        }
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ssi/SSIServletExternalResolver.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ssi/SSIServletExternalResolver.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ssi/SSIServletExternalResolver.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,568 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation. Licensed 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.ssi;
+
+
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.net.URL;
+import java.net.URLConnection;
+import java.net.URLDecoder;
+import java.util.Collection;
+import java.util.Date;
+import java.util.Enumeration;
+import javax.servlet.RequestDispatcher;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import org.apache.catalina.connector.Request;
+import org.apache.coyote.Constants;
+
+/**
+ * An implementation of SSIExternalResolver that is used with servlets.
+ * 
+ * @author Dan Sandberg
+ * @author David Becker
+ * @version $Revision: 425917 $, $Date: 2006-07-26 19:34:34 -0500 (Wed, 26 Jul 2006) $
+ */
+public class SSIServletExternalResolver implements SSIExternalResolver {
+    protected final String VARIABLE_NAMES[] = {"AUTH_TYPE", "CONTENT_LENGTH",
+            "CONTENT_TYPE", "DOCUMENT_NAME", "DOCUMENT_URI",
+            "GATEWAY_INTERFACE", "HTTP_ACCEPT", "HTTP_ACCEPT_ENCODING",
+            "HTTP_ACCEPT_LANGUAGE", "HTTP_CONNECTION", "HTTP_HOST",
+            "HTTP_REFERER", "HTTP_USER_AGENT", "PATH_INFO", "PATH_TRANSLATED",
+            "QUERY_STRING", "QUERY_STRING_UNESCAPED", "REMOTE_ADDR",
+            "REMOTE_HOST", "REMOTE_PORT", "REMOTE_USER", "REQUEST_METHOD",
+            "REQUEST_URI", "SCRIPT_FILENAME", "SCRIPT_NAME", "SERVER_ADDR",
+            "SERVER_NAME", "SERVER_PORT", "SERVER_PROTOCOL", "SERVER_SOFTWARE",
+            "UNIQUE_ID"};
+    protected ServletContext context;
+    protected HttpServletRequest req;
+    protected HttpServletResponse res;
+    protected boolean isVirtualWebappRelative;
+    protected int debug;
+    protected String inputEncoding;
+
+    public SSIServletExternalResolver(ServletContext context,
+            HttpServletRequest req, HttpServletResponse res,
+            boolean isVirtualWebappRelative, int debug, String inputEncoding) {
+        this.context = context;
+        this.req = req;
+        this.res = res;
+        this.isVirtualWebappRelative = isVirtualWebappRelative;
+        this.debug = debug;
+        this.inputEncoding = inputEncoding;
+    }
+
+
+    public void log(String message, Throwable throwable) {
+        //We can't assume that Servlet.log( message, null )
+        //is the same as Servlet.log( message ), since API
+        //doesn't seem to say so.
+        if (throwable != null) {
+            context.log(message, throwable);
+        } else {
+            context.log(message);
+        }
+    }
+
+
+    public void addVariableNames(Collection variableNames) {
+        for (int i = 0; i < VARIABLE_NAMES.length; i++) {
+            String variableName = VARIABLE_NAMES[i];
+            String variableValue = getVariableValue(variableName);
+            if (variableValue != null) {
+                variableNames.add(variableName);
+            }
+        }
+        Enumeration e = req.getAttributeNames();
+        while (e.hasMoreElements()) {
+            String name = (String)e.nextElement();
+            if (!isNameReserved(name)) {
+                variableNames.add(name);
+            }
+        }
+    }
+
+
+    protected Object getReqAttributeIgnoreCase(String targetName) {
+        Object object = null;
+        if (!isNameReserved(targetName)) {
+            object = req.getAttribute(targetName);
+            if (object == null) {
+                Enumeration e = req.getAttributeNames();
+                while (e.hasMoreElements()) {
+                    String name = (String)e.nextElement();
+                    if (targetName.equalsIgnoreCase(name)
+                            && !isNameReserved(name)) {
+                        object = req.getAttribute(name);
+                        if (object != null) {
+                            break;
+                        }
+                    }
+                }
+            }
+        }
+        return object;
+    }
+
+
+    protected boolean isNameReserved(String name) {
+        return name.startsWith("java.") || name.startsWith("javax.")
+                || name.startsWith("sun.");
+    }
+
+
+    public void setVariableValue(String name, String value) {
+        if (!isNameReserved(name)) {
+            req.setAttribute(name, value);
+        }
+    }
+
+
+    public String getVariableValue(String name) {
+        String retVal = null;
+        Object object = getReqAttributeIgnoreCase(name);
+        if (object != null) {
+            retVal = object.toString();
+        } else {
+            retVal = getCGIVariable(name);
+        }
+        return retVal;
+    }
+
+
+    protected String getCGIVariable(String name) {
+        String retVal = null;
+        String[] nameParts = name.toUpperCase().split("_");
+        int requiredParts = 2;
+        if (nameParts.length == 1) {
+            if (nameParts[0].equals("PATH")) {
+                requiredParts = 1;
+                retVal = null; // Not implemented
+            }
+        }
+        else if (nameParts[0].equals("AUTH")) {
+            if (nameParts[1].equals("TYPE")) {
+                retVal = req.getAuthType();
+            }
+        } else if(nameParts[0].equals("CONTENT")) {
+            if (nameParts[1].equals("LENGTH")) {
+                int contentLength = req.getContentLength();
+                if (contentLength >= 0) {
+                    retVal = Integer.toString(contentLength);
+                }
+            } else if (nameParts[1].equals("TYPE")) {
+                retVal = req.getContentType();
+            }
+        } else if (nameParts[0].equals("DOCUMENT")) {
+            if (nameParts[1].equals("NAME")) {
+                String requestURI = req.getRequestURI();
+                retVal = requestURI.substring(requestURI.lastIndexOf('/') + 1);
+            } else if (nameParts[1].equals("URI")) {
+                retVal = req.getRequestURI();
+            }
+        } else if (name.equalsIgnoreCase("GATEWAY_INTERFACE")) {
+            retVal = "CGI/1.1";
+        } else if (nameParts[0].equals("HTTP")) {
+            if (nameParts[1].equals("ACCEPT")) {
+                String accept = null;
+                if (nameParts.length == 2) {
+                    accept = "Accept";
+                } else if (nameParts[2].equals("ENCODING")) {
+                    requiredParts = 3;
+                    accept = "Accept-Encoding";
+                } else if (nameParts[2].equals("LANGUAGE")) {
+                    requiredParts = 3;
+                    accept = "Accept-Language";
+                }
+                if (accept != null) {
+                    Enumeration acceptHeaders = req.getHeaders(accept);
+                    if (acceptHeaders != null)
+                        if (acceptHeaders.hasMoreElements()) {
+                            StringBuffer rv = new StringBuffer(
+                                    (String) acceptHeaders.nextElement());
+                            while (acceptHeaders.hasMoreElements()) {
+                                rv.append(", ");
+                                rv.append((String) acceptHeaders.nextElement());
+                            }
+                        retVal = rv.toString();
+                    }
+                }
+            }
+            else if (nameParts[1].equals("CONNECTION")) {
+                retVal = req.getHeader("Connection");
+            }
+            else if (nameParts[1].equals("HOST")) {
+                retVal = req.getHeader("Host");
+            }
+            else if (nameParts[1].equals("REFERER")) {
+                retVal = req.getHeader("Referer");
+            }
+            else if (nameParts[1].equals("USER"))
+                if (nameParts.length == 3)
+                    if (nameParts[2].equals("AGENT")) {
+                        requiredParts = 3;
+                        retVal = req.getHeader("User-Agent");
+                    }
+
+        } else if (nameParts[0].equals("PATH")) {
+            if (nameParts[1].equals("INFO")) {
+                retVal = req.getPathInfo();
+            } else if (nameParts[1].equals("TRANSLATED")) {
+                retVal = req.getPathTranslated();
+            }
+        } else if (nameParts[0].equals("QUERY")) {
+            if (nameParts[1].equals("STRING")) {
+                String queryString = req.getQueryString();
+                if (nameParts.length == 2) {
+                    //apache displays this as an empty string rather than (none)
+                    retVal = nullToEmptyString(queryString);
+                } else if (nameParts[2].equals("UNESCAPED")) {
+                    requiredParts = 3;
+                    if (queryString != null) {
+                        // Use default as a last resort
+                        String queryStringEncoding =
+                            Constants.DEFAULT_CHARACTER_ENCODING;
+                
+                        String uriEncoding = null;
+                        boolean useBodyEncodingForURI = false;
+                
+                        // Get encoding settings from request / connector if
+                        // possible
+                        String requestEncoding = req.getCharacterEncoding();
+                        if (req instanceof Request) {
+                            uriEncoding =
+                                ((Request)req).getConnector().getURIEncoding();
+                            useBodyEncodingForURI = ((Request)req)
+                                    .getConnector().getUseBodyEncodingForURI();
+                        }
+                
+                        // If valid, apply settings from request / connector
+                        if (uriEncoding != null) {
+                            queryStringEncoding = uriEncoding;
+                        } else if(useBodyEncodingForURI) {
+                            if (requestEncoding != null) {
+                                queryStringEncoding = requestEncoding;
+                            }
+                        }
+                
+                        try {
+                            retVal = URLDecoder.decode(queryString,
+                                    queryStringEncoding);                       
+                        } catch (UnsupportedEncodingException e) {
+                            retVal = queryString;
+                        }
+                    }
+                }
+            }
+        } else if(nameParts[0].equals("REMOTE")) {
+            if (nameParts[1].equals("ADDR")) {
+                retVal = req.getRemoteAddr();
+            } else if (nameParts[1].equals("HOST")) {
+                retVal = req.getRemoteHost();
+            } else if (nameParts[1].equals("IDENT")) {
+                retVal = null; // Not implemented
+            } else if (nameParts[1].equals("PORT")) {
+                retVal = Integer.toString( req.getRemotePort());
+            } else if (nameParts[1].equals("USER")) {
+                retVal = req.getRemoteUser();
+            }
+        } else if(nameParts[0].equals("REQUEST")) {
+            if (nameParts[1].equals("METHOD")) {
+                retVal = req.getMethod();
+            }
+            else if (nameParts[1].equals("URI")) {
+                // If this is an error page, get the original URI
+                retVal = (String) req.getAttribute(
+                        "javax.servlet.forward.request_uri");
+                if (retVal == null) retVal=req.getRequestURI();
+            }
+        } else if (nameParts[0].equals("SCRIPT")) {
+            String scriptName = req.getServletPath();
+            if (nameParts[1].equals("FILENAME")) {
+                retVal = context.getRealPath(scriptName);
+            }
+            else if (nameParts[1].equals("NAME")) {
+                retVal = scriptName;
+            }
+        } else if (nameParts[0].equals("SERVER")) {
+            if (nameParts[1].equals("ADDR")) {
+                retVal = req.getLocalAddr();
+            }
+            if (nameParts[1].equals("NAME")) {
+                retVal = req.getServerName();
+            } else if (nameParts[1].equals("PORT")) {
+                retVal = Integer.toString(req.getServerPort());
+            } else if (nameParts[1].equals("PROTOCOL")) {
+                retVal = req.getProtocol();
+            } else if (nameParts[1].equals("SOFTWARE")) {
+                StringBuffer rv = new StringBuffer(context.getServerInfo());
+                rv.append(" ");
+                rv.append(System.getProperty("java.vm.name"));
+                rv.append("/");
+                rv.append(System.getProperty("java.vm.version"));
+                rv.append(" ");
+                rv.append(System.getProperty("os.name"));
+                retVal = rv.toString();
+            }
+        } else if (name.equalsIgnoreCase("UNIQUE_ID")) {
+            retVal = req.getRequestedSessionId();
+        }
+        if (requiredParts != nameParts.length) return null;
+            return retVal;
+    }
+
+    public Date getCurrentDate() {
+        return new Date();
+    }
+
+
+    protected String nullToEmptyString(String string) {
+        String retVal = string;
+        if (retVal == null) {
+            retVal = "";
+        }
+        return retVal;
+    }
+
+
+    protected String getPathWithoutFileName(String servletPath) {
+        String retVal = null;
+        int lastSlash = servletPath.lastIndexOf('/');
+        if (lastSlash >= 0) {
+            //cut off file namee
+            retVal = servletPath.substring(0, lastSlash + 1);
+        }
+        return retVal;
+    }
+
+
+    protected String getPathWithoutContext(String servletPath) {
+        String retVal = null;
+        int secondSlash = servletPath.indexOf('/', 1);
+        if (secondSlash >= 0) {
+            //cut off context
+            retVal = servletPath.substring(secondSlash);
+        }
+        return retVal;
+    }
+
+
+    protected String getAbsolutePath(String path) throws IOException {
+        String pathWithoutContext = SSIServletRequestUtil.getRelativePath(req);
+        String prefix = getPathWithoutFileName(pathWithoutContext);
+        if (prefix == null) {
+            throw new IOException("Couldn't remove filename from path: "
+                    + pathWithoutContext);
+        }
+        String fullPath = prefix + path;
+        String retVal = SSIServletRequestUtil.normalize(fullPath);
+        if (retVal == null) {
+            throw new IOException("Normalization yielded null on path: "
+                    + fullPath);
+        }
+        return retVal;
+    }
+
+
+    protected ServletContextAndPath getServletContextAndPathFromNonVirtualPath(
+            String nonVirtualPath) throws IOException {
+        if (nonVirtualPath.startsWith("/") || nonVirtualPath.startsWith("\\")) {
+            throw new IOException("A non-virtual path can't be absolute: "
+                    + nonVirtualPath);
+        }
+        if (nonVirtualPath.indexOf("../") >= 0) {
+            throw new IOException("A non-virtual path can't contain '../' : "
+                    + nonVirtualPath);
+        }
+        String path = getAbsolutePath(nonVirtualPath);
+        ServletContextAndPath csAndP = new ServletContextAndPath(
+                context, path);
+        return csAndP;
+    }
+
+
+    protected ServletContextAndPath getServletContextAndPathFromVirtualPath(
+            String virtualPath) throws IOException {
+
+        if (!virtualPath.startsWith("/") && !virtualPath.startsWith("\\")) {
+            return new ServletContextAndPath(context,
+                    getAbsolutePath(virtualPath));
+        } else {
+            String normalized = SSIServletRequestUtil.normalize(virtualPath);
+            if (isVirtualWebappRelative) {
+                return new ServletContextAndPath(context, normalized);
+            } else {
+                ServletContext normContext = context.getContext(normalized);
+                if (normContext == null) {
+                    throw new IOException("Couldn't get context for path: "
+                            + normalized);
+                }
+                //If it's the root context, then there is no context element
+                // to remove,
+                // ie:
+                // '/file1.shtml' vs '/appName1/file1.shtml'
+                if (!isRootContext(normContext)) {
+                    String noContext = getPathWithoutContext(normalized);
+                    if (noContext == null) {
+                        throw new IOException(
+                                "Couldn't remove context from path: "
+                                        + normalized);
+                    }
+                    return new ServletContextAndPath(normContext, noContext);
+                } else {
+                    return new ServletContextAndPath(normContext, normalized);
+                }
+            }
+        }
+    }
+
+
+    //Assumes servletContext is not-null
+    //Assumes that identity comparison will be true for the same context
+    //Assuming the above, getContext("/") will be non-null as long as the root
+    // context is
+    // accessible.
+    //If it isn't, then servletContext can't be the root context anyway, hence
+    // they will
+    // not match.
+    protected boolean isRootContext(ServletContext servletContext) {
+        return servletContext == servletContext.getContext("/");
+    }
+
+
+    protected ServletContextAndPath getServletContextAndPath(
+            String originalPath, boolean virtual) throws IOException {
+        ServletContextAndPath csAndP = null;
+        if (debug > 0) {
+            log("SSIServletExternalResolver.getServletContextAndPath( "
+                    + originalPath + ", " + virtual + ")", null);
+        }
+        if (virtual) {
+            csAndP = getServletContextAndPathFromVirtualPath(originalPath);
+        } else {
+            csAndP = getServletContextAndPathFromNonVirtualPath(originalPath);
+        }
+        return csAndP;
+    }
+
+
+    protected URLConnection getURLConnection(String originalPath,
+            boolean virtual) throws IOException {
+        ServletContextAndPath csAndP = getServletContextAndPath(originalPath,
+                virtual);
+        ServletContext context = csAndP.getServletContext();
+        String path = csAndP.getPath();
+        URL url = context.getResource(path);
+        if (url == null) {
+            throw new IOException("Context did not contain resource: " + path);
+        }
+        URLConnection urlConnection = url.openConnection();
+        return urlConnection;
+    }
+
+
+    public long getFileLastModified(String path, boolean virtual)
+            throws IOException {
+        long lastModified = 0;
+        try {
+            URLConnection urlConnection = getURLConnection(path, virtual);
+            lastModified = urlConnection.getLastModified();
+        } catch (IOException e) {
+            // Ignore this. It will always fail for non-file based includes
+        }
+        return lastModified;
+    }
+
+
+    public long getFileSize(String path, boolean virtual) throws IOException {
+        long fileSize = -1;
+        try {
+            URLConnection urlConnection = getURLConnection(path, virtual);
+            fileSize = urlConnection.getContentLength();
+        } catch (IOException e) {
+            // Ignore this. It will always fail for non-file based includes
+        }
+        return fileSize;
+    }
+
+
+    //We are making lots of unnecessary copies of the included data here. If
+    //someone ever complains that this is slow, we should connect the included
+    // stream to the print writer that SSICommand uses.
+    public String getFileText(String originalPath, boolean virtual)
+            throws IOException {
+        try {
+            ServletContextAndPath csAndP = getServletContextAndPath(
+                    originalPath, virtual);
+            ServletContext context = csAndP.getServletContext();
+            String path = csAndP.getPath();
+            RequestDispatcher rd = context.getRequestDispatcher(path);
+            if (rd == null) {
+                throw new IOException(
+                        "Couldn't get request dispatcher for path: " + path);
+            }
+            ByteArrayServletOutputStream basos =
+                new ByteArrayServletOutputStream();
+            ResponseIncludeWrapper responseIncludeWrapper =
+                new ResponseIncludeWrapper(context, req, res, basos);
+            rd.include(req, responseIncludeWrapper);
+            //We can't assume the included servlet flushed its output
+            responseIncludeWrapper.flushOutputStreamOrWriter();
+            byte[] bytes = basos.toByteArray();
+
+            //Assume platform default encoding unless otherwise specified
+            String retVal;
+            if (inputEncoding == null) {
+                retVal = new String( bytes );
+            } else {
+                retVal = new String (bytes, inputEncoding);
+            }
+
+            //make an assumption that an empty response is a failure. This is
+            // a problem
+            // if a truly empty file
+            //were included, but not sure how else to tell.
+            if (retVal.equals("") && !req.getMethod().equalsIgnoreCase(
+                    org.apache.coyote.http11.Constants.HEAD)) {
+                throw new IOException("Couldn't find file: " + path);
+            }
+            return retVal;
+        } catch (ServletException e) {
+            throw new IOException("Couldn't include file: " + originalPath
+                    + " because of ServletException: " + e.getMessage());
+        }
+    }
+
+    protected class ServletContextAndPath {
+        protected ServletContext servletContext;
+        protected String path;
+
+
+        public ServletContextAndPath(ServletContext servletContext,
+                                     String path) {
+            this.servletContext = servletContext;
+            this.path = path;
+        }
+
+
+        public ServletContext getServletContext() {
+            return servletContext;
+        }
+
+
+        public String getPath() {
+            return path;
+        }
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ssi/SSIServletRequestUtil.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ssi/SSIServletRequestUtil.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ssi/SSIServletRequestUtil.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,71 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation. Licensed 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.ssi;
+
+
+import javax.servlet.http.HttpServletRequest;
+import org.apache.catalina.util.RequestUtil;
+public class SSIServletRequestUtil {
+    /**
+     * Return the relative path associated with this servlet. Taken from
+     * DefaultServlet.java. Perhaps this should be put in
+     * org.apache.catalina.util somewhere? Seems like it would be widely used.
+     * 
+     * @param request
+     *            The servlet request we are processing
+     */
+    public static String getRelativePath(HttpServletRequest request) {
+        // Are we being processed by a RequestDispatcher.include()?
+        if (request.getAttribute("javax.servlet.include.request_uri") != null) {
+            String result = (String)request
+                    .getAttribute("javax.servlet.include.path_info");
+            if (result == null)
+                result = (String)request
+                        .getAttribute("javax.servlet.include.servlet_path");
+            if ((result == null) || (result.equals(""))) result = "/";
+            return (result);
+        }
+        // No, extract the desired path directly from the request
+        String result = request.getPathInfo();
+        if (result == null) {
+            result = request.getServletPath();
+        }
+        if ((result == null) || (result.equals(""))) {
+            result = "/";
+        }
+        return normalize(result);
+    }
+
+
+    /**
+     * Return a context-relative path, beginning with a "/", that represents
+     * the canonical version of the specified path after ".." and "." elements
+     * are resolved out. If the specified path attempts to go outside the
+     * boundaries of the current context (i.e. too many ".." path elements are
+     * present), return <code>null</code> instead. This normalize should be
+     * the same as DefaultServlet.normalize, which is almost the same ( see
+     * source code below ) as RequestUtil.normalize. Do we need all this
+     * duplication?
+     * 
+     * @param path
+     *            Path to be normalized
+     */
+    public static String normalize(String path) {
+        if (path == null) return null;
+        String normalized = path;
+        //Why doesn't RequestUtil do this??
+        // Normalize the slashes and add leading slash if necessary
+        if (normalized.indexOf('\\') >= 0)
+            normalized = normalized.replace('\\', '/');
+        normalized = RequestUtil.normalize(path);
+        return normalized;
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ssi/SSISet.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ssi/SSISet.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ssi/SSISet.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,58 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation. Licensed 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.ssi;
+
+
+import java.io.PrintWriter;
+/**
+ * Implements the Server-side #set command
+ * 
+ * @author Paul Speed
+ * @author Dan Sandberg
+ * @author David Becker
+ * @version $Revision: 303882 $, $Date: 2005-04-23 05:22:37 -0500 (Sat, 23 Apr 2005) $
+ */
+public class SSISet implements SSICommand {
+    /**
+     * @see SSICommand
+     */
+    public long process(SSIMediator ssiMediator, String commandName,
+            String[] paramNames, String[] paramValues, PrintWriter writer)
+            throws SSIStopProcessingException {
+        long lastModified = 0;
+        String errorMessage = ssiMediator.getConfigErrMsg();
+        String variableName = null;
+        for (int i = 0; i < paramNames.length; i++) {
+            String paramName = paramNames[i];
+            String paramValue = paramValues[i];
+            if (paramName.equalsIgnoreCase("var")) {
+                variableName = paramValue;
+            } else if (paramName.equalsIgnoreCase("value")) {
+                if (variableName != null) {
+                    String substitutedValue = ssiMediator
+                            .substituteVariables(paramValue);
+                    ssiMediator.setVariableValue(variableName,
+                            substitutedValue);
+                    lastModified = System.currentTimeMillis();
+                } else {
+                    ssiMediator.log("#set--no variable specified");
+                    writer.write(errorMessage);
+                    throw new SSIStopProcessingException();
+                }
+            } else {
+                ssiMediator.log("#set--Invalid attribute: " + paramName);
+                writer.write(errorMessage);
+                throw new SSIStopProcessingException();
+            }
+        }
+        return lastModified;
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ssi/SSIStopProcessingException.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ssi/SSIStopProcessingException.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ssi/SSIStopProcessingException.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,24 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation. Licensed 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.ssi;
+
+
+/**
+ * Exception used to tell SSIProcessor that it should stop processing SSI
+ * commands. This is used to mimick the Apache behavior in #set with invalid
+ * attributes.
+ * 
+ * @author Paul Speed
+ * @author Dan Sandberg
+ * @version $Revision: 303166 $, $Date: 2004-09-01 13:33:33 -0500 (Wed, 01 Sep 2004) $
+ */
+public class SSIStopProcessingException extends Exception {
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ssi/package.html
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ssi/package.html	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/ssi/package.html	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,16 @@
+<body>
+<p>This package contains code that is used by the SsiInvoker.</p>
+<p>This class consists of <code>SsiMediator.java</code> which works as a
+mediator between the different SsiCommands. To add a command you have to
+implement the <code>SsiCommand</code> interface and extend the
+<code>SsiMediator</code>. Commands currently implemented are</p>
+
+<ul>
+<li><b>SsiConfig</b> - Implementation of the NCSA command Config i.e. &lt;!--#config errmsg="error?"--&gt;</li>
+<li><b>SsiEcho</b> - Implementation of the NCSA command Echo i.e. &lt;!--#echo var="SERVER_NAME"--&gt;</li>
+<li><b>SsiExec</b> - Not implemented</li>
+<li><b>SsiFlastMod</b> - Implementation of the NCSA command flastmod i.e. &lt;!--#flastmod virtual="file"--&gt;</li>
+<li><b>SsiFsize</b> - Implementation of the NCSA command fsize i.e. &lt;!--#fsize file="file"--&gt;</li>
+<li><b>SsiInclude</b> - Implementation of the NCSA command Include i.e. &lt;!--#config virtual="includefile"--&gt;</li>
+</ul>
+</body>

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/startup/Authenticators.properties
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/startup/Authenticators.properties	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/startup/Authenticators.properties	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,5 @@
+BASIC=org.apache.catalina.authenticator.BasicAuthenticator
+CLIENT-CERT=org.apache.catalina.authenticator.SSLAuthenticator
+DIGEST=org.apache.catalina.authenticator.DigestAuthenticator
+FORM=org.apache.catalina.authenticator.FormAuthenticator
+NONE=org.apache.catalina.authenticator.NonLoginAuthenticator

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/startup/Bootstrap.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/startup/Bootstrap.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/startup/Bootstrap.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,517 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.startup;
+
+
+import java.io.File;
+import java.lang.reflect.Method;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.StringTokenizer;
+
+import javax.management.MBeanServer;
+import javax.management.MBeanServerFactory;
+import javax.management.ObjectName;
+
+import org.apache.catalina.security.SecurityClassLoad;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+
+/**
+ * Boostrap loader for Catalina.  This application constructs a class loader
+ * for use in loading the Catalina internal classes (by accumulating all of the
+ * JAR files found in the "server" directory under "catalina.home"), and
+ * starts the regular execution of the container.  The purpose of this
+ * roundabout approach is to keep the Catalina internal classes (and any
+ * other classes they depend on, such as an XML parser) out of the system
+ * class path and therefore not visible to application level classes.
+ *
+ * @author Craig R. McClanahan
+ * @author Remy Maucherat
+ * @version $Revision: 393434 $ $Date: 2006-04-12 05:55:14 -0500 (Wed, 12 Apr 2006) $
+ */
+
+public final class Bootstrap {
+
+    private static Log log = LogFactory.getLog(Bootstrap.class);
+    
+    // -------------------------------------------------------------- Constants
+
+
+    protected static final String CATALINA_HOME_TOKEN = "${catalina.home}";
+    protected static final String CATALINA_BASE_TOKEN = "${catalina.base}";
+
+
+    // ------------------------------------------------------- Static Variables
+
+
+    private static final String JMX_ERROR_MESSAGE =
+        "This release of Apache Tomcat was packaged to run on J2SE 5.0 \n"
+        + "or later. It can be run on earlier JVMs by downloading and \n"
+        + "installing a compatibility package from the Apache Tomcat \n"
+        + "binary download page.";
+
+
+    /**
+     * Daemon object used by main.
+     */
+    private static Bootstrap daemon = null;
+
+
+    // -------------------------------------------------------------- Variables
+
+
+    /**
+     * Daemon reference.
+     */
+    private Object catalinaDaemon = null;
+
+
+    protected ClassLoader commonLoader = null;
+    protected ClassLoader catalinaLoader = null;
+    protected ClassLoader sharedLoader = null;
+
+
+    // -------------------------------------------------------- Private Methods
+
+
+    private void initClassLoaders() {
+        try {
+            commonLoader = createClassLoader("common", null);
+            if( commonLoader == null ) {
+                // no config file, default to this loader - we might be in a 'single' env.
+                commonLoader=this.getClass().getClassLoader();
+            }
+            catalinaLoader = createClassLoader("server", commonLoader);
+            sharedLoader = createClassLoader("shared", commonLoader);
+        } catch (Throwable t) {
+            log.error("Class loader creation threw exception", t);
+            System.exit(1);
+        }
+    }
+
+
+    private ClassLoader createClassLoader(String name, ClassLoader parent)
+        throws Exception {
+
+        String value = CatalinaProperties.getProperty(name + ".loader");
+        if ((value == null) || (value.equals("")))
+            return parent;
+
+        ArrayList repositoryLocations = new ArrayList();
+        ArrayList repositoryTypes = new ArrayList();
+        int i;
+ 
+        StringTokenizer tokenizer = new StringTokenizer(value, ",");
+        while (tokenizer.hasMoreElements()) {
+            String repository = tokenizer.nextToken();
+
+            // Local repository
+            boolean replace = false;
+            String before = repository;
+            while ((i=repository.indexOf(CATALINA_HOME_TOKEN))>=0) {
+                replace=true;
+                if (i>0) {
+                repository = repository.substring(0,i) + getCatalinaHome() 
+                    + repository.substring(i+CATALINA_HOME_TOKEN.length());
+                } else {
+                    repository = getCatalinaHome() 
+                        + repository.substring(CATALINA_HOME_TOKEN.length());
+                }
+            }
+            while ((i=repository.indexOf(CATALINA_BASE_TOKEN))>=0) {
+                replace=true;
+                if (i>0) {
+                repository = repository.substring(0,i) + getCatalinaBase() 
+                    + repository.substring(i+CATALINA_BASE_TOKEN.length());
+                } else {
+                    repository = getCatalinaBase() 
+                        + repository.substring(CATALINA_BASE_TOKEN.length());
+                }
+            }
+            if (replace && log.isDebugEnabled())
+                log.debug("Expanded " + before + " to " + replace);
+
+            // Check for a JAR URL repository
+            try {
+                URL url=new URL(repository);
+                repositoryLocations.add(repository);
+                repositoryTypes.add(ClassLoaderFactory.IS_URL);
+                continue;
+            } catch (MalformedURLException e) {
+                // Ignore
+            }
+
+            if (repository.endsWith("*.jar")) {
+                repository = repository.substring
+                    (0, repository.length() - "*.jar".length());
+                repositoryLocations.add(repository);
+                repositoryTypes.add(ClassLoaderFactory.IS_GLOB);
+            } else if (repository.endsWith(".jar")) {
+                repositoryLocations.add(repository);
+                repositoryTypes.add(ClassLoaderFactory.IS_JAR);
+            } else {
+                repositoryLocations.add(repository);
+                repositoryTypes.add(ClassLoaderFactory.IS_DIR);
+            }
+        }
+
+        String[] locations = (String[]) repositoryLocations.toArray(new String[0]);
+        Integer[] types = (Integer[]) repositoryTypes.toArray(new Integer[0]);
+ 
+        ClassLoader classLoader = ClassLoaderFactory.createClassLoader
+            (locations, types, parent);
+
+        // Retrieving MBean server
+        MBeanServer mBeanServer = null;
+        if (MBeanServerFactory.findMBeanServer(null).size() > 0) {
+            mBeanServer =
+                (MBeanServer) MBeanServerFactory.findMBeanServer(null).get(0);
+        } else {
+            mBeanServer = MBeanServerFactory.createMBeanServer();
+        }
+
+        // Register the server classloader
+        ObjectName objectName =
+            new ObjectName("Catalina:type=ServerClassLoader,name=" + name);
+        mBeanServer.registerMBean(classLoader, objectName);
+
+        return classLoader;
+
+    }
+
+
+    /**
+     * Initialize daemon.
+     */
+    public void init()
+        throws Exception
+    {
+
+        // Set Catalina path
+        setCatalinaHome();
+        setCatalinaBase();
+
+        initClassLoaders();
+
+        Thread.currentThread().setContextClassLoader(catalinaLoader);
+
+        SecurityClassLoad.securityClassLoad(catalinaLoader);
+
+        // Load our startup class and call its process() method
+        if (log.isDebugEnabled())
+            log.debug("Loading startup class");
+        Class startupClass =
+            catalinaLoader.loadClass
+            ("org.apache.catalina.startup.Catalina");
+        Object startupInstance = startupClass.newInstance();
+
+        // Set the shared extensions class loader
+        if (log.isDebugEnabled())
+            log.debug("Setting startup class properties");
+        String methodName = "setParentClassLoader";
+        Class paramTypes[] = new Class[1];
+        paramTypes[0] = Class.forName("java.lang.ClassLoader");
+        Object paramValues[] = new Object[1];
+        paramValues[0] = sharedLoader;
+        Method method =
+            startupInstance.getClass().getMethod(methodName, paramTypes);
+        method.invoke(startupInstance, paramValues);
+
+        catalinaDaemon = startupInstance;
+
+    }
+
+
+    /**
+     * Load daemon.
+     */
+    private void load(String[] arguments)
+        throws Exception {
+
+        // Call the load() method
+        String methodName = "load";
+        Object param[];
+        Class paramTypes[];
+        if (arguments==null || arguments.length==0) {
+            paramTypes = null;
+            param = null;
+        } else {
+            paramTypes = new Class[1];
+            paramTypes[0] = arguments.getClass();
+            param = new Object[1];
+            param[0] = arguments;
+        }
+        Method method = 
+            catalinaDaemon.getClass().getMethod(methodName, paramTypes);
+        if (log.isDebugEnabled())
+            log.debug("Calling startup class " + method);
+        method.invoke(catalinaDaemon, param);
+
+    }
+
+
+    // ----------------------------------------------------------- Main Program
+
+
+    /**
+     * Load the Catalina daemon.
+     */
+    public void init(String[] arguments)
+        throws Exception {
+
+        init();
+        load(arguments);
+
+    }
+
+
+    /**
+     * Start the Catalina daemon.
+     */
+    public void start()
+        throws Exception {
+        if( catalinaDaemon==null ) init();
+
+        Method method = catalinaDaemon.getClass().getMethod("start", (Class [] )null);
+        method.invoke(catalinaDaemon, (Object [])null);
+
+    }
+
+
+    /**
+     * Stop the Catalina Daemon.
+     */
+    public void stop()
+        throws Exception {
+
+        Method method = catalinaDaemon.getClass().getMethod("stop", (Class [] ) null);
+        method.invoke(catalinaDaemon, (Object [] ) null);
+
+    }
+
+
+    /**
+     * Stop the standlone server.
+     */
+    public void stopServer()
+        throws Exception {
+
+        Method method = 
+            catalinaDaemon.getClass().getMethod("stopServer", (Class []) null);
+        method.invoke(catalinaDaemon, (Object []) null);
+
+    }
+
+
+   /**
+     * Stop the standlone server.
+     */
+    public void stopServer(String[] arguments)
+        throws Exception {
+
+        Object param[];
+        Class paramTypes[];
+        if (arguments==null || arguments.length==0) {
+            paramTypes = null;
+            param = null;
+        } else {
+            paramTypes = new Class[1];
+            paramTypes[0] = arguments.getClass();
+            param = new Object[1];
+            param[0] = arguments;
+        }
+        Method method = 
+            catalinaDaemon.getClass().getMethod("stopServer", paramTypes);
+        method.invoke(catalinaDaemon, param);
+
+    }
+
+
+    /**
+     * Set flag.
+     */
+    public void setAwait(boolean await)
+        throws Exception {
+
+        Class paramTypes[] = new Class[1];
+        paramTypes[0] = Boolean.TYPE;
+        Object paramValues[] = new Object[1];
+        paramValues[0] = new Boolean(await);
+        Method method = 
+            catalinaDaemon.getClass().getMethod("setAwait", paramTypes);
+        method.invoke(catalinaDaemon, paramValues);
+
+    }
+
+    public boolean getAwait()
+        throws Exception
+    {
+        Class paramTypes[] = new Class[0];
+        Object paramValues[] = new Object[0];
+        Method method =
+            catalinaDaemon.getClass().getMethod("getAwait", paramTypes);
+        Boolean b=(Boolean)method.invoke(catalinaDaemon, paramValues);
+        return b.booleanValue();
+    }
+
+
+    /**
+     * Destroy the Catalina Daemon.
+     */
+    public void destroy() {
+
+        // FIXME
+
+    }
+
+
+    /**
+     * Main method, used for testing only.
+     *
+     * @param args Command line arguments to be processed
+     */
+    public static void main(String args[]) {
+
+        try {
+            // Attempt to load JMX class
+            new ObjectName("test:foo=bar");
+        } catch (Throwable t) {
+            System.out.println(JMX_ERROR_MESSAGE);
+            try {
+                // Give users some time to read the message before exiting
+                Thread.sleep(5000);
+            } catch (Exception ex) {
+            }
+            return;
+        }
+
+        if (daemon == null) {
+            daemon = new Bootstrap();
+            try {
+                daemon.init();
+            } catch (Throwable t) {
+                t.printStackTrace();
+                return;
+            }
+        }
+
+        try {
+            String command = "start";
+            if (args.length > 0) {
+                command = args[args.length - 1];
+            }
+
+            if (command.equals("startd")) {
+                args[0] = "start";
+                daemon.load(args);
+                daemon.start();
+            } else if (command.equals("stopd")) {
+                args[0] = "stop";
+                daemon.stop();
+            } else if (command.equals("start")) {
+                daemon.setAwait(true);
+                daemon.load(args);
+                daemon.start();
+            } else if (command.equals("stop")) {
+                daemon.stopServer(args);
+            } else {
+                log.warn("Bootstrap: command \"" + command + "\" does not exist.");
+            }
+        } catch (Throwable t) {
+            t.printStackTrace();
+        }
+
+    }
+
+    public void setCatalinaHome(String s) {
+        System.setProperty( "catalina.home", s );
+    }
+
+    public void setCatalinaBase(String s) {
+        System.setProperty( "catalina.base", s );
+    }
+
+
+    /**
+     * Set the <code>catalina.base</code> System property to the current
+     * working directory if it has not been set.
+     */
+    private void setCatalinaBase() {
+
+        if (System.getProperty("catalina.base") != null)
+            return;
+        if (System.getProperty("catalina.home") != null)
+            System.setProperty("catalina.base",
+                               System.getProperty("catalina.home"));
+        else
+            System.setProperty("catalina.base",
+                               System.getProperty("user.dir"));
+
+    }
+
+
+    /**
+     * Set the <code>catalina.home</code> System property to the current
+     * working directory if it has not been set.
+     */
+    private void setCatalinaHome() {
+
+        if (System.getProperty("catalina.home") != null)
+            return;
+        File bootstrapJar = 
+            new File(System.getProperty("user.dir"), "bootstrap.jar");
+        if (bootstrapJar.exists()) {
+            try {
+                System.setProperty
+                    ("catalina.home", 
+                     (new File(System.getProperty("user.dir"), ".."))
+                     .getCanonicalPath());
+            } catch (Exception e) {
+                // Ignore
+                System.setProperty("catalina.home",
+                                   System.getProperty("user.dir"));
+            }
+        } else {
+            System.setProperty("catalina.home",
+                               System.getProperty("user.dir"));
+        }
+
+    }
+
+
+    /**
+     * Get the value of the catalina.home environment variable.
+     */
+    public static String getCatalinaHome() {
+        return System.getProperty("catalina.home",
+                                  System.getProperty("user.dir"));
+    }
+
+
+    /**
+     * Get the value of the catalina.base environment variable.
+     */
+    public static String getCatalinaBase() {
+        return System.getProperty("catalina.base", getCatalinaHome());
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/startup/Catalina.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/startup/Catalina.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/startup/Catalina.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,688 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.startup;
+
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.net.Socket;
+import org.apache.catalina.Container;
+import org.apache.catalina.Lifecycle;
+import org.apache.catalina.LifecycleException;
+import org.apache.catalina.Server;
+import org.apache.catalina.core.StandardServer;
+import org.apache.tomcat.util.digester.Digester;
+import org.apache.tomcat.util.digester.Rule;
+import org.xml.sax.Attributes;
+import org.xml.sax.InputSource;
+
+
+/**
+ * Startup/Shutdown shell program for Catalina.  The following command line
+ * options are recognized:
+ * <ul>
+ * <li><b>-config {pathname}</b> - Set the pathname of the configuration file
+ *     to be processed.  If a relative path is specified, it will be
+ *     interpreted as relative to the directory pathname specified by the
+ *     "catalina.base" system property.   [conf/server.xml]
+ * <li><b>-help</b> - Display usage information.
+ * <li><b>-stop</b> - Stop the currently running instance of Catalina.
+ * </u>
+ *
+ * Should do the same thing as Embedded, but using a server.xml file.
+ *
+ * @author Craig R. McClanahan
+ * @author Remy Maucherat
+ * @version $Revision: 380229 $ $Date: 2006-02-23 15:28:29 -0600 (Thu, 23 Feb 2006) $
+ */
+
+public class Catalina extends Embedded {
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * Pathname to the server configuration file.
+     */
+    protected String configFile = "conf/server.xml";
+
+    // XXX Should be moved to embedded
+    /**
+     * The shared extensions class loader for this server.
+     */
+    protected ClassLoader parentClassLoader =
+        Catalina.class.getClassLoader();
+
+
+    /**
+     * The server component we are starting or stopping
+     */
+    protected Server server = null;
+
+
+    /**
+     * Are we starting a new server?
+     */
+    protected boolean starting = false;
+
+
+    /**
+     * Are we stopping an existing server?
+     */
+    protected boolean stopping = false;
+
+
+    /**
+     * Use shutdown hook flag.
+     */
+    protected boolean useShutdownHook = true;
+
+
+    /**
+     * Shutdown hook.
+     */
+    protected Thread shutdownHook = null;
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    public void setConfig(String file) {
+        configFile = file;
+    }
+
+
+    public void setConfigFile(String file) {
+        configFile = file;
+    }
+
+
+    public String getConfigFile() {
+        return configFile;
+    }
+
+
+    public void setUseShutdownHook(boolean useShutdownHook) {
+        this.useShutdownHook = useShutdownHook;
+    }
+
+
+    public boolean getUseShutdownHook() {
+        return useShutdownHook;
+    }
+
+
+    /**
+     * Set the shared extensions class loader.
+     *
+     * @param parentClassLoader The shared extensions class loader.
+     */
+    public void setParentClassLoader(ClassLoader parentClassLoader) {
+
+        this.parentClassLoader = parentClassLoader;
+
+    }
+
+
+    /**
+     * Set the server instance we are configuring.
+     *
+     * @param server The new server
+     */
+    public void setServer(Server server) {
+
+        this.server = server;
+
+    }
+
+    // ----------------------------------------------------------- Main Program
+
+    /**
+     * The application main program.
+     *
+     * @param args Command line arguments
+     */
+    public static void main(String args[]) {
+        (new Catalina()).process(args);
+    }
+
+
+    /**
+     * The instance main program.
+     *
+     * @param args Command line arguments
+     */
+    public void process(String args[]) {
+
+        setAwait(true);
+        setCatalinaHome();
+        setCatalinaBase();
+        try {
+            if (arguments(args)) {
+                if (starting) {
+                    load(args);
+                    start();
+                } else if (stopping) {
+                    stopServer();
+                }
+            }
+        } catch (Exception e) {
+            e.printStackTrace(System.out);
+        }
+    }
+
+
+    // ------------------------------------------------------ Protected Methods
+
+
+    /**
+     * Process the specified command line arguments, and return
+     * <code>true</code> if we should continue processing; otherwise
+     * return <code>false</code>.
+     *
+     * @param args Command line arguments to process
+     */
+    protected boolean arguments(String args[]) {
+
+        boolean isConfig = false;
+
+        if (args.length < 1) {
+            usage();
+            return (false);
+        }
+
+        for (int i = 0; i < args.length; i++) {
+            if (isConfig) {
+                configFile = args[i];
+                isConfig = false;
+            } else if (args[i].equals("-config")) {
+                isConfig = true;
+            } else if (args[i].equals("-nonaming")) {
+                setUseNaming( false );
+            } else if (args[i].equals("-help")) {
+                usage();
+                return (false);
+            } else if (args[i].equals("start")) {
+                starting = true;
+                stopping = false;
+            } else if (args[i].equals("stop")) {
+                starting = false;
+                stopping = true;
+            } else {
+                usage();
+                return (false);
+            }
+        }
+
+        return (true);
+
+    }
+
+
+    /**
+     * Return a File object representing our configuration file.
+     */
+    protected File configFile() {
+
+        File file = new File(configFile);
+        if (!file.isAbsolute())
+            file = new File(System.getProperty("catalina.base"), configFile);
+        return (file);
+
+    }
+
+
+    /**
+     * Create and configure the Digester we will be using for startup.
+     */
+    protected Digester createStartDigester() {
+        long t1=System.currentTimeMillis();
+        // Initialize the digester
+        Digester digester = new Digester();
+        digester.setValidating(false);
+        digester.setClassLoader(StandardServer.class.getClassLoader());
+
+        // Configure the actions we will be using
+        digester.addObjectCreate("Server",
+                                 "org.apache.catalina.core.StandardServer",
+                                 "className");
+        digester.addSetProperties("Server");
+        digester.addSetNext("Server",
+                            "setServer",
+                            "org.apache.catalina.Server");
+
+        digester.addObjectCreate("Server/GlobalNamingResources",
+                                 "org.apache.catalina.deploy.NamingResources");
+        digester.addSetProperties("Server/GlobalNamingResources");
+        digester.addSetNext("Server/GlobalNamingResources",
+                            "setGlobalNamingResources",
+                            "org.apache.catalina.deploy.NamingResources");
+
+        digester.addObjectCreate("Server/Listener",
+                                 null, // MUST be specified in the element
+                                 "className");
+        digester.addSetProperties("Server/Listener");
+        digester.addSetNext("Server/Listener",
+                            "addLifecycleListener",
+                            "org.apache.catalina.LifecycleListener");
+
+        digester.addObjectCreate("Server/Service",
+                                 "org.apache.catalina.core.StandardService",
+                                 "className");
+        digester.addSetProperties("Server/Service");
+        digester.addSetNext("Server/Service",
+                            "addService",
+                            "org.apache.catalina.Service");
+
+        digester.addObjectCreate("Server/Service/Listener",
+                                 null, // MUST be specified in the element
+                                 "className");
+        digester.addSetProperties("Server/Service/Listener");
+        digester.addSetNext("Server/Service/Listener",
+                            "addLifecycleListener",
+                            "org.apache.catalina.LifecycleListener");
+
+        digester.addRule("Server/Service/Connector",
+                         new ConnectorCreateRule());
+        digester.addRule("Server/Service/Connector", 
+                         new SetAllPropertiesRule());
+        digester.addSetNext("Server/Service/Connector",
+                            "addConnector",
+                            "org.apache.catalina.connector.Connector");
+
+        digester.addObjectCreate("Server/Service/Connector/Listener",
+                                 null, // MUST be specified in the element
+                                 "className");
+        digester.addSetProperties("Server/Service/Connector/Listener");
+        digester.addSetNext("Server/Service/Connector/Listener",
+                            "addLifecycleListener",
+                            "org.apache.catalina.LifecycleListener");
+
+        // Add RuleSets for nested elements
+        digester.addRuleSet(new NamingRuleSet("Server/GlobalNamingResources/"));
+        digester.addRuleSet(new EngineRuleSet("Server/Service/"));
+        digester.addRuleSet(new HostRuleSet("Server/Service/Engine/"));
+        digester.addRuleSet(new ContextRuleSet("Server/Service/Engine/Host/"));
+        digester.addRuleSet(ClusterRuleSetFactory.getClusterRuleSet("Server/Service/Engine/Host/Cluster/"));
+        digester.addRuleSet(new NamingRuleSet("Server/Service/Engine/Host/Context/"));
+
+        // When the 'engine' is found, set the parentClassLoader.
+        digester.addRule("Server/Service/Engine",
+                         new SetParentClassLoaderRule(parentClassLoader));
+        digester.addRuleSet(ClusterRuleSetFactory.getClusterRuleSet("Server/Service/Engine/Cluster/"));
+
+        long t2=System.currentTimeMillis();
+        if (log.isDebugEnabled())
+            log.debug("Digester for server.xml created " + ( t2-t1 ));
+        return (digester);
+
+    }
+
+
+    /**
+     * Create and configure the Digester we will be using for shutdown.
+     */
+    protected Digester createStopDigester() {
+
+        // Initialize the digester
+        Digester digester = new Digester();
+
+        // Configure the rules we need for shutting down
+        digester.addObjectCreate("Server",
+                                 "org.apache.catalina.core.StandardServer",
+                                 "className");
+        digester.addSetProperties("Server");
+        digester.addSetNext("Server",
+                            "setServer",
+                            "org.apache.catalina.Server");
+
+        return (digester);
+
+    }
+
+
+    public void stopServer() {
+        stopServer(null);
+    }
+
+    public void stopServer(String[] arguments) {
+
+        if (arguments != null) {
+            arguments(arguments);
+        }
+
+        if( server == null ) {
+            // Create and execute our Digester
+            Digester digester = createStopDigester();
+            digester.setClassLoader(Thread.currentThread().getContextClassLoader());
+            File file = configFile();
+            try {
+                InputSource is =
+                    new InputSource("file://" + file.getAbsolutePath());
+                FileInputStream fis = new FileInputStream(file);
+                is.setByteStream(fis);
+                digester.push(this);
+                digester.parse(is);
+                fis.close();
+            } catch (Exception e) {
+                log.error("Catalina.stop: ", e);
+                System.exit(1);
+            }
+        }
+
+        // Stop the existing server
+        try {
+            Socket socket = new Socket("127.0.0.1", server.getPort());
+            OutputStream stream = socket.getOutputStream();
+            String shutdown = server.getShutdown();
+            for (int i = 0; i < shutdown.length(); i++)
+                stream.write(shutdown.charAt(i));
+            stream.flush();
+            stream.close();
+            socket.close();
+        } catch (IOException e) {
+            log.error("Catalina.stop: ", e);
+            System.exit(1);
+        }
+
+    }
+
+
+    /**
+     * Set the <code>catalina.base</code> System property to the current
+     * working directory if it has not been set.
+     * @deprecated Use initDirs()
+     */
+    public void setCatalinaBase() {
+        initDirs();
+    }
+
+    /**
+     * Set the <code>catalina.home</code> System property to the current
+     * working directory if it has not been set.
+     * @deprecated Use initDirs()
+     */
+    public void setCatalinaHome() {
+        initDirs();
+    }
+
+    /**
+     * Start a new server instance.
+     */
+    public void load() {
+
+        initDirs();
+
+        // Before digester - it may be needed
+
+        initNaming();
+
+        // Create and execute our Digester
+        Digester digester = createStartDigester();
+        long t1 = System.currentTimeMillis();
+
+        Exception ex = null;
+        InputSource inputSource = null;
+        InputStream inputStream = null;
+        File file = null;
+        try {
+            file = configFile();
+            inputStream = new FileInputStream(file);
+            inputSource = new InputSource("file://" + file.getAbsolutePath());
+        } catch (Exception e) {
+            ;
+        }
+        if (inputStream == null) {
+            try {
+                inputStream = getClass().getClassLoader()
+                    .getResourceAsStream(getConfigFile());
+                inputSource = new InputSource
+                    (getClass().getClassLoader()
+                     .getResource(getConfigFile()).toString());
+            } catch (Exception e) {
+                ;
+            }
+        }
+
+        // This should be included in catalina.jar
+        // Alternative: don't bother with xml, just create it manually.
+        if( inputStream==null ) {
+            try {
+                inputStream = getClass().getClassLoader()
+                .getResourceAsStream("server-embed.xml");
+                inputSource = new InputSource
+                (getClass().getClassLoader()
+                        .getResource("server-embed.xml").toString());
+            } catch (Exception e) {
+                ;
+            }
+        }
+        
+
+        if ((inputStream == null) && (file != null)) {
+            log.warn("Can't load server.xml from " + file.getAbsolutePath());
+            return;
+        }
+
+        try {
+            inputSource.setByteStream(inputStream);
+            digester.push(this);
+            digester.parse(inputSource);
+            inputStream.close();
+        } catch (Exception e) {
+            log.warn("Catalina.start using "
+                               + getConfigFile() + ": " , e);
+            return;
+        }
+
+        // Stream redirection
+        initStreams();
+
+        // Start the new server
+        if (server instanceof Lifecycle) {
+            try {
+                server.initialize();
+            } catch (LifecycleException e) {
+                log.error("Catalina.start", e);
+            }
+        }
+
+        long t2 = System.currentTimeMillis();
+        if(log.isInfoEnabled())
+            log.info("Initialization processed in " + (t2 - t1) + " ms");
+
+    }
+
+
+    /* 
+     * Load using arguments
+     */
+    public void load(String args[]) {
+
+        try {
+            if (arguments(args))
+                load();
+        } catch (Exception e) {
+            e.printStackTrace(System.out);
+        }
+    }
+
+    public void create() {
+
+    }
+
+    public void destroy() {
+
+    }
+
+    /**
+     * Start a new server instance.
+     */
+    public void start() {
+
+        if (server == null) {
+            load();
+        }
+
+        long t1 = System.currentTimeMillis();
+
+        // Start the new server
+        if (server instanceof Lifecycle) {
+            try {
+                ((Lifecycle) server).start();
+            } catch (LifecycleException e) {
+                log.error("Catalina.start: ", e);
+            }
+        }
+
+        long t2 = System.currentTimeMillis();
+        if(log.isInfoEnabled())
+            log.info("Server startup in " + (t2 - t1) + " ms");
+
+        try {
+            // Register shutdown hook
+            if (useShutdownHook) {
+                if (shutdownHook == null) {
+                    shutdownHook = new CatalinaShutdownHook();
+                }
+                Runtime.getRuntime().addShutdownHook(shutdownHook);
+            }
+        } catch (Throwable t) {
+            // This will fail on JDK 1.2. Ignoring, as Tomcat can run
+            // fine without the shutdown hook.
+        }
+
+        if (await) {
+            await();
+            stop();
+        }
+
+    }
+
+
+    /**
+     * Stop an existing server instance.
+     */
+    public void stop() {
+
+        try {
+            // Remove the ShutdownHook first so that server.stop() 
+            // doesn't get invoked twice
+            if (useShutdownHook) {
+                Runtime.getRuntime().removeShutdownHook(shutdownHook);
+            }
+        } catch (Throwable t) {
+            // This will fail on JDK 1.2. Ignoring, as Tomcat can run
+            // fine without the shutdown hook.
+        }
+
+        // Shut down the server
+        if (server instanceof Lifecycle) {
+            try {
+                ((Lifecycle) server).stop();
+            } catch (LifecycleException e) {
+                log.error("Catalina.stop", e);
+            }
+        }
+
+    }
+
+
+    /**
+     * Await and shutdown.
+     */
+    public void await() {
+
+        server.await();
+
+    }
+
+
+    /**
+     * Print usage information for this application.
+     */
+    protected void usage() {
+
+        System.out.println
+            ("usage: java org.apache.catalina.startup.Catalina"
+             + " [ -config {pathname} ]"
+             + " [ -nonaming ] { start | stop }");
+
+    }
+
+
+    // --------------------------------------- CatalinaShutdownHook Inner Class
+
+    // XXX Should be moved to embedded !
+    /**
+     * Shutdown hook which will perform a clean shutdown of Catalina if needed.
+     */
+    protected class CatalinaShutdownHook extends Thread {
+
+        public void run() {
+
+            if (server != null) {
+                Catalina.this.stop();
+            }
+            
+        }
+
+    }
+    
+    
+    private static org.apache.commons.logging.Log log=
+        org.apache.commons.logging.LogFactory.getLog( Catalina.class );
+
+}
+
+
+// ------------------------------------------------------------ Private Classes
+
+
+/**
+ * Rule that sets the parent class loader for the top object on the stack,
+ * which must be a <code>Container</code>.
+ */
+
+final class SetParentClassLoaderRule extends Rule {
+
+    public SetParentClassLoaderRule(ClassLoader parentClassLoader) {
+
+        this.parentClassLoader = parentClassLoader;
+
+    }
+
+    ClassLoader parentClassLoader = null;
+
+    public void begin(String namespace, String name, Attributes attributes)
+        throws Exception {
+
+        if (digester.getLogger().isDebugEnabled())
+            digester.getLogger().debug("Setting parent class loader");
+
+        Container top = (Container) digester.peek();
+        top.setParentClassLoader(parentClassLoader);
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/startup/CatalinaProperties.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/startup/CatalinaProperties.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/startup/CatalinaProperties.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,171 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.startup;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.Enumeration;
+import java.util.Properties;
+
+
+/**
+ * Utility class to read the bootstrap Catalina configuration.
+ *
+ * @author Remy Maucherat
+ * @version $Revision: 304109 $ $Date: 2005-09-29 09:36:25 -0500 (Thu, 29 Sep 2005) $
+ */
+
+public class CatalinaProperties {
+
+
+    // ------------------------------------------------------- Static Variables
+
+    private static org.apache.commons.logging.Log log=
+        org.apache.commons.logging.LogFactory.getLog( CatalinaProperties.class );
+
+    private static Properties properties = null;
+
+
+    static {
+
+        loadProperties();
+
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Return specified property value.
+     */
+    public static String getProperty(String name) {
+	
+        return properties.getProperty(name);
+
+    }
+
+
+    /**
+     * Return specified property value.
+     */
+    public static String getProperty(String name, String defaultValue) {
+
+        return properties.getProperty(name, defaultValue);
+
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Load properties.
+     */
+    private static void loadProperties() {
+
+        InputStream is = null;
+        Throwable error = null;
+
+        try {
+            String configUrl = getConfigUrl();
+            if (configUrl != null) {
+                is = (new URL(configUrl)).openStream();
+            }
+        } catch (Throwable t) {
+            // Ignore
+        }
+
+        if (is == null) {
+            try {
+                File home = new File(getCatalinaBase());
+                File conf = new File(home, "conf");
+                File properties = new File(conf, "catalina.properties");
+                is = new FileInputStream(properties);
+            } catch (Throwable t) {
+                // Ignore
+            }
+        }
+
+        if (is == null) {
+            try {
+                is = CatalinaProperties.class.getResourceAsStream
+                    ("/org/apache/catalina/startup/catalina.properties");
+            } catch (Throwable t) {
+                // Ignore
+            }
+        }
+
+        if (is != null) {
+            try {
+                properties = new Properties();
+                properties.load(is);
+                is.close();
+            } catch (Throwable t) {
+                error = t;
+            }
+        }
+
+        if ((is == null) || (error != null)) {
+            // Do something
+            log.warn("Failed to load catalina.properties", error);
+            // That's fine - we have reasonable defaults.
+            properties=new Properties();
+        }
+
+        // Register the properties as system properties
+        Enumeration enumeration = properties.propertyNames();
+        while (enumeration.hasMoreElements()) {
+            String name = (String) enumeration.nextElement();
+            String value = properties.getProperty(name);
+            if (value != null) {
+                System.setProperty(name, value);
+            }
+        }
+
+    }
+
+
+    /**
+     * Get the value of the catalina.home environment variable.
+     */
+    private static String getCatalinaHome() {
+        return System.getProperty("catalina.home",
+                                  System.getProperty("user.dir"));
+    }
+    
+    
+    /**
+     * Get the value of the catalina.base environment variable.
+     */
+    private static String getCatalinaBase() {
+        return System.getProperty("catalina.base", getCatalinaHome());
+    }
+
+
+    /**
+     * Get the value of the configuration URL.
+     */
+    private static String getConfigUrl() {
+        return System.getProperty("catalina.config");
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/startup/ClassLoaderFactory.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/startup/ClassLoaderFactory.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/startup/ClassLoaderFactory.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,259 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.startup;
+
+
+import java.io.File;
+import java.net.URL;
+import java.util.ArrayList;
+
+import org.apache.catalina.loader.StandardClassLoader;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+
+/**
+ * <p>Utility class for building class loaders for Catalina.  The factory
+ * method requires the following parameters in order to build a new class
+ * loader (with suitable defaults in all cases):</p>
+ * <ul>
+ * <li>A set of directories containing unpacked classes (and resources)
+ *     that should be included in the class loader's
+ *     repositories.</li>
+ * <li>A set of directories containing classes and resources in JAR files.
+ *     Each readable JAR file discovered in these directories will be
+ *     added to the class loader's repositories.</li>
+ * <li><code>ClassLoader</code> instance that should become the parent of
+ *     the new class loader.</li>
+ * </ul>
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 393434 $ $Date: 2006-04-12 05:55:14 -0500 (Wed, 12 Apr 2006) $
+ */
+
+public final class ClassLoaderFactory {
+
+
+    private static Log log = LogFactory.getLog(ClassLoaderFactory.class);
+
+    protected static final Integer IS_DIR = new Integer(0);
+    protected static final Integer IS_JAR = new Integer(1);
+    protected static final Integer IS_GLOB = new Integer(2);
+    protected static final Integer IS_URL = new Integer(3);
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Create and return a new class loader, based on the configuration
+     * defaults and the specified directory paths:
+     *
+     * @param unpacked Array of pathnames to unpacked directories that should
+     *  be added to the repositories of the class loader, or <code>null</code> 
+     * for no unpacked directories to be considered
+     * @param packed Array of pathnames to directories containing JAR files
+     *  that should be added to the repositories of the class loader, 
+     * or <code>null</code> for no directories of JAR files to be considered
+     * @param parent Parent class loader for the new class loader, or
+     *  <code>null</code> for the system class loader.
+     *
+     * @exception Exception if an error occurs constructing the class loader
+     */
+    public static ClassLoader createClassLoader(File unpacked[],
+                                                File packed[],
+                                                ClassLoader parent)
+        throws Exception {
+        return createClassLoader(unpacked, packed, null, parent);
+    }
+
+
+    /**
+     * Create and return a new class loader, based on the configuration
+     * defaults and the specified directory paths:
+     *
+     * @param unpacked Array of pathnames to unpacked directories that should
+     *  be added to the repositories of the class loader, or <code>null</code> 
+     * for no unpacked directories to be considered
+     * @param packed Array of pathnames to directories containing JAR files
+     *  that should be added to the repositories of the class loader, 
+     * or <code>null</code> for no directories of JAR files to be considered
+     * @param urls Array of URLs to remote repositories, designing either JAR 
+     *  resources or uncompressed directories that should be added to 
+     *  the repositories of the class loader, or <code>null</code> for no 
+     *  directories of JAR files to be considered
+     * @param parent Parent class loader for the new class loader, or
+     *  <code>null</code> for the system class loader.
+     *
+     * @exception Exception if an error occurs constructing the class loader
+     */
+    public static ClassLoader createClassLoader(File unpacked[],
+                                                File packed[],
+                                                URL urls[],
+                                                ClassLoader parent)
+        throws Exception {
+
+        if (log.isDebugEnabled())
+            log.debug("Creating new class loader");
+
+        // Construct the "class path" for this class loader
+        ArrayList list = new ArrayList();
+
+        // Add unpacked directories
+        if (unpacked != null) {
+            for (int i = 0; i < unpacked.length; i++)  {
+                File file = unpacked[i];
+                if (!file.exists() || !file.canRead())
+                    continue;
+                file = new File(file.getCanonicalPath() + File.separator);
+                URL url = file.toURL();
+                if (log.isDebugEnabled())
+                    log.debug("  Including directory " + url);
+                list.add(url);
+            }
+        }
+
+        // Add packed directory JAR files
+        if (packed != null) {
+            for (int i = 0; i < packed.length; i++) {
+                File directory = packed[i];
+                if (!directory.isDirectory() || !directory.exists() ||
+                    !directory.canRead())
+                    continue;
+                String filenames[] = directory.list();
+                for (int j = 0; j < filenames.length; j++) {
+                    String filename = filenames[j].toLowerCase();
+                    if (!filename.endsWith(".jar"))
+                        continue;
+                    File file = new File(directory, filenames[j]);
+                    if (log.isDebugEnabled())
+                        log.debug("  Including jar file " + file.getAbsolutePath());
+                    URL url = file.toURL();
+                    list.add(url);
+                }
+            }
+        }
+
+        // Construct the class loader itself
+        URL[] array = (URL[]) list.toArray(new URL[list.size()]);
+        StandardClassLoader classLoader = null;
+        if (parent == null)
+            classLoader = new StandardClassLoader(array);
+        else
+            classLoader = new StandardClassLoader(array, parent);
+        return (classLoader);
+
+    }
+
+
+    /**
+     * Create and return a new class loader, based on the configuration
+     * defaults and the specified directory paths:
+     *
+     * @param locations Array of strings containing class directories, jar files,
+     *  jar directories or URLS that should be added to the repositories of
+     *  the class loader. The type is given by the member of param types.
+     * @param types Array of types for the members of param locations.
+     *  Possible values are IS_DIR (class directory), IS_JAR (single jar file),
+     *  IS_GLOB (directory of jar files) and IS_URL (URL).
+     * @param parent Parent class loader for the new class loader, or
+     *  <code>null</code> for the system class loader.
+     *
+     * @exception Exception if an error occurs constructing the class loader
+     */
+    public static ClassLoader createClassLoader(String locations[],
+                                                Integer types[],
+                                                ClassLoader parent)
+        throws Exception {
+
+        if (log.isDebugEnabled())
+            log.debug("Creating new class loader");
+
+        // Construct the "class path" for this class loader
+        ArrayList list = new ArrayList();
+
+        if (locations != null && types != null && locations.length == types.length) {
+            for (int i = 0; i < locations.length; i++)  {
+                String location = locations[i];
+                if ( types[i] == IS_URL ) {
+                    URL url = new URL(location);
+                    if (log.isDebugEnabled())
+                        log.debug("  Including URL " + url);
+                    list.add(url);
+                } else if ( types[i] == IS_DIR ) {
+                    File directory = new File(location);
+                    directory = new File(directory.getCanonicalPath());
+                    if (!directory.exists() || !directory.isDirectory() ||
+                        !directory.canRead())
+                         continue;
+                    URL url = directory.toURL();
+                    if (log.isDebugEnabled())
+                        log.debug("  Including directory " + url);
+                    list.add(url);
+                } else if ( types[i] == IS_JAR ) {
+                    File file=new File(location);
+                    file = new File(file.getCanonicalPath());
+                    if (!file.exists() || !file.canRead())
+                        continue;
+                    URL url = file.toURL();
+                    if (log.isDebugEnabled())
+                        log.debug("  Including jar file " + url);
+                    list.add(url);
+                } else if ( types[i] == IS_GLOB ) {
+                    File directory=new File(location);
+                    if (!directory.exists() || !directory.isDirectory() ||
+                        !directory.canRead())
+                        continue;
+                    if (log.isDebugEnabled())
+                        log.debug("  Including directory glob "
+                            + directory.getAbsolutePath());
+                    String filenames[] = directory.list();
+                    for (int j = 0; j < filenames.length; j++) {
+                        String filename = filenames[j].toLowerCase();
+                        if (!filename.endsWith(".jar"))
+                            continue;
+                        File file = new File(directory, filenames[j]);
+                        file = new File(file.getCanonicalPath());
+                        if (!file.exists() || !file.canRead())
+                            continue;
+                        if (log.isDebugEnabled())
+                            log.debug("    Including glob jar file "
+                                + file.getAbsolutePath());
+                        URL url = file.toURL();
+                        list.add(url);
+                    }
+                }
+            }
+        }
+
+        // Construct the class loader itself
+        URL[] array = (URL[]) list.toArray(new URL[list.size()]);
+        if (log.isDebugEnabled())
+            for (int i = 0; i < array.length; i++) {
+                log.debug("  location " + i + " is " + array[i]);
+            }
+        StandardClassLoader classLoader = null;
+        if (parent == null)
+            classLoader = new StandardClassLoader(array);
+        else
+            classLoader = new StandardClassLoader(array, parent);
+        return (classLoader);
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/startup/ClusterRuleSetFactory.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/startup/ClusterRuleSetFactory.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/startup/ClusterRuleSetFactory.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,202 @@
+/*
+ * Copyright 1999-2001,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.startup;
+
+
+import org.apache.tomcat.util.digester.Digester;
+import org.apache.tomcat.util.digester.RuleSetBase;
+import java.lang.reflect.Constructor;
+import org.apache.commons.logging.LogFactory;
+import org.apache.commons.logging.Log;
+import java.lang.reflect.InvocationTargetException;
+public class ClusterRuleSetFactory {
+    
+    public static Log log = LogFactory.getLog(ClusterRuleSetFactory.class);
+    
+    public static RuleSetBase getClusterRuleSet(String prefix) {
+        
+        //OLD CLUSTER 1
+        //first try the same classloader as this class server/lib
+        try {
+            return loadRuleSet(prefix,"org.apache.catalina.cluster.ClusterRuleSet",ClusterRuleSetFactory.class.getClassLoader());
+        } catch ( Exception x ) {
+            //display warning
+            if ( log.isDebugEnabled() ) log.debug("Unable to load ClusterRuleSet (org.apache.catalina.cluster.ClusterRuleSet), falling back on context classloader");
+        }
+        //try to load it from the context class loader
+        try {
+            return loadRuleSet(prefix,"org.apache.catalina.cluster.ClusterRuleSet",Thread.currentThread().getContextClassLoader());
+        } catch ( Exception x ) {
+            //display warning
+            if ( log.isDebugEnabled() ) log.debug("Unable to load ClusterRuleSet (org.apache.catalina.cluster.ClusterRuleSet), will try to load the HA cluster");
+        }
+        
+        //NEW CLUSTER 2
+        //first try the same classloader as this class server/lib
+        try {
+            return loadRuleSet(prefix,"org.apache.catalina.ha.ClusterRuleSet",ClusterRuleSetFactory.class.getClassLoader());
+        } catch ( Exception x ) {
+            //display warning
+            if ( log.isDebugEnabled() ) log.debug("Unable to load HA ClusterRuleSet (org.apache.catalina.ha.ClusterRuleSet), falling back on context classloader");
+        }
+        //try to load it from the context class loader
+        try {
+            return loadRuleSet(prefix,"org.apache.catalina.ha.ClusterRuleSet",Thread.currentThread().getContextClassLoader());
+        } catch ( Exception x ) {
+            //display warning
+            if ( log.isDebugEnabled() ) log.debug("Unable to load HA ClusterRuleSet (org.apache.catalina.ha.ClusterRuleSet), falling back on DefaultClusterRuleSet");
+        }
+
+        log.info("Unable to find a cluster rule set in the classpath. Will load the default rule set.");
+        return new DefaultClusterRuleSet(prefix);
+    }
+    
+    
+    protected static RuleSetBase loadRuleSet(String prefix, String className, ClassLoader cl) 
+        throws ClassNotFoundException, InstantiationException, 
+               NoSuchMethodException,IllegalAccessException,
+               InvocationTargetException {
+        Class clazz = Class.forName(className,true,cl);
+        Constructor cons = clazz.getConstructor(new Class[] {String.class});
+        return (RuleSetBase)cons.newInstance(new String[] {prefix});
+    }
+    
+    /**
+     * <p><strong>RuleSet</strong> for processing the contents of a
+     * Cluster definition element.  </p>
+     *
+     * @author Filip Hanik
+     * @author Peter Rossbach
+     * @version $Revision: 379550 $ $Date: 2006-02-21 12:06:35 -0600 (Tue, 21 Feb 2006) $
+     */
+
+    public static class DefaultClusterRuleSet extends RuleSetBase {
+
+
+        // ----------------------------------------------------- Instance Variables
+
+
+        /**
+         * The matching pattern prefix to use for recognizing our elements.
+         */
+        protected String prefix = null;
+
+
+        // ------------------------------------------------------------ Constructor
+
+
+        /**
+         * Construct an instance of this <code>RuleSet</code> with the default
+         * matching pattern prefix.
+         */
+        public DefaultClusterRuleSet() {
+
+            this("");
+
+        }
+
+
+        /**
+         * Construct an instance of this <code>RuleSet</code> with the specified
+         * matching pattern prefix.
+         *
+         * @param prefix Prefix for matching pattern rules (including the
+         *  trailing slash character)
+         */
+        public DefaultClusterRuleSet(String prefix) {
+            super();
+            this.namespaceURI = null;
+            this.prefix = prefix;
+        }
+
+
+        // --------------------------------------------------------- Public Methods
+
+
+        /**
+         * <p>Add the set of Rule instances defined in this RuleSet to the
+         * specified <code>Digester</code> instance, associating them with
+         * our namespace URI (if any).  This method should only be called
+         * by a Digester instance.</p>
+         *
+         * @param digester Digester instance to which the new Rule instances
+         *  should be added.
+         */
+        public void addRuleInstances(Digester digester) {
+            //Cluster configuration start
+            digester.addObjectCreate(prefix + "Membership",
+                                     null, // MUST be specified in the element
+                                     "className");
+            digester.addSetProperties(prefix + "Membership");
+            digester.addSetNext(prefix + "Membership",
+                                "setMembershipService",
+                                "org.apache.catalina.cluster.MembershipService");
+
+            digester.addObjectCreate(prefix + "Sender",
+                                     null, // MUST be specified in the element
+                                     "className");
+            digester.addSetProperties(prefix + "Sender");
+            digester.addSetNext(prefix + "Sender",
+                                "setClusterSender",
+                                "org.apache.catalina.cluster.ClusterSender");
+
+            digester.addObjectCreate(prefix + "Receiver",
+                                     null, // MUST be specified in the element
+                                     "className");
+            digester.addSetProperties(prefix + "Receiver");
+            digester.addSetNext(prefix + "Receiver",
+                                "setClusterReceiver",
+                                "org.apache.catalina.cluster.ClusterReceiver");
+
+            digester.addObjectCreate(prefix + "Valve",
+                                     null, // MUST be specified in the element
+                                     "className");
+            digester.addSetProperties(prefix + "Valve");
+            digester.addSetNext(prefix + "Valve",
+                                "addValve",
+                                "org.apache.catalina.Valve");
+
+            digester.addObjectCreate(prefix + "Deployer",
+                                     null, // MUST be specified in the element
+                                     "className");
+            digester.addSetProperties(prefix + "Deployer");
+            digester.addSetNext(prefix + "Deployer",
+                                "setClusterDeployer",
+                                "org.apache.catalina.cluster.ClusterDeployer");
+
+            digester.addObjectCreate(prefix + "Listener",
+                    null, // MUST be specified in the element
+                    "className");
+            digester.addSetProperties(prefix + "Listener");
+            digester.addSetNext(prefix + "Listener",
+                                "addLifecycleListener",
+                                "org.apache.catalina.LifecycleListener");
+
+            digester.addObjectCreate(prefix + "ClusterListener",
+                    null, // MUST be specified in the element
+                    "className");
+            digester.addSetProperties(prefix + "ClusterListener");
+            digester.addSetNext(prefix + "ClusterListener",
+                                "addClusterListener",
+                                "org.apache.catalina.cluster.MessageListener");
+            //Cluster configuration end
+        }
+
+
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/startup/ConnectorCreateRule.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/startup/ConnectorCreateRule.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/startup/ConnectorCreateRule.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,55 @@
+/* $Id: ConnectorCreateRule.java 303287 2004-09-29 09:55:39Z remm $
+ *
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.startup;
+
+
+import org.apache.catalina.connector.Connector;
+import org.apache.tomcat.util.digester.Rule;
+import org.xml.sax.Attributes;
+
+
+/**
+ * Rule implementation that creates a connector.
+ */
+
+public class ConnectorCreateRule extends Rule {
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Process the beginning of this element.
+     *
+     * @param attributes The attribute list of this element
+     */
+    public void begin(Attributes attributes) throws Exception {
+        digester.push(new Connector(attributes.getValue("protocol")));
+    }
+
+
+    /**
+     * Process the end of this element.
+     */
+    public void end() throws Exception {
+        Object top = digester.pop();
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/startup/Constants.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/startup/Constants.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/startup/Constants.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,95 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.startup;
+
+
+/**
+ * String constants for the startup package.
+ *
+ * @author Craig R. McClanahan
+ * @author Jean-Francois Arcand
+ * @version $Revision: 303179 $ $Date: 2004-09-02 05:28:00 -0500 (Thu, 02 Sep 2004) $
+ */
+
+public final class Constants {
+
+    public static final String Package = "org.apache.catalina.startup";
+
+    public static final String ApplicationContextXml = "META-INF/context.xml";
+    public static final String ApplicationWebXml = "/WEB-INF/web.xml";
+    public static final String DefaultContextXml = "conf/context.xml";
+    public static final String DefaultWebXml = "conf/web.xml";
+    public static final String HostContextXml = "context.xml.default";
+    public static final String HostWebXml = "web.xml.default";
+
+    public static final String TldDtdPublicId_11 =
+        "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.1//EN";
+    public static final String TldDtdResourcePath_11 =
+        "/javax/servlet/jsp/resources/web-jsptaglibrary_1_1.dtd";
+
+    public static final String TldDtdPublicId_12 =
+        "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN";
+    public static final String TldDtdResourcePath_12 =
+        "/javax/servlet/jsp/resources/web-jsptaglibrary_1_2.dtd";
+
+    public static final String TldSchemaPublicId_20 =
+        "web-jsptaglibrary_2_0.xsd";;
+    public static final String TldSchemaResourcePath_20 =
+        "/javax/servlet/resources/web-jsptaglibrary_2_0.xsd";
+
+    public static final String WebDtdPublicId_22 =
+        "-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN";
+    public static final String WebDtdResourcePath_22 =
+        "/javax/servlet/resources/web-app_2_2.dtd";
+
+    public static final String WebDtdPublicId_23 =
+        "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN";
+    public static final String WebDtdResourcePath_23 =
+        "/javax/servlet/resources/web-app_2_3.dtd";
+
+    public static final String WebSchemaPublicId_24 =
+        "web-app_2_4.xsd";;
+    public static final String WebSchemaResourcePath_24 =
+        "/javax/servlet/resources/web-app_2_4.xsd";
+
+    public static final String J2eeSchemaPublicId_14 =
+        "j2ee_1_4.xsd";;
+    public static final String J2eeSchemaResourcePath_14 =
+        "/javax/servlet/resources/j2ee_1_4.xsd";
+
+    public static final String W3cSchemaPublicId_10 =
+        "xml.xsd";;
+    public static final String W3cSchemaResourcePath_10 =
+        "/javax/servlet/resources/xml.xsd";
+
+    public static final String JspSchemaPublicId_20 =
+        "jsp_2_0.xsd";;
+    public static final String JspSchemaResourcePath_20 =
+        "/javax/servlet/resources/jsp_2_0.xsd";
+    
+    public static final String J2eeWebServiceSchemaPublicId_11 =
+            "j2ee_web_services_1_1.xsd";
+    public static final String J2eeWebServiceSchemaResourcePath_11 =
+            "/javax/servlet/resources/j2ee_web_services_1_1.xsd";
+    
+    public static final String J2eeWebServiceClientSchemaPublicId_11 =
+            "j2ee_web_services_client_1_1.xsd";
+    public static final String J2eeWebServiceClientSchemaResourcePath_11 =
+            "/javax/servlet/resources/j2ee_web_services_client_1_1.xsd";
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/startup/ContextConfig.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/startup/ContextConfig.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/startup/ContextConfig.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,1356 @@
+/*
+ * Copyright 1999-2001,2004-2005 The Apache Software Foundation.
+ * 
+ * Licensed 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.startup;
+
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.Map;
+import java.util.Properties;
+
+import javax.servlet.ServletContext;
+
+import org.apache.catalina.Authenticator;
+import org.apache.catalina.Container;
+import org.apache.catalina.Context;
+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.Pipeline;
+import org.apache.catalina.Valve;
+import org.apache.catalina.Wrapper;
+import org.apache.catalina.core.ContainerBase;
+import org.apache.catalina.core.StandardContext;
+import org.apache.catalina.core.StandardEngine;
+import org.apache.catalina.core.StandardHost;
+import org.apache.catalina.deploy.ErrorPage;
+import org.apache.catalina.deploy.FilterDef;
+import org.apache.catalina.deploy.FilterMap;
+import org.apache.catalina.deploy.LoginConfig;
+import org.apache.catalina.deploy.SecurityConstraint;
+import org.apache.catalina.util.StringManager;
+import org.apache.tomcat.util.digester.Digester;
+import org.apache.tomcat.util.digester.RuleSet;
+import org.xml.sax.ErrorHandler;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXParseException;
+
+/**
+ * Startup event listener for a <b>Context</b> that configures the properties
+ * of that Context, and the associated defined servlets.
+ *
+ * @author Craig R. McClanahan
+ * @author Jean-Francois Arcand
+ * @version $Revision: 394930 $ $Date: 2006-04-18 07:59:06 -0500 (Tue, 18 Apr 2006) $
+ */
+
+public class ContextConfig
+    implements LifecycleListener {
+
+    protected static org.apache.commons.logging.Log log=
+        org.apache.commons.logging.LogFactory.getLog( ContextConfig.class );
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /*
+     * Custom mappings of login methods to authenticators
+     */
+    protected Map customAuthenticators;
+
+
+    /**
+     * The set of Authenticators that we know how to configure.  The key is
+     * the name of the implemented authentication method, and the value is
+     * the fully qualified Java class name of the corresponding Valve.
+     */
+    protected static Properties authenticators = null;
+
+
+    /**
+     * The Context we are associated with.
+     */
+    protected Context context = null;
+
+
+    /**
+     * The default web application's context file location.
+     */
+    protected String defaultContextXml = null;
+    
+    
+    /**
+     * The default web application's deployment descriptor location.
+     */
+    protected String defaultWebXml = null;
+    
+    
+    /**
+     * Track any fatal errors during startup configuration processing.
+     */
+    protected boolean ok = false;
+
+
+    /**
+     * Any parse error which occurred while parsing XML descriptors.
+     */
+    protected SAXParseException parseException = null;
+
+    
+    /**
+     * Original docBase.
+     */
+    protected String originalDocBase = null;
+    
+
+    /**
+     * The string resources for this package.
+     */
+    protected static final StringManager sm =
+        StringManager.getManager(Constants.Package);
+
+
+    /**
+     * The <code>Digester</code> we will use to process web application
+     * context files.
+     */
+    protected static Digester contextDigester = null;
+    
+    
+    /**
+     * The <code>Digester</code> we will use to process web application
+     * deployment descriptor files.
+     */
+    protected static Digester webDigester = null;
+    
+    
+    /**
+     * The <code>Rule</code> used to parse the web.xml
+     */
+    protected static WebRuleSet webRuleSet = new WebRuleSet();
+
+    /**
+     * Attribute value used to turn on/off XML validation
+     */
+     protected static boolean xmlValidation = false;
+
+
+    /**
+     * Attribute value used to turn on/off XML namespace awarenes.
+     */
+    protected static boolean xmlNamespaceAware = false;
+
+    
+    /**
+     * Deployment count.
+     */
+    protected static long deploymentCount = 0L;
+    
+    
+    protected static final LoginConfig DUMMY_LOGIN_CONFIG =
+                                new LoginConfig("NONE", null, null, null);
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * Return the location of the default deployment descriptor
+     */
+    public String getDefaultWebXml() {
+        if( defaultWebXml == null ) {
+            defaultWebXml=Constants.DefaultWebXml;
+        }
+
+        return (this.defaultWebXml);
+
+    }
+
+
+    /**
+     * Set the location of the default deployment descriptor
+     *
+     * @param path Absolute/relative path to the default web.xml
+     */
+    public void setDefaultWebXml(String path) {
+
+        this.defaultWebXml = path;
+
+    }
+
+
+    /**
+     * Return the location of the default context file
+     */
+    public String getDefaultContextXml() {
+        if( defaultContextXml == null ) {
+            defaultContextXml=Constants.DefaultContextXml;
+        }
+
+        return (this.defaultContextXml);
+
+    }
+
+
+    /**
+     * Set the location of the default context file
+     *
+     * @param path Absolute/relative path to the default context.xml
+     */
+    public void setDefaultContextXml(String path) {
+
+        this.defaultContextXml = path;
+
+    }
+
+
+    /**
+     * Sets custom mappings of login methods to authenticators.
+     *
+     * @param customAuthenticators Custom mappings of login methods to
+     * authenticators
+     */
+    public void setCustomAuthenticators(Map customAuthenticators) {
+        this.customAuthenticators = customAuthenticators;
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Process events for an associated Context.
+     *
+     * @param event The lifecycle event that has occurred
+     */
+    public void lifecycleEvent(LifecycleEvent event) {
+
+        // Identify the context we are associated with
+        try {
+            context = (Context) event.getLifecycle();
+        } catch (ClassCastException e) {
+            log.error(sm.getString("contextConfig.cce", event.getLifecycle()), e);
+            return;
+        }
+
+        // Process the event that has occurred
+        if (event.getType().equals(Lifecycle.START_EVENT)) {
+            start();
+        } else if (event.getType().equals(StandardContext.BEFORE_START_EVENT)) {
+            beforeStart();
+        } else if (event.getType().equals(StandardContext.AFTER_START_EVENT)) {
+            // Restore docBase for management tools
+            if (originalDocBase != null) {
+                String docBase = context.getDocBase();
+                context.setDocBase(originalDocBase);
+                originalDocBase = docBase;
+            }
+        } else if (event.getType().equals(Lifecycle.STOP_EVENT)) {
+            if (originalDocBase != null) {
+                String docBase = context.getDocBase();
+                context.setDocBase(originalDocBase);
+                originalDocBase = docBase;
+            }
+            stop();
+        } else if (event.getType().equals(Lifecycle.INIT_EVENT)) {
+            init();
+        } else if (event.getType().equals(Lifecycle.DESTROY_EVENT)) {
+            destroy();
+        }
+
+    }
+
+
+    // -------------------------------------------------------- protected Methods
+
+
+    /**
+     * Process the application configuration file, if it exists.
+     */
+    protected void applicationWebConfig() {
+
+        String altDDName = null;
+
+        // Open the application web.xml file, if it exists
+        InputStream stream = null;
+        ServletContext servletContext = context.getServletContext();
+        if (servletContext != null) {
+            altDDName = (String)servletContext.getAttribute(
+                                                        Globals.ALT_DD_ATTR);
+            if (altDDName != null) {
+                try {
+                    stream = new FileInputStream(altDDName);
+                } catch (FileNotFoundException e) {
+                    log.error(sm.getString("contextConfig.altDDNotFound",
+                                           altDDName));
+                }
+            }
+            else {
+                stream = servletContext.getResourceAsStream
+                    (Constants.ApplicationWebXml);
+            }
+        }
+        if (stream == null) {
+            if (log.isDebugEnabled()) {
+                log.debug(sm.getString("contextConfig.applicationMissing") + " " + context);
+            }
+            return;
+        }
+        
+        long t1=System.currentTimeMillis();
+
+        if (webDigester == null){
+            webDigester = createWebDigester();
+        }
+        
+        URL url=null;
+        // Process the application web.xml file
+        synchronized (webDigester) {
+            try {
+                if (altDDName != null) {
+                    url = new File(altDDName).toURL();
+                } else {
+                    url = servletContext.getResource(
+                                                Constants.ApplicationWebXml);
+                }
+                if( url!=null ) {
+                    InputSource is = new InputSource(url.toExternalForm());
+                    is.setByteStream(stream);
+                    if (context instanceof StandardContext) {
+                        ((StandardContext) context).setReplaceWelcomeFiles(true);
+                    }
+                    webDigester.push(context);
+                    webDigester.setErrorHandler(new ContextErrorHandler());
+
+                    if(log.isDebugEnabled()) {
+                        log.debug("Parsing application web.xml file at " + url.toExternalForm());
+                    }
+
+                    webDigester.parse(is);
+
+                    if (parseException != null) {
+                        ok = false;
+                    }
+                } else {
+                    log.info("No web.xml, using defaults " + context );
+                }
+            } catch (SAXParseException e) {
+                log.error(sm.getString("contextConfig.applicationParse", url.toExternalForm()), e);
+                log.error(sm.getString("contextConfig.applicationPosition",
+                                 "" + e.getLineNumber(),
+                                 "" + e.getColumnNumber()));
+                ok = false;
+            } catch (Exception e) {
+                log.error(sm.getString("contextConfig.applicationParse", url.toExternalForm()), e);
+                ok = false;
+            } finally {
+                webDigester.reset();
+                parseException = null;
+                try {
+                    if (stream != null) {
+                        stream.close();
+                    }
+                } catch (IOException e) {
+                    log.error(sm.getString("contextConfig.applicationClose"), e);
+                }
+            }
+        }
+        webRuleSet.recycle();
+
+        long t2=System.currentTimeMillis();
+        if (context instanceof StandardContext) {
+            ((StandardContext) context).setStartupTime(t2-t1);
+        }
+    }
+
+
+    /**
+     * Set up an Authenticator automatically if required, and one has not
+     * already been configured.
+     */
+    protected synchronized void authenticatorConfig() {
+
+        // Does this Context require an Authenticator?
+        SecurityConstraint constraints[] = context.findConstraints();
+        if ((constraints == null) || (constraints.length == 0))
+            return;
+        LoginConfig loginConfig = context.getLoginConfig();
+        if (loginConfig == null) {
+            loginConfig = DUMMY_LOGIN_CONFIG;
+            context.setLoginConfig(loginConfig);
+        }
+
+        // Has an authenticator been configured already?
+        if (context instanceof Authenticator)
+            return;
+        if (context instanceof ContainerBase) {
+            Pipeline pipeline = ((ContainerBase) context).getPipeline();
+            if (pipeline != null) {
+                Valve basic = pipeline.getBasic();
+                if ((basic != null) && (basic instanceof Authenticator))
+                    return;
+                Valve valves[] = pipeline.getValves();
+                for (int i = 0; i < valves.length; i++) {
+                    if (valves[i] instanceof Authenticator)
+                        return;
+                }
+            }
+        } else {
+            return;     // Cannot install a Valve even if it would be needed
+        }
+
+        // Has a Realm been configured for us to authenticate against?
+        if (context.getRealm() == null) {
+            log.error(sm.getString("contextConfig.missingRealm"));
+            ok = false;
+            return;
+        }
+
+        /*
+         * First check to see if there is a custom mapping for the login
+         * method. If so, use it. Otherwise, check if there is a mapping in
+         * org/apache/catalina/startup/Authenticators.properties.
+         */
+        Valve authenticator = null;
+        if (customAuthenticators != null) {
+            authenticator = (Valve)
+                customAuthenticators.get(loginConfig.getAuthMethod());
+        }
+        if (authenticator == null) {
+            // Load our mapping properties if necessary
+            if (authenticators == null) {
+                try {
+                    InputStream is=this.getClass().getClassLoader().getResourceAsStream("org/apache/catalina/startup/Authenticators.properties");
+                    if( is!=null ) {
+                        authenticators = new Properties();
+                        authenticators.load(is);
+                    } else {
+                        log.error(sm.getString(
+                                "contextConfig.authenticatorResources"));
+                        ok=false;
+                        return;
+                    }
+                } catch (IOException e) {
+                    log.error(sm.getString(
+                                "contextConfig.authenticatorResources"), e);
+                    ok = false;
+                    return;
+                }
+            }
+
+            // Identify the class name of the Valve we should configure
+            String authenticatorName = null;
+            authenticatorName =
+                    authenticators.getProperty(loginConfig.getAuthMethod());
+            if (authenticatorName == null) {
+                log.error(sm.getString("contextConfig.authenticatorMissing",
+                                 loginConfig.getAuthMethod()));
+                ok = false;
+                return;
+            }
+
+            // Instantiate and install an Authenticator of the requested class
+            try {
+                Class authenticatorClass = Class.forName(authenticatorName);
+                authenticator = (Valve) authenticatorClass.newInstance();
+            } catch (Throwable t) {
+                log.error(sm.getString(
+                                    "contextConfig.authenticatorInstantiate",
+                                    authenticatorName),
+                          t);
+                ok = false;
+            }
+        }
+
+        if (authenticator != null && context instanceof ContainerBase) {
+            Pipeline pipeline = ((ContainerBase) context).getPipeline();
+            if (pipeline != null) {
+                ((ContainerBase) context).addValve(authenticator);
+                if (log.isDebugEnabled()) {
+                    log.debug(sm.getString(
+                                    "contextConfig.authenticatorConfigured",
+                                    loginConfig.getAuthMethod()));
+                }
+            }
+        }
+
+    }
+
+
+    /**
+     * Create (if necessary) and return a Digester configured to process the
+     * web application deployment descriptor (web.xml).
+     */
+    protected static Digester createWebDigester() {
+        Digester webDigester =
+            createWebXmlDigester(xmlNamespaceAware, xmlValidation);
+        return webDigester;
+    }
+
+
+    /**
+     * Create (if necessary) and return a Digester configured to process the
+     * web application deployment descriptor (web.xml).
+     */
+    public static Digester createWebXmlDigester(boolean namespaceAware,
+                                                boolean validation) {
+        
+        Digester webDigester =  DigesterFactory.newDigester(xmlValidation,
+                                                            xmlNamespaceAware,
+                                                            webRuleSet);
+        return webDigester;
+    }
+
+    
+    /**
+     * Create (if necessary) and return a Digester configured to process the
+     * context configuration descriptor for an application.
+     */
+    protected Digester createContextDigester() {
+        Digester digester = new Digester();
+        digester.setValidating(false);
+        RuleSet contextRuleSet = new ContextRuleSet("", false);
+        digester.addRuleSet(contextRuleSet);
+        RuleSet namingRuleSet = new NamingRuleSet("Context/");
+        digester.addRuleSet(namingRuleSet);
+        return digester;
+    }
+
+
+    protected String getBaseDir() {
+        Container engineC=context.getParent().getParent();
+        if( engineC instanceof StandardEngine ) {
+            return ((StandardEngine)engineC).getBaseDir();
+        }
+        return System.getProperty("catalina.base");
+    }
+
+    /**
+     * Process the default configuration file, if it exists.
+     * The default config must be read with the container loader - so
+     * container servlets can be loaded
+     */
+    protected void defaultWebConfig() {
+        long t1=System.currentTimeMillis();
+
+        // Open the default web.xml file, if it exists
+        if( defaultWebXml==null && context instanceof StandardContext ) {
+            defaultWebXml=((StandardContext)context).getDefaultWebXml();
+        }
+        // set the default if we don't have any overrides
+        if( defaultWebXml==null ) getDefaultWebXml();
+
+        File file = new File(this.defaultWebXml);
+        if (!file.isAbsolute()) {
+            file = new File(getBaseDir(),
+                            this.defaultWebXml);
+        }
+
+        InputStream stream = null;
+        InputSource source = null;
+
+        try {
+            if ( ! file.exists() ) {
+                // Use getResource and getResourceAsStream
+                stream = getClass().getClassLoader()
+                    .getResourceAsStream(defaultWebXml);
+                if( stream != null ) {
+                    source = new InputSource
+                            (getClass().getClassLoader()
+                            .getResource(defaultWebXml).toString());
+                } 
+                if( stream== null ) { 
+                    // maybe embedded
+                    stream = getClass().getClassLoader()
+                        .getResourceAsStream("web-embed.xml");
+                    if( stream != null ) {
+                        source = new InputSource
+                        (getClass().getClassLoader()
+                                .getResource("web-embed.xml").toString());
+                    }                                         
+                }
+                
+                if( stream== null ) {
+                    log.info("No default web.xml");
+                }
+            } else {
+                source =
+                    new InputSource("file://" + file.getAbsolutePath());
+                stream = new FileInputStream(file);
+            }
+        } catch (Exception e) {
+            log.error(sm.getString("contextConfig.defaultMissing") 
+                      + " " + defaultWebXml + " " + file , e);
+        }
+
+        if (webDigester == null){
+            webDigester = createWebDigester();
+        }
+        
+        if (stream != null) {
+            processDefaultWebConfig(webDigester, stream, source);
+            webRuleSet.recycle();
+        }
+
+        long t2=System.currentTimeMillis();
+        if( (t2-t1) > 200 )
+            log.debug("Processed default web.xml " + file + " "  + ( t2-t1));
+
+        stream = null;
+        source = null;
+
+        String resourceName = getHostConfigPath(Constants.HostWebXml);
+        file = new File(getConfigBase(), resourceName);
+        
+        try {
+            if ( ! file.exists() ) {
+                // Use getResource and getResourceAsStream
+                stream = getClass().getClassLoader()
+                    .getResourceAsStream(resourceName);
+                if( stream != null ) {
+                    source = new InputSource
+                            (getClass().getClassLoader()
+                            .getResource(resourceName).toString());
+                }
+            } else {
+                source =
+                    new InputSource("file://" + file.getAbsolutePath());
+                stream = new FileInputStream(file);
+            }
+        } catch (Exception e) {
+            log.error(sm.getString("contextConfig.defaultMissing") 
+                      + " " + resourceName + " " + file , e);
+        }
+
+        if (stream != null) {
+            processDefaultWebConfig(webDigester, stream, source);
+            webRuleSet.recycle();
+        }
+
+    }
+
+
+    /**
+     * Process a default web.xml.
+     */
+    protected void processDefaultWebConfig(Digester digester, InputStream stream, 
+            InputSource source) {
+
+        if (log.isDebugEnabled())
+            log.debug("Processing context [" + context.getName() 
+                    + "] web configuration resource " + source.getSystemId());
+
+        // Process the default web.xml file
+        synchronized (digester) {
+            try {
+                source.setByteStream(stream);
+                
+                if (context instanceof StandardContext)
+                    ((StandardContext) context).setReplaceWelcomeFiles(true);
+                digester.setClassLoader(this.getClass().getClassLoader());
+                digester.setUseContextClassLoader(false);
+                digester.push(context);
+                digester.setErrorHandler(new ContextErrorHandler());
+                digester.parse(source);
+                if (parseException != null) {
+                    ok = false;
+                }
+            } catch (SAXParseException e) {
+                log.error(sm.getString("contextConfig.defaultParse"), e);
+                log.error(sm.getString("contextConfig.defaultPosition",
+                                 "" + e.getLineNumber(),
+                                 "" + e.getColumnNumber()));
+                ok = false;
+            } catch (Exception e) {
+                log.error(sm.getString("contextConfig.defaultParse"), e);
+                ok = false;
+            } finally {
+                digester.reset();
+                parseException = null;
+                try {
+                    if (stream != null) {
+                        stream.close();
+                    }
+                } catch (IOException e) {
+                    log.error(sm.getString("contextConfig.defaultClose"), e);
+                }
+            }
+        }
+    }
+
+
+    /**
+     * Process the default configuration file, if it exists.
+     */
+    protected void contextConfig() {
+        
+        // Open the default web.xml file, if it exists
+        if( defaultContextXml==null && context instanceof StandardContext ) {
+            defaultContextXml = ((StandardContext)context).getDefaultContextXml();
+        }
+        // set the default if we don't have any overrides
+        if( defaultContextXml==null ) getDefaultContextXml();
+
+        if (!context.getOverride()) {
+            processContextConfig(new File(getBaseDir()), defaultContextXml);
+            processContextConfig(getConfigBase(), getHostConfigPath(Constants.HostContextXml));
+        }
+        if (context.getConfigFile() != null)
+            processContextConfig(new File(context.getConfigFile()), null);
+        
+    }
+
+    
+    /**
+     * Process a context.xml.
+     */
+    protected void processContextConfig(File baseDir, String resourceName) {
+        
+        if (log.isDebugEnabled())
+            log.debug("Processing context [" + context.getName() 
+                    + "] configuration file " + baseDir + " " + resourceName);
+
+        InputSource source = null;
+        InputStream stream = null;
+
+        File file = baseDir;
+        if (resourceName != null) {
+            file = new File(baseDir, resourceName);
+        }
+        
+        try {
+            if ( !file.exists() ) {
+                if (resourceName != null) {
+                    // Use getResource and getResourceAsStream
+                    stream = getClass().getClassLoader()
+                        .getResourceAsStream(resourceName);
+                    if( stream != null ) {
+                        source = new InputSource
+                            (getClass().getClassLoader()
+                            .getResource(resourceName).toString());
+                    }
+                }
+            } else {
+                source =
+                    new InputSource("file://" + file.getAbsolutePath());
+                stream = new FileInputStream(file);
+                // Add as watched resource so that cascade reload occurs if a default
+                // config file is modified/added/removed
+                context.addWatchedResource(file.getAbsolutePath());
+            }
+        } catch (Exception e) {
+            log.error(sm.getString("contextConfig.defaultMissing") 
+                      + " " + resourceName + " " + file , e);
+        }
+        
+        if (source == null)
+            return;
+        if (contextDigester == null){
+            contextDigester = createContextDigester();
+        }
+        synchronized (contextDigester) {
+            try {
+                source.setByteStream(stream);
+                contextDigester.setClassLoader(this.getClass().getClassLoader());
+                contextDigester.setUseContextClassLoader(false);
+                contextDigester.push(context.getParent());
+                contextDigester.push(context);
+                contextDigester.setErrorHandler(new ContextErrorHandler());
+                contextDigester.parse(source);
+                if (parseException != null) {
+                    ok = false;
+                }
+                if (log.isDebugEnabled())
+                    log.debug("Successfully processed context [" + context.getName() 
+                            + "] configuration file " + baseDir + " " + resourceName);
+            } catch (SAXParseException e) {
+                log.error(sm.getString("contextConfig.defaultParse"), e);
+                log.error(sm.getString("contextConfig.defaultPosition",
+                                 "" + e.getLineNumber(),
+                                 "" + e.getColumnNumber()));
+                ok = false;
+            } catch (Exception e) {
+                log.error(sm.getString("contextConfig.defaultParse"), e);
+                ok = false;
+            } finally {
+                contextDigester.reset();
+                parseException = null;
+                try {
+                    if (stream != null) {
+                        stream.close();
+                    }
+                } catch (IOException e) {
+                    log.error(sm.getString("contextConfig.defaultClose"), e);
+                }
+            }
+        }
+    }
+
+    
+    /**
+     * Adjust docBase.
+     */
+    protected void fixDocBase()
+        throws IOException {
+        
+        Host host = (Host) context.getParent();
+        String appBase = host.getAppBase();
+
+        boolean unpackWARs = true;
+        if (host instanceof StandardHost) {
+            unpackWARs = ((StandardHost) host).isUnpackWARs() 
+                && ((StandardContext) context).getUnpackWAR();
+        }
+
+        File canonicalAppBase = new File(appBase);
+        if (canonicalAppBase.isAbsolute()) {
+            canonicalAppBase = canonicalAppBase.getCanonicalFile();
+        } else {
+            canonicalAppBase = 
+                new File(System.getProperty("catalina.base"), appBase)
+                .getCanonicalFile();
+        }
+
+        String docBase = context.getDocBase();
+        if (docBase == null) {
+            // Trying to guess the docBase according to the path
+            String path = context.getPath();
+            if (path == null) {
+                return;
+            }
+            if (path.equals("")) {
+                docBase = "ROOT";
+            } else {
+                if (path.startsWith("/")) {
+                    docBase = path.substring(1);
+                } else {
+                    docBase = path;
+                }
+            }
+        }
+
+        File file = new File(docBase);
+        if (!file.isAbsolute()) {
+            docBase = (new File(canonicalAppBase, docBase)).getPath();
+        } else {
+            docBase = file.getCanonicalPath();
+        }
+        file = new File(docBase);
+        String origDocBase = docBase ;
+ 
+        if (docBase.toLowerCase().endsWith(".war") && !file.isDirectory() && unpackWARs) {
+            URL war = new URL("jar:" + (new File(docBase)).toURL() + "!/");
+            String contextPath = context.getPath();
+            if (contextPath.equals("")) {
+                contextPath = "ROOT";
+            }
+            docBase = ExpandWar.expand(host, war, contextPath);
+            file = new File(docBase);
+            docBase = file.getCanonicalPath();
+            if (context instanceof StandardContext) {
+                ((StandardContext) context).setOriginalDocBase(origDocBase);
+            }
+        } else {
+            File docDir = new File(docBase);
+            if (!docDir.exists()) {
+                File warFile = new File(docBase + ".war");
+                if (warFile.exists()) {
+                    if (unpackWARs) {
+                        URL war = new URL("jar:" + warFile.toURL() + "!/");
+                        docBase = ExpandWar.expand(host, war, context.getPath());
+                        file = new File(docBase);
+                        docBase = file.getCanonicalPath();
+                    } else {
+                        docBase = warFile.getCanonicalPath();
+                    }
+                }
+                if (context instanceof StandardContext) {
+                    ((StandardContext)context).setOriginalDocBase(origDocBase);
+                }
+            }
+        }
+
+        if (docBase.startsWith(canonicalAppBase.getPath())) {
+            docBase = docBase.substring(canonicalAppBase.getPath().length());
+            docBase = docBase.replace(File.separatorChar, '/');
+            if (docBase.startsWith("/")) {
+                docBase = docBase.substring(1);
+            }
+        } else {
+            docBase = docBase.replace(File.separatorChar, '/');
+        }
+
+        context.setDocBase(docBase);
+
+    }
+    
+    
+    protected void antiLocking()
+        throws IOException {
+
+        if ((context instanceof StandardContext) 
+            && ((StandardContext) context).getAntiResourceLocking()) {
+            
+            Host host = (Host) context.getParent();
+            String appBase = host.getAppBase();
+            String docBase = context.getDocBase();
+            if (docBase == null)
+                return;
+            if (originalDocBase == null) {
+                originalDocBase = docBase;
+            } else {
+                docBase = originalDocBase;
+            }
+            File docBaseFile = new File(docBase);
+            if (!docBaseFile.isAbsolute()) {
+                File file = new File(appBase);
+                if (!file.isAbsolute()) {
+                    file = new File(System.getProperty("catalina.base"), appBase);
+                }
+                docBaseFile = new File(file, docBase);
+            }
+            
+            String path = context.getPath();
+            if (path == null) {
+                return;
+            }
+            if (path.equals("")) {
+                docBase = "ROOT";
+            } else {
+                if (path.startsWith("/")) {
+                    docBase = path.substring(1);
+                } else {
+                    docBase = path;
+                }
+            }
+
+            File file = null;
+            if (docBase.toLowerCase().endsWith(".war")) {
+                file = new File(System.getProperty("java.io.tmpdir"),
+                        deploymentCount++ + "-" + docBase + ".war");
+            } else {
+                file = new File(System.getProperty("java.io.tmpdir"), 
+                        deploymentCount++ + "-" + docBase);
+            }
+            
+            if (log.isDebugEnabled())
+                log.debug("Anti locking context[" + context.getPath() 
+                        + "] 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.
+     */
+    protected void init() {
+        // Called from StandardContext.init()
+
+        if (log.isDebugEnabled())
+            log.debug(sm.getString("contextConfig.init"));
+        context.setConfigured(false);
+        ok = true;
+        
+        contextConfig();
+        
+        try {
+            fixDocBase();
+        } catch (IOException e) {
+            log.error(sm.getString("contextConfig.fixDocBase"), e);
+        }
+        
+    }
+    
+    
+    /**
+     * Process a "before start" event for this Context.
+     */
+    protected synchronized void beforeStart() {
+        
+        try {
+            antiLocking();
+        } catch (IOException e) {
+            log.error(sm.getString("contextConfig.antiLocking"), e);
+        }
+        
+    }
+    
+    
+    /**
+     * Process a "start" event for this Context.
+     */
+    protected synchronized void start() {
+        // Called from StandardContext.start()
+
+        if (log.isDebugEnabled())
+            log.debug(sm.getString("contextConfig.start"));
+
+        // Set properties based on DefaultContext
+        Container container = context.getParent();
+        if( !context.getOverride() ) {
+            if( container instanceof Host ) {
+                // Reset the value only if the attribute wasn't
+                // set on the context.
+                xmlValidation = context.getXmlValidation();
+                if (!xmlValidation) {
+                    xmlValidation = ((Host)container).getXmlValidation();
+                }
+                
+                xmlNamespaceAware = context.getXmlNamespaceAware();
+                if (!xmlNamespaceAware){
+                    xmlNamespaceAware 
+                                = ((Host)container).getXmlNamespaceAware();
+                }
+
+                container = container.getParent();
+            }
+        }
+
+        // Process the default and application web.xml files
+        defaultWebConfig();
+        applicationWebConfig();
+        if (ok) {
+            validateSecurityRoles();
+        }
+
+        // Configure an authenticator if we need one
+        if (ok)
+            authenticatorConfig();
+
+        // Dump the contents of this pipeline if requested
+        if ((log.isDebugEnabled()) && (context instanceof ContainerBase)) {
+            log.debug("Pipeline Configuration:");
+            Pipeline pipeline = ((ContainerBase) context).getPipeline();
+            Valve valves[] = null;
+            if (pipeline != null)
+                valves = pipeline.getValves();
+            if (valves != null) {
+                for (int i = 0; i < valves.length; i++) {
+                    log.debug("  " + valves[i].getInfo());
+                }
+            }
+            log.debug("======================");
+        }
+
+        // Make our application available if no problems were encountered
+        if (ok)
+            context.setConfigured(true);
+        else {
+            log.error(sm.getString("contextConfig.unavailable"));
+            context.setConfigured(false);
+        }
+
+    }
+
+
+    /**
+     * Process a "stop" event for this Context.
+     */
+    protected synchronized void stop() {
+
+        if (log.isDebugEnabled())
+            log.debug(sm.getString("contextConfig.stop"));
+
+        int i;
+
+        // Removing children
+        Container[] children = context.findChildren();
+        for (i = 0; i < children.length; i++) {
+            context.removeChild(children[i]);
+        }
+
+        // Removing application parameters
+        /*
+        ApplicationParameter[] applicationParameters =
+            context.findApplicationParameters();
+        for (i = 0; i < applicationParameters.length; i++) {
+            context.removeApplicationParameter
+                (applicationParameters[i].getName());
+        }
+        */
+
+        // Removing security constraints
+        SecurityConstraint[] securityConstraints = context.findConstraints();
+        for (i = 0; i < securityConstraints.length; i++) {
+            context.removeConstraint(securityConstraints[i]);
+        }
+
+        // Removing Ejbs
+        /*
+        ContextEjb[] contextEjbs = context.findEjbs();
+        for (i = 0; i < contextEjbs.length; i++) {
+            context.removeEjb(contextEjbs[i].getName());
+        }
+        */
+
+        // Removing environments
+        /*
+        ContextEnvironment[] contextEnvironments = context.findEnvironments();
+        for (i = 0; i < contextEnvironments.length; i++) {
+            context.removeEnvironment(contextEnvironments[i].getName());
+        }
+        */
+
+        // Removing errors pages
+        ErrorPage[] errorPages = context.findErrorPages();
+        for (i = 0; i < errorPages.length; i++) {
+            context.removeErrorPage(errorPages[i]);
+        }
+
+        // Removing filter defs
+        FilterDef[] filterDefs = context.findFilterDefs();
+        for (i = 0; i < filterDefs.length; i++) {
+            context.removeFilterDef(filterDefs[i]);
+        }
+
+        // Removing filter maps
+        FilterMap[] filterMaps = context.findFilterMaps();
+        for (i = 0; i < filterMaps.length; i++) {
+            context.removeFilterMap(filterMaps[i]);
+        }
+
+        // Removing local ejbs
+        /*
+        ContextLocalEjb[] contextLocalEjbs = context.findLocalEjbs();
+        for (i = 0; i < contextLocalEjbs.length; i++) {
+            context.removeLocalEjb(contextLocalEjbs[i].getName());
+        }
+        */
+
+        // Removing Mime mappings
+        String[] mimeMappings = context.findMimeMappings();
+        for (i = 0; i < mimeMappings.length; i++) {
+            context.removeMimeMapping(mimeMappings[i]);
+        }
+
+        // Removing parameters
+        String[] parameters = context.findParameters();
+        for (i = 0; i < parameters.length; i++) {
+            context.removeParameter(parameters[i]);
+        }
+
+        // Removing resource env refs
+        /*
+        String[] resourceEnvRefs = context.findResourceEnvRefs();
+        for (i = 0; i < resourceEnvRefs.length; i++) {
+            context.removeResourceEnvRef(resourceEnvRefs[i]);
+        }
+        */
+
+        // Removing resource links
+        /*
+        ContextResourceLink[] contextResourceLinks =
+            context.findResourceLinks();
+        for (i = 0; i < contextResourceLinks.length; i++) {
+            context.removeResourceLink(contextResourceLinks[i].getName());
+        }
+        */
+
+        // Removing resources
+        /*
+        ContextResource[] contextResources = context.findResources();
+        for (i = 0; i < contextResources.length; i++) {
+            context.removeResource(contextResources[i].getName());
+        }
+        */
+
+        // Removing sercurity role
+        String[] securityRoles = context.findSecurityRoles();
+        for (i = 0; i < securityRoles.length; i++) {
+            context.removeSecurityRole(securityRoles[i]);
+        }
+
+        // Removing servlet mappings
+        String[] servletMappings = context.findServletMappings();
+        for (i = 0; i < servletMappings.length; i++) {
+            context.removeServletMapping(servletMappings[i]);
+        }
+
+        // FIXME : Removing status pages
+
+        // Removing taglibs
+        String[] taglibs = context.findTaglibs();
+        for (i = 0; i < taglibs.length; i++) {
+            context.removeTaglib(taglibs[i]);
+        }
+
+        // Removing welcome files
+        String[] welcomeFiles = context.findWelcomeFiles();
+        for (i = 0; i < welcomeFiles.length; i++) {
+            context.removeWelcomeFile(welcomeFiles[i]);
+        }
+
+        // Removing wrapper lifecycles
+        String[] wrapperLifecycles = context.findWrapperLifecycles();
+        for (i = 0; i < wrapperLifecycles.length; i++) {
+            context.removeWrapperLifecycle(wrapperLifecycles[i]);
+        }
+
+        // Removing wrapper listeners
+        String[] wrapperListeners = context.findWrapperListeners();
+        for (i = 0; i < wrapperListeners.length; i++) {
+            context.removeWrapperListener(wrapperListeners[i]);
+        }
+
+        // Remove (partially) folders and files created by antiLocking
+        Host host = (Host) context.getParent();
+        String appBase = host.getAppBase();
+        String docBase = context.getDocBase();
+        if ((docBase != null) && (originalDocBase != null)) {
+            File docBaseFile = new File(docBase);
+            if (!docBaseFile.isAbsolute()) {
+                docBaseFile = new File(appBase, docBase);
+            }
+            ExpandWar.delete(docBaseFile);
+        }
+        
+        ok = true;
+
+    }
+    
+    
+    /**
+     * Process a "destroy" event for this Context.
+     */
+    protected synchronized void destroy() {
+        // Called from StandardContext.destroy()
+        if (log.isDebugEnabled())
+            log.debug(sm.getString("contextConfig.destroy"));
+
+        // Changed to getWorkPath per Bugzilla 35819.
+        String workDir = ((StandardContext) context).getWorkPath();
+        if (workDir != null)
+            ExpandWar.delete(new File(workDir));
+    }
+    
+    
+    /**
+     * Validate the usage of security role names in the web application
+     * deployment descriptor.  If any problems are found, issue warning
+     * messages (for backwards compatibility) and add the missing roles.
+     * (To make these problems fatal instead, simply set the <code>ok</code>
+     * instance variable to <code>false</code> as well).
+     */
+    protected void validateSecurityRoles() {
+
+        // Check role names used in <security-constraint> elements
+        SecurityConstraint constraints[] = context.findConstraints();
+        for (int i = 0; i < constraints.length; i++) {
+            String roles[] = constraints[i].findAuthRoles();
+            for (int j = 0; j < roles.length; j++) {
+                if (!"*".equals(roles[j]) &&
+                    !context.findSecurityRole(roles[j])) {
+                    log.info(sm.getString("contextConfig.role.auth", roles[j]));
+                    context.addSecurityRole(roles[j]);
+                }
+            }
+        }
+
+        // Check role names used in <servlet> elements
+        Container wrappers[] = context.findChildren();
+        for (int i = 0; i < wrappers.length; i++) {
+            Wrapper wrapper = (Wrapper) wrappers[i];
+            String runAs = wrapper.getRunAs();
+            if ((runAs != null) && !context.findSecurityRole(runAs)) {
+                log.info(sm.getString("contextConfig.role.runas", runAs));
+                context.addSecurityRole(runAs);
+            }
+            String names[] = wrapper.findSecurityReferences();
+            for (int j = 0; j < names.length; j++) {
+                String link = wrapper.findSecurityReference(names[j]);
+                if ((link != null) && !context.findSecurityRole(link)) {
+                    log.info(sm.getString("contextConfig.role.link", link));
+                    context.addSecurityRole(link);
+                }
+            }
+        }
+
+    }
+
+
+    /**
+     * Get config base.
+     */
+    protected File getConfigBase() {
+        File configBase = 
+            new File(System.getProperty("catalina.base"), "conf");
+        if (!configBase.exists()) {
+            return null;
+        } else {
+            return configBase;
+        }
+    }  
+
+    
+    protected String getHostConfigPath(String resourceName) {
+        StringBuffer result = new StringBuffer();
+        Container container = context;
+        Container host = null;
+        Container engine = null;
+        while (container != null) {
+            if (container instanceof Host)
+                host = container;
+            if (container instanceof Engine)
+                engine = container;
+            container = container.getParent();
+        }
+        if (engine != null) {
+            result.append(engine.getName()).append('/');
+        }
+        if (host != null) {
+            result.append(host.getName()).append('/');
+        }
+        result.append(resourceName);
+        return result.toString();
+    }
+
+
+    protected class ContextErrorHandler
+        implements ErrorHandler {
+
+        public void error(SAXParseException exception) {
+            parseException = exception;
+        }
+
+        public void fatalError(SAXParseException exception) {
+            parseException = exception;
+        }
+
+        public void warning(SAXParseException exception) {
+            parseException = exception;
+        }
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/startup/ContextRuleSet.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/startup/ContextRuleSet.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/startup/ContextRuleSet.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,214 @@
+/*
+ * Copyright 1999-2001,2004-2005 The Apache Software Foundation.
+ * 
+ * Licensed 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.startup;
+
+
+import org.apache.tomcat.util.digester.Digester;
+import org.apache.tomcat.util.digester.RuleSetBase;
+
+
+/**
+ * <p><strong>RuleSet</strong> for processing the contents of a
+ * Context or DefaultContext definition element.  To enable parsing of a
+ * DefaultContext, be sure to specify a prefix that ends with "/Default".</p>
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 440936 $ $Date: 2006-09-06 20:51:28 -0500 (Wed, 06 Sep 2006) $
+ */
+
+public class ContextRuleSet extends RuleSetBase {
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The matching pattern prefix to use for recognizing our elements.
+     */
+    protected String prefix = null;
+
+
+    /**
+     * Should the context be created.
+     */
+    protected boolean create = true;
+
+
+    // ------------------------------------------------------------ Constructor
+
+
+    /**
+     * Construct an instance of this <code>RuleSet</code> with the default
+     * matching pattern prefix.
+     */
+    public ContextRuleSet() {
+
+        this("");
+
+    }
+
+
+    /**
+     * Construct an instance of this <code>RuleSet</code> with the specified
+     * matching pattern prefix.
+     *
+     * @param prefix Prefix for matching pattern rules (including the
+     *  trailing slash character)
+     */
+    public ContextRuleSet(String prefix) {
+
+        super();
+        this.namespaceURI = null;
+        this.prefix = prefix;
+
+    }
+
+
+    /**
+     * Construct an instance of this <code>RuleSet</code> with the specified
+     * matching pattern prefix.
+     *
+     * @param prefix Prefix for matching pattern rules (including the
+     *  trailing slash character)
+     */
+    public ContextRuleSet(String prefix, boolean create) {
+
+        super();
+        this.namespaceURI = null;
+        this.prefix = prefix;
+        this.create = create;
+
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * <p>Add the set of Rule instances defined in this RuleSet to the
+     * specified <code>Digester</code> instance, associating them with
+     * our namespace URI (if any).  This method should only be called
+     * by a Digester instance.</p>
+     *
+     * @param digester Digester instance to which the new Rule instances
+     *  should be added.
+     */
+    public void addRuleInstances(Digester digester) {
+
+        if (create) {
+            digester.addObjectCreate(prefix + "Context",
+                    "org.apache.catalina.core.StandardContext", "className");
+            digester.addSetProperties(prefix + "Context");
+        } else {
+            digester.addRule(prefix + "Context", new SetContextPropertiesRule());
+        }
+
+        if (create) {
+            digester.addRule(prefix + "Context",
+                             new LifecycleListenerRule
+                                 ("org.apache.catalina.startup.ContextConfig",
+                                  "configClass"));
+            digester.addSetNext(prefix + "Context",
+                                "addChild",
+                                "org.apache.catalina.Container");
+        }
+        digester.addCallMethod(prefix + "Context/InstanceListener",
+                               "addInstanceListener", 0);
+
+        digester.addObjectCreate(prefix + "Context/Listener",
+                                 null, // MUST be specified in the element
+                                 "className");
+        digester.addSetProperties(prefix + "Context/Listener");
+        digester.addSetNext(prefix + "Context/Listener",
+                            "addLifecycleListener",
+                            "org.apache.catalina.LifecycleListener");
+
+        digester.addObjectCreate(prefix + "Context/Loader",
+                            "org.apache.catalina.loader.WebappLoader",
+                            "className");
+        digester.addSetProperties(prefix + "Context/Loader");
+        digester.addSetNext(prefix + "Context/Loader",
+                            "setLoader",
+                            "org.apache.catalina.Loader");
+
+        digester.addObjectCreate(prefix + "Context/Manager",
+                                 "org.apache.catalina.session.StandardManager",
+                                 "className");
+        digester.addSetProperties(prefix + "Context/Manager");
+        digester.addSetNext(prefix + "Context/Manager",
+                            "setManager",
+                            "org.apache.catalina.Manager");
+
+        digester.addObjectCreate(prefix + "Context/Manager/Store",
+                                 null, // MUST be specified in the element
+                                 "className");
+        digester.addSetProperties(prefix + "Context/Manager/Store");
+        digester.addSetNext(prefix + "Context/Manager/Store",
+                            "setStore",
+                            "org.apache.catalina.Store");
+
+        digester.addObjectCreate(prefix + "Context/Parameter",
+                                 "org.apache.catalina.deploy.ApplicationParameter");
+        digester.addSetProperties(prefix + "Context/Parameter");
+        digester.addSetNext(prefix + "Context/Parameter",
+                            "addApplicationParameter",
+                            "org.apache.catalina.deploy.ApplicationParameter");
+
+        digester.addObjectCreate(prefix + "Context/Realm",
+                                 null, // MUST be specified in the element
+                                 "className");
+        digester.addSetProperties(prefix + "Context/Realm");
+        digester.addSetNext(prefix + "Context/Realm",
+                            "setRealm",
+                            "org.apache.catalina.Realm");
+
+        digester.addObjectCreate(prefix + "Context/Resources",
+                                 "org.apache.naming.resources.FileDirContext",
+                                 "className");
+        digester.addSetProperties(prefix + "Context/Resources");
+        digester.addSetNext(prefix + "Context/Resources",
+                            "setResources",
+                            "javax.naming.directory.DirContext");
+
+        digester.addObjectCreate(prefix + "Context/ResourceLink",
+                "org.apache.catalina.deploy.ContextResourceLink");
+        digester.addSetProperties(prefix + "Context/ResourceLink");
+        digester.addRule(prefix + "Context/ResourceLink",
+                new SetNextNamingRule("addResourceLink",
+                        "org.apache.catalina.deploy.ContextResourceLink"));
+
+        digester.addObjectCreate(prefix + "Context/Valve",
+                                 null, // MUST be specified in the element
+                                 "className");
+        digester.addSetProperties(prefix + "Context/Valve");
+        digester.addSetNext(prefix + "Context/Valve",
+                            "addValve",
+                            "org.apache.catalina.Valve");
+
+        digester.addCallMethod(prefix + "Context/WatchedResource",
+                               "addWatchedResource", 0);
+
+        digester.addCallMethod(prefix + "Context/WrapperLifecycle",
+                               "addWrapperLifecycle", 0);
+
+        digester.addCallMethod(prefix + "Context/WrapperListener",
+                               "addWrapperListener", 0);
+
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/startup/CopyParentClassLoaderRule.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/startup/CopyParentClassLoaderRule.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/startup/CopyParentClassLoaderRule.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,76 @@
+/*
+ * Copyright 1999-2001,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.startup;
+
+
+import java.lang.reflect.Method;
+import org.apache.catalina.Container;
+import org.apache.tomcat.util.digester.Rule;
+import org.xml.sax.Attributes;
+
+
+/**
+ * <p>Rule that copies the <code>parentClassLoader</code> property from the
+ * next-to-top item on the stack (which must be a <code>Container</code>)
+ * to the top item on the stack (which must also be a
+ * <code>Container</code>).</p>
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302984 $ $Date: 2004-06-26 12:41:33 -0500 (Sat, 26 Jun 2004) $
+ */
+
+public class CopyParentClassLoaderRule extends Rule {
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Construct a new instance of this Rule.
+     */
+    public CopyParentClassLoaderRule() {
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Handle the beginning of an XML element.
+     *
+     * @param attributes The attributes of this element
+     *
+     * @exception Exception if a processing error occurs
+     */
+    public void begin(String namespace, String name, Attributes attributes)
+        throws Exception {
+
+        if (digester.getLogger().isDebugEnabled())
+            digester.getLogger().debug("Copying parent class loader");
+        Container child = (Container) digester.peek(0);
+        Object parent = digester.peek(1);
+        Method method =
+            parent.getClass().getMethod("getParentClassLoader", new Class[0]);
+        ClassLoader classLoader =
+            (ClassLoader) method.invoke(parent, new Object[0]);
+        child.setParentClassLoader(classLoader);
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/startup/DigesterFactory.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/startup/DigesterFactory.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/startup/DigesterFactory.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,164 @@
+/*
+ * Copyright 1999-2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.startup;
+
+import java.net.URL;
+
+import org.apache.catalina.util.SchemaResolver;
+import org.apache.tomcat.util.digester.Digester;
+import org.apache.tomcat.util.digester.RuleSet;
+
+/**
+ * Wrapper class around the Digester that hide Digester's initialization details
+ *
+ * @author Jean-Francois Arcand
+ */
+public class DigesterFactory {
+    /**
+     * The log.
+     */
+   protected static org.apache.commons.logging.Log log = 
+       org.apache.commons.logging.LogFactory.getLog(DigesterFactory.class);
+
+    /**
+     * The XML entiry resolver used by the Digester.
+     */
+    private static SchemaResolver schemaResolver;
+
+
+    /**
+     * Create a <code>Digester</code> parser with no <code>Rule</code>
+     * associated and XML validation turned off.
+     */
+    public static Digester newDigester(){
+        return newDigester(false, false, null);
+    }
+
+    
+    /**
+     * Create a <code>Digester</code> parser with XML validation turned off.
+     * @param rule an instance of <code>RuleSet</code> used for parsing the xml.
+     */
+    public static Digester newDigester(RuleSet rule){
+        return newDigester(false,false,rule);
+    }
+
+    
+    /**
+     * Create a <code>Digester</code> parser.
+     * @param xmlValidation turn on/off xml validation
+     * @param xmlNamespaceAware turn on/off namespace validation
+     * @param rule an instance of <code>RuleSet</code> used for parsing the xml.
+     */
+    public static Digester newDigester(boolean xmlValidation,
+                                       boolean xmlNamespaceAware,
+                                       RuleSet rule) {
+        Digester digester = new Digester();
+        digester.setNamespaceAware(xmlNamespaceAware);
+        digester.setValidating(xmlValidation);
+        digester.setUseContextClassLoader(true);
+
+        if (xmlValidation || xmlNamespaceAware){
+            configureSchema(digester);        
+        }
+
+        schemaResolver = new SchemaResolver(digester);
+        registerLocalSchema();
+        
+        digester.setEntityResolver(schemaResolver);
+        if ( rule != null ) {
+            digester.addRuleSet(rule);
+        }
+
+        return (digester);
+    }
+
+
+    /**
+     * Utilities used to force the parser to use local schema, when available,
+     * instead of the <code>schemaLocation</code> XML element.
+     */
+    protected static void registerLocalSchema(){
+        // J2EE
+        register(Constants.J2eeSchemaResourcePath_14,
+                 Constants.J2eeSchemaPublicId_14);
+        // W3C
+        register(Constants.W3cSchemaResourcePath_10,
+                 Constants.W3cSchemaPublicId_10);
+        // JSP
+        register(Constants.JspSchemaResourcePath_20,
+                 Constants.JspSchemaPublicId_20);
+        // TLD
+        register(Constants.TldDtdResourcePath_11,  
+                 Constants.TldDtdPublicId_11);
+        
+        register(Constants.TldDtdResourcePath_12,
+                 Constants.TldDtdPublicId_12);
+
+        register(Constants.TldSchemaResourcePath_20,
+                 Constants.TldSchemaPublicId_20);
+
+        // web.xml    
+        register(Constants.WebDtdResourcePath_22,
+                 Constants.WebDtdPublicId_22);
+
+        register(Constants.WebDtdResourcePath_23,
+                 Constants.WebDtdPublicId_23);
+
+        register(Constants.WebSchemaResourcePath_24,
+                 Constants.WebSchemaPublicId_24);
+
+        // Web Service
+        register(Constants.J2eeWebServiceSchemaResourcePath_11,
+                 Constants.J2eeWebServiceSchemaPublicId_11);
+
+        register(Constants.J2eeWebServiceClientSchemaResourcePath_11,
+                 Constants.J2eeWebServiceClientSchemaPublicId_11);
+
+    }
+
+
+    /**
+     * Load the resource and add it to the resolver.
+     */
+    protected static void register(String resourceURL, String resourcePublicId){
+        URL url = DigesterFactory.class.getResource(resourceURL);
+   
+        if(url == null) {
+            log.warn("Could not get url for " + resourceURL);
+        } else {
+            schemaResolver.register(resourcePublicId , url.toString() );
+        }
+    }
+
+
+    /**
+     * Turn on DTD and/or validation (based on the parser implementation)
+     */
+    protected static void configureSchema(Digester digester){
+        URL url = DigesterFactory.class
+                        .getResource(Constants.WebSchemaResourcePath_24);
+  
+        if(url == null) {
+            log.error("Could not get url for " 
+                                        + Constants.WebSchemaResourcePath_24);
+        } else {
+            digester.setSchema(url.toString());     
+        }
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/startup/Embedded.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/startup/Embedded.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/startup/Embedded.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,993 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.startup;
+
+
+import java.io.File;
+import java.io.IOException;
+import java.net.InetAddress;
+import java.util.HashMap;
+
+import org.apache.catalina.Authenticator;
+import org.apache.catalina.Container;
+import org.apache.catalina.Context;
+import org.apache.catalina.Engine;
+import org.apache.catalina.Host;
+import org.apache.catalina.Lifecycle;
+import org.apache.catalina.LifecycleException;
+import org.apache.catalina.LifecycleListener;
+import org.apache.catalina.Loader;
+import org.apache.catalina.Realm;
+import org.apache.catalina.Valve;
+import org.apache.catalina.connector.Connector;
+import org.apache.catalina.core.StandardContext;
+import org.apache.catalina.core.StandardEngine;
+import org.apache.catalina.core.StandardHost;
+import org.apache.catalina.core.StandardService;
+import org.apache.catalina.loader.WebappLoader;
+import org.apache.catalina.security.SecurityConfig;
+import org.apache.catalina.util.LifecycleSupport;
+import org.apache.catalina.util.StringManager;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.tomcat.util.IntrospectionUtils;
+import org.apache.tomcat.util.log.SystemLogHandler;
+
+
+/**
+ * Convenience class to embed a Catalina servlet container environment
+ * inside another application.  You must call the methods of this class in the
+ * following order to ensure correct operation.
+ *
+ * <ul>
+ * <li>Instantiate a new instance of this class.</li>
+ * <li>Set the relevant properties of this object itself.  In particular,
+ *     you will want to establish the default Logger to be used, as well
+ *     as the default Realm if you are using container-managed security.</li>
+ * <li>Call <code>createEngine()</code> to create an Engine object, and then
+ *     call its property setters as desired.</li>
+ * <li>Call <code>createHost()</code> to create at least one virtual Host
+ *     associated with the newly created Engine, and then call its property
+ *     setters as desired.  After you customize this Host, add it to the
+ *     corresponding Engine with <code>engine.addChild(host)</code>.</li>
+ * <li>Call <code>createContext()</code> to create at least one Context
+ *     associated with each newly created Host, and then call its property
+ *     setters as desired.  You <strong>SHOULD</strong> create a Context with
+ *     a pathname equal to a zero-length string, which will be used to process
+ *     all requests not mapped to some other Context.  After you customize
+ *     this Context, add it to the corresponding Host with
+ *     <code>host.addChild(context)</code>.</li>
+ * <li>Call <code>addEngine()</code> to attach this Engine to the set of
+ *     defined Engines for this object.</li>
+ * <li>Call <code>createConnector()</code> to create at least one TCP/IP
+ *     connector, and then call its property setters as desired.</li>
+ * <li>Call <code>addConnector()</code> to attach this Connector to the set
+ *     of defined Connectors for this object.  The added Connector will use
+ *     the most recently added Engine to process its received requests.</li>
+ * <li>Repeat the above series of steps as often as required (although there
+ *     will typically be only one Engine instance created).</li>
+ * <li>Call <code>start()</code> to initiate normal operations of all the
+ *     attached components.</li>
+ * </ul>
+ *
+ * After normal operations have begun, you can add and remove Connectors,
+ * Engines, Hosts, and Contexts on the fly.  However, once you have removed
+ * a particular component, it must be thrown away -- you can create a new one
+ * with the same characteristics if you merely want to do a restart.
+ * <p>
+ * To initiate a normal shutdown, call the <code>stop()</code> method of
+ * this object.
+ * <p>
+ * @see org.apache.catalina.startup.Catalina#main For a complete example
+ * of how Tomcat is set up and launched as an Embedded application.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 304107 $ $Date: 2005-09-29 00:52:48 -0500 (Thu, 29 Sep 2005) $
+ */
+
+public class Embedded  extends StandardService implements Lifecycle {
+    private static Log log = LogFactory.getLog(Embedded.class);
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Construct a new instance of this class with default properties.
+     */
+    public Embedded() {
+
+        this(null);
+
+    }
+
+
+    /**
+     * Construct a new instance of this class with specified properties.
+     *
+     * @param realm Realm implementation to be inherited by all components
+     *  (unless overridden further down the container hierarchy)
+     */
+    public Embedded(Realm realm) {
+
+        super();
+        setRealm(realm);
+        setSecurityProtection();
+        
+    }
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * Is naming enabled ?
+     */
+    protected boolean useNaming = true;
+
+
+    /**
+     * Is standard streams redirection enabled ?
+     */
+    protected boolean redirectStreams = true;
+
+
+    /**
+     * The set of Engines that have been deployed in this server.  Normally
+     * there will only be one.
+     */
+    protected Engine engines[] = new Engine[0];
+
+
+    /**
+     * Custom mappings of login methods to authenticators
+     */
+    protected HashMap authenticators;
+
+
+    /**
+     * Descriptive information about this server implementation.
+     */
+    protected static final String info =
+        "org.apache.catalina.startup.Embedded/1.0";
+
+
+    /**
+     * The lifecycle event support for this component.
+     */
+    protected LifecycleSupport lifecycle = new LifecycleSupport(this);
+
+
+    /**
+     * The default realm to be used by all containers associated with
+     * this compoennt.
+     */
+    protected Realm realm = null;
+
+
+    /**
+     * The string manager for this package.
+     */
+    protected static StringManager sm =
+        StringManager.getManager(Constants.Package);
+
+
+    /**
+     * Has this component been started yet?
+     */
+    protected boolean started = false;
+
+    /**
+     * Use await.
+     */
+    protected boolean await = false;
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * Return true if naming is enabled.
+     */
+    public boolean isUseNaming() {
+
+        return (this.useNaming);
+
+    }
+
+
+    /**
+     * Enables or disables naming support.
+     *
+     * @param useNaming The new use naming value
+     */
+    public void setUseNaming(boolean useNaming) {
+
+        boolean oldUseNaming = this.useNaming;
+        this.useNaming = useNaming;
+        support.firePropertyChange("useNaming", new Boolean(oldUseNaming),
+                                   new Boolean(this.useNaming));
+
+    }
+
+
+    /**
+     * Return true if redirction of standard streams is enabled.
+     */
+    public boolean isRedirectStreams() {
+
+        return (this.redirectStreams);
+
+    }
+
+
+    /**
+     * Enables or disables naming support.
+     *
+     * @param useNaming The new use naming value
+     */
+    public void setRedirectStreams(boolean redirectStreams) {
+
+        boolean oldRedirectStreams = this.redirectStreams;
+        this.redirectStreams = redirectStreams;
+        support.firePropertyChange("redirectStreams", new Boolean(oldRedirectStreams),
+                                   new Boolean(this.redirectStreams));
+
+    }
+
+
+    /**
+     * Return the default Realm for our Containers.
+     */
+    public Realm getRealm() {
+
+        return (this.realm);
+
+    }
+
+
+    /**
+     * Set the default Realm for our Containers.
+     *
+     * @param realm The new default realm
+     */
+    public void setRealm(Realm realm) {
+
+        Realm oldRealm = this.realm;
+        this.realm = realm;
+        support.firePropertyChange("realm", oldRealm, this.realm);
+
+    }
+
+    public void setAwait(boolean b) {
+        await = b;
+    }
+
+    public boolean isAwait() {
+        return await;
+    }
+
+    public void setCatalinaHome( String s ) {
+        System.setProperty( "catalina.home", s);
+    }
+
+    public void setCatalinaBase( String s ) {
+        System.setProperty( "catalina.base", s);
+    }
+
+    public String getCatalinaHome() {
+        return System.getProperty("catalina.home");
+    }
+
+    public String getCatalinaBase() {
+        return System.getProperty("catalina.base");
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+    /**
+     * Add a new Connector to the set of defined Connectors.  The newly
+     * added Connector will be associated with the most recently added Engine.
+     *
+     * @param connector The connector to be added
+     *
+     * @exception IllegalStateException if no engines have been added yet
+     */
+    public synchronized void addConnector(Connector connector) {
+
+        if( log.isDebugEnabled() ) {
+            log.debug("Adding connector (" + connector.getInfo() + ")");
+        }
+
+        // Make sure we have a Container to send requests to
+        if (engines.length < 1)
+            throw new IllegalStateException
+                (sm.getString("embedded.noEngines"));
+
+        /*
+         * Add the connector. This will set the connector's container to the
+         * most recently added Engine
+         */
+        super.addConnector(connector);
+    }
+
+
+    /**
+     * Add a new Engine to the set of defined Engines.
+     *
+     * @param engine The engine to be added
+     */
+    public synchronized void addEngine(Engine engine) {
+
+        if( log.isDebugEnabled() )
+            log.debug("Adding engine (" + engine.getInfo() + ")");
+
+        // Add this Engine to our set of defined Engines
+        Engine results[] = new Engine[engines.length + 1];
+        for (int i = 0; i < engines.length; i++)
+            results[i] = engines[i];
+        results[engines.length] = engine;
+        engines = results;
+
+        // Start this Engine if necessary
+        if (started && (engine instanceof Lifecycle)) {
+            try {
+                ((Lifecycle) engine).start();
+            } catch (LifecycleException e) {
+                log.error("Engine.start", e);
+            }
+        }
+
+        this.container = engine;
+    }
+
+
+    /**
+     * Create, configure, and return a new TCP/IP socket connector
+     * based on the specified properties.
+     *
+     * @param address InetAddress to bind to, or <code>null</code> if the
+     * connector is supposed to bind to all addresses on this server
+     * @param port Port number to listen to
+     * @param secure true if the generated connector is supposed to be
+     * SSL-enabled, and false otherwise
+     */
+    public Connector createConnector(InetAddress address, int port,
+                                     boolean secure) {
+	return createConnector(address != null? address.toString() : null,
+			       port, secure);
+    }
+
+    public Connector createConnector(String address, int port,
+                                     boolean secure) {
+        String protocol = "http";
+        if (secure) {
+            protocol = "https";
+        }
+
+        return createConnector(address, port, protocol);
+    }
+
+
+    public Connector createConnector(InetAddress address, int port,
+                                     String protocol) {
+	return createConnector(address != null? address.toString() : null,
+			       port, protocol);
+    }
+
+    public Connector createConnector(String address, int port,
+				     String protocol) {
+
+        Connector connector = null;
+
+	if (address != null) {
+	    /*
+	     * InetAddress.toString() returns a string of the form
+	     * "<hostname>/<literal_IP>". Get the latter part, so that the
+	     * address can be parsed (back) into an InetAddress using
+	     * InetAddress.getByName().
+	     */
+	    int index = address.indexOf('/');
+	    if (index != -1) {
+		address = address.substring(index + 1);
+	    }
+	}
+
+	if (log.isDebugEnabled()) {
+            log.debug("Creating connector for address='" +
+		      ((address == null) ? "ALL" : address) +
+		      "' port='" + port + "' protocol='" + protocol + "'");
+	}
+
+        try {
+
+            if (protocol.equals("ajp")) {
+                connector = new Connector("org.apache.jk.server.JkCoyoteHandler");
+            } else if (protocol.equals("memory")) {
+                connector = new Connector("org.apache.coyote.memory.MemoryProtocolHandler");
+            } else if (protocol.equals("http")) {
+                connector = new Connector();
+            } else if (protocol.equals("https")) {
+                connector = new Connector();
+                connector.setScheme("https");
+                connector.setSecure(true);
+                // FIXME !!!! SET SSL PROPERTIES
+            }
+
+            if (address != null) {
+                IntrospectionUtils.setProperty(connector, "address", 
+                                               "" + address);
+            }
+            IntrospectionUtils.setProperty(connector, "port", "" + port);
+
+        } catch (Exception e) {
+            log.error("Couldn't create connector.");
+        } 
+
+        return (connector);
+
+    }
+
+    /**
+     * Create, configure, and return a Context that will process all
+     * HTTP requests received from one of the associated Connectors,
+     * and directed to the specified context path on the virtual host
+     * to which this Context is connected.
+     * <p>
+     * After you have customized the properties, listeners, and Valves
+     * for this Context, you must attach it to the corresponding Host
+     * by calling:
+     * <pre>
+     *   host.addChild(context);
+     * </pre>
+     * which will also cause the Context to be started if the Host has
+     * already been started.
+     *
+     * @param path Context path of this application ("" for the default
+     *  application for this host, must start with a slash otherwise)
+     * @param docBase Absolute pathname to the document base directory
+     *  for this web application
+     *
+     * @exception IllegalArgumentException if an invalid parameter
+     *  is specified
+     */
+    public Context createContext(String path, String docBase) {
+
+        if( log.isDebugEnabled() )
+            log.debug("Creating context '" + path + "' with docBase '" +
+                       docBase + "'");
+
+        StandardContext context = new StandardContext();
+
+        context.setDocBase(docBase);
+        context.setPath(path);
+
+        ContextConfig config = new ContextConfig();
+        config.setCustomAuthenticators(authenticators);
+        ((Lifecycle) context).addLifecycleListener(config);
+
+        return (context);
+
+    }
+
+
+    /**
+     * Create, configure, and return an Engine that will process all
+     * HTTP requests received from one of the associated Connectors,
+     * based on the specified properties.
+     */
+    public Engine createEngine() {
+
+        if( log.isDebugEnabled() )
+            log.debug("Creating engine");
+
+        StandardEngine engine = new StandardEngine();
+
+        // Default host will be set to the first host added
+        engine.setRealm(realm);         // Inherited by all children
+
+        return (engine);
+
+    }
+
+
+    /**
+     * Create, configure, and return a Host that will process all
+     * HTTP requests received from one of the associated Connectors,
+     * and directed to the specified virtual host.
+     * <p>
+     * After you have customized the properties, listeners, and Valves
+     * for this Host, you must attach it to the corresponding Engine
+     * by calling:
+     * <pre>
+     *   engine.addChild(host);
+     * </pre>
+     * which will also cause the Host to be started if the Engine has
+     * already been started.  If this is the default (or only) Host you
+     * will be defining, you may also tell the Engine to pass all requests
+     * not assigned to another virtual host to this one:
+     * <pre>
+     *   engine.setDefaultHost(host.getName());
+     * </pre>
+     *
+     * @param name Canonical name of this virtual host
+     * @param appBase Absolute pathname to the application base directory
+     *  for this virtual host
+     *
+     * @exception IllegalArgumentException if an invalid parameter
+     *  is specified
+     */
+    public Host createHost(String name, String appBase) {
+
+        if( log.isDebugEnabled() )
+            log.debug("Creating host '" + name + "' with appBase '" +
+                       appBase + "'");
+
+        StandardHost host = new StandardHost();
+
+        host.setAppBase(appBase);
+        host.setName(name);
+
+        return (host);
+
+    }
+
+
+    /**
+     * Create and return a class loader manager that can be customized, and
+     * then attached to a Context, before it is started.
+     *
+     * @param parent ClassLoader that will be the parent of the one
+     *  created by this Loader
+     */
+    public Loader createLoader(ClassLoader parent) {
+
+        if( log.isDebugEnabled() )
+            log.debug("Creating Loader with parent class loader '" +
+                       parent + "'");
+
+        WebappLoader loader = new WebappLoader(parent);
+        return (loader);
+
+    }
+
+
+    /**
+     * Return descriptive information about this Server implementation and
+     * the corresponding version number, in the format
+     * <code>&lt;description&gt;/&lt;version&gt;</code>.
+     */
+    public String getInfo() {
+
+        return (info);
+
+    }
+
+
+    /**
+     * Remove the specified Context from the set of defined Contexts for its
+     * associated Host.  If this is the last Context for this Host, the Host
+     * will also be removed.
+     *
+     * @param context The Context to be removed
+     */
+    public synchronized void removeContext(Context context) {
+
+        if( log.isDebugEnabled() )
+            log.debug("Removing context[" + context.getPath() + "]");
+
+        // Is this Context actually among those that are defined?
+        boolean found = false;
+        for (int i = 0; i < engines.length; i++) {
+            Container hosts[] = engines[i].findChildren();
+            for (int j = 0; j < hosts.length; j++) {
+                Container contexts[] = hosts[j].findChildren();
+                for (int k = 0; k < contexts.length; k++) {
+                    if (context == (Context) contexts[k]) {
+                        found = true;
+                        break;
+                    }
+                }
+                if (found)
+                    break;
+            }
+            if (found)
+                break;
+        }
+        if (!found)
+            return;
+
+        // Remove this Context from the associated Host
+        if( log.isDebugEnabled() )
+            log.debug(" Removing this Context");
+        context.getParent().removeChild(context);
+
+    }
+
+
+    /**
+     * Remove the specified Engine from the set of defined Engines, along with
+     * all of its related Hosts and Contexts.  All associated Connectors are
+     * also removed.
+     *
+     * @param engine The Engine to be removed
+     */
+    public synchronized void removeEngine(Engine engine) {
+
+        if( log.isDebugEnabled() )
+            log.debug("Removing engine (" + engine.getInfo() + ")");
+
+        // Is the specified Engine actually defined?
+        int j = -1;
+        for (int i = 0; i < engines.length; i++) {
+            if (engine == engines[i]) {
+                j = i;
+                break;
+            }
+        }
+        if (j < 0)
+            return;
+
+        // Remove any Connector that is using this Engine
+        if( log.isDebugEnabled() )
+            log.debug(" Removing related Containers");
+        while (true) {
+            int n = -1;
+            for (int i = 0; i < connectors.length; i++) {
+                if (connectors[i].getContainer() == (Container) engine) {
+                    n = i;
+                    break;
+                }
+            }
+            if (n < 0)
+                break;
+            removeConnector(connectors[n]);
+        }
+
+        // Stop this Engine if necessary
+        if (engine instanceof Lifecycle) {
+            if( log.isDebugEnabled() )
+                log.debug(" Stopping this Engine");
+            try {
+                ((Lifecycle) engine).stop();
+            } catch (LifecycleException e) {
+                log.error("Engine.stop", e);
+            }
+        }
+
+        // Remove this Engine from our set of defined Engines
+        if( log.isDebugEnabled() )
+            log.debug(" Removing this Engine");
+        int k = 0;
+        Engine results[] = new Engine[engines.length - 1];
+        for (int i = 0; i < engines.length; i++) {
+            if (i != j)
+                results[k++] = engines[i];
+        }
+        engines = results;
+
+    }
+
+
+    /**
+     * Remove the specified Host, along with all of its related Contexts,
+     * from the set of defined Hosts for its associated Engine.  If this is
+     * the last Host for this Engine, the Engine will also be removed.
+     *
+     * @param host The Host to be removed
+     */
+    public synchronized void removeHost(Host host) {
+
+        if( log.isDebugEnabled() )
+            log.debug("Removing host[" + host.getName() + "]");
+
+        // Is this Host actually among those that are defined?
+        boolean found = false;
+        for (int i = 0; i < engines.length; i++) {
+            Container hosts[] = engines[i].findChildren();
+            for (int j = 0; j < hosts.length; j++) {
+                if (host == (Host) hosts[j]) {
+                    found = true;
+                    break;
+
+                }
+            }
+            if (found)
+                break;
+        }
+        if (!found)
+            return;
+
+        // Remove this Host from the associated Engine
+        if( log.isDebugEnabled() )
+            log.debug(" Removing this Host");
+        host.getParent().removeChild(host);
+
+    }
+
+
+    /*
+     * Maps the specified login method to the specified authenticator, allowing
+     * the mappings in org/apache/catalina/startup/Authenticators.properties
+     * to be overridden.
+     *
+     * @param authenticator Authenticator to handle authentication for the
+     * specified login method
+     * @param loginMethod Login method that maps to the specified authenticator
+     *
+     * @throws IllegalArgumentException if the specified authenticator does not
+     * implement the org.apache.catalina.Valve interface
+     */
+    public void addAuthenticator(Authenticator authenticator,
+                                 String loginMethod) {
+        if (!(authenticator instanceof Valve)) {
+            throw new IllegalArgumentException(
+                sm.getString("embedded.authenticatorNotInstanceOfValve"));
+        }
+        if (authenticators == null) {
+            synchronized (this) {
+                if (authenticators == null) {
+                    authenticators = new HashMap();
+                }
+            }
+        }
+        authenticators.put(loginMethod, authenticator);
+    }
+
+
+    // ------------------------------------------------------ Lifecycle Methods
+
+
+    /**
+     * Add a lifecycle event listener to this component.
+     *
+     * @param listener The listener to add
+     */
+    public void addLifecycleListener(LifecycleListener listener) {
+
+        lifecycle.addLifecycleListener(listener);
+
+    }
+
+
+    /**
+     * Get the lifecycle listeners associated with this lifecycle. If this 
+     * Lifecycle has no listeners registered, a zero-length array is returned.
+     */
+    public LifecycleListener[] findLifecycleListeners() {
+
+        return lifecycle.findLifecycleListeners();
+
+    }
+
+
+    /**
+     * Remove a lifecycle event listener from this component.
+     *
+     * @param listener The listener to remove
+     */
+    public void removeLifecycleListener(LifecycleListener listener) {
+
+        lifecycle.removeLifecycleListener(listener);
+
+    }
+
+
+    /**
+     * Prepare for the beginning of active use of the public methods of this
+     * component.  This method should be called after <code>configure()</code>,
+     * and before any of the public methods of the component are utilized.
+     *
+     * @exception LifecycleException if this component detects a fatal error
+     *  that prevents this component from being used
+     */
+    public void start() throws LifecycleException {
+
+        if( log.isInfoEnabled() )
+            log.info("Starting tomcat server");
+
+        // Validate the setup of our required system properties
+        initDirs();
+
+        // Initialize some naming specific properties
+        initNaming();
+
+        // Validate and update our current component state
+        if (started)
+            throw new LifecycleException
+                (sm.getString("embedded.alreadyStarted"));
+        lifecycle.fireLifecycleEvent(START_EVENT, null);
+        started = true;
+        initialized = true;
+
+        // Start our defined Engines first
+        for (int i = 0; i < engines.length; i++) {
+            if (engines[i] instanceof Lifecycle)
+                ((Lifecycle) engines[i]).start();
+        }
+
+        // Start our defined Connectors second
+        for (int i = 0; i < connectors.length; i++) {
+            connectors[i].initialize();
+            if (connectors[i] instanceof Lifecycle)
+                ((Lifecycle) connectors[i]).start();
+        }
+
+    }
+
+
+    /**
+     * Gracefully terminate the active use of the public methods of this
+     * component.  This method should be the last one called on a given
+     * instance of this component.
+     *
+     * @exception LifecycleException if this component detects a fatal error
+     *  that needs to be reported
+     */
+    public void stop() throws LifecycleException {
+
+        if( log.isDebugEnabled() )
+            log.debug("Stopping embedded server");
+
+        // Validate and update our current component state
+        if (!started)
+            throw new LifecycleException
+                (sm.getString("embedded.notStarted"));
+        lifecycle.fireLifecycleEvent(STOP_EVENT, null);
+        started = false;
+
+        // Stop our defined Connectors first
+        for (int i = 0; i < connectors.length; i++) {
+            if (connectors[i] instanceof Lifecycle)
+                ((Lifecycle) connectors[i]).stop();
+        }
+
+        // Stop our defined Engines second
+        for (int i = 0; i < engines.length; i++) {
+            if (engines[i] instanceof Lifecycle)
+                ((Lifecycle) engines[i]).stop();
+        }
+
+    }
+
+
+    // ------------------------------------------------------ Protected Methods
+
+
+    /** Initialize naming - this should only enable java:env and root naming.
+     * If tomcat is embeded in an application that already defines those -
+     * it shouldn't do it.
+     *
+     * XXX The 2 should be separated, you may want to enable java: but not
+     * the initial context and the reverse
+     * XXX Can we "guess" - i.e. lookup java: and if something is returned assume
+     * false ?
+     * XXX We have a major problem with the current setting for java: url
+     */
+    protected void initNaming() {
+        // Setting additional variables
+        if (!useNaming) {
+            log.info( "Catalina naming disabled");
+            System.setProperty("catalina.useNaming", "false");
+        } else {
+            System.setProperty("catalina.useNaming", "true");
+            String value = "org.apache.naming";
+            String oldValue =
+                System.getProperty(javax.naming.Context.URL_PKG_PREFIXES);
+            if (oldValue != null) {
+                value = value + ":" + oldValue;
+            }
+            System.setProperty(javax.naming.Context.URL_PKG_PREFIXES, value);
+            if( log.isDebugEnabled() )
+                log.debug("Setting naming prefix=" + value);
+            value = System.getProperty
+                (javax.naming.Context.INITIAL_CONTEXT_FACTORY);
+            if (value == null) {
+                System.setProperty
+                    (javax.naming.Context.INITIAL_CONTEXT_FACTORY,
+                     "org.apache.naming.java.javaURLContextFactory");
+            } else {
+                log.debug( "INITIAL_CONTEXT_FACTORY alread set " + value );
+            }
+        }
+    }
+
+
+    protected void initDirs() {
+
+        String catalinaHome = System.getProperty("catalina.home");
+        if (catalinaHome == null) {
+            // Backwards compatibility patch for J2EE RI 1.3
+            String j2eeHome = System.getProperty("com.sun.enterprise.home");
+            if (j2eeHome != null) {
+                catalinaHome=System.getProperty("com.sun.enterprise.home");
+            } else if (System.getProperty("catalina.base") != null) {
+                catalinaHome = System.getProperty("catalina.base");
+            } else {
+                // Use IntrospectionUtils and guess the dir
+                catalinaHome = IntrospectionUtils.guessInstall
+                    ("catalina.home", "catalina.base", "catalina.jar");
+                if (catalinaHome == null) {
+                    catalinaHome = IntrospectionUtils.guessInstall
+                        ("tomcat.install", "catalina.home", "tomcat.jar");
+                }
+            }
+        }
+        // last resort - for minimal/embedded cases. 
+        if(catalinaHome==null) {
+            catalinaHome=System.getProperty("user.dir");
+        }
+        if (catalinaHome != null) {
+            File home = new File(catalinaHome);
+            if (!home.isAbsolute()) {
+                try {
+                    catalinaHome = home.getCanonicalPath();
+                } catch (IOException e) {
+                    catalinaHome = home.getAbsolutePath();
+                }
+            }
+            System.setProperty("catalina.home", catalinaHome);
+        }
+
+        if (System.getProperty("catalina.base") == null) {
+            System.setProperty("catalina.base",
+                               catalinaHome);
+        } else {
+            String catalinaBase = System.getProperty("catalina.base");
+            File base = new File(catalinaBase);
+            if (!base.isAbsolute()) {
+                try {
+                    catalinaBase = base.getCanonicalPath();
+                } catch (IOException e) {
+                    catalinaBase = base.getAbsolutePath();
+                }
+            }
+            System.setProperty("catalina.base", catalinaBase);
+        }
+        
+        String temp = System.getProperty("java.io.tmpdir");
+        if (temp == null || (!(new File(temp)).exists())
+                || (!(new File(temp)).isDirectory())) {
+            log.error(sm.getString("embedded.notmp", temp));
+        }
+
+    }
+
+    
+    protected void initStreams() {
+        if (redirectStreams) {
+            // Replace System.out and System.err with a custom PrintStream
+            SystemLogHandler systemlog = new SystemLogHandler(System.out);
+            System.setOut(systemlog);
+            System.setErr(systemlog);
+        }
+    }
+    
+
+    // -------------------------------------------------------- Private Methods
+
+    /**
+     * Set the security package access/protection.
+     */
+    protected void setSecurityProtection(){
+        SecurityConfig securityConfig = SecurityConfig.newInstance();
+        securityConfig.setPackageDefinition();
+        securityConfig.setPackageAccess();
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/startup/EngineConfig.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/startup/EngineConfig.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/startup/EngineConfig.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,111 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.startup;
+
+
+import org.apache.catalina.Engine;
+import org.apache.catalina.Lifecycle;
+import org.apache.catalina.LifecycleEvent;
+import org.apache.catalina.LifecycleListener;
+import org.apache.catalina.util.StringManager;
+
+
+/**
+ * Startup event listener for a <b>Engine</b> that configures the properties
+ * of that Engine, and the associated defined contexts.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 349922 $ $Date: 2005-11-30 05:10:55 -0600 (Wed, 30 Nov 2005) $
+ */
+
+public class EngineConfig
+    implements LifecycleListener {
+
+
+    protected static org.apache.commons.logging.Log log=
+        org.apache.commons.logging.LogFactory.getLog( EngineConfig.class );
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The Engine we are associated with.
+     */
+    protected Engine engine = null;
+
+
+    /**
+     * The string resources for this package.
+     */
+    protected static final StringManager sm =
+        StringManager.getManager(Constants.Package);
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Process the START event for an associated Engine.
+     *
+     * @param event The lifecycle event that has occurred
+     */
+    public void lifecycleEvent(LifecycleEvent event) {
+
+        // Identify the engine we are associated with
+        try {
+            engine = (Engine) event.getLifecycle();
+        } catch (ClassCastException e) {
+            log.error(sm.getString("engineConfig.cce", event.getLifecycle()), e);
+            return;
+        }
+
+        // Process the event that has occurred
+        if (event.getType().equals(Lifecycle.START_EVENT))
+            start();
+        else if (event.getType().equals(Lifecycle.STOP_EVENT))
+            stop();
+
+    }
+
+
+    // -------------------------------------------------------- Protected Methods
+
+
+    /**
+     * Process a "start" event for this Engine.
+     */
+    protected void start() {
+
+        if (engine.getLogger().isDebugEnabled())
+            engine.getLogger().debug(sm.getString("engineConfig.start"));
+
+    }
+
+
+    /**
+     * Process a "stop" event for this Engine.
+     */
+    protected void stop() {
+
+        if (engine.getLogger().isDebugEnabled())
+            engine.getLogger().debug(sm.getString("engineConfig.stop"));
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/startup/EngineRuleSet.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/startup/EngineRuleSet.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/startup/EngineRuleSet.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,149 @@
+/*
+ * Copyright 1999-2001,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.startup;
+
+
+import org.apache.tomcat.util.digester.Digester;
+import org.apache.tomcat.util.digester.RuleSetBase;
+
+
+/**
+ * <p><strong>RuleSet</strong> for processing the contents of a
+ * Engine definition element.  This <code>RuleSet</code> does NOT include
+ * any rules for nested Host or DefaultContext elements, which should
+ * be added via instances of <code>HostRuleSet</code> or
+ * <code>ContextRuleSet</code>, respectively.</p>
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 303970 $ $Date: 2005-06-30 08:08:14 -0500 (Thu, 30 Jun 2005) $
+ */
+
+public class EngineRuleSet extends RuleSetBase {
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The matching pattern prefix to use for recognizing our elements.
+     */
+    protected String prefix = null;
+
+
+    // ------------------------------------------------------------ Constructor
+
+
+    /**
+     * Construct an instance of this <code>RuleSet</code> with the default
+     * matching pattern prefix.
+     */
+    public EngineRuleSet() {
+
+        this("");
+
+    }
+
+
+    /**
+     * Construct an instance of this <code>RuleSet</code> with the specified
+     * matching pattern prefix.
+     *
+     * @param prefix Prefix for matching pattern rules (including the
+     *  trailing slash character)
+     */
+    public EngineRuleSet(String prefix) {
+
+        super();
+        this.namespaceURI = null;
+        this.prefix = prefix;
+
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * <p>Add the set of Rule instances defined in this RuleSet to the
+     * specified <code>Digester</code> instance, associating them with
+     * our namespace URI (if any).  This method should only be called
+     * by a Digester instance.</p>
+     *
+     * @param digester Digester instance to which the new Rule instances
+     *  should be added.
+     */
+    public void addRuleInstances(Digester digester) {
+
+        digester.addObjectCreate(prefix + "Engine",
+                                 "org.apache.catalina.core.StandardEngine",
+                                 "className");
+        digester.addSetProperties(prefix + "Engine");
+        digester.addRule(prefix + "Engine",
+                         new LifecycleListenerRule
+                         ("org.apache.catalina.startup.EngineConfig",
+                          "engineConfigClass"));
+        digester.addSetNext(prefix + "Engine",
+                            "setContainer",
+                            "org.apache.catalina.Container");
+
+        //Cluster configuration start
+        digester.addObjectCreate(prefix + "Engine/Cluster",
+                                 null, // MUST be specified in the element
+                                 "className");
+        digester.addSetProperties(prefix + "Engine/Cluster");
+        digester.addSetNext(prefix + "Engine/Cluster",
+                            "setCluster",
+                            "org.apache.catalina.Cluster");
+        //Cluster configuration end
+
+        digester.addObjectCreate(prefix + "Engine/Listener",
+                                 null, // MUST be specified in the element
+                                 "className");
+        digester.addSetProperties(prefix + "Engine/Listener");
+        digester.addSetNext(prefix + "Engine/Listener",
+                            "addLifecycleListener",
+                            "org.apache.catalina.LifecycleListener");
+
+        digester.addObjectCreate(prefix + "Engine/Logger",
+                                 null, // MUST be specified in the element
+                                 "className");
+        digester.addSetProperties(prefix + "Engine/Logger");
+        digester.addSetNext(prefix + "Engine/Logger",
+                            "setLogger",
+                            "org.apache.catalina.Logger");
+
+        digester.addObjectCreate(prefix + "Engine/Realm",
+                                 null, // MUST be specified in the element
+                                 "className");
+        digester.addSetProperties(prefix + "Engine/Realm");
+        digester.addSetNext(prefix + "Engine/Realm",
+                            "setRealm",
+                            "org.apache.catalina.Realm");
+
+        digester.addObjectCreate(prefix + "Engine/Valve",
+                                 null, // MUST be specified in the element
+                                 "className");
+        digester.addSetProperties(prefix + "Engine/Valve");
+        digester.addSetNext(prefix + "Engine/Valve",
+                            "addValve",
+                            "org.apache.catalina.Valve");
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/startup/ExpandWar.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/startup/ExpandWar.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/startup/ExpandWar.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,334 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.startup;
+
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.InputStream;
+import java.io.IOException;
+import java.net.JarURLConnection;
+import java.net.URL;
+import java.nio.channels.FileChannel;
+import java.util.Enumeration;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+
+import org.apache.catalina.Host;
+import org.apache.catalina.util.StringManager;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * Expand out a WAR in a Host's appBase.
+ *
+ * @author Craig R. McClanahan
+ * @author Remy Maucherat
+ * @author Glenn L. Nielsen
+ * @version $Revision: 303769 $
+ */
+
+public class ExpandWar {
+
+    private static Log log = LogFactory.getLog(ExpandWar.class);
+
+    /**
+     * The string resources for this package.
+     */
+    protected static final StringManager sm =
+        StringManager.getManager(Constants.Package);
+
+
+    /**
+     * Expand the WAR file found at the specified URL into an unpacked
+     * directory structure, and return the absolute pathname to the expanded
+     * directory.
+     *
+     * @param host Host war is being installed for
+     * @param war URL of the web application archive to be expanded
+     *  (must start with "jar:")
+     *
+     * @exception IllegalArgumentException if this is not a "jar:" URL
+     * @exception IOException if an input/output error was encountered
+     *  during expansion
+     */
+    public static String expand(Host host, URL war)
+        throws IOException {
+
+        // Calculate the directory name of the expanded directory
+        if (host.getLogger().isDebugEnabled()) {
+            host.getLogger().debug("expand(" + war.toString() + ")");
+        }
+        String pathname = war.toString().replace('\\', '/');
+        if (pathname.endsWith("!/")) {
+            pathname = pathname.substring(0, pathname.length() - 2);
+        }
+        int period = pathname.lastIndexOf('.');
+        if (period >= pathname.length() - 4)
+            pathname = pathname.substring(0, period);
+        int slash = pathname.lastIndexOf('/');
+        if (slash >= 0) {
+            pathname = pathname.substring(slash + 1);
+        }
+        if (host.getLogger().isDebugEnabled()) {
+            host.getLogger().debug("  Proposed directory name: " + pathname);
+        }
+        return expand(host, war, pathname);
+
+    }
+
+
+    /**
+     * Expand the WAR file found at the specified URL into an unpacked
+     * directory structure, and return the absolute pathname to the expanded
+     * directory.
+     *
+     * @param host Host war is being installed for
+     * @param war URL of the web application archive to be expanded
+     *  (must start with "jar:")
+     * @param pathname Context path name for web application
+     *
+     * @exception IllegalArgumentException if this is not a "jar:" URL
+     * @exception IOException if an input/output error was encountered
+     *  during expansion
+     */
+    public static String expand(Host host, URL war, String pathname)
+        throws IOException {
+
+        // Make sure that there is no such directory already existing
+        File appBase = new File(host.getAppBase());
+        if (!appBase.isAbsolute()) {
+            appBase = new File(System.getProperty("catalina.base"),
+                               host.getAppBase());
+        }
+        if (!appBase.exists() || !appBase.isDirectory()) {
+            throw new IOException
+                (sm.getString("hostConfig.appBase",
+                              appBase.getAbsolutePath()));
+        }
+        File docBase = new File(appBase, pathname);
+        if (docBase.exists()) {
+            // War file is already installed
+            return (docBase.getAbsolutePath());
+        }
+
+        // Create the new document base directory
+        docBase.mkdir();
+
+        // Expand the WAR into the new document base directory
+        JarURLConnection juc = (JarURLConnection) war.openConnection();
+        juc.setUseCaches(false);
+        JarFile jarFile = null;
+        InputStream input = null;
+        try {
+            jarFile = juc.getJarFile();
+            Enumeration jarEntries = jarFile.entries();
+            while (jarEntries.hasMoreElements()) {
+                JarEntry jarEntry = (JarEntry) jarEntries.nextElement();
+                String name = jarEntry.getName();
+                int last = name.lastIndexOf('/');
+                if (last >= 0) {
+                    File parent = new File(docBase,
+                                           name.substring(0, last));
+                    parent.mkdirs();
+                }
+                if (name.endsWith("/")) {
+                    continue;
+                }
+                input = jarFile.getInputStream(jarEntry);
+
+                // Bugzilla 33636
+                File expandedFile = expand(input, docBase, name);
+                long lastModified = jarEntry.getTime();
+                if ((lastModified != -1) && (lastModified != 0) && (expandedFile != null)) {
+                    expandedFile.setLastModified(lastModified);
+                }
+
+                input.close();
+                input = null;
+            }
+        } catch (IOException e) {
+            // If something went wrong, delete expanded dir to keep things 
+            // clean
+            deleteDir(docBase);
+            throw e;
+        } finally {
+            if (input != null) {
+                try {
+                    input.close();
+                } catch (Throwable t) {
+                    ;
+                }
+                input = null;
+            }
+            if (jarFile != null) {
+                try {
+                    jarFile.close();
+                } catch (Throwable t) {
+                    ;
+                }
+                jarFile = null;
+            }
+        }
+
+        // Return the absolute path to our new document base directory
+        return (docBase.getAbsolutePath());
+
+    }
+
+
+    /**
+     * Copy the specified file or directory to the destination.
+     *
+     * @param src File object representing the source
+     * @param dest File object representing the destination
+     */
+    public static boolean copy(File src, File dest) {
+        
+        boolean result = true;
+        
+        String files[] = null;
+        if (src.isDirectory()) {
+            files = src.list();
+            result = dest.mkdir();
+        } else {
+            files = new String[1];
+            files[0] = "";
+        }
+        if (files == null) {
+            files = new String[0];
+        }
+        for (int i = 0; (i < files.length) && result; i++) {
+            File fileSrc = new File(src, files[i]);
+            File fileDest = new File(dest, files[i]);
+            if (fileSrc.isDirectory()) {
+                result = copy(fileSrc, fileDest);
+            } else {
+                FileChannel ic = null;
+                FileChannel oc = null;
+                try {
+                    ic = (new FileInputStream(fileSrc)).getChannel();
+                    oc = (new FileOutputStream(fileDest)).getChannel();
+                    ic.transferTo(0, ic.size(), oc);
+                } catch (IOException e) {
+                    log.error(sm.getString
+                            ("expandWar.copy", fileSrc, fileDest), e);
+                    result = false;
+                } finally {
+                    if (ic != null) {
+                        try {
+                            ic.close();
+                        } catch (IOException e) {
+                        }
+                    }
+                    if (oc != null) {
+                        try {
+                            oc.close();
+                        } catch (IOException e) {
+                        }
+                    }
+                }
+            }
+        }
+        return result;
+        
+    }
+    
+    
+    /**
+     * Delete the specified directory, including all of its contents and
+     * subdirectories recursively.
+     *
+     * @param dir File object representing the directory to be deleted
+     */
+    public static boolean delete(File dir) {
+        if (dir.isDirectory()) {
+            return deleteDir(dir);
+        } else {
+            return dir.delete();
+        }
+    }
+    
+    
+    /**
+     * Delete the specified directory, including all of its contents and
+     * subdirectories recursively.
+     *
+     * @param dir File object representing the directory to be deleted
+     */
+    public static boolean deleteDir(File dir) {
+
+        String files[] = dir.list();
+        if (files == null) {
+            files = new String[0];
+        }
+        for (int i = 0; i < files.length; i++) {
+            File file = new File(dir, files[i]);
+            if (file.isDirectory()) {
+                deleteDir(file);
+            } else {
+                file.delete();
+            }
+        }
+        return dir.delete();
+
+    }
+
+
+    /**
+     * Expand the specified input stream into the specified directory, creating
+     * a file named from the specified relative path.
+     *
+     * @param input InputStream to be copied
+     * @param docBase Document base directory into which we are expanding
+     * @param name Relative pathname of the file to be created
+     * @return A handle to the expanded File
+     *
+     * @exception IOException if an input/output error occurs
+     */
+    protected static File expand(InputStream input, File docBase, String name)
+        throws IOException {
+
+        File file = new File(docBase, name);
+        BufferedOutputStream output = null;
+        try {
+            output = 
+                new BufferedOutputStream(new FileOutputStream(file));
+            byte buffer[] = new byte[2048];
+            while (true) {
+                int n = input.read(buffer);
+                if (n <= 0)
+                    break;
+                output.write(buffer, 0, n);
+            }
+        } finally {
+            if (output != null) {
+                try {
+                    output.close();
+                } catch (IOException e) {
+                    // Ignore
+                }
+            }
+        }
+
+        return file;
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/startup/HomesUserDatabase.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/startup/HomesUserDatabase.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/startup/HomesUserDatabase.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,143 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.startup;
+
+
+import java.io.File;
+import java.util.Hashtable;
+import java.util.Enumeration;
+
+
+/**
+ * Concrete implementation of the <strong>UserDatabase</code> interface
+ * considers all directories in a directory whose pathname is specified
+ * to our constructor to be "home" directories for those users.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public final class HomesUserDatabase
+    implements UserDatabase {
+
+
+    // --------------------------------------------------------- Constructors
+
+
+    /**
+     * Initialize a new instance of this user database component.
+     */
+    public HomesUserDatabase() {
+
+        super();
+
+    }
+
+
+    // --------------------------------------------------- Instance Variables
+
+
+    /**
+     * The set of home directories for all defined users, keyed by username.
+     */
+    private Hashtable homes = new Hashtable();
+
+
+    /**
+     * The UserConfig listener with which we are associated.
+     */
+    private UserConfig userConfig = null;
+
+
+    // ----------------------------------------------------------- Properties
+
+
+    /**
+     * Return the UserConfig listener with which we are associated.
+     */
+    public UserConfig getUserConfig() {
+
+        return (this.userConfig);
+
+    }
+
+
+    /**
+     * Set the UserConfig listener with which we are associated.
+     *
+     * @param userConfig The new UserConfig listener
+     */
+    public void setUserConfig(UserConfig userConfig) {
+
+        this.userConfig = userConfig;
+        init();
+
+    }
+
+
+    // ------------------------------------------------------- Public Methods
+
+
+    /**
+     * Return an absolute pathname to the home directory for the specified user.
+     *
+     * @param user User for which a home directory should be retrieved
+     */
+    public String getHome(String user) {
+
+        return ((String) homes.get(user));
+
+    }
+
+
+    /**
+     * Return an enumeration of the usernames defined on this server.
+     */
+    public Enumeration getUsers() {
+
+        return (homes.keys());
+
+    }
+
+
+    // ------------------------------------------------------ Private Methods
+
+
+    /**
+     * Initialize our set of users and home directories.
+     */
+    private void init() {
+
+        String homeBase = userConfig.getHomeBase();
+        File homeBaseDir = new File(homeBase);
+        if (!homeBaseDir.exists() || !homeBaseDir.isDirectory())
+            return;
+        String homeBaseFiles[] = homeBaseDir.list();
+
+        for (int i = 0; i < homeBaseFiles.length; i++) {
+            File homeDir = new File(homeBaseDir, homeBaseFiles[i]);
+            if (!homeDir.isDirectory() || !homeDir.canRead())
+                continue;
+            homes.put(homeBaseFiles[i], homeDir.toString());
+        }
+
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/startup/HostConfig.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/startup/HostConfig.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/startup/HostConfig.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,1315 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.startup;
+
+
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+
+import javax.management.ObjectName;
+
+import org.apache.catalina.Container;
+import org.apache.catalina.Context;
+import org.apache.catalina.Engine;
+import org.apache.catalina.Host;
+import org.apache.catalina.Lifecycle;
+import org.apache.catalina.LifecycleEvent;
+import org.apache.catalina.LifecycleListener;
+import org.apache.catalina.core.ContainerBase;
+import org.apache.catalina.core.StandardHost;
+import org.apache.catalina.util.StringManager;
+import org.apache.commons.modeler.Registry;
+import org.apache.tomcat.util.digester.Digester;
+
+
+/**
+ * Startup event listener for a <b>Host</b> that configures the properties
+ * of that Host, and the associated defined contexts.
+ *
+ * @author Craig R. McClanahan
+ * @author Remy Maucherat
+ * @version $Revision: 386336 $ $Date: 2006-03-16 08:13:00 -0600 (Thu, 16 Mar 2006) $
+ */
+public class HostConfig
+    implements LifecycleListener {
+    
+    protected static org.apache.commons.logging.Log log=
+         org.apache.commons.logging.LogFactory.getLog( HostConfig.class );
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * App base.
+     */
+    protected File appBase = null;
+
+
+    /**
+     * Config base.
+     */
+    protected File configBase = null;
+
+
+    /**
+     * The Java class name of the Context configuration class we should use.
+     */
+    protected String configClass = "org.apache.catalina.startup.ContextConfig";
+
+
+    /**
+     * The Java class name of the Context implementation we should use.
+     */
+    protected String contextClass = "org.apache.catalina.core.StandardContext";
+
+
+    /**
+     * The Host we are associated with.
+     */
+    protected Host host = null;
+
+    
+    /**
+     * The JMX ObjectName of this component.
+     */
+    protected ObjectName oname = null;
+    
+
+    /**
+     * The string resources for this package.
+     */
+    protected static final StringManager sm =
+        StringManager.getManager(Constants.Package);
+
+
+    /**
+     * Should we deploy XML Context config files?
+     */
+    protected boolean deployXML = false;
+
+
+    /**
+     * Should we unpack WAR files when auto-deploying applications in the
+     * <code>appBase</code> directory?
+     */
+    protected boolean unpackWARs = false;
+
+
+    /**
+     * Map of deployed applications.
+     */
+    protected HashMap deployed = new HashMap();
+
+    
+    /**
+     * List of applications which are being serviced, and shouldn't be 
+     * deployed/undeployed/redeployed at the moment.
+     */
+    protected ArrayList serviced = new ArrayList();
+    
+
+    /**
+     * Attribute value used to turn on/off XML validation
+     */
+    protected boolean xmlValidation = false;
+
+
+    /**
+     * Attribute value used to turn on/off XML namespace awarenes.
+     */
+    protected boolean xmlNamespaceAware = false;
+
+
+    /**
+     * The <code>Digester</code> instance used to parse context descriptors.
+     */
+    protected static Digester digester = createDigester();
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * Return the Context configuration class name.
+     */
+    public String getConfigClass() {
+
+        return (this.configClass);
+
+    }
+
+
+    /**
+     * Set the Context configuration class name.
+     *
+     * @param configClass The new Context configuration class name.
+     */
+    public void setConfigClass(String configClass) {
+
+        this.configClass = configClass;
+
+    }
+
+
+    /**
+     * Return the Context implementation class name.
+     */
+    public String getContextClass() {
+
+        return (this.contextClass);
+
+    }
+
+
+    /**
+     * Set the Context implementation class name.
+     *
+     * @param contextClass The new Context implementation class name.
+     */
+    public void setContextClass(String contextClass) {
+
+        this.contextClass = contextClass;
+
+    }
+
+
+    /**
+     * Return the deploy XML config file flag for this component.
+     */
+    public boolean isDeployXML() {
+
+        return (this.deployXML);
+
+    }
+
+
+    /**
+     * Set the deploy XML config file flag for this component.
+     *
+     * @param deployXML The new deploy XML flag
+     */
+    public void setDeployXML(boolean deployXML) {
+
+        this.deployXML= deployXML;
+
+    }
+
+
+    /**
+     * Return the unpack WARs flag.
+     */
+    public boolean isUnpackWARs() {
+
+        return (this.unpackWARs);
+
+    }
+
+
+    /**
+     * Set the unpack WARs flag.
+     *
+     * @param unpackWARs The new unpack WARs flag
+     */
+    public void setUnpackWARs(boolean unpackWARs) {
+
+        this.unpackWARs = unpackWARs;
+
+    }
+    
+    
+     /**
+     * Set the validation feature of the XML parser used when
+     * parsing xml instances.
+     * @param xmlValidation true to enable xml instance validation
+     */
+    public void setXmlValidation(boolean xmlValidation){
+        this.xmlValidation = xmlValidation;
+    }
+
+    /**
+     * Get the server.xml <host> attribute's xmlValidation.
+     * @return true if validation is enabled.
+     *
+     */
+    public boolean getXmlValidation(){
+        return xmlValidation;
+    }
+
+    /**
+     * Get the server.xml <host> attribute's xmlNamespaceAware.
+     * @return true if namespace awarenes is enabled.
+     *
+     */
+    public boolean getXmlNamespaceAware(){
+        return xmlNamespaceAware;
+    }
+
+
+    /**
+     * Set the namespace aware feature of the XML parser used when
+     * parsing xml instances.
+     * @param xmlNamespaceAware true to enable namespace awareness
+     */
+    public void setXmlNamespaceAware(boolean xmlNamespaceAware){
+        this.xmlNamespaceAware=xmlNamespaceAware;
+    }    
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Process the START event for an associated Host.
+     *
+     * @param event The lifecycle event that has occurred
+     */
+    public void lifecycleEvent(LifecycleEvent event) {
+
+        if (event.getType().equals(Lifecycle.PERIODIC_EVENT))
+            check();
+
+        // Identify the host we are associated with
+        try {
+            host = (Host) event.getLifecycle();
+            if (host instanceof StandardHost) {
+                setDeployXML(((StandardHost) host).isDeployXML());
+                setUnpackWARs(((StandardHost) host).isUnpackWARs());
+                setXmlNamespaceAware(((StandardHost) host).getXmlNamespaceAware());
+                setXmlValidation(((StandardHost) host).getXmlValidation());
+            }
+        } catch (ClassCastException e) {
+            log.error(sm.getString("hostConfig.cce", event.getLifecycle()), e);
+            return;
+        }
+
+        // Process the event that has occurred
+        if (event.getType().equals(Lifecycle.START_EVENT))
+            start();
+        else if (event.getType().equals(Lifecycle.STOP_EVENT))
+            stop();
+
+    }
+
+    
+    /**
+     * Add a serviced application to the list.
+     */
+    public synchronized void addServiced(String name) {
+        serviced.add(name);
+    }
+    
+    
+    /**
+     * Is application serviced ?
+     * @return state of the application
+     */
+    public synchronized boolean isServiced(String name) {
+        return (serviced.contains(name));
+    }
+    
+
+    /**
+     * Removed a serviced application from the list.
+     */
+    public synchronized void removeServiced(String name) {
+        serviced.remove(name);
+    }
+
+    
+    /**
+     * Get the instant where an application was deployed.
+     * @return 0L if no application with that name is deployed, or the instant
+     * on which the application was deployed
+     */
+    public long getDeploymentTime(String name) {
+    	DeployedApplication app = (DeployedApplication) deployed.get(name);
+    	if (app == null) {
+    		return 0L;
+    	} else {
+    		return app.timestamp;
+    	}
+    }
+    
+    
+    // ------------------------------------------------------ Protected Methods
+
+    
+    /**
+     * Create the digester which will be used to parse context config files.
+     */
+    protected static Digester createDigester() {
+        Digester digester = new Digester();
+        digester.setValidating(false);
+        // 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 
+        // properties are set)
+        digester.addSetProperties("Context");
+        return (digester);
+    }
+    
+
+    /**
+     * Return a File object representing the "application root" directory
+     * for our associated Host.
+     */
+    protected File appBase() {
+
+        if (appBase != null) {
+            return appBase;
+        }
+
+        File file = new File(host.getAppBase());
+        if (!file.isAbsolute())
+            file = new File(System.getProperty("catalina.base"),
+                            host.getAppBase());
+        try {
+            appBase = file.getCanonicalFile();
+        } catch (IOException e) {
+            appBase = file;
+        }
+        return (appBase);
+
+    }
+
+
+    /**
+     * Return a File object representing the "configuration root" directory
+     * for our associated Host.
+     */
+    protected File configBase() {
+
+        if (configBase != null) {
+            return configBase;
+        }
+
+        File file = new File(System.getProperty("catalina.base"), "conf");
+        Container parent = host.getParent();
+        if ((parent != null) && (parent instanceof Engine)) {
+            file = new File(file, parent.getName());
+        }
+        file = new File(file, host.getName());
+        try {
+            configBase = file.getCanonicalFile();
+        } catch (IOException e) {
+            configBase = file;
+        }
+        return (configBase);
+
+    }
+
+    /**
+     * Get the name of the configBase.
+     * For use with JMX management.
+     */
+    public String getConfigBaseName() {
+        return configBase().getAbsolutePath();
+    }
+
+    /**
+     * Given a context path, get the config file name.
+     */
+    protected String getConfigFile(String path) {
+        String basename = null;
+        if (path.equals("")) {
+            basename = "ROOT";
+        } else {
+            basename = path.substring(1).replace('/', '#');
+        }
+        return (basename);
+    }
+
+    
+    /**
+     * Given a context path, get the config file name.
+     */
+    protected String getDocBase(String path) {
+        String basename = null;
+        if (path.equals("")) {
+            basename = "ROOT";
+        } else {
+            basename = path.substring(1);
+        }
+        return (basename);
+    }
+
+    
+    /**
+     * Deploy applications for any directories or WAR files that are found
+     * in our "application root" directory.
+     */
+    protected void deployApps() {
+
+        File appBase = appBase();
+        File configBase = configBase();
+        // Deploy XML descriptors from configBase
+        deployDescriptors(configBase, configBase.list());
+        // Deploy WARs, and loop if additional descriptors are found
+        deployWARs(appBase, appBase.list());
+        // Deploy expanded folders
+        deployDirectories(appBase, appBase.list());
+        
+    }
+
+
+    /**
+     * Deploy applications for any directories or WAR files that are found
+     * in our "application root" directory.
+     */
+    protected void deployApps(String name) {
+
+        File appBase = appBase();
+        File configBase = configBase();
+        String baseName = getConfigFile(name);
+        String docBase = getConfigFile(name);
+        
+        // Deploy XML descriptors from configBase
+        File xml = new File(configBase, baseName + ".xml");
+        if (xml.exists())
+            deployDescriptor(name, xml, baseName + ".xml");
+        // Deploy WARs, and loop if additional descriptors are found
+        File war = new File(appBase, docBase + ".war");
+        if (war.exists())
+            deployWAR(name, war, docBase + ".war");
+        // Deploy expanded folders
+        File dir = new File(appBase, docBase);
+        if (dir.exists())
+            deployDirectory(name, dir, docBase);
+        
+    }
+
+
+    /**
+     * Deploy XML context descriptors.
+     */
+    protected void deployDescriptors(File configBase, String[] files) {
+
+        if (files == null)
+            return;
+        
+        for (int i = 0; i < files.length; i++) {
+
+            if (files[i].equalsIgnoreCase("META-INF"))
+                continue;
+            if (files[i].equalsIgnoreCase("WEB-INF"))
+                continue;
+            File contextXml = new File(configBase, files[i]);
+            if (files[i].toLowerCase().endsWith(".xml")) {
+
+                // Calculate the context path and make sure it is unique
+                String nameTmp = files[i].substring(0, files[i].length() - 4);
+                String contextPath = "/" + nameTmp.replace('#', '/');
+                if (nameTmp.equals("ROOT")) {
+                    contextPath = "";
+                }
+
+                if (isServiced(contextPath))
+                    continue;
+                
+                String file = files[i];
+
+                deployDescriptor(contextPath, contextXml, file);
+                
+            }
+
+        }
+
+    }
+
+
+    /**
+     * @param contextPath
+     * @param contextXml
+     * @param file
+     */
+    protected void deployDescriptor(String contextPath, File contextXml, String file) {
+        if (deploymentExists(contextPath)) {
+            return;
+        }
+        
+        DeployedApplication deployedApp = new DeployedApplication(contextPath);
+
+        // Assume this is a configuration descriptor and deploy it
+        if(log.isDebugEnabled()) {
+            log.debug(sm.getString("hostConfig.deployDescriptor", file));
+        }
+
+        Context context = null;
+        try {
+            synchronized (digester) {
+                try {
+                    context = (Context) digester.parse(contextXml);
+                    if (context == null) {
+                        log.error(sm.getString("hostConfig.deployDescriptor.error",
+                                file));
+                        return;
+                    }
+                } finally {
+                    digester.reset();
+                }
+            }
+            if (context instanceof Lifecycle) {
+                Class clazz = Class.forName(host.getConfigClass());
+                LifecycleListener listener =
+                    (LifecycleListener) clazz.newInstance();
+                ((Lifecycle) context).addLifecycleListener(listener);
+            }
+            context.setConfigFile(contextXml.getAbsolutePath());
+            context.setPath(contextPath);
+            // Add the associated docBase to the redeployed list if it's a WAR
+            boolean isWar = false;
+            boolean isExternal = false;
+            if (context.getDocBase() != null) {
+                File docBase = new File(context.getDocBase());
+                if (!docBase.isAbsolute()) {
+                    docBase = new File(appBase(), context.getDocBase());
+                }
+                // If external docBase, register .xml as redeploy first
+                if (!docBase.getCanonicalPath().startsWith(appBase().getAbsolutePath())) {
+                    isExternal = true;
+                    deployedApp.redeployResources.put
+                        (contextXml.getAbsolutePath(), new Long(contextXml.lastModified()));
+                    deployedApp.redeployResources.put(docBase.getAbsolutePath(),
+                        new Long(docBase.lastModified()));
+                    if (docBase.getAbsolutePath().toLowerCase().endsWith(".war")) {
+                        isWar = true;
+                    }
+                } else {
+                    log.warn(sm.getString("hostConfig.deployDescriptor.localDocBaseSpecified",
+                             docBase));
+                    // Ignore specified docBase
+                    context.setDocBase(null);
+                }
+            }
+            host.addChild(context);
+            // Get paths for WAR and expanded WAR in appBase
+            String name = null;
+            String path = context.getPath();
+            if (path.equals("")) {
+                name = "ROOT";
+            } else {
+                if (path.startsWith("/")) {
+                    name = path.substring(1);
+                } else {
+                    name = path;
+                }
+            }
+            File expandedDocBase = new File(name);
+            File warDocBase = new File(name + ".war");
+            if (!expandedDocBase.isAbsolute()) {
+                expandedDocBase = new File(appBase(), name);
+                warDocBase = new File(appBase(), name + ".war");
+            }
+            // Add the eventual unpacked WAR and all the resources which will be
+            // watched inside it
+            if (isWar && unpackWARs) {
+                deployedApp.redeployResources.put(expandedDocBase.getAbsolutePath(),
+                        new Long(expandedDocBase.lastModified()));
+                deployedApp.redeployResources.put
+                    (contextXml.getAbsolutePath(), new Long(contextXml.lastModified()));
+                addWatchedResources(deployedApp, expandedDocBase.getAbsolutePath(), context);
+            } else {
+                // Find an existing matching war and expanded folder
+                if (warDocBase.exists()) {
+                    deployedApp.redeployResources.put(warDocBase.getAbsolutePath(),
+                            new Long(warDocBase.lastModified()));
+                }
+                if (expandedDocBase.exists()) {
+                    deployedApp.redeployResources.put(expandedDocBase.getAbsolutePath(),
+                            new Long(expandedDocBase.lastModified()));
+                    addWatchedResources(deployedApp, 
+                            expandedDocBase.getAbsolutePath(), context);
+                } else {
+                    addWatchedResources(deployedApp, null, context);
+                }
+                // Add the context XML to the list of files which should trigger a redeployment
+                if (!isExternal) {
+                    deployedApp.redeployResources.put
+                        (contextXml.getAbsolutePath(), new Long(contextXml.lastModified()));
+                }
+            }
+        } catch (Throwable t) {
+            log.error(sm.getString("hostConfig.deployDescriptor.error",
+                                   file), t);
+        }
+
+        if (context != null && host.findChild(context.getName()) != null) {
+            deployed.put(contextPath, deployedApp);
+        }
+    }
+
+
+    /**
+     * Deploy WAR files.
+     */
+    protected void deployWARs(File appBase, String[] files) {
+        
+        if (files == null)
+            return;
+        
+        boolean checkAdditionalDeployments = false;
+        
+        for (int i = 0; i < files.length; i++) {
+            
+            if (files[i].equalsIgnoreCase("META-INF"))
+                continue;
+            if (files[i].equalsIgnoreCase("WEB-INF"))
+                continue;
+            File dir = new File(appBase, files[i]);
+            if (files[i].toLowerCase().endsWith(".war")) {
+                
+                // Calculate the context path and make sure it is unique
+                String contextPath = "/" + files[i];
+                int period = contextPath.lastIndexOf(".");
+                if (period >= 0)
+                    contextPath = contextPath.substring(0, period);
+                if (contextPath.equals("/ROOT"))
+                    contextPath = "";
+                
+                if (isServiced(contextPath))
+                    continue;
+                
+                String file = files[i];
+                
+                deployWAR(contextPath, dir, file);
+                
+            }
+            
+        }
+        
+    }
+
+
+    /**
+     * @param contextPath
+     * @param dir
+     * @param file
+     */
+    protected void deployWAR(String contextPath, File dir, String file) {
+        
+        if (deploymentExists(contextPath))
+            return;
+        
+        // Checking for a nested /META-INF/context.xml
+        JarFile jar = null;
+        JarEntry entry = null;
+        InputStream istream = null;
+        BufferedOutputStream ostream = null;
+        File xml = new File
+            (configBase, file.substring(0, file.lastIndexOf(".")) + ".xml");
+        if (deployXML && !xml.exists()) {
+            try {
+                jar = new JarFile(dir);
+                entry = jar.getJarEntry(Constants.ApplicationContextXml);
+                if (entry != null) {
+                    istream = jar.getInputStream(entry);
+                    
+                    configBase.mkdirs();
+                    
+                    ostream =
+                        new BufferedOutputStream
+                        (new FileOutputStream(xml), 1024);
+                    byte buffer[] = new byte[1024];
+                    while (true) {
+                        int n = istream.read(buffer);
+                        if (n < 0) {
+                            break;
+                        }
+                        ostream.write(buffer, 0, n);
+                    }
+                    ostream.flush();
+                    ostream.close();
+                    ostream = null;
+                    istream.close();
+                    istream = null;
+                    entry = null;
+                    jar.close();
+                    jar = null;
+                }
+            } catch (Exception e) {
+                // Ignore and continue
+                if (ostream != null) {
+                    try {
+                        ostream.close();
+                    } catch (Throwable t) {
+                        ;
+                    }
+                    ostream = null;
+                }
+                if (istream != null) {
+                    try {
+                        istream.close();
+                    } catch (Throwable t) {
+                        ;
+                    }
+                    istream = null;
+                }
+            } finally {
+                entry = null;
+                if (jar != null) {
+                    try {
+                        jar.close();
+                    } catch (Throwable t) {
+                        ;
+                    }
+                    jar = null;
+                }
+            }
+        }
+        
+        DeployedApplication deployedApp = new DeployedApplication(contextPath);
+        
+        // Deploy the application in this WAR file
+        if(log.isInfoEnabled()) 
+            log.info(sm.getString("hostConfig.deployJar", file));
+
+        // Populate redeploy resources with the WAR file
+        deployedApp.redeployResources.put
+            (dir.getAbsolutePath(), new Long(dir.lastModified()));
+
+        try {
+            Context context = (Context) Class.forName(contextClass).newInstance();
+            if (context instanceof Lifecycle) {
+                Class clazz = Class.forName(host.getConfigClass());
+                LifecycleListener listener =
+                    (LifecycleListener) clazz.newInstance();
+                ((Lifecycle) context).addLifecycleListener(listener);
+            }
+            context.setPath(contextPath);
+            context.setDocBase(file);
+            if (xml.exists()) {
+                context.setConfigFile(xml.getAbsolutePath());
+                deployedApp.redeployResources.put
+                    (xml.getAbsolutePath(), new Long(xml.lastModified()));
+            }
+            host.addChild(context);
+            // If we're unpacking WARs, the docBase will be mutated after
+            // starting the context
+            if (unpackWARs && (context.getDocBase() != null)) {
+                String name = null;
+                String path = context.getPath();
+                if (path.equals("")) {
+                    name = "ROOT";
+                } else {
+                    if (path.startsWith("/")) {
+                        name = path.substring(1);
+                    } else {
+                        name = path;
+                    }
+                }
+                File docBase = new File(name);
+                if (!docBase.isAbsolute()) {
+                    docBase = new File(appBase(), name);
+                }
+                deployedApp.redeployResources.put(docBase.getAbsolutePath(),
+                        new Long(docBase.lastModified()));
+                addWatchedResources(deployedApp, docBase.getAbsolutePath(), context);
+            } else {
+                addWatchedResources(deployedApp, null, context);
+            }
+        } catch (Throwable t) {
+            log.error(sm.getString("hostConfig.deployJar.error", file), t);
+        }
+        
+        deployed.put(contextPath, deployedApp);
+    }
+
+
+    /**
+     * Deploy directories.
+     */
+    protected void deployDirectories(File appBase, String[] files) {
+
+        if (files == null)
+            return;
+        
+        for (int i = 0; i < files.length; i++) {
+
+            if (files[i].equalsIgnoreCase("META-INF"))
+                continue;
+            if (files[i].equalsIgnoreCase("WEB-INF"))
+                continue;
+            File dir = new File(appBase, files[i]);
+            if (dir.isDirectory()) {
+
+                // Calculate the context path and make sure it is unique
+                String contextPath = "/" + files[i];
+                if (files[i].equals("ROOT"))
+                    contextPath = "";
+
+                if (isServiced(contextPath))
+                    continue;
+
+                deployDirectory(contextPath, dir, files[i]);
+            
+            }
+
+        }
+
+    }
+
+    
+    /**
+     * @param contextPath
+     * @param dir
+     * @param file
+     */
+    protected void deployDirectory(String contextPath, File dir, String file) {
+        DeployedApplication deployedApp = new DeployedApplication(contextPath);
+        
+        if (deploymentExists(contextPath))
+            return;
+
+        // Deploy the application in this directory
+        if( log.isDebugEnabled() ) 
+            log.debug(sm.getString("hostConfig.deployDir", file));
+        try {
+            Context context = (Context) Class.forName(contextClass).newInstance();
+            if (context instanceof Lifecycle) {
+                Class clazz = Class.forName(host.getConfigClass());
+                LifecycleListener listener =
+                    (LifecycleListener) clazz.newInstance();
+                ((Lifecycle) context).addLifecycleListener(listener);
+            }
+            context.setPath(contextPath);
+            context.setDocBase(file);
+            File configFile = new File(dir, Constants.ApplicationContextXml);
+            if (deployXML) {
+                context.setConfigFile(configFile.getAbsolutePath());
+            }
+            host.addChild(context);
+            deployedApp.redeployResources.put(dir.getAbsolutePath(),
+                    new Long(dir.lastModified()));
+            if (deployXML) {
+                deployedApp.redeployResources.put(configFile.getAbsolutePath(),
+                        new Long(configFile.lastModified()));
+            }
+            addWatchedResources(deployedApp, dir.getAbsolutePath(), context);
+        } catch (Throwable t) {
+            log.error(sm.getString("hostConfig.deployDir.error", file), t);
+        }
+
+        deployed.put(contextPath, deployedApp);
+    }
+
+    
+    /**
+     * Check if a webapp is already deployed in this host.
+     * 
+     * @param contextPath of the context which will be checked
+     */
+    protected boolean deploymentExists(String contextPath) {
+        return (deployed.containsKey(contextPath) || (host.findChild(contextPath) != null));
+    }
+    
+
+    /**
+     * Add watched resources to the specified Context.
+     * @param app HostConfig deployed app
+     * @param docBase web app docBase
+     * @param context web application context
+     */
+    protected void addWatchedResources(DeployedApplication app, String docBase, Context context) {
+        // FIXME: Feature idea. Add support for patterns (ex: WEB-INF/*, WEB-INF/*.xml), where
+        //        we would only check if at least one resource is newer than app.timestamp
+        File docBaseFile = null;
+        if (docBase != null) {
+            docBaseFile = new File(docBase);
+            if (!docBaseFile.isAbsolute()) {
+                docBaseFile = new File(appBase(), docBase);
+            }
+        }
+        String[] watchedResources = context.findWatchedResources();
+        for (int i = 0; i < watchedResources.length; i++) {
+            File resource = new File(watchedResources[i]);
+            if (!resource.isAbsolute()) {
+                if (docBase != null) {
+                    resource = new File(docBaseFile, watchedResources[i]);
+                } else {
+                    continue;
+                }
+            }
+            app.reloadResources.put(resource.getAbsolutePath(), 
+                    new Long(resource.lastModified()));
+        }
+    }
+    
+
+    /**
+     * Check resources for redeployment and reloading.
+     */
+    protected synchronized void checkResources(DeployedApplication app) {
+        String[] resources = (String[]) app.redeployResources.keySet().toArray(new String[0]);
+        for (int i = 0; i < resources.length; i++) {
+            File resource = new File(resources[i]);
+            if (log.isDebugEnabled())
+                log.debug("Checking context[" + app.name + "] redeploy resource " + resource);
+            if (resource.exists()) {
+                long lastModified = ((Long) app.redeployResources.get(resources[i])).longValue();
+                if ((!resource.isDirectory()) && resource.lastModified() > lastModified) {
+                    // Undeploy application
+                    if (log.isInfoEnabled())
+                        log.info(sm.getString("hostConfig.undeploy", app.name));
+                    ContainerBase context = (ContainerBase) host.findChild(app.name);
+                    try {
+                        host.removeChild(context);
+                    } catch (Throwable t) {
+                        log.warn(sm.getString
+                                 ("hostConfig.context.remove", app.name), t);
+                    }
+                    try {
+                        context.destroy();
+                    } catch (Throwable t) {
+                        log.warn(sm.getString
+                                 ("hostConfig.context.destroy", 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();
+                            if ((current.getAbsolutePath().startsWith(appBase().getAbsolutePath()))
+                                    || (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);
+                    return;
+                }
+            } else {
+                long lastModified = ((Long) app.redeployResources.get(resources[i])).longValue();
+                if (lastModified == 0L) {
+                    continue;
+                }
+                // Undeploy application
+                if (log.isInfoEnabled())
+                    log.info(sm.getString("hostConfig.undeploy", app.name));
+                ContainerBase context = (ContainerBase) host.findChild(app.name);
+                try {
+                    host.removeChild(context);
+                } catch (Throwable t) {
+                    log.warn(sm.getString
+                             ("hostConfig.context.remove", app.name), t);
+                }
+                try {
+                    context.destroy();
+                } catch (Throwable t) {
+                    log.warn(sm.getString
+                             ("hostConfig.context.destroy", 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();
+                        if ((current.getAbsolutePath().startsWith(appBase().getAbsolutePath()))
+                            || (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 = (String[]) 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();
+                        if ((current.getAbsolutePath().startsWith(appBase().getAbsolutePath()))
+                            || ((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);
+                return;
+            }
+        }
+        resources = (String[]) app.reloadResources.keySet().toArray(new String[0]);
+        for (int i = 0; i < resources.length; i++) {
+            File resource = new File(resources[i]);
+            if (log.isDebugEnabled())
+                log.debug("Checking context[" + app.name + "] reload resource " + resource);
+            long lastModified = ((Long) app.reloadResources.get(resources[i])).longValue();
+            if ((!resource.exists() && lastModified != 0L) 
+                || (resource.lastModified() != lastModified)) {
+                // Reload application
+                if(log.isInfoEnabled())
+                    log.info(sm.getString("hostConfig.reload", app.name));
+                Container context = host.findChild(app.name);
+                try {
+                    ((Lifecycle) context).stop();
+                } catch (Exception e) {
+                    log.warn(sm.getString
+                             ("hostConfig.context.restart", app.name), e);
+                }
+                // If the context was not started (for example an error 
+                // in web.xml) we'll still get to try to start
+                try {
+                    ((Lifecycle) context).start();
+                } catch (Exception e) {
+                    log.warn(sm.getString
+                             ("hostConfig.context.restart", app.name), e);
+                }
+                // Update times
+                app.reloadResources.put(resources[i], new Long(resource.lastModified()));
+                app.timestamp = System.currentTimeMillis();
+                return;
+            }
+        }
+    }
+    
+    
+    /**
+     * Process a "start" event for this Host.
+     */
+    public void start() {
+
+        if (log.isDebugEnabled())
+            log.debug(sm.getString("hostConfig.start"));
+
+        try {
+            ObjectName hostON = new ObjectName(host.getObjectName());
+            oname = new ObjectName
+                (hostON.getDomain() + ":type=Deployer,host=" + host.getName());
+            Registry.getRegistry(null, null).registerComponent
+                (this, oname, this.getClass().getName());
+        } catch (Exception e) {
+            log.error(sm.getString("hostConfig.jmx.register", oname), e);
+        }
+
+        if (host.getDeployOnStartup())
+            deployApps();
+        
+    }
+
+
+    /**
+     * Process a "stop" event for this Host.
+     */
+    public void stop() {
+
+        if (log.isDebugEnabled())
+            log.debug(sm.getString("hostConfig.stop"));
+
+        undeployApps();
+
+        if (oname != null) {
+            try {
+                Registry.getRegistry(null, null).unregisterComponent(oname);
+            } catch (Exception e) {
+                log.error(sm.getString("hostConfig.jmx.unregister", oname), e);
+            }
+        }
+        oname = null;
+        appBase = null;
+        configBase = null;
+
+    }
+
+
+    /**
+     * Undeploy all deployed applications.
+     */
+    protected void undeployApps() {
+
+        if (log.isDebugEnabled())
+            log.debug(sm.getString("hostConfig.undeploying"));
+
+        // Soft undeploy all contexts we have deployed
+        DeployedApplication[] apps = 
+            (DeployedApplication[]) deployed.values().toArray(new DeployedApplication[0]);
+        for (int i = 0; i < apps.length; i++) {
+            try {
+                host.removeChild(host.findChild(apps[i].name));
+            } catch (Throwable t) {
+                log.warn(sm.getString
+                        ("hostConfig.context.remove", apps[i].name), t);
+            }
+        }
+        
+        deployed.clear();
+
+    }
+
+
+    /**
+     * Check status of all webapps.
+     */
+    protected void check() {
+
+        if (host.getAutoDeploy()) {
+            // Check for resources modification to trigger redeployment
+            DeployedApplication[] apps = 
+                (DeployedApplication[]) deployed.values().toArray(new DeployedApplication[0]);
+            for (int i = 0; i < apps.length; i++) {
+                if (!isServiced(apps[i].name))
+                    checkResources(apps[i]);
+            }
+            // Hotdeploy applications
+            deployApps();
+        }
+
+    }
+
+    
+    /**
+     * Check status of a specific webapp, for use with stuff like management webapps.
+     */
+    public void check(String name) {
+        DeployedApplication app = (DeployedApplication) deployed.get(name);
+        if (app != null) {
+            checkResources(app);
+        } else {
+            deployApps(name);
+        }
+    }
+
+    /**
+     * Add a new Context to be managed by us.
+     * Entry point for the admin webapp, and other JMX Context controlers.
+     */
+    public void manageApp(Context context)  {    
+
+        String contextPath = context.getPath();
+        
+        if (deployed.containsKey(contextPath))
+            return;
+
+        DeployedApplication deployedApp = new DeployedApplication(contextPath);
+        
+        // Add the associated docBase to the redeployed list if it's a WAR
+        boolean isWar = false;
+        if (context.getDocBase() != null) {
+            File docBase = new File(context.getDocBase());
+            if (!docBase.isAbsolute()) {
+                docBase = new File(appBase(), context.getDocBase());
+            }
+            deployedApp.redeployResources.put(docBase.getAbsolutePath(),
+                                          new Long(docBase.lastModified()));
+            if (docBase.getAbsolutePath().toLowerCase().endsWith(".war")) {
+                isWar = true;
+            }
+        }
+        host.addChild(context);
+        // Add the eventual unpacked WAR and all the resources which will be
+        // watched inside it
+        if (isWar && unpackWARs) {
+            String name = null;
+            String path = context.getPath();
+            if (path.equals("")) {
+                name = "ROOT";
+            } else {
+                if (path.startsWith("/")) {
+                    name = path.substring(1);
+                } else {
+                    name = path;
+                }
+            }
+            File docBase = new File(name);
+            if (!docBase.isAbsolute()) {
+                docBase = new File(appBase(), name);
+            }
+            deployedApp.redeployResources.put(docBase.getAbsolutePath(),
+                        new Long(docBase.lastModified()));
+            addWatchedResources(deployedApp, docBase.getAbsolutePath(), context);
+        } else {
+            addWatchedResources(deployedApp, null, context);
+        }
+        deployed.put(contextPath, deployedApp);
+    }
+
+    /**
+     * Remove a webapp from our control.
+     * Entry point for the admin webapp, and other JMX Context controlers.
+     */
+    public void unmanageApp(String contextPath) {
+        if(isServiced(contextPath)) {
+            deployed.remove(contextPath);
+            host.removeChild(host.findChild(contextPath));
+        }
+    }
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * This class represents the state of a deployed application, as well as 
+     * the monitored resources.
+     */
+    protected class DeployedApplication {
+    	public DeployedApplication(String name) {
+    		this.name = name;
+    	}
+    	
+    	/**
+    	 * Application context path. The assertion is that 
+    	 * (host.getChild(name) != null).
+    	 */
+    	public String name;
+    	
+    	/**
+    	 * 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.
+         * The value is the last modification time.
+    	 */
+    	public LinkedHashMap redeployResources = new LinkedHashMap();
+
+    	/**
+    	 * 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.
+         * The value is the last modification time.
+    	 */
+    	public HashMap reloadResources = new HashMap();
+
+    	/**
+    	 * Instant where the application was last put in service.
+    	 */
+    	public long timestamp = System.currentTimeMillis();
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/startup/HostRuleSet.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/startup/HostRuleSet.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/startup/HostRuleSet.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,145 @@
+/*
+ * Copyright 1999-2001,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.startup;
+
+
+import org.apache.tomcat.util.digester.Digester;
+import org.apache.tomcat.util.digester.RuleSetBase;
+
+
+/**
+ * <p><strong>RuleSet</strong> for processing the contents of a
+ * Host definition element.  This <code>RuleSet</code> does NOT include
+ * any rules for nested Context or DefaultContext elements, which should
+ * be added via instances of <code>ContextRuleSet</code>.</p>
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302984 $ $Date: 2004-06-26 12:41:33 -0500 (Sat, 26 Jun 2004) $
+ */
+
+public class HostRuleSet extends RuleSetBase {
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The matching pattern prefix to use for recognizing our elements.
+     */
+    protected String prefix = null;
+
+
+    // ------------------------------------------------------------ Constructor
+
+
+    /**
+     * Construct an instance of this <code>RuleSet</code> with the default
+     * matching pattern prefix.
+     */
+    public HostRuleSet() {
+
+        this("");
+
+    }
+
+
+    /**
+     * Construct an instance of this <code>RuleSet</code> with the specified
+     * matching pattern prefix.
+     *
+     * @param prefix Prefix for matching pattern rules (including the
+     *  trailing slash character)
+     */
+    public HostRuleSet(String prefix) {
+
+        super();
+        this.namespaceURI = null;
+        this.prefix = prefix;
+
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * <p>Add the set of Rule instances defined in this RuleSet to the
+     * specified <code>Digester</code> instance, associating them with
+     * our namespace URI (if any).  This method should only be called
+     * by a Digester instance.</p>
+     *
+     * @param digester Digester instance to which the new Rule instances
+     *  should be added.
+     */
+    public void addRuleInstances(Digester digester) {
+
+        digester.addObjectCreate(prefix + "Host",
+                                 "org.apache.catalina.core.StandardHost",
+                                 "className");
+        digester.addSetProperties(prefix + "Host");
+        digester.addRule(prefix + "Host",
+                         new CopyParentClassLoaderRule());
+        digester.addRule(prefix + "Host",
+                         new LifecycleListenerRule
+                         ("org.apache.catalina.startup.HostConfig",
+                          "hostConfigClass"));
+        digester.addSetNext(prefix + "Host",
+                            "addChild",
+                            "org.apache.catalina.Container");
+
+        digester.addCallMethod(prefix + "Host/Alias",
+                               "addAlias", 0);
+
+        //Cluster configuration start
+        digester.addObjectCreate(prefix + "Host/Cluster",
+                                 null, // MUST be specified in the element
+                                 "className");
+        digester.addSetProperties(prefix + "Host/Cluster");
+        digester.addSetNext(prefix + "Host/Cluster",
+                            "setCluster",
+                            "org.apache.catalina.Cluster");
+        //Cluster configuration end
+
+        digester.addObjectCreate(prefix + "Host/Listener",
+                                 null, // MUST be specified in the element
+                                 "className");
+        digester.addSetProperties(prefix + "Host/Listener");
+        digester.addSetNext(prefix + "Host/Listener",
+                            "addLifecycleListener",
+                            "org.apache.catalina.LifecycleListener");
+
+        digester.addObjectCreate(prefix + "Host/Realm",
+                                 null, // MUST be specified in the element
+                                 "className");
+        digester.addSetProperties(prefix + "Host/Realm");
+        digester.addSetNext(prefix + "Host/Realm",
+                            "setRealm",
+                            "org.apache.catalina.Realm");
+
+        digester.addObjectCreate(prefix + "Host/Valve",
+                                 null, // MUST be specified in the element
+                                 "className");
+        digester.addSetProperties(prefix + "Host/Valve");
+        digester.addSetNext(prefix + "Host/Valve",
+                            "addValve",
+                            "org.apache.catalina.Valve");
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/startup/LifecycleListenerRule.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/startup/LifecycleListenerRule.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/startup/LifecycleListenerRule.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,102 @@
+/*
+ * Copyright 1999-2001,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.startup;
+
+
+import org.apache.catalina.Lifecycle;
+import org.apache.catalina.LifecycleListener;
+import org.apache.tomcat.util.digester.Rule;
+import org.xml.sax.Attributes;
+
+
+/**
+ * <p>Rule that creates a new <code>LifecycleListener</code> instance,
+ * and associates it with the top object on the stack (which must
+ * implement <code>LifecycleListener</code>).</p>
+ */
+
+public class LifecycleListenerRule extends Rule {
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Construct a new instance of this Rule.
+     *
+     * @param listenerClass Default name of the LifecycleListener
+     *  implementation class to be created
+     * @param attributeName Name of the attribute that optionally
+     *  includes an override name of the LifecycleListener class
+     */
+    public LifecycleListenerRule(String listenerClass, String attributeName) {
+
+        this.listenerClass = listenerClass;
+        this.attributeName = attributeName;
+
+    }
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The attribute name of an attribute that can override the
+     * implementation class name.
+     */
+    private String attributeName;
+
+
+    /**
+     * The name of the <code>LifecycleListener</code> implementation class.
+     */
+    private String listenerClass;
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Handle the beginning of an XML element.
+     *
+     * @param attributes The attributes of this element
+     *
+     * @exception Exception if a processing error occurs
+     */
+    public void begin(String namespace, String name, Attributes attributes)
+        throws Exception {
+
+        // Instantiate a new LifecyleListener implementation object
+        String className = listenerClass;
+        if (attributeName != null) {
+            String value = attributes.getValue(attributeName);
+            if (value != null)
+                className = value;
+        }
+        Class clazz = Class.forName(className);
+        LifecycleListener listener =
+            (LifecycleListener) clazz.newInstance();
+
+        // Add this LifecycleListener to our associated component
+        Lifecycle lifecycle = (Lifecycle) digester.peek();
+        lifecycle.addLifecycleListener(listener);
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/startup/LocalStrings.properties
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/startup/LocalStrings.properties	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/startup/LocalStrings.properties	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,77 @@
+contextConfig.applicationClose=Error closing application web.xml
+contextConfig.applicationConfig=Configuration error in application web.xml
+contextConfig.applicationListener=Exception creating listener of class {0}
+contextConfig.applicationMissing=Missing application web.xml, using defaults only
+contextConfig.applicationParse=Parse error in application web.xml file at {0}
+contextConfig.applicationPosition=Occurred at line {0} column {1}
+contextConfig.authenticatorConfigured=Configured an authenticator for method {0}
+contextConfig.authenticatorInstantiate=Cannot instantiate an authenticator of class {0}
+contextConfig.authenticatorMissing=Cannot configure an authenticator for method {0}
+contextConfig.authenticatorResources=Cannot load authenticators mapping list
+contextConfig.cce=Lifecycle event data object {0} is not a Context
+contextConfig.certificatesConfig.added=Added certificates -> request attribute Valve
+contextConfig.certificatesConfig.error=Exception adding CertificatesValve:
+contextConfig.defaultClose=Error closing default web.xml
+contextConfig.defaultConfig=Configuration error in default web.xml
+contextConfig.defaultMissing=Missing default web.xml, using application web.xml only
+contextConfig.defaultParse=Parse error in default web.xml
+contextConfig.defaultPosition=Occurred at line {0} column {1}
+contextConfig.fixDocBase=Exception fixing docBase: {0} 
+contextConfig.init=ContextConfig: Initializing
+contextConfig.missingRealm=No Realm has been configured to authenticate against
+contextConfig.role.auth=WARNING: Security role name {0} used in an <auth-constraint> without being defined in a <security-role>
+contextConfig.role.link=WARNING: Security role name {0} used in a <role-link> without being defined in a <security-role>
+contextConfig.role.runas=WARNING: Security role name {0} used in a <run-as> without being defined in a <security-role>
+contextConfig.start=ContextConfig: Processing START
+contextConfig.stop=ContextConfig: Processing STOP
+contextConfig.tldEntryException=Exception processing TLD {0} in JAR at resource path {1} in context {2}
+contextConfig.tldFileException=Exception processing TLD at resource path {0} in context {1}
+contextConfig.tldJarException=Exception processing JAR at resource path {0} in context {1}
+contextConfig.tldResourcePath=Invalid TLD resource path {0}
+contextConfig.unavailable=Marking this application unavailable due to previous error(s)
+contextConfig.altDDNotFound=alt-dd file {0} not found
+embedded.alreadyStarted=Embedded service has already been started
+embedded.noEngines=No engines have been defined yet
+embedded.notmp=Cannot find specified temporary folder at {0}
+embedded.notStarted=Embedded service has not yet been started
+embedded.authenticatorNotInstanceOfValve=Specified Authenticator is not a Valve
+engineConfig.cce=Lifecycle event data object {0} is not an Engine
+engineConfig.start=EngineConfig: Processing START
+engineConfig.stop=EngineConfig: Processing STOP
+expandWar.copy=Error copying {0} to {1}
+hostConfig.appBase=Application base directory {0} does not exist
+hostConfig.canonicalizing=Error delete redeploy resources from context [{0}]
+hostConfig.cce=Lifecycle event data object {0} is not a Host
+hostConfig.context.destroy=Error during context [{0}] destroy
+hostConfig.context.remove=Error while removing context [{0}]
+hostConfig.context.restart=Error during context [{0}] restart
+hostConfig.deploy=Deploying web application directory {0}
+hostConfig.deployDescriptor=Deploying configuration descriptor {0}
+hostConfig.deployDescriptor.error=Error deploying configuration descriptor {0}
+hostConfig.deployDescriptor.localDocBaseSpecified=A docBase {0} inside the host appBase has been specified, and will be ignored
+hostConfig.deployDir=Deploying web application directory {0}
+hostConfig.deployDir.error=Error deploying web application directory {0}
+hostConfig.deployJar=Deploying web application archive {0}
+hostConfig.deployJar.error=Error deploying web application archive {0}
+hostConfig.deploy.error=Exception while deploying web application directory {0}
+hostConfig.deploying=Deploying discovered web applications
+hostConfig.expand=Expanding web application archive {0}
+hostConfig.expand.error=Exception while expanding web application archive {0}
+hostConfig.expanding=Expanding discovered web application archives
+hostConfig.jmx.register=Register context [{0}] failed
+hostConfig.jmx.unregister=Unregister context [{0}] failed
+hostConfig.reload=Reloading context [{0}]
+hostConfig.removeXML=Context [{0}] is undeployed
+hostConfig.removeDIR=Directory {0} is undeployed
+hostConfig.removeWAR=War {0} is undeployed
+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.undeploying=Undeploying deployed web applications
+userConfig.database=Exception loading user database
+userConfig.deploy=Deploying web application for user {0}
+userConfig.deploying=Deploying user web applications
+userConfig.error=Error deploying web application for user {0}
+userConfig.start=UserConfig: Processing START
+userConfig.stop=UserConfig: Processing STOP

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/startup/LocalStrings_es.properties
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/startup/LocalStrings_es.properties	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/startup/LocalStrings_es.properties	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,61 @@
+contextConfig.applicationClose=Error durante el cierre del archivo web.xml de la aplicación
+contextConfig.applicationConfig=Errror de configuración en el archivo web.xml de la aplicación
+contextConfig.applicationListener=Excepción durante la creación de la clase de escucha (listener) {0}
+contextConfig.applicationMissing=Falta el archivo web.xml de la aplicaciónb. Utilizando los parámetros por defecto
+contextConfig.applicationParse=Error de evaluación (parse) en el archivo web.xml de la aplicación
+contextConfig.applicationPosition=Se ha producido en la línea {0} columna {1}
+contextConfig.authenticatorConfigured=Configuración de un autentificador (authenticator) para el método {0}
+contextConfig.authenticatorInstantiate=Imposible de instanciar un autenticador (authenticator) para la clase {0}
+contextConfig.authenticatorMissing=Imposible de configurar un autentificador (authenticator) para el método {0}
+contextConfig.authenticatorResources=Imposible de cargar la lista de correspondencia de autenticadores (authenticators)
+contextConfig.cce=El objeto de los datos de evento de ciclo de vida (Lifecycle event data object) {0} no es un Contexto
+contextConfig.certificatesConfig.added=Adición de certificados -> requiere válvula de atributo (attribute Valve)
+contextConfig.certificatesConfig.error=Excepción durante la adición de "CertificatesValve":
+contextConfig.defaultClose=Error durante el cierre del archivo web.xml por defecto
+contextConfig.defaultConfig=Error de configuración en el archivo web.xml por defecto
+contextConfig.defaultMissing=Falta el archivo web.xml por defecto, utilizando sólo el archivo web.xml de la aplicación
+contextConfig.defaultParse=Error de evaluación (parse) en el arcivo web.xml por defecto
+contextConfig.defaultPosition=Se ha producido en la línea {0} columna {1}
+contextConfig.missingRealm=Algún reino (realm) no ha sido configurado para realizar la autenticación
+contextConfig.role.auth=ATENCIÓN: El nombre de papel de seguridad {0} es usado en un <auth-constraint> sin haber sido definido en <security-role>
+contextConfig.role.link=ATENCIÓN: El nombre de papel de seguridad {0} es usado en un <role-link> sin haber sido definido en <security-role>
+contextConfig.role.runas=ATENCIÓN: El nombre de papel de seguridad {0} es usado en un <run-as> sin haber sido definido en <security-role>
+contextConfig.start="ContextConfig": Tratamiento del "START"
+contextConfig.stop="ContextConfig": Tratamiento del "STOP"
+contextConfig.tldEntryException=Excepción durante el tratamiento de la TLD {0} en el JAR indicado por la trayectoria de recurso {1}
+contextConfig.tldFileException=Excepción durante el tratamiento de la TLD indicada por la trayectoria de recurso {0}
+contextConfig.tldJarException=Excepción durante el tratamiento del JAR indicado por la trayectoria de recurso {0}
+contextConfig.tldResourcePath=Trayectoria de recurso TLD {0} inválida
+contextConfig.unavailable=Esta aplicación está marcada como no disponible debido a los errores precedentes
+embedded.alreadyStarted=El servicio embebido (embedded service) ya ha sido arrancado
+embedded.noEngines=Algún motor (engine) no ha sido aún definido
+embedded.notStarted=El servicio embebido (embedded service) aún no ha sido arrancado
+engineConfig.cce=El objeto de los datos de evento de ciclo de vida (Lifecycle event data object) {0} no es un motor (engine)
+engineConfig.start="EngineConfig": Tratamiento del "START"
+engineConfig.stop="EngineConfig": Tratamiento del "STOP"
+hostConfig.appBase=No existe el directorio base de la aplicación {0}
+hostConfig.cce=El objeto de los datos de evento de ciclo de vida (Lifecycle event data object) {0} no es una máquina (host)
+hostConfig.deploy=Desplieque del directorio {0} de la aplicación web
+hostConfig.deployDescriptor=Desplieque del descriptor de configuración {0}
+hostConfig.deployDescriptor.error=Error durante el despliegue del descriptor de configuración {0}
+hostConfig.deployDir=Despliegue del directorio {0} de la aplicación web
+hostConfig.deployDir.error=Error durante el despliegue del directorio {0} de la aplicación web
+hostConfig.deployJar=Despliegue del archivo {0} de la aplicación web
+hostConfig.deployJar.error=Error durante el despliegue del archivo {0} de la aplicación web
+hostConfig.deploy.error=Excepción en el directorio {0} de la aplicación web
+hostConfig.deploying=Desplegando aplicaciones web descubiertas
+hostConfig.expand=Descompresión del archivo {0} de la aplicación web
+hostConfig.expand.error=Excepción durante la descompresión del archivo {0} de la aplicación web
+hostConfig.expanding=Descubierta descompresión de archivos de aplicaciones web
+hostConfig.context.restart=Error durante el arranque del contexto {0}
+hostConfig.start="HostConfig": Tratamiento del "START"
+hostConfig.stop="HostConfig": Tratamiento del "STOP"
+hostConfig.undeploy=Repliegue (undeploy) de la aplicación web que tiene como trayectoria de contexto {0}
+hostConfig.undeploy.error=Error durante el repliegue (undeploy) de la aplicación web que tiene como trayectoria de contexto {0}
+hostConfig.undeploying=Repliegue de las aplicaciones web desplegadas
+userConfig.database=Excepción durante la carga de base de datos de usuario
+userConfig.deploy=Despliegue de la aplicación web para el usuario {0}
+userConfig.deploying=Desplegando aplicaciones web para el usuario
+userConfig.error=Error durante el despliegue de la aplicación web para el usario {0}
+userConfig.start="UserConfig": Tratamiento del "START"
+userConfig.stop="UserConfig": Tratamiento del "STOP"

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/startup/LocalStrings_fr.properties
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/startup/LocalStrings_fr.properties	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/startup/LocalStrings_fr.properties	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,59 @@
+contextConfig.applicationClose=Erreur lors de la fermeture du fichier web.xml de l''application
+contextConfig.applicationConfig=Erreur de configuration dans le fichier web.xml de l''application
+contextConfig.applicationListener=Exception lors de la création de la classe d''écoute (listener) {0}
+contextConfig.applicationMissing=Le fichier web.xml de l''application est absent, utilisation des paramêtres par défaut
+contextConfig.applicationParse=Erreur d''évaluation (parse) dans le fichier web.xml de l''application
+contextConfig.applicationPosition=S''est produite à la ligne {0} colonne {1}
+contextConfig.authenticatorConfigured=Configuration d''un authentificateur (authenticator) pour la méthode {0}
+contextConfig.authenticatorInstantiate=Impossible d''instancier un authentificateur (authenticator) pour la classe {0}
+contextConfig.authenticatorMissing=Impossible de configurer un authentificateur (authenticator) pour la méthode {0}
+contextConfig.authenticatorResources=Impossible de charger la liste de correspondance des authentificateur (authenticators)
+contextConfig.cce=L''objet donnée évènement cycle de vie (Lifecycle event data object) {0} n''est pas un Contexte
+contextConfig.certificatesConfig.added=Ajout de certificats -> requête Attribut de Valve (attribute Valve)
+contextConfig.certificatesConfig.error=Exception lors de l''ajout des "CertificatesValve":
+contextConfig.defaultClose=Erreur lors de la fermeture du fichier web.xml par défaut
+contextConfig.defaultConfig=Erreur de configuration dans le fichier web.xml par défaut
+contextConfig.defaultMissing=Le fichier web.xml par défaut est absent, utilisation du fichier web.xml de l''application web.xml seulement
+contextConfig.defaultParse=Erreur d''évaluation (parse) dans le fichier web.xml par défaut
+contextConfig.defaultPosition=S''est produite à la ligne {0} colonne {1}
+contextConfig.missingRealm=Aucun royaume (realm) n''a été configuré pour réaliser l''authentification
+contextConfig.role.auth=ATTENTION: Le nom de rôle de sécurité {0} est utilisé dans un <auth-constraint> sans avoir été défini dans <security-role>
+contextConfig.role.link=ATTENTION: Le nom de rôle de sécurité {0} est utilisé dans un <role-link> sans avoir été défini dans <security-role>
+contextConfig.role.runas=ATTENTION: Le nom de rôle de sécurité {0} est utilisé dans un <run-as> sans avoir été défini dans <security-role>
+contextConfig.start="ContextConfig": Traitement du "START"
+contextConfig.stop="ContextConfig": Traitement du "STOP"
+contextConfig.tldEntryException=Exception lors du traitement de la TLD {0} dans le JAR indiqué par le chemin de ressource {1}
+contextConfig.tldFileException=Exception lors du traitement de la TLD indiqué par le chemin de ressource {0}
+contextConfig.tldJarException=Exception lors du traitement du JAR indiqué par le chemin de ressource {0}
+contextConfig.tldResourcePath=Chemin de ressource TLD {0} invalide
+contextConfig.unavailable=Cette application est marquée comme non disponible suite aux erreurs précédentes
+embedded.alreadyStarted=Le service enfoui (embedded service) a déjà été démarré
+embedded.noEngines=Aucun moteur (engine) n''a encore été défini
+embedded.notStarted=Le service enfoui (embedded service) n''a pas encore été démarré
+engineConfig.cce=L''objet donnée évènement cycle de vie (Lifecycle event data object) {0} n''est pas un moteur (engine)
+engineConfig.start="EngineConfig": Traitement du "START"
+engineConfig.stop="EngineConfig": Traitement du "STOP"
+hostConfig.cce=L''objet donnée évènement cycle de vie (Lifecycle event data object) {0} n''est pas un hôte
+hostConfig.deploy=Déploiement du répertoire {0} de l''application web
+hostConfig.deployDescriptor=Déploiement du descripteur de configuration {0}
+hostConfig.deployDescriptor.error=Erreur lors du déploiement du descripteur de configuration {0}
+hostConfig.deployDir=Déploiement du répertoire {0} de l''application web
+hostConfig.deployDir.error=Erreur lors du déploiement du répertoire {0} de l''application web
+hostConfig.deployJar=Déploiement de l''archive {0} de l''application web
+hostConfig.deployJar.error=Erreur lors du déploiement de l''archive {0} de l''application web
+hostConfig.deploy.error=Exception lors du répertoire {0} de l''application web
+hostConfig.deploying=Déploiement des applications web découvertes (discovered)
+hostConfig.expand=Décompression de l''archive {0} de l''application web
+hostConfig.expand.error=Exception lors de la décompression de l''archive {0} de l''application web
+hostConfig.expanding=Décompression des archives des applications web découvertes (discovered)
+hostConfig.start="HostConfig": Traitement du "START"
+hostConfig.stop="HostConfig": Traitement du "STOP"
+hostConfig.undeploy=Repli (undeploy) de l''application web ayant pour chemin de contexte {0}
+hostConfig.undeploy.error=Erreur lors du repli (undeploy) de l''application web ayant pour chemin de contexte {0}
+hostConfig.undeploying=Repli des applications web déployées
+userConfig.database=Exception lors du chargement de la base de données utilisateur
+userConfig.deploy=Déploiement de l''application web pour l''utilisateur {0}
+userConfig.deploying=Déploiement des applications web utilisateur
+userConfig.error=Erreur lors du déploiement de l''application web pour l''utilisateur {0}
+userConfig.start="UserConfig": Traitement du "START"
+userConfig.stop="UserConfig": Traitement du "STOP"

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/startup/LocalStrings_ja.properties
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/startup/LocalStrings_ja.properties	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/startup/LocalStrings_ja.properties	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,64 @@
+contextConfig.applicationClose=\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u306eweb.xml\u3092\u30af\u30ed\u30fc\u30ba\u4e2d\u306e\u30a8\u30e9\u30fc\u3067\u3059
+contextConfig.applicationConfig=\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u306eweb.xml\u306e\u8a2d\u5b9a\u30a8\u30e9\u30fc\u3067\u3059
+contextConfig.applicationListener=\u30af\u30e9\u30b9 {0} \u306e\u30ea\u30b9\u30ca\u3092\u4f5c\u6210\u4e2d\u306e\u4f8b\u5916\u3067\u3059
+contextConfig.applicationMissing=\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u306eweb.xml\u304c\u898b\u3064\u304b\u308a\u307e\u305b\u3093\u3001\u30c7\u30d5\u30a9\u30eb\u30c8\u3060\u3051\u3092\u4f7f\u7528\u3057\u307e\u3059
+contextConfig.applicationParse=\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u306eweb.xml\u4e2d\u306e\u89e3\u6790\u30a8\u30e9\u30fc\u3067\u3059
+contextConfig.applicationPosition={0}\u884c\u306e{1}\u5217\u76ee\u3067\u767a\u751f\u3057\u307e\u3057\u305f
+contextConfig.authenticatorConfigured=\u30e1\u30bd\u30c3\u30c9 {0} \u306e\u30aa\u30fc\u30bb\u30f3\u30c6\u30a3\u30b1\u30fc\u30bf\u3092\u8a2d\u5b9a\u3057\u307e\u3059
+contextConfig.authenticatorInstantiate=\u30af\u30e9\u30b9 {0} \u306e\u30aa\u30fc\u30bb\u30f3\u30c6\u30a3\u30b1\u30fc\u30bf\u3092\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u5316\u3067\u304d\u307e\u305b\u3093
+contextConfig.authenticatorMissing=\u30e1\u30bd\u30c3\u30c9 {0} \u306e\u30aa\u30fc\u30bb\u30f3\u30c6\u30a3\u30b1\u30fc\u30bf\u3092\u8a2d\u5b9a\u3067\u304d\u307e\u305b\u3093
+contextConfig.authenticatorResources=\u30aa\u30fc\u30bb\u30f3\u30c6\u30a3\u30b1\u30fc\u30bf\u306e\u30de\u30c3\u30d7\u30ea\u30b9\u30c8\u3092\u30ed\u30fc\u30c9\u3067\u304d\u307e\u305b\u3093
+contextConfig.cce=\u30e9\u30a4\u30d5\u30b5\u30a4\u30af\u30eb\u30a4\u30d9\u30f3\u30c8\u30c7\u30fc\u30bf\u30aa\u30d6\u30b8\u30a7\u30af\u30c8 {0} \u306f\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u3067\u306f\u3042\u308a\u307e\u305b\u3093
+contextConfig.certificatesConfig.added=\u8a3c\u660e\u66f8\u3092\u30ea\u30af\u30a8\u30b9\u30c8\u306e\u5c5e\u6027\u5024\u306b\u8ffd\u52a0\u3057\u307e\u3059
+contextConfig.certificatesConfig.error=CertificatesValve\u3092\u8ffd\u52a0\u4e2d\u306b\u4f8b\u5916\u304c\u767a\u751f\u3057\u307e\u3057\u305f:
+contextConfig.defaultClose=\u30c7\u30d5\u30a9\u30eb\u30c8\u306eweb.xml\u306e\u30af\u30ed\u30fc\u30ba\u4e2d\u306b\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f
+contextConfig.defaultConfig=\u30c7\u30d5\u30a9\u30eb\u30c8\u306eweb.xml\u306e\u4e2d\u306e\u8a2d\u5b9a\u30a8\u30e9\u30fc\u3067\u3059
+contextConfig.defaultMissing=\u30c7\u30d5\u30a9\u30eb\u30c8\u306eweb.xml\u304c\u898b\u3064\u304b\u308a\u307e\u305b\u3093\u3001\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u306eweb.xml\u3060\u3051\u3092\u4f7f\u7528\u3057\u307e\u3059
+contextConfig.defaultParse=\u30c7\u30d5\u30a9\u30eb\u30c8\u306eweb.xml\u4e2d\u306e\u89e3\u6790\u30a8\u30e9\u30fc\u3067\u3059
+contextConfig.defaultPosition={0}\u884c\u306e{1}\u5217\u76ee\u3067\u767a\u751f\u3057\u307e\u3057\u305f
+contextConfig.missingRealm=\u8a8d\u8a3c\u3059\u308b\u305f\u3081\u306b\u30ec\u30eb\u30e0\u304c\u8a2d\u5b9a\u3055\u308c\u3066\u3044\u307e\u305b\u3093
+contextConfig.role.auth=\u8b66\u544a: <security-role>\u306b\u5b9a\u7fa9\u3055\u308c\u3066\u3044\u306a\u3044\u30bb\u30ad\u30e5\u30ea\u30c6\u30a3\u30ed\u30fc\u30eb\u540d {0} \u304c<auth-constraint>\u306e\u4e2d\u3067\u4f7f\u7528\u3055\u308c\u307e\u3057\u305f
+contextConfig.role.link=\u8b66\u544a: <security-role>\u306b\u5b9a\u7fa9\u3055\u308c\u3066\u3044\u306a\u3044\u30bb\u30ad\u30e5\u30ea\u30c6\u30a3\u30ed\u30fc\u30eb\u540d {0} \u304c<role-link>\u306e\u4e2d\u3067\u4f7f\u7528\u3055\u308c\u307e\u3057\u305f
+contextConfig.role.runas=\u8b66\u544a: <security-role>\u306b\u5b9a\u7fa9\u3055\u308c\u3066\u3044\u306a\u3044\u30bb\u30ad\u30e5\u30ea\u30c6\u30a3\u30ed\u30fc\u30eb\u540d {0} \u304c<run-as>\u306e\u4e2d\u3067\u4f7f\u7528\u3055\u308c\u307e\u3057\u305f
+contextConfig.start=ContextConfig: \u51e6\u7406\u3092\u958b\u59cb\u3057\u307e\u3059
+contextConfig.stop=ContextConfig: \u51e6\u7406\u3092\u505c\u6b62\u3057\u307e\u3059
+contextConfig.tldEntryException=\u30ea\u30bd\u30fc\u30b9\u30d1\u30b9 {1} \u306eJAR\u30d5\u30a1\u30a4\u30eb\u306eTLD {0} \u3092\u51e6\u7406\u4e2d\u306e\u4f8b\u5916\u3067\u3059
+contextConfig.tldFileException=\u30ea\u30bd\u30fc\u30b9\u30d1\u30b9 {0} \u306eTLD\u3092\u51e6\u7406\u4e2d\u306e\u4f8b\u5916\u3067\u3059
+contextConfig.tldJarException=\u30ea\u30bd\u30fc\u30b9\u30d1\u30b9 {0} \u306eJAR\u30d5\u30a1\u30a4\u30eb\u3092\u51e6\u7406\u4e2d\u306e\u4f8b\u5916\u3067\u3059
+contextConfig.tldResourcePath=\u7121\u52b9\u306aTLD\u306e\u30ea\u30bd\u30fc\u30b9\u30d1\u30b9 {0}
+contextConfig.unavailable=\u524d\u306e\u30a8\u30e9\u30fc\u306e\u305f\u3081\u306b\u3053\u306e\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u306f\u5229\u7528\u3067\u304d\u306a\u3044\u3088\u3046\u306b\u30de\u30fc\u30af\u3057\u307e\u3059
+embedded.alreadyStarted=\u7d44\u307f\u8fbc\u307f\u30b5\u30fc\u30d3\u30b9\u306f\u65e2\u306b\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u3059
+embedded.noEngines=\u307e\u3060\u30a8\u30f3\u30b8\u30f3\u304c\u5b9a\u7fa9\u3055\u308c\u3066\u3044\u307e\u305b\u3093
+embedded.notStarted=\u7d44\u307f\u8fbc\u307f\u30b5\u30fc\u30d3\u30b9\u306f\u307e\u3060\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u305b\u3093
+engineConfig.cce=\u30e9\u30a4\u30d5\u30b5\u30a4\u30af\u30eb\u30a4\u30d9\u30f3\u30c8\u30c7\u30fc\u30bf\u30aa\u30d6\u30b8\u30a7\u30af\u30c8 {0} \u306f\u30a8\u30f3\u30b8\u30f3\u3067\u306f\u3042\u308a\u307e\u305b\u3093
+engineConfig.start=EngineConfig: \u51e6\u7406\u3092\u958b\u59cb\u3057\u307e\u3059
+engineConfig.stop=EngineConfig: \u51e6\u7406\u3092\u505c\u6b62\u3057\u307e\u3059
+hostConfig.appBase=\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u30d9\u30fc\u30b9\u30c7\u30a3\u30ec\u30af\u30c8\u30ea {0} \u306f\u5b58\u5728\u3057\u307e\u305b\u3093
+hostConfig.cce=\u30e9\u30a4\u30d5\u30b5\u30a4\u30af\u30eb\u30a4\u30d9\u30f3\u30c8\u30c7\u30fc\u30bf\u30aa\u30d6\u30b8\u30a7\u30af\u30c8 {0} \u306f\u30db\u30b9\u30c8\u3067\u306f\u3042\u308a\u307e\u305b\u3093
+hostConfig.deploy=Web\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u30c7\u30a3\u30ec\u30af\u30c8\u30ea {0} \u3092\u914d\u5099\u3057\u307e\u3059
+hostConfig.deployDescriptor=\u8a2d\u5b9a\u8a18\u8ff0\u5b50 {0} \u3092\u914d\u5099\u3057\u307e\u3059
+hostConfig.deployDescriptor.error=\u8a2d\u5b9a\u8a18\u8ff0\u5b50 {0} \u3092\u914d\u5099\u4e2d\u306e\u30a8\u30e9\u30fc\u3067\u3059
+hostConfig.deployDir=Web\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u30c7\u30a3\u30ec\u30af\u30c8\u30ea {0} \u3092\u914d\u5099\u3057\u307e\u3059
+hostConfig.deployDir.error=Web\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u30c7\u30a3\u30ec\u30af\u30c8\u30ea {0} \u3092\u914d\u5099\u4e2d\u306e\u30a8\u30e9\u30fc\u3067\u3059
+hostConfig.deployJar=Web\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u30a2\u30fc\u30ab\u30a4\u30d6 {0} \u3092\u914d\u5099\u3057\u307e\u3059
+hostConfig.deployJar.error=Web\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u30a2\u30fc\u30ab\u30a4\u30d6 {0} \u3092\u914d\u5099\u4e2d\u306e\u30a8\u30e9\u30fc\u3067\u3059
+hostConfig.deploy.error=Web\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u30c7\u30a3\u30ec\u30af\u30c8\u30ea {0} \u3092\u914d\u5099\u4e2d\u306e\u4f8b\u5916\u3067\u3059
+hostConfig.deploying=\u898b\u3064\u304b\u3063\u305fWeb\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u3092\u914d\u5099\u3057\u307e\u3059
+hostConfig.expand=Web\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u30a2\u30fc\u30ab\u30a4\u30d6 {0} \u3092\u5c55\u958b\u3057\u307e\u3059
+hostConfig.expand.error=Web\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u30a2\u30fc\u30ab\u30a4\u30d6 {0} \u3092\u5c55\u958b\u4e2d\u306e\u4f8b\u5916\u3067\u3059
+hostConfig.expanding=\u898b\u3064\u304b\u3063\u305fWeb\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u30a2\u30fc\u30ab\u30a4\u30d6\u3092\u5c55\u958b\u3057\u307e\u3059
+hostConfig.context.restart=\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8 {0} \u3092\u518d\u8d77\u52d5\u4e2d\u306e\u30a8\u30e9\u30fc\u3067\u3059
+hostConfig.removeXML=\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8 {0} \u306e\u914d\u5099\u3092\u89e3\u9664\u3057\u307e\u3057\u305f
+hostConfig.removeDIR=\u30c7\u30a3\u30ec\u30af\u30c8\u30ea {0} \u306e\u914d\u5099\u3092\u89e3\u9664\u3057\u307e\u3057\u305f
+hostConfig.removeWAR=WAR\u30d5\u30a1\u30a4\u30eb {0} \u306e\u914d\u5099\u3092\u89e3\u9664\u3057\u307e\u3057\u305f
+hostConfig.start=HostConfig: \u51e6\u7406\u3092\u505c\u6b62\u3057\u307e\u3059
+hostConfig.stop=HostConfig: \u51e6\u7406\u3092\u505c\u6b62\u3057\u307e\u3059
+hostConfig.undeploy=\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u30d1\u30b9 {0} \u306eWeb\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u306e\u914d\u5099\u3092\u89e3\u9664\u3057\u307e\u3059
+hostConfig.undeploy.error=\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u30d1\u30b9 {0} \u306eWeb\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u306e\u914d\u5099\u3092\u89e3\u9664\u4e2d\u306e\u30a8\u30e9\u30fc\u3067\u3059
+hostConfig.undeploying=\u914d\u5099\u3055\u308c\u305fWeb\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u306e\u914d\u5099\u3092\u89e3\u9664\u3057\u3066\u3044\u307e\u3059
+userConfig.database=\u30e6\u30fc\u30b6\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u306e\u30ed\u30fc\u30c9\u4e2d\u306e\u4f8b\u5916\u3067\u3059
+userConfig.deploy=\u30e6\u30fc\u30b6 {0} \u306eWeb\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u3092\u914d\u5099\u3057\u307e\u3059
+userConfig.deploying=\u30e6\u30fc\u30b6\u306eWeb\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u3092\u914d\u5099\u3057\u307e\u3059
+userConfig.error=\u30e6\u30fc\u30b6 {0} \u306eWeb\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u3092\u914d\u5099\u4e2d\u306e\u30a8\u30e9\u30fc\u3067\u3059
+userConfig.start=UserConfig: \u51e6\u7406\u3092\u958b\u59cb\u3057\u307e\u3059
+userConfig.stop=UserConfig: \u51e6\u7406\u3092\u505c\u6b62\u3057\u307e\u3059

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/startup/NamingRuleSet.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/startup/NamingRuleSet.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/startup/NamingRuleSet.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,135 @@
+/*
+ * Copyright 1999-2001,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.startup;
+
+
+import org.apache.tomcat.util.digester.Digester;
+import org.apache.tomcat.util.digester.RuleSetBase;
+
+
+/**
+ * <p><strong>RuleSet</strong> for processing the JNDI Enterprise Naming
+ * Context resource declaration elements.</p>
+ *
+ * @author Craig R. McClanahan
+ * @author Remy Maucherat
+ * @version $Revision: 303177 $ $Date: 2004-09-02 05:05:00 -0500 (Thu, 02 Sep 2004) $
+ */
+
+public class NamingRuleSet extends RuleSetBase {
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The matching pattern prefix to use for recognizing our elements.
+     */
+    protected String prefix = null;
+
+
+    // ------------------------------------------------------------ Constructor
+
+
+    /**
+     * Construct an instance of this <code>RuleSet</code> with the default
+     * matching pattern prefix.
+     */
+    public NamingRuleSet() {
+
+        this("");
+
+    }
+
+
+    /**
+     * Construct an instance of this <code>RuleSet</code> with the specified
+     * matching pattern prefix.
+     *
+     * @param prefix Prefix for matching pattern rules (including the
+     *  trailing slash character)
+     */
+    public NamingRuleSet(String prefix) {
+
+        super();
+        this.namespaceURI = null;
+        this.prefix = prefix;
+
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * <p>Add the set of Rule instances defined in this RuleSet to the
+     * specified <code>Digester</code> instance, associating them with
+     * our namespace URI (if any).  This method should only be called
+     * by a Digester instance.</p>
+     *
+     * @param digester Digester instance to which the new Rule instances
+     *  should be added.
+     */
+    public void addRuleInstances(Digester digester) {
+
+        digester.addObjectCreate(prefix + "Ejb",
+                                 "org.apache.catalina.deploy.ContextEjb");
+        digester.addRule(prefix + "Ejb", new SetAllPropertiesRule());
+        digester.addRule(prefix + "Ejb",
+                new SetNextNamingRule("addEjb",
+                            "org.apache.catalina.deploy.ContextEjb"));
+
+        digester.addObjectCreate(prefix + "Environment",
+                                 "org.apache.catalina.deploy.ContextEnvironment");
+        digester.addSetProperties(prefix + "Environment");
+        digester.addRule(prefix + "Environment",
+                            new SetNextNamingRule("addEnvironment",
+                            "org.apache.catalina.deploy.ContextEnvironment"));
+
+        digester.addObjectCreate(prefix + "LocalEjb",
+                                 "org.apache.catalina.deploy.ContextLocalEjb");
+        digester.addRule(prefix + "LocalEjb", new SetAllPropertiesRule());
+        digester.addRule(prefix + "LocalEjb",
+                new SetNextNamingRule("addLocalEjb",
+                            "org.apache.catalina.deploy.ContextLocalEjb"));
+
+        digester.addObjectCreate(prefix + "Resource",
+                                 "org.apache.catalina.deploy.ContextResource");
+        digester.addRule(prefix + "Resource", new SetAllPropertiesRule());
+        digester.addRule(prefix + "Resource",
+                new SetNextNamingRule("addResource",
+                            "org.apache.catalina.deploy.ContextResource"));
+
+        digester.addObjectCreate(prefix + "ResourceEnvRef",
+            "org.apache.catalina.deploy.ContextResourceEnvRef");
+        digester.addRule(prefix + "ResourceEnvRef", new SetAllPropertiesRule());
+        digester.addRule(prefix + "ResourceEnvRef",
+                new SetNextNamingRule("addResourceEnvRef",
+                            "org.apache.catalina.deploy.ContextResourceEnvRef"));
+
+        digester.addObjectCreate(prefix + "Transaction",
+            "org.apache.catalina.deploy.ContextTransaction");
+        digester.addRule(prefix + "Transaction", new SetAllPropertiesRule());
+        digester.addRule(prefix + "Transaction",
+                new SetNextNamingRule("setTransaction",
+                            "org.apache.catalina.deploy.ContextTransaction"));
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/startup/PasswdUserDatabase.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/startup/PasswdUserDatabase.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/startup/PasswdUserDatabase.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,193 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.startup;
+
+
+import java.io.BufferedReader;
+import java.io.FileReader;
+import java.io.IOException;
+import java.util.Hashtable;
+import java.util.Enumeration;
+
+
+/**
+ * Concrete implementation of the <strong>UserDatabase</code> interface
+ * that processes the <code>/etc/passwd</code> file on a Unix system.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public final class PasswdUserDatabase
+    implements UserDatabase {
+
+
+    // --------------------------------------------------------- Constructors
+
+
+    /**
+     * Initialize a new instance of this user database component.
+     */
+    public PasswdUserDatabase() {
+
+        super();
+
+    }
+
+
+    // --------------------------------------------------- Instance Variables
+
+
+    /**
+     * The pathname of the Unix password file.
+     */
+    private static final String PASSWORD_FILE = "/etc/passwd";
+
+
+    /**
+     * The set of home directories for all defined users, keyed by username.
+     */
+    private Hashtable homes = new Hashtable();
+
+
+    /**
+     * The UserConfig listener with which we are associated.
+     */
+    private UserConfig userConfig = null;
+
+
+    // ----------------------------------------------------------- Properties
+
+
+    /**
+     * Return the UserConfig listener with which we are associated.
+     */
+    public UserConfig getUserConfig() {
+
+        return (this.userConfig);
+
+    }
+
+
+    /**
+     * Set the UserConfig listener with which we are associated.
+     *
+     * @param userConfig The new UserConfig listener
+     */
+    public void setUserConfig(UserConfig userConfig) {
+
+        this.userConfig = userConfig;
+        init();
+
+    }
+
+
+    // ------------------------------------------------------- Public Methods
+
+
+    /**
+     * Return an absolute pathname to the home directory for the specified user.
+     *
+     * @param user User for which a home directory should be retrieved
+     */
+    public String getHome(String user) {
+
+        return ((String) homes.get(user));
+
+    }
+
+
+    /**
+     * Return an enumeration of the usernames defined on this server.
+     */
+    public Enumeration getUsers() {
+
+        return (homes.keys());
+
+    }
+
+
+    // ------------------------------------------------------ Private Methods
+
+
+    /**
+     * Initialize our set of users and home directories.
+     */
+    private void init() {
+
+        BufferedReader reader = null;
+        try {
+
+            reader = new BufferedReader(new FileReader(PASSWORD_FILE));
+
+            while (true) {
+
+                // Accumulate the next line
+                StringBuffer buffer = new StringBuffer();
+                while (true) {
+                    int ch = reader.read();
+                    if ((ch < 0) || (ch == '\n'))
+                        break;
+                    buffer.append((char) ch);
+                }
+                String line = buffer.toString();
+                if (line.length() < 1)
+                    break;
+
+                // Parse the line into constituent elements
+                int n = 0;
+                String tokens[] = new String[7];
+                for (int i = 0; i < tokens.length; i++)
+                    tokens[i] = null;
+                while (n < tokens.length) {
+                    String token = null;
+                    int colon = line.indexOf(':');
+                    if (colon >= 0) {
+                        token = line.substring(0, colon);
+                        line = line.substring(colon + 1);
+                    } else {
+                        token = line;
+                        line = "";
+                    }
+                    tokens[n++] = token;
+                }
+
+                // Add this user and corresponding directory
+                if ((tokens[0] != null) && (tokens[5] != null))
+                    homes.put(tokens[0], tokens[5]);
+
+            }
+
+            reader.close();
+            reader = null;
+
+        } catch (Exception e) {
+            if (reader != null) {
+                try {
+                    reader.close();
+                } catch (IOException f) {
+                    ;
+                }
+                reader = null;
+            }
+        }
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/startup/SetAllPropertiesRule.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/startup/SetAllPropertiesRule.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/startup/SetAllPropertiesRule.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,64 @@
+/*
+ * Copyright 1999-2001,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.startup;
+
+import org.xml.sax.Attributes;
+
+import org.apache.tomcat.util.IntrospectionUtils;
+import org.apache.tomcat.util.digester.Rule;
+
+/**
+ * Rule that uses the introspection utils to set properties.
+ * 
+ * @author Remy Maucherat
+ */
+public class SetAllPropertiesRule extends Rule {
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Handle the beginning of an XML element.
+     *
+     * @param attributes The attributes of this element
+     *
+     * @exception Exception if a processing error occurs
+     */
+    public void begin(String namespace, String nameX, Attributes attributes)
+        throws Exception {
+
+        for (int i = 0; i < attributes.getLength(); i++) {
+            String name = attributes.getLocalName(i);
+            if ("".equals(name)) {
+                name = attributes.getQName(i);
+            }
+            String value = attributes.getValue(i);
+            IntrospectionUtils.setProperty(digester.peek(), name, value);
+        }
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/startup/SetContextPropertiesRule.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/startup/SetContextPropertiesRule.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/startup/SetContextPropertiesRule.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,68 @@
+/*
+ * Copyright 1999-2001,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.startup;
+
+import org.xml.sax.Attributes;
+
+import org.apache.tomcat.util.IntrospectionUtils;
+import org.apache.tomcat.util.digester.Rule;
+
+/**
+ * Rule that uses the introspection utils to set properties of a context 
+ * (everything except "path").
+ * 
+ * @author Remy Maucherat
+ */
+public class SetContextPropertiesRule extends Rule {
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Handle the beginning of an XML element.
+     *
+     * @param attributes The attributes of this element
+     *
+     * @exception Exception if a processing error occurs
+     */
+    public void begin(String namespace, String nameX, Attributes attributes)
+        throws Exception {
+
+        for (int i = 0; i < attributes.getLength(); i++) {
+            String name = attributes.getLocalName(i);
+            if ("".equals(name)) {
+                name = attributes.getQName(i);
+            }
+            if ("path".equals(name) || "docBase".equals(name)) {
+                continue;
+            }
+            String value = attributes.getValue(i);
+            IntrospectionUtils.setProperty(digester.peek(), name, value);
+        }
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/startup/SetNextNamingRule.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/startup/SetNextNamingRule.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/startup/SetNextNamingRule.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,119 @@
+/* $Id: SetNextNamingRule.java 303133 2004-08-29 16:46:15Z yoavs $
+ *
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.startup;
+
+import org.apache.catalina.Context;
+import org.apache.catalina.deploy.NamingResources;
+import org.apache.tomcat.util.IntrospectionUtils;
+import org.apache.tomcat.util.digester.Rule;
+
+
+/**
+ * <p>Rule implementation that calls a method on the (top-1) (parent)
+ * object, passing the top object (child) as an argument.  It is
+ * commonly used to establish parent-child relationships.</p>
+ *
+ * <p>This rule now supports more flexible method matching by default.
+ * It is possible that this may break (some) code 
+ * written against release 1.1.1 or earlier.
+ * </p> 
+ */
+
+public class SetNextNamingRule extends Rule {
+
+
+    // ----------------------------------------------------------- Constructors
+
+    
+    /**
+     * Construct a "set next" rule with the specified method name.
+     *
+     * @param methodName Method name of the parent method to call
+     * @param paramType Java class of the parent method's argument
+     *  (if you wish to use a primitive type, specify the corresonding
+     *  Java wrapper class instead, such as <code>java.lang.Boolean</code>
+     *  for a <code>boolean</code> parameter)
+     */
+    public SetNextNamingRule(String methodName,
+                       String paramType) {
+
+        this.methodName = methodName;
+        this.paramType = paramType;
+
+    }
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The method name to call on the parent object.
+     */
+    protected String methodName = null;
+
+
+    /**
+     * The Java class name of the parameter type expected by the method.
+     */
+    protected String paramType = null;
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Process the end of this element.
+     */
+    public void end() throws Exception {
+
+        // Identify the objects to be used
+        Object child = digester.peek(0);
+        Object parent = digester.peek(1);
+
+        NamingResources namingResources = null;
+        if (parent instanceof Context) {
+            namingResources = ((Context) parent).getNamingResources();
+        } else {
+            namingResources = (NamingResources) parent;
+        }
+        
+        // Call the specified method
+        IntrospectionUtils.callMethod1(namingResources, methodName,
+                child, paramType, digester.getClassLoader());
+
+    }
+
+
+    /**
+     * Render a printable version of this Rule.
+     */
+    public String toString() {
+
+        StringBuffer sb = new StringBuffer("SetNextRule[");
+        sb.append("methodName=");
+        sb.append(methodName);
+        sb.append(", paramType=");
+        sb.append(paramType);
+        sb.append("]");
+        return (sb.toString());
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/startup/TldConfig.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/startup/TldConfig.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/startup/TldConfig.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,724 @@
+/*
+ * Copyright 1999-2001,2004-2006 The Apache Software Foundation.
+ * 
+ * Licensed 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.startup;
+
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+import java.util.StringTokenizer;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+
+import javax.naming.NameClassPair;
+import javax.naming.NamingEnumeration;
+import javax.naming.NamingException;
+import javax.naming.directory.DirContext;
+import javax.servlet.ServletException;
+
+import org.apache.catalina.Context;
+import org.apache.catalina.Globals;
+import org.apache.catalina.core.StandardContext;
+import org.apache.catalina.util.StringManager;
+import org.apache.tomcat.util.digester.Digester;
+import org.xml.sax.InputSource;
+
+/**
+ * Startup event listener for a <b>Context</b> that configures the properties
+ * of that Context, and the associated defined servlets.
+ *
+ * @author Craig R. McClanahan
+ * @author Jean-Francois Arcand
+ * @author Costin Manolache
+ */
+public final class TldConfig  {
+
+    // Names of JARs that are known not to contain any TLDs
+    private static HashSet noTldJars;
+
+    private static org.apache.commons.logging.Log log=
+        org.apache.commons.logging.LogFactory.getLog( TldConfig.class );
+
+    private static final String FILE_URL_PREFIX = "file:";
+    private static final int FILE_URL_PREFIX_LEN = FILE_URL_PREFIX.length();
+
+
+    /*
+     * Initializes the set of JARs that are known not to contain any TLDs
+     */
+    static {
+        noTldJars = new HashSet();
+        noTldJars.add("catalina.jar");
+        noTldJars.add("catalina-ant.jar");
+        noTldJars.add("catalina-cluster.jar");
+        noTldJars.add("catalina-optional.jar");
+        noTldJars.add("commons-el.jar");
+        noTldJars.add("commons-logging-api.jar");
+        noTldJars.add("commons-modeler.jar");
+        noTldJars.add("jasper-compiler.jar");
+        noTldJars.add("jasper-compiler-jdt.jar");
+        noTldJars.add("jasper-runtime.jar");
+        noTldJars.add("jsp-api.jar");
+        noTldJars.add("naming-resources.jar");
+        noTldJars.add("naming-factory.jar");
+        noTldJars.add("naming-factory-dbcp.jar");
+        noTldJars.add("servlet-api.jar");
+        noTldJars.add("servlets-cgi.jar");
+        noTldJars.add("servlets-default.jar");
+        noTldJars.add("servlets-invoker.jar");
+        noTldJars.add("servlets-ssi.jar");
+        noTldJars.add("servlets-webdav.jar");
+        noTldJars.add("tomcat-ajp.jar");
+        noTldJars.add("tomcat-coyote.jar");
+        noTldJars.add("tomcat-http.jar");
+        noTldJars.add("tomcat-util.jar");
+        // i18n JARs
+        noTldJars.add("catalina-i18n-en.jar");
+        noTldJars.add("catalina-i18n-es.jar");
+        noTldJars.add("catalina-i18n-fr.jar");
+        noTldJars.add("catalina-i18n-ja.jar");
+        // Misc JARs not included with Tomcat
+        noTldJars.add("ant.jar");
+        noTldJars.add("commons-dbcp.jar");
+        noTldJars.add("commons-beanutils.jar");
+        noTldJars.add("commons-fileupload-1.0.jar");
+        noTldJars.add("commons-pool.jar");
+        noTldJars.add("commons-digester.jar");
+        noTldJars.add("commons-logging.jar");
+        noTldJars.add("commons-collections.jar");
+        noTldJars.add("jmx.jar");
+        noTldJars.add("jmx-tools.jar");
+        noTldJars.add("xercesImpl.jar");
+        noTldJars.add("xmlParserAPIs.jar");
+        noTldJars.add("xml-apis.jar");
+        // JARs from J2SE runtime
+        noTldJars.add("sunjce_provider.jar");
+        noTldJars.add("ldapsec.jar");
+        noTldJars.add("localedata.jar");
+        noTldJars.add("dnsns.jar");
+    }
+
+
+    // ----------------------------------------------------- Instance Variables
+
+    /**
+     * The Context we are associated with.
+     */
+    private Context context = null;
+
+
+    /**
+     * The string resources for this package.
+     */
+    private static final StringManager sm =
+        StringManager.getManager(Constants.Package);
+
+    /**
+     * The <code>Digester</code> we will use to process tag library
+     * descriptor files.
+     */
+    private static Digester tldDigester = null;
+
+
+    /**
+     * Attribute value used to turn on/off TLD validation
+     */
+     private static boolean tldValidation = false;
+
+
+    /**
+     * Attribute value used to turn on/off TLD  namespace awarenes.
+     */
+    private static boolean tldNamespaceAware = false;
+
+    private boolean rescan=true;
+
+    private ArrayList listeners=new ArrayList();
+
+    // --------------------------------------------------------- Public Methods
+
+    /**
+     * 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) {
+        if (jarNames != null) {
+            noTldJars.clear();
+            StringTokenizer tokenizer = new StringTokenizer(jarNames, ",");
+            while (tokenizer.hasMoreElements()) {
+                noTldJars.add(tokenizer.nextToken());
+            }
+        }
+    }
+
+    /**
+     * Set the validation feature of the XML parser used when
+     * parsing xml instances.
+     * @param tldValidation true to enable xml instance validation
+     */
+    public void setTldValidation(boolean tldValidation){
+        TldConfig.tldValidation = tldValidation;
+    }
+
+    /**
+     * Get the server.xml <host> attribute's xmlValidation.
+     * @return true if validation is enabled.
+     *
+     */
+    public boolean getTldValidation(){
+        return tldValidation;
+    }
+
+    /**
+     * Get the server.xml <host> attribute's xmlNamespaceAware.
+     * @return true if namespace awarenes is enabled.
+     *
+     */
+    public boolean getTldNamespaceAware(){
+        return tldNamespaceAware;
+    }
+
+
+    /**
+     * Set the namespace aware feature of the XML parser used when
+     * parsing xml instances.
+     * @param tldNamespaceAware true to enable namespace awareness
+     */
+    public void setTldNamespaceAware(boolean tldNamespaceAware){
+        TldConfig.tldNamespaceAware = tldNamespaceAware;
+    }    
+
+
+    public boolean isRescan() {
+        return rescan;
+    }
+
+    public void setRescan(boolean rescan) {
+        this.rescan = rescan;
+    }
+
+    public Context getContext() {
+        return context;
+    }
+
+    public void setContext(Context context) {
+        this.context = context;
+    }
+
+    public void addApplicationListener( String s ) {
+        //if(log.isDebugEnabled())
+            log.debug( "Add tld listener " + s);
+        listeners.add(s);
+    }
+
+    public String[] getTldListeners() {
+        String result[]=new String[listeners.size()];
+        listeners.toArray(result);
+        return result;
+    }
+
+
+    /**
+     * Scan for and configure all tag library descriptors found in this
+     * web application.
+     *
+     * @exception Exception if a fatal input/output or parsing error occurs
+     */
+    public void execute() throws Exception {
+        long t1=System.currentTimeMillis();
+
+        File tldCache=null;
+
+        if (context instanceof StandardContext) {
+            File workDir= (File)
+                ((StandardContext)context).getServletContext().getAttribute(Globals.WORK_DIR_ATTR);
+            tldCache=new File( workDir, "tldCache.ser");
+        }
+
+        // Option to not rescan
+        if( ! rescan ) {
+            // find the cache
+            if( tldCache!= null && tldCache.exists()) {
+                // just read it...
+                processCache(tldCache);
+                return;
+            }
+        }
+
+        /*
+         * Acquire the list of TLD resource paths, possibly embedded in JAR
+         * files, to be processed
+         */
+        Set resourcePaths = tldScanResourcePaths();
+        Map jarPaths = getJarPaths();
+
+        // Check to see if we can use cached listeners
+        if (tldCache != null && tldCache.exists()) {
+            long lastModified = getLastModified(resourcePaths, jarPaths);
+            if (lastModified < tldCache.lastModified()) {
+                processCache(tldCache);
+                return;
+            }
+        }
+
+        // Scan each accumulated resource path for TLDs to be processed
+        Iterator paths = resourcePaths.iterator();
+        while (paths.hasNext()) {
+            String path = (String) paths.next();
+            if (path.endsWith(".jar")) {
+                tldScanJar(path);
+            } else {
+                tldScanTld(path);
+            }
+        }
+        if (jarPaths != null) {
+            paths = jarPaths.values().iterator();
+            while (paths.hasNext()) {
+                tldScanJar((File) paths.next());
+            }
+        }
+
+        String list[] = getTldListeners();
+
+        if( tldCache!= null ) {
+            log.debug( "Saving tld cache: " + tldCache + " " + list.length);
+            try {
+                FileOutputStream out=new FileOutputStream(tldCache);
+                ObjectOutputStream oos=new ObjectOutputStream( out );
+                oos.writeObject( list );
+                oos.close();
+            } catch( IOException ex ) {
+                ex.printStackTrace();
+            }
+        }
+
+        if( log.isDebugEnabled() )
+            log.debug( "Adding tld listeners:" + list.length);
+        for( int i=0; list!=null && i<list.length; i++ ) {
+            context.addApplicationListener(list[i]);
+        }
+
+        long t2=System.currentTimeMillis();
+        if( context instanceof StandardContext ) {
+            ((StandardContext)context).setTldScanTime(t2-t1);
+        }
+
+    }
+
+    // -------------------------------------------------------- Private Methods
+
+    /*
+     * Returns the last modification date of the given sets of resources.
+     *
+     * @param resourcePaths
+     * @param jarPaths
+     *
+     * @return Last modification date
+     */
+    private long getLastModified(Set resourcePaths, Map jarPaths)
+            throws Exception {
+
+        long lastModified = 0;
+
+        Iterator paths = resourcePaths.iterator();
+        while (paths.hasNext()) {
+            String path = (String) paths.next();
+            URL url = context.getServletContext().getResource(path);
+            if (url == null) {
+                log.debug( "Null url "+ path );
+                break;
+            }
+            long lastM = url.openConnection().getLastModified();
+            if (lastM > lastModified) lastModified = lastM;
+            if (log.isDebugEnabled()) {
+                log.debug( "Last modified " + path + " " + lastM);
+            }
+        }
+
+        if (jarPaths != null) {
+            paths = jarPaths.values().iterator();
+            while (paths.hasNext()) {
+                File jarFile = (File) paths.next();
+                long lastM = jarFile.lastModified();
+                if (lastM > lastModified) lastModified = lastM;
+                if (log.isDebugEnabled()) {
+                    log.debug("Last modified " + jarFile.getAbsolutePath()
+                              + " " + lastM);
+                }
+            }
+        }
+
+        return lastModified;
+    }
+
+    private void processCache(File tldCache ) throws IOException {
+        // read the cache and return;
+        try {
+            FileInputStream in=new FileInputStream(tldCache);
+            ObjectInputStream ois=new ObjectInputStream( in );
+            String list[]=(String [])ois.readObject();
+            if( log.isDebugEnabled() )
+                log.debug("Reusing tldCache " + tldCache + " " + list.length);
+            for( int i=0; list!=null && i<list.length; i++ ) {
+                context.addApplicationListener(list[i]);
+            }
+            ois.close();
+        } catch( ClassNotFoundException ex ) {
+            ex.printStackTrace();
+        }
+    }
+
+    /**
+     * Create (if necessary) and return a Digester configured to process a tag
+     * library descriptor, looking for additional listener classes to be
+     * registered.
+     */
+    private static Digester createTldDigester() {
+
+        return DigesterFactory.newDigester(tldValidation, 
+                                           tldNamespaceAware, 
+                                           new TldRuleSet());
+
+    }
+
+
+    /**
+     * Scan the JAR file at the specified resource path for TLDs in the
+     * <code>META-INF</code> subdirectory, and scan each TLD for application
+     * event listeners that need to be registered.
+     *
+     * @param resourcePath Resource path of the JAR file to scan
+     *
+     * @exception Exception if an exception occurs while scanning this JAR
+     */
+    private void tldScanJar(String resourcePath) throws Exception {
+
+        if (log.isDebugEnabled()) {
+            log.debug(" Scanning JAR at resource path '" + resourcePath + "'");
+        }
+
+        URL url = context.getServletContext().getResource(resourcePath);
+        if (url == null) {
+            throw new IllegalArgumentException
+                                (sm.getString("contextConfig.tldResourcePath",
+                                              resourcePath));
+        }
+
+        File file = new File(url.getFile());
+        file = file.getCanonicalFile();
+        tldScanJar(file);
+
+    }
+
+    /**
+     * Scans all TLD entries in the given JAR for application listeners.
+     *
+     * @param file JAR file whose TLD entries are scanned for application
+     * listeners
+     */
+    private void tldScanJar(File file) throws Exception {
+
+        JarFile jarFile = null;
+        String name = null;
+
+        String jarPath = file.getAbsolutePath();
+
+        try {
+            jarFile = new JarFile(file);
+            Enumeration entries = jarFile.entries();
+            while (entries.hasMoreElements()) {
+                JarEntry entry = (JarEntry) entries.nextElement();
+                name = entry.getName();
+                if (!name.startsWith("META-INF/")) {
+                    continue;
+                }
+                if (!name.endsWith(".tld")) {
+                    continue;
+                }
+                if (log.isTraceEnabled()) {
+                    log.trace("  Processing TLD at '" + name + "'");
+                }
+                try {
+                    tldScanStream(new InputSource(jarFile.getInputStream(entry)));
+                } catch (Exception e) {
+                    log.error(sm.getString("contextConfig.tldEntryException",
+                                           name, jarPath, context.getPath()),
+                              e);
+                }
+            }
+        } catch (Exception e) {
+            log.error(sm.getString("contextConfig.tldJarException",
+                                   jarPath, context.getPath()),
+                      e);
+        } finally {
+            if (jarFile != null) {
+                try {
+                    jarFile.close();
+                } catch (Throwable t) {
+                    // Ignore
+                }
+            }
+        }
+    }
+
+    /**
+     * Scan the TLD contents in the specified input stream, and register
+     * any application event listeners found there.  <b>NOTE</b> - It is
+     * the responsibility of the caller to close the InputStream after this
+     * method returns.
+     *
+     * @param resourceStream InputStream containing a tag library descriptor
+     *
+     * @exception Exception if an exception occurs while scanning this TLD
+     */
+    private void tldScanStream(InputSource resourceStream)
+        throws Exception {
+
+        if (tldDigester == null){
+            tldDigester = createTldDigester();
+        }
+        
+        synchronized (tldDigester) {
+            try {
+                tldDigester.push(this);
+                tldDigester.parse(resourceStream);
+            } finally {
+                tldDigester.reset();
+            }
+        }
+
+    }
+
+    /**
+     * Scan the TLD contents at the specified resource path, and register
+     * any application event listeners found there.
+     *
+     * @param resourcePath Resource path being scanned
+     *
+     * @exception Exception if an exception occurs while scanning this TLD
+     */
+    private void tldScanTld(String resourcePath) throws Exception {
+
+        if (log.isDebugEnabled()) {
+            log.debug(" Scanning TLD at resource path '" + resourcePath + "'");
+        }
+
+        InputSource inputSource = null;
+        try {
+            // Bugzilla 38476
+            InputStream stream =
+                context.getServletContext().getResourceAsStream(resourcePath);
+            if (stream == null) {
+                throw new IllegalArgumentException
+                    (sm.getString("contextConfig.tldResourcePath",
+                                  resourcePath));
+            }
+
+            inputSource = new InputSource(stream);
+            if (inputSource == null) {
+                throw new IllegalArgumentException
+                    (sm.getString("contextConfig.tldResourcePath",
+                                  resourcePath));
+            }
+            tldScanStream(inputSource);
+        } catch (Exception e) {
+             throw new ServletException
+                 (sm.getString("contextConfig.tldFileException", resourcePath,
+                               context.getPath()),
+                  e);
+        } 
+
+    }
+
+    /**
+     * Accumulate and return a Set of resource paths to be analyzed for
+     * tag library descriptors.  Each element of the returned set will be
+     * the context-relative path to either a tag library descriptor file,
+     * or to a JAR file that may contain tag library descriptors in its
+     * <code>META-INF</code> subdirectory.
+     *
+     * @exception IOException if an input/output error occurs while
+     *  accumulating the list of resource paths
+     */
+    private Set tldScanResourcePaths() throws IOException {
+        if (log.isDebugEnabled()) {
+            log.debug(" Accumulating TLD resource paths");
+        }
+        Set resourcePaths = new HashSet();
+
+        // Accumulate resource paths explicitly listed in the web application
+        // deployment descriptor
+        if (log.isTraceEnabled()) {
+            log.trace("  Scanning <taglib> elements in web.xml");
+        }
+        String taglibs[] = context.findTaglibs();
+        for (int i = 0; i < taglibs.length; i++) {
+            String resourcePath = context.findTaglib(taglibs[i]);
+            // FIXME - Servlet 2.4 DTD implies that the location MUST be
+            // a context-relative path starting with '/'?
+            if (!resourcePath.startsWith("/")) {
+                resourcePath = "/WEB-INF/" + resourcePath;
+            }
+            if (log.isTraceEnabled()) {
+                log.trace("   Adding path '" + resourcePath +
+                    "' for URI '" + taglibs[i] + "'");
+            }
+            resourcePaths.add(resourcePath);
+        }
+
+        DirContext resources = context.getResources();
+        if (resources != null) {
+            tldScanResourcePathsWebInf(resources, "/WEB-INF", resourcePaths);
+        }
+
+        // Return the completed set
+        return (resourcePaths);
+
+    }
+
+    /*
+     * Scans the web application's subdirectory identified by rootPath,
+     * along with its subdirectories, for TLDs.
+     *
+     * Initially, rootPath equals /WEB-INF. The /WEB-INF/classes and
+     * /WEB-INF/lib subdirectories are excluded from the search, as per the
+     * JSP 2.0 spec.
+     *
+     * @param resources The web application's resources
+     * @param rootPath The path whose subdirectories are to be searched for
+     * TLDs
+     * @param tldPaths The set of TLD resource paths to add to
+     */
+    private void tldScanResourcePathsWebInf(DirContext resources,
+                                            String rootPath,
+                                            Set tldPaths) 
+            throws IOException {
+
+        if (log.isTraceEnabled()) {
+            log.trace("  Scanning TLDs in " + rootPath + " subdirectory");
+        }
+
+        try {
+            NamingEnumeration items = resources.list(rootPath);
+            while (items.hasMoreElements()) {
+                NameClassPair item = (NameClassPair) items.nextElement();
+                String resourcePath = rootPath + "/" + item.getName();
+                if (!resourcePath.endsWith(".tld")
+                        && (resourcePath.startsWith("/WEB-INF/classes")
+                            || resourcePath.startsWith("/WEB-INF/lib"))) {
+                    continue;
+                }
+                if (resourcePath.endsWith(".tld")) {
+                    if (log.isTraceEnabled()) {
+                        log.trace("   Adding path '" + resourcePath + "'");
+                    }
+                    tldPaths.add(resourcePath);
+                } else {
+                    tldScanResourcePathsWebInf(resources, resourcePath,
+                                               tldPaths);
+                }
+            }
+        } catch (NamingException e) {
+            ; // Silent catch: it's valid that no /WEB-INF directory exists
+        }
+    }
+
+    /**
+     * Returns a map of the paths to all JAR files that are accessible to the
+     * webapp and will be scanned for TLDs.
+     *
+     * The map always includes all the JARs under WEB-INF/lib, as well as
+     * shared JARs in the classloader delegation chain of the webapp's
+     * classloader.
+     *
+     * The latter constitutes a Tomcat-specific extension to the TLD search
+     * order defined in the JSP spec. It allows tag libraries packaged as JAR
+     * files to be shared by web applications by simply dropping them in a 
+     * location that all web applications have access to (e.g.,
+     * <CATALINA_HOME>/common/lib).
+     *
+     * The set of shared JARs to be scanned for TLDs is narrowed down by
+     * the <tt>noTldJars</tt> class variable, which contains the names of JARs
+     * that are known not to contain any TLDs.
+     *
+     * @return Map of JAR file paths
+     */
+    private Map getJarPaths() {
+
+        HashMap jarPathMap = null;
+
+        ClassLoader webappLoader = Thread.currentThread().getContextClassLoader();
+        ClassLoader loader = webappLoader;
+        while (loader != null) {
+            if (loader instanceof URLClassLoader) {
+                URL[] urls = ((URLClassLoader) loader).getURLs();
+                for (int i=0; i<urls.length; i++) {
+                    // Expect file URLs
+                    // This is definitely not as clean as using JAR URLs either
+                    // over file or the custom jndi handler, but a lot less
+                    // buggy overall
+                    File file = new File(urls[i].getFile());
+                    try {
+                        file = file.getCanonicalFile();
+                    } catch (IOException e) {
+                        // Ignore
+                    }
+                    if (!file.exists()) {
+                        continue;
+                    }
+                    String path = file.getAbsolutePath();
+                    if (!path.endsWith(".jar")) {
+                        continue;
+                    }
+                    /*
+                     * Scan all JARs from WEB-INF/lib, plus any shared JARs
+                     * that are not known not to contain any TLDs
+                     */
+                    if (loader == webappLoader
+                            || noTldJars == null
+                            || !noTldJars.contains(file.getName())) {
+                        if (jarPathMap == null) {
+                            jarPathMap = new HashMap();
+                            jarPathMap.put(path, file);
+                        } else if (!jarPathMap.containsKey(path)) {
+                            jarPathMap.put(path, file);
+                        }
+                    }
+                }
+            }
+            loader = loader.getParent();
+        }
+
+        return jarPathMap;
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/startup/TldRuleSet.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/startup/TldRuleSet.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/startup/TldRuleSet.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,95 @@
+/*
+ * Copyright 1999-2001,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.startup;
+
+
+import org.apache.tomcat.util.digester.Digester;
+import org.apache.tomcat.util.digester.RuleSetBase;
+
+
+/**
+ * <p><strong>RuleSet</strong> for processing the contents of a tag library
+ * descriptor resource.</p>
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302984 $ $Date: 2004-06-26 12:41:33 -0500 (Sat, 26 Jun 2004) $
+ */
+
+public class TldRuleSet extends RuleSetBase {
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The matching pattern prefix to use for recognizing our elements.
+     */
+    protected String prefix = null;
+
+
+    // ------------------------------------------------------------ Constructor
+
+
+    /**
+     * Construct an instance of this <code>RuleSet</code> with the default
+     * matching pattern prefix.
+     */
+    public TldRuleSet() {
+
+        this("");
+
+    }
+
+
+    /**
+     * Construct an instance of this <code>RuleSet</code> with the specified
+     * matching pattern prefix.
+     *
+     * @param prefix Prefix for matching pattern rules (including the
+     *  trailing slash character)
+     */
+    public TldRuleSet(String prefix) {
+
+        super();
+        this.namespaceURI = null;
+        this.prefix = prefix;
+
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * <p>Add the set of Rule instances defined in this RuleSet to the
+     * specified <code>Digester</code> instance, associating them with
+     * our namespace URI (if any).  This method should only be called
+     * by a Digester instance.</p>
+     *
+     * @param digester Digester instance to which the new Rule instances
+     *  should be added.
+     */
+    public void addRuleInstances(Digester digester) {
+
+        digester.addCallMethod(prefix + "taglib/listener/listener-class",
+                               "addApplicationListener", 0);
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/startup/Tool.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/startup/Tool.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/startup/Tool.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,243 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.startup;
+
+
+import java.io.File;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+
+/**
+ * <p>General purpose wrapper for command line tools that should execute in an
+ * environment with the common class loader environment set up by Catalina.
+ * This should be executed from a command line script that conforms to
+ * the following requirements:</p>
+ * <ul>
+ * <li>Passes the <code>catalina.home</code> system property configured with
+ *     the pathname of the Tomcat installation directory.</li>
+ * <li>Sets the system classpath to include <code>bootstrap.jar</code> and
+ *     <code>$JAVA_HOME/lib/tools.jar</code>.</li>
+ * </ul>
+ *
+ * <p>The command line to execute the tool looks like:</p>
+ * <pre>
+ *   java -classpath $CLASSPATH org.apache.catalina.startup.Tool \
+ *     ${options} ${classname} ${arguments}
+ * </pre>
+ *
+ * <p>with the following replacement contents:
+ * <ul>
+ * <li><strong>${options}</strong> - Command line options for this Tool wrapper.
+ *     The following options are supported:
+ *     <ul>
+ *     <li><em>-ant</em> : Set the <code>ant.home</code> system property
+ *         to corresponding to the value of <code>catalina.home</code>
+ *         (useful when your command line tool runs Ant).</li>
+ *     <li><em>-common</em> : Add <code>common/classes</code> and
+ *         <code>common/lib</codE) to the class loader repositories.</li>
+ *     <li><em>-server</em> : Add <code>server/classes</code> and
+ *         <code>server/lib</code> to the class loader repositories.</li>
+ *     <li><em>-shared</em> : Add <code>shared/classes</code> and
+ *         <code>shared/lib</code> to the class loader repositories.</li>
+ *     </ul>
+ * <li><strong>${classname}</strong> - Fully qualified Java class name of the
+ *     application's main class.</li>
+ * <li><strong>${arguments}</strong> - Command line arguments to be passed to
+ *     the application's <code>main()</code> method.</li>
+ * </ul>
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302983 $ $Date: 2004-06-25 18:56:25 -0500 (Fri, 25 Jun 2004) $
+ */
+
+public final class Tool {
+
+
+    private static Log log = LogFactory.getLog(Tool.class);
+    
+    // ------------------------------------------------------- Static Variables
+
+
+    /**
+     * Set <code>ant.home</code> system property?
+     */
+    private static boolean ant = false;
+
+
+    /**
+     * The pathname of our installation base directory.
+     */
+    private static String catalinaHome = System.getProperty("catalina.home");
+
+
+    /**
+     * Include common classes in the repositories?
+     */
+    private static boolean common = false;
+
+
+    /**
+     * Include server classes in the repositories?
+     */
+    private static boolean server = false;
+
+
+    /**
+     * Include shared classes in the repositories?
+     */
+    private static boolean shared = false;
+
+
+    // ----------------------------------------------------------- Main Program
+
+
+    /**
+     * The main program for the bootstrap.
+     *
+     * @param args Command line arguments to be processed
+     */
+    public static void main(String args[]) {
+
+        // Verify that "catalina.home" was passed.
+        if (catalinaHome == null) {
+            log.error("Must set 'catalina.home' system property");
+            System.exit(1);
+        }
+
+        // Process command line options
+        int index = 0;
+        while (true) {
+            if (index == args.length) {
+                usage();
+                System.exit(1);
+            }
+            if ("-ant".equals(args[index]))
+                ant = true;
+            else if ("-common".equals(args[index]))
+                common = true;
+            else if ("-server".equals(args[index]))
+                server = true;
+            else if ("-shared".equals(args[index]))
+                shared = true;
+            else
+                break;
+            index++;
+        }
+        if (index > args.length) {
+            usage();
+            System.exit(1);
+        }
+
+        // Set "ant.home" if requested
+        if (ant)
+            System.setProperty("ant.home", catalinaHome);
+
+        // Construct the class loader we will be using
+        ClassLoader classLoader = null;
+        try {
+            ArrayList packed = new ArrayList();
+            ArrayList unpacked = new ArrayList();
+            unpacked.add(new File(catalinaHome, "classes"));
+            packed.add(new File(catalinaHome, "lib"));
+            if (common) {
+                unpacked.add(new File(catalinaHome,
+                                      "common" + File.separator + "classes"));
+                packed.add(new File(catalinaHome,
+                                    "common" + File.separator + "lib"));
+            }
+            if (server) {
+                unpacked.add(new File(catalinaHome,
+                                      "server" + File.separator + "classes"));
+                packed.add(new File(catalinaHome,
+                                    "server" + File.separator + "lib"));
+            }
+            if (shared) {
+                unpacked.add(new File(catalinaHome,
+                                      "shared" + File.separator + "classes"));
+                packed.add(new File(catalinaHome,
+                                    "shared" + File.separator + "lib"));
+            }
+            classLoader =
+                ClassLoaderFactory.createClassLoader
+                ((File[]) unpacked.toArray(new File[0]),
+                 (File[]) packed.toArray(new File[0]),
+                 null);
+        } catch (Throwable t) {
+            log.error("Class loader creation threw exception", t);
+            System.exit(1);
+        }
+        Thread.currentThread().setContextClassLoader(classLoader);
+
+        // Load our application class
+        Class clazz = null;
+        String className = args[index++];
+        try {
+            if (log.isDebugEnabled())
+                log.debug("Loading application class " + className);
+            clazz = classLoader.loadClass(className);
+        } catch (Throwable t) {
+            log.error("Exception creating instance of " + className, t);
+            System.exit(1);
+        }
+
+        // Locate the static main() method of the application class
+        Method method = null;
+        String params[] = new String[args.length - index];
+        System.arraycopy(args, index, params, 0, params.length);
+        try {
+            if (log.isDebugEnabled())
+                log.debug("Identifying main() method");
+            String methodName = "main";
+            Class paramTypes[] = new Class[1];
+            paramTypes[0] = params.getClass();
+            method = clazz.getMethod(methodName, paramTypes);
+        } catch (Throwable t) {
+            log.error("Exception locating main() method", t);
+            System.exit(1);
+        }
+
+        // Invoke the main method of the application class
+        try {
+            if (log.isDebugEnabled())
+                log.debug("Calling main() method");
+            Object paramValues[] = new Object[1];
+            paramValues[0] = params;
+            method.invoke(null, paramValues);
+        } catch (Throwable t) {
+            log.error("Exception calling main() method", t);
+            System.exit(1);
+        }
+
+    }
+
+
+    /**
+     * Display usage information about this tool.
+     */
+    private static void usage() {
+
+        log.info("Usage:  java org.apache.catalina.startup.Tool [<options>] <class> [<arguments>]");
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/startup/UserConfig.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/startup/UserConfig.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/startup/UserConfig.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,338 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.startup;
+
+
+import java.io.File;
+import java.util.Enumeration;
+
+import org.apache.catalina.Context;
+import org.apache.catalina.Host;
+import org.apache.catalina.Lifecycle;
+import org.apache.catalina.LifecycleEvent;
+import org.apache.catalina.LifecycleListener;
+import org.apache.catalina.util.StringManager;
+
+
+/**
+ * Startup event listener for a <b>Host</b> that configures Contexts (web
+ * applications) for all defined "users" who have a web application in a
+ * directory with the specified name in their home directories.  The context
+ * path of each deployed application will be set to <code>~xxxxx</code>, where
+ * xxxxx is the username of the owning user for that web application
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302976 $ $Date: 2004-06-23 08:51:38 -0500 (Wed, 23 Jun 2004) $
+ */
+
+public final class UserConfig
+    implements LifecycleListener {
+
+
+    private static org.apache.commons.logging.Log log=
+        org.apache.commons.logging.LogFactory.getLog( UserConfig.class );
+
+    
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The Java class name of the Context configuration class we should use.
+     */
+    private String configClass = "org.apache.catalina.startup.ContextConfig";
+
+
+    /**
+     * The Java class name of the Context implementation we should use.
+     */
+    private String contextClass = "org.apache.catalina.core.StandardContext";
+
+
+    /**
+     * The directory name to be searched for within each user home directory.
+     */
+    private String directoryName = "public_html";
+
+
+    /**
+     * The base directory containing user home directories.
+     */
+    private String homeBase = null;
+
+
+    /**
+     * The Host we are associated with.
+     */
+    private Host host = null;
+
+
+    /**
+     * The string resources for this package.
+     */
+    private static final StringManager sm =
+        StringManager.getManager(Constants.Package);
+
+
+    /**
+     * The Java class name of the user database class we should use.
+     */
+    private String userClass =
+        "org.apache.catalina.startup.PasswdUserDatabase";
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * Return the Context configuration class name.
+     */
+    public String getConfigClass() {
+
+        return (this.configClass);
+
+    }
+
+
+    /**
+     * Set the Context configuration class name.
+     *
+     * @param configClass The new Context configuration class name.
+     */
+    public void setConfigClass(String configClass) {
+
+        this.configClass = configClass;
+
+    }
+
+
+    /**
+     * Return the Context implementation class name.
+     */
+    public String getContextClass() {
+
+        return (this.contextClass);
+
+    }
+
+
+    /**
+     * Set the Context implementation class name.
+     *
+     * @param contextClass The new Context implementation class name.
+     */
+    public void setContextClass(String contextClass) {
+
+        this.contextClass = contextClass;
+
+    }
+
+
+    /**
+     * Return the directory name for user web applications.
+     */
+    public String getDirectoryName() {
+
+        return (this.directoryName);
+
+    }
+
+
+    /**
+     * Set the directory name for user web applications.
+     *
+     * @param directoryName The new directory name
+     */
+    public void setDirectoryName(String directoryName) {
+
+        this.directoryName = directoryName;
+
+    }
+
+
+    /**
+     * Return the base directory containing user home directories.
+     */
+    public String getHomeBase() {
+
+        return (this.homeBase);
+
+    }
+
+
+    /**
+     * Set the base directory containing user home directories.
+     *
+     * @param homeBase The new base directory
+     */
+    public void setHomeBase(String homeBase) {
+
+        this.homeBase = homeBase;
+
+    }
+
+
+    /**
+     * Return the user database class name for this component.
+     */
+    public String getUserClass() {
+
+        return (this.userClass);
+
+    }
+
+
+    /**
+     * Set the user database class name for this component.
+     */
+    public void setUserClass(String userClass) {
+
+        this.userClass = userClass;
+
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Process the START event for an associated Host.
+     *
+     * @param event The lifecycle event that has occurred
+     */
+    public void lifecycleEvent(LifecycleEvent event) {
+
+        // Identify the host we are associated with
+        try {
+            host = (Host) event.getLifecycle();
+        } catch (ClassCastException e) {
+            log.error(sm.getString("hostConfig.cce", event.getLifecycle()), e);
+            return;
+        }
+
+        // Process the event that has occurred
+        if (event.getType().equals(Lifecycle.START_EVENT))
+            start();
+        else if (event.getType().equals(Lifecycle.STOP_EVENT))
+            stop();
+
+    }
+
+
+    // -------------------------------------------------------- Private Methods
+
+
+    /**
+     * Deploy a web application for any user who has a web application present
+     * in a directory with a specified name within their home directory.
+     */
+    private void deploy() {
+
+        if (host.getLogger().isDebugEnabled())
+            host.getLogger().debug(sm.getString("userConfig.deploying"));
+
+        // Load the user database object for this host
+        UserDatabase database = null;
+        try {
+            Class clazz = Class.forName(userClass);
+            database = (UserDatabase) clazz.newInstance();
+            database.setUserConfig(this);
+        } catch (Exception e) {
+            host.getLogger().error(sm.getString("userConfig.database"), e);
+            return;
+        }
+
+        // Deploy the web application (if any) for each defined user
+        Enumeration users = database.getUsers();
+        while (users.hasMoreElements()) {
+            String user = (String) users.nextElement();
+            String home = database.getHome(user);
+            deploy(user, home);
+        }
+
+    }
+
+
+    /**
+     * Deploy a web application for the specified user if they have such an
+     * application in the defined directory within their home directory.
+     *
+     * @param user Username owning the application to be deployed
+     * @param home Home directory of this user
+     */
+    private void deploy(String user, String home) {
+
+        // Does this user have a web application to be deployed?
+        String contextPath = "/~" + user;
+        if (host.findChild(contextPath) != null)
+            return;
+        File app = new File(home, directoryName);
+        if (!app.exists() || !app.isDirectory())
+            return;
+        /*
+        File dd = new File(app, "/WEB-INF/web.xml");
+        if (!dd.exists() || !dd.isFile() || !dd.canRead())
+            return;
+        */
+        host.getLogger().info(sm.getString("userConfig.deploy", user));
+
+        // Deploy the web application for this user
+        try {
+            Class clazz = Class.forName(contextClass);
+            Context context =
+              (Context) clazz.newInstance();
+            context.setPath(contextPath);
+            context.setDocBase(app.toString());
+            if (context instanceof Lifecycle) {
+                clazz = Class.forName(configClass);
+                LifecycleListener listener =
+                  (LifecycleListener) clazz.newInstance();
+                ((Lifecycle) context).addLifecycleListener(listener);
+            }
+            host.addChild(context);
+        } catch (Exception e) {
+            host.getLogger().error(sm.getString("userConfig.error", user), e);
+        }
+
+    }
+
+
+    /**
+     * Process a "start" event for this Host.
+     */
+    private void start() {
+
+        if (host.getLogger().isDebugEnabled())
+            host.getLogger().debug(sm.getString("userConfig.start"));
+
+        deploy();
+
+    }
+
+
+    /**
+     * Process a "stop" event for this Host.
+     */
+    private void stop() {
+
+        if (host.getLogger().isDebugEnabled())
+            host.getLogger().debug(sm.getString("userConfig.stop"));
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/startup/UserDatabase.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/startup/UserDatabase.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/startup/UserDatabase.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,69 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.startup;
+
+
+import java.util.Enumeration;
+
+
+/**
+ * Abstraction of the set of users defined by the operating system on the
+ * current server platform.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public interface UserDatabase {
+
+
+    // ----------------------------------------------------------- Properties
+
+
+    /**
+     * Return the UserConfig listener with which we are associated.
+     */
+    public UserConfig getUserConfig();
+
+
+    /**
+     * Set the UserConfig listener with which we are associated.
+     *
+     * @param userConfig The new UserConfig listener
+     */
+    public void setUserConfig(UserConfig userConfig);
+
+
+    // ------------------------------------------------------- Public Methods
+
+
+    /**
+     * Return an absolute pathname to the home directory for the specified user.
+     *
+     * @param user User for which a home directory should be retrieved
+     */
+    public String getHome(String user);
+
+
+    /**
+     * Return an enumeration of the usernames defined on this server.
+     */
+    public Enumeration getUsers();
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/startup/WebRuleSet.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/startup/WebRuleSet.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/startup/WebRuleSet.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,616 @@
+/*
+ * Copyright 1999-2001,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.startup;
+
+
+import java.lang.reflect.Method;
+import org.apache.catalina.Context;
+import org.apache.catalina.Wrapper;
+import org.apache.catalina.deploy.SecurityConstraint;
+import org.apache.tomcat.util.digester.Digester;
+import org.apache.tomcat.util.digester.Rule;
+import org.apache.tomcat.util.digester.RuleSetBase;
+import org.xml.sax.Attributes;
+
+
+/**
+ * <p><strong>RuleSet</strong> for processing the contents of a web application
+ * deployment descriptor (<code>/WEB-INF/web.xml</code>) resource.</p>
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 304108 $ $Date: 2005-09-29 00:55:15 -0500 (Thu, 29 Sep 2005) $
+ */
+
+public class WebRuleSet extends RuleSetBase {
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The matching pattern prefix to use for recognizing our elements.
+     */
+    protected String prefix = null;
+    
+    
+    /**
+     * The <code>SetSessionConfig</code> rule used to parse the web.xml
+     */
+    protected SetSessionConfig sessionConfig;
+    
+    
+    /**
+     * The <code>SetLoginConfig</code> rule used to parse the web.xml
+     */
+    protected SetLoginConfig loginConfig;
+
+    
+    /**
+     * The <code>SetJspConfig</code> rule used to parse the web.xml
+     */    
+    protected SetJspConfig jspConfig;
+
+
+    // ------------------------------------------------------------ Constructor
+
+
+    /**
+     * Construct an instance of this <code>RuleSet</code> with the default
+     * matching pattern prefix.
+     */
+    public WebRuleSet() {
+
+        this("");
+
+    }
+
+
+    /**
+     * Construct an instance of this <code>RuleSet</code> with the specified
+     * matching pattern prefix.
+     *
+     * @param prefix Prefix for matching pattern rules (including the
+     *  trailing slash character)
+     */
+    public WebRuleSet(String prefix) {
+
+        super();
+        this.namespaceURI = null;
+        this.prefix = prefix;
+
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * <p>Add the set of Rule instances defined in this RuleSet to the
+     * specified <code>Digester</code> instance, associating them with
+     * our namespace URI (if any).  This method should only be called
+     * by a Digester instance.</p>
+     *
+     * @param digester Digester instance to which the new Rule instances
+     *  should be added.
+     */
+    public void addRuleInstances(Digester digester) {
+        sessionConfig = new SetSessionConfig();
+        jspConfig = new SetJspConfig();
+        loginConfig = new SetLoginConfig();
+        
+        digester.addRule(prefix + "web-app",
+                         new SetPublicIdRule("setPublicId"));
+
+        digester.addCallMethod(prefix + "web-app/context-param",
+                               "addParameter", 2);
+        digester.addCallParam(prefix + "web-app/context-param/param-name", 0);
+        digester.addCallParam(prefix + "web-app/context-param/param-value", 1);
+
+        digester.addCallMethod(prefix + "web-app/display-name",
+                               "setDisplayName", 0);
+
+        digester.addRule(prefix + "web-app/distributable",
+                         new SetDistributableRule());
+
+        digester.addObjectCreate(prefix + "web-app/ejb-local-ref",
+                                 "org.apache.catalina.deploy.ContextLocalEjb");
+        digester.addRule(prefix + "web-app/ejb-local-ref",
+                new SetNextNamingRule("addLocalEjb",
+                            "org.apache.catalina.deploy.ContextLocalEjb"));
+
+        digester.addCallMethod(prefix + "web-app/ejb-local-ref/description",
+                               "setDescription", 0);
+        digester.addCallMethod(prefix + "web-app/ejb-local-ref/ejb-link",
+                               "setLink", 0);
+        digester.addCallMethod(prefix + "web-app/ejb-local-ref/ejb-ref-name",
+                               "setName", 0);
+        digester.addCallMethod(prefix + "web-app/ejb-local-ref/ejb-ref-type",
+                               "setType", 0);
+        digester.addCallMethod(prefix + "web-app/ejb-local-ref/local",
+                               "setLocal", 0);
+        digester.addCallMethod(prefix + "web-app/ejb-local-ref/local-home",
+                               "setHome", 0);
+
+        digester.addObjectCreate(prefix + "web-app/ejb-ref",
+                                 "org.apache.catalina.deploy.ContextEjb");
+        digester.addRule(prefix + "web-app/ejb-ref",
+                new SetNextNamingRule("addEjb",
+                            "org.apache.catalina.deploy.ContextEjb"));
+
+        digester.addCallMethod(prefix + "web-app/ejb-ref/description",
+                               "setDescription", 0);
+        digester.addCallMethod(prefix + "web-app/ejb-ref/ejb-link",
+                               "setLink", 0);
+        digester.addCallMethod(prefix + "web-app/ejb-ref/ejb-ref-name",
+                               "setName", 0);
+        digester.addCallMethod(prefix + "web-app/ejb-ref/ejb-ref-type",
+                               "setType", 0);
+        digester.addCallMethod(prefix + "web-app/ejb-ref/home",
+                               "setHome", 0);
+        digester.addCallMethod(prefix + "web-app/ejb-ref/remote",
+                               "setRemote", 0);
+
+        digester.addObjectCreate(prefix + "web-app/env-entry",
+                                 "org.apache.catalina.deploy.ContextEnvironment");
+        digester.addRule(prefix + "web-app/env-entry",
+                new SetNextNamingRule("addEnvironment",
+                            "org.apache.catalina.deploy.ContextEnvironment"));
+
+        digester.addCallMethod(prefix + "web-app/env-entry/description",
+                               "setDescription", 0);
+        digester.addCallMethod(prefix + "web-app/env-entry/env-entry-name",
+                               "setName", 0);
+        digester.addCallMethod(prefix + "web-app/env-entry/env-entry-type",
+                               "setType", 0);
+        digester.addCallMethod(prefix + "web-app/env-entry/env-entry-value",
+                               "setValue", 0);
+
+        digester.addObjectCreate(prefix + "web-app/error-page",
+                                 "org.apache.catalina.deploy.ErrorPage");
+        digester.addSetNext(prefix + "web-app/error-page",
+                            "addErrorPage",
+                            "org.apache.catalina.deploy.ErrorPage");
+
+        digester.addCallMethod(prefix + "web-app/error-page/error-code",
+                               "setErrorCode", 0);
+        digester.addCallMethod(prefix + "web-app/error-page/exception-type",
+                               "setExceptionType", 0);
+        digester.addCallMethod(prefix + "web-app/error-page/location",
+                               "setLocation", 0);
+
+        digester.addObjectCreate(prefix + "web-app/filter",
+                                 "org.apache.catalina.deploy.FilterDef");
+        digester.addSetNext(prefix + "web-app/filter",
+                            "addFilterDef",
+                            "org.apache.catalina.deploy.FilterDef");
+
+        digester.addCallMethod(prefix + "web-app/filter/description",
+                               "setDescription", 0);
+        digester.addCallMethod(prefix + "web-app/filter/display-name",
+                               "setDisplayName", 0);
+        digester.addCallMethod(prefix + "web-app/filter/filter-class",
+                               "setFilterClass", 0);
+        digester.addCallMethod(prefix + "web-app/filter/filter-name",
+                               "setFilterName", 0);
+        digester.addCallMethod(prefix + "web-app/filter/large-icon",
+                               "setLargeIcon", 0);
+        digester.addCallMethod(prefix + "web-app/filter/small-icon",
+                               "setSmallIcon", 0);
+
+        digester.addCallMethod(prefix + "web-app/filter/init-param",
+                               "addInitParameter", 2);
+        digester.addCallParam(prefix + "web-app/filter/init-param/param-name",
+                              0);
+        digester.addCallParam(prefix + "web-app/filter/init-param/param-value",
+                              1);
+
+        digester.addObjectCreate(prefix + "web-app/filter-mapping",
+                                 "org.apache.catalina.deploy.FilterMap");
+        digester.addSetNext(prefix + "web-app/filter-mapping",
+                            "addFilterMap",
+                            "org.apache.catalina.deploy.FilterMap");
+
+        digester.addCallMethod(prefix + "web-app/filter-mapping/filter-name",
+                               "setFilterName", 0);
+        digester.addCallMethod(prefix + "web-app/filter-mapping/servlet-name",
+                               "setServletName", 0);
+        digester.addCallMethod(prefix + "web-app/filter-mapping/url-pattern",
+                               "setURLPattern", 0);
+
+        digester.addCallMethod(prefix + "web-app/filter-mapping/dispatcher",
+                               "setDispatcher", 0);
+
+         digester.addCallMethod(prefix + "web-app/listener/listener-class",
+                                "addApplicationListener", 0);
+         
+        digester.addRule(prefix + "web-app/jsp-config",
+                         jspConfig);
+        
+        digester.addCallMethod(prefix + "web-app/jsp-config/jsp-property-group/url-pattern",
+                               "addJspMapping", 0);
+
+        digester.addCallMethod(prefix + "web-app/listener/listener-class",
+                               "addApplicationListener", 0);
+        
+        digester.addRule(prefix + "web-app/login-config",
+                         loginConfig);
+
+        digester.addObjectCreate(prefix + "web-app/login-config",
+                                 "org.apache.catalina.deploy.LoginConfig");
+        digester.addSetNext(prefix + "web-app/login-config",
+                            "setLoginConfig",
+                            "org.apache.catalina.deploy.LoginConfig");
+
+        digester.addCallMethod(prefix + "web-app/login-config/auth-method",
+                               "setAuthMethod", 0);
+        digester.addCallMethod(prefix + "web-app/login-config/realm-name",
+                               "setRealmName", 0);
+        digester.addCallMethod(prefix + "web-app/login-config/form-login-config/form-error-page",
+                               "setErrorPage", 0);
+        digester.addCallMethod(prefix + "web-app/login-config/form-login-config/form-login-page",
+                               "setLoginPage", 0);
+
+        digester.addCallMethod(prefix + "web-app/mime-mapping",
+                               "addMimeMapping", 2);
+        digester.addCallParam(prefix + "web-app/mime-mapping/extension", 0);
+        digester.addCallParam(prefix + "web-app/mime-mapping/mime-type", 1);
+
+        digester.addObjectCreate(prefix + "web-app/resource-env-ref",
+            "org.apache.catalina.deploy.ContextResourceEnvRef");
+        digester.addRule(prefix + "web-app/resource-env-ref",
+                    new SetNextNamingRule("addResourceEnvRef",
+                        "org.apache.catalina.deploy.ContextResourceEnvRef"));
+
+        digester.addCallMethod(prefix + "web-app/resource-env-ref/resource-env-ref-name",
+                "setName", 0);
+        digester.addCallMethod(prefix + "web-app/resource-env-ref/resource-env-ref-type",
+                "setType", 0);
+
+        digester.addObjectCreate(prefix + "web-app/message-destination",
+                                 "org.apache.catalina.deploy.MessageDestination");
+        digester.addSetNext(prefix + "web-app/message-destination",
+                            "addMessageDestination",
+                            "org.apache.catalina.deploy.MessageDestination");
+
+        digester.addCallMethod(prefix + "web-app/message-destination/description",
+                               "setDescription", 0);
+        digester.addCallMethod(prefix + "web-app/message-destination/display-name",
+                               "setDisplayName", 0);
+        digester.addCallMethod(prefix + "web-app/message-destination/icon/large-icon",
+                               "setLargeIcon", 0);
+        digester.addCallMethod(prefix + "web-app/message-destination/icon/small-icon",
+                               "setSmallIcon", 0);
+        digester.addCallMethod(prefix + "web-app/message-destination/message-destination-name",
+                               "setName", 0);
+
+        digester.addObjectCreate(prefix + "web-app/message-destination-ref",
+                                 "org.apache.catalina.deploy.MessageDestinationRef");
+        digester.addSetNext(prefix + "web-app/message-destination-ref",
+                            "addMessageDestinationRef",
+                            "org.apache.catalina.deploy.MessageDestinationRef");
+
+        digester.addCallMethod(prefix + "web-app/message-destination-ref/description",
+                               "setDescription", 0);
+        digester.addCallMethod(prefix + "web-app/message-destination-ref/message-destination-link",
+                               "setLink", 0);
+        digester.addCallMethod(prefix + "web-app/message-destination-ref/message-destination-ref-name",
+                               "setName", 0);
+        digester.addCallMethod(prefix + "web-app/message-destination-ref/message-destination-type",
+                               "setType", 0);
+        digester.addCallMethod(prefix + "web-app/message-destination-ref/message-destination-usage",
+                               "setUsage", 0);
+
+        digester.addObjectCreate(prefix + "web-app/resource-ref",
+                                 "org.apache.catalina.deploy.ContextResource");
+        digester.addRule(prefix + "web-app/resource-ref",
+                new SetNextNamingRule("addResource",
+                            "org.apache.catalina.deploy.ContextResource"));
+
+        digester.addCallMethod(prefix + "web-app/resource-ref/description",
+                               "setDescription", 0);
+        digester.addCallMethod(prefix + "web-app/resource-ref/res-auth",
+                               "setAuth", 0);
+        digester.addCallMethod(prefix + "web-app/resource-ref/res-ref-name",
+                               "setName", 0);
+        digester.addCallMethod(prefix + "web-app/resource-ref/res-sharing-scope",
+                               "setScope", 0);
+        digester.addCallMethod(prefix + "web-app/resource-ref/res-type",
+                               "setType", 0);
+
+        digester.addObjectCreate(prefix + "web-app/security-constraint",
+                                 "org.apache.catalina.deploy.SecurityConstraint");
+        digester.addSetNext(prefix + "web-app/security-constraint",
+                            "addConstraint",
+                            "org.apache.catalina.deploy.SecurityConstraint");
+
+        digester.addRule(prefix + "web-app/security-constraint/auth-constraint",
+                         new SetAuthConstraintRule());
+        digester.addCallMethod(prefix + "web-app/security-constraint/auth-constraint/role-name",
+                               "addAuthRole", 0);
+        digester.addCallMethod(prefix + "web-app/security-constraint/display-name",
+                               "setDisplayName", 0);
+        digester.addCallMethod(prefix + "web-app/security-constraint/user-data-constraint/transport-guarantee",
+                               "setUserConstraint", 0);
+
+        digester.addObjectCreate(prefix + "web-app/security-constraint/web-resource-collection",
+                                 "org.apache.catalina.deploy.SecurityCollection");
+        digester.addSetNext(prefix + "web-app/security-constraint/web-resource-collection",
+                            "addCollection",
+                            "org.apache.catalina.deploy.SecurityCollection");
+        digester.addCallMethod(prefix + "web-app/security-constraint/web-resource-collection/http-method",
+                               "addMethod", 0);
+        digester.addCallMethod(prefix + "web-app/security-constraint/web-resource-collection/url-pattern",
+                               "addPattern", 0);
+        digester.addCallMethod(prefix + "web-app/security-constraint/web-resource-collection/web-resource-name",
+                               "setName", 0);
+
+        digester.addCallMethod(prefix + "web-app/security-role/role-name",
+                               "addSecurityRole", 0);
+
+        digester.addRule(prefix + "web-app/servlet",
+                         new WrapperCreateRule());
+        digester.addSetNext(prefix + "web-app/servlet",
+                            "addChild",
+                            "org.apache.catalina.Container");
+
+        digester.addCallMethod(prefix + "web-app/servlet/init-param",
+                               "addInitParameter", 2);
+        digester.addCallParam(prefix + "web-app/servlet/init-param/param-name",
+                              0);
+        digester.addCallParam(prefix + "web-app/servlet/init-param/param-value",
+                              1);
+
+        digester.addCallMethod(prefix + "web-app/servlet/jsp-file",
+                               "setJspFile", 0);
+        digester.addCallMethod(prefix + "web-app/servlet/load-on-startup",
+                               "setLoadOnStartupString", 0);
+        digester.addCallMethod(prefix + "web-app/servlet/run-as/role-name",
+                               "setRunAs", 0);
+
+        digester.addCallMethod(prefix + "web-app/servlet/security-role-ref",
+                               "addSecurityReference", 2);
+        digester.addCallParam(prefix + "web-app/servlet/security-role-ref/role-link", 1);
+        digester.addCallParam(prefix + "web-app/servlet/security-role-ref/role-name", 0);
+
+        digester.addCallMethod(prefix + "web-app/servlet/servlet-class",
+                              "setServletClass", 0);
+        digester.addCallMethod(prefix + "web-app/servlet/servlet-name",
+                              "setName", 0);
+
+        digester.addCallMethod(prefix + "web-app/servlet-mapping",
+                               "addServletMapping", 2);
+        digester.addCallParam(prefix + "web-app/servlet-mapping/servlet-name", 1);
+        digester.addCallParam(prefix + "web-app/servlet-mapping/url-pattern", 0);
+
+        digester.addRule(prefix + "web-app/session-config",
+                         sessionConfig);
+        
+        digester.addCallMethod(prefix + "web-app/session-config/session-timeout",
+                               "setSessionTimeout", 1,
+                               new Class[] { Integer.TYPE });
+        digester.addCallParam(prefix + "web-app/session-config/session-timeout", 0);
+
+        digester.addCallMethod(prefix + "web-app/taglib",
+                               "addTaglib", 2);
+        digester.addCallParam(prefix + "web-app/taglib/taglib-location", 1);
+        digester.addCallParam(prefix + "web-app/taglib/taglib-uri", 0);
+
+        digester.addCallMethod(prefix + "web-app/welcome-file-list/welcome-file",
+                               "addWelcomeFile", 0);
+
+        digester.addCallMethod(prefix + "web-app/locale-encoding-mapping-list/locale-encoding-mapping",
+                              "addLocaleEncodingMappingParameter", 2);
+        digester.addCallParam(prefix + "web-app/locale-encoding-mapping-list/locale-encoding-mapping/locale", 0);
+        digester.addCallParam(prefix + "web-app/locale-encoding-mapping-list/locale-encoding-mapping/encoding", 1);
+
+    }
+
+    /**
+     * Reset counter used for validating the web.xml file.
+     */
+    public void recycle(){
+        jspConfig.isJspConfigSet = false;
+        sessionConfig.isSessionConfigSet = false;
+        loginConfig.isLoginConfigSet = false;
+    }
+}
+
+
+// ----------------------------------------------------------- Private Classes
+
+
+/**
+ * Rule to check that the <code>login-config</code> is occuring 
+ * only 1 time within the web.xml
+ */
+final class SetLoginConfig extends Rule {
+    protected boolean isLoginConfigSet = false;
+    public SetLoginConfig() {
+    }
+
+    public void begin(String namespace, String name, Attributes attributes)
+        throws Exception {
+        if (isLoginConfigSet){
+            throw new IllegalArgumentException(
+            "<login-config> element is limited to 1 occurance");
+        }
+        isLoginConfigSet = true;
+    }
+
+}
+
+
+/**
+ * Rule to check that the <code>jsp-config</code> is occuring 
+ * only 1 time within the web.xml
+ */
+final class SetJspConfig extends Rule {
+    protected boolean isJspConfigSet = false;
+    public SetJspConfig() {
+    }
+
+    public void begin(String namespace, String name, Attributes attributes)
+        throws Exception {
+        if (isJspConfigSet){
+            throw new IllegalArgumentException(
+            "<jsp-config> element is limited to 1 occurance");
+        }
+        isJspConfigSet = true;
+    }
+
+}
+
+
+/**
+ * Rule to check that the <code>session-config</code> is occuring 
+ * only 1 time within the web.xml
+ */
+final class SetSessionConfig extends Rule {
+    protected boolean isSessionConfigSet = false;
+    public SetSessionConfig() {
+    }
+
+    public void begin(String namespace, String name, Attributes attributes)
+        throws Exception {
+        if (isSessionConfigSet){
+            throw new IllegalArgumentException(
+            "<session-config> element is limited to 1 occurance");
+        }
+        isSessionConfigSet = true;
+    }
+
+}
+
+/**
+ * A Rule that calls the <code>setAuthConstraint(true)</code> method of
+ * the top item on the stack, which must be of type
+ * <code>org.apache.catalina.deploy.SecurityConstraint</code>.
+ */
+
+final class SetAuthConstraintRule extends Rule {
+
+    public SetAuthConstraintRule() {
+    }
+
+    public void begin(String namespace, String name, Attributes attributes)
+        throws Exception {
+        SecurityConstraint securityConstraint =
+            (SecurityConstraint) digester.peek();
+        securityConstraint.setAuthConstraint(true);
+        if (digester.getLogger().isDebugEnabled()) {
+            digester.getLogger()
+               .debug("Calling SecurityConstraint.setAuthConstraint(true)");
+        }
+    }
+
+}
+
+
+/**
+ * Class that calls <code>setDistributable(true)</code> for the top object
+ * on the stack, which must be a <code>org.apache.catalina.Context</code>.
+ */
+
+final class SetDistributableRule extends Rule {
+
+    public SetDistributableRule() {
+    }
+
+    public void begin(String namespace, String name, Attributes attributes)
+        throws Exception {
+        Context context = (Context) digester.peek();
+        context.setDistributable(true);
+        if (digester.getLogger().isDebugEnabled()) {
+            digester.getLogger().debug
+               (context.getClass().getName() + ".setDistributable( true)");
+        }
+    }
+
+}
+
+
+/**
+ * Class that calls a property setter for the top object on the stack,
+ * passing the public ID of the entity we are currently processing.
+ */
+
+final class SetPublicIdRule extends Rule {
+
+    public SetPublicIdRule(String method) {
+        this.method = method;
+    }
+
+    private String method = null;
+
+    public void begin(String namespace, String name, Attributes attributes)
+        throws Exception {
+
+        Context context = (Context) digester.peek(digester.getCount() - 1);
+        Object top = digester.peek();
+        Class paramClasses[] = new Class[1];
+        paramClasses[0] = "String".getClass();
+        String paramValues[] = new String[1];
+        paramValues[0] = digester.getPublicId();
+
+        Method m = null;
+        try {
+            m = top.getClass().getMethod(method, paramClasses);
+        } catch (NoSuchMethodException e) {
+            digester.getLogger().error("Can't find method " + method + " in "
+                                       + top + " CLASS " + top.getClass());
+            return;
+        }
+
+        m.invoke(top, (Object [])paramValues);
+        if (digester.getLogger().isDebugEnabled())
+            digester.getLogger().debug("" + top.getClass().getName() + "." 
+                                       + method + "(" + paramValues[0] + ")");
+
+    }
+
+}
+
+
+/**
+ * A Rule that calls the factory method on the specified Context to
+ * create the object that is to be added to the stack.
+ */
+
+final class WrapperCreateRule extends Rule {
+
+    public WrapperCreateRule() {
+    }
+
+    public void begin(String namespace, String name, Attributes attributes)
+        throws Exception {
+        Context context =
+            (Context) digester.peek(digester.getCount() - 1);
+        Wrapper wrapper = context.createWrapper();
+        digester.push(wrapper);
+        if (digester.getLogger().isDebugEnabled())
+            digester.getLogger().debug("new " + wrapper.getClass().getName());
+    }
+
+    public void end(String namespace, String name)
+        throws Exception {
+        Wrapper wrapper = (Wrapper) digester.pop();
+        if (digester.getLogger().isDebugEnabled())
+            digester.getLogger().debug("pop " + wrapper.getClass().getName());
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/startup/catalina.properties
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/startup/catalina.properties	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/startup/catalina.properties	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,66 @@
+#
+# List of comma-separated packages that start with or equal this string
+# will cause a security exception to be thrown when
+# passed to checkPackageAccess unless the
+# corresponding RuntimePermission ("accessClassInPackage."+package) has
+# been granted.
+package.access=sun.,org.apache.catalina.,org.apache.coyote.,org.apache.tomcat.,org.apache.jasper.,sun.beans.
+#
+# List of comma-separated packages that start with or equal this string
+# will cause a security exception to be thrown when
+# passed to checkPackageDefinition unless the
+# corresponding RuntimePermission ("defineClassInPackage."+package) has
+# been granted.
+#
+# by default, no packages are restricted for definition, and none of
+# the class loaders supplied with the JDK call checkPackageDefinition.
+#
+package.definition=sun.,java.,org.apache.catalina.,org.apache.coyote.,org.apache.tomcat.,org.apache.jasper.
+
+#
+#
+# List of comma-separated paths defining the contents of the "common" 
+# classloader. Prefixes should be used to define what is the repository type.
+# Path may be relative to the CATALINA_HOME or CATALINA_BASE path or absolute.
+# If left as blank,the JVM system loader will be used as Catalina's "common" 
+# loader.
+# Examples:
+#     "foo": Add this folder as a class repository
+#     "foo/*.jar": Add all the JARs of the specified folder as class 
+#                  repositories
+#     "foo/bar.jar": Add bar.jar as a class repository
+common.loader=${catalina.home}/common/classes,${catalina.home}/common/i18n/*.jar,${catalina.home}/common/endorsed/*.jar,${catalina.home}/common/lib/*.jar
+
+#
+# List of comma-separated paths defining the contents of the "server" 
+# classloader. Prefixes should be used to define what is the repository type.
+# Path may be relative to the CATALINA_HOME or CATALINA_BASE path or absolute.
+# If left as blank, the "common" loader will be used as Catalina's "server" 
+# loader.
+# Examples:
+#     "foo": Add this folder as a class repository
+#     "foo/*.jar": Add all the JARs of the specified folder as class 
+#                  repositories
+#     "foo/bar.jar": Add bar.jar as a class repository
+server.loader=${catalina.home}/server/classes,${catalina.home}/server/lib/*.jar
+
+#
+# List of comma-separated paths defining the contents of the "shared" 
+# classloader. Prefixes should be used to define what is the repository type.
+# Path may be relative to the CATALINA_BASE path or absolute. If left as blank,
+# the "common" loader will be used as Catalina's "shared" loader.
+# Examples:
+#     "foo": Add this folder as a class repository
+#     "foo/*.jar": Add all the JARs of the specified folder as class 
+#                  repositories
+#     "foo/bar.jar": Add bar.jar as a class repository 
+# Please note that for single jars, e.g. bar.jar, you need the URL form
+# starting with file:.
+shared.loader=${catalina.base}/shared/classes,${catalina.base}/shared/lib/*.jar
+
+#
+# String cache configuration.
+tomcat.util.buf.StringCache.byte.enabled=true
+#tomcat.util.buf.StringCache.char.enabled=true
+#tomcat.util.buf.StringCache.trainThreshold=500000
+#tomcat.util.buf.StringCache.cacheSize=5000

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/startup/mbeans-descriptors.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/startup/mbeans-descriptors.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/startup/mbeans-descriptors.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,111 @@
+<?xml version="1.0"?>
+<mbeans-descriptors>
+
+  <mbean name="ContextConfig"
+         description="Startup event listener for a Context that configures the properties of that Context, and the associated defined servlets"
+         domain="Catalina"
+         group="Listener"
+         type="org.apache.catalina.startup.ContextConfig">
+    
+    <attribute name="className"
+               description="Fully qualified class name of the managed object"
+               type="java.lang.String"
+               writeable="false"/>
+      
+  </mbean>
+
+  <mbean name="EngineConfig"
+         description="Startup event listener for a Engine that configures the properties of that Engine, and the associated defined contexts"
+         domain="Catalina"
+         group="Listener"
+         type="org.apache.catalina.startup.EngineConfig">
+
+    <attribute name="className"
+               description="Fully qualified class name of the managed object"
+               type="java.lang.String"
+               writeable="false"/>
+      
+  </mbean>
+
+
+  <mbean name="HostConfig"
+         description="Startup event listener for a Host that configures the properties of that Host, and the associated defined contexts"
+         domain="Catalina"
+         group="Listener"
+         type="org.apache.catalina.startup.HostConfig">
+    
+    <attribute name="className"
+               description="Fully qualified class name of the managed object"
+               type="java.lang.String"
+               writeable="false"/>
+
+    <attribute name="configBaseName"
+               description="The base directory for Context configuration files"
+               type="java.lang.String"
+               writeable="false" />
+
+    <attribute name="configClass"
+               description="The Java class name of the Context configuration class we should use"
+               type="java.lang.String"/>
+
+    <attribute name="contextClass"
+               description="The Java class name of the Context implementation we should use"
+               type="java.lang.String"/>
+      
+    <operation name="check"
+               description="Check a web application name for updates"
+               impact="ACTION"
+               returnType="void">
+      <parameter name="name"
+                 description="Application name"
+                 type="java.lang.String"/>
+    </operation>
+
+    <operation name="addServiced"
+               description="Add a web application name to the serviced list"
+               impact="ACTION"
+               returnType="void">
+      <parameter name="name"
+                 description="Application name"
+                 type="java.lang.String"/>
+    </operation>
+
+    <operation name="isServiced"
+               description="Add a web application name to the serviced list"
+               impact="ACTION"
+               returnType="boolean">
+      <parameter name="name"
+                 description="Application name"
+                 type="java.lang.String"/>
+    </operation>
+
+    <operation name="manageApp"
+               description="Add a web application managed externally"
+               impact="ACTION"
+               returnType="void">
+      <parameter name="context"
+                 description="Context to add"
+                 type="org.apache.catalina.Context" />
+    </operation>
+
+    <operation name="removeServiced"
+               description="Add a web application name to the serviced list"
+               impact="ACTION"
+               returnType="void">
+      <parameter name="name"
+                 description="Application name"
+                 type="java.lang.String"/>
+    </operation>
+
+    <operation name="unmanageApp"
+               description="Remove a web application from checks"
+               impact="ACTION"
+               returnType="void">
+      <parameter name="contextPath"
+                 description="The application path"
+                 type="java.lang.String" />
+    </operation>
+
+  </mbean>
+
+</mbeans-descriptors>

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/users/AbstractGroup.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/users/AbstractGroup.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/users/AbstractGroup.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,168 @@
+/*
+ * Copyright 2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.users;
+
+
+import java.util.Iterator;
+
+import org.apache.catalina.Group;
+import org.apache.catalina.Role;
+import org.apache.catalina.UserDatabase;
+
+
+/**
+ * <p>Convenience base class for {@link Group} implementations.</p>
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 303133 $ $Date: 2004-08-29 11:46:15 -0500 (Sun, 29 Aug 2004) $
+ * @since 4.1
+ */
+
+public abstract class AbstractGroup implements Group {
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The description of this group.
+     */
+    protected String description = null;
+
+
+    /**
+     * The group name of this group.
+     */
+    protected String groupname = null;
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * Return the description of this group.
+     */
+    public String getDescription() {
+
+        return (this.description);
+
+    }
+
+
+    /**
+     * Set the description of this group.
+     *
+     * @param description The new description
+     */
+    public void setDescription(String description) {
+
+        this.description = description;
+
+    }
+
+
+    /**
+     * Return the group name of this group, which must be unique
+     * within the scope of a {@link UserDatabase}.
+     */
+    public String getGroupname() {
+
+        return (this.groupname);
+
+    }
+
+
+    /**
+     * Set the group name of this group, which must be unique
+     * within the scope of a {@link UserDatabase}.
+     *
+     * @param groupname The new group name
+     */
+    public void setGroupname(String groupname) {
+
+        this.groupname = groupname;
+
+    }
+
+
+    /**
+     * Return the set of {@link Role}s assigned specifically to this group.
+     */
+    public abstract Iterator getRoles();
+
+
+    /**
+     * Return the {@link UserDatabase} within which this Group is defined.
+     */
+    public abstract UserDatabase getUserDatabase();
+
+
+    /**
+     * Return an Iterator over the set of {@link org.apache.catalina.User}s that 
+     * are members of this group.
+     */
+    public abstract Iterator getUsers();
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Add a new {@link Role} to those assigned specifically to this group.
+     *
+     * @param role The new role
+     */
+    public abstract void addRole(Role role);
+
+
+    /**
+     * Is this group specifically assigned the specified {@link Role}?
+     *
+     * @param role The role to check
+     */
+    public abstract boolean isInRole(Role role);
+
+
+    /**
+     * Remove a {@link Role} from those assigned to this group.
+     *
+     * @param role The old role
+     */
+    public abstract void removeRole(Role role);
+
+
+    /**
+     * Remove all {@link Role}s from those assigned to this group.
+     */
+    public abstract void removeRoles();
+
+
+    // ------------------------------------------------------ Principal Methods
+
+
+    /**
+     * Make the principal name the same as the group name.
+     */
+    public String getName() {
+
+        return (getGroupname());
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/users/AbstractRole.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/users/AbstractRole.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/users/AbstractRole.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,122 @@
+/*
+ * Copyright 2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.users;
+
+
+import org.apache.catalina.Role;
+import org.apache.catalina.UserDatabase;
+
+
+/**
+ * <p>Convenience base class for {@link Role} implementations.</p>
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ * @since 4.1
+ */
+
+public abstract class AbstractRole implements Role {
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The description of this Role.
+     */
+    protected String description = null;
+
+
+    /**
+     * The role name of this Role.
+     */
+    protected String rolename = null;
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * Return the description of this role.
+     */
+    public String getDescription() {
+
+        return (this.description);
+
+    }
+
+
+    /**
+     * Set the description of this role.
+     *
+     * @param description The new description
+     */
+    public void setDescription(String description) {
+
+        this.description = description;
+
+    }
+
+
+    /**
+     * Return the role name of this role, which must be unique
+     * within the scope of a {@link UserDatabase}.
+     */
+    public String getRolename() {
+
+        return (this.rolename);
+
+    }
+
+
+    /**
+     * Set the role name of this role, which must be unique
+     * within the scope of a {@link UserDatabase}.
+     *
+     * @param rolename The new role name
+     */
+    public void setRolename(String rolename) {
+
+        this.rolename = rolename;
+
+    }
+
+
+    /**
+     * Return the {@link UserDatabase} within which this Role is defined.
+     */
+    public abstract UserDatabase getUserDatabase();
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    // ------------------------------------------------------ Principal Methods
+
+
+    /**
+     * Make the principal name the same as the role name.
+     */
+    public String getName() {
+
+        return (getRolename());
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/users/AbstractUser.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/users/AbstractUser.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/users/AbstractUser.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,224 @@
+/*
+ * Copyright 2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.users;
+
+
+import java.util.Iterator;
+import org.apache.catalina.Group;
+import org.apache.catalina.Role;
+import org.apache.catalina.User;
+
+
+/**
+ * <p>Convenience base class for {@link User} implementations.</p>
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 303133 $ $Date: 2004-08-29 11:46:15 -0500 (Sun, 29 Aug 2004) $
+ * @since 4.1
+ */
+
+public abstract class AbstractUser implements User {
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The full name of this user.
+     */
+    protected String fullName = null;
+
+
+    /**
+     * The logon password of this user.
+     */
+    protected String password = null;
+
+
+    /**
+     * The logon username of this user.
+     */
+    protected String username = null;
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * Return the full name of this user.
+     */
+    public String getFullName() {
+
+        return (this.fullName);
+
+    }
+
+
+    /**
+     * Set the full name of this user.
+     *
+     * @param fullName The new full name
+     */
+    public void setFullName(String fullName) {
+
+        this.fullName = fullName;
+
+    }
+
+
+    /**
+     * Return the set of {@link Group}s to which this user belongs.
+     */
+    public abstract Iterator getGroups();
+
+
+    /**
+     * Return the logon password of this user, optionally prefixed with the
+     * identifier of an encoding scheme surrounded by curly braces, such as
+     * <code>{md5}xxxxx</code>.
+     */
+    public String getPassword() {
+
+        return (this.password);
+
+    }
+
+
+    /**
+     * Set the logon password of this user, optionally prefixed with the
+     * identifier of an encoding scheme surrounded by curly braces, such as
+     * <code>{md5}xxxxx</code>.
+     *
+     * @param password The new logon password
+     */
+    public void setPassword(String password) {
+
+        this.password = password;
+
+    }
+
+
+    /**
+     * Return the set of {@link Role}s assigned specifically to this user.
+     */
+    public abstract Iterator getRoles();
+
+
+    /**
+     * Return the logon username of this user, which must be unique
+     * within the scope of a {@link org.apache.catalina.UserDatabase}.
+     */
+    public String getUsername() {
+
+        return (this.username);
+
+    }
+
+
+    /**
+     * Set the logon username of this user, which must be unique within
+     * the scope of a {@link org.apache.catalina.UserDatabase}.
+     *
+     * @param username The new logon username
+     */
+    public void setUsername(String username) {
+
+        this.username = username;
+
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Add a new {@link Group} to those this user belongs to.
+     *
+     * @param group The new group
+     */
+    public abstract void addGroup(Group group);
+
+
+    /**
+     * Add a new {@link Role} to those assigned specifically to this user.
+     *
+     * @param role The new role
+     */
+    public abstract void addRole(Role role);
+
+
+    /**
+     * Is this user in the specified {@link Group}?
+     *
+     * @param group The group to check
+     */
+    public abstract boolean isInGroup(Group group);
+
+
+    /**
+     * Is this user specifically assigned the specified {@link Role}?  This
+     * method does <strong>NOT</strong> check for roles inherited based on
+     * {@link Group} membership.
+     *
+     * @param role The role to check
+     */
+    public abstract boolean isInRole(Role role);
+
+
+    /**
+     * Remove a {@link Group} from those this user belongs to.
+     *
+     * @param group The old group
+     */
+    public abstract void removeGroup(Group group);
+
+
+    /**
+     * Remove all {@link Group}s from those this user belongs to.
+     */
+    public abstract void removeGroups();
+
+
+    /**
+     * Remove a {@link Role} from those assigned to this user.
+     *
+     * @param role The old role
+     */
+    public abstract void removeRole(Role role);
+
+
+    /**
+     * Remove all {@link Role}s from those assigned to this user.
+     */
+    public abstract void removeRoles();
+
+
+    // ------------------------------------------------------ Principal Methods
+
+
+    /**
+     * Make the principal name the same as the group name.
+     */
+    public String getName() {
+
+        return (getUsername());
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/users/Constants.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/users/Constants.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/users/Constants.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.users;
+
+
+/**
+ * Manifest constants for this Java package.
+ *
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ * @since 4.1
+ */
+
+public final class Constants {
+
+    public static final String Package = "org.apache.catalina.users";
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/users/LocalStrings.properties
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/users/LocalStrings.properties	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/users/LocalStrings.properties	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,5 @@
+memoryUserDatabase.invalidGroup=Invalid group name {0}
+memoryUserDatabase.renameOld=Cannot rename original file to {0}
+memoryUserDatabase.renameNew=Cannot rename new file to {0}
+memoryUserDatabase.writeException=IOException writing to {0}
+memoryUserDatabase.notPersistable=User database is not persistable - no write permissions on directory

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/users/LocalStrings_es.properties
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/users/LocalStrings_es.properties	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/users/LocalStrings_es.properties	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,4 @@
+memoryUserDatabase.invalidGroup=Nombre de grupo {0} inválido
+memoryUserDatabase.renameOld=Imposible de renombrar el archivo original a {0}
+memoryUserDatabase.renameNew=Imposible de renombrar el archivo nuevo a {0}
+memoryUserDatabase.writeException=IOException durante la escritura hacia {0}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/users/LocalStrings_fr.properties
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/users/LocalStrings_fr.properties	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/users/LocalStrings_fr.properties	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,4 @@
+memoryUserDatabase.invalidGroup=Nom de groupe invalide {0}
+memoryUserDatabase.renameOld=Impossible de renommer le fichier original en {0}
+memoryUserDatabase.renameNew=Impossible de renommer le nouveau fichier en {0}
+memoryUserDatabase.writeException=IOException lors de l''écriture vers {0}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/users/LocalStrings_ja.properties
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/users/LocalStrings_ja.properties	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/users/LocalStrings_ja.properties	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,4 @@
+memoryUserDatabase.invalidGroup=\u7121\u52b9\u306a\u30b0\u30eb\u30fc\u30d7\u540d {0}
+memoryUserDatabase.renameOld=\u5143\u306e\u30d5\u30a1\u30a4\u30eb\u540d\u3092 {0} \u306b\u5909\u66f4\u3067\u304d\u307e\u305b\u3093
+memoryUserDatabase.renameNew=\u65b0\u3057\u3044\u30d5\u30a1\u30a4\u30eb\u540d\u3092 {0} \u306b\u5909\u66f4\u3067\u304d\u307e\u305b\u3093
+memoryUserDatabase.writeException={0} \u306b\u66f8\u304d\u8fbc\u307f\u4e2d\u306eIOException\u3067\u3059

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/users/MemoryGroup.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/users/MemoryGroup.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/users/MemoryGroup.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,213 @@
+/*
+ * Copyright 2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.users;
+
+
+import java.util.ArrayList;
+import java.util.Iterator;
+
+import org.apache.catalina.Role;
+import org.apache.catalina.UserDatabase;
+
+
+/**
+ * <p>Concrete implementation of {@link org.apache.catalina.Group} for the
+ * {@link MemoryUserDatabase} implementation of {@link UserDatabase}.</p>
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 303133 $ $Date: 2004-08-29 11:46:15 -0500 (Sun, 29 Aug 2004) $
+ * @since 4.1
+ */
+
+public class MemoryGroup extends AbstractGroup {
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Package-private constructor used by the factory method in
+     * {@link MemoryUserDatabase}.
+     *
+     * @param database The {@link MemoryUserDatabase} that owns this group
+     * @param groupname Group name of this group
+     * @param description Description of this group
+     */
+    MemoryGroup(MemoryUserDatabase database,
+                String groupname, String description) {
+
+        super();
+        this.database = database;
+        setGroupname(groupname);
+        setDescription(description);
+
+    }
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The {@link MemoryUserDatabase} that owns this group.
+     */
+    protected MemoryUserDatabase database = null;
+
+
+    /**
+     * The set of {@link Role}s associated with this group.
+     */
+    protected ArrayList roles = new ArrayList();
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * Return the set of {@link Role}s assigned specifically to this group.
+     */
+    public Iterator getRoles() {
+
+        synchronized (roles) {
+            return (roles.iterator());
+        }
+
+    }
+
+
+    /**
+     * Return the {@link UserDatabase} within which this Group is defined.
+     */
+    public UserDatabase getUserDatabase() {
+
+        return (this.database);
+
+    }
+
+
+    /**
+     * Return the set of {@link org.apache.catalina.User}s that are members of this group.
+     */
+    public Iterator getUsers() {
+
+        ArrayList results = new ArrayList();
+        Iterator users = database.getUsers();
+        while (users.hasNext()) {
+            MemoryUser user = (MemoryUser) users.next();
+            if (user.isInGroup(this)) {
+                results.add(user);
+            }
+        }
+        return (results.iterator());
+
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Add a new {@link Role} to those assigned specifically to this group.
+     *
+     * @param role The new role
+     */
+    public void addRole(Role role) {
+
+        synchronized (roles) {
+            if (!roles.contains(role)) {
+                roles.add(role);
+            }
+        }
+
+    }
+
+
+    /**
+     * Is this group specifically assigned the specified {@link Role}?
+     *
+     * @param role The role to check
+     */
+    public boolean isInRole(Role role) {
+
+        synchronized (roles) {
+            return (roles.contains(role));
+        }
+
+    }
+
+
+    /**
+     * Remove a {@link Role} from those assigned to this group.
+     *
+     * @param role The old role
+     */
+    public void removeRole(Role role) {
+
+        synchronized (roles) {
+            roles.remove(role);
+        }
+
+    }
+
+
+    /**
+     * Remove all {@link Role}s from those assigned to this group.
+     */
+    public void removeRoles() {
+
+        synchronized (roles) {
+            roles.clear();
+        }
+
+    }
+
+
+    /**
+     * <p>Return a String representation of this group in XML format.</p>
+     */
+    public String toString() {
+
+        StringBuffer sb = new StringBuffer("<group groupname=\"");
+        sb.append(groupname);
+        sb.append("\"");
+        if (description != null) {
+            sb.append(" description=\"");
+            sb.append(description);
+            sb.append("\"");
+        }
+        synchronized (roles) {
+            if (roles.size() > 0) {
+                sb.append(" roles=\"");
+                int n = 0;
+                Iterator values = roles.iterator();
+                while (values.hasNext()) {
+                    if (n > 0) {
+                        sb.append(',');
+                    }
+                    n++;
+                    sb.append((String) ((Role) values.next()).getRolename());
+                }
+                sb.append("\"");
+            }
+        }
+        sb.append("/>");
+        return (sb.toString());
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/users/MemoryRole.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/users/MemoryRole.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/users/MemoryRole.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,102 @@
+/*
+ * Copyright 2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.users;
+
+
+import org.apache.catalina.UserDatabase;
+
+
+/**
+ * <p>Concrete implementation of {@link org.apache.catalina.Role} for the
+ * {@link MemoryUserDatabase} implementation of {@link UserDatabase}.</p>
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 303133 $ $Date: 2004-08-29 11:46:15 -0500 (Sun, 29 Aug 2004) $
+ * @since 4.1
+ */
+
+public class MemoryRole extends AbstractRole {
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Package-private constructor used by the factory method in
+     * {@link MemoryUserDatabase}.
+     *
+     * @param database The {@link MemoryUserDatabase} that owns this role
+     * @param rolename Role name of this role
+     * @param description Description of this role
+     */
+    MemoryRole(MemoryUserDatabase database,
+               String rolename, String description) {
+
+        super();
+        this.database = database;
+        setRolename(rolename);
+        setDescription(description);
+
+    }
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The {@link MemoryUserDatabase} that owns this role.
+     */
+    protected MemoryUserDatabase database = null;
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * Return the {@link UserDatabase} within which this role is defined.
+     */
+    public UserDatabase getUserDatabase() {
+
+        return (this.database);
+
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * <p>Return a String representation of this role in XML format.</p>
+     */
+    public String toString() {
+
+        StringBuffer sb = new StringBuffer("<role rolename=\"");
+        sb.append(rolename);
+        sb.append("\"");
+        if (description != null) {
+            sb.append(" description=\"");
+            sb.append(description);
+            sb.append("\"");
+        }
+        sb.append("/>");
+        return (sb.toString());
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/users/MemoryUser.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/users/MemoryUser.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/users/MemoryUser.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,296 @@
+/*
+ * Copyright 2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.users;
+
+
+import java.util.ArrayList;
+import java.util.Iterator;
+
+import org.apache.catalina.Group;
+import org.apache.catalina.Role;
+import org.apache.catalina.UserDatabase;
+import org.apache.catalina.util.RequestUtil;
+
+/**
+ * <p>Concrete implementation of {@link org.apache.catalina.User} for the
+ * {@link MemoryUserDatabase} implementation of {@link UserDatabase}.</p>
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 303133 $ $Date: 2004-08-29 11:46:15 -0500 (Sun, 29 Aug 2004) $
+ * @since 4.1
+ */
+
+public class MemoryUser extends AbstractUser {
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Package-private constructor used by the factory method in
+     * {@link MemoryUserDatabase}.
+     *
+     * @param database The {@link MemoryUserDatabase} that owns this user
+     * @param username Logon username of the new user
+     * @param password Logon password of the new user
+     * @param fullName Full name of the new user
+     */
+    MemoryUser(MemoryUserDatabase database, String username,
+               String password, String fullName) {
+
+        super();
+        this.database = database;
+        setUsername(username);
+        setPassword(password);
+        setFullName(fullName);
+
+    }
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The {@link MemoryUserDatabase} that owns this user.
+     */
+    protected MemoryUserDatabase database = null;
+
+
+    /**
+     * The set of {@link Group}s that this user is a member of.
+     */
+    protected ArrayList groups = new ArrayList();
+
+
+    /**
+     * The set of {@link Role}s associated with this user.
+     */
+    protected ArrayList roles = new ArrayList();
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * Return the set of {@link Group}s to which this user belongs.
+     */
+    public Iterator getGroups() {
+
+        synchronized (groups) {
+            return (groups.iterator());
+        }
+
+    }
+
+
+    /**
+     * Return the set of {@link Role}s assigned specifically to this user.
+     */
+    public Iterator getRoles() {
+
+        synchronized (roles) {
+            return (roles.iterator());
+        }
+
+    }
+
+
+    /**
+     * Return the {@link UserDatabase} within which this User is defined.
+     */
+    public UserDatabase getUserDatabase() {
+
+        return (this.database);
+
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Add a new {@link Group} to those this user belongs to.
+     *
+     * @param group The new group
+     */
+    public void addGroup(Group group) {
+
+        synchronized (groups) {
+            if (!groups.contains(group)) {
+                groups.add(group);
+            }
+        }
+
+    }
+
+
+    /**
+     * Add a new {@link Role} to those assigned specifically to this user.
+     *
+     * @param role The new role
+     */
+    public void addRole(Role role) {
+
+        synchronized (roles) {
+            if (!roles.contains(role)) {
+                roles.add(role);
+            }
+        }
+
+    }
+
+
+    /**
+     * Is this user in the specified group?
+     *
+     * @param group The group to check
+     */
+    public boolean isInGroup(Group group) {
+
+        synchronized (groups) {
+            return (groups.contains(group));
+        }
+
+    }
+
+
+    /**
+     * Is this user specifically assigned the specified {@link Role}?  This
+     * method does <strong>NOT</strong> check for roles inherited based on
+     * {@link Group} membership.
+     *
+     * @param role The role to check
+     */
+    public boolean isInRole(Role role) {
+
+        synchronized (roles) {
+            return (roles.contains(role));
+        }
+
+    }
+
+
+    /**
+     * Remove a {@link Group} from those this user belongs to.
+     *
+     * @param group The old group
+     */
+    public void removeGroup(Group group) {
+
+        synchronized (groups) {
+            groups.remove(group);
+        }
+
+    }
+
+
+    /**
+     * Remove all {@link Group}s from those this user belongs to.
+     */
+    public void removeGroups() {
+
+        synchronized (groups) {
+            groups.clear();
+        }
+
+    }
+
+
+    /**
+     * Remove a {@link Role} from those assigned to this user.
+     *
+     * @param role The old role
+     */
+    public void removeRole(Role role) {
+
+        synchronized (roles) {
+            roles.remove(role);
+        }
+
+    }
+
+
+    /**
+     * Remove all {@link Role}s from those assigned to this user.
+     */
+    public void removeRoles() {
+
+        synchronized (roles) {
+            roles.clear();
+        }
+
+    }
+
+
+    /**
+     * <p>Return a String representation of this user in XML format.</p>
+     *
+     * <p><strong>IMPLEMENTATION NOTE</strong> - For backwards compatibility,
+     * the reader that processes this entry will accept either
+     * <code>username</code> or </code>name</code> for the username
+     * property.</p>
+     */
+    public String toString() {
+
+        StringBuffer sb = new StringBuffer("<user username=\"");
+        sb.append(RequestUtil.filter(username));
+        sb.append("\" password=\"");
+        sb.append(RequestUtil.filter(password));
+        sb.append("\"");
+        if (fullName != null) {
+            sb.append(" fullName=\"");
+            sb.append(RequestUtil.filter(fullName));
+            sb.append("\"");
+        }
+        synchronized (groups) {
+            if (groups.size() > 0) {
+                sb.append(" groups=\"");
+                int n = 0;
+                Iterator values = groups.iterator();
+                while (values.hasNext()) {
+                    if (n > 0) {
+                        sb.append(',');
+                    }
+                    n++;
+                    sb.append(RequestUtil.filter(((Group) values.next()).getGroupname()));
+                }
+                sb.append("\"");
+            }
+        }
+        synchronized (roles) {
+            if (roles.size() > 0) {
+                sb.append(" roles=\"");
+                int n = 0;
+                Iterator values = roles.iterator();
+                while (values.hasNext()) {
+                    if (n > 0) {
+                        sb.append(',');
+                    }
+                    n++;
+                    sb.append(RequestUtil.filter(((Role) values.next()).getRolename()));
+                }
+                sb.append("\"");
+            }
+        }
+        sb.append("/>");
+        return (sb.toString());
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/users/MemoryUserDatabase.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/users/MemoryUserDatabase.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/users/MemoryUserDatabase.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,803 @@
+/*
+ * Copyright 2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.users;
+
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+import java.util.HashMap;
+import java.util.Iterator;
+import org.apache.catalina.Group;
+import org.apache.catalina.Role;
+import org.apache.catalina.User;
+import org.apache.catalina.UserDatabase;
+import org.apache.catalina.util.StringManager;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.tomcat.util.digester.Digester;
+import org.apache.tomcat.util.digester.ObjectCreationFactory;
+import org.xml.sax.Attributes;
+
+
+/**
+ * <p>Concrete implementation of {@link UserDatabase} that loads all
+ * defined users, groups, and roles into an in-memory data structure,
+ * and uses a specified XML file for its persistent storage.</p>
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 304047 $ $Date: 2005-08-04 08:12:16 -0500 (Thu, 04 Aug 2005) $
+ * @since 4.1
+ */
+
+public class MemoryUserDatabase implements UserDatabase {
+
+
+    private static Log log = LogFactory.getLog(MemoryUserDatabase.class);
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Create a new instance with default values.
+     */
+    public MemoryUserDatabase() {
+
+        super();
+
+    }
+
+
+    /**
+     * Create a new instance with the specified values.
+     *
+     * @param id Unique global identifier of this user database
+     */
+    public MemoryUserDatabase(String id) {
+
+        super();
+        this.id = id;
+
+    }
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The set of {@link Group}s defined in this database, keyed by
+     * group name.
+     */
+    protected HashMap groups = new HashMap();
+
+
+    /**
+     * The unique global identifier of this user database.
+     */
+    protected String id = null;
+
+
+    /**
+     * The relative (to <code>catalina.base</code>) or absolute pathname to
+     * the XML file in which we will save our persistent information.
+     */
+    protected String pathname = "conf/tomcat-users.xml";
+
+
+    /**
+     * The relative or absolute pathname to the file in which our old
+     * information is stored while renaming is in progress.
+     */
+    protected String pathnameOld = pathname + ".old";
+
+
+    /**
+     * The relative or absolute pathname ot the file in which we write
+     * our new information prior to renaming.
+     */
+    protected String pathnameNew = pathname + ".new";
+
+
+    /**
+     * A flag, indicating if the user database is read only.
+     */
+    protected boolean readonly = false;
+
+    /**
+     * The set of {@link Role}s defined in this database, keyed by
+     * role name.
+     */
+    protected HashMap roles = new HashMap();
+
+
+    /**
+     * The string manager for this package.
+     */
+    private static StringManager sm =
+        StringManager.getManager(Constants.Package);
+
+
+    /**
+     * The set of {@link User}s defined in this database, keyed by
+     * user name.
+     */
+    protected HashMap users = new HashMap();
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * Return the set of {@link Group}s defined in this user database.
+     */
+    public Iterator getGroups() {
+
+        synchronized (groups) {
+            return (groups.values().iterator());
+        }
+
+    }
+
+
+    /**
+     * Return the unique global identifier of this user database.
+     */
+    public String getId() {
+
+        return (this.id);
+
+    }
+
+
+    /**
+     * Return the relative or absolute pathname to the persistent storage file.
+     */
+    public String getPathname() {
+
+        return (this.pathname);
+
+    }
+
+
+    /**
+     * Set the relative or absolute pathname to the persistent storage file.
+     *
+     * @param pathname The new pathname
+     */
+    public void setPathname(String pathname) {
+
+        this.pathname = pathname;
+        this.pathnameOld = pathname + ".old";
+        this.pathnameNew = pathname + ".new";
+
+    }
+
+
+    /**
+     * Returning the readonly status of the user database
+     */
+    public boolean getReadonly() {
+
+        return (this.readonly);
+
+    }
+
+
+    /**
+     * Setting the readonly status of the user database
+     *
+     * @param pathname The new pathname
+     */
+    public void setReadonly(boolean readonly) {
+
+        this.readonly = readonly;
+
+    }
+
+
+    /**
+     * Return the set of {@link Role}s defined in this user database.
+     */
+    public Iterator getRoles() {
+
+        synchronized (roles) {
+            return (roles.values().iterator());
+        }
+
+    }
+
+
+    /**
+     * Return the set of {@link User}s defined in this user database.
+     */
+    public Iterator getUsers() {
+
+        synchronized (users) {
+            return (users.values().iterator());
+        }
+
+    }
+
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Finalize access to this user database.
+     *
+     * @exception Exception if any exception is thrown during closing
+     */
+    public void close() throws Exception {
+
+        save();
+
+        synchronized (groups) {
+            synchronized (users) {
+                users.clear();
+                groups.clear();
+            }
+        }
+
+    }
+
+
+    /**
+     * Create and return a new {@link Group} defined in this user database.
+     *
+     * @param groupname The group name of the new group (must be unique)
+     * @param description The description of this group
+     */
+    public Group createGroup(String groupname, String description) {
+
+        MemoryGroup group = new MemoryGroup(this, groupname, description);
+        synchronized (groups) {
+            groups.put(group.getGroupname(), group);
+        }
+        return (group);
+
+    }
+
+
+    /**
+     * Create and return a new {@link Role} defined in this user database.
+     *
+     * @param rolename The role name of the new group (must be unique)
+     * @param description The description of this group
+     */
+    public Role createRole(String rolename, String description) {
+
+        MemoryRole role = new MemoryRole(this, rolename, description);
+        synchronized (roles) {
+            roles.put(role.getRolename(), role);
+        }
+        return (role);
+
+    }
+
+
+    /**
+     * Create and return a new {@link User} defined in this user database.
+     *
+     * @param username The logon username of the new user (must be unique)
+     * @param password The logon password of the new user
+     * @param fullName The full name of the new user
+     */
+    public User createUser(String username, String password,
+                           String fullName) {
+
+        MemoryUser user = new MemoryUser(this, username, password, fullName);
+        synchronized (users) {
+            users.put(user.getUsername(), user);
+        }
+        return (user);
+
+    }
+
+
+    /**
+     * Return the {@link Group} with the specified group name, if any;
+     * otherwise return <code>null</code>.
+     *
+     * @param groupname Name of the group to return
+     */
+    public Group findGroup(String groupname) {
+
+        synchronized (groups) {
+            return ((Group) groups.get(groupname));
+        }
+
+    }
+
+
+    /**
+     * Return the {@link Role} with the specified role name, if any;
+     * otherwise return <code>null</code>.
+     *
+     * @param rolename Name of the role to return
+     */
+    public Role findRole(String rolename) {
+
+        synchronized (roles) {
+            return ((Role) roles.get(rolename));
+        }
+
+    }
+
+
+    /**
+     * Return the {@link User} with the specified user name, if any;
+     * otherwise return <code>null</code>.
+     *
+     * @param username Name of the user to return
+     */
+    public User findUser(String username) {
+
+        synchronized (users) {
+            return ((User) users.get(username));
+        }
+
+    }
+
+
+    /**
+     * Initialize access to this user database.
+     *
+     * @exception Exception if any exception is thrown during opening
+     */
+    public void open() throws Exception {
+
+        synchronized (groups) {
+            synchronized (users) {
+
+                // Erase any previous groups and users
+                users.clear();
+                groups.clear();
+                roles.clear();
+
+                // Construct a reader for the XML input file (if it exists)
+                File file = new File(pathname);
+                if (!file.isAbsolute()) {
+                    file = new File(System.getProperty("catalina.base"),
+                                    pathname);
+                }
+                if (!file.exists()) {
+                    return;
+                }
+                FileInputStream fis = new FileInputStream(file);
+
+                // Construct a digester to read the XML input file
+                Digester digester = new Digester();
+                digester.addFactoryCreate
+                    ("tomcat-users/group",
+                     new MemoryGroupCreationFactory(this));
+                digester.addFactoryCreate
+                    ("tomcat-users/role",
+                     new MemoryRoleCreationFactory(this));
+                digester.addFactoryCreate
+                    ("tomcat-users/user",
+                     new MemoryUserCreationFactory(this));
+
+                // Parse the XML input file to load this database
+                try {
+                    digester.parse(fis);
+                    fis.close();
+                } catch (Exception e) {
+                    try {
+                        fis.close();
+                    } catch (Throwable t) {
+                        ;
+                    }
+                    throw e;
+                }
+
+            }
+        }
+
+    }
+
+
+    /**
+     * Remove the specified {@link Group} from this user database.
+     *
+     * @param group The group to be removed
+     */
+    public void removeGroup(Group group) {
+
+        synchronized (groups) {
+            Iterator users = getUsers();
+            while (users.hasNext()) {
+                User user = (User) users.next();
+                user.removeGroup(group);
+            }
+            groups.remove(group.getGroupname());
+        }
+
+    }
+
+
+    /**
+     * Remove the specified {@link Role} from this user database.
+     *
+     * @param role The role to be removed
+     */
+    public void removeRole(Role role) {
+
+        synchronized (roles) {
+            Iterator groups = getGroups();
+            while (groups.hasNext()) {
+                Group group = (Group) groups.next();
+                group.removeRole(role);
+            }
+            Iterator users = getUsers();
+            while (users.hasNext()) {
+                User user = (User) users.next();
+                user.removeRole(role);
+            }
+            roles.remove(role.getRolename());
+        }
+
+    }
+
+
+    /**
+     * Remove the specified {@link User} from this user database.
+     *
+     * @param user The user to be removed
+     */
+    public void removeUser(User user) {
+
+        synchronized (users) {
+            users.remove(user.getUsername());
+        }
+
+    }
+
+
+    /**
+     * Check for permissions to save this user database
+     * to persistent storage location
+     *
+     */
+    public boolean isWriteable() {
+
+        File file = new File(pathname);
+        if (!file.isAbsolute()) {
+            file = new File(System.getProperty("catalina.base"),
+                            pathname);
+        }
+        File dir = file.getParentFile();
+        return dir.exists() && dir.isDirectory() && dir.canWrite();
+
+    }
+
+
+    /**
+     * Save any updated information to the persistent storage location for
+     * this user database.
+     *
+     * @exception Exception if any exception is thrown during saving
+     */
+    public void save() throws Exception {
+
+        if (getReadonly()) {
+            return;
+        }
+
+        if (!isWriteable()) {
+            log.warn(sm.getString("memoryUserDatabase.notPersistable"));
+            return;
+        }
+
+        // Write out contents to a temporary file
+        File fileNew = new File(pathnameNew);
+        if (!fileNew.isAbsolute()) {
+            fileNew =
+                new File(System.getProperty("catalina.base"), pathnameNew);
+        }
+        PrintWriter writer = null;
+        try {
+
+            // Configure our PrintWriter
+            FileOutputStream fos = new FileOutputStream(fileNew);
+            OutputStreamWriter osw = new OutputStreamWriter(fos, "UTF8");
+            writer = new PrintWriter(osw);
+
+            // Print the file prolog
+            writer.println("<?xml version='1.0' encoding='utf-8'?>");
+            writer.println("<tomcat-users>");
+
+            // Print entries for each defined role, group, and user
+            Iterator values = null;
+            values = getRoles();
+            while (values.hasNext()) {
+                writer.print("  ");
+                writer.println(values.next());
+            }
+            values = getGroups();
+            while (values.hasNext()) {
+                writer.print("  ");
+                writer.println(values.next());
+            }
+            values = getUsers();
+            while (values.hasNext()) {
+                writer.print("  ");
+                writer.println(values.next());
+            }
+
+            // Print the file epilog
+            writer.println("</tomcat-users>");
+
+            // Check for errors that occurred while printing
+            if (writer.checkError()) {
+                writer.close();
+                fileNew.delete();
+                throw new IOException
+                    (sm.getString("memoryUserDatabase.writeException",
+                                  fileNew.getAbsolutePath()));
+            }
+            writer.close();
+        } catch (IOException e) {
+            if (writer != null) {
+                writer.close();
+            }
+            fileNew.delete();
+            throw e;
+        }
+
+        // Perform the required renames to permanently save this file
+        File fileOld = new File(pathnameOld);
+        if (!fileOld.isAbsolute()) {
+            fileOld =
+                new File(System.getProperty("catalina.base"), pathnameOld);
+        }
+        fileOld.delete();
+        File fileOrig = new File(pathname);
+        if (!fileOrig.isAbsolute()) {
+            fileOrig =
+                new File(System.getProperty("catalina.base"), pathname);
+        }
+        if (fileOrig.exists()) {
+            fileOld.delete();
+            if (!fileOrig.renameTo(fileOld)) {
+                throw new IOException
+                    (sm.getString("memoryUserDatabase.renameOld",
+                                  fileOld.getAbsolutePath()));
+            }
+        }
+        if (!fileNew.renameTo(fileOrig)) {
+            if (fileOld.exists()) {
+                fileOld.renameTo(fileOrig);
+            }
+            throw new IOException
+                (sm.getString("memoryUserDatabase.renameNew",
+                              fileOrig.getAbsolutePath()));
+        }
+        fileOld.delete();
+
+    }
+
+
+    /**
+     * Return a String representation of this UserDatabase.
+     */
+    public String toString() {
+
+        StringBuffer sb = new StringBuffer("MemoryUserDatabase[id=");
+        sb.append(this.id);
+        sb.append(",pathname=");
+        sb.append(pathname);
+        sb.append(",groupCount=");
+        sb.append(this.groups.size());
+        sb.append(",roleCount=");
+        sb.append(this.roles.size());
+        sb.append(",userCount=");
+        sb.append(this.users.size());
+        sb.append("]");
+        return (sb.toString());
+
+    }
+
+
+    // -------------------------------------------------------- Package Methods
+
+
+    /**
+     * Return the <code>StringManager</code> for use in looking up messages.
+     */
+    StringManager getStringManager() {
+
+        return (sm);
+
+    }
+
+
+}
+
+
+
+/**
+ * Digester object creation factory for group instances.
+ */
+class MemoryGroupCreationFactory implements ObjectCreationFactory {
+
+    public MemoryGroupCreationFactory(MemoryUserDatabase database) {
+        this.database = database;
+    }
+
+    public Object createObject(Attributes attributes) {
+        String groupname = attributes.getValue("groupname");
+        if (groupname == null) {
+            groupname = attributes.getValue("name");
+        }
+        String description = attributes.getValue("description");
+        String roles = attributes.getValue("roles");
+        Group group = database.createGroup(groupname, description);
+        if (roles != null) {
+            while (roles.length() > 0) {
+                String rolename = null;
+                int comma = roles.indexOf(',');
+                if (comma >= 0) {
+                    rolename = roles.substring(0, comma).trim();
+                    roles = roles.substring(comma + 1);
+                } else {
+                    rolename = roles.trim();
+                    roles = "";
+                }
+                if (rolename.length() > 0) {
+                    Role role = database.findRole(rolename);
+                    if (role == null) {
+                        role = database.createRole(rolename, null);
+                    }
+                    group.addRole(role);
+                }
+            }
+        }
+        return (group);
+    }
+
+    private MemoryUserDatabase database = null;
+
+    private Digester digester = null;
+
+    public Digester getDigester() {
+        return (this.digester);
+    }
+
+    public void setDigester(Digester digester) {
+        this.digester = digester;
+    }
+
+}
+
+
+/**
+ * Digester object creation factory for role instances.
+ */
+class MemoryRoleCreationFactory implements ObjectCreationFactory {
+
+    public MemoryRoleCreationFactory(MemoryUserDatabase database) {
+        this.database = database;
+    }
+
+    public Object createObject(Attributes attributes) {
+        String rolename = attributes.getValue("rolename");
+        if (rolename == null) {
+            rolename = attributes.getValue("name");
+        }
+        String description = attributes.getValue("description");
+        Role role = database.createRole(rolename, description);
+        return (role);
+    }
+
+    private MemoryUserDatabase database = null;
+
+    private Digester digester = null;
+
+    public Digester getDigester() {
+        return (this.digester);
+    }
+
+    public void setDigester(Digester digester) {
+        this.digester = digester;
+    }
+
+}
+
+
+/**
+ * Digester object creation factory for user instances.
+ */
+class MemoryUserCreationFactory implements ObjectCreationFactory {
+
+    public MemoryUserCreationFactory(MemoryUserDatabase database) {
+        this.database = database;
+    }
+
+    public Object createObject(Attributes attributes) {
+        String username = attributes.getValue("username");
+        if (username == null) {
+            username = attributes.getValue("name");
+        }
+        String password = attributes.getValue("password");
+        String fullName = attributes.getValue("fullName");
+        if (fullName == null) {
+            fullName = attributes.getValue("fullname");
+        }
+        String groups = attributes.getValue("groups");
+        String roles = attributes.getValue("roles");
+        User user = database.createUser(username, password, fullName);
+        if (groups != null) {
+            while (groups.length() > 0) {
+                String groupname = null;
+                int comma = groups.indexOf(',');
+                if (comma >= 0) {
+                    groupname = groups.substring(0, comma).trim();
+                    groups = groups.substring(comma + 1);
+                } else {
+                    groupname = groups.trim();
+                    groups = "";
+                }
+                if (groupname.length() > 0) {
+                    Group group = database.findGroup(groupname);
+                    if (group == null) {
+                        group = database.createGroup(groupname, null);
+                    }
+                    user.addGroup(group);
+                }
+            }
+        }
+        if (roles != null) {
+            while (roles.length() > 0) {
+                String rolename = null;
+                int comma = roles.indexOf(',');
+                if (comma >= 0) {
+                    rolename = roles.substring(0, comma).trim();
+                    roles = roles.substring(comma + 1);
+                } else {
+                    rolename = roles.trim();
+                    roles = "";
+                }
+                if (rolename.length() > 0) {
+                    Role role = database.findRole(rolename);
+                    if (role == null) {
+                        role = database.createRole(rolename, null);
+                    }
+                    user.addRole(role);
+                }
+            }
+        }
+        return (user);
+    }
+
+    private MemoryUserDatabase database = null;
+
+    private Digester digester = null;
+
+    public Digester getDigester() {
+        return (this.digester);
+    }
+
+    public void setDigester(Digester digester) {
+        this.digester = digester;
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/users/MemoryUserDatabaseFactory.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/users/MemoryUserDatabaseFactory.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/users/MemoryUserDatabaseFactory.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,109 @@
+/*
+ * Copyright 2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.users;
+
+
+import java.util.Hashtable;
+
+import javax.naming.Context;
+import javax.naming.Name;
+import javax.naming.RefAddr;
+import javax.naming.Reference;
+import javax.naming.spi.ObjectFactory;
+
+
+/**
+ * <p>JNDI object creation factory for <code>MemoryUserDatabase</code>
+ * instances.  This makes it convenient to configure a user database
+ * in the global JNDI resources associated with this Catalina instance,
+ * and then link to that resource for web applications that administer
+ * the contents of the user database.</p>
+ *
+ * <p>The <code>MemoryUserDatabase</code> instance is configured based
+ * on the following parameter values:</p>
+ * <ul>
+ * <li><strong>pathname</strong> - Absolute or relative (to the directory
+ *     path specified by the <code>catalina.base</code> system property)
+ *     pathname to the XML file from which our user information is loaded,
+ *     and to which it is stored.  [conf/tomcat-users.xml]</li>
+ * </ul>
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 304046 $ $Date: 2005-08-04 08:06:56 -0500 (Thu, 04 Aug 2005) $
+ * @since 4.1
+ */
+
+public class MemoryUserDatabaseFactory implements ObjectFactory {
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * <p>Create and return a new <code>MemoryUserDatabase</code> instance
+     * that has been configured according to the properties of the
+     * specified <code>Reference</code>.  If you instance can be created,
+     * return <code>null</code> instead.</p>
+     *
+     * @param obj The possibly null object containing location or
+     *  reference information that can be used in creating an object
+     * @param name The name of this object relative to <code>nameCtx</code>
+     * @param nameCtx The context relative to which the <code>name</code>
+     *  parameter is specified, or <code>null</code> if <code>name</code>
+     *  is relative to the default initial context
+     * @param environment The possibly null environment that is used in
+     *  creating this object
+     */
+    public Object getObjectInstance(Object obj, Name name, Context nameCtx,
+                                    Hashtable environment)
+        throws Exception {
+
+        // We only know how to deal with <code>javax.naming.Reference</code>s
+        // that specify a class name of "org.apache.catalina.UserDatabase"
+        if ((obj == null) || !(obj instanceof Reference)) {
+            return (null);
+        }
+        Reference ref = (Reference) obj;
+        if (!"org.apache.catalina.UserDatabase".equals(ref.getClassName())) {
+            return (null);
+        }
+
+        // Create and configure a MemoryUserDatabase instance based on the
+        // RefAddr values associated with this Reference
+        MemoryUserDatabase database = new MemoryUserDatabase(name.toString());
+        RefAddr ra = null;
+
+        ra = ref.get("pathname");
+        if (ra != null) {
+            database.setPathname(ra.getContent().toString());
+        }
+
+        ra = ref.get("readonly");
+        if (ra != null) {
+            database.setReadonly(Boolean.valueOf(ra.getContent().toString()).booleanValue());
+        }
+
+        // Return the configured database instance
+        database.open();
+        database.save();
+        return (database);
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/users/mbeans-descriptors.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/users/mbeans-descriptors.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/users/mbeans-descriptors.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,280 @@
+<?xml version="1.0"?>
+<mbeans-descriptors>
+
+  <mbean         name="JDBCUserDatabase"
+            className="org.apache.catalina.mbeans.JDBCUserDatabaseMBean"
+          description="JDBC based user and group database"
+               domain="Users"
+                group="UserDatabase"
+                 type="org.apache.catalina.users.JDBCUserDatabase">
+
+    <attribute   name="groups"
+          description="MBean Names of all defined groups"
+                 type="[Ljava.lang.String;"
+            writeable="false"/>
+
+    <attribute   name="roles"
+          description="MBean Names of all defined roles"
+                 type="[Ljava.lang.String;"
+            writeable="false"/>
+
+    <attribute   name="users"
+          description="MBean Names of all defined users"
+                 type="[Ljava.lang.String;"
+            writeable="false"/>
+
+    <operation   name="createGroup"
+          description="Create new group and return MBean name"
+               impact="ACTION"
+           returnType="java.lang.String">
+      <parameter name="groupname"
+          description="Group name of the new group"
+                 type="java.lang.String"/>
+      <parameter name="description"
+          description="Description of the new group"
+                 type="java.lang.String"/>
+    </operation>
+
+    <operation   name="createRole"
+          description="Create new role and return MBean name"
+               impact="ACTION"
+           returnType="java.lang.String">
+      <parameter name="rolename"
+          description="Role name of the new role"
+                 type="java.lang.String"/>
+      <parameter name="description"
+          description="Description of the new role"
+                 type="java.lang.String"/>
+    </operation>
+
+    <operation   name="createUser"
+          description="Create new user and return MBean name"
+               impact="ACTION"
+           returnType="java.lang.String">
+      <parameter name="username"
+          description="User name of the new user"
+                 type="java.lang.String"/>
+      <parameter name="password"
+          description="Password of the new user"
+                 type="java.lang.String"/>
+      <parameter name="fullName"
+          description="Full name of the new user"
+                 type="java.lang.String"/>
+    </operation>
+
+    <operation   name="findGroup"
+          description="Return MBean Name of the specified group (if any)"
+               impact="INFO"
+           returnType="java.lang.String">
+      <parameter name="groupname"
+          description="Group name of the requested group"
+                 type="java.lang.String"/>
+    </operation>
+
+    <operation   name="findRole"
+          description="Return MBean Name of the specified role (if any)"
+               impact="INFO"
+           returnType="java.lang.String">
+      <parameter name="rolename"
+          description="Role name of the requested role"
+                 type="java.lang.String"/>
+    </operation>
+
+    <operation   name="findUser"
+          description="Return MBean Name of the specified user (if any)"
+               impact="INFO"
+           returnType="java.lang.String">
+      <parameter name="username"
+          description="User name of the requested user"
+                 type="java.lang.String"/>
+    </operation>
+
+    <operation   name="removeGroup"
+          description="Remove existing group (and all user memberships)"
+               impact="ACTION"
+           returnType="void">
+      <parameter name="groupname"
+          description="Group name of the group to remove"
+                 type="java.lang.String"/>
+    </operation>
+
+    <operation   name="removeRole"
+          description="Remove existing role"
+               impact="ACTION"
+           returnType="void">
+      <parameter name="rolename"
+          description="Role name of the role to remove"
+                 type="java.lang.String"/>
+    </operation>
+
+    <operation   name="removeUser"
+          description="Remove existing user (and all group memberships)"
+               impact="ACTION"
+           returnType="void">
+      <parameter name="username"
+          description="User name of the user to remove"
+                 type="java.lang.String"/>
+    </operation>
+
+    <operation   name="save"
+          description="Save current users and groups to persistent storage"
+               impact="ACTION"
+           returnType="void">
+    </operation>
+
+
+    <operation name="start" description="Start" impact="ACTION" returnType="void" />
+    <operation name="stop" description="Stop" impact="ACTION" returnType="void" />
+    <operation name="init" description="Init" impact="ACTION" returnType="void" />
+    <operation name="destroy" description="Destroy" impact="ACTION" returnType="void" />
+  </mbean>
+
+  <mbean         name="MemoryUserDatabase"
+            className="org.apache.catalina.mbeans.MemoryUserDatabaseMBean"
+          description="In-memory user and group database"
+               domain="Users"
+                group="UserDatabase"
+                 type="org.apache.catalina.users.MemoryUserDatabase">
+
+    <attribute   name="encoding"
+          description="Character encoding to use when writing XML file"
+                 type="java.lang.String"/>
+
+    <attribute   name="groups"
+          description="MBean Names of all defined groups"
+                 type="[Ljava.lang.String;"
+            writeable="false"/>
+
+    <attribute   name="pathname"
+          description="Relative or absolute pathname to database file"
+                 type="java.lang.String"/>
+
+    <attribute   name="roles"
+          description="MBean Names of all defined roles"
+                 type="[Ljava.lang.String;"
+            writeable="false"/>
+
+    <attribute   name="users"
+          description="MBean Names of all defined users"
+                 type="[Ljava.lang.String;"
+            writeable="false"/>
+
+    <attribute   name="readonly"
+          description="No persistant save of the user database"
+                 type="boolean"
+            writeable="false"/>
+
+    <attribute   name="writeable"
+          description="Check if user database is writeable"
+               impact="INFO"
+                   is="true"
+           writeable="false"/>
+
+    <operation   name="createGroup"
+          description="Create new group and return MBean name"
+               impact="ACTION"
+           returnType="java.lang.String">
+      <parameter name="groupname"
+          description="Group name of the new group"
+                 type="java.lang.String"/>
+      <parameter name="description"
+          description="Description of the new group"
+                 type="java.lang.String"/>
+    </operation>
+
+    <operation   name="createRole"
+          description="Create new role and return MBean name"
+               impact="ACTION"
+           returnType="java.lang.String">
+      <parameter name="rolename"
+          description="Role name of the new role"
+                 type="java.lang.String"/>
+      <parameter name="description"
+          description="Description of the new role"
+                 type="java.lang.String"/>
+    </operation>
+
+    <operation   name="createUser"
+          description="Create new user and return MBean name"
+               impact="ACTION"
+           returnType="java.lang.String">
+      <parameter name="username"
+          description="User name of the new user"
+                 type="java.lang.String"/>
+      <parameter name="password"
+          description="Password of the new user"
+                 type="java.lang.String"/>
+      <parameter name="fullName"
+          description="Full name of the new user"
+                 type="java.lang.String"/>
+    </operation>
+
+    <operation   name="findGroup"
+          description="Return MBean Name of the specified group (if any)"
+               impact="INFO"
+           returnType="java.lang.String">
+      <parameter name="groupname"
+          description="Group name of the requested group"
+                 type="java.lang.String"/>
+    </operation>
+
+    <operation   name="findRole"
+          description="Return MBean Name of the specified role (if any)"
+               impact="INFO"
+           returnType="java.lang.String">
+      <parameter name="rolename"
+          description="Role name of the requested role"
+                 type="java.lang.String"/>
+    </operation>
+
+    <operation   name="findUser"
+          description="Return MBean Name of the specified user (if any)"
+               impact="INFO"
+           returnType="java.lang.String">
+      <parameter name="username"
+          description="User name of the requested user"
+                 type="java.lang.String"/>
+    </operation>
+
+    <operation   name="removeGroup"
+          description="Remove existing group (and all user memberships)"
+               impact="ACTION"
+           returnType="void">
+      <parameter name="groupname"
+          description="Group name of the group to remove"
+                 type="java.lang.String"/>
+    </operation>
+
+    <operation   name="removeRole"
+          description="Remove existing role"
+               impact="ACTION"
+           returnType="void">
+      <parameter name="rolename"
+          description="Role name of the role to remove"
+                 type="java.lang.String"/>
+    </operation>
+
+    <operation   name="removeUser"
+          description="Remove existing user (and all group memberships)"
+               impact="ACTION"
+           returnType="void">
+      <parameter name="username"
+          description="User name of the user to remove"
+                 type="java.lang.String"/>
+    </operation>
+
+    <operation   name="save"
+          description="Save current users and groups to persistent storage"
+               impact="ACTION"
+           returnType="void">
+    </operation>
+
+
+    <operation name="start" description="Start" impact="ACTION" returnType="void" />
+    <operation name="stop" description="Stop" impact="ACTION" returnType="void" />
+    <operation name="init" description="Init" impact="ACTION" returnType="void" />
+    <operation name="destroy" description="Destroy" impact="ACTION" returnType="void" />
+  </mbean>
+
+
+</mbeans-descriptors>

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/Base64.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/Base64.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/Base64.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,286 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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 org.apache.tomcat.util.buf.ByteChunk;
+import org.apache.tomcat.util.buf.CharChunk;
+
+/**
+ * This class provides encode/decode for RFC 2045 Base64 as defined by
+ * RFC 2045, N. Freed and N. Borenstein.  <a
+ * href="http://www.ietf.org/rfc/rfc2045.txt">RFC 2045</a>:
+ * Multipurpose Internet Mail Extensions (MIME) Part One: Format of
+ * Internet Message Bodies. Reference 1996
+ *
+ * @author Jeffrey Rodriguez
+ * @version $Id: Base64.java 303133 2004-08-29 16:46:15Z yoavs $
+ */
+public final class  Base64
+{
+    static private final int  BASELENGTH         = 255;
+    static private final int  LOOKUPLENGTH       = 64;
+    static private final int  TWENTYFOURBITGROUP = 24;
+    static private final int  EIGHTBIT           = 8;
+    static private final int  SIXTEENBIT         = 16;
+    static private final int  SIXBIT             = 6;
+    static private final int  FOURBYTE           = 4;
+    static private final int  SIGN               = -128;
+    static private final byte PAD                = (byte) '=';
+    static private byte [] base64Alphabet       = new byte[BASELENGTH];
+    static private byte [] lookUpBase64Alphabet = new byte[LOOKUPLENGTH];
+    //static private final Log log = LogSource.getInstance("org.apache.commons.util.Base64");
+
+    static
+    {
+        for (int i = 0; i < BASELENGTH; i++ )
+        {
+            base64Alphabet[i] = -1;
+        }
+        for (int i = 'Z'; i >= 'A'; i--)
+        {
+            base64Alphabet[i] = (byte) (i - 'A');
+        }
+        for (int i = 'z'; i>= 'a'; i--)
+        {
+            base64Alphabet[i] = (byte) (i - 'a' + 26);
+        }
+        for (int i = '9'; i >= '0'; i--)
+        {
+            base64Alphabet[i] = (byte) (i - '0' + 52);
+        }
+
+        base64Alphabet['+']  = 62;
+        base64Alphabet['/']  = 63;
+
+        for (int i = 0; i <= 25; i++ )
+            lookUpBase64Alphabet[i] = (byte) ('A' + i);
+
+        for (int i = 26,  j = 0; i <= 51; i++, j++ )
+            lookUpBase64Alphabet[i] = (byte) ('a'+ j);
+
+        for (int i = 52,  j = 0; i <= 61; i++, j++ )
+            lookUpBase64Alphabet[i] = (byte) ('0' + j);
+
+        lookUpBase64Alphabet[62] = (byte) '+';
+        lookUpBase64Alphabet[63] = (byte) '/';
+    }
+
+    public static boolean isBase64( String isValidString )
+    {
+        return isArrayByteBase64(isValidString.getBytes());
+    }
+
+    public static boolean isBase64( byte octect )
+    {
+        //shall we ignore white space? JEFF??
+        return (octect == PAD || base64Alphabet[octect] != -1);
+    }
+
+    public static boolean isArrayByteBase64( byte[] arrayOctect )
+    {
+        int length = arrayOctect.length;
+        if (length == 0)
+        {
+            // shouldn't a 0 length array be valid base64 data?
+            // return false;
+            return true;
+        }
+        for (int i=0; i < length; i++)
+        {
+            if ( !Base64.isBase64(arrayOctect[i]) )
+                return false;
+        }
+        return true;
+    }
+
+    /**
+     * Encodes hex octects into Base64.
+     *
+     * @param binaryData Array containing binary data to encode.
+     * @return Base64-encoded data.
+     */
+    public static byte[] encode( byte[] binaryData )
+    {
+        int      lengthDataBits    = binaryData.length*EIGHTBIT;
+        int      fewerThan24bits   = lengthDataBits%TWENTYFOURBITGROUP;
+        int      numberTriplets    = lengthDataBits/TWENTYFOURBITGROUP;
+        byte     encodedData[]     = null;
+
+
+        if (fewerThan24bits != 0)
+        {
+            //data not divisible by 24 bit
+            encodedData = new byte[ (numberTriplets + 1 ) * 4 ];
+        }
+        else
+        {
+            // 16 or 8 bit
+            encodedData = new byte[ numberTriplets * 4 ];
+        }
+
+        byte k = 0, l = 0, b1 = 0, b2 = 0, b3 = 0;
+
+        int encodedIndex = 0;
+        int dataIndex   = 0;
+        int i           = 0;
+        //log.debug("number of triplets = " + numberTriplets);
+        for ( i = 0; i<numberTriplets; i++ )
+        {
+            dataIndex = i*3;
+            b1 = binaryData[dataIndex];
+            b2 = binaryData[dataIndex + 1];
+            b3 = binaryData[dataIndex + 2];
+
+            //log.debug("b1= " + b1 +", b2= " + b2 + ", b3= " + b3);
+
+            l  = (byte)(b2 & 0x0f);
+            k  = (byte)(b1 & 0x03);
+
+            encodedIndex = i * 4;
+            byte val1 = ((b1 & SIGN)==0)?(byte)(b1>>2):(byte)((b1)>>2^0xc0);
+            byte val2 = ((b2 & SIGN)==0)?(byte)(b2>>4):(byte)((b2)>>4^0xf0);
+            byte val3 = ((b3 & SIGN)==0)?(byte)(b3>>6):(byte)((b3)>>6^0xfc);
+
+            encodedData[encodedIndex]   = lookUpBase64Alphabet[ val1 ];
+            //log.debug( "val2 = " + val2 );
+            //log.debug( "k4   = " + (k<<4) );
+            //log.debug(  "vak  = " + (val2 | (k<<4)) );
+            encodedData[encodedIndex+1] =
+                lookUpBase64Alphabet[ val2 | ( k<<4 )];
+            encodedData[encodedIndex+2] =
+                lookUpBase64Alphabet[ (l <<2 ) | val3 ];
+            encodedData[encodedIndex+3] = lookUpBase64Alphabet[ b3 & 0x3f ];
+        }
+
+        // form integral number of 6-bit groups
+        dataIndex    = i*3;
+        encodedIndex = i*4;
+        if (fewerThan24bits == EIGHTBIT )
+        {
+            b1 = binaryData[dataIndex];
+            k = (byte) ( b1 &0x03 );
+            //log.debug("b1=" + b1);
+            //log.debug("b1<<2 = " + (b1>>2) );
+            byte val1 = ((b1 & SIGN)==0)?(byte)(b1>>2):(byte)((b1)>>2^0xc0);
+            encodedData[encodedIndex]     = lookUpBase64Alphabet[ val1 ];
+            encodedData[encodedIndex + 1] = lookUpBase64Alphabet[ k<<4 ];
+            encodedData[encodedIndex + 2] = PAD;
+            encodedData[encodedIndex + 3] = PAD;
+        }
+        else if (fewerThan24bits == SIXTEENBIT)
+        {
+
+            b1 = binaryData[dataIndex];
+            b2 = binaryData[dataIndex +1 ];
+            l = (byte) (b2 & 0x0f);
+            k = (byte) (b1 & 0x03);
+
+            byte val1 = ((b1 & SIGN) == 0)?(byte)(b1>>2):(byte)((b1)>>2^0xc0);
+            byte val2 = ((b2 & SIGN) == 0)?(byte)(b2>>4):(byte)((b2)>>4^0xf0);
+
+            encodedData[encodedIndex]     = lookUpBase64Alphabet[ val1 ];
+            encodedData[encodedIndex + 1] =
+                lookUpBase64Alphabet[ val2 | ( k<<4 )];
+            encodedData[encodedIndex + 2] = lookUpBase64Alphabet[ l<<2 ];
+            encodedData[encodedIndex + 3] = PAD;
+        }
+
+        return encodedData;
+    }
+
+    /**
+     * Decodes Base64 data into octects
+     *
+     * @param base64DataBC Byte array containing Base64 data
+     * @param decodedDataCC The decoded data chars
+     */
+    public static void decode( ByteChunk base64DataBC, CharChunk decodedDataCC)
+    {
+        int start = base64DataBC.getStart();
+        int end = base64DataBC.getEnd();
+        byte[] base64Data = base64DataBC.getBuffer();
+        
+        decodedDataCC.recycle();
+        
+        // handle the edge case, so we don't have to worry about it later
+        if(end - start == 0) { return; }
+
+        int      numberQuadruple    = (end - start)/FOURBYTE;
+        byte     b1=0,b2=0,b3=0, b4=0, marker0=0, marker1=0;
+
+        // Throw away anything not in base64Data
+
+        int encodedIndex = 0;
+        int dataIndex = start;
+        char[] decodedData = null;
+        
+        {
+            // this sizes the output array properly - rlw
+            int lastData = end - start;
+            // ignore the '=' padding
+            while (base64Data[start+lastData-1] == PAD)
+            {
+                if (--lastData == 0)
+                {
+                    return;
+                }
+            }
+            decodedDataCC.allocate(lastData - numberQuadruple, -1);
+            decodedDataCC.setEnd(lastData - numberQuadruple);
+            decodedData = decodedDataCC.getBuffer();
+        }
+
+        for (int i = 0; i < numberQuadruple; i++)
+        {
+            dataIndex = start + i * 4;
+            marker0   = base64Data[dataIndex + 2];
+            marker1   = base64Data[dataIndex + 3];
+
+            b1 = base64Alphabet[base64Data[dataIndex]];
+            b2 = base64Alphabet[base64Data[dataIndex +1]];
+
+            if (marker0 != PAD && marker1 != PAD)
+            {
+                //No PAD e.g 3cQl
+                b3 = base64Alphabet[ marker0 ];
+                b4 = base64Alphabet[ marker1 ];
+
+                decodedData[encodedIndex]   = (char) ((  b1 <<2 | b2>>4 ) & 0xff);
+                decodedData[encodedIndex + 1] =
+                    (char) ((((b2 & 0xf)<<4 ) |( (b3>>2) & 0xf) ) & 0xff);
+                decodedData[encodedIndex + 2] = (char) (( b3<<6 | b4 ) & 0xff);
+            }
+            else if (marker0 == PAD)
+            {
+                //Two PAD e.g. 3c[Pad][Pad]
+                decodedData[encodedIndex]   = (char) ((  b1 <<2 | b2>>4 ) & 0xff);
+            }
+            else if (marker1 == PAD)
+            {
+                //One PAD e.g. 3cQ[Pad]
+                b3 = base64Alphabet[ marker0 ];
+
+                decodedData[encodedIndex]   = (char) ((  b1 <<2 | b2>>4 ) & 0xff);
+                decodedData[encodedIndex + 1] =
+                    (char) ((((b2 & 0xf)<<4 ) |( (b3>>2) & 0xf) ) & 0xff);
+            }
+            encodedIndex += 3;
+        }
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/CGIProcessEnvironment.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/CGIProcessEnvironment.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/CGIProcessEnvironment.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,449 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.io.File;
+import java.net.URLEncoder;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.StringTokenizer;
+
+import javax.servlet.ServletContext;
+import javax.servlet.http.HttpServletRequest;
+
+
+/**
+ * Encapsulates the CGI Process' environment and rules to derive
+ * that environment from the servlet container and request information.
+ * @author   Martin Dengler [root at martindengler.com]
+ * @version  $Revision: 421480 $, $Date: 2006-07-12 21:26:36 -0500 (Wed, 12 Jul 2006) $
+ * @since    Tomcat 4.0
+ * @deprecated
+ */
+
+public class CGIProcessEnvironment extends ProcessEnvironment {
+    
+    
+    private static org.apache.commons.logging.Log log=
+        org.apache.commons.logging.LogFactory.getLog( CGIProcessEnvironment.class );
+    
+    /** cgi command's query parameters */
+    private Hashtable queryParameters = null;
+
+    /**
+     *  The CGI search path will start at
+     *    webAppRootDir + File.separator + cgiPathPrefix
+     *    (or webAppRootDir alone if cgiPathPrefix is
+     *    null)
+     */
+    private String cgiPathPrefix = null;
+
+
+    /**
+     * Creates a ProcessEnvironment and derives the necessary environment,
+     * working directory, command, etc.  The cgi path prefix is initialized
+     * to "" (the empty string).
+     *
+     * @param  req       HttpServletRequest for information provided by
+     *                   the Servlet API
+     * @param  context   ServletContext for information provided by
+     *                   the Servlet API
+     */
+    public CGIProcessEnvironment(HttpServletRequest req,
+        ServletContext context) {
+            this(req, context, "");
+    }
+
+
+
+    /**
+     * Creates a ProcessEnvironment and derives the necessary environment,
+     * working directory, command, etc.
+     * @param req             HttpServletRequest for information provided by
+     *                        the Servlet API
+     * @param context         ServletContext for information provided by
+     *                        the Servlet API
+     * @param cgiPathPrefix   subdirectory of webAppRootDir below which the
+     *                        web app's CGIs may be stored; can be null or "".
+     */
+    public CGIProcessEnvironment(HttpServletRequest req,
+        ServletContext context, String cgiPathPrefix) {
+            this(req, context, cgiPathPrefix, 0);
+    }
+
+
+
+    /**
+     * Creates a ProcessEnvironment and derives the necessary environment,
+     * working directory, command, etc.
+     * @param req             HttpServletRequest for information provided by
+     *                        the Servlet API
+     * @param context         ServletContext for information provided by
+     *                        the Servlet API
+     * @param  debug          int debug level (0 == none, 6 == lots)
+     */
+    public CGIProcessEnvironment(HttpServletRequest req,
+        ServletContext context, int debug) {
+            this(req, context, "", 0);
+    }
+
+
+
+
+    /**
+     * Creates a ProcessEnvironment and derives the necessary environment,
+     * working directory, command, etc.
+     * @param req             HttpServletRequest for information provided by
+     *                        the Servlet API
+     * @param context         ServletContext for information provided by
+     *                        the Servlet API
+     * @param cgiPathPrefix   subdirectory of webAppRootDir below which the
+     *                        web app's CGIs may be stored; can be null or "".
+     * @param  debug          int debug level (0 == none, 6 == lots)
+     */
+    public CGIProcessEnvironment(HttpServletRequest req,
+        ServletContext context, String cgiPathPrefix, int debug) {
+            super(req, context, debug);
+            this.cgiPathPrefix = cgiPathPrefix;
+            queryParameters = new Hashtable();
+            Enumeration paramNames = req.getParameterNames();
+            while (paramNames != null && paramNames.hasMoreElements()) {
+                String param = paramNames.nextElement().toString();
+                if (param != null) {
+                    queryParameters.put(param,
+                        URLEncoder.encode(req.getParameter(param)));
+                }
+            }
+            this.valid = deriveProcessEnvironment(req);
+    }
+
+
+
+    /**
+     * Constructs the CGI environment to be supplied to the invoked CGI
+     * script; relies heavliy on Servlet API methods and findCGI
+     * @param    req request associated with the CGI invokation
+     * @return   true if environment was set OK, false if there was a problem
+     *           and no environment was set
+     */
+    protected boolean deriveProcessEnvironment(HttpServletRequest req) {
+        /*
+         * This method is slightly ugly; c'est la vie.
+         * "You cannot stop [ugliness], you can only hope to contain [it]"
+         * (apologies to Marv Albert regarding MJ)
+         */
+
+        Hashtable envp;
+        super.deriveProcessEnvironment(req);
+        envp = getEnvironment();
+
+        String sPathInfoOrig = null;
+        String sPathTranslatedOrig = null;
+        String sPathInfoCGI = null;
+        String sPathTranslatedCGI = null;
+        String sCGIFullPath = null;
+        String sCGIScriptName = null;
+        String sCGIFullName = null;
+        String sCGIName = null;
+        String[] sCGINames;
+        sPathInfoOrig = this.pathInfo;
+        sPathInfoOrig = sPathInfoOrig == null ? "" : sPathInfoOrig;
+        sPathTranslatedOrig = req.getPathTranslated();
+        sPathTranslatedOrig = sPathTranslatedOrig == null ? "" :
+            sPathTranslatedOrig;
+            sCGINames =
+                findCGI(sPathInfoOrig, getWebAppRootDir(), getContextPath(),
+                getServletPath(), cgiPathPrefix);
+        sCGIFullPath = sCGINames[0];
+        sCGIScriptName = sCGINames[1];
+        sCGIFullName = sCGINames[2];
+        sCGIName = sCGINames[3];
+        if (sCGIFullPath == null || sCGIScriptName == null
+            || sCGIFullName == null || sCGIName == null) {
+                return false;
+        }
+        envp.put("SERVER_SOFTWARE", "TOMCAT");
+        envp.put("SERVER_NAME", nullsToBlanks(req.getServerName()));
+        envp.put("GATEWAY_INTERFACE", "CGI/1.1");
+        envp.put("SERVER_PROTOCOL", nullsToBlanks(req.getProtocol()));
+        int port = req.getServerPort();
+        Integer iPort = (port == 0 ? new Integer(-1) : new Integer(port));
+        envp.put("SERVER_PORT", iPort.toString());
+        envp.put("REQUEST_METHOD", nullsToBlanks(req.getMethod()));
+
+        /*-
+        * PATH_INFO should be determined by using sCGIFullName:
+        * 1) Let sCGIFullName not end in a "/" (see method findCGI)
+        * 2) Let sCGIFullName equal the pathInfo fragment which
+        *    corresponds to the actual cgi script.
+        * 3) Thus, PATH_INFO = request.getPathInfo().substring(
+        *                      sCGIFullName.length())
+        *
+        * (see method findCGI, where the real work is done)
+        *
+        */
+
+        if (pathInfo == null ||
+            (pathInfo.substring(sCGIFullName.length()).length() <= 0)) {
+                sPathInfoCGI = "";
+        } else {
+            sPathInfoCGI = pathInfo.substring(sCGIFullName.length());
+        }
+        envp.put("PATH_INFO", sPathInfoCGI);
+
+        /*-
+        * PATH_TRANSLATED must be determined after PATH_INFO (and the
+        * implied real cgi-script) has been taken into account.
+        *
+        * The following example demonstrates:
+        *
+        * servlet info   = /servlet/cgigw/dir1/dir2/cgi1/trans1/trans2
+        * cgifullpath    = /servlet/cgigw/dir1/dir2/cgi1
+        * path_info      = /trans1/trans2
+        * webAppRootDir  = servletContext.getRealPath("/")
+        *
+        * path_translated = servletContext.getRealPath("/trans1/trans2")
+        *
+        * That is, PATH_TRANSLATED = webAppRootDir + sPathInfoCGI
+        * (unless sPathInfoCGI is null or blank, then the CGI
+        * specification dictates that the PATH_TRANSLATED metavariable
+        * SHOULD NOT be defined.
+        *
+        */
+
+        if (sPathInfoCGI != null && !("".equals(sPathInfoCGI))) {
+            sPathTranslatedCGI = getContext().getRealPath(sPathInfoCGI);
+        } else {
+            sPathTranslatedCGI = null;
+        }
+        if (sPathTranslatedCGI == null || "".equals(sPathTranslatedCGI)) {
+            //NOOP
+        } else {
+            envp.put("PATH_TRANSLATED", nullsToBlanks(sPathTranslatedCGI));
+        }
+        envp.put("SCRIPT_NAME", nullsToBlanks(sCGIScriptName));
+        envp.put("QUERY_STRING", nullsToBlanks(req.getQueryString()));
+        envp.put("REMOTE_HOST", nullsToBlanks(req.getRemoteHost()));
+        envp.put("REMOTE_ADDR", nullsToBlanks(req.getRemoteAddr()));
+        envp.put("AUTH_TYPE", nullsToBlanks(req.getAuthType()));
+        envp.put("REMOTE_USER", nullsToBlanks(req.getRemoteUser()));
+        envp.put("REMOTE_IDENT", ""); //not necessary for full compliance
+        envp.put("CONTENT_TYPE", nullsToBlanks(req.getContentType()));
+
+        /* Note CGI spec says CONTENT_LENGTH must be NULL ("") or undefined
+        * if there is no content, so we cannot put 0 or -1 in as per the
+        * Servlet API spec.
+        */
+
+        int contentLength = req.getContentLength();
+        String sContentLength = (contentLength <= 0 ? "" : (
+            new Integer(contentLength)).toString());
+        envp.put("CONTENT_LENGTH", sContentLength);
+        Enumeration headers = req.getHeaderNames();
+        String header = null;
+        while (headers.hasMoreElements()) {
+            header = null;
+            header = ((String)headers.nextElement()).toUpperCase();
+            //REMIND: rewrite multiple headers as if received as single
+            //REMIND: change character set
+            //REMIND: I forgot what the previous REMIND means
+            if ("AUTHORIZATION".equalsIgnoreCase(header)
+                || "PROXY_AUTHORIZATION".equalsIgnoreCase(header)) {
+                    //NOOP per CGI specification section 11.2
+            } else if ("HOST".equalsIgnoreCase(header)) {
+                String host = req.getHeader(header);
+                envp.put("HTTP_" + header.replace('-', '_'),
+                    host.substring(0, host.indexOf(":")));
+            } else {
+                envp.put("HTTP_" + header.replace('-', '_'),
+                    req.getHeader(header));
+            }
+        }
+        command = sCGIFullPath;
+        workingDirectory = new File(command.substring(0,
+            command.lastIndexOf(File.separator)));
+        envp.put("X_TOMCAT_COMMAND_PATH", command); //for kicks
+        this.setEnvironment(envp);
+        return true;
+    }
+
+
+    /**
+     * Resolves core information about the cgi script. <p> Example URI:
+     * <PRE> /servlet/cgigateway/dir1/realCGIscript/pathinfo1 </PRE> <ul>
+     * <LI><b>path</b> = $CATALINA_HOME/mywebapp/dir1/realCGIscript
+     * <LI><b>scriptName</b> = /servlet/cgigateway/dir1/realCGIscript</LI>
+     * <LI><b>cgiName</b> = /dir1/realCGIscript
+     * <LI><b>name</b> = realCGIscript
+     * </ul>
+     * </p>
+     * <p>
+     * CGI search algorithm: search the real path below
+     * &lt;my-webapp-root&gt; and find the first non-directory in
+     * the getPathTranslated("/"), reading/searching from left-to-right.
+     * </p>
+     * <p>
+     * The CGI search path will start at
+     * webAppRootDir + File.separator + cgiPathPrefix (or webAppRootDir
+     * alone if cgiPathPrefix is null).
+     * </p>
+     * <p>
+     * cgiPathPrefix is usually set by the calling servlet to the servlet's
+     * cgiPathPrefix init parameter
+     * </p>
+     *
+     * @param pathInfo       String from HttpServletRequest.getPathInfo()
+     * @param webAppRootDir  String from context.getRealPath("/")
+     * @param contextPath    String as from HttpServletRequest.getContextPath()
+     * @param servletPath    String as from HttpServletRequest.getServletPath()
+     * @param cgiPathPrefix  subdirectory of webAppRootDir below which the
+     *                       web app's CGIs may be stored; can be null.
+     * @return
+     * <ul> <li> <code>path</code>  -    full file-system path to valid cgi
+     *                                   script, or null if no cgi was found
+     * <li> <code>scriptName</code> -    CGI variable SCRIPT_NAME; the full
+     *                                   URL path to valid cgi script or
+     *                                   null if no cgi was found
+     * <li> <code>cgiName</code>    -    servlet pathInfo fragment
+     *                                   corresponding to the cgi script
+     *                                   itself, or null if not found
+     * <li> <code>name</code>       -    simple name (no directories) of
+     *                                   the cgi script, or null if no cgi
+     *                                   was found
+     * </ul>
+     * @since Tomcat 4.0
+     */
+    protected String[] findCGI(String pathInfo, String webAppRootDir,
+        String contextPath, String servletPath, String cgiPathPrefix) {
+            String path = null;
+            String name = null;
+            String scriptname = null;
+            String cginame = null;
+            if ((webAppRootDir != null)
+                && (webAppRootDir.lastIndexOf("/")
+                == (webAppRootDir.length() - 1))) {
+                    //strip the trailing "/" from the webAppRootDir
+                    webAppRootDir =
+                        webAppRootDir.substring(0,
+                        (webAppRootDir.length() - 1));
+            }
+            if (cgiPathPrefix != null) {
+                webAppRootDir = webAppRootDir + File.separator
+                    + cgiPathPrefix;
+            }
+            
+            if (log.isDebugEnabled()) {
+                log.debug("findCGI: start = [" + webAppRootDir
+                    + "], pathInfo = [" + pathInfo + "] ");
+            }
+            File currentLocation = new File(webAppRootDir);
+            StringTokenizer dirWalker = new StringTokenizer(pathInfo, "/");
+            while (!currentLocation.isFile() && dirWalker.hasMoreElements()) {
+                currentLocation = new
+                    File(currentLocation, (String) dirWalker.nextElement());
+                if (log.isDebugEnabled())  {
+                    log.debug("findCGI: traversing to [" + currentLocation + "]");
+                }
+            }
+            if (!currentLocation.isFile()) {
+                return new String[] { null, null, null, null };
+            } else {
+                if (log.isDebugEnabled())  {
+                    log.debug("findCGI: FOUND cgi at [" + currentLocation + "]");
+                }
+                path = currentLocation.getAbsolutePath();
+                name = currentLocation.getName();
+                cginame = currentLocation.getParent()
+                    .substring(webAppRootDir.length())
+                    + File.separator + name;
+                    if (".".equals(contextPath)) {
+                        scriptname = servletPath + cginame;
+                } else {
+                    scriptname = contextPath + servletPath + cginame;
+                }
+            }
+            if (log.isDebugEnabled())  {
+                log.debug("findCGI calc: name=" + name + ", path=" + path
+                    + ", scriptname=" + scriptname + ", cginame=" + cginame);
+            }
+            return new String[] { path, scriptname, cginame, name };
+    }
+
+
+    /**
+     * Print important CGI environment information in an
+     * easy-to-read HTML table
+     * @return  HTML string containing CGI environment info
+     */
+    public String toString() {
+        StringBuffer sb = new StringBuffer();
+        sb.append("<TABLE border=2>");
+        sb.append("<tr><th colspan=2 bgcolor=grey>");
+        sb.append("ProcessEnvironment Info</th></tr>");
+        sb.append("<tr><td>Debug Level</td><td>");
+        sb.append(debug);
+        sb.append("</td></tr>");
+        sb.append("<tr><td>Validity:</td><td>");
+        sb.append(isValid());
+        sb.append("</td></tr>");
+        if (isValid()) {
+            Enumeration envk = env.keys();
+            while (envk.hasMoreElements()) {
+                String s = (String)envk.nextElement();
+                sb.append("<tr><td>");
+                sb.append(s);
+                sb.append("</td><td>");
+                sb.append(blanksToString((String)env.get(s),
+                    "[will be set to blank]"));
+                    sb.append("</td></tr>");
+            }
+        }
+        sb.append("<tr><td colspan=2><HR></td></tr>");
+        sb.append("<tr><td>Derived Command</td><td>");
+        sb.append(nullsToBlanks(command));
+        sb.append("</td></tr>");
+        sb.append("<tr><td>Working Directory</td><td>");
+        if (workingDirectory != null) {
+            sb.append(workingDirectory.toString());
+        }
+        sb.append("</td></tr>");
+        sb.append("<tr><td colspan=2>Query Params</td></tr>");
+        Enumeration paramk = queryParameters.keys();
+        while (paramk.hasMoreElements()) {
+            String s = paramk.nextElement().toString();
+            sb.append("<tr><td>");
+            sb.append(s);
+            sb.append("</td><td>");
+            sb.append(queryParameters.get(s).toString());
+            sb.append("</td></tr>");
+        }
+
+        sb.append("</TABLE><p>end.");
+        return sb.toString();
+    }
+
+
+    /**
+     * Gets process' derived query parameters
+     * @return   process' query parameters
+     */
+    public Hashtable getParameters() {
+        return queryParameters;
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/CharsetMapper.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/CharsetMapper.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/CharsetMapper.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,131 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.io.InputStream;
+import java.util.Locale;
+import java.util.Properties;
+
+
+
+/**
+ * Utility class that attempts to map from a Locale to the corresponding
+ * character set to be used for interpreting input text (or generating
+ * output text) when the Content-Type header does not include one.  You
+ * can customize the behavior of this class by modifying the mapping data
+ * it loads, or by subclassing it (to change the algorithm) and then using
+ * your own version for a particular web application.
+ *
+ * @author Craig R. McClanahan
+ * @version $Date: 2005-01-05 04:00:45 -0600 (Wed, 05 Jan 2005) $ $Version$
+ */
+
+public class CharsetMapper {
+
+
+    // ---------------------------------------------------- Manifest Constants
+
+
+    /**
+     * Default properties resource name.
+     */
+    public static final String DEFAULT_RESOURCE =
+      "/org/apache/catalina/util/CharsetMapperDefault.properties";
+
+
+    // ---------------------------------------------------------- Constructors
+
+
+    /**
+     * Construct a new CharsetMapper using the default properties resource.
+     */
+    public CharsetMapper() {
+        this(DEFAULT_RESOURCE);
+    }
+
+
+    /**
+     * Construct a new CharsetMapper using the specified properties resource.
+     *
+     * @param name Name of a properties resource to be loaded
+     *
+     * @exception IllegalArgumentException if the specified properties
+     *  resource could not be loaded for any reason.
+     */
+    public CharsetMapper(String name) {
+        try {
+            InputStream stream =
+              this.getClass().getResourceAsStream(name);
+            map.load(stream);
+            stream.close();
+        } catch (Throwable t) {
+            throw new IllegalArgumentException(t.toString());
+        }
+    }
+
+
+    // ---------------------------------------------------- Instance Variables
+
+
+    /**
+     * The mapping properties that have been initialized from the specified or
+     * default properties resource.
+     */
+    private Properties map = new Properties();
+
+
+    // ------------------------------------------------------- Public Methods
+
+
+    /**
+     * Calculate the name of a character set to be assumed, given the specified
+     * Locale and the absence of a character set specified as part of the
+     * content type header.
+     *
+     * @param locale The locale for which to calculate a character set
+     */
+    public String getCharset(Locale locale) {
+        // Match full language_country_variant first, then language_country, 
+        // then language only
+        String charset = map.getProperty(locale.toString());
+        if (charset == null) {
+            charset = map.getProperty(locale.getLanguage() + "_" 
+                    + locale.getCountry());
+            if (charset == null) {
+                charset = map.getProperty(locale.getLanguage());
+            }
+        }
+        return (charset);
+    }
+
+    
+    /**
+     * The deployment descriptor can have a
+     * locale-encoding-mapping-list element which describes the
+     * webapp's desired mapping from locale to charset.  This method
+     * gets called when processing the web.xml file for a context
+     *
+     * @param locale The locale for a character set
+     * @param charset The charset to be associated with the locale
+     */
+    public void addCharsetMappingFromDeploymentDescriptor(String locale, String charset) {
+        map.put(locale, charset);
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/CharsetMapperDefault.properties
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/CharsetMapperDefault.properties	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/CharsetMapperDefault.properties	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,2 @@
+en=ISO-8859-1
+fr=ISO-8859-1

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/CookieTools.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/CookieTools.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/CookieTools.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,158 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.text.*;
+import java.util.*;
+
+import javax.servlet.http.Cookie;
+
+// XXX use only one Date instance/request, reuse it.
+
+/**
+ * Cookie utils - generate cookie header, etc
+ *
+ * @author Original Author Unknown
+ * @author duncan at eng.sun.com
+ */
+public class CookieTools {
+
+    /** Return the header name to set the cookie, based on cookie
+     *  version
+     */
+    public static String getCookieHeaderName(Cookie cookie) {
+        int version = cookie.getVersion();
+
+        if (version == 1) {
+            return "Set-Cookie2";
+        } else {
+            return "Set-Cookie";
+        }
+    }
+
+    /** Return the header value used to set this cookie
+     *  @deprecated Use StringBuffer version
+     */
+    public static String getCookieHeaderValue(Cookie cookie) {
+        StringBuffer buf = new StringBuffer();
+        getCookieHeaderValue( cookie, buf );
+        return buf.toString();
+    }
+
+    /** Return the header value used to set this cookie
+     */
+    public static void getCookieHeaderValue(Cookie cookie, StringBuffer buf) {
+        int version = cookie.getVersion();
+
+        // this part is the same for all cookies
+
+        String name = cookie.getName();     // Avoid NPE on malformed cookies
+        if (name == null)
+            name = "";
+        String value = cookie.getValue();
+        if (value == null)
+            value = "";
+        
+        buf.append(name);
+        buf.append("=");
+        maybeQuote(version, buf, value);
+
+        // add version 1 specific information
+        if (version == 1) {
+            // Version=1 ... required
+            buf.append ("; Version=1");
+
+            // Comment=comment
+            if (cookie.getComment() != null) {
+                buf.append ("; Comment=");
+                maybeQuote (version, buf, cookie.getComment());
+            }
+        }
+
+        // add domain information, if present
+
+        if (cookie.getDomain() != null) {
+            buf.append("; Domain=");
+            maybeQuote (version, buf, cookie.getDomain());
+        }
+
+        // Max-Age=secs/Discard ... or use old "Expires" format
+        if (cookie.getMaxAge() >= 0) {
+            if (version == 0) {
+                buf.append ("; Expires=");
+                if (cookie.getMaxAge() == 0)
+                    DateTool.oldCookieFormat.format(new Date(10000), buf,
+                                                    new FieldPosition(0));
+                else
+                    DateTool.oldCookieFormat.format
+                        (new Date( System.currentTimeMillis() +
+                                   cookie.getMaxAge() *1000L), buf,
+                         new FieldPosition(0));
+            } else {
+                buf.append ("; Max-Age=");
+                buf.append (cookie.getMaxAge());
+            }
+        } else if (version == 1)
+          buf.append ("; Discard");
+
+        // Path=path
+        if (cookie.getPath() != null) {
+            buf.append ("; Path=");
+            maybeQuote (version, buf, cookie.getPath());
+        }
+
+        // Secure
+        if (cookie.getSecure()) {
+          buf.append ("; Secure");
+        }
+    }
+
+    static void maybeQuote (int version, StringBuffer buf,
+                                    String value)
+    {
+        if (version == 0 || isToken (value))
+            buf.append (value);
+        else {
+            buf.append ('"');
+            buf.append (value);
+            buf.append ('"');
+        }
+    }
+
+        //
+    // from RFC 2068, token special case characters
+    //
+    private static final String tspecials = "()<>@,;:\\\"/[]?={} \t";
+
+    /*
+     * Return true iff the string counts as an HTTP/1.1 "token".
+     */
+    private static boolean isToken (String value) {
+        int len = value.length ();
+
+        for (int i = 0; i < len; i++) {
+            char c = value.charAt (i);
+
+            if (c < 0x20 || c >= 0x7f || tspecials.indexOf (c) != -1)
+              return false;
+        }
+        return true;
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/CustomObjectInputStream.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/CustomObjectInputStream.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/CustomObjectInputStream.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,101 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.io.InputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectStreamClass;
+import java.lang.reflect.Proxy;
+
+/**
+ * Custom subclass of <code>ObjectInputStream</code> that loads from the
+ * class loader for this web application.  This allows classes defined only
+ * with the web application to be found correctly.
+ *
+ * @author Craig R. McClanahan
+ * @author Bip Thelin
+ * @version $Revision: 304082 $, $Date: 2005-09-08 10:41:11 -0500 (Thu, 08 Sep 2005) $
+ */
+
+public final class CustomObjectInputStream
+    extends ObjectInputStream {
+
+
+    /**
+     * The class loader we will use to resolve classes.
+     */
+    private ClassLoader classLoader = null;
+
+
+    /**
+     * Construct a new instance of CustomObjectInputStream
+     *
+     * @param stream The input stream we will read from
+     * @param classLoader The class loader used to instantiate objects
+     *
+     * @exception IOException if an input/output error occurs
+     */
+    public CustomObjectInputStream(InputStream stream,
+                                   ClassLoader classLoader)
+        throws IOException {
+
+        super(stream);
+        this.classLoader = classLoader;
+    }
+
+
+    /**
+     * Load the local class equivalent of the specified stream class
+     * description, by using the class loader assigned to this Context.
+     *
+     * @param classDesc Class description from the input stream
+     *
+     * @exception ClassNotFoundException if this class cannot be found
+     * @exception IOException if an input/output error occurs
+     */
+    public Class resolveClass(ObjectStreamClass classDesc)
+        throws ClassNotFoundException, IOException {
+        try {
+            return Class.forName(classDesc.getName(), false, classLoader);
+        } catch (ClassNotFoundException e) {
+            // Try also the superclass because of primitive types
+            return super.resolveClass(classDesc);
+        }
+    }
+
+
+    /**
+     * Return a proxy class that implements the interfaces named in a proxy
+     * class descriptor. Do this using the class loader assigned to this
+     * Context.
+     */
+    protected Class resolveProxyClass(String[] interfaces)
+        throws IOException, ClassNotFoundException {
+
+        Class[] cinterfaces = new Class[interfaces.length];
+        for (int i = 0; i < interfaces.length; i++)
+            cinterfaces[i] = classLoader.loadClass(interfaces[i]);
+
+        try {
+            return Proxy.getProxyClass(classLoader, cinterfaces);
+        } catch (IllegalArgumentException e) {
+            throw new ClassNotFoundException(null, e);
+        }
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/DOMWriter.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/DOMWriter.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/DOMWriter.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,348 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.io.OutputStreamWriter;
+import java.io.PrintWriter;
+import java.io.UnsupportedEncodingException;
+import java.io.Writer;
+
+import org.w3c.dom.Attr;
+import org.w3c.dom.Document;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+/**
+ * A sample DOM writer. This sample program illustrates how to
+ * traverse a DOM tree in order to print a document that is parsed.
+ */
+public class DOMWriter {
+
+   //
+   // Data
+   //
+
+   /** Default Encoding */
+   private static  String
+   PRINTWRITER_ENCODING = "UTF8";
+
+   private static String MIME2JAVA_ENCODINGS[] =
+    { "Default", "UTF-8", "US-ASCII", "ISO-8859-1", "ISO-8859-2", "ISO-8859-3", "ISO-8859-4",
+      "ISO-8859-5", "ISO-8859-6", "ISO-8859-7", "ISO-8859-8", "ISO-8859-9", "ISO-2022-JP",
+      "SHIFT_JIS", "EUC-JP","GB2312", "BIG5", "EUC-KR", "ISO-2022-KR", "KOI8-R", "EBCDIC-CP-US",
+      "EBCDIC-CP-CA", "EBCDIC-CP-NL", "EBCDIC-CP-DK", "EBCDIC-CP-NO", "EBCDIC-CP-FI", "EBCDIC-CP-SE",
+      "EBCDIC-CP-IT", "EBCDIC-CP-ES", "EBCDIC-CP-GB", "EBCDIC-CP-FR", "EBCDIC-CP-AR1",
+      "EBCDIC-CP-HE", "EBCDIC-CP-CH", "EBCDIC-CP-ROECE","EBCDIC-CP-YU",
+      "EBCDIC-CP-IS", "EBCDIC-CP-AR2", "UTF-16"
+    };
+
+   /** Output qualified names */
+   private boolean qualifiedNames = true;
+
+   /** Print writer. */
+   protected PrintWriter out;
+
+   /** Canonical output. */
+   protected boolean canonical;
+
+
+   public DOMWriter(String encoding, boolean canonical)
+   throws UnsupportedEncodingException {
+      out = new PrintWriter(new OutputStreamWriter(System.out, encoding));
+      this.canonical = canonical;
+   } // <init>(String,boolean)
+
+   //
+   // Constructors
+   //
+
+   /** Default constructor. */
+   public DOMWriter(boolean canonical) throws UnsupportedEncodingException {
+      this( getWriterEncoding(), canonical);
+   }
+
+    public DOMWriter(Writer writer, boolean canonical) {
+        out = new PrintWriter(writer);
+        this.canonical = canonical;
+    }
+
+   public boolean getQualifiedNames() {
+      return this.qualifiedNames;
+   }
+
+   public void setQualifiedNames(boolean qualifiedNames) {
+      this.qualifiedNames = qualifiedNames;
+   }
+
+   public static String getWriterEncoding( ) {
+      return (PRINTWRITER_ENCODING);
+   }// getWriterEncoding
+
+   public static void  setWriterEncoding( String encoding ) {
+      if( encoding.equalsIgnoreCase( "DEFAULT" ) )
+         PRINTWRITER_ENCODING  = "UTF8";
+      else if( encoding.equalsIgnoreCase( "UTF-16" ) )
+         PRINTWRITER_ENCODING  = "Unicode";
+      else
+         PRINTWRITER_ENCODING = MIME2Java.convert( encoding );
+   }// setWriterEncoding
+
+
+   public static boolean isValidJavaEncoding( String encoding ) {
+      for ( int i = 0; i < MIME2JAVA_ENCODINGS.length; i++ )
+         if ( encoding.equals( MIME2JAVA_ENCODINGS[i] ) )
+            return (true);
+
+      return (false);
+   }// isValidJavaEncoding
+
+
+   /** Prints the specified node, recursively. */
+   public void print(Node node) {
+
+      // is there anything to do?
+      if ( node == null ) {
+         return;
+      }
+
+      int type = node.getNodeType();
+      switch ( type ) {
+         // print document
+         case Node.DOCUMENT_NODE: {
+               if ( !canonical ) {
+                  String  Encoding = getWriterEncoding();
+                  if( Encoding.equalsIgnoreCase( "DEFAULT" ) )
+                     Encoding = "UTF-8";
+                  else if( Encoding.equalsIgnoreCase( "Unicode" ) )
+                     Encoding = "UTF-16";
+                  else
+                     Encoding = MIME2Java.reverse( Encoding );
+
+                  out.println("<?xml version=\"1.0\" encoding=\""+
+                           Encoding + "\"?>");
+               }
+               print(((Document)node).getDocumentElement());
+               out.flush();
+               break;
+            }
+
+            // print element with attributes
+         case Node.ELEMENT_NODE: {
+               out.print('<');
+               if (this.qualifiedNames) { 
+                  out.print(node.getNodeName());
+               } else {
+                  out.print(node.getLocalName());
+               }
+               Attr attrs[] = sortAttributes(node.getAttributes());
+               for ( int i = 0; i < attrs.length; i++ ) {
+                  Attr attr = attrs[i];
+                  out.print(' ');
+                  if (this.qualifiedNames) {
+                     out.print(attr.getNodeName());
+                  } else {
+                     out.print(attr.getLocalName());
+                  }
+                  
+                  out.print("=\"");
+                  out.print(normalize(attr.getNodeValue()));
+                  out.print('"');
+               }
+               out.print('>');
+               NodeList children = node.getChildNodes();
+               if ( children != null ) {
+                  int len = children.getLength();
+                  for ( int i = 0; i < len; i++ ) {
+                     print(children.item(i));
+                  }
+               }
+               break;
+            }
+
+            // handle entity reference nodes
+         case Node.ENTITY_REFERENCE_NODE: {
+               if ( canonical ) {
+                  NodeList children = node.getChildNodes();
+                  if ( children != null ) {
+                     int len = children.getLength();
+                     for ( int i = 0; i < len; i++ ) {
+                        print(children.item(i));
+                     }
+                  }
+               } else {
+                  out.print('&');
+                  if (this.qualifiedNames) {
+                     out.print(node.getNodeName());
+                  } else {
+                     out.print(node.getLocalName());
+                  }
+                  out.print(';');
+               }
+               break;
+            }
+
+            // print cdata sections
+         case Node.CDATA_SECTION_NODE: {
+               if ( canonical ) {
+                  out.print(normalize(node.getNodeValue()));
+               } else {
+                  out.print("<![CDATA[");
+                  out.print(node.getNodeValue());
+                  out.print("]]>");
+               }
+               break;
+            }
+
+            // print text
+         case Node.TEXT_NODE: {
+               out.print(normalize(node.getNodeValue()));
+               break;
+            }
+
+            // print processing instruction
+         case Node.PROCESSING_INSTRUCTION_NODE: {
+               out.print("<?");
+               if (this.qualifiedNames) {
+                  out.print(node.getNodeName());
+               } else {
+                  out.print(node.getLocalName());
+               }
+               
+               String data = node.getNodeValue();
+               if ( data != null && data.length() > 0 ) {
+                  out.print(' ');
+                  out.print(data);
+               }
+               out.print("?>");
+               break;
+            }
+      }
+
+      if ( type == Node.ELEMENT_NODE ) {
+         out.print("</");
+         if (this.qualifiedNames) {
+            out.print(node.getNodeName());
+         } else {
+            out.print(node.getLocalName());
+         }
+         out.print('>');
+      }
+
+      out.flush();
+
+   } // print(Node)
+
+   /** Returns a sorted list of attributes. */
+   protected Attr[] sortAttributes(NamedNodeMap attrs) {
+
+      int len = (attrs != null) ? attrs.getLength() : 0;
+      Attr array[] = new Attr[len];
+      for ( int i = 0; i < len; i++ ) {
+         array[i] = (Attr)attrs.item(i);
+      }
+      for ( int i = 0; i < len - 1; i++ ) {
+         String name = null;
+         if (this.qualifiedNames) {
+            name  = array[i].getNodeName();
+         } else {
+            name  = array[i].getLocalName();
+         }
+         int    index = i;
+         for ( int j = i + 1; j < len; j++ ) {
+            String curName = null;
+            if (this.qualifiedNames) {
+               curName = array[j].getNodeName();
+            } else {
+               curName = array[j].getLocalName();
+            }
+            if ( curName.compareTo(name) < 0 ) {
+               name  = curName;
+               index = j;
+            }
+         }
+         if ( index != i ) {
+            Attr temp    = array[i];
+            array[i]     = array[index];
+            array[index] = temp;
+         }
+      }
+
+      return (array);
+
+   } // sortAttributes(NamedNodeMap):Attr[]
+
+
+   /** Normalizes the given string. */
+   protected String normalize(String s) {
+      StringBuffer str = new StringBuffer();
+
+      int len = (s != null) ? s.length() : 0;
+      for ( int i = 0; i < len; i++ ) {
+         char ch = s.charAt(i);
+         switch ( ch ) {
+            case '<': {
+                  str.append("&lt;");
+                  break;
+               }
+            case '>': {
+                  str.append("&gt;");
+                  break;
+               }
+            case '&': {
+                  str.append("&amp;");
+                  break;
+               }
+            case '"': {
+                  str.append("&quot;");
+                  break;
+               }
+            case '\r':
+            case '\n': {
+                  if ( canonical ) {
+                     str.append("&#");
+                     str.append(Integer.toString(ch));
+                     str.append(';');
+                     break;
+                  }
+                  // else, default append char
+               }
+            default: {
+                  str.append(ch);
+               }
+         }
+      }
+
+      return (str.toString());
+
+   } // normalize(String):String
+
+   private static void printValidJavaEncoding() {
+      System.err.println( "    ENCODINGS:" );
+      System.err.print( "   " );
+      for( int i = 0;
+                     i < MIME2JAVA_ENCODINGS.length; i++) {
+         System.err.print( MIME2JAVA_ENCODINGS[i] + " " );
+      if( (i % 7 ) == 0 ){
+         System.err.println();
+         System.err.print( "   " );
+         }
+      }
+
+   } // printJavaEncoding()
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/DateTool.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/DateTool.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/DateTool.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,98 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.Locale;
+import java.util.TimeZone;
+
+/**
+ *  Common place for date utils.
+ *
+ * @author dac at eng.sun.com
+ * @author Jason Hunter [jch at eng.sun.com]
+ * @author James Todd [gonzo at eng.sun.com]
+ * @author Costin Manolache
+ */
+public class DateTool {
+
+    private static StringManager sm =
+        StringManager.getManager("org.apache.catalina.util");
+
+    /**
+     * US locale - all HTTP dates are in english
+     */
+    public final static Locale LOCALE_US = Locale.US;
+
+    /**
+     * GMT timezone - all HTTP dates are on GMT
+     */
+    public final static TimeZone GMT_ZONE = TimeZone.getTimeZone("GMT");
+
+    /**
+     * format for RFC 1123 date string -- "Sun, 06 Nov 1994 08:49:37 GMT"
+     */
+    public final static String RFC1123_PATTERN =
+        "EEE, dd MMM yyyyy HH:mm:ss z";
+
+    /** 
+     * Format for http response header date field
+     */
+    public static final String HTTP_RESPONSE_DATE_HEADER =
+        "EEE, dd MMM yyyy HH:mm:ss zzz";
+
+    // format for RFC 1036 date string -- "Sunday, 06-Nov-94 08:49:37 GMT"
+    private final static String rfc1036Pattern =
+        "EEEEEEEEE, dd-MMM-yy HH:mm:ss z";
+
+    // format for C asctime() date string -- "Sun Nov  6 08:49:37 1994"
+    private final static String asctimePattern =
+        "EEE MMM d HH:mm:ss yyyyy";
+
+    /**
+     * Pattern used for old cookies
+     */
+    public final static String OLD_COOKIE_PATTERN = "EEE, dd-MMM-yyyy HH:mm:ss z";
+
+    /**
+     * DateFormat to be used to format dates
+     */
+    public final static DateFormat rfc1123Format =
+        new SimpleDateFormat(RFC1123_PATTERN, LOCALE_US);
+
+    /**
+     * DateFormat to be used to format old netscape cookies
+     */
+    public final static DateFormat oldCookieFormat =
+        new SimpleDateFormat(OLD_COOKIE_PATTERN, LOCALE_US);
+
+    public final static DateFormat rfc1036Format =
+        new SimpleDateFormat(rfc1036Pattern, LOCALE_US);
+
+    public final static DateFormat asctimeFormat =
+        new SimpleDateFormat(asctimePattern, LOCALE_US);
+
+    static {
+        rfc1123Format.setTimeZone(GMT_ZONE);
+        oldCookieFormat.setTimeZone(GMT_ZONE);
+        rfc1036Format.setTimeZone(GMT_ZONE);
+        asctimeFormat.setTimeZone(GMT_ZONE);
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/Enumerator.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/Enumerator.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/Enumerator.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,175 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.util.Collection;
+import java.util.Enumeration;
+import java.util.Iterator;
+import java.util.List;
+import java.util.ArrayList;
+import java.util.Map;
+import java.util.NoSuchElementException;
+
+
+/**
+ * Adapter class that wraps an <code>Enumeration</code> around a Java2
+ * collection classes object <code>Iterator</code> so that existing APIs
+ * returning Enumerations can easily run on top of the new collections.
+ * Constructors are provided to easliy create such wrappers.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public final class Enumerator implements Enumeration {
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Return an Enumeration over the values of the specified Collection.
+     *
+     * @param collection Collection whose values should be enumerated
+     */
+    public Enumerator(Collection collection) {
+
+        this(collection.iterator());
+
+    }
+
+
+    /**
+     * Return an Enumeration over the values of the specified Collection.
+     *
+     * @param collection Collection whose values should be enumerated
+     * @param clone true to clone iterator
+     */
+    public Enumerator(Collection collection, boolean clone) {
+
+        this(collection.iterator(), clone);
+
+    }
+
+
+    /**
+     * Return an Enumeration over the values returned by the
+     * specified Iterator.
+     *
+     * @param iterator Iterator to be wrapped
+     */
+    public Enumerator(Iterator iterator) {
+
+        super();
+        this.iterator = iterator;
+
+    }
+
+
+    /**
+     * Return an Enumeration over the values returned by the
+     * specified Iterator.
+     *
+     * @param iterator Iterator to be wrapped
+     * @param clone true to clone iterator
+     */
+    public Enumerator(Iterator iterator, boolean clone) {
+
+        super();
+        if (!clone) {
+            this.iterator = iterator;
+        } else {
+            List list = new ArrayList();
+            while (iterator.hasNext()) {
+                list.add(iterator.next());
+            }
+            this.iterator = list.iterator();   
+        }
+
+    }
+
+
+    /**
+     * Return an Enumeration over the values of the specified Map.
+     *
+     * @param map Map whose values should be enumerated
+     */
+    public Enumerator(Map map) {
+
+        this(map.values().iterator());
+
+    }
+
+
+    /**
+     * Return an Enumeration over the values of the specified Map.
+     *
+     * @param map Map whose values should be enumerated
+     * @param clone true to clone iterator
+     */
+    public Enumerator(Map map, boolean clone) {
+
+        this(map.values().iterator(), clone);
+
+    }
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The <code>Iterator</code> over which the <code>Enumeration</code>
+     * represented by this class actually operates.
+     */
+    private Iterator iterator = null;
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Tests if this enumeration contains more elements.
+     *
+     * @return <code>true</code> if and only if this enumeration object
+     *  contains at least one more element to provide, <code>false</code>
+     *  otherwise
+     */
+    public boolean hasMoreElements() {
+
+        return (iterator.hasNext());
+
+    }
+
+
+    /**
+     * Returns the next element of this enumeration if this enumeration
+     * has at least one more element to provide.
+     *
+     * @return the next element of this enumeration
+     *
+     * @exception NoSuchElementException if no more elements exist
+     */
+    public Object nextElement() throws NoSuchElementException {
+
+        return (iterator.next());
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/Extension.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/Extension.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/Extension.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,303 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.util.StringTokenizer;
+
+
+/**
+ * Utility class that represents either an available "Optional Package"
+ * (formerly known as "Standard Extension") as described in the manifest
+ * of a JAR file, or the requirement for such an optional package.  It is
+ * used to support the requirements of the Servlet Specification, version
+ * 2.3, related to providing shared extensions to all webapps.
+ * <p>
+ * In addition, static utility methods are available to scan a manifest
+ * and return an array of either available or required optional modules
+ * documented in that manifest.
+ * <p>
+ * For more information about optional packages, see the document
+ * <em>Optional Package Versioning</em> in the documentation bundle for your
+ * Java2 Standard Edition package, in file
+ * <code>guide/extensions/versioning.html</code>.
+ *
+ * @author Craig McClanahan
+ * @author Justyna Horwat
+ * @author Greg Murray
+ * @version $Revision: 360278 $ $Date: 2005-12-31 07:26:41 -0600 (Sat, 31 Dec 2005) $
+ */
+
+public final class Extension {
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * The name of the optional package being made available, or required.
+     */
+    private String extensionName = null;
+    
+
+    public String getExtensionName() {
+        return (this.extensionName);
+    }
+
+    public void setExtensionName(String extensionName) {
+        this.extensionName = extensionName;
+    }
+
+    /**
+     * The URL from which the most recent version of this optional package
+     * can be obtained if it is not already installed.
+     */
+    private String implementationURL = null;
+
+    public String getImplementationURL() {
+        return (this.implementationURL);
+    }
+
+    public void setImplementationURL(String implementationURL) {
+        this.implementationURL = implementationURL;
+    }
+
+
+    /**
+     * The name of the company or organization that produced this
+     * implementation of this optional package.
+     */
+    private String implementationVendor = null;
+
+    public String getImplementationVendor() {
+        return (this.implementationVendor);
+    }
+
+    public void setImplementationVendor(String implementationVendor) {
+        this.implementationVendor = implementationVendor;
+    }
+
+
+    /**
+     * The unique identifier of the company that produced the optional
+     * package contained in this JAR file.
+     */
+    private String implementationVendorId = null;
+
+    public String getImplementationVendorId() {
+        return (this.implementationVendorId);
+    }
+
+    public void setImplementationVendorId(String implementationVendorId) {
+        this.implementationVendorId = implementationVendorId;
+    }
+
+
+    /**
+     * The version number (dotted decimal notation) for this implementation
+     * of the optional package.
+     */
+    private String implementationVersion = null;
+
+    public String getImplementationVersion() {
+        return (this.implementationVersion);
+    }
+
+    public void setImplementationVersion(String implementationVersion) {
+        this.implementationVersion = implementationVersion;
+    }
+
+
+    /**
+     * The name of the company or organization that originated the
+     * specification to which this optional package conforms.
+     */
+    private String specificationVendor = null;
+
+    public String getSpecificationVendor() {
+        return (this.specificationVendor);
+    }
+
+    public void setSpecificationVendor(String specificationVendor) {
+        this.specificationVendor = specificationVendor;
+    }
+
+
+    /**
+     * The version number (dotted decimal notation) of the specification
+     * to which this optional package conforms.
+     */
+    private String specificationVersion = null;
+
+    public String getSpecificationVersion() {
+        return (this.specificationVersion);
+    }
+
+    public void setSpecificationVersion(String specificationVersion) {
+        this.specificationVersion = specificationVersion;
+    }
+
+
+    /**
+     * fulfilled is true if all the required extension dependencies have been
+     * satisfied
+     */
+    private boolean fulfilled = false;
+
+    public void setFulfilled(boolean fulfilled) {
+        this.fulfilled = fulfilled;
+    }
+    
+    public boolean isFulfilled() {
+        return fulfilled;
+    }
+
+    // --------------------------------------------------------- Public Methods
+
+    /**
+     * Return <code>true</code> if the specified <code>Extension</code>
+     * (which represents an optional package required by this application)
+     * is satisfied by this <code>Extension</code> (which represents an
+     * optional package that is already installed.  Otherwise, return
+     * <code>false</code>.
+     *
+     * @param required Extension of the required optional package
+     */
+    public boolean isCompatibleWith(Extension required) {
+
+        // Extension Name must match
+        if (extensionName == null)
+            return (false);
+        if (!extensionName.equals(required.getExtensionName()))
+            return (false);
+
+        // If specified, available specification version must be >= required
+        if (required.getSpecificationVersion() != null) {
+            if (!isNewer(specificationVersion,
+                         required.getSpecificationVersion()))
+                return (false);
+        }
+
+        // If specified, Implementation Vendor ID must match
+        if (required.getImplementationVendorId() != null) {
+            if (implementationVendorId == null)
+                return (false);
+            if (!implementationVendorId.equals(required
+                    .getImplementationVendorId()))
+                return (false);
+        }
+
+        // If specified, Implementation version must be >= required
+        if (required.getImplementationVersion() != null) {
+            if (!isNewer(implementationVersion,
+                         required.getImplementationVersion()))
+                return (false);
+        }
+
+        // This available optional package satisfies the requirements
+        return (true);
+
+    }
+
+    /**
+     * Return a String representation of this object.
+     */
+    public String toString() {
+
+        StringBuffer sb = new StringBuffer("Extension[");
+        sb.append(extensionName);
+        if (implementationURL != null) {
+            sb.append(", implementationURL=");
+            sb.append(implementationURL);
+        }
+        if (implementationVendor != null) {
+            sb.append(", implementationVendor=");
+            sb.append(implementationVendor);
+        }
+        if (implementationVendorId != null) {
+            sb.append(", implementationVendorId=");
+            sb.append(implementationVendorId);
+        }
+        if (implementationVersion != null) {
+            sb.append(", implementationVersion=");
+            sb.append(implementationVersion);
+        }
+        if (specificationVendor != null) {
+            sb.append(", specificationVendor=");
+            sb.append(specificationVendor);
+        }
+        if (specificationVersion != null) {
+            sb.append(", specificationVersion=");
+            sb.append(specificationVersion);
+        }
+        sb.append("]");
+        return (sb.toString());
+
+    }
+
+
+    // -------------------------------------------------------- Private Methods
+
+
+
+    /**
+     * Return <code>true</code> if the first version number is greater than
+     * or equal to the second; otherwise return <code>false</code>.
+     *
+     * @param first First version number (dotted decimal)
+     * @param second Second version number (dotted decimal)
+     *
+     * @exception NumberFormatException on a malformed version number
+     */
+    private boolean isNewer(String first, String second)
+        throws NumberFormatException {
+
+        if ((first == null) || (second == null))
+            return (false);
+        if (first.equals(second))
+            return (true);
+
+        StringTokenizer fTok = new StringTokenizer(first, ".", true);
+        StringTokenizer sTok = new StringTokenizer(second, ".", true);
+        int fVersion = 0;
+        int sVersion = 0;
+        while (fTok.hasMoreTokens() || sTok.hasMoreTokens()) {
+            if (fTok.hasMoreTokens())
+                fVersion = Integer.parseInt(fTok.nextToken());
+            else
+                fVersion = 0;
+            if (sTok.hasMoreTokens())
+                sVersion = Integer.parseInt(sTok.nextToken());
+            else
+                sVersion = 0;
+            if (fVersion < sVersion)
+                return (false);
+            else if (fVersion > sVersion)
+                return (true);
+            if (fTok.hasMoreTokens())   // Swallow the periods
+                fTok.nextToken();
+            if (sTok.hasMoreTokens())
+                sTok.nextToken();
+        }
+
+        return (true);  // Exact match
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/ExtensionValidator.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/ExtensionValidator.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/ExtensionValidator.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,423 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+import java.util.StringTokenizer;
+import java.util.jar.JarInputStream;
+import java.util.jar.Manifest;
+
+import javax.naming.Binding;
+import javax.naming.NamingEnumeration;
+import javax.naming.NamingException;
+import javax.naming.directory.DirContext;
+
+import org.apache.catalina.core.StandardContext;
+import org.apache.naming.resources.Resource;
+
+
+/**
+ * Ensures that all extension dependies are resolved for a WEB application
+ * are met. This class builds a master list of extensions available to an
+ * applicaiton and then validates those extensions.
+ *
+ * See http://java.sun.com/j2se/1.4/docs/guide/extensions/spec.html for
+ * a detailed explanation of the extension mechanism in Java.
+ *
+ * @author Greg Murray
+ * @author Justyna Horwat
+ * @version $Revision: 360278 $ $Date: 2005-12-31 07:26:41 -0600 (Sat, 31 Dec 2005) $
+ *
+ */
+public final class ExtensionValidator {
+
+    private static org.apache.commons.logging.Log log=
+        org.apache.commons.logging.LogFactory.getLog(ExtensionValidator.class);
+
+    /**
+     * The string resources for this package.
+     */
+    private static StringManager sm =
+        StringManager.getManager("org.apache.catalina.util");
+    
+    private static ArrayList containerAvailableExtensions = null;
+    private static ArrayList containerManifestResources = new ArrayList();
+
+
+    // ----------------------------------------------------- Static Initializer
+
+
+    /**
+     *  This static initializer loads the container level extensions that are
+     *  available to all web applications. This method scans all extension 
+     *  directories available via the "java.ext.dirs" System property. 
+     *
+     *  The System Class-Path is also scanned for jar files that may contain 
+     *  available extensions.
+     */
+    static {
+
+        // check for container level optional packages
+        String systemClasspath = System.getProperty("java.class.path");
+
+        StringTokenizer strTok = new StringTokenizer(systemClasspath, 
+                                                     File.pathSeparator);
+
+        // build a list of jar files in the classpath
+        while (strTok.hasMoreTokens()) {
+            String classpathItem = strTok.nextToken();
+            if (classpathItem.toLowerCase().endsWith(".jar")) {
+                File item = new File(classpathItem);
+                if (item.exists()) {
+                    try {
+                        addSystemResource(item);
+                    } catch (IOException e) {
+                        log.error(sm.getString
+                                  ("extensionValidator.failload", item), e);
+                    }
+                }
+            }
+        }
+
+        // add specified folders to the list
+        addFolderList("java.ext.dirs");
+        addFolderList("catalina.ext.dirs");
+
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Runtime validation of a Web Applicaiton.
+     *
+     * This method uses JNDI to look up the resources located under a 
+     * <code>DirContext</code>. It locates Web Application MANIFEST.MF 
+     * file in the /META-INF/ directory of the application and all 
+     * MANIFEST.MF files in each JAR file located in the WEB-INF/lib 
+     * directory and creates an <code>ArrayList</code> of 
+     * <code>ManifestResorce<code> objects. These objects are then passed 
+     * to the validateManifestResources method for validation.
+     *
+     * @param dirContext The JNDI root of the Web Application
+     * @param context The context from which the Logger and path to the
+     *                application
+     *
+     * @return true if all required extensions satisfied
+     */
+    public static synchronized boolean validateApplication(
+                                           DirContext dirContext, 
+                                           StandardContext context)
+                    throws IOException {
+
+        String appName = context.getPath();
+        ArrayList appManifestResources = new ArrayList();
+        // If the application context is null it does not exist and 
+        // therefore is not valid
+        if (dirContext == null) return false;
+        // Find the Manifest for the Web Applicaiton
+        InputStream inputStream = null;
+        try {
+            NamingEnumeration wne = dirContext.listBindings("/META-INF/");
+            Binding binding = (Binding) wne.nextElement();
+            if (binding.getName().toUpperCase().equals("MANIFEST.MF")) {
+                Resource resource = (Resource)dirContext.lookup
+                                    ("/META-INF/" + binding.getName());
+                inputStream = resource.streamContent();
+                Manifest manifest = new Manifest(inputStream);
+                inputStream.close();
+                inputStream = null;
+                ManifestResource mre = new ManifestResource
+                    (sm.getString("extensionValidator.web-application-manifest"),
+                    manifest, ManifestResource.WAR);
+                appManifestResources.add(mre);
+            } 
+        } catch (NamingException nex) {
+            // Application does not contain a MANIFEST.MF file
+        } catch (NoSuchElementException nse) {
+            // Application does not contain a MANIFEST.MF file
+        } finally {
+            if (inputStream != null) {
+                try {
+                    inputStream.close();
+                } catch (Throwable t) {
+                    // Ignore
+                }
+            }
+        }
+
+        // Locate the Manifests for all bundled JARs
+        NamingEnumeration ne = null;
+        try {
+            if (dirContext != null) {
+                ne = dirContext.listBindings("WEB-INF/lib/");
+            }
+            while ((ne != null) && ne.hasMoreElements()) {
+                Binding binding = (Binding)ne.nextElement();
+                if (!binding.getName().toLowerCase().endsWith(".jar")) {
+                    continue;
+                }
+                Resource resource = (Resource)dirContext.lookup
+                                        ("/WEB-INF/lib/" + binding.getName());
+                Manifest jmanifest = getManifest(resource.streamContent());
+                if (jmanifest != null) {
+                    ManifestResource mre = new ManifestResource(
+                                                binding.getName(),
+                                                jmanifest, 
+                                                ManifestResource.APPLICATION);
+                    appManifestResources.add(mre);
+                }
+            }
+        } catch (NamingException nex) {
+            // Jump out of the check for this application because it 
+            // has no resources
+        }
+
+        return validateManifestResources(appName, appManifestResources);
+    }
+
+
+    /**
+     * Checks to see if the given system JAR file contains a MANIFEST, and adds
+     * it to the container's manifest resources.
+     *
+     * @param jarFile The system JAR whose manifest to add
+     */
+    public static void addSystemResource(File jarFile) throws IOException {
+        Manifest manifest = getManifest(new FileInputStream(jarFile));
+        if (manifest != null)  {
+            ManifestResource mre
+                = new ManifestResource(jarFile.getAbsolutePath(),
+                                       manifest,
+                                       ManifestResource.SYSTEM);
+            containerManifestResources.add(mre);
+        }
+    }
+
+
+    // -------------------------------------------------------- Private Methods
+
+
+    /**
+     * Validates a <code>ArrayList</code> of <code>ManifestResource</code> 
+     * objects. This method requires an application name (which is the 
+     * context root of the application at runtime).  
+     *
+     * <code>false</false> is returned if the extension dependencies
+     * represented by any given <code>ManifestResource</code> objects 
+     * is not met.
+     *
+     * This method should also provide static validation of a Web Applicaiton 
+     * if provided with the necessary parameters.
+     *
+     * @param appName The name of the Application that will appear in the 
+     *                error messages
+     * @param resources A list of <code>ManifestResource</code> objects 
+     *                  to be validated.
+     *
+     * @return true if manifest resource file requirements are met
+     */
+    private static boolean validateManifestResources(String appName, 
+                                                     ArrayList resources) {
+        boolean passes = true;
+        int failureCount = 0;        
+        ArrayList availableExtensions = null;
+
+        Iterator it = resources.iterator();
+        while (it.hasNext()) {
+            ManifestResource mre = (ManifestResource)it.next();
+            ArrayList requiredList = mre.getRequiredExtensions();
+            if (requiredList == null) {
+                continue;
+            }
+
+            // build the list of available extensions if necessary
+            if (availableExtensions == null) {
+                availableExtensions = buildAvailableExtensionsList(resources);
+            }
+
+            // load the container level resource map if it has not been built
+            // yet
+            if (containerAvailableExtensions == null) {
+                containerAvailableExtensions
+                    = buildAvailableExtensionsList(containerManifestResources);
+            }
+
+            // iterate through the list of required extensions
+            Iterator rit = requiredList.iterator();
+            while (rit.hasNext()) {
+                boolean found = false;
+                Extension requiredExt = (Extension)rit.next();
+                // check the applicaion itself for the extension
+                if (availableExtensions != null) {
+                    Iterator ait = availableExtensions.iterator();
+                    while (ait.hasNext()) {
+                        Extension targetExt = (Extension) ait.next();
+                        if (targetExt.isCompatibleWith(requiredExt)) {
+                            requiredExt.setFulfilled(true);
+                            found = true;
+                            break;
+                        }
+                    }
+                }
+                // check the container level list for the extension
+                if (!found && containerAvailableExtensions != null) {
+                    Iterator cit = containerAvailableExtensions.iterator();
+                    while (cit.hasNext()) {
+                        Extension targetExt = (Extension) cit.next();
+                        if (targetExt.isCompatibleWith(requiredExt)) {
+                            requiredExt.setFulfilled(true);
+                            found = true;
+                            break;
+                        }
+                    }
+                }
+                if (!found) {
+                    // Failure
+                    log.info(sm.getString(
+                        "extensionValidator.extension-not-found-error",
+                        appName, mre.getResourceName(),
+                        requiredExt.getExtensionName()));
+                    passes = false;
+                    failureCount++;
+                }
+            }
+        }
+
+        if (!passes) {
+            log.info(sm.getString(
+                     "extensionValidator.extension-validation-error", appName,
+                     failureCount + ""));
+        }
+
+        return passes;
+    }
+    
+   /* 
+    * Build this list of available extensions so that we do not have to 
+    * re-build this list every time we iterate through the list of required 
+    * extensions. All available extensions in all of the 
+    * <code>MainfestResource</code> objects will be added to a 
+    * <code>HashMap</code> which is returned on the first dependency list
+    * processing pass. 
+    *
+    * The key is the name + implementation version.
+    *
+    * NOTE: A list is built only if there is a dependency that needs 
+    * to be checked (performance optimization).
+    *
+    * @param resources A list of <code>ManifestResource</code> objects
+    *
+    * @return HashMap Map of available extensions
+    */
+    private static ArrayList buildAvailableExtensionsList(ArrayList resources) {
+
+        ArrayList availableList = null;
+
+        Iterator it = resources.iterator();
+        while (it.hasNext()) {
+            ManifestResource mre = (ManifestResource)it.next();
+            ArrayList list = mre.getAvailableExtensions();
+            if (list != null) {
+                Iterator values = list.iterator();
+                while (values.hasNext()) {
+                    Extension ext = (Extension) values.next();
+                    if (availableList == null) {
+                        availableList = new ArrayList();
+                        availableList.add(ext);
+                    } else {
+                        availableList.add(ext);
+                    }
+                }
+            }
+        }
+
+        return availableList;
+    }
+    
+    /**
+     * Return the Manifest from a jar file or war file
+     *
+     * @param inStream Input stream to a WAR or JAR file
+     * @return The WAR's or JAR's manifest
+     */
+    private static Manifest getManifest(InputStream inStream)
+            throws IOException {
+
+        Manifest manifest = null;
+        JarInputStream jin = null;
+
+        try {
+            jin = new JarInputStream(inStream);
+            manifest = jin.getManifest();
+            jin.close();
+            jin = null;
+        } finally {
+            if (jin != null) {
+                try {
+                    jin.close();
+                } catch (Throwable t) {
+                    // Ignore
+                }
+            }
+        }
+
+        return manifest;
+    }
+
+
+    /**
+     * Add the JARs specified to the extension list.
+     */
+    private static void addFolderList(String property) {
+
+        // get the files in the extensions directory
+        String extensionsDir = System.getProperty(property);
+        if (extensionsDir != null) {
+            StringTokenizer extensionsTok
+                = new StringTokenizer(extensionsDir, File.pathSeparator);
+            while (extensionsTok.hasMoreTokens()) {
+                File targetDir = new File(extensionsTok.nextToken());
+                if (!targetDir.exists() || !targetDir.isDirectory()) {
+                    continue;
+                }
+                File[] files = targetDir.listFiles();
+                for (int i = 0; i < files.length; i++) {
+                    if (files[i].getName().toLowerCase().endsWith(".jar")) {
+                        try {
+                            addSystemResource(files[i]);
+                        } catch (IOException e) {
+                            log.error
+                                (sm.getString
+                                 ("extensionValidator.failload", files[i]), e);
+                        }
+                    }
+                }
+            }
+        }
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/FastDateFormat.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/FastDateFormat.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/FastDateFormat.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,123 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.util.Date;
+
+import java.text.DateFormat;
+import java.text.FieldPosition;
+import java.text.ParsePosition;
+import java.text.SimpleDateFormat;
+
+/**
+ * Fast date formatter that caches recently formatted date information
+ * and uses it to avoid too-frequent calls to the underlying
+ * formatter.  Note: breaks fieldPosition param of format(Date,
+ * StringBuffer, FieldPosition).  If you care about the field
+ * position, call the underlying DateFormat directly.
+ *
+ * @author Stan Bailes
+ * @author Alex Chaffee
+ **/
+public class FastDateFormat extends DateFormat {
+    DateFormat    df;
+    long          lastSec = -1;
+    StringBuffer  sb      = new StringBuffer();
+    FieldPosition fp      = new FieldPosition(DateFormat.MILLISECOND_FIELD);
+
+    public FastDateFormat(DateFormat df) {
+        this.df = df;
+    }
+
+    public Date parse(String text, ParsePosition pos) {
+        return df.parse(text, pos);
+    }
+
+    /**
+     * Note: breaks functionality of fieldPosition param. Also:
+     * there's a bug in SimpleDateFormat with "S" and "SS", use "SSS"
+     * instead if you want a msec field.
+     **/
+    public StringBuffer format(Date date, StringBuffer toAppendTo,
+                               FieldPosition fieldPosition) {
+        long dt = date.getTime();
+        long ds = dt / 1000;
+        if (ds != lastSec) {
+            sb.setLength(0);
+            df.format(date, sb, fp);
+            lastSec = ds;
+        } else {
+            // munge current msec into existing string
+            int ms = (int)(dt % 1000);
+            int pos = fp.getEndIndex();
+            int begin = fp.getBeginIndex();
+            if (pos > 0) {
+                if (pos > begin)
+                    sb.setCharAt(--pos, Character.forDigit(ms % 10, 10));
+                ms /= 10;
+                if (pos > begin)
+                    sb.setCharAt(--pos, Character.forDigit(ms % 10, 10));
+                ms /= 10;
+                if (pos > begin)
+                    sb.setCharAt(--pos, Character.forDigit(ms % 10, 10));
+            }
+        }
+        toAppendTo.append(sb.toString());
+        return toAppendTo;
+    }
+
+    public static void main(String[] args) {
+        String format = "yyyy-MM-dd HH:mm:ss.SSS";
+        if (args.length > 0)
+            format = args[0];
+        SimpleDateFormat sdf = new SimpleDateFormat(format);
+        FastDateFormat fdf = new FastDateFormat(sdf);
+        Date d = new Date();
+
+        d.setTime(1); System.out.println(fdf.format(d) + "\t" + sdf.format(d));
+        d.setTime(20); System.out.println(fdf.format(d) + "\t" + sdf.format(d));
+        d.setTime(500); System.out.println(fdf.format(d) + "\t" + sdf.format(d));
+        d.setTime(543); System.out.println(fdf.format(d) + "\t" + sdf.format(d));
+        d.setTime(999); System.out.println(fdf.format(d) + "\t" + sdf.format(d));
+        d.setTime(1050); System.out.println(fdf.format(d) + "\t" + sdf.format(d));
+        d.setTime(2543); System.out.println(fdf.format(d) + "\t" + sdf.format(d));
+        d.setTime(12345); System.out.println(fdf.format(d) + "\t" + sdf.format(d));
+        d.setTime(12340); System.out.println(fdf.format(d) + "\t" + sdf.format(d));
+
+        final int reps = 100000;
+        {
+            long start = System.currentTimeMillis();
+            for (int i = 0; i < reps; i++) {
+                d.setTime(System.currentTimeMillis());
+                fdf.format(d);
+            }
+            long elap = System.currentTimeMillis() - start;
+            System.out.println("fast: " + elap + " elapsed");
+            System.out.println(fdf.format(d));
+        }
+        {
+            long start = System.currentTimeMillis();
+            for (int i = 0; i < reps; i++) {
+                d.setTime(System.currentTimeMillis());
+                sdf.format(d);
+            }
+            long elap = System.currentTimeMillis() - start;
+            System.out.println("slow: " + elap + " elapsed");
+            System.out.println(sdf.format(d));
+        }
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/HexUtils.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/HexUtils.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/HexUtils.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,176 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.io.ByteArrayOutputStream;
+
+/**
+ * Library of utility methods useful in dealing with converting byte arrays
+ * to and from strings of hexadecimal digits.
+ *
+ * @author Craig R. McClanahan
+ */
+
+public final class HexUtils {
+    // Code from Ajp11, from Apache's JServ
+
+    // Table for HEX to DEC byte translation
+    public 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,
+    };
+
+
+
+    /**
+     * The string manager for this package.
+     */
+    private static StringManager sm =
+        StringManager.getManager("org.apache.catalina.util");
+
+
+    /**
+     * Convert a String of hexadecimal digits into the corresponding
+     * byte array by encoding each two hexadecimal digits as a byte.
+     *
+     * @param digits Hexadecimal digits representation
+     *
+     * @exception IllegalArgumentException if an invalid hexadecimal digit
+     *  is found, or the input string contains an odd number of hexadecimal
+     *  digits
+     */
+    public static byte[] convert(String digits) {
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        for (int i = 0; i < digits.length(); i += 2) {
+            char c1 = digits.charAt(i);
+            if ((i+1) >= digits.length())
+                throw new IllegalArgumentException
+                    (sm.getString("hexUtil.odd"));
+            char c2 = digits.charAt(i + 1);
+            byte b = 0;
+            if ((c1 >= '0') && (c1 <= '9'))
+                b += ((c1 - '0') * 16);
+            else if ((c1 >= 'a') && (c1 <= 'f'))
+                b += ((c1 - 'a' + 10) * 16);
+            else if ((c1 >= 'A') && (c1 <= 'F'))
+                b += ((c1 - 'A' + 10) * 16);
+            else
+                throw new IllegalArgumentException
+                    (sm.getString("hexUtil.bad"));
+            if ((c2 >= '0') && (c2 <= '9'))
+                b += (c2 - '0');
+            else if ((c2 >= 'a') && (c2 <= 'f'))
+                b += (c2 - 'a' + 10);
+            else if ((c2 >= 'A') && (c2 <= 'F'))
+                b += (c2 - 'A' + 10);
+            else
+                throw new IllegalArgumentException
+                    (sm.getString("hexUtil.bad"));
+            baos.write(b);
+        }
+        return (baos.toByteArray());
+
+    }
+
+
+    /**
+     * Convert a byte array into a printable format containing a
+     * String of hexadecimal digit characters (two per byte).
+     *
+     * @param bytes Byte array representation
+     */
+    public static String convert(byte bytes[]) {
+
+        StringBuffer sb = new StringBuffer(bytes.length * 2);
+        for (int i = 0; i < bytes.length; i++) {
+            sb.append(convertDigit((int) (bytes[i] >> 4)));
+            sb.append(convertDigit((int) (bytes[i] & 0x0f)));
+        }
+        return (sb.toString());
+
+    }
+
+    /**
+     * Convert 4 hex digits to an int, and return the number of converted
+     * bytes.
+     *
+     * @param hex Byte array containing exactly four hexadecimal digits
+     *
+     * @exception IllegalArgumentException if an invalid hexadecimal digit
+     *  is included
+     */
+    public static int convert2Int( byte[] hex ) {
+        // Code from Ajp11, from Apache's JServ
+
+        // assert b.length==4
+        // assert valid data
+        int len;
+        if(hex.length < 4 ) return 0;
+        if( DEC[hex[0]]<0 )
+            throw new IllegalArgumentException(sm.getString("hexUtil.bad"));
+        len = DEC[hex[0]];
+        len = len << 4;
+        if( DEC[hex[1]]<0 )
+            throw new IllegalArgumentException(sm.getString("hexUtil.bad"));
+        len += DEC[hex[1]];
+        len = len << 4;
+        if( DEC[hex[2]]<0 )
+            throw new IllegalArgumentException(sm.getString("hexUtil.bad"));
+        len += DEC[hex[2]];
+        len = len << 4;
+        if( DEC[hex[3]]<0 )
+            throw new IllegalArgumentException(sm.getString("hexUtil.bad"));
+        len += DEC[hex[3]];
+        return len;
+    }
+
+
+
+    /**
+     * [Private] Convert the specified value (0 .. 15) to the corresponding
+     * hexadecimal digit.
+     *
+     * @param value Value to be converted
+     */
+    private static char convertDigit(int value) {
+
+        value &= 0x0f;
+        if (value >= 10)
+            return ((char) (value - 10 + 'a'));
+        else
+            return ((char) (value + '0'));
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/IOTools.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/IOTools.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/IOTools.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,86 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.io.InputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.Reader;
+import java.io.Writer;
+
+
+/**
+ * Contains commonly needed I/O-related methods 
+ *
+ * @author Dan Sandberg
+ */
+public class IOTools {
+    protected final static int DEFAULT_BUFFER_SIZE=4*1024; //4k
+
+    //Ensure non-instantiability
+    private IOTools() {
+    }
+
+     /**
+     * Read input from reader and write it to writer until there is no more
+     * input from reader.
+     *
+     * @param reader the reader to read from.
+     * @param writer the writer to write to.
+     * @param buf the char array to use as a bufferx
+     */
+    public static void flow( Reader reader, Writer writer, char[] buf ) 
+        throws IOException {
+        int numRead;
+        while ( (numRead = reader.read(buf) ) >= 0) {
+            writer.write(buf, 0, numRead);
+        }
+    }
+
+    /**
+     * @see #flow( Reader, Writer, char[] )
+     */
+    public static void flow( Reader reader, Writer writer ) 
+        throws IOException {
+        char[] buf = new char[DEFAULT_BUFFER_SIZE];
+        flow( reader, writer, buf );
+    }
+
+    /**
+     * Read input from input stream and write it to output stream 
+     * until there is no more input from input stream.
+     *
+     * @param is input stream the input stream to read from.
+     * @param os output stream the output stream to write to.
+     * @param buf the byte array to use as a buffer
+     */
+    public static void flow( InputStream is, OutputStream os, byte[] buf ) 
+        throws IOException {
+        int numRead;
+        while ( (numRead = is.read(buf) ) >= 0) {
+            os.write(buf, 0, numRead);
+        }
+    }  
+
+    /**
+     * @see #flow( java.io.InputStream, java.io.OutputStream, byte[] )
+     */ 
+    public static void flow( InputStream is, OutputStream os ) 
+        throws IOException {
+        byte[] buf = new byte[DEFAULT_BUFFER_SIZE];
+        flow( is, os, buf );
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/InstanceSupport.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/InstanceSupport.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/InstanceSupport.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,361 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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 javax.servlet.Filter;
+import javax.servlet.Servlet;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import org.apache.catalina.InstanceEvent;
+import org.apache.catalina.InstanceListener;
+import org.apache.catalina.Wrapper;
+
+
+/**
+ * Support class to assist in firing InstanceEvent notifications to
+ * registered InstanceListeners.
+ *
+ * @author Craig R. McClanahan
+ * @version $Id: InstanceSupport.java 303133 2004-08-29 16:46:15Z yoavs $
+ */
+
+public final class InstanceSupport {
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Construct a new InstanceSupport object associated with the specified
+     * Instance component.
+     *
+     * @param wrapper The component that will be the source
+     *  of events that we fire
+     */
+    public InstanceSupport(Wrapper wrapper) {
+
+        super();
+        this.wrapper = wrapper;
+
+    }
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The set of registered InstanceListeners for event notifications.
+     */
+    private InstanceListener listeners[] = new InstanceListener[0];
+
+
+    /**
+     * The source component for instance events that we will fire.
+     */
+    private Wrapper wrapper = null;
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * Return the Wrapper with which we are associated.
+     */
+    public Wrapper getWrapper() {
+
+        return (this.wrapper);
+
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Add a lifecycle event listener to this component.
+     *
+     * @param listener The listener to add
+     */
+    public void addInstanceListener(InstanceListener listener) {
+
+      synchronized (listeners) {
+          InstanceListener results[] =
+            new InstanceListener[listeners.length + 1];
+          for (int i = 0; i < listeners.length; i++)
+              results[i] = listeners[i];
+          results[listeners.length] = listener;
+          listeners = results;
+      }
+
+    }
+
+
+    /**
+     * Notify all lifecycle event listeners that a particular event has
+     * occurred for this Container.  The default implementation performs
+     * this notification synchronously using the calling thread.
+     *
+     * @param type Event type
+     * @param filter The relevant Filter for this event
+     */
+    public void fireInstanceEvent(String type, Filter filter) {
+
+        if (listeners.length == 0)
+            return;
+
+        InstanceEvent event = new InstanceEvent(wrapper, filter, type);
+        InstanceListener interested[] = null;
+        synchronized (listeners) {
+            interested = (InstanceListener[]) listeners.clone();
+        }
+        for (int i = 0; i < interested.length; i++)
+            interested[i].instanceEvent(event);
+
+    }
+
+
+    /**
+     * Notify all lifecycle event listeners that a particular event has
+     * occurred for this Container.  The default implementation performs
+     * this notification synchronously using the calling thread.
+     *
+     * @param type Event type
+     * @param filter The relevant Filter for this event
+     * @param exception Exception that occurred
+     */
+    public void fireInstanceEvent(String type, Filter filter,
+                                  Throwable exception) {
+
+        if (listeners.length == 0)
+            return;
+
+        InstanceEvent event = new InstanceEvent(wrapper, filter, type,
+                                                exception);
+        InstanceListener interested[] = null;
+        synchronized (listeners) {
+            interested = (InstanceListener[]) listeners.clone();
+        }
+        for (int i = 0; i < interested.length; i++)
+            interested[i].instanceEvent(event);
+
+    }
+
+
+    /**
+     * Notify all lifecycle event listeners that a particular event has
+     * occurred for this Container.  The default implementation performs
+     * this notification synchronously using the calling thread.
+     *
+     * @param type Event type
+     * @param filter The relevant Filter for this event
+     * @param request The servlet request we are processing
+     * @param response The servlet response we are processing
+     */
+    public void fireInstanceEvent(String type, Filter filter,
+                                  ServletRequest request,
+                                  ServletResponse response) {
+
+        if (listeners.length == 0)
+            return;
+
+        InstanceEvent event = new InstanceEvent(wrapper, filter, type,
+                                                request, response);
+        InstanceListener interested[] = null;
+        synchronized (listeners) {
+            interested = (InstanceListener[]) listeners.clone();
+        }
+        for (int i = 0; i < interested.length; i++)
+            interested[i].instanceEvent(event);
+
+    }
+
+
+    /**
+     * Notify all lifecycle event listeners that a particular event has
+     * occurred for this Container.  The default implementation performs
+     * this notification synchronously using the calling thread.
+     *
+     * @param type Event type
+     * @param filter The relevant Filter for this event
+     * @param request The servlet request we are processing
+     * @param response The servlet response we are processing
+     * @param exception Exception that occurred
+     */
+    public void fireInstanceEvent(String type, Filter filter,
+                                  ServletRequest request,
+                                  ServletResponse response,
+                                  Throwable exception) {
+
+        if (listeners.length == 0)
+            return;
+
+        InstanceEvent event = new InstanceEvent(wrapper, filter, type,
+                                                request, response, exception);
+        InstanceListener interested[] = null;
+        synchronized (listeners) {
+            interested = (InstanceListener[]) listeners.clone();
+        }
+        for (int i = 0; i < interested.length; i++)
+            interested[i].instanceEvent(event);
+
+    }
+
+
+    /**
+     * Notify all lifecycle event listeners that a particular event has
+     * occurred for this Container.  The default implementation performs
+     * this notification synchronously using the calling thread.
+     *
+     * @param type Event type
+     * @param servlet The relevant Servlet for this event
+     */
+    public void fireInstanceEvent(String type, Servlet servlet) {
+
+        if (listeners.length == 0)
+            return;
+
+        InstanceEvent event = new InstanceEvent(wrapper, servlet, type);
+        InstanceListener interested[] = null;
+        synchronized (listeners) {
+            interested = (InstanceListener[]) listeners.clone();
+        }
+        for (int i = 0; i < interested.length; i++)
+            interested[i].instanceEvent(event);
+
+    }
+
+
+    /**
+     * Notify all lifecycle event listeners that a particular event has
+     * occurred for this Container.  The default implementation performs
+     * this notification synchronously using the calling thread.
+     *
+     * @param type Event type
+     * @param servlet The relevant Servlet for this event
+     * @param exception Exception that occurred
+     */
+    public void fireInstanceEvent(String type, Servlet servlet,
+                                  Throwable exception) {
+
+        if (listeners.length == 0)
+            return;
+
+        InstanceEvent event = new InstanceEvent(wrapper, servlet, type,
+                                                exception);
+        InstanceListener interested[] = null;
+        synchronized (listeners) {
+            interested = (InstanceListener[]) listeners.clone();
+        }
+        for (int i = 0; i < interested.length; i++)
+            interested[i].instanceEvent(event);
+
+    }
+
+
+    /**
+     * Notify all lifecycle event listeners that a particular event has
+     * occurred for this Container.  The default implementation performs
+     * this notification synchronously using the calling thread.
+     *
+     * @param type Event type
+     * @param servlet The relevant Servlet for this event
+     * @param request The servlet request we are processing
+     * @param response The servlet response we are processing
+     */
+    public void fireInstanceEvent(String type, Servlet servlet,
+                                  ServletRequest request,
+                                  ServletResponse response) {
+
+        if (listeners.length == 0)
+            return;
+
+        InstanceEvent event = new InstanceEvent(wrapper, servlet, type,
+                                                request, response);
+        InstanceListener interested[] = null;
+        synchronized (listeners) {
+            interested = (InstanceListener[]) listeners.clone();
+        }
+        for (int i = 0; i < interested.length; i++)
+            interested[i].instanceEvent(event);
+
+    }
+
+
+    /**
+     * Notify all lifecycle event listeners that a particular event has
+     * occurred for this Container.  The default implementation performs
+     * this notification synchronously using the calling thread.
+     *
+     * @param type Event type
+     * @param servlet The relevant Servlet for this event
+     * @param request The servlet request we are processing
+     * @param response The servlet response we are processing
+     * @param exception Exception that occurred
+     */
+    public void fireInstanceEvent(String type, Servlet servlet,
+                                  ServletRequest request,
+                                  ServletResponse response,
+                                  Throwable exception) {
+
+        if (listeners.length == 0)
+            return;
+
+        InstanceEvent event = new InstanceEvent(wrapper, servlet, type,
+                                                request, response, exception);
+        InstanceListener interested[] = null;
+        synchronized (listeners) {
+            interested = (InstanceListener[]) listeners.clone();
+        }
+        for (int i = 0; i < interested.length; i++)
+            interested[i].instanceEvent(event);
+
+    }
+
+
+    /**
+     * Remove a lifecycle event listener from this component.
+     *
+     * @param listener The listener to remove
+     */
+    public void removeInstanceListener(InstanceListener listener) {
+
+        synchronized (listeners) {
+            int n = -1;
+            for (int i = 0; i < listeners.length; i++) {
+                if (listeners[i] == listener) {
+                    n = i;
+                    break;
+                }
+            }
+            if (n < 0)
+                return;
+            InstanceListener results[] =
+              new InstanceListener[listeners.length - 1];
+            int j = 0;
+            for (int i = 0; i < listeners.length; i++) {
+                if (i != n)
+                    results[j++] = listeners[i];
+            }
+            listeners = results;
+        }
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/LifecycleSupport.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/LifecycleSupport.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/LifecycleSupport.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,154 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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 org.apache.catalina.Lifecycle;
+import org.apache.catalina.LifecycleEvent;
+import org.apache.catalina.LifecycleListener;
+
+
+/**
+ * Support class to assist in firing LifecycleEvent notifications to
+ * registered LifecycleListeners.
+ *
+ * @author Craig R. McClanahan
+ * @version $Id: LifecycleSupport.java 302726 2004-02-27 14:59:07Z yoavs $
+ */
+
+public final class LifecycleSupport {
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Construct a new LifecycleSupport object associated with the specified
+     * Lifecycle component.
+     *
+     * @param lifecycle The Lifecycle component that will be the source
+     *  of events that we fire
+     */
+    public LifecycleSupport(Lifecycle lifecycle) {
+
+        super();
+        this.lifecycle = lifecycle;
+
+    }
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The source component for lifecycle events that we will fire.
+     */
+    private Lifecycle lifecycle = null;
+
+
+    /**
+     * The set of registered LifecycleListeners for event notifications.
+     */
+    private LifecycleListener listeners[] = new LifecycleListener[0];
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Add a lifecycle event listener to this component.
+     *
+     * @param listener The listener to add
+     */
+    public void addLifecycleListener(LifecycleListener listener) {
+
+      synchronized (listeners) {
+          LifecycleListener results[] =
+            new LifecycleListener[listeners.length + 1];
+          for (int i = 0; i < listeners.length; i++)
+              results[i] = listeners[i];
+          results[listeners.length] = listener;
+          listeners = results;
+      }
+
+    }
+
+
+    /**
+     * Get the lifecycle listeners associated with this lifecycle. If this 
+     * Lifecycle has no listeners registered, a zero-length array is returned.
+     */
+    public LifecycleListener[] findLifecycleListeners() {
+
+        return listeners;
+
+    }
+
+
+    /**
+     * Notify all lifecycle event listeners that a particular event has
+     * occurred for this Container.  The default implementation performs
+     * this notification synchronously using the calling thread.
+     *
+     * @param type Event type
+     * @param data Event data
+     */
+    public void fireLifecycleEvent(String type, Object data) {
+
+        LifecycleEvent event = new LifecycleEvent(lifecycle, type, data);
+        LifecycleListener interested[] = null;
+        synchronized (listeners) {
+            interested = (LifecycleListener[]) listeners.clone();
+        }
+        for (int i = 0; i < interested.length; i++)
+            interested[i].lifecycleEvent(event);
+
+    }
+
+
+    /**
+     * Remove a lifecycle event listener from this component.
+     *
+     * @param listener The listener to remove
+     */
+    public void removeLifecycleListener(LifecycleListener listener) {
+
+        synchronized (listeners) {
+            int n = -1;
+            for (int i = 0; i < listeners.length; i++) {
+                if (listeners[i] == listener) {
+                    n = i;
+                    break;
+                }
+            }
+            if (n < 0)
+                return;
+            LifecycleListener results[] =
+              new LifecycleListener[listeners.length - 1];
+            int j = 0;
+            for (int i = 0; i < listeners.length; i++) {
+                if (i != n)
+                    results[j++] = listeners[i];
+            }
+            listeners = results;
+        }
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/LocalStrings.properties
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/LocalStrings.properties	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/LocalStrings.properties	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,11 @@
+parameterMap.locked=No modifications are allowed to a locked ParameterMap
+resourceSet.locked=No modifications are allowed to a locked ResourceSet
+hexUtil.bad=Bad hexadecimal digit
+hexUtil.odd=Odd number of hexadecimal digits
+#Default Messages Utilized by the ExtensionValidator
+extensionValidator.web-application-manifest=Web Application Manifest
+extensionValidator.extension-not-found-error=ExtensionValidator[{0}][{1}]: Required extension "{2}" not found.
+extensionValidator.extension-validation-error=ExtensionValidator[{0}]: Failure to find {1} required extension(s).
+extensionValidator.failload=Failure loading extension {0}
+SecurityUtil.doAsPrivilege=An exception occurs when running the PrivilegedExceptionAction block.
+

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/LocalStrings_es.properties
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/LocalStrings_es.properties	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/LocalStrings_es.properties	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,10 @@
+parameterMap.locked=No se permiten modificaciones en un ParameterMap bloqueado
+resourceSet.locked=No se permiten modificaciones en un ResourceSet bloqueado
+hexUtil.bad=Dígito hexadecimal incorrecto
+hexUtil.odd=Número de dígitos hexadecimales impar
+#Default Messages Utilized by the ExtensionValidator
+extensionValidator.web-application-manifest=Manifiesto de Aplicación Web
+extensionValidator.extension-not-found-error=ExtensionValidator[{0}][{1}]: La extensión no encuentra el "{2}" requerido.
+extensionValidator.extension-validation-error=ExtensionValidator[{0}]: Imposible de hallar la(s) extension(es) {1} requerida(s).
+SecurityUtil.doAsPrivilege=Una excepción se ha producido durante la ejecución del bloque PrivilegedExceptionAction.
+

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/LocalStrings_fr.properties
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/LocalStrings_fr.properties	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/LocalStrings_fr.properties	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,10 @@
+parameterMap.locked=Aucune modification n''est authorisée sur un ParameterMap vérrouillé
+resourceSet.locked=Aucune modification n''est authorisée sur un ResourceSet vérrouillé
+hexUtil.bad=Mauvais digit hexadecimal
+hexUtil.odd=Nombre impair de digits hexadecimaux
+#Default Messages Utilized by the ExtensionValidator
+extensionValidator.web-application-manifest=Web Application Manifest
+extensionValidator.extension-not-found-error=ExtensionValidator[{0}][{1}]: L''extension requise "{2}" est introuvable.
+extensionValidator.extension-validation-error=ExtensionValidator[{0}]: Impossible de trouver {1} extension(s) requise(s).
+SecurityUtil.doAsPrivilege=Une exception s''est produite lors de l''execution du bloc PrivilegedExceptionAction.
+

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/LocalStrings_ja.properties
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/LocalStrings_ja.properties	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/LocalStrings_ja.properties	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,11 @@
+parameterMap.locked=\u30ed\u30c3\u30af\u3055\u308c\u305fParameterMap\u306f\u5909\u66f4\u304c\u8a31\u3055\u308c\u307e\u305b\u3093
+resourceSet.locked=\u30ed\u30c3\u30af\u3055\u308c\u305fResourceSet\u306f\u5909\u66f4\u304c\u8a31\u3055\u308c\u307e\u305b\u3093
+hexUtil.bad=\u7121\u52b9\u306a16\u9032\u6570\u5024\u3067\u3059
+hexUtil.odd=\u5947\u6570\u6841\u306e16\u9032\u6570\u5024\u3067\u3059
+#Default Messages Utilized by the ExtensionValidator
+extensionValidator.web-application-manifest=Web\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u30de\u30cb\u30d5\u30a7\u30b9\u30c8
+extensionValidator.extension-not-found-error=ExtensionValidator[{0}][{1}]: \u5fc5\u8981\u306a\u62e1\u5f35 "{2}" \u304c\u898b\u3064\u304b\u308a\u307e\u305b\u3093\u3002
+extensionValidator.extension-validation-error=ExtensionValidator[{0}]: \u5fc5\u8981\u306a\u62e1\u5f35 "{1}" \u304c\u898b\u3064\u304b\u308a\u307e\u305b\u3093\u3002
+extensionValidator.failload=\u62e1\u5f35 {0} \u306e\u30ed\u30fc\u30c9\u306b\u5931\u6557\u3057\u307e\u3057\u305f
+SecurityUtil.doAsPrivilege=PrivilegedExceptionAction\u30d6\u30ed\u30c3\u30af\u3092\u5b9f\u884c\u4e2d\u306b\u4f8b\u5916\u304c\u767a\u751f\u3057\u307e\u3057\u305f\u3002
+

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/MD5Encoder.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/MD5Encoder.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/MD5Encoder.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,72 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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;
+
+
+/**
+ * Encode an MD5 digest into a String.
+ * <p>
+ * The 128 bit MD5 hash is converted into a 32 character long String.
+ * Each character of the String is the hexadecimal representation of 4 bits
+ * of the digest.
+ *
+ * @author Remy Maucherat
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public final class MD5Encoder {
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    private static final char[] hexadecimal =
+    {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
+     'a', 'b', 'c', 'd', 'e', 'f'};
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Encodes the 128 bit (16 bytes) MD5 into a 32 character String.
+     *
+     * @param binaryData Array containing the digest
+     * @return Encoded MD5, or null if encoding failed
+     */
+    public String encode( byte[] binaryData ) {
+
+        if (binaryData.length != 16)
+            return null;
+
+        char[] buffer = new char[32];
+
+        for (int i=0; i<16; i++) {
+            int low = (int) (binaryData[i] & 0x0f);
+            int high = (int) ((binaryData[i] & 0xf0) >> 4);
+            buffer[i*2] = hexadecimal[high];
+            buffer[i*2 + 1] = hexadecimal[low];
+        }
+
+        return new String(buffer);
+
+    }
+
+
+}
+

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/MIME2Java.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/MIME2Java.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/MIME2Java.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,602 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.util.*;
+
+/**
+ * MIME2Java is a convenience class which handles conversions between MIME charset names
+ * and Java encoding names.
+ * <p>The supported XML encodings are the intersection of XML-supported code sets and those
+ * supported in JDK 1.1.
+ * <p>MIME charset names are used on <var>xmlEncoding</var> parameters to methods such
+ * as <code>TXDocument#setEncoding</code> and <code>DTD#setEncoding</code>.
+ * <p>Java encoding names are used on <var>encoding</var> parameters to
+ * methods such as <code>TXDocument#printWithFormat</code> and <code>DTD#printExternal</code>.
+ * <P>
+ * <TABLE BORDER="0" WIDTH="100%">
+ *  <TR>
+ *      <TD WIDTH="33%">
+ *          <P ALIGN="CENTER"><B>Common Name</B>
+ *      </TD>
+ *      <TD WIDTH="15%">
+ *          <P ALIGN="CENTER"><B>Use this name in XML files</B>
+ *      </TD>
+ *      <TD WIDTH="12%">
+ *          <P ALIGN="CENTER"><B>Name Type</B>
+ *      </TD>
+ *      <TD WIDTH="31%">
+ *          <P ALIGN="CENTER"><B>Xerces converts to this Java Encoder Name</B>
+ *      </TD>
+ *  </TR>
+ *  <TR>
+ *      <TD WIDTH="33%">8 bit Unicode</TD>
+ *      <TD WIDTH="15%">
+ *          <P ALIGN="CENTER">UTF-8
+ *      </TD>
+ *      <TD WIDTH="12%">
+ *          <P ALIGN="CENTER">IANA
+ *      </TD>
+ *      <TD WIDTH="31%">
+ *          <P ALIGN="CENTER">UTF8
+ *      </TD>
+ *  </TR>
+ *  <TR>
+ *      <TD WIDTH="33%">ISO Latin 1</TD>
+ *      <TD WIDTH="15%">
+ *          <P ALIGN="CENTER">ISO-8859-1
+ *      </TD>
+ *      <TD WIDTH="12%">
+ *          <P ALIGN="CENTER">MIME
+ *      </TD>
+ *      <TD WIDTH="31%">
+ *          <P ALIGN="CENTER">ISO-8859-1
+ *      </TD>
+ *  </TR>
+ *  <TR>
+ *      <TD WIDTH="33%">ISO Latin 2</TD>
+ *      <TD WIDTH="15%">
+ *          <P ALIGN="CENTER">ISO-8859-2
+ *      </TD>
+ *      <TD WIDTH="12%">
+ *          <P ALIGN="CENTER">MIME
+ *      </TD>
+ *      <TD WIDTH="31%">
+ *          <P ALIGN="CENTER">ISO-8859-2
+ *      </TD>
+ *  </TR>
+ *  <TR>
+ *      <TD WIDTH="33%">ISO Latin 3</TD>
+ *      <TD WIDTH="15%">
+ *          <P ALIGN="CENTER">ISO-8859-3
+ *      </TD>
+ *      <TD WIDTH="12%">
+ *          <P ALIGN="CENTER">MIME
+ *      </TD>
+ *      <TD WIDTH="31%">
+ *          <P ALIGN="CENTER">ISO-8859-3
+ *      </TD>
+ *  </TR>
+ *  <TR>
+ *      <TD WIDTH="33%">ISO Latin 4</TD>
+ *      <TD WIDTH="15%">
+ *          <P ALIGN="CENTER">ISO-8859-4
+ *      </TD>
+ *      <TD WIDTH="12%">
+ *          <P ALIGN="CENTER">MIME
+ *      </TD>
+ *      <TD WIDTH="31%">
+ *          <P ALIGN="CENTER">ISO-8859-4
+ *      </TD>
+ *  </TR>
+ *  <TR>
+ *      <TD WIDTH="33%">ISO Latin Cyrillic</TD>
+ *      <TD WIDTH="15%">
+ *          <P ALIGN="CENTER">ISO-8859-5
+ *      </TD>
+ *      <TD WIDTH="12%">
+ *          <P ALIGN="CENTER">MIME
+ *      </TD>
+ *      <TD WIDTH="31%">
+ *          <P ALIGN="CENTER">ISO-8859-5
+ *      </TD>
+ *  </TR>
+ *  <TR>
+ *      <TD WIDTH="33%">ISO Latin Arabic</TD>
+ *      <TD WIDTH="15%">
+ *          <P ALIGN="CENTER">ISO-8859-6
+ *      </TD>
+ *      <TD WIDTH="12%">
+ *          <P ALIGN="CENTER">MIME
+ *      </TD>
+ *      <TD WIDTH="31%">
+ *          <P ALIGN="CENTER">ISO-8859-6
+ *      </TD>
+ *  </TR>
+ *  <TR>
+ *      <TD WIDTH="33%">ISO Latin Greek</TD>
+ *      <TD WIDTH="15%">
+ *          <P ALIGN="CENTER">ISO-8859-7
+ *      </TD>
+ *      <TD WIDTH="12%">
+ *          <P ALIGN="CENTER">MIME
+ *      </TD>
+ *      <TD WIDTH="31%">
+ *          <P ALIGN="CENTER">ISO-8859-7
+ *      </TD>
+ *  </TR>
+ *  <TR>
+ *      <TD WIDTH="33%">ISO Latin Hebrew</TD>
+ *      <TD WIDTH="15%">
+ *          <P ALIGN="CENTER">ISO-8859-8
+ *      </TD>
+ *      <TD WIDTH="12%">
+ *          <P ALIGN="CENTER">MIME
+ *      </TD>
+ *      <TD WIDTH="31%">
+ *          <P ALIGN="CENTER">ISO-8859-8
+ *      </TD>
+ *  </TR>
+ *  <TR>
+ *      <TD WIDTH="33%">ISO Latin 5</TD>
+ *      <TD WIDTH="15%">
+ *          <P ALIGN="CENTER">ISO-8859-9
+ *      </TD>
+ *      <TD WIDTH="12%">
+ *          <P ALIGN="CENTER">MIME
+ *      </TD>
+ *      <TD WIDTH="31%">
+ *          <P ALIGN="CENTER">ISO-8859-9
+ *      </TD>
+ *  </TR>
+ *  <TR>
+ *      <TD WIDTH="33%">EBCDIC: US</TD>
+ *      <TD WIDTH="15%">
+ *          <P ALIGN="CENTER">ebcdic-cp-us
+ *      </TD>
+ *      <TD WIDTH="12%">
+ *          <P ALIGN="CENTER">IANA
+ *      </TD>
+ *      <TD WIDTH="31%">
+ *          <P ALIGN="CENTER">cp037
+ *      </TD>
+ *  </TR>
+ *  <TR>
+ *      <TD WIDTH="33%">EBCDIC: Canada</TD>
+ *      <TD WIDTH="15%">
+ *          <P ALIGN="CENTER">ebcdic-cp-ca
+ *      </TD>
+ *      <TD WIDTH="12%">
+ *          <P ALIGN="CENTER">IANA
+ *      </TD>
+ *      <TD WIDTH="31%">
+ *          <P ALIGN="CENTER">cp037
+ *      </TD>
+ *  </TR>
+ *  <TR>
+ *      <TD WIDTH="33%">EBCDIC: Netherlands</TD>
+ *      <TD WIDTH="15%">
+ *          <P ALIGN="CENTER">ebcdic-cp-nl
+ *      </TD>
+ *      <TD WIDTH="12%">
+ *          <P ALIGN="CENTER">IANA
+ *      </TD>
+ *      <TD WIDTH="31%">
+ *          <P ALIGN="CENTER">cp037
+ *      </TD>
+ *  </TR>
+ *  <TR>
+ *      <TD WIDTH="33%">EBCDIC: Denmark</TD>
+ *      <TD WIDTH="15%">
+ *          <P ALIGN="CENTER">ebcdic-cp-dk
+ *      </TD>
+ *      <TD WIDTH="12%">
+ *          <P ALIGN="CENTER">IANA
+ *      </TD>
+ *      <TD WIDTH="31%">
+ *          <P ALIGN="CENTER">cp277
+ *      </TD>
+ *  </TR>
+ *  <TR>
+ *      <TD WIDTH="33%">EBCDIC: Norway</TD>
+ *      <TD WIDTH="15%">
+ *          <P ALIGN="CENTER">ebcdic-cp-no
+ *      </TD>
+ *      <TD WIDTH="12%">
+ *          <P ALIGN="CENTER">IANA
+ *      </TD>
+ *      <TD WIDTH="31%">
+ *          <P ALIGN="CENTER">cp277
+ *      </TD>
+ *  </TR>
+ *  <TR>
+ *      <TD WIDTH="33%">EBCDIC: Finland</TD>
+ *      <TD WIDTH="15%">
+ *          <P ALIGN="CENTER">ebcdic-cp-fi
+ *      </TD>
+ *      <TD WIDTH="12%">
+ *          <P ALIGN="CENTER">IANA
+ *      </TD>
+ *      <TD WIDTH="31%">
+ *          <P ALIGN="CENTER">cp278
+ *      </TD>
+ *  </TR>
+ *  <TR>
+ *      <TD WIDTH="33%">EBCDIC: Sweden</TD>
+ *      <TD WIDTH="15%">
+ *          <P ALIGN="CENTER">ebcdic-cp-se
+ *      </TD>
+ *      <TD WIDTH="12%">
+ *          <P ALIGN="CENTER">IANA
+ *      </TD>
+ *      <TD WIDTH="31%">
+ *          <P ALIGN="CENTER">cp278
+ *      </TD>
+ *  </TR>
+ *  <TR>
+ *      <TD WIDTH="33%">EBCDIC: Italy</TD>
+ *      <TD WIDTH="15%">
+ *          <P ALIGN="CENTER">ebcdic-cp-it
+ *      </TD>
+ *      <TD WIDTH="12%">
+ *          <P ALIGN="CENTER">IANA
+ *      </TD>
+ *      <TD WIDTH="31%">
+ *          <P ALIGN="CENTER">cp280
+ *      </TD>
+ *  </TR>
+ *  <TR>
+ *      <TD WIDTH="33%">EBCDIC: Spain, Latin America</TD>
+ *      <TD WIDTH="15%">
+ *          <P ALIGN="CENTER">ebcdic-cp-es
+ *      </TD>
+ *      <TD WIDTH="12%">
+ *          <P ALIGN="CENTER">IANA
+ *      </TD>
+ *      <TD WIDTH="31%">
+ *          <P ALIGN="CENTER">cp284
+ *      </TD>
+ *  </TR>
+ *  <TR>
+ *      <TD WIDTH="33%">EBCDIC: Great Britain</TD>
+ *      <TD WIDTH="15%">
+ *          <P ALIGN="CENTER">ebcdic-cp-gb
+ *      </TD>
+ *      <TD WIDTH="12%">
+ *          <P ALIGN="CENTER">IANA
+ *      </TD>
+ *      <TD WIDTH="31%">
+ *          <P ALIGN="CENTER">cp285
+ *      </TD>
+ *  </TR>
+ *  <TR>
+ *      <TD WIDTH="33%">EBCDIC: France</TD>
+ *      <TD WIDTH="15%">
+ *          <P ALIGN="CENTER">ebcdic-cp-fr
+ *      </TD>
+ *      <TD WIDTH="12%">
+ *          <P ALIGN="CENTER">IANA
+ *      </TD>
+ *      <TD WIDTH="31%">
+ *          <P ALIGN="CENTER">cp297
+ *      </TD>
+ *  </TR>
+ *  <TR>
+ *      <TD WIDTH="33%">EBCDIC: Arabic</TD>
+ *      <TD WIDTH="15%">
+ *          <P ALIGN="CENTER">ebcdic-cp-ar1
+ *      </TD>
+ *      <TD WIDTH="12%">
+ *          <P ALIGN="CENTER">IANA
+ *      </TD>
+ *      <TD WIDTH="31%">
+ *          <P ALIGN="CENTER">cp420
+ *      </TD>
+ *  </TR>
+ *  <TR>
+ *      <TD WIDTH="33%">EBCDIC: Hebrew</TD>
+ *      <TD WIDTH="15%">
+ *          <P ALIGN="CENTER">ebcdic-cp-he
+ *      </TD>
+ *      <TD WIDTH="12%">
+ *          <P ALIGN="CENTER">IANA
+ *      </TD>
+ *      <TD WIDTH="31%">
+ *          <P ALIGN="CENTER">cp424
+ *      </TD>
+ *  </TR>
+ *  <TR>
+ *      <TD WIDTH="33%">EBCDIC: Switzerland</TD>
+ *      <TD WIDTH="15%">
+ *          <P ALIGN="CENTER">ebcdic-cp-ch
+ *      </TD>
+ *      <TD WIDTH="12%">
+ *          <P ALIGN="CENTER">IANA
+ *      </TD>
+ *      <TD WIDTH="31%">
+ *          <P ALIGN="CENTER">cp500
+ *      </TD>
+ *  </TR>
+ *  <TR>
+ *      <TD WIDTH="33%">EBCDIC: Roece</TD>
+ *      <TD WIDTH="15%">
+ *          <P ALIGN="CENTER">ebcdic-cp-roece
+ *      </TD>
+ *      <TD WIDTH="12%">
+ *          <P ALIGN="CENTER">IANA
+ *      </TD>
+ *      <TD WIDTH="31%">
+ *          <P ALIGN="CENTER">cp870
+ *      </TD>
+ *  </TR>
+ *  <TR>
+ *      <TD WIDTH="33%">EBCDIC: Yogoslavia</TD>
+ *      <TD WIDTH="15%">
+ *          <P ALIGN="CENTER">ebcdic-cp-yu
+ *      </TD>
+ *      <TD WIDTH="12%">
+ *          <P ALIGN="CENTER">IANA
+ *      </TD>
+ *      <TD WIDTH="31%">
+ *          <P ALIGN="CENTER">cp870
+ *      </TD>
+ *  </TR>
+ *  <TR>
+ *      <TD WIDTH="33%">EBCDIC: Iceland</TD>
+ *      <TD WIDTH="15%">
+ *          <P ALIGN="CENTER">ebcdic-cp-is
+ *      </TD>
+ *      <TD WIDTH="12%">
+ *          <P ALIGN="CENTER">IANA
+ *      </TD>
+ *      <TD WIDTH="31%">
+ *          <P ALIGN="CENTER">cp871
+ *      </TD>
+ *  </TR>
+ *  <TR>
+ *      <TD WIDTH="33%">EBCDIC: Urdu</TD>
+ *      <TD WIDTH="15%">
+ *          <P ALIGN="CENTER">ebcdic-cp-ar2
+ *      </TD>
+ *      <TD WIDTH="12%">
+ *          <P ALIGN="CENTER">IANA
+ *      </TD>
+ *      <TD WIDTH="31%">
+ *          <P ALIGN="CENTER">cp918
+ *      </TD>
+ *  </TR>
+ *  <TR>
+ *      <TD WIDTH="33%">Chinese for PRC, mixed 1/2 byte</TD>
+ *      <TD WIDTH="15%">
+ *          <P ALIGN="CENTER">gb2312
+ *      </TD>
+ *      <TD WIDTH="12%">
+ *          <P ALIGN="CENTER">MIME
+ *      </TD>
+ *      <TD WIDTH="31%">
+ *          <P ALIGN="CENTER">GB2312
+ *      </TD>
+ *  </TR>
+ *  <TR>
+ *      <TD WIDTH="33%">Extended Unix Code, packed for Japanese</TD>
+ *      <TD WIDTH="15%">
+ *          <P ALIGN="CENTER">euc-jp
+ *      </TD>
+ *      <TD WIDTH="12%">
+ *          <P ALIGN="CENTER">MIME
+ *      </TD>
+ *      <TD WIDTH="31%">
+ *          <P ALIGN="CENTER">eucjis
+ *      </TD>
+ *  </TR>
+ *  <TR>
+ *      <TD WIDTH="33%">Japanese: iso-2022-jp</TD>
+ *      <TD WIDTH="15%">
+ *          <P ALIGN="CENTER">iso-2020-jp
+ *      </TD>
+ *      <TD WIDTH="12%">
+ *          <P ALIGN="CENTER">MIME
+ *      </TD>
+ *      <TD WIDTH="31%">
+ *          <P ALIGN="CENTER">JIS
+ *      </TD>
+ *  </TR>
+ *  <TR>
+ *      <TD WIDTH="33%">Japanese: Shift JIS</TD>
+ *      <TD WIDTH="15%">
+ *          <P ALIGN="CENTER">Shift_JIS
+ *      </TD>
+ *      <TD WIDTH="12%">
+ *          <P ALIGN="CENTER">MIME
+ *      </TD>
+ *      <TD WIDTH="31%">
+ *          <P ALIGN="CENTER">SJIS
+ *      </TD>
+ *  </TR>
+ *  <TR>
+ *      <TD WIDTH="33%">Chinese: Big5</TD>
+ *      <TD WIDTH="15%">
+ *          <P ALIGN="CENTER">Big5
+ *      </TD>
+ *      <TD WIDTH="12%">
+ *          <P ALIGN="CENTER">MIME
+ *      </TD>
+ *      <TD WIDTH="31%">
+ *          <P ALIGN="CENTER">Big5
+ *      </TD>
+ *  </TR>
+ *  <TR>
+ *      <TD WIDTH="33%">Extended Unix Code, packed for Korean</TD>
+ *      <TD WIDTH="15%">
+ *          <P ALIGN="CENTER">euc-kr
+ *      </TD>
+ *      <TD WIDTH="12%">
+ *          <P ALIGN="CENTER">MIME
+ *      </TD>
+ *      <TD WIDTH="31%">
+ *          <P ALIGN="CENTER">iso2022kr
+ *      </TD>
+ *  </TR>
+ *  <TR>
+ *      <TD WIDTH="33%">Cyrillic</TD>
+ *      <TD WIDTH="15%">
+ *          <P ALIGN="CENTER">koi8-r
+ *      </TD>
+ *      <TD WIDTH="12%">
+ *          <P ALIGN="CENTER">MIME
+ *      </TD>
+ *      <TD WIDTH="31%">
+ *          <P ALIGN="CENTER">koi8-r
+ *      </TD>
+ *  </TR>
+ * </TABLE>
+ *
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ * @author TAMURA Kent &lt;kent at trl.ibm.co.jp&gt;
+ */
+public class MIME2Java {
+
+    static private Hashtable s_enchash;
+    static private Hashtable s_revhash;
+
+    static {
+        s_enchash = new Hashtable();
+        //    <preferred MIME name>, <Java encoding name>
+        s_enchash.put("UTF-8", "UTF8");
+        s_enchash.put("US-ASCII",        "8859_1");    // ?
+        s_enchash.put("ISO-8859-1",      "8859_1");
+        s_enchash.put("ISO-8859-2",      "8859_2");
+        s_enchash.put("ISO-8859-3",      "8859_3");
+        s_enchash.put("ISO-8859-4",      "8859_4");
+        s_enchash.put("ISO-8859-5",      "8859_5");
+        s_enchash.put("ISO-8859-6",      "8859_6");
+        s_enchash.put("ISO-8859-7",      "8859_7");
+        s_enchash.put("ISO-8859-8",      "8859_8");
+        s_enchash.put("ISO-8859-9",      "8859_9");
+        s_enchash.put("ISO-2022-JP",     "JIS");
+        s_enchash.put("SHIFT_JIS",       "SJIS");
+        s_enchash.put("EUC-JP",          "EUCJIS");
+        s_enchash.put("GB2312",          "GB2312");
+        s_enchash.put("BIG5",            "Big5");
+        s_enchash.put("EUC-KR",          "KSC5601");
+        s_enchash.put("ISO-2022-KR",     "ISO2022KR");
+        s_enchash.put("KOI8-R",          "KOI8_R");
+
+        s_enchash.put("EBCDIC-CP-US",    "CP037");
+        s_enchash.put("EBCDIC-CP-CA",    "CP037");
+        s_enchash.put("EBCDIC-CP-NL",    "CP037");
+        s_enchash.put("EBCDIC-CP-DK",    "CP277");
+        s_enchash.put("EBCDIC-CP-NO",    "CP277");
+        s_enchash.put("EBCDIC-CP-FI",    "CP278");
+        s_enchash.put("EBCDIC-CP-SE",    "CP278");
+        s_enchash.put("EBCDIC-CP-IT",    "CP280");
+        s_enchash.put("EBCDIC-CP-ES",    "CP284");
+        s_enchash.put("EBCDIC-CP-GB",    "CP285");
+        s_enchash.put("EBCDIC-CP-FR",    "CP297");
+        s_enchash.put("EBCDIC-CP-AR1",   "CP420");
+        s_enchash.put("EBCDIC-CP-HE",    "CP424");
+        s_enchash.put("EBCDIC-CP-CH",    "CP500");
+        s_enchash.put("EBCDIC-CP-ROECE", "CP870");
+        s_enchash.put("EBCDIC-CP-YU",    "CP870");
+        s_enchash.put("EBCDIC-CP-IS",    "CP871");
+        s_enchash.put("EBCDIC-CP-AR2",   "CP918");
+
+                                                // j:CNS11643 -> EUC-TW?
+                                                // ISO-2022-CN? ISO-2022-CN-EXT?
+
+        s_revhash = new Hashtable();
+        //    <Java encoding name>, <preferred MIME name>
+        s_revhash.put("UTF8", "UTF-8");
+        //s_revhash.put("8859_1", "US-ASCII");    // ?
+        s_revhash.put("8859_1", "ISO-8859-1");
+        s_revhash.put("8859_2", "ISO-8859-2");
+        s_revhash.put("8859_3", "ISO-8859-3");
+        s_revhash.put("8859_4", "ISO-8859-4");
+        s_revhash.put("8859_5", "ISO-8859-5");
+        s_revhash.put("8859_6", "ISO-8859-6");
+        s_revhash.put("8859_7", "ISO-8859-7");
+        s_revhash.put("8859_8", "ISO-8859-8");
+        s_revhash.put("8859_9", "ISO-8859-9");
+        s_revhash.put("JIS", "ISO-2022-JP");
+        s_revhash.put("SJIS", "Shift_JIS");
+        s_revhash.put("EUCJIS", "EUC-JP");
+        s_revhash.put("GB2312", "GB2312");
+        s_revhash.put("BIG5", "Big5");
+        s_revhash.put("KSC5601", "EUC-KR");
+        s_revhash.put("ISO2022KR", "ISO-2022-KR");
+        s_revhash.put("KOI8_R", "KOI8-R");
+
+        s_revhash.put("CP037", "EBCDIC-CP-US");
+        s_revhash.put("CP037", "EBCDIC-CP-CA");
+        s_revhash.put("CP037", "EBCDIC-CP-NL");
+        s_revhash.put("CP277", "EBCDIC-CP-DK");
+        s_revhash.put("CP277", "EBCDIC-CP-NO");
+        s_revhash.put("CP278", "EBCDIC-CP-FI");
+        s_revhash.put("CP278", "EBCDIC-CP-SE");
+        s_revhash.put("CP280", "EBCDIC-CP-IT");
+        s_revhash.put("CP284", "EBCDIC-CP-ES");
+        s_revhash.put("CP285", "EBCDIC-CP-GB");
+        s_revhash.put("CP297", "EBCDIC-CP-FR");
+        s_revhash.put("CP420", "EBCDIC-CP-AR1");
+        s_revhash.put("CP424", "EBCDIC-CP-HE");
+        s_revhash.put("CP500", "EBCDIC-CP-CH");
+        s_revhash.put("CP870", "EBCDIC-CP-ROECE");
+        s_revhash.put("CP870", "EBCDIC-CP-YU");
+        s_revhash.put("CP871", "EBCDIC-CP-IS");
+        s_revhash.put("CP918", "EBCDIC-CP-AR2");
+    }
+
+    private MIME2Java() {
+    }
+
+    /**
+     * Convert a MIME charset name, also known as an XML encoding name, to a Java encoding name.
+     * @param   mimeCharsetName Case insensitive MIME charset name: <code>UTF-8, US-ASCII, ISO-8859-1,
+     *                          ISO-8859-2, ISO-8859-3, ISO-8859-4, ISO-8859-5, ISO-8859-6,
+     *                          ISO-8859-7, ISO-8859-8, ISO-8859-9, ISO-2022-JP, Shift_JIS,
+     *                          EUC-JP, GB2312, Big5, EUC-KR, ISO-2022-KR, KOI8-R,
+     *                          EBCDIC-CP-US, EBCDIC-CP-CA, EBCDIC-CP-NL, EBCDIC-CP-DK,
+     *                          EBCDIC-CP-NO, EBCDIC-CP-FI, EBCDIC-CP-SE, EBCDIC-CP-IT,
+     *                          EBCDIC-CP-ES, EBCDIC-CP-GB, EBCDIC-CP-FR, EBCDIC-CP-AR1,
+     *                          EBCDIC-CP-HE, EBCDIC-CP-CH, EBCDIC-CP-ROECE, EBCDIC-CP-YU,
+     *                          EBCDIC-CP-IS and EBCDIC-CP-AR2</code>.
+     * @return                  Java encoding name, or <var>null</var> if <var>mimeCharsetName</var>
+     *                          is unknown.
+     * @see #reverse
+     */
+    public static String convert(String mimeCharsetName) {
+        return (String)s_enchash.get(mimeCharsetName.toUpperCase());
+    }
+
+    /**
+     * Convert a Java encoding name to MIME charset name.
+     * Available values of <i>encoding</i> are "UTF8", "8859_1", "8859_2", "8859_3", "8859_4",
+     * "8859_5", "8859_6", "8859_7", "8859_8", "8859_9", "JIS", "SJIS", "EUCJIS",
+     * "GB2312", "BIG5", "KSC5601", "ISO2022KR",  "KOI8_R", "CP037", "CP277", "CP278",
+     * "CP280", "CP284", "CP285", "CP297", "CP420", "CP424", "CP500", "CP870", "CP871" and "CP918".
+     * @param   encoding    Case insensitive Java encoding name: <code>UTF8, 8859_1, 8859_2, 8859_3,
+     *                      8859_4, 8859_5, 8859_6, 8859_7, 8859_8, 8859_9, JIS, SJIS, EUCJIS,
+     *                      GB2312, BIG5, KSC5601, ISO2022KR, KOI8_R, CP037, CP277, CP278,
+     *                      CP280, CP284, CP285, CP297, CP420, CP424, CP500, CP870, CP871
+     *                      and CP918</code>.
+     * @return              MIME charset name, or <var>null</var> if <var>encoding</var> is unknown.
+     * @see #convert
+     */
+    public static String reverse(String encoding) {
+        return (String)s_revhash.get(encoding.toUpperCase());
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/ManifestResource.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/ManifestResource.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/ManifestResource.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,241 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.util.Iterator;
+import java.util.jar.Manifest;
+import java.util.jar.Attributes;
+import java.util.ArrayList;
+
+/**
+ *  Representation of a Manifest file and its available extensions and
+ *  required extensions
+ *  
+ * @author Greg Murray
+ * @author Justyna Horwat
+ * @version $Revision: 360278 $ $Date: 2005-12-31 07:26:41 -0600 (Sat, 31 Dec 2005) $
+ * 
+ */
+public class ManifestResource {
+    
+    // ------------------------------------------------------------- Properties
+
+    // These are the resource types for determining effect error messages
+    public static final int SYSTEM = 1;
+    public static final int WAR = 2;
+    public static final int APPLICATION = 3;
+    
+    private ArrayList availableExtensions = null;
+    private ArrayList requiredExtensions = null;
+    
+    private String resourceName = null;
+    private int resourceType = -1;
+        
+    public ManifestResource(String resourceName, Manifest manifest, 
+                            int resourceType) {
+        this.resourceName = resourceName;
+        this.resourceType = resourceType;
+        processManifest(manifest);
+    }
+    
+    /**
+     * Gets the name of the resource
+     *
+     * @return The name of the resource
+     */
+    public String getResourceName() {
+        return resourceName;
+    }
+
+    /**
+     * Gets the list of available extensions
+     *
+     * @return List of available extensions
+     */
+    public ArrayList getAvailableExtensions() {
+        return availableExtensions;
+    }
+    
+    /**
+     * Gets the list of required extensions
+     *
+     * @return List of required extensions
+     */
+    public ArrayList getRequiredExtensions() {
+        return requiredExtensions;   
+    }
+    
+    // --------------------------------------------------------- Public Methods
+
+    /**
+     * Gets the number of available extensions
+     *
+     * @return The number of available extensions
+     */
+    public int getAvailableExtensionCount() {
+        return (availableExtensions != null) ? availableExtensions.size() : 0;
+    }
+    
+    /**
+     * Gets the number of required extensions
+     *
+     * @return The number of required extensions
+     */
+    public int getRequiredExtensionCount() {
+        return (requiredExtensions != null) ? requiredExtensions.size() : 0;
+    }
+    
+    /**
+     * Convienience method to check if this <code>ManifestResource</code>
+     * has an requires extensions.
+     *
+     * @return true if required extensions are present
+     */
+    public boolean requiresExtensions() {
+        return (requiredExtensions != null) ? true : false;
+    }
+    
+    /**
+     * Returns <code>true</code> if all required extension dependencies
+     * have been meet for this <code>ManifestResource</code> object.
+     *
+     * @return boolean true if all extension dependencies have been satisfied
+     */
+    public boolean isFulfilled() {
+        if (requiredExtensions == null) {
+            return false;
+        }
+        Iterator it = requiredExtensions.iterator();
+        while (it.hasNext()) {
+            Extension ext = (Extension)it.next();
+            if (!ext.isFulfilled()) return false;            
+        }
+        return true;
+    }
+    
+    public String toString() {
+
+        StringBuffer sb = new StringBuffer("ManifestResource[");
+        sb.append(resourceName);
+
+        sb.append(", isFulfilled=");
+        sb.append(isFulfilled() +"");
+        sb.append(", requiredExtensionCount =");
+        sb.append(getRequiredExtensionCount());
+        sb.append(", availableExtensionCount=");
+        sb.append(getAvailableExtensionCount());
+        switch (resourceType) {
+            case SYSTEM : sb.append(", resourceType=SYSTEM"); break;
+            case WAR : sb.append(", resourceType=WAR"); break;
+            case APPLICATION : sb.append(", resourceType=APPLICATION"); break;
+        }
+        sb.append("]");
+        return (sb.toString());
+    }
+
+
+    // -------------------------------------------------------- Private Methods
+
+    private void processManifest(Manifest manifest) {
+        availableExtensions = getAvailableExtensions(manifest);
+        requiredExtensions = getRequiredExtensions(manifest);
+    }
+    
+    /**
+     * Return the set of <code>Extension</code> objects representing optional
+     * packages that are required by the application associated with the
+     * specified <code>Manifest</code>.
+     *
+     * @param manifest Manifest to be parsed
+     *
+     * @return List of required extensions, or null if the application
+     * does not require any extensions
+     */
+    private ArrayList getRequiredExtensions(Manifest manifest) {
+
+        Attributes attributes = manifest.getMainAttributes();
+        String names = attributes.getValue("Extension-List");
+        if (names == null)
+            return null;
+
+        ArrayList extensionList = new ArrayList();
+        names += " ";
+
+        while (true) {
+
+            int space = names.indexOf(' ');
+            if (space < 0)
+                break;
+            String name = names.substring(0, space).trim();
+            names = names.substring(space + 1);
+
+            String value =
+                attributes.getValue(name + "-Extension-Name");
+            if (value == null)
+                continue;
+            Extension extension = new Extension();
+            extension.setExtensionName(value);
+            extension.setImplementationURL
+                (attributes.getValue(name + "-Implementation-URL"));
+            extension.setImplementationVendorId
+                (attributes.getValue(name + "-Implementation-Vendor-Id"));
+            String version = attributes.getValue(name + "-Implementation-Version");
+            extension.setImplementationVersion(version);
+            extension.setSpecificationVersion
+                (attributes.getValue(name + "-Specification-Version"));
+            extensionList.add(extension);
+        }
+        return extensionList;
+    }
+    
+    /**
+     * Return the set of <code>Extension</code> objects representing optional
+     * packages that are bundled with the application associated with the
+     * specified <code>Manifest</code>.
+     *
+     * @param manifest Manifest to be parsed
+     *
+     * @return List of available extensions, or null if the web application
+     * does not bundle any extensions
+     */
+    private ArrayList getAvailableExtensions(Manifest manifest) {
+
+        Attributes attributes = manifest.getMainAttributes();
+        String name = attributes.getValue("Extension-Name");
+        if (name == null)
+            return null;
+
+        ArrayList extensionList = new ArrayList();
+
+        Extension extension = new Extension();
+        extension.setExtensionName(name);
+        extension.setImplementationURL(
+            attributes.getValue("Implementation-URL"));
+        extension.setImplementationVendor(
+            attributes.getValue("Implementation-Vendor"));
+        extension.setImplementationVendorId(
+            attributes.getValue("Implementation-Vendor-Id"));
+        extension.setImplementationVersion(
+            attributes.getValue("Implementation-Version"));
+        extension.setSpecificationVersion(
+            attributes.getValue("Specification-Version"));
+
+        extensionList.add(extension);
+
+        return extensionList;
+    }
+    
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/ParameterMap.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/ParameterMap.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/ParameterMap.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,211 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.util.HashMap;
+import java.util.Map;
+
+
+/**
+ * Extended implementation of <strong>HashMap</strong> that includes a
+ * <code>locked</code> property.  This class can be used to safely expose
+ * Catalina internal parameter map objects to user classes without having
+ * to clone them in order to avoid modifications.  When first created, a
+ * <code>ParmaeterMap</code> instance is not locked.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public final class ParameterMap extends HashMap {
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Construct a new, empty map with the default initial capacity and
+     * load factor.
+     */
+    public ParameterMap() {
+
+        super();
+
+    }
+
+
+    /**
+     * Construct a new, empty map with the specified initial capacity and
+     * default load factor.
+     *
+     * @param initialCapacity The initial capacity of this map
+     */
+    public ParameterMap(int initialCapacity) {
+
+        super(initialCapacity);
+
+    }
+
+
+    /**
+     * Construct a new, empty map with the specified initial capacity and
+     * load factor.
+     *
+     * @param initialCapacity The initial capacity of this map
+     * @param loadFactor The load factor of this map
+     */
+    public ParameterMap(int initialCapacity, float loadFactor) {
+
+        super(initialCapacity, loadFactor);
+
+    }
+
+
+    /**
+     * Construct a new map with the same mappings as the given map.
+     *
+     * @param map Map whose contents are dupliated in the new map
+     */
+    public ParameterMap(Map map) {
+
+        super(map);
+
+    }
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * The current lock state of this parameter map.
+     */
+    private boolean locked = false;
+
+
+    /**
+     * Return the locked state of this parameter map.
+     */
+    public boolean isLocked() {
+
+        return (this.locked);
+
+    }
+
+
+    /**
+     * Set the locked state of this parameter map.
+     *
+     * @param locked The new locked state
+     */
+    public void setLocked(boolean locked) {
+
+        this.locked = locked;
+
+    }
+
+
+    /**
+     * The string manager for this package.
+     */
+    private static final StringManager sm =
+        StringManager.getManager("org.apache.catalina.util");
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+
+    /**
+     * Remove all mappings from this map.
+     *
+     * @exception IllegalStateException if this map is currently locked
+     */
+    public void clear() {
+
+        if (locked)
+            throw new IllegalStateException
+                (sm.getString("parameterMap.locked"));
+        super.clear();
+
+    }
+
+
+    /**
+     * Associate the specified value with the specified key in this map.  If
+     * the map previously contained a mapping for this key, the old value is
+     * replaced.
+     *
+     * @param key Key with which the specified value is to be associated
+     * @param value Value to be associated with the specified key
+     *
+     * @return The previous value associated with the specified key, or
+     *  <code>null</code> if there was no mapping for key
+     *
+     * @exception IllegalStateException if this map is currently locked
+     */
+    public Object put(Object key, Object value) {
+
+        if (locked)
+            throw new IllegalStateException
+                (sm.getString("parameterMap.locked"));
+        return (super.put(key, value));
+
+    }
+
+
+    /**
+     * Copy all of the mappings from the specified map to this one.  These
+     * mappings replace any mappings that this map had for any of the keys
+     * currently in the specified Map.
+     *
+     * @param map Mappings to be stored into this map
+     *
+     * @exception IllegalStateException if this map is currently locked
+     */
+    public void putAll(Map map) {
+
+        if (locked)
+            throw new IllegalStateException
+                (sm.getString("parameterMap.locked"));
+        super.putAll(map);
+
+    }
+
+
+    /**
+     * Remove the mapping for this key from the map if present.
+     *
+     * @param key Key whose mapping is to be removed from the map
+     *
+     * @return The previous value associated with the specified key, or
+     *  <code>null</code> if there was no mapping for that key
+     *
+     * @exception IllegalStateException if this map is currently locked
+     */
+    public Object remove(Object key) {
+
+        if (locked)
+            throw new IllegalStateException
+                (sm.getString("parameterMap.locked"));
+        return (super.remove(key));
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/ProcessEnvironment.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/ProcessEnvironment.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/ProcessEnvironment.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,316 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.io.File;
+import java.util.Enumeration;
+import java.util.Hashtable;
+
+import javax.servlet.ServletContext;
+import javax.servlet.http.HttpServletRequest;
+
+
+
+/**
+ * Encapsulates the Process environment and rules to derive
+ * that environment from the servlet container and request information.
+ * @author   Martin Dengler [root at martindengler.com]
+ * @version  $Revision: 421480 $, $Date: 2006-07-12 21:26:36 -0500 (Wed, 12 Jul 2006) $
+ * @since    Tomcat 4.0
+ * @deprecated
+ */
+public class ProcessEnvironment {
+    
+    private static org.apache.commons.logging.Log log=
+        org.apache.commons.logging.LogFactory.getLog( ProcessEnvironment.class );
+    
+    /** context of the enclosing servlet */
+    private ServletContext context = null;
+
+    /** real file system directory of the enclosing servlet's web app */
+    private String webAppRootDir = null;
+
+    /** context path of enclosing servlet */
+    private String contextPath = null;
+
+    /** pathInfo for the current request */
+    protected String pathInfo = null;
+
+    /** servlet URI of the enclosing servlet */
+    private String servletPath = null;
+
+    /** derived process environment */
+    protected Hashtable env = null;
+
+    /** command to be invoked */
+    protected String command = null;
+
+    /** whether or not this object is valid or not */
+    protected boolean valid = false;
+
+    /** the debugging detail level for this instance. */
+    protected int debug = 0;
+
+    /** process' desired working directory */
+    protected File workingDirectory = null;
+
+
+    /**
+     * Creates a ProcessEnvironment and derives the necessary environment,
+     * working directory, command, etc.
+     * @param  req       HttpServletRequest for information provided by
+     *                   the Servlet API
+     * @param  context   ServletContext for information provided by
+     *                   the Servlet API
+     */
+    public ProcessEnvironment(HttpServletRequest req,
+        ServletContext context) {
+        this(req, context, 0);
+    }
+
+
+    /**
+     * Creates a ProcessEnvironment and derives the necessary environment,
+     * working directory, command, etc.
+     * @param  req       HttpServletRequest for information provided by
+     *                   the Servlet API
+     * @param  context   ServletContext for information provided by
+     *                   the Servlet API
+     * @param  debug     int debug level (0 == none, 4 == medium, 6 == lots)
+     */
+    public ProcessEnvironment(HttpServletRequest req,
+        ServletContext context, int debug) {
+            this.debug = debug;
+            setupFromContext(context);
+            setupFromRequest(req);
+            this.valid = deriveProcessEnvironment(req);
+            if (log.isDebugEnabled()) 
+                log.debug(this.getClass().getName() + "() ctor, debug level " + 
+                          debug);
+    }
+
+
+    /**
+     * Uses the ServletContext to set some process variables
+     * @param  context   ServletContext for information provided by
+     *                   the Servlet API
+     */
+    protected void setupFromContext(ServletContext context) {
+        this.context = context;
+        this.webAppRootDir = context.getRealPath("/");
+    }
+
+
+    /**
+     * Uses the HttpServletRequest to set most process variables
+     * @param  req   HttpServletRequest for information provided by
+     *               the Servlet API
+     */
+    protected void setupFromRequest(HttpServletRequest req) {
+        this.contextPath = req.getContextPath();
+        this.pathInfo = req.getPathInfo();
+        this.servletPath = req.getServletPath();
+    }
+
+
+    /**
+     * Print important process environment information in an
+     * easy-to-read HTML table
+     * @return  HTML string containing process environment info
+     */
+    public String toString() {
+        StringBuffer sb = new StringBuffer();
+        sb.append("<TABLE border=2>");
+        sb.append("<tr><th colspan=2 bgcolor=grey>");
+        sb.append("ProcessEnvironment Info</th></tr>");
+        sb.append("<tr><td>Debug Level</td><td>");
+        sb.append(debug);
+        sb.append("</td></tr>");
+        sb.append("<tr><td>Validity:</td><td>");
+        sb.append(isValid());
+        sb.append("</td></tr>");
+        if (isValid()) {
+            Enumeration envk = env.keys();
+            while (envk.hasMoreElements()) {
+                String s = (String)envk.nextElement();
+                sb.append("<tr><td>");
+                sb.append(s);
+                sb.append("</td><td>");
+                sb.append(blanksToString((String)env.get(s),
+                    "[will be set to blank]"));
+                    sb.append("</td></tr>");
+            }
+        }
+        sb.append("<tr><td colspan=2><HR></td></tr>");
+        sb.append("<tr><td>Derived Command</td><td>");
+        sb.append(nullsToBlanks(command));
+        sb.append("</td></tr>");
+        sb.append("<tr><td>Working Directory</td><td>");
+        if (workingDirectory != null) {
+            sb.append(workingDirectory.toString());
+        }
+        sb.append("</td></tr>");
+        sb.append("</TABLE><p>end.");
+        return sb.toString();
+    }
+
+
+    /**
+     * Gets derived command string
+     * @return  command string
+     */
+    public String getCommand() {
+        return command;
+    }
+
+
+    /**
+     * Sets the desired command string
+     * @param   command String command as desired
+     * @return  command string
+     */
+    protected String setCommand(String command) {
+        return command;
+    }
+
+
+    /**
+     * Gets this process' derived working directory
+     * @return  working directory
+     */
+    public File getWorkingDirectory() {
+        return workingDirectory;
+    }
+
+
+    /**
+     * Gets process' environment
+     * @return   process' environment
+     */
+    public Hashtable getEnvironment() {
+        return env;
+    }
+
+
+    /**
+     * Sets process' environment
+     * @param    env process' environment
+     * @return   Hashtable to which the process' environment was set
+     */
+    public Hashtable setEnvironment(Hashtable env) {
+        this.env = env;
+        return this.env;
+    }
+
+
+    /**
+     * Gets validity status
+     * @return   true if this environment is valid, false otherwise
+     */
+    public boolean isValid() {
+        return valid;
+    }
+
+
+    /**
+     * Converts null strings to blank strings ("")
+     * @param    s string to be converted if necessary
+     * @return   a non-null string, either the original or the empty string
+     *           ("") if the original was <code>null</code>
+     */
+    protected String nullsToBlanks(String s) {
+        return nullsToString(s, "");
+    }
+
+
+    /**
+     * Converts null strings to another string
+     * @param    couldBeNull string to be converted if necessary
+     * @param    subForNulls string to return instead of a null string
+     * @return   a non-null string, either the original or the substitute
+     *           string if the original was <code>null</code>
+     */
+    protected String nullsToString(String couldBeNull, String subForNulls) {
+        return (couldBeNull == null ? subForNulls : couldBeNull);
+    }
+
+
+    /**
+     * Converts blank strings to another string
+     * @param    couldBeBlank string to be converted if necessary
+     * @param    subForBlanks string to return instead of a blank string
+     * @return   a non-null string, either the original or the substitute
+     *           string if the original was <code>null</code> or empty ("")
+     */
+    protected String blanksToString(String couldBeBlank,
+        String subForBlanks) {
+            return (("".equals(couldBeBlank) || couldBeBlank == null) ?
+                subForBlanks : couldBeBlank);
+    }
+
+
+    /**
+     * Constructs the Process environment to be supplied to the invoked
+     * process.  Defines an environment no environment variables.
+     * <p>
+     * Should be overriden by subclasses to perform useful setup.
+     * </p>
+     *
+     * @param    req request associated with the
+     *           Process' invocation
+     * @return   true if environment was set OK, false if there was a problem
+     *           and no environment was set
+     */
+    protected boolean deriveProcessEnvironment(HttpServletRequest req) {
+
+        Hashtable envp = new Hashtable();
+        command = getCommand();
+        if (command != null) {
+            workingDirectory = new
+                File(command.substring(0,
+                command.lastIndexOf(File.separator)));
+                envp.put("X_TOMCAT_COMMAND_PATH", command); //for kicks
+        }
+        this.env = envp;
+        return true;
+    }
+
+
+    /**
+     * Gets the root directory of the web application to which this process\
+     * belongs
+     * @return  root directory
+     */
+    public String getWebAppRootDir() {
+        return webAppRootDir;
+    }
+
+
+    public String getContextPath(){
+            return contextPath;
+        }
+
+
+    public ServletContext getContext(){
+            return context;
+        }
+
+
+    public String getServletPath(){
+            return servletPath;
+        }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/ProcessHelper.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/ProcessHelper.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/ProcessHelper.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,497 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.io.BufferedOutputStream;
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Vector;
+
+import javax.servlet.http.HttpServletResponse;
+
+/**
+     * Encapsulates the knowledge of how to run a CGI script, given the
+     * script's desired environment and (optionally) input/output streams
+     *
+     * <p>
+     *
+     * Exposes a <code>run</code> method used to actually invoke the
+     * CGI.
+     *
+     * </p>
+     * <p>
+     *
+     * The CGI environment and settings are derived from the information
+     * passed to the constuctor.
+     *
+     * </p>
+     * <p>
+     *
+     * The input and output streams can be set by the <code>setInput</code>
+     * and <code>setResponse</code> methods, respectively.
+     * </p>
+     *
+     * @author    Martin Dengler [root at martindengler.com]
+     * @version   $Revision: 421480 $, $Date: 2006-07-12 21:26:36 -0500 (Wed, 12 Jul 2006) $
+     * @deprecated
+     */
+public class ProcessHelper {
+
+    private static org.apache.commons.logging.Log log=
+        org.apache.commons.logging.LogFactory.getLog( ProcessHelper.class );
+    
+    /** script/command to be executed */
+    private String command = null;
+
+    /** environment used when invoking the cgi script */
+    private Hashtable env = null;
+
+    /** working directory used when invoking the cgi script */
+    private File wd = null;
+
+    /** query parameters to be passed to the invoked script */
+    private Hashtable params = null;
+
+    /** stdin to be passed to cgi script */
+    private InputStream stdin = null;
+
+    /** response object used to set headers & get output stream */
+    private HttpServletResponse response = null;
+
+    /** boolean tracking whether this object has enough info to run() */
+    private boolean readyToRun = false;
+
+    /** the debugging detail level for this instance. */
+    private int debug = 0;
+
+    /** the time in ms to wait for the client to send us CGI input data */
+    private int iClientInputTimeout;
+
+    /**
+     *  Creates a ProcessHelper and initializes its environment, working
+     *  directory, and query parameters.
+     *  <BR>
+     *  Input/output streams (optional) are set using the
+     *  <code>setInput</code> and <code>setResponse</code> methods,
+     *  respectively.
+     *
+     * @param  command  string full path to command to be executed
+     * @param  env      Hashtable with the desired script environment
+     * @param  wd       File with the script's desired working directory
+     * @param  params   Hashtable with the script's query parameters
+     */
+    public ProcessHelper(
+        String command,
+        Hashtable env,
+        File wd,
+        Hashtable params) {
+        this.command = command;
+        this.env = env;
+        this.wd = wd;
+        this.params = params;
+        updateReadyStatus();
+    }
+
+    /**
+     * Checks & sets ready status
+     */
+    protected void updateReadyStatus() {
+        if (command != null
+            && env != null
+            && wd != null
+            && params != null
+            && response != null) {
+            readyToRun = true;
+        } else {
+            readyToRun = false;
+        }
+    }
+
+    /**
+     * Gets ready status
+     *
+     * @return   false if not ready (<code>run</code> will throw
+     *           an exception), true if ready
+     */
+    public boolean isReady() {
+        return readyToRun;
+    }
+
+    /**
+     * Sets HttpServletResponse object used to set headers and send
+     * output to
+     *
+     * @param  response   HttpServletResponse to be used
+     *
+     */
+    public void setResponse(HttpServletResponse response) {
+        this.response = response;
+        updateReadyStatus();
+    }
+
+    /**
+     * Sets standard input to be passed on to the invoked cgi script
+     *
+     * @param  stdin   InputStream to be used
+     *
+     */
+    public void setInput(InputStream stdin) {
+        this.stdin = stdin;
+        updateReadyStatus();
+    }
+
+    /**
+     * Converts a Hashtable to a String array by converting each
+     * key/value pair in the Hashtable to a String in the form
+     * "key=value" (hashkey + "=" + hash.get(hashkey).toString())
+     *
+     * @param  h   Hashtable to convert
+     *
+     * @return     converted string array
+     *
+     * @exception  NullPointerException   if a hash key has a null value
+     *
+     */
+    private String[] hashToStringArray(Hashtable h)
+        throws NullPointerException {
+        Vector v = new Vector();
+        Enumeration e = h.keys();
+        while (e.hasMoreElements()) {
+            String k = e.nextElement().toString();
+            v.add(k + "=" + h.get(k));
+        }
+        String[] strArr = new String[v.size()];
+        v.copyInto(strArr);
+        return strArr;
+    }
+
+    /**
+     * Executes a process script with the desired environment, current working
+     * directory, and input/output streams
+     *
+     * <p>
+     * This implements the following CGI specification recommedations:
+     * <UL>
+     * <LI> Servers SHOULD provide the "<code>query</code>" component of
+     *      the script-URI as command-line arguments to scripts if it
+     *      does not contain any unencoded "=" characters and the
+     *      command-line arguments can be generated in an unambiguous
+     *      manner.
+     * <LI> Servers SHOULD set the AUTH_TYPE metavariable to the value
+     *      of the "<code>auth-scheme</code>" token of the
+     *      "<code>Authorization</code>" if it was supplied as part of the
+     *      request header.  See <code>getCGIEnvironment</code> method.
+     * <LI> Where applicable, servers SHOULD set the current working
+     *      directory to the directory in which the script is located
+     *      before invoking it.
+     * <LI> Server implementations SHOULD define their behavior for the
+     *      following cases:
+     *     <ul>
+     *     <LI> <u>Allowed characters in pathInfo</u>:  This implementation
+     *             does not allow ASCII NUL nor any character which cannot
+     *             be URL-encoded according to internet standards;
+     *     <LI> <u>Allowed characters in path segments</u>: This
+     *             implementation does not allow non-terminal NULL
+     *             segments in the the path -- IOExceptions may be thrown;
+     *     <LI> <u>"<code>.</code>" and "<code>..</code>" path
+     *             segments</u>:
+     *             This implementation does not allow "<code>.</code>" and
+     *             "<code>..</code>" in the the path, and such characters
+     *             will result in an IOException being thrown;
+     *     <LI> <u>Implementation limitations</u>: This implementation
+     *             does not impose any limitations except as documented
+     *             above.  This implementation may be limited by the
+     *             servlet container used to house this implementation.
+     *             In particular, all the primary CGI variable values
+     *             are derived either directly or indirectly from the
+     *             container's implementation of the Servlet API methods.
+     *     </ul>
+     * </UL>
+     * </p>
+     *
+     * For more information, see java.lang.Runtime#exec(String command, 
+     * String[] envp, File dir)
+     *
+     * @exception IOException if problems during reading/writing occur
+     *
+     */
+    public void run() throws IOException {
+
+        /*
+         * REMIND:  this method feels too big; should it be re-written?
+         */
+
+        if (!isReady()) {
+            throw new IOException(
+                this.getClass().getName() + ": not ready to run.");
+        }
+
+        if (log.isDebugEnabled()) {
+            log.debug("runCGI(envp=[" + env + "], command=" + command + ")");
+        }
+
+        if ((command.indexOf(File.separator + "." + File.separator) >= 0)
+            || (command.indexOf(File.separator + "..") >= 0)
+            || (command.indexOf(".." + File.separator) >= 0)) {
+            throw new IOException(
+                this.getClass().getName()
+                    + "Illegal Character in CGI command "
+                    + "path ('.' or '..') detected.  Not "
+                    + "running CGI ["
+                    + command
+                    + "].");
+        }
+
+        /* original content/structure of this section taken from
+         * http://developer.java.sun.com/developer/
+         *                               bugParade/bugs/4216884.html
+         * with major modifications by Martin Dengler
+         */
+        Runtime rt = null;
+        BufferedReader commandsStdOut = null;
+        BufferedReader commandsStdErr = null;
+        BufferedOutputStream commandsStdIn = null;
+        Process proc = null;
+        byte[] bBuf = new byte[1024];
+        char[] cBuf = new char[1024];
+        int bufRead = -1;
+
+        //create query arguments
+        Enumeration paramNames = params.keys();
+        StringBuffer cmdAndArgs = new StringBuffer(command);
+        if (paramNames != null && paramNames.hasMoreElements()) {
+            cmdAndArgs.append(" ");
+            while (paramNames.hasMoreElements()) {
+                String k = (String) paramNames.nextElement();
+                String v = params.get(k).toString();
+                if ((k.indexOf("=") < 0) && (v.indexOf("=") < 0)) {
+                    cmdAndArgs.append(k);
+                    cmdAndArgs.append("=");
+                    v = java.net.URLEncoder.encode(v);
+                    cmdAndArgs.append(v);
+                    cmdAndArgs.append(" ");
+                }
+            }
+        }
+
+        String postIn = getPostInput(params);
+        int contentLength =
+            (postIn.length() + System.getProperty("line.separator").length());
+        if ("POST".equals(env.get("REQUEST_METHOD"))) {
+            env.put("CONTENT_LENGTH", new Integer(contentLength));
+        }
+
+        rt = Runtime.getRuntime();
+        proc = rt.exec(cmdAndArgs.toString(), hashToStringArray(env), wd);
+
+        /*
+         * provide input to cgi
+         * First  -- parameters
+         * Second -- any remaining input
+         */
+        commandsStdIn = new BufferedOutputStream(proc.getOutputStream());
+        if (log.isDebugEnabled()) {
+            log.debug("runCGI stdin=[" + stdin + "], qs=" + env.get("QUERY_STRING"));
+        }
+        if ("POST".equals(env.get("REQUEST_METHOD"))) {
+            if (log.isDebugEnabled()) {
+                log.debug("runCGI: writing ---------------\n");
+                log.debug(postIn);
+                log.debug(
+                    "runCGI: new content_length="
+                        + contentLength
+                        + "---------------\n");
+            }
+            commandsStdIn.write(postIn.getBytes());
+        }
+        if (stdin != null) {
+            //REMIND: document this
+            /* assume if nothing is available after a time, that nothing is
+             * coming...
+             */
+            if (stdin.available() <= 0) {
+                if (log.isDebugEnabled()) {
+                    log.debug(
+                        "runCGI stdin is NOT available ["
+                            + stdin.available()
+                            + "]");
+                }
+                try {
+                    Thread.sleep(iClientInputTimeout);
+                } catch (InterruptedException ignored) {
+                }
+            }
+            if (stdin.available() > 0) {
+                if (log.isDebugEnabled()) {
+                    log.debug(
+                        "runCGI stdin IS available ["
+                            + stdin.available()
+                            + "]");
+                }
+                bBuf = new byte[1024];
+                bufRead = -1;
+                try {
+                    while ((bufRead = stdin.read(bBuf)) != -1) {
+                        if (log.isDebugEnabled()) {
+                            log.debug(
+                                "runCGI: read ["
+                                    + bufRead
+                                    + "] bytes from stdin");
+                        }
+                        commandsStdIn.write(bBuf, 0, bufRead);
+                    }
+                    if (log.isDebugEnabled()) {
+                        log.debug("runCGI: DONE READING from stdin");
+                    }
+                } catch (IOException ioe) {
+                    log.error("runCGI: couldn't write all bytes.", ioe);
+                }
+            }
+        }
+        commandsStdIn.flush();
+        commandsStdIn.close();
+
+        /* we want to wait for the process to exit,  Process.waitFor()
+         * is useless in our situation; see
+         * http://developer.java.sun.com/developer/
+         *                               bugParade/bugs/4223650.html
+         */
+
+        boolean isRunning = true;
+        commandsStdOut =
+            new BufferedReader(new InputStreamReader(proc.getInputStream()));
+        commandsStdErr =
+            new BufferedReader(new InputStreamReader(proc.getErrorStream()));
+        BufferedWriter servletContainerStdout = null;
+
+        try {
+            if (response.getOutputStream() != null) {
+                servletContainerStdout =
+                    new BufferedWriter(
+                        new OutputStreamWriter(response.getOutputStream()));
+            }
+        } catch (IOException ignored) {
+            //NOOP: no output will be written
+        }
+
+        while (isRunning) {
+
+            try {
+                //read stderr first
+                cBuf = new char[1024];
+                while ((bufRead = commandsStdErr.read(cBuf)) != -1) {
+                    if (servletContainerStdout != null) {
+                        servletContainerStdout.write(cBuf, 0, bufRead);
+                    }
+                }
+
+                //set headers
+                String line = null;
+                while (((line = commandsStdOut.readLine()) != null)
+                    && !("".equals(line))) {
+                    if (log.isDebugEnabled()) {
+                        log.debug("runCGI: addHeader(\"" + line + "\")");
+                    }
+                    if (line.startsWith("HTTP")) {
+                        //TODO: should set status codes (NPH support)
+                        /*
+                         * response.setStatus(getStatusCode(line));
+                         */
+                    } else {
+                        response.addHeader(
+                            line.substring(0, line.indexOf(":")).trim(),
+                            line.substring(line.indexOf(":") + 1).trim());
+                    }
+                }
+
+                //write output
+                cBuf = new char[1024];
+                while ((bufRead = commandsStdOut.read(cBuf)) != -1) {
+                    if (servletContainerStdout != null) {
+                        if (log.isDebugEnabled()) {
+                            log.debug("runCGI: write(\"" + new String(cBuf) + "\")");
+                        }
+                        servletContainerStdout.write(cBuf, 0, bufRead);
+                    }
+                }
+
+                if (servletContainerStdout != null) {
+                    servletContainerStdout.flush();
+                }
+
+                proc.exitValue(); // Throws exception if alive
+
+                isRunning = false;
+
+            } catch (IllegalThreadStateException e) {
+                try {
+                    Thread.sleep(500);
+                } catch (InterruptedException ignored) {
+                }
+            }
+        } //replacement for Process.waitFor()
+
+    }
+
+    /**
+     * Gets a string for input to a POST cgi script
+     *
+     * @param  params   Hashtable of query parameters to be passed to
+     *                  the CGI script
+     * @return          for use as input to the CGI script
+     */
+
+    protected String getPostInput(Hashtable params) {
+        String lineSeparator = System.getProperty("line.separator");
+        Enumeration paramNames = params.keys();
+        StringBuffer postInput = new StringBuffer("");
+        StringBuffer qs = new StringBuffer("");
+        if (paramNames != null && paramNames.hasMoreElements()) {
+            while (paramNames.hasMoreElements()) {
+                String k = (String) paramNames.nextElement();
+                String v = params.get(k).toString();
+                if ((k.indexOf("=") < 0) && (v.indexOf("=") < 0)) {
+                    postInput.append(k);
+                    qs.append(k);
+                    postInput.append("=");
+                    qs.append("=");
+                    postInput.append(v);
+                    qs.append(v);
+                    postInput.append(lineSeparator);
+                    qs.append("&");
+                }
+            }
+        }
+        qs.append(lineSeparator);
+        return qs.append(postInput).toString();
+    }
+
+    public int getIClientInputTimeout() {
+        return iClientInputTimeout;
+    }
+
+    public void setIClientInputTimeout(int iClientInputTimeout) {
+        this.iClientInputTimeout = iClientInputTimeout;
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/Queue.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/Queue.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/Queue.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,87 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.util.Vector;
+
+/**
+ * A simple FIFO queue class which causes the calling thread to wait
+ * if the queue is empty and notifies threads that are waiting when it
+ * is not empty.
+ *
+ * @author Anil V (akv at eng.sun.com)
+ */
+public class Queue {
+    private Vector vector = new Vector();
+
+    /**
+     * Put the object into the queue.
+     *
+     * @param   object          the object to be appended to the
+     *                          queue.
+     */
+    public synchronized void put(Object object) {
+        vector.addElement(object);
+        notify();
+    }
+
+    /**
+     * Pull the first object out of the queue. Wait if the queue is
+     * empty.
+     */
+    public synchronized Object pull() {
+        while (isEmpty())
+            try {
+                wait();
+            } catch (InterruptedException ex) {
+            }
+        return get();
+    }
+
+    /**
+     * Get the first object out of the queue. Return null if the queue
+     * is empty.
+     */
+    public synchronized Object get() {
+        Object object = peek();
+        if (object != null)
+            vector.removeElementAt(0);
+        return object;
+    }
+
+    /**
+     * Peek to see if something is available.
+     */
+    public Object peek() {
+        if (isEmpty())
+            return null;
+        return vector.elementAt(0);
+    }
+
+    /**
+     * Is the queue empty?
+     */
+    public boolean isEmpty() {
+        return vector.isEmpty();
+    }
+
+    /**
+     * How many elements are there in this queue?
+     */
+    public int size() {
+        return vector.size();
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/RequestUtil.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/RequestUtil.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/RequestUtil.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,509 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.io.UnsupportedEncodingException;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Map;
+import java.util.TimeZone;
+
+import javax.servlet.http.Cookie;
+
+
+/**
+ * General purpose request parsing and encoding utility methods.
+ *
+ * @author Craig R. McClanahan
+ * @author Tim Tye
+ * @version $Revision: 302905 $ $Date: 2004-05-26 11:41:54 -0500 (Wed, 26 May 2004) $
+ */
+
+public final class RequestUtil {
+
+
+    /**
+     * The DateFormat to use for generating readable dates in cookies.
+     */
+    private static SimpleDateFormat format =
+        new SimpleDateFormat(" EEEE, dd-MMM-yy kk:mm:ss zz");
+
+    static {
+        format.setTimeZone(TimeZone.getTimeZone("GMT"));
+    }
+
+
+    /**
+     * Encode a cookie as per RFC 2109.  The resulting string can be used
+     * as the value for a <code>Set-Cookie</code> header.
+     *
+     * @param cookie The cookie to encode.
+     * @return A string following RFC 2109.
+     */
+    public static String encodeCookie(Cookie cookie) {
+
+        StringBuffer buf = new StringBuffer( cookie.getName() );
+        buf.append("=");
+        buf.append(cookie.getValue());
+
+        if (cookie.getComment() != null) {
+            buf.append("; Comment=\"");
+            buf.append(cookie.getComment());
+            buf.append("\"");
+        }
+
+        if (cookie.getDomain() != null) {
+            buf.append("; Domain=\"");
+            buf.append(cookie.getDomain());
+            buf.append("\"");
+        }
+
+        long age = cookie.getMaxAge();
+        if (cookie.getMaxAge() >= 0) {
+            buf.append("; Max-Age=\"");
+            buf.append(cookie.getMaxAge());
+            buf.append("\"");
+        }
+
+        if (cookie.getPath() != null) {
+            buf.append("; Path=\"");
+            buf.append(cookie.getPath());
+            buf.append("\"");
+        }
+
+        if (cookie.getSecure()) {
+            buf.append("; Secure");
+        }
+
+        if (cookie.getVersion() > 0) {
+            buf.append("; Version=\"");
+            buf.append(cookie.getVersion());
+            buf.append("\"");
+        }
+
+        return (buf.toString());
+    }
+
+
+    /**
+     * Filter the specified message string for characters that are sensitive
+     * in HTML.  This avoids potential attacks caused by including JavaScript
+     * codes in the request URL that is often reported in error messages.
+     *
+     * @param message The message string to be filtered
+     */
+    public static String filter(String message) {
+
+        if (message == null)
+            return (null);
+
+        char content[] = new char[message.length()];
+        message.getChars(0, message.length(), content, 0);
+        StringBuffer result = new StringBuffer(content.length + 50);
+        for (int i = 0; i < content.length; i++) {
+            switch (content[i]) {
+            case '<':
+                result.append("&lt;");
+                break;
+            case '>':
+                result.append("&gt;");
+                break;
+            case '&':
+                result.append("&amp;");
+                break;
+            case '"':
+                result.append("&quot;");
+                break;
+            default:
+                result.append(content[i]);
+            }
+        }
+        return (result.toString());
+
+    }
+
+
+    /**
+     * Normalize a relative URI path that may have relative values ("/./",
+     * "/../", and so on ) it it.  <strong>WARNING</strong> - This method is
+     * useful only for normalizing application-generated paths.  It does not
+     * try to perform security checks for malicious input.
+     *
+     * @param path Relative path to be normalized
+     */
+    public static String normalize(String path) {
+
+        if (path == null)
+            return null;
+
+        // Create a place for the normalized path
+        String normalized = path;
+
+        if (normalized.equals("/."))
+            return "/";
+
+        // Add a leading "/" if necessary
+        if (!normalized.startsWith("/"))
+            normalized = "/" + normalized;
+
+        // Resolve occurrences of "//" in the normalized path
+        while (true) {
+            int index = normalized.indexOf("//");
+            if (index < 0)
+                break;
+            normalized = normalized.substring(0, index) +
+                normalized.substring(index + 1);
+        }
+
+        // Resolve occurrences of "/./" in the normalized path
+        while (true) {
+            int index = normalized.indexOf("/./");
+            if (index < 0)
+                break;
+            normalized = normalized.substring(0, index) +
+                normalized.substring(index + 2);
+        }
+
+        // Resolve occurrences of "/../" in the normalized path
+        while (true) {
+            int index = normalized.indexOf("/../");
+            if (index < 0)
+                break;
+            if (index == 0)
+                return (null);  // Trying to go outside our context
+            int index2 = normalized.lastIndexOf('/', index - 1);
+            normalized = normalized.substring(0, index2) +
+                normalized.substring(index + 3);
+        }
+
+        // Return the normalized path that we have completed
+        return (normalized);
+
+    }
+
+
+    /**
+     * Parse the character encoding from the specified content type header.
+     * If the content type is null, or there is no explicit character encoding,
+     * <code>null</code> is returned.
+     *
+     * @param contentType a content type header
+     */
+    public static String parseCharacterEncoding(String contentType) {
+
+        if (contentType == null)
+            return (null);
+        int start = contentType.indexOf("charset=");
+        if (start < 0)
+            return (null);
+        String encoding = contentType.substring(start + 8);
+        int end = encoding.indexOf(';');
+        if (end >= 0)
+            encoding = encoding.substring(0, end);
+        encoding = encoding.trim();
+        if ((encoding.length() > 2) && (encoding.startsWith("\""))
+            && (encoding.endsWith("\"")))
+            encoding = encoding.substring(1, encoding.length() - 1);
+        return (encoding.trim());
+
+    }
+
+
+    /**
+     * Parse a cookie header into an array of cookies according to RFC 2109.
+     *
+     * @param header Value of an HTTP "Cookie" header
+     */
+    public static Cookie[] parseCookieHeader(String header) {
+
+        if ((header == null) || (header.length() < 1))
+            return (new Cookie[0]);
+
+        ArrayList cookies = new ArrayList();
+        while (header.length() > 0) {
+            int semicolon = header.indexOf(';');
+            if (semicolon < 0)
+                semicolon = header.length();
+            if (semicolon == 0)
+                break;
+            String token = header.substring(0, semicolon);
+            if (semicolon < header.length())
+                header = header.substring(semicolon + 1);
+            else
+                header = "";
+            try {
+                int equals = token.indexOf('=');
+                if (equals > 0) {
+                    String name = token.substring(0, equals).trim();
+                    String value = token.substring(equals+1).trim();
+                    cookies.add(new Cookie(name, value));
+                }
+            } catch (Throwable e) {
+                ;
+            }
+        }
+
+        return ((Cookie[]) cookies.toArray(new Cookie[cookies.size()]));
+
+    }
+
+
+    /**
+     * Append request parameters from the specified String to the specified
+     * Map.  It is presumed that the specified Map is not accessed from any
+     * other thread, so no synchronization is performed.
+     * <p>
+     * <strong>IMPLEMENTATION NOTE</strong>:  URL decoding is performed
+     * individually on the parsed name and value elements, rather than on
+     * the entire query string ahead of time, to properly deal with the case
+     * where the name or value includes an encoded "=" or "&" character
+     * that would otherwise be interpreted as a delimiter.
+     *
+     * @param map Map that accumulates the resulting parameters
+     * @param data Input string containing request parameters
+     *
+     * @exception IllegalArgumentException if the data is malformed
+     */
+    public static void parseParameters(Map map, String data, String encoding)
+        throws UnsupportedEncodingException {
+
+        if ((data != null) && (data.length() > 0)) {
+
+            // use the specified encoding to extract bytes out of the
+            // given string so that the encoding is not lost. If an
+            // encoding is not specified, let it use platform default
+            byte[] bytes = null;
+            try {
+                if (encoding == null) {
+                    bytes = data.getBytes();
+                } else {
+                    bytes = data.getBytes(encoding);
+                }
+            } catch (UnsupportedEncodingException uee) {
+            }
+
+            parseParameters(map, bytes, encoding);
+        }
+
+    }
+
+
+    /**
+     * Decode and return the specified URL-encoded String.
+     * When the byte array is converted to a string, the system default
+     * character encoding is used...  This may be different than some other
+     * servers.
+     *
+     * @param str The url-encoded string
+     *
+     * @exception IllegalArgumentException if a '%' character is not followed
+     * by a valid 2-digit hexadecimal number
+     */
+    public static String URLDecode(String str) {
+
+        return URLDecode(str, null);
+
+    }
+
+
+    /**
+     * Decode and return the specified URL-encoded String.
+     *
+     * @param str The url-encoded string
+     * @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
+     */
+    public static String URLDecode(String str, String enc) {
+
+        if (str == null)
+            return (null);
+
+        // use the specified encoding to extract bytes out of the
+        // given string so that the encoding is not lost. If an
+        // encoding is not specified, let it use platform default
+        byte[] bytes = null;
+        try {
+            if (enc == null) {
+                bytes = str.getBytes();
+            } else {
+                bytes = str.getBytes(enc);
+            }
+        } catch (UnsupportedEncodingException uee) {}
+
+        return URLDecode(bytes, enc);
+
+    }
+
+
+    /**
+     * Decode and return the specified URL-encoded byte array.
+     *
+     * @param bytes The url-encoded byte array
+     * @exception IllegalArgumentException if a '%' character is not followed
+     * by a valid 2-digit hexadecimal number
+     */
+    public static String URLDecode(byte[] bytes) {
+        return URLDecode(bytes, null);
+    }
+
+
+    /**
+     * Decode and return the specified URL-encoded byte array.
+     *
+     * @param bytes The url-encoded byte array
+     * @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
+     */
+    public static String URLDecode(byte[] bytes, String enc) {
+
+        if (bytes == null)
+            return (null);
+
+        int len = bytes.length;
+        int ix = 0;
+        int ox = 0;
+        while (ix < len) {
+            byte b = bytes[ix++];     // Get byte to test
+            if (b == '+') {
+                b = (byte)' ';
+            } else if (b == '%') {
+                b = (byte) ((convertHexDigit(bytes[ix++]) << 4)
+                            + convertHexDigit(bytes[ix++]));
+            }
+            bytes[ox++] = b;
+        }
+        if (enc != null) {
+            try {
+                return new String(bytes, 0, ox, enc);
+            } catch (Exception e) {
+                e.printStackTrace();
+            }
+        }
+        return new String(bytes, 0, ox);
+
+    }
+
+
+    /**
+     * Convert a byte character value to hexidecimal digit value.
+     *
+     * @param b the character value byte
+     */
+    private static byte convertHexDigit( byte b ) {
+        if ((b >= '0') && (b <= '9')) return (byte)(b - '0');
+        if ((b >= 'a') && (b <= 'f')) return (byte)(b - 'a' + 10);
+        if ((b >= 'A') && (b <= 'F')) return (byte)(b - 'A' + 10);
+        return 0;
+    }
+
+
+    /**
+     * Put name and value pair in map.  When name already exist, add value
+     * to array of values.
+     *
+     * @param map The map to populate
+     * @param name The parameter name
+     * @param value The parameter value
+     */
+    private static void putMapEntry( Map map, String name, String value) {
+        String[] newValues = null;
+        String[] oldValues = (String[]) map.get(name);
+        if (oldValues == null) {
+            newValues = new String[1];
+            newValues[0] = value;
+        } else {
+            newValues = new String[oldValues.length + 1];
+            System.arraycopy(oldValues, 0, newValues, 0, oldValues.length);
+            newValues[oldValues.length] = value;
+        }
+        map.put(name, newValues);
+    }
+
+
+    /**
+     * Append request parameters from the specified String to the specified
+     * Map.  It is presumed that the specified Map is not accessed from any
+     * other thread, so no synchronization is performed.
+     * <p>
+     * <strong>IMPLEMENTATION NOTE</strong>:  URL decoding is performed
+     * individually on the parsed name and value elements, rather than on
+     * the entire query string ahead of time, to properly deal with the case
+     * where the name or value includes an encoded "=" or "&" character
+     * that would otherwise be interpreted as a delimiter.
+     *
+     * NOTE: byte array data is modified by this method.  Caller beware.
+     *
+     * @param map Map that accumulates the resulting parameters
+     * @param data Input string containing request parameters
+     * @param encoding Encoding to use for converting hex
+     *
+     * @exception UnsupportedEncodingException if the data is malformed
+     */
+    public static void parseParameters(Map map, byte[] data, String encoding)
+        throws UnsupportedEncodingException {
+
+        if (data != null && data.length > 0) {
+            int    pos = 0;
+            int    ix = 0;
+            int    ox = 0;
+            String key = null;
+            String value = null;
+            while (ix < data.length) {
+                byte c = data[ix++];
+                switch ((char) c) {
+                case '&':
+                    value = new String(data, 0, ox, encoding);
+                    if (key != null) {
+                        putMapEntry(map, key, value);
+                        key = null;
+                    }
+                    ox = 0;
+                    break;
+                case '=':
+                    if (key == null) {
+                        key = new String(data, 0, ox, encoding);
+                        ox = 0;
+                    } else {
+                        data[ox++] = c;
+                    }                   
+                    break;  
+                case '+':
+                    data[ox++] = (byte)' ';
+                    break;
+                case '%':
+                    data[ox++] = (byte)((convertHexDigit(data[ix++]) << 4)
+                                    + convertHexDigit(data[ix++]));
+                    break;
+                default:
+                    data[ox++] = c;
+                }
+            }
+            //The last value does not end in '&'.  So save it now.
+            if (key != null) {
+                value = new String(data, 0, ox, encoding);
+                putMapEntry(map, key, value);
+            }
+        }
+
+    }
+
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/ResourceSet.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/ResourceSet.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/ResourceSet.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,184 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.util.Collection;
+import java.util.HashSet;
+
+
+/**
+ * Extended implementation of <strong>HashSet</strong> that includes a
+ * <code>locked</code> property.  This class can be used to safely expose
+ * resource path sets to user classes without having to clone them in order
+ * to avoid modifications.  When first created, a <code>ResourceMap</code>
+ * is not locked.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public final class ResourceSet extends HashSet {
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Construct a new, empty set with the default initial capacity and
+     * load factor.
+     */
+    public ResourceSet() {
+
+        super();
+
+    }
+
+
+    /**
+     * Construct a new, empty set with the specified initial capacity and
+     * default load factor.
+     *
+     * @param initialCapacity The initial capacity of this set
+     */
+    public ResourceSet(int initialCapacity) {
+
+        super(initialCapacity);
+
+    }
+
+
+    /**
+     * Construct a new, empty set with the specified initial capacity and
+     * load factor.
+     *
+     * @param initialCapacity The initial capacity of this set
+     * @param loadFactor The load factor of this set
+     */
+    public ResourceSet(int initialCapacity, float loadFactor) {
+
+        super(initialCapacity, loadFactor);
+
+    }
+
+
+    /**
+     * Construct a new set with the same contents as the existing collection.
+     *
+     * @param coll The collection whose contents we should copy
+     */
+    public ResourceSet(Collection coll) {
+
+        super(coll);
+
+    }
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * The current lock state of this parameter map.
+     */
+    private boolean locked = false;
+
+
+    /**
+     * Return the locked state of this parameter map.
+     */
+    public boolean isLocked() {
+
+        return (this.locked);
+
+    }
+
+
+    /**
+     * Set the locked state of this parameter map.
+     *
+     * @param locked The new locked state
+     */
+    public void setLocked(boolean locked) {
+
+        this.locked = locked;
+
+    }
+
+
+    /**
+     * The string manager for this package.
+     */
+    private static final StringManager sm =
+        StringManager.getManager("org.apache.catalina.util");
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Add the specified element to this set if it is not already present.
+     * Return <code>true</code> if the element was added.
+     *
+     * @param o The object to be added
+     *
+     * @exception IllegalStateException if this ResourceSet is locked
+     */
+    public boolean add(Object o) {
+
+        if (locked)
+            throw new IllegalStateException
+              (sm.getString("resourceSet.locked"));
+        return (super.add(o));
+
+    }
+
+
+    /**
+     * Remove all of the elements from this set.
+     *
+     * @exception IllegalStateException if this ResourceSet is locked
+     */
+    public void clear() {
+
+        if (locked)
+            throw new IllegalStateException
+              (sm.getString("resourceSet.locked"));
+        super.clear();
+
+    }
+
+
+    /**
+     * Remove the given element from this set if it is present.
+     * Return <code>true</code> if the element was removed.
+     *
+     * @param o The object to be removed
+     *
+     * @exception IllegalStateException if this ResourceSet is locked
+     */
+    public boolean remove(Object o) {
+
+        if (locked)
+            throw new IllegalStateException
+              (sm.getString("resourceSet.locked"));
+        return (super.remove(o));
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/SchemaResolver.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/SchemaResolver.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/SchemaResolver.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,133 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.util.HashMap;
+
+import org.apache.tomcat.util.digester.Digester;
+import org.xml.sax.InputSource;
+import org.xml.sax.EntityResolver;
+import org.xml.sax.SAXException;
+
+/**
+ * This class implements a local SAX's <code>EntityResolver</code>. All
+ * DTDs and schemas used to validate the web.xml file will re-directed
+ * to a local file stored in the servlet-api.jar and jsp-api.jar.
+ *
+ * @author Jean-Francois Arcand
+ */
+public class SchemaResolver implements EntityResolver {
+
+    /**
+     * The disgester instance for which this class is the entity resolver.
+     */
+    protected Digester digester;
+
+
+    /**
+     * The URLs of dtds and schemas that have been registered, keyed by the
+     * public identifier that corresponds.
+     */
+    protected HashMap entityValidator = new HashMap();
+
+
+    /**
+     * The public identifier of the DTD we are currently parsing under
+     * (if any).
+     */
+    protected String publicId = null;
+
+
+    /**
+     * Extension to make the difference between DTD and Schema.
+     */
+    protected String schemaExtension = "xsd";
+
+
+    /**
+     * Create a new <code>EntityResolver</code> that will redirect
+     * all remote dtds and schema to a locat destination.
+     * @param digester The digester instance.
+     */
+    public SchemaResolver(Digester digester) {
+        this.digester = digester;
+    }
+
+
+    /**
+     * Register the specified DTD/Schema URL for the specified public
+     * identifier. This must be called before the first call to
+     * <code>parse()</code>.
+     *
+     * When adding a schema file (*.xsd), only the name of the file
+     * will get added. If two schemas with the same name are added,
+     * only the last one will be stored.
+     *
+     * @param publicId Public identifier of the DTD to be resolved
+     * @param entityURL The URL to use for reading this DTD
+     */
+     public void register(String publicId, String entityURL) {
+         String key = publicId;
+         if (publicId.indexOf(schemaExtension) != -1)
+             key = publicId.substring(publicId.lastIndexOf('/')+1);
+         entityValidator.put(key, entityURL);
+     }
+
+
+    /**
+     * Resolve the requested external entity.
+     *
+     * @param publicId The public identifier of the entity being referenced
+     * @param systemId The system identifier of the entity being referenced
+     *
+     * @exception SAXException if a parsing exception occurs
+     *
+     */
+    public InputSource resolveEntity(String publicId, String systemId)
+        throws SAXException {
+
+        if (publicId != null) {
+            this.publicId = publicId;
+            digester.setPublicId(publicId);
+        }
+
+        // Has this system identifier been registered?
+        String entityURL = null;
+        if (publicId != null) {
+            entityURL = (String) entityValidator.get(publicId);
+        }
+
+        // Redirect the schema location to a local destination
+        String key = null;
+        if (entityURL == null && systemId != null) {
+            key = systemId.substring(systemId.lastIndexOf('/')+1);
+            entityURL = (String)entityValidator.get(key);
+        }
+
+        if (entityURL == null) {
+           return (null);
+        }
+
+        try {
+            return (new InputSource(entityURL));
+        } catch (Exception e) {
+            throw new SAXException(e);
+        }
+
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/ServerInfo.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/ServerInfo.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/ServerInfo.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,124 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ *
+ * Licensed 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.io.InputStream;
+import java.util.Properties;
+
+
+/**
+ * Simple utility module to make it easy to plug in the server identifier
+ * when integrating Tomcat.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 303276 $ $Date: 2004-09-24 11:41:12 -0500 (Fri, 24 Sep 2004) $
+ */
+
+public class ServerInfo {
+
+
+    // ------------------------------------------------------- Static Variables
+
+
+    /**
+     * The server information String with which we identify ourselves.
+     */
+    private static String serverInfo = null;
+
+    /**
+     * The server built String.
+     */
+    private static String serverBuilt = null;
+
+    /**
+     * The server's version number String.
+     */
+    private static String serverNumber = null;
+
+    static {
+
+        try {
+            InputStream is = ServerInfo.class.getResourceAsStream
+                ("/org/apache/catalina/util/ServerInfo.properties");
+            Properties props = new Properties();
+            props.load(is);
+            is.close();
+            serverInfo = props.getProperty("server.info");
+            serverBuilt = props.getProperty("server.built");
+            serverNumber = props.getProperty("server.number");
+        } catch (Throwable t) {
+            ;
+        }
+        if (serverInfo == null)
+            serverInfo = "Apache Tomcat";
+        if (serverBuilt == null)
+            serverBuilt = "unknown";
+        if (serverNumber == null)
+            serverNumber = "5.5.0.0";
+        
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Return the server identification for this version of Tomcat.
+     */
+    public static String getServerInfo() {
+
+        return (serverInfo);
+
+    }
+
+    /**
+     * Return the server built time for this version of Tomcat.
+     */
+    public static String getServerBuilt() {
+
+        return (serverBuilt);
+
+    }
+
+    /**
+     * Return the server's version number.
+     */
+    public static String getServerNumber() {
+
+        return (serverNumber);
+
+    }
+
+    public static void main(String args[]) {
+        System.out.println("Server version: " + getServerInfo());
+        System.out.println("Server built:   " + getServerBuilt());
+        System.out.println("Server number:  " + getServerNumber());
+        System.out.println("OS Name:        " +
+                           System.getProperty("os.name"));
+        System.out.println("OS Version:     " +
+                           System.getProperty("os.version"));
+        System.out.println("Architecture:   " +
+                           System.getProperty("os.arch"));
+        System.out.println("JVM Version:    " +
+                           System.getProperty("java.runtime.version"));
+        System.out.println("JVM Vendor:     " +
+                           System.getProperty("java.vm.vendor"));                        
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/ServerInfo.properties
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/ServerInfo.properties	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/ServerInfo.properties	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,3 @@
+server.info=Apache Tomcat/@VERSION@
+server.number=@VERSION_NUMBER@
+server.built=@VERSION_BUILT@

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/Strftime.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/Strftime.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/Strftime.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,262 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.text.SimpleDateFormat;
+import java.util.Properties;
+import java.util.Date;
+import java.util.Locale;
+import java.util.TimeZone;
+
+/**
+ * Converts dates to strings using the same format specifiers as strftime
+ *
+ * Note: This does not mimic strftime perfectly.  Certain strftime commands, 
+ *       are not supported, and will convert as if they were literals.
+ *
+ *       Certain complicated commands, like those dealing with the week of the year
+ *       probably don't have exactly the same behavior as strftime.
+ *
+ *       These limitations are due to use SimpleDateTime.  If the conversion was done
+ *       manually, all these limitations could be eliminated.
+ *
+ *       The interface looks like a subset of DateFormat.  Maybe someday someone will make this class
+ *       extend DateFormat.
+ *
+ * @author Bip Thelin
+ * @author Dan Sandberg
+ * @version $Revision: 303133 $, $Date: 2004-08-29 11:46:15 -0500 (Sun, 29 Aug 2004) $
+ */
+public class Strftime {
+    protected static Properties translate;
+    protected SimpleDateFormat simpleDateFormat;
+
+    /**
+     * Initialize our pattern translation
+     */
+    static {
+        translate = new Properties();
+        translate.put("a","EEE");
+        translate.put("A","EEEE");
+        translate.put("b","MMM");
+        translate.put("B","MMMM");
+        translate.put("c","EEE MMM d HH:mm:ss yyyy");
+
+        //There's no way to specify the century in SimpleDateFormat.  We don't want to hard-code
+        //20 since this could be wrong for the pre-2000 files.
+        //translate.put("C", "20");
+        translate.put("d","dd");
+        translate.put("D","MM/dd/yy");
+        translate.put("e","dd"); //will show as '03' instead of ' 3'
+        translate.put("F","yyyy-MM-dd");
+        translate.put("g","yy");
+        translate.put("G","yyyy");
+        translate.put("H","HH");
+        translate.put("h","MMM");
+        translate.put("I","hh");
+        translate.put("j","DDD");
+        translate.put("k","HH"); //will show as '07' instead of ' 7'
+        translate.put("l","hh"); //will show as '07' instead of ' 7'
+        translate.put("m","MM");
+        translate.put("M","mm");
+        translate.put("n","\n");
+        translate.put("p","a");
+        translate.put("P","a");  //will show as pm instead of PM
+        translate.put("r","hh:mm:ss a");
+        translate.put("R","HH:mm");
+        //There's no way to specify this with SimpleDateFormat
+        //translate.put("s","seconds since ecpoch");
+        translate.put("S","ss");
+        translate.put("t","\t");
+        translate.put("T","HH:mm:ss");
+        //There's no way to specify this with SimpleDateFormat
+        //translate.put("u","day of week ( 1-7 )");
+
+        //There's no way to specify this with SimpleDateFormat
+        //translate.put("U","week in year with first sunday as first day...");
+
+        translate.put("V","ww"); //I'm not sure this is always exactly the same
+
+        //There's no way to specify this with SimpleDateFormat
+        //translate.put("W","week in year with first monday as first day...");
+
+        //There's no way to specify this with SimpleDateFormat
+        //translate.put("w","E");
+        translate.put("X","HH:mm:ss");
+        translate.put("x","MM/dd/yy");
+        translate.put("y","yy");
+        translate.put("Y","yyyy");
+        translate.put("Z","z");
+        translate.put("z","Z");
+        translate.put("%","%");
+    }
+
+
+    /**
+     * Create an instance of this date formatting class
+     *
+     * @see #Strftime( String, Locale )
+     */
+    public Strftime( String origFormat ) {
+        String convertedFormat = convertDateFormat( origFormat );
+        simpleDateFormat = new SimpleDateFormat( convertedFormat );
+    }
+
+    /**
+     * Create an instance of this date formatting class
+     * 
+     * @param origFormat the strftime-style formatting string
+     * @param locale the locale to use for locale-specific conversions
+     */
+    public Strftime( String origFormat, Locale locale ) {
+        String convertedFormat = convertDateFormat( origFormat );
+        simpleDateFormat = new SimpleDateFormat( convertedFormat, locale );
+    }
+
+    /**
+     * Format the date according to the strftime-style string given in the constructor.
+     *
+     * @param date the date to format
+     * @return the formatted date
+     */
+    public String format( Date date ) {
+        return simpleDateFormat.format( date );
+    }
+
+    /**
+     * Get the timezone used for formatting conversions
+     *
+     * @return the timezone
+     */
+    public TimeZone getTimeZone() {
+        return simpleDateFormat.getTimeZone();
+    }
+
+    /**
+     * Change the timezone used to format dates
+     *
+     * @see SimpleDateFormat#setTimeZone
+     */
+    public void setTimeZone( TimeZone timeZone ) {
+        simpleDateFormat.setTimeZone( timeZone );
+    }
+
+    /**
+     * Search the provided pattern and get the C standard
+     * Date/Time formatting rules and convert them to the
+     * Java equivalent.
+     *
+     * @param pattern The pattern to search
+     * @return The modified pattern
+     */
+    protected String convertDateFormat( String pattern ) {
+        boolean inside = false;
+        boolean mark = false;
+        boolean modifiedCommand = false;
+
+        StringBuffer buf = new StringBuffer();
+
+        for(int i = 0; i < pattern.length(); i++) {
+            char c = pattern.charAt(i);
+
+            if ( c=='%' && !mark ) {
+                mark=true;
+            } else {
+                if ( mark ) {
+                    if ( modifiedCommand ) {
+                        //don't do anything--we just wanted to skip a char
+                        modifiedCommand = false;
+                        mark = false;
+                    } else {
+                        inside = translateCommand( buf, pattern, i, inside );
+                        //It's a modifier code
+                        if ( c=='O' || c=='E' ) {
+                            modifiedCommand = true;
+                        } else {
+                            mark=false;
+                        }
+                    }
+                } else {
+                    if ( !inside && c != ' ' ) {
+                        //We start a literal, which we need to quote
+                        buf.append("'");
+                        inside = true;
+                    }
+                    
+                    buf.append(c);
+                }
+            }
+        }
+
+        if ( buf.length() > 0 ) {
+            char lastChar = buf.charAt( buf.length() - 1 );
+
+            if( lastChar!='\'' && inside ) {
+                buf.append('\'');
+            }
+        }
+        return buf.toString();
+    }
+
+    protected String quote( String str, boolean insideQuotes ) {
+        String retVal = str;
+        if ( !insideQuotes ) {
+            retVal = '\'' + retVal + '\'';
+        }
+        return retVal;
+    }
+
+    /**
+     * Try to get the Java Date/Time formatting associated with
+     * the C standard provided.
+     *
+     * @param buf The buffer
+     * @param pattern The date/time pattern
+     * @param index The char index
+     * @param oldInside Flag value
+     * @return True if new is inside buffer
+     */
+    protected boolean translateCommand( StringBuffer buf, String pattern, int index, boolean oldInside ) {
+        char firstChar = pattern.charAt( index );
+        boolean newInside = oldInside;
+
+        //O and E are modifiers, they mean to present an alternative representation of the next char
+        //we just handle the next char as if the O or E wasn't there
+        if ( firstChar == 'O' || firstChar == 'E' ) {
+            if ( index + 1 < pattern.length() ) {               
+                newInside = translateCommand( buf, pattern, index + 1, oldInside );
+            } else {
+                buf.append( quote("%" + firstChar, oldInside ) );
+            }
+        } else {
+            String command = translate.getProperty( String.valueOf( firstChar ) );
+            
+            //If we don't find a format, treat it as a literal--That's what apache does
+            if ( command == null ) {
+                buf.append( quote( "%" + firstChar, oldInside ) );
+            } else {
+                //If we were inside quotes, close the quotes
+                if ( oldInside ) {
+                    buf.append( '\'' );
+                }
+                buf.append( command );
+                newInside = false;
+            }
+        }
+        return newInside;
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/StringManager.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/StringManager.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/StringManager.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,252 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.text.MessageFormat;
+import java.util.Hashtable;
+import java.util.Locale;
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+import java.net.URLClassLoader;
+
+/**
+ * An internationalization / localization helper class which reduces
+ * the bother of handling ResourceBundles and takes care of the
+ * common cases of message formating which otherwise require the
+ * creation of Object arrays and such.
+ *
+ * <p>The StringManager operates on a package basis. One StringManager
+ * per package can be created and accessed via the getManager method
+ * call.
+ *
+ * <p>The StringManager will look for a ResourceBundle named by
+ * the package name given plus the suffix of "LocalStrings". In
+ * practice, this means that the localized information will be contained
+ * in a LocalStrings.properties file located in the package
+ * directory of the classpath.
+ *
+ * <p>Please see the documentation for java.util.ResourceBundle for
+ * more information.
+ *
+ * @author James Duncan Davidson [duncan at eng.sun.com]
+ * @author James Todd [gonzo at eng.sun.com]
+ */
+
+public class StringManager {
+
+    /**
+     * The ResourceBundle for this StringManager.
+     */
+
+    private ResourceBundle bundle;
+    
+    private static org.apache.commons.logging.Log log=
+        org.apache.commons.logging.LogFactory.getLog( StringManager.class );
+    
+    /**
+     * Creates a new StringManager for a given package. This is a
+     * private method and all access to it is arbitrated by the
+     * static getManager method call so that only one StringManager
+     * per package will be created.
+     *
+     * @param packageName Name of package to create StringManager for.
+     */
+
+    private StringManager(String packageName) {
+        String bundleName = packageName + ".LocalStrings";
+        try {
+            bundle = ResourceBundle.getBundle(bundleName);
+            return;
+        } catch( MissingResourceException ex ) {
+            // Try from the current loader ( that's the case for trusted apps )
+            ClassLoader cl=Thread.currentThread().getContextClassLoader();
+            if( cl != null ) {
+                try {
+                    bundle=ResourceBundle.getBundle(bundleName, Locale.getDefault(), cl);
+                    return;
+                } catch(MissingResourceException ex2) {
+                }
+            }
+            if( cl==null )
+                cl=this.getClass().getClassLoader();
+
+            if (log.isDebugEnabled())
+                log.debug("Can't find resource " + bundleName +
+                    " " + cl);
+            if( cl instanceof URLClassLoader ) {
+                if (log.isDebugEnabled()) 
+                    log.debug( ((URLClassLoader)cl).getURLs());
+            }
+        }
+    }
+
+    /**
+     * Get a string from the underlying resource bundle.
+     *
+     * @param key The resource name
+     */
+    public String getString(String key) {
+        return MessageFormat.format(getStringInternal(key), (Object [])null);
+    }
+
+
+    protected String getStringInternal(String key) {
+        if (key == null) {
+            String msg = "key is null";
+
+            throw new NullPointerException(msg);
+        }
+
+        String str = null;
+
+        if( bundle==null )
+            return key;
+        try {
+            str = bundle.getString(key);
+        } catch (MissingResourceException mre) {
+            str = "Cannot find message associated with key '" + key + "'";
+        }
+
+        return str;
+    }
+
+    /**
+     * Get a string from the underlying resource bundle and format
+     * it with the given set of arguments.
+     *
+     * @param key The resource name
+     * @param args Formatting directives
+     */
+
+    public String getString(String key, Object[] args) {
+        String iString = null;
+        String value = getStringInternal(key);
+
+        // this check for the runtime exception is some pre 1.1.6
+        // VM's don't do an automatic toString() on the passed in
+        // objects and barf out
+
+        try {
+            // ensure the arguments are not null so pre 1.2 VM's don't barf
+            Object nonNullArgs[] = args;
+            for (int i=0; i<args.length; i++) {
+                if (args[i] == null) {
+                    if (nonNullArgs==args) nonNullArgs=(Object[])args.clone();
+                    nonNullArgs[i] = "null";
+                }
+            }
+
+            iString = MessageFormat.format(value, nonNullArgs);
+        } catch (IllegalArgumentException iae) {
+            StringBuffer buf = new StringBuffer();
+            buf.append(value);
+            for (int i = 0; i < args.length; i++) {
+                buf.append(" arg[" + i + "]=" + args[i]);
+            }
+            iString = buf.toString();
+        }
+        return iString;
+    }
+
+    /**
+     * Get a string from the underlying resource bundle and format it
+     * with the given object argument. This argument can of course be
+     * a String object.
+     *
+     * @param key The resource name
+     * @param arg Formatting directive
+     */
+
+    public String getString(String key, Object arg) {
+        Object[] args = new Object[] {arg};
+        return getString(key, args);
+    }
+
+    /**
+     * Get a string from the underlying resource bundle and format it
+     * with the given object arguments. These arguments can of course
+     * be String objects.
+     *
+     * @param key The resource name
+     * @param arg1 Formatting directive
+     * @param arg2 Formatting directive
+     */
+
+    public String getString(String key, Object arg1, Object arg2) {
+        Object[] args = new Object[] {arg1, arg2};
+        return getString(key, args);
+    }
+
+    /**
+     * Get a string from the underlying resource bundle and format it
+     * with the given object arguments. These arguments can of course
+     * be String objects.
+     *
+     * @param key The resource name
+     * @param arg1 Formatting directive
+     * @param arg2 Formatting directive
+     * @param arg3 Formatting directive
+     */
+
+    public String getString(String key, Object arg1, Object arg2,
+                            Object arg3) {
+        Object[] args = new Object[] {arg1, arg2, arg3};
+        return getString(key, args);
+    }
+
+    /**
+     * Get a string from the underlying resource bundle and format it
+     * with the given object arguments. These arguments can of course
+     * be String objects.
+     *
+     * @param key The resource name
+     * @param arg1 Formatting directive
+     * @param arg2 Formatting directive
+     * @param arg3 Formatting directive
+     * @param arg4 Formatting directive
+     */
+
+    public String getString(String key, Object arg1, Object arg2,
+                            Object arg3, Object arg4) {
+        Object[] args = new Object[] {arg1, arg2, arg3, arg4};
+        return getString(key, args);
+    }
+    // --------------------------------------------------------------
+    // STATIC SUPPORT METHODS
+    // --------------------------------------------------------------
+
+    private static Hashtable managers = new Hashtable();
+
+    /**
+     * Get the StringManager for a particular package. If a manager for
+     * a package already exists, it will be reused, else a new
+     * StringManager will be created and returned.
+     *
+     * @param packageName The package name
+     */
+
+    public synchronized static StringManager getManager(String packageName) {
+        StringManager mgr = (StringManager)managers.get(packageName);
+
+        if (mgr == null) {
+            mgr = new StringManager(packageName);
+            managers.put(packageName, mgr);
+        }
+        return mgr;
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/StringParser.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/StringParser.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/StringParser.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,323 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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;
+
+
+/**
+ * Utility class for string parsing that is higher performance than
+ * StringParser for simple delimited text cases.  Parsing is performed
+ * by setting the string, and then using the <code>findXxxx()</code> and
+ * <code>skipXxxx()</code> families of methods to remember significant
+ * offsets.  To retrieve the parsed substrings, call the <code>extract()</code>
+ * method with the appropriate saved offset values.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public final class StringParser {
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Construct a string parser with no preset string to be parsed.
+     */
+    public StringParser() {
+
+        this(null);
+
+    }
+
+
+    /**
+     * Construct a string parser that is initialized to parse the specified
+     * string.
+     *
+     * @param string The string to be parsed
+     */
+    public StringParser(String string) {
+
+        super();
+        setString(string);
+
+    }
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The characters of the current string, as a character array.  Stored
+     * when the string is first specified to speed up access to characters
+     * being compared during parsing.
+     */
+    private char chars[] = null;
+
+
+    /**
+     * The zero-relative index of the current point at which we are
+     * positioned within the string being parsed.  <strong>NOTE</strong>:
+     * the value of this index can be one larger than the index of the last
+     * character of the string (i.e. equal to the string length) if you
+     * parse off the end of the string.  This value is useful for extracting
+     * substrings that include the end of the string.
+     */
+    private int index = 0;
+
+
+    /**
+     * The length of the String we are currently parsing.  Stored when the
+     * string is first specified to avoid repeated recalculations.
+     */
+    private int length = 0;
+
+
+    /**
+     * The String we are currently parsing.
+     */
+    private String string = null;
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * Return the zero-relative index of our current parsing position
+     * within the string being parsed.
+     */
+    public int getIndex() {
+
+        return (this.index);
+
+    }
+
+
+    /**
+     * Return the length of the string we are parsing.
+     */
+    public int getLength() {
+
+        return (this.length);
+
+    }
+
+
+    /**
+     * Return the String we are currently parsing.
+     */
+    public String getString() {
+
+        return (this.string);
+
+    }
+
+
+    /**
+     * Set the String we are currently parsing.  The parser state is also reset
+     * to begin at the start of this string.
+     *
+     * @param string The string to be parsed.
+     */
+    public void setString(String string) {
+
+        this.string = string;
+        if (string != null) {
+            this.length = string.length();
+            chars = this.string.toCharArray();
+        } else {
+            this.length = 0;
+            chars = new char[0];
+        }
+        reset();
+
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Advance the current parsing position by one, if we are not already
+     * past the end of the string.
+     */
+    public void advance() {
+
+        if (index < length)
+            index++;
+
+    }
+
+
+    /**
+     * Extract and return a substring that starts at the specified position,
+     * and extends to the end of the string being parsed.  If this is not
+     * possible, a zero-length string is returned.
+     *
+     * @param start Starting index, zero relative, inclusive
+     */
+    public String extract(int start) {
+
+        if ((start < 0) || (start >= length))
+            return ("");
+        else
+            return (string.substring(start));
+
+    }
+
+
+    /**
+     * Extract and return a substring that starts at the specified position,
+     * and ends at the character before the specified position.  If this is
+     * not possible, a zero-length string is returned.
+     *
+     * @param start Starting index, zero relative, inclusive
+     * @param end Ending index, zero relative, exclusive
+     */
+    public String extract(int start, int end) {
+
+        if ((start < 0) || (start >= end) || (end > length))
+            return ("");
+        else
+            return (string.substring(start, end));
+
+    }
+
+
+    /**
+     * Return the index of the next occurrence of the specified character,
+     * or the index of the character after the last position of the string
+     * if no more occurrences of this character are found.  The current
+     * parsing position is updated to the returned value.
+     *
+     * @param ch Character to be found
+     */
+    public int findChar(char ch) {
+
+        while ((index < length) && (ch != chars[index]))
+            index++;
+        return (index);
+
+    }
+
+
+    /**
+     * Return the index of the next occurrence of a non-whitespace character,
+     * or the index of the character after the last position of the string
+     * if no more non-whitespace characters are found.  The current
+     * parsing position is updated to the returned value.
+     */
+    public int findText() {
+
+        while ((index < length) && isWhite(chars[index]))
+            index++;
+        return (index);
+
+    }
+
+
+    /**
+     * Return the index of the next occurrence of a whitespace character,
+     * or the index of the character after the last position of the string
+     * if no more whitespace characters are found.  The current parsing
+     * position is updated to the returned value.
+     */
+    public int findWhite() {
+
+        while ((index < length) && !isWhite(chars[index]))
+            index++;
+        return (index);
+
+    }
+
+
+    /**
+     * Reset the current state of the parser to the beginning of the
+     * current string being parsed.
+     */
+    public void reset() {
+
+        index = 0;
+
+    }
+
+
+    /**
+     * Advance the current parsing position while it is pointing at the
+     * specified character, or until it moves past the end of the string.
+     * Return the final value.
+     *
+     * @param ch Character to be skipped
+     */
+    public int skipChar(char ch) {
+
+        while ((index < length) && (ch == chars[index]))
+            index++;
+        return (index);
+
+    }
+
+
+    /**
+     * Advance the current parsing position while it is pointing at a
+     * non-whitespace character, or until it moves past the end of the string.
+     * Return the final value.
+     */
+    public int skipText() {
+
+        while ((index < length) && !isWhite(chars[index]))
+            index++;
+        return (index);
+
+    }
+
+
+    /**
+     * Advance the current parsing position while it is pointing at a
+     * whitespace character, or until it moves past the end of the string.
+     * Return the final value.
+     */
+    public int skipWhite() {
+
+        while ((index < length) && isWhite(chars[index]))
+            index++;
+        return (index);
+
+    }
+
+
+    // ------------------------------------------------------ Protected Methods
+
+
+    /**
+     * Is the specified character considered to be whitespace?
+     *
+     * @param ch Character to be checked
+     */
+    protected boolean isWhite(char ch) {
+
+        if ((ch == ' ') || (ch == '\t') || (ch == '\r') || (ch == '\n'))
+            return (true);
+        else
+            return (false);
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/TomcatCSS.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/TomcatCSS.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/TomcatCSS.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,36 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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;
+
+
+public class TomcatCSS {
+
+    public static final String TOMCAT_CSS =
+        "H1 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:22px;} " +
+        "H2 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:16px;} " +
+        "H3 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:14px;} " +
+        "BODY {font-family:Tahoma,Arial,sans-serif;color:black;background-color:white;} " +
+        "B {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;} " +
+        "P {font-family:Tahoma,Arial,sans-serif;background:white;color:black;font-size:12px;}" +
+        "A {color : black;}" +
+        "A.name {color : black;}" +
+        "HR {color : #525D76;}";
+
+
+}
+

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/URL.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/URL.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/URL.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,707 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.io.Serializable;
+import java.net.MalformedURLException;
+
+
+/**
+ * <p><strong>URL</strong> is designed to provide public APIs for parsing
+ * and synthesizing Uniform Resource Locators as similar as possible to the
+ * APIs of <code>java.net.URL</code>, but without the ability to open a
+ * stream or connection.  One of the consequences of this is that you can
+ * construct URLs for protocols for which a URLStreamHandler is not
+ * available (such as an "https" URL when JSSE is not installed).</p>
+ *
+ * <p><strong>WARNING</strong> - This class assumes that the string
+ * representation of a URL conforms to the <code>spec</code> argument
+ * as described in RFC 2396 "Uniform Resource Identifiers: Generic Syntax":
+ * <pre>
+ *   &lt;scheme&gt;//&lt;authority&gt;&lt;path&gt;?&lt;query&gt;#&lt;fragment&gt;
+ * </pre></p>
+ *
+ * <p><strong>FIXME</strong> - This class really ought to end up in a Commons
+ * package someplace.</p>
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public final class URL implements Serializable {
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Create a URL object from the specified String representation.
+     *
+     * @param spec String representation of the URL
+     *
+     * @exception MalformedURLException if the string representation
+     *  cannot be parsed successfully
+     */
+    public URL(String spec) throws MalformedURLException {
+
+        this(null, spec);
+
+    }
+
+
+    /**
+     * Create a URL object by parsing a string representation relative
+     * to a specified context.  Based on logic from JDK 1.3.1's
+     * <code>java.net.URL</code>.
+     *
+     * @param context URL against which the relative representation
+     *  is resolved
+     * @param spec String representation of the URL (usually relative)
+     *
+     * @exception MalformedURLException if the string representation
+     *  cannot be parsed successfully
+     */
+    public URL(URL context, String spec) throws MalformedURLException {
+
+        String original = spec;
+        int i, limit, c;
+        int start = 0;
+        String newProtocol = null;
+        boolean aRef = false;
+
+        try {
+
+            // Eliminate leading and trailing whitespace
+            limit = spec.length();
+            while ((limit > 0) && (spec.charAt(limit - 1) <= ' ')) {
+                limit--;
+            }
+            while ((start < limit) && (spec.charAt(start) <= ' ')) {
+                start++;
+            }
+
+            // If the string representation starts with "url:", skip it
+            if (spec.regionMatches(true, start, "url:", 0, 4)) {
+                start += 4;
+            }
+
+            // Is this a ref relative to the context URL?
+            if ((start < spec.length()) && (spec.charAt(start) == '#')) {
+                aRef = true;
+            }
+
+            // Parse out the new protocol
+            for (i = start; !aRef && (i < limit) &&
+                     ((c = spec.charAt(i)) != '/'); i++) {
+                if (c == ':') {
+                    String s = spec.substring(start, i).toLowerCase();
+                    // Assume all protocols are valid
+                    newProtocol = s;
+                    start = i + 1;
+                    break;
+                }
+            }
+
+            // Only use our context if the protocols match
+            protocol = newProtocol;
+            if ((context != null) && ((newProtocol == null) ||
+                 newProtocol.equalsIgnoreCase(context.getProtocol()))) {
+                // If the context is a hierarchical URL scheme and the spec
+                // contains a matching scheme then maintain backwards
+                // compatibility and treat it as if the spec didn't contain
+                // the scheme; see 5.2.3 of RFC2396
+                if ((context.getPath() != null) &&
+                    (context.getPath().startsWith("/")))
+                    newProtocol = null;
+                if (newProtocol == null) {
+                    protocol = context.getProtocol();
+                    authority = context.getAuthority();
+                    userInfo = context.getUserInfo();
+                    host = context.getHost();
+                    port = context.getPort();
+                    file = context.getFile();
+                    int question = file.lastIndexOf("?");
+                    if (question < 0)
+                        path = file;
+                    else
+                        path = file.substring(0, question);
+                }
+            }
+
+            if (protocol == null)
+                throw new MalformedURLException("no protocol: " + original);
+
+            // Parse out any ref portion of the spec
+            i = spec.indexOf('#', start);
+            if (i >= 0) {
+                ref = spec.substring(i + 1, limit);
+                limit = i;
+            }
+
+            // Parse the remainder of the spec in a protocol-specific fashion
+            parse(spec, start, limit);
+            if (context != null)
+                normalize();
+
+
+        } catch (MalformedURLException e) {
+            throw e;
+        } catch (Exception e) {
+            throw new MalformedURLException(e.toString());
+        }
+
+    }
+
+
+
+
+
+    /**
+     * Create a URL object from the specified components.  The default port
+     * number for the specified protocol will be used.
+     *
+     * @param protocol Name of the protocol to use
+     * @param host Name of the host addressed by this protocol
+     * @param file Filename on the specified host
+     *
+     * @exception MalformedURLException is never thrown, but present for
+     *  compatible APIs
+     */
+    public URL(String protocol, String host, String file)
+        throws MalformedURLException {
+
+        this(protocol, host, -1, file);
+
+    }
+
+
+    /**
+     * Create a URL object from the specified components.  Specifying a port
+     * number of -1 indicates that the URL should use the default port for
+     * that protocol.  Based on logic from JDK 1.3.1's
+     * <code>java.net.URL</code>.
+     *
+     * @param protocol Name of the protocol to use
+     * @param host Name of the host addressed by this protocol
+     * @param port Port number, or -1 for the default port for this protocol
+     * @param file Filename on the specified host
+     *
+     * @exception MalformedURLException is never thrown, but present for
+     *  compatible APIs
+     */
+    public URL(String protocol, String host, int port, String file)
+        throws MalformedURLException {
+
+        this.protocol = protocol;
+        this.host = host;
+        this.port = port;
+
+        int hash = file.indexOf('#');
+        this.file = hash < 0 ? file : file.substring(0, hash);
+        this.ref = hash < 0 ? null : file.substring(hash + 1);
+        int question = file.lastIndexOf('?');
+        if (question >= 0) {
+            query = file.substring(question + 1);
+            path = file.substring(0, question);
+        } else
+            path = file;
+
+        if ((host != null) && (host.length() > 0))
+            authority = (port == -1) ? host : host + ":" + port;
+
+    }
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The authority part of the URL.
+     */
+    private String authority = null;
+
+
+    /**
+     * The filename part of the URL.
+     */
+    private String file = null;
+
+
+    /**
+     * The host name part of the URL.
+     */
+    private String host = null;
+
+
+    /**
+     * The path part of the URL.
+     */
+    private String path = null;
+
+
+    /**
+     * The port number part of the URL.
+     */
+    private int port = -1;
+
+
+    /**
+     * The protocol name part of the URL.
+     */
+    private String protocol = null;
+
+
+    /**
+     * The query part of the URL.
+     */
+    private String query = null;
+
+
+    /**
+     * The reference part of the URL.
+     */
+    private String ref = null;
+
+
+    /**
+     * The user info part of the URL.
+     */
+    private String userInfo = null;
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Compare two URLs for equality.  The result is <code>true</code> if and
+     * only if the argument is not null, and is a <code>URL</code> object
+     * that represents the same <code>URL</code> as this object.  Two
+     * <code>URLs</code> are equal if they have the same protocol and
+     * reference the same host, the same port number on the host,
+     * and the same file and anchor on the host.
+     *
+     * @param obj The URL to compare against
+     */
+    public boolean equals(Object obj) {
+
+        if (obj == null)
+            return (false);
+        if (!(obj instanceof URL))
+            return (false);
+        URL other = (URL) obj;
+        if (!sameFile(other))
+            return (false);
+        return (compare(ref, other.getRef()));
+
+    }
+
+
+    /**
+     * Return the authority part of the URL.
+     */
+    public String getAuthority() {
+
+        return (this.authority);
+
+    }
+
+
+    /**
+     * Return the filename part of the URL.  <strong>NOTE</strong> - For
+     * compatibility with <code>java.net.URL</code>, this value includes
+     * the query string if there was one.  For just the path portion,
+     * call <code>getPath()</code> instead.
+     */
+    public String getFile() {
+
+        if (file == null)
+            return ("");
+        return (this.file);
+
+    }
+
+
+    /**
+     * Return the host name part of the URL.
+     */
+    public String getHost() {
+
+        return (this.host);
+
+    }
+
+
+    /**
+     * Return the path part of the URL.
+     */
+    public String getPath() {
+
+        if (this.path == null)
+            return ("");
+        return (this.path);
+
+    }
+
+
+    /**
+     * Return the port number part of the URL.
+     */
+    public int getPort() {
+
+        return (this.port);
+
+    }
+
+
+    /**
+     * Return the protocol name part of the URL.
+     */
+    public String getProtocol() {
+
+        return (this.protocol);
+
+    }
+
+
+    /**
+     * Return the query part of the URL.
+     */
+    public String getQuery() {
+
+        return (this.query);
+
+    }
+
+
+    /**
+     * Return the reference part of the URL.
+     */
+    public String getRef() {
+
+        return (this.ref);
+
+    }
+
+
+    /**
+     * Return the user info part of the URL.
+     */
+    public String getUserInfo() {
+
+        return (this.userInfo);
+
+    }
+
+
+    /**
+     * Normalize the <code>path</code> (and therefore <code>file</code>)
+     * portions of this URL.
+     * <p>
+     * <strong>NOTE</strong> - This method is not part of the public API
+     * of <code>java.net.URL</code>, but is provided as a value added
+     * service of this implementation.
+     *
+     * @exception MalformedURLException if a normalization error occurs,
+     *  such as trying to move about the hierarchical root
+     */
+    public void normalize() throws MalformedURLException {
+
+        // Special case for null path
+        if (path == null) {
+            if (query != null)
+                file = "?" + query;
+            else
+                file = "";
+            return;
+        }
+
+        // Create a place for the normalized path
+        String normalized = path;
+        if (normalized.equals("/.")) {
+            path = "/";
+            if (query != null)
+                file = path + "?" + query;
+            else
+                file = path;
+            return;
+        }
+
+        // Normalize the slashes and add leading slash if necessary
+        if (normalized.indexOf('\\') >= 0)
+            normalized = normalized.replace('\\', '/');
+        if (!normalized.startsWith("/"))
+            normalized = "/" + normalized;
+
+        // Resolve occurrences of "//" in the normalized path
+        while (true) {
+            int index = normalized.indexOf("//");
+            if (index < 0)
+                break;
+            normalized = normalized.substring(0, index) +
+                normalized.substring(index + 1);
+        }
+
+        // Resolve occurrences of "/./" in the normalized path
+        while (true) {
+            int index = normalized.indexOf("/./");
+            if (index < 0)
+                break;
+            normalized = normalized.substring(0, index) +
+                normalized.substring(index + 2);
+        }
+
+        // Resolve occurrences of "/../" in the normalized path
+        while (true) {
+            int index = normalized.indexOf("/../");
+            if (index < 0)
+                break;
+            if (index == 0)
+                throw new MalformedURLException
+                    ("Invalid relative URL reference");
+            int index2 = normalized.lastIndexOf('/', index - 1);
+            normalized = normalized.substring(0, index2) +
+                normalized.substring(index + 3);
+        }
+
+        // Resolve occurrences of "/." at the end of the normalized path
+        if (normalized.endsWith("/."))
+            normalized = normalized.substring(0, normalized.length() - 1);
+
+        // Resolve occurrences of "/.." at the end of the normalized path
+        if (normalized.endsWith("/..")) {
+            int index = normalized.length() - 3;
+            int index2 = normalized.lastIndexOf('/', index - 1);
+            if (index2 < 0)
+                throw new MalformedURLException
+                    ("Invalid relative URL reference");
+            normalized = normalized.substring(0, index2 + 1);
+        }
+
+        // Return the normalized path that we have completed
+        path = normalized;
+        if (query != null)
+            file = path + "?" + query;
+        else
+            file = path;
+
+    }
+
+
+    /**
+     * Compare two URLs, excluding the "ref" fields.  Returns <code>true</code>
+     * if this <code>URL</code> and the <code>other</code> argument both refer
+     * to the same resource.  The two <code>URLs</code> might not both contain
+     * the same anchor.
+     */
+    public boolean sameFile(URL other) {
+
+        if (!compare(protocol, other.getProtocol()))
+            return (false);
+        if (!compare(host, other.getHost()))
+            return (false);
+        if (port != other.getPort())
+            return (false);
+        if (!compare(file, other.getFile()))
+            return (false);
+        return (true);
+
+    }
+
+
+    /**
+     * Return a string representation of this URL.  This follow the rules in
+     * RFC 2396, Section 5.2, Step 7.
+     */
+    public String toExternalForm() {
+
+        StringBuffer sb = new StringBuffer();
+        if (protocol != null) {
+            sb.append(protocol);
+            sb.append(":");
+        }
+        if (authority != null) {
+            sb.append("//");
+            sb.append(authority);
+        }
+        if (path != null)
+            sb.append(path);
+        if (query != null) {
+            sb.append('?');
+            sb.append(query);
+        }
+        if (ref != null) {
+            sb.append('#');
+            sb.append(ref);
+        }
+        return (sb.toString());
+
+    }
+
+
+    /**
+     * Return a string representation of this object.
+     */
+    public String toString() {
+
+        StringBuffer sb = new StringBuffer("URL[");
+        sb.append("authority=");
+        sb.append(authority);
+        sb.append(", file=");
+        sb.append(file);
+        sb.append(", host=");
+        sb.append(host);
+        sb.append(", port=");
+        sb.append(port);
+        sb.append(", protocol=");
+        sb.append(protocol);
+        sb.append(", query=");
+        sb.append(query);
+        sb.append(", ref=");
+        sb.append(ref);
+        sb.append(", userInfo=");
+        sb.append(userInfo);
+        sb.append("]");
+        return (sb.toString());
+
+        //        return (toExternalForm());
+
+    }
+
+
+    // -------------------------------------------------------- Private Methods
+
+
+    /**
+     * Compare to String values for equality, taking appropriate care if one
+     * or both of the values are <code>null</code>.
+     *
+     * @param first First string
+     * @param second Second string
+     */
+    private boolean compare(String first, String second) {
+
+        if (first == null) {
+            if (second == null)
+                return (true);
+            else
+                return (false);
+        } else {
+            if (second == null)
+                return (false);
+            else
+                return (first.equals(second));
+        }
+
+    }
+
+
+    /**
+     * Parse the specified portion of the string representation of a URL,
+     * assuming that it has a format similar to that for <code>http</code>.
+     *
+     * <p><strong>FIXME</strong> - This algorithm can undoubtedly be optimized
+     * for performance.  However, that needs to wait until after sufficient
+     * unit tests are implemented to guarantee correct behavior with no
+     * regressions.</p>
+     *
+     * @param spec String representation being parsed
+     * @param start Starting offset, which will be just after the ':' (if
+     *  there is one) that determined the protocol name
+     * @param limit Ending position, which will be the position of the '#'
+     *  (if there is one) that delimited the anchor
+     *
+     * @exception MalformedURLException if a parsing error occurs
+     */
+    private void parse(String spec, int start, int limit)
+        throws MalformedURLException {
+
+        // Trim the query string (if any) off the tail end
+        int question = spec.lastIndexOf('?', limit - 1);
+        if ((question >= 0) && (question < limit)) {
+            query = spec.substring(question + 1, limit);
+            limit = question;
+        } else {
+            query = null;
+        }
+
+        // Parse the authority section
+        if (spec.indexOf("//", start) == start) {
+            int pathStart = spec.indexOf("/", start + 2);
+            if ((pathStart >= 0) && (pathStart < limit)) {
+                authority = spec.substring(start + 2, pathStart);
+                start = pathStart;
+            } else {
+                authority = spec.substring(start + 2, limit);
+                start = limit;
+            }
+            if (authority.length() > 0) {
+                int at = authority.indexOf('@');
+                if( at >= 0 ) {
+                    userInfo = authority.substring(0,at);
+                }
+                int colon = authority.indexOf(':',at+1);
+                if (colon >= 0) {
+                    try {
+                        port =
+                            Integer.parseInt(authority.substring(colon + 1));
+                    } catch (NumberFormatException e) {
+                        throw new MalformedURLException(e.toString());
+                    }
+                    host = authority.substring(at+1, colon);
+                } else {
+                    host = authority.substring(at+1);
+                    port = -1;
+                }
+            }
+        }
+
+        // Parse the path section
+        if (spec.indexOf("/", start) == start) {     // Absolute path
+            path = spec.substring(start, limit);
+            if (query != null)
+                file = path + "?" + query;
+            else
+                file = path;
+            return;
+        }
+
+        // Resolve relative path against our context's file
+        if (path == null) {
+            if (query != null)
+                file = "?" + query;
+            else
+                file = null;
+            return;
+        }
+        if (!path.startsWith("/"))
+            throw new MalformedURLException
+                ("Base path does not start with '/'");
+        if (!path.endsWith("/"))
+            path += "/../";
+        path += spec.substring(start, limit);
+        if (query != null)
+            file = path + "?" + query;
+        else
+            file = path;
+        return;
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/URLEncoder.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/URLEncoder.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/URLEncoder.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,100 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.util.BitSet;
+
+/**
+ *
+ * This class is very similar to the java.net.URLEncoder class.
+ *
+ * Unfortunately, with java.net.URLEncoder there is no way to specify to the 
+ * java.net.URLEncoder which characters should NOT be encoded.
+ *
+ * This code was moved from DefaultServlet.java
+ *
+ * @author Craig R. McClanahan
+ * @author Remy Maucherat
+ */
+public class URLEncoder {
+    protected static final char[] hexadecimal =
+    {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
+     'A', 'B', 'C', 'D', 'E', 'F'};
+
+    //Array containing the safe characters set.
+    protected BitSet safeCharacters = new BitSet(256);
+
+    public URLEncoder() {
+        for (char i = 'a'; i <= 'z'; i++) {
+            addSafeCharacter(i);
+        }
+        for (char i = 'A'; i <= 'Z'; i++) {
+            addSafeCharacter(i);
+        }
+        for (char i = '0'; i <= '9'; i++) {
+            addSafeCharacter(i);
+        }
+    }
+
+    public void addSafeCharacter( char c ) {
+	safeCharacters.set( c );
+    }
+
+    public String encode( String path ) {
+        int maxBytesPerChar = 10;
+        int caseDiff = ('a' - 'A');
+        StringBuffer rewrittenPath = new StringBuffer(path.length());
+        ByteArrayOutputStream buf = new ByteArrayOutputStream(maxBytesPerChar);
+        OutputStreamWriter writer = null;
+        try {
+            writer = new OutputStreamWriter(buf, "UTF8");
+        } catch (Exception e) {
+            e.printStackTrace();
+            writer = new OutputStreamWriter(buf);
+        }
+
+        for (int i = 0; i < path.length(); i++) {
+            int c = (int) path.charAt(i);
+            if (safeCharacters.get(c)) {
+                rewrittenPath.append((char)c);
+            } else {
+                // convert to external encoding before hex conversion
+                try {
+                    writer.write((char)c);
+                    writer.flush();
+                } catch(IOException e) {
+                    buf.reset();
+                    continue;
+                }
+                byte[] ba = buf.toByteArray();
+                for (int j = 0; j < ba.length; j++) {
+                    // Converting each byte in the buffer
+                    byte toEncode = ba[j];
+                    rewrittenPath.append('%');
+                    int low = (int) (toEncode & 0x0f);
+                    int high = (int) ((toEncode & 0xf0) >> 4);
+                    rewrittenPath.append(hexadecimal[high]);
+                    rewrittenPath.append(hexadecimal[low]);
+                }
+                buf.reset();
+            }
+        }
+        return rewrittenPath.toString();
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/XMLWriter.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/XMLWriter.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/util/XMLWriter.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,243 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.io.IOException;
+import java.io.Writer;
+
+/**
+ * XMLWriter helper class.
+ *
+ * @author <a href="mailto:remm at apache.org">Remy Maucherat</a>
+ */
+public class XMLWriter {
+
+
+    // -------------------------------------------------------------- Constants
+
+
+    /**
+     * Opening tag.
+     */
+    public static final int OPENING = 0;
+
+
+    /**
+     * Closing tag.
+     */
+    public static final int CLOSING = 1;
+
+
+    /**
+     * Element with no content.
+     */
+    public static final int NO_CONTENT = 2;
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * Buffer.
+     */
+    protected StringBuffer buffer = new StringBuffer();
+
+
+    /**
+     * Writer.
+     */
+    protected Writer writer = null;
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Constructor.
+     */
+    public XMLWriter() {
+    }
+
+
+    /**
+     * Constructor.
+     */
+    public XMLWriter(Writer writer) {
+        this.writer = writer;
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Retrieve generated XML.
+     *
+     * @return String containing the generated XML
+     */
+    public String toString() {
+        return buffer.toString();
+    }
+
+
+    /**
+     * Write property to the XML.
+     *
+     * @param namespace Namespace
+     * @param namespaceInfo Namespace info
+     * @param name Property name
+     * @param value Property value
+     */
+    public void writeProperty(String namespace, String namespaceInfo,
+                              String name, String value) {
+        writeElement(namespace, namespaceInfo, name, OPENING);
+        buffer.append(value);
+        writeElement(namespace, namespaceInfo, name, CLOSING);
+
+    }
+
+
+    /**
+     * Write property to the XML.
+     *
+     * @param namespace Namespace
+     * @param name Property name
+     * @param value Property value
+     */
+    public void writeProperty(String namespace, String name, String value) {
+        writeElement(namespace, name, OPENING);
+        buffer.append(value);
+        writeElement(namespace, name, CLOSING);
+    }
+
+
+    /**
+     * Write property to the XML.
+     *
+     * @param namespace Namespace
+     * @param name Property name
+     */
+    public void writeProperty(String namespace, String name) {
+        writeElement(namespace, name, NO_CONTENT);
+    }
+
+
+    /**
+     * Write an element.
+     *
+     * @param name Element name
+     * @param namespace Namespace abbreviation
+     * @param type Element type
+     */
+    public void writeElement(String namespace, String name, int type) {
+        writeElement(namespace, null, name, type);
+    }
+
+
+    /**
+     * Write an element.
+     *
+     * @param namespace Namespace abbreviation
+     * @param namespaceInfo Namespace info
+     * @param name Element name
+     * @param type Element type
+     */
+    public void writeElement(String namespace, String namespaceInfo,
+                             String name, int type) {
+        if ((namespace != null) && (namespace.length() > 0)) {
+            switch (type) {
+            case OPENING:
+                if (namespaceInfo != null) {
+                    buffer.append("<" + namespace + ":" + name + " xmlns:"
+                                  + namespace + "=\""
+                                  + namespaceInfo + "\">");
+                } else {
+                    buffer.append("<" + namespace + ":" + name + ">");
+                }
+                break;
+            case CLOSING:
+                buffer.append("</" + namespace + ":" + name + ">\n");
+                break;
+            case NO_CONTENT:
+            default:
+                if (namespaceInfo != null) {
+                    buffer.append("<" + namespace + ":" + name + " xmlns:"
+                                  + namespace + "=\""
+                                  + namespaceInfo + "\"/>");
+                } else {
+                    buffer.append("<" + namespace + ":" + name + "/>");
+                }
+                break;
+            }
+        } else {
+            switch (type) {
+            case OPENING:
+                buffer.append("<" + name + ">");
+                break;
+            case CLOSING:
+                buffer.append("</" + name + ">\n");
+                break;
+            case NO_CONTENT:
+            default:
+                buffer.append("<" + name + "/>");
+                break;
+            }
+        }
+    }
+
+
+    /**
+     * Write text.
+     *
+     * @param text Text to append
+     */
+    public void writeText(String text) {
+        buffer.append(text);
+    }
+
+
+    /**
+     * Write data.
+     *
+     * @param data Data to append
+     */
+    public void writeData(String data) {
+        buffer.append("<![CDATA[" + data + "]]>");
+    }
+
+
+    /**
+     * Write XML Header.
+     */
+    public void writeXMLHeader() {
+        buffer.append("<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n");
+    }
+
+
+    /**
+     * Send data and reinitializes buffer.
+     */
+    public void sendData()
+        throws IOException {
+        if (writer != null) {
+            writer.write(buffer.toString());
+            buffer = new StringBuffer();
+        }
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/valves/AccessLogValve.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/valves/AccessLogValve.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/valves/AccessLogValve.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,1131 @@
+/*
+ * Copyright 1999-2001,2004 The Apache Software Foundation.
+ *
+ * Licensed 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.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.net.InetAddress;
+import java.text.DecimalFormat;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.TimeZone;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpSession;
+
+import org.apache.catalina.Lifecycle;
+import org.apache.catalina.LifecycleException;
+import org.apache.catalina.LifecycleListener;
+import org.apache.catalina.connector.Request;
+import org.apache.catalina.connector.Response;
+import org.apache.catalina.util.LifecycleSupport;
+import org.apache.catalina.util.StringManager;
+
+
+/**
+ * <p>Implementation of the <b>Valve</b> interface that generates a web server
+ * access log with the detailed line contents matching a configurable pattern.
+ * The syntax of the available patterns is similar to that supported by the
+ * Apache <code>mod_log_config</code> module.  As an additional feature,
+ * automatic rollover of log files when the date changes is also supported.</p>
+ *
+ * <p>Patterns for the logged message may include constant text or any of the
+ * following replacement strings, for which the corresponding information
+ * from the specified Response is substituted:</p>
+ * <ul>
+ * <li><b>%a</b> - Remote IP address
+ * <li><b>%A</b> - Local IP address
+ * <li><b>%b</b> - Bytes sent, excluding HTTP headers, or '-' if no bytes
+ *     were sent
+ * <li><b>%B</b> - Bytes sent, excluding HTTP headers
+ * <li><b>%h</b> - Remote host name
+ * <li><b>%H</b> - Request protocol
+ * <li><b>%l</b> - Remote logical username from identd (always returns '-')
+ * <li><b>%m</b> - Request method
+ * <li><b>%p</b> - Local port
+ * <li><b>%q</b> - Query string (prepended with a '?' if it exists, otherwise
+ *     an empty string
+ * <li><b>%r</b> - First line of the request
+ * <li><b>%s</b> - HTTP status code of the response
+ * <li><b>%S</b> - User session ID
+ * <li><b>%t</b> - Date and time, in Common Log Format format
+ * <li><b>%u</b> - Remote user that was authenticated
+ * <li><b>%U</b> - Requested URL path
+ * <li><b>%v</b> - Local server name
+ * <li><b>%D</b> - Time taken to process the request, in millis
+ * <li><b>%T</b> - Time taken to process the request, in seconds
+ * </ul>
+ * <p>In addition, the caller can specify one of the following aliases for
+ * commonly utilized patterns:</p>
+ * <ul>
+ * <li><b>common</b> - <code>%h %l %u %t "%r" %s %b</code>
+ * <li><b>combined</b> -
+ *   <code>%h %l %u %t "%r" %s %b "%{Referer}i" "%{User-Agent}i"</code>
+ * </ul>
+ *
+ * <p>
+ * There is also support to write information from the cookie, incoming
+ * header, the Session or something else in the ServletRequest.<br>
+ * It is modeled after the apache syntax:
+ * <ul>
+ * <li><code>%{xxx}i</code> for incoming headers
+ * <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
+ * </ul>
+ * </p>
+ *
+ * <p>
+ * Conditional logging is also supported. This can be done with the
+ * <code>condition</code> property.
+ * If the value returned from ServletRequest.getAttribute(condition)
+ * yields a non-null value. The logging will be skipped.
+ * </p>
+ *
+ * @author Craig R. McClanahan
+ * @author Jason Brittain
+ * @version $Revision: 303826 $ $Date: 2005-03-31 04:31:54 -0600 (Thu, 31 Mar 2005) $
+ */
+
+public class AccessLogValve
+    extends ValveBase
+    implements Lifecycle {
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Construct a new instance of this class with default property values.
+     */
+    public AccessLogValve() {
+
+        super();
+        setPattern("common");
+
+
+    }
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The as-of date for the currently open log file, or a zero-length
+     * string if there is no open log file.
+     */
+    private String dateStamp = "";
+
+
+    /**
+     * The directory in which log files are created.
+     */
+    private String directory = "logs";
+
+
+    /**
+     * The descriptive information about this implementation.
+     */
+    protected static final String info =
+        "org.apache.catalina.valves.AccessLogValve/1.0";
+
+
+    /**
+     * The lifecycle event support for this component.
+     */
+    protected LifecycleSupport lifecycle = new LifecycleSupport(this);
+
+
+    /**
+     * The set of month abbreviations for log messages.
+     */
+    protected static final String months[] =
+    { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+      "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
+
+
+    /**
+     * If the current log pattern is the same as the common access log
+     * format pattern, then we'll set this variable to true and log in
+     * a more optimal and hard-coded way.
+     */
+    private boolean common = false;
+
+
+    /**
+     * For the combined format (common, plus useragent and referer), we do
+     * the same
+     */
+    private boolean combined = false;
+
+
+    /**
+     * The pattern used to format our access log lines.
+     */
+    private String pattern = null;
+
+
+    /**
+     * The prefix that is added to log file filenames.
+     */
+    private String prefix = "access_log.";
+
+
+    /**
+     * Should we rotate our log file? Default is true (like old behavior)
+     */
+    private boolean rotatable = true;
+
+
+    /**
+     * The string manager for this package.
+     */
+    private StringManager sm =
+        StringManager.getManager(Constants.Package);
+
+
+    /**
+     * Has this component been started yet?
+     */
+    private boolean started = false;
+
+
+    /**
+     * The suffix that is added to log file filenames.
+     */
+    private String suffix = "";
+
+
+    /**
+     * The PrintWriter to which we are currently logging, if any.
+     */
+    private PrintWriter writer = null;
+
+
+    /**
+     * A date formatter to format a Date into a date in the format
+     * "yyyy-MM-dd".
+     */
+    private SimpleDateFormat dateFormatter = null;
+
+
+    /**
+     * A date formatter to format Dates into a day string in the format
+     * "dd".
+     */
+    private SimpleDateFormat dayFormatter = null;
+
+
+    /**
+     * A date formatter to format a Date into a month string in the format
+     * "MM".
+     */
+    private SimpleDateFormat monthFormatter = null;
+
+
+    /**
+     * Time taken formatter for 3 decimal places.
+     */
+     private DecimalFormat timeTakenFormatter = null;
+
+
+    /**
+     * A date formatter to format a Date into a year string in the format
+     * "yyyy".
+     */
+    private SimpleDateFormat yearFormatter = null;
+
+
+    /**
+     * A date formatter to format a Date into a time in the format
+     * "kk:mm:ss" (kk is a 24-hour representation of the hour).
+     */
+    private SimpleDateFormat timeFormatter = null;
+
+
+    /**
+     * The system timezone.
+     */
+    private TimeZone timezone = null;
+
+    
+    /**
+     * The time zone offset relative to GMT in text form when daylight saving
+     * is not in operation.
+     */
+    private String timeZoneNoDST = null;
+
+
+    /**
+     * The time zone offset relative to GMT in text form when daylight saving
+     * is in operation.
+     */
+    private String timeZoneDST = null;
+    
+    
+    /**
+     * The system time when we last updated the Date that this valve
+     * uses for log lines.
+     */
+    private Date currentDate = null;
+
+
+    /**
+     * When formatting log lines, we often use strings like this one (" ").
+     */
+    private String space = " ";
+
+
+    /**
+     * Resolve hosts.
+     */
+    private boolean resolveHosts = false;
+
+
+    /**
+     * Instant when the log daily rotation was last checked.
+     */
+    private long rotationLastChecked = 0L;
+
+
+    /**
+     * Are we doing conditional logging. default false.
+     */
+    private String condition = null;
+
+
+    /**
+     * Date format to place in log file name. Use at your own risk!
+     */
+    private String fileDateFormat = null;
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * Return the directory in which we create log files.
+     */
+    public String getDirectory() {
+
+        return (directory);
+
+    }
+
+
+    /**
+     * Set the directory in which we create log files.
+     *
+     * @param directory The new log file directory
+     */
+    public void setDirectory(String directory) {
+
+        this.directory = directory;
+
+    }
+
+
+    /**
+     * Return descriptive information about this implementation.
+     */
+    public String getInfo() {
+
+        return (info);
+
+    }
+
+
+    /**
+     * Return the format pattern.
+     */
+    public String getPattern() {
+
+        return (this.pattern);
+
+    }
+
+
+    /**
+     * Set the format pattern, first translating any recognized alias.
+     *
+     * @param pattern The new pattern
+     */
+    public void setPattern(String pattern) {
+
+        if (pattern == null)
+            pattern = "";
+        if (pattern.equals(Constants.AccessLog.COMMON_ALIAS))
+            pattern = Constants.AccessLog.COMMON_PATTERN;
+        if (pattern.equals(Constants.AccessLog.COMBINED_ALIAS))
+            pattern = Constants.AccessLog.COMBINED_PATTERN;
+        this.pattern = pattern;
+
+        if (this.pattern.equals(Constants.AccessLog.COMMON_PATTERN))
+            common = true;
+        else
+            common = false;
+
+        if (this.pattern.equals(Constants.AccessLog.COMBINED_PATTERN))
+            combined = true;
+        else
+            combined = false;
+
+    }
+
+
+    /**
+     * Return the log file prefix.
+     */
+    public String getPrefix() {
+
+        return (prefix);
+
+    }
+
+
+    /**
+     * Set the log file prefix.
+     *
+     * @param prefix The new log file prefix
+     */
+    public void setPrefix(String prefix) {
+
+        this.prefix = prefix;
+
+    }
+
+
+    /**
+     * Should we rotate the logs
+     */
+    public boolean isRotatable() {
+
+        return rotatable;
+
+    }
+
+
+    /**
+     * Set the value is we should we rotate the logs
+     *
+     * @param rotatable true is we should rotate.
+     */
+    public void setRotatable(boolean rotatable) {
+
+        this.rotatable = rotatable;
+
+    }
+
+
+    /**
+     * Return the log file suffix.
+     */
+    public String getSuffix() {
+
+        return (suffix);
+
+    }
+
+
+    /**
+     * Set the log file suffix.
+     *
+     * @param suffix The new log file suffix
+     */
+    public void setSuffix(String suffix) {
+
+        this.suffix = suffix;
+
+    }
+
+
+    /**
+     * Set the resolve hosts flag.
+     *
+     * @param resolveHosts The new resolve hosts value
+     */
+    public void setResolveHosts(boolean resolveHosts) {
+
+        this.resolveHosts = resolveHosts;
+
+    }
+
+
+    /**
+     * Get the value of the resolve hosts flag.
+     */
+    public boolean isResolveHosts() {
+
+        return resolveHosts;
+
+    }
+
+
+    /**
+     * Return whether the attribute name to look for when
+     * performing conditional loggging. If null, every
+     * request is logged.
+     */
+    public String getCondition() {
+
+        return condition;
+
+    }
+
+
+    /**
+     * Set the ServletRequest.attribute to look for to perform
+     * conditional logging. Set to null to log everything.
+     *
+     * @param condition Set to null to log everything
+     */
+    public void setCondition(String condition) {
+
+        this.condition = condition;
+
+    }
+
+    /**
+     *  Return the date format date based log rotation.
+     */
+    public String getFileDateFormat() {
+        return fileDateFormat;
+    }
+
+
+    /**
+     *  Set the date format date based log rotation.
+     */
+    public void setFileDateFormat(String fileDateFormat) {
+        this.fileDateFormat =  fileDateFormat;
+    }
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Log a message summarizing the specified request and response, according
+     * to the format specified by the <code>pattern</code> property.
+     *
+     * @param request Request being processed
+     * @param response Response being processed
+     *
+     * @exception IOException if an input/output error has occurred
+     * @exception ServletException if a servlet error has occurred
+     */
+    public void invoke(Request request, Response response)
+        throws IOException, ServletException {
+
+        // Pass this request on to the next valve in our pipeline
+        long t1=System.currentTimeMillis();
+
+        getNext().invoke(request, response);
+
+        long t2=System.currentTimeMillis();
+        long time=t2-t1;
+
+        if (condition!=null &&
+                null!=request.getRequest().getAttribute(condition)) {
+            return;
+        }
+
+
+        Date date = getDate();
+        StringBuffer result = new StringBuffer();
+
+        // Check to see if we should log using the "common" access log pattern
+        if (common || combined) {
+            String value = null;
+
+            if (isResolveHosts())
+                result.append(request.getRemoteHost());
+            else
+                result.append(request.getRemoteAddr());
+
+            result.append(" - ");
+
+            value = request.getRemoteUser();
+            if (value == null)
+                result.append("- ");
+            else {
+                result.append(value);
+                result.append(space);
+            }
+
+            result.append("[");
+            result.append(dayFormatter.format(date));           // Day
+            result.append('/');
+            result.append(lookup(monthFormatter.format(date))); // Month
+            result.append('/');
+            result.append(yearFormatter.format(date));          // Year
+            result.append(':');
+            result.append(timeFormatter.format(date));          // Time
+            result.append(space);
+            result.append(getTimeZone(date));                   // Time Zone
+            result.append("] \"");
+
+            result.append(request.getMethod());
+            result.append(space);
+            result.append(request.getRequestURI());
+            if (request.getQueryString() != null) {
+                result.append('?');
+                result.append(request.getQueryString());
+            }
+            result.append(space);
+            result.append(request.getProtocol());
+            result.append("\" ");
+
+            result.append(response.getStatus());
+
+            result.append(space);
+
+            int length = response.getContentCount();
+
+            if (length <= 0)
+                value = "-";
+            else
+                value = "" + length;
+            result.append(value);
+
+            if (combined) {
+                result.append(space);
+                result.append("\"");
+                String referer = request.getHeader("referer");
+                if(referer != null)
+                    result.append(referer);
+                else
+                    result.append("-");
+                result.append("\"");
+
+                result.append(space);
+                result.append("\"");
+                String ua = request.getHeader("user-agent");
+                if(ua != null)
+                    result.append(ua);
+                else
+                    result.append("-");
+                result.append("\"");
+            }
+
+        } else {
+            // Generate a message based on the defined pattern
+            boolean replace = false;
+            for (int i = 0; i < pattern.length(); i++) {
+                char ch = pattern.charAt(i);
+                if (replace) {
+                    /* For code that processes {, the behavior will be ... if I
+                     * do not enounter a closing } - then I ignore the {
+                     */
+                    if ('{' == ch){
+                        StringBuffer name = new StringBuffer();
+                        int j = i + 1;
+                        for(;j < pattern.length() && '}' != pattern.charAt(j); j++) {
+                            name.append(pattern.charAt(j));
+                        }
+                        if (j+1 < pattern.length()) {
+                            /* the +1 was to account for } which we increment now */
+                            j++;
+                            result.append(replace(name.toString(),
+                                                pattern.charAt(j),
+                                                request,
+                                                response));
+                            i=j; /*Since we walked more than one character*/
+                        } else {
+                            //D'oh - end of string - pretend we never did this
+                            //and do processing the "old way"
+                            result.append(replace(ch, date, request, response, time));
+                        }
+                    } else {
+                        result.append(replace(ch, date, request, response,time ));
+                    }
+                    replace = false;
+                } else if (ch == '%') {
+                    replace = true;
+                } else {
+                    result.append(ch);
+                }
+            }
+        }
+        log(result.toString(), date);
+
+    }
+
+
+    // -------------------------------------------------------- Private Methods
+
+
+    /**
+     * Close the currently open log file (if any)
+     */
+    private synchronized void close() {
+
+        if (writer == null)
+            return;
+        writer.flush();
+        writer.close();
+        writer = null;
+        dateStamp = "";
+
+    }
+
+
+    /**
+     * Log the specified message to the log file, switching files if the date
+     * has changed since the previous log call.
+     *
+     * @param message Message to be logged
+     * @param date the current Date object (so this method doesn't need to
+     *        create a new one)
+     */
+    public void log(String message, Date date) {
+
+        if (rotatable){
+            // Only do a logfile switch check once a second, max.
+            long systime = System.currentTimeMillis();
+            if ((systime - rotationLastChecked) > 1000) {
+
+                // We need a new currentDate
+                currentDate = new Date(systime);
+                rotationLastChecked = systime;
+
+                // Check for a change of date
+                String tsDate = dateFormatter.format(currentDate);
+
+                // If the date has changed, switch log files
+                if (!dateStamp.equals(tsDate)) {
+                    synchronized (this) {
+                        if (!dateStamp.equals(tsDate)) {
+                            close();
+                            dateStamp = tsDate;
+                            open();
+                        }
+                    }
+                }
+
+            }
+        }
+
+        // Log this message
+        if (writer != null) {
+            writer.println(message);
+        }
+
+    }
+
+
+    /**
+     * Return the month abbreviation for the specified month, which must
+     * be a two-digit String.
+     *
+     * @param month Month number ("01" .. "12").
+     */
+    private String lookup(String month) {
+
+        int index;
+        try {
+            index = Integer.parseInt(month) - 1;
+        } catch (Throwable t) {
+            index = 0;  // Can not happen, in theory
+        }
+        return (months[index]);
+
+    }
+
+
+    /**
+     * Open the new log file for the date specified by <code>dateStamp</code>.
+     */
+    private synchronized void open() {
+
+        // Create the directory if necessary
+        File dir = new File(directory);
+        if (!dir.isAbsolute())
+            dir = new File(System.getProperty("catalina.base"), directory);
+        dir.mkdirs();
+
+        // Open the current log file
+        try {
+            String pathname;
+            // If no rotate - no need for dateStamp in fileName
+            if (rotatable){
+                pathname = dir.getAbsolutePath() + File.separator +
+                            prefix + dateStamp + suffix;
+            } else {
+                pathname = dir.getAbsolutePath() + File.separator +
+                            prefix + suffix;
+            }
+            writer = new PrintWriter(new FileWriter(pathname, true), true);
+        } catch (IOException e) {
+            writer = null;
+        }
+
+    }
+
+
+    /**
+     * Return the replacement text for the specified pattern character.
+     *
+     * @param pattern Pattern character identifying the desired text
+     * @param date the current Date so that this method doesn't need to
+     *        create one
+     * @param request Request being processed
+     * @param response Response being processed
+     */
+    private String replace(char pattern, Date date, Request request,
+                           Response response, long time) {
+
+        String value = null;
+
+        if (pattern == 'a') {
+            value = request.getRemoteAddr();
+        } else if (pattern == 'A') {
+            try {
+                value = InetAddress.getLocalHost().getHostAddress();
+            } catch(Throwable e){
+                value = "127.0.0.1";
+            }
+        } else if (pattern == 'b') {
+            int length = response.getContentCount();
+            if (length <= 0)
+                value = "-";
+            else
+                value = "" + length;
+        } else if (pattern == 'B') {
+            value = "" + response.getContentLength();
+        } else if (pattern == 'h') {
+            value = request.getRemoteHost();
+        } else if (pattern == 'H') {
+            value = request.getProtocol();
+        } else if (pattern == 'l') {
+            value = "-";
+        } else if (pattern == 'm') {
+            if (request != null)
+                value = request.getMethod();
+            else
+                value = "";
+        } else if (pattern == 'p') {
+            value = "" + request.getServerPort();
+        } else if (pattern == 'D') {
+                    value = "" + time;
+        } else if (pattern == 'q') {
+            String query = null;
+            if (request != null)
+                query = request.getQueryString();
+            if (query != null)
+                value = "?" + query;
+            else
+                value = "";
+        } else if (pattern == 'r') {
+            StringBuffer sb = new StringBuffer();
+            if (request != null) {
+                sb.append(request.getMethod());
+                sb.append(space);
+                sb.append(request.getRequestURI());
+                if (request.getQueryString() != null) {
+                    sb.append('?');
+                    sb.append(request.getQueryString());
+                }
+                sb.append(space);
+                sb.append(request.getProtocol());
+            } else {
+                sb.append("- - ");
+                sb.append(request.getProtocol());
+            }
+            value = sb.toString();
+        } else if (pattern == 'S') {
+            if (request != null)
+                if (request.getSession(false) != null)
+                    value = request.getSessionInternal(false).getIdInternal();
+                else value = "-";
+            else
+                value = "-";
+        } else if (pattern == 's') {
+            if (response != null)
+                value = "" + response.getStatus();
+            else
+                value = "-";
+        } else if (pattern == 't') {
+            StringBuffer temp = new StringBuffer("[");
+            temp.append(dayFormatter.format(date));             // Day
+            temp.append('/');
+            temp.append(lookup(monthFormatter.format(date)));   // Month
+            temp.append('/');
+            temp.append(yearFormatter.format(date));            // Year
+            temp.append(':');
+            temp.append(timeFormatter.format(date));            // Time
+            temp.append(' ');
+            temp.append(getTimeZone(date));                     // Timezone
+            temp.append(']');
+            value = temp.toString();
+        } else if (pattern == 'T') {
+            value = timeTakenFormatter.format(time/1000d);
+        } else if (pattern == 'u') {
+            if (request != null)
+                value = request.getRemoteUser();
+            if (value == null)
+                value = "-";
+        } else if (pattern == 'U') {
+            if (request != null)
+                value = request.getRequestURI();
+            else
+                value = "-";
+        } else if (pattern == 'v') {
+            value = request.getServerName();
+        } else {
+            value = "???" + pattern + "???";
+        }
+
+        if (value == null)
+            return ("");
+        else
+            return (value);
+
+    }
+
+
+    /**
+     * Return the replacement text for the specified "header/parameter".
+     *
+     * @param header The header/parameter to get
+     * @param type Where to get it from i=input,c=cookie,r=ServletRequest,s=Session
+     * @param request Request being processed
+     * @param response Response being processed
+     */
+    private String replace(String header, char type, Request request,
+                           Response response) {
+
+        Object value = null;
+
+        switch (type) {
+            case 'i':
+                if (null != request)
+                    value = request.getHeader(header);
+                else
+                    value= "??";
+                break;
+/*
+            // Someone please make me work
+            case 'o':
+                break;
+*/
+            case 'c':
+                 Cookie[] c = request.getCookies();
+                 for (int i=0; c != null && i < c.length; i++){
+                     if (header.equals(c[i].getName())){
+                         value = c[i].getValue();
+                         break;
+                     }
+                 }
+                break;
+            case 'r':
+                if (null != request)
+                    value = request.getAttribute(header);
+                else
+                    value= "??";
+                break;
+            case 's':
+                if (null != request) {
+                    HttpSession sess = request.getSession(false);
+                    if (null != sess)
+                        value = sess.getAttribute(header);
+                }
+               break;
+            default:
+                value = "???";
+        }
+
+        /* try catch in case toString() barfs */
+        try {
+            if (value!=null)
+                if (value instanceof String)
+                    return (String)value;
+                else
+                    return value.toString();
+            else
+               return "-";
+        } catch(Throwable e) {
+            return "-";
+        }
+    }
+
+
+    /**
+     * 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.
+     *
+     * @return Date
+     */
+    private Date getDate() {
+        if(currentDate == null) {
+        currentDate = new Date();
+        } else {
+          // Only create a new Date once per second, max.
+          long systime = System.currentTimeMillis();
+          if ((systime - currentDate.getTime()) > 1000) {
+              currentDate = new Date(systime);
+          }
+    }
+
+        return currentDate;
+    }
+
+
+    private String getTimeZone(Date date) {
+        if (timezone.inDaylightTime(date)) {
+            return timeZoneDST;
+        } else {
+            return timeZoneNoDST;
+        }
+    }
+    
+    
+    private String calculateTimeZoneOffset(long offset) {
+        StringBuffer tz = new StringBuffer();
+        if ((offset<0))  {
+            tz.append("-");
+            offset = -offset;
+        } else {
+            tz.append("+");
+        }
+
+        long hourOffset = offset/(1000*60*60);
+        long minuteOffset = (offset/(1000*60)) % 60;
+
+        if (hourOffset<10)
+            tz.append("0");
+        tz.append(hourOffset);
+
+        if (minuteOffset<10)
+            tz.append("0");
+        tz.append(minuteOffset);
+
+        return tz.toString();
+    }
+
+
+    // ------------------------------------------------------ Lifecycle Methods
+
+
+    /**
+     * Add a lifecycle event listener to this component.
+     *
+     * @param listener The listener to add
+     */
+    public void addLifecycleListener(LifecycleListener listener) {
+
+        lifecycle.addLifecycleListener(listener);
+
+    }
+
+
+    /**
+     * Get the lifecycle listeners associated with this lifecycle. If this
+     * Lifecycle has no listeners registered, a zero-length array is returned.
+     */
+    public LifecycleListener[] findLifecycleListeners() {
+
+        return lifecycle.findLifecycleListeners();
+
+    }
+
+
+    /**
+     * Remove a lifecycle event listener from this component.
+     *
+     * @param listener The listener to add
+     */
+    public void removeLifecycleListener(LifecycleListener listener) {
+
+        lifecycle.removeLifecycleListener(listener);
+
+    }
+
+
+    /**
+     * Prepare for the beginning of active use of the public methods of this
+     * component.  This method should be called after <code>configure()</code>,
+     * and before any of the public methods of the component are utilized.
+     *
+     * @exception LifecycleException if this component detects a fatal error
+     *  that prevents this component from being used
+     */
+    public void start() throws LifecycleException {
+
+        // Validate and update our current component state
+        if (started)
+            throw new LifecycleException
+                (sm.getString("accessLogValve.alreadyStarted"));
+        lifecycle.fireLifecycleEvent(START_EVENT, null);
+        started = true;
+
+        // Initialize the timeZone, Date formatters, and currentDate
+        timezone = TimeZone.getDefault();
+        timeZoneNoDST = calculateTimeZoneOffset(timezone.getRawOffset());
+        Calendar calendar = Calendar.getInstance(timezone);
+        int offset = calendar.get(Calendar.DST_OFFSET);
+        timeZoneDST = calculateTimeZoneOffset(timezone.getRawOffset()+offset);
+        
+        if (fileDateFormat==null || fileDateFormat.length()==0)
+            fileDateFormat = "yyyy-MM-dd";
+        dateFormatter = new SimpleDateFormat(fileDateFormat);
+        dateFormatter.setTimeZone(timezone);
+        dayFormatter = new SimpleDateFormat("dd");
+        dayFormatter.setTimeZone(timezone);
+        monthFormatter = new SimpleDateFormat("MM");
+        monthFormatter.setTimeZone(timezone);
+        yearFormatter = new SimpleDateFormat("yyyy");
+        yearFormatter.setTimeZone(timezone);
+        timeFormatter = new SimpleDateFormat("HH:mm:ss");
+        timeFormatter.setTimeZone(timezone);
+        currentDate = new Date();
+        dateStamp = dateFormatter.format(currentDate);
+        timeTakenFormatter = new DecimalFormat("0.000");
+
+        open();
+
+    }
+
+
+    /**
+     * Gracefully terminate the active use of the public methods of this
+     * component.  This method should be the last one called on a given
+     * instance of this component.
+     *
+     * @exception LifecycleException if this component detects a fatal error
+     *  that needs to be reported
+     */
+    public void stop() throws LifecycleException {
+
+        // Validate and update our current component state
+        if (!started)
+            throw new LifecycleException
+                (sm.getString("accessLogValve.notStarted"));
+        lifecycle.fireLifecycleEvent(STOP_EVENT, null);
+        started = false;
+
+        close();
+
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/valves/Constants.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/valves/Constants.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/valves/Constants.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,40 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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;
+
+
+/**
+ * Manifest constants for the <code>org.apache.catalina.valves</code>
+ * package.
+ *
+ * @author Craig R. McClanahan
+ */
+
+public final class Constants {
+
+    public static final String Package = "org.apache.catalina.valves";
+
+    // Constants for the AccessLogValve class
+    public static final class AccessLog {
+        public static final String COMMON_ALIAS = "common";
+        public static final String COMMON_PATTERN = "%h %l %u %t \"%r\" %s %b";
+        public static final String COMBINED_ALIAS = "combined";
+        public static final String COMBINED_PATTERN = "%h %l %u %t \"%r\" %s %b \"%{Referer}i\" \"%{User-Agent}i\"";
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/valves/ErrorReportValve.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/valves/ErrorReportValve.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/valves/ErrorReportValve.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,284 @@
+/*
+ * Copyright 1999-2001,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.io.IOException;
+import java.io.Writer;
+
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.catalina.Globals;
+import org.apache.catalina.connector.Request;
+import org.apache.catalina.connector.Response;
+import org.apache.catalina.util.RequestUtil;
+import org.apache.catalina.util.ServerInfo;
+import org.apache.catalina.util.StringManager;
+import org.apache.tomcat.util.IntrospectionUtils;
+import org.apache.tomcat.util.compat.JdkCompat;
+
+/**
+ * <p>Implementation of a Valve that outputs HTML error pages.</p>
+ *
+ * <p>This Valve should be attached at the Host level, although it will work
+ * if attached to a Context.</p>
+ *
+ * <p>HTML code from the Cocoon 2 project.</p>
+ *
+ * @author Remy Maucherat
+ * @author Craig R. McClanahan
+ * @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 $Revision: 304023 $ $Date: 2005-07-26 07:45:22 -0500 (Tue, 26 Jul 2005) $
+ */
+
+public class ErrorReportValve
+    extends ValveBase {
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The descriptive information related to this implementation.
+     */
+    private static final String info =
+        "org.apache.catalina.valves.ErrorReportValve/1.0";
+
+
+    /**
+     * The StringManager for this package.
+     */
+    protected static StringManager sm =
+        StringManager.getManager(Constants.Package);
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * Return descriptive information about this Valve implementation.
+     */
+    public String getInfo() {
+
+        return (info);
+
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Invoke the next Valve in the sequence. When the invoke returns, check
+     * the response state, and output an error report is necessary.
+     *
+     * @param request The servlet request to be processed
+     * @param response The servlet response to be created
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception ServletException if a servlet error occurs
+     */
+    public void invoke(Request request, Response response)
+        throws IOException, ServletException {
+
+        // Perform the request
+        getNext().invoke(request, response);
+
+        ServletRequest sreq = (ServletRequest) request;
+        Throwable throwable =
+            (Throwable) sreq.getAttribute(Globals.EXCEPTION_ATTR);
+
+        ServletResponse sresp = (ServletResponse) response;
+        if (sresp.isCommitted()) {
+            return;
+        }
+
+        if (throwable != null) {
+
+            // The response is an error
+            response.setError();
+
+            // Reset the response (if possible)
+            try {
+                sresp.reset();
+            } catch (IllegalStateException e) {
+                ;
+            }
+
+            response.sendError
+                (HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
+
+        }
+
+        response.setSuspended(false);
+
+        try {
+            report(request, response, throwable);
+        } catch (Throwable tt) {
+            ;
+        }
+
+    }
+
+
+    // ------------------------------------------------------ Protected Methods
+
+
+    /**
+     * Prints out an error report.
+     *
+     * @param request The request being processed
+     * @param response The response being generated
+     * @param throwable The exception that occurred (which possibly wraps
+     *  a root cause exception
+     */
+    protected void report(Request request, Response response,
+                          Throwable throwable)
+        throws IOException {
+
+        // Do nothing on non-HTTP responses
+        int statusCode = response.getStatus();
+
+        // Do nothing on a 1xx, 2xx and 3xx status
+        // Do nothing if anything has been written already
+        if ((statusCode < 400) || (response.getContentCount() > 0))
+            return;
+
+        Throwable rootCause = null;
+
+        if (throwable != null) {
+
+            if (throwable instanceof ServletException)
+                rootCause = ((ServletException) throwable).getRootCause();
+
+        }
+
+        String message = RequestUtil.filter(response.getMessage());
+        if (message == null)
+            message = "";
+
+        // Do nothing if there is no report for the specified status code
+        String report = null;
+        try {
+            report = sm.getString("http." + statusCode, message);
+        } catch (Throwable t) {
+            ;
+        }
+        if (report == null)
+            return;
+
+        StringBuffer sb = new StringBuffer();
+
+        sb.append("<html><head><title>");
+        sb.append(ServerInfo.getServerInfo()).append(" - ");
+        sb.append(sm.getString("errorReportValve.errorReport"));
+        sb.append("</title>");
+        sb.append("<style><!--");
+        sb.append(org.apache.catalina.util.TomcatCSS.TOMCAT_CSS);
+        sb.append("--></style> ");
+        sb.append("</head><body>");
+        sb.append("<h1>");
+        sb.append(sm.getString("errorReportValve.statusHeader",
+                               "" + statusCode, message)).append("</h1>");
+        sb.append("<HR size=\"1\" noshade=\"noshade\">");
+        sb.append("<p><b>type</b> ");
+        if (throwable != null) {
+            sb.append(sm.getString("errorReportValve.exceptionReport"));
+        } else {
+            sb.append(sm.getString("errorReportValve.statusReport"));
+        }
+        sb.append("</p>");
+        sb.append("<p><b>");
+        sb.append(sm.getString("errorReportValve.message"));
+        sb.append("</b> <u>");
+        sb.append(message).append("</u></p>");
+        sb.append("<p><b>");
+        sb.append(sm.getString("errorReportValve.description"));
+        sb.append("</b> <u>");
+        sb.append(report);
+        sb.append("</u></p>");
+
+        if (throwable != null) {
+
+            String stackTrace = JdkCompat.getJdkCompat()
+                .getPartialServletStackTrace(throwable);
+            sb.append("<p><b>");
+            sb.append(sm.getString("errorReportValve.exception"));
+            sb.append("</b> <pre>");
+            sb.append(RequestUtil.filter(stackTrace));
+            sb.append("</pre></p>");
+
+            while (rootCause != null) {
+                stackTrace = JdkCompat.getJdkCompat()
+                    .getPartialServletStackTrace(rootCause);
+                sb.append("<p><b>");
+                sb.append(sm.getString("errorReportValve.rootCause"));
+                sb.append("</b> <pre>");
+                sb.append(RequestUtil.filter(stackTrace));
+                sb.append("</pre></p>");
+                // In case root cause is somehow heavily nested
+                try {
+                    rootCause = (Throwable)IntrospectionUtils.getProperty
+                                                (rootCause, "rootCause");
+                } catch (ClassCastException e) {
+                    rootCause = null;
+                }
+            }
+
+            sb.append("<p><b>");
+            sb.append(sm.getString("errorReportValve.note"));
+            sb.append("</b> <u>");
+            sb.append(sm.getString("errorReportValve.rootCauseInLogs",
+                                   ServerInfo.getServerInfo()));
+            sb.append("</u></p>");
+
+        }
+
+        sb.append("<HR size=\"1\" noshade=\"noshade\">");
+        sb.append("<h3>").append(ServerInfo.getServerInfo()).append("</h3>");
+        sb.append("</body></html>");
+
+        try {
+            try {
+                response.setContentType("text/html");
+                response.setCharacterEncoding("utf-8");
+            } catch (Throwable t) {
+                if (container.getLogger().isDebugEnabled())
+                    container.getLogger().debug("status.setContentType", t);
+            }
+            Writer writer = response.getReporter();
+            if (writer != null) {
+                // If writer is null, it's an indication that the response has
+                // been hard committed already, which should never happen
+                writer.write(sb.toString());
+            }
+        } catch (IOException e) {
+            ;
+        } catch (IllegalStateException e) {
+            ;
+        }
+        
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/valves/ExtendedAccessLogValve.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/valves/ExtendedAccessLogValve.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/valves/ExtendedAccessLogValve.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,1429 @@
+/*
+ * Copyright 1999-2001,2004 The Apache Software Foundation.
+ *
+ * Licensed 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.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.net.InetAddress;
+import java.net.URLEncoder;
+import java.text.DecimalFormat;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.TimeZone;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpSession;
+
+import org.apache.catalina.Lifecycle;
+import org.apache.catalina.LifecycleException;
+import org.apache.catalina.LifecycleListener;
+import org.apache.catalina.connector.Request;
+import org.apache.catalina.connector.Response;
+import org.apache.catalina.util.LifecycleSupport;
+import org.apache.catalina.util.ServerInfo;
+import org.apache.catalina.util.StringManager;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+
+
+/**
+ * An implementation of the W3c Extended Log File Format. See
+ * http://www.w3.org/TR/WD-logfile.html for more information about the format.
+ *
+ * The following fields are supported:
+ * <ul>
+ * <li><code>c-dns</code>:  Client hostname</li>
+ * <li><code>c-ip</code>:  Client ip address</li>
+ * <li><code>bytes</code>:  bytes served</li>
+ * <li><code>cs-method</code>:  request method</li>
+ * <li><code>cs-uri</code>:  The full uri requested</li>
+ * <li><code>cs-uri-query</code>:  The query string</li>
+ * <li><code>cs-uri-stem</code>:  The uri without query string</li>
+ * <li><code>date</code>:  The date in yyyy-mm-dd  format for GMT</li>
+ * <li><code>s-dns</code>: The server dns entry </li>
+ * <li><code>s-ip</code>:  The server ip address</li>
+ * <li><code>cs(XXX)</code>:  The value of header XXX from client to server</li>
+ * <li><code>sc(XXX)</code>: The value of header XXX from server to client </li>
+ * <li><code>sc-status</code>:  The status code</li>
+ * <li><code>time</code>:  Time the request was served</li>
+ * <li><code>time-taken</code>:  Time (in seconds) taken to serve the request</li>
+ * <li><code>x-A(XXX)</code>: Pull XXX attribute from the servlet context </li>
+ * <li><code>x-C(XXX)</code>: Pull the first cookie of the name XXX </li>
+ * <li><code>x-R(XXX)</code>: Pull XXX attribute from the servlet request </li>
+ * <li><code>x-S(XXX)</code>: Pull XXX attribute from the session </li>
+ * <li><code>x-P(...)</code>:  Call request.getParameter(...)
+ *                             and URLencode it. Helpful to capture
+ *                             certain POST parameters.
+ * </li>
+ * <li>For any of the x-H(...) the following method will be called from the
+ *                HttpServletRequestObject </li>
+ * <li><code>x-H(authType)</code>: getAuthType </li>
+ * <li><code>x-H(characterEncoding)</code>: getCharacterEncoding </li>
+ * <li><code>x-H(contentLength)</code>: getContentLength </li>
+ * <li><code>x-H(locale)</code>:  getLocale</li>
+ * <li><code>x-H(protocol)</code>: getProtocol </li>
+ * <li><code>x-H(remoteUser)</code>:  getRemoteUser</li>
+ * <li><code>x-H(requestedSessionId)</code>: getGequestedSessionId</li>
+ * <li><code>x-H(requestedSessionIdFromCookie)</code>:
+ *                  isRequestedSessionIdFromCookie </li>
+ * <li><code>x-H(requestedSessionIdValid)</code>:
+ *                  isRequestedSessionIdValid</li>
+ * <li><code>x-H(scheme)</code>:  getScheme</li>
+ * <li><code>x-H(secure)</code>:  isSecure</li>
+ * </ul>
+ *
+ *
+ *
+ * <p>
+ * Log rotation can be on or off. This is dictated by the rotatable
+ * property.
+ * </p>
+ *
+ * <p>
+ * For UNIX users, another field called <code>checkExists</code>is also
+ * available. If set to true, the log file's existence will be checked before
+ * each logging. This way an external log rotator can move the file
+ * somewhere and tomcat will start with a new file.
+ * </p>
+ *
+ * <p>
+ * For JMX junkies, a public method called </code>rotate</code> has
+ * been made available to allow you to tell this instance to move
+ * the existing log file to somewhere else start writing a new log file.
+ * </p>
+ *
+ * <p>
+ * Conditional logging is also supported. This can be done with the
+ * <code>condition</code> property.
+ * If the value returned from ServletRequest.getAttribute(condition)
+ * yields a non-null value. The logging will be skipped.
+ * </p>
+ *
+ * <p>
+ * For extended attributes coming from a getAttribute() call,
+ * it is you responsibility to ensure there are no newline or
+ * control characters.
+ * </p>
+ *
+ *
+ * @author Tim Funk
+ * @version $Revision: 303601 $ $Date: 2004-12-23 17:58:07 -0600 (Thu, 23 Dec 2004) $
+ */
+
+public class ExtendedAccessLogValve
+    extends ValveBase
+    implements Lifecycle {
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Construct a new instance of this class with default property values.
+     */
+    public ExtendedAccessLogValve() {
+
+        super();
+
+
+    }
+
+
+    // ----------------------------------------------------- Instance Variables
+    private static Log log = LogFactory.getLog(ExtendedAccessLogValve.class);
+
+
+    /**
+     * The descriptive information about this implementation.
+     */
+    protected static final String info =
+        "org.apache.catalina.valves.ExtendedAccessLogValve/1.0";
+
+
+    /**
+     * The lifecycle event support for this component.
+     */
+    protected LifecycleSupport lifecycle = new LifecycleSupport(this);
+
+
+
+    /**
+     * The string manager for this package.
+     */
+    private StringManager sm =
+        StringManager.getManager(Constants.Package);
+
+
+    /**
+     * Has this component been started yet?
+     */
+    private boolean started = false;
+
+
+    /**
+     * The as-of date for the currently open log file, or a zero-length
+     * string if there is no open log file.
+     */
+    private String dateStamp = "";
+
+
+    /**
+     * The PrintWriter to which we are currently logging, if any.
+     */
+    private PrintWriter writer = null;
+
+
+    /**
+     * The formatter for the date contained in the file name.
+     */
+    private SimpleDateFormat fileDateFormatter = null;
+
+
+    /**
+     * A date formatter to format a Date into a date in the format
+     * "yyyy-MM-dd".
+     */
+    private SimpleDateFormat dateFormatter = null;
+
+
+    /**
+     * A date formatter to format a Date into a time in the format
+     * "kk:mm:ss" (kk is a 24-hour representation of the hour).
+     */
+    private SimpleDateFormat timeFormatter = null;
+
+
+    /**
+     * Time taken formatter for 3 decimal places.
+     */
+     private DecimalFormat timeTakenFormatter = null;
+
+
+    /**
+     * My ip address. Look it up once and remember it. Dump this if we can
+     * determine another reliable way to get server ip address since this
+     * server may have many ip's.
+     */
+    private String myIpAddress = null;
+
+
+    /**
+     * My dns name. Look it up once and remember it. Dump this if we can
+     * determine another reliable way to get server name address since this
+     * server may have many ip's.
+     */
+    private String myDNSName = null;
+
+
+    /**
+     * Holder for all of the fields to log after the pattern is decoded.
+     */
+    private FieldInfo[] fieldInfos;
+
+
+    /**
+     * The current log file we are writing to. Helpful when checkExists
+     * is true.
+     */
+    private File currentLogFile = null;
+
+
+
+    /**
+     * The system time when we last updated the Date that this valve
+     * uses for log lines.
+     */
+    private Date currentDate = null;
+
+
+    /**
+     * Instant when the log daily rotation was last checked.
+     */
+    private long rotationLastChecked = 0L;
+
+
+    /**
+     * The directory in which log files are created.
+     */
+    private String directory = "logs";
+
+
+    /**
+     * The pattern used to format our access log lines.
+     */
+    private String pattern = null;
+
+
+    /**
+     * The prefix that is added to log file filenames.
+     */
+    private String prefix = "access_log.";
+
+
+    /**
+     * Should we rotate our log file? Default is true (like old behavior)
+     */
+    private boolean rotatable = true;
+
+
+    /**
+     * The suffix that is added to log file filenames.
+     */
+    private String suffix = "";
+
+
+    /**
+     * Are we doing conditional logging. default false.
+     */
+    private String condition = null;
+
+
+    /**
+     * Do we check for log file existence? Helpful if an external
+     * agent renames the log file so we can automagically recreate it.
+     */
+    private boolean checkExists = false;
+
+
+    /**
+     * Date format to place in log file name. Use at your own risk!
+     */
+    private String fileDateFormat = null;
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * Return the directory in which we create log files.
+     */
+    public String getDirectory() {
+
+        return (directory);
+
+    }
+
+
+    /**
+     * Set the directory in which we create log files.
+     *
+     * @param directory The new log file directory
+     */
+    public void setDirectory(String directory) {
+
+        this.directory = directory;
+
+    }
+
+
+    /**
+     * Return descriptive information about this implementation.
+     */
+    public String getInfo() {
+
+        return (info);
+
+    }
+
+
+    /**
+     * Return the format pattern.
+     */
+    public String getPattern() {
+
+        return (this.pattern);
+
+    }
+
+
+    /**
+     * Set the format pattern, first translating any recognized alias.
+     *
+     * @param pattern The new pattern pattern
+     */
+    public void setPattern(String pattern) {
+
+        FieldInfo[] f= decodePattern(pattern);
+        if (f!=null) {
+            this.pattern = pattern;
+            this.fieldInfos = f;
+        }
+    }
+
+
+    /**
+     * Return the log file prefix.
+     */
+    public String getPrefix() {
+
+        return (prefix);
+
+    }
+
+
+    /**
+     * Set the log file prefix.
+     *
+     * @param prefix The new log file prefix
+     */
+    public void setPrefix(String prefix) {
+
+        this.prefix = prefix;
+
+    }
+
+
+    /**
+     * Return true if logs are automatically rotated.
+     */
+    public boolean isRotatable() {
+
+        return rotatable;
+
+    }
+
+
+    /**
+     * Set the value is we should we rotate the logs
+     *
+     * @param rotatable true is we should rotate.
+     */
+    public void setRotatable(boolean rotatable) {
+
+        this.rotatable = rotatable;
+
+    }
+
+
+    /**
+     * Return the log file suffix.
+     */
+    public String getSuffix() {
+
+        return (suffix);
+
+    }
+
+
+    /**
+     * Set the log file suffix.
+     *
+     * @param suffix The new log file suffix
+     */
+    public void setSuffix(String suffix) {
+
+        this.suffix = suffix;
+
+    }
+
+
+
+    /**
+     * Return whether the attribute name to look for when
+     * performing conditional loggging. If null, every
+     * request is logged.
+     */
+    public String getCondition() {
+
+        return condition;
+
+    }
+
+
+    /**
+     * Set the ServletRequest.attribute to look for to perform
+     * conditional logging. Set to null to log everything.
+     *
+     * @param condition Set to null to log everything
+     */
+    public void setCondition(String condition) {
+
+        this.condition = condition;
+
+    }
+
+
+
+    /**
+     * Check for file existence before logging.
+     */
+    public boolean isCheckExists() {
+
+        return checkExists;
+
+    }
+
+
+    /**
+     * Set whether to check for log file existence before logging.
+     *
+     * @param checkExists true meaning to check for file existence.
+     */
+    public void setCheckExists(boolean checkExists) {
+
+        this.checkExists = checkExists;
+
+    }
+
+
+    /**
+     *  Return the date format date based log rotation.
+     */
+    public String getFileDateFormat() {
+        return fileDateFormat;
+    }
+
+
+    /**
+     *  Set the date format date based log rotation.
+     */
+    public void setFileDateFormat(String fileDateFormat) {
+        this.fileDateFormat =  fileDateFormat;
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Log a message summarizing the specified request and response, according
+     * to the format specified by the <code>pattern</code> property.
+     *
+     * @param request Request being processed
+     * @param response Response being processed
+     *
+     * @exception IOException if an input/output error has occurred
+     * @exception ServletException if a servlet error has occurred
+     */
+    public void invoke(Request request, Response response)
+        throws IOException, ServletException {
+
+        // Pass this request on to the next valve in our pipeline
+        long endTime;
+        long runTime;
+        long startTime=System.currentTimeMillis();
+
+        getNext().invoke(request, response);
+
+        endTime = System.currentTimeMillis();
+        runTime = endTime-startTime;
+
+        if (fieldInfos==null || condition!=null &&
+              null!=request.getRequest().getAttribute(condition)) {
+            return;
+        }
+
+
+        Date date = getDate(endTime);
+        StringBuffer result = new StringBuffer();
+
+        for (int i=0; fieldInfos!=null && i<fieldInfos.length; i++) {
+            switch(fieldInfos[i].type) {
+                case FieldInfo.DATA_CLIENT:
+                    if (FieldInfo.FIELD_IP==fieldInfos[i].location)
+                        result.append(request.getRequest().getRemoteAddr());
+                    else if (FieldInfo.FIELD_DNS==fieldInfos[i].location)
+                        result.append(request.getRequest().getRemoteHost());
+                    else
+                        result.append("?WTF?"); /* This should never happen! */
+                    break;
+                case FieldInfo.DATA_SERVER:
+                    if (FieldInfo.FIELD_IP==fieldInfos[i].location)
+                        result.append(myIpAddress);
+                    else if (FieldInfo.FIELD_DNS==fieldInfos[i].location)
+                        result.append(myDNSName);
+                    else
+                        result.append("?WTF?"); /* This should never happen! */
+                    break;
+                case FieldInfo.DATA_REMOTE:
+                    result.append('?'); /* I don't know how to handle these! */
+                    break;
+                case FieldInfo.DATA_CLIENT_TO_SERVER:
+                    result.append(getClientToServer(fieldInfos[i], request));
+                    break;
+                case FieldInfo.DATA_SERVER_TO_CLIENT:
+                    result.append(getServerToClient(fieldInfos[i], response));
+                    break;
+                case FieldInfo.DATA_SERVER_TO_RSERVER:
+                    result.append('-');
+                    break;
+                case FieldInfo.DATA_RSERVER_TO_SERVER:
+                    result.append('-');
+                    break;
+                case FieldInfo.DATA_APP_SPECIFIC:
+                    result.append(getAppSpecific(fieldInfos[i], request));
+                    break;
+                case FieldInfo.DATA_SPECIAL:
+                    if (FieldInfo.SPECIAL_DATE==fieldInfos[i].location)
+                        result.append(dateFormatter.format(date));
+                    else if (FieldInfo.SPECIAL_TIME_TAKEN==fieldInfos[i].location)
+                        result.append(timeTakenFormatter.format(runTime/1000d));
+                    else if (FieldInfo.SPECIAL_TIME==fieldInfos[i].location)
+                        result.append(timeFormatter.format(date));
+                    else if (FieldInfo.SPECIAL_BYTES==fieldInfos[i].location) {
+                        int length = response.getContentCount();
+                        if (length > 0)
+                            result.append(length);
+                        else
+                            result.append("-");
+                    } else if (FieldInfo.SPECIAL_CACHED==fieldInfos[i].location)
+                        result.append('-'); /* I don't know how to evaluate this! */
+                    else
+                        result.append("?WTF?"); /* This should never happen! */
+                    break;
+                default:
+                    result.append("?WTF?"); /* This should never happen! */
+            }
+
+            if (fieldInfos[i].postWhiteSpace!=null) {
+                result.append(fieldInfos[i].postWhiteSpace);
+            }
+        }
+        log(result.toString(), date);
+
+    }
+
+
+    /**
+     * Rename the existing log file to something else. Then open the
+     * old log file name up once again. Intended to be called by a JMX
+     * agent.
+     *
+     *
+     * @param newFileName The file name to move the log file entry to
+     * @return true if a file was rotated with no error
+     */
+    public synchronized boolean rotate(String newFileName) {
+
+        if (currentLogFile!=null) {
+            File holder = currentLogFile;
+            close();
+            try {
+                holder.renameTo(new File(newFileName));
+            } catch(Throwable e){
+                log.error("rotate failed", e);
+            }
+
+            /* Make sure date is correct */
+            currentDate = new Date(System.currentTimeMillis());
+            dateStamp = fileDateFormatter.format(currentDate);
+
+            open();
+            return true;
+        } else {
+            return false;
+        }
+
+    }
+
+    // -------------------------------------------------------- Private Methods
+
+
+    /**
+     *  Return the client to server data.
+     *  @param fieldInfo The field to decode.
+     *  @param request The object we pull data from.
+     *  @return The appropriate value.
+     */
+     private String getClientToServer(FieldInfo fieldInfo, Request request) {
+
+        switch(fieldInfo.location) {
+            case FieldInfo.FIELD_METHOD:
+                return request.getMethod();
+            case FieldInfo.FIELD_URI:
+                if (null==request.getQueryString())
+                    return request.getRequestURI();
+                else
+                    return request.getRequestURI() + "?" + request.getQueryString();
+            case FieldInfo.FIELD_URI_STEM:
+                return request.getRequestURI();
+            case FieldInfo.FIELD_URI_QUERY:
+                if (null==request.getQueryString())
+                    return "-";
+                return request.getQueryString();
+            case FieldInfo.FIELD_HEADER:
+                return wrap(request.getHeader(fieldInfo.value));
+            default:
+                ;
+        }
+
+        return "-";
+
+    }
+
+
+    /**
+     *  Return the server to client data.
+     *  @param fieldInfo The field to decode.
+     *  @param response The object we pull data from.
+     *  @return The appropriate value.
+     */
+    private String getServerToClient(FieldInfo fieldInfo, Response response) {
+        switch(fieldInfo.location) {
+            case FieldInfo.FIELD_STATUS:
+                return "" + response.getStatus();
+            case FieldInfo.FIELD_COMMENT:
+                return "?"; /* Not coded yet*/
+            case FieldInfo.FIELD_HEADER:
+                return wrap(response.getHeader(fieldInfo.value));
+            default:
+                ;
+        }
+
+        return "-";
+
+    }
+
+
+    /**
+     * Get app specific data.
+     * @param fieldInfo The field to decode
+     * @param request Where we will pull the data from.
+     * @return The appropriate value
+     */
+    private String getAppSpecific(FieldInfo fieldInfo, Request request) {
+
+        switch(fieldInfo.xType) {
+            case FieldInfo.X_PARAMETER:
+                return wrap(urlEncode(request.getParameter(fieldInfo.value)));
+            case FieldInfo.X_REQUEST:
+                return wrap(request.getAttribute(fieldInfo.value));
+            case FieldInfo.X_SESSION:
+                HttpSession session = null;
+                if (request!=null){
+                    session = request.getSession(false);
+                    if (session!=null)
+                        return wrap(session.getAttribute(fieldInfo.value));
+                }
+                break;
+            case FieldInfo.X_COOKIE:
+                Cookie[] c = request.getCookies();
+                for (int i=0; c != null && i < c.length; i++){
+                    if (fieldInfo.value.equals(c[i].getName())){
+                        return wrap(c[i].getValue());
+                    }
+                 }
+            case FieldInfo.X_APP:
+                return wrap(request.getContext().getServletContext()
+                                .getAttribute(fieldInfo.value));
+            case FieldInfo.X_SERVLET_REQUEST:
+                if (fieldInfo.location==FieldInfo.X_LOC_AUTHTYPE) {
+                    return wrap(request.getAuthType());
+                } else if (fieldInfo.location==FieldInfo.X_LOC_REMOTEUSER) {
+                    return wrap(request.getRemoteUser());
+                } else if (fieldInfo.location==
+                            FieldInfo.X_LOC_REQUESTEDSESSIONID) {
+                    return wrap(request.getRequestedSessionId());
+                } else if (fieldInfo.location==
+                            FieldInfo.X_LOC_REQUESTEDSESSIONIDFROMCOOKIE) {
+                    return wrap(""+request.isRequestedSessionIdFromCookie());
+                } else if (fieldInfo.location==
+                            FieldInfo.X_LOC_REQUESTEDSESSIONIDVALID) {
+                    return wrap(""+request.isRequestedSessionIdValid());
+                } else if (fieldInfo.location==FieldInfo.X_LOC_CONTENTLENGTH) {
+                    return wrap(""+request.getContentLength());
+                } else if (fieldInfo.location==
+                            FieldInfo.X_LOC_CHARACTERENCODING) {
+                    return wrap(request.getCharacterEncoding());
+                } else if (fieldInfo.location==FieldInfo.X_LOC_LOCALE) {
+                    return wrap(request.getLocale());
+                } else if (fieldInfo.location==FieldInfo.X_LOC_PROTOCOL) {
+                    return wrap(request.getProtocol());
+                } else if (fieldInfo.location==FieldInfo.X_LOC_SCHEME) {
+                    return wrap(request.getScheme());
+                } else if (fieldInfo.location==FieldInfo.X_LOC_SECURE) {
+                    return wrap(""+request.isSecure());
+                }
+                break;
+            default:
+                ;
+        }
+
+        return "-";
+
+    }
+
+
+    /**
+     *  urlEncode the given string. If null or empty, return null.
+     */
+    private String urlEncode(String value) {
+        if (null==value || value.length()==0) {
+            return null;
+        }
+        return URLEncoder.encode(value);
+    }
+
+
+    /**
+     *  Wrap the incoming value into quotes and escape any inner
+     *  quotes with double quotes.
+     *
+     *  @param value - The value to wrap quotes around
+     *  @return '-' if empty of null. Otherwise, toString() will
+     *     be called on the object and the value will be wrapped
+     *     in quotes and any quotes will be escaped with 2
+     *     sets of quotes.
+     */
+    private String wrap(Object value) {
+
+        String svalue;
+        // Does the value contain a " ? If so must encode it
+        if (value==null || "-".equals(value))
+            return "-";
+
+
+        try {
+            svalue = value.toString();
+            if ("".equals(svalue))
+                return "-";
+        } catch(Throwable e){
+            /* Log error */
+            return "-";
+        }
+
+        /* Wrap all quotes in double quotes. */
+        StringBuffer buffer = new StringBuffer(svalue.length()+2);
+        buffer.append('"');
+        int i=0;
+        while (i<svalue.length()) {
+            int j = svalue.indexOf('"', i);
+            if (j==-1) {
+                buffer.append(svalue.substring(i));
+                i=svalue.length();
+            } else {
+                buffer.append(svalue.substring(i, j+1));
+                buffer.append('"');
+                i=j+2;
+            }
+        }
+
+        buffer.append('"');
+        return buffer.toString();
+
+    }
+
+
+    /**
+     * Close the currently open log file (if any)
+     */
+    private synchronized void close() {
+
+        if (writer == null)
+            return;
+        writer.flush();
+        writer.close();
+        writer = null;
+        currentLogFile = null;
+
+    }
+
+
+    /**
+     * Log the specified message to the log file, switching files if the date
+     * has changed since the previous log call.
+     *
+     * @param message Message to be logged
+     * @param date the current Date object (so this method doesn't need to
+     *        create a new one)
+     */
+    private void log(String message, Date date) {
+
+        if (rotatable){
+            // Only do a logfile switch check once a second, max.
+            long systime = System.currentTimeMillis();
+            if ((systime - rotationLastChecked) > 1000) {
+
+                // We need a new currentDate
+                currentDate = new Date(systime);
+                rotationLastChecked = systime;
+
+                // Check for a change of date
+                String tsDate = fileDateFormatter.format(currentDate);
+
+                // If the date has changed, switch log files
+                if (!dateStamp.equals(tsDate)) {
+                    synchronized (this) {
+                        if (!dateStamp.equals(tsDate)) {
+                            close();
+                            dateStamp = tsDate;
+                            open();
+                        }
+                    }
+                }
+            }
+        }
+
+        /* In case something external rotated the file instead */
+        if (checkExists){
+            synchronized (this) {
+                if (currentLogFile!=null && !currentLogFile.exists()) {
+                    try {
+                        close();
+                    } catch (Throwable e){
+                        log.info("at least this wasn't swallowed", e);
+                    }
+
+                    /* Make sure date is correct */
+                    currentDate = new Date(System.currentTimeMillis());
+                    dateStamp = fileDateFormatter.format(currentDate);
+
+                    open();
+                }
+            }
+        }
+
+        // Log this message
+        if (writer != null) {
+            writer.println(message);
+        }
+
+    }
+
+
+    /**
+     * Open the new log file for the date specified by <code>dateStamp</code>.
+     */
+    private synchronized void open() {
+
+        // Create the directory if necessary
+        File dir = new File(directory);
+        if (!dir.isAbsolute())
+            dir = new File(System.getProperty("catalina.base"), directory);
+        dir.mkdirs();
+
+        // Open the current log file
+        try {
+            String pathname;
+
+            // If no rotate - no need for dateStamp in fileName
+            if (rotatable){
+                pathname = dir.getAbsolutePath() + File.separator +
+                            prefix + dateStamp + suffix;
+            } else {
+                pathname = dir.getAbsolutePath() + File.separator +
+                            prefix + suffix;
+            }
+
+            currentLogFile = new File(pathname);
+            writer = new PrintWriter(new FileWriter(pathname, true), true);
+            if (currentLogFile.length()==0) {
+                writer.println("#Fields: " + pattern);
+                writer.println("#Version: 1.0");
+                writer.println("#Software: " + ServerInfo.getServerInfo());
+            }
+
+
+        } catch (IOException e) {
+            writer = null;
+            currentLogFile = null;
+        }
+
+    }
+
+
+    /**
+     * 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.
+     */
+    private Date getDate(long systime) {
+        /* Avoid extra call to System.currentTimeMillis(); */
+        if (0==systime) {
+            systime = System.currentTimeMillis();
+        }
+
+        // Only create a new Date once per second, max.
+        if ((systime - currentDate.getTime()) > 1000) {
+            currentDate.setTime(systime);
+        }
+
+        return currentDate;
+
+    }
+
+
+    // ------------------------------------------------------ Lifecycle Methods
+
+
+    /**
+     * Add a lifecycle event listener to this component.
+     *
+     * @param listener The listener to add
+     */
+    public void addLifecycleListener(LifecycleListener listener) {
+
+        lifecycle.addLifecycleListener(listener);
+
+    }
+
+
+    /**
+     * Get the lifecycle listeners associated with this lifecycle. If this
+     * Lifecycle has no listeners registered, a zero-length array is returned.
+     */
+    public LifecycleListener[] findLifecycleListeners() {
+
+        return lifecycle.findLifecycleListeners();
+
+    }
+
+
+    /**
+     * Remove a lifecycle event listener from this component.
+     *
+     * @param listener The listener to add
+     */
+    public void removeLifecycleListener(LifecycleListener listener) {
+
+        lifecycle.removeLifecycleListener(listener);
+
+    }
+
+
+    /**
+     * Prepare for the beginning of active use of the public methods of this
+     * component.  This method should be called after <code>configure()</code>,
+     * and before any of the public methods of the component are utilized.
+     *
+     * @exception LifecycleException if this component detects a fatal error
+     *  that prevents this component from being used
+     */
+    public void start() throws LifecycleException {
+
+        // Validate and update our current component state
+        if (started)
+            throw new LifecycleException
+                (sm.getString("extendedAccessLogValve.alreadyStarted"));
+        lifecycle.fireLifecycleEvent(START_EVENT, null);
+        started = true;
+
+        // Initialize the timeZone, Date formatters, and currentDate
+        TimeZone tz = TimeZone.getTimeZone("GMT");
+        dateFormatter = new SimpleDateFormat("yyyy-MM-dd");
+        dateFormatter.setTimeZone(tz);
+        timeFormatter = new SimpleDateFormat("HH:mm:ss");
+        timeFormatter.setTimeZone(tz);
+        currentDate = new Date(System.currentTimeMillis());
+        if (fileDateFormat==null || fileDateFormat.length()==0)
+            fileDateFormat = "yyyy-MM-dd";
+        fileDateFormatter = new SimpleDateFormat(fileDateFormat);
+        dateStamp = fileDateFormatter.format(currentDate);
+        timeTakenFormatter = new DecimalFormat("0.000");
+
+        /* Everybody say ick ... ick */
+        try {
+            InetAddress inetAddress = InetAddress.getLocalHost();
+            myIpAddress = inetAddress.getHostAddress();
+            myDNSName = inetAddress.getHostName();
+        } catch(Throwable e){
+            myIpAddress="127.0.0.1";
+            myDNSName="localhost";
+        }
+
+        open();
+
+    }
+
+
+    /**
+     * Gracefully terminate the active use of the public methods of this
+     * component.  This method should be the last one called on a given
+     * instance of this component.
+     *
+     * @exception LifecycleException if this component detects a fatal error
+     *  that needs to be reported
+     */
+    public void stop() throws LifecycleException {
+
+        // Validate and update our current component state
+        if (!started)
+            throw new LifecycleException
+                (sm.getString("extendedAccessLogValve.notStarted"));
+        lifecycle.fireLifecycleEvent(STOP_EVENT, null);
+        started = false;
+
+        close();
+
+    }
+
+
+    /**
+     * Decode the given pattern. Is public so a pattern may
+     * allows to be validated.
+     * @param fields The pattern to decode
+     * @return null on error.  Otherwise array of decoded fields
+     */
+    public FieldInfo[] decodePattern(String fields) {
+
+        if (log.isDebugEnabled())
+            log.debug("decodePattern, fields=" + fields);
+
+        LinkedList list = new LinkedList();
+
+        //Ignore leading whitespace.
+        int i=0;
+        for (;i<fields.length() && Character.isWhitespace(fields.charAt(i));i++);
+
+        if (i>=fields.length()) {
+            log.info("fields was just empty or whitespace");
+            return null;
+        }
+
+        int j;
+        while(i<fields.length()) {
+            if (log.isDebugEnabled())
+                log.debug("fields.substring(i)=" + fields.substring(i));
+
+            FieldInfo currentFieldInfo = new FieldInfo();
+
+
+            if (fields.startsWith("date",i)) {
+                currentFieldInfo.type = FieldInfo.DATA_SPECIAL;
+                currentFieldInfo.location = FieldInfo.SPECIAL_DATE;
+                i+="date".length();
+            } else if (fields.startsWith("time-taken",i)) {
+                currentFieldInfo.type = FieldInfo.DATA_SPECIAL;
+                currentFieldInfo.location = FieldInfo.SPECIAL_TIME_TAKEN;
+                i+="time-taken".length();
+            } else if (fields.startsWith("time",i)) {
+                currentFieldInfo.type = FieldInfo.DATA_SPECIAL;
+                currentFieldInfo.location = FieldInfo.SPECIAL_TIME;
+                i+="time".length();
+            } else if (fields.startsWith("bytes",i)) {
+                currentFieldInfo.type = FieldInfo.DATA_SPECIAL;
+                currentFieldInfo.location = FieldInfo.SPECIAL_BYTES;
+                i+="bytes".length();
+            } else if (fields.startsWith("cached",i)) {
+                currentFieldInfo.type = FieldInfo.DATA_SPECIAL;
+                currentFieldInfo.location = FieldInfo.SPECIAL_CACHED;
+                i+="cached".length();
+            } else if (fields.startsWith("c-ip",i)) {
+                currentFieldInfo.type = FieldInfo.DATA_CLIENT;
+                currentFieldInfo.location = FieldInfo.FIELD_IP;
+                i+="c-ip".length();
+            } else if (fields.startsWith("c-dns",i)) {
+                currentFieldInfo.type = FieldInfo.DATA_CLIENT;
+                currentFieldInfo.location = FieldInfo.FIELD_DNS;
+                i+="c-dns".length();
+            } else if (fields.startsWith("s-ip",i)) {
+                currentFieldInfo.type = FieldInfo.DATA_SERVER;
+                currentFieldInfo.location = FieldInfo.FIELD_IP;
+                i+="s-ip".length();
+            } else if (fields.startsWith("s-dns",i)) {
+                currentFieldInfo.type = FieldInfo.DATA_SERVER;
+                currentFieldInfo.location = FieldInfo.FIELD_DNS;
+                i+="s-dns".length();
+            } else if (fields.startsWith("cs",i)) {
+                i = decode(fields, i+2, currentFieldInfo,
+                            FieldInfo.DATA_CLIENT_TO_SERVER);
+                if (i<0)
+                    return null;
+            } else if (fields.startsWith("sc",i)) {
+                i = decode(fields, i+2, currentFieldInfo,
+                            FieldInfo.DATA_SERVER_TO_CLIENT);
+                if (i<0)
+                    return null;
+            } else if (fields.startsWith("sr",i)) {
+                i = decode(fields, i+2, currentFieldInfo,
+                            FieldInfo.DATA_SERVER_TO_RSERVER);
+                if (i<0)
+                    return null;
+            } else if (fields.startsWith("rs",i)) {
+                i = decode(fields, i+2, currentFieldInfo,
+                            FieldInfo.DATA_RSERVER_TO_SERVER);
+                if (i<0)
+                    return null;
+            } else if (fields.startsWith("x",i)) {
+                i = decodeAppSpecific(fields, i, currentFieldInfo);
+            } else {
+                // Unable to decode ...
+                log.error("unable to decode with rest of chars being: " +
+                            fields.substring(i));
+                return null;
+            }
+
+            // By this point we should have the field, get the whitespace
+            j=i;
+            for (;j<fields.length() && Character.isWhitespace(fields.charAt(j));j++);
+
+            if (j>=fields.length()) {
+                if (j==i) {
+                    // Special case - end of string
+                    currentFieldInfo.postWhiteSpace = "";
+                } else {
+                    currentFieldInfo.postWhiteSpace = fields.substring(i);
+                    i=j;
+                }
+            } else {
+                currentFieldInfo.postWhiteSpace = fields.substring(i,j);
+                i=j;
+            }
+
+            list.add(currentFieldInfo);
+        }
+
+        i=0;
+        FieldInfo[] f = new FieldInfo[list.size()];
+        for (Iterator k = list.iterator(); k.hasNext();)
+             f[i++] = (FieldInfo)k.next();
+
+        if (log.isDebugEnabled())
+            log.debug("finished decoding with length of: " + i);
+
+        return f;
+    }
+
+    /**
+     * Decode the cs or sc fields.
+     * Returns negative on error.
+     *
+     * @param fields The pattern to decode
+     * @param i The string index where we are decoding.
+     * @param fieldInfo Where to store the results
+     * @param type The type we are decoding.
+     * @return -1 on error. Otherwise the new String index.
+     */
+    private int decode(String fields, int i, FieldInfo fieldInfo, short type) {
+
+        if (fields.startsWith("-status",i)) {
+            fieldInfo.location = FieldInfo.FIELD_STATUS;
+            i+="-status".length();
+        } else if (fields.startsWith("-comment",i)) {
+            fieldInfo.location = FieldInfo.FIELD_COMMENT;
+            i+="-comment".length();
+        } else if (fields.startsWith("-uri-query",i)) {
+            fieldInfo.location = FieldInfo.FIELD_URI_QUERY;
+            i+="-uri-query".length();
+        } else if (fields.startsWith("-uri-stem",i)) {
+            fieldInfo.location = FieldInfo.FIELD_URI_STEM;
+            i+="-uri-stem".length();
+        } else if (fields.startsWith("-uri",i)) {
+            fieldInfo.location = FieldInfo.FIELD_URI;
+            i+="-uri".length();
+        } else if (fields.startsWith("-method",i)) {
+            fieldInfo.location = FieldInfo.FIELD_METHOD;
+            i+="-method".length();
+        } else if (fields.startsWith("(",i)) {
+            fieldInfo.location = FieldInfo.FIELD_HEADER;
+            i++;                                  /* Move past the ( */
+            int j = fields.indexOf(')', i);
+            if (j==-1) {                          /* Not found */
+                log.error("No closing ) found for in decode");
+                return -1;
+            }
+            fieldInfo.value = fields.substring(i,j);
+            i=j+1;                                // Move pointer past ) */
+        } else {
+            log.error("The next characters couldn't be decoded: " + fields.substring(i));
+            return -1;
+        }
+
+        fieldInfo.type = type;
+        return i;
+
+    }
+
+
+    /**
+      * Decode app specific log entry.
+      *
+      * Special fields are of the form:
+      * x-C(...) - For cookie
+      * x-A(...) - Value in servletContext
+      * x-S(...) - Value in session
+      * x-R(...) - Value in servletRequest
+      * @param fields The pattern to decode
+      * @param i The string index where we are decoding.
+      * @param fieldInfo Where to store the results
+      * @return -1 on error. Otherwise the new String index.
+      */
+    private int decodeAppSpecific(String fields, int i, FieldInfo fieldInfo) {
+
+        fieldInfo.type = FieldInfo.DATA_APP_SPECIFIC;
+        /* Move past 'x-' */
+        i+=2;
+
+        if (i>=fields.length()) {
+            log.error("End of line reached before decoding x- param");
+            return -1;
+        }
+
+        switch(fields.charAt(i)) {
+            case 'A':
+                fieldInfo.xType = FieldInfo.X_APP;
+                break;
+            case 'C':
+                fieldInfo.xType = FieldInfo.X_COOKIE;
+                break;
+            case 'R':
+                fieldInfo.xType = FieldInfo.X_REQUEST;
+                break;
+            case 'S':
+                fieldInfo.xType = FieldInfo.X_SESSION;
+                break;
+            case 'H':
+                fieldInfo.xType = FieldInfo.X_SERVLET_REQUEST;
+                break;
+            case 'P':
+                fieldInfo.xType = FieldInfo.X_PARAMETER;
+                break;
+            default:
+                return -1;
+        }
+
+        /* test that next char is a ( */
+        if (i+1!=fields.indexOf('(',i)) {
+            log.error("x param in wrong format. Needs to be 'x-#(...)' read the docs!");
+            return -1;
+        }
+        i+=2; /* Move inside of the () */
+
+        /* Look for ending ) and return error if not found. */
+        int j = fields.indexOf(')',i);
+        if (j==-1) {
+            log.error("x param in wrong format. No closing ')'!");
+            return -1;
+        }
+
+        fieldInfo.value = fields.substring(i,j);
+
+        if (fieldInfo.xType == FieldInfo.X_SERVLET_REQUEST) {
+            if ("authType".equals(fieldInfo.value)){
+                fieldInfo.location = FieldInfo.X_LOC_AUTHTYPE;
+            } else if ("remoteUser".equals(fieldInfo.value)){
+                fieldInfo.location = FieldInfo.X_LOC_REMOTEUSER;
+            } else if ("requestedSessionId".equals(fieldInfo.value)){
+                fieldInfo.location = FieldInfo.X_LOC_REQUESTEDSESSIONID;
+            } else if ("requestedSessionIdFromCookie".equals(fieldInfo.value)){
+                fieldInfo.location = FieldInfo.X_LOC_REQUESTEDSESSIONIDFROMCOOKIE;
+            } else if ("requestedSessionIdValid".equals(fieldInfo.value)){
+                fieldInfo.location = FieldInfo.X_LOC_REQUESTEDSESSIONIDVALID;
+            } else if ("contentLength".equals(fieldInfo.value)){
+                fieldInfo.location = FieldInfo.X_LOC_CONTENTLENGTH;
+            } else if ("characterEncoding".equals(fieldInfo.value)){
+                fieldInfo.location = FieldInfo.X_LOC_CHARACTERENCODING;
+            } else if ("locale".equals(fieldInfo.value)){
+                fieldInfo.location = FieldInfo.X_LOC_LOCALE;
+            } else if ("protocol".equals(fieldInfo.value)){
+                fieldInfo.location = FieldInfo.X_LOC_PROTOCOL;
+            } else if ("scheme".equals(fieldInfo.value)){
+                fieldInfo.location = FieldInfo.X_LOC_SCHEME;
+            } else if ("secure".equals(fieldInfo.value)){
+                fieldInfo.location = FieldInfo.X_LOC_SECURE;
+            } else {
+                log.error("x param for servlet request, couldn't decode value: " +
+                            fieldInfo.location);
+                return -1;
+            }
+        }
+
+        return j+1;
+
+    }
+
+
+}
+
+/**
+ * A simple helper for decoding the pattern.
+ */
+class FieldInfo {
+    /*
+       The goal of the constants listed below is to make the construction of the log
+       entry as quick as possible via numerci decodings of the methods to call instead
+       of performing many String comparisons on each logging request.
+    */
+
+    /* Where the data is located. */
+    static final short DATA_CLIENT = 0;
+    static final short DATA_SERVER = 1;
+    static final short DATA_REMOTE = 2;
+    static final short DATA_CLIENT_TO_SERVER = 3;
+    static final short DATA_SERVER_TO_CLIENT = 4;
+    static final short DATA_SERVER_TO_RSERVER = 5; /* Here to honor the spec. */
+    static final short DATA_RSERVER_TO_SERVER = 6; /* Here to honor the spec. */
+    static final short DATA_APP_SPECIFIC = 7;
+    static final short DATA_SPECIAL = 8;
+
+    /* The type of special fields. */
+    static final short SPECIAL_DATE         = 1;
+    static final short SPECIAL_TIME_TAKEN   = 2;
+    static final short SPECIAL_TIME         = 3;
+    static final short SPECIAL_BYTES        = 4;
+    static final short SPECIAL_CACHED       = 5;
+
+    /* Where to pull the data for prefixed values */
+    static final short FIELD_IP            = 1;
+    static final short FIELD_DNS           = 2;
+    static final short FIELD_STATUS        = 3;
+    static final short FIELD_COMMENT       = 4;
+    static final short FIELD_METHOD        = 5;
+    static final short FIELD_URI           = 6;
+    static final short FIELD_URI_STEM      = 7;
+    static final short FIELD_URI_QUERY     = 8;
+    static final short FIELD_HEADER        = 9;
+
+
+    /* Application Specific parameters */
+    static final short X_REQUEST = 1; /* For x app specific */
+    static final short X_SESSION = 2; /* For x app specific */
+    static final short X_COOKIE  = 3; /* For x app specific */
+    static final short X_APP     = 4; /* For x app specific */
+    static final short X_SERVLET_REQUEST = 5; /* For x app specific */
+    static final short X_PARAMETER = 6; /* For x app specific */
+
+    static final short X_LOC_AUTHTYPE                       = 1;
+    static final short X_LOC_REMOTEUSER                     = 2;
+    static final short X_LOC_REQUESTEDSESSIONID             = 3;
+    static final short X_LOC_REQUESTEDSESSIONIDFROMCOOKIE   = 4;
+    static final short X_LOC_REQUESTEDSESSIONIDVALID        = 5;
+    static final short X_LOC_CONTENTLENGTH                  = 6;
+    static final short X_LOC_CHARACTERENCODING              = 7;
+    static final short X_LOC_LOCALE                         = 8;
+    static final short X_LOC_PROTOCOL                       = 9;
+    static final short X_LOC_SCHEME                         = 10;
+    static final short X_LOC_SECURE                         = 11;
+
+
+
+    /** The field type */
+    short type;
+
+    /** Where to pull the data from? Icky variable name. */
+    short location;
+
+    /** The x- specific place to pull the data from. */
+    short xType;
+
+    /** The field value if needed. Needed for headers and app specific. */
+    String value;
+
+    /** Any white space after this field? Put it here. */
+    String postWhiteSpace = null;
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/valves/FastCommonAccessLogValve.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/valves/FastCommonAccessLogValve.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/valves/FastCommonAccessLogValve.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,855 @@
+/*
+ * Copyright 1999-2005 The Apache Software Foundation.
+ * 
+ * Licensed 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.io.BufferedWriter;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.TimeZone;
+
+import javax.servlet.ServletException;
+
+import org.apache.catalina.Lifecycle;
+import org.apache.catalina.LifecycleException;
+import org.apache.catalina.LifecycleListener;
+import org.apache.catalina.connector.Request;
+import org.apache.catalina.connector.Response;
+import org.apache.catalina.util.LifecycleSupport;
+import org.apache.catalina.util.StringManager;
+
+
+/**
+ * <p>Implementation of the <b>Valve</b> interface that generates a web server
+ * access log with the detailed line contents matching either the common or
+ * combined patterns.  As an additional feature, automatic rollover of log files
+ * when the date changes is also supported.</p>
+ * <p>
+ * Conditional logging is also supported. This can be done with the
+ * <code>condition</code> property.
+ * If the value returned from ServletRequest.getAttribute(condition)
+ * yields a non-null value. The logging will be skipped.
+ * </p>
+ *
+ * @author Craig R. McClanahan
+ * @author Jason Brittain
+ * @author Remy Maucherat
+ * @version $Revision: 304032 $ $Date: 2005-07-27 10:11:55 -0500 (Wed, 27 Jul 2005) $
+ */
+
+public final class FastCommonAccessLogValve
+    extends ValveBase
+    implements Lifecycle {
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Construct a new instance of this class with default property values.
+     */
+    public FastCommonAccessLogValve() {
+
+        super();
+        setPattern("common");
+
+
+    }
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The as-of date for the currently open log file, or a zero-length
+     * string if there is no open log file.
+     */
+    private String dateStamp = "";
+
+
+    /**
+     * The directory in which log files are created.
+     */
+    private String directory = "logs";
+
+
+    /**
+     * The descriptive information about this implementation.
+     */
+    protected static final String info =
+        "org.apache.catalina.valves.FastCommonAccessLogValve/1.0";
+
+
+    /**
+     * The lifecycle event support for this component.
+     */
+    protected LifecycleSupport lifecycle = new LifecycleSupport(this);
+
+
+    /**
+     * The set of month abbreviations for log messages.
+     */
+    protected static final String months[] =
+    { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+      "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
+
+
+    /**
+     * If the current log pattern is the same as the common access log
+     * format pattern, then we'll set this variable to true and log in
+     * a more optimal and hard-coded way.
+     */
+    private boolean common = false;
+
+
+    /**
+     * For the combined format (common, plus useragent and referer), we do
+     * the same
+     */
+    private boolean combined = false;
+
+
+    /**
+     * The pattern used to format our access log lines.
+     */
+    private String pattern = null;
+
+
+    /**
+     * The prefix that is added to log file filenames.
+     */
+    private String prefix = "access_log.";
+
+
+    /**
+     * Should we rotate our log file? Default is true (like old behavior)
+     */
+    private boolean rotatable = true;
+
+
+    /**
+     * The string manager for this package.
+     */
+    private StringManager sm =
+        StringManager.getManager(Constants.Package);
+
+
+    /**
+     * Has this component been started yet?
+     */
+    private boolean started = false;
+
+
+    /**
+     * The suffix that is added to log file filenames.
+     */
+    private String suffix = "";
+
+
+    /**
+     * The PrintWriter to which we are currently logging, if any.
+     */
+    private PrintWriter writer = null;
+
+
+    /**
+     * A date formatter to format a Date into a date in the format
+     * "yyyy-MM-dd".
+     */
+    private SimpleDateFormat dateFormatter = null;
+
+
+    /**
+     * A date formatter to format Dates into a day string in the format
+     * "dd".
+     */
+    private SimpleDateFormat dayFormatter = null;
+
+
+    /**
+     * A date formatter to format a Date into a month string in the format
+     * "MM".
+     */
+    private SimpleDateFormat monthFormatter = null;
+
+
+    /**
+     * A date formatter to format a Date into a year string in the format
+     * "yyyy".
+     */
+    private SimpleDateFormat yearFormatter = null;
+
+
+    /**
+     * A date formatter to format a Date into a time in the format
+     * "kk:mm:ss" (kk is a 24-hour representation of the hour).
+     */
+    private SimpleDateFormat timeFormatter = null;
+
+
+    /**
+     * The system timezone.
+     */
+    private TimeZone timezone = null;
+
+    
+    /**
+     * The time zone offset relative to GMT in text form when daylight saving
+     * is not in operation.
+     */
+    private String timeZoneNoDST = null;
+ 
+    /**
+     * The time zone offset relative to GMT in text form when daylight saving
+     * is in operation.
+     */
+    private String timeZoneDST = null;
+
+
+    /**
+     * The system time when we last updated the Date that this valve
+     * uses for log lines.
+     */
+    private String currentDateString = null;
+    
+    
+    /**
+     * The instant where the date string was last updated.
+     */
+    private long currentDate = 0L;
+
+
+    /**
+     * When formatting log lines, we often use strings like this one (" ").
+     */
+    private String space = " ";
+
+
+    /**
+     * Resolve hosts.
+     */
+    private boolean resolveHosts = false;
+
+
+    /**
+     * Instant when the log daily rotation was last checked.
+     */
+    private long rotationLastChecked = 0L;
+
+
+    /**
+     * Are we doing conditional logging. default false.
+     */
+    private String condition = null;
+
+
+    /**
+     * Date format to place in log file name. Use at your own risk!
+     */
+    private String fileDateFormat = null;
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * Return the directory in which we create log files.
+     */
+    public String getDirectory() {
+
+        return (directory);
+
+    }
+
+
+    /**
+     * Set the directory in which we create log files.
+     *
+     * @param directory The new log file directory
+     */
+    public void setDirectory(String directory) {
+
+        this.directory = directory;
+
+    }
+
+
+    /**
+     * Return descriptive information about this implementation.
+     */
+    public String getInfo() {
+
+        return (info);
+
+    }
+
+
+    /**
+     * Return the format pattern.
+     */
+    public String getPattern() {
+
+        return (this.pattern);
+
+    }
+
+
+    /**
+     * Set the format pattern, first translating any recognized alias.
+     *
+     * @param pattern The new pattern
+     */
+    public void setPattern(String pattern) {
+
+        if (pattern == null)
+            pattern = "";
+        if (pattern.equals(Constants.AccessLog.COMMON_ALIAS))
+            pattern = Constants.AccessLog.COMMON_PATTERN;
+        if (pattern.equals(Constants.AccessLog.COMBINED_ALIAS))
+            pattern = Constants.AccessLog.COMBINED_PATTERN;
+        this.pattern = pattern;
+
+        if (this.pattern.equals(Constants.AccessLog.COMBINED_PATTERN))
+            combined = true;
+        else
+            combined = false;
+
+    }
+
+
+    /**
+     * Return the log file prefix.
+     */
+    public String getPrefix() {
+
+        return (prefix);
+
+    }
+
+
+    /**
+     * Set the log file prefix.
+     *
+     * @param prefix The new log file prefix
+     */
+    public void setPrefix(String prefix) {
+
+        this.prefix = prefix;
+
+    }
+
+
+    /**
+     * Should we rotate the logs
+     */
+    public boolean isRotatable() {
+
+        return rotatable;
+
+    }
+
+
+    /**
+     * Set the value is we should we rotate the logs
+     *
+     * @param rotatable true is we should rotate.
+     */
+    public void setRotatable(boolean rotatable) {
+
+        this.rotatable = rotatable;
+
+    }
+
+
+    /**
+     * Return the log file suffix.
+     */
+    public String getSuffix() {
+
+        return (suffix);
+
+    }
+
+
+    /**
+     * Set the log file suffix.
+     *
+     * @param suffix The new log file suffix
+     */
+    public void setSuffix(String suffix) {
+
+        this.suffix = suffix;
+
+    }
+
+
+    /**
+     * Set the resolve hosts flag.
+     *
+     * @param resolveHosts The new resolve hosts value
+     */
+    public void setResolveHosts(boolean resolveHosts) {
+
+        this.resolveHosts = resolveHosts;
+
+    }
+
+
+    /**
+     * Get the value of the resolve hosts flag.
+     */
+    public boolean isResolveHosts() {
+
+        return resolveHosts;
+
+    }
+
+
+    /**
+     * Return whether the attribute name to look for when
+     * performing conditional loggging. If null, every
+     * request is logged.
+     */
+    public String getCondition() {
+
+        return condition;
+
+    }
+
+
+    /**
+     * Set the ServletRequest.attribute to look for to perform
+     * conditional logging. Set to null to log everything.
+     *
+     * @param condition Set to null to log everything
+     */
+    public void setCondition(String condition) {
+
+        this.condition = condition;
+
+    }
+
+    /**
+     *  Return the date format date based log rotation.
+     */
+    public String getFileDateFormat() {
+        return fileDateFormat;
+    }
+
+
+    /**
+     *  Set the date format date based log rotation.
+     */
+    public void setFileDateFormat(String fileDateFormat) {
+        this.fileDateFormat =  fileDateFormat;
+    }
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Execute a periodic task, such as reloading, etc. This method will be
+     * invoked inside the classloading context of this container. Unexpected
+     * throwables will be caught and logged.
+     */
+    public void backgroundProcess() {
+        if (writer != null)
+            writer.flush();
+    }
+
+
+    /**
+     * Log a message summarizing the specified request and response, according
+     * to the format specified by the <code>pattern</code> property.
+     *
+     * @param request Request being processed
+     * @param response Response being processed
+     *
+     * @exception IOException if an input/output error has occurred
+     * @exception ServletException if a servlet error has occurred
+     */
+    public void invoke(Request request, Response response)
+        throws IOException, ServletException {
+
+        // Pass this request on to the next valve in our pipeline
+        getNext().invoke(request, response);
+
+        if (condition!=null &&
+                null!=request.getRequest().getAttribute(condition)) {
+            return;
+        }
+
+        StringBuffer result = new StringBuffer();
+
+        // Check to see if we should log using the "common" access log pattern
+        String value = null;
+        
+        if (isResolveHosts())
+            result.append(request.getRemoteHost());
+        else
+            result.append(request.getRemoteAddr());
+        
+        result.append(" - ");
+        
+        value = request.getRemoteUser();
+        if (value == null)
+            result.append("- ");
+        else {
+            result.append(value);
+            result.append(space);
+        }
+        
+        result.append(getCurrentDateString());
+        
+        result.append(request.getMethod());
+        result.append(space);
+        result.append(request.getRequestURI());
+        if (request.getQueryString() != null) {
+            result.append('?');
+            result.append(request.getQueryString());
+        }
+        result.append(space);
+        result.append(request.getProtocol());
+        result.append("\" ");
+        
+        result.append(response.getStatus());
+        
+        result.append(space);
+        
+        int length = response.getContentCount();
+        
+        if (length <= 0)
+            value = "-";
+        else
+            value = "" + length;
+        result.append(value);
+        
+        if (combined) {
+            result.append(space);
+            result.append("\"");
+            String referer = request.getHeader("referer");
+            if(referer != null)
+                result.append(referer);
+            else
+                result.append("-");
+            result.append("\"");
+            
+            result.append(space);
+            result.append("\"");
+            String ua = request.getHeader("user-agent");
+            if(ua != null)
+                result.append(ua);
+            else
+                result.append("-");
+            result.append("\"");
+        }
+        
+        log(result.toString());
+        
+    }
+
+
+    // -------------------------------------------------------- Private Methods
+
+
+    /**
+     * Close the currently open log file (if any)
+     */
+    private synchronized void close() {
+
+        if (writer == null)
+            return;
+        writer.flush();
+        writer.close();
+        writer = null;
+        dateStamp = "";
+
+    }
+
+
+    /**
+     * Log the specified message to the log file, switching files if the date
+     * has changed since the previous log call.
+     *
+     * @param message Message to be logged
+     */
+    public void log(String message) {
+
+        // Log this message
+        if (writer != null) {
+            writer.println(message);
+        }
+
+    }
+
+
+    /**
+     * Return the month abbreviation for the specified month, which must
+     * be a two-digit String.
+     *
+     * @param month Month number ("01" .. "12").
+     */
+    private String lookup(String month) {
+
+        int index;
+        try {
+            index = Integer.parseInt(month) - 1;
+        } catch (Throwable t) {
+            index = 0;  // Can not happen, in theory
+        }
+        return (months[index]);
+
+    }
+
+
+    /**
+     * Open the new log file for the date specified by <code>dateStamp</code>.
+     */
+    private synchronized void open() {
+
+        // Create the directory if necessary
+        File dir = new File(directory);
+        if (!dir.isAbsolute())
+            dir = new File(System.getProperty("catalina.base"), directory);
+        dir.mkdirs();
+
+        // Open the current log file
+        try {
+            String pathname;
+            // If no rotate - no need for dateStamp in fileName
+            if (rotatable){
+                pathname = dir.getAbsolutePath() + File.separator +
+                            prefix + dateStamp + suffix;
+            } else {
+                pathname = dir.getAbsolutePath() + File.separator +
+                            prefix + suffix;
+            }
+            writer = new PrintWriter(new BufferedWriter
+                    (new FileWriter(pathname, true), 128000), false);
+        } catch (IOException e) {
+            writer = null;
+        }
+
+    }
+
+
+    /**
+     * 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.
+     *
+     * @return Date
+     */
+    private String getCurrentDateString() {
+        // Only create a new Date once per second, max.
+        long systime = System.currentTimeMillis();
+        if ((systime - currentDate) > 1000) {
+            synchronized (this) {
+                // We don't care about being exact here: if an entry does get
+                // logged as having happened during the previous second
+                // it will not make any difference
+                if ((systime - currentDate) > 1000) {
+
+                    // Format the new date
+                    Date date = new Date();
+                    StringBuffer result = new StringBuffer(32);
+                    result.append("[");
+                    // Day
+                    result.append(dayFormatter.format(date));
+                    result.append('/');
+                    // Month
+                    result.append(lookup(monthFormatter.format(date)));
+                    result.append('/');
+                    // Year
+                    result.append(yearFormatter.format(date));
+                    result.append(':');
+                    // Time
+                    result.append(timeFormatter.format(date));
+                    result.append(space);
+                    // Time zone
+                    result.append(getTimeZone(date));
+                    result.append("] \"");
+                    
+                    // Check for log rotation
+                    if (rotatable) {
+                        // Check for a change of date
+                        String tsDate = dateFormatter.format(date);
+                        // If the date has changed, switch log files
+                        if (!dateStamp.equals(tsDate)) {
+                            synchronized (this) {
+                                if (!dateStamp.equals(tsDate)) {
+                                    close();
+                                    dateStamp = tsDate;
+                                    open();
+                                }
+                            }
+                        }
+                    }
+                    
+                    currentDateString = result.toString();
+                    currentDate = date.getTime();
+                }
+            }
+        }
+        return currentDateString;
+    }
+
+
+    private String getTimeZone(Date date) {
+        if (timezone.inDaylightTime(date)) {
+            return timeZoneDST;
+        } else {
+            return timeZoneNoDST;
+        }
+    }
+    
+    
+    private String calculateTimeZoneOffset(long offset) {
+        StringBuffer tz = new StringBuffer();
+        if ((offset<0))  {
+            tz.append("-");
+            offset = -offset;
+        } else {
+            tz.append("+");
+        }
+
+        long hourOffset = offset/(1000*60*60);
+        long minuteOffset = (offset/(1000*60)) % 60;
+
+        if (hourOffset<10)
+            tz.append("0");
+        tz.append(hourOffset);
+
+        if (minuteOffset<10)
+            tz.append("0");
+        tz.append(minuteOffset);
+
+        return tz.toString();
+    }
+
+
+    // ------------------------------------------------------ Lifecycle Methods
+
+
+    /**
+     * Add a lifecycle event listener to this component.
+     *
+     * @param listener The listener to add
+     */
+    public void addLifecycleListener(LifecycleListener listener) {
+
+        lifecycle.addLifecycleListener(listener);
+
+    }
+
+
+    /**
+     * Get the lifecycle listeners associated with this lifecycle. If this
+     * Lifecycle has no listeners registered, a zero-length array is returned.
+     */
+    public LifecycleListener[] findLifecycleListeners() {
+
+        return lifecycle.findLifecycleListeners();
+
+    }
+
+
+    /**
+     * Remove a lifecycle event listener from this component.
+     *
+     * @param listener The listener to add
+     */
+    public void removeLifecycleListener(LifecycleListener listener) {
+
+        lifecycle.removeLifecycleListener(listener);
+
+    }
+
+
+    /**
+     * Prepare for the beginning of active use of the public methods of this
+     * component.  This method should be called after <code>configure()</code>,
+     * and before any of the public methods of the component are utilized.
+     *
+     * @exception LifecycleException if this component detects a fatal error
+     *  that prevents this component from being used
+     */
+    public void start() throws LifecycleException {
+
+        // Validate and update our current component state
+        if (started)
+            throw new LifecycleException
+                (sm.getString("accessLogValve.alreadyStarted"));
+        lifecycle.fireLifecycleEvent(START_EVENT, null);
+        started = true;
+
+        // Initialize the timeZone, Date formatters, and currentDate
+        timezone = TimeZone.getDefault();
+        timeZoneNoDST = calculateTimeZoneOffset(timezone.getRawOffset());
+        Calendar calendar = Calendar.getInstance(timezone);
+        int offset = calendar.get(Calendar.DST_OFFSET);
+        timeZoneDST = calculateTimeZoneOffset(timezone.getRawOffset()+offset);
+        
+        if (fileDateFormat==null || fileDateFormat.length()==0)
+            fileDateFormat = "yyyy-MM-dd";
+        dateFormatter = new SimpleDateFormat(fileDateFormat);
+        dateFormatter.setTimeZone(timezone);
+        dayFormatter = new SimpleDateFormat("dd");
+        dayFormatter.setTimeZone(timezone);
+        monthFormatter = new SimpleDateFormat("MM");
+        monthFormatter.setTimeZone(timezone);
+        yearFormatter = new SimpleDateFormat("yyyy");
+        yearFormatter.setTimeZone(timezone);
+        timeFormatter = new SimpleDateFormat("HH:mm:ss");
+        timeFormatter.setTimeZone(timezone);
+        currentDateString = getCurrentDateString();
+        dateStamp = dateFormatter.format(new Date());
+
+        open();
+
+    }
+
+
+    /**
+     * Gracefully terminate the active use of the public methods of this
+     * component.  This method should be the last one called on a given
+     * instance of this component.
+     *
+     * @exception LifecycleException if this component detects a fatal error
+     *  that needs to be reported
+     */
+    public void stop() throws LifecycleException {
+
+        // Validate and update our current component state
+        if (!started)
+            throw new LifecycleException
+                (sm.getString("accessLogValve.notStarted"));
+        lifecycle.fireLifecycleEvent(STOP_EVENT, null);
+        started = false;
+
+        close();
+
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/valves/JDBCAccessLogValve.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/valves/JDBCAccessLogValve.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/valves/JDBCAccessLogValve.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,681 @@
+/*
+ * Copyright 1999-2001,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.io.IOException;
+import java.sql.Connection;
+import java.sql.Driver;
+import java.sql.PreparedStatement;
+import java.sql.SQLException;
+import java.sql.Timestamp;
+import java.util.Properties;
+
+import javax.servlet.ServletException;
+
+import org.apache.catalina.Lifecycle;
+import org.apache.catalina.LifecycleException;
+import org.apache.catalina.LifecycleListener;
+import org.apache.catalina.connector.Request;
+import org.apache.catalina.connector.Response;
+import org.apache.catalina.util.LifecycleSupport;
+import org.apache.catalina.util.StringManager;
+
+/**
+ * <p>
+ * This Tomcat extension logs server access directly to a database, and can 
+ * be used instead of the regular file-based access log implemented in 
+ * AccessLogValve.
+ * To use, copy into the server/classes directory of the Tomcat installation
+ * and configure in server.xml as:
+ * <pre>
+ * 		&lt;Valve className="JDBCAccessLogValve"
+ *        	driverName="<i>your_jdbc_driver</i>"
+ *        	connectionURL="<i>your_jdbc_url</i>"
+ *        	pattern="combined" resolveHosts="false"
+ * 		/&gt;
+ * </pre>
+ * </p>
+ * <p>
+ * Many parameters can be configured, such as the database connection (with
+ * <code>driverName</code> and <code>connectionURL</code>),
+ * the table name (<code>tableName</code>)
+ * and the field names (corresponding to the get/set method names).
+ * The same options as AccessLogValve are supported, such as
+ * <code>resolveHosts</code> and <code>pattern</code> ("common" or "combined" 
+ * only).
+ * </p>
+ * <p>
+ * When Tomcat is started, a database connection (with autoReconnect option)
+ * is created and used for all the log activity. When Tomcat is shutdown, the
+ * database connection is closed.
+ * This logger can be used at the level of the Engine context (being shared
+ * by all the defined hosts) or the Host context (one instance of the logger 
+ * per host, possibly using different databases).
+ * </p>
+ * <p>
+ * The database table can be created with the following command:
+ * </p>
+ * <pre>
+ * CREATE TABLE access (
+ * id INT UNSIGNED AUTO_INCREMENT NOT NULL,
+ * ts TIMESTAMP NOT NULL,
+ * remoteHost CHAR(15) NOT NULL,
+ * userName CHAR(15),
+ * timestamp TIMESTAMP NOT NULL,
+ * virtualHost VARCHAR(64) NOT NULL,
+ * method VARCHAR(8) NOT NULL,
+ * query VARCHAR(255) NOT NULL,
+ * status SMALLINT UNSIGNED NOT NULL,
+ * bytes INT UNSIGNED NOT NULL,
+ * referer VARCHAR(128),
+ * userAgent VARCHAR(128),
+ * PRIMARY KEY (id),
+ * INDEX (ts),
+ * INDEX (remoteHost),
+ * INDEX (virtualHost),
+ * INDEX (query),
+ * INDEX (userAgent)
+ * );
+ * </pre>
+ * <p>
+ * If the table is created as above, its name and the field names don't need 
+ * to be defined.
+ * </p>
+ * <p>
+ * If the request method is "common", only these fields are used:
+ * <code>remoteHost, user, timeStamp, query, status, bytes</code>
+ * </p>
+ * <p>
+ * <i>TO DO: provide option for excluding logging of certain MIME types.</i>
+ * </p>
+ * 
+ * @author Andre de Jesus
+ * @author Peter Rossbach
+ */
+
+public final class JDBCAccessLogValve 
+    extends ValveBase 
+    implements Lifecycle {
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Class constructor. Initializes the fields with the default values.
+     * The defaults are:
+     * <pre>
+     * 		driverName = null;
+     * 		connectionURL = null;
+     * 		tableName = "access";
+     * 		remoteHostField = "remoteHost";
+     * 		userField = "userName";
+     * 		timestampField = "timestamp";
+     * 		virtualHostField = "virtualHost";
+     * 		methodField = "method";
+     * 		queryField = "query";
+     * 		statusField = "status";
+     * 		bytesField = "bytes";
+     * 		refererField = "referer";
+     * 		userAgentField = "userAgent";
+     * 		pattern = "common";
+     * 		resolveHosts = false;
+     * </pre>
+     */
+    public JDBCAccessLogValve() {
+        super();
+        driverName = null;
+        connectionURL = null;
+        tableName = "access";
+        remoteHostField = "remoteHost";
+        userField = "userName";
+        timestampField = "timestamp";
+        virtualHostField = "virtualHost";
+        methodField = "method";
+        queryField = "query";
+        statusField = "status";
+        bytesField = "bytes";
+        refererField = "referer";
+        userAgentField = "userAgent";
+        pattern = "common";
+        resolveHosts = false;
+        conn = null;
+        ps = null;
+        currentTimeMillis = new java.util.Date().getTime();
+    }
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+   /**
+     * The connection username to use when trying to connect to the database.
+     */
+    protected String connectionName = null;
+
+
+    /**
+     * The connection URL to use when trying to connect to the database.
+     */
+    protected String connectionPassword = null;
+
+   /**
+     * Instance of the JDBC Driver class we use as a connection factory.
+     */
+    protected Driver driver = null;
+
+
+    private String driverName;
+    private String connectionURL;
+    private String tableName;
+    private String remoteHostField;
+    private String userField;
+    private String timestampField;
+    private String virtualHostField;
+    private String methodField;
+    private String queryField;
+    private String statusField;
+    private String bytesField;
+    private String refererField;
+    private String userAgentField;
+    private String pattern;
+    private boolean resolveHosts;
+
+
+    private Connection conn;
+    private PreparedStatement ps;
+
+
+    private long currentTimeMillis;
+
+
+    /**
+     * The descriptive information about this implementation.
+     */
+    protected static String info = 
+        "org.apache.catalina.valves.JDBCAccessLogValve/1.1";
+
+
+    /**
+     * The lifecycle event support for this component.
+     */
+    protected LifecycleSupport lifecycle = new LifecycleSupport(this);
+
+
+    /**
+     * The string manager for this package.
+     */
+    private StringManager sm = StringManager.getManager(Constants.Package);
+
+
+    /**
+     * Has this component been started yet?
+     */
+    private boolean started = false;
+
+
+    // ------------------------------------------------------------- Properties
+ 
+    /**
+     * Return the username to use to connect to the database.
+     *
+     */
+    public String getConnectionName() {
+        return connectionName;
+    }
+
+    /**
+     * Set the username to use to connect to the database.
+     *
+     * @param connectionName Username
+     */
+    public void setConnectionName(String connectionName) {
+        this.connectionName = connectionName;
+    }
+
+    /**
+     * Sets the database driver name.
+     * 
+     * @param driverName The complete name of the database driver class.
+     */
+    public void setDriverName(String driverName) {
+        this.driverName = driverName;
+    }
+
+   /**
+     * Return the password to use to connect to the database.
+     *
+     */
+    public String getConnectionPassword() {
+        return connectionPassword;
+    }
+
+    /**
+     * Set the password to use to connect to the database.
+     *
+     * @param connectionPassword User password
+     */
+    public void setConnectionPassword(String connectionPassword) {
+        this.connectionPassword = connectionPassword;
+    }
+
+    /**
+     * Sets the JDBC URL for the database where the log is stored.
+     * 
+     * @param connectionURL The JDBC URL of the database.
+     */
+    public void setConnectionURL(String connectionURL) {
+        this.connectionURL = connectionURL;
+    }
+
+
+    /**
+     * Sets the name of the table where the logs are stored.
+     * 
+     * @param tableName The name of the table.
+     */
+    public void setTableName(String tableName) {
+        this.tableName = tableName;
+    }
+
+
+    /**
+     * Sets the name of the field containing the remote host.
+     * 
+     * @param remoteHostField The name of the remote host field.
+     */
+    public void setRemoteHostField(String remoteHostField) {
+        this.remoteHostField = remoteHostField;
+    }
+
+
+    /**
+     * Sets the name of the field containing the remote user name.
+     * 
+     * @param userField The name of the remote user field.
+     */
+    public void setUserField(String userField) {
+        this.userField = userField;
+    }
+
+
+    /**
+     * Sets the name of the field containing the server-determined timestamp.
+     * 
+     * @param timestampField The name of the server-determined timestamp field.
+     */
+    public void setTimestampField(String timestampField) {
+        this.timestampField = timestampField;
+    }
+
+
+    /**
+     * Sets the name of the field containing the virtual host information 
+     * (this is in fact the server name).
+     * 
+     * @param virtualHostField The name of the virtual host field.
+     */
+    public void setVirtualHostField(String virtualHostField) {
+        this.virtualHostField = virtualHostField;
+    }
+
+
+    /**
+     * Sets the name of the field containing the HTTP request method.
+     * 
+     * @param methodField The name of the HTTP request method field.
+     */
+    public void setMethodField(String methodField) {
+        this.methodField = methodField;
+    }
+
+
+    /**
+     * Sets the name of the field containing the URL part of the HTTP query.
+     * 
+     * @param queryField The name of the field containing the URL part of 
+     * the HTTP query.
+     */
+    public void setQueryField(String queryField) {
+        this.queryField = queryField;
+    }
+
+
+  /**
+   * Sets the name of the field containing the HTTP response status code.
+   * 
+   * @param statusField The name of the HTTP response status code field.
+   */  
+    public void setStatusField(String statusField) {
+        this.statusField = statusField;
+    }
+
+
+    /**
+     * Sets the name of the field containing the number of bytes returned.
+     * 
+     * @param bytesField The name of the returned bytes field.
+     */
+    public void setBytesField(String bytesField) {
+        this.bytesField = bytesField;
+    }
+
+
+    /**
+     * Sets the name of the field containing the referer.
+     * 
+     * @param refererField The referer field name.
+     */
+    public void setRefererField(String refererField) {
+        this.refererField = refererField;
+    }
+
+
+    /**
+     * Sets the name of the field containing the user agent.
+     * 
+     * @param userAgentField The name of the user agent field.
+     */
+    public void setUserAgentField(String userAgentField) {
+        this.userAgentField = userAgentField;
+    }
+
+
+    /**
+     * Sets the logging pattern. The patterns supported correspond to the 
+     * file-based "common" and "combined". These are translated into the use 
+     * of tables containing either set of fields.
+     * <P><I>TO DO: more flexible field choices.</I></P>
+     * 
+     * @param pattern The name of the logging pattern.
+     */
+    public void setPattern(String pattern) {
+        this.pattern = pattern;
+    }
+
+
+    /**
+     * Determines whether IP host name resolution is done.
+     * 
+     * @param resolveHosts "true" or "false", if host IP resolution 
+     * is desired or not.
+     */
+    public void setResolveHosts(String resolveHosts) {
+        this.resolveHosts = new Boolean(resolveHosts).booleanValue();
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * This method is invoked by Tomcat on each query.
+     * 
+     * @param request The Request object.
+     * @param response The Response object.
+     *
+     * @exception IOException Should not be thrown.
+     * @exception ServletException Database SQLException is wrapped 
+     * in a ServletException.
+     */    
+    public void invoke(Request request, Response response) 
+        throws IOException, ServletException {
+
+        getNext().invoke(request, response);
+
+        String remoteHost = "";
+        if(resolveHosts)
+            remoteHost = request.getRemoteHost();
+        else
+            remoteHost = request.getRemoteAddr();
+        String user = "";
+        if(request != null)
+            user = request.getRemoteUser();
+        String query="";
+        if(request != null)
+            query = request.getRequestURI();
+        int bytes = response.getContentCount();
+        if(bytes < 0)
+            bytes = 0;
+        int status = response.getStatus();
+        if (pattern.equals("combined")) {
+                String virtualHost = "";
+                if(request != null)
+                    virtualHost = request.getServerName();
+                String method = "";
+                if(request != null)
+                    method = request.getMethod();
+                String referer = "";
+                if(request != null)
+                    referer = request.getHeader("referer");
+                String userAgent = "";
+                if(request != null)
+                    userAgent = request.getHeader("user-agent");
+        }
+        synchronized (this) {
+          int numberOfTries = 2;
+          while (numberOfTries>0) {
+            try {
+                open();
+    
+                ps.setString(1, remoteHost);
+                ps.setString(2, user);
+                ps.setTimestamp(3, new Timestamp(getCurrentTimeMillis()));
+                ps.setString(4, query);
+                ps.setInt(5, status);
+                ps.setInt(6, bytes);
+                if (pattern.equals("combined")) {
+     
+                      String virtualHost = "";
+                      if(request != null)
+                         virtualHost = request.getServerName();
+                      String method = "";
+                      if(request != null)
+                         method = request.getMethod();
+                      String referer = "";
+                      if(request != null)
+                         referer = request.getHeader("referer");
+                      String userAgent = "";
+                      if(request != null)
+                         userAgent = request.getHeader("user-agent");
+                      ps.setString(7, virtualHost);
+                      ps.setString(8, method);
+                      ps.setString(9, referer);
+                      ps.setString(10, userAgent);
+                }
+                ps.executeUpdate();
+                return;
+              } catch (SQLException e) {
+                // Log the problem for posterity
+                  container.getLogger().error(sm.getString("jdbcAccessLogValve.exception"), e);
+
+                // Close the connection so that it gets reopened next time
+                if (conn != null)
+                    close();
+              }
+    	      numberOfTries--;        
+           }
+        }
+
+    }	
+
+
+    /**
+     * Adds a Lifecycle listener.
+     * 
+     * @param listener The listener to add.
+     */  
+    public void addLifecycleListener(LifecycleListener listener) {
+
+        lifecycle.addLifecycleListener(listener);
+
+    }
+
+
+    /**
+     * Get the lifecycle listeners associated with this lifecycle. If this 
+     * Lifecycle has no listeners registered, a zero-length array is returned.
+     */
+    public LifecycleListener[] findLifecycleListeners() {
+
+        return lifecycle.findLifecycleListeners();
+
+    }
+
+
+    /**
+     * Removes a Lifecycle listener.
+     * 
+     * @param listener The listener to remove.
+     */
+    public void removeLifecycleListener(LifecycleListener listener) {
+
+        lifecycle.removeLifecycleListener(listener);
+
+    }
+
+    /**
+     * Open (if necessary) and return a database connection for use by
+     * this AccessLogValve.
+     *
+     * @exception SQLException if a database error occurs
+     */
+    protected void open() throws SQLException {
+
+        // Do nothing if there is a database connection already open
+        if (conn != null)
+            return ;
+
+        // Instantiate our database driver if necessary
+        if (driver == null) {
+            try {
+                Class clazz = Class.forName(driverName);
+                driver = (Driver) clazz.newInstance();
+            } catch (Throwable e) {
+                throw new SQLException(e.getMessage());
+            }
+        }
+
+        // Open a new connection
+        Properties props = new Properties();
+        props.put("autoReconnect", "true");
+        if (connectionName != null)
+            props.put("user", connectionName);
+        if (connectionPassword != null)
+            props.put("password", connectionPassword);
+        conn = driver.connect(connectionURL, props);
+        conn.setAutoCommit(true);
+        if (pattern.equals("common")) {
+                ps = conn.prepareStatement
+                    ("INSERT INTO " + tableName + " (" 
+                     + remoteHostField + ", " + userField + ", "
+                     + timestampField +", " + queryField + ", "
+                     + statusField + ", " + bytesField 
+                     + ") VALUES(?, ?, ?, ?, ?, ?)");
+        } else if (pattern.equals("combined")) {
+                ps = conn.prepareStatement
+                    ("INSERT INTO " + tableName + " (" 
+                     + remoteHostField + ", " + userField + ", "
+                     + timestampField + ", " + queryField + ", " 
+                     + statusField + ", " + bytesField + ", " 
+                     + virtualHostField + ", " + methodField + ", "
+                     + refererField + ", " + userAgentField
+                     + ") VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
+        }
+    }
+
+    /**
+     * Close the specified database connection.
+     */
+    protected void close() {
+
+        // Do nothing if the database connection is already closed
+        if (conn == null)
+            return;
+
+        // Close our prepared statements (if any)
+        try {
+            ps.close();
+        } catch (Throwable f) {
+            ;
+        }
+        this.ps = null;
+
+
+
+        // Close this database connection, and log any errors
+        try {
+            conn.close();
+        } catch (SQLException e) {
+            container.getLogger().error(sm.getString("jdbcAccessLogValeve.close"), e); // Just log it here            
+        } finally {
+           this.conn = null;
+        }
+
+    }
+    /**
+     * Invoked by Tomcat on startup. The database connection is set here.
+     * 
+     * @exception LifecycleException Can be thrown on lifecycle 
+     * inconsistencies or on database errors (as a wrapped SQLException).
+     */
+    public void start() throws LifecycleException {
+
+        if (started)
+            throw new LifecycleException
+                (sm.getString("accessLogValve.alreadyStarted"));
+        lifecycle.fireLifecycleEvent(START_EVENT, null);
+        started = true;
+
+        try {
+            open() ;        
+        } catch (SQLException e) {
+            throw new LifecycleException(e);
+        }
+
+    }
+
+
+    /**
+     * Invoked by tomcat on shutdown. The database connection is closed here.
+     * 
+     * @exception LifecycleException Can be thrown on lifecycle 
+     * inconsistencies or on database errors (as a wrapped SQLException).
+     */
+    public void stop() throws LifecycleException {
+
+        if (!started)
+            throw new LifecycleException
+                (sm.getString("accessLogValve.notStarted"));
+        lifecycle.fireLifecycleEvent(STOP_EVENT, null);
+        started = false;
+        
+        close() ;
+    	
+    }
+
+
+    public long getCurrentTimeMillis() {
+        long systime  =  System.currentTimeMillis();
+        if ((systime - currentTimeMillis) > 1000) {
+            currentTimeMillis  =  new java.util.Date(systime).getTime();
+        }
+        return currentTimeMillis;
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/valves/LocalStrings.properties
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/valves/LocalStrings.properties	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/valves/LocalStrings.properties	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,71 @@
+accessLogValve.alreadyStarted=Access Logger has already been started
+accessLogValve.notStarted=Access Logger has not yet been started
+semaphoreValve.alreadyStarted=Semaphore valve has already been started
+semaphoreValve.notStarted=Semaphore valve has not yet been started
+certificatesValve.alreadyStarted=Certificates Valve has already been started
+certificatesValve.notStarted=Certificates Valve has not yet been started
+interceptorValve.alreadyStarted=Interceptor Valve has already been started
+interceptorValve.notStarted=Interceptor Valve has not yet been started
+requestFilterValve.next=No ''next'' valve has been configured
+requestFilterValve.syntax=Syntax error in request filter pattern {0}
+requestListenerValve.requestInit=Exception sending request initialized lifecycle event to listener instance of class {0}
+requestListenerValve.requestDestroy=Exception sending request destroyed lifecycle event to listener instance of class {0}
+valveBase.noNext=Configuration error: No ''next'' valve configured
+jdbcAccessLogValve.exception=Exception performing insert access entry
+jdbcAccessLogValve.close=Exception closing database connection
+
+# Error report valve
+errorReportValve.errorReport=Error report
+errorReportValve.statusHeader=HTTP Status {0} - {1}
+errorReportValve.exceptionReport=Exception report
+errorReportValve.statusReport=Status report
+errorReportValve.message=message
+errorReportValve.description=description
+errorReportValve.exception=exception
+errorReportValve.rootCause=root cause
+errorReportValve.note=note
+errorReportValve.rootCauseInLogs=The full stack trace of the root cause is available in the {0} logs.
+
+# 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}).
+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}).

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/valves/LocalStrings_es.properties
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/valves/LocalStrings_es.properties	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/valves/LocalStrings_es.properties	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,69 @@
+accessLogValve.alreadyStarted=El Registrador de accesos ya se había iniciado
+accessLogValve.notStarted=El Registrador de accesos no se ha iniciado
+certificatesValve.alreadyStarted=La válvula de certificados ya se había iniciado
+certificatesValve.notStarted=La válvula de certificados no se ha iniciado
+interceptorValve.alreadyStarted=La válvula interceptora ya se había iniciado
+interceptorValve.notStarted=La válvula interceptora no se ha iniciado
+requestFilterValve.next=No hay ''siguiente'' válvula configurada
+requestFilterValve.syntax=Error de sintáxis en petición de filtro patrón {0}
+requestListenerValve.requestInit=Una excepción durante el envío de requerimiento ha iniciado un evento de ciclo de vida (lifecycle event) para la instancia de clase a la escucha (listener) {0}
+requestListenerValve.requestDestroy=Una excepción durante el envío de requerimiento ha destruído un evento de ciclo de vida (lifecycle event) para la instancia de clase a la escucha (listener) {0}
+valveBase.noNext=Error de configuración: No hay ''siguiente'' válvula configurada
+jdbcAccessLogValve.exception=Excepción realizando entrada de acceso a inserción
+jdbcAccessLogValve.close=Excepción cerrando conexión a base de datos
+
+# Error report valve
+errorReportValve.errorReport=Informe de Error
+errorReportValve.statusHeader=Estado HTTP {0} - {1}
+errorReportValve.exceptionReport=Informe de Excepción
+errorReportValve.statusReport=Informe de estado
+errorReportValve.message=mensaje
+errorReportValve.description=descripción
+errorReportValve.exception=excepción
+errorReportValve.rootCause=causa raíz
+errorReportValve.note=nota
+errorReportValve.rootCauseInLogs=La traza completa de la causa de este error se encuentra en los archivos de diario de {0}.
+
+# HTTP status reports
+http.100=El cliente puede continuar ({0}).
+http.101=El servidor está conmutando protocolos con arreglo a la cabecera "Upgrade" ({0}).
+http.201=El requerimiento tuvo éxito 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ón meta presentada por el cliente no se originó desde el servidor ({0}).
+http.204=El requerimiento tuvo éxito pero no hay información que devolver ({0}).
+http.205=El cliente no debería de limpiar la vista del documento que causó que este requerimiento fuera enviado ({0}).
+http.206=El servidor ha rellenado paciálmente un requerimiento GET para este recurso ({0}).
+http.207=Se han devuelto valores múltiples de estado ({0}).
+http.300=El recurso requerido ({0}) corresponde a una cualquiera de un conjunto de representaciones, cada una con su propia localización específica.
+http.301=El recurso requerido ({0}) ha sido movido permanéntemente a una nueva localización.
+http.302=El recurso requerido ({0}) ha sido movido temporálmente a una nueva localización.
+http.303=La respuesta a este requerimiento se puede hallar bajo una URI diferente ({0}).
+http.304=El recurso requerido ({0}) está disponible y no ha sido modificado.
+http.305=El recurso requerido ({0}) debe de ser accedido a través del apoderado (proxy) dado mediante la cabecera "Location".
+http.400=El requerimiento enviado por el cliente era sintácticamente incorrecto ({0}).
+http.401=Este requerimiento requiere autenticación 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á disponible.
+http.405=El método HTTP especificado no está permitido para el recurso requerido ({0}).
+http.406=El recurso identificado por este requerimiento sólo es capaz de generar respuestas con características 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á disponible y no se conoce dirección de reenvío.
+http.411=Este requerimiento no puede ser manejado sin un tamaño definido de contenido ({0}).
+http.412=Una precondición especificada ha fallado para este requerimiento ({0}).
+http.413=La entidad de requerimiento es mayor de lo que el servidor quiere o puede procesar.
+http.414=El servidor rechazó este requerimiento porque la URI requerida era demasiado larga ({0}).
+http.415=El servidor rechazó este requerimiento porque la entidad requerida se encuentra en un formato no soportado por el recurso requerido para el método 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ó el tipo de contenido y la sintáxis del requerimiento pero no pudo procesar las instrucciones contenidas ({0}).
+http.423=La fuente o recurso de destino de un método está bloqueada ({0}).
+http.500=El servidor encontró 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ó una respuesta inválida desde un servidor que consultó cuando actuaba como apoderado o pasarela ({0}).
+http.503=El servicio requerido ({0}) no está disponible en este momento.
+http.504=El servidor recibió un Tiempo Agotado desde un servidor superior cuando actuaba como pasarela o apoderado ({0}).
+http.505=El servidor no soporta la versión de protocolo HTTP requerida ({0}).
+http.507=El recurso no tiene espacio suficiente para registrar el estado del recurso tras la ejecución de este método ({0}).

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/valves/LocalStrings_fr.properties
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/valves/LocalStrings_fr.properties	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/valves/LocalStrings_fr.properties	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,67 @@
+accessLogValve.alreadyStarted=Le traceur d''accès a déjà été démarré
+accessLogValve.notStarted=Le traceur d''accès n''a pas encore été démarré
+certificatesValve.alreadyStarted=La Valve de Certificats a déjà été démarrée
+certificatesValve.notStarted=La Valve de Certificats n''a pas encore été démarrée
+interceptorValve.alreadyStarted=La Valve d''Interception a déjà été démarré
+interceptorValve.notStarted=La Valve d''Interception n''a pas encore été démarrée
+requestFilterValve.next=Aucune Valve ''suivante'' n''a été configurée
+requestFilterValve.syntax=Erreur de synthaxe dans le pattern de filtre de requête {0}
+requestListenerValve.requestInit=Une exception lors de l''envoi de requête a initié un évènement cycle de vie (lifecycle event) pour l''instance de classe à l''écoute (listener) {0}
+requestListenerValve.requestDestroy=Une exception lors de l''envoi de requête a détruit un évènement cycle de vie (lifecycle event) pour l''instance de classe à l''écoute (listener) {0}
+valveBase.noNext=Erreur de configuration error: Aucune Valve ''suivante'' n''a été configurée
+
+# Error report valve
+errorReportValve.errorReport=Rapport d''erreur
+errorReportValve.statusHeader=Etat HTTP {0} - {1}
+errorReportValve.exceptionReport=Rapport d''exception
+errorReportValve.statusReport=Rapport d''état
+errorReportValve.message=message
+errorReportValve.description=description
+errorReportValve.exception=exception
+errorReportValve.rootCause=cause mère
+errorReportValve.note=note
+errorReportValve.rootCauseInLogs=La trace complète de la cause mère 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ête ({0}).
+http.201=La requête a réussi et une nouvelle ressource ({0}) a été créee sur le serveur.
+http.202=La requête a été accepté pour traitement, mais n''a pas été terminée ({0}).
+http.203=L''information meta présentée par le client n''a pas pour origine ce server ({0}).
+http.204=La requête a réussi mais il n''y a aucune information à retourner ({0}).
+http.205=Le client doit remettre à zéro la vue de document qui a causée l''envoi de cette requête ({0}).
+http.206=Le serveur a satisfait une requête GET partielle pour cette ressource ({0}).
+http.207=Plusieurs valeurs d''états ont été retournées ({0}).
+http.300=La ressource demandée ({0}) correspond à plusieurs représentations, chacune avec sa propre localisation.
+http.301=La ressource demandée ({0}) a été déplacée de façon permanente vers une nouvelle localisation.
+http.302=La ressource demandée ({0}) a été déplacée de façon temporaire vers une nouvelle localisation.
+http.303=La réponse à cette requête peut être trouvée à une URI différente ({0}).
+http.304=La ressource demandée ({0}) est disponible et n''a pas été modifiée.
+http.305=La ressource demandée ({0}) doit être accédée au travers du relais indiqué par la directive "Location" de l''entête.
+http.400=La requête envoyée par le client était syntaxiquement incorrecte ({0}).
+http.401=La requête nécessite une authentification HTTP ({0}).
+http.402=Un paiement est demandé pour accéder à cette ressource ({0}).
+http.403=L''accès à la ressource demandée ({0}) a été interdit.
+http.404=La ressource demandée ({0}) n''est pas disponible.
+http.405=La méthode HTTP spécifiée n''est pas autorisée pour la ressource demandée ({0}).
+http.406=La ressource identifiée par cette requête n''est capable de générer des réponses qu''avec des caractéristiques incompatible avec la directive "accept" présente dans l''entête de requête ({0}).
+http.407=Le client doit d''abord s''authentifier auprès du relais ({0}).
+http.408=Le client n''a pas produit de requête pendant le temps d''attente du serveur ({0}).
+http.409=La requête ne peut être finalisée suite à un conflit lié à l''état de la ressource ({0}).
+http.410=La ressource demandée ({0}) n''est pas disponible, et aucune addresse de rebond (forwarding) n''est connue.
+http.411=La requête ne peut être traitée sans définition d''une taille de contenu (content length) ({0}).
+http.412=Une condition préalable demandée a échouée pour cette requête ({0}).
+http.413=L''entité de requête est plus importante que ce que le serveur veut ou peut traiter.
+http.414=Le serveur a refusé cette requête car URI de requête est trop longue ({0}).
+http.415=Le serveur a refusé cette requête car l''entité de requête est dans un format non supporté par la ressource demandée avec la méthode spécifiée ({0}).
+http.416=La place d''octets (byte range) ne peut être satisfaite ({0}).
+http.417=L''attente indiqué dans la directive "Expect" de l''entête de requête ({0}) ne peut être satisfaite.
+http.422=Le serveur a compris le type de contenu (content type) ainsi que la synthaxe de la requête mais a été incapable de traiter les instructions contenues ({0}).
+http.423=La ressource source ou destination de la méthode est vérrouillée ({0}).
+http.500=Le serveur a rencontré une erreur interne ({0}) qui l''a empêché de satisfaire la requête.
+http.501=Le serveur ne supporte pas la fonctionnalité demandée pour satisfaire cette requête ({0}).
+http.502=Le serveur a reçu une réponse invalide d''un serveur qu''il consultait en tant que relais ou passerelle ({0}).
+http.503=Le service demandé ({0}) n''est pas disponible actuellement.
+http.504=Le serveur a reçu un dépassement de delais (timeout) d''un serveur amont qu''il consultait en tant que relais ou passerelle ({0}).
+http.505=Le serveur ne supporte pas la version de protocole HTTP demandé ({0}).
+http.507=La ressource n''a pas assez d''espace pour enregistrer l''état de la ressource après exécution de cette méthode ({0}).

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/valves/LocalStrings_ja.properties
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/valves/LocalStrings_ja.properties	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/valves/LocalStrings_ja.properties	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,24 @@
+accessLogValve.alreadyStarted=\u30a2\u30af\u30bb\u30b9\u30ed\u30ac\u30fc\u306f\u65e2\u306b\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u3059
+accessLogValve.notStarted=\u30a2\u30af\u30bb\u30b9\u30ed\u30ac\u30fc\u306f\u307e\u3060\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u305b\u3093
+certificatesValve.alreadyStarted=\u8a8d\u8a3c\u30d0\u30eb\u30d6\u306f\u65e2\u306b\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u3059
+certificatesValve.notStarted=\u8a8d\u8a3c\u30d0\u30eb\u30d6\u306f\u307e\u3060\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u305b\u3093
+interceptorValve.alreadyStarted=\u30a4\u30f3\u30bf\u30fc\u30bb\u30d7\u30bf\u30d0\u30eb\u30d6\u306f\u65e2\u306b\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u3059
+interceptorValve.notStarted=\u30a4\u30f3\u30bf\u30fc\u30bb\u30d7\u30bf\u30d0\u30eb\u30d6\u306f\u307e\u3060\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u305b\u3093
+requestFilterValve.next=\u6b21\u306e\u30d0\u30eb\u30d6\u304c\u8a2d\u5b9a\u3055\u308c\u3066\u3044\u307e\u305b\u3093
+requestFilterValve.syntax=\u30ea\u30af\u30a8\u30b9\u30c8\u30d5\u30a3\u30eb\u30bf\u30d1\u30bf\u30fc\u30f3 {0} \u306b\u69cb\u6587\u30a8\u30e9\u30fc\u304c\u3042\u308a\u307e\u3059
+requestListenerValve.requestInit=\u30af\u30e9\u30b9 {0} \u306e\u30ea\u30b9\u30ca\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u306b\u521d\u671f\u5316\u3059\u308b\u30e9\u30a4\u30d5\u30b5\u30a4\u30af\u30eb\u30a4\u30d9\u30f3\u30c8\u306e\u30ea\u30af\u30a8\u30b9\u30c8\u3092\u9001\u4fe1\u4e2d\u306e\u4f8b\u5916\u3067\u3059
+requestListenerValve.requestDestroy=\u30af\u30e9\u30b9 {0} \u306e\u30ea\u30b9\u30ca\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u306b\u5ec3\u68c4\u3059\u308b\u30e9\u30a4\u30d5\u30b5\u30a4\u30af\u30eb\u30a4\u30d9\u30f3\u30c8\u306e\u30ea\u30af\u30a8\u30b9\u30c8\u3092\u9001\u4fe1\u4e2d\u306e\u4f8b\u5916\u3067\u3059
+jdbcAccessLogValve.exception=\u30a2\u30af\u30bb\u30b9\u30a8\u30f3\u30c8\u30ea\u306e\u633f\u5165\u3092\u5b9f\u884c\u4e2d\u306e\u4f8b\u5916\u3067\u3059
+jdbcAccessLogValve.close=\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u63a5\u7d9a\u3092\u30af\u30ed\u30fc\u30ba\u4e2d\u306e\u4f8b\u5916\u3067\u3059
+
+# Error report valve
+valveBase.noNext=\u8a2d\u5b9a\u30a8\u30e9\u30fc: \u6b21\u306e\u30d0\u30eb\u30d6\u304c\u8a2d\u5b9a\u3055\u308c\u3066\u3044\u307e\u305b\u3093
+errorReportValve.statusHeader=HTTP\u30b9\u30c6\u30fc\u30bf\u30b9 {0} - {1}
+errorReportValve.exceptionReport=\u4f8b\u5916\u30ec\u30dd\u30fc\u30c8
+errorReportValve.statusReport=\u30b9\u30c6\u30fc\u30bf\u30b9\u30ec\u30dd\u30fc\u30c8
+errorReportValve.message=\u30e1\u30c3\u30bb\u30fc\u30b8
+errorReportValve.description=\u8aac\u660e
+errorReportValve.exception=\u4f8b\u5916
+errorReportValve.rootCause=\u539f\u56e0
+errorReportValve.note=\u6ce8\u610f
+errorReportValve.rootCauseInLogs=\u539f\u56e0\u306e\u3059\u3079\u3066\u306e\u30b9\u30bf\u30c3\u30af\u30c8\u30ec\u30fc\u30b9\u306f\u3001{0}\u306e\u30ed\u30b0\u306b\u8a18\u9332\u3055\u308c\u3066\u3044\u307e\u3059

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/valves/PersistentValve.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/valves/PersistentValve.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/valves/PersistentValve.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,210 @@
+/*
+ * Copyright 1999-2001,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.io.IOException;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.catalina.Context;
+import org.apache.catalina.Manager;
+import org.apache.catalina.Session;
+import org.apache.catalina.Store;
+import org.apache.catalina.connector.Request;
+import org.apache.catalina.connector.Response;
+import org.apache.catalina.core.StandardHost;
+import org.apache.catalina.session.PersistentManager;
+import org.apache.catalina.util.StringManager;
+
+
+/**
+ * Valve that implements the default basic behavior for the
+ * <code>StandardHost</code> container implementation.
+ * <p>
+ * <b>USAGE CONSTRAINT</b>: To work correctly it requires a  PersistentManager.
+ *
+ * @author Jean-Frederic Clere
+ * @version $Revision: 303826 $ $Date: 2005-03-31 04:31:54 -0600 (Thu, 31 Mar 2005) $
+ */
+
+public class PersistentValve
+    extends ValveBase {
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The descriptive information related to this implementation.
+     */
+    private static final String info =
+        "org.apache.catalina.valves.PersistentValve/1.0";
+
+
+    /**
+     * The string manager for this package.
+     */
+    private static final StringManager sm =
+        StringManager.getManager(Constants.Package);
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * Return descriptive information about this Valve implementation.
+     */
+    public String getInfo() {
+
+        return (info);
+
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Select the appropriate child Context to process this request,
+     * based on the specified request URI.  If no matching Context can
+     * be found, return an appropriate HTTP error.
+     *
+     * @param request Request to be processed
+     * @param response Response to be produced
+     *
+     * @exception IOException if an input/output error occurred
+     * @exception ServletException if a servlet error occurred
+     */
+    public void invoke(Request request, Response response)
+        throws IOException, ServletException {
+
+        // Select the Context to be used for this Request
+        StandardHost host = (StandardHost) getContainer();
+        Context context = request.getContext();
+        if (context == null) {
+            response.sendError
+                (HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
+                 sm.getString("standardHost.noContext"));
+            return;
+        }
+
+        // Bind the context CL to the current thread
+        Thread.currentThread().setContextClassLoader
+            (context.getLoader().getClassLoader());
+
+        // Update the session last access time for our session (if any)
+        String sessionId = request.getRequestedSessionId();
+        Manager manager = context.getManager();
+        if (sessionId != null && manager != null) {
+            if (manager instanceof PersistentManager) {
+                Store store = ((PersistentManager) manager).getStore();
+                if (store != null) {
+                    Session session = null;
+                    try {
+                        session = store.load(sessionId);
+                    } catch (Exception e) {
+                        container.getLogger().error("deserializeError");
+                    }
+                    if (session != null) {
+                        if (!session.isValid() ||
+                            isSessionStale(session, System.currentTimeMillis())) {
+                            if (container.getLogger().isDebugEnabled())
+                                container.getLogger().debug("session swapped in is invalid or expired");
+                            session.expire();
+                            store.remove(sessionId);
+                        } else {
+                            session.setManager(manager);
+                            // session.setId(sessionId); Only if new ???
+                            manager.add(session);
+                            // ((StandardSession)session).activate();
+                            session.access();
+                        }
+                    }
+                }
+            }
+        }
+        if (container.getLogger().isDebugEnabled())
+            container.getLogger().debug("sessionId: " + sessionId);
+
+        // Ask the next valve to process the request.
+        getNext().invoke(request, response);
+
+        // Read the sessionid after the response.
+        // HttpSession hsess = hreq.getSession(false);
+        Session hsess;
+        try {
+            hsess = request.getSessionInternal();
+        } catch (Exception ex) {
+            hsess = null;
+        }
+        String newsessionId = null;
+        if (hsess!=null)
+            newsessionId = hsess.getIdInternal();
+
+        if (container.getLogger().isDebugEnabled())
+            container.getLogger().debug("newsessionId: " + newsessionId);
+        if (newsessionId!=null) {
+            /* store the session in the store and remove it from the manager */
+            if (manager instanceof PersistentManager) {
+                Session session = manager.findSession(newsessionId);
+                Store store = ((PersistentManager) manager).getStore();
+                if (store != null && session!=null &&
+                    session.isValid() &&
+                    !isSessionStale(session, System.currentTimeMillis())) {
+                    // ((StandardSession)session).passivate();
+                    store.save(session);
+                    ((PersistentManager) manager).removeSuper(session);
+                    session.recycle();
+                } else {
+                    if (container.getLogger().isDebugEnabled())
+                        container.getLogger().debug("newsessionId store: " + store + " session: " +
+                                session + " valid: " + session.isValid() +
+                                " Staled: " +
+                                isSessionStale(session, System.currentTimeMillis()));
+
+                }
+            } else {
+                if (container.getLogger().isDebugEnabled())
+                    container.getLogger().debug("newsessionId Manager: " + manager);
+            }
+        }
+    }
+
+    /**
+     * Indicate whether the session has been idle for longer
+     * than its expiration date as of the supplied time.
+     *
+     * FIXME: Probably belongs in the Session class.
+     */
+    protected boolean isSessionStale(Session session, long timeNow) {
+ 
+        int maxInactiveInterval = session.getMaxInactiveInterval();
+        if (maxInactiveInterval >= 0) {
+            int timeIdle = // Truncate, do not round up
+                (int) ((timeNow - session.getLastAccessedTime()) / 1000L);
+            if (timeIdle >= maxInactiveInterval)
+                return true;
+        }
+ 
+        return false;
+ 
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/valves/RemoteAddrValve.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/valves/RemoteAddrValve.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/valves/RemoteAddrValve.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,85 @@
+/*
+ * Copyright 1999-2001,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.io.IOException;
+import javax.servlet.ServletException;
+import org.apache.catalina.connector.Request;
+import org.apache.catalina.connector.Response;
+
+
+/**
+ * Concrete implementation of <code>RequestFilterValve</code> that filters
+ * based on the string representation of the remote client's IP address.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 303133 $ $Date: 2004-08-29 11:46:15 -0500 (Sun, 29 Aug 2004) $
+ */
+
+public final class RemoteAddrValve
+    extends RequestFilterValve {
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The descriptive information related to this implementation.
+     */
+    private static final String info =
+        "org.apache.catalina.valves.RemoteAddrValve/1.0";
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * Return descriptive information about this Valve implementation.
+     */
+    public String getInfo() {
+
+        return (info);
+
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Extract the desired request property, and pass it (along with the
+     * specified request and response objects) to the protected
+     * <code>process()</code> method to perform the actual filtering.
+     * This method must be implemented by a concrete subclass.
+     *
+     * @param request The servlet request to be processed
+     * @param response The servlet response to be created
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception ServletException if a servlet error occurs
+     */
+    public void invoke(Request request, Response response)
+        throws IOException, ServletException {
+
+        process(request.getRequest().getRemoteAddr(), request, response);
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/valves/RemoteHostValve.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/valves/RemoteHostValve.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/valves/RemoteHostValve.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,85 @@
+/*
+ * Copyright 1999-2001,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.io.IOException;
+import javax.servlet.ServletException;
+import org.apache.catalina.connector.Request;
+import org.apache.catalina.connector.Response;
+
+
+/**
+ * Concrete implementation of <code>RequestFilterValve</code> that filters
+ * based on the remote client's host name.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 304096 $ $Date: 2005-09-20 16:02:12 -0500 (Tue, 20 Sep 2005) $
+ */
+
+public final class RemoteHostValve
+    extends RequestFilterValve {
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The descriptive information related to this implementation.
+     */
+    private static final String info =
+        "org.apache.catalina.valves.RemoteHostValve/1.0";
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * Return descriptive information about this Valve implementation.
+     */
+    public String getInfo() {
+
+        return (info);
+
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Extract the desired request property, and pass it (along with the
+     * specified request and response objects) to the protected
+     * <code>process()</code> method to perform the actual filtering.
+     * This method must be implemented by a concrete subclass.
+     *
+     * @param request The servlet request to be processed
+     * @param response The servlet response to be created
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception ServletException if a servlet error occurs
+     */
+    public void invoke(Request request, Response response)
+        throws IOException, ServletException {
+
+        process(request.getRequest().getRemoteHost(), request, response);
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/valves/RequestDumperValve.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/valves/RequestDumperValve.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/valves/RequestDumperValve.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,191 @@
+/*
+ * Copyright 1999-2001,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.io.IOException;
+import java.util.Enumeration;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.Cookie;
+
+import org.apache.catalina.connector.Request;
+import org.apache.catalina.connector.Response;
+import org.apache.catalina.util.StringManager;
+import org.apache.commons.logging.Log;
+
+
+/**
+ * <p>Implementation of a Valve that logs interesting contents from the
+ * specified Request (before processing) and the corresponding Response
+ * (after processing).  It is especially useful in debugging problems
+ * related to headers and cookies.</p>
+ *
+ * <p>This Valve may be attached to any Container, depending on the granularity
+ * of the logging you wish to perform.</p>
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 303133 $ $Date: 2004-08-29 11:46:15 -0500 (Sun, 29 Aug 2004) $
+ */
+
+public class RequestDumperValve
+    extends ValveBase {
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The descriptive information related to this implementation.
+     */
+    private static final String info =
+        "org.apache.catalina.valves.RequestDumperValve/1.0";
+
+
+    /**
+     * The StringManager for this package.
+     */
+    protected static StringManager sm =
+        StringManager.getManager(Constants.Package);
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * Return descriptive information about this Valve implementation.
+     */
+    public String getInfo() {
+
+        return (info);
+
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Log the interesting request parameters, invoke the next Valve in the
+     * sequence, and log the interesting response parameters.
+     *
+     * @param request The servlet request to be processed
+     * @param response The servlet response to be created
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception ServletException if a servlet error occurs
+     */
+    public void invoke(Request request, Response response)
+        throws IOException, ServletException {
+
+        Log log = container.getLogger();
+        
+        // Log pre-service information
+        log.info("REQUEST URI       =" + request.getRequestURI());
+        log.info("          authType=" + request.getAuthType());
+        log.info(" characterEncoding=" + request.getCharacterEncoding());
+        log.info("     contentLength=" + request.getContentLength());
+        log.info("       contentType=" + request.getContentType());
+        log.info("       contextPath=" + request.getContextPath());
+        Cookie cookies[] = request.getCookies();
+        if (cookies != null) {
+            for (int i = 0; i < cookies.length; i++)
+                log.info("            cookie=" + cookies[i].getName() + "=" +
+                    cookies[i].getValue());
+        }
+        Enumeration hnames = request.getHeaderNames();
+        while (hnames.hasMoreElements()) {
+            String hname = (String) hnames.nextElement();
+            Enumeration hvalues = request.getHeaders(hname);
+            while (hvalues.hasMoreElements()) {
+                String hvalue = (String) hvalues.nextElement();
+                log.info("            header=" + hname + "=" + hvalue);
+            }
+        }
+        log.info("            locale=" + request.getLocale());
+        log.info("            method=" + request.getMethod());
+        Enumeration pnames = request.getParameterNames();
+        while (pnames.hasMoreElements()) {
+            String pname = (String) pnames.nextElement();
+            String pvalues[] = request.getParameterValues(pname);
+            StringBuffer result = new StringBuffer(pname);
+            result.append('=');
+            for (int i = 0; i < pvalues.length; i++) {
+                if (i > 0)
+                    result.append(", ");
+                result.append(pvalues[i]);
+            }
+            log.info("         parameter=" + result.toString());
+        }
+        log.info("          pathInfo=" + request.getPathInfo());
+        log.info("          protocol=" + request.getProtocol());
+        log.info("       queryString=" + request.getQueryString());
+        log.info("        remoteAddr=" + request.getRemoteAddr());
+        log.info("        remoteHost=" + request.getRemoteHost());
+        log.info("        remoteUser=" + request.getRemoteUser());
+        log.info("requestedSessionId=" + request.getRequestedSessionId());
+        log.info("            scheme=" + request.getScheme());
+        log.info("        serverName=" + request.getServerName());
+        log.info("        serverPort=" + request.getServerPort());
+        log.info("       servletPath=" + request.getServletPath());
+        log.info("          isSecure=" + request.isSecure());
+        log.info("---------------------------------------------------------------");
+
+        // Perform the request
+        getNext().invoke(request, response);
+
+        // Log post-service information
+        log.info("---------------------------------------------------------------");
+        log.info("          authType=" + request.getAuthType());
+        log.info("     contentLength=" + response.getContentLength());
+        log.info("       contentType=" + response.getContentType());
+        Cookie rcookies[] = response.getCookies();
+        for (int i = 0; i < rcookies.length; i++) {
+            log.info("            cookie=" + rcookies[i].getName() + "=" +
+                rcookies[i].getValue() + "; domain=" +
+                rcookies[i].getDomain() + "; path=" + rcookies[i].getPath());
+        }
+        String rhnames[] = response.getHeaderNames();
+        for (int i = 0; i < rhnames.length; i++) {
+            String rhvalues[] = response.getHeaderValues(rhnames[i]);
+            for (int j = 0; j < rhvalues.length; j++)
+                log.info("            header=" + rhnames[i] + "=" + rhvalues[j]);
+        }
+        log.info("           message=" + response.getMessage());
+        log.info("        remoteUser=" + request.getRemoteUser());
+        log.info("            status=" + response.getStatus());
+        log.info("===============================================================");
+
+    }
+
+
+    /**
+     * Return a String rendering of this object.
+     */
+    public String toString() {
+
+        StringBuffer sb = new StringBuffer("RequestDumperValve[");
+        if (container != null)
+            sb.append(container.getName());
+        sb.append("]");
+        return (sb.toString());
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/valves/RequestFilterValve.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/valves/RequestFilterValve.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/valves/RequestFilterValve.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,292 @@
+/*
+ * Copyright 1999-2001,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.io.IOException;
+import java.util.ArrayList;
+import java.util.regex.Pattern;
+import java.util.regex.PatternSyntaxException;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.catalina.connector.Request;
+import org.apache.catalina.connector.Response;
+import org.apache.catalina.util.StringManager;
+import org.apache.tomcat.util.compat.JdkCompat;
+
+/**
+ * Implementation of a Valve that performs filtering based on comparing the
+ * appropriate request property (selected based on which subclass you choose
+ * to configure into your Container's pipeline) against a set of regular
+ * expressions configured for this Valve.
+ * <p>
+ * This valve is configured by setting the <code>allow</code> and/or
+ * <code>deny</code> properties to a comma-delimited list of regular
+ * expressions (in the syntax supported by the jakarta-regexp library) to
+ * which the appropriate request property will be compared.  Evaluation
+ * proceeds as follows:
+ * <ul>
+ * <li>The subclass extracts the request property to be filtered, and
+ *     calls the common <code>process()</code> method.
+ * <li>If there are any deny expressions configured, the property will
+ *     be compared to each such expression.  If a match is found, this
+ *     request will be rejected with a "Forbidden" HTTP response.</li>
+ * <li>If there are any allow expressions configured, the property will
+ *     be compared to each such expression.  If a match is found, this
+ *     request will be allowed to pass through to the next Valve in the
+ *     current pipeline.</li>
+ * <li>If one or more deny expressions was specified but no allow expressions,
+ *     allow this request to pass through (because none of the deny
+ *     expressions matched it).
+ * <li>The request will be rejected with a "Forbidden" HTTP response.</li>
+ * </ul>
+ * <p>
+ * This Valve may be attached to any Container, depending on the granularity
+ * of the filtering you wish to perform.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 303161 $ $Date: 2004-09-01 05:10:10 -0500 (Wed, 01 Sep 2004) $
+ */
+
+public abstract class RequestFilterValve
+    extends ValveBase {
+
+
+    // ----------------------------------------------------- Class Variables
+
+
+    /**
+     * JDK compatibility support
+     */
+    private static final JdkCompat jdkCompat = JdkCompat.getJdkCompat();
+
+
+    /**
+     * The descriptive information related to this implementation.
+     */
+    private static final String info =
+        "org.apache.catalina.valves.RequestFilterValve/1.0";
+
+
+    /**
+     * The StringManager for this package.
+     */
+    protected static StringManager sm =
+        StringManager.getManager(Constants.Package);
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The comma-delimited set of <code>allow</code> expressions.
+     */
+    protected String allow = null;
+
+
+    /**
+     * The set of <code>allow</code> regular expressions we will evaluate.
+     */
+    protected Pattern allows[] = new Pattern[0];
+
+
+    /**
+     * The set of <code>deny</code> regular expressions we will evaluate.
+     */
+    protected Pattern denies[] = new Pattern[0];
+
+
+    /**
+     * The comma-delimited set of <code>deny</code> expressions.
+     */
+    protected String deny = null;
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * Return a comma-delimited set of the <code>allow</code> expressions
+     * configured for this Valve, if any; otherwise, return <code>null</code>.
+     */
+    public String getAllow() {
+
+        return (this.allow);
+
+    }
+
+
+    /**
+     * Set the comma-delimited set of the <code>allow</code> expressions
+     * configured for this Valve, if any.
+     *
+     * @param allow The new set of allow expressions
+     */
+    public void setAllow(String allow) {
+
+        this.allow = allow;
+        allows = precalculate(allow);
+
+    }
+
+
+    /**
+     * Return a comma-delimited set of the <code>deny</code> expressions
+     * configured for this Valve, if any; otherwise, return <code>null</code>.
+     */
+    public String getDeny() {
+
+        return (this.deny);
+
+    }
+
+
+    /**
+     * Set the comma-delimited set of the <code>deny</code> expressions
+     * configured for this Valve, if any.
+     *
+     * @param deny The new set of deny expressions
+     */
+    public void setDeny(String deny) {
+
+        this.deny = deny;
+        denies = precalculate(deny);
+
+    }
+
+
+    /**
+     * Return descriptive information about this Valve implementation.
+     */
+    public String getInfo() {
+
+        return (info);
+
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Extract the desired request property, and pass it (along with the
+     * specified request and response objects) to the protected
+     * <code>process()</code> method to perform the actual filtering.
+     * This method must be implemented by a concrete subclass.
+     *
+     * @param request The servlet request to be processed
+     * @param response The servlet response to be created
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception ServletException if a servlet error occurs
+     */
+    public abstract void invoke(Request request, Response response)
+        throws IOException, ServletException;
+
+
+    // ------------------------------------------------------ Protected Methods
+
+
+    /**
+     * Return an array of regular expression objects initialized from the
+     * specified argument, which must be <code>null</code> or a comma-delimited
+     * list of regular expression patterns.
+     *
+     * @param list The comma-separated list of patterns
+     *
+     * @exception IllegalArgumentException if one of the patterns has
+     *  invalid syntax
+     */
+    protected Pattern[] precalculate(String list) {
+
+        if (list == null)
+            return (new Pattern[0]);
+        list = list.trim();
+        if (list.length() < 1)
+            return (new Pattern[0]);
+        list += ",";
+
+        ArrayList reList = new ArrayList();
+        while (list.length() > 0) {
+            int comma = list.indexOf(',');
+            if (comma < 0)
+                break;
+            String pattern = list.substring(0, comma).trim();
+            try {
+                reList.add(Pattern.compile(pattern));
+            } catch (PatternSyntaxException e) {
+                IllegalArgumentException iae = new IllegalArgumentException
+                    (sm.getString("requestFilterValve.syntax", pattern));
+                jdkCompat.chainException(iae, e);
+                throw iae;
+            }
+            list = list.substring(comma + 1);
+        }
+
+        Pattern reArray[] = new Pattern[reList.size()];
+        return ((Pattern[]) reList.toArray(reArray));
+
+    }
+
+
+    /**
+     * Perform the filtering that has been configured for this Valve, matching
+     * against the specified request property.
+     *
+     * @param property The request property on which to filter
+     * @param request The servlet request to be processed
+     * @param response The servlet response to be processed
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception ServletException if a servlet error occurs
+     */
+    protected void process(String property,
+                           Request request, Response response)
+        throws IOException, ServletException {
+
+        // Check the deny patterns, if any
+        for (int i = 0; i < denies.length; i++) {
+            if (denies[i].matcher(property).matches()) {
+                response.sendError(HttpServletResponse.SC_FORBIDDEN);
+                return;
+            }
+        }
+
+        // Check the allow patterns, if any
+        for (int i = 0; i < allows.length; i++) {
+            if (allows[i].matcher(property).matches()) {
+                getNext().invoke(request, response);
+                return;
+            }
+        }
+
+        // Allow if denies specified but not allows
+        if ((denies.length > 0) && (allows.length == 0)) {
+            getNext().invoke(request, response);
+            return;
+        }
+
+        // Deny this request
+        response.sendError(HttpServletResponse.SC_FORBIDDEN);
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/valves/SemaphoreValve.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/valves/SemaphoreValve.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/valves/SemaphoreValve.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,276 @@
+/*
+ * Copyright 1999-2001,2005 The Apache Software Foundation.
+ * 
+ * Licensed 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.io.IOException;
+import java.util.concurrent.Semaphore;
+
+import javax.servlet.ServletException;
+
+import org.apache.catalina.Lifecycle;
+import org.apache.catalina.LifecycleException;
+import org.apache.catalina.LifecycleListener;
+import org.apache.catalina.connector.Request;
+import org.apache.catalina.connector.Response;
+import org.apache.catalina.util.LifecycleSupport;
+import org.apache.catalina.util.StringManager;
+
+
+/**
+ * <p>Implementation of a Valve that limits concurrency.</p>
+ *
+ * <p>This Valve may be attached to any Container, depending on the granularity
+ * of the concurrency control you wish to perform.</p>
+ *
+ * @author Remy Maucherat
+ * @version $Revision: 386404 $ $Date: 2006-03-16 11:50:37 -0600 (Thu, 16 Mar 2006) $
+ */
+
+public class SemaphoreValve
+    extends ValveBase
+    implements Lifecycle {
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The descriptive information related to this implementation.
+     */
+    private static final String info =
+        "org.apache.catalina.valves.SemaphoreValve/1.0";
+
+
+    /**
+     * The string manager for this package.
+     */
+    private StringManager sm =
+        StringManager.getManager(Constants.Package);
+
+
+    /**
+     * Semaphore.
+     */
+    protected Semaphore semaphore = null;
+    
+
+    /**
+     * The lifecycle event support for this component.
+     */
+    protected LifecycleSupport lifecycle = new LifecycleSupport(this);
+
+
+    /**
+     * Has this component been started yet?
+     */
+    private boolean started = false;
+
+
+    // ------------------------------------------------------------- Properties
+
+    
+    /**
+     * Concurrency level of the semaphore.
+     */
+    protected int concurrency = 10;
+    public int getConcurrency() { return concurrency; }
+    public void setConcurrency(int concurrency) { this.concurrency = concurrency; }
+    
+
+    /**
+     * Fairness of the semaphore.
+     */
+    protected boolean fairness = false;
+    public boolean getFairness() { return fairness; }
+    public void setFairness(boolean fairness) { this.fairness = fairness; }
+    
+
+    /**
+     * Block until a permit is available.
+     */
+    protected boolean block = true;
+    public boolean getBlock() { return block; }
+    public void setBlock(boolean block) { this.block = block; }
+    
+
+    /**
+     * Block interruptibly until a permit is available.
+     */
+    protected boolean interruptible = false;
+    public boolean getInterruptible() { return interruptible; }
+    public void setInterruptible(boolean interruptible) { this.interruptible = interruptible; }
+    
+
+    // ------------------------------------------------------ Lifecycle Methods
+
+
+    /**
+     * Add a lifecycle event listener to this component.
+     *
+     * @param listener The listener to add
+     */
+    public void addLifecycleListener(LifecycleListener listener) {
+
+        lifecycle.addLifecycleListener(listener);
+
+    }
+
+
+    /**
+     * Get the lifecycle listeners associated with this lifecycle. If this
+     * Lifecycle has no listeners registered, a zero-length array is returned.
+     */
+    public LifecycleListener[] findLifecycleListeners() {
+
+        return lifecycle.findLifecycleListeners();
+
+    }
+
+
+    /**
+     * Remove a lifecycle event listener from this component.
+     *
+     * @param listener The listener to add
+     */
+    public void removeLifecycleListener(LifecycleListener listener) {
+
+        lifecycle.removeLifecycleListener(listener);
+
+    }
+
+
+    /**
+     * Prepare for the beginning of active use of the public methods of this
+     * component.  This method should be called after <code>configure()</code>,
+     * and before any of the public methods of the component are utilized.
+     *
+     * @exception LifecycleException if this component detects a fatal error
+     *  that prevents this component from being used
+     */
+    public void start() throws LifecycleException {
+
+        // Validate and update our current component state
+        if (started)
+            throw new LifecycleException
+                (sm.getString("semaphoreValve.alreadyStarted"));
+        lifecycle.fireLifecycleEvent(START_EVENT, null);
+        started = true;
+
+        semaphore = new Semaphore(concurrency, fairness);
+
+    }
+
+
+    /**
+     * Gracefully terminate the active use of the public methods of this
+     * component.  This method should be the last one called on a given
+     * instance of this component.
+     *
+     * @exception LifecycleException if this component detects a fatal error
+     *  that needs to be reported
+     */
+    public void stop() throws LifecycleException {
+
+        // Validate and update our current component state
+        if (!started)
+            throw new LifecycleException
+                (sm.getString("semaphoreValve.notStarted"));
+        lifecycle.fireLifecycleEvent(STOP_EVENT, null);
+        started = false;
+
+        semaphore = null;
+
+    }
+
+    
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Return descriptive information about this Valve implementation.
+     */
+    public String getInfo() {
+        return (info);
+    }
+
+
+    /**
+     * Do concurrency control on the request using the semaphore.
+     *
+     * @param request The servlet request to be processed
+     * @param response The servlet response to be created
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception ServletException if a servlet error occurs
+     */
+    public void invoke(Request request, Response response)
+        throws IOException, ServletException {
+
+        if (controlConcurrency(request, response)) {
+            boolean shouldRelease = true;
+            try {
+                if (block) {
+                    if (interruptible) {
+                        try {
+                            semaphore.acquire();
+                        } catch (InterruptedException e) {
+                            shouldRelease = false;
+                            permitDenied(request, response);
+                            return;
+                        }  
+                    } else {
+                        semaphore.acquireUninterruptibly();
+                    }
+                } else {
+                    if (!semaphore.tryAcquire()) {
+                        shouldRelease = false;
+                        permitDenied(request, response);
+                        return;
+                    }
+                }
+                getNext().invoke(request, response);
+            } finally {
+                if (shouldRelease) {
+                    semaphore.release();
+                }
+            }
+        } else {
+            getNext().invoke(request, response);
+        }
+
+    }
+
+    
+    /**
+     * Subclass friendly method to add conditions.
+     */
+    public boolean controlConcurrency(Request request, Response response) {
+        return true;
+    }
+    
+
+    /**
+     * Subclass friendly method to add error handling when a permit isn't granted.
+     */
+    public void permitDenied(Request request, Response response)
+        throws IOException, ServletException {
+    }
+    
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/valves/ValveBase.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/valves/ValveBase.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/valves/ValveBase.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,320 @@
+/*
+ * Copyright 1999-2001,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.io.IOException;
+
+import javax.management.MBeanRegistration;
+import javax.management.MBeanServer;
+import javax.management.MalformedObjectNameException;
+import javax.management.ObjectName;
+import javax.servlet.ServletException;
+
+import org.apache.catalina.Contained;
+import org.apache.catalina.Container;
+import org.apache.catalina.Context;
+import org.apache.catalina.Engine;
+import org.apache.catalina.Host;
+import org.apache.catalina.Pipeline;
+import org.apache.catalina.Valve;
+import org.apache.catalina.Wrapper;
+import org.apache.catalina.connector.Request;
+import org.apache.catalina.connector.Response;
+import org.apache.catalina.core.ContainerBase;
+import org.apache.catalina.util.StringManager;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+
+/**
+ * Convenience base class for implementations of the <b>Valve</b> interface.
+ * A subclass <strong>MUST</strong> implement an <code>invoke()</code>
+ * method to provide the required functionality, and <strong>MAY</strong>
+ * implement the <code>Lifecycle</code> interface to provide configuration
+ * management and lifecycle support.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 304023 $ $Date: 2005-07-26 07:45:22 -0500 (Tue, 26 Jul 2005) $
+ */
+
+public abstract class ValveBase
+    implements Contained, Valve, MBeanRegistration {
+    private static Log log = LogFactory.getLog(ValveBase.class);
+
+    //------------------------------------------------------ Instance Variables
+
+
+    /**
+     * The Container whose pipeline this Valve is a component of.
+     */
+    protected Container container = null;
+
+
+    /**
+     * Container log
+     */
+    protected Log containerLog = null;
+
+
+    /**
+     * Descriptive information about this Valve implementation.  This value
+     * should be overridden by subclasses.
+     */
+    protected static String info =
+        "org.apache.catalina.core.ValveBase/1.0";
+
+
+    /**
+     * The next Valve in the pipeline this Valve is a component of.
+     */
+    protected Valve next = null;
+
+
+    /**
+     * The string manager for this package.
+     */
+    protected final static StringManager sm =
+        StringManager.getManager(Constants.Package);
+
+
+    //-------------------------------------------------------------- Properties
+
+
+    /**
+     * Return the Container with which this Valve is associated, if any.
+     */
+    public Container getContainer() {
+
+        return (container);
+
+    }
+
+
+    /**
+     * Set the Container with which this Valve is associated, if any.
+     *
+     * @param container The new associated container
+     */
+    public void setContainer(Container container) {
+
+        this.container = container;
+
+    }
+
+
+    /**
+     * Return descriptive information about this Valve implementation.
+     */
+    public String getInfo() {
+
+        return (info);
+
+    }
+
+
+    /**
+     * Return the next Valve in this pipeline, or <code>null</code> if this
+     * is the last Valve in the pipeline.
+     */
+    public Valve getNext() {
+
+        return (next);
+
+    }
+
+
+    /**
+     * Set the Valve that follows this one in the pipeline it is part of.
+     *
+     * @param valve The new next valve
+     */
+    public void setNext(Valve valve) {
+
+        this.next = valve;
+
+    }
+
+
+    //---------------------------------------------------------- Public Methods
+
+
+    /**
+     * Execute a periodic task, such as reloading, etc. This method will be
+     * invoked inside the classloading context of this container. Unexpected
+     * throwables will be caught and logged.
+     */
+    public void backgroundProcess() {
+    }
+
+
+    /**
+     * The implementation-specific logic represented by this Valve.  See the
+     * Valve description for the normal design patterns for this method.
+     * <p>
+     * This method <strong>MUST</strong> be provided by a subclass.
+     *
+     * @param request The servlet request to be processed
+     * @param response The servlet response to be created
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception ServletException if a servlet error occurs
+     */
+    public abstract void invoke(Request request, Response response)
+        throws IOException, ServletException;
+
+
+    /**
+     * Return a String rendering of this object.
+     */
+    public String toString() {
+        StringBuffer sb = new StringBuffer(this.getClass().getName());
+        sb.append("[");
+        if (container != null)
+            sb.append(container.getName());
+        sb.append("]");
+        return (sb.toString());
+    }
+
+
+    // -------------------- JMX and Registration  --------------------
+    protected String domain;
+    protected ObjectName oname;
+    protected MBeanServer mserver;
+    protected ObjectName controller;
+
+    public ObjectName getObjectName() {
+        return oname;
+    }
+
+    public void setObjectName(ObjectName oname) {
+        this.oname = oname;
+    }
+
+    public String getDomain() {
+        return domain;
+    }
+
+    public ObjectName preRegister(MBeanServer server,
+                                  ObjectName name) throws Exception {
+        oname=name;
+        mserver=server;
+        domain=name.getDomain();
+
+
+        return name;
+    }
+
+    public void postRegister(Boolean registrationDone) {
+    }
+
+    public void preDeregister() throws Exception {
+    }
+
+    public void postDeregister() {
+    }
+
+    public ObjectName getController() {
+        return controller;
+    }
+
+    public void setController(ObjectName controller) {
+        this.controller = controller;
+    }
+
+    /** From the name, extract the parent object name
+     *
+     * @param valveName The valve name
+     * @return ObjectName The parent name
+     */
+    public ObjectName getParentName( ObjectName valveName ) {
+
+        return null;
+    }
+
+    public ObjectName createObjectName(String domain, ObjectName parent)
+            throws MalformedObjectNameException
+    {
+        Container container=this.getContainer();
+        if( container == null || ! (container instanceof ContainerBase) )
+            return null;
+        this.containerLog = container.getLogger();
+        ContainerBase containerBase=(ContainerBase)container;
+        Pipeline pipe=containerBase.getPipeline();
+        Valve valves[]=pipe.getValves();
+
+        /* Compute the "parent name" part */
+        String parentName="";
+        if (container instanceof Engine) {
+        } else if (container instanceof Host) {
+            parentName=",host=" +container.getName();
+        } else if (container instanceof Context) {
+                    String path = ((Context)container).getPath();
+                    if (path.length() < 1) {
+                        path = "/";
+                    }
+                    Host host = (Host) container.getParent();
+                    parentName=",path=" + path + ",host=" +
+                            host.getName();
+        } else if (container instanceof Wrapper) {
+            Context ctx = (Context) container.getParent();
+            String path = ctx.getPath();
+            if (path.length() < 1) {
+                path = "/";
+            }
+            Host host = (Host) ctx.getParent();
+            parentName=",servlet=" + container.getName() +
+                    ",path=" + path + ",host=" + host.getName();
+        }
+        log.debug("valve parent=" + parentName + " " + parent);
+
+        String className=this.getClass().getName();
+        int period = className.lastIndexOf('.');
+        if (period >= 0)
+            className = className.substring(period + 1);
+
+        int seq=0;
+        for( int i=0; i<valves.length; i++ ) {
+            // Find other valves with the same name
+            if (valves[i] == this) {
+                break;
+            }
+            if( valves[i]!=null &&
+                    valves[i].getClass() == this.getClass() ) {
+                log.debug("Duplicate " + valves[i] + " " + this + " " + container);
+                seq++;
+            }
+        }
+        String ext="";
+        if( seq > 0 ) {
+            ext=",seq=" + seq;
+        }
+
+        ObjectName objectName = 
+            new ObjectName( domain + ":type=Valve,name=" + className + ext + parentName);
+        log.debug("valve objectname = "+objectName);
+        return objectName;
+    }
+
+    // -------------------- JMX data  --------------------
+
+    public ObjectName getContainerName() {
+        if( container== null) return null;
+        return ((ContainerBase)container).getJmxName();
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/valves/mbeans-descriptors.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/valves/mbeans-descriptors.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/valves/mbeans-descriptors.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,292 @@
+<?xml version="1.0"?>
+<mbeans-descriptors>
+
+  <mbean name="AccessLogValve"
+         description="Valve that generates a web server access log"
+         domain="Catalina"
+         group="Valve"
+         type="org.apache.catalina.valves.AccessLogValve">
+
+    <attribute name="className"
+               description="Fully qualified class name of the managed object"
+               type="java.lang.String"
+               writeable="false"/>
+
+    <attribute name="containerName"
+               description="Object name of the container"
+               type="javax.management.ObjectName"/>
+
+    <attribute name="directory"
+               description="The directory in which log files are created"
+               type="java.lang.String"/>
+
+    <attribute   name="pattern"
+               description="The pattern used to format our access log lines"
+               type="java.lang.String"/>
+
+    <attribute name="prefix"
+               description="The prefix that is added to log file filenames"
+               type="java.lang.String"/>
+
+    <attribute name="resolveHosts"
+               description="Resolve hosts"
+               is="true"
+               type="boolean"/>
+
+    <attribute name="rotatable"
+               description="Flag to indicate automatic log rotation."
+               is="true"
+               type="boolean"/>
+
+    <attribute name="suffix"
+               description="The suffix that is added to log file filenames"
+               type="java.lang.String"/>
+
+    <attribute name="condition"
+               description="The value to look for conditional logging."
+               type="java.lang.String"/>
+
+    <attribute name="fileDateFormat"
+               description="The format for the date date based log rotation."
+               type="java.lang.String"/>
+  </mbean>
+
+  <mbean name="ErrorReportValve"
+         description="Implementation of a Valve that outputs HTML error pages"
+         domain="Catalina"
+         group="Valve"
+         type="org.apache.catalina.valves.ErrorReportValve">
+
+    <attribute name="className"
+               description="Fully qualified class name of the managed object"
+               type="java.lang.String"
+               writeable="false"/>
+
+    <attribute name="containerName"
+               description="Object name of the container"
+               type="javax.management.ObjectName"/>
+
+  </mbean>
+
+  <mbean name="ExtendedAccessLogValve"
+         description="Valve that generates a web server access log"
+         domain="Catalina"
+         group="Valve"
+         type="org.apache.catalina.valves.ExtendedAccessLogValve">
+
+    <attribute name="className"
+               description="Fully qualified class name of the managed object"
+               type="java.lang.String"
+               writeable="false"/>
+
+    <attribute name="containerName"
+               description="Object name of the container"
+               type="javax.management.ObjectName"/>
+
+    <attribute name="directory"
+               description="The directory in which log files are created"
+               type="java.lang.String"/>
+
+    <attribute   name="pattern"
+               description="The pattern used to format our access log lines"
+               type="java.lang.String"/>
+
+    <attribute name="prefix"
+               description="The prefix that is added to log file filenames"
+               type="java.lang.String"/>
+
+    <attribute name="rotatable"
+               description="Rotate log"
+               is="true"
+               type="boolean"/>
+
+    <attribute name="condition"
+               description="The value to look for conditional logging."
+               type="java.lang.String"/>
+
+    <attribute name="checkExists"
+               description="Check for file existence before each logging."
+               is="true"
+               type="boolean"/>
+
+    <attribute name="suffix"
+               description="The suffix that is added to log file filenames"
+               type="java.lang.String"/>
+
+    <attribute name="fileDateFormat"
+               description="The format for the date date based log rotation."
+               type="java.lang.String"/>
+
+    <operation name="rotate"
+               description="Move the existing log file to a new name"
+               impact="ACTION"
+               returnType="boolean">
+      <parameter name="newFileName"
+                 description="File name to move the log file to."
+                 type="java.lang.String"/>
+    </operation>
+
+  </mbean>
+
+  <mbean name="FastCommonAccessLogValve"
+         description="Valve that generates a web server access log"
+         domain="Catalina"
+         group="Valve"
+         type="org.apache.catalina.valves.FastCommonAccessLogValve">
+
+    <attribute name="className"
+               description="Fully qualified class name of the managed object"
+               type="java.lang.String"
+               writeable="false"/>
+
+    <attribute name="containerName"
+               description="Object name of the container"
+               type="javax.management.ObjectName"/>
+
+    <attribute name="directory"
+               description="The directory in which log files are created"
+               type="java.lang.String"/>
+
+    <attribute   name="pattern"
+               description="The pattern used to format our access log lines, which must be either common or combined"
+               type="java.lang.String"/>
+
+    <attribute name="prefix"
+               description="The prefix that is added to log file filenames"
+               type="java.lang.String"/>
+
+    <attribute name="resolveHosts"
+               description="Resolve hosts"
+               is="true"
+               type="boolean"/>
+
+    <attribute name="rotatable"
+               description="Flag to indicate automatic log rotation."
+               is="true"
+               type="boolean"/>
+
+    <attribute name="suffix"
+               description="The suffix that is added to log file filenames"
+               type="java.lang.String"/>
+
+    <attribute name="condition"
+               description="The value to look for conditional logging."
+               type="java.lang.String"/>
+
+    <attribute name="fileDateFormat"
+               description="The format for the date date based log rotation."
+               type="java.lang.String"/>
+  </mbean>
+
+  <mbean name="SemaphoreValve"
+         description="Valve that does concurrency control"
+         domain="Catalina"
+         group="Valve"
+         type="org.apache.catalina.valves.SemaphoreValve">
+
+    <attribute name="className"
+               description="Fully qualified class name of the managed object"
+               type="java.lang.String"
+               writeable="false"/>
+
+    <attribute name="containerName"
+               description="Object name of the container"
+               type="javax.management.ObjectName"/>
+
+    <attribute name="concurrency"
+               description="Desired concurrency level"
+               type="int"/>
+
+    <attribute name="fairness"
+               description="Use a fair semaphore"
+               type="boolean"/>
+
+  </mbean>
+
+  <mbean name="RemoteAddrValve"
+         description="Concrete implementation of RequestFilterValve that  filters based on the string representation of the remote client's IP address"
+         domain="Catalina"
+         group="Valve"
+         type="org.apache.catalina.valves.RemoteAddrValve">
+
+    <attribute name="allow"
+               description="The comma-delimited set of allow expressions"
+               type="java.lang.String"/>
+
+    <attribute name="containerName"
+               description="Object name of the container"
+               type="javax.management.ObjectName"/>
+
+    <attribute   name="className"
+               description="Fully qualified class name of the managed object"
+               type="java.lang.String"
+               writeable="false"/>
+
+    <attribute   name="deny"
+               description="The comma-delimited set of deny expressions"
+               type="java.lang.String"/>
+
+  </mbean>
+
+  <mbean name="RemoteHostValve"
+         description="Concrete implementation of RequestFilterValve that
+         filters based on the string representation of the remote
+         client's host name"
+         domain="Catalina"
+         group="Valve"
+         type="org.apache.catalina.valves.RemoteHostValve">
+
+    <attribute   name="allow"
+               description="The comma-delimited set of allow expressions"
+               type="java.lang.String"/>
+
+    <attribute name="containerName"
+               description="Object name of the container"
+               type="javax.management.ObjectName"/>
+
+    <attribute   name="className"
+               description="Fully qualified class name of the managed object"
+               type="java.lang.String"
+               writeable="false"/>
+
+    <attribute   name="deny"
+               description="The comma-delimited set of deny expressions"
+               type="java.lang.String"/>
+
+  </mbean>
+
+  <mbean name="RequestDumperValve"
+         description="Implementation of a Valve that logs interesting contents from the specified Request and the corresponding Response"
+         domain="Catalina"
+         group="Valve"
+         type="org.apache.catalina.valves.RequestDumperValve">
+
+    <attribute name="containerName"
+               description="Object name of the container"
+               type="javax.management.ObjectName"/>
+
+    <attribute name="className"
+               description="Fully qualified class name of the managed object"
+               type="java.lang.String"
+               writeable="false"/>
+
+  </mbean>
+
+  <mbean name="RequestListenerValve"
+         description="Valve that handles request initialization and destroy events"
+         domain="Catalina"
+         group="Valve"
+         type="org.apache.catalina.valves.RequestListenerValve">
+
+    <attribute   name="className"
+               description="Fully qualified class name of the managed object"
+               type="java.lang.String"
+               writeable="false"/>
+
+    <attribute name="containerName"
+               description="Object name of the container"
+               type="javax.management.ObjectName"/>
+
+  </mbean>
+
+</mbeans-descriptors>

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/valves/package.html
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/valves/package.html	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/catalina/valves/package.html	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,12 @@
+<body>
+
+<p>This package contains a variety of small Valve implementations that do
+not warrant being packaged separately.  In addition, there is a convenience
+base class (<code>ValveBase</code>) that supports the usual mechanisms for
+including custom Valves into the corresponding Pipeline.</p>
+
+<p>Other packages that include Valves include
+<code>org.apache.tomcat.logger</code> and
+<code>org.apache.tomcat.security</code>.</p>
+
+</body>

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/Constants.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/Constants.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/Constants.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,29 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.naming;
+
+
+/**
+ * Static constants for this package.
+ */
+
+public final class Constants {
+
+    public static final String Package = "org.apache.naming";
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/ContextAccessController.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/ContextAccessController.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/ContextAccessController.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,128 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.naming;
+
+import java.util.Hashtable;
+
+/**
+ * Handles the access control on the JNDI contexts.
+ *
+ * @author Remy Maucherat
+ * @version $Revision: 303133 $ $Date: 2004-08-29 11:46:15 -0500 (Sun, 29 Aug 2004) $
+ */
+
+public class ContextAccessController {
+
+
+    // -------------------------------------------------------------- Variables
+
+
+    /**
+     * Catalina context names on which writing is not allowed.
+     */
+    private static Hashtable readOnlyContexts = new Hashtable();
+
+
+    /**
+     * Security tokens repository.
+     */
+    private static Hashtable securityTokens = new Hashtable();
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Set a security token for a context. Can be set only once.
+     * 
+     * @param name Name of the context
+     * @param token Security token
+     */
+    public static void setSecurityToken(Object name, Object token) {
+        if ((!securityTokens.containsKey(name)) && (token != null)) {
+            securityTokens.put(name, token);
+        }
+    }
+
+
+    /**
+     * Remove a security token for a context.
+     * 
+     * @param name Name of the context
+     * @param token Security token
+     */
+    public static void unsetSecurityToken(Object name, Object token) {
+        if (checkSecurityToken(name, token)) {
+            securityTokens.remove(name);
+        }
+    }
+
+
+    /**
+     * Check a submitted security token. The submitted token must be equal to
+     * the token present in the repository. If no token is present for the 
+     * context, then returns true.
+     * 
+     * @param name Name of the context
+     * @param token Submitted security token
+     */
+    public static boolean checkSecurityToken
+        (Object name, Object token) {
+        Object refToken = securityTokens.get(name);
+        if (refToken == null)
+            return (true);
+        if ((refToken != null) && (refToken.equals(token)))
+            return (true);
+        return (false);
+    }
+
+
+    /**
+     * Allow writing to a context.
+     * 
+     * @param name Name of the context
+     * @param token Security token
+     */
+    public static void setWritable(Object name, Object token) {
+        if (checkSecurityToken(name, token))
+            readOnlyContexts.remove(name);
+    }
+
+
+    /**
+     * Set whether or not a context is writable.
+     * 
+     * @param name Name of the context
+     */
+    public static void setReadOnly(Object name) {
+        readOnlyContexts.put(name, name);
+    }
+
+
+    /**
+     * Returns if a context is writable.
+     * 
+     * @param name Name of the context
+     */
+    public static boolean isWritable(Object name) {
+        return !(readOnlyContexts.containsKey(name));
+    }
+
+
+}
+

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/ContextBindings.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/ContextBindings.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/ContextBindings.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,362 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.naming;
+
+import java.util.Hashtable;
+import javax.naming.NamingException;
+import javax.naming.Context;
+
+/**
+ * Handles the associations :
+ * <ul>
+ * <li>Catalina context name with the NamingContext</li>
+ * <li>Calling thread with the NamingContext</li>
+ * </ul>
+ *
+ * @author Remy Maucherat
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class ContextBindings {
+
+
+    // -------------------------------------------------------------- Variables
+
+
+    /**
+     * Bindings name - naming context. Keyed by name.
+     */
+    private static Hashtable contextNameBindings = new Hashtable();
+
+
+    /**
+     * Bindings thread - naming context. Keyed by thread id.
+     */
+    private static Hashtable threadBindings = new Hashtable();
+
+
+    /**
+     * Bindings thread - name. Keyed by thread id.
+     */
+    private static Hashtable threadNameBindings = new Hashtable();
+
+
+    /**
+     * Bindings class loader - naming context. Keyed by CL id.
+     */
+    private static Hashtable clBindings = new Hashtable();
+
+
+    /**
+     * Bindings class loader - name. Keyed by CL id.
+     */
+    private static Hashtable clNameBindings = new Hashtable();
+
+
+    /**
+     * The string manager for this package.
+     */
+    protected static StringManager sm = 
+        StringManager.getManager(Constants.Package);
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Binds a context name.
+     * 
+     * @param name Name of the context
+     * @param context Associated naming context instance
+     */
+    public static void bindContext(Object name, Context context) {
+        bindContext(name, context, null);
+    }
+
+
+    /**
+     * Binds a context name.
+     * 
+     * @param name Name of the context
+     * @param context Associated naming context instance
+     * @param token Security token
+     */
+    public static void bindContext(Object name, Context context, 
+                                   Object token) {
+        if (ContextAccessController.checkSecurityToken(name, token))
+            contextNameBindings.put(name, context);
+    }
+
+
+    /**
+     * Unbind context name.
+     * 
+     * @param name Name of the context
+     */
+    public static void unbindContext(Object name) {
+        unbindContext(name, null);
+    }
+
+
+    /**
+     * Unbind context name.
+     * 
+     * @param name Name of the context
+     * @param token Security token
+     */
+    public static void unbindContext(Object name, Object token) {
+        if (ContextAccessController.checkSecurityToken(name, token))
+            contextNameBindings.remove(name);
+    }
+
+
+    /**
+     * Retrieve a naming context.
+     * 
+     * @param name Name of the context
+     */
+    static Context getContext(Object name) {
+        return (Context) contextNameBindings.get(name);
+    }
+
+
+    /**
+     * Binds a naming context to a thread.
+     * 
+     * @param name Name of the context
+     */
+    public static void bindThread(Object name) 
+        throws NamingException {
+        bindThread(name, null);
+    }
+
+
+    /**
+     * Binds a naming context to a thread.
+     * 
+     * @param name Name of the context
+     * @param token Security token
+     */
+    public static void bindThread(Object name, Object token) 
+        throws NamingException {
+        if (ContextAccessController.checkSecurityToken(name, token)) {
+            Context context = (Context) contextNameBindings.get(name);
+            if (context == null)
+                throw new NamingException
+                    (sm.getString("contextBindings.unknownContext", name));
+            threadBindings.put(Thread.currentThread(), context);
+            threadNameBindings.put(Thread.currentThread(), name);
+        }
+    }
+
+
+    /**
+     * Unbinds a naming context to a thread.
+     * 
+     * @param name Name of the context
+     */
+    public static void unbindThread(Object name) {
+        unbindThread(name, null);
+    }
+
+
+    /**
+     * Unbinds a naming context to a thread.
+     * 
+     * @param name Name of the context
+     * @param token Security token
+     */
+    public static void unbindThread(Object name, Object token) {
+        if (ContextAccessController.checkSecurityToken(name, token)) {
+            threadBindings.remove(Thread.currentThread());
+            threadNameBindings.remove(Thread.currentThread());
+        }
+    }
+
+
+    /**
+     * Retrieves the naming context bound to a thread.
+     */
+    public static Context getThread()
+        throws NamingException {
+        Context context = 
+            (Context) threadBindings.get(Thread.currentThread());
+        if (context == null)
+            throw new NamingException
+                (sm.getString("contextBindings.noContextBoundToThread"));
+        return context;
+    }
+
+
+    /**
+     * Retrieves the naming context name bound to a thread.
+     */
+    static Object getThreadName()
+        throws NamingException {
+        Object name = threadNameBindings.get(Thread.currentThread());
+        if (name == null)
+            throw new NamingException
+                (sm.getString("contextBindings.noContextBoundToThread"));
+        return name;
+    }
+
+
+    /**
+     * Tests if current thread is bound to a context.
+     */
+    public static boolean isThreadBound() {
+        return (threadBindings.containsKey(Thread.currentThread()));
+    }
+
+
+    /**
+     * Binds a naming context to a class loader.
+     * 
+     * @param name Name of the context
+     */
+    public static void bindClassLoader(Object name) 
+        throws NamingException {
+        bindClassLoader(name, null);
+    }
+
+
+    /**
+     * Binds a naming context to a thread.
+     * 
+     * @param name Name of the context
+     * @param token Security token
+     */
+    public static void bindClassLoader(Object name, Object token) 
+        throws NamingException {
+        bindClassLoader
+            (name, token, Thread.currentThread().getContextClassLoader());
+    }
+
+
+    /**
+     * Binds a naming context to a thread.
+     * 
+     * @param name Name of the context
+     * @param token Security token
+     */
+    public static void bindClassLoader(Object name, Object token, 
+                                       ClassLoader classLoader) 
+        throws NamingException {
+        if (ContextAccessController.checkSecurityToken(name, token)) {
+            Context context = (Context) contextNameBindings.get(name);
+            if (context == null)
+                throw new NamingException
+                    (sm.getString("contextBindings.unknownContext", name));
+            clBindings.put(classLoader, context);
+            clNameBindings.put(classLoader, name);
+        }
+    }
+
+
+    /**
+     * Unbinds a naming context to a class loader.
+     * 
+     * @param name Name of the context
+     */
+    public static void unbindClassLoader(Object name) {
+        unbindClassLoader(name, null);
+    }
+
+
+    /**
+     * Unbinds a naming context to a class loader.
+     * 
+     * @param name Name of the context
+     * @param token Security token
+     */
+    public static void unbindClassLoader(Object name, Object token) {
+        unbindClassLoader(name, token, 
+                          Thread.currentThread().getContextClassLoader());
+    }
+
+
+    /**
+     * Unbinds a naming context to a class loader.
+     * 
+     * @param name Name of the context
+     * @param token Security token
+     */
+    public static void unbindClassLoader(Object name, Object token, 
+                                         ClassLoader classLoader) {
+        if (ContextAccessController.checkSecurityToken(name, token)) {
+            Object n = clNameBindings.get(classLoader);
+            if ((n==null) || !(n.equals(name))) {
+                return;
+            }
+            clBindings.remove(classLoader);
+            clNameBindings.remove(classLoader);
+        }
+    }
+
+
+    /**
+     * Retrieves the naming context bound to a class loader.
+     */
+    public static Context getClassLoader()
+        throws NamingException {
+        ClassLoader cl = Thread.currentThread().getContextClassLoader();
+        Context context = null;
+        do {
+            context = (Context) clBindings.get(cl);
+            if (context != null) {
+                return context;
+            }
+        } while ((cl = cl.getParent()) != null);
+        throw new NamingException
+            (sm.getString("contextBindings.noContextBoundToCL"));
+    }
+
+
+    /**
+     * Retrieves the naming context name bound to a class loader.
+     */
+    static Object getClassLoaderName()
+        throws NamingException {
+        ClassLoader cl = Thread.currentThread().getContextClassLoader();
+        Object name = null;
+        do {
+            name = clNameBindings.get(cl);
+            if (name != null) {
+                return name;
+            }
+        } while ((cl = cl.getParent()) != null);
+        throw new NamingException
+            (sm.getString("contextBindings.noContextBoundToCL"));
+    }
+
+
+    /**
+     * Tests if current class loader is bound to a context.
+     */
+    public static boolean isClassLoaderBound() {
+        ClassLoader cl = Thread.currentThread().getContextClassLoader();
+        do {
+            if (clBindings.containsKey(cl)) {
+                return true;
+            }
+        } while ((cl = cl.getParent()) != null);
+        return false;
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/EjbRef.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/EjbRef.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/EjbRef.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,137 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.naming;
+
+import javax.naming.Context;
+import javax.naming.Reference;
+import javax.naming.StringRefAddr;
+
+/**
+ * Represents a reference address to an EJB.
+ *
+ * @author Remy Maucherat
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class EjbRef
+    extends Reference {
+
+
+    // -------------------------------------------------------------- Constants
+
+
+    /**
+     * Default factory for this reference.
+     */
+    public static final String DEFAULT_FACTORY = 
+        org.apache.naming.factory.Constants.DEFAULT_EJB_FACTORY;
+
+
+    /**
+     * EJB type address type.
+     */
+    public static final String TYPE = "type";
+
+
+    /**
+     * Remote interface classname address type.
+     */
+    public static final String REMOTE = "remote";
+
+
+    /**
+     * Link address type.
+     */
+    public static final String LINK = "link";
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * EJB Reference.
+     * 
+     * @param ejbType EJB type
+     * @param home Home interface classname
+     * @param remote Remote interface classname
+     * @param link EJB link
+     */
+    public EjbRef(String ejbType, String home, String remote, String link) {
+        this(ejbType, home, remote, link, null, null);
+    }
+
+
+    /**
+     * EJB Reference.
+     * 
+     * @param ejbType EJB type
+     * @param home Home interface classname
+     * @param remote Remote interface classname
+     * @param link EJB link
+     */
+    public EjbRef(String ejbType, String home, String remote, String link,
+                  String factory, String factoryLocation) {
+        super(home, factory, factoryLocation);
+        StringRefAddr refAddr = null;
+        if (ejbType != null) {
+            refAddr = new StringRefAddr(TYPE, ejbType);
+            add(refAddr);
+        }
+        if (remote != null) {
+            refAddr = new StringRefAddr(REMOTE, remote);
+            add(refAddr);
+        }
+        if (link != null) {
+            refAddr = new StringRefAddr(LINK, link);
+            add(refAddr);
+        }
+    }
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    // -------------------------------------------------------- RefAddr Methods
+
+
+    // ------------------------------------------------------ Reference Methods
+
+
+    /**
+     * Retrieves the class name of the factory of the object to which this 
+     * reference refers.
+     */
+    public String getFactoryClassName() {
+        String factory = super.getFactoryClassName();
+        if (factory != null) {
+            return factory;
+        } else {
+            factory = System.getProperty(Context.OBJECT_FACTORIES);
+            if (factory != null) {
+                return null;
+            } else {
+                return DEFAULT_FACTORY;
+            }
+        }
+    }
+
+
+    // ------------------------------------------------------------- Properties
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/JndiPermission.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/JndiPermission.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/JndiPermission.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,61 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.naming;
+
+import java.security.BasicPermission;
+
+/**
+ * Java SecurityManager Permission class for JNDI name based file resources
+ * <p>
+ * The JndiPermission extends the BasicPermission.
+ * The permission name is a full or partial jndi resource name.
+ * An * can be used at the end of the name to match all named
+ * resources that start with name.  There are no actions.</p>
+ * <p>
+ * Example that grants permission to read all JNDI file based resources:
+ * <li> permission org.apache.naming.JndiPermission "*";</li>
+ * </p>
+ *
+ * @author Glenn Nielsen
+ * @version $Revision: 303133 $ $Date: 2004-08-29 11:46:15 -0500 (Sun, 29 Aug 2004) $
+ */
+
+public final class JndiPermission extends BasicPermission {
+
+    // ----------------------------------------------------------- Constructors
+
+    /**
+     * Creates a new JndiPermission with no actions
+     *
+     * @param name - JNDI resource path name
+     */
+    public JndiPermission(String name) {
+        super(name);
+    }
+
+    /**
+     * Creates a new JndiPermission with actions
+     *
+     * @param name - JNDI resource path name
+     * @param actions - JNDI actions (none defined)
+     */
+    public JndiPermission(String name, String actions) {
+        super(name,actions);
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/LocalStrings.properties
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/LocalStrings.properties	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/LocalStrings.properties	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,11 @@
+contextBindings.unknownContext=Unknown context name : {0}
+contextBindings.noContextBoundToThread=No naming context bound to this thread
+contextBindings.noContextBoundToCL=No naming context bound to this class loader
+selectorContext.noJavaUrl=This context must be accessed throught a java: URL
+namingContext.contextExpected=Name is not bound to a Context
+namingContext.failResolvingReference=Unexpected exception resolving reference
+namingContext.nameNotBound=Name {0} is not bound in this Context
+namingContext.readOnly=Context is read only
+namingContext.invalidName=Name is not valid
+namingContext.alreadyBound=Name {0} is already bound in this Context
+namingContext.noAbsoluteName=Can''t generate an absolute name for this namespace

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/LocalStrings_es.properties
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/LocalStrings_es.properties	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/LocalStrings_es.properties	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,16 @@
+# $Id: LocalStrings_es.properties 301082 2002-07-18 16:47:23Z remm $
+
+# language es
+
+# package org.apache.naming
+
+
+contextBindings.unknownContext=Contexto {0} desconocido 
+contextBindings.noContextBoundToThread=No hay contexto de nombres asociado a este hilo
+selectorContext.noJavaUrl=Este contexto debe de ser accedido a traves de una URL de tipo java:
+namingContext.contextExpected=El nombre no esta asociado a ningun Contexto
+namingContext.nameNotBound=El nombre {0} no este asociado a este contexto
+namingContext.readOnly=El contexto es de solo lectura
+namingContext.invalidName=Nombre no valido
+namingContext.noAbsoluteName=No se puede generar un nombre absoluto para este espacio de nombres
+namingContext.alreadyBound=El nombre {0} este ya asociado en este Contexto

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/LocalStrings_fr.properties
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/LocalStrings_fr.properties	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/LocalStrings_fr.properties	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,11 @@
+contextBindings.unknownContext=Nom de Contexte inconnu : {0}
+contextBindings.noContextBoundToThread=Aucun Contexte de nommage lié à ce thread
+contextBindings.noContextBoundToCL=Aucun Contexte de nommage lié à ce chargeur de classes
+selectorContext.noJavaUrl=Ce Contexte doit être accédé par une java: URL
+namingContext.contextExpected=Le Nom n''est pas lié à un Contexte
+namingContext.failResolvingReference=Une erreur s est produite durant la résolution de la référence
+namingContext.nameNotBound=Le Nom {0} n''est pas lié à ce Contexte
+namingContext.readOnly=Le Contexte est en lecture seule
+namingContext.invalidName=Le Nom est invalide
+namingContext.alreadyBound=Le Nom {0} est déjà lié à ce Contexte
+namingContext.noAbsoluteName=Impossible de générer un nom absolu pour cet espace de nommage (namespace)

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/LocalStrings_ja.properties
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/LocalStrings_ja.properties	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/LocalStrings_ja.properties	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,11 @@
+contextBindings.unknownContext=\u672a\u77e5\u306e\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u540d\u3067\u3059: {0}
+contextBindings.noContextBoundToThread=\u540d\u524d\u4ed8\u3051\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u306f\u3053\u306e\u30b9\u30ec\u30c3\u30c9\u306b\u30d0\u30a4\u30f3\u30c9\u3055\u308c\u3066\u3044\u307e\u305b\u3093
+contextBindings.noContextBoundToCL=\u540d\u524d\u4ed8\u3051\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u306f\u3053\u306e\u30af\u30e9\u30b9\u30ed\u30fc\u30c0\u306b\u30d0\u30a4\u30f3\u30c9\u3055\u308c\u3066\u3044\u307e\u305b\u3093
+selectorContext.noJavaUrl=\u3053\u306e\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u306b\u306fjava: URL\u3092\u7528\u3044\u3066\u30a2\u30af\u30bb\u30b9\u3055\u308c\u306d\u3070\u3044\u3051\u307e\u305b\u3093
+namingContext.contextExpected=\u540d\u524d\u304c\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u306b\u30d0\u30a4\u30f3\u30c9\u3055\u308c\u3066\u3044\u307e\u305b\u3093
+namingContext.failResolvingReference=\u53c2\u7167\u306e\u89e3\u6c7a\u4e2d\u306b\u4e88\u6e2c\u3057\u306a\u3044\u4f8b\u5916\u304c\u767a\u751f\u3057\u307e\u3057\u305f
+namingContext.nameNotBound=\u540d\u524d {0} \u306f\u3053\u306e\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u306b\u30d0\u30a4\u30f3\u30c9\u3055\u308c\u3066\u3044\u307e\u305b\u3093
+namingContext.readOnly=\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u306f\u30ea\u30fc\u30c9\u30aa\u30f3\u30ea\u30fc\u3067\u3059
+namingContext.invalidName=\u540d\u524d\u306f\u7121\u52b9\u3067\u3059
+namingContext.alreadyBound=\u540d\u524d {0} \u306f\u65e2\u306b\u3053\u306e\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u306b\u30d0\u30a4\u30f3\u30c9\u3055\u308c\u3066\u3044\u307e\u3059
+namingContext.noAbsoluteName=\u3053\u306e\u540d\u524d\u7a7a\u9593\u306b\u7d76\u5bfe\u540d\u3092\u751f\u6210\u3067\u304d\u307e\u305b\u3093

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/NameParserImpl.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/NameParserImpl.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/NameParserImpl.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,56 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.naming;
+
+import javax.naming.NameParser;
+import javax.naming.Name;
+import javax.naming.NamingException;
+import javax.naming.CompositeName;
+
+/**
+ * Parses names.
+ *
+ * @author Remy Maucherat
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class NameParserImpl 
+    implements NameParser {
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    // ----------------------------------------------------- NameParser Methods
+
+
+    /**
+     * Parses a name into its components.
+     * 
+     * @param name The non-null string name to parse
+     * @return A non-null parsed form of the name using the naming convention 
+     * of this parser.
+     */
+    public Name parse(String name)
+        throws NamingException {
+        return new CompositeName(name);
+    }
+
+
+}
+

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/NamingContext.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/NamingContext.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/NamingContext.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,907 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.naming;
+
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.Enumeration;
+import javax.naming.Context;
+import javax.naming.Name;
+import javax.naming.LinkRef;
+import javax.naming.CompositeName;
+import javax.naming.NameParser;
+import javax.naming.Referenceable;
+import javax.naming.Reference;
+import javax.naming.NamingEnumeration;
+import javax.naming.NamingException;
+import javax.naming.NameAlreadyBoundException;
+import javax.naming.NameNotFoundException;
+import javax.naming.NotContextException;
+import javax.naming.InitialContext;
+import javax.naming.OperationNotSupportedException;
+import javax.naming.spi.NamingManager;
+
+/**
+ * Catalina JNDI Context implementation.
+ *
+ * @author Remy Maucherat
+ * @version $Revision: 366304 $ $Date: 2006-01-05 15:42:29 -0600 (Thu, 05 Jan 2006) $
+ */
+public class NamingContext implements Context {
+
+
+    // -------------------------------------------------------------- Constants
+
+
+    /**
+     * Name parser for this context.
+     */
+    protected static final NameParser nameParser = new NameParserImpl();
+
+
+    private static org.apache.commons.logging.Log log =
+        org.apache.commons.logging.LogFactory.getLog(NamingContext.class);
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Builds a naming context using the given environment.
+     */
+    public NamingContext(Hashtable env, String name) 
+        throws NamingException {
+        this.bindings = new HashMap();
+        this.env = new Hashtable();
+        // FIXME ? Could be put in the environment ?
+        this.name = name;
+        // Populating the environment hashtable
+        if (env != null ) {
+            Enumeration envEntries = env.keys();
+            while (envEntries.hasMoreElements()) {
+                String entryName = (String) envEntries.nextElement();
+                addToEnvironment(entryName, env.get(entryName));
+            }
+        }
+    }
+
+
+    /**
+     * Builds a naming context using the given environment.
+     */
+    public NamingContext(Hashtable env, String name, HashMap bindings) 
+        throws NamingException {
+        this(env, name);
+        this.bindings = bindings;
+    }
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * Environment.
+     */
+    protected Hashtable env;
+
+
+    /**
+     * The string manager for this package.
+     */
+    protected StringManager sm = StringManager.getManager(Constants.Package);
+
+
+    /**
+     * Bindings in this Context.
+     */
+    protected HashMap bindings;
+
+
+    /**
+     * Name of the associated Catalina Context.
+     */
+    protected String name;
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    // -------------------------------------------------------- Context Methods
+
+
+    /**
+     * Retrieves the named object. If name is empty, returns a new instance 
+     * of this context (which represents the same naming context as this 
+     * context, but its environment may be modified independently and it may 
+     * be accessed concurrently).
+     * 
+     * @param name the name of the object to look up
+     * @return the object bound to name
+     * @exception NamingException if a naming exception is encountered
+     */
+    public Object lookup(Name name)
+        throws NamingException {
+        return lookup(name, true);
+    }
+
+
+    /**
+     * Retrieves the named object.
+     * 
+     * @param name the name of the object to look up
+     * @return the object bound to name
+     * @exception NamingException if a naming exception is encountered
+     */
+    public Object lookup(String name)
+        throws NamingException {
+        return lookup(new CompositeName(name), true);
+    }
+
+
+    /**
+     * Binds a name to an object. All intermediate contexts and the target 
+     * context (that named by all but terminal atomic component of the name) 
+     * must already exist.
+     * 
+     * @param name the name to bind; may not be empty
+     * @param obj the object to bind; possibly null
+     * @exception NameAlreadyBoundException if name is already bound
+     * @exception InvalidAttributesException if object did not supply all 
+     * mandatory attributes
+     * @exception NamingException if a naming exception is encountered
+     */
+    public void bind(Name name, Object obj)
+        throws NamingException {
+        bind(name, obj, false);
+    }
+
+
+    /**
+     * Binds a name to an object.
+     * 
+     * @param name the name to bind; may not be empty
+     * @param obj the object to bind; possibly null
+     * @exception NameAlreadyBoundException if name is already bound
+     * @exception InvalidAttributesException if object did not supply all 
+     * mandatory attributes
+     * @exception NamingException if a naming exception is encountered
+     */
+    public void bind(String name, Object obj)
+        throws NamingException {
+        bind(new CompositeName(name), obj);
+    }
+
+
+    /**
+     * Binds a name to an object, overwriting any existing binding. All 
+     * intermediate contexts and the target context (that named by all but 
+     * terminal atomic component of the name) must already exist.
+     * <p>
+     * If the object is a DirContext, any existing attributes associated with 
+     * the name are replaced with those of the object. Otherwise, any 
+     * existing attributes associated with the name remain unchanged.
+     * 
+     * @param name the name to bind; may not be empty
+     * @param obj the object to bind; possibly null
+     * @exception InvalidAttributesException if object did not supply all 
+     * mandatory attributes
+     * @exception NamingException if a naming exception is encountered
+     */
+    public void rebind(Name name, Object obj)
+        throws NamingException {
+        bind(name, obj, true);
+    }
+
+
+    /**
+     * Binds a name to an object, overwriting any existing binding.
+     * 
+     * @param name the name to bind; may not be empty
+     * @param obj the object to bind; possibly null
+     * @exception InvalidAttributesException if object did not supply all 
+     * mandatory attributes
+     * @exception NamingException if a naming exception is encountered
+     */
+    public void rebind(String name, Object obj)
+        throws NamingException {
+        rebind(new CompositeName(name), obj);
+    }
+
+
+    /**
+     * Unbinds the named object. Removes the terminal atomic name in name 
+     * from the target context--that named by all but the terminal atomic 
+     * part of name.
+     * <p>
+     * This method is idempotent. It succeeds even if the terminal atomic 
+     * name is not bound in the target context, but throws 
+     * NameNotFoundException if any of the intermediate contexts do not exist. 
+     * 
+     * @param name the name to bind; may not be empty
+     * @exception NameNotFoundException if an intermediate context does not 
+     * exist
+     * @exception NamingException if a naming exception is encountered
+     */
+    public void unbind(Name name)
+        throws NamingException {
+        checkWritable();
+        
+        while ((!name.isEmpty()) && (name.get(0).length() == 0))
+            name = name.getSuffix(1);
+        if (name.isEmpty())
+            throw new NamingException
+                (sm.getString("namingContext.invalidName"));
+        
+        NamingEntry entry = (NamingEntry) bindings.get(name.get(0));
+        
+        if (entry == null) {
+            throw new NameNotFoundException
+                (sm.getString("namingContext.nameNotBound", name.get(0)));
+        }
+        
+        if (name.size() > 1) {
+            if (entry.type == NamingEntry.CONTEXT) {
+                ((Context) entry.value).unbind(name.getSuffix(1));
+            } else {
+                throw new NamingException
+                    (sm.getString("namingContext.contextExpected"));
+            }
+        } else {
+            bindings.remove(name.get(0));
+        }
+        
+    }
+
+
+    /**
+     * Unbinds the named object.
+     * 
+     * @param name the name to bind; may not be empty
+     * @exception NameNotFoundException if an intermediate context does not 
+     * exist
+     * @exception NamingException if a naming exception is encountered
+     */
+    public void unbind(String name)
+        throws NamingException {
+        unbind(new CompositeName(name));
+    }
+
+
+    /**
+     * Binds a new name to the object bound to an old name, and unbinds the 
+     * old name. Both names are relative to this context. Any attributes 
+     * associated with the old name become associated with the new name. 
+     * Intermediate contexts of the old name are not changed.
+     * 
+     * @param oldName the name of the existing binding; may not be empty
+     * @param newName the name of the new binding; may not be empty
+     * @exception NameAlreadyBoundException if newName is already bound
+     * @exception NamingException if a naming exception is encountered
+     */
+    public void rename(Name oldName, Name newName)
+        throws NamingException {
+        Object value = lookup(oldName);
+        bind(newName, value);
+        unbind(oldName);
+    }
+
+
+    /**
+     * Binds a new name to the object bound to an old name, and unbinds the 
+     * old name.
+     * 
+     * @param oldName the name of the existing binding; may not be empty
+     * @param newName the name of the new binding; may not be empty
+     * @exception NameAlreadyBoundException if newName is already bound
+     * @exception NamingException if a naming exception is encountered
+     */
+    public void rename(String oldName, String newName)
+        throws NamingException {
+        rename(new CompositeName(oldName), new CompositeName(newName));
+    }
+
+
+    /**
+     * 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
+     */
+    public NamingEnumeration list(Name name)
+        throws NamingException {
+        // Removing empty parts
+        while ((!name.isEmpty()) && (name.get(0).length() == 0))
+            name = name.getSuffix(1);
+        if (name.isEmpty()) {
+            return new NamingContextEnumeration(bindings.values().iterator());
+        }
+        
+        NamingEntry entry = (NamingEntry) bindings.get(name.get(0));
+        
+        if (entry == null) {
+            throw new NameNotFoundException
+                (sm.getString("namingContext.nameNotBound", name.get(0)));
+        }
+        
+        if (entry.type != NamingEntry.CONTEXT) {
+            throw new NamingException
+                (sm.getString("namingContext.contextExpected"));
+        }
+        return ((Context) entry.value).list(name.getSuffix(1));
+    }
+
+
+    /**
+     * Enumerates the names bound in the named context, along with the class 
+     * names of objects bound to them.
+     * 
+     * @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
+     */
+    public NamingEnumeration list(String name)
+        throws NamingException {
+        return list(new CompositeName(name));
+    }
+
+
+    /**
+     * Enumerates the names bound in the named context, along with the 
+     * 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 bindings in this context. 
+     * Each element of the enumeration is of type Binding.
+     * @exception NamingException if a naming exception is encountered
+     */
+    public NamingEnumeration listBindings(Name name)
+        throws NamingException {
+        // Removing empty parts
+        while ((!name.isEmpty()) && (name.get(0).length() == 0))
+            name = name.getSuffix(1);
+        if (name.isEmpty()) {
+            return new NamingContextBindingsEnumeration(bindings.values().iterator(), this);
+        }
+        
+        NamingEntry entry = (NamingEntry) bindings.get(name.get(0));
+        
+        if (entry == null) {
+            throw new NameNotFoundException
+                (sm.getString("namingContext.nameNotBound", name.get(0)));
+        }
+        
+        if (entry.type != NamingEntry.CONTEXT) {
+            throw new NamingException
+                (sm.getString("namingContext.contextExpected"));
+        }
+        return ((Context) entry.value).listBindings(name.getSuffix(1));
+    }
+
+
+    /**
+     * Enumerates the names bound in the named context, along with the 
+     * objects bound to them.
+     * 
+     * @param name the name of the context to list
+     * @return an enumeration of the bindings in this context. 
+     * Each element of the enumeration is of type Binding.
+     * @exception NamingException if a naming exception is encountered
+     */
+    public NamingEnumeration listBindings(String name)
+        throws NamingException {
+        return listBindings(new CompositeName(name));
+    }
+
+
+    /**
+     * Destroys the named context and removes it from the namespace. Any 
+     * attributes associated with the name are also removed. Intermediate 
+     * contexts are not destroyed.
+     * <p>
+     * This method is idempotent. It succeeds even if the terminal atomic 
+     * name is not bound in the target context, but throws 
+     * NameNotFoundException if any of the intermediate contexts do not exist. 
+     * 
+     * In a federated naming system, a context from one naming system may be 
+     * bound to a name in another. One can subsequently look up and perform 
+     * operations on the foreign context using a composite name. However, an 
+     * attempt destroy the context using this composite name will fail with 
+     * NotContextException, because the foreign context is not a "subcontext" 
+     * of the context in which it is bound. Instead, use unbind() to remove 
+     * the binding of the foreign context. Destroying the foreign context 
+     * requires that the destroySubcontext() be performed on a context from 
+     * the foreign context's "native" naming system.
+     * 
+     * @param name the name of the context to be destroyed; may not be empty
+     * @exception NameNotFoundException if an intermediate context does not 
+     * exist
+     * @exception NotContextException if the name is bound but does not name 
+     * a context, or does not name a context of the appropriate type
+     */
+    public void destroySubcontext(Name name)
+        throws NamingException {
+        
+        checkWritable();
+        
+        while ((!name.isEmpty()) && (name.get(0).length() == 0))
+            name = name.getSuffix(1);
+        if (name.isEmpty())
+            throw new NamingException
+                (sm.getString("namingContext.invalidName"));
+        
+        NamingEntry entry = (NamingEntry) bindings.get(name.get(0));
+        
+        if (entry == null) {
+            throw new NameNotFoundException
+                (sm.getString("namingContext.nameNotBound", name.get(0)));
+        }
+        
+        if (name.size() > 1) {
+            if (entry.type == NamingEntry.CONTEXT) {
+                ((Context) entry.value).unbind(name.getSuffix(1));
+            } else {
+                throw new NamingException
+                    (sm.getString("namingContext.contextExpected"));
+            }
+        } else {
+            if (entry.type == NamingEntry.CONTEXT) {
+                ((Context) entry.value).close();
+                bindings.remove(name.get(0));
+            } else {
+                throw new NotContextException
+                    (sm.getString("namingContext.contextExpected"));
+            }
+        }
+        
+    }
+
+
+    /**
+     * Destroys the named context and removes it from the namespace.
+     * 
+     * @param name the name of the context to be destroyed; may not be empty
+     * @exception NameNotFoundException if an intermediate context does not 
+     * exist
+     * @exception NotContextException if the name is bound but does not name 
+     * a context, or does not name a context of the appropriate type
+     */
+    public void destroySubcontext(String name)
+        throws NamingException {
+        destroySubcontext(new CompositeName(name));
+    }
+
+
+    /**
+     * Creates and binds a new context. Creates a new context with the given 
+     * name and binds it in the target context (that named by all but 
+     * terminal atomic component of the name). All intermediate contexts and 
+     * the target context must already exist.
+     * 
+     * @param name the name of the context to create; may not be empty
+     * @return the newly created context
+     * @exception NameAlreadyBoundException if name is already bound
+     * @exception InvalidAttributesException if creation of the subcontext 
+     * requires specification of mandatory attributes
+     * @exception NamingException if a naming exception is encountered
+     */
+    public Context createSubcontext(Name name)
+        throws NamingException {
+        checkWritable();
+        
+        Context newContext = new NamingContext(env, this.name);
+        bind(name, newContext);
+        
+        return newContext;
+    }
+
+
+    /**
+     * Creates and binds a new context.
+     * 
+     * @param name the name of the context to create; may not be empty
+     * @return the newly created context
+     * @exception NameAlreadyBoundException if name is already bound
+     * @exception InvalidAttributesException if creation of the subcontext 
+     * requires specification of mandatory attributes
+     * @exception NamingException if a naming exception is encountered
+     */
+    public Context createSubcontext(String name)
+        throws NamingException {
+        return createSubcontext(new CompositeName(name));
+    }
+
+
+    /**
+     * Retrieves the named object, following links except for the terminal 
+     * atomic component of the name. If the object bound to name is not a 
+     * link, returns the object itself.
+     * 
+     * @param name the name of the object to look up
+     * @return the object bound to name, not following the terminal link 
+     * (if any).
+     * @exception NamingException if a naming exception is encountered
+     */
+    public Object lookupLink(Name name)
+        throws NamingException {
+        return lookup(name, false);
+    }
+
+
+    /**
+     * Retrieves the named object, following links except for the terminal 
+     * atomic component of the name.
+     * 
+     * @param name the name of the object to look up
+     * @return the object bound to name, not following the terminal link 
+     * (if any).
+     * @exception NamingException if a naming exception is encountered
+     */
+    public Object lookupLink(String name)
+        throws NamingException {
+        return lookup(new CompositeName(name), false);
+    }
+
+
+    /**
+     * Retrieves the parser associated with the named context. In a 
+     * federation of namespaces, different naming systems will parse names 
+     * differently. This method allows an application to get a parser for 
+     * parsing names into their atomic components using the naming convention 
+     * of a particular naming system. Within any single naming system, 
+     * NameParser objects returned by this method must be equal (using the 
+     * equals() test).
+     * 
+     * @param name the name of the context from which to get the parser
+     * @return a name parser that can parse compound names into their atomic 
+     * components
+     * @exception NamingException if a naming exception is encountered
+     */
+    public NameParser getNameParser(Name name)
+        throws NamingException {
+
+        while ((!name.isEmpty()) && (name.get(0).length() == 0))
+            name = name.getSuffix(1);
+        if (name.isEmpty())
+            return nameParser;
+
+        if (name.size() > 1) {
+            Object obj = bindings.get(name.get(0));
+            if (obj instanceof Context) {
+                return ((Context) obj).getNameParser(name.getSuffix(1));
+            } else {
+                throw new NotContextException
+                    (sm.getString("namingContext.contextExpected"));
+            }
+        }
+
+        return nameParser;
+
+    }
+
+
+    /**
+     * Retrieves the parser associated with the named context.
+     * 
+     * @param name the name of the context from which to get the parser
+     * @return a name parser that can parse compound names into their atomic 
+     * components
+     * @exception NamingException if a naming exception is encountered
+     */
+    public NameParser getNameParser(String name)
+        throws NamingException {
+        return getNameParser(new CompositeName(name));
+    }
+
+
+    /**
+     * Composes the name of this context with a name relative to this context.
+     * <p>
+     * Given a name (name) relative to this context, and the name (prefix) 
+     * of this context relative to one of its ancestors, this method returns 
+     * the composition of the two names using the syntax appropriate for the 
+     * naming system(s) involved. That is, if name names an object relative 
+     * to this context, the result is the name of the same object, but 
+     * relative to the ancestor context. None of the names may be null.
+     * 
+     * @param name a name relative to this context
+     * @param prefix the name of this context relative to one of its ancestors
+     * @return the composition of prefix and name
+     * @exception NamingException if a naming exception is encountered
+     */
+    public Name composeName(Name name, Name prefix)
+        throws NamingException {
+        prefix = (Name) prefix.clone();
+        return prefix.addAll(name);
+    }
+
+
+    /**
+     * Composes the name of this context with a name relative to this context.
+     * 
+     * @param name a name relative to this context
+     * @param prefix the name of this context relative to one of its ancestors
+     * @return the composition of prefix and name
+     * @exception NamingException if a naming exception is encountered
+     */
+    public String composeName(String name, String prefix)
+        throws NamingException {
+        return prefix + "/" + name;
+    }
+
+
+    /**
+     * Adds a new environment property to the environment of this context. If 
+     * the property already exists, its value is overwritten.
+     * 
+     * @param propName the name of the environment property to add; may not 
+     * be null
+     * @param propVal the value of the property to add; may not be null
+     * @exception NamingException if a naming exception is encountered
+     */
+    public Object addToEnvironment(String propName, Object propVal)
+        throws NamingException {
+        return env.put(propName, propVal);
+    }
+
+
+    /**
+     * Removes an environment property from the environment of this context. 
+     * 
+     * @param propName the name of the environment property to remove; 
+     * may not be null
+     * @exception NamingException if a naming exception is encountered
+     */
+    public Object removeFromEnvironment(String propName)
+        throws NamingException {
+        return env.remove(propName);
+    }
+
+
+    /**
+     * Retrieves the environment in effect for this context. See class 
+     * description for more details on environment properties. 
+     * The caller should not make any changes to the object returned: their 
+     * effect on the context is undefined. The environment of this context 
+     * may be changed using addToEnvironment() and removeFromEnvironment().
+     * 
+     * @return the environment of this context; never null
+     * @exception NamingException if a naming exception is encountered
+     */
+    public Hashtable getEnvironment()
+        throws NamingException {
+        return env;
+    }
+
+
+    /**
+     * Closes this context. This method releases this context's resources 
+     * immediately, instead of waiting for them to be released automatically 
+     * by the garbage collector.
+     * This method is idempotent: invoking it on a context that has already 
+     * been closed has no effect. Invoking any other method on a closed 
+     * context is not allowed, and results in undefined behaviour.
+     * 
+     * @exception NamingException if a naming exception is encountered
+     */
+    public void close()
+        throws NamingException {
+        env.clear();
+    }
+
+
+    /**
+     * Retrieves the full name of this context within its own namespace.
+     * <p>
+     * Many naming services have a notion of a "full name" for objects in 
+     * their respective namespaces. For example, an LDAP entry has a 
+     * distinguished name, and a DNS record has a fully qualified name. This 
+     * method allows the client application to retrieve this name. The string 
+     * returned by this method is not a JNDI composite name and should not be 
+     * passed directly to context methods. In naming systems for which the 
+     * notion of full name does not make sense, 
+     * OperationNotSupportedException is thrown.
+     * 
+     * @return this context's name in its own namespace; never null
+     * @exception OperationNotSupportedException if the naming system does 
+     * not have the notion of a full name
+     * @exception NamingException if a naming exception is encountered
+     */
+    public String getNameInNamespace()
+        throws NamingException {
+        throw  new OperationNotSupportedException
+            (sm.getString("namingContext.noAbsoluteName"));
+        //FIXME ?
+    }
+
+
+    // ------------------------------------------------------ Protected Methods
+
+
+    /**
+     * Retrieves the named object.
+     * 
+     * @param name the name of the object to look up
+     * @param resolveLinks If true, the links will be resolved
+     * @return the object bound to name
+     * @exception NamingException if a naming exception is encountered
+     */
+    protected Object lookup(Name name, boolean resolveLinks)
+        throws NamingException {
+
+        // Removing empty parts
+        while ((!name.isEmpty()) && (name.get(0).length() == 0))
+            name = name.getSuffix(1);
+        if (name.isEmpty()) {
+            // If name is empty, a newly allocated naming context is returned
+            return new NamingContext(env, this.name, bindings);
+        }
+        
+        NamingEntry entry = (NamingEntry) bindings.get(name.get(0));
+        
+        if (entry == null) {
+            throw new NameNotFoundException
+                (sm.getString("namingContext.nameNotBound", name.get(0)));
+        }
+        
+        if (name.size() > 1) {
+            // If the size of the name is greater that 1, then we go through a
+            // number of subcontexts.
+            if (entry.type != NamingEntry.CONTEXT) {
+                throw new NamingException
+                    (sm.getString("namingContext.contextExpected"));
+            }
+            return ((Context) entry.value).lookup(name.getSuffix(1));
+        } else {
+            if ((resolveLinks) && (entry.type == NamingEntry.LINK_REF)) {
+                String link = ((LinkRef) entry.value).getLinkName();
+                if (link.startsWith(".")) {
+                    // Link relative to this context
+                    return lookup(link.substring(1));
+                } else {
+                    return (new InitialContext(env)).lookup(link);
+                }
+            } else if (entry.type == NamingEntry.REFERENCE) {
+                try {
+                    Object obj = NamingManager.getObjectInstance
+                        (entry.value, name, this, env);
+                    if (obj != null) {
+                        entry.value = obj;
+                        entry.type = NamingEntry.ENTRY;
+                    }
+                    return obj;
+                } catch (NamingException e) {
+                    throw e;
+                } catch (Exception e) {
+                    log.warn(sm.getString
+                             ("namingContext.failResolvingReference"), e);
+                    throw new NamingException(e.getMessage());
+                }
+            } else {
+                return entry.value;
+            }
+        }
+        
+    }
+
+
+    /**
+     * Binds a name to an object. All intermediate contexts and the target 
+     * context (that named by all but terminal atomic component of the name) 
+     * must already exist.
+     * 
+     * @param name the name to bind; may not be empty
+     * @param obj the object to bind; possibly null
+     * @param rebind if true, then perform a rebind (ie, overwrite)
+     * @exception NameAlreadyBoundException if name is already bound
+     * @exception InvalidAttributesException if object did not supply all 
+     * mandatory attributes
+     * @exception NamingException if a naming exception is encountered
+     */
+    protected void bind(Name name, Object obj, boolean rebind)
+        throws NamingException {
+        
+        checkWritable();
+        
+        while ((!name.isEmpty()) && (name.get(0).length() == 0))
+            name = name.getSuffix(1);
+        if (name.isEmpty())
+            throw new NamingException
+                (sm.getString("namingContext.invalidName"));
+        
+        NamingEntry entry = (NamingEntry) bindings.get(name.get(0));
+        
+        if (name.size() > 1) {
+            if (entry == null) {
+                throw new NameNotFoundException
+                    (sm.getString("namingContext.nameNotBound", name.get(0)));
+            }
+            if (entry.type == NamingEntry.CONTEXT) {
+                if (rebind) {
+                    ((Context) entry.value).rebind(name.getSuffix(1), obj);
+                } else {
+                    ((Context) entry.value).bind(name.getSuffix(1), obj);
+                }
+            } else {
+                throw new NamingException
+                    (sm.getString("namingContext.contextExpected"));
+            }
+        } else {
+            if ((!rebind) && (entry != null)) {
+                throw new NameAlreadyBoundException
+                    (sm.getString("namingContext.alreadyBound", name.get(0)));
+            } else {
+                // Getting the type of the object and wrapping it within a new
+                // NamingEntry
+                Object toBind = 
+                    NamingManager.getStateToBind(obj, name, this, env);
+                if (toBind instanceof Context) {
+                    entry = new NamingEntry(name.get(0), toBind, 
+                                            NamingEntry.CONTEXT);
+                } else if (toBind instanceof LinkRef) {
+                    entry = new NamingEntry(name.get(0), toBind, 
+                                            NamingEntry.LINK_REF);
+                } else if (toBind instanceof Reference) {
+                    entry = new NamingEntry(name.get(0), toBind, 
+                                            NamingEntry.REFERENCE);
+                } else if (toBind instanceof Referenceable) {
+                    toBind = ((Referenceable) toBind).getReference();
+                    entry = new NamingEntry(name.get(0), toBind, 
+                                            NamingEntry.REFERENCE);
+                } else {
+                    entry = new NamingEntry(name.get(0), toBind, 
+                                            NamingEntry.ENTRY);
+                }
+                bindings.put(name.get(0), entry);
+            }
+        }
+        
+    }
+
+
+    /**
+     * Returns true if writing is allowed on this context.
+     */
+    protected boolean isWritable() {
+        return ContextAccessController.isWritable(name);
+    }
+
+
+    /**
+     * Throws a naming exception is Context is not writable.
+     */
+    protected void checkWritable() 
+        throws NamingException {
+        if (!isWritable())
+            throw new NamingException(sm.getString("namingContext.readOnly"));
+    }
+
+
+}
+

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/NamingContextBindingsEnumeration.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/NamingContextBindingsEnumeration.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/NamingContextBindingsEnumeration.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,128 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.naming;
+
+import java.util.Iterator;
+
+import javax.naming.Binding;
+import javax.naming.CompositeName;
+import javax.naming.Context;
+import javax.naming.NamingEnumeration;
+import javax.naming.NamingException;
+
+/**
+ * Naming enumeration implementation.
+ *
+ * @author Remy Maucherat
+ * @version $Revision: 366304 $ $Date: 2006-01-05 15:42:29 -0600 (Thu, 05 Jan 2006) $
+ */
+
+public class NamingContextBindingsEnumeration 
+    implements NamingEnumeration {
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    public NamingContextBindingsEnumeration(Iterator entries, Context ctx) {
+    	iterator = entries;
+        this.ctx = ctx;
+    }
+
+    // -------------------------------------------------------------- Variables
+
+
+    /**
+     * Underlying enumeration.
+     */
+    protected Iterator iterator;
+
+    
+    /**
+     * The context for which this enumeration is being generated.
+     */
+    private Context ctx;
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Retrieves the next element in the enumeration.
+     */
+    public Object next()
+        throws NamingException {
+        return nextElementInternal();
+    }
+
+
+    /**
+     * Determines whether there are any more elements in the enumeration.
+     */
+    public boolean hasMore()
+        throws NamingException {
+        return iterator.hasNext();
+    }
+
+
+    /**
+     * Closes this enumeration.
+     */
+    public void close()
+        throws NamingException {
+    }
+
+
+    public boolean hasMoreElements() {
+        return iterator.hasNext();
+    }
+
+
+    public Object nextElement() {
+        try {
+            return nextElementInternal();
+        } catch (NamingException e) {
+            throw new RuntimeException(e.getMessage(), e);
+        }
+    }
+    
+    private Object nextElementInternal() throws NamingException {
+        NamingEntry entry = (NamingEntry) iterator.next();
+        
+        // If the entry is a reference, resolve it
+        if (entry.type == NamingEntry.REFERENCE
+                || entry.type == NamingEntry.LINK_REF) {
+            try {
+                // A lookup will resolve the entry
+                ctx.lookup(new CompositeName(entry.name));
+            } catch (NamingException e) {
+                throw e;
+            } catch (Exception e) {
+                NamingException ne = new NamingException(e.getMessage());
+                ne.initCause(e);
+                throw ne;
+            }
+        }
+        
+        return new Binding(entry.name, entry.value.getClass().getName(), 
+                           entry.value, true);
+    }
+
+
+}
+

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/NamingContextEnumeration.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/NamingContextEnumeration.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/NamingContextEnumeration.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,95 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.naming;
+
+import java.util.Iterator;
+
+import javax.naming.NameClassPair;
+import javax.naming.NamingEnumeration;
+import javax.naming.NamingException;
+
+/**
+ * Naming enumeration implementation.
+ *
+ * @author Remy Maucherat
+ * @version $Revision: 303022 $ $Date: 2004-07-23 17:46:08 -0500 (Fri, 23 Jul 2004) $
+ */
+
+public class NamingContextEnumeration 
+    implements NamingEnumeration {
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    public NamingContextEnumeration(Iterator entries) {
+    	iterator = entries;
+    }
+
+
+    // -------------------------------------------------------------- Variables
+
+
+    /**
+     * Underlying enumeration.
+     */
+    protected Iterator iterator;
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Retrieves the next element in the enumeration.
+     */
+    public Object next()
+        throws NamingException {
+        return nextElement();
+    }
+
+
+    /**
+     * Determines whether there are any more elements in the enumeration.
+     */
+    public boolean hasMore()
+        throws NamingException {
+        return iterator.hasNext();
+    }
+
+
+    /**
+     * Closes this enumeration.
+     */
+    public void close()
+        throws NamingException {
+    }
+
+
+    public boolean hasMoreElements() {
+        return iterator.hasNext();
+    }
+
+
+    public Object nextElement() {
+        NamingEntry entry = (NamingEntry) iterator.next();
+        return new NameClassPair(entry.name, entry.value.getClass().getName());
+    }
+
+
+}
+

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/NamingEntry.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/NamingEntry.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/NamingEntry.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,80 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.naming;
+
+
+/**
+ * Represents a binding in a NamingContext.
+ *
+ * @author Remy Maucherat
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class NamingEntry {
+
+
+    // -------------------------------------------------------------- Constants
+
+
+    public static final int ENTRY = 0;
+    public static final int LINK_REF = 1;
+    public static final int REFERENCE = 2;
+    
+    public static final int CONTEXT = 10;
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    public NamingEntry(String name, Object value, int type) {
+        this.name = name;
+        this.value = value;
+        this.type = type;
+    }
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The type instance variable is used to avoid unsing RTTI when doing
+     * lookups.
+     */
+    public int type;
+    public String name;
+    public Object value;
+
+
+    // --------------------------------------------------------- Object Methods
+
+
+    public boolean equals(Object obj) {
+        if ((obj != null) && (obj instanceof NamingEntry)) {
+            return name.equals(((NamingEntry) obj).name);
+        } else {
+            return false;
+        }
+    }
+
+
+    public int hashCode() {
+        return name.hashCode();
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/NamingService.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/NamingService.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/NamingService.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,229 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.naming;
+
+import javax.naming.Context;
+import javax.management.NotificationBroadcasterSupport;
+import javax.management.ObjectName;
+import javax.management.MBeanServer;
+import javax.management.MBeanRegistration;
+import javax.management.AttributeChangeNotification;
+import javax.management.Notification;
+
+/**
+ * Implementation of the NamingService JMX MBean.
+ * 
+ * @author <a href="mailto:remm at apache.org">Remy Maucherat</a>
+ * @version $Revision: 303104 $
+ */
+
+public final class NamingService
+    extends NotificationBroadcasterSupport
+    implements NamingServiceMBean, MBeanRegistration {
+    
+    
+    // ----------------------------------------------------- Instance Variables
+    
+    
+    /**
+     * Status of the Slide domain.
+     */
+    private int state = STOPPED;
+    
+    
+    /**
+     * Notification sequence number.
+     */
+    private long sequenceNumber = 0;
+    
+    
+    /**
+     * Old URL packages value.
+     */
+    private String oldUrlValue = "";
+    
+    
+    /**
+     * Old initial context value.
+     */
+    private String oldIcValue = "";
+    
+    
+    // ---------------------------------------------- MBeanRegistration Methods
+    
+    
+    public ObjectName preRegister(MBeanServer server, ObjectName name)
+        throws Exception {
+        return new ObjectName(OBJECT_NAME);
+    }
+    
+    
+    public void postRegister(Boolean registrationDone) {
+        if (!registrationDone.booleanValue())
+            destroy();
+    }
+    
+    
+    public void preDeregister()
+        throws Exception {
+    }
+    
+    
+    public void postDeregister() {
+        destroy();
+    }
+    
+    
+    // ----------------------------------------------------- SlideMBean Methods
+    
+    
+    /**
+     * Retruns the Catalina component name.
+     */
+    public String getName() {
+        return NAME;
+    }
+    
+    
+    /**
+     * Returns the state.
+     */
+    public int getState() {
+        return state;
+    }
+    
+    
+    /**
+     * Returns a String representation of the state.
+     */
+    public String getStateString() {
+        return states[state];
+    }
+    
+    
+    /**
+     * Start the servlet container.
+     */
+    public void start()
+        throws Exception {
+        
+        Notification notification = null;
+        
+        if (state != STOPPED)
+            return;
+        
+        state = STARTING;
+        
+        // Notifying the MBEan server that we're starting
+        
+        notification = new AttributeChangeNotification
+            (this, sequenceNumber++, System.currentTimeMillis(), 
+             "Starting " + NAME, "State", "java.lang.Integer", 
+             new Integer(STOPPED), new Integer(STARTING));
+        sendNotification(notification);
+        
+        try {
+            
+            String value = "org.apache.naming";
+            String oldValue = System.getProperty(Context.URL_PKG_PREFIXES);
+            if (oldValue != null) {
+                oldUrlValue = oldValue;
+                value = oldValue + ":" + value;
+            }
+            System.setProperty(Context.URL_PKG_PREFIXES, value);
+            
+            oldValue = System.getProperty(Context.INITIAL_CONTEXT_FACTORY);
+            if ((oldValue != null) && (oldValue.length() > 0)) {
+                oldIcValue = oldValue;
+            } else {
+                System.setProperty(Context.INITIAL_CONTEXT_FACTORY,
+                                   Constants.Package 
+                                   + ".java.javaURLContextFactory");
+            }
+            
+        } catch (Throwable t) {
+            state = STOPPED;
+            notification = new AttributeChangeNotification
+                (this, sequenceNumber++, System.currentTimeMillis(), 
+                 "Stopped " + NAME, "State", "java.lang.Integer", 
+                 new Integer(STARTING), new Integer(STOPPED));
+            sendNotification(notification);
+        }
+        
+        state = STARTED;
+        notification = new AttributeChangeNotification
+            (this, sequenceNumber++, System.currentTimeMillis(), 
+             "Started " + NAME, "State", "java.lang.Integer", 
+             new Integer(STARTING), new Integer(STARTED));
+        sendNotification(notification);
+        
+    }
+    
+    
+    /**
+     * Stop the servlet container.
+     */
+    public void stop() {
+        
+        Notification notification = null;
+        
+        if (state != STARTED)
+            return;
+        
+        state = STOPPING;
+        
+        notification = new AttributeChangeNotification
+            (this, sequenceNumber++, System.currentTimeMillis(), 
+             "Stopping " + NAME, "State", "java.lang.Integer", 
+             new Integer(STARTED), new Integer(STOPPING));
+        sendNotification(notification);
+        
+        try {
+            
+            System.setProperty(Context.URL_PKG_PREFIXES, oldUrlValue);
+            System.setProperty(Context.INITIAL_CONTEXT_FACTORY, oldIcValue);
+            
+        } catch (Throwable t) {
+            
+            // FIXME
+            t.printStackTrace();
+            
+        }
+        
+        state = STOPPED;
+        
+        notification = new AttributeChangeNotification
+            (this, sequenceNumber++, System.currentTimeMillis(), 
+             "Stopped " + NAME, "State", "java.lang.Integer", 
+             new Integer(STOPPING), new Integer(STOPPED));
+        sendNotification(notification);
+        
+    }
+    
+    
+    /**
+     * Destroy servlet container (if any is running).
+     */
+    public void destroy() {
+        
+        if (getState() != STOPPED)
+            stop();
+        
+    }
+    
+    
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/NamingServiceMBean.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/NamingServiceMBean.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/NamingServiceMBean.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,97 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.naming;
+
+/**
+ * Naming MBean interface.
+ * 
+ * @author <a href="mailto:remm at apache.org">Remy Maucherat</a>
+ * @version $Revision: 302726 $
+ */
+
+public interface NamingServiceMBean {
+    
+    
+    // -------------------------------------------------------------- Constants
+    
+    
+    /**
+     * Status constants.
+     */
+    public static final String[] states = 
+    {"Stopped", "Stopping", "Starting", "Started"};
+    
+    
+    public static final int STOPPED  = 0;
+    public static final int STOPPING = 1;
+    public static final int STARTING = 2;
+    public static final int STARTED  = 3;
+    
+    
+    /**
+     * Component name.
+     */
+    public static final String NAME = "Apache JNDI Naming Service";
+    
+    
+    /**
+     * Object name.
+     */
+    public static final String OBJECT_NAME = ":service=Naming";
+    
+    
+    // ------------------------------------------------------ Interface Methods
+    
+    
+    /**
+     * Retruns the JNDI component name.
+     */
+    public String getName();
+    
+    
+    /**
+     * Returns the state.
+     */
+    public int getState();
+    
+    
+    /**
+     * Returns a String representation of the state.
+     */
+    public String getStateString();
+    
+    
+    /**
+     * Start the servlet container.
+     */
+    public void start()
+        throws Exception;
+    
+    
+    /**
+     * Stop the servlet container.
+     */
+    public void stop();
+    
+    
+    /**
+     * Destroy servlet container (if any is running).
+     */
+    public void destroy();
+    
+    
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/ResourceEnvRef.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/ResourceEnvRef.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/ResourceEnvRef.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,98 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.naming;
+
+import javax.naming.Context;
+import javax.naming.Reference;
+
+/**
+ * Represents a reference address to a resource environment.
+ *
+ * @author Remy Maucherat
+ * @version $Revision: 303133 $ $Date: 2004-08-29 11:46:15 -0500 (Sun, 29 Aug 2004) $
+ */
+
+public class ResourceEnvRef
+    extends Reference {
+
+
+    // -------------------------------------------------------------- Constants
+
+
+    /**
+     * Default factory for this reference.
+     */
+    public static final String DEFAULT_FACTORY = 
+        org.apache.naming.factory.Constants.DEFAULT_RESOURCE_ENV_FACTORY;
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Resource env reference.
+     * 
+     * @param resourceType Type
+     */
+    public ResourceEnvRef(String resourceType) {
+        super(resourceType);
+    }
+
+
+    /**
+     * Resource env reference.
+     * 
+     * @param resourceType Type
+     * @param factory The factory class
+     * @param factoryLocation The factory location
+     */
+    public ResourceEnvRef(String resourceType, String factory,
+                          String factoryLocation) {
+        super(resourceType, factory, factoryLocation);
+    }
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    // ------------------------------------------------------ Reference Methods
+
+
+    /**
+     * Retrieves the class name of the factory of the object to which this 
+     * reference refers.
+     */
+    public String getFactoryClassName() {
+        String factory = super.getFactoryClassName();
+        if (factory != null) {
+            return factory;
+        } else {
+            factory = System.getProperty(Context.OBJECT_FACTORIES);
+            if (factory != null) {
+                return null;
+            } else {
+                return DEFAULT_FACTORY;
+            }
+        }
+    }
+
+
+    // ------------------------------------------------------------- Properties
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/ResourceLinkRef.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/ResourceLinkRef.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/ResourceLinkRef.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,110 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.naming;
+
+import javax.naming.Context;
+import javax.naming.Reference;
+import javax.naming.StringRefAddr;
+
+/**
+ * Represents a reference address to a resource.
+ *
+ * @author Remy Maucherat
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class ResourceLinkRef
+    extends Reference {
+
+
+    // -------------------------------------------------------------- Constants
+
+
+    /**
+     * Default factory for this reference.
+     */
+    public static final String DEFAULT_FACTORY = 
+        org.apache.naming.factory.Constants.DEFAULT_RESOURCE_LINK_FACTORY;
+
+
+    /**
+     * Description address type.
+     */
+    public static final String GLOBALNAME = "globalName";
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * ResourceLink Reference.
+     * 
+     * @param resourceClass Resource class
+     * @param globalName Global name
+     */
+    public ResourceLinkRef(String resourceClass, String globalName) {
+        this(resourceClass, globalName, null, null);
+    }
+
+
+    /**
+     * ResourceLink Reference.
+     * 
+     * @param resourceClass Resource class
+     * @param globalName Global name
+     */
+    public ResourceLinkRef(String resourceClass, String globalName, 
+                           String factory, String factoryLocation) {
+        super(resourceClass, factory, factoryLocation);
+        StringRefAddr refAddr = null;
+        if (globalName != null) {
+            refAddr = new StringRefAddr(GLOBALNAME, globalName);
+            add(refAddr);
+        }
+    }
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    // ------------------------------------------------------ Reference Methods
+
+
+    /**
+     * Retrieves the class name of the factory of the object to which this 
+     * reference refers.
+     */
+    public String getFactoryClassName() {
+        String factory = super.getFactoryClassName();
+        if (factory != null) {
+            return factory;
+        } else {
+            factory = System.getProperty(Context.OBJECT_FACTORIES);
+            if (factory != null) {
+                return null;
+            } else {
+                return DEFAULT_FACTORY;
+            }
+        }
+    }
+
+
+    // ------------------------------------------------------------- Properties
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/ResourceRef.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/ResourceRef.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/ResourceRef.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,167 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.naming;
+
+import java.util.Enumeration;
+
+import javax.naming.Context;
+import javax.naming.RefAddr;
+import javax.naming.Reference;
+import javax.naming.StringRefAddr;
+
+/**
+ * Represents a reference address to a resource.
+ *
+ * @author Remy Maucherat
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class ResourceRef
+    extends Reference {
+
+
+    // -------------------------------------------------------------- Constants
+
+
+    /**
+     * Default factory for this reference.
+     */
+    public static final String DEFAULT_FACTORY = 
+        org.apache.naming.factory.Constants.DEFAULT_RESOURCE_FACTORY;
+
+
+    /**
+     * Description address type.
+     */
+    public static final String DESCRIPTION = "description";
+
+
+    /**
+     * Scope address type.
+     */
+    public static final String SCOPE = "scope";
+
+
+    /**
+     * Auth address type.
+     */
+    public static final String AUTH = "auth";
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Resource Reference.
+     * 
+     * @param resourceClass Resource class
+     * @param scope Resource scope
+     * @param auth Resource authetication
+     */
+    public ResourceRef(String resourceClass, String description, 
+                       String scope, String auth) {
+        this(resourceClass, description, scope, auth, null, null);
+    }
+
+
+    /**
+     * Resource Reference.
+     * 
+     * @param resourceClass Resource class
+     * @param scope Resource scope
+     * @param auth Resource authetication
+     */
+    public ResourceRef(String resourceClass, String description, 
+                       String scope, String auth, String factory,
+                       String factoryLocation) {
+        super(resourceClass, factory, factoryLocation);
+        StringRefAddr refAddr = null;
+        if (description != null) {
+            refAddr = new StringRefAddr(DESCRIPTION, description);
+            add(refAddr);
+        }
+        if (scope != null) {
+            refAddr = new StringRefAddr(SCOPE, scope);
+            add(refAddr);
+        }
+        if (auth != null) {
+            refAddr = new StringRefAddr(AUTH, auth);
+            add(refAddr);
+        }
+    }
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    // ------------------------------------------------------ Reference Methods
+
+
+    /**
+     * Retrieves the class name of the factory of the object to which this 
+     * reference refers.
+     */
+    public String getFactoryClassName() {
+        String factory = super.getFactoryClassName();
+        if (factory != null) {
+            return factory;
+        } else {
+            factory = System.getProperty(Context.OBJECT_FACTORIES);
+            if (factory != null) {
+                return null;
+            } else {
+                return DEFAULT_FACTORY;
+            }
+        }
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Return a String rendering of this object.
+     */
+    public String toString() {
+
+        StringBuffer sb = new StringBuffer("ResourceRef[");
+        sb.append("className=");
+        sb.append(getClassName());
+        sb.append(",factoryClassLocation=");
+        sb.append(getFactoryClassLocation());
+        sb.append(",factoryClassName=");
+        sb.append(getFactoryClassName());
+        Enumeration refAddrs = getAll();
+        while (refAddrs.hasMoreElements()) {
+            RefAddr refAddr = (RefAddr) refAddrs.nextElement();
+            sb.append(",{type=");
+            sb.append(refAddr.getType());
+            sb.append(",content=");
+            sb.append(refAddr.getContent());
+            sb.append("}");
+        }
+        sb.append("]");
+        return (sb.toString());
+
+    }
+
+
+    // ------------------------------------------------------------- Properties
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/SelectorContext.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/SelectorContext.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/SelectorContext.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,694 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.naming;
+
+import java.util.Hashtable;
+import javax.naming.Context;
+import javax.naming.Name;
+import javax.naming.NameParser;
+import javax.naming.NamingEnumeration;
+import javax.naming.NamingException;
+
+/**
+ * Catalina JNDI Context implementation.
+ *
+ * @author Remy Maucherat
+ * @version $Revision: 303999 $ $Date: 2005-07-20 16:25:18 -0500 (Wed, 20 Jul 2005) $
+ */
+
+public class SelectorContext implements Context {
+
+
+    // -------------------------------------------------------------- Constants
+
+
+    /**
+     * Namespace URL.
+     */
+    public static final String prefix = "java:";
+
+
+    /**
+     * Namespace URL length.
+     */
+    public static final int prefixLength = prefix.length();
+
+
+    /**
+     * Initial context prefix.
+     */
+    public static final String IC_PREFIX = "IC_";
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Builds a Catalina selector context using the given environment.
+     */
+    public SelectorContext(Hashtable env) {
+        this.env = env;
+    }
+
+
+    /**
+     * Builds a Catalina selector context using the given environment.
+     */
+    public SelectorContext(Hashtable env, boolean initialContext) {
+        this(env);
+        this.initialContext = initialContext;
+    }
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * Environment.
+     */
+    protected Hashtable env;
+
+
+    /**
+     * The string manager for this package.
+     */
+    protected StringManager sm = StringManager.getManager(Constants.Package);
+
+
+    /**
+     * Request for an initial context.
+     */
+    protected boolean initialContext = false;
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    // -------------------------------------------------------- Context Methods
+
+
+    /**
+     * Retrieves the named object. If name is empty, returns a new instance 
+     * of this context (which represents the same naming context as this 
+     * context, but its environment may be modified independently and it may 
+     * be accessed concurrently).
+     * 
+     * @param name the name of the object to look up
+     * @return the object bound to name
+     * @exception NamingException if a naming exception is encountered
+     */
+    public Object lookup(Name name)
+        throws NamingException {
+        // Strip the URL header
+        // Find the appropriate NamingContext according to the current bindings
+        // Execute the lookup on that context
+        return getBoundContext().lookup(parseName(name));
+    }
+
+
+    /**
+     * Retrieves the named object.
+     * 
+     * @param name the name of the object to look up
+     * @return the object bound to name
+     * @exception NamingException if a naming exception is encountered
+     */
+    public Object lookup(String name)
+        throws NamingException {
+        // Strip the URL header
+        // Find the appropriate NamingContext according to the current bindings
+        // Execute the lookup on that context
+        return getBoundContext().lookup(parseName(name));
+    }
+
+
+    /**
+     * Binds a name to an object. All intermediate contexts and the target 
+     * context (that named by all but terminal atomic component of the name) 
+     * must already exist.
+     * 
+     * @param name the name to bind; may not be empty
+     * @param obj the object to bind; possibly null
+     * @exception NameAlreadyBoundException if name is already bound
+     * @exception InvalidAttributesException if object did not supply all 
+     * mandatory attributes
+     * @exception NamingException if a naming exception is encountered
+     */
+    public void bind(Name name, Object obj)
+        throws NamingException {
+        getBoundContext().bind(parseName(name), obj);
+    }
+
+
+    /**
+     * Binds a name to an object.
+     * 
+     * @param name the name to bind; may not be empty
+     * @param obj the object to bind; possibly null
+     * @exception NameAlreadyBoundException if name is already bound
+     * @exception InvalidAttributesException if object did not supply all 
+     * mandatory attributes
+     * @exception NamingException if a naming exception is encountered
+     */
+    public void bind(String name, Object obj)
+        throws NamingException {
+        getBoundContext().bind(parseName(name), obj);
+    }
+
+
+    /**
+     * Binds a name to an object, overwriting any existing binding. All 
+     * intermediate contexts and the target context (that named by all but 
+     * terminal atomic component of the name) must already exist.
+     * <p>
+     * If the object is a DirContext, any existing attributes associated with 
+     * the name are replaced with those of the object. Otherwise, any 
+     * existing attributes associated with the name remain unchanged.
+     * 
+     * @param name the name to bind; may not be empty
+     * @param obj the object to bind; possibly null
+     * @exception InvalidAttributesException if object did not supply all 
+     * mandatory attributes
+     * @exception NamingException if a naming exception is encountered
+     */
+    public void rebind(Name name, Object obj)
+        throws NamingException {
+        getBoundContext().rebind(parseName(name), obj);
+    }
+
+
+    /**
+     * Binds a name to an object, overwriting any existing binding.
+     * 
+     * @param name the name to bind; may not be empty
+     * @param obj the object to bind; possibly null
+     * @exception InvalidAttributesException if object did not supply all 
+     * mandatory attributes
+     * @exception NamingException if a naming exception is encountered
+     */
+    public void rebind(String name, Object obj)
+        throws NamingException {
+        getBoundContext().rebind(parseName(name), obj);
+    }
+
+
+    /**
+     * Unbinds the named object. Removes the terminal atomic name in name 
+     * from the target context--that named by all but the terminal atomic 
+     * part of name.
+     * <p>
+     * This method is idempotent. It succeeds even if the terminal atomic 
+     * name is not bound in the target context, but throws 
+     * NameNotFoundException if any of the intermediate contexts do not exist. 
+     * 
+     * @param name the name to bind; may not be empty
+     * @exception NameNotFoundException if an intermediate context does not 
+     * exist
+     * @exception NamingException if a naming exception is encountered
+     */
+    public void unbind(Name name)
+        throws NamingException {
+        getBoundContext().unbind(parseName(name));
+    }
+
+
+    /**
+     * Unbinds the named object.
+     * 
+     * @param name the name to bind; may not be empty
+     * @exception NameNotFoundException if an intermediate context does not 
+     * exist
+     * @exception NamingException if a naming exception is encountered
+     */
+    public void unbind(String name)
+        throws NamingException {
+        getBoundContext().unbind(parseName(name));
+    }
+
+
+    /**
+     * Binds a new name to the object bound to an old name, and unbinds the 
+     * old name. Both names are relative to this context. Any attributes 
+     * associated with the old name become associated with the new name. 
+     * Intermediate contexts of the old name are not changed.
+     * 
+     * @param oldName the name of the existing binding; may not be empty
+     * @param newName the name of the new binding; may not be empty
+     * @exception NameAlreadyBoundException if newName is already bound
+     * @exception NamingException if a naming exception is encountered
+     */
+    public void rename(Name oldName, Name newName)
+        throws NamingException {
+        getBoundContext().rename(parseName(oldName), parseName(newName));
+    }
+
+
+    /**
+     * Binds a new name to the object bound to an old name, and unbinds the 
+     * old name.
+     * 
+     * @param oldName the name of the existing binding; may not be empty
+     * @param newName the name of the new binding; may not be empty
+     * @exception NameAlreadyBoundException if newName is already bound
+     * @exception NamingException if a naming exception is encountered
+     */
+    public void rename(String oldName, String newName)
+        throws NamingException {
+        getBoundContext().rename(parseName(oldName), parseName(newName));
+    }
+
+
+    /**
+     * 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
+     */
+    public NamingEnumeration list(Name name)
+        throws NamingException {
+        return getBoundContext().list(parseName(name));
+    }
+
+
+    /**
+     * Enumerates the names bound in the named context, along with the class 
+     * names of objects bound to them.
+     * 
+     * @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
+     */
+    public NamingEnumeration list(String name)
+        throws NamingException {
+        return getBoundContext().list(parseName(name));
+    }
+
+
+    /**
+     * Enumerates the names bound in the named context, along with the 
+     * 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 bindings in this context. 
+     * Each element of the enumeration is of type Binding.
+     * @exception NamingException if a naming exception is encountered
+     */
+    public NamingEnumeration listBindings(Name name)
+        throws NamingException {
+        return getBoundContext().listBindings(parseName(name));
+    }
+
+
+    /**
+     * Enumerates the names bound in the named context, along with the 
+     * objects bound to them.
+     * 
+     * @param name the name of the context to list
+     * @return an enumeration of the bindings in this context. 
+     * Each element of the enumeration is of type Binding.
+     * @exception NamingException if a naming exception is encountered
+     */
+    public NamingEnumeration listBindings(String name)
+        throws NamingException {
+        return getBoundContext().listBindings(parseName(name));
+    }
+
+
+    /**
+     * Destroys the named context and removes it from the namespace. Any 
+     * attributes associated with the name are also removed. Intermediate 
+     * contexts are not destroyed.
+     * <p>
+     * This method is idempotent. It succeeds even if the terminal atomic 
+     * name is not bound in the target context, but throws 
+     * NameNotFoundException if any of the intermediate contexts do not exist. 
+     * 
+     * In a federated naming system, a context from one naming system may be 
+     * bound to a name in another. One can subsequently look up and perform 
+     * operations on the foreign context using a composite name. However, an 
+     * attempt destroy the context using this composite name will fail with 
+     * NotContextException, because the foreign context is not a "subcontext" 
+     * of the context in which it is bound. Instead, use unbind() to remove 
+     * the binding of the foreign context. Destroying the foreign context 
+     * requires that the destroySubcontext() be performed on a context from 
+     * the foreign context's "native" naming system.
+     * 
+     * @param name the name of the context to be destroyed; may not be empty
+     * @exception NameNotFoundException if an intermediate context does not 
+     * exist
+     * @exception NotContextException if the name is bound but does not name 
+     * a context, or does not name a context of the appropriate type
+     */
+    public void destroySubcontext(Name name)
+        throws NamingException {
+        getBoundContext().destroySubcontext(parseName(name));
+    }
+
+
+    /**
+     * Destroys the named context and removes it from the namespace.
+     * 
+     * @param name the name of the context to be destroyed; may not be empty
+     * @exception NameNotFoundException if an intermediate context does not 
+     * exist
+     * @exception NotContextException if the name is bound but does not name 
+     * a context, or does not name a context of the appropriate type
+     */
+    public void destroySubcontext(String name)
+        throws NamingException {
+        getBoundContext().destroySubcontext(parseName(name));
+    }
+
+
+    /**
+     * Creates and binds a new context. Creates a new context with the given 
+     * name and binds it in the target context (that named by all but 
+     * terminal atomic component of the name). All intermediate contexts and 
+     * the target context must already exist.
+     * 
+     * @param name the name of the context to create; may not be empty
+     * @return the newly created context
+     * @exception NameAlreadyBoundException if name is already bound
+     * @exception InvalidAttributesException if creation of the subcontext 
+     * requires specification of mandatory attributes
+     * @exception NamingException if a naming exception is encountered
+     */
+    public Context createSubcontext(Name name)
+        throws NamingException {
+        return getBoundContext().createSubcontext(parseName(name));
+    }
+
+
+    /**
+     * Creates and binds a new context.
+     * 
+     * @param name the name of the context to create; may not be empty
+     * @return the newly created context
+     * @exception NameAlreadyBoundException if name is already bound
+     * @exception InvalidAttributesException if creation of the subcontext 
+     * requires specification of mandatory attributes
+     * @exception NamingException if a naming exception is encountered
+     */
+    public Context createSubcontext(String name)
+        throws NamingException {
+        return getBoundContext().createSubcontext(parseName(name));
+    }
+
+
+    /**
+     * Retrieves the named object, following links except for the terminal 
+     * atomic component of the name. If the object bound to name is not a 
+     * link, returns the object itself.
+     * 
+     * @param name the name of the object to look up
+     * @return the object bound to name, not following the terminal link 
+     * (if any).
+     * @exception NamingException if a naming exception is encountered
+     */
+    public Object lookupLink(Name name)
+        throws NamingException {
+        return getBoundContext().lookupLink(parseName(name));
+    }
+
+
+    /**
+     * Retrieves the named object, following links except for the terminal 
+     * atomic component of the name.
+     * 
+     * @param name the name of the object to look up
+     * @return the object bound to name, not following the terminal link 
+     * (if any).
+     * @exception NamingException if a naming exception is encountered
+     */
+    public Object lookupLink(String name)
+        throws NamingException {
+        return getBoundContext().lookupLink(parseName(name));
+    }
+
+
+    /**
+     * Retrieves the parser associated with the named context. In a 
+     * federation of namespaces, different naming systems will parse names 
+     * differently. This method allows an application to get a parser for 
+     * parsing names into their atomic components using the naming convention 
+     * of a particular naming system. Within any single naming system, 
+     * NameParser objects returned by this method must be equal (using the 
+     * equals() test).
+     * 
+     * @param name the name of the context from which to get the parser
+     * @return a name parser that can parse compound names into their atomic 
+     * components
+     * @exception NamingException if a naming exception is encountered
+     */
+    public NameParser getNameParser(Name name)
+        throws NamingException {
+        return getBoundContext().getNameParser(parseName(name));
+    }
+
+
+    /**
+     * Retrieves the parser associated with the named context.
+     * 
+     * @param name the name of the context from which to get the parser
+     * @return a name parser that can parse compound names into their atomic 
+     * components
+     * @exception NamingException if a naming exception is encountered
+     */
+    public NameParser getNameParser(String name)
+        throws NamingException {
+        return getBoundContext().getNameParser(parseName(name));
+    }
+
+
+    /**
+     * Composes the name of this context with a name relative to this context.
+     * <p>
+     * Given a name (name) relative to this context, and the name (prefix) 
+     * of this context relative to one of its ancestors, this method returns 
+     * the composition of the two names using the syntax appropriate for the 
+     * naming system(s) involved. That is, if name names an object relative 
+     * to this context, the result is the name of the same object, but 
+     * relative to the ancestor context. None of the names may be null.
+     * 
+     * @param name a name relative to this context
+     * @param prefix the name of this context relative to one of its ancestors
+     * @return the composition of prefix and name
+     * @exception NamingException if a naming exception is encountered
+     */
+    public Name composeName(Name name, Name prefix)
+        throws NamingException {
+        prefix = (Name) prefix.clone();
+        return prefix.addAll(name);
+    }
+
+
+    /**
+     * Composes the name of this context with a name relative to this context.
+     * 
+     * @param name a name relative to this context
+     * @param prefix the name of this context relative to one of its ancestors
+     * @return the composition of prefix and name
+     * @exception NamingException if a naming exception is encountered
+     */
+    public String composeName(String name, String prefix)
+        throws NamingException {
+        return prefix + "/" + name;
+    }
+
+
+    /**
+     * Adds a new environment property to the environment of this context. If 
+     * the property already exists, its value is overwritten.
+     * 
+     * @param propName the name of the environment property to add; may not 
+     * be null
+     * @param propVal the value of the property to add; may not be null
+     * @exception NamingException if a naming exception is encountered
+     */
+    public Object addToEnvironment(String propName, Object propVal)
+        throws NamingException {
+        return getBoundContext().addToEnvironment(propName, propVal);
+    }
+
+
+    /**
+     * Removes an environment property from the environment of this context. 
+     * 
+     * @param propName the name of the environment property to remove; 
+     * may not be null
+     * @exception NamingException if a naming exception is encountered
+     */
+    public Object removeFromEnvironment(String propName)
+        throws NamingException {
+        return getBoundContext().removeFromEnvironment(propName);
+    }
+
+
+    /**
+     * Retrieves the environment in effect for this context. See class 
+     * description for more details on environment properties. 
+     * The caller should not make any changes to the object returned: their 
+     * effect on the context is undefined. The environment of this context 
+     * may be changed using addToEnvironment() and removeFromEnvironment().
+     * 
+     * @return the environment of this context; never null
+     * @exception NamingException if a naming exception is encountered
+     */
+    public Hashtable getEnvironment()
+        throws NamingException {
+        return getBoundContext().getEnvironment();
+    }
+
+
+    /**
+     * Closes this context. This method releases this context's resources 
+     * immediately, instead of waiting for them to be released automatically 
+     * by the garbage collector.
+     * This method is idempotent: invoking it on a context that has already 
+     * been closed has no effect. Invoking any other method on a closed 
+     * context is not allowed, and results in undefined behaviour.
+     * 
+     * @exception NamingException if a naming exception is encountered
+     */
+    public void close()
+        throws NamingException {
+        getBoundContext().close();
+    }
+
+
+    /**
+     * Retrieves the full name of this context within its own namespace.
+     * <p>
+     * Many naming services have a notion of a "full name" for objects in 
+     * their respective namespaces. For example, an LDAP entry has a 
+     * distinguished name, and a DNS record has a fully qualified name. This 
+     * method allows the client application to retrieve this name. The string 
+     * returned by this method is not a JNDI composite name and should not be 
+     * passed directly to context methods. In naming systems for which the 
+     * notion of full name does not make sense, 
+     * OperationNotSupportedException is thrown.
+     * 
+     * @return this context's name in its own namespace; never null
+     * @exception OperationNotSupportedException if the naming system does 
+     * not have the notion of a full name
+     * @exception NamingException if a naming exception is encountered
+     */
+    public String getNameInNamespace()
+        throws NamingException {
+        return prefix;
+    }
+
+
+    // ------------------------------------------------------ Protected Methods
+
+
+    /**
+     * Get the bound context.
+     */
+    protected Context getBoundContext()
+        throws NamingException {
+
+        if (initialContext) {
+            String ICName = IC_PREFIX;
+            if (ContextBindings.isThreadBound()) {
+                ICName += ContextBindings.getThreadName();
+            } else if (ContextBindings.isClassLoaderBound()) {
+                ICName += ContextBindings.getClassLoaderName();
+            }
+            Context initialContext = ContextBindings.getContext(ICName);
+            if (initialContext == null) {
+                // Allocating a new context and binding it to the appropriate 
+                // name
+                initialContext = new NamingContext(env, ICName);
+                ContextBindings.bindContext(ICName, initialContext);
+            }
+            return initialContext;
+        } else {
+            if (ContextBindings.isThreadBound()) {
+                return ContextBindings.getThread();
+            } else {
+                return ContextBindings.getClassLoader();
+            }
+        }
+
+    }
+
+
+    /**
+     * Strips the URL header.
+     * 
+     * @return the parsed name
+     * @exception NamingException if there is no "java:" header or if no 
+     * naming context has been bound to this thread
+     */
+    protected String parseName(String name) 
+        throws NamingException {
+        
+        if ((!initialContext) && (name.startsWith(prefix))) {
+            return (name.substring(prefixLength));
+        } else {
+            if (initialContext) {
+                return (name);
+            } else {
+                throw new NamingException
+                    (sm.getString("selectorContext.noJavaUrl"));
+            }
+        }
+        
+    }
+
+
+    /**
+     * Strips the URL header.
+     * 
+     * @return the parsed name
+     * @exception NamingException if there is no "java:" header or if no 
+     * naming context has been bound to this thread
+     */
+    protected Name parseName(Name name) 
+        throws NamingException {
+
+        if ((!initialContext) && (!name.isEmpty()) 
+            && (name.get(0).equals(prefix))) {
+            return (name.getSuffix(1));
+        } else {
+            if (initialContext) {
+                return (name);
+            } else {
+                throw new NamingException
+                    (sm.getString("selectorContext.noJavaUrl"));
+            }
+        }
+
+    }
+
+
+}
+

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/StringManager.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/StringManager.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/StringManager.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,217 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.naming;
+
+import java.text.MessageFormat;
+import java.util.Hashtable;
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+
+/**
+ * An internationalization / localization helper class which reduces
+ * the bother of handling ResourceBundles and takes care of the
+ * common cases of message formating which otherwise require the
+ * creation of Object arrays and such.
+ *
+ * <p>The StringManager operates on a package basis. One StringManager
+ * per package can be created and accessed via the getManager method
+ * call.
+ *
+ * <p>The StringManager will look for a ResourceBundle named by
+ * the package name given plus the suffix of "LocalStrings". In
+ * practice, this means that the localized information will be contained
+ * in a LocalStrings.properties file located in the package
+ * directory of the classpath.
+ *
+ * <p>Please see the documentation for java.util.ResourceBundle for
+ * more information.
+ *
+ * @author James Duncan Davidson [duncan at eng.sun.com]
+ * @author James Todd [gonzo at eng.sun.com]
+ */
+
+public class StringManager {
+
+    /**
+     * The ResourceBundle for this StringManager.
+     */
+    
+    private ResourceBundle bundle;
+
+    /**
+     * Creates a new StringManager for a given package. This is a
+     * private method and all access to it is arbitrated by the
+     * static getManager method call so that only one StringManager
+     * per package will be created.
+     *
+     * @param packageName Name of package to create StringManager for.
+     */
+
+    private StringManager(String packageName) {
+	String bundleName = packageName + ".LocalStrings";
+	bundle = ResourceBundle.getBundle(bundleName);
+    }
+
+    /**
+     * Get a string from the underlying resource bundle.
+     *
+     * @param key 
+     */
+    
+    public String getString(String key) {
+        if (key == null) {
+            String msg = "key is null";
+
+            throw new NullPointerException(msg);
+        }
+
+        String str = null;
+
+        try {
+	    str = bundle.getString(key);
+        } catch (MissingResourceException mre) {
+            str = "Cannot find message associated with key '" + key + "'";
+        }
+
+        return str;
+    }
+
+    /**
+     * Get a string from the underlying resource bundle and format
+     * it with the given set of arguments.
+     *
+     * @param key
+     * @param args
+     */
+
+    public String getString(String key, Object[] args) {
+	String iString = null;
+        String value = getString(key);
+
+	// this check for the runtime exception is some pre 1.1.6
+	// VM's don't do an automatic toString() on the passed in
+	// objects and barf out
+	
+	try {
+            // ensure the arguments are not null so pre 1.2 VM's don't barf
+            Object nonNullArgs[] = args;
+            for (int i=0; i<args.length; i++) {
+		if (args[i] == null) {
+		    if (nonNullArgs==args) nonNullArgs=(Object[])args.clone();
+		    nonNullArgs[i] = "null";
+		}
+	    }
+ 
+            iString = MessageFormat.format(value, nonNullArgs);
+	} catch (IllegalArgumentException iae) {
+	    StringBuffer buf = new StringBuffer();
+	    buf.append(value);
+	    for (int i = 0; i < args.length; i++) {
+		buf.append(" arg[" + i + "]=" + args[i]);
+	    }
+	    iString = buf.toString();
+	}
+	return iString;
+    }
+
+    /**
+     * Get a string from the underlying resource bundle and format it
+     * with the given object argument. This argument can of course be
+     * a String object.
+     *
+     * @param key
+     * @param arg
+     */
+
+    public String getString(String key, Object arg) {
+	Object[] args = new Object[] {arg};
+	return getString(key, args);
+    }
+
+    /**
+     * Get a string from the underlying resource bundle and format it
+     * with the given object arguments. These arguments can of course
+     * be String objects.
+     *
+     * @param key
+     * @param arg1
+     * @param arg2
+     */
+
+    public String getString(String key, Object arg1, Object arg2) {
+	Object[] args = new Object[] {arg1, arg2};
+	return getString(key, args);
+    }
+    
+    /**
+     * Get a string from the underlying resource bundle and format it
+     * with the given object arguments. These arguments can of course
+     * be String objects.
+     *
+     * @param key
+     * @param arg1
+     * @param arg2
+     * @param arg3
+     */
+
+    public String getString(String key, Object arg1, Object arg2,
+			    Object arg3) {
+	Object[] args = new Object[] {arg1, arg2, arg3};
+	return getString(key, args);
+    }
+    
+    /**
+     * Get a string from the underlying resource bundle and format it
+     * with the given object arguments. These arguments can of course
+     * be String objects.
+     *
+     * @param key
+     * @param arg1
+     * @param arg2
+     * @param arg3
+     * @param arg4
+     */
+
+    public String getString(String key, Object arg1, Object arg2,
+			    Object arg3, Object arg4) {
+	Object[] args = new Object[] {arg1, arg2, arg3, arg4};
+	return getString(key, args);
+    }   
+    // --------------------------------------------------------------
+    // STATIC SUPPORT METHODS
+    // --------------------------------------------------------------
+
+    private static Hashtable managers = new Hashtable();
+
+    /**
+     * Get the StringManager for a particular package. If a manager for
+     * a package already exists, it will be reused, else a new
+     * StringManager will be created and returned.
+     *
+     * @param packageName
+     */
+
+    public synchronized static StringManager getManager(String packageName) {
+	StringManager mgr = (StringManager)managers.get(packageName);
+	if (mgr == null) {
+	    mgr = new StringManager(packageName);
+	    managers.put(packageName, mgr);
+	}
+	return mgr;
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/TransactionRef.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/TransactionRef.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/TransactionRef.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,94 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.naming;
+
+import javax.naming.Context;
+import javax.naming.Reference;
+
+/**
+ * Represents a reference address to a transaction.
+ *
+ * @author Remy Maucherat
+ * @version $Revision: 303133 $ $Date: 2004-08-29 11:46:15 -0500 (Sun, 29 Aug 2004) $
+ */
+
+public class TransactionRef
+    extends Reference {
+
+
+    // -------------------------------------------------------------- Constants
+
+
+    /**
+     * Default factory for this reference.
+     */
+    public static final String DEFAULT_FACTORY = 
+        org.apache.naming.factory.Constants.DEFAULT_TRANSACTION_FACTORY;
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Resource Reference.
+     */
+    public TransactionRef() {
+        this(null, null);
+    }
+
+
+    /**
+     * Resource Reference.
+     *
+     * @param factory The factory class
+     * @param factoryLocation The factory location
+     */
+    public TransactionRef(String factory, String factoryLocation) {
+        super("javax.transaction.UserTransaction", factory, factoryLocation);
+    }
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    // ------------------------------------------------------ Reference Methods
+
+
+    /**
+     * Retrieves the class name of the factory of the object to which this 
+     * reference refers.
+     */
+    public String getFactoryClassName() {
+        String factory = super.getFactoryClassName();
+        if (factory != null) {
+            return factory;
+        } else {
+            factory = System.getProperty(Context.OBJECT_FACTORIES);
+            if (factory != null) {
+                return null;
+            } else {
+                return DEFAULT_FACTORY;
+            }
+        }
+    }
+
+
+    // ------------------------------------------------------------- Properties
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/factory/BeanFactory.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/factory/BeanFactory.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/factory/BeanFactory.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,245 @@
+/*
+ * Copyright 1999-2001,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.naming.factory;
+
+import java.util.Hashtable;
+import java.util.Enumeration;
+import javax.naming.Name;
+import javax.naming.Context;
+import javax.naming.NamingException;
+import javax.naming.Reference;
+import javax.naming.RefAddr;
+import javax.naming.spi.ObjectFactory;
+import org.apache.naming.ResourceRef;
+
+import java.beans.Introspector;
+import java.beans.BeanInfo;
+import java.beans.PropertyDescriptor;
+
+import java.lang.reflect.Method;
+
+/**
+ * Object factory for any Resource conforming to the JavaBean spec.
+ * 
+ * <p>This factory can be configured in a <code>&lt;DefaultContext&gt;</code>
+ * or <code>&lt;Context&gt;</code> element in your <code>conf/server.xml</code>
+ * configuration file.  An example of factory configuration is:</p>
+ * <pre>
+ * &lt;Resource name="jdbc/myDataSource" auth="SERVLET"
+ *   type="oracle.jdbc.pool.OracleConnectionCacheImpl"/&gt;
+ * &lt;ResourceParams name="jdbc/myDataSource"&gt;
+ *   &lt;parameter&gt;
+ *     &lt;name&gt;factory&lt;/name&gt;
+ *     &lt;value&gt;org.apache.naming.factory.BeanFactory&lt;/value&gt;
+ *   &lt;/parameter&gt;
+ *   &lt;parameter&gt;
+ *     &lt;name&gt;driverType&lt;/name&gt;
+ *     &lt;value&gt;thin&lt;/value&gt;
+ *   &lt;/parameter&gt;
+ *   &lt;parameter&gt;
+ *     &lt;name&gt;serverName&lt;/name&gt;
+ *     &lt;value&gt;hue&lt;/value&gt;
+ *   &lt;/parameter&gt;
+ *   &lt;parameter&gt;
+ *     &lt;name&gt;networkProtocol&lt;/name&gt;
+ *     &lt;value&gt;tcp&lt;/value&gt;
+ *   &lt;/parameter&gt; 
+ *   &lt;parameter&gt;
+ *     &lt;name&gt;databaseName&lt;/name&gt;
+ *     &lt;value&gt;XXXX&lt;/value&gt;
+ *   &lt;/parameter&gt;
+ *   &lt;parameter&gt;
+ *     &lt;name&gt;portNumber&lt;/name&gt;
+ *     &lt;value&gt;NNNN&lt;/value&gt;
+ *   &lt;/parameter&gt;
+ *   &lt;parameter&gt;
+ *     &lt;name&gt;user&lt;/name&gt;
+ *     &lt;value&gt;XXXX&lt;/value&gt;
+ *   &lt;/parameter&gt;
+ *   &lt;parameter&gt;
+ *     &lt;name&gt;password&lt;/name&gt;
+ *     &lt;value&gt;XXXX&lt;/value&gt;
+ *   &lt;/parameter&gt;
+ *   &lt;parameter&gt;
+ *     &lt;name&gt;maxLimit&lt;/name&gt;
+ *     &lt;value&gt;5&lt;/value&gt;
+ *   &lt;/parameter&gt;
+ * &lt;/ResourceParams&gt;
+ * </pre>
+ *
+ * @author <a href="mailto:aner at ncstech.com">Aner Perez</a>
+ */
+public class BeanFactory
+    implements ObjectFactory {
+
+    // ----------------------------------------------------------- Constructors
+
+
+    // -------------------------------------------------------------- Constants
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    // -------------------------------------------------- ObjectFactory Methods
+
+
+    /**
+     * Create a new Bean instance.
+     * 
+     * @param obj The reference object describing the Bean
+     */
+    public Object getObjectInstance(Object obj, Name name, Context nameCtx,
+                                    Hashtable environment)
+        throws NamingException {
+
+        if (obj instanceof ResourceRef) {
+
+            try {
+                
+                Reference ref = (Reference) obj;
+                String beanClassName = ref.getClassName();
+                Class beanClass = null;
+                ClassLoader tcl = 
+                    Thread.currentThread().getContextClassLoader();
+                if (tcl != null) {
+                    try {
+                        beanClass = tcl.loadClass(beanClassName);
+                    } catch(ClassNotFoundException e) {
+                    }
+                } else {
+                    try {
+                        beanClass = Class.forName(beanClassName);
+                    } catch(ClassNotFoundException e) {
+                        e.printStackTrace();
+                    }
+                }
+                if (beanClass == null) {
+                    throw new NamingException
+                        ("Class not found: " + beanClassName);
+                }
+                
+                BeanInfo bi = Introspector.getBeanInfo(beanClass);
+                PropertyDescriptor[] pda = bi.getPropertyDescriptors();
+                
+                Object bean = beanClass.newInstance();
+                
+                Enumeration e = ref.getAll();
+                while (e.hasMoreElements()) {
+                    
+                    RefAddr ra = (RefAddr) e.nextElement();
+                    String propName = ra.getType();
+                    
+                    if (propName.equals(Constants.FACTORY) ||
+                        propName.equals("scope") || propName.equals("auth")) {
+                        continue;
+                    }
+                    
+                    String value = (String)ra.getContent();
+                    
+                    Object[] valueArray = new Object[1];
+                    
+                    int i = 0;
+                    for (i = 0; i<pda.length; i++) {
+
+                        if (pda[i].getName().equals(propName)) {
+
+                            Class propType = pda[i].getPropertyType();
+
+                            if (propType.equals(String.class)) {
+                                valueArray[0] = value;
+                            } else if (propType.equals(Character.class) 
+                                       || propType.equals(char.class)) {
+                                valueArray[0] = new Character(value.charAt(0));
+                            } else if (propType.equals(Byte.class) 
+                                       || propType.equals(byte.class)) {
+                                valueArray[0] = new Byte(value);
+                            } else if (propType.equals(Short.class) 
+                                       || propType.equals(short.class)) {
+                                valueArray[0] = new Short(value);
+                            } else if (propType.equals(Integer.class) 
+                                       || propType.equals(int.class)) {
+                                valueArray[0] = new Integer(value);
+                            } else if (propType.equals(Long.class) 
+                                       || propType.equals(long.class)) {
+                                valueArray[0] = new Long(value);
+                            } else if (propType.equals(Float.class) 
+                                       || propType.equals(float.class)) {
+                                valueArray[0] = new Float(value);
+                            } else if (propType.equals(Double.class) 
+                                       || propType.equals(double.class)) {
+                                valueArray[0] = new Double(value);
+                            } else if (propType.equals(Boolean.class)
+                                       || propType.equals(boolean.class)) {
+                                valueArray[0] = new Boolean(value);
+                            } else {
+                                throw new NamingException
+                                    ("String conversion for property type '"
+                                     + propType.getName() + "' not available");
+                            }
+                            
+                            Method setProp = pda[i].getWriteMethod();
+                            if (setProp != null) {
+                                setProp.invoke(bean, valueArray);
+                            } else {
+                                throw new NamingException
+                                    ("Write not allowed for property: " 
+                                     + propName);
+                            }
+
+                            break;
+
+                        }
+
+                    }
+
+                    if (i == pda.length) {
+                        throw new NamingException
+                            ("No set method found for property: " + propName);
+                    }
+
+                }
+
+                return bean;
+
+            } catch (java.beans.IntrospectionException ie) {
+                NamingException ne = new NamingException(ie.getMessage());
+                ne.setRootCause(ie);
+                throw ne;
+            } catch (java.lang.IllegalAccessException iae) {
+                NamingException ne = new NamingException(iae.getMessage());
+                ne.setRootCause(iae);
+                throw ne;
+            } catch (java.lang.InstantiationException ie2) {
+                NamingException ne = new NamingException(ie2.getMessage());
+                ne.setRootCause(ie2);
+                throw ne;
+            } catch (java.lang.reflect.InvocationTargetException ite) {
+                NamingException ne = new NamingException(ite.getMessage());
+                ne.setRootCause(ite);
+                throw ne;
+            }
+
+        } else {
+            return null;
+        }
+
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/factory/Constants.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/factory/Constants.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/factory/Constants.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,54 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.naming.factory;
+
+
+/**
+ * Static constants for this package.
+ */
+
+public final class Constants {
+
+    public static final String Package = "org.apache.naming.factory";
+
+    public static final String DEFAULT_RESOURCE_FACTORY = 
+        Package + ".ResourceFactory";
+
+    public static final String DEFAULT_RESOURCE_LINK_FACTORY = 
+        Package + ".ResourceLinkFactory";
+
+    public static final String DEFAULT_TRANSACTION_FACTORY = 
+        Package + ".TransactionFactory";
+
+    public static final String DEFAULT_RESOURCE_ENV_FACTORY = 
+        Package + ".ResourceEnvFactory";
+
+    public static final String DEFAULT_EJB_FACTORY = 
+        Package + ".EjbFactory";
+
+    public static final String DBCP_DATASOURCE_FACTORY = 
+        "org.apache.tomcat.dbcp.dbcp.BasicDataSourceFactory";
+
+    public static final String OPENEJB_EJB_FACTORY = 
+        Package + ".OpenEjbFactory";
+
+    public static final String OBJECT_FACTORIES = "";
+
+    public static final String FACTORY = "factory";
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/factory/EjbFactory.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/factory/EjbFactory.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/factory/EjbFactory.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,171 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.naming.factory;
+
+import java.util.Hashtable;
+import javax.naming.Name;
+import javax.naming.Context;
+import javax.naming.InitialContext;
+import javax.naming.NamingException;
+import javax.naming.Reference;
+import javax.naming.RefAddr;
+import javax.naming.spi.ObjectFactory;
+import org.apache.naming.EjbRef;
+
+/**
+ * Object factory for EJBs.
+ * 
+ * @author Remy Maucherat
+ * @version $Revision: 375650 $ $Date: 2006-02-07 11:55:11 -0600 (Tue, 07 Feb 2006) $
+ */
+
+public class EjbFactory
+    implements ObjectFactory {
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    // -------------------------------------------------------------- Constants
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    // -------------------------------------------------- ObjectFactory Methods
+
+
+    /**
+     * Crete a new EJB instance.
+     * 
+     * @param obj The reference object describing the DataSource
+     */
+    public Object getObjectInstance(Object obj, Name name, Context nameCtx,
+                                    Hashtable environment)
+        throws Exception {
+        
+        if (obj instanceof EjbRef) {
+            Reference ref = (Reference) obj;
+
+            // If ejb-link has been specified, resolving the link using JNDI
+            RefAddr linkRefAddr = ref.get(EjbRef.LINK);
+            if (linkRefAddr != null) {
+                // Retrieving the EJB link
+                String ejbLink = linkRefAddr.getContent().toString();
+                Object beanObj = (new InitialContext()).lookup(ejbLink);
+                // Load home interface and checking if bean correctly
+                // implements specified home interface
+                /*
+                String homeClassName = ref.getClassName();
+                try {
+                    Class home = Class.forName(homeClassName);
+                    if (home.isInstance(beanObj)) {
+                        System.out.println("Bean of type " 
+                                           + beanObj.getClass().getName() 
+                                           + " implements home interface " 
+                                           + home.getName());
+                    } else {
+                        System.out.println("Bean of type " 
+                                           + beanObj.getClass().getName() 
+                                           + " doesn't implement home interface " 
+                                           + home.getName());
+                        throw new NamingException
+                            ("Bean of type " + beanObj.getClass().getName() 
+                             + " doesn't implement home interface " 
+                             + home.getName());
+                    }
+                } catch (ClassNotFoundException e) {
+                    System.out.println("Couldn't load home interface "
+                                       + homeClassName);
+                }
+                */
+                return beanObj;
+            }
+            
+            ObjectFactory factory = null;
+            RefAddr factoryRefAddr = ref.get(Constants.FACTORY);
+            if (factoryRefAddr != null) {
+                // Using the specified factory
+                String factoryClassName = 
+                    factoryRefAddr.getContent().toString();
+                // Loading factory
+                ClassLoader tcl = 
+                    Thread.currentThread().getContextClassLoader();
+                Class factoryClass = null;
+                if (tcl != null) {
+                    try {
+                        factoryClass = tcl.loadClass(factoryClassName);
+                    } catch(ClassNotFoundException e) {
+                        NamingException ex = new NamingException
+                            ("Could not load resource factory class");
+                        ex.initCause(e);
+                        throw ex;
+                    }
+                } else {
+                    try {
+                        factoryClass = Class.forName(factoryClassName);
+                    } catch(ClassNotFoundException e) {
+                        NamingException ex = new NamingException
+                            ("Could not load resource factory class");
+                        ex.initCause(e);
+                        throw ex;
+                    }
+                }
+                if (factoryClass != null) {
+                    try {
+                        factory = (ObjectFactory) factoryClass.newInstance();
+                    } catch(Throwable t) {
+                    }
+                }
+            } else {
+                String javaxEjbFactoryClassName =
+                    System.getProperty("javax.ejb.Factory",
+                                       Constants.OPENEJB_EJB_FACTORY);
+                try {
+                    factory = (ObjectFactory)
+                        Class.forName(javaxEjbFactoryClassName).newInstance();
+                } catch(Throwable t) {
+                    if (t instanceof NamingException)
+                        throw (NamingException) t;
+                    NamingException ex = new NamingException
+                        ("Could not create resource factory instance");
+                    ex.initCause(t);
+                    throw ex;
+                }
+            }
+
+            if (factory != null) {
+                return factory.getObjectInstance
+                    (obj, name, nameCtx, environment);
+            } else {
+                throw new NamingException
+                    ("Cannot create resource instance");
+            }
+
+        }
+
+        return null;
+
+    }
+
+
+}
+

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/factory/MailSessionFactory.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/factory/MailSessionFactory.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/factory/MailSessionFactory.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,156 @@
+/*
+ * Copyright 1999-2001,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.naming.factory;
+
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Properties;
+import javax.mail.Authenticator;
+import javax.mail.PasswordAuthentication;
+import javax.mail.Session;
+import javax.naming.Name;
+import javax.naming.Context;
+import javax.naming.RefAddr;
+import javax.naming.Reference;
+import javax.naming.spi.ObjectFactory;
+
+/**
+ * <p>Factory class that creates a JNDI named JavaMail Session factory,
+ * which can be used for managing inbound and outbound electronic mail
+ * messages via JavaMail APIs.  All messaging environment properties
+ * described in the JavaMail Specification may be passed to the Session
+ * factory; however the following properties are the most commonly used:</p>
+ * <ul>
+ * <li>
+ * <li><strong>mail.smtp.host</strong> - Hostname for outbound transport
+ *     connections.  Defaults to <code>localhost</code> if not specified.</li>
+ * </ul>
+ *
+ * <p>This factory can be configured in a <code>&lt;DefaultContext&gt;</code>
+ * or <code>&lt;Context&gt;</code> element in your <code>conf/server.xml</code>
+ * configuration file.  An example of factory configuration is:</p>
+ * <pre>
+ * &lt;Resource name="mail/smtp" auth="CONTAINER"
+ *           type="javax.mail.Session"/&gt;
+ * &lt;ResourceParams name="mail/smtp"&gt;
+ *   &lt;parameter&gt;
+ *     &lt;name&gt;factory&lt;/name&gt;
+ *     &lt;value&gt;org.apache.naming.factory.MailSessionFactory&lt;/value&gt;
+ *   &lt;/parameter&gt;
+ *   &lt;parameter&gt;
+ *     &lt;name&gt;mail.smtp.host&lt;/name&gt;
+ *     &lt;value&gt;mail.mycompany.com&lt;/value&gt;
+ *   &lt;/parameter&gt;
+ * &lt;/ResourceParams&gt;
+ * </pre>
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 303771 $ $Date: 2005-03-23 09:30:56 -0600 (Wed, 23 Mar 2005) $
+ */
+
+public class MailSessionFactory implements ObjectFactory {
+
+
+    /**
+     * The Java type for which this factory knows how to create objects.
+     */
+    protected static final String factoryType = "javax.mail.Session";
+
+
+    /**
+     * Create and return an object instance based on the specified
+     * characteristics.
+     *
+     * @param refObj Reference information containing our parameters, or null
+     *  if there are no parameters
+     * @param name The name of this object, relative to context, or null
+     *  if there is no name
+     * @param context The context to which name is relative, or null if name
+     *  is relative to the default initial context
+     * @param env Environment variables, or null if there are none
+     *
+     * @exception Exception if an error occurs during object creation
+     */
+    public Object getObjectInstance(Object refObj, Name name, Context context,
+				    Hashtable env) throws Exception 
+    {
+
+        // Return null if we cannot create an object of the requested type
+	final Reference ref = (Reference) refObj;
+        if (!ref.getClassName().equals(factoryType))
+            return (null);
+
+        // Create a new Session inside a doPrivileged block, so that JavaMail
+        // can read its default properties without throwing Security
+        // exceptions.
+        //
+        // Bugzilla 31288, 33077: add support for authentication.
+        return AccessController.doPrivileged( new PrivilegedAction() {
+		public Object run() {
+
+                    // Create the JavaMail properties we will use
+                    Properties props = new Properties();
+                    props.put("mail.transport.protocol", "smtp");
+                    props.put("mail.smtp.host", "localhost");
+
+                    String password = null;
+
+                    Enumeration attrs = ref.getAll();
+                    while (attrs.hasMoreElements()) {
+                        RefAddr attr = (RefAddr) attrs.nextElement();
+                        if ("factory".equals(attr.getType())) {
+                            continue;
+                        }
+
+                        if ("password".equals(attr.getType())) {
+                            password = (String) attr.getContent();
+                            continue;
+                        }
+
+                        props.put(attr.getType(), (String) attr.getContent());
+                    }
+
+                    Authenticator auth = null;
+                    if (password != null) {
+                        String user = props.getProperty("mail.smtp.user");
+                        if(user == null) {
+                            user = props.getProperty("mail.user");
+                        }
+                        
+                        if(user != null) {
+                            final PasswordAuthentication pa = new PasswordAuthentication(user, password);
+                            auth = new Authenticator() {
+                                    protected PasswordAuthentication getPasswordAuthentication() {
+                                        return pa;
+                                    }
+                                };
+                        }
+                    }
+
+                    // Create and return the new Session object
+                    Session session = Session.getInstance(props, auth);
+                    return (session);
+
+		}
+	    } );
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/factory/OpenEjbFactory.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/factory/OpenEjbFactory.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/factory/OpenEjbFactory.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,89 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.naming.factory;
+
+import org.apache.naming.EjbRef;
+
+import javax.naming.Context;
+import javax.naming.InitialContext;
+import javax.naming.Name;
+import javax.naming.Reference;
+import javax.naming.RefAddr;
+import javax.naming.spi.ObjectFactory;
+import java.util.Hashtable;
+import java.util.Properties;
+
+/**
+ * Object factory for EJBs.
+ * 
+ * @author Jacek Laskowski
+ * @author Remy Maucherat
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+public class OpenEjbFactory implements ObjectFactory {
+
+
+    // -------------------------------------------------------------- Constants
+
+
+    protected static final String DEFAULT_OPENEJB_FACTORY = 
+        "org.openejb.client.LocalInitialContextFactory";
+
+
+    // -------------------------------------------------- ObjectFactory Methods
+
+
+    /**
+     * Crete a new EJB instance using OpenEJB.
+     * 
+     * @param obj The reference object describing the DataSource
+     */
+    public Object getObjectInstance(Object obj, Name name, Context nameCtx,
+                                    Hashtable environment)
+        throws Exception {
+
+        Object beanObj = null;
+
+        if (obj instanceof EjbRef) {
+
+            Reference ref = (Reference) obj;
+
+            String factory = DEFAULT_OPENEJB_FACTORY;
+            RefAddr factoryRefAddr = ref.get("openejb.factory");
+            if (factoryRefAddr != null) {
+                // Retrieving the OpenEJB factory
+                factory = factoryRefAddr.getContent().toString();
+            }
+
+            Properties env = new Properties();
+            env.put(Context.INITIAL_CONTEXT_FACTORY, factory);
+
+            RefAddr linkRefAddr = ref.get("openejb.link");
+            if (linkRefAddr != null) {
+                String ejbLink = linkRefAddr.getContent().toString();
+                beanObj = (new InitialContext(env)).lookup(ejbLink);
+            }
+
+        }
+
+        return beanObj;
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/factory/ResourceEnvFactory.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/factory/ResourceEnvFactory.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/factory/ResourceEnvFactory.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,124 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.naming.factory;
+
+import java.util.Hashtable;
+import javax.naming.Name;
+import javax.naming.Context;
+import javax.naming.NamingException;
+import javax.naming.Reference;
+import javax.naming.RefAddr;
+import javax.naming.spi.ObjectFactory;
+import org.apache.naming.ResourceEnvRef;
+
+/**
+ * Object factory for Resources env.
+ * 
+ * @author Remy Maucherat
+ * @version $Revision: 375650 $ $Date: 2006-02-07 11:55:11 -0600 (Tue, 07 Feb 2006) $
+ */
+
+public class ResourceEnvFactory
+    implements ObjectFactory {
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    // -------------------------------------------------------------- Constants
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    // -------------------------------------------------- ObjectFactory Methods
+
+
+    /**
+     * Crete a new Resource env instance.
+     * 
+     * @param obj The reference object describing the DataSource
+     */
+    public Object getObjectInstance(Object obj, Name name, Context nameCtx,
+                                    Hashtable environment)
+        throws Exception {
+        
+        if (obj instanceof ResourceEnvRef) {
+            Reference ref = (Reference) obj;
+            ObjectFactory factory = null;
+            RefAddr factoryRefAddr = ref.get(Constants.FACTORY);
+            if (factoryRefAddr != null) {
+                // Using the specified factory
+                String factoryClassName = 
+                    factoryRefAddr.getContent().toString();
+                // Loading factory
+                ClassLoader tcl = 
+                    Thread.currentThread().getContextClassLoader();
+                Class factoryClass = null;
+                if (tcl != null) {
+                    try {
+                        factoryClass = tcl.loadClass(factoryClassName);
+                    } catch(ClassNotFoundException e) {
+                        NamingException ex = new NamingException
+                            ("Could not load resource factory class");
+                        ex.initCause(e);
+                        throw ex;
+                    }
+                } else {
+                    try {
+                        factoryClass = Class.forName(factoryClassName);
+                    } catch(ClassNotFoundException e) {
+                        NamingException ex = new NamingException
+                            ("Could not load resource factory class");
+                        ex.initCause(e);
+                        throw ex;
+                    }
+                }
+                if (factoryClass != null) {
+                    try {
+                        factory = (ObjectFactory) factoryClass.newInstance();
+                    } catch(Throwable t) {
+                        if (t instanceof NamingException)
+                            throw (NamingException) t;
+                        NamingException ex = new NamingException
+                            ("Could not create resource factory instance");
+                        ex.initCause(t);
+                        throw ex;
+                    }
+                }
+            }
+            // Note: No defaults here
+            if (factory != null) {
+                return factory.getObjectInstance
+                    (obj, name, nameCtx, environment);
+            } else {
+                throw new NamingException
+                    ("Cannot create resource instance");
+            }
+        }
+
+        return null;
+
+    }
+
+
+}
+

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/factory/ResourceFactory.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/factory/ResourceFactory.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/factory/ResourceFactory.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,153 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.naming.factory;
+
+import java.util.Hashtable;
+import javax.naming.Name;
+import javax.naming.Context;
+import javax.naming.NamingException;
+import javax.naming.Reference;
+import javax.naming.RefAddr;
+import javax.naming.spi.ObjectFactory;
+import org.apache.naming.ResourceRef;
+
+/**
+ * Object factory for Resources.
+ * 
+ * @author Remy Maucherat
+ * @version $Revision: 375650 $ $Date: 2006-02-07 11:55:11 -0600 (Tue, 07 Feb 2006) $
+ */
+
+public class ResourceFactory
+    implements ObjectFactory {
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    // -------------------------------------------------------------- Constants
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    // -------------------------------------------------- ObjectFactory Methods
+
+
+    /**
+     * Crete a new DataSource instance.
+     * 
+     * @param obj The reference object describing the DataSource
+     */
+    public Object getObjectInstance(Object obj, Name name, Context nameCtx,
+                                    Hashtable environment)
+        throws Exception {
+        
+        if (obj instanceof ResourceRef) {
+            Reference ref = (Reference) obj;
+            ObjectFactory factory = null;
+            RefAddr factoryRefAddr = ref.get(Constants.FACTORY);
+            if (factoryRefAddr != null) {
+                // Using the specified factory
+                String factoryClassName = 
+                    factoryRefAddr.getContent().toString();
+                // Loading factory
+                ClassLoader tcl = 
+                    Thread.currentThread().getContextClassLoader();
+                Class factoryClass = null;
+                if (tcl != null) {
+                    try {
+                        factoryClass = tcl.loadClass(factoryClassName);
+                    } catch(ClassNotFoundException e) {
+                        NamingException ex = new NamingException
+                            ("Could not load resource factory class");
+                        ex.initCause(e);
+                        throw ex;
+                    }
+                } else {
+                    try {
+                        factoryClass = Class.forName(factoryClassName);
+                    } catch(ClassNotFoundException e) {
+                        NamingException ex = new NamingException
+                            ("Could not load resource factory class");
+                        ex.initCause(e);
+                        throw ex;
+                    }
+                }
+                if (factoryClass != null) {
+                    try {
+                        factory = (ObjectFactory) factoryClass.newInstance();
+                    } catch (Throwable t) {
+                        if (t instanceof NamingException)
+                            throw (NamingException) t;
+                        NamingException ex = new NamingException
+                            ("Could not create resource factory instance");
+                        ex.initCause(t);
+                        throw ex;
+                    }
+                }
+            } else {
+                if (ref.getClassName().equals("javax.sql.DataSource")) {
+                    String javaxSqlDataSourceFactoryClassName =
+                        System.getProperty("javax.sql.DataSource.Factory",
+                                           Constants.DBCP_DATASOURCE_FACTORY);
+                    try {
+                        factory = (ObjectFactory) 
+                            Class.forName(javaxSqlDataSourceFactoryClassName)
+                            .newInstance();
+                    } catch (Throwable t) {
+                        NamingException ex = new NamingException
+                            ("Could not create resource factory instance");
+                        ex.initCause(t);
+                        throw ex;
+                    }
+                } else if (ref.getClassName().equals("javax.mail.Session")) {
+                    String javaxMailSessionFactoryClassName =
+                        System.getProperty("javax.mail.Session.Factory",
+                                           "org.apache.naming.factory.MailSessionFactory");
+                    try {
+                        factory = (ObjectFactory) 
+                            Class.forName(javaxMailSessionFactoryClassName)
+                            .newInstance();
+                    } catch(Throwable t) {
+                        NamingException ex = new NamingException
+                            ("Could not create resource factory instance");
+                        ex.initCause(t);
+                        throw ex;
+                    }
+                }
+            }
+            if (factory != null) {
+                return factory.getObjectInstance
+                    (obj, name, nameCtx, environment);
+            } else {
+                throw new NamingException
+                    ("Cannot create resource instance");
+            }
+        }
+        
+        return null;
+
+    }
+
+
+}
+

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/factory/ResourceLinkFactory.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/factory/ResourceLinkFactory.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/factory/ResourceLinkFactory.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,107 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.naming.factory;
+
+import java.util.Hashtable;
+
+import javax.naming.Context;
+import javax.naming.Name;
+import javax.naming.NamingException;
+import javax.naming.RefAddr;
+import javax.naming.Reference;
+import javax.naming.spi.ObjectFactory;
+
+import org.apache.naming.ResourceLinkRef;
+
+
+/**
+ * <p>Object factory for resource links.</p>
+ * 
+ * @author Remy Maucherat
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class ResourceLinkFactory
+    implements ObjectFactory {
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    // ------------------------------------------------------- Static Variables
+
+
+    /**
+     * Global naming context.
+     */
+    private static Context globalContext = null;
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Set the global context (note: can only be used once).
+     * 
+     * @param newGlobalContext new global context value
+     */
+    public static void setGlobalContext(Context newGlobalContext) {
+        if (globalContext != null)
+            return;
+        globalContext = newGlobalContext;
+    }
+
+
+    // -------------------------------------------------- ObjectFactory Methods
+
+
+    /**
+     * Create a new DataSource instance.
+     * 
+     * @param obj The reference object describing the DataSource
+     */
+    public Object getObjectInstance(Object obj, Name name, Context nameCtx,
+                                    Hashtable environment)
+        throws NamingException {
+        
+        if (!(obj instanceof ResourceLinkRef))
+            return null;
+
+        // Can we process this request?
+        Reference ref = (Reference) obj;
+
+        String type = ref.getClassName();
+
+        // Read the global ref addr
+        String globalName = null;
+        RefAddr refAddr = ref.get(ResourceLinkRef.GLOBALNAME);
+        if (refAddr != null) {
+            globalName = refAddr.getContent().toString();
+            Object result = null;
+            result = globalContext.lookup(globalName);
+            // FIXME: Check type
+            return result;
+        }
+
+        return (null);
+
+        
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/factory/SendMailFactory.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/factory/SendMailFactory.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/factory/SendMailFactory.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,125 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.naming.factory;
+
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.Hashtable;
+import java.util.Properties;
+import java.util.Enumeration;
+import javax.mail.Session;
+import javax.mail.internet.InternetAddress;
+import javax.mail.internet.MimeMessage;
+import javax.mail.internet.MimePart;
+import javax.mail.internet.MimePartDataSource;
+import javax.naming.Name;
+import javax.naming.Context;
+import javax.naming.Reference;
+import javax.naming.RefAddr;
+import javax.naming.spi.ObjectFactory;
+
+/**
+ * Factory class that creates a JNDI named javamail MimePartDataSource
+ * object which can be used for sending email using SMTP.
+ * <p>
+ * Can be configured in the DefaultContext or Context scope
+ * of your server.xml configuration file.
+ * <p>
+ * Example:
+ * <p>
+ * <pre>
+ * &lt;Resource name="mail/send" auth="CONTAINER"
+ *           type="javax.mail.internet.MimePartDataSource"/>
+ * &lt;ResourceParams name="mail/send">
+ *   &lt;parameter>&lt;name>factory&lt;/name>
+ *     &lt;value>org.apache.naming.factory.SendMailFactory&lt;/value>
+ *   &lt;/parameter>
+ *   &lt;parameter>&lt;name>mail.smtp.host&lt;/name>
+ *     &lt;value>your.smtp.host&lt;/value>
+ *   &lt;/parameter>
+ *   &lt;parameter>&lt;name>mail.smtp.user&lt;/name>
+ *     &lt;value>someuser&lt;/value>
+ *   &lt;/parameter>
+ *   &lt;parameter>&lt;name>mail.from&lt;/name>
+ *     &lt;value>someuser at some.host&lt;/value>
+ *   &lt;/parameter>
+ *   &lt;parameter>&lt;name>mail.smtp.sendpartial&lt;/name>
+ *     &lt;value>true&lt;/value>
+ *   &lt;/parameter>
+ *  &lt;parameter>&lt;name>mail.smtp.dsn.notify&lt;/name>
+ *     &lt;value>FAILURE&lt;/value>
+ *   &lt;/parameter>
+ *   &lt;parameter>&lt;name>mail.smtp.dsn.ret&lt;/name>
+ *     &lt;value>FULL&lt;/value>
+ *   &lt;/parameter>
+ * &lt;/ResourceParams>
+ * </pre>
+ *
+ * @author Glenn Nielsen Rich Catlett
+ */
+
+public class SendMailFactory implements ObjectFactory 
+{
+    // The class name for the javamail MimeMessageDataSource
+    protected final String DataSourceClassName = 
+	"javax.mail.internet.MimePartDataSource";
+
+    public Object getObjectInstance(Object RefObj, Name Nm, Context Ctx,
+				    Hashtable Env) throws Exception 
+    {
+	final Reference Ref = (Reference)RefObj;
+
+	// Creation of the DataSource is wrapped inside a doPrivileged
+	// so that javamail can read its default properties without
+	// throwing Security Exceptions
+	if (Ref.getClassName().equals(DataSourceClassName)) {
+	    return AccessController.doPrivileged( new PrivilegedAction()
+	    {
+		public Object run() {
+        	    // set up the smtp session that will send the message
+	            Properties props = new Properties();
+		    // enumeration of all refaddr
+		    Enumeration list = Ref.getAll();
+		    // current refaddr to be set
+		    RefAddr refaddr;
+	            // set transport to smtp
+	            props.put("mail.transport.protocol", "smtp");
+
+		    while (list.hasMoreElements()) {
+			refaddr = (RefAddr)list.nextElement();
+
+			// set property
+			props.put(refaddr.getType(), (String)refaddr.getContent());
+		    }
+		    MimeMessage message = new MimeMessage(
+			Session.getInstance(props));
+		    try {
+			String from = (String)Ref.get("mail.from").getContent();
+		        message.setFrom(new InternetAddress(from));
+		        message.setSubject("");
+		    } catch (Exception e) {}
+		    MimePartDataSource mds = new MimePartDataSource(
+			(MimePart)message);
+		    return mds;
+		}
+	    } );
+	}
+	else { // We can't create an instance of the DataSource
+	    return null;
+	}
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/factory/TransactionFactory.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/factory/TransactionFactory.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/factory/TransactionFactory.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,124 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.naming.factory;
+
+import java.util.Hashtable;
+import javax.naming.Name;
+import javax.naming.Context;
+import javax.naming.NamingException;
+import javax.naming.Reference;
+import javax.naming.RefAddr;
+import javax.naming.spi.ObjectFactory;
+import org.apache.naming.TransactionRef;
+
+/**
+ * Object factory for User trasactions.
+ * 
+ * @author Remy Maucherat
+ * @version $Revision: 375650 $ $Date: 2006-02-07 11:55:11 -0600 (Tue, 07 Feb 2006) $
+ */
+
+public class TransactionFactory
+    implements ObjectFactory {
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    // -------------------------------------------------------------- Constants
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    // -------------------------------------------------- ObjectFactory Methods
+
+
+    /**
+     * Crete a new User transaction instance.
+     * 
+     * @param obj The reference object describing the DataSource
+     */
+    public Object getObjectInstance(Object obj, Name name, Context nameCtx,
+                                    Hashtable environment)
+        throws Exception {
+        
+        if (obj instanceof TransactionRef) {
+            Reference ref = (Reference) obj;
+            ObjectFactory factory = null;
+            RefAddr factoryRefAddr = ref.get(Constants.FACTORY);
+            if (factoryRefAddr != null) {
+                // Using the specified factory
+                String factoryClassName = 
+                    factoryRefAddr.getContent().toString();
+                // Loading factory
+                ClassLoader tcl = 
+                    Thread.currentThread().getContextClassLoader();
+                Class factoryClass = null;
+                if (tcl != null) {
+                    try {
+                        factoryClass = tcl.loadClass(factoryClassName);
+                    } catch(ClassNotFoundException e) {
+                        NamingException ex = new NamingException
+                            ("Could not load resource factory class");
+                        ex.initCause(e);
+                        throw ex;
+                    }
+                } else {
+                    try {
+                        factoryClass = Class.forName(factoryClassName);
+                    } catch(ClassNotFoundException e) {
+                        NamingException ex = new NamingException
+                            ("Could not load resource factory class");
+                        ex.initCause(e);
+                        throw ex;
+                    }
+                }
+                if (factoryClass != null) {
+                    try {
+                        factory = (ObjectFactory) factoryClass.newInstance();
+                    } catch(Throwable t) {
+                        if (t instanceof NamingException)
+                            throw (NamingException) t;
+                        NamingException ex = new NamingException
+                            ("Could not create resource factory instance");
+                        ex.initCause(t);
+                        throw ex;
+                    }
+                }
+            }
+            if (factory != null) {
+                return factory.getObjectInstance
+                    (obj, name, nameCtx, environment);
+            } else {
+                throw new NamingException
+                    ("Cannot create resource instance");
+            }
+            
+        }
+        
+        return null;
+        
+    }
+
+
+}
+

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/factory/package.html
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/factory/package.html	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/factory/package.html	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,7 @@
+<body>
+
+<p>This package contains object factories used by the naming service.</p>
+
+<p></p>
+
+</body>

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/java/javaURLContextFactory.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/java/javaURLContextFactory.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/java/javaURLContextFactory.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,111 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.naming.java;
+
+import java.util.Hashtable;
+import javax.naming.Name;
+import javax.naming.Context;
+import javax.naming.NamingException;
+import javax.naming.spi.ObjectFactory;
+import javax.naming.spi.InitialContextFactory;
+import org.apache.naming.SelectorContext;
+import org.apache.naming.NamingContext;
+import org.apache.naming.ContextBindings;
+
+/**
+ * Context factory for the "java:" namespace.
+ * <p>
+ * <b>Important note</b> : This factory MUST be associated with the "java" URL
+ * prefix, which can be done by either :
+ * <ul>
+ * <li>Adding a 
+ * java.naming.factory.url.pkgs=org.apache.catalina.util.naming property
+ * to the JNDI properties file</li>
+ * <li>Setting an environment variable named Context.URL_PKG_PREFIXES with 
+ * its value including the org.apache.catalina.util.naming package name. 
+ * More detail about this can be found in the JNDI documentation : 
+ * {@link javax.naming.spi.NamingManager#getURLContext(java.lang.String, java.util.Hashtable)}.</li>
+ * </ul>
+ * 
+ * @author Remy Maucherat
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class javaURLContextFactory
+    implements ObjectFactory, InitialContextFactory {
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    // -------------------------------------------------------------- Constants
+
+
+    public static final String MAIN = "initialContext";
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * Initial context.
+     */
+    protected static Context initialContext = null;
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    // -------------------------------------------------- ObjectFactory Methods
+
+
+    /**
+     * Crete a new Context's instance.
+     */
+    public Object getObjectInstance(Object obj, Name name, Context nameCtx,
+                                    Hashtable environment)
+        throws NamingException {
+        if ((ContextBindings.isThreadBound()) || 
+            (ContextBindings.isClassLoaderBound())) {
+            return new SelectorContext(environment);
+        } else {
+            return null;
+        }
+    }
+
+
+    /**
+     * Get a new (writable) initial context.
+     */
+    public Context getInitialContext(Hashtable environment)
+        throws NamingException {
+        if (ContextBindings.isThreadBound() || 
+            (ContextBindings.isClassLoaderBound())) {
+            // Redirect the request to the bound initial context
+            return new SelectorContext(environment, true);
+        } else {
+            // If the thread is not bound, return a shared writable context
+            if (initialContext == null)
+                initialContext = new NamingContext(environment, MAIN);
+            return initialContext;
+        }
+    }
+
+
+}
+

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/java/package.html
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/java/package.html	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/java/package.html	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,7 @@
+<body>
+
+<p>This package contains the URL context factory for the "java" namespace.</p>
+
+<p></p>
+
+</body>

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/package.html
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/package.html	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/package.html	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,7 @@
+<body>
+
+<p>This package contains a memory based naming service provider.</p>
+
+<p></p>
+
+</body>

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/resources/BaseDirContext.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/resources/BaseDirContext.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/resources/BaseDirContext.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,1208 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.naming.resources;
+
+import java.util.Hashtable;
+
+import javax.naming.Context;
+import javax.naming.Name;
+import javax.naming.NameParser;
+import javax.naming.NamingEnumeration;
+import javax.naming.NamingException;
+import javax.naming.directory.Attributes;
+import javax.naming.directory.DirContext;
+import javax.naming.directory.ModificationItem;
+import javax.naming.directory.SearchControls;
+
+import org.apache.naming.NameParserImpl;
+import org.apache.naming.StringManager;
+
+/**
+ * Directory Context implementation helper class.
+ *
+ * @author Remy Maucherat
+ * @version $Revision: 303999 $ $Date: 2005-07-20 16:25:18 -0500 (Wed, 20 Jul 2005) $
+ */
+
+public abstract class BaseDirContext implements DirContext {
+
+
+    // -------------------------------------------------------------- Constants
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Builds a base directory context.
+     */
+    public BaseDirContext() {
+        this.env = new Hashtable();
+    }
+
+
+    /**
+     * Builds a base directory context using the given environment.
+     */
+    public BaseDirContext(Hashtable env) {
+        this.env = env;
+    }
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The document base path.
+     */
+    protected String docBase = null;
+
+
+    /**
+     * Environment.
+     */
+    protected Hashtable env;
+
+
+    /**
+     * The string manager for this package.
+     */
+    protected StringManager sm = StringManager.getManager(Constants.Package);
+
+
+    /**
+     * Name parser for this context.
+     */
+    protected final NameParser nameParser = new NameParserImpl();
+
+
+    /**
+     * Cached.
+     */
+    protected boolean cached = true;
+
+
+    /**
+     * Cache TTL.
+     */
+    protected int cacheTTL = 5000; // 5s
+
+
+    /**
+     * Max size of resources which will have their content cached.
+     */
+    protected int cacheMaxSize = 10240; // 10 MB
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * Return the document root for this component.
+     */
+    public String getDocBase() {
+        return (this.docBase);
+    }
+
+
+    /**
+     * Set the document root for this component.
+     *
+     * @param docBase The new document root
+     *
+     * @exception IllegalArgumentException if the specified value is not
+     *  supported by this implementation
+     * @exception IllegalArgumentException if this would create a
+     *  malformed URL
+     */
+    public void setDocBase(String docBase) {
+
+        // Validate the format of the proposed document root
+        if (docBase == null)
+            throw new IllegalArgumentException
+                (sm.getString("resources.null"));
+
+        // Change the document root property
+        this.docBase = docBase;
+
+    }
+
+
+    /**
+     * Set cached.
+     */
+    public void setCached(boolean cached) {
+        this.cached = cached;
+    }
+
+
+    /**
+     * Is cached ?
+     */
+    public boolean isCached() {
+        return cached;
+    }
+
+
+    /**
+     * Set cache TTL.
+     */
+    public void setCacheTTL(int cacheTTL) {
+        this.cacheTTL = cacheTTL;
+    }
+
+
+    /**
+     * Get cache TTL.
+     */
+    public int getCacheTTL() {
+        return cacheTTL;
+    }
+
+
+    /**
+     * Return the maximum size of the cache in KB.
+     */
+    public int getCacheMaxSize() {
+        return cacheMaxSize;
+    }
+
+
+    /**
+     * Set the maximum size of the cache in KB.
+     */
+    public void setCacheMaxSize(int cacheMaxSize) {
+        this.cacheMaxSize = cacheMaxSize;
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Allocate resources for this directory context.
+     */
+    public void allocate() {
+        ; // No action taken by the default implementation
+    }
+
+
+    /**
+     * Release any resources allocated for this directory context.
+     */
+    public void release() {
+        ; // No action taken by the default implementation
+    }
+
+
+    // -------------------------------------------------------- Context Methods
+
+
+    /**
+     * Retrieves the named object. If name is empty, returns a new instance 
+     * of this context (which represents the same naming context as this 
+     * context, but its environment may be modified independently and it may 
+     * be accessed concurrently).
+     * 
+     * @param name the name of the object to look up
+     * @return the object bound to name
+     * @exception NamingException if a naming exception is encountered
+     */
+    public Object lookup(Name name)
+        throws NamingException {
+        return lookup(name.toString());
+    }
+
+
+    /**
+     * Retrieves the named object.
+     * 
+     * @param name the name of the object to look up
+     * @return the object bound to name
+     * @exception NamingException if a naming exception is encountered
+     */
+    public abstract Object lookup(String name)
+        throws NamingException;
+
+
+    /**
+     * Binds a name to an object. All intermediate contexts and the target 
+     * context (that named by all but terminal atomic component of the name) 
+     * must already exist.
+     * 
+     * @param name the name to bind; may not be empty
+     * @param obj the object to bind; possibly null
+     * @exception NameAlreadyBoundException if name is already bound
+     * @exception InvalidAttributesException if object did not supply all 
+     * mandatory attributes
+     * @exception NamingException if a naming exception is encountered
+     */
+    public void bind(Name name, Object obj)
+        throws NamingException {
+        bind(name.toString(), obj);
+    }
+
+
+    /**
+     * Binds a name to an object.
+     * 
+     * @param name the name to bind; may not be empty
+     * @param obj the object to bind; possibly null
+     * @exception NameAlreadyBoundException if name is already bound
+     * @exception InvalidAttributesException if object did not supply all 
+     * mandatory attributes
+     * @exception NamingException if a naming exception is encountered
+     */
+    public void bind(String name, Object obj)
+        throws NamingException {
+        bind(name, obj, null);
+    }
+
+
+    /**
+     * Binds a name to an object, overwriting any existing binding. All 
+     * intermediate contexts and the target context (that named by all but 
+     * terminal atomic component of the name) must already exist.
+     * <p>
+     * If the object is a DirContext, any existing attributes associated with 
+     * the name are replaced with those of the object. Otherwise, any 
+     * existing attributes associated with the name remain unchanged.
+     * 
+     * @param name the name to bind; may not be empty
+     * @param obj the object to bind; possibly null
+     * @exception InvalidAttributesException if object did not supply all 
+     * mandatory attributes
+     * @exception NamingException if a naming exception is encountered
+     */
+    public void rebind(Name name, Object obj)
+        throws NamingException {
+        rebind(name.toString(), obj);
+    }
+
+
+    /**
+     * Binds a name to an object, overwriting any existing binding.
+     * 
+     * @param name the name to bind; may not be empty
+     * @param obj the object to bind; possibly null
+     * @exception InvalidAttributesException if object did not supply all 
+     * mandatory attributes
+     * @exception NamingException if a naming exception is encountered
+     */
+    public void rebind(String name, Object obj)
+        throws NamingException {
+        rebind(name, obj, null);
+    }
+
+
+    /**
+     * Unbinds the named object. Removes the terminal atomic name in name 
+     * from the target context--that named by all but the terminal atomic 
+     * part of name.
+     * <p>
+     * This method is idempotent. It succeeds even if the terminal atomic 
+     * name is not bound in the target context, but throws 
+     * NameNotFoundException if any of the intermediate contexts do not exist. 
+     * 
+     * @param name the name to bind; may not be empty
+     * @exception NameNotFoundException if an intermediate context does not 
+     * exist
+     * @exception NamingException if a naming exception is encountered
+     */
+    public void unbind(Name name)
+        throws NamingException {
+        unbind(name.toString());
+    }
+
+
+    /**
+     * Unbinds the named object.
+     * 
+     * @param name the name to bind; may not be empty
+     * @exception NameNotFoundException if an intermediate context does not 
+     * exist
+     * @exception NamingException if a naming exception is encountered
+     */
+    public abstract void unbind(String name)
+        throws NamingException;
+
+
+    /**
+     * Binds a new name to the object bound to an old name, and unbinds the 
+     * old name. Both names are relative to this context. Any attributes 
+     * associated with the old name become associated with the new name. 
+     * Intermediate contexts of the old name are not changed.
+     * 
+     * @param oldName the name of the existing binding; may not be empty
+     * @param newName the name of the new binding; may not be empty
+     * @exception NameAlreadyBoundException if newName is already bound
+     * @exception NamingException if a naming exception is encountered
+     */
+    public void rename(Name oldName, Name newName)
+        throws NamingException {
+        rename(oldName.toString(), newName.toString());
+    }
+
+
+    /**
+     * Binds a new name to the object bound to an old name, and unbinds the 
+     * old name.
+     * 
+     * @param oldName the name of the existing binding; may not be empty
+     * @param newName the name of the new binding; may not be empty
+     * @exception NameAlreadyBoundException if newName is already bound
+     * @exception NamingException if a naming exception is encountered
+     */
+    public abstract void rename(String oldName, String newName)
+        throws NamingException;
+
+
+    /**
+     * 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
+     */
+    public NamingEnumeration list(Name name)
+        throws NamingException {
+        return list(name.toString());
+    }
+
+
+    /**
+     * Enumerates the names bound in the named context, along with the class 
+     * names of objects bound to them.
+     * 
+     * @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
+     */
+    public abstract NamingEnumeration list(String name)
+        throws NamingException;
+
+
+    /**
+     * Enumerates the names bound in the named context, along with the 
+     * 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 bindings in this context. 
+     * Each element of the enumeration is of type Binding.
+     * @exception NamingException if a naming exception is encountered
+     */
+    public NamingEnumeration listBindings(Name name)
+        throws NamingException {
+        return listBindings(name.toString());
+    }
+
+
+    /**
+     * Enumerates the names bound in the named context, along with the 
+     * objects bound to them.
+     * 
+     * @param name the name of the context to list
+     * @return an enumeration of the bindings in this context. 
+     * Each element of the enumeration is of type Binding.
+     * @exception NamingException if a naming exception is encountered
+     */
+    public abstract NamingEnumeration listBindings(String name)
+        throws NamingException;
+
+
+    /**
+     * Destroys the named context and removes it from the namespace. Any 
+     * attributes associated with the name are also removed. Intermediate 
+     * contexts are not destroyed.
+     * <p>
+     * This method is idempotent. It succeeds even if the terminal atomic 
+     * name is not bound in the target context, but throws 
+     * NameNotFoundException if any of the intermediate contexts do not exist. 
+     * 
+     * In a federated naming system, a context from one naming system may be 
+     * bound to a name in another. One can subsequently look up and perform 
+     * operations on the foreign context using a composite name. However, an 
+     * attempt destroy the context using this composite name will fail with 
+     * NotContextException, because the foreign context is not a "subcontext" 
+     * of the context in which it is bound. Instead, use unbind() to remove 
+     * the binding of the foreign context. Destroying the foreign context 
+     * requires that the destroySubcontext() be performed on a context from 
+     * the foreign context's "native" naming system.
+     * 
+     * @param name the name of the context to be destroyed; may not be empty
+     * @exception NameNotFoundException if an intermediate context does not 
+     * exist
+     * @exception NotContextException if the name is bound but does not name 
+     * a context, or does not name a context of the appropriate type
+     */
+    public void destroySubcontext(Name name)
+        throws NamingException {
+        destroySubcontext(name.toString());
+    }
+
+
+    /**
+     * Destroys the named context and removes it from the namespace.
+     * 
+     * @param name the name of the context to be destroyed; may not be empty
+     * @exception NameNotFoundException if an intermediate context does not 
+     * exist
+     * @exception NotContextException if the name is bound but does not name 
+     * a context, or does not name a context of the appropriate type
+     */
+    public abstract void destroySubcontext(String name)
+        throws NamingException;
+
+
+    /**
+     * Creates and binds a new context. Creates a new context with the given 
+     * name and binds it in the target context (that named by all but 
+     * terminal atomic component of the name). All intermediate contexts and 
+     * the target context must already exist.
+     * 
+     * @param name the name of the context to create; may not be empty
+     * @return the newly created context
+     * @exception NameAlreadyBoundException if name is already bound
+     * @exception InvalidAttributesException if creation of the subcontext 
+     * requires specification of mandatory attributes
+     * @exception NamingException if a naming exception is encountered
+     */
+    public Context createSubcontext(Name name)
+        throws NamingException {
+        return createSubcontext(name.toString());
+    }
+
+
+    /**
+     * Creates and binds a new context.
+     * 
+     * @param name the name of the context to create; may not be empty
+     * @return the newly created context
+     * @exception NameAlreadyBoundException if name is already bound
+     * @exception InvalidAttributesException if creation of the subcontext 
+     * requires specification of mandatory attributes
+     * @exception NamingException if a naming exception is encountered
+     */
+    public Context createSubcontext(String name)
+        throws NamingException {
+        return createSubcontext(name, null);
+    }
+
+
+    /**
+     * Retrieves the named object, following links except for the terminal 
+     * atomic component of the name. If the object bound to name is not a 
+     * link, returns the object itself.
+     * 
+     * @param name the name of the object to look up
+     * @return the object bound to name, not following the terminal link 
+     * (if any).
+     * @exception NamingException if a naming exception is encountered
+     */
+    public Object lookupLink(Name name)
+        throws NamingException {
+        return lookupLink(name.toString());
+    }
+
+
+    /**
+     * Retrieves the named object, following links except for the terminal 
+     * atomic component of the name.
+     * 
+     * @param name the name of the object to look up
+     * @return the object bound to name, not following the terminal link 
+     * (if any).
+     * @exception NamingException if a naming exception is encountered
+     */
+    public abstract Object lookupLink(String name)
+        throws NamingException;
+
+
+    /**
+     * Retrieves the parser associated with the named context. In a 
+     * federation of namespaces, different naming systems will parse names 
+     * differently. This method allows an application to get a parser for 
+     * parsing names into their atomic components using the naming convention 
+     * of a particular naming system. Within any single naming system, 
+     * NameParser objects returned by this method must be equal (using the 
+     * equals() test).
+     * 
+     * @param name the name of the context from which to get the parser
+     * @return a name parser that can parse compound names into their atomic 
+     * components
+     * @exception NamingException if a naming exception is encountered
+     */
+    public NameParser getNameParser(Name name)
+        throws NamingException {
+        return new NameParserImpl();
+    }
+
+
+    /**
+     * Retrieves the parser associated with the named context.
+     * 
+     * @param name the name of the context from which to get the parser
+     * @return a name parser that can parse compound names into their atomic 
+     * components
+     * @exception NamingException if a naming exception is encountered
+     */
+    public NameParser getNameParser(String name)
+        throws NamingException {
+        return new NameParserImpl();
+    }
+
+
+    /**
+     * Composes the name of this context with a name relative to this context.
+     * <p>
+     * Given a name (name) relative to this context, and the name (prefix) 
+     * of this context relative to one of its ancestors, this method returns 
+     * the composition of the two names using the syntax appropriate for the 
+     * naming system(s) involved. That is, if name names an object relative 
+     * to this context, the result is the name of the same object, but 
+     * relative to the ancestor context. None of the names may be null.
+     * 
+     * @param name a name relative to this context
+     * @param prefix the name of this context relative to one of its ancestors
+     * @return the composition of prefix and name
+     * @exception NamingException if a naming exception is encountered
+     */
+    public Name composeName(Name name, Name prefix)
+        throws NamingException {
+        prefix = (Name) prefix.clone();
+        return prefix.addAll(name);
+    }
+
+
+    /**
+     * Composes the name of this context with a name relative to this context.
+     * 
+     * @param name a name relative to this context
+     * @param prefix the name of this context relative to one of its ancestors
+     * @return the composition of prefix and name
+     * @exception NamingException if a naming exception is encountered
+     */
+    public String composeName(String name, String prefix)
+        throws NamingException {
+        return prefix + "/" + name;
+    }
+
+
+    /**
+     * Adds a new environment property to the environment of this context. If 
+     * the property already exists, its value is overwritten.
+     * 
+     * @param propName the name of the environment property to add; may not 
+     * be null
+     * @param propVal the value of the property to add; may not be null
+     * @exception NamingException if a naming exception is encountered
+     */
+    public Object addToEnvironment(String propName, Object propVal)
+        throws NamingException {
+        return env.put(propName, propVal);
+    }
+
+
+    /**
+     * Removes an environment property from the environment of this context. 
+     * 
+     * @param propName the name of the environment property to remove; 
+     * may not be null
+     * @exception NamingException if a naming exception is encountered
+     */
+    public Object removeFromEnvironment(String propName)
+        throws NamingException {
+        return env.remove(propName);
+    }
+
+
+    /**
+     * Retrieves the environment in effect for this context. See class 
+     * description for more details on environment properties. 
+     * The caller should not make any changes to the object returned: their 
+     * effect on the context is undefined. The environment of this context 
+     * may be changed using addToEnvironment() and removeFromEnvironment().
+     * 
+     * @return the environment of this context; never null
+     * @exception NamingException if a naming exception is encountered
+     */
+    public Hashtable getEnvironment()
+        throws NamingException {
+        return env;
+    }
+
+
+    /**
+     * Closes this context. This method releases this context's resources 
+     * immediately, instead of waiting for them to be released automatically 
+     * by the garbage collector.
+     * This method is idempotent: invoking it on a context that has already 
+     * been closed has no effect. Invoking any other method on a closed 
+     * context is not allowed, and results in undefined behaviour.
+     * 
+     * @exception NamingException if a naming exception is encountered
+     */
+    public void close()
+        throws NamingException {
+        env.clear();
+    }
+
+
+    /**
+     * Retrieves the full name of this context within its own namespace.
+     * <p>
+     * Many naming services have a notion of a "full name" for objects in 
+     * their respective namespaces. For example, an LDAP entry has a 
+     * distinguished name, and a DNS record has a fully qualified name. This 
+     * method allows the client application to retrieve this name. The string 
+     * returned by this method is not a JNDI composite name and should not be 
+     * passed directly to context methods. In naming systems for which the 
+     * notion of full name does not make sense, 
+     * OperationNotSupportedException is thrown.
+     * 
+     * @return this context's name in its own namespace; never null
+     * @exception OperationNotSupportedException if the naming system does 
+     * not have the notion of a full name
+     * @exception NamingException if a naming exception is encountered
+     */
+    public abstract String getNameInNamespace()
+        throws NamingException;
+
+
+    // ----------------------------------------------------- DirContext Methods
+
+
+    /**
+     * Retrieves all of the attributes associated with a named object. 
+     * 
+     * @return the set of attributes associated with name. 
+     * Returns an empty attribute set if name has no attributes; never null.
+     * @param name the name of the object from which to retrieve attributes
+     * @exception NamingException if a naming exception is encountered
+     */
+    public Attributes getAttributes(Name name)
+        throws NamingException {
+        return getAttributes(name.toString());
+    }
+
+
+    /**
+     * Retrieves all of the attributes associated with a named object.
+     * 
+     * @return the set of attributes associated with name
+     * @param name the name of the object from which to retrieve attributes
+     * @exception NamingException if a naming exception is encountered
+     */
+    public Attributes getAttributes(String name)
+        throws NamingException {
+        return getAttributes(name, null);
+    }
+
+
+    /**
+     * Retrieves selected attributes associated with a named object. 
+     * See the class description regarding attribute models, attribute type 
+     * names, and operational attributes.
+     * 
+     * @return the requested attributes; never null
+     * @param name the name of the object from which to retrieve attributes
+     * @param attrIds the identifiers of the attributes to retrieve. null 
+     * indicates that all attributes should be retrieved; an empty array 
+     * indicates that none should be retrieved
+     * @exception NamingException if a naming exception is encountered
+     */
+    public Attributes getAttributes(Name name, String[] attrIds)
+        throws NamingException {
+        return getAttributes(name.toString(), attrIds);
+    }
+    
+    
+    /**
+     * Retrieves selected attributes associated with a named object.
+     * 
+     * @return the requested attributes; never null
+     * @param name the name of the object from which to retrieve attributes
+     * @param attrIds the identifiers of the attributes to retrieve. null 
+     * indicates that all attributes should be retrieved; an empty array 
+     * indicates that none should be retrieved
+     * @exception NamingException if a naming exception is encountered
+     */
+    public abstract Attributes getAttributes(String name, String[] attrIds)
+        throws NamingException;
+
+
+    /**
+     * Modifies the attributes associated with a named object. The order of 
+     * the modifications is not specified. Where possible, the modifications 
+     * are performed atomically.
+     * 
+     * @param name the name of the object whose attributes will be updated
+     * @param mod_op the modification operation, one of: ADD_ATTRIBUTE, 
+     * REPLACE_ATTRIBUTE, REMOVE_ATTRIBUTE
+     * @param attrs the attributes to be used for the modification; may not 
+     * be null
+     * @exception AttributeModificationException if the modification cannot be
+     * completed successfully
+     * @exception NamingException if a naming exception is encountered
+     */
+    public void modifyAttributes(Name name, int mod_op, Attributes attrs)
+        throws NamingException {
+        modifyAttributes(name.toString(), mod_op, attrs);
+    }
+
+
+    /**
+     * Modifies the attributes associated with a named object.
+     * 
+     * @param name the name of the object whose attributes will be updated
+     * @param mod_op the modification operation, one of: ADD_ATTRIBUTE, 
+     * REPLACE_ATTRIBUTE, REMOVE_ATTRIBUTE
+     * @param attrs the attributes to be used for the modification; may not 
+     * be null
+     * @exception AttributeModificationException if the modification cannot be
+     * completed successfully
+     * @exception NamingException if a naming exception is encountered
+     */
+    public abstract void modifyAttributes
+        (String name, int mod_op, Attributes attrs)
+        throws NamingException;
+
+
+    /**
+     * Modifies the attributes associated with a named object using an an 
+     * ordered list of modifications. The modifications are performed in the 
+     * order specified. Each modification specifies a modification operation 
+     * code and an attribute on which to operate. Where possible, the 
+     * modifications are performed atomically.
+     * 
+     * @param name the name of the object whose attributes will be updated
+     * @param mods an ordered sequence of modifications to be performed; may 
+     * not be null
+     * @exception AttributeModificationException if the modification cannot be
+     * completed successfully
+     * @exception NamingException if a naming exception is encountered
+     */
+    public void modifyAttributes(Name name, ModificationItem[] mods)
+        throws NamingException {
+        modifyAttributes(name.toString(), mods);
+    }
+
+
+    /**
+     * Modifies the attributes associated with a named object using an an 
+     * ordered list of modifications.
+     * 
+     * @param name the name of the object whose attributes will be updated
+     * @param mods an ordered sequence of modifications to be performed; may 
+     * not be null
+     * @exception AttributeModificationException if the modification cannot be
+     * completed successfully
+     * @exception NamingException if a naming exception is encountered
+     */
+    public abstract void modifyAttributes(String name, ModificationItem[] mods)
+        throws NamingException;
+
+
+    /**
+     * Binds a name to an object, along with associated attributes. If attrs 
+     * is null, the resulting binding will have the attributes associated 
+     * with obj if obj is a DirContext, and no attributes otherwise. If attrs 
+     * is non-null, the resulting binding will have attrs as its attributes; 
+     * any attributes associated with obj are ignored.
+     * 
+     * @param name the name to bind; may not be empty
+     * @param obj the object to bind; possibly null
+     * @param attrs the attributes to associate with the binding
+     * @exception NameAlreadyBoundException if name is already bound
+     * @exception InvalidAttributesException if some "mandatory" attributes 
+     * of the binding are not supplied
+     * @exception NamingException if a naming exception is encountered
+     */
+    public void bind(Name name, Object obj, Attributes attrs)
+        throws NamingException {
+        bind(name.toString(), obj, attrs);
+    }
+
+
+    /**
+     * Binds a name to an object, along with associated attributes.
+     * 
+     * @param name the name to bind; may not be empty
+     * @param obj the object to bind; possibly null
+     * @param attrs the attributes to associate with the binding
+     * @exception NameAlreadyBoundException if name is already bound
+     * @exception InvalidAttributesException if some "mandatory" attributes 
+     * of the binding are not supplied
+     * @exception NamingException if a naming exception is encountered
+     */
+    public abstract void bind(String name, Object obj, Attributes attrs)
+        throws NamingException;
+
+
+    /**
+     * Binds a name to an object, along with associated attributes, 
+     * overwriting any existing binding. If attrs is null and obj is a 
+     * DirContext, the attributes from obj are used. If attrs is null and obj 
+     * is not a DirContext, any existing attributes associated with the object
+     * already bound in the directory remain unchanged. If attrs is non-null, 
+     * any existing attributes associated with the object already bound in 
+     * the directory are removed and attrs is associated with the named 
+     * object. If obj is a DirContext and attrs is non-null, the attributes 
+     * of obj are ignored.
+     * 
+     * @param name the name to bind; may not be empty
+     * @param obj the object to bind; possibly null
+     * @param attrs the attributes to associate with the binding
+     * @exception InvalidAttributesException if some "mandatory" attributes 
+     * of the binding are not supplied
+     * @exception NamingException if a naming exception is encountered
+     */
+    public void rebind(Name name, Object obj, Attributes attrs)
+        throws NamingException {
+        rebind(name.toString(), obj, attrs);
+    }
+
+
+    /**
+     * Binds a name to an object, along with associated attributes, 
+     * overwriting any existing binding.
+     * 
+     * @param name the name to bind; may not be empty
+     * @param obj the object to bind; possibly null
+     * @param attrs the attributes to associate with the binding
+     * @exception InvalidAttributesException if some "mandatory" attributes 
+     * of the binding are not supplied
+     * @exception NamingException if a naming exception is encountered
+     */
+    public abstract void rebind(String name, Object obj, Attributes attrs)
+        throws NamingException;
+
+
+    /**
+     * Creates and binds a new context, along with associated attributes. 
+     * This method creates a new subcontext with the given name, binds it in 
+     * the target context (that named by all but terminal atomic component of 
+     * the name), and associates the supplied attributes with the newly 
+     * created object. All intermediate and target contexts must already 
+     * exist. If attrs is null, this method is equivalent to 
+     * Context.createSubcontext().
+     * 
+     * @param name the name of the context to create; may not be empty
+     * @param attrs the attributes to associate with the newly created context
+     * @return the newly created context
+     * @exception NameAlreadyBoundException if the name is already bound
+     * @exception InvalidAttributesException if attrs does not contain all 
+     * the mandatory attributes required for creation
+     * @exception NamingException if a naming exception is encountered
+     */
+    public DirContext createSubcontext(Name name, Attributes attrs)
+        throws NamingException {
+        return createSubcontext(name.toString(), attrs);
+    }
+
+
+    /**
+     * Creates and binds a new context, along with associated attributes.
+     * 
+     * @param name the name of the context to create; may not be empty
+     * @param attrs the attributes to associate with the newly created context
+     * @return the newly created context
+     * @exception NameAlreadyBoundException if the name is already bound
+     * @exception InvalidAttributesException if attrs does not contain all 
+     * the mandatory attributes required for creation
+     * @exception NamingException if a naming exception is encountered
+     */
+    public abstract DirContext createSubcontext(String name, Attributes attrs)
+        throws NamingException;
+
+
+    /**
+     * Retrieves the schema associated with the named object. The schema 
+     * describes rules regarding the structure of the namespace and the 
+     * attributes stored within it. The schema specifies what types of 
+     * objects can be added to the directory and where they can be added; 
+     * what mandatory and optional attributes an object can have. The range 
+     * of support for schemas is directory-specific.
+     * 
+     * @param name the name of the object whose schema is to be retrieved
+     * @return the schema associated with the context; never null
+     * @exception OperationNotSupportedException if schema not supported
+     * @exception NamingException if a naming exception is encountered
+     */
+    public DirContext getSchema(Name name)
+        throws NamingException {
+        return getSchema(name.toString());
+    }
+
+
+    /**
+     * Retrieves the schema associated with the named object.
+     * 
+     * @param name the name of the object whose schema is to be retrieved
+     * @return the schema associated with the context; never null
+     * @exception OperationNotSupportedException if schema not supported
+     * @exception NamingException if a naming exception is encountered
+     */
+    public abstract DirContext getSchema(String name)
+        throws NamingException;
+
+
+    /**
+     * Retrieves a context containing the schema objects of the named 
+     * object's class definitions.
+     * 
+     * @param name the name of the object whose object class definition is to 
+     * be retrieved
+     * @return the DirContext containing the named object's class 
+     * definitions; never null
+     * @exception OperationNotSupportedException if schema not supported
+     * @exception NamingException if a naming exception is encountered
+     */
+    public DirContext getSchemaClassDefinition(Name name)
+        throws NamingException {
+        return getSchemaClassDefinition(name.toString());
+    }
+
+
+    /**
+     * Retrieves a context containing the schema objects of the named 
+     * object's class definitions.
+     * 
+     * @param name the name of the object whose object class definition is to 
+     * be retrieved
+     * @return the DirContext containing the named object's class 
+     * definitions; never null
+     * @exception OperationNotSupportedException if schema not supported
+     * @exception NamingException if a naming exception is encountered
+     */
+    public abstract DirContext getSchemaClassDefinition(String name)
+        throws NamingException;
+
+
+    /**
+     * Searches in a single context for objects that contain a specified set 
+     * of attributes, and retrieves selected attributes. The search is 
+     * performed using the default SearchControls settings.
+     * 
+     * @param name the name of the context to search
+     * @param matchingAttributes the attributes to search for. If empty or 
+     * null, all objects in the target context are returned.
+     * @param attributesToReturn the attributes to return. null indicates 
+     * that all attributes are to be returned; an empty array indicates that 
+     * none are to be returned.
+     * @return a non-null enumeration of SearchResult objects. Each 
+     * SearchResult contains the attributes identified by attributesToReturn 
+     * and the name of the corresponding object, named relative to the 
+     * context named by name.
+     * @exception NamingException if a naming exception is encountered
+     */
+    public NamingEnumeration search(Name name, Attributes matchingAttributes,
+                                    String[] attributesToReturn)
+        throws NamingException {
+        return search(name.toString(), matchingAttributes, attributesToReturn);
+    }
+
+
+    /**
+     * Searches in a single context for objects that contain a specified set 
+     * of attributes, and retrieves selected attributes.
+     * 
+     * @param name the name of the context to search
+     * @param matchingAttributes the attributes to search for. If empty or 
+     * null, all objects in the target context are returned.
+     * @param attributesToReturn the attributes to return. null indicates 
+     * that all attributes are to be returned; an empty array indicates that 
+     * none are to be returned.
+     * @return a non-null enumeration of SearchResult objects. Each 
+     * SearchResult contains the attributes identified by attributesToReturn 
+     * and the name of the corresponding object, named relative to the 
+     * context named by name.
+     * @exception NamingException if a naming exception is encountered
+     */
+    public abstract NamingEnumeration search
+        (String name, Attributes matchingAttributes,
+         String[] attributesToReturn)
+        throws NamingException;
+
+
+    /**
+     * Searches in a single context for objects that contain a specified set 
+     * of attributes. This method returns all the attributes of such objects. 
+     * It is equivalent to supplying null as the atributesToReturn parameter 
+     * to the method search(Name, Attributes, String[]).
+     * 
+     * @param name the name of the context to search
+     * @param matchingAttributes the attributes to search for. If empty or 
+     * null, all objects in the target context are returned.
+     * @return a non-null enumeration of SearchResult objects. Each 
+     * SearchResult contains the attributes identified by attributesToReturn 
+     * and the name of the corresponding object, named relative to the 
+     * context named by name.
+     * @exception NamingException if a naming exception is encountered
+     */
+    public NamingEnumeration search(Name name, Attributes matchingAttributes)
+        throws NamingException {
+        return search(name.toString(), matchingAttributes);
+    }
+
+
+    /**
+     * Searches in a single context for objects that contain a specified set 
+     * of attributes.
+     * 
+     * @param name the name of the context to search
+     * @param matchingAttributes the attributes to search for. If empty or 
+     * null, all objects in the target context are returned.
+     * @return a non-null enumeration of SearchResult objects. Each 
+     * SearchResult contains the attributes identified by attributesToReturn 
+     * and the name of the corresponding object, named relative to the 
+     * context named by name.
+     * @exception NamingException if a naming exception is encountered
+     */
+    public abstract NamingEnumeration search
+        (String name, Attributes matchingAttributes)
+        throws NamingException;
+
+
+    /**
+     * Searches in the named context or object for entries that satisfy the 
+     * given search filter. Performs the search as specified by the search 
+     * controls.
+     * 
+     * @param name the name of the context or object to search
+     * @param filter the filter expression to use for the search; may not be 
+     * null
+     * @param cons the search controls that control the search. If null, 
+     * the default search controls are used (equivalent to 
+     * (new SearchControls())).
+     * @return an enumeration of SearchResults of the objects that satisfy 
+     * the filter; never null
+     * @exception InvalidSearchFilterException if the search filter specified 
+     * is not supported or understood by the underlying directory
+     * @exception InvalidSearchControlsException if the search controls 
+     * contain invalid settings
+     * @exception NamingException if a naming exception is encountered
+     */
+    public NamingEnumeration search
+        (Name name, String filter, SearchControls cons)
+        throws NamingException {
+        return search(name.toString(), filter, cons);
+    }
+
+
+    /**
+     * Searches in the named context or object for entries that satisfy the 
+     * given search filter. Performs the search as specified by the search 
+     * controls.
+     * 
+     * @param name the name of the context or object to search
+     * @param filter the filter expression to use for the search; may not be 
+     * null
+     * @param cons the search controls that control the search. If null, 
+     * the default search controls are used (equivalent to 
+     * (new SearchControls())).
+     * @return an enumeration of SearchResults of the objects that satisfy 
+     * the filter; never null
+     * @exception InvalidSearchFilterException if the search filter 
+     * specified is not supported or understood by the underlying directory
+     * @exception InvalidSearchControlsException if the search controls 
+     * contain invalid settings
+     * @exception NamingException if a naming exception is encountered
+     */
+    public abstract NamingEnumeration search(String name, String filter, 
+                                             SearchControls cons)
+        throws NamingException;
+
+
+    /**
+     * Searches in the named context or object for entries that satisfy the 
+     * given search filter. Performs the search as specified by the search 
+     * controls.
+     * 
+     * @param name the name of the context or object to search
+     * @param filterExpr the filter expression to use for the search. 
+     * The expression may contain variables of the form "{i}" where i is a 
+     * nonnegative integer. May not be null.
+     * @param filterArgs the array of arguments to substitute for the 
+     * variables in filterExpr. The value of filterArgs[i] will replace each 
+     * occurrence of "{i}". If null, equivalent to an empty array.
+     * @param cons the search controls that control the search. If null, the 
+     * default search controls are used (equivalent to (new SearchControls())).
+     * @return an enumeration of SearchResults of the objects that satisy the 
+     * filter; never null
+     * @exception ArrayIndexOutOfBoundsException if filterExpr contains {i} 
+     * expressions where i is outside the bounds of the array filterArgs
+     * @exception InvalidSearchControlsException if cons contains invalid 
+     * settings
+     * @exception InvalidSearchFilterException if filterExpr with filterArgs 
+     * represents an invalid search filter
+     * @exception NamingException if a naming exception is encountered
+     */
+    public NamingEnumeration search(Name name, String filterExpr, 
+                                    Object[] filterArgs, SearchControls cons)
+        throws NamingException {
+        return search(name.toString(), filterExpr, filterArgs, cons);
+    }
+
+
+    /**
+     * Searches in the named context or object for entries that satisfy the 
+     * given search filter. Performs the search as specified by the search 
+     * controls.
+     * 
+     * @param name the name of the context or object to search
+     * @param filterExpr the filter expression to use for the search. 
+     * The expression may contain variables of the form "{i}" where i is a 
+     * nonnegative integer. May not be null.
+     * @param filterArgs the array of arguments to substitute for the 
+     * variables in filterExpr. The value of filterArgs[i] will replace each 
+     * occurrence of "{i}". If null, equivalent to an empty array.
+     * @param cons the search controls that control the search. If null, the 
+     * default search controls are used (equivalent to (new SearchControls())).
+     * @return an enumeration of SearchResults of the objects that satisy the 
+     * filter; never null
+     * @exception ArrayIndexOutOfBoundsException if filterExpr contains {i} 
+     * expressions where i is outside the bounds of the array filterArgs
+     * @exception InvalidSearchControlsException if cons contains invalid 
+     * settings
+     * @exception InvalidSearchFilterException if filterExpr with filterArgs 
+     * represents an invalid search filter
+     * @exception NamingException if a naming exception is encountered
+     */
+    public abstract NamingEnumeration search
+        (String name, String filterExpr, 
+         Object[] filterArgs, SearchControls cons)
+        throws NamingException;
+
+
+    // ------------------------------------------------------ Protected Methods
+
+
+}
+

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/resources/CacheEntry.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/resources/CacheEntry.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/resources/CacheEntry.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,67 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.naming.resources;
+
+import javax.naming.directory.DirContext;
+
+/**
+ * Implements a cache entry.
+ * 
+ * @author <a href="mailto:remm at apache.org">Remy Maucherat</a>
+ * @version $Revision: 302726 $
+ */
+public class CacheEntry {
+    
+    
+    // ------------------------------------------------- Instance Variables
+
+
+    public long timestamp = -1;
+    public String name = null;
+    public ResourceAttributes attributes = null;
+    public Resource resource = null;
+    public DirContext context = null;
+    public boolean exists = true;
+    public long accessCount = 0;
+    public int size = 1;
+
+
+    // ----------------------------------------------------- Public Methods
+
+
+    public void recycle() {
+        timestamp = -1;
+        name = null;
+        attributes = null;
+        resource = null;
+        context = null;
+        exists = true;
+        accessCount = 0;
+        size = 1;
+    }
+
+
+    public String toString() {
+        return ("Cache entry: " + name + "\n"
+                + "Exists: " + exists + "\n"
+                + "Attributes: " + attributes + "\n"
+                + "Resource: " + resource + "\n"
+                + "Context: " + context);
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/resources/Constants.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/resources/Constants.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/resources/Constants.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,35 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.naming.resources;
+
+
+/**
+ * Static constants for this package.
+ */
+
+public final class Constants {
+
+    public static final String PROTOCOL_HANDLER_VARIABLE = 
+        "java.protocol.handler.pkgs";
+
+    public static final String Package = "org.apache.naming.resources";
+
+    // Default namespace name
+    public static final String DEFAULT_NAMESPACE = "DAV:";
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/resources/DirContextURLConnection.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/resources/DirContextURLConnection.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/resources/DirContextURLConnection.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,358 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.naming.resources;
+
+import java.net.URL;
+import java.net.URLConnection;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.FileNotFoundException;
+import java.security.Permission;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.Vector;
+import javax.naming.NamingException;
+import javax.naming.NamingEnumeration;
+import javax.naming.NameClassPair;
+import javax.naming.directory.DirContext;
+import javax.naming.directory.Attribute;
+import javax.naming.directory.Attributes;
+import org.apache.naming.JndiPermission;
+import org.apache.naming.resources.Resource;
+import org.apache.naming.resources.ResourceAttributes;
+
+/**
+ * Connection to a JNDI directory context.
+ * <p/>
+ * Note: All the object attribute names are the WebDAV names, not the HTTP 
+ * names, so this class overrides some methods from URLConnection to do the
+ * queries using the right names. Content handler is also not used; the 
+ * content is directly returned.
+ * 
+ * @author <a href="mailto:remm at apache.org">Remy Maucherat</a>
+ * @version $Revision: 303022 $
+ */
+public class DirContextURLConnection 
+    extends URLConnection {
+    
+    
+    // ----------------------------------------------------------- Constructors
+    
+    
+    public DirContextURLConnection(DirContext context, URL url) {
+        super(url);
+        if (context == null)
+            throw new IllegalArgumentException
+                ("Directory context can't be null");
+        if (System.getSecurityManager() != null) {
+            this.permission = new JndiPermission(url.toString());
+	}
+        this.context = context;
+    }
+    
+    
+    // ----------------------------------------------------- Instance Variables
+    
+    
+    /**
+     * Directory context.
+     */
+    protected DirContext context;
+    
+    
+    /**
+     * Associated resource.
+     */
+    protected Resource resource;
+    
+    
+    /**
+     * Associated DirContext.
+     */
+    protected DirContext collection;
+    
+    
+    /**
+     * Other unknown object.
+     */
+    protected Object object;
+    
+    
+    /**
+     * Attributes.
+     */
+    protected Attributes attributes;
+    
+    
+    /**
+     * Date.
+     */
+    protected long date;
+    
+    
+    /**
+     * Permission
+     */
+    protected Permission permission;
+
+
+    // ------------------------------------------------------------- Properties
+    
+    
+    /**
+     * Connect to the DirContext, and retrive the bound object, as well as
+     * its attributes. If no object is bound with the name specified in the
+     * URL, then an IOException is thrown.
+     * 
+     * @throws IOException Object not found
+     */
+    public void connect()
+        throws IOException {
+        
+        if (!connected) {
+            
+            try {
+                date = System.currentTimeMillis();
+                String path = getURL().getFile();
+                if (context instanceof ProxyDirContext) {
+                    ProxyDirContext proxyDirContext = 
+                        (ProxyDirContext) context;
+                    String hostName = proxyDirContext.getHostName();
+                    String contextName = proxyDirContext.getContextName();
+                    if (hostName != null) {
+                        if (!path.startsWith("/" + hostName + "/"))
+                            return;
+                        path = path.substring(hostName.length()+ 1);
+                    }
+                    if (contextName != null) {
+                        if (!path.startsWith(contextName + "/")) {
+                            return;
+                        } else {
+                            path = path.substring(contextName.length());
+                        }
+                    }
+                }
+                object = context.lookup(path);
+                attributes = context.getAttributes(path);
+                if (object instanceof Resource)
+                    resource = (Resource) object;
+                if (object instanceof DirContext)
+                    collection = (DirContext) object;
+            } catch (NamingException e) {
+                // Object not found
+            }
+            
+            connected = true;
+            
+        }
+        
+    }
+    
+    
+    /**
+     * Return the content length value.
+     */
+    public int getContentLength() {
+        return getHeaderFieldInt(ResourceAttributes.CONTENT_LENGTH, -1);
+    }
+    
+    
+    /**
+     * Return the content type value.
+     */
+    public String getContentType() {
+        return getHeaderField(ResourceAttributes.CONTENT_TYPE);
+    }
+    
+    
+    /**
+     * Return the last modified date.
+     */
+    public long getDate() {
+        return date;
+    }
+    
+    
+    /**
+     * Return the last modified date.
+     */
+    public long getLastModified() {
+
+        if (!connected) {
+            // Try to connect (silently)
+            try {
+                connect();
+            } catch (IOException e) {
+            }
+        }
+
+        if (attributes == null)
+            return 0;
+
+        Attribute lastModified = 
+            attributes.get(ResourceAttributes.LAST_MODIFIED);
+        if (lastModified != null) {
+            try {
+                Date lmDate = (Date) lastModified.get();
+                return lmDate.getTime();
+            } catch (Exception e) {
+            }
+        }
+
+        return 0;
+    }
+    
+    
+    /**
+     * Returns the name of the specified header field.
+     */
+    public String getHeaderField(String name) {
+
+        if (!connected) {
+            // Try to connect (silently)
+            try {
+                connect();
+            } catch (IOException e) {
+            }
+        }
+        
+        if (attributes == null)
+            return (null);
+
+        Attribute attribute = attributes.get(name);
+        try {
+            return attribute.get().toString();
+        } catch (Exception e) {
+            // Shouldn't happen, unless the attribute has no value
+        }
+
+        return (null);
+        
+    }
+    
+    
+    /**
+     * Get object content.
+     */
+    public Object getContent()
+        throws IOException {
+        
+        if (!connected)
+            connect();
+        
+        if (resource != null)
+            return getInputStream();
+        if (collection != null)
+            return collection;
+        if (object != null)
+            return object;
+        
+        throw new FileNotFoundException();
+        
+    }
+    
+    
+    /**
+     * Get object content.
+     */
+    public Object getContent(Class[] classes)
+        throws IOException {
+        
+        Object object = getContent();
+        
+        for (int i = 0; i < classes.length; i++) {
+            if (classes[i].isInstance(object))
+                return object;
+        }
+        
+        return null;
+        
+    }
+    
+    
+    /**
+     * Get input stream.
+     */
+    public InputStream getInputStream() 
+        throws IOException {
+        
+        if (!connected)
+            connect();
+        
+        if (resource == null) {
+            throw new FileNotFoundException();
+        } else {
+            // Reopen resource
+            try {
+                resource = (Resource) context.lookup(getURL().getFile());
+            } catch (NamingException e) {
+            }
+        }
+        
+        return (resource.streamContent());
+        
+    }
+    
+    
+    /**
+     * Get the Permission for this URL
+     */
+    public Permission getPermission() {
+
+        return permission;
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+    
+    
+    /**
+     * List children of this collection. The names given are relative to this
+     * URI's path. The full uri of the children is then : path + "/" + name.
+     */
+    public Enumeration list()
+        throws IOException {
+        
+        if (!connected) {
+            connect();
+        }
+        
+        if ((resource == null) && (collection == null)) {
+            throw new FileNotFoundException();
+        }
+        
+        Vector result = new Vector();
+        
+        if (collection != null) {
+            try {
+                NamingEnumeration enumeration = context.list(getURL().getFile());
+                while (enumeration.hasMoreElements()) {
+                    NameClassPair ncp = (NameClassPair) enumeration.nextElement();
+                    result.addElement(ncp.getName());
+                }
+            } catch (NamingException e) {
+                // Unexpected exception
+                throw new FileNotFoundException();
+            }
+        }
+        
+        return result.elements();
+        
+    }
+    
+    
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/resources/DirContextURLStreamHandler.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/resources/DirContextURLStreamHandler.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/resources/DirContextURLStreamHandler.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,261 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.naming.resources;
+
+import java.io.IOException;
+import java.net.URL;
+import java.net.URLConnection;
+import java.net.URLStreamHandler;
+import java.util.Hashtable;
+
+import javax.naming.directory.DirContext;
+
+/**
+ * Stream handler to a JNDI directory context.
+ * 
+ * @author <a href="mailto:remm at apache.org">Remy Maucherat</a>
+ * @version $Revision: 304080 $
+ */
+public class DirContextURLStreamHandler 
+    extends URLStreamHandler {
+    
+    
+    // ----------------------------------------------------------- Constructors
+    
+    
+    public DirContextURLStreamHandler() {
+    }
+    
+    
+    public DirContextURLStreamHandler(DirContext context) {
+        this.context = context;
+    }
+    
+    
+    // -------------------------------------------------------------- Variables
+    
+    
+    /**
+     * Bindings class loader - directory context. Keyed by CL id.
+     */
+    private static Hashtable clBindings = new Hashtable();
+    
+    
+    /**
+     * Bindings thread - directory context. Keyed by thread id.
+     */
+    private static Hashtable threadBindings = new Hashtable();
+    
+    
+    // ----------------------------------------------------- Instance Variables
+    
+    
+    /**
+     * Directory context.
+     */
+    protected DirContext context = null;
+    
+    
+    // ------------------------------------------------------------- Properties
+    
+    
+    // ----------------------------------------------- URLStreamHandler Methods
+    
+    
+    /**
+     * Opens a connection to the object referenced by the <code>URL</code> 
+     * argument.
+     */
+    protected URLConnection openConnection(URL u) 
+        throws IOException {
+        DirContext currentContext = this.context;
+        if (currentContext == null)
+            currentContext = get();
+        return new DirContextURLConnection(currentContext, u);
+    }
+    
+    
+    // ------------------------------------------------------------ URL Methods
+    
+    
+    /**
+     * Override as part of the fix for 36534, to ensure toString is correct.
+     */
+    protected String toExternalForm(URL u) {
+        // pre-compute length of StringBuffer
+        int len = u.getProtocol().length() + 1;
+        if (u.getPath() != null) {
+            len += u.getPath().length();
+        }
+        if (u.getQuery() != null) {
+            len += 1 + u.getQuery().length();
+        }
+        if (u.getRef() != null) 
+            len += 1 + u.getRef().length();
+        StringBuffer result = new StringBuffer(len);
+        result.append(u.getProtocol());
+        result.append(":");
+        if (u.getPath() != null) {
+            result.append(u.getPath());
+        }
+        if (u.getQuery() != null) {
+            result.append('?');
+            result.append(u.getQuery());
+        }
+        if (u.getRef() != null) {
+            result.append("#");
+            result.append(u.getRef());
+        }
+        return result.toString();
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+    
+    
+    /**
+     * Set the java.protocol.handler.pkgs system property.
+     */
+    public static void setProtocolHandler() {
+        String value = System.getProperty(Constants.PROTOCOL_HANDLER_VARIABLE);
+        if (value == null) {
+            value = Constants.Package;
+            System.setProperty(Constants.PROTOCOL_HANDLER_VARIABLE, value);
+        } else if (value.indexOf(Constants.Package) == -1) {
+            value += "|" + Constants.Package;
+            System.setProperty(Constants.PROTOCOL_HANDLER_VARIABLE, value);
+        }
+    }
+    
+    
+    /**
+     * Returns true if the thread or the context class loader of the current 
+     * thread is bound.
+     */
+    public static boolean isBound() {
+        return (clBindings.containsKey
+                (Thread.currentThread().getContextClassLoader()))
+            || (threadBindings.containsKey(Thread.currentThread()));
+    }
+    
+    
+    /**
+     * Binds a directory context to a class loader.
+     */
+    public static void bind(DirContext dirContext) {
+        ClassLoader currentCL = 
+            Thread.currentThread().getContextClassLoader();
+        if (currentCL != null)
+            clBindings.put(currentCL, dirContext);
+    }
+    
+    
+    /**
+     * Unbinds a directory context to a class loader.
+     */
+    public static void unbind() {
+        ClassLoader currentCL = 
+            Thread.currentThread().getContextClassLoader();
+        if (currentCL != null)
+            clBindings.remove(currentCL);
+    }
+    
+    
+    /**
+     * Binds a directory context to a thread.
+     */
+    public static void bindThread(DirContext dirContext) {
+        threadBindings.put(Thread.currentThread(), dirContext);
+    }
+    
+    
+    /**
+     * Unbinds a directory context to a thread.
+     */
+    public static void unbindThread() {
+        threadBindings.remove(Thread.currentThread());
+    }
+    
+    
+    /**
+     * Get the bound context.
+     */
+    public static DirContext get() {
+
+        DirContext result = null;
+
+        Thread currentThread = Thread.currentThread();
+        ClassLoader currentCL = currentThread.getContextClassLoader();
+
+        // Checking CL binding
+        result = (DirContext) clBindings.get(currentCL);
+        if (result != null)
+            return result;
+
+        // Checking thread biding
+        result = (DirContext) threadBindings.get(currentThread);
+
+        // Checking parent CL binding
+        currentCL = currentCL.getParent();
+        while (currentCL != null) {
+            result = (DirContext) clBindings.get(currentCL);
+            if (result != null)
+                return result;
+            currentCL = currentCL.getParent();
+        }
+
+        if (result == null)
+            throw new IllegalStateException("Illegal class loader binding");
+
+        return result;
+
+    }
+    
+    
+    /**
+     * Binds a directory context to a class loader.
+     */
+    public static void bind(ClassLoader cl, DirContext dirContext) {
+        clBindings.put(cl, dirContext);
+    }
+    
+    
+    /**
+     * Unbinds a directory context to a class loader.
+     */
+    public static void unbind(ClassLoader cl) {
+        clBindings.remove(cl);
+    }
+    
+    
+    /**
+     * Get the bound context.
+     */
+    public static DirContext get(ClassLoader cl) {
+        return (DirContext) clBindings.get(cl);
+    }
+    
+    
+    /**
+     * Get the bound context.
+     */
+    public static DirContext get(Thread thread) {
+        return (DirContext) threadBindings.get(thread);
+    }
+    
+    
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/resources/DirContextURLStreamHandlerFactory.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/resources/DirContextURLStreamHandlerFactory.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/resources/DirContextURLStreamHandlerFactory.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,65 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.naming.resources;
+
+import java.net.URLStreamHandler;
+import java.net.URLStreamHandlerFactory;
+
+/**
+ * Factory for Stream handlers to a JNDI directory context.
+ * 
+ * @author <a href="mailto:remm at apache.org">Remy Maucherat</a>
+ * @version $Revision: 302726 $
+ */
+public class DirContextURLStreamHandlerFactory 
+    implements URLStreamHandlerFactory {
+    
+    
+    // ----------------------------------------------------------- Constructors
+    
+    
+    public DirContextURLStreamHandlerFactory() {
+    }
+    
+    
+    // ----------------------------------------------------- Instance Variables
+    
+    
+    // ------------------------------------------------------------- Properties
+    
+    
+    // ---------------------------------------- URLStreamHandlerFactory Methods
+    
+    
+    /**
+     * Creates a new URLStreamHandler instance with the specified protocol.
+     * Will return null if the protocol is not <code>jndi</code>.
+     * 
+     * @param protocol the protocol (must be "jndi" here)
+     * @return a URLStreamHandler for the jndi protocol, or null if the 
+     * protocol is not JNDI
+     */
+    public URLStreamHandler createURLStreamHandler(String protocol) {
+        if (protocol.equals("jndi")) {
+            return new DirContextURLStreamHandler();
+        } else {
+            return null;
+        }
+    }
+    
+    
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/resources/FileDirContext.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/resources/FileDirContext.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/resources/FileDirContext.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,1140 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ *
+ * Licensed 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.naming.resources;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.Hashtable;
+
+import javax.naming.NameAlreadyBoundException;
+import javax.naming.NamingEnumeration;
+import javax.naming.NamingException;
+import javax.naming.OperationNotSupportedException;
+import javax.naming.directory.Attributes;
+import javax.naming.directory.DirContext;
+import javax.naming.directory.ModificationItem;
+import javax.naming.directory.SearchControls;
+
+import org.apache.naming.NamingContextBindingsEnumeration;
+import org.apache.naming.NamingContextEnumeration;
+import org.apache.naming.NamingEntry;
+
+/**
+ * Filesystem Directory Context implementation helper class.
+ *
+ * @author Remy Maucherat
+ * @version $Revision: 393882 $ $Date: 2006-04-13 13:46:19 -0500 (Thu, 13 Apr 2006) $
+ */
+
+public class FileDirContext extends BaseDirContext {
+
+    private static org.apache.commons.logging.Log log=
+        org.apache.commons.logging.LogFactory.getLog( FileDirContext.class );
+
+    // -------------------------------------------------------------- Constants
+
+
+    /**
+     * The descriptive information string for this implementation.
+     */
+    protected static final int BUFFER_SIZE = 2048;
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Builds a file directory context using the given environment.
+     */
+    public FileDirContext() {
+        super();
+    }
+
+
+    /**
+     * Builds a file directory context using the given environment.
+     */
+    public FileDirContext(Hashtable env) {
+        super(env);
+    }
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The document base directory.
+     */
+    protected File base = null;
+
+
+    /**
+     * Absolute normalized filename of the base.
+     */
+    protected String absoluteBase = null;
+
+
+    /**
+     * Case sensitivity.
+     */
+    protected boolean caseSensitive = true;
+
+
+    /**
+     * Allow linking.
+     */
+    protected boolean allowLinking = false;
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * Set the document root.
+     *
+     * @param docBase The new document root
+     *
+     * @exception IllegalArgumentException if the specified value is not
+     *  supported by this implementation
+     * @exception IllegalArgumentException if this would create a
+     *  malformed URL
+     */
+    public void setDocBase(String docBase) {
+
+    // Validate the format of the proposed document root
+    if (docBase == null)
+        throw new IllegalArgumentException
+        (sm.getString("resources.null"));
+
+    // Calculate a File object referencing this document base directory
+    base = new File(docBase);
+        try {
+            base = base.getCanonicalFile();
+        } catch (IOException e) {
+            // Ignore
+        }
+
+    // Validate that the document base is an existing directory
+    if (!base.exists() || !base.isDirectory() || !base.canRead())
+        throw new IllegalArgumentException
+        (sm.getString("fileResources.base", docBase));
+        this.absoluteBase = base.getAbsolutePath();
+        super.setDocBase(docBase);
+
+    }
+
+
+    /**
+     * Set case sensitivity.
+     */
+    public void setCaseSensitive(boolean caseSensitive) {
+        this.caseSensitive = caseSensitive;
+    }
+
+
+    /**
+     * Is case sensitive ?
+     */
+    public boolean isCaseSensitive() {
+        return caseSensitive;
+    }
+
+
+    /**
+     * Set allow linking.
+     */
+    public void setAllowLinking(boolean allowLinking) {
+        this.allowLinking = allowLinking;
+    }
+
+
+    /**
+     * Is linking allowed.
+     */
+    public boolean getAllowLinking() {
+        return allowLinking;
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Release any resources allocated for this directory context.
+     */
+    public void release() {
+
+        caseSensitive = true;
+        allowLinking = false;
+        absoluteBase = null;
+        base = null;
+        super.release();
+
+    }
+
+
+    // -------------------------------------------------------- Context Methods
+
+
+    /**
+     * Retrieves the named object.
+     *
+     * @param name the name of the object to look up
+     * @return the object bound to name
+     * @exception NamingException if a naming exception is encountered
+     */
+    public Object lookup(String name)
+        throws NamingException {
+        Object result = null;
+        File file = file(name);
+
+        if (file == null)
+            throw new NamingException
+                (sm.getString("resources.notFound", name));
+
+        if (file.isDirectory()) {
+            FileDirContext tempContext = new FileDirContext(env);
+            tempContext.setDocBase(file.getPath());
+            tempContext.setAllowLinking(getAllowLinking());
+            tempContext.setCaseSensitive(isCaseSensitive());
+            result = tempContext;
+        } else {
+            result = new FileResource(file);
+        }
+
+        return result;
+
+    }
+
+
+    /**
+     * Unbinds the named object. Removes the terminal atomic name in name
+     * from the target context--that named by all but the terminal atomic
+     * part of name.
+     * <p>
+     * This method is idempotent. It succeeds even if the terminal atomic
+     * name is not bound in the target context, but throws
+     * NameNotFoundException if any of the intermediate contexts do not exist.
+     *
+     * @param name the name to bind; may not be empty
+     * @exception NameNotFoundException if an intermediate context does not
+     * exist
+     * @exception NamingException if a naming exception is encountered
+     */
+    public void unbind(String name)
+        throws NamingException {
+
+        File file = file(name);
+
+        if (file == null)
+            throw new NamingException
+                (sm.getString("resources.notFound", name));
+
+        if (!file.delete())
+            throw new NamingException
+                (sm.getString("resources.unbindFailed", name));
+
+    }
+
+
+    /**
+     * Binds a new name to the object bound to an old name, and unbinds the
+     * old name. Both names are relative to this context. Any attributes
+     * associated with the old name become associated with the new name.
+     * Intermediate contexts of the old name are not changed.
+     *
+     * @param oldName the name of the existing binding; may not be empty
+     * @param newName the name of the new binding; may not be empty
+     * @exception NameAlreadyBoundException if newName is already bound
+     * @exception NamingException if a naming exception is encountered
+     */
+    public void rename(String oldName, String newName)
+        throws NamingException {
+
+        File file = file(oldName);
+
+        if (file == null)
+            throw new NamingException
+                (sm.getString("resources.notFound", oldName));
+
+        File newFile = new File(base, newName);
+
+        file.renameTo(newFile);
+
+    }
+
+
+    /**
+     * 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
+     */
+    public NamingEnumeration list(String name)
+        throws NamingException {
+
+        File file = file(name);
+
+        if (file == null)
+            throw new NamingException
+                (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.
+     * <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 bindings in this context.
+     * Each element of the enumeration is of type Binding.
+     * @exception NamingException if a naming exception is encountered
+     */
+    public NamingEnumeration listBindings(String name)
+        throws NamingException {
+
+        File file = file(name);
+
+        if (file == null)
+            throw new NamingException
+                (sm.getString("resources.notFound", name));
+
+        return new NamingContextBindingsEnumeration(list(file).iterator(),
+                this);
+
+    }
+
+
+    /**
+     * Destroys the named context and removes it from the namespace. Any
+     * attributes associated with the name are also removed. Intermediate
+     * contexts are not destroyed.
+     * <p>
+     * This method is idempotent. It succeeds even if the terminal atomic
+     * name is not bound in the target context, but throws
+     * NameNotFoundException if any of the intermediate contexts do not exist.
+     *
+     * In a federated naming system, a context from one naming system may be
+     * bound to a name in another. One can subsequently look up and perform
+     * operations on the foreign context using a composite name. However, an
+     * attempt destroy the context using this composite name will fail with
+     * NotContextException, because the foreign context is not a "subcontext"
+     * of the context in which it is bound. Instead, use unbind() to remove
+     * the binding of the foreign context. Destroying the foreign context
+     * requires that the destroySubcontext() be performed on a context from
+     * the foreign context's "native" naming system.
+     *
+     * @param name the name of the context to be destroyed; may not be empty
+     * @exception NameNotFoundException if an intermediate context does not
+     * exist
+     * @exception NotContextException if the name is bound but does not name
+     * a context, or does not name a context of the appropriate type
+     */
+    public void destroySubcontext(String name)
+        throws NamingException {
+        unbind(name);
+    }
+
+
+    /**
+     * Retrieves the named object, following links except for the terminal
+     * atomic component of the name. If the object bound to name is not a
+     * link, returns the object itself.
+     *
+     * @param name the name of the object to look up
+     * @return the object bound to name, not following the terminal link
+     * (if any).
+     * @exception NamingException if a naming exception is encountered
+     */
+    public Object lookupLink(String name)
+        throws NamingException {
+        // Note : Links are not supported
+        return lookup(name);
+    }
+
+
+    /**
+     * Retrieves the full name of this context within its own namespace.
+     * <p>
+     * Many naming services have a notion of a "full name" for objects in
+     * their respective namespaces. For example, an LDAP entry has a
+     * distinguished name, and a DNS record has a fully qualified name. This
+     * method allows the client application to retrieve this name. The string
+     * returned by this method is not a JNDI composite name and should not be
+     * passed directly to context methods. In naming systems for which the
+     * notion of full name does not make sense,
+     * OperationNotSupportedException is thrown.
+     *
+     * @return this context's name in its own namespace; never null
+     * @exception OperationNotSupportedException if the naming system does
+     * not have the notion of a full name
+     * @exception NamingException if a naming exception is encountered
+     */
+    public String getNameInNamespace()
+        throws NamingException {
+        return docBase;
+    }
+
+
+    // ----------------------------------------------------- DirContext Methods
+
+
+    /**
+     * Retrieves selected attributes associated with a named object.
+     * See the class description regarding attribute models, attribute type
+     * names, and operational attributes.
+     *
+     * @return the requested attributes; never null
+     * @param name the name of the object from which to retrieve attributes
+     * @param attrIds the identifiers of the attributes to retrieve. null
+     * indicates that all attributes should be retrieved; an empty array
+     * indicates that none should be retrieved
+     * @exception NamingException if a naming exception is encountered
+     */
+    public Attributes getAttributes(String name, String[] attrIds)
+        throws NamingException {
+
+        // Building attribute list
+        File file = file(name);
+
+        if (file == null)
+            throw new NamingException
+                (sm.getString("resources.notFound", name));
+
+        return new FileResourceAttributes(file);
+
+    }
+
+
+    /**
+     * Modifies the attributes associated with a named object. The order of
+     * the modifications is not specified. Where possible, the modifications
+     * are performed atomically.
+     *
+     * @param name the name of the object whose attributes will be updated
+     * @param mod_op the modification operation, one of: ADD_ATTRIBUTE,
+     * REPLACE_ATTRIBUTE, REMOVE_ATTRIBUTE
+     * @param attrs the attributes to be used for the modification; may not
+     * be null
+     * @exception AttributeModificationException if the modification cannot be
+     * completed successfully
+     * @exception NamingException if a naming exception is encountered
+     */
+    public void modifyAttributes(String name, int mod_op, Attributes attrs)
+        throws NamingException {
+
+    }
+
+
+    /**
+     * Modifies the attributes associated with a named object using an an
+     * ordered list of modifications. The modifications are performed in the
+     * order specified. Each modification specifies a modification operation
+     * code and an attribute on which to operate. Where possible, the
+     * modifications are performed atomically.
+     *
+     * @param name the name of the object whose attributes will be updated
+     * @param mods an ordered sequence of modifications to be performed; may
+     * not be null
+     * @exception AttributeModificationException if the modification cannot be
+     * completed successfully
+     * @exception NamingException if a naming exception is encountered
+     */
+    public void modifyAttributes(String name, ModificationItem[] mods)
+        throws NamingException {
+
+    }
+
+
+    /**
+     * Binds a name to an object, along with associated attributes. If attrs
+     * is null, the resulting binding will have the attributes associated
+     * with obj if obj is a DirContext, and no attributes otherwise. If attrs
+     * is non-null, the resulting binding will have attrs as its attributes;
+     * any attributes associated with obj are ignored.
+     *
+     * @param name the name to bind; may not be empty
+     * @param obj the object to bind; possibly null
+     * @param attrs the attributes to associate with the binding
+     * @exception NameAlreadyBoundException if name is already bound
+     * @exception InvalidAttributesException if some "mandatory" attributes
+     * of the binding are not supplied
+     * @exception NamingException if a naming exception is encountered
+     */
+    public void bind(String name, Object obj, Attributes attrs)
+        throws NamingException {
+
+        // Note: No custom attributes allowed
+
+        File file = new File(base, name);
+        if (file.exists())
+            throw new NameAlreadyBoundException
+                (sm.getString("resources.alreadyBound", name));
+
+        rebind(name, obj, attrs);
+
+    }
+
+
+    /**
+     * Binds a name to an object, along with associated attributes,
+     * overwriting any existing binding. If attrs is null and obj is a
+     * DirContext, the attributes from obj are used. If attrs is null and obj
+     * is not a DirContext, any existing attributes associated with the object
+     * already bound in the directory remain unchanged. If attrs is non-null,
+     * any existing attributes associated with the object already bound in
+     * the directory are removed and attrs is associated with the named
+     * object. If obj is a DirContext and attrs is non-null, the attributes
+     * of obj are ignored.
+     *
+     * @param name the name to bind; may not be empty
+     * @param obj the object to bind; possibly null
+     * @param attrs the attributes to associate with the binding
+     * @exception InvalidAttributesException if some "mandatory" attributes
+     * of the binding are not supplied
+     * @exception NamingException if a naming exception is encountered
+     */
+    public void rebind(String name, Object obj, Attributes attrs)
+        throws NamingException {
+
+        // Note: No custom attributes allowed
+        // Check obj type
+
+        File file = new File(base, name);
+
+        InputStream is = null;
+        if (obj instanceof Resource) {
+            try {
+                is = ((Resource) obj).streamContent();
+            } catch (IOException e) {
+            }
+        } else if (obj instanceof InputStream) {
+            is = (InputStream) obj;
+        } else if (obj instanceof DirContext) {
+            if (file.exists()) {
+                if (!file.delete())
+                    throw new NamingException
+                        (sm.getString("resources.bindFailed", name));
+            }
+            if (!file.mkdir())
+                throw new NamingException
+                    (sm.getString("resources.bindFailed", name));
+        }
+        if (is == null)
+            throw new NamingException
+                (sm.getString("resources.bindFailed", name));
+
+        // Open os
+
+        try {
+            FileOutputStream os = null;
+            byte buffer[] = new byte[BUFFER_SIZE];
+            int len = -1;
+            try {
+                os = new FileOutputStream(file);
+                while (true) {
+                    len = is.read(buffer);
+                    if (len == -1)
+                        break;
+                    os.write(buffer, 0, len);
+                }
+            } finally {
+                if (os != null)
+                    os.close();
+                is.close();
+            }
+        } catch (IOException e) {
+            throw new NamingException
+                (sm.getString("resources.bindFailed", e));
+        }
+
+    }
+
+
+    /**
+     * Creates and binds a new context, along with associated attributes.
+     * This method creates a new subcontext with the given name, binds it in
+     * the target context (that named by all but terminal atomic component of
+     * the name), and associates the supplied attributes with the newly
+     * created object. All intermediate and target contexts must already
+     * exist. If attrs is null, this method is equivalent to
+     * Context.createSubcontext().
+     *
+     * @param name the name of the context to create; may not be empty
+     * @param attrs the attributes to associate with the newly created context
+     * @return the newly created context
+     * @exception NameAlreadyBoundException if the name is already bound
+     * @exception InvalidAttributesException if attrs does not contain all
+     * the mandatory attributes required for creation
+     * @exception NamingException if a naming exception is encountered
+     */
+    public DirContext createSubcontext(String name, Attributes attrs)
+        throws NamingException {
+
+        File file = new File(base, name);
+        if (file.exists())
+            throw new NameAlreadyBoundException
+                (sm.getString("resources.alreadyBound", name));
+        if (!file.mkdir())
+            throw new NamingException
+                (sm.getString("resources.bindFailed", name));
+        return (DirContext) lookup(name);
+
+    }
+
+
+    /**
+     * Retrieves the schema associated with the named object. The schema
+     * describes rules regarding the structure of the namespace and the
+     * attributes stored within it. The schema specifies what types of
+     * objects can be added to the directory and where they can be added;
+     * what mandatory and optional attributes an object can have. The range
+     * of support for schemas is directory-specific.
+     *
+     * @param name the name of the object whose schema is to be retrieved
+     * @return the schema associated with the context; never null
+     * @exception OperationNotSupportedException if schema not supported
+     * @exception NamingException if a naming exception is encountered
+     */
+    public DirContext getSchema(String name)
+        throws NamingException {
+        throw new OperationNotSupportedException();
+    }
+
+
+    /**
+     * Retrieves a context containing the schema objects of the named
+     * object's class definitions.
+     *
+     * @param name the name of the object whose object class definition is to
+     * be retrieved
+     * @return the DirContext containing the named object's class
+     * definitions; never null
+     * @exception OperationNotSupportedException if schema not supported
+     * @exception NamingException if a naming exception is encountered
+     */
+    public DirContext getSchemaClassDefinition(String name)
+        throws NamingException {
+        throw new OperationNotSupportedException();
+    }
+
+
+    /**
+     * Searches in a single context for objects that contain a specified set
+     * of attributes, and retrieves selected attributes. The search is
+     * performed using the default SearchControls settings.
+     *
+     * @param name the name of the context to search
+     * @param matchingAttributes the attributes to search for. If empty or
+     * null, all objects in the target context are returned.
+     * @param attributesToReturn the attributes to return. null indicates
+     * that all attributes are to be returned; an empty array indicates that
+     * none are to be returned.
+     * @return a non-null enumeration of SearchResult objects. Each
+     * SearchResult contains the attributes identified by attributesToReturn
+     * and the name of the corresponding object, named relative to the
+     * context named by name.
+     * @exception NamingException if a naming exception is encountered
+     */
+    public NamingEnumeration search(String name, Attributes matchingAttributes,
+                                    String[] attributesToReturn)
+        throws NamingException {
+        return null;
+    }
+
+
+    /**
+     * Searches in a single context for objects that contain a specified set
+     * of attributes. This method returns all the attributes of such objects.
+     * It is equivalent to supplying null as the atributesToReturn parameter
+     * to the method search(Name, Attributes, String[]).
+     *
+     * @param name the name of the context to search
+     * @param matchingAttributes the attributes to search for. If empty or
+     * null, all objects in the target context are returned.
+     * @return a non-null enumeration of SearchResult objects. Each
+     * SearchResult contains the attributes identified by attributesToReturn
+     * and the name of the corresponding object, named relative to the
+     * context named by name.
+     * @exception NamingException if a naming exception is encountered
+     */
+    public NamingEnumeration search(String name, Attributes matchingAttributes)
+        throws NamingException {
+        return null;
+    }
+
+
+    /**
+     * Searches in the named context or object for entries that satisfy the
+     * given search filter. Performs the search as specified by the search
+     * controls.
+     *
+     * @param name the name of the context or object to search
+     * @param filter the filter expression to use for the search; may not be
+     * null
+     * @param cons the search controls that control the search. If null,
+     * the default search controls are used (equivalent to
+     * (new SearchControls())).
+     * @return an enumeration of SearchResults of the objects that satisfy
+     * the filter; never null
+     * @exception InvalidSearchFilterException if the search filter specified
+     * is not supported or understood by the underlying directory
+     * @exception InvalidSearchControlsException if the search controls
+     * contain invalid settings
+     * @exception NamingException if a naming exception is encountered
+     */
+    public NamingEnumeration search(String name, String filter,
+                                    SearchControls cons)
+        throws NamingException {
+        return null;
+    }
+
+
+    /**
+     * Searches in the named context or object for entries that satisfy the
+     * given search filter. Performs the search as specified by the search
+     * controls.
+     *
+     * @param name the name of the context or object to search
+     * @param filterExpr the filter expression to use for the search.
+     * The expression may contain variables of the form "{i}" where i is a
+     * nonnegative integer. May not be null.
+     * @param filterArgs the array of arguments to substitute for the
+     * variables in filterExpr. The value of filterArgs[i] will replace each
+     * occurrence of "{i}". If null, equivalent to an empty array.
+     * @param cons the search controls that control the search. If null, the
+     * default search controls are used (equivalent to (new SearchControls())).
+     * @return an enumeration of SearchResults of the objects that satisy the
+     * filter; never null
+     * @exception ArrayIndexOutOfBoundsException if filterExpr contains {i}
+     * expressions where i is outside the bounds of the array filterArgs
+     * @exception InvalidSearchControlsException if cons contains invalid
+     * settings
+     * @exception InvalidSearchFilterException if filterExpr with filterArgs
+     * represents an invalid search filter
+     * @exception NamingException if a naming exception is encountered
+     */
+    public NamingEnumeration search(String name, String filterExpr,
+                                    Object[] filterArgs, SearchControls cons)
+        throws NamingException {
+        return null;
+    }
+
+
+    // ------------------------------------------------------ Protected Methods
+
+
+    /**
+     * Return a context-relative path, beginning with a "/", that represents
+     * the canonical version of the specified path after ".." and "." elements
+     * are resolved out.  If the specified path attempts to go outside the
+     * boundaries of the current context (i.e. too many ".." path elements
+     * are present), return <code>null</code> instead.
+     *
+     * @param path Path to be normalized
+     */
+    protected String normalize(String path) {
+
+    String normalized = path;
+
+    // Normalize the slashes and add leading slash if necessary
+    if (File.separatorChar == '\\' && normalized.indexOf('\\') >= 0)
+        normalized = normalized.replace('\\', '/');
+    if (!normalized.startsWith("/"))
+        normalized = "/" + normalized;
+
+    // Resolve occurrences of "//" in the normalized path
+    while (true) {
+        int index = normalized.indexOf("//");
+        if (index < 0)
+        break;
+        normalized = normalized.substring(0, index) +
+        normalized.substring(index + 1);
+    }
+
+    // Resolve occurrences of "/./" in the normalized path
+    while (true) {
+        int index = normalized.indexOf("/./");
+        if (index < 0)
+        break;
+        normalized = normalized.substring(0, index) +
+        normalized.substring(index + 2);
+    }
+
+    // Resolve occurrences of "/../" in the normalized path
+    while (true) {
+        int index = normalized.indexOf("/../");
+        if (index < 0)
+        break;
+        if (index == 0)
+        return (null);  // Trying to go outside our context
+        int index2 = normalized.lastIndexOf('/', index - 1);
+        normalized = normalized.substring(0, index2) +
+        normalized.substring(index + 3);
+    }
+
+    // Return the normalized path that we have completed
+    return (normalized);
+
+    }
+
+
+    /**
+     * Return a File object representing the specified normalized
+     * context-relative path if it exists and is readable.  Otherwise,
+     * return <code>null</code>.
+     *
+     * @param name Normalized context-relative path (with leading '/')
+     */
+    protected File file(String name) {
+
+        File file = new File(base, name);
+        if (file.exists() && file.canRead()) {
+
+        	if (allowLinking)
+        		return file;
+        	
+            // Check that this file belongs to our root path
+            String canPath = null;
+            try {
+                canPath = file.getCanonicalPath();
+            } catch (IOException e) {
+            }
+            if (canPath == null)
+                return null;
+
+            // Bugzilla 38154: after release() the absoluteBase is null, leading to an NPE
+            if (absoluteBase == null) {
+                return null;
+            }
+
+            // Check to see if going outside of the web application root
+            if (!canPath.startsWith(absoluteBase)) {
+                return null;
+            }
+
+            // Case sensitivity check
+            if (caseSensitive) {
+                String fileAbsPath = file.getAbsolutePath();
+                if (fileAbsPath.endsWith("."))
+                    fileAbsPath = fileAbsPath + "/";
+                String absPath = normalize(fileAbsPath);
+                if (canPath != null)
+                    canPath = normalize(canPath);
+                if ((absoluteBase.length() < absPath.length())
+                    && (absoluteBase.length() < canPath.length())) {
+                    absPath = absPath.substring(absoluteBase.length() + 1);
+                    if ((canPath == null) || (absPath == null))
+                        return null;
+                    if (absPath.equals(""))
+                        absPath = "/";
+                    canPath = canPath.substring(absoluteBase.length() + 1);
+                    if (canPath.equals(""))
+                        canPath = "/";
+                    if (!canPath.equals(absPath))
+                        return null;
+                }
+            }
+
+        } else {
+            return null;
+        }
+        return file;
+
+    }
+
+
+    /**
+     * List the resources which are members of a collection.
+     *
+     * @param file Collection
+     * @return Vector containg NamingEntry objects
+     */
+    protected ArrayList list(File file) {
+
+        ArrayList entries = new ArrayList();
+        if (!file.isDirectory())
+            return entries;
+        String[] names = file.list();
+        if (names==null) {
+            /* Some IO error occurred such as bad file permissions.
+               Prevent a NPE with Arrays.sort(names) */
+            log.warn(sm.getString("fileResources.listingNull",
+                                  file.getAbsolutePath()));
+            return entries;
+        }
+
+        Arrays.sort(names);             // Sort alphabetically
+        if (names == null)
+            return entries;
+        NamingEntry entry = null;
+
+        for (int i = 0; i < names.length; i++) {
+
+            File currentFile = new File(file, names[i]);
+            Object object = null;
+            if (currentFile.isDirectory()) {
+                FileDirContext tempContext = new FileDirContext(env);
+                tempContext.setDocBase(file.getPath());
+                tempContext.setAllowLinking(getAllowLinking());
+                tempContext.setCaseSensitive(isCaseSensitive());
+                object = tempContext;
+            } else {
+                object = new FileResource(currentFile);
+            }
+            entry = new NamingEntry(names[i], object, NamingEntry.ENTRY);
+            entries.add(entry);
+
+        }
+
+        return entries;
+
+    }
+
+
+    // ----------------------------------------------- FileResource Inner Class
+
+
+    /**
+     * This specialized resource implementation avoids opening the IputStream
+     * to the file right away (which would put a lock on the file).
+     */
+    protected class FileResource extends Resource {
+
+
+        // -------------------------------------------------------- Constructor
+
+
+        public FileResource(File file) {
+            this.file = file;
+        }
+
+
+        // --------------------------------------------------- Member Variables
+
+
+        /**
+         * Associated file object.
+         */
+        protected File file;
+
+
+        /**
+         * File length.
+         */
+        protected long length = -1L;
+
+
+        // --------------------------------------------------- Resource Methods
+
+
+        /**
+         * Content accessor.
+         *
+         * @return InputStream
+         */
+        public InputStream streamContent()
+            throws IOException {
+            if (binaryContent == null) {
+                inputStream = new FileInputStream(file);
+            }
+            return super.streamContent();
+        }
+
+
+    }
+
+
+    // ------------------------------------- FileResourceAttributes Inner Class
+
+
+    /**
+     * This specialized resource attribute implementation does some lazy
+     * reading (to speed up simple checks, like checking the last modified
+     * date).
+     */
+    protected class FileResourceAttributes extends ResourceAttributes {
+
+
+        // -------------------------------------------------------- Constructor
+
+
+        public FileResourceAttributes(File file) {
+            this.file = file;
+        }
+
+        // --------------------------------------------------- Member Variables
+
+
+        protected File file;
+
+
+        protected boolean accessed = false;
+
+
+        protected String canonicalPath = null;
+
+
+        // ----------------------------------------- ResourceAttributes Methods
+
+
+        /**
+         * Is collection.
+         */
+        public boolean isCollection() {
+            if (!accessed) {
+                collection = file.isDirectory();
+                accessed = true;
+            }
+            return super.isCollection();
+        }
+
+
+        /**
+         * Get content length.
+         *
+         * @return content length value
+         */
+        public long getContentLength() {
+            if (contentLength != -1L)
+                return contentLength;
+            contentLength = file.length();
+            return contentLength;
+        }
+
+
+        /**
+         * Get creation time.
+         *
+         * @return creation time value
+         */
+        public long getCreation() {
+            if (creation != -1L)
+                return creation;
+            creation = file.lastModified();
+            return creation;
+        }
+
+
+        /**
+         * Get creation date.
+         *
+         * @return Creation date value
+         */
+        public Date getCreationDate() {
+            if (creation == -1L) {
+                creation = file.lastModified();
+            }
+            return super.getCreationDate();
+        }
+
+
+        /**
+         * Get last modified time.
+         *
+         * @return lastModified time value
+         */
+        public long getLastModified() {
+            if (lastModified != -1L)
+                return lastModified;
+            lastModified = file.lastModified();
+            return lastModified;
+        }
+
+
+        /**
+         * Get lastModified date.
+         *
+         * @return LastModified date value
+         */
+        public Date getLastModifiedDate() {
+            if (lastModified == -1L) {
+                lastModified = file.lastModified();
+            }
+            return super.getLastModifiedDate();
+        }
+
+
+        /**
+         * Get name.
+         *
+         * @return Name value
+         */
+        public String getName() {
+            if (name == null)
+                name = file.getName();
+            return name;
+        }
+
+
+        /**
+         * Get resource type.
+         *
+         * @return String resource type
+         */
+        public String getResourceType() {
+            if (!accessed) {
+                collection = file.isDirectory();
+                accessed = true;
+            }
+            return super.getResourceType();
+        }
+
+        
+        /**
+         * Get canonical path.
+         * 
+         * @return String the file's canonical path
+         */
+        public String getCanonicalPath() {
+            if (canonicalPath == null) {
+                try {
+                    canonicalPath = file.getCanonicalPath();
+                } catch (IOException e) {
+                    // Ignore
+                }
+            }
+            return canonicalPath;
+        }
+        
+
+    }
+
+
+}
+

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/resources/ImmutableNameNotFoundException.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/resources/ImmutableNameNotFoundException.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/resources/ImmutableNameNotFoundException.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,39 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.naming.resources;
+
+import javax.naming.Name;
+import javax.naming.NameNotFoundException;
+
+/**
+ * Immutable exception to avoid useless object creation by the proxy context.
+ * This should be used only by the proxy context. Actual contexts should return
+ * properly populated exceptions.
+ * 
+ * @author <a href="mailto:remm at apache.org">Remy Maucherat</a>
+ * @version $Revision: 302726 $
+ */
+public class ImmutableNameNotFoundException
+    extends NameNotFoundException {
+
+    public void appendRemainingComponent(String name) {}
+    public void appendRemainingName(Name name) {}
+    public void setRemainingName(Name name) {}
+    public void setResolverName(Name name) {}
+    public void setRootCause(Throwable e) {}
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/resources/LocalStrings.properties
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/resources/LocalStrings.properties	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/resources/LocalStrings.properties	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,21 @@
+fileResources.base=Document base {0} does not exist or is not a readable directory
+fileResources.listingNull=Could not get dir listing for {0}
+warResources.notWar=Doc base must point to a WAR file
+warResources.invalidWar=Invalid or unreadable WAR file : {0}
+jarResources.syntax=Document base {0} must start with ''jar:'' and end with ''!/''
+resources.alreadyStarted=Resources has already been started
+resources.connect=Cannot connect to document base {0}
+resources.input=Cannot create input stream for resource {0}
+resources.notStarted=Resources has not yet been started
+resources.null=Document base cannot be null
+resources.notFound=Resource {0} not found
+resources.path=Context relative path {0} must start with ''/''
+resources.alreadyBound=Name {0} is already bound in this Context
+resources.bindFailed=Bind failed: {0}
+resources.unbindFailed=Unbind failed: {0}
+standardResources.alreadyStarted=Resources has already been started
+standardResources.directory=File base {0} is not a directory
+standardResources.exists=File base {0} does not exist
+standardResources.notStarted=Resources has not yet been started
+standardResources.null=Document base cannot be null
+standardResources.slash=Document base {0} must not end with a slash

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/resources/LocalStrings_es.properties
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/resources/LocalStrings_es.properties	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/resources/LocalStrings_es.properties	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,20 @@
+fileResources.base=El Documento base {0} no existe o no es un directorio legible
+warResources.notWar=Doc base debe de apuntar a un archivo WAR
+warResources.invalidWar=Archivo WAR inválido o ilegible: {0}
+jarResources.syntax=Documento base {0} debe de empezar con ''jar:'' y acabar con ''!/''
+resources.alreadyStarted=Ya han sido arrancados los Recursos
+resources.connect=No puedo conectar a documento base {0}
+resources.input=No puedo crear flujo (stream) de entrada para recurso {0}
+resources.notStarted=Aún no han sido arrancados los Recursos
+resources.null=El Documento base no puede ser nulo
+resources.notFound=Recurso {0} no hallado
+resources.path=Trayectoria relativa a contexto {0} debe de comenzar con ''/''
+resources.alreadyBound=El Nombre {0} ya ha sido cambiado (bound) en este Contexto
+resources.bindFailed=Falló el Cambio (Bind): {0}
+resources.unbindFailed=Falló el Descambio (Unbind): {0}
+standardResources.alreadyStarted=Ya han sido arrancados los Recursos
+standardResources.directory=El archivo base {0} no es un directorio
+standardResources.exists=El archivo base {0} no existe
+standardResources.notStarted=Aún no han sido arrancados los Recursos
+standardResources.null=El Documento base no puede ser nulo
+standardResources.slash=El Documento base {0} no debe de terminar con una barra

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/resources/LocalStrings_fr.properties
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/resources/LocalStrings_fr.properties	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/resources/LocalStrings_fr.properties	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,20 @@
+fileResources.base=Le document base {0} n''existe pas ou n''est pas un répertoire lisible
+warResources.notWar=Doc base doit pointé vers un fichier WAR
+warResources.invalidWar=Fichier WAR invalide ou illisible  : {0}
+jarResources.syntax=Le document base {0} doit commencé par ''jar:'' et finir avec ''!/''
+resources.alreadyStarted=Les Ressources ont déjà été démarrées
+resources.connect=Impossible de se connecter au document base {0}
+resources.input=Impossible de créer l''input stream pour la ressource {0}
+resources.notStarted=Les ressources n''ont pas encore été démarrées
+resources.null=Le document base ne peut être nul
+resources.notFound=La ressource {0} est introuvable
+resources.path=Le chemin relatif de context {0} doit commencé par ''/''
+resources.alreadyBound=Le nom {0} est déjà référencé par ce contexte
+resources.bindFailed=Le liage a échoué: {0}
+resources.unbindFailed=Le déliage a échoué: {0}
+standardResources.alreadyStarted=Les ressources ont déja été démarrées
+standardResources.directory=Le file base {0} n''est pas un répertoire
+standardResources.exists=Le file base {0} n''existe pas
+standardResources.notStarted=Les ressources n''ont pas encore été démarrées
+standardResources.null=Le document base ne peut être nul
+standardResources.slash=Le document base {0} ne doit pas se terminer par un ''/''

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/resources/LocalStrings_ja.properties
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/resources/LocalStrings_ja.properties	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/resources/LocalStrings_ja.properties	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,21 @@
+fileResources.base=\u30c9\u30ad\u30e5\u30e1\u30f3\u30c8\u30d9\u30fc\u30b9 {0} \u304c\u5b58\u5728\u3057\u306a\u3044\u3001\u53c8\u306f\u8aad\u3081\u306a\u3044\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u3067\u3059
+fileResources.listingNull={0} \u306e\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u306e\u30ea\u30b9\u30c8\u3092\u53d6\u5f97\u3067\u304d\u307e\u305b\u3093
+warResources.notWar=\u30c9\u30ad\u30e5\u30e1\u30f3\u30c8\u30d9\u30fc\u30b9\u306fWAR\u30d5\u30a1\u30a4\u30eb\u3092\u793a\u3055\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093
+warResources.invalidWar=\u7121\u52b9\u53c8\u306f\u8aad\u3081\u306a\u3044WAR\u30d5\u30a1\u30a4\u30eb\u3067\u3059 : {0}
+jarResources.syntax=\u30c9\u30ad\u30e5\u30e1\u30f3\u30c8\u30d9\u30fc\u30b9 {0} \u306f''jar:''\u3067\u59cb\u307e\u308a\u3001''!/''\u3067\u7d42\u3089\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093
+resources.alreadyStarted=\u30ea\u30bd\u30fc\u30b9\u306f\u65e2\u306b\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u3059
+resources.connect=\u30c9\u30ad\u30e5\u30e1\u30f3\u30c8\u30d9\u30fc\u30b9 {0} \u306b\u63a5\u7d9a\u3067\u304d\u307e\u305b\u3093
+resources.input=\u30ea\u30bd\u30fc\u30b9 {0} \u306b\u5165\u529b\u30b9\u30c8\u30ea\u30fc\u30e0\u3092\u4f5c\u6210\u3067\u304d\u307e\u305b\u3093
+resources.notStarted=\u30ea\u30bd\u30fc\u30b9\u306f\u307e\u3060\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u305b\u3093
+resources.null=\u30c9\u30ad\u30e5\u30e1\u30f3\u30c8\u30d9\u30fc\u30b9\u306fnull\u3067\u3042\u3063\u3066\u306f\u3044\u3051\u307e\u305b\u3093
+resources.notFound=\u30ea\u30bd\u30fc\u30b9 {0} \u304c\u898b\u3064\u304b\u308a\u307e\u305b\u3093
+resources.path=\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u76f8\u5bfe\u30d1\u30b9 {0} \u306f''/''\u3067\u59cb\u307e\u3089\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093
+resources.alreadyBound=\u540d\u524d {0} \u306f\u65e2\u306b\u3053\u306e\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u306b\u30d0\u30a4\u30f3\u30c9\u3055\u308c\u3066\u3044\u307e\u3059
+resources.bindFailed=\u30d0\u30a4\u30f3\u30c9\u304c\u5931\u6557\u3057\u307e\u3057\u305f: {0}
+resources.unbindFailed=\u30a2\u30f3\u30d0\u30a4\u30f3\u30c9\u304c\u5931\u6557\u3057\u307e\u3057\u305f: {0}
+standardResources.alreadyStarted=\u30ea\u30bd\u30fc\u30b9\u306f\u65e2\u306b\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u3059
+standardResources.directory=\u30d5\u30a1\u30a4\u30eb\u30d9\u30fc\u30b9 {0} \u306f\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u3067\u306f\u3042\u308a\u307e\u305b\u3093
+standardResources.exists=\u30d5\u30a1\u30a4\u30eb\u30d9\u30fc\u30b9 {0} \u306f\u5b58\u5728\u3057\u307e\u305b\u3093
+standardResources.notStarted=\u30ea\u30bd\u30fc\u30b9\u304c\u307e\u3060\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u305b\u3093
+standardResources.null=\u30c9\u30ad\u30e5\u30e1\u30f3\u30c8\u30d9\u30fc\u30b9\u306fnull\u3067\u3042\u3063\u3066\u306f\u3044\u3051\u307e\u305b\u3093
+standardResources.slash=\u30c9\u30ad\u30e5\u30e1\u30f3\u30c8\u30d9\u30fc\u30b9 {0} \u306f\u30b9\u30e9\u30c3\u30b7\u30e5\u3067\u7d42\u3063\u3066\u306f\u3044\u3051\u307e\u305b\u3093

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/resources/ProxyDirContext.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/resources/ProxyDirContext.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/resources/ProxyDirContext.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,1620 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.naming.resources;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Hashtable;
+
+import javax.naming.Context;
+import javax.naming.Name;
+import javax.naming.NameNotFoundException;
+import javax.naming.NameParser;
+import javax.naming.NamingEnumeration;
+import javax.naming.NamingException;
+import javax.naming.directory.Attributes;
+import javax.naming.directory.DirContext;
+import javax.naming.directory.ModificationItem;
+import javax.naming.directory.SearchControls;
+
+import org.apache.naming.StringManager;
+
+/**
+ * Proxy Directory Context implementation.
+ *
+ * @author Remy Maucherat
+ * @version $Revision: 304085 $ $Date: 2005-09-12 05:57:46 -0500 (Mon, 12 Sep 2005) $
+ */
+
+public class ProxyDirContext implements DirContext {
+
+
+    // -------------------------------------------------------------- Constants
+
+
+    public static final String CONTEXT = "context";
+    public static final String HOST = "host";
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Builds a proxy directory context using the given environment.
+     */
+    public ProxyDirContext(Hashtable env, DirContext dirContext) {
+        this.env = env;
+        this.dirContext = dirContext;
+        if (dirContext instanceof BaseDirContext) {
+            // Initialize parameters based on the associated dir context, like
+            // the caching policy.
+            BaseDirContext baseDirContext = (BaseDirContext) dirContext;
+            if (baseDirContext.isCached()) {
+                try {
+                    cache = (ResourceCache) 
+                        Class.forName(cacheClassName).newInstance();
+                } catch (Exception e) {
+                    //FIXME
+                    e.printStackTrace();
+                }
+                cache.setCacheMaxSize(baseDirContext.getCacheMaxSize());
+                cacheTTL = baseDirContext.getCacheTTL();
+                cacheObjectMaxSize = baseDirContext.getCacheMaxSize() / 20;
+            }
+        }
+        hostName = (String) env.get(HOST);
+        contextName = (String) env.get(CONTEXT);
+    }
+
+
+    /**
+     * Builds a clone of this proxy dir context, wrapping the given directory
+     * context, and sharing the same cache.
+     */
+    // TODO: Refactor using the proxy field
+    /*
+    protected ProxyDirContext(ProxyDirContext proxyDirContext, 
+                              DirContext dirContext, String vPath) {
+        this.env = proxyDirContext.env;
+        this.dirContext = dirContext;
+        this.vPath = vPath;
+        this.cache = proxyDirContext.cache;
+        this.cacheMaxSize = proxyDirContext.cacheMaxSize;
+        this.cacheSize = proxyDirContext.cacheSize;
+        this.cacheTTL = proxyDirContext.cacheTTL;
+        this.cacheObjectMaxSize = proxyDirContext.cacheObjectMaxSize;
+        this.notFoundCache = proxyDirContext.notFoundCache;
+        this.hostName = proxyDirContext.hostName;
+        this.contextName = proxyDirContext.contextName;
+    }
+    */
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * Proxy DirContext (either this or the real proxy).
+     */
+    protected ProxyDirContext proxy = this;
+
+
+    /**
+     * Environment.
+     */
+    protected Hashtable env;
+
+
+    /**
+     * The string manager for this package.
+     */
+    protected StringManager sm = StringManager.getManager(Constants.Package);
+
+
+    /**
+     * Associated DirContext.
+     */
+    protected DirContext dirContext;
+
+
+    /**
+     * Virtual path.
+     */
+    protected String vPath = null;
+
+
+    /**
+     * Host name.
+     */
+    protected String hostName;
+
+
+    /**
+     * Context name.
+     */
+    protected String contextName;
+
+
+    /**
+     * Cache class.
+     */
+    protected String cacheClassName = 
+        "org.apache.naming.resources.ResourceCache";
+
+
+    /**
+     * Cache.
+     */
+    protected ResourceCache cache = null;
+
+
+    /**
+     * Cache TTL.
+     */
+    protected int cacheTTL = 5000; // 5s
+
+
+    /**
+     * Max size of resources which will have their content cached.
+     */
+    protected int cacheObjectMaxSize = 512; // 512 KB
+
+
+    /**
+     * Immutable name not found exception.
+     */
+    protected NameNotFoundException notFoundException =
+        new ImmutableNameNotFoundException();
+
+
+    /**
+     * Non cacheable resources.
+     */
+    protected String[] nonCacheable = { "/WEB-INF/lib/", "/WEB-INF/classes/" };
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Get the cache used for this context.
+     */
+    public ResourceCache getCache() {
+        return cache;
+    }
+
+
+    /**
+     * Return the actual directory context we are wrapping.
+     */
+    public DirContext getDirContext() {
+        return this.dirContext;
+    }
+
+
+    /**
+     * Return the document root for this component.
+     */
+    public String getDocBase() {
+        if (dirContext instanceof BaseDirContext)
+            return ((BaseDirContext) dirContext).getDocBase();
+        else
+            return "";
+    }
+
+
+    /**
+     * Return the host name.
+     */
+    public String getHostName() {
+        return this.hostName;
+    }
+
+
+    /**
+     * Return the context name.
+     */
+    public String getContextName() {
+        return this.contextName;
+    }
+
+
+    // -------------------------------------------------------- Context Methods
+
+
+    /**
+     * Retrieves the named object. If name is empty, returns a new instance 
+     * of this context (which represents the same naming context as this 
+     * context, but its environment may be modified independently and it may 
+     * be accessed concurrently).
+     * 
+     * @param name the name of the object to look up
+     * @return the object bound to name
+     * @exception NamingException if a naming exception is encountered
+     */
+    public Object lookup(Name name)
+        throws NamingException {
+        CacheEntry entry = cacheLookup(name.toString());
+        if (entry != null) {
+            if (!entry.exists) {
+                throw notFoundException;
+            }
+            if (entry.resource != null) {
+                // Check content caching.
+                return entry.resource;
+            } else {
+                return entry.context;
+            }
+        }
+        Object object = dirContext.lookup(parseName(name));
+        if (object instanceof InputStream)
+            return new Resource((InputStream) object);
+        else
+            return object;
+    }
+
+
+    /**
+     * Retrieves the named object.
+     * 
+     * @param name the name of the object to look up
+     * @return the object bound to name
+     * @exception NamingException if a naming exception is encountered
+     */
+    public Object lookup(String name)
+        throws NamingException {
+        CacheEntry entry = cacheLookup(name);
+        if (entry != null) {
+            if (!entry.exists) {
+                throw notFoundException;
+            }
+            if (entry.resource != null) {
+                return entry.resource;
+            } else {
+                return entry.context;
+            }
+        }
+        Object object = dirContext.lookup(parseName(name));
+        if (object instanceof InputStream) {
+            return new Resource((InputStream) object);
+        } else if (object instanceof DirContext) {
+            return object;
+        } else if (object instanceof Resource) {
+            return object;
+        } else {
+            return new Resource(new ByteArrayInputStream
+                (object.toString().getBytes()));
+        }
+    }
+
+
+    /**
+     * Binds a name to an object. All intermediate contexts and the target 
+     * context (that named by all but terminal atomic component of the name) 
+     * must already exist.
+     * 
+     * @param name the name to bind; may not be empty
+     * @param obj the object to bind; possibly null
+     * @exception NameAlreadyBoundException if name is already bound
+     * @exception InvalidAttributesException if object did not supply all 
+     * mandatory attributes
+     * @exception NamingException if a naming exception is encountered
+     */
+    public void bind(Name name, Object obj)
+        throws NamingException {
+        dirContext.bind(parseName(name), obj);
+        cacheUnload(name.toString());
+    }
+
+
+    /**
+     * Binds a name to an object.
+     * 
+     * @param name the name to bind; may not be empty
+     * @param obj the object to bind; possibly null
+     * @exception NameAlreadyBoundException if name is already bound
+     * @exception InvalidAttributesException if object did not supply all 
+     * mandatory attributes
+     * @exception NamingException if a naming exception is encountered
+     */
+    public void bind(String name, Object obj)
+        throws NamingException {
+        dirContext.bind(parseName(name), obj);
+        cacheUnload(name);
+    }
+
+
+    /**
+     * Binds a name to an object, overwriting any existing binding. All 
+     * intermediate contexts and the target context (that named by all but 
+     * terminal atomic component of the name) must already exist.
+     * <p>
+     * If the object is a DirContext, any existing attributes associated with 
+     * the name are replaced with those of the object. Otherwise, any 
+     * existing attributes associated with the name remain unchanged.
+     * 
+     * @param name the name to bind; may not be empty
+     * @param obj the object to bind; possibly null
+     * @exception InvalidAttributesException if object did not supply all 
+     * mandatory attributes
+     * @exception NamingException if a naming exception is encountered
+     */
+    public void rebind(Name name, Object obj)
+        throws NamingException {
+        dirContext.rebind(parseName(name), obj);
+        cacheUnload(name.toString());
+    }
+
+
+    /**
+     * Binds a name to an object, overwriting any existing binding.
+     * 
+     * @param name the name to bind; may not be empty
+     * @param obj the object to bind; possibly null
+     * @exception InvalidAttributesException if object did not supply all 
+     * mandatory attributes
+     * @exception NamingException if a naming exception is encountered
+     */
+    public void rebind(String name, Object obj)
+        throws NamingException {
+        dirContext.rebind(parseName(name), obj);
+        cacheUnload(name);
+    }
+
+
+    /**
+     * Unbinds the named object. Removes the terminal atomic name in name 
+     * from the target context--that named by all but the terminal atomic 
+     * part of name.
+     * <p>
+     * This method is idempotent. It succeeds even if the terminal atomic 
+     * name is not bound in the target context, but throws 
+     * NameNotFoundException if any of the intermediate contexts do not exist. 
+     * 
+     * @param name the name to bind; may not be empty
+     * @exception NameNotFoundException if an intermediate context does not 
+     * exist
+     * @exception NamingException if a naming exception is encountered
+     */
+    public void unbind(Name name)
+        throws NamingException {
+        dirContext.unbind(parseName(name));
+        cacheUnload(name.toString());
+    }
+
+
+    /**
+     * Unbinds the named object.
+     * 
+     * @param name the name to bind; may not be empty
+     * @exception NameNotFoundException if an intermediate context does not 
+     * exist
+     * @exception NamingException if a naming exception is encountered
+     */
+    public void unbind(String name)
+        throws NamingException {
+        dirContext.unbind(parseName(name));
+        cacheUnload(name);
+    }
+
+
+    /**
+     * Binds a new name to the object bound to an old name, and unbinds the 
+     * old name. Both names are relative to this context. Any attributes 
+     * associated with the old name become associated with the new name. 
+     * Intermediate contexts of the old name are not changed.
+     * 
+     * @param oldName the name of the existing binding; may not be empty
+     * @param newName the name of the new binding; may not be empty
+     * @exception NameAlreadyBoundException if newName is already bound
+     * @exception NamingException if a naming exception is encountered
+     */
+    public void rename(Name oldName, Name newName)
+        throws NamingException {
+        dirContext.rename(parseName(oldName), parseName(newName));
+        cacheUnload(oldName.toString());
+    }
+
+
+    /**
+     * Binds a new name to the object bound to an old name, and unbinds the 
+     * old name.
+     * 
+     * @param oldName the name of the existing binding; may not be empty
+     * @param newName the name of the new binding; may not be empty
+     * @exception NameAlreadyBoundException if newName is already bound
+     * @exception NamingException if a naming exception is encountered
+     */
+    public void rename(String oldName, String newName)
+        throws NamingException {
+        dirContext.rename(parseName(oldName), parseName(newName));
+        cacheUnload(oldName);
+    }
+
+
+    /**
+     * 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
+     */
+    public NamingEnumeration list(Name name)
+        throws NamingException {
+        return dirContext.list(parseName(name));
+    }
+
+
+    /**
+     * Enumerates the names bound in the named context, along with the class 
+     * names of objects bound to them.
+     * 
+     * @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
+     */
+    public NamingEnumeration list(String name)
+        throws NamingException {
+        return dirContext.list(parseName(name));
+    }
+
+
+    /**
+     * Enumerates the names bound in the named context, along with the 
+     * 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 bindings in this context. 
+     * Each element of the enumeration is of type Binding.
+     * @exception NamingException if a naming exception is encountered
+     */
+    public NamingEnumeration listBindings(Name name)
+        throws NamingException {
+        return dirContext.listBindings(parseName(name));
+    }
+
+
+    /**
+     * Enumerates the names bound in the named context, along with the 
+     * objects bound to them.
+     * 
+     * @param name the name of the context to list
+     * @return an enumeration of the bindings in this context. 
+     * Each element of the enumeration is of type Binding.
+     * @exception NamingException if a naming exception is encountered
+     */
+    public NamingEnumeration listBindings(String name)
+        throws NamingException {
+        return dirContext.listBindings(parseName(name));
+    }
+
+
+    /**
+     * Destroys the named context and removes it from the namespace. Any 
+     * attributes associated with the name are also removed. Intermediate 
+     * contexts are not destroyed.
+     * <p>
+     * This method is idempotent. It succeeds even if the terminal atomic 
+     * name is not bound in the target context, but throws 
+     * NameNotFoundException if any of the intermediate contexts do not exist. 
+     * 
+     * In a federated naming system, a context from one naming system may be 
+     * bound to a name in another. One can subsequently look up and perform 
+     * operations on the foreign context using a composite name. However, an 
+     * attempt destroy the context using this composite name will fail with 
+     * NotContextException, because the foreign context is not a "subcontext" 
+     * of the context in which it is bound. Instead, use unbind() to remove 
+     * the binding of the foreign context. Destroying the foreign context 
+     * requires that the destroySubcontext() be performed on a context from 
+     * the foreign context's "native" naming system.
+     * 
+     * @param name the name of the context to be destroyed; may not be empty
+     * @exception NameNotFoundException if an intermediate context does not 
+     * exist
+     * @exception NotContextException if the name is bound but does not name 
+     * a context, or does not name a context of the appropriate type
+     */
+    public void destroySubcontext(Name name)
+        throws NamingException {
+        dirContext.destroySubcontext(parseName(name));
+        cacheUnload(name.toString());
+    }
+
+
+    /**
+     * Destroys the named context and removes it from the namespace.
+     * 
+     * @param name the name of the context to be destroyed; may not be empty
+     * @exception NameNotFoundException if an intermediate context does not 
+     * exist
+     * @exception NotContextException if the name is bound but does not name 
+     * a context, or does not name a context of the appropriate type
+     */
+    public void destroySubcontext(String name)
+        throws NamingException {
+        dirContext.destroySubcontext(parseName(name));
+        cacheUnload(name);
+    }
+
+
+    /**
+     * Creates and binds a new context. Creates a new context with the given 
+     * name and binds it in the target context (that named by all but 
+     * terminal atomic component of the name). All intermediate contexts and 
+     * the target context must already exist.
+     * 
+     * @param name the name of the context to create; may not be empty
+     * @return the newly created context
+     * @exception NameAlreadyBoundException if name is already bound
+     * @exception InvalidAttributesException if creation of the subcontext 
+     * requires specification of mandatory attributes
+     * @exception NamingException if a naming exception is encountered
+     */
+    public Context createSubcontext(Name name)
+        throws NamingException {
+        Context context = dirContext.createSubcontext(parseName(name));
+        cacheUnload(name.toString());
+        return context;
+    }
+
+
+    /**
+     * Creates and binds a new context.
+     * 
+     * @param name the name of the context to create; may not be empty
+     * @return the newly created context
+     * @exception NameAlreadyBoundException if name is already bound
+     * @exception InvalidAttributesException if creation of the subcontext 
+     * requires specification of mandatory attributes
+     * @exception NamingException if a naming exception is encountered
+     */
+    public Context createSubcontext(String name)
+        throws NamingException {
+        Context context = dirContext.createSubcontext(parseName(name));
+        cacheUnload(name);
+        return context;
+    }
+
+
+    /**
+     * Retrieves the named object, following links except for the terminal 
+     * atomic component of the name. If the object bound to name is not a 
+     * link, returns the object itself.
+     * 
+     * @param name the name of the object to look up
+     * @return the object bound to name, not following the terminal link 
+     * (if any).
+     * @exception NamingException if a naming exception is encountered
+     */
+    public Object lookupLink(Name name)
+        throws NamingException {
+        return dirContext.lookupLink(parseName(name));
+    }
+
+
+    /**
+     * Retrieves the named object, following links except for the terminal 
+     * atomic component of the name.
+     * 
+     * @param name the name of the object to look up
+     * @return the object bound to name, not following the terminal link 
+     * (if any).
+     * @exception NamingException if a naming exception is encountered
+     */
+    public Object lookupLink(String name)
+        throws NamingException {
+        return dirContext.lookupLink(parseName(name));
+    }
+
+
+    /**
+     * Retrieves the parser associated with the named context. In a 
+     * federation of namespaces, different naming systems will parse names 
+     * differently. This method allows an application to get a parser for 
+     * parsing names into their atomic components using the naming convention 
+     * of a particular naming system. Within any single naming system, 
+     * NameParser objects returned by this method must be equal (using the 
+     * equals() test).
+     * 
+     * @param name the name of the context from which to get the parser
+     * @return a name parser that can parse compound names into their atomic 
+     * components
+     * @exception NamingException if a naming exception is encountered
+     */
+    public NameParser getNameParser(Name name)
+        throws NamingException {
+        return dirContext.getNameParser(parseName(name));
+    }
+
+
+    /**
+     * Retrieves the parser associated with the named context.
+     * 
+     * @param name the name of the context from which to get the parser
+     * @return a name parser that can parse compound names into their atomic 
+     * components
+     * @exception NamingException if a naming exception is encountered
+     */
+    public NameParser getNameParser(String name)
+        throws NamingException {
+        return dirContext.getNameParser(parseName(name));
+    }
+
+
+    /**
+     * Composes the name of this context with a name relative to this context.
+     * <p>
+     * Given a name (name) relative to this context, and the name (prefix) 
+     * of this context relative to one of its ancestors, this method returns 
+     * the composition of the two names using the syntax appropriate for the 
+     * naming system(s) involved. That is, if name names an object relative 
+     * to this context, the result is the name of the same object, but 
+     * relative to the ancestor context. None of the names may be null.
+     * 
+     * @param name a name relative to this context
+     * @param prefix the name of this context relative to one of its ancestors
+     * @return the composition of prefix and name
+     * @exception NamingException if a naming exception is encountered
+     */
+    public Name composeName(Name name, Name prefix)
+        throws NamingException {
+        prefix = (Name) prefix.clone();
+        return prefix.addAll(name);
+    }
+
+
+    /**
+     * Composes the name of this context with a name relative to this context.
+     * 
+     * @param name a name relative to this context
+     * @param prefix the name of this context relative to one of its ancestors
+     * @return the composition of prefix and name
+     * @exception NamingException if a naming exception is encountered
+     */
+    public String composeName(String name, String prefix)
+        throws NamingException {
+        return prefix + "/" + name;
+    }
+
+
+    /**
+     * Adds a new environment property to the environment of this context. If 
+     * the property already exists, its value is overwritten.
+     * 
+     * @param propName the name of the environment property to add; may not 
+     * be null
+     * @param propVal the value of the property to add; may not be null
+     * @exception NamingException if a naming exception is encountered
+     */
+    public Object addToEnvironment(String propName, Object propVal)
+        throws NamingException {
+        return dirContext.addToEnvironment(propName, propVal);
+    }
+
+
+    /**
+     * Removes an environment property from the environment of this context. 
+     * 
+     * @param propName the name of the environment property to remove; 
+     * may not be null
+     * @exception NamingException if a naming exception is encountered
+     */
+    public Object removeFromEnvironment(String propName)
+        throws NamingException {
+        return dirContext.removeFromEnvironment(propName);
+    }
+
+
+    /**
+     * Retrieves the environment in effect for this context. See class 
+     * description for more details on environment properties. 
+     * The caller should not make any changes to the object returned: their 
+     * effect on the context is undefined. The environment of this context 
+     * may be changed using addToEnvironment() and removeFromEnvironment().
+     * 
+     * @return the environment of this context; never null
+     * @exception NamingException if a naming exception is encountered
+     */
+    public Hashtable getEnvironment()
+        throws NamingException {
+        return dirContext.getEnvironment();
+    }
+
+
+    /**
+     * Closes this context. This method releases this context's resources 
+     * immediately, instead of waiting for them to be released automatically 
+     * by the garbage collector.
+     * This method is idempotent: invoking it on a context that has already 
+     * been closed has no effect. Invoking any other method on a closed 
+     * context is not allowed, and results in undefined behaviour.
+     * 
+     * @exception NamingException if a naming exception is encountered
+     */
+    public void close()
+        throws NamingException {
+        dirContext.close();
+    }
+
+
+    /**
+     * Retrieves the full name of this context within its own namespace.
+     * <p>
+     * Many naming services have a notion of a "full name" for objects in 
+     * their respective namespaces. For example, an LDAP entry has a 
+     * distinguished name, and a DNS record has a fully qualified name. This 
+     * method allows the client application to retrieve this name. The string 
+     * returned by this method is not a JNDI composite name and should not be 
+     * passed directly to context methods. In naming systems for which the 
+     * notion of full name does not make sense, 
+     * OperationNotSupportedException is thrown.
+     * 
+     * @return this context's name in its own namespace; never null
+     * @exception OperationNotSupportedException if the naming system does 
+     * not have the notion of a full name
+     * @exception NamingException if a naming exception is encountered
+     */
+    public String getNameInNamespace()
+        throws NamingException {
+        return dirContext.getNameInNamespace();
+    }
+
+
+    // ----------------------------------------------------- DirContext Methods
+
+
+    /**
+     * Retrieves all of the attributes associated with a named object. 
+     * 
+     * @return the set of attributes associated with name. 
+     * Returns an empty attribute set if name has no attributes; never null.
+     * @param name the name of the object from which to retrieve attributes
+     * @exception NamingException if a naming exception is encountered
+     */
+    public Attributes getAttributes(Name name)
+        throws NamingException {
+        CacheEntry entry = cacheLookup(name.toString());
+        if (entry != null) {
+            if (!entry.exists) {
+                throw notFoundException;
+            }
+            return entry.attributes;
+        }
+        Attributes attributes = dirContext.getAttributes(parseName(name));
+        if (!(attributes instanceof ResourceAttributes)) {
+            attributes = new ResourceAttributes(attributes);
+        }
+        return attributes;
+    }
+
+
+    /**
+     * Retrieves all of the attributes associated with a named object.
+     * 
+     * @return the set of attributes associated with name
+     * @param name the name of the object from which to retrieve attributes
+     * @exception NamingException if a naming exception is encountered
+     */
+    public Attributes getAttributes(String name)
+        throws NamingException {
+        CacheEntry entry = cacheLookup(name);
+        if (entry != null) {
+            if (!entry.exists) {
+                throw notFoundException;
+            }
+            return entry.attributes;
+        }
+        Attributes attributes = dirContext.getAttributes(parseName(name));
+        if (!(attributes instanceof ResourceAttributes)) {
+            attributes = new ResourceAttributes(attributes);
+        }
+        return attributes;
+    }
+
+
+    /**
+     * Retrieves selected attributes associated with a named object. 
+     * See the class description regarding attribute models, attribute type 
+     * names, and operational attributes.
+     * 
+     * @return the requested attributes; never null
+     * @param name the name of the object from which to retrieve attributes
+     * @param attrIds the identifiers of the attributes to retrieve. null 
+     * indicates that all attributes should be retrieved; an empty array 
+     * indicates that none should be retrieved
+     * @exception NamingException if a naming exception is encountered
+     */
+    public Attributes getAttributes(Name name, String[] attrIds)
+        throws NamingException {
+        Attributes attributes = 
+            dirContext.getAttributes(parseName(name), attrIds);
+        if (!(attributes instanceof ResourceAttributes)) {
+            attributes = new ResourceAttributes(attributes);
+        }
+        return attributes;
+    }
+
+
+    /**
+     * Retrieves selected attributes associated with a named object.
+     * 
+     * @return the requested attributes; never null
+     * @param name the name of the object from which to retrieve attributes
+     * @param attrIds the identifiers of the attributes to retrieve. null 
+     * indicates that all attributes should be retrieved; an empty array 
+     * indicates that none should be retrieved
+     * @exception NamingException if a naming exception is encountered
+     */
+     public Attributes getAttributes(String name, String[] attrIds)
+         throws NamingException {
+        Attributes attributes = 
+            dirContext.getAttributes(parseName(name), attrIds);
+        if (!(attributes instanceof ResourceAttributes)) {
+            attributes = new ResourceAttributes(attributes);
+        }
+        return attributes;
+     }
+
+
+    /**
+     * Modifies the attributes associated with a named object. The order of 
+     * the modifications is not specified. Where possible, the modifications 
+     * are performed atomically.
+     * 
+     * @param name the name of the object whose attributes will be updated
+     * @param mod_op the modification operation, one of: ADD_ATTRIBUTE, 
+     * REPLACE_ATTRIBUTE, REMOVE_ATTRIBUTE
+     * @param attrs the attributes to be used for the modification; may not 
+     * be null
+     * @exception AttributeModificationException if the modification cannot be
+     * completed successfully
+     * @exception NamingException if a naming exception is encountered
+     */
+    public void modifyAttributes(Name name, int mod_op, Attributes attrs)
+        throws NamingException {
+        dirContext.modifyAttributes(parseName(name), mod_op, attrs);
+        cacheUnload(name.toString());
+    }
+
+
+    /**
+     * Modifies the attributes associated with a named object.
+     * 
+     * @param name the name of the object whose attributes will be updated
+     * @param mod_op the modification operation, one of: ADD_ATTRIBUTE, 
+     * REPLACE_ATTRIBUTE, REMOVE_ATTRIBUTE
+     * @param attrs the attributes to be used for the modification; may not 
+     * be null
+     * @exception AttributeModificationException if the modification cannot be
+     * completed successfully
+     * @exception NamingException if a naming exception is encountered
+     */
+    public void modifyAttributes(String name, int mod_op, Attributes attrs)
+        throws NamingException {
+        dirContext.modifyAttributes(parseName(name), mod_op, attrs);
+        cacheUnload(name);
+    }
+
+
+    /**
+     * Modifies the attributes associated with a named object using an an 
+     * ordered list of modifications. The modifications are performed in the 
+     * order specified. Each modification specifies a modification operation 
+     * code and an attribute on which to operate. Where possible, the 
+     * modifications are performed atomically.
+     * 
+     * @param name the name of the object whose attributes will be updated
+     * @param mods an ordered sequence of modifications to be performed; may 
+     * not be null
+     * @exception AttributeModificationException if the modification cannot be
+     * completed successfully
+     * @exception NamingException if a naming exception is encountered
+     */
+    public void modifyAttributes(Name name, ModificationItem[] mods)
+        throws NamingException {
+        dirContext.modifyAttributes(parseName(name), mods);
+        cacheUnload(name.toString());
+    }
+
+
+    /**
+     * Modifies the attributes associated with a named object using an an 
+     * ordered list of modifications.
+     * 
+     * @param name the name of the object whose attributes will be updated
+     * @param mods an ordered sequence of modifications to be performed; may 
+     * not be null
+     * @exception AttributeModificationException if the modification cannot be
+     * completed successfully
+     * @exception NamingException if a naming exception is encountered
+     */
+    public void modifyAttributes(String name, ModificationItem[] mods)
+        throws NamingException {
+        dirContext.modifyAttributes(parseName(name), mods);
+        cacheUnload(name);
+    }
+
+
+    /**
+     * Binds a name to an object, along with associated attributes. If attrs 
+     * is null, the resulting binding will have the attributes associated 
+     * with obj if obj is a DirContext, and no attributes otherwise. If attrs 
+     * is non-null, the resulting binding will have attrs as its attributes; 
+     * any attributes associated with obj are ignored.
+     * 
+     * @param name the name to bind; may not be empty
+     * @param obj the object to bind; possibly null
+     * @param attrs the attributes to associate with the binding
+     * @exception NameAlreadyBoundException if name is already bound
+     * @exception InvalidAttributesException if some "mandatory" attributes 
+     * of the binding are not supplied
+     * @exception NamingException if a naming exception is encountered
+     */
+    public void bind(Name name, Object obj, Attributes attrs)
+        throws NamingException {
+        dirContext.bind(parseName(name), obj, attrs);
+        cacheUnload(name.toString());
+    }
+
+
+    /**
+     * Binds a name to an object, along with associated attributes.
+     * 
+     * @param name the name to bind; may not be empty
+     * @param obj the object to bind; possibly null
+     * @param attrs the attributes to associate with the binding
+     * @exception NameAlreadyBoundException if name is already bound
+     * @exception InvalidAttributesException if some "mandatory" attributes 
+     * of the binding are not supplied
+     * @exception NamingException if a naming exception is encountered
+     */
+    public void bind(String name, Object obj, Attributes attrs)
+        throws NamingException {
+        dirContext.bind(parseName(name), obj, attrs);
+        cacheUnload(name);
+    }
+
+
+    /**
+     * Binds a name to an object, along with associated attributes, 
+     * overwriting any existing binding. If attrs is null and obj is a 
+     * DirContext, the attributes from obj are used. If attrs is null and obj 
+     * is not a DirContext, any existing attributes associated with the object
+     * already bound in the directory remain unchanged. If attrs is non-null, 
+     * any existing attributes associated with the object already bound in 
+     * the directory are removed and attrs is associated with the named 
+     * object. If obj is a DirContext and attrs is non-null, the attributes 
+     * of obj are ignored.
+     * 
+     * @param name the name to bind; may not be empty
+     * @param obj the object to bind; possibly null
+     * @param attrs the attributes to associate with the binding
+     * @exception InvalidAttributesException if some "mandatory" attributes 
+     * of the binding are not supplied
+     * @exception NamingException if a naming exception is encountered
+     */
+    public void rebind(Name name, Object obj, Attributes attrs)
+        throws NamingException {
+        dirContext.rebind(parseName(name), obj, attrs);
+        cacheUnload(name.toString());
+    }
+
+
+    /**
+     * Binds a name to an object, along with associated attributes, 
+     * overwriting any existing binding.
+     * 
+     * @param name the name to bind; may not be empty
+     * @param obj the object to bind; possibly null
+     * @param attrs the attributes to associate with the binding
+     * @exception InvalidAttributesException if some "mandatory" attributes 
+     * of the binding are not supplied
+     * @exception NamingException if a naming exception is encountered
+     */
+    public void rebind(String name, Object obj, Attributes attrs)
+        throws NamingException {
+        dirContext.rebind(parseName(name), obj, attrs);
+        cacheUnload(name);
+    }
+
+
+    /**
+     * Creates and binds a new context, along with associated attributes. 
+     * This method creates a new subcontext with the given name, binds it in 
+     * the target context (that named by all but terminal atomic component of 
+     * the name), and associates the supplied attributes with the newly 
+     * created object. All intermediate and target contexts must already 
+     * exist. If attrs is null, this method is equivalent to 
+     * Context.createSubcontext().
+     * 
+     * @param name the name of the context to create; may not be empty
+     * @param attrs the attributes to associate with the newly created context
+     * @return the newly created context
+     * @exception NameAlreadyBoundException if the name is already bound
+     * @exception InvalidAttributesException if attrs does not contain all 
+     * the mandatory attributes required for creation
+     * @exception NamingException if a naming exception is encountered
+     */
+    public DirContext createSubcontext(Name name, Attributes attrs)
+        throws NamingException {
+        DirContext context = 
+            dirContext.createSubcontext(parseName(name), attrs);
+        cacheUnload(name.toString());
+        return context;
+    }
+
+
+    /**
+     * Creates and binds a new context, along with associated attributes.
+     * 
+     * @param name the name of the context to create; may not be empty
+     * @param attrs the attributes to associate with the newly created context
+     * @return the newly created context
+     * @exception NameAlreadyBoundException if the name is already bound
+     * @exception InvalidAttributesException if attrs does not contain all 
+     * the mandatory attributes required for creation
+     * @exception NamingException if a naming exception is encountered
+     */
+    public DirContext createSubcontext(String name, Attributes attrs)
+        throws NamingException {
+        DirContext context = 
+            dirContext.createSubcontext(parseName(name), attrs);
+        cacheUnload(name);
+        return context;
+    }
+
+
+    /**
+     * Retrieves the schema associated with the named object. The schema 
+     * describes rules regarding the structure of the namespace and the 
+     * attributes stored within it. The schema specifies what types of 
+     * objects can be added to the directory and where they can be added; 
+     * what mandatory and optional attributes an object can have. The range 
+     * of support for schemas is directory-specific.
+     * 
+     * @param name the name of the object whose schema is to be retrieved
+     * @return the schema associated with the context; never null
+     * @exception OperationNotSupportedException if schema not supported
+     * @exception NamingException if a naming exception is encountered
+     */
+    public DirContext getSchema(Name name)
+        throws NamingException {
+        return dirContext.getSchema(parseName(name));
+    }
+
+
+    /**
+     * Retrieves the schema associated with the named object.
+     * 
+     * @param name the name of the object whose schema is to be retrieved
+     * @return the schema associated with the context; never null
+     * @exception OperationNotSupportedException if schema not supported
+     * @exception NamingException if a naming exception is encountered
+     */
+    public DirContext getSchema(String name)
+        throws NamingException {
+        return dirContext.getSchema(parseName(name));
+    }
+
+
+    /**
+     * Retrieves a context containing the schema objects of the named 
+     * object's class definitions.
+     * 
+     * @param name the name of the object whose object class definition is to 
+     * be retrieved
+     * @return the DirContext containing the named object's class 
+     * definitions; never null
+     * @exception OperationNotSupportedException if schema not supported
+     * @exception NamingException if a naming exception is encountered
+     */
+    public DirContext getSchemaClassDefinition(Name name)
+        throws NamingException {
+        return dirContext.getSchemaClassDefinition(parseName(name));
+    }
+
+
+    /**
+     * Retrieves a context containing the schema objects of the named 
+     * object's class definitions.
+     * 
+     * @param name the name of the object whose object class definition is to 
+     * be retrieved
+     * @return the DirContext containing the named object's class 
+     * definitions; never null
+     * @exception OperationNotSupportedException if schema not supported
+     * @exception NamingException if a naming exception is encountered
+     */
+    public DirContext getSchemaClassDefinition(String name)
+        throws NamingException {
+        return dirContext.getSchemaClassDefinition(parseName(name));
+    }
+
+
+    /**
+     * Searches in a single context for objects that contain a specified set 
+     * of attributes, and retrieves selected attributes. The search is 
+     * performed using the default SearchControls settings.
+     * 
+     * @param name the name of the context to search
+     * @param matchingAttributes the attributes to search for. If empty or 
+     * null, all objects in the target context are returned.
+     * @param attributesToReturn the attributes to return. null indicates 
+     * that all attributes are to be returned; an empty array indicates that 
+     * none are to be returned.
+     * @return a non-null enumeration of SearchResult objects. Each 
+     * SearchResult contains the attributes identified by attributesToReturn 
+     * and the name of the corresponding object, named relative to the 
+     * context named by name.
+     * @exception NamingException if a naming exception is encountered
+     */
+    public NamingEnumeration search(Name name, Attributes matchingAttributes,
+                                    String[] attributesToReturn)
+        throws NamingException {
+        return dirContext.search(parseName(name), matchingAttributes, 
+                                 attributesToReturn);
+    }
+
+
+    /**
+     * Searches in a single context for objects that contain a specified set 
+     * of attributes, and retrieves selected attributes.
+     * 
+     * @param name the name of the context to search
+     * @param matchingAttributes the attributes to search for. If empty or 
+     * null, all objects in the target context are returned.
+     * @param attributesToReturn the attributes to return. null indicates 
+     * that all attributes are to be returned; an empty array indicates that 
+     * none are to be returned.
+     * @return a non-null enumeration of SearchResult objects. Each 
+     * SearchResult contains the attributes identified by attributesToReturn 
+     * and the name of the corresponding object, named relative to the 
+     * context named by name.
+     * @exception NamingException if a naming exception is encountered
+     */
+    public NamingEnumeration search(String name, Attributes matchingAttributes,
+                                    String[] attributesToReturn)
+        throws NamingException {
+        return dirContext.search(parseName(name), matchingAttributes, 
+                                 attributesToReturn);
+    }
+
+
+    /**
+     * Searches in a single context for objects that contain a specified set 
+     * of attributes. This method returns all the attributes of such objects. 
+     * It is equivalent to supplying null as the atributesToReturn parameter 
+     * to the method search(Name, Attributes, String[]).
+     * 
+     * @param name the name of the context to search
+     * @param matchingAttributes the attributes to search for. If empty or 
+     * null, all objects in the target context are returned.
+     * @return a non-null enumeration of SearchResult objects. Each 
+     * SearchResult contains the attributes identified by attributesToReturn 
+     * and the name of the corresponding object, named relative to the 
+     * context named by name.
+     * @exception NamingException if a naming exception is encountered
+     */
+    public NamingEnumeration search(Name name, Attributes matchingAttributes)
+        throws NamingException {
+        return dirContext.search(parseName(name), matchingAttributes);
+    }
+
+
+    /**
+     * Searches in a single context for objects that contain a specified set 
+     * of attributes.
+     * 
+     * @param name the name of the context to search
+     * @param matchingAttributes the attributes to search for. If empty or 
+     * null, all objects in the target context are returned.
+     * @return a non-null enumeration of SearchResult objects. Each 
+     * SearchResult contains the attributes identified by attributesToReturn 
+     * and the name of the corresponding object, named relative to the 
+     * context named by name.
+     * @exception NamingException if a naming exception is encountered
+     */
+    public NamingEnumeration search(String name, Attributes matchingAttributes)
+        throws NamingException {
+        return dirContext.search(parseName(name), matchingAttributes);
+    }
+
+
+    /**
+     * Searches in the named context or object for entries that satisfy the 
+     * given search filter. Performs the search as specified by the search 
+     * controls.
+     * 
+     * @param name the name of the context or object to search
+     * @param filter the filter expression to use for the search; may not be 
+     * null
+     * @param cons the search controls that control the search. If null, 
+     * the default search controls are used (equivalent to 
+     * (new SearchControls())).
+     * @return an enumeration of SearchResults of the objects that satisfy 
+     * the filter; never null
+     * @exception InvalidSearchFilterException if the search filter specified 
+     * is not supported or understood by the underlying directory
+     * @exception InvalidSearchControlsException if the search controls 
+     * contain invalid settings
+     * @exception NamingException if a naming exception is encountered
+     */
+    public NamingEnumeration search(Name name, String filter, 
+                                    SearchControls cons)
+        throws NamingException {
+        return dirContext.search(parseName(name), filter, cons);
+    }
+
+
+    /**
+     * Searches in the named context or object for entries that satisfy the 
+     * given search filter. Performs the search as specified by the search 
+     * controls.
+     * 
+     * @param name the name of the context or object to search
+     * @param filter the filter expression to use for the search; may not be 
+     * null
+     * @param cons the search controls that control the search. If null, 
+     * the default search controls are used (equivalent to 
+     * (new SearchControls())).
+     * @return an enumeration of SearchResults of the objects that satisfy 
+     * the filter; never null
+     * @exception InvalidSearchFilterException if the search filter 
+     * specified is not supported or understood by the underlying directory
+     * @exception InvalidSearchControlsException if the search controls 
+     * contain invalid settings
+     * @exception NamingException if a naming exception is encountered
+     */
+    public NamingEnumeration search(String name, String filter, 
+                                    SearchControls cons)
+        throws NamingException {
+        return dirContext.search(parseName(name), filter, cons);
+    }
+
+
+    /**
+     * Searches in the named context or object for entries that satisfy the 
+     * given search filter. Performs the search as specified by the search 
+     * controls.
+     * 
+     * @param name the name of the context or object to search
+     * @param filterExpr the filter expression to use for the search. 
+     * The expression may contain variables of the form "{i}" where i is a 
+     * nonnegative integer. May not be null.
+     * @param filterArgs the array of arguments to substitute for the 
+     * variables in filterExpr. The value of filterArgs[i] will replace each 
+     * occurrence of "{i}". If null, equivalent to an empty array.
+     * @param cons the search controls that control the search. If null, the 
+     * default search controls are used (equivalent to (new SearchControls())).
+     * @return an enumeration of SearchResults of the objects that satisy the 
+     * filter; never null
+     * @exception ArrayIndexOutOfBoundsException if filterExpr contains {i} 
+     * expressions where i is outside the bounds of the array filterArgs
+     * @exception InvalidSearchControlsException if cons contains invalid 
+     * settings
+     * @exception InvalidSearchFilterException if filterExpr with filterArgs 
+     * represents an invalid search filter
+     * @exception NamingException if a naming exception is encountered
+     */
+    public NamingEnumeration search(Name name, String filterExpr,
+                                    Object[] filterArgs, SearchControls cons)
+        throws NamingException {
+        return dirContext.search(parseName(name), filterExpr, filterArgs, 
+                                 cons);
+    }
+
+
+    /**
+     * Searches in the named context or object for entries that satisfy the 
+     * given search filter. Performs the search as specified by the search 
+     * controls.
+     * 
+     * @param name the name of the context or object to search
+     * @param filterExpr the filter expression to use for the search. 
+     * The expression may contain variables of the form "{i}" where i is a 
+     * nonnegative integer. May not be null.
+     * @param filterArgs the array of arguments to substitute for the 
+     * variables in filterExpr. The value of filterArgs[i] will replace each 
+     * occurrence of "{i}". If null, equivalent to an empty array.
+     * @param cons the search controls that control the search. If null, the 
+     * default search controls are used (equivalent to (new SearchControls())).
+     * @return an enumeration of SearchResults of the objects that satisy the 
+     * filter; never null
+     * @exception ArrayIndexOutOfBoundsException if filterExpr contains {i} 
+     * expressions where i is outside the bounds of the array filterArgs
+     * @exception InvalidSearchControlsException if cons contains invalid 
+     * settings
+     * @exception InvalidSearchFilterException if filterExpr with filterArgs 
+     * represents an invalid search filter
+     * @exception NamingException if a naming exception is encountered
+     */
+    public NamingEnumeration search(String name, String filterExpr,
+                                    Object[] filterArgs, SearchControls cons)
+        throws NamingException {
+        return dirContext.search(parseName(name), filterExpr, filterArgs, 
+                                 cons);
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Retrieves the named object as a cache entry, without any exception.
+     * 
+     * @param name the name of the object to look up
+     * @return the cache entry bound to name
+     */
+    public CacheEntry lookupCache(String name) {
+        CacheEntry entry = cacheLookup(name);
+        if (entry == null) {
+            entry = new CacheEntry();
+            entry.name = name;
+            try {
+                Object object = dirContext.lookup(parseName(name));
+                if (object instanceof InputStream) {
+                    entry.resource = new Resource((InputStream) object);
+                } else if (object instanceof DirContext) {
+                    entry.context = (DirContext) object;
+                } else if (object instanceof Resource) {
+                    entry.resource = (Resource) object;
+                } else {
+                    entry.resource = new Resource(new ByteArrayInputStream
+                        (object.toString().getBytes()));
+                }
+                Attributes attributes = dirContext.getAttributes(parseName(name));
+                if (!(attributes instanceof ResourceAttributes)) {
+                    attributes = new ResourceAttributes(attributes);
+                }
+                entry.attributes = (ResourceAttributes) attributes;
+            } catch (NamingException e) {
+                entry.exists = false;
+            }
+        }
+        return entry;
+    }
+
+
+    // ------------------------------------------------------ Protected Methods
+
+
+    /**
+     * Parses a name.
+     * 
+     * @return the parsed name
+     */
+    protected String parseName(String name) 
+        throws NamingException {
+        return name;
+    }
+
+
+    /**
+     * Parses a name.
+     * 
+     * @return the parsed name
+     */
+    protected Name parseName(Name name) 
+        throws NamingException {
+        return name;
+    }
+
+
+    /**
+     * Lookup in cache.
+     */
+    protected CacheEntry cacheLookup(String name) {
+        if (cache == null)
+            return (null);
+        if (name == null)
+            name = "";
+        for (int i = 0; i < nonCacheable.length; i++) {
+            if (name.startsWith(nonCacheable[i])) {
+                return (null);
+            }
+        }
+        CacheEntry cacheEntry = cache.lookup(name);
+        if (cacheEntry == null) {
+            cacheEntry = new CacheEntry();
+            cacheEntry.name = name;
+            // Load entry
+            cacheLoad(cacheEntry);
+        } else {
+            if (!validate(cacheEntry)) {
+                if (!revalidate(cacheEntry)) {
+                    cacheUnload(cacheEntry.name);
+                    return (null);
+                } else {
+                    cacheEntry.timestamp = 
+                        System.currentTimeMillis() + cacheTTL;
+                }
+            }
+            cacheEntry.accessCount++;
+        }
+        return (cacheEntry);
+    }
+
+
+    /**
+     * Validate entry.
+     */
+    protected boolean validate(CacheEntry entry) {
+        if (((!entry.exists)
+             || (entry.context != null)
+             || ((entry.resource != null) 
+                 && (entry.resource.getContent() != null)))
+            && (System.currentTimeMillis() < entry.timestamp)) {
+            return true;
+        }
+        return false;
+    }
+
+
+    /**
+     * Revalidate entry.
+     */
+    protected boolean revalidate(CacheEntry entry) {
+        // Get the attributes at the given path, and check the last 
+        // modification date
+        if (!entry.exists)
+            return false;
+        if (entry.attributes == null)
+            return false;
+        long lastModified = entry.attributes.getLastModified();
+        long contentLength = entry.attributes.getContentLength();
+        if (lastModified <= 0)
+            return false;
+        try {
+            Attributes tempAttributes = dirContext.getAttributes(entry.name);
+            ResourceAttributes attributes = null;
+            if (!(tempAttributes instanceof ResourceAttributes)) {
+                attributes = new ResourceAttributes(tempAttributes);
+            } else {
+                attributes = (ResourceAttributes) tempAttributes;
+            }
+            long lastModified2 = attributes.getLastModified();
+            long contentLength2 = attributes.getContentLength();
+            return (lastModified == lastModified2) 
+                && (contentLength == contentLength2);
+        } catch (NamingException e) {
+            return false;
+        }
+    }
+
+
+    /**
+     * Load entry into cache.
+     */
+    protected void cacheLoad(CacheEntry entry) {
+
+        String name = entry.name;
+
+        // Retrieve missing info
+        boolean exists = true;
+
+        // Retrieving attributes
+        if (entry.attributes == null) {
+            try {
+                Attributes attributes = dirContext.getAttributes(entry.name);
+                if (!(attributes instanceof ResourceAttributes)) {
+                    entry.attributes = 
+                        new ResourceAttributes(attributes);
+                } else {
+                    entry.attributes = (ResourceAttributes) attributes;
+                }
+            } catch (NamingException e) {
+                exists = false;
+            }
+        }
+
+        // Retriving object
+        if ((exists) && (entry.resource == null) && (entry.context == null)) {
+            try {
+                Object object = dirContext.lookup(name);
+                if (object instanceof InputStream) {
+                    entry.resource = new Resource((InputStream) object);
+                } else if (object instanceof DirContext) {
+                    entry.context = (DirContext) object;
+                } else if (object instanceof Resource) {
+                    entry.resource = (Resource) object;
+                } else {
+                    entry.resource = new Resource(new ByteArrayInputStream
+                        (object.toString().getBytes()));
+                }
+            } catch (NamingException e) {
+                exists = false;
+            }
+        }
+
+        // Load object content
+        if ((exists) && (entry.resource != null) 
+            && (entry.resource.getContent() == null) 
+            && (entry.attributes.getContentLength() >= 0)
+            && (entry.attributes.getContentLength() < 
+                (cacheObjectMaxSize * 1024))) {
+            int length = (int) entry.attributes.getContentLength();
+            // The entry size is 1 + the resource size in KB, if it will be 
+            // cached
+            entry.size += (entry.attributes.getContentLength() / 1024);
+            InputStream is = null;
+            try {
+                is = entry.resource.streamContent();
+                int pos = 0;
+                byte[] b = new byte[length];
+                while (pos < length) {
+                    int n = is.read(b, pos, length - pos);
+                    if (n < 0)
+                        break;
+                    pos = pos + n;
+                }
+                entry.resource.setContent(b);
+            } catch (IOException e) {
+                ; // Ignore
+            } finally {
+                try {
+                    if (is != null)
+                        is.close();
+                } catch (IOException e) {
+                    ; // Ignore
+                }
+            }
+        }
+
+        // Set existence flag
+        entry.exists = exists;
+
+        // Set timestamp
+        entry.timestamp = System.currentTimeMillis() + cacheTTL;
+
+        // Add new entry to cache
+        synchronized (cache) {
+            // Check cache size, and remove elements if too big
+            if ((cache.lookup(name) == null) && cache.allocate(entry.size)) {
+                cache.load(entry);
+            }
+        }
+
+    }
+
+
+    /**
+     * Remove entry from cache.
+     */
+    protected boolean cacheUnload(String name) {
+        if (cache == null)
+            return false;
+        synchronized (cache) {
+            return cache.unload(name);
+        }
+    }
+
+
+}
+

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/resources/RecyclableNamingEnumeration.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/resources/RecyclableNamingEnumeration.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/resources/RecyclableNamingEnumeration.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,112 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.naming.resources;
+
+import java.util.Enumeration;
+import java.util.Vector;
+
+import javax.naming.NamingEnumeration;
+import javax.naming.NamingException;
+
+/**
+ * Naming enumeration implementation.
+ *
+ * @author Remy Maucherat
+ * @version $Revision: 303022 $ $Date: 2004-07-23 17:46:08 -0500 (Fri, 23 Jul 2004) $
+ */
+
+public class RecyclableNamingEnumeration 
+    implements NamingEnumeration {
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    public RecyclableNamingEnumeration(Vector entries) {
+        this.entries = entries;
+        recycle();
+    }
+
+
+    // -------------------------------------------------------------- Variables
+
+
+    /**
+     * Entries.
+     */
+    protected Vector entries;
+
+
+    /**
+     * Underlying enumeration.
+     */
+    protected Enumeration enumeration;
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Retrieves the next element in the enumeration.
+     */
+    public Object next()
+        throws NamingException {
+        return nextElement();
+    }
+
+
+    /**
+     * Determines whether there are any more elements in the enumeration.
+     */
+    public boolean hasMore()
+        throws NamingException {
+        return enumeration.hasMoreElements();
+    }
+
+
+    /**
+     * Closes this enumeration.
+     */
+    public void close()
+        throws NamingException {
+    }
+
+
+    public boolean hasMoreElements() {
+        return enumeration.hasMoreElements();
+    }
+
+
+    public Object nextElement() {
+        return enumeration.nextElement();
+    }
+
+
+    // -------------------------------------------------------- Package Methods
+
+
+    /**
+     * Recycle.
+     */
+    void recycle() {
+    	enumeration = entries.elements();
+    }
+
+
+}
+

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/resources/Resource.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/resources/Resource.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/resources/Resource.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,111 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.naming.resources;
+
+import java.io.InputStream;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+
+/**
+ * Encapsultes the contents of a resource.
+ * 
+ * @author <a href="mailto:remm at apache.org">Remy Maucherat</a>
+ * @version $Revision: 302726 $
+ */
+public class Resource {
+    
+    
+    // ----------------------------------------------------------- Constructors
+    
+    
+    public Resource() {
+    }
+    
+    
+    public Resource(InputStream inputStream) {
+        setContent(inputStream);
+    }
+    
+    
+    public Resource(byte[] binaryContent) {
+        setContent(binaryContent);
+    }
+    
+    
+    // ----------------------------------------------------- Instance Variables
+    
+    
+    /**
+     * Binary content.
+     */
+    protected byte[] binaryContent = null;
+    
+    
+    /**
+     * Input stream.
+     */
+    protected InputStream inputStream = null;
+    
+    
+    // ------------------------------------------------------------- Properties
+    
+    
+    /**
+     * Content accessor.
+     * 
+     * @return InputStream
+     */
+    public InputStream streamContent()
+        throws IOException {
+        if (binaryContent != null) {
+            return new ByteArrayInputStream(binaryContent);
+        }
+        return inputStream;
+    }
+    
+    
+    /**
+     * Content accessor.
+     * 
+     * @return binary content
+     */
+    public byte[] getContent() {
+        return binaryContent;
+    }
+    
+    
+    /**
+     * Content mutator.
+     * 
+     * @param inputStream New input stream
+     */
+    public void setContent(InputStream inputStream) {
+        this.inputStream = inputStream;
+    }
+    
+    
+    /**
+     * Content mutator.
+     * 
+     * @param binaryContent New bin content
+     */
+    public void setContent(byte[] binaryContent) {
+        this.binaryContent = binaryContent;
+    }
+    
+    
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/resources/ResourceAttributes.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/resources/ResourceAttributes.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/resources/ResourceAttributes.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,915 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.naming.resources;
+
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Locale;
+import java.util.TimeZone;
+import java.util.Vector;
+
+import javax.naming.NamingEnumeration;
+import javax.naming.NamingException;
+import javax.naming.directory.Attribute;
+import javax.naming.directory.Attributes;
+import javax.naming.directory.BasicAttribute;
+
+/**
+ * Attributes implementation.
+ * 
+ * @author <a href="mailto:remm at apache.org">Remy Maucherat</a>
+ * @version $Revision: 303877 $
+ */
+public class ResourceAttributes implements Attributes {
+    
+    
+    // -------------------------------------------------------------- Constants
+    
+    
+    // Default attribute names
+    
+    /**
+     * Creation date.
+     */
+    public static final String CREATION_DATE = "creationdate";
+    
+    
+    /**
+     * Creation date.
+     */
+    public static final String ALTERNATE_CREATION_DATE = "creation-date";
+    
+    
+    /**
+     * Last modification date.
+     */
+    public static final String LAST_MODIFIED = "getlastmodified";
+    
+    
+    /**
+     * Last modification date.
+     */
+    public static final String ALTERNATE_LAST_MODIFIED = "last-modified";
+    
+    
+    /**
+     * Name.
+     */
+    public static final String NAME = "displayname";
+    
+    
+    /**
+     * Type.
+     */
+    public static final String TYPE = "resourcetype";
+    
+    
+    /**
+     * Type.
+     */
+    public static final String ALTERNATE_TYPE = "content-type";
+    
+    
+    /**
+     * Source.
+     */
+    public static final String SOURCE = "source";
+    
+    
+    /**
+     * MIME type of the content.
+     */
+    public static final String CONTENT_TYPE = "getcontenttype";
+    
+    
+    /**
+     * Content language.
+     */
+    public static final String CONTENT_LANGUAGE = "getcontentlanguage";
+    
+    
+    /**
+     * Content length.
+     */
+    public static final String CONTENT_LENGTH = "getcontentlength";
+    
+    
+    /**
+     * Content length.
+     */
+    public static final String ALTERNATE_CONTENT_LENGTH = "content-length";
+    
+    
+    /**
+     * ETag.
+     */
+    public static final String ETAG = "getetag";
+    
+    
+    /**
+     * Collection type.
+     */
+    public static final String COLLECTION_TYPE = "<collection/>";
+    
+    
+    /**
+     * HTTP date format.
+     */
+    protected static final SimpleDateFormat format =
+        new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US);
+    
+    
+    /**
+     * Date formats using for Date parsing.
+     */
+    protected static final SimpleDateFormat formats[] = {
+        new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US),
+        new SimpleDateFormat("EEEEEE, dd-MMM-yy HH:mm:ss zzz", Locale.US),
+        new SimpleDateFormat("EEE MMMM d HH:mm:ss yyyy", Locale.US)
+    };
+    
+    
+    protected final static TimeZone gmtZone = TimeZone.getTimeZone("GMT");
+
+
+    /**
+     * GMT timezone - all HTTP dates are on GMT
+     */
+    static {
+
+        format.setTimeZone(gmtZone);
+
+        formats[0].setTimeZone(gmtZone);
+        formats[1].setTimeZone(gmtZone);
+        formats[2].setTimeZone(gmtZone);
+
+    }
+
+
+    // ----------------------------------------------------------- Constructors
+    
+    
+    /**
+     * Default constructor.
+     */
+    public ResourceAttributes() {
+    }
+    
+    
+    /**
+     * Merges with another attribute set.
+     */
+    public ResourceAttributes(Attributes attributes) {
+        this.attributes = attributes;
+    }
+    
+    
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * Collection flag.
+     */
+    protected boolean collection = false;
+
+
+    /**
+     * Content length.
+     */
+    protected long contentLength = -1;
+
+
+    /**
+     * Creation time.
+     */
+    protected long creation = -1;
+
+
+    /**
+     * Creation date.
+     */
+    protected Date creationDate = null;
+
+
+    /**
+     * Last modified time.
+     */
+    protected long lastModified = -1;
+
+
+    /**
+     * Last modified date.
+     */
+    protected Date lastModifiedDate = null;
+
+    
+    /**
+     * Last modified date in HTTP format.
+     */
+    protected String lastModifiedHttp = null;
+    
+
+    /**
+     * MIME type.
+     */
+    protected String mimeType = null;
+    
+
+    /**
+     * Name.
+     */
+    protected String name = null;
+
+
+    /**
+     * Weak ETag.
+     */
+    protected String weakETag = null;
+
+
+    /**
+     * Strong ETag.
+     */
+    protected String strongETag = null;
+
+
+    /**
+     * External attributes.
+     */
+    protected Attributes attributes = null;
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * Is collection.
+     */
+    public boolean isCollection() {
+        if (attributes != null) {
+            return (getResourceType().equals(COLLECTION_TYPE));
+        } else {
+            return (collection);
+        }
+    }
+    
+    
+    /**
+     * Set collection flag.
+     *
+     * @param collection New flag value
+     */
+    public void setCollection(boolean collection) {
+        this.collection = collection;
+        if (attributes != null) {
+            String value = "";
+            if (collection)
+                value = COLLECTION_TYPE;
+            attributes.put(TYPE, value);
+        }
+    }
+    
+    
+    /**
+     * Get content length.
+     * 
+     * @return content length value
+     */
+    public long getContentLength() {
+        if (contentLength != -1L)
+            return contentLength;
+        if (attributes != null) {
+            Attribute attribute = attributes.get(CONTENT_LENGTH);
+            if (attribute != null) {
+                try {
+                    Object value = attribute.get();
+                    if (value instanceof Long) {
+                        contentLength = ((Long) value).longValue();
+                    } else {
+                        try {
+                            contentLength = Long.parseLong(value.toString());
+                        } catch (NumberFormatException e) {
+                            ; // Ignore
+                        }
+                    }
+                } catch (NamingException e) {
+                    ; // No value for the attribute
+                }
+            }
+        }
+        return contentLength;
+    }
+    
+    
+    /**
+     * Set content length.
+     * 
+     * @param contentLength New content length value
+     */
+    public void setContentLength(long contentLength) {
+        this.contentLength = contentLength;
+        if (attributes != null)
+            attributes.put(CONTENT_LENGTH, new Long(contentLength));
+    }
+    
+    
+    /**
+     * Get creation time.
+     * 
+     * @return creation time value
+     */
+    public long getCreation() {
+        if (creation != -1L)
+            return creation;
+        if (creationDate != null)
+            return creationDate.getTime();
+        if (attributes != null) {
+            Attribute attribute = attributes.get(CREATION_DATE);
+            if (attribute != null) {
+                try {
+                    Object value = attribute.get();
+                    if (value instanceof Long) {
+                        creation = ((Long) value).longValue();
+                    } else if (value instanceof Date) {
+                        creation = ((Date) value).getTime();
+                        creationDate = (Date) value;
+                    } else {
+                        String creationDateValue = value.toString();
+                        Date result = null;
+                        // Parsing the HTTP Date
+                        for (int i = 0; (result == null) && 
+                                 (i < formats.length); i++) {
+                            try {
+                                result = formats[i].parse(creationDateValue);
+                            } catch (ParseException e) {
+                                ;
+                            }
+                        }
+                        if (result != null) {
+                            creation = result.getTime();
+                            creationDate = result;
+                        }
+                    }
+                } catch (NamingException e) {
+                    ; // No value for the attribute
+                }
+            }
+        }
+        return creation;
+    }
+    
+    
+    /**
+     * Set creation.
+     * 
+     * @param creation New creation value
+     */
+    public void setCreation(long creation) {
+        this.creation = creation;
+        this.creationDate = null;
+        if (attributes != null)
+            attributes.put(CREATION_DATE, new Date(creation));
+    }
+    
+    
+    /**
+     * Get creation date.
+     * 
+     * @return Creation date value
+     */
+    public Date getCreationDate() {
+        if (creationDate != null)
+            return creationDate;
+        if (creation != -1L) {
+            creationDate = new Date(creation);
+            return creationDate;
+        }
+        if (attributes != null) {
+            Attribute attribute = attributes.get(CREATION_DATE);
+            if (attribute != null) {
+                try {
+                    Object value = attribute.get();
+                    if (value instanceof Long) {
+                        creation = ((Long) value).longValue();
+                        creationDate = new Date(creation);
+                    } else if (value instanceof Date) {
+                        creation = ((Date) value).getTime();
+                        creationDate = (Date) value;
+                    } else {
+                        String creationDateValue = value.toString();
+                        Date result = null;
+                        // Parsing the HTTP Date
+                        for (int i = 0; (result == null) && 
+                                 (i < formats.length); i++) {
+                            try {
+                                result = formats[i].parse(creationDateValue);
+                            } catch (ParseException e) {
+                                ;
+                            }
+                        }
+                        if (result != null) {
+                            creation = result.getTime();
+                            creationDate = result;
+                        }
+                    }
+                } catch (NamingException e) {
+                    ; // No value for the attribute
+                }
+            }
+        }
+        return creationDate;
+    }
+    
+    
+    /**
+     * Creation date mutator.
+     * 
+     * @param creationDate New creation date
+     */
+    public void setCreationDate(Date creationDate) {
+        this.creation = creationDate.getTime();
+        this.creationDate = creationDate;
+        if (attributes != null)
+            attributes.put(CREATION_DATE, creationDate);
+    }
+    
+    
+    /**
+     * Get last modified time.
+     * 
+     * @return lastModified time value
+     */
+    public long getLastModified() {
+        if (lastModified != -1L)
+            return lastModified;
+        if (lastModifiedDate != null)
+            return lastModifiedDate.getTime();
+        if (attributes != null) {
+            Attribute attribute = attributes.get(LAST_MODIFIED);
+            if (attribute != null) {
+                try {
+                    Object value = attribute.get();
+                    if (value instanceof Long) {
+                        lastModified = ((Long) value).longValue();
+                    } else if (value instanceof Date) {
+                        lastModified = ((Date) value).getTime();
+                        lastModifiedDate = (Date) value;
+                    } else {
+                        String lastModifiedDateValue = value.toString();
+                        Date result = null;
+                        // Parsing the HTTP Date
+                        for (int i = 0; (result == null) && 
+                                 (i < formats.length); i++) {
+                            try {
+                                result = 
+                                    formats[i].parse(lastModifiedDateValue);
+                            } catch (ParseException e) {
+                                ;
+                            }
+                        }
+                        if (result != null) {
+                            lastModified = result.getTime();
+                            lastModifiedDate = result;
+                        }
+                    }
+                } catch (NamingException e) {
+                    ; // No value for the attribute
+                }
+            }
+        }
+        return lastModified;
+    }
+    
+    
+    /**
+     * Set last modified.
+     * 
+     * @param lastModified New last modified value
+     */
+    public void setLastModified(long lastModified) {
+        this.lastModified = lastModified;
+        this.lastModifiedDate = null;
+        if (attributes != null)
+            attributes.put(LAST_MODIFIED, new Date(lastModified));
+    }
+    
+    
+    /**
+     * Set last modified date.
+     * 
+     * @param lastModified New last modified date value
+     * @deprecated
+     */
+    public void setLastModified(Date lastModified) {
+        setLastModifiedDate(lastModified);
+    }
+
+
+    /**
+     * Get lastModified date.
+     * 
+     * @return LastModified date value
+     */
+    public Date getLastModifiedDate() {
+        if (lastModifiedDate != null)
+            return lastModifiedDate;
+        if (lastModified != -1L) {
+            lastModifiedDate = new Date(lastModified);
+            return lastModifiedDate;
+        }
+        if (attributes != null) {
+            Attribute attribute = attributes.get(LAST_MODIFIED);
+            if (attribute != null) {
+                try {
+                    Object value = attribute.get();
+                    if (value instanceof Long) {
+                        lastModified = ((Long) value).longValue();
+                        lastModifiedDate = new Date(lastModified);
+                    } else if (value instanceof Date) {
+                        lastModified = ((Date) value).getTime();
+                        lastModifiedDate = (Date) value;
+                    } else {
+                        String lastModifiedDateValue = value.toString();
+                        Date result = null;
+                        // Parsing the HTTP Date
+                        for (int i = 0; (result == null) && 
+                                 (i < formats.length); i++) {
+                            try {
+                                result = 
+                                    formats[i].parse(lastModifiedDateValue);
+                            } catch (ParseException e) {
+                                ;
+                            }
+                        }
+                        if (result != null) {
+                            lastModified = result.getTime();
+                            lastModifiedDate = result;
+                        }
+                    }
+                } catch (NamingException e) {
+                    ; // No value for the attribute
+                }
+            }
+        }
+        return lastModifiedDate;
+    }
+    
+    
+    /**
+     * Last modified date mutator.
+     * 
+     * @param lastModifiedDate New last modified date
+     */
+    public void setLastModifiedDate(Date lastModifiedDate) {
+        this.lastModified = lastModifiedDate.getTime();
+        this.lastModifiedDate = lastModifiedDate;
+        if (attributes != null)
+            attributes.put(LAST_MODIFIED, lastModifiedDate);
+    }
+    
+    
+    /**
+     * @return Returns the lastModifiedHttp.
+     */
+    public String getLastModifiedHttp() {
+        if (lastModifiedHttp != null)
+            return lastModifiedHttp;
+        Date modifiedDate = getLastModifiedDate();
+        if (modifiedDate == null) {
+            modifiedDate = getCreationDate();
+        }
+        if (modifiedDate == null) {
+            modifiedDate = new Date();
+        }
+        synchronized (format) {
+            lastModifiedHttp = format.format(modifiedDate);
+        }
+        return lastModifiedHttp;
+    }
+    
+    
+    /**
+     * @param lastModifiedHttp The lastModifiedHttp to set.
+     */
+    public void setLastModifiedHttp(String lastModifiedHttp) {
+        this.lastModifiedHttp = lastModifiedHttp;
+    }
+    
+    
+    /**
+     * @return Returns the mimeType.
+     */
+    public String getMimeType() {
+        return mimeType;
+    }
+    
+    
+    /**
+     * @param mimeType The mimeType to set.
+     */
+    public void setMimeType(String mimeType) {
+        this.mimeType = mimeType;
+    }
+
+    
+    /**
+     * Get name.
+     * 
+     * @return Name value
+     */
+    public String getName() {
+        if (name != null)
+            return name;
+        if (attributes != null) {
+            Attribute attribute = attributes.get(NAME);
+            if (attribute != null) {
+                try {
+                    name = attribute.get().toString();
+                } catch (NamingException e) {
+                    ; // No value for the attribute
+                }
+            }
+        }
+        return name;
+    }
+
+
+    /**
+     * Set name.
+     * 
+     * @param name New name value
+     */
+    public void setName(String name) {
+        this.name = name;
+        if (attributes != null)
+            attributes.put(NAME, name);
+    }
+    
+    
+    /**
+     * Get resource type.
+     * 
+     * @return String resource type
+     */
+    public String getResourceType() {
+        String result = null;
+        if (attributes != null) {
+            Attribute attribute = attributes.get(TYPE);
+            if (attribute != null) {
+                try {
+                    result = attribute.get().toString();
+                } catch (NamingException e) {
+                    ; // No value for the attribute
+                }
+            }
+        }
+        if (result == null) {
+            if (collection)
+                result = COLLECTION_TYPE;
+            else
+                result = "";
+        }
+        return result;
+    }
+    
+    
+    /**
+     * Type mutator.
+     * 
+     * @param resourceType New resource type
+     */
+    public void setResourceType(String resourceType) {
+        collection = resourceType.equals(COLLECTION_TYPE);
+        if (attributes != null)
+            attributes.put(TYPE, resourceType);
+    }
+
+
+    /**
+     * Get ETag.
+     * 
+     * @return Weak ETag
+     */
+    public String getETag() {
+        return getETag(false);
+    }
+
+
+    /**
+     * Get ETag.
+     * 
+     * @param strong If true, the strong ETag will be returned
+     * @return ETag
+     */
+    public String getETag(boolean strong) {
+        String result = null;
+        if (attributes != null) {
+            Attribute attribute = attributes.get(ETAG);
+            if (attribute != null) {
+                try {
+                    result = attribute.get().toString();
+                } catch (NamingException e) {
+                    ; // No value for the attribute
+                }
+            }
+        }
+        if (strong) {
+            // The strong ETag must always be calculated by the resources
+            result = strongETag;
+        } else {
+            // The weakETag is contentLenght + lastModified
+            if (weakETag == null) {
+                weakETag = "W/\"" + getContentLength() + "-" 
+                    + getLastModified() + "\"";
+            }
+            result = weakETag;
+        }
+        return result;
+    }
+
+
+    /**
+     * Set strong ETag.
+     */
+    public void setETag(String eTag) {
+        this.strongETag = eTag;
+        if (attributes != null)
+            attributes.put(ETAG, eTag);
+    }
+
+    
+    /**
+     * Return the canonical path of the resource, to possibly be used for 
+     * direct file serving. Implementations which support this should override
+     * it to return the file path.
+     * 
+     * @return The canonical path of the resource
+     */
+    public String getCanonicalPath() {
+        return null;
+    }
+    
+    
+    // ----------------------------------------------------- Attributes Methods
+
+
+    /**
+     * Get attribute.
+     */
+    public Attribute get(String attrID) {
+        if (attributes == null) {
+            if (attrID.equals(CREATION_DATE)) {
+                return new BasicAttribute(CREATION_DATE, getCreationDate());
+            } else if (attrID.equals(ALTERNATE_CREATION_DATE)) {
+                return new BasicAttribute(ALTERNATE_CREATION_DATE, 
+                                          getCreationDate());
+            } else if (attrID.equals(LAST_MODIFIED)) {
+                return new BasicAttribute(LAST_MODIFIED, 
+                                          getLastModifiedDate());
+            } else if (attrID.equals(ALTERNATE_LAST_MODIFIED)) {
+                return new BasicAttribute(ALTERNATE_LAST_MODIFIED,
+                                          getLastModifiedDate());
+            } else if (attrID.equals(NAME)) {
+                return new BasicAttribute(NAME, getName());
+            } else if (attrID.equals(TYPE)) {
+                return new BasicAttribute(TYPE, getResourceType());
+            } else if (attrID.equals(ALTERNATE_TYPE)) {
+                return new BasicAttribute(ALTERNATE_TYPE, getResourceType());
+            } else if (attrID.equals(CONTENT_LENGTH)) {
+                return new BasicAttribute(CONTENT_LENGTH, 
+                                          new Long(getContentLength()));
+            } else if (attrID.equals(ALTERNATE_CONTENT_LENGTH)) {
+                return new BasicAttribute(ALTERNATE_CONTENT_LENGTH, 
+                                          new Long(getContentLength()));
+            }
+        } else {
+            return attributes.get(attrID);
+        }
+        return null;
+    }
+    
+    
+    /**
+     * Put attribute.
+     */
+    public Attribute put(Attribute attribute) {
+        if (attributes == null) {
+            try {
+                return put(attribute.getID(), attribute.get());
+            } catch (NamingException e) {
+                return null;
+            }
+        } else {
+            return attributes.put(attribute);
+        }
+    }
+    
+    
+    /**
+     * Put attribute.
+     */
+    public Attribute put(String attrID, Object val) {
+        if (attributes == null) {
+            return null; // No reason to implement this
+        } else {
+            return attributes.put(attrID, val);
+        }
+    }
+    
+    
+    /**
+     * Remove attribute.
+     */
+    public Attribute remove(String attrID) {
+        if (attributes == null) {
+            return null; // No reason to implement this
+        } else {
+            return attributes.remove(attrID);
+        }
+    }
+    
+    
+    /**
+     * Get all attributes.
+     */
+    public NamingEnumeration getAll() {
+        if (attributes == null) {
+            Vector attributes = new Vector();
+            attributes.addElement(new BasicAttribute
+                                  (CREATION_DATE, getCreationDate()));
+            attributes.addElement(new BasicAttribute
+                                  (LAST_MODIFIED, getLastModifiedDate()));
+            attributes.addElement(new BasicAttribute(NAME, getName()));
+            attributes.addElement(new BasicAttribute(TYPE, getResourceType()));
+            attributes.addElement
+                (new BasicAttribute(CONTENT_LENGTH, 
+                                    new Long(getContentLength())));
+            return new RecyclableNamingEnumeration(attributes);
+        } else {
+            return attributes.getAll();
+        }
+    }
+    
+    
+    /**
+     * Get all attribute IDs.
+     */
+    public NamingEnumeration getIDs() {
+        if (attributes == null) {
+            Vector attributeIDs = new Vector();
+            attributeIDs.addElement(CREATION_DATE);
+            attributeIDs.addElement(LAST_MODIFIED);
+            attributeIDs.addElement(NAME);
+            attributeIDs.addElement(TYPE);
+            attributeIDs.addElement(CONTENT_LENGTH);
+            return new RecyclableNamingEnumeration(attributeIDs);
+        } else {
+            return attributes.getIDs();
+        }
+    }
+    
+    
+    /**
+     * Retrieves the number of attributes in the attribute set.
+     */
+    public int size() {
+        if (attributes == null) {
+            return 5;
+        } else {
+            return attributes.size();
+        }
+    }
+    
+    
+    /**
+     * Clone the attributes object (WARNING: fake cloning).
+     */
+    public Object clone() {
+        return this;
+    }
+    
+    
+    /**
+     * Case sensitivity.
+     */
+    public boolean isCaseIgnored() {
+        return false;
+    }
+    
+    
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/resources/ResourceCache.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/resources/ResourceCache.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/resources/ResourceCache.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,422 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.naming.resources;
+
+import java.util.HashMap;
+import java.util.Random;
+
+
+/**
+ * Implements a special purpose cache.
+ * 
+ * @author <a href="mailto:remm at apache.org">Remy Maucherat</a>
+ * @version $Revision: 436866 $
+ */
+public class ResourceCache {
+    
+    
+    // ----------------------------------------------------------- Constructors
+    
+    
+    public ResourceCache() {
+    }
+    
+    
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * Random generator used to determine elements to free.
+     */
+    protected Random random = new Random();
+
+
+    /**
+     * Cache.
+     * Path -> Cache entry.
+     */
+    protected CacheEntry[] cache = new CacheEntry[0];
+
+
+    /**
+     * Not found cache.
+     */
+    protected HashMap notFoundCache = new HashMap();
+
+
+    /**
+     * Max size of resources which will have their content cached.
+     */
+    protected int cacheMaxSize = 10240; // 10 MB
+
+
+    /**
+     * Max amount of removals during a make space.
+     */
+    protected int maxAllocateIterations = 20;
+
+
+    /**
+     * Entry hit ratio at which an entry will never be removed from the cache.
+     * Compared with entry.access / hitsCount
+     */
+    protected long desiredEntryAccessRatio = 3;
+
+
+    /**
+     * Spare amount of not found entries.
+     */
+    protected int spareNotFoundEntries = 500;
+
+
+    /**
+     * Current cache size in KB.
+     */
+    protected int cacheSize = 0;
+
+
+    /**
+     * Number of accesses to the cache.
+     */
+    protected long accessCount = 0;
+
+
+    /**
+     * Number of cache hits.
+     */
+    protected long hitsCount = 0;
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * Return the access count.
+     * Note: Update is not synced, so the number may not be completely 
+     * accurate.
+     */
+    public long getAccessCount() {
+        return accessCount;
+    }
+
+
+    /**
+     * Return the maximum size of the cache in KB.
+     */
+    public int getCacheMaxSize() {
+        return cacheMaxSize;
+    }
+
+
+    /**
+     * Set the maximum size of the cache in KB.
+     */
+    public void setCacheMaxSize(int cacheMaxSize) {
+        this.cacheMaxSize = cacheMaxSize;
+    }
+
+
+    /**
+     * Return the current cache size in KB.
+     */
+    public int getCacheSize() {
+        return cacheSize;
+    }
+
+
+    /**
+     * Return desired entry access ratio.
+     */
+    public long getDesiredEntryAccessRatio() {
+        return desiredEntryAccessRatio;
+    }
+
+
+    /**
+     * Set the desired entry access ratio.
+     */
+    public void setDesiredEntryAccessRatio(long desiredEntryAccessRatio) {
+        this.desiredEntryAccessRatio = desiredEntryAccessRatio;
+    }
+
+
+    /**
+     * Return the number of cache hits.
+     * Note: Update is not synced, so the number may not be completely 
+     * accurate.
+     */
+    public long getHitsCount() {
+        return hitsCount;
+    }
+
+
+    /**
+     * Return the maximum amount of iterations during a space allocation.
+     */
+    public int getMaxAllocateIterations() {
+        return maxAllocateIterations;
+    }
+
+
+    /**
+     * Set the maximum amount of iterations during a space allocation.
+     */
+    public void setMaxAllocateIterations(int maxAllocateIterations) {
+        this.maxAllocateIterations = maxAllocateIterations;
+    }
+
+
+    /**
+     * Return the amount of spare not found entries.
+     */
+    public int getSpareNotFoundEntries() {
+        return spareNotFoundEntries;
+    }
+
+
+    /**
+     * Set the amount of spare not found entries.
+     */
+    public void setSpareNotFoundEntries(int spareNotFoundEntries) {
+        this.spareNotFoundEntries = spareNotFoundEntries;
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    public boolean allocate(int space) {
+
+        int toFree = space - (cacheMaxSize - cacheSize);
+
+        if (toFree <= 0) {
+            return true;
+        }
+
+        // Increase the amount to free so that allocate won't have to run right
+        // away again
+        toFree += (cacheMaxSize / 20);
+
+        int size = notFoundCache.size();
+        if (size > spareNotFoundEntries) {
+            notFoundCache.clear();
+            cacheSize -= size;
+            toFree -= size;
+        }
+
+        if (toFree <= 0) {
+            return true;
+        }
+
+        int attempts = 0;
+        int entriesFound = 0;
+        long totalSpace = 0;
+        int[] toRemove = new int[maxAllocateIterations];
+        while (toFree > 0) {
+            if (attempts == maxAllocateIterations) {
+                // Give up, no changes are made to the current cache
+                return false;
+            }
+            if (toFree > 0) {
+                // Randomly select an entry in the array
+                int entryPos = -1;
+                boolean unique = false;
+                while (!unique) {
+                    unique = true;
+                    entryPos = random.nextInt(cache.length) ;
+                    // Guarantee uniqueness
+                    for (int i = 0; i < entriesFound; i++) {
+                        if (toRemove[i] == entryPos) {
+                            unique = false;
+                        }
+                    }
+                }
+                long entryAccessRatio = 
+                    ((cache[entryPos].accessCount * 100) / accessCount);
+                if (entryAccessRatio < desiredEntryAccessRatio) {
+                    toRemove[entriesFound] = entryPos;
+                    totalSpace += cache[entryPos].size;
+                    toFree -= cache[entryPos].size;
+                    entriesFound++;
+                }
+            }
+            attempts++;
+        }
+
+        // Now remove the selected entries
+        java.util.Arrays.sort(toRemove, 0, entriesFound);
+        CacheEntry[] newCache = new CacheEntry[cache.length - entriesFound];
+        int pos = 0;
+        int n = -1;
+        if (entriesFound > 0) {
+            n = toRemove[0];
+            for (int i = 0; i < cache.length; i++) {
+                if (i == n) {
+                    if ((pos + 1) < entriesFound) {
+                        n = toRemove[pos + 1];
+                        pos++;
+                    } else {
+                        pos++;
+                        n = -1;
+                    }
+                } else {
+                    newCache[i - pos] = cache[i];
+                }
+            }
+        }
+        cache = newCache;
+        cacheSize -= totalSpace;
+
+        return true;
+
+    }
+
+
+    public CacheEntry lookup(String name) {
+
+        CacheEntry cacheEntry = null;
+        CacheEntry[] currentCache = cache;
+        accessCount++;
+        int pos = find(currentCache, name);
+        if ((pos != -1) && (name.equals(currentCache[pos].name))) {
+            cacheEntry = currentCache[pos];
+        }
+
+        if (cacheEntry == null) {
+            try {
+                cacheEntry = (CacheEntry) notFoundCache.get(name);
+            } catch (Exception e) {
+                // Ignore: the reliability of this lookup is not critical
+            }
+        }
+        if (cacheEntry != null) {
+            hitsCount++;
+        }
+        return cacheEntry;
+
+    }
+
+
+    public void load(CacheEntry entry) {
+        if (entry.exists) {
+            if (insertCache(entry)) {
+                cacheSize += entry.size;
+            }
+        } else {
+            int sizeIncrement = (notFoundCache.get(entry.name) == null) ? 1 : 0;
+            notFoundCache.put(entry.name, entry);
+            cacheSize += sizeIncrement;
+        }
+    }
+
+
+    public boolean unload(String name) {
+        CacheEntry removedEntry = removeCache(name);
+        if (removedEntry != null) {
+            cacheSize -= removedEntry.size;
+            return true;
+        } else if (notFoundCache.remove(name) != null) {
+            cacheSize--;
+            return true;
+        }
+        return false;
+    }
+
+
+    /**
+     * Find a map elemnt given its name in a sorted array of map elements.
+     * This will return the index for the closest inferior or equal item in the
+     * given array.
+     */
+    private static final int find(CacheEntry[] map, String name) {
+
+        int a = 0;
+        int b = map.length - 1;
+
+        // Special cases: -1 and 0
+        if (b == -1) {
+            return -1;
+        }
+        if (name.compareTo(map[0].name) < 0) {
+            return -1;
+        }
+        if (b == 0) {
+            return 0;
+        }
+
+        int i = 0;
+        while (true) {
+            i = (b + a) / 2;
+            int result = name.compareTo(map[i].name);
+            if (result > 0) {
+                a = i;
+            } else if (result == 0) {
+                return i;
+            } else {
+                b = i;
+            }
+            if ((b - a) == 1) {
+                int result2 = name.compareTo(map[b].name);
+                if (result2 < 0) {
+                    return a;
+                } else {
+                    return b;
+                }
+            }
+        }
+
+    }
+
+
+    /**
+     * Insert into the right place in a sorted MapElement array, and prevent
+     * duplicates.
+     */
+    private final boolean insertCache(CacheEntry newElement) {
+        CacheEntry[] oldCache = cache;
+        int pos = find(oldCache, newElement.name);
+        if ((pos != -1) && (newElement.name.equals(oldCache[pos].name))) {
+            return false;
+        }
+        CacheEntry[] newCache = new CacheEntry[cache.length + 1];
+        System.arraycopy(oldCache, 0, newCache, 0, pos + 1);
+        newCache[pos + 1] = newElement;
+        System.arraycopy
+            (oldCache, pos + 1, newCache, pos + 2, oldCache.length - pos - 1);
+        cache = newCache;
+        return true;
+    }
+
+
+    /**
+     * Insert into the right place in a sorted MapElement array.
+     */
+    private final CacheEntry removeCache(String name) {
+        CacheEntry[] oldCache = cache;
+        int pos = find(oldCache, name);
+        if ((pos != -1) && (name.equals(oldCache[pos].name))) {
+            CacheEntry[] newCache = new CacheEntry[cache.length - 1];
+            System.arraycopy(oldCache, 0, newCache, 0, pos);
+            System.arraycopy(oldCache, pos + 1, newCache, pos, 
+                             oldCache.length - pos - 1);
+            cache = newCache;
+            return oldCache[pos];
+        }
+        return null;
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/resources/WARDirContext.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/resources/WARDirContext.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/resources/WARDirContext.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,953 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.naming.resources;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipException;
+import java.util.zip.ZipFile;
+
+import javax.naming.CompositeName;
+import javax.naming.Name;
+import javax.naming.NamingEnumeration;
+import javax.naming.NamingException;
+import javax.naming.OperationNotSupportedException;
+import javax.naming.directory.Attributes;
+import javax.naming.directory.DirContext;
+import javax.naming.directory.ModificationItem;
+import javax.naming.directory.SearchControls;
+
+import org.apache.naming.NamingContextBindingsEnumeration;
+import org.apache.naming.NamingContextEnumeration;
+import org.apache.naming.NamingEntry;
+
+/**
+ * WAR Directory Context implementation.
+ *
+ * @author Remy Maucherat
+ * @version $Revision: 366304 $ $Date: 2006-01-05 15:42:29 -0600 (Thu, 05 Jan 2006) $
+ */
+
+public class WARDirContext extends BaseDirContext {
+
+    private static org.apache.commons.logging.Log log=
+        org.apache.commons.logging.LogFactory.getLog( WARDirContext.class );
+    
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Builds a WAR directory context using the given environment.
+     */
+    public WARDirContext() {
+        super();
+    }
+
+
+    /**
+     * Builds a WAR directory context using the given environment.
+     */
+    public WARDirContext(Hashtable env) {
+        super(env);
+    }
+
+
+    /**
+     * Constructor used for returning fake subcontexts.
+     */
+    protected WARDirContext(ZipFile base, Entry entries) {
+        this.base = base;
+        this.entries = entries;
+    }
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The WAR file.
+     */
+    protected ZipFile base = null;
+
+
+    /**
+     * WAR entries.
+     */
+    protected Entry entries = null;
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * Set the document root.
+     * 
+     * @param docBase The new document root
+     * 
+     * @exception IllegalArgumentException if the specified value is not
+     *  supported by this implementation
+     * @exception IllegalArgumentException if this would create a
+     *  malformed URL
+     */
+    public void setDocBase(String docBase) {
+
+	// Validate the format of the proposed document root
+	if (docBase == null)
+	    throw new IllegalArgumentException
+		(sm.getString("resources.null"));
+	if (!(docBase.endsWith(".war")))
+	    throw new IllegalArgumentException
+		(sm.getString("warResources.notWar"));
+
+	// Calculate a File object referencing this document base directory
+	File base = new File(docBase);
+
+	// Validate that the document base is an existing directory
+	if (!base.exists() || !base.canRead() || base.isDirectory())
+	    throw new IllegalArgumentException
+		(sm.getString("warResources.invalidWar", docBase));
+        try {
+            this.base = new ZipFile(base);
+        } catch (Exception e) {
+	    throw new IllegalArgumentException
+		(sm.getString("warResources.invalidWar", e.getMessage()));
+        }
+        super.setDocBase(docBase);
+
+        loadEntries();
+
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Release any resources allocated for this directory context.
+     */
+    public void release() {
+
+        entries = null;
+        if (base != null) {
+            try {
+                base.close();
+            } catch (IOException e) {
+                log.warn
+                    ("Exception closing WAR File " + base.getName(), e);
+            }
+        }
+        base = null;
+        super.release();
+
+    }
+
+
+    // -------------------------------------------------------- Context Methods
+
+
+    /**
+     * Retrieves the named object.
+     * 
+     * @param name the name of the object to look up
+     * @return the object bound to name
+     * @exception NamingException if a naming exception is encountered
+     */
+    public Object lookup(String name)
+        throws NamingException {
+        return lookup(new CompositeName(name));
+    }
+
+
+    /**
+     * Retrieves the named object. If name is empty, returns a new instance 
+     * of this context (which represents the same naming context as this 
+     * context, but its environment may be modified independently and it may 
+     * be accessed concurrently).
+     * 
+     * @param name the name of the object to look up
+     * @return the object bound to name
+     * @exception NamingException if a naming exception is encountered
+     */
+    public Object lookup(Name name)
+        throws NamingException {
+        if (name.isEmpty())
+            return this;
+        Entry entry = treeLookup(name);
+        if (entry == null)
+            throw new NamingException
+                (sm.getString("resources.notFound", name));
+        ZipEntry zipEntry = entry.getEntry();
+        if (zipEntry.isDirectory())
+            return new WARDirContext(base, entry);
+        else
+            return new WARResource(entry.getEntry());
+    }
+
+
+    /**
+     * Unbinds the named object. Removes the terminal atomic name in name 
+     * from the target context--that named by all but the terminal atomic 
+     * part of name.
+     * <p>
+     * This method is idempotent. It succeeds even if the terminal atomic 
+     * name is not bound in the target context, but throws 
+     * NameNotFoundException if any of the intermediate contexts do not exist. 
+     * 
+     * @param name the name to bind; may not be empty
+     * @exception NameNotFoundException if an intermediate context does not 
+     * exist
+     * @exception NamingException if a naming exception is encountered
+     */
+    public void unbind(String name)
+        throws NamingException {
+        throw new OperationNotSupportedException();
+    }
+
+
+    /**
+     * Binds a new name to the object bound to an old name, and unbinds the 
+     * old name. Both names are relative to this context. Any attributes 
+     * associated with the old name become associated with the new name. 
+     * Intermediate contexts of the old name are not changed.
+     * 
+     * @param oldName the name of the existing binding; may not be empty
+     * @param newName the name of the new binding; may not be empty
+     * @exception NameAlreadyBoundException if newName is already bound
+     * @exception NamingException if a naming exception is encountered
+     */
+    public void rename(String oldName, String newName)
+        throws NamingException {
+        throw new OperationNotSupportedException();
+    }
+
+
+    /**
+     * 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
+     */
+    public NamingEnumeration list(String name)
+        throws NamingException {
+        return list(new CompositeName(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
+     */
+    public NamingEnumeration list(Name name)
+        throws NamingException {
+        if (name.isEmpty())
+            return new NamingContextEnumeration(list(entries).iterator());
+        Entry entry = treeLookup(name);
+        if (entry == null)
+            throw new NamingException
+                (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.
+     * <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 bindings in this context. 
+     * Each element of the enumeration is of type Binding.
+     * @exception NamingException if a naming exception is encountered
+     */
+    public NamingEnumeration listBindings(String name)
+        throws NamingException {
+        return listBindings(new CompositeName(name));
+    }
+
+
+    /**
+     * Enumerates the names bound in the named context, along with the 
+     * 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 bindings in this context. 
+     * Each element of the enumeration is of type Binding.
+     * @exception NamingException if a naming exception is encountered
+     */
+    public NamingEnumeration listBindings(Name name)
+        throws NamingException {
+        if (name.isEmpty())
+            return new NamingContextBindingsEnumeration(list(entries).iterator(),
+                    this);
+        Entry entry = treeLookup(name);
+        if (entry == null)
+            throw new NamingException
+                (sm.getString("resources.notFound", name));
+        return new NamingContextBindingsEnumeration(list(entry).iterator(),
+                this);
+    }
+
+
+    /**
+     * Destroys the named context and removes it from the namespace. Any 
+     * attributes associated with the name are also removed. Intermediate 
+     * contexts are not destroyed.
+     * <p>
+     * This method is idempotent. It succeeds even if the terminal atomic 
+     * name is not bound in the target context, but throws 
+     * NameNotFoundException if any of the intermediate contexts do not exist. 
+     * 
+     * In a federated naming system, a context from one naming system may be 
+     * bound to a name in another. One can subsequently look up and perform 
+     * operations on the foreign context using a composite name. However, an 
+     * attempt destroy the context using this composite name will fail with 
+     * NotContextException, because the foreign context is not a "subcontext" 
+     * of the context in which it is bound. Instead, use unbind() to remove 
+     * the binding of the foreign context. Destroying the foreign context 
+     * requires that the destroySubcontext() be performed on a context from 
+     * the foreign context's "native" naming system.
+     * 
+     * @param name the name of the context to be destroyed; may not be empty
+     * @exception NameNotFoundException if an intermediate context does not 
+     * exist
+     * @exception NotContextException if the name is bound but does not name 
+     * a context, or does not name a context of the appropriate type
+     */
+    public void destroySubcontext(String name)
+        throws NamingException {
+        throw new OperationNotSupportedException();
+    }
+
+
+    /**
+     * Retrieves the named object, following links except for the terminal 
+     * atomic component of the name. If the object bound to name is not a 
+     * link, returns the object itself.
+     * 
+     * @param name the name of the object to look up
+     * @return the object bound to name, not following the terminal link 
+     * (if any).
+     * @exception NamingException if a naming exception is encountered
+     */
+    public Object lookupLink(String name)
+        throws NamingException {
+        // Note : Links are not supported
+        return lookup(name);
+    }
+
+
+    /**
+     * Retrieves the full name of this context within its own namespace.
+     * <p>
+     * Many naming services have a notion of a "full name" for objects in 
+     * their respective namespaces. For example, an LDAP entry has a 
+     * distinguished name, and a DNS record has a fully qualified name. This 
+     * method allows the client application to retrieve this name. The string 
+     * returned by this method is not a JNDI composite name and should not be 
+     * passed directly to context methods. In naming systems for which the 
+     * notion of full name does not make sense, 
+     * OperationNotSupportedException is thrown.
+     * 
+     * @return this context's name in its own namespace; never null
+     * @exception OperationNotSupportedException if the naming system does 
+     * not have the notion of a full name
+     * @exception NamingException if a naming exception is encountered
+     */
+    public String getNameInNamespace()
+        throws NamingException {
+        return docBase;
+    }
+
+
+    // ----------------------------------------------------- DirContext Methods
+
+
+    /**
+     * Retrieves selected attributes associated with a named object. 
+     * See the class description regarding attribute models, attribute type 
+     * names, and operational attributes.
+     * 
+     * @return the requested attributes; never null
+     * @param name the name of the object from which to retrieve attributes
+     * @param attrIds the identifiers of the attributes to retrieve. null 
+     * indicates that all attributes should be retrieved; an empty array 
+     * indicates that none should be retrieved
+     * @exception NamingException if a naming exception is encountered
+     */
+    public Attributes getAttributes(String name, String[] attrIds)
+        throws NamingException {
+        return getAttributes(new CompositeName(name), attrIds);
+    }
+
+
+    /**
+     * Retrieves all of the attributes associated with a named object. 
+     * 
+     * @return the set of attributes associated with name. 
+     * Returns an empty attribute set if name has no attributes; never null.
+     * @param name the name of the object from which to retrieve attributes
+     * @exception NamingException if a naming exception is encountered
+     */
+    public Attributes getAttributes(Name name, String[] attrIds)
+        throws NamingException {
+        
+        Entry entry = null;
+        if (name.isEmpty())
+            entry = entries;
+        else
+            entry = treeLookup(name);
+        if (entry == null)
+            throw new NamingException
+                (sm.getString("resources.notFound", name));
+        
+        ZipEntry zipEntry = entry.getEntry();
+
+        ResourceAttributes attrs = new ResourceAttributes();
+        attrs.setCreationDate(new Date(zipEntry.getTime()));
+        attrs.setName(entry.getName());
+        if (!zipEntry.isDirectory())
+            attrs.setResourceType("");
+        attrs.setContentLength(zipEntry.getSize());
+        attrs.setLastModified(zipEntry.getTime());
+        
+        return attrs;
+        
+    }
+
+
+    /**
+     * Modifies the attributes associated with a named object. The order of 
+     * the modifications is not specified. Where possible, the modifications 
+     * are performed atomically.
+     * 
+     * @param name the name of the object whose attributes will be updated
+     * @param mod_op the modification operation, one of: ADD_ATTRIBUTE, 
+     * REPLACE_ATTRIBUTE, REMOVE_ATTRIBUTE
+     * @param attrs the attributes to be used for the modification; may not 
+     * be null
+     * @exception AttributeModificationException if the modification cannot be
+     * completed successfully
+     * @exception NamingException if a naming exception is encountered
+     */
+    public void modifyAttributes(String name, int mod_op, Attributes attrs)
+        throws NamingException {
+        throw new OperationNotSupportedException();
+    }
+
+
+    /**
+     * Modifies the attributes associated with a named object using an an 
+     * ordered list of modifications. The modifications are performed in the 
+     * order specified. Each modification specifies a modification operation 
+     * code and an attribute on which to operate. Where possible, the 
+     * modifications are performed atomically.
+     * 
+     * @param name the name of the object whose attributes will be updated
+     * @param mods an ordered sequence of modifications to be performed; may 
+     * not be null
+     * @exception AttributeModificationException if the modification cannot be
+     * completed successfully
+     * @exception NamingException if a naming exception is encountered
+     */
+    public void modifyAttributes(String name, ModificationItem[] mods)
+        throws NamingException {
+        throw new OperationNotSupportedException();
+    }
+
+
+    /**
+     * Binds a name to an object, along with associated attributes. If attrs 
+     * is null, the resulting binding will have the attributes associated 
+     * with obj if obj is a DirContext, and no attributes otherwise. If attrs 
+     * is non-null, the resulting binding will have attrs as its attributes; 
+     * any attributes associated with obj are ignored.
+     * 
+     * @param name the name to bind; may not be empty
+     * @param obj the object to bind; possibly null
+     * @param attrs the attributes to associate with the binding
+     * @exception NameAlreadyBoundException if name is already bound
+     * @exception InvalidAttributesException if some "mandatory" attributes 
+     * of the binding are not supplied
+     * @exception NamingException if a naming exception is encountered
+     */
+    public void bind(String name, Object obj, Attributes attrs)
+        throws NamingException {
+        throw new OperationNotSupportedException();
+    }
+
+
+    /**
+     * Binds a name to an object, along with associated attributes, 
+     * overwriting any existing binding. If attrs is null and obj is a 
+     * DirContext, the attributes from obj are used. If attrs is null and obj 
+     * is not a DirContext, any existing attributes associated with the object
+     * already bound in the directory remain unchanged. If attrs is non-null, 
+     * any existing attributes associated with the object already bound in 
+     * the directory are removed and attrs is associated with the named 
+     * object. If obj is a DirContext and attrs is non-null, the attributes 
+     * of obj are ignored.
+     * 
+     * @param name the name to bind; may not be empty
+     * @param obj the object to bind; possibly null
+     * @param attrs the attributes to associate with the binding
+     * @exception InvalidAttributesException if some "mandatory" attributes 
+     * of the binding are not supplied
+     * @exception NamingException if a naming exception is encountered
+     */
+    public void rebind(String name, Object obj, Attributes attrs)
+        throws NamingException {
+        throw new OperationNotSupportedException();
+    }
+
+
+    /**
+     * Creates and binds a new context, along with associated attributes. 
+     * This method creates a new subcontext with the given name, binds it in 
+     * the target context (that named by all but terminal atomic component of 
+     * the name), and associates the supplied attributes with the newly 
+     * created object. All intermediate and target contexts must already 
+     * exist. If attrs is null, this method is equivalent to 
+     * Context.createSubcontext().
+     * 
+     * @param name the name of the context to create; may not be empty
+     * @param attrs the attributes to associate with the newly created context
+     * @return the newly created context
+     * @exception NameAlreadyBoundException if the name is already bound
+     * @exception InvalidAttributesException if attrs does not contain all 
+     * the mandatory attributes required for creation
+     * @exception NamingException if a naming exception is encountered
+     */
+    public DirContext createSubcontext(String name, Attributes attrs)
+        throws NamingException {
+        throw new OperationNotSupportedException();
+    }
+
+
+    /**
+     * Retrieves the schema associated with the named object. The schema 
+     * describes rules regarding the structure of the namespace and the 
+     * attributes stored within it. The schema specifies what types of 
+     * objects can be added to the directory and where they can be added; 
+     * what mandatory and optional attributes an object can have. The range 
+     * of support for schemas is directory-specific.
+     * 
+     * @param name the name of the object whose schema is to be retrieved
+     * @return the schema associated with the context; never null
+     * @exception OperationNotSupportedException if schema not supported
+     * @exception NamingException if a naming exception is encountered
+     */
+    public DirContext getSchema(String name)
+        throws NamingException {
+        throw new OperationNotSupportedException();
+    }
+
+
+    /**
+     * Retrieves a context containing the schema objects of the named 
+     * object's class definitions.
+     * 
+     * @param name the name of the object whose object class definition is to 
+     * be retrieved
+     * @return the DirContext containing the named object's class 
+     * definitions; never null
+     * @exception OperationNotSupportedException if schema not supported
+     * @exception NamingException if a naming exception is encountered
+     */
+    public DirContext getSchemaClassDefinition(String name)
+        throws NamingException {
+        throw new OperationNotSupportedException();
+    }
+
+
+    /**
+     * Searches in a single context for objects that contain a specified set 
+     * of attributes, and retrieves selected attributes. The search is 
+     * performed using the default SearchControls settings.
+     * 
+     * @param name the name of the context to search
+     * @param matchingAttributes the attributes to search for. If empty or 
+     * null, all objects in the target context are returned.
+     * @param attributesToReturn the attributes to return. null indicates 
+     * that all attributes are to be returned; an empty array indicates that 
+     * none are to be returned.
+     * @return a non-null enumeration of SearchResult objects. Each 
+     * SearchResult contains the attributes identified by attributesToReturn 
+     * and the name of the corresponding object, named relative to the 
+     * context named by name.
+     * @exception NamingException if a naming exception is encountered
+     */
+    public NamingEnumeration search(String name, Attributes matchingAttributes,
+                                    String[] attributesToReturn)
+        throws NamingException {
+        throw new OperationNotSupportedException();
+    }
+
+
+    /**
+     * Searches in a single context for objects that contain a specified set 
+     * of attributes. This method returns all the attributes of such objects. 
+     * It is equivalent to supplying null as the atributesToReturn parameter 
+     * to the method search(Name, Attributes, String[]).
+     * 
+     * @param name the name of the context to search
+     * @param matchingAttributes the attributes to search for. If empty or 
+     * null, all objects in the target context are returned.
+     * @return a non-null enumeration of SearchResult objects. Each 
+     * SearchResult contains the attributes identified by attributesToReturn 
+     * and the name of the corresponding object, named relative to the 
+     * context named by name.
+     * @exception NamingException if a naming exception is encountered
+     */
+    public NamingEnumeration search(String name, Attributes matchingAttributes)
+        throws NamingException {
+        throw new OperationNotSupportedException();
+    }
+
+
+    /**
+     * Searches in the named context or object for entries that satisfy the 
+     * given search filter. Performs the search as specified by the search 
+     * controls.
+     * 
+     * @param name the name of the context or object to search
+     * @param filter the filter expression to use for the search; may not be 
+     * null
+     * @param cons the search controls that control the search. If null, 
+     * the default search controls are used (equivalent to 
+     * (new SearchControls())).
+     * @return an enumeration of SearchResults of the objects that satisfy 
+     * the filter; never null
+     * @exception InvalidSearchFilterException if the search filter specified 
+     * is not supported or understood by the underlying directory
+     * @exception InvalidSearchControlsException if the search controls 
+     * contain invalid settings
+     * @exception NamingException if a naming exception is encountered
+     */
+    public NamingEnumeration search(String name, String filter, 
+                                    SearchControls cons)
+        throws NamingException {
+        throw new OperationNotSupportedException();
+    }
+
+
+    /**
+     * Searches in the named context or object for entries that satisfy the 
+     * given search filter. Performs the search as specified by the search 
+     * controls.
+     * 
+     * @param name the name of the context or object to search
+     * @param filterExpr the filter expression to use for the search. 
+     * The expression may contain variables of the form "{i}" where i is a 
+     * nonnegative integer. May not be null.
+     * @param filterArgs the array of arguments to substitute for the 
+     * variables in filterExpr. The value of filterArgs[i] will replace each 
+     * occurrence of "{i}". If null, equivalent to an empty array.
+     * @param cons the search controls that control the search. If null, the 
+     * default search controls are used (equivalent to (new SearchControls())).
+     * @return an enumeration of SearchResults of the objects that satisy the 
+     * filter; never null
+     * @exception ArrayIndexOutOfBoundsException if filterExpr contains {i} 
+     * expressions where i is outside the bounds of the array filterArgs
+     * @exception InvalidSearchControlsException if cons contains invalid 
+     * settings
+     * @exception InvalidSearchFilterException if filterExpr with filterArgs 
+     * represents an invalid search filter
+     * @exception NamingException if a naming exception is encountered
+     */
+    public NamingEnumeration search(String name, String filterExpr, 
+                                    Object[] filterArgs, SearchControls cons)
+        throws NamingException {
+        throw new OperationNotSupportedException();
+    }
+
+
+    // ------------------------------------------------------ Protected Methods
+
+
+    /**
+     * Normalize the name of an entry read from the Zip.
+     */
+    protected String normalize(ZipEntry entry) {
+
+        String result = "/" + entry.getName();
+        if (entry.isDirectory()) {
+            result = result.substring(0, result.length() - 1);
+        }
+        return result;
+
+    }
+
+
+    /**
+     * Constructs a tree of the entries contained in a WAR file.
+     */
+    protected void loadEntries() {
+
+        try {
+
+            Enumeration entryList = base.entries();
+            entries = new Entry("/", new ZipEntry("/"));
+            
+            while (entryList.hasMoreElements()) {
+                
+                ZipEntry entry = (ZipEntry) entryList.nextElement();
+                String name = normalize(entry);
+                int pos = name.lastIndexOf('/');
+                // Check that parent entries exist and, if not, create them.
+                // This fixes a bug for war files that don't record separate
+                // zip entries for the directories.
+                int currentPos = -1;
+                int lastPos = 0;
+                while ((currentPos = name.indexOf('/', lastPos)) != -1) {
+                    Name parentName = new CompositeName(name.substring(0, lastPos));
+                    Name childName = new CompositeName(name.substring(0, currentPos));
+                    String entryName = name.substring(lastPos, currentPos);
+                    // Parent should have been created in last cycle through
+                    // this loop
+                    Entry parent = treeLookup(parentName);
+                    Entry child = treeLookup(childName);
+                    if (child == null) {
+                        // Create a new entry for missing entry and strip off
+                        // the leading '/' character and appended on by the
+                        // normalize method and add '/' character to end to
+                        // signify that it is a directory entry
+                        String zipName = name.substring(1, currentPos) + "/";
+                        child = new Entry(entryName, new ZipEntry(zipName));
+                        if (parent != null)
+                            parent.addChild(child);
+                    }
+                    // Increment lastPos
+                    lastPos = currentPos + 1;
+                }
+                String entryName = name.substring(pos + 1, name.length());
+                Name compositeName = new CompositeName(name.substring(0, pos));
+                Entry parent = treeLookup(compositeName);
+                Entry child = new Entry(entryName, entry);
+                if (parent != null)
+                    parent.addChild(child);
+                
+            }
+
+        } catch (Exception e) {
+        }
+
+    }
+
+
+    /**
+     * Entry tree lookup.
+     */
+    protected Entry treeLookup(Name name) {
+        if (name.isEmpty())
+            return entries;
+        Entry currentEntry = entries;
+        for (int i = 0; i < name.size(); i++) {
+            if (name.get(i).length() == 0)
+                continue;
+            currentEntry = currentEntry.getChild(name.get(i));
+            if (currentEntry == null)
+                return null;
+        }
+        return currentEntry;
+    }
+
+
+    /**
+     * List children as objects.
+     */
+    protected ArrayList list(Entry entry) {
+        
+        ArrayList entries = new ArrayList();
+        Entry[] children = entry.getChildren();
+        Arrays.sort(children);
+        NamingEntry namingEntry = null;
+        
+        for (int i = 0; i < children.length; i++) {
+            ZipEntry current = children[i].getEntry();
+            Object object = null;
+            if (current.isDirectory()) {
+                object = new WARDirContext(base, children[i]);
+            } else {
+                object = new WARResource(current);
+            }
+            namingEntry = new NamingEntry
+                (children[i].getName(), object, NamingEntry.ENTRY);
+            entries.add(namingEntry);
+        }
+        
+        return entries;
+        
+    }
+
+
+    // ---------------------------------------------------- Entries Inner Class
+
+
+    /**
+     * Entries structure.
+     */
+    protected class Entry implements Comparable {
+
+
+        // -------------------------------------------------------- Constructor
+        
+        
+        public Entry(String name, ZipEntry entry) {
+            this.name = name;
+            this.entry = entry;
+        }
+        
+        
+        // --------------------------------------------------- Member Variables
+        
+        
+        protected String name = null;
+        
+        
+        protected ZipEntry entry = null;
+        
+        
+        protected Entry children[] = new Entry[0];
+        
+        
+        // ----------------------------------------------------- Public Methods
+        
+        
+        public int compareTo(Object o) {
+            if (!(o instanceof Entry))
+                return (+1);
+            return (name.compareTo(((Entry) o).getName()));
+        }
+
+        public ZipEntry getEntry() {
+            return entry;
+        }
+        
+        
+        public String getName() {
+            return name;
+        }
+        
+        
+        public void addChild(Entry entry) {
+            Entry[] newChildren = new Entry[children.length + 1];
+            for (int i = 0; i < children.length; i++)
+                newChildren[i] = children[i];
+            newChildren[children.length] = entry;
+            children = newChildren;
+        }
+
+
+        public Entry[] getChildren() {
+            return children;
+        }
+
+
+        public Entry getChild(String name) {
+            for (int i = 0; i < children.length; i++) {
+                if (children[i].name.equals(name)) {
+                    return children[i];
+                }
+            }
+            return null;
+        }
+
+
+    }
+
+
+    // ------------------------------------------------ WARResource Inner Class
+
+
+    /**
+     * This specialized resource implementation avoids opening the IputStream
+     * to the WAR right away.
+     */
+    protected class WARResource extends Resource {
+        
+        
+        // -------------------------------------------------------- Constructor
+        
+        
+        public WARResource(ZipEntry entry) {
+            this.entry = entry;
+        }
+        
+        
+        // --------------------------------------------------- Member Variables
+        
+        
+        protected ZipEntry entry;
+        
+        
+        // ----------------------------------------------------- Public Methods
+        
+        
+        /**
+         * Content accessor.
+         * 
+         * @return InputStream
+         */
+        public InputStream streamContent()
+            throws IOException {
+            try {
+                if (binaryContent == null) {
+                    inputStream = base.getInputStream(entry);
+                }
+            } catch (ZipException e) {
+                throw new IOException(e.getMessage());
+            }
+            return super.streamContent();
+        }
+        
+        
+    }
+
+
+}
+

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/resources/jndi/Handler.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/resources/jndi/Handler.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/resources/jndi/Handler.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,38 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.naming.resources.jndi;
+
+import org.apache.naming.resources.DirContextURLStreamHandler;
+
+/**
+ * Stream handler to a JNDI directory context.
+ * 
+ * @author <a href="mailto:remm at apache.org">Remy Maucherat</a>
+ * @version $Revision: 302726 $
+ */
+public class Handler 
+    extends DirContextURLStreamHandler {
+    
+    
+    // ----------------------------------------------------------- Constructors
+    
+    
+    public Handler() {
+    }
+    
+    
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/resources/package.html
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/resources/package.html	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/share/org/apache/naming/resources/package.html	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,15 @@
+<body>
+
+<p>This package contains the resources directory context implemetation.
+This includes :
+<ul>
+<li>A CacheDirContext which handles caching and acts as a proxy for the real 
+resources context</li>
+<li>A FileDirContext, an implementation of DirContext to access the 
+filesystem</li>
+</ul>
+</p>
+
+<p></p>
+
+</body>

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/temp/README.txt
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/temp/README.txt	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/temp/README.txt	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,5 @@
+This temp directory is used by the JVM for temporary file storage.
+The JVM is configured to use this as its java.io.tmpdir in the
+catalina.sh and catalina.bat scripts.  Tomcat is configured to use
+this temporary directory rather than its default for security reasons.
+The temp directory must exist for Tomcat to work correctly.

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/test/org/apache/catalina/util/CookieToolsTestCase.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/test/org/apache/catalina/util/CookieToolsTestCase.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/test/org/apache/catalina/util/CookieToolsTestCase.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,153 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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 javax.servlet.http.Cookie;
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+
+
+/**
+ * Unit tests for the <code>CookieTools</code> class.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class CookieToolsTestCase extends TestCase {
+
+
+    public static void main(String args[]) {
+        System.out.println("TestCase started");
+    }
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * A "version 0" cookie.
+     */
+    protected Cookie version0 = null;
+
+
+    /**
+     * A "version 1" cookie.
+     */
+    protected Cookie version1 = null;
+
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Construct a new instance of this test case.
+     *
+     * @param name Name of the test case
+     */
+    public CookieToolsTestCase(String name) {
+
+        super(name);
+
+    }
+
+
+    // --------------------------------------------------- Overall Test Methods
+
+
+    /**
+     * Set up instance variables required by this test case.
+     */
+    public void setUp() {
+
+        version0 = new Cookie("Version 0 Name", "Version 0 Value");
+        version0.setComment("Version 0 Comment");
+        version0.setDomain("localhost");
+        version0.setPath("/version0");
+        version0.setVersion(0);
+
+        version1 = new Cookie("Version 1 Name", "Version 1 Value");
+        version1.setComment("Version 1 Comment");
+        version1.setDomain("localhost");
+        version1.setPath("/version1");
+        version1.setVersion(1);
+
+    }
+
+
+    /**
+     * Return the tests included in this test suite.
+     */
+    public static Test suite() {
+
+        return (new TestSuite(CookieToolsTestCase.class));
+
+    }
+
+
+    /**
+     * Tear down instance variables required by this test case.
+     */
+    public void tearDown() {
+
+        version0 = null;
+        version1 = null;
+
+    }
+
+
+    // ------------------------------------------------ Individual Test Methods
+
+
+    /**
+     * Check the value returned by <code>getCookieHeaderName()</code>.
+     */
+    public void testGetCookieHeaderName() {
+
+        assertEquals("Version 0 cookie header name", "Set-Cookie",
+                     CookieTools.getCookieHeaderName(version0));
+        assertEquals("Version 1 cookie header name", "Set-Cookie2",
+                     CookieTools.getCookieHeaderName(version1));
+
+    }
+
+
+    /**
+     * Check the value returned by <code>getCookieHeaderValue()</code>
+     */
+    public void testGetCookieHeaderValue() {
+
+        StringBuffer sb = null;
+
+        sb = new StringBuffer();
+        CookieTools.getCookieHeaderValue(version0, sb);
+        assertEquals("Version 0 cookie header value",
+                     "Version 0 Name=Version 0 Value;Domain=localhost;Path=/version0",
+                     sb.toString());
+
+        sb = new StringBuffer();
+        CookieTools.getCookieHeaderValue(version1, sb);
+        assertEquals("Version 1 cookie header value",
+                     "Version 1 Name=\"Version 1 Value\";Version=1;Comment=\"Version 1 Comment\";Domain=localhost;Discard;Path=\"/version1\"",
+                     sb.toString());
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/test/org/apache/catalina/util/URLTestCase.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/test/org/apache/catalina/util/URLTestCase.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/test/org/apache/catalina/util/URLTestCase.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,639 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.net.MalformedURLException;
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+
+
+/**
+ * Unit tests for the <code>org.apache.catalina.util.URL</code> class.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class URLTestCase extends TestCase {
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Construct a new instance of this test case.
+     *
+     * @param name Name of the test case
+     */
+    public URLTestCase(String name) {
+
+        super(name);
+
+    }
+
+
+    // --------------------------------------------------- Overall Test Methods
+
+
+    /**
+     * Set up instance variables required by this test case.
+     */
+    public void setUp() {
+
+        ; // No action required
+
+    }
+
+
+    /**
+     * Return the tests included in this test suite.
+     */
+    public static Test suite() {
+
+        return (new TestSuite(URLTestCase.class));
+
+    }
+
+
+    /**
+     * Tear down instance variables required by this test case.
+     */
+    public void tearDown() {
+
+        ; // No action required
+
+    }
+
+
+    // ------------------------------------------------ Individual Test Methods
+
+
+    /**
+     * Negative tests for absolute URL strings in various patterns.  Each of
+     * these should throw <code>MalformedURLException</code>.
+     */
+    public void testNegativeAbsolute() {
+
+        negative("index.html");
+        negative("index.html#ref");
+        negative("index.html?name=value");
+        negative("index.html?name=value#ref");
+
+        negative("/index.html");
+        negative("/index.html#ref");
+        negative("/index.html?name=value");
+        negative("/index.html?name=value#ref");
+
+    }
+
+
+    /**
+     * Negative tests for <code>normalize()</code>.  Attempts to normalize
+     * these legal URLs should throw <code>MalformedURLException</code>.
+     */
+    public void testNegativeNormalize() {
+
+        normalize("http://localhost/..");
+        normalize("http://localhost/..#ref");
+        normalize("http://localhost/..?name=value");
+        normalize("http://localhost/..?name=value#ref");
+
+        normalize("http://localhost:8080/..");
+        normalize("http://localhost:8080/..#ref");
+        normalize("http://localhost:8080/..?name=value");
+        normalize("http://localhost:8080/..?name=value#ref");
+ 
+        normalize("http://localhost/../");
+        normalize("http://localhost/../#ref");
+        normalize("http://localhost/../?name=value");
+        normalize("http://localhost/../?name=value#ref");
+
+        normalize("http://localhost:8080/../");
+        normalize("http://localhost:8080/../#ref");
+        normalize("http://localhost:8080/../?name=value");
+        normalize("http://localhost:8080/../?name=value#ref");
+ 
+        normalize("http://localhost/index.html/../../foo.html");
+        normalize("http://localhost/index.html/../../foo.html#ref");
+        normalize("http://localhost/index.html/../../foo.html?name=value");
+        normalize("http://localhost/index.html/../../foo.html?name=value#ref");
+
+        normalize("http://localhost:8080/index.html/../../foo.html");
+        normalize("http://localhost:8080/index.html/../../foo.html#ref");
+        normalize("http://localhost:8080/index.html/../../foo.html?name=value");
+        normalize("http://localhost:8080/index.html/../../foo.html?name=value#ref");
+ 
+    }
+
+
+    /**
+     * Negative tests for relative URL strings in various patterns.  Each of
+     * these should throw <code>MalformedURLException</code>.
+     */
+    public void testNegativeRelative() {
+
+        // Commented out because java.net.URL ignores extraneous "../"
+        //        negative("http://a/b/c/d;p?q", "../../../g");
+        //        negative("http://a/b/c/d;p?q", "/../g");
+
+    }
+
+
+    /**
+     * Positive tests for absolute URL strings in various patterns.
+     */
+    public void testPositiveAbsolute() {
+
+        positive("http://a/b/c/d;p?q");
+
+        positive("http://localhost/index.html");
+        positive("http://localhost/index.html#ref");
+        positive("http://localhost/index.html?name=value");
+        positive("http://localhost/index.html?name=value#ref");
+
+        positive("http://localhost:8080/index.html");
+        positive("http://localhost:8080/index.html#ref");
+        positive("http://localhost:8080/index.html?name=value");
+        positive("http://localhost:8080/index.html?name=value#ref");
+
+        positive("http://localhost/index.html/.");
+        positive("http://localhost/index.html/.#ref");
+        positive("http://localhost/index.html/.?name=value");
+        positive("http://localhost/index.html/.?name=value#ref");
+
+        positive("http://localhost:8080/index.html/.");
+        positive("http://localhost:8080/index.html/.#ref");
+        positive("http://localhost:8080/index.html/.?name=value");
+        positive("http://localhost:8080/index.html/.?name=value#ref");
+
+        positive("http://localhost/index.html/foo/..");
+        positive("http://localhost/index.html/foo/..#ref");
+        positive("http://localhost/index.html/foo/..?name=value");
+        positive("http://localhost/index.html/foo/..?name=value#ref");
+
+        positive("http://localhost:8080/index.html/foo/..");
+        positive("http://localhost:8080/index.html/foo/..#ref");
+        positive("http://localhost:8080/index.html/foo/..?name=value");
+        positive("http://localhost:8080/index.html/foo/..?name=value#ref");
+
+        positive("http://localhost/index.html/../foo.html");
+        positive("http://localhost/index.html/../foo.html#ref");
+        positive("http://localhost/index.html/../foo.html?name=value");
+        positive("http://localhost/index.html/../foo.html?name=value#ref");
+
+        positive("http://localhost:8080/index.html/../foo.html");
+        positive("http://localhost:8080/index.html/../foo.html#ref");
+        positive("http://localhost:8080/index.html/../foo.html?name=value");
+        positive("http://localhost:8080/index.html/../foo.html?name=value#ref");
+
+        positive("http://localhost");
+        positive("http://localhost#ref");
+        positive("http://localhost?name=value");
+        positive("http://localhost?name=value#ref");
+
+        positive("http://localhost:8080");
+        positive("http://localhost:8080#ref");
+        positive("http://localhost:8080?name=value");
+        positive("http://localhost:8080?name=value#ref");
+
+        positive("http://localhost/");
+        positive("http://localhost/#ref");
+        positive("http://localhost/?name=value");
+        positive("http://localhost/?name=value#ref");
+
+        positive("http://localhost:8080/");
+        positive("http://localhost:8080/#ref");
+        positive("http://localhost:8080/?name=value");
+        positive("http://localhost:8080/?name=value#ref");
+
+    }
+
+
+    /**
+     * Positive tests for normalizing absolute URL strings in various patterns.
+     */
+    public void testPositiveNormalize() {
+
+        normalize("http://a/b/c/d;p?q",
+                  "http://a/b/c/d;p?q");
+
+        normalize("http://localhost/index.html",
+                  "http://localhost/index.html");
+        normalize("http://localhost/index.html#ref",
+                  "http://localhost/index.html#ref");
+        normalize("http://localhost/index.html?name=value",
+                  "http://localhost/index.html?name=value");
+        normalize("http://localhost/index.html?name=value#ref",
+                  "http://localhost/index.html?name=value#ref");
+
+        normalize("http://localhost:8080/index.html",
+                  "http://localhost:8080/index.html");
+        normalize("http://localhost:8080/index.html#ref",
+                  "http://localhost:8080/index.html#ref");
+        normalize("http://localhost:8080/index.html?name=value",
+                  "http://localhost:8080/index.html?name=value");
+        normalize("http://localhost:8080/index.html?name=value#ref",
+                  "http://localhost:8080/index.html?name=value#ref");
+
+        normalize("http://localhost/./index.html",
+                  "http://localhost/index.html");
+        normalize("http://localhost/./index.html#ref",
+                  "http://localhost/index.html#ref");
+        normalize("http://localhost/./index.html?name=value",
+                  "http://localhost/index.html?name=value");
+        normalize("http://localhost/./index.html?name=value#ref",
+                  "http://localhost/index.html?name=value#ref");
+
+        normalize("http://localhost:8080/./index.html",
+                  "http://localhost:8080/index.html");
+        normalize("http://localhost:8080/./index.html#ref",
+                  "http://localhost:8080/index.html#ref");
+        normalize("http://localhost:8080/./index.html?name=value",
+                  "http://localhost:8080/index.html?name=value");
+        normalize("http://localhost:8080/./index.html?name=value#ref",
+                  "http://localhost:8080/index.html?name=value#ref");
+
+        normalize("http://localhost/index.html/.",
+                  "http://localhost/index.html/");
+        normalize("http://localhost/index.html/.#ref",
+                  "http://localhost/index.html/#ref");
+        normalize("http://localhost/index.html/.?name=value",
+                  "http://localhost/index.html/?name=value");
+        normalize("http://localhost/index.html/.?name=value#ref",
+                  "http://localhost/index.html/?name=value#ref");
+
+        normalize("http://localhost:8080/index.html/.",
+                  "http://localhost:8080/index.html/");
+        normalize("http://localhost:8080/index.html/.#ref",
+                  "http://localhost:8080/index.html/#ref");
+        normalize("http://localhost:8080/index.html/.?name=value",
+                  "http://localhost:8080/index.html/?name=value");
+        normalize("http://localhost:8080/index.html/.?name=value#ref",
+                  "http://localhost:8080/index.html/?name=value#ref");
+
+        normalize("http://localhost/index.html/./",
+                  "http://localhost/index.html/");
+        normalize("http://localhost/index.html/./#ref",
+                  "http://localhost/index.html/#ref");
+        normalize("http://localhost/index.html/./?name=value",
+                  "http://localhost/index.html/?name=value");
+        normalize("http://localhost/index.html/./?name=value#ref",
+                  "http://localhost/index.html/?name=value#ref");
+
+        normalize("http://localhost:8080/index.html/./",
+                  "http://localhost:8080/index.html/");
+        normalize("http://localhost:8080/index.html/./#ref",
+                  "http://localhost:8080/index.html/#ref");
+        normalize("http://localhost:8080/index.html/./?name=value",
+                  "http://localhost:8080/index.html/?name=value");
+        normalize("http://localhost:8080/index.html/./?name=value#ref",
+                  "http://localhost:8080/index.html/?name=value#ref");
+
+        normalize("http://localhost/foo.html/../index.html",
+                  "http://localhost/index.html");
+        normalize("http://localhost/foo.html/../index.html#ref",
+                  "http://localhost/index.html#ref");
+        normalize("http://localhost/foo.html/../index.html?name=value",
+                  "http://localhost/index.html?name=value");
+        normalize("http://localhost/foo.html/../index.html?name=value#ref",
+                  "http://localhost/index.html?name=value#ref");
+
+        normalize("http://localhost:8080/foo.html/../index.html",
+                  "http://localhost:8080/index.html");
+        normalize("http://localhost:8080/foo.html/../index.html#ref",
+                  "http://localhost:8080/index.html#ref");
+        normalize("http://localhost:8080/foo.html/../index.html?name=value",
+                  "http://localhost:8080/index.html?name=value");
+        normalize("http://localhost:8080/foo.html/../index.html?name=value#ref",
+                  "http://localhost:8080/index.html?name=value#ref");
+
+        normalize("http://localhost/index.html/foo.html/..",
+                  "http://localhost/index.html/");
+        normalize("http://localhost/index.html/foo.html/..#ref",
+                  "http://localhost/index.html/#ref");
+        normalize("http://localhost/index.html/foo.html/..?name=value",
+                  "http://localhost/index.html/?name=value");
+        normalize("http://localhost/index.html/foo.html/..?name=value#ref",
+                  "http://localhost/index.html/?name=value#ref");
+
+        normalize("http://localhost:8080/index.html/foo.html/..",
+                  "http://localhost:8080/index.html/");
+        normalize("http://localhost:8080/index.html/foo.html/..#ref",
+                  "http://localhost:8080/index.html/#ref");
+        normalize("http://localhost:8080/index.html/foo.html/..?name=value",
+                  "http://localhost:8080/index.html/?name=value");
+        normalize("http://localhost:8080/index.html/foo.html/..?name=value#ref",
+                  "http://localhost:8080/index.html/?name=value#ref");
+
+        normalize("http://localhost/index.html/foo.html/../",
+                  "http://localhost/index.html/");
+        normalize("http://localhost/index.html/foo.html/../#ref",
+                  "http://localhost/index.html/#ref");
+        normalize("http://localhost/index.html/foo.html/../?name=value",
+                  "http://localhost/index.html/?name=value");
+        normalize("http://localhost/index.html/foo.html/../?name=value#ref",
+                  "http://localhost/index.html/?name=value#ref");
+
+        normalize("http://localhost:8080/index.html/foo.html/../",
+                  "http://localhost:8080/index.html/");
+        normalize("http://localhost:8080/index.html/foo.html/../#ref",
+                  "http://localhost:8080/index.html/#ref");
+        normalize("http://localhost:8080/index.html/foo.html/../?name=value",
+                  "http://localhost:8080/index.html/?name=value");
+        normalize("http://localhost:8080/index.html/foo.html/../?name=value#ref",
+                  "http://localhost:8080/index.html/?name=value#ref");
+
+    }
+
+
+    /**
+     * Positive tests for relative URL strings in various patterns.
+     */
+    public void testPositiveRelative() {
+
+        // Test cases based on RFC 2396, Appendix C
+        positive("http://a/b/c/d;p?q", "http:h");
+        positive("http://a/b/c/d;p?q", "g");
+        positive("http://a/b/c/d;p?q", "./g");
+        positive("http://a/b/c/d;p?q", "g/");
+        positive("http://a/b/c/d;p?q", "/g");
+        //        positive("http://a/b/c/d;p?q", "//g");
+        positive("http://a/b/c/d;p?q", "?y");
+        positive("http://a/b/c/d;p?q", "g?y");
+        //        positive("http://a/b/c/d;p?q", "#s");
+        positive("http://a/b/c/d;p?q", "g#s");
+        positive("http://a/b/c/d;p?q", "g?y#s");
+        positive("http://a/b/c/d;p?q", ";x");
+        positive("http://a/b/c/d;p?q", "g;x");
+        positive("http://a/b/c/d;p?q", "g;x?y#s");
+        positive("http://a/b/c/d;p?q", ".");
+        positive("http://a/b/c/d;p?q", "./");
+        positive("http://a/b/c/d;p?q", "..");
+        positive("http://a/b/c/d;p?q", "../");
+        positive("http://a/b/c/d;p?q", "../g");
+        positive("http://a/b/c/d;p?q", "../..");
+        positive("http://a/b/c/d;p?q", "../../");
+        positive("http://a/b/c/d;p?q", "../../g");
+        // Commented because java.net.URL doesn't normalize out the "/./"????
+        //        positive("http://a/b/c/d;p?q", "/./g");
+        positive("http://a/b/c/d;p?q", "g.");
+        positive("http://a/b/c/d;p?q", ".g");
+        positive("http://a/b/c/d;p?q", "g..");
+        positive("http://a/b/c/d;p?q", "..g");
+        positive("http://a/b/c/d;p?q", "./../g");
+        positive("http://a/b/c/d;p?q", "./g/.");
+        positive("http://a/b/c/d;p?q", "g/./h");
+        positive("http://a/b/c/d;p?q", "g/../h");
+        positive("http://a/b/c/d;p?q", "g;x=1/./y");
+        positive("http://a/b/c/d;p?q", "g;x=1/../y");
+        positive("http://a/b/c/d;p?q", "g?y/./x");
+        positive("http://a/b/c/d;p?q", "g?y/../x");
+        positive("http://a/b/c/d;p?q", "g#s/./x");
+        positive("http://a/b/c/d;p?q", "g#s/../x");
+        positive("http://a/b", "c");
+        positive("http://a/b/", "c");
+
+    }
+
+
+    // -------------------------------------------------------- Private Methods
+
+
+    /**
+     * Check that both our URL class and <code>java.net.URL</code> throw
+     * <code>MalformedURLException</code> on an absolute URL specification.
+     *
+     * @param spec Absolute URL specification to be checked
+     */
+    private void negative(String spec) {
+
+        try {
+            java.net.URL url = new java.net.URL(spec);
+            fail(spec + " should have failed on java.net.URL " +
+                 "but returned " + url.toExternalForm());
+        } catch (MalformedURLException e) {
+            ; // Expected response
+        }
+
+        try {
+            URL url = new URL(spec);
+            fail(spec + " should have failed on tested URL " +
+                 "but returned " + url.toExternalForm());
+        } catch (MalformedURLException e) {
+            ; // Expected response
+        }
+
+    }
+
+
+    /**
+     * Check that both our URL class and <code>java.net.URL</code> throw
+     * <code>MalformedURLException</code> on an absolute URL specification
+     * plus the corresponding relative URL specification.
+     *
+     * @param abs Absolute URL specification to be checked
+     * @param rel Relative URL specification to be checked
+     */
+    private void negative(String abs, String rel) {
+
+        java.net.URL baseNet = null;
+        URL baseUrl = null;
+
+        try {
+            baseNet = new java.net.URL(abs);
+        } catch (MalformedURLException e) {
+            fail(abs + " net URL threw " + e);
+        }
+
+        try {
+            baseUrl = new URL(abs);
+        } catch (MalformedURLException e) {
+            fail(abs + " url URL threw " + e);
+        }
+
+        try {
+            java.net.URL url = new java.net.URL(baseNet, rel);
+            fail(rel + " should have failed on java.net.URL " +
+                 "but returned " + url.toExternalForm());
+        } catch (MalformedURLException e) {
+            ; // Expected response
+        }
+
+        try {
+            URL url = new URL(baseUrl, rel);
+            fail(rel + " should have failed on tested URL " +
+                 "but returned " + url.toExternalForm());
+        } catch (MalformedURLException e) {
+            ; // Expected response
+        }
+
+    }
+
+
+    /**
+     * Attempts to normalize the specified URL should throw
+     * MalformedURLException.
+     *
+     * @param spec Unnormalized version of the URL specification
+     */
+    private void normalize(String spec) {
+
+        URL url = null;
+        try {
+            url = new URL(spec);
+        } catch (Throwable t) {
+            fail(spec + " should not have thrown " + t);
+        }
+
+        try {
+            url.normalize();
+            fail(spec + ".normalize() should have thrown MUE");
+        } catch (MalformedURLException e) {
+            ; // Expected result
+        }
+
+    }
+
+
+    /**
+     * It should be possible to normalize the specified URL into the
+     * specified normalized form.
+     *
+     * @param spec Unnormalized version of the URL specification
+     * @param norm Normalized version of the URL specification
+     */
+    private void normalize(String spec, String norm) {
+
+        try {
+            URL url = new URL(spec);
+            url.normalize();
+            assertEquals(spec + ".normalize()", norm, url.toExternalForm());
+        } catch (Throwable t) {
+            fail(spec + ".normalize() threw " + t);
+        }
+
+    }
+
+
+    /**
+     * Check the details of our URL class against <code>java.net.URL</code>
+     * for an absolute URL specification.
+     *
+     * @param spec Absolute URL specification to be checked
+     */
+    private void positive(String spec) {
+
+        // Compare results with what java.net.URL returns
+        try {
+            URL url = new URL(spec);
+            java.net.URL net = new java.net.URL(spec);
+            assertEquals(spec + " toExternalForm()",
+                         net.toExternalForm(),
+                         url.toExternalForm());
+            assertEquals(spec + ".getAuthority()",
+                         net.getAuthority(),
+                         url.getAuthority());
+            assertEquals(spec + ".getFile()",
+                         net.getFile(),
+                         url.getFile());
+            assertEquals(spec + ".getHost()",
+                         net.getHost(),
+                         url.getHost());
+            assertEquals(spec + ".getPath()",
+                         net.getPath(),
+                         url.getPath());
+            assertEquals(spec + ".getPort()",
+                         net.getPort(),
+                         url.getPort());
+            assertEquals(spec + ".getProtocol()",
+                         net.getProtocol(),
+                         url.getProtocol());
+            assertEquals(spec + ".getQuery()",
+                         net.getQuery(),
+                         url.getQuery());
+            assertEquals(spec + ".getRef()",
+                         net.getRef(),
+                         url.getRef());
+            assertEquals(spec + ".getUserInfo()",
+                         net.getUserInfo(),
+                         url.getUserInfo());
+        } catch (Throwable t) {
+            fail(spec + " positive test threw " + t);
+        }
+
+    }
+
+
+    /**
+     * Check the details of our URL class against <code>java.net.URL</code>
+     * for a relative URL specification.
+     *
+     * @param abs Absolute URL specification for base reference
+     * @param rel Relative URL specification to resolve
+     */
+    private void positive(String abs, String rel) {
+
+        // Compare results with what java.net.URL returns
+        try {
+            URL urlBase = new URL(abs);
+            java.net.URL netBase = new java.net.URL(abs);
+            URL url = new URL(urlBase, rel);
+            java.net.URL net = new java.net.URL(netBase, rel);
+            assertEquals(rel + " toExternalForm()",
+                         net.toExternalForm(),
+                         url.toExternalForm());
+            assertEquals(rel + ".getAuthority()",
+                         net.getAuthority(),
+                         url.getAuthority());
+            assertEquals(rel + ".getFile()",
+                         net.getFile(),
+                         url.getFile());
+            assertEquals(rel + ".getHost()",
+                         net.getHost(),
+                         url.getHost());
+            assertEquals(rel + ".getPath()",
+                         net.getPath(),
+                         url.getPath());
+            assertEquals(rel + ".getPort()",
+                         net.getPort(),
+                         url.getPort());
+            assertEquals(rel + ".getProtocol()",
+                         net.getProtocol(),
+                         url.getProtocol());
+            assertEquals(rel + ".getQuery()",
+                         net.getQuery(),
+                         url.getQuery());
+            assertEquals(rel + ".getRef()",
+                         net.getRef(),
+                         url.getRef());
+            assertEquals(rel + ".getUserInfo()",
+                         net.getUserInfo(),
+                         url.getUserInfo());
+        } catch (Throwable t) {
+            fail(rel + " positive test threw " + t);
+        }
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/test/org/apache/naming/resources/BaseDirContextTestCase.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/test/org/apache/naming/resources/BaseDirContextTestCase.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/test/org/apache/naming/resources/BaseDirContextTestCase.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,541 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.naming.resources;
+
+import java.util.Date;
+
+import javax.naming.Binding;
+import javax.naming.NameClassPair;
+import javax.naming.NamingEnumeration;
+import javax.naming.NamingException;
+
+import javax.naming.directory.Attribute;
+import javax.naming.directory.Attributes;
+import javax.naming.directory.DirContext;
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+
+
+/**
+ * <p>Basic unit tests for the <code>javax.naming.directory.DirContext</code>
+ * implementations.  This class must be subclassed for each individual
+ * <code>DirContext</code> implementation.</p>
+ *
+ * <p><strong>WARNING</strong>:  These tests make certain assumptions that
+ * can generate "false negative" results if they are violated:</p>
+ * <ul>
+ * <li>The pathname of a directory (or WAR file) containing the static
+ *     resources of the <code>/examples</code> web application shipped
+ *     with Tomcat is passed to our test class as a system property
+ *     named <code>doc.base</code>.</li>
+ * <li>The entry names that can be found in the top-level DirContext of
+ *     the static resources are enumerated in the <code>topLevelNames</code>
+ *     variable.</li>
+ * <li>The entry names that can be found in the WEB-INF DirContext of
+ *     the static resources are enumerated in the <code>webInfNames</code>
+ *     variable.</li>
+ * <li>The entry names in either the top-level or WEB-INF DirContext contexts
+ *     that should themselves be <code>DirContext</code> implementations (i.e.
+ *     "subdirectories" in the static resources for this web application)
+ *     are enumerated in the <code>dirContextNames</code> variable.</li>
+ * </ul>
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public abstract class BaseDirContextTestCase extends TestCase {
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * A directory context implementation to be tested.
+     */
+    protected DirContext context = null;
+
+
+    /**
+     * The pathname of the document base directory for this directory context.
+     */
+    protected String docBase = System.getProperty("doc.base");
+
+
+    /**
+     * Entry names that must be DirContexts.  Names not on this list are
+     * assumed to be Resources.
+     */
+    protected static final String dirContextNames[] =
+    { "classes", "images", "jsp", "lib", "META-INF", "WEB-INF" };
+
+
+    /**
+     * The set of names that should be present in the top-level
+     * directory context.
+     */
+    protected static final String topLevelNames[] =
+    { "index.jsp", "jakarta-banner.gif", "tomcat.gif", "tomcat-power.gif", "META-INF", "WEB-INF" };
+
+    /**
+     * The set of names that should be present in the WEB-INF
+     * directory context.
+     */
+    protected static final String webInfNames[] =
+    { "classes", "jsp", "lib", "web.xml" };
+
+
+    /**
+     * The set of names that should be attributes of WEB-INF.
+     */
+    protected static final String webInfAttrs[] =
+    { "creationdate", "displayname", "getcontentlength", "getlastmodified",
+      "resourcetype" };
+
+
+    /**
+     * The set of names that should be attributes of WEB-INF/web.xml.
+     */
+    protected static final String webXmlAttrs[] =
+    { "creationdate", "displayname", "getcontentlength", "getlastmodified",
+      "resourcetype" };
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Construct a new instance of this test case.
+     *
+     * @param name Name of the test case
+     */
+    public BaseDirContextTestCase(String name) {
+
+        super(name);
+
+    }
+
+
+    // --------------------------------------------------- Overall Test Methods
+
+
+    /**
+     * Set up instance variables required by this test case.  This method
+     * <strong>MUST</strong> be implemented by a subclass.
+     */
+    public abstract void setUp();
+
+
+    /**
+     * Return the tests included in this test suite.  This method
+     * <strong>MUST</strong> be implemented by a subclass.
+     */
+    // public abstract static Test suite();
+
+
+    /**
+     * Tear down instance variables required by this test case.  This method
+     * <strong>MUST</strong> be implemented by a subclass.
+     */
+    public abstract void tearDown();
+
+
+    // ------------------------------------------------ Individual Test Methods
+
+
+    /**
+     * Test the attributes returned for the <code>WEB-INF</code> entry.
+     */
+    public abstract void testGetAttributesWebInf();
+
+
+    /**
+     * Test the attributes returned for the <code>WEB-INF/web.xml</code>
+     * entry.
+     */
+    public abstract void testGetAttributesWebXml();
+
+
+    /**
+     * We should be able to list the contents of the top-level context itself,
+     * and locate some entries we know are there.
+     */
+    public void testListTopLevel() {
+
+        try {
+            checkList(context.list(""), topLevelNames);
+        } catch (NamingException e) {
+            fail("NamingException: " + e);
+        }
+
+    }
+
+
+    /**
+     * We should be able to list the contents of the WEB-INF entry,
+     * and locate some entries we know are there.
+     */
+    public void testListWebInfDirect() {
+
+        try {
+
+            // Look up the WEB-INF entry
+            Object webInfEntry = context.lookup("WEB-INF");
+            assertNotNull("Found WEB-INF entry", webInfEntry);
+            assertTrue("WEB-INF entry is a DirContext",
+                   webInfEntry instanceof DirContext);
+            DirContext webInfContext = (DirContext) webInfEntry;
+
+            // Check the contents of the WEB-INF context directly
+            checkList(webInfContext.list(""), webInfNames);
+
+        } catch (NamingException e) {
+            fail("NamingException: " + e);
+        }
+
+
+    }
+
+
+    /**
+     * We should be able to list the contents of the WEB-INF entry,
+     * and locate some entries we know are there.
+     */
+    public void testListWebInfIndirect() {
+
+        try {
+            checkList(context.list("WEB-INF"), webInfNames);
+        } catch (NamingException e) {
+            fail("NamingException: " + e);
+        }
+
+    }
+
+
+    /**
+     * We should be able to list the bindings of the top-level context itself,
+     * and locate some entries we know are there.
+     */
+    public void testListBindingsTopLevel() {
+
+        try {
+            checkListBindings(context.listBindings(""), topLevelNames);
+        } catch (NamingException e) {
+            fail("NamingException: " + e);
+        }
+
+    }
+
+
+    /**
+     * We should be able to list the bindings of the WEB-INF entry,
+     * and locate some entries we know are there.
+     */
+    public void testListBindingsWebInfDirect() {
+
+        try {
+
+            // Look up the WEB-INF entry
+            Object webInfEntry = context.lookup("WEB-INF");
+            assertNotNull("Found WEB-INF entry", webInfEntry);
+            assertTrue("WEB-INF entry is a DirContext",
+                   webInfEntry instanceof DirContext);
+            DirContext webInfContext = (DirContext) webInfEntry;
+
+            // Check the bindings of the WEB-INF context directly
+            checkListBindings(webInfContext.listBindings(""), webInfNames);
+
+        } catch (NamingException e) {
+            fail("NamingException: " + e);
+        }
+
+
+    }
+
+
+    /**
+     * We should be able to list the bindings of the WEB-INF entry,
+     * and locate some entries we know are there.
+     */
+    public void testListBindingsWebInfIndirect() {
+
+        try {
+            checkListBindings(context.listBindings("WEB-INF"), webInfNames);
+        } catch (NamingException e) {
+            fail("NamingException: " + e);
+        }
+
+    }
+
+
+    // -------------------------------------------------------- Support Methods
+
+
+    /**
+     * Check the results of a list() call against the specified entry list.
+     *
+     * @param enum The naming enumeration we are checking
+     * @param list The list of entry names we are expecting
+     *
+     * @exception NamingException if a naming exception occurs
+     */
+    protected void checkList(NamingEnumeration ne, String list[])
+        throws NamingException {
+
+        String contextClassName = context.getClass().getName();
+
+        assertNotNull("NamingEnumeration is not null", ne);
+        while (ne.hasMore()) {
+
+            Object next = ne.next();
+            assertTrue("list() returns NameClassPair instances",
+                   next instanceof NameClassPair);
+            NameClassPair ncp = (NameClassPair) next;
+
+            assertTrue("Name '" + ncp.getName() + "' is expected",
+                   isListed(ncp.getName(), list));
+
+            if (isDirContext(ncp.getName())) {
+                assertTrue("Class '" + ncp.getClassName() + "' is '" +
+                       contextClassName + "'",
+                       contextClassName.equals(ncp.getClassName()));
+            }
+
+            assertTrue("Relative is 'true'", ncp.isRelative());
+
+        }
+
+    }
+
+
+    /**
+     * Check the results of a listBindings() call against the
+     * specified entry list.
+     *
+     * @param enum The naming enumeration we are checking
+     * @param list The list of entry names we are expecting
+     *
+     * @exception NamingException if a naming exception occurs
+     */
+    protected void checkListBindings(NamingEnumeration ne, String list[])
+        throws NamingException {
+
+        String contextClassName = context.getClass().getName();
+
+        assertNotNull("NamingEnumeration is not null", ne);
+        while (ne.hasMore()) {
+
+            Object next = ne.next();
+            assertTrue("listBindings() returns Binding instances",
+                   next instanceof Binding);
+            Binding b = (Binding) next;
+
+            assertTrue("Name '" + b.getName() + "' is expected",
+                   isListed(b.getName(), list));
+
+            if (isDirContext(b.getName())) {
+                assertTrue("Class '" + b.getClassName() + "' is '" +
+                       contextClassName + "'",
+                       contextClassName.equals(b.getClassName()));
+            }
+
+            assertTrue("Relative is 'true'", b.isRelative());
+
+            Object object = b.getObject();
+            assertNotNull("Name '" + b.getName() + "' has a non-null object",
+                          object);
+            if(isDirContext(b.getName())) {
+            	assertTrue("Entry '" + b.getName() + "' is a DirContext",
+                        object instanceof DirContext);          	
+            }  else {
+            	assertTrue("Entry '" + b.getName() + "' is a Resource",
+                       object instanceof Resource); 
+            }
+
+        }
+
+    }
+
+
+    /**
+     * Check the attributes associated with a WEB-INF entry.
+     *
+     * @param attrs The attributes for this entry
+     * @param creationDate The creation date for this entry
+     * @param contentLength The content length for this entry
+     * @param displayName The display name for this entry
+     * @param lastModifiedDate The last modified date for this entry
+     */
+    protected void checkWebInfAttributes(Attributes attrs,
+                                         Date creationDate,
+                                         long contentLength,
+                                         String displayName,
+                                         Date lastModifiedDate)
+        throws NamingException {
+
+        assertNotNull("getAttributes() returned non-null", attrs);
+
+        NamingEnumeration ne = attrs.getAll();
+        assertNotNull("getAll() returned non-null", ne);
+        while (ne.hasMore()) {
+
+            Object next = ne.next();
+            assertTrue("getAll() returns Attribute instances",
+                   next instanceof Attribute);
+            Attribute attr = (Attribute) next;
+            String name = attr.getID();
+            int index = getIndex(name, webInfAttrs);
+            assertTrue("WEB-INF attribute '" + name + "' is expected",
+                   index >= 0);
+            Object value = attr.get();
+            assertNotNull("get() returned non-null", value);
+
+            if (name.equals("creationdate")) {
+                assertTrue("Creation date is a date",
+                       value instanceof Date);
+                assertTrue("Creation date equals " + creationDate,
+                       creationDate.equals((Date) value));
+            } else if (name.equals("displayname")) {
+                assertTrue("Display name is a string",
+                       value instanceof String);
+                assertTrue("Display name equals " + displayName,
+                       displayName.equals((String) value));
+            } else if (name.equals("getcontentlength")) {
+                assertTrue("Content length is a long",
+                       value instanceof Long);
+                assertTrue("Content length equals " + contentLength,
+                       contentLength == ((Long) value).longValue());
+            } else if (name.equals("getlastmodified")) {
+                assertTrue("Last modified date is a date",
+                       value instanceof Date);
+                assertTrue("Last modified date is " + lastModifiedDate,
+                       lastModifiedDate.equals((Date) value));
+            }
+
+        }
+
+    }
+
+
+    /**
+     * Check the attributes associated with a WEB-INF/web.xml entry.
+     *
+     * @param attrs The attributes for this entry
+     * @param creationDate The creation date for this entry
+     * @param contentLength The content length for this entry
+     * @param displayName The display name for this entry
+     * @param lastModifiedDate The last modified date for this entry
+     */
+    protected void checkWebXmlAttributes(Attributes attrs,
+                                         Date creationDate,
+                                         long contentLength,
+                                         String displayName,
+                                         Date lastModifiedDate)
+        throws NamingException {
+
+        assertNotNull("getAttributes() returned non-null", attrs);
+
+        NamingEnumeration ne = attrs.getAll();
+        assertNotNull("getAll() returned non-null", ne);
+        while (ne.hasMore()) {
+
+            Object next = ne.next();
+            assertTrue("getAll() returns Attribute instances",
+                   next instanceof Attribute);
+            Attribute attr = (Attribute) next;
+            String name = attr.getID();
+            int index = getIndex(name, webXmlAttrs);
+            assertTrue("WEB-INF/web.xml attribute '" + name + "' is expected",
+                   index >= 0);
+            Object value = attr.get();
+            assertNotNull("get() returned non-null", value);
+
+            if (name.equals("creationdate")) {
+                assertTrue("Creation date is a date",
+                       value instanceof Date);
+                assertTrue("Creation date equals " + creationDate,
+                       creationDate.equals((Date) value));
+            } else if (name.equals("displayname")) {
+                assertTrue("Display name is a string",
+                       value instanceof String);
+                assertTrue("Display name equals " + displayName,
+                       displayName.equals((String) value));
+            } else if (name.equals("getcontentlength")) {
+                assertTrue("Content length is a long",
+                       value instanceof Long);
+                assertTrue("Content length equals " + contentLength,
+                       contentLength == ((Long) value).longValue());
+            } else if (name.equals("getlastmodified")) {
+                assertTrue("Last modified date is a date",
+                       value instanceof Date);
+                assertTrue("Last modified date is " + lastModifiedDate,
+                       lastModifiedDate.equals((Date) value));
+            }
+
+        }
+
+    }
+
+
+    /**
+     * Return the index of the specified name in the specified list, or
+     * -1 if the name is not present.
+     *
+     * @param name Name to be looked up
+     * @param list List of names to be checked
+     */
+    protected int getIndex(String name, String list[]) {
+
+        for (int i = 0; i < list.length; i++) {
+            if (name.equals(list[i]))
+                return (i);
+        }
+        return (-1);
+
+    }
+
+
+    /**
+     * Is an entry of the specified name supposed to be a DirContext?
+     *
+     * @param name Name to be checked
+     */
+    protected boolean isDirContext(String name) {
+
+        return (isListed(name, dirContextNames));
+
+    }
+
+
+    /**
+     * Returns <code>true</code> if the specified name is found in the
+     * specified list.
+     *
+     * @param name Name to be looked up
+     * @param list List to be looked up into
+     */
+    protected boolean isListed(String name, String list[]) {
+
+        return (getIndex(name, list) >= 0);
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/test/org/apache/naming/resources/FileDirContextTestCase.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/test/org/apache/naming/resources/FileDirContextTestCase.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/test/org/apache/naming/resources/FileDirContextTestCase.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,165 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.naming.resources;
+
+import java.io.File;
+
+import java.util.Date;
+
+import javax.naming.NamingException;
+
+import javax.naming.directory.Attribute;
+import javax.naming.directory.Attributes;
+import javax.naming.directory.DirContext;
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+
+
+/**
+ * Unit tests for <code>org.apache.naming.resources.FileDirContext</code>.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class FileDirContextTestCase extends BaseDirContextTestCase {
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Construct a new instance of this test case.
+     *
+     * @param name Name of the test case
+     */
+    public FileDirContextTestCase(String name) {
+
+        super(name);
+
+    }
+
+
+    // --------------------------------------------------- Overall Test Methods
+
+
+    /**
+     * Set up instance variables required by this test case.  This method
+     * <strong>MUST</strong> be implemented by a subclass.
+     */
+    public void setUp() {
+
+        context = new FileDirContext();
+        ((FileDirContext) context).setDocBase(docBase);
+
+    }
+
+
+    /**
+     * Return the tests included in this test suite.  This method
+     * <strong>MUST</strong> be implemented by a subclass.
+     */
+    public static Test suite() {
+
+        return (new TestSuite(FileDirContextTestCase.class));
+
+    }
+
+
+    /**
+     * Tear down instance variables required by this test case.  This method
+     * <strong>MUST</strong> be implemented by a subclass.
+     */
+    public void tearDown() {
+
+        context = null;
+
+    }
+
+
+    // ------------------------------------------------ Individual Test Methods
+
+
+    /**
+     * Test the attributes returned for the <code>WEB-INF</code> entry.
+     */
+    public void testGetAttributesWebInf() {
+
+        try {
+
+            // Identify a local file object for WEB-INF
+            File docBaseFile = new File(docBase);
+            File webInfFile = new File(docBaseFile, "WEB-INF");
+
+            // Look up the attributes for the WEB-INF entry
+            Attributes attributes = context.getAttributes("WEB-INF");
+
+            // Enumerate and check the attributes for this entry
+            checkWebInfAttributes(attributes,
+                                  new Date(webInfFile.lastModified()),
+                                  webInfFile.length(),
+                                  "WEB-INF",
+                                  new Date(webInfFile.lastModified()));
+
+        } catch (NamingException e) {
+
+            fail("NamingException: " + e);
+
+        }
+
+    }
+
+
+    /**
+     * Test the attributes returned for the <code>WEB-INF/web.xml</code>
+     * entry.
+     */
+    public void testGetAttributesWebXml() {
+
+        try {
+
+            // Identify a local file object for WEB-INF/web.xml
+            File docBaseFile = new File(docBase);
+            File webInfFile = new File(docBaseFile, "WEB-INF");
+            File webXmlFile = new File(webInfFile, "web.xml");
+
+            // Look up the attributes for the WEB-INF entry
+            Attributes attributes = context.getAttributes("WEB-INF/web.xml");
+
+            // Enumerate and check the attributes for this entry
+            checkWebXmlAttributes(attributes,
+                                  new Date(webXmlFile.lastModified()),
+                                  webXmlFile.length(),
+                                  "web.xml",
+                                  new Date(webXmlFile.lastModified()));
+
+        } catch (NamingException e) {
+
+            fail("NamingException:  " + e);
+
+        }
+
+    }
+
+
+}
+
+
+

Added: branches/tomcat5.5/upstream/5.5.20/container/catalina/src/test/org/apache/naming/resources/WARDirContextTestCase.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/catalina/src/test/org/apache/naming/resources/WARDirContextTestCase.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/catalina/src/test/org/apache/naming/resources/WARDirContextTestCase.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,179 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.naming.resources;
+
+import java.io.File;
+import java.io.IOException;
+
+import java.util.Date;
+
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+
+import javax.naming.NamingException;
+
+import javax.naming.directory.Attribute;
+import javax.naming.directory.Attributes;
+import javax.naming.directory.DirContext;
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+
+
+/**
+ * Unit tests for <code>org.apache.naming.resources.WARDirContext</code>.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class WARDirContextTestCase extends BaseDirContextTestCase {
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Construct a new instance of this test case.
+     *
+     * @param name Name of the test case
+     */
+    public WARDirContextTestCase(String name) {
+
+        super(name);
+
+    }
+
+
+    // --------------------------------------------------- Overall Test Methods
+
+
+    /**
+     * Set up instance variables required by this test case.  This method
+     * <strong>MUST</strong> be implemented by a subclass.
+     */
+    public void setUp() {
+
+        context = new WARDirContext();
+        ((WARDirContext) context).setDocBase(docBase);
+
+    }
+
+
+    /**
+     * Return the tests included in this test suite.  This method
+     * <strong>MUST</strong> be implemented by a subclass.
+     */
+    public static Test suite() {
+
+        return (new TestSuite(WARDirContextTestCase.class));
+
+    }
+
+
+    /**
+     * Tear down instance variables required by this test case.  This method
+     * <strong>MUST</strong> be implemented by a subclass.
+     */
+    public void tearDown() {
+
+        context = null;
+
+    }
+
+
+    // ------------------------------------------------ Individual Test Methods
+
+
+    /**
+     * Test the attributes returned for the <code>WEB-INF</code> entry.
+     */
+    public void testGetAttributesWebInf() {
+
+        try {
+
+            // Look up the attributes of this WAR file entry
+            JarFile jarFile = new JarFile(docBase);
+            assertNotNull("Created JarFile for " + docBase, jarFile);
+            JarEntry jarEntry =
+                (JarEntry) jarFile.getEntry("WEB-INF");
+            assertNotNull("Created JarEntry for WEB-INF", jarEntry);
+
+            // Look up the attributes for the WEB-INF entry
+            Attributes attributes = context.getAttributes("WEB-INF");
+
+            // Enumerate and check the attributes for this entry
+            checkWebInfAttributes(attributes,
+                                  new Date(jarEntry.getTime()),
+                                  jarEntry.getSize(),
+                                  "WEB-INF",
+                                  new Date(jarEntry.getTime()));
+
+        } catch (IOException e) {
+
+            fail("IOException: " + e);
+
+        } catch (NamingException e) {
+
+            fail("NamingException: " + e);
+
+        }
+
+    }
+
+
+    /**
+     * Test the attributes returned for the <code>WEB-INF/web.xml</code>
+     * entry.
+     */
+    public void testGetAttributesWebXml() {
+
+        try {
+
+            // Look up the attributes of this WAR file entry
+            JarFile jarFile = new JarFile(docBase);
+            assertNotNull("Created JarFile for " + docBase, jarFile);
+            JarEntry jarEntry =
+                (JarEntry) jarFile.getEntry("WEB-INF/web.xml");
+            assertNotNull("Created JarEntry for WEB-INF/web.xml", jarEntry);
+
+            // Look up the attributes for the WEB-INF/web.xml entry
+            Attributes attributes = context.getAttributes("WEB-INF/web.xml");
+
+            // Enumerate and check the attributes for this entry
+            checkWebXmlAttributes(attributes,
+                                  new Date(jarEntry.getTime()),
+                                  jarEntry.getSize(),
+                                  "web.xml",
+                                  new Date(jarEntry.getTime()));
+
+        } catch (IOException e) {
+
+            fail("IOException: " + e);
+
+        } catch (NamingException e) {
+
+            fail("NamingException:  " + e);
+
+        }
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/etc/mx4j.license
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/etc/mx4j.license	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/etc/mx4j.license	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,51 @@
+/* ====================================================================
+ * The MX4J License, Version 1.0
+ *
+ * Copyright (c) 2001 MX4J.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ *    if any, must include the following acknowledgment:
+ *       "This product includes software developed by the
+ *        MX4J project (http://mx4j.sourceforge.net)."
+ *    Alternately, this acknowledgment may appear in the software itself,
+ *    if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "MX4J" and "mx4j" must not be used to endorse or promote
+ *    products derived from this software without prior written
+ *    permission. For written permission, please contact biorn_steedom at users.sourceforge.net
+ *
+ * 5. Products derived from this software may not be called "MX4J",
+ *    nor may "MX4J" appear in their name, without prior written
+ *    permission of Simone Bordet.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL CARLOS QUIROZ OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of MX4J.  For more information on
+ * MX4J, please see
+ * <http://mx4j.sourceforge.net>.
+ */

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/build.properties
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/build.properties	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/build.properties	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,2 @@
+#Uncomment the following line to enable the new cluster set
+#cluster-ha=true

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/build.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/build.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/build.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,95 @@
+<project name="Modules" default="dist" basedir=".">
+
+
+  <!-- ===================== Initialize Property Values =================== -->
+
+  <!-- See "build.properties.sample" in the top level directory for all     -->
+  <!-- property values you must customize for successful building!!!        -->
+  <!--property file="build.properties"/>
+  <property file="../build.properties"/>
+  <property file="${user.home}/build.properties"/-->
+
+  <property file="build.properties"/>
+
+  <!-- =================== BUILD: Create Directories ====================== -->
+  <target name="build-prepare">
+    <available property="jdk1.4.present" classname="java.nio.Buffer" />
+  </target>
+
+
+  <!-- =================== BUILD: Compile Subprojects ===================== -->
+  <!-- Add a new target for each module subproject -->
+
+  <target name="cluster" if="jdk1.4.present" unless="cluster-ha">
+    <ant dir="${basedir}/cluster" target="dist"/>
+  </target>
+
+  <target name="groupcom" if="cluster-ha" >
+    <ant dir="${basedir}/groupcom" target="dist">
+        <property name="groupcom.dist" value="${cluster.dist}"/>
+    </ant>
+  </target>
+
+  <target name="ha" if="cluster-ha" >
+    <ant dir="${basedir}/ha" target="dist">
+        <property name="ha.dist" value="${cluster.dist}"/>
+    </ant>
+  </target>
+  
+  
+  <target name="config" unless="cluster-ha" >
+    <ant dir="${basedir}/storeconfig" target="dist"/>
+  </target>
+
+  <target name="config-ha" if="cluster-ha" >
+    <ant dir="${basedir}/storeconfig-ha" target="dist"/>
+  </target>
+
+
+  <!-- ================= BUILD: Compile Server Components ================= -->
+  <!-- Update the depends list for each subproject -->
+  <target name="build" depends="build-prepare,cluster,groupcom,ha,config-ha,config"/>
+
+
+  <!-- ======================= BUILD: Clean Directory ===================== -->
+  <target name="build-clean">
+  </target>
+
+
+  <!-- ==================== BUILD: Rebuild Everything ===================== -->
+  <target name="all" depends="build-clean,dist"/>
+
+
+  <!-- ================= DEPLOY: Deploy Webapps Projects ================== -->
+  <target name="deploy" depends="dist"
+   description="Build and deploy Modules component">
+
+  </target>
+
+
+  <!-- ================= DIST: Create Distribution Files ================== -->
+  <target name="dist" depends="build"/>
+
+
+  <!-- ======================= DIST: Clean Directory ====================== -->
+  <target name="dist-clean">
+  </target>
+
+
+  <!-- ====================== Convenient Synonyms ========================= -->
+  <target name="clean" depends="build-clean,dist-clean"
+   description="Clean build and dist directories"/>
+
+
+  <!-- ===================== TEST: Compile Unit Tests ===================== -->
+  <target name="build-tests" depends="dist" if="junit.present">
+  </target>
+
+
+  <!-- ===================== TEST: Execute Unit Tests ===================== -->
+  <target name="test" if="junit.present"
+   description="Run all unit test cases">
+  </target>
+
+
+</project>

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/build.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/build.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/build.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,155 @@
+<project name="Cluster" default="dist" basedir=".">
+
+
+  <!-- ===================== Initialize Property Values =================== -->
+
+  <property file="../../../build.properties" />
+  <property file="../../../build/build.properties" />
+  <property file="../../../build/build.properties.default" />
+
+  <!-- Build Defaults -->
+  <property name="catalina.home"  location="../.."/>
+  <property name="catalina.build" location="../../../build/build"/>
+  <property name="cluster.build"  value="${catalina.home}/modules/cluster/build"/>
+  <property name="cluster.dist"   value="${catalina.home}/modules/cluster/dist"/>
+
+    <!-- Construct Catalina classpath -->
+  <path id="cluster.classpath">
+    <pathelement location="${catalina.build}/server/lib/catalina.jar"/>
+    <pathelement location="${catalina.build}/server/lib/tomcat-util.jar"/>
+    <pathelement location="${commons-modeler.jar}"/>
+    <pathelement location="${commons-logging.jar}"/>
+    <pathelement location="${jmx.jar}"/>
+    <pathelement location="${catalina.build}/common/lib/servlet-api.jar"/>
+  </path>
+
+    <!-- Source path -->
+  <path id="javadoc.sourcepath">
+    <pathelement location="src/share"/>
+  </path>
+
+
+  <!-- =================== BUILD: Set compile flags ======================= -->
+  <target name="flags">
+    <!-- JDK flags -->
+    <available property="jdk.1.2.present" classname="java.util.HashMap" />
+    <available property="jdk.1.3.present" 
+     classname="java.lang.reflect.Proxy" />
+    <available property="jdk.1.4.present" classname="java.nio.Buffer" />
+  </target>
+
+
+  <!-- =================== BUILD: Set compile flags ======================= -->
+  <target name="flags.display" depends="flags" unless="flags.hide">
+
+    <echo message="--- Build environment for Catalina ---" />
+
+    <echo message="If ${property_name} is displayed, then the property is not set)" />
+
+    <echo message="--- Build options ---" />
+    <echo message="full.dist=${full.dist}" />
+    <echo message="build.sysclasspath=${build.sysclasspath}" />
+    <echo message="compile.debug=${compile.debug}" />
+    <echo message="compile.deprecation=${compile.deprecation}" />
+    <echo message="compile.optimize=${compile.optimize}" />
+
+    <echo message="--- Ant Flags ---" />
+    <echo message="&lt;style&gt; task available (required)=${style.available}" />
+
+    <echo message="--- JDK ---" />
+    <echo message="jdk.1.2.present=${jdk.1.2.present}" />
+    <echo message="jdk.1.3.present=${jdk.1.3.present}" />
+    <echo message="jdk.1.4.present=${jdk.1.4.present}" />
+
+  </target>
+
+  <!-- =================== BUILD: Create Directories ====================== -->
+  <target name="build-prepare">
+    <mkdir dir="${catalina.build}"/>
+    <mkdir dir="${catalina.build}/classes"/>
+    <mkdir dir="${cluster.dist}"/>
+  </target>
+
+
+
+
+  <!-- ================ BUILD: Compile Catalina Components ================ -->
+  
+  <target name="build-catalina-cluster" depends="build-prepare">
+    <!-- Compile internal server components -->
+    <javac srcdir="${basedir}/src/share" destdir="${catalina.build}/classes"
+           debug="${compile.debug}" deprecation="${compile.deprecation}"
+           optimize="${compile.optimize}"
+           excludes="**/CVS/**"  	   
+    	>
+        <classpath refid="cluster.classpath" />
+    </javac>
+    <copy file="${basedir}/src/share/org/apache/catalina/cluster/LocalStrings.properties"
+    	  tofile="${catalina.build}/classes/org/apache/catalina/cluster/LocalStrings.properties"/>
+    <copy file="${basedir}/src/share/org/apache/catalina/cluster/session/LocalStrings.properties"
+    	  tofile="${catalina.build}/classes/org/apache/catalina/cluster/session/LocalStrings.properties"/>
+    <copy file="${basedir}/src/share/org/apache/catalina/cluster/tcp/LocalStrings.properties"
+    	  tofile="${catalina.build}/classes/org/apache/catalina/cluster/tcp/LocalStrings.properties"/>
+    <copy file="${basedir}/src/share/org/apache/catalina/cluster/tcp/DataSenders.properties"
+    	  tofile="${catalina.build}/classes/org/apache/catalina/cluster/tcp/DataSenders.properties"/>
+    <copy file="${basedir}/src/share/org/apache/catalina/cluster/session/mbeans-descriptors.xml"
+    	  tofile="${catalina.build}/classes/org/apache/catalina/cluster/session/mbeans-descriptors.xml"/>
+    <copy file="${basedir}/src/share/org/apache/catalina/cluster/tcp/mbeans-descriptors.xml"
+    	  tofile="${catalina.build}/classes/org/apache/catalina/cluster/tcp/mbeans-descriptors.xml"/>
+    <copy file="${basedir}/src/share/org/apache/catalina/cluster/mcast/LocalStrings.properties"
+    	  tofile="${catalina.build}/classes/org/apache/catalina/cluster/mcast/LocalStrings.properties"/>
+    <copy file="${basedir}/src/share/org/apache/catalina/cluster/mcast/mbeans-descriptors.xml"
+     	  tofile="${catalina.build}/classes/org/apache/catalina/cluster/mcast/mbeans-descriptors.xml"/>
+   </target>
+
+
+  <!-- ================ BUILD: Create Catalina Javadocs =================== -->
+  <target name="javadoc">
+    <delete dir="${catalina.build}/javadoc"/>
+    <mkdir dir="${catalina.build}/javadoc"/>
+    <javadoc packagenames="org.apache.catalina.*,org.apache.naming.*"
+      classpathref="catalina.classpath"
+      sourcepathref="javadoc.sourcepath"
+      destdir="${catalina.build}/javadoc"
+      author="true"
+      version="true"
+      windowtitle="Catalina Internal API Documentation"
+      doctitle="Catalina API"
+      bottom="Copyright &#169; 2000-2002 Apache Software Foundation.  All Rights Reserved."
+    />
+  </target>
+
+
+  <!-- ======================= BUILD: Clean Directory ===================== -->
+  <target name="build-clean">
+    <delete dir="${catalina.build}"/>
+  </target>
+
+
+  <!-- ==================== BUILD: Rebuild Everything ===================== -->
+
+
+
+
+  <!-- ================ DIST: Create Distribution ========================= -->
+  <target name="dist" depends="build-catalina-cluster">
+    
+    <jar destfile="${cluster.dist}/catalina-cluster.jar"
+         basedir="${catalina.build}/classes">
+       <include name="org/apache/catalina/cluster/**" />
+       <exclude name="**/package.html" />
+       <exclude name="**/LocalStrings_*" />
+    </jar>
+  </target>
+
+  <target name="copy" depends="dist" >
+     <copy file="${cluster.dist}/catalina-cluster.jar" todir="${catalina.build}/server/lib" />
+  </target>
+  
+  <!-- ======================== DIST: Clean Directory ===================== -->
+
+
+  <!-- ====================== Convenient Synonyms ========================= -->
+
+
+</project>

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/etc/cluster-server.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/etc/cluster-server.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/etc/cluster-server.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,368 @@
+<!-- Example Server Configuration File  - Search for Cluster-->
+<!-- Note that component elements are nested corresponding to their
+     parent-child relationships with each other -->
+
+<!-- A "Server" is a singleton element that represents the entire JVM,
+     which may contain one or more "Service" instances.  The Server
+     listens for a shutdown command on the indicated port.
+
+     Note:  A "Server" is not itself a "Container", so you may not
+     define subcomponents such as "Valves" or "Loggers" at this level.
+ -->
+
+<Server port="8005" shutdown="SHUTDOWN" debug="0">
+
+
+  <!-- Comment these entries out to disable JMX MBeans support -->
+  <!-- You may also configure custom components (e.g. Valves/Realms) by 
+       including your own mbean-descriptor file(s), and setting the 
+       "descriptors" attribute to point to a ';' seperated list of paths
+       (in the ClassLoader sense) of files to add to the default list.
+       e.g. descriptors="/com/myfirm/mypackage/mbean-descriptor.xml"
+  -->
+  <Listener className="org.apache.catalina.mbeans.ServerLifecycleListener"
+            debug="0"/>
+  <Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener"
+            debug="0"/>
+  
+  <!-- Global JNDI resources -->
+  <GlobalNamingResources>
+
+    <!-- Test entry for demonstration purposes -->
+    <Environment name="simpleValue" type="java.lang.Integer" value="30"/>
+
+    <!-- Editable user database that can also be used by
+         UserDatabaseRealm to authenticate users -->
+    <Resource name="UserDatabase" auth="Container"
+              type="org.apache.catalina.UserDatabase"
+       description="User database that can be updated and saved">
+    </Resource>
+    <ResourceParams name="UserDatabase">
+      <parameter>
+        <name>factory</name>
+        <value>org.apache.catalina.users.MemoryUserDatabaseFactory</value>
+      </parameter>
+      <parameter>
+        <name>pathname</name>
+        <value>conf/tomcat-users.xml</value>
+      </parameter>
+    </ResourceParams>
+
+  </GlobalNamingResources>
+
+  <!-- A "Service" is a collection of one or more "Connectors" that share
+       a single "Container" (and therefore the web applications visible
+       within that Container).  Normally, that Container is an "Engine",
+       but this is not required.
+
+       Note:  A "Service" is not itself a "Container", so you may not
+       define subcomponents such as "Valves" or "Loggers" at this level.
+   -->
+
+  <!-- Define the Tomcat Stand-Alone Service -->
+  <Service name="Tomcat-Standalone">
+
+    <!-- A "Connector" represents an endpoint by which requests are received
+         and responses are returned.  Each Connector passes requests on to the
+         associated "Container" (normally an Engine) for processing.
+
+         By default, a non-SSL HTTP/1.1 Connector is established on port 8080.
+         You can also enable an SSL HTTP/1.1 Connector on port 8443 by
+         following the instructions below and uncommenting the second Connector
+         entry.  SSL support requires the following steps (see the SSL Config
+         HOWTO in the Tomcat 5 documentation bundle for more detailed
+         instructions):
+         * If your JDK version 1.3 or prior, download and install JSSE 1.0.2 or
+           later, and put the JAR files into "$JAVA_HOME/jre/lib/ext".
+         * Execute:
+             %JAVA_HOME%\bin\keytool -genkey -alias tomcat -keyalg RSA (Windows)
+             $JAVA_HOME/bin/keytool -genkey -alias tomcat -keyalg RSA  (Unix)
+           with a password value of "changeit" for both the certificate and
+           the keystore itself.
+
+         By default, DNS lookups are enabled when a web application calls
+         request.getRemoteHost().  This can have an adverse impact on
+         performance, so you can disable it by setting the
+         "enableLookups" attribute to "false".  When DNS lookups are disabled,
+         request.getRemoteHost() will return the String version of the
+         IP address of the remote client.
+    -->
+
+    <!-- Define a non-SSL Coyote HTTP/1.1 Connector on port 8080 -->
+    <Connector className="org.apache.coyote.tomcat5.CoyoteConnector"
+               port="8080" minProcessors="5" maxProcessors="100"
+               enableLookups="true" redirectPort="8443" acceptCount="100"
+               debug="0" connectionTimeout="20000" 
+               disableUploadTimeout="true" />
+    <!-- Note : To disable connection timeouts, set connectionTimeout value
+     to -1 -->
+
+    <!-- Define a SSL Coyote HTTP/1.1 Connector on port 8443 -->
+    <!--
+    <Connector className="org.apache.coyote.tomcat5.CoyoteConnector"
+               port="8443" minProcessors="5" maxProcessors="75"
+               enableLookups="true" disableUploadTimeout="true"
+           acceptCount="100" debug="0" scheme="https" secure="true">
+      <Factory className="org.apache.coyote.tomcat5.CoyoteServerSocketFactory"
+               clientAuth="false" protocol="TLS" />
+    </Connector>
+    -->
+
+    <!-- Define a Coyote/JK2 AJP 1.3 Connector on port 8009 -->
+    <Connector className="org.apache.coyote.tomcat5.CoyoteConnector"
+               port="8009" minProcessors="5" maxProcessors="75"
+               enableLookups="true" redirectPort="8443"
+               acceptCount="10" debug="0"
+               protocolHandlerClassName="org.apache.jk.server.JkCoyoteHandler"/>
+
+    <!-- Define a Proxied HTTP/1.1 Connector on port 8082 -->
+    <!-- See proxy documentation for more information about using this. -->
+    <!--
+    <Connector className="org.apache.coyote.tomcat5.CoyoteConnector"
+               port="8082" minProcessors="5" maxProcessors="75"
+               enableLookups="true"
+               acceptCount="100" debug="0" connectionTimeout="20000"
+               proxyPort="80" disableUploadTimeout="true" />
+    -->
+
+    <!-- An Engine represents the entry point (within Catalina) that processes
+         every request.  The Engine implementation for Tomcat stand alone
+         analyzes the HTTP headers included with the request, and passes them
+         on to the appropriate Host (virtual host). -->
+
+    <!-- You should set jvmRoute to support load-balancing via JK/JK2 ie :
+    <Engine name="Standalone" defaultHost="localhost" debug="0" jmvRoute="jvm1">         
+    --> 
+         
+    <!-- Define the top level container in our container hierarchy -->
+    <Engine name="Standalone" defaultHost="localhost" debug="0">
+
+      <!-- The request dumper valve dumps useful debugging information about
+           the request headers and cookies that were received, and the response
+           headers and cookies that were sent, for all requests received by
+           this instance of Tomcat.  If you care only about requests to a
+           particular virtual host, or a particular application, nest this
+           element inside the corresponding <Host> or <Context> entry instead.
+
+           For a similar mechanism that is portable to all Servlet 2.4
+           containers, check out the "RequestDumperFilter" Filter in the
+           example application (the source for this filter may be found in
+           "$CATALINA_HOME/webapps/examples/WEB-INF/classes/filters").
+
+           Request dumping is disabled by default.  Uncomment the following
+           element to enable it. -->
+      <!--
+      <Valve className="org.apache.catalina.valves.RequestDumperValve"/>
+      -->
+
+      <!-- Global logger unless overridden at lower levels -->
+      <Logger className="org.apache.catalina.logger.FileLogger"
+              prefix="catalina_log." suffix=".txt"
+              timestamp="true"/>
+
+      <!-- Because this Realm is here, an instance will be shared globally -->
+
+      <!-- This Realm uses the UserDatabase configured in the global JNDI
+           resources under the key "UserDatabase".  Any edits
+           that are performed against this UserDatabase are immediately
+           available for use by the Realm.  -->
+      <Realm className="org.apache.catalina.realm.UserDatabaseRealm"
+                 debug="0" resourceName="UserDatabase"/>
+
+      <!-- Comment out the old realm but leave here for now in case we
+           need to go back quickly -->
+      <!--
+      <Realm className="org.apache.catalina.realm.MemoryRealm" />
+      -->
+
+      <!-- Replace the above Realm with one of the following to get a Realm
+           stored in a database and accessed via JDBC -->
+
+      <!--
+      <Realm  className="org.apache.catalina.realm.JDBCRealm" debug="99"
+             driverName="org.gjt.mm.mysql.Driver"
+          connectionURL="jdbc:mysql://localhost/authority"
+         connectionName="test" connectionPassword="test"
+              userTable="users" userNameCol="user_name" userCredCol="user_pass"
+          userRoleTable="user_roles" roleNameCol="role_name" />
+      -->
+
+      <!--
+      <Realm  className="org.apache.catalina.realm.JDBCRealm" debug="99"
+             driverName="oracle.jdbc.driver.OracleDriver"
+          connectionURL="jdbc:oracle:thin:@ntserver:1521:ORCL"
+         connectionName="scott" connectionPassword="tiger"
+              userTable="users" userNameCol="user_name" userCredCol="user_pass"
+          userRoleTable="user_roles" roleNameCol="role_name" />
+      -->
+
+      <!--
+      <Realm  className="org.apache.catalina.realm.JDBCRealm" debug="99"
+             driverName="sun.jdbc.odbc.JdbcOdbcDriver"
+          connectionURL="jdbc:odbc:CATALINA"
+              userTable="users" userNameCol="user_name" userCredCol="user_pass"
+          userRoleTable="user_roles" roleNameCol="role_name" />
+      -->
+
+      <!-- Define the default virtual host -->
+      <Host name="localhost" debug="0" appBase="webapps"
+       unpackWARs="true" autoDeploy="true">
+       
+        
+        <!-- Defines a cluster for this node,
+             By defining this element, means that every manager will be changed.
+             So when running a cluster, only make sure that you have webapps in there
+             that need to be clustered and remove the other ones.
+             A cluster has the following parameters:
+             
+             className = the fully qualified name of the cluster class
+             
+             name = a descriptive name for your cluster, can be anything
+             
+             debug = the debug level, higher means more output
+             
+             mcastAddr = the multicast address, has to be the same for all the nodes
+             
+             mcastPort = the multicast port, has to be the same for all the nodes
+             
+             mcastFrequency = the number of milliseconds in between sending a "I'm alive" heartbeat
+             
+             mcastDropTime = the number a milliseconds before a node is considered "dead" if no heartbeat is received
+             
+             tcpThreadCount = the number of threads to handle incoming replication requests, optimal would be the same amount of threads as nodes 
+
+             tcpListenAddress = the listen address (bind address) for TCP cluster request on this host, 
+                                in case of multiple ethernet cards.
+                                auto means that address becomes
+                                InetAddress.getLocalHost().getHostAddress()
+
+             tcpListenPort = the tcp listen port
+             
+             tcpSelectorTimeout = the timeout (ms) for the Selector.select() method in case the OS
+                                  has a wakup bug in java.nio. Set to 0 for no timeout
+
+             printToScreen = true means that managers will also print to std.out
+
+             expireSessionsOnShutdown = true means that 
+
+             useDirtyFlag = true means that we only replicate a session after setAttribute,removeAttribute has been called.
+                            false means to replicate the session after each request.
+                            false means that replication would work for the following piece of code:
+                            <%
+                            HashMap map = new HashMap();
+                            session.setAttribute("map",map);
+                            map.put("key","value");
+                            %>
+        -->             
+             
+            
+        <Cluster  className="org.apache.catalina.cluster.tcp.SimpleTcpCluster"
+                  name="FilipsCluster"
+                  debug="10"
+                  serviceclass="org.apache.catalina.cluster.mcast.McastService"
+                  mcastAddr="228.0.0.4"
+                  mcastPort="45564"
+                  mcastFrequency="500"
+                  mcastDropTime="3000"
+                  tcpThreadCount="2"
+                  tcpListenAddress="auto"
+                  tcpListenPort="4001"
+                  tcpSelectorTimeout="100"
+                  printToScreen="false"
+                  expireSessionsOnShutdown="false"
+                  useDirtyFlag="true"
+        />
+        
+        <!--
+            When configuring for clustering, you also add in a valve to catch all the requests
+            coming in, at the end of the request, the session may or may not be replicated.
+            A session is replicated if and only if all the conditions are met:
+            1. useDirtyFlag is true or setAttribute or removeAttribute has been called AND
+            2. a session exists (has been created)
+            3. the request is not trapped by the "filter" attribute
+            
+            The filter attribute is to filter out requests that could not modify the session,
+            hence we don't replicate the session after the end of this request.
+            The filter is negative, ie, anything you put in the filter, you mean to filter out,
+            ie, no replication will be done on requests that match one of the filters.
+            The filter attribute is delimited by ;, so you can't escape out ; even if you wanted to.
+            
+            filter=".*\.gif;.*\.js;" means that we will not replicate the session after requests with the URI
+            ending with .gif and .js are intercepted.
+        -->
+            
+        <Valve className="org.apache.catalina.cluster.tcp.ReplicationValve"
+               filter=".*\.gif;.*\.js;.*\.jpg;.*\.htm;.*\.html;.*\.txt;"/>
+
+      <!-- Add the following attributes if you want to turn XML validation
+           on. Remember to comment the Host element above. 
+           
+           Note: XML Schema validationn will works with Xerces 2.0.1 or 
+           Xerces 2.1. Xerces 2.0.2 and Xerces 2.2 have bugs that prevent 
+           their use with Tomcat-->
+      <!--
+      <Host name="localhost" debug="0" appBase="webapps"
+       unpackWARs="true" autoDeploy="true"
+       xmlValidation="true" xmlNamespaceAware="true">
+      -->
+
+        <!-- Uncomment this to cluster this host using JavaGroups. The
+             protocol attribute can be used to configure the JavaGroups
+             network stack (the defaults are used if it's not specified). -->
+        <!--
+        <Cluster className="org.apache.catalina.cluster.JGCluster"/>
+        -->
+
+        <!-- Normally, users must authenticate themselves to each web app
+             individually.  Uncomment the following entry if you would like
+             a user to be authenticated the first time they encounter a
+             resource protected by a security constraint, and then have that
+             user identity maintained across *all* web applications contained
+             in this virtual host. -->
+        <!--
+        <Valve className="org.apache.catalina.authenticator.SingleSignOn"
+                   debug="0"/>
+        -->
+        
+        <!-- Access log processes all requests for this virtual host.  By
+             default, log files are created in the "logs" directory relative to
+             $CATALINA_HOME.  If you wish, you can specify a different
+             directory with the "directory" attribute.  Specify either a relative
+             (to $CATALINA_HOME) or absolute path to the desired directory.
+        -->
+        <!--
+        <Valve className="org.apache.catalina.valves.AccessLogValve"
+                 directory="logs"  prefix="localhost_access_log." suffix=".txt"
+                 pattern="common" resolveHosts="false"/>
+        -->
+
+        <!-- Logger shared by all Contexts related to this virtual host.  By
+             default (when using FileLogger), log files are created in the "logs"
+             directory relative to $CATALINA_HOME.  If you wish, you can specify
+             a different directory with the "directory" attribute.  Specify either a
+             relative (to $CATALINA_HOME) or absolute path to the desired
+             directory.-->
+        <Logger className="org.apache.catalina.logger.FileLogger"
+                 directory="logs"  prefix="localhost_log." suffix=".txt"
+            timestamp="true"/>
+
+        <!-- Define properties for each web application.  This is only needed
+             if you want to set non-default properties, or have web application
+             document roots in places other than the virtual host's appBase
+             directory.  -->
+
+        <!-- Tomcat Root Context -->
+        <!--
+        <Context path="/reptest" docBase="reptest" debug="0">
+            
+        </Context>
+        -->
+        
+
+      </Host>
+
+    </Engine>
+
+  </Service>
+
+</Server>

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/CatalinaCluster.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/CatalinaCluster.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/CatalinaCluster.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,141 @@
+/*
+ * Copyright 1999,2004-2005 The Apache Software Foundation.
+ * 
+ * Licensed 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.cluster;
+
+import java.util.Map;
+
+import org.apache.catalina.Cluster;
+import org.apache.catalina.LifecycleException;
+import org.apache.catalina.Manager;
+import org.apache.catalina.Valve;
+import org.apache.commons.logging.Log;
+
+/**
+ * A <b>CatalinaCluster</b> interface allows to plug in and out the 
+ * different cluster implementations
+ *
+ * @author Filip Hanik
+ * @version $Revision: 380229 $, $Date: 2006-02-23 15:28:29 -0600 (Thu, 23 Feb 2006) $
+ */
+
+public interface CatalinaCluster extends Cluster {
+    // ----------------------------------------------------- Instance Variables
+
+    /**
+     * Descriptive information about this component implementation.
+     */
+    public String info = "CatalinaCluster/2.0";
+    
+    /**
+     * Start the cluster, the owning container will invoke this
+     * @throws Exception - if failure to start cluster
+     */
+    public void start() throws Exception;
+    
+    /**
+     * Stops the cluster, the owning container will invoke this
+     * @throws LifecycleException
+     */
+    public void stop() throws LifecycleException;
+    
+    /**
+     * Returns the associates logger with this cluster.
+     *
+     * @return Log
+     */
+    public Log getLogger();
+    
+    /**
+     * receive a message to all the members in the cluster.
+     *
+     * @param msg ClusterMessage
+     */
+    public void receive(ClusterMessage msg);
+ 
+    /**
+     * Sends a message to all the members in the cluster
+     * @param msg ClusterMessage
+     */
+    public void send(ClusterMessage msg);
+    
+    /**
+     * Sends a message to a specific member in the cluster.
+     *
+     * @param msg ClusterMessage
+     * @param dest Member
+     */
+    public void send(ClusterMessage msg, Member dest);
+    
+    /**
+     * Sends a message to a all members at local cluster domain
+     *
+     * @param msg ClusterMessage
+     */
+    public void sendClusterDomain(ClusterMessage msg);
+
+    /**
+     * Returns that cluster has members.
+     */
+    public boolean hasMembers();
+
+    /**
+     * Returns all the members currently participating in the cluster.
+     *
+     * @return Member[]
+     */
+    public Member[] getMembers();
+    
+    /**
+     * Return the member that represents this node.
+     *
+     * @return Member
+     */
+    public Member getLocalMember();
+    
+    public void setClusterSender(ClusterSender sender);
+    
+    public ClusterSender getClusterSender();
+    
+    public void setClusterReceiver(ClusterReceiver receiver);
+    
+    public ClusterReceiver getClusterReceiver();
+    
+    public void setMembershipService(MembershipService service);
+    
+    public MembershipService getMembershipService();
+    
+    public void addValve(Valve valve);
+    
+    public void addClusterListener(MessageListener listener);
+    
+    public void removeClusterListener(MessageListener listener);
+    
+    public void setClusterDeployer(ClusterDeployer deployer);
+    
+    public ClusterDeployer getClusterDeployer();
+    
+    /**
+     * @return The map of managers
+     */
+    public Map getManagers();
+
+    public Manager getManager(String name);
+    public void removeManager(String name,Manager manager);
+    public void addManager(String name,Manager manager);
+    public Valve[] getValves();
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/ClusterDeployer.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/ClusterDeployer.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/ClusterDeployer.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,106 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ *
+ * Licensed 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.cluster;
+
+/**
+ * A <b>ClusterDeployer</b> interface allows to plug in and out the
+ * different deployment implementations
+ *
+ * @author Filip Hanik
+ * @version $Revision: 380229 $, $Date: 2006-02-23 15:28:29 -0600 (Thu, 23 Feb 2006) $
+ */
+import org.apache.catalina.LifecycleException;
+import java.io.IOException;
+import java.net.URL;
+
+public interface ClusterDeployer extends MessageListener {
+    /**
+     * Descriptive information about this component implementation.
+     */
+    public String info = "ClusterDeployer/1.0";
+    /**
+     * Start the cluster deployer, the owning container will invoke this
+     * @throws Exception - if failure to start cluster
+     */
+    public void start() throws Exception;
+
+    /**
+     * Stops the cluster deployer, the owning container will invoke this
+     * @throws LifecycleException
+     */
+    public void stop() throws LifecycleException;
+
+    /**
+     * Sets the deployer for this cluster deployer to use.
+     * @param deployer Deployer
+     */
+    // FIXME
+    //public void setDeployer(Deployer deployer);
+
+    /**
+     * Install a new web application, whose web application archive is at the
+     * specified URL, into this container and all the other
+     * members of the cluster with the specified context path.
+     * A context path of "" (the empty string) should be used for the root
+     * application for this container.  Otherwise, the context path must
+     * start with a slash.
+     * <p>
+     * If this application is successfully installed locally, 
+     * a ContainerEvent of type
+     * <code>INSTALL_EVENT</code> will be sent to all registered listeners,
+     * with the newly created <code>Context</code> as an argument.
+     *
+     * @param contextPath The context path to which this application should
+     *  be installed (must be unique)
+     * @param war A URL of type "jar:" that points to a WAR file, or type
+     *  "file:" that points to an unpacked directory structure containing
+     *  the web application to be installed
+     *
+     * @exception IllegalArgumentException if the specified context path
+     *  is malformed (it must be "" or start with a slash)
+     * @exception IllegalStateException if the specified context path
+     *  is already attached to an existing web application
+     * @exception IOException if an input/output error was encountered
+     *  during installation
+     */
+    public void install(String contextPath, URL war) throws IOException;
+
+    /**
+     * Remove an existing web application, attached to the specified context
+     * path.  If this application is successfully removed, a
+     * ContainerEvent of type <code>REMOVE_EVENT</code> will be sent to all
+     * registered listeners, with the removed <code>Context</code> as
+     * an argument. Deletes the web application war file and/or directory
+     * if they exist in the Host's appBase.
+     *
+     * @param contextPath The context path of the application to be removed
+     * @param undeploy boolean flag to remove web application from server
+     *
+     * @exception IllegalArgumentException if the specified context path
+     *  is malformed (it must be "" or start with a slash)
+     * @exception IllegalArgumentException if the specified context path does
+     *  not identify a currently installed web application
+     * @exception IOException if an input/output error occurs during
+     *  removal
+     */
+    public void remove(String contextPath, boolean undeploy) throws IOException;
+
+    /**
+     * call from container Background Process
+     */
+    public void backgroundProcess();
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/ClusterManager.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/ClusterManager.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/ClusterManager.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,101 @@
+/*
+ * Copyright 1999,2004-2005 The Apache Software Foundation.
+ * 
+ * Licensed 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.cluster;
+
+
+import org.apache.catalina.Manager;
+
+
+/**
+ * The common interface used by all cluster manager.
+ * This is so that we can have a more pluggable way
+ * of swapping session managers for different algorithms.
+ *
+ * @author Filip Hanik
+ * @author Peter Rossbach
+ */
+public interface ClusterManager extends Manager {
+
+   /**
+    * A message was received from another node, this
+    * is the callback method to implement if you are interested in
+    * receiving replication messages.
+    * @param msg - the message received.
+    */
+   public void messageDataReceived(ClusterMessage msg);
+
+   /**
+    * When the request has been completed, the replication valve
+    * will notify the manager, and the manager will decide whether
+    * any replication is needed or not.
+    * If there is a need for replication, the manager will
+    * create a session message and that will be replicated.
+    * The cluster determines where it gets sent.
+    * @param sessionId - the sessionId that just completed.
+    * @return a SessionMessage to be sent.
+    */
+   public ClusterMessage requestCompleted(String sessionId);
+
+   /**
+    * When the manager expires session not tied to a request.
+    * The cluster will periodically ask for a list of sessions
+    * that should expire and that should be sent across the wire.
+    * @return String[] The invalidated sessions
+    */
+   public String[] getInvalidatedSessions();
+   
+   /**
+    * Return the name of the manager, at host /context name and at engine hostname+/context.
+    * @return String
+    * @since 5.5.10
+    */
+   public String getName();
+   
+   /**
+    * Set the name of the manager, at host /context name and at engine hostname+/context
+    * @param name
+    * @since 5.5.10
+    */
+   public void setName(String name);
+         
+   public CatalinaCluster getCluster();
+
+   public void setCluster(CatalinaCluster cluster);
+   
+   /**
+    * @return Manager send only to same cluster domain.
+    * @since 5.5.10
+    */
+   public boolean isSendClusterDomainOnly();
+
+   /**
+    * @param sendClusterDomainOnly Flag value.
+    * @since 5.5.10
+    */
+   public void setSendClusterDomainOnly(boolean sendClusterDomainOnly);
+
+   /**
+    * @param mode The mode
+    * @since 5.5.10
+    */
+   public void setDefaultMode(boolean mode);
+
+   /**
+    * @since 5.5.10
+    */
+   public boolean isDefaultMode();
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/ClusterMessage.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/ClusterMessage.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/ClusterMessage.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,98 @@
+/*
+ * Copyright 1999,2005 The Apache Software Foundation.
+ *
+ * Licensed 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.cluster;
+
+import java.io.Serializable;
+
+/**
+ * @author Peter Rossbach
+ */
+public interface ClusterMessage extends Serializable {
+    
+    public final static int FLAG_FORBIDDEN = 0 ;
+    public final static int FLAG_ALLOWED = 1 ;
+    public final static int FLAG_DEFAULT = 2 ;
+    
+    /**
+     * Get the address that this message originated from.  This would be set
+     * if the message was being relayed from a host other than the one
+     * that originally sent it.
+     */
+    public Member getAddress();
+
+    /**
+     * Called by the cluster before sending it to the other
+     * nodes.
+     *
+     * @param member Member
+     */
+    public void setAddress(Member member);
+
+    /**
+     * Timestamp message.
+     *
+     * @return long
+     */
+    public long getTimestamp();
+
+    /**
+     * Called by the cluster before sending out
+     * the message.
+     *
+     * @param timestamp The timestamp
+     */
+    public void setTimestamp(long timestamp);
+
+    /**
+     * Each message must have a unique ID, in case of using async replication,
+     * and a smart queue, this id is used to replace messages not yet sent.
+     *
+     * @return String
+     */
+    public String getUniqueId();
+
+    /**
+     * Each message can made the desicion that resend is allowed or not or handle by default.
+     * @return 0 Forbidden, 1 allowed, 2 default
+     * @since 5.5.10
+     */
+    public int getResend();
+    
+    /**
+     * set desicion that resend is allowed or not or handle by default.
+     *
+     * @param resend 0 Forbidden, 1 allowed, 2 default
+     * @since 5.5.10
+     */
+    public void setResend(int resend) ;
+
+    /**
+     * Each message can made the desicion that compress is allowed or not or handle by default.
+     *
+     * @return 0 Forbidden, 1 allowed, 2 default
+     * @since 5.5.10
+     */
+    public int getCompress();
+    
+    /**
+     * set desicion that compress is allowed or not or handle by default.
+     *
+     * @param compress 0 Forbidden, 1 allowed, 2 default
+     * @since 5.5.10
+     */
+    public void setCompress(int compress) ;
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/ClusterReceiver.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/ClusterReceiver.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/ClusterReceiver.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,81 @@
+/*
+ * Copyright 1999,2004-2005 The Apache Software Foundation.
+ * 
+ * Licensed 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.cluster;
+
+
+/**
+ * Cluster Receiver Interface
+ * @author Filip Hanik
+ * @author Peter Rossbach
+ * @version $Revision: 380229 $, $Date: 2006-02-23 15:28:29 -0600 (Thu, 23 Feb 2006) $
+ */
+public interface ClusterReceiver {
+    /**
+     * Start message listing
+     * @throws java.io.IOException
+     */
+    public void start() throws java.io.IOException;
+
+    /**
+     * Stop message listing 
+     */
+    public void stop();
+
+    /**
+     * set callback.
+     *
+     * @param cluster The cluster
+     */
+    public void setCatalinaCluster(CatalinaCluster cluster);
+    
+    /**
+     * get Callback.
+     *
+     * @return The cluster
+     */
+    public CatalinaCluster getCatalinaCluster();
+    
+    /**
+     * Send Ack to sender or not.
+     *
+     * @return The flag value
+     */
+    public boolean isSendAck();
+    
+    /**
+     * set ack mode
+     * @param isSendAck
+     */
+    public void setSendAck(boolean isSendAck);
+    
+    public boolean isCompress() ;
+    public void setCompress(boolean compress);
+
+    /**
+     * get the listing ip interface
+     * @return The host
+     */
+    public String getHost();
+    
+    
+    /**
+     * get the listing ip port
+     * @return The port
+     */
+    public int getPort();
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/ClusterRuleSet.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/ClusterRuleSet.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/ClusterRuleSet.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,155 @@
+/*
+ * Copyright 1999-2001,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.cluster;
+
+
+import org.apache.tomcat.util.digester.Digester;
+import org.apache.tomcat.util.digester.RuleSetBase;
+
+
+/**
+ * <p><strong>RuleSet</strong> for processing the contents of a
+ * Cluster definition element.  </p>
+ *
+ * @author Filip Hanik
+ * @author Peter Rossbach
+ * @version $Revision: 380229 $ $Date: 2006-02-23 15:28:29 -0600 (Thu, 23 Feb 2006) $
+ */
+
+public class ClusterRuleSet extends RuleSetBase {
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The matching pattern prefix to use for recognizing our elements.
+     */
+    protected String prefix = null;
+
+
+    // ------------------------------------------------------------ Constructor
+
+
+    /**
+     * Construct an instance of this <code>RuleSet</code> with the default
+     * matching pattern prefix.
+     */
+    public ClusterRuleSet() {
+
+        this("");
+
+    }
+
+
+    /**
+     * Construct an instance of this <code>RuleSet</code> with the specified
+     * matching pattern prefix.
+     *
+     * @param prefix Prefix for matching pattern rules (including the
+     *  trailing slash character)
+     */
+    public ClusterRuleSet(String prefix) {
+        super();
+        this.namespaceURI = null;
+        this.prefix = prefix;
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * <p>Add the set of Rule instances defined in this RuleSet to the
+     * specified <code>Digester</code> instance, associating them with
+     * our namespace URI (if any).  This method should only be called
+     * by a Digester instance.</p>
+     *
+     * @param digester Digester instance to which the new Rule instances
+     *  should be added.
+     */
+    public void addRuleInstances(Digester digester) {
+        //Cluster configuration start
+        digester.addObjectCreate(prefix + "Membership",
+                                 null, // MUST be specified in the element
+                                 "className");
+        digester.addSetProperties(prefix + "Membership");
+        digester.addSetNext(prefix + "Membership",
+                            "setMembershipService",
+                            "org.apache.catalina.cluster.MembershipService");
+
+        digester.addObjectCreate(prefix + "Sender",
+                                 null, // MUST be specified in the element
+                                 "className");
+        digester.addSetProperties(prefix + "Sender");
+        digester.addSetNext(prefix + "Sender",
+                            "setClusterSender",
+                            "org.apache.catalina.cluster.ClusterSender");
+
+        digester.addObjectCreate(prefix + "Receiver",
+                                 null, // MUST be specified in the element
+                                 "className");
+        digester.addSetProperties(prefix + "Receiver");
+        digester.addSetNext(prefix + "Receiver",
+                            "setClusterReceiver",
+                            "org.apache.catalina.cluster.ClusterReceiver");
+
+        digester.addObjectCreate(prefix + "Valve",
+                                 null, // MUST be specified in the element
+                                 "className");
+        digester.addSetProperties(prefix + "Valve");
+        digester.addSetNext(prefix + "Valve",
+                            "addValve",
+                            "org.apache.catalina.Valve");
+
+        digester.addObjectCreate(prefix + "Deployer",
+                                 null, // MUST be specified in the element
+                                 "className");
+        digester.addSetProperties(prefix + "Deployer");
+        digester.addSetNext(prefix + "Deployer",
+                            "setClusterDeployer",
+                            "org.apache.catalina.cluster.ClusterDeployer");
+
+        digester.addObjectCreate(prefix + "Listener",
+                null, // MUST be specified in the element
+                "className");
+        digester.addSetProperties(prefix + "Listener");
+        digester.addSetNext(prefix + "Listener",
+                            "addLifecycleListener",
+                            "org.apache.catalina.LifecycleListener");
+
+        digester.addObjectCreate(prefix + "ClusterListener",
+                null, // MUST be specified in the element
+                "className");
+        digester.addSetProperties(prefix + "ClusterListener");
+        digester.addSetNext(prefix + "ClusterListener",
+                            "addClusterListener",
+                            "org.apache.catalina.cluster.MessageListener");
+        //Cluster configuration end
+    }
+
+
+    public void setPrefix(String prefix) {
+        this.prefix = prefix;
+    }
+
+    public String getPrefix() {
+        return prefix;
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/ClusterSender.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/ClusterSender.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/ClusterSender.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,59 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.cluster;
+
+import org.apache.catalina.cluster.tcp.SimpleTcpCluster;
+
+
+/**
+ * 
+ * @author Filip Hanik
+ * @author Peter Rossbach
+ * @version $Revision: 303950 $, $Date: 2005-06-09 15:38:30 -0500 (Thu, 09 Jun 2005) $
+ *
+ */
+public interface ClusterSender
+{
+
+    public void add(Member member);
+
+    public void remove(Member member);
+
+    public void start() throws java.io.IOException;
+
+    public void stop();
+
+    public void backgroundProcess() ;
+
+    public void sendMessage(ClusterMessage message, Member member) throws java.io.IOException;
+
+    public void sendMessage(ClusterMessage message) throws java.io.IOException;
+    
+    public void sendMessageClusterDomain(ClusterMessage message) throws java.io.IOException;
+
+    public boolean isWaitForAck();
+    public void setWaitForAck(boolean isWaitForAck);
+
+    public boolean isCompress() ;
+    public void setCompress(boolean compress);
+
+    /**
+     * @param cluster
+     */
+    public void setCatalinaCluster(SimpleTcpCluster cluster);
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/ClusterSession.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/ClusterSession.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/ClusterSession.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,37 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.cluster;
+
+import org.apache.catalina.Session;
+import javax.servlet.http.HttpSession;
+
+public interface ClusterSession extends Session, HttpSession {
+   /**
+    * returns true if this session is the primary session, if that is the
+    * case, the manager can expire it upon timeout.
+    * @return True if this session is primary
+    */
+   public boolean isPrimarySession();
+
+   /**
+    * Sets whether this is the primary session or not.
+    * @param primarySession Flag value
+    */
+   public void setPrimarySession(boolean primarySession);
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/ClusterValve.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/ClusterValve.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/ClusterValve.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,36 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.cluster;
+
+/**
+ * Cluster Valve Interface to mark all Cluster Valves 
+ * Only those Valve can'be configured as Cluster Valves
+ * @author Peter Rossbach
+ * @version $Revision: 303842 $, $Date: 2005-04-10 11:20:46 -0500 (Sun, 10 Apr 2005) $
+ */
+public interface ClusterValve {
+    /**
+     * Returns the cluster the cluster deployer is associated with
+     * @return CatalinaCluster
+     */
+    public CatalinaCluster getCluster();
+
+    /**
+     * Associates the cluster deployer with a cluster
+     * @param cluster CatalinaCluster
+     */
+    public void setCluster(CatalinaCluster cluster);
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/Constants.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/Constants.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/Constants.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,30 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.cluster;
+
+/**
+ * Manifest constants for the <code>org.apache.catalina.cluster</code>
+ * package.
+ *
+ * @author Bip Thelin
+ * @version $Revision: 302726 $, $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public final class Constants {
+    public static final String Package = "org.apache.catalina.cluster";
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/LocalStrings.properties
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/LocalStrings.properties	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/LocalStrings.properties	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1 @@
+cluster.mbean.register.already=MBean {0} already registered!

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/Member.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/Member.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/Member.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,65 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.cluster;
+
+/**
+ * The Member interface, defines a member in the Cluster.
+ * A member is a Tomcat process that participates in session replication.<BR>
+ * Each member can carry a set of properties, defined by the actual implementation.<BR>
+ * For TCP replication has been targeted for the first release, the hostname and listen port
+ * of the member is defined as hardcoded stuff.<BR>
+ * The Member interface together with MembershipListener, MembershipService are interfaces used to
+ * switch out the service used to establish membership in between the cluster nodes.
+ *
+ * @author Filip Hanik
+ * @version $Revision: 303950 $, $Date: 2005-06-09 15:38:30 -0500 (Thu, 09 Jun 2005) $
+ */
+
+
+public interface Member {
+    /**
+     * Return implementation specific properties about this cluster node.
+     */
+    public java.util.HashMap getMemberProperties();
+    /**
+     * Returns the name of this node, should be unique within the cluster.
+     */
+    public String getName();
+  
+    /**
+     * Returns the name of the cluster domain from this node
+     */
+    public String getDomain();
+    
+    /**
+     * Returns the TCP listen host for the TCP implementation
+     */
+    public String getHost();
+    /**
+     * Returns the TCP listen portfor the TCP implementation
+     */
+    public int getPort();
+
+    /**
+     * Contains information on how long this member has been online.
+     * The result is the number of milli seconds this member has been
+     * broadcasting its membership to the cluster.
+     * @return nr of milliseconds since this member started.
+     */
+    public long getMemberAliveTime();
+    
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/MembershipListener.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/MembershipListener.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/MembershipListener.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,33 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.cluster;
+
+/**
+ * The MembershipListener interface is used as a callback to the
+ * membership service. It has two methods that will notify the listener
+ * when a member has joined the cluster and when a member has disappeared (crashed)
+ *
+ * @author Filip Hanik
+ * @version $Revision: 302726 $, $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+
+public interface MembershipListener {
+    public void memberAdded(Member member);
+    public void memberDisappeared(Member member);
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/MembershipService.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/MembershipService.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/MembershipService.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,114 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.cluster;
+
+import org.apache.catalina.cluster.tcp.SimpleTcpCluster;
+
+/**
+ * The membership service helps the cluster determine the membership
+ * logic in the cluster.
+ * @author Peter Rossbach
+ * @author Filip Hanik
+ * @version $Revision: 380229 $, $Date: 2006-02-23 15:28:29 -0600 (Thu, 23 Feb 2006) $
+ */
+
+
+public interface MembershipService {
+
+    /**
+     * Sets the properties for the membership service. This must be called before
+     * the <code>start()</code> method is called.
+     * The properties are implementation specific.
+     * @param properties - to be used to configure the membership service.
+     */
+    public void setProperties(java.util.Properties properties);
+    /**
+     * Returns the properties for the configuration used.
+     */
+    public java.util.Properties getProperties();
+    /**
+     * Starts the membership service. If a membership listeners is added
+     * the listener will start to receive membership events.
+     * Performs a start level 1 and 2
+     * @throws java.lang.Exception if the service fails to start.
+     */
+    public void start() throws java.lang.Exception;
+
+    /**
+     * Starts the membership service. If a membership listeners is added
+     * the listener will start to receive membership events.
+     * @param level - level 1 starts listening for members, level 2 
+     * starts broad casting the server
+     * @throws java.lang.Exception if the service fails to start.
+     */
+    public void start(int level) throws java.lang.Exception;
+
+
+    /**
+     * Stops the membership service
+     */
+    public void stop();
+    
+    /**
+     * Returns that cluster has members.
+     */
+    public boolean hasMembers();
+    
+    /**
+     * Returns a list of all the members in the cluster.
+     */
+    
+    public Member[] getMembers();
+    
+    /**
+     * Returns the member object that defines this member
+     */
+    public Member getLocalMember();
+
+    /**
+     * Return all members by name
+     */
+    public String[] getMembersByName() ; 
+    
+    /**
+     * Return the member by name
+     */
+    public Member findMemberByName(String name) ;
+
+    /**
+     * Sets the local member properties for broadcasting
+     */
+    public void setLocalMemberProperties(String listenHost, int listenPort);
+    
+    /**
+     * Sets the membership listener, only one listener can be added.
+     * If you call this method twice, the last listener will be used.
+     * @param listener The listener
+     */
+    public void addMembershipListener(MembershipListener listener);
+    
+    /**
+     * removes the membership listener.
+     */
+    public void removeMembershipListener();
+
+    /**
+     * @param cluster
+     */
+    public void setCatalinaCluster(SimpleTcpCluster cluster);
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/MessageListener.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/MessageListener.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/MessageListener.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,41 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.cluster;
+
+public interface MessageListener {
+    
+    public void messageReceived(ClusterMessage msg);
+    
+    public boolean accept(ClusterMessage msg);
+    
+    public boolean equals(Object listener);
+    
+    public int hashCode();
+    
+    /**
+     * Returns the cluster the cluster deployer is associated with
+     * @return CatalinaCluster
+     */
+    public CatalinaCluster getCluster();
+
+    /**
+     * Associates the cluster deployer with a cluster
+     * @param cluster CatalinaCluster
+     */
+    public void setCluster(CatalinaCluster cluster);
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/deploy/FarmWarDeployer.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/deploy/FarmWarDeployer.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/deploy/FarmWarDeployer.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,740 @@
+/*
+ * Copyright 1999,2004-2005 The Apache Software Foundation.
+ *
+ * Licensed 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.cluster.deploy;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URL;
+import java.util.HashMap;
+
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+
+import org.apache.catalina.Context;
+import org.apache.catalina.Engine;
+import org.apache.catalina.Host;
+import org.apache.catalina.Lifecycle;
+import org.apache.catalina.LifecycleException;
+import org.apache.catalina.cluster.CatalinaCluster;
+import org.apache.catalina.cluster.ClusterDeployer;
+import org.apache.catalina.cluster.ClusterMessage;
+import org.apache.catalina.cluster.Member;
+import org.apache.commons.modeler.Registry;
+
+/**
+ * <p>
+ * A farm war deployer is a class that is able to deploy/undeploy web
+ * applications in WAR form within the cluster.
+ * </p>
+ * Any host can act as the admin, and will have three directories
+ * <ul>
+ * <li>deployDir - the directory where we watch for changes</li>
+ * <li>applicationDir - the directory where we install applications</li>
+ * <li>tempDir - a temporaryDirectory to store binary data when downloading a
+ * war from the cluster</li>
+ * </ul>
+ * Currently we only support deployment of WAR files since they are easier to
+ * send across the wire.
+ * 
+ * @author Filip Hanik
+ * @author Peter Rossbach
+ * @version $Revision: 390639 $
+ */
+public class FarmWarDeployer implements ClusterDeployer, FileChangeListener {
+    /*--Static Variables----------------------------------------*/
+    public static org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory
+            .getLog(FarmWarDeployer.class);
+    /**
+     * The descriptive information about this implementation.
+     */
+    private static final String info = "FarmWarDeployer/1.2";
+
+    /*--Instance Variables--------------------------------------*/
+    protected CatalinaCluster cluster = null;
+
+    protected boolean started = false; //default 5 seconds
+
+    protected HashMap fileFactories = new HashMap();
+
+    protected String deployDir;
+
+    protected String tempDir;
+
+    protected String watchDir;
+
+    protected boolean watchEnabled = false;
+
+    protected WarWatcher watcher = null;
+
+    /**
+     * Iteration count for background processing.
+     */
+    private int count = 0;
+
+    /**
+     * Frequency of the Farm watchDir check. Cluster wide deployment will be
+     * done once for the specified amount of backgrondProcess calls (ie, the
+     * lower the amount, the most often the checks will occur).
+     */
+    protected int processDeployFrequency = 2;
+
+    /**
+     * Path where context descriptors should be deployed.
+     */
+    protected File configBase = null;
+
+    /**
+     * The associated host.
+     */
+    protected Host host = null;
+
+    /**
+     * The host appBase.
+     */
+    protected File appBase = null;
+
+    /**
+     * MBean server.
+     */
+    protected MBeanServer mBeanServer = null;
+
+    /**
+     * The associated deployer ObjectName.
+     */
+    protected ObjectName oname = null;
+
+    /*--Constructor---------------------------------------------*/
+    public FarmWarDeployer() {
+    }
+
+    /**
+     * Return descriptive information about this deployer implementation and the
+     * corresponding version number, in the format
+     * <code>&lt;description&gt;/&lt;version&gt;</code>.
+     */
+    public String getInfo() {
+
+        return (info);
+
+    }
+
+    /*--Logic---------------------------------------------------*/
+    public void start() throws Exception {
+        if (started)
+            return;
+        getCluster().addClusterListener(this);
+        if (watchEnabled) {
+            watcher = new WarWatcher(this, new File(getWatchDir()));
+            if (log.isInfoEnabled())
+                log.info("Cluster deployment is watching " + getWatchDir()
+                        + " for changes.");
+        }
+
+        // Check to correct engine and host setup
+        host = (Host) getCluster().getContainer();
+        Engine engine = (Engine) host.getParent();
+        try {
+            oname = new ObjectName(engine.getName() + ":type=Deployer,host="
+                    + host.getName());
+        } catch (Exception e) {
+            log.error("Can't construct MBean object name" + e);
+        }
+        configBase = new File(System.getProperty("catalina.base"), "conf");
+        if (engine != null) {
+            configBase = new File(configBase, engine.getName());
+        }
+        if (host != null) {
+            configBase = new File(configBase, host.getName());
+        }
+
+        // Retrieve the MBean server
+        mBeanServer = Registry.getRegistry(null, null).getMBeanServer();
+
+        started = true;
+        count = 0;
+        if (log.isInfoEnabled())
+            log.info("Cluster FarmWarDeployer started.");
+    }
+
+    /*
+     * stop cluster wide deployments
+     * 
+     * @see org.apache.catalina.cluster.ClusterDeployer#stop()
+     */
+    public void stop() throws LifecycleException {
+        started = false;
+        getCluster().removeClusterListener(this);
+        count = 0;
+        if (watcher != null) {
+            watcher.clear();
+            watcher = null;
+
+        }
+        if (log.isInfoEnabled())
+            log.info("Cluster FarmWarDeployer stopped.");
+    }
+
+    public void cleanDeployDir() {
+        throw new java.lang.UnsupportedOperationException(
+                "Method cleanDeployDir() not yet implemented.");
+    }
+
+    /**
+     * Callback from the cluster, when a message is received, The cluster will
+     * broadcast it invoking the messageReceived on the receiver.
+     * 
+     * @param msg
+     *            ClusterMessage - the message received from the cluster
+     */
+    public void messageReceived(ClusterMessage msg) {
+        try {
+            if (msg instanceof FileMessage && msg != null) {
+                FileMessage fmsg = (FileMessage) msg;
+                if (log.isDebugEnabled())
+                    log.debug("receive cluster deployment [ path: "
+                            + fmsg.getContextPath() + " war:  "
+                            + fmsg.getFileName() + " ]");
+                FileMessageFactory factory = getFactory(fmsg);
+                // TODO correct second try after app is in service!
+                if (factory.writeMessage(fmsg)) {
+                    //last message received war file is completed
+                    String name = factory.getFile().getName();
+                    if (!name.endsWith(".war"))
+                        name = name + ".war";
+                    File deployable = new File(getDeployDir(), name);
+                    try {
+                        String path = fmsg.getContextPath();
+                        if (!isServiced(path)) {
+                            addServiced(path);
+                            try {
+                                remove(path);
+                                factory.getFile().renameTo(deployable);
+                                check(path);
+                            } finally {
+                                removeServiced(path);
+                            }
+                            if (log.isDebugEnabled())
+                                log.debug("deployment from " + path
+                                        + " finished.");
+                        } else
+                            log.error("Application " + path
+                                    + " in used. touch war file " + name
+                                    + " again!");
+                    } catch (Exception ex) {
+                        log.error(ex);
+                    } finally {
+                        removeFactory(fmsg);
+                    }
+                }
+            } else if (msg instanceof UndeployMessage && msg != null) {
+                try {
+                    UndeployMessage umsg = (UndeployMessage) msg;
+                    String path = umsg.getContextPath();
+                    if (log.isDebugEnabled())
+                        log.debug("receive cluster undeployment from " + path);
+                    if (!isServiced(path)) {
+                        addServiced(path);
+                        try {
+                            remove(path);
+                        } finally {
+                            removeServiced(path);
+                        }
+                        if (log.isDebugEnabled())
+                            log.debug("undeployment from " + path
+                                    + " finished.");
+                    } else
+                        log.error("Application "
+                            + path
+                            + " in used. Sorry not remove from backup cluster nodes!");
+                } catch (Exception ex) {
+                    log.error(ex);
+                }
+            }
+        } catch (java.io.IOException x) {
+            log.error("Unable to read farm deploy file message.", x);
+        }
+    }
+
+    /**
+     * create factory for all transported war files
+     * 
+     * @param msg
+     * @return Factory for all app message (war files)
+     * @throws java.io.FileNotFoundException
+     * @throws java.io.IOException
+     */
+    public synchronized FileMessageFactory getFactory(FileMessage msg)
+            throws java.io.FileNotFoundException, java.io.IOException {
+        File tmpFile = new File(msg.getFileName());
+        File writeToFile = new File(getTempDir(), tmpFile.getName());
+        FileMessageFactory factory = (FileMessageFactory) fileFactories.get(msg
+                .getFileName());
+        if (factory == null) {
+            factory = FileMessageFactory.getInstance(writeToFile, true);
+            fileFactories.put(msg.getFileName(), factory);
+        }
+        return factory;
+    }
+
+    /**
+     * Remove file (war) from messages)
+     * 
+     * @param msg
+     */
+    public void removeFactory(FileMessage msg) {
+        fileFactories.remove(msg.getFileName());
+    }
+
+    /**
+     * Before the cluster invokes messageReceived the cluster will ask the
+     * receiver to accept or decline the message, In the future, when messages
+     * get big, the accept method will only take a message header
+     * 
+     * @param msg
+     *            ClusterMessage
+     * @return boolean - returns true to indicate that messageReceived should be
+     *         invoked. If false is returned, the messageReceived method will
+     *         not be invoked.
+     */
+    public boolean accept(ClusterMessage msg) {
+        return (msg instanceof FileMessage) || (msg instanceof UndeployMessage);
+    }
+
+    /**
+     * Install a new web application, whose web application archive is at the
+     * specified URL, into this container and all the other members of the
+     * cluster with the specified context path. A context path of "" (the empty
+     * string) should be used for the root application for this container.
+     * Otherwise, the context path must start with a slash.
+     * <p>
+     * If this application is successfully installed locally, a ContainerEvent
+     * of type <code>INSTALL_EVENT</code> will be sent to all registered
+     * listeners, with the newly created <code>Context</code> as an argument.
+     * 
+     * @param contextPath
+     *            The context path to which this application should be installed
+     *            (must be unique)
+     * @param war
+     *            A URL of type "jar:" that points to a WAR file, or type
+     *            "file:" that points to an unpacked directory structure
+     *            containing the web application to be installed
+     * 
+     * @exception IllegalArgumentException
+     *                if the specified context path is malformed (it must be ""
+     *                or start with a slash)
+     * @exception IllegalStateException
+     *                if the specified context path is already attached to an
+     *                existing web application
+     * @exception IOException
+     *                if an input/output error was encountered during
+     *                installation
+     */
+    public void install(String contextPath, URL war) throws IOException {
+        Member[] members = getCluster().getMembers();
+        Member localMember = getCluster().getLocalMember();
+        FileMessageFactory factory = FileMessageFactory.getInstance(new File(
+                war.getFile()), false);
+        FileMessage msg = new FileMessage(localMember, war.getFile(),
+                contextPath);
+        if(log.isDebugEnabled())
+            log.debug("Send cluster war deployment [ path:"
+                    + contextPath + " war: " + war + " ] started.");
+        msg = factory.readMessage(msg);
+        while (msg != null) {
+            for (int i = 0; i < members.length; i++) {
+                if (log.isDebugEnabled())
+                    log.debug("Send cluster war fragment [ path: "
+                            + contextPath + " war: " + war + " to: " +  members[i] + " ]");
+                getCluster().send(msg, members[i]);
+            }
+            msg = factory.readMessage(msg);
+        }
+        if(log.isDebugEnabled())
+            log.debug("Send cluster war deployment [ path: "
+                    + contextPath + " war: " + war + " ] finished.");
+    }
+
+    /**
+     * Remove an existing web application, attached to the specified context
+     * path. If this application is successfully removed, a ContainerEvent of
+     * type <code>REMOVE_EVENT</code> will be sent to all registered
+     * listeners, with the removed <code>Context</code> as an argument.
+     * Deletes the web application war file and/or directory if they exist in
+     * the Host's appBase.
+     * 
+     * @param contextPath
+     *            The context path of the application to be removed
+     * @param undeploy
+     *            boolean flag to remove web application from server
+     * 
+     * @exception IllegalArgumentException
+     *                if the specified context path is malformed (it must be ""
+     *                or start with a slash)
+     * @exception IllegalArgumentException
+     *                if the specified context path does not identify a
+     *                currently installed web application
+     * @exception IOException
+     *                if an input/output error occurs during removal
+     */
+    public void remove(String contextPath, boolean undeploy) throws IOException {
+        if (log.isInfoEnabled())
+            log.info("Cluster wide remove of web app " + contextPath);
+        Member localMember = getCluster().getLocalMember();
+        UndeployMessage msg = new UndeployMessage(localMember, System
+                .currentTimeMillis(), "Undeploy:" + contextPath + ":"
+                + System.currentTimeMillis(), contextPath, undeploy);
+        if (log.isDebugEnabled())
+            log.debug("Send cluster wide undeployment from "
+                    + contextPath );
+        cluster.send(msg);
+        // remove locally
+        if (undeploy) {
+            try {
+                if (!isServiced(contextPath)) {
+                    addServiced(contextPath);
+                    try {
+                        remove(contextPath);
+                    } finally {
+                        removeServiced(contextPath);
+                    }
+                } else
+                    log.error("Local remove from " + contextPath
+                            + "failed, other manager has app in service!");
+
+            } catch (Exception ex) {
+                log.error("local remove from " + contextPath + " failed", ex);
+            }
+        }
+
+    }
+
+    /*
+     * Modifcation from watchDir war detected!
+     * 
+     * @see org.apache.catalina.cluster.deploy.FileChangeListener#fileModified(java.io.File)
+     */
+    public void fileModified(File newWar) {
+        try {
+            File deployWar = new File(getDeployDir(), newWar.getName());
+            copy(newWar, deployWar);
+            String contextName = getContextName(deployWar);
+            if (log.isInfoEnabled())
+                log.info("Installing webapp[" + contextName + "] from "
+                        + deployWar.getAbsolutePath());
+            try {
+                remove(contextName, false);
+            } catch (Exception x) {
+                log.error("No removal", x);
+            }
+            install(contextName, deployWar.toURL());
+        } catch (Exception x) {
+            log.error("Unable to install WAR file", x);
+        }
+    }
+
+    /*
+     * War remvoe from watchDir
+     * 
+     * @see org.apache.catalina.cluster.deploy.FileChangeListener#fileRemoved(java.io.File)
+     */
+    public void fileRemoved(File removeWar) {
+        try {
+            String contextName = getContextName(removeWar);
+            if (log.isInfoEnabled())
+                log.info("Removing webapp[" + contextName + "]");
+            remove(contextName, true);
+        } catch (Exception x) {
+            log.error("Unable to remove WAR file", x);
+        }
+    }
+
+    /**
+     * Create a context path from war
+     * @param war War filename
+     * @return '/filename' or if war name is ROOT.war context name is empty string '' 
+     */
+    protected String getContextName(File war) {
+        String contextName = "/"
+        + war.getName().substring(0,
+                war.getName().lastIndexOf(".war"));
+        if("/ROOT".equals(contextName))
+            contextName= "" ;
+        return contextName ;
+    }
+    
+    /**
+     * Given a context path, get the config file name.
+     */
+    protected String getConfigFile(String path) {
+        String basename = null;
+        if (path.equals("")) {
+            basename = "ROOT";
+        } else {
+            basename = path.substring(1).replace('/', '#');
+        }
+        return (basename);
+    }
+
+    /**
+     * Given a context path, get the config file name.
+     */
+    protected String getDocBase(String path) {
+        String basename = null;
+        if (path.equals("")) {
+            basename = "ROOT";
+        } else {
+            basename = path.substring(1);
+        }
+        return (basename);
+    }
+
+    /**
+     * Return a File object representing the "application root" directory for
+     * our associated Host.
+     */
+    protected File getAppBase() {
+
+        if (appBase != null) {
+            return appBase;
+        }
+
+        File file = new File(host.getAppBase());
+        if (!file.isAbsolute())
+            file = new File(System.getProperty("catalina.base"), host
+                    .getAppBase());
+        try {
+            appBase = file.getCanonicalFile();
+        } catch (IOException e) {
+            appBase = file;
+        }
+        return (appBase);
+
+    }
+
+    /**
+     * Invoke the remove method on the deployer.
+     */
+    protected void remove(String path) throws Exception {
+        // TODO Handle remove also work dir content !
+        // Stop the context first to be nicer
+        Context context = (Context) host.findChild(path);
+        if (context != null) {
+            if(log.isDebugEnabled())
+                log.debug("Undeploy local context " +path );
+            ((Lifecycle) context).stop();
+            File war = new File(getAppBase(), getDocBase(path) + ".war");
+            File dir = new File(getAppBase(), getDocBase(path));
+            File xml = new File(configBase, getConfigFile(path) + ".xml");
+            if (war.exists()) {
+                war.delete();
+            } else if (dir.exists()) {
+                undeployDir(dir);
+            } else {
+                xml.delete();
+            }
+            // Perform new deployment and remove internal HostConfig state
+            check(path);
+        }
+
+    }
+
+    /**
+     * Delete the specified directory, including all of its contents and
+     * subdirectories recursively.
+     * 
+     * @param dir
+     *            File object representing the directory to be deleted
+     */
+    protected void undeployDir(File dir) {
+
+        String files[] = dir.list();
+        if (files == null) {
+            files = new String[0];
+        }
+        for (int i = 0; i < files.length; i++) {
+            File file = new File(dir, files[i]);
+            if (file.isDirectory()) {
+                undeployDir(file);
+            } else {
+                file.delete();
+            }
+        }
+        dir.delete();
+
+    }
+
+    /*
+     * Call watcher to check for deploy changes
+     * 
+     * @see org.apache.catalina.cluster.ClusterDeployer#backgroundProcess()
+     */
+    public void backgroundProcess() {
+        if (started) {
+            count = (count + 1) % processDeployFrequency;
+            if (count == 0 && watchEnabled) {
+                watcher.check();
+            }
+        }
+
+    }
+
+    /*--Deployer Operations ------------------------------------*/
+
+    /**
+     * Invoke the check method on the deployer.
+     */
+    protected void check(String name) throws Exception {
+        String[] params = { name };
+        String[] signature = { "java.lang.String" };
+        mBeanServer.invoke(oname, "check", params, signature);
+    }
+
+    /**
+     * Invoke the check method on the deployer.
+     */
+    protected boolean isServiced(String name) throws Exception {
+        String[] params = { name };
+        String[] signature = { "java.lang.String" };
+        Boolean result = (Boolean) mBeanServer.invoke(oname, "isServiced",
+                params, signature);
+        return result.booleanValue();
+    }
+
+    /**
+     * Invoke the check method on the deployer.
+     */
+    protected void addServiced(String name) throws Exception {
+        String[] params = { name };
+        String[] signature = { "java.lang.String" };
+        mBeanServer.invoke(oname, "addServiced", params, signature);
+    }
+
+    /**
+     * Invoke the check method on the deployer.
+     */
+    protected void removeServiced(String name) throws Exception {
+        String[] params = { name };
+        String[] signature = { "java.lang.String" };
+        mBeanServer.invoke(oname, "removeServiced", params, signature);
+    }
+
+    /*--Instance Getters/Setters--------------------------------*/
+    public CatalinaCluster getCluster() {
+        return cluster;
+    }
+
+    public void setCluster(CatalinaCluster cluster) {
+        this.cluster = cluster;
+    }
+
+    public boolean equals(Object listener) {
+        return super.equals(listener);
+    }
+
+    public int hashCode() {
+        return super.hashCode();
+    }
+
+    public String getDeployDir() {
+        return deployDir;
+    }
+
+    public void setDeployDir(String deployDir) {
+        this.deployDir = deployDir;
+    }
+
+    public String getTempDir() {
+        return tempDir;
+    }
+
+    public void setTempDir(String tempDir) {
+        this.tempDir = tempDir;
+    }
+
+    public String getWatchDir() {
+        return watchDir;
+    }
+
+    public void setWatchDir(String watchDir) {
+        this.watchDir = watchDir;
+    }
+
+    public boolean isWatchEnabled() {
+        return watchEnabled;
+    }
+
+    public boolean getWatchEnabled() {
+        return watchEnabled;
+    }
+
+    public void setWatchEnabled(boolean watchEnabled) {
+        this.watchEnabled = watchEnabled;
+    }
+
+    /**
+     * Return the frequency of watcher checks.
+     */
+    public int getProcessDeployFrequency() {
+
+        return (this.processDeployFrequency);
+
+    }
+
+    /**
+     * Set the watcher checks frequency.
+     * 
+     * @param processExpiresFrequency
+     *            the new manager checks frequency
+     */
+    public void setProcessDeployFrequency(int processExpiresFrequency) {
+
+        if (processExpiresFrequency <= 0) {
+            return;
+        }
+        this.processDeployFrequency = processExpiresFrequency;
+    }
+
+    /**
+     * Copy a file to the specified temp directory.
+     * @param from copy from temp
+     * @param to   to host appBase directory
+     * @return true, copy successful
+     */
+    protected boolean copy(File from, File to) {
+        try {
+            if (!to.exists())
+                to.createNewFile();
+            java.io.FileInputStream is = new java.io.FileInputStream(from);
+            java.io.FileOutputStream os = new java.io.FileOutputStream(to,
+                    false);
+            byte[] buf = new byte[4096];
+            while (true) {
+                int len = is.read(buf);
+                if (len < 0)
+                    break;
+                os.write(buf, 0, len);
+            }
+            is.close();
+            os.close();
+        } catch (IOException e) {
+            log.error("Unable to copy file from:" + from + " to:" + to, e);
+            return false;
+        }
+        return true;
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/deploy/FileChangeListener.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/deploy/FileChangeListener.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/deploy/FileChangeListener.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,23 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.cluster.deploy;
+import java.io.File;
+
+public interface FileChangeListener {
+    public void fileModified(File f);
+    public void fileRemoved(File f);
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/deploy/FileMessage.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/deploy/FileMessage.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/deploy/FileMessage.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,152 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.cluster.deploy;
+
+import org.apache.catalina.cluster.ClusterMessage;
+import org.apache.catalina.cluster.Member;
+import java.io.Serializable;
+
+/**
+ * Contains the data for a file being transferred over TCP, this is 
+ * essentially a fragment of a file, read and written by the FileMessageFactory
+ * @author Filip Hanik
+ * @version 1.0
+ */
+
+public class FileMessage implements ClusterMessage, Serializable {
+    private int messageNumber;
+    private byte[] data;
+    private int dataLength;
+    private org.apache.catalina.cluster.Member address;
+    
+    private long timestamp;
+    private long totalLength;
+    private long totalNrOfMsgs;
+    private String fileName;
+    private String contextPath;
+    private int resend = ClusterMessage.FLAG_FORBIDDEN;
+    private int compress = ClusterMessage.FLAG_DEFAULT ;
+    
+    public FileMessage(Member source,
+                       String fileName,
+                       String contextPath) {
+        this.address=source;
+        this.fileName=fileName;
+        this.contextPath=contextPath;
+    }
+    
+    /*
+    public void writeExternal(ObjectOutput out) throws IOException {
+                   
+    }
+    
+    public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
+                  
+    }
+    */
+   
+    public int getMessageNumber() {
+        return messageNumber;
+    }
+    public void setMessageNumber(int messageNumber) {
+        this.messageNumber = messageNumber;
+    }
+    public long getTotalNrOfMsgs() {
+        return totalNrOfMsgs;
+    }
+    public void setTotalNrOfMsgs(long totalNrOfMsgs) {
+        this.totalNrOfMsgs = totalNrOfMsgs;
+    }
+    public byte[] getData() {
+        return data;
+    }
+    public void setData(byte[] data, int length) {
+        this.data = data;
+        this.dataLength = length;
+    }
+    public int getDataLength() {
+        return dataLength;
+    }
+    public void setDataLength(int dataLength) {
+        this.dataLength = dataLength;
+    }
+    public long getTotalLength() {
+        return totalLength;
+    }
+    public void setTotalLength(long totalLength) {
+        this.totalLength = totalLength;
+    }
+    public org.apache.catalina.cluster.Member getAddress() {
+        return address;
+    }
+    public void setAddress(org.apache.catalina.cluster.Member address) {
+        this.address = address;
+    }
+    public String getUniqueId() {
+        StringBuffer result = new StringBuffer(getFileName());
+        result.append("#-#");
+        result.append(getMessageNumber());
+        result.append("#-#");
+        result.append(System.currentTimeMillis());
+        return result.toString();
+    }
+
+    public long getTimestamp() {
+        return timestamp;
+    }
+    public void setTimestamp(long timestamp) {
+        this.timestamp = timestamp;
+    }
+    public String getFileName() {
+        return fileName;
+    }
+    public void setFileName(String fileName) {
+        this.fileName = fileName;
+    }
+    public String getContextPath() {
+        return contextPath;
+    }
+
+    /**
+     * @return Returns the compress.
+     * @since 5.5.10 
+     */
+    public int getCompress() {
+        return compress;
+    }
+    /**
+     * @param compress The compress to set.
+     * @since 5.5.10
+     */
+    public void setCompress(int compress) {
+        this.compress = compress;
+    }
+    /**
+     * @return Returns the resend.
+     * @since 5.5.10
+     */
+    public int getResend() {
+        return resend;
+    }
+    /**
+     * @param resend The resend to set.
+     * @since 5.5.10
+     */
+    public void setResend(int resend) {
+        this.resend = resend;
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/deploy/FileMessageFactory.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/deploy/FileMessageFactory.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/deploy/FileMessageFactory.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,311 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.cluster.deploy;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.FileNotFoundException;
+
+/**
+ * This factory is used to read files and write files by splitting them up into
+ * smaller messages. So that entire files don't have to be read into memory.
+ * <BR>
+ * The factory can be used as a reader or writer but not both at the same time.
+ * When done reading or writing the factory will close the input or output
+ * streams and mark the factory as closed. It is not possible to use it after
+ * that. <BR>
+ * To force a cleanup, call cleanup() from the calling object. <BR>
+ * This class is not thread safe.
+ * 
+ * @author Filip Hanik
+ * @version 1.0
+ */
+public class FileMessageFactory {
+    /*--Static Variables----------------------------------------*/
+    public static org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory
+            .getLog(FileMessageFactory.class);
+
+    /**
+     * The number of bytes that we read from file
+     */
+    public static final int READ_SIZE = 1024 * 10; //10kb
+
+    /**
+     * The file that we are reading/writing
+     */
+    protected File file = null;
+
+    /**
+     * True means that we are writing with this factory. False means that we are
+     * reading with this factory
+     */
+    protected boolean openForWrite;
+
+    /**
+     * Once the factory is used, it can not be reused.
+     */
+    protected boolean closed = false;
+
+    /**
+     * When openForWrite=false, the input stream is held by this variable
+     */
+    protected FileInputStream in;
+
+    /**
+     * When openForWrite=true, the output stream is held by this variable
+     */
+    protected FileOutputStream out;
+
+    /**
+     * The number of messages we have read or written
+     */
+    protected int nrOfMessagesProcessed = 0;
+
+    /**
+     * The total size of the file
+     */
+    protected long size = 0;
+
+    /**
+     * The total number of packets that we split this file into
+     */
+    protected long totalNrOfMessages = 0;
+
+    /**
+     * The bytes that we hold the data in, not thread safe.
+     */
+    protected byte[] data = new byte[READ_SIZE];
+
+    /**
+     * Private constructor, either instantiates a factory to read or write. <BR>
+     * When openForWrite==true, then a the file, f, will be created and an
+     * output stream is opened to write to it. <BR>
+     * When openForWrite==false, an input stream is opened, the file has to
+     * exist.
+     * 
+     * @param f
+     *            File - the file to be read/written
+     * @param openForWrite
+     *            boolean - true means we are writing to the file, false means
+     *            we are reading from the file
+     * @throws FileNotFoundException -
+     *             if the file to be read doesn't exist
+     * @throws IOException -
+     *             if the system fails to open input/output streams to the file
+     *             or if it fails to create the file to be written to.
+     */
+    private FileMessageFactory(File f, boolean openForWrite)
+            throws FileNotFoundException, IOException {
+        this.file = f;
+        this.openForWrite = openForWrite;
+        if (log.isDebugEnabled())
+            log.debug("open file " + f + " write " + openForWrite);
+        if (openForWrite) {
+            if (!file.exists())
+                file.createNewFile();
+            out = new FileOutputStream(f);
+        } else {
+            size = file.length();
+            totalNrOfMessages = (size / READ_SIZE) + 1;
+            in = new FileInputStream(f);
+        }//end if
+
+    }
+
+    /**
+     * Creates a factory to read or write from a file. When opening for read,
+     * the readMessage can be invoked, and when opening for write the
+     * writeMessage can be invoked.
+     * 
+     * @param f
+     *            File - the file to be read or written
+     * @param openForWrite
+     *            boolean - true, means we are writing to the file, false means
+     *            we are reading from it
+     * @throws FileNotFoundException -
+     *             if the file to be read doesn't exist
+     * @throws IOException -
+     *             if it fails to create the file that is to be written
+     * @return FileMessageFactory
+     */
+    public static FileMessageFactory getInstance(File f, boolean openForWrite)
+            throws FileNotFoundException, IOException {
+        return new FileMessageFactory(f, openForWrite);
+    }
+
+    /**
+     * Reads file data into the file message and sets the size, totalLength,
+     * totalNrOfMsgs and the message number <BR>
+     * If EOF is reached, the factory returns null, and closes itself, otherwise
+     * the same message is returned as was passed in. This makes sure that not
+     * more memory is ever used. To remember, neither the file message or the
+     * factory are thread safe. dont hand off the message to one thread and read
+     * the same with another.
+     * 
+     * @param f
+     *            FileMessage - the message to be populated with file data
+     * @throws IllegalArgumentException -
+     *             if the factory is for writing or is closed
+     * @throws IOException -
+     *             if a file read exception occurs
+     * @return FileMessage - returns the same message passed in as a parameter,
+     *         or null if EOF
+     */
+    public FileMessage readMessage(FileMessage f)
+            throws IllegalArgumentException, IOException {
+        checkState(false);
+        int length = in.read(data);
+        if (length == -1) {
+            cleanup();
+            return null;
+        } else {
+            f.setData(data, length);
+            f.setTotalLength(size);
+            f.setTotalNrOfMsgs(totalNrOfMessages);
+            f.setMessageNumber(++nrOfMessagesProcessed);
+            return f;
+        }//end if
+    }
+
+    /**
+     * Writes a message to file. If (msg.getMessageNumber() ==
+     * msg.getTotalNrOfMsgs()) the output stream will be closed after writing.
+     * 
+     * @param msg
+     *            FileMessage - message containing data to be written
+     * @throws IllegalArgumentException -
+     *             if the factory is opened for read or closed
+     * @throws IOException -
+     *             if a file write error occurs
+     * @return returns true if the file is complete and outputstream is closed,
+     *         false otherwise.
+     */
+    public boolean writeMessage(FileMessage msg)
+            throws IllegalArgumentException, IOException {
+        if (!openForWrite)
+            throw new IllegalArgumentException(
+                    "Can't write message, this factory is reading.");
+        if (log.isDebugEnabled())
+            log.debug("Message " + msg + " data " + msg.getData()
+                    + " data length " + msg.getDataLength() + " out " + out);
+        if (out != null) {
+            out.write(msg.getData(), 0, msg.getDataLength());
+            nrOfMessagesProcessed++;
+            out.flush();
+            if (msg.getMessageNumber() == msg.getTotalNrOfMsgs()) {
+                out.close();
+                cleanup();
+                return true;
+            }//end if
+        } else {
+            if (log.isWarnEnabled())
+                log.warn("Receive Message again -- Sender ActTimeout to short [ path: "
+                                + msg.getContextPath()
+                                + " war: "
+                                + msg.getFileName()
+                                + " data: "
+                                + msg.getData()
+                                + " data length: " + msg.getDataLength() + " ]");
+        }
+        return false;
+    }//writeMessage
+
+    /**
+     * Closes the factory, its streams and sets all its references to null
+     */
+    public void cleanup() {
+        if (in != null)
+            try {
+                in.close();
+            } catch (Exception ignore) {
+            }
+        if (out != null)
+            try {
+                out.close();
+            } catch (Exception ignore) {
+            }
+        in = null;
+        out = null;
+        size = 0;
+        closed = true;
+        data = null;
+        nrOfMessagesProcessed = 0;
+        totalNrOfMessages = 0;
+    }
+
+    /**
+     * Check to make sure the factory is able to perform the function it is
+     * asked to do. Invoked by readMessage/writeMessage before those methods
+     * proceed.
+     * 
+     * @param openForWrite
+     *            boolean
+     * @throws IllegalArgumentException
+     */
+    protected void checkState(boolean openForWrite)
+            throws IllegalArgumentException {
+        if (this.openForWrite != openForWrite) {
+            cleanup();
+            if (openForWrite)
+                throw new IllegalArgumentException(
+                        "Can't write message, this factory is reading.");
+            else
+                throw new IllegalArgumentException(
+                        "Can't read message, this factory is writing.");
+        }
+        if (this.closed) {
+            cleanup();
+            throw new IllegalArgumentException("Factory has been closed.");
+        }
+    }
+
+    /**
+     * Example usage.
+     * 
+     * @param args
+     *            String[], args[0] - read from filename, args[1] write to
+     *            filename
+     * @throws Exception
+     */
+    public static void main(String[] args) throws Exception {
+
+        System.out
+                .println("Usage: FileMessageFactory fileToBeRead fileToBeWritten");
+        System.out
+                .println("Usage: This will make a copy of the file on the local file system");
+        FileMessageFactory read = getInstance(new File(args[0]), false);
+        FileMessageFactory write = getInstance(new File(args[1]), true);
+        FileMessage msg = new FileMessage(null, args[0], args[0]);
+        msg = read.readMessage(msg);
+        System.out.println("Expecting to write " + msg.getTotalNrOfMsgs()
+                + " messages.");
+        int cnt = 0;
+        while (msg != null) {
+            write.writeMessage(msg);
+            cnt++;
+            msg = read.readMessage(msg);
+        }//while
+        System.out.println("Actually wrote " + cnt + " messages.");
+    }///main
+
+    public File getFile() {
+        return file;
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/deploy/UndeployMessage.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/deploy/UndeployMessage.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/deploy/UndeployMessage.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,113 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ *
+ * Licensed 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.cluster.deploy;
+
+import org.apache.catalina.cluster.ClusterMessage;
+import org.apache.catalina.cluster.Member;
+import java.io.Serializable;
+public class UndeployMessage implements ClusterMessage,Serializable {
+    private Member address;
+    private long timestamp;
+    private String uniqueId;
+    private String contextPath;
+    private boolean undeploy;
+    private int resend = ClusterMessage.FLAG_DEFAULT ;
+    private int compress = ClusterMessage.FLAG_DEFAULT ;
+
+    public UndeployMessage() {} //for serialization
+    public UndeployMessage(Member address,
+                           long timestamp,
+                           String uniqueId,
+                           String contextPath,
+                           boolean undeploy) {
+        this.address  = address;
+        this.timestamp= timestamp;
+        this.undeploy = undeploy;
+        this.uniqueId = uniqueId;
+        this.undeploy = undeploy;
+        this.contextPath = contextPath;
+    }
+
+    public Member getAddress() {
+        return address;
+    }
+
+    public void setAddress(Member address) {
+        this.address = address;
+    }
+
+    public long getTimestamp() {
+        return timestamp;
+    }
+
+    public void setTimestamp(long timestamp) {
+        this.timestamp = timestamp;
+    }
+
+    public String getUniqueId() {
+        return uniqueId;
+    }
+
+    public void setUniqueId(String uniqueId) {
+        this.uniqueId = uniqueId;
+    }
+
+    public String getContextPath() {
+        return contextPath;
+    }
+
+    public void setContextPath(String contextPath) {
+        this.contextPath = contextPath;
+    }
+
+    public boolean getUndeploy() {
+        return undeploy;
+    }
+
+    public void setUndeploy(boolean undeploy) {
+        this.undeploy = undeploy;
+    }
+    /**
+     * @return Returns the compress.
+     * @since 5.5.10 
+     */
+    public int getCompress() {
+        return compress;
+    }
+    /**
+     * @param compress The compress to set.
+     * @since 5.5.10
+     */
+    public void setCompress(int compress) {
+        this.compress = compress;
+    }
+    /**
+     * @return Returns the resend.
+     * @since 5.5.10
+     */
+    public int getResend() {
+        return resend;
+    }
+    /**
+     * @param resend The resend to set.
+     * @since 5.5.10
+     */
+    public void setResend(int resend) {
+        this.resend = resend;
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/deploy/WarWatcher.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/deploy/WarWatcher.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/deploy/WarWatcher.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,238 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.cluster.deploy;
+
+import java.io.File;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Iterator;
+
+/**
+ * <p>
+ * The <b>WarWatcher </b> watches the deployDir for changes made to the
+ * directory (adding new WAR files->deploy or remove WAR files->undeploy) And
+ * notifies a listener of the changes made
+ * </p>
+ * 
+ * @author Filip Hanik
+ * @author Peter Rossbach
+ * @version 1.1
+ */
+
+public class WarWatcher {
+
+    /*--Static Variables----------------------------------------*/
+    public static org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory
+            .getLog(WarWatcher.class);
+
+    /*--Instance Variables--------------------------------------*/
+    /**
+     * Directory to watch for war files
+     */
+    protected File watchDir = null;
+
+    /**
+     * Parent to be notified of changes
+     */
+    protected FileChangeListener listener = null;
+
+    /**
+     * Currently deployed files
+     */
+    protected Map currentStatus = new HashMap();
+
+    /*--Constructor---------------------------------------------*/
+
+    public WarWatcher() {
+    }
+
+    public WarWatcher(FileChangeListener listener, File watchDir) {
+        this.listener = listener;
+        this.watchDir = watchDir;
+    }
+
+    /*--Logic---------------------------------------------------*/
+
+    /**
+     * check for modification and send notifcation to listener
+     */
+    public void check() {
+        if (log.isInfoEnabled())
+            log.info("check cluster wars at " + watchDir);
+        File[] list = watchDir.listFiles(new WarFilter());
+        if (list == null)
+            list = new File[0];
+        //first make sure all the files are listed in our current status
+        for (int i = 0; i < list.length; i++) {
+            addWarInfo(list[i]);
+        }
+
+        //check all the status codes and update the FarmDeployer
+        for (Iterator i = currentStatus.entrySet().iterator(); i.hasNext();) {
+            Map.Entry entry = (Map.Entry) i.next();
+            WarInfo info = (WarInfo) entry.getValue();
+            int check = info.check();
+            if (check == 1) {
+                listener.fileModified(info.getWar());
+            } else if (check == -1) {
+                listener.fileRemoved(info.getWar());
+                //no need to keep in memory
+                currentStatus.remove(info.getWar());
+            }
+        }
+
+    }
+
+    /**
+     * add cluster war to the watcher state
+     * @param warfile
+     */
+    protected void addWarInfo(File warfile) {
+        WarInfo info = (WarInfo) currentStatus.get(warfile.getAbsolutePath());
+        if (info == null) {
+            info = new WarInfo(warfile);
+            info.setLastState(-1); //assume file is non existent
+            currentStatus.put(warfile.getAbsolutePath(), info);
+        }
+    }
+
+    /**
+     * clear watcher state
+     */
+    public void clear() {
+        currentStatus.clear();
+    }
+
+    /**
+     * @return Returns the watchDir.
+     */
+    public File getWatchDir() {
+        return watchDir;
+    }
+
+    /**
+     * @param watchDir
+     *            The watchDir to set.
+     */
+    public void setWatchDir(File watchDir) {
+        this.watchDir = watchDir;
+    }
+
+    /**
+     * @return Returns the listener.
+     */
+    public FileChangeListener getListener() {
+        return listener;
+    }
+
+    /**
+     * @param listener
+     *            The listener to set.
+     */
+    public void setListener(FileChangeListener listener) {
+        this.listener = listener;
+    }
+
+    /*--Inner classes-------------------------------------------*/
+
+    /**
+     * File name filter for war files
+     */
+    protected class WarFilter implements java.io.FilenameFilter {
+        public boolean accept(File path, String name) {
+            if (name == null)
+                return false;
+            return name.endsWith(".war");
+        }
+    }
+
+    /**
+     * File information on existing WAR files
+     */
+    protected class WarInfo {
+        protected File war = null;
+
+        protected long lastChecked = 0;
+
+        protected long lastState = 0;
+
+        public WarInfo(File war) {
+            this.war = war;
+            this.lastChecked = war.lastModified();
+            if (!war.exists())
+                lastState = -1;
+        }
+
+        public boolean modified() {
+            return war.exists() && war.lastModified() > lastChecked;
+        }
+
+        public boolean exists() {
+            return war.exists();
+        }
+
+        /**
+         * Returns 1 if the file has been added/modified, 0 if the file is
+         * unchanged and -1 if the file has been removed
+         * 
+         * @return int 1=file added; 0=unchanged; -1=file removed
+         */
+        public int check() {
+            //file unchanged by default
+            int result = 0;
+
+            if (modified()) {
+                //file has changed - timestamp
+                result = 1;
+                lastState = result;
+            } else if ((!exists()) && (!(lastState == -1))) {
+                //file was removed
+                result = -1;
+                lastState = result;
+            } else if ((lastState == -1) && exists()) {
+                //file was added
+                result = 1;
+                lastState = result;
+            }
+            this.lastChecked = System.currentTimeMillis();
+            return result;
+        }
+
+        public File getWar() {
+            return war;
+        }
+
+        public int hashCode() {
+            return war.getAbsolutePath().hashCode();
+        }
+
+        public boolean equals(Object other) {
+            if (other instanceof WarInfo) {
+                WarInfo wo = (WarInfo) other;
+                return wo.getWar().equals(getWar());
+            } else {
+                return false;
+            }
+        }
+
+        protected void setLastState(int lastState) {
+            this.lastState = lastState;
+        }
+
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/io/ListenCallback.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/io/ListenCallback.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/io/ListenCallback.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,47 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.cluster.io;
+
+import org.apache.catalina.cluster.tcp.ClusterData ;
+
+/**
+ * The listen callback interface is used by the replication system
+ * when data has been received. The interface does not care about
+ * objects and marshalling and just passes the bytes straight through.
+ * @author Filip Hanik
+ * @author Peter Rossbach
+ * @version $Revision: 303987 $, $Date: 2005-07-08 15:50:30 -0500 (Fri, 08 Jul 2005) $
+ */
+public interface ListenCallback
+{
+    /**
+     * This method is invoked on the callback object to notify it that new data has
+     * been received from one of the cluster nodes.
+     * @param data - the message bytes received from the cluster/replication system
+     */
+     public void messageDataReceived(ClusterData data);
+     
+    /** receiver must be send ack
+      */
+     public boolean isSendAck() ;
+     
+     /** send ack
+      *
+      */
+     public void sendAck() throws java.io.IOException ;
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/io/ObjectReader.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/io/ObjectReader.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/io/ObjectReader.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,124 @@
+/*
+ * Copyright 1999,2004-2005 The Apache Software Foundation.
+ * 
+ * Licensed 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.cluster.io;
+
+import java.nio.ByteBuffer;
+import java.nio.channels.Selector;
+import java.nio.channels.SocketChannel;
+
+import org.apache.catalina.cluster.tcp.ClusterData;
+
+/**
+ * The object reader object is an object used in conjunction with
+ * java.nio TCP messages. This object stores the message bytes in a
+ * <code>XByteBuffer</code> until a full package has been received.
+ * When a full package has been received, the append method will call messageDataReceived
+ * on the callback object associated with this object reader.<BR>
+ * This object uses an XByteBuffer which is an extendable object buffer that also allows
+ * for message encoding and decoding.
+ *
+ * @author Filip Hanik
+ * @author Peter Rossbach
+ * @version $Revision: 380229 $, $Date: 2006-02-23 15:28:29 -0600 (Thu, 23 Feb 2006) $
+ */
+public class ObjectReader {
+
+    private SocketChannel channel;
+
+    private Selector selector;
+
+    private ListenCallback callback;
+
+    private XByteBuffer buffer;
+
+    /**
+     * Create XByteBuffer and store parameter
+     * @param channel
+     * @param selector
+     * @param callback
+     */
+    public ObjectReader(SocketChannel channel, Selector selector, ListenCallback callback) {
+        this.channel = channel;
+        this.selector = selector;
+        this.callback = callback;
+        this.buffer = new XByteBuffer();
+    }
+
+    /**
+     * get the current SimpleTcpCluster
+     * @return Returns the callback.
+     */
+    public ListenCallback getCallback() {
+        return callback;
+    }
+
+    /**
+     * Get underlying NIO channel
+     * @return The socket
+     */
+    public SocketChannel getChannel() {
+        return this.channel;
+    }
+
+    /**
+     * Append new bytes to buffer. 
+     * @see XByteBuffer#countPackages()
+     * @param data new transfer buffer
+     * @param off offset
+     * @param len length in buffer
+     * @return number of messages that sended to callback
+     * @throws java.io.IOException
+     */
+     public int append(byte[] data,int off,int len) throws java.io.IOException {
+        buffer.append(data,off,len);
+        int pkgCnt = buffer.countPackages();
+        return pkgCnt;
+    }
+
+    /**
+     * Send buffer to cluster listener (callback).
+     * Is message complete receiver send message to callback?
+     *
+     * @see org.apache.catalina.cluster.tcp.ClusterReceiverBase#messageDataReceived(ClusterData)
+     * @see XByteBuffer#doesPackageExist()
+     * @see XByteBuffer#extractPackage(boolean)
+     *
+     * @return number of received packages/messages
+     * @throws java.io.IOException
+     */
+    public int execute() throws java.io.IOException {
+        int pkgCnt = 0;
+        boolean pkgExists = buffer.doesPackageExist();
+        while ( pkgExists ) {
+            ClusterData data = buffer.extractPackage(true);
+            getCallback().messageDataReceived(data);
+            pkgCnt++;
+            pkgExists = buffer.doesPackageExist();
+        }
+        return pkgCnt;
+    }
+    
+    /**
+     * Write Ack to sender
+     * @param buf
+     * @return The bytes written count
+     * @throws java.io.IOException
+     */
+    public int write(ByteBuffer buf) throws java.io.IOException {
+        return getChannel().write(buf);
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/io/SocketObjectReader.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/io/SocketObjectReader.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/io/SocketObjectReader.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,109 @@
+/*
+ * Copyright 1999,2004-2005 The Apache Software Foundation.
+ * 
+ * Licensed 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.cluster.io;
+
+
+import java.net.Socket;
+
+import org.apache.catalina.cluster.tcp.ClusterData;
+
+/**
+ * The object reader object is an object used in conjunction with
+ * java.nio TCP messages. This object stores the message bytes in a
+ * <code>XByteBuffer</code> until a full package has been received.
+ * When a full package has been received, the append method will call messageDataReceived
+ * on the callback object associated with this object reader.<BR>
+ * This object uses an XByteBuffer which is an extendable object buffer that also allows
+ * for message encoding and decoding.
+ *
+ * @author Filip Hanik
+ * @author Peter Rossbach
+ * @version $Revision: 304032 $, $Date: 2005-07-27 10:11:55 -0500 (Wed, 27 Jul 2005) $
+ * @since 5.5.10
+ */
+public class SocketObjectReader
+{
+    private Socket socket;
+    private ListenCallback callback;
+    private XByteBuffer buffer;
+
+    /**
+     * use this socket and callback to receive messages
+     * @param socket listener socket
+     * @param callback ClusterReceiverBase listener
+     */
+    public SocketObjectReader( Socket socket,
+                               ListenCallback callback)  {
+        this.socket = socket;
+        this.callback = callback;
+        this.buffer = new XByteBuffer();
+    }
+
+    
+    /**
+     * Append new bytes to buffer. 
+     * Is message complete receiver send message to callback
+     * @see org.apache.catalina.cluster.tcp.ClusterReceiverBase#messageDataReceived(ClusterData)
+     * @see XByteBuffer#doesPackageExist()
+     * @see XByteBuffer#extractPackage(boolean)
+     * @param data new transfer buffer
+     * @param off offset
+     * @param len length in buffer
+     * @return number of messages that sended to callback
+     * @throws java.io.IOException
+     */
+    public int append(byte[] data,int off,int len) throws java.io.IOException {
+        if(len > 0)
+            buffer.append(data,off,len);
+        boolean pkgExists = buffer.doesPackageExist();
+        int pkgCnt = 0;
+        while ( pkgExists ) {
+            ClusterData cdata = buffer.extractPackage(true);
+            if(callback.isSendAck())
+                callback.sendAck() ;
+            callback.messageDataReceived(cdata);
+            pkgCnt++;
+            pkgExists = buffer.doesPackageExist();
+        }
+        return pkgCnt;
+    }
+
+    
+    /**
+     * send message to callback
+     * @see SocketObjectReader#append(byte[], int, int)
+     * @return Count of packages written
+     * @throws java.io.IOException
+     */
+    public int execute() throws java.io.IOException {
+        return append(null,0,0);
+    }
+
+    /**
+     * write data to socket (ack)
+     * @see org.apache.catalina.cluster.tcp.SocketReplicationListener#sendAck
+     * @param data
+     * @return Always zero
+     * @throws java.io.IOException
+     */
+    public int write(byte[] data)
+       throws java.io.IOException {
+       socket.getOutputStream().write(data);
+       return 0;
+
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/io/XByteBuffer.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/io/XByteBuffer.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/io/XByteBuffer.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,357 @@
+/*
+ * Copyright 1999,2004-2005 The Apache Software Foundation.
+ * 
+ * Licensed 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.cluster.io;
+
+import org.apache.catalina.cluster.tcp.ClusterData;
+
+/**
+ * The XByteBuffer provides a dual functionality.
+ * One, it stores message bytes and automatically extends the byte buffer if needed.<BR>
+ * Two, it can encode and decode packages so that they can be defined and identified
+ * as they come in on a socket.
+ * <br/>
+ * Transfer package:
+ * <ul>
+ * <li><b>START_DATA/b> - 7 bytes - <i>FLT2002</i></li>
+ * <li><b>COMPRESS</b>  - 4 bytes - is message compressed flag</li>
+ * <li><b>SIZE</b>      - 4 bytes - size of the data package</li>
+ * <li><b>DATA</b>      - should be as many bytes as the prev SIZE</li>
+ * <li><b>END_DATA</b>  - 7 bytes - <i>TLF2003</i></lI>
+ * </ul>
+ * FIXME: Why we not use a list of byte buffers?
+ * FIXME: Used a pool of buffers instead, every time new generation
+ *
+ * @author Filip Hanik
+ * @author Peter Rossbach
+ * @version $Revision: 384818 $, $Date: 2006-03-10 09:29:17 -0600 (Fri, 10 Mar 2006) $
+ */
+public class XByteBuffer
+{
+    
+    public static org.apache.commons.logging.Log log =
+        org.apache.commons.logging.LogFactory.getLog( XByteBuffer.class );
+    
+    /**
+     * This is a package header, 7 bytes (FLT2002)
+     */
+    public static final byte[] START_DATA = {70,76,84,50,48,48,50};
+    
+    /**
+     * This is the package footer, 7 bytes (TLF2003)
+     */
+    public static final byte[] END_DATA = {84,76,70,50,48,48,51};
+ 
+    /**
+     * Default size on the initial byte buffer
+     */
+    static final int DEF_SIZE = 1024;
+ 
+    /**
+     * Default size to extend the buffer with
+     */
+    static final int DEF_EXT  = 1024;
+    
+    /**
+     * Variable to hold the data
+     */
+    protected byte[] buf = null;
+    
+    /**
+     * Current length of data in the buffer
+     */
+    protected int bufSize = 0;
+    
+    /**
+     * Constructs a new XByteBuffer
+     * @param size - the initial size of the byte buffer
+     */
+    public XByteBuffer(int size) {
+        buf = new byte[size];
+    }
+
+    /**
+     * Constructs a new XByteBuffer with an initial size of 1024 bytes
+     */
+    public XByteBuffer()  {
+        this(DEF_SIZE);
+    }
+
+    /**
+     * Returns the bytes in the buffer, in its exact length
+     */
+    public byte[] getBytes() {
+        byte[] b = new byte[bufSize];
+        System.arraycopy(buf,0,b,0,bufSize);
+        return b;
+    }
+
+    /**
+     * Resets the buffer
+     */
+    public void clear() {
+        bufSize = 0;
+    }
+
+    /**
+     * Appends the data to the buffer. If the data is incorrectly formatted, ie, the data should always start with the
+     * header, false will be returned and the data will be discarded.
+     * @param b - bytes to be appended
+     * @param off - the offset to extract data from
+     * @param len - the number of bytes to append.
+     * @return true if the data was appended correctly. Returns false if the package is incorrect, ie missing header or something, or the length of data is 0
+     */
+    public boolean append(byte[] b, int off, int len) {
+        if ((off < 0) || (off > b.length) || (len < 0) ||
+            ((off + len) > b.length) || ((off + len) < 0))  {
+            throw new IndexOutOfBoundsException();
+        } else if (len == 0) {
+            return false;
+        }
+
+        int newcount = bufSize + len;
+        if (newcount > buf.length) {
+            byte newbuf[] = new byte[Math.max(buf.length << 1, newcount)];
+            System.arraycopy(buf, 0, newbuf, 0, bufSize);
+            buf = newbuf;
+        }
+        System.arraycopy(b, off, buf, bufSize, len);
+        bufSize = newcount;
+
+        if (bufSize > START_DATA.length && (firstIndexOf(buf,0,START_DATA)==-1)){
+            bufSize = 0;
+            log.error("Discarded the package, invalid header");
+            return false;
+        }
+        return true;
+    }
+
+
+    /**
+     * Internal mechanism to make a check if a complete package exists
+     * within the buffer
+     * @return - true if a complete package (header,compress,size,data,footer) exists within the buffer
+     */
+    public int countPackages()
+    {
+        int cnt = 0;
+        int pos = START_DATA.length;
+        int start = 0;
+
+        while ( start < bufSize ) {
+            //first check start header
+            int index = XByteBuffer.firstIndexOf(buf,start,START_DATA);
+            //if the header (START_DATA) isn't the first thing or
+            //the buffer isn't even 14 bytes
+            if ( index != start || ((bufSize-start)<14) ) break;
+            //next 4 bytes are compress flag not needed for count packages
+            //then get the size 4 bytes
+            int size = toInt(buf, pos+4);
+            //now the total buffer has to be long enough to hold
+            //START_DATA.length+8+size+END_DATA.length
+            pos = start + START_DATA.length + 8 + size;
+            if ( (pos + END_DATA.length) > bufSize) break;
+            //and finally check the footer of the package END_DATA
+            int newpos = firstIndexOf(buf, pos, END_DATA);
+            //mismatch, there is no package
+            if (newpos != pos) break;
+            //increase the packet count
+            cnt++;
+            //reset the values
+            start = pos + END_DATA.length;
+            pos = start + START_DATA.length;
+        }
+        return cnt;
+    }
+
+    /**
+     * Method to check if a package exists in this byte buffer.
+     * @return - true if a complete package (header,compress,size,data,footer) exists within the buffer
+     */
+    public boolean doesPackageExist()  {
+        return (countPackages()>0);
+    }
+
+    /**
+     * Extracts the message bytes from a package.
+     * If no package exists, a IllegalStateException will be thrown.
+     * @param clearFromBuffer - if true, the package will be removed from the byte buffer
+     * @return - returns the actual message bytes (header, compress,size and footer not included).
+     */
+    public ClusterData extractPackage(boolean clearFromBuffer)
+            throws java.io.IOException {
+        int psize = countPackages();
+        if (psize == 0) throw new java.lang.IllegalStateException("No package exists in XByteBuffer");
+        int compress = toInt(buf, START_DATA.length);
+        int size = toInt(buf, START_DATA.length +4);
+        byte[] data = new byte[size];
+        System.arraycopy(buf, START_DATA.length + 8, data, 0, size);
+        ClusterData cdata = new ClusterData() ;
+        cdata.setMessage(data);
+        cdata.setCompress(compress);
+        if (clearFromBuffer) {
+            int totalsize = START_DATA.length + 8 + size + END_DATA.length;
+            bufSize = bufSize - totalsize;
+            System.arraycopy(buf, totalsize, buf, 0, bufSize);
+        }
+        return cdata;
+    }
+
+    /**
+     * Convert four bytes to an int
+     * @param b - the byte array containing the four bytes
+     * @param off - the offset
+     * @return the integer value constructed from the four bytes
+     * @exception java.lang.ArrayIndexOutOfBoundsException
+     */
+    public static int toInt(byte[] b,int off){
+        return ( ( (int) b[off+3]) & 0xFF) +
+            ( ( ( (int) b[off+2]) & 0xFF) << 8) +
+            ( ( ( (int) b[off+1]) & 0xFF) << 16) +
+            ( ( ( (int) b[off+0]) & 0xFF) << 24);
+    }
+
+    /**
+     * Convert eight bytes to a long
+     * @param b - the byte array containing the four bytes
+     * @param off - the offset
+     * @return the long value constructed from the eight bytes
+     * @exception java.lang.ArrayIndexOutOfBoundsException
+     */
+    public static long toLong(byte[] b,int off){
+        return ( ( (long) b[off+7]) & 0xFF) +
+            ( ( ( (long) b[off+6]) & 0xFF) << 8) +
+            ( ( ( (long) b[off+5]) & 0xFF) << 16) +
+            ( ( ( (long) b[off+4]) & 0xFF) << 24) +
+            ( ( ( (long) b[off+3]) & 0xFF) << 32) +
+            ( ( ( (long) b[off+2]) & 0xFF) << 40) +
+            ( ( ( (long) b[off+1]) & 0xFF) << 48) +
+            ( ( ( (long) b[off+0]) & 0xFF) << 56);
+    }
+
+    /**
+     * Converts an integer to four bytes
+     * @param n - the integer
+     * @return - four bytes in an array
+     */
+    public static byte[] toBytes(int n) {
+        byte[] b = new byte[4];
+        b[3] = (byte) (n);
+        n >>>= 8;
+        b[2] = (byte) (n);
+        n >>>= 8;
+        b[1] = (byte) (n);
+        n >>>= 8;
+        b[0] = (byte) (n);
+        return b;
+    }
+
+    /**
+     * Converts an long to eight bytes
+     * @param n - the long
+     * @return - eight bytes in an array
+     */
+    public static byte[] toBytes(long n) {
+        byte[] b = new byte[8];
+        b[7] = (byte) (n);
+        n >>>= 8;
+        b[6] = (byte) (n);
+        n >>>= 8;
+        b[5] = (byte) (n);
+        n >>>= 8;
+        b[4] = (byte) (n);
+        n >>>= 8;
+        b[3] = (byte) (n);
+        n >>>= 8;
+        b[2] = (byte) (n);
+        n >>>= 8;
+        b[1] = (byte) (n);
+        n >>>= 8;
+        b[0] = (byte) (n);
+        return b;
+    }
+
+    /**
+     * Similar to a String.IndexOf, but uses pure bytes
+     * @param src - the source bytes to be searched
+     * @param srcOff - offset on the source buffer
+     * @param find - the string to be found within src
+     * @return - the index of the first matching byte. -1 if the find array is not found
+     */
+    public static int firstIndexOf(byte[] src, int srcOff, byte[] find){
+        int result = -1;
+        if (find.length > src.length) return result;
+        if (find.length == 0 || src.length == 0) return result;
+        if (srcOff >= src.length ) throw new java.lang.ArrayIndexOutOfBoundsException();
+        boolean found = false;
+        int srclen = src.length;
+        int findlen = find.length;
+        byte first = find[0];
+        int pos = srcOff;
+        while (!found) {
+            //find the first byte
+            while (pos < srclen){
+                if (first == src[pos])
+                    break;
+                pos++;
+            }
+            if (pos >= srclen)
+                return -1;
+
+            //we found the first character
+            //match the rest of the bytes - they have to match
+            if ( (srclen - pos) < findlen)
+                return -1;
+            //assume it does exist
+            found = true;
+            for (int i = 1; ( (i < findlen) && found); i++)
+                found = found && (find[i] == src[pos + i]);
+            if (found)
+                result = pos;
+            else if ( (srclen - pos) < findlen)
+                return -1; //no more matches possible
+            else
+                pos++;
+        }
+        return result;
+    }
+
+    /**
+     * Creates a complete data package
+     * @param indata - the message data to be contained within the package
+     * @param compressed - compression flag for the indata buffer
+     * @return - a full package (header,compress,size,data,footer)
+     * 
+     */
+    public static byte[] createDataPackage(byte[] indata, int compressed)
+            throws java.io.IOException {
+        byte[] data = indata;
+        byte[] comprdata = XByteBuffer.toBytes(compressed);
+        int length = 
+            START_DATA.length + //header length
+            4 + //compression flag
+            4 + //data length indicator
+            data.length + //actual data length
+            END_DATA.length; //footer length
+        byte[] result = new byte[length];
+        System.arraycopy(START_DATA, 0, result, 0, START_DATA.length);
+        System.arraycopy(comprdata, 0, result, START_DATA.length, 4);
+        System.arraycopy(toBytes(data.length), 0, result, START_DATA.length + 4, 4);
+        System.arraycopy(data, 0, result, START_DATA.length + 8, data.length);
+        System.arraycopy(END_DATA, 0, result, START_DATA.length + 8 + data.length, END_DATA.length);
+        return result;
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/mbeans-descriptors.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/mbeans-descriptors.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/mbeans-descriptors.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,94 @@
+<?xml version="1.0"?>
+<mbeans-descriptors>
+
+  <mbean         name="SimpleTcpCluster"
+            className="org.apache.catalina.mbeans.ClassNameMBean"
+          description="Tcp Cluster implementation"
+               domain="Catalina"
+                group="Cluster"
+                 type="org.apache.catalina.cluster.tcp.SimpleTcpCluster">
+
+    <attribute   name="protocolStack"
+          description="JavaGroups protocol stack selection"
+                 type="java.lang.String"/>
+
+  </mbean>
+
+
+  <mbean         name="SimpleTcpReplicationManager"
+            className="org.apache.catalina.mbeans.ClassNameMBean"
+          description="Clustered implementation of the Manager interface"
+               domain="Catalina"
+                group="Manager"
+                 type="org.apache.catalina.cluster.tcp.SimpleTcpReplicationManager">
+
+    <attribute   name="algorithm"
+          description="The message digest algorithm to be used when generating
+                       session identifiers"
+                 type="java.lang.String"/>
+
+    <attribute   name="checkInterval"
+          description="The interval (in seconds) between checks for expired
+                       sessions"
+                 type="int"/>
+
+    <attribute   name="className"
+          description="Fully qualified class name of the managed object"
+                 type="java.lang.String"
+            writeable="false"/>
+
+    <attribute   name="distributable"
+          description="The distributable flag for Sessions created by this
+                       Manager"
+                 type="boolean"/>
+
+    <attribute   name="entropy"
+          description="A String initialization parameter used to increase the
+                       entropy of the initialization of our random number
+                       generator"
+                 type="java.lang.String"/>
+
+    <attribute   name="managedResource"
+          description="The managed resource this MBean is associated with"
+                 type="java.lang.Object"/>
+
+    <attribute   name="maxActiveSessions"
+          description="The maximum number of active Sessions allowed, or -1
+                       for no limit"
+                 type="int"/>
+
+    <attribute   name="maxInactiveInterval"
+          description="The default maximum inactive interval for Sessions
+                       created by this Manager"
+                 type="int"/>
+
+    <attribute   name="name"
+          description="The descriptive name of this Manager implementation
+                       (for logging)"
+                 type="java.lang.String"
+            writeable="false"/>
+
+  </mbean>
+
+
+
+<mbean         name="ReplicationValve"
+            className="org.apache.catalina.mbeans.ClassNameMBean"
+          description="Valve for simple tcp replication"
+               domain="Catalina"
+                group="Valve"
+                 type="org.apache.catalina.cluster.tcp.ReplicationValve">
+
+    <attribute   name="className"
+          description="Fully qualified class name of the managed object"
+                 type="java.lang.String"
+            writeable="false"/>
+
+    <attribute   name="debug"
+          description="The debugging detail level for this component"
+                 type="int"/>
+
+  </mbean>
+
+
+</mbeans-descriptors>

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/mcast/Constants.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/mcast/Constants.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/mcast/Constants.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,32 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.cluster.mcast;
+
+/**
+ * Manifest constants for the <code>org.apache.catalina.cluster.mcast</code>
+ * package.
+ *
+ * @author Peter Rossbach
+ * @version $Revision: 303950 $ $Date: 2005-06-09 15:38:30 -0500 (Thu, 09 Jun 2005) $
+ */
+
+public class Constants {
+
+    public static final String Package = "org.apache.catalina.cluster.mcast";
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/mcast/LocalStrings.properties
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/mcast/LocalStrings.properties	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/mcast/LocalStrings.properties	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1 @@
+cluster.mbean.register.already=MBean {0} already registered!

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/mcast/McastMember.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/mcast/McastMember.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/mcast/McastMember.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,338 @@
+/*
+ * Copyright 1999,2004-2005 The Apache Software Foundation.
+ * 
+ * Licensed 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.cluster.mcast;
+
+import org.apache.catalina.cluster.Member;
+import org.apache.catalina.cluster.io.XByteBuffer;
+
+/**
+ * A <b>membership</b> implementation using simple multicast.
+ * This is the representation of a multicast member.
+ * Carries the host, and port of the this or other cluster nodes.
+ *
+ * @author Filip Hanik
+ * @author Peter Rossbach
+ * @version $Revision: 304032 $, $Date: 2005-07-27 10:11:55 -0500 (Wed, 27 Jul 2005) $
+ */
+public class McastMember implements Member, java.io.Serializable {
+
+    /**
+     * Digits, used for "superfast" de-serialization of an
+     * IP address
+     */
+    final transient static char[] digits = {
+        '0', '1', '2', '3', '4', '5',
+        '6', '7', '8', '9'};
+
+    /**
+     * Public properties specific to this implementation
+     */
+    public static final transient String TCP_LISTEN_PORT = "tcpListenPort";
+    public static final transient String TCP_LISTEN_HOST = "tcpListenHost";
+    public static final transient String MEMBER_NAME = "memberName";
+    public static final transient String MEMBER_DOMAIN = "memberDomain";
+    
+    /**
+     * The listen host for this member
+     */
+    protected String host;
+    /**
+     * The tcp listen port for this member
+     */
+    protected int port;
+    /**
+     * The name for this member, has be be unique within the cluster.
+     */
+    private String name;
+
+    /**
+     * The name of the cluster domain from this node
+     */
+    private String domain;
+    
+    /**
+     * Counter for how many messages have been sent from this member
+     */
+    protected int msgCount = 0;
+    /**
+     * The number of milliseconds since this members was
+     * created, is kept track of using the start time
+     */
+    protected long memberAliveTime = 0;
+
+
+    /**
+     * Construct a new member object
+     * @param name - the name of this member, cluster unique
+     * @param domain - the cluster domain name of this member
+     * @param host - the tcp listen host
+     * @param port - the tcp listen port
+     */
+    public McastMember(String name,
+                       String domain,
+                       String host,
+                       int port,
+                       long aliveTime) {
+        this.host = host;
+        this.port = port;
+        this.name = name;
+        this.domain = domain;
+        this.memberAliveTime=aliveTime;
+    }
+
+    /**
+     *
+     * @return a Hashmap containing the following properties:<BR>
+     * 1. tcpListenPort - the port this member listens to for messages - string<BR>
+     * 2. tcpListenHost - the host address of this member - string<BR>
+     * 3. memberName    - the name of this member - string<BR>
+     */
+    public java.util.HashMap getMemberProperties() {
+        java.util.HashMap map = new java.util.HashMap(2);
+        map.put(McastMember.TCP_LISTEN_HOST,this.host);
+        map.put(McastMember.TCP_LISTEN_PORT,String.valueOf(this.port));
+        map.put(McastMember.MEMBER_NAME,name);
+        map.put(McastMember.MEMBER_DOMAIN,domain);
+        return map;
+    }
+
+    /**
+     * Increment the message count.
+     */
+    protected void inc() {
+        msgCount++;
+    }
+
+    /**
+     * Create a data package to send over the wire representing this member.
+     * This is faster than serialization.
+     * @return - the bytes for this member deserialized
+     * @throws Exception
+     */
+    protected byte[] getData(long startTime) throws Exception {
+        //package looks like
+        //alive - 8 bytes
+        //port - 4 bytes
+        //host - 4 bytes
+        //nlen - 4 bytes
+        //name - nlen bytes
+        //dlen - 4 bytes
+        //domain - dlen bytes
+        byte[] named = getName().getBytes();
+        byte[] domaind = getDomain().getBytes();
+        byte[] addr = java.net.InetAddress.getByName(host).getAddress();
+        byte[] data = new byte[8+4+addr.length+4+named.length+4+domaind.length];
+        long alive=System.currentTimeMillis()-startTime;
+        System.arraycopy(XByteBuffer.toBytes((long)alive),0,data,0,8);
+        System.arraycopy(XByteBuffer.toBytes(port),0,data,8,4);
+        System.arraycopy(addr,0,data,12,addr.length);
+        System.arraycopy(XByteBuffer.toBytes(named.length),0,data,16,4);
+        System.arraycopy(named,0,data,20,named.length);
+        System.arraycopy(XByteBuffer.toBytes(domaind.length),0,data,named.length+20,4);
+        System.arraycopy(domaind,0,data,named.length+24,domaind.length);
+        return data;
+    }
+    /**
+     * Deserializes a member from data sent over the wire
+     * @param data - the bytes received
+     * @return a member object.
+     */
+    protected static McastMember getMember(byte[] data) {
+       //package looks like
+       //alive - 8 bytes
+       //port - 4 bytes
+       //host - 4 bytes
+       //nlen - 4 bytes
+       //name - nlen bytes
+       //dlen - 4 bytes
+       //domain - dlen bytes
+       byte[] alived = new byte[8];
+       System.arraycopy(data, 0, alived, 0, 8);
+       byte[] portd = new byte[4];
+       System.arraycopy(data, 8, portd, 0, 4);
+       byte[] addr = new byte[4];
+       System.arraycopy(data, 12, addr, 0, 4);
+       //FIXME control the nlen
+       byte[] nlend = new byte[4];
+       System.arraycopy(data, 16, nlend, 0, 4);
+       int nlen = XByteBuffer.toInt(nlend, 0);
+       byte[] named = new byte[nlen];
+       System.arraycopy(data, 20, named, 0, named.length);
+       //FIXME control the dlen
+       byte[] dlend = new byte[4];
+       System.arraycopy(data, nlen + 20, dlend, 0, 4);
+       int dlen = XByteBuffer.toInt(dlend, 0);
+       byte[] domaind = new byte[dlen];
+       System.arraycopy(data, nlen + 24, domaind, 0, domaind.length);
+       return new McastMember(new String(named),
+                              new String(domaind),
+                              addressToString(addr),
+                              XByteBuffer.toInt(portd, 0),
+                              XByteBuffer.toLong(alived, 0));
+    }
+
+    /**
+     * Return the name of this object
+     * @return a unique name to the cluster
+     */
+    public String getName() {
+        return name;
+    }
+    
+    /**
+     * Return the domain of this object
+     * @return a cluster domain to the cluster
+     */
+    public String getDomain() {
+        return domain;
+    }
+    
+    /**
+     * Return the listen port of this member
+     * @return - tcp listen port
+     */
+    public int getPort()  {
+        return this.port;
+    }
+
+    /**
+     * Return the TCP listen host for this member
+     * @return IP address or host name
+     */
+    public String getHost()  {
+        return this.host;
+    }
+
+    /**
+     * Contains information on how long this member has been online.
+     * The result is the number of milli seconds this member has been
+     * broadcasting its membership to the cluster.
+     * @return nr of milliseconds since this member started.
+     */
+    public long getMemberAliveTime() {
+       return memberAliveTime;
+    }
+
+    public void setMemberAliveTime(long time) {
+       memberAliveTime=time;
+    }
+
+
+
+    /**
+     * String representation of this object
+     */
+    public String toString()  {
+        return "org.apache.catalina.cluster.mcast.McastMember["+name+","+domain+","+host+","+port+", alive="+memberAliveTime+"]";
+    }
+
+    /**
+     * @see java.lang.Object#hashCode()
+     * @return The hash code
+     */
+    public int hashCode() {
+        return this.name.hashCode();
+    }
+
+    /**
+     * Returns true if the param o is a McastMember with the same name
+     * @param o
+     */
+    public boolean equals(Object o) {
+        if ( o instanceof McastMember )    {
+            return this.name.equals(((McastMember)o).getName());
+        }
+        else
+            return false;
+    }
+
+    /**
+     * Converts for bytes (ip address) to a string representation of it<BR>
+     * Highly optimized method.
+     * @param address (4 bytes ip address)
+     * @return string representation of that ip address
+     */
+    private static final String addressToString(byte[] address) {
+        int q, r = 0;
+        int charPos = 15;
+        char[] buf = new char[15];
+        char dot = '.';
+
+        int i = address[3] & 0xFF;
+        for (; ; )
+        {
+            q = (i * 52429) >>> (19);
+            r = i - ( (q << 3) + (q << 1));
+            buf[--charPos] = digits[r];
+            i = q;
+            if (i == 0)
+                break;
+        }
+        buf[--charPos] = dot;
+        i = address[2] & 0xFF;
+        for (; ; )
+        {
+            q = (i * 52429) >>> (19);
+            r = i - ( (q << 3) + (q << 1));
+            buf[--charPos] = digits[r];
+            i = q;
+            if (i == 0)
+                break;
+        }
+        buf[--charPos] = dot;
+
+        i = address[1] & 0xFF;
+        for (; ; )
+        {
+            q = (i * 52429) >>> (19);
+            r = i - ( (q << 3) + (q << 1));
+            buf[--charPos] = digits[r];
+            i = q;
+            if (i == 0)
+                break;
+        }
+
+        buf[--charPos] = dot;
+        i = address[0] & 0xFF;
+
+        for (; ; )
+        {
+            q = (i * 52429) >>> (19);
+            r = i - ( (q << 3) + (q << 1));
+            buf[--charPos] = digits[r];
+            i = q;
+            if (i == 0)
+                break;
+        }
+        return new String(buf, charPos, 15 - charPos);
+    }
+    public void setHost(String host) {
+        this.host = host;
+    }
+    public void setMsgCount(int msgCount) {
+        this.msgCount = msgCount;
+    }
+    public void setName(String name) {
+        this.name = name;
+    }
+    public void setDomain(String domain) {
+        this.domain = domain;
+    }
+    public void setPort(int port) {
+        this.port = port;
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/mcast/McastMembership.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/mcast/McastMembership.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/mcast/McastMembership.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,280 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.cluster.mcast;
+
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Iterator;
+
+/**
+ * A <b>membership</b> implementation using simple multicast.
+ * This is the representation of a multicast membership.
+ * This class is responsible for maintaining a list of active cluster nodes in the cluster.
+ * If a node fails to send out a heartbeat, the node will be dismissed.
+ *
+ * @author Filip Hanik
+ * @author Peter Rossbach
+ * @version $Revision: 356540 $, $Date: 2005-12-13 10:53:40 -0600 (Tue, 13 Dec 2005) $
+ */
+public class McastMembership
+{
+    protected static final McastMember[] EMPTY_MEMBERS = new McastMember[0];
+    
+    /**
+     * The name of this membership, has to be the same as the name for the local
+     * member
+     */
+    protected String name;
+    
+    /**
+     * A map of all the members in the cluster.
+     */
+    protected Map map = new HashMap();
+    
+    /**
+     * A list of all the members in the cluster.
+     */
+    protected McastMember[] members = EMPTY_MEMBERS;
+    
+    /**
+      * sort members by alive time
+      */
+    protected MemberComparator memberComparator = new MemberComparator();
+
+    /**
+     * Constructs a new membership
+     * @param name - has to be the name of the local member. Used to filter the local member from the cluster membership
+     */
+    public McastMembership(String name) {
+        this.name = name;
+    }
+
+    /**
+     * Reset the membership and start over fresh.
+     * Ie, delete all the members and wait for them to ping again and join this membership
+     */
+    public synchronized void reset() {
+        map.clear();
+        members = EMPTY_MEMBERS ;
+    }
+
+    /**
+     * Notify the membership that this member has announced itself.
+     *
+     * @param member - the member that just pinged us
+     * @return - true if this member is new to the cluster, false otherwise.
+     * @return - false if this member is the local member or updated.
+     */
+    public synchronized boolean memberAlive(McastMember member) {
+        boolean result = false;
+        //ignore ourselves
+        if ( member.getName().equals(name) ) return result;
+
+        //return true if the membership has changed
+        MbrEntry entry = (MbrEntry)map.get(member.getName());
+        if ( entry == null ) {
+            entry = new MbrEntry(member);
+            map.put(member.getName(),entry);
+            addMcastMember(member);
+            result = true;
+       } else {
+            //update the member alive time
+            McastMember updateMember = entry.getMember() ;
+            if(updateMember.getMemberAliveTime() != member.getMemberAliveTime()) {
+                updateMember.setMemberAliveTime(member.getMemberAliveTime());
+                Arrays.sort(members, memberComparator);
+            }
+        }
+        entry.accessed();
+ 
+        return result;
+    }
+
+    /**
+     * Add a member to this component and sort array with memberComparator
+     * @param member The member to add
+     */
+    protected void addMcastMember(McastMember member) {
+      synchronized (members) {
+          McastMember results[] =
+            new McastMember[members.length + 1];
+          for (int i = 0; i < members.length; i++)
+              results[i] = members[i];
+          results[members.length] = member;
+          members = results;
+          Arrays.sort(members, memberComparator);
+      }
+    }
+    
+    /**
+     * Remove a member from this component.
+     * 
+     * @param member The member to remove
+     */
+    protected void removeMcastMember(McastMember member) {
+        synchronized (members) {
+            int n = -1;
+            for (int i = 0; i < members.length; i++) {
+                if (members[i] == member) {
+                    n = i;
+                    break;
+                }
+            }
+            if (n < 0)
+                return;
+            McastMember results[] =
+              new McastMember[members.length - 1];
+            int j = 0;
+            for (int i = 0; i < members.length; i++) {
+                if (i != n)
+                    results[j++] = members[i];
+            }
+            members = results;
+        }
+    }
+
+    /**
+     * Runs a refresh cycle and returns a list of members that has expired.
+     * This also removes the members from the membership, in such a way that
+     * getMembers() = getMembers() - expire()
+     * @param maxtime - the max time a member can remain unannounced before it is considered dead.
+     * @return the list of expired members
+     */
+    public synchronized McastMember[] expire(long maxtime) {
+        if(!hasMembers() )
+           return EMPTY_MEMBERS;
+       
+        ArrayList list = null;
+        Iterator i = map.values().iterator();
+        while(i.hasNext()) {
+            MbrEntry entry = (MbrEntry)i.next();
+            if( entry.hasExpired(maxtime) ) {
+                if(list == null) // only need a list when members are expired (smaller gc)
+                    list = new java.util.ArrayList();
+                list.add(entry.getMember());
+            }
+        }
+        
+        if(list != null) {
+            McastMember[] result = new McastMember[list.size()];
+            list.toArray(result);
+            for( int j=0; j<result.length; j++) {
+                map.remove(result[j].getName());
+                removeMcastMember(result[j]);
+            }
+            return result;
+        } else {
+            return EMPTY_MEMBERS ;
+        }
+    }
+
+    /**
+     * Returning that service has members or not
+     */
+    public synchronized boolean hasMembers() {
+        return members.length > 0 ;
+    }
+ 
+    /**
+     * Returning a list of all the members in the membership
+     * We not need a copy: add and remove generate new arrays.
+     */
+    public synchronized McastMember[] getMembers() {
+        if(hasMembers()) {
+            return members;
+        } else {
+            return EMPTY_MEMBERS;
+        }
+    }
+
+    /**
+     * get a copy from all member entries
+     */
+    protected synchronized MbrEntry[] getMemberEntries()
+    {
+        MbrEntry[] result = new MbrEntry[map.size()];
+        java.util.Iterator i = map.entrySet().iterator();
+        int pos = 0;
+        while ( i.hasNext() )
+            result[pos++] = ((MbrEntry)((java.util.Map.Entry)i.next()).getValue());
+        return result;
+    }
+    
+    // --------------------------------------------- Inner Class
+
+    private class MemberComparator implements java.util.Comparator {
+
+        public int compare(Object o1, Object o2) {
+            try {
+                return compare((McastMember) o1, (McastMember) o2);
+            } catch (ClassCastException x) {
+                return 0;
+            }
+        }
+
+        public int compare(McastMember m1, McastMember m2) {
+            //longer alive time, means sort first
+            long result = m2.getMemberAliveTime() - m1.getMemberAliveTime();
+            if (result < 0)
+                return -1;
+            else if (result == 0)
+                return 0;
+            else
+                return 1;
+        }
+    }
+    
+    /**
+     * Inner class that represents a member entry
+     */
+    protected static class MbrEntry
+    {
+
+        protected McastMember mbr;
+        protected long lastHeardFrom;
+
+        public MbrEntry(McastMember mbr) {
+           this.mbr = mbr;
+        }
+
+        /**
+         * Indicate that this member has been accessed.
+         */
+        public void accessed(){
+           lastHeardFrom = System.currentTimeMillis();
+        }
+
+        /**
+         * Return the actual McastMember object
+         */
+        public McastMember getMember() {
+            return mbr;
+        }
+
+        /**
+         * Check if this dude has expired
+         * @param maxtime The time threshold
+         */
+        public boolean hasExpired(long maxtime) {
+            long delta = System.currentTimeMillis() - lastHeardFrom;
+            return delta > maxtime;
+        }
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/mcast/McastService.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/mcast/McastService.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/mcast/McastService.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,503 @@
+/*
+ * Copyright 1999,2004-2005 The Apache Software Foundation.
+ * 
+ * Licensed 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.cluster.mcast;
+
+import java.util.Properties;
+
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+
+import org.apache.catalina.Cluster;
+import org.apache.catalina.Container;
+import org.apache.catalina.cluster.Member;
+import org.apache.catalina.cluster.MembershipListener;
+import org.apache.catalina.cluster.MembershipService;
+import org.apache.catalina.cluster.tcp.SimpleTcpCluster;
+import org.apache.catalina.core.StandardHost;
+import org.apache.catalina.util.StringManager;
+import org.apache.commons.modeler.Registry;
+
+/**
+ * A <b>membership</b> implementation using simple multicast.
+ * This is the representation of a multicast membership service.
+ * This class is responsible for maintaining a list of active cluster nodes in the cluster.
+ * If a node fails to send out a heartbeat, the node will be dismissed.
+ *
+ * FIXME i18n messages
+ * 
+ * @author Peter Rossbach
+ * @author Filip Hanik
+ * @version $Revision: 380229 $, $Date: 2006-02-23 15:28:29 -0600 (Thu, 23 Feb 2006) $
+ */
+
+
+public class McastService implements MembershipService,MembershipListener {
+
+    private static org.apache.commons.logging.Log log =
+        org.apache.commons.logging.LogFactory.getLog( McastService.class );
+
+    /**
+     * The string manager for this package.
+     */
+    protected StringManager sm = StringManager.getManager(Constants.Package);
+
+    /**
+     * The descriptive information about this implementation.
+     */
+    private static final String info = "McastService/2.1";
+
+    /**
+     * The implementation specific properties
+     */
+    protected Properties properties = new Properties();
+    /**
+     * A handle to the actual low level implementation
+     */
+    protected McastServiceImpl impl;
+    /**
+     * A membership listener delegate (should be the cluster :)
+     */
+    protected MembershipListener listener;
+    /**
+     * The local member
+     */
+    protected McastMember localMember ;
+    private int mcastSoTimeout;
+    private int mcastTTL;
+
+    /**
+     * my cluster
+     */
+    private SimpleTcpCluster cluster;
+
+    /**
+     * Transmitter Mbean name
+     */
+    private ObjectName objectName;
+
+    private Registry registry;
+
+    /**
+     * Create a membership service.
+     */
+    public McastService() {
+        properties.setProperty("mcastClusterDomain", "catalina");
+    }
+
+    /**
+     * Return descriptive information about this implementation and the
+     * corresponding version number, in the format
+     * <code>&lt;description&gt;/&lt;version&gt;</code>.
+     */
+    public String getInfo() {
+        return (info);
+    }
+    
+    /**
+     * Transmitter ObjectName
+     * 
+     * @param name
+     */
+    public void setObjectName(ObjectName name) {
+        objectName = name;
+    }
+
+    public ObjectName getObjectName() {
+        return objectName;
+    }
+
+    /**
+     *
+     * @param properties
+     * <BR/>All are required<BR />
+     * 1. mcastPort - the port to listen to<BR>
+     * 2. mcastAddress - the mcast group address<BR>
+     * 3. mcastClusterDomain - the mcast cluster domain<BR>
+     * 4. bindAddress - the bind address if any - only one that can be null<BR>
+     * 5. memberDropTime - the time a member is gone before it is considered gone.<BR>
+     * 6. msgFrequency - the frequency of sending messages<BR>
+     * 7. tcpListenPort - the port this member listens to<BR>
+     * 8. tcpListenHost - the bind address of this member<BR>
+     * @exception java.lang.IllegalArgumentException if a property is missing.
+     */
+    public void setProperties(Properties properties) {
+        hasProperty(properties,"mcastPort");
+        hasProperty(properties,"mcastAddress");
+        hasProperty(properties,"mcastClusterDomain");
+        hasProperty(properties,"memberDropTime");
+        hasProperty(properties,"msgFrequency");
+        hasProperty(properties,"tcpListenPort");
+        hasProperty(properties,"tcpListenHost");
+        this.properties = properties;
+    }
+
+    /**
+     * Return the properties, see setProperties
+     */
+    public Properties getProperties() {
+        return properties;
+    }
+
+    /*
+     * configured in cluster
+     * 
+     * @see org.apache.catalina.cluster.ClusterSender#setCatalinaCluster(org.apache.catalina.cluster.tcp.SimpleTcpCluster)
+     */
+    public void setCatalinaCluster(SimpleTcpCluster cluster) {
+        this.cluster = cluster;
+
+    }
+
+    /**
+     * Return the cluster for this membership service
+     */
+    public Cluster getCatalinaCluster() {
+        return cluster ;
+    }
+
+    /**
+     * Return the local member name
+     */
+    public String getLocalMemberName() {
+        return localMember.toString() ;
+    }
+ 
+    /**
+     * Return the local member
+     */
+    public Member getLocalMember() {
+        localMember.setMemberAliveTime(System.currentTimeMillis()-impl.getServiceStartTime());
+        return localMember;
+    }
+    
+    /**
+     * Sets the local member properties for broadcasting
+     */
+    public void setLocalMemberProperties(String listenHost, int listenPort) {
+        properties.setProperty("tcpListenHost",listenHost);
+        properties.setProperty("tcpListenPort",String.valueOf(listenPort));
+    }
+    
+    public void setMcastAddr(String addr) {
+        properties.setProperty("mcastAddress", addr);
+    }
+
+    public String getMcastAddr() {
+        return properties.getProperty("mcastAddress");
+    }
+
+    public void setMcastBindAddress(String bindaddr) {
+        properties.setProperty("mcastBindAddress", bindaddr);
+    }
+
+    public String getMcastBindAddress() {
+        return properties.getProperty("mcastBindAddress");
+    }
+
+    public void setMcastClusterDomain(String clusterDomain) {
+        properties.setProperty("mcastClusterDomain", clusterDomain);
+    }
+
+    public String getMcastClusterDomain() {
+        return properties.getProperty("mcastClusterDomain");
+    }
+
+    public void setMcastPort(int port) {
+        properties.setProperty("mcastPort", String.valueOf(port));
+    }
+
+    public int getMcastPort() {
+        String p = properties.getProperty("mcastPort");
+        return new Integer(p).intValue();
+    }
+    
+    public void setMcastFrequency(long time) {
+        properties.setProperty("msgFrequency", String.valueOf(time));
+    }
+
+    public long getMcastFrequency() {
+        String p = properties.getProperty("msgFrequency");
+        return new Long(p).longValue();
+    }
+
+    public void setMcastDropTime(long time) {
+        properties.setProperty("memberDropTime", String.valueOf(time));
+    }
+
+    public long getMcastDropTime() {
+        String p = properties.getProperty("memberDropTime");
+        return new Long(p).longValue();
+    }
+
+    /**
+     * Check if a required property is available.
+     * @param properties The set of properties
+     * @param name The property to check for
+     */
+    protected void hasProperty(Properties properties, String name){
+        if ( properties.getProperty(name)==null) throw new IllegalArgumentException("Required property \""+name+"\" is missing.");
+    }
+
+    /**
+     * Start broadcasting and listening to membership pings
+     * @throws java.lang.Exception if a IO error occurs
+     */
+    public void start() throws java.lang.Exception {
+        start(1);
+        start(2);
+        registerMBean();
+    }
+    
+    public void start(int level) throws java.lang.Exception {
+        if ( impl != null ) {
+            impl.start(level);
+            return;
+        }
+        String host = getProperties().getProperty("tcpListenHost");
+        String domain = getProperties().getProperty("mcastClusterDomain");
+        int port = Integer.parseInt(getProperties().getProperty("tcpListenPort"));
+        String name = "tcp://"+host+":"+port;
+        if ( localMember == null ) {
+            localMember = new McastMember(name, domain, host, port, 100);
+        } else {
+            localMember.setName(name);
+            localMember.setDomain(domain);
+            localMember.setHost(host);
+            localMember.setPort(port);
+            localMember.setMemberAliveTime(100);
+        }
+        java.net.InetAddress bind = null;
+        if ( properties.getProperty("mcastBindAddress")!= null ) {
+            bind = java.net.InetAddress.getByName(properties.getProperty("mcastBindAddress"));
+        }
+        int ttl = -1;
+        int soTimeout = -1;
+        if ( properties.getProperty("mcastTTL") != null ) {
+            try {
+                ttl = Integer.parseInt(properties.getProperty("mcastTTL"));
+            } catch ( Exception x ) {
+                log.error("Unable to parse mcastTTL="+properties.getProperty("mcastTTL"),x);
+            }
+        }
+        if ( properties.getProperty("mcastSoTimeout") != null ) {
+            try {
+                soTimeout = Integer.parseInt(properties.getProperty("mcastSoTimeout"));
+            } catch ( Exception x ) {
+                log.error("Unable to parse mcastSoTimeout="+properties.getProperty("mcastSoTimeout"),x);
+            }
+        }
+
+        impl = new McastServiceImpl((McastMember)localMember,Long.parseLong(properties.getProperty("msgFrequency")),
+                                    Long.parseLong(properties.getProperty("memberDropTime")),
+                                    Integer.parseInt(properties.getProperty("mcastPort")),
+                                    bind,
+                                    java.net.InetAddress.getByName(properties.getProperty("mcastAddress")),
+                                    ttl,
+                                    soTimeout,
+                                    this);
+
+        impl.start(level);
+		long memberwait = (Long.parseLong(properties.getProperty("msgFrequency"))*4);
+        if(log.isInfoEnabled())
+            log.info("Sleeping for "+memberwait+" milliseconds to establish cluster membership");
+        Thread.sleep(memberwait);
+
+    }
+
+ 
+    /**
+     * Stop broadcasting and listening to membership pings
+     */
+    public void stop() {
+        try  {
+            if ( impl != null) impl.stop();
+        } catch ( Exception x)  {
+            log.error("Unable to stop the mcast service.",x);
+        }
+        impl = null;
+        unregisterMBean();
+    }
+
+    /**
+     * register mbean descriptor for package mcast 
+     * @throws Exception
+     */
+    protected void initMBeans() throws Exception {
+      if(registry == null) {
+        registry = Registry.getRegistry(null, null);
+        registry.loadMetadata(this.getClass().getResourceAsStream(
+            "mbeans-descriptors.xml"));
+      }
+    }
+    
+    /**
+     * register MBeans for Membership
+     *
+     */
+    protected void registerMBean() {
+        if (cluster != null) {
+            ObjectName clusterName = cluster.getObjectName();
+            try {
+                MBeanServer mserver = cluster.getMBeanServer();
+                initMBeans();
+                Container container = cluster.getContainer();
+                String name = clusterName.getDomain() + ":type=ClusterMembership";
+                if (container instanceof StandardHost) {
+                    name += ",host=" + clusterName.getKeyProperty("host");
+                }
+                ObjectName mcastName = new ObjectName(name);
+                if (mserver.isRegistered(mcastName)) {
+                    if (log.isWarnEnabled())
+                        log.warn(sm.getString(
+                                "cluster.mbean.register.already", mcastName));
+                    return;
+                }
+                setObjectName(mcastName);
+                mserver.registerMBean(cluster.getManagedBean(this),
+                        getObjectName());
+                if (log.isInfoEnabled())
+                    log.info("membership mbean registered (" + mcastName + ")");
+            } catch (Exception e) {
+                log.warn("membership mbean creation failed (" + clusterName + ")" ,e);
+            }
+        }
+    }
+
+    /**
+     * unregister MBeans for Membership
+     *
+     */
+    protected void unregisterMBean() {
+        if (cluster != null && getObjectName() != null) {
+            try {
+                MBeanServer mserver = cluster.getMBeanServer();
+                mserver.unregisterMBean(getObjectName());
+            } catch (Exception e) {
+                log.error(e);
+            }
+        }
+    }
+
+    /**
+     * Return all the members by name
+     */
+    public String[] getMembersByName() {
+        Member[] currentMembers = getMembers();
+        String [] membernames ;
+        if(currentMembers != null) {
+            membernames = new String[currentMembers.length];
+            for (int i = 0; i < currentMembers.length; i++) {
+                membernames[i] = currentMembers[i].toString() ;
+            }
+        } else
+            membernames = new String[0] ;
+        return membernames ;
+    }
+ 
+    /**
+     * Return the member by name
+     */
+    public Member findMemberByName(String name) {
+        Member[] currentMembers = getMembers();
+        for (int i = 0; i < currentMembers.length; i++) {
+            if (name.equals(currentMembers[i].toString()))
+                return currentMembers[i];
+        }
+        return null;
+    }
+
+    /**
+     * has members?
+     */
+    public boolean hasMembers() {
+       if ( impl == null || impl.membership == null ) return false;
+       return impl.membership.hasMembers();
+    }
+
+    /**
+     * Return all the members
+     */
+    public Member[] getMembers() {
+        if ( impl == null || impl.membership == null ) return null;
+        return impl.membership.getMembers();
+    }
+    /**
+     * Add a membership listener, this version only supports one listener per service,
+     * so calling this method twice will result in only the second listener being active.
+     * @param listener The listener
+     */
+    public void addMembershipListener(MembershipListener listener) {
+        this.listener = listener;
+    }
+    /**
+     * Remove the membership listener
+     */
+    public void removeMembershipListener(){
+        listener = null;
+    }
+
+    public void memberAdded(Member member) {
+        if ( listener!=null ) listener.memberAdded(member);
+    }
+
+    /**
+     * Callback from the impl when a new member has been received
+     * @param member The member
+     */
+    public void memberDisappeared(Member member)
+    {
+        if ( listener!=null ) listener.memberDisappeared(member);
+    }
+
+    public int getMcastSoTimeout() {
+        return mcastSoTimeout;
+    }
+    public void setMcastSoTimeout(int mcastSoTimeout) {
+        this.mcastSoTimeout = mcastSoTimeout;
+        properties.setProperty("mcastSoTimeout", String.valueOf(mcastSoTimeout));
+    }
+    public int getMcastTTL() {
+        return mcastTTL;
+    }
+    public void setMcastTTL(int mcastTTL) {
+        this.mcastTTL = mcastTTL;
+        properties.setProperty("mcastTTL", String.valueOf(mcastTTL));
+    }
+
+    /**
+     * Simple test program
+     * @param args Command-line arguments
+     * @throws Exception If an error occurs
+     */
+    public static void main(String args[]) throws Exception {
+		if(log.isInfoEnabled())
+            log.info("Usage McastService hostname tcpport");
+        McastService service = new McastService();
+        java.util.Properties p = new java.util.Properties();
+        p.setProperty("mcastPort","5555");
+        p.setProperty("mcastAddress","224.10.10.10");
+        p.setProperty("mcastClusterDomain","catalina");
+        p.setProperty("bindAddress","localhost");
+        p.setProperty("memberDropTime","3000");
+        p.setProperty("msgFrequency","500");
+        p.setProperty("tcpListenPort",args[1]);
+        p.setProperty("tcpListenHost",args[0]);
+        service.setProperties(p);
+        service.start();
+        Thread.sleep(60*1000*60);
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/mcast/McastServiceImpl.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/mcast/McastServiceImpl.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/mcast/McastServiceImpl.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,282 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.cluster.mcast;
+
+
+import java.net.MulticastSocket;
+import java.io.IOException;
+import java.net.InetAddress ;
+import java.net.DatagramPacket;
+import org.apache.catalina.cluster.MembershipListener;
+
+/**
+ * A <b>membership</b> implementation using simple multicast.
+ * This is the representation of a multicast membership service.
+ * This class is responsible for maintaining a list of active cluster nodes in the cluster.
+ * If a node fails to send out a heartbeat, the node will be dismissed.
+ * This is the low level implementation that handles the multicasting sockets.
+ * Need to fix this, could use java.nio and only need one thread to send and receive, or
+ * just use a timeout on the receive
+ * @author Filip Hanik
+ * @version $Revision: 356540 $, $Date: 2005-12-13 10:53:40 -0600 (Tue, 13 Dec 2005) $
+ */
+public class McastServiceImpl
+{
+    private static org.apache.commons.logging.Log log =
+        org.apache.commons.logging.LogFactory.getLog( McastService.class );
+    /**
+     * Internal flag used for the listen thread that listens to the multicasting socket.
+     */
+    protected boolean doRun = false;
+    /**
+     * Socket that we intend to listen to
+     */
+    protected MulticastSocket socket;
+    /**
+     * The local member that we intend to broad cast over and over again
+     */
+    protected McastMember member;
+    /**
+     * The multicast address
+     */
+    protected InetAddress address;
+    /**
+     * The multicast port
+     */
+    protected int port;
+    /**
+     * The time it takes for a member to expire.
+     */
+    protected long timeToExpiration;
+    /**
+     * How often to we send out a broadcast saying we are alive, must be smaller than timeToExpiration
+     */
+    protected long sendFrequency;
+    /**
+     * Reuse the sendPacket, no need to create a new one everytime
+     */
+    protected DatagramPacket sendPacket;
+    /**
+     * Reuse the receivePacket, no need to create a new one everytime
+     */
+    protected DatagramPacket receivePacket;
+    /**
+     * The membership, used so that we calculate memberships when they arrive or don't arrive
+     */
+    protected McastMembership membership;
+    /**
+     * The actual listener, for callback when shits goes down
+     */
+    protected MembershipListener service;
+    /**
+     * Thread to listen for pings
+     */
+    protected ReceiverThread receiver;
+    /**
+     * Thread to send pings
+     */
+    protected SenderThread sender;
+
+    /**
+     * When was the service started
+     */
+    protected long serviceStartTime = System.currentTimeMillis();
+    
+    protected int mcastTTL = -1;
+    protected int mcastSoTimeout = -1;
+    protected InetAddress mcastBindAddress = null;
+
+    /**
+     * Create a new mcast service impl
+     * @param member - the local member
+     * @param sendFrequency - the time (ms) in between pings sent out
+     * @param expireTime - the time (ms) for a member to expire
+     * @param port - the mcast port
+     * @param bind - the bind address (not sure this is used yet)
+     * @param mcastAddress - the mcast address
+     * @param service - the callback service
+     * @throws IOException
+     */
+    public McastServiceImpl(
+        McastMember member,
+        long sendFrequency,
+        long expireTime,
+        int port,
+        InetAddress bind,
+        InetAddress mcastAddress,
+        int ttl,
+        int soTimeout,
+        MembershipListener service)
+    throws IOException {
+        this.member = member;
+        address = mcastAddress;
+        this.port = port;
+        this.mcastSoTimeout = soTimeout;
+        this.mcastTTL = ttl;
+        this.mcastBindAddress = bind;
+        setupSocket();
+        sendPacket = new DatagramPacket(new byte[1000],1000);
+        sendPacket.setAddress(address);
+        sendPacket.setPort(port);
+        receivePacket = new DatagramPacket(new byte[1000],1000);
+        receivePacket.setAddress(address);
+        receivePacket.setPort(port);
+        membership = new McastMembership(member.getName());
+        timeToExpiration = expireTime;
+        this.service = service;
+        this.sendFrequency = sendFrequency;
+    }
+    
+    protected void setupSocket() throws IOException {
+        if (mcastBindAddress != null) socket = new MulticastSocket(new java.net.
+            InetSocketAddress(mcastBindAddress, port));
+        else socket = new MulticastSocket(port);
+        if (mcastBindAddress != null) {
+			if(log.isInfoEnabled())
+                log.info("Setting multihome multicast interface to:" +
+                         mcastBindAddress);
+            socket.setInterface(mcastBindAddress);
+        } //end if
+        if ( mcastSoTimeout >= 0 ) {
+ 			if(log.isInfoEnabled())
+                log.info("Setting cluster mcast soTimeout to "+mcastSoTimeout);
+            socket.setSoTimeout(mcastSoTimeout);
+        }
+        if ( mcastTTL >= 0 ) {
+			if(log.isInfoEnabled())
+                log.info("Setting cluster mcast TTL to " + mcastTTL);
+            socket.setTimeToLive(mcastTTL);
+        }
+    }
+
+    /**
+     * Start the service
+     * @param level 1 starts the receiver, level 2 starts the sender
+     * @throws IOException if the service fails to start
+     * @throws IllegalStateException if the service is already started
+     */
+    public synchronized void start(int level) throws IOException {
+        if ( sender != null && receiver != null ) throw new IllegalStateException("Service already running.");
+        if ( level == 1 ) {
+            socket.joinGroup(address);
+            doRun = true;
+            receiver = new ReceiverThread();
+            receiver.setDaemon(true);
+            receiver.start();
+        }
+        if ( level==2 ) {
+            serviceStartTime = System.currentTimeMillis();
+            sender = new SenderThread(sendFrequency);
+            sender.setDaemon(true);
+            sender.start();
+            
+        }
+    }
+
+    /**
+     * Stops the service
+     * @throws IOException if the service fails to disconnect from the sockets
+     */
+    public synchronized void stop() throws IOException {
+        socket.leaveGroup(address);
+        doRun = false;
+        sender = null;
+        receiver = null;
+        serviceStartTime = Long.MAX_VALUE;
+    }
+
+    /**
+     * Receive a datagram packet, locking wait
+     * @throws IOException
+     */
+    public void receive() throws IOException {
+        socket.receive(receivePacket);
+        byte[] data = new byte[receivePacket.getLength()];
+        System.arraycopy(receivePacket.getData(),receivePacket.getOffset(),data,0,data.length);
+        McastMember m = McastMember.getMember(data);
+        if(log.isDebugEnabled())
+            log.debug("Mcast receive ping from member " + m);
+        if ( membership.memberAlive(m) ) {
+            if(log.isDebugEnabled())
+                log.debug("Mcast add member " + m);
+            service.memberAdded(m);
+        }
+        McastMember[] expired = membership.expire(timeToExpiration);
+        for ( int i=0; i<expired.length; i++) {
+            if(log.isDebugEnabled())
+                log.debug("Mcast exipre  member " + m);
+            service.memberDisappeared(expired[i]);
+        }
+    }
+
+    /**
+     * Send a ping
+     * @throws Exception
+     */
+    public void send() throws Exception{
+        member.inc();
+        if(log.isDebugEnabled())
+            log.debug("Mcast send ping from member " + member);
+        byte[] data = member.getData(this.serviceStartTime);
+        DatagramPacket p = new DatagramPacket(data,data.length);
+        p.setAddress(address);
+        p.setPort(port);
+        socket.send(p);
+    }
+
+    public long getServiceStartTime() {
+       return this.serviceStartTime;
+    }
+
+
+    public class ReceiverThread extends Thread {
+        public ReceiverThread() {
+            super();
+            setName("Cluster-MembershipReceiver");
+        }
+        public void run() {
+            while ( doRun ) {
+                try {
+                    receive();
+                } catch ( Exception x ) {
+                    log.warn("Error receiving mcast package. Sleeping 500ms",x);
+                    try { Thread.sleep(500); } catch ( Exception ignore ){}
+                    
+                }
+            }
+        }
+    }//class ReceiverThread
+
+    public class SenderThread extends Thread {
+        long time;
+        public SenderThread(long time) {
+            this.time = time;
+            setName("Cluster-MembershipSender");
+
+        }
+        public void run() {
+            while ( doRun ) {
+                try {
+                    send();
+                } catch ( Exception x ) {
+                    log.warn("Unable to send mcast message.",x);
+                }
+                try { Thread.sleep(time); } catch ( Exception ignore ) {}
+            }
+        }
+    }//class SenderThread
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/mcast/mbeans-descriptors.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/mcast/mbeans-descriptors.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/mcast/mbeans-descriptors.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mbeans-descriptors PUBLIC
+   "-//Apache Software Foundation//DTD Model MBeans Configuration File"
+   "http://jakarta.apache.org/commons/dtds/mbeans-descriptors.dtd">
+<mbeans-descriptors>
+
+  <mbean         name="McastService"
+           description="Cluster Membership service implementation"
+               domain="Catalina"
+                group="Cluster"
+                 type="org.apache.catalina.cluster.mcast.McastService">
+    <attribute   name="info"
+          description="Class version info"
+                 type="java.lang.String"
+                 writeable="false"/>
+    <attribute   name="mcastAddr"
+          description="Multicast IP Address"
+                 type="java.lang.String"/>
+    <attribute   name="mcastBindAddress"
+          description="Multicast IP Interface address (default auto)"
+                 type="java.lang.String"/>
+    <attribute   name="mcastPort"
+          description="Multicast UDP Port"
+                 type="int"/>
+    <attribute   name="mcastFrequency"
+          description="Ping Frequency at msec"
+                 type="long"/>
+    <attribute   name="mcastClusterDomain"
+          description="Cluster Domain of this member"
+                 type="java.lang.String"/>
+    <attribute   name="mcastDropTime"
+          description="Timeout from frequency ping after member disapper notify"
+                 type="long"/>
+    <attribute   name="mcastSoTimeout"
+          description="Multicast Socket Timeout"
+                 type="int"/>
+    <attribute   name="mcastTTL"
+          description=""
+                 type="int"/>
+    <attribute   name="localMemberName"
+          description="Complete local receiver information"
+                 type="java.lang.String"
+                 writeable="false"/>
+    <attribute   name="membersByName"
+          description="Complete remote sender information"
+                 type="[Ljava.lang.String;"
+                 writeable="false"/>
+
+    <operation   name="start"
+               description="Start the cluster membership"
+               impact="ACTION"
+               returnType="void">
+    </operation>
+    
+    <operation name="stop"
+               description="Stop the cluster membership"
+               impact="ACTION"
+               returnType="void">
+    </operation>
+                 
+  </mbean>
+
+</mbeans-descriptors>

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/package.html
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/package.html	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/package.html	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,11 @@
+<body>
+
+<p>This package contains code for Clustering, the base class
+of a Cluster is <code>org.apache.catalina.Cluster</code> implementations
+of this class is done when implementing a new Cluster protocol</p>
+
+<p>The only Cluster protocol currently implemented is a JavaGroups based<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<b>JGCluster.java</b>
+</p>
+
+</body>

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/session/ClusterListener.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/session/ClusterListener.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/session/ClusterListener.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,101 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ *
+ * Licensed 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.cluster.session;
+
+import org.apache.catalina.cluster.CatalinaCluster;
+import org.apache.catalina.cluster.ClusterMessage;
+import org.apache.catalina.cluster.MessageListener;
+import org.apache.catalina.util.StringManager;
+
+/**
+ * Receive SessionID cluster change from other backup node after primary session
+ * node is failed.
+ * 
+ * @author Peter Rossbach
+ * @version $Revision: 380229 $ $Date: 2006-02-23 15:28:29 -0600 (Thu, 23 Feb 2006) $
+ */
+public abstract class ClusterListener implements MessageListener {
+
+    public static org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory
+            .getLog(ClusterListener.class);
+
+
+    //--Instance Variables--------------------------------------
+
+    /**
+     * The string manager for this package.
+     */
+    protected StringManager sm = StringManager.getManager(Constants.Package);
+
+    protected CatalinaCluster cluster = null;
+
+    //--Constructor---------------------------------------------
+
+    public ClusterListener() {
+    }
+    
+    //--Instance Getters/Setters--------------------------------
+    
+    public CatalinaCluster getCluster() {
+        return cluster;
+    }
+
+    public void setCluster(CatalinaCluster cluster) {
+        if (log.isDebugEnabled()) {
+            if (cluster != null)
+                log.debug("add ClusterListener " + this.toString()
+                        + " to cluster" + cluster);
+            else
+                log.debug("remove ClusterListener " + this.toString()
+                        + " from cluster");
+        }
+        this.cluster = cluster;
+    }
+
+    public boolean equals(Object listener) {
+        return super.equals(listener);
+    }
+
+    public int hashCode() {
+        return super.hashCode();
+    }
+
+    //--Logic---------------------------------------------------
+
+
+    /**
+     * Callback from the cluster, when a message is received, The cluster will
+     * broadcast it invoking the messageReceived on the receiver.
+     * 
+     * @param msg
+     *            ClusterMessage - the message received from the cluster
+     */
+    public abstract void messageReceived(ClusterMessage msg) ;
+    
+
+    /**
+     * Accept only SessionIDMessages
+     * 
+     * @param msg
+     *            ClusterMessage
+     * @return boolean - returns true to indicate that messageReceived should be
+     *         invoked. If false is returned, the messageReceived method will
+     *         not be invoked.
+     */
+    public abstract boolean accept(ClusterMessage msg) ;
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/session/ClusterSessionListener.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/session/ClusterSessionListener.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/session/ClusterSessionListener.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,105 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ *
+ * Licensed 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.cluster.session;
+
+import java.util.Map;
+
+import org.apache.catalina.cluster.ClusterManager;
+import org.apache.catalina.cluster.ClusterMessage;
+
+/**
+ * Receive replicated SessionMessage form other cluster node.
+ * 
+ * @author Peter Rossbach
+ * @version $Revision: 390627 $ $Date: 2006-04-01 03:24:34 -0600 (Sat, 01 Apr 2006) $
+ */
+public class ClusterSessionListener extends ClusterListener {
+ 
+    /**
+     * The descriptive information about this implementation.
+     */
+    protected static final String info = "org.apache.catalina.session.ClusterSessionListener/1.1";
+
+    //--Constructor---------------------------------------------
+
+    public ClusterSessionListener() {
+    }
+
+    //--Logic---------------------------------------------------
+
+    /**
+     * Return descriptive information about this implementation.
+     */
+    public String getInfo() {
+
+        return (info);
+
+    }
+
+    /**
+     * Callback from the cluster, when a message is received, The cluster will
+     * broadcast it invoking the messageReceived on the receiver.
+     * 
+     * @param myobj
+     *            ClusterMessage - the message received from the cluster
+     */
+    public void messageReceived(ClusterMessage myobj) {
+        if (myobj != null && myobj instanceof SessionMessage) {
+            SessionMessage msg = (SessionMessage) myobj;
+            String ctxname = msg.getContextName();
+            //check if the message is a EVT_GET_ALL_SESSIONS,
+            //if so, wait until we are fully started up
+            Map managers = cluster.getManagers() ;
+            if (ctxname == null) {
+                java.util.Iterator i = managers.keySet().iterator();
+                while (i.hasNext()) {
+                    String key = (String) i.next();
+                    ClusterManager mgr = (ClusterManager) managers.get(key);
+                    if (mgr != null)
+                        mgr.messageDataReceived(msg);
+                    else {
+                        //this happens a lot before the system has started
+                        // up
+                        if (log.isDebugEnabled())
+                            log.debug("Context manager doesn't exist:"
+                                    + key);
+                    }
+                }
+            } else {
+                ClusterManager mgr = (ClusterManager) managers.get(ctxname);
+                if (mgr != null)
+                    mgr.messageDataReceived(msg);
+                else if (log.isErrorEnabled())
+                    log.error("Context manager doesn't exist:" + ctxname);
+            }
+        }
+    }
+
+    /**
+     * Accept only SessionMessage
+     * 
+     * @param msg
+     *            ClusterMessage
+     * @return boolean - returns true to indicate that messageReceived should be
+     *         invoked. If false is returned, the messageReceived method will
+     *         not be invoked.
+     */
+    public boolean accept(ClusterMessage msg) {
+        return (msg instanceof SessionMessage);
+    }
+}
+

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/session/Constants.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/session/Constants.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/session/Constants.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,31 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.cluster.session;
+
+/**
+ * Manifest constants for the <code>org.apache.catalina.cluster.session</code>
+ * package.
+ *
+ * @author Peter Rossbach Pero
+ */
+
+public class Constants {
+
+    public static final String Package = "org.apache.catalina.cluster.session";
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/session/DeltaManager.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/session/DeltaManager.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/session/DeltaManager.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,1751 @@
+/*
+ * Copyright 1999,2004-2005 The Apache Software Foundation.
+ * 
+ * Licensed 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.cluster.session;
+
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.Iterator;
+
+import org.apache.catalina.Cluster;
+import org.apache.catalina.Container;
+import org.apache.catalina.Context;
+import org.apache.catalina.Engine;
+import org.apache.catalina.Host;
+import org.apache.catalina.Valve;
+import org.apache.catalina.Lifecycle;
+import org.apache.catalina.LifecycleException;
+import org.apache.catalina.LifecycleListener;
+import org.apache.catalina.Loader;
+import org.apache.catalina.Session;
+import org.apache.catalina.cluster.CatalinaCluster;
+import org.apache.catalina.cluster.ClusterManager;
+import org.apache.catalina.cluster.ClusterMessage;
+import org.apache.catalina.cluster.Member;
+import org.apache.catalina.session.ManagerBase;
+import org.apache.catalina.cluster.tcp.ReplicationValve;
+import org.apache.catalina.util.CustomObjectInputStream;
+import org.apache.catalina.util.LifecycleSupport;
+import org.apache.catalina.util.StringManager;
+import org.apache.catalina.core.StandardContext;
+
+/**
+ * The DeltaManager manages replicated sessions by only replicating the deltas
+ * in data. For applications written to handle this, the DeltaManager is the
+ * optimal way of replicating data.
+ * 
+ * This code is almost identical to StandardManager with a difference in how it
+ * persists sessions and some modifications to it.
+ * 
+ * <b>IMPLEMENTATION NOTE </b>: Correct behavior of session storing and
+ * reloading depends upon external calls to the <code>start()</code> and
+ * <code>stop()</code> methods of this class at the correct times.
+ * 
+ * @author Filip Hanik
+ * @author Craig R. McClanahan
+ * @author Jean-Francois Arcand
+ * @author Peter Rossbach
+ * @version $Revision: 408460 $ $Date: 2006-05-21 13:26:01 -0500 (Sun, 21 May 2006) $
+ */
+
+public class DeltaManager extends ManagerBase implements Lifecycle,
+        PropertyChangeListener, ClusterManager {
+
+    // ---------------------------------------------------- Security Classes
+
+    public static org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory
+            .getLog(DeltaManager.class);
+
+    /**
+     * The string manager for this package.
+     */
+    protected static StringManager sm = StringManager
+            .getManager(Constants.Package);
+
+    // ----------------------------------------------------- Instance Variables
+
+    /**
+     * The descriptive information about this implementation.
+     */
+    private static final String info = "DeltaManager/2.1";
+
+    /**
+     * Has this component been started yet?
+     */
+    private boolean started = false;
+
+    /**
+     * The descriptive name of this Manager implementation (for logging).
+     */
+    protected static String managerName = "DeltaManager";
+
+    protected String name = null;
+    
+    protected boolean defaultMode = false;
+
+    private CatalinaCluster cluster = null;
+
+    /**
+     * cached replication valve cluster container!
+     */
+    private ReplicationValve replicationValve = null ;
+    
+    /**
+     * The lifecycle event support for this component.
+     */
+    protected LifecycleSupport lifecycle = new LifecycleSupport(this);
+
+    /**
+     * The maximum number of active Sessions allowed, or -1 for no limit.
+     */
+    private int maxActiveSessions = -1;
+    
+    private boolean expireSessionsOnShutdown = false;
+
+    private boolean notifyListenersOnReplication = true;
+
+    private boolean notifySessionListenersOnReplication = true;
+
+    private boolean stateTransfered = false ;
+
+    private int stateTransferTimeout = 60;
+
+    private boolean sendAllSessions = true;
+
+    private boolean sendClusterDomainOnly = true ;
+    
+    private int sendAllSessionsSize = 1000 ;
+    
+    /**
+     * wait time between send session block (default 2 sec) 
+     */
+    private int sendAllSessionsWaitTime = 2 * 1000 ; 
+
+    private ArrayList receivedMessageQueue = new ArrayList() ;
+    
+    private boolean receiverQueue = false ;
+
+    private boolean stateTimestampDrop = true ;
+
+    private long stateTransferCreateSendTime; 
+    
+    // ------------------------------------------------------------------ stats attributes
+    
+    int rejectedSessions = 0;
+
+    private long sessionReplaceCounter = 0 ;
+
+    long processingTime = 0;
+
+    private long counterReceive_EVT_GET_ALL_SESSIONS = 0 ;
+
+    private long counterSend_EVT_ALL_SESSION_DATA = 0 ;
+
+    private long counterReceive_EVT_ALL_SESSION_DATA = 0 ;
+
+    private long counterReceive_EVT_SESSION_CREATED = 0 ;
+
+    private long counterReceive_EVT_SESSION_EXPIRED = 0;
+
+    private long counterReceive_EVT_SESSION_ACCESSED = 0 ;
+
+    private long counterReceive_EVT_SESSION_DELTA = 0;
+
+    private long counterSend_EVT_GET_ALL_SESSIONS = 0 ;
+
+    private long counterSend_EVT_SESSION_CREATED = 0;
+
+    private long counterSend_EVT_SESSION_DELTA = 0 ;
+
+    private long counterSend_EVT_SESSION_ACCESSED = 0;
+
+    private long counterSend_EVT_SESSION_EXPIRED = 0;
+
+    private int counterSend_EVT_ALL_SESSION_TRANSFERCOMPLETE = 0 ;
+
+    private int counterReceive_EVT_ALL_SESSION_TRANSFERCOMPLETE = 0 ;
+
+    private int counterNoStateTransfered = 0 ;
+
+
+    // ------------------------------------------------------------- Constructor
+  
+    public DeltaManager() {
+        super();
+    }
+
+    // ------------------------------------------------------------- Properties
+    
+    public static ClassLoader[] getClassLoaders(Container container) {
+        Loader loader = null;
+        ClassLoader classLoader = null;
+        if (container != null) loader = container.getLoader();
+        if (loader != null) classLoader = loader.getClassLoader();
+        else classLoader = Thread.currentThread().getContextClassLoader();
+        if ( classLoader == Thread.currentThread().getContextClassLoader() ) {
+            return new ClassLoader[] {classLoader};
+        } else {
+            return new ClassLoader[] {classLoader,Thread.currentThread().getContextClassLoader()};
+        }
+    }
+
+    
+    /**
+     * Return descriptive information about this Manager implementation and the
+     * corresponding version number, in the format
+     * <code>&lt;description&gt;/&lt;version&gt;</code>.
+     */
+    public String getInfo() {
+
+        return (info);
+
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    /**
+     * Return the descriptive short name of this Manager implementation.
+     */
+    public String getName() {
+
+        return (name);
+
+    }
+
+    /**
+     * @return Returns the counterSend_EVT_GET_ALL_SESSIONS.
+     */
+    public long getCounterSend_EVT_GET_ALL_SESSIONS() {
+        return counterSend_EVT_GET_ALL_SESSIONS;
+    }
+    
+    /**
+     * @return Returns the counterSend_EVT_SESSION_ACCESSED.
+     */
+    public long getCounterSend_EVT_SESSION_ACCESSED() {
+        return counterSend_EVT_SESSION_ACCESSED;
+    }
+    
+    /**
+     * @return Returns the counterSend_EVT_SESSION_CREATED.
+     */
+    public long getCounterSend_EVT_SESSION_CREATED() {
+        return counterSend_EVT_SESSION_CREATED;
+    }
+
+    /**
+     * @return Returns the counterSend_EVT_SESSION_DELTA.
+     */
+    public long getCounterSend_EVT_SESSION_DELTA() {
+        return counterSend_EVT_SESSION_DELTA;
+    }
+
+    /**
+     * @return Returns the counterSend_EVT_SESSION_EXPIRED.
+     */
+    public long getCounterSend_EVT_SESSION_EXPIRED() {
+        return counterSend_EVT_SESSION_EXPIRED;
+    }
+ 
+    /**
+     * @return Returns the counterSend_EVT_ALL_SESSION_DATA.
+     */
+    public long getCounterSend_EVT_ALL_SESSION_DATA() {
+        return counterSend_EVT_ALL_SESSION_DATA;
+    }
+
+    /**
+     * @return Returns the counterSend_EVT_ALL_SESSION_TRANSFERCOMPLETE.
+     */
+    public int getCounterSend_EVT_ALL_SESSION_TRANSFERCOMPLETE() {
+        return counterSend_EVT_ALL_SESSION_TRANSFERCOMPLETE;
+    }
+ 
+    /**
+     * @return Returns the counterReceive_EVT_ALL_SESSION_DATA.
+     */
+    public long getCounterReceive_EVT_ALL_SESSION_DATA() {
+        return counterReceive_EVT_ALL_SESSION_DATA;
+    }
+    
+    /**
+     * @return Returns the counterReceive_EVT_GET_ALL_SESSIONS.
+     */
+    public long getCounterReceive_EVT_GET_ALL_SESSIONS() {
+        return counterReceive_EVT_GET_ALL_SESSIONS;
+    }
+    
+    /**
+     * @return Returns the counterReceive_EVT_SESSION_ACCESSED.
+     */
+    public long getCounterReceive_EVT_SESSION_ACCESSED() {
+        return counterReceive_EVT_SESSION_ACCESSED;
+    }
+    
+    /**
+     * @return Returns the counterReceive_EVT_SESSION_CREATED.
+     */
+    public long getCounterReceive_EVT_SESSION_CREATED() {
+        return counterReceive_EVT_SESSION_CREATED;
+    }
+    
+    /**
+     * @return Returns the counterReceive_EVT_SESSION_DELTA.
+     */
+    public long getCounterReceive_EVT_SESSION_DELTA() {
+        return counterReceive_EVT_SESSION_DELTA;
+    }
+    
+    /**
+     * @return Returns the counterReceive_EVT_SESSION_EXPIRED.
+     */
+    public long getCounterReceive_EVT_SESSION_EXPIRED() {
+        return counterReceive_EVT_SESSION_EXPIRED;
+    }
+    
+    
+    /**
+     * @return Returns the counterReceive_EVT_ALL_SESSION_TRANSFERCOMPLETE.
+     */
+    public int getCounterReceive_EVT_ALL_SESSION_TRANSFERCOMPLETE() {
+        return counterReceive_EVT_ALL_SESSION_TRANSFERCOMPLETE;
+    }
+    
+    /**
+     * @return Returns the processingTime.
+     */
+    public long getProcessingTime() {
+        return processingTime;
+    }
+ 
+    /**
+     * @return Returns the sessionReplaceCounter.
+     */
+    public long getSessionReplaceCounter() {
+        return sessionReplaceCounter;
+    }
+    
+    /**
+     * Number of session creations that failed due to maxActiveSessions
+     * 
+     * @return The count
+     */
+    public int getRejectedSessions() {
+        return rejectedSessions;
+    }
+
+    public void setRejectedSessions(int rejectedSessions) {
+        this.rejectedSessions = rejectedSessions;
+    }
+
+    /**
+     * @return Returns the counterNoStateTransfered.
+     */
+    public int getCounterNoStateTransfered() {
+        return counterNoStateTransfered;
+    }
+    
+    public int getReceivedQueueSize() {
+        return receivedMessageQueue.size() ;
+    }
+    
+    /**
+     * @return Returns the stateTransferTimeout.
+     */
+    public int getStateTransferTimeout() {
+        return stateTransferTimeout;
+    }
+    /**
+     * @param timeoutAllSession The timeout
+     */
+    public void setStateTransferTimeout(int timeoutAllSession) {
+        this.stateTransferTimeout = timeoutAllSession;
+    }
+
+    /**
+     * is session state transfered complete?
+     * 
+     */
+    public boolean getStateTransfered() {
+        return stateTransfered;
+    }
+
+    /**
+     * set that state ist complete transfered  
+     * @param stateTransfered
+     */
+    public void setStateTransfered(boolean stateTransfered) {
+        this.stateTransfered = stateTransfered;
+    }
+    
+    /**
+     * @return Returns the sendAllSessionsWaitTime in msec
+     */
+    public int getSendAllSessionsWaitTime() {
+        return sendAllSessionsWaitTime;
+    }
+    
+    /**
+     * @param sendAllSessionsWaitTime The sendAllSessionsWaitTime to set at msec.
+     */
+    public void setSendAllSessionsWaitTime(int sendAllSessionsWaitTime) {
+        this.sendAllSessionsWaitTime = sendAllSessionsWaitTime;
+    }
+    
+    /**
+     * @return Returns the sendClusterDomainOnly.
+     */
+    public boolean isSendClusterDomainOnly() {
+        return sendClusterDomainOnly;
+    }
+    
+    /**
+     * @param sendClusterDomainOnly The sendClusterDomainOnly to set.
+     */
+    public void setSendClusterDomainOnly(boolean sendClusterDomainOnly) {
+        this.sendClusterDomainOnly = sendClusterDomainOnly;
+    }
+
+    /**
+     * @return Returns the stateTimestampDrop.
+     */
+    public boolean isStateTimestampDrop() {
+        return stateTimestampDrop;
+    }
+    
+    /**
+     * @param isTimestampDrop The new flag value
+     */
+    public void setStateTimestampDrop(boolean isTimestampDrop) {
+        this.stateTimestampDrop = isTimestampDrop;
+    }
+    
+    /**
+     * Return the maximum number of active Sessions allowed, or -1 for no limit.
+     */
+    public int getMaxActiveSessions() {
+
+        return (this.maxActiveSessions);
+
+    }
+
+    /**
+     * Set the maximum number of actives Sessions allowed, or -1 for no limit.
+     * 
+     * @param max
+     *            The new maximum number of sessions
+     */
+    public void setMaxActiveSessions(int max) {
+
+        int oldMaxActiveSessions = this.maxActiveSessions;
+        this.maxActiveSessions = max;
+        support.firePropertyChange("maxActiveSessions", new Integer(
+                oldMaxActiveSessions), new Integer(this.maxActiveSessions));
+
+    }
+    
+    /**
+     * 
+     * @return Returns the sendAllSessions.
+     */
+    public boolean isSendAllSessions() {
+        return sendAllSessions;
+    }
+    
+    /**
+     * @param sendAllSessions The sendAllSessions to set.
+     */
+    public void setSendAllSessions(boolean sendAllSessions) {
+        this.sendAllSessions = sendAllSessions;
+    }
+    
+    /**
+     * @return Returns the sendAllSessionsSize.
+     */
+    public int getSendAllSessionsSize() {
+        return sendAllSessionsSize;
+    }
+    
+    /**
+     * @param sendAllSessionsSize The sendAllSessionsSize to set.
+     */
+    public void setSendAllSessionsSize(int sendAllSessionsSize) {
+        this.sendAllSessionsSize = sendAllSessionsSize;
+    }
+    
+    /**
+     * @return Returns the notifySessionListenersOnReplication.
+     */
+    public boolean isNotifySessionListenersOnReplication() {
+        return notifySessionListenersOnReplication;
+    }
+    
+    /**
+     * @param notifyListenersCreateSessionOnReplication The notifySessionListenersOnReplication to set.
+     */
+    public void setNotifySessionListenersOnReplication(
+            boolean notifyListenersCreateSessionOnReplication) {
+        this.notifySessionListenersOnReplication = notifyListenersCreateSessionOnReplication;
+    }
+    
+    
+    public boolean isExpireSessionsOnShutdown() {
+        return expireSessionsOnShutdown;
+    }
+
+    public void setExpireSessionsOnShutdown(boolean expireSessionsOnShutdown) {
+        this.expireSessionsOnShutdown = expireSessionsOnShutdown;
+    }
+    
+    public boolean isNotifyListenersOnReplication() {
+        return notifyListenersOnReplication;
+    }
+
+    public void setNotifyListenersOnReplication(
+            boolean notifyListenersOnReplication) {
+        this.notifyListenersOnReplication = notifyListenersOnReplication;
+    }
+
+    
+    /**
+     * @return Returns the defaultMode.
+     */
+    public boolean isDefaultMode() {
+        return defaultMode;
+    }
+    /**
+     * @param defaultMode The defaultMode to set.
+     */
+    public void setDefaultMode(boolean defaultMode) {
+        this.defaultMode = defaultMode;
+    }
+    
+    public CatalinaCluster getCluster() {
+        return cluster;
+    }
+
+    public void setCluster(CatalinaCluster cluster) {
+        this.cluster = cluster;
+    }
+
+    /**
+     * Set the Container with which this Manager has been associated. If it is a
+     * Context (the usual case), listen for changes to the session timeout
+     * property.
+     * 
+     * @param container
+     *            The associated Container
+     */
+    public void setContainer(Container container) {
+
+        // De-register from the old Container (if any)
+        if ((this.container != null) && (this.container instanceof Context))
+            ((Context) this.container).removePropertyChangeListener(this);
+
+        // Default processing provided by our superclass
+        super.setContainer(container);
+
+        // Register with the new Container (if any)
+        if ((this.container != null) && (this.container instanceof Context)) {
+            setMaxInactiveInterval(((Context) this.container)
+                    .getSessionTimeout() * 60);
+            ((Context) this.container).addPropertyChangeListener(this);
+        }
+
+    }
+    
+    // --------------------------------------------------------- Public Methods
+
+    /**
+     * Construct and return a new session object, based on the default settings
+     * specified by this Manager's properties. The session id will be assigned
+     * by this method, and available via the getId() method of the returned
+     * session. If a new session cannot be created for any reason, return
+     * <code>null</code>.
+     * 
+     * @exception IllegalStateException
+     *                if a new session cannot be instantiated for any reason
+     * 
+     * Construct and return a new session object, based on the default settings
+     * specified by this Manager's properties. The session id will be assigned
+     * by this method, and available via the getId() method of the returned
+     * session. If a new session cannot be created for any reason, return
+     * <code>null</code>.
+     * 
+     * @exception IllegalStateException
+     *                if a new session cannot be instantiated for any reason
+     */
+    public Session createSession(String sessionId) {
+        return createSession(sessionId, true);
+    }
+
+    /**
+     * create new session with check maxActiveSessions and send session creation
+     * to other cluster nodes.
+     * 
+     * @param distribute
+     * @return The session
+     */
+    public Session createSession(String sessionId, boolean distribute) {
+
+        if ((maxActiveSessions >= 0) && (sessions.size() >= maxActiveSessions)) {
+            rejectedSessions++;
+            throw new IllegalStateException(sm
+                    .getString("deltaManager.createSession.ise"));
+        }
+
+        DeltaSession session = (DeltaSession) super.createSession(sessionId) ;
+        if (distribute) {
+            sendCreateSession(session.getId(), session);
+        }
+        if (log.isDebugEnabled())
+            log.debug(sm.getString("deltaManager.createSession.newSession",
+                    session.getId(), new Integer(sessions.size())));
+
+        return (session);
+
+    }
+
+    /**
+     * Send create session evt to all backup node
+     * @param sessionId
+     * @param session
+     */
+    protected void sendCreateSession(String sessionId, DeltaSession session) {
+        if(cluster.getMembers().length > 0 ) {
+            SessionMessage msg = new SessionMessageImpl(getName(),
+                    SessionMessage.EVT_SESSION_CREATED, null, sessionId,
+                    sessionId + "-" + System.currentTimeMillis());
+            msg.setTimestamp(session.getCreationTime());
+            if (log.isDebugEnabled())
+                log.debug(sm.getString("deltaManager.sendMessage.newSession",
+                        name, sessionId));
+            counterSend_EVT_SESSION_CREATED++;
+            send(msg);
+        }
+    }
+    
+    /**
+     * Send messages to other backup member (domain or all)
+     * @param msg Session message
+     */
+    protected void send(SessionMessage msg) {
+        if(cluster != null) {
+            if(isSendClusterDomainOnly())
+                cluster.sendClusterDomain(msg);
+            else
+                cluster.send(msg);
+        }
+    }
+
+    /**
+     * Create DeltaSession
+     * @see org.apache.catalina.Manager#createEmptySession()
+     */
+    public Session createEmptySession() {
+        return getNewDeltaSession() ;
+    }
+    
+    /**
+     * Get new session class to be used in the doLoad() method.
+     */
+    protected DeltaSession getNewDeltaSession() {
+        return new DeltaSession(this);
+    }
+
+    /**
+     * Load Deltarequest from external node
+     * Load the Class at container classloader
+     * @see DeltaRequest#readExternal(java.io.ObjectInput)
+     * @param session
+     * @param data message data
+     * @return The request
+     * @throws ClassNotFoundException
+     * @throws IOException
+     */
+    protected DeltaRequest loadDeltaRequest(DeltaSession session, byte[] data)
+            throws ClassNotFoundException, IOException {
+        ByteArrayInputStream fis = null;
+        ReplicationStream ois = null;
+        Loader loader = null;
+        fis = new ByteArrayInputStream(data);
+        ois = new ReplicationStream(fis, getClassLoaders(this.container)[0]);
+        session.getDeltaRequest().readExternal(ois);
+        ois.close();
+        return session.getDeltaRequest();
+    }
+
+    /**
+     * serialize DeltaRequest
+     * @see DeltaRequest#writeExternal(java.io.ObjectOutput)
+     * 
+     * @param deltaRequest
+     * @return serialized delta request
+     * @throws IOException
+     */
+    protected byte[] unloadDeltaRequest(DeltaRequest deltaRequest)
+            throws IOException {
+        ByteArrayOutputStream bos = new ByteArrayOutputStream();
+        ObjectOutputStream oos = new ObjectOutputStream(bos);
+        deltaRequest.writeExternal(oos);
+        oos.flush();
+        oos.close();
+        return bos.toByteArray();
+    }
+
+    /**
+     * Load sessions from other cluster node.
+     * FIXME replace currently sessions with same id without notifcation.
+     * FIXME SSO handling is not really correct with the session replacement!
+     * @exception ClassNotFoundException
+     *                if a serialized class cannot be found during the reload
+     * @exception IOException
+     *                if an input/output error occurs
+     */
+    protected void deserializeSessions(byte[] data) throws ClassNotFoundException,
+            IOException {
+
+        // Initialize our internal data structures
+        //sessions.clear(); //should not do this
+        // Open an input stream to the specified pathname, if any
+        ClassLoader originalLoader = Thread.currentThread()
+                .getContextClassLoader();
+        ObjectInputStream ois = null;
+        // Load the previously unloaded active sessions
+        try {
+            ois = openDeserializeObjectStream(data);
+            Integer count = (Integer) ois.readObject();
+            int n = count.intValue();
+            for (int i = 0; i < n; i++) {
+                DeltaSession session = (DeltaSession) createEmptySession();
+                session.readObjectData(ois);
+                session.setManager(this);
+                session.setValid(true);
+                session.setPrimarySession(false);
+                //in case the nodes in the cluster are out of
+                //time synch, this will make sure that we have the
+                //correct timestamp, isValid returns true, cause
+                // accessCount=1
+                session.access();
+                //make sure that the session gets ready to expire if
+                // needed
+                session.setAccessCount(0);
+                session.resetDeltaRequest();
+                // FIXME How inform other session id cache like SingleSignOn
+                // increment sessionCounter to correct stats report
+                if (findSession(session.getIdInternal()) == null ) {
+                    sessionCounter++;
+                } else {
+                    sessionReplaceCounter++;
+                    // FIXME better is to grap this sessions again !
+                    if (log.isWarnEnabled())
+                        log.warn(sm.getString(
+                                "deltaManager.loading.existing.session",
+                                session.getIdInternal()));
+                }
+                add(session);
+            }
+        } catch (ClassNotFoundException e) {
+            log.error(sm.getString("deltaManager.loading.cnfe", e), e);
+            throw e;
+        } catch (IOException e) {
+            log.error(sm.getString("deltaManager.loading.ioe", e), e);
+            throw e;
+        } finally {
+            // Close the input stream
+            try {
+                if (ois != null)
+                    ois.close();
+            } catch (IOException f) {
+                // ignored
+            }
+            ois = null;
+            if (originalLoader != null)
+                Thread.currentThread().setContextClassLoader(originalLoader);
+        }
+
+    }
+
+    /**
+     * Open Stream and use correct ClassLoader (Container) Switch
+     * ThreadClassLoader
+     * 
+     * @param data
+     * @return The object input stream
+     * @throws IOException
+     */
+    protected ObjectInputStream openDeserializeObjectStream(byte[] data) throws IOException {
+        ObjectInputStream ois = null;
+        ByteArrayInputStream fis = null;
+        try {
+            Loader loader = null;
+            ClassLoader classLoader = null;
+            fis = new ByteArrayInputStream(data);
+            BufferedInputStream bis = new BufferedInputStream(fis);
+            if (container != null)
+                loader = container.getLoader();
+            if (loader != null)
+                classLoader = loader.getClassLoader();
+            if (classLoader != null) {
+                if (log.isTraceEnabled())
+                    log.trace(sm.getString(
+                            "deltaManager.loading.withContextClassLoader",
+                            getName()));
+                ois = new CustomObjectInputStream(bis, classLoader);
+                Thread.currentThread().setContextClassLoader(classLoader);
+            } else {
+                if (log.isTraceEnabled())
+                    log.trace(sm.getString(
+                            "deltaManager.loading.withoutClassLoader",
+                            getName()));
+                ois = new ObjectInputStream(bis);
+            }
+        } catch (IOException e) {
+            log.error(sm.getString("deltaManager.loading.ioe", e), e);
+            if (ois != null) {
+                try {
+                    ois.close();
+                } catch (IOException f) {
+                    ;
+                }
+                ois = null;
+            }
+            throw e;
+        }
+        return ois;
+    }
+
+    /**
+     * Save any currently active sessions in the appropriate persistence
+     * mechanism, if any. If persistence is not supported, this method returns
+     * without doing anything.
+     * 
+     * @exception IOException
+     *                if an input/output error occurs
+     */
+    protected byte[] serializeSessions(Session[] currentSessions) throws IOException {
+
+        // Open an output stream to the specified pathname, if any
+        ByteArrayOutputStream fos = null;
+        ObjectOutputStream oos = null;
+
+        try {
+            fos = new ByteArrayOutputStream();
+            oos = new ObjectOutputStream(new BufferedOutputStream(fos));
+            oos.writeObject(new Integer(currentSessions.length));
+            for(int i=0 ; i < currentSessions.length;i++) {
+                ((DeltaSession)currentSessions[i]).writeObjectData(oos);                
+            }
+            // Flush and close the output stream
+            oos.flush();
+        } catch (IOException e) {
+            log.error(sm.getString("deltaManager.unloading.ioe", e), e);
+            throw e;
+        } finally {
+            if (oos != null) {
+                try {
+                    oos.close();
+                } catch (IOException f) {
+                    ;
+                }
+                oos = null;
+            }
+        }
+        // send object data as byte[]
+        return fos.toByteArray();
+    }
+
+    // ------------------------------------------------------ Lifecycle Methods
+
+    /**
+     * Add a lifecycle event listener to this component.
+     * 
+     * @param listener
+     *            The listener to add
+     */
+    public void addLifecycleListener(LifecycleListener listener) {
+
+        lifecycle.addLifecycleListener(listener);
+
+    }
+
+    /**
+     * Get the lifecycle listeners associated with this lifecycle. If this
+     * Lifecycle has no listeners registered, a zero-length array is returned.
+     */
+    public LifecycleListener[] findLifecycleListeners() {
+
+        return lifecycle.findLifecycleListeners();
+
+    }
+
+    /**
+     * Remove a lifecycle event listener from this component.
+     * 
+     * @param listener
+     *            The listener to remove
+     */
+    public void removeLifecycleListener(LifecycleListener listener) {
+
+        lifecycle.removeLifecycleListener(listener);
+
+    }
+
+    /**
+     * Prepare for the beginning of active use of the public methods of this
+     * component. This method should be called after <code>configure()</code>,
+     * and before any of the public methods of the component are utilized.
+     * 
+     * @exception LifecycleException
+     *                if this component detects a fatal error that prevents this
+     *                component from being used
+     */
+    public void start() throws LifecycleException {
+        if (!initialized)
+            init();
+
+        // Validate and update our current component state
+        if (started) {
+            return;
+        }
+        started = true;
+        lifecycle.fireLifecycleEvent(START_EVENT, null);
+
+        // Force initialization of the random number generator
+        generateSessionId();
+
+        // Load unloaded sessions, if any
+        try {
+            //the channel is already running
+            Cluster cluster = getCluster() ;
+            // stop remove cluster binding
+            if(cluster == null) {
+                Container context = getContainer() ;
+                if(context != null && context instanceof Context) {
+                     Container host = context.getParent() ;
+                     if(host != null && host instanceof Host) {
+                         cluster = host.getCluster();
+                         if(cluster != null && cluster instanceof CatalinaCluster) {
+                             setCluster((CatalinaCluster) cluster) ;
+                         } else {
+                             Container engine = host.getParent() ;
+                             if(engine != null && engine instanceof Engine) {
+                                 cluster = engine.getCluster();
+                                 if(cluster != null && cluster instanceof CatalinaCluster) {
+                                         setCluster((CatalinaCluster) cluster) ;
+                                 }
+                             } else {
+                                     cluster = null ;
+                             }
+                         }
+                     }
+                }
+            }
+            if (cluster == null) {
+                log.error(sm.getString("deltaManager.noCluster", getName()));
+                return;
+            } else {
+                if (log.isInfoEnabled()) {
+                    String type = "unknown" ;
+                    if( cluster.getContainer() instanceof Host){
+                        type = "Host" ;
+                    } else if( cluster.getContainer() instanceof Engine){
+                        type = "Engine" ;
+                    }
+                    log.info(sm
+                            .getString("deltaManager.registerCluster", getName(), type, cluster.getClusterName()));
+                }
+            }
+            if (log.isInfoEnabled())
+                log.info(sm
+                        .getString("deltaManager.startClustering", getName()));
+            //to survice context reloads, as only a stop/start is called, not
+            // createManager
+            ((CatalinaCluster)cluster).addManager(getName(), this);
+
+            getAllClusterSessions();
+
+        } catch (Throwable t) {
+            log.error(sm.getString("deltaManager.managerLoad"), t);
+        }
+    }
+
+    /**
+     * get from first session master the backup from all clustered sessions
+     * @see #findSessionMasterMember()
+     */
+    public synchronized void getAllClusterSessions() {
+        if (cluster != null && cluster.getMembers().length > 0) {
+            long beforeSendTime = System.currentTimeMillis();
+            Member mbr = findSessionMasterMember();
+            if(mbr == null) { // No domain member found
+                 return;
+            }
+            SessionMessage msg = new SessionMessageImpl(this.getName(),
+                    SessionMessage.EVT_GET_ALL_SESSIONS, null, "GET-ALL",
+                    "GET-ALL-" + getName());
+            msg.setResend(ClusterMessage.FLAG_FORBIDDEN);
+            // set reference time
+            msg.setTimestamp(beforeSendTime);
+            stateTransferCreateSendTime = beforeSendTime ;
+            // request session state
+            counterSend_EVT_GET_ALL_SESSIONS++;
+            stateTransfered = false ;
+            // FIXME This send call block the deploy thread, when sender waitForAck is enabled
+            try {
+                synchronized(receivedMessageQueue) {
+                     receiverQueue = true ;
+                }
+                cluster.send(msg, mbr);
+                if (log.isWarnEnabled())
+                    log.warn(sm.getString("deltaManager.waitForSessionState",
+                            getName(), mbr));
+                // FIXME At sender ack mode this method check only the state transfer and resend is a problem!
+                waitForSendAllSessions(beforeSendTime);
+            } finally {
+                synchronized(receivedMessageQueue) {
+                    for (Iterator iter = receivedMessageQueue.iterator(); iter
+                            .hasNext();) {
+                        SessionMessage smsg = (SessionMessage) iter.next();
+                        if (!stateTimestampDrop) {
+                            messageReceived(smsg,
+                                    smsg.getAddress() != null ? (Member) smsg
+                                            .getAddress() : null);
+                        } else {
+                            if (smsg.getEventType() != SessionMessage.EVT_GET_ALL_SESSIONS
+                                    && smsg.getTimestamp() >= stateTransferCreateSendTime) {
+                                // FIXME handle EVT_GET_ALL_SESSIONS later
+                                messageReceived(
+                                        smsg,
+                                        smsg.getAddress() != null ? (Member) smsg
+                                                .getAddress()
+                                                : null);
+                            } else {
+                                if (log.isWarnEnabled()) {
+                                    log.warn(sm.getString(
+                                            "deltaManager.dropMessage",
+                                            getName(), smsg
+                                                    .getEventTypeString(),
+                                            new Date(stateTransferCreateSendTime), new Date(
+                                                    smsg.getTimestamp())));
+                                }
+                            }
+                        }
+                    }        
+                    receivedMessageQueue.clear();
+                    receiverQueue = false ;
+                }
+           }
+        } else {
+            if (log.isInfoEnabled())
+                log.info(sm.getString("deltaManager.noMembers", getName()));
+        }
+    }
+
+    /**
+     * Register cross context session at replication valve thread local
+     * @param session cross context session
+     */
+    protected void registerSessionAtReplicationValve(DeltaSession session) {
+	    	if(replicationValve == null) {
+	    		if(container instanceof StandardContext
+	    				&& ((StandardContext)container).getCrossContext()) {
+	    			Cluster cluster = getCluster() ;
+	    			if(cluster != null && cluster instanceof CatalinaCluster) {
+	    				Valve[] valves = ((CatalinaCluster)cluster).getValves();
+	    				if(valves != null && valves.length > 0) {
+	    					for(int i=0; replicationValve == null && i < valves.length ; i++ ){
+	    						if(valves[i] instanceof ReplicationValve)
+	    							replicationValve = (ReplicationValve)valves[i] ;
+	    					}
+	    					
+	    					if(replicationValve == null && log.isDebugEnabled()) {
+	    						log.debug("no ReplicationValve found for CrossContext Support");
+	    					}
+	    				}
+	    			}
+	    		}
+	    	}
+	    	if(replicationValve != null) {
+	    		replicationValve.registerReplicationSession(session);
+	    	}
+    	}
+    
+    /**
+     * Find the master of the session state
+     * @return master member of sessions 
+     */
+    protected Member findSessionMasterMember() {
+        Member mbr = null;
+        Member mbrs[] = cluster.getMembers();
+        String localMemberDomain = cluster.getMembershipService().getLocalMember().getDomain();
+        if(isSendClusterDomainOnly()) {
+            for (int i = 0; mbr == null && i < mbrs.length; i++) {
+                Member member = mbrs[i];
+                if(localMemberDomain.equals(member.getDomain()))
+                    mbr = member ;
+            }
+        } else {
+            if(mbrs.length != 0 )
+                mbr = mbrs[0];
+        }
+        if(mbr == null && log.isWarnEnabled())
+           log.warn(sm.getString("deltaManager.noMasterMember",
+                    getName(), localMemberDomain));
+        if(mbr != null && log.isDebugEnabled())
+            log.warn(sm.getString("deltaManager.foundMasterMember",
+                     getName(), mbr));
+        return mbr;
+    }
+
+    /**
+     * Wait that cluster session state is transfer or timeout after 60 Sec
+     * With stateTransferTimeout == -1 wait that backup is transfered (forever mode)
+     */
+    protected void waitForSendAllSessions(long beforeSendTime) {
+        long reqStart = System.currentTimeMillis();
+        long reqNow = reqStart ;
+        boolean isTimeout = false;
+        if(getStateTransferTimeout() > 0) {
+            // wait that state is transfered with timeout check
+            do {
+                try {
+                    Thread.sleep(100);
+                } catch (Exception sleep) {
+                }
+                reqNow = System.currentTimeMillis();
+                isTimeout = ((reqNow - reqStart) > (1000 * getStateTransferTimeout()));
+            } while ((!getStateTransfered()) && (!isTimeout));
+        } else {
+            if(getStateTransferTimeout() == -1) {
+                // wait that state is transfered
+                do {
+                    try {
+                        Thread.sleep(100);
+                    } catch (Exception sleep) {
+                    }
+                } while ((!getStateTransfered()));
+                reqNow = System.currentTimeMillis();
+            }
+        }
+        if (isTimeout || (!getStateTransfered())) {
+            counterNoStateTransfered++ ;
+            log.error(sm.getString("deltaManager.noSessionState",
+                    getName(),new Date(beforeSendTime),new Long(reqNow - beforeSendTime)));
+        } else {
+            if (log.isInfoEnabled())
+                log.info(sm.getString("deltaManager.sessionReceived",
+                        getName(), new Date(beforeSendTime), new Long(reqNow - beforeSendTime)));
+        }
+    }
+
+    /**
+     * Gracefully terminate the active use of the public methods of this
+     * component. This method should be the last one called on a given instance
+     * of this component.
+     * 
+     * @exception LifecycleException
+     *                if this component detects a fatal error that needs to be
+     *                reported
+     */
+    public void stop() throws LifecycleException {
+
+        if (log.isDebugEnabled())
+            log.debug(sm.getString("deltaManager.stopped", getName()));
+
+
+        // Validate and update our current component state
+        if (!started)
+            throw new LifecycleException(sm
+                    .getString("deltaManager.notStarted"));
+        lifecycle.fireLifecycleEvent(STOP_EVENT, null);
+        started = false;
+
+        // Expire all active sessions
+        if (log.isInfoEnabled())
+            log.info(sm.getString("deltaManager.expireSessions", getName()));
+        Session sessions[] = findSessions();
+        for (int i = 0; i < sessions.length; i++) {
+            DeltaSession session = (DeltaSession) sessions[i];
+            if (!session.isValid())
+                continue;
+            try {
+                session.expire(true, isExpireSessionsOnShutdown());
+            } catch (Throwable ignore) {
+                ;
+            } 
+        }
+
+        // Require a new random number generator if we are restarted
+        this.random = null;
+        getCluster().removeManager(getName(),this);
+        replicationValve = null;
+        if (initialized) {
+            destroy();
+        }
+    }
+
+    // ----------------------------------------- PropertyChangeListener Methods
+
+    /**
+     * Process property change events from our associated Context.
+     * 
+     * @param event
+     *            The property change event that has occurred
+     */
+    public void propertyChange(PropertyChangeEvent event) {
+
+        // Validate the source of this event
+        if (!(event.getSource() instanceof Context))
+            return;
+        // Process a relevant property change
+        if (event.getPropertyName().equals("sessionTimeout")) {
+            try {
+                setMaxInactiveInterval(((Integer) event.getNewValue())
+                        .intValue() * 60);
+            } catch (NumberFormatException e) {
+                log.error(sm.getString("deltaManager.sessionTimeout", event
+                        .getNewValue()));
+            }
+        }
+
+    }
+
+    // -------------------------------------------------------- Replication
+    // Methods
+
+    /**
+     * A message was received from another node, this is the callback method to
+     * implement if you are interested in receiving replication messages.
+     * 
+     * @param cmsg -
+     *            the message received.
+     */
+    public void messageDataReceived(ClusterMessage cmsg) {
+        if (cmsg != null && cmsg instanceof SessionMessage) {
+            SessionMessage msg = (SessionMessage) cmsg;
+            switch (msg.getEventType()) {
+            case SessionMessage.EVT_GET_ALL_SESSIONS:
+            case SessionMessage.EVT_SESSION_CREATED: 
+            case SessionMessage.EVT_SESSION_EXPIRED: 
+            case SessionMessage.EVT_SESSION_ACCESSED:
+            case SessionMessage.EVT_SESSION_DELTA: {
+                synchronized(receivedMessageQueue) {
+                    if(receiverQueue) {
+                        receivedMessageQueue.add(msg);
+                        return ;
+                    }
+                }
+               break;
+            }
+            default: {
+                //we didn't queue, do nothing
+                break;
+            }
+            } //switch
+            
+            messageReceived(msg, msg.getAddress() != null ? (Member) msg
+                    .getAddress() : null);
+        }
+    }
+
+    /**
+     * When the request has been completed, the replication valve will notify
+     * the manager, and the manager will decide whether any replication is
+     * needed or not. If there is a need for replication, the manager will
+     * create a session message and that will be replicated. The cluster
+     * determines where it gets sent.
+     * 
+     * @param sessionId -
+     *            the sessionId that just completed.
+     * @return a SessionMessage to be sent,
+     */
+    public ClusterMessage requestCompleted(String sessionId) {
+        try {
+            DeltaSession session = (DeltaSession) findSession(sessionId);
+            DeltaRequest deltaRequest = session.getDeltaRequest();
+            SessionMessage msg = null;
+            boolean isDeltaRequest = false ;
+            synchronized(deltaRequest) {
+                isDeltaRequest = deltaRequest.getSize() > 0 ;
+                if (isDeltaRequest) {    
+                    counterSend_EVT_SESSION_DELTA++;
+                    byte[] data = unloadDeltaRequest(deltaRequest);
+                    msg = new SessionMessageImpl(getName(),
+                            SessionMessage.EVT_SESSION_DELTA, data, sessionId,
+                            sessionId + "-" + System.currentTimeMillis());
+                    session.resetDeltaRequest();
+                }  
+            }
+            if(!isDeltaRequest) {
+                if(!session.isPrimarySession()) {               
+                    counterSend_EVT_SESSION_ACCESSED++;
+                    msg = new SessionMessageImpl(getName(),
+                            SessionMessage.EVT_SESSION_ACCESSED, null, sessionId,
+                            sessionId + "-" + System.currentTimeMillis());
+                    if (log.isDebugEnabled()) {
+                        log.debug(sm.getString(
+                                "deltaManager.createMessage.accessChangePrimary",
+                                getName(), sessionId));
+                    }
+                }    
+            } else { // log only outside synch block!
+                if (log.isDebugEnabled()) {
+                    log.debug(sm.getString(
+                        "deltaManager.createMessage.delta",
+                        getName(), sessionId));
+                }
+            }
+            session.setPrimarySession(true);
+            //check to see if we need to send out an access message
+            if ((msg == null)) {
+                long replDelta = System.currentTimeMillis()
+                        - session.getLastTimeReplicated();
+                if (replDelta > (getMaxInactiveInterval() * 1000)) {
+                    counterSend_EVT_SESSION_ACCESSED++;
+                    msg = new SessionMessageImpl(getName(),
+                            SessionMessage.EVT_SESSION_ACCESSED, null,
+                            sessionId, sessionId + "-" + System.currentTimeMillis());
+                    if (log.isDebugEnabled()) {
+                        log.debug(sm.getString(
+                                "deltaManager.createMessage.access", getName(),
+                                sessionId));
+                    }
+                }
+
+            }
+
+            //update last replicated time
+            if (msg != null)
+                session.setLastTimeReplicated(System.currentTimeMillis());
+            return msg;
+        } catch (IOException x) {
+            log.error(sm.getString(
+                    "deltaManager.createMessage.unableCreateDeltaRequest",
+                    sessionId), x);
+            return null;
+        }
+
+    }
+    /**
+     * Reset manager statistics
+     */
+    public synchronized void resetStatistics() {
+        processingTime = 0 ;
+        expiredSessions = 0 ;
+        rejectedSessions = 0 ;
+        sessionReplaceCounter = 0 ;
+        counterNoStateTransfered = 0 ;
+        maxActive = getActiveSessions() ;
+        sessionCounter = getActiveSessions() ;
+        counterReceive_EVT_ALL_SESSION_DATA = 0;
+        counterReceive_EVT_GET_ALL_SESSIONS = 0;
+        counterReceive_EVT_SESSION_ACCESSED = 0 ;
+        counterReceive_EVT_SESSION_CREATED = 0 ;
+        counterReceive_EVT_SESSION_DELTA = 0 ;
+        counterReceive_EVT_SESSION_EXPIRED = 0 ;
+        counterReceive_EVT_ALL_SESSION_TRANSFERCOMPLETE = 0;
+        counterSend_EVT_ALL_SESSION_DATA = 0;
+        counterSend_EVT_GET_ALL_SESSIONS = 0;
+        counterSend_EVT_SESSION_ACCESSED = 0 ;
+        counterSend_EVT_SESSION_CREATED = 0 ;
+        counterSend_EVT_SESSION_DELTA = 0 ;
+        counterSend_EVT_SESSION_EXPIRED = 0 ;
+        counterSend_EVT_ALL_SESSION_TRANSFERCOMPLETE = 0;
+        
+    }
+   
+    //  -------------------------------------------------------- persistence handler
+
+    public void load() {
+
+    }
+
+    public void unload() {
+
+    }
+
+    //  -------------------------------------------------------- expire
+
+    /**
+     * send session expired to other cluster nodes
+     * 
+     * @param id
+     *            session id
+     */
+    protected void sessionExpired(String id) {
+        counterSend_EVT_SESSION_EXPIRED++ ;
+        SessionMessage msg = new SessionMessageImpl(getName(),
+                SessionMessage.EVT_SESSION_EXPIRED, null, id, id
+                        + "-EXPIRED-MSG");
+        if (log.isDebugEnabled())
+            log.debug(sm.getString("deltaManager.createMessage.expire",
+                    getName(), id));
+        send(msg);
+    }
+
+    /**
+     * Exipre all find sessions.
+     */
+    public void expireAllLocalSessions()
+    {
+        long timeNow = System.currentTimeMillis();
+        Session sessions[] = findSessions();
+        int expireDirect  = 0 ;
+        int expireIndirect = 0 ;
+        
+        if(log.isDebugEnabled())
+            log.debug("Start expire all sessions " + getName() + " at " + timeNow + " sessioncount " + sessions.length);
+        for (int i = 0; i < sessions.length; i++) {
+            if (sessions[i] instanceof DeltaSession) {
+                DeltaSession session = (DeltaSession) sessions[i];
+                if (session.isPrimarySession()) {
+                    if (session.isValid()) {
+                        session.expire();
+                        expireDirect++;
+                    } else {
+                        expireIndirect++;
+                    }
+                }
+            }
+        }
+        long timeEnd = System.currentTimeMillis();
+        if(log.isDebugEnabled())
+             log.debug("End expire sessions " + getName() + " exipre processingTime " + (timeEnd - timeNow) + " expired direct sessions: " + expireDirect + " expired direct sessions: " + expireIndirect);
+      
+    }
+    
+    /**
+     * When the manager expires session not tied to a request. The cluster will
+     * periodically ask for a list of sessions that should expire and that
+     * should be sent across the wire.
+     * 
+     * @return The invalidated sessions array
+     */
+    public String[] getInvalidatedSessions() {
+        return new String[0];
+    }
+
+    //  -------------------------------------------------------- message receive
+
+    /**
+     * Test that sender and local domain is the same
+     */
+    protected boolean checkSenderDomain(SessionMessage msg,Member sender) {
+        String localMemberDomain = cluster.getMembershipService().getLocalMember().getDomain();
+        boolean sameDomain= localMemberDomain.equals(sender.getDomain());
+        if (!sameDomain && log.isWarnEnabled()) {
+                log.warn(sm.getString("deltaManager.receiveMessage.fromWrongDomain",
+                        new Object[] {getName(), 
+                        msg.getEventTypeString(), 
+                        sender,
+                        sender.getDomain(),
+                        localMemberDomain }
+                ));
+        }
+        return sameDomain ;
+    }
+
+    /**
+     * This method is called by the received thread when a SessionMessage has
+     * been received from one of the other nodes in the cluster.
+     * 
+     * @param msg -
+     *            the message received
+     * @param sender -
+     *            the sender of the message, this is used if we receive a
+     *            EVT_GET_ALL_SESSION message, so that we only reply to the
+     *            requesting node
+     */
+    protected void messageReceived(SessionMessage msg, Member sender) {
+        if(isSendClusterDomainOnly() && !checkSenderDomain(msg,sender)) {
+            return;
+        }
+        ClassLoader contextLoader = Thread.currentThread().getContextClassLoader();
+        try {
+            ClassLoader[] loaders = getClassLoaders(container);
+            if ( loaders != null && loaders.length > 0 ) Thread.currentThread().setContextClassLoader(loaders[0]);
+            if (log.isDebugEnabled())
+                log.debug(sm.getString("deltaManager.receiveMessage.eventType",
+                        getName(), msg.getEventTypeString(), sender));
+ 
+            switch (msg.getEventType()) {
+            case SessionMessage.EVT_GET_ALL_SESSIONS: {
+                handleGET_ALL_SESSIONS(msg,sender);
+                break;
+            }
+            case SessionMessage.EVT_ALL_SESSION_DATA: {
+                handleALL_SESSION_DATA(msg,sender);
+                break;
+            }
+            case SessionMessage.EVT_ALL_SESSION_TRANSFERCOMPLETE: {
+                handleALL_SESSION_TRANSFERCOMPLETE(msg,sender);
+                break;
+            }
+            case SessionMessage.EVT_SESSION_CREATED: {
+                handleSESSION_CREATED(msg,sender);
+                break;
+            }
+            case SessionMessage.EVT_SESSION_EXPIRED: {
+                handleSESSION_EXPIRED(msg,sender);
+                break;
+            }
+            case SessionMessage.EVT_SESSION_ACCESSED: {
+                handleSESSION_ACCESSED(msg,sender);
+                break;
+            }
+            case SessionMessage.EVT_SESSION_DELTA: {
+               handleSESSION_DELTA(msg,sender);
+               break;
+            }
+            default: {
+                //we didn't recognize the message type, do nothing
+                break;
+            }
+            } //switch
+        } catch (Exception x) {
+            log.error(sm.getString("deltaManager.receiveMessage.error",
+                    getName()), x);
+        } finally {
+            Thread.currentThread().setContextClassLoader(contextLoader);
+        }
+    }
+
+    // -------------------------------------------------------- message receiver handler
+
+
+    /**
+     * handle receive session state is complete transfered
+     * @param msg
+     * @param sender
+     */
+    protected void handleALL_SESSION_TRANSFERCOMPLETE(SessionMessage msg, Member sender) {
+        counterReceive_EVT_ALL_SESSION_TRANSFERCOMPLETE++ ;
+        if (log.isDebugEnabled())
+            log.debug(sm.getString(
+                    "deltaManager.receiveMessage.transfercomplete",
+                    getName(), sender.getHost(), new Integer(sender.getPort())));
+        stateTransferCreateSendTime = msg.getTimestamp() ;
+        stateTransfered = true ;
+    }
+
+    /**
+     * handle receive session delta
+     * @param msg
+     * @param sender
+     * @throws IOException
+     * @throws ClassNotFoundException
+     */
+    protected void handleSESSION_DELTA(SessionMessage msg, Member sender)
+            throws IOException, ClassNotFoundException {
+        counterReceive_EVT_SESSION_DELTA++;
+        byte[] delta = msg.getSession();
+        DeltaSession session = (DeltaSession) findSession(msg.getSessionID());
+        if (session != null) {
+            if (log.isDebugEnabled())
+                log.debug(sm.getString("deltaManager.receiveMessage.delta",
+                    getName(), msg.getSessionID()));
+            DeltaRequest dreq = loadDeltaRequest(session, delta);
+            dreq.execute(session, notifyListenersOnReplication);
+            session.setPrimarySession(false);
+        }
+    }
+
+    /**
+     * handle receive session is access at other node ( primary session is now false)
+     * @param msg
+     * @param sender
+     * @throws IOException
+     */
+    protected void handleSESSION_ACCESSED(SessionMessage msg,Member sender) throws IOException {
+        counterReceive_EVT_SESSION_ACCESSED++;
+        DeltaSession session = (DeltaSession) findSession(msg
+                .getSessionID());
+        if (session != null) {
+            if (log.isDebugEnabled())
+                log.debug(sm.getString(
+                        "deltaManager.receiveMessage.accessed",
+                        getName(), msg.getSessionID()));
+            session.access();
+            session.setPrimarySession(false);
+            session.endAccess();
+        }
+    }
+
+    /**
+     * handle receive session is expire at other node ( expire session also here)
+     * @param msg
+     * @param sender
+     * @throws IOException
+     */
+    protected void handleSESSION_EXPIRED(SessionMessage msg,Member sender) throws IOException {
+        counterReceive_EVT_SESSION_EXPIRED++;
+        DeltaSession session = (DeltaSession) findSession(msg
+                .getSessionID());
+        if (session != null) {
+            if (log.isDebugEnabled())
+                log.debug(sm.getString(
+                        "deltaManager.receiveMessage.expired",
+                        getName(), msg.getSessionID()));
+            session.expire(notifySessionListenersOnReplication, false);
+        }
+    }
+
+    /**
+     * handle receive new session is created at other node (create backup - primary false)
+     * @param msg
+     * @param sender
+     */
+    protected void handleSESSION_CREATED(SessionMessage msg,Member sender) {
+        counterReceive_EVT_SESSION_CREATED++;
+        if (log.isDebugEnabled())
+            log.debug(sm.getString(
+                    "deltaManager.receiveMessage.createNewSession",
+                    getName(), msg.getSessionID()));
+        DeltaSession session = (DeltaSession) createEmptySession();
+        session.setManager(this);
+        session.setValid(true);
+        session.setPrimarySession(false);
+        session.setCreationTime(msg.getTimestamp());
+        session.access();
+        if(notifySessionListenersOnReplication)
+            session.setId(msg.getSessionID());
+        else
+            session.setIdInternal(msg.getSessionID());
+        session.resetDeltaRequest();
+        session.endAccess();
+
+    }
+
+    /**
+     * handle receive sessions from other not ( restart )
+     * @param msg
+     * @param sender
+     * @throws ClassNotFoundException
+     * @throws IOException
+     */
+    protected void handleALL_SESSION_DATA(SessionMessage msg,Member sender) throws ClassNotFoundException, IOException {
+        counterReceive_EVT_ALL_SESSION_DATA++;
+        if (log.isDebugEnabled())
+            log.debug(sm.getString(
+                    "deltaManager.receiveMessage.allSessionDataBegin",
+                    getName()));
+        byte[] data = msg.getSession();
+        deserializeSessions(data);
+        if (log.isDebugEnabled())
+            log.debug(sm.getString(
+                    "deltaManager.receiveMessage.allSessionDataAfter",
+                    getName()));
+        //stateTransferred = true;
+    }
+
+    /**
+     * handle receive that other node want all sessions ( restart )
+     * a) send all sessions with one message
+     * b) send session at blocks
+     * After sending send state is complete transfered
+     * @param msg
+     * @param sender
+     * @throws IOException
+     */
+    protected void handleGET_ALL_SESSIONS(SessionMessage msg, Member sender)
+            throws IOException {
+        counterReceive_EVT_GET_ALL_SESSIONS++;
+        //get a list of all the session from this manager
+        if (log.isDebugEnabled())
+            log.debug(sm.getString(
+                    "deltaManager.receiveMessage.unloadingBegin", getName()));
+        // Write the number of active sessions, followed by the details
+        // get all sessions and serialize without sync
+        Session[] currentSessions = findSessions();
+        long findSessionTimestamp = System.currentTimeMillis() ;
+        if (isSendAllSessions()) {
+            sendSessions(sender, currentSessions, findSessionTimestamp);
+        } else {
+            // send session at blocks
+            int len = currentSessions.length < getSendAllSessionsSize() ? currentSessions.length
+                    : getSendAllSessionsSize();
+            Session[] sendSessions = new Session[len];
+            for (int i = 0; i < currentSessions.length; i += getSendAllSessionsSize()) {
+                len = i + getSendAllSessionsSize() > currentSessions.length ? currentSessions.length
+                        - i 
+                        : getSendAllSessionsSize();
+                System.arraycopy(currentSessions, i, sendSessions, 0, len);
+                sendSessions(sender, sendSessions,findSessionTimestamp);
+                if (getSendAllSessionsWaitTime() > 0) {
+                    try {
+                        Thread.sleep(getSendAllSessionsWaitTime());
+                    } catch (Exception sleep) {
+                    }
+                }
+            }
+        }
+        
+        SessionMessage newmsg = new SessionMessageImpl(name,
+                SessionMessage.EVT_ALL_SESSION_TRANSFERCOMPLETE, null,
+                "SESSION-STATE-TRANSFERED", "SESSION-STATE-TRANSFERED"
+                        + getName());
+        newmsg.setTimestamp(findSessionTimestamp);
+        if (log.isDebugEnabled())
+            log.debug(sm.getString(
+                    "deltaManager.createMessage.allSessionTransfered",
+                    getName()));
+        counterSend_EVT_ALL_SESSION_TRANSFERCOMPLETE++;
+        cluster.send(newmsg, sender);
+    }
+
+
+    /**
+     * send a block of session to sender
+     * @param sender
+     * @param currentSessions
+     * @param sendTimestamp
+     * @throws IOException
+     */
+    protected void sendSessions(Member sender, Session[] currentSessions,
+            long sendTimestamp) throws IOException {
+        byte[] data = serializeSessions(currentSessions);
+        if (log.isDebugEnabled())
+            log.debug(sm.getString(
+                    "deltaManager.receiveMessage.unloadingAfter",
+                    getName()));
+        SessionMessage newmsg = new SessionMessageImpl(name,
+                SessionMessage.EVT_ALL_SESSION_DATA, data,
+                "SESSION-STATE", "SESSION-STATE-" + getName());
+        newmsg.setTimestamp(sendTimestamp);
+        //if(isSendSESSIONSTATEcompressed()) {
+        //    newmsg.setCompress(ClusterMessage.FLAG_ALLOWED);
+        //}
+        if (log.isDebugEnabled())
+            log.debug(sm.getString(
+                    "deltaManager.createMessage.allSessionData",
+                    getName()));
+        counterSend_EVT_ALL_SESSION_DATA++;
+        cluster.send(newmsg, sender);
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/session/DeltaRequest.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/session/DeltaRequest.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/session/DeltaRequest.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,359 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.cluster.session;
+
+/**
+ * This class is used to track the series of actions that happens when
+ * a request is executed. These actions will then translate into invokations of methods 
+ * on the actual session.
+ * This class is NOT thread safe. One DeltaRequest per session
+ * @author <a href="mailto:fhanik at apache.org">Filip Hanik</a>
+ * @version 1.0
+ */
+
+import java.io.Externalizable;
+import java.security.Principal;
+import java.util.LinkedList;
+
+import org.apache.catalina.realm.GenericPrincipal;
+import org.apache.catalina.util.StringManager;
+
+
+public class DeltaRequest implements Externalizable {
+
+    public static org.apache.commons.logging.Log log =
+        org.apache.commons.logging.LogFactory.getLog( DeltaRequest.class );
+
+    /**
+     * The string manager for this package.
+     */
+    protected static StringManager sm = StringManager
+            .getManager(Constants.Package);
+
+    public static final int TYPE_ATTRIBUTE = 0;
+    public static final int TYPE_PRINCIPAL = 1;
+    public static final int TYPE_ISNEW = 2;
+    public static final int TYPE_MAXINTERVAL = 3;
+
+    public static final int ACTION_SET = 0;
+    public static final int ACTION_REMOVE = 1;
+
+    public static final String NAME_PRINCIPAL = "__SET__PRINCIPAL__";
+    public static final String NAME_MAXINTERVAL = "__SET__MAXINTERVAL__";
+    public static final String NAME_ISNEW = "__SET__ISNEW__";
+
+    private String sessionId;
+    private LinkedList actions = new LinkedList();
+    private LinkedList actionPool = new LinkedList();
+    
+    private boolean recordAllActions = false;
+
+    public DeltaRequest() {
+        
+    }
+    
+    public DeltaRequest(String sessionId, boolean recordAllActions) {
+        this.recordAllActions=recordAllActions;
+        if(sessionId != null)
+            setSessionId(sessionId);
+    }
+
+
+    public void setAttribute(String name, Object value) {
+        int action = (value==null)?ACTION_REMOVE:ACTION_SET;
+        addAction(TYPE_ATTRIBUTE,action,name,value);
+    }
+
+    public void removeAttribute(String name) {
+        int action = ACTION_REMOVE;
+        addAction(TYPE_ATTRIBUTE,action,name,null);
+    }
+
+    public void setMaxInactiveInterval(int interval) {
+        int action = ACTION_SET;
+        addAction(TYPE_MAXINTERVAL,action,NAME_MAXINTERVAL,new Integer(interval));
+    }
+    
+    /**
+     * convert principal at SerializablePrincipal for backup nodes.
+     * Only support principals from type {@link GenericPrincipal GenericPrincipal}
+     * @param p Session principal
+     * @see GenericPrincipal
+     */
+    public void setPrincipal(Principal p) {
+        int action = (p==null)?ACTION_REMOVE:ACTION_SET;
+        SerializablePrincipal sp = null;
+        if ( p != null ) {
+            if(p instanceof GenericPrincipal) {
+                sp = SerializablePrincipal.createPrincipal((GenericPrincipal)p);
+                if(log.isDebugEnabled())
+                    log.debug(sm.getString("deltaRequest.showPrincipal", p.getName() , getSessionId()));
+            } else
+                log.error(sm.getString("deltaRequest.wrongPrincipalClass",p.getClass().getName()));
+        }
+        addAction(TYPE_PRINCIPAL,action,NAME_PRINCIPAL,sp);
+    }
+
+    public void setNew(boolean n) {
+        int action = ACTION_SET;
+        addAction(TYPE_ISNEW,action,NAME_ISNEW,new Boolean(n));
+    }
+
+    protected synchronized void addAction(int type,
+                             int action,
+                             String name,
+                             Object value) {
+        AttributeInfo info = null;
+        if ( this.actionPool.size() > 0 ) {
+            try {
+                info = (AttributeInfo) actionPool.removeFirst();
+            }catch ( Exception x ) {
+                log.error("Unable to remove element:",x);
+                info = new AttributeInfo(type, action, name, value);
+            }
+            info.init(type,action,name,value);
+        } else {
+            info = new AttributeInfo(type, action, name, value);
+        }
+        //if we have already done something to this attribute, make sure
+        //we don't send multiple actions across the wire
+        if ( !recordAllActions) {
+            try {
+                actions.remove(info);
+            } catch (java.util.NoSuchElementException x) {
+                //do nothing, we wanted to remove it anyway
+            }
+        }
+        //add the action
+        actions.addLast(info);
+    }
+    
+    public void execute(DeltaSession session) {
+        execute(session,true);
+    }
+
+    public synchronized void execute(DeltaSession session, boolean notifyListeners) {
+        if ( !this.sessionId.equals( session.getId() ) )
+            throw new java.lang.IllegalArgumentException("Session id mismatch, not executing the delta request");
+        session.access();
+        for ( int i=0; i<actions.size(); i++ ) {
+            AttributeInfo info = (AttributeInfo)actions.get(i);
+            switch ( info.getType() ) {
+                case TYPE_ATTRIBUTE: {
+                    if ( info.getAction() == ACTION_SET ) {
+                        session.setAttribute(info.getName(), info.getValue(),notifyListeners,false);
+                    }  else
+                        session.removeAttribute(info.getName(),notifyListeners,false);
+                    break;
+                }//case
+                case TYPE_ISNEW: {
+                    session.setNew(((Boolean)info.getValue()).booleanValue(),false);
+                    break;
+                }//case
+                case TYPE_MAXINTERVAL: {
+                    session.setMaxInactiveInterval(((Integer)info.getValue()).intValue(),false);
+                    break;
+                }//case
+                case TYPE_PRINCIPAL: {
+                    Principal p = null;
+                    if ( info.getAction() == ACTION_SET ) {
+                        SerializablePrincipal sp = (SerializablePrincipal)info.getValue();
+                        p = (Principal)sp.getPrincipal(session.getManager().getContainer().getRealm());
+                    }
+                    session.setPrincipal(p,false);
+                    break;
+                }//case
+                default : throw new java.lang.IllegalArgumentException("Invalid attribute info type="+info);
+            }//switch
+        }//for
+        session.endAccess();
+        reset();
+    }
+
+    public synchronized void reset() {
+        while ( actions.size() > 0 ) {
+            try {
+                AttributeInfo info = (AttributeInfo) actions.removeFirst();
+                info.recycle();
+                actionPool.addLast(info);
+            }catch  ( Exception x ) {
+                log.error("Unable to remove element",x);
+            }
+        }
+        actions.clear();
+    }
+    
+    public String getSessionId() {
+        return sessionId;
+    }
+    public void setSessionId(String sessionId) {
+        this.sessionId = sessionId;
+        if ( sessionId == null ) {
+            new Exception("Session Id is null for setSessionId").fillInStackTrace().printStackTrace();
+        }
+    }
+    public int getSize() {
+        return actions.size();
+    }
+    
+    public synchronized void clear() {
+        actions.clear();
+        actionPool.clear();
+    }
+    
+    public synchronized void readExternal(java.io.ObjectInput in) throws java.io.IOException,
+        java.lang.ClassNotFoundException {
+        //sessionId - String
+        //recordAll - boolean
+        //size - int
+        //AttributeInfo - in an array
+        reset();
+        sessionId = in.readUTF();
+        recordAllActions = in.readBoolean();
+        int cnt = in.readInt();
+        if (actions == null)
+            actions = new LinkedList();
+        else
+            actions.clear();
+        for (int i = 0; i < cnt; i++) {
+            AttributeInfo info = null;
+            if (this.actionPool.size() > 0) {
+                try {
+                    info = (AttributeInfo) actionPool.removeFirst();
+                } catch ( Exception x )  {
+                    log.error("Unable to remove element",x);
+                    info = new AttributeInfo(-1,-1,null,null);
+                }
+            }
+            else {
+                info = new AttributeInfo(-1,-1,null,null);
+            }
+            info.readExternal(in);
+            actions.addLast(info);
+        }//for
+    }
+        
+
+
+    public synchronized void writeExternal(java.io.ObjectOutput out ) throws java.io.IOException {
+        //sessionId - String
+        //recordAll - boolean
+        //size - int
+        //AttributeInfo - in an array
+        out.writeUTF(getSessionId());
+        out.writeBoolean(recordAllActions);
+        out.writeInt(getSize());
+        for ( int i=0; i<getSize(); i++ ) {
+            AttributeInfo info = (AttributeInfo)actions.get(i);
+            info.writeExternal(out);
+        }
+    }
+    
+    private static class AttributeInfo implements java.io.Externalizable {
+        private String name = null;
+        private Object value = null;
+        private int action;
+        private int type;
+
+        public AttributeInfo() {}
+
+        public AttributeInfo(int type,
+                             int action,
+                             String name,
+                             Object value) {
+            super();
+            init(type,action,name,value);
+        }
+
+        public void init(int type,
+                         int action,
+                         String name,
+                         Object value) {
+            this.name = name;
+            this.value = value;
+            this.action = action;
+            this.type = type;
+        }
+
+        public int getType() {
+            return type;
+        }
+
+        public int getAction() {
+            return action;
+        }
+
+        public Object getValue() {
+            return value;
+        }
+        public int hashCode() {
+            return name.hashCode();
+        }
+
+        public String getName() {
+            return name;
+        }
+        
+        public void recycle() {
+            name = null;
+            value = null;
+            type=-1;
+            action=-1;
+        }
+
+        public boolean equals(Object o) {
+            if ( ! (o instanceof AttributeInfo ) ) return false;
+            AttributeInfo other =  (AttributeInfo)o;
+            return other.getName().equals(this.getName());
+        }
+        
+        public synchronized void readExternal(java.io.ObjectInput in ) throws java.io.IOException,
+            java.lang.ClassNotFoundException {
+            //type - int
+            //action - int
+            //name - String
+            //value - object
+            type = in.readInt();
+            action = in.readInt();
+            name = in.readUTF();
+            value = in.readObject();
+        }
+
+        public synchronized void writeExternal(java.io.ObjectOutput out) throws java.io.
+            IOException {
+            //type - int
+            //action - int
+            //name - String
+            //value - object
+            out.writeInt(getType());
+            out.writeInt(getAction());
+            out.writeUTF(getName());
+            out.writeObject(getValue());
+        }
+        
+        public String toString() {
+            StringBuffer buf = new StringBuffer("AttributeInfo[type=");
+            buf.append(getType()).append(", action=").append(getAction());
+            buf.append(", name=").append(getName()).append(", value=").append(getValue());
+            buf.append(", addr=").append(super.toString()).append("]");
+            return buf.toString();
+        }
+
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/session/DeltaSession.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/session/DeltaSession.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/session/DeltaSession.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,1701 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.cluster.session;
+
+import java.beans.PropertyChangeSupport;
+import java.io.IOException;
+import java.io.NotSerializableException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+import java.lang.reflect.Method;
+import java.security.AccessController;
+import java.security.Principal;
+import java.security.PrivilegedAction;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.Map;
+
+import javax.servlet.ServletContext;
+import javax.servlet.http.HttpSession;
+import javax.servlet.http.HttpSessionAttributeListener;
+import javax.servlet.http.HttpSessionBindingEvent;
+import javax.servlet.http.HttpSessionBindingListener;
+import javax.servlet.http.HttpSessionContext;
+import javax.servlet.http.HttpSessionEvent;
+import javax.servlet.http.HttpSessionListener;
+
+import org.apache.catalina.Context;
+import org.apache.catalina.Manager;
+import org.apache.catalina.Session;
+import org.apache.catalina.SessionEvent;
+import org.apache.catalina.SessionListener;
+import org.apache.catalina.cluster.ClusterSession;
+import org.apache.catalina.realm.GenericPrincipal;
+import org.apache.catalina.util.Enumerator;
+import org.apache.catalina.util.StringManager;
+
+/**
+ * 
+ * Similar to the StandardSession, this code is identical, but for update and
+ * some small issues, simply copied in the first release. This session will keep
+ * track of deltas during a request.
+ * <p>
+ * <b>IMPLEMENTATION NOTE </b>: An instance of this class represents both the
+ * internal (Session) and application level (HttpSession) view of the session.
+ * However, because the class itself is not declared public, Java logic outside
+ * of the <code>org.apache.catalina.session</code> package cannot cast an
+ * HttpSession view of this instance back to a Session view.
+ * <p>
+ * <b>IMPLEMENTATION NOTE </b>: If you add fields to this class, you must make
+ * sure that you carry them over in the read/writeObject methods so that this
+ * class is properly serialized.
+ * 
+ * @author Filip Hanik
+ * @author Craig R. McClanahan
+ * @author Sean Legassick
+ * @author <a href="mailto:jon at latchkey.com">Jon S. Stevens </a>
+ * @version $Revision: 399358 $ $Date: 2006-05-03 12:16:15 -0500 (Wed, 03 May 2006) $
+ */
+
+public class DeltaSession implements HttpSession, Session, Serializable,
+        ClusterSession {
+
+    public static org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory
+            .getLog(DeltaManager.class);
+
+    /**
+     * The string manager for this package.
+     */
+    protected static StringManager smp = StringManager
+            .getManager(Constants.Package);
+
+
+    // ----------------------------------------------------- Instance Variables
+
+    /**
+     * Type array.
+     */
+    protected static final String EMPTY_ARRAY[] = new String[0];
+
+    /**
+     * The dummy attribute value serialized when a NotSerializableException is
+     * encountered in <code>writeObject()</code>.
+     */
+    private static final String NOT_SERIALIZED = "___NOT_SERIALIZABLE_EXCEPTION___";
+
+    /**
+     * The collection of user data attributes associated with this Session.
+     */
+    private Map attributes = new Hashtable();
+
+    /**
+     * The authentication type used to authenticate our cached Principal, if
+     * any. NOTE: This value is not included in the serialized version of this
+     * object.
+     */
+    private transient String authType = null;
+
+    /**
+     * The <code>java.lang.Method</code> for the
+     * <code>fireContainerEvent()</code> method of the
+     * <code>org.apache.catalina.core.StandardContext</code> method, if our
+     * Context implementation is of this class. This value is computed
+     * dynamically the first time it is needed, or after a session reload (since
+     * it is declared transient).
+     */
+    private transient Method containerEventMethod = null;
+
+    /**
+     * The method signature for the <code>fireContainerEvent</code> method.
+     */
+    private static final Class containerEventTypes[] = { String.class,
+            Object.class };
+
+    /**
+     * The time this session was created, in milliseconds since midnight,
+     * January 1, 1970 GMT.
+     */
+    private long creationTime = 0L;
+
+    /**
+     * We are currently processing a session expiration, so bypass certain
+     * IllegalStateException tests. NOTE: This value is not included in the
+     * serialized version of this object.
+     */
+    private transient boolean expiring = false;
+
+    /**
+     * The facade associated with this session. NOTE: This value is not included
+     * in the serialized version of this object.
+     */
+    private transient DeltaSessionFacade facade = null;
+
+    /**
+     * The session identifier of this Session.
+     */
+    private String id = null;
+
+    /**
+     * Descriptive information describing this Session implementation.
+     */
+    private static final String info = "DeltaSession/1.1";
+
+    /**
+     * The last accessed time for this Session.
+     */
+    private long lastAccessedTime = creationTime;
+
+    /**
+     * The session event listeners for this Session.
+     */
+    private transient ArrayList listeners = new ArrayList();
+
+    /**
+     * The Manager with which this Session is associated.
+     */
+    private transient Manager manager = null;
+
+    /**
+     * The maximum time interval, in seconds, between client requests before the
+     * servlet container may invalidate this session. A negative time indicates
+     * that the session should never time out.
+     */
+    private int maxInactiveInterval = -1;
+
+    /**
+     * Flag indicating whether this session is new or not.
+     */
+    private boolean isNew = false;
+
+    /**
+     * Flag indicating whether this session is valid or not.
+     */
+    protected boolean isValid = false;
+
+    /**
+     * Internal notes associated with this session by Catalina components and
+     * event listeners. <b>IMPLEMENTATION NOTE: </b> This object is <em>not</em>
+     * saved and restored across session serializations!
+     */
+    private transient Map notes = new Hashtable();
+
+    /**
+     * The authenticated Principal associated with this session, if any.
+     * <b>IMPLEMENTATION NOTE: </b> This object is <i>not </i> saved and
+     * restored across session serializations!
+     */
+    private transient Principal principal = null;
+
+    /**
+     * The string manager for this package.
+     */
+    private static StringManager sm = StringManager
+            .getManager(Constants.Package);
+
+    /**
+     * The HTTP session context associated with this session.
+     */
+    private static HttpSessionContext sessionContext = null;
+
+    /**
+     * The property change support for this component. NOTE: This value is not
+     * included in the serialized version of this object.
+     */
+    private transient PropertyChangeSupport support = new PropertyChangeSupport(
+            this);
+
+    /**
+     * The current accessed time for this session.
+     */
+    private long thisAccessedTime = creationTime;
+
+    /**
+     * only the primary session will expire, or be able to expire due to
+     * inactivity. This is set to false as soon as I receive this session over
+     * the wire in a session message. That means that someone else has made a
+     * request on another server.
+     */
+    private transient boolean isPrimarySession = true;
+
+    /**
+     * The delta request contains all the action info
+     *  
+     */
+    private transient DeltaRequest deltaRequest = null;
+
+    /**
+     * Last time the session was replicatd, used for distributed expiring of
+     * session
+     */
+    private transient long lastTimeReplicated = System.currentTimeMillis();
+
+    /**
+     * The access count for this session
+     */
+    protected transient int accessCount = 0;
+
+    // ----------------------------------------------------------- Constructors
+    
+    /**
+     * Construct a new Session associated with the specified Manager.
+     * 
+     * @param manager
+     *            The manager with which this Session is associated
+     */
+    public DeltaSession(Manager manager) {
+
+        super();
+        this.manager = manager;
+        this.resetDeltaRequest();
+    }
+
+    // ----------------------------------------------------- Session Properties
+
+    /**
+     * returns true if this session is the primary session, if that is the case,
+     * the manager can expire it upon timeout.
+     */
+    public boolean isPrimarySession() {
+        return isPrimarySession;
+    }
+
+    /**
+     * Sets whether this is the primary session or not.
+     * 
+     * @param primarySession
+     *            Flag value
+     */
+    public void setPrimarySession(boolean primarySession) {
+        this.isPrimarySession = primarySession;
+    }
+
+    /**
+     * Return the authentication type used to authenticate our cached Principal,
+     * if any.
+     */
+    public String getAuthType() {
+
+        return (this.authType);
+
+    }
+
+    /**
+     * Set the authentication type used to authenticate our cached Principal, if
+     * any.
+     * 
+     * @param authType
+     *            The new cached authentication type
+     */
+    public void setAuthType(String authType) {
+
+        String oldAuthType = this.authType;
+        this.authType = authType;
+        support.firePropertyChange("authType", oldAuthType, this.authType);
+
+    }
+
+    /**
+     * Set the creation time for this session. This method is called by the
+     * Manager when an existing Session instance is reused.
+     * 
+     * @param time
+     *            The new creation time
+     */
+    public void setCreationTime(long time) {
+
+        this.creationTime = time;
+        this.lastAccessedTime = time;
+        this.thisAccessedTime = time;
+
+    }
+
+    /**
+     * Return the session identifier for this session.
+     */
+    public String getId() {
+        return (this.id);
+
+    }
+
+
+    /**
+     * Return the session identifier for this session.
+     */
+    public String getIdInternal() {
+
+        return (this.id);
+
+    }
+
+
+    /**
+     * Set the session identifier for this session without notify listeners.
+     * 
+     * @param id
+     *            The new session identifier
+     */
+    public void setIdInternal(String id) {
+        if ((this.id != null) && (manager != null))
+            manager.remove(this);
+
+        this.id = id;
+
+        if (manager != null)
+            manager.add(this);
+        if ( deltaRequest == null ) resetDeltaRequest();
+        else deltaRequest.setSessionId(id);
+    }
+
+    /**
+     * Set the session identifier for this session.
+     * 
+     * @param id
+     *            The new session identifier
+     */
+    public void setId(String id) {
+        setIdInternal(id);
+        tellNew();
+     }
+
+    /**
+     * Inform the listeners about the new session.
+     *  
+     */
+    public void tellNew() {
+
+        // Notify interested session event listeners
+        fireSessionEvent(Session.SESSION_CREATED_EVENT, null);
+
+        // Notify interested application event listeners
+        Context context = (Context) manager.getContainer();
+        //fix for standalone manager without container
+        if (context != null) {
+            Object listeners[] = context.getApplicationLifecycleListeners();
+            if (listeners != null) {
+                HttpSessionEvent event = new HttpSessionEvent(getSession());
+                for (int i = 0; i < listeners.length; i++) {
+                    if (!(listeners[i] instanceof HttpSessionListener))
+                        continue;
+                    HttpSessionListener listener = (HttpSessionListener) listeners[i];
+                    try {
+                        fireContainerEvent(context, "beforeSessionCreated",
+                                listener);
+                        listener.sessionCreated(event);
+                        fireContainerEvent(context, "afterSessionCreated",
+                                listener);
+                    } catch (Throwable t) {
+                        try {
+                            fireContainerEvent(context, "afterSessionCreated",
+                                    listener);
+                        } catch (Exception e) {
+                            ;
+                        }
+                        // FIXME - should we do anything besides log these?
+                        log.error(sm.getString("standardSession.sessionEvent"),
+                                t);
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Return descriptive information about this Session implementation and the
+     * corresponding version number, in the format
+     * <code>&lt;description&gt;/&lt;version&gt;</code>.
+     */
+    public String getInfo() {
+
+        return (info);
+
+    }
+
+    /**
+     * Return the last time the client sent a request associated with this
+     * session, as the number of milliseconds since midnight, January 1, 1970
+     * GMT. Actions that your application takes, such as getting or setting a
+     * value associated with the session, do not affect the access time.
+     */
+    public long getLastAccessedTime() {
+
+        if (!isValid()) {
+            throw new IllegalStateException(sm
+                    .getString("standardSession.getLastAccessedTime.ise"));
+        }
+            
+        return (this.lastAccessedTime);
+    }
+
+    /**
+     * Return the last client access time without invalidation check
+     * @see #getLastAccessedTime().
+     */
+    public long getLastAccessedTimeInternal() {
+        return (this.lastAccessedTime);
+    }
+
+    /**
+     * Return the Manager within which this Session is valid.
+     */
+    public Manager getManager() {
+
+        return (this.manager);
+
+    }
+
+    /**
+     * Set the Manager within which this Session is valid.
+     * 
+     * @param manager
+     *            The new Manager
+     */
+    public void setManager(Manager manager) {
+
+        this.manager = manager;
+
+    }
+
+    /**
+     * Return the maximum time interval, in seconds, between client requests
+     * before the servlet container will invalidate the session. A negative time
+     * indicates that the session should never time out.
+     */
+    public int getMaxInactiveInterval() {
+
+        return (this.maxInactiveInterval);
+
+    }
+
+    /**
+     * Set the maximum time interval, in seconds, between client requests before
+     * the servlet container will invalidate the session. A negative time
+     * indicates that the session should never time out.
+     * 
+     * @param interval
+     *            The new maximum interval
+     */
+    public void setMaxInactiveInterval(int interval) {
+        setMaxInactiveInterval(interval, true);
+    }
+
+    public void setMaxInactiveInterval(int interval, boolean addDeltaRequest) {
+
+        this.maxInactiveInterval = interval;
+        if (isValid && interval == 0) {
+            expire();
+        } else {
+            if (addDeltaRequest && (deltaRequest != null))
+                deltaRequest.setMaxInactiveInterval(interval);
+        }
+
+    }
+
+    /**
+     * Set the <code>isNew</code> flag for this session.
+     * 
+     * @param isNew
+     *            The new value for the <code>isNew</code> flag
+     */
+    public void setNew(boolean isNew) {
+        setNew(isNew, true);
+    }
+
+    public void setNew(boolean isNew, boolean addDeltaRequest) {
+        this.isNew = isNew;
+        if (addDeltaRequest && (deltaRequest != null))
+            deltaRequest.setNew(isNew);
+    }
+
+    /**
+     * Return the authenticated Principal that is associated with this Session.
+     * This provides an <code>Authenticator</code> with a means to cache a
+     * previously authenticated Principal, and avoid potentially expensive
+     * <code>Realm.authenticate()</code> calls on every request. If there is
+     * no current associated Principal, return <code>null</code>.
+     */
+    public Principal getPrincipal() {
+
+        return (this.principal);
+
+    }
+
+    /**
+     * Set the authenticated Principal that is associated with this Session.
+     * This provides an <code>Authenticator</code> with a means to cache a
+     * previously authenticated Principal, and avoid potentially expensive
+     * <code>Realm.authenticate()</code> calls on every request.
+     * 
+     * @param principal
+     *            The new Principal, or <code>null</code> if none
+     */
+    public void setPrincipal(Principal principal) {
+        setPrincipal(principal, true);
+    }
+
+    public void setPrincipal(Principal principal, boolean addDeltaRequest) {
+        Principal oldPrincipal = this.principal;
+        this.principal = principal;
+        support.firePropertyChange("principal", oldPrincipal, this.principal);
+        if (addDeltaRequest && (deltaRequest != null))
+            deltaRequest.setPrincipal(principal);
+    }
+
+    /**
+     * Return the <code>HttpSession</code> for which this object is the
+     * facade.
+     */
+    public HttpSession getSession() {
+
+        if (facade == null) {
+            if (System.getSecurityManager() != null) {
+                final DeltaSession fsession = this;
+                facade = (DeltaSessionFacade) AccessController
+                        .doPrivileged(new PrivilegedAction() {
+                            public Object run() {
+                                return new DeltaSessionFacade(fsession);
+                            }
+                        });
+            } else {
+                facade = new DeltaSessionFacade(this);
+            }
+        }
+        return (facade);
+
+    }
+
+    /**
+     * Return the <code>isValid</code> flag for this session.
+     */
+    public boolean isValid() {
+
+        if (this.expiring) {
+            return true;
+        }
+
+        if (!this.isValid) {
+            return false;
+        }
+
+        if (accessCount > 0) {
+            return true;
+        }
+
+        if (maxInactiveInterval >= 0) {
+            long timeNow = System.currentTimeMillis();
+            int timeIdle = (int) ((timeNow - thisAccessedTime) / 1000L);
+            if (isPrimarySession()) {
+                if(timeIdle >= maxInactiveInterval) {
+                    expire(true);
+                }
+            } else {
+                if (timeIdle >= (2 * maxInactiveInterval)) {
+                //if the session has been idle twice as long as allowed,
+                //the primary session has probably crashed, and no other
+                //requests are coming in. that is why we do this. otherwise
+                //we would have a memory leak
+                    expire(true, false);
+                }
+            }
+        }
+
+        return (this.isValid);
+    }
+
+    /**
+     * Set the <code>isValid</code> flag for this session.
+     * 
+     * @param isValid
+     *            The new value for the <code>isValid</code> flag
+     */
+    public void setValid(boolean isValid) {
+
+        this.isValid = isValid;
+    }
+
+    // ------------------------------------------------- Session Public Methods
+
+    /**
+     * Update the accessed time information for this session. This method should
+     * be called by the context when a request comes in for a particular
+     * session, even if the application does not reference it.
+     */
+    public void access() {
+
+        this.lastAccessedTime = this.thisAccessedTime;
+        this.thisAccessedTime = System.currentTimeMillis();
+
+        evaluateIfValid();
+
+        accessCount++;
+    }
+
+    public void endAccess() {
+        isNew = false;
+        accessCount--;
+        if(manager instanceof DeltaManager)
+            ((DeltaManager)manager).registerSessionAtReplicationValve(this);
+    }
+
+    /**
+     * Add a session event listener to this component.
+     */
+    public void addSessionListener(SessionListener listener) {
+
+        synchronized (listeners) {
+            listeners.add(listener);
+        }
+
+    }
+
+    /**
+     * Perform the internal processing required to invalidate this session,
+     * without triggering an exception if the session has already expired.
+     */
+    public void expire() {
+
+        expire(true);
+
+    }
+
+    /**
+     * Perform the internal processing required to invalidate this session,
+     * without triggering an exception if the session has already expired.
+     * 
+     * @param notify
+     *            Should we notify listeners about the demise of this session?
+     */
+    public void expire(boolean notify) {
+        expire(notify, true);
+    }
+
+    public void expire(boolean notify, boolean notifyCluster) {
+
+        // Mark this session as "being expired" if needed
+        if (expiring)
+            return;
+        String expiredId = getIdInternal();
+
+        synchronized (this) {
+
+            if (manager == null)
+                return;
+
+            expiring = true;
+
+            // Notify interested application event listeners
+            // FIXME - Assumes we call listeners in reverse order
+            Context context = (Context) manager.getContainer();
+            //fix for standalone manager without container
+            if (context != null) {
+                Object listeners[] = context.getApplicationLifecycleListeners();
+                if (notify && (listeners != null)) {
+                    HttpSessionEvent event = new HttpSessionEvent(getSession());
+                    for (int i = 0; i < listeners.length; i++) {
+                        int j = (listeners.length - 1) - i;
+                        if (!(listeners[j] instanceof HttpSessionListener))
+                            continue;
+                        HttpSessionListener listener = (HttpSessionListener) listeners[j];
+                        try {
+                            fireContainerEvent(context,
+                                    "beforeSessionDestroyed", listener);
+                            listener.sessionDestroyed(event);
+                            fireContainerEvent(context,
+                                    "afterSessionDestroyed", listener);
+                        } catch (Throwable t) {
+                            try {
+                                fireContainerEvent(context,
+                                        "afterSessionDestroyed", listener);
+                            } catch (Exception e) {
+                                ;
+                            }
+                            // FIXME - should we do anything besides log these?
+                            log.error(sm
+                                    .getString("standardSession.sessionEvent"),
+                                    t);
+                        }
+                    }
+                }
+            }//end if
+            //end fix
+            accessCount = 0;
+            setValid(false);
+
+            if (manager != null) {
+
+                /*
+                 * Compute how long this session has been alive, and update
+                 * session manager's related properties accordingly
+                 */
+                long timeNow = System.currentTimeMillis();
+                int timeAlive = (int) ((timeNow - creationTime)/1000);
+                synchronized (manager) {
+                    if (timeAlive > manager.getSessionMaxAliveTime()) {
+                        manager.setSessionMaxAliveTime(timeAlive);
+                    }
+                    int numExpired = manager.getExpiredSessions();
+                    numExpired++;
+                    manager.setExpiredSessions(numExpired);
+                    int average = manager.getSessionAverageAliveTime();
+                    average = ((average * (numExpired-1)) + timeAlive)/numExpired;
+                    manager.setSessionAverageAliveTime(average);
+                }
+
+                // Remove this session from our manager's active sessions
+                manager.remove(this);
+            }
+            
+            // Notify interested session event listeners
+            if (notify) {
+                fireSessionEvent(Session.SESSION_DESTROYED_EVENT, null);
+            }
+
+            // We have completed expire of this session
+            expiring = false;
+
+            // Unbind any objects associated with this session
+            String keys[] = keys();
+            for (int i = 0; i < keys.length; i++)
+                removeAttributeInternal(keys[i], notify, false);
+
+            if (notifyCluster && manager != null) {
+                if (log.isDebugEnabled())
+                    log.debug(smp.getString("deltaSession.notifying",
+                        ((DeltaManager) manager).getName(), new Boolean(
+                                isPrimarySession()), expiredId));
+                ((DeltaManager) manager).sessionExpired(expiredId);
+            }
+        }
+
+    }
+
+    /**
+     * Return the object bound with the specified name to the internal notes for
+     * this session, or <code>null</code> if no such binding exists.
+     * 
+     * @param name
+     *            Name of the note to be returned
+     */
+    public Object getNote(String name) {
+            return (notes.get(name));
+    }
+
+    /**
+     * Return an Iterator containing the String names of all notes bindings that
+     * exist for this session.
+     */
+    public Iterator getNoteNames() {
+            return (notes.keySet().iterator());
+    }
+
+    /**
+     * Release all object references, and initialize instance variables, in
+     * preparation for reuse of this object.
+     */
+    public void recycle() {
+
+        // Reset the instance variables associated with this Session
+        attributes.clear();
+        setAuthType(null);
+        creationTime = 0L;
+        expiring = false;
+        id = null;
+        lastAccessedTime = 0L;
+        maxInactiveInterval = -1;
+        accessCount = 0;
+        notes.clear();
+        setPrincipal(null);
+        isNew = false;
+        isValid = false;
+        manager = null;
+        deltaRequest.clear();
+
+    }
+
+    /**
+     * Remove any object bound to the specified name in the internal notes for
+     * this session.
+     * 
+     * @param name
+     *            Name of the note to be removed
+     */
+    public void removeNote(String name) {
+        notes.remove(name);
+    }
+
+    /**
+     * Remove a session event listener from this component.
+     */
+    public void removeSessionListener(SessionListener listener) {
+
+        synchronized (listeners) {
+            listeners.remove(listener);
+        }
+
+    }
+
+    /**
+     * Bind an object to a specified name in the internal notes associated with
+     * this session, replacing any existing binding for this name.
+     * 
+     * @param name
+     *            Name to which the object should be bound
+     * @param value
+     *            Object to be bound to the specified name
+     */
+    public void setNote(String name, Object value) {
+        notes.put(name, value);
+    }
+
+    /**
+     * Return a string representation of this object.
+     */
+    public String toString() {
+
+        StringBuffer sb = new StringBuffer();
+        sb.append("DeltaSession[");
+        sb.append(id);
+        sb.append("]");
+        return (sb.toString());
+
+    }
+
+    // ------------------------------------------------ Session Package Methods
+
+    /**
+     * Read a serialized version of the contents of this session object from the
+     * specified object input stream, without requiring that the StandardSession
+     * itself have been serialized.
+     * 
+     * @param stream
+     *            The object input stream to read from
+     * 
+     * @exception ClassNotFoundException
+     *                if an unknown class is specified
+     * @exception IOException
+     *                if an input/output error occurs
+     */
+    public void readObjectData(ObjectInputStream stream)
+            throws ClassNotFoundException, IOException {
+
+        readObject(stream);
+
+    }
+
+    /**
+     * Write a serialized version of the contents of this session object to the
+     * specified object output stream, without requiring that the
+     * StandardSession itself have been serialized.
+     * 
+     * @param stream
+     *            The object output stream to write to
+     * 
+     * @exception IOException
+     *                if an input/output error occurs
+     */
+    public void writeObjectData(ObjectOutputStream stream) throws IOException {
+
+        writeObject(stream);
+
+    }
+
+    public void resetDeltaRequest() {
+        if (deltaRequest == null) {
+            deltaRequest = new DeltaRequest(getIdInternal(), false);
+        } else {
+            deltaRequest.reset();
+            deltaRequest.setSessionId(getIdInternal());
+        }
+    }
+
+    public DeltaRequest getDeltaRequest() {
+        if (deltaRequest == null)
+            resetDeltaRequest();
+        return deltaRequest;
+    }
+
+    // ------------------------------------------------- HttpSession Properties
+
+    /**
+     * Return the time when this session was created, in milliseconds since
+     * midnight, January 1, 1970 GMT.
+     * 
+     * @exception IllegalStateException
+     *                if this method is called on an invalidated session
+     */
+    public long getCreationTime() {
+
+        if (!expiring && !isValid)
+            throw new IllegalStateException(sm
+                    .getString("standardSession.getCreationTime.ise"));
+
+        return (this.creationTime);
+
+    }
+
+    /**
+     * Return the ServletContext to which this session belongs.
+     */
+    public ServletContext getServletContext() {
+
+        if (manager == null)
+            return (null);
+        Context context = (Context) manager.getContainer();
+        if (context == null)
+            return (null);
+        else
+            return (context.getServletContext());
+
+    }
+
+    /**
+     * Return the session context with which this session is associated.
+     * 
+     * @deprecated As of Version 2.1, this method is deprecated and has no
+     *             replacement. It will be removed in a future version of the
+     *             Java Servlet API.
+     */
+    public HttpSessionContext getSessionContext() {
+
+        if (sessionContext == null)
+            sessionContext = new StandardSessionContext();
+        return (sessionContext);
+
+    }
+
+    // ----------------------------------------------HttpSession Public Methods
+
+    /**
+     * Return the object bound with the specified name in this session, or
+     * <code>null</code> if no object is bound with that name.
+     * 
+     * @param name
+     *            Name of the attribute to be returned
+     * 
+     * @exception IllegalStateException
+     *                if this method is called on an invalidated session
+     */
+    public Object getAttribute(String name) {
+
+        if (!isValid())
+            throw new IllegalStateException(sm
+                    .getString("standardSession.getAttribute.ise"));
+        return (attributes.get(name));
+    }
+
+    /**
+     * Return an <code>Enumeration</code> of <code>String</code> objects
+     * containing the names of the objects bound to this session.
+     * 
+     * @exception IllegalStateException
+     *                if this method is called on an invalidated session
+     */
+    public Enumeration getAttributeNames() {
+
+        if (!isValid())
+            throw new IllegalStateException(sm
+                    .getString("standardSession.getAttributeNames.ise"));
+        return (new Enumerator(attributes.keySet(), true));
+    }
+
+    /**
+     * Return the object bound with the specified name in this session, or
+     * <code>null</code> if no object is bound with that name.
+     * 
+     * @param name
+     *            Name of the value to be returned
+     * 
+     * @exception IllegalStateException
+     *                if this method is called on an invalidated session
+     * 
+     * @deprecated As of Version 2.2, this method is replaced by
+     *             <code>getAttribute()</code>
+     */
+    public Object getValue(String name) {
+
+        return (getAttribute(name));
+
+    }
+
+    /**
+     * Return the set of names of objects bound to this session. If there are no
+     * such objects, a zero-length array is returned.
+     * 
+     * @exception IllegalStateException
+     *                if this method is called on an invalidated session
+     * 
+     * @deprecated As of Version 2.2, this method is replaced by
+     *             <code>getAttributeNames()</code>
+     */
+    public String[] getValueNames() {
+
+        if (!isValid())
+            throw new IllegalStateException(sm
+                    .getString("standardSession.getValueNames.ise"));
+
+        return (keys());
+
+    }
+
+    /**
+     * Invalidates this session and unbinds any objects bound to it.
+     * 
+     * @exception IllegalStateException
+     *                if this method is called on an invalidated session
+     */
+    public void invalidate() {
+
+        if (!isValid())
+            throw new IllegalStateException(sm
+                    .getString("standardSession.invalidate.ise"));
+
+        // Cause this session to expire
+        expire();
+
+    }
+
+    /**
+     * Return <code>true</code> if the client does not yet know about the
+     * session, or if the client chooses not to join the session. For example,
+     * if the server used only cookie-based sessions, and the client has
+     * disabled the use of cookies, then a session would be new on each request.
+     * 
+     * @exception IllegalStateException
+     *                if this method is called on an invalidated session
+     */
+    public boolean isNew() {
+
+        if (!isValid())
+            throw new IllegalStateException(sm
+                    .getString("standardSession.isNew.ise"));
+
+        return (this.isNew);
+
+    }
+
+    /**
+     * Bind an object to this session, using the specified name. If an object of
+     * the same name is already bound to this session, the object is replaced.
+     * <p>
+     * After this method executes, and if the object implements
+     * <code>HttpSessionBindingListener</code>, the container calls
+     * <code>valueBound()</code> on the object.
+     * 
+     * @param name
+     *            Name to which the object is bound, cannot be null
+     * @param value
+     *            Object to be bound, cannot be null
+     * 
+     * @exception IllegalStateException
+     *                if this method is called on an invalidated session
+     * 
+     * @deprecated As of Version 2.2, this method is replaced by
+     *             <code>setAttribute()</code>
+     */
+    public void putValue(String name, Object value) {
+
+        setAttribute(name, value);
+
+    }
+
+    /**
+     * Remove the object bound with the specified name from this session. If the
+     * session does not have an object bound with this name, this method does
+     * nothing.
+     * <p>
+     * After this method executes, and if the object implements
+     * <code>HttpSessionBindingListener</code>, the container calls
+     * <code>valueUnbound()</code> on the object.
+     * 
+     * @param name
+     *            Name of the object to remove from this session.
+     * 
+     * @exception IllegalStateException
+     *                if this method is called on an invalidated session
+     */
+    public void removeAttribute(String name) {
+
+        removeAttribute(name, true);
+
+    }
+
+    /**
+     * Remove the object bound with the specified name from this session. If the
+     * session does not have an object bound with this name, this method does
+     * nothing.
+     * <p>
+     * After this method executes, and if the object implements
+     * <code>HttpSessionBindingListener</code>, the container calls
+     * <code>valueUnbound()</code> on the object.
+     * 
+     * @param name
+     *            Name of the object to remove from this session.
+     * @param notify
+     *            Should we notify interested listeners that this attribute is
+     *            being removed?
+     * 
+     * @exception IllegalStateException
+     *                if this method is called on an invalidated session
+     */
+    public void removeAttribute(String name, boolean notify) {
+        removeAttribute(name, notify, true);
+    }
+
+    public void removeAttribute(String name, boolean notify,
+            boolean addDeltaRequest) {
+
+        // Validate our current state
+        if (!isValid())
+            throw new IllegalStateException(sm
+                    .getString("standardSession.removeAttribute.ise"));
+        removeAttributeInternal(name, notify, addDeltaRequest);
+    }
+
+    /**
+     * Remove the object bound with the specified name from this session. If the
+     * session does not have an object bound with this name, this method does
+     * nothing.
+     * <p>
+     * After this method executes, and if the object implements
+     * <code>HttpSessionBindingListener</code>, the container calls
+     * <code>valueUnbound()</code> on the object.
+     * 
+     * @param name
+     *            Name of the object to remove from this session.
+     * 
+     * @exception IllegalStateException
+     *                if this method is called on an invalidated session
+     * 
+     * @deprecated As of Version 2.2, this method is replaced by
+     *             <code>removeAttribute()</code>
+     */
+    public void removeValue(String name) {
+
+        removeAttribute(name);
+
+    }
+
+    /**
+     * Bind an object to this session, using the specified name. If an object of
+     * the same name is already bound to this session, the object is replaced.
+     * <p>
+     * After this method executes, and if the object implements
+     * <code>HttpSessionBindingListener</code>, the container calls
+     * <code>valueBound()</code> on the object.
+     * 
+     * @param name
+     *            Name to which the object is bound, cannot be null
+     * @param value
+     *            Object to be bound, cannot be null
+     * 
+     * @exception IllegalArgumentException
+     *                if an attempt is made to add a non-serializable object in
+     *                an environment marked distributable.
+     * @exception IllegalStateException
+     *                if this method is called on an invalidated session
+     */
+    public void setAttribute(String name, Object value) {
+        setAttribute(name, value, true, true);
+    }
+
+    public void setAttribute(String name, Object value, boolean notify,
+            boolean addDeltaRequest) {
+
+        // Name cannot be null
+        if (name == null)
+            throw new IllegalArgumentException(sm
+                    .getString("standardSession.setAttribute.namenull"));
+
+        // Null value is the same as removeAttribute()
+        if (value == null) {
+            removeAttribute(name);
+            return;
+        }
+
+        // Validate our current state
+        if (!isValid())
+            throw new IllegalStateException(sm
+                    .getString("standardSession.setAttribute.ise"));
+        if (!(value instanceof java.io.Serializable)) {
+            throw new IllegalArgumentException("Attribute [" + name
+                    + "] is not serializable");
+        }
+
+        if (addDeltaRequest && (deltaRequest != null))
+            deltaRequest.setAttribute(name, value);
+
+
+        // Construct an event with the new value
+        HttpSessionBindingEvent event = null;
+
+        // Call the valueBound() method if necessary
+        if (value instanceof HttpSessionBindingListener && notify) {
+            // Don't call any notification if replacing with the same value
+            Object oldValue = attributes.get(name);
+            if (value != oldValue) {
+                event = new HttpSessionBindingEvent(getSession(), name, value);
+                try {
+                    ((HttpSessionBindingListener) value).valueBound(event);
+                } catch (Exception x) {
+                    log.error(smp.getString("deltaSession.valueBound.ex"), x);
+                }
+            }
+        }
+
+        // Replace or add this attribute
+        Object unbound = attributes.put(name, value);
+        // Call the valueUnbound() method if necessary
+        if ((unbound != null) && (unbound != value) && notify
+                && (unbound instanceof HttpSessionBindingListener)) {
+            try {
+                ((HttpSessionBindingListener) unbound)
+                        .valueUnbound(new HttpSessionBindingEvent(
+                                (HttpSession) getSession(), name));
+            } catch (Exception x) {
+                log.error(smp.getString("deltaSession.valueBinding.ex"), x);
+            }
+
+        }
+
+        //dont notify any listeners
+        if (!notify)
+            return;
+
+        // Notify interested application event listeners
+        Context context = (Context) manager.getContainer();
+        //fix for standalone manager without container
+        if (context != null) {
+            Object listeners[] = context.getApplicationEventListeners();
+            if (listeners == null)
+                return;
+            for (int i = 0; i < listeners.length; i++) {
+                if (!(listeners[i] instanceof HttpSessionAttributeListener))
+                    continue;
+                HttpSessionAttributeListener listener = (HttpSessionAttributeListener) listeners[i];
+                try {
+                    if (unbound != null) {
+                        fireContainerEvent(context,
+                                "beforeSessionAttributeReplaced", listener);
+                        if (event == null) {
+                            event = new HttpSessionBindingEvent(getSession(),
+                                    name, unbound);
+                        }
+                        listener.attributeReplaced(event);
+                        fireContainerEvent(context,
+                                "afterSessionAttributeReplaced", listener);
+                    } else {
+                        fireContainerEvent(context,
+                                "beforeSessionAttributeAdded", listener);
+                        if (event == null) {
+                            event = new HttpSessionBindingEvent(getSession(),
+                                    name, value);
+                        }
+                        listener.attributeAdded(event);
+                        fireContainerEvent(context,
+                                "afterSessionAttributeAdded", listener);
+                    }
+                } catch (Throwable t) {
+                    try {
+                        if (unbound != null) {
+                            fireContainerEvent(context,
+                                    "afterSessionAttributeReplaced", listener);
+                        } else {
+                            fireContainerEvent(context,
+                                    "afterSessionAttributeAdded", listener);
+                        }
+                    } catch (Exception e) {
+                        ;
+                    }
+                    // FIXME - should we do anything besides log these?
+                    log
+                            .error(
+                                    sm
+                                            .getString("standardSession.attributeEvent"),
+                                    t);
+                }
+            } //for
+        }//end if
+        //end fix
+
+    }
+
+    // -------------------------------------------- HttpSession Private Methods
+
+    /**
+     * Read a serialized version of this session object from the specified
+     * object input stream.
+     * <p>
+     * <b>IMPLEMENTATION NOTE </b>: The reference to the owning Manager is not
+     * restored by this method, and must be set explicitly.
+     * 
+     * @param stream
+     *            The input stream to read from
+     * 
+     * @exception ClassNotFoundException
+     *                if an unknown class is specified
+     * @exception IOException
+     *                if an input/output error occurs
+     */
+    private void readObject(ObjectInputStream stream)
+            throws ClassNotFoundException, IOException {
+
+        // Deserialize the scalar instance variables (except Manager)
+        authType = null; // Transient only
+        creationTime = ((Long) stream.readObject()).longValue();
+        lastAccessedTime = ((Long) stream.readObject()).longValue();
+        maxInactiveInterval = ((Integer) stream.readObject()).intValue();
+        isNew = ((Boolean) stream.readObject()).booleanValue();
+        isValid = ((Boolean) stream.readObject()).booleanValue();
+        thisAccessedTime = ((Long) stream.readObject()).longValue();
+        boolean hasPrincipal = stream.readBoolean();
+        principal = null;
+        if (hasPrincipal) {
+            principal = SerializablePrincipal.readPrincipal(stream,
+                    getManager().getContainer().getRealm());
+        }
+
+        //        setId((String) stream.readObject());
+        id = (String) stream.readObject();
+        if (log.isDebugEnabled())
+            log.debug(smp.getString("deltaSession.readSession",  id));
+
+        // Deserialize the attribute count and attribute values
+        if (attributes == null)
+            attributes = new Hashtable();
+        int n = ((Integer) stream.readObject()).intValue();
+        boolean isValidSave = isValid;
+        isValid = true;
+        for (int i = 0; i < n; i++) {
+            String name = (String) stream.readObject();
+            Object value = (Object) stream.readObject();
+            if ((value instanceof String) && (value.equals(NOT_SERIALIZED)))
+                continue;
+            attributes.put(name, value);
+        }
+        isValid = isValidSave;
+        
+        if (listeners == null) {
+            listeners = new ArrayList();
+        }
+        
+        if (notes == null) {
+            notes = new Hashtable();
+        }
+    }
+
+    /**
+     * Write a serialized version of this session object to the specified object
+     * output stream.
+     * <p>
+     * <b>IMPLEMENTATION NOTE </b>: The owning Manager will not be stored in the
+     * serialized representation of this Session. After calling
+     * <code>readObject()</code>, you must set the associated Manager
+     * explicitly.
+     * <p>
+     * <b>IMPLEMENTATION NOTE </b>: Any attribute that is not Serializable will
+     * be unbound from the session, with appropriate actions if it implements
+     * HttpSessionBindingListener. If you do not want any such attributes, be
+     * sure the <code>distributable</code> property of the associated Manager
+     * is set to <code>true</code>.
+     * 
+     * @param stream
+     *            The output stream to write to
+     * 
+     * @exception IOException
+     *                if an input/output error occurs
+     */
+    private void writeObject(ObjectOutputStream stream) throws IOException {
+
+        // Write the scalar instance variables (except Manager)
+        stream.writeObject(new Long(creationTime));
+        stream.writeObject(new Long(lastAccessedTime));
+        stream.writeObject(new Integer(maxInactiveInterval));
+        stream.writeObject(new Boolean(isNew));
+        stream.writeObject(new Boolean(isValid));
+        stream.writeObject(new Long(thisAccessedTime));
+        stream.writeBoolean(getPrincipal() != null);
+        if (getPrincipal() != null) {
+            SerializablePrincipal.writePrincipal((GenericPrincipal) principal,
+                    stream);
+        }
+
+        stream.writeObject(id);
+        if (log.isDebugEnabled())
+            log.debug(smp.getString("deltaSession.writeSession",id));
+
+        // Accumulate the names of serializable and non-serializable attributes
+        String keys[] = keys();
+        ArrayList saveNames = new ArrayList();
+        ArrayList saveValues = new ArrayList();
+        for (int i = 0; i < keys.length; i++) {
+            Object value = null;
+            value = attributes.get(keys[i]);
+            if (value == null)
+                continue;
+            else if (value instanceof Serializable) {
+                saveNames.add(keys[i]);
+                saveValues.add(value);
+            }
+        }
+
+        // Serialize the attribute count and the Serializable attributes
+        int n = saveNames.size();
+        stream.writeObject(new Integer(n));
+        for (int i = 0; i < n; i++) {
+            stream.writeObject((String) saveNames.get(i));
+            try {
+                stream.writeObject(saveValues.get(i));
+                //                if (log.isDebugEnabled())
+                //                    log.debug(" storing attribute '" + saveNames.get(i) +
+                //                        "' with value '" + saveValues.get(i) + "'");
+            } catch (NotSerializableException e) {
+                log.error(sm.getString("standardSession.notSerializable",
+                        saveNames.get(i), id), e);
+                stream.writeObject(NOT_SERIALIZED);
+                log.error("  storing attribute '" + saveNames.get(i)
+                        + "' with value NOT_SERIALIZED");
+            }
+        }
+
+    }
+
+    private void evaluateIfValid() {
+        /*
+         * If this session has expired or is in the process of expiring or will
+         * never expire, return
+         */
+        if (!this.isValid || expiring || maxInactiveInterval < 0)
+            return;
+
+        isValid();
+
+    }
+
+    // -------------------------------------------------------- Private Methods
+
+    /**
+     * Fire container events if the Context implementation is the
+     * <code>org.apache.catalina.core.StandardContext</code>.
+     * 
+     * @param context
+     *            Context for which to fire events
+     * @param type
+     *            Event type
+     * @param data
+     *            Event data
+     * 
+     * @exception Exception
+     *                occurred during event firing
+     */
+    private void fireContainerEvent(Context context, String type, Object data)
+            throws Exception {
+
+        if (!"org.apache.catalina.core.StandardContext".equals(context
+                .getClass().getName())) {
+            return; // Container events are not supported
+        }
+        // NOTE: Race condition is harmless, so do not synchronize
+        if (containerEventMethod == null) {
+            containerEventMethod = context.getClass().getMethod(
+                    "fireContainerEvent", containerEventTypes);
+        }
+        Object containerEventParams[] = new Object[2];
+        containerEventParams[0] = type;
+        containerEventParams[1] = data;
+        containerEventMethod.invoke(context, containerEventParams);
+
+    }
+
+    /**
+     * Notify all session event listeners that a particular event has occurred
+     * for this Session. The default implementation performs this notification
+     * synchronously using the calling thread.
+     * 
+     * @param type
+     *            Event type
+     * @param data
+     *            Event data
+     */
+    public void fireSessionEvent(String type, Object data) {
+        if (listeners.size() < 1)
+            return;
+        SessionEvent event = new SessionEvent(this, type, data);
+        SessionListener list[] = new SessionListener[0];
+        synchronized (listeners) {
+            list = (SessionListener[]) listeners.toArray(list);
+        }
+
+        for (int i = 0; i < list.length; i++) {
+            ((SessionListener) list[i]).sessionEvent(event);
+        }
+
+    }
+
+    /**
+     * Return the names of all currently defined session attributes as an array
+     * of Strings. If there are no defined attributes, a zero-length array is
+     * returned.
+     */
+    protected String[] keys() {
+        return ((String[]) attributes.keySet().toArray(EMPTY_ARRAY));
+    }
+
+    /**
+     * Return the value of an attribute without a check for validity.
+     */
+    protected Object getAttributeInternal(String name) {
+        return (attributes.get(name));  
+    }
+
+    protected void removeAttributeInternal(String name, boolean notify,
+            boolean addDeltaRequest) {
+
+        // Remove this attribute from our collection
+        Object value = attributes.remove(name);
+        if (value == null)
+            return;
+
+        if (addDeltaRequest && (deltaRequest != null))
+            deltaRequest.removeAttribute(name);
+
+        // Do we need to do valueUnbound() and attributeRemoved() notification?
+        if (!notify) {
+            return;
+        }
+
+        // Call the valueUnbound() method if necessary
+         HttpSessionBindingEvent event = null;
+         if (value instanceof HttpSessionBindingListener) {
+            event = new HttpSessionBindingEvent(
+                (HttpSession) getSession(), name, value);
+            try {
+                ((HttpSessionBindingListener) value).valueUnbound(event);
+            } catch (Exception x) {
+                log.error(smp.getString("deltaSession.valueUnbound.ex"), x);
+            }
+        }
+        // Notify interested application event listeners
+        Context context = (Context) manager.getContainer();
+        //fix for standalone manager without container
+        if (context != null) {
+            Object listeners[] = context.getApplicationEventListeners();
+            if (listeners == null)
+                return;
+            for (int i = 0; i < listeners.length; i++) {
+                if (!(listeners[i] instanceof HttpSessionAttributeListener))
+                    continue;
+                HttpSessionAttributeListener listener = (HttpSessionAttributeListener) listeners[i];
+                try {
+                    fireContainerEvent(context,
+                            "beforeSessionAttributeRemoved", listener);
+                    if (event == null) {
+                        event = new HttpSessionBindingEvent
+                            (getSession(), name, value);
+                    }
+                    listener.attributeRemoved(event);
+                    fireContainerEvent(context, "afterSessionAttributeRemoved",
+                            listener);
+                } catch (Throwable t) {
+                    try {
+                        fireContainerEvent(context,
+                                "afterSessionAttributeRemoved", listener);
+                    } catch (Exception e) {
+                        ;
+                    }
+                    // FIXME - should we do anything besides log these?
+                    log
+                            .error(
+                                    sm
+                                            .getString("standardSession.attributeEvent"),
+                                    t);
+                }
+            } //for
+        }//end if
+        //end fix
+
+    }
+
+    protected long getLastTimeReplicated() {
+        return lastTimeReplicated;
+    }
+
+    protected void setLastTimeReplicated(long lastTimeReplicated) {
+        this.lastTimeReplicated = lastTimeReplicated;
+    }
+
+    protected void setAccessCount(int accessCount) {
+        this.accessCount = accessCount;
+    }
+
+    protected int getAccessCount() {
+        return accessCount;
+    }
+
+}
+
+// -------------------------------------------------------------- Private Class
+
+/**
+ * This class is a dummy implementation of the <code>HttpSessionContext</code>
+ * interface, to conform to the requirement that such an object be returned when
+ * <code>HttpSession.getSessionContext()</code> is called.
+ * 
+ * @author Craig R. McClanahan
+ * 
+ * @deprecated As of Java Servlet API 2.1 with no replacement. The interface
+ *             will be removed in a future version of this API.
+ */
+
+final class StandardSessionContext implements HttpSessionContext {
+
+    private HashMap dummy = new HashMap();
+
+    /**
+     * Return the session identifiers of all sessions defined within this
+     * context.
+     * 
+     * @deprecated As of Java Servlet API 2.1 with no replacement. This method
+     *             must return an empty <code>Enumeration</code> and will be
+     *             removed in a future version of the API.
+     */
+    public Enumeration getIds() {
+
+        return (new Enumerator(dummy));
+
+    }
+
+    /**
+     * Return the <code>HttpSession</code> associated with the specified
+     * session identifier.
+     * 
+     * @param id
+     *            Session identifier for which to look up a session
+     * 
+     * @deprecated As of Java Servlet API 2.1 with no replacement. This method
+     *             must return null and will be removed in a future version of
+     *             the API.
+     */
+    public HttpSession getSession(String id) {
+
+        return (null);
+
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/session/DeltaSessionFacade.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/session/DeltaSessionFacade.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/session/DeltaSessionFacade.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,159 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.cluster.session;
+
+
+import java.util.Enumeration;
+
+import javax.servlet.ServletContext;
+import javax.servlet.http.HttpSession;
+import javax.servlet.http.HttpSessionContext;
+
+
+/**
+ * Facade for the DeltaSession object.
+ *
+ * @author Remy Maucherat
+ * @author Filip Hanik
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class DeltaSessionFacade
+    implements HttpSession {
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Construct a new session facade.
+     */
+    public DeltaSessionFacade(DeltaSession session) {
+        super();
+        this.session = (HttpSession) session;
+    }
+
+
+    /**
+     * Construct a new session facade.
+     */
+    public DeltaSessionFacade(HttpSession session) {
+        super();
+        this.session = session;
+    }
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * Wrapped session object.
+     */
+    private HttpSession session = null;
+
+
+    // ---------------------------------------------------- HttpSession Methods
+
+
+    public long getCreationTime() {
+        return session.getCreationTime();
+    }
+
+
+    public String getId() {
+        return session.getId();
+    }
+
+
+    public long getLastAccessedTime() {
+        return session.getLastAccessedTime();
+    }
+
+
+    public ServletContext getServletContext() {
+        // FIXME : Facade this object ?
+        return session.getServletContext();
+    }
+
+
+    public void setMaxInactiveInterval(int interval) {
+        session.setMaxInactiveInterval(interval);
+    }
+
+
+    public int getMaxInactiveInterval() {
+        return session.getMaxInactiveInterval();
+    }
+
+
+    public HttpSessionContext getSessionContext() {
+        return session.getSessionContext();
+    }
+
+
+    public Object getAttribute(String name) {
+        return session.getAttribute(name);
+    }
+
+
+    public Object getValue(String name) {
+        return session.getAttribute(name);
+    }
+
+
+    public Enumeration getAttributeNames() {
+        return session.getAttributeNames();
+    }
+
+
+    public String[] getValueNames() {
+        return session.getValueNames();
+    }
+
+
+    public void setAttribute(String name, Object value) {
+        session.setAttribute(name, value);
+    }
+
+
+    public void putValue(String name, Object value) {
+        session.setAttribute(name, value);
+    }
+
+
+    public void removeAttribute(String name) {
+        session.removeAttribute(name);
+    }
+
+
+    public void removeValue(String name) {
+        session.removeAttribute(name);
+    }
+
+
+    public void invalidate() {
+        session.invalidate();
+    }
+
+
+    public boolean isNew() {
+        return session.isNew();
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/session/JvmRouteBinderValve.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/session/JvmRouteBinderValve.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/session/JvmRouteBinderValve.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,545 @@
+/*
+ * Copyright 1999,2004-2005 The Apache Software Foundation.
+ * 
+ * Licensed 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.cluster.session;
+
+import java.io.IOException;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.Cookie;
+
+import org.apache.catalina.Container;
+import org.apache.catalina.Context;
+import org.apache.catalina.Engine;
+import org.apache.catalina.Globals;
+import org.apache.catalina.Host;
+import org.apache.catalina.Lifecycle;
+import org.apache.catalina.LifecycleException;
+import org.apache.catalina.LifecycleListener;
+import org.apache.catalina.Manager;
+import org.apache.catalina.Session;
+import org.apache.catalina.cluster.CatalinaCluster;
+import org.apache.catalina.cluster.ClusterManager;
+import org.apache.catalina.cluster.ClusterMessage;
+import org.apache.catalina.cluster.ClusterValve;
+import org.apache.catalina.connector.Request;
+import org.apache.catalina.connector.Response;
+import org.apache.catalina.session.ManagerBase;
+import org.apache.catalina.util.LifecycleSupport;
+import org.apache.catalina.util.StringManager;
+import org.apache.catalina.valves.ValveBase;
+
+/**
+ * Valve to handle Tomcat jvmRoute takeover using mod_jk module after node
+ * failure. After a node crashed the next request going to other cluster node.
+ * Now the answering from apache is slower ( make some error handshaking. Very
+ * bad with apache at my windows.). We rewrite now the jsessionid
+ * information to the backup cluster node. After the next response all client
+ * request goes direct to the backup node. The change sessionid send also to all
+ * other cluster nodes. Well, now the session stickyness work directly to the
+ * backup node and traffic don't go back too restarted cluster nodes!
+ * As jsessionid was created by cookie, the change JSESSIONID cookie resend with next response.
+ *  
+ * At all cluster node you must configure the as ClusterListener since 5.5.10
+ * {@link org.apache.catalina.cluster.session.JvmRouteSessionIDBinderListener JvmRouteSessionIDBinderListener}
+ * or before with
+ * org.apache.catalina.cluster.session.JvmRouteSessionIDBinderListenerLifecycle.
+ * 
+ * Add this Valve to your host definition at conf/server.xml .
+ * 
+ * Since 5.5.10 as direct cluster valve:<br/>
+ * <pre>
+ *  &lt;Cluster&gt;
+ *  &lt;Valve className=&quot;org.apache.catalina.cluster.session.JvmRouteBinderValve&quot; /&gt;  
+ *  &lt;/Cluster&gt;
+ * </pre>
+ * <br />
+ * Before 5.5.10 as Host element:<br/>
+ * <pre>
+ *  &lt;Hostr&gt;
+ *  &lt;Valve className=&quot;org.apache.catalina.cluster.session.JvmRouteBinderValve&quot; /&gt;  
+ *  &lt;/Hostr&gt;
+ * </pre>
+ * 
+ * Trick:<br/>
+ * You can enable this mod_jk turnover mode via JMX before you drop a node to all backup nodes!
+ * Set enable true on all JvmRouteBinderValve backups, disable worker at mod_jk 
+ * and then drop node and restart it! Then enable mod_jk Worker and disable JvmRouteBinderValves again. 
+ * This use case means that only requested session are migrated.
+ * 
+ * @author Peter Rossbach
+ * @version $Revision: 393256 $ $Date: 2006-04-11 11:20:28 -0500 (Tue, 11 Apr 2006) $
+ */
+public class JvmRouteBinderValve extends ValveBase implements ClusterValve, Lifecycle {
+
+    /*--Static Variables----------------------------------------*/
+    public static org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory
+            .getLog(JvmRouteBinderValve.class);
+
+    /**
+     * The descriptive information about this implementation.
+     */
+    protected static final String info = "org.apache.catalina.cluster.session.JvmRouteBinderValve/1.3";
+
+    /*--Instance Variables--------------------------------------*/
+
+    /**
+     * the cluster
+     */
+    protected CatalinaCluster cluster;
+
+    /**
+     * The string manager for this package.
+     */
+    protected StringManager sm = StringManager.getManager(Constants.Package);
+
+    /**
+     * Has this component been started yet?
+     */
+    protected boolean started = false;
+
+    /**
+     * enabled this component
+     */
+    protected boolean enabled = true;
+
+    /**
+     * number of session that no at this tomcat instanz hosted
+     */
+    protected long numberOfSessions = 0;
+
+    protected String sessionIdAttribute = "org.apache.catalina.cluster.session.JvmRouteOrignalSessionID";
+
+    /**
+     * The lifecycle event support for this component.
+     */
+    protected LifecycleSupport lifecycle = new LifecycleSupport(this);
+
+    /*--Logic---------------------------------------------------*/
+
+    /**
+     * Return descriptive information about this implementation.
+     */
+    public String getInfo() {
+
+        return (info);
+
+    }
+
+    /**
+     * set session id attribute to failed node for request.
+     * 
+     * @return Returns the sessionIdAttribute.
+     */
+    public String getSessionIdAttribute() {
+        return sessionIdAttribute;
+    }
+
+    /**
+     * get name of failed reqeust session attribute
+     * 
+     * @param sessionIdAttribute
+     *            The sessionIdAttribute to set.
+     */
+    public void setSessionIdAttribute(String sessionIdAttribute) {
+        this.sessionIdAttribute = sessionIdAttribute;
+    }
+
+    /**
+     * @return Returns the number of migrated sessions.
+     */
+    public long getNumberOfSessions() {
+        return numberOfSessions;
+    }
+
+    /**
+     * @return Returns the enabled.
+     */
+    public boolean getEnabled() {
+        return enabled;
+    }
+
+    /**
+     * @param enabled
+     *            The enabled to set.
+     */
+    public void setEnabled(boolean enabled) {
+        this.enabled = enabled;
+    }
+
+    /**
+     * Detect possible the JVMRoute change at cluster backup node..
+     * 
+     * @param request
+     *            tomcat request being processed
+     * @param response
+     *            tomcat response being processed
+     * @exception IOException
+     *                if an input/output error has occurred
+     * @exception ServletException
+     *                if a servlet error has occurred
+     */
+    public void invoke(Request request, Response response) throws IOException,
+            ServletException {
+
+         if (getEnabled() 
+             && getCluster() != null
+             && request.getContext() != null
+             && request.getContext().getDistributable() ) {
+             // valve cluster can access manager - other cluster handle turnover 
+             // at host level - hopefully!
+             Manager manager = request.getContext().getManager();
+             if (manager != null && manager instanceof ClusterManager
+                     && getCluster().getManager(((ClusterManager)manager).getName()) != null)
+                 handlePossibleTurnover(request, response);
+        }
+        // Pass this request on to the next valve in our pipeline
+        getNext().invoke(request, response);
+    }
+
+    /**
+     * handle possible session turn over.
+     * 
+     * @see JvmRouteBinderValve#handleJvmRoute(Request, Response, String, String)
+     * @param request current request
+     * @param response current response
+     */
+    protected void handlePossibleTurnover(Request request, Response response) {
+        Session session = request.getSessionInternal(false);
+        if (session != null) {
+            long t1 = System.currentTimeMillis();
+            String jvmRoute = getLocalJvmRoute(request);
+            if (jvmRoute == null) {
+                if (log.isWarnEnabled())
+                    log.warn(sm.getString("jvmRoute.missingJvmRouteAttribute"));
+                return;
+            }
+            handleJvmRoute( request, response,session.getIdInternal(), jvmRoute);
+            if (log.isDebugEnabled()) {
+                long t2 = System.currentTimeMillis();
+                long time = t2 - t1;
+                log.debug(sm.getString("jvmRoute.turnoverInfo", new Long(time)));
+            }
+        }
+    }
+
+    /**
+     * get jvmroute from engine
+     * 
+     * @param request current request
+     * @return return jvmRoute from ManagerBase or null
+     */
+    protected String getLocalJvmRoute(Request request) {
+        Manager manager = getManager(request);
+        if(manager instanceof ManagerBase)
+            return ((ManagerBase) manager).getJvmRoute();
+        return null ;
+    }
+
+    /**
+     * get Cluster DeltaManager
+     * 
+     * @param request current request
+     * @return manager or null
+     */
+    protected Manager getManager(Request request) {
+        Manager manager = request.getContext().getManager();
+        if (log.isDebugEnabled()) {
+            if(manager != null)
+                log.debug(sm.getString("jvmRoute.foundManager", manager,  request.getContext().getName()));
+            else 
+                log.debug(sm.getString("jvmRoute.notFoundManager", manager,  request.getContext().getName()));
+        }
+        return manager;
+    }
+
+    /**
+     * @return Returns the cluster.
+     */
+    public CatalinaCluster getCluster() {
+        return cluster;
+    }
+    
+    /**
+     * @param cluster The cluster to set.
+     */
+    public void setCluster(CatalinaCluster cluster) {
+        this.cluster = cluster;
+    }
+    
+    /**
+     * Handle jvmRoute stickyness after tomcat instance failed. After this
+     * correction a new Cookie send to client with new jvmRoute and the
+     * SessionID change propage to the other cluster nodes.
+     * 
+     * @param request current request
+     * @param response
+     *            Tomcat Response
+     * @param sessionId
+     *            request SessionID from Cookie
+     * @param localJvmRoute
+     *            local jvmRoute
+     */
+    protected void handleJvmRoute(
+            Request request, Response response,String sessionId, String localJvmRoute) {
+        // get requested jvmRoute.
+        String requestJvmRoute = null;
+        int index = sessionId.indexOf(".");
+        if (index > 0) {
+            requestJvmRoute = sessionId
+                    .substring(index + 1, sessionId.length());
+        }
+        if (requestJvmRoute != null && !requestJvmRoute.equals(localJvmRoute)) {
+            if (log.isDebugEnabled()) {
+                log.debug(sm.getString("jvmRoute.failover", requestJvmRoute,
+                        localJvmRoute, sessionId));
+            }
+            // OK - turnover the session ?
+            String newSessionID = sessionId.substring(0, index) + "."
+                    + localJvmRoute;
+            Session catalinaSession = null;
+            try {
+                catalinaSession = getManager(request).findSession(sessionId);
+            } catch (IOException e) {
+                // Hups!
+            }
+            if (catalinaSession != null) {
+                changeSessionID(request, response, sessionId, newSessionID,
+                        catalinaSession);
+                numberOfSessions++;
+            } else {
+                if (log.isDebugEnabled()) {
+                    log.debug(sm.getString("jvmRoute.cannotFindSession",
+                            sessionId));
+                }
+            }
+        }
+    }
+
+    /**
+     * change session id and send to all cluster nodes
+     * 
+     * @param request current request
+     * @param response current response
+     * @param sessionId
+     *            original session id
+     * @param newSessionID
+     *            new session id for node migration
+     * @param catalinaSession
+     *            current session with original session id
+     */
+    protected void changeSessionID(Request request,
+            Response response, String sessionId, String newSessionID, Session catalinaSession) {
+        lifecycle.fireLifecycleEvent("Before session migration",
+                catalinaSession);
+        request.setRequestedSessionId(newSessionID);
+        catalinaSession.setId(newSessionID);
+        if (catalinaSession instanceof DeltaSession)
+            ((DeltaSession) catalinaSession).resetDeltaRequest();
+        if(request.isRequestedSessionIdFromCookie())
+            setNewSessionCookie(request, response,newSessionID);
+        // set orginal sessionid at request, to allow application detect the
+        // change
+        if (sessionIdAttribute != null && !"".equals(sessionIdAttribute)) {
+            if (log.isDebugEnabled()) {
+                log.debug(sm.getString("jvmRoute.set.orignalsessionid",sessionIdAttribute,sessionId));
+            }
+            request.setAttribute(sessionIdAttribute, sessionId);
+        }
+        // now sending the change to all other clusternode!
+        ClusterManager manager = (ClusterManager)catalinaSession.getManager();
+        sendSessionIDClusterBackup(manager,request,sessionId, newSessionID);
+        lifecycle
+                .fireLifecycleEvent("After session migration", catalinaSession);
+        if (log.isDebugEnabled()) {
+            log.debug(sm.getString("jvmRoute.changeSession", sessionId,
+                    newSessionID));
+        }
+    }
+
+    /**
+     * Send the changed Sessionid to all clusternodes.
+     * 
+     * @see JvmRouteSessionIDBinderListener#messageReceived(ClusterMessage)
+     * @param manager
+     *            ClusterManager
+     * @param sessionId
+     *            current failed sessionid
+     * @param newSessionID
+     *            new session id, bind to the new cluster node
+     */
+    protected void sendSessionIDClusterBackup(ClusterManager manager,Request request,String sessionId,
+            String newSessionID) {
+        SessionIDMessage msg = new SessionIDMessage();
+        msg.setOrignalSessionID(sessionId);
+        msg.setBackupSessionID(newSessionID);
+        Context context = request.getContext();
+        msg.setContextPath(context.getPath());
+        msg.setHost(context.getParent().getName());
+        if(manager.isSendClusterDomainOnly())
+            cluster.sendClusterDomain(msg);
+        else
+            cluster.send(msg);
+    }
+
+    /**
+     * Sets a new cookie for the given session id and response and see
+     * {@link org.apache.catalina.connector.Request#configureSessionCookie(javax.servlet.http.Cookie)}
+     * 
+     * @param request current request
+     * @param response Tomcat Response
+     * @param sessionId The session id
+     */
+    protected void setNewSessionCookie(Request request,
+                                       Response response, String sessionId) {
+        if (response != null) {
+            Context context = request.getContext();
+            if (context.getCookies()) {
+                // set a new session cookie
+                Cookie newCookie = new Cookie(Globals.SESSION_COOKIE_NAME,
+                        sessionId);
+                newCookie.setMaxAge(-1);
+                String contextPath = null;
+                if (!response.getConnector().getEmptySessionPath()
+                        && (context != null)) {
+                    contextPath = context.getEncodedPath();
+                }
+                if ((contextPath != null) && (contextPath.length() > 0)) {
+                    newCookie.setPath(contextPath);
+                } else {
+                    newCookie.setPath("/");
+                }
+                if (request.isSecure()) {
+                    newCookie.setSecure(true);
+                }
+                if (log.isDebugEnabled()) {
+                    log.debug(sm.getString("jvmRoute.newSessionCookie",
+                            sessionId, Globals.SESSION_COOKIE_NAME, newCookie
+                                    .getPath(), new Boolean(newCookie
+                                    .getSecure())));
+                }
+                response.addCookie(newCookie);
+            }
+        }
+    }
+
+    // ------------------------------------------------------ Lifecycle Methods
+
+    /**
+     * Add a lifecycle event listener to this component.
+     * 
+     * @param listener
+     *            The listener to add
+     */
+    public void addLifecycleListener(LifecycleListener listener) {
+
+        lifecycle.addLifecycleListener(listener);
+
+    }
+
+    /**
+     * Get the lifecycle listeners associated with this lifecycle. If this
+     * Lifecycle has no listeners registered, a zero-length array is returned.
+     */
+    public LifecycleListener[] findLifecycleListeners() {
+
+        return lifecycle.findLifecycleListeners();
+
+    }
+
+    /**
+     * Remove a lifecycle event listener from this component.
+     * 
+     * @param listener
+     *            The listener to add
+     */
+    public void removeLifecycleListener(LifecycleListener listener) {
+
+        lifecycle.removeLifecycleListener(listener);
+
+    }
+
+    /**
+     * Prepare for the beginning of active use of the public methods of this
+     * component. This method should be called after <code>configure()</code>,
+     * and before any of the public methods of the component are utilized.
+     * 
+     * @exception LifecycleException
+     *                if this component detects a fatal error that prevents this
+     *                component from being used
+     */
+    public void start() throws LifecycleException {
+
+        // Validate and update our current component state
+        if (started)
+            throw new LifecycleException(sm
+                    .getString("jvmRoute.valve.alreadyStarted"));
+        lifecycle.fireLifecycleEvent(START_EVENT, null);
+        started = true;
+        if (cluster == null) {
+            Container hostContainer = getContainer();
+            // compatibility with JvmRouteBinderValve version 1.1
+            // ( setup at context.xml or context.xml.default )
+            if (!(hostContainer instanceof Host)) {
+                if (log.isWarnEnabled())
+                    log.warn(sm.getString("jvmRoute.configure.warn"));
+                hostContainer = hostContainer.getParent();
+            }
+            if (hostContainer instanceof Host
+                    && ((Host) hostContainer).getCluster() != null) {
+                cluster = (CatalinaCluster) ((Host) hostContainer).getCluster();
+            } else {
+                Container engine = hostContainer.getParent() ;
+                if (engine instanceof Engine
+                        && ((Engine) engine).getCluster() != null) {
+                    cluster = (CatalinaCluster) ((Engine) engine).getCluster();
+                }
+            }
+        }
+        if (cluster == null) {
+            throw new RuntimeException("No clustering support at container "
+                    + container.getName());
+        }
+        
+        if (log.isInfoEnabled())
+            log.info(sm.getString("jvmRoute.valve.started"));
+
+    }
+
+    /**
+     * Gracefully terminate the active use of the public methods of this
+     * component. This method should be the last one called on a given instance
+     * of this component.
+     * 
+     * @exception LifecycleException
+     *                if this component detects a fatal error that needs to be
+     *                reported
+     */
+    public void stop() throws LifecycleException {
+
+        // Validate and update our current component state
+        if (!started)
+            throw new LifecycleException(sm
+                    .getString("jvmRoute.valve.notStarted"));
+        lifecycle.fireLifecycleEvent(STOP_EVENT, null);
+        started = false;
+        cluster = null;
+        numberOfSessions = 0;
+        if (log.isInfoEnabled())
+            log.info(sm.getString("jvmRoute.valve.stopped"));
+
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/session/JvmRouteSessionIDBinderLifecycleListener.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/session/JvmRouteSessionIDBinderLifecycleListener.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/session/JvmRouteSessionIDBinderLifecycleListener.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,215 @@
+/*
+ * Copyright 1999,2004-2005 The Apache Software Foundation.
+ *
+ * Licensed 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.cluster.session;
+
+import javax.management.MBeanServer;
+import javax.management.MBeanServerFactory;
+import javax.management.MalformedObjectNameException;
+import javax.management.ObjectName;
+import javax.management.modelmbean.ModelMBean;
+
+import org.apache.catalina.Lifecycle;
+import org.apache.catalina.LifecycleEvent;
+import org.apache.catalina.LifecycleListener;
+import org.apache.catalina.cluster.CatalinaCluster;
+import org.apache.catalina.cluster.MessageListener;
+import org.apache.catalina.core.StandardHost;
+import org.apache.catalina.util.StringManager;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.commons.modeler.ManagedBean;
+import org.apache.commons.modeler.Registry;
+
+/**
+ * Register new JvmRouteSessionIDBinderListener to receive Session ID changes.
+ * 
+ * add following at your server.xml Host section
+ * 
+ * <pre>
+ *        &lt;Host &gt;... 
+ *          &lt;Listener className=&quot;org.apache.catalina.cluster.session.JvmRouteSessionIDBinderLifecycleListener&quot; /&gt;
+ *          &lt;Cluster ...&gt;
+ *        &lt;/Host&gt;
+ * </pre>
+ * FIXME add Engine support
+ * @deprecated
+ * @author Peter Rossbach
+ */
+public class JvmRouteSessionIDBinderLifecycleListener implements
+        LifecycleListener {
+    private static Log log = LogFactory
+            .getLog(JvmRouteSessionIDBinderLifecycleListener.class);
+
+    /**
+     * The descriptive information string for this implementation.
+     */
+    private static final String info = "org.apache.catalina.cluster.session.JvmRouteSessionIDBinderLifecycleListener/1.0";
+
+    /**
+     * The string resources for this package.
+     */
+    protected static final StringManager sm = StringManager
+            .getManager(Constants.Package);
+
+    private boolean enabled = true;
+
+    private MBeanServer mserver = null;
+
+    private Registry registry = null;
+
+    private MessageListener sessionMoverListener;
+
+    /*
+     * start and stop cluster
+     * 
+     * @see org.apache.catalina.LifecycleListener#lifecycleEvent(org.apache.catalina.LifecycleEvent)
+     */
+    public void lifecycleEvent(LifecycleEvent event) {
+
+        if (enabled && event.getSource() instanceof StandardHost) {
+
+            if (Lifecycle.AFTER_START_EVENT.equals(event.getType())) {
+                if (log.isDebugEnabled())
+                    log.debug(sm.getString("jvmRoute.listener.started"));
+                startSessionIDListener((StandardHost) event.getSource());
+            } else if (Lifecycle.BEFORE_STOP_EVENT.equals(event.getType())) {
+                if (log.isDebugEnabled())
+                    log.debug(sm.getString("jvmRoute.listener.stopped"));
+                stopSessionIDListener((StandardHost) event.getSource());
+            }
+        }
+    }
+
+    /**
+     * stop sessionID binder at cluster
+     * 
+     * @param host
+     *            clustered host
+     */
+    protected void stopSessionIDListener(StandardHost host) {
+        if (sessionMoverListener != null) {
+            CatalinaCluster cluster = (CatalinaCluster) host.getCluster();
+            cluster.removeClusterListener(sessionMoverListener);
+            if (mserver != null) {
+                try {
+                    ObjectName objectName = getObjectName(host);
+                    mserver.unregisterMBean(objectName);
+                } catch (Exception e) {
+                    log.error(e);
+                }
+            }
+        }
+    }
+
+    /**
+     * @param host
+     * @return The object name
+     * @throws MalformedObjectNameException
+     */
+    protected ObjectName getObjectName(StandardHost host) throws MalformedObjectNameException {
+        ObjectName objectName = new ObjectName(
+                host.getDomain()
+                        + ":type=Listener,name=JvmRouteSessionIDBinderListener,host=" + host.getName());
+        return objectName;
+    }
+
+    /**
+     * start sessionID mover at cluster
+     * 
+     * @param host
+     *            clustered host
+     */
+    protected void startSessionIDListener(StandardHost host) {
+        try {
+            ObjectName objectName = null;
+            getMBeanServer();
+            objectName = getObjectName(host);
+            if (mserver.isRegistered(objectName)) {
+                if (log.isInfoEnabled())
+                    log.info(sm.getString("jvmRoute.run.already"));
+                return;
+            }
+            sessionMoverListener = new JvmRouteSessionIDBinderListener();
+            mserver.registerMBean(getManagedBean(sessionMoverListener),
+                    objectName);
+            CatalinaCluster cluster = (CatalinaCluster) host.getCluster();
+            sessionMoverListener.setCluster(cluster);
+            ((JvmRouteSessionIDBinderListener) sessionMoverListener).start();
+        } catch (Exception ex) {
+            log.error(ex.getMessage(), ex);
+        }
+    }
+
+    protected MBeanServer getMBeanServer() throws Exception {
+        if (mserver == null) {
+            if (MBeanServerFactory.findMBeanServer(null).size() > 0) {
+                mserver = (MBeanServer) MBeanServerFactory
+                        .findMBeanServer(null).get(0);
+            } else {
+                mserver = MBeanServerFactory.createMBeanServer();
+            }
+            registry = Registry.getRegistry(null, null);
+            registry.loadMetadata(this.getClass().getResourceAsStream(
+                    "mbeans-descriptors.xml"));
+        }
+        return (mserver);
+    }
+
+    /**
+     * Returns the ModelMBean
+     * 
+     * @param object
+     *            The Object to get the ModelMBean for
+     * @return The ModelMBean
+     * @throws Exception
+     *             If an error occurs this constructors throws this exception
+     */
+    protected ModelMBean getManagedBean(Object object) throws Exception {
+        ModelMBean mbean = null;
+        if (registry != null) {
+            ManagedBean managedBean = registry.findManagedBean(object
+                    .getClass().getName());
+            mbean = managedBean.createMBean(object);
+        }
+        return mbean;
+    }
+
+    /**
+     * @return Returns the enabled.
+     */
+    public boolean isEnabled() {
+        return enabled;
+    }
+
+    /**
+     * @param enabled
+     *            The enabled to set.
+     */
+    public void setEnabled(boolean enabled) {
+        this.enabled = enabled;
+    }
+
+    /**
+     * Return descriptive information about this Listener implementation and the
+     * corresponding version number, in the format
+     * <code>&lt;description&gt;/&lt;version&gt;</code>.
+     */
+    public String getInfo() {
+
+        return (info);
+
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/session/JvmRouteSessionIDBinderListener.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/session/JvmRouteSessionIDBinderListener.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/session/JvmRouteSessionIDBinderListener.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,164 @@
+/*
+ * Copyright 1999,2004-2005 The Apache Software Foundation.
+ *
+ * Licensed 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.cluster.session;
+
+import java.io.IOException;
+
+import org.apache.catalina.Container;
+import org.apache.catalina.Context;
+import org.apache.catalina.Engine;
+import org.apache.catalina.LifecycleException;
+import org.apache.catalina.Session;
+import org.apache.catalina.cluster.ClusterMessage;
+import org.apache.catalina.core.StandardEngine;
+
+/**
+ * Receive SessionID cluster change from other backup node after primary session
+ * node is failed.
+ * 
+ * @author Peter Rossbach
+ * @version $Revision: 380229 $ $Date: 2006-02-23 15:28:29 -0600 (Thu, 23 Feb 2006) $
+ */
+public class JvmRouteSessionIDBinderListener extends ClusterListener {
+ 
+    /**
+     * The descriptive information about this implementation.
+     */
+    protected static final String info = "org.apache.catalina.cluster.session.JvmRouteSessionIDBinderListener/1.1";
+
+    //--Instance Variables--------------------------------------
+
+
+    protected boolean started = false;
+
+    /**
+     * number of session that goes to this cluster node
+     */
+    private long numberOfSessions = 0;
+
+    //--Constructor---------------------------------------------
+
+    public JvmRouteSessionIDBinderListener() {
+    }
+
+    //--Logic---------------------------------------------------
+
+    /**
+     * Return descriptive information about this implementation.
+     */
+    public String getInfo() {
+
+        return (info);
+
+    }
+
+    /**
+     * @return Returns the numberOfSessions.
+     */
+    public long getNumberOfSessions() {
+        return numberOfSessions;
+    }
+
+    /**
+     * Add this Mover as Cluster Listener ( receiver)
+     * 
+     * @throws LifecycleException
+     */
+    public void start() throws LifecycleException {
+        if (started)
+            return;
+        getCluster().addClusterListener(this);
+        started = true;
+        if (log.isInfoEnabled())
+            log.info(sm.getString("jvmRoute.clusterListener.started"));
+    }
+
+    /**
+     * Remove this from Cluster Listener
+     * 
+     * @throws LifecycleException
+     */
+    public void stop() throws LifecycleException {
+        started = false;
+        getCluster().removeClusterListener(this);
+        if (log.isInfoEnabled())
+            log.info(sm.getString("jvmRoute.clusterListener.stopped"));
+    }
+
+    /**
+     * Callback from the cluster, when a message is received, The cluster will
+     * broadcast it invoking the messageReceived on the receiver.
+     * 
+     * @param msg
+     *            ClusterMessage - the message received from the cluster
+     */
+    public void messageReceived(ClusterMessage msg) {
+        if (msg instanceof SessionIDMessage && msg != null) {
+            SessionIDMessage sessionmsg = (SessionIDMessage) msg;
+            if (log.isDebugEnabled())
+                log.debug(sm.getString(
+                        "jvmRoute.receiveMessage.sessionIDChanged", sessionmsg
+                                .getOrignalSessionID(), sessionmsg
+                                .getBackupSessionID(), sessionmsg
+                                .getContextPath()));
+            Container container = getCluster().getContainer();
+            Container host = null ;
+            if(container instanceof Engine) {
+                host = container.findChild(sessionmsg.getHost());
+            } else {
+                host = container ;
+            }
+            if (host != null) {
+                Context context = (Context) host.findChild(sessionmsg
+                        .getContextPath());
+                if (context != null) {
+                    try {
+                        Session session = context.getManager().findSession(
+                                sessionmsg.getOrignalSessionID());
+                        if (session != null) {
+                            session.setId(sessionmsg.getBackupSessionID());
+                        } else if (log.isInfoEnabled())
+                            log.info(sm.getString("jvmRoute.lostSession",
+                                    sessionmsg.getOrignalSessionID(),
+                                    sessionmsg.getContextPath()));
+                    } catch (IOException e) {
+                        log.error(e);
+                    }
+
+                } else if (log.isErrorEnabled())
+                    log.error(sm.getString("jvmRoute.contextNotFound",
+                            sessionmsg.getContextPath(), ((StandardEngine) host
+                                    .getParent()).getJvmRoute()));
+            } else if (log.isErrorEnabled())
+                log.error(sm.getString("jvmRoute.hostNotFound", sessionmsg.getContextPath()));
+        }
+    }
+
+    /**
+     * Accept only SessionIDMessages
+     * 
+     * @param msg
+     *            ClusterMessage
+     * @return boolean - returns true to indicate that messageReceived should be
+     *         invoked. If false is returned, the messageReceived method will
+     *         not be invoked.
+     */
+    public boolean accept(ClusterMessage msg) {
+        return (msg instanceof SessionIDMessage);
+    }
+}
+

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/session/LocalStrings.properties
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/session/LocalStrings.properties	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/session/LocalStrings.properties	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,96 @@
+deltaManager.createSession.ise=createSession: Too many active sessions
+deltaManager.createSession.newSession=Created a DeltaSession with Id [{0}] Total count={1}
+deltaManager.createMessage.access=Manager [{0}]: create session message [{1}] access.
+deltaManager.createMessage.accessChangePrimary=Manager [{0}]: create session message [{1}] access to change primary.
+deltaManager.createMessage.allSessionData=Manager [{0}] send all session data.
+deltaManager.createMessage.allSessionTransfered=Manager [{0}] send all session data transfered
+deltaManager.createMessage.delta=Manager [{0}]: create session message [{1}] delta request.
+deltaManager.createMessage.expire=Manager [{0}]: create session message [{1}] expire.
+deltaManager.createMessage.unableCreateDeltaRequest=Unable to serialize delta request for sessionid [{0}]
+deltaManager.dropMessage=Manager [{0}]: Drop message {1} inside GET_ALL_SESSIONS sync phase start date {2} message date {3}
+deltaManager.foundMasterMember=Found for context [{0}] the replication master member [{1}]
+deltaManager.loading.cnfe=ClassNotFoundException while loading persisted sessions: {0}
+deltaManager.loading.existing.session=overload existing session {0} 
+deltaManager.loading.ioe=IOException while loading persisted sessions: {0}
+deltaManager.loading.withContextClassLoader=Manager [{0}]: Loading the object data with a context class loader.
+deltaManager.loading.withoutClassLoader=Manager [{0}]: Loading the object data without a context class loader.
+deltaManager.managerLoad=Exception loading sessions from persistent storage
+deltaManager.noCluster=Starting... no cluster associated with this context: [{0}]
+deltaManager.noMasterMember=Starting... with no other member for context [{0}] at domain [{1}]
+deltaManager.noMembers=Manager [{0}]: skipping state transfer. No members active in cluster group.
+deltaManager.noSessionState=Manager [{0}]: No session state send at {1} received, timing out after {2} ms.
+deltaManager.notStarted=Manager has not yet been started
+deltaManager.sendMessage.newSession=Manager [{0}] send new session ({1})
+deltaManager.expireSessions=Manager [{0}] expiring sessions upon shutdown
+deltaManager.receiveMessage.accessed=Manager [{0}]: received session [{1}] accessed.
+deltaManager.receiveMessage.createNewSession=Manager [{0}]: received session [{1}] created.
+deltaManager.receiveMessage.delta=Manager [{0}]: received session [{1}] delta.
+deltaManager.receiveMessage.error=Manager [{0}]: Unable to receive message through TCP channel
+deltaManager.receiveMessage.eventType=Manager [{0}]: Received SessionMessage of type=({1}) from [{2}]
+deltaManager.receiveMessage.expired=Manager [{0}]: received session [{1}] expired.
+deltaManager.receiveMessage.transfercomplete=Manager [{0}] received from node [{1}:{2}] session state transfered.
+deltaManager.receiveMessage.unloadingAfter=Manager [{0}]: unloading sessions complete
+deltaManager.receiveMessage.unloadingBegin=Manager [{0}]: start unloading sessions
+deltaManager.receiveMessage.allSessionDataAfter=Manager [{0}]: session state deserialized
+deltaManager.receiveMessage.allSessionDataBegin=Manager [{0}]: received session state data
+deltaManager.receiveMessage.fromWrongDomain=Manager [{0}]: Received wrong SessionMessage of type=({1}) from [{2}] with domain [{3}] (localdomain [{4}] 
+deltaManager.registerCluster=Register manager {0} to cluster element {1} with name {2}
+deltaManager.sessionReceived=Manager [{0}]; session state send at {1} received in {2} ms.
+deltaManager.sessionTimeout=Invalid session timeout setting {0}
+deltaManager.startClustering=Starting clustering manager at {0}
+deltaManager.stopped=Manager [{0}] is stopping
+deltaManager.unloading.ioe=IOException while saving persisted sessions: {0}
+deltaManager.waitForSessionState=Manager [{0}], requesting session state from {1}. This operation will timeout if no session state has been received within 60 seconds.
+deltaRequest.showPrincipal=Principal [{0}] is set to session {1}
+deltaRequest.wrongPrincipalClass=DeltaManager only support GenericPrincipal. Your realm used principal class {0}.
+deltaSession.notifying=Notifying cluster of expiration primary={0} sessionId [{1}]
+deltaSession.valueBound.ex=Session bound listener throw an exception
+deltaSession.valueBinding.ex=Session binding listener throw an exception
+deltaSession.valueUnbound.ex=Session unbound listener throw an exception
+deltaSession.readSession=readObject() loading session [{0}]
+deltaSession.readAttribute=session [{0}] loading attribute '{1}' with value '{2}'
+deltaSession.writeSession=writeObject() storing session [{0}]
+jvmRoute.cannotFindSession=Can't find session [{0}]
+jvmRoute.changeSession=Changed session from [{0}] to [{1}]
+jvmRoute.clusterListener.started=Cluster JvmRouteSessionIDBinderListener started
+jvmRoute.clusterListener.stopped=Cluster JvmRouteSessionIDBinderListener stopped
+jvmRoute.configure.warn=Please, setup your JvmRouteBinderValve at host valve, not at context valve!
+jvmRoute.contextNotFound=Context [{0}] not found at node [{1}]!
+jvmRoute.failover=Detected a failover with different jvmRoute - orginal route: [{0}] new one: [{1}] at session id [{2}]
+jvmRoute.foundManager=Found Cluster DeltaManager {0} at {1}
+jvmRoute.hostNotFound=No host found [{0}]
+jvmRoute.listener.started=SessionID Binder Listener started
+jvmRoute.listener.stopped=SessionID Binder Listener stopped
+jvmRoute.lostSession=Lost Session [{0}] at path [{1}]
+jvmRoute.missingJvmRouteAttribute=No engine jvmRoute attribute configured!
+jvmRoute.newSessionCookie=Setting cookie with session id [{0}] name: [{1}] path: [{2}] secure: [{3}]
+jvmRoute.notFoundManager=Not found Cluster DeltaManager {0} at {1}
+jvmRoute.receiveMessage.sessionIDChanged=Cluster JvmRouteSessionIDBinderListener received orginal session ID [{0}] set to new id [{1}] for context path [{2}]
+jvmRoute.run.already=jvmRoute SessionID receiver run already
+jvmRoute.skipURLSessionIDs=Skip reassign jvm route check, sessionid comes from URL!
+jvmRoute.turnoverInfo=Turnover Check time {0} msec
+jvmRoute.valve.alreadyStarted=jvmRoute backup sessionID correction is started
+jvmRoute.valve.notStarted=jvmRoute backup sessionID correction run already
+jvmRoute.valve.started=JvmRouteBinderValve started
+jvmRoute.valve.stopped=JvmRouteBinderValve stopped
+jvmRoute.set.orignalsessionid=Set Orginal Session id at request attriute {0} value: {1}
+standardSession.getId.ise=getId: Session already invalidated
+standardSession.attributeEvent=Session attribute event listener threw exception
+standardSession.attributeEvent=Session attribute event listener threw exception
+standardSession.bindingEvent=Session binding event listener threw exception
+standardSession.invalidate.ise=invalidate: Session already invalidated
+standardSession.isNew.ise=isNew: Session already invalidated
+standardSession.getAttribute.ise=getAttribute: Session already invalidated
+standardSession.getAttributeNames.ise=getAttributeNames: Session already invalidated
+standardSession.getCreationTime.ise=getCreationTime: Session already invalidated
+standardSession.getLastAccessedTime.ise=getLastAccessedTime: Session already invalidated
+standardSession.getId.ise=getId: Session already invalidated
+standardSession.getMaxInactiveInterval.ise=getMaxInactiveInterval: Session already invalidated
+standardSession.getValueNames.ise=getValueNames: Session already invalidated
+standardSession.notSerializable=Cannot serialize session attribute {0} for session {1}
+standardSession.removeAttribute.ise=removeAttribute: Session already invalidated
+standardSession.sessionEvent=Session event listener threw exception
+standardSession.setAttribute.iae=setAttribute: Non-serializable attribute
+standardSession.setAttribute.ise=setAttribute: Session already invalidated
+standardSession.setAttribute.namenull=setAttribute: name parameter cannot be null
+standardSession.sessionCreated=Created Session id = {0}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/session/ReplicatedSession.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/session/ReplicatedSession.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/session/ReplicatedSession.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,285 @@
+
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.cluster.session;
+
+/**
+ * Title:        Tomcat Session Replication for Tomcat 4.0 <BR>
+ * Description:  A very simple straight forward implementation of
+ *               session replication of servers in a cluster.<BR>
+ *               This session replication is implemented "live". By live
+ *               I mean, when a session attribute is added into a session on Node A
+ *               a message is broadcasted to other messages and setAttribute is called on the replicated
+ *               sessions.<BR>
+ *               A full description of this implementation can be found under
+ *               <href="http://www.filip.net/tomcat/">Filip's Tomcat Page</a><BR>
+ *
+ * Copyright:    See apache license
+ * @author  Filip Hanik
+ * @version $Revision: 303842 $ $Date: 2005-04-10 11:20:46 -0500 (Sun, 10 Apr 2005) $
+ * Description:<BR>
+ * The ReplicatedSession class is a simple extension of the StandardSession class
+ * It overrides a few methods (setAttribute, removeAttribute, expire, access) and has
+ * hooks into the InMemoryReplicationManager to broadcast and receive events from the cluster.<BR>
+ * This class inherits the readObjectData and writeObject data methods from the StandardSession
+ * and does not contain any serializable elements in addition to the inherited ones from the StandardSession
+ *
+ */
+import org.apache.catalina.Manager;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.security.Principal;
+
+public class ReplicatedSession extends org.apache.catalina.session.StandardSession
+implements org.apache.catalina.cluster.ClusterSession{
+
+    private transient Manager mManager = null;
+    protected boolean isDirty = false;
+    private transient long lastAccessWasDistributed = System.currentTimeMillis();
+    private boolean isPrimarySession=true;
+    
+
+    public ReplicatedSession(Manager manager) {
+        super(manager);
+        mManager = manager;
+    }
+
+
+    public boolean isDirty()
+    {
+        return isDirty;
+    }
+
+    public void setIsDirty(boolean dirty)
+    {
+        isDirty = dirty;
+    }
+
+
+    public void setLastAccessWasDistributed(long time) {
+        lastAccessWasDistributed = time;
+    }
+
+    public long getLastAccessWasDistributed() {
+        return lastAccessWasDistributed;
+    }
+
+
+    public void removeAttribute(String name) {
+        setIsDirty(true);
+        super.removeAttribute(name);
+    }
+
+    /**
+     * see parent description,
+     * plus we also notify other nodes in the cluster
+     */
+    public void removeAttribute(String name, boolean notify) {
+        setIsDirty(true);
+        super.removeAttribute(name,notify);
+    }
+
+
+    /**
+     * Sets an attribute and notifies the other nodes in the cluster
+     */
+    public void setAttribute(String name, Object value)
+    {
+        if ( value == null ) {
+          removeAttribute(name);
+          return;
+        }
+        if (!(value instanceof java.io.Serializable))
+            throw new java.lang.IllegalArgumentException("Value for attribute "+name+" is not serializable.");
+        setIsDirty(true);
+        super.setAttribute(name,value);
+    }
+
+    public void setMaxInactiveInterval(int interval) {
+        setIsDirty(true);
+        super.setMaxInactiveInterval(interval);
+    }
+
+
+    /**
+     * Sets the manager for this session
+     * @param mgr - the servers InMemoryReplicationManager
+     */
+    public void setManager(SimpleTcpReplicationManager mgr)
+    {
+        mManager = mgr;
+        super.setManager(mgr);
+    }
+
+
+    /**
+     * Set the authenticated Principal that is associated with this Session.
+     * This provides an <code>Authenticator</code> with a means to cache a
+     * previously authenticated Principal, and avoid potentially expensive
+     * <code>Realm.authenticate()</code> calls on every request.
+     *
+     * @param principal The new Principal, or <code>null</code> if none
+     */
+    public void setPrincipal(Principal principal) {
+        super.setPrincipal(principal);
+        setIsDirty(true);
+    }
+
+    public void expire() {
+        SimpleTcpReplicationManager mgr =(SimpleTcpReplicationManager)getManager();
+        mgr.sessionInvalidated(getIdInternal());
+        setIsDirty(true);
+        super.expire();
+    }
+
+    public void invalidate() {
+        SimpleTcpReplicationManager mgr =(SimpleTcpReplicationManager)getManager();
+        mgr.sessionInvalidated(getIdInternal());
+        setIsDirty(true);
+        super.invalidate();
+    }
+
+
+    /**
+     * Read a serialized version of the contents of this session object from
+     * the specified object input stream, without requiring that the
+     * StandardSession itself have been serialized.
+     *
+     * @param stream The object input stream to read from
+     *
+     * @exception ClassNotFoundException if an unknown class is specified
+     * @exception IOException if an input/output error occurs
+     */
+    public void readObjectData(ObjectInputStream stream)
+        throws ClassNotFoundException, IOException {
+
+        super.readObjectData(stream);
+
+    }
+
+
+    /**
+     * Write a serialized version of the contents of this session object to
+     * the specified object output stream, without requiring that the
+     * StandardSession itself have been serialized.
+     *
+     * @param stream The object output stream to write to
+     *
+     * @exception IOException if an input/output error occurs
+     */
+    public void writeObjectData(ObjectOutputStream stream)
+        throws IOException {
+
+        super.writeObjectData(stream);
+
+    }
+    
+    public void setId(String id, boolean tellNew) {
+
+        if ((this.id != null) && (manager != null))
+            manager.remove(this);
+
+        this.id = id;
+
+        if (manager != null)
+            manager.add(this);
+        if (tellNew) tellNew();
+    }
+    
+    
+
+
+
+
+
+
+    /**
+     * returns true if this session is the primary session, if that is the
+     * case, the manager can expire it upon timeout.
+     */
+    public boolean isPrimarySession() {
+        return isPrimarySession;
+    }
+
+    /**
+     * Sets whether this is the primary session or not.
+     * @param primarySession Flag value
+     */
+    public void setPrimarySession(boolean primarySession) {
+        this.isPrimarySession=primarySession;
+    }
+
+
+
+
+    /**
+     * Implements a log method to log through the manager
+     */
+    protected void log(String message) {
+
+        if ((mManager != null) && (mManager instanceof SimpleTcpReplicationManager)) {
+            ((SimpleTcpReplicationManager) mManager).log.debug("ReplicatedSession: " + message);
+        } else {
+            System.out.println("ReplicatedSession: " + message);
+        }
+
+    }
+
+    protected void log(String message, Throwable x) {
+
+        if ((mManager != null) && (mManager instanceof SimpleTcpReplicationManager)) {
+            ((SimpleTcpReplicationManager) mManager).log.error("ReplicatedSession: " + message,x);
+        } else {
+            System.out.println("ReplicatedSession: " + message);
+            x.printStackTrace();
+        }
+
+    }
+
+    public String toString() {
+        StringBuffer buf = new StringBuffer("ReplicatedSession id=");
+        buf.append(getIdInternal()).append(" ref=").append(super.toString()).append("\n");
+        java.util.Enumeration e = getAttributeNames();
+        while ( e.hasMoreElements() ) {
+            String name = (String)e.nextElement();
+            Object value = getAttribute(name);
+            buf.append("\tname=").append(name).append("; value=").append(value).append("\n");
+        }
+        buf.append("\tLastAccess=").append(getLastAccessedTime()).append("\n");
+        return buf.toString();
+    }
+    public int getAccessCount() {
+        return accessCount;
+    }
+    public void setAccessCount(int accessCount) {
+        this.accessCount = accessCount;
+    }
+    public long getLastAccessedTime() {
+        return lastAccessedTime;
+    }
+    public void setLastAccessedTime(long lastAccessedTime) {
+        this.lastAccessedTime = lastAccessedTime;
+    }
+    public long getThisAccessedTime() {
+        return thisAccessedTime;
+    }
+    public void setThisAccessedTime(long thisAccessedTime) {
+        this.thisAccessedTime = thisAccessedTime;
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/session/ReplicationStream.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/session/ReplicationStream.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/session/ReplicationStream.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,99 @@
+/*
+ * Copyright 1999,2004-2005 The Apache Software Foundation.
+ * 
+ * Licensed 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.cluster.session;
+
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectStreamClass;
+
+/**
+ * Custom subclass of <code>ObjectInputStream</code> that loads from the
+ * class loader for this web application.  This allows classes defined only
+ * with the web application to be found correctly.
+ *
+ * @author Craig R. McClanahan
+ * @author Bip Thelin
+ * @version $Revision: 380229 $, $Date: 2006-02-23 15:28:29 -0600 (Thu, 23 Feb 2006) $
+ */
+
+public final class ReplicationStream extends ObjectInputStream {
+
+
+    /**
+     * The class loader we will use to resolve classes.
+     */
+    private ClassLoader classLoader = null;
+
+    /**
+     * Construct a new instance of CustomObjectInputStream
+     *
+     * @param stream The input stream we will read from
+     * @param classLoader The class loader used to instantiate objects
+     *
+     * @exception IOException if an input/output error occurs
+     */
+    public ReplicationStream(InputStream stream,
+                             ClassLoader classLoader)
+        throws IOException {
+
+        super(stream);
+        this.classLoader = classLoader;
+    }
+
+    /**
+     * Load the local class equivalent of the specified stream class
+     * description, by using the class loader assigned to this Context.
+     *
+     * @param classDesc Class description from the input stream
+     *
+     * @exception ClassNotFoundException if this class cannot be found
+     * @exception IOException if an input/output error occurs
+     */
+    public Class resolveClass(ObjectStreamClass classDesc)
+        throws ClassNotFoundException, IOException {
+        String name = classDesc.getName();
+        boolean tryRepFirst = name.startsWith("org.apache.catalina.cluster");
+        try {
+            try
+            {
+                if ( tryRepFirst ) return findReplicationClass(name);
+                else return findWebappClass(name);
+            }
+            catch ( Exception x )
+            {
+                if ( tryRepFirst ) return findWebappClass(name);
+                else return findReplicationClass(name);
+            }
+        } catch (ClassNotFoundException e) {
+            return super.resolveClass(classDesc);
+        }
+    }
+    
+    public Class findReplicationClass(String name)
+        throws ClassNotFoundException, IOException {
+        return Class.forName(name, false, getClass().getClassLoader());
+    }
+
+    public Class findWebappClass(String name)
+        throws ClassNotFoundException, IOException {
+        return Class.forName(name, false, classLoader);
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/session/SerializablePrincipal.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/session/SerializablePrincipal.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/session/SerializablePrincipal.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,190 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.cluster.session;
+
+
+import java.util.Arrays;
+import java.util.List;
+import org.apache.catalina.Realm;
+
+
+/**
+ * Generic implementation of <strong>java.security.Principal</strong> that
+ * is available for use by <code>Realm</code> implementations.
+ * The GenericPrincipal does NOT implement serializable and I didn't want to change that implementation
+ * hence I implemented this one instead.
+ * @author Filip Hanik
+ * @version $Revision: 303587 $ $Date: 2004-12-09 08:36:43 -0600 (Thu, 09 Dec 2004) $
+ */
+import org.apache.catalina.realm.GenericPrincipal;
+public class SerializablePrincipal  implements java.io.Serializable {
+
+
+    // ----------------------------------------------------------- Constructors
+
+    public SerializablePrincipal()
+    {
+        super();
+    }
+    /**
+     * Construct a new Principal, associated with the specified Realm, for the
+     * specified username and password.
+     *
+     * @param realm The Realm that owns this Principal
+     * @param name The username of the user represented by this Principal
+     * @param password Credentials used to authenticate this user
+     */
+    public SerializablePrincipal(Realm realm, String name, String password) {
+
+        this(realm, name, password, null);
+
+    }
+
+
+    /**
+     * Construct a new Principal, associated with the specified Realm, for the
+     * specified username and password, with the specified role names
+     * (as Strings).
+     *
+     * @param realm The Realm that owns this principal
+     * @param name The username of the user represented by this Principal
+     * @param password Credentials used to authenticate this user
+     * @param roles List of roles (must be Strings) possessed by this user
+     */
+    public SerializablePrincipal(Realm realm, String name, String password,
+                            List roles) {
+
+        super();
+        this.realm = realm;
+        this.name = name;
+        this.password = password;
+        if (roles != null) {
+            this.roles = new String[roles.size()];
+            this.roles = (String[]) roles.toArray(this.roles);
+            if (this.roles.length > 0)
+                Arrays.sort(this.roles);
+        }
+
+    }
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * The username of the user represented by this Principal.
+     */
+    protected String name = null;
+
+    public String getName() {
+        return (this.name);
+    }
+
+
+    /**
+     * The authentication credentials for the user represented by
+     * this Principal.
+     */
+    protected String password = null;
+
+    public String getPassword() {
+        return (this.password);
+    }
+
+
+    /**
+     * The Realm with which this Principal is associated.
+     */
+    protected transient Realm realm = null;
+
+    public Realm getRealm() {
+        return (this.realm);
+    }
+
+    public void setRealm(Realm realm) {
+        this.realm = realm;
+    }
+
+
+
+
+    /**
+     * The set of roles associated with this user.
+     */
+    protected String roles[] = new String[0];
+
+    public String[] getRoles() {
+        return (this.roles);
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+
+
+    /**
+     * Return a String representation of this object, which exposes only
+     * information that should be public.
+     */
+    public String toString() {
+
+        StringBuffer sb = new StringBuffer("SerializablePrincipal[");
+        sb.append(this.name);
+        sb.append("]");
+        return (sb.toString());
+
+    }
+
+    public static SerializablePrincipal createPrincipal(GenericPrincipal principal)
+    {
+        if ( principal==null) return null;
+        return new SerializablePrincipal(principal.getRealm(),
+                                         principal.getName(),
+                                         principal.getPassword(),
+                                         principal.getRoles()!=null?Arrays.asList(principal.getRoles()):null);
+    }
+
+    public GenericPrincipal getPrincipal( Realm realm )
+    {
+        return new GenericPrincipal(realm,name,password,getRoles()!=null?Arrays.asList(getRoles()):null);
+    }
+    
+    public static GenericPrincipal readPrincipal(java.io.ObjectInputStream in, Realm realm) throws java.io.IOException{
+        String name = in.readUTF();
+        boolean hasPwd = in.readBoolean();
+        String pwd = null;
+        if ( hasPwd ) pwd = in.readUTF();
+        int size = in.readInt();
+        String[] roles = new String[size];
+        for ( int i=0; i<size; i++ ) roles[i] = in.readUTF();
+        return new GenericPrincipal(realm,name,pwd,Arrays.asList(roles));
+    }
+    
+    public static void writePrincipal(GenericPrincipal p, java.io.ObjectOutputStream out) throws java.io.IOException {
+        out.writeUTF(p.getName());
+        out.writeBoolean(p.getPassword()!=null);
+        if ( p.getPassword()!= null ) out.writeUTF(p.getPassword());
+        String[] roles = p.getRoles();
+        if ( roles == null ) roles = new String[0];
+        out.writeInt(roles.length);
+        for ( int i=0; i<roles.length; i++ ) out.writeUTF(roles[i]);
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/session/SessionIDMessage.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/session/SessionIDMessage.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/session/SessionIDMessage.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,182 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ *
+ * Licensed 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.cluster.session;
+
+import org.apache.catalina.cluster.ClusterMessage;
+
+/**
+ * Session id change cluster message
+ * 
+ * @author Peter Rossbach
+ * 
+ * @version $Revision: 326110 $ $Date: 2005-10-18 09:08:36 -0500 (Tue, 18 Oct 2005) $
+ */
+public class SessionIDMessage implements ClusterMessage {
+
+	private org.apache.catalina.cluster.Member address;
+
+	private int messageNumber;
+
+	private long timestamp;
+
+	private String orignalSessionID;
+
+	private String backupSessionID;
+
+	private String host ;
+	private String contextPath;
+    private int resend = ClusterMessage.FLAG_DEFAULT ;
+    private int compress = ClusterMessage.FLAG_DEFAULT ;
+
+	public org.apache.catalina.cluster.Member getAddress() {
+		return address;
+	}
+
+	public void setAddress(org.apache.catalina.cluster.Member address) {
+		this.address = address;
+	}
+
+	public String getUniqueId() {
+		StringBuffer result = new StringBuffer(getOrignalSessionID());
+		result.append("#-#");
+		result.append(getHost());
+                result.append("#-#");
+                result.append(getContextPath());
+		result.append("#-#");
+		result.append(getMessageNumber());
+		result.append("#-#");
+		result.append(System.currentTimeMillis());
+		return result.toString();
+	}
+
+	/**
+         * @return Returns the host.
+         */
+        public String getHost() {
+             return host;
+        }
+    
+        /**
+         * @param host The host to set.
+         */
+         public void setHost(String host) {
+             this.host = host;
+        }
+    
+	/**
+	 * @return Returns the contextPath.
+	 */
+	public String getContextPath() {
+		return contextPath;
+	}
+	/**
+	 * @param contextPath The contextPath to set.
+	 */
+	public void setContextPath(String contextPath) {
+		this.contextPath = contextPath;
+	}
+	/**
+	 * @return Returns the messageNumber.
+	 */
+	public int getMessageNumber() {
+		return messageNumber;
+	}
+
+	/**
+	 * @param messageNumber
+	 *            The messageNumber to set.
+	 */
+	public void setMessageNumber(int messageNumber) {
+		this.messageNumber = messageNumber;
+	}
+
+	/**
+	 * @return Returns the timestamp.
+	 */
+	public long getTimestamp() {
+		return timestamp;
+	}
+
+	/**
+	 * @param timestamp
+	 *            The timestamp to set.
+	 */
+	public void setTimestamp(long timestamp) {
+		this.timestamp = timestamp;
+	}
+
+	/**
+	 * @return Returns the backupSessionID.
+	 */
+	public String getBackupSessionID() {
+		return backupSessionID;
+	}
+
+	/**
+	 * @param backupSessionID
+	 *            The backupSessionID to set.
+	 */
+	public void setBackupSessionID(String backupSessionID) {
+		this.backupSessionID = backupSessionID;
+	}
+
+	/**
+	 * @return Returns the orignalSessionID.
+	 */
+	public String getOrignalSessionID() {
+		return orignalSessionID;
+	}
+
+	/**
+	 * @param orignalSessionID
+	 *            The orignalSessionID to set.
+	 */
+	public void setOrignalSessionID(String orignalSessionID) {
+		this.orignalSessionID = orignalSessionID;
+	}
+
+    /**
+     * @return Returns the compress.
+     * @since 5.5.10 
+     */
+    public int getCompress() {
+        return compress;
+    }
+    /**
+     * @param compress The compress to set.
+     * @since 5.5.10
+     */
+    public void setCompress(int compress) {
+        this.compress = compress;
+    }
+    /**
+     * @return Returns the resend.
+     * @since 5.5.10
+     */
+    public int getResend() {
+        return resend;
+    }
+    /**
+     * @param resend The resend to set.
+     * @since 5.5.10
+     */
+    public void setResend(int resend) {
+        this.resend = resend;
+    }
+
+
+}
+

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/session/SessionMessage.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/session/SessionMessage.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/session/SessionMessage.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,103 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.cluster.session;
+import org.apache.catalina.cluster.ClusterMessage;
+
+/**
+ *
+ * <B>Class Description:</B><BR>
+ * The SessionMessage class is a class that is used when a session has been
+ * created, modified, expired in a Tomcat cluster node.<BR>
+ *
+ * The following events are currently available:
+ * <ul>
+ *   <li><pre>public static final int EVT_SESSION_CREATED</pre><li>
+ *   <li><pre>public static final int EVT_SESSION_ACCESSED</pre><li>
+ *   <li><pre>public static final int EVT_ATTRIBUTE_ADDED</pre><li>
+ *   <li><pre>public static final int EVT_ATTRIBUTE_REMOVED</pre><li>
+ *   <li><pre>public static final int EVT_SESSION_EXPIRED_WONOTIFY</pre><li>
+ *   <li><pre>public static final int EVT_SESSION_EXPIRED_WNOTIFY</pre><li>
+ *   <li><pre>public static final int EVT_GET_ALL_SESSIONS</pre><li>
+ *   <li><pre>public static final int EVT_SET_USER_PRINCIPAL</pre><li>
+ *   <li><pre>public static final int EVT_SET_SESSION_NOTE</pre><li>
+ *   <li><pre>public static final int EVT_REMOVE_SESSION_NOTE</pre><li>
+ * </ul>
+ *
+ */
+
+public interface SessionMessage extends ClusterMessage, java.io.Serializable
+{
+
+    /**
+     * Event type used when a session has been created on a node
+     */
+    public static final int EVT_SESSION_CREATED = 1;
+    /**
+     * Event type used when a session has expired
+     */
+    public static final int EVT_SESSION_EXPIRED = 2;
+
+    /**
+     * Event type used when a session has been accessed (ie, last access time
+     * has been updated. This is used so that the replicated sessions will not expire
+     * on the network
+     */
+    public static final int EVT_SESSION_ACCESSED = 3;
+    /**
+     * Event type used when a server comes online for the first time.
+     * The first thing the newly started server wants to do is to grab the
+     * all the sessions from one of the nodes and keep the same state in there
+     */
+    public static final int EVT_GET_ALL_SESSIONS = 4;
+    /**
+     * Event type used when an attribute has been added to a session,
+     * the attribute will be sent to all the other nodes in the cluster
+     */
+    public static final int EVT_SESSION_DELTA  = 13;
+
+    /**
+     * When a session state is transferred, this is the event.
+     */
+    public static final int EVT_ALL_SESSION_DATA = 12;
+    
+    /**
+     * When a session state is complete transferred, this is the event.
+     */
+    public static final int EVT_ALL_SESSION_TRANSFERCOMPLETE = 14;
+    
+
+    
+    public String getContextName();
+    
+    public String getEventTypeString();
+    
+    /**
+     * returns the event type
+     * @return one of the event types EVT_XXXX
+     */
+    public int getEventType(); 
+    /**
+     * @return the serialized data for the session
+     */
+    public byte[] getSession();
+    /**
+     * @return the session ID for the session
+     */
+    public String getSessionID();
+    
+
+
+}//SessionMessage

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/session/SessionMessageImpl.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/session/SessionMessageImpl.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/session/SessionMessageImpl.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,207 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.cluster.session;
+
+
+import org.apache.catalina.cluster.ClusterMessage;
+import org.apache.catalina.cluster.Member;
+
+/**
+ * Session cluster message
+ * 
+ * @author Filip Hanik
+ * @author Peter Rossbach
+ * 
+ * @version $Revision: 326110 $ $Date: 2005-10-18 09:08:36 -0500 (Tue, 18 Oct 2005) $
+ */
+public class SessionMessageImpl implements SessionMessage, java.io.Serializable {
+    
+    public SessionMessageImpl() {
+    }
+    
+    
+    /*
+
+     * Private serializable variables to keep the messages state
+     */
+    private int mEvtType = -1;
+    private byte[] mSession;
+    private String mSessionID;
+    private Member mSrc;
+    private String mContextName;
+    private long serializationTimestamp;
+    private boolean timestampSet = false ;
+    private String uniqueId;
+    private int resend = ClusterMessage.FLAG_DEFAULT ;
+    private int compress = ClusterMessage.FLAG_DEFAULT ;
+
+
+    private SessionMessageImpl( String contextName,
+                           int eventtype,
+                           byte[] session,
+                           String sessionID)
+    {
+        mEvtType = eventtype;
+        mSession = session;
+        mSessionID = sessionID;
+        mContextName = contextName;
+        uniqueId = sessionID;
+    }
+
+    /**
+     * Creates a session message. Depending on what event type you want this
+     * message to represent, you populate the different parameters in the constructor<BR>
+      * The following rules apply dependent on what event type argument you use:<BR>
+     * <B>EVT_SESSION_CREATED</B><BR>
+     *    The parameters: session, sessionID must be set.<BR>
+     * <B>EVT_SESSION_EXPIRED</B><BR>
+     *    The parameters: sessionID must be set.<BR>
+     * <B>EVT_SESSION_ACCESSED</B><BR>
+     *    The parameters: sessionID must be set.<BR>
+     * <B>EVT_SESSION_EXPIRED_XXXX</B><BR>
+     *    The parameters: sessionID must be set.<BR>
+     * <B>EVT_SESSION_DELTA</B><BR>
+     *    Send attribute delta (add,update,remove attribute or principal, ...).<BR>
+     * <B>EVT_ALL_SESSION_DATA</B><BR>
+     *    Send complete serializes session list<BR>
+     * <B>EVT_ALL_SESSION_TRANSFERCOMPLETE</B><BR>
+     *    send that all session state information are transfered
+     *    after GET_ALL_SESSION received from this sender.<BR>
+     * @param contextName - the name of the context (application
+     * @param eventtype - one of the 8 event type defined in this class
+     * @param session - the serialized byte array of the session itself
+     * @param sessionID - the id that identifies this session
+     * @param uniqueID - the id that identifies this message
+     */
+    public SessionMessageImpl( String contextName,
+                           int eventtype,
+                           byte[] session,
+                           String sessionID,
+                           String uniqueID)
+    {
+        this(contextName,eventtype,session,sessionID);
+        uniqueId = uniqueID;
+    }
+
+    /**
+     * returns the event type
+     * @return one of the event types EVT_XXXX
+     */
+    public int getEventType() { return mEvtType; }
+
+    /**
+     * @return the serialized data for the session
+     */
+    public byte[] getSession() { return mSession;}
+
+    /**
+     * @return the session ID for the session
+     */
+    public String getSessionID(){ return mSessionID; }
+    
+    /**
+     * set message send time but only the first setting works (one shot)
+     */
+    public void setTimestamp(long time) {
+        synchronized(this) {
+            if(!timestampSet) {
+                serializationTimestamp=time;
+                timestampSet = true ;
+            }
+        }
+    }
+    
+    public long getTimestamp() { return serializationTimestamp;}
+    
+    /**
+     * clear text event type name (for logging purpose only) 
+     * @return the event type in a string representating, useful for debugging
+     */
+    public String getEventTypeString()
+    {
+        switch (mEvtType)
+        {
+            case EVT_SESSION_CREATED : return "SESSION-MODIFIED";
+            case EVT_SESSION_EXPIRED : return "SESSION-EXPIRED";
+            case EVT_SESSION_ACCESSED : return "SESSION-ACCESSED";
+            case EVT_GET_ALL_SESSIONS : return "SESSION-GET-ALL";
+            case EVT_SESSION_DELTA : return "SESSION-DELTA";
+            case EVT_ALL_SESSION_DATA : return "ALL-SESSION-DATA";
+            case EVT_ALL_SESSION_TRANSFERCOMPLETE : return "SESSION-STATE-TRANSFERED";
+            default : return "UNKNOWN-EVENT-TYPE";
+        }
+    }
+
+    /**
+     * Get the address that this message originated from.  This would be set
+     * if the message was being relayed from a host other than the one
+     * that originally sent it.
+     */
+    public Member getAddress()
+    {
+        return this.mSrc;
+    }
+
+    /**
+     * Use this method to set the address that this message originated from.
+     * This can be used when re-sending the EVT_GET_ALL_SESSIONS message to
+     * another machine in the group.
+     */
+    public void setAddress(Member src)
+    {
+        this.mSrc = src;
+    }
+
+    public String getContextName() {
+       return mContextName;
+    }
+    public String getUniqueId() {
+        return uniqueId;
+    }
+    public void setUniqueId(String uniqueId) {
+        this.uniqueId = uniqueId;
+    }
+
+    /**
+     * @return Returns the compress.
+     * @since 5.5.10 
+     */
+    public int getCompress() {
+        return compress;
+    }
+    /**
+     * @param compress The compress to set.
+     * @since 5.5.10
+     */
+    public void setCompress(int compress) {
+        this.compress = compress;
+    }
+    /**
+     * @return Returns the resend.
+     * @since 5.5.10
+     */
+    public int getResend() {
+        return resend;
+    }
+    /**
+     * @param resend The resend to set.
+     * @since 5.5.10
+     */
+    public void setResend(int resend) {
+        this.resend = resend;
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/session/SimpleTcpReplicationManager.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/session/SimpleTcpReplicationManager.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/session/SimpleTcpReplicationManager.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,651 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.cluster.session;
+
+import java.io.IOException;
+
+import org.apache.catalina.LifecycleException;
+import org.apache.catalina.Session;
+import org.apache.catalina.cluster.CatalinaCluster;
+import org.apache.catalina.cluster.ClusterManager;
+import org.apache.catalina.cluster.ClusterMessage;
+import org.apache.catalina.cluster.Member;
+import org.apache.catalina.realm.GenericPrincipal;
+import org.apache.catalina.session.StandardManager;
+
+/**
+ * Title:        Tomcat Session Replication for Tomcat 4.0 <BR>
+ * Description:  A very simple straight forward implementation of
+ *               session replication of servers in a cluster.<BR>
+ *               This session replication is implemented "live". By live
+ *               I mean, when a session attribute is added into a session on Node A
+ *               a message is broadcasted to other messages and setAttribute is called on the
+ *               replicated sessions.<BR>
+ *               A full description of this implementation can be found under
+ *               <href="http://www.filip.net/tomcat/">Filip's Tomcat Page</a><BR>
+ *
+ * Copyright:    See apache license
+ * Company:      www.filip.net
+ * @author  <a href="mailto:mail at filip.net">Filip Hanik</a>
+ * @author Bela Ban (modifications for synchronous replication)
+ * @version 1.0 for TC 4.0
+ * Description: The InMemoryReplicationManager is a session manager that replicated
+ * session information in memory. It uses <a href="www.javagroups.com">JavaGroups</a> as
+ * a communication protocol to ensure guaranteed and ordered message delivery.
+ * JavaGroups also provides a very flexible protocol stack to ensure that the replication
+ * can be used in any environment.
+ * <BR><BR>
+ * The InMemoryReplicationManager extends the StandardManager hence it allows for us
+ * to inherit all the basic session management features like expiration, session listeners etc
+ * <BR><BR>
+ * To communicate with other nodes in the cluster, the InMemoryReplicationManager sends out 7 different type of multicast messages
+ * all defined in the SessionMessage class.<BR>
+ * When a session is replicated (not an attribute added/removed) the session is serialized into
+ * a byte array using the StandardSession.readObjectData, StandardSession.writeObjectData methods.
+ */
+public class SimpleTcpReplicationManager extends StandardManager
+implements ClusterManager
+{
+    public static org.apache.commons.logging.Log log =
+        org.apache.commons.logging.LogFactory.getLog( SimpleTcpReplicationManager.class );
+
+    //the channel configuration
+    protected String mChannelConfig = null;
+
+    //the group name
+    protected String mGroupName = "TomcatReplication";
+
+    //somehow start() gets called more than once
+    protected boolean mChannelStarted = false;
+
+    //log to screen
+    protected boolean mPrintToScreen = true;
+
+    protected boolean defaultMode = false;
+
+    protected boolean mManagerRunning = false;
+
+    /** Use synchronous rather than asynchronous replication. Every session modification (creation, change, removal etc)
+     * will be sent to all members. The call will then wait for max milliseconds, or forever (if timeout is 0) for
+     * all responses.
+     */
+    protected boolean synchronousReplication=true;
+
+    /** Set to true if we don't want the sessions to expire on shutdown */
+    protected boolean mExpireSessionsOnShutdown = true;
+
+    protected boolean useDirtyFlag = false;
+
+    protected String name;
+
+    protected boolean distributable = true;
+
+    protected CatalinaCluster cluster;
+
+    protected java.util.HashMap invalidatedSessions = new java.util.HashMap();
+
+    /**
+     * Flag to keep track if the state has been transferred or not
+     * Assumes false.
+     */
+    protected boolean stateTransferred = false;
+    private boolean notifyListenersOnReplication;
+    private boolean sendClusterDomainOnly = true ;
+
+    /**
+     * Constructor, just calls super()
+     *
+     */
+    public SimpleTcpReplicationManager()
+    {
+        super();
+    }
+
+    public boolean isSendClusterDomainOnly() {
+        return sendClusterDomainOnly;
+    }
+    
+    /**
+     * @param sendClusterDomainOnly The sendClusterDomainOnly to set.
+     */
+    public void setSendClusterDomainOnly(boolean sendClusterDomainOnly) {
+        this.sendClusterDomainOnly = sendClusterDomainOnly;
+    }
+  
+    /**
+     * @return Returns the defaultMode.
+     */
+    public boolean isDefaultMode() {
+        return defaultMode;
+    }
+    /**
+     * @param defaultMode The defaultMode to set.
+     */
+    public void setDefaultMode(boolean defaultMode) {
+        this.defaultMode = defaultMode;
+    }
+    
+    public boolean isManagerRunning()
+    {
+        return mManagerRunning;
+    }
+
+    public void setUseDirtyFlag(boolean usedirtyflag)
+    {
+        this.useDirtyFlag = usedirtyflag;
+    }
+
+    public void setExpireSessionsOnShutdown(boolean expireSessionsOnShutdown)
+    {
+        mExpireSessionsOnShutdown = expireSessionsOnShutdown;
+    }
+
+    public void setCluster(CatalinaCluster cluster) {
+        if(log.isDebugEnabled())
+            log.debug("Cluster associated with SimpleTcpReplicationManager");
+        this.cluster = cluster;
+    }
+
+    public boolean getExpireSessionsOnShutdown()
+    {
+        return mExpireSessionsOnShutdown;
+    }
+
+    public void setPrintToScreen(boolean printtoscreen)
+    {
+        if(log.isDebugEnabled())
+            log.debug("Setting screen debug to:"+printtoscreen);
+        mPrintToScreen = printtoscreen;
+    }
+
+    public void setSynchronousReplication(boolean flag)
+    {
+        synchronousReplication=flag;
+    }
+
+    /**
+     * Override persistence since they don't go hand in hand with replication for now.
+     */
+    public void unload() throws IOException {
+        if ( !getDistributable() ) {
+            super.unload();
+        }
+    }
+
+    /**
+     * Creates a HTTP session.
+     * Most of the code in here is copied from the StandardManager.
+     * This is not pretty, yeah I know, but it was necessary since the
+     * StandardManager had hard coded the session instantiation to the a
+     * StandardSession, when we actually want to instantiate a ReplicatedSession<BR>
+     * If the call comes from the Tomcat servlet engine, a SessionMessage goes out to the other
+     * nodes in the cluster that this session has been created.
+     * @param notify - if set to true the other nodes in the cluster will be notified.
+     *                 This flag is needed so that we can create a session before we deserialize
+     *                 a replicated one
+     *
+     * @see ReplicatedSession
+     */
+    protected Session createSession(String sessionId, boolean notify, boolean setId)
+    {
+
+        //inherited from the basic manager
+        if ((getMaxActiveSessions() >= 0) &&
+           (sessions.size() >= getMaxActiveSessions()))
+            throw new IllegalStateException(sm.getString("standardManager.createSession.ise"));
+
+
+        Session session = new ReplicatedSession(this);
+
+        // Initialize the properties of the new session and return it
+        session.setNew(true);
+        session.setValid(true);
+        session.setCreationTime(System.currentTimeMillis());
+        session.setMaxInactiveInterval(this.maxInactiveInterval);
+        if(sessionId == null)
+            sessionId = generateSessionId();
+        if ( setId ) session.setId(sessionId);
+        if ( notify && (cluster!=null) ) {
+            ((ReplicatedSession)session).setIsDirty(true);
+        }
+        return (session);
+    }//createSession
+
+    //=========================================================================
+    // OVERRIDE THESE METHODS TO IMPLEMENT THE REPLICATION
+    //=========================================================================
+
+    /**
+     * Construct and return a new session object, based on the default
+     * settings specified by this Manager's properties.  The session
+     * id will be assigned by this method, and available via the getId()
+     * method of the returned session.  If a new session cannot be created
+     * for any reason, return <code>null</code>.
+     *
+     * @exception IllegalStateException if a new session cannot be
+     *  instantiated for any reason
+     */
+    public Session createSession(String sessionId)
+    {
+        //create a session and notify the other nodes in the cluster
+        Session session =  createSession(sessionId,getDistributable(),true);
+        add(session);
+        return session;
+    }
+
+    public void sessionInvalidated(String sessionId) {
+        synchronized ( invalidatedSessions ) {
+            invalidatedSessions.put(sessionId, sessionId);
+        }
+    }
+
+    public String[] getInvalidatedSessions() {
+        synchronized ( invalidatedSessions ) {
+            String[] result = new String[invalidatedSessions.size()];
+            invalidatedSessions.values().toArray(result);
+            return result;
+        }
+
+    }
+
+    public ClusterMessage requestCompleted(String sessionId)
+    {
+        if (  !getDistributable() ) {
+            log.warn("Received requestCompleted message, although this context["+
+                     getName()+"] is not distributable. Ignoring message");
+            return null;
+        }
+        //notify javagroups
+        try
+        {
+            if ( invalidatedSessions.get(sessionId) != null ) {
+                synchronized ( invalidatedSessions ) {
+                    invalidatedSessions.remove(sessionId);
+                    SessionMessage msg = new SessionMessageImpl(name,
+                    SessionMessage.EVT_SESSION_EXPIRED,
+                    null,
+                    sessionId,
+                    sessionId);
+                return msg;
+                }
+            } else {
+                ReplicatedSession session = (ReplicatedSession) findSession(
+                    sessionId);
+                if (session != null) {
+                    //return immediately if the session is not dirty
+                    if (useDirtyFlag && (!session.isDirty())) {
+                        //but before we return doing nothing,
+                        //see if we should send
+                        //an updated last access message so that
+                        //sessions across cluster dont expire
+                        long interval = session.getMaxInactiveInterval();
+                        long lastaccdist = System.currentTimeMillis() -
+                            session.getLastAccessWasDistributed();
+                        if ( interval*1000 < 3 * lastaccdist ) {
+                            SessionMessage accmsg = new SessionMessageImpl(name,
+                                SessionMessage.EVT_SESSION_ACCESSED,
+                                null,
+                                sessionId,
+                                sessionId);
+                            session.setLastAccessWasDistributed(System.currentTimeMillis());
+                            return accmsg;
+                        }
+                        return null;
+                    }
+
+                    session.setIsDirty(false);
+                    if (log.isDebugEnabled()) {
+                        try {
+                            log.debug("Sending session to cluster=" + session);
+                        }
+                        catch (Exception ignore) {}
+                    }
+                    SessionMessage msg = new SessionMessageImpl(name,
+                        SessionMessage.EVT_SESSION_CREATED,
+                        writeSession(session),
+                        session.getIdInternal(),
+                        session.getIdInternal());
+                    return msg;
+                } //end if
+            }//end if
+        }
+        catch (Exception x )
+        {
+            log.error("Unable to replicate session",x);
+        }
+        return null;
+    }
+
+    /**
+     * Serialize a session into a byte array<BR>
+     * This method simple calls the writeObjectData method on the session
+     * and returns the byte data from that call
+     * @param session - the session to be serialized
+     * @return a byte array containing the session data, null if the serialization failed
+     */
+    protected byte[] writeSession( Session session )
+    {
+        try
+        {
+            java.io.ByteArrayOutputStream session_data = new java.io.ByteArrayOutputStream();
+            java.io.ObjectOutputStream session_out = new java.io.ObjectOutputStream(session_data);
+            session_out.flush();
+            boolean hasPrincipal = session.getPrincipal() != null;
+            session_out.writeBoolean(hasPrincipal);
+            if ( hasPrincipal )
+            {
+                session_out.writeObject(SerializablePrincipal.createPrincipal((GenericPrincipal)session.getPrincipal()));
+            }//end if
+            ((ReplicatedSession)session).writeObjectData(session_out);
+            return session_data.toByteArray();
+
+        }
+        catch ( Exception x )
+        {
+            log.error("Failed to serialize the session!",x);
+        }
+        return null;
+    }
+
+    /**
+     * Reinstantiates a serialized session from the data passed in.
+     * This will first call createSession() so that we get a fresh instance with all
+     * the managers set and all the transient fields validated.
+     * Then it calls Session.readObjectData(byte[]) to deserialize the object
+     * @param data - a byte array containing session data
+     * @return a valid Session object, null if an error occurs
+     *
+     */
+    protected Session readSession( byte[] data, String sessionId )
+    {
+        try
+        {
+            java.io.ByteArrayInputStream session_data = new java.io.ByteArrayInputStream(data);
+            ReplicationStream session_in = new ReplicationStream(session_data,container.getLoader().getClassLoader());
+
+            Session session = sessionId!=null?this.findSession(sessionId):null;
+            boolean isNew = (session==null);
+            //clear the old values from the existing session
+            if ( session!=null ) {
+                ReplicatedSession rs = (ReplicatedSession)session;
+                rs.expire(false);  //cleans up the previous values, since we are not doing removes
+                session = null;
+            }//end if
+
+            if (session==null) {
+                session = createSession(null,false, false);
+                sessions.remove(session.getIdInternal());
+            }
+            
+            
+            boolean hasPrincipal = session_in.readBoolean();
+            SerializablePrincipal p = null;
+            if ( hasPrincipal )
+                p = (SerializablePrincipal)session_in.readObject();
+            ((ReplicatedSession)session).readObjectData(session_in);
+            if ( hasPrincipal )
+                session.setPrincipal(p.getPrincipal(getContainer().getRealm()));
+            ((ReplicatedSession)session).setId(sessionId,isNew);
+            ReplicatedSession rsession = (ReplicatedSession)session; 
+            rsession.setAccessCount(1);
+            session.setManager(this);
+            session.setValid(true);
+            rsession.setLastAccessedTime(System.currentTimeMillis());
+            rsession.setThisAccessedTime(System.currentTimeMillis());
+            ((ReplicatedSession)session).setAccessCount(0);
+            session.setNew(false);
+            if(log.isTraceEnabled())
+                 log.trace("Session loaded id="+sessionId +
+                               " actualId="+session.getId()+ 
+                               " exists="+this.sessions.containsKey(sessionId)+
+                               " valid="+rsession.isValid());
+            return session;
+
+        }
+        catch ( Exception x )
+        {
+            log.error("Failed to deserialize the session!",x);
+        }
+        return null;
+    }
+
+    public String getName() {
+        return this.name;
+    }
+    /**
+     * Prepare for the beginning of active use of the public methods of this
+     * component.  This method should be called after <code>configure()</code>,
+     * and before any of the public methods of the component are utilized.<BR>
+     * Starts the cluster communication channel, this will connect with the other nodes
+     * in the cluster, and request the current session state to be transferred to this node.
+     * @exception IllegalStateException if this component has already been
+     *  started
+     * @exception LifecycleException if this component detects a fatal error
+     *  that prevents this component from being used
+     */
+    public void start() throws LifecycleException {
+        mManagerRunning = true;
+        super.start();
+        //start the javagroups channel
+        try {
+            //the channel is already running
+            if ( mChannelStarted ) return;
+            if(log.isInfoEnabled())
+                log.info("Starting clustering manager...:"+getName());
+            if ( cluster == null ) {
+                log.error("Starting... no cluster associated with this context:"+getName());
+                return;
+            }
+            cluster.addManager(getName(),this);
+
+            if (cluster.getMembers().length > 0) {
+                Member mbr = cluster.getMembers()[0];
+                SessionMessage msg =
+                    new SessionMessageImpl(this.getName(),
+                                       SessionMessage.EVT_GET_ALL_SESSIONS,
+                                       null,
+                                       "GET-ALL",
+                                       "GET-ALL-"+this.getName());
+                cluster.send(msg, mbr);
+                if(log.isWarnEnabled())
+                     log.warn("Manager["+getName()+"], requesting session state from "+mbr+
+                         ". This operation will timeout if no session state has been received within "+
+                         "60 seconds");
+                long reqStart = System.currentTimeMillis();
+                long reqNow = 0;
+                boolean isTimeout=false;
+                do {
+                    try {
+                        Thread.sleep(100);
+                    }catch ( Exception sleep) {}
+                    reqNow = System.currentTimeMillis();
+                    isTimeout=((reqNow-reqStart)>(1000*60));
+                } while ( (!isStateTransferred()) && (!isTimeout));
+                if ( isTimeout || (!isStateTransferred()) ) {
+                    log.error("Manager["+getName()+"], No session state received, timing out.");
+                }else {
+                    if(log.isInfoEnabled())
+                        log.info("Manager["+getName()+"], session state received in "+(reqNow-reqStart)+" ms.");
+                }
+            } else {
+                if(log.isInfoEnabled())
+                    log.info("Manager["+getName()+"], skipping state transfer. No members active in cluster group.");
+            }//end if
+            mChannelStarted = true;
+        }  catch ( Exception x ) {
+            log.error("Unable to start SimpleTcpReplicationManager",x);
+        }
+    }
+
+    /**
+     * Gracefully terminate the active use of the public methods of this
+     * component.  This method should be the last one called on a given
+     * instance of this component.<BR>
+     * This will disconnect the cluster communication channel and stop the listener thread.
+     * @exception IllegalStateException if this component has not been started
+     * @exception LifecycleException if this component detects a fatal error
+     *  that needs to be reported
+     */
+    public void stop() throws LifecycleException
+    {
+        mManagerRunning = false;
+        mChannelStarted = false;
+        super.stop();
+        //stop the javagroup channel
+        try
+        {
+            this.sessions.clear();
+            cluster.removeManager(getName(),this);
+//            mReplicationListener.stopListening();
+//            mReplicationTransmitter.stop();
+//            service.stop();
+//            service = null;
+        }
+        catch ( Exception x )
+        {
+            log.error("Unable to stop SimpleTcpReplicationManager",x);
+        }
+    }
+
+    public void setDistributable(boolean dist) {
+        this.distributable = dist;
+    }
+
+    public boolean getDistributable() {
+        return distributable;
+    }
+
+    /**
+     * This method is called by the received thread when a SessionMessage has
+     * been received from one of the other nodes in the cluster.
+     * @param msg - the message received
+     * @param sender - the sender of the message, this is used if we receive a
+     *                 EVT_GET_ALL_SESSION message, so that we only reply to
+     *                 the requesting node
+     */
+    protected void messageReceived( SessionMessage msg, Member sender ) {
+        try  {
+            if(log.isInfoEnabled()) {
+                log.debug("Received SessionMessage of type="+msg.getEventTypeString());
+                log.debug("Received SessionMessage sender="+sender);
+            }
+            switch ( msg.getEventType() ) {
+                case SessionMessage.EVT_GET_ALL_SESSIONS: {
+                    //get a list of all the session from this manager
+                    Object[] sessions = findSessions();
+                    java.io.ByteArrayOutputStream bout = new java.io.ByteArrayOutputStream();
+                    java.io.ObjectOutputStream oout = new java.io.ObjectOutputStream(bout);
+                    oout.writeInt(sessions.length);
+                    for (int i=0; i<sessions.length; i++){
+                        ReplicatedSession ses = (ReplicatedSession)sessions[i];
+                        oout.writeUTF(ses.getIdInternal());
+                        byte[] data = writeSession(ses);
+                        oout.writeObject(data);
+                    }//for
+                    //don't send a message if we don't have to
+                    oout.flush();
+                    oout.close();
+                    byte[] data = bout.toByteArray();
+                    SessionMessage newmsg = new SessionMessageImpl(name,
+                        SessionMessage.EVT_ALL_SESSION_DATA,
+                        data, "SESSION-STATE","SESSION-STATE-"+getName());
+                    cluster.send(newmsg, sender);
+                    break;
+                }
+                case SessionMessage.EVT_ALL_SESSION_DATA: {
+                    java.io.ByteArrayInputStream bin =
+                        new java.io.ByteArrayInputStream(msg.getSession());
+                    java.io.ObjectInputStream oin = new java.io.ObjectInputStream(bin);
+                    int size = oin.readInt();
+                    for ( int i=0; i<size; i++) {
+                        String id = oin.readUTF();
+                        byte[] data = (byte[])oin.readObject();
+                        Session session = readSession(data,id);
+                    }//for
+                    stateTransferred=true;
+                    break;
+                }
+                case SessionMessage.EVT_SESSION_CREATED: {
+                    Session session = this.readSession(msg.getSession(),msg.getSessionID());
+                    if ( log.isDebugEnabled() ) {
+                        log.debug("Received replicated session=" + session +
+                            " isValid=" + session.isValid());
+                    }
+                    break;
+                }
+                case SessionMessage.EVT_SESSION_EXPIRED: {
+                    Session session = findSession(msg.getSessionID());
+                    if ( session != null ) {
+                        session.expire();
+                        this.remove(session);
+                    }//end if
+                    break;
+                }
+                case SessionMessage.EVT_SESSION_ACCESSED :{
+                    Session session = findSession(msg.getSessionID());
+                    if ( session != null ) {
+                        session.access();
+                        session.endAccess();
+                    }
+                    break;
+                }
+                default:  {
+                    //we didn't recognize the message type, do nothing
+                    break;
+                }
+            }//switch
+        }
+        catch ( Exception x )
+        {
+            log.error("Unable to receive message through TCP channel",x);
+        }
+    }
+
+    public void messageDataReceived(ClusterMessage cmsg) {
+        try {
+            if ( cmsg instanceof SessionMessage ) {
+                SessionMessage msg = (SessionMessage)cmsg;
+                messageReceived(msg,
+                                msg.getAddress() != null ? (Member) msg.getAddress() : null);
+            }
+        } catch(Throwable ex){
+            log.error("InMemoryReplicationManager.messageDataReceived()", ex);
+        }//catch
+    }
+
+    public boolean isStateTransferred() {
+        return stateTransferred;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+    public boolean isNotifyListenersOnReplication() {
+        return notifyListenersOnReplication;
+    }
+    public void setNotifyListenersOnReplication(boolean notifyListenersOnReplication) {
+        this.notifyListenersOnReplication = notifyListenersOnReplication;
+    }
+
+
+    /* 
+     * @see org.apache.catalina.cluster.ClusterManager#getCluster()
+     */
+    public CatalinaCluster getCluster() {
+        return cluster;
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/session/mbeans-descriptors.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/session/mbeans-descriptors.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/session/mbeans-descriptors.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,320 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mbeans-descriptors PUBLIC
+   "-//Apache Software Foundation//DTD Model MBeans Configuration File"
+   "http://jakarta.apache.org/commons/dtds/mbeans-descriptors.dtd">
+<mbeans-descriptors>
+    <mbean name="JvmRouteBinderValve" description="mod_jk jvmRoute jsessionid cookie backup correction" domain="Catalina"
+        group="Valve" type="org.apache.catalina.cluster.session.JvmRouteBinderValve">
+        <attribute name="className"
+               description="Fully qualified class name of the managed object"
+               type="java.lang.String"
+               writeable="false"/>        
+        <attribute name="info" 
+		           description="describe version" type="java.lang.String" writeable="false"/>
+        <attribute name="enabled" 
+		           description="enable a jvm Route check" type="boolean"/>
+        <attribute name="numberOfSessions"
+		           description="number of jvmRoute session corrections" type="long" writeable="false"/>
+        <attribute name="sessionIdAttribute" 
+		    description="Name of attribute with sessionid value before turnover a session" 
+		    type="java.lang.String" 
+		    />
+        <operation name="start" description="Stops the Cluster JvmRouteBinderValve" 
+		           impact="ACTION" returnType="void"/>
+        <operation name="stop" description="Stops the Cluster JvmRouteBinderValve" 
+		           impact="ACTION" returnType="void"/>
+    </mbean>
+	<mbean name="JvmRouteSessionIDBinderListener"
+		description="Monitors the jvmRoute activity"
+		domain="Catalina"
+        group="Listener"
+		type="org.apache.catalina.cluster.session.JvmRouteSessionIDBinderListener">
+        <attribute name="info" 
+		           description="describe version" type="java.lang.String" writeable="false"/>
+        <attribute name="numberOfSessions" 
+		    description="number of jvmRoute session corrections" 
+		    type="long" 
+		    writeable="false"/>
+    </mbean>
+    
+   <mbean        name="DeltaManager"
+          description="Cluster Manager implementation of the Manager interface"
+               domain="Catalina"
+                group="Manager"
+                 type="org.apache.catalina.cluster.session.DeltaManager">
+
+    <attribute   name="info" 
+		  description="describe version"
+		         type="java.lang.String"
+		    writeable="false"/>
+		    
+    <attribute   name="algorithm"
+          description="The message digest algorithm to be used when generating
+                       session identifiers"
+                 type="java.lang.String"/>
+                 
+    <attribute   name="randomFile"
+          description="File source of random - /dev/urandom or a pipe"
+                 type="java.lang.String"/>
+
+    <attribute   name="className"
+          description="Fully qualified class name of the managed object"
+                 type="java.lang.String"
+            writeable="false"/>
+
+    <attribute   name="distributable"
+          description="The distributable flag for Sessions created by this
+                       Manager"
+                 type="boolean"/>
+
+    <attribute   name="entropy"
+          description="A String initialization parameter used to increase the
+                       entropy of the initialization of our random number
+                       generator"
+                 type="java.lang.String"/>
+
+    <attribute   name="maxActiveSessions"
+          description="The maximum number of active Sessions allowed, or -1
+                       for no limit"
+                 type="int"/>
+
+    <attribute   name="maxInactiveInterval"
+          description="The default maximum inactive interval for Sessions
+                       created by this Manager"
+                 type="int"/>
+
+    <attribute name="processExpiresFrequency"
+               description="The frequency of the manager checks (expiration and passivation)"
+               type="int"/>
+               
+    <attribute   name="sessionIdLength"
+          description="The session id length (in bytes) of Sessions
+                       created by this Manager"
+                 type="int"/>
+
+    <attribute   name="name"
+          description="The descriptive name of this Manager implementation
+                       (for logging)"
+                 type="java.lang.String"
+            writeable="false"/>
+
+    <attribute   name="activeSessions"
+          description="Number of active sessions at this moment"
+                 type="int" 
+            writeable="false"/>
+
+    <attribute   name="sessionCounter"
+          description="Total number of sessions created by this manager"
+                 type="int" />
+
+    <attribute   name="sessionReplaceCounter"
+          description="Total number of replaced sessions that load from external nodes"
+                 type="long" />
+
+    <attribute   name="maxActive"
+          description="Maximum number of active sessions so far"
+                 type="int" />
+
+    <attribute   name="sessionMaxAliveTime"
+          description="Longest time an expired session had been alive"
+                 type="int" />
+
+    <attribute   name="sessionAverageAliveTime"
+          description="Average time an expired session had been alive"
+                 type="int" />
+
+    <attribute   name="sendClusterDomainOnly"
+                   is="true"
+          description="The sendClusterDomainOnly flag send sessions only to members as same cluster domain"
+                 type="boolean"/>
+
+    <attribute   name="rejectedSessions"
+          description="Number of sessions we rejected due to maxActive beeing reached"
+                 type="int" />
+
+    <attribute   name="expiredSessions"
+          description="Number of sessions that expired ( doesn't include explicit invalidations )"
+                 type="int" />
+
+    <attribute   name="stateTransferTimeout"
+          description="state transfer timeout in sec"
+                 type="int"/>
+
+    <attribute   name="processingTime"
+          description="Time spent doing housekeeping and expiration"
+                 type="long" />
+
+    <attribute   name="duplicates"
+          description="Number of duplicated session ids generated"
+                 type="int" />
+
+    <attribute   name="counterReceive_EVT_GET_ALL_SESSIONS"
+          description="Count receive EVT_GET_ALL_SESSIONS messages"
+                 type="long"
+            writeable="false" />
+
+    <attribute   name="counterReceive_EVT_ALL_SESSION_DATA"
+          description="Count receive EVT_ALL_SESSION_DATA messages"
+                 type="long"
+            writeable="false" />
+
+    <attribute   name="counterReceive_EVT_SESSION_CREATED"
+          description="Count receive EVT_SESSION_CREATED messages"
+                 type="long"
+            writeable="false" />
+
+    <attribute   name="counterReceive_EVT_SESSION_DELTA"
+          description="Count receive EVT_SESSION_DELTA messages"
+                 type="long"
+            writeable="false" />
+
+    <attribute   name="counterReceive_EVT_SESSION_ACCESSED"
+          description="Count receive EVT_SESSION_ACCESSED messages"
+                 type="long"
+            writeable="false" />
+
+    <attribute   name="counterReceive_EVT_SESSION_EXPIRED"
+          description="Count receive EVT_SESSION_EXPIRED messages"
+                 type="long"
+            writeable="false" />
+
+    <attribute   name="counterReceive_EVT_ALL_SESSION_TRANSFERCOMPLETE"
+          description="Count receive EVT_ALL_SESSION_TRANSFERCOMPLETE messages"
+                 type="long"
+            writeable="false" />
+
+    <attribute   name="counterSend_EVT_GET_ALL_SESSIONS"
+          description="Count send EVT_GET_ALL_SESSIONS messages"
+                 type="long"
+            writeable="false" />
+
+    <attribute   name="counterSend_EVT_ALL_SESSION_DATA"
+          description="Count send EVT_ALL_SESSION_DATA messages"
+                 type="long"
+            writeable="false" />
+
+    <attribute   name="counterSend_EVT_SESSION_CREATED"
+          description="Count send EVT_SESSION_CREATED messages"
+                 type="long"
+            writeable="false" />
+
+    <attribute   name="counterSend_EVT_SESSION_DELTA"
+          description="Count send EVT_SESSION_DELTA messages"
+                 type="long"
+            writeable="false" />
+
+    <attribute   name="counterSend_EVT_SESSION_ACCESSED"
+          description="Count send EVT_SESSION_ACCESSED messages"
+                 type="long"
+            writeable="false" />
+
+    <attribute   name="counterSend_EVT_SESSION_EXPIRED"
+          description="Count send EVT_SESSION_EXPIRED messages"
+                 type="long"
+            writeable="false" />
+
+    <attribute   name="counterSend_EVT_ALL_SESSION_TRANSFERCOMPLETE"
+          description="Count send EVT_ALL_SESSION_TRANSFERCOMPLETE messages"
+                 type="long"
+            writeable="false" />
+
+    <attribute   name="counterNoStateTransfered"
+          description="Count the failed session transfers noStateTransfered"
+                 type="int"
+            writeable="false" />
+            
+    <attribute   name="receivedQueueSize"
+          description="length of receive queue size when session received from other node"
+                 type="int"
+            writeable="false" />            
+
+    <attribute   name="expireSessionsOnShutdown"
+                   is="true"
+          description="exipre all sessions cluster wide as one node goes down"
+                 type="boolean" />
+
+    <attribute   name="notifyListenersOnReplication"
+                   is="true"
+          description="Send session attribute change events on backup nodes"
+                 type="boolean" />
+
+    <attribute   name="notifySessionListenersOnReplication"
+                   is="true"
+          description="Send session start/stop events on backup nodes"
+                 type="boolean" />
+
+    <attribute   name="sendAllSessions"
+                   is="true"
+          description="Send all sessions at one big block"
+                 type="boolean" />
+
+    <attribute   name="sendAllSessionsSize"
+          description="session block size when sendAllSessions=false (default=1000)"
+                 type="int" />
+
+    <attribute   name="sendAllSessionsWaitTime"
+          description="wait time between send session block (default 2 sec)"
+                 type="int" />
+
+    <operation   name="listSessionIds"
+          description="Return the list of active session ids"
+               impact="ACTION"
+           returnType="java.lang.String">
+    </operation>
+
+    <operation   name="getSessionAttribute"
+          description="Return a session attribute"
+               impact="ACTION"
+           returnType="java.lang.String">
+      <parameter name="sessionId"
+          description="Id of the session"
+                 type="java.lang.String"/>
+      <parameter name="key"
+          description="key of the attribute"
+                 type="java.lang.String"/>
+    </operation>
+
+    <operation   name="expireSession"
+          description="Expire a session"
+               impact="ACTION"
+           returnType="void">
+      <parameter name="sessionId"
+          description="Id of the session"
+                 type="java.lang.String"/>
+    </operation>
+
+    <operation   name="getLastAccessedTime"
+          description="Get the last access time"
+               impact="ACTION"
+           returnType="java.lang.String">
+      <parameter name="sessionId"
+          description="Id of the session"
+                 type="java.lang.String"/>
+    </operation>
+    
+	<operation name="expireAllLocalSessions"
+               description="Exipre all active local sessions and replicate the invalid sessions"
+               impact="ACTION"
+               returnType="void">
+    </operation>
+
+	<operation name="processExpires"
+               description="force process to expire sessions"
+               impact="ACTION"
+               returnType="void">
+    </operation>
+    
+	<operation name="resetStatistics"
+               description="Reset all statistics"
+               impact="ACTION"
+               returnType="void">
+    </operation>
+	<operation name="getAllClusterSessions"
+               description="send to oldest cluster member that this node need all cluster sessions (resync member)"
+               impact="ACTION"
+               returnType="void">
+    </operation>
+
+  </mbean>
+
+</mbeans-descriptors>

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/tcp/AsyncSocketSender.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/tcp/AsyncSocketSender.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/tcp/AsyncSocketSender.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,282 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.cluster.tcp;
+
+import java.net.InetAddress;
+
+import org.apache.catalina.cluster.util.SmartQueue;
+
+/**
+ * Send cluster messages from a Message queue with only one socket. Ack and keep
+ * Alive Handling is supported.
+ * <ul>
+ * <li>With autoConnect=false at ReplicationTransmitter, you can disconnect the
+ * sender and all messages are queued. Only use this for small maintaince
+ * isuses!</li>
+ * <li>waitForAck=true, means that receiver ack the transfer</li>
+ * <li>after one minute idle time, or number of request (100) the connection is
+ * reconnected with next request. Change this for production use!</li>
+ * <li>default ackTimeout is 15 sec: this is very low for big all session replication messages after restart a node</li>
+ * <li>disable keepAlive: keepAliveTimeout="-1" and keepAliveMaxRequestCount="-1"</li>
+ * </ul>
+ * 
+ * @author Filip Hanik
+ * @author Peter Rossbach
+ * @version $Revision: 366253 $ $Date: 2006-01-05 13:30:42 -0600 (Thu, 05 Jan 2006) $
+ */
+public class AsyncSocketSender extends DataSender {
+    
+    private static int threadCounter = 1;
+
+    private static org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory
+            .getLog(AsyncSocketSender.class);
+
+    /**
+     * The descriptive information about this implementation.
+     */
+    private static final String info = "AsyncSocketSender/2.0";
+
+    // ----------------------------------------------------- Instance Variables
+
+    /**
+     * Message Queue
+     */
+    private SmartQueue queue = new SmartQueue();
+
+    /**
+     * Active thread to push messages asynchronous to the other replication node
+     */
+    private QueueThread queueThread = null;
+
+    /**
+     * Count number of queue message
+     */
+    private long inQueueCounter = 0;
+
+    /**
+     * Count all successfull push messages from queue
+     */
+    private long outQueueCounter = 0;
+
+    // ------------------------------------------------------------- Constructor
+
+    /**
+     * start background thread to push incomming cluster messages to replication
+     * node
+     * 
+     * @param domain replication cluster domain (session domain)
+     * @param host replication node tcp address
+     * @param port replication node tcp port
+     */
+    public AsyncSocketSender(String domain,InetAddress host, int port) {
+        super(domain,host, port);
+        checkThread();
+    }
+
+    // ------------------------------------------------------------- Properties
+
+    /**
+     * Return descriptive information about this implementation and the
+     * corresponding version number, in the format
+     * <code>&lt;description&gt;/&lt;version&gt;</code>.
+     */
+    public String getInfo() {
+
+        return (info);
+
+    }
+
+    /**
+     * @return Returns the inQueueCounter.
+     */
+    public long getInQueueCounter() {
+        return inQueueCounter;
+    }
+
+    /**
+     * @return Returns the outQueueCounter.
+     */
+    public long getOutQueueCounter() {
+        return outQueueCounter;
+    }
+
+    /**
+     * @return Returns the queueSize.
+     */
+    public int getQueueSize() {
+        return queue.size();
+    }
+
+    /**
+     * @return Returns the queuedNrOfBytes.
+     */
+    public long getQueuedNrOfBytes() {
+        if(queueThread != null)
+            return queueThread.getQueuedNrOfBytes();
+        return 0l ;
+    }
+
+    // --------------------------------------------------------- Public Methods
+
+    /*
+     * Connect to socket and start background thread to ppush queued messages
+     * 
+     * @see org.apache.catalina.cluster.tcp.IDataSender#connect()
+     */
+    public void connect() throws java.io.IOException {
+        super.connect();
+        checkThread();
+    }
+
+    /**
+     * Disconnect socket ad stop queue thread
+     * 
+     * @see org.apache.catalina.cluster.tcp.IDataSender#disconnect()
+     */
+    public void disconnect() {
+        stopThread();
+        super.disconnect();
+    }
+
+    /**
+     * Send message to queue for later sending
+     * 
+     * @see org.apache.catalina.cluster.tcp.DataSender#pushMessage(ClusterData)
+     */
+    public void sendMessage(ClusterData data)
+            throws java.io.IOException {
+        SmartQueue.SmartEntry entry = new SmartQueue.SmartEntry(data.getUniqueId(), data);
+        queue.add(entry);
+        synchronized (this) {
+            inQueueCounter++;
+            if(queueThread != null)
+                queueThread.incQueuedNrOfBytes(data.getMessage().length);
+       }
+        if (log.isTraceEnabled())
+            log.trace(sm.getString("AsyncSocketSender.queue.message",
+                    getAddress().getHostAddress(), new Integer(getPort()), data.getUniqueId(), new Long(
+                            data.getMessage().length)));
+    }
+
+    /*
+     * Reset sender statistics
+     */
+    public synchronized void resetStatistics() {
+        super.resetStatistics();
+        inQueueCounter = queue.size();
+        outQueueCounter = 0;
+
+    }
+
+    /**
+     * Name of this SockerSender
+     */
+    public String toString() {
+        StringBuffer buf = new StringBuffer("AsyncSocketSender[");
+        buf.append(getAddress().getHostAddress()).append(":").append(getPort()).append("]");
+        return buf.toString();
+    }
+
+    // --------------------------------------------------------- Public Methods
+
+    /**
+     * Start Queue thread as daemon
+     */
+    protected void checkThread() {
+        if (queueThread == null) {
+            if (log.isInfoEnabled())
+                log.info(sm.getString("AsyncSocketSender.create.thread",
+                        getAddress(), new Integer(getPort())));
+            queueThread = new QueueThread(this);
+            queueThread.setDaemon(true);
+            queueThread.start();
+        }
+    }
+
+    /**
+     * stop queue worker thread
+     */
+    protected void stopThread() {
+        if (queueThread != null) {
+            queueThread.stopRunning();
+            queueThread = null;
+        }
+    }
+
+    // -------------------------------------------------------- Inner Class
+
+    private class QueueThread extends Thread {
+        AsyncSocketSender sender;
+
+        private boolean keepRunning = true;
+
+        /**
+         * Current number of bytes from all queued messages
+         */
+        private long queuedNrOfBytes = 0;
+
+        public QueueThread(AsyncSocketSender sender) {
+            this.sender = sender;
+            setName("Cluster-AsyncSocketSender-" + (threadCounter++));
+        }
+
+        protected long getQueuedNrOfBytes() {
+            return queuedNrOfBytes ;
+        }
+        
+        protected synchronized void setQueuedNrOfBytes(long queuedNrOfBytes) {
+            this.queuedNrOfBytes = queuedNrOfBytes;
+        }
+
+        protected synchronized void incQueuedNrOfBytes(long size) {
+            queuedNrOfBytes += size;
+        }
+        
+        protected synchronized void decQueuedNrOfBytes(long size) {
+            queuedNrOfBytes -= size;
+        }
+
+        public void stopRunning() {
+            keepRunning = false;
+        }
+
+        /**
+         * Get one queued message and push it to the replication node
+         * 
+         * @see DataSender#pushMessage(String, byte[])
+         */
+        public void run() {
+            while (keepRunning) {
+                SmartQueue.SmartEntry entry = sender.queue.remove(5000);
+                if (entry != null) {
+                    int messagesize = 0;
+                    try {
+                        ClusterData data = (ClusterData) entry.getValue();
+                        messagesize = data.getMessage().length;
+                        sender.pushMessage(data);
+                    } catch (Exception x) {
+                        log.warn(sm.getString("AsyncSocketSender.send.error",
+                                entry.getKey()));
+                    } finally {
+                        outQueueCounter++;
+                        decQueuedNrOfBytes(messagesize);
+                    }
+                }
+            }
+        }
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/tcp/ClusterData.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/tcp/ClusterData.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/tcp/ClusterData.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,123 @@
+/*
+ * Copyright 1999,2005 The Apache Software Foundation.
+ * 
+ * Licensed 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.cluster.tcp;
+
+import org.apache.catalina.cluster.ClusterMessage;
+
+
+/**
+ * @author Peter Rossbach
+ * @version $Revision: 380229 $ $Date: 2006-02-23 15:28:29 -0600 (Thu, 23 Feb 2006) $
+ * @since 5.5.10
+ */
+public class ClusterData {
+
+    private int resend = ClusterMessage.FLAG_DEFAULT ;
+    private int compress = ClusterMessage.FLAG_DEFAULT ;
+    private byte[] message ;
+    private long timestamp ;
+    private String uniqueId ;
+    private String type ;
+    
+    public ClusterData() {}
+    
+    /**
+     * @param type message type (class)
+     * @param uniqueId unique message id
+     * @param message message data
+     * @param timestamp message creation date
+     */
+    public ClusterData(String type, String uniqueId, byte[] message, long timestamp
+            ) {
+        this.uniqueId = uniqueId;
+        this.message = message;
+        this.timestamp = timestamp;
+    }
+    
+    
+    /**
+     * @return Returns the type.
+     */
+    public String getType() {
+        return type;
+    }
+    /**
+     * @param type The type to set.
+     */
+    public void setType(String type) {
+        this.type = type;
+    }
+    /**
+     * @return Returns the message.
+     */
+    public byte[] getMessage() {
+        return message;
+    }
+    /**
+     * @param message The message to set.
+     */
+    public void setMessage(byte[] message) {
+        this.message = message;
+    }
+    /**
+     * @return Returns the timestamp.
+     */
+    public long getTimestamp() {
+        return timestamp;
+    }
+    /**
+     * @param timestamp The timestamp to set.
+     */
+    public void setTimestamp(long timestamp) {
+        this.timestamp = timestamp;
+    }
+    /**
+     * @return Returns the uniqueId.
+     */
+    public String getUniqueId() {
+        return uniqueId;
+    }
+    /**
+     * @param uniqueId The uniqueId to set.
+     */
+    public void setUniqueId(String uniqueId) {
+        this.uniqueId = uniqueId;
+    }
+    /**
+     * @return Returns the compress.
+     */
+    public int getCompress() {
+        return compress;
+    }
+    /**
+     * @param compress The compress to set.
+     */
+    public void setCompress(int compress) {
+        this.compress = compress;
+    }
+    /**
+     * @return Returns the resend.
+     */
+    public int getResend() {
+        return resend;
+    }
+    /**
+     * @param resend The resend to set.
+     */
+    public void setResend(int resend) {
+        this.resend = resend;
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/tcp/ClusterReceiverBase.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/tcp/ClusterReceiverBase.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/tcp/ClusterReceiverBase.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,523 @@
+/*
+ * Copyright 1999,2005 The Apache Software Foundation.
+ * 
+ * Licensed 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.cluster.tcp;
+
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.zip.GZIPInputStream;
+
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+
+import org.apache.catalina.Container;
+import org.apache.catalina.cluster.CatalinaCluster;
+import org.apache.catalina.cluster.ClusterMessage;
+import org.apache.catalina.cluster.ClusterReceiver;
+import org.apache.catalina.cluster.io.ListenCallback;
+import org.apache.catalina.cluster.session.ClusterSessionListener;
+import org.apache.catalina.cluster.session.ReplicationStream;
+import org.apache.catalina.core.StandardHost;
+import org.apache.catalina.util.StringManager;
+
+/**
+* FIXME i18n log messages
+* @author Peter Rossbach
+* @version $Revision: 418134 $ $Date: 2006-06-29 15:54:33 -0500 (Thu, 29 Jun 2006) $
+*/
+
+public abstract class ClusterReceiverBase implements Runnable, ClusterReceiver,ListenCallback {
+    
+    protected static org.apache.commons.logging.Log log =
+        org.apache.commons.logging.LogFactory.getLog( ClusterReceiverBase.class );
+
+    /**
+     * The string manager for this package.
+     */
+    protected StringManager sm = StringManager.getManager(Constants.Package);
+
+    private CatalinaCluster cluster;
+    private java.net.InetAddress bind;
+    private String tcpListenAddress;
+    private int tcpListenPort;
+    private boolean sendAck;
+    protected boolean doListen = false;
+
+    /**
+     * total bytes to recevied
+     */
+    protected long totalReceivedBytes = 0;
+    
+    /**
+     * doProcessingStats
+     */
+    protected boolean doReceivedProcessingStats = false;
+
+    /**
+     * proessingTime
+     */
+    protected long receivedProcessingTime = 0;
+    
+    /**
+     * min proessingTime
+     */
+    protected long minReceivedProcessingTime = Long.MAX_VALUE ;
+
+    /**
+     * max proessingTime
+     */
+    protected long maxReceivedProcessingTime = 0;
+    
+    /**
+     * Sending Stats
+     */
+    private long nrOfMsgsReceived = 0;
+
+    private long receivedTime = 0;
+
+    private long lastChecked = System.currentTimeMillis();
+
+
+    /**
+     * Compress message data bytes
+     */
+    private boolean compress = true ;
+
+    /**
+     * Transmitter Mbean name
+     */
+    private ObjectName objectName;
+
+    /**
+     * @return Returns the doListen.
+     */
+    public boolean isDoListen() {
+        return doListen;
+    }
+
+    /**
+     * @return Returns the bind.
+     */
+    public java.net.InetAddress getBind() {
+        if (bind == null) {
+            try {
+                if ("auto".equals(tcpListenAddress)) {
+                    tcpListenAddress = java.net.InetAddress.getLocalHost()
+                            .getHostAddress();
+                }
+                if (log.isDebugEnabled())
+                    log.debug("Starting replication listener on address:"
+                            + tcpListenAddress);
+                bind = java.net.InetAddress.getByName(tcpListenAddress);
+            } catch (IOException ioe) {
+                log.error("Failed bind replication listener on address:"
+                        + tcpListenAddress, ioe);
+            }
+        }
+      return bind;
+    }
+    
+    /**
+     * @param bind The bind to set.
+     */
+    public void setBind(java.net.InetAddress bind) {
+        this.bind = bind;
+    }
+    public void setCatalinaCluster(CatalinaCluster cluster) {
+        this.cluster = cluster;
+    }
+
+    public CatalinaCluster getCatalinaCluster() {
+        return (CatalinaCluster) cluster;
+    }
+    
+    /**
+     *  set Receiver ObjectName
+     * 
+     * @param name
+     */
+    public void setObjectName(ObjectName name) {
+        objectName = name;
+    }
+
+    /**
+     * Receiver ObjectName
+     * 
+     */
+    public ObjectName getObjectName() {
+        return objectName;
+    }
+    
+    /**
+     * @return Returns the compress.
+     */
+    public boolean isCompress() {
+        return compress;
+    }
+    
+    /**
+     * @param compressMessageData The compress to set.
+     */
+    public void setCompress(boolean compressMessageData) {
+        this.compress = compressMessageData;
+    }
+    
+    /**
+     * Send ACK to sender
+     * 
+     * @return True if sending ACK
+     */
+    public boolean isSendAck() {
+        return sendAck;
+    }
+
+    /**
+     * set ack mode or not!
+     * 
+     * @param sendAck
+     */
+    public void setSendAck(boolean sendAck) {
+        this.sendAck = sendAck;
+    }
+ 
+    public String getTcpListenAddress() {
+        return tcpListenAddress;
+    }
+    
+    public void setTcpListenAddress(String tcpListenAddress) {
+        this.tcpListenAddress = tcpListenAddress;
+    }
+    
+    public int getTcpListenPort() {
+        return tcpListenPort;
+    }
+    
+    public void setTcpListenPort(int tcpListenPort) {
+        this.tcpListenPort = tcpListenPort;
+    }
+  
+    public String getHost() {
+        return getTcpListenAddress();
+    }
+
+    public int getPort() {
+        return getTcpListenPort();
+    }
+    // ------------------------------------------------------------- stats
+
+    /**
+     * @return Returns the doReceivedProcessingStats.
+     */
+    public boolean isDoReceivedProcessingStats() {
+        return doReceivedProcessingStats;
+    }
+    /**
+     * @param doReceiverProcessingStats The doReceivedProcessingStats to set.
+     */
+    public void setDoReceivedProcessingStats(boolean doReceiverProcessingStats) {
+        this.doReceivedProcessingStats = doReceiverProcessingStats;
+    }
+    /**
+     * @return Returns the maxReceivedProcessingTime.
+     */
+    public long getMaxReceivedProcessingTime() {
+        return maxReceivedProcessingTime;
+    }
+    /**
+     * @return Returns the minReceivedProcessingTime.
+     */
+    public long getMinReceivedProcessingTime() {
+        return minReceivedProcessingTime;
+    }
+    /**
+     * @return Returns the receivedProcessingTime.
+     */
+    public long getReceivedProcessingTime() {
+        return receivedProcessingTime;
+    }
+    /**
+     * @return Returns the totalReceivedBytes.
+     */
+    public long getTotalReceivedBytes() {
+        return totalReceivedBytes;
+    }
+    
+    /**
+     * @return Returns the avg receivedProcessingTime/nrOfMsgsReceived.
+     */
+    public double getAvgReceivedProcessingTime() {
+        if ( nrOfMsgsReceived > 0 ) {
+            return ((double)receivedProcessingTime) / nrOfMsgsReceived;
+        } else {
+            return 0;
+        }
+    }
+
+    /**
+     * @return Returns the avg totalReceivedBytes/nrOfMsgsReceived.
+     */
+    public long getAvgTotalReceivedBytes() {
+        if ( nrOfMsgsReceived > 0 ) {
+            return ((long)totalReceivedBytes) / nrOfMsgsReceived;
+        } else {
+            return 0;
+        }
+    }
+
+    /**
+     * @return Returns the receivedTime.
+     */
+    public long getReceivedTime() {
+        return receivedTime;
+    }
+
+    /**
+     * @return Returns the lastChecked.
+     */
+    public long getLastChecked() {
+        return lastChecked;
+    }
+
+    /**
+     * @return Returns the nrOfMsgsReceived.
+     */
+    public long getNrOfMsgsReceived() {
+        return nrOfMsgsReceived;
+    }
+
+    /**
+     * start cluster receiver
+     * 
+     * @see org.apache.catalina.cluster.ClusterReceiver#start()
+     */
+    public void start() {
+        try {
+            getBind();
+            Thread t = new Thread(this, "ClusterReceiver");
+            t.setDaemon(true);
+            t.start();
+        } catch (Exception x) {
+            log.fatal("Unable to start cluster receiver", x);
+        }
+        registerReceiverMBean();
+    }
+
+ 
+    /**
+     * Stop accept
+     * 
+     * @see org.apache.catalina.cluster.ClusterReceiver#stop()
+     * @see #stopListening()
+     */
+    public void stop() {
+        stopListening();
+        unregisterRecevierMBean();
+     
+    }
+    
+    /**
+     * Register Recevier MBean
+     * <domain>:type=ClusterReceiver,host=<host>
+     */
+    protected void registerReceiverMBean() {
+        if (cluster != null && cluster instanceof SimpleTcpCluster) {
+            SimpleTcpCluster scluster = (SimpleTcpCluster) cluster;
+            ObjectName clusterName = scluster.getObjectName();
+            try {
+                MBeanServer mserver = scluster.getMBeanServer();
+                Container container = cluster.getContainer();
+                String name = clusterName.getDomain() + ":type=ClusterReceiver";
+                if (container instanceof StandardHost) {
+                    name += ",host=" + clusterName.getKeyProperty("host");
+                }
+                ObjectName receiverName = new ObjectName(name);
+                if (mserver.isRegistered(receiverName)) {
+                    if (log.isWarnEnabled())
+                        log.warn(sm.getString(
+                                "cluster.mbean.register.already",
+                                receiverName));
+                    return;
+                }
+                setObjectName(receiverName);
+                mserver.registerMBean(scluster.getManagedBean(this),
+                        getObjectName());
+            } catch (Exception e) {
+                log.warn(e);
+            }
+        }
+    }
+   
+    /**
+     * UnRegister Recevier MBean
+     * <domain>:type=ClusterReceiver,host=<host>
+     */
+    protected void unregisterRecevierMBean() {
+        if (cluster != null && getObjectName() != null
+                && cluster instanceof SimpleTcpCluster) {
+            SimpleTcpCluster scluster = (SimpleTcpCluster) cluster;
+            try {
+                MBeanServer mserver = scluster.getMBeanServer();
+                mserver.unregisterMBean(getObjectName());
+            } catch (Exception e) {
+                log.error(e);
+            }
+        }
+    }
+
+    /**
+     * stop Listener sockets
+     */
+    protected abstract void stopListening() ;
+
+    /**
+     * Start Listener
+     * @throws Exception
+     */
+    protected abstract void listen ()
+       throws Exception ;
+
+    
+    /**
+     * Start thread and listen
+     */
+    public void run()
+    {
+        try
+        {
+            listen();
+        }
+        catch ( Exception x )
+        {
+            log.error("Unable to start cluster listener.",x);
+        }
+    }
+
+    // --------------------------------------------------------- receiver messages
+
+    /**
+     * receiver Message from other node.
+     * All SessionMessage forward to ClusterManager and other message dispatch to all accept MessageListener.
+     *
+     * @see ClusterSessionListener#messageReceived(ClusterMessage)
+     */
+    public void messageDataReceived(ClusterData data) {
+    //public void messageDataReceived(byte[] data) {
+        long timeSent = 0 ;
+        if (doReceivedProcessingStats) {
+            timeSent = System.currentTimeMillis();
+        }
+        try {
+            ClusterMessage message = deserialize(data);
+            cluster.receive(message);
+        } catch (Exception x) {
+            log
+                    .error(
+                            "Unable to deserialize session message or unexpected exception from message listener.",
+                            x);
+        } finally {
+            if (doReceivedProcessingStats) {
+                addReceivedProcessingStats(timeSent);
+            }
+        }
+    }
+
+    /**
+     * deserialize the receieve cluster message
+     * @param data uncompress data
+     * @return The message
+     * @throws IOException
+     * @throws ClassNotFoundException
+     */
+    //protected ClusterMessage deserialize(byte[] data)
+    protected ClusterMessage deserialize(ClusterData data)
+            throws IOException, ClassNotFoundException {
+        Object message = null;
+        if (data != null) {
+            InputStream instream;
+            if (isCompress() || data.getCompress() == ClusterMessage.FLAG_ALLOWED ) {
+                instream = new GZIPInputStream(new ByteArrayInputStream(data.getMessage()));
+            } else {
+                instream = new ByteArrayInputStream(data.getMessage());
+            }
+            ReplicationStream stream = new ReplicationStream(instream,
+                    getClass().getClassLoader());
+            message = stream.readObject();
+            // calc stats really received bytes
+            totalReceivedBytes += data.getMessage().length;
+            //totalReceivedBytes += data.length;
+            nrOfMsgsReceived++;
+            instream.close();
+        }
+        if (message instanceof ClusterMessage)
+            return (ClusterMessage) message;
+        else {
+            if (log.isDebugEnabled())
+                log.debug("Message " + message.toString() + " from type "
+                        + message.getClass().getName()
+                        + " transfered but is not a cluster message");
+            return null;
+        }
+    }
+    
+    // --------------------------------------------- Performance Stats
+
+    /**
+     * Reset sender statistics
+     */
+    public synchronized void resetStatistics() {
+        nrOfMsgsReceived = 0;
+        totalReceivedBytes = 0;
+        minReceivedProcessingTime = Long.MAX_VALUE ;
+        maxReceivedProcessingTime = 0 ;
+        receivedProcessingTime = 0 ;
+        receivedTime = 0 ;
+    }
+
+    /**
+     * Add receiver processing stats times
+     * @param startTime
+     */
+    protected void addReceivedProcessingStats(long startTime) {
+        long current = System.currentTimeMillis() ;
+        long time = current - startTime ;
+        synchronized(this) {
+            if(time < minReceivedProcessingTime)
+                minReceivedProcessingTime = time ;
+            if( time > maxReceivedProcessingTime)
+                maxReceivedProcessingTime = time ;
+            receivedProcessingTime += time ;
+        }
+        if (log.isDebugEnabled()) {
+            if ((current - lastChecked) > 5000) {
+                log.debug("Calc msg send time total=" + receivedTime
+                        + "ms num request=" + nrOfMsgsReceived
+                        + " average per msg="
+                        + (receivedTime / nrOfMsgsReceived) + "ms.");
+                lastChecked=current ;
+            }
+        }
+    }
+    
+    /* (non-Javadoc)
+     * @see org.apache.catalina.cluster.io.ListenCallback#sendAck()
+     */
+    public void sendAck() throws IOException {
+        // do nothing
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/tcp/Constants.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/tcp/Constants.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/tcp/Constants.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,32 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.cluster.tcp;
+
+/**
+ * Manifest constants for the <code>org.apache.catalina.cluster.tcp</code>
+ * package.
+ *
+ * @author Peter Rossbach
+ * @version $Revision: 303753 $ $Date: 2005-03-14 15:24:30 -0600 (Mon, 14 Mar 2005) $
+ */
+
+public class Constants {
+
+    public static final String Package = "org.apache.catalina.cluster.tcp";
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/tcp/DataSender.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/tcp/DataSender.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/tcp/DataSender.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,945 @@
+/*
+ * Copyright 1999,2005 The Apache Software Foundation.
+ * 
+ * Licensed 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.cluster.tcp;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.net.InetAddress;
+import java.net.Socket;
+import java.net.SocketException;
+
+import org.apache.catalina.cluster.ClusterMessage;
+import org.apache.catalina.cluster.io.XByteBuffer;
+import org.apache.catalina.util.StringManager;
+
+/**
+ * Send cluster messages with only one socket. Ack and keep Alive Handling is
+ * supported
+ * 
+ * @author Peter Rossbach
+ * @author Filip Hanik
+ * @version $Revision: 418134 $ $Date: 2006-06-29 15:54:33 -0500 (Thu, 29 Jun 2006) $
+ * @since 5.5.7
+ */
+public class DataSender implements IDataSender {
+
+    private static org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory
+            .getLog(DataSender.class);
+
+    /**
+     * The string manager for this package.
+     */
+    protected static StringManager sm = StringManager
+            .getManager(Constants.Package);
+
+    // ----------------------------------------------------- Instance Variables
+
+    /**
+     * The descriptive information about this implementation.
+     */
+    private static final String info = "DataSender/2.1";
+
+    /**
+     * receiver address
+     */
+    private InetAddress address;
+
+    /**
+     * receiver port
+     */
+    private int port;
+
+    
+    /**
+     * cluster domain
+     */
+    private String domain;
+
+    /**
+     * current sender socket
+     */
+    private Socket socket = null;
+
+    /**
+     * is Socket really connected
+     */
+    private boolean isSocketConnected = false;
+
+    /**
+     * Message transfer over socket ?
+     */
+    private boolean isMessageTransferStarted = false;
+
+    /**
+     * sender is in suspect state (last transfer failed)
+     */
+    private SenderState senderState = new SenderState();
+
+    /**
+     * wait time for ack
+     */
+    private long ackTimeout;
+
+    /**
+     * number of requests
+     */
+    protected long nrOfRequests = 0;
+
+    /**
+     * total bytes to transfer
+     */
+    protected long totalBytes = 0;
+
+    /**
+     * number of connects
+     */
+    protected long connectCounter = 0;
+
+    /**
+     * number of explizit disconnects
+     */
+    protected long disconnectCounter = 0;
+
+    /**
+     * number of failing acks
+     */
+    protected long missingAckCounter = 0;
+
+    /**
+     * number of data resends (second trys after socket failure)
+     */
+    protected long dataResendCounter = 0;
+
+    /**
+     * number of data failure sends 
+     */
+    protected long dataFailureCounter = 0;
+    
+    /**
+     * doProcessingStats
+     */
+    protected boolean doProcessingStats = false;
+
+    /**
+     * proessingTime
+     */
+    protected long processingTime = 0;
+    
+    /**
+     * min proessingTime
+     */
+    protected long minProcessingTime = Long.MAX_VALUE ;
+
+    /**
+     * max proessingTime
+     */
+    protected long maxProcessingTime = 0;
+   
+    /**
+     * doWaitAckStats
+     */
+    protected boolean doWaitAckStats = false;
+
+    /**
+     * waitAckTime
+     */
+    protected long waitAckTime = 0;
+    
+    /**
+     * min waitAckTime
+     */
+    protected long minWaitAckTime = Long.MAX_VALUE ;
+
+    /**
+     * max waitAckTime
+     */
+    protected long maxWaitAckTime = 0;
+
+    /**
+     * keep socket open for no more than one min
+     */
+    private long keepAliveTimeout = 60 * 1000;
+
+    /**
+     * max requests before reconnecting (default -1 unlimited)
+     */
+    private int keepAliveMaxRequestCount = -1;
+
+    /**
+     * Last connect timestamp
+     */
+    protected long keepAliveConnectTime = 0;
+
+    /**
+     * keepalive counter
+     */
+    protected int keepAliveCount = 0;
+
+    /**
+     * wait for receiver Ack
+     */
+    private boolean waitForAck = false;
+
+    /**
+     * number of socket close
+     */
+    private int socketCloseCounter = 0 ;
+
+    /**
+     * number of socket open
+     */
+    private int socketOpenCounter = 0 ;
+
+    /**
+     * number of socket open failures
+     */
+    private int socketOpenFailureCounter = 0 ;
+
+    /**
+     * After failure make a resend
+     */
+    private boolean resend = false ;
+    
+    // ------------------------------------------------------------- Constructor
+    
+    public DataSender(String domain,InetAddress host, int port) {
+        this.address = host;
+        this.port = port;
+        this.domain = domain;
+        if (log.isDebugEnabled())
+            log.debug(sm.getString("IDataSender.create",address, new Integer(port)));
+    }
+
+    public DataSender(String domain,InetAddress host, int port, SenderState state) {
+        this(domain,host,port);
+        if ( state != null ) this.senderState = state;
+    }
+    // ------------------------------------------------------------- Properties
+
+    /**
+     * Return descriptive information about this implementation and the
+     * corresponding version number, in the format
+     * <code>&lt;description&gt;/&lt;version&gt;</code>.
+     */
+    public String getInfo() {
+
+        return (info);
+
+    }
+
+    /**
+     * @return Returns the nrOfRequests.
+     */
+    public long getNrOfRequests() {
+        return nrOfRequests;
+    }
+
+    /**
+     * @return Returns the totalBytes.
+     */
+    public long getTotalBytes() {
+        return totalBytes;
+    }
+
+    /**
+     * @return Returns the avg totalBytes/nrOfRequests.
+     */
+    public long getAvgMessageSize() {
+        if ( nrOfRequests > 0 ) {
+            return totalBytes / nrOfRequests;
+        } else {
+            return 0;
+        }
+    }
+
+    /**
+     * @return Returns the avg processingTime/nrOfRequests.
+     */
+    public double getAvgProcessingTime() {
+        if ( nrOfRequests > 0 ) {
+            return ((double)processingTime) / nrOfRequests;
+        } else {
+            return 0;
+        }
+    }
+ 
+    /**
+     * @return Returns the maxProcessingTime.
+     */
+    public long getMaxProcessingTime() {
+        return maxProcessingTime;
+    }
+    
+    /**
+     * @return Returns the minProcessingTime.
+     */
+    public long getMinProcessingTime() {
+        return minProcessingTime;
+    }
+    
+    /**
+     * @return Returns the processingTime.
+     */
+    public long getProcessingTime() {
+        return processingTime;
+    }
+    
+    /**
+     * @return Returns the doProcessingStats.
+     */
+    public boolean isDoProcessingStats() {
+        return doProcessingStats;
+    }
+    
+    /**
+     * @param doProcessingStats The doProcessingStats to set.
+     */
+    public void setDoProcessingStats(boolean doProcessingStats) {
+        this.doProcessingStats = doProcessingStats;
+    }
+ 
+ 
+    /**
+     * @return Returns the doWaitAckStats.
+     */
+    public boolean isDoWaitAckStats() {
+        return doWaitAckStats;
+    }
+    
+    /**
+     * @param doWaitAckStats The doWaitAckStats to set.
+     */
+    public void setDoWaitAckStats(boolean doWaitAckStats) {
+        this.doWaitAckStats = doWaitAckStats;
+    }
+    
+    /**
+     * @return Returns the avg waitAckTime/nrOfRequests.
+     */
+    public double getAvgWaitAckTime() {
+        if ( nrOfRequests > 0 ) {
+            return ((double)waitAckTime) / nrOfRequests;
+        } else {
+            return 0;
+        }
+    }
+ 
+    /**
+     * @return Returns the maxWaitAckTime.
+     */
+    public long getMaxWaitAckTime() {
+        return maxWaitAckTime;
+    }
+    
+    /**
+     * @return Returns the minWaitAckTime.
+     */
+    public long getMinWaitAckTime() {
+        return minWaitAckTime;
+    }
+    
+    /**
+     * @return Returns the waitAckTime.
+     */
+    public long getWaitAckTime() {
+        return waitAckTime;
+    }
+    
+    /**
+     * @return Returns the connectCounter.
+     */
+    public long getConnectCounter() {
+        return connectCounter;
+    }
+
+    /**
+     * @return Returns the disconnectCounter.
+     */
+    public long getDisconnectCounter() {
+        return disconnectCounter;
+    }
+
+    /**
+     * @return Returns the missingAckCounter.
+     */
+    public long getMissingAckCounter() {
+        return missingAckCounter;
+    }
+
+    /**
+     * @return Returns the socketOpenCounter.
+     */
+    public int getSocketOpenCounter() {
+        return socketOpenCounter;
+    }
+    
+    /**
+     * @return Returns the socketOpenFailureCounter.
+     */
+    public int getSocketOpenFailureCounter() {
+        return socketOpenFailureCounter;
+    }
+
+    /**
+     * @return Returns the socketCloseCounter.
+     */
+    public int getSocketCloseCounter() {
+        return socketCloseCounter;
+    }
+
+    /**
+     * @return Returns the dataResendCounter.
+     */
+    public long getDataResendCounter() {
+        return dataResendCounter;
+    }
+
+    /**
+     * @return Returns the dataFailureCounter.
+     */
+    public long getDataFailureCounter() {
+        return dataFailureCounter;
+    }
+    
+    /**
+     * @param address The address to set.
+     */
+    public void setAddress(InetAddress address) {
+        this.address = address;
+    }
+
+    public InetAddress getAddress() {
+        return address;
+    }
+
+    
+    /**
+     * @param port The port to set.
+     */
+    public void setPort(int port) {
+        this.port = port;
+    }
+    
+    public int getPort() {
+        return port;
+    }
+
+    /**
+     * @return Returns the domain.
+     */
+    public String getDomain() {
+        return domain;
+    }
+    
+    /**
+     * @param domain The domain to set.
+     */
+    public void setDomain(String domain) {
+        this.domain = domain;
+    }
+    
+    public boolean isConnected() {
+        return isSocketConnected;
+    }
+
+    /**
+     * @return Is DataSender send a message
+     */
+    public boolean isMessageTransferStarted() {
+        return isMessageTransferStarted;
+    }
+    
+    /**
+     * @param isSocketConnected
+     *            The isSocketConnected to set.
+     */
+    protected void setSocketConnected(boolean isSocketConnected) {
+        this.isSocketConnected = isSocketConnected;
+    }
+
+    public boolean isSuspect() {
+        return senderState.isSuspect() || senderState.isFailing();
+    }
+
+    public boolean getSuspect() {
+        return isSuspect();
+    }
+
+    public void setSuspect(boolean suspect) {
+        if ( suspect ) 
+            this.senderState.setSuspect();
+        else
+            this.senderState.setReady();
+    }
+
+    public long getAckTimeout() {
+        return ackTimeout;
+    }
+
+    public void setAckTimeout(long ackTimeout) {
+        this.ackTimeout = ackTimeout;
+    }
+
+    public long getKeepAliveTimeout() {
+        return keepAliveTimeout;
+    }
+
+    public void setKeepAliveTimeout(long keepAliveTimeout) {
+        this.keepAliveTimeout = keepAliveTimeout;
+    }
+
+    public int getKeepAliveMaxRequestCount() {
+        return keepAliveMaxRequestCount;
+    }
+
+    public void setKeepAliveMaxRequestCount(int keepAliveMaxRequestCount) {
+        this.keepAliveMaxRequestCount = keepAliveMaxRequestCount;
+    }
+
+    /**
+     * @return Returns the keepAliveConnectTime.
+     */
+    public long getKeepAliveConnectTime() {
+        return keepAliveConnectTime;
+    }
+
+    /**
+     * @return Returns the keepAliveCount.
+     */
+    public int getKeepAliveCount() {
+        return keepAliveCount;
+    }
+
+    /**
+     * @return Returns the waitForAck.
+     */
+    public boolean isWaitForAck() {
+        return waitForAck;
+    }
+
+    /**
+     * @param waitForAck
+     *            The waitForAck to set.
+     */
+    public void setWaitForAck(boolean waitForAck) {
+        this.waitForAck = waitForAck;
+    }
+
+    /**
+     * @return Returns the resend.
+     */
+    public boolean isResend() {
+        return resend;
+    }
+    /**
+     * @param resend The resend to set.
+     */
+    public void setResend(boolean resend) {
+        this.resend = resend;
+    }
+    /**
+     * @return Returns the socket.
+     */
+    public Socket getSocket() {
+        return socket;
+    }
+
+    public SenderState getSenderState() {
+        return senderState;
+    }
+
+    /**
+     * @param socket The socket to set.
+     */
+    public void setSocket(Socket socket) {
+        this.socket = socket;
+    }
+    // --------------------------------------------------------- Public Methods
+
+    /**
+     * Connect other cluster member receiver 
+     * @see org.apache.catalina.cluster.tcp.IDataSender#connect()
+     */
+    public synchronized void connect() throws java.io.IOException {
+        if(!isMessageTransferStarted) {
+            openSocket();
+            if(isConnected()) {
+                connectCounter++;
+                if (log.isDebugEnabled())
+                    log.debug(sm.getString("IDataSender.connect", address.getHostAddress(),
+                            new Integer(port),new Long(connectCounter)));
+            }
+        } else 
+            if (log.isWarnEnabled())
+               log.warn(sm.getString("IDataSender.message.create", address.getHostAddress(),new Integer(port)));
+   }
+
+ 
+    /**
+     * disconnect and close socket
+     * 
+     * @see IDataSender#disconnect()
+     */
+    public synchronized void disconnect() {
+        if(!isMessageTransferStarted) {
+            boolean connect = isConnected() ;
+            closeSocket();
+            if(connect) {
+                disconnectCounter++;
+                if (log.isDebugEnabled())
+                    log.debug(sm.getString("IDataSender.disconnect", address.getHostAddress(),
+                        new Integer(port),new Long(disconnectCounter)));
+            }
+        } else 
+            if (log.isWarnEnabled())
+               log.warn(sm.getString("IDataSender.message.disconnect", address.getHostAddress(),new Integer(port)));
+        
+    }
+
+    /**
+     * Check, if time to close socket! Important for AsyncSocketSender that
+     * replication thread is not fork again! <b>Only work when keepAliveTimeout
+     * or keepAliveMaxRequestCount greater -1 </b>
+     * FIXME Can we close a socket when a message wait for ack?
+     * @return true, is socket close
+     * @see DataSender#closeSocket()
+     */
+    public synchronized boolean checkKeepAlive() {
+        boolean isCloseSocket = true ;
+        if(!isMessageTransferStarted) {
+            if(isConnected()) {
+                if ((keepAliveTimeout > -1 && (System.currentTimeMillis() - keepAliveConnectTime) > keepAliveTimeout)
+                    || (keepAliveMaxRequestCount > -1 && keepAliveCount >= keepAliveMaxRequestCount)) {
+                        closeSocket();
+               } else
+                    isCloseSocket = false ;
+            }
+        } else
+            isCloseSocket = false ;
+        
+        return isCloseSocket;
+    }
+
+    /**
+     * Send message
+     * 
+     * @see org.apache.catalina.cluster.tcp.IDataSender#sendMessage(,
+     *      ClusterData)
+     */
+    public synchronized void sendMessage(ClusterData data)
+            throws java.io.IOException {
+        pushMessage(data);
+    }
+
+    /**
+     * Reset sender statistics
+     */
+    public synchronized void resetStatistics() {
+        nrOfRequests = 0;
+        totalBytes = 0;
+        disconnectCounter = 0;
+        connectCounter = isConnected() ? 1 : 0;
+        missingAckCounter = 0;
+        dataResendCounter = 0;
+        dataFailureCounter = 0 ;
+        socketOpenCounter =isConnected() ? 1 : 0;
+        socketOpenFailureCounter = 0 ;
+        socketCloseCounter = 0;
+        processingTime = 0 ;
+        minProcessingTime = Long.MAX_VALUE ;
+        maxProcessingTime = 0 ;
+        waitAckTime = 0 ;
+        minWaitAckTime = Long.MAX_VALUE ;
+        maxWaitAckTime = 0 ;
+    }
+
+    /**
+     * Name of this SockerSender
+     */
+    public String toString() {
+        StringBuffer buf = new StringBuffer("DataSender[");
+        buf.append(getAddress()).append(":").append(getPort()).append("]");
+        return buf.toString();
+    }
+
+    // --------------------------------------------------------- Protected Methods
+ 
+    /**
+     * open real socket and set time out when waitForAck is enabled
+     * is socket open return directly
+     * @throws IOException
+     * @throws SocketException
+     */
+    protected void openSocket() throws IOException, SocketException {
+       if(isConnected())
+           return ;
+       try {
+            createSocket();
+            if (isWaitForAck())
+                socket.setSoTimeout((int) ackTimeout);
+            isSocketConnected = true;
+            socketOpenCounter++;
+            this.keepAliveCount = 0;
+            this.keepAliveConnectTime = System.currentTimeMillis();
+            if (log.isDebugEnabled())
+                log.debug(sm.getString("IDataSender.openSocket", address
+                        .getHostAddress(), new Integer(port),new Long(socketOpenCounter)));
+      } catch (IOException ex1) {
+            socketOpenFailureCounter++ ;
+            if (log.isDebugEnabled())
+                log.debug(sm.getString("IDataSender.openSocket.failure",
+                        address.getHostAddress(), new Integer(port),new Long(socketOpenFailureCounter)), ex1);
+            throw ex1;
+        }
+        
+     }
+
+    /**
+     * @throws IOException
+     * @throws SocketException
+     */
+    protected void createSocket() throws IOException, SocketException {
+        socket = new Socket(getAddress(), getPort());
+    }
+
+    /**
+     * close socket
+     * 
+     * @see DataSender#disconnect()
+     * @see DataSender#closeSocket()
+     */
+    protected void closeSocket() {
+        if(isConnected()) {
+             if (socket != null) {
+                try {
+                    socket.close();
+                } catch (IOException x) {
+                } finally {
+                    socket = null;
+                }
+            }
+            this.keepAliveCount = 0;
+            isSocketConnected = false;
+            socketCloseCounter++;
+            if (log.isDebugEnabled())
+                log.debug(sm.getString("IDataSender.closeSocket",
+                        address.getHostAddress(), new Integer(port),new Long(socketCloseCounter)));
+       }
+    }
+
+    /**
+     * Add statistic for this socket instance
+     * 
+     * @param length
+     */
+    protected void addStats(int length) {
+        nrOfRequests++;
+        totalBytes += length;
+        if (log.isInfoEnabled() && (nrOfRequests % 1000) == 0) {
+            log.info(sm.getString("IDataSender.stats", new Object[] {
+                    getAddress().getHostAddress(), new Integer(getPort()),
+                    new Long(totalBytes), new Long(nrOfRequests),
+                    new Long(totalBytes / nrOfRequests),
+                    new Long(getProcessingTime()),
+                    new Double(getAvgProcessingTime())}));
+        }
+    }
+
+    /**
+     * Add processing stats times
+     * @param startTime
+     */
+    protected void addProcessingStats(long startTime) {
+        long time = System.currentTimeMillis() - startTime ;
+        if(time < minProcessingTime)
+            minProcessingTime = time ;
+        if( time > maxProcessingTime)
+            maxProcessingTime = time ;
+        processingTime += time ;
+    }
+    
+    /**
+     * Add waitAck stats times
+     * @param startTime
+     */
+    protected void addWaitAckStats(long startTime) {
+        long time = System.currentTimeMillis() - startTime ;
+        if(time < minWaitAckTime)
+            minWaitAckTime = time ;
+        if( time > maxWaitAckTime)
+            maxWaitAckTime = time ;
+        waitAckTime += time ;
+    }
+    /**
+     * Push messages with only one socket at a time
+     * Wait for ack is needed and make auto retry when write message is failed.
+     * After sending error close and reopen socket again.
+     * 
+     * After successfull sending update stats
+     * 
+     * WARNING: Subclasses must be very carefull that only one thread call this pushMessage at once!!!
+     * 
+     * @see #closeSocket()
+     * @see #openSocket()
+     * @see #writeData(ClusterData)
+     * 
+     * @param data
+     *            data to send
+     * @throws java.io.IOException
+     * @since 5.5.10
+     */
+    protected void pushMessage( ClusterData data)
+            throws java.io.IOException {
+        long time = 0 ;
+        if(doProcessingStats) {
+            time = System.currentTimeMillis();
+        }
+        boolean messageTransfered = false ;
+        synchronized(this) {
+            checkKeepAlive();
+            if (!isConnected())
+                openSocket();
+            else if(keepAliveTimeout > -1)
+                this.keepAliveConnectTime = System.currentTimeMillis();
+        }
+        IOException exception = null;
+        try {
+             writeData(data);
+             messageTransfered = true ;
+        } catch (java.io.IOException x) {
+            if(data.getResend() == ClusterMessage.FLAG_ALLOWED || 
+                    (data.getResend() == ClusterMessage.FLAG_DEFAULT && isResend() )) {
+                // second try with fresh connection
+                dataResendCounter++;
+                if (log.isTraceEnabled())
+                    log.trace(sm.getString("IDataSender.send.again", address.getHostAddress(),
+                            new Integer(port)),x);
+                synchronized(this) {
+                    closeSocket();
+                    openSocket();
+                }
+                try {
+                    writeData(data);
+                    messageTransfered = true;
+                } catch (IOException xx) {
+                    exception = xx;
+                    throw xx ;
+                }
+            } else {
+                synchronized(this) {
+                    closeSocket();
+                }
+                exception = x;
+                throw x ;
+            }
+        } finally {
+            this.keepAliveCount++;
+            checkKeepAlive();
+            if(doProcessingStats) {
+                addProcessingStats(time);
+            }
+            if(messageTransfered) {
+                addStats(data.getMessage().length);
+                if (log.isTraceEnabled()) {
+                    log.trace(sm.getString("IDataSender.send.message", address.getHostAddress(),
+                        new Integer(port), data.getUniqueId(), new Long(data.getMessage().length)));
+                }
+            } else {
+                dataFailureCounter++;
+                throw exception;
+            }
+        }
+    }
+
+    /**
+     * Sent real cluster Message to socket stream
+     * FIXME send compress
+     * @param data
+     * @throws IOException
+     * @since 5.5.10
+     */
+    protected void writeData(ClusterData data) throws IOException { 
+        synchronized(this) {
+            isMessageTransferStarted = true ;
+        }
+        try {
+            byte[] message = data.getMessage();
+            OutputStream out = socket.getOutputStream();
+            out.write(XByteBuffer.createDataPackage(message,data.getCompress()));
+            out.flush();
+            if (isWaitForAck())
+                waitForAck(ackTimeout);
+        } finally {
+            synchronized(this) {
+                isMessageTransferStarted = false ;
+            }
+        }
+    }
+
+    /**
+     * Wait for Acknowledgement from other server
+     * FIXME Please, not wait only for three charcters, better control that the wait ack message is correct.
+     * @param timeout
+     * @throws java.io.IOException
+     * @throws java.net.SocketTimeoutException
+     */
+    protected void waitForAck(long timeout) throws java.io.IOException {
+        long time = 0 ;
+        if(doWaitAckStats) {
+            time = System.currentTimeMillis();
+        }
+        try {
+            int bytesRead = 0;
+            if ( log.isTraceEnabled() ) 
+                log.trace(sm.getString("IDataSender.ack.start",getAddress(), new Integer(socket.getLocalPort())));
+            int i = socket.getInputStream().read();
+            while ((i != -1) && (i != 3) && bytesRead < 10) {
+                if ( log.isTraceEnabled() ) 
+                    log.trace(sm.getString("IDataSender.ack.read",getAddress(), new Integer(socket.getLocalPort()),new Character((char) i)));
+                bytesRead++;
+                i = socket.getInputStream().read();
+            }
+            if (i != 3) {
+                if (i == -1) {
+                    throw new IOException(sm.getString("IDataSender.ack.eof",getAddress(), new Integer(socket.getLocalPort())));
+                } else {
+                    throw new IOException(sm.getString("IDataSender.ack.wrong",getAddress(), new Integer(socket.getLocalPort())));
+                }
+            } else {
+                if (log.isTraceEnabled()) {
+                    log.trace(sm.getString("IDataSender.ack.receive", getAddress(),new Integer(socket.getLocalPort())));
+                }
+            }
+        } catch (IOException x) {
+            missingAckCounter++;
+            String errmsg = sm.getString("IDataSender.ack.missing", getAddress(),
+                                         new Integer(socket.getLocalPort()), 
+                                         new Long(this.ackTimeout));
+            if ( !this.isSuspect() ) {
+                this.setSuspect(true);
+                if ( log.isWarnEnabled() ) log.warn(errmsg, x);
+            } else {
+                if ( log.isDebugEnabled() )log.debug(errmsg, x);
+            }
+            throw x;
+        } finally {
+            if(doWaitAckStats) {
+                addWaitAckStats(time);
+            }
+        }
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/tcp/DataSenders.properties
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/tcp/DataSenders.properties	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/tcp/DataSenders.properties	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,4 @@
+fastasyncqueue=org.apache.catalina.cluster.tcp.FastAsyncSocketSender
+asynchronous=org.apache.catalina.cluster.tcp.AsyncSocketSender
+synchronous=org.apache.catalina.cluster.tcp.SocketSender
+pooled=org.apache.catalina.cluster.tcp.PooledSocketSender

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/tcp/FastAsyncSocketSender.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/tcp/FastAsyncSocketSender.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/tcp/FastAsyncSocketSender.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,491 @@
+/*
+ * Copyright 1999,2004-2005 The Apache Software Foundation.
+ * 
+ * Licensed 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.cluster.tcp;
+
+import java.net.InetAddress;
+
+import org.apache.catalina.cluster.util.FastQueue;
+import org.apache.catalina.cluster.util.LinkObject;
+import org.apache.catalina.cluster.util.IQueue;
+
+/**
+ * Send cluster messages from a Message queue with only one socket. Ack and keep
+ * Alive Handling is supported. Fast Queue can limit queue size and consume all messages at queue at one block.<br/>
+ * Limit the queue lock contention under high load!<br/>
+ * <ul>
+ * <li>With autoConnect=false at ReplicationTransmitter, you can disconnect the
+ * sender and all messages are queued. Only use this for small maintaince
+ * isuses!</li>
+ * <li>waitForAck=true, means that receiver ack the transfer</li>
+ * <li>after one minute idle time, or number of request (100) the connection is
+ * reconnected with next request. Change this for production use!</li>
+ * <li>default ackTimeout is 15 sec: this is very low for big all session
+ * replication messages after restart a node</li>
+ * <li>disable keepAlive: keepAliveTimeout="-1" and
+ * keepAliveMaxRequestCount="-1"</li>
+ * <li>maxQueueLength: Limit the sender queue length (membership goes well, but transfer is failure!!)</li>
+ * </ul>
+ * FIXME: refactor code duplications with AsyncSocketSender => configurable or extract super class 
+ * @author Peter Rossbach ( idea comes form Rainer Jung)
+ * @version $Revision: 366253 $ $Date: 2006-01-05 13:30:42 -0600 (Thu, 05 Jan 2006) $
+ * @since 5.5.9
+ */
+public class FastAsyncSocketSender extends DataSender {
+
+    private static int threadCounter = 1;
+
+    private static org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory
+            .getLog(FastAsyncSocketSender.class);
+
+    /**
+     * The descriptive information about this implementation.
+     */
+    private static final String info = "FastAsyncSocketSender/3.0";
+
+    // ----------------------------------------------------- Instance Variables
+
+    /**
+     * Message Queue
+     */
+    private FastQueue queue = new FastQueue();
+
+    /**
+     * Active thread to push messages asynchronous to the other replication node
+     */
+    private FastQueueThread queueThread = null;
+
+    /**
+     * Count number of queue message
+     */
+    private long inQueueCounter = 0;
+
+    /**
+     * Count all successfull push messages from queue
+     */
+    private long outQueueCounter = 0;
+
+    private int threadPriority = Thread.NORM_PRIORITY;;
+
+    // ------------------------------------------------------------- Constructor
+
+    /**
+     * start background thread to push incomming cluster messages to replication
+     * node
+     * 
+     * @param domain replication cluster domain (session domain)
+     * @param host replication node tcp address
+     * @param port replication node tcp port
+     */
+    public FastAsyncSocketSender(String domain,InetAddress host, int port) {
+        super(domain,host, port);
+        checkThread();
+    }
+  
+    // ------------------------------------------------------------- Properties
+
+    /**
+     * Return descriptive information about this implementation and the
+     * corresponding version number, in the format
+     * <code>&lt;description&gt;/&lt;version&gt;</code>.
+     */
+    public String getInfo() {
+
+        return (info);
+
+    }
+ 
+
+    /**
+     * get current add wait timeout 
+     * @return current wait timeout
+     */
+    public long getQueueAddWaitTimeout() {
+        
+        return queue.getAddWaitTimeout();
+    }
+
+    /**
+     * Set add wait timeout (default 10000 msec)
+     * @param timeout
+     */
+    public void setQueueAddWaitTimeout(long timeout) {
+        queue.setAddWaitTimeout(timeout);
+    }
+
+    /**
+     * get current remove wait timeout
+     * @return The timeout
+     */
+    public long getQueueRemoveWaitTimeout() {
+        return queue.getRemoveWaitTimeout();
+    }
+
+    /**
+     * set remove wait timeout ( default 30000 msec)
+     * @param timeout
+     */
+    public void setRemoveWaitTimeout(long timeout) {
+        queue.setRemoveWaitTimeout(timeout);
+    }
+
+    /**
+     * @return Returns the checkLock.
+     */
+    public boolean isQueueCheckLock() {
+        return queue.isCheckLock();
+    }
+    /**
+     * @param checkLock The checkLock to set.
+     */
+    public void setQueueCheckLock(boolean checkLock) {
+        queue.setCheckLock(checkLock);
+    }
+    /**
+     * @return Returns the doStats.
+     */
+    public boolean isQueueDoStats() {
+        return queue.isDoStats();
+    }
+    /**
+     * @param doStats The doStats to set.
+     */
+    public void setQueueDoStats(boolean doStats) {
+        queue.setDoStats(doStats);
+    }
+    /**
+     * @return Returns the timeWait.
+     */
+    public boolean isQueueTimeWait() {
+        return queue.isTimeWait();
+    }
+    /**
+     * @param timeWait The timeWait to set.
+     */
+    public void setQueueTimeWait(boolean timeWait) {
+        queue.setTimeWait(timeWait);
+    }
+        
+    /**
+     * @return Returns the inQueueCounter.
+     */
+    public int getMaxQueueLength() {
+        return queue.getMaxQueueLength();
+    }
+
+    /**
+     * @param length max queue length
+     */
+    public void setMaxQueueLength(int length) {
+        queue.setMaxQueueLength(length);
+    }
+
+    /**
+     * @return Returns the add wait times.
+     */
+    public long getQueueAddWaitTime() {
+        return queue.getAddWait();
+    }
+
+    /**
+     * @return Returns the add wait times.
+     */
+    public long getQueueRemoveWaitTime() {
+        return queue.getRemoveWait();
+    }
+
+    /**
+     * @return Returns the inQueueCounter.
+     */
+    public long getInQueueCounter() {
+        return inQueueCounter;
+    }
+
+    /**
+     * @return Returns the outQueueCounter.
+     */
+    public long getOutQueueCounter() {
+        return outQueueCounter;
+    }
+
+    /**
+     * @return Returns the queueSize.
+     */
+    public int getQueueSize() {
+        return queue.getSize();
+    }
+
+    /**
+     * change active the queue Thread priority 
+     * @param threadPriority value must be between MIN and MAX Thread Priority
+     * @exception IllegalArgumentException
+     */
+    public void setThreadPriority(int threadPriority) {
+        if (log.isDebugEnabled())
+            log.debug(sm.getString("FastAsyncSocketSender.setThreadPriority",
+                    getAddress().getHostAddress(), new Integer(getPort()),
+                    new Integer(threadPriority)));
+        if (threadPriority < Thread.MIN_PRIORITY) {
+            throw new IllegalArgumentException(sm.getString(
+                    "FastAsyncSocketSender.min.exception", getAddress()
+                            .getHostAddress(), new Integer(getPort()),
+                    new Integer(threadPriority)));
+        } else if (threadPriority > Thread.MAX_PRIORITY) {
+            throw new IllegalArgumentException(sm.getString(
+                    "FastAsyncSocketSender.max.exception", getAddress()
+                            .getHostAddress(), new Integer(getPort()),
+                    new Integer(threadPriority)));
+        }
+        this.threadPriority = threadPriority;
+        if (queueThread != null)
+            queueThread.setPriority(threadPriority);
+    }
+
+    /**
+     * Get the current threadPriority
+     * @return The thread priority
+     */
+    public int getThreadPriority() {
+        return threadPriority;
+    }
+
+    /**
+     * @return Returns the queuedNrOfBytes.
+     */
+    public long getQueuedNrOfBytes() {
+        if(queueThread != null)
+            return queueThread.getQueuedNrOfBytes();
+        return 0l ;
+    }
+
+    // --------------------------------------------------------- Public Methods
+
+    /**
+     * Connect to socket and start background thread to push queued messages
+     * 
+     * @see org.apache.catalina.cluster.tcp.IDataSender#connect()
+     */
+    public void connect() throws java.io.IOException {
+        super.connect();
+        checkThread();
+        if(!queue.isEnabled())
+            queue.start() ;
+    }
+
+    /**
+     * Disconnect socket ad stop queue thread
+     * 
+     * @see org.apache.catalina.cluster.tcp.IDataSender#disconnect()
+     */
+    public void disconnect() {
+        stopThread();
+        // delete "remove" lock at queue
+        queue.stop() ;
+        // enable that sendMessage can add new messages
+        queue.start() ;
+        // close socket
+        super.disconnect();
+    }
+
+    /**
+     * Send message to queue for later sending.
+     * 
+     * @see org.apache.catalina.cluster.tcp.DataSender#pushMessage(ClusterData)
+     */
+    public void sendMessage(ClusterData data)
+            throws java.io.IOException {
+        queue.add(data.getUniqueId(), data);
+        synchronized (this) {
+            inQueueCounter++;
+            if(queueThread != null)
+                queueThread.incQueuedNrOfBytes(data.getMessage().length);
+        }
+        if (log.isTraceEnabled())
+            log.trace(sm.getString("AsyncSocketSender.queue.message",
+                    getAddress().getHostAddress(), new Integer(getPort()), data.getUniqueId(), new Long(
+                            data.getMessage().length)));
+    }
+
+    /**
+     * Reset sender statistics
+     */
+    public synchronized void resetStatistics() {
+        super.resetStatistics();
+        inQueueCounter = queue.getSize();
+        outQueueCounter = 0;
+        queue.resetStatistics();
+    }
+
+    /**
+     * Name of this SockerSender
+     */
+    public String toString() {
+        StringBuffer buf = new StringBuffer("FastAsyncSocketSender[");
+        buf.append(getAddress().getHostAddress()).append(":").append(getPort()).append("]");
+        return buf.toString();
+    }
+
+    // --------------------------------------------------------- Public Methods
+
+    /**
+     * Start Queue thread as daemon
+     */
+    protected void checkThread() {
+        if (queueThread == null) {
+            if (log.isInfoEnabled())
+                log.info(sm.getString("AsyncSocketSender.create.thread",
+                        getAddress(), new Integer(getPort())));
+            queueThread = new FastQueueThread(this, queue);
+            queueThread.setDaemon(true);
+            queueThread.setPriority(getThreadPriority());
+            queueThread.start();
+        }
+    }
+
+    /**
+     * stop queue worker thread
+     */
+    protected void stopThread() {
+        if (queueThread != null) {
+            queueThread.stopRunning();
+            queueThread = null;
+        }
+    }
+
+    // -------------------------------------------------------- Inner Class
+
+    private class FastQueueThread extends Thread {
+
+        
+        /**
+         * Sender queue
+         */
+        private IQueue queue = null;
+
+        /**
+         * Active sender
+         */
+        private FastAsyncSocketSender sender = null;
+
+        /**
+         * Thread is active
+         */
+        private boolean keepRunning = true;
+
+        /**
+         * Current number of bytes from all queued messages
+         */
+        private long queuedNrOfBytes = 0;
+
+       
+
+        /**
+         * Only use inside FastAsyncSocketSender
+         * @param sender
+         * @param queue
+         */
+        private FastQueueThread(FastAsyncSocketSender sender, IQueue queue) {
+            setName("Cluster-FastAsyncSocketSender-" + (threadCounter++));
+            this.queue = queue;
+            this.sender = sender;
+        }
+        
+        /**
+         * @return Returns the queuedNrOfBytes.
+         */
+        public long getQueuedNrOfBytes() {
+            return queuedNrOfBytes;
+        }
+        
+        protected synchronized void setQueuedNrOfBytes(long queuedNrOfBytes) {
+            this.queuedNrOfBytes = queuedNrOfBytes;
+        }
+
+        protected synchronized void incQueuedNrOfBytes(long size) {
+            queuedNrOfBytes += size;
+        }
+        
+        protected synchronized void decQueuedNrOfBytes(long size) {
+            queuedNrOfBytes -= size;
+        }
+
+
+        /**
+         * Stop backend thread!
+         */
+         public void stopRunning() {
+            keepRunning = false;
+        }
+        
+        
+        /**
+         * Get the objects from queue and send all mesages to the sender.
+         * @see java.lang.Runnable#run()
+         */
+        public void run() {
+            while (keepRunning) {
+                LinkObject entry = getQueuedMessage();
+                if (entry != null) {
+                    pushQueuedMessages(entry);
+                } else {
+                    if (keepRunning) {
+                        log.warn(sm.getString("AsyncSocketSender.queue.empty",
+                                sender.getAddress(), new Integer(sender
+                                        .getPort())));
+                    }
+                }
+            }
+        }
+
+        /**
+         * Get List of queue cluster messages
+         * @return list of cluster messages
+         */
+        protected LinkObject getQueuedMessage() {
+            // get a link list of all queued objects
+            if (log.isTraceEnabled())
+                log.trace("Queuesize before=" + ((FastQueue) queue).getSize());
+            LinkObject entry = queue.remove();
+            if (log.isTraceEnabled())
+                log.trace("Queuesize after=" + ((FastQueue) queue).getSize());
+            return entry;
+        }
+
+        /**
+         * @param entry
+         */
+        protected void pushQueuedMessages(LinkObject entry) {
+            do {
+                int messagesize = 0;
+                try {
+                    ClusterData data = (ClusterData) entry.data();
+                    messagesize = data.getMessage().length;
+                    sender.pushMessage(data);
+                } catch (Exception x) {
+                    log.warn(sm.getString(
+                            "AsyncSocketSender.send.error", entry
+                                    .getKey()), x);
+                } finally {
+                    outQueueCounter++;
+                    decQueuedNrOfBytes(messagesize);
+                }
+                entry = entry.next();
+            } while (entry != null);
+        }
+
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/tcp/IDataSender.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/tcp/IDataSender.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/tcp/IDataSender.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,45 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.cluster.tcp;
+
+/**
+ * @author Peter Rossbach
+ * @version $Revision: 303993 $ $Date: 2005-07-16 16:05:54 -0500 (Sat, 16 Jul 2005) $
+ * @since 5.5.7
+ */
+
+public interface IDataSender
+{
+    public void setAddress(java.net.InetAddress address);
+    public java.net.InetAddress getAddress();
+    public void setPort(int port);
+    public int getPort();
+    public void connect() throws java.io.IOException;
+    public void disconnect();
+    public void sendMessage(ClusterData data) throws java.io.IOException;
+    public boolean isConnected();
+    public void setSuspect(boolean suspect);
+    public boolean getSuspect();
+    public void setAckTimeout(long timeout);
+    public long getAckTimeout();
+    public boolean isWaitForAck();
+    public void setWaitForAck(boolean isWaitForAck);
+    public boolean checkKeepAlive();
+    public String getDomain() ;
+    public void setDomain(String domain) ;
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/tcp/IDataSenderFactory.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/tcp/IDataSenderFactory.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/tcp/IDataSenderFactory.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,185 @@
+/*
+ * Copyright 1999,2004-2005 The Apache Software Foundation.
+ * 
+ * Licensed 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.cluster.tcp;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.reflect.Constructor;
+import java.net.InetAddress;
+import java.util.Iterator;
+import java.util.Properties;
+
+import org.apache.catalina.cluster.Member;
+import org.apache.catalina.util.StringManager;
+
+/**
+ * Create DataSender for different modes. DataSender factory load mode list from 
+ * <code>org/apache/catalina/cluster/tcp/DataSenders.properties</code> resource.
+ * 
+ * @author Peter Rossbach
+ * @version $Revision: 304032 $ $Date: 2005-07-27 10:11:55 -0500 (Wed, 27 Jul 2005) $
+ * @since 5.5.7
+ */
+public class IDataSenderFactory {
+
+    private static org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory
+            .getLog(IDataSenderFactory.class);
+    
+    private static final String DATASENDERS_PROPERTIES = "org/apache/catalina/cluster/tcp/DataSenders.properties";
+    public static final String SYNC_MODE = "synchronous";
+    public static final String ASYNC_MODE = "asynchronous";
+    public static final String POOLED_SYNC_MODE = "pooled";
+    public static final String FAST_ASYNC_QUEUE_MODE = "fastasyncqueue";
+
+    /**
+     * The string manager for this package.
+     */
+    protected static StringManager sm = StringManager
+            .getManager(Constants.Package);
+
+    // ----------------------------------------------------- Instance Variables
+
+    /**
+     * The descriptive information about this implementation.
+     */
+    private static final String info = "IDataSenderFactory/2.0";
+
+    private IDataSenderFactory() {
+    }
+
+    private Properties senderModes;
+
+    private static IDataSenderFactory factory ;
+
+    static {
+        factory = new IDataSenderFactory();
+        factory.loadSenderModes();
+    }
+
+    // ------------------------------------------------------------- Properties
+
+    /**
+     * Return descriptive information about this implementation and the
+     * corresponding version number, in the format
+     * <code>&lt;description&gt;/&lt;version&gt;</code>.
+     */
+    public static String getInfo() {
+        return (info);
+    }
+    
+    // ------------------------------------------------------------- static
+
+    /**
+     * Create a new DataSender
+     * @param mode replicaton mode 
+     * @param mbr sender target
+     * @return new sender object
+     * @throws java.io.IOException
+     */
+    public synchronized static IDataSender getIDataSender(String mode,
+            Member mbr) throws java.io.IOException {
+       // Identify the class name of the DataSender we should configure
+       IDataSender sender = factory.getSender(mode,mbr);
+       if(sender == null)
+           throw new java.io.IOException("Invalid replication mode=" + mode);          
+       return sender ;    
+    }
+
+    /**
+     * Check that mode is valid
+     * @param mode
+     * @return The replication mode (may be null if sender mode)
+     */
+    public static String validateMode(String mode) {
+        if(factory.isSenderMode(mode))
+            return null ;
+        else {
+            StringBuffer buffer = new StringBuffer("Replication mode has to be '");
+            for (Iterator iter = factory.senderModes.keySet().iterator(); iter.hasNext();) {
+                String key = (String) iter.next();  
+                buffer.append(key);
+                if(iter.hasNext())
+                    buffer.append("', '");
+            }
+            return buffer.toString();        
+        }
+    }
+    
+    // ------------------------------------------------------------- private
+
+    private boolean isSenderMode(String mode){
+        return senderModes != null && senderModes.containsKey(mode) ;           
+    }
+
+    private IDataSender getSender(String mode,Member mbr) {
+        IDataSender sender = null;
+        String senderName = null;
+        senderName = senderModes.getProperty(mode);
+        if (senderName != null) {
+
+            // Instantiate and install a data replication sender of the requested class
+            try {
+                Class senderClass = Class.forName(senderName);
+                Class paramTypes[] = new Class[3];
+                paramTypes[0] = Class.forName("java.lang.String");
+                paramTypes[1] = Class.forName("java.net.InetAddress");
+                paramTypes[2] = Integer.TYPE ;
+                Constructor constructor = senderClass.getConstructor(paramTypes);
+                if (constructor != null) {
+                    Object paramValues[] = new Object[3];
+                    paramValues[0] = mbr.getDomain();
+                    paramValues[1] = InetAddress.getByName(mbr.getHost());
+                    paramValues[2] = new Integer(mbr.getPort());
+                    sender = (IDataSender) constructor.newInstance(paramValues);
+                } else {
+                    log.error(sm.getString("IDataSender.senderModes.Instantiate",
+                            senderName));
+                }
+            } catch (Throwable t) {
+                log.error(sm.getString("IDataSender.senderModes.Instantiate",
+                        senderName), t);
+            }
+        } else {
+            log.error(sm.getString("IDataSender.senderModes.Missing", mode));
+        }
+        return sender;
+    }
+
+    private synchronized void loadSenderModes() {
+        // Load our mapping properties if necessary
+        if (senderModes == null) {
+            try {
+                InputStream is = IDataSender.class
+                        .getClassLoader()
+                        .getResourceAsStream(
+                                DATASENDERS_PROPERTIES);
+                if (is != null) {
+                    senderModes = new Properties();
+                    senderModes.load(is);
+                } else {
+                    log.error(sm.getString("IDataSender.senderModes.Resources"));
+                    return;
+                }
+            } catch (IOException e) {
+                log.error(sm.getString("IDataSender.senderModes.Resources"), e);
+                return;
+            }
+        }
+
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/tcp/LocalStrings.properties
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/tcp/LocalStrings.properties	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/tcp/LocalStrings.properties	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,72 @@
+AsyncSocketSender.create.thread=Create sender [{0}:{1,number,integer}] queue thread to tcp background replication
+AsyncSocketSender.queue.message=Queue message to [{0}:{1,number,integer}] id=[{2}] size={3}
+AsyncSocketSender.send.error=Unable to asynchronously send session with id=[{0}] - message will be ignored.
+AsyncSocketSender.queue.empty=Queue in sender [{0}:{1,number,integer}] returned null element!
+cluster.mbean.register.already=MBean {0} already registered!
+FastAsyncSocketSender.setThreadPriority=[{0}:{1,number,integer}] set priority to {2}
+FastAsyncSocketSender.min.exception=[{0}:{1,number,integer}] new priority {2} < MIN_PRIORITY
+FastAsyncSocketSender.max.exception=[{0}:{1,number,integer}] new priority {2} > MAX_PRIORITY
+IDataSender.ack.eof=EOF reached at local port [{0}:{1,number,integer}]
+IDataSender.ack.receive=Got ACK at local port [{0}:{1,number,integer}]
+IDataSender.ack.missing=Unable to read acknowledgement from [{0}:{1,number,integer}] in {2,number,integer} ms. Disconnecting socket, and trying again.
+IDataSender.ack.read=Read wait ack char '{2}' [{0}:{1,number,integer}]
+IDataSender.ack.start=Waiting for ACK message [{0}:{1,number,integer}]
+IDataSender.ack.wrong=Missing correct ACK after 10 bytes read at local port [{0}:{1,number,integer}]
+IDataSender.closeSocket=Sender close socket to [{0}:{1,number,integer}] (close count {2,number,integer})
+IDataSender.connect=Sender connect to [{0}:{1,number,integer}] (connect count {2,number,integer})
+IDataSender.create=Create sender [{0}:{1,number,integer}]
+IDataSender.disconnect=Sender disconnect from [{0}:{1,number,integer}] (disconnect count {2,number,integer})
+IDataSender.message.disconnect=Message transfered: Sender can't disconnect from [{0}:{1,number,integer}]
+IDataSender.message.create=Message transfered: Sender can't create current socket [{0}:{1,number,integer}]
+IDataSender.openSocket=Sender open socket to [{0}:{1,number,integer}] (open count {2,number,integer})
+IDataSender.openSocket.failure=Open sender socket [{0}:{1,number,integer}] failure! (open failure count {2,number,integer})
+IDataSender.send.again=Send data again to [{0}:{1,number,integer}]
+IDataSender.send.crash=Send message crashed [{0}:{1,number,integer}] type=[{2}], id=[{3}]
+IDataSender.send.message=Send message to [{0}:{1,number,integer}] id=[{2}] size={3,number,integer}
+IDataSender.send.lost=Message lost: [{0}:{1,number,integer}] type=[{2}], id=[{3}]
+IDataSender.senderModes.Configured=Configured a data replication sender for mode {0}
+IDataSender.senderModes.Instantiate=Can't instantiate a data replication sender of class {0}
+IDataSender.senderModes.Missing=Can't configure a data replication sender for mode {0}
+IDataSender.senderModes.Resources=Can't load data replication sender mapping list
+IDataSender.stats=Send stats from [{0}:{1,number,integer}], Nr of bytes sent={2,number,integer} over {3} = {4,number,integer} bytes/request, processing time {5,number,integer} msec, avg processing time {6,number,integer} msec
+PoolSocketSender.senderQueue.sender.failed=PoolSocketSender create new sender to [{0}:{1,number,integer}] failed
+PoolSocketSender.noMoreSender=No socket sender available for client [{0}:{1,number,integer}] did it disappeared?
+ReplicationTransmitter.getProperty=get property {0}
+ReplicationTransmitter.setProperty=set property {0}: {1} old value {2}
+ReplicationTransmitter.started=Start ClusterSender at cluster {0} with name {1}
+ReplicationTransmitter.stopped=Stopped ClusterSender at cluster {0} with name {1}
+ReplicationValve.crossContext.add=add Cross Context session replication container to replicationValve threadlocal
+ReplicationValve.crossContext.registerSession=register Cross context session id={0} from context {1}
+ReplicationValve.crossContext.remove=remove Cross Context session replication container from replicationValve threadlocal
+ReplicationValve.crossContext.sendDelta=send Cross Context session delta from context {0}.
+ReplicationValve.filter.loading=Loading request filters={0}
+ReplicationValve.filter.token=Request filter={0}
+ReplicationValve.filter.token.failure=Unable to compile filter={0}
+ReplicationValve.invoke.uri=Invoking replication request on {0}
+ReplicationValve.nocluster=No cluster configured for this request.
+ReplicationValve.resetDeltaRequest=Cluster is standalone: reset Session Request Delta at context {0}
+ReplicationValve.send.failure=Unable to perform replication request.
+ReplicationValve.send.invalid.failure=Unable to send session [id={0}] invalid message over cluster.
+ReplicationValve.session.found=Context {0}: Found session {1} but it isn't a ClusterSession.
+ReplicationValve.session.indicator=Context {0}: Primarity of session {1} in request attribute {2} is {3}.
+ReplicationValve.session.invalid=Context {0}: Requested session {1} is invalid, removed or not replicated at this node.
+ReplicationValve.stats=Average request time= {0} ms for Cluster overhead time={1} ms for {2} requests {3} filter requests {4} send requests {5} cross context requests (Request={6} ms Cluster={7} ms).
+SimpleTcpCluster.event.log=Cluster receive listener event {0} with data {1}
+SimpleTcpCluster.getProperty=get property {0}
+SimpleTcpCluster.setProperty=set property {0}: {1} old value {2}
+SimpleTcpCluster.default.addClusterListener=Add Default ClusterListener at cluster {0}
+SimpleTcpCluster.default.addClusterValves=Add Default ClusterValves at cluster {0}
+SimpleTcpCluster.default.addClusterReceiver=Add Default ClusterReceiver at cluster {0}
+SimpleTcpCluster.default.addClusterSender=Add Default ClusterSender at cluster {0}
+SimpleTcpCluster.default.addMembershipService=Add Default Membership Service at cluster {0}
+SimpleTcpCluster.log.receive=RECEIVE {0,date}:{0,time} {1,number} {2}:{3,number,integer} {4} {5}
+SimpleTcpCluster.log.send=SEND {0,date}:{0,time} {1,number} {2}:{3,number,integer} {4} 
+SimpleTcpCluster.log.send.all=SEND {0,date}:{0,time} {1,number} - {2}
+SocketReplictionListener.allreadyExists=ServerSocket [{0}:{1}] allready started!
+SocketReplictionListener.accept.failure=ServerSocket [{0}:{1}] - Exception to start thread or accept server socket
+SocketReplictionListener.open=Open Socket at [{0}:{1}]
+SocketReplictionListener.openclose.failure=ServerSocket [{0}:{1}] - Exception to open or close server socket
+SocketReplictionListener.portbusy=Port busy at [{0}:{i}] - reason [{2}]
+SocketReplictionListener.serverSocket.notExists=Fatal error: Receiver socket not bound address={0} port={1} maxport={2}
+SocketReplictionListener.timeout=Receiver ServerSocket no started [{0}:{1}] - reason: timeout={2} or listen={3}
+SocketReplictionListener.unlockSocket.failure=UnLocksocket failure at ServerSocket [{0:{1}]

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/tcp/PooledSocketSender.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/tcp/PooledSocketSender.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/tcp/PooledSocketSender.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,268 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.cluster.tcp;
+
+import java.io.IOException;
+import java.net.InetAddress;
+import java.util.LinkedList;
+
+/**
+ * Send cluster messages with a pool of sockets (25).
+ * 
+ * FIXME support processing stats
+ * 
+ * @author Filip Hanik
+ * @author Peter Rossbach
+ * @version 1.2
+ */
+
+public class PooledSocketSender extends DataSender {
+
+    private static org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory
+            .getLog(org.apache.catalina.cluster.tcp.PooledSocketSender.class);
+
+    /**
+     * The descriptive information about this implementation.
+     */
+    private static final String info = "PooledSocketSender/2.0";
+
+    // ----------------------------------------------------- Instance Variables
+
+    private int maxPoolSocketLimit = 25;
+
+    private SenderQueue senderQueue = null;
+    
+    //  ----------------------------------------------------- Constructor
+
+   /**
+    * @param domain replication cluster domain (session domain)
+    * @param host replication node tcp address
+    * @param port replication node tcp port
+    */
+    public PooledSocketSender(String domain,InetAddress host, int port) {
+        super(domain,host, port);
+        senderQueue = new SenderQueue(this, maxPoolSocketLimit);
+    }
+   
+    //  ----------------------------------------------------- Public Properties
+
+    /**
+     * Return descriptive information about this implementation and the
+     * corresponding version number, in the format
+     * <code>&lt;description&gt;/&lt;version&gt;</code>.
+     */
+    public String getInfo() {
+
+        return (info);
+
+    }
+
+    public void setMaxPoolSocketLimit(int limit) {
+        maxPoolSocketLimit = limit;
+        senderQueue.setLimit(limit);
+    }
+
+    public int getMaxPoolSocketLimit() {
+        return maxPoolSocketLimit;
+    }
+
+    public int getInPoolSize() {
+        return senderQueue.getInPoolSize();
+    }
+
+    public int getInUsePoolSize() {
+        return senderQueue.getInUsePoolSize();
+    }
+
+    //  ----------------------------------------------------- Public Methode
+
+    public synchronized void connect() throws java.io.IOException {
+        //do nothing, happens in the socket sender itself
+        senderQueue.open();
+        setSocketConnected(true);
+        connectCounter++;
+    }
+
+    public synchronized void disconnect() {
+        senderQueue.close();
+        setSocketConnected(false);
+        disconnectCounter++;
+    }
+
+    /**
+     * send message and use a pool of SocketSenders
+     * 
+     * @param messageId Message unique identifier
+     * @param data Message data
+     * @throws java.io.IOException
+     */
+    public void sendMessage(ClusterData data) throws IOException {
+        //get a socket sender from the pool
+        if(!isConnected()) {
+            synchronized(this) {
+                if(!isConnected())
+                    connect();
+            }
+        }
+        SocketSender sender = senderQueue.getSender(0);
+        if (sender == null) {
+            log.warn(sm.getString("PoolSocketSender.noMoreSender", this.getAddress(), new Integer(this.getPort())));
+            return;
+        }
+        //send the message
+        try {
+            sender.sendMessage(data);
+        } finally {
+            //return the connection to the pool
+            senderQueue.returnSender(sender);
+        }
+        addStats(data.getMessage().length);
+    }
+
+    public String toString() {
+        StringBuffer buf = new StringBuffer("PooledSocketSender[");
+        buf.append(getAddress()).append(":").append(getPort()).append("]");
+        return buf.toString();
+    }
+
+    //  ----------------------------------------------------- Inner Class
+
+    private class SenderQueue {
+        private int limit = 25;
+
+        PooledSocketSender parent = null;
+
+        private LinkedList queue = new LinkedList();
+
+        private LinkedList inuse = new LinkedList();
+
+        private Object mutex = new Object();
+
+        private boolean isOpen = true;
+
+        public SenderQueue(PooledSocketSender parent, int limit) {
+            this.limit = limit;
+            this.parent = parent;
+        }
+
+        /**
+         * @return Returns the limit.
+         */
+        public int getLimit() {
+            return limit;
+        }
+        /**
+         * @param limit The limit to set.
+         */
+        public void setLimit(int limit) {
+            this.limit = limit;
+        }
+        /**
+         * @return
+         */
+        public int getInUsePoolSize() {
+            return inuse.size();
+        }
+
+        /**
+         * @return
+         */
+        public int getInPoolSize() {
+            return queue.size();
+        }
+
+        public SocketSender getSender(long timeout) {
+            SocketSender sender = null;
+            long start = System.currentTimeMillis();
+            long delta = 0;
+            do {
+                synchronized (mutex) {
+                    if (!isOpen)
+                        throw new IllegalStateException(
+                                "Socket pool is closed.");
+                    if (queue.size() > 0) {
+                        sender = (SocketSender) queue.removeFirst();
+                    } else if (inuse.size() < limit) {
+                        sender = getNewSocketSender();
+                    } else {
+                        try {
+                            mutex.wait(timeout);
+                        } catch (Exception x) {
+                            PooledSocketSender.log.warn(sm.getString("PoolSocketSender.senderQueue.sender.failed",parent.getAddress(),new Integer(parent.getPort())),x);
+                        }//catch
+                    }//end if
+                    if (sender != null) {
+                        inuse.add(sender);
+                    }
+                }//synchronized
+                delta = System.currentTimeMillis() - start;
+            } while ((isOpen) && (sender == null)
+                    && (timeout == 0 ? true : (delta < timeout)));
+            //to do
+            return sender;
+        }
+
+        public void returnSender(SocketSender sender) {
+            //to do
+            synchronized (mutex) {
+                queue.add(sender);
+                inuse.remove(sender);
+                mutex.notify();
+            }
+        }
+
+        private SocketSender getNewSocketSender() {
+            //new SocketSender(
+            SocketSender sender = new SocketSender(getDomain(),
+                                                   parent.getAddress(), 
+                                                   parent.getPort(),
+                                                   parent.getSenderState() );
+            sender.setKeepAliveMaxRequestCount(parent
+                    .getKeepAliveMaxRequestCount());
+            sender.setKeepAliveTimeout(parent.getKeepAliveTimeout());
+            sender.setAckTimeout(parent.getAckTimeout());
+            sender.setWaitForAck(parent.isWaitForAck());
+            sender.setResend(parent.isResend());
+            return sender;
+
+        }
+
+        public void close() {
+            synchronized (mutex) {
+                for (int i = 0; i < queue.size(); i++) {
+                    SocketSender sender = (SocketSender) queue.get(i);
+                    sender.disconnect();
+                }//for
+                for (int i = 0; i < inuse.size(); i++) {
+                    SocketSender sender = (SocketSender) inuse.get(i);
+                    sender.disconnect();
+                }//for
+                queue.clear();
+                inuse.clear();
+                isOpen = false;
+                mutex.notifyAll();
+            }
+        }
+
+        public void open() {
+            synchronized (mutex) {
+                isOpen = true;
+                mutex.notifyAll();
+            }
+        }
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/tcp/ReplicationListener.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/tcp/ReplicationListener.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/tcp/ReplicationListener.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,254 @@
+/*
+ * Copyright 1999,2004-2005 The Apache Software Foundation.
+ * 
+ * Licensed 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.cluster.tcp;
+
+
+import java.net.InetSocketAddress;
+import java.net.ServerSocket;
+import java.nio.channels.SelectableChannel;
+import java.nio.channels.SelectionKey;
+import java.nio.channels.Selector;
+import java.nio.channels.ServerSocketChannel;
+import java.nio.channels.SocketChannel;
+import java.util.Iterator;
+
+import org.apache.catalina.cluster.io.ObjectReader;
+
+/**
+* FIXME i18n log messages
+* FIXME jmx support
+* @author Peter Rossbach
+* @author Filip Hanik
+* @version $Revision: 380229 $ $Date: 2006-02-23 15:28:29 -0600 (Thu, 23 Feb 2006) $
+*/
+public class ReplicationListener extends ClusterReceiverBase
+{
+
+    /**
+     * The descriptive information about this implementation.
+     */
+    private static final String info = "ReplicationListener/1.2";
+    
+    private ThreadPool pool = null;
+    private int tcpThreadCount;
+    private long tcpSelectorTimeout;    
+    private Selector selector = null;
+    
+    private Object interestOpsMutex = new Object();
+    
+    public ReplicationListener() {
+    }
+    
+    /**
+     * Return descriptive information about this implementation and the
+     * corresponding version number, in the format
+     * <code>&lt;description&gt;/&lt;version&gt;</code>.
+     */
+    public String getInfo() {
+
+        return (info);
+
+    }
+ 
+    public long getTcpSelectorTimeout() {
+        return tcpSelectorTimeout;
+    }
+    public void setTcpSelectorTimeout(long tcpSelectorTimeout) {
+        this.tcpSelectorTimeout = tcpSelectorTimeout;
+    }
+    public int getTcpThreadCount() {
+        return tcpThreadCount;
+    }
+    public void setTcpThreadCount(int tcpThreadCount) {
+        this.tcpThreadCount = tcpThreadCount;
+    }
+    public Object getInterestOpsMutex() {
+        return interestOpsMutex;
+    }
+
+    /**
+     * start cluster receiver
+     * @throws Exception
+     * @see org.apache.catalina.cluster.ClusterReceiver#start()
+     */
+    public void start() {
+            try {
+                pool = new ThreadPool(tcpThreadCount, TcpReplicationThread.class, interestOpsMutex);
+            } catch (Exception e) {
+                log.error("ThreadPool can initilzed. Listener not started",e);
+                return ;
+            }
+            super.start() ;
+     }
+    
+
+    /**
+     * get data from channel and store in byte array
+     * send it to cluster
+     * @throws IOException
+     * @throws java.nio.channels.ClosedChannelException
+     */
+    protected void listen ()
+        throws Exception
+    {
+        if (doListen) {
+            log.warn("ServerSocketChannel allready started");
+            return;
+        }
+        doListen=true;
+        // allocate an unbound server socket channel
+        ServerSocketChannel serverChannel = ServerSocketChannel.open();
+        // Get the associated ServerSocket to bind it with
+        ServerSocket serverSocket = serverChannel.socket();
+        // create a new Selector for use below
+        selector = Selector.open();
+        // set the port the server channel will listen to
+        serverSocket.bind (new InetSocketAddress (getBind(),getTcpListenPort()));
+        // set non-blocking mode for the listening socket
+        serverChannel.configureBlocking (false);
+        // register the ServerSocketChannel with the Selector
+        serverChannel.register (selector, SelectionKey.OP_ACCEPT);
+        while (doListen && selector != null) {
+            // this may block for a long time, upon return the
+            // selected set contains keys of the ready channels
+            try {
+
+                int n = selector.select(tcpSelectorTimeout);
+                if (n == 0) {
+                    //there is a good chance that we got here 
+                    //because the TcpReplicationThread called
+                    //selector wakeup().
+                    //if that happens, we must ensure that that
+                    //thread has enough time to call interestOps
+                    synchronized (interestOpsMutex) {
+                        //if we got the lock, means there are no
+                        //keys trying to register for the 
+                        //interestOps method
+                    }
+                    continue; // nothing to do
+                }
+                // get an iterator over the set of selected keys
+                Iterator it = selector.selectedKeys().iterator();
+                // look at each key in the selected set
+                while (it.hasNext()) {
+                    SelectionKey key = (SelectionKey) it.next();
+                    // Is a new connection coming in?
+                    if (key.isAcceptable()) {
+                        ServerSocketChannel server =
+                            (ServerSocketChannel) key.channel();
+                        SocketChannel channel = server.accept();
+                        Object attach = new ObjectReader(channel, selector,
+                                    this) ;
+                        registerChannel(selector,
+                                        channel,
+                                        SelectionKey.OP_READ,
+                                        attach);
+                    }
+                    // is there data to read on this channel?
+                    if (key.isReadable()) {
+                        readDataFromSocket(key);
+                    } else {
+                        key.interestOps(key.interestOps() & (~SelectionKey.OP_WRITE));
+                    }
+
+                    // remove key from selected set, it's been handled
+                    it.remove();
+                }
+            } catch (java.nio.channels.ClosedSelectorException cse) {
+                // ignore is normal at shutdown or stop listen socket
+            } catch (java.nio.channels.CancelledKeyException nx) {
+                log.warn(
+                    "Replication client disconnected, error when polling key. Ignoring client.");
+            } catch (Exception x) {
+                log.error("Unable to process request in ReplicationListener", x);
+            }
+
+        }
+        serverChannel.close();
+        if(selector != null)
+            selector.close();
+    }
+
+    /**
+     * Close Selector.
+     *
+     * @see org.apache.catalina.cluster.tcp.ClusterReceiverBase#stopListening()
+     */
+    protected void stopListening() {
+        // Bugzilla 37529: http://issues.apache.org/bugzilla/show_bug.cgi?id=37529
+        doListen = false;
+        if ( selector != null ) {
+            try {
+                for(int i = 0; i < getTcpThreadCount(); i++) {
+                    selector.wakeup();
+                }
+                selector.close();
+            } catch ( Exception x ) {
+                log.error("Unable to close cluster receiver selector.",x);
+            } finally {
+                selector = null;                
+            }
+        }
+   }
+        
+    // ----------------------------------------------------------
+
+    /**
+     * Register the given channel with the given selector for
+     * the given operations of interest
+     */
+    protected void registerChannel (Selector selector,
+                                    SelectableChannel channel,
+                                    int ops,
+                                    Object attach)
+    throws Exception {
+        if (channel == null) return; // could happen
+        // set the new channel non-blocking
+        channel.configureBlocking (false);
+        // register it with the selector
+        channel.register (selector, ops, attach);
+    }
+
+    // ----------------------------------------------------------
+
+    /**
+     * Sample data handler method for a channel with data ready to read.
+     * @param key A SelectionKey object associated with a channel
+     *  determined by the selector to be ready for reading.  If the
+     *  channel returns an EOF condition, it is closed here, which
+     *  automatically invalidates the associated key.  The selector
+     *  will then de-register the channel on the next select call.
+     */
+    protected void readDataFromSocket (SelectionKey key)
+        throws Exception
+    {
+        TcpReplicationThread worker = (TcpReplicationThread)pool.getWorker();
+        if (worker == null) {
+            // No threads available, do nothing, the selection
+            // loop will keep calling this method until a
+            // thread becomes available.
+            // FIXME: This design could be improved.
+            if(log.isDebugEnabled())
+                log.debug("No TcpReplicationThread available");
+        } else {
+            // invoking this wakes up the worker thread then returns
+            worker.serviceChannel(key, isSendAck());
+        }
+    }
+
+    
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/tcp/ReplicationTransmitter.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/tcp/ReplicationTransmitter.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/tcp/ReplicationTransmitter.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,898 @@
+/*
+ * Copyright 1999,2004-2005 The Apache Software Foundation.
+ * 
+ * Licensed 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.cluster.tcp;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.ObjectOutputStream;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.zip.GZIPOutputStream;
+
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+
+import org.apache.catalina.Container;
+import org.apache.catalina.cluster.ClusterMessage;
+import org.apache.catalina.cluster.ClusterSender;
+import org.apache.catalina.cluster.Member;
+import org.apache.catalina.cluster.util.IDynamicProperty;
+import org.apache.catalina.core.StandardHost;
+import org.apache.catalina.util.StringManager;
+import org.apache.tomcat.util.IntrospectionUtils;
+
+/**
+ * Transmit message to ohter cluster members create sender from replicationMode
+ * type 
+ * FIXME i18n log messages
+ * FIXME compress data depends on message type and size 
+ * FIXME send very big messages at some block see FarmWarDeployer!
+ * TODO pause and resume senders
+ * 
+ * @author Peter Rossbach
+ * @author Filip Hanik
+ * @version $Revision: 418134 $ $Date: 2006-06-29 15:54:33 -0500 (Thu, 29 Jun 2006) $
+ */
+public class ReplicationTransmitter implements ClusterSender,IDynamicProperty {
+    private static org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory
+            .getLog(ReplicationTransmitter.class);
+
+    /**
+     * The descriptive information about this implementation.
+     */
+    private static final String info = "ReplicationTransmitter/3.0";
+
+    /**
+     * The string manager for this package.
+     */
+    protected StringManager sm = StringManager.getManager(Constants.Package);
+
+    private Map map = new HashMap();
+
+    public ReplicationTransmitter() {
+    }
+
+    /**
+     * number of transmitted messages>
+     */
+    private long nrOfRequests = 0;
+
+    /**
+     * number of transmitted bytes
+     */
+    private long totalBytes = 0;
+
+    /**
+     * number of failure
+     */
+    private long failureCounter = 0;
+
+    /**
+     * Iteration count for background processing.
+     */
+    private int count = 0;
+
+    /**
+     * Frequency of the check sender keepAlive Socket Status.
+     */
+    protected int processSenderFrequency = 2;
+
+    /**
+     * current sender replication mode
+     */
+    private String replicationMode;
+
+    /**
+     * sender default ackTimeout
+     */
+    private long ackTimeout = 15000; //15 seconds by default
+
+    /**
+     * enabled wait for ack
+     */
+    private boolean waitForAck = true;
+
+    /**
+     * autoConnect sender when next message send
+     */
+    private boolean autoConnect = false;
+
+    /**
+     * Compress message data bytes
+     */
+    private boolean compress = false;
+
+    /**
+     * doTransmitterProcessingStats
+     */
+    protected boolean doTransmitterProcessingStats = false;
+
+    /**
+     * proessingTime
+     */
+    protected long processingTime = 0;
+    
+    /**
+     * min proessingTime
+     */
+    protected long minProcessingTime = Long.MAX_VALUE ;
+
+    /**
+     * max proessingTime
+     */
+    protected long maxProcessingTime = 0;
+   
+    /**
+     * dynamic sender <code>properties</code>
+     */
+    private Map properties = new HashMap();
+
+    /**
+     * my cluster
+     */
+    private SimpleTcpCluster cluster;
+
+    /**
+     * Transmitter Mbean name
+     */
+    private ObjectName objectName;
+
+    // ------------------------------------------------------------- Properties
+
+    /**
+     * Return descriptive information about this implementation and the
+     * corresponding version number, in the format
+     * <code>&lt;description&gt;/&lt;version&gt;</code>.
+     */
+    public String getInfo() {
+        return (info);
+    }
+
+    /**
+     * @return Returns the nrOfRequests.
+     */
+    public long getNrOfRequests() {
+        return nrOfRequests;
+    }
+
+    /**
+     * @return Returns the totalBytes.
+     */
+    public long getTotalBytes() {
+        return totalBytes;
+    }
+
+    /**
+     * @return Returns the failureCounter.
+     */
+    public long getFailureCounter() {
+        return failureCounter;
+    }
+
+    /**
+     * current replication mode
+     * 
+     * @return The mode
+     */
+    public String getReplicationMode() {
+        return replicationMode;
+    }
+
+    /**
+     * set replication Mode (pooled, synchonous, asynchonous, fastasyncqueue)
+     * 
+     * @see IDataSenderFactory#validateMode(String)
+     * @param mode
+     */
+    public void setReplicationMode(String mode) {
+        String msg = IDataSenderFactory.validateMode(mode);
+        if (msg == null) {
+            if (log.isDebugEnabled())
+                log.debug("Setting replication mode to " + mode);
+            this.replicationMode = mode;
+        } else
+            throw new IllegalArgumentException(msg);
+
+    }
+
+    /**
+     * @return Returns the avg processingTime/nrOfRequests.
+     */
+    public double getAvgProcessingTime() {
+        if ( nrOfRequests > 0 ) {
+            return ((double)processingTime) / nrOfRequests;
+        } else {
+            return 0;
+        }
+    }
+ 
+    /**
+     * @return Returns the maxProcessingTime.
+     */
+    public long getMaxProcessingTime() {
+        return maxProcessingTime;
+    }
+    
+    /**
+     * @return Returns the minProcessingTime.
+     */
+    public long getMinProcessingTime() {
+        return minProcessingTime;
+    }
+    
+    /**
+     * @return Returns the processingTime.
+     */
+    public long getProcessingTime() {
+        return processingTime;
+    }
+    
+    /**
+     * @return Returns the doTransmitterProcessingStats.
+     */
+    public boolean isDoTransmitterProcessingStats() {
+        return doTransmitterProcessingStats;
+    }
+    
+    /**
+     * @param doProcessingStats The doTransmitterProcessingStats to set.
+     */
+    public void setDoTransmitterProcessingStats(boolean doProcessingStats) {
+        this.doTransmitterProcessingStats = doProcessingStats;
+    }
+ 
+
+    /**
+     * Transmitter ObjectName
+     * 
+     * @param name
+     */
+    public void setObjectName(ObjectName name) {
+        objectName = name;
+    }
+
+    public ObjectName getObjectName() {
+        return objectName;
+    }
+
+    /**
+     * @return Returns the compress.
+     */
+    public boolean isCompress() {
+        return compress;
+    }
+
+    /**
+     * @param compressMessageData
+     *            The compress to set.
+     */
+    public void setCompress(boolean compressMessageData) {
+        this.compress = compressMessageData;
+    }
+
+    /**
+     * @return Returns the autoConnect.
+     */
+    public boolean isAutoConnect() {
+        return autoConnect;
+    }
+
+    /**
+     * @param autoConnect
+     *            The autoConnect to set.
+     */
+    public void setAutoConnect(boolean autoConnect) {
+        this.autoConnect = autoConnect;
+        setProperty("autoConnect", String.valueOf(autoConnect));
+
+    }
+
+    /**
+     * @return The ack timeout
+     */
+    public long getAckTimeout() {
+        return ackTimeout;
+    }
+
+    /**
+     * @param ackTimeout
+     */
+    public void setAckTimeout(long ackTimeout) {
+        this.ackTimeout = ackTimeout;
+        setProperty("ackTimeout", String.valueOf(ackTimeout));
+    }
+
+    /**
+     * @return Returns the waitForAck.
+     */
+    public boolean isWaitForAck() {
+        return waitForAck;
+    }
+
+    /**
+     * @param waitForAck
+     *            The waitForAck to set.
+     */
+    public void setWaitForAck(boolean waitForAck) {
+        this.waitForAck = waitForAck;
+        setProperty("waitForAck", String.valueOf(waitForAck));
+    }
+
+    
+    /**
+     * @return Returns the processSenderFrequency.
+     */
+    public int getProcessSenderFrequency() {
+        return processSenderFrequency;
+    }
+    
+    /**
+     * @param processSenderFrequency The processSenderFrequency to set.
+     */
+    public void setProcessSenderFrequency(int processSenderFrequency) {
+        this.processSenderFrequency = processSenderFrequency;
+    }
+    
+    /*
+     * configured in cluster
+     * 
+     * @see org.apache.catalina.cluster.ClusterSender#setCatalinaCluster(org.apache.catalina.cluster.tcp.SimpleTcpCluster)
+     */
+    public void setCatalinaCluster(SimpleTcpCluster cluster) {
+        this.cluster = cluster;
+
+    }
+
+    /**
+     * @return True if synchronized sender
+     * @deprecated since version 5.5.7
+     */
+    public boolean getIsSenderSynchronized() {
+        return IDataSenderFactory.SYNC_MODE.equals(replicationMode)
+                || IDataSenderFactory.POOLED_SYNC_MODE.equals(replicationMode);
+    }
+
+    // ------------------------------------------------------------- dynamic
+    // sender property handling
+
+    /**
+     * set config attributes with reflect
+     * 
+     * @param name
+     * @param value
+     */
+    public void setProperty(String name, Object value) {
+        if (log.isTraceEnabled())
+            log.trace(sm.getString("ReplicationTransmitter.setProperty", name,
+                    value, properties.get(name)));
+
+        properties.put(name, value);
+    }
+
+    /**
+     * get current config
+     * 
+     * @param key
+     * @return The property
+     */
+    public Object getProperty(String key) {
+        if (log.isTraceEnabled())
+            log.trace(sm.getString("ReplicationTransmitter.getProperty", key));
+        return properties.get(key);
+    }
+
+    /**
+     * Get all properties keys
+     * 
+     * @return An iterator over the propery name set
+     */
+    public Iterator getPropertyNames() {
+        return properties.keySet().iterator();
+    }
+
+    /**
+     * remove a configured property.
+     * 
+     * @param key
+     */
+    public void removeProperty(String key) {
+        properties.remove(key);
+    }
+
+    // ------------------------------------------------------------- public
+    
+    /**
+     * Send data to one member
+     * FIXME set filtering messages
+     * @see org.apache.catalina.cluster.ClusterSender#sendMessage(org.apache.catalina.cluster.ClusterMessage, org.apache.catalina.cluster.Member)
+     */
+    public void sendMessage(ClusterMessage message, Member member)
+            throws java.io.IOException {       
+        long time = 0 ;
+        if(doTransmitterProcessingStats) {
+            time = System.currentTimeMillis();
+        }
+        try {
+            ClusterData data = serialize(message);
+            String key = getKey(member);
+            IDataSender sender = (IDataSender) map.get(key);
+            sendMessageData(data, sender);
+        } finally {
+            if (doTransmitterProcessingStats) {
+                addProcessingStats(time);
+            }
+        }
+    }
+    
+    /**
+     * Send to all senders at same cluster domain as message from address
+     * @param message Cluster message to send
+     * @since 5.5.10
+     * FIXME Refactor with sendMessage get a sender list from
+     */
+    public void sendMessageClusterDomain(ClusterMessage message) 
+         throws java.io.IOException {
+        long time = 0;
+        if (doTransmitterProcessingStats) {
+            time = System.currentTimeMillis();
+        }
+        try {
+            String domain = message.getAddress().getDomain();
+            if(domain == null)
+                throw new RuntimeException("Domain at member not set");
+            ClusterData data = serialize(message);
+            IDataSender[] senders = getSenders();
+            for (int i = 0; i < senders.length; i++) {
+
+                IDataSender sender = senders[i];
+                if(domain.equals(sender.getDomain())) {
+                    try {
+                        boolean success = sendMessageData(data, sender);
+                    } catch (Exception x) {
+                        //THIS WILL NEVER HAPPEN, as sendMessageData swallows the error
+                    }
+                }
+            }
+        } finally {
+            // FIXME better exception handling
+            if (doTransmitterProcessingStats) {
+                addProcessingStats(time);
+            }
+        }
+    
+    }
+
+    /**
+     * send message to all senders (broadcast)
+     * @see org.apache.catalina.cluster.ClusterSender#sendMessage(org.apache.catalina.cluster.ClusterMessage)
+     * FIXME Refactor with sendMessageClusterDomain!
+     */
+    public void sendMessage(ClusterMessage message)
+            throws java.io.IOException {
+        long time = 0;
+        if (doTransmitterProcessingStats) {
+            time = System.currentTimeMillis();
+        }
+        try {
+            ClusterData data = serialize(message);
+            IDataSender[] senders = getSenders();
+            for (int i = 0; i < senders.length; i++) {
+
+                IDataSender sender = senders[i];
+                try {
+                    sendMessageData(data, sender);
+                } catch (Exception x) {
+                    // FIXME remember exception and send it at finally
+                }
+            }
+        } finally {
+            // FIXME better exception handling
+            if (doTransmitterProcessingStats) {
+                addProcessingStats(time);
+            }
+        }
+    }
+
+    /**
+     * start the sender and register transmitter mbean
+     * 
+     * @see org.apache.catalina.cluster.ClusterSender#start()
+     */
+    public void start() throws java.io.IOException {
+        if (cluster != null) {
+            ObjectName clusterName = cluster.getObjectName();
+            ObjectName transmitterName = null ;
+            try {
+                MBeanServer mserver = cluster.getMBeanServer();
+                Container container = cluster.getContainer();
+                String name = clusterName.getDomain() + ":type=ClusterSender";
+                if (container instanceof StandardHost) {
+                    name += ",host=" + clusterName.getKeyProperty("host");
+                }
+                transmitterName = new ObjectName(name);
+                if (mserver.isRegistered(transmitterName)) {
+                    if (log.isWarnEnabled())
+                        log.warn(sm.getString(
+                                "cluster.mbean.register.already",
+                                transmitterName));
+                    return;
+                }
+                setObjectName(transmitterName);
+                mserver.registerMBean(cluster.getManagedBean(this),
+                        getObjectName());
+                if(log.isInfoEnabled())
+                    log.info(sm.getString("ReplicationTransmitter.started",
+                            clusterName, transmitterName));
+
+            } catch (Exception e) {
+                log.warn(e);
+            }
+        }
+    }
+
+    /*
+     * stop the sender and deregister mbeans (transmitter, senders)
+     * 
+     * @see org.apache.catalina.cluster.ClusterSender#stop()
+     */
+    public synchronized void stop() {
+        Iterator i = map.entrySet().iterator();
+        while (i.hasNext()) {
+            IDataSender sender = (IDataSender) ((java.util.Map.Entry) i.next())
+                    .getValue();
+            try {
+                unregisterSenderMBean(sender);
+                sender.disconnect();
+            } catch (Exception x) {
+            }
+            i.remove();
+        }
+        if (cluster != null && getObjectName() != null) {
+            try {
+                MBeanServer mserver = cluster.getMBeanServer();
+                mserver.unregisterMBean(getObjectName());
+            } catch (Exception e) {
+                log.error(e);
+            }
+            if(log.isInfoEnabled())
+                log.info(sm.getString("ReplicationTransmitter.stopped",
+                        cluster.getObjectName(), getObjectName()));
+        }
+
+    }
+
+    /**
+     * Call transmitter to check for sender socket status
+     * 
+     * @see SimpleTcpCluster#backgroundProcess()
+     */
+    public void backgroundProcess() {
+        count = (count + 1) % processSenderFrequency;
+        if (count == 0) {
+            checkKeepAlive();
+        }
+    }
+
+    /**
+     * Check all DataSender Socket to close socket at keepAlive mode
+     * @see DataSender#checkKeepAlive()
+     */
+    public void checkKeepAlive() {
+        if (map.size() > 0) {
+            java.util.Iterator iter = map.entrySet().iterator();
+            while (iter.hasNext()) {
+                IDataSender sender = (IDataSender) ((java.util.Map.Entry) iter
+                        .next()).getValue();
+                if (sender != null)
+                    sender.checkKeepAlive();
+            }
+        }
+    }
+
+    /**
+     * get all current senders
+     * 
+     * @return The senders
+     */
+    public IDataSender[] getSenders() {
+        java.util.Iterator iter = map.entrySet().iterator();
+        IDataSender[] array = new IDataSender[map.size()];
+        int i = 0;
+        while (iter.hasNext()) {
+            IDataSender sender = (IDataSender) ((java.util.Map.Entry) iter
+                    .next()).getValue();
+            if (sender != null)
+                array[i] = sender;
+            i++;
+        }
+        return array;
+    }
+
+    /**
+     * get all current senders
+     * 
+     * @return The sender object names
+     */
+    public ObjectName[] getSenderObjectNames() {
+        java.util.Iterator iter = map.entrySet().iterator();
+        ObjectName array[] = new ObjectName[map.size()];
+        int i = 0;
+        while (iter.hasNext()) {
+            IDataSender sender = (IDataSender) ((java.util.Map.Entry) iter
+                    .next()).getValue();
+            if (sender != null)
+                array[i] = getSenderObjectName(sender);
+            i++;
+        }
+        return array;
+    }
+
+    /**
+     * Reset sender statistics
+     */
+    public synchronized void resetStatistics() {
+        nrOfRequests = 0;
+        totalBytes = 0;
+        failureCounter = 0;
+        processingTime = 0;
+        minProcessingTime = Long.MAX_VALUE;
+        maxProcessingTime = 0;
+    }
+
+    /**
+     * add new cluster member and create sender ( s. replicationMode) transfer
+     * current properties to sender
+     * 
+     * @see org.apache.catalina.cluster.ClusterSender#add(org.apache.catalina.cluster.Member)
+     */
+    public synchronized void add(Member member) {
+        try {
+            String key = getKey(member);
+            if (!map.containsKey(key)) {
+                IDataSender sender = IDataSenderFactory.getIDataSender(
+                        replicationMode, member);
+                transferSenderProperty(sender);
+                map.put(key, sender);
+                registerSenderMBean(member, sender);
+            }
+        } catch (java.io.IOException x) {
+            log.error("Unable to create and add a IDataSender object.", x);
+        }
+    }
+
+    /**
+     * remove sender from transmitter. ( deregister mbean and disconnect sender )
+     * 
+     * @see org.apache.catalina.cluster.ClusterSender#remove(org.apache.catalina.cluster.Member)
+     */
+    public synchronized void remove(Member member) {
+        String key = getKey(member);
+        IDataSender toberemoved = (IDataSender) map.get(key);
+        if (toberemoved == null)
+            return;
+        unregisterSenderMBean(toberemoved);
+        toberemoved.disconnect();
+        map.remove(key);
+
+    }
+
+    // ------------------------------------------------------------- protected
+
+    /**
+     * calc number of requests and transfered bytes. Log stats all 100 requets
+     * 
+     * @param length
+     */
+    protected synchronized void addStats(int length) {
+        nrOfRequests++;
+        totalBytes += length;
+        if (log.isDebugEnabled() && (nrOfRequests % 100) == 0) {
+            log.debug("Nr of bytes sent=" + totalBytes + " over "
+                    + nrOfRequests + "; avg=" + (totalBytes / nrOfRequests)
+                    + " bytes/request; failures=" + failureCounter);
+        }
+
+    }
+
+    /**
+     * Transfer all properties from transmitter to concrete sender
+     * 
+     * @param sender
+     */
+    protected void transferSenderProperty(IDataSender sender) {
+        for (Iterator iter = getPropertyNames(); iter.hasNext();) {
+            String pkey = (String) iter.next();
+            Object value = getProperty(pkey);
+            IntrospectionUtils.setProperty(sender, pkey, value.toString());
+        }
+    }
+
+    /**
+     * set unique key to find sender
+     * 
+     * @param member
+     * @return concat member.host:member.port
+     */
+    protected String getKey(Member member) {
+        return member.getHost() + ":" + member.getPort();
+    }
+
+    /**
+     * unregsister sendern Mbean
+     * 
+     * @see #getSenderObjectName(IDataSender)
+     * @param sender
+     */
+    protected void unregisterSenderMBean(IDataSender sender) {
+        try {
+            MBeanServer mserver = cluster.getMBeanServer();
+            if (mserver != null) {
+                mserver.unregisterMBean(getSenderObjectName(sender));
+            }
+        } catch (Exception e) {
+            log.warn(e);
+        }
+    }
+
+    /**
+     * register MBean and check it exist (big problem!)
+     * 
+     * @param member
+     * @param sender
+     */
+    protected void registerSenderMBean(Member member, IDataSender sender) {
+        if (member != null && cluster != null) {
+            try {
+                MBeanServer mserver = cluster.getMBeanServer();
+                ObjectName senderName = getSenderObjectName(sender);
+                if (mserver.isRegistered(senderName)) {
+                    if (log.isWarnEnabled())
+                        log.warn(sm.getString(
+                                "cluster.mbean.register.already", senderName));
+                    return;
+                }
+                mserver.registerMBean(cluster.getManagedBean(sender),
+                        senderName);
+            } catch (Exception e) {
+                log.warn(e);
+            }
+        }
+    }
+
+    
+    /**
+     * build sender ObjectName (
+     * engine.domain:type=IDataSender,host="host",senderAddress="receiver.address",senderPort="port" )
+     * 
+     * @param sender
+     * @return The sender object name
+     */
+    protected ObjectName getSenderObjectName(IDataSender sender) {
+        ObjectName senderName = null;
+        try {
+            ObjectName clusterName = cluster.getObjectName();
+            Container container = cluster.getContainer();
+            String name = clusterName.getDomain() + ":type=IDataSender";
+            if (container instanceof StandardHost) {
+                name += ",host=" + clusterName.getKeyProperty("host");
+            }
+            senderName = new ObjectName(name + ",senderAddress="
+                    + sender.getAddress().getHostAddress() + ",senderPort="
+                    + sender.getPort());
+        } catch (Exception e) {
+            log.warn(e);
+        }
+        return senderName;
+    }
+
+    /**
+     * serialize message and add timestamp from message
+     * handle compression
+     * @see GZIPOutputStream
+     * @param msg cluster message
+     * @return cluster message as byte array
+     * @throws IOException
+     * @since 5.5.10
+     */
+    protected ClusterData serialize(ClusterMessage msg) throws IOException {
+        msg.setTimestamp(System.currentTimeMillis());
+        ByteArrayOutputStream outs = new ByteArrayOutputStream();
+        ObjectOutputStream out;
+        GZIPOutputStream gout = null;
+        ClusterData data = new ClusterData();
+        data.setType(msg.getClass().getName());
+        data.setUniqueId(msg.getUniqueId());
+        data.setTimestamp(msg.getTimestamp());
+        data.setCompress(msg.getCompress());
+        data.setResend(msg.getResend());
+        // FIXME add stats: How much comress and uncompress messages and bytes are transfered
+        if ((isCompress() && msg.getCompress() != ClusterMessage.FLAG_FORBIDDEN)
+                || msg.getCompress() == ClusterMessage.FLAG_ALLOWED) {
+            gout = new GZIPOutputStream(outs);
+            out = new ObjectOutputStream(gout);
+        } else {
+            out = new ObjectOutputStream(outs);
+        }
+        out.writeObject(msg);
+        // flush out the gzip stream to byte buffer
+        if(gout != null) {
+            gout.flush();
+            gout.close();
+        }
+        data.setMessage(outs.toByteArray());
+        return data;
+    }
+ 
+
+    /**
+     * Send message to concrete sender. If autoConnect is true, check is
+     * connection broken and the reconnect the complete sender.
+     * <ul>
+     * <li>failure the suspect flag is set true. After successfully sending the
+     * suspect flag is set to false.</li>
+     * <li>Stats is only update after sussesfull sending</li>
+     * </ul>
+     * 
+     * @param data message Data
+     * @param sender concrete message sender
+     * @return true if the message got sent, false otherwise
+     * @throws java.io.IOException If an error occurs
+     */
+    protected boolean sendMessageData(ClusterData data,
+                                   IDataSender sender) throws java.io.IOException {
+        if (sender == null)
+            throw new java.io.IOException("Sender not available. Make sure sender information is available to the ReplicationTransmitter.");
+        try {
+            // deprecated not needed DataSender#pushMessage can handle connection
+            if (autoConnect) {
+                synchronized(sender) {
+                    if(!sender.isConnected())
+                        sender.connect();
+                }
+            }
+            sender.sendMessage(data);
+            sender.setSuspect(false);
+            addStats(data.getMessage().length);
+            return true;
+        } catch (Exception x) {
+            if (!sender.getSuspect()) {
+                if (log.isErrorEnabled() ) log.error("Unable to send replicated message, is member ["+sender.toString()+"] down?",x);
+            } else if (log.isDebugEnabled() ) {
+                log.debug("Unable to send replicated message, is member ["+sender.toString()+"] down?",x);
+            }
+            sender.setSuspect(true);
+            failureCounter++;
+            return false;
+        }
+
+    }
+    /**
+     * Add processing stats times
+     * @param startTime
+     */
+    protected void addProcessingStats(long startTime) {
+        long time = System.currentTimeMillis() - startTime ;
+        if(time < minProcessingTime)
+            minProcessingTime = time ;
+        if( time > maxProcessingTime)
+            maxProcessingTime = time ;
+        processingTime += time ;
+    }
+ 
+ 
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/tcp/ReplicationValve.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/tcp/ReplicationValve.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/tcp/ReplicationValve.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,659 @@
+/*
+ * Copyright 1999,2004-2005 The Apache Software Foundation.
+ * 
+ * Licensed 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.cluster.tcp;
+
+import java.io.IOException;
+import java.util.StringTokenizer;
+import java.util.regex.Pattern;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Iterator;
+import javax.servlet.ServletException;
+
+import org.apache.catalina.Manager;
+import org.apache.catalina.Session;
+import org.apache.catalina.Context;
+import org.apache.catalina.core.StandardContext;
+import org.apache.catalina.cluster.CatalinaCluster;
+import org.apache.catalina.cluster.ClusterManager;
+import org.apache.catalina.cluster.ClusterMessage;
+import org.apache.catalina.cluster.ClusterSession;
+import org.apache.catalina.cluster.ClusterValve;
+import org.apache.catalina.cluster.session.DeltaManager;
+import org.apache.catalina.cluster.session.DeltaSession;
+import org.apache.catalina.connector.Request;
+import org.apache.catalina.connector.Response;
+import org.apache.catalina.util.StringManager;
+import org.apache.catalina.valves.ValveBase;
+
+/**
+ * <p>Implementation of a Valve that logs interesting contents from the
+ * specified Request (before processing) and the corresponding Response
+ * (after processing).  It is especially useful in debugging problems
+ * related to headers and cookies.</p>
+ *
+ * <p>This Valve may be attached to any Container, depending on the granularity
+ * of the logging you wish to perform.</p>
+ *
+ * <p>primaryIndicator=true, then the request attribute <i>org.apache.catalina.cluster.tcp.isPrimarySession.</i>
+ * is set true, when request processing is at sessions primary node.
+ * </p>
+ *
+ * @author Craig R. McClanahan
+ * @author Filip Hanik
+ * @author Peter Rossbach
+ * @version $Revision: 386118 $ $Date: 2006-03-15 11:20:34 -0600 (Wed, 15 Mar 2006) $
+ */
+
+public class ReplicationValve
+    extends ValveBase implements ClusterValve {
+    
+    private static org.apache.commons.logging.Log log =
+        org.apache.commons.logging.LogFactory.getLog( ReplicationValve.class );
+
+    // ----------------------------------------------------- Instance Variables
+
+    /**
+     * The descriptive information related to this implementation.
+     */
+    private static final String info =
+        "org.apache.catalina.cluster.tcp.ReplicationValve/2.0";
+
+
+    /**
+     * The StringManager for this package.
+     */
+    protected static StringManager sm =
+        StringManager.getManager(Constants.Package);
+
+    private CatalinaCluster cluster = null ;
+
+    /**
+     * holds file endings to not call for like images and others
+     */
+    protected java.util.regex.Pattern[] reqFilters = new java.util.regex.Pattern[0];
+    
+    /**
+     * Orginal filter 
+     */
+    protected String filter ;
+    
+    /**
+     * crossContext session container 
+     */
+    protected ThreadLocal crossContextSessions = new ThreadLocal() ;
+    
+    /**
+     * doProcessingStats (default = off)
+     */
+    protected boolean doProcessingStats = false;
+    
+    protected long totalRequestTime = 0;
+    protected long totalSendTime = 0;
+    protected long nrOfRequests = 0;
+    protected long lastSendTime = 0;
+    protected long nrOfFilterRequests = 0;
+    protected long nrOfSendRequests = 0;
+    protected long nrOfCrossContextSendRequests = 0;
+    
+    /**
+     * must primary change indicator set 
+     */
+    protected boolean primaryIndicator = false ;
+    
+    /**
+     * Name of primary change indicator as request attribute
+     */
+    protected String primaryIndicatorName = "org.apache.catalina.cluster.tcp.isPrimarySession";
+   
+    // ------------------------------------------------------------- Properties
+
+    public ReplicationValve() {
+    }
+    
+    /**
+     * Return descriptive information about this Valve implementation.
+     */
+    public String getInfo() {
+
+        return (info);
+
+    }
+    
+    /**
+     * @return Returns the cluster.
+     */
+    public CatalinaCluster getCluster() {
+        return cluster;
+    }
+    
+    /**
+     * @param cluster The cluster to set.
+     */
+    public void setCluster(CatalinaCluster cluster) {
+        this.cluster = cluster;
+    }
+ 
+    /**
+     * @return Returns the filter
+     */
+    public String getFilter() {
+       return filter ;
+    }
+
+    /**
+     * compile filter string to regular expressions
+     * @see Pattern#compile(java.lang.String)
+     * @param filter
+     *            The filter to set.
+     */
+    public void setFilter(String filter) {
+        if (log.isDebugEnabled())
+            log.debug(sm.getString("ReplicationValve.filter.loading", filter));
+        this.filter = filter;
+        StringTokenizer t = new StringTokenizer(filter, ";");
+        this.reqFilters = new Pattern[t.countTokens()];
+        int i = 0;
+        while (t.hasMoreTokens()) {
+            String s = t.nextToken();
+            if (log.isTraceEnabled())
+                log.trace(sm.getString("ReplicationValve.filter.token", s));
+            try {
+                reqFilters[i++] = Pattern.compile(s);
+            } catch (Exception x) {
+                log.error(sm.getString("ReplicationValve.filter.token.failure",
+                        s), x);
+            }
+        }
+    }
+
+    /**
+     * @return Returns the primaryIndicator.
+     */
+    public boolean isPrimaryIndicator() {
+        return primaryIndicator;
+    }
+
+    /**
+     * @param primaryIndicator The primaryIndicator to set.
+     */
+    public void setPrimaryIndicator(boolean primaryIndicator) {
+        this.primaryIndicator = primaryIndicator;
+    }
+    
+    /**
+     * @return Returns the primaryIndicatorName.
+     */
+    public String getPrimaryIndicatorName() {
+        return primaryIndicatorName;
+    }
+    
+    /**
+     * @param primaryIndicatorName The primaryIndicatorName to set.
+     */
+    public void setPrimaryIndicatorName(String primaryIndicatorName) {
+        this.primaryIndicatorName = primaryIndicatorName;
+    }
+    
+    /**
+     * Calc processing stats
+     */
+    public boolean isDoProcessingStats() {
+        return doProcessingStats;
+    }
+
+    /**
+     * Set Calc processing stats
+     * @see #resetStatistics()
+     */
+    public void setDoProcessingStats(boolean doProcessingStats) {
+        this.doProcessingStats = doProcessingStats;
+    }
+
+    /**
+     * @return Returns the lastSendTime.
+     */
+    public long getLastSendTime() {
+        return lastSendTime;
+    }
+    
+    /**
+     * @return Returns the nrOfRequests.
+     */
+    public long getNrOfRequests() {
+        return nrOfRequests;
+    }
+    
+    /**
+     * @return Returns the nrOfFilterRequests.
+     */
+    public long getNrOfFilterRequests() {
+        return nrOfFilterRequests;
+    }
+
+    /**
+     * @return Returns the nrOfCrossContextSendRequests.
+     */
+    public long getNrOfCrossContextSendRequests() {
+        return nrOfCrossContextSendRequests;
+    }
+
+    /**
+     * @return Returns the nrOfSendRequests.
+     */
+    public long getNrOfSendRequests() {
+        return nrOfSendRequests;
+    }
+
+    /**
+     * @return Returns the totalRequestTime.
+     */
+    public long getTotalRequestTime() {
+        return totalRequestTime;
+    }
+    
+    /**
+     * @return Returns the totalSendTime.
+     */
+    public long getTotalSendTime() {
+        return totalSendTime;
+    }
+
+    /**
+     * @return Returns the reqFilters.
+     */
+    protected java.util.regex.Pattern[] getReqFilters() {
+        return reqFilters;
+    }
+    
+    /**
+     * @param reqFilters The reqFilters to set.
+     */
+    protected void setReqFilters(java.util.regex.Pattern[] reqFilters) {
+        this.reqFilters = reqFilters;
+    }
+    
+    
+    // --------------------------------------------------------- Public Methods
+    
+    /**
+     * Register all cross context sessions inside endAccess.
+     * Use a list with contains check, that the Portlet API can include a lot of fragments from same or
+     * different applications with session changes.
+     *
+     * @param session cross context session
+     */
+    public void registerReplicationSession(DeltaSession session) {
+        List sessions = (List)crossContextSessions.get();
+        if(sessions != null) {
+            if(!sessions.contains(session)) {
+                if(log.isDebugEnabled())
+                    log.debug(sm.getString("ReplicationValve.crossContext.registerSession",
+                        session.getIdInternal(),
+                        session.getManager().getContainer().getName()));
+                sessions.add(session);
+            }
+        }
+    }
+
+    /**
+     * Log the interesting request parameters, invoke the next Valve in the
+     * sequence, and log the interesting response parameters.
+     *
+     * @param request The servlet request to be processed
+     * @param response The servlet response to be created
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception ServletException if a servlet error occurs
+     */
+    public void invoke(Request request, Response response)
+        throws IOException, ServletException
+    {
+        long totalstart = 0;
+
+        //this happens before the request
+        if(isDoProcessingStats()) {
+            totalstart = System.currentTimeMillis();
+        }
+        if (primaryIndicator) {
+            createPrimaryIndicator(request) ;
+        }
+        Context context = request.getContext();
+        boolean isCrossContext = context != null
+                && context instanceof StandardContext
+                && ((StandardContext) context).getCrossContext();
+        try {
+            if(isCrossContext) {
+                if(log.isDebugEnabled())
+                    log.debug(sm.getString("ReplicationValve.crossContext.add"));
+                //FIXME add Pool of Arraylists
+                crossContextSessions.set(new ArrayList());
+            }
+            getNext().invoke(request, response);
+            Manager manager = request.getContext().getManager();
+            if (manager != null && manager instanceof ClusterManager) {
+                ClusterManager clusterManager = (ClusterManager) manager;
+                CatalinaCluster containerCluster = (CatalinaCluster) getContainer().getCluster();
+                if (containerCluster == null) {
+                    if (log.isWarnEnabled())
+                        log.warn(sm.getString("ReplicationValve.nocluster"));
+                    return;
+                }
+                // valve cluster can access manager - other cluster handle replication 
+                // at host level - hopefully!
+                if(containerCluster.getManager(clusterManager.getName()) == null)
+                    return ;
+                if(containerCluster.hasMembers()) {
+                    sendReplicationMessage(request, totalstart, isCrossContext, clusterManager, containerCluster);
+                } else {
+                    resetReplicationRequest(request,isCrossContext);
+                }        
+            }
+        } finally {
+            // Array must be remove: Current master request send endAccess at recycle. 
+            // Don't register this request session again!
+            if(isCrossContext) {
+                if(log.isDebugEnabled())
+                    log.debug(sm.getString("ReplicationValve.crossContext.remove"));
+                // crossContextSessions.remove() only exist at Java 5
+                // register ArrayList at a pool
+                crossContextSessions.set(null);
+            }
+        }
+    }
+
+    
+    /**
+     * reset the active statitics 
+     */
+    public void resetStatistics() {
+        totalRequestTime = 0 ;
+        totalSendTime = 0 ;
+        lastSendTime = 0 ;
+        nrOfFilterRequests = 0 ;
+        nrOfRequests = 0 ;
+        nrOfSendRequests = 0;
+        nrOfCrossContextSendRequests = 0;
+    }
+    
+    /**
+     * Return a String rendering of this object.
+     */
+    public String toString() {
+
+        StringBuffer sb = new StringBuffer("ReplicationValve[");
+        if (container != null)
+            sb.append(container.getName());
+        sb.append("]");
+        return (sb.toString());
+
+    }
+
+    // --------------------------------------------------------- Protected Methods
+
+    /**
+     * @param request
+     * @param totalstart
+     * @param isCrossContext
+     * @param clusterManager
+     * @param containerCluster
+     */
+    protected void sendReplicationMessage(Request request, long totalstart, boolean isCrossContext, ClusterManager clusterManager, CatalinaCluster containerCluster) {
+        //this happens after the request
+        long start = 0;
+        if(isDoProcessingStats()) {
+            start = System.currentTimeMillis();
+        }
+        try {
+            // send invalid sessions
+            // DeltaManager returns String[0]
+            if (!(clusterManager instanceof DeltaManager))
+                sendInvalidSessions(clusterManager, containerCluster);
+            // send replication
+            sendSessionReplicationMessage(request, clusterManager, containerCluster);
+            if(isCrossContext)
+                sendCrossContextSession(containerCluster);
+        } catch (Exception x) {
+            // FIXME we have a lot of sends, but the trouble with one node stops the correct replication to other nodes!
+            log.error(sm.getString("ReplicationValve.send.failure"), x);
+        } finally {
+            // FIXME this stats update are not cheap!!
+            if(isDoProcessingStats()) {
+                updateStats(totalstart,start);
+            }
+        }
+    }
+
+    /**
+     * Send all changed cross context sessions to backups
+     * @param containerCluster
+     */
+    protected void sendCrossContextSession(CatalinaCluster containerCluster) {
+        Object sessions = crossContextSessions.get();
+        if(sessions != null && sessions instanceof List
+                && ((List)sessions).size() >0) {
+            for(Iterator iter = ((List)sessions).iterator(); iter.hasNext() ;) {          
+                Session session = (Session)iter.next();
+                if(log.isDebugEnabled())
+                    log.debug(sm.getString("ReplicationValve.crossContext.sendDelta",  
+                            session.getManager().getContainer().getName() ));
+                sendMessage(session,(ClusterManager)session.getManager(),containerCluster);
+                if(isDoProcessingStats()) {
+                    nrOfCrossContextSendRequests++;
+                }
+            }
+        }
+    }
+  
+    /**
+     * Fix memory leak for long sessions with many changes, when no backup member exists!
+     * set primarySession flag at request session and all crossContext sessions
+     * @see DeltaManager#requestCompleted(String)
+     * @param request current request after responce is generated
+     * @param isCrossContext check crosscontext threadlocal
+     */
+    protected void resetReplicationRequest(Request request, boolean isCrossContext) {
+        Session contextSession = request.getSessionInternal(false);
+        if(contextSession != null & contextSession instanceof DeltaSession){
+            resetDeltaRequest(contextSession);
+            ((DeltaSession)contextSession).setPrimarySession(true);
+        }
+        if(isCrossContext) {
+            Object sessions = crossContextSessions.get();
+            if(sessions != null && sessions instanceof List
+               && ((List)sessions).size() >0) {
+                Iterator iter = ((List)sessions).iterator();
+                for(; iter.hasNext() ;) {          
+                    Session session = (Session)iter.next();
+                    resetDeltaRequest(session);
+                    if(session instanceof DeltaSession)
+                        ((DeltaSession)contextSession).setPrimarySession(true);                        
+                }
+            }
+        }                     
+    }
+
+    /**
+     * Reset DeltaRequest from session
+     * @param session HttpSession from current request or cross context session
+     */
+    protected void resetDeltaRequest(Session session) {
+        if(log.isDebugEnabled()) {
+            log.debug(sm.getString("ReplicationValve.resetDeltaRequest" , 
+                session.getManager().getContainer().getName() ));
+        }
+        ((DeltaSession)session).resetDeltaRequest();
+    }
+
+    /**
+     * Send Cluster Replication Request
+     * @param request current request
+     * @param manager session manager
+     * @param cluster replication cluster
+     */
+    protected void sendSessionReplicationMessage(Request request,
+            ClusterManager manager, CatalinaCluster cluster) {
+        Session session = request.getSessionInternal(false);
+        if (session != null) {
+            String uri = request.getDecodedRequestURI();
+            // request without session change
+            if (!isRequestWithoutSessionChange(uri)) {
+                if (log.isDebugEnabled())
+                    log.debug(sm.getString("ReplicationValve.invoke.uri", uri));
+                sendMessage(session,manager,cluster);
+            } else
+                if(isDoProcessingStats())
+                    nrOfFilterRequests++;
+        }
+
+    }
+
+   /**
+    * Send message delta message from request session 
+    * @param request current request
+    * @param manager session manager
+    * @param cluster replication cluster
+    */
+    protected void sendMessage(Session session,
+             ClusterManager manager, CatalinaCluster cluster) {
+        String id = session.getIdInternal();
+        if (id != null) {
+            send(manager, cluster, id);
+        }
+    }
+
+    /**
+     * send manager requestCompleted message to cluster
+     * @param manager SessionManager
+     * @param cluster replication cluster
+     * @param sessionId sessionid from the manager
+     * @see DeltaManager#requestCompleted(String)
+     * @see SimpleTcpCluster#send(ClusterMessage)
+     */
+    protected void send(ClusterManager manager, CatalinaCluster cluster, String sessionId) {
+        ClusterMessage msg = manager.requestCompleted(sessionId);
+        if (msg != null) {
+            if(manager.isSendClusterDomainOnly()) {
+                cluster.sendClusterDomain(msg);
+            } else {
+                cluster.send(msg);
+            }
+            if(isDoProcessingStats())
+                nrOfSendRequests++;
+        }
+    }
+    
+    /**
+     * check for session invalidations
+     * @param manager
+     * @param cluster
+     */
+    protected void sendInvalidSessions(ClusterManager manager, CatalinaCluster cluster) {
+        String[] invalidIds=manager.getInvalidatedSessions();
+        if ( invalidIds.length > 0 ) {
+            for ( int i=0;i<invalidIds.length; i++ ) {
+                try {
+                    send(manager,cluster,invalidIds[i]);
+                } catch ( Exception x ) {
+                    log.error(sm.getString("ReplicationValve.send.invalid.failure",invalidIds[i]),x);
+                }
+            }
+        }
+    }
+    
+    /**
+     * is request without possible session change
+     * @param uri The request uri
+     * @return True if no session change
+     */
+    protected boolean isRequestWithoutSessionChange(String uri) {
+
+        boolean filterfound = false;
+
+        for (int i = 0; (i < reqFilters.length) && (!filterfound); i++) {
+            java.util.regex.Matcher matcher = reqFilters[i].matcher(uri);
+            filterfound = matcher.matches();
+        }
+        return filterfound;
+    }
+
+    /**
+     * protocol cluster replications stats
+     * @param requestTime
+     * @param clusterTime
+     */
+    protected  void updateStats(long requestTime, long clusterTime) {
+        synchronized(this) {
+            lastSendTime=System.currentTimeMillis();
+            totalSendTime+=lastSendTime - clusterTime;
+            totalRequestTime+=lastSendTime - requestTime;
+            nrOfRequests++;
+        }
+        if(log.isInfoEnabled()) {
+            if ( (nrOfRequests % 100) == 0 ) {
+                 log.info(sm.getString("ReplicationValve.stats",
+                     new Object[]{
+                         new Long(totalRequestTime/nrOfRequests),
+                         new Long(totalSendTime/nrOfRequests),
+                         new Long(nrOfRequests),
+                         new Long(nrOfSendRequests),
+                         new Long(nrOfCrossContextSendRequests),
+                         new Long(nrOfFilterRequests),
+                         new Long(totalRequestTime),
+                         new Long(totalSendTime)}));
+             }
+        }
+    }
+
+
+    /**
+     * Mark Request that processed at primary node with attribute
+     * primaryIndicatorName
+     * 
+     * @param request
+     * @throws IOException
+     */
+    protected void createPrimaryIndicator(Request request) throws IOException {
+        String id = request.getRequestedSessionId();
+        if ((id != null) && (id.length() > 0)) {
+            Manager manager = request.getContext().getManager();
+            Session session = manager.findSession(id);
+            if (session instanceof ClusterSession) {
+                ClusterSession cses = (ClusterSession) session;
+                if (cses != null) {
+                    Boolean isPrimary = new Boolean(cses.isPrimarySession());
+                    if (log.isDebugEnabled())
+                        log.debug(sm.getString(
+                                "ReplicationValve.session.indicator", request.getContext().getName(),id,
+                                primaryIndicatorName, isPrimary));
+                    request.setAttribute(primaryIndicatorName, isPrimary);
+                }
+            } else {
+                if (log.isDebugEnabled()) {
+                    if (session != null) {
+                        log.debug(sm.getString(
+                                "ReplicationValve.session.found", request.getContext().getName(),id));
+                    } else {
+                        log.debug(sm.getString(
+                                "ReplicationValve.session.invalid", request.getContext().getName(),id));
+                    }
+                }
+            }
+        }
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/tcp/SendMessageData.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/tcp/SendMessageData.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/tcp/SendMessageData.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,81 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.cluster.tcp;
+
+import org.apache.catalina.cluster.Member;
+
+/**
+ * @author Peter Rossbach
+ * @version $Revision: 303987 $ $Date: 2005-07-08 15:50:30 -0500 (Fri, 08 Jul 2005) $
+ */
+public class SendMessageData {
+
+    private Object message ;
+    private Member destination ;
+    private Exception exception ;
+    
+    
+    /**
+     * @param message
+     * @param destination
+     * @param exception
+     */
+    public SendMessageData(Object message, Member destination,
+            Exception exception) {
+        super();
+        this.message = message;
+        this.destination = destination;
+        this.exception = exception;
+    }
+    
+    /**
+     * @return Returns the destination.
+     */
+    public Member getDestination() {
+        return destination;
+    }
+    /**
+     * @param destination The destination to set.
+     */
+    public void setDestination(Member destination) {
+        this.destination = destination;
+    }
+    /**
+     * @return Returns the exception.
+     */
+    public Exception getException() {
+        return exception;
+    }
+    /**
+     * @param exception The exception to set.
+     */
+    public void setException(Exception exception) {
+        this.exception = exception;
+    }
+    /**
+     * @return Returns the message.
+     */
+    public Object getMessage() {
+        return message;
+    }
+    /**
+     * @param message The message to set.
+     */
+    public void setMessage(Object message) {
+        this.message = message;
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/tcp/SenderState.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/tcp/SenderState.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/tcp/SenderState.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,82 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.cluster.tcp;
+
+
+/**
+ * Send cluster messages with a pool of sockets (25).
+ * 
+ * FIXME support processing stats
+ * 
+ * @author Filip Hanik
+ * @version 1.0
+ * @since 5.5.16
+ */
+
+public class SenderState {
+    
+    public static final int READY = 0;
+    public static final int SUSPECT = 1;
+    public static final int FAILING = 2;
+    /**
+     * The descriptive information about this implementation.
+     */
+    private static final String info = "SenderState/1.0";
+
+    // ----------------------------------------------------- Instance Variables
+
+    private int state = READY;
+
+    //  ----------------------------------------------------- Constructor
+
+    
+    public SenderState() {
+        this(READY);
+    }
+
+    public SenderState(int state) {
+        this.state = state;
+    }
+    
+    public boolean isSuspect() {
+        return state == SUSPECT;
+    }
+
+    public void setSuspect() {
+        state = SUSPECT;
+    }
+    
+    public boolean isReady() {
+        return state == READY;
+    }
+    
+    public void setReady() {
+        state = READY;
+    }
+    
+    public boolean isFailing() {
+        return state == FAILING;
+    }
+    
+    public void setFailing() {
+        state = FAILING;
+    }
+    
+
+    //  ----------------------------------------------------- Public Properties
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/tcp/SimpleTcpCluster.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/tcp/SimpleTcpCluster.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/tcp/SimpleTcpCluster.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,1396 @@
+/*
+ * Copyright 1999,2004-2005 The Apache Software Foundation.
+ * 
+ * Licensed 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.cluster.tcp;
+
+import java.beans.PropertyChangeSupport;
+import java.io.IOException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import javax.management.MBeanServer;
+import javax.management.MBeanServerFactory;
+import javax.management.ObjectName;
+import javax.management.modelmbean.ModelMBean;
+
+import org.apache.catalina.Container;
+import org.apache.catalina.Context;
+import org.apache.catalina.Engine;
+import org.apache.catalina.Host;
+import org.apache.catalina.Lifecycle;
+import org.apache.catalina.LifecycleEvent;
+import org.apache.catalina.LifecycleException;
+import org.apache.catalina.LifecycleListener;
+import org.apache.catalina.Manager;
+import org.apache.catalina.Valve;
+import org.apache.catalina.cluster.CatalinaCluster;
+import org.apache.catalina.cluster.ClusterManager;
+import org.apache.catalina.cluster.ClusterMessage;
+import org.apache.catalina.cluster.ClusterReceiver;
+import org.apache.catalina.cluster.ClusterSender;
+import org.apache.catalina.cluster.ClusterValve;
+import org.apache.catalina.cluster.Member;
+import org.apache.catalina.cluster.MembershipListener;
+import org.apache.catalina.cluster.MembershipService;
+import org.apache.catalina.cluster.MessageListener;
+import org.apache.catalina.cluster.mcast.McastService;
+import org.apache.catalina.cluster.session.ClusterSessionListener;
+import org.apache.catalina.cluster.session.DeltaManager;
+import org.apache.catalina.cluster.util.IDynamicProperty;
+import org.apache.catalina.core.StandardEngine;
+import org.apache.catalina.core.StandardHost;
+import org.apache.catalina.util.LifecycleSupport;
+import org.apache.catalina.util.StringManager;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.commons.modeler.ManagedBean;
+import org.apache.commons.modeler.Registry;
+import org.apache.tomcat.util.IntrospectionUtils;
+
+/**
+ * A <b>Cluster </b> implementation using simple multicast. Responsible for
+ * 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 $Revision: 412798 $, $Date: 2006-06-08 11:57:24 -0500 (Thu, 08 Jun 2006) $
+ */
+public class SimpleTcpCluster implements CatalinaCluster, Lifecycle,
+        MembershipListener, LifecycleListener, IDynamicProperty {
+
+    public static Log log = LogFactory.getLog(SimpleTcpCluster.class);
+
+    // ----------------------------------------------------- Instance Variables
+
+    /**
+     * Descriptive information about this component implementation.
+     */
+    protected static final String info = "SimpleTcpCluster/2.2";
+
+    public static final String BEFORE_MEMBERREGISTER_EVENT = "before_member_register";
+
+    public static final String AFTER_MEMBERREGISTER_EVENT = "after_member_register";
+
+    public static final String BEFORE_MANAGERREGISTER_EVENT = "before_manager_register";
+
+    public static final String AFTER_MANAGERREGISTER_EVENT = "after_manager_register";
+
+    public static final String BEFORE_MANAGERUNREGISTER_EVENT = "before_manager_unregister";
+
+    public static final String AFTER_MANAGERUNREGISTER_EVENT = "after_manager_unregister";
+
+    public static final String BEFORE_MEMBERUNREGISTER_EVENT = "before_member_unregister";
+
+    public static final String AFTER_MEMBERUNREGISTER_EVENT = "after_member_unregister";
+
+    public static final String SEND_MESSAGE_FAILURE_EVENT = "send_message_failure";
+
+    public static final String RECEIVE_MESSAGE_FAILURE_EVENT = "receive_message_failure";
+
+    /**
+     * the service that provides the membership
+     */
+    protected MembershipService membershipService = null;
+
+    /**
+     * Name for logging purpose
+     */
+    protected String clusterImpName = "SimpleTcpCluster";
+
+    /**
+     * The string manager for this package.
+     */
+    protected StringManager sm = StringManager.getManager(Constants.Package);
+
+    /**
+     * The cluster name to join
+     */
+    protected String clusterName ;
+
+    /**
+     * The Container associated with this Cluster.
+     */
+    protected Container container = null;
+
+    /**
+     * The lifecycle event support for this component.
+     */
+    protected LifecycleSupport lifecycle = new LifecycleSupport(this);
+
+    /**
+     * Globale MBean Server
+     */
+    private MBeanServer mserver = null;
+
+    /**
+     * Current Catalina Registry
+     */
+    private Registry registry = null;
+
+    /**
+     * Has this component been started?
+     */
+    protected boolean started = false;
+
+    /**
+     * The property change support for this component.
+     */
+    protected PropertyChangeSupport support = new PropertyChangeSupport(this);
+
+    /**
+     * The context name <->manager association for distributed contexts.
+     */
+    protected Map managers = new HashMap();
+
+    private String managerClassName = "org.apache.catalina.cluster.session.DeltaManager";
+
+    /**
+     * Sender to send data with
+     */
+    private org.apache.catalina.cluster.ClusterSender clusterSender;
+
+    /**
+     * Receiver to register call back with
+     */
+    private org.apache.catalina.cluster.ClusterReceiver clusterReceiver;
+
+    private List valves = new ArrayList();
+
+    private org.apache.catalina.cluster.ClusterDeployer clusterDeployer;
+
+    private boolean defaultMode = true ;
+    
+    /**
+     * Listeners of messages
+     */
+    protected List clusterListeners = new ArrayList();
+
+    /**
+     * Comment for <code>notifyLifecycleListenerOnFailure</code>
+     */
+    private boolean notifyLifecycleListenerOnFailure = false;
+
+    private ObjectName objectName = null;
+
+    /**
+     * dynamic sender <code>properties</code>
+     */
+    private Map properties = new HashMap();
+
+    /**
+     * The cluster log device name to log at level info
+     */
+    private String clusterLogName = "org.apache.catalina.cluster.tcp.SimpleTcpCluster";
+
+    private boolean doClusterLog = false;
+
+    private Log clusterLog = null;
+
+    // ------------------------------------------------------------- Properties
+
+    public SimpleTcpCluster() {
+    }
+
+    /**
+     * Return descriptive information about this Cluster implementation and the
+     * corresponding version number, in the format
+     * <code>&lt;description&gt;/&lt;version&gt;</code>.
+     */
+    public String getInfo() {
+        return (info);
+    }
+
+    /**
+     * Set the name of the cluster to join, if no cluster with this name is
+     * present create one.
+     * 
+     * @param clusterName
+     *            The clustername to join
+     */
+    public void setClusterName(String clusterName) {
+        this.clusterName = clusterName;
+    }
+
+    /**
+     * Return the name of the cluster that this Server is currently configured
+     * to operate within.
+     * 
+     * @return The name of the cluster associated with this server
+     */
+    public String getClusterName() {
+        if(clusterName == null && container != null)
+            return container.getName() ;
+        return clusterName;
+    }
+
+    /**
+     * Set the Container associated with our Cluster
+     * 
+     * @param container
+     *            The Container to use
+     */
+    public void setContainer(Container container) {
+        Container oldContainer = this.container;
+        this.container = container;
+        support.firePropertyChange("container", oldContainer, this.container);
+    }
+
+    /**
+     * Get the Container associated with our Cluster
+     * 
+     * @return The Container associated with our Cluster
+     */
+    public Container getContainer() {
+        return (this.container);
+    }
+
+    /**
+     * @return Returns the notifyLifecycleListenerOnFailure.
+     */
+    public boolean isNotifyLifecycleListenerOnFailure() {
+        return notifyLifecycleListenerOnFailure;
+    }
+
+    /**
+     * @param notifyListenerOnFailure
+     *            The notifyLifecycleListenerOnFailure to set.
+     */
+    public void setNotifyLifecycleListenerOnFailure(
+            boolean notifyListenerOnFailure) {
+        boolean oldNotifyListenerOnFailure = this.notifyLifecycleListenerOnFailure;
+        this.notifyLifecycleListenerOnFailure = notifyListenerOnFailure;
+        support.firePropertyChange("notifyLifecycleListenerOnFailure",
+                oldNotifyListenerOnFailure,
+                this.notifyLifecycleListenerOnFailure);
+    }
+
+    /**
+     * @return Returns the defaultMode.
+     */
+    public boolean isDefaultMode() {
+        return defaultMode;
+    }
+    
+    /**
+     * @param defaultMode The defaultMode to set.
+     */
+    public void setDefaultMode(boolean defaultMode) {
+        this.defaultMode = defaultMode;
+    }
+    
+    public String getManagerClassName() {
+        if(managerClassName != null)
+            return managerClassName;
+        return (String)getProperty("manager.className");
+    }
+
+    public void setManagerClassName(String managerClassName) {
+        this.managerClassName = managerClassName;
+    }
+
+    public ClusterSender getClusterSender() {
+        return clusterSender;
+    }
+
+    public void setClusterSender(ClusterSender clusterSender) {
+        this.clusterSender = clusterSender;
+    }
+
+    public ClusterReceiver getClusterReceiver() {
+        return clusterReceiver;
+    }
+
+    public void setClusterReceiver(ClusterReceiver clusterReceiver) {
+        this.clusterReceiver = clusterReceiver;
+    }
+
+    public MembershipService getMembershipService() {
+        return membershipService;
+    }
+
+    public void setMembershipService(MembershipService membershipService) {
+        this.membershipService = membershipService;
+    }
+
+    /**
+     * Add cluster valve 
+     * Cluster Valves are only add to container when cluster is started!
+     * @param valve The new cluster Valve.
+     */
+    public void addValve(Valve valve) {
+        if (valve instanceof ClusterValve)
+            valves.add(valve);
+    }
+
+    /**
+     * get all cluster valves
+     * @return current cluster valves
+     */
+    public Valve[] getValves() {
+        return (Valve[]) valves.toArray(new Valve[valves.size()]);
+    }
+
+    /**
+     * Get the cluster listeners associated with this cluster. If this Array has
+     * no listeners registered, a zero-length array is returned.
+     */
+    public MessageListener[] findClusterListeners() {
+        if (clusterListeners.size() > 0) {
+            MessageListener[] listener = new MessageListener[clusterListeners
+                    .size()];
+            clusterListeners.toArray(listener);
+            return listener;
+        } else
+            return new MessageListener[0];
+
+    }
+
+    /**
+     * add cluster message listener and register cluster to this listener
+     * 
+     * @see org.apache.catalina.cluster.CatalinaCluster#addClusterListener(org.apache.catalina.cluster.MessageListener)
+     */
+    public void addClusterListener(MessageListener listener) {
+        if (listener != null && !clusterListeners.contains(listener)) {
+            clusterListeners.add(listener);
+            listener.setCluster(this);
+        }
+    }
+
+    /**
+     * remove message listener and deregister Cluster from listener
+     * 
+     * @see org.apache.catalina.cluster.CatalinaCluster#removeClusterListener(org.apache.catalina.cluster.MessageListener)
+     */
+    public void removeClusterListener(MessageListener listener) {
+        if (listener != null) {
+            clusterListeners.remove(listener);
+            listener.setCluster(null);
+        }
+    }
+
+    /**
+     * get current Deployer
+     */
+    public org.apache.catalina.cluster.ClusterDeployer getClusterDeployer() {
+        return clusterDeployer;
+    }
+
+    /**
+     * set a new Deployer, must be set before cluster started!
+     */
+    public void setClusterDeployer(
+            org.apache.catalina.cluster.ClusterDeployer clusterDeployer) {
+        this.clusterDeployer = clusterDeployer;
+    }
+
+    /**
+     * has members
+     */
+    public boolean hasMembers() {
+        return membershipService.hasMembers();
+    }
+    
+    /**
+     * Get all current cluster members
+     * @return all members or empty array 
+     */
+    public Member[] getMembers() {
+        return membershipService.getMembers();
+    }
+
+    /**
+     * Return the member that represents this node.
+     * 
+     * @return Member
+     */
+    public Member getLocalMember() {
+        return membershipService.getLocalMember();
+    }
+
+    // ------------------------------------------------------------- dynamic
+    // manager property handling
+
+    /**
+     * JMX hack to direct use at jconsole
+     * 
+     * @param name
+     * @param value
+     */
+    public void setProperty(String name, String value) {
+        setProperty(name, (Object) value);
+    }
+
+    /**
+     * set config attributes with reflect and propagate to all managers
+     * 
+     * @param name
+     * @param value
+     */
+    public void setProperty(String name, Object value) {
+        if (log.isTraceEnabled())
+            log.trace(sm.getString("SimpleTcpCluster.setProperty", name, value,
+                    properties.get(name)));
+
+        properties.put(name, value);
+        if(started) {
+            // FIXME Hmm, is that correct when some DeltaManagers are direct configured inside Context?
+            // Why we not support it for other elements, like sender, receiver or membership?
+            // Must we restart element after change?
+            if (name.startsWith("manager")) {
+                String key = name.substring("manager".length() + 1);
+                String pvalue = value.toString();
+                for (Iterator iter = managers.values().iterator(); iter.hasNext();) {
+                    Manager manager = (Manager) iter.next();
+                    if(manager instanceof DeltaManager && ((ClusterManager) manager).isDefaultMode()) {
+                        IntrospectionUtils.setProperty(manager, key, pvalue );
+                    }
+                }
+            } 
+        }
+    }
+
+    /**
+     * get current config
+     * 
+     * @param key
+     * @return The property
+     */
+    public Object getProperty(String key) {
+        if (log.isTraceEnabled())
+            log.trace(sm.getString("SimpleTcpCluster.getProperty", key));
+        return properties.get(key);
+    }
+
+    /**
+     * Get all properties keys
+     * 
+     * @return An iterator over the property names.
+     */
+    public Iterator getPropertyNames() {
+        return properties.keySet().iterator();
+    }
+
+    /**
+     * remove a configured property.
+     * 
+     * @param key
+     */
+    public void removeProperty(String key) {
+        properties.remove(key);
+    }
+
+    /**
+     * transfer properties from cluster configuration to subelement bean.
+     * @param prefix
+     * @param bean
+     */
+    protected void transferProperty(String prefix, Object bean) {
+        if (prefix != null) {
+            for (Iterator iter = getPropertyNames(); iter.hasNext();) {
+                String pkey = (String) iter.next();
+                if (pkey.startsWith(prefix)) {
+                    String key = pkey.substring(prefix.length() + 1);
+                    Object value = getProperty(pkey);
+                    IntrospectionUtils.setProperty(bean, key, value.toString());
+                }
+            }
+        }
+    }
+
+    // --------------------------------------------------------- Public Methods
+
+    /**
+     * @return Returns the managers.
+     */
+    public Map getManagers() {
+        return managers;
+    }
+
+    /**
+     * Create new Manager without add to cluster (comes with start the manager)
+     * 
+     * @param name
+     *            Context Name of this manager
+     * @see org.apache.catalina.Cluster#createManager(java.lang.String)
+     * @see #addManager(String, Manager)
+     * @see DeltaManager#start()
+     */
+    public synchronized Manager createManager(String name) {
+        ClassLoader oldCtxLoader = Thread.currentThread().getContextClassLoader();
+        Manager manager = null;
+        try {
+            Thread.currentThread().setContextClassLoader(SimpleTcpCluster.class.getClassLoader());
+            if (log.isDebugEnabled())
+                log.debug("Creating ClusterManager for context " + name + " using class " + getManagerClassName());
+            try {
+                manager = (Manager) getClass().getClassLoader().loadClass(getManagerClassName()).newInstance();
+            } catch (Exception x) {
+                log.error("Unable to load class for replication manager", x);
+                manager = new org.apache.catalina.cluster.session.DeltaManager();
+            } finally {
+                if (manager != null) {
+                    manager.setDistributable(true);
+                    if (manager instanceof ClusterManager) {
+                        ClusterManager cmanager = (ClusterManager) manager;
+                        cmanager.setDefaultMode(true);
+                        cmanager.setName(getManagerName(name, manager));
+                        cmanager.setCluster(this);
+                    }
+                }
+            }
+        }finally {
+            Thread.currentThread().setContextClassLoader(oldCtxLoader);
+        }
+        return manager;
+    }
+
+    /**
+     * remove an application form cluster replication bus
+     * 
+     * @see org.apache.catalina.cluster.CatalinaCluster#removeManager(java.lang.String,Manager)
+     */
+    public void removeManager(String name,Manager manager) {
+        if (manager != null) {
+            // Notify our interested LifecycleListeners
+            lifecycle.fireLifecycleEvent(BEFORE_MANAGERUNREGISTER_EVENT,
+                    manager);
+            managers.remove(getManagerName(name,manager));
+            if (manager instanceof ClusterManager)
+                ((ClusterManager) manager).setCluster(null);
+            // Notify our interested LifecycleListeners
+            lifecycle
+                    .fireLifecycleEvent(AFTER_MANAGERUNREGISTER_EVENT, manager);
+        }
+    }
+
+    /**
+     * add an application to cluster replication bus
+     * 
+     * @param name
+     *            of the context
+     * @param manager
+     *            manager to register
+     * @see org.apache.catalina.cluster.CatalinaCluster#addManager(java.lang.String,
+     *      org.apache.catalina.Manager)
+     */
+    public void addManager(String name, Manager manager) {
+        if (!manager.getDistributable()) {
+            log.warn("Manager with name " + name
+                    + " is not distributable, can't add as cluster manager");
+            return;
+        }
+        // Notify our interested LifecycleListeners
+        lifecycle.fireLifecycleEvent(BEFORE_MANAGERREGISTER_EVENT, manager);
+        String clusterName = getManagerName(name, manager);
+        if (manager instanceof ClusterManager) {
+            ClusterManager cmanager = (ClusterManager) manager ;
+            cmanager.setName(clusterName);
+            cmanager.setCluster(this);
+            if(cmanager.isDefaultMode())
+                transferProperty("manager",cmanager);
+        }
+        managers.put(clusterName, manager);
+        // Notify our interested LifecycleListeners
+        lifecycle.fireLifecycleEvent(AFTER_MANAGERREGISTER_EVENT, manager);
+    }
+
+    /**
+     * @param name
+     * @param manager
+     * @return
+     */
+    private String getManagerName(String name, Manager manager) {
+        String clusterName = name ;
+        if(getContainer() instanceof Engine) {
+            Container context = manager.getContainer() ;
+            if(context != null && context instanceof Context) {
+                Container host = ((Context)context).getParent();
+                if(host != null && host instanceof Host)
+                    clusterName = host.getName()  + name ;
+            }
+        }
+        return clusterName;
+    }
+
+    /*
+     * Get Manager
+     * 
+     * @see org.apache.catalina.cluster.CatalinaCluster#getManager(java.lang.String)
+     */
+    public Manager getManager(String name) {
+        return (Manager) managers.get(name);
+    }
+
+ 
+    // ------------------------------------------------------ Lifecycle Methods
+
+    /**
+     * Execute a periodic task, such as reloading, etc. This method will be
+     * invoked inside the classloading context of this container. Unexpected
+     * throwables will be caught and logged.
+     * @see org.apache.catalina.cluster.deploy.FarmWarDeployer#backgroundProcess()
+     * @see ReplicationTransmitter#backgroundProcess()
+     */
+    public void backgroundProcess() {
+        if (clusterDeployer != null)
+            clusterDeployer.backgroundProcess();
+        if (clusterSender != null)
+            clusterSender.backgroundProcess();
+    }
+
+    /**
+     * Add a lifecycle event listener to this component.
+     * 
+     * @param listener
+     *            The listener to add
+     */
+    public void addLifecycleListener(LifecycleListener listener) {
+        lifecycle.addLifecycleListener(listener);
+    }
+
+    /**
+     * Get the lifecycle listeners associated with this lifecycle. If this
+     * Lifecycle has no listeners registered, a zero-length array is returned.
+     */
+    public LifecycleListener[] findLifecycleListeners() {
+
+        return lifecycle.findLifecycleListeners();
+
+    }
+
+    /**
+     * Remove a lifecycle event listener from this component.
+     * 
+     * @param listener
+     *            The listener to remove
+     */
+    public void removeLifecycleListener(LifecycleListener listener) {
+        lifecycle.removeLifecycleListener(listener);
+    }
+
+    /**
+     * Use as base to handle start/stop/periodic Events from host. Currently
+     * only log the messages as trace level.
+     * 
+     * @see org.apache.catalina.LifecycleListener#lifecycleEvent(org.apache.catalina.LifecycleEvent)
+     */
+    public void lifecycleEvent(LifecycleEvent lifecycleEvent) {
+        if (log.isTraceEnabled())
+            log.trace(sm.getString("SimpleTcpCluster.event.log", lifecycleEvent
+                    .getType(), lifecycleEvent.getData()));
+    }
+
+    // ------------------------------------------------------ public
+
+    /**
+     * Prepare for the beginning of active use of the public methods of this
+     * component. This method should be called after <code>configure()</code>,
+     * and before any of the public methods of the component are utilized. <BR>
+     * Starts the cluster communication channel, this will connect with the
+     * other nodes in the cluster, and request the current session state to be
+     * transferred to this node.
+     * 
+     * @exception IllegalStateException
+     *                if this component has already been started
+     * @exception LifecycleException
+     *                if this component detects a fatal error that prevents this
+     *                component from being used
+     */
+    public void start() throws LifecycleException {
+        if (started)
+            throw new LifecycleException(sm.getString("cluster.alreadyStarted"));
+        if (log.isInfoEnabled())
+            log.info("Cluster is about to start");
+        getClusterLog();
+        // Notify our interested LifecycleListeners
+        lifecycle.fireLifecycleEvent(BEFORE_START_EVENT, this);
+        try {
+            if(isDefaultMode() && valves.size() == 0) {
+                createDefaultClusterValves() ;
+            }
+            registerClusterValve();
+            registerMBeans();
+            // setup the default cluster session listener (DeltaManager support)
+            if(isDefaultMode() && clusterListeners.size() == 0) {
+                createDefaultClusterListener();
+            }
+            // setup the default cluster Receiver
+            if(isDefaultMode() && clusterReceiver == null) {
+                createDefaultClusterReceiver();
+            }
+            // setup the default cluster sender
+            if(isDefaultMode() && clusterSender == null) {
+                createDefaultClusterSender();
+            }
+            // start the receiver.
+            if(clusterReceiver != null) {
+                clusterReceiver.setSendAck(clusterSender.isWaitForAck());
+                clusterReceiver.setCompress(clusterSender.isCompress());
+                clusterReceiver.setCatalinaCluster(this);
+                clusterReceiver.start();
+            }
+     
+            // start the sender.
+            if(clusterSender != null && clusterReceiver != null) {
+                clusterSender.setCatalinaCluster(this);
+                clusterSender.start();
+            }
+            
+            // start the membership service.
+            if(isDefaultMode() && membershipService == null) {
+                createDefaultMembershipService();
+            }
+            
+            if(membershipService != null && clusterReceiver != null) {
+                membershipService.setLocalMemberProperties(clusterReceiver
+                    .getHost(), clusterReceiver.getPort());
+                membershipService.addMembershipListener(this);
+                membershipService.setCatalinaCluster(this);
+                membershipService.start();
+                // start the deployer.
+                try {
+                    if (clusterDeployer != null) {
+                        clusterDeployer.setCluster(this);
+                        clusterDeployer.start();
+                    }
+                } catch (Throwable x) {
+                    log.fatal("Unable to retrieve the container deployer. Cluster deployment disabled.",x);
+                }
+            }
+            this.started = true;
+            // Notify our interested LifecycleListeners
+            lifecycle.fireLifecycleEvent(AFTER_START_EVENT, this);
+        } catch (Exception x) {
+            log.error("Unable to start cluster.", x);
+            throw new LifecycleException(x);
+        }
+    }
+
+    /**
+     * Create default membership service:
+     * <pre>
+     * &lt;Membership 
+     *             className="org.apache.catalina.cluster.mcast.McastService"
+     *             mcastAddr="228.0.0.4"
+     *             mcastPort="8012"
+     *             mcastFrequency="1000"
+     *             mcastDropTime="30000"/&gt;
+     * </pre>
+     */
+    protected void createDefaultMembershipService() {
+        if (log.isInfoEnabled()) {
+            log.info(sm.getString(
+                    "SimpleTcpCluster.default.addMembershipService",
+                    getClusterName()));
+        }
+        
+        McastService mService= new McastService();
+        mService.setMcastAddr("228.0.0.4");
+        mService.setMcastPort(8012);
+        mService.setMcastFrequency(1000);
+        mService.setMcastDropTime(30000);
+        transferProperty("service",mService);        
+        setMembershipService(mService);          
+    }
+
+    
+    /**
+     * Create default cluster sender
+     * <pre>
+     *  &lt;Sender
+     *     className="org.apache.catalina.cluster.tcp.ReplicationTransmitter"
+     *     replicationMode="fastasyncqueue"
+     *     doTransmitterProcessingStats="true"
+     *     doProcessingStats="true"/&gt;
+     *  </pre>
+     */
+    protected void createDefaultClusterSender() {
+        if (log.isInfoEnabled()) {
+            log.info(sm.getString(
+                    "SimpleTcpCluster.default.addClusterSender",
+                    getClusterName()));
+        }        
+        ReplicationTransmitter sender= new ReplicationTransmitter();
+        sender.setReplicationMode("fastasyncqueue");
+        sender.setDoTransmitterProcessingStats(true);
+        sender.setProperty("doProcessingStats", "true");
+        transferProperty("sender",sender);
+        setClusterSender(sender);          
+    }
+
+    /**
+     * Create default receiver:
+     * <pre>
+     *   &lt;Receiver 
+     *     className="org.apache.catalina.cluster.tcp.SocketReplicationListener"
+     *     tcpListenAddress="auto"
+     *     tcpListenPort="8015"
+     *     tcpListenMaxPort="8019"
+     *     doReceivedProcessingStats="true"
+     *   /&gt;
+     * </pre>
+     */
+    protected void createDefaultClusterReceiver() {
+        if (log.isInfoEnabled()) {
+            log.info(sm.getString(
+                    "SimpleTcpCluster.default.addClusterReceiver",
+                    getClusterName()));
+        }
+        SocketReplicationListener receiver= new SocketReplicationListener();
+        receiver.setTcpListenAddress("auto");
+        receiver.setDoReceivedProcessingStats(true);
+        receiver.setTcpListenPort(8015);
+        receiver.setTcpListenMaxPort(8019);
+        transferProperty("receiver",receiver);
+        setClusterReceiver(receiver);          
+        
+    }
+
+    /**
+     * Create default session cluster listener:
+     *  <pre>
+     * &lt;ClusterListener 
+     *   className="org.apache.catalina.cluster.session.ClusterSessionListener" /&gt;
+     * </pre>
+     */
+    protected void createDefaultClusterListener() {
+        if (log.isInfoEnabled()) {
+            log.info(sm.getString(
+                    "SimpleTcpCluster.default.addClusterListener",
+                    getClusterName()));
+        }
+        ClusterSessionListener listener = new ClusterSessionListener();
+        transferProperty("listener",listener);
+        addClusterListener(listener);
+        
+    }
+
+    /**
+     * Create default ReplicationValve
+     * <pre>
+     * &lt;Valve 
+     *    className="org.apache.catalina.cluster.tcp.ReplicationValve"
+     *    filter=".*\.gif;.*\.js;.*\.css;.*\.png;.*\.jpeg;.*\.jpg;.*\.htm;.*\.html;.*\.txt;"
+     *    primaryIndicator="true" /&gt;
+     * </pre>
+     */
+    protected void createDefaultClusterValves() {
+        if (log.isInfoEnabled()) {
+            log.info(sm.getString(
+                    "SimpleTcpCluster.default.addClusterValves",
+                    getClusterName()));
+        }
+        ReplicationValve valve= new ReplicationValve() ;
+        valve.setFilter(".*\\.gif;.*\\.js;.*\\.css;.*\\.png;.*\\.jpeg;.*\\.jpg;.*\\.htm;.*\\.html;.*\\.txt;");
+        valve.setPrimaryIndicator(true);
+        transferProperty("valve",valve);
+        addValve(valve);
+        
+    }
+
+    /**
+     * register all cluster valve to host or engine
+     * @throws Exception
+     * @throws ClassNotFoundException
+     */
+    protected void registerClusterValve() throws Exception {
+        if(container != null ) {
+            for (Iterator iter = valves.iterator(); iter.hasNext();) {
+                ClusterValve valve = (ClusterValve) iter.next();
+                if (log.isDebugEnabled())
+                    log.debug("Invoking addValve on " + getContainer()
+                            + " with class=" + valve.getClass().getName());
+                if (valve != null) {
+                    IntrospectionUtils.callMethodN(getContainer(), "addValve",
+                            new Object[] { valve },
+                            new Class[] { org.apache.catalina.Valve.class });
+
+                }
+                valve.setCluster(this);
+            }
+        }
+    }
+
+    /**
+     * unregister all cluster valve to host or engine
+     * @throws Exception
+     * @throws ClassNotFoundException
+     */
+    protected void unregisterClusterValve() throws Exception {
+        for (Iterator iter = valves.iterator(); iter.hasNext();) {
+            ClusterValve valve = (ClusterValve) iter.next();
+            if (log.isDebugEnabled())
+                log.debug("Invoking removeValve on " + getContainer()
+                        + " with class=" + valve.getClass().getName());
+            if (valve != null) {
+                    IntrospectionUtils.callMethodN(getContainer(), "removeValve",
+                        new Object[] { valve }, new Class[] { org.apache.catalina.Valve.class });
+            }
+            valve.setCluster(this);
+        }
+    }
+
+    /**
+     * Gracefully terminate the active cluster component.<br/>
+     * This will disconnect the cluster communication channel, stop the
+     * listener and deregister the valves from host or engine.<br/><br/>
+     * <b>Note:</b><br/>The sub elements receiver, sender, membership,
+     * listener or valves are not removed. You can easily start the cluster again.
+     * 
+     * @exception IllegalStateException
+     *                if this component has not been started
+     * @exception LifecycleException
+     *                if this component detects a fatal error that needs to be
+     *                reported
+     */
+    public void stop() throws LifecycleException {
+
+        if (!started)
+            throw new IllegalStateException(sm.getString("cluster.notStarted"));
+        // Notify our interested LifecycleListeners
+        lifecycle.fireLifecycleEvent(BEFORE_STOP_EVENT, this);
+
+        if (clusterDeployer != null) {
+            clusterDeployer.stop();
+        }
+        // FIXME remove registered managers!!
+        if(membershipService != null) {
+            membershipService.stop();
+            membershipService.removeMembershipListener();
+        }
+        if(clusterSender != null) {
+            try {
+                clusterSender.stop();
+            } catch (Exception x) {
+                log.error("Unable to stop cluster sender.", x);
+            }
+        }
+        if(clusterReceiver != null ){
+            try {
+                clusterReceiver.stop();
+                clusterReceiver.setCatalinaCluster(null);
+            } catch (Exception x) {
+                log.error("Unable to stop cluster receiver.", x);
+            }
+        }
+        unregisterMBeans();
+        try {
+            unregisterClusterValve();
+        } catch (Exception x) {
+            log.error("Unable to stop cluster valve.", x);
+        }
+        started = false;
+        // Notify our interested LifecycleListeners
+        lifecycle.fireLifecycleEvent(AFTER_STOP_EVENT, this);
+        clusterLog = null ;
+   }
+
+    /**
+     * send message to all cluster members same cluster domain
+     * 
+     * @see org.apache.catalina.cluster.CatalinaCluster#send(org.apache.catalina.cluster.ClusterMessage)
+     */
+    public void sendClusterDomain(ClusterMessage msg) {
+        long start = 0;
+        if (doClusterLog)
+            start = System.currentTimeMillis();
+        try {
+            msg.setAddress(membershipService.getLocalMember());
+            clusterSender.sendMessageClusterDomain(msg);
+        } catch (Exception x) {
+            if (notifyLifecycleListenerOnFailure) {
+                // Notify our interested LifecycleListeners
+                lifecycle.fireLifecycleEvent(SEND_MESSAGE_FAILURE_EVENT,
+                        new SendMessageData(msg, null, x));
+            }
+            log.error("Unable to send message through cluster sender.", x);
+        }
+        if (doClusterLog)
+            logSendMessage(msg, start, null);
+    } 
+
+
+    /**
+     * send message to all cluster members
+     * @param msg message to transfer
+     * 
+     * @see org.apache.catalina.cluster.CatalinaCluster#send(org.apache.catalina.cluster.ClusterMessage)
+     */
+    public void send(ClusterMessage msg) {
+        send(msg, null);
+    }
+
+    /**
+     * send a cluster message to one member (very usefull JMX method for remote scripting)
+     * 
+     * @param msg message to transfer
+     * @param dest Receiver member with name
+     * @see org.apache.catalina.cluster.CatalinaCluster#send(org.apache.catalina.cluster.ClusterMessage,
+     *      org.apache.catalina.cluster.Member)
+     * @see McastService#findMemberByName(String)
+     */
+    public void sendToMember(ClusterMessage msg, String dest) {
+        Member member = getMembershipService().findMemberByName(dest);
+        if (member != null) {
+            send(msg, member);
+        } else {
+            log.error("sendToMember: member " + dest + " not found!");
+        }        
+    }
+    
+    /**
+     * send a cluster message to one member
+     * 
+     * @param msg message to transfer
+     * @param dest Receiver member
+     * @see org.apache.catalina.cluster.CatalinaCluster#send(org.apache.catalina.cluster.ClusterMessage,
+     *      org.apache.catalina.cluster.Member)
+     */
+    public void send(ClusterMessage msg, Member dest) {
+        long start = 0;
+        if (doClusterLog)
+            start = System.currentTimeMillis();
+        try {
+            msg.setAddress(membershipService.getLocalMember());
+            if (dest != null) {
+                if (!membershipService.getLocalMember().equals(dest)) {
+                    clusterSender.sendMessage(msg, dest);
+                } else
+                    log.error("Unable to send message to local member " + msg);
+            } else {
+                clusterSender.sendMessage(msg);
+            }
+        } catch (Exception x) {
+            if (notifyLifecycleListenerOnFailure) {
+                // Notify our interested LifecycleListeners
+                lifecycle.fireLifecycleEvent(SEND_MESSAGE_FAILURE_EVENT,
+                        new SendMessageData(msg, dest, x));
+            }
+            log.error("Unable to send message through cluster sender.", x);
+        }
+        if (doClusterLog)
+            logSendMessage(msg, start, dest);
+    }
+
+    /**
+     * New cluster member is registered
+     * 
+     * @see org.apache.catalina.cluster.MembershipListener#memberAdded(org.apache.catalina.cluster.Member)
+     */
+    public void memberAdded(Member member) {
+        try {
+            if (log.isInfoEnabled())
+                log.info("Replication member added:" + member);
+            // Notify our interested LifecycleListeners
+            lifecycle.fireLifecycleEvent(BEFORE_MEMBERREGISTER_EVENT, member);
+            clusterSender.add(member);
+            // Notify our interested LifecycleListeners
+            lifecycle.fireLifecycleEvent(AFTER_MEMBERREGISTER_EVENT, member);
+        } catch (Exception x) {
+            log.error("Unable to connect to replication system.", x);
+        }
+
+    }
+
+    /**
+     * Cluster member is gone
+     * 
+     * @see org.apache.catalina.cluster.MembershipListener#memberDisappeared(org.apache.catalina.cluster.Member)
+     */
+    public void memberDisappeared(Member member) {
+        if (log.isInfoEnabled())
+            log.info("Received member disappeared:" + member);
+        try {
+            // Notify our interested LifecycleListeners
+            lifecycle.fireLifecycleEvent(BEFORE_MEMBERUNREGISTER_EVENT, member);
+            clusterSender.remove(member);
+            // Notify our interested LifecycleListeners
+            lifecycle.fireLifecycleEvent(AFTER_MEMBERUNREGISTER_EVENT, member);
+        } catch (Exception x) {
+            log.error("Unable remove cluster node from replication system.", x);
+        }
+
+    }
+
+    // --------------------------------------------------------- receiver
+    // messages
+
+    /**
+     * notify all listeners from receiving a new message is not ClusterMessage
+     * emitt Failure Event to LifecylceListener
+     * 
+     * @param message
+     *            receveived Message
+     */
+    public void receive(ClusterMessage message) {
+
+        long start = 0;
+        if (doClusterLog)
+            start = System.currentTimeMillis();
+        if (log.isDebugEnabled() && message != null)
+            log.debug("Assuming clocks are synched: Replication for "
+                    + message.getUniqueId() + " took="
+                    + (System.currentTimeMillis() - (message).getTimestamp())
+                    + " ms.");
+
+        //invoke all the listeners
+        boolean accepted = false;
+        if (message != null) {
+            for (Iterator iter = clusterListeners.iterator(); iter.hasNext();) {
+                MessageListener listener = (MessageListener) iter.next();
+                if (listener.accept(message)) {
+                    accepted = true;
+                    listener.messageReceived(message);
+                }
+            }
+        }
+        if (!accepted && log.isDebugEnabled()) {
+            if (notifyLifecycleListenerOnFailure) {
+                Member dest = message.getAddress();
+                // Notify our interested LifecycleListeners
+                lifecycle.fireLifecycleEvent(RECEIVE_MESSAGE_FAILURE_EVENT,
+                        new SendMessageData(message, dest, null));
+            }
+            log.debug("Message " + message.toString() + " from type "
+                    + message.getClass().getName()
+                    + " transfered but no listener registered");
+        }
+        if (doClusterLog)
+            logReceiveMessage(message, start, accepted);
+    }
+
+    // --------------------------------------------------------- Logger
+
+    /**
+     * @return Returns the clusterLogName.
+     */
+    public String getClusterLogName() {
+        return clusterLogName;
+    }
+    
+    /**
+     * @param clusterLogName The clusterLogName to set.
+     */
+    public void setClusterLogName(String clusterLogName) {
+        this.clusterLogName = clusterLogName;
+    }
+    
+    /**
+     * @return Returns the doClusterLog.
+     */
+    public boolean isDoClusterLog() {
+        return doClusterLog;
+    }
+    
+    /**
+     * @param doClusterLog The doClusterLog to set.
+     */
+    public void setDoClusterLog(boolean doClusterLog) {
+        this.doClusterLog = doClusterLog;
+    }    
+    public Log getLogger() {
+        return log;
+    }
+
+    public Log getClusterLog() {
+        if (clusterLog == null && clusterLogName != null
+                && !"".equals(clusterLogName))
+            clusterLog = LogFactory.getLog(clusterLogName);
+
+        return clusterLog;
+    }
+
+    /**
+     * log received message to cluster transfer log
+     * @param message
+     * @param start
+     * @param accepted
+     */
+    protected void logReceiveMessage(ClusterMessage message, long start,
+            boolean accepted) {
+        if (clusterLog != null && clusterLog.isInfoEnabled()) {
+            clusterLog.info(sm.getString("SimpleTcpCluster.log.receive", new Object[] {
+                    new Date(start),
+                    new Long(System.currentTimeMillis() - start),
+                    message.getAddress().getHost(),
+                    new Integer(message.getAddress().getPort()),
+                    message.getUniqueId(), new Boolean(accepted) }));
+        }
+    }
+
+    /**
+     * log sended message to cluster transfer log
+     * @param message
+     * @param start
+     * @param dest
+     */
+    protected void logSendMessage(ClusterMessage message, long start,
+            Member dest) {
+        if (clusterLog != null && clusterLog.isInfoEnabled()) {
+            if (dest != null) {
+                clusterLog.info(sm.getString("SimpleTcpCluster.log.send",
+                        new Object[] { new Date(start),
+                                new Long(System.currentTimeMillis() - start),
+                                dest.getHost(), new Integer(dest.getPort()),
+                                message.getUniqueId() }));
+            } else {
+                clusterLog.info(sm.getString("SimpleTcpCluster.log.send.all",
+                        new Object[] { new Date(start),
+                                new Long(System.currentTimeMillis() - start),
+                                message.getUniqueId() }));
+            }
+        }
+    }
+
+    // --------------------------------------------- JMX MBeans
+
+    /**
+     * register Means at cluster.
+     */
+    protected void registerMBeans() {
+        try {
+            getMBeanServer();
+            String domain = mserver.getDefaultDomain();
+            String name = ":type=Cluster";
+            if (container instanceof StandardHost) {
+                domain = ((StandardHost) container).getDomain();
+                name += ",host=" + container.getName();
+            } else {
+                if (container instanceof StandardEngine) {
+                    domain = ((StandardEngine) container).getDomain();
+                }
+            }
+            ObjectName clusterName = new ObjectName(domain + name);
+
+            if (mserver.isRegistered(clusterName)) {
+                if (log.isWarnEnabled())
+                    log.warn(sm.getString("cluster.mbean.register.already",
+                            clusterName));
+                return;
+            }
+            setObjectName(clusterName);
+            mserver.registerMBean(getManagedBean(this), getObjectName());
+        } catch (Exception ex) {
+            log.error(ex.getMessage(), ex);
+        }
+    }
+
+    protected void unregisterMBeans() {
+        if (mserver != null) {
+            try {
+                mserver.unregisterMBean(getObjectName());
+            } catch (Exception e) {
+                log.error(e);
+            }
+        }
+    }
+
+    /**
+     * Get current Catalina MBean Server and load mbean registry
+     * 
+     * @return The server
+     * @throws Exception
+     */
+    public MBeanServer getMBeanServer() throws Exception {
+        if (mserver == null) {
+            if (MBeanServerFactory.findMBeanServer(null).size() > 0) {
+                mserver = (MBeanServer) MBeanServerFactory
+                        .findMBeanServer(null).get(0);
+            } else {
+                mserver = MBeanServerFactory.createMBeanServer();
+            }
+            registry = Registry.getRegistry(null, null);
+            registry.loadMetadata(this.getClass().getResourceAsStream(
+                    "mbeans-descriptors.xml"));
+        }
+        return (mserver);
+    }
+
+    /**
+     * Returns the ModelMBean
+     * 
+     * @param object
+     *            The Object to get the ModelMBean for
+     * @return The ModelMBean
+     * @throws Exception
+     *             If an error occurs this constructors throws this exception
+     */
+    public ModelMBean getManagedBean(Object object) throws Exception {
+        ModelMBean mbean = null;
+        if (registry != null) {
+            ManagedBean managedBean = registry.findManagedBean(object
+                    .getClass().getName());
+            mbean = managedBean.createMBean(object);
+        }
+        return mbean;
+    }
+
+    public void setObjectName(ObjectName name) {
+        objectName = name;
+    }
+
+    public ObjectName getObjectName() {
+        return objectName;
+    }
+
+    // ------------------------------------------------------------- deprecated
+
+    /**
+     * 
+     * @see org.apache.catalina.Cluster#setProtocol(java.lang.String)
+     */
+    public void setProtocol(String protocol) {
+    }
+
+    /**
+     * @see org.apache.catalina.Cluster#getProtocol()
+     */
+    public String getProtocol() {
+        return null;
+    }
+
+    /**
+     * @see org.apache.catalina.Cluster#startContext(java.lang.String)
+     */
+    public void startContext(String contextPath) throws IOException {
+        
+    }
+
+    /**
+     * @see org.apache.catalina.Cluster#installContext(java.lang.String, java.net.URL)
+     */
+    public void installContext(String contextPath, URL war) {
+        
+    }
+
+    /**
+     * @see org.apache.catalina.Cluster#stop(java.lang.String)
+     */
+    public void stop(String contextPath) throws IOException {
+        
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/tcp/SocketReplicationListener.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/tcp/SocketReplicationListener.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/tcp/SocketReplicationListener.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,256 @@
+/*
+ * Copyright 1999,2004-2005 The Apache Software Foundation.
+ * 
+ * Licensed 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.cluster.tcp;
+
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.ServerSocket;
+import java.net.Socket;
+
+import org.apache.catalina.util.StringManager;
+
+/**
+ * @author Peter Rossbach
+ * @version $Revision: 304032 $, $Date: 2005-07-27 10:11:55 -0500 (Wed, 27 Jul 2005) $
+ */
+public class SocketReplicationListener extends ClusterReceiverBase {
+
+    // ---------------------------------------------------- Statics
+
+    private static org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory
+            .getLog(SocketReplicationListener.class);
+
+    /**
+     * The string manager for this package.
+     */
+    protected static StringManager sm = StringManager
+            .getManager(Constants.Package);
+   
+    /**
+     * The descriptive information about this implementation.
+     */
+    private static final String info = "SocketReplicationListener/1.2";
+
+    //  ---------------------------------------------------- Properties
+    private ServerSocket serverSocket = null;
+
+    private int tcpListenMaxPort ;
+    
+    /**
+     * 
+     * One second timeout to wait that socket started
+     */
+    private int tcpListenTimeout = 1 ;
+    
+    //  ---------------------------------------------------- Constructor
+
+    public SocketReplicationListener() {
+    }
+
+    //  ---------------------------------------------------- Properties
+
+    /**
+     * Return descriptive information about this implementation and the
+     * corresponding version number, in the format
+     * <code>&lt;description&gt;/&lt;version&gt;</code>.
+     */
+    public String getInfo() {
+        return (info);
+    }
+    
+    /**
+     * @return Returns the tcpListenMaxPort.
+     */
+    public int getTcpListenMaxPort() {
+        return tcpListenMaxPort;
+    }
+    
+    /**
+     * @param maxListenPort The tcpListenMaxPort to set.
+     */
+    public void setTcpListenMaxPort(int maxListenPort) {
+        this.tcpListenMaxPort = maxListenPort;
+    }
+     
+    /**
+     * @return Returns the tcpListenTimeout.
+     */
+    public int getTcpListenTimeout() {
+        return tcpListenTimeout;
+    }
+    /**
+     * @param tcpListenTimeout The tcpListenTimeout to set.
+     */
+    public void setTcpListenTimeout(int tcpListenTimeout) {
+        this.tcpListenTimeout = tcpListenTimeout;
+    }
+
+    //  ---------------------------------------------------- public methods
+
+    /**
+     * Wait the createServerSocket find the correct socket port when default config is used.
+     * @see org.apache.catalina.cluster.ClusterReceiver#start()
+     * @see #createServerSocket()
+     */
+    public void start() {
+        super.start();
+        long reqStart = System.currentTimeMillis();
+        long reqNow = 0 ;
+        boolean isTimeout = false ;
+        do {
+            try {
+                Thread.sleep(50);
+            } catch (Exception sleep) {
+            }
+            reqNow = System.currentTimeMillis();
+            isTimeout = ((reqNow - reqStart) > (1000 * getTcpListenTimeout()));
+        } while (!doListen && (!isTimeout));
+        if (isTimeout || (!doListen)) {
+            log.error(sm.getString("SocketReplictionListener.timeout",
+                    getTcpListenAddress(),Integer.toString(getTcpListenPort()),
+                    Long.toString(reqNow - reqStart), Boolean.toString(doListen)));
+        }
+    }
+    
+    //  ---------------------------------------------------- protected methods
+
+    /**
+     * Master/Slave Sender handling / bind Server Socket at addres and port
+     * 
+     * @throws Exception
+     */
+    protected void listen() {
+        if (doListen) {
+            log.warn(sm.getString("SocketReplictionListener.allreadyExists",
+                    getTcpListenAddress(),Integer.toString(getTcpListenPort())));
+            return;
+        }
+
+        // Get the associated ServerSocket to bind it with
+        try {
+            serverSocket = createServerSocket();
+            if(serverSocket != null) {
+                doListen = true;
+                while (doListen) {
+                    try {
+                        Socket socket = serverSocket.accept();
+                        if (doListen) {
+                            SocketReplicationThread t = new SocketReplicationThread(
+                                    this, socket);
+                            t.setDaemon(true);
+                            t.start();
+                        }
+                    } catch (IOException iex) {
+                        log.warn(sm.getString("SocketReplictionListener.accept.failure",
+                                getTcpListenAddress(),
+                                Integer.toString(getTcpListenPort())), iex);
+                    }
+                }
+                serverSocket.close();
+            } else {
+                log.fatal(sm.getString("SocketReplictionListener.serverSocket.notExists",
+                        getTcpListenAddress(),
+                        Integer.toString(getTcpListenPort()),
+                        Integer.toString(getTcpListenMaxPort())));
+            }                
+        } catch (IOException iex) {
+            log.warn(sm.getString("SocketReplictionListener.openclose.failure",
+                    getTcpListenAddress(),
+                    Integer.toString(getTcpListenPort())), iex);
+        } finally {
+            doListen = false;
+            serverSocket = null;
+        }
+    }
+
+    /**
+     * create a Server Socket between tcpListenerPort and tcpListenMaxPort
+     */
+    protected ServerSocket createServerSocket() {
+        int startPort = getTcpListenPort() ;
+        int maxPort = getTcpListenMaxPort() ;
+        InetAddress inet = getBind() ;
+        ServerSocket sSocket = null ;
+        if (maxPort < startPort)
+            maxPort = startPort;
+        for( int i=startPort; i<=maxPort; i++ ) {
+            try {
+                if( inet == null ) {
+                    sSocket = new ServerSocket( i, 0 );
+                } else {
+                    sSocket=new ServerSocket( i, 0, inet );
+                }
+                setTcpListenPort(i);
+                break;
+            } catch( IOException ex ) {
+                if(log.isDebugEnabled())
+                    log.debug(sm.getString("SocketReplictionListener.portbusy",
+                            inet.getHostAddress(),
+                            Integer.toString(i), 
+                            ex.toString()));
+                continue;
+            }
+        }
+        if(sSocket != null && log.isInfoEnabled())
+            log.info(sm.getString("SocketReplictionListener.open",
+                    inet.getHostAddress(),
+                    Integer.toString(getTcpListenPort())));
+        return sSocket ;
+   }
+
+    /**
+     * Need to create a connection to unlock the ServerSocker#accept(). Very
+     * fine trick from channelSocket :-)  See
+     * org.apache.jk.common.ChannelSocket's unLockSocket method (it's private,
+     * so you may need to inspect the source).
+     */
+    protected void unLockSocket() {
+        Socket s = null;
+        InetAddress ladr = getBind();
+
+        try {
+            if (ladr == null || "0.0.0.0".equals(ladr.getHostAddress())) {
+                ladr = InetAddress.getLocalHost();
+            }
+            s = new Socket(ladr, getTcpListenPort());
+            // setting soLinger to a small value will help shutdown the
+            // connection quicker
+            s.setSoLinger(true, 0);
+
+        } catch (IOException iex) {
+            log.warn(sm.getString("SocketReplictionListener.unlockSocket.failure",
+                    getTcpListenAddress(),
+                    Integer.toString(getTcpListenPort())), iex);
+        } finally {
+            try {
+                if (s != null)
+                    s.close();
+            } catch (IOException ignore) {
+            }
+        }
+    }
+
+    /**
+     * Close serverSockets
+     * FIXME the channelSocket to connect own socket to terminate accpet loop!
+     */
+    protected void stopListening() {
+        unLockSocket();
+        doListen = false;
+    }
+    
+ }

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/tcp/SocketReplicationThread.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/tcp/SocketReplicationThread.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/tcp/SocketReplicationThread.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,128 @@
+/*
+ * Copyright 1999,2005 The Apache Software Foundation.
+ * 
+ * Licensed 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.cluster.tcp;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.Socket;
+import java.net.SocketException;
+
+import org.apache.catalina.cluster.io.ListenCallback;
+import org.apache.catalina.cluster.io.SocketObjectReader;
+
+/**
+ * @author Peter Rossbach
+ * FIXME ThreadPooling
+ * FIXME Socket timeout
+ * @version $Revision: 345232 $, $Date: 2005-11-17 05:58:42 -0600 (Thu, 17 Nov 2005) $
+ */
+public class SocketReplicationThread extends Thread implements ListenCallback {
+    private static org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory
+            .getLog(SocketReplicationThread.class);
+
+    private static byte[] ACK_COMMAND = new byte[] { 6, 2, 3 };
+
+    private static int count = 0;
+
+    private SocketReplicationListener master;
+
+    private Socket socket;
+
+    private SocketObjectReader reader;
+
+    private boolean keepRunning = true;
+
+    /**
+     * Fork Listen Worker Thread!
+     * 
+     * @param socket
+     * @param reader
+     * @param sendAck
+     */
+    SocketReplicationThread(SocketReplicationListener master, Socket socket
+           ) {
+        super("ClusterListenThread-" + count++);
+        this.master = master;
+        this.socket = socket;
+        this.reader =  new SocketObjectReader(socket,this);
+    }
+
+    /**
+     * read sender messages / is message complete send ack and wait for next
+     * message!
+     * 
+     * @see SocketObjectReader#append(byte[],int,int)
+     * @see java.lang.Runnable#run()
+     */
+    public void run() {
+        try {
+            byte[] buffer = new byte[1024];
+            InputStream in = socket.getInputStream();
+            while (keepRunning) {
+                int cnt = in.read(buffer);
+                if (log.isTraceEnabled()) {
+                    log.trace("read " + cnt + " bytes from " + socket.getPort());
+                }
+                int ack = 0;
+                if (cnt > 0) {
+                    ack = reader.append(buffer, 0, cnt);
+                    if (log.isTraceEnabled()) {
+                        log.trace("sending " + ack + " ack packages to " + socket.getLocalPort() );
+                    }
+                    keepRunning = master.isDoListen();
+                } else
+                    // EOF
+                    keepRunning = false;
+            }
+        } catch (SocketException se) {
+            // ignore this: normal shutdown or stop listen socket 
+        } catch (IOException x) {
+            log.error("Unable to read data from client, disconnecting.", x);
+        } finally {
+            // finish socket
+            if (socket != null) {
+                try {
+
+                    socket.close();
+                } catch (Exception ignore) {
+                }
+            }
+            keepRunning = false;
+            socket = null;
+        }
+    }
+    
+    public void messageDataReceived(ClusterData data) {
+        master.messageDataReceived(data);
+    }   
+    
+    public boolean isSendAck() {
+        return master.isSendAck();
+    }
+    
+    /**
+     * send a reply-acknowledgement
+     * 
+     * @throws java.io.IOException
+     */
+    public void sendAck() throws java.io.IOException {
+        socket.getOutputStream().write(ACK_COMMAND);
+        if (log.isTraceEnabled()) {
+            log.trace("ACK sent to " + socket.getPort());
+        }
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/tcp/SocketSender.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/tcp/SocketSender.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/tcp/SocketSender.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,71 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.cluster.tcp;
+
+import java.net.InetAddress;
+
+/**
+ * Send cluster messages sync to request with only one socket.
+ * 
+ * @author Filip Hanik
+ * @author Peter Rossbach
+ * @version 1.2
+ */
+
+public class SocketSender extends DataSender {
+    // ----------------------------------------------------- Instance Variables
+
+    /**
+     * The descriptive information about this implementation.
+     */
+    private static final String info = "SocketSender/1.2";
+
+    // ------------------------------------------------------------- Constructor
+   
+   /**
+    * @param domain replication cluster domain (session domain)
+    * @param host replication node tcp address
+    * @param port replication node tcp port
+    */
+    public SocketSender(String domain,InetAddress host, int port) {
+        super(domain,host, port);
+    }
+
+    public SocketSender(String domain,InetAddress host, int port, SenderState state) {
+        super(domain,host, port, state);
+    }
+
+    // ------------------------------------------------------------- Properties
+
+    /**
+     * Return descriptive information about this implementation and the
+     * corresponding version number, in the format
+     * <code>&lt;description&gt;/&lt;version&gt;</code>.
+     */
+    public String getInfo() {
+
+        return (info);
+
+    }
+
+    public String toString() {
+        StringBuffer buf = new StringBuffer("SocketSender[");
+        buf.append(getAddress()).append(":").append(getPort()).append("]");
+        return buf.toString();
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/tcp/TcpReplicationThread.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/tcp/TcpReplicationThread.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/tcp/TcpReplicationThread.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,184 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.cluster.tcp;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.channels.SelectionKey;
+import java.nio.channels.SocketChannel;
+
+import org.apache.catalina.cluster.io.ObjectReader;
+
+/**
+ * A worker thread class which can drain channels and echo-back the input. Each
+ * instance is constructed with a reference to the owning thread pool object.
+ * When started, the thread loops forever waiting to be awakened to service the
+ * channel associated with a SelectionKey object. The worker is tasked by
+ * calling its serviceChannel() method with a SelectionKey object. The
+ * serviceChannel() method stores the key reference in the thread object then
+ * calls notify() to wake it up. When the channel has been drained, the worker
+ * thread returns itself to its parent pool.
+ * 
+ * @author Filip Hanik
+ * 
+ * @version $Revision: 390625 $, $Date: 2006-04-01 03:23:46 -0600 (Sat, 01 Apr 2006) $
+ */
+public class TcpReplicationThread extends WorkerThread {
+    public static final byte[] ACK_COMMAND = new byte[] {6, 2, 3};
+    private static org.apache.commons.logging.Log log =
+        org.apache.commons.logging.LogFactory.getLog( TcpReplicationThread.class );
+    private ByteBuffer buffer = ByteBuffer.allocate (1024);
+    private SelectionKey key;
+    private boolean sendAck=true;
+
+    
+    TcpReplicationThread ()
+    {
+    }
+
+    // loop forever waiting for work to do
+    public synchronized void run()
+    {
+        while (doRun) {
+            try {
+                // sleep and release object lock
+                this.wait();
+            } catch (InterruptedException e) {
+                if(log.isInfoEnabled())
+                    log.info("TCP worker thread interrupted in cluster",e);
+                // clear interrupt status
+                Thread.interrupted();
+            }
+            if (key == null) {
+                continue;	// just in case
+            }
+            try {
+                drainChannel (key);
+            } catch (Exception e) {
+                //this is common, since the sockets on the other
+                //end expire after a certain time.
+                if ( e instanceof IOException ) {
+                    //dont spew out stack traces for IO exceptions unless debug is enabled.
+                    if (log.isDebugEnabled()) log.debug ("IOException in replication worker, unable to drain channel. Probable cause: Keep alive socket closed.", e);
+                } else if ( log.isErrorEnabled() ) {
+                    //this is a real error, log it.
+                    log.error("Exception caught in TcpReplicationThread.drainChannel.",e);
+                } 
+
+                // close channel and nudge selector
+                try {
+                    key.channel().close();
+                } catch (IOException ex) {
+                    log.error("Unable to close channel.",ex);
+                }
+                key.selector().wakeup();
+            }
+            key = null;
+            // done, ready for more, return to pool
+            this.pool.returnWorker (this);
+        }
+    }
+
+    /**
+     * Called to initiate a unit of work by this worker thread
+     * on the provided SelectionKey object.  This method is
+     * synchronized, as is the run() method, so only one key
+     * can be serviced at a given time.
+     * Before waking the worker thread, and before returning
+     * to the main selection loop, this key's interest set is
+     * updated to remove OP_READ.  This will cause the selector
+     * to ignore read-readiness for this channel while the
+     * worker thread is servicing it.
+     */
+    synchronized void serviceChannel (SelectionKey key, boolean sendAck)
+    {
+        this.key = key;
+        this.sendAck=sendAck;
+        key.interestOps (key.interestOps() & (~SelectionKey.OP_READ));
+        key.interestOps (key.interestOps() & (~SelectionKey.OP_WRITE));
+        this.notify();		// awaken the thread
+    }
+
+    /**
+     * The actual code which drains the channel associated with
+     * the given key.  This method assumes the key has been
+     * modified prior to invocation to turn off selection
+     * interest in OP_READ.  When this method completes it
+     * re-enables OP_READ and calls wakeup() on the selector
+     * so the selector will resume watching this channel.
+     */
+    protected void drainChannel (SelectionKey key)
+        throws Exception
+    {
+        boolean packetReceived=false;
+        SocketChannel channel = (SocketChannel) key.channel();
+        int count;
+        buffer.clear();			// make buffer empty
+        ObjectReader reader = (ObjectReader)key.attachment();
+        // loop while data available, channel is non-blocking
+        while ((count = channel.read (buffer)) > 0) {
+            buffer.flip();		// make buffer readable
+            reader.append(buffer.array(),0,count);
+            buffer.clear();		// make buffer empty
+        }
+        //check to see if any data is available
+        int pkgcnt = reader.execute();
+        if (log.isTraceEnabled()) {
+            log.trace("sending " + pkgcnt + " ack packages to " + channel.socket().getLocalPort() );
+        }
+        
+        if (sendAck) {
+            while ( pkgcnt > 0 ) {
+                sendAck(key,channel);
+                pkgcnt--;
+            }
+        }
+        
+        if (count < 0) {
+            // close channel on EOF, invalidates the key
+            channel.close();
+            return;
+        }
+        
+        //acquire the interestOps mutex
+        Object mutex = this.getPool().getInterestOpsMutex();
+        synchronized (mutex) {
+            // cycle the selector so this key is active again
+            key.selector().wakeup();
+            // resume interest in OP_READ, OP_WRITE
+            int resumeOps = key.interestOps() | SelectionKey.OP_READ;
+            key.interestOps(resumeOps);
+        }
+        
+    }
+
+    /**
+     * send a reply-acknowledgement (6,2,3)
+     * @param key
+     * @param channel
+     */
+    protected void sendAck(SelectionKey key, SocketChannel channel) {
+        
+        try {
+            channel.write(ByteBuffer.wrap(ACK_COMMAND));
+            if (log.isTraceEnabled()) {
+                log.trace("ACK sent to " + channel.socket().getPort());
+            }
+        } catch ( java.io.IOException x ) {
+            log.warn("Unable to send ACK back through channel, channel disconnected?: "+x.getMessage());
+        }
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/tcp/ThreadPool.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/tcp/ThreadPool.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/tcp/ThreadPool.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,95 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.cluster.tcp;
+import java.util.List;
+import java.util.LinkedList;
+
+/**
+ * @author not attributable
+ * @version 1.0
+ */
+
+public class ThreadPool
+{
+    /**
+     * A very simple thread pool class.  The pool size is set at
+     * construction time and remains fixed.  Threads are cycled
+     * through a FIFO idle queue.
+     */
+
+    List idle = new LinkedList();
+    Object mutex = new Object();
+    Object interestOpsMutex = null;
+
+    ThreadPool (int poolSize, Class threadClass, Object interestOpsMutex) throws Exception {
+        // fill up the pool with worker threads
+        this.interestOpsMutex = interestOpsMutex;
+        for (int i = 0; i < poolSize; i++) {
+            WorkerThread thread = (WorkerThread)threadClass.newInstance();
+            thread.setPool(this);
+
+            // set thread name for debugging, start it
+            thread.setName (threadClass.getName()+"[" + (i + 1)+"]");
+            thread.setDaemon(true);
+            thread.setPriority(Thread.MAX_PRIORITY);
+            thread.start();
+
+            idle.add (thread);
+        }
+    }
+
+    /**
+     * Find an idle worker thread, if any.  Could return null.
+     */
+    WorkerThread getWorker()
+    {
+        WorkerThread worker = null;
+
+        
+        synchronized (mutex) {
+            while ( worker == null ) {
+                if (idle.size() > 0) {
+                    try {
+                        worker = (WorkerThread) idle.remove(0);
+                    } catch (java.util.NoSuchElementException x) {
+                        //this means that there are no available workers
+                        worker = null;
+                    }
+                } else {
+                    try { mutex.wait(); } catch ( java.lang.InterruptedException x ) {}
+                }
+            }
+        }
+
+        return (worker);
+    }
+
+    /**
+     * Called by the worker thread to return itself to the
+     * idle pool.
+     */
+    void returnWorker (WorkerThread worker)
+    {
+        synchronized (mutex) {
+            idle.add (worker);
+            mutex.notify();
+        }
+    }
+    public Object getInterestOpsMutex() {
+        return interestOpsMutex;
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/tcp/WorkerThread.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/tcp/WorkerThread.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/tcp/WorkerThread.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,44 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.cluster.tcp;
+
+
+/**
+ * @author Filip Hanik
+ * @version $Revision: 366253 $ $Date: 2006-01-05 13:30:42 -0600 (Thu, 05 Jan 2006) $
+ */
+public class WorkerThread extends Thread
+{
+    protected ThreadPool pool;
+    protected boolean doRun = true;
+
+
+    public void setPool(ThreadPool pool) {
+        this.pool = pool;
+    }
+    
+    public ThreadPool getPool() {
+        return pool;
+    }
+
+    public void close()
+    {
+        doRun = false;
+        notify();
+
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/tcp/mbeans-descriptors.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/tcp/mbeans-descriptors.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/tcp/mbeans-descriptors.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,1052 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mbeans-descriptors PUBLIC
+   "-//Apache Software Foundation//DTD Model MBeans Configuration File"
+   "http://jakarta.apache.org/commons/dtds/mbeans-descriptors.dtd">
+<mbeans-descriptors>
+
+  <mbean         name="SimpleTcpCluster"
+           description="Tcp Cluster implementation"
+               domain="Catalina"
+                group="Cluster"
+                 type="org.apache.catalina.cluster.tcp.SimpleTcpCluster">
+    <attribute   name="info"
+          description="Class version info"
+                 type="java.lang.String"
+                 writeable="false"/>
+    <attribute   name="notifyLifecycleListenerOnFailure"
+          description="notify lifecycleListener from message transfer failure"
+			     is="true"
+                 type="boolean"/>                 
+    <attribute   name="clusterName"
+          description="name of cluster"
+                 type="java.lang.String"/>
+    <attribute   name="managerClassName"
+          description="session mananager classname"
+                 type="java.lang.String"/>
+    <attribute   name="clusterLogName"
+          description="Name of cluster transfer log device"
+                 type="java.lang.String"/>
+    <attribute   name="doClusterLog"
+			     is="true"
+          description="enable cluster log transfer logging"
+                 type="boolean"/>
+    <operation   name="setProperty"
+               description="set a property to all cluster managers (with prefix 'manager.')"
+               impact="ACTION"
+               returnType="void">
+      <parameter name="key"
+                 description="Property name"
+                 type="java.lang.String"/>
+      <parameter name="value"
+                 description="Property value"
+                 type="java.lang.String"/>
+    </operation>
+
+    <operation   name="send"
+               description="send message to all cluster members"
+               impact="ACTION"
+               returnType="void">
+      <parameter name="message"
+                 description="replication message"
+                 type="org.apache.catalina.cluster.ClusterMessage"/>
+    </operation>
+    
+    <operation   name="sendClusterDomain"
+               description="send message to all cluster members with same domain"
+               impact="ACTION"
+               returnType="void">
+      <parameter name="message"
+                 description="replication message"
+                 type="org.apache.catalina.cluster.ClusterMessage"/>
+    </operation>
+        
+    <operation   name="sendToMember"
+               description="send message to one cluster member"
+               impact="ACTION"
+               returnType="void">
+      <parameter name="message"
+                 description="replication message"
+                 type="org.apache.catalina.cluster.ClusterMessage"/>
+      <parameter name="member"
+                 description="cluster member"
+                 type="java.lang.String"/>
+    </operation>
+
+    <operation   name="start"
+               description="Start the cluster"
+               impact="ACTION"
+               returnType="void">
+    </operation>
+    
+    <operation name="stop"
+               description="Stop the cluster"
+               impact="ACTION"
+               returnType="void">
+    </operation>
+                 
+  </mbean>
+
+  <mbean         name="ReplicationListener"
+           description="Tcp Cluster ReplicationListener implementation"
+               domain="Catalina"
+                group="Cluster"
+                 type="org.apache.catalina.cluster.tcp.ReplicationListener">
+    <attribute   name="info"
+          description="Class version info"
+                 type="java.lang.String"
+                 writeable="false"/>
+    <attribute   name="tcpListenAddress"
+          description="tcp listener address"
+                 type="java.lang.String"/>
+    <attribute   name="tcpListenPort"
+          description="tcp listener port"
+                 type="int"/>
+    <attribute   name="tcpThreadCount"
+          description="number of tcp listener worker threads"
+                 type="int"/>
+    <attribute   name="tcpSelectorTimeout"
+          description="tcp listener Selector timeout"
+                 type="long"/>
+    <attribute   name="nrOfMsgsReceived"
+          description="number of messages received from other nodes"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="receivedTime"
+          description="total time message send time"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="receivedProcessingTime"
+          description="received processing time"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="minReceivedProcessingTime"
+          description="minimal received processing time"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="avgReceivedProcessingTime"
+          description="received processing time / nrOfRequests"
+                 type="double"
+                 writeable="false"/>
+    <attribute   name="maxReceivedProcessingTime"
+          description="maximal received processing time"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="doReceivedProcessingStats"
+          description="create received processing time stats"
+			     is="true"
+                 type="boolean" />                
+    <attribute   name="avgTotalReceivedBytes"
+          description="received totalReceivedBytes / nrOfMsgsReceived"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="totalReceivedBytes"
+          description="number of bytes received"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="sendAck"
+          description="send ack after data received"
+			     is="true"
+                 type="boolean"
+                 writeable="false" />
+    <attribute   name="compress"
+          description="data received compressed"
+			     is="true"
+                 type="boolean"
+                 writeable="false" />
+    <attribute   name="doListen"
+          description="is port really started"
+			     is="true"
+                 type="boolean"
+                 writeable="false" />
+                 
+	<operation name="resetStatistics"
+               description="Reset all statistics"
+               impact="ACTION"
+               returnType="void">
+    </operation>	
+
+    <operation   name="start"
+               description="Start the cluster"
+               impact="ACTION"
+               returnType="void">
+    </operation>
+    
+    <operation name="stop"
+               description="Stop the cluster"
+               impact="ACTION"
+               returnType="void">
+    </operation>
+                 
+  </mbean>
+
+  <mbean         name="SocketReplicationListener"
+           description="Tcp Cluster SocketReplicationListener implementation"
+               domain="Catalina"
+                group="Cluster"
+                 type="org.apache.catalina.cluster.tcp.SocketReplicationListener">
+    <attribute   name="info"
+          description="Class version info"
+                 type="java.lang.String"
+                 writeable="false"/>
+    <attribute   name="tcpListenAddress"
+          description="tcp listener address"
+                 type="java.lang.String"/>
+    <attribute   name="tcpListenPort"
+          description="tcp listener port"
+                 type="int"/>
+    <attribute   name="tcpListenMaxPort"
+          description="max tcp listen used port"
+                 type="int"/>
+    <attribute   name="tcpListenTimeout"
+          description="max tcp listen timeout (sec) wait for ServerSocket start"
+                 type="int"/>                
+    <attribute   name="nrOfMsgsReceived"
+          description="number of messages received from other nodes"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="receivedTime"
+          description="total time message send time"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="receivedProcessingTime"
+          description="received processing time"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="minReceivedProcessingTime"
+          description="minimal received processing time"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="avgReceivedProcessingTime"
+          description="received processing time / nrOfRequests"
+                 type="double"
+                 writeable="false"/>
+    <attribute   name="maxReceivedProcessingTime"
+          description="maximal received processing time"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="doReceivedProcessingStats"
+          description="create received processing time stats"
+			     is="true"
+                 type="boolean" />                
+    <attribute   name="avgTotalReceivedBytes"
+          description="received totalReceivedBytes / nrOfMsgsReceived"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="totalReceivedBytes"
+          description="number of bytes received"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="sendAck"
+          description="send ack after data received"
+			     is="true"
+                 type="boolean"
+                 writeable="false" />
+   <attribute   name="compress"
+          description="data received compressed"
+			     is="true"
+                 type="boolean"
+                 writeable="false" />
+   <attribute   name="doListen"
+          description="is port really started"
+			     is="true"
+                 type="boolean"
+                 writeable="false" />
+                 
+	<operation name="resetStatistics"
+               description="Reset all statistics"
+               impact="ACTION"
+               returnType="void">
+    </operation>	
+
+    <operation   name="start"
+               description="Start the cluster"
+               impact="ACTION"
+               returnType="void">
+    </operation>
+    
+    <operation name="stop"
+               description="Stop the cluster"
+               impact="ACTION"
+               returnType="void">
+    </operation>
+                 
+  </mbean>
+  
+  <mbean         name="ReplicationTransmitter"
+          description="Tcp replication transmitter"
+               domain="Catalina"
+                group="ClusterSender"
+                 type="org.apache.catalina.cluster.tcp.ReplicationTransmitter">
+    <attribute   name="info"
+          description="Class version info"
+                 type="java.lang.String"
+                 writeable="false"/>
+    <attribute   name="replicationMode"
+          description="replication mode (synchnous,pooled.asynchnous,fastasyncqueue)"
+                 type="java.lang.String"/>
+    <attribute   name="ackTimeout"
+          description="acknowledge timeout"
+                 type="long"/>
+    <attribute   name="autoConnect"
+          description="is sender disabled, fork a new socket"
+			     is="true"
+                 type="boolean" />
+    <attribute   name="waitForAck"
+          description="Wait for ack after data send"
+			     is="true"
+                 type="boolean"
+                 writeable="false" />
+    <attribute   name="processingTime"
+          description="sending processing time"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="minProcessingTime"
+          description="minimal sending processing time"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="avgProcessingTime"
+          description="processing time / nrOfRequests"
+                 type="double"
+                 writeable="false"/>
+    <attribute   name="maxProcessingTime"
+          description="maximal sending processing time"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="doTransmitterProcessingStats"
+          description="create processing time stats"
+			     is="true"
+                 type="boolean" />                
+    <attribute   name="nrOfRequests"
+          description="number of send messages to other members"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="totalBytes"
+          description="number of bytes transfered"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="failureCounter"
+          description="number of wrong transfers"
+                 type="long"
+                 writeable="false"/>
+	<attribute name="senderObjectNames"
+               description="get all sender object names"
+               type="[Ljavax.management.ObjectName;"
+               writeable="false"/>
+    <operation   name="start"
+               description="Start the cluster"
+               impact="ACTION"
+               returnType="void">
+    </operation>    
+    <operation name="stop"
+               description="Stop the cluster"
+               impact="ACTION"
+               returnType="void">
+    </operation>
+	<operation name="resetStatistics"
+               description="Reset all statistics"
+               impact="ACTION"
+               returnType="void">
+    </operation>	
+	<operation name="checkKeepAlive"
+               description="Check all sender connection for close socket (keepalive)"
+               impact="ACTION"
+               returnType="void">
+    </operation>
+  </mbean>
+
+  <mbean         name="AsyncSocketSender"
+          description="Async Cluster Sender"
+               domain="Catalina"
+                group="IDataSender"
+                 type="org.apache.catalina.cluster.tcp.AsyncSocketSender">
+    <attribute   name="info"
+          description="Class version info"
+                 type="java.lang.String"
+                 writeable="false"/>
+    <attribute   name="address"
+          description="sender ip address"
+                 type="java.net.InetAddress"
+                 writeable="false"/>
+    <attribute   name="port"
+          description="sender port"
+                 type="int"
+                 writeable="false" />
+    <attribute   name="suspect"
+          description="Socket is gone"
+                 type="boolean"/>
+    <attribute   name="waitForAck"
+          description="Wait for ack after data send"
+			     is="true"
+                 type="boolean"
+                 writeable="false"/>
+    <attribute   name="ackTimeout"
+          description="acknowledge timeout"
+                 type="long"/>                 
+    <attribute   name="avgMessageSize"
+                 writeable="false"
+          description="avg message size (totalbytes/nrOfRequests"
+                 type="long"/>
+    <attribute   name="queueSize"
+                 writeable="false"
+          description="queue size"
+                 type="int"/>
+    <attribute   name="queuedNrOfBytes"
+                 writeable="false"
+          description="number of bytes over all queued messages"
+                 type="long"/>
+    <attribute   name="messageTransferStarted"
+          description="message is in transfer"
+                 type="boolean"
+                 is="true"
+                 writeable="false"/>
+    <attribute   name="keepAliveTimeout"
+          description="active socket keep alive timeout"
+                 type="long"/>
+    <attribute   name="keepAliveMaxRequestCount"
+          description="max request over this socket"
+                 type="int"/>
+    <attribute   name="keepAliveCount"
+          description="keep Alive request count"
+                 type="int"
+                 writeable="false"/>
+    <attribute   name="keepAliveConnectTime"
+          description="Connect time for keep alive"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="resend"
+          description="after send failure make a resend"
+			     is="true"
+                 type="boolean" />
+    <attribute   name="connected"
+                 is="true"
+          description="socket connected"
+                 type="boolean"
+                 writeable="false"/>
+    <attribute   name="nrOfRequests"
+          description="number of send messages to other members"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="totalBytes"
+          description="number of bytes transfered"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="processingTime"
+          description="sending processing time"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="minProcessingTime"
+          description="minimal sending processing time"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="avgProcessingTime"
+          description="processing time / nrOfRequests"
+                 type="double"
+                 writeable="false"/>
+    <attribute   name="maxProcessingTime"
+          description="maximal sending processing time"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="doProcessingStats"
+          description="create processing time stats"
+			     is="true"
+                 type="boolean" />
+    <attribute   name="waitAckTime"
+          description="sending waitAck time"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="minWaitAckTime"
+          description="minimal sending waitAck time"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="avgWaitAckTime"
+          description="waitAck time / nrOfRequests"
+                 type="double"
+                 writeable="false"/>
+    <attribute   name="maxWaitAckTime"
+          description="maximal sending waitAck time"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="doWaitAckStats"
+          description="create waitAck time stats"
+			     is="true"
+                 type="boolean" />
+    <attribute   name="connectCounter"
+          description="counts connects"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="disconnectCounter"
+          description="counts disconnects"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="socketOpenCounter"
+          description="counts open socket (KeepAlive and connects)"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="socketOpenFailureCounter"
+          description="counts open socket failures"
+                 type="long"
+                 writeable="false"/>                 				 
+    <attribute   name="socketCloseCounter"
+          description="counts closed socket (KeepAlive and disconnects)"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="missingAckCounter"
+          description="counts missing ack"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="dataResendCounter"
+          description="counts data resends"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="dataFailureCounter"
+          description="counts data send failures"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="inQueueCounter"
+          description="counts all queued messages"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="outQueueCounter"
+          description="counts all successfully sended messages"
+                 type="long"
+                 writeable="false"/>
+	<operation name="connect"
+               description="connect to other replication node"
+               impact="ACTION"
+               returnType="void">
+    </operation>
+	<operation name="disconnect"
+               description="disconnect to other replication node"
+               impact="ACTION"
+               returnType="void">
+    </operation>
+	<operation name="checkKeepAlive"
+               description="Check connection for close socket"
+               impact="ACTION"
+               returnType="boolean">
+    </operation>
+	<operation name="resetStatistics"
+               description="Reset all statistics"
+               impact="ACTION"
+               returnType="void">
+    </operation>
+				 
+  </mbean>
+
+ <mbean         name="FastAsyncSocketSender"
+          description="Fast Async Cluster Sender"
+               domain="Catalina"
+                group="IDataSender"
+                 type="org.apache.catalina.cluster.tcp.FastAsyncSocketSender">
+    <attribute   name="info"
+          description="Class version info"
+                 type="java.lang.String"
+                 writeable="false"/>
+    <attribute   name="threadPriority"
+          description="change queue thread priority"
+                 type="int"/>                 
+    <attribute   name="address"
+          description="sender ip address"
+                 type="java.net.InetAddress"
+                 writeable="false"/>
+    <attribute   name="port"
+          description="sender port"
+                 type="int"
+                 writeable="false" />
+    <attribute   name="suspect"
+          description="Socket is gone"
+                 type="boolean"/>
+    <attribute   name="waitForAck"
+          description="Wait for ack after data send"
+			     is="true"
+                 type="boolean"
+                 writeable="false"/>
+    <attribute   name="ackTimeout"
+          description="acknowledge timeout"
+                 type="long"/>
+    <attribute   name="avgMessageSize"
+                 writeable="false"
+          description="avg message size (totalbytes/nrOfRequests"
+                 type="long" />
+    <attribute   name="queueSize"
+                 writeable="false"
+          description="queue size"
+                 type="int"/>
+    <attribute   name="queuedNrOfBytes"
+                 writeable="false"
+          description="number of bytes over all queued messages"
+                 type="long"/>
+    <attribute   name="messageTransferStarted"
+          description="message is in transfer"
+                 type="boolean"
+                 is="true"
+                 writeable="false"/>
+    <attribute   name="keepAliveTimeout"
+          description="active socket keep alive timeout"
+                 type="long"/>
+    <attribute   name="keepAliveMaxRequestCount"
+          description="max request over this socket"
+                 type="int"/>
+    <attribute   name="queueAddWaitTimeout"
+          description="add wait timeout (default 10000 msec)"
+                 type="long"/>
+    <attribute   name="queueRemoveWaitTimeout"
+          description="remove wait timeout (default 30000 msec)"
+                 type="long"/>
+    <attribute   name="maxQueueLength"
+          description="max queue length"
+                 type="int"/>
+    <attribute   name="queueTimeWait"
+          description="remember queue wait times"
+                 is="true"
+                 type="boolean"/>
+    <attribute   name="queueCheckLock"
+          description="check to lost locks"
+                 is="true"
+                 type="boolean"/>
+    <attribute   name="queueDoStats"
+          description="activated queue stats"
+                 is="true"
+                 type="boolean"/>
+    <attribute   name="keepAliveCount"
+          description="keep Alive request count"
+                 type="int"
+                 writeable="false"/>
+    <attribute   name="keepAliveConnectTime"
+          description="Connect time for keep alive"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="resend"
+          description="after send failure make a resend"
+			     is="true"
+                 type="boolean" />
+    <attribute   name="connected"
+                 is="true"
+          description="socket connected"
+                 type="boolean"
+                 writeable="false"/>
+    <attribute   name="nrOfRequests"
+          description="number of send messages to other members"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="totalBytes"
+          description="number of bytes transfered"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="processingTime"
+          description="sending processing time"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="minProcessingTime"
+          description="minimal sending processing time"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="avgProcessingTime"
+          description="processing time / nrOfRequests"
+                 type="double"
+                 writeable="false"/>
+    <attribute   name="maxProcessingTime"
+          description="maximal sending processing time"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="doProcessingStats"
+          description="create Processing time stats"
+			     is="true"
+                 type="boolean" />                 
+    <attribute   name="waitAckTime"
+          description="sending waitAck time"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="minWaitAckTime"
+          description="minimal sending waitAck time"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="avgWaitAckTime"
+          description="waitAck time / nrOfRequests"
+                 type="double"
+                 writeable="false"/>
+    <attribute   name="maxWaitAckTime"
+          description="maximal sending waitAck time"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="doWaitAckStats"
+          description="create waitAck time stats"
+			     is="true"
+                 type="boolean" />
+    <attribute   name="connectCounter"
+          description="counts connects"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="disconnectCounter"
+          description="counts disconnects"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="socketOpenCounter"
+          description="counts open socket (KeepAlive and connects)"
+                 type="long"
+                 writeable="false"/>				 
+    <attribute   name="socketOpenFailureCounter"
+          description="counts open socket failures"
+                 type="long"
+                 writeable="false"/>                 				 
+    <attribute   name="socketCloseCounter"
+          description="counts closed socket (KeepAlive and disconnects)"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="missingAckCounter"
+          description="counts missing ack"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="dataResendCounter"
+          description="counts data resends"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="dataFailureCounter"
+          description="counts data send failures"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="inQueueCounter"
+          description="counts all queued messages"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="outQueueCounter"
+          description="counts all successfully sended messages"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="queueAddWaitTime"
+          description="queue add wait time (tomcat thread waits)"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="queueRemoveWaitTime"
+          description="queue remove wait time (queue thread waits)"
+                 type="long"
+                 writeable="false"/>
+ 	<operation name="connect"
+               description="connect to other replication node"
+               impact="ACTION"
+               returnType="void">
+    </operation>
+	<operation name="disconnect"
+               description="disconnect to other replication node"
+               impact="ACTION"
+               returnType="void">
+    </operation>
+	<operation name="checkKeepAlive"
+               description="Check connection for close socket"
+               impact="ACTION"
+               returnType="boolean">
+    </operation>
+	<operation name="resetStatistics"
+               description="Reset all statistics"
+               impact="ACTION"
+               returnType="void">
+    </operation>
+				 
+  </mbean>
+
+  <mbean         name="PooledSocketSender"
+          description="Pooled Cluster Sender"
+               domain="Catalina"
+                group="IDataSender"
+                 type="org.apache.catalina.cluster.tcp.PooledSocketSender">
+    <attribute   name="address"
+          description="sender ip address"
+                 type="java.net.InetAddress"
+                 writeable="false"/>
+    <attribute   name="port"
+          description="sender port"
+                 type="int"
+                 writeable="false" />
+    <attribute   name="suspect"
+          description="Socket is gone"
+                 type="boolean"/>
+    <attribute   name="ackTimeout"
+          description="acknowledge timeout"
+                 type="long"/>
+    <attribute   name="waitForAck"
+          description="Wait for ack after data send"
+			     is="true"
+                 type="boolean"
+                 writeable="false" />
+    <attribute   name="maxPoolSocketLimit"
+          description="Max parallel sockets"
+                 type="int"/>
+    <attribute   name="inPoolSize"
+          description="get current SocketSender pool size"
+                 type="int"/>
+    <attribute   name="inUsePoolSize"
+          description="get size of current busy SocketSender from pool"
+                 type="int"/>                 
+    <attribute   name="keepAliveTimeout"
+          description="active socket keep alive timeout"
+                 type="long"/>
+    <attribute   name="keepAliveMaxRequestCount"
+          description="max request over this socket"
+                 type="int"/>
+    <attribute   name="resend"
+          description="after send failure make a resend"
+			     is="true"
+                 type="boolean" />
+    <attribute   name="connected"
+                 is="true"
+          description="socket connected"
+                 type="boolean"
+                 writeable="false"/>
+    <attribute   name="avgMessageSize"
+                 writeable="false"
+          description="avg message size (totalbytes/nrOfRequests"
+                 type="long"/>
+    <attribute   name="nrOfRequests"
+          description="number of send messages to other members"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="totalBytes"
+          description="number of bytes transfered"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="connectCounter"
+          description="counts connects"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="disconnectCounter"
+          description="counts disconnects"
+                 type="long"
+                 writeable="false"/>
+	<operation name="connect"
+               description="start Queue to connect to ohter replication node"
+               impact="ACTION"
+               returnType="void">
+    </operation>
+	<operation name="disconnect"
+               description="stop Queue to other replication node"
+               impact="ACTION"
+               returnType="void">
+    </operation>
+	<operation name="resetStatistics"
+               description="Reset all statistics"
+               impact="ACTION"
+               returnType="void">
+    </operation>
+				 
+  </mbean>
+
+  <mbean         name="SocketSender"
+          description="Sync Cluster Sender"
+               domain="Catalina"
+                group="IDataSender"
+                 type="org.apache.catalina.cluster.tcp.SocketSender">
+    <attribute   name="address"
+          description="sender ip address"
+                 type="java.net.InetAddress"
+                 writeable="false"/>
+    <attribute   name="port"
+          description="sender port"
+                 type="int"
+                 writeable="false" />
+    <attribute   name="suspect"
+          description="Socket is gone"
+                 type="boolean"/>
+    <attribute   name="ackTimeout"
+          description="acknowledge timeout"
+                 type="long"/>
+    <attribute   name="waitForAck"
+          description="Wait for ack after data send"
+			     is="true"
+                 type="boolean"
+                 writeable="false" />
+    <attribute   name="keepAliveTimeout"
+          description="active socket keep alive timeout"
+                 type="long"/>
+    <attribute   name="keepAliveMaxRequestCount"
+          description="max request over this socket"
+                 type="int"/>
+    <attribute   name="messageTransferStarted"
+          description="message is in transfer"
+                 type="boolean"
+                 is="true"
+                 writeable="false"/>
+    <attribute   name="keepAliveCount"
+          description="keep Alive request count"
+                 type="int"
+                 writeable="false"/>
+    <attribute   name="keepAliveConnectTime"
+          description="Connect time for keep alive"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="resend"
+          description="after send failure make a resend"
+			     is="true"
+                 type="boolean" />
+    <attribute   name="connected"
+                 is="true"
+          description="socket connected"
+                 type="boolean"
+                 writeable="false"/>
+    <attribute   name="avgMessageSize"
+                 writeable="false"
+          description="avg message size (totalbytes/nrOfRequests"
+                 type="long"/>
+    <attribute   name="nrOfRequests"
+          description="number of send messages to other members"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="totalBytes"
+          description="number of bytes transfered"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="processingTime"
+          description="sending processing time"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="minProcessingTime"
+          description="minimal sending processing time"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="avgProcessingTime"
+          description="processing time / nrOfRequests"
+                 type="double"
+                 writeable="false"/>
+    <attribute   name="maxProcessingTime"
+          description="maximal sending processing time"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="doProcessingStats"
+          description="create Processing time stats"
+			     is="true"
+                 type="boolean" />
+    <attribute   name="waitAckTime"
+          description="sending waitAck time"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="minWaitAckTime"
+          description="minimal sending waitAck time"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="avgWaitAckTime"
+          description="waitAck time / nrOfRequests"
+                 type="double"
+                 writeable="false"/>
+    <attribute   name="maxWaitAckTime"
+          description="maximal sending waitAck time"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="doWaitAckStats"
+          description="create waitAck time stats"
+			     is="true"
+                 type="boolean" />
+    <attribute   name="connectCounter"
+          description="counts connects"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="disconnectCounter"
+          description="counts disconnects"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="socketCloseCounter"
+          description="counts closed socket (KeepAlive and disconnects)"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="socketOpenFailureCounter"
+          description="counts open socket failures"
+                 type="long"
+                 writeable="false"/>                 				 
+    <attribute   name="socketOpenCounter"
+          description="counts open socket (KeepAlive and connects)"
+                 type="long"
+                 writeable="false"/>				 
+    <attribute   name="missingAckCounter"
+          description="counts missing ack"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="dataResendCounter"
+          description="counts data resends"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="dataFailureCounter"
+          description="counts data send failures"
+                 type="long"
+                 writeable="false"/>
+	<operation name="connect"
+               description="connect to other replication node"
+               impact="ACTION"
+               returnType="void">
+    </operation>
+	<operation name="disconnect"
+               description="disconnect to other replication node"
+               impact="ACTION"
+               returnType="void">
+    </operation>
+	<operation name="checkKeepAlive"
+               description="Check connection for close socket"
+               impact="ACTION"
+               returnType="boolean">
+    </operation>
+	<operation name="resetStatistics"
+               description="Reset all statistics"
+               impact="ACTION"
+               returnType="void">
+    </operation>
+				 
+  </mbean>
+    
+  <mbean         name="ReplicationValve"
+          description="Valve for simple tcp replication"
+               domain="Catalina"
+                group="Valve"
+                 type="org.apache.catalina.cluster.tcp.ReplicationValve">
+    <attribute   name="info"
+          description="Class version info"
+                 type="java.lang.String"
+                 writeable="false"/>
+    <attribute   name="filter"
+          description="resource filter to disable session replication check"
+                 type="java.lang.String"/>
+    <attribute   name="primaryIndicator"
+ 			     is="true"
+          description="set indicator that request processing is at primary session node"
+                 type="boolean"/>
+    <attribute   name="primaryIndicatorName"
+          description="Request attribute name to indicate that request processing is at primary session node"
+                 type="java.lang.String"/>
+    <attribute   name="doProcessingStats"
+ 			     is="true"
+          description="active statistics counting"
+                 type="boolean"/>
+	<attribute   name="nrOfRequests"
+          description="number of replicated requests"
+                 type="long"
+                 writeable="false"/>
+	<attribute   name="nrOfFilterRequests"
+          description="number of filtered requests"
+                 type="long"
+                 writeable="false"/>
+	<attribute   name="nrOfSendRequests"
+          description="number of send requests"
+                 type="long"
+                 writeable="false"/>
+	<attribute   name="nrOfCrossContextSendRequests"
+          description="number of send cross context session requests"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="totalRequestTime"
+          description="total replicated request time"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="totalSendTime"
+          description="total replicated send time"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="lastSendTime"
+          description="last replicated request time"
+                 type="long"
+                 writeable="false"/>
+    <operation name="resetStatistics"
+               description="Reset all statistics"
+               impact="ACTION"
+               returnType="void">
+    </operation>
+                 
+  </mbean>
+
+
+</mbeans-descriptors>

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/util/FastQueue.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/util/FastQueue.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/util/FastQueue.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,627 @@
+/*
+ * Copyright 1999,2004-2005 The Apache Software Foundation.
+ * 
+ * Licensed 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.cluster.util;
+
+/**
+ * A fast queue that remover thread lock the adder thread. <br/>Limit the queue
+ * length when you have strange producer thread problemes.
+ * 
+ * FIXME add i18n support to log messages
+ * @author Rainer Jung
+ * @author Peter Rossbach
+ * @version $Revision: 418134 $ $Date: 2006-06-29 15:54:33 -0500 (Thu, 29 Jun 2006) $
+ */
+public class FastQueue implements IQueue {
+
+    private static org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory
+            .getLog(FastQueue.class);
+
+    /**
+     * This is the actual queue
+     */
+    private SingleRemoveSynchronizedAddLock lock = null;
+
+    /**
+     * First Object at queue (consumer message)
+     */
+    private LinkObject first = null;
+
+    /**
+     * Last object in queue (producer Object)
+     */
+    private LinkObject last = null;
+
+    /**
+     * Current Queue elements size
+     */
+    private int size = 0;
+
+    /**
+     * check lock to detect strange threadings things
+     */
+    private boolean checkLock = false;
+
+    /**
+     * protocol the thread wait times
+     */
+    private boolean timeWait = false;
+
+    /**
+     * calc stats data
+     */
+    private boolean doStats = false;
+
+    private boolean inAdd = false;
+
+    private boolean inRemove = false;
+
+    private boolean inMutex = false;
+
+    /**
+     * limit the queue legnth ( default is unlimited)
+     */
+    private int maxQueueLength = 0;
+
+    /**
+     * addWaitTimeout for producer
+     */
+    private long addWaitTimeout = 10000L;
+
+    
+    /**
+     * removeWaitTimeout for consumer
+     */
+    private long removeWaitTimeout = 30000L;
+
+    /**
+     * enabled the queue
+     */
+    private boolean enabled = true;
+
+    /**
+     * calc all add objects
+     */
+    private long addCounter = 0;
+
+    /**
+     * calc all add objetcs in error state ( see limit queue length)
+     */
+    private long addErrorCounter = 0;
+
+    /**
+     * calc all remove objects
+     */
+    private long removeCounter = 0;
+
+    /**
+     * calc all remove objects failures (hupps probleme detection)
+     */
+    private long removeErrorCounter = 0;
+
+    /**
+     * Calc wait time thread
+     */
+    private long addWait = 0;
+
+    /**
+     * Calc remove time threads
+     */
+    private long removeWait = 0;
+
+    /**
+     *  max queue size
+     */
+    private int maxSize = 0;
+
+    /**
+     * avg queue size
+     */
+    private long avgSize = 0;
+
+    private int maxSizeSample = 0;
+
+    private long avgSizeSample = 0;
+
+    /**
+     *  avg size sample interval
+     */
+    private int sampleInterval = 100;
+
+    /**
+     * Generate Queue SingleRemoveSynchronizedAddLock and set add and wait
+     * Timeouts
+     */
+    public FastQueue() {
+        lock = new SingleRemoveSynchronizedAddLock();
+        lock.setAddWaitTimeout(addWaitTimeout);
+        lock.setRemoveWaitTimeout(removeWaitTimeout);
+    }
+
+    /**
+     * get current add wait timeout
+     * 
+     * @return current wait timeout
+     */
+    public long getAddWaitTimeout() {
+        addWaitTimeout = lock.getAddWaitTimeout();
+        return addWaitTimeout;
+    }
+
+    /**
+     * Set add wait timeout (default 10000 msec)
+     * 
+     * @param timeout
+     */
+    public void setAddWaitTimeout(long timeout) {
+        addWaitTimeout = timeout;
+        lock.setAddWaitTimeout(addWaitTimeout);
+    }
+
+    /**
+     * get current remove wait timeout
+     * 
+     * @return The timeout
+     */
+    public long getRemoveWaitTimeout() {
+        removeWaitTimeout = lock.getRemoveWaitTimeout();
+        return removeWaitTimeout;
+    }
+
+    /**
+     * set remove wait timeout ( default 30000 msec)
+     * 
+     * @param timeout
+     */
+    public void setRemoveWaitTimeout(long timeout) {
+        removeWaitTimeout = timeout;
+        lock.setRemoveWaitTimeout(removeWaitTimeout);
+    }
+
+    /**
+     * get Max Queue length
+     * 
+     * @see org.apache.catalina.cluster.util.IQueue#getMaxQueueLength()
+     */
+    public int getMaxQueueLength() {
+        return maxQueueLength;
+    }
+
+    public void setMaxQueueLength(int length) {
+        maxQueueLength = length;
+    }
+
+    public boolean isEnabled() {
+        return enabled;
+    }
+
+    public void setEnabled(boolean enable) {
+        enabled = enable;
+        if (!enabled) {
+            lock.abortRemove();
+        }
+    }
+
+    /**
+     * @return Returns the checkLock.
+     */
+    public boolean isCheckLock() {
+        return checkLock;
+    }
+
+    /**
+     * @param checkLock The checkLock to set.
+     */
+    public void setCheckLock(boolean checkLock) {
+        this.checkLock = checkLock;
+    }
+
+    /**
+     * @return Returns the doStats.
+     */
+    public boolean isDoStats() {
+        return doStats;
+    }
+
+    /**
+     * @param doStats The doStats to set.
+     */
+    public void setDoStats(boolean doStats) {
+        this.doStats = doStats;
+    }
+
+    /**
+     * @return Returns the timeWait.
+     */
+    public boolean isTimeWait() {
+        return timeWait;
+    }
+
+    /**
+     * @param timeWait The timeWait to set.
+     */
+    public void setTimeWait(boolean timeWait) {
+        this.timeWait = timeWait;
+    }
+
+    public int getSampleInterval() {
+        return sampleInterval;
+    }
+
+    public void setSampleInterval(int interval) {
+        if ( interval > 0 ) {
+           sampleInterval = interval;
+        }
+    }
+
+    public long getAddCounter() {
+        return addCounter;
+    }
+
+    public void setAddCounter(long counter) {
+        addCounter = counter;
+    }
+
+    public long getAddErrorCounter() {
+        return addErrorCounter;
+    }
+
+    public void setAddErrorCounter(long counter) {
+        addErrorCounter = counter;
+    }
+
+    public long getRemoveCounter() {
+        return removeCounter;
+    }
+
+    public void setRemoveCounter(long counter) {
+        removeCounter = counter;
+    }
+
+    public long getRemoveErrorCounter() {
+        return removeErrorCounter;
+    }
+
+    public void setRemoveErrorCounter(long counter) {
+        removeErrorCounter = counter;
+    }
+
+    public long getAddWait() {
+        return addWait;
+    }
+
+    public void setAddWait(long wait) {
+        addWait = wait;
+    }
+
+    public long getRemoveWait() {
+        return removeWait;
+    }
+
+    public void setRemoveWait(long wait) {
+        removeWait = wait;
+    }
+
+    /**
+     * @return The max size
+     */
+    public int getMaxSize() {
+        return maxSize;
+    }
+
+    /**
+     * @param size
+     */
+    public void setMaxSize(int size) {
+        maxSize = size;
+    }
+
+    
+    /**
+     * Avg queue size
+     * @return The average queue size
+     */
+    public long getAvgSize() {
+        if (addCounter > 0) {
+            return avgSize / addCounter;
+        } else {
+            return 0;
+        }
+    }
+
+    /**
+     * reset all stats data 
+     */
+    public void resetStatistics() {
+        addCounter = 0;
+        addErrorCounter = 0;
+        removeCounter = 0;
+        removeErrorCounter = 0;
+        avgSize = 0;
+        maxSize = 0;
+        addWait = 0;
+        removeWait = 0;
+    }
+
+    /**
+     * unlock queue for next add 
+     */
+    public void unlockAdd() {
+        lock.unlockAdd(size > 0 ? true : false);
+    }
+
+    /**
+     * unlock queue for next remove 
+     */
+    public void unlockRemove() {
+        lock.unlockRemove();
+    }
+
+    /**
+     * start queuing
+     */
+    public void start() {
+        setEnabled(true);
+    }
+
+    /**
+     * start queuing
+     */
+    public void stop() {
+        setEnabled(false);
+    }
+
+    public long getSample() {
+        return addCounter % sampleInterval;
+    }
+
+    public int getMaxSizeSample() {
+        return maxSizeSample;
+    }
+
+    public void setMaxSizeSample(int size) {
+        maxSizeSample = size;
+    }
+
+    public long getAvgSizeSample() {
+        long sample = addCounter % sampleInterval;
+        if (sample > 0) {
+            return avgSizeSample / sample;
+        } else if (addCounter > 0) {
+            return avgSizeSample / sampleInterval;
+        } else {
+            return 0;
+        }
+    }
+
+    public int getSize() {
+        int sz;
+        sz = size;
+        return sz;
+    }
+
+    /**
+     * Add new data to the queue
+     * @see org.apache.catalina.cluster.util.IQueue#add(java.lang.String, java.lang.Object)
+     * FIXME extract some method
+     */
+    public boolean add(String key, Object data) {
+        boolean ok = true;
+        long time = 0;
+
+        if (!enabled) {
+            if (log.isInfoEnabled())
+                log.info("FastQueue.add: queue disabled, add aborted");
+            return false;
+        }
+
+        if (timeWait) {
+            time = System.currentTimeMillis();
+        }
+        lock.lockAdd();
+        try {
+            if (timeWait) {
+                addWait += (System.currentTimeMillis() - time);
+            }
+
+            if (log.isTraceEnabled()) {
+                log.trace("FastQueue.add: starting with size " + size);
+            }
+            if (checkLock) {
+                if (inAdd)
+                    log.warn("FastQueue.add: Detected other add");
+                inAdd = true;
+                if (inMutex)
+                    log.warn("FastQueue.add: Detected other mutex in add");
+                inMutex = true;
+            }
+
+            if ((maxQueueLength > 0) && (size >= maxQueueLength)) {
+                ok = false;
+                if (log.isTraceEnabled()) {
+                    log.trace("FastQueue.add: Could not add, since queue is full ("
+                            + size + ">=" + maxQueueLength + ")");
+                }
+
+            } else {
+                LinkObject element = new LinkObject(key, data);
+                if (size == 0) {
+                    first = last = element;
+                    size = 1;
+                } else {
+                    if (last == null) {
+                        ok = false;
+                        log
+                                .error("FastQueue.add: Could not add, since last is null although size is "
+                                        + size + " (>0)");
+                    } else {
+                        last.append(element);
+                        last = element;
+                        size++;
+                    }
+                }
+
+            }
+
+            if (doStats) {
+                if (ok) {
+                    if (addCounter % sampleInterval == 0) {
+                        maxSizeSample = 0;
+                        avgSizeSample = 0;
+                    }
+                    addCounter++;
+                    if (size > maxSize) {
+                        maxSize = size;
+                    }
+                    if (size > maxSizeSample) {
+                        maxSizeSample = size;
+                    }
+                    avgSize += size;
+                    avgSizeSample += size;
+                } else {
+                    addErrorCounter++;
+                }
+            }
+
+            if (first == null) {
+                log.error("FastQueue.add: first is null, size is " + size
+                        + " at end of add");
+            }
+            if (last == null) {
+                log.error("FastQueue.add: last is null, size is " + size
+                        + " at end of add");
+            }
+
+            if (checkLock) {
+                if (!inMutex)
+                    log.warn("FastQueue.add: Cancelled by other mutex in add");
+                inMutex = false;
+                if (!inAdd)
+                    log.warn("FastQueue.add: Cancelled by other add");
+                inAdd = false;
+            }
+            if (log.isTraceEnabled()) {
+                log.trace("FastQueue.add: add ending with size " + size);
+            }
+
+            if (timeWait) {
+                time = System.currentTimeMillis();
+            }
+        } finally {
+            lock.unlockAdd(true);
+        }
+        if (timeWait) {
+            addWait += (System.currentTimeMillis() - time);
+        }
+        return ok;
+    }
+
+    /**
+     * remove the complete queued object list
+     * @see org.apache.catalina.cluster.util.IQueue#remove()
+     * FIXME extract some method
+     */
+    public LinkObject remove() {
+        LinkObject element;
+        boolean gotLock;
+        long time = 0;
+
+        if (!enabled) {
+            if (log.isInfoEnabled())
+                log.info("FastQueue.remove: queue disabled, remove aborted");
+            return null;
+        }
+
+        if (timeWait) {
+            time = System.currentTimeMillis();
+        }
+        gotLock = lock.lockRemove();
+        try {
+
+            if (!gotLock) {
+                if (enabled) {
+                    if (timeWait) {
+                        removeWait += (System.currentTimeMillis() - time);
+                    }
+                    if (doStats) {
+                        removeErrorCounter++;
+                    }
+                    if (log.isInfoEnabled())
+                        log.info("FastQueue.remove: Remove aborted although queue enabled");
+                } else {
+                    if (log.isInfoEnabled())
+                        log.info("FastQueue.remove: queue disabled, remove aborted");
+                }
+                return null;
+            }
+
+            if (timeWait) {
+                removeWait += (System.currentTimeMillis() - time);
+            }
+
+            if (log.isTraceEnabled()) {
+                log.trace("FastQueue.remove: remove starting with size " + size);
+            }
+            if (checkLock) {
+                if (inRemove)
+                    log.warn("FastQueue.remove: Detected other remove");
+                inRemove = true;
+                if (inMutex)
+                    log.warn("FastQueue.remove: Detected other mutex in remove");
+                inMutex = true;
+            }
+
+            element = first;
+
+            if (doStats) {
+                if (element != null) {
+                    removeCounter++;
+                } else {
+                    removeErrorCounter++;
+                    log
+                            .error("FastQueue.remove: Could not remove, since first is null although size is "
+                                    + size + " (>0)");
+                }
+            }
+
+            first = last = null;
+            size = 0;
+
+            if (checkLock) {
+                if (!inMutex)
+                    log.warn("FastQueue.remove: Cancelled by other mutex in remove");
+                inMutex = false;
+                if (!inRemove)
+                    log.warn("FastQueue.remove: Cancelled by other remove");
+                inRemove = false;
+            }
+            if (log.isTraceEnabled()) {
+                log.trace("FastQueue.remove: remove ending with size " + size);
+            }
+
+            if (timeWait) {
+                time = System.currentTimeMillis();
+            }
+        } finally {
+            lock.unlockRemove();
+        }
+        if (timeWait) {
+            removeWait += (System.currentTimeMillis() - time);
+        }
+        return element;
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/util/IDynamicProperty.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/util/IDynamicProperty.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/util/IDynamicProperty.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,57 @@
+/*
+ * Copyright 1999,2004-2005 The Apache Software Foundation.
+ * 
+ * Licensed 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.cluster.util;
+
+import java.util.Iterator;
+
+/**
+ * @author Peter Rossbach
+ * @version $Revision: 304032 $, $Date: 2005-07-27 10:11:55 -0500 (Wed, 27 Jul 2005) $
+ */
+
+public interface IDynamicProperty {
+
+    /**
+     * set config attributes with reflect
+     * 
+     * @param name
+     * @param value
+     */
+    public void setProperty(String name, Object value) ;
+
+    /**
+     * get current config
+     * 
+     * @param key
+     * @return The property
+     */
+    public Object getProperty(String key) ;
+    /**
+     * Get all properties keys
+     * 
+     * @return An iterator over the property names
+     */
+    public Iterator getPropertyNames() ;
+
+    /**
+     * remove a configured property.
+     * 
+     * @param key
+     */
+    public void removeProperty(String key) ;
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/util/IQueue.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/util/IQueue.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/util/IQueue.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,35 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.cluster.util;
+
+/**
+ * A queue interface<BR>
+ *
+ * @author Rainer Jung
+ * @author Peter Rossbach
+ * @version $Revision: 303753 $ $Date: 2005-03-14 15:24:30 -0600 (Mon, 14 Mar 2005) $
+ */
+
+public interface IQueue {
+
+    public LinkObject remove();
+    public boolean add(String key,Object data);
+    public int getMaxQueueLength();
+    public void setMaxQueueLength(int length);
+    public void start();
+    public void stop();
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/util/LinkObject.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/util/LinkObject.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/util/LinkObject.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,81 @@
+/*
+ * Copyright 1999,2004-2005 The Apache Software Foundation.
+ * 
+ * Licensed 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.cluster.util;
+
+/**
+ * The class <b>LinkObject</b> implements an element
+ * for a linked list, consisting of a general
+ * data object and a pointer to the next element.
+ *
+ * @author Rainer Jung
+ * @author Peter Rossbach
+ * @version $Revision: 304032 $ $Date: 2005-07-27 10:11:55 -0500 (Wed, 27 Jul 2005) $
+
+ */
+
+public class LinkObject {
+
+    private Object payload;
+    private LinkObject next;
+    private String key ;
+    
+    /**
+     * Construct a new element from the data object.
+     * Sets the pointer to null.
+     *
+     * @param key The key
+     * @param payload The data object.
+     */
+    public LinkObject(String key,Object payload) {
+        this.payload = payload;
+        this.next = null;
+        this.key = key ;
+    }
+
+    /**
+     * Set the next element.
+     * @param next The next element.
+     */
+    public void append(LinkObject next) {
+        this.next = next;
+    }
+
+    /**
+     * Get the next element.
+     * @return The next element.
+     */
+    public LinkObject next() {
+        return next;
+    }
+
+    /**
+     * Get the data object from the element.
+     * @return The data object from the element.
+     */
+    public Object data() {
+        return payload;
+    }
+
+    /**
+     * Get the unique message id
+     * @return the unique message id
+     */
+    public Object getKey() {
+        return key;
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/util/SingleRemoveSynchronizedAddLock.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/util/SingleRemoveSynchronizedAddLock.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/util/SingleRemoveSynchronizedAddLock.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,251 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.cluster.util;
+
+/**
+ * The class <b>SingleRemoveSynchronizedAddLock</b> implement locking for accessing the queue
+ * by a single remove thread and multiple add threads.
+ *
+ * A thread is only allowed to be either the remove or
+ * an add thread.
+ *
+ * The lock can either be owned by the remove thread
+ * or by a single add thread.
+ *
+ * If the remove thread tries to get the lock,
+ * but the queue is empty, it will block (poll)
+ * until an add threads adds an entry to the queue and
+ * releases the lock.
+ * 
+ * If the remove thread and add threads compete for
+ * the lock and an add thread releases the lock, then
+ * the remove thread will get the lock first.
+ *
+ * The remove thread removes all entries in the queue
+ * at once and proceeses them without further
+ * polling the queue.
+ *
+ * The lock is not reentrant, in the sense, that all
+ * threads must release an owned lock before competing
+ * for the lock again!
+ *
+ * @author Rainer Jung
+ * @author Peter Rossbach
+ * @version 1.1
+ */
+ 
+public class SingleRemoveSynchronizedAddLock {
+    
+    public SingleRemoveSynchronizedAddLock() {
+    }
+    
+    public SingleRemoveSynchronizedAddLock(boolean dataAvailable) {
+        this.dataAvailable=dataAvailable;
+    }
+    
+    /**
+     * Time in milliseconds after which threads
+     * waiting for an add lock are woken up.
+     * This is used as a safety measure in case
+     * thread notification via the unlock methods
+     * has a bug.
+     */
+    private long addWaitTimeout = 10000L;
+
+    /**
+     * Time in milliseconds after which threads
+     * waiting for a remove lock are woken up.
+     * This is used as a safety measure in case
+     * thread notification via the unlock methods
+     * has a bug.
+     */
+    private long removeWaitTimeout = 30000L;
+
+    /**
+     * The current remove thread.
+     * It is set to the remove thread polling for entries.
+     * It is reset to null when the remove thread
+     * releases the lock and proceeds processing
+     * the removed entries.
+     */
+    private Thread remover = null;
+
+    /**
+     * A flag indicating, if an add thread owns the lock.
+     */
+    private boolean addLocked = false;
+
+    /**
+     * A flag indicating, if the remove thread owns the lock.
+     */
+    private boolean removeLocked = false;
+
+    /**
+     * A flag indicating, if the remove thread is allowed
+     * to wait for the lock. The flag is set to false, when aborting.
+     */
+    private boolean removeEnabled = true;
+
+    /**
+     * A flag indicating, if the remover needs polling.
+     * It indicates, if the locked object has data available
+     * to be removed.
+     */
+    private boolean dataAvailable = false;
+
+    /**
+     * @return Value of addWaitTimeout
+     */
+    public synchronized long getAddWaitTimeout() {
+        return addWaitTimeout;
+    }
+
+    /**
+     * Set value of addWaitTimeout
+     */
+    public synchronized void setAddWaitTimeout(long timeout) {
+        addWaitTimeout = timeout;
+    }
+
+    /**
+     * @return Value of removeWaitTimeout
+     */
+    public synchronized long getRemoveWaitTimeout() {
+        return removeWaitTimeout;
+    }
+
+    /**
+     * Set value of removeWaitTimeout
+     */
+    public synchronized void setRemoveWaitTimeout(long timeout) {
+        removeWaitTimeout = timeout;
+    }
+
+    /**
+     * Check if the locked object has data available
+     * i.e. the remover can stop poling and get the lock.
+     * @return True iff the lock Object has data available.
+     */
+    public synchronized boolean isDataAvailable() {
+        return dataAvailable;
+    }
+
+    /**
+     * Check if an add thread owns the lock.
+     * @return True iff an add thread owns the lock.
+     */
+    public synchronized boolean isAddLocked() {
+        return addLocked;
+    }
+
+    /**
+     * Check if the remove thread owns the lock.
+     * @return True iff the remove thread owns the lock.
+     */
+    public synchronized boolean isRemoveLocked() {
+        return removeLocked;
+    }
+
+    /**
+     * Check if the remove thread is polling.
+     * @return True iff the remove thread is polling.
+     */
+    public synchronized boolean isRemovePolling() {
+        if ( remover != null ) {
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Acquires the lock by an add thread and sets the add flag.
+     * If any add thread or the remove thread already acquired the lock
+     * this add thread will block until the lock is released.
+     */
+    public synchronized void lockAdd() {
+        if ( addLocked || removeLocked ) {
+            do {
+                try {
+                    wait(addWaitTimeout);
+                } catch ( InterruptedException e ) {
+                }
+            } while ( addLocked || removeLocked );
+        }
+        addLocked=true;
+    }
+
+    /**
+     * Acquires the lock by the remove thread and sets the remove flag.
+     * If any add thread already acquired the lock or the queue is
+     * empty, the remove thread will block until the lock is released
+     * and the queue is not empty.
+     */
+    public synchronized boolean lockRemove() {
+        removeLocked=false;
+        removeEnabled=true;
+        if ( ( addLocked || ! dataAvailable ) && removeEnabled ) {
+            remover=Thread.currentThread();
+            do {
+                try {
+                    wait(removeWaitTimeout);
+                } catch ( InterruptedException e ) {
+                }
+            } while ( ( addLocked || ! dataAvailable ) && removeEnabled );
+            remover=null;
+        }
+        if ( removeEnabled ) {
+            removeLocked=true;
+        } 
+        return removeLocked;
+    }
+
+    /**
+     * Releases the lock by an add thread and reset the remove flag.
+     * If the reader thread is polling, notify it.
+     */
+    public synchronized void unlockAdd(boolean dataAvailable) {
+        addLocked=false;
+        this.dataAvailable=dataAvailable;
+        if ( ( remover != null ) && ( dataAvailable || ! removeEnabled ) ) {
+            remover.interrupt();
+        } else {
+            notifyAll();
+        }
+    }
+
+    /**
+     * Releases the lock by the remove thread and reset the add flag.
+     * Notify all waiting add threads,
+     * that the lock has been released by the remove thread.
+     */
+    public synchronized void unlockRemove() {
+        removeLocked=false;
+        dataAvailable=false;
+        notifyAll();
+    }
+
+    /**
+     * Abort any polling remover thread
+     */
+    public synchronized void abortRemove() {
+        removeEnabled=false;
+        if ( remover != null ) {
+            remover.interrupt();
+        }
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/util/SmartQueue.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/util/SmartQueue.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/src/share/org/apache/catalina/cluster/util/SmartQueue.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,189 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.cluster.util;
+
+/**
+ * A smart queue, used for async replication <BR>
+ * the "smart" part of this queue is that if the session is already queued for
+ * replication, and it is updated again, the session will simply be replaced,
+ * hence we don't replicate stuff that is obsolete. Put this into util, since it
+ * is quite generic.
+ * 
+ * @author Filip Hanik
+ * @version 1.0
+ */
+
+import java.util.LinkedList;
+import java.util.HashMap;
+
+public class SmartQueue {
+
+    public static org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory
+            .getLog(SmartQueue.class);
+
+    /**
+     * This is the actual queue
+     */
+    private LinkedList queue = new LinkedList();
+
+    /**
+     * And this is only for performance, fast lookups
+     */
+    private HashMap queueMap = new HashMap();
+
+    private Object mutex = new Object();
+
+    public SmartQueue() {
+    }
+
+    /**
+     * Add an object to the queue
+     * 
+     * @param entry -
+     *            the smart entry
+     */
+    public void add(SmartEntry entry) {
+        /*
+         * make sure we are within a synchronized block since we are dealing
+         * with two unsync collections
+         */
+        synchronized (mutex) {
+            /* check to see if this object has already been queued */
+            SmartEntry current = (SmartEntry) queueMap.get(entry.getKey());
+            if (current == null) {
+                /* the object has not been queued, at it to the end of the queue */
+                if (log.isDebugEnabled())
+                    log.debug("[" + Thread.currentThread().getName()
+                            + "][SmartQueue] Adding new object=" + entry);
+                queue.addLast(entry);
+                queueMap.put(entry.getKey(), entry);
+            } else {
+                /* the object has been queued, replace the value */
+                if (log.isDebugEnabled())
+                    log.debug("[" + Thread.currentThread().getName()
+                            + "][SmartQueue] Replacing old object=" + current);
+                current.setValue(entry.getValue());
+                if (log.isDebugEnabled())
+                    log.debug("with new object=" + current);
+            }
+            /*
+             * wake up all the threads that are waiting for the lock to be
+             * released
+             */
+            mutex.notifyAll();
+        }
+    }
+
+    public int size() {
+        synchronized (mutex) {
+            return queue.size();
+        }
+    }
+
+    /**
+     * Blocks forever until an element has been added to the queue
+     */
+    public SmartEntry remove() {
+        return remove(0);
+    }
+
+    public SmartEntry remove(long timeout) {
+        SmartEntry result = null;
+        long startEntry = System.currentTimeMillis();
+        synchronized (mutex) {
+            while (size() == 0) {
+                try {
+                    if (log.isDebugEnabled())
+                        log
+                                .debug("["
+                                        + Thread.currentThread().getName()
+                                        + "][SmartQueue] Queue sleeping until object added size="
+                                        + size() + ".");
+                    if ((timeout != 0)
+                            && ((System.currentTimeMillis() - startEntry) > timeout)) {
+                        return null;
+                    }
+                    mutex.wait(timeout);
+                    if (log.isDebugEnabled())
+                        log
+                                .debug("["
+                                        + Thread.currentThread().getName()
+                                        + "][SmartQueue] Queue woke up or interrupted size="
+                                        + size() + ".");
+                } catch (IllegalMonitorStateException ex) {
+                    throw ex;
+                } catch (InterruptedException ex) {
+                }//catch
+            }//while
+            /* guaranteed that we are not empty by now */
+            result = (SmartEntry) queue.removeFirst();
+            queueMap.remove(result.getKey());
+            if (log.isDebugEnabled())
+                log.debug("[" + Thread.currentThread().getName()
+                        + "][SmartQueue] Returning=" + result);
+        }
+        return result;
+    }
+
+    public static class SmartEntry {
+        protected Object key;
+
+        protected Object value;
+
+        public SmartEntry(Object key, Object value) {
+            if (key == null)
+                throw new IllegalArgumentException(
+                        "SmartEntry key can not be null.");
+            if (value == null)
+                throw new IllegalArgumentException(
+                        "SmartEntry value can not be null.");
+            this.key = key;
+            this.value = value;
+        }
+
+        public Object getKey() {
+            return key;
+        }
+
+        public Object getValue() {
+            return value;
+        }
+
+        public void setValue(Object value) {
+            if (value == null)
+                throw new IllegalArgumentException(
+                        "SmartEntry value can not be null.");
+            this.value = value;
+        }
+
+        public int hashCode() {
+            return key.hashCode();
+        }
+
+        public boolean equals(Object o) {
+            if (!(o instanceof SmartEntry))
+                return false;
+            SmartEntry other = (SmartEntry) o;
+            return other.getKey().equals(getKey());
+        }
+
+        public String toString() {
+            return "[SmartyEntry key=" + key + " value=" + value + "]";
+        }
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/test/build.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/test/build.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/test/build.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,103 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!-- @author Peter Rossbach -->
+<project name="Tomcat: Cluster Testcases" basedir="." default="test">
+	<property file="../../../../build/build.properties" />
+	<property file="../../../../build/build.properties.default" />
+	<property name="test.report.logs" value="logs/reports" />
+	<property name="test.results" value="logs/test-results" />
+
+	<property name="compile.optimize" value="true" />
+	<property name="compile.debug" value="true" />
+	<property name="compile.source" value="1.4" />
+	<property name="compile.deprecation" value="true" />
+	<property name="compile.nowarn" value="off" />
+	<property name="compile.encoding" value="ISO-8859-1" />
+	<property name="build.dir" value="build/test" />
+	<property name="src.dir" value="src/share" />
+	<property name="catalina.home" value="../../../../build/build" />
+
+	<!-- Build the classpath -->
+	<path id="project.classpath">
+		<pathelement location="${jmx.jar}" />
+		<pathelement location="${commons-logging.jar}" />
+		<pathelement location="${log4j.jar}" />
+		<fileset dir="${catalina.home}/common/endorsed">
+			<include name="*.jar" />
+		</fileset>
+		<fileset dir="${catalina.home}/common/lib">
+			<include name="*.jar" />
+		</fileset>
+		<fileset dir="${catalina.home}/server/lib">
+			<include name="*.jar" />
+		</fileset>
+	</path>
+
+	<target name="build-prepare">
+		<mkdir dir="${build.dir}" />
+	</target>
+
+	<target name="info" description="Shows a information about this ant script">
+		<echo>
+			This ant script implements some testcases to verify the key functions of tomcat clustering module.
+			You find this script at: ${ant.file}
+		</echo>
+	</target>
+
+	<!-- This target compiles all sources out of the 
+			projects source tree -->
+	<target name="compile" depends="build-prepare" description="This target compiles all sources out of the projects source tree">
+
+		<!-- Copies the static resources out of the src tree
+				to the build/classes dir -->
+		<copy todir="${build.dir}/classes">
+			<fileset dir="${src.dir}">
+				<include name="**" />
+				<exclude name="**/*.java" />
+			</fileset>
+		</copy>
+
+		<!-- Compiles all sources -->
+		<javac destdir="${build.dir}/classes" srcdir="${src.dir}" includes="**/*.java" excludes="**/CVS/**" deprecation="${compile.deprecation}" debug="${compile.debug}" source="${compile.source}" optimize="${compile.optimize}" nowarn="${compile.nowarn}" encoding="${compile.encoding}">
+			<classpath>
+				<path refid="project.classpath" />
+			</classpath>
+		</javac>
+	</target>
+
+	<target name="test" depends="compile" description="Run unit tests">
+		<delete dir="${test.results}" />
+		<mkdir dir="${test.results}" />
+		<junit fork="yes" failureProperty="test.failure">
+			<jvmarg value="-Dcatalina.base=${basedir}" />
+			<jvmarg value="-Dcatalina.home=${catalina.home}" />
+			<jvmarg value="-Dlog4j.configuration=file:conf/log4j.xml" />
+			<classpath>
+				<pathelement location="${build.dir}/classes" />
+				<path refid="project.classpath" />
+			</classpath>
+			<formatter type="plain" usefile="false" />
+			<formatter type="xml" />
+			<batchtest todir="${test.results}">
+				<fileset dir="${build.dir}/classes" includes="**/*Test.class" />
+			</batchtest>
+		</junit>
+		<mkdir dir="${test.report.logs}" />
+		<junitreport todir="${test.report.logs}">
+			<fileset dir="${test.results}" />
+			<report format="frames" todir="${test.report.logs}" />
+		</junitreport>
+		<antcall target="checktest" />
+	</target>
+
+	<target name="checktest" if="test.failure">
+		<fail message="some test failed" />
+	</target>
+
+	<target name="clean">
+		<delete dir="${build}/dir" />
+		<delete dir="build" />
+		<delete dir="${test.report.logs}" />
+		<delete dir="${test.results}" />
+		<delete dir="logs" />
+	</target>
+</project>

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/test/conf/log4j.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/test/conf/log4j.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/test/conf/log4j.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
+<!-- ===================================================================== -->
+<!-- -->
+<!-- Log4j Configuration -->
+<!-- -->
+<!-- ===================================================================== -->
+<!-- $Id: log4j.xml 303832 2005-04-03 16:03:01Z pero $ -->
+<!--
+| For more configuration infromation and examples see the Jakarta Log4j
+| owebsite: http://jakarta.apache.org/log4j
+-->
+<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/" debug="false">
+
+<!-- ============================== -->
+<!-- Append messages to the console -->
+<!-- ==============================-->
+
+<appender name="CONSOLE" class="org.apache.log4j.ConsoleAppender">
+   <param name="Target" value="System.out"/>
+   <param name="Threshold" value="debug"/>
+   <layout class="org.apache.log4j.PatternLayout">
+      <param name="ConversionPattern" value="%d{ABSOLUTE} %-5p [%c{1}] %m%n"/>
+   </layout>
+</appender>
+
+
+<category name="org.apache.catalina.cluster" 
+           additivity="false"> 
+   <priority value="info" />
+   <appender-ref ref="CONSOLE" />
+</category>
+
+<category name="org.apache.catalina" 
+           additivity="false"> 
+   <priority value="info" />
+   <appender-ref ref="CONSOLE" />
+</category>
+
+<!-- Setup the Root c  -->
+<root>
+   <priority value="info" />
+   <appender-ref ref="CONSOLE"/>
+</root>
+</log4j:configuration> 
+

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/test/src/share/org/apache/catalina/cluster/io/XByteBufferTest.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/test/src/share/org/apache/catalina/cluster/io/XByteBufferTest.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/test/src/share/org/apache/catalina/cluster/io/XByteBufferTest.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,123 @@
+/*
+ * Copyright 1999,2005 The Apache Software Foundation.
+ * 
+ * Licensed 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.cluster.io;
+
+import java.io.IOException;
+
+import junit.framework.TestCase;
+
+import org.apache.catalina.cluster.tcp.ClusterData;
+import org.apache.catalina.cluster.ClusterMessage;
+
+/**
+ * @author Peter Rossbach
+ * 
+ * @version $Revision: 384818 $ $Date: 2006-03-10 09:29:17 -0600 (Fri, 10 Mar 2006) $
+ */
+public class XByteBufferTest extends TestCase {
+
+    public void testBytes() {
+        XByteBuffer xbuf = new XByteBuffer() ;
+        assertEquals(0,xbuf.bufSize);
+        assertEquals(1024,xbuf.buf.length);
+        assertEquals(0,xbuf.getBytes().length);
+        assertNotSame(xbuf.buf,xbuf.getBytes());
+    }
+    
+    
+    /**
+     * Test append to message buffer
+     * Test that only correct message header are appended 
+     */
+    public void testAppend() {
+        XByteBuffer xbuf = new XByteBuffer();
+        byte[] bs = new byte[] { 1, 2, 3 };
+        boolean status = xbuf.append(bs, 0, 3);
+        assertTrue(status);
+        assertEquals(3, xbuf.bufSize);
+        byte buf[] = xbuf.getBytes();
+        assertEquals(3, buf.length);
+        status = xbuf.append(bs, 0, 3);
+        assertTrue(status);
+        status = xbuf.append(bs, 0, 3);
+        // not a correct message !!
+        assertFalse(status);
+        // buffer is cleared
+        assertEquals(0,xbuf.bufSize);
+        status = xbuf.append(XByteBuffer.START_DATA,0, XByteBuffer.START_DATA.length);
+        assertTrue(status);      
+    }
+    
+    /**
+     * Test create a uncompressed multi message data package and extract it
+     * @throws IOException
+     */
+    public void testSendUncompressedMessage() throws IOException {
+        assertSendMessage();
+    }
+
+    /**
+     * @throws IOException
+     */
+    private void assertSendMessage() throws IOException {
+        byte[] test = createMessage();
+        XByteBuffer b = new XByteBuffer();
+        b.append(test, 0, test.length);
+        int s = b.countPackages();
+        byte[] d ;
+        ClusterData data ;
+        assertEquals(3, s);
+        for (byte i = 1; i < 4; i++) {
+            data = b.extractPackage(true);
+            d = data.getMessage();
+            assertEquals("wrong message content",i, d[0]);
+        }
+    }
+
+    /**
+     * create three message inside one byte buffer
+     * @return three clustermessage at one byte array
+     * @see XByteBuffer#createDataPackage(byte[])
+     * @throws IOException
+     */
+    private byte[] createMessage() throws IOException {
+        byte[] d1 = XByteBuffer.createDataPackage(new byte[] { 1 },ClusterMessage.FLAG_FORBIDDEN);
+        byte[] d2 = XByteBuffer.createDataPackage(new byte[] { 2 },ClusterMessage.FLAG_FORBIDDEN);
+        byte[] d3 = XByteBuffer.createDataPackage(new byte[] { 3 },ClusterMessage.FLAG_FORBIDDEN);
+        byte[] test = new byte[d1.length + d2.length + d3.length + 5];
+        System.arraycopy(d1, 0, test, 0, d1.length);
+        System.arraycopy(d2, 0, test, d1.length, d2.length);
+        System.arraycopy(d3, 0, test, d2.length + d1.length, d3.length);
+        return test;
+    }
+
+
+    /**
+     * Test the type convertes to and from byte array
+     */
+    public void testTypeConverter() {
+        byte[] d = XByteBuffer.toBytes(Integer.MAX_VALUE);
+        assertEquals(4, d.length);
+        assertEquals(Integer.MAX_VALUE, XByteBuffer.toInt(d, 0));
+
+        d = XByteBuffer.toBytes(Long.MAX_VALUE);
+        assertEquals(8, d.length);
+        assertEquals(Long.MAX_VALUE, XByteBuffer.toLong(d, 0));
+        d = XByteBuffer.toBytes((long) 4564564);
+        assertEquals(4564564, XByteBuffer.toLong(d, 0));
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/test/src/share/org/apache/catalina/cluster/mcast/McastMemberTest.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/test/src/share/org/apache/catalina/cluster/mcast/McastMemberTest.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/test/src/share/org/apache/catalina/cluster/mcast/McastMemberTest.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,54 @@
+/*
+ * Copyright 1999,2005 The Apache Software Foundation.
+ * 
+ * Licensed 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.cluster.mcast;
+
+import org.apache.catalina.cluster.io.XByteBuffer;
+
+import junit.framework.TestCase;
+
+/**
+ * @author Peter Rossbach
+ * 
+ * @version $Revision: 303950 $
+ */
+public class McastMemberTest extends TestCase{
+
+    private static final String TEST = "0123456789";
+    public void testGetMember() throws Exception {
+        byte[] data = new byte[44];
+        long alive=System.currentTimeMillis()-20;
+        System.arraycopy(XByteBuffer.toBytes((long)alive),0,data,0,8);
+        System.arraycopy(XByteBuffer.toBytes(20000),0,data,8,4);
+        System.arraycopy(XByteBuffer.toBytes(120000000),0,data,12,4);
+        System.arraycopy(XByteBuffer.toBytes(10),0,data,16,4);
+        System.arraycopy(TEST.getBytes(),0,data,20,TEST.length());
+        System.arraycopy(XByteBuffer.toBytes(10),0,data,30,4);
+        System.arraycopy(TEST.getBytes(),0,data,34,TEST.length());
+        McastMember member = McastMember.getMember(data);
+        assertEquals(member.getName(),TEST);
+        assertEquals(member.getDomain(),TEST);
+        assertEquals(member.getPort(),20000);
+        assertEquals(member.getHost(),"7.39.14.0");
+        byte[] data1 = member.getData(20);
+        assertEquals(data.length,data1.length);
+        McastMember member1 = McastMember.getMember(data1);
+        assertEquals(member1.getName(),TEST);
+        assertEquals(member1.getDomain(),TEST);
+        assertEquals(member1.getPort(),20000);
+        assertEquals(member1.getHost(),"7.39.14.0");
+        
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/test/src/share/org/apache/catalina/cluster/session/DeltaManagerTest.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/test/src/share/org/apache/catalina/cluster/session/DeltaManagerTest.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/test/src/share/org/apache/catalina/cluster/session/DeltaManagerTest.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,143 @@
+/*
+ * Copyright 1999,2005 The Apache Software Foundation.
+ * 
+ * Licensed 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.cluster.session;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import junit.framework.TestCase;
+
+import org.apache.catalina.Session;
+import org.apache.catalina.cluster.ClusterMessage;
+import org.apache.catalina.cluster.Member;
+import org.apache.catalina.cluster.mcast.McastMember;
+import org.apache.catalina.cluster.mcast.McastService;
+import org.apache.catalina.cluster.tcp.SimpleTcpCluster;
+
+/**
+ * @author Peter Rossbach
+ * 
+ * @version $Revision: 303950 $ $Date: 2005-06-09 15:38:30 -0500 (Thu, 09 Jun 2005) $
+ */
+public class DeltaManagerTest extends TestCase {
+
+    public void testCreateSession() {
+        MockDeltaManager manager = new MockDeltaManager() ;
+        Session session = manager.createSession(null,false);
+        assertNotNull(session.getId());
+        assertEquals(32, session.getId().length());
+        session = manager.createSession(null,true);
+        assertEquals(session,manager.session);
+        assertEquals(session.getId(),manager.sessionID);
+    }
+    
+    public void testhandleGET_ALL_SESSIONS() throws Exception {
+        MockDeltaManager manager = new MockDeltaManager() ;
+        Session session = manager.createSession(null,false);
+        assertEquals(session, manager.findSession(session.getId()));
+        for (int i = 0; i < 10; i++) {
+            manager.createSession(null,false);
+        }
+        assertEquals(11,manager.getSessionCounter());
+        Member sender = new McastMember("test","d10","localhost",8080,3000);
+        MockCluster cluster = new MockCluster ();
+        manager.setCluster(cluster);
+        manager.setSendAllSessionsSize(2);
+        manager.handleGET_ALL_SESSIONS(null,sender);
+        // send all session activ - 6 sessions message and one transfer complete
+        assertEquals(2,cluster.sendcounter);
+        
+        // send session blockwise
+        cluster.sendcounter=0;
+        manager.setSendAllSessions(false);
+        manager.handleGET_ALL_SESSIONS(null,sender);
+        // 11 session activ - 6 sessions message and one transfer complete
+        assertEquals(7,cluster.sendcounter);
+    }
+    
+    public void testFirstMemberhandleGET_ALL_SESSIONS() throws Exception {
+        MockDeltaManager manager = new MockDeltaManager() ;
+        MockCluster cluster = new MockCluster ();
+        McastService service = new MockMcastService() ; 
+        cluster.setMembershipService(service);
+        manager.setCluster(cluster);
+        manager.getAllClusterSessions();
+        assertEquals(0,cluster.sendcounter);
+        manager.setSendClusterDomainOnly(false);
+        manager.getAllClusterSessions();
+        assertEquals(0,cluster.sendcounter);
+        manager.setSendClusterDomainOnly(true);
+        service.memberAdded(new McastMember("franz2", "d11", "127.0.0.1", 7002, 100));
+        manager.getAllClusterSessions();
+        assertEquals(0,cluster.sendcounter);
+        service.memberAdded(new McastMember("franz3", "d10", "127.0.0.1", 7003, 100));
+        assertNotNull(manager.findSessionMasterMember());
+    }
+    
+    class MockMcastService extends McastService {
+        List members = new ArrayList();
+        
+        public MockMcastService() {
+            localMember =new McastMember("franz", "d10", "127.0.0.1", 7001, 100) ; 
+       }
+        public void memberAdded(Member member) {
+            members.add(member);
+        }
+        public Member getLocalMember() {
+            return localMember;
+        }
+
+        public Member[] getMembers() {
+            return (Member[]) members.toArray(new Member[members.size()]);
+        }
+    }
+    
+    class MockDeltaManager extends DeltaManager {
+        
+        private String sessionID;
+        private DeltaSession session;
+
+
+        /**
+         * 
+         */
+        public MockDeltaManager() {
+            super();
+        }
+        
+        
+        /* (non-Javadoc)
+         * @see org.apache.catalina.cluster.session.DeltaManager#sendCreateSession(java.lang.String, org.apache.catalina.cluster.session.DeltaSession)
+         */
+        protected void sendCreateSession(String sessionId, DeltaSession session) {
+           this.sessionID = sessionId ;
+           this.session = session ;
+        }       
+        
+    }
+    
+    class MockCluster extends SimpleTcpCluster {
+    
+        private int sendcounter;
+
+        /** don't send only count sends
+         * @see org.apache.catalina.cluster.CatalinaCluster#send(org.apache.catalina.cluster.ClusterMessage, org.apache.catalina.cluster.Member)
+         */
+        public void send(ClusterMessage msg, Member dest) {
+            sendcounter++ ;
+        }
+}
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/test/src/share/org/apache/catalina/cluster/session/DeltaSessionTest.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/test/src/share/org/apache/catalina/cluster/session/DeltaSessionTest.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/test/src/share/org/apache/catalina/cluster/session/DeltaSessionTest.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,97 @@
+/*
+ * Copyright 1999,2005 The Apache Software Foundation.
+ * 
+ * Licensed 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.cluster.session;
+
+import junit.framework.TestCase;
+
+import org.apache.catalina.Manager;
+
+/**
+ * @author Peter Rossbach
+ * 
+ * @version $Revision: 384817 $ $Date: 2006-03-10 09:27:43 -0600 (Fri, 10 Mar 2006) $
+ */
+public class DeltaSessionTest extends TestCase {
+
+    public void testPrimarySessionisValid() {
+        DeltaManager manager = new DeltaManager() { public DeltaSession getNewDeltaSession() { return new MockSession(this) ; } } ;
+        manager.setMaxInactiveInterval(1);
+        MockSession session = (MockSession)manager.createSession("hello",false);
+        assertTrue(session.isPrimarySession());
+        assertTrue(session.isValid()) ;
+        assertEquals(1,session.getMaxInactiveInterval());
+        try {
+            Thread.sleep(2000);
+        } catch (Exception sleep) {
+        }
+        long timeNow = System.currentTimeMillis();
+        int timeIdle = (int) ((timeNow - session.getLastAccessedTimeInternal()) / 1000L);
+        assertEquals(2,timeIdle);
+        assertTrue(timeIdle > session.getMaxInactiveInterval());
+        assertFalse(session.isValid()) ;
+        assertEquals(1,session.expireNotifyCalled);
+        assertEquals(1,session.expireNotifyClusterCalled);
+    }
+ 
+    public void testBackupSessionisValid() {
+        DeltaManager manager = new DeltaManager() { public DeltaSession getNewDeltaSession() { return new MockSession(this) ; } } ;
+        manager.setMaxInactiveInterval(1);
+        MockSession session = (MockSession)manager.createSession("hello",false);
+        session.setPrimarySession(false);
+        try {
+            Thread.sleep(1000);
+        } catch (Exception sleep) {
+        }
+        assertTrue(session.isValid()) ;
+        assertEquals(0,session.expireNotifyCalled);
+        assertEquals(0,session.expireNotifyClusterCalled);
+        try {
+            Thread.sleep(2000);
+        } catch (Exception sleep) {
+        }
+        assertFalse(session.isValid()) ;
+        assertEquals(1,session.expireNotifyCalled);
+        // no cluster notification
+        assertEquals(0,session.expireNotifyClusterCalled);
+    }
+    
+    class MockSession extends DeltaSession {
+
+        long expireCalled = 0 ;
+        long expireNotifyCalled = 0 ;
+        long expireNotifyClusterCalled = 0 ;
+        
+        
+        /**
+         * @param manager
+         */
+        public MockSession(Manager manager) {
+            super(manager);
+        }
+      
+        /* (non-Javadoc)
+         * @see org.apache.catalina.cluster.session.DeltaSession#expire(boolean, boolean)
+         */
+        public void expire(boolean notify, boolean notifyCluster) {
+            expireCalled++ ;
+            if(notify)
+                expireNotifyCalled++ ;
+            if(notifyCluster)
+                expireNotifyClusterCalled++ ;
+            isValid = false ;
+        }
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/test/src/share/org/apache/catalina/cluster/tcp/DataSenderTest.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/test/src/share/org/apache/catalina/cluster/tcp/DataSenderTest.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/test/src/share/org/apache/catalina/cluster/tcp/DataSenderTest.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,417 @@
+/*
+ * Copyright 1999,2005 The Apache Software Foundation.
+ * 
+ * Licensed 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.cluster.tcp;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.InetAddress;
+import java.net.Socket;
+import java.net.SocketException;
+import java.net.SocketTimeoutException;
+import java.net.UnknownHostException;
+
+import junit.framework.TestCase;
+
+/**
+ * @author Peter Rossbach
+ * 
+ * @version $Revision: 366254 $ $Date: 2006-01-05 13:32:21 -0600 (Thu, 05 Jan 2006) $
+ */
+public class DataSenderTest extends TestCase {
+    
+    /**
+     * Test that close Socket before socket open again!
+     * @throws Exception
+     */
+    public void testOpenAgain() throws Exception {
+        DataSender sender = createMockDataSender(); 
+        assertEquals(1,sender.getSocketOpenCounter());
+        assertEquals(0,sender.getSocketCloseCounter());
+        sender.openSocket() ;
+        assertEquals(1,sender.getSocketOpenCounter());
+        assertEquals(0,sender.getSocketCloseCounter());
+        sender.closeSocket() ;
+        sender.openSocket() ;
+        assertEquals(1,sender.getSocketCloseCounter());
+        assertEquals(2,sender.getSocketOpenCounter());
+    }
+    
+    /**
+     * Test Connect/disconnet open and close underlying sockets
+     * @throws Exception
+     */
+    public void testConnectDisconnect() throws Exception {
+        InetAddress host = InetAddress.getByName("127.0.0.1");
+        DataSender sender = new MockDataSender("catalina",host, 3434);
+        sender.connect() ;
+        assertTrue(sender.isConnected());
+        assertEquals(1,sender.getSocketOpenCounter());
+        assertEquals(0,sender.getSocketCloseCounter());
+        assertEquals(1,sender.getConnectCounter());
+        sender.disconnect();
+        assertFalse(sender.isConnected());
+        assertEquals(1,sender.getSocketCloseCounter());
+        assertEquals(1,sender.getDisconnectCounter());
+   }
+    
+    /**
+     * Test Socket setup and OpenClose Counter
+     * @throws Exception
+     */
+    public void testOpenCloseSocketCounter() throws Exception {
+        DataSender sender = createMockDataSender();
+        assertEquals(0, sender.getSocket().getSoTimeout());
+        sender.closeSocket();
+        assertEquals(1, sender.getSocketOpenCounter());
+        assertEquals(1, sender.getSocketCloseCounter());
+    }
+
+    /**
+     * Test Socket IOException with SocketCounter increment
+     * @throws Exception
+     */
+    public void testFailedOpenSocketCounter() throws Exception {
+        InetAddress host = InetAddress.getByName("127.0.0.1");
+        DataSender sender = new MockFailedDataSender("catalina",host, 3434);
+        try {
+            sender.openSocket();
+            fail("Sender not send expected IOException");
+        } catch (IOException ioe) {
+            assertEquals(0, sender.getSocketOpenCounter());
+            assertEquals(1, sender.getSocketOpenFailureCounter());
+        }
+    }
+
+    /**
+     * read ack from receiver
+     * @throws Exception
+     */
+    public void testWaitForAck() throws Exception {
+        DataSender sender = createMockDataSender();
+        assertNotNull(sender.getSocket());
+        sender.waitForAck(15000);  
+        ByteArrayInputStream stream = (ByteArrayInputStream)sender.getSocket().getInputStream();
+        assertEquals(-1,stream.read());
+    }
+    
+    /**
+     * @return
+     * @throws UnknownHostException
+     * @throws IOException
+     * @throws SocketException
+     */
+    private DataSender createMockDataSender() throws UnknownHostException, IOException, SocketException {
+        InetAddress host = InetAddress.getByName("127.0.0.1");
+        DataSender sender = new MockDataSender("catalina",host, 3434);
+        sender.openSocket();
+        return sender;
+    }
+
+    /**
+     * Send message with  wait ack and simulate ack Exceptions
+     * @throws Exception
+     */
+    public void testWriteData()throws Exception {
+        DataSender sender = createMockDataSender();
+        ClusterData data = new ClusterData("test", "123",new byte[]{ 1,2,3 }, System.currentTimeMillis() );
+        sender.writeData(data) ;
+        ByteArrayOutputStream stream = (ByteArrayOutputStream)sender.getSocket().getOutputStream();
+        assertEquals(25,stream.size());
+        ByteArrayInputStream istream = (ByteArrayInputStream)sender.getSocket().getInputStream();
+        assertEquals(6,istream.read());    
+        MockSocket socket =((MockSocket)sender.getSocket());
+        socket.reset();
+        sender.setWaitForAck(true);
+        socket.setReadIOException(true);
+        try {
+            sender.writeData(data);
+            fail("Missing Ack IOException") ;
+        } catch (IOException ioe) {} ;
+        socket.reset();
+        socket.setReadIOException(false);
+        socket.setReadSocketTimeoutException(true);
+        try {
+            sender.writeData(data);
+            fail("Missing Ack SocketTimeoutException") ;
+        } catch (SocketTimeoutException soe) {} ;               
+
+    }
+    
+    /**
+     * Send message without wait ack
+     * @throws Exception
+     */
+    public void testWriteDataWithOutAck()throws Exception {
+        InetAddress host = InetAddress.getByName("127.0.0.1");
+        DataSender sender = new MockDataSender("catalina",host, 3434);
+        sender.setWaitForAck(false);
+        sender.openSocket();
+        ClusterData data = new ClusterData("test", "123",new byte[]{ 1,2,3 }, System.currentTimeMillis() );
+        sender.writeData(data) ;
+        ByteArrayOutputStream stream = (ByteArrayOutputStream)sender.getSocket().getOutputStream();
+        assertEquals(25,stream.size());
+        ByteArrayInputStream istream = (ByteArrayInputStream)sender.getSocket().getInputStream();
+        assertEquals(3,TcpReplicationThread.ACK_COMMAND.length);
+        assertEquals(TcpReplicationThread.ACK_COMMAND[0],istream.read());        
+        assertEquals(TcpReplicationThread.ACK_COMMAND[1],istream.read());        
+        assertEquals(TcpReplicationThread.ACK_COMMAND[2],istream.read());   
+     }
+    
+    /**
+     * Check close socket fro keep alive handling is correct (number of request and timeout
+     * @throws Exception
+     */
+    public void testCheckKeepAlive() throws Exception {
+        DataSender sender = createMockDataSender() ;
+        assertFalse(sender.checkKeepAlive()) ;
+        sender.setKeepAliveMaxRequestCount(1);
+        sender.keepAliveCount = 1;
+        assertTrue(sender.checkKeepAlive());
+        assertEquals(1,sender.getSocketCloseCounter());
+        assertEquals(0,sender.getKeepAliveCount());
+        sender.openSocket();
+        assertEquals(0,sender.getKeepAliveCount());
+        sender.setKeepAliveMaxRequestCount(100);
+        sender.keepAliveConnectTime = System.currentTimeMillis() - sender.getKeepAliveTimeout() ;
+        assertFalse(sender.checkKeepAlive());
+        assertTrue(sender.isConnected());
+        assertEquals(1,sender.getSocketCloseCounter());
+        sender.keepAliveConnectTime-- ;
+        assertTrue(sender.checkKeepAlive());
+        assertEquals(2,sender.getSocketCloseCounter());
+    }
+    
+    
+    /**
+     * Push a mesage over moch socket to receiver
+     * @throws Exception
+     */
+    public void testPushMessage() throws Exception {
+        InetAddress host = InetAddress.getByName("127.0.0.1");
+        DataSender sender = new MockDataSender("catalina",host, 3434);
+        assertFalse(sender.isConnected());
+        assertPushMessage(sender);
+        ((MockSocket)sender.getSocket()).reset();
+        // let see the processingtime 
+        sender.setDoProcessingStats(true);
+        pushMessage(sender);
+        assertEquals(sender.getProcessingTime(),sender.getMinProcessingTime());
+        assertEquals(sender.getProcessingTime(),sender.getMaxProcessingTime());
+    }
+   
+    /**
+     * Test retry after socket write failure
+     * @throws Exception
+     */
+    public void testPushMessageRetryFailure() throws Exception {
+        InetAddress host = InetAddress.getByName("127.0.0.1");
+        DataSender sender = new MockDataSender("catalina",host, 3434);
+        sender.setResend(true);
+        sender.openSocket() ;
+        ((MockSocket)sender.getSocket()).setWriteIOException(true);
+        assertPushMessage(sender);
+        assertEquals(2,sender.getSocketOpenCounter());
+        assertEquals(1,sender.getSocketCloseCounter());
+    }
+    
+    /**
+     * Test socket closed after socket write failure without retry
+     * @throws Exception
+     */
+    public void testPushMessageFailure() throws Exception {
+        InetAddress host = InetAddress.getByName("127.0.0.1");
+        DataSender sender = new MockDataSender("catalina",host, 3434);
+        sender.openSocket() ;
+        ((MockSocket)sender.getSocket()).setWriteIOException(true);
+        try {
+            assertPushMessage(sender);
+            fail("No IOException is thrown");
+        } catch (IOException ioe) {}
+        assertFalse(sender.isConnected());
+        assertEquals(1,sender.getSocketOpenCounter());
+        assertEquals(1,sender.getSocketCloseCounter());
+    }
+
+    /**
+     * @param sender
+     * @throws IOException
+     */
+    private void assertPushMessage(DataSender sender) throws IOException {
+        ByteArrayOutputStream stream = pushMessage(sender);
+        assertEquals("message format is wrong",25,stream.size());
+        assertEquals("socket is not at keep alive mode",1,sender.getKeepAliveCount());
+        assertEquals("no stats or wrong number of request message counter",1,sender.getNrOfRequests());
+        assertEquals("to long operation",0,sender.getProcessingTime());
+        assertEquals(Long.MAX_VALUE,sender.getMinProcessingTime());
+    }
+
+    /**
+     * @param sender
+     * @return
+     * @throws IOException
+     */
+    private ByteArrayOutputStream pushMessage(DataSender sender) throws IOException {
+        ClusterData data = new ClusterData("unique-id", "123",new byte[]{ 1,2,3 }, System.currentTimeMillis() );
+        sender.pushMessage(data );
+        assertTrue("sender is not connect after message pushed!",sender.isConnected());
+        ByteArrayOutputStream stream = (ByteArrayOutputStream)sender.getSocket().getOutputStream();
+        return stream;
+    }
+
+    /**
+     * Simulate Create socket failure 
+     */
+    class MockFailedDataSender extends DataSender {
+
+        /**
+         * @param host
+         * @param port
+         */
+        public MockFailedDataSender(String domain,InetAddress host, int port) {
+            super(domain,host, port);
+        }
+
+        /*
+         * throw IOException
+         * 
+         * @see org.apache.catalina.cluster.tcp.DataSender#createSocket()
+         */
+        protected void createSocket() throws IOException, SocketException {
+            throw new IOException();
+        }
+    }
+
+    /**
+     * Simulate open real socket to a server!!
+     */
+    class MockDataSender extends DataSender {
+
+        
+        /**
+         * @param host
+         * @param port
+         */
+        public MockDataSender(String domain,InetAddress host, int port) {
+            super(domain,host, port);
+            
+        }
+
+        protected void createSocket() throws IOException, SocketException {
+            setSocket(new MockSocket(getAddress(), getPort()));
+        }
+        
+    }
+    
+    /**
+     * Don't open Socket really
+     */
+    class MockSocket extends Socket {
+
+        private InputStream ackInputStream ;
+        private OutputStream messageStream ;
+        private boolean writeIOException = false ;
+        private boolean readIOException = false ;
+        private boolean readSocketTimeoutException = false ;
+               
+        /**
+         * @param address
+         * @param port
+         * @throws java.io.IOException
+         */
+        public MockSocket(InetAddress address, int port) throws IOException {
+            ackInputStream = new ByteArrayInputStream(TcpReplicationThread.ACK_COMMAND);
+            messageStream = new ByteArrayOutputStream() ;
+        }
+        
+        public void reset() throws IOException {
+           ackInputStream.reset() ;
+        }
+        
+        
+        /**
+         * @return Returns the readIOException.
+         */
+        public boolean isReadIOException() {
+            return readIOException;
+        }
+        
+        /**
+         * @param readIOException The readIOException to set.
+         */
+        public void setReadIOException(boolean readIOException) {
+            this.readIOException = readIOException;
+        }
+        
+        /**
+         * @return Returns the readSocketTimeoutException.
+         */
+        public boolean isReadSocketTimeoutException() {
+            return readSocketTimeoutException;
+        }
+        
+        /**
+         * @param readSocketTimeoutException The readSocketTimeoutException to set.
+         */
+        public void setReadSocketTimeoutException(
+                boolean readSocketTimeoutException) {
+            this.readSocketTimeoutException = readSocketTimeoutException;
+        }
+        /**
+         * @return Returns the writeIOException.
+         */
+        public boolean isWriteIOException() {
+            return writeIOException;
+        }
+        
+        /**
+         * @param writeIOException The writeIOException to set.
+         */
+        public void setWriteIOException(boolean writeIOException) {
+            this.writeIOException = writeIOException;
+        }
+        
+        /**
+         *  get ack Stream ( 3 bytes)
+         * @see TcpReplicationThread#ACK_COMMAND
+         * @see java.net.Socket#getInputStream()
+         */
+        public InputStream getInputStream() throws IOException {
+            if(isReadIOException()) {
+                throw new IOException("MockSocket");
+            }
+            if(isReadSocketTimeoutException()) {
+                throw new SocketTimeoutException("MockSocket");
+            }
+            return ackInputStream;
+        }
+        
+        
+        /**
+         * Buffer Output in simple byte array stream
+         * @see java.net.Socket#getOutputStream()
+         */
+        public OutputStream getOutputStream() throws IOException {
+            if(isWriteIOException()) {
+                throw new IOException("MockSocket");
+            }
+            return messageStream;
+        }
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/test/src/share/org/apache/catalina/cluster/tcp/ReplicationTransmitterTest.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/test/src/share/org/apache/catalina/cluster/tcp/ReplicationTransmitterTest.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/test/src/share/org/apache/catalina/cluster/tcp/ReplicationTransmitterTest.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,75 @@
+/*
+ * Copyright 1999,2005 The Apache Software Foundation.
+ * 
+ * Licensed 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.cluster.tcp;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.util.zip.GZIPInputStream;
+
+import junit.framework.TestCase;
+
+import org.apache.catalina.cluster.session.ReplicationStream;
+import org.apache.catalina.cluster.session.SessionMessageImpl;
+
+/**
+ * @author Peter Rossbach
+ * 
+ * @version $Revision: 303962 $ $Date: 2005-06-26 16:21:50 -0500 (Sun, 26 Jun 2005) $
+ */
+public class ReplicationTransmitterTest extends TestCase {
+
+    public void testCreateMessageData() throws Exception {
+        ReplicationTransmitter transmitter = new ReplicationTransmitter();
+        transmitter.setCompress(true);
+        SessionMessageImpl message= new SessionMessageImpl();
+        message.setUniqueId("test");
+        ClusterData data = transmitter.serialize(message);
+        assertTrue(200 < data.getMessage().length);
+        Object myobj = getGZPObject(data.getMessage());
+        assertTrue(myobj instanceof SessionMessageImpl);
+        assertEquals("test", ((SessionMessageImpl)myobj).getUniqueId());
+        
+    }
+
+    /**
+     * @param data
+     * @return
+     * @throws IOException
+     * @throws ClassNotFoundException
+     */
+    private Object getGZPObject(byte[] data) throws IOException, ClassNotFoundException {
+        ByteArrayInputStream bin = 
+            new ByteArrayInputStream(data);
+        GZIPInputStream gin = 
+            new GZIPInputStream(bin);
+        byte[] tmp = new byte[1024];
+        int length = gin.read(tmp);
+        byte[] result = new byte[0];
+        while (length > 0) {
+            byte[] tmpdata = result;
+            result = new byte[result.length + length];
+            System.arraycopy(tmpdata, 0, result, 0, tmpdata.length);
+            System.arraycopy(tmp, 0, result, tmpdata.length, length);
+            length = gin.read(tmp);
+        }
+        gin.close();
+        ReplicationStream stream = new ReplicationStream(
+                new java.io.ByteArrayInputStream(result), getClass()
+                        .getClassLoader());
+        Object myobj = stream.readObject();
+        return myobj;
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/test/src/share/org/apache/catalina/cluster/tcp/ReplicationValveTest.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/test/src/share/org/apache/catalina/cluster/tcp/ReplicationValveTest.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/test/src/share/org/apache/catalina/cluster/tcp/ReplicationValveTest.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,40 @@
+/*
+ * Copyright 1999,2005 The Apache Software Foundation.
+ * 
+ * Licensed 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.cluster.tcp;
+
+import junit.framework.TestCase;
+
+/**
+ * @author Peter Rossbach
+ * 
+ * @version $Revision: 303832 $ $Date: 2005-04-03 11:03:01 -0500 (Sun, 03 Apr 2005) $
+ */
+public class ReplicationValveTest extends TestCase {
+
+    
+    public void testIsRequestWithoutSessionChange() {
+        ReplicationValve valve = new ReplicationValve() ;
+        valve.setFilter(".*\\.html");
+        assertEquals(1,valve.getReqFilters().length) ;
+        assertTrue(valve.isRequestWithoutSessionChange("/ClusterTest/index.html")) ;        
+        assertFalse(valve.isRequestWithoutSessionChange("/ClusterTest/index.jsp")) ;        
+        valve.setFilter(".*\\.html;.*\\.css");
+        assertEquals(2,valve.getReqFilters().length) ;
+        assertTrue(valve.isRequestWithoutSessionChange("/ClusterTest/index.html")) ;        
+        assertTrue(valve.isRequestWithoutSessionChange("/ClusterTest/layout.css")) ;        
+    }
+    
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/test/src/share/org/apache/catalina/cluster/tcp/SimpleTcpClusterTest.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/test/src/share/org/apache/catalina/cluster/tcp/SimpleTcpClusterTest.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/test/src/share/org/apache/catalina/cluster/tcp/SimpleTcpClusterTest.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,47 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.cluster.tcp;
+
+import junit.framework.TestCase;
+
+import org.apache.catalina.LifecycleException;
+import org.apache.catalina.cluster.deploy.FarmWarDeployer;
+import org.apache.catalina.cluster.mcast.McastService;
+import org.apache.catalina.cluster.session.ClusterSessionListener;
+
+/*
+* @author Peter Rossbach
+* @version $Revision: 303864 $ $Date: 2005-04-18 13:55:38 -0500 (Mon, 18 Apr 2005) $
+*/
+public class SimpleTcpClusterTest extends TestCase {
+
+    
+    public void testCreateClusterSessionListenerAtStart() throws LifecycleException
+    {
+        SimpleTcpCluster cluster = new SimpleTcpCluster() ;
+        cluster.setMembershipService( new McastService() { public void start() {} });
+        cluster.setClusterDeployer(new FarmWarDeployer() { public void start() {}});
+        SocketReplicationListener receiver = new SocketReplicationListener(){ public void start() {}};
+        receiver.setTcpListenAddress("localhost");
+        receiver.setTcpListenPort(45660);
+        cluster.setClusterReceiver(receiver);
+        cluster.setClusterSender(new ReplicationTransmitter(){ public void start() {}});
+        cluster.start();
+        assertEquals(1,cluster.clusterListeners.size());
+        assertTrue( cluster.clusterListeners.get(0) instanceof ClusterSessionListener);
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/to-do.txt
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/to-do.txt	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/cluster/to-do.txt	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,398 @@
+==============================
+Next actions
+==============================
+
+- Membership coordinator logic and membership view Id.
+ 
+- Implement primary/secondary replication logic (fhanik)
+  Idea for implementation: Cookie stores info primary/backup node and hit counter.
+  Steps to implement: (coming soon)
+  Scenarios: 
+  1. Request in: new session dest: any
+  2. Request in: existing session dest: primary server
+  3. Request in: existing session dest: non-primary server (fail over)
+  4. Request in: existing session dest: backup server 
+  5. Backup node crash
+  6. Primary node crash (step 3)
+  7. Sequence 6. then 2. (hit counter)
+  8. Sequence 5. then 4. (swap)
+  9. New member joins 
+  10. Backup and primary crash -> death!
+  11. Sequence 2. in: invalid hit counter 
+  12. Sequence 4. in: invalid hit counter
+  13. Session expires
+  14. Sequence 3. then 13. on the old primary
+  
+  Notes:
+  Ability to add a custom "Session expired" redirect for global 
+  redirects to never forward an invalid session into the server
+  when the session data has gone lost.
+  Ie, in a normal scenario, the session is viewed as "new"
+  but they may wanna display a session expired redirect.
+  Security:
+  Dont store any sensitive info in the new cookie.
+  only pointers to members.
+
+  
+- break out membership/messaging module and improve JMX
+  The clustering code has become very cluttered.
+  We need to break out the membership and the messaging 
+  away from the logic of session handling and JMX.
+  The latter should be built on top of the clustering module, and not baked into it.
+  (maybe complete refactor for Tomcat 6)
+  Steps:
+  1. Build a group object, to allow sending of messages
+     The group object will handle encompass membership and 
+     messaging under one umbrella.
+  2. Enable group RPC
+     Through the group object, enable RPC style messaging
+     This should be used for message like state transfers, instead of waiting for a timeout.
+     RCP strategies - first response, majority response, all response
+  3. Group/Message interceptors - to perform logic such as fragmentation, ordering etc.
+  4. JMX  
+     JMX should be added on top of the core code, not inside the core code.
+     The idea of JMX as management should be added outside to the core components.
+     For example, SimpleTCPCluster should not contain JMX code, if I want to create
+     a different cluster class, I have to rewrite all the JMX code again.
+     Instead, create JMX beans that reference core components through interfaces.
+
+- Create stats object
+   Instead of keeping stats embedded in the code, make it reusable in
+   a shared component.
+
+- support CrossContext session replication
+    Idea: use endAccess to signal replicationValve that session from other app has changed.
+    refactor ReplicationValve 
+    When session is serialzed from other app, set right app classloader
+    endaccess is also send at CoyoteAdpater for context session as recycle the request
+- Add MbeanFactory to generate dynamic cluster at runtime.
+    Problem: How we can start those central services?
+    - StandardEngine support load Mbean from external file.     
+- when a lot of messages expire it comes to burst of messages 
+     - all 60 Sec when ManagerBase#processExpires is called a lot of messages are send!
+     - Better is to transfer a spezial epxire message with an array of expired session messages.
+     - This reduce message transfer and reduce waits for acks.
+     - complicated implementation thing , sessions expires when call isValid :-(     
+- build a tool that receive the stage and present it as simple web app.
+    	detect some problems
+    	different active sessions
+    	long queues
+    	detect long wait acks
+        Idea: Wrote a ant script with the new jmx tasks!
+        Optimzied information access:
+        	Create a MBean.attribute that store the complete cluster state 
+        	information inside one attribute from type TabularData and CompositeData!
+        	Implement as SimpleTcpCluster operation
+        	Cluster <CompositeData>
+        	  -- Attributes <SimpleType>
+        	  -- ClusterMembership
+        	      -- Attributes <SimpleType>
+        	      -- Members <CompositeType>
+        	         -- Attributes <SimpeType>
+        	  -- ClusterReceiver
+        	      -- Attributes <SimpleType>
+        	  -- ClusterSender
+        	      -- Attributes <SimpleType>
+        	      -- DataSenders <TabularData>
+        	         -- Sender <CompositeType>
+        	         	-- Attributes <SimpeType>
+        	         	-- (optional)Queue Stats <CompositeData>
+ 	       	         		-- Attributes <SimpeType>      	    
+- add cluster setup template (src)	
+- documentation
+	wrote a complete new how-to
+	add example configurations
+	add complete attribute descriptions
+	add JMX information
+	add deployment help
+	Need help (pero)
+- implement fragmentation of large replication objects
+  (note this will be done in the Group object, see top.)
+	Compress at message level - this will go away! instead there will be a GZip interceptor
+	Splitting Messages ala FarmDeployer war handling
+- add a message type to the message header.
+    - filtering at receiver that drop message before build Object
+    - define short type definition.
+       - Every Session message with differenz type
+       - type with String
+- add test cluster project
+	functional testing a lot of szenarios
+		differen replication mode
+		restart after failure
+		crash under load
+		compress and uncompressed
+    Junit test ( started)
+    automated regression testing with some standard configs
+    wrote a test client that can get a JMX State to verify the different cluster testszenarios
+	 - direct JSR 160 client - preferred option
+	 - via mx4j http adaptor ( xml protocol)
+	 - setup different szenarios
+	use new remote jmx ant tasks to grab information from mbeans 
+- filter all cluster messages 
+     - Filtering that no all message send to all member.
+     - Now with domain mode registeration session message only send to
+       members from same domain.
+- setup a Cluster LifecycleListener to send the cluster status! (monitoring)
+     - Make the compact state via JMX API avialable first.
+     - setup cluster Listener that send own state to spezial member (sender from a message like GET_ALL_SESSIONS)
+     - create a cluster status app (html/xml)
+         - attributes
+            - send message
+            - current members
+            - receive message
+            - active session at different clustered manager
+            - which app are clusters (registered managers)
+            - avg processing times
+         
+         - operations
+            - resetStats
+            - send a message (String)
+            - getDisplay state from other members??
+            - stop queue to send
+            - queue receiver message from some members ( later send after redeploying)
+            - configure some send parameters
+                 - keepalive
+                 - compress
+                 - wait for ack
+         - other things
+            - based on Cluster JMX API                     
+            - watch some values from complete cluster and display some graphs
+            - display the informations from all nodes
+            - display informations from other cluster domains
+            	via XML documents and http
+            - display stats as xml
+            - operation via JMX (MX4J adaptor)	    
+
+================
+problems
+================ 
+- How we can stop the request traffic when restart an application?
+    currently the jk 1.2.10 can only disable the complete loadbalancer,
+    but this detect only the new session request desicion.
+    Request with sessions marks send to tomcat. 
+    Fix: jk > 1.2.11 has a stopped flag, but then all application stop traffic
+    and session transfer from other nodes not stopped!!
+    	Stop MembershipService via JMX and after redeploying application,
+    	start MembershipService and restart the application Session Manager or send GETALL Session from backup?
+    	then enable apache worker again !! :-(
+    	easier stop tomcats, deploy new app and start again... 
+- Can't stop message replication for a spezial member and application
+   - this need a spezial cluster message and send filter at SimpleTcpCluster 
+- Don't generate cluster message when no member is at cluster!
+   - Register DeltaManager as Cluster LifecycleListener and stop cresting and sending
+   - Reduce memory consume when only local node is active
+   - Important feature when nodes crashed, and only one server exists under load...
+   
+==============================
+Nice to have:
+==============================
+- Replication ContextAttributes	
+- Configure the McastService no accept every member.
+	- receive a secret key
+	- have a allow or deny list like RequestFilterValve
+	- Also receiver don't accept request from not allowed members
+- ReplicationListener and SocketReplicationListener only accept data from cluster member (low level ip restriction)
+- PooledSocketSender
+	Add more stats
+	check all Pooled sender checkKeepAlive
+- Implement a NonSerializable interface for session attributes that do not
+wish to be replicated
+        Then we must have ClusterNonSerializable at common classloader
+- Extend StandardSession if possible
+- Implement context attribute replication (?)
+	pero:
+		Also send Start/Stop messages from Context to complete cluster!
+        With 5.5.10 you can wrote a Cluster Lifecycle Manager that do this.
+            Register for AFTER_MANAGERREGISTER_EVENT and AFTER_MANAGERUNREGISTER_EVENT
+            and also to the context ServletContextAttributeEvent Listener
+            Access the Context
+            	((Manager)event.getData()).getContainer()                     	
+- Fix farm deployment for 5.5
+   pero:
+     Every start all application are deployed only to all running cluster nodes
+     	New registered nodes don't get the applications!
+     	Deploy must send a GET_ALL_APP to all other Deployers.
+        FH: Correction, you should not send GET_ALL_APP to all deployers, only
+to the main one. Which could be another property of the Member object, it
+would not make sense to transfer the same webapp over and over again.
+     		Only watchEnabled Deployer send this member all deployed application.
+		pero:
+		   Yes very true, but currently we distribute also all wars from watch node at begining.
+		   Waiting to start other nodes is only change to not got these war's!
+		   I have made some experiments to register war deployment at new memberAdded to cluster.	   
+     Add JMX Support
+     	Resend Deployed Applications to all or one cluster node.
+     	Show all watch Resource
+     	Processing Time
+     	Change fileMessage Buffersize.
+     	Start/Stop Cluster wide application
+     Deployer and Watcher sync with engine background thread! 
+     	Fixed!		
+     Last FileMessage fragment need longe ackTimeout	
+    	<Cluster ..> <Sender ... ackTimeout="60000"/> </Cluster> 	
+- Change the cluster protocol that developer can add there own data serialzable/deserialzable format (high risk)
+  Note from Filip: Lets not do this, last attempt caused a broken clustering piece for 4 versions. 
+   Currently 
+   	header 		    6 bytes (FLT2002)
+    compressflag    4 byte
+   	data.length     4 bytes
+   	data, 
+   	end header      6 bytes (TLF2003)
+   	
+   Optimized to 
+      header 		2 bytes (TC)
+      type   		1 byte
+      compressflag  1 byte
+      data.length 	4 bytes, 
+      data | <real uncompressed data.length (4 bytes)> data
+      
+      "type" means user defined type and receiver extract bytes and type and sende it to callback
+      	s. ObjectReader or SocketObjectReader
+                       
+       compress     1
+       first data 4 data bytes are the real uncompressed data length. ( Is for better memory management atr recevier side, S. XByteBuffer)
+       
+   change at DataSender.writeData and XByteBuffer and add flexible handling to ClusterSender and ClusterReceiver
+   
+- Add single sign on support
+
+==============================   
+COMPLETED
+==============================
+5.5.16 (fhanik)
+- Extensive logging when a member crashes
+  When a member crashes and you use pooled socket mode then 
+  the logs are spewing out info.
+  Instead, now we only report one IOException if it happens, and 
+  mark the member as suspect.
+
+5.5.16 (fhanik)
+- Average message size
+  For my test application, the average message size has increased from
+  526 bytes per message to over 750 bytes per message from version 5.0.28 to 5.5.15.
+  Need to investigate why this is the case and where the 200+ extra bytes are coming from.
+  Fix: The default compress value had changed. The new default is that no compression is used.
+  To re-enable compression, <Sender compress="true" in the sender element.
+
+5.5.15 (pero)
+- Optimized getMembers access from McastMembership
+    Member list was copied at every access. (Used inside ReplicationValve.invoke)
+    SimpleTcpCluster need a alive time sorted array
+
+5.5.11 (pero)
+- MemoryUser principal from UserDatabaseRealm not handled to replicated 
+	- look inside DeltaRequest.setPrincipal(Principal,boolean)
+		 detected by Dirk de Kok (tomdev 16.8.2005)
+	- only GenericPrincipal from all other realms are handled well.
+    - change JAASRealm and UserDatabaseRealm that also used GenericPrincipal
+5.5.10 (pero)
+- Cluster config at engine level (user request 06/05)
+	 Register a cluster infrastructur for many vhosts
+	 configure backup systems!
+	 Add Cluster Element to digister		
+- add mapping sender mapping properties file (IDataSenderFactory)
+	- let advanced people eaiser implemented there own sender mode
+- We register different application with same name from different host?
+	SimpleTcpManager register manager with app name + hostname when Cluster is configured as Engine element.
+- Configured DeltaManager inside context
+	- SimpleTcpCluster setProperty and transferproperty reflect changes only to defaultMode managers
+    - Look inside SimpleTcpCluster.addManager and DeltaManager.start?
+- Session serialization eat memory but now we can send session messages with blocks...
+	When all sessions serialze after GET_ALL_SESSION is received following works
+	- find all sessions
+	- serialize a block or all sessions as byte array
+	- serialize the complete SessionMessageImpl to transfer message
+- WaitForAck mode and resend probleme
+   - Now message creator can configure resend and compress mode!
+- Add a default simple cluster config with good defaults and only
+  one cluster element inside server.xml. Setup with fastasyncmode.
+  Service Elements
+  	ReplicationTransmitter,
+  	SocketReplicationListener,
+  	McastService,
+  	ClusterSessionListener
+  	ReplicationValve
+  You can change property setting with SimpleTcpCluster prefix "sender.XXX, receiver.XXX, valve.XXX, listener.XXX, service.XXX"	
+- Fix resend GET_ALL_SESSIONS when wait ACK failed at receiver side
+- Fix that ClusterValve not remove when cluster stops 
+- Set timestamp only at first time inside SessionMessageImpl
+- Set timestamp from findsessions when handling GET_ALL_SESSION
+    - Set this timestamp to all SEND_SESSION_DATA and TRANSFER Complete messages
+    - Drop all received message inside GET_ALL_SESSION message queue (DeltaManager)    
+
+- Mcast Service as JMX MBean (change cluster domain at runtime)    
+- send cluster domain with mcast ping
+    - With sendClusterDomainOnly=true only session message from same domain are received
+    - Session only replicated to members from same domain, with sendClusterDomainOnly=false
+      at Sender (ReplicationTransmitter) session messages send to all members.
+    - GET ALL Session send to first member inside same cluster domain
+- better restart szenario at DeltaManager after failure restart (java service wrapper).
+   queue all other session events
+   as STATE Transfer Complete is received, dequeue all received sessions messages.   
+- restructure methods at DeltaManager
+- extract handleXXS methods for better DeltaManager subclassing.
+- split big get all sessions from one server into blocks of sessions and separate STATE Transfer message!
+- no complete sync sessions when GET ALL Sessions event is received.
+- add JMX API for ClusteRreceiver
+- ClusterReceiver is now Callback when message is received
+- SimpleTcpCluster only receive ClusterMessage (API change)
+       Redesign SimpleTcpCluster message receiving to ClusterReceiverBase:
+          - optimized data uncompressed
+          - better extendablity
+          - XByteBuffer only buffer bytes and don't uncompress.
+          - Add receiver JMX stats with new attribute 'Receiver.doReceivedProcessingStats'   
+          - optimized createManager and addManager that also can configured normal StandardManager 
+            to use cluster message transfer without replication.
+- add support to dynamic property transfer from SimpleTcpCluster to the Manager
+    like ReplicationTransmitter
+        All manager attributes can be configured:
+          - expireSessionsOnShutdown (false)
+          - notifySessionListenersOnReplication (true)
+          - notifyListenersOnReplication (true)
+          - maxActiveSessions (-1)
+          - timeoutAllSession (60 sec)
+          - sessionIdLength (16)
+          - processExpiresFrequency (6 - exipre all six engine background periodic event (60 sec))
+          - algorithm (MD5)
+          - entropy
+          - randomFile
+          - randomClass
+- Setup the cluster without SessionReplication Manager
+         Only a message bus.
+         Configure the bus with you ClusterListener and valves and a StandardManager         
+- reduce cpu and memory consume (Receiver)
+    - set new compress sender flag at default=false ( < CPU usage)
+    - Make compact algo 
+        currently message receive data is split at XbyteBuffer#extractPackage and
+        SimpleTcpCluster#messageDataReceived     
+- reduce memory and cpu consume (send message)
+    - set new compress sender flag at default=false ( < CPU usage)
+    - don't copy the buffer to add message header
+        transfer this from SimpleTcpCluster to DataSender pushMessage
+        successfull refactored
+    - make it possible that a subclass crypt the transfered messages
+       sub class ReplicationTransmitter and override createMessageData
+    - don't copy START and END Header for every message, instead send dirctly and DataSender.writeData.   
+- Add a flag for replicated attribute events, to enable or disable them 
+     Now can configued with notifyListenersOnReplication=false at SimpleTCPCluster
+     Also can drop HttpSessionLsitener events
+         can configued with notifySessionListenersOnReplication=false at SimpleTCPCluster
+- Refactoring DeltaManager
+- Transfer attributes from Cluster config to DeltaManager
+- Fix at 5.5.9 cluster hang bug! 
+- Add more Valve to direct cluster config
+- Add Lifecycle Listener support to direct cluster config
+- Add ClusterListener support to direct cluster config
+- Add new SocketReplicationListener
+- Add Stats to DeltaManager
+
+5.5.9  (pero)
+- JMX friendly
+    pero:  Add some MBeanSupport to SimpleTCPCluster, ReplicationTransmitter and Senders
+- Add Keep Alive and WaitForAck at async mode implementation.
+       Make this feature configurable to Sender element at server.xml
+       Is include with 5.5.8
+- Add support to new Async Mode from Rainer Jung
+       Integrated with 5.5.9
+       fastasyncqueue mode
+ 

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/VERSION
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/VERSION	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/VERSION	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,65 @@
+0.9.5.2
+  - made the UniqueId serializable
+0.9.5.1
+  - create a protocol around the multicast packages, so that we can go to nio eventually
+  - corrected tracing
+0.9.5.0
+  - added message tracers
+0.9.4.9
+  - max multicast packet is no roughly 64k instead of 8k
+  - tribes throws an illegal argument exception if the payload added is too large  
+0.9.4.8
+  - fix bug in the NIO sender, it should use flip instead of rewind
+0.9.4.7
+  - release the socket key to the poller before sending the data requests up through the channel
+    this makes receiving data non blocking, even if the application is
+0.9.4.6
+  - fix package processing, the old release was hogging a thread for a single connection, making concurrency not so efficient,
+    this fix uses the thread for one package, then moves on. faster concurrency, and much less memory usage in high stress environments
+0.9.4.4
+  - temporary work around for the threading problem, go directly to max threads
+0.9.4.3
+  - minor fixes to threading and test cases
+0.9.4.2
+  - Huge Performance improvements on the NIOReceiver
+  - revision 418518
+  - worked out the build script to generate versioned jars
+0.9.4.1
+  - fixed bug with the command being transferred but not deserialized
+0.9.4.0
+  - Added Member.getCommand, to separate out internal tribes logic from application payload
+  - when setting payload, the update should get sent immediately
+  - domain name filter, using an interceptor if we wish
+  - major version bump since we are changing the protocol for member
+0.9.3.2
+  - MemberImpl.toString has a limit on the size it prints out
+0.9.3.1
+  - fixed a bug in the startup sequence. If the local member gets created, then we need to set the unique Id
+  - default multicast packet can be 8kb
+0.9.3.0
+  - fixed bugs
+0.9.2.9
+  - jdk1.4 support for buffer pools
+0.9.2.8
+  - finished coordinator and bug fixes in the coordinator and ChannelReceiver
+0.9.2.6
+  - first version of the NonBlockingCoordinator implemented
+  - org.apache.catalina.tribes.demos.CoordinationDemo implemented
+0.9.2.5
+  - minor updates
+0.9.2.4
+  - leader election, work in progress
+0.9.2.3
+  - Keep alive pings for AbstractReplicatedMap
+  - Improved TcpFailureDetector
+0.9.2.2
+  - removed getMemberProperties from the membership interface
+0.9.2.1
+ - remove domain from membership
+ - documentation updates
+0.9.2.0
+ - message dispatch interceptor is included if no other interceptors are added so that
+   async messaging is enabled in the default stack
+0.9.1.2
+ - 1.4 compatibility
+0.9.1.1

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/build.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/build.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/build.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,151 @@
+<project name="GroupCom" default="dist" basedir=".">
+
+
+  <!-- ===================== Initialize Property Values =================== -->
+
+  <property file="../../../build.properties" />
+  <property file="../../../build/build.properties" />
+  <property file="../../../build/build.properties.default" />
+
+  <!-- Build Defaults -->
+  <property name="catalina.home"  location="../.."/>
+  <property name="catalina.build" location="../../../build/build"/>
+  <property name="groupcom.build"  value="${catalina.home}/modules/groupcom/build"/>
+  <property name="groupcom.dist"   value="${catalina.home}/modules/groupcom/dist"/>
+
+    <!-- Construct Catalina classpath -->
+  <path id="groupcom.classpath">
+    <pathelement location="${catalina.build}/server/lib/catalina.jar"/>
+    <pathelement location="${catalina.build}/server/lib/tomcat-util.jar"/>
+    <pathelement location="${commons-modeler.jar}"/>
+    <pathelement location="${commons-logging.jar}"/>
+    <pathelement location="${jmx.jar}"/>
+    <pathelement location="${catalina.build}/common/lib/servlet-api.jar"/>
+  </path>
+
+    <!-- Source path -->
+  <path id="javadoc.sourcepath">
+    <pathelement location="src/share"/>
+  </path>
+
+
+  <!-- =================== BUILD: Set compile flags ======================= -->
+  <target name="flags">
+    <!-- JDK flags -->
+    <available property="jdk.1.2.present" classname="java.util.HashMap" />
+    <available property="jdk.1.3.present" 
+     classname="java.lang.reflect.Proxy" />
+    <available property="jdk.1.4.present" classname="java.nio.Buffer" />
+  </target>
+
+
+  <!-- =================== BUILD: Set compile flags ======================= -->
+  <target name="flags.display" depends="flags" unless="flags.hide">
+
+    <echo message="--- Build environment for Catalina ---" />
+
+    <echo message="If ${property_name} is displayed, then the property is not set)" />
+
+    <echo message="--- Build options ---" />
+    <echo message="full.dist=${full.dist}" />
+    <echo message="build.sysclasspath=${build.sysclasspath}" />
+    <echo message="compile.debug=${compile.debug}" />
+    <echo message="compile.deprecation=${compile.deprecation}" />
+    <echo message="compile.optimize=${compile.optimize}" />
+
+    <echo message="--- Ant Flags ---" />
+    <echo message="&lt;style&gt; task available (required)=${style.available}" />
+
+    <echo message="--- JDK ---" />
+    <echo message="jdk.1.2.present=${jdk.1.2.present}" />
+    <echo message="jdk.1.3.present=${jdk.1.3.present}" />
+    <echo message="jdk.1.4.present=${jdk.1.4.present}" />
+
+  </target>
+
+  <!-- =================== BUILD: Create Directories ====================== -->
+  <target name="build-prepare">
+    <mkdir dir="${catalina.build}"/>
+    <mkdir dir="${catalina.build}/classes"/>
+    <mkdir dir="${groupcom.dist}"/>
+  </target>
+
+
+  
+
+  <!-- ================ BUILD: Compile Catalina Components ================ -->
+  
+  <target name="build-catalina-groupcom" depends="build-prepare">
+    <!-- Compile internal server components -->
+    <javac srcdir="${basedir}/src/share" destdir="${catalina.build}/classes"
+           debug="${compile.debug}" deprecation="${compile.deprecation}"
+           optimize="${compile.optimize}"
+           excludes="**/CVS/**"  	   
+    	>
+        <classpath refid="groupcom.classpath" />
+    </javac>
+    <copy file="${basedir}/src/share/org/apache/catalina/tribes/LocalStrings.properties"
+    	  tofile="${catalina.build}/classes/org/apache/catalina/tribes/LocalStrings.properties"/>
+    <copy file="${basedir}/src/share/org/apache/catalina/tribes/transport/LocalStrings.properties"
+    	  tofile="${catalina.build}/classes/org/apache/catalina/tribes/transport/LocalStrings.properties"/>
+    <copy file="${basedir}/src/share/org/apache/catalina/tribes/transport/mbeans-descriptors.xml"
+    	  tofile="${catalina.build}/classes/org/apache/catalina/tribes/transport/mbeans-descriptors.xml"/>
+    <copy file="${basedir}/src/share/org/apache/catalina/tribes/membership/LocalStrings.properties"
+    	  tofile="${catalina.build}/classes/org/apache/catalina/tribes/membership/LocalStrings.properties"/>
+    <copy file="${basedir}/src/share/org/apache/catalina/tribes/membership/mbeans-descriptors.xml"
+     	  tofile="${catalina.build}/classes/org/apache/catalina/tribes/membership/mbeans-descriptors.xml"/>
+   </target>
+
+
+  <!-- ================ BUILD: Create Catalina Javadocs =================== -->
+  <target name="javadoc">
+    <delete dir="${catalina.build}/javadoc"/>
+    <mkdir dir="${catalina.build}/javadoc"/>
+    <javadoc packagenames="org.apache.catalina.*,org.apache.naming.*"
+      classpathref="catalina.classpath"
+      sourcepathref="javadoc.sourcepath"
+      destdir="${catalina.build}/javadoc"
+      author="true"
+      version="true"
+      windowtitle="Catalina Internal API Documentation"
+      doctitle="Catalina API"
+      bottom="Copyright &#169; 2000-2002 Apache Software Foundation.  All Rights Reserved."
+    />
+  </target>
+
+
+  <!-- ======================= BUILD: Clean Directory ===================== -->
+  <target name="build-clean">
+    <delete dir="${catalina.build}"/>
+  </target>
+
+
+  <!-- ==================== BUILD: Rebuild Everything ===================== -->
+
+
+
+
+  <!-- ================ DIST: Create Distribution ========================= -->
+  <target name="dist" depends="build-catalina-groupcom">
+    
+    <jar destfile="${groupcom.dist}/catalina-tribes.jar"
+         basedir="${catalina.build}/classes">
+       <include name="org/apache/catalina/tribes/**" />
+       <exclude name="**/package.html" />
+       <exclude name="**/LocalStrings_*" />
+    </jar>
+  </target>
+
+  <target name="copy" depends="dist" >
+     <copy file="${groupcom.dist}/catalina-tribes.jar" todir="${catalina.build}/server/lib" />
+  </target>
+  
+  <!-- ======================== DIST: Clean Directory ===================== -->
+
+  <target name="clean">
+      <delete dir="${catalina.build}/classes"/>
+  </target>
+  <!-- ====================== Convenient Synonyms ========================= -->
+
+
+</project>

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/doc/faq.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/doc/faq.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/doc/faq.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,21 @@
+<?xml version="1.0"?>
+<!DOCTYPE document [
+  <!ENTITY project SYSTEM "project.xml">
+]>
+<document url="introduction.html">
+
+    &project;
+
+    <properties>
+        <author email="fhanik at apache.org">Filip Hanik</author>
+        <title>Apache Tribes - Frequently Asked Questions</title>
+    </properties>
+
+<body>
+
+
+<section name="Frequently Asked Questions">
+</section>
+</body>
+
+</document>

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/doc/introduction.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/doc/introduction.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/doc/introduction.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,330 @@
+<?xml version="1.0"?>
+<!DOCTYPE document [
+  <!ENTITY project SYSTEM "project.xml">
+]>
+<document url="introduction.html">
+
+    &project;
+
+    <properties>
+        <author email="fhanik at apache.org">Filip Hanik</author>
+        <title>Apache Tribes - Introduction</title>
+    </properties>
+
+<body>
+
+
+<section name="Quick Start">
+
+  <p>Apache Tribes is a group or peer-to-peer communcation framework that enables you to easily connect
+     your remote objects to communicate with each other.
+  </p>
+  <ul>
+    <li>Import: <code>org.apache.catalina.tribes.Channel</code></li>
+    <li>Import: <code>org.apache.catalina.tribes.Member</code></li>
+    <li>Import: <code>org.apache.catalina.tribes.MembershipListener</code></li>
+    <li>Import: <code>org.apache.catalina.tribes.ChannelListener</code></li>
+    <li>Import: <code>org.apache.catalina.tribes.group.GroupChannel</code></li>
+    <li>Create a class that implements: <code>org.apache.catalina.tribes.ChannelListener</code></li>
+    <li>Create a class that implements: <code>org.apache.catalina.tribes.MembershipListener</code></li>
+    <li>Simple class to demonstrate how to send a message:
+      <source>
+        //create a channel
+        Channel myChannel = new GroupChannel();
+
+        //create my listeners
+        ChannelListener msgListener = new MyMessageListener();
+        MembershipListener mbrListener = new MyMemberListener();
+
+        //attach the listeners to the channel
+        myChannel.addMembershipListener(mbrListener);
+        myChannel.addChannelListener(msgListener);
+
+        //start the channel
+        myChannel.start(Channel.DEFAULT);
+
+        //create a message to be sent, message must implement java.io.Serializable
+        //for performance reasons you probably want them to implement java.io.Externalizable
+        Serializable myMsg = new MyMessage();
+
+        //retrieve my current members
+        Member[] group = myChannel.getMembers();
+
+        //send the message
+        channel.send(group,myMsg,Channel.SEND_OPTIONS_DEFAULT);
+      </source>
+    </li>
+  </ul>
+  <p>
+      Simple yeah? There is a lot more to Tribes than we have shown, hopefully the docs will be able
+      to explain more to you. Remember, that we are always interested in suggestions, improvements, bug fixes
+      and anything that you think would help this project.
+  </p>
+  <p>
+      Note: Tribes is currently built for JDK1.5, you can run on JDK1.4 by a small modifications to locks used from the <code>java.util.concurrent</code> package.
+  </p>
+</section>
+
+
+<section name="What is Tribes">
+  <p>
+    Tribes is a messaging framework with group communication abilities. Tribes allows you to send and receive
+    messages over a network, it also allows for dynamic discovery of other nodes in the network.<br/>
+    And that is the short story, it really is as simple as that. What makes Tribes useful and unique will be
+    described in the section below.<br/>
+  </p>
+  <p>
+    The Tribes module was started early 2006 and a small part of the code base comes from the clustering module
+    that has been existing since 2003 or 2004.
+    The current cluster implementation has several short comings and many work arounds were created due
+    to the complexity in group communication. Long story short, what should have been two modules a long time
+    ago, will be now. Tribes takes out the complexity of messaging from the replication module and becomes
+    a fully independent and highly flexible group communication module.<br/>
+  </p>
+  <p>
+    In Tomcat the old <code>modules/cluster</code> has now become <code>modules/groupcom</code>(Tribes) and
+    <code>modules/ha</code> (replication). This will allow development to proceed and let the developers
+    focus on the issues they are actually working on rather than getting boggled down in details of a module
+    they are not interested in. The understanding is that both communication and replication are complex enough,
+    and when trying to develop them in the same module, well you know, it becomes a cluster :)<br/>
+  </p>
+  <p>
+    Tribes allows for guaranteed messaging, and can be customized in many ways. Why is this important?<br/>
+    Well, you as a developer want to know that the messages you are sending are reaching their destination.
+    More than that, if a message doesn't reach its destination, the application on top of Tribes will be notified
+    that the message was never sent, and what node it failed.
+  </p>
+
+</section>
+
+<section name="Why another messaging framework">
+  <p>
+    I am a big fan of reusing code and would never dream of developing something if someone else has already
+    done it and it was available to me and the community I try to serve.<br/>
+    When I did my research to improve the clustering module I was constantly faced with a few obstacles:<br/>
+    1. The framework wasn't flexible enough<br/>
+    2. The framework was licensed in a way that neither I nor the community could use it<br/>
+    3. Several features that I needed were missing<br/>
+    4. Messaging was guaranteed, but no feedback was reported to me<br/>
+    5. The semantics of my message delivery had to be configured before runtime<br/>
+    And the list continues...
+  </p>
+  <p>
+    So I came up with Tribes, to address these issues and other issues that came along.
+    When designing Tribes I wanted to make sure I didn't lose any of the flexibility and
+    delivery semantics that the existing frameworks already delivered. The goal was to create a framework
+    that could do everything that the others already did, but to provide more flexibility for the application
+    developer. In the next section will give you the high level overview of what features tribes offers or will offer.
+  </p>
+</section>
+
+<section name="Feature Overview">
+  <p>
+    To give you an idea of the feature set I will list it out here.
+    Some of the features are not yet completed, if that is the case they are marked accordingly.
+  </p>
+  <p>
+    <b>Pluggable modules</b><br/>
+    Tribes is built using interfaces. Any of the modules or components that are part of Tribes can be swapped out
+    to customize your own Tribes implementation.
+  </p>
+  <p>
+    <b>Guaranteed Messaging</b><br/>
+    In the default implementation of Tribes uses TCP for messaging. TCP already has guaranteed message delivery
+    and flow control built in. I believe that the performance of Java TCP, will outperform an implementation of
+    Java/UDP/flow-control/message guarantee since the logic happens further down the stack.<br/>
+    Tribes supports both non-blocking and blocking IO operations. The recommended setting is to use non blocking
+    as it promotes better parallelism when sending and receiving messages. The blocking implementation is available
+    for those platforms where NIO is still a trouble child.
+  </p>
+  <p>
+    <b>Different Guarantee Levels</b><br/>
+    There are three different levels of delivery guarantee when a message is sent.<br/>
+    <ol>
+      <li>IO Based send guarantee. - fastest, least reliable<br/>
+          This means that Tribes considers the message transfer to be successful
+          if the message was sent to the socket send buffer and accepted.<br/>
+          On blocking IO, this would be <code>socket.getOutputStream().write(msg)</code><br/>
+          On non blocking IO, this would be <code>socketChannel.write()</code>, and the buffer byte buffer gets emptied
+          followed by a <code>socketChannel.read()</code> to ensure the channel still open.
+          The <code>read()</code> has been added since <code>write()</code> will succeed if the connection has been &quot;closed&quot;
+          when using NIO.
+      </li>
+      <li>ACK based. - recommended, guaranteed delivery<br/>
+          When the message has been received on a remote node, an ACK is sent back to the sender,
+          indicating that the message was received successfully.
+      </li>
+      <li>SYNC_ACK based. - guaranteed delivery, guaranteed processed, slowest<br/>
+          When the message has been received on a remote node, the node will process
+          the message and if the message was processed successfully, an ACK is sent back to the sender
+          indicating that the message was received and processed successfully.
+          If the message was received, but processing it failed, an ACK_FAIL will be sent back
+          to the sender. This is a unique feature that adds an incredible amount value to the application
+          developer. Most frameworks here will tell you that the message was delivered, and the application
+          developer has to build in logic on whether the message was actually processed properly by the application
+          on the remote node. If configured, Tribes will throw an exception when it receives an ACK_FAIL
+          and associate that exception with the member that didn't process the message.
+      </li>
+    </ol>
+    You can of course write even more sophisticated guarantee levels, and some of them will be mentioned later on
+    in the documentation. One mentionable level would be a 2-Phase-Commit, where the remote applications don't receive
+    the message until all nodes have received the message. Sort of like a all-or-nothing protocol.
+  </p>
+  <p>
+    <b>Per Message Delivery Attributes</b><br/>
+    Perhaps the feature that makes Tribes stand out from the crowd of group communication frameworks.
+    Tribes enables you to send to decide what delivery semantics a message transfer should have on a per
+    message basis. Meaning, that your messages are not delivered based on some static configuration
+    that remains fixed after the message framework has been started.<br/>
+    To give you an example of how powerful this feature is, I'll try to illustrate it with a simple example.
+    Imagine you need to send 10 different messsages, you could send the the following way:
+    <source>
+      Message_1 - asynchronous and fast, no guarantee required, fire and forget
+      Message_2 - all-or-nothing, either all receivers get it, or none.
+      Message_3 - encrypted and SYNC_ACK based
+      Message_4 - asynchronous, SYNC_ACK and call back when the message is processed on the remote nodes
+      Message_5 - totally ordered, this message should be received in the same order on all nodes that have been
+                  send totally ordered
+      Message_6 - asynchronous and totally ordered
+      Message_7 - RPC message, send a message, wait for all remote nodes to reply before returning
+      Message_8 - RPC message, wait for the first reply
+      Message_9 - RPC message, asynchronous, don't wait for a reply, collect them via a callback
+      Message_10- sent to a member that is not part of this group
+    </source>
+    As you can imagine by now, these are just examples. The number of different semantics you can apply on a
+    per-message-basis is almost limitless. Tribes allows you to set up to 28 different on a message
+    and then configure Tribes to what flag results in what action on the message.<br/>
+    Imagine a shared transactional cache, probably &gt;90% are reads, and the dirty reads should be completely
+    unordered and delivered as fast as possible. But transactional writes on the other hand, have to
+    be ordered so that no cache gets corrupted. With tribes you would send the write messages totally ordered,
+    while the read messages you simple fire to achieve highest throughput.<br/>
+    There are probably better examples on how this powerful feature can be used, so use your imagination and
+    your experience to think of how this could benefit you in your application.
+  </p>
+  <p>
+    <b>Interceptor based message processing</b><br/>
+    Tribes uses a customizable interceptor stack to process messages that are sent and received.<br/>
+    <i>So what, all frameworks have this!</i><br/>
+    Yes, but in Tribes interceptors can react to a message based on the per-message-attributes
+    that are sent runtime. Meaning, that if you add a encryption interceptor that encrypts message
+    you can decide if this interceptor will encrypt all messages, or only certain messages that are decided
+    by the applications running on top of Tribes.<br/>
+    This is how Tribes is able to send some messages totally ordered and others fire and forget style
+    like the example above.<br/>
+    The number of interceptors that are available will keep growing, and we would appreciate any contributions
+    that you might have.
+  </p>
+  <p>
+    <b>Threadless Interceptor stack</b>
+    The interceptor don't require any separate threads to perform their message manipulation.<br/>
+    Messages that are sent will piggy back on the thread that is sending them all the way through transmission.
+    The exception is the <code>MessageDispatchInterceptor</code> that will queue up the message
+    and send it on a separate thread for asynchronous message delivery.
+    Messages received are controlled by a thread pool in the <code>receiver</code> component.<br/>
+    The channel object can send a <code>heartbeat()</code> through the interceptor stack to allow
+    for timeouts, cleanup and other events.<br/>
+    The <code>MessageDispatchInterceptor</code> is the only interceptor that is configured by default.
+  </p>
+  <p>
+    <b>Parallel Delivery</b><br/>
+    Tribes support parallel delivery of messages. Meaning that node_A could send three messages to node_B in
+    parallel. This feature becomes useful when sending messages with different delivery semantics.
+    Otherwise if Message_1 was sent totally ordered, Message_2 would have to wait for that message to complete.<br/>
+    Through NIO, Tribes is also able to send a message to several receivers at the same time on the same thread.
+  </p>
+  <p>
+    <b>Silent Member Messaging</b><br/>
+    With Tribes you are able to send messages to members that are not in your group.
+    So by default, you can already send messages over a wide area network, even though the dynamic discover
+    module today is limited to local area networks by using multicast for dynamic node discovery.
+    Of course, the membership component will be expanded to support WAN memberships in the future.
+    But this is very useful, when you want to hide members from the rest of the group and only communicate with them
+  </p>
+</section>
+
+<section name="Where can I get Tribes">
+  <p>
+    I hope you have enjoyed this short introduction to Tribes. You can download <a href="../apache-tribes.jar">Tribes here</a>
+    or you can download Tribes <a href="../tribes-all.zip">including javadoc and this doc</a>
+  </p>
+
+
+</section>
+
+<!--
+<section name="Cluster Configuration for ReplicationTransmitter">
+<p>
+List of Attributes<br/>
+<table border="1" cellpadding="5">
+
+  <tr>
+    <th align="center" bgcolor="aqua">Attribute</th>
+    <th align="center" bgcolor="aqua">Description</th>
+    <th align="center" bgcolor="aqua">Default value</th>
+  </tr>
+
+  <tr>
+    <td>replicationMode</td>
+    <td>replication mode (<em>synchronous</em>, <em>pooled</em>, <em>asynchronous</em> or <em>fastasyncqueue</em>)
+    </td>
+    <td><code>pooled</code></td>
+  </tr>
+
+  <tr>
+    <td>processSenderFrequency</td>
+    <td>Control the sender keepalive status and drop sender socket connection after timeout is reached.
+    Check every processSenderFrequency value engine background ticks.
+    </td>
+    <td><code>2</code></td>
+  </tr>
+
+  <tr>
+    <td>compress</td>
+    <td>compress bytes before sending (consume memory, but reduce network traffic - GZIP)</td>
+    <td><code>false</code></td>
+  </tr>
+
+  <tr>
+    <td>ackTimeout</td>
+    <td>acknowledge timeout and only usefull it waitForAck is true</td>
+    <td><code>15000</code></td>
+  </tr>
+
+  <tr>
+    <td>waitForAck</td>
+    <td>Wait for ack after data send</td>
+    <td><code>false</code></td>
+  </tr>
+
+  <tr>
+    <td>autoConnect</td>
+    <td>is sender disabled, fork a new socket</td>
+    <td><code>false</code></td>
+  </tr>
+
+  <tr>
+    <td>doTransmitterProcessingStats</td>
+    <td>create processing time stats</td>
+    <td><code>false</code></td>
+  </tr>
+</table>
+</p>
+<p>
+Example to get statistic information, wait for ack at every message send and transfer at compressed mode<br/>
+<source>
+    &lt;Sender
+      className="org.apache.catalina.cluster.tcp.ReplicationTransmitter"
+      replicationMode="fastasyncqueue"
+      compress="true"
+      doTransmitterProcessingStats="true"
+      ackTimeout="15000"
+      waitForAck="true"
+      autoConnect="false"/&gt;
+</source>
+</p>
+</section>
+
+-->
+</body>
+
+</document>

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/doc/leader-election-initiate-election.dia
===================================================================
(Binary files differ)


Property changes on: branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/doc/leader-election-initiate-election.dia
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/doc/leader-election-initiate-election.jpg
===================================================================
(Binary files differ)


Property changes on: branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/doc/leader-election-initiate-election.jpg
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/doc/leader-election-message-arrives.dia
===================================================================
(Binary files differ)


Property changes on: branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/doc/leader-election-message-arrives.dia
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/doc/leader-election-message-arrives.jpg
===================================================================
(Binary files differ)


Property changes on: branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/doc/leader-election-message-arrives.jpg
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/doc/project.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/doc/project.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/doc/project.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<project name="Apache Tribes Documentation - Top Level Directory"
+        href="http://tomcat.apache.org/">
+
+    <title>Apache Tribes - The Tomcat Cluster Communication Module</title>
+
+    <logo href="http://tomcat.apache.org/tomcat-5.5-doc/images/tomcat.gif">Apache Tomcat</logo>
+
+
+    <body>
+
+    <menu name="Links">
+        <item name="Docs Home"             href="index.html"/>
+        <item name="FAQ"                   href="../faq" />
+    </menu>
+
+    <menu name="User Guide">
+        <item name="1) Introduction"        href="introduction.html"/>
+        <item name="2) Setup"               href="setup.html"/>
+        <item name="3) FAQ"                 href="faq.html"/>
+    </menu>
+
+    <menu name="Reference">
+        <item name="Release Notes"         href="RELEASE-NOTES.txt"/>
+        <item name="JavaDoc"               href="../javadoc/index.html"/>
+    </menu>
+
+    <menu name="Apache Tribes Development">
+        <item name="Membership"              href="membership.html"/>
+        <item name="Transport"             href="transport.html"/>
+        <item name="Interceptors"             href="interceptors.html"/>
+        <item name="Status"                href="status.html"/>
+        <item name="Developers"            href="developers.html"/>
+    </menu>
+
+    </body>
+
+</project>

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/doc/setup.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/doc/setup.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/doc/setup.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,21 @@
+<?xml version="1.0"?>
+<!DOCTYPE document [
+  <!ENTITY project SYSTEM "project.xml">
+]>
+<document url="introduction.html">
+
+    &project;
+
+    <properties>
+        <author email="fhanik at apache.org">Filip Hanik</author>
+        <title>Apache Tribes - Configuration</title>
+    </properties>
+
+<body>
+
+
+<section name="Configuration Overview">
+</section>
+</body>
+
+</document>

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/doc/tomcat-docs.xsl
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/doc/tomcat-docs.xsl	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/doc/tomcat-docs.xsl	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,436 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!-- Content Stylesheet for "tomcat-docs" Documentation -->
+
+<!-- $Id: tomcat-docs.xsl 377243 2006-02-12 21:26:03Z markt $ -->
+
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+  version="1.0">
+
+
+  <!-- Output method -->
+  <xsl:output method="html"
+            encoding="iso-8859-1"
+              indent="no"/>
+
+
+  <!-- Defined parameters (overrideable) -->
+  <xsl:param    name="home-name"        select="'The Tomcat Project'"/>
+  <xsl:param    name="home-href"        select="'http://tomcat.apache.org/'"/>
+  <xsl:param    name="home-logo"        select="'/images/tomcat.gif'"/>
+  <xsl:param    name="printer-logo"     select="'/images/printer.gif'"/>
+  <xsl:param    name="apache-logo"      select="'/images/asf-logo.gif'"/>
+  <xsl:param    name="relative-path"    select="'.'"/>
+  <xsl:param    name="void-image"       select="'/images/void.gif'"/>
+  <xsl:param    name="project-menu"     select="'menu'"/>
+  <xsl:param    name="standalone"       select="''"/>
+  <xsl:param    name="buglink"          select="'http://issues.apache.org/bugzilla/show_bug.cgi?id='"/>
+
+  <!-- Defined variables (non-overrideable) -->
+  <xsl:variable name="body-bg"          select="'#ffffff'"/>
+  <xsl:variable name="body-fg"          select="'#000000'"/>
+  <xsl:variable name="body-link"        select="'#525D76'"/>
+  <xsl:variable name="banner-bg"        select="'#525D76'"/>
+  <xsl:variable name="banner-fg"        select="'#ffffff'"/>
+  <xsl:variable name="sub-banner-bg"    select="'#828DA6'"/>
+  <xsl:variable name="sub-banner-fg"    select="'#ffffff'"/>
+  <xsl:variable name="source-color"     select="'#023264'"/>
+  <xsl:variable name="attributes-color" select="'#023264'"/>
+  <xsl:variable name="table-th-bg"      select="'#039acc'"/>
+  <xsl:variable name="table-td-bg"      select="'#a0ddf0'"/>
+
+  <!-- Process an entire document into an HTML page -->
+  <xsl:template match="document">
+  <xsl:variable name="project"
+              select="document('project.xml')/project"/>
+    <html>
+    <head>
+    <title><xsl:value-of select="project/title"/> - <xsl:value-of select="properties/title"/></title>
+    <xsl:for-each select="properties/author">
+      <xsl:variable name="name">
+        <xsl:value-of select="."/>
+      </xsl:variable>
+      <xsl:variable name="email">
+        <xsl:value-of select="@email"/>
+      </xsl:variable>
+      <meta name="author" value="{$name}"/>
+      <meta name="email" value="{$email}"/>
+    </xsl:for-each>
+    </head>
+
+    <body bgcolor="{$body-bg}" text="{$body-fg}" link="{$body-link}"
+          alink="{$body-link}" vlink="{$body-link}">
+
+    <table border="0" width="100%" cellspacing="0">
+
+      <xsl:comment>PAGE HEADER</xsl:comment>
+      <tr>
+        <td>
+        <xsl:if test="project/logo">
+          <xsl:variable name="alt">
+            <xsl:value-of select="project/logo"/>
+          </xsl:variable>
+          <xsl:variable name="home">
+            <xsl:value-of select="project/@href"/>
+          </xsl:variable>
+          <xsl:variable name="src">
+            <!--<xsl:value-of select="$relative-path"/>--><xsl:value-of select="project/logo/@href"/>
+          </xsl:variable>
+
+          <xsl:comment>PROJECT LOGO</xsl:comment>
+          <a href="{$home}">
+            <img src="{$src}" align="right" alt="{$alt}" border="0"/>
+          </a>
+        </xsl:if>
+        </td>
+        <td>
+          <font face="arial,helvetica,sanserif">
+            <h1><xsl:value-of select="$project/title"/></h1>
+          </font>
+        </td>
+        <td>
+          <xsl:comment>APACHE LOGO</xsl:comment>
+          <xsl:variable name="src">
+            <xsl:value-of select="$relative-path"/><xsl:value-of select="$apache-logo"/>
+          </xsl:variable>
+          <a href="http://www.apache.org/">
+            <img src="http://tomcat.apache.org/tomcat-5.5-doc/images/asf-logo.gif" align="right" alt="Apache Logo" border="0"/>
+          </a>
+        </td>
+      </tr>
+    </table>
+
+    <table border="0" width="100%" cellspacing="4">
+
+      <xsl:comment>HEADER SEPARATOR</xsl:comment>
+      <tr>
+        <td colspan="2">
+          <hr noshade="noshade" size="1"/>
+        </td>
+      </tr>
+
+      <tr>
+
+        <!-- Don't generate a menu if styling printer friendly docs -->
+        <xsl:if test="$project-menu = 'menu'">
+          <xsl:comment>LEFT SIDE NAVIGATION</xsl:comment>
+          <td width="20%" valign="top" nowrap="true">
+            <xsl:apply-templates select="project/body/menu"/>
+          </td>
+        </xsl:if>
+
+        <xsl:comment>RIGHT SIDE MAIN BODY</xsl:comment>
+        <td width="80%" valign="top" align="left">
+          <table border="0" width="100%" cellspacing="4">
+            <tr>
+              <td align="left" valign="top">
+                <h1><xsl:value-of select="project/title"/></h1>
+                <h2><xsl:value-of select="properties/title"/></h2>
+              </td>
+              <td align="right" valign="top" nowrap="true">
+                <!-- Add the printer friendly link for docs with a menu -->
+                <xsl:if test="$project-menu = 'menu'">
+                  <xsl:variable name="src">
+                    <xsl:value-of select="$relative-path"/><xsl:value-of select="$printer-logo"/>
+                  </xsl:variable>
+                  <xsl:variable name="url">
+                    <xsl:value-of select="/document/@url"/>
+                  </xsl:variable>
+                  <small>
+                    <a href="printer/{$url}">
+                      <img src="{$src}" border="0" alt="Printer Friendly Version"/>
+                      <br />print-friendly<br />version
+                    </a>
+                  </small>
+                </xsl:if>
+                <xsl:if test="$project-menu != 'menu'">
+                  <xsl:variable name="void">
+                    <xsl:value-of select="$relative-path"/><xsl:value-of select="$void-image"/>
+                    </xsl:variable>
+                  <img src="{$void}" width="1" height="1" vspace="0" hspace="0" border="0"/>
+                </xsl:if>
+              </td>
+            </tr>
+          </table>
+          <xsl:apply-templates select="body/section"/>
+        </td>
+
+      </tr>
+
+      <xsl:comment>FOOTER SEPARATOR</xsl:comment>
+      <tr>
+        <td colspan="2">
+          <hr noshade="noshade" size="1"/>
+        </td>
+      </tr>
+
+      <xsl:comment>PAGE FOOTER</xsl:comment>
+      <tr><td colspan="2">
+        <div align="center"><font color="{$body-link}" size="-1"><em>
+        Copyright &#169; 1999-2006, Apache Software Foundation
+        </em></font></div>
+      </td></tr>
+
+    </table>
+    </body>
+    </html>
+
+  </xsl:template>
+
+
+  <!-- Process a menu for the navigation bar -->
+  <xsl:template match="menu">
+    <p><strong><xsl:value-of select="@name"/></strong></p>
+    <ul>
+      <xsl:apply-templates select="item"/>
+    </ul>
+  </xsl:template>
+
+
+  <!-- Process a menu item for the navigation bar -->
+  <xsl:template match="item">
+    <xsl:variable name="href">
+      <xsl:value-of select="@href"/>
+    </xsl:variable>
+    <li><a href="{$href}"><xsl:value-of select="@name"/></a></li>
+  </xsl:template>
+
+
+  <!-- Process a documentation section -->
+  <xsl:template match="section">
+    <xsl:variable name="name">
+      <xsl:value-of select="@name"/>
+    </xsl:variable>
+    <table border="0" cellspacing="0" cellpadding="2">
+      <!-- Section heading -->
+      <tr><td bgcolor="{$banner-bg}">
+          <font color="{$banner-fg}" face="arial,helvetica.sanserif">
+          <a name="{$name}">
+          <strong><xsl:value-of select="@name"/></strong></a></font>
+      </td></tr>
+      <!-- Section body -->
+      <tr><td><blockquote>
+        <xsl:apply-templates/>
+      </blockquote></td></tr>
+    </table>
+  </xsl:template>
+
+
+  <!-- Process a documentation subsection -->
+  <xsl:template match="subsection">
+    <xsl:variable name="name">
+      <xsl:value-of select="@name"/>
+    </xsl:variable>
+    <table border="0" cellspacing="0" cellpadding="2">
+      <!-- Subsection heading -->
+      <tr><td bgcolor="{$sub-banner-bg}">
+          <font color="{$sub-banner-fg}" face="arial,helvetica.sanserif">
+          <a name="{$name}">
+          <strong><xsl:value-of select="@name"/></strong></a></font>
+      </td></tr>
+      <!-- Subsection body -->
+      <tr><td><blockquote>
+        <xsl:apply-templates/>
+      </blockquote></td></tr>
+    </table>
+  </xsl:template>
+
+
+  <!-- Process a source code example -->
+  <xsl:template match="source">
+    <xsl:variable name="void">
+      <xsl:value-of select="$relative-path"/><xsl:value-of select="$void-image"/>
+    </xsl:variable>
+    <div align="left">
+      <table cellspacing="4" cellpadding="0" border="0">
+        <tr>
+          <td bgcolor="{$source-color}" width="1" height="1">
+            <img src="{$void}" width="1" height="1" vspace="0" hspace="0" border="0"/>
+          </td>
+          <td bgcolor="{$source-color}" height="1">
+            <img src="{$void}" width="1" height="1" vspace="0" hspace="0" border="0"/>
+          </td>
+          <td bgcolor="{$source-color}" width="1" height="1">
+            <img src="{$void}" width="1" height="1" vspace="0" hspace="0" border="0"/>
+          </td>
+        </tr>
+        <tr>
+          <td bgcolor="{$source-color}" width="1">
+            <img src="{$void}" width="1" height="1" vspace="0" hspace="0" border="0"/>
+          </td>
+          <td bgcolor="#ffffff" height="1"><pre>
+            <xsl:value-of select="."/>
+          </pre></td>
+          <td bgcolor="{$source-color}" width="1">
+            <img src="{$void}" width="1" height="1" vspace="0" hspace="0" border="0"/>
+          </td>
+        </tr>
+        <tr>
+          <td bgcolor="{$source-color}" width="1" height="1">
+            <img src="{$void}" width="1" height="1" vspace="0" hspace="0" border="0"/>
+          </td>
+          <td bgcolor="{$source-color}" height="1">
+            <img src="{$void}" width="1" height="1" vspace="0" hspace="0" border="0"/>
+          </td>
+          <td bgcolor="{$source-color}" width="1" height="1">
+            <img src="{$void}" width="1" height="1" vspace="0" hspace="0" border="0"/>
+          </td>
+        </tr>
+      </table>
+    </div>
+  </xsl:template>
+
+
+  <!-- Process an attributes list with nested attribute elements -->
+  <xsl:template match="attributes">
+    <table border="1" cellpadding="5">
+      <tr>
+        <th width="15%" bgcolor="{$attributes-color}">
+          <font color="#ffffff">Attribute</font>
+        </th>
+        <th width="85%" bgcolor="{$attributes-color}">
+          <font color="#ffffff">Description</font>
+        </th>
+      </tr>
+      <xsl:for-each select="attribute">
+        <tr>
+          <td align="left" valign="center">
+            <xsl:if test="@required = 'true'">
+              <strong><code><xsl:value-of select="@name"/></code></strong>
+            </xsl:if>
+            <xsl:if test="@required != 'true'">
+              <code><xsl:value-of select="@name"/></code>
+            </xsl:if>
+          </td>
+          <td align="left" valign="center">
+            <xsl:apply-templates/>
+          </td>
+        </tr>
+      </xsl:for-each>
+    </table>
+  </xsl:template>
+
+  <!-- Fix relative links in printer friendly versions of the docs -->
+  <xsl:template match="a">
+    <xsl:variable name="href" select="@href"/>
+    <xsl:choose>
+      <xsl:when test="$standalone = 'standalone'">
+        <xsl:apply-templates/>
+      </xsl:when>
+      <xsl:when test="$project-menu != 'menu' and starts-with(@href,'../')">
+        <a href="../{$href}"><xsl:apply-templates/></a>
+      </xsl:when>
+      <xsl:when test="$project-menu != 'menu' and starts-with(@href,'./') and contains(substring(@href,3),'/')">
+        <a href=".{$href}"><xsl:apply-templates/></a>
+      </xsl:when>
+      <xsl:when test="$project-menu != 'menu' and not(contains(@href,'//')) and not(starts-with(@href,'/')) and not(starts-with(@href,'#')) and contains(@href,'/')">
+        <a href="../{$href}"><xsl:apply-templates/></a>
+      </xsl:when>
+      <xsl:when test="$href != ''">
+        <a href="{$href}"><xsl:apply-templates/></a>
+      </xsl:when>
+      <xsl:otherwise>
+        <xsl:variable name="name" select="@name"/>
+        <a name="{$name}"><xsl:apply-templates/></a>
+      </xsl:otherwise>
+    </xsl:choose>
+  </xsl:template>
+
+  <!-- Changelog related tags -->
+  <xsl:template match="changelog">
+    <table border="0" cellpadding="2" cellspacing="2">
+      <xsl:apply-templates/>
+    </table>
+  </xsl:template>
+
+  <xsl:template match="changelog/add">
+    <tr>
+      <xsl:variable name="src"><xsl:value-of select="$relative-path"/>/images/add.gif</xsl:variable>
+      <td><img alt="add" class="icon" src="{$src}"/></td>
+      <td><xsl:apply-templates/></td>
+    </tr>
+  </xsl:template>
+
+  <xsl:template match="changelog/update">
+    <tr>
+      <xsl:variable name="src"><xsl:value-of select="$relative-path"/>/images/update.gif</xsl:variable>
+      <td><img alt="update" class="icon" src="{$src}"/></td>
+      <td><xsl:apply-templates/></td>
+    </tr>
+  </xsl:template>
+
+  <xsl:template match="changelog/design">
+    <tr>
+      <xsl:variable name="src"><xsl:value-of select="$relative-path"/>/images/design.gif</xsl:variable>
+      <td><img alt="design" class="icon" src="{$src}"/></td>
+      <td><xsl:apply-templates/></td>
+    </tr>
+  </xsl:template>
+
+  <xsl:template match="changelog/docs">
+    <tr>
+      <xsl:variable name="src"><xsl:value-of select="$relative-path"/>/images/docs.gif</xsl:variable>
+      <td><img alt="docs" class="icon" src="{$src}"/></td>
+      <td><xsl:apply-templates/></td>
+    </tr>
+  </xsl:template>
+
+  <xsl:template match="changelog/fix">
+    <tr>
+      <xsl:variable name="src"><xsl:value-of select="$relative-path"/>/images/fix.gif</xsl:variable>
+      <td><img alt="fix" class="icon" src="{$src}"/></td>
+      <td><xsl:apply-templates/></td>
+    </tr>
+  </xsl:template>
+
+  <xsl:template match="changelog/scode">
+    <tr>
+      <xsl:variable name="src"><xsl:value-of select="$relative-path"/>/images/code.gif</xsl:variable>
+      <td><img alt="code" class="icon" src="{$src}"/></td>
+      <td><xsl:apply-templates/></td>
+    </tr>
+  </xsl:template>
+
+  <!-- Process an attributes list with nested attribute elements -->
+  <xsl:template match="status">
+    <table border="1" cellpadding="5">
+      <tr>
+        <th width="15%" bgcolor="{$attributes-color}">
+          <font color="#ffffff">Priority</font>
+        </th>
+        <th width="50%" bgcolor="{$attributes-color}">
+          <font color="#ffffff">Action Item</font>
+        </th>
+        <th width="25%" bgcolor="{$attributes-color}">
+          <font color="#ffffff">Volunteers</font>
+        </th>
+        <xsl:for-each select="item">
+        <tr>
+          <td align="left" valign="center">
+            <xsl:value-of select="@priority"/>
+          </td>
+          <td align="left" valign="center">
+            <xsl:apply-templates/>
+          </td>
+          <td align="left" valign="center">
+            <xsl:value-of select="@owner"/>
+          </td>
+        </tr>
+        </xsl:for-each>
+      </tr>
+    </table>
+  </xsl:template>
+
+  <!-- Link to a bug report -->
+  <xsl:template match="bug">
+      <xsl:variable name="link"><xsl:value-of select="$buglink"/><xsl:value-of select="text()"/></xsl:variable>
+      <a href="{$link}"><xsl:apply-templates/></a>
+  </xsl:template>
+
+  <!-- Process everything else by just passing it through -->
+  <xsl:template match="*|@*">
+    <xsl:copy>
+      <xsl:apply-templates select="@*|*|text()"/>
+    </xsl:copy>
+  </xsl:template>
+
+</xsl:stylesheet>

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/etc/cluster-server.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/etc/cluster-server.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/etc/cluster-server.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,394 @@
+<!-- Example Server Configuration File -->
+<!-- Note that component elements are nested corresponding to their
+     parent-child relationships with each other -->
+
+<!-- A "Server" is a singleton element that represents the entire JVM,
+     which may contain one or more "Service" instances.  The Server
+     listens for a shutdown command on the indicated port.
+
+     Note:  A "Server" is not itself a "Container", so you may not
+     define subcomponents such as "Valves" or "Loggers" at this level.
+ -->
+
+<Server port="7005" shutdown="SHUTDOWN">
+
+  <!-- Comment these entries out to disable JMX MBeans support used for the 
+       administration web application -->
+  <Listener className="org.apache.catalina.core.AprLifecycleListener" />
+  <Listener className="org.apache.catalina.mbeans.ServerLifecycleListener" />
+  <Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" />
+  <Listener className="org.apache.catalina.storeconfig.StoreConfigLifecycleListener"/>
+
+  <!-- Global JNDI resources -->
+  <GlobalNamingResources>
+
+    <!-- Test entry for demonstration purposes -->
+    <Environment name="simpleValue" type="java.lang.Integer" value="30"/>
+
+    <!-- Editable user database that can also be used by
+         UserDatabaseRealm to authenticate users -->
+    <Resource name="UserDatabase" auth="Container"
+              type="org.apache.catalina.UserDatabase"
+       description="User database that can be updated and saved"
+           factory="org.apache.catalina.users.MemoryUserDatabaseFactory"
+          pathname="conf/tomcat-users.xml" />
+
+  </GlobalNamingResources>
+
+  <!-- A "Service" is a collection of one or more "Connectors" that share
+       a single "Container" (and therefore the web applications visible
+       within that Container).  Normally, that Container is an "Engine",
+       but this is not required.
+
+       Note:  A "Service" is not itself a "Container", so you may not
+       define subcomponents such as "Valves" or "Loggers" at this level.
+   -->
+
+  <!-- Define the Tomcat Stand-Alone Service -->
+  <Service name="Catalina">
+
+    <!-- A "Connector" represents an endpoint by which requests are received
+         and responses are returned.  Each Connector passes requests on to the
+         associated "Container" (normally an Engine) for processing.
+
+         By default, a non-SSL HTTP/1.1 Connector is established on port 8080.
+         You can also enable an SSL HTTP/1.1 Connector on port 8443 by
+         following the instructions below and uncommenting the second Connector
+         entry.  SSL support requires the following steps (see the SSL Config
+         HOWTO in the Tomcat 5 documentation bundle for more detailed
+         instructions):
+         * If your JDK version 1.3 or prior, download and install JSSE 1.0.2 or
+           later, and put the JAR files into "$JAVA_HOME/jre/lib/ext".
+         * Execute:
+             %JAVA_HOME%\bin\keytool -genkey -alias tomcat -keyalg RSA (Windows)
+             $JAVA_HOME/bin/keytool -genkey -alias tomcat -keyalg RSA  (Unix)
+           with a password value of "changeit" for both the certificate and
+           the keystore itself.
+
+         By default, DNS lookups are enabled when a web application calls
+         request.getRemoteHost().  This can have an adverse impact on
+         performance, so you can disable it by setting the
+         "enableLookups" attribute to "false".  When DNS lookups are disabled,
+         request.getRemoteHost() will return the String version of the
+         IP address of the remote client.
+    -->
+
+    <!-- Define a non-SSL HTTP/1.1 Connector on port 8080 -->
+    <Connector port="7080" maxHttpHeaderSize="8192"
+               maxThreads="150" minSpareThreads="25" maxSpareThreads="75"
+               enableLookups="false" redirectPort="8443" acceptCount="100"
+               connectionTimeout="20000" disableUploadTimeout="true" />
+    <!-- Note : To disable connection timeouts, set connectionTimeout value
+     to 0 -->
+	
+	<!-- Note : To use gzip compression you could set the following properties :
+	
+			   compression="on" 
+			   compressionMinSize="2048" 
+			   noCompressionUserAgents="gozilla, traviata" 
+			   compressableMimeType="text/html,text/xml"
+	-->
+
+    <!-- Define a SSL HTTP/1.1 Connector on port 8443 -->
+    <!--
+    <Connector port="8443" maxHttpHeaderSize="8192"
+               maxThreads="150" minSpareThreads="25" maxSpareThreads="75"
+               enableLookups="false" disableUploadTimeout="true"
+               acceptCount="100" scheme="https" secure="true"
+               clientAuth="false" sslProtocol="TLS" />
+    -->
+
+    <!-- Define an AJP 1.3 Connector on port 8009 -->
+    <Connector port="7009" 
+               enableLookups="false" redirectPort="8443" protocol="AJP/1.3" />
+
+    <!-- Define a Proxied HTTP/1.1 Connector on port 8082 -->
+    <!-- See proxy documentation for more information about using this. -->
+    <!--
+    <Connector port="7082" 
+               maxThreads="150" minSpareThreads="25" maxSpareThreads="75"
+               enableLookups="false" acceptCount="100" connectionTimeout="20000"
+               proxyPort="80" disableUploadTimeout="true" />
+    -->
+
+    <!-- An Engine represents the entry point (within Catalina) that processes
+         every request.  The Engine implementation for Tomcat stand alone
+         analyzes the HTTP headers included with the request, and passes them
+         on to the appropriate Host (virtual host). -->
+
+    <!-- You should set jvmRoute to support load-balancing via AJP ie :
+    <Engine name="Standalone" defaultHost="localhost" jvmRoute="jvm1">         
+    --> 
+         
+    <!-- Define the top level container in our container hierarchy -->
+    <Engine name="Catalina" defaultHost="localhost">
+
+      <!-- The request dumper valve dumps useful debugging information about
+           the request headers and cookies that were received, and the response
+           headers and cookies that were sent, for all requests received by
+           this instance of Tomcat.  If you care only about requests to a
+           particular virtual host, or a particular application, nest this
+           element inside the corresponding <Host> or <Context> entry instead.
+
+           For a similar mechanism that is portable to all Servlet 2.4
+           containers, check out the "RequestDumperFilter" Filter in the
+           example application (the source for this filter may be found in
+           "$CATALINA_HOME/webapps/examples/WEB-INF/classes/filters").
+
+           Request dumping is disabled by default.  Uncomment the following
+           element to enable it. -->
+      <!--
+      <Valve className="org.apache.catalina.valves.RequestDumperValve"/>
+      -->
+
+      <!-- Because this Realm is here, an instance will be shared globally -->
+
+      <!-- This Realm uses the UserDatabase configured in the global JNDI
+           resources under the key "UserDatabase".  Any edits
+           that are performed against this UserDatabase are immediately
+           available for use by the Realm.  -->
+      <Realm className="org.apache.catalina.realm.UserDatabaseRealm"
+             resourceName="UserDatabase"/>
+
+      <!-- Comment out the old realm but leave here for now in case we
+           need to go back quickly -->
+      <!--
+      <Realm className="org.apache.catalina.realm.MemoryRealm" />
+      -->
+
+      <!-- Replace the above Realm with one of the following to get a Realm
+           stored in a database and accessed via JDBC -->
+
+      <!--
+      <Realm  className="org.apache.catalina.realm.JDBCRealm"
+             driverName="org.gjt.mm.mysql.Driver"
+          connectionURL="jdbc:mysql://localhost/authority"
+         connectionName="test" connectionPassword="test"
+              userTable="users" userNameCol="user_name" userCredCol="user_pass"
+          userRoleTable="user_roles" roleNameCol="role_name" />
+      -->
+
+      <!--
+      <Realm  className="org.apache.catalina.realm.JDBCRealm"
+             driverName="oracle.jdbc.driver.OracleDriver"
+          connectionURL="jdbc:oracle:thin:@ntserver:1521:ORCL"
+         connectionName="scott" connectionPassword="tiger"
+              userTable="users" userNameCol="user_name" userCredCol="user_pass"
+          userRoleTable="user_roles" roleNameCol="role_name" />
+      -->
+
+      <!--
+      <Realm  className="org.apache.catalina.realm.JDBCRealm"
+             driverName="sun.jdbc.odbc.JdbcOdbcDriver"
+          connectionURL="jdbc:odbc:CATALINA"
+              userTable="users" userNameCol="user_name" userCredCol="user_pass"
+          userRoleTable="user_roles" roleNameCol="role_name" />
+      -->
+
+      <!-- Define the default virtual host
+           Note: XML Schema validation will not work with Xerces 2.2.
+       -->
+      <Host name="localhost" appBase="webapps"
+       unpackWARs="true" autoDeploy="true"
+       xmlValidation="false" xmlNamespaceAware="false">
+
+        <!-- Defines a cluster for this node,
+             By defining this element, means that every manager will be changed.
+             So when running a cluster, only make sure that you have webapps in there
+             that need to be clustered and remove the other ones.
+             A cluster has the following parameters:
+
+             className = the fully qualified name of the cluster class
+
+             clusterName = a descriptive name for your cluster, can be anything
+
+             mcastAddr = the multicast address, has to be the same for all the nodes
+
+             mcastPort = the multicast port, has to be the same for all the nodes
+             
+             mcastBindAddr = bind the multicast socket to a specific address
+             
+             mcastTTL = the multicast TTL if you want to limit your broadcast
+             
+             mcastSoTimeout = the multicast readtimeout 
+
+             mcastFrequency = the number of milliseconds in between sending a "I'm alive" heartbeat
+
+             mcastDropTime = the number a milliseconds before a node is considered "dead" if no heartbeat is received
+
+             tcpThreadCount = the number of threads to handle incoming replication requests, optimal would be the same amount of threads as nodes 
+
+             tcpListenAddress = the listen address (bind address) for TCP cluster request on this host, 
+                                in case of multiple ethernet cards.
+                                auto means that address becomes
+                                InetAddress.getLocalHost().getHostAddress()
+
+             tcpListenPort = the tcp listen port
+
+             tcpSelectorTimeout = the timeout (ms) for the Selector.select() method in case the OS
+                                  has a wakup bug in java.nio. Set to 0 for no timeout
+
+             printToScreen = true means that managers will also print to std.out
+
+             expireSessionsOnShutdown = true means that 
+
+             useDirtyFlag = true means that we only replicate a session after setAttribute,removeAttribute has been called.
+                            false means to replicate the session after each request.
+                            false means that replication would work for the following piece of code: (only for SimpleTcpReplicationManager)
+                            <%
+                            HashMap map = (HashMap)session.getAttribute("map");
+                            map.put("key","value");
+                            %>
+             replicationMode = can be either 'pooled', 'synchronous' or 'asynchronous'.
+                               * Pooled means that the replication happens using several sockets in a synchronous way. Ie, the data gets replicated, then the request return. This is the same as the 'synchronous' setting except it uses a pool of sockets, hence it is multithreaded. This is the fastest and safest configuration. To use this, also increase the nr of tcp threads that you have dealing with replication.
+                               * Synchronous means that the thread that executes the request, is also the
+                               thread the replicates the data to the other nodes, and will not return until all
+                               nodes have received the information.
+                               * Asynchronous means that there is a specific 'sender' thread for each cluster node,
+                               so the request thread will queue the replication request into a "smart" queue,
+                               and then return to the client.
+                               The "smart" queue is a queue where when a session is added to the queue, and the same session
+                               already exists in the queue from a previous request, that session will be replaced
+                               in the queue instead of replicating two requests. This almost never happens, unless there is a 
+                               large network delay.
+        -->             
+        <!--
+            When configuring for clustering, you also add in a valve to catch all the requests
+            coming in, at the end of the request, the session may or may not be replicated.
+            A session is replicated if and only if all the conditions are met:
+            1. useDirtyFlag is true or setAttribute or removeAttribute has been called AND
+            2. a session exists (has been created)
+            3. the request is not trapped by the "filter" attribute
+
+            The filter attribute is to filter out requests that could not modify the session,
+            hence we don't replicate the session after the end of this request.
+            The filter is negative, ie, anything you put in the filter, you mean to filter out,
+            ie, no replication will be done on requests that match one of the filters.
+            The filter attribute is delimited by ;, so you can't escape out ; even if you wanted to.
+
+            filter=".*\.gif;.*\.js;" means that we will not replicate the session after requests with the URI
+            ending with .gif and .js are intercepted.
+            
+            The deployer element can be used to deploy apps cluster wide.
+            Currently the deployment only deploys/undeploys to working members in the cluster
+            so no WARs are copied upons startup of a broken node.
+            The deployer watches a directory (watchDir) for WAR files when watchEnabled="true"
+            When a new war file is added the war gets deployed to the local instance,
+            and then deployed to the other instances in the cluster.
+            When a war file is deleted from the watchDir the war is undeployed locally 
+            and cluster wide
+        -->
+        
+        <Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"
+                 managerClassName="org.apache.catalina.ha.session.BackupManager"
+                 expireSessionsOnShutdown="false"
+                 notifyListenersOnReplication="true"
+                 channelSendOptions="11"
+                 manager.mapSendOptions="11">
+
+            <Channel className="org.apache.catalina.tribes.group.GroupChannel">
+                <Membership 
+                    className="org.apache.catalina.tribes.membership.McastService"
+                    mcastAddr="228.0.0.4"
+                    mcastPort="45564"
+                    mcastFrequency="500"
+                    mcastDropTime="3000"/>
+
+                <Receiver 
+                    className="org.apache.catalina.tribes.transport.nio.NioReceiver"
+                    tcpListenAddress="auto"
+                    tcpListenPort="4001"
+                    minThreads="6"
+                    maxThreads="25"
+                    rxBufSize="43800"
+                    txBufSize="25188"
+                    autoBind="10"/>
+
+                <Sender
+                    className="org.apache.catalina.tribes.transport.ReplicationTransmitter">
+                    <Transport className="org.apache.catalina.tribes.transport.nio.PooledParallelSender"
+                        rxBufSize="43800"
+                        txBufSize="25188"/>
+                </Sender>
+                <!--
+                <Interceptor className="org.apache.catalina.tribes.group.interceptors.GzipInterceptor"/>
+                <Interceptor className="org.apache.catalina.tribes.group.interceptors.FragmentationInterceptor"/>
+                <Interceptor className="org.apache.catalina.tribes.group.interceptors.OrderInterceptor"/>
+                <Interceptor className="org.apache.catalina.tribes.group.interceptors.MessageDispatchInterceptor"/>
+                -->
+            </Channel>
+            
+            <Valve className="org.apache.catalina.ha.tcp.ReplicationValve"
+                   filter=".*\.gif;.*\.js;.*\.jpg;.*\.png;.*\.htm;.*\.html;.*\.css;.*\.txt;"/>
+                   
+            <Deployer className="org.apache.catalina.ha.deploy.FarmWarDeployer"
+                      tempDir="/tmp/war-temp/"
+                      deployDir="/tmp/war-deploy/"
+                      watchDir="/tmp/war-listen/"
+                      watchEnabled="false"/>
+                      
+            <ClusterListener className="org.apache.catalina.ha.session.ClusterSessionListener"/>
+        </Cluster>
+    
+
+
+
+        <!-- Normally, users must authenticate themselves to each web app
+             individually.  Uncomment the following entry if you would like
+             a user to be authenticated the first time they encounter a
+             resource protected by a security constraint, and then have that
+             user identity maintained across *all* web applications contained
+             in this virtual host. -->
+        <!--
+        <Valve className="org.apache.catalina.authenticator.SingleSignOn" />
+        -->
+
+        <!-- Access log processes all requests for this virtual host.  By
+             default, log files are created in the "logs" directory relative to
+             $CATALINA_HOME.  If you wish, you can specify a different
+             directory with the "directory" attribute.  Specify either a relative
+             (to $CATALINA_HOME) or absolute path to the desired directory.
+        -->
+        <!--
+        <Valve className="org.apache.catalina.valves.AccessLogValve"
+                 directory="logs"  prefix="localhost_access_log." suffix=".txt"
+                 pattern="common" resolveHosts="false"/>
+        -->
+
+        <!-- Access log processes all requests for this virtual host.  By
+             default, log files are created in the "logs" directory relative to
+             $CATALINA_HOME.  If you wish, you can specify a different
+             directory with the "directory" attribute.  Specify either a relative
+             (to $CATALINA_HOME) or absolute path to the desired directory.
+             This access log implementation is optimized for maximum performance,
+             but is hardcoded to support only the "common" and "combined" patterns.
+        -->
+        <!--
+        <Valve className="org.apache.catalina.valves.FastCommonAccessLogValve"
+                 directory="logs"  prefix="localhost_access_log." suffix=".txt"
+                 pattern="common" resolveHosts="false"/>
+        -->
+        <!-- Access log processes all requests for this virtual host.  By
+             default, log files are created in the "logs" directory relative to
+             $CATALINA_HOME.  If you wish, you can specify a different
+             directory with the "directory" attribute.  Specify either a relative
+             (to $CATALINA_HOME) or absolute path to the desired directory.
+             This access log implementation is optimized for maximum performance,
+             but is hardcoded to support only the "common" and "combined" patterns.
+
+             This valve use NIO direct Byte Buffer to asynchornously store the
+             log.
+        -->
+        <!--
+        <Valve className="org.apache.catalina.valves.ByteBufferAccessLogValve"
+                 directory="logs"  prefix="localhost_access_log." suffix=".txt"
+                 pattern="common" resolveHosts="false"/>
+        -->
+
+      </Host>
+
+    </Engine>
+
+  </Service>
+
+</Server>

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/ByteMessage.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/ByteMessage.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/ByteMessage.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,101 @@
+/*
+ * Copyright 1999,2004-2005 The Apache Software Foundation.
+ *
+ * Licensed 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.tribes;
+
+import java.io.Serializable;
+import java.io.Externalizable;
+import java.io.ObjectInput;
+import java.io.IOException;
+import java.io.ObjectOutput;
+
+/**
+ * A byte message is not serialized and deserialized by the channel
+ * instead it is sent as a byte array<br>
+ * By default Tribes uses java serialization when it receives an object
+ * to be sent over the wire. Java serialization is not the most
+ * efficient of serializing data, and Tribes might not even
+ * have access to the correct class loaders to deserialize the object properly.
+ * <br>
+ * The ByteMessage class is a class where the channel when it receives it will
+ * not attempt to perform serialization, instead it will simply stream the <code>getMessage()</code>
+ * bytes.<br>
+ * If you are using multiple applications on top of Tribes you should add some sort of header
+ * so that you can decide with the <code>ChannelListener.accept()</code> whether this message was intended
+ * for you.
+ * @author Filip Hanik
+ * @version $Revision: 304032 $, $Date: 2005-07-27 10:11:55 -0500 (Wed, 27 Jul 2005) $
+ */
+
+public class ByteMessage implements Serializable, Externalizable {
+    /**
+     * Storage for the message to be sent
+     */
+    private byte[] message;
+
+
+    /**
+     * Creates an empty byte message
+     * Constructor also for deserialization
+     */
+    public ByteMessage() {
+    }
+
+    /**
+     * Creates a byte message wit h
+     * @param data byte[] - the message contents
+     */
+    public ByteMessage(byte[] data) {
+        message = data;
+    }
+
+    /**
+     * Returns the message contents of this byte message
+     * @return byte[] - message contents, can be null
+     */
+    public byte[] getMessage() {
+        return message;
+    }
+
+    /**
+     * Sets the message contents of this byte message
+     * @param message byte[]
+     */
+    public void setMessage(byte[] message) {
+        this.message = message;
+    }
+
+    /**
+     * @see java.io.Externalizable#readExternal
+     * @param in ObjectInput
+     * @throws IOException
+     */
+    public void readExternal(ObjectInput in ) throws IOException {
+        int length = in.readInt();
+        message = new byte[length];
+        in.read(message,0,length);
+    }
+
+    /**
+     * @see java.io.Externalizable#writeExternal
+     * @param out ObjectOutput
+     * @throws IOException
+     */
+    public void writeExternal(ObjectOutput out) throws IOException {
+        out.writeInt(message!=null?message.length:0);
+        if ( message!=null ) out.write(message,0,message.length);
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/Channel.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/Channel.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/Channel.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,335 @@
+/*
+ * Copyright 1999,2004-2005 The Apache Software Foundation.
+ * 
+ * Licensed 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.tribes;
+
+import java.io.Serializable;
+
+/**
+ * Channel interface<br>
+ * A channel is a representation of a group of nodes all participating in some sort of
+ * communication with each other.<br>
+ * The channel is the main API class for Tribes, this is essentially the only class
+ * that an application needs to be aware of. Through the channel the application can:<br>
+ * 1. send messages<br>
+ * 2. receive message (by registering a <code>ChannelListener</code><br>
+ * 3. get all members of the group <code>getMembers()</code><br>
+ * 4. receive notifications of members added and members disappeared by
+ *    registerering a <code>MembershipListener</code><br>
+ * <br>
+ * The channel has 5 major components:<br>
+ * 1. Data receiver, with a built in thread pool to receive messages from other peers<br>
+ * 2. Data sender, an implementation for sending data using NIO or java.io<br>
+ * 3. Membership listener,listens for membership broadcasts<br>
+ * 4. Membership broadcaster, broadcasts membership pings.<br>
+ * 5. Channel interceptors, the ability to manipulate messages as they are sent or arrive<br><br>
+ * The channel layout is:
+ * <pre><code>
+ *  ChannelListener_1..ChannelListener_N MembershipListener_1..MembershipListener_N [Application Layer]
+ *            \          \                  /                   /
+ *             \          \                /                   /
+ *              \          \              /                   /
+ *               \          \            /                   /
+ *                \          \          /                   /
+ *                 \          \        /                   /
+ *                  ---------------------------------------
+ *                                  |
+ *                                  |
+ *                               Channel
+ *                                  |
+ *                         ChannelInterceptor_1
+ *                                  |                                               [Channel stack]
+ *                         ChannelInterceptor_N
+ *                                  |
+ *                             Coordinator (implements MessageListener,MembershipListener,ChannelInterceptor)
+ *                          --------------------
+ *                         /        |           \ 
+ *                        /         |            \
+ *                       /          |             \
+ *                      /           |              \
+ *                     /            |               \
+ *           MembershipService ChannelSender ChannelReceiver                        [IO layer]
+ * </code></pre>
+ * 
+ * For example usage @see org.apache.catalina.tribes.group.GroupChannel
+ * @author Filip Hanik
+ * @version $Revision: 304032 $, $Date: 2005-07-27 10:11:55 -0500 (Wed, 27 Jul 2005) $
+ */
+public interface Channel {
+    
+    /**
+     * Start and stop sequences can be controlled by these constants
+     * This allows you to start separate components of the channel <br>
+     * DEFAULT - starts or stops all components in the channel
+     * @see #start(int)
+     * @see #stop(int)
+     */
+    public static final int DEFAULT = 15;
+
+    /**
+     * Start and stop sequences can be controlled by these constants
+     * This allows you to start separate components of the channel <br>
+     * SND_RX_SEQ - starts or stops the data receiver. Start means opening a server socket
+     * in case of a TCP implementation
+     * @see #start(int)
+     * @see #stop(int)
+     */
+    public static final int SND_RX_SEQ = 1;
+
+    /**
+     * Start and stop sequences can be controlled by these constants
+     * This allows you to start separate components of the channel <br>
+     * SND_TX_SEQ - starts or stops the data sender. This should not open any sockets,
+     * as sockets are opened on demand when a message is being sent
+     * @see #start(int)
+     * @see #stop(int)
+     */
+    public static final int SND_TX_SEQ = 2;
+
+    /**
+     * Start and stop sequences can be controlled by these constants
+     * This allows you to start separate components of the channel <br>
+     * MBR_RX_SEQ - starts or stops the membership listener. In a multicast implementation
+     * this will open a datagram socket and join a group and listen for membership messages
+     * members joining
+     * @see #start(int)
+     * @see #stop(int)
+     */
+    public static final int MBR_RX_SEQ = 4;
+
+    /**
+     * Start and stop sequences can be controlled by these constants
+     * This allows you to start separate components of the channel <br>
+     * MBR_TX_SEQ - starts or stops the membership broadcaster. In a multicast implementation
+     * this will open a datagram socket and join a group and broadcast the local member information
+     * @see #start(int)
+     * @see #stop(int)
+     */
+    public static final int MBR_TX_SEQ = 8;
+    
+    /**
+     * Send options, when a message is sent, it can have an option flag
+     * to trigger certain behavior. Most flags are used to trigger channel interceptors
+     * as the message passes through the channel stack. <br>
+     * However, there are four default flags that every channel implementation must implement<br>
+     * SEND_OPTIONS_BYTE_MESSAGE - The message is a pure byte message and no marshalling or unmarshalling will
+     * be performed.<br>
+     * 
+     * @see #send(Member[], Serializable , int)
+     * @see #send(Member[], Serializable, int, ErrorHandler)
+     */
+    public static final int SEND_OPTIONS_BYTE_MESSAGE = 0x0001;
+
+    /**
+     * Send options, when a message is sent, it can have an option flag
+     * to trigger certain behavior. Most flags are used to trigger channel interceptors
+     * as the message passes through the channel stack. <br>
+     * However, there are four default flags that every channel implementation must implement<br>
+     * SEND_OPTIONS_USE_ACK - Message is sent and an ACK is received when the message has been received by the recipient<br>
+     * If no ack is received, the message is not considered successful<br>
+     * @see #send(Member[], Serializable , int)
+     * @see #send(Member[], Serializable, int, ErrorHandler)
+     */
+    public static final int SEND_OPTIONS_USE_ACK = 0x0002;
+
+    /**
+     * Send options, when a message is sent, it can have an option flag
+     * to trigger certain behavior. Most flags are used to trigger channel interceptors
+     * as the message passes through the channel stack. <br>
+     * However, there are four default flags that every channel implementation must implement<br>
+     * SEND_OPTIONS_SYNCHRONIZED_ACK - Message is sent and an ACK is received when the message has been received and 
+     * processed by the recipient<br>
+     * If no ack is received, the message is not considered successful<br>
+     * @see #send(Member[], Serializable , int)
+     * @see #send(Member[], Serializable, int, ErrorHandler)
+     */
+    public static final int SEND_OPTIONS_SYNCHRONIZED_ACK = 0x0004;
+    
+    /**
+     * Send options, when a message is sent, it can have an option flag
+     * to trigger certain behavior. Most flags are used to trigger channel interceptors
+     * as the message passes through the channel stack. <br>
+     * However, there are four default flags that every channel implementation must implement<br>
+     * SEND_OPTIONS_ASYNCHRONOUS - Message is sent and an ACK is received when the message has been received and 
+     * processed by the recipient<br>
+     * If no ack is received, the message is not considered successful<br>
+     * @see #send(Member[], Serializable , int)
+     * @see #send(Member[], Serializable, int, ErrorHandler)
+     */
+    public static final int SEND_OPTIONS_ASYNCHRONOUS = 0x0008;
+    
+
+    /**
+     * Send options, when a message is sent, it can have an option flag
+     * to trigger certain behavior. Most flags are used to trigger channel interceptors
+     * as the message passes through the channel stack. <br>
+     * However, there are four default flags that every channel implementation must implement<br>
+     * SEND_OPTIONS_DEFAULT - the default sending options, just a helper variable. <br>
+     * The default is <code>int SEND_OPTIONS_DEFAULT = SEND_OPTIONS_USE_ACK;</code><br>
+     * @see #SEND_OPTIONS_USE_ACK
+     * @see #send(Member[], Serializable , int)
+     * @see #send(Member[], Serializable, int, ErrorHandler)
+     */
+    public static final int SEND_OPTIONS_DEFAULT = SEND_OPTIONS_USE_ACK;
+
+    
+    /**
+     * Adds an interceptor to the channel message chain.
+     * @param interceptor ChannelInterceptor
+     */
+    public void addInterceptor(ChannelInterceptor interceptor);
+    
+    /**
+     * Starts up the channel. This can be called multiple times for individual services to start
+     * The svc parameter can be the logical or value of any constants
+     * @param svc int value of <BR>
+     * DEFAULT - will start all services <BR>
+     * MBR_RX_SEQ - starts the membership receiver <BR>
+     * MBR_TX_SEQ - starts the membership broadcaster <BR>
+     * SND_TX_SEQ - starts the replication transmitter<BR>
+     * SND_RX_SEQ - starts the replication receiver<BR>
+     * <b>Note:</b> In order for the membership broadcaster to 
+     * transmit the correct information, it has to be started after the replication receiver.
+     * @throws ChannelException if a startup error occurs or the service is already started or an error occurs.
+     */
+    public void start(int svc) throws ChannelException;
+
+    /**
+     * Shuts down the channel. This can be called multiple times for individual services to shutdown
+     * The svc parameter can be the logical or value of any constants
+     * @param svc int value of <BR>
+     * DEFAULT - will shutdown all services <BR>
+     * MBR_RX_SEQ - stops the membership receiver <BR>
+     * MBR_TX_SEQ - stops the membership broadcaster <BR>
+     * SND_TX_SEQ - stops the replication transmitter<BR>
+     * SND_RX_SEQ - stops the replication receiver<BR>
+     * @throws ChannelException if a startup error occurs or the service is already stopped or an error occurs.
+     */
+    public void stop(int svc) throws ChannelException;    
+    
+    /**
+     * Send a message to one or more members in the cluster
+     * @param destination Member[] - the destinations, can not be null or zero length, the reason for that
+     * is that a membership change can occur and at that time the application is uncertain what group the message
+     * actually got sent to.
+     * @param msg Serializable - the message to send, has to be serializable, or a <code>ByteMessage</code> to 
+     * send a pure byte array
+     * @param options int - sender options, see class documentation for each interceptor that is configured in order to trigger interceptors
+     * @return a unique Id that identifies the message that is sent
+     * @see ByteMessage
+     * @see #SEND_OPTIONS_USE_ACK
+     * @see #SEND_OPTIONS_ASYNCHRONOUS
+     * @see #SEND_OPTIONS_SYNCHRONIZED_ACK
+     */
+    public UniqueId send(Member[] destination, Serializable msg, int options) throws ChannelException;
+
+    /**
+     * Send a message to one or more members in the cluster
+     * @param destination Member[] - the destinations, null or zero length means all
+     * @param msg ClusterMessage - the message to send
+     * @param options int - sender options, see class documentation
+     * @param handler ErrorHandler - handle errors through a callback, rather than throw it
+     * @return a unique Id that identifies the message that is sent
+     * @exception ChannelException - if a serialization error happens.
+     */
+    public UniqueId send(Member[] destination, Serializable msg, int options, ErrorHandler handler) throws ChannelException;
+    
+    /**
+     * Sends a heart beat through the interceptor stacks
+     * Use this method to alert interceptors and other components to 
+     * clean up garbage, timed out messages etc.<br>
+     * If you application has a background thread, then you can save one thread,
+     * by configuring your channel to not use an internal heartbeat thread
+     * and invoking this method.
+     * @see #setHeartbeat(boolean)
+     */
+    public void heartbeat();
+    
+    /**
+     * Enables or disables internal heartbeat.
+     * @param enable boolean - default value is implementation specific
+     * @see #heartbeat()
+     */
+    public void setHeartbeat(boolean enable);
+    
+    /**
+     * Add a membership listener, will get notified when a new member joins, leaves or crashes
+     * <br>If the membership listener implements the Heartbeat interface
+     * the <code>heartbeat()</code> method will be invoked when the heartbeat runs on the channel
+     * @param listener MembershipListener
+     * @see MembershipListener
+     */
+    public void addMembershipListener(MembershipListener listener);
+    
+    /**
+     * Add a channel listener, this is a callback object when messages are received
+     * <br>If the channel listener implements the Heartbeat interface
+     * the <code>heartbeat()</code> method will be invoked when the heartbeat runs on the channel
+     * @param listener ChannelListener
+     * @see ChannelListener
+     * @see Heartbeat
+     */
+    public void addChannelListener(ChannelListener listener);
+
+    /**
+     * remove a membership listener, listeners are removed based on Object.hashCode and Object.equals
+     * @param listener MembershipListener
+     * @see MembershipListener
+     */
+    public void removeMembershipListener(MembershipListener listener);
+    /**
+     * remove a channel listener, listeners are removed based on Object.hashCode and Object.equals
+     * @param listener ChannelListener
+     * @see ChannelListener
+     */
+    public void removeChannelListener(ChannelListener listener);
+    
+    /**
+     * Returns true if there are any members in the group,
+     * this call is the same as <code>getMembers().length>0</code>
+     * @return boolean - true if there are any members automatically discovered
+     */
+    public boolean hasMembers() ;
+
+    /**
+     * Get all current group members
+     * @return all members or empty array, never null 
+     */
+    public Member[] getMembers() ;
+
+    /**
+     * Return the member that represents this node. This is also the data
+     * that gets broadcasted through the membership broadcaster component
+     * @param incAlive - optimization, true if you want it to calculate alive time
+     * since the membership service started.
+     * @return Member
+     */
+    public Member getLocalMember(boolean incAlive);
+    
+    /**
+     * Returns the member from the membership service with complete and 
+     * recent data. Some implementations might serialize and send 
+     * membership information along with a message, and instead of sending
+     * complete membership details, only send the primary identifier for the member
+     * but not the payload or other information. When such message is received
+     * the application can retrieve the cached member through this call.<br>
+     * In most cases, this is not necessary.
+     * @param mbr Member
+     * @return Member
+     */
+    public Member getMember(Member mbr);
+
+    
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/ChannelException.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/ChannelException.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/ChannelException.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,161 @@
+/*
+ * Copyright 1999,2004-2005 The Apache Software Foundation.
+ * 
+ * Licensed 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.tribes;
+
+import java.util.ArrayList;
+
+/**
+ * Channel Exception<br>
+ * A channel exception is thrown when an internal error happens
+ * somewhere in the channel. <br>
+ * When a global error happens, the cause can be retrieved using <code>getCause()</code><br><br>
+ * If an application is sending a message and some of the recipients fail to receive it,
+ * the application can retrieve what recipients failed by using the <code>getFaultyMembers()</code>
+ * method. This way, an application will always know if a message was delivered successfully or not.
+ * @author Filip Hanik
+ * @version $Revision: 304032 $, $Date: 2005-07-27 10:11:55 -0500 (Wed, 27 Jul 2005) $
+ */
+
+public class ChannelException extends Exception {
+    /*
+     * Holds a list of faulty members
+     */
+    private ArrayList faultyMembers=null;
+    
+    /**
+     * Constructor, creates a ChannelException
+     * @see java.lang.Exception#Exception()
+     */
+    public ChannelException() {
+        super();
+    }
+
+    /**
+     * Constructor, creates a ChannelException with an error message
+     * @see java.lang.Exception#Exception(String)
+     */
+    public ChannelException(String message) {
+        super(message);
+    }
+
+    /**
+     * Constructor, creates a ChannelException with an error message and a cause
+     * @param message String
+     * @param cause Throwable
+     * @see java.lang.Exception#Exception(String,Throwable)
+     */
+    public ChannelException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    /**
+     * Constructor, creates a ChannelException with a cause
+     * @param cause Throwable
+     * @see java.lang.Exception#Exception(Throwable)
+     */
+    public ChannelException(Throwable cause) {
+        super(cause);
+    }
+    
+    /**
+     * Returns the message for this exception
+     * @return String
+     * @see java.lang.Exception#getMessage()
+     */
+    public String getMessage() {
+        StringBuffer buf = new StringBuffer(super.getMessage());
+        if (faultyMembers==null || faultyMembers.size() == 0 ) {
+            buf.append("; No faulty members identified.");
+        } else {
+            buf.append("; Faulty members:");
+            for ( int i=0; i<faultyMembers.size(); i++ ) {
+                FaultyMember mbr = (FaultyMember)faultyMembers.get(i);
+                buf.append(mbr.getMember().getName());
+                buf.append("; ");
+            }
+        }
+        return buf.toString();
+    }
+    
+    /**
+     * Adds a faulty member, and the reason the member failed.
+     * @param mbr Member
+     * @param x Exception
+     */
+    public void addFaultyMember(Member mbr, Exception x ) {
+        addFaultyMember(new FaultyMember(mbr,x));
+    }
+    
+    /**
+     * Adds a list of faulty members
+     * @param mbrs FaultyMember[]
+     */
+    public void addFaultyMember(FaultyMember[] mbrs) {
+        for (int i=0; mbrs!=null && i<mbrs.length; i++ ) {
+            addFaultyMember(mbrs[i]);
+        }
+    }
+
+    /**
+     * Adds a faulty member
+     * @param mbr FaultyMember
+     */
+    public void addFaultyMember(FaultyMember mbr) {
+        if ( this.faultyMembers==null ) this.faultyMembers = new ArrayList();
+        faultyMembers.add(mbr);
+    }
+    
+    /**
+     * Returns an array of members that failed and the reason they failed.
+     * @return FaultyMember[]
+     */
+    public FaultyMember[] getFaultyMembers() {
+        if ( this.faultyMembers==null ) return new FaultyMember[0];
+        return (FaultyMember[])faultyMembers.toArray(new FaultyMember[faultyMembers.size()]);
+    }
+    
+    /**
+     * 
+     * <p>Title: FaultyMember class</p> 
+     * 
+     * <p>Description: Represent a failure to a specific member when a message was sent
+     * to more than one member</p> 
+     * 
+     * @author Filip Hanik
+     * @version 1.0
+     */
+    public static class FaultyMember {
+        protected Exception cause;
+        protected Member member;
+        public FaultyMember(Member mbr, Exception x) { 
+            this.member = mbr;
+            this.cause = x;
+        }
+        
+        public Member getMember() {
+            return member;
+        }
+        
+        public Exception getCause() {
+            return cause;
+        }
+        
+        public String toString() {
+            return "FaultyMember:"+member.toString();
+        }
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/ChannelInterceptor.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/ChannelInterceptor.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/ChannelInterceptor.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,179 @@
+/*
+ * Copyright 1999,2004-2006 The Apache Software Foundation.
+ * 
+ * Licensed 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.tribes;
+
+import org.apache.catalina.tribes.group.InterceptorPayload;
+
+/**
+ * A ChannelInterceptor is an interceptor that intercepts 
+ * messages and membership messages in the channel stack.
+ * This allows interceptors to modify the message or perform
+ * other actions when a message is sent or received.<br>
+ * Interceptors are tied together in a linked list.
+ * @see org.apache.catalina.tribes.group.ChannelInterceptorBase
+ * @author Filip Hanik
+ * @version $Revision: 304032 $, $Date: 2005-07-27 10:11:55 -0500 (Wed, 27 Jul 2005) $
+ */   
+
+public interface ChannelInterceptor extends MembershipListener, Heartbeat {
+
+    /**
+     * An interceptor can react to a message based on a set bit on the 
+     * message options. <br>
+     * When a message is sent, the options can be retrieved from ChannelMessage.getOptions()
+     * and if the bit is set, this interceptor will react to it.<br>
+     * A simple evaluation if an interceptor should react to the message would be:<br>
+     * <code>boolean react = (getOptionFlag() == (getOptionFlag() & ChannelMessage.getOptions()));</code><br>
+     * The default option is 0, meaning there is no way for the application to trigger the
+     * interceptor. The interceptor itself will decide.<br>
+     * @return int
+     * @see ChannelMessage#getOptions()
+     */
+    public int getOptionFlag();
+    
+    /**
+     * Sets the option flag
+     * @param flag int
+     * @see #getOptionFlag()
+     */
+    public void setOptionFlag(int flag);
+
+    /**
+     * Set the next interceptor in the list of interceptors
+     * @param next ChannelInterceptor
+     */
+    public void setNext(ChannelInterceptor next) ;
+
+    /**
+     * Retrieve the next interceptor in the list
+     * @return ChannelInterceptor - returns the next interceptor in the list or null if no more interceptors exist
+     */
+    public ChannelInterceptor getNext();
+
+    /**
+     * Set the previous interceptor in the list
+     * @param previous ChannelInterceptor
+     */
+    public void setPrevious(ChannelInterceptor previous);
+
+    /**
+     * Retrieve the previous interceptor in the list
+     * @return ChannelInterceptor - returns the previous interceptor in the list or null if no more interceptors exist
+     */
+    public ChannelInterceptor getPrevious();
+
+    /**
+     * The <code>sendMessage</code> method is called when a message is being sent to one more destinations.
+     * The interceptor can modify any of the parameters and then pass on the message down the stack by
+     * invoking <code>getNext().sendMessage(destination,msg,payload)</code><br>
+     * Alternatively the interceptor can stop the message from being sent by not invoking 
+     * <code>getNext().sendMessage(destination,msg,payload)</code><br>
+     * If the message is to be sent asynchronous the application can be notified of completion and 
+     * errors by passing in an error handler attached to a payload object.<br>
+     * The ChannelMessage.getAddress contains Channel.getLocalMember, and can be overwritten 
+     * to simulate a message sent from another node.<br>
+     * @param destination Member[] - the destination for this message
+     * @param msg ChannelMessage - the message to be sent
+     * @param payload InterceptorPayload - the payload, carrying an error handler and future useful data, can be null
+     * @throws ChannelException
+     * @see ErrorHandler
+     * @see InterceptorPayload
+     */
+    public void sendMessage(Member[] destination, ChannelMessage msg, InterceptorPayload payload) throws ChannelException;
+    
+    /**
+     * the <code>messageReceived</code> is invoked when a message is received.
+     * <code>ChannelMessage.getAddress()</code> is the sender, or the reply-to address
+     * if it has been overwritten.
+     * @param data ChannelMessage
+     */
+    public void messageReceived(ChannelMessage data);
+    
+    /**
+     * The <code>heartbeat()</code> method gets invoked periodically
+     * to allow interceptors to clean up resources, time out object and 
+     * perform actions that are unrelated to sending/receiving data.
+     */
+    public void heartbeat();
+    
+    /**
+     * Intercepts the <code>Channel.hasMembers()</code> method
+     * @return boolean - if the channel has members in its membership group
+     * @see Channel#hasMembers()
+     */
+    public boolean hasMembers() ;
+
+    /**
+     * Intercepts the code>Channel.getMembers()</code> method
+     * @return Member[]
+     * @see Channel#getMembers()
+     */
+    public Member[] getMembers() ;
+
+    /**
+     * Intercepts the code>Channel.getLocalMember(boolean)</code> method
+     * @param incAliveTime boolean
+     * @return Member
+     * @see Channel#getLocalMember(boolean)
+     */
+    public Member getLocalMember(boolean incAliveTime) ;
+
+    /**
+     * Intercepts the code>Channel.getMember(Member)</code> method
+     * @param mbr Member
+     * @return Member - the actual member information, including stay alive
+     * @see Channel#getMember(Member)
+     */
+    public Member getMember(Member mbr);
+    
+    /**
+     * Starts up the channel. This can be called multiple times for individual services to start
+     * The svc parameter can be the logical or value of any constants
+     * @param svc int value of <BR>
+     * Channel.DEFAULT - will start all services <BR>
+     * Channel.MBR_RX_SEQ - starts the membership receiver <BR>
+     * Channel.MBR_TX_SEQ - starts the membership broadcaster <BR>
+     * Channel.SND_TX_SEQ - starts the replication transmitter<BR>
+     * Channel.SND_RX_SEQ - starts the replication receiver<BR>
+     * @throws ChannelException if a startup error occurs or the service is already started.
+     * @see Channel
+     */
+    public void start(int svc) throws ChannelException;
+
+    /**
+     * Shuts down the channel. This can be called multiple times for individual services to shutdown
+     * The svc parameter can be the logical or value of any constants
+     * @param svc int value of <BR>
+     * Channel.DEFAULT - will shutdown all services <BR>
+     * Channel.MBR_RX_SEQ - stops the membership receiver <BR>
+     * Channel.MBR_TX_SEQ - stops the membership broadcaster <BR>
+     * Channel.SND_TX_SEQ - stops the replication transmitter<BR>
+     * Channel.SND_RX_SEQ - stops the replication receiver<BR>
+     * @throws ChannelException if a startup error occurs or the service is already started.
+     * @see Channel
+     */
+    public void stop(int svc) throws ChannelException;
+    
+    public void fireInterceptorEvent(InterceptorEvent event);
+
+    interface InterceptorEvent {
+        int getEventType();
+        String getEventTypeDesc();
+        ChannelInterceptor getInterceptor();
+    }
+    
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/ChannelListener.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/ChannelListener.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/ChannelListener.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,67 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tribes;
+
+import java.io.Serializable;
+/**
+ * 
+ * <p>Title: ChannelListener</p> 
+ * 
+ * <p>Description: An interface to listens to incoming messages from a channel </p> 
+ * When a message is received, the Channel will invoke the channel listener in a conditional sequence.
+ * <code>if ( listener.accept(msg,sender) ) listener.messageReceived(msg,sender);</code><br>
+ * A ChannelListener implementation MUST NOT return true on <code>accept(Serializable, Member)</code>
+ * if it doesn't intend to process the message. The channel can this way track whether a message
+ * was processed by an above application or if it was just received and forgot about, a featuer required
+ * to support message-response(RPC) calls<br>
+ * 
+ * @author Filip Hanik
+ * @version 1.0
+ */
+
+public interface ChannelListener {
+
+    /**
+     * Receive a message from the channel
+     * @param msg Serializable
+     * @param sender - the source of the message
+     */
+    public void messageReceived(Serializable msg, Member sender);
+
+    /**
+     * Invoked by the channel to determine if the listener will process this message or not.
+     * @param msg Serializable
+     * @param sender Member
+     * @return boolean
+     */
+    public boolean accept(Serializable msg, Member sender);
+
+    /**
+     * 
+     * @param listener Object
+     * @return boolean
+     * @see Object#equals(Object)
+     */
+    public boolean equals(Object listener);
+
+    /**
+     * 
+     * @return int
+     * @see Object#hashCode(int)
+     */
+    public int hashCode();
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/ChannelMessage.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/ChannelMessage.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/ChannelMessage.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,108 @@
+/*
+ * Copyright 1999,2005 The Apache Software Foundation.
+ *
+ * Licensed 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.tribes;
+
+import java.io.Serializable;
+import org.apache.catalina.tribes.io.XByteBuffer;
+
+/**
+ * Message that is passed through the interceptor stack after the 
+ * data serialized in the Channel object and then passed down to the 
+ * interceptor and eventually down to the ChannelSender component
+ * @author Filip Hanik
+ * 
+ */
+public interface ChannelMessage extends Serializable {
+    
+    
+    
+    
+    /**
+     * Get the address that this message originated from.  
+     * Almost always <code>Channel.getLocalMember(boolean)</code><br>
+     * This would be set to a different address 
+     * if the message was being relayed from a host other than the one
+     * that originally sent it.
+     * @return the source or reply-to address of this message
+     */
+    public Member getAddress();
+
+    /**
+     * Sets the source or reply-to address of this message
+     * @param member Member
+     */
+    public void setAddress(Member member);
+
+    /**
+     * Timestamp of when the message was created.
+     * @return long timestamp in milliseconds
+     */
+    public long getTimestamp();
+
+    /**
+     *
+     * Sets the timestamp of this message
+     * @param timestamp The timestamp
+     */
+    public void setTimestamp(long timestamp);
+
+    /**
+     * Each message must have a globally unique Id.
+     * interceptors heavily depend on this id for message processing
+     * @return byte
+     */
+    public byte[] getUniqueId();
+    
+    /**
+     * The byte buffer that contains the actual message payload
+     * @param buf XByteBuffer
+     */
+    public void setMessage(XByteBuffer buf);
+    
+    /**
+     * returns the byte buffer that contains the actual message payload
+     * @return XByteBuffer
+     */
+    public XByteBuffer getMessage();
+    
+    /**
+     * The message options is a 32 bit flag set
+     * that triggers interceptors and message behavior.
+     * @see Channel#send(Member[], Serializable, int) 
+     * @see ChannelInterceptor#getOptionFlag
+     * @return int - the option bits set for this message
+     */
+    public int getOptions();
+    
+    /**
+     * sets the option bits for this message
+     * @param options int
+     * @see #getOptions()
+     */
+    public void setOptions(int options);
+    
+    /**
+     * Shallow clone, what gets cloned depends on the implementation
+     * @return ChannelMessage
+     */
+    public Object clone();
+
+    /**
+     * Deep clone, all fields MUST get cloned
+     * @return ChannelMessage
+     */
+    public Object deepclone();
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/ChannelReceiver.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/ChannelReceiver.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/ChannelReceiver.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,68 @@
+/*
+ * Copyright 1999,2004-2005 The Apache Software Foundation.
+ * 
+ * Licensed 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.tribes;
+
+
+/**
+ * ChannelReceiver Interface<br>
+ * The <code>ChannelReceiver</code> interface is the data receiver component 
+ * at the bottom layer, the IO layer (for layers see the javadoc for the {@link Channel} interface).
+ * This class may optionally implement a thread pool for parallel processing of incoming messages.
+ * @author Filip Hanik
+ * @version $Revision: 379904 $, $Date: 2006-02-22 15:16:25 -0600 (Wed, 22 Feb 2006) $
+ */
+public interface ChannelReceiver extends Heartbeat {
+    /**
+     * Start listening for incoming messages on the host/port
+     * @throws java.io.IOException
+     */
+    public void start() throws java.io.IOException;
+
+    /**
+     * Stop listening for messages
+     */
+    public void stop();
+
+    /**
+     * String representation of the IPv4 or IPv6 address that this host is listening
+     * to.
+     * @return the host that this receiver is listening to
+     */
+    public String getHost();
+    
+    
+    /**
+     * Returns the listening port
+     * @return port
+     */
+    public int getPort();
+    
+    /**
+     * Sets the message listener to receive notification of incoming
+     * @param listener MessageListener
+     * @see MessageListener
+     */
+    public void setMessageListener(MessageListener listener);
+    
+    /**
+     * Returns the message listener that is associated with this receiver
+     * @return MessageListener
+     * @see MessageListener
+     */
+    public MessageListener getMessageListener();
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/ChannelSender.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/ChannelSender.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/ChannelSender.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,68 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tribes;
+
+
+/**
+ * ChannelReceiver Interface<br>
+ * The <code>ChannelSender</code> interface is the data sender component 
+ * at the bottom layer, the IO layer (for layers see the javadoc for the {@link Channel} interface).<br>
+ * The channel sender must support "silent" members, ie, be able to send a message to a member
+ * that is not in the membership, but is part of the destination parameter
+ * @author Filip Hanik
+ * @version $Revision: 379904 $, $Date: 2006-02-22 15:16:25 -0600 (Wed, 22 Feb 2006) $
+ */
+public interface ChannelSender extends Heartbeat
+{
+    /**
+     * Notify the sender of a member being added to the group.<br>
+     * Optional. This can be an empty implementation, that does nothing
+     * @param member Member
+     */
+    public void add(Member member);
+    /**
+     * Notification that a member has been removed or crashed.
+     * Can be used to clean up open connections etc
+     * @param member Member
+     */
+    public void remove(Member member);
+    
+    /**
+     * Start the channel sender
+     * @throws IOException if preprocessing takes place and an error happens
+     */
+    public void start() throws java.io.IOException;
+    /**
+     * Stop the channel sender
+     */
+    public void stop();
+    
+    /**
+     * A channel heartbeat, use this method to clean up resources
+     */
+    public void heartbeat() ;
+    
+    /**
+     * Send a message to one or more recipients.
+     * @param message ChannelMessage - the message to be sent
+     * @param destination Member[] - the destinations
+     * @throws ChannelException - if an error happens, the ChannelSender MUST report
+     * individual send failures on a per member basis, using ChannelException.addFaultyMember
+     * @see ChannelException#addFaultyMember(Member,java.lang.Exception)
+     */
+    public void sendMessage(ChannelMessage message, Member[] destination) throws ChannelException;
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/Constants.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/Constants.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/Constants.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,31 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tribes;
+
+/**
+ * Manifest constants for the <code>org.apache.catalina.tribes</code>
+ * package.
+ *
+ * @author Bip Thelin
+ * @author Filip Hanik
+ * @version $Revision: 302726 $, $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public final class Constants {
+    public static final String Package = "org.apache.catalina.tribes";
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/ErrorHandler.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/ErrorHandler.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/ErrorHandler.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,45 @@
+/*
+ * Copyright 1999,2004-2006 The Apache Software Foundation.
+ * 
+ * Licensed 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.tribes;
+
+
+
+/**
+ * The <code>ErrorHandler</code> class is used when sending messages
+ * that are sent asynchronously and the application still needs to get 
+ * confirmation when the message was sent successfully or when a message errored out.
+ * @author Filip Hanik
+ * @version 1.0
+ */
+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)
+     */
+    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)
+     */
+    public void handleCompletion(UniqueId id);
+    
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/Heartbeat.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/Heartbeat.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/Heartbeat.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,33 @@
+/*
+ * Copyright 1999,2004-2005 The Apache Software Foundation.
+ * 
+ * Licensed 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.tribes;
+
+/**
+ * Can be implemented by the ChannelListener and Membership listeners to receive heartbeat
+ * notifications from the Channel
+ * @author Filip Hanik
+ * @version 1.0
+ * @see Channel
+ * @see Channel#heartbeat()
+ */
+public interface Heartbeat {
+    
+    /**
+     * Heartbeat invokation for resources cleanup etc
+     */
+    public void heartbeat();
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/LocalStrings.properties
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/LocalStrings.properties	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/LocalStrings.properties	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1 @@
+cluster.mbean.register.already=MBean {0} already registered!

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/ManagedChannel.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/ManagedChannel.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/ManagedChannel.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,77 @@
+/*
+ * Copyright 1999,2004-2005 The Apache Software Foundation.
+ * 
+ * Licensed 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.tribes;
+
+import java.util.Iterator;
+
+/**
+ * Channel interface
+ * A managed channel interface gives you access to the components of the channels
+ * such as senders, receivers, interceptors etc for configurations purposes
+ * @author Filip Hanik
+ * @version $Revision: 304032 $, $Date: 2005-07-27 10:11:55 -0500 (Wed, 27 Jul 2005) $
+ */
+public interface ManagedChannel extends Channel {
+
+    /**
+     * Sets the channel sender
+     * @param sender ChannelSender
+     * @see ChannelSender
+     */
+    public void setChannelSender(ChannelSender sender);
+
+    /**
+     * Sets the channel receiver
+     * @param receiver ChannelReceiver
+     * @see ChannelReceiver
+     */
+    public void setChannelReceiver(ChannelReceiver receiver);
+    
+    /**
+     * Sets the membership service
+     * @param service MembershipService
+     * @see MembershipService
+     */
+    public void setMembershipService(MembershipService service);
+
+    /**
+     * returns the channel sender
+     * @return ChannelSender
+     * @see ChannelSender
+     */
+    public ChannelSender getChannelSender();
+    
+    /**
+     * returns the channel receiver
+     * @return ChannelReceiver
+     * @see ChannelReceiver
+     */
+    public ChannelReceiver getChannelReceiver();
+    
+    /**
+     * Returns the membership service
+     * @return MembershipService
+     * @see MembershipService
+     */
+    public MembershipService getMembershipService();
+
+    /**
+     * Returns the interceptor stack
+     * @return Iterator
+     * @see Channel#addInterceptor(ChannelInterceptor)
+     */
+    public Iterator getInterceptors();
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/Member.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/Member.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/Member.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,109 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tribes;
+
+/**
+ * The Member interface, defines a member in the group.
+ * Each member can carry a set of properties, defined by the actual implementation.<BR>
+ * A member is identified by the host/ip/uniqueId<br>
+ * The host is what interface the member is listening to, to receive data<br>
+ * The port is what port the member is listening to, to receive data<br>
+ * The uniqueId defines the session id for the member. This is an important feature
+ * since a member that has crashed and the starts up again on the same port/host is 
+ * not guaranteed to be the same member, so no state transfers will ever be confused
+ * @author Filip Hanik
+ * @version $Revision: 303950 $, $Date: 2005-06-09 15:38:30 -0500 (Thu, 09 Jun 2005) $
+ */
+
+
+public interface Member {
+    
+    /**
+     * When a member leaves the cluster, the payload of the memberDisappeared member
+     * will be the following bytes. This indicates a soft shutdown, and not a crash
+     */
+    public static final byte[] SHUTDOWN_PAYLOAD = new byte[] {66, 65, 66, 89, 45, 65, 76, 69, 88};
+    
+    /**
+     * Returns the name of this node, should be unique within the group.
+     */
+    public String getName();
+  
+    /**
+     * Returns the listen host for the ChannelReceiver implementation
+     * @return IPv4 or IPv6 representation of the host address this member listens to incoming data
+     * @see ChannelReceiver
+     */
+    public byte[] getHost();
+
+    /**
+     * Returns the listen port for the ChannelReceiver implementation
+     * @return IPv4 or IPv6 representation of the host address this member listens to incoming data
+     * @see ChannelReceiver
+     */
+    public int getPort();
+
+    /**
+     * Contains information on how long this member has been online.
+     * The result is the number of milli seconds this member has been
+     * broadcasting its membership to the group.
+     * @return nr of milliseconds since this member started.
+     */
+    public long getMemberAliveTime();
+    
+    /**
+     * The current state of the member
+     * @return boolean - true if the member is functioning correctly
+     */
+    public boolean isReady();
+    /**
+     * The current state of the member
+     * @return boolean - true if the member is suspect, but the crash has not been confirmed
+     */
+    public boolean isSuspect();
+    
+    /**
+     * 
+     * @return boolean - true if the member has been confirmed to malfunction 
+     */
+    public boolean isFailing();
+    
+    /**
+     * returns a UUID unique for this member over all sessions.
+     * If the member crashes and restarts, the uniqueId will be different.
+     * @return byte[]
+     */
+    public byte[] getUniqueId();
+    
+    /**
+     * returns the payload associated with this member
+     * @return byte[]
+     */
+    public byte[] getPayload();
+    
+    /**
+     * returns the command associated with this member
+     * @return byte[]
+     */
+    public byte[] getCommand();
+    
+    /**
+     * Domain for this cluster
+     * @return byte[]
+     */
+    public byte[] getDomain();
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/MembershipListener.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/MembershipListener.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/MembershipListener.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,44 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tribes;
+
+/**
+ * The MembershipListener interface is used as a callback to the
+ * membership service. It has two methods that will notify the listener
+ * when a member has joined the group and when a member has disappeared (crashed)
+ *
+ * @author Filip Hanik
+ * @version $Revision: 302726 $, $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+
+public interface MembershipListener {
+    /**
+     * A member was added to the group
+     * @param member Member - the member that was added
+     */
+    public void memberAdded(Member member);
+    
+    /**
+     * A member was removed from the group<br>
+     * If the member left voluntarily, the payload will contain the Member.SHUTDOWN_PAYLOAD data
+     * @param member Member
+     * @see Member#SHUTDOWN_PAYLOAD
+     */
+    public void memberDisappeared(Member member);
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/MembershipService.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/MembershipService.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/MembershipService.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,134 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tribes;
+
+
+/**
+ * MembershipService Interface<br>
+ * The <code>MembershipService</code> interface is the membership component 
+ * at the bottom layer, the IO layer (for layers see the javadoc for the {@link Channel} interface).<br>
+ * @author Filip Hanik
+ * @version $Revision: 378093 $, $Date: 2006-02-15 15:13:45 -0600 (Wed, 15 Feb 2006) $
+ */
+
+
+public interface MembershipService {
+    
+    public static final int MBR_RX = Channel.MBR_RX_SEQ;
+    public static final int MBR_TX = Channel.MBR_TX_SEQ;
+    
+    /**
+     * Sets the properties for the membership service. This must be called before
+     * the <code>start()</code> method is called.
+     * The properties are implementation specific.
+     * @param properties - to be used to configure the membership service.
+     */
+    public void setProperties(java.util.Properties properties);
+    /**
+     * Returns the properties for the configuration used.
+     */
+    public java.util.Properties getProperties();
+    /**
+     * Starts the membership service. If a membership listeners is added
+     * the listener will start to receive membership events.
+     * Performs a start level 1 and 2
+     * @throws java.lang.Exception if the service fails to start.
+     */
+    public void start() throws java.lang.Exception;
+
+    /**
+     * Starts the membership service. If a membership listeners is added
+     * the listener will start to receive membership events.
+     * @param level - level MBR_RX starts listening for members, level MBR_TX 
+     * starts broad casting the server
+     * @throws java.lang.Exception if the service fails to start.
+     * @throws java.lang.IllegalArgumentException if the level is incorrect.
+     */
+    public void start(int level) throws java.lang.Exception;
+
+
+    /**
+     * Starts the membership service. If a membership listeners is added
+     * the listener will start to receive membership events.
+     * @param level - level MBR_RX stops listening for members, level MBR_TX 
+     * stops broad casting the server
+     * @throws java.lang.Exception if the service fails to stop
+     * @throws java.lang.IllegalArgumentException if the level is incorrect.
+     */
+
+    public void stop(int level);
+    
+    /**
+     * @return true if the the group contains members
+     */
+    public boolean hasMembers();
+    
+    
+    /**
+     * 
+     * @param mbr Member
+     * @return Member
+     */
+    public Member getMember(Member mbr);
+    /**
+     * Returns a list of all the members in the cluster.
+     */
+    
+    public Member[] getMembers();
+    
+    /**
+     * Returns the member object that defines this member
+     */
+    public Member getLocalMember(boolean incAliveTime);
+
+    /**
+     * Return all members by name
+     */
+    public String[] getMembersByName() ; 
+    
+    /**
+     * Return the member by name
+     */
+    public Member findMemberByName(String name) ;
+
+    /**
+     * Sets the local member properties for broadcasting
+     */
+    public void setLocalMemberProperties(String listenHost, int listenPort);
+    
+    /**
+     * Sets the membership listener, only one listener can be added.
+     * If you call this method twice, the last listener will be used.
+     * @param listener The listener
+     */
+    public void setMembershipListener(MembershipListener listener);
+    
+    /**
+     * removes the membership listener.
+     */
+    public void removeMembershipListener();
+    
+    /**
+     * Set a payload to be broadcasted with each membership 
+     * broadcast.
+     * @param payload byte[]
+     */
+    public void setPayload(byte[] payload);
+    
+    public void setDomain(byte[] domain);
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/MessageListener.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/MessageListener.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/MessageListener.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,42 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tribes;
+
+/**
+ * 
+ * <p>Title: MessageListener</p> 
+ * 
+ * <p>Description: The listener to be registered with the ChannelReceiver, internal Tribes component</p> 
+ * 
+ * @author Filip Hanik
+ * @version 1.0
+ */
+
+public interface MessageListener {
+    
+    /**
+     * Receive a message from the IO components in the Channel stack
+     * @param msg ChannelMessage
+     */
+    public void messageReceived(ChannelMessage msg);
+    
+    public boolean accept(ChannelMessage msg);
+    
+    public boolean equals(Object listener);
+    
+    public int hashCode();
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/RemoteProcessException.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/RemoteProcessException.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/RemoteProcessException.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,46 @@
+/*
+ * Copyright 1999,2006 The Apache Software Foundation.
+ * 
+ * Licensed 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.tribes;
+
+/**
+ * <p>Title: RemoteProcessException</p>
+ *
+ * <p>Description: Message thrown by a sender when USE_SYNC_ACK receives a FAIL_ACK_COMMAND.<br>
+ * This means that the message was received on the remote node but the processing of the message failed.
+ * This message will be embedded in a ChannelException.FaultyMember
+ * </p>
+ * @see ChannelException
+ * @author Filip Hanik
+ * @version 1.0
+ */
+public class RemoteProcessException extends RuntimeException {
+    public RemoteProcessException() {
+        super();
+    }
+
+    public RemoteProcessException(String message) {
+        super(message);
+    }
+
+    public RemoteProcessException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    public RemoteProcessException(Throwable cause) {
+        super(cause);
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/UniqueId.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/UniqueId.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/UniqueId.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,71 @@
+/*
+ * Copyright 1999,2004-2005 The Apache Software Foundation.
+ * 
+ * Licensed 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.tribes;
+
+import org.apache.catalina.tribes.util.Arrays;
+import java.io.Serializable;
+
+/**
+ * <p>Title: Represents a globabally unique Id</p>
+ *
+ * <p>Company: </p>
+ *
+ * @author Filip Hanik
+ * @version 1.0
+ */
+public final class UniqueId implements Serializable{
+    protected byte[] id;
+    
+    public UniqueId() {
+    }
+
+    public UniqueId(byte[] id) {
+        this.id = id;
+    }
+    
+    public UniqueId(byte[] id, int offset, int length) {
+        this.id = new byte[length];
+        System.arraycopy(id,offset,this.id,0,length);
+    }
+    
+    public int hashCode() {
+        if ( id == null ) return 0;
+        return Arrays.hashCode(id);
+    }
+    
+    public boolean equals(Object other) {
+        boolean result = (other instanceof UniqueId);
+        if ( result ) {
+            UniqueId uid = (UniqueId)other;
+            if ( this.id == null && uid.id == null ) result = true;
+            else if ( this.id == null && uid.id != null ) result = false;
+            else if ( this.id != null && uid.id == null ) result = false;
+            else result = Arrays.equals(this.id,uid.id);
+        }//end if
+        return result;
+    }
+    
+    public byte[] getBytes() {
+        return id;
+    }
+    
+    public String toString() {
+        StringBuffer buf = new StringBuffer("UniqueId");
+        buf.append(org.apache.catalina.tribes.util.Arrays.toString(id));
+        return buf.toString();
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/group/AbsoluteOrder.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/group/AbsoluteOrder.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/group/AbsoluteOrder.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,100 @@
+package org.apache.catalina.tribes.group;
+
+import org.apache.catalina.tribes.Member;
+import java.util.Comparator;
+import java.util.Arrays;
+
+/**
+ * <p>Title: Membership - Absolute Order</p>
+ *
+ * <p>Description: A simple, yet agreeable and efficient way of ordering members</p>
+ * <p>
+ *    Ordering members can serve as a basis for electing a leader or coordinating efforts.<br>
+ *    This is stinky simple, it works on the basis of the <code>Member</code> interface
+ *    and orders members in the following format:
+ * 
+ *  <ol>
+ *     <li>IP comparison - byte by byte, lower byte higher rank</li>
+ *     <li>IPv4 addresses rank higher than IPv6, ie the lesser number of bytes, the higher rank</li>
+ *     <li>Port comparison - lower port, higher rank</li>
+ *     <li>UniqueId comparison- byte by byte, lower byte higher rank</li>
+ *  </ol>
+ *     
+ * </p>
+ *
+ * @author Filip Hanik
+ * @version 1.0
+ * @see org.apache.catalina.tribes.Member
+ */
+public class AbsoluteOrder {
+    public static final AbsoluteComparator comp = new AbsoluteComparator();
+    
+    protected AbsoluteOrder() {
+        super();
+    }
+
+    
+    
+    public static void absoluteOrder(Member[] members) {
+        if ( members == null || members.length == 0 ) return;
+        Arrays.sort(members,comp);
+    }
+    
+    
+    public static class AbsoluteComparator implements Comparator {
+        public int compare(Object o1, Object o2) {
+            if ( !((o1 instanceof Member) && (o2 instanceof Member)) ) return 0;
+            return compareMembers((Member)o1,(Member)o2);
+        }
+        
+        public int compareMembers(Member m1, Member m2) {
+            int result = compareIps(m1,m2);
+            if ( result == 0 ) result = comparePorts(m1,m2);
+            if ( result == 0 ) result = compareIds(m1,m2);
+            return result;
+        }
+        
+        public int compareIps(Member m1, Member m2) {
+            return compareBytes(m1.getHost(),m2.getHost());
+        }
+        
+        public int comparePorts(Member m1, Member m2) {
+            return compareInts(m1.getPort(),m2.getPort());
+        }
+        
+        public int compareIds(Member m1, Member m2) {
+            return compareBytes(m1.getUniqueId(),m2.getUniqueId());
+        }
+        
+        protected int compareBytes(byte[] d1, byte[] d2) {
+            int result = 0;
+            if ( d1.length == d2.length ) {
+                for (int i=0; (result==0) && (i<d1.length); i++) {
+                    result = compareBytes(d1[i],d2[i]);
+                }
+            } else if ( d1.length < d2.length) {
+                result = -1;
+            } else {
+                result = 1;
+            }
+            return result;
+        }
+        
+        protected int compareBytes(byte b1, byte b2) {
+            return compareInts((int)b1,(int)b2);
+        }
+        
+        protected int compareInts(int b1, int b2) {
+            int result = 0;
+            if ( b1 == b2 ) {
+
+            } else if ( b1 < b2) {
+                result = -1;
+            } else {
+                result = 1;
+            }
+            return result;
+        }
+    }
+    
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/group/ChannelCoordinator.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/group/ChannelCoordinator.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/group/ChannelCoordinator.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,317 @@
+/*
+ * Copyright 1999,2004-2006 The Apache Software Foundation.
+ * 
+ * Licensed 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.tribes.group;
+
+import org.apache.catalina.tribes.ChannelException;
+import org.apache.catalina.tribes.ChannelMessage;
+import org.apache.catalina.tribes.ChannelReceiver;
+import org.apache.catalina.tribes.ChannelSender;
+
+import org.apache.catalina.tribes.Member;
+import org.apache.catalina.tribes.MembershipService;
+import org.apache.catalina.tribes.MessageListener;
+import org.apache.catalina.tribes.transport.SenderState;
+import org.apache.catalina.tribes.transport.ReplicationTransmitter;
+import org.apache.catalina.tribes.membership.McastService;
+import org.apache.catalina.tribes.transport.nio.NioReceiver;
+import org.apache.catalina.tribes.Channel;
+import org.apache.catalina.tribes.util.Logs;
+import org.apache.catalina.tribes.UniqueId;
+import org.apache.catalina.tribes.util.Arrays;
+
+
+/**
+ * The channel coordinator object coordinates the membership service,
+ * the sender and the receiver.
+ * This is the last interceptor in the chain.
+ * @author Filip Hanik
+ * @version $Revision: 304032 $, $Date: 2005-07-27 10:11:55 -0500 (Wed, 27 Jul 2005) $
+ */
+public class ChannelCoordinator extends ChannelInterceptorBase implements MessageListener {
+    private ChannelReceiver clusterReceiver = new NioReceiver();
+    private ChannelSender clusterSender = new ReplicationTransmitter();
+    private MembershipService membershipService = new McastService();
+    
+    //override optionflag
+    protected int optionFlag = Channel.SEND_OPTIONS_BYTE_MESSAGE|Channel.SEND_OPTIONS_USE_ACK|Channel.SEND_OPTIONS_SYNCHRONIZED_ACK;
+    public int getOptionFlag() {return optionFlag;}
+    public void setOptionFlag(int flag) {optionFlag=flag;}
+    
+    private int startLevel = 0;
+
+    public ChannelCoordinator() {
+        
+    }
+    
+    public ChannelCoordinator(ChannelReceiver receiver,
+                              ChannelSender sender,
+                              MembershipService service) {
+        this();
+        this.setClusterReceiver(receiver);
+        this.setClusterSender(sender);
+        this.setMembershipService(service);
+    }
+    
+    /**
+     * Send a message to one or more members in the cluster
+     * @param destination Member[] - the destinations, null or zero length means all
+     * @param msg ClusterMessage - the message to send
+     * @param options int - sender options, see class documentation
+     * @return ClusterMessage[] - the replies from the members, if any.
+     */
+    public void sendMessage(Member[] destination, ChannelMessage msg, InterceptorPayload payload) throws ChannelException {
+        if ( destination == null ) destination = membershipService.getMembers();
+        clusterSender.sendMessage(msg,destination);
+        if ( Logs.MESSAGES.isTraceEnabled() ) {
+            Logs.MESSAGES.trace("ChannelCoordinator - Sent msg:" + new UniqueId(msg.getUniqueId()) + " at " +new java.sql.Timestamp(System.currentTimeMillis())+ " to "+Arrays.toNameString(destination));
+        }
+    }
+    
+
+    /**
+     * Starts up the channel. This can be called multiple times for individual services to start
+     * The svc parameter can be the logical or value of any constants
+     * @param svc int value of <BR>
+     * DEFAULT - will start all services <BR>
+     * MBR_RX_SEQ - starts the membership receiver <BR>
+     * MBR_TX_SEQ - starts the membership broadcaster <BR>
+     * SND_TX_SEQ - starts the replication transmitter<BR>
+     * SND_RX_SEQ - starts the replication receiver<BR>
+     * @throws ChannelException if a startup error occurs or the service is already started.
+     */
+    public void start(int svc) throws ChannelException {
+        this.internalStart(svc);
+    }
+
+    /**
+     * Shuts down the channel. This can be called multiple times for individual services to shutdown
+     * The svc parameter can be the logical or value of any constants
+     * @param svc int value of <BR>
+     * DEFAULT - will shutdown all services <BR>
+     * MBR_RX_SEQ - stops the membership receiver <BR>
+     * MBR_TX_SEQ - stops the membership broadcaster <BR>
+     * SND_TX_SEQ - stops the replication transmitter<BR>
+     * SND_RX_SEQ - stops the replication receiver<BR>
+     * @throws ChannelException if a startup error occurs or the service is already started.
+     */
+    public void stop(int svc) throws ChannelException {
+        this.internalStop(svc);
+    }    
+
+
+    /**
+     * Starts up the channel. This can be called multiple times for individual services to start
+     * The svc parameter can be the logical or value of any constants
+     * @param svc int value of <BR>
+     * DEFAULT - will start all services <BR>
+     * MBR_RX_SEQ - starts the membership receiver <BR>
+     * MBR_TX_SEQ - starts the membership broadcaster <BR>
+     * SND_TX_SEQ - starts the replication transmitter<BR>
+     * SND_RX_SEQ - starts the replication receiver<BR>
+     * @throws ChannelException if a startup error occurs or the service is already started.
+     */
+    protected synchronized void internalStart(int svc) throws ChannelException {
+        try {
+            boolean valid = false;
+            //make sure we don't pass down any flags that are unrelated to the bottom layer
+            svc = svc & Channel.DEFAULT;
+
+            if (startLevel == Channel.DEFAULT) return; //we have already started up all components
+            if (svc == 0 ) return;//nothing to start
+            
+            if (svc == (svc & startLevel)) throw new ChannelException("Channel already started for level:"+svc);
+
+            //must start the receiver first so that we can coordinate the port it
+            //listens to with the local membership settings
+            if ( Channel.SND_RX_SEQ==(svc & Channel.SND_RX_SEQ) ) {
+                clusterReceiver.setMessageListener(this);
+                clusterReceiver.start();
+                //synchronize, big time FIXME
+                membershipService.setLocalMemberProperties(getClusterReceiver().getHost(), getClusterReceiver().getPort());
+                valid = true;
+            }
+            if ( Channel.SND_TX_SEQ==(svc & Channel.SND_TX_SEQ) ) {
+                clusterSender.start();
+                valid = true;
+            }
+            
+            if ( Channel.MBR_RX_SEQ==(svc & Channel.MBR_RX_SEQ) ) {
+                membershipService.setMembershipListener(this);
+                membershipService.start(MembershipService.MBR_RX);
+                valid = true;
+            }
+            if ( Channel.MBR_TX_SEQ==(svc & Channel.MBR_TX_SEQ) ) {
+                membershipService.start(MembershipService.MBR_TX);
+                valid = true;
+            }
+            
+            if ( !valid) {
+                throw new IllegalArgumentException("Invalid start level, valid levels are:SND_RX_SEQ,SND_TX_SEQ,MBR_TX_SEQ,MBR_RX_SEQ");
+            }
+            startLevel = (startLevel | svc);
+        }catch ( ChannelException cx ) {
+            throw cx;
+        }catch ( Exception x ) {
+            throw new ChannelException(x);
+        }
+    }
+
+    /**
+     * Shuts down the channel. This can be called multiple times for individual services to shutdown
+     * The svc parameter can be the logical or value of any constants
+     * @param svc int value of <BR>
+     * DEFAULT - will shutdown all services <BR>
+     * MBR_RX_SEQ - starts the membership receiver <BR>
+     * MBR_TX_SEQ - starts the membership broadcaster <BR>
+     * SND_TX_SEQ - starts the replication transmitter<BR>
+     * SND_RX_SEQ - starts the replication receiver<BR>
+     * @throws ChannelException if a startup error occurs or the service is already started.
+     */
+    protected synchronized void internalStop(int svc) throws ChannelException {
+        try {
+            //make sure we don't pass down any flags that are unrelated to the bottom layer
+            svc = svc & Channel.DEFAULT;
+
+            if (startLevel == 0) return; //we have already stopped up all components
+            if (svc == 0 ) return;//nothing to stop
+
+            boolean valid = false;
+            if ( Channel.SND_RX_SEQ==(svc & Channel.SND_RX_SEQ) ) {
+                clusterReceiver.stop();
+                clusterReceiver.setMessageListener(null);
+                valid = true;
+            }
+            if ( Channel.SND_TX_SEQ==(svc & Channel.SND_TX_SEQ) ) {
+                clusterSender.stop();
+                valid = true;
+            }
+
+            if ( Channel.MBR_RX_SEQ==(svc & Channel.MBR_RX_SEQ) ) {
+                membershipService.stop(MembershipService.MBR_RX);
+                membershipService.setMembershipListener(null);
+                valid = true;
+                
+            }
+            if ( Channel.MBR_TX_SEQ==(svc & Channel.MBR_TX_SEQ) ) {
+                valid = true;
+                membershipService.stop(MembershipService.MBR_TX);
+            }            
+            if ( !valid) {
+                throw new IllegalArgumentException("Invalid start level, valid levels are:SND_RX_SEQ,SND_TX_SEQ,MBR_TX_SEQ,MBR_RX_SEQ");
+            }
+
+            startLevel = (startLevel & (~svc));
+            
+        }catch ( Exception x ) {
+            throw new ChannelException(x);
+        } finally {
+            
+        }
+
+    }
+    
+    public void memberAdded(Member member){
+        SenderState.getSenderState(member);
+        if ( clusterSender!=null ) clusterSender.add(member);
+        super.memberAdded(member);
+    }
+    
+    public void memberDisappeared(Member member){
+        SenderState.removeSenderState(member);
+        if ( clusterSender!=null ) clusterSender.remove(member);
+        super.memberDisappeared(member);
+    }
+    
+    public void messageReceived(ChannelMessage msg) {
+        if ( Logs.MESSAGES.isTraceEnabled() ) {
+            Logs.MESSAGES.trace("ChannelCoordinator - Received msg:" + new UniqueId(msg.getUniqueId()) + " at " +new java.sql.Timestamp(System.currentTimeMillis())+ " from "+msg.getAddress().getName());
+        }
+        super.messageReceived(msg);
+    }
+
+
+    public ChannelReceiver getClusterReceiver() {
+        return clusterReceiver;
+    }
+
+    public ChannelSender getClusterSender() {
+        return clusterSender;
+    }
+
+    public MembershipService getMembershipService() {
+        return membershipService;
+    }
+
+    public void setClusterReceiver(ChannelReceiver clusterReceiver) {
+        if ( clusterReceiver != null ) {
+            this.clusterReceiver = clusterReceiver;
+            this.clusterReceiver.setMessageListener(this);
+        } else {
+            if  (this.clusterReceiver!=null ) this.clusterReceiver.setMessageListener(null);
+            this.clusterReceiver = null;
+        }
+    }
+
+    public void setClusterSender(ChannelSender clusterSender) {
+        this.clusterSender = clusterSender;
+    }
+
+    public void setMembershipService(MembershipService membershipService) {
+        this.membershipService = membershipService;
+        this.membershipService.setMembershipListener(this);
+    }
+    
+    public void hearbeat() {
+        if ( clusterSender!=null ) clusterSender.heartbeat();
+        super.heartbeat();
+    }
+    
+    /**
+     * has members
+     */
+    public boolean hasMembers() {
+        return this.getMembershipService().hasMembers();
+    }
+
+    /**
+     * Get all current cluster members
+     * @return all members or empty array
+     */
+    public Member[] getMembers() {
+        return this.getMembershipService().getMembers();
+    }
+
+    /**
+     * 
+     * @param mbr Member
+     * @return Member
+     */
+    public Member getMember(Member mbr){
+        return this.getMembershipService().getMember(mbr);
+    }
+
+
+    /**
+     * Return the member that represents this node.
+     *
+     * @return Member
+     */
+    public Member getLocalMember(boolean incAlive) {
+        return this.getMembershipService().getLocalMember(incAlive);
+    }
+
+   
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/group/ChannelInterceptorBase.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/group/ChannelInterceptorBase.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/group/ChannelInterceptorBase.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,171 @@
+/*
+ * Copyright 1999,2004-2006 The Apache Software Foundation.
+ *
+ * Licensed 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.tribes.group;
+
+import org.apache.catalina.tribes.ChannelException;
+import org.apache.catalina.tribes.ChannelInterceptor;
+import org.apache.catalina.tribes.ChannelMessage;
+import org.apache.catalina.tribes.Member;
+
+/**
+ * Abstract class for the interceptor base class.
+ * @author Filip Hanik
+ * @version $Revision: 304032 $, $Date: 2005-07-27 10:11:55 -0500 (Wed, 27 Jul 2005) $
+ */
+
+public abstract class ChannelInterceptorBase implements ChannelInterceptor {
+
+    protected static org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory.getLog(
+        ChannelInterceptorBase.class);
+
+    private ChannelInterceptor next;
+    private ChannelInterceptor previous;
+    //default value, always process
+    protected int optionFlag = 0;
+
+    public ChannelInterceptorBase() {
+
+    }
+    
+    public boolean okToProcess(int messageFlags) { 
+        if (this.optionFlag == 0 ) return true;
+        return ((optionFlag&messageFlags) == optionFlag);
+    }
+
+    public final void setNext(ChannelInterceptor next) {
+        this.next = next;
+    }
+
+    public final ChannelInterceptor getNext() {
+        return next;
+    }
+
+    public final void setPrevious(ChannelInterceptor previous) {
+        this.previous = previous;
+    }
+
+    public void setOptionFlag(int optionFlag) {
+        this.optionFlag = optionFlag;
+    }
+
+    public final ChannelInterceptor getPrevious() {
+        return previous;
+    }
+
+    public int getOptionFlag() {
+        return optionFlag;
+    }
+
+    public void sendMessage(Member[] destination, ChannelMessage msg, InterceptorPayload payload) throws
+        ChannelException {
+        if (getNext() != null) getNext().sendMessage(destination, msg, payload);
+    }
+
+    public void messageReceived(ChannelMessage msg) {
+        if (getPrevious() != null) getPrevious().messageReceived(msg);
+    }
+
+    public boolean accept(ChannelMessage msg) {
+        return true;
+    }
+
+    public void memberAdded(Member member) {
+        //notify upwards
+        if (getPrevious() != null) getPrevious().memberAdded(member);
+    }
+
+    public void memberDisappeared(Member member) {
+        //notify upwards
+        if (getPrevious() != null) getPrevious().memberDisappeared(member);
+    }
+
+    public void heartbeat() {
+        if (getNext() != null) getNext().heartbeat();
+    }
+
+    /**
+     * has members
+     */
+    public boolean hasMembers() {
+        if ( getNext()!=null )return getNext().hasMembers();
+        else return false;
+    }
+
+    /**
+     * Get all current cluster members
+     * @return all members or empty array
+     */
+    public Member[] getMembers() {
+        if ( getNext()!=null ) return getNext().getMembers();
+        else return null;
+    }
+
+    /**
+     *
+     * @param mbr Member
+     * @return Member
+     */
+    public Member getMember(Member mbr) {
+        if ( getNext()!=null) return getNext().getMember(mbr);
+        else return null;
+    }
+
+    /**
+     * Return the member that represents this node.
+     *
+     * @return Member
+     */
+    public Member getLocalMember(boolean incAlive) {
+        if ( getNext()!=null ) return getNext().getLocalMember(incAlive);
+        else return null;
+    }
+    
+    /**
+     * Starts up the channel. This can be called multiple times for individual services to start
+     * The svc parameter can be the logical or value of any constants
+     * @param svc int value of <BR>
+     * DEFAULT - will start all services <BR>
+     * MBR_RX_SEQ - starts the membership receiver <BR>
+     * MBR_TX_SEQ - starts the membership broadcaster <BR>
+     * SND_TX_SEQ - starts the replication transmitter<BR>
+     * SND_RX_SEQ - starts the replication receiver<BR>
+     * @throws ChannelException if a startup error occurs or the service is already started.
+     */
+    public void start(int svc) throws ChannelException {
+        if ( getNext()!=null ) getNext().start(svc);
+    }
+
+    /**
+     * Shuts down the channel. This can be called multiple times for individual services to shutdown
+     * The svc parameter can be the logical or value of any constants
+     * @param svc int value of <BR>
+     * DEFAULT - will shutdown all services <BR>
+     * MBR_RX_SEQ - stops the membership receiver <BR>
+     * MBR_TX_SEQ - stops the membership broadcaster <BR>
+     * SND_TX_SEQ - stops the replication transmitter<BR>
+     * SND_RX_SEQ - stops the replication receiver<BR>
+     * @throws ChannelException if a startup error occurs or the service is already started.
+     */
+    public void stop(int svc) throws ChannelException {
+        if (getNext() != null) getNext().stop(svc);
+    }
+    
+    public void fireInterceptorEvent(InterceptorEvent event) {
+        //empty operation
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/group/GroupChannel.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/group/GroupChannel.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/group/GroupChannel.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,666 @@
+/*
+ * Copyright 1999,2004-2006 The Apache Software Foundation.
+ *
+ * Licensed 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.tribes.group;
+
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Iterator;
+
+import org.apache.catalina.tribes.ByteMessage;
+import org.apache.catalina.tribes.Channel;
+import org.apache.catalina.tribes.ChannelException;
+import org.apache.catalina.tribes.ChannelInterceptor;
+import org.apache.catalina.tribes.ChannelListener;
+import org.apache.catalina.tribes.ChannelMessage;
+import org.apache.catalina.tribes.ChannelReceiver;
+import org.apache.catalina.tribes.ChannelSender;
+import org.apache.catalina.tribes.ErrorHandler;
+import org.apache.catalina.tribes.ManagedChannel;
+import org.apache.catalina.tribes.Member;
+import org.apache.catalina.tribes.MembershipListener;
+import org.apache.catalina.tribes.MembershipService;
+import org.apache.catalina.tribes.group.interceptors.MessageDispatchInterceptor;
+import org.apache.catalina.tribes.io.ChannelData;
+import org.apache.catalina.tribes.io.XByteBuffer;
+import org.apache.catalina.tribes.UniqueId;
+import org.apache.catalina.tribes.Heartbeat;
+import org.apache.catalina.tribes.io.BufferPool;
+import java.io.IOException;
+import org.apache.catalina.tribes.RemoteProcessException;
+import org.apache.catalina.tribes.util.Logs;
+import org.apache.catalina.tribes.util.Arrays;
+
+/**
+ * The default implementation of a Channel.<br>
+ * The GroupChannel manages the replication channel. It coordinates
+ * message being sent and received with membership announcements.
+ * The channel has an chain of interceptors that can modify the message or perform other logic.<br>
+ * It manages a complete group, both membership and replication.
+ * @author Filip Hanik
+ * @version $Revision: 304032 $, $Date: 2005-07-27 10:11:55 -0500 (Wed, 27 Jul 2005) $
+ */
+public class GroupChannel extends ChannelInterceptorBase implements ManagedChannel {
+    /**
+     * Flag to determine if the channel manages its own heartbeat
+     * If set to true, the channel will start a local thread for the heart beat.
+     */
+    protected boolean heartbeat = true;
+    /**
+     * If <code>heartbeat == true</code> then how often do we want this
+     * heartbeat to run. default is one minute
+     */
+    protected long heartbeatSleeptime = 5*1000;//every 5 seconds
+
+    /**
+     * Internal heartbeat thread
+     */
+    protected HeartbeatThread hbthread = null;
+
+    /**
+     * The  <code>ChannelCoordinator</code> coordinates the bottom layer components:<br>
+     * - MembershipService<br>
+     * - ChannelSender <br>
+     * - ChannelReceiver<br>
+     */
+    protected ChannelCoordinator coordinator = new ChannelCoordinator();
+
+    /**
+     * The first interceptor in the inteceptor stack.
+     * The interceptors are chained in a linked list, so we only need a reference to the
+     * first one
+     */
+    protected ChannelInterceptor interceptors = null;
+
+    /**
+     * A list of membership listeners that subscribe to membership announcements
+     */
+    protected ArrayList membershipListeners = new ArrayList();
+
+    /**
+     * A list of channel listeners that subscribe to incoming messages
+     */
+    protected ArrayList channelListeners = new ArrayList();
+
+    /**
+     * If set to true, the GroupChannel will check to make sure that
+     */
+    protected boolean optionCheck = false;
+
+    /**
+     * Creates a GroupChannel. This constructor will also
+     * add the first interceptor in the GroupChannel.<br>
+     * The first interceptor is always the channel itself.
+     */
+    public GroupChannel() {
+        addInterceptor(this);
+    }
+
+
+    /**
+     * Adds an interceptor to the stack for message processing<br>
+     * Interceptors are ordered in the way they are added.<br>
+     * <code>channel.addInterceptor(A);</code><br>
+     * <code>channel.addInterceptor(C);</code><br>
+     * <code>channel.addInterceptor(B);</code><br>
+     * Will result in a interceptor stack like this:<br>
+     * <code>A -> C -> B</code><br>
+     * The complete stack will look like this:<br>
+     * <code>Channel -> A -> C -> B -> ChannelCoordinator</code><br>
+     * @param interceptor ChannelInterceptorBase
+     */
+    public void addInterceptor(ChannelInterceptor interceptor) {
+        if ( interceptors == null ) {
+            interceptors = interceptor;
+            interceptors.setNext(coordinator);
+            interceptors.setPrevious(null);
+            coordinator.setPrevious(interceptors);
+        } else {
+            ChannelInterceptor last = interceptors;
+            while ( last.getNext() != coordinator ) {
+                last = last.getNext();
+            }
+            last.setNext(interceptor);
+            interceptor.setNext(coordinator);
+            interceptor.setPrevious(last);
+            coordinator.setPrevious(interceptor);
+        }
+    }
+
+    /**
+     * Sends a heartbeat through the interceptor stack.<br>
+     * Invoke this method from the application on a periodic basis if
+     * you have turned off internal heartbeats <code>channel.setHeartbeat(false)</code>
+     */
+    public void heartbeat() {
+        super.heartbeat();
+        Iterator i = membershipListeners.iterator();
+        while ( i.hasNext() ) {
+            Object o = i.next();
+            if ( o instanceof Heartbeat ) ((Heartbeat)o).heartbeat();
+        }
+        i = channelListeners.iterator();
+        while ( i.hasNext() ) {
+            Object o = i.next();
+            if ( o instanceof Heartbeat ) ((Heartbeat)o).heartbeat();
+        }
+
+    }
+
+
+    /**
+     * Send a message to the destinations specified
+     * @param destination Member[] - destination.length > 1
+     * @param msg Serializable - the message to send
+     * @param options int - sender options, options can trigger guarantee levels and different interceptors to
+     * react to the message see class documentation for the <code>Channel</code> object.<br>
+     * @return UniqueId - the unique Id that was assigned to this message
+     * @throws ChannelException - if an error occurs processing the message
+     * @see org.apache.catalina.tribes.Channel
+     */
+    public UniqueId send(Member[] destination, Serializable msg, int options) throws ChannelException {
+        return send(destination,msg,options,null);
+    }
+
+    /**
+     *
+     * @param destination Member[] - destination.length > 1
+     * @param msg Serializable - the message to send
+     * @param options int - sender options, options can trigger guarantee levels and different interceptors to
+     * react to the message see class documentation for the <code>Channel</code> object.<br>
+     * @param handler - callback object for error handling and completion notification, used when a message is
+     * sent asynchronously using the <code>Channel.SEND_OPTIONS_ASYNCHRONOUS</code> flag enabled.
+     * @return UniqueId - the unique Id that was assigned to this message
+     * @throws ChannelException - if an error occurs processing the message
+     * @see org.apache.catalina.tribes.Channel
+     */
+    public UniqueId send(Member[] destination, Serializable msg, int options, ErrorHandler handler) throws ChannelException {
+        if ( msg == null ) throw new ChannelException("Cant send a NULL message");
+        XByteBuffer buffer = null;
+        try {
+            if ( destination == null || destination.length == 0) throw new ChannelException("No destination given");
+            ChannelData data = new ChannelData(true);//generates a unique Id
+            data.setAddress(getLocalMember(false));
+            data.setTimestamp(System.currentTimeMillis());
+            byte[] b = null;
+            if ( msg instanceof ByteMessage ){
+                b = ((ByteMessage)msg).getMessage();
+                options = options | SEND_OPTIONS_BYTE_MESSAGE;
+            } else {
+                b = XByteBuffer.serialize(msg);
+                options = options & (~SEND_OPTIONS_BYTE_MESSAGE);
+            }
+            data.setOptions(options);
+            //XByteBuffer buffer = new XByteBuffer(b.length+128,false);
+            buffer = BufferPool.getBufferPool().getBuffer(b.length+128, false);
+            buffer.append(b,0,b.length);
+            data.setMessage(buffer);
+            InterceptorPayload payload = null;
+            if ( handler != null ) {
+                payload = new InterceptorPayload();
+                payload.setErrorHandler(handler);
+            }
+            getFirstInterceptor().sendMessage(destination, data, payload);
+            if ( Logs.MESSAGES.isTraceEnabled() ) {
+                Logs.MESSAGES.trace("GroupChannel - Sent msg:" + new UniqueId(data.getUniqueId()) + " at " +new java.sql.Timestamp(System.currentTimeMillis())+ " to "+Arrays.toNameString(destination));
+                Logs.MESSAGES.trace("GroupChannel - Send Message:" + new UniqueId(data.getUniqueId()) + " is " +msg);
+            }
+
+            return new UniqueId(data.getUniqueId());
+        }catch ( Exception x ) {
+            if ( x instanceof ChannelException ) throw (ChannelException)x;
+            throw new ChannelException(x);
+        } finally {
+            if ( buffer != null ) BufferPool.getBufferPool().returnBuffer(buffer);
+        }
+    }
+
+
+    /**
+     * Callback from the interceptor stack. <br>
+     * When a message is received from a remote node, this method will be invoked by
+     * the previous interceptor.<br>
+     * This method can also be used to send a message to other components within the same application,
+     * but its an extreme case, and you're probably better off doing that logic between the applications itself.
+     * @param msg ChannelMessage
+     */
+    public void messageReceived(ChannelMessage msg) {
+        if ( msg == null ) return;
+        try {
+            if ( Logs.MESSAGES.isTraceEnabled() ) {
+                Logs.MESSAGES.trace("GroupChannel - Received msg:" + new UniqueId(msg.getUniqueId()) + " at " +new java.sql.Timestamp(System.currentTimeMillis())+ " from "+msg.getAddress().getName());
+            }
+
+            Serializable fwd = null;
+            if ( (msg.getOptions() & SEND_OPTIONS_BYTE_MESSAGE) == SEND_OPTIONS_BYTE_MESSAGE ) {
+                fwd = new ByteMessage(msg.getMessage().getBytes());
+            } else {
+                fwd = XByteBuffer.deserialize(msg.getMessage().getBytesDirect(),0,msg.getMessage().getLength());
+            }
+            if ( Logs.MESSAGES.isTraceEnabled() ) {
+                Logs.MESSAGES.trace("GroupChannel - Receive Message:" + new UniqueId(msg.getUniqueId()) + " is " +fwd);
+            }
+
+            //get the actual member with the correct alive time
+            Member source = msg.getAddress();
+            boolean rx = false;
+            boolean delivered = false;
+            for ( int i=0; i<channelListeners.size(); i++ ) {
+                ChannelListener channelListener = (ChannelListener)channelListeners.get(i);
+                if (channelListener != null && channelListener.accept(fwd, source)) {
+                    channelListener.messageReceived(fwd, source);
+                    delivered = true;
+                    //if the message was accepted by an RPC channel, that channel
+                    //is responsible for returning the reply, otherwise we send an absence reply
+                    if ( channelListener instanceof RpcChannel ) rx = true;
+                }
+            }//for
+            if ((!rx) && (fwd instanceof RpcMessage)) {
+                //if we have a message that requires a response,
+                //but none was given, send back an immediate one
+                sendNoRpcChannelReply((RpcMessage)fwd,source);
+            }
+            if ( Logs.MESSAGES.isTraceEnabled() ) {
+                Logs.MESSAGES.trace("GroupChannel delivered["+delivered+"] id:"+new UniqueId(msg.getUniqueId()));
+            }
+
+        } catch ( Exception x ) {
+            if ( log.isDebugEnabled() ) log.error("Unable to process channel:IOException.",x);
+            throw new RemoteProcessException("IOException:"+x.getMessage(),x);
+        }
+    }
+
+    /**
+     * Sends a <code>NoRpcChannelReply</code> message to a member<br>
+     * This method gets invoked by the channel if a RPC message comes in
+     * and no channel listener accepts the message. This avoids timeout
+     * @param msg RpcMessage
+     * @param destination Member - the destination for the reply
+     */
+    protected void sendNoRpcChannelReply(RpcMessage msg, Member destination) {
+        try {
+            //avoid circular loop
+            if ( msg instanceof RpcMessage.NoRpcChannelReply) return;
+            RpcMessage.NoRpcChannelReply reply = new RpcMessage.NoRpcChannelReply(msg.rpcId,msg.uuid);
+            send(new Member[]{destination},reply,Channel.SEND_OPTIONS_ASYNCHRONOUS);
+        } catch ( Exception x ) {
+            log.error("Unable to find rpc channel, failed to send NoRpcChannelReply.",x);
+        }
+    }
+
+    /**
+     * memberAdded gets invoked by the interceptor below the channel
+     * and the channel will broadcast it to the membership listeners
+     * @param member Member - the new member
+     */
+    public void memberAdded(Member member) {
+        //notify upwards
+        for (int i=0; i<membershipListeners.size(); i++ ) {
+            MembershipListener membershipListener = (MembershipListener)membershipListeners.get(i);
+            if (membershipListener != null) membershipListener.memberAdded(member);
+        }
+    }
+
+    /**
+     * memberDisappeared gets invoked by the interceptor below the channel
+     * and the channel will broadcast it to the membership listeners
+     * @param member Member - the member that left or crashed
+     */
+    public void memberDisappeared(Member member) {
+        //notify upwards
+        for (int i=0; i<membershipListeners.size(); i++ ) {
+            MembershipListener membershipListener = (MembershipListener)membershipListeners.get(i);
+            if (membershipListener != null) membershipListener.memberDisappeared(member);
+        }
+    }
+
+    /**
+     * Sets up the default implementation interceptor stack
+     * if no interceptors have been added
+     * @throws ChannelException
+     */
+    protected synchronized void setupDefaultStack() throws ChannelException {
+
+        if ( getFirstInterceptor() != null &&
+             ((getFirstInterceptor().getNext() instanceof ChannelCoordinator))) {
+            ChannelInterceptor interceptor = null;
+            Class clazz = null;
+            try {
+                clazz = Class.forName("org.apache.catalina.tribes.group.interceptors.MessageDispatch15Interceptor",
+                                      true,GroupChannel.class.getClassLoader());
+                clazz.newInstance();
+            } catch ( Throwable x ) {
+                clazz = MessageDispatchInterceptor.class;
+            }//catch
+            try {
+                interceptor = (ChannelInterceptor) clazz.newInstance();
+            } catch (Exception x) {
+                throw new ChannelException("Unable to add MessageDispatchInterceptor to interceptor chain.",x);
+            }
+            this.addInterceptor(interceptor);
+        }
+    }
+
+    /**
+     * Validates the option flags that each interceptor is using and reports
+     * an error if two interceptor share the same flag.
+     * @throws ChannelException
+     */
+    protected void checkOptionFlags() throws ChannelException {
+        StringBuffer conflicts = new StringBuffer();
+        ChannelInterceptor first = interceptors;
+        while ( first != null ) {
+            int flag = first.getOptionFlag();
+            if ( flag != 0 ) {
+                ChannelInterceptor next = first.getNext();
+                while ( next != null ) {
+                    int nflag = next.getOptionFlag();
+                    if (nflag!=0 && (((flag & nflag) == flag ) || ((flag & nflag) == nflag)) ) {
+                        conflicts.append("[");
+                        conflicts.append(first.getClass().getName());
+                        conflicts.append(":");
+                        conflicts.append(flag);
+                        conflicts.append(" == ");
+                        conflicts.append(next.getClass().getName());
+                        conflicts.append(":");
+                        conflicts.append(nflag);
+                        conflicts.append("] ");
+                    }//end if
+                    next = next.getNext();
+                }//while
+            }//end if
+            first = first.getNext();
+        }//while
+        if ( conflicts.length() > 0 ) throw new ChannelException("Interceptor option flag conflict: "+conflicts.toString());
+
+    }
+
+    /**
+     * Starts the channel
+     * @param svc int - what service to start
+     * @throws ChannelException
+     * @see org.apache.catalina.tribes.Channel#start(int)
+     */
+    public synchronized void start(int svc) throws ChannelException {
+        setupDefaultStack();
+        if (optionCheck) checkOptionFlags();
+        super.start(svc);
+        if ( hbthread == null && heartbeat ) {
+            hbthread = new HeartbeatThread(this,heartbeatSleeptime);
+            hbthread.start();
+        }
+    }
+
+    /**
+     * Stops the channel
+     * @param svc int
+     * @throws ChannelException
+     * @see org.apache.catalina.tribes.Channel#stop(int)
+     */
+    public synchronized void stop(int svc) throws ChannelException {
+        if (hbthread != null) {
+            hbthread.stopHeartbeat();
+            hbthread = null;
+        }
+        super.stop(svc);
+    }
+
+    /**
+     * Returns the first interceptor of the stack. Useful for traversal.
+     * @return ChannelInterceptor
+     */
+    public ChannelInterceptor getFirstInterceptor() {
+        if (interceptors != null) return interceptors;
+        else return coordinator;
+    }
+
+    /**
+     * Returns the channel receiver component
+     * @return ChannelReceiver
+     */
+    public ChannelReceiver getChannelReceiver() {
+        return coordinator.getClusterReceiver();
+    }
+
+    /**
+     * Returns the channel sender component
+     * @return ChannelSender
+     */
+    public ChannelSender getChannelSender() {
+        return coordinator.getClusterSender();
+    }
+
+    /**
+     * Returns the membership service component
+     * @return MembershipService
+     */
+    public MembershipService getMembershipService() {
+        return coordinator.getMembershipService();
+    }
+
+    /**
+     * Sets the channel receiver component
+     * @param clusterReceiver ChannelReceiver
+     */
+    public void setChannelReceiver(ChannelReceiver clusterReceiver) {
+        coordinator.setClusterReceiver(clusterReceiver);
+    }
+
+    /**
+     * Sets the channel sender component
+     * @param clusterSender ChannelSender
+     */
+    public void setChannelSender(ChannelSender clusterSender) {
+        coordinator.setClusterSender(clusterSender);
+    }
+
+    /**
+     * Sets the membership component
+     * @param membershipService MembershipService
+     */
+    public void setMembershipService(MembershipService membershipService) {
+        coordinator.setMembershipService(membershipService);
+    }
+
+    /**
+     * Adds a membership listener to the channel.<br>
+     * Membership listeners are uniquely identified using the equals(Object) method
+     * @param membershipListener MembershipListener
+     */
+    public void addMembershipListener(MembershipListener membershipListener) {
+        if (!this.membershipListeners.contains(membershipListener) )
+            this.membershipListeners.add(membershipListener);
+    }
+
+    /**
+     * Removes a membership listener from the channel.<br>
+     * Membership listeners are uniquely identified using the equals(Object) method
+     * @param membershipListener MembershipListener
+     */
+
+    public void removeMembershipListener(MembershipListener membershipListener) {
+        membershipListeners.remove(membershipListener);
+    }
+
+    /**
+     * Adds a channel listener to the channel.<br>
+     * Channel listeners are uniquely identified using the equals(Object) method
+     * @param channelListener ChannelListener
+     */
+    public void addChannelListener(ChannelListener channelListener) {
+        if (!this.channelListeners.contains(channelListener) ) {
+            this.channelListeners.add(channelListener);
+        } else {
+            throw new IllegalArgumentException("Listener already exists:"+channelListener);
+        }
+    }
+
+    /**
+     *
+     * Removes a channel listener from the channel.<br>
+     * Channel listeners are uniquely identified using the equals(Object) method
+     * @param channelListener ChannelListener
+     */
+    public void removeChannelListener(ChannelListener channelListener) {
+        channelListeners.remove(channelListener);
+    }
+
+    /**
+     * Returns an iterator of all the interceptors in this stack
+     * @return Iterator
+     */
+    public Iterator getInterceptors() {
+        return new InterceptorIterator(this.getNext(),this.coordinator);
+    }
+
+    /**
+     * Enables/disables the option check<br>
+     * Setting this to true, will make the GroupChannel perform a conflict check
+     * on the interceptors. If two interceptors are using the same option flag
+     * and throw an error upon start.
+     * @param optionCheck boolean
+     */
+    public void setOptionCheck(boolean optionCheck) {
+        this.optionCheck = optionCheck;
+    }
+
+    /**
+     * Configure local heartbeat sleep time<br>
+     * Only used when <code>getHeartbeat()==true</code>
+     * @param heartbeatSleeptime long - time in milliseconds to sleep between heartbeats
+     */
+    public void setHeartbeatSleeptime(long heartbeatSleeptime) {
+        this.heartbeatSleeptime = heartbeatSleeptime;
+    }
+
+    /**
+     * Enables or disables local heartbeat.
+     * if <code>setHeartbeat(true)</code> is invoked then the channel will start an internal
+     * thread to invoke <code>Channel.heartbeat()</code> every <code>getHeartbeatSleeptime</code> milliseconds
+     * @param heartbeat boolean
+     */
+    public void setHeartbeat(boolean heartbeat) {
+        this.heartbeat = heartbeat;
+    }
+
+    /**
+     * @see #setOptionCheck(boolean)
+     * @return boolean
+     */
+    public boolean getOptionCheck() {
+        return optionCheck;
+    }
+
+    /**
+     * @see #setHeartbeat(boolean)
+     * @return boolean
+     */
+    public boolean getHeartbeat() {
+        return heartbeat;
+    }
+
+    /**
+     * Returns the sleep time in milliseconds that the internal heartbeat will
+     * sleep in between invokations of <code>Channel.heartbeat()</code>
+     * @return long
+     */
+    public long getHeartbeatSleeptime() {
+        return heartbeatSleeptime;
+    }
+
+    /**
+     *
+     * <p>Title: Interceptor Iterator</p>
+     *
+     * <p>Description: An iterator to loop through the interceptors in a channel</p>
+     *
+     * @version 1.0
+     */
+    public static class InterceptorIterator implements Iterator {
+        private ChannelInterceptor end;
+        private ChannelInterceptor start;
+        public InterceptorIterator(ChannelInterceptor start, ChannelInterceptor end) {
+            this.end = end;
+            this.start = start;
+        }
+
+        public boolean hasNext() {
+            return start!=null && start != end;
+        }
+
+        public Object next() {
+            Object result = null;
+            if ( hasNext() ) {
+                result = start;
+                start = start.getNext();
+            }
+            return result;
+        }
+
+        public void remove() {
+            //empty operation
+        }
+    }
+
+    /**
+     *
+     * <p>Title: Internal heartbeat thread</p>
+     *
+     * <p>Description: if <code>Channel.getHeartbeat()==true</code> then a thread of this class
+     * is created</p>
+     *
+     * @version 1.0
+     */
+    public static class HeartbeatThread extends Thread {
+        protected static org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory.getLog(HeartbeatThread.class);
+        protected static int counter = 1;
+        protected static synchronized int inc() {
+            return counter++;
+        }
+
+        protected boolean doRun = true;
+        protected GroupChannel channel;
+        protected long sleepTime;
+        public HeartbeatThread(GroupChannel channel, long sleepTime) {
+            super();
+            this.setPriority(MIN_PRIORITY);
+            setName("GroupChannel-Heartbeat-"+inc());
+            setDaemon(true);
+            this.channel = channel;
+            this.sleepTime = sleepTime;
+        }
+        public void stopHeartbeat() {
+            doRun = false;
+            interrupt();
+        }
+
+        public void run() {
+            while (doRun) {
+                try {
+                    Thread.sleep(sleepTime);
+                    channel.heartbeat();
+                } catch ( InterruptedException x ) {
+                    interrupted();
+                } catch ( Exception x ) {
+                    log.error("Unable to send heartbeat through Tribes interceptor stack. Will try to sleep again.",x);
+                }//catch
+            }//while
+        }//run
+    }//HeartbeatThread
+
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/group/InterceptorPayload.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/group/InterceptorPayload.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/group/InterceptorPayload.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,34 @@
+/*
+ * Copyright 1999,2004-2006 The Apache Software Foundation.
+ * 
+ * Licensed 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.tribes.group;
+
+import org.apache.catalina.tribes.ErrorHandler;
+
+/**
+ * @author Filip Hanik
+ * @version 1.0
+ */
+public class InterceptorPayload  {
+    private ErrorHandler errorHandler;
+    
+    public ErrorHandler getErrorHandler() {
+        return errorHandler;
+    }
+
+    public void setErrorHandler(ErrorHandler errorHandler) {
+        this.errorHandler = errorHandler;
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/group/Response.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/group/Response.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/group/Response.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,53 @@
+/*
+ * Copyright 1999,2004-2006 The Apache Software Foundation.
+ * 
+ * Licensed 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.tribes.group;
+
+import java.io.Serializable;
+
+import org.apache.catalina.tribes.Member;
+
+/**
+ * A response object holds a message from a responding partner.
+ * @author Filip Hanik
+ * @version 1.0
+ */
+public class Response {
+    private Member source;
+    private Serializable message;
+    public Response() {
+    }
+    
+    public Response(Member source, Serializable message) {
+        this.source = source;
+        this.message = message;
+    }
+
+    public void setSource(Member source) {
+        this.source = source;
+    }
+
+    public void setMessage(Serializable message) {
+        this.message = message;
+    }
+
+    public Member getSource() {
+        return source;
+    }
+
+    public Serializable getMessage() {
+        return message;
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/group/RpcCallback.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/group/RpcCallback.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/group/RpcCallback.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,45 @@
+/*
+ * Copyright 1999,2004-2006 The Apache Software Foundation.
+ * 
+ * Licensed 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.tribes.group;
+
+import java.io.Serializable;
+
+import org.apache.catalina.tribes.Member;
+
+/**
+ * The RpcCallback interface is an interface for the Tribes channel to request a
+ * response object to a request that came in.
+ * @author not attributable
+ * @version 1.0
+ */
+public interface RpcCallback {
+    
+    /**
+     * 
+     * @param msg Serializable
+     * @return Serializable - null if no reply should be sent
+     */
+    public Serializable replyRequest(Serializable msg, Member sender);
+    
+    /**
+     * If the reply has already been sent to the requesting thread,
+     * the rpc callback can handle any data that comes in after the fact.
+     * @param msg Serializable
+     * @param sender Member
+     */
+    public void leftOver(Serializable msg, Member sender);
+    
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/group/RpcChannel.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/group/RpcChannel.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/group/RpcChannel.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,261 @@
+/*
+ * Copyright 1999,2004-2006 The Apache Software Foundation.
+ * 
+ * Licensed 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.tribes.group;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+
+import org.apache.catalina.tribes.Channel;
+import org.apache.catalina.tribes.ChannelException;
+import org.apache.catalina.tribes.ChannelListener;
+import org.apache.catalina.tribes.Member;
+import org.apache.catalina.tribes.util.UUIDGenerator;
+
+/**
+ * A channel to handle RPC messaging
+ * @author Filip Hanik
+ */
+public class RpcChannel implements ChannelListener{
+    protected static org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory.getLog(RpcChannel.class);
+    
+    public static final int FIRST_REPLY = 1;
+    public static final int MAJORITY_REPLY = 2;
+    public static final int ALL_REPLY = 3;
+    public static final int NO_REPLY = 4;
+    
+    private Channel channel;
+    private RpcCallback callback;
+    private byte[] rpcId;
+    
+    private HashMap responseMap = new HashMap();
+
+    /**
+     * Create an RPC channel. You can have several RPC channels attached to a group
+     * all separated out by the uniqueness
+     * @param rpcId - the unique Id for this RPC group
+     * @param channel Channel
+     * @param callback RpcCallback
+     */
+    public RpcChannel(byte[] rpcId, Channel channel, RpcCallback callback) {
+        this.channel = channel;
+        this.callback = callback;
+        this.rpcId = rpcId;
+        channel.addChannelListener(this);
+    }
+    
+    
+    /**
+     * Send a message and wait for the response.
+     * @param destination Member[] - the destination for the message, and the members you request a reply from
+     * @param message Serializable - the message you are sending out
+     * @param options int - FIRST_REPLY, MAJORITY_REPLY or ALL_REPLY
+     * @param timeout long - timeout in milliseconds, if no reply is received within this time null is returned
+     * @return Response[] - an array of response objects.
+     * @throws ChannelException
+     */
+    public Response[] send(Member[] destination, 
+                           Serializable message,
+                           int rpcOptions, 
+                           int channelOptions,
+                           long timeout) throws ChannelException {
+        
+        if ( destination==null || destination.length == 0 ) return new Response[0];
+        
+        //avoid dead lock
+        channelOptions = channelOptions & ~Channel.SEND_OPTIONS_SYNCHRONIZED_ACK;
+        
+        RpcCollectorKey key = new RpcCollectorKey(UUIDGenerator.randomUUID(false));
+        RpcCollector collector = new RpcCollector(key,rpcOptions,destination.length,timeout);
+        try {
+            synchronized (collector) {
+                if ( rpcOptions != NO_REPLY ) responseMap.put(key, collector);
+                RpcMessage rmsg = new RpcMessage(rpcId, key.id, message);
+                channel.send(destination, rmsg, channelOptions);
+                if ( rpcOptions != NO_REPLY ) collector.wait(timeout);
+            }
+        } catch ( InterruptedException ix ) {
+            Thread.currentThread().interrupted();
+            //throw new ChannelException(ix);
+        }finally {
+            responseMap.remove(key);
+        }
+        return collector.getResponses();
+    }
+    
+    public void messageReceived(Serializable msg, Member sender) {
+        RpcMessage rmsg = (RpcMessage)msg;
+        RpcCollectorKey key = new RpcCollectorKey(rmsg.uuid);
+        if ( rmsg.reply ) {
+            RpcCollector collector = (RpcCollector)responseMap.get(key);
+            if (collector == null) {
+                callback.leftOver(rmsg.message, sender);
+            } else {
+                synchronized (collector) {
+                    //make sure it hasn't been removed
+                    if ( responseMap.containsKey(key) ) {
+                        if ( (rmsg instanceof RpcMessage.NoRpcChannelReply) ) 
+                            collector.destcnt--;
+                        else 
+                            collector.addResponse(rmsg.message, sender);
+                        if (collector.isComplete()) collector.notifyAll();
+                    } else {
+                        if (! (rmsg instanceof RpcMessage.NoRpcChannelReply) ) 
+                            callback.leftOver(rmsg.message, sender);
+                    }
+                }//synchronized
+            }//end if
+        } else{
+            Serializable reply = callback.replyRequest(rmsg.message,sender);
+            rmsg.reply = true;
+            rmsg.message = reply;
+            try {
+                channel.send(new Member[] {sender}, rmsg,0);
+            }catch ( Exception x )  {
+                log.error("Unable to send back reply in RpcChannel.",x);
+            }
+        }//end if
+    }
+    
+    public void breakdown() {
+        channel.removeChannelListener(this);
+    }
+    
+    public void finalize() {
+        breakdown();
+    }
+    
+    public boolean accept(Serializable msg, Member sender) {
+        if ( msg instanceof RpcMessage ) {
+            RpcMessage rmsg = (RpcMessage)msg;
+            return Arrays.equals(rmsg.rpcId,rpcId);
+        }else return false;
+    }
+    
+    public Channel getChannel() {
+        return channel;
+    }
+
+    public RpcCallback getCallback() {
+        return callback;
+    }
+
+    public byte[] getRpcId() {
+        return rpcId;
+    }
+
+    public void setChannel(Channel channel) {
+        this.channel = channel;
+    }
+
+    public void setCallback(RpcCallback callback) {
+        this.callback = callback;
+    }
+
+    public void setRpcId(byte[] rpcId) {
+        this.rpcId = rpcId;
+    }
+    
+
+
+    /**
+     * 
+     * Class that holds all response.
+     * @author not attributable
+     * @version 1.0
+     */
+    public static class RpcCollector {
+        public ArrayList responses = new ArrayList(); 
+        public RpcCollectorKey key;
+        public int options;
+        public int destcnt;
+        public long timeout;
+        
+        public RpcCollector(RpcCollectorKey key, int options, int destcnt, long timeout) {
+            this.key = key;
+            this.options = options;
+            this.destcnt = destcnt;
+            this.timeout = timeout;
+        }
+        
+        public void addResponse(Serializable message, Member sender){
+            Response resp = new Response(sender,message);
+            responses.add(resp);
+        }
+        
+        public boolean isComplete() {
+            if ( destcnt <= 0 ) return true;
+            switch (options) {
+                case ALL_REPLY:
+                    return destcnt == responses.size();
+                case MAJORITY_REPLY:
+                {
+                    float perc = ((float)responses.size()) / ((float)destcnt);
+                    return perc >= 0.50f;
+                }
+                case FIRST_REPLY:
+                    return responses.size()>0;
+                default:
+                    return false;
+            }
+        }
+        
+        public int hashCode() {
+            return key.hashCode();
+        }
+        
+        public boolean equals(Object o) {
+            if ( o instanceof RpcCollector ) {
+                RpcCollector r = (RpcCollector)o;
+                return r.key.equals(this.key);
+            } else return false;
+        }
+        
+        public Response[] getResponses() {
+            return (Response[])responses.toArray(new Response[responses.size()]);
+        }
+    }
+    
+    public static class RpcCollectorKey {
+        byte[] id;
+        public RpcCollectorKey(byte[] id) {
+            this.id = id;
+        }
+        
+        public int hashCode() {
+            return id[0]+id[1]+id[2]+id[3];
+        }
+
+        public boolean equals(Object o) {
+            if ( o instanceof RpcCollectorKey ) {
+                RpcCollectorKey r = (RpcCollectorKey)o;
+                return Arrays.equals(id,r.id);
+            } else return false;
+        }
+        
+    }
+    
+    protected static String bToS(byte[] data) {
+        StringBuffer buf = new StringBuffer(4*16);
+        buf.append("{");
+        for (int i=0; data!=null && i<data.length; i++ ) buf.append(String.valueOf(data[i])).append(" ");
+        buf.append("}");
+        return buf.toString();
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/group/RpcMessage.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/group/RpcMessage.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/group/RpcMessage.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,103 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tribes.group;
+
+import java.io.ObjectInput;
+import java.io.Serializable;
+import java.io.Externalizable;
+import java.io.IOException;
+import java.io.ObjectOutput;
+
+/**
+ * <p>Title: </p>
+ *
+ * <p>Description: </p>
+ *
+ * <p>Copyright: Copyright (c) 2005</p>
+ *
+ * <p>Company: </p>
+ *
+ * @author not attributable
+ * @version 1.0
+ */
+public class RpcMessage implements Externalizable {
+
+    protected Serializable message;
+    protected byte[] uuid;
+    protected byte[] rpcId;
+    protected boolean reply = false;
+
+    public RpcMessage() {
+        //for serialization
+    }
+
+    public RpcMessage(byte[] rpcId, byte[] uuid, Serializable message) {
+        this.rpcId = rpcId;
+        this.uuid = uuid;
+        this.message = message;
+    }
+
+    public void readExternal(ObjectInput in) throws IOException,ClassNotFoundException {
+        reply = in.readBoolean();
+        int length = in.readInt();
+        uuid = new byte[length];
+        in.read(uuid, 0, length);
+        length = in.readInt();
+        rpcId = new byte[length];
+        in.read(rpcId, 0, length);
+        message = (Serializable)in.readObject();
+    }
+
+    public void writeExternal(ObjectOutput out) throws IOException {
+        out.writeBoolean(reply);
+        out.writeInt(uuid.length);
+        out.write(uuid, 0, uuid.length);
+        out.writeInt(rpcId.length);
+        out.write(rpcId, 0, rpcId.length);
+        out.writeObject(message);
+    }
+    
+    public static class NoRpcChannelReply extends RpcMessage {
+        public NoRpcChannelReply() {
+            
+        }
+
+        public NoRpcChannelReply(byte[] rpcid, byte[] uuid) {
+            super(rpcid,uuid,null);
+            reply = true;
+        }
+
+        public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
+            reply = true;
+            int length = in.readInt();
+            uuid = new byte[length];
+            in.read(uuid, 0, length);
+            length = in.readInt();
+            rpcId = new byte[length];
+            in.read(rpcId, 0, length);
+        }
+
+        public void writeExternal(ObjectOutput out) throws IOException {
+            out.writeInt(uuid.length);
+            out.write(uuid, 0, uuid.length);
+            out.writeInt(rpcId.length);
+            out.write(rpcId, 0, rpcId.length);
+        }
+    }    
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/group/interceptors/DomainFilterInterceptor.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/group/interceptors/DomainFilterInterceptor.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/group/interceptors/DomainFilterInterceptor.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,101 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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
+ */
+package org.apache.catalina.tribes.group.interceptors;
+
+import org.apache.catalina.tribes.ChannelMessage;
+import org.apache.catalina.tribes.Member;
+import org.apache.catalina.tribes.group.ChannelInterceptorBase;
+import org.apache.catalina.tribes.membership.MemberImpl;
+import org.apache.catalina.tribes.membership.Membership;
+import java.util.Arrays;
+
+/**
+ * <p>Title: Member domain filter interceptor </p>
+ *
+ * <p>Description: Filters membership based on domain.
+ * </p>
+ *
+ * @author Filip Hanik
+ * @version 1.0
+ */
+public class DomainFilterInterceptor extends ChannelInterceptorBase {
+
+    private static org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory.getLog( DomainFilterInterceptor.class );
+
+    protected Membership membership = null;
+    
+    protected byte[] domain = new byte[0];
+
+    public void messageReceived(ChannelMessage msg) {
+        //should we filter incoming based on domain?
+        super.messageReceived(msg);
+    }//messageReceived
+
+
+    public void memberAdded(Member member) {
+        if ( membership == null ) setupMembership();
+        boolean notify = false;
+        synchronized (membership) {
+            notify = Arrays.equals(domain,member.getDomain());
+            if ( notify ) notify = membership.memberAlive((MemberImpl)member);
+        }
+        if ( notify ) super.memberAdded(member);
+    }
+
+    public void memberDisappeared(Member member) {
+        if ( membership == null ) setupMembership();
+        boolean notify = false;
+        synchronized (membership) {
+            notify = Arrays.equals(domain,member.getDomain());
+            membership.removeMember((MemberImpl)member);
+        }
+        if ( notify ) super.memberDisappeared(member);
+    }
+
+    public boolean hasMembers() {
+        if ( membership == null ) setupMembership();
+        return membership.hasMembers();
+    }
+
+    public Member[] getMembers() {
+        if ( membership == null ) setupMembership();
+        return membership.getMembers();
+    }
+
+    public Member getMember(Member mbr) {
+        if ( membership == null ) setupMembership();
+        return membership.getMember(mbr);
+    }
+
+    public Member getLocalMember(boolean incAlive) {
+        return super.getLocalMember(incAlive);
+    }
+
+
+    protected synchronized void setupMembership() {
+        if ( membership == null ) {
+            membership = new Membership((MemberImpl)super.getLocalMember(true));
+        }
+
+    }
+
+    public byte[] getDomain() {
+        return domain;
+    }
+
+    public void setDomain(byte[] domain) {
+        this.domain = domain;
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/group/interceptors/FragmentationInterceptor.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/group/interceptors/FragmentationInterceptor.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/group/interceptors/FragmentationInterceptor.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,241 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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
+ */
+
+package org.apache.catalina.tribes.group.interceptors;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Set;
+
+import org.apache.catalina.tribes.ChannelException;
+import org.apache.catalina.tribes.ChannelMessage;
+import org.apache.catalina.tribes.Member;
+import org.apache.catalina.tribes.group.ChannelInterceptorBase;
+import org.apache.catalina.tribes.group.InterceptorPayload;
+import org.apache.catalina.tribes.io.XByteBuffer;
+
+/**
+ *
+ * The fragmentation interceptor splits up large messages into smaller messages and assembles them on the other end.
+ * This is very useful when you don't want large messages hogging the sending sockets
+ * and smaller messages can make it through.
+ * 
+ * <br><b>Configuration Options</b><br>
+ * OrderInteceptor.expire=<milliseconds> - how long do we keep the fragments in memory and wait for the rest to arrive<b>default=60,000ms -> 60seconds</b>
+ * This setting is useful to avoid OutOfMemoryErrors<br>
+ * OrderInteceptor.maxSize=<max message size> - message size in bytes <b>default=1024*100 (around a tenth of a MB)</b><br>
+ * @author Filip Hanik
+ * @version 1.0
+ */
+public class FragmentationInterceptor extends ChannelInterceptorBase {
+    private static org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory.getLog( FragmentationInterceptor.class );
+    
+    protected HashMap fragpieces = new HashMap();
+    private int maxSize = 1024*100;
+    private long expire = 1000 * 60; //one minute expiration
+    protected boolean deepclone = true;
+
+
+    public void sendMessage(Member[] destination, ChannelMessage msg, InterceptorPayload payload) throws ChannelException {
+        int size = msg.getMessage().getLength();
+        boolean frag = (size>maxSize) && okToProcess(msg.getOptions());
+        if ( frag ) {
+            frag(destination, msg, payload);
+        } else {
+            msg.getMessage().append(frag);
+            super.sendMessage(destination, msg, payload);
+        }
+    }
+    
+    public void messageReceived(ChannelMessage msg) {
+        boolean isFrag = XByteBuffer.toBoolean(msg.getMessage().getBytesDirect(),msg.getMessage().getLength()-1);
+        msg.getMessage().trim(1);
+        if ( isFrag ) {
+            defrag(msg);
+        } else {
+            super.messageReceived(msg);
+        }
+    }
+
+    
+    public FragCollection getFragCollection(FragKey key, ChannelMessage msg) {
+        FragCollection coll = (FragCollection)fragpieces.get(key);
+        if ( coll == null ) {
+            synchronized (fragpieces) {
+                coll = (FragCollection)fragpieces.get(key);
+                if ( coll == null ) {
+                    coll = new FragCollection(msg);
+                    fragpieces.put(key, coll);
+                }
+            }
+        } 
+        return coll;
+    }
+    
+    public void removeFragCollection(FragKey key) {
+        fragpieces.remove(key);
+    }
+    
+    public void defrag(ChannelMessage msg ) { 
+        FragKey key = new FragKey(msg.getUniqueId());
+        FragCollection coll = getFragCollection(key,msg);
+        coll.addMessage((ChannelMessage)msg.deepclone());
+
+        if ( coll.complete() ) {
+            removeFragCollection(key);
+            ChannelMessage complete = coll.assemble();
+            super.messageReceived(complete);
+            
+        }
+    }
+
+    public void frag(Member[] destination, ChannelMessage msg, InterceptorPayload payload) throws ChannelException {
+        int size = msg.getMessage().getLength();
+
+        int count = ((size / maxSize )+(size%maxSize==0?0:1));
+        ChannelMessage[] messages = new ChannelMessage[count];
+        int remaining = size;
+        for ( int i=0; i<count; i++ ) {
+            ChannelMessage tmp = (ChannelMessage)msg.clone();
+            int offset = (i*maxSize);
+            int length = Math.min(remaining,maxSize);
+            tmp.getMessage().clear();
+            tmp.getMessage().append(msg.getMessage().getBytesDirect(),offset,length);
+            //add the msg nr
+            //tmp.getMessage().append(XByteBuffer.toBytes(i),0,4);
+            tmp.getMessage().append(i);
+            //add the total nr of messages
+            //tmp.getMessage().append(XByteBuffer.toBytes(count),0,4);
+            tmp.getMessage().append(count);
+            //add true as the frag flag
+            //byte[] flag = XByteBuffer.toBytes(true);
+            //tmp.getMessage().append(flag,0,flag.length);
+            tmp.getMessage().append(true);
+            messages[i] = tmp;
+            remaining -= length;
+            
+        }
+        for ( int i=0; i<messages.length; i++ ) {
+            super.sendMessage(destination,messages[i],payload);
+        }
+    }
+    
+    public void heartbeat() {
+        try {
+            Set set = fragpieces.keySet(); 
+            Object[] keys = set.toArray();
+            for ( int i=0; i<keys.length; i++ ) {
+                FragKey key = (FragKey)keys[i];
+                if ( key != null && key.expired(getExpire()) ) 
+                    removeFragCollection(key);
+            }
+        }catch ( Exception x ) {
+            if ( log.isErrorEnabled() ) {
+                log.error("Unable to perform heartbeat clean up in the frag interceptor",x);
+            }
+        }
+        super.heartbeat();
+    }
+
+    
+
+    public int getMaxSize() {
+        return maxSize;
+    }
+
+    public long getExpire() {
+        return expire;
+    }
+
+    public void setMaxSize(int maxSize) {
+        this.maxSize = maxSize;
+    }
+
+    public void setExpire(long expire) {
+        this.expire = expire;
+    }
+
+    public static class FragCollection {
+        private long received = System.currentTimeMillis();
+        private ChannelMessage msg;
+        private XByteBuffer[] frags;
+        public FragCollection(ChannelMessage msg) {
+            //get the total messages
+            int count = XByteBuffer.toInt(msg.getMessage().getBytesDirect(),msg.getMessage().getLength()-4);
+            frags = new XByteBuffer[count];
+            this.msg = msg;
+        }
+        
+        public void addMessage(ChannelMessage msg) {
+            //remove the total messages
+            msg.getMessage().trim(4);
+            //get the msg nr
+            int nr = XByteBuffer.toInt(msg.getMessage().getBytesDirect(),msg.getMessage().getLength()-4);
+            //remove the msg nr
+            msg.getMessage().trim(4);
+            frags[nr] = msg.getMessage();
+            
+        }
+        
+        public boolean complete() {
+            boolean result = true;
+            for ( int i=0; (i<frags.length) && (result); i++ ) result = (frags[i] != null);
+            return result;
+        }
+        
+        public ChannelMessage assemble() {
+            if ( !complete() ) throw new IllegalStateException("Fragments are missing.");
+            int buffersize = 0;
+            for (int i=0; i<frags.length; i++ ) buffersize += frags[i].getLength();
+            XByteBuffer buf = new XByteBuffer(buffersize,false);
+            msg.setMessage(buf);
+            for ( int i=0; i<frags.length; i++ ) {
+                msg.getMessage().append(frags[i].getBytesDirect(),0,frags[i].getLength());
+            }
+            return msg;
+        }
+        
+        public boolean expired(long expire) {
+            return (System.currentTimeMillis()-received)>expire;
+        }
+
+        
+        
+    }
+    
+    public static class FragKey {
+        private byte[] uniqueId;
+        private long received = System.currentTimeMillis();
+        public FragKey(byte[] id ) {
+            this.uniqueId = id;
+        }
+        public int hashCode() {
+            return XByteBuffer.toInt(uniqueId,0);
+        }
+        
+        public boolean equals(Object o ) {
+            if ( o instanceof FragKey ) {
+            return Arrays.equals(uniqueId,((FragKey)o).uniqueId);
+        } else return false;
+
+        }
+        
+        public boolean expired(long expire) {
+            return (System.currentTimeMillis()-received)>expire;
+        }
+
+    }
+    
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/group/interceptors/GzipInterceptor.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/group/interceptors/GzipInterceptor.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/group/interceptors/GzipInterceptor.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,99 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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
+ */
+
+package org.apache.catalina.tribes.group.interceptors;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.zip.GZIPInputStream;
+import java.util.zip.GZIPOutputStream;
+
+import org.apache.catalina.tribes.ChannelException;
+import org.apache.catalina.tribes.ChannelMessage;
+import org.apache.catalina.tribes.Member;
+import org.apache.catalina.tribes.group.ChannelInterceptorBase;
+import org.apache.catalina.tribes.group.InterceptorPayload;
+
+
+
+/**
+ *
+ *
+ * @author Filip Hanik
+ * @version 1.0
+ */
+public class GzipInterceptor extends ChannelInterceptorBase {
+    public static final int DEFAULT_BUFFER_SIZE = 2048;
+    
+    public void sendMessage(Member[] destination, ChannelMessage msg, InterceptorPayload payload) throws ChannelException {
+        try {
+            byte[] data = compress(msg.getMessage().getBytes());
+            msg.getMessage().trim(msg.getMessage().getLength());
+            msg.getMessage().append(data,0,data.length);
+            getNext().sendMessage(destination, msg, payload);
+        } catch ( IOException x ) {
+            log.error("Unable to compress byte contents");
+            throw new ChannelException(x);
+        }
+    }
+
+    public void messageReceived(ChannelMessage msg) {
+        try {
+            byte[] data = decompress(msg.getMessage().getBytes());
+            msg.getMessage().trim(msg.getMessage().getLength());
+            msg.getMessage().append(data,0,data.length);
+            getPrevious().messageReceived(msg);
+        } catch ( IOException x ) {
+            log.error("Unable to decompress byte contents",x);
+        }
+    }
+    
+    public static byte[] compress(byte[] data) throws IOException {
+        ByteArrayOutputStream bout = new ByteArrayOutputStream();
+        GZIPOutputStream gout = new GZIPOutputStream(bout);
+        gout.write(data);
+        gout.flush();
+        gout.close();
+        return bout.toByteArray();
+    }
+    
+    /**
+     * @todo Fix to create an automatically growing buffer.
+     * @param data byte[]
+     * @return byte[]
+     * @throws IOException
+     */
+    public static byte[] decompress(byte[] data) throws IOException {
+        ByteArrayInputStream bin = new ByteArrayInputStream(data);
+        GZIPInputStream gin = new GZIPInputStream(bin);
+        byte[] tmp = new byte[DEFAULT_BUFFER_SIZE];
+        int length = gin.read(tmp);
+        byte[] result = new byte[length];
+        System.arraycopy(tmp,0,result,0,length);
+        return result;
+    }
+    
+    public static void main(String[] arg) throws Exception {
+        byte[] data = new byte[1024];
+        Arrays.fill(data,(byte)1);
+        byte[] compress = compress(data);
+        byte[] decompress = decompress(compress);
+        System.out.println("Debug test");
+        
+    }
+    
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/group/interceptors/MessageDispatch15Interceptor.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/group/interceptors/MessageDispatch15Interceptor.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/group/interceptors/MessageDispatch15Interceptor.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,111 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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
+ */
+package org.apache.catalina.tribes.group.interceptors;
+
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.atomic.AtomicLong;
+
+import org.apache.catalina.tribes.ChannelMessage;
+import org.apache.catalina.tribes.Member;
+import org.apache.catalina.tribes.group.InterceptorPayload;
+import org.apache.catalina.tribes.transport.bio.util.LinkObject;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * 
+ * Same implementation as the MessageDispatchInterceptor
+ * except is ues an atomic long for the currentSize calculation
+ * and uses a thread pool for message sending.
+ * 
+ * @author Filip Hanik
+ * @version 1.0
+ */
+
+public class MessageDispatch15Interceptor extends MessageDispatchInterceptor {
+
+    protected AtomicLong currentSize = new AtomicLong(0);
+    protected ThreadPoolExecutor executor = null;
+    protected int maxThreads = 10;
+    protected int maxSpareThreads = 2;
+    protected long keepAliveTime = 5000;
+    protected LinkedBlockingQueue<Runnable> runnablequeue = new LinkedBlockingQueue<Runnable>();
+
+    public long getCurrentSize() {
+        return currentSize.get();
+    }
+
+    public long addAndGetCurrentSize(long inc) {
+        return currentSize.addAndGet(inc);
+    }
+
+    public long setAndGetCurrentSize(long value) {
+        currentSize.set(value);
+        return value;
+    }
+    
+    public boolean addToQueue(ChannelMessage msg, Member[] destination, InterceptorPayload payload) {
+        final LinkObject obj = new LinkObject(msg,destination,payload);
+        Runnable r = new Runnable() {
+            public void run() {
+                sendAsyncData(obj);
+            }
+        };
+        executor.execute(r);
+        return true;
+    }
+
+    public LinkObject removeFromQueue() {
+        return null; //not used, thread pool contains its own queue.
+    }
+
+    public void startQueue() {
+        if ( run ) return;
+        executor = new ThreadPoolExecutor(maxSpareThreads,maxThreads,keepAliveTime,TimeUnit.MILLISECONDS,runnablequeue);
+        run = true;
+    }
+
+    public void stopQueue() {
+        run = false;
+        executor.shutdownNow();
+        setAndGetCurrentSize(0);
+        runnablequeue.clear();
+    }
+
+    public long getKeepAliveTime() {
+        return keepAliveTime;
+    }
+
+    public int getMaxSpareThreads() {
+        return maxSpareThreads;
+    }
+
+    public int getMaxThreads() {
+        return maxThreads;
+    }
+
+    public void setKeepAliveTime(long keepAliveTime) {
+        this.keepAliveTime = keepAliveTime;
+    }
+
+    public void setMaxSpareThreads(int maxSpareThreads) {
+        this.maxSpareThreads = maxSpareThreads;
+    }
+
+    public void setMaxThreads(int maxThreads) {
+        this.maxThreads = maxThreads;
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/group/interceptors/MessageDispatchInterceptor.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/group/interceptors/MessageDispatchInterceptor.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/group/interceptors/MessageDispatchInterceptor.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,201 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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
+ */
+
+package org.apache.catalina.tribes.group.interceptors;
+
+import org.apache.catalina.tribes.Channel;
+import org.apache.catalina.tribes.ChannelException;
+import org.apache.catalina.tribes.ChannelMessage;
+import org.apache.catalina.tribes.Member;
+import org.apache.catalina.tribes.group.ChannelInterceptorBase;
+import org.apache.catalina.tribes.group.InterceptorPayload;
+import org.apache.catalina.tribes.transport.bio.util.FastQueue;
+import org.apache.catalina.tribes.transport.bio.util.LinkObject;
+import org.apache.catalina.tribes.UniqueId;
+
+/**
+ *
+ * The message dispatcher is a way to enable asynchronous communication
+ * through a channel. The dispatcher will look for the <code>Channel.SEND_OPTIONS_ASYNCHRONOUS</code>
+ * flag to be set, if it is, it will queue the message for delivery and immediately return to the sender.
+ * 
+ * 
+ * 
+ * @author Filip Hanik
+ * @version 1.0
+ */
+public class MessageDispatchInterceptor extends ChannelInterceptorBase implements Runnable {
+    protected static org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory.getLog(MessageDispatchInterceptor.class);
+
+    protected long maxQueueSize = 1024*1024*64; //64MB
+    protected FastQueue queue = new FastQueue();
+    protected boolean run = false;
+    protected Thread msgDispatchThread = null;
+    protected long currentSize = 0;
+    protected boolean useDeepClone = true;
+    protected boolean alwaysSend = true;
+
+    public MessageDispatchInterceptor() {
+        setOptionFlag(Channel.SEND_OPTIONS_ASYNCHRONOUS);
+    }
+
+    public void sendMessage(Member[] destination, ChannelMessage msg, InterceptorPayload payload) throws ChannelException {
+        boolean async = (msg.getOptions() & Channel.SEND_OPTIONS_ASYNCHRONOUS) == Channel.SEND_OPTIONS_ASYNCHRONOUS;
+        if ( async && run ) {
+            if ( (getCurrentSize()+msg.getMessage().getLength()) > maxQueueSize ) {
+                if ( alwaysSend ) {
+                    super.sendMessage(destination,msg,payload);
+                    return;
+                } else {
+                    throw new ChannelException("Asynchronous queue is full, reached its limit of " + maxQueueSize +" bytes, current:" + getCurrentSize() + " bytes.");
+                }//end if
+            }//end if
+            //add to queue
+            if ( useDeepClone ) msg = (ChannelMessage)msg.deepclone();
+            if (!addToQueue(msg, destination, payload) ) {
+                throw new ChannelException("Unable to add the message to the async queue, queue bug?");
+            }
+            addAndGetCurrentSize(msg.getMessage().getLength());
+        } else {
+            super.sendMessage(destination, msg, payload);
+        }
+    }
+    
+    public boolean addToQueue(ChannelMessage msg, Member[] destination, InterceptorPayload payload) {
+        return queue.add(msg,destination,payload);
+    }
+    
+    public LinkObject removeFromQueue() {
+        return queue.remove();
+    }
+    
+    public void startQueue() {
+        msgDispatchThread = new Thread(this);
+        msgDispatchThread.setName("MessageDispatchInterceptor.MessageDispatchThread");
+        msgDispatchThread.setDaemon(true);
+        msgDispatchThread.setPriority(Thread.MAX_PRIORITY);
+        queue.setEnabled(true);
+        run = true;
+        msgDispatchThread.start();
+    }
+    
+    public void stopQueue() {
+        run = false;
+        msgDispatchThread.interrupt();
+        queue.setEnabled(false);
+        setAndGetCurrentSize(0);
+    }
+    
+    
+    public void setOptionFlag(int flag) {
+        if ( flag != Channel.SEND_OPTIONS_ASYNCHRONOUS ) log.warn("Warning, you are overriding the asynchronous option flag, this will disable the Channel.SEND_OPTIONS_ASYNCHRONOUS that other apps might use.");
+        super.setOptionFlag(flag);
+    }
+
+    public void setMaxQueueSize(long maxQueueSize) {
+        this.maxQueueSize = maxQueueSize;
+    }
+
+    public void setUseDeepClone(boolean useDeepClone) {
+        this.useDeepClone = useDeepClone;
+    }
+
+    public long getMaxQueueSize() {
+        return maxQueueSize;
+    }
+
+    public boolean getUseDeepClone() {
+        return useDeepClone;
+    }
+    
+    public long getCurrentSize() {
+        return currentSize;
+    }
+    
+    public synchronized long addAndGetCurrentSize(long inc) {
+        currentSize += inc;
+        return currentSize;
+    }
+    
+    public synchronized long setAndGetCurrentSize(long value) {
+        currentSize = value;
+        return value;
+    }
+
+    public void start(int svc) throws ChannelException {
+        //start the thread
+        if (!run ) {
+            synchronized (this) {
+                if ( !run && ((svc & Channel.SND_TX_SEQ)==Channel.SND_TX_SEQ) ) {//only start with the sender
+                    startQueue();
+                }//end if
+            }//sync
+        }//end if
+        super.start(svc);
+    }
+
+    
+    public void stop(int svc) throws ChannelException {
+        //stop the thread
+        if ( run ) {
+            synchronized (this) {
+                if ( run && ((svc & Channel.SND_TX_SEQ)==Channel.SND_TX_SEQ)) {
+                    stopQueue();
+                }//end if
+            }//sync
+        }//end if
+
+        super.stop(svc);
+    }
+    
+    public void run() {
+        while ( run ) {
+            LinkObject link = removeFromQueue();
+            if ( link == null ) continue; //should not happen unless we exceed wait time
+            while ( link != null && run ) {
+                link = sendAsyncData(link);
+            }//while
+        }//while
+    }//run
+
+    protected LinkObject sendAsyncData(LinkObject link) {
+        ChannelMessage msg = link.data();
+        Member[] destination = link.getDestination();
+        try {
+            super.sendMessage(destination,msg,null);
+            try {
+                if ( link.getHandler() != null ) link.getHandler().handleCompletion(new UniqueId(msg.getUniqueId())); 
+            } catch ( Exception ex ) {
+                log.error("Unable to report back completed message.",ex);
+            }
+        } catch ( Exception x ) {
+            ChannelException cx = null;
+            if ( x instanceof ChannelException ) cx = (ChannelException)x;
+            else cx = new ChannelException(x);
+            if ( log.isDebugEnabled() ) log.debug("Error while processing async message.",x);
+            try {
+                if (link.getHandler() != null) link.getHandler().handleError(cx, new UniqueId(msg.getUniqueId()));
+            } catch ( Exception ex ) {
+                log.error("Unable to report back error message.",ex);
+            }
+        } finally {
+            addAndGetCurrentSize(-msg.getMessage().getLength());
+            link = link.next();
+        }//try
+        return link;
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/group/interceptors/NonBlockingCoordinator.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/group/interceptors/NonBlockingCoordinator.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/group/interceptors/NonBlockingCoordinator.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,839 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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
+ */
+package org.apache.catalina.tribes.group.interceptors;
+
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import org.apache.catalina.tribes.Channel;
+import org.apache.catalina.tribes.ChannelException;
+import org.apache.catalina.tribes.ChannelInterceptor;
+import org.apache.catalina.tribes.ChannelInterceptor.InterceptorEvent;
+import org.apache.catalina.tribes.ChannelMessage;
+import org.apache.catalina.tribes.Member;
+import org.apache.catalina.tribes.UniqueId;
+import org.apache.catalina.tribes.group.AbsoluteOrder;
+import org.apache.catalina.tribes.group.ChannelInterceptorBase;
+import org.apache.catalina.tribes.group.InterceptorPayload;
+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.util.Arrays;
+import org.apache.catalina.tribes.util.UUIDGenerator;
+
+/**
+ * <p>Title: Auto merging leader election algorithm</p>
+ *
+ * <p>Description: Implementation of a simple coordinator algorithm that not only selects a coordinator,
+ *    it also merges groups automatically when members are discovered that werent part of the 
+ *    </p>
+ * <p>This algorithm is non blocking meaning it allows for transactions while the coordination phase is going on
+ * </p>
+ * <p>This implementation is based on a home brewed algorithm that uses the AbsoluteOrder of a membership
+ * to pass a token ring of the current membership.<br>
+ * This is not the same as just using AbsoluteOrder! Consider the following scenario:<br>
+ * Nodes, A,B,C,D,E on a network, in that priority. AbsoluteOrder will only work if all
+ * nodes are receiving pings from all the other nodes. 
+ * meaning, that node{i} receives pings from node{all}-node{i}<br>
+ * but the following could happen if a multicast problem occurs.
+ * A has members {B,C,D}<br>
+ * B has members {A,C}<br>
+ * C has members {D,E}<br>
+ * D has members {A,B,C,E}<br>
+ * E has members {A,C,D}<br>
+ * Because the default Tribes membership implementation, relies on the multicast packets to 
+ * arrive at all nodes correctly, there is nothing guaranteeing that it will.<br>
+ * <br>
+ * To best explain how this algorithm works, lets take the above example:
+ * For simplicity we assume that a send operation is O(1) for all nodes, although this algorithm will work
+ * where messages overlap, as they all depend on absolute order<br>
+ * Scenario 1: A,B,C,D,E all come online at the same time
+ * Eval phase, A thinks of itself as leader, B thinks of A as leader,
+ * C thinks of itself as leader, D,E think of A as leader<br>
+ * Token phase:<br>
+ * (1) A sends out a message X{A-ldr, A-src, mbrs-A,B,C,D} to B where X is the id for the message(and the view)<br>
+ * (1) C sends out a message Y{C-ldr, C-src, mbrs-C,D,E} to D where Y is the id for the message(and the view)<br>
+ * (2) B receives X{A-ldr, A-src, mbrs-A,B,C,D}, sends X{A-ldr, A-src, mbrs-A,B,C,D} to C <br>
+ * (2) D receives Y{C-ldr, C-src, mbrs-C,D,E} D is aware of A,B, sends Y{A-ldr, C-src, mbrs-A,B,C,D,E} to E<br>
+ * (3) C receives X{A-ldr, A-src, mbrs-A,B,C,D}, sends X{A-ldr, A-src, mbrs-A,B,C,D,E} to D<br>
+ * (3) E receives Y{A-ldr, C-src, mbrs-A,B,C,D,E} sends Y{A-ldr, C-src, mbrs-A,B,C,D,E} to A<br>
+ * (4) D receives X{A-ldr, A-src, mbrs-A,B,C,D,E} sends sends X{A-ldr, A-src, mbrs-A,B,C,D,E} to A<br>
+ * (4) A receives Y{A-ldr, C-src, mbrs-A,B,C,D,E}, holds the message, add E to its list of members<br>
+ * (5) A receives X{A-ldr, A-src, mbrs-A,B,C,D,E} <br>
+ * At this point, the state looks like<br>
+ * A - {A-ldr, mbrs-A,B,C,D,E, id=X}<br>
+ * B - {A-ldr, mbrs-A,B,C,D, id=X}<br>
+ * C - {A-ldr, mbrs-A,B,C,D,E, id=X}<br>
+ * D - {A-ldr, mbrs-A,B,C,D,E, id=X}<br>
+ * E - {A-ldr, mbrs-A,B,C,D,E, id=Y}<br>
+ * <br>
+ * A message doesn't stop until it reaches its original sender, unless its dropped by a higher leader.
+ * As you can see, E still thinks the viewId=Y, which is not correct. But at this point we have 
+ * arrived at the same membership and all nodes are informed of each other.<br>
+ * To synchronize the rest we simply perform the following check at A when A receives X:<br>
+ * Original X{A-ldr, A-src, mbrs-A,B,C,D} == Arrived X{A-ldr, A-src, mbrs-A,B,C,D,E}<br>
+ * Since the condition is false, A, will resend the token, and A sends X{A-ldr, A-src, mbrs-A,B,C,D,E} to B
+ * When A receives X again, the token is complete. <br>
+ * Optionally, A can send a message X{A-ldr, A-src, mbrs-A,B,C,D,E confirmed} to A,B,C,D,E who then
+ * install and accept the view.
+ * </p>
+ * <p>
+ * Lets assume that C1 arrives, C1 has lower priority than C, but higher priority than D.<br>
+ * Lets also assume that C1 sees the following view {B,D,E}<br>
+ * C1 waits for a token to arrive. When the token arrives, the same scenario as above will happen.<br>
+ * In the scenario where C1 sees {D,E} and A,B,C can not see C1, no token will ever arrive.<br>
+ * In this case, C1 sends a Z{C1-ldr, C1-src, mbrs-C1,D,E} to D<br>
+ * D receives Z{C1-ldr, C1-src, mbrs-C1,D,E} and sends Z{A-ldr, C1-src, mbrs-A,B,C,C1,D,E} to E<br>
+ * E receives Z{A-ldr, C1-src, mbrs-A,B,C,C1,D,E} and sends it to A<br>
+ * A sends Z{A-ldr, A-src, mbrs-A,B,C,C1,D,E} to B and the chain continues until A receives the token again.
+ * At that time A optionally sends out Z{A-ldr, A-src, mbrs-A,B,C,C1,D,E, confirmed} to A,B,C,C1,D,E
+ * </p>
+ * <p>To ensure that the view gets implemented at all nodes at the same time, 
+ *    A will send out a VIEW_CONF message, this is the 'confirmed' message that is optional above.
+ * <p>Ideally, the interceptor below this one would be the TcpFailureDetector to ensure correct memberships</p>
+ *
+ * <p>The example above, of course can be simplified with a finite statemachine:<br>
+ * But I suck at writing state machines, my head gets all confused. One day I will document this algorithm though.<br>
+ * Maybe I'll do a state diagram :)
+ * </p>
+ * <h2>State Diagrams</h2>
+ * <a href="http://people.apache.org/~fhanik/tribes/docs/leader-election-initiate-election.jpg">Initiate an election</a><br><br>
+ * <a href="http://people.apache.org/~fhanik/tribes/docs/leader-election-message-arrives.jpg">Receive an election message</a><br><br>
+ * 
+ * @author Filip Hanik
+ * @version 1.0
+ * 
+ * 
+ * 
+ */
+public class NonBlockingCoordinator extends ChannelInterceptorBase {
+    
+    /**
+     * header for a coordination message
+     */
+    protected static final byte[] COORD_HEADER = new byte[] {-86, 38, -34, -29, -98, 90, 65, 63, -81, -122, -6, -110, 99, -54, 13, 63};
+    /**
+     * Coordination request
+     */
+    protected static final byte[] COORD_REQUEST = new byte[] {104, -95, -92, -42, 114, -36, 71, -19, -79, 20, 122, 101, -1, -48, -49, 30};
+    /**
+     * Coordination confirmation, for blocking installations
+     */
+    protected static final byte[] COORD_CONF = new byte[] {67, 88, 107, -86, 69, 23, 76, -70, -91, -23, -87, -25, -125, 86, 75, 20};
+    
+    /**
+     * Alive message
+     */
+    protected static final byte[] COORD_ALIVE = new byte[] {79, -121, -25, -15, -59, 5, 64, 94, -77, 113, -119, -88, 52, 114, -56, -46,
+                                                            -18, 102, 10, 34, -127, -9, 71, 115, -70, 72, -101, 88, 72, -124, 127, 111,
+                                                            74, 76, -116, 50, 111, 103, 65, 3, -77, 51, -35, 0, 119, 117, 9, -26,
+                                                            119, 50, -75, -105, -102, 36, 79, 37, -68, -84, -123, 15, -22, -109, 106, -55};
+    /**
+     * Time to wait for coordination timeout
+     */
+    protected long waitForCoordMsgTimeout = 15000;
+    /**
+     * Our current view
+     */
+    protected Membership view = null;
+    /**
+     * Out current viewId
+     */
+    protected UniqueId viewId;
+
+    /**
+     * Our nonblocking membership
+     */
+    protected Membership membership = null;
+    
+    /**
+     * indicates that we are running an election 
+     * and this is the one we are running
+     */
+    protected UniqueId suggestedviewId;
+    protected Membership suggestedView;
+    
+    protected boolean started = false;
+    protected final int startsvc = 0xFFFF;
+    
+    protected Object electionMutex = new Object();
+    
+    protected AtomicBoolean coordMsgReceived = new AtomicBoolean(false);
+    
+    public NonBlockingCoordinator() {
+        super();
+    }
+    
+//============================================================================================================    
+//              COORDINATION HANDLING
+//============================================================================================================
+    
+    public void startElection(boolean force) throws ChannelException {
+        synchronized (electionMutex) {
+            MemberImpl local = (MemberImpl)getLocalMember(false);
+            MemberImpl[] others = (MemberImpl[])membership.getMembers();
+            fireInterceptorEvent(new CoordinationEvent(CoordinationEvent.EVT_START_ELECT,this,"Election initated"));
+            if ( others.length == 0 ) {
+                this.viewId = new UniqueId(UUIDGenerator.randomUUID(false));
+                this.view = new Membership(local,AbsoluteOrder.comp, true);
+                this.handleViewConf(this.createElectionMsg(local,others,local),local,view);
+                return; //the only member, no need for an election
+            }
+            if ( suggestedviewId != null ) {
+                
+                if ( view != null && Arrays.diff(view,suggestedView,local).length == 0 &&  Arrays.diff(suggestedView,view,local).length == 0) {
+                    suggestedviewId = null;
+                    suggestedView = null;
+                    fireInterceptorEvent(new CoordinationEvent(CoordinationEvent.EVT_ELECT_ABANDONED,this,"Election abandoned, running election matches view"));
+                } else {
+                    fireInterceptorEvent(new CoordinationEvent(CoordinationEvent.EVT_ELECT_ABANDONED,this,"Election abandoned, election running"));
+                }
+                return; //election already running, I'm not allowed to have two of them
+            }
+            if ( view != null && Arrays.diff(view,membership,local).length == 0 &&  Arrays.diff(membership,view,local).length == 0) {
+                fireInterceptorEvent(new CoordinationEvent(CoordinationEvent.EVT_ELECT_ABANDONED,this,"Election abandoned, view matches membership"));
+                return; //already have this view installed
+            }            
+            int prio = AbsoluteOrder.comp.compare(local,others[0]);
+            MemberImpl leader = ( prio < 0 )?local:others[0];//am I the leader in my view?
+            if ( local.equals(leader) || force ) {
+                CoordinationMessage msg = createElectionMsg(local, others, leader);
+                suggestedviewId = msg.getId();
+                suggestedView = new Membership(local,AbsoluteOrder.comp,true);
+                Arrays.fill(suggestedView,msg.getMembers());
+                fireInterceptorEvent(new CoordinationEvent(CoordinationEvent.EVT_PROCESS_ELECT,this,"Election, sending request"));
+                sendElectionMsg(local,others[0],msg);
+            } else {
+                try {
+                    coordMsgReceived.set(false);
+                    fireInterceptorEvent(new CoordinationEvent(CoordinationEvent.EVT_WAIT_FOR_MSG,this,"Election, waiting for request"));
+                    electionMutex.wait(waitForCoordMsgTimeout);
+                }catch ( InterruptedException x ) {
+                    Thread.currentThread().interrupted();
+                }
+                if ( suggestedviewId == null && (!coordMsgReceived.get())) {
+                    //no message arrived, send the coord msg
+//                    fireInterceptorEvent(new CoordinationEvent(CoordinationEvent.EVT_WAIT_FOR_MSG,this,"Election, waiting timed out."));
+//                    startElection(true);
+                    fireInterceptorEvent(new CoordinationEvent(CoordinationEvent.EVT_ELECT_ABANDONED,this,"Election abandoned, waiting timed out."));
+                } else {
+                    fireInterceptorEvent(new CoordinationEvent(CoordinationEvent.EVT_ELECT_ABANDONED,this,"Election abandoned, received a message"));
+                }
+            }//end if
+            
+        }
+    }
+
+    private CoordinationMessage createElectionMsg(MemberImpl local, MemberImpl[] others, MemberImpl leader) {
+        Membership m = new Membership(local,AbsoluteOrder.comp,true);
+        Arrays.fill(m,others);
+        MemberImpl[] mbrs = m.getMembers();
+        m.reset(); 
+        CoordinationMessage msg = new CoordinationMessage(leader, local, mbrs,new UniqueId(UUIDGenerator.randomUUID(true)), this.COORD_REQUEST);
+        return msg;
+    }
+
+    protected void sendElectionMsg(MemberImpl local, MemberImpl next, CoordinationMessage msg) throws ChannelException {
+        fireInterceptorEvent(new CoordinationEvent(CoordinationEvent.EVT_SEND_MSG,this,"Sending election message to("+next.getName()+")"));
+        super.sendMessage(new Member[] {next}, createData(msg, local), null);
+    }
+    
+    protected void sendElectionMsgToNextInline(MemberImpl local, CoordinationMessage msg) throws ChannelException { 
+        int next = Arrays.nextIndex(local,msg.getMembers());
+        int current = next;
+        msg.leader = msg.getMembers()[0];
+        boolean sent =  false;
+        while ( !sent && current >= 0 ) {
+            try {
+                sendElectionMsg(local, (MemberImpl) msg.getMembers()[current], msg);
+                sent = true;
+            }catch ( ChannelException x  ) {
+                log.warn("Unable to send election message to:"+msg.getMembers()[current]);
+                current = Arrays.nextIndex(msg.getMembers()[current],msg.getMembers());
+                if ( current == next ) throw x;
+            }
+        }
+    }
+    
+    public Member getNextInLine(MemberImpl local, MemberImpl[] others) {
+        MemberImpl result = null;
+        for ( int i=0; i<others.length; i++ ) {
+            
+        }
+        return result;
+    }
+    
+    public ChannelData createData(CoordinationMessage msg, MemberImpl local) {
+        msg.write();
+        ChannelData data = new ChannelData(true);
+        data.setAddress(local);
+        data.setMessage(msg.getBuffer());
+        data.setOptions(Channel.SEND_OPTIONS_USE_ACK);
+        data.setTimestamp(System.currentTimeMillis());
+        return data;
+    }
+    
+    protected void viewChange(UniqueId viewId, Member[] view) {
+        //invoke any listeners
+    }
+    
+    protected boolean alive(Member mbr) {
+        return TcpFailureDetector.memberAlive(mbr,
+                                              COORD_ALIVE,
+                                              false,
+                                              false,
+                                              waitForCoordMsgTimeout,
+                                              waitForCoordMsgTimeout,
+                                              getOptionFlag());
+    }
+    
+    protected Membership mergeOnArrive(CoordinationMessage msg, Member sender) {
+        fireInterceptorEvent(new CoordinationEvent(CoordinationEvent.EVT_PRE_MERGE,this,"Pre merge"));
+        MemberImpl local = (MemberImpl)getLocalMember(false);
+        Membership merged = new Membership(local,AbsoluteOrder.comp,true);
+        Arrays.fill(merged,msg.getMembers());
+        Arrays.fill(merged,getMembers());
+        Member[] diff = Arrays.diff(merged,membership,local);
+        for ( int i=0; i<diff.length; i++ ) {
+            if (!alive(diff[i])) merged.removeMember((MemberImpl)diff[i]);
+            else memberAdded(diff[i],false);
+        }
+        fireInterceptorEvent(new CoordinationEvent(CoordinationEvent.EVT_POST_MERGE,this,"Post merge"));
+        return merged;
+    }
+    
+    protected void processCoordMessage(CoordinationMessage msg, Member sender) throws ChannelException {
+        if ( !coordMsgReceived.get() ) {
+            coordMsgReceived.set(true);
+            synchronized (electionMutex) { electionMutex.notifyAll();}
+        } 
+        msg.timestamp = System.currentTimeMillis();
+        Membership merged = mergeOnArrive(msg, sender);
+        if (isViewConf(msg)) handleViewConf(msg, sender, merged);
+        else handleToken(msg, sender, merged);
+        ClassLoader loader;
+
+    }
+    
+    protected void handleToken(CoordinationMessage msg, Member sender,Membership merged) throws ChannelException {
+        MemberImpl local = (MemberImpl)getLocalMember(false);
+        if ( local.equals(msg.getSource()) ) {
+            //my message msg.src=local
+            handleMyToken(local, msg, sender,merged);
+        } else {
+            handleOtherToken(local, msg, sender,merged);
+        }
+    }
+    
+    protected void handleMyToken(MemberImpl local, CoordinationMessage msg, Member sender,Membership merged) throws ChannelException {
+        if ( local.equals(msg.getLeader()) ) {
+            //no leadership change
+            if ( Arrays.sameMembers(msg.getMembers(),merged.getMembers()) ) {
+                msg.type = COORD_CONF;
+                super.sendMessage(Arrays.remove(msg.getMembers(),local),createData(msg,local),null);
+                handleViewConf(msg,local,merged);
+            } else {
+                //membership change
+                suggestedView = new Membership(local,AbsoluteOrder.comp,true);
+                suggestedviewId = msg.getId();
+                Arrays.fill(suggestedView,merged.getMembers());
+                msg.view = (MemberImpl[])merged.getMembers();
+                sendElectionMsgToNextInline(local,msg);
+            }
+        } else {
+            //leadership change
+            suggestedView = null;
+            suggestedviewId = null;
+            msg.view = (MemberImpl[])merged.getMembers();
+            sendElectionMsgToNextInline(local,msg);
+        }
+    }
+    
+    protected void handleOtherToken(MemberImpl local, CoordinationMessage msg, Member sender,Membership merged) throws ChannelException {
+        if ( local.equals(msg.getLeader()) ) {
+            //I am the new leader
+            //startElection(false);
+        } else {
+            msg.view = (MemberImpl[])merged.getMembers();
+            sendElectionMsgToNextInline(local,msg);
+        }
+    }
+    
+    protected void handleViewConf(CoordinationMessage msg, Member sender,Membership merged) throws ChannelException {
+        if ( viewId != null && msg.getId().equals(viewId) ) return;//we already have this view
+        view = new Membership((MemberImpl)getLocalMember(false),AbsoluteOrder.comp,true);
+        Arrays.fill(view,msg.getMembers());
+        viewId = msg.getId();
+        
+        if ( viewId.equals(suggestedviewId) ) {
+            suggestedView = null;
+            suggestedviewId = null;
+        }
+        
+        if (suggestedView != null && AbsoluteOrder.comp.compare(suggestedView.getMembers()[0],merged.getMembers()[0])<0 ) {
+            suggestedView = null;
+            suggestedviewId = null;
+        }
+        
+        viewChange(viewId,view.getMembers());
+        fireInterceptorEvent(new CoordinationEvent(CoordinationEvent.EVT_CONF_RX,this,"Accepted View"));
+        
+        if ( suggestedviewId == null && hasHigherPriority(merged.getMembers(),membership.getMembers()) ) {
+            startElection(false);
+        }
+    }
+    
+    protected boolean isViewConf(CoordinationMessage msg) {
+        return Arrays.contains(msg.getType(),0,COORD_CONF,0,COORD_CONF.length);
+    }
+    
+    protected boolean hasHigherPriority(Member[] complete, Member[] local) {
+        if ( local == null || local.length == 0 ) return false;
+        if ( complete == null || complete.length == 0 ) return true;
+        AbsoluteOrder.absoluteOrder(complete);
+        AbsoluteOrder.absoluteOrder(local);
+        return (AbsoluteOrder.comp.compare(complete[0],local[0]) > 0);
+        
+    }
+
+    
+    /**
+     * Returns coordinator if one is available
+     * @return Member
+     */
+    public Member getCoordinator() {
+        return (view != null && view.hasMembers()) ? view.getMembers()[0] : null;
+    }
+    
+    public Member[] getView() {
+        return (view != null && view.hasMembers()) ? view.getMembers() : new Member[0];
+    }
+    
+    public UniqueId getViewId() {
+        return viewId;
+    }
+    
+    /**
+    * Block in/out messages while a election is going on
+    */
+   protected void halt() {
+
+   }
+
+   /**
+    * Release lock for in/out messages election is completed
+    */
+   protected void release() {
+
+   }
+
+   /**
+    * Wait for an election to end
+    */
+   protected void waitForRelease() {
+
+   }
+
+    
+//============================================================================================================    
+//              OVERRIDDEN METHODS FROM CHANNEL INTERCEPTOR BASE    
+//============================================================================================================
+    public void start(int svc) throws ChannelException {
+            if (membership == null) setupMembership();
+            if (started)return;
+            fireInterceptorEvent(new CoordinationEvent(CoordinationEvent.EVT_START, this, "Before start"));
+            super.start(startsvc);
+            started = true;
+            if (view == null) view = new Membership( (MemberImpl)super.getLocalMember(true), AbsoluteOrder.comp, true);
+            fireInterceptorEvent(new CoordinationEvent(CoordinationEvent.EVT_START, this, "After start"));
+            startElection(false);
+    }
+
+    public void stop(int svc) throws ChannelException {
+        try {
+            halt();
+            synchronized (electionMutex) {
+                if (!started)return;
+                started = false;
+                fireInterceptorEvent(new CoordinationEvent(CoordinationEvent.EVT_STOP, this, "Before stop"));
+                super.stop(startsvc);
+                this.view = null;
+                this.viewId = null;
+                this.suggestedView = null;
+                this.suggestedviewId = null;
+                this.membership.reset();
+                fireInterceptorEvent(new CoordinationEvent(CoordinationEvent.EVT_STOP, this, "After stop"));
+            }
+        }finally {
+            release();
+        }
+    }
+    
+    
+    public void sendMessage(Member[] destination, ChannelMessage msg, InterceptorPayload payload) throws ChannelException {
+        waitForRelease();
+        super.sendMessage(destination, msg, payload);
+    }
+
+    public void messageReceived(ChannelMessage msg) {
+        if ( Arrays.contains(msg.getMessage().getBytesDirect(),0,COORD_ALIVE,0,COORD_ALIVE.length) ) {
+            //ignore message, its an alive message
+            fireInterceptorEvent(new CoordinationEvent(CoordinationEvent.EVT_MSG_ARRIVE,this,"Alive Message"));
+
+        } else if ( Arrays.contains(msg.getMessage().getBytesDirect(),0,COORD_HEADER,0,COORD_HEADER.length) ) {
+            try {
+                CoordinationMessage cmsg = new CoordinationMessage(msg.getMessage());
+                Member[] cmbr = cmsg.getMembers();
+                fireInterceptorEvent(new CoordinationEvent(CoordinationEvent.EVT_MSG_ARRIVE,this,"Coord Msg Arrived("+Arrays.toNameString(cmbr)+")"));
+                processCoordMessage(cmsg, msg.getAddress());
+            }catch ( ChannelException x ) {
+                log.error("Error processing coordination message. Could be fatal.",x);
+            }
+        } else {
+            super.messageReceived(msg);
+        }
+    }
+
+    public boolean accept(ChannelMessage msg) {
+        return super.accept(msg);
+    }
+
+    public void memberAdded(Member member) {
+        memberAdded(member,true);
+    }
+
+    public void memberAdded(Member member,boolean elect) {
+        try {
+            if ( membership == null ) setupMembership();
+            if ( membership.memberAlive((MemberImpl)member) ) super.memberAdded(member);
+            try {
+                fireInterceptorEvent(new CoordinationEvent(CoordinationEvent.EVT_MBR_ADD,this,"Member add("+member.getName()+")"));
+                if (started && elect) startElection(false);
+            }catch ( ChannelException x ) {
+                log.error("Unable to start election when member was added.",x);
+            }
+        }finally {
+        }
+        
+    }
+
+    public void memberDisappeared(Member member) {
+        try {
+            
+            membership.removeMember((MemberImpl)member);
+            super.memberDisappeared(member);
+            try {
+                fireInterceptorEvent(new CoordinationEvent(CoordinationEvent.EVT_MBR_DEL,this,"Member remove("+member.getName()+")"));
+                if ( started && (isCoordinator() || isHighest()) ) 
+                    startElection(true); //to do, if a member disappears, only the coordinator can start
+            }catch ( ChannelException x ) {
+                log.error("Unable to start election when member was removed.",x);
+            }
+        }finally {
+        }
+    }
+    
+    public boolean isHighest() {
+        Member local = getLocalMember(false);
+        if ( membership.getMembers().length == 0 ) return true;
+        else return AbsoluteOrder.comp.compare(local,membership.getMembers()[0])<=0;
+    }
+    
+    public boolean isCoordinator() {
+        Member coord = getCoordinator();
+        return coord != null && getLocalMember(false).equals(coord);
+    }
+
+    public void heartbeat() {
+        try {
+            MemberImpl local = (MemberImpl)getLocalMember(false);
+            if ( view != null && (Arrays.diff(view,membership,local).length != 0 ||  Arrays.diff(membership,view,local).length != 0) ) {
+                if ( isHighest() ) {
+                    fireInterceptorEvent(new CoordinationEvent(CoordinationEvent.EVT_START_ELECT, this,
+                                                               "Heartbeat found inconsistency, restart election"));
+                    startElection(true);
+                }            
+            }
+        } catch ( Exception x  ){
+            log.error("Unable to perform heartbeat.",x);
+        } finally {
+            super.heartbeat();
+        }
+    }
+
+    /**
+     * has members
+     */
+    public boolean hasMembers() {
+        
+        return membership.hasMembers();
+    }
+
+    /**
+     * Get all current cluster members
+     * @return all members or empty array
+     */
+    public Member[] getMembers() {
+        
+        return membership.getMembers();
+    }
+
+    /**
+     *
+     * @param mbr Member
+     * @return Member
+     */
+    public Member getMember(Member mbr) {
+        
+        return membership.getMember(mbr);
+    }
+
+    /**
+     * Return the member that represents this node.
+     *
+     * @return Member
+     */
+    public Member getLocalMember(boolean incAlive) {
+        Member local = super.getLocalMember(incAlive);
+        if ( view == null && (local != null)) setupMembership();
+        return local;
+    }
+    
+    protected synchronized void setupMembership() {
+        if ( membership == null ) {
+            membership  = new Membership((MemberImpl)super.getLocalMember(true),AbsoluteOrder.comp,false);
+        }
+    }
+    
+    
+//============================================================================================================    
+//              HELPER CLASSES FOR COORDINATION
+//============================================================================================================
+    
+    
+   
+    
+    public static class CoordinationMessage {
+        //X{A-ldr, A-src, mbrs-A,B,C,D}
+        protected XByteBuffer buf;
+        protected MemberImpl leader;
+        protected MemberImpl source;
+        protected MemberImpl[] view;
+        protected UniqueId id;
+        protected byte[] type;
+        protected long timestamp = System.currentTimeMillis();
+        
+        public CoordinationMessage(XByteBuffer buf) {
+            this.buf = buf;
+            parse();
+        }
+
+        public CoordinationMessage(MemberImpl leader,
+                                   MemberImpl source, 
+                                   MemberImpl[] view,
+                                   UniqueId id,
+                                   byte[] type) {
+            this.buf = new XByteBuffer(4096,false);
+            this.leader = leader;
+            this.source = source;
+            this.view = view;
+            this.id = id;
+            this.type = type;
+            this.write();
+        }
+        
+
+        public byte[] getHeader() {
+            return NonBlockingCoordinator.COORD_HEADER;
+        }
+        
+        public MemberImpl getLeader() {
+            if ( leader == null ) parse();
+            return leader;
+        }
+        
+        public MemberImpl getSource() {
+            if ( source == null ) parse();
+            return source;
+        }
+        
+        public UniqueId getId() {
+            if ( id == null ) parse();
+            return id;
+        }
+        
+        public MemberImpl[] getMembers() {
+            if ( view == null ) parse();
+            return view;
+        }
+        
+        public byte[] getType() {
+            if (type == null ) parse();
+            return type;
+        }
+        
+        public XByteBuffer getBuffer() {
+            return this.buf;
+        }
+        
+        public void parse() {
+            //header
+            int offset = 16;
+            //leader
+            int ldrLen = buf.toInt(buf.getBytesDirect(),offset);
+            offset += 4;
+            byte[] ldr = new byte[ldrLen];
+            System.arraycopy(buf.getBytesDirect(),offset,ldr,0,ldrLen);
+            leader = MemberImpl.getMember(ldr);
+            offset += ldrLen;
+            //source
+            int srcLen = buf.toInt(buf.getBytesDirect(),offset);
+            offset += 4;
+            byte[] src = new byte[srcLen];
+            System.arraycopy(buf.getBytesDirect(),offset,src,0,srcLen);
+            source = MemberImpl.getMember(src);
+            offset += srcLen;
+            //view
+            int mbrCount = buf.toInt(buf.getBytesDirect(),offset);
+            offset += 4;
+            view = new MemberImpl[mbrCount];
+            for (int i=0; i<view.length; i++ ) {
+                int mbrLen = buf.toInt(buf.getBytesDirect(),offset);
+                offset += 4;
+                byte[] mbr = new byte[mbrLen];
+                System.arraycopy(buf.getBytesDirect(), offset, mbr, 0, mbrLen);
+                view[i] = MemberImpl.getMember(mbr);
+                offset += mbrLen;
+            }
+            //id
+            this.id = new UniqueId(buf.getBytesDirect(),offset,16);
+            offset += 16;
+            type = new byte[16];
+            System.arraycopy(buf.getBytesDirect(), offset, type, 0, type.length);
+            offset += 16;
+            
+        }
+        
+        public void write() {
+            buf.reset();
+            //header
+            buf.append(COORD_HEADER,0,COORD_HEADER.length);
+            //leader
+            byte[] ldr = leader.getData(false,false);
+            buf.append(ldr.length);
+            buf.append(ldr,0,ldr.length);
+            ldr = null;
+            //source
+            byte[] src = source.getData(false,false);
+            buf.append(src.length);
+            buf.append(src,0,src.length);
+            src = null;
+            //view
+            buf.append(view.length);
+            for (int i=0; i<view.length; i++ ) {
+                byte[] mbr = view[i].getData(false,false);
+                buf.append(mbr.length);
+                buf.append(mbr,0,mbr.length);
+            }
+            //id
+            buf.append(id.getBytes(),0,id.getBytes().length);
+            buf.append(type,0,type.length);
+        }
+    }
+    
+    public void fireInterceptorEvent(InterceptorEvent event) {
+        if (event instanceof CoordinationEvent &&
+            ((CoordinationEvent)event).type == CoordinationEvent.EVT_CONF_RX) 
+            log.info(event);
+    }
+    
+    public static class CoordinationEvent implements InterceptorEvent {
+        public static final int EVT_START = 1;
+        public static final int EVT_MBR_ADD = 2;
+        public static final int EVT_MBR_DEL = 3;
+        public static final int EVT_START_ELECT = 4;
+        public static final int EVT_PROCESS_ELECT = 5;
+        public static final int EVT_MSG_ARRIVE = 6;
+        public static final int EVT_PRE_MERGE = 7;
+        public static final int EVT_POST_MERGE = 8;
+        public static final int EVT_WAIT_FOR_MSG = 9;
+        public static final int EVT_SEND_MSG = 10;
+        public static final int EVT_STOP = 11;
+        public static final int EVT_CONF_RX = 12;
+        public static final int EVT_ELECT_ABANDONED = 13;
+        
+        int type;
+        ChannelInterceptor interceptor;
+        Member coord; 
+        Member[] mbrs;
+        String info;
+        Membership view;
+        Membership suggestedView;
+        public CoordinationEvent(int type,ChannelInterceptor interceptor, String info) {
+            this.type = type;
+            this.interceptor = interceptor;
+            this.coord = ((NonBlockingCoordinator)interceptor).getCoordinator();
+            this.mbrs = ((NonBlockingCoordinator)interceptor).membership.getMembers();
+            this.info = info;
+            this.view = ((NonBlockingCoordinator)interceptor).view;
+            this.suggestedView = ((NonBlockingCoordinator)interceptor).suggestedView;
+        }
+        
+        public int getEventType() {
+            return type;
+        }
+        
+        public String getEventTypeDesc() {
+            switch (type) {
+                case  EVT_START: return "EVT_START:"+info;
+                case  EVT_MBR_ADD: return "EVT_MBR_ADD:"+info;
+                case  EVT_MBR_DEL: return "EVT_MBR_DEL:"+info;
+                case  EVT_START_ELECT: return "EVT_START_ELECT:"+info;
+                case  EVT_PROCESS_ELECT: return "EVT_PROCESS_ELECT:"+info;
+                case  EVT_MSG_ARRIVE: return "EVT_MSG_ARRIVE:"+info;
+                case  EVT_PRE_MERGE: return "EVT_PRE_MERGE:"+info;
+                case  EVT_POST_MERGE: return "EVT_POST_MERGE:"+info;
+                case  EVT_WAIT_FOR_MSG: return "EVT_WAIT_FOR_MSG:"+info;
+                case  EVT_SEND_MSG: return "EVT_SEND_MSG:"+info;
+                case  EVT_STOP: return "EVT_STOP:"+info;
+                case  EVT_CONF_RX: return "EVT_CONF_RX:"+info;
+                case EVT_ELECT_ABANDONED: return "EVT_ELECT_ABANDONED:"+info;
+                default: return "Unknown";
+            }
+        }
+        
+        public ChannelInterceptor getInterceptor() {
+            return interceptor;
+        }
+        
+        public String toString() {
+            StringBuffer buf = new StringBuffer("CoordinationEvent[type=");
+            buf.append(type).append("\n\tLocal:");
+            Member local = interceptor.getLocalMember(false);
+            buf.append(local!=null?local.getName():"").append("\n\tCoord:");
+            buf.append(coord!=null?coord.getName():"").append("\n\tView:");
+            buf.append(Arrays.toNameString(view!=null?view.getMembers():null)).append("\n\tSuggested View:");
+            buf.append(Arrays.toNameString(suggestedView!=null?suggestedView.getMembers():null)).append("\n\tMembers:");
+            buf.append(Arrays.toNameString(mbrs)).append("\n\tInfo:");
+            buf.append(info).append("]");
+            return buf.toString();
+        }
+    }
+
+    
+
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/group/interceptors/OrderInterceptor.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/group/interceptors/OrderInterceptor.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/group/interceptors/OrderInterceptor.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,298 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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
+ */
+
+package org.apache.catalina.tribes.group.interceptors;
+
+import java.util.HashMap;
+
+import org.apache.catalina.tribes.ChannelException;
+import org.apache.catalina.tribes.ChannelMessage;
+import org.apache.catalina.tribes.Member;
+import org.apache.catalina.tribes.group.ChannelInterceptorBase;
+import org.apache.catalina.tribes.group.InterceptorPayload;
+import org.apache.catalina.tribes.io.XByteBuffer;
+
+
+
+/**
+ *
+ * The order interceptor guarantees that messages are received in the same order they were 
+ * sent.
+ * This interceptor works best with the ack=true setting. <br>
+ * There is no point in 
+ * using this with the replicationMode="fastasynchqueue" as this mode guarantees ordering.<BR>
+ * If you are using the mode ack=false replicationMode=pooled, and have a lot of concurrent threads,
+ * this interceptor can really slow you down, as many messages will be completely out of order
+ * and the queue might become rather large. If this is the case, then you might want to set 
+ * the value OrderInterceptor.maxQueue = 25 (meaning that we will never keep more than 25 messages in our queue)
+ * <br><b>Configuration Options</b><br>
+ * OrderInteceptor.expire=<milliseconds> - if a message arrives out of order, how long before we act on it <b>default=3000ms</b><br>
+ * OrderInteceptor.maxQueue=<max queue size> - how much can the queue grow to ensure ordering. 
+ *   This setting is useful to avoid OutOfMemoryErrors<b>default=Integer.MAX_VALUE</b><br>
+ * OrderInterceptor.forwardExpired=<boolean> - this flag tells the interceptor what to 
+ * do when a message has expired or the queue has grown larger than the maxQueue value.
+ * true means that the message is sent up the stack to the receiver that will receive and out of order message
+ * false means, forget the message and reset the message counter. <b>default=true</b>
+ * 
+ * 
+ * @author Filip Hanik
+ * @version 1.0
+ */
+public class OrderInterceptor extends ChannelInterceptorBase {
+    private HashMap outcounter = new HashMap();
+    private HashMap incounter = new HashMap();
+    private HashMap incoming = new HashMap();
+    private long expire = 3000;
+    private boolean forwardExpired = true;
+    private int maxQueue = Integer.MAX_VALUE;
+
+    public void sendMessage(Member[] destination, ChannelMessage msg, InterceptorPayload payload) throws ChannelException {
+        for ( int i=0; i<destination.length; i++ ) {
+            int nr = incCounter(destination[i]);
+            //reduce byte copy
+            msg.getMessage().append(nr);
+            try {
+                getNext().sendMessage(new Member[] {destination[i]}, msg, payload);
+            }finally {
+                msg.getMessage().trim(4);
+            }
+        }
+    }
+
+    public void messageReceived(ChannelMessage msg) {
+        int msgnr = XByteBuffer.toInt(msg.getMessage().getBytesDirect(),msg.getMessage().getLength()-4);
+        msg.getMessage().trim(4);
+        MessageOrder order = new MessageOrder(msgnr,(ChannelMessage)msg.deepclone());
+        if ( processIncoming(order) ) processLeftOvers(msg.getAddress(),false);
+    }
+    
+    public synchronized void processLeftOvers(Member member, boolean force) {
+        MessageOrder tmp = (MessageOrder)incoming.get(member);
+        if ( force ) {
+            Counter cnt = getInCounter(member);
+            cnt.setCounter(Integer.MAX_VALUE);
+        }
+        if ( tmp!= null ) processIncoming(tmp);
+    }
+    /**
+     * 
+     * @param order MessageOrder
+     * @return boolean - true if a message expired and was processed
+     */
+    public synchronized boolean processIncoming(MessageOrder order) {
+        boolean result = false;
+        Member member = order.getMessage().getAddress();
+        Counter cnt = getInCounter(member);
+        
+        MessageOrder tmp = (MessageOrder)incoming.get(member);
+        if ( tmp != null ) {
+            order = MessageOrder.add(tmp,order);
+        }
+        
+        
+        while ( (order!=null) && (order.getMsgNr() <= cnt.getCounter())  ) {
+            //we are right on target. process orders
+            if ( order.getMsgNr() == cnt.getCounter() ) cnt.inc();
+            else if ( order.getMsgNr() > cnt.getCounter() ) cnt.setCounter(order.getMsgNr());
+            super.messageReceived(order.getMessage());
+            order.setMessage(null);
+            order = order.next;
+        }
+        MessageOrder head = order;
+        MessageOrder prev = null;
+        tmp = order;
+        //flag to empty out the queue when it larger than maxQueue
+        boolean empty = order!=null?order.getCount()>=maxQueue:false;
+        while ( tmp != null ) {
+            //process expired messages or empty out the queue
+            if ( tmp.isExpired(expire) || empty ) {
+                //reset the head
+                if ( tmp == head ) head = tmp.next;
+                cnt.setCounter(tmp.getMsgNr()+1);
+                if ( getForwardExpired() ) super.messageReceived(tmp.getMessage());
+                tmp.setMessage(null);
+                tmp = tmp.next;
+                if ( prev != null ) prev.next = tmp;  
+                result = true;
+            } else {
+                prev = tmp;
+                tmp = tmp.next;
+            }
+        }
+        if ( head == null ) incoming.remove(member);
+        else incoming.put(member, head);
+        return result;
+    }
+    
+    public void memberAdded(Member member) {
+        //notify upwards
+        getInCounter(member);
+        getOutCounter(member);
+        super.memberAdded(member);
+    }
+
+    public void memberDisappeared(Member member) {
+        //notify upwards
+        outcounter.remove(member);
+        incounter.remove(member);
+        //clear the remaining queue
+        processLeftOvers(member,true);
+        super.memberDisappeared(member);
+    }
+    
+    public int incCounter(Member mbr) { 
+        Counter cnt = getOutCounter(mbr);
+        return cnt.inc();
+    }
+    
+    public synchronized Counter getInCounter(Member mbr) {
+        Counter cnt = (Counter)incounter.get(mbr);
+        if ( cnt == null ) {
+            cnt = new Counter();
+            cnt.inc(); //always start at 1 for incoming
+            incounter.put(mbr,cnt);
+        }
+        return cnt;
+    }
+
+    public synchronized Counter getOutCounter(Member mbr) {
+        Counter cnt = (Counter)outcounter.get(mbr);
+        if ( cnt == null ) {
+            cnt = new Counter();
+            outcounter.put(mbr,cnt);
+        }
+        return cnt;
+    }
+
+    public static class Counter {
+        private int value = 0;
+        
+        public int getCounter() {
+            return value;
+        }
+        
+        public synchronized void setCounter(int counter) {
+            this.value = counter;
+        }
+        
+        public synchronized int inc() {
+            return ++value;
+        }
+    }
+    
+    public static class MessageOrder {
+        private long received = System.currentTimeMillis();
+        private MessageOrder next;
+        private int msgNr;
+        private ChannelMessage msg = null;
+        public MessageOrder(int msgNr,ChannelMessage msg) {
+            this.msgNr = msgNr;
+            this.msg = msg;
+        }
+        
+        public boolean isExpired(long expireTime) {
+            return (System.currentTimeMillis()-received) > expireTime;
+        }
+        
+        public ChannelMessage getMessage() {
+            return msg;
+        }
+        
+        public void setMessage(ChannelMessage msg) {
+            this.msg = msg;
+        }
+        
+        public void setNext(MessageOrder order) {
+            this.next = order;
+        }
+        public MessageOrder getNext() {
+            return next;
+        }
+        
+        public int getCount() {
+            int counter = 1;
+            MessageOrder tmp = next;
+            while ( tmp != null ) {
+                counter++;
+                tmp = tmp.next;
+            }
+            return counter;
+        }
+        
+        public static MessageOrder add(MessageOrder head, MessageOrder add) {
+            if ( head == null ) return add;
+            if ( add == null ) return head;
+            if ( head == add ) return add;
+
+            if ( head.getMsgNr() > add.getMsgNr() ) {
+                add.next = head;
+                return add;
+            }
+            
+            MessageOrder iter = head;
+            MessageOrder prev = null;
+            while ( iter.getMsgNr() < add.getMsgNr() && (iter.next !=null ) ) {
+                prev = iter;
+                iter = iter.next;
+            }
+            if ( iter.getMsgNr() < add.getMsgNr() ) {
+                //add after
+                add.next = iter.next;
+                iter.next = add;
+            } else if (iter.getMsgNr() > add.getMsgNr()) {
+                //add before
+                prev.next = add;
+                add.next = iter;
+                
+            } else {
+                throw new ArithmeticException("Message added has the same counter, synchronization bug. Disable the order interceptor");
+            }
+            
+            return head;
+        }
+        
+        public int getMsgNr() {
+            return msgNr;
+        }
+        
+        
+        
+    }
+
+    public void setExpire(long expire) {
+        this.expire = expire;
+    }
+
+    public void setForwardExpired(boolean forwardExpired) {
+        this.forwardExpired = forwardExpired;
+    }
+
+    public void setMaxQueue(int maxQueue) {
+        this.maxQueue = maxQueue;
+    }
+
+    public long getExpire() {
+        return expire;
+    }
+
+    public boolean getForwardExpired() {
+        return forwardExpired;
+    }
+
+    public int getMaxQueue() {
+        return maxQueue;
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/group/interceptors/StaticMembershipInterceptor.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/group/interceptors/StaticMembershipInterceptor.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/group/interceptors/StaticMembershipInterceptor.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,101 @@
+package org.apache.catalina.tribes.group.interceptors;
+
+import org.apache.catalina.tribes.group.ChannelInterceptorBase;
+import org.apache.catalina.tribes.Member;
+import java.util.ArrayList;
+import org.apache.catalina.tribes.group.AbsoluteOrder;
+import org.apache.catalina.tribes.ChannelException;
+import org.apache.catalina.tribes.Channel;
+
+public class StaticMembershipInterceptor
+    extends ChannelInterceptorBase {
+    protected ArrayList members = new ArrayList();
+    protected Member localMember = null;
+
+    public StaticMembershipInterceptor() {
+        super();
+    }
+
+    public void addStaticMember(Member member) {
+        synchronized (members) {
+            if (!members.contains(member)) members.add(member);
+        }
+    }
+
+    public void removeStaticMember(Member member) {
+        synchronized (members) {
+            if (members.contains(member)) members.remove(member);
+        }
+    }
+
+    public void setLocalMember(Member member) {
+        this.localMember = member;
+    }
+
+    /**
+     * has members
+     */
+    public boolean hasMembers() {
+        return super.hasMembers() || (members.size()>0);
+    }
+
+    /**
+     * Get all current cluster members
+     * @return all members or empty array
+     */
+    public Member[] getMembers() {
+        if ( members.size() == 0 ) return super.getMembers();
+        else {
+            synchronized (members) {
+                Member[] others = super.getMembers();
+                Member[] result = new Member[members.size() + others.length];
+                for (int i = 0; i < others.length; i++) result[i] = others[i];
+                for (int i = 0; i < members.size(); i++) result[i + others.length] = (Member) members.get(i);
+                AbsoluteOrder.absoluteOrder(result);
+                return result;
+            }//sync
+        }//end if
+    }
+
+    /**
+     *
+     * @param mbr Member
+     * @return Member
+     */
+    public Member getMember(Member mbr) {
+        if ( members.contains(mbr) ) return (Member)members.get(members.indexOf(mbr));
+        else return super.getMember(mbr);
+    }
+
+    /**
+     * Return the member that represents this node.
+     *
+     * @return Member
+     */
+    public Member getLocalMember(boolean incAlive) {
+        if (this.localMember != null ) return localMember;
+        else return super.getLocalMember(incAlive);
+    }
+    
+    /**
+     * Send notifications upwards
+     * @param svc int
+     * @throws ChannelException
+     */
+    public void start(int svc) throws ChannelException {
+        if ( (Channel.SND_RX_SEQ&svc)==Channel.SND_RX_SEQ ) super.start(Channel.SND_RX_SEQ); 
+        if ( (Channel.SND_TX_SEQ&svc)==Channel.SND_TX_SEQ ) super.start(Channel.SND_TX_SEQ); 
+        final Member[] mbrs = (Member[])members.toArray(new Member[members.size()]);
+        final ChannelInterceptorBase base = this;
+        Thread t = new Thread() {
+            public void run() {
+                for (int i=0; i<mbrs.length; i++ ) {
+                    base.memberAdded(mbrs[i]);
+                }
+            }
+        };
+        t.start();
+        super.start(svc & (~Channel.SND_RX_SEQ) & (~Channel.SND_TX_SEQ));
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/group/interceptors/TcpFailureDetector.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/group/interceptors/TcpFailureDetector.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/group/interceptors/TcpFailureDetector.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,288 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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
+ */
+package org.apache.catalina.tribes.group.interceptors;
+
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.Socket;
+import java.net.SocketTimeoutException;
+import java.util.Arrays;
+import java.util.HashMap;
+
+import org.apache.catalina.tribes.Channel;
+import org.apache.catalina.tribes.ChannelException;
+import org.apache.catalina.tribes.ChannelException.FaultyMember;
+import org.apache.catalina.tribes.ChannelMessage;
+import org.apache.catalina.tribes.Member;
+import org.apache.catalina.tribes.RemoteProcessException;
+import org.apache.catalina.tribes.group.ChannelInterceptorBase;
+import org.apache.catalina.tribes.group.InterceptorPayload;
+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 java.net.ConnectException;
+
+/**
+ * <p>Title: A perfect failure detector </p>
+ *
+ * <p>Description: The TcpFailureDetector is a useful interceptor
+ * that adds reliability to the membership layer.</p>
+ * <p>
+ * If the network is busy, or the system is busy so that the membership receiver thread
+ * is not getting enough time to update its table, members can be &quot;timed out&quot;
+ * This failure detector will intercept the memberDisappeared message(unless its a true shutdown message)
+ * and connect to the member using TCP.
+ * </p>
+ * <p>
+ * The TcpFailureDetector works in two ways. <br>
+ * 1. It intercepts memberDisappeared events
+ * 2. It catches send errors 
+ * </p>
+ *
+ * @author Filip Hanik
+ * @version 1.0
+ */
+public class TcpFailureDetector extends ChannelInterceptorBase {
+    
+    private static org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory.getLog( TcpFailureDetector.class );
+    
+    protected static byte[] TCP_FAIL_DETECT = new byte[] {
+        79, -89, 115, 72, 121, -126, 67, -55, -97, 111, -119, -128, -95, 91, 7, 20,
+        125, -39, 82, 91, -21, -15, 67, -102, -73, 126, -66, -113, -127, 103, 30, -74,
+        55, 21, -66, -121, 69, 126, 76, -88, -65, 10, 77, 19, 83, 56, 21, 50,
+        85, -10, -108, -73, 58, -6, 64, 120, -111, 4, 125, -41, 114, -124, -64, -43};      
+    
+    protected boolean performConnectTest = true;
+
+    protected long connectTimeout = 1000;//1 second default
+    
+    protected boolean performSendTest = true;
+
+    protected boolean performReadTest = false;
+    
+    protected long readTestTimeout = 5000;//5 seconds
+    
+    protected Membership membership = null;
+    
+    protected HashMap removeSuspects = new HashMap();
+    
+    protected HashMap addSuspects = new HashMap();
+    
+    public void sendMessage(Member[] destination, ChannelMessage msg, InterceptorPayload payload) throws ChannelException {
+        try {
+            super.sendMessage(destination, msg, payload);
+        }catch ( ChannelException cx ) {
+            FaultyMember[] mbrs = cx.getFaultyMembers();
+            for ( int i=0; i<mbrs.length; i++ ) {
+                if ( mbrs[i].getCause()!=null &&  
+                     (!(mbrs[i].getCause() instanceof RemoteProcessException)) ) {//RemoteProcessException's are ok
+                    this.memberDisappeared(mbrs[i].getMember());
+                }//end if
+            }//for
+            throw cx;
+        }
+    }
+
+    public void messageReceived(ChannelMessage msg) {
+        //catch incoming 
+        boolean process = true;
+        if ( okToProcess(msg.getOptions()) ) {
+            //check to see if it is a testMessage, if so, process = false
+            process = ( (msg.getMessage().getLength() != TCP_FAIL_DETECT.length) ||
+                        (!Arrays.equals(TCP_FAIL_DETECT,msg.getMessage().getBytes()) ) );
+        }//end if
+            
+        //ignore the message, it doesnt have the flag set
+        if ( process ) super.messageReceived(msg);
+        else if ( log.isDebugEnabled() ) log.debug("Received a failure detector packet:"+msg);
+    }//messageReceived
+    
+    
+    public void memberAdded(Member member) {
+        if ( membership == null ) setupMembership();
+        boolean notify = false;
+        synchronized (membership) {
+            if (removeSuspects.containsKey(member)) {
+                //previously marked suspect, system below picked up the member again
+                removeSuspects.remove(member);
+            } else if (membership.getMember( (MemberImpl) member) == null){
+                //if we add it here, then add it upwards too
+                //check to see if it is alive
+                if (memberAlive(member)) {
+                    membership.memberAlive( (MemberImpl) member);
+                    notify = true;
+                } else {
+                    addSuspects.put(member, new Long(System.currentTimeMillis()));
+                }
+            }
+        }
+        if ( notify ) super.memberAdded(member);
+    }
+
+    public void memberDisappeared(Member member) {
+        if ( membership == null ) setupMembership();
+        boolean notify = false;
+        boolean shutdown = Arrays.equals(member.getCommand(),Member.SHUTDOWN_PAYLOAD);
+        if ( !shutdown ) log.info("Received memberDisappeared["+member+"] message. Will verify.");
+        synchronized (membership) {
+            //check to see if the member really is gone
+            //if the payload is not a shutdown message
+            if (shutdown || !memberAlive(member)) {
+                //not correct, we need to maintain the map
+                membership.removeMember( (MemberImpl) member);
+                removeSuspects.remove(member);
+                notify = true;
+            } else {
+                //add the member as suspect
+                removeSuspects.put(member, new Long(System.currentTimeMillis()));
+            }
+        }
+        if ( notify ) {
+            log.info("Verification complete. Member disappeared["+member+"]");
+            super.memberDisappeared(member);
+        } else {
+            log.info("Verification complete. Member still alive["+member+"]");
+
+        }
+    }
+    
+    public boolean hasMembers() {
+        if ( membership == null ) setupMembership();
+        return membership.hasMembers();
+    }
+
+    public Member[] getMembers() {
+        if ( membership == null ) setupMembership();
+        return membership.getMembers();
+    }
+
+    public Member getMember(Member mbr) {
+        if ( membership == null ) setupMembership();
+        return membership.getMember(mbr);
+    }
+
+    public Member getLocalMember(boolean incAlive) {
+        return super.getLocalMember(incAlive);
+    }
+    
+    public void heartbeat() {
+        try {
+            if (membership == null) setupMembership();
+            synchronized (membership) {
+                //update all alive times
+                Member[] members = super.getMembers();
+                for (int i = 0; members != null && i < members.length; i++) {
+                    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])) {
+                            log.warn("Member added, even though we werent notified:" + members[i]);
+                            super.memberAdded(members[i]);
+                        } else {
+                            membership.removeMember( (MemberImpl) members[i]);
+                        } //end if
+                    } //end if
+                } //for
+
+                //check suspect members if they are still alive,
+                //if not, simply issue the memberDisappeared message
+                MemberImpl[] keys = (MemberImpl[]) removeSuspects.keySet().toArray(new MemberImpl[removeSuspects.size()]);
+                for (int i = 0; i < keys.length; i++) {
+                    MemberImpl m = (MemberImpl) keys[i];
+                    if (membership.getMember(m) != null && (!memberAlive(m))) {
+                        membership.removeMember(m);
+                        super.memberDisappeared(m);
+                        removeSuspects.remove(m);
+                        log.info("Suspect member, confirmed dead.["+m+"]");
+                    } //end if
+                }
+
+                //check add suspects members if they are alive now,
+                //if they are, simply issue the memberAdded message
+                keys = (MemberImpl[]) addSuspects.keySet().toArray(new MemberImpl[addSuspects.size()]);
+                for (int i = 0; i < keys.length; i++) {
+                    MemberImpl m = (MemberImpl) keys[i];
+                    if ( membership.getMember(m) == null && (memberAlive(m))) {
+                        membership.memberAlive(m);
+                        super.memberAdded(m);
+                        addSuspects.remove(m);
+                        log.info("Suspect member, confirmed alive.["+m+"]");
+                    } //end if
+                }
+            }
+        }catch ( Exception x ) {
+            log.warn("Unable to perform heartbeat on the TcpFailureDetector.",x);
+        } finally {
+            super.heartbeat();
+        }
+    }
+    
+    protected synchronized void setupMembership() {
+        if ( membership == null ) {
+            membership = new Membership((MemberImpl)super.getLocalMember(true));
+        }
+        
+    }
+    
+    protected boolean memberAlive(Member mbr) {
+        return memberAlive(mbr,TCP_FAIL_DETECT,performSendTest,performReadTest,readTestTimeout,connectTimeout,getOptionFlag());
+    }
+    
+    protected static boolean memberAlive(Member mbr, byte[] msgData, 
+                                         boolean sendTest, boolean readTest,
+                                         long readTimeout, long conTimeout,
+                                         int optionFlag) {
+        //could be a shutdown notification
+        if ( Arrays.equals(mbr.getCommand(),Member.SHUTDOWN_PAYLOAD) ) return false;
+        
+        Socket socket = new Socket();        
+        try {
+            InetAddress ia = InetAddress.getByAddress(mbr.getHost());
+            InetSocketAddress addr = new InetSocketAddress(ia, mbr.getPort());
+            socket.setSoTimeout((int)readTimeout);
+            socket.connect(addr, (int) conTimeout);
+            if ( sendTest ) {
+                ChannelData data = new ChannelData(true);
+                data.setAddress(mbr);
+                data.setMessage(new XByteBuffer(msgData,false));
+                data.setTimestamp(System.currentTimeMillis());
+                int options = optionFlag | Channel.SEND_OPTIONS_BYTE_MESSAGE;
+                if ( readTest ) options = (options | Channel.SEND_OPTIONS_USE_ACK);
+                else options = (options & (~Channel.SEND_OPTIONS_USE_ACK));
+                data.setOptions(options);
+                byte[] message = XByteBuffer.createDataPackage(data);
+                socket.getOutputStream().write(message);
+                if ( readTest ) {
+                    int length = socket.getInputStream().read(message);
+                    return length > 0;
+                }
+            }//end if
+            return true;
+        } catch ( SocketTimeoutException sx) {
+            //do nothing, we couldn't connect
+        } catch ( ConnectException cx) {
+            //do nothing, we couldn't connect
+        }catch (Exception x ) {
+            log.error("Unable to perform failure detection check, assuming member down.",x);
+        } finally {
+            try {socket.close(); } catch ( Exception ignore ){}
+        }
+        return false;
+    }
+
+
+
+    
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/group/interceptors/ThroughputInterceptor.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/group/interceptors/ThroughputInterceptor.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/group/interceptors/ThroughputInterceptor.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,119 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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
+ */
+
+package org.apache.catalina.tribes.group.interceptors;
+
+import org.apache.catalina.tribes.ChannelException;
+import org.apache.catalina.tribes.ChannelMessage;
+import org.apache.catalina.tribes.Member;
+import org.apache.catalina.tribes.group.ChannelInterceptorBase;
+import org.apache.catalina.tribes.group.InterceptorPayload;
+import org.apache.catalina.tribes.io.ChannelData;
+import org.apache.catalina.tribes.io.XByteBuffer;
+import java.text.DecimalFormat;
+import org.apache.catalina.tribes.membership.MemberImpl;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicLong;
+
+
+
+/**
+ *
+ *
+ * @author Filip Hanik
+ * @version 1.0
+ */
+public class ThroughputInterceptor extends ChannelInterceptorBase {
+    protected static org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory.getLog(ThroughputInterceptor.class);
+
+    double mbTx = 0;
+    double mbAppTx = 0;
+    double mbRx = 0;
+    double timeTx = 0;
+    double lastCnt = 0;
+    AtomicLong msgTxCnt = new AtomicLong(1);
+    AtomicLong msgRxCnt = new AtomicLong(0);
+    AtomicLong msgTxErr = new AtomicLong(0);
+    int interval = 10000;
+    AtomicInteger access = new AtomicInteger(0);
+    long txStart = 0;
+    long rxStart = 0;
+    DecimalFormat df = new DecimalFormat("#0.00");
+
+
+    public void sendMessage(Member[] destination, ChannelMessage msg, InterceptorPayload payload) throws ChannelException {
+        if ( access.addAndGet(1) == 1 ) txStart = System.currentTimeMillis();
+        long bytes = XByteBuffer.getDataPackageLength(((ChannelData)msg).getDataPackageLength());
+        try {
+            super.sendMessage(destination, msg, payload);
+        }catch ( ChannelException x ) {
+            msgTxErr.addAndGet(1);
+            access.addAndGet(-1);
+            throw x;
+        } 
+        mbTx += ((double)(bytes*destination.length))/(1024d*1024d);
+        mbAppTx += ((double)(bytes))/(1024d*1024d);
+        if ( access.addAndGet(-1) == 0 ) {
+            long stop = System.currentTimeMillis();
+            timeTx += ( (double) (stop - txStart)) / 1000d;
+            if ((msgTxCnt.get() / interval) >= lastCnt) {
+                lastCnt++;
+                report(timeTx);
+            }
+        }
+        msgTxCnt.addAndGet(1);
+    }
+
+    public void messageReceived(ChannelMessage msg) {
+        if ( rxStart == 0 ) rxStart = System.currentTimeMillis();
+        long bytes = XByteBuffer.getDataPackageLength(((ChannelData)msg).getDataPackageLength());
+        mbRx += ((double)bytes)/(1024d*1024d);
+        msgRxCnt.addAndGet(1);
+        if ( msgRxCnt.get() % interval == 0 ) report(timeTx);
+        super.messageReceived(msg);
+        
+    }
+    
+    public void report(double timeTx) {
+        StringBuffer buf = new StringBuffer("ThroughputInterceptor Report[\n\tTx Msg:");
+        buf.append(msgTxCnt).append(" messages\n\tSent:");
+        buf.append(df.format(mbTx));
+        buf.append(" MB (total)\n\tSent:");
+        buf.append(df.format(mbAppTx));
+        buf.append(" MB (application)\n\tTime:");
+        buf.append(df.format(timeTx));
+        buf.append(" seconds\n\tTx Speed:");
+        buf.append(df.format(mbTx/timeTx));
+        buf.append(" MB/sec (total)\n\tTxSpeed:");
+        buf.append(df.format(mbAppTx/timeTx));
+        buf.append(" MB/sec (application)\n\tError Msg:");
+        buf.append(msgTxErr).append("\n\tRx Msg:");
+        buf.append(msgRxCnt);
+        buf.append(" messages\n\tRx Speed:");
+        buf.append(df.format(mbRx/((double)((System.currentTimeMillis()-rxStart)/1000))));
+        buf.append(" MB/sec (since 1st msg)\n\tReceived:");
+        buf.append(df.format(mbRx)).append(" MB]\n");
+        if ( log.isInfoEnabled() ) log.info(buf);
+    }
+    
+    public void setInterval(int interval) {
+        this.interval = interval;
+    }
+
+    public int getInterval() {
+        return interval;
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/group/interceptors/TwoPhaseCommitInterceptor.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/group/interceptors/TwoPhaseCommitInterceptor.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/group/interceptors/TwoPhaseCommitInterceptor.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,148 @@
+/*
+ * Copyright 1999,2004-2006 The Apache Software Foundation.
+ *
+ * Licensed 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.tribes.group.interceptors;
+
+import java.util.HashMap;
+
+import org.apache.catalina.tribes.ChannelException;
+import org.apache.catalina.tribes.ChannelMessage;
+import org.apache.catalina.tribes.Member;
+import org.apache.catalina.tribes.group.ChannelInterceptorBase;
+import org.apache.catalina.tribes.group.InterceptorPayload;
+import org.apache.catalina.tribes.util.UUIDGenerator;
+import org.apache.catalina.tribes.util.Arrays;
+import org.apache.catalina.tribes.UniqueId;
+import java.util.Map;
+
+/**
+ * <p>Title: </p>
+ *
+ * <p>Description: </p>
+ *
+ * <p>Copyright: Copyright (c) 2005</p>
+ *
+ * <p>Company: </p>
+ *
+ * @author not attributable
+ * @version 1.0
+ */
+public class TwoPhaseCommitInterceptor extends ChannelInterceptorBase {
+
+    public static final byte[] START_DATA = new byte[] {113, 1, -58, 2, -34, -60, 75, -78, -101, -12, 32, -29, 32, 111, -40, 4};
+    public static final byte[] END_DATA = new byte[] {54, -13, 90, 110, 47, -31, 75, -24, -81, -29, 36, 52, -58, 77, -110, 56};
+    private static org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory.getLog(TwoPhaseCommitInterceptor.class);
+
+    protected HashMap messages = new HashMap();
+    protected long expire = 1000 * 60; //one minute expiration
+    protected boolean deepclone = true;
+
+    public void sendMessage(Member[] destination, ChannelMessage msg, InterceptorPayload payload) throws
+        ChannelException {
+        //todo, optimize, if destination.length==1, then we can do
+        //msg.setOptions(msg.getOptions() & (~getOptionFlag())
+        //and just send one message
+        if (okToProcess(msg.getOptions()) ) {
+            super.sendMessage(destination, msg, null);
+            ChannelMessage confirmation = null;
+            if ( deepclone ) confirmation = (ChannelMessage)msg.deepclone();
+            else confirmation = (ChannelMessage)msg.clone();
+            confirmation.getMessage().reset();
+            UUIDGenerator.randomUUID(false,confirmation.getUniqueId(),0);
+            confirmation.getMessage().append(START_DATA,0,START_DATA.length);
+            confirmation.getMessage().append(msg.getUniqueId(),0,msg.getUniqueId().length);
+            confirmation.getMessage().append(END_DATA,0,END_DATA.length);
+            super.sendMessage(destination,confirmation,payload);
+        } else {
+            //turn off two phase commit
+            //this wont work if the interceptor has 0 as a flag
+            //since there is no flag to turn off
+            //msg.setOptions(msg.getOptions() & (~getOptionFlag()));
+            super.sendMessage(destination, msg, payload);
+        }
+    }
+
+    public void messageReceived(ChannelMessage msg) {
+        if (okToProcess(msg.getOptions())) {
+            if ( msg.getMessage().getLength() == (START_DATA.length+msg.getUniqueId().length+END_DATA.length) &&
+                 Arrays.contains(msg.getMessage().getBytesDirect(),0,START_DATA,0,START_DATA.length) &&
+                 Arrays.contains(msg.getMessage().getBytesDirect(),START_DATA.length+msg.getUniqueId().length,END_DATA,0,END_DATA.length) ) {
+                UniqueId id = new UniqueId(msg.getMessage().getBytesDirect(),START_DATA.length,msg.getUniqueId().length);
+                MapEntry original = (MapEntry)messages.get(id);
+                if ( original != null ) {
+                    super.messageReceived(original.msg);
+                    messages.remove(id);
+                } else log.warn("Received a confirmation, but original message is missing. Id:"+Arrays.toString(id.getBytes()));
+            } else {
+                UniqueId id = new UniqueId(msg.getUniqueId());
+                MapEntry entry = new MapEntry((ChannelMessage)msg.deepclone(),id,System.currentTimeMillis());
+                messages.put(id,entry);
+            }
+        } else {
+            super.messageReceived(msg);
+        }
+    }
+
+    public boolean getDeepclone() {
+        return deepclone;
+    }
+
+    public long getExpire() {
+        return expire;
+    }
+
+    public void setDeepclone(boolean deepclone) {
+        this.deepclone = deepclone;
+    }
+
+    public void setExpire(long expire) {
+        this.expire = expire;
+    }
+    
+    public void heartbeat() {
+        try {
+            long now = System.currentTimeMillis();
+            Map.Entry[] entries = (Map.Entry[])messages.entrySet().toArray(new Map.Entry[messages.size()]);
+            for (int i=0; i<entries.length; i++ ) {
+                MapEntry entry = (MapEntry)entries[i].getValue();
+                if ( entry.expired(now,expire) ) {
+                    log.info("Message ["+entry.id+"] has expired. Removing.");
+                    messages.remove(entry.id);
+                }//end if
+            }
+        } catch ( Exception x ) {
+            log.warn("Unable to perform heartbeat on the TwoPhaseCommit interceptor.",x);
+        } finally {
+            super.heartbeat();
+        }
+    }
+    
+    public static class MapEntry {
+        public ChannelMessage msg;
+        public UniqueId id;
+        public long timestamp;
+        
+        public MapEntry(ChannelMessage msg, UniqueId id, long timestamp) {
+            this.msg = msg;
+            this.id = id;
+            this.timestamp = timestamp;
+        }
+        public boolean expired(long now, long expiration) {
+            return (now - timestamp ) > expiration;
+        }
+
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/io/BufferPool.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/io/BufferPool.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/io/BufferPool.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,93 @@
+/*
+ * Copyright 1999,2004-2006 The Apache Software Foundation.
+ *
+ * Licensed 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.tribes.io;
+
+import org.apache.commons.logging.LogFactory;
+
+import org.apache.commons.logging.Log;
+
+/**
+ *
+ * @author Filip Hanik
+ * 
+ * @version 1.0
+ */
+public class BufferPool {
+    protected static Log log = LogFactory.getLog(BufferPool.class);
+
+    public static int DEFAULT_POOL_SIZE = 100*1024*1024; //100MB
+
+
+
+    protected static BufferPool instance = null;
+    protected BufferPoolAPI pool = null;
+
+    private BufferPool(BufferPoolAPI pool) {
+        this.pool = pool;
+    }
+
+    public XByteBuffer getBuffer(int minSize, boolean discard) {
+        if ( pool != null ) return pool.getBuffer(minSize, discard);
+        else return new XByteBuffer(minSize,discard);
+    }
+
+    public void returnBuffer(XByteBuffer buffer) {
+        if ( pool != null ) pool.returnBuffer(buffer);
+    }
+
+    public void clear() {
+        if ( pool != null ) pool.clear();
+    }
+
+
+    public static BufferPool getBufferPool() {
+        if (  (instance == null) ) {
+            synchronized (BufferPool.class) {
+                if ( instance == null ) {
+                   BufferPoolAPI pool = null;
+                   Class clazz = null;
+                   try {
+                       clazz = Class.forName("org.apache.catalina.tribes.io.BufferPool15Impl");
+                       pool = (BufferPoolAPI)clazz.newInstance();
+                   } catch ( Throwable x ) {
+                       try {
+                           clazz = Class.forName("org.apache.catalina.tribes.io.BufferPool14Impl");
+                           pool = (BufferPoolAPI)clazz.newInstance();
+                       } catch ( Throwable e ) {
+                           log.warn("Unable to initilize BufferPool, not pooling XByteBuffer objects:"+x.getMessage());
+                           if ( log.isDebugEnabled() ) log.debug("Unable to initilize BufferPool, not pooling XByteBuffer objects:",x);
+                       }
+                   }
+                   pool.setMaxSize(DEFAULT_POOL_SIZE);
+                   log.info("Created a buffer pool with max size:"+DEFAULT_POOL_SIZE+" bytes of type:"+(clazz!=null?clazz.getName():"null"));
+                   instance = new BufferPool(pool);
+                }//end if
+            }//sync
+        }//end if
+        return instance;
+    }
+
+
+    public static interface BufferPoolAPI {
+        public void setMaxSize(int bytes);
+
+        public XByteBuffer getBuffer(int minSize, boolean discard);
+
+        public void returnBuffer(XByteBuffer buffer);
+
+        public void clear();
+    }    
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/io/BufferPool14Impl.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/io/BufferPool14Impl.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/io/BufferPool14Impl.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,69 @@
+/*
+ * Copyright 1999,2004-2006 The Apache Software Foundation.
+ *
+ * Licensed 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.tribes.io;
+
+import java.util.Queue;
+import java.util.LinkedList;
+
+
+/**
+ *
+ * @author Filip Hanik
+ * @version 1.0
+ */
+class BufferPool14Impl implements BufferPool.BufferPoolAPI {
+    protected int maxSize;
+    protected int size = 0;
+    protected LinkedList queue = new LinkedList();
+
+    public void setMaxSize(int bytes) {
+        this.maxSize = bytes;
+    }
+    
+    public synchronized int addAndGet(int val) {
+        size = size + (val);
+        return size;
+    }
+    
+    
+
+    public synchronized XByteBuffer getBuffer(int minSize, boolean discard) {
+        XByteBuffer buffer = (XByteBuffer)(queue.size()>0?queue.remove(0):null);
+        if ( buffer != null ) addAndGet(-buffer.getCapacity());
+        if ( buffer == null ) buffer = new XByteBuffer(minSize,discard);
+        else if ( buffer.getCapacity() <= minSize ) buffer.expand(minSize);
+        buffer.setDiscard(discard);
+        buffer.reset();
+        return buffer;
+    }
+
+    public synchronized void returnBuffer(XByteBuffer buffer) {
+        if ( (size + buffer.getCapacity()) <= maxSize ) {
+            addAndGet(buffer.getCapacity());
+            queue.add(buffer);
+        }
+    }
+
+    public synchronized void clear() {
+        queue.clear();
+        size = 0;
+    }
+
+    public int getMaxSize() {
+        return maxSize;
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/io/BufferPool15Impl.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/io/BufferPool15Impl.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/io/BufferPool15Impl.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,62 @@
+/*
+ * Copyright 1999,2004-2006 The Apache Software Foundation.
+ *
+ * Licensed 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.tribes.io;
+
+import java.util.concurrent.ConcurrentLinkedQueue;
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ *
+ * @author Filip Hanik
+ * @version 1.0
+ */
+class BufferPool15Impl implements BufferPool.BufferPoolAPI {
+    protected int maxSize;
+    protected AtomicInteger size = new AtomicInteger(0);
+    protected ConcurrentLinkedQueue queue = new ConcurrentLinkedQueue();
+
+    public void setMaxSize(int bytes) {
+        this.maxSize = bytes;
+    }
+
+
+    public XByteBuffer getBuffer(int minSize, boolean discard) {
+        XByteBuffer buffer = (XByteBuffer)queue.poll();
+        if ( buffer != null ) size.addAndGet(-buffer.getCapacity());
+        if ( buffer == null ) buffer = new XByteBuffer(minSize,discard);
+        else if ( buffer.getCapacity() <= minSize ) buffer.expand(minSize);
+        buffer.setDiscard(discard);
+        buffer.reset();
+        return buffer;
+    }
+
+    public void returnBuffer(XByteBuffer buffer) {
+        if ( (size.get() + buffer.getCapacity()) <= maxSize ) {
+            size.addAndGet(buffer.getCapacity());
+            queue.offer(buffer);
+        }
+    }
+
+    public void clear() {
+        queue.clear();
+        size.set(0);
+    }
+
+    public int getMaxSize() {
+        return maxSize;
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/io/ChannelData.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/io/ChannelData.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/io/ChannelData.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,356 @@
+/*
+ * Copyright 1999,2005 The Apache Software Foundation.
+ * 
+ * Licensed 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.tribes.io;
+
+import java.util.Arrays;
+
+import org.apache.catalina.tribes.ChannelMessage;
+import org.apache.catalina.tribes.Member;
+import org.apache.catalina.tribes.membership.MemberImpl;
+import org.apache.catalina.tribes.util.UUIDGenerator;
+import org.apache.catalina.tribes.Channel;
+import java.sql.Timestamp;
+
+/**
+ * The <code>ChannelData</code> object is used to transfer a message through the 
+ * channel interceptor stack and eventually out on a transport to be sent 
+ * to another node. While the message is being processed by the different 
+ * interceptors, the message data can be manipulated as each interceptor seems appropriate.
+ * @author Peter Rossbach
+ * @author Filip Hanik
+ * @version $Revision: 377484 $ $Date: 2006-02-13 15:00:05 -0600 (Mon, 13 Feb 2006) $
+ * 
+ */
+public class ChannelData implements ChannelMessage {
+    public static ChannelData[] EMPTY_DATA_ARRAY = new ChannelData[0];
+    
+    public static boolean USE_SECURE_RANDOM_FOR_UUID = false;
+    
+    /**
+     * The options this message was sent with
+     */
+    private int options = 0 ;
+    /**
+     * The message data, stored in a dynamic buffer
+     */
+    private XByteBuffer message ;
+    /**
+     * The timestamp that goes with this message
+     */
+    private long timestamp ;
+    /**
+     * A unique message id
+     */
+    private byte[] uniqueId ;
+    /**
+     * The source or reply-to address for this message
+     */
+    private Member address;
+
+    /**
+     * Creates an empty channel data with a new unique Id
+     * @see #ChannelData(boolean)
+     */
+    public ChannelData() {
+        this(true);
+    }
+    
+    /**
+     * Create an empty channel data object
+     * @param generateUUID boolean - if true, a unique Id will be generated
+     */
+    public ChannelData(boolean generateUUID) {
+        if ( generateUUID ) generateUUID();
+    }
+    
+    
+    
+    /**
+     * Creates a new channel data object with data
+     * @param uniqueId - unique message id
+     * @param message - message data
+     * @param timestamp - message timestamp
+     */
+    public ChannelData(byte[] uniqueId, XByteBuffer message, long timestamp) {
+        this.uniqueId = uniqueId;
+        this.message = message;
+        this.timestamp = timestamp;
+    }
+    
+    /**
+     * @return Returns the message byte buffer
+     */
+    public XByteBuffer getMessage() {
+        return message;
+    }
+    /**
+     * @param message The message to send.
+     */
+    public void setMessage(XByteBuffer message) {
+        this.message = message;
+    }
+    /**
+     * @return Returns the timestamp.
+     */
+    public long getTimestamp() {
+        return timestamp;
+    }
+    /**
+     * @param timestamp The timestamp to send
+     */
+    public void setTimestamp(long timestamp) {
+        this.timestamp = timestamp;
+    }
+    /**
+     * @return Returns the uniqueId.
+     */
+    public byte[] getUniqueId() {
+        return uniqueId;
+    }
+    /**
+     * @param uniqueId The uniqueId to send.
+     */
+    public void setUniqueId(byte[] uniqueId) {
+        this.uniqueId = uniqueId;
+    }
+    /**
+     * @return returns the message options 
+     * see org.apache.catalina.tribes.Channel#sendMessage(org.apache.catalina.tribes.Member[], java.io.Serializable, int)
+     *                                                 
+     */
+    public int getOptions() {
+        return options;
+    }
+    /**
+     * @param sets the message options
+     */
+    public void setOptions(int options) {
+        this.options = options;
+    }
+    
+    /**
+     * Returns the source or reply-to address
+     * @return Member
+     */
+    public Member getAddress() {
+        return address;
+    }
+
+    /**
+     * Sets the source or reply-to address
+     * @param address Member
+     */
+    public void setAddress(Member address) {
+        this.address = address;
+    }
+    
+    /**
+     * Generates a UUID and invokes setUniqueId
+     */
+    public void generateUUID() {
+        byte[] data = new byte[16];
+        UUIDGenerator.randomUUID(USE_SECURE_RANDOM_FOR_UUID,data,0);
+        setUniqueId(data);
+    }
+
+    public int getDataPackageLength() {
+        int length = 
+            4 + //options
+            8 + //timestamp  off=4
+            4 + //unique id length off=12
+            uniqueId.length+ //id data off=12+uniqueId.length
+            4 + //addr length off=12+uniqueId.length+4
+            ((MemberImpl)address).getDataLength()+ //member data off=12+uniqueId.length+4+add.length
+            4 + //message length off=12+uniqueId.length+4+add.length+4
+            message.getLength();
+        return length;
+
+    }
+    
+    /**
+     * Serializes the ChannelData object into a byte[] array
+     * @return byte[]
+     */
+    public byte[] getDataPackage()  {
+        int length = getDataPackageLength();
+        byte[] data = new byte[length];
+        int offset = 0;
+        return getDataPackage(data,offset);
+    }
+
+    public byte[] getDataPackage(byte[] data, int offset)  {
+        byte[] addr = ((MemberImpl)address).getData(false);
+        XByteBuffer.toBytes(options,data,offset);
+        offset += 4; //options
+        XByteBuffer.toBytes(timestamp,data,offset);
+        offset += 8; //timestamp
+        XByteBuffer.toBytes(uniqueId.length,data,offset);
+        offset += 4; //uniqueId.length
+        System.arraycopy(uniqueId,0,data,offset,uniqueId.length);
+        offset += uniqueId.length; //uniqueId data
+        XByteBuffer.toBytes(addr.length,data,offset);
+        offset += 4; //addr.length
+        System.arraycopy(addr,0,data,offset,addr.length);
+        offset += addr.length; //addr data
+        XByteBuffer.toBytes(message.getLength(),data,offset);
+        offset += 4; //message.length
+        System.arraycopy(message.getBytesDirect(),0,data,offset,message.getLength());
+        offset += message.getLength(); //message data
+        return data;
+    }
+    
+    /**
+     * Deserializes a ChannelData object from a byte array
+     * @param b byte[]
+     * @return ChannelData
+     */
+    public static ChannelData getDataFromPackage(XByteBuffer xbuf)  {
+        ChannelData data = new ChannelData(false);
+        int offset = 0;
+        data.setOptions(XByteBuffer.toInt(xbuf.getBytesDirect(),offset));
+        offset += 4; //options
+        data.setTimestamp(XByteBuffer.toLong(xbuf.getBytesDirect(),offset));
+        offset += 8; //timestamp
+        data.uniqueId = new byte[XByteBuffer.toInt(xbuf.getBytesDirect(),offset)];
+        offset += 4; //uniqueId length
+        System.arraycopy(xbuf.getBytesDirect(),offset,data.uniqueId,0,data.uniqueId.length);
+        offset += data.uniqueId.length; //uniqueId data
+        byte[] addr = new byte[XByteBuffer.toInt(xbuf.getBytesDirect(),offset)];
+        offset += 4; //addr length
+        System.arraycopy(xbuf.getBytesDirect(),offset,addr,0,addr.length);
+        data.setAddress(MemberImpl.getMember(addr));
+        offset += addr.length; //addr data
+        int xsize = XByteBuffer.toInt(xbuf.getBytesDirect(),offset);
+        offset += 4; //xsize length
+        System.arraycopy(xbuf.getBytesDirect(),offset,xbuf.getBytesDirect(),0,xsize);
+        xbuf.setLength(xsize);
+        data.message = xbuf;
+        return data;
+
+    }
+
+    public static ChannelData getDataFromPackage(byte[] b)  {
+        ChannelData data = new ChannelData(false);
+        int offset = 0;
+        data.setOptions(XByteBuffer.toInt(b,offset));
+        offset += 4; //options
+        data.setTimestamp(XByteBuffer.toLong(b,offset));
+        offset += 8; //timestamp
+        data.uniqueId = new byte[XByteBuffer.toInt(b,offset)];
+        offset += 4; //uniqueId length
+        System.arraycopy(b,offset,data.uniqueId,0,data.uniqueId.length);
+        offset += data.uniqueId.length; //uniqueId data
+        byte[] addr = new byte[XByteBuffer.toInt(b,offset)];
+        offset += 4; //addr length
+        System.arraycopy(b,offset,addr,0,addr.length);
+        data.setAddress(MemberImpl.getMember(addr));
+        offset += addr.length; //addr data
+        int xsize = XByteBuffer.toInt(b,offset);
+        //data.message = new XByteBuffer(new byte[xsize],false);
+        data.message = BufferPool.getBufferPool().getBuffer(xsize,false);
+        offset += 4; //message length
+        System.arraycopy(b,offset,data.message.getBytesDirect(),0,xsize);
+        data.message.append(b,offset,xsize);
+        offset += xsize; //message data
+        return data;
+    }
+    
+    public int hashCode() {
+        return XByteBuffer.toInt(getUniqueId(),0);
+    }
+    
+    /**
+     * Compares to ChannelData objects, only compares on getUniqueId().equals(o.getUniqueId())
+     * @param o Object
+     * @return boolean
+     */
+    public boolean equals(Object o) {
+        if ( o instanceof ChannelData ) {
+            return Arrays.equals(getUniqueId(),((ChannelData)o).getUniqueId());
+        } else return false;
+    }
+    
+    /**
+     * Create a shallow clone, only the data gets recreated
+     * @return ClusterData
+     */
+    public Object clone() {
+//        byte[] d = this.getDataPackage();
+//        return ClusterData.getDataFromPackage(d);
+        ChannelData clone = new ChannelData(false);
+        clone.options = this.options;
+        clone.message = new XByteBuffer(this.message.getBytesDirect(),false);
+        clone.timestamp = this.timestamp;
+        clone.uniqueId = this.uniqueId;
+        clone.address = this.address;
+        return clone;
+    }
+    
+    /**
+     * Complete clone
+     * @return ClusterData
+     */
+    public Object deepclone() {
+        byte[] d = this.getDataPackage();
+        return ChannelData.getDataFromPackage(d);
+    }
+    
+    /**
+     * Utility method, returns true if the options flag indicates that an ack
+     * is to be sent after the message has been received and processed
+     * @param options int - the options for the message
+     * @return boolean 
+     * @see org.apache.catalina.tribes.Channel#SEND_OPTIONS_USE_ACK
+     * @see org.apache.catalina.tribes.Channel#SEND_OPTIONS_SYNCHRONIZED_ACK
+     */
+    public static boolean sendAckSync(int options) {
+        return ( (Channel.SEND_OPTIONS_USE_ACK & options) == Channel.SEND_OPTIONS_USE_ACK) &&
+            ( (Channel.SEND_OPTIONS_SYNCHRONIZED_ACK & options) == Channel.SEND_OPTIONS_SYNCHRONIZED_ACK);
+    }
+
+
+    /**
+     * Utility method, returns true if the options flag indicates that an ack
+     * is to be sent after the message has been received but not yet processed
+     * @param options int - the options for the message
+     * @return boolean 
+     * @see org.apache.catalina.tribes.Channel#SEND_OPTIONS_USE_ACK
+     * @see org.apache.catalina.tribes.Channel#SEND_OPTIONS_SYNCHRONIZED_ACK
+     */
+    public static boolean sendAckAsync(int options) {
+        return ( (Channel.SEND_OPTIONS_USE_ACK & options) == Channel.SEND_OPTIONS_USE_ACK) &&
+            ( (Channel.SEND_OPTIONS_SYNCHRONIZED_ACK & options) != Channel.SEND_OPTIONS_SYNCHRONIZED_ACK);
+    }
+    
+    public String toString() {
+        StringBuffer buf = new StringBuffer();
+        buf.append("ClusterData[src=");
+        buf.append(getAddress()).append("; id=");
+        buf.append(bToS(getUniqueId())).append("; sent=");
+        buf.append(new Timestamp(this.getTimestamp()).toString()).append("]");
+        return buf.toString();
+    }
+    
+    public static String bToS(byte[] data) {
+        StringBuffer buf = new StringBuffer(4*16);
+        buf.append("{");
+        for (int i=0; data!=null && i<data.length; i++ ) buf.append(String.valueOf(data[i])).append(" ");
+        buf.append("}");
+        return buf.toString();
+    }
+
+    
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/io/DirectByteArrayOutputStream.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/io/DirectByteArrayOutputStream.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/io/DirectByteArrayOutputStream.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,62 @@
+/*
+ * Copyright 1999,2004-2006 The Apache Software Foundation.
+ *
+ * Licensed 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.tribes.io;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+/**
+ * Byte array output stream that exposes the byte array directly
+ *
+ * @author not attributable
+ * @version 1.0
+ */
+public class DirectByteArrayOutputStream extends OutputStream {
+    
+    private XByteBuffer buffer;
+    
+    public DirectByteArrayOutputStream(int size) {
+        buffer = new XByteBuffer(size,false);
+    }
+
+    /**
+     * Writes the specified byte to this output stream.
+     *
+     * @param b the <code>byte</code>.
+     * @throws IOException if an I/O error occurs. In particular, an
+     *   <code>IOException</code> may be thrown if the output stream has
+     *   been closed.
+     * @todo Implement this java.io.OutputStream method
+     */
+    public void write(int b) throws IOException {
+        buffer.append((byte)b);
+    }
+    
+    public int size() {
+        return buffer.getLength();
+    }
+    
+    public byte[] getArrayDirect() {
+        return buffer.getBytesDirect();
+    }
+    
+    public byte[] getArray() {
+        return buffer.getBytes();
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/io/ListenCallback.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/io/ListenCallback.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/io/ListenCallback.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,41 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tribes.io;
+
+import org.apache.catalina.tribes.ChannelMessage;
+
+
+
+/**
+ * Internal interface, similar to the MessageListener but used 
+ * at the IO base
+ * The listen callback interface is used by the replication system
+ * when data has been received. The interface does not care about
+ * objects and marshalling and just passes the bytes straight through.
+ * @author Filip Hanik
+ * @version $Revision: 303987 $, $Date: 2005-07-08 15:50:30 -0500 (Fri, 08 Jul 2005) $
+ */
+public interface ListenCallback
+{
+    /**
+     * This method is invoked on the callback object to notify it that new data has
+     * been received from one of the cluster nodes.
+     * @param data - the message bytes received from the cluster/replication system
+     */
+     public void messageDataReceived(ChannelMessage data);
+     
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/io/ObjectReader.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/io/ObjectReader.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/io/ObjectReader.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,164 @@
+/*
+ * Copyright 1999,2004-2005 The Apache Software Foundation.
+ * 
+ * Licensed 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.tribes.io;
+
+import java.io.IOException;
+import java.net.Socket;
+import java.nio.ByteBuffer;
+import java.nio.channels.SocketChannel;
+
+import org.apache.catalina.tribes.ChannelMessage;
+
+
+
+/**
+ * The object reader object is an object used in conjunction with
+ * java.nio TCP messages. This object stores the message bytes in a
+ * <code>XByteBuffer</code> until a full package has been received.
+ * This object uses an XByteBuffer which is an extendable object buffer that also allows
+ * for message encoding and decoding.
+ *
+ * @author Filip Hanik
+ * @version $Revision: 377484 $, $Date: 2006-02-13 15:00:05 -0600 (Mon, 13 Feb 2006) $
+ */
+public class ObjectReader {
+
+    protected static org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory.getLog(ObjectReader.class);
+
+    private XByteBuffer buffer;
+    
+    protected long lastAccess = System.currentTimeMillis();
+    
+    protected boolean accessed = false;
+    private boolean cancelled;
+
+    /**
+     * Creates an <code>ObjectReader</code> for a TCP NIO socket channel
+     * @param channel - the channel to be read.
+     */
+    public ObjectReader(SocketChannel channel) {
+        this(channel.socket());
+    }
+    
+    /**
+     * Creates an <code>ObjectReader</code> for a TCP socket
+     * @param socket Socket
+     */
+    public ObjectReader(Socket socket) {
+        try{
+            this.buffer = new XByteBuffer(socket.getReceiveBufferSize(), true);
+        }catch ( IOException x ) {
+            //unable to get buffer size
+            log.warn("Unable to retrieve the socket receiver buffer size, setting to default 43800 bytes.");
+            this.buffer = new XByteBuffer(43800,true);
+        }
+    }
+    
+    public synchronized void access() {
+        this.accessed = true;
+        this.lastAccess = System.currentTimeMillis();
+    }
+    
+    public synchronized void finish() {
+        this.accessed = false;
+        this.lastAccess = System.currentTimeMillis();
+    }
+    
+    public boolean isAccessed() {
+        return this.accessed;
+    }
+
+    /**
+     * Append new bytes to buffer. 
+     * @see XByteBuffer#countPackages()
+     * @param data new transfer buffer
+     * @param off offset
+     * @param len length in buffer
+     * @return number of messages that sended to callback
+     * @throws java.io.IOException
+     */
+    public int append(ByteBuffer data, int len, boolean count) throws java.io.IOException {
+       buffer.append(data,len);
+       int pkgCnt = -1;
+       if ( count ) pkgCnt = buffer.countPackages();
+       return pkgCnt;
+   }
+
+     public int append(byte[] data,int off,int len, boolean count) throws java.io.IOException {
+        buffer.append(data,off,len);
+        int pkgCnt = -1;
+        if ( count ) pkgCnt = buffer.countPackages();
+        return pkgCnt;
+    }
+
+    /**
+     * Send buffer to cluster listener (callback).
+     * Is message complete receiver send message to callback?
+     *
+     * @see org.apache.catalina.tribes.transport.ClusterReceiverBase#messageDataReceived(ChannelMessage)
+     * @see XByteBuffer#doesPackageExist()
+     * @see XByteBuffer#extractPackage(boolean)
+     *
+     * @return number of received packages/messages
+     * @throws java.io.IOException
+     */
+    public ChannelMessage[] execute() throws java.io.IOException {
+        int pkgCnt = buffer.countPackages();
+        ChannelMessage[] result = new ChannelMessage[pkgCnt];
+        for (int i=0; i<pkgCnt; i++)  {
+            ChannelMessage data = buffer.extractPackage(true);
+            result[i] = data;
+        }
+        return result;
+    }
+    
+    public int bufferSize() {
+        return buffer.getLength();
+    }
+    
+
+    public boolean hasPackage() {
+        return buffer.countPackages(true)>0;
+    }
+    /**
+     * Returns the number of packages that the reader has read
+     * @return int
+     */
+    public int count() {
+        return buffer.countPackages();
+    }
+    
+    public void close() {
+        this.buffer = null;
+    }
+
+    public long getLastAccess() {
+        return lastAccess;
+    }
+
+    public boolean isCancelled() {
+        return cancelled;
+    }
+
+    public void setLastAccess(long lastAccess) {
+        this.lastAccess = lastAccess;
+    }
+
+    public void setCancelled(boolean cancelled) {
+        this.cancelled = cancelled;
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/io/ReplicationStream.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/io/ReplicationStream.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/io/ReplicationStream.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,116 @@
+/*
+ * Copyright 1999,2004-2005 The Apache Software Foundation.
+ * 
+ * Licensed 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.tribes.io;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectStreamClass;
+
+/**
+ * Custom subclass of <code>ObjectInputStream</code> that loads from the
+ * class loader for this web application.  This allows classes defined only
+ * with the web application to be found correctly.
+ *
+ * @author Craig R. McClanahan
+ * @author Bip Thelin
+ * @author Filip Hanik
+ * @version $Revision: 377484 $, $Date: 2006-02-13 15:00:05 -0600 (Mon, 13 Feb 2006) $
+ */
+
+public final class ReplicationStream extends ObjectInputStream {
+
+    
+    /**
+     * The class loader we will use to resolve classes.
+     */
+    private ClassLoader[] classLoaders = null;
+    
+
+    /**
+     * Construct a new instance of CustomObjectInputStream
+     *
+     * @param stream The input stream we will read from
+     * @param classLoader The class loader used to instantiate objects
+     *
+     * @exception IOException if an input/output error occurs
+     */
+    public ReplicationStream(InputStream stream,
+                             ClassLoader[] classLoaders)
+        throws IOException {
+
+        super(stream);
+        this.classLoaders = classLoaders;
+    }
+
+    /**
+     * Load the local class equivalent of the specified stream class
+     * description, by using the class loader assigned to this Context.
+     *
+     * @param classDesc Class description from the input stream
+     *
+     * @exception ClassNotFoundException if this class cannot be found
+     * @exception IOException if an input/output error occurs
+     */
+    public Class resolveClass(ObjectStreamClass classDesc)
+        throws ClassNotFoundException, IOException {
+        String name = classDesc.getName();
+        boolean tryRepFirst = name.startsWith("org.apache.catalina.tribes");
+        try {
+            try
+            {
+                if ( tryRepFirst ) return findReplicationClass(name);
+                else return findExternalClass(name);
+            }
+            catch ( Exception x )
+            {
+                if ( tryRepFirst ) return findExternalClass(name);
+                else return findReplicationClass(name);
+            }
+        } catch (ClassNotFoundException e) {
+            return super.resolveClass(classDesc);
+        }
+    }
+    
+    public Class findReplicationClass(String name)
+        throws ClassNotFoundException, IOException {
+        Class clazz = Class.forName(name, false, getClass().getClassLoader());
+        return clazz;
+    }
+
+    public Class findExternalClass(String name) throws ClassNotFoundException  {
+        ClassNotFoundException cnfe = null;
+        for (int i=0; i<classLoaders.length; i++ ) {
+            try {
+                Class clazz = Class.forName(name, false, classLoaders[i]);
+                return clazz;
+            } catch ( ClassNotFoundException x ) {
+                cnfe = x;
+            } 
+        }
+        if ( cnfe != null ) throw cnfe;
+        else throw new ClassNotFoundException(name);
+    }
+    
+    public void close() throws IOException  {
+        this.classLoaders = null;
+        super.close();
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/io/XByteBuffer.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/io/XByteBuffer.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/io/XByteBuffer.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,611 @@
+/*
+ * Copyright 1999,2004-2005 The Apache Software Foundation.
+ * 
+ * Licensed 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.tribes.io;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+import java.nio.ByteBuffer;
+
+/**
+ * The XByteBuffer provides a dual functionality.
+ * One, it stores message bytes and automatically extends the byte buffer if needed.<BR>
+ * Two, it can encode and decode packages so that they can be defined and identified
+ * as they come in on a socket.
+ * <br>
+ * <b>THIS CLASS IS NOT THREAD SAFE</B><BR>
+ * <br/>
+ * Transfer package:
+ * <ul>
+ * <li><b>START_DATA/b> - 7 bytes - <i>FLT2002</i></li>
+ * <li><b>SIZE</b>      - 4 bytes - size of the data package</li>
+ * <li><b>DATA</b>      - should be as many bytes as the prev SIZE</li>
+ * <li><b>END_DATA</b>  - 7 bytes - <i>TLF2003</i></lI>
+ * </ul>
+ * @author Filip Hanik
+ * @version $Revision: 377484 $, $Date: 2006-02-13 15:00:05 -0600 (Mon, 13 Feb 2006) $
+ */
+public class XByteBuffer
+{
+    
+    public static org.apache.commons.logging.Log log =
+        org.apache.commons.logging.LogFactory.getLog( XByteBuffer.class );
+    
+    /**
+     * This is a package header, 7 bytes (FLT2002)
+     */
+    public static final byte[] START_DATA = {70,76,84,50,48,48,50};
+    
+    /**
+     * This is the package footer, 7 bytes (TLF2003)
+     */
+    public static final byte[] END_DATA = {84,76,70,50,48,48,51};
+ 
+    /**
+     * Default size on the initial byte buffer
+     */
+    private static final int DEF_SIZE = 2048;
+ 
+    /**
+     * Default size to extend the buffer with
+     */
+    private static final int DEF_EXT  = 1024;
+    
+    /**
+     * Variable to hold the data
+     */
+    protected byte[] buf = null;
+    
+    /**
+     * Current length of data in the buffer
+     */
+    protected int bufSize = 0;
+    
+    /**
+     * Flag for discarding invalid packages
+     * If this flag is set to true, and append(byte[],...) is called,
+     * the data added will be inspected, and if it doesn't start with 
+     * <code>START_DATA</code> it will be thrown away.
+     * 
+     */
+    protected boolean discard = true;
+    
+    /**
+     * Constructs a new XByteBuffer
+     * @param size - the initial size of the byte buffer
+     * @todo use a pool of byte[] for performance
+     */
+    public XByteBuffer(int size, boolean discard) {
+        buf = new byte[size];
+        this.discard = discard;
+    }
+    
+    public XByteBuffer(byte[] data,boolean discard) {
+        this(data,data.length+128,discard);
+    }
+    
+    public XByteBuffer(byte[] data, int size,boolean discard) {
+        int length = Math.max(data.length,size);
+        buf = new byte[length];
+        System.arraycopy(data,0,buf,0,data.length);
+        bufSize = data.length;
+        this.discard = discard;
+    }
+    
+    public int getLength() {
+        return bufSize;
+    }
+
+    public void setLength(int size) {
+        if ( size > buf.length ) throw new ArrayIndexOutOfBoundsException("Size is larger than existing buffer.");
+        bufSize = size;
+    }
+    
+    public void trim(int length) {
+        if ( (bufSize - length) < 0 ) 
+            throw new ArrayIndexOutOfBoundsException("Can't trim more bytes than are available. length:"+bufSize+" trim:"+length);
+        bufSize -= length;
+    }
+    
+    public void reset() {
+        bufSize = 0;
+    }
+            
+    public byte[] getBytesDirect() {
+        return this.buf;
+    }
+
+    /**
+     * Returns the bytes in the buffer, in its exact length
+     */
+    public byte[] getBytes() {
+        byte[] b = new byte[bufSize];
+        System.arraycopy(buf,0,b,0,bufSize);
+        return b;
+    }
+
+    /**
+     * Resets the buffer
+     */
+    public void clear() {
+        bufSize = 0;
+    }
+
+    /**
+     * Appends the data to the buffer. If the data is incorrectly formatted, ie, the data should always start with the
+     * header, false will be returned and the data will be discarded.
+     * @param b - bytes to be appended
+     * @param off - the offset to extract data from
+     * @param len - the number of bytes to append.
+     * @return true if the data was appended correctly. Returns false if the package is incorrect, ie missing header or something, or the length of data is 0
+     */
+    public boolean append(ByteBuffer b, int len) {
+        int newcount = bufSize + len;
+        if (newcount > buf.length) {
+            expand(newcount);
+        }
+        b.get(buf,bufSize,len);
+        
+        bufSize = newcount;
+        
+        if ( discard ) {
+            if (bufSize > START_DATA.length && (firstIndexOf(buf, 0, START_DATA) == -1)) {
+                bufSize = 0;
+                log.error("Discarded the package, invalid header");
+                return false;
+            }
+        }
+        return true;
+
+    }
+    
+    public boolean append(byte i) {
+        int newcount = bufSize + 1;
+        if (newcount > buf.length) {
+            expand(newcount);
+        }
+        buf[bufSize] = i;
+        bufSize = newcount;
+        return true;
+    }
+
+
+    public boolean append(boolean i) {
+        int newcount = bufSize + 1;
+        if (newcount > buf.length) {
+            expand(newcount);
+        }
+        XByteBuffer.toBytes(i,buf,bufSize);
+        bufSize = newcount;
+        return true;
+    }
+
+    public boolean append(long i) {
+        int newcount = bufSize + 8;
+        if (newcount > buf.length) {
+            expand(newcount);
+        }
+        XByteBuffer.toBytes(i,buf,bufSize);
+        bufSize = newcount;
+        return true;
+    }
+    
+    public boolean append(int i) {
+        int newcount = bufSize + 4;
+        if (newcount > buf.length) {
+            expand(newcount);
+        }
+        XByteBuffer.toBytes(i,buf,bufSize);
+        bufSize = newcount;
+        return true;
+    }
+
+    public boolean append(byte[] b, int off, int len) {
+        if ((off < 0) || (off > b.length) || (len < 0) ||
+            ((off + len) > b.length) || ((off + len) < 0))  {
+            throw new IndexOutOfBoundsException();
+        } else if (len == 0) {
+            return false;
+        }
+
+        int newcount = bufSize + len;
+        if (newcount > buf.length) {
+            expand(newcount);
+        }
+        System.arraycopy(b, off, buf, bufSize, len);
+        bufSize = newcount;
+
+        if ( discard ) {
+            if (bufSize > START_DATA.length && (firstIndexOf(buf, 0, START_DATA) == -1)) {
+                bufSize = 0;
+                log.error("Discarded the package, invalid header");
+                return false;
+            }
+        }
+        return true;
+    }
+
+    public void expand(int newcount) {
+        //don't change the allocation strategy
+        byte newbuf[] = new byte[Math.max(buf.length << 1, newcount)];
+        System.arraycopy(buf, 0, newbuf, 0, bufSize);
+        buf = newbuf;
+    }
+    
+    public int getCapacity() {
+        return buf.length;
+    }
+
+
+    /**
+     * Internal mechanism to make a check if a complete package exists
+     * within the buffer
+     * @return - true if a complete package (header,compress,size,data,footer) exists within the buffer
+     */
+    public int countPackages() {
+        return countPackages(false);
+    }
+
+    public int countPackages(boolean first)
+    {
+        int cnt = 0;
+        int pos = START_DATA.length;
+        int start = 0;
+
+        while ( start < bufSize ) {
+            //first check start header
+            int index = XByteBuffer.firstIndexOf(buf,start,START_DATA);
+            //if the header (START_DATA) isn't the first thing or
+            //the buffer isn't even 14 bytes
+            if ( index != start || ((bufSize-start)<14) ) break;
+            //next 4 bytes are compress flag not needed for count packages
+            //then get the size 4 bytes
+            int size = toInt(buf, pos);
+            //now the total buffer has to be long enough to hold
+            //START_DATA.length+4+size+END_DATA.length
+            pos = start + START_DATA.length + 4 + size;
+            if ( (pos + END_DATA.length) > bufSize) break;
+            //and finally check the footer of the package END_DATA
+            int newpos = firstIndexOf(buf, pos, END_DATA);
+            //mismatch, there is no package
+            if (newpos != pos) break;
+            //increase the packet count
+            cnt++;
+            //reset the values
+            start = pos + END_DATA.length;
+            pos = start + START_DATA.length;
+            //we only want to verify that we have at least one package
+            if ( first ) break;
+        }
+        return cnt;
+    }
+
+    /**
+     * Method to check if a package exists in this byte buffer.
+     * @return - true if a complete package (header,options,size,data,footer) exists within the buffer
+     */
+    public boolean doesPackageExist()  {
+        return (countPackages(true)>0);
+    }
+
+    /**
+     * Extracts the message bytes from a package.
+     * If no package exists, a IllegalStateException will be thrown.
+     * @param clearFromBuffer - if true, the package will be removed from the byte buffer
+     * @return - returns the actual message bytes (header, compress,size and footer not included).
+     */
+    public XByteBuffer extractDataPackage(boolean clearFromBuffer) {
+        int psize = countPackages(true);
+        if (psize == 0) {
+            throw new java.lang.IllegalStateException("No package exists in XByteBuffer");
+        }
+        int size = toInt(buf, START_DATA.length);
+        XByteBuffer xbuf = BufferPool.getBufferPool().getBuffer(size,false);
+        xbuf.setLength(size);
+        System.arraycopy(buf, START_DATA.length + 4, xbuf.getBytesDirect(), 0, size);
+        if (clearFromBuffer) {
+            int totalsize = START_DATA.length + 4 + size + END_DATA.length;
+            bufSize = bufSize - totalsize;
+            System.arraycopy(buf, totalsize, buf, 0, bufSize);
+        }
+        return xbuf;
+
+    }
+    
+    public ChannelData extractPackage(boolean clearFromBuffer) throws java.io.IOException {
+        XByteBuffer xbuf = extractDataPackage(clearFromBuffer);
+        ChannelData cdata = ChannelData.getDataFromPackage(xbuf);
+        return cdata;
+    }
+    
+    /**
+     * Creates a complete data package
+     * @param indata - the message data to be contained within the package
+     * @param compressed - compression flag for the indata buffer
+     * @return - a full package (header,size,data,footer)
+     * 
+     */
+    public static byte[] createDataPackage(ChannelData cdata) {
+//        return createDataPackage(cdata.getDataPackage());
+        //avoid one extra byte array creation
+        int dlength = cdata.getDataPackageLength();
+        int length = getDataPackageLength(dlength);
+        byte[] data = new byte[length];
+        int offset = 0;
+        System.arraycopy(START_DATA, 0, data, offset, START_DATA.length);
+        offset += START_DATA.length;
+        toBytes(dlength,data, START_DATA.length);
+        offset += 4;
+        cdata.getDataPackage(data,offset);
+        offset += dlength;
+        System.arraycopy(END_DATA, 0, data, offset, END_DATA.length);
+        offset += END_DATA.length;
+        return data;
+    }
+    
+    public static byte[] createDataPackage(byte[] data, int doff, int dlength, byte[] buffer, int bufoff) {
+        if ( (buffer.length-bufoff) > getDataPackageLength(dlength) ) {
+            throw new ArrayIndexOutOfBoundsException("Unable to create data package, buffer is too small.");
+        }
+        System.arraycopy(START_DATA, 0, buffer, bufoff, START_DATA.length);
+        toBytes(data.length,buffer, bufoff+START_DATA.length);
+        System.arraycopy(data, doff, buffer, bufoff+START_DATA.length + 4, dlength);
+        System.arraycopy(END_DATA, 0, buffer, bufoff+START_DATA.length + 4 + data.length, END_DATA.length);
+        return buffer;
+    }
+
+    
+    public static int getDataPackageLength(int datalength) {
+        int length = 
+            START_DATA.length + //header length
+            4 + //data length indicator
+            datalength + //actual data length
+            END_DATA.length; //footer length
+        return length;
+
+    }
+    
+    public static byte[] createDataPackage(byte[] data) {
+        int length = getDataPackageLength(data.length);
+        byte[] result = new byte[length];
+        return createDataPackage(data,0,data.length,result,0);
+    }
+    
+    
+
+//    public static void fillDataPackage(byte[] data, int doff, int dlength, XByteBuffer buf) {
+//        int pkglen = getDataPackageLength(dlength);
+//        if ( buf.getCapacity() <  pkglen ) buf.expand(pkglen);
+//        createDataPackage(data,doff,dlength,buf.getBytesDirect(),buf.getLength());
+//    }
+
+    /**
+     * Convert four bytes to an int
+     * @param b - the byte array containing the four bytes
+     * @param off - the offset
+     * @return the integer value constructed from the four bytes
+     * @exception java.lang.ArrayIndexOutOfBoundsException
+     */
+    public static int toInt(byte[] b,int off){
+        return ( ( (int) b[off+3]) & 0xFF) +
+            ( ( ( (int) b[off+2]) & 0xFF) << 8) +
+            ( ( ( (int) b[off+1]) & 0xFF) << 16) +
+            ( ( ( (int) b[off+0]) & 0xFF) << 24);
+    }
+
+    /**
+     * Convert eight bytes to a long
+     * @param b - the byte array containing the four bytes
+     * @param off - the offset
+     * @return the long value constructed from the eight bytes
+     * @exception java.lang.ArrayIndexOutOfBoundsException
+     */
+    public static long toLong(byte[] b,int off){
+        return ( ( (long) b[off+7]) & 0xFF) +
+            ( ( ( (long) b[off+6]) & 0xFF) << 8) +
+            ( ( ( (long) b[off+5]) & 0xFF) << 16) +
+            ( ( ( (long) b[off+4]) & 0xFF) << 24) +
+            ( ( ( (long) b[off+3]) & 0xFF) << 32) +
+            ( ( ( (long) b[off+2]) & 0xFF) << 40) +
+            ( ( ( (long) b[off+1]) & 0xFF) << 48) +
+            ( ( ( (long) b[off+0]) & 0xFF) << 56);
+    }
+
+    
+    /**
+     * Converts an integer to four bytes
+     * @param n - the integer
+     * @return - four bytes in an array
+     * @deprecated use toBytes(boolean,byte[],int)
+     */
+    public static byte[] toBytes(boolean bool) {
+        byte[] b = new byte[1] ;
+        return toBytes(bool,b,0);
+
+    }
+    
+    public static byte[] toBytes(boolean bool, byte[] data, int offset) {
+        data[offset] = (byte)(bool?1:0);
+        return data;
+    }
+    
+    /**
+     * 
+     * @param <any> long
+     * @return use
+     */
+    public static boolean toBoolean(byte[] b, int offset) {
+        return b[offset] != 0;
+    }
+
+    
+    /**
+     * Converts an integer to four bytes
+     * @param n - the integer
+     * @return - four bytes in an array
+     * @deprecated use toBytes(int,byte[],int)
+     */
+    public static byte[] toBytes(int n) {
+        return toBytes(n,new byte[4],0);
+    }
+
+    public static byte[] toBytes(int n,byte[] b, int offset) {
+        b[offset+3] = (byte) (n);
+        n >>>= 8;
+        b[offset+2] = (byte) (n);
+        n >>>= 8;
+        b[offset+1] = (byte) (n);
+        n >>>= 8;
+        b[offset+0] = (byte) (n);
+        return b;
+    }
+
+    /**
+     * Converts an long to eight bytes
+     * @param n - the long
+     * @return - eight bytes in an array
+     * @deprecated use toBytes(long,byte[],int)
+     */
+    public static byte[] toBytes(long n) {
+        return toBytes(n,new byte[8],0);
+    }
+    public static byte[] toBytes(long n, byte[] b, int offset) {
+        b[offset+7] = (byte) (n);
+        n >>>= 8;
+        b[offset+6] = (byte) (n);
+        n >>>= 8;
+        b[offset+5] = (byte) (n);
+        n >>>= 8;
+        b[offset+4] = (byte) (n);
+        n >>>= 8;
+        b[offset+3] = (byte) (n);
+        n >>>= 8;
+        b[offset+2] = (byte) (n);
+        n >>>= 8;
+        b[offset+1] = (byte) (n);
+        n >>>= 8;
+        b[offset+0] = (byte) (n);
+        return b;
+    }
+
+    /**
+     * Similar to a String.IndexOf, but uses pure bytes
+     * @param src - the source bytes to be searched
+     * @param srcOff - offset on the source buffer
+     * @param find - the string to be found within src
+     * @return - the index of the first matching byte. -1 if the find array is not found
+     */
+    public static int firstIndexOf(byte[] src, int srcOff, byte[] find){
+        int result = -1;
+        if (find.length > src.length) return result;
+        if (find.length == 0 || src.length == 0) return result;
+        if (srcOff >= src.length ) throw new java.lang.ArrayIndexOutOfBoundsException();
+        boolean found = false;
+        int srclen = src.length;
+        int findlen = find.length;
+        byte first = find[0];
+        int pos = srcOff;
+        while (!found) {
+            //find the first byte
+            while (pos < srclen){
+                if (first == src[pos])
+                    break;
+                pos++;
+            }
+            if (pos >= srclen)
+                return -1;
+
+            //we found the first character
+            //match the rest of the bytes - they have to match
+            if ( (srclen - pos) < findlen)
+                return -1;
+            //assume it does exist
+            found = true;
+            for (int i = 1; ( (i < findlen) && found); i++)
+                found = found && (find[i] == src[pos + i]);
+            if (found)
+                result = pos;
+            else if ( (srclen - pos) < findlen)
+                return -1; //no more matches possible
+            else
+                pos++;
+        }
+        return result;
+    }
+
+    
+    public static Serializable deserialize(byte[] data) 
+        throws IOException, ClassNotFoundException, ClassCastException {
+        return deserialize(data,0,data.length);
+    }
+    
+    public static Serializable deserialize(byte[] data, int offset, int length)  
+        throws IOException, ClassNotFoundException, ClassCastException {
+        return deserialize(data,offset,length,null);     
+    }
+    public static int invokecount = 0;
+    public static Serializable deserialize(byte[] data, int offset, int length, ClassLoader[] cls) 
+        throws IOException, ClassNotFoundException, ClassCastException {
+        synchronized (XByteBuffer.class) { invokecount++;}
+        Object message = null;
+        if ( cls == null ) cls = new ClassLoader[0];
+        if (data != null) {
+            InputStream  instream = new ByteArrayInputStream(data,offset,length);
+            ObjectInputStream stream = null;
+            stream = (cls.length>0)? new ReplicationStream(instream,cls):new ObjectInputStream(instream);
+            message = stream.readObject();
+            instream.close();
+            stream.close();
+        }
+        if ( message == null ) {
+            return null;
+        } else if (message instanceof Serializable)
+            return (Serializable) message;
+        else {
+            throw new ClassCastException("Message has the wrong class. It should implement Serializable, instead it is:"+message.getClass().getName());
+        }
+    }
+
+    /**
+     * Serializes a message into cluster data
+     * @param msg ClusterMessage
+     * @param compress boolean
+     * @return 
+     * @throws IOException
+     */
+    public static byte[] serialize(Serializable msg) throws IOException {
+        ByteArrayOutputStream outs = new ByteArrayOutputStream();
+        ObjectOutputStream out = new ObjectOutputStream(outs);
+        out.writeObject(msg);
+        out.flush();
+        byte[] data = outs.toByteArray();
+        return data;
+    }
+
+    public void setDiscard(boolean discard) {
+        this.discard = discard;
+    }
+
+    public boolean getDiscard() {
+        return discard;
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/mbeans-descriptors.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/mbeans-descriptors.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/mbeans-descriptors.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,94 @@
+<?xml version="1.0"?>
+<mbeans-descriptors>
+
+  <mbean         name="SimpleTcpCluster"
+            className="org.apache.catalina.mbeans.ClassNameMBean"
+          description="Tcp Cluster implementation"
+               domain="Catalina"
+                group="Cluster"
+                 type="org.apache.catalina.cluster.tcp.SimpleTcpCluster">
+
+    <attribute   name="protocolStack"
+          description="JavaGroups protocol stack selection"
+                 type="java.lang.String"/>
+
+  </mbean>
+
+
+  <mbean         name="SimpleTcpReplicationManager"
+            className="org.apache.catalina.mbeans.ClassNameMBean"
+          description="Clustered implementation of the Manager interface"
+               domain="Catalina"
+                group="Manager"
+                 type="org.apache.catalina.cluster.tcp.SimpleTcpReplicationManager">
+
+    <attribute   name="algorithm"
+          description="The message digest algorithm to be used when generating
+                       session identifiers"
+                 type="java.lang.String"/>
+
+    <attribute   name="checkInterval"
+          description="The interval (in seconds) between checks for expired
+                       sessions"
+                 type="int"/>
+
+    <attribute   name="className"
+          description="Fully qualified class name of the managed object"
+                 type="java.lang.String"
+            writeable="false"/>
+
+    <attribute   name="distributable"
+          description="The distributable flag for Sessions created by this
+                       Manager"
+                 type="boolean"/>
+
+    <attribute   name="entropy"
+          description="A String initialization parameter used to increase the
+                       entropy of the initialization of our random number
+                       generator"
+                 type="java.lang.String"/>
+
+    <attribute   name="managedResource"
+          description="The managed resource this MBean is associated with"
+                 type="java.lang.Object"/>
+
+    <attribute   name="maxActiveSessions"
+          description="The maximum number of active Sessions allowed, or -1
+                       for no limit"
+                 type="int"/>
+
+    <attribute   name="maxInactiveInterval"
+          description="The default maximum inactive interval for Sessions
+                       created by this Manager"
+                 type="int"/>
+
+    <attribute   name="name"
+          description="The descriptive name of this Manager implementation
+                       (for logging)"
+                 type="java.lang.String"
+            writeable="false"/>
+
+  </mbean>
+
+
+
+<mbean         name="ReplicationValve"
+            className="org.apache.catalina.mbeans.ClassNameMBean"
+          description="Valve for simple tcp replication"
+               domain="Catalina"
+                group="Valve"
+                 type="org.apache.catalina.cluster.tcp.ReplicationValve">
+
+    <attribute   name="className"
+          description="Fully qualified class name of the managed object"
+                 type="java.lang.String"
+            writeable="false"/>
+
+    <attribute   name="debug"
+          description="The debugging detail level for this component"
+                 type="int"/>
+
+  </mbean>
+
+
+</mbeans-descriptors>

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/membership/Constants.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/membership/Constants.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/membership/Constants.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,39 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tribes.membership;
+
+import org.apache.catalina.tribes.util.Arrays;
+
+
+/**
+ * Manifest constants for the <code>org.apache.catalina.tribes.membership</code>
+ * package.
+ *
+ * @author Peter Rossbach
+ * @version $Revision: 303950 $ $Date: 2005-06-09 15:38:30 -0500 (Thu, 09 Jun 2005) $
+ * @author Filip Hanik
+ */
+
+public class Constants {
+
+    public static final String Package = "org.apache.catalina.tribes.membership";
+    public static void main(String[] args) throws Exception {
+        System.out.println(Arrays.toString("TRIBES-B".getBytes()));
+        System.out.println(Arrays.toString("TRIBES-E".getBytes()));
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/membership/LocalStrings.properties
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/membership/LocalStrings.properties	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/membership/LocalStrings.properties	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1 @@
+cluster.mbean.register.already=MBean {0} already registered!

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/membership/McastService.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/membership/McastService.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/membership/McastService.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,448 @@
+/*
+ * Copyright 1999,2004-2005 The Apache Software Foundation.
+ * 
+ * Licensed 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.tribes.membership;
+
+import java.util.Properties;
+
+import org.apache.catalina.tribes.Member;
+import org.apache.catalina.tribes.MembershipListener;
+import org.apache.catalina.tribes.MembershipService;
+import org.apache.catalina.tribes.util.StringManager;
+import org.apache.catalina.tribes.util.UUIDGenerator;
+import java.io.IOException;
+
+/**
+ * A <b>membership</b> implementation using simple multicast.
+ * This is the representation of a multicast membership service.
+ * This class is responsible for maintaining a list of active cluster nodes in the cluster.
+ * If a node fails to send out a heartbeat, the node will be dismissed.
+ *
+ * @author Filip Hanik
+ * @version $Revision: 378093 $, $Date: 2006-02-15 15:13:45 -0600 (Wed, 15 Feb 2006) $
+ */
+
+
+public class McastService implements MembershipService,MembershipListener {
+
+    private static org.apache.commons.logging.Log log =
+        org.apache.commons.logging.LogFactory.getLog( McastService.class );
+
+    /**
+     * The string manager for this package.
+     */
+    protected StringManager sm = StringManager.getManager(Constants.Package);
+
+    /**
+     * The descriptive information about this implementation.
+     */
+    private static final String info = "McastService/2.1";
+
+    /**
+     * The implementation specific properties
+     */
+    protected Properties properties = new Properties();
+    /**
+     * A handle to the actual low level implementation
+     */
+    protected McastServiceImpl impl;
+    /**
+     * A membership listener delegate (should be the cluster :)
+     */
+    protected MembershipListener listener;
+    /**
+     * The local member
+     */
+    protected MemberImpl localMember ;
+    private int mcastSoTimeout;
+    private int mcastTTL;
+    
+    protected byte[] payload;
+    
+    protected byte[] domain;
+
+    /**
+     * Create a membership service.
+     */
+    public McastService() {
+        //default values
+        properties.setProperty("mcastPort","45564");
+        properties.setProperty("mcastAddress","228.0.0.4");
+        properties.setProperty("memberDropTime","3000");
+        properties.setProperty("mcastFrequency","500");
+
+    }
+
+    /**
+     * Return descriptive information about this implementation and the
+     * corresponding version number, in the format
+     * <code>&lt;description&gt;/&lt;version&gt;</code>.
+     */
+    public String getInfo() {
+        return (info);
+    }
+    
+    /**
+     *
+     * @param properties
+     * <BR/>All are required<BR />
+     * 1. mcastPort - the port to listen to<BR>
+     * 2. mcastAddress - the mcast group address<BR>
+     * 4. bindAddress - the bind address if any - only one that can be null<BR>
+     * 5. memberDropTime - the time a member is gone before it is considered gone.<BR>
+     * 6. mcastFrequency - the frequency of sending messages<BR>
+     * 7. tcpListenPort - the port this member listens to<BR>
+     * 8. tcpListenHost - the bind address of this member<BR>
+     * @exception java.lang.IllegalArgumentException if a property is missing.
+     */
+    public void setProperties(Properties properties) {
+        hasProperty(properties,"mcastPort");
+        hasProperty(properties,"mcastAddress");
+        hasProperty(properties,"memberDropTime");
+        hasProperty(properties,"mcastFrequency");
+        hasProperty(properties,"tcpListenPort");
+        hasProperty(properties,"tcpListenHost");
+        this.properties = properties;
+    }
+
+    /**
+     * Return the properties, see setProperties
+     */
+    public Properties getProperties() {
+        return properties;
+    }
+
+    /**
+     * Return the local member name
+     */
+    public String getLocalMemberName() {
+        return localMember.toString() ;
+    }
+ 
+    /**
+     * Return the local member
+     */
+    public Member getLocalMember(boolean alive) {
+        if ( alive && localMember != null && impl != null) localMember.setMemberAliveTime(System.currentTimeMillis()-impl.getServiceStartTime());
+        return localMember;
+    }
+    
+    /**
+     * Sets the local member properties for broadcasting
+     */
+    public void setLocalMemberProperties(String listenHost, int listenPort) {
+        properties.setProperty("tcpListenHost",listenHost);
+        properties.setProperty("tcpListenPort",String.valueOf(listenPort));
+        try {
+            if (localMember != null) {
+                localMember.setHostname(listenHost);
+                localMember.setPort(listenPort);
+            } else {
+                localMember = new MemberImpl(listenHost, listenPort, 0);
+                localMember.setUniqueId(UUIDGenerator.randomUUID(true));
+                localMember.setPayload(getPayload());
+                localMember.setDomain(getDomain());
+            }
+            localMember.getData(true, true);
+        }catch ( IOException x ) {
+            throw new IllegalArgumentException(x);
+        }
+    }
+    
+    public void setMcastAddr(String addr) {
+        properties.setProperty("mcastAddress", addr);
+    }
+
+    public String getMcastAddr() {
+        return properties.getProperty("mcastAddress");
+    }
+
+    public void setMcastBindAddress(String bindaddr) {
+        properties.setProperty("mcastBindAddress", bindaddr);
+    }
+
+    public String getMcastBindAddress() {
+        return properties.getProperty("mcastBindAddress");
+    }
+
+    public void setMcastPort(int port) {
+        properties.setProperty("mcastPort", String.valueOf(port));
+    }
+
+    public int getMcastPort() {
+        String p = properties.getProperty("mcastPort");
+        return new Integer(p).intValue();
+    }
+    
+    public void setMcastFrequency(long time) {
+        properties.setProperty("mcastFrequency", String.valueOf(time));
+    }
+
+    public long getMcastFrequency() {
+        String p = properties.getProperty("mcastFrequency");
+        return new Long(p).longValue();
+    }
+
+    public void setMcastDropTime(long time) {
+        properties.setProperty("memberDropTime", String.valueOf(time));
+    }
+
+    public long getMcastDropTime() {
+        String p = properties.getProperty("memberDropTime");
+        return new Long(p).longValue();
+    }
+
+    /**
+     * Check if a required property is available.
+     * @param properties The set of properties
+     * @param name The property to check for
+     */
+    protected void hasProperty(Properties properties, String name){
+        if ( properties.getProperty(name)==null) throw new IllegalArgumentException("McastService:Required property \""+name+"\" is missing.");
+    }
+
+    /**
+     * Start broadcasting and listening to membership pings
+     * @throws java.lang.Exception if a IO error occurs
+     */
+    public void start() throws java.lang.Exception {
+        start(MembershipService.MBR_RX);
+        start(MembershipService.MBR_TX);
+    }
+    
+    public void start(int level) throws java.lang.Exception {
+        hasProperty(properties,"mcastPort");
+        hasProperty(properties,"mcastAddress");
+        hasProperty(properties,"memberDropTime");
+        hasProperty(properties,"mcastFrequency");
+        hasProperty(properties,"tcpListenPort");
+        hasProperty(properties,"tcpListenHost");
+
+        if ( impl != null ) {
+            impl.start(level);
+            return;
+        }
+        String host = getProperties().getProperty("tcpListenHost");
+        int port = Integer.parseInt(getProperties().getProperty("tcpListenPort"));
+        
+        if ( localMember == null ) {
+            localMember = new MemberImpl(host, port, 100);
+            localMember.setUniqueId(UUIDGenerator.randomUUID(true));
+        } else {
+            localMember.setHostname(host);
+            localMember.setPort(port);
+            localMember.setMemberAliveTime(100);
+        }
+        if ( this.payload != null ) localMember.setPayload(payload);
+        if ( this.domain != null ) localMember.setDomain(domain);
+        localMember.setServiceStartTime(System.currentTimeMillis());
+        java.net.InetAddress bind = null;
+        if ( properties.getProperty("mcastBindAddress")!= null ) {
+            bind = java.net.InetAddress.getByName(properties.getProperty("mcastBindAddress"));
+        }
+        int ttl = -1;
+        int soTimeout = -1;
+        if ( properties.getProperty("mcastTTL") != null ) {
+            try {
+                ttl = Integer.parseInt(properties.getProperty("mcastTTL"));
+            } catch ( Exception x ) {
+                log.error("Unable to parse mcastTTL="+properties.getProperty("mcastTTL"),x);
+            }
+        }
+        if ( properties.getProperty("mcastSoTimeout") != null ) {
+            try {
+                soTimeout = Integer.parseInt(properties.getProperty("mcastSoTimeout"));
+            } catch ( Exception x ) {
+                log.error("Unable to parse mcastSoTimeout="+properties.getProperty("mcastSoTimeout"),x);
+            }
+        }
+
+        impl = new McastServiceImpl((MemberImpl)localMember,Long.parseLong(properties.getProperty("mcastFrequency")),
+                                    Long.parseLong(properties.getProperty("memberDropTime")),
+                                    Integer.parseInt(properties.getProperty("mcastPort")),
+                                    bind,
+                                    java.net.InetAddress.getByName(properties.getProperty("mcastAddress")),
+                                    ttl,
+                                    soTimeout,
+                                    this);
+        
+        impl.start(level);
+		
+
+    }
+
+ 
+    /**
+     * Stop broadcasting and listening to membership pings
+     */
+    public void stop(int svc) {
+        try  {
+            if ( impl != null && impl.stop(svc) ) impl = null;
+        } catch ( Exception x)  {
+            log.error("Unable to stop the mcast service, level:"+svc+".",x);
+        }
+    }
+
+
+    /**
+     * Return all the members by name
+     */
+    public String[] getMembersByName() {
+        Member[] currentMembers = getMembers();
+        String [] membernames ;
+        if(currentMembers != null) {
+            membernames = new String[currentMembers.length];
+            for (int i = 0; i < currentMembers.length; i++) {
+                membernames[i] = currentMembers[i].toString() ;
+            }
+        } else
+            membernames = new String[0] ;
+        return membernames ;
+    }
+ 
+    /**
+     * Return the member by name
+     */
+    public Member findMemberByName(String name) {
+        Member[] currentMembers = getMembers();
+        for (int i = 0; i < currentMembers.length; i++) {
+            if (name.equals(currentMembers[i].toString()))
+                return currentMembers[i];
+        }
+        return null;
+    }
+
+    /**
+     * has members?
+     */
+    public boolean hasMembers() {
+       if ( impl == null || impl.membership == null ) return false;
+       return impl.membership.hasMembers();
+    }
+    
+    public Member getMember(Member mbr) {
+        if ( impl == null || impl.membership == null ) return null;
+        return impl.membership.getMember(mbr);
+    }
+
+    /**
+     * Return all the members
+     */
+    public Member[] getMembers() {
+        if ( impl == null || impl.membership == null ) return null;
+        return impl.membership.getMembers();
+    }
+    /**
+     * Add a membership listener, this version only supports one listener per service,
+     * so calling this method twice will result in only the second listener being active.
+     * @param listener The listener
+     */
+    public void setMembershipListener(MembershipListener listener) {
+        this.listener = listener;
+    }
+    /**
+     * Remove the membership listener
+     */
+    public void removeMembershipListener(){
+        listener = null;
+    }
+
+    public void memberAdded(Member member) {
+        if ( listener!=null ) listener.memberAdded(member);
+    }
+
+    /**
+     * Callback from the impl when a new member has been received
+     * @param member The member
+     */
+    public void memberDisappeared(Member member)
+    {
+        if ( listener!=null ) listener.memberDisappeared(member);
+    }
+
+    public int getMcastSoTimeout() {
+        return mcastSoTimeout;
+    }
+    public void setMcastSoTimeout(int mcastSoTimeout) {
+        this.mcastSoTimeout = mcastSoTimeout;
+        properties.setProperty("mcastSoTimeout", String.valueOf(mcastSoTimeout));
+    }
+    public int getMcastTTL() {
+        return mcastTTL;
+    }
+
+    public byte[] getPayload() {
+        return payload;
+    }
+    
+    public byte[] getDomain() {
+        return domain;
+    }
+
+    public void setMcastTTL(int mcastTTL) {
+        this.mcastTTL = mcastTTL;
+        properties.setProperty("mcastTTL", String.valueOf(mcastTTL));
+    }
+
+    public void setPayload(byte[] payload) {
+        this.payload = payload;
+        if ( localMember != null ) {
+            localMember.setPayload(payload);
+            localMember.getData(true,true);
+            try {
+                if (impl != null) impl.send(false);
+            }catch ( Exception x ) {
+                log.error("Unable to send payload update.",x);
+            }
+        }
+    }
+    
+    public void setDomain(byte[] domain) {
+        this.domain = domain;
+        if ( localMember != null ) {
+            localMember.setDomain(domain);
+            localMember.getData(true,true);
+            try {
+                if (impl != null) impl.send(false);
+            }catch ( Exception x ) {
+                log.error("Unable to send domain update.",x);
+            }
+        }
+    }
+
+    /**
+     * Simple test program
+     * @param args Command-line arguments
+     * @throws Exception If an error occurs
+     */
+    public static void main(String args[]) throws Exception {
+		if(log.isInfoEnabled())
+            log.info("Usage McastService hostname tcpport");
+        McastService service = new McastService();
+        java.util.Properties p = new java.util.Properties();
+        p.setProperty("mcastPort","5555");
+        p.setProperty("mcastAddress","224.10.10.10");
+        p.setProperty("mcastClusterDomain","catalina");
+        p.setProperty("bindAddress","localhost");
+        p.setProperty("memberDropTime","3000");
+        p.setProperty("mcastFrequency","500");
+        p.setProperty("tcpListenPort","4000");
+        p.setProperty("tcpListenHost","127.0.0.1");
+        service.setProperties(p);
+        service.start();
+        Thread.sleep(60*1000*60);
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/membership/McastServiceImpl.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/membership/McastServiceImpl.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/membership/McastServiceImpl.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,397 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tribes.membership;
+
+
+import java.io.IOException;
+import java.net.DatagramPacket;
+import java.net.InetAddress;
+import java.net.MulticastSocket;
+
+import org.apache.catalina.tribes.MembershipListener;
+import java.util.Arrays;
+import java.net.SocketTimeoutException;
+import org.apache.catalina.tribes.Member;
+import org.apache.catalina.tribes.Channel;
+import java.net.InetSocketAddress;
+
+/**
+ * A <b>membership</b> implementation using simple multicast.
+ * This is the representation of a multicast membership service.
+ * This class is responsible for maintaining a list of active cluster nodes in the cluster.
+ * If a node fails to send out a heartbeat, the node will be dismissed.
+ * This is the low level implementation that handles the multicasting sockets.
+ * Need to fix this, could use java.nio and only need one thread to send and receive, or
+ * just use a timeout on the receive
+ * @author Filip Hanik
+ * @version $Revision: 356540 $, $Date: 2005-12-13 10:53:40 -0600 (Tue, 13 Dec 2005) $
+ */
+public class McastServiceImpl
+{
+    private static org.apache.commons.logging.Log log =
+        org.apache.commons.logging.LogFactory.getLog( McastService.class );
+    
+    protected static int MAX_PACKET_SIZE = 65535;
+    /**
+     * Internal flag used for the listen thread that listens to the multicasting socket.
+     */
+    protected boolean doRunSender = false;
+    protected boolean doRunReceiver = false;
+    protected int startLevel = 0;
+    /**
+     * Socket that we intend to listen to
+     */
+    protected MulticastSocket socket;
+    /**
+     * The local member that we intend to broad cast over and over again
+     */
+    protected MemberImpl member;
+    /**
+     * The multicast address
+     */
+    protected InetAddress address;
+    /**
+     * The multicast port
+     */
+    protected int port;
+    /**
+     * The time it takes for a member to expire.
+     */
+    protected long timeToExpiration;
+    /**
+     * How often to we send out a broadcast saying we are alive, must be smaller than timeToExpiration
+     */
+    protected long sendFrequency;
+    /**
+     * Reuse the sendPacket, no need to create a new one everytime
+     */
+    protected DatagramPacket sendPacket;
+    /**
+     * Reuse the receivePacket, no need to create a new one everytime
+     */
+    protected DatagramPacket receivePacket;
+    /**
+     * The membership, used so that we calculate memberships when they arrive or don't arrive
+     */
+    protected Membership membership;
+    /**
+     * The actual listener, for callback when shits goes down
+     */
+    protected MembershipListener service;
+    /**
+     * Thread to listen for pings
+     */
+    protected ReceiverThread receiver;
+    /**
+     * Thread to send pings
+     */
+    protected SenderThread sender;
+
+    /**
+     * When was the service started
+     */
+    protected long serviceStartTime = System.currentTimeMillis();
+    
+    /**
+     * Time to live for the multicast packets that are being sent out
+     */
+    protected int mcastTTL = -1;
+    /**
+     * Read timeout on the mcast socket
+     */
+    protected int mcastSoTimeout = -1;
+    /**
+     * bind address
+     */
+    protected InetAddress mcastBindAddress = null;
+    
+    /**
+     * Create a new mcast service impl
+     * @param member - the local member
+     * @param sendFrequency - the time (ms) in between pings sent out
+     * @param expireTime - the time (ms) for a member to expire
+     * @param port - the mcast port
+     * @param bind - the bind address (not sure this is used yet)
+     * @param mcastAddress - the mcast address
+     * @param service - the callback service
+     * @throws IOException
+     */
+    public McastServiceImpl(
+        MemberImpl member,
+        long sendFrequency,
+        long expireTime,
+        int port,
+        InetAddress bind,
+        InetAddress mcastAddress,
+        int ttl,
+        int soTimeout,
+        MembershipListener service)
+    throws IOException {
+        this.member = member;
+        this.address = mcastAddress;
+        this.port = port;
+        this.mcastSoTimeout = soTimeout;
+        this.mcastTTL = ttl;
+        this.mcastBindAddress = bind;
+        this.timeToExpiration = expireTime;
+        this.service = service;
+        this.sendFrequency = sendFrequency;
+        setupSocket();
+        sendPacket = new DatagramPacket(new byte[MAX_PACKET_SIZE],MAX_PACKET_SIZE);
+        sendPacket.setAddress(address);
+        sendPacket.setPort(port);
+        receivePacket = new DatagramPacket(new byte[MAX_PACKET_SIZE],MAX_PACKET_SIZE);
+        receivePacket.setAddress(address);
+        receivePacket.setPort(port);
+        membership = new Membership(member);
+    }
+    
+    protected void setupSocket() throws IOException {
+        if (mcastBindAddress != null) socket = new MulticastSocket(new InetSocketAddress(mcastBindAddress, port));
+        else socket = new MulticastSocket(port);
+        if (mcastBindAddress != null) {
+			if(log.isInfoEnabled())
+                log.info("Setting multihome multicast interface to:" +mcastBindAddress);
+            socket.setInterface(mcastBindAddress);
+        } //end if
+        //force a so timeout so that we don't block forever
+        if ( mcastSoTimeout <= 0 ) mcastSoTimeout = (int)sendFrequency;
+        if(log.isInfoEnabled())
+            log.info("Setting cluster mcast soTimeout to "+mcastSoTimeout);
+        socket.setSoTimeout(mcastSoTimeout);
+
+        if ( mcastTTL >= 0 ) {
+			if(log.isInfoEnabled())
+                log.info("Setting cluster mcast TTL to " + mcastTTL);
+            socket.setTimeToLive(mcastTTL);
+        }
+    }
+    
+    
+
+    /**
+     * Start the service
+     * @param level 1 starts the receiver, level 2 starts the sender
+     * @throws IOException if the service fails to start
+     * @throws IllegalStateException if the service is already started
+     */
+    public synchronized void start(int level) throws IOException {
+        boolean valid = false;
+        if ( (level & Channel.MBR_RX_SEQ)==Channel.MBR_RX_SEQ ) {
+            if ( receiver != null ) throw new IllegalStateException("McastService.receive already running.");
+            if ( sender == null ) socket.joinGroup(address);
+            doRunReceiver = true;
+            receiver = new ReceiverThread();
+            receiver.setDaemon(true);
+            receiver.start();
+            valid = true;
+        } 
+        if ( (level & Channel.MBR_TX_SEQ)==Channel.MBR_TX_SEQ ) {
+            if ( sender != null ) throw new IllegalStateException("McastService.send already running.");
+            if ( receiver == null ) socket.joinGroup(address);
+            //make sure at least one packet gets out there
+            send(false);
+            doRunSender = true;
+            serviceStartTime = System.currentTimeMillis();
+            sender = new SenderThread(sendFrequency);
+            sender.setDaemon(true);
+            sender.start();
+            //we have started the receiver, but not yet waited for membership to establish
+            valid = true;
+        } 
+        if (!valid) {
+            throw new IllegalArgumentException("Invalid start level. Only acceptable levels are Channel.MBR_RX_SEQ and Channel.MBR_TX_SEQ");
+        }
+        //pause, once or twice
+        waitForMembers(level);
+        startLevel = (startLevel | level);
+    }
+
+    private void waitForMembers(int level) {
+        long memberwait = sendFrequency*2;
+        if(log.isInfoEnabled())
+            log.info("Sleeping for "+memberwait+" milliseconds to establish cluster membership, start level:"+level);
+        try {Thread.sleep(memberwait);}catch (InterruptedException ignore){}
+        if(log.isInfoEnabled())
+            log.info("Done sleeping, membership established, start level:"+level);
+    }
+
+    /**
+     * Stops the service
+     * @throws IOException if the service fails to disconnect from the sockets
+     */
+    public synchronized boolean stop(int level) throws IOException {
+        boolean valid = false;
+        
+        if ( (level & Channel.MBR_RX_SEQ)==Channel.MBR_RX_SEQ ) {
+            valid = true;
+            doRunReceiver = false;
+            if ( receiver !=null ) receiver.interrupt();
+            receiver = null;
+        } 
+        if ( (level & Channel.MBR_TX_SEQ)==Channel.MBR_TX_SEQ ) {
+            valid = true;
+            doRunSender = false;
+            if ( sender != null )sender.interrupt();
+            sender = null;
+        } 
+        
+        if (!valid) {
+            throw new IllegalArgumentException("Invalid stop level. Only acceptable levels are Channel.MBR_RX_SEQ and Channel.MBR_TX_SEQ");
+        }
+        startLevel = (startLevel & (~level));
+        //we're shutting down, send a shutdown message and close the socket
+        if ( startLevel == 0 ) {
+            //send a stop message
+            member.setCommand(Member.SHUTDOWN_PAYLOAD);
+            member.getData(true, true);
+            send(false);
+            //leave mcast group
+            try {socket.leaveGroup(address);}catch ( Exception ignore){}
+            serviceStartTime = Long.MAX_VALUE;
+        }
+        return (startLevel == 0);
+    }
+
+    /**
+     * Receive a datagram packet, locking wait
+     * @throws IOException
+     */
+    public void receive() throws IOException {
+        try {
+            socket.receive(receivePacket);
+            if(receivePacket.getLength() > MAX_PACKET_SIZE) {
+                log.error("Multicast packet received was too long, dropping package:"+receivePacket.getLength());
+            } else {
+                byte[] data = new byte[receivePacket.getLength()];
+                System.arraycopy(receivePacket.getData(), receivePacket.getOffset(), data, 0, data.length);
+                final MemberImpl m = MemberImpl.getMember(data);
+                if (log.isTraceEnabled()) log.trace("Mcast receive ping from member " + m);
+                Thread t = null;
+                if (Arrays.equals(m.getCommand(), Member.SHUTDOWN_PAYLOAD)) {
+                    if (log.isDebugEnabled()) log.debug("Member has shutdown:" + m);
+                    membership.removeMember(m);
+                    t = new Thread() {
+                        public void run() {
+                            service.memberDisappeared(m);
+                        }
+                    };
+                } else if (membership.memberAlive(m)) {
+                    if (log.isDebugEnabled()) log.debug("Mcast add member " + m);
+                    t = new Thread() {
+                        public void run() {
+                            service.memberAdded(m);
+                        }
+                    };
+                } //end if
+                if ( t != null ) t.start();
+            }
+        } catch (SocketTimeoutException x ) { 
+            //do nothing, this is normal, we don't want to block forever
+            //since the receive thread is the same thread
+            //that does membership expiration
+        }
+        checkExpired();
+    }
+    
+    protected Object expiredMutex = new Object();
+    protected void checkExpired() {
+        synchronized (expiredMutex) {
+            MemberImpl[] expired = membership.expire(timeToExpiration);
+            for (int i = 0; i < expired.length; i++) {
+                final MemberImpl member = expired[i];
+                if (log.isDebugEnabled())
+                    log.debug("Mcast exipre  member " + expired[i]);
+                try {
+                    Thread t = new Thread() {
+                        public void run() {
+                            service.memberDisappeared(member);
+                        }
+                    };
+                    t.start();
+                } catch (Exception x) {
+                    log.error("Unable to process member disappeared message.", x);
+                }
+            }
+        }
+    }
+
+    /**
+     * Send a ping
+     * @throws Exception
+     */ 
+    public void send(boolean checkexpired) throws IOException{
+        //ignore if we haven't started the sender
+        //if ( (startLevel&Channel.MBR_TX_SEQ) != Channel.MBR_TX_SEQ ) return;
+        member.inc();
+        if(log.isTraceEnabled())
+            log.trace("Mcast send ping from member " + member);
+        byte[] data = member.getData();
+        DatagramPacket p = new DatagramPacket(data,data.length);
+        p.setAddress(address);
+        p.setPort(port);
+        socket.send(p);
+        if ( checkexpired ) checkExpired();
+    }
+
+    public long getServiceStartTime() {
+       return this.serviceStartTime;
+    }
+
+
+    public class ReceiverThread extends Thread {
+        public ReceiverThread() {
+            super();
+            setName("Cluster-MembershipReceiver");
+        }
+        public void run() {
+            while ( doRunReceiver ) {
+                try {
+                    receive();
+                } catch ( ArrayIndexOutOfBoundsException ax ) {
+                    //we can ignore this, as it means we have an invalid package
+                    //but we will log it to debug
+                    if ( log.isDebugEnabled() )
+                        log.debug("Invalid member mcast package.",ax);
+                } catch ( Exception x ) {
+                    log.warn("Error receiving mcast package. Sleeping 500ms",x);
+                    try { Thread.sleep(500); } catch ( Exception ignore ){}
+                    
+                }
+            }
+        }
+    }//class ReceiverThread
+
+    public class SenderThread extends Thread {
+        long time;
+        public SenderThread(long time) {
+            this.time = time;
+            setName("Cluster-MembershipSender");
+
+        }
+        public void run() {
+            while ( doRunSender ) {
+                try {
+                    send(true);
+                } catch ( Exception x ) {
+                    log.warn("Unable to send mcast message.",x);
+                }
+                try { Thread.sleep(time); } catch ( Exception ignore ) {}
+            }
+        }
+    }//class SenderThread
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/membership/MemberImpl.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/membership/MemberImpl.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/membership/MemberImpl.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,570 @@
+/*
+ * Copyright 1999,2004-2005 The Apache Software Foundation.
+ * 
+ * Licensed 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.tribes.membership;
+
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+import java.util.Arrays;
+
+import org.apache.catalina.tribes.Member;
+import org.apache.catalina.tribes.io.XByteBuffer;
+import org.apache.catalina.tribes.transport.SenderState;
+
+/**
+ * A <b>membership</b> implementation using simple multicast.
+ * This is the representation of a multicast member.
+ * Carries the host, and port of the this or other cluster nodes.
+ *
+ * @author Filip Hanik
+ * @version $Revision: 304032 $, $Date: 2005-07-27 10:11:55 -0500 (Wed, 27 Jul 2005) $
+ */
+public class MemberImpl implements Member, java.io.Externalizable {
+
+    /**
+     * Public properties specific to this implementation
+     */
+    public static final transient String TCP_LISTEN_PORT = "tcpListenPort";
+    public static final transient String TCP_LISTEN_HOST = "tcpListenHost";
+    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};
+    public static final transient byte[] TRIBES_MBR_END   = new byte[] {84, 82, 73, 66, 69, 83, 45, 69};
+    
+    /**
+     * The listen host for this member
+     */
+    protected byte[] host;
+    protected transient String hostname;
+    /**
+     * The tcp listen port for this member
+     */
+    protected int port;
+
+    /**
+     * Counter for how many broadcast messages have been sent from this member
+     */
+    protected int msgCount = 0;
+    /**
+     * The number of milliseconds since this members was
+     * created, is kept track of using the start time
+     */
+    protected long memberAliveTime = 0;
+    
+    /**
+     * For the local member only
+     */
+    protected transient long serviceStartTime;
+    
+    /**
+     * To avoid serialization over and over again, once the local dataPkg
+     * has been set, we use that to transmit data
+     */
+    protected transient byte[] dataPkg = null;
+
+    /**
+     * Unique session Id for this member
+     */
+    protected byte[] uniqueId = new byte[16];
+    
+    /**
+     * Custom payload that an app framework can broadcast
+     * Also used to transport stop command.
+     */
+    protected byte[] payload = new byte[0];
+    
+    /**
+     * Command, so that the custom payload doesn't have to be used
+     * This is for internal tribes use, such as SHUTDOWN_COMMAND
+     */
+    protected byte[] command = new byte[0];
+
+    /**
+     * Domain if we want to filter based on domain.
+     */
+    protected byte[] domain = new byte[0];
+    
+    /**
+     * Empty constructor for serialization
+     */
+    public MemberImpl() {
+        
+    }
+
+    /**
+     * Construct a new member object
+     * @param name - the name of this member, cluster unique
+     * @param domain - the cluster domain name of this member
+     * @param host - the tcp listen host
+     * @param port - the tcp listen port
+     */
+    public MemberImpl(String host,
+                      int port,
+                      long aliveTime) throws IOException {
+        setHostname(host);
+        this.port = port;
+        this.memberAliveTime=aliveTime;
+    }
+    
+    public MemberImpl(String host,
+                      int port,
+                      long aliveTime,
+                      byte[] payload) throws IOException {
+        this(host,port,aliveTime);
+        setPayload(payload);
+    }
+    
+    public boolean isReady() {
+        return SenderState.getSenderState(this).isReady();
+    }
+    public boolean isSuspect() {
+        return SenderState.getSenderState(this).isSuspect();
+    }
+    public boolean isFailing() {
+        return SenderState.getSenderState(this).isFailing();
+    }
+
+    /**
+     * Increment the message count.
+     */
+    protected void inc() {
+        msgCount++;
+    }
+
+    /**
+     * Create a data package to send over the wire representing this member.
+     * This is faster than serialization.
+     * @return - the bytes for this member deserialized
+     * @throws Exception
+     */
+    public byte[] getData()  {
+        return getData(true);
+    }
+    /**
+     * Highly optimized version of serializing a member into a byte array
+     * Returns a cached byte[] reference, do not modify this data
+     * @param getalive boolean
+     * @return byte[]
+     */
+    public byte[] getData(boolean getalive)  {
+        return getData(getalive,false);
+    }
+    
+    
+    public int getDataLength() {
+        return TRIBES_MBR_BEGIN.length+ //start pkg
+               4+ //data length
+               8+ //alive time
+               4+ //port
+               1+ //host length
+               host.length+ //host
+               4+ //command length
+               command.length+ //command
+               4+ //domain length
+               domain.length+ //domain
+               16+ //unique id
+               4+ //payload length
+               payload.length+ //payload
+               TRIBES_MBR_END.length; //end pkg
+    }
+    
+    /**
+     * 
+     * @param getalive boolean - calculate memberAlive time
+     * @param reset boolean - reset the cached data package, and create a new one
+     * @return byte[]
+     */
+    public byte[] getData(boolean getalive, boolean reset)  {
+        if ( reset ) dataPkg = null;
+        //look in cache first
+        if ( dataPkg!=null ) {
+            if ( getalive ) {
+                //you'd be surprised, but System.currentTimeMillis
+                //shows up on the profiler
+                long alive=System.currentTimeMillis()-getServiceStartTime();
+                XByteBuffer.toBytes( (long) alive, dataPkg, TRIBES_MBR_BEGIN.length+4);
+            }
+            return dataPkg;
+        }
+        
+        //package looks like
+        //start package TRIBES_MBR_BEGIN.length
+        //package length - 4 bytes
+        //alive - 8 bytes
+        //port - 4 bytes
+        //host length - 1 byte
+        //host - hl bytes
+        //clen - 4 bytes
+        //command - clen bytes
+        //dlen - 4 bytes
+        //domain - dlen bytes
+        //uniqueId - 16 bytes
+        //payload length - 4 bytes
+        //payload plen bytes
+        //end package TRIBES_MBR_END.length
+        byte[] addr = host;
+        long alive=System.currentTimeMillis()-getServiceStartTime();
+        byte hl = (byte)addr.length;
+        byte[] data = new byte[getDataLength()];
+        
+        int bodylength = (getDataLength() - TRIBES_MBR_BEGIN.length - TRIBES_MBR_END.length - 4);
+        
+        int pos = 0;
+        
+        //TRIBES_MBR_BEGIN
+        System.arraycopy(TRIBES_MBR_BEGIN,0,data,pos,TRIBES_MBR_BEGIN.length);
+        pos += TRIBES_MBR_BEGIN.length;
+        
+        //body length
+        XByteBuffer.toBytes(bodylength,data,pos);
+        pos += 4;
+        
+        //alive data
+        XByteBuffer.toBytes((long)alive,data,pos);
+        pos += 8;
+        //port
+        XByteBuffer.toBytes(port,data,pos);
+        pos += 4;
+        //host length
+        data[pos++] = hl;
+        //host
+        System.arraycopy(addr,0,data,pos,addr.length);
+        pos+=addr.length;
+        //clen - 4 bytes
+        XByteBuffer.toBytes(command.length,data,pos);
+        pos+=4;
+        //command - clen bytes
+        System.arraycopy(command,0,data,pos,command.length);
+        pos+=command.length;
+        //dlen - 4 bytes
+        XByteBuffer.toBytes(domain.length,data,pos);
+        pos+=4;
+        //domain - dlen bytes
+        System.arraycopy(domain,0,data,pos,domain.length);
+        pos+=domain.length;
+        //unique Id
+        System.arraycopy(uniqueId,0,data,pos,uniqueId.length);
+        pos+=uniqueId.length;
+        //payload
+        XByteBuffer.toBytes(payload.length,data,pos);
+        pos+=4;
+        System.arraycopy(payload,0,data,pos,payload.length);
+        pos+=payload.length;
+        
+        //TRIBES_MBR_END
+        System.arraycopy(TRIBES_MBR_END,0,data,pos,TRIBES_MBR_END.length);
+        pos += TRIBES_MBR_END.length;
+
+        //create local data
+        dataPkg = data;
+        return data;
+    }
+    /**
+     * Deserializes a member from data sent over the wire
+     * @param data - the bytes received
+     * @return a member object.
+     */
+    public static MemberImpl getMember(byte[] data, MemberImpl member) {
+        return getMember(data,0,data.length,member);
+    }
+
+    public static MemberImpl getMember(byte[] data, int offset, int length, MemberImpl member) {
+        //package looks like
+        //start package TRIBES_MBR_BEGIN.length
+        //package length - 4 bytes
+        //alive - 8 bytes
+        //port - 4 bytes
+        //host length - 1 byte
+        //host - hl bytes
+        //clen - 4 bytes
+        //command - clen bytes
+        //dlen - 4 bytes
+        //domain - dlen bytes
+        //uniqueId - 16 bytes
+        //payload length - 4 bytes
+        //payload plen bytes
+        //end package TRIBES_MBR_END.length
+
+        int pos = offset;
+        
+        if (XByteBuffer.firstIndexOf(data,offset,TRIBES_MBR_BEGIN)!=pos) {
+            throw new IllegalArgumentException("Invalid package, should start with:"+org.apache.catalina.tribes.util.Arrays.toString(TRIBES_MBR_BEGIN));
+        }
+
+        if ( length < (TRIBES_MBR_BEGIN.length+4) ) {
+            throw new ArrayIndexOutOfBoundsException("Member package to small to validate.");
+        }
+        
+        pos += TRIBES_MBR_BEGIN.length;
+        
+        int bodylength = XByteBuffer.toInt(data,pos);
+        pos += 4;
+        
+        if ( length < (bodylength+4+TRIBES_MBR_BEGIN.length+TRIBES_MBR_END.length) ) {
+            throw new ArrayIndexOutOfBoundsException("Not enough bytes in member package.");
+        }
+        
+        int endpos = pos+bodylength;
+        if (XByteBuffer.firstIndexOf(data,endpos,TRIBES_MBR_END)!=endpos) {
+            throw new IllegalArgumentException("Invalid package, should end with:"+org.apache.catalina.tribes.util.Arrays.toString(TRIBES_MBR_END));
+        }
+
+
+        byte[] alived = new byte[8];
+        System.arraycopy(data, pos, alived, 0, 8);
+        pos += 8;
+        byte[] portd = new byte[4];
+        System.arraycopy(data, pos, portd, 0, 4);
+        pos += 4;
+    
+        byte hl = data[pos++];
+        byte[] addr = new byte[hl];
+        System.arraycopy(data, pos, addr, 0, hl);
+        pos += hl;
+    
+        int cl = XByteBuffer.toInt(data, pos);
+        pos += 4;
+    
+        byte[] command = new byte[cl];
+        System.arraycopy(data, pos, command, 0, command.length);
+        pos += command.length;
+    
+        int dl = XByteBuffer.toInt(data, pos);
+        pos += 4;
+    
+        byte[] domain = new byte[dl];
+        System.arraycopy(data, pos, domain, 0, domain.length);
+        pos += domain.length;
+    
+        byte[] uniqueId = new byte[16];
+        System.arraycopy(data, pos, uniqueId, 0, 16);
+        pos += 16;
+    
+        int pl = XByteBuffer.toInt(data, pos);
+        pos += 4;
+    
+        byte[] payload = new byte[pl];
+        System.arraycopy(data, pos, payload, 0, payload.length);
+        pos += payload.length;
+    
+        member.setHost(addr);
+        member.setPort(XByteBuffer.toInt(portd, 0));
+        member.setMemberAliveTime(XByteBuffer.toLong(alived, 0));
+        member.setUniqueId(uniqueId);
+        member.payload = payload;
+        member.domain = domain;
+        member.command = command;
+    
+        member.dataPkg = new byte[length];
+        System.arraycopy(data, offset, member.dataPkg, 0, length);
+    
+        return member;
+    }
+
+    public static MemberImpl getMember(byte[] data) {
+       return getMember(data,new MemberImpl());
+    }
+
+    /**
+     * Return the name of this object
+     * @return a unique name to the cluster
+     */
+    public String getName() {
+        return "tcp://"+getHostname()+":"+getPort();
+    }
+    
+    /**
+     * Return the listen port of this member
+     * @return - tcp listen port
+     */
+    public int getPort()  {
+        return this.port;
+    }
+
+    /**
+     * Return the TCP listen host for this member
+     * @return IP address or host name
+     */
+    public byte[] getHost()  {
+        return host;
+    }
+    
+    public String getHostname() {
+        if ( this.hostname != null ) return hostname;
+        else {
+            try {
+                this.hostname = java.net.InetAddress.getByAddress(host).getHostName();
+                return this.hostname;
+            }catch ( IOException x ) {
+                throw new RuntimeException("Unable to parse hostname.",x);
+            }
+        }
+    }
+
+    /**
+     * Contains information on how long this member has been online.
+     * The result is the number of milli seconds this member has been
+     * broadcasting its membership to the cluster.
+     * @return nr of milliseconds since this member started.
+     */
+    public long getMemberAliveTime() {
+       return memberAliveTime;
+    }
+
+    public long getServiceStartTime() {
+        return serviceStartTime;
+    }
+
+    public byte[] getUniqueId() {
+        return uniqueId;
+    }
+
+    public byte[] getPayload() {
+        return payload;
+    }
+
+    public byte[] getCommand() {
+        return command;
+    }
+
+    public byte[] getDomain() {
+        return domain;
+    }
+
+    public void setMemberAliveTime(long time) {
+       memberAliveTime=time;
+    }
+
+
+
+    /**
+     * String representation of this object
+     */
+    public String toString()  {
+        StringBuffer buf = new StringBuffer("org.apache.catalina.tribes.membership.MemberImpl[");
+        buf.append(getName()).append(",");
+        buf.append(getHostname()).append(",");
+        buf.append(port).append(", alive=");
+        buf.append(memberAliveTime).append(",");
+        buf.append("id=").append(bToS(this.uniqueId)).append(", ");
+        buf.append("payload=").append(bToS(this.payload,8)).append(", ");
+        buf.append("command=").append(bToS(this.command,8)).append(", ");
+        buf.append("domain=").append(bToS(this.domain,8)).append(", ");
+        buf.append("]");
+        return buf.toString();
+    }
+    public static String bToS(byte[] data) {
+        return bToS(data,data.length);
+    }
+    public static String bToS(byte[] data, int max) {
+        StringBuffer buf = new StringBuffer(4*16);
+        buf.append("{");
+        for (int i=0; data!=null && i<data.length; i++ ) {
+            buf.append(String.valueOf(data[i])).append(" ");
+            if ( i==max ) {
+                buf.append("...("+data.length+")");
+                break;
+            }
+        }
+        buf.append("}");
+        return buf.toString();
+    }
+
+    /**
+     * @see java.lang.Object#hashCode()
+     * @return The hash code
+     */
+    public int hashCode() {
+        return getHost()[0]+getHost()[1]+getHost()[2]+getHost()[3];
+    }
+
+    /**
+     * Returns true if the param o is a McastMember with the same name
+     * @param o
+     */
+    public boolean equals(Object o) {
+        if ( o instanceof MemberImpl )    {
+            return Arrays.equals(this.getHost(),((MemberImpl)o).getHost()) &&
+                   this.getPort() == ((MemberImpl)o).getPort() &&
+                   Arrays.equals(this.getUniqueId(),((MemberImpl)o).getUniqueId());
+        }
+        else
+            return false;
+    }
+    
+    public void setHost(byte[] host) {
+        this.host = host;
+    }
+    
+    public void setHostname(String host) throws IOException {
+        hostname = host;
+        this.host = java.net.InetAddress.getByName(host).getAddress();
+    }
+    
+    public void setMsgCount(int msgCount) {
+        this.msgCount = msgCount;
+    }
+
+    public void setPort(int port) {
+        this.port = port;
+        this.dataPkg = null;
+    }
+
+    public void setServiceStartTime(long serviceStartTime) {
+        this.serviceStartTime = serviceStartTime;
+    }
+
+    public void setUniqueId(byte[] uniqueId) {
+        this.uniqueId = uniqueId!=null?uniqueId:new byte[16];
+        getData(true,true);
+    }
+
+    public void setPayload(byte[] payload) {
+        byte[] oldpayload = this.payload;
+        this.payload = payload!=null?payload:new byte[0];
+        if ( this.getData(true,true).length > McastServiceImpl.MAX_PACKET_SIZE ) {
+            this.payload = oldpayload;
+            throw new IllegalArgumentException("Payload is to large for tribes to handle.");
+        }
+        
+    }
+
+    public void setCommand(byte[] command) {
+        this.command = command!=null?command:new byte[0];
+        getData(true,true);
+    }
+
+    public void setDomain(byte[] domain) {
+        this.domain = domain!=null?domain:new byte[0];
+        getData(true,true);
+    }
+
+    public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
+        int length = in.readInt();
+        byte[] message = new byte[length];
+        in.read(message);
+        getMember(message,this);
+        
+    }
+
+    public void writeExternal(ObjectOutput out) throws IOException {
+        byte[] data = this.getData();
+        out.writeInt(data.length);
+        out.write(data);
+    }
+    
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/membership/Membership.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/membership/Membership.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/membership/Membership.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,324 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tribes.membership;
+
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import org.apache.catalina.tribes.Member;
+import java.util.Comparator;
+
+/**
+ * A <b>membership</b> implementation using simple multicast.
+ * This is the representation of a multicast membership.
+ * This class is responsible for maintaining a list of active cluster nodes in the cluster.
+ * If a node fails to send out a heartbeat, the node will be dismissed.
+ *
+ * @author Filip Hanik
+ * @author Peter Rossbach
+ * @version $Revision: 356540 $, $Date: 2005-12-13 10:53:40 -0600 (Tue, 13 Dec 2005) $
+ */
+public class Membership
+{
+    protected static final MemberImpl[] EMPTY_MEMBERS = new MemberImpl[0];
+    
+    /**
+     * The name of this membership, has to be the same as the name for the local
+     * member
+     */
+    protected MemberImpl local;
+    
+    /**
+     * A map of all the members in the cluster.
+     */
+    protected HashMap map = new HashMap();
+    
+    /**
+     * A list of all the members in the cluster.
+     */
+    protected MemberImpl[] members = EMPTY_MEMBERS;
+    
+    /**
+      * sort members by alive time
+      */
+    protected Comparator memberComparator = new MemberComparator();
+
+    public Object clone() {
+        synchronized (members) {
+            Membership clone = new Membership(local, memberComparator);
+            clone.map = (HashMap) map.clone();
+            clone.members = new MemberImpl[members.length];
+            System.arraycopy(members,0,clone.members,0,members.length);
+            return clone;
+        }
+    }
+
+    /**
+     * Constructs a new membership
+     * @param name - has to be the name of the local member. Used to filter the local member from the cluster membership
+     */
+    public Membership(MemberImpl local, boolean includeLocal) {
+        this.local = local;
+        if ( includeLocal ) addMember(local);
+    }
+
+    public Membership(MemberImpl local) {
+        this(local,false);
+    }
+
+    public Membership(MemberImpl local, Comparator comp) {
+        this(local,comp,false);
+    }
+
+    public Membership(MemberImpl local, Comparator comp, boolean includeLocal) {
+        this(local,includeLocal);
+        this.memberComparator = comp;
+    }
+    /**
+     * Reset the membership and start over fresh.
+     * Ie, delete all the members and wait for them to ping again and join this membership
+     */
+    public synchronized void reset() {
+        map.clear();
+        members = EMPTY_MEMBERS ;
+    }
+
+    /**
+     * Notify the membership that this member has announced itself.
+     *
+     * @param member - the member that just pinged us
+     * @return - true if this member is new to the cluster, false otherwise.
+     * @return - false if this member is the local member or updated.
+     */
+    public synchronized boolean memberAlive(MemberImpl member) {
+        boolean result = false;
+        //ignore ourselves
+        if (  member.equals(local) ) return result;
+
+        //return true if the membership has changed
+        MbrEntry entry = (MbrEntry)map.get(member);
+        if ( entry == null ) {
+            entry = addMember(member);
+            result = true;
+       } else {
+            //update the member alive time
+            MemberImpl updateMember = entry.getMember() ;
+            if(updateMember.getMemberAliveTime() != member.getMemberAliveTime()) {
+                //update fields that can change
+                updateMember.setMemberAliveTime(member.getMemberAliveTime());
+                updateMember.setPayload(member.getPayload());
+                updateMember.setCommand(member.getCommand());
+                Arrays.sort(members, memberComparator);
+            }
+        }
+        entry.accessed();
+        return result;
+    }
+
+    /**
+     * Add a member to this component and sort array with memberComparator
+     * @param member The member to add
+     */
+    public synchronized MbrEntry addMember(MemberImpl member) {
+      synchronized (members) {
+          MbrEntry entry = new MbrEntry(member);
+          if (!map.containsKey(member) ) {
+              map.put(member, entry);
+              MemberImpl results[] = new MemberImpl[members.length + 1];
+              for (int i = 0; i < members.length; i++) results[i] = members[i];
+              results[members.length] = member;
+              members = results;
+              Arrays.sort(members, memberComparator);
+          }
+          return entry;
+      }
+    }
+    
+    /**
+     * Remove a member from this component.
+     * 
+     * @param member The member to remove
+     */
+    public void removeMember(MemberImpl member) {
+        map.remove(member);
+        synchronized (members) {
+            int n = -1;
+            for (int i = 0; i < members.length; i++) {
+                if (members[i] == member || members[i].equals(member)) {
+                    n = i;
+                    break;
+                }
+            }
+            if (n < 0) return;
+            MemberImpl results[] = new MemberImpl[members.length - 1];
+            int j = 0;
+            for (int i = 0; i < members.length; i++) {
+                if (i != n)
+                    results[j++] = members[i];
+            }
+            members = results;
+        }
+    }
+    
+    /**
+     * Runs a refresh cycle and returns a list of members that has expired.
+     * This also removes the members from the membership, in such a way that
+     * getMembers() = getMembers() - expire()
+     * @param maxtime - the max time a member can remain unannounced before it is considered dead.
+     * @return the list of expired members
+     */
+    public synchronized MemberImpl[] expire(long maxtime) {
+        if(!hasMembers() )
+           return EMPTY_MEMBERS;
+       
+        ArrayList list = null;
+        Iterator i = map.values().iterator();
+        while(i.hasNext()) {
+            MbrEntry entry = (MbrEntry)i.next();
+            if( entry.hasExpired(maxtime) ) {
+                if(list == null) // only need a list when members are expired (smaller gc)
+                    list = new java.util.ArrayList();
+                list.add(entry.getMember());
+            }
+        }
+        
+        if(list != null) {
+            MemberImpl[] result = new MemberImpl[list.size()];
+            list.toArray(result);
+            for( int j=0; j<result.length; j++) {
+                removeMember(result[j]);
+            }
+            return result;
+        } else {
+            return EMPTY_MEMBERS ;
+        }
+    }
+
+    /**
+     * Returning that service has members or not
+     */
+    public boolean hasMembers() {
+        return members.length > 0 ;
+    }
+    
+    
+    public MemberImpl getMember(Member mbr) {
+        if(hasMembers()) {
+            MemberImpl result = null;
+            for ( int i=0; i<this.members.length && result==null; i++ ) {
+                if ( members[i].equals(mbr) ) result = members[i];
+            }//for
+            return result;
+        } else {
+            return null;
+        }
+    }
+    
+    public boolean contains(Member mbr) { 
+        return getMember(mbr)!=null;
+    }
+ 
+    /**
+     * Returning a list of all the members in the membership
+     * We not need a copy: add and remove generate new arrays.
+     */
+    public MemberImpl[] getMembers() {
+        if(hasMembers()) {
+            return members;
+        } else {
+            return EMPTY_MEMBERS;
+        }
+    }
+
+    /**
+     * get a copy from all member entries
+     */
+    protected synchronized MbrEntry[] getMemberEntries()
+    {
+        MbrEntry[] result = new MbrEntry[map.size()];
+        java.util.Iterator i = map.entrySet().iterator();
+        int pos = 0;
+        while ( i.hasNext() )
+            result[pos++] = ((MbrEntry)((java.util.Map.Entry)i.next()).getValue());
+        return result;
+    }
+    
+    // --------------------------------------------- Inner Class
+
+    private class MemberComparator implements java.util.Comparator {
+
+        public int compare(Object o1, Object o2) {
+            try {
+                return compare((MemberImpl) o1, (MemberImpl) o2);
+            } catch (ClassCastException x) {
+                return 0;
+            }
+        }
+
+        public int compare(MemberImpl m1, MemberImpl m2) {
+            //longer alive time, means sort first
+            long result = m2.getMemberAliveTime() - m1.getMemberAliveTime();
+            if (result < 0)
+                return -1;
+            else if (result == 0)
+                return 0;
+            else
+                return 1;
+        }
+    }
+    
+    /**
+     * Inner class that represents a member entry
+     */
+    protected static class MbrEntry
+    {
+
+        protected MemberImpl mbr;
+        protected long lastHeardFrom;
+
+        public MbrEntry(MemberImpl mbr) {
+           this.mbr = mbr;
+        }
+
+        /**
+         * Indicate that this member has been accessed.
+         */
+        public void accessed(){
+           lastHeardFrom = System.currentTimeMillis();
+        }
+
+        /**
+         * Return the actual Member object
+         */
+        public MemberImpl getMember() {
+            return mbr;
+        }
+
+        /**
+         * Check if this dude has expired
+         * @param maxtime The time threshold
+         */
+        public boolean hasExpired(long maxtime) {
+            long delta = System.currentTimeMillis() - lastHeardFrom;
+            return delta > maxtime;
+        }
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/membership/mbeans-descriptors.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/membership/mbeans-descriptors.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/membership/mbeans-descriptors.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mbeans-descriptors PUBLIC
+   "-//Apache Software Foundation//DTD Model MBeans Configuration File"
+   "http://jakarta.apache.org/commons/dtds/mbeans-descriptors.dtd">
+<mbeans-descriptors>
+
+  <mbean         name="McastService"
+           description="Cluster Membership service implementation"
+               domain="Catalina"
+                group="Cluster"
+                 type="org.apache.catalina.cluster.mcast.McastService">
+    <attribute   name="info"
+          description="Class version info"
+                 type="java.lang.String"
+                 writeable="false"/>
+    <attribute   name="mcastAddr"
+          description="Multicast IP Address"
+                 type="java.lang.String"/>
+    <attribute   name="mcastBindAddress"
+          description="Multicast IP Interface address (default auto)"
+                 type="java.lang.String"/>
+    <attribute   name="mcastPort"
+          description="Multicast UDP Port"
+                 type="int"/>
+    <attribute   name="mcastFrequency"
+          description="Ping Frequency at msec"
+                 type="long"/>
+    <attribute   name="mcastClusterDomain"
+          description="Cluster Domain of this member"
+                 type="java.lang.String"/>
+    <attribute   name="mcastDropTime"
+          description="Timeout from frequency ping after member disapper notify"
+                 type="long"/>
+    <attribute   name="mcastSoTimeout"
+          description="Multicast Socket Timeout"
+                 type="int"/>
+    <attribute   name="mcastTTL"
+          description=""
+                 type="int"/>
+    <attribute   name="localMemberName"
+          description="Complete local receiver information"
+                 type="java.lang.String"
+                 writeable="false"/>
+    <attribute   name="membersByName"
+          description="Complete remote sender information"
+                 type="[Ljava.lang.String;"
+                 writeable="false"/>
+
+    <operation   name="start"
+               description="Start the cluster membership"
+               impact="ACTION"
+               returnType="void">
+    </operation>
+    
+    <operation name="stop"
+               description="Stop the cluster membership"
+               impact="ACTION"
+               returnType="void">
+    </operation>
+                 
+  </mbean>
+
+</mbeans-descriptors>

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/package.html
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/package.html	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/package.html	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,70 @@
+<body>
+<head><title>Apache Tribes - The Tomcat Cluster Communication Module</title>
+<h3>QuickStart</h3>
+    <pre><code>
+            //create a channel
+            Channel myChannel = new GroupChannel();
+
+            //create my listeners
+            MyMessageListener msgListener = new MyMessageListener();
+            MyMemberListener mbrListener = new MyMemberListener();
+
+            //attach the listeners to the channel
+            myChannel.addMembershipListener(mbrListener);
+            myChannel.addChannelListener(msgListener);
+
+            //start the channel
+            myChannel.start(Channel.DEFAULT);
+
+            //create a message to be sent, message must implement java.io.Serializable
+            //for performance reasons you probably want them to implement java.io.Externalizable
+            Serializable myMsg = new MyMessage();
+
+            //retrieve my current members
+            Member[] group = myChannel.getMembers();
+
+            //send the message
+            channel.send(group,myMsg,Channel.SEND_OPTIONS_DEFAULT);
+
+    </code></pre>
+<h3>Interfaces for the Application Developer</h3>
+    <ol>
+        <li><code>org.apache.catalina.tribes.Channel</code>
+            Main component to interact with to send messages
+        </li>
+        <li><code>org.apache.catalina.tribes.MembershipListener</code>
+            Listen to membership changes
+        </li>
+        <li><code>org.apache.catalina.tribes.ChannelListener</code>
+            Listen to data messages
+        </li>
+        <li><code>org.apache.catalina.tribes.Member</code>
+            Identifies a node, implementation specific, default is org.apache.catalina.tribes.membership.MemberImpl
+        </li>
+    </ol>
+    <h3>Interfaces for the Tribes Component Developer</h3>
+    <ol>
+        <li><code>org.apache.catalina.tribes.Channel</code>
+            Main component to that the application interacts with
+        </li>
+        <li><code>org.apache.catalina.tribes.ChannelReceiver</code>
+            IO Component to receive messages over some network transport
+        </li>
+        <li><code>org.apache.catalina.tribes.ChannelSender</code>
+            IO Component to send messages over some network transport
+        </li>
+        <li><code>org.apache.catalina.tribes.MembershipService</code>
+            IO Component that handles membership discovery and 
+        </li>
+        <li><code>org.apache.catalina.tribes.ChannelInterceptor</code>
+            interceptors between the Channel and the IO layer
+        </li>
+        <li><code>org.apache.catalina.tribes.ChannelMessage</code>
+            The message that is sent through the interceptor stack down to the IO layer 
+        </li>
+
+        <li><code>org.apache.catalina.tribes.Member</code>
+            Identifies a node, implementation specific to the underlying IO logic
+        </li>
+    </ol>
+</body>

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/tipis/AbstractReplicatedMap.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/tipis/AbstractReplicatedMap.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/tipis/AbstractReplicatedMap.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,1271 @@
+/*
+ * Copyright 1999,2004-2006 The Apache Software Foundation.
+ *
+ * Licensed 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.tribes.tipis;
+
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+import java.io.Serializable;
+import java.io.UnsupportedEncodingException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.catalina.tribes.Channel;
+import org.apache.catalina.tribes.ChannelException;
+import org.apache.catalina.tribes.ChannelListener;
+import org.apache.catalina.tribes.Heartbeat;
+import org.apache.catalina.tribes.Member;
+import org.apache.catalina.tribes.MembershipListener;
+import org.apache.catalina.tribes.group.Response;
+import org.apache.catalina.tribes.group.RpcCallback;
+import org.apache.catalina.tribes.group.RpcChannel;
+import org.apache.catalina.tribes.io.XByteBuffer;
+import org.apache.catalina.tribes.membership.MemberImpl;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.catalina.tribes.util.Arrays;
+import java.util.ConcurrentModificationException;
+
+/**
+ * <p>Title: </p>
+ *
+ * <p>Description: </p>
+ *
+ * <p>Copyright: Copyright (c) 2005</p>
+ *
+ * <p>Company: </p>
+ *
+ * @author not attributable
+ * @version 1.0
+ */
+public abstract class AbstractReplicatedMap extends LinkedHashMap implements RpcCallback, ChannelListener, MembershipListener, Heartbeat {
+    protected static Log log = LogFactory.getLog(AbstractReplicatedMap.class);
+
+    /**
+     * The default initial capacity - MUST be a power of two.
+     */
+    public static final int DEFAULT_INITIAL_CAPACITY = 16;
+
+    /**
+     * The load factor used when none specified in constructor.
+     **/
+    public static final float DEFAULT_LOAD_FACTOR = 0.75f;
+    
+    /**
+     * Used to identify the map
+     */
+    final String chset = "ISO-8859-1";
+
+//------------------------------------------------------------------------------
+//              INSTANCE VARIABLES
+//------------------------------------------------------------------------------
+    private transient long rpcTimeout = 5000;
+    private transient Channel channel;
+    private transient RpcChannel rpcChannel;
+    private transient byte[] mapContextName;
+    private transient boolean stateTransferred = false;
+    private transient Object stateMutex = new Object();
+    private transient HashMap mapMembers = new HashMap();
+    private transient int channelSendOptions = Channel.SEND_OPTIONS_DEFAULT;
+    private transient Object mapOwner;
+    private transient ClassLoader[] externalLoaders;
+    protected transient int currentNode = 0;
+    private transient long accessTimeout = 5000;
+    private transient String mapname = "";
+    
+
+//------------------------------------------------------------------------------
+//              CONSTRUCTORS
+//------------------------------------------------------------------------------
+
+    /**
+     * Creates a new map
+     * @param channel The channel to use for communication
+     * @param timeout long - timeout for RPC messags
+     * @param mapContextName String - unique name for this map, to allow multiple maps per channel
+     * @param initialCapacity int - the size of this map, see HashMap
+     * @param loadFactor float - load factor, see HashMap
+     * @param cls - a list of classloaders to be used for deserialization of objects.
+     */
+    public AbstractReplicatedMap(Object owner,
+                                 Channel channel, 
+                                 long timeout, 
+                                 String mapContextName, 
+                                 int initialCapacity,
+                                 float loadFactor,
+                                 int channelSendOptions,
+                                 ClassLoader[] cls) {
+        super(initialCapacity, loadFactor);
+        init(owner, channel, mapContextName, timeout, channelSendOptions, cls);
+        
+    }
+
+    protected Member[] wrap(Member m) {
+        if ( m == null ) return new Member[0];
+        else return new Member[] {m};
+    }
+
+    private void init(Object owner, Channel channel, String mapContextName, long timeout, int channelSendOptions,ClassLoader[] cls) {
+        log.info("Initializing AbstractReplicatedMap with context name:"+mapContextName);
+        this.mapOwner = owner;
+        this.externalLoaders = cls;
+        this.channelSendOptions = channelSendOptions;
+        this.channel = channel;
+        this.rpcTimeout = timeout;
+
+        try {
+            this.mapname = mapContextName;
+            //unique context is more efficient if it is stored as bytes
+            this.mapContextName = mapContextName.getBytes(chset);
+        } catch (UnsupportedEncodingException x) {
+            log.warn("Unable to encode mapContextName[" + mapContextName + "] using getBytes(" + chset +") using default getBytes()", x);
+            this.mapContextName = mapContextName.getBytes();
+        }
+        if ( log.isTraceEnabled() ) log.trace("Created Lazy Map with name:"+mapContextName+", bytes:"+Arrays.toString(this.mapContextName));
+
+        //create an rpc channel and add the map as a listener
+        this.rpcChannel = new RpcChannel(this.mapContextName, channel, this);
+        this.channel.addChannelListener(this);
+        this.channel.addMembershipListener(this);
+        
+        
+        try {
+            broadcast(MapMessage.MSG_INIT, true);
+            //transfer state from another map
+            transferState();
+            broadcast(MapMessage.MSG_START, true);
+        } catch (ChannelException x) {
+            log.warn("Unable to send map start message.");
+            throw new RuntimeException("Unable to start replicated map.",x);
+        }
+
+    }
+    
+    
+    private void ping(long timeout) throws ChannelException {
+        //send out a map membership message, only wait for the first reply
+        MapMessage msg = new MapMessage(this.mapContextName, MapMessage.MSG_INIT,
+                                        false, null, null, null, wrap(channel.getLocalMember(false)));
+        Response[] resp = rpcChannel.send(channel.getMembers(), msg, rpcChannel.ALL_REPLY, (channelSendOptions), (int)accessTimeout);
+        for (int i = 0; i < resp.length; i++) {
+            memberAlive(resp[i].getSource());
+        }//for
+
+        synchronized (mapMembers) {
+            Iterator it = mapMembers.entrySet().iterator();
+            long now = System.currentTimeMillis();
+            while ( it.hasNext() ) {
+                Map.Entry entry = (Map.Entry)it.next();
+                long access = ((Long)entry.getValue()).longValue(); 
+                if ( (now - access) > timeout ) memberDisappeared((Member)entry.getKey());
+            }
+        }//synch
+    }
+
+    private void memberAlive(Member member) {
+        synchronized (mapMembers) {
+            if (!mapMembers.containsKey(member)) {
+                mapMemberAdded(member);
+            } //end if
+            mapMembers.put(member, new Long(System.currentTimeMillis()));
+        }
+    }
+
+    private void broadcast(int msgtype, boolean rpc) throws ChannelException {
+        //send out a map membership message, only wait for the first reply
+        MapMessage msg = new MapMessage(this.mapContextName, msgtype,
+                                        false, null, null, null, wrap(channel.getLocalMember(false)));
+        if ( rpc) {
+            Response[] resp = rpcChannel.send(channel.getMembers(), msg, rpcChannel.FIRST_REPLY, (channelSendOptions),rpcTimeout);
+            for (int i = 0; i < resp.length; i++) {
+                mapMemberAdded(resp[i].getSource());
+                messageReceived(resp[i].getMessage(), resp[i].getSource());
+            }
+        } else {
+            channel.send(channel.getMembers(),msg,channelSendOptions);
+        }
+    }
+
+    public void breakdown() {
+        finalize();
+    }
+
+    public void finalize() {
+        try {broadcast(MapMessage.MSG_STOP,false); }catch ( Exception ignore){}
+        //cleanup
+        if (this.rpcChannel != null) {
+            this.rpcChannel.breakdown();
+        }
+        if (this.channel != null) {
+            this.channel.removeChannelListener(this);
+            this.channel.removeMembershipListener(this);
+        }
+        this.rpcChannel = null;
+        this.channel = null;
+        this.mapMembers.clear();
+        super.clear();
+        this.stateTransferred = false;
+        this.externalLoaders = null;
+    }
+    
+    public int hashCode() {
+        return Arrays.hashCode(this.mapContextName);
+    }
+    
+    public boolean equals(Object o) {
+        if ( o == null ) return false;
+        if ( !(o instanceof AbstractReplicatedMap)) return false;
+        if ( !(o.getClass().equals(this.getClass())) ) return false;
+        AbstractReplicatedMap other = (AbstractReplicatedMap)o;
+        return Arrays.equals(mapContextName,other.mapContextName);
+    }
+
+//------------------------------------------------------------------------------
+//              GROUP COM INTERFACES
+//------------------------------------------------------------------------------
+    public Member[] getMapMembers(HashMap members) {
+        synchronized (members) {
+            Member[] result = new Member[members.size()];
+            members.keySet().toArray(result);
+            return result;
+        }
+    }
+    public Member[] getMapMembers() {
+        return getMapMembers(this.mapMembers);
+    }
+    
+    public Member[] getMapMembersExcl(Member[] exclude) {
+        synchronized (mapMembers) {
+            HashMap list = (HashMap)mapMembers.clone();
+            for (int i=0; i<exclude.length;i++) list.remove(exclude[i]);
+            return getMapMembers(list);
+        }
+    }
+
+
+    /**
+     * Replicates any changes to the object since the last time
+     * The object has to be primary, ie, if the object is a proxy or a backup, it will not be replicated<br>
+     * @param complete - if set to true, the object is replicated to its backup
+     * if set to false, only objects that implement ReplicatedMapEntry and the isDirty() returns true will
+     * be replicated
+     */
+    public void replicate(Object key, boolean complete) {
+        if ( log.isTraceEnabled() )
+            log.trace("Replicate invoked on key:"+key);
+        MapEntry entry = (MapEntry)super.get(key);
+        if ( !entry.isSerializable() ) return;
+        if (entry != null && entry.isPrimary() && entry.getBackupNodes()!= null && entry.getBackupNodes().length > 0) {
+            Object value = entry.getValue();
+            //check to see if we need to replicate this object isDirty()||complete
+            boolean repl = complete || ( (value instanceof ReplicatedMapEntry) && ( (ReplicatedMapEntry) value).isDirty());
+            
+            if (!repl) {
+                if ( log.isTraceEnabled() )
+                    log.trace("Not replicating:"+key+", no change made");
+                
+                return;
+            }
+            //check to see if the message is diffable
+            boolean diff = ( (value instanceof ReplicatedMapEntry) && ( (ReplicatedMapEntry) value).isDiffable());
+            MapMessage msg = null;
+            if (diff) {
+                ReplicatedMapEntry rentry = (ReplicatedMapEntry)entry.getValue();
+                try {
+                    rentry.lock();
+                    //construct a diff message
+                    msg = new MapMessage(mapContextName, MapMessage.MSG_BACKUP,
+                                         true, (Serializable) entry.getKey(), null,
+                                         rentry.getDiff(),
+                                         entry.getBackupNodes());
+                } catch (IOException x) {
+                    log.error("Unable to diff object. Will replicate the entire object instead.", x);
+                } finally {
+                    rentry.unlock();
+                }
+                
+            }
+            if (msg == null) {
+                //construct a complete
+                msg = new MapMessage(mapContextName, MapMessage.MSG_BACKUP,
+                                     false, (Serializable) entry.getKey(),
+                                     (Serializable) entry.getValue(),
+                                     null, entry.getBackupNodes());
+
+            }
+            try {
+                if ( channel!=null && entry.getBackupNodes()!= null && entry.getBackupNodes().length > 0 ) {
+                    channel.send(entry.getBackupNodes(), msg, channelSendOptions);
+                }
+            } catch (ChannelException x) {
+                log.error("Unable to replicate data.", x);
+            }
+        } //end if
+
+    }
+
+    /**
+     * This can be invoked by a periodic thread to replicate out any changes.
+     * For maps that don't store objects that implement ReplicatedMapEntry, this
+     * method should be used infrequently to avoid large amounts of data transfer
+     * @param complete boolean
+     */
+    public void replicate(boolean complete) {
+        Iterator i = super.entrySet().iterator();
+        while (i.hasNext()) {
+            Map.Entry e = (Map.Entry) i.next();
+            replicate(e.getKey(), complete);
+        } //while
+
+    }
+
+    public void transferState() {
+        try {
+            Member[] members = getMapMembers();
+            Member backup = members.length > 0 ? (Member) members[0] : null;
+            if (backup != null) {
+                MapMessage msg = new MapMessage(mapContextName, MapMessage.MSG_STATE, false,
+                                                null, null, null, null);
+                Response[] resp = rpcChannel.send(new Member[] {backup}, msg, rpcChannel.FIRST_REPLY, channelSendOptions, rpcTimeout);
+                if (resp.length > 0) {
+                    synchronized (stateMutex) {
+                        msg = (MapMessage) resp[0].getMessage();
+                        msg.deserialize(getExternalLoaders());
+                        ArrayList list = (ArrayList) msg.getValue();
+                        for (int i = 0; i < list.size(); i++) {
+                            messageReceived( (Serializable) list.get(i), resp[0].getSource());
+                        } //for
+                    }
+                } else {
+                    log.warn("Transfer state, 0 replies, probably a timeout.");
+                }
+            }
+        } catch (ChannelException x) {
+            log.error("Unable to transfer LazyReplicatedMap state.", x);
+        } catch (IOException x) {
+            log.error("Unable to transfer LazyReplicatedMap state.", x);
+        } catch (ClassNotFoundException x) {
+            log.error("Unable to transfer LazyReplicatedMap state.", x);
+        }
+        stateTransferred = true;
+    }
+
+    /**
+     * @todo implement state transfer
+     * @param msg Serializable
+     * @return Serializable - null if no reply should be sent
+     */
+    public Serializable replyRequest(Serializable msg, final Member sender) {
+        if (! (msg instanceof MapMessage))return null;
+        MapMessage mapmsg = (MapMessage) msg;
+
+        //map init request
+        if (mapmsg.getMsgType() == mapmsg.MSG_INIT) {
+            mapmsg.setBackUpNodes(wrap(channel.getLocalMember(false)));
+            return mapmsg;
+        }
+        
+        //map start request
+        if (mapmsg.getMsgType() == mapmsg.MSG_START) {
+            mapmsg.setBackUpNodes(wrap(channel.getLocalMember(false)));
+            mapMemberAdded(sender);
+            return mapmsg;
+        }
+
+        //backup request
+        if (mapmsg.getMsgType() == mapmsg.MSG_RETRIEVE_BACKUP) {
+            MapEntry entry = (MapEntry)super.get(mapmsg.getKey());
+            if (entry == null || (!entry.isSerializable()) )return null;
+            mapmsg.setValue( (Serializable) entry.getValue());
+            return mapmsg;
+        }
+
+        //state transfer request
+        if (mapmsg.getMsgType() == mapmsg.MSG_STATE) {
+            synchronized (stateMutex) { //make sure we dont do two things at the same time
+                ArrayList list = new ArrayList();
+                Iterator i = super.entrySet().iterator();
+                while (i.hasNext()) {
+                    Map.Entry e = (Map.Entry) i.next();
+                    MapEntry entry = (MapEntry) e.getValue();
+                    if ( entry.isSerializable() ) {
+                        MapMessage me = new MapMessage(mapContextName, MapMessage.MSG_PROXY,
+                            false, (Serializable) entry.getKey(), null, null, entry.getBackupNodes());
+                        list.add(me);
+                    }
+                }
+                mapmsg.setValue(list);
+                return mapmsg;
+                
+            } //synchronized
+        }
+
+        return null;
+
+    }
+
+    /**
+     * If the reply has already been sent to the requesting thread,
+     * the rpc callback can handle any data that comes in after the fact.
+     * @param msg Serializable
+     * @param sender Member
+     */
+    public void leftOver(Serializable msg, Member sender) {
+        //left over membership messages
+        if (! (msg instanceof MapMessage))return;
+
+        MapMessage mapmsg = (MapMessage) msg;
+        try {
+            mapmsg.deserialize(getExternalLoaders());
+            if (mapmsg.getMsgType() == MapMessage.MSG_START) {
+                mapMemberAdded(mapmsg.getBackupNodes()[0]);
+            } else if (mapmsg.getMsgType() == MapMessage.MSG_INIT) {
+                memberAlive(mapmsg.getBackupNodes()[0]);
+            }
+        } catch (IOException x ) {
+            log.error("Unable to deserialize MapMessage.",x);
+        } catch (ClassNotFoundException x ) {
+            log.error("Unable to deserialize MapMessage.",x);
+        }
+    }
+
+    public void messageReceived(Serializable msg, Member sender) {
+        if (! (msg instanceof MapMessage)) return;
+
+        MapMessage mapmsg = (MapMessage) msg;
+        if ( log.isTraceEnabled() ) {
+            log.trace("Map["+mapname+"] received message:"+mapmsg);
+        }
+        
+        try {
+            mapmsg.deserialize(getExternalLoaders());
+        } catch (IOException x) {
+            log.error("Unable to deserialize MapMessage.", x);
+            return;
+        } catch (ClassNotFoundException x) {
+            log.error("Unable to deserialize MapMessage.", x);
+            return;
+        }
+        if ( log.isTraceEnabled() ) 
+            log.trace("Map message received from:"+sender.getName()+" msg:"+mapmsg);
+        if (mapmsg.getMsgType() == MapMessage.MSG_START) {
+            mapMemberAdded(mapmsg.getBackupNodes()[0]);
+        }
+
+        if (mapmsg.getMsgType() == MapMessage.MSG_STOP) {
+            memberDisappeared(mapmsg.getBackupNodes()[0]);
+        }
+
+        if (mapmsg.getMsgType() == MapMessage.MSG_PROXY) {
+            MapEntry entry = (MapEntry)super.get(mapmsg.getKey());
+            if ( entry==null ) {
+                entry = new MapEntry(mapmsg.getKey(), mapmsg.getValue());
+                entry.setBackup(false);
+                entry.setProxy(true);
+                entry.setBackupNodes(mapmsg.getBackupNodes());
+                super.put(entry.getKey(), entry);
+            } else {
+                entry.setProxy(true);
+                entry.setBackup(false);
+                entry.setBackupNodes(mapmsg.getBackupNodes());
+            }
+        }
+
+        if (mapmsg.getMsgType() == MapMessage.MSG_REMOVE) {
+            super.remove(mapmsg.getKey());
+        }
+
+        if (mapmsg.getMsgType() == MapMessage.MSG_BACKUP) {
+            MapEntry entry = (MapEntry)super.get(mapmsg.getKey());
+            if (entry == null) {
+                entry = new MapEntry(mapmsg.getKey(), mapmsg.getValue());
+                entry.setBackup(true);
+                entry.setProxy(false);
+                entry.setBackupNodes(mapmsg.getBackupNodes());
+                if (mapmsg.getValue()!=null && mapmsg.getValue() instanceof ReplicatedMapEntry ) {
+                    ((ReplicatedMapEntry)mapmsg.getValue()).setOwner(getMapOwner());
+                }
+            } else {
+                entry.setBackup(true);
+                entry.setProxy(false);
+                entry.setBackupNodes(mapmsg.getBackupNodes());
+                if (entry.getValue() instanceof ReplicatedMapEntry) {
+                    ReplicatedMapEntry diff = (ReplicatedMapEntry) entry.getValue();
+                    if (mapmsg.isDiff()) {
+                        try {
+                            diff.lock();
+                            diff.applyDiff(mapmsg.getDiffValue(), 0, mapmsg.getDiffValue().length);
+                        } catch (Exception x) {
+                            log.error("Unable to apply diff to key:" + entry.getKey(), x);
+                        } finally {
+                            diff.unlock();
+                        }
+                    } else {
+                        if ( mapmsg.getValue()!=null ) entry.setValue(mapmsg.getValue());
+                        ((ReplicatedMapEntry)entry.getValue()).setOwner(getMapOwner());
+                    } //end if
+                } else if  (mapmsg.getValue() instanceof ReplicatedMapEntry) {
+                    ReplicatedMapEntry re = (ReplicatedMapEntry)mapmsg.getValue();
+                    re.setOwner(getMapOwner());
+                    entry.setValue(re);
+                } else {
+                    if ( mapmsg.getValue()!=null ) entry.setValue(mapmsg.getValue());
+                } //end if
+            } //end if
+            super.put(entry.getKey(), entry);
+        } //end if
+    }
+
+    public boolean accept(Serializable msg, Member sender) {
+        boolean result = false;
+        if (msg instanceof MapMessage) {
+            if ( log.isTraceEnabled() ) log.trace("Map["+mapname+"] accepting...."+msg);
+            result = Arrays.equals(mapContextName, ( (MapMessage) msg).getMapId());
+            if ( log.isTraceEnabled() ) log.trace("Msg["+mapname+"] accepted["+result+"]...."+msg);
+        }
+        return result;
+    }
+
+    public void mapMemberAdded(Member member) {
+        if ( member.equals(getChannel().getLocalMember(false)) ) return;
+        boolean memberAdded = false;
+        //select a backup node if we don't have one
+        synchronized (mapMembers) {
+            if (!mapMembers.containsKey(member) ) {
+                mapMembers.put(member, new Long(System.currentTimeMillis()));
+                memberAdded = true;
+            }
+        }
+        if ( memberAdded ) {
+            synchronized (stateMutex) {
+                Iterator i = super.entrySet().iterator();
+                while (i.hasNext()) {
+                    Map.Entry e = (Map.Entry) i.next();
+                    MapEntry entry = (MapEntry) e.getValue();
+                    if ( entry == null ) continue;
+                    if (entry.isPrimary() && (entry.getBackupNodes() == null || entry.getBackupNodes().length == 0)) {
+                        try {
+                            Member[] backup = publishEntryInfo(entry.getKey(), entry.getValue());
+                            entry.setBackupNodes(backup);
+                        } catch (ChannelException x) {
+                            log.error("Unable to select backup node.", x);
+                        } //catch
+                    } //end if
+                } //while
+            } //synchronized
+        }//end if
+    }
+    
+    public boolean inSet(Member m, Member[] set) {
+        if ( set == null ) return false;
+        boolean result = false;
+        for (int i=0; i<set.length && (!result); i++ )
+            if ( m.equals(set[i]) ) result = true;
+        return result;
+    }
+
+    public Member[] excludeFromSet(Member[] mbrs, Member[] set) {
+        ArrayList result = new ArrayList();
+        for (int i=0; i<set.length; i++ ) {
+            boolean include = true;
+            for (int j=0; j<mbrs.length; j++ ) 
+                if ( mbrs[j].equals(set[i]) ) include = false;
+            if ( include ) result.add(set[i]);
+        }
+        return (Member[])result.toArray(new Member[result.size()]);
+    }
+
+    public void memberAdded(Member member) {
+        //do nothing
+    }
+
+    public void memberDisappeared(Member member) {
+        boolean removed = false;
+        synchronized (mapMembers) {
+            removed = (mapMembers.remove(member) != null );
+        }
+        Iterator i = super.entrySet().iterator();
+        while (i.hasNext()) {
+            Map.Entry e = (Map.Entry) i.next();
+            MapEntry entry = (MapEntry) e.getValue();
+            if (entry.isPrimary() && inSet(member,entry.getBackupNodes())) {
+                try {
+                    Member[] backup = publishEntryInfo(entry.getKey(), entry.getValue());
+                    entry.setBackupNodes(backup);
+                } catch (ChannelException x) {
+                    log.error("Unable to relocate[" + entry.getKey() + "] to a new backup node", x);
+                }
+            } //end if
+        } //while
+    }
+
+    public int getNextBackupIndex() {
+        int size = mapMembers.size();
+        if (mapMembers.size() == 0)return -1;
+        int node = currentNode++;
+        if (node >= size) {
+            node = 0;
+            currentNode = 0;
+        }
+        return node;
+    }
+    public Member getNextBackupNode() {
+        Member[] members = getMapMembers();
+        int node = getNextBackupIndex();
+        if ( members.length == 0 || node==-1) return null;
+        if ( node >= members.length ) node = 0;
+        return members[node];
+    }
+
+    protected abstract Member[] publishEntryInfo(Object key, Object value) throws ChannelException;
+    
+    public void heartbeat() {
+        try {
+            ping(accessTimeout);
+        }catch ( Exception x ) {
+            log.error("Unable to send AbstractReplicatedMap.ping message",x);
+        }
+    }
+
+//------------------------------------------------------------------------------    
+//              METHODS TO OVERRIDE    
+//------------------------------------------------------------------------------
+  
+    /**
+     * Removes an object from this map, it will also remove it from 
+     * 
+     * @param key Object
+     * @return Object
+     */
+    public Object remove(Object key) {
+        MapEntry entry = (MapEntry)super.remove(key);
+
+        try {
+            MapMessage msg = new MapMessage(getMapContextName(),MapMessage.MSG_REMOVE,false,(Serializable)key,null,null,null);
+            getChannel().send(getMapMembers(), msg,getChannelSendOptions());
+        } catch ( ChannelException x ) {
+            log.error("Unable to replicate out data for a LazyReplicatedMap.remove operation",x);
+        }
+        return entry!=null?entry.getValue():null;
+    }
+    
+    public Object get(Object key) {
+            MapEntry entry = (MapEntry)super.get(key);
+            if (log.isTraceEnabled()) log.trace("Requesting id:"+key+" entry:"+entry);
+            if ( entry == null ) return null;
+            if ( !entry.isPrimary() ) {
+                //if the message is not primary, we need to retrieve the latest value
+                try {
+                    Member[] backup = null;
+                    MapMessage msg = null;
+                    if ( !entry.isBackup() ) {
+                        //make sure we don't retrieve from ourselves
+                        msg = new MapMessage(getMapContextName(), MapMessage.MSG_RETRIEVE_BACKUP, false,
+                                             (Serializable) key, null, null, null);
+                        Response[] resp = getRpcChannel().send(entry.getBackupNodes(),msg, this.getRpcChannel().FIRST_REPLY, Channel.SEND_OPTIONS_DEFAULT, getRpcTimeout());
+                        if (resp == null || resp.length == 0) {
+                            //no responses
+                            log.warn("Unable to retrieve remote object for key:" + key);
+                            return null;
+                        }
+                        msg = (MapMessage) resp[0].getMessage();
+                        msg.deserialize(getExternalLoaders());
+                        backup = entry.getBackupNodes();
+                        if ( entry.getValue() instanceof ReplicatedMapEntry ) {
+                            ReplicatedMapEntry val = (ReplicatedMapEntry)entry.getValue();
+                            val.setOwner(getMapOwner());
+                        }
+                        if ( msg.getValue()!=null ) entry.setValue(msg.getValue());
+                    }
+                    if (entry.isBackup()) {
+                        //select a new backup node
+                        backup = publishEntryInfo(key, entry.getValue());
+                    } else if ( entry.isProxy() ) {
+                        //invalidate the previous primary
+                        msg = new MapMessage(getMapContextName(),MapMessage.MSG_PROXY,false,(Serializable)key,null,null,backup);
+                        Member[] dest = getMapMembersExcl(backup);
+                        if ( dest!=null && dest.length >0) {
+                            getChannel().send(dest, msg, getChannelSendOptions());
+                        }
+                    }
+    
+                    entry.setBackupNodes(backup);
+                    entry.setBackup(false);
+                    entry.setProxy(false);
+    
+    
+                } catch (Exception x) {
+                    log.error("Unable to replicate out data for a LazyReplicatedMap.get operation", x);
+                    return null;
+                }
+            }
+            if (log.isTraceEnabled()) log.trace("Requesting id:"+key+" result:"+entry.getValue());
+            return entry.getValue();
+    }    
+
+    
+    protected void printMap(String header) {
+        try {
+            System.out.println("\nDEBUG MAP:"+header);
+            System.out.println("Map["+ new String(mapContextName, chset) + ", Map Size:" + super.size());
+            Member[] mbrs = getMapMembers();
+            for ( int i=0; i<mbrs.length;i++ ) {
+                System.out.println("Mbr["+(i+1)+"="+mbrs[i].getName());
+            }
+            Iterator i = super.entrySet().iterator();
+            int cnt = 0;
+
+            while (i.hasNext()) {
+                Map.Entry e = (Map.Entry) i.next();
+                System.out.println( (++cnt) + ". " + e.getValue());
+            }
+            System.out.println("EndMap]\n\n");
+        }catch ( Exception ignore) {
+            ignore.printStackTrace();
+        }
+    }
+    
+    /**
+         * Returns true if the key has an entry in the map.
+         * The entry can be a proxy or a backup entry, invoking <code>get(key)</code>
+         * will make this entry primary for the group
+         * @param key Object
+         * @return boolean
+         */
+        public boolean containsKey(Object key) {
+            return super.containsKey(key);
+        }
+    
+    
+        public Object put(Object key, Object value) {
+            MapEntry entry = new MapEntry(key,value);
+            entry.setBackup(false);
+            entry.setProxy(false);
+    
+            Object old = null;
+    
+            //make sure that any old values get removed
+            if ( containsKey(key) ) old = remove(key);
+            try {
+                Member[] backup = publishEntryInfo(key, value);
+                entry.setBackupNodes(backup);
+            } catch (ChannelException x) {
+                log.error("Unable to replicate out data for a LazyReplicatedMap.put operation", x);
+            }
+            super.put(key,entry);
+            return old;
+        }
+    
+    
+        /**
+         * Copies all values from one map to this instance
+         * @param m Map
+         */
+        public void putAll(Map m) {
+            Iterator i = m.entrySet().iterator();
+            while ( i.hasNext() ) {
+                Map.Entry entry = (Map.Entry)i.next();
+                put(entry.getKey(),entry.getValue());
+            }
+        }
+    
+        public void clear() {
+            //only delete active keys
+            Iterator keys = keySet().iterator();
+            while ( keys.hasNext() ) remove(keys.next());
+        }
+    
+        public boolean containsValue(Object value) {
+            if ( value == null ) {
+                return super.containsValue(value);
+            } else {
+                Iterator i = super.entrySet().iterator();
+                while (i.hasNext()) {
+                    Map.Entry e = (Map.Entry) i.next();
+                    MapEntry entry = (MapEntry) e.getValue();
+                    if (entry.isPrimary() && value.equals(entry.getValue())) return true;
+                }//while
+                return false;
+            }//end if
+        }
+    
+        public Object clone() {
+            throw new UnsupportedOperationException("This operation is not valid on a replicated map");
+        }
+    
+        /**
+         * Returns the entire contents of the map
+         * Map.Entry.getValue() will return a LazyReplicatedMap.MapEntry object containing all the information 
+         * about the object.
+         * @return Set
+         */
+        public Set entrySetFull() {
+            return super.entrySet();
+        }
+    
+        public Set keySetFull() {
+            return super.keySet();
+        }
+    
+        public int sizeFull() {
+            return super.size();
+        }
+    
+        public Set entrySet() {
+            LinkedHashSet set = new LinkedHashSet(super.size());
+            Iterator i = super.entrySet().iterator();
+            while ( i.hasNext() ) {
+                Map.Entry e = (Map.Entry)i.next();
+                MapEntry entry = (MapEntry)e.getValue();
+                if ( entry.isPrimary() ) set.add(entry);
+            }
+            return Collections.unmodifiableSet(set);
+        }
+    
+        public Set keySet() {
+            //todo implement
+            //should only return keys where this is active.
+            LinkedHashSet set = new LinkedHashSet(super.size());
+            Iterator i = super.entrySet().iterator();
+            while ( i.hasNext() ) {
+                Map.Entry e = (Map.Entry)i.next();
+                MapEntry entry = (MapEntry)e.getValue();
+                if ( entry.isPrimary() ) set.add(entry.getKey());
+            }
+            return Collections.unmodifiableSet(set);
+        }
+    
+    
+        public int size() {
+            //todo, implement a counter variable instead
+            //only count active members in this node
+            int counter = 0;
+            Object[] items = super.entrySet().toArray();
+            for (int i=0; i<items.length; i++ ) {
+                Map.Entry e = (Map.Entry) items[i];
+                if ( e != null ) {
+                    MapEntry entry = (MapEntry) e.getValue();
+                    if (entry.isPrimary() && entry.getValue() != null) counter++;
+                }
+            }
+            return counter;
+        }
+    
+        protected boolean removeEldestEntry(Map.Entry eldest) {
+            return false;
+        }
+    
+        public boolean isEmpty() {
+            return size()==0;
+        }
+    
+        public Collection values() {
+            ArrayList values = new ArrayList(super.size());
+            Iterator i = super.entrySet().iterator();
+            while ( i.hasNext() ) {
+                Map.Entry e = (Map.Entry)i.next();
+                MapEntry entry = (MapEntry)e.getValue();
+                if ( entry.isPrimary() && entry.getValue()!=null) values.add(entry.getValue());
+            }
+            return Collections.unmodifiableCollection(values);
+        }
+        
+
+//------------------------------------------------------------------------------
+//                Map Entry class
+//------------------------------------------------------------------------------
+    public static class MapEntry implements Map.Entry {
+        private boolean backup;
+        private boolean proxy;
+        private Member[] backupNodes;
+
+        private Object key;
+        private Object value;
+
+        public MapEntry(Object key, Object value) {
+            setKey(key);
+            setValue(value);
+            
+        }
+        
+        public boolean isKeySerializable() {
+            return (key == null) || (key instanceof Serializable);
+        }
+        
+        public boolean isValueSerializable() {
+            return (value==null) || (value instanceof Serializable);
+        }
+        
+        public boolean isSerializable() {
+            return isKeySerializable() && isValueSerializable();
+        }
+        
+        public boolean isBackup() {
+            return backup;
+        }
+
+        public void setBackup(boolean backup) {
+            this.backup = backup;
+        }
+
+        public boolean isProxy() {
+            return proxy;
+        }
+
+        public boolean isPrimary() {
+            return ( (!proxy) && (!backup));
+        }
+
+        public void setProxy(boolean proxy) {
+            this.proxy = proxy;
+        }
+
+        public boolean isDiffable() {
+            return (value instanceof ReplicatedMapEntry) &&
+                   ((ReplicatedMapEntry)value).isDiffable();
+        }
+
+        public void setBackupNodes(Member[] nodes) {
+            this.backupNodes = nodes;
+        }
+
+        public Member[] getBackupNodes() {
+            return backupNodes;
+        }
+
+        public Object getValue() {
+            return value;
+        }
+
+        public Object setValue(Object value) {
+            Object old = this.value;
+            this.value = (Serializable) value;
+            return old;
+        }
+
+        public Object getKey() {
+            return key;
+        }
+        
+        public Object setKey(Object key) {
+            Object old = this.key;
+            this.key = (Serializable)key;
+            return old;
+        }
+
+        public int hashCode() {
+            return key.hashCode();
+        }
+
+        public boolean equals(Object o) {
+            return key.equals(o);
+        }
+
+        /**
+         * apply a diff, or an entire object
+         * @param data byte[]
+         * @param offset int
+         * @param length int
+         * @param diff boolean
+         * @throws IOException
+         * @throws ClassNotFoundException
+         */
+        public void apply(byte[] data, int offset, int length, boolean diff) throws IOException, ClassNotFoundException {
+            if (isDiffable() && diff) {
+                ReplicatedMapEntry rentry = (ReplicatedMapEntry) value;
+                try {
+                    rentry.lock();
+                    rentry.applyDiff(data, offset, length);
+                } finally {
+                    rentry.unlock();
+                }
+            } else if (length == 0) {
+                value = null;
+                proxy = true;
+            } else {
+                value = XByteBuffer.deserialize(data, offset, length);
+            }
+        }
+        
+        public String toString() {
+            StringBuffer buf = new StringBuffer("MapEntry[key:");
+            buf.append(getKey()).append("; ");
+            buf.append("value:").append(getValue()).append("; ");
+            buf.append("primary:").append(isPrimary()).append("; ");
+            buf.append("backup:").append(isBackup()).append("; ");
+            buf.append("proxy:").append(isProxy()).append(";]");
+            return buf.toString();
+        }
+
+    }
+
+//------------------------------------------------------------------------------
+//                map message to send to and from other maps
+//------------------------------------------------------------------------------
+
+    public static class MapMessage implements Serializable {
+        public static final int MSG_BACKUP = 1;
+        public static final int MSG_RETRIEVE_BACKUP = 2;
+        public static final int MSG_PROXY = 3;
+        public static final int MSG_REMOVE = 4;
+        public static final int MSG_STATE = 5;
+        public static final int MSG_START = 6;
+        public static final int MSG_STOP = 7;
+        public static final int MSG_INIT = 8;
+
+        private byte[] mapId;
+        private int msgtype;
+        private boolean diff;
+        private transient Serializable key;
+        private transient Serializable value;
+        private byte[] valuedata;
+        private byte[] keydata;
+        private byte[] diffvalue;
+        private Member[] nodes;
+        
+        public String toString() {
+            StringBuffer buf = new StringBuffer("MapMessage[context=");
+            buf.append(new String(mapId));
+            buf.append("; type=");
+            buf.append(getTypeDesc());
+            buf.append("; key=");
+            buf.append(key);
+            buf.append("; value=");
+            buf.append(value);
+            return buf.toString();
+        }
+        
+        public String getTypeDesc() {
+            switch (msgtype) {
+                case MSG_BACKUP: return "MSG_BACKUP";
+                case MSG_RETRIEVE_BACKUP: return "MSG_RETRIEVE_BACKUP";
+                case MSG_PROXY: return "MSG_PROXY";
+                case MSG_REMOVE: return "MSG_REMOVE";
+                case MSG_STATE: return "MSG_STATE";
+                case MSG_START: return "MSG_START";
+                case MSG_STOP: return "MSG_STOP";
+                case MSG_INIT: return "MSG_INIT";
+                default : return "UNKNOWN";
+            }
+        }
+
+        public MapMessage() {}
+
+        public MapMessage(byte[] mapId,int msgtype, boolean diff,
+                          Serializable key, Serializable value,
+                          byte[] diffvalue, Member[] nodes)  {
+            this.mapId = mapId;
+            this.msgtype = msgtype;
+            this.diff = diff;
+            this.key = key;
+            this.value = value;
+            this.diffvalue = diffvalue;
+            this.nodes = nodes;
+            setValue(value);
+            setKey(key);
+        }
+        
+        public void deserialize(ClassLoader[] cls) throws IOException, ClassNotFoundException {
+            key(cls);
+            value(cls);
+        }
+
+        public int getMsgType() {
+            return msgtype;
+        }
+
+        public boolean isDiff() {
+            return diff;
+        }
+
+        public Serializable getKey() {
+            try {
+                return key(null);
+            } catch ( Exception x ) {
+                log.error("Deserialization error of the MapMessage.key",x);
+                return null;
+            }
+        }
+
+        public Serializable key(ClassLoader[] cls) throws IOException, ClassNotFoundException {
+            if ( key!=null ) return key;
+            if ( keydata == null || keydata.length == 0 ) return null;
+            key = XByteBuffer.deserialize(keydata,0,keydata.length,cls);
+            keydata = null;
+            return key;
+        }
+        
+        public byte[] getKeyData() {
+            return keydata;
+        }
+        
+        public Serializable getValue() {
+            try {
+                return value(null);
+            } catch ( Exception x ) {
+                log.error("Deserialization error of the MapMessage.value",x);
+                return null;
+            }
+        }
+
+        public Serializable value(ClassLoader[] cls) throws IOException, ClassNotFoundException  {
+            if ( value!=null ) return value;
+            if ( valuedata == null || valuedata.length == 0 ) return null;
+            value = XByteBuffer.deserialize(valuedata,0,valuedata.length,cls);
+            valuedata = null;;
+            return value;
+        }
+        
+        public byte[] getValueData() {
+            return valuedata;
+        }
+
+        public byte[] getDiffValue() {
+            return diffvalue;
+        }
+
+        public Member[] getBackupNodes() {
+            return nodes;
+        }
+
+        private void setBackUpNodes(Member[] nodes) {
+            this.nodes = nodes;
+        }
+
+        public byte[] getMapId() {
+            return mapId;
+        }
+
+        public void setValue(Serializable value) {
+            try {
+                if ( value != null ) valuedata = XByteBuffer.serialize(value);
+                this.value = value;
+            }catch ( IOException x ) {
+                throw new RuntimeException(x);
+            }
+        }
+        
+        public void setKey(Serializable key) {
+            try {
+                if (key != null) keydata = XByteBuffer.serialize(key);
+                this.key = key;
+            } catch (IOException x) {
+                throw new RuntimeException(x);
+            }
+        }
+        
+        protected Member[] readMembers(ObjectInput in) throws IOException, ClassNotFoundException {
+            int nodecount = in.readInt();
+            Member[] members = new Member[nodecount];
+            for ( int i=0; i<members.length; i++ ) {
+                byte[] d = new byte[in.readInt()];
+                in.read(d);
+                if (d.length > 0) members[i] = MemberImpl.getMember(d);
+            }
+            return members;
+        }
+        
+        protected void writeMembers(ObjectOutput out,Member[] members) throws IOException {
+            if ( members == null ) members = new Member[0];
+            out.writeInt(members.length);
+            for (int i=0; i<members.length; i++ ) {
+                if ( members[i] != null ) {
+                    byte[] d = members[i] != null ? ( (MemberImpl)members[i]).getData(false) : new byte[0];
+                    out.writeInt(d.length);
+                    out.write(d);
+                }
+            }
+        }
+        
+        
+        /**
+         * shallow clone
+         * @return Object
+         */
+        public Object clone() {
+            MapMessage msg = new MapMessage(this.mapId, this.msgtype, this.diff, this.key, this.value, this.diffvalue, this.nodes);
+            msg.keydata = this.keydata;
+            msg.valuedata = this.valuedata;
+            return msg;
+        }
+    } //MapMessage
+
+
+    public Channel getChannel() {
+        return channel;
+    }
+
+    public byte[] getMapContextName() {
+        return mapContextName;
+    }
+
+    public RpcChannel getRpcChannel() {
+        return rpcChannel;
+    }
+
+    public long getRpcTimeout() {
+        return rpcTimeout;
+    }
+
+    public Object getStateMutex() {
+        return stateMutex;
+    }
+
+    public boolean isStateTransferred() {
+        return stateTransferred;
+    }
+
+    public Object getMapOwner() {
+        return mapOwner;
+    }
+
+    public ClassLoader[] getExternalLoaders() {
+        return externalLoaders;
+    }
+
+    public int getChannelSendOptions() {
+        return channelSendOptions;
+    }
+
+    public long getAccessTimeout() {
+        return accessTimeout;
+    }
+
+    public void setMapOwner(Object mapOwner) {
+        this.mapOwner = mapOwner;
+    }
+
+    public void setExternalLoaders(ClassLoader[] externalLoaders) {
+        this.externalLoaders = externalLoaders;
+    }
+
+    public void setChannelSendOptions(int channelSendOptions) {
+        this.channelSendOptions = channelSendOptions;
+    }
+
+    public void setAccessTimeout(long accessTimeout) {
+        this.accessTimeout = accessTimeout;
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/tipis/LazyReplicatedMap.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/tipis/LazyReplicatedMap.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/tipis/LazyReplicatedMap.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,184 @@
+/*
+ * Copyright 1999,2004-2006 The Apache Software Foundation.
+ *
+ * Licensed 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.tribes.tipis;
+
+import java.io.Serializable;
+
+import org.apache.catalina.tribes.Channel;
+import org.apache.catalina.tribes.ChannelException;
+import org.apache.catalina.tribes.ChannelListener;
+import org.apache.catalina.tribes.Member;
+import org.apache.catalina.tribes.MembershipListener;
+import org.apache.catalina.tribes.group.RpcCallback;
+import org.apache.catalina.tribes.util.Arrays;
+import org.apache.catalina.tribes.UniqueId;
+
+/**
+ * A smart implementation of a stateful replicated map. uses primary/secondary backup strategy. 
+ * One node is always the primary and one node is always the backup.
+ * This map is synchronized across a cluster, and only has one backup member.<br/>
+ * A perfect usage for this map would be a session map for a session manager in a clustered environment.<br/>
+ * The only way to modify this list is to use the <code>put, putAll, remove</code> methods.
+ * entrySet, entrySetFull, keySet, keySetFull, returns all non modifiable sets.<br><br>
+ * If objects (values) in the map change without invoking <code>put()</code> or <code>remove()</code>
+ * the data can be distributed using two different methods:<br>
+ * <code>replicate(boolean)</code> and <code>replicate(Object, boolean)</code><br>
+ * These two methods are very important two understand. The map can work with two set of value objects:<br>
+ * 1. Serializable - the entire object gets serialized each time it is replicated<br>
+ * 2. ReplicatedMapEntry - this interface allows for a isDirty() flag and to replicate diffs if desired.<br>
+ * Implementing the <code>ReplicatedMapEntry</code> interface allows you to decide what objects 
+ * get replicated and how much data gets replicated each time.<br>
+ * If you implement a smart AOP mechanism to detect changes in underlying objects, you can replicate
+ * only those changes by implementing the ReplicatedMapEntry interface, and return true when isDiffable()
+ * is invoked.<br><br>
+ * 
+ * This map implementation doesn't have a background thread running to replicate changes.
+ * If you do have changes without invoking put/remove then you need to invoke one of the following methods:
+ * <ul>
+ * <li><code>replicate(Object,boolean)</code> - replicates only the object that belongs to the key</li>
+ * <li><code>replicate(boolean)</code> - Scans the entire map for changes and replicates data</li>
+ *  </ul>
+ * the <code>boolean</code> value in the <code>replicate</code> method used to decide 
+ * whether to only replicate objects that implement the <code>ReplicatedMapEntry</code> interface
+ * or to replicate all objects. If an object doesn't implement the <code>ReplicatedMapEntry</code> interface
+ * each time the object gets replicated the entire object gets serialized, hence a call to <code>replicate(true)</code>
+ * will replicate all objects in this map that are using this node as primary.
+ * 
+ * <br><br><b>REMBER TO CALL <code>breakdown()</code> or <code>finalize()</code> when you are done with the map to 
+ * avoid memory leaks.<br><br>
+ * @todo implement periodic sync/transfer thread
+ * @author Filip Hanik
+ * @version 1.0
+ */
+public class LazyReplicatedMap extends AbstractReplicatedMap 
+    implements RpcCallback, ChannelListener, MembershipListener {
+    protected static org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory.getLog(LazyReplicatedMap.class);
+    
+    
+    
+//------------------------------------------------------------------------------    
+//              CONSTRUCTORS / DESTRUCTORS
+//------------------------------------------------------------------------------   
+    /**
+         * Creates a new map
+         * @param channel The channel to use for communication
+         * @param timeout long - timeout for RPC messags
+         * @param mapContextName String - unique name for this map, to allow multiple maps per channel
+         * @param initialCapacity int - the size of this map, see HashMap
+         * @param loadFactor float - load factor, see HashMap
+         */
+        public LazyReplicatedMap(Object owner, Channel channel, long timeout, String mapContextName, int initialCapacity, float loadFactor, ClassLoader[] cls) {
+            super(owner,channel,timeout,mapContextName,initialCapacity,loadFactor, Channel.SEND_OPTIONS_DEFAULT,cls);
+        }
+
+        /**
+         * Creates a new map
+         * @param channel The channel to use for communication
+         * @param timeout long - timeout for RPC messags
+         * @param mapContextName String - unique name for this map, to allow multiple maps per channel
+         * @param initialCapacity int - the size of this map, see HashMap
+         */
+        public LazyReplicatedMap(Object owner, Channel channel, long timeout, String mapContextName, int initialCapacity, ClassLoader[] cls) {
+            super(owner, channel,timeout,mapContextName,initialCapacity, LazyReplicatedMap.DEFAULT_LOAD_FACTOR, Channel.SEND_OPTIONS_DEFAULT, cls);
+        }
+
+        /**
+         * Creates a new map
+         * @param channel The channel to use for communication
+         * @param timeout long - timeout for RPC messags
+         * @param mapContextName String - unique name for this map, to allow multiple maps per channel
+         */
+        public LazyReplicatedMap(Object owner, Channel channel, long timeout, String mapContextName, ClassLoader[] cls) {
+            super(owner, channel,timeout,mapContextName, LazyReplicatedMap.DEFAULT_INITIAL_CAPACITY,LazyReplicatedMap.DEFAULT_LOAD_FACTOR,Channel.SEND_OPTIONS_DEFAULT, cls);
+        }
+
+
+
+
+    
+//------------------------------------------------------------------------------    
+//              METHODS TO OVERRIDE    
+//------------------------------------------------------------------------------
+    /**
+     * publish info about a map pair (key/value) to other nodes in the cluster
+     * @param key Object
+     * @param value Object
+     * @return Member - the backup node
+     * @throws ChannelException
+     */
+    protected Member[] publishEntryInfo(Object key, Object value) throws ChannelException {
+        if  (! (key instanceof Serializable && value instanceof Serializable)  ) return new Member[0];
+        Member[] members = getMapMembers();
+        int firstIdx = getNextBackupIndex();
+        int nextIdx = firstIdx;
+        Member[] backup = new Member[0];
+        
+        //there are no backups
+        if ( members.length == 0 || firstIdx == -1 ) return backup;
+        
+        boolean success = false;
+        do {
+            //select a backup node
+            Member next = members[firstIdx];
+            
+            //increment for the next round of back up selection
+            nextIdx = firstIdx + 1;
+            if ( nextIdx >= members.length ) nextIdx = 0;
+            
+            if (next == null) {
+                continue;
+            }
+            MapMessage msg = null;
+            try {
+                backup = wrap(next);
+                //publish the backup data to one node
+                msg = new MapMessage(getMapContextName(), MapMessage.MSG_BACKUP, false,
+                                     (Serializable) key, (Serializable) value, null, backup);
+                if ( log.isTraceEnabled() ) 
+                    log.trace("Publishing backup data:"+msg+" to: "+next.getName());
+                UniqueId id = getChannel().send(backup, msg, getChannelSendOptions());
+                if ( log.isTraceEnabled() )
+                    log.trace("Data published:"+msg+" msg Id:"+id);
+                //we published out to a backup, mark the test success
+                success = true;
+            }catch ( ChannelException x ) {
+                log.error("Unable to replicate backup key:"+key+" to backup:"+next+". Reason:"+x.getMessage(),x);
+            }
+            try {
+                //publish the data out to all nodes
+                Member[] proxies = excludeFromSet(backup, getMapMembers());
+                if (success && proxies.length > 0 ) {
+                    msg = new MapMessage(getMapContextName(), MapMessage.MSG_PROXY, false,
+                                         (Serializable) key, null, null, backup);
+                    if ( log.isTraceEnabled() ) 
+                    log.trace("Publishing proxy data:"+msg+" to: "+Arrays.toNameString(proxies));
+                    getChannel().send(proxies, msg, getChannelSendOptions());
+                }
+            }catch  ( ChannelException x ) {
+                //log the error, but proceed, this should only happen if a node went down,
+                //and if the node went down, then it can't receive the message, the others
+                //should still get it.
+                log.error("Unable to replicate proxy key:"+key+" to backup:"+next+". Reason:"+x.getMessage(),x);
+            }
+        } while ( !success && (firstIdx!=nextIdx));
+        return backup;
+    }
+    
+    
+
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/tipis/ReplicatedMap.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/tipis/ReplicatedMap.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/tipis/ReplicatedMap.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,117 @@
+/*
+ * Copyright 1999,2004-2006 The Apache Software Foundation.
+ *
+ * Licensed 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.tribes.tipis;
+
+import java.io.Serializable;
+
+import org.apache.catalina.tribes.Channel;
+import org.apache.catalina.tribes.ChannelException;
+import org.apache.catalina.tribes.ChannelListener;
+import org.apache.catalina.tribes.Member;
+import org.apache.catalina.tribes.MembershipListener;
+import org.apache.catalina.tribes.group.RpcCallback;
+
+/**
+ * All-to-all replication for a hash map implementation. Each node in the cluster will carry an identical 
+ * copy of the map.<br><br>
+ * This map implementation doesn't have a background thread running to replicate changes.
+ * If you do have changes without invoking put/remove then you need to invoke one of the following methods:
+ * <ul>
+ * <li><code>replicate(Object,boolean)</code> - replicates only the object that belongs to the key</li>
+ * <li><code>replicate(boolean)</code> - Scans the entire map for changes and replicates data</li>
+ *  </ul>
+ * the <code>boolean</code> value in the <code>replicate</code> method used to decide
+ * whether to only replicate objects that implement the <code>ReplicatedMapEntry</code> interface
+ * or to replicate all objects. If an object doesn't implement the <code>ReplicatedMapEntry</code> interface
+ * each time the object gets replicated the entire object gets serialized, hence a call to <code>replicate(true)</code>
+ * will replicate all objects in this map that are using this node as primary.
+ *
+ * <br><br><b>REMBER TO CALL <code>breakdown()</code> or <code>finalize()</code> when you are done with the map to
+ * avoid memory leaks.<br><br>
+ * @todo implement periodic sync/transfer thread
+ * @author Filip Hanik
+ * @version 1.0
+ * 
+ * @todo memberDisappeared, should do nothing except change map membership
+ *       by default it relocates the primary objects
+ */
+public class ReplicatedMap extends AbstractReplicatedMap implements RpcCallback, ChannelListener, MembershipListener {
+
+    protected static org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory.getLog(ReplicatedMap.class);
+
+//------------------------------------------------------------------------------
+//              CONSTRUCTORS / DESTRUCTORS
+//------------------------------------------------------------------------------
+    /**
+     * Creates a new map
+     * @param channel The channel to use for communication
+     * @param timeout long - timeout for RPC messags
+     * @param mapContextName String - unique name for this map, to allow multiple maps per channel
+     * @param initialCapacity int - the size of this map, see HashMap
+     * @param loadFactor float - load factor, see HashMap
+     */
+    public ReplicatedMap(Object owner, Channel channel, long timeout, String mapContextName, int initialCapacity,float loadFactor, ClassLoader[] cls) {
+        super(owner,channel, timeout, mapContextName, initialCapacity, loadFactor, Channel.SEND_OPTIONS_DEFAULT, cls);
+    }
+
+    /**
+     * Creates a new map
+     * @param channel The channel to use for communication
+     * @param timeout long - timeout for RPC messags
+     * @param mapContextName String - unique name for this map, to allow multiple maps per channel
+     * @param initialCapacity int - the size of this map, see HashMap
+     */
+    public ReplicatedMap(Object owner, Channel channel, long timeout, String mapContextName, int initialCapacity, ClassLoader[] cls) {
+        super(owner,channel, timeout, mapContextName, initialCapacity, AbstractReplicatedMap.DEFAULT_LOAD_FACTOR,Channel.SEND_OPTIONS_DEFAULT, cls);
+    }
+
+    /**
+     * Creates a new map
+     * @param channel The channel to use for communication
+     * @param timeout long - timeout for RPC messags
+     * @param mapContextName String - unique name for this map, to allow multiple maps per channel
+     */
+    public ReplicatedMap(Object owner, Channel channel, long timeout, String mapContextName, ClassLoader[] cls) {
+        super(owner, channel, timeout, mapContextName,AbstractReplicatedMap.DEFAULT_INITIAL_CAPACITY, AbstractReplicatedMap.DEFAULT_LOAD_FACTOR, Channel.SEND_OPTIONS_DEFAULT, cls);
+    }
+
+//------------------------------------------------------------------------------
+//              METHODS TO OVERRIDE
+//------------------------------------------------------------------------------
+    /**
+     * publish info about a map pair (key/value) to other nodes in the cluster
+     * @param key Object
+     * @param value Object
+     * @return Member - the backup node
+     * @throws ChannelException
+     */
+    protected Member[] publishEntryInfo(Object key, Object value) throws ChannelException {
+        if  (! (key instanceof Serializable && value instanceof Serializable)  ) return new Member[0];
+        //select a backup node
+        Member[] backup = getMapMembers();
+
+        if (backup == null || backup.length == 0) return null;
+
+        //publish the data out to all nodes
+        MapMessage msg = new MapMessage(getMapContextName(), MapMessage.MSG_BACKUP, false,
+                                        (Serializable) key, null, null, backup);
+
+        getChannel().send(getMapMembers(), msg, getChannelSendOptions());
+
+        return backup;
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/tipis/ReplicatedMapEntry.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/tipis/ReplicatedMapEntry.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/tipis/ReplicatedMapEntry.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,123 @@
+/*
+ * Copyright 1999,2004-2006 The Apache Software Foundation.
+ *
+ * Licensed 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.tribes.tipis;
+
+import java.io.IOException;
+import java.io.Serializable;
+
+/**
+ * 
+ * For smarter replication, an object can implement this interface to replicate diffs<br>
+ * The replication logic will call the methods in the following order:<br>
+ * <code>
+ * 1. if ( entry.isDirty() ) <br>
+ *      try {
+ * 2.     entry.lock();<br>
+ * 3.     byte[] diff = entry.getDiff();<br>
+ * 4.     entry.reset();<br>
+ *      } finally {<br>
+ * 5.     entry.unlock();<br>
+ *      }<br>
+ *    }<br>
+ * </code>
+ * <br>
+ * <br>
+ * When the data is deserialized the logic is called in the following order<br>
+ * <code>
+ * 1. ReplicatedMapEntry entry = (ReplicatedMapEntry)objectIn.readObject();<br>
+ * 2. if ( isBackup(entry)||isPrimary(entry) ) entry.setOwner(owner); <br>
+ * </code>
+ * <br>
+ * 
+ * 
+ * @author Filip Hanik
+ * @version 1.0
+ */
+public interface ReplicatedMapEntry extends Serializable {
+    
+    /**
+     * Has the object changed since last replication
+     * and is not in a locked state
+     * @return boolean
+     */
+    public boolean isDirty();
+    
+    /**
+     * If this returns true, the map will extract the diff using getDiff()
+     * Otherwise it will serialize the entire object.
+     * @return boolean
+     */
+    public boolean isDiffable();
+    
+    /**
+     * Returns a diff and sets the dirty map to false
+     * @return byte[]
+     * @throws IOException
+     */
+    public byte[] getDiff() throws IOException;
+    
+    
+    /**
+     * Applies a diff to an existing object.
+     * @param diff byte[]
+     * @param offset int
+     * @param length int
+     * @throws IOException
+     */
+    public void applyDiff(byte[] diff, int offset, int length) throws IOException, ClassNotFoundException;
+    
+    /**
+     * Resets the current diff state and resets the dirty flag
+     */
+    public void resetDiff();
+    
+    /**
+     * Lock during serialization
+     */
+    public void lock();
+    
+    /**
+     * Unlock after serialization
+     */
+    public void unlock();
+    
+    /**
+     * This method is called after the object has been 
+     * created on a remote map. On this method,
+     * the object can initialize itself for any data that wasn't 
+     * 
+     * @param owner Object
+     */
+    public void setOwner(Object owner);
+    
+    /**
+     * For accuracy checking, a serialized attribute can contain a version number
+     * This number increases as modifications are made to the data.
+     * The replicated map can use this to ensure accuracy on a periodic basis
+     * @return long - the version number or -1 if the data is not versioned
+     */
+    public long getVersion();
+    
+    /**
+     * Forces a certain version to a replicated map entry<br>
+     * @param version long
+     */
+    public void setVersion(long version);
+    
+    
+    
+    
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/tipis/Streamable.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/tipis/Streamable.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/tipis/Streamable.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,60 @@
+/*
+ * Copyright 1999,2004-2006 The Apache Software Foundation.
+ * 
+ * Licensed 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.tribes.tipis;
+
+import java.io.IOException;
+
+/**
+ * Example usage:
+ * <code><pre>
+ * byte[] data = new byte[1024];
+ * Streamable st = ....;
+ * while ( !st.eof() ) {
+ * &nbsp;&nbsp;int length = st.read(data,0,data.length);
+ * &nbsp;&nbsp;String s = new String(data,0,length);
+ * &nbsp;&nbsp;System.out.println(s);
+ * }
+ * </pre></code>
+ * @author Filip Hanik
+ * @version 1.0
+ */
+public interface Streamable {
+    
+    /**
+     * returns true if the stream has reached its end
+     * @return boolean
+     */
+    public boolean eof();
+   
+    /**
+     * write data into the byte array starting at offset, maximum bytes read are (data.length-offset)
+     * @param data byte[] - the array to read data into
+     * @param offset int - start position for writing data
+     * @return int - the number of bytes written into the data buffer
+     */
+    public int write(byte[] data, int offset, int length) throws IOException;
+    
+    /**
+     * read data into the byte array starting at offset
+     * @param data byte[] - the array to read data into
+     * @param offset int - start position for writing data
+     * @param length - the desired read length
+     * @return int - the number of bytes read from the data buffer
+     */
+    public int read(byte[] data, int offset, int length) throws IOException;
+
+   
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/transport/AbstractSender.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/transport/AbstractSender.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/transport/AbstractSender.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,302 @@
+/*
+ * Copyright 1999,2006 The Apache Software Foundation.
+ * 
+ * Licensed 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.tribes.transport;
+
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+
+import org.apache.catalina.tribes.Member;
+
+/**
+ * <p>Title: </p>
+ *
+ * <p>Description: </p>
+ *
+ * <p>Copyright: Copyright (c) 2005</p>
+ *
+ * <p>Company: </p>
+ *
+ * @author not attributable
+ * @version 1.0
+ */
+public abstract class AbstractSender implements DataSender {
+    
+    private boolean connected = false;
+    private int rxBufSize = 25188;
+    private int txBufSize = 43800;
+    private boolean directBuffer = false;
+    private int keepAliveCount = -1;
+    private int requestCount = 0;
+    private long connectTime;
+    private long keepAliveTime = -1;
+    private long timeout = 3000;
+    private Member destination;
+    private InetAddress address;
+    private int port;
+    private int maxRetryAttempts = 1;//1 resends
+    private int attempt;
+    private boolean tcpNoDelay = true;
+    private boolean soKeepAlive = false;
+    private boolean ooBInline = true;
+    private boolean soReuseAddress = true;
+    private boolean soLingerOn = false;
+    private int soLingerTime = 3;
+    private int soTrafficClass = 0x04 | 0x08 | 0x010;
+    private boolean throwOnFailedAck = false;
+    
+    /**
+     * transfers sender properties from one sender to another
+     * @param from AbstractSender
+     * @param to AbstractSender
+     */
+    public static void transferProperties(AbstractSender from, AbstractSender to) {
+        to.rxBufSize = from.rxBufSize;
+        to.txBufSize = from.txBufSize;
+        to.directBuffer = from.directBuffer;
+        to.keepAliveCount = from.keepAliveCount;
+        to.keepAliveTime = from.keepAliveTime;
+        to.timeout = from.timeout;
+        to.destination = from.destination;
+        to.address = from.address;
+        to.port = from.port;
+        to.maxRetryAttempts = from.maxRetryAttempts;
+        to.tcpNoDelay = from.tcpNoDelay;
+        to.soKeepAlive = from.soKeepAlive;
+        to.ooBInline = from.ooBInline;
+        to.soReuseAddress = from.soReuseAddress;
+        to.soLingerOn = from.soLingerOn;
+        to.soLingerTime = from.soLingerTime;
+        to.soTrafficClass = from.soTrafficClass;
+        to.throwOnFailedAck = from.throwOnFailedAck;
+    }   
+
+    
+    public AbstractSender() {
+        
+    }
+    
+    /**
+     * connect
+     *
+     * @throws IOException
+     * @todo Implement this org.apache.catalina.tribes.transport.DataSender method
+     */
+    public abstract void connect() throws IOException;
+
+    /**
+     * disconnect
+     *
+     * @todo Implement this org.apache.catalina.tribes.transport.DataSender method
+     */
+    public abstract void disconnect();
+
+    /**
+     * keepalive
+     *
+     * @return boolean
+     * @todo Implement this org.apache.catalina.tribes.transport.DataSender method
+     */
+    public boolean keepalive() {
+        boolean disconnect = false;
+        if ( keepAliveCount >= 0 && requestCount>keepAliveCount ) disconnect = true;
+        else if ( keepAliveTime >= 0 && keepAliveTime> (System.currentTimeMillis()-connectTime) ) disconnect = true;
+        if ( disconnect ) disconnect();
+        return disconnect;
+    }
+    
+    protected void setConnected(boolean connected){
+        this.connected = connected;
+    }
+    
+    public boolean isConnected() {
+        return connected;
+    }
+
+    public long getConnectTime() {
+        return connectTime;
+    }
+
+    public Member getDestination() {
+        return destination;
+    }
+
+
+    public int getKeepAliveCount() {
+        return keepAliveCount;
+    }
+
+    public long getKeepAliveTime() {
+        return keepAliveTime;
+    }
+
+    public int getRequestCount() {
+        return requestCount;
+    }
+
+    public int getRxBufSize() {
+        return rxBufSize;
+    }
+
+    public long getTimeout() {
+        return timeout;
+    }
+
+    public int getTxBufSize() {
+        return txBufSize;
+    }
+
+    public InetAddress getAddress() {
+        return address;
+    }
+
+    public int getPort() {
+        return port;
+    }
+
+    public int getMaxRetryAttempts() {
+        return maxRetryAttempts;
+    }
+
+    public void setDirectBuffer(boolean directBuffer) {
+        this.directBuffer = directBuffer;
+    }
+
+    public boolean getDirectBuffer() {
+        return this.directBuffer;
+    }
+
+    public int getAttempt() {
+        return attempt;
+    }
+
+    public boolean getTcpNoDelay() {
+        return tcpNoDelay;
+    }
+
+    public boolean getSoKeepAlive() {
+        return soKeepAlive;
+    }
+
+    public boolean getOoBInline() {
+        return ooBInline;
+    }
+
+    public boolean getSoReuseAddress() {
+        return soReuseAddress;
+    }
+
+    public boolean getSoLingerOn() {
+        return soLingerOn;
+    }
+
+    public int getSoLingerTime() {
+        return soLingerTime;
+    }
+
+    public int getSoTrafficClass() {
+        return soTrafficClass;
+    }
+
+    public boolean getThrowOnFailedAck() {
+        return throwOnFailedAck;
+    }
+
+    public void setKeepAliveCount(int keepAliveCount) {
+        this.keepAliveCount = keepAliveCount;
+    }
+
+    public void setKeepAliveTime(long keepAliveTime) {
+        this.keepAliveTime = keepAliveTime;
+    }
+
+    public void setRequestCount(int requestCount) {
+        this.requestCount = requestCount;
+    }
+
+    public void setRxBufSize(int rxBufSize) {
+        this.rxBufSize = rxBufSize;
+    }
+
+    public void setTimeout(long timeout) {
+        this.timeout = timeout;
+    }
+
+    public void setTxBufSize(int txBufSize) {
+        this.txBufSize = txBufSize;
+    }
+
+    public void setConnectTime(long connectTime) {
+        this.connectTime = connectTime;
+    }
+
+    public void setMaxRetryAttempts(int maxRetryAttempts) {
+        this.maxRetryAttempts = maxRetryAttempts;
+    }
+
+    public void setAttempt(int attempt) {
+        this.attempt = attempt;
+    }
+
+    public void setTcpNoDelay(boolean tcpNoDelay) {
+        this.tcpNoDelay = tcpNoDelay;
+    }
+
+    public void setSoKeepAlive(boolean soKeepAlive) {
+        this.soKeepAlive = soKeepAlive;
+    }
+
+    public void setOoBInline(boolean ooBInline) {
+        this.ooBInline = ooBInline;
+    }
+
+    public void setSoReuseAddress(boolean soReuseAddress) {
+        this.soReuseAddress = soReuseAddress;
+    }
+
+    public void setSoLingerOn(boolean soLingerOn) {
+        this.soLingerOn = soLingerOn;
+    }
+
+    public void setSoLingerTime(int soLingerTime) {
+        this.soLingerTime = soLingerTime;
+    }
+
+    public void setSoTrafficClass(int soTrafficClass) {
+        this.soTrafficClass = soTrafficClass;
+    }
+
+    public void setThrowOnFailedAck(boolean throwOnFailedAck) {
+        this.throwOnFailedAck = throwOnFailedAck;
+    }
+
+    public void setDestination(Member destination) throws UnknownHostException {
+        this.destination = destination;
+        this.address = InetAddress.getByAddress(destination.getHost());
+        this.port = destination.getPort();
+
+    }
+
+    public void setPort(int port) {
+        this.port = port;
+    }
+
+    public void setAddress(InetAddress address) {
+        this.address = address;
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/transport/Constants.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/transport/Constants.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/transport/Constants.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,42 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tribes.transport;
+
+import org.apache.catalina.tribes.io.XByteBuffer;
+
+/**
+ * Manifest constants for the <code>org.apache.catalina.tribes.transport</code>
+ * package.
+ * @author Filip Hanik
+ * @author Peter Rossbach
+ * @version $Revision: 303753 $ $Date: 2005-03-14 15:24:30 -0600 (Mon, 14 Mar 2005) $
+ */
+
+public class Constants {
+
+    public static final String Package = "org.apache.catalina.tribes.transport";
+    
+    /*
+     * Do not change any of these values!
+     */
+    public static final byte[] ACK_DATA = new byte[] {6, 2, 3};
+    public static final byte[] FAIL_ACK_DATA = new byte[] {11, 0, 5};
+    public static final byte[] ACK_COMMAND = XByteBuffer.createDataPackage(ACK_DATA);
+    public static final byte[] FAIL_ACK_COMMAND = XByteBuffer.createDataPackage(FAIL_ACK_DATA);
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/transport/DataSender.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/transport/DataSender.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/transport/DataSender.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,46 @@
+/*
+ * Copyright 1999,2006 The Apache Software Foundation.
+ * 
+ * Licensed 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.tribes.transport;
+
+import java.io.IOException;
+
+/**
+ * <p>Title: </p>
+ *
+ * <p>Description: </p>
+ *
+ * <p>Copyright: Copyright (c) 2005</p>
+ *
+ * <p>Company: </p>
+ *
+ * @author not attributable
+ * @version 1.0
+ */
+public interface DataSender {
+    public void connect() throws IOException;
+    public void disconnect();
+    public boolean isConnected();
+    public void setRxBufSize(int size);
+    public void setTxBufSize(int size);
+    public boolean keepalive();
+    public void setTimeout(long timeout);
+    public void setKeepAliveCount(int maxRequests);
+    public void setKeepAliveTime(long keepAliveTimeInMs);
+    public int getRequestCount();
+    public long getConnectTime();
+    
+    
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/transport/LocalStrings.properties
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/transport/LocalStrings.properties	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/transport/LocalStrings.properties	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,69 @@
+AsyncSocketSender.create.thread=Create sender [{0}:{1,number,integer}] queue thread to tcp background replication
+AsyncSocketSender.queue.message=Queue message to [{0}:{1,number,integer}] id=[{2}] size={3}
+AsyncSocketSender.send.error=Unable to asynchronously send session with id=[{0}] - message will be ignored.
+AsyncSocketSender.queue.empty=Queue in sender [{0}:{1,number,integer}] returned null element!
+cluster.mbean.register.already=MBean {0} already registered!
+IDataSender.ack.eof=EOF reached at local port [{0}:{1,number,integer}]
+IDataSender.ack.receive=Got ACK at local port [{0}:{1,number,integer}]
+IDataSender.ack.missing=Unable to read acknowledgement from [{0}:{1,number,integer}] in {2,number,integer} ms. Disconnecting socket, and trying again.
+IDataSender.ack.read=Read wait ack char '{2}' [{0}:{1,number,integer}]
+IDataSender.ack.start=Waiting for ACK message [{0}:{1,number,integer}]
+IDataSender.ack.wrong=Missing correct ACK after 10 bytes read at local port [{0}:{1,number,integer}]
+IDataSender.closeSocket=Sender close socket to [{0}:{1,number,integer}] (close count {2,number,integer})
+IDataSender.connect=Sender connect to [{0}:{1,number,integer}] (connect count {2,number,integer})
+IDataSender.create=Create sender [{0}:{1,number,integer}]
+IDataSender.disconnect=Sender disconnect from [{0}:{1,number,integer}] (disconnect count {2,number,integer})
+IDataSender.message.disconnect=Message transfered: Sender can't disconnect from [{0}:{1,number,integer}]
+IDataSender.message.create=Message transfered: Sender can't create current socket [{0}:{1,number,integer}]
+IDataSender.openSocket=Sender open socket to [{0}:{1,number,integer}] (open count {2,number,integer})
+IDataSender.openSocket.failure=Open sender socket [{0}:{1,number,integer}] failure! (open failure count {2,number,integer})
+IDataSender.send.again=Send data again to [{0}:{1,number,integer}]
+IDataSender.send.crash=Send message crashed [{0}:{1,number,integer}] type=[{2}], id=[{3}]
+IDataSender.send.message=Send message to [{0}:{1,number,integer}] id=[{2}] size={3,number,integer}
+IDataSender.send.lost=Message lost: [{0}:{1,number,integer}] type=[{2}], id=[{3}]
+IDataSender.senderModes.Configured=Configured a data replication sender for mode {0}
+IDataSender.senderModes.Instantiate=Can't instantiate a data replication sender of class {0}
+IDataSender.senderModes.Missing=Can't configure a data replication sender for mode {0}
+IDataSender.senderModes.Resources=Can't load data replication sender mapping list
+IDataSender.stats=Send stats from [{0}:{1,number,integer}], Nr of bytes sent={2,number,integer} over {3} = {4,number,integer} bytes/request, processing time {5,number,integer} msec, avg processing time {6,number,integer} msec
+PoolSocketSender.senderQueue.sender.failed=PoolSocketSender create new sender to [{0}:{1,number,integer}] failed
+PoolSocketSender.noMoreSender=No socket sender available for client [{0}:{1,number,integer}] did it disappeared?
+ReplicationTransmitter.getProperty=get property {0}
+ReplicationTransmitter.setProperty=set property {0}: {1} old value {2}
+ReplicationTransmitter.started=Start ClusterSender at cluster {0} with name {1}
+ReplicationTransmitter.stopped=Stopped ClusterSender at cluster {0} with name {1}
+ReplicationValve.crossContext.add=add Cross Context session replication container to replicationValve threadlocal
+ReplicationValve.crossContext.registerSession=register Cross context session id={0} from context {1}
+ReplicationValve.crossContext.remove=remove Cross Context session replication container from replicationValve threadlocal
+ReplicationValve.crossContext.sendDelta=send Cross Context session delta from context {0}.
+ReplicationValve.filter.loading=Loading request filters={0}
+ReplicationValve.filter.token=Request filter={0}
+ReplicationValve.filter.token.failure=Unable to compile filter={0}
+ReplicationValve.invoke.uri=Invoking replication request on {0}
+ReplicationValve.nocluster=No cluster configured for this request.
+ReplicationValve.resetDeltaRequest=Cluster is standalone: reset Session Request Delta at context {0}
+ReplicationValve.send.failure=Unable to perform replication request.
+ReplicationValve.send.invalid.failure=Unable to send session [id={0}] invalid message over cluster.
+ReplicationValve.session.found=Context {0}: Found session {1} but it isn't a ClusterSession.
+ReplicationValve.session.indicator=Context {0}: Primarity of session {0} in request attribute {1} is {2}.
+ReplicationValve.session.invalid=Context {0}: Requested session {1} is invalid, removed or not replicated at this node.
+ReplicationValve.stats=Average request time= {0} ms for Cluster overhead time={1} ms for {2} requests {3} filter requests {4} send requests {5} cross context requests (Request={6} ms Cluster={7} ms).
+SimpleTcpCluster.event.log=Cluster receive listener event {0} with data {1}
+SimpleTcpCluster.getProperty=get property {0}
+SimpleTcpCluster.setProperty=set property {0}: {1} old value {2}
+SimpleTcpCluster.default.addClusterListener=Add Default ClusterListener at cluster {0}
+SimpleTcpCluster.default.addClusterValves=Add Default ClusterValves at cluster {0}
+SimpleTcpCluster.default.addClusterReceiver=Add Default ClusterReceiver at cluster {0}
+SimpleTcpCluster.default.addClusterSender=Add Default ClusterSender at cluster {0}
+SimpleTcpCluster.default.addMembershipService=Add Default Membership Service at cluster {0}
+SimpleTcpCluster.log.receive=RECEIVE {0,date}:{0,time} {1,number} {2}:{3,number,integer} {4} {5}
+SimpleTcpCluster.log.send=SEND {0,date}:{0,time} {1,number} {2}:{3,number,integer} {4} 
+SimpleTcpCluster.log.send.all=SEND {0,date}:{0,time} {1,number} - {2}
+SocketReplictionListener.allreadyExists=ServerSocket [{0}:{1}] allready started!
+SocketReplictionListener.accept.failure=ServerSocket [{0}:{1}] - Exception to start thread or accept server socket
+SocketReplictionListener.open=Open Socket at [{0}:{1}]
+SocketReplictionListener.openclose.failure=ServerSocket [{0}:{1}] - Exception to open or close server socket
+SocketReplictionListener.portbusy=Port busy at [{0}:{i}] - reason [{2}]
+SocketReplictionListener.serverSocket.notExists=Fatal error: Receiver socket not bound address={0} port={1} maxport={2}
+SocketReplictionListener.timeout=Receiver ServerSocket no started [{0}:{1}] - reason: timeout={2} or listen={3}
+SocketReplictionListener.unlockSocket.failure=UnLocksocket failure at ServerSocket [{0:{1}]

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/transport/MultiPointSender.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/transport/MultiPointSender.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/transport/MultiPointSender.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,37 @@
+/*
+ * Copyright 1999,2006 The Apache Software Foundation.
+ * 
+ * Licensed 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.tribes.transport;
+import org.apache.catalina.tribes.ChannelMessage;
+import org.apache.catalina.tribes.ChannelException;
+import org.apache.catalina.tribes.Member;
+
+/**
+ * @author Filip Hanik
+ * @version $Revision: 303993 $ $Date: 2005-07-16 16:05:54 -0500 (Sat, 16 Jul 2005) $
+ * @since 5.5.16
+ */
+
+public interface MultiPointSender extends DataSender
+{
+    public void sendMessage(Member[] destination, ChannelMessage data) throws ChannelException;
+    public void setRxBufSize(int size);
+    public void setTxBufSize(int size);
+    public void setMaxRetryAttempts(int attempts);
+    public void setDirectBuffer(boolean directBuf);
+    public void memberAdded(Member member);
+    public void memberDisappeared(Member member);
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/transport/PooledSender.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/transport/PooledSender.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/transport/PooledSender.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,197 @@
+/*
+ * Copyright 1999,2004-2005 The Apache Software Foundation.
+ *
+ * Licensed 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.tribes.transport;
+
+import java.io.IOException;
+import java.util.List;
+
+/**
+ * <p>Title: </p>
+ *
+ * <p>Description: </p>
+ *
+ * <p>Copyright: Copyright (c) 2005</p>
+ *
+ * <p>Company: </p>
+ *
+ * @author not attributable
+ * @version 1.0
+ */
+public abstract class PooledSender extends AbstractSender implements MultiPointSender {
+    
+    private SenderQueue queue = null;
+    private int poolSize = 25;
+    public PooledSender() {
+        queue = new SenderQueue(this,poolSize);
+    }
+    
+    public abstract DataSender getNewDataSender();
+    
+    public DataSender getSender() {
+        return queue.getSender(getTimeout());
+    }
+    
+    public void returnSender(DataSender sender) {
+        sender.keepalive();
+        queue.returnSender(sender);
+    }
+    
+    public synchronized void connect() throws IOException {
+        //do nothing, happens in the socket sender itself
+        queue.open();
+        setConnected(true);
+    }
+    
+    public synchronized void disconnect() {
+        queue.close();
+        setConnected(false);
+    }
+    
+    
+    public int getInPoolSize() {
+        return queue.getInPoolSize();
+    }
+
+    public int getInUsePoolSize() {
+        return queue.getInUsePoolSize();
+    }
+
+
+    public void setPoolSize(int poolSize) {
+        this.poolSize = poolSize;
+        queue.setLimit(poolSize);
+    }
+
+    public int getPoolSize() {
+        return poolSize;
+    }
+
+    public boolean keepalive() {
+        //do nothing, the pool checks on every return
+        return false;
+    }
+
+    
+
+    //  ----------------------------------------------------- Inner Class
+
+    private class SenderQueue {
+        private int limit = 25;
+
+        PooledSender parent = null;
+
+        private List notinuse = null;
+
+        private List inuse = null;
+
+        private boolean isOpen = true;
+
+        public SenderQueue(PooledSender parent, int limit) {
+            this.limit = limit;
+            this.parent = parent;
+            notinuse = new java.util.LinkedList();
+            inuse = new java.util.LinkedList();
+        }
+
+        /**
+         * @return Returns the limit.
+         */
+        public int getLimit() {
+            return limit;
+        }
+        /**
+         * @param limit The limit to set.
+         */
+        public void setLimit(int limit) {
+            this.limit = limit;
+        }
+        /**
+         * @return
+         */
+        public int getInUsePoolSize() {
+            return inuse.size();
+        }
+
+        /**
+         * @return
+         */
+        public int getInPoolSize() {
+            return notinuse.size();
+        }
+
+        public synchronized DataSender getSender(long timeout) {
+            long start = System.currentTimeMillis();
+            while ( true ) {
+                if (!isOpen)throw new IllegalStateException("Queue is closed");
+                DataSender sender = null;
+                if (notinuse.size() == 0 && inuse.size() < limit) {
+                    sender = parent.getNewDataSender();
+                } else if (notinuse.size() > 0) {
+                    sender = (DataSender) notinuse.remove(0);
+                }
+                if (sender != null) {
+                    inuse.add(sender);
+                    return sender;
+                }//end if
+                long delta = System.currentTimeMillis() - start;
+                if ( delta > timeout && timeout>0) return null;
+                else {
+                    try {
+                        wait(Math.max(timeout - delta,1));
+                    }catch (InterruptedException x){}
+                }//end if
+            }
+        }
+
+        public synchronized void returnSender(DataSender sender) {
+            if ( !isOpen) {
+                sender.disconnect();
+                return;
+            }
+            //to do
+            inuse.remove(sender);
+            //just in case the limit has changed
+            if ( notinuse.size() < this.getLimit() ) notinuse.add(sender);
+            else try {sender.disconnect(); } catch ( Exception ignore){}
+            notify();
+        }
+
+        public synchronized void close() {
+            isOpen = false;
+            Object[] unused = notinuse.toArray();
+            Object[] used = inuse.toArray();
+            for (int i = 0; i < unused.length; i++) {
+                DataSender sender = (DataSender) unused[i];
+                sender.disconnect();
+            }//for
+            for (int i = 0; i < used.length; i++) {
+                DataSender sender = (DataSender) used[i];
+                sender.disconnect();
+            }//for
+            notinuse.clear();
+            inuse.clear();
+            notify();
+            
+
+
+        }
+
+        public synchronized void open() {
+            isOpen = true;
+            notify();
+        }
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/transport/ReceiverBase.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/transport/ReceiverBase.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/transport/ReceiverBase.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,383 @@
+/*
+ * Copyright 1999,2006 The Apache Software Foundation.
+ * 
+ * Licensed 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.tribes.transport;
+
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.ServerSocket;
+
+import org.apache.catalina.tribes.ChannelMessage;
+import org.apache.catalina.tribes.ChannelReceiver;
+import org.apache.catalina.tribes.MessageListener;
+import org.apache.catalina.tribes.io.ListenCallback;
+import org.apache.commons.logging.Log;
+
+/**
+ * <p>Title: </p>
+ *
+ * <p>Description: </p>
+ *
+ * <p>Copyright: Copyright (c) 2005</p>
+ *
+ * <p>Company: </p>
+ *
+ * @author not attributable
+ * @version 1.0
+ */
+public abstract class ReceiverBase implements ChannelReceiver, ListenCallback, ThreadPool.ThreadCreator {
+
+    public static final int OPTION_DIRECT_BUFFER = 0x0004;
+
+
+    protected static org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory.getLog(ReceiverBase.class);
+    
+    private MessageListener listener;
+    private String host = "auto";
+    private InetAddress bind;
+    private int port  = 4000;
+    private int rxBufSize = 43800;
+    private int txBufSize = 25188;
+    private boolean listen = false;
+    private ThreadPool pool;
+    private boolean direct = true;
+    private long tcpSelectorTimeout = 5000;
+    //how many times to search for an available socket
+    private int autoBind = 10;
+    private int maxThreads = 15;
+    private int minThreads = 6;
+    private boolean tcpNoDelay = true;
+    private boolean soKeepAlive = false;
+    private boolean ooBInline = true;
+    private boolean soReuseAddress = true;
+    private boolean soLingerOn = true;
+    private int soLingerTime = 3;
+    private int soTrafficClass = 0x04 | 0x08 | 0x010;
+    private int timeout = 3000; //3 seconds
+    private boolean useBufferPool = true;
+
+
+    public ReceiverBase() {
+    }
+    
+    /**
+     * getMessageListener
+     *
+     * @return MessageListener
+     * @todo Implement this org.apache.catalina.tribes.ChannelReceiver method
+     */
+    public MessageListener getMessageListener() {
+        return listener;
+    }
+
+    /**
+     *
+     * @return The port
+     * @todo Implement this org.apache.catalina.tribes.ChannelReceiver method
+     */
+    public int getPort() {
+        return port;
+    }
+
+    public int getRxBufSize() {
+        return rxBufSize;
+    }
+
+    public int getTxBufSize() {
+        return txBufSize;
+    }
+    
+    /**
+     * @deprecated use getMinThreads()/getMaxThreads()
+     * @return int
+     */
+    public int getTcpThreadCount() {
+        return getMinThreads();
+    }
+
+    /**
+     * setMessageListener
+     *
+     * @param listener MessageListener
+     * @todo Implement this org.apache.catalina.tribes.ChannelReceiver method
+     */
+    public void setMessageListener(MessageListener listener) {
+        this.listener = listener;
+    }
+
+    public void setTcpListenPort(int tcpListenPort) {
+        this.port = tcpListenPort;
+    }
+
+    public void setTcpListenAddress(String tcpListenHost) {
+        this.host = tcpListenHost;
+    }
+
+    public void setRxBufSize(int rxBufSize) {
+        this.rxBufSize = rxBufSize;
+    }
+
+    public void setTxBufSize(int txBufSize) {
+        this.txBufSize = txBufSize;
+    }
+
+    public void setTcpThreadCount(int tcpThreadCount) {
+        setMinThreads(tcpThreadCount);
+    }
+
+    /**
+     * @return Returns the bind.
+     */
+    public InetAddress getBind() {
+        if (bind == null) {
+            try {
+                if ("auto".equals(host)) {
+                    host = java.net.InetAddress.getLocalHost().getHostAddress();
+                }
+                if (log.isDebugEnabled())
+                    log.debug("Starting replication listener on address:"+ host);
+                bind = java.net.InetAddress.getByName(host);
+            } catch (IOException ioe) {
+                log.error("Failed bind replication listener on address:"+ host, ioe);
+            }
+        }
+        return bind;
+    }
+    
+    /**
+     * recursive bind to find the next available port
+     * @param socket ServerSocket
+     * @param portstart int
+     * @param retries int
+     * @return int
+     * @throws IOException
+     */
+    protected int bind(ServerSocket socket, int portstart, int retries) throws IOException {
+        InetSocketAddress addr = null;
+        while ( retries > 0 ) {
+            try {
+                addr = new InetSocketAddress(getBind(), portstart);
+                socket.bind(addr);
+                setTcpListenPort(portstart);
+                log.info("Receiver Server Socket bound to:"+addr);
+                return 0;
+            }catch ( IOException x) {
+                retries--;
+                if ( retries <= 0 ) {
+                    log.info("Unable to bind server socket to:"+addr+" throwing error.");
+                    throw x;
+                }
+                portstart++;
+                try {Thread.sleep(25);}catch( InterruptedException ti){Thread.currentThread().interrupted();}
+                retries = bind(socket,portstart,retries);
+            }
+        }
+        return retries;
+    }
+    
+    public void messageDataReceived(ChannelMessage data) {
+        if ( this.listener != null ) {
+            if ( listener.accept(data) ) listener.messageReceived(data);
+        }
+    }
+    
+    public int getWorkerThreadOptions() {
+        int options = 0;
+        if ( getDirect() ) options = options | OPTION_DIRECT_BUFFER;
+        return options;
+    }
+
+
+    /**
+     * @param bind The bind to set.
+     */
+    public void setBind(java.net.InetAddress bind) {
+        this.bind = bind;
+    }
+
+
+    public int getTcpListenPort() {
+        return this.port;
+    }
+
+    public boolean getDirect() {
+        return direct;
+    }
+
+
+
+    public void setDirect(boolean direct) {
+        this.direct = direct;
+    }
+
+
+
+    public String getHost() {
+        getBind();
+        return this.host;
+    }
+
+    public long getTcpSelectorTimeout() {
+        return tcpSelectorTimeout;
+    }
+
+    public boolean doListen() {
+        return listen;
+    }
+
+    public MessageListener getListener() {
+        return listener;
+    }
+
+    public ThreadPool getPool() {
+        return pool;
+    }
+
+    public String getTcpListenAddress() {
+        return getHost();
+    }
+
+    public int getAutoBind() {
+        return autoBind;
+    }
+
+    public int getMaxThreads() {
+        return maxThreads;
+    }
+
+    public int getMinThreads() {
+        return minThreads;
+    }
+
+    public boolean getTcpNoDelay() {
+        return tcpNoDelay;
+    }
+
+    public boolean getSoKeepAlive() {
+        return soKeepAlive;
+    }
+
+    public boolean getOoBInline() {
+        return ooBInline;
+    }
+
+
+    public boolean getSoLingerOn() {
+        return soLingerOn;
+    }
+
+    public int getSoLingerTime() {
+        return soLingerTime;
+    }
+
+    public boolean getSoReuseAddress() {
+        return soReuseAddress;
+    }
+
+    public int getSoTrafficClass() {
+        return soTrafficClass;
+    }
+
+    public int getTimeout() {
+        return timeout;
+    }
+
+    public boolean getUseBufferPool() {
+        return useBufferPool;
+    }
+
+    public void setTcpSelectorTimeout(long selTimeout) {
+        tcpSelectorTimeout = selTimeout;
+    }
+
+    public void setListen(boolean doListen) {
+        this.listen = doListen;
+    }
+
+    public void setHost(String host) {
+        this.host = host;
+    }
+
+    public void setListener(MessageListener listener) {
+        this.listener = listener;
+    }
+
+    public void setLog(Log log) {
+        this.log = log;
+    }
+
+    public void setPool(ThreadPool pool) {
+        this.pool = pool;
+    }
+
+    public void setPort(int port) {
+        this.port = port;
+    }
+
+    public void setAutoBind(int autoBind) {
+        this.autoBind = autoBind;
+        if ( this.autoBind <= 0 ) this.autoBind = 1;
+    }
+
+    public void setMaxThreads(int maxThreads) {
+        this.maxThreads = maxThreads;
+    }
+
+    public void setMinThreads(int minThreads) {
+        this.minThreads = minThreads;
+    }
+
+    public void setTcpNoDelay(boolean tcpNoDelay) {
+        this.tcpNoDelay = tcpNoDelay;
+    }
+
+    public void setSoKeepAlive(boolean soKeepAlive) {
+        this.soKeepAlive = soKeepAlive;
+    }
+
+    public void setOoBInline(boolean ooBInline) {
+        this.ooBInline = ooBInline;
+    }
+
+
+    public void setSoLingerOn(boolean soLingerOn) {
+        this.soLingerOn = soLingerOn;
+    }
+
+    public void setSoLingerTime(int soLingerTime) {
+        this.soLingerTime = soLingerTime;
+    }
+
+    public void setSoReuseAddress(boolean soReuseAddress) {
+        this.soReuseAddress = soReuseAddress;
+    }
+
+    public void setSoTrafficClass(int soTrafficClass) {
+        this.soTrafficClass = soTrafficClass;
+    }
+
+    public void setTimeout(int timeout) {
+        this.timeout = timeout;
+    }
+
+    public void setUseBufferPool(boolean useBufferPool) {
+        this.useBufferPool = useBufferPool;
+    }
+
+    public void heartbeat() {
+        //empty operation
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/transport/ReplicationTransmitter.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/transport/ReplicationTransmitter.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/transport/ReplicationTransmitter.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,134 @@
+/*
+ * Copyright 1999,2004-2005 The Apache Software Foundation.
+ * 
+ * Licensed 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.tribes.transport;
+
+import org.apache.catalina.tribes.ChannelException;
+import org.apache.catalina.tribes.ChannelMessage;
+import org.apache.catalina.tribes.ChannelSender;
+import org.apache.catalina.tribes.Member;
+import org.apache.catalina.tribes.util.StringManager;
+import org.apache.catalina.tribes.transport.nio.PooledParallelSender;
+
+/**
+ * Transmit message to other cluster members
+ * Actual senders are created based on the replicationMode
+ * type 
+ * 
+ * @author Filip Hanik
+ * @version $Revision: 379956 $ $Date: 2006-02-22 16:57:35 -0600 (Wed, 22 Feb 2006) $
+ */
+public class ReplicationTransmitter implements ChannelSender {
+    private static org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory.getLog(ReplicationTransmitter.class);
+
+    /**
+     * The descriptive information about this implementation.
+     */
+    private static final String info = "ReplicationTransmitter/3.0";
+
+    /**
+     * The string manager for this package.
+     */
+    protected StringManager sm = StringManager.getManager(Constants.Package);
+
+    
+
+    public ReplicationTransmitter() {
+    }
+
+    private MultiPointSender transport = new PooledParallelSender();
+
+    /**
+     * Return descriptive information about this implementation and the
+     * corresponding version number, in the format
+     * <code>&lt;description&gt;/&lt;version&gt;</code>.
+     */
+    public String getInfo() {
+        return (info);
+    }
+
+    public MultiPointSender getTransport() {
+        return transport;
+    }
+
+    public void setTransport(MultiPointSender transport) {
+        this.transport = transport;
+    }
+    
+    // ------------------------------------------------------------- public
+    
+    /**
+     * Send data to one member
+     * @see org.apache.catalina.tribes.ClusterSender#sendMessage(org.apache.catalina.tribes.ClusterMessage, org.apache.catalina.tribes.Member)
+     */
+    public void sendMessage(ChannelMessage message, Member[] destination) throws ChannelException {
+        MultiPointSender sender = getTransport();
+        sender.sendMessage(destination,message);
+    }
+    
+    
+    /**
+     * start the sender and register transmitter mbean
+     * 
+     * @see org.apache.catalina.tribes.ClusterSender#start()
+     */
+    public void start() throws java.io.IOException {
+        getTransport().connect();
+    }
+
+    /*
+     * stop the sender and deregister mbeans (transmitter, senders)
+     * 
+     * @see org.apache.catalina.tribes.ClusterSender#stop()
+     */
+    public synchronized void stop() {
+        getTransport().disconnect();
+    }
+
+    /**
+     * Call transmitter to check for sender socket status
+     * 
+     * @see SimpleTcpCluster#backgroundProcess()
+     */
+
+    public void heartbeat() {
+        
+    }
+
+    /**
+     * add new cluster member and create sender ( s. replicationMode) transfer
+     * current properties to sender
+     * 
+     * @see org.apache.catalina.tribes.ClusterSender#add(org.apache.catalina.tribes.Member)
+     */
+    public synchronized void add(Member member) {
+        getTransport().memberAdded(member);
+    }
+
+    /**
+     * remove sender from transmitter. ( deregister mbean and disconnect sender )
+     * 
+     * @see org.apache.catalina.tribes.ClusterSender#remove(org.apache.catalina.tribes.Member)
+     */
+    public synchronized void remove(Member member) {
+        getTransport().memberDisappeared(member);
+    }
+
+    // ------------------------------------------------------------- protected
+
+    
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/transport/SenderState.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/transport/SenderState.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/transport/SenderState.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,114 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tribes.transport;
+
+import org.apache.catalina.tribes.Member;
+import java.util.HashMap;
+
+
+/**
+ * 
+ * @author Filip Hanik
+ * @version 1.0
+ * @since 5.5.16
+ */
+
+public class SenderState {
+    
+    public static final int READY = 0;
+    public static final int SUSPECT = 1;
+    public static final int FAILING = 2;
+    /**
+     * The descriptive information about this implementation.
+     */
+    private static final String info = "SenderState/1.0";
+    
+    
+    protected static HashMap memberStates = new HashMap();
+    
+    public static SenderState getSenderState(Member member) {
+        return getSenderState(member,true);
+    }
+
+    public static SenderState getSenderState(Member member, boolean create) {
+        SenderState state = (SenderState)memberStates.get(member);
+        if ( state == null && create) {
+            synchronized ( memberStates ) {
+                state = (SenderState)memberStates.get(member);
+                if ( state == null ) {
+                    state = new SenderState();
+                    memberStates.put(member,state);
+                }
+            }
+        }
+        return state;
+    }
+    
+    public static void removeSenderState(Member member) {
+        synchronized ( memberStates ) {
+            memberStates.remove(member);
+        }
+    }
+    
+
+    // ----------------------------------------------------- Instance Variables
+
+    private int state = READY;
+
+    //  ----------------------------------------------------- Constructor
+
+    
+    private SenderState() {
+        this(READY);
+    }
+
+    private SenderState(int state) {
+        this.state = state;
+    }
+    
+    /**
+     * 
+     * @return boolean
+     */
+    public boolean isSuspect() {
+        return (state == SUSPECT) || (state == FAILING);
+    }
+
+    public void setSuspect() {
+        state = SUSPECT;
+    }
+    
+    public boolean isReady() {
+        return state == READY;
+    }
+    
+    public void setReady() {
+        state = READY;
+    }
+    
+    public boolean isFailing() {
+        return state == FAILING;
+    }
+    
+    public void setFailing() {
+        state = FAILING;
+    }
+    
+
+    //  ----------------------------------------------------- Public Properties
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/transport/ThreadPool.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/transport/ThreadPool.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/transport/ThreadPool.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,164 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tribes.transport;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * @author not attributable
+ * @version 1.0
+ */
+
+public class ThreadPool
+{
+    /**
+     * A very simple thread pool class.  The pool size is set at
+     * construction time and remains fixed.  Threads are cycled
+     * through a FIFO idle queue.
+     */
+
+    List idle = new LinkedList();
+    List used = new LinkedList();
+    
+    Object mutex = new Object();
+    boolean running = true;
+    
+    private static int counter = 1;
+    private int maxThreads;
+    private int minThreads;
+    
+    private ThreadCreator creator = null;
+
+    private static synchronized int inc() {
+        return counter++;
+    }
+
+    
+    public ThreadPool (int maxThreads, int minThreads, ThreadCreator creator) throws Exception {
+        // fill up the pool with worker threads
+        this.maxThreads = maxThreads;
+        this.minThreads = minThreads;
+        this.creator = creator;
+        //for (int i = 0; i < minThreads; i++) {
+        for (int i = 0; i < maxThreads; i++) { //temporary fix for thread hand off problem
+            WorkerThread thread = creator.getWorkerThread();
+            setupThread(thread);
+            idle.add (thread);
+        }
+    }
+    
+    protected void setupThread(WorkerThread thread) {
+        synchronized (thread) {
+            thread.setPool(this);
+            thread.setName(thread.getClass().getName() + "[" + inc() + "]");
+            thread.setDaemon(true);
+            thread.setPriority(Thread.MAX_PRIORITY);
+            thread.start();
+            try {thread.wait(500); }catch ( InterruptedException x ) {}
+        }
+    }
+
+    /**
+     * Find an idle worker thread, if any.  Could return null.
+     */
+    public WorkerThread getWorker()
+    {
+        WorkerThread worker = null;
+        synchronized (mutex) {
+            while ( worker == null && running ) {
+                if (idle.size() > 0) {
+                    try {
+                        worker = (WorkerThread) idle.remove(0);
+                    } catch (java.util.NoSuchElementException x) {
+                        //this means that there are no available workers
+                        worker = null;
+                    }
+                } else if ( used.size() < this.maxThreads && creator != null) {
+                    worker = creator.getWorkerThread();
+                    setupThread(worker);
+                } else {
+                    try { mutex.wait(); } catch ( java.lang.InterruptedException x ) {Thread.currentThread().interrupted();}
+                }
+            }//while
+            if ( worker != null ) used.add(worker);
+        }
+        return (worker);
+    }
+    
+    public int available() {
+        return idle.size();
+    }
+
+    /**
+     * Called by the worker thread to return itself to the
+     * idle pool.
+     */
+    public void returnWorker (WorkerThread worker) {
+        if ( running ) {
+            synchronized (mutex) {
+                used.remove(worker);
+                //if ( idle.size() < minThreads && !idle.contains(worker)) idle.add(worker);
+                if ( idle.size() < maxThreads && !idle.contains(worker)) idle.add(worker); //let max be the upper limit
+                else {
+                    worker.setDoRun(false);
+                    synchronized (worker){worker.notify();}
+                }
+                mutex.notify();
+            }
+        }else {
+            worker.setDoRun(false);
+            synchronized (worker){worker.notify();}
+        }
+    }
+
+    public int getMaxThreads() {
+        return maxThreads;
+    }
+
+    public int getMinThreads() {
+        return minThreads;
+    }
+
+    public void stop() {
+        running = false;
+        synchronized (mutex) {
+            Iterator i = idle.iterator();
+            while ( i.hasNext() ) {
+                WorkerThread worker = (WorkerThread)i.next();
+                returnWorker(worker);
+                i.remove();
+            }
+        }
+    }
+
+    public void setMaxThreads(int maxThreads) {
+        this.maxThreads = maxThreads;
+    }
+
+    public void setMinThreads(int minThreads) {
+        this.minThreads = minThreads;
+    }
+
+    public ThreadCreator getThreadCreator() {
+        return this.creator;
+    }
+    
+    public static interface ThreadCreator {
+        public WorkerThread getWorkerThread();
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/transport/WorkerThread.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/transport/WorkerThread.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/transport/WorkerThread.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,88 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tribes.transport;
+
+import org.apache.catalina.tribes.io.ListenCallback;
+
+
+
+
+/**
+ * @author Filip Hanik
+ * @version $Revision: 366253 $ $Date: 2006-01-05 13:30:42 -0600 (Thu, 05 Jan 2006) $
+ */
+public abstract class WorkerThread extends Thread 
+{
+    
+    public static final int OPTION_DIRECT_BUFFER = ReceiverBase.OPTION_DIRECT_BUFFER;
+    
+    private ListenCallback callback;
+    private ThreadPool pool;
+    private boolean doRun = true;
+    private int options;
+    protected boolean useBufferPool = true;
+
+    public WorkerThread(ListenCallback callback) {
+        this.callback = callback;
+    }
+
+    public void setPool(ThreadPool pool) {
+        this.pool = pool;
+    }
+
+    public void setOptions(int options) {
+        this.options = options;
+    }
+
+    public void setCallback(ListenCallback callback) {
+        this.callback = callback;
+    }
+
+    public void setDoRun(boolean doRun) {
+        this.doRun = doRun;
+    }
+
+    public ThreadPool getPool() {
+        return pool;
+    }
+
+    public int getOptions() {
+        return options;
+    }
+
+    public ListenCallback getCallback() {
+        return callback;
+    }
+
+    public boolean isDoRun() {
+        return doRun;
+    }
+
+    public void close()
+    {
+        doRun = false;
+        notify();
+    }
+    
+    public void setUseBufferPool(boolean usebufpool) {
+        useBufferPool = usebufpool;
+    }
+    
+    public boolean getUseBufferPool() {
+        return useBufferPool;
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/transport/bio/BioReceiver.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/transport/bio/BioReceiver.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/transport/bio/BioReceiver.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,160 @@
+/*
+ * Copyright 1999,2006 The Apache Software Foundation.
+ * 
+ * Licensed 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.tribes.transport.bio;
+
+import java.io.IOException;
+import java.net.ServerSocket;
+import java.net.Socket;
+
+import org.apache.catalina.tribes.ChannelReceiver;
+import org.apache.catalina.tribes.io.ListenCallback;
+import org.apache.catalina.tribes.io.ObjectReader;
+import org.apache.catalina.tribes.transport.ReceiverBase;
+import org.apache.catalina.tribes.transport.ThreadPool;
+import org.apache.catalina.tribes.transport.WorkerThread;
+
+/**
+ * <p>Title: </p>
+ *
+ * <p>Description: </p>
+ *
+ * <p>Copyright: Copyright (c) 2005</p>
+ *
+ * <p>Company: </p>
+ *
+ * @author not attributable
+ * @version 1.0
+ */
+public class BioReceiver extends ReceiverBase implements Runnable, ChannelReceiver, ListenCallback {
+
+    protected static org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory.getLog(BioReceiver.class);
+
+    protected ServerSocket serverSocket;
+
+    public BioReceiver() {
+    }
+
+    /**
+     *
+     * @throws IOException
+     * @todo Implement this org.apache.catalina.tribes.ChannelReceiver method
+     */
+    public void start() throws IOException {
+        try {
+            setPool(new ThreadPool(getMaxThreads(),getMinThreads(),this));
+        } catch (Exception x) {
+            log.fatal("ThreadPool can initilzed. Listener not started", x);
+            if ( x instanceof IOException ) throw (IOException)x;
+            else throw new IOException(x.getMessage());
+        }
+        try {
+            getBind();
+            bind();
+            Thread t = new Thread(this, "BioReceiver");
+            t.setDaemon(true);
+            t.start();
+        } catch (Exception x) {
+            log.fatal("Unable to start cluster receiver", x);
+            if ( x instanceof IOException ) throw (IOException)x;
+            else throw new IOException(x.getMessage());
+        }
+    }
+    
+    public WorkerThread getWorkerThread() {
+        return getReplicationThread();
+    }
+    
+    protected BioReplicationThread getReplicationThread() {
+        BioReplicationThread result = new BioReplicationThread(this);
+        result.setOptions(getWorkerThreadOptions());
+        result.setUseBufferPool(this.getUseBufferPool());
+        return result;
+    }
+
+    /**
+     *
+     * @todo Implement this org.apache.catalina.tribes.ChannelReceiver method
+     */
+    public void stop() {
+        setListen(false);
+        try {
+            this.serverSocket.close();
+        }catch ( Exception x ) {}
+    }
+
+    
+    
+    
+    protected void bind() throws IOException {
+        // allocate an unbound server socket channel
+        serverSocket = new ServerSocket();
+        // set the port the server channel will listen to
+        //serverSocket.bind(new InetSocketAddress(getBind(), getTcpListenPort()));
+        bind(serverSocket,getPort(),getAutoBind());
+    }
+    
+    
+    
+    public void run() {
+        try {
+            listen();
+        } catch (Exception x) {
+            log.error("Unable to run replication listener.", x);
+        }
+    }
+    
+    public void listen() throws Exception {
+        if (doListen()) {
+            log.warn("ServerSocket already started");
+            return;
+        }
+        setListen(true);
+
+        while ( doListen() ) {
+            Socket socket = null;
+            if ( getPool().available() < 1 ) {
+                if ( log.isWarnEnabled() )
+                    log.warn("All BIO server replication threads are busy, unable to handle more requests until a thread is freed up.");
+            }
+            BioReplicationThread thread = (BioReplicationThread)getPool().getWorker();
+            if ( thread == null ) continue; //should never happen
+            try {
+                socket = serverSocket.accept();
+            }catch ( Exception x ) {
+                if ( doListen() ) throw x;
+            }
+            if ( !doListen() ) {
+                thread.setDoRun(false);
+                thread.serviceSocket(null,null);
+                break; //regular shutdown
+            }
+            if ( socket == null ) continue;
+            socket.setReceiveBufferSize(getRxBufSize());
+            socket.setSendBufferSize(getRxBufSize());
+            socket.setTcpNoDelay(getTcpNoDelay());
+            socket.setKeepAlive(getSoKeepAlive());
+            socket.setOOBInline(getOoBInline());
+            socket.setReuseAddress(getSoReuseAddress());
+            socket.setSoLinger(getSoLingerOn(),getSoLingerTime());
+            socket.setTrafficClass(getSoTrafficClass());
+            socket.setSoTimeout(getTimeout());
+            ObjectReader reader = new ObjectReader(socket);
+            thread.serviceSocket(socket,reader);
+        }//while
+    }
+    
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/transport/bio/BioReplicationThread.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/transport/bio/BioReplicationThread.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/transport/bio/BioReplicationThread.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,180 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tribes.transport.bio;
+import java.io.IOException;
+
+import org.apache.catalina.tribes.io.ObjectReader;
+import org.apache.catalina.tribes.transport.Constants;
+import org.apache.catalina.tribes.transport.WorkerThread;
+import java.net.Socket;
+import java.io.InputStream;
+import org.apache.catalina.tribes.transport.ReceiverBase;
+import java.io.OutputStream;
+import org.apache.catalina.tribes.io.ListenCallback;
+import org.apache.catalina.tribes.ChannelMessage;
+import org.apache.catalina.tribes.io.ChannelData;
+import org.apache.catalina.tribes.io.BufferPool;
+
+/**
+ * A worker thread class which can drain channels and echo-back the input. Each
+ * instance is constructed with a reference to the owning thread pool object.
+ * When started, the thread loops forever waiting to be awakened to service the
+ * channel associated with a SelectionKey object. The worker is tasked by
+ * calling its serviceChannel() method with a SelectionKey object. The
+ * serviceChannel() method stores the key reference in the thread object then
+ * calls notify() to wake it up. When the channel has been drained, the worker
+ * thread returns itself to its parent pool.
+ * 
+ * @author Filip Hanik
+ * 
+ * @version $Revision: 378050 $, $Date: 2006-02-15 12:30:02 -0600 (Wed, 15 Feb 2006) $
+ */
+public class BioReplicationThread extends WorkerThread {
+
+
+    protected static org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory.getLog( BioReplicationThread.class );
+    
+    protected Socket socket;
+    protected ObjectReader reader;
+    
+    public BioReplicationThread (ListenCallback callback) {
+        super(callback);
+    }
+
+    // loop forever waiting for work to do
+    public synchronized void run()
+    {
+        this.notify();
+        while (isDoRun()) {
+            try {
+                // sleep and release object lock
+                this.wait();
+            } catch (InterruptedException e) {
+                if(log.isInfoEnabled())
+                    log.info("TCP worker thread interrupted in cluster",e);
+                // clear interrupt status
+                Thread.interrupted();
+            }
+            if ( socket == null ) continue;
+            try {
+                drainSocket();
+            } catch ( Exception x ) {
+                log.error("Unable to service bio socket");
+            }finally {
+                try {socket.close();}catch ( Exception ignore){}
+                try {reader.close();}catch ( Exception ignore){}
+                reader = null;
+                socket = null;
+            }
+            // done, ready for more, return to pool
+            if ( getPool() != null ) getPool().returnWorker (this);
+            else setDoRun(false);
+        }
+    }
+
+    
+    public synchronized void serviceSocket(Socket socket, ObjectReader reader) {
+        this.socket = socket;
+        this.reader = reader;
+        this.notify();		// awaken the thread
+    }
+    
+    protected void execute(ObjectReader reader) throws Exception{
+        int pkgcnt = reader.count();
+
+        if ( pkgcnt > 0 ) {
+            ChannelMessage[] msgs = reader.execute();
+            for ( int i=0; i<msgs.length; i++ ) {
+                /**
+                 * Use send ack here if you want to ack the request to the remote 
+                 * server before completing the request
+                 * This is considered an asynchronized request
+                 */
+                if (ChannelData.sendAckAsync(msgs[i].getOptions())) sendAck(Constants.ACK_COMMAND);
+                try {
+                    //process the message
+                    getCallback().messageDataReceived(msgs[i]);
+                    /**
+                     * Use send ack here if you want the request to complete on this
+                     * server before sending the ack to the remote server
+                     * This is considered a synchronized request
+                     */
+                    if (ChannelData.sendAckSync(msgs[i].getOptions())) sendAck(Constants.ACK_COMMAND);
+                }catch  ( Exception x ) {
+                    if (ChannelData.sendAckSync(msgs[i].getOptions())) sendAck(Constants.FAIL_ACK_COMMAND);
+                    log.error("Error thrown from messageDataReceived.",x);
+                }
+                if ( getUseBufferPool() ) {
+                    BufferPool.getBufferPool().returnBuffer(msgs[i].getMessage());
+                    msgs[i].setMessage(null);
+                }
+            }                       
+        }
+
+       
+    }
+
+    /**
+     * The actual code which drains the channel associated with
+     * the given key.  This method assumes the key has been
+     * modified prior to invocation to turn off selection
+     * interest in OP_READ.  When this method completes it
+     * re-enables OP_READ and calls wakeup() on the selector
+     * so the selector will resume watching this channel.
+     */
+    protected void drainSocket () throws Exception {
+        InputStream in = socket.getInputStream();
+        // loop while data available, channel is non-blocking
+        byte[] buf = new byte[1024];
+        int length = in.read(buf);
+        while ( length >= 0 ) {
+            int count = reader.append(buf,0,length,true);
+            if ( count > 0 ) execute(reader);
+            length = in.read(buf);
+        }
+    }
+
+
+
+
+    /**
+     * send a reply-acknowledgement (6,2,3)
+     * @param key
+     * @param channel
+     */
+    protected void sendAck(byte[] command) {
+        try {
+            OutputStream out = socket.getOutputStream();
+            out.write(command);
+            out.flush();
+            if (log.isTraceEnabled()) {
+                log.trace("ACK sent to " + socket.getPort());
+            }
+        } catch ( java.io.IOException x ) {
+            log.warn("Unable to send ACK back through channel, channel disconnected?: "+x.getMessage());
+        }
+    }
+    
+    public void close() {
+        setDoRun(false);
+        try {socket.close();}catch ( Exception ignore){}
+        try {reader.close();}catch ( Exception ignore){}
+        reader = null;
+        socket = null;
+        super.close();
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/transport/bio/BioSender.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/transport/bio/BioSender.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/transport/bio/BioSender.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,305 @@
+/*
+ * Copyright 1999,2006 The Apache Software Foundation.
+ * 
+ * Licensed 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.tribes.transport.bio;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.InetSocketAddress;
+import java.net.Socket;
+import java.net.UnknownHostException;
+import java.util.Arrays;
+
+import org.apache.catalina.tribes.Member;
+import org.apache.catalina.tribes.RemoteProcessException;
+import org.apache.catalina.tribes.io.XByteBuffer;
+import org.apache.catalina.tribes.transport.AbstractSender;
+import org.apache.catalina.tribes.transport.Constants;
+import org.apache.catalina.tribes.transport.DataSender;
+import org.apache.catalina.tribes.transport.SenderState;
+import org.apache.catalina.tribes.util.StringManager;
+
+/**
+ * Send cluster messages with only one socket. Ack and keep Alive Handling is
+ * supported
+ * 
+ * @author Peter Rossbach
+ * @author Filip Hanik
+ * @version $Revision: 377484 $ $Date: 2006-02-13 15:00:05 -0600 (Mon, 13 Feb 2006) $
+ * @since 5.5.16
+ */
+public class BioSender extends AbstractSender implements DataSender {
+
+    private static org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory.getLog(BioSender.class);
+
+    /**
+     * The string manager for this package.
+     */
+    protected static StringManager sm = StringManager.getManager(Constants.Package);
+
+    // ----------------------------------------------------- Instance Variables
+
+    /**
+     * The descriptive information about this implementation.
+     */
+    private static final String info = "DataSender/3.0";
+
+    
+    /**
+     * current sender socket
+     */
+    private Socket socket = null;
+    private OutputStream soOut = null;
+    private InputStream soIn = null;
+    
+    protected XByteBuffer ackbuf = new XByteBuffer(Constants.ACK_COMMAND.length,true);
+
+
+    // ------------------------------------------------------------- Constructor
+    
+    public BioSender()  {
+    }
+
+
+    // ------------------------------------------------------------- Properties
+
+    /**
+     * Return descriptive information about this implementation and the
+     * corresponding version number, in the format
+     * <code>&lt;description&gt;/&lt;version&gt;</code>.
+     */
+    public String getInfo() {
+        return (info);
+    }
+
+    // --------------------------------------------------------- Public Methods
+
+    /**
+     * Connect other cluster member receiver 
+     * @see org.apache.catalina.tribes.transport.IDataSender#connect()
+     */
+    public  void connect() throws IOException {
+        openSocket();
+   }
+
+ 
+    /**
+     * disconnect and close socket
+     * 
+     * @see IDataSender#disconnect()
+     */
+    public  void disconnect() {
+        boolean connect = isConnected();
+        closeSocket();
+        if (connect) {
+            if (log.isDebugEnabled())
+                log.debug(sm.getString("IDataSender.disconnect", getAddress().getHostAddress(), new Integer(getPort()), new Long(0)));
+        }
+        
+    }
+
+    /**
+     * Send message
+     * 
+     * @see org.apache.catalina.tribes.transport.IDataSender#sendMessage(,
+     *      ChannelMessage)
+     */
+    public  void sendMessage(byte[] data, boolean waitForAck) throws IOException {
+        boolean messageTransfered = false ;
+        IOException exception = null;
+        setAttempt(0);
+        try {
+             // first try with existing connection
+             pushMessage(data,false,waitForAck);
+             messageTransfered = true ;
+        } catch (IOException x) {
+            SenderState.getSenderState(getDestination()).setSuspect();
+            exception = x;
+            if (log.isTraceEnabled()) log.trace(sm.getString("IDataSender.send.again", getAddress().getHostAddress(),new Integer(getPort())),x);
+            while ( getAttempt()<getMaxRetryAttempts() ) {
+                try {
+                    setAttempt(getAttempt()+1);
+                    // second try with fresh connection
+                    pushMessage(data, true,waitForAck);
+                    messageTransfered = true;
+                    exception = null;
+                } catch (IOException xx) {
+                    exception = xx;
+                    closeSocket();
+                }
+            }
+        } finally {
+            setRequestCount(getRequestCount()+1);
+            keepalive();
+            if(messageTransfered) {
+
+            } else {
+                if ( exception != null ) throw exception;
+            }
+        }
+
+    }
+
+    
+    /**
+     * Name of this SockerSender
+     */
+    public String toString() {
+        StringBuffer buf = new StringBuffer("DataSender[(");
+        buf.append(super.toString()).append(")");
+        buf.append(getAddress()).append(":").append(getPort()).append("]");
+        return buf.toString();
+    }
+
+    // --------------------------------------------------------- Protected Methods
+ 
+    /**
+     * open real socket and set time out when waitForAck is enabled
+     * is socket open return directly
+     */
+    protected  void openSocket() throws IOException {
+       if(isConnected()) return ;
+       try {
+           socket = new Socket();
+           InetSocketAddress sockaddr = new InetSocketAddress(getAddress(), getPort());
+           socket.connect(sockaddr,(int)getTimeout());
+           socket.setSendBufferSize(getTxBufSize());
+           socket.setReceiveBufferSize(getRxBufSize());
+           socket.setSoTimeout( (int) getTimeout());
+           socket.setTcpNoDelay(getTcpNoDelay());
+           socket.setKeepAlive(getSoKeepAlive());
+           socket.setReuseAddress(getSoReuseAddress());
+           socket.setOOBInline(getOoBInline());
+           socket.setSoLinger(getSoLingerOn(),getSoLingerTime());
+           socket.setTrafficClass(getSoTrafficClass());
+           setConnected(true);
+           soOut = socket.getOutputStream();
+           soIn  = socket.getInputStream();
+           setRequestCount(0);
+           setConnectTime(System.currentTimeMillis());
+           if (log.isDebugEnabled())
+               log.debug(sm.getString("IDataSender.openSocket", getAddress().getHostAddress(), new Integer(getPort()), new Long(0)));
+      } catch (IOException ex1) {
+          SenderState.getSenderState(getDestination()).setSuspect();
+          if (log.isDebugEnabled())
+              log.debug(sm.getString("IDataSender.openSocket.failure",getAddress().getHostAddress(), new Integer(getPort()),new Long(0)), ex1);
+          throw (ex1);
+        }
+        
+     }
+
+    /**
+     * close socket
+     * 
+     * @see DataSender#disconnect()
+     * @see DataSender#closeSocket()
+     */
+    protected  void closeSocket() {
+        if(isConnected()) {
+             if (socket != null) {
+                try {
+                    socket.close();
+                } catch (IOException x) {
+                } finally {
+                    socket = null;
+                    soOut = null;
+                    soIn = null;
+                }
+            }
+            setRequestCount(0);
+            setConnected(false);
+            if (log.isDebugEnabled())
+                log.debug(sm.getString("IDataSender.closeSocket",getAddress().getHostAddress(), new Integer(getPort()),new Long(0)));
+       }
+    }
+
+    /**
+     * Push messages with only one socket at a time
+     * Wait for ack is needed and make auto retry when write message is failed.
+     * After sending error close and reopen socket again.
+     * 
+     * After successfull sending update stats
+     * 
+     * WARNING: Subclasses must be very carefull that only one thread call this pushMessage at once!!!
+     * 
+     * @see #closeSocket()
+     * @see #openSocket()
+     * @see #writeData(ChannelMessage)
+     * 
+     * @param data
+     *            data to send
+     * @since 5.5.10
+     */
+    
+    protected  void pushMessage(byte[] data, boolean reconnect, boolean waitForAck) throws IOException {
+        keepalive();
+        if ( reconnect ) closeSocket();
+        if (!isConnected()) openSocket();
+        soOut.write(data);
+        soOut.flush();
+        if (waitForAck) waitForAck();
+        SenderState.getSenderState(getDestination()).setReady();
+
+    }
+    
+    /**
+     * Wait for Acknowledgement from other server
+     * FIXME Please, not wait only for three charcters, better control that the wait ack message is correct.
+     * @param timeout
+     * @throws java.io.IOException
+     * @throws java.net.SocketTimeoutException
+     */
+    protected  void waitForAck() throws java.io.IOException {
+        try {
+            boolean ackReceived = false;
+            boolean failAckReceived = false;
+            ackbuf.clear();
+            int bytesRead = 0;
+            int i = soIn.read();
+            while ((i != -1) && (bytesRead < Constants.ACK_COMMAND.length)) {
+                bytesRead++;
+                byte d = (byte)i;
+                ackbuf.append(d);
+                if (ackbuf.doesPackageExist() ) {
+                    byte[] ackcmd = ackbuf.extractDataPackage(true).getBytes();
+                    ackReceived = Arrays.equals(ackcmd,org.apache.catalina.tribes.transport.Constants.ACK_DATA);
+                    failAckReceived = Arrays.equals(ackcmd,org.apache.catalina.tribes.transport.Constants.FAIL_ACK_DATA);
+                    ackReceived = ackReceived || failAckReceived;
+                    break;
+                }
+                i = soIn.read();
+            }
+            if (!ackReceived) {
+                if (i == -1) throw new IOException(sm.getString("IDataSender.ack.eof",getAddress(), new Integer(socket.getLocalPort())));
+                else throw new IOException(sm.getString("IDataSender.ack.wrong",getAddress(), new Integer(socket.getLocalPort())));
+            } else if ( failAckReceived && getThrowOnFailedAck()) {
+                throw new RemoteProcessException("Received a failed ack:org.apache.catalina.tribes.transport.Constants.FAIL_ACK_DATA");
+            }
+        } catch (IOException x) {
+            String errmsg = sm.getString("IDataSender.ack.missing", getAddress(),new Integer(socket.getLocalPort()), new Long(getTimeout()));
+            if ( SenderState.getSenderState(getDestination()).isReady() ) {
+                SenderState.getSenderState(getDestination()).setSuspect();
+                if ( log.isWarnEnabled() ) log.warn(errmsg, x);
+            } else {
+                if ( log.isDebugEnabled() )log.debug(errmsg, x);
+            }
+            throw x;
+        } finally {
+            ackbuf.clear();
+        }
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/transport/bio/MultipointBioSender.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/transport/bio/MultipointBioSender.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/transport/bio/MultipointBioSender.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,134 @@
+package org.apache.catalina.tribes.transport.bio;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.catalina.tribes.ChannelException;
+import org.apache.catalina.tribes.ChannelMessage;
+import org.apache.catalina.tribes.Member;
+import org.apache.catalina.tribes.io.ChannelData;
+import org.apache.catalina.tribes.io.XByteBuffer;
+import org.apache.catalina.tribes.transport.MultiPointSender;
+import org.apache.catalina.tribes.transport.AbstractSender;
+import org.apache.catalina.tribes.Channel;
+
+/**
+ * <p>Title: </p>
+ *
+ * <p>Description: </p>
+ *
+ * <p>Copyright: Copyright (c) 2005</p>
+ *
+ * <p>Company: </p>
+ *
+ * @author not attributable
+ * @version 1.0
+ */
+public class MultipointBioSender extends AbstractSender implements MultiPointSender {
+    public MultipointBioSender() {
+    }
+    
+    protected long selectTimeout = 1000; 
+    protected HashMap bioSenders = new HashMap();
+    private boolean autoConnect;
+
+    public synchronized void sendMessage(Member[] destination, ChannelMessage msg) throws ChannelException {
+        byte[] data = XByteBuffer.createDataPackage((ChannelData)msg);
+        BioSender[] senders = setupForSend(destination);
+        ChannelException cx = null;
+        for ( int i=0; i<senders.length; i++ ) {
+            try {
+                senders[i].sendMessage(data,(msg.getOptions()&Channel.SEND_OPTIONS_USE_ACK)==Channel.SEND_OPTIONS_USE_ACK);
+            } catch (Exception x) {
+                if (cx == null) cx = new ChannelException(x);
+                cx.addFaultyMember(destination[i],x);
+            }
+        }
+        if (cx!=null ) throw cx;
+    }
+
+
+
+    protected BioSender[] setupForSend(Member[] destination) throws ChannelException {
+        ChannelException cx = null;
+        BioSender[] result = new BioSender[destination.length];
+        for ( int i=0; i<destination.length; i++ ) {
+            try {
+                BioSender sender = (BioSender) bioSenders.get(destination[i]);
+                if (sender == null) {
+                    sender = new BioSender();
+                    sender.transferProperties(this,sender);
+                    sender.setDestination(destination[i]);
+                    bioSenders.put(destination[i], sender);
+                }
+                result[i] = sender;
+                if (!result[i].isConnected() ) result[i].connect();
+                result[i].keepalive();
+            }catch (Exception x ) {
+                if ( cx== null ) cx = new ChannelException(x);
+                cx.addFaultyMember(destination[i],x);
+            }
+        }
+        if ( cx!=null ) throw cx;
+        else return result;
+    }
+
+    public void connect() throws IOException {
+        //do nothing, we connect on demand
+        setConnected(true);
+    }
+
+
+    private synchronized void close() throws ChannelException  {
+        ChannelException x = null;
+        Object[] members = bioSenders.keySet().toArray();
+        for (int i=0; i<members.length; i++ ) {
+            Member mbr = (Member)members[i];
+            try {
+                BioSender sender = (BioSender)bioSenders.get(mbr);
+                sender.disconnect();
+            }catch ( Exception e ) {
+                if ( x == null ) x = new ChannelException(e);
+                x.addFaultyMember(mbr,e);
+            }
+            bioSenders.remove(mbr);
+        }
+        if ( x != null ) throw x;
+    }
+
+    public void memberAdded(Member member) {
+
+    }
+
+    public void memberDisappeared(Member member) {
+        //disconnect senders
+        BioSender sender = (BioSender)bioSenders.remove(member);
+        if ( sender != null ) sender.disconnect();
+    }
+
+
+    public synchronized void disconnect() {
+        try {close(); }catch (Exception x){}
+        setConnected(false);
+    }
+
+    public void finalize() {
+        try {disconnect(); }catch ( Exception ignore){}
+    }
+
+
+    public boolean keepalive() {
+        //throw new UnsupportedOperationException("Method ParallelBioSender.checkKeepAlive() not implemented");
+        boolean result = false;
+        Map.Entry[] entries = (Map.Entry[])bioSenders.entrySet().toArray(new Map.Entry[bioSenders.size()]);
+        for ( int i=0; i<entries.length; i++ ) {
+            BioSender sender = (BioSender)entries[i].getValue();
+            if ( sender.keepalive() ) {
+                bioSenders.remove(entries[i].getKey());
+            }
+        }
+        return result;
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/transport/bio/PooledMultiSender.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/transport/bio/PooledMultiSender.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/transport/bio/PooledMultiSender.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,67 @@
+package org.apache.catalina.tribes.transport.bio;
+
+import org.apache.catalina.tribes.transport.DataSender;
+import org.apache.catalina.tribes.transport.PooledSender;
+import org.apache.catalina.tribes.Member;
+import org.apache.catalina.tribes.ChannelException;
+import org.apache.catalina.tribes.transport.MultiPointSender;
+import org.apache.catalina.tribes.ChannelMessage;
+
+/**
+ * <p>Title: </p>
+ *
+ * <p>Description: </p>
+ *
+ * <p>Copyright: Copyright (c) 2005</p>
+ *
+ * <p>Company: </p>
+ *
+ * @author not attributable
+ * @version 1.0
+ */
+public class PooledMultiSender extends PooledSender {
+    
+
+    public PooledMultiSender() {
+    }
+    
+    public void sendMessage(Member[] destination, ChannelMessage msg) throws ChannelException {
+        MultiPointSender sender = null;
+        try {
+            sender = (MultiPointSender)getSender();
+            if (sender == null) {
+                ChannelException cx = new ChannelException("Unable to retrieve a data sender, time out error.");
+                for (int i = 0; i < destination.length; i++) cx.addFaultyMember(destination[i], new NullPointerException("Unable to retrieve a sender from the sender pool"));
+                throw cx;
+            } else {
+                sender.sendMessage(destination, msg);
+            }
+            sender.keepalive();
+        }finally {
+            if ( sender != null ) returnSender(sender);
+        }
+    }
+
+    /**
+     * getNewDataSender
+     *
+     * @return DataSender
+     * @todo Implement this org.apache.catalina.tribes.transport.PooledSender
+     *   method
+     */
+    public DataSender getNewDataSender() {
+        MultipointBioSender sender = new MultipointBioSender();
+        sender.transferProperties(this,sender);
+        return sender;
+    }
+
+
+    public void memberAdded(Member member) {
+
+    }
+
+    public void memberDisappeared(Member member) {
+        //disconnect senders
+    } 
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/transport/bio/util/FastQueue.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/transport/bio/util/FastQueue.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/transport/bio/util/FastQueue.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,393 @@
+/*
+ * Copyright 1999,2004-2005 The Apache Software Foundation.
+ * 
+ * Licensed 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.tribes.transport.bio.util;
+
+import org.apache.catalina.tribes.ChannelMessage;
+import org.apache.catalina.tribes.ErrorHandler;
+import org.apache.catalina.tribes.Member;
+import org.apache.catalina.tribes.group.InterceptorPayload;
+
+
+
+/**
+ * A fast queue that remover thread lock the adder thread. <br/>Limit the queue
+ * length when you have strange producer thread problemes.
+ * 
+ * FIXME add i18n support to log messages
+ * @author Rainer Jung
+ * @author Peter Rossbach
+ * @version $Revision: 345567 $ $Date: 2005-11-18 15:07:23 -0600 (Fri, 18 Nov 2005) $
+ */
+public class FastQueue {
+
+    private static org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory.getLog(FastQueue.class);
+
+    /**
+     * This is the actual queue
+     */
+    private SingleRemoveSynchronizedAddLock lock = null;
+
+    /**
+     * First Object at queue (consumer message)
+     */
+    private LinkObject first = null;
+
+    /**
+     * Last object in queue (producer Object)
+     */
+    private LinkObject last = null;
+
+    /**
+     * Current Queue elements size
+     */
+    private int size = 0;
+
+    /**
+     * check lock to detect strange threadings things
+     */
+    private boolean checkLock = false;
+
+    /**
+     * protocol the thread wait times
+     */
+    private boolean timeWait = false;
+
+    private boolean inAdd = false;
+
+    private boolean inRemove = false;
+
+    private boolean inMutex = false;
+
+    /**
+     * limit the queue legnth ( default is unlimited)
+     */
+    private int maxQueueLength = 0;
+
+    /**
+     * addWaitTimeout for producer
+     */
+    private long addWaitTimeout = 10000L;
+
+    
+    /**
+     * removeWaitTimeout for consumer
+     */
+    private long removeWaitTimeout = 30000L;
+
+    /**
+     * enabled the queue
+     */
+    private boolean enabled = true;
+
+    /**
+     *  max queue size
+     */
+    private int maxSize = 0;
+
+    /**
+     *  avg size sample interval
+     */
+    private int sampleInterval = 100;
+
+    /**
+     * Generate Queue SingleRemoveSynchronizedAddLock and set add and wait
+     * Timeouts
+     */
+    public FastQueue() {
+        lock = new SingleRemoveSynchronizedAddLock();
+        lock.setAddWaitTimeout(addWaitTimeout);
+        lock.setRemoveWaitTimeout(removeWaitTimeout);
+    }
+
+    /**
+     * get current add wait timeout
+     * 
+     * @return current wait timeout
+     */
+    public long getAddWaitTimeout() {
+        addWaitTimeout = lock.getAddWaitTimeout();
+        return addWaitTimeout;
+    }
+
+    /**
+     * Set add wait timeout (default 10000 msec)
+     * 
+     * @param timeout
+     */
+    public void setAddWaitTimeout(long timeout) {
+        addWaitTimeout = timeout;
+        lock.setAddWaitTimeout(addWaitTimeout);
+    }
+
+    /**
+     * get current remove wait timeout
+     * 
+     * @return The timeout
+     */
+    public long getRemoveWaitTimeout() {
+        removeWaitTimeout = lock.getRemoveWaitTimeout();
+        return removeWaitTimeout;
+    }
+
+    /**
+     * set remove wait timeout ( default 30000 msec)
+     * 
+     * @param timeout
+     */
+    public void setRemoveWaitTimeout(long timeout) {
+        removeWaitTimeout = timeout;
+        lock.setRemoveWaitTimeout(removeWaitTimeout);
+    }
+
+    /**
+     * get Max Queue length
+     * 
+     * @see org.apache.catalina.tribes.util.IQueue#getMaxQueueLength()
+     */
+    public int getMaxQueueLength() {
+        return maxQueueLength;
+    }
+
+    public void setMaxQueueLength(int length) {
+        maxQueueLength = length;
+    }
+
+    public boolean isEnabled() {
+        return enabled;
+    }
+
+    public void setEnabled(boolean enable) {
+        enabled = enable;
+        if (!enabled) {
+            lock.abortRemove();
+            last = first = null;
+        }
+    }
+
+    /**
+     * @return Returns the checkLock.
+     */
+    public boolean isCheckLock() {
+        return checkLock;
+    }
+
+    /**
+     * @param checkLock The checkLock to set.
+     */
+    public void setCheckLock(boolean checkLock) {
+        this.checkLock = checkLock;
+    }
+
+    
+    /**
+     * @return The max size
+     */
+    public int getMaxSize() {
+        return maxSize;
+    }
+
+    /**
+     * @param size
+     */
+    public void setMaxSize(int size) {
+        maxSize = size;
+    }
+
+    
+    /**
+     * unlock queue for next add 
+     */
+    public void unlockAdd() {
+        lock.unlockAdd(size > 0 ? true : false);
+    }
+
+    /**
+     * unlock queue for next remove 
+     */
+    public void unlockRemove() {
+        lock.unlockRemove();
+    }
+
+    /**
+     * start queuing
+     */
+    public void start() {
+        setEnabled(true);
+    }
+
+    /**
+     * start queuing
+     */
+    public void stop() {
+        setEnabled(false);
+    }
+
+    public int getSize() {
+        return size;
+    }
+
+    public SingleRemoveSynchronizedAddLock getLock() {
+        return lock;
+    }
+
+    /**
+     * Add new data to the queue
+     * @see org.apache.catalina.tribes.util.IQueue#add(java.lang.String, java.lang.Object)
+     * FIXME extract some method
+     */
+    public boolean add(ChannelMessage msg, Member[] destination, InterceptorPayload payload) {
+        boolean ok = true;
+        long time = 0;
+
+        if (!enabled) {
+            if (log.isInfoEnabled())
+                log.info("FastQueue.add: queue disabled, add aborted");
+            return false;
+        }
+
+        if (timeWait) {
+            time = System.currentTimeMillis();
+        }
+        lock.lockAdd();
+        try {
+            if (log.isTraceEnabled()) {
+                log.trace("FastQueue.add: starting with size " + size);
+            }
+            if (checkLock) {
+                if (inAdd)
+                    log.warn("FastQueue.add: Detected other add");
+                inAdd = true;
+                if (inMutex)
+                    log.warn("FastQueue.add: Detected other mutex in add");
+                inMutex = true;
+            }
+
+            if ((maxQueueLength > 0) && (size >= maxQueueLength)) {
+                ok = false;
+                if (log.isTraceEnabled()) {
+                    log.trace("FastQueue.add: Could not add, since queue is full (" + size + ">=" + maxQueueLength + ")");
+                }
+            } else {
+                LinkObject element = new LinkObject(msg,destination, payload);
+                if (size == 0) {
+                    first = last = element;
+                    size = 1;
+                } else {
+                    if (last == null) {
+                        ok = false;
+                        log.error("FastQueue.add: Could not add, since last is null although size is "+ size + " (>0)");
+                    } else {
+                        last.append(element);
+                        last = element;
+                        size++;
+                    }
+                }
+            }
+
+            if (first == null) {
+                log.error("FastQueue.add: first is null, size is " + size + " at end of add");
+            }
+            if (last == null) {
+                log.error("FastQueue.add: last is null, size is " + size+ " at end of add");
+            }
+
+            if (checkLock) {
+                if (!inMutex) log.warn("FastQueue.add: Cancelled by other mutex in add");
+                inMutex = false;
+                if (!inAdd) log.warn("FastQueue.add: Cancelled by other add");
+                inAdd = false;
+            }
+            if (log.isTraceEnabled()) log.trace("FastQueue.add: add ending with size " + size);
+
+        } finally {
+            lock.unlockAdd(true);
+        }
+        return ok;
+    }
+
+    /**
+     * remove the complete queued object list
+     * @see org.apache.catalina.tribes.util.IQueue#remove()
+     * FIXME extract some method
+     */
+    public LinkObject remove() {
+        LinkObject element;
+        boolean gotLock;
+        long time = 0;
+
+        if (!enabled) {
+            if (log.isInfoEnabled())
+                log.info("FastQueue.remove: queue disabled, remove aborted");
+            return null;
+        }
+
+        if (timeWait) {
+            time = System.currentTimeMillis();
+        }
+        gotLock = lock.lockRemove();
+        try {
+
+            if (!gotLock) {
+                if (enabled) {
+                    if (log.isInfoEnabled())
+                        log.info("FastQueue.remove: Remove aborted although queue enabled");
+                } else {
+                    if (log.isInfoEnabled())
+                        log.info("FastQueue.remove: queue disabled, remove aborted");
+                }
+                return null;
+            }
+
+            if (log.isTraceEnabled()) {
+                log.trace("FastQueue.remove: remove starting with size " + size);
+            }
+            if (checkLock) {
+                if (inRemove)
+                    log.warn("FastQueue.remove: Detected other remove");
+                inRemove = true;
+                if (inMutex)
+                    log.warn("FastQueue.remove: Detected other mutex in remove");
+                inMutex = true;
+            }
+
+            element = first;
+
+            first = last = null;
+            size = 0;
+
+            if (checkLock) {
+                if (!inMutex)
+                    log.warn("FastQueue.remove: Cancelled by other mutex in remove");
+                inMutex = false;
+                if (!inRemove)
+                    log.warn("FastQueue.remove: Cancelled by other remove");
+                inRemove = false;
+            }
+            if (log.isTraceEnabled()) {
+                log.trace("FastQueue.remove: remove ending with size " + size);
+            }
+
+            if (timeWait) {
+                time = System.currentTimeMillis();
+            }
+        } finally {
+            lock.unlockRemove();
+        }
+        return element;
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/transport/bio/util/LinkObject.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/transport/bio/util/LinkObject.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/transport/bio/util/LinkObject.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,107 @@
+/*
+ * Copyright 1999,2004-2005 The Apache Software Foundation.
+ * 
+ * Licensed 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.tribes.transport.bio.util;
+
+import org.apache.catalina.tribes.ChannelMessage;
+import org.apache.catalina.tribes.ErrorHandler;
+import org.apache.catalina.tribes.Member;
+import org.apache.catalina.tribes.group.InterceptorPayload;
+
+/**
+ * The class <b>LinkObject</b> implements an element
+ * for a linked list, consisting of a general
+ * data object and a pointer to the next element.
+ *
+ * @author Rainer Jung
+ * @author Peter Rossbach
+ * @author Filip Hanik
+ * @version $Revision: 304032 $ $Date: 2005-07-27 10:11:55 -0500 (Wed, 27 Jul 2005) $
+
+ */
+
+public class LinkObject {
+
+    private ChannelMessage msg;
+    private LinkObject next;
+    private byte[] key ;
+    private Member[] destination;
+    private InterceptorPayload payload;
+
+    /**
+     * Construct a new element from the data object.
+     * Sets the pointer to null.
+     *
+     * @param key The key
+     * @param payload The data object.
+     */
+    public LinkObject(ChannelMessage msg, Member[] destination, InterceptorPayload payload) {
+        this.msg = msg;
+        this.next = null;
+        this.key = msg.getUniqueId();
+        this.payload = payload;
+        this.destination = destination;
+    }
+
+    /**
+     * Set the next element.
+     * @param next The next element.
+     */
+    public void append(LinkObject next) {
+        this.next = next;
+    }
+
+    /**
+     * Get the next element.
+     * @return The next element.
+     */
+    public LinkObject next() {
+        return next;
+    }
+    
+    public void setNext(LinkObject next) {
+        this.next = next;
+    }
+
+    /**
+     * Get the data object from the element.
+     * @return The data object from the element.
+     */
+    public ChannelMessage data() {
+        return msg;
+    }
+
+    /**
+     * Get the unique message id
+     * @return the unique message id
+     */
+    public byte[] getKey() {
+        return key;
+    }
+
+    public ErrorHandler getHandler() {
+        return payload!=null?payload.getErrorHandler():null;
+    }
+
+    public InterceptorPayload getPayload() {
+        return payload;
+    }
+
+    public Member[] getDestination() {
+        return destination;
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/transport/bio/util/SingleRemoveSynchronizedAddLock.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/transport/bio/util/SingleRemoveSynchronizedAddLock.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/transport/bio/util/SingleRemoveSynchronizedAddLock.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,253 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tribes.transport.bio.util;
+
+/**
+ * The class <b>SingleRemoveSynchronizedAddLock</b> implement locking for accessing the queue
+ * by a single remove thread and multiple add threads.
+ *
+ * A thread is only allowed to be either the remove or
+ * an add thread.
+ *
+ * The lock can either be owned by the remove thread
+ * or by a single add thread.
+ *
+ * If the remove thread tries to get the lock,
+ * but the queue is empty, it will block (poll)
+ * until an add threads adds an entry to the queue and
+ * releases the lock.
+ * 
+ * If the remove thread and add threads compete for
+ * the lock and an add thread releases the lock, then
+ * the remove thread will get the lock first.
+ *
+ * The remove thread removes all entries in the queue
+ * at once and proceeses them without further
+ * polling the queue.
+ *
+ * The lock is not reentrant, in the sense, that all
+ * threads must release an owned lock before competing
+ * for the lock again!
+ *
+ * @author Rainer Jung
+ * @author Peter Rossbach
+ * @version 1.1
+ */
+ 
+public class SingleRemoveSynchronizedAddLock {
+    
+    public SingleRemoveSynchronizedAddLock() {
+    }
+    
+    public SingleRemoveSynchronizedAddLock(boolean dataAvailable) {
+        this.dataAvailable=dataAvailable;
+    }
+    
+    /**
+     * Time in milliseconds after which threads
+     * waiting for an add lock are woken up.
+     * This is used as a safety measure in case
+     * thread notification via the unlock methods
+     * has a bug.
+     */
+    private long addWaitTimeout = 10000L;
+
+    /**
+     * Time in milliseconds after which threads
+     * waiting for a remove lock are woken up.
+     * This is used as a safety measure in case
+     * thread notification via the unlock methods
+     * has a bug.
+     */
+    private long removeWaitTimeout = 30000L;
+
+    /**
+     * The current remove thread.
+     * It is set to the remove thread polling for entries.
+     * It is reset to null when the remove thread
+     * releases the lock and proceeds processing
+     * the removed entries.
+     */
+    private Thread remover = null;
+
+    /**
+     * A flag indicating, if an add thread owns the lock.
+     */
+    private boolean addLocked = false;
+
+    /**
+     * A flag indicating, if the remove thread owns the lock.
+     */
+    private boolean removeLocked = false;
+
+    /**
+     * A flag indicating, if the remove thread is allowed
+     * to wait for the lock. The flag is set to false, when aborting.
+     */
+    private boolean removeEnabled = true;
+
+    /**
+     * A flag indicating, if the remover needs polling.
+     * It indicates, if the locked object has data available
+     * to be removed.
+     */
+    private boolean dataAvailable = false;
+
+    /**
+     * @return Value of addWaitTimeout
+     */
+    public synchronized long getAddWaitTimeout() {
+        return addWaitTimeout;
+    }
+
+    /**
+     * Set value of addWaitTimeout
+     */
+    public synchronized void setAddWaitTimeout(long timeout) {
+        addWaitTimeout = timeout;
+    }
+
+    /**
+     * @return Value of removeWaitTimeout
+     */
+    public synchronized long getRemoveWaitTimeout() {
+        return removeWaitTimeout;
+    }
+
+    /**
+     * Set value of removeWaitTimeout
+     */
+    public synchronized void setRemoveWaitTimeout(long timeout) {
+        removeWaitTimeout = timeout;
+    }
+
+    /**
+     * Check if the locked object has data available
+     * i.e. the remover can stop poling and get the lock.
+     * @return True iff the lock Object has data available.
+     */
+    public synchronized boolean isDataAvailable() {
+        return dataAvailable;
+    }
+
+    /**
+     * Check if an add thread owns the lock.
+     * @return True iff an add thread owns the lock.
+     */
+    public synchronized boolean isAddLocked() {
+        return addLocked;
+    }
+
+    /**
+     * Check if the remove thread owns the lock.
+     * @return True iff the remove thread owns the lock.
+     */
+    public synchronized boolean isRemoveLocked() {
+        return removeLocked;
+    }
+
+    /**
+     * Check if the remove thread is polling.
+     * @return True iff the remove thread is polling.
+     */
+    public synchronized boolean isRemovePolling() {
+        if ( remover != null ) {
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Acquires the lock by an add thread and sets the add flag.
+     * If any add thread or the remove thread already acquired the lock
+     * this add thread will block until the lock is released.
+     */
+    public synchronized void lockAdd() {
+        if ( addLocked || removeLocked ) {
+            do {
+                try {
+                    wait(addWaitTimeout);
+                } catch ( InterruptedException e ) {
+                    Thread.currentThread().interrupted();
+                }
+            } while ( addLocked || removeLocked );
+        }
+        addLocked=true;
+    }
+
+    /**
+     * Acquires the lock by the remove thread and sets the remove flag.
+     * If any add thread already acquired the lock or the queue is
+     * empty, the remove thread will block until the lock is released
+     * and the queue is not empty.
+     */
+    public synchronized boolean lockRemove() {
+        removeLocked=false;
+        removeEnabled=true;
+        if ( ( addLocked || ! dataAvailable ) && removeEnabled ) {
+            remover=Thread.currentThread();
+            do {
+                try {
+                    wait(removeWaitTimeout);
+                } catch ( InterruptedException e ) {
+                    Thread.currentThread().interrupted();
+                }
+            } while ( ( addLocked || ! dataAvailable ) && removeEnabled );
+            remover=null;
+        }
+        if ( removeEnabled ) {
+            removeLocked=true;
+        } 
+        return removeLocked;
+    }
+
+    /**
+     * Releases the lock by an add thread and reset the remove flag.
+     * If the reader thread is polling, notify it.
+     */
+    public synchronized void unlockAdd(boolean dataAvailable) {
+        addLocked=false;
+        this.dataAvailable=dataAvailable;
+        if ( ( remover != null ) && ( dataAvailable || ! removeEnabled ) ) {
+            remover.interrupt();
+        } else {
+            notifyAll();
+        }
+    }
+
+    /**
+     * Releases the lock by the remove thread and reset the add flag.
+     * Notify all waiting add threads,
+     * that the lock has been released by the remove thread.
+     */
+    public synchronized void unlockRemove() {
+        removeLocked=false;
+        dataAvailable=false;
+        notifyAll();
+    }
+
+    /**
+     * Abort any polling remover thread
+     */
+    public synchronized void abortRemove() {
+        removeEnabled=false;
+        if ( remover != null ) {
+            remover.interrupt();
+        }
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/transport/mbeans-descriptors.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/transport/mbeans-descriptors.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/transport/mbeans-descriptors.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,835 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mbeans-descriptors PUBLIC
+   "-//Apache Software Foundation//DTD Model MBeans Configuration File"
+   "http://jakarta.apache.org/commons/dtds/mbeans-descriptors.dtd">
+<mbeans-descriptors>
+
+  <mbean         name="SimpleTcpCluster"
+           description="Tcp Cluster implementation"
+               domain="Catalina"
+                group="Cluster"
+                 type="org.apache.catalina.cluster.tcp.SimpleTcpCluster">
+    <attribute   name="info"
+          description="Class version info"
+                 type="java.lang.String"
+                 writeable="false"/>
+    <attribute   name="notifyLifecycleListenerOnFailure"
+          description="notify lifecycleListener from message transfer failure"
+			     is="true"
+                 type="boolean"/>                 
+    <attribute   name="clusterName"
+          description="name of cluster"
+                 type="java.lang.String"/>
+    <attribute   name="managerClassName"
+          description="session mananager classname"
+                 type="java.lang.String"/>
+    <attribute   name="clusterLogName"
+          description="Name of cluster transfer log device"
+                 type="java.lang.String"/>
+    <attribute   name="doClusterLog"
+			     is="true"
+          description="enable cluster log transfer logging"
+                 type="boolean"/>
+    <operation   name="setProperty"
+               description="set a property to all cluster managers (with prefix 'manager.')"
+               impact="ACTION"
+               returnType="void">
+      <parameter name="key"
+                 description="Property name"
+                 type="java.lang.String"/>
+      <parameter name="value"
+                 description="Property value"
+                 type="java.lang.String"/>
+    </operation>
+
+    <operation   name="send"
+               description="send message to all cluster members"
+               impact="ACTION"
+               returnType="void">
+      <parameter name="message"
+                 description="replication message"
+                 type="org.apache.catalina.cluster.ClusterMessage"/>
+    </operation>
+    
+    <operation   name="sendClusterDomain"
+               description="send message to all cluster members with same domain"
+               impact="ACTION"
+               returnType="void">
+      <parameter name="message"
+                 description="replication message"
+                 type="org.apache.catalina.cluster.ClusterMessage"/>
+    </operation>
+        
+    <operation   name="sendToMember"
+               description="send message to one cluster member"
+               impact="ACTION"
+               returnType="void">
+      <parameter name="message"
+                 description="replication message"
+                 type="org.apache.catalina..cluster.ClusterMessage"/>
+      <parameter name="member"
+                 description="cluster member"
+                 type="java.lang.String"/>
+    </operation>
+
+    <operation   name="start"
+               description="Start the cluster"
+               impact="ACTION"
+               returnType="void">
+    </operation>
+    
+    <operation name="stop"
+               description="Stop the cluster"
+               impact="ACTION"
+               returnType="void">
+    </operation>
+                 
+  </mbean>
+
+  <mbean         name="ClusterReceiverBase"
+           description="Tcp Cluster NioReceiver implementation"
+               domain="Catalina"
+                group="Cluster"
+                 type="org.apache.catalina.cluster.tcp.ClusterReceiverBase">
+    <attribute   name="info"
+          description="Class version info"
+                 type="java.lang.String"
+                 writeable="false"/>
+    <attribute   name="tcpListenAddress"
+          description="tcp listener address"
+                 type="java.lang.String"/>
+    <attribute   name="tcpListenPort"
+          description="tcp listener port"
+                 type="int"/>
+    <attribute   name="tcpThreadCount"
+          description="number of tcp listener worker threads"
+                 type="int"/>
+    <attribute   name="tcpSelectorTimeout"
+          description="tcp listener Selector timeout"
+                 type="long"/>
+    <attribute   name="nrOfMsgsReceived"
+          description="number of messages received from other nodes"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="receivedTime"
+          description="total time message send time"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="receivedProcessingTime"
+          description="received processing time"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="minReceivedProcessingTime"
+          description="minimal received processing time"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="avgReceivedProcessingTime"
+          description="received processing time / nrOfRequests"
+                 type="double"
+                 writeable="false"/>
+    <attribute   name="maxReceivedProcessingTime"
+          description="maximal received processing time"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="doReceivedProcessingStats"
+          description="create received processing time stats"
+			     is="true"
+                 type="boolean" />                
+    <attribute   name="avgTotalReceivedBytes"
+          description="received totalReceivedBytes / nrOfMsgsReceived"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="totalReceivedBytes"
+          description="number of bytes received"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="sendAck"
+          description="send ack after data received"
+			     is="true"
+                 type="boolean"
+                 writeable="false" />
+    <attribute   name="compress"
+          description="data received compressed"
+			     is="true"
+                 type="boolean"
+                 writeable="false" />
+    <attribute   name="doListen"
+          description="is port really started"
+			     is="true"
+                 type="boolean"
+                 writeable="false" />
+                 
+	<operation name="resetStatistics"
+               description="Reset all statistics"
+               impact="ACTION"
+               returnType="void">
+    </operation>	
+
+    <operation   name="start"
+               description="Start the cluster"
+               impact="ACTION"
+               returnType="void">
+    </operation>
+    
+    <operation name="stop"
+               description="Stop the cluster"
+               impact="ACTION"
+               returnType="void">
+    </operation>
+                 
+  </mbean>
+
+  <mbean         name="SocketReplicationListener"
+           description="Tcp Cluster SocketReplicationListener implementation"
+               domain="Catalina"
+                group="Cluster"
+                 type="org.apache.catalina.cluster.tcp.SocketReplicationListener">
+    <attribute   name="info"
+          description="Class version info"
+                 type="java.lang.String"
+                 writeable="false"/>
+    <attribute   name="tcpListenAddress"
+          description="tcp listener address"
+                 type="java.lang.String"/>
+    <attribute   name="tcpListenPort"
+          description="tcp listener port"
+                 type="int"/>
+    <attribute   name="tcpListenMaxPort"
+          description="max tcp listen used port"
+                 type="int"/>
+    <attribute   name="tcpListenTimeout"
+          description="max tcp listen timeout (sec) wait for ServerSocket start"
+                 type="int"/>                
+    <attribute   name="nrOfMsgsReceived"
+          description="number of messages received from other nodes"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="receivedTime"
+          description="total time message send time"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="receivedProcessingTime"
+          description="received processing time"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="minReceivedProcessingTime"
+          description="minimal received processing time"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="avgReceivedProcessingTime"
+          description="received processing time / nrOfRequests"
+                 type="double"
+                 writeable="false"/>
+    <attribute   name="maxReceivedProcessingTime"
+          description="maximal received processing time"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="doReceivedProcessingStats"
+          description="create received processing time stats"
+			     is="true"
+                 type="boolean" />                
+    <attribute   name="avgTotalReceivedBytes"
+          description="received totalReceivedBytes / nrOfMsgsReceived"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="totalReceivedBytes"
+          description="number of bytes received"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="sendAck"
+          description="send ack after data received"
+			     is="true"
+                 type="boolean"
+                 writeable="false" />
+   <attribute   name="compress"
+          description="data received compressed"
+			     is="true"
+                 type="boolean"
+                 writeable="false" />
+   <attribute   name="doListen"
+          description="is port really started"
+			     is="true"
+                 type="boolean"
+                 writeable="false" />
+                 
+	<operation name="resetStatistics"
+               description="Reset all statistics"
+               impact="ACTION"
+               returnType="void">
+    </operation>	
+
+    <operation   name="start"
+               description="Start the cluster"
+               impact="ACTION"
+               returnType="void">
+    </operation>
+    
+    <operation name="stop"
+               description="Stop the cluster"
+               impact="ACTION"
+               returnType="void">
+    </operation>
+                 
+  </mbean>
+  
+  <mbean         name="ReplicationTransmitter"
+          description="Tcp replication transmitter"
+               domain="Catalina"
+                group="ClusterSender"
+                 type="org.apache.catalina.cluster.tcp.ReplicationTransmitter">
+    <attribute   name="info"
+          description="Class version info"
+                 type="java.lang.String"
+                 writeable="false"/>
+    <attribute   name="replicationMode"
+          description="replication mode (synchnous,pooled.asynchnous,fastasyncqueue)"
+                 type="java.lang.String"/>
+    <attribute   name="ackTimeout"
+          description="acknowledge timeout"
+                 type="long"/>
+    <attribute   name="autoConnect"
+          description="is sender disabled, fork a new socket"
+			     is="true"
+                 type="boolean" />
+    <attribute   name="waitForAck"
+          description="Wait for ack after data send"
+			     is="true"
+                 type="boolean"
+                 writeable="false" />
+    <attribute   name="processingTime"
+          description="sending processing time"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="minProcessingTime"
+          description="minimal sending processing time"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="avgProcessingTime"
+          description="processing time / nrOfRequests"
+                 type="double"
+                 writeable="false"/>
+    <attribute   name="maxProcessingTime"
+          description="maximal sending processing time"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="doTransmitterProcessingStats"
+          description="create processing time stats"
+			     is="true"
+                 type="boolean" />                
+    <attribute   name="nrOfRequests"
+          description="number of send messages to other members"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="totalBytes"
+          description="number of bytes transfered"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="failureCounter"
+          description="number of wrong transfers"
+                 type="long"
+                 writeable="false"/>
+	<attribute name="senderObjectNames"
+               description="get all sender object names"
+               type="[Ljavax.management.ObjectName;"
+               writeable="false"/>
+    <operation   name="start"
+               description="Start the cluster"
+               impact="ACTION"
+               returnType="void">
+    </operation>    
+    <operation name="stop"
+               description="Stop the cluster"
+               impact="ACTION"
+               returnType="void">
+    </operation>
+	<operation name="resetStatistics"
+               description="Reset all statistics"
+               impact="ACTION"
+               returnType="void">
+    </operation>	
+	<operation name="checkKeepAlive"
+               description="Check all sender connection for close socket (keepalive)"
+               impact="ACTION"
+               returnType="void">
+    </operation>
+  </mbean>
+
+  <mbean         name="AsyncSocketSender"
+          description="Async Cluster Sender"
+               domain="Catalina"
+                group="IDataSender"
+                 type="org.apache.catalina.cluster.tcp.AsyncSocketSender">
+    <attribute   name="info"
+          description="Class version info"
+                 type="java.lang.String"
+                 writeable="false"/>
+    <attribute   name="address"
+          description="sender ip address"
+                 type="java.net.InetAddress"
+                 writeable="false"/>
+    <attribute   name="port"
+          description="sender port"
+                 type="int"
+                 writeable="false" />
+    <attribute   name="suspect"
+          description="Socket is gone"
+                 type="boolean"/>
+    <attribute   name="waitForAck"
+          description="Wait for ack after data send"
+			     is="true"
+                 type="boolean"
+                 writeable="false"/>
+    <attribute   name="ackTimeout"
+          description="acknowledge timeout"
+                 type="long"/>                 
+    <attribute   name="avgMessageSize"
+                 writeable="false"
+          description="avg message size (totalbytes/nrOfRequests"
+                 type="long"/>
+    <attribute   name="queueSize"
+                 writeable="false"
+          description="queue size"
+                 type="int"/>
+    <attribute   name="queuedNrOfBytes"
+                 writeable="false"
+          description="number of bytes over all queued messages"
+                 type="long"/>
+    <attribute   name="messageTransferStarted"
+          description="message is in transfer"
+                 type="boolean"
+                 is="true"
+                 writeable="false"/>
+    <attribute   name="keepAliveTimeout"
+          description="active socket keep alive timeout"
+                 type="long"/>
+    <attribute   name="keepAliveMaxRequestCount"
+          description="max request over this socket"
+                 type="int"/>
+    <attribute   name="keepAliveCount"
+          description="keep Alive request count"
+                 type="int"
+                 writeable="false"/>
+    <attribute   name="keepAliveConnectTime"
+          description="Connect time for keep alive"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="resend"
+          description="after send failure make a resend"
+			     is="true"
+                 type="boolean" />
+    <attribute   name="connected"
+                 is="true"
+          description="socket connected"
+                 type="boolean"
+                 writeable="false"/>
+    <attribute   name="nrOfRequests"
+          description="number of send messages to other members"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="totalBytes"
+          description="number of bytes transfered"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="processingTime"
+          description="sending processing time"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="minProcessingTime"
+          description="minimal sending processing time"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="avgProcessingTime"
+          description="processing time / nrOfRequests"
+                 type="double"
+                 writeable="false"/>
+    <attribute   name="maxProcessingTime"
+          description="maximal sending processing time"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="doProcessingStats"
+          description="create processing time stats"
+			     is="true"
+                 type="boolean" />
+    <attribute   name="waitAckTime"
+          description="sending waitAck time"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="minWaitAckTime"
+          description="minimal sending waitAck time"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="avgWaitAckTime"
+          description="waitAck time / nrOfRequests"
+                 type="double"
+                 writeable="false"/>
+    <attribute   name="maxWaitAckTime"
+          description="maximal sending waitAck time"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="doWaitAckStats"
+          description="create waitAck time stats"
+			     is="true"
+                 type="boolean" />
+    <attribute   name="connectCounter"
+          description="counts connects"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="disconnectCounter"
+          description="counts disconnects"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="socketOpenCounter"
+          description="counts open socket (KeepAlive and connects)"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="socketOpenFailureCounter"
+          description="counts open socket failures"
+                 type="long"
+                 writeable="false"/>                 				 
+    <attribute   name="socketCloseCounter"
+          description="counts closed socket (KeepAlive and disconnects)"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="missingAckCounter"
+          description="counts missing ack"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="dataResendCounter"
+          description="counts data resends"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="dataFailureCounter"
+          description="counts data send failures"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="inQueueCounter"
+          description="counts all queued messages"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="outQueueCounter"
+          description="counts all successfully sended messages"
+                 type="long"
+                 writeable="false"/>
+	<operation name="connect"
+               description="connect to other replication node"
+               impact="ACTION"
+               returnType="void">
+    </operation>
+	<operation name="disconnect"
+               description="disconnect to other replication node"
+               impact="ACTION"
+               returnType="void">
+    </operation>
+	<operation name="checkKeepAlive"
+               description="Check connection for close socket"
+               impact="ACTION"
+               returnType="boolean">
+    </operation>
+	<operation name="resetStatistics"
+               description="Reset all statistics"
+               impact="ACTION"
+               returnType="void">
+    </operation>
+				 
+  </mbean>
+
+  <mbean         name="MultiSocketSender"
+          description="Multi Socket Sender, more than one socket per member"
+               domain="Catalina"
+                group="IDataSender"
+                 type="org.apache.catalina.cluster.tcp.PooledSocketSender">
+    <attribute   name="address"
+          description="sender ip address"
+                 type="java.net.InetAddress"
+                 writeable="false"/>
+    <attribute   name="port"
+          description="sender port"
+                 type="int"
+                 writeable="false" />
+    <attribute   name="suspect"
+          description="Socket is gone"
+                 type="boolean"/>
+    <attribute   name="ackTimeout"
+          description="acknowledge timeout"
+                 type="long"/>
+    <attribute   name="waitForAck"
+          description="Wait for ack after data send"
+			     is="true"
+                 type="boolean"
+                 writeable="false" />
+    <attribute   name="maxPoolSocketLimit"
+          description="Max parallel sockets"
+                 type="int"/>
+    <attribute   name="keepAliveTimeout"
+          description="active socket keep alive timeout"
+                 type="long"/>
+    <attribute   name="keepAliveMaxRequestCount"
+          description="max request over this socket"
+                 type="int"/>
+    <attribute   name="resend"
+          description="after send failure make a resend"
+			     is="true"
+                 type="boolean" />
+    <attribute   name="connected"
+                 is="true"
+          description="socket connected"
+                 type="boolean"
+                 writeable="false"/>
+    <attribute   name="avgMessageSize"
+                 writeable="false"
+          description="avg message size (totalbytes/nrOfRequests"
+                 type="long"/>
+    <attribute   name="nrOfRequests"
+          description="number of send messages to other members"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="totalBytes"
+          description="number of bytes transfered"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="connectCounter"
+          description="counts connects"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="disconnectCounter"
+          description="counts disconnects"
+                 type="long"
+                 writeable="false"/>
+	<operation name="connect"
+               description="start Queue to connect to ohter replication node"
+               impact="ACTION"
+               returnType="void">
+    </operation>
+	<operation name="disconnect"
+               description="stop Queue to other replication node"
+               impact="ACTION"
+               returnType="void">
+    </operation>
+	<operation name="resetStatistics"
+               description="Reset all statistics"
+               impact="ACTION"
+               returnType="void">
+    </operation>
+				 
+  </mbean>
+
+  <mbean         name="SocketSender"
+          description="Sync Cluster Sender"
+               domain="Catalina"
+                group="IDataSender"
+                 type="org.apache.catalina.cluster.tcp.SocketSender">
+    <attribute   name="address"
+          description="sender ip address"
+                 type="java.net.InetAddress"
+                 writeable="false"/>
+    <attribute   name="port"
+          description="sender port"
+                 type="int"
+                 writeable="false" />
+    <attribute   name="suspect"
+          description="Socket is gone"
+                 type="boolean"/>
+    <attribute   name="ackTimeout"
+          description="acknowledge timeout"
+                 type="long"/>
+    <attribute   name="waitForAck"
+          description="Wait for ack after data send"
+			     is="true"
+                 type="boolean"
+                 writeable="false" />
+    <attribute   name="keepAliveTimeout"
+          description="active socket keep alive timeout"
+                 type="long"/>
+    <attribute   name="keepAliveMaxRequestCount"
+          description="max request over this socket"
+                 type="int"/>
+    <attribute   name="messageTransferStarted"
+          description="message is in transfer"
+                 type="boolean"
+                 is="true"
+                 writeable="false"/>
+    <attribute   name="keepAliveCount"
+          description="keep Alive request count"
+                 type="int"
+                 writeable="false"/>
+    <attribute   name="keepAliveConnectTime"
+          description="Connect time for keep alive"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="resend"
+          description="after send failure make a resend"
+			     is="true"
+                 type="boolean" />
+    <attribute   name="connected"
+                 is="true"
+          description="socket connected"
+                 type="boolean"
+                 writeable="false"/>
+    <attribute   name="avgMessageSize"
+                 writeable="false"
+          description="avg message size (totalbytes/nrOfRequests"
+                 type="long"/>
+    <attribute   name="nrOfRequests"
+          description="number of send messages to other members"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="totalBytes"
+          description="number of bytes transfered"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="processingTime"
+          description="sending processing time"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="minProcessingTime"
+          description="minimal sending processing time"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="avgProcessingTime"
+          description="processing time / nrOfRequests"
+                 type="double"
+                 writeable="false"/>
+    <attribute   name="maxProcessingTime"
+          description="maximal sending processing time"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="doProcessingStats"
+          description="create Processing time stats"
+			     is="true"
+                 type="boolean" />
+    <attribute   name="waitAckTime"
+          description="sending waitAck time"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="minWaitAckTime"
+          description="minimal sending waitAck time"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="avgWaitAckTime"
+          description="waitAck time / nrOfRequests"
+                 type="double"
+                 writeable="false"/>
+    <attribute   name="maxWaitAckTime"
+          description="maximal sending waitAck time"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="doWaitAckStats"
+          description="create waitAck time stats"
+			     is="true"
+                 type="boolean" />
+    <attribute   name="connectCounter"
+          description="counts connects"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="disconnectCounter"
+          description="counts disconnects"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="socketCloseCounter"
+          description="counts closed socket (KeepAlive and disconnects)"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="socketOpenFailureCounter"
+          description="counts open socket failures"
+                 type="long"
+                 writeable="false"/>                 				 
+    <attribute   name="socketOpenCounter"
+          description="counts open socket (KeepAlive and connects)"
+                 type="long"
+                 writeable="false"/>				 
+    <attribute   name="missingAckCounter"
+          description="counts missing ack"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="dataResendCounter"
+          description="counts data resends"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="dataFailureCounter"
+          description="counts data send failures"
+                 type="long"
+                 writeable="false"/>
+	<operation name="connect"
+               description="connect to other replication node"
+               impact="ACTION"
+               returnType="void">
+    </operation>
+	<operation name="disconnect"
+               description="disconnect to other replication node"
+               impact="ACTION"
+               returnType="void">
+    </operation>
+	<operation name="checkKeepAlive"
+               description="Check connection for close socket"
+               impact="ACTION"
+               returnType="boolean">
+    </operation>
+	<operation name="resetStatistics"
+               description="Reset all statistics"
+               impact="ACTION"
+               returnType="void">
+    </operation>
+				 
+  </mbean>
+    
+  <mbean         name="ReplicationValve"
+          description="Valve for simple tcp replication"
+               domain="Catalina"
+                group="Valve"
+                 type="org.apache.catalina.cluster.tcp.ReplicationValve">
+    <attribute   name="info"
+          description="Class version info"
+                 type="java.lang.String"
+                 writeable="false"/>
+    <attribute   name="filter"
+          description="resource filter to disable session replication check"
+                 type="java.lang.String"/>
+    <attribute   name="primaryIndicator"
+ 			     is="true"
+          description="set indicator that request processing is at primary session node"
+                 type="boolean"/>
+    <attribute   name="primaryIndicatorName"
+          description="Request attribute name to indicate that request processing is at primary session node"
+                 type="java.lang.String"/>
+    <attribute   name="doProcessingStats"
+ 			     is="true"
+          description="active statistics counting"
+                 type="boolean"/>
+	<attribute   name="nrOfRequests"
+          description="number of replicated requests"
+                 type="long"
+                 writeable="false"/>
+	<attribute   name="nrOfFilterRequests"
+          description="number of filtered requests"
+                 type="long"
+                 writeable="false"/>
+	<attribute   name="nrOfSendRequests"
+          description="number of send requests"
+                 type="long"
+                 writeable="false"/>
+	<attribute   name="nrOfCrossContextSendRequests"
+          description="number of send cross context session requests"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="totalRequestTime"
+          description="total replicated request time"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="totalSendTime"
+          description="total replicated send time"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="lastSendTime"
+          description="last replicated request time"
+                 type="long"
+                 writeable="false"/>
+    <operation name="resetStatistics"
+               description="Reset all statistics"
+               impact="ACTION"
+               returnType="void">
+    </operation>
+                 
+  </mbean>
+
+
+</mbeans-descriptors>

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/transport/nio/NioReceiver.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/transport/nio/NioReceiver.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/transport/nio/NioReceiver.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,382 @@
+/*
+ * Copyright 1999,2004-2005 The Apache Software Foundation.
+ *
+ * Licensed 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.tribes.transport.nio;
+
+import java.io.IOException;
+import java.net.ServerSocket;
+import java.nio.channels.SelectableChannel;
+import java.nio.channels.SelectionKey;
+import java.nio.channels.Selector;
+import java.nio.channels.ServerSocketChannel;
+import java.nio.channels.SocketChannel;
+import java.util.Iterator;
+
+import org.apache.catalina.tribes.ChannelReceiver;
+import org.apache.catalina.tribes.io.ListenCallback;
+import org.apache.catalina.tribes.io.ObjectReader;
+import org.apache.catalina.tribes.transport.Constants;
+import org.apache.catalina.tribes.transport.ReceiverBase;
+import org.apache.catalina.tribes.transport.ThreadPool;
+import org.apache.catalina.tribes.transport.WorkerThread;
+import org.apache.catalina.tribes.util.StringManager;
+import java.util.LinkedList;
+import java.util.Set;
+import java.nio.channels.CancelledKeyException;
+
+/**
+ * @author Filip Hanik
+ * @version $Revision: 379904 $ $Date: 2006-02-22 15:16:25 -0600 (Wed, 22 Feb 2006) $
+ */
+public class NioReceiver extends ReceiverBase implements Runnable, ChannelReceiver, ListenCallback {
+
+    protected static org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory.getLog(NioReceiver.class);
+
+    /**
+     * The string manager for this package.
+     */
+    protected StringManager sm = StringManager.getManager(Constants.Package);
+
+    /**
+     * The descriptive information about this implementation.
+     */
+    private static final String info = "NioReceiver/1.0";
+
+    private Selector selector = null;
+    private ServerSocketChannel serverChannel = null;
+
+    protected LinkedList events = new LinkedList();
+//    private Object interestOpsMutex = new Object();
+
+    public NioReceiver() {
+    }
+
+    /**
+     * Return descriptive information about this implementation and the
+     * corresponding version number, in the format
+     * <code>&lt;description&gt;/&lt;version&gt;</code>.
+     */
+    public String getInfo() {
+        return (info);
+    }
+
+//    public Object getInterestOpsMutex() {
+//        return interestOpsMutex;
+//    }
+
+    public void stop() {
+        this.stopListening();
+    }
+
+    /**
+     * start cluster receiver
+     * @throws Exception
+     * @see org.apache.catalina.tribes.ClusterReceiver#start()
+     */
+    public void start() throws IOException {
+        try {
+//            setPool(new ThreadPool(interestOpsMutex, getMaxThreads(),getMinThreads(),this));
+            setPool(new ThreadPool(getMaxThreads(),getMinThreads(),this));
+        } catch (Exception x) {
+            log.fatal("ThreadPool can initilzed. Listener not started", x);
+            if ( x instanceof IOException ) throw (IOException)x;
+            else throw new IOException(x.getMessage());
+        }
+        try {
+            getBind();
+            bind();
+            Thread t = new Thread(this, "NioReceiver");
+            t.setDaemon(true);
+            t.start();
+        } catch (Exception x) {
+            log.fatal("Unable to start cluster receiver", x);
+            if ( x instanceof IOException ) throw (IOException)x;
+            else throw new IOException(x.getMessage());
+        }
+    }
+    
+    public WorkerThread getWorkerThread() {
+        NioReplicationThread thread = new NioReplicationThread(this,this);
+        thread.setUseBufferPool(this.getUseBufferPool());
+        thread.setRxBufSize(getRxBufSize());
+        thread.setOptions(getWorkerThreadOptions());
+        return thread;
+    }
+    
+    
+    
+    protected void bind() throws IOException {
+        // allocate an unbound server socket channel
+        serverChannel = ServerSocketChannel.open();
+        // Get the associated ServerSocket to bind it with
+        ServerSocket serverSocket = serverChannel.socket();
+        // create a new Selector for use below
+        selector = Selector.open();
+        // set the port the server channel will listen to
+        //serverSocket.bind(new InetSocketAddress(getBind(), getTcpListenPort()));
+        bind(serverSocket,getTcpListenPort(),getAutoBind());
+        // set non-blocking mode for the listening socket
+        serverChannel.configureBlocking(false);
+        // register the ServerSocketChannel with the Selector
+        serverChannel.register(selector, SelectionKey.OP_ACCEPT);
+        
+    }
+    
+    public void addEvent(Runnable event) {
+        if ( selector != null ) {
+            synchronized (events) {
+                events.add(event);
+            }
+            if ( log.isTraceEnabled() ) log.trace("Adding event to selector:"+event);
+            selector.wakeup();
+        }
+    }
+
+    public void events() {
+        if ( events.size() == 0 ) return;
+        synchronized (events) {
+            Runnable r = null;
+            while ( (events.size() > 0) && (r = (Runnable)events.removeFirst()) != null ) {
+                try {
+                    if ( log.isTraceEnabled() ) log.trace("Processing event in selector:"+r);
+                    r.run();
+                } catch ( Exception x ) {
+                    log.error("",x);
+                }
+            }
+            events.clear();
+        }
+    }
+    
+    public static void cancelledKey(SelectionKey key) {
+        ObjectReader reader = (ObjectReader)key.attachment();
+        if ( reader != null ) {
+            reader.setCancelled(true);
+            reader.finish();
+        }
+        key.cancel(); 
+        key.attach(null);
+        try { ((SocketChannel)key.channel()).socket().close(); } catch (IOException e) { if (log.isDebugEnabled()) log.debug("", e); }
+        try { key.channel().close(); } catch (IOException e) { if (log.isDebugEnabled()) log.debug("", e); }
+        
+    }
+    
+    protected void socketTimeouts() {
+        //timeout
+        Set keys = selector.keys();
+        long now = System.currentTimeMillis();
+        for (Iterator iter = keys.iterator(); iter.hasNext(); ) {
+            SelectionKey key = (SelectionKey) iter.next();
+            try {
+//                if (key.interestOps() == SelectionKey.OP_READ) {
+//                    //only timeout sockets that we are waiting for a read from
+//                    ObjectReader ka = (ObjectReader) key.attachment();
+//                    long delta = now - ka.getLastAccess();
+//                    if (delta > (long) getTimeout()) {
+//                        cancelledKey(key);
+//                    }
+//                }
+//                else
+                if ( key.interestOps() == 0 ) {
+                    //check for keys that didn't make it in.
+                    ObjectReader ka = (ObjectReader) key.attachment();
+                    if ( ka != null ) {
+                        long delta = now - ka.getLastAccess();
+                        if (delta > (long) getTimeout() && (!ka.isAccessed())) {
+                            log.warn("Channel key is registered, but has had no interest ops for the last "+getTimeout()+" ms. (cancelled:"+ka.isCancelled()+"):"+key+" last access:"+new java.sql.Timestamp(ka.getLastAccess()));
+//                            System.out.println("Interest:"+key.interestOps());
+//                            System.out.println("Ready Ops:"+key.readyOps());
+//                            System.out.println("Valid:"+key.isValid());
+                            ka.setLastAccess(now);
+                            //key.interestOps(SelectionKey.OP_READ);
+                        }//end if
+                    } else {
+                        cancelledKey(key);
+                    }//end if
+                }//end if
+            }catch ( CancelledKeyException ckx ) {
+                cancelledKey(key);
+            }
+        }
+    }
+
+
+    /**
+     * get data from channel and store in byte array
+     * send it to cluster
+     * @throws IOException
+     * @throws java.nio.channels.ClosedChannelException
+     */
+    protected void listen() throws Exception {
+        if (doListen()) {
+            log.warn("ServerSocketChannel already started");
+            return;
+        }
+        
+        setListen(true);
+
+        while (doListen() && selector != null) {
+            // this may block for a long time, upon return the
+            // selected set contains keys of the ready channels
+            try {
+                events();
+                socketTimeouts();
+                int n = selector.select(getTcpSelectorTimeout());
+                if (n == 0) {
+                    //there is a good chance that we got here
+                    //because the TcpReplicationThread called
+                    //selector wakeup().
+                    //if that happens, we must ensure that that
+                    //thread has enough time to call interestOps
+//                    synchronized (interestOpsMutex) {
+                        //if we got the lock, means there are no
+                        //keys trying to register for the
+                        //interestOps method
+//                    }
+                    continue; // nothing to do
+                }
+                // get an iterator over the set of selected keys
+                Iterator it = selector.selectedKeys().iterator();
+                // look at each key in the selected set
+                while (it.hasNext()) {
+                    SelectionKey key = (SelectionKey) it.next();
+                    // Is a new connection coming in?
+                    if (key.isAcceptable()) {
+                        ServerSocketChannel server = (ServerSocketChannel) key.channel();
+                        SocketChannel channel = server.accept();
+                        channel.socket().setReceiveBufferSize(getRxBufSize());
+                        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,
+                                        channel,
+                                        SelectionKey.OP_READ,
+                                        attach);
+                    }
+                    // is there data to read on this channel?
+                    if (key.isReadable()) {
+                        readDataFromSocket(key);
+                    } else {
+                        key.interestOps(key.interestOps() & (~SelectionKey.OP_WRITE));
+                    }
+
+                    // remove key from selected set, it's been handled
+                    it.remove();
+                }
+            } catch (java.nio.channels.ClosedSelectorException cse) {
+                // ignore is normal at shutdown or stop listen socket
+            } catch (java.nio.channels.CancelledKeyException nx) {
+                log.warn("Replication client disconnected, error when polling key. Ignoring client.");
+            } catch (Throwable x) {
+                try {
+                    log.error("Unable to process request in NioReceiver", x);
+                }catch ( Throwable tx ) {
+                    //in case an out of memory error, will affect the logging framework as well
+                    tx.printStackTrace();
+                }
+            }
+
+        }
+        serverChannel.close();
+        if (selector != null)
+            selector.close();
+    }
+
+    
+
+    /**
+     * Close Selector.
+     *
+     * @see org.apache.catalina.tribes.transport.ClusterReceiverBase#stopListening()
+     */
+    protected void stopListening() {
+        // Bugzilla 37529: http://issues.apache.org/bugzilla/show_bug.cgi?id=37529
+        setListen(false);
+        if (selector != null) {
+            try {
+                for (int i = 0; i < getMaxThreads(); i++) {
+                    selector.wakeup();
+                }
+                selector.close();
+            } catch (Exception x) {
+                log.error("Unable to close cluster receiver selector.", x);
+            } finally {
+                selector = null;
+            }
+        }
+    }
+
+    // ----------------------------------------------------------
+
+    /**
+     * Register the given channel with the given selector for
+     * the given operations of interest
+     */
+    protected void registerChannel(Selector selector,
+                                   SelectableChannel channel,
+                                   int ops,
+                                   Object attach) throws Exception {
+        if (channel == null)return; // could happen
+        // set the new channel non-blocking
+        channel.configureBlocking(false);
+        // register it with the selector
+        channel.register(selector, ops, attach);
+    }
+
+    /**
+     * Start thread and listen
+     */
+    public void run() {
+        try {
+            listen();
+        } catch (Exception x) {
+            log.error("Unable to run replication listener.", x);
+        }
+    }
+
+    // ----------------------------------------------------------
+
+    /**
+     * Sample data handler method for a channel with data ready to read.
+     * @param key A SelectionKey object associated with a channel
+     *  determined by the selector to be ready for reading.  If the
+     *  channel returns an EOF condition, it is closed here, which
+     *  automatically invalidates the associated key.  The selector
+     *  will then de-register the channel on the next select call.
+     */
+    protected void readDataFromSocket(SelectionKey key) throws Exception {
+        NioReplicationThread worker = (NioReplicationThread) getPool().getWorker();
+        if (worker == null) {
+            // No threads available, do nothing, the selection
+            // loop will keep calling this method until a
+            // thread becomes available, the thread pool itself has a waiting mechanism
+            // so we will not wait here.
+            if (log.isDebugEnabled())
+                log.debug("No TcpReplicationThread available");
+        } else {
+            // invoking this wakes up the worker thread then returns
+            worker.serviceChannel(key);
+        }
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/transport/nio/NioReplicationThread.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/transport/nio/NioReplicationThread.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/transport/nio/NioReplicationThread.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,310 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tribes.transport.nio;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.channels.SelectionKey;
+import java.nio.channels.SocketChannel;
+
+import org.apache.catalina.tribes.io.ObjectReader;
+import org.apache.catalina.tribes.transport.Constants;
+import org.apache.catalina.tribes.transport.WorkerThread;
+import org.apache.catalina.tribes.ChannelMessage;
+import org.apache.catalina.tribes.io.ListenCallback;
+import org.apache.catalina.tribes.io.ChannelData;
+import org.apache.catalina.tribes.io.BufferPool;
+import java.nio.channels.CancelledKeyException;
+import org.apache.catalina.tribes.UniqueId;
+import org.apache.catalina.tribes.RemoteProcessException;
+import org.apache.catalina.tribes.util.Logs;
+
+/**
+ * A worker thread class which can drain channels and echo-back the input. Each
+ * instance is constructed with a reference to the owning thread pool object.
+ * When started, the thread loops forever waiting to be awakened to service the
+ * channel associated with a SelectionKey object. The worker is tasked by
+ * calling its serviceChannel() method with a SelectionKey object. The
+ * serviceChannel() method stores the key reference in the thread object then
+ * calls notify() to wake it up. When the channel has been drained, the worker
+ * thread returns itself to its parent pool.
+ * 
+ * @author Filip Hanik
+ * 
+ * @version $Revision: 378050 $, $Date: 2006-02-15 12:30:02 -0600 (Wed, 15 Feb 2006) $
+ */
+public class NioReplicationThread extends WorkerThread {
+    
+    private static org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory.getLog( NioReplicationThread.class );
+    
+    private ByteBuffer buffer = null;
+    private SelectionKey key;
+    private int rxBufSize;
+    private NioReceiver receiver;
+    public NioReplicationThread (ListenCallback callback, NioReceiver receiver)
+    {
+        super(callback);
+        this.receiver = receiver;
+    }
+
+    // loop forever waiting for work to do
+    public synchronized void run() { 
+        this.notify();
+        if ( (getOptions() & OPTION_DIRECT_BUFFER) == OPTION_DIRECT_BUFFER ) {
+            buffer = ByteBuffer.allocateDirect(getRxBufSize());
+        }else {
+            buffer = ByteBuffer.allocate (getRxBufSize());
+        }
+        while (isDoRun()) {
+            try {
+                // sleep and release object lock
+                this.wait();
+            } catch (InterruptedException e) {
+                if(log.isInfoEnabled()) log.info("TCP worker thread interrupted in cluster",e);
+                // clear interrupt status
+                Thread.interrupted();
+            }
+            if (key == null) {
+                continue;	// just in case
+            }
+            if ( log.isTraceEnabled() ) 
+                log.trace("Servicing key:"+key);
+
+            try {
+                ObjectReader reader = (ObjectReader)key.attachment();
+                if ( reader == null ) {
+                    if ( log.isTraceEnabled() ) 
+                        log.trace("No object reader, cancelling:"+key);
+                    cancelKey(key);
+                } else {
+                    if ( log.isTraceEnabled() ) 
+                        log.trace("Draining channel:"+key);
+
+                    drainChannel(key, reader);
+                }
+            } catch (Exception e) {
+                //this is common, since the sockets on the other
+                //end expire after a certain time.
+                if ( e instanceof CancelledKeyException ) {
+                    //do nothing
+                } else if ( e instanceof IOException ) {
+                    //dont spew out stack traces for IO exceptions unless debug is enabled.
+                    if (log.isDebugEnabled()) log.debug ("IOException in replication worker, unable to drain channel. Probable cause: Keep alive socket closed["+e.getMessage()+"].", e);
+                    else log.warn ("IOException in replication worker, unable to drain channel. Probable cause: Keep alive socket closed["+e.getMessage()+"].");
+                } else if ( log.isErrorEnabled() ) {
+                    //this is a real error, log it.
+                    log.error("Exception caught in TcpReplicationThread.drainChannel.",e);
+                } 
+                cancelKey(key);
+            } finally {
+                
+            }
+            key = null;
+            // done, ready for more, return to pool
+            getPool().returnWorker (this);
+        }
+    }
+
+    /**
+     * Called to initiate a unit of work by this worker thread
+     * on the provided SelectionKey object.  This method is
+     * synchronized, as is the run() method, so only one key
+     * can be serviced at a given time.
+     * Before waking the worker thread, and before returning
+     * to the main selection loop, this key's interest set is
+     * updated to remove OP_READ.  This will cause the selector
+     * to ignore read-readiness for this channel while the
+     * worker thread is servicing it.
+     */
+    public synchronized void serviceChannel (SelectionKey key) {
+        if ( log.isTraceEnabled() ) 
+            log.trace("About to service key:"+key);
+        ObjectReader reader = (ObjectReader)key.attachment();
+        if ( reader != null ) reader.setLastAccess(System.currentTimeMillis());
+        this.key = key;
+        key.interestOps (key.interestOps() & (~SelectionKey.OP_READ));
+        key.interestOps (key.interestOps() & (~SelectionKey.OP_WRITE));
+        this.notify();		// awaken the thread
+    }
+
+    /**
+     * The actual code which drains the channel associated with
+     * the given key.  This method assumes the key has been
+     * modified prior to invocation to turn off selection
+     * interest in OP_READ.  When this method completes it
+     * re-enables OP_READ and calls wakeup() on the selector
+     * so the selector will resume watching this channel.
+     */
+    protected void drainChannel (final SelectionKey key, ObjectReader reader) throws Exception {
+        reader.setLastAccess(System.currentTimeMillis());
+        reader.access();
+        SocketChannel channel = (SocketChannel) key.channel();
+        int count;
+        buffer.clear();			// make buffer empty
+
+        // loop while data available, channel is non-blocking
+        while ((count = channel.read (buffer)) > 0) {
+            buffer.flip();		// make buffer readable
+            if ( buffer.hasArray() ) 
+                reader.append(buffer.array(),0,count,false);
+            else 
+                reader.append(buffer,count,false);
+            buffer.clear();		// make buffer empty
+            //do we have at least one package?
+            if ( reader.hasPackage() ) break;
+        }
+
+        int pkgcnt = reader.count();
+        
+        if (count < 0 && pkgcnt == 0 ) {
+            //end of stream, and no more packages to process
+            remoteEof(key);
+            return;
+        }
+        
+        ChannelMessage[] msgs = pkgcnt == 0? ChannelData.EMPTY_DATA_ARRAY : reader.execute();
+        
+        registerForRead(key,reader);//register to read new data, before we send it off to avoid dead locks
+        
+        for ( int i=0; i<msgs.length; i++ ) {
+            /**
+             * Use send ack here if you want to ack the request to the remote 
+             * server before completing the request
+             * This is considered an asynchronized request
+             */
+            if (ChannelData.sendAckAsync(msgs[i].getOptions())) sendAck(key,channel,Constants.ACK_COMMAND);
+            try {
+                if ( Logs.MESSAGES.isTraceEnabled() ) {
+                    try {
+                        Logs.MESSAGES.trace("NioReplicationThread - Received msg:" + new UniqueId(msgs[i].getUniqueId()) + " at " + new java.sql.Timestamp(System.currentTimeMillis()));
+                    }catch ( Throwable t ) {}
+                }
+                //process the message
+                getCallback().messageDataReceived(msgs[i]);
+                /**
+                 * Use send ack here if you want the request to complete on this 
+                 * server before sending the ack to the remote server
+                 * This is considered a synchronized request
+                 */
+                if (ChannelData.sendAckSync(msgs[i].getOptions())) sendAck(key,channel,Constants.ACK_COMMAND);
+            }catch ( RemoteProcessException e ) {
+                if ( log.isDebugEnabled() ) log.error("Processing of cluster message failed.",e);
+                if (ChannelData.sendAckSync(msgs[i].getOptions())) sendAck(key,channel,Constants.FAIL_ACK_COMMAND);
+            }catch ( Exception e ) {
+                log.error("Processing of cluster message failed.",e);
+                if (ChannelData.sendAckSync(msgs[i].getOptions())) sendAck(key,channel,Constants.FAIL_ACK_COMMAND);
+            }
+            if ( getUseBufferPool() ) {
+                BufferPool.getBufferPool().returnBuffer(msgs[i].getMessage());
+                msgs[i].setMessage(null);
+            }
+        }                        
+        
+        if (count < 0) {
+            remoteEof(key);
+            return;
+        }
+    }
+
+    private void remoteEof(SelectionKey key) {
+        // close channel on EOF, invalidates the key
+        if ( log.isDebugEnabled() ) log.debug("Channel closed on the remote end, disconnecting");
+        cancelKey(key);
+    }
+
+    protected void registerForRead(final SelectionKey key, ObjectReader reader) {
+        if ( log.isTraceEnabled() ) 
+            log.trace("Adding key for read event:"+key);
+        reader.finish();
+        //register our OP_READ interest
+        Runnable r = new Runnable() {
+            public void run() {
+                try {
+                    if (key.isValid()) {
+                        // cycle the selector so this key is active again
+                        key.selector().wakeup();
+                        // resume interest in OP_READ, OP_WRITE
+                        int resumeOps = key.interestOps() | SelectionKey.OP_READ;
+                        key.interestOps(resumeOps);
+                        if ( log.isTraceEnabled() ) 
+                            log.trace("Registering key for read:"+key);
+                    }
+                } catch (CancelledKeyException ckx ) {
+                    NioReceiver.cancelledKey(key);
+                    if ( log.isTraceEnabled() ) 
+                        log.trace("CKX Cancelling key:"+key);
+
+                } catch (Exception x) {
+                    log.error("Error registering key for read:"+key,x);
+                }
+            }
+        };
+        receiver.addEvent(r);
+    }
+
+    private void cancelKey(final SelectionKey key) {
+        if ( log.isTraceEnabled() ) 
+            log.trace("Adding key for cancel event:"+key);
+
+        ObjectReader reader = (ObjectReader)key.attachment();
+        if ( reader != null ) {
+            reader.setCancelled(true);
+            reader.finish();
+        }
+        Runnable cx = new Runnable() {
+            public void run() {
+                if ( log.isTraceEnabled() ) 
+                    log.trace("Cancelling key:"+key);
+
+                NioReceiver.cancelledKey(key);
+            }
+        };
+        receiver.addEvent(cx);
+    }
+    
+    
+
+
+
+    /**
+     * send a reply-acknowledgement (6,2,3)
+     * @param key
+     * @param channel
+     */
+    protected void sendAck(SelectionKey key, SocketChannel channel, byte[] command) {
+        
+        try {
+            ByteBuffer buf = ByteBuffer.wrap(command);
+            int total = 0;
+            while ( total < command.length ) {
+                total += channel.write(buf);
+            }
+            if (log.isTraceEnabled()) {
+                log.trace("ACK sent to " + channel.socket().getPort());
+            }
+        } catch ( java.io.IOException x ) {
+            log.warn("Unable to send ACK back through channel, channel disconnected?: "+x.getMessage());
+        }
+    }
+
+    public void setRxBufSize(int rxBufSize) {
+        this.rxBufSize = rxBufSize;
+    }
+
+    public int getRxBufSize() {
+        return rxBufSize;
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/transport/nio/NioSender.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/transport/nio/NioSender.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/transport/nio/NioSender.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,330 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tribes.transport.nio;
+
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.net.UnknownHostException;
+import java.nio.ByteBuffer;
+import java.nio.channels.SelectionKey;
+import java.nio.channels.Selector;
+import java.nio.channels.SocketChannel;
+import java.util.Arrays;
+
+import org.apache.catalina.tribes.Member;
+import org.apache.catalina.tribes.io.XByteBuffer;
+import org.apache.catalina.tribes.transport.AbstractSender;
+import org.apache.catalina.tribes.transport.DataSender;
+import org.apache.catalina.tribes.RemoteProcessException;
+
+/**
+ * This class is NOT thread safe and should never be used with more than one thread at a time
+ * 
+ * This is a state machine, handled by the process method
+ * States are:
+ * - NOT_CONNECTED -> connect() -> CONNECTED
+ * - CONNECTED -> setMessage() -> READY TO WRITE
+ * - READY_TO_WRITE -> write() -> READY TO WRITE | READY TO READ
+ * - READY_TO_READ -> read() -> READY_TO_READ | TRANSFER_COMPLETE
+ * - TRANSFER_COMPLETE -> CONNECTED
+ * 
+ * @author Filip Hanik
+ * @version 1.0
+ */
+public class NioSender extends AbstractSender implements DataSender{
+
+    protected static org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory.getLog(NioSender.class);
+
+    
+    
+    protected Selector selector;    
+    protected SocketChannel socketChannel;
+
+    /*
+     * STATE VARIABLES *
+     */
+    protected ByteBuffer readbuf = null;
+    protected ByteBuffer writebuf = null;
+    protected byte[] current = null;
+    protected XByteBuffer ackbuf = new XByteBuffer(128,true);
+    protected int remaining = 0;
+    protected boolean complete;
+    
+    protected boolean connecting = false;
+    
+    public NioSender() {
+        super();
+        
+    }
+    
+    /**
+     * State machine to send data
+     * @param key SelectionKey
+     * @return boolean
+     * @throws IOException
+     */
+    public boolean process(SelectionKey key, boolean waitForAck) throws IOException {
+        int ops = key.readyOps();
+        key.interestOps(key.interestOps() & ~ops);
+        //in case disconnect has been called
+        if ((!isConnected()) && (!connecting)) throw new IOException("Sender has been disconnected, can't selection key.");
+        if ( !key.isValid() ) throw new IOException("Key is not valid, it must have been cancelled.");
+        if ( key.isConnectable() ) {
+            if ( socketChannel.finishConnect() ) {
+                //we connected, register ourselves for writing
+                setConnected(true);
+                connecting = false;
+                setRequestCount(0);
+                setConnectTime(System.currentTimeMillis());
+                socketChannel.socket().setSendBufferSize(getTxBufSize());
+                socketChannel.socket().setReceiveBufferSize(getRxBufSize());
+                socketChannel.socket().setSoTimeout((int)getTimeout());
+                socketChannel.socket().setSoLinger(false,0);
+                socketChannel.socket().setTcpNoDelay(getTcpNoDelay());
+                socketChannel.socket().setKeepAlive(getSoKeepAlive());
+                socketChannel.socket().setReuseAddress(getSoReuseAddress());
+                socketChannel.socket().setOOBInline(getOoBInline());
+                socketChannel.socket().setSoLinger(getSoLingerOn(),getSoLingerTime());
+                socketChannel.socket().setTrafficClass(getSoTrafficClass());
+                if ( current != null ) key.interestOps(key.interestOps() | SelectionKey.OP_WRITE);
+                return false;
+            } else  { 
+                //wait for the connection to finish
+                key.interestOps(key.interestOps() | SelectionKey.OP_CONNECT);
+                return false;
+            }//end if
+        } else if ( key.isWritable() ) {
+            boolean writecomplete = write(key);
+            if ( writecomplete ) {
+                //we are completed, should we read an ack?
+                if ( waitForAck ) {
+                    //register to read the ack
+                    key.interestOps(key.interestOps() | SelectionKey.OP_READ);
+                } else {
+                    //if not, we are ready, setMessage will reregister us for another write interest
+                    //do a health check, we have no way of verify a disconnected
+                    //socket since we don't register for OP_READ on waitForAck=false
+                    read(key);//this causes overhead
+                    setRequestCount(getRequestCount()+1);
+                    return true;
+                }
+            } else {
+                //we are not complete, lets write some more
+                key.interestOps(key.interestOps()|SelectionKey.OP_WRITE);
+            }//end if
+        } else if ( key.isReadable() ) {
+            boolean readcomplete = read(key);
+            if ( readcomplete ) {
+                setRequestCount(getRequestCount()+1);
+                return true;
+            } else {
+                key.interestOps(key.interestOps() | SelectionKey.OP_READ);
+            }//end if
+        } else {
+            //unknown state, should never happen
+            log.warn("Data is in unknown state. readyOps="+ops);
+            throw new IOException("Data is in unknown state. readyOps="+ops);
+        }//end if
+        return false;
+    }
+    
+    
+
+    protected boolean read(SelectionKey key) throws IOException {
+        //if there is no message here, we are done
+        if ( current == null ) return true;
+        int read = socketChannel.read(readbuf);
+        //end of stream
+        if ( read == -1 ) throw new IOException("Unable to receive an ack message. EOF on socket channel has been reached.");
+        //no data read
+        else if ( read == 0 ) return false;
+        readbuf.flip();
+        ackbuf.append(readbuf,read);
+        readbuf.clear();
+        if (ackbuf.doesPackageExist() ) {
+            byte[] ackcmd = ackbuf.extractDataPackage(true).getBytes();
+            boolean ack = Arrays.equals(ackcmd,org.apache.catalina.tribes.transport.Constants.ACK_DATA);
+            boolean fack = Arrays.equals(ackcmd,org.apache.catalina.tribes.transport.Constants.FAIL_ACK_DATA);
+            if ( fack && getThrowOnFailedAck() ) throw new RemoteProcessException("Received a failed ack:org.apache.catalina.tribes.transport.Constants.FAIL_ACK_DATA");
+            return ack || fack;
+        } else {
+            return false;
+        }
+    }
+
+    
+    protected boolean write(SelectionKey key) throws IOException {
+        if ( (!isConnected()) || (this.socketChannel==null)) {
+            throw new IOException("NioSender is not connected, this should not occur.");
+        }
+        if ( current != null ) {
+            if ( remaining > 0 ) {
+                //weve written everything, or we are starting a new package
+                //protect against buffer overwrite
+                int byteswritten = socketChannel.write(writebuf);
+                remaining -= byteswritten;
+                //if the entire message was written from the buffer
+                //reset the position counter
+                if ( remaining < 0 ) {
+                    remaining = 0;
+                }
+            }
+            return (remaining==0);
+        }
+        //no message to send, we can consider that complete
+        return true;
+    }
+
+    /**
+     * connect - blocking in this operation
+     *
+     * @throws IOException
+     * @todo Implement this org.apache.catalina.tribes.transport.IDataSender method
+     */
+    public synchronized void connect() throws IOException {
+        if ( connecting ) return;
+        connecting = true;
+        if ( isConnected() ) throw new IOException("NioSender is already in connected state.");
+        if ( readbuf == null ) {
+            readbuf = getReadBuffer();
+        } else {
+            readbuf.clear();
+        }
+        if ( writebuf == null ) {
+            writebuf = getWriteBuffer();
+        } else {
+            writebuf.clear();
+        }
+        
+        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);
+        socketChannel.connect(addr);
+        socketChannel.register(getSelector(),SelectionKey.OP_CONNECT,this);
+    }
+    
+
+    /**
+     * disconnect
+     *
+     * @todo Implement this org.apache.catalina.tribes.transport.IDataSender method
+     */
+    public void disconnect() {
+        try {
+            connecting = false;
+            setConnected(false);
+            if ( socketChannel != null ) {
+                try {
+                    try {socketChannel.socket().close();}catch ( Exception x){}
+                    //error free close, all the way
+                    //try {socket.shutdownOutput();}catch ( Exception x){}
+                    //try {socket.shutdownInput();}catch ( Exception x){}
+                    //try {socket.close();}catch ( Exception x){}
+                    try {socketChannel.close();}catch ( Exception x){}
+                }finally {
+                    socketChannel = null;
+                }
+            }
+        } catch ( Exception x ) {
+            log.error("Unable to disconnect NioSender. msg="+x.getMessage());
+            if ( log.isDebugEnabled() ) log.debug("Unable to disconnect NioSender. msg="+x.getMessage(),x);
+        } finally {
+        }
+
+    }
+    
+    public void reset() {
+        if ( isConnected() && readbuf == null) {
+            readbuf = getReadBuffer();
+        }
+        if ( readbuf != null ) readbuf.clear();
+        if ( writebuf != null ) writebuf.clear();
+        current = null;
+        ackbuf.clear();
+        remaining = 0;
+        complete = false;
+        setAttempt(0);
+        setRequestCount(0);
+        setConnectTime(-1);
+    }
+
+    private ByteBuffer getReadBuffer() { 
+        return getBuffer(getRxBufSize());
+    }
+    
+    private ByteBuffer getWriteBuffer() {
+        return getBuffer(getTxBufSize());
+    }
+
+    private ByteBuffer getBuffer(int size) {
+        return (getDirectBuffer()?ByteBuffer.allocateDirect(size):ByteBuffer.allocate(size));
+    }
+    
+    /**
+    * sendMessage
+    *
+    * @param data ChannelMessage
+    * @throws IOException
+    * @todo Implement this org.apache.catalina.tribes.transport.IDataSender method
+    */
+   public synchronized void setMessage(byte[] data) throws IOException {
+       setMessage(data,0,data.length);
+   }
+
+   public synchronized void setMessage(byte[] data,int offset, int length) throws IOException {
+       if ( data != null ) {
+           current = data;
+           remaining = length;
+           ackbuf.clear();
+           if ( writebuf != null ) writebuf.clear();
+           else writebuf = getBuffer(length);
+           if ( writebuf.capacity() < length ) writebuf = getBuffer(length);
+           writebuf.put(data,offset,length);
+           //writebuf.rewind();
+           //set the limit so that we don't write non wanted data
+           //writebuf.limit(length);
+           writebuf.flip();
+           if (isConnected()) {
+               socketChannel.register(getSelector(), SelectionKey.OP_WRITE, this);
+           }
+       } 
+   }
+   
+   public byte[] getMessage() {
+       return current;
+   }
+
+
+
+    public boolean isComplete() {
+        return complete;
+    }
+
+    public Selector getSelector() {
+        return selector;
+    }
+
+    public void setSelector(Selector selector) {
+        this.selector = selector;
+    }
+
+
+    public void setComplete(boolean complete) {
+        this.complete = complete;
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/transport/nio/ParallelNioSender.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/transport/nio/ParallelNioSender.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/transport/nio/ParallelNioSender.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,288 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tribes.transport.nio;
+
+
+import java.io.IOException;
+import java.nio.channels.SelectionKey;
+import java.nio.channels.Selector;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import org.apache.catalina.tribes.ChannelException;
+import org.apache.catalina.tribes.ChannelMessage;
+import org.apache.catalina.tribes.Member;
+import org.apache.catalina.tribes.io.ChannelData;
+import org.apache.catalina.tribes.io.XByteBuffer;
+import org.apache.catalina.tribes.transport.MultiPointSender;
+import org.apache.catalina.tribes.transport.SenderState;
+import org.apache.catalina.tribes.transport.AbstractSender;
+import java.net.UnknownHostException;
+import org.apache.catalina.tribes.Channel;
+import org.apache.catalina.tribes.group.RpcChannel;
+import org.apache.catalina.tribes.util.Logs;
+import org.apache.catalina.tribes.UniqueId;
+
+/**
+ * <p>Title: </p>
+ *
+ * <p>Description: </p>
+ *
+ * <p>Copyright: Copyright (c) 2005</p>
+ *
+ * <p>Company: </p>
+ *
+ * @author not attributable
+ * @version 1.0
+ */
+public class ParallelNioSender extends AbstractSender implements MultiPointSender {
+    
+    protected static org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory.getLog(ParallelNioSender.class);
+    protected long selectTimeout = 5000; //default 5 seconds, same as send timeout
+    protected Selector selector;
+    protected HashMap nioSenders = new HashMap();
+
+    public ParallelNioSender() throws IOException {
+        selector = Selector.open();
+        setConnected(true);
+    }
+    
+    
+    public synchronized void sendMessage(Member[] destination, ChannelMessage msg) throws ChannelException {
+        long start = System.currentTimeMillis();
+        byte[] data = XByteBuffer.createDataPackage((ChannelData)msg);
+        NioSender[] senders = setupForSend(destination);
+        connect(senders);
+        setData(senders,data);
+        
+        int remaining = senders.length;
+        ChannelException cx = null;
+        try {
+            //loop until complete, an error happens, or we timeout
+            long delta = System.currentTimeMillis() - start;
+            boolean waitForAck = (Channel.SEND_OPTIONS_USE_ACK & msg.getOptions()) == Channel.SEND_OPTIONS_USE_ACK;
+            while ( (remaining>0) && (delta<getTimeout()) ) {
+                try {
+                    remaining -= doLoop(selectTimeout, getMaxRetryAttempts(),waitForAck,msg);
+                } catch (Exception x ) {
+                    if ( cx == null ) {
+                        if ( x instanceof ChannelException ) cx = (ChannelException)x;
+                        else cx = new ChannelException("Parallel NIO send failed.", x);
+                    } else {
+                        if (x instanceof ChannelException) cx.addFaultyMember( ( (ChannelException) x).getFaultyMembers());
+                    }
+                }
+                //bail out if all remaining senders are failing
+                if ( cx != null && cx.getFaultyMembers().length == remaining ) throw cx;
+                delta = System.currentTimeMillis() - start;
+            }
+            if ( remaining > 0 ) {
+                //timeout has occured
+                cx = new ChannelException("Operation has timed out("+getTimeout()+" ms.).");
+                for (int i=0; i<senders.length; i++ ) {
+                    if (!senders[i].isComplete() ) cx.addFaultyMember(senders[i].getDestination(),null);
+                }
+                throw cx;
+            }
+        } catch (Exception x ) {
+            try { this.disconnect(); } catch (Exception ignore) {}
+            if ( x instanceof ChannelException ) throw (ChannelException)x;
+            else throw new ChannelException(x);
+        }
+        
+    }
+    
+    private int doLoop(long selectTimeOut, int maxAttempts, boolean waitForAck, ChannelMessage msg) throws IOException, ChannelException {
+        int completed = 0;
+        int selectedKeys = selector.select(selectTimeOut);
+        
+        if (selectedKeys == 0) {
+            return 0;
+        }
+        
+        Iterator it = selector.selectedKeys().iterator();
+        while (it.hasNext()) {
+            SelectionKey sk = (SelectionKey) it.next();
+            it.remove();
+            int readyOps = sk.readyOps();
+            sk.interestOps(sk.interestOps() & ~readyOps);
+            NioSender sender = (NioSender) sk.attachment();
+            try {
+                if (sender.process(sk,waitForAck)) {
+                    completed++;
+                    sender.setComplete(true);
+                    if ( Logs.MESSAGES.isTraceEnabled() ) {
+                        Logs.MESSAGES.trace("ParallelNioSender - Sent msg:" + new UniqueId(msg.getUniqueId()) + " at " +new java.sql.Timestamp(System.currentTimeMillis())+ " to "+sender.getDestination().getName());
+                    }
+                    SenderState.getSenderState(sender.getDestination()).setReady();
+                }//end if
+            } catch (Exception x) {
+                SenderState state = SenderState.getSenderState(sender.getDestination());
+                int attempt = sender.getAttempt()+1;
+                boolean retry = (sender.getAttempt() <= maxAttempts && maxAttempts>0);
+                synchronized (state) {
+                
+                    //sk.cancel();
+                    if (state.isSuspect()) state.setFailing();
+                    if (state.isReady()) {
+                        state.setSuspect();
+                        if ( retry ) 
+                            log.warn("Member send is failing for:" + sender.getDestination().getName() +" ; Setting to suspect and retrying.");
+                        else 
+                            log.warn("Member send is failing for:" + sender.getDestination().getName() +" ; Setting to suspect.", x);
+                    }                    
+                }
+                if ( !isConnected() ) {
+                    log.warn("Not retrying send for:" + sender.getDestination().getName() + "; Sender is disconnected.");
+                    ChannelException cx = new ChannelException("Send failed, and sender is disconnected. Not retrying.",x);
+                    cx.addFaultyMember(sender.getDestination(),x);
+                    throw cx;
+                }
+                
+                byte[] data = sender.getMessage();
+                if ( retry ) {
+                    try { 
+                        sender.disconnect(); 
+                        sender.connect();
+                        sender.setAttempt(attempt);
+                        sender.setMessage(data);
+                    }catch ( Exception ignore){
+                        state.setFailing();
+                    }
+                } else {
+                    ChannelException cx = new ChannelException("Send failed, attempt:"+sender.getAttempt()+" max:"+maxAttempts,x);
+                    cx.addFaultyMember(sender.getDestination(),x);
+                    throw cx;
+                }//end if
+            }
+        }
+        return completed;
+
+    }
+    
+    private void connect(NioSender[] senders) throws ChannelException {
+        ChannelException x = null;
+        for (int i=0; i<senders.length; i++ ) {
+            try {
+                if (!senders[i].isConnected()) senders[i].connect();
+            }catch ( IOException io ) {
+                if ( x==null ) x = new ChannelException(io);
+                x.addFaultyMember(senders[i].getDestination(),io);
+            }
+        }
+        if ( x != null ) throw x;
+    }
+    
+    private void setData(NioSender[] senders, byte[] data) throws ChannelException {
+        ChannelException x = null;
+        for (int i=0; i<senders.length; i++ ) {
+            try {
+                senders[i].setMessage(data);
+            }catch ( IOException io ) {
+                if ( x==null ) x = new ChannelException(io);
+                x.addFaultyMember(senders[i].getDestination(),io);
+            }
+        }
+        if ( x != null ) throw x;
+    }
+    
+    
+    private NioSender[] setupForSend(Member[] destination) throws ChannelException {
+        ChannelException cx = null;
+        NioSender[] result = new NioSender[destination.length];
+        for ( int i=0; i<destination.length; i++ ) {
+            NioSender sender = (NioSender)nioSenders.get(destination[i]);
+            try {
+
+                if (sender == null) {
+                    sender = new NioSender();
+                    sender.transferProperties(this, sender);
+                    nioSenders.put(destination[i], sender);
+                }
+                if (sender != null) {
+                    sender.reset();
+                    sender.setDestination(destination[i]);
+                    sender.setSelector(selector);
+                    result[i] = sender;
+                }
+            }catch ( UnknownHostException x ) {
+                if (cx == null) cx = new ChannelException("Unable to setup NioSender.", x);
+                cx.addFaultyMember(destination[i], x);
+            }
+        }
+        if ( cx != null ) throw cx;
+        else return result;
+    }
+    
+    public void connect() {
+        //do nothing, we connect on demand
+        setConnected(true);
+    }
+    
+    
+    private synchronized void close() throws ChannelException  {
+        ChannelException x = null;
+        Object[] members = nioSenders.keySet().toArray();
+        for (int i=0; i<members.length; i++ ) {
+            Member mbr = (Member)members[i];
+            try {
+                NioSender sender = (NioSender)nioSenders.get(mbr);
+                sender.disconnect();
+            }catch ( Exception e ) {
+                if ( x == null ) x = new ChannelException(e);
+                x.addFaultyMember(mbr,e);
+            }
+            nioSenders.remove(mbr);
+        }
+        if ( x != null ) throw x;
+    }
+    
+    public void memberAdded(Member member) {
+        
+    }
+    
+    public void memberDisappeared(Member member) {
+        //disconnect senders
+        NioSender sender = (NioSender)nioSenders.remove(member);
+        if ( sender != null ) sender.disconnect();
+    }
+
+    
+    public synchronized void disconnect() {
+        setConnected(false);
+        try {close(); }catch (Exception x){}
+        
+    }
+    
+    public void finalize() {
+        try {disconnect(); }catch ( Exception ignore){}
+    }
+
+    public boolean keepalive() {
+        //throw new UnsupportedOperationException("Method ParallelNioSender.checkKeepAlive() not implemented");
+        boolean result = false;
+        for ( Iterator i = nioSenders.entrySet().iterator(); i.hasNext();  ) {
+            Map.Entry entry = (Map.Entry)i.next();
+            NioSender sender = (NioSender)entry.getValue();
+            if ( sender.keepalive() ) {
+                nioSenders.remove(entry.getKey());
+            }
+        }
+        return result;
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/transport/nio/PooledParallelSender.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/transport/nio/PooledParallelSender.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/transport/nio/PooledParallelSender.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,84 @@
+/*
+ * Copyright 1999,2004-2006 The Apache Software Foundation.
+ *
+ * Licensed 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.tribes.transport.nio;
+
+import java.io.IOException;
+
+import org.apache.catalina.tribes.ChannelException;
+import org.apache.catalina.tribes.ChannelMessage;
+import org.apache.catalina.tribes.Member;
+import org.apache.catalina.tribes.transport.DataSender;
+import org.apache.catalina.tribes.transport.MultiPointSender;
+import org.apache.catalina.tribes.transport.PooledSender;
+
+/**
+ * <p>Title: </p>
+ *
+ * <p>Description: </p>
+ *
+ * <p>Copyright: Copyright (c) 2005</p>
+ *
+ * <p>Company: </p>
+ *
+ * @author not attributable
+ * @version 1.0
+ */
+public class PooledParallelSender extends PooledSender implements MultiPointSender {
+    protected boolean connected = true;
+    public PooledParallelSender() {
+        super();
+    }
+    
+    public void sendMessage(Member[] destination, ChannelMessage message) throws ChannelException {
+        if ( !connected ) throw new ChannelException("Sender not connected.");
+        ParallelNioSender sender = (ParallelNioSender)getSender();
+        try {
+            sender.sendMessage(destination, message);
+            sender.keepalive();
+        }finally {
+            if ( !connected ) disconnect();
+            returnSender(sender);
+        }
+    }
+
+    public DataSender getNewDataSender() {
+        try {
+            ParallelNioSender sender = new ParallelNioSender();
+            sender.transferProperties(this,sender);
+            return sender;
+        } catch ( IOException x ) {
+            throw new RuntimeException("Unable to open NIO selector.",x);
+        }
+    }
+    
+    public synchronized void disconnect() {
+        this.connected = false;
+        super.disconnect();
+    }
+
+    public synchronized void connect() throws IOException {
+        this.connected = true;
+        super.connect();
+    }
+
+    public void memberAdded(Member member) {
+    
+    }
+    
+    public void memberDisappeared(Member member) {
+        //disconnect senders
+    }    
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/util/Arrays.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/util/Arrays.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/util/Arrays.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,195 @@
+/*
+ * Copyright 1999,2004-2006 The Apache Software Foundation.
+ *
+ * Licensed 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.tribes.util;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.catalina.tribes.ChannelMessage;
+import org.apache.catalina.tribes.Member;
+import org.apache.catalina.tribes.UniqueId;
+import org.apache.catalina.tribes.group.AbsoluteOrder;
+import org.apache.catalina.tribes.membership.MemberImpl;
+import org.apache.catalina.tribes.membership.Membership;
+
+/**
+ * @author Filip Hanik
+ * @version 1.0
+ */
+public class Arrays {
+
+    public static boolean contains(byte[] source, int srcoffset, byte[] key, int keyoffset, int length) {
+        if ( srcoffset < 0 || srcoffset >= source.length) throw new ArrayIndexOutOfBoundsException("srcoffset is out of bounds.");
+        if ( keyoffset < 0 || keyoffset >= key.length) throw new ArrayIndexOutOfBoundsException("keyoffset is out of bounds.");
+        if ( length > (key.length-keyoffset) ) throw new ArrayIndexOutOfBoundsException("not enough data elements in the key, length is out of bounds.");
+        //we don't have enough data to validate it
+        if ( length > (source.length-srcoffset) ) return false;
+        boolean match = true;
+        int pos = keyoffset;
+        for ( int i=srcoffset; match && i<length; i++ ) {
+            match = (source[i] == key[pos++]);
+        }
+        return match;
+    }
+    
+    public static String toString(byte[] data) {
+        return toString(data,0,data!=null?data.length:0);
+    }
+
+    public static String toString(byte[] data, int offset, int length) {
+        StringBuffer buf = new StringBuffer("{");
+        if ( data != null && length > 0 ) {
+            buf.append(data[offset++]);
+            for (int i = offset; i < length; i++) {
+                buf.append(", ").append(data[i]);
+            }
+        }
+        buf.append("}");
+        return buf.toString();
+    }
+    
+    public static String toString(Object[] data) {
+        return toString(data,0,data!=null?data.length:0);
+    }
+    
+    public static String toString(Object[] data, int offset, int length) {
+        StringBuffer buf = new StringBuffer("{");
+        if ( data != null && length > 0 ) {
+            buf.append(data[offset++]);
+            for (int i = offset; i < length; i++) {
+                buf.append(", ").append(data[i]);
+            }
+        }
+        buf.append("}");
+        return buf.toString();
+    }
+    
+    public static String toNameString(Member[] data) {
+        return toNameString(data,0,data!=null?data.length:0);
+    }
+    
+    public static String toNameString(Member[] data, int offset, int length) {
+        StringBuffer buf = new StringBuffer("{");
+        if ( data != null && length > 0 ) {
+            buf.append(data[offset++].getName());
+            for (int i = offset; i < length; i++) {
+                buf.append(", ").append(data[i].getName());
+            }
+        }
+        buf.append("}");
+        return buf.toString();
+    }
+
+    public static int add(int[] data) {
+        int result = 0;
+        for (int i=0;i<data.length; i++ ) result += data[i];
+        return result;
+    }
+    
+    public static UniqueId getUniqudId(ChannelMessage msg) {
+        return new UniqueId(msg.getUniqueId());
+    }
+
+    public static UniqueId getUniqudId(byte[] data) {
+        return new UniqueId(data);
+    }
+    
+    public static boolean equals(byte[] o1, byte[] o2) {
+        return java.util.Arrays.equals(o1,o2);
+    }
+
+    public static boolean equals(Object[] o1, Object[] o2) {
+        boolean result = o1.length == o2.length;
+        if ( result ) for (int i=0; i<o1.length && result; i++ ) result = o1[i].equals(o2[i]);
+        return result;
+    }
+    
+    public static boolean sameMembers(Member[] m1, Member[] m2) {
+        AbsoluteOrder.absoluteOrder(m1);
+        AbsoluteOrder.absoluteOrder(m2);
+        return equals(m1,m2);
+    }
+    
+    public static Member[] merge(Member[] m1, Member[] m2) {
+        AbsoluteOrder.absoluteOrder(m1);
+        AbsoluteOrder.absoluteOrder(m2);
+        ArrayList list = new ArrayList(java.util.Arrays.asList(m1));
+        for (int i=0; i<m2.length; i++) if ( !list.contains(m2[i]) ) list.add(m2[i]);
+        Member[] result = new Member[list.size()];
+        list.toArray(result);
+        AbsoluteOrder.absoluteOrder(result);
+        return result;
+    }
+    
+    public static void fill(Membership mbrship, Member[] m) {
+        for (int i=0; i<m.length; i++ ) mbrship.addMember((MemberImpl)m[i]);
+    }
+    
+    public static Member[] diff(Membership complete, Membership local, MemberImpl ignore) {
+        ArrayList result = new ArrayList();
+        MemberImpl[] comp = complete.getMembers();
+        for ( int i=0; i<comp.length; i++ ) {
+            if ( ignore!=null && ignore.equals(comp[i]) ) continue;
+            if ( local.getMember(comp[i]) == null ) result.add(comp[i]);
+        }
+        return (MemberImpl[])result.toArray(new MemberImpl[result.size()]);
+    }
+    
+    public static Member[] remove(Member[] all, Member remove) {
+        return extract(all,new Member[] {remove});
+    }
+    
+    public static Member[] extract(Member[] all, Member[] remove) {
+        List alist = java.util.Arrays.asList(all);
+        ArrayList list = new ArrayList(alist);
+        for (int i=0; i<remove.length; i++ ) list.remove(remove[i]);
+        return (Member[])list.toArray(new Member[list.size()]);
+    }
+    
+    public static int indexOf(Member member, Member[] members) {
+        int result = -1;
+        for (int i=0; (result==-1) && (i<members.length); i++ ) 
+            if ( member.equals(members[i]) ) result = i;
+        return result;
+    }
+    
+    public static int nextIndex(Member member, Member[] members) {
+        int idx = indexOf(member,members)+1;
+        if (idx >= members.length ) idx = ((members.length>0)?0:-1);
+        
+//System.out.println("Next index:"+idx);
+//System.out.println("Member:"+member.getName());
+//System.out.println("Members:"+toNameString(members));
+        return idx;
+    }
+    
+    public static int hashCode(byte a[]) {
+        if (a == null)
+            return 0;
+
+        int result = 1;
+        for (int i=0; i<a.length; i++) {
+            byte element = a[i];
+            result = 31 * result + element;
+        }
+        return result;
+    }
+
+
+    
+    
+    
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/util/Logs.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/util/Logs.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/util/Logs.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,28 @@
+/*
+ * Copyright 1999,2004-2005 The Apache Software Foundation.
+ * 
+ * Licensed 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.tribes.util;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+/**
+ * 
+ * Simple class that holds references to global loggers
+ * @author Filip Hanik
+ * @version 1.0
+ */
+public class Logs {
+    public static Log MESSAGES = LogFactory.getLog( "org.apache.catalina.tribes.MESSAGES" );
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/util/StringManager.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/util/StringManager.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/util/StringManager.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,252 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tribes.util;
+
+import java.text.MessageFormat;
+import java.util.Hashtable;
+import java.util.Locale;
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+import java.net.URLClassLoader;
+
+/**
+ * An internationalization / localization helper class which reduces
+ * the bother of handling ResourceBundles and takes care of the
+ * common cases of message formating which otherwise require the
+ * creation of Object arrays and such.
+ *
+ * <p>The StringManager operates on a package basis. One StringManager
+ * per package can be created and accessed via the getManager method
+ * call.
+ *
+ * <p>The StringManager will look for a ResourceBundle named by
+ * the package name given plus the suffix of "LocalStrings". In
+ * practice, this means that the localized information will be contained
+ * in a LocalStrings.properties file located in the package
+ * directory of the classpath.
+ *
+ * <p>Please see the documentation for java.util.ResourceBundle for
+ * more information.
+ *
+ * @author James Duncan Davidson [duncan at eng.sun.com]
+ * @author James Todd [gonzo at eng.sun.com]
+ */
+
+public class StringManager {
+
+    /**
+     * The ResourceBundle for this StringManager.
+     */
+
+    private ResourceBundle bundle;
+
+    private static org.apache.commons.logging.Log log=
+        org.apache.commons.logging.LogFactory.getLog( StringManager.class );
+
+    /**
+     * Creates a new StringManager for a given package. This is a
+     * private method and all access to it is arbitrated by the
+     * static getManager method call so that only one StringManager
+     * per package will be created.
+     *
+     * @param packageName Name of package to create StringManager for.
+     */
+
+    private StringManager(String packageName) {
+        String bundleName = packageName + ".LocalStrings";
+        try {
+            bundle = ResourceBundle.getBundle(bundleName);
+            return;
+        } catch( MissingResourceException ex ) {
+            // Try from the current loader ( that's the case for trusted apps )
+            ClassLoader cl=Thread.currentThread().getContextClassLoader();
+            if( cl != null ) {
+                try {
+                    bundle=ResourceBundle.getBundle(bundleName, Locale.getDefault(), cl);
+                    return;
+                } catch(MissingResourceException ex2) {
+                }
+            }
+            if( cl==null )
+                cl=this.getClass().getClassLoader();
+
+            if (log.isDebugEnabled())
+                log.debug("Can't find resource " + bundleName +
+                    " " + cl);
+            if( cl instanceof URLClassLoader ) {
+                if (log.isDebugEnabled()) 
+                    log.debug( ((URLClassLoader)cl).getURLs());
+            }
+        }
+    }
+
+    /**
+     * Get a string from the underlying resource bundle.
+     *
+     * @param key The resource name
+     */
+    public String getString(String key) {
+        return MessageFormat.format(getStringInternal(key), (Object [])null);
+    }
+
+
+    protected String getStringInternal(String key) {
+        if (key == null) {
+            String msg = "key is null";
+
+            throw new NullPointerException(msg);
+        }
+
+        String str = null;
+
+        if( bundle==null )
+            return key;
+        try {
+            str = bundle.getString(key);
+        } catch (MissingResourceException mre) {
+            str = "Cannot find message associated with key '" + key + "'";
+        }
+
+        return str;
+    }
+
+    /**
+     * Get a string from the underlying resource bundle and format
+     * it with the given set of arguments.
+     *
+     * @param key The resource name
+     * @param args Formatting directives
+     */
+
+    public String getString(String key, Object[] args) {
+        String iString = null;
+        String value = getStringInternal(key);
+
+        // this check for the runtime exception is some pre 1.1.6
+        // VM's don't do an automatic toString() on the passed in
+        // objects and barf out
+
+        try {
+            // ensure the arguments are not null so pre 1.2 VM's don't barf
+            Object nonNullArgs[] = args;
+            for (int i=0; i<args.length; i++) {
+                if (args[i] == null) {
+                    if (nonNullArgs==args) nonNullArgs=(Object[])args.clone();
+                    nonNullArgs[i] = "null";
+                }
+            }
+
+            iString = MessageFormat.format(value, nonNullArgs);
+        } catch (IllegalArgumentException iae) {
+            StringBuffer buf = new StringBuffer();
+            buf.append(value);
+            for (int i = 0; i < args.length; i++) {
+                buf.append(" arg[" + i + "]=" + args[i]);
+            }
+            iString = buf.toString();
+        }
+        return iString;
+    }
+
+    /**
+     * Get a string from the underlying resource bundle and format it
+     * with the given object argument. This argument can of course be
+     * a String object.
+     *
+     * @param key The resource name
+     * @param arg Formatting directive
+     */
+
+    public String getString(String key, Object arg) {
+        Object[] args = new Object[] {arg};
+        return getString(key, args);
+    }
+
+    /**
+     * Get a string from the underlying resource bundle and format it
+     * with the given object arguments. These arguments can of course
+     * be String objects.
+     *
+     * @param key The resource name
+     * @param arg1 Formatting directive
+     * @param arg2 Formatting directive
+     */
+
+    public String getString(String key, Object arg1, Object arg2) {
+        Object[] args = new Object[] {arg1, arg2};
+        return getString(key, args);
+    }
+
+    /**
+     * Get a string from the underlying resource bundle and format it
+     * with the given object arguments. These arguments can of course
+     * be String objects.
+     *
+     * @param key The resource name
+     * @param arg1 Formatting directive
+     * @param arg2 Formatting directive
+     * @param arg3 Formatting directive
+     */
+
+    public String getString(String key, Object arg1, Object arg2,
+                            Object arg3) {
+        Object[] args = new Object[] {arg1, arg2, arg3};
+        return getString(key, args);
+    }
+
+    /**
+     * Get a string from the underlying resource bundle and format it
+     * with the given object arguments. These arguments can of course
+     * be String objects.
+     *
+     * @param key The resource name
+     * @param arg1 Formatting directive
+     * @param arg2 Formatting directive
+     * @param arg3 Formatting directive
+     * @param arg4 Formatting directive
+     */
+
+    public String getString(String key, Object arg1, Object arg2,
+                            Object arg3, Object arg4) {
+        Object[] args = new Object[] {arg1, arg2, arg3, arg4};
+        return getString(key, args);
+    }
+    // --------------------------------------------------------------
+    // STATIC SUPPORT METHODS
+    // --------------------------------------------------------------
+
+    private static Hashtable managers = new Hashtable();
+
+    /**
+     * Get the StringManager for a particular package. If a manager for
+     * a package already exists, it will be reused, else a new
+     * StringManager will be created and returned.
+     *
+     * @param packageName The package name
+     */
+
+    public synchronized static StringManager getManager(String packageName) {
+        StringManager mgr = (StringManager)managers.get(packageName);
+
+        if (mgr == null) {
+            mgr = new StringManager(packageName);
+            managers.put(packageName, mgr);
+        }
+        return mgr;
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/util/UUIDGenerator.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/util/UUIDGenerator.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/src/share/org/apache/catalina/tribes/util/UUIDGenerator.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,76 @@
+/*
+ * Copyright 1999,2006 The Apache Software Foundation.
+ * 
+ * Licensed 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.tribes.util;
+
+import java.security.SecureRandom;
+import java.util.Random;
+
+/**
+ * simple generation of a UUID 
+ * @author Filip Hanik
+ * @version 1.0
+ */
+public class UUIDGenerator {
+    public static final int UUID_LENGTH = 16;
+    public static final int UUID_VERSION = 4;
+    public static final int BYTES_PER_INT = 4;
+    public static final int BITS_PER_BYTE = 8;
+    
+    protected static SecureRandom secrand = null;
+    protected static Random rand = new Random(System.currentTimeMillis());
+    static {
+        secrand = new SecureRandom();
+        secrand.setSeed(rand.nextLong());
+    }
+    
+    public static byte[] randomUUID(boolean secure) {
+        byte[] result = new byte[UUID_LENGTH];
+        return randomUUID(secure,result,0);
+    }
+
+    public static byte[] randomUUID(boolean secure, byte[] into, int offset) {
+        if ( (offset+UUID_LENGTH)>into.length )
+            throw new ArrayIndexOutOfBoundsException("Unable to fit "+UUID_LENGTH+" bytes into the array. length:"+into.length+" required length:"+(offset+UUID_LENGTH));
+        Random r = (secure&&(secrand!=null))?secrand:rand;
+        nextBytes(into,offset,UUID_LENGTH,r);
+        into[6+offset] &= 0x0F;
+        into[6+offset] |= (UUID_VERSION << 4);
+        into[8+offset] &= 0x3F; //0011 1111
+        into[8+offset] |= 0x80; //1000 0000
+        return into;
+    }
+    
+    /**
+     * Same as java.util.Random.nextBytes except this one we dont have to allocate a new byte array
+     * @param into byte[]
+     * @param offset int
+     * @param length int
+     * @param r Random
+     */
+    public static void nextBytes(byte[] into, int offset, int length, Random r) {
+        int numRequested = length;
+        int numGot = 0, rnd = 0;
+        while (true) {
+            for (int i = 0; i < BYTES_PER_INT; i++) {
+                if (numGot == numRequested) return;
+                rnd = (i == 0 ? r.nextInt() : rnd >> BITS_PER_BYTE);
+                into[offset+numGot] = (byte) rnd;
+                numGot++;
+            }
+        }
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/test/java/org/apache/catalina/tribes/demos/ChannelCreator.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/test/java/org/apache/catalina/tribes/demos/ChannelCreator.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/test/java/org/apache/catalina/tribes/demos/ChannelCreator.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,253 @@
+/*
+ * Copyright 1999,2004-2006 The Apache Software Foundation.
+ *
+ * Licensed 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.tribes.demos;
+
+import java.util.Iterator;
+import java.util.Properties;
+
+import org.apache.catalina.tribes.Channel;
+import org.apache.catalina.tribes.ManagedChannel;
+import org.apache.catalina.tribes.group.GroupChannel;
+import org.apache.catalina.tribes.group.interceptors.FragmentationInterceptor;
+import org.apache.catalina.tribes.group.interceptors.GzipInterceptor;
+import org.apache.catalina.tribes.group.interceptors.MessageDispatchInterceptor;
+import org.apache.catalina.tribes.group.interceptors.OrderInterceptor;
+import org.apache.catalina.tribes.membership.McastService;
+import org.apache.catalina.tribes.transport.MultiPointSender;
+import org.apache.catalina.tribes.transport.ReceiverBase;
+import org.apache.catalina.tribes.transport.ReplicationTransmitter;
+import org.apache.catalina.tribes.group.interceptors.ThroughputInterceptor;
+import org.apache.catalina.tribes.group.interceptors.MessageDispatch15Interceptor;
+import org.apache.catalina.tribes.group.interceptors.TcpFailureDetector;
+import org.apache.catalina.tribes.group.interceptors.DomainFilterInterceptor;
+import java.util.ArrayList;
+import org.apache.catalina.tribes.membership.MemberImpl;
+import org.apache.catalina.tribes.group.interceptors.StaticMembershipInterceptor;
+import org.apache.catalina.tribes.Member;
+
+/**
+ * <p>Title: </p>
+ *
+ * <p>Description: </p>
+ *
+ *
+ * <p>Company: </p>
+ *
+ * @author fhanik
+ * @version 1.0
+ */
+public class ChannelCreator {
+    
+    org.apache.commons.logging.impl.LogFactoryImpl impl=null;
+    public static StringBuffer usage() {
+        StringBuffer buf = new StringBuffer();
+        buf.append("\n\t\t[-bind tcpbindaddress]")
+           .append("\n\t\t[-tcpselto tcpselectortimeout]") 
+           .append("\n\t\t[-tcpthreads tcpthreadcount]") 
+           .append("\n\t\t[-port tcplistenport]")
+           .append("\n\t\t[-autobind tcpbindtryrange]")
+           .append("\n\t\t[-ackto acktimeout]") 
+           .append("\n\t\t[-receiver org.apache.catalina.tribes.transport.nio.NioReceiver|org.apache.catalina.tribes.transport.bio.BioReceiver|]")
+           .append("\n\t\t[-transport org.apache.catalina.tribes.transport.nio.PooledParallelSender|org.apache.catalina.tribes.transport.bio.PooledMultiSender]")
+           .append("\n\t\t[-transport.xxx transport specific property]")
+           .append("\n\t\t[-maddr multicastaddr]")
+           .append("\n\t\t[-mport multicastport]")
+           .append("\n\t\t[-mbind multicastbindaddr]")
+           .append("\n\t\t[-mfreq multicastfrequency]")
+           .append("\n\t\t[-mdrop multicastdroptime]")
+           .append("\n\t\t[-gzip]")
+           .append("\n\t\t[-static hostname:port (-static localhost:9999 -static 127.0.0.1:8888 can be repeated)]")
+           .append("\n\t\t[-order]")
+           .append("\n\t\t[-ordersize maxorderqueuesize]")
+           .append("\n\t\t[-frag]")
+           .append("\n\t\t[-fragsize maxmsgsize]")
+           .append("\n\t\t[-throughput]")
+           .append("\n\t\t[-failuredetect]")
+           .append("\n\t\t[-async]")
+           .append("\n\t\t[-asyncsize maxqueuesizeinkilobytes]");
+       return buf;
+
+    }
+
+    public static Channel createChannel(String[] args) throws Exception {
+        String bind = "auto";
+        int port = 4001;
+        String mbind = null;
+        boolean gzip = false;
+        int tcpseltimeout = 5000;
+        int tcpthreadcount = 4;
+        int acktimeout = 15000;
+        String mcastaddr = "228.0.0.5";
+        int mcastport = 45565;
+        long mcastfreq = 500;
+        long mcastdrop = 2000;
+        boolean order = false;
+        int ordersize = Integer.MAX_VALUE;
+        boolean frag = false;
+        int fragsize = 1024;
+        int autoBind = 10;
+        ArrayList staticMembers = new ArrayList();
+        Properties transportProperties = new Properties();
+        String transport = "org.apache.catalina.tribes.transport.nio.PooledParallelSender";
+        String receiver = "org.apache.catalina.tribes.transport.nio.NioReceiver";
+        boolean async = false;
+        int asyncsize = 1024*1024*50; //50MB
+        boolean throughput = false;
+        boolean failuredetect = false;
+        
+        for (int i = 0; i < args.length; i++) {
+            if ("-bind".equals(args[i])) {
+                bind = args[++i];
+            } else if ("-port".equals(args[i])) {
+                port = Integer.parseInt(args[++i]);
+            } else if ("-autobind".equals(args[i])) {
+                autoBind = Integer.parseInt(args[++i]);
+            } else if ("-tcpselto".equals(args[i])) {
+                tcpseltimeout = Integer.parseInt(args[++i]);
+            } else if ("-tcpthreads".equals(args[i])) {
+                tcpthreadcount = Integer.parseInt(args[++i]);
+            } else if ("-gzip".equals(args[i])) {
+                gzip = true;
+            } else if ("-async".equals(args[i])) {
+                async = true;
+            } else if ("-failuredetect".equals(args[i])) {
+                failuredetect = true;
+            } else if ("-asyncsize".equals(args[i])) {
+                asyncsize = Integer.parseInt(args[++i]);
+                System.out.println("Setting MessageDispatchInterceptor.maxQueueSize="+asyncsize);
+            } else if ("-static".equals(args[i])) {
+                String d = args[++i];
+                String h = d.substring(0,d.indexOf(":"));
+                String p = d.substring(h.length()+1);
+                MemberImpl m = new MemberImpl(h,Integer.parseInt(p),2000);
+                staticMembers.add(m);
+            } else if ("-throughput".equals(args[i])) {
+                throughput = true;
+            } else if ("-order".equals(args[i])) {
+                order = true;
+            } else if ("-ordersize".equals(args[i])) {
+                ordersize = Integer.parseInt(args[++i]);
+                System.out.println("Setting OrderInterceptor.maxQueue="+ordersize);
+            } else if ("-frag".equals(args[i])) {
+                frag = true;
+            } else if ("-fragsize".equals(args[i])) {
+                fragsize = Integer.parseInt(args[++i]);
+                System.out.println("Setting FragmentationInterceptor.maxSize="+fragsize);
+            } else if ("-ackto".equals(args[i])) {
+                acktimeout = Integer.parseInt(args[++i]);
+            } else if ("-transport".equals(args[i])) {
+                transport = args[++i];
+            } else if (args[i]!=null && args[i].startsWith("transport.")) {
+                String key = args[i];
+                String val = args[++i];
+                transportProperties.setProperty(key,val);
+            } else if ("-receiver".equals(args[i])) {
+                receiver = args[++i];
+            } else if ("-maddr".equals(args[i])) {
+                mcastaddr = args[++i];
+            } else if ("-mport".equals(args[i])) {
+                mcastport = Integer.parseInt(args[++i]);
+            } else if ("-mfreq".equals(args[i])) {
+                mcastfreq = Long.parseLong(args[++i]);
+            } else if ("-mdrop".equals(args[i])) {
+                mcastdrop = Long.parseLong(args[++i]);
+            } else if ("-mbind".equals(args[i])) {
+                mbind = args[++i];
+            }
+        }
+        
+        System.out.println("Creating receiver class="+receiver);
+        Class cl = Class.forName(receiver,true,ChannelCreator.class.getClassLoader());
+        ReceiverBase rx = (ReceiverBase)cl.newInstance();
+        rx.setTcpListenAddress(bind);
+        rx.setTcpListenPort(port);
+        rx.setTcpSelectorTimeout(tcpseltimeout);
+        rx.setTcpThreadCount(tcpthreadcount);
+        rx.getBind();
+        rx.setRxBufSize(43800);
+        rx.setTxBufSize(25188);
+        rx.setAutoBind(autoBind);
+
+        
+        ReplicationTransmitter ps = new ReplicationTransmitter();
+        System.out.println("Creating transport class="+transport);
+        MultiPointSender sender = (MultiPointSender)Class.forName(transport,true,ChannelCreator.class.getClassLoader()).newInstance();
+        sender.setTimeout(acktimeout);
+        sender.setMaxRetryAttempts(2);
+        sender.setRxBufSize(43800);
+        sender.setTxBufSize(25188);
+
+        Iterator i = transportProperties.keySet().iterator();
+        while ( i.hasNext() ) {
+            String key = (String)i.next();
+            IntrospectionUtils.setProperty(sender,key,transportProperties.getProperty(key));
+        }
+        ps.setTransport(sender);
+
+        McastService service = new McastService();
+        service.setMcastAddr(mcastaddr);
+        if (mbind != null) service.setMcastBindAddress(mbind);
+        service.setMcastFrequency(mcastfreq);
+        service.setMcastDropTime(mcastdrop);
+        service.setMcastPort(mcastport);
+
+        ManagedChannel channel = new GroupChannel();
+        channel.setChannelReceiver(rx);
+        channel.setChannelSender(ps);
+        channel.setMembershipService(service);
+        
+        if ( throughput ) channel.addInterceptor(new ThroughputInterceptor());
+        if (gzip) channel.addInterceptor(new GzipInterceptor());
+        if ( frag ) {
+            FragmentationInterceptor fi = new FragmentationInterceptor();
+            fi.setMaxSize(fragsize);
+            channel.addInterceptor(fi);
+        }
+        if (order) {
+            OrderInterceptor oi = new OrderInterceptor();
+            oi.setMaxQueue(ordersize);
+            channel.addInterceptor(oi);
+        }
+        
+        if ( async ) {
+            MessageDispatchInterceptor mi = new MessageDispatch15Interceptor();
+            mi.setMaxQueueSize(asyncsize);
+            channel.addInterceptor(mi);
+            System.out.println("Added MessageDispatchInterceptor");
+        }
+        
+        if ( failuredetect ) {
+            TcpFailureDetector tcpfi = new TcpFailureDetector();
+            channel.addInterceptor(tcpfi);
+        }
+        if ( staticMembers.size() > 0 ) {
+            StaticMembershipInterceptor smi = new StaticMembershipInterceptor();
+            for (int x=0; x<staticMembers.size(); x++ ) {
+                smi.addStaticMember((Member)staticMembers.get(x));
+            }
+            channel.addInterceptor(smi);
+        }
+
+
+        byte[] domain = new byte[] {1,2,3,4,5,6,7,8,9,0};
+        ((McastService)channel.getMembershipService()).setDomain(domain);
+        DomainFilterInterceptor filter = new DomainFilterInterceptor();
+        filter.setDomain(domain);
+        channel.addInterceptor(filter);
+        return channel;
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/test/java/org/apache/catalina/tribes/demos/CoordinationDemo.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/test/java/org/apache/catalina/tribes/demos/CoordinationDemo.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/test/java/org/apache/catalina/tribes/demos/CoordinationDemo.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,348 @@
+package org.apache.catalina.tribes.demos;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.util.StringTokenizer;
+
+import org.apache.catalina.tribes.ChannelInterceptor;
+import org.apache.catalina.tribes.ChannelInterceptor.InterceptorEvent;
+import org.apache.catalina.tribes.Member;
+import org.apache.catalina.tribes.group.GroupChannel;
+import org.apache.catalina.tribes.group.interceptors.MessageDispatch15Interceptor;
+import org.apache.catalina.tribes.group.interceptors.NonBlockingCoordinator;
+import org.apache.catalina.tribes.group.interceptors.TcpFailureDetector;
+import org.apache.catalina.tribes.transport.ReceiverBase;
+import org.apache.catalina.tribes.util.Arrays;
+
+
+
+public class CoordinationDemo {
+    static int CHANNEL_COUNT = 5;
+    static int SCREEN_WIDTH = 120;
+    static long SLEEP_TIME = 10;
+    static int CLEAR_SCREEN = 30;
+    static boolean MULTI_THREAD = false;
+    static boolean[] VIEW_EVENTS = new boolean[255];
+    StringBuffer statusLine = new StringBuffer();
+    Status[] status = null;
+    BufferedReader reader = null;
+    /**
+     * Construct and show the application.
+     */
+    public CoordinationDemo() {
+    }
+    
+    public void init() {
+        reader = new BufferedReader(new InputStreamReader(System.in));
+        status = new Status[CHANNEL_COUNT];
+    }
+    
+    
+    public void clearScreen() {
+        StringBuffer buf = new StringBuffer(700);
+        for (int i=0; i<CLEAR_SCREEN; i++ ) buf.append("\n");
+        System.out.println(buf);
+    }
+
+    public void printMenuOptions() {
+        System.out.println("Commands:");
+        System.out.println("\tstart [member id]");
+        System.out.println("\tstop  [member id]");
+        System.out.println("\tprint (refresh)");
+        System.out.println("\tquit");
+        System.out.print("Enter command:");
+    }
+    
+    public synchronized void printScreen() {
+        clearScreen();
+        System.out.println(" ###."+getHeader());
+        for ( int i=0; i<status.length; i++ ) {
+            System.out.print(leftfill(String.valueOf(i+1)+".",5," "));
+            if ( status[i] != null ) System.out.print(status[i].getStatusLine());
+        }
+        System.out.println("\n\n");
+        System.out.println("Overall status:"+statusLine);
+        printMenuOptions();
+        
+    }
+    
+    public String getHeader() {
+        //member - 30
+        //running- 10
+        //coord - 30
+        //view-id - 24
+        //view count - 8
+
+        StringBuffer buf = new StringBuffer();
+        buf.append(leftfill("Member",30," "));
+        buf.append(leftfill("Running",10," "));
+        buf.append(leftfill("Coord",30," "));
+        buf.append(leftfill("View-id(short)",24," "));
+        buf.append(leftfill("Count",8," "));
+        buf.append("\n");
+        
+        buf.append(rightfill("==="+new java.sql.Timestamp(System.currentTimeMillis()).toString(),SCREEN_WIDTH,"="));
+        buf.append("\n");
+        return buf.toString();
+    }
+    
+    public String[] tokenize(String line) {
+        StringTokenizer tz = new StringTokenizer(line," ");
+        String[] result = new String[tz.countTokens()];
+        for (int i=0; i<result.length; i++ ) result[i] = tz.nextToken();
+        return result;
+    }
+    
+    public void waitForInput() throws IOException {
+        for ( int i=0; i<status.length; i++ ) status[i] = new Status(this);
+        printScreen();
+        String l = reader.readLine();
+        String[] args = tokenize(l);
+        while ( args.length >= 1 && (!"quit".equalsIgnoreCase(args[0]))) {
+            if ("start".equalsIgnoreCase(args[0])) {
+                cmdStart(args);
+            } else if ("stop".equalsIgnoreCase(args[0])) {
+                cmdStop(args);
+
+            }
+            printScreen();
+            l = reader.readLine();
+            args = tokenize(l);
+        }
+        for ( int i=0; i<status.length; i++ ) status[i].stop();
+    }
+
+    private void cmdStop(String[] args) {
+        if ( args.length == 1 ) {
+            setSystemStatus("System shutting down...");
+            Thread[] t = new Thread[CHANNEL_COUNT];
+            for (int i = 0; i < status.length; i++) {
+                final int j = i;
+                t[j] = new Thread() {
+                    public void run() {
+                        status[j].stop();
+                    }
+                };
+            }
+            for (int i = 0; i < status.length; i++) if (MULTI_THREAD ) t[i].start(); else t[i].run();
+            setSystemStatus("System stopped.");
+        } else { 
+            int index = -1;
+            try { index = Integer.parseInt(args[1])-1;}catch ( Exception x ) {setSystemStatus("Invalid index:"+args[1]);}
+            if ( index >= 0 ) {
+                setSystemStatus("Stopping member:"+(index+1));
+                status[index].stop();
+                setSystemStatus("Member stopped:"+(index+1));
+            }
+        }
+    }
+
+    private void cmdStart(String[] args) {
+        if ( args.length == 1 ) {
+            setSystemStatus("System starting up...");
+            Thread[] t = new Thread[CHANNEL_COUNT];
+            for (int i = 0; i < status.length; i++) {
+                final int j = i;
+                t[j] = new Thread() {
+                    public void run() {
+                        status[j].start();
+                    }
+                };
+            }
+            for (int i = 0; i < status.length; i++) if (MULTI_THREAD ) t[i].start(); else t[i].run();
+            setSystemStatus("System started.");
+        } else { 
+            int index = -1;
+            try { index = Integer.parseInt(args[1])-1;}catch ( Exception x ) {setSystemStatus("Invalid index:"+args[1]);}
+            if ( index >= 0 ) {
+                setSystemStatus("Starting member:"+(index+1));
+                status[index].start();
+                setSystemStatus("Member started:"+(index+1));
+            }
+        }
+    }
+
+    public void setSystemStatus(String status) {
+        statusLine.delete(0,statusLine.length());
+        statusLine.append(status);
+    }
+    
+    
+    
+    public static void setEvents(String events) {
+        java.util.Arrays.fill(VIEW_EVENTS,false);
+        StringTokenizer t = new StringTokenizer(events,",");
+        while (t.hasMoreTokens() ) {
+            int idx = Integer.parseInt(t.nextToken());
+            VIEW_EVENTS[idx] = true;
+        }
+    }
+    
+    public static void run(String[] args,CoordinationDemo demo) throws Exception {
+        usage();
+        java.util.Arrays.fill(VIEW_EVENTS,true);
+
+        for (int i=0; i<args.length; i++ ) {
+            if ( "-c".equals(args[i]) )
+                CHANNEL_COUNT = Integer.parseInt(args[++i]);
+            else if ( "-t".equals(args[i]) )
+                MULTI_THREAD = Boolean.parseBoolean(args[++i]);
+            else if ( "-s".equals(args[i]) )
+                SLEEP_TIME = Long.parseLong(args[++i]);
+            else if ( "-sc".equals(args[i]) )
+                CLEAR_SCREEN = Integer.parseInt(args[++i]);
+            else if ( "-p".equals(args[i]) )
+                setEvents(args[++i]);
+            else if ( "-h".equals(args[i]) ) System.exit(0);
+        }
+        demo.init();
+        demo.waitForInput();
+    }    
+
+    private static void usage() {
+        System.out.println("Usage:");
+        System.out.println("\tjava org.apache.catalina.tribes.demos.CoordinationDemo -c channel-count(int) -t multi-thread(true|false) -s sleep-time(ms) -sc clear-screen(int) -p view_events_csv(1,2,5,7)");
+        System.out.println("Example:");
+        System.out.println("\tjava o.a.c.t.d.CoordinationDemo -> starts demo single threaded start/stop with 5 channels");
+        System.out.println("\tjava o.a.c.t.d.CoordinationDemo -c 10 -> starts demo single threaded start/stop with 10 channels");
+        System.out.println("\tjava o.a.c.t.d.CoordinationDemo -c 7 -t true -s 1000 -sc 50-> starts demo multi threaded start/stop with 7 channels and 1 second sleep time between events and 50 lines to clear screen");
+        System.out.println("\tjava o.a.c.t.d.CoordinationDemo -t true -p 12 -> starts demo multi threaded start/stop with 5 channels and only prints the EVT_CONF_RX event");
+        System.out.println();
+    }
+    public static void main(String[] args) throws Exception {
+        CoordinationDemo demo = new CoordinationDemo();
+        run(args,demo);
+    }
+    
+    public static String leftfill(String value, int length, String ch) {
+        return fill(value,length,ch,true);
+    }
+    
+    public static String rightfill(String value, int length, String ch) {
+        return fill(value,length,ch,false);
+    }    
+
+    public static String fill(String value, int length, String ch, boolean left) {
+        StringBuffer buf = new StringBuffer();
+        if ( !left ) buf.append(value.trim());
+        for (int i=value.trim().length(); i<length; i++ ) buf.append(ch);
+        if ( left ) buf.append(value.trim());
+        return buf.toString();
+    }
+    
+    
+    public static class Status {
+        public CoordinationDemo parent;
+        public GroupChannel channel;
+        NonBlockingCoordinator interceptor = null;
+        public String status;
+        public Exception error;
+        public String startstatus = "new";
+        
+        public Status(CoordinationDemo parent) {
+            this.parent = parent;
+        }
+        
+        public String getStatusLine() {
+            //member - 30
+            //running- 10
+            //coord - 30
+            //view-id - 24
+            //view count - 8
+            StringBuffer buf = new StringBuffer();
+            String local = "";
+            String coord = "";
+            String viewId = "";
+            String count = "0";
+            if ( channel != null ) {
+                Member lm = channel.getLocalMember(false);
+                local = lm!=null?lm.getName():"";
+                coord = interceptor!=null && interceptor.getCoordinator()!=null?interceptor.getCoordinator().getName():"";
+                viewId = getByteString(interceptor.getViewId()!=null?interceptor.getViewId().getBytes():new byte[0]);
+                count = String.valueOf(interceptor.getView().length);
+            }
+            buf.append(leftfill(local,30," "));
+            buf.append(leftfill(startstatus, 10, " "));
+            buf.append(leftfill(coord, 30, " "));
+            buf.append(leftfill(viewId, 24, " "));
+            buf.append(leftfill(count, 8, " "));
+            buf.append("\n");
+            buf.append("Status:"+status);
+            buf.append("\n");
+            return buf.toString();
+        }
+        
+        public String getByteString(byte[] b) {
+            if ( b == null ) return "{}";
+            return Arrays.toString(b,0,Math.min(b.length,4));
+        }
+        
+        public void start() {
+            try {
+                if ( channel == null ) {
+                    channel = createChannel();
+                    startstatus = "starting";
+                    channel.start(channel.DEFAULT);
+                    startstatus = "running";
+                } else {
+                    status = "Channel already started.";
+                }
+            } catch ( Exception x ) {
+                synchronized (System.err) {
+                    System.err.println("Start failed:");
+                    StackTraceElement[] els = x.getStackTrace();
+                    for (int i = 0; i < els.length; i++) System.err.println(els[i].toString());
+                }
+                status = "Start failed:"+x.getMessage();
+                error = x;
+                startstatus = "failed";
+                try { channel.stop(GroupChannel.DEFAULT);}catch(Exception ignore){}
+                channel = null;
+                interceptor = null;
+            }
+        }
+        
+        public void stop() {
+            try {
+                if ( channel != null ) {
+                    channel.stop(channel.DEFAULT);
+                    status = "Channel Stopped";
+                } else {
+                    status = "Channel Already Stopped";
+                }
+            }catch ( Exception x )  {
+                synchronized (System.err) {
+                    System.err.println("Stop failed:");
+                    StackTraceElement[] els = x.getStackTrace();
+                    for (int i = 0; i < els.length; i++) System.err.println(els[i].toString());
+                }
+
+                status = "Stop failed:"+x.getMessage();
+                error = x;
+            }finally {
+                startstatus = "stopped";
+                channel = null;
+                interceptor = null;
+            }
+        }
+        
+        public GroupChannel createChannel() {
+            channel = new GroupChannel();
+            ((ReceiverBase)channel.getChannelReceiver()).setAutoBind(100);
+            interceptor = new NonBlockingCoordinator() {
+                public void fireInterceptorEvent(InterceptorEvent event) {
+                    status = event.getEventTypeDesc();
+                    int type = event.getEventType();
+                    boolean display = VIEW_EVENTS[type];
+                    if ( display ) parent.printScreen();
+                    try { Thread.sleep(SLEEP_TIME); }catch ( Exception x){}
+                }
+            };
+            channel.addInterceptor(interceptor);
+            channel.addInterceptor(new TcpFailureDetector());
+            channel.addInterceptor(new MessageDispatch15Interceptor());
+            return channel;
+        }
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/test/java/org/apache/catalina/tribes/demos/EchoRpcTest.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/test/java/org/apache/catalina/tribes/demos/EchoRpcTest.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/test/java/org/apache/catalina/tribes/demos/EchoRpcTest.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,204 @@
+package org.apache.catalina.tribes.demos;
+
+import java.io.Serializable;
+
+import org.apache.catalina.tribes.Member;
+import org.apache.catalina.tribes.group.RpcCallback;
+import org.apache.catalina.tribes.Channel;
+import org.apache.catalina.tribes.ManagedChannel;
+import org.apache.catalina.tribes.group.RpcChannel;
+import org.apache.catalina.tribes.group.Response;
+
+
+/**
+ * <p>Title: </p>
+ *
+ * <p>Description: </p>
+ *
+ * <p>Copyright: Copyright (c) 2005</p>
+ *
+ * <p>Company: </p>
+ *
+ * @author not attributable
+ * @version 1.0
+ */
+public class EchoRpcTest implements RpcCallback, Runnable {
+    
+    Channel channel;
+    int count;
+    String message;
+    long pause;
+    RpcChannel rpc;
+    int options;
+    long timeout;
+    String name;
+    
+    public EchoRpcTest(Channel channel, String name, int count, String message, long pause, int options, long timeout) {
+        this.channel = channel;
+        this.count = count;
+        this.message = message;
+        this.pause = pause;
+        this.options = options;
+        this.rpc = new RpcChannel(name.getBytes(),channel,this);
+        this.timeout = timeout;
+        this.name = name;
+    }
+
+    /**
+     * If the reply has already been sent to the requesting thread, the rpc
+     * callback can handle any data that comes in after the fact.
+     *
+     * @param msg Serializable
+     * @param sender Member
+     * @todo Implement this org.apache.catalina.tribes.tipis.RpcCallback
+     *   method
+     */
+    public void leftOver(Serializable msg, Member sender) {
+        System.out.println("Received a left over message from ["+sender.getName()+"] with data ["+msg+"]");
+    }
+
+    /**
+     *
+     * @param msg Serializable
+     * @param sender Member
+     * @return Serializable - null if no reply should be sent
+     * @todo Implement this org.apache.catalina.tribes.tipis.RpcCallback
+     *   method
+     */
+    public Serializable replyRequest(Serializable msg, Member sender) {
+        System.out.println("Received a reply request message from ["+sender.getName()+"] with data ["+msg+"]");
+        return "Reply("+name+"):"+msg;
+    }
+    
+    public void run() {
+        long counter = 0;
+        while (counter<count) {
+            String msg = message + " cnt="+(++counter);
+            try {
+                System.out.println("Sending ["+msg+"]");
+                long start = System.currentTimeMillis();
+                Response[] resp = rpc.send(channel.getMembers(),(Serializable)msg,options,Channel.SEND_OPTIONS_DEFAULT,timeout);
+                System.out.println("Send of ["+msg+"] completed. Nr of responses="+resp.length+" Time:"+(System.currentTimeMillis()-start)+" ms.");
+                for ( int i=0; i<resp.length; i++ ) {
+                    System.out.println("Received a response message from ["+resp[i].getSource().getName()+"] with data ["+resp[i].getMessage()+"]");
+                }
+            Thread.sleep(pause);
+        }catch(Exception x){}
+        }
+    }
+    
+    public static void usage() {
+            System.out.println("Tribes RPC tester.");
+            System.out.println("Usage:\n\t"+
+                               "java EchoRpcTest [options]\n\t"+
+                               "Options:\n\t\t"+
+                               "[-mode all|first|majority]  \n\t\t"+
+                               "[-debug]  \n\t\t"+
+                               "[-count messagecount]  \n\t\t"+
+                               "[-timeout timeoutinms]  \n\t\t"+
+                               "[-stats statinterval]  \n\t\t"+
+                               "[-pause nrofsecondstopausebetweensends]  \n\t\t"+
+                               "[-message message]  \n\t\t"+
+                               "[-name rpcname]  \n\t\t"+
+                               "[-break (halts execution on exception)]\n"+
+                               "\tChannel options:"+
+                               ChannelCreator.usage()+"\n\n"+
+                               "Example:\n\t"+
+                               "java EchoRpcTest -port 4004\n\t"+
+                               "java EchoRpcTest -bind 192.168.0.45 -port 4005\n\t"+
+                               "java EchoRpcTest -bind 192.168.0.45 -port 4005 -mbind 192.168.0.45 -count 100 -stats 10\n");
+        }
+    
+        public static void main(String[] args) throws Exception {
+            boolean send = true;
+            boolean debug = false;
+            long pause = 3000;
+            int count = 1000000;
+            int stats = 10000;
+            String name = "EchoRpcId";
+            boolean breakOnEx = false;
+            int threads = 1;
+            int options = RpcChannel.ALL_REPLY;
+            long timeout = 15000;
+            String message = "EchoRpcMessage";
+            if ( args.length == 0 ) {
+                args = new String[] {"-help"};
+            }
+            for (int i = 0; i < args.length; i++) {
+                if ("-threads".equals(args[i])) {
+                    threads = Integer.parseInt(args[++i]);
+                } else if ("-count".equals(args[i])) {
+                    count = Integer.parseInt(args[++i]);
+                    System.out.println("Sending "+count+" messages.");
+                } else if ("-pause".equals(args[i])) {
+                    pause = Long.parseLong(args[++i])*1000;
+                } else if ("-break".equals(args[i])) {
+                    breakOnEx = true;
+                } else if ("-stats".equals(args[i])) {
+                    stats = Integer.parseInt(args[++i]);
+                    System.out.println("Stats every "+stats+" message");
+                } else if ("-timeout".equals(args[i])) {
+                    timeout = Long.parseLong(args[++i]);
+                } else if ("-message".equals(args[i])) {
+                    message = args[++i];
+                } else if ("-name".equals(args[i])) {
+                    name = args[++i];
+                } else if ("-mode".equals(args[i])) {
+                    if ( "all".equals(args[++i]) ) options = RpcChannel.ALL_REPLY;
+                    else if ( "first".equals(args[i]) ) options = RpcChannel.FIRST_REPLY;
+                    else if ( "majority".equals(args[i]) ) options = RpcChannel.MAJORITY_REPLY;
+                } else if ("-debug".equals(args[i])) {
+                    debug = true;
+                } else if ("-help".equals(args[i])) 
+                {
+                    usage();
+                    System.exit(1);
+                }
+            }
+    
+    
+            ManagedChannel channel = (ManagedChannel)ChannelCreator.createChannel(args);
+            EchoRpcTest test = new EchoRpcTest(channel,name,count,message,pause,options,timeout);
+            channel.start(channel.DEFAULT);
+            Runtime.getRuntime().addShutdownHook(new Shutdown(channel));
+            test.run();
+    
+            System.out.println("System test complete, sleeping to let threads finish.");
+            Thread.sleep(60*1000*60);
+        } 
+    
+        public static class Shutdown extends Thread {
+            ManagedChannel channel = null;
+            public Shutdown(ManagedChannel channel) {
+                this.channel = channel;
+            }
+    
+            public void run() {
+                System.out.println("Shutting down...");
+                SystemExit exit = new SystemExit(5000);
+                exit.setDaemon(true);
+                exit.start();
+                try {
+                    channel.stop(channel.DEFAULT);
+    
+                }catch ( Exception x ) {
+                    x.printStackTrace();
+                }
+                System.out.println("Channel stopped.");
+            }
+        }
+        public static class SystemExit extends Thread {
+            private long delay;
+            public SystemExit(long delay) {
+                this.delay = delay;
+            }
+            public void run () {
+                try {
+                    Thread.sleep(delay);
+                }catch ( Exception x ) {
+                    x.printStackTrace();
+                }
+                System.exit(0);
+    
+            }
+    }}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/test/java/org/apache/catalina/tribes/demos/IntrospectionUtils.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/test/java/org/apache/catalina/tribes/demos/IntrospectionUtils.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/test/java/org/apache/catalina/tribes/demos/IntrospectionUtils.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,1002 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.tribes.demos;
+
+import java.io.File;
+import java.io.FilenameFilter;
+import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.net.InetAddress;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.UnknownHostException;
+import java.util.Hashtable;
+import java.util.StringTokenizer;
+import java.util.Vector;
+
+// Depends: JDK1.1
+
+/**
+ * Utils for introspection and reflection
+ */
+public final class IntrospectionUtils {
+
+
+    private static org.apache.commons.logging.Log log=
+        org.apache.commons.logging.LogFactory.getLog( IntrospectionUtils.class );
+
+    /**
+     * Call execute() - any ant-like task should work
+     */
+    public static void execute(Object proxy, String method) throws Exception {
+        Method executeM = null;
+        Class c = proxy.getClass();
+        Class params[] = new Class[0];
+        //	params[0]=args.getClass();
+        executeM = findMethod(c, method, params);
+        if (executeM == null) {
+            throw new RuntimeException("No execute in " + proxy.getClass());
+        }
+        executeM.invoke(proxy, (Object[]) null);//new Object[] { args });
+    }
+
+    /**
+     * Call void setAttribute( String ,Object )
+     */
+    public static void setAttribute(Object proxy, String n, Object v)
+            throws Exception {
+        if (proxy instanceof AttributeHolder) {
+            ((AttributeHolder) proxy).setAttribute(n, v);
+            return;
+        }
+
+        Method executeM = null;
+        Class c = proxy.getClass();
+        Class params[] = new Class[2];
+        params[0] = String.class;
+        params[1] = Object.class;
+        executeM = findMethod(c, "setAttribute", params);
+        if (executeM == null) {
+            if (log.isDebugEnabled())
+                log.debug("No setAttribute in " + proxy.getClass());
+            return;
+        }
+        if (false)
+            if (log.isDebugEnabled())
+                log.debug("Setting " + n + "=" + v + "  in " + proxy);
+        executeM.invoke(proxy, new Object[] { n, v });
+        return;
+    }
+
+    /**
+     * Call void getAttribute( String )
+     */
+    public static Object getAttribute(Object proxy, String n) throws Exception {
+        Method executeM = null;
+        Class c = proxy.getClass();
+        Class params[] = new Class[1];
+        params[0] = String.class;
+        executeM = findMethod(c, "getAttribute", params);
+        if (executeM == null) {
+            if (log.isDebugEnabled())
+                log.debug("No getAttribute in " + proxy.getClass());
+            return null;
+        }
+        return executeM.invoke(proxy, new Object[] { n });
+    }
+
+    /**
+     * Construct a URLClassLoader. Will compile and work in JDK1.1 too.
+     */
+    public static ClassLoader getURLClassLoader(URL urls[], ClassLoader parent) {
+        try {
+            Class urlCL = Class.forName("java.net.URLClassLoader");
+            Class paramT[] = new Class[2];
+            paramT[0] = urls.getClass();
+            paramT[1] = ClassLoader.class;
+            Method m = findMethod(urlCL, "newInstance", paramT);
+            if (m == null)
+                return null;
+
+            ClassLoader cl = (ClassLoader) m.invoke(urlCL, new Object[] { urls,
+                    parent });
+            return cl;
+        } catch (ClassNotFoundException ex) {
+            // jdk1.1
+            return null;
+        } catch (Exception ex) {
+            ex.printStackTrace();
+            return null;
+        }
+    }
+
+    public static String guessInstall(String installSysProp,
+            String homeSysProp, String jarName) {
+        return guessInstall(installSysProp, homeSysProp, jarName, null);
+    }
+
+    /**
+     * Guess a product install/home by analyzing the class path. It works for
+     * product using the pattern: lib/executable.jar or if executable.jar is
+     * included in classpath by a shell script. ( java -jar also works )
+     *
+     * Insures both "install" and "home" System properties are set. If either or
+     * both System properties are unset, "install" and "home" will be set to the
+     * same value. This value will be the other System property that is set, or
+     * the guessed value if neither is set.
+     */
+    public static String guessInstall(String installSysProp,
+            String homeSysProp, String jarName, String classFile) {
+        String install = null;
+        String home = null;
+
+        if (installSysProp != null)
+            install = System.getProperty(installSysProp);
+
+        if (homeSysProp != null)
+            home = System.getProperty(homeSysProp);
+
+        if (install != null) {
+            if (home == null)
+                System.getProperties().put(homeSysProp, install);
+            return install;
+        }
+
+        // Find the directory where jarName.jar is located
+
+        String cpath = System.getProperty("java.class.path");
+        String pathSep = System.getProperty("path.separator");
+        StringTokenizer st = new StringTokenizer(cpath, pathSep);
+        while (st.hasMoreTokens()) {
+            String path = st.nextToken();
+            //	    log( "path " + path );
+            if (path.endsWith(jarName)) {
+                home = path.substring(0, path.length() - jarName.length());
+                try {
+                    if ("".equals(home)) {
+                        home = new File("./").getCanonicalPath();
+                    } else if (home.endsWith(File.separator)) {
+                        home = home.substring(0, home.length() - 1);
+                    }
+                    File f = new File(home);
+                    String parentDir = f.getParent();
+                    if (parentDir == null)
+                        parentDir = home; // unix style
+                    File f1 = new File(parentDir);
+                    install = f1.getCanonicalPath();
+                    if (installSysProp != null)
+                        System.getProperties().put(installSysProp, install);
+                    if (home == null && homeSysProp != null)
+                        System.getProperties().put(homeSysProp, install);
+                    return install;
+                } catch (Exception ex) {
+                    ex.printStackTrace();
+                }
+            } else {
+                String fname = path + (path.endsWith("/") ? "" : "/")
+                        + classFile;
+                if (new File(fname).exists()) {
+                    try {
+                        File f = new File(path);
+                        String parentDir = f.getParent();
+                        if (parentDir == null)
+                            parentDir = path; // unix style
+                        File f1 = new File(parentDir);
+                        install = f1.getCanonicalPath();
+                        if (installSysProp != null)
+                            System.getProperties().put(installSysProp, install);
+                        if (home == null && homeSysProp != null)
+                            System.getProperties().put(homeSysProp, install);
+                        return install;
+                    } catch (Exception ex) {
+                        ex.printStackTrace();
+                    }
+                }
+            }
+        }
+
+        // if install directory can't be found, use home as the default
+        if (home != null) {
+            System.getProperties().put(installSysProp, home);
+            return home;
+        }
+
+        return null;
+    }
+
+    /**
+     * Debug method, display the classpath
+     */
+    public static void displayClassPath(String msg, URL[] cp) {
+        if (log.isDebugEnabled()) {
+            log.debug(msg);
+            for (int i = 0; i < cp.length; i++) {
+                log.debug(cp[i].getFile());
+            }
+        }
+    }
+
+    public static String PATH_SEPARATOR = System.getProperty("path.separator");
+
+    /**
+     * Adds classpath entries from a vector of URL's to the "tc_path_add" System
+     * property. This System property lists the classpath entries common to web
+     * applications. This System property is currently used by Jasper when its
+     * JSP servlet compiles the Java file for a JSP.
+     */
+    public static String classPathAdd(URL urls[], String cp) {
+        if (urls == null)
+            return cp;
+
+        for (int i = 0; i < urls.length; i++) {
+            if (cp != null)
+                cp += PATH_SEPARATOR + urls[i].getFile();
+            else
+                cp = urls[i].getFile();
+        }
+        return cp;
+    }
+
+    /**
+     * Find a method with the right name If found, call the method ( if param is
+     * int or boolean we'll convert value to the right type before) - that means
+     * you can have setDebug(1).
+     */
+    public static void setProperty(Object o, String name, String value) {
+        if (dbg > 1)
+            d("setProperty(" + o.getClass() + " " + name + "=" + value + ")");
+
+        String setter = "set" + capitalize(name);
+
+        try {
+            Method methods[] = findMethods(o.getClass());
+            Method setPropertyMethod = null;
+
+            // First, the ideal case - a setFoo( String ) method
+            for (int i = 0; i < methods.length; i++) {
+                Class paramT[] = methods[i].getParameterTypes();
+                if (setter.equals(methods[i].getName()) && paramT.length == 1
+                        && "java.lang.String".equals(paramT[0].getName())) {
+
+                    methods[i].invoke(o, new Object[] { value });
+                    return;
+                }
+            }
+
+            // Try a setFoo ( int ) or ( boolean )
+            for (int i = 0; i < methods.length; i++) {
+                boolean ok = true;
+                if (setter.equals(methods[i].getName())
+                        && methods[i].getParameterTypes().length == 1) {
+
+                    // match - find the type and invoke it
+                    Class paramType = methods[i].getParameterTypes()[0];
+                    Object params[] = new Object[1];
+
+                    // Try a setFoo ( int )
+                    if ("java.lang.Integer".equals(paramType.getName())
+                            || "int".equals(paramType.getName())) {
+                        try {
+                            params[0] = new Integer(value);
+                        } catch (NumberFormatException ex) {
+                            ok = false;
+                        }
+                    // Try a setFoo ( long )
+                    }else if ("java.lang.Long".equals(paramType.getName())
+                                || "long".equals(paramType.getName())) {
+                            try {
+                                params[0] = new Long(value);
+                            } catch (NumberFormatException ex) {
+                                ok = false;
+                            }
+
+                        // Try a setFoo ( boolean )
+                    } else if ("java.lang.Boolean".equals(paramType.getName())
+                            || "boolean".equals(paramType.getName())) {
+                        params[0] = new Boolean(value);
+
+                        // Try a setFoo ( InetAddress )
+                    } else if ("java.net.InetAddress".equals(paramType
+                            .getName())) {
+                        try {
+                            params[0] = InetAddress.getByName(value);
+                        } catch (UnknownHostException exc) {
+                            d("Unable to resolve host name:" + value);
+                            ok = false;
+                        }
+
+                        // Unknown type
+                    } else {
+                        d("Unknown type " + paramType.getName());
+                    }
+
+                    if (ok) {
+                        methods[i].invoke(o, params);
+                        return;
+                    }
+                }
+
+                // save "setProperty" for later
+                if ("setProperty".equals(methods[i].getName())) {
+                    setPropertyMethod = methods[i];
+                }
+            }
+
+            // Ok, no setXXX found, try a setProperty("name", "value")
+            if (setPropertyMethod != null) {
+                Object params[] = new Object[2];
+                params[0] = name;
+                params[1] = value;
+                setPropertyMethod.invoke(o, params);
+            }
+
+        } catch (IllegalArgumentException ex2) {
+            log.warn("IAE " + o + " " + name + " " + value, ex2);
+        } catch (SecurityException ex1) {
+            if (dbg > 0)
+                d("SecurityException for " + o.getClass() + " " + name + "="
+                        + value + ")");
+            if (dbg > 1)
+                ex1.printStackTrace();
+        } catch (IllegalAccessException iae) {
+            if (dbg > 0)
+                d("IllegalAccessException for " + o.getClass() + " " + name
+                        + "=" + value + ")");
+            if (dbg > 1)
+                iae.printStackTrace();
+        } catch (InvocationTargetException ie) {
+            if (dbg > 0)
+                d("InvocationTargetException for " + o.getClass() + " " + name
+                        + "=" + value + ")");
+            if (dbg > 1)
+                ie.printStackTrace();
+        }
+    }
+
+    public static Object getProperty(Object o, String name) {
+        String getter = "get" + capitalize(name);
+        String isGetter = "is" + capitalize(name);
+
+        try {
+            Method methods[] = findMethods(o.getClass());
+            Method getPropertyMethod = null;
+
+            // First, the ideal case - a getFoo() method
+            for (int i = 0; i < methods.length; i++) {
+                Class paramT[] = methods[i].getParameterTypes();
+                if (getter.equals(methods[i].getName()) && paramT.length == 0) {
+                    return methods[i].invoke(o, (Object[]) null);
+                }
+                if (isGetter.equals(methods[i].getName()) && paramT.length == 0) {
+                    return methods[i].invoke(o, (Object[]) null);
+                }
+
+                if ("getProperty".equals(methods[i].getName())) {
+                    getPropertyMethod = methods[i];
+                }
+            }
+
+            // Ok, no setXXX found, try a getProperty("name")
+            if (getPropertyMethod != null) {
+                Object params[] = new Object[1];
+                params[0] = name;
+                return getPropertyMethod.invoke(o, params);
+            }
+
+        } catch (IllegalArgumentException ex2) {
+            log.warn("IAE " + o + " " + name, ex2);
+        } catch (SecurityException ex1) {
+            if (dbg > 0)
+                d("SecurityException for " + o.getClass() + " " + name + ")");
+            if (dbg > 1)
+                ex1.printStackTrace();
+        } catch (IllegalAccessException iae) {
+            if (dbg > 0)
+                d("IllegalAccessException for " + o.getClass() + " " + name
+                        + ")");
+            if (dbg > 1)
+                iae.printStackTrace();
+        } catch (InvocationTargetException ie) {
+            if (dbg > 0)
+                d("InvocationTargetException for " + o.getClass() + " " + name
+                        + ")");
+            if (dbg > 1)
+                ie.printStackTrace();
+        }
+        return null;
+    }
+
+    /**
+     */
+    public static void setProperty(Object o, String name) {
+        String setter = "set" + capitalize(name);
+        try {
+            Method methods[] = findMethods(o.getClass());
+            Method setPropertyMethod = null;
+            // find setFoo() method
+            for (int i = 0; i < methods.length; i++) {
+                Class paramT[] = methods[i].getParameterTypes();
+                if (setter.equals(methods[i].getName()) && paramT.length == 0) {
+                    methods[i].invoke(o, new Object[] {});
+                    return;
+                }
+            }
+        } catch (Exception ex1) {
+            if (dbg > 0)
+                d("Exception for " + o.getClass() + " " + name);
+            if (dbg > 1)
+                ex1.printStackTrace();
+        }
+    }
+
+    /**
+     * Replace ${NAME} with the property value
+     *
+     * @deprecated Use the explicit method
+     */
+    public static String replaceProperties(String value, Object getter) {
+        if (getter instanceof Hashtable)
+            return replaceProperties(value, (Hashtable) getter, null);
+
+        if (getter instanceof PropertySource) {
+            PropertySource src[] = new PropertySource[] { (PropertySource) getter };
+            return replaceProperties(value, null, src);
+        }
+        return value;
+    }
+
+    /**
+     * Replace ${NAME} with the property value
+     */
+    public static String replaceProperties(String value, Hashtable staticProp,
+            PropertySource dynamicProp[]) {
+        StringBuffer sb = new StringBuffer();
+        int prev = 0;
+        // assert value!=nil
+        int pos;
+        while ((pos = value.indexOf("$", prev)) >= 0) {
+            if (pos > 0) {
+                sb.append(value.substring(prev, pos));
+            }
+            if (pos == (value.length() - 1)) {
+                sb.append('$');
+                prev = pos + 1;
+            } else if (value.charAt(pos + 1) != '{') {
+                sb.append('$');
+                prev = pos + 1; // XXX
+            } else {
+                int endName = value.indexOf('}', pos);
+                if (endName < 0) {
+                    sb.append(value.substring(pos));
+                    prev = value.length();
+                    continue;
+                }
+                String n = value.substring(pos + 2, endName);
+                String v = null;
+                if (staticProp != null) {
+                    v = (String) ((Hashtable) staticProp).get(n);
+                }
+                if (v == null && dynamicProp != null) {
+                    for (int i = 0; i < dynamicProp.length; i++) {
+                        v = dynamicProp[i].getProperty(n);
+                        if (v != null) {
+                            break;
+                        }
+                    }
+                }
+                if (v == null)
+                    v = "${" + n + "}";
+
+                sb.append(v);
+                prev = endName + 1;
+            }
+        }
+        if (prev < value.length())
+            sb.append(value.substring(prev));
+        return sb.toString();
+    }
+
+    /**
+     * Reverse of Introspector.decapitalize
+     */
+    public static String capitalize(String name) {
+        if (name == null || name.length() == 0) {
+            return name;
+        }
+        char chars[] = name.toCharArray();
+        chars[0] = Character.toUpperCase(chars[0]);
+        return new String(chars);
+    }
+
+    public static String unCapitalize(String name) {
+        if (name == null || name.length() == 0) {
+            return name;
+        }
+        char chars[] = name.toCharArray();
+        chars[0] = Character.toLowerCase(chars[0]);
+        return new String(chars);
+    }
+
+    // -------------------- Class path tools --------------------
+
+    /**
+     * Add all the jar files in a dir to the classpath, represented as a Vector
+     * of URLs.
+     */
+    public static void addToClassPath(Vector cpV, String dir) {
+        try {
+            String cpComp[] = getFilesByExt(dir, ".jar");
+            if (cpComp != null) {
+                int jarCount = cpComp.length;
+                for (int i = 0; i < jarCount; i++) {
+                    URL url = getURL(dir, cpComp[i]);
+                    if (url != null)
+                        cpV.addElement(url);
+                }
+            }
+        } catch (Exception ex) {
+            ex.printStackTrace();
+        }
+    }
+
+    public static void addToolsJar(Vector v) {
+        try {
+            // Add tools.jar in any case
+            File f = new File(System.getProperty("java.home")
+                    + "/../lib/tools.jar");
+
+            if (!f.exists()) {
+                // On some systems java.home gets set to the root of jdk.
+                // That's a bug, but we can work around and be nice.
+                f = new File(System.getProperty("java.home") + "/lib/tools.jar");
+                if (f.exists()) {
+                    if (log.isDebugEnabled())
+                        log.debug("Detected strange java.home value "
+                            + System.getProperty("java.home")
+                            + ", it should point to jre");
+                }
+            }
+            URL url = new URL("file", "", f.getAbsolutePath());
+
+            v.addElement(url);
+        } catch (MalformedURLException ex) {
+            ex.printStackTrace();
+        }
+    }
+
+    /**
+     * Return all files with a given extension in a dir
+     */
+    public static String[] getFilesByExt(String ld, String ext) {
+        File dir = new File(ld);
+        String[] names = null;
+        final String lext = ext;
+        if (dir.isDirectory()) {
+            names = dir.list(new FilenameFilter() {
+                public boolean accept(File d, String name) {
+                    if (name.endsWith(lext)) {
+                        return true;
+                    }
+                    return false;
+                }
+            });
+        }
+        return names;
+    }
+
+    /**
+     * Construct a file url from a file, using a base dir
+     */
+    public static URL getURL(String base, String file) {
+        try {
+            File baseF = new File(base);
+            File f = new File(baseF, file);
+            String path = f.getCanonicalPath();
+            if (f.isDirectory()) {
+                path += "/";
+            }
+            if (!f.exists())
+                return null;
+            return new URL("file", "", path);
+        } catch (Exception ex) {
+            ex.printStackTrace();
+            return null;
+        }
+    }
+
+    /**
+     * Add elements from the classpath <i>cp </i> to a Vector <i>jars </i> as
+     * file URLs (We use Vector for JDK 1.1 compat).
+     * <p>
+     *
+     * @param jars The jar list
+     * @param cp a String classpath of directory or jar file elements
+     *   separated by path.separator delimiters.
+     * @throws IOException If an I/O error occurs
+     * @throws MalformedURLException Doh ;)
+     */
+    public static void addJarsFromClassPath(Vector jars, String cp)
+            throws IOException, MalformedURLException {
+        String sep = System.getProperty("path.separator");
+        String token;
+        StringTokenizer st;
+        if (cp != null) {
+            st = new StringTokenizer(cp, sep);
+            while (st.hasMoreTokens()) {
+                File f = new File(st.nextToken());
+                String path = f.getCanonicalPath();
+                if (f.isDirectory()) {
+                    path += "/";
+                }
+                URL url = new URL("file", "", path);
+                if (!jars.contains(url)) {
+                    jars.addElement(url);
+                }
+            }
+        }
+    }
+
+    /**
+     * Return a URL[] that can be used to construct a class loader
+     */
+    public static URL[] getClassPath(Vector v) {
+        URL[] urls = new URL[v.size()];
+        for (int i = 0; i < v.size(); i++) {
+            urls[i] = (URL) v.elementAt(i);
+        }
+        return urls;
+    }
+
+    /**
+     * Construct a URL classpath from files in a directory, a cpath property,
+     * and tools.jar.
+     */
+    public static URL[] getClassPath(String dir, String cpath,
+            String cpathProp, boolean addTools) throws IOException,
+            MalformedURLException {
+        Vector jarsV = new Vector();
+        if (dir != null) {
+            // Add dir/classes first, if it exists
+            URL url = getURL(dir, "classes");
+            if (url != null)
+                jarsV.addElement(url);
+            addToClassPath(jarsV, dir);
+        }
+
+        if (cpath != null)
+            addJarsFromClassPath(jarsV, cpath);
+
+        if (cpathProp != null) {
+            String cpath1 = System.getProperty(cpathProp);
+            addJarsFromClassPath(jarsV, cpath1);
+        }
+
+        if (addTools)
+            addToolsJar(jarsV);
+
+        return getClassPath(jarsV);
+    }
+
+    // -------------------- Mapping command line params to setters
+
+    public static boolean processArgs(Object proxy, String args[])
+            throws Exception {
+        String args0[] = null;
+        if (null != findMethod(proxy.getClass(), "getOptions1", new Class[] {})) {
+            args0 = (String[]) callMethod0(proxy, "getOptions1");
+        }
+
+        if (args0 == null) {
+            //args0=findVoidSetters(proxy.getClass());
+            args0 = findBooleanSetters(proxy.getClass());
+        }
+        Hashtable h = null;
+        if (null != findMethod(proxy.getClass(), "getOptionAliases",
+                new Class[] {})) {
+            h = (Hashtable) callMethod0(proxy, "getOptionAliases");
+        }
+        return processArgs(proxy, args, args0, null, h);
+    }
+
+    public static boolean processArgs(Object proxy, String args[],
+            String args0[], String args1[], Hashtable aliases) throws Exception {
+        for (int i = 0; i < args.length; i++) {
+            String arg = args[i];
+            if (arg.startsWith("-"))
+                arg = arg.substring(1);
+            if (aliases != null && aliases.get(arg) != null)
+                arg = (String) aliases.get(arg);
+
+            if (args0 != null) {
+                boolean set = false;
+                for (int j = 0; j < args0.length; j++) {
+                    if (args0[j].equalsIgnoreCase(arg)) {
+                        setProperty(proxy, args0[j], "true");
+                        set = true;
+                        break;
+                    }
+                }
+                if (set)
+                    continue;
+            }
+            if (args1 != null) {
+                for (int j = 0; j < args1.length; j++) {
+                    if (args1[j].equalsIgnoreCase(arg)) {
+                        i++;
+                        if (i >= args.length)
+                            return false;
+                        setProperty(proxy, arg, args[i]);
+                        break;
+                    }
+                }
+            } else {
+                // if args1 is not specified,assume all other options have param
+                i++;
+                if (i >= args.length)
+                    return false;
+                setProperty(proxy, arg, args[i]);
+            }
+
+        }
+        return true;
+    }
+
+    // -------------------- other utils --------------------
+    public static void clear() {
+        objectMethods.clear();
+    }
+
+    public static String[] findVoidSetters(Class c) {
+        Method m[] = findMethods(c);
+        if (m == null)
+            return null;
+        Vector v = new Vector();
+        for (int i = 0; i < m.length; i++) {
+            if (m[i].getName().startsWith("set")
+                    && m[i].getParameterTypes().length == 0) {
+                String arg = m[i].getName().substring(3);
+                v.addElement(unCapitalize(arg));
+            }
+        }
+        String s[] = new String[v.size()];
+        for (int i = 0; i < s.length; i++) {
+            s[i] = (String) v.elementAt(i);
+        }
+        return s;
+    }
+
+    public static String[] findBooleanSetters(Class c) {
+        Method m[] = findMethods(c);
+        if (m == null)
+            return null;
+        Vector v = new Vector();
+        for (int i = 0; i < m.length; i++) {
+            if (m[i].getName().startsWith("set")
+                    && m[i].getParameterTypes().length == 1
+                    && "boolean".equalsIgnoreCase(m[i].getParameterTypes()[0]
+                            .getName())) {
+                String arg = m[i].getName().substring(3);
+                v.addElement(unCapitalize(arg));
+            }
+        }
+        String s[] = new String[v.size()];
+        for (int i = 0; i < s.length; i++) {
+            s[i] = (String) v.elementAt(i);
+        }
+        return s;
+    }
+
+    static Hashtable objectMethods = new Hashtable();
+
+    public static Method[] findMethods(Class c) {
+        Method methods[] = (Method[]) objectMethods.get(c);
+        if (methods != null)
+            return methods;
+
+        methods = c.getMethods();
+        objectMethods.put(c, methods);
+        return methods;
+    }
+
+    public static Method findMethod(Class c, String name, Class params[]) {
+        Method methods[] = findMethods(c);
+        if (methods == null)
+            return null;
+        for (int i = 0; i < methods.length; i++) {
+            if (methods[i].getName().equals(name)) {
+                Class methodParams[] = methods[i].getParameterTypes();
+                if (methodParams == null)
+                    if (params == null || params.length == 0)
+                        return methods[i];
+                if (params == null)
+                    if (methodParams == null || methodParams.length == 0)
+                        return methods[i];
+                if (params.length != methodParams.length)
+                    continue;
+                boolean found = true;
+                for (int j = 0; j < params.length; j++) {
+                    if (params[j] != methodParams[j]) {
+                        found = false;
+                        break;
+                    }
+                }
+                if (found)
+                    return methods[i];
+            }
+        }
+        return null;
+    }
+
+    /** Test if the object implements a particular
+     *  method
+     */
+    public static boolean hasHook(Object obj, String methodN) {
+        try {
+            Method myMethods[] = findMethods(obj.getClass());
+            for (int i = 0; i < myMethods.length; i++) {
+                if (methodN.equals(myMethods[i].getName())) {
+                    // check if it's overriden
+                    Class declaring = myMethods[i].getDeclaringClass();
+                    Class parentOfDeclaring = declaring.getSuperclass();
+                    // this works only if the base class doesn't extend
+                    // another class.
+
+                    // if the method is declared in a top level class
+                    // like BaseInterceptor parent is Object, otherwise
+                    // parent is BaseInterceptor or an intermediate class
+                    if (!"java.lang.Object".equals(parentOfDeclaring.getName())) {
+                        return true;
+                    }
+                }
+            }
+        } catch (Exception ex) {
+            ex.printStackTrace();
+        }
+        return false;
+    }
+
+    public static void callMain(Class c, String args[]) throws Exception {
+        Class p[] = new Class[1];
+        p[0] = args.getClass();
+        Method m = c.getMethod("main", p);
+        m.invoke(c, new Object[] { args });
+    }
+
+    public static Object callMethod1(Object target, String methodN,
+            Object param1, String typeParam1, ClassLoader cl) throws Exception {
+        if (target == null || param1 == null) {
+            d("Assert: Illegal params " + target + " " + param1);
+        }
+        if (dbg > 0)
+            d("callMethod1 " + target.getClass().getName() + " "
+                    + param1.getClass().getName() + " " + typeParam1);
+
+        Class params[] = new Class[1];
+        if (typeParam1 == null)
+            params[0] = param1.getClass();
+        else
+            params[0] = cl.loadClass(typeParam1);
+        Method m = findMethod(target.getClass(), methodN, params);
+        if (m == null)
+            throw new NoSuchMethodException(target.getClass().getName() + " "
+                    + methodN);
+        return m.invoke(target, new Object[] { param1 });
+    }
+
+    public static Object callMethod0(Object target, String methodN)
+            throws Exception {
+        if (target == null) {
+            d("Assert: Illegal params " + target);
+            return null;
+        }
+        if (dbg > 0)
+            d("callMethod0 " + target.getClass().getName() + "." + methodN);
+
+        Class params[] = new Class[0];
+        Method m = findMethod(target.getClass(), methodN, params);
+        if (m == null)
+            throw new NoSuchMethodException(target.getClass().getName() + " "
+                    + methodN);
+        return m.invoke(target, emptyArray);
+    }
+
+    static Object[] emptyArray = new Object[] {};
+
+    public static Object callMethodN(Object target, String methodN,
+            Object params[], Class typeParams[]) throws Exception {
+        Method m = null;
+        m = findMethod(target.getClass(), methodN, typeParams);
+        if (m == null) {
+            d("Can't find method " + methodN + " in " + target + " CLASS "
+                    + target.getClass());
+            return null;
+        }
+        Object o = m.invoke(target, params);
+
+        if (dbg > 0) {
+            // debug
+            StringBuffer sb = new StringBuffer();
+            sb.append("" + target.getClass().getName() + "." + methodN + "( ");
+            for (int i = 0; i < params.length; i++) {
+                if (i > 0)
+                    sb.append(", ");
+                sb.append(params[i]);
+            }
+            sb.append(")");
+            d(sb.toString());
+        }
+        return o;
+    }
+
+    public static Object convert(String object, Class paramType) {
+        Object result = null;
+        if ("java.lang.String".equals(paramType.getName())) {
+            result = object;
+        } else if ("java.lang.Integer".equals(paramType.getName())
+                || "int".equals(paramType.getName())) {
+            try {
+                result = new Integer(object);
+            } catch (NumberFormatException ex) {
+            }
+            // Try a setFoo ( boolean )
+        } else if ("java.lang.Boolean".equals(paramType.getName())
+                || "boolean".equals(paramType.getName())) {
+            result = new Boolean(object);
+
+            // Try a setFoo ( InetAddress )
+        } else if ("java.net.InetAddress".equals(paramType
+                .getName())) {
+            try {
+                result = InetAddress.getByName(object);
+            } catch (UnknownHostException exc) {
+                d("Unable to resolve host name:" + object);
+            }
+
+            // Unknown type
+        } else {
+            d("Unknown type " + paramType.getName());
+        }
+        if (result == null) {
+            throw new IllegalArgumentException("Can't convert argument: " + object);
+        }
+        return result;
+    }
+
+    // -------------------- Get property --------------------
+    // This provides a layer of abstraction
+
+    public static interface PropertySource {
+
+        public String getProperty(String key);
+
+    }
+
+    public static interface AttributeHolder {
+
+        public void setAttribute(String key, Object o);
+
+    }
+
+    // debug --------------------
+    static final int dbg = 0;
+
+    static void d(String s) {
+        if (log.isDebugEnabled())
+            log.debug("IntrospectionUtils: " + s);
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/test/java/org/apache/catalina/tribes/demos/LoadTest.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/test/java/org/apache/catalina/tribes/demos/LoadTest.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/test/java/org/apache/catalina/tribes/demos/LoadTest.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,424 @@
+/*
+ * Copyright 1999,2004-2006 The Apache Software Foundation.
+ * 
+ * Licensed 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.tribes.demos;
+
+import java.io.Serializable;
+import java.util.Random;
+
+import org.apache.catalina.tribes.ByteMessage;
+import org.apache.catalina.tribes.ChannelException;
+import org.apache.catalina.tribes.ChannelListener;
+import org.apache.catalina.tribes.ManagedChannel;
+import org.apache.catalina.tribes.Member;
+import org.apache.catalina.tribes.MembershipListener;
+import org.apache.catalina.tribes.io.XByteBuffer;
+import org.apache.catalina.tribes.Channel;
+import java.io.Externalizable;
+
+
+/**
+ * <p>Title: </p>
+ *
+ * <p>Description: </p>
+ *
+ * <p>Copyright: Copyright (c) 2005</p>
+ *
+ * <p>Company: </p>
+ *
+ * @author not attributable
+ * @version 1.0
+ */
+public class LoadTest implements MembershipListener,ChannelListener, Runnable {
+    protected static org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory.getLog(LoadTest.class);
+    public static int size = 24000;
+    public static Object mutex = new Object();
+    public boolean doRun = true;
+    
+    public long bytesReceived = 0;
+    public float mBytesReceived = 0;
+    public int  messagesReceived = 0;
+    public boolean send = true;
+    public boolean debug = false;
+    public int msgCount = 100;
+    ManagedChannel channel=null;
+    public int statsInterval = 10000;
+    public long pause = 0;
+    public boolean breakonChannelException = false;
+    public boolean async = false;
+    public long receiveStart = 0;
+    public int channelOptions = Channel.SEND_OPTIONS_DEFAULT;
+    
+    static int messageSize = 0;
+    
+    public static long messagesSent = 0;
+    public static long messageStartSendTime = 0;
+    public static long messageEndSendTime = 0;
+    public static int  threadCount = 0;
+    
+    public static synchronized void startTest() {
+        threadCount++;
+        if ( messageStartSendTime == 0 ) messageStartSendTime = System.currentTimeMillis();
+    }
+    
+    public static synchronized void endTest() {
+        threadCount--;
+        if ( messageEndSendTime == 0 && threadCount==0 ) messageEndSendTime = System.currentTimeMillis();
+    }
+
+    
+    public static synchronized long addSendStats(long count) {
+        messagesSent+=count;
+        return 0l;
+    }    
+    
+    private static void printSendStats(long counter, int messageSize) {
+        float cnt = (float)counter;
+        float size = (float)messageSize;
+        float time = (float)(System.currentTimeMillis()-messageStartSendTime) / 1000f;
+        log.info("****SEND STATS-"+Thread.currentThread().getName()+"*****"+
+                 "\n\tMessage count:"+counter+
+                 "\n\tTotal bytes  :"+(long)(size*cnt)+
+                 "\n\tTotal seconds:"+(time)+
+                 "\n\tBytes/second :"+(size*cnt/time)+
+                 "\n\tMBytes/second:"+(size*cnt/time/1024f/1024f));
+    }
+
+    
+    
+    public LoadTest(ManagedChannel channel, 
+                    boolean send,
+                    int msgCount,
+                    boolean debug,
+                    long pause,
+                    int stats,
+                    boolean breakOnEx) {
+        this.channel = channel;
+        this.send = send;
+        this.msgCount = msgCount;
+        this.debug = debug;
+        this.pause = pause;
+        this.statsInterval = stats;
+        this.breakonChannelException = breakOnEx;
+    }
+    
+    
+    
+    public void run() {
+        
+        long counter = 0;
+        long total = 0;
+        LoadMessage msg = new LoadMessage();
+        int messageSize = LoadTest.messageSize;
+        
+        try {
+            startTest();
+            while (total < msgCount) {
+                if (channel.getMembers().length == 0 || (!send)) {
+                    synchronized (mutex) {
+                        try {
+                            mutex.wait();
+                        } catch (InterruptedException x) {
+                            log.info("Thread interrupted from wait");
+                        }
+                    }
+                } else {
+                    try {
+                        //msg.setMsgNr((int)++total);
+                        counter++;
+                        if (debug) {
+                            printArray(msg.getMessage());
+                        }
+                        channel.send(channel.getMembers(), msg, channelOptions);
+                        if ( pause > 0 ) {
+                            if ( debug) System.out.println("Pausing sender for "+pause+" ms.");
+                            Thread.sleep(pause);
+                        }
+                    } catch (ChannelException x) {
+                        if ( debug ) log.error("Unable to send message:"+x.getMessage(),x);
+                        log.error("Unable to send message:"+x.getMessage());
+                        ChannelException.FaultyMember[] faulty = x.getFaultyMembers();
+                        for (int i=0; i<faulty.length; i++ ) log.error("Faulty: "+faulty[i]);
+                        --counter;
+                        if ( this.breakonChannelException ) throw x;
+                    }
+                }
+                if ( (counter % statsInterval) == 0 && (counter > 0)) {
+                    //add to the global counter
+                    counter = addSendStats(counter);
+                    //print from the global counter
+                    //printSendStats(LoadTest.messagesSent, LoadTest.messageSize, LoadTest.messageSendTime);
+                    printSendStats(LoadTest.messagesSent, LoadTest.messageSize);
+                    
+                }
+
+            }
+        }catch ( Exception x ) {
+            log.error("Captured error while sending:"+x.getMessage());
+            if ( debug ) log.error("",x);
+            printSendStats(LoadTest.messagesSent, LoadTest.messageSize);
+        }
+        endTest();
+    }
+
+    
+
+    /**
+     * memberAdded
+     *
+     * @param member Member
+     * @todo Implement this org.apache.catalina.tribes.MembershipListener
+     *   method
+     */
+    public void memberAdded(Member member) {
+        log.info("Member added:"+member);
+        synchronized (mutex) {
+            mutex.notifyAll();
+        }
+    }
+
+    /**
+     * memberDisappeared
+     *
+     * @param member Member
+     * @todo Implement this org.apache.catalina.tribes.MembershipListener
+     *   method
+     */
+    public void memberDisappeared(Member member) {
+        log.info("Member disappeared:"+member);
+    }
+    
+    public boolean accept(Serializable msg, Member mbr){ 
+       return (msg instanceof LoadMessage) || (msg instanceof ByteMessage);
+    }
+    
+    public void messageReceived(Serializable msg, Member mbr){ 
+        if ( receiveStart == 0 ) receiveStart = System.currentTimeMillis();
+        if ( debug ) {
+            if ( msg instanceof LoadMessage ) {
+                printArray(((LoadMessage)msg).getMessage());
+            }
+        }
+        
+        if ( msg instanceof ByteMessage && !(msg instanceof LoadMessage)) {
+            LoadMessage tmp = new LoadMessage();
+            tmp.setMessage(((ByteMessage)msg).getMessage());
+            msg = tmp;
+            tmp = null;
+        }
+        
+        
+        bytesReceived+=((LoadMessage)msg).getMessage().length;
+        mBytesReceived+=((float)((LoadMessage)msg).getMessage().length)/1024f/1024f;
+        messagesReceived++;
+        if ( (messagesReceived%statsInterval)==0 || (messagesReceived==msgCount)) {
+            float bytes = (float)(((LoadMessage)msg).getMessage().length*messagesReceived);
+            float seconds = ((float)(System.currentTimeMillis()-receiveStart)) / 1000f;
+            log.info("****RECEIVE STATS-"+Thread.currentThread().getName()+"*****"+
+                     "\n\tMessage count :"+(long)messagesReceived+
+                     "\n\tTotal bytes   :"+(long)bytes+
+                     "\n\tTotal mbytes  :"+(long)mBytesReceived+
+                     "\n\tTime since 1st:"+seconds+" seconds"+
+                     "\n\tBytes/second  :"+(bytes/seconds)+
+                     "\n\tMBytes/second :"+(mBytesReceived/seconds)+"\n");
+
+        }
+    }
+    
+    
+    public static void printArray(byte[] data) {
+        System.out.print("{");
+        for (int i=0; i<data.length; i++ ) {
+            System.out.print(data[i]);
+            System.out.print(",");
+        }
+        System.out.println("} size:"+data.length);
+    }
+
+    
+    
+    //public static class LoadMessage implements Serializable  {
+    public static class LoadMessage extends ByteMessage  implements Serializable {
+        
+        public static byte[] outdata = new byte[size];
+        public static Random r = new Random(System.currentTimeMillis());
+        public static int getMessageSize (LoadMessage msg) {
+            int messageSize = msg.getMessage().length;
+            if ( ((Object)msg) instanceof ByteMessage ) return messageSize;
+            try {
+                messageSize  = XByteBuffer.serialize(new LoadMessage()).length;
+                log.info("Average message size:" + messageSize + " bytes");
+            } catch (Exception x) {
+                log.error("Unable to calculate test message size.", x);
+            }
+            return messageSize;
+        }
+        static {
+            r.nextBytes(outdata);
+        }
+        
+        protected byte[] message = getMessage();
+        
+        public LoadMessage() {
+        }
+        
+        public byte[] getMessage() {
+            if ( message == null ) {
+                message = outdata;
+            }
+            return message;
+        }
+        
+        public void setMessage(byte[] data) {
+            this.message = data;
+        }
+    }
+    
+    public static void usage() {
+        System.out.println("Tribes Load tester.");
+        System.out.println("The load tester can be used in sender or received mode or both");
+        System.out.println("Usage:\n\t"+
+                           "java LoadTest [options]\n\t"+
+                           "Options:\n\t\t"+
+                           "[-mode receive|send|both]  \n\t\t"+
+                           "[-startoptions startflags (default is Channel.DEFAULT) ]  \n\t\t"+
+                           "[-debug]  \n\t\t"+
+                           "[-count messagecount]  \n\t\t"+
+                           "[-stats statinterval]  \n\t\t"+
+                           "[-pause nrofsecondstopausebetweensends]  \n\t\t"+
+                           "[-threads numberofsenderthreads]  \n\t\t"+
+                           "[-size messagesize]  \n\t\t"+
+                           "[-sendoptions channeloptions]  \n\t\t"+
+                           "[-break (halts execution on exception)]\n"+
+                           "[-shutdown (issues a channel.stop() command after send is completed)]\n"+
+                           "\tChannel options:"+
+                           ChannelCreator.usage()+"\n\n"+
+                           "Example:\n\t"+
+                           "java LoadTest -port 4004\n\t"+
+                           "java LoadTest -bind 192.168.0.45 -port 4005\n\t"+
+                           "java LoadTest -bind 192.168.0.45 -port 4005 -mbind 192.168.0.45 -count 100 -stats 10\n");
+    }
+    
+    public static void main(String[] args) throws Exception {
+        boolean send = true;
+        boolean debug = false;
+        long pause = 0;
+        int count = 1000000;
+        int stats = 10000;
+        boolean breakOnEx = false;
+        int threads = 1;
+        boolean shutdown = false;
+        int startoptions = Channel.DEFAULT;
+        int channelOptions = Channel.SEND_OPTIONS_DEFAULT;
+        if ( args.length == 0 ) {
+            args = new String[] {"-help"};
+        }
+        for (int i = 0; i < args.length; i++) {
+            if ("-threads".equals(args[i])) {
+                threads = Integer.parseInt(args[++i]);
+            } else if ("-count".equals(args[i])) {
+                count = Integer.parseInt(args[++i]);
+                System.out.println("Sending "+count+" messages.");
+            } else if ("-pause".equals(args[i])) {
+                pause = Long.parseLong(args[++i])*1000;
+            } else if ("-break".equals(args[i])) {
+                breakOnEx = true;
+            } else if ("-shutdown".equals(args[i])) {
+                shutdown = true;
+            } else if ("-stats".equals(args[i])) {
+                stats = Integer.parseInt(args[++i]);
+                System.out.println("Stats every "+stats+" message");
+            } else if ("-sendoptions".equals(args[i])) {
+                channelOptions = Integer.parseInt(args[++i]);
+                System.out.println("Setting send options to "+channelOptions);
+            } else if ("-startoptions".equals(args[i])) {
+                startoptions = Integer.parseInt(args[++i]);
+                System.out.println("Setting start options to "+startoptions);
+            } else if ("-size".equals(args[i])) {
+                size = Integer.parseInt(args[++i])-4;
+                System.out.println("Message size will be:"+(size+4)+" bytes");
+            } else if ("-mode".equals(args[i])) {
+                if ( "receive".equals(args[++i]) ) send = false;
+            } else if ("-debug".equals(args[i])) {
+                debug = true;
+            } else if ("-help".equals(args[i])) 
+            {
+                usage();
+                System.exit(1);
+            }
+        }
+        
+        ManagedChannel channel = (ManagedChannel)ChannelCreator.createChannel(args);
+        
+        LoadTest test = new LoadTest(channel,send,count,debug,pause,stats,breakOnEx);
+        test.channelOptions = channelOptions;
+        LoadMessage msg = new LoadMessage();
+        
+        messageSize = LoadMessage.getMessageSize(msg);
+        channel.addChannelListener(test);
+        channel.addMembershipListener(test);
+        channel.start(startoptions);
+        Runtime.getRuntime().addShutdownHook(new Shutdown(channel));
+        while ( threads > 1 ) {
+            Thread t = new Thread(test);
+            t.setDaemon(true);
+            t.start();
+            threads--;
+            test = new LoadTest(channel,send,count,debug,pause,stats,breakOnEx);
+            test.channelOptions = channelOptions;
+        }
+        test.run();
+        if ( shutdown && send ) channel.stop(channel.DEFAULT);
+        System.out.println("System test complete, sleeping to let threads finish.");
+        Thread.sleep(60*1000*60);
+    } 
+    
+    public static class Shutdown extends Thread {
+        ManagedChannel channel = null;
+        public Shutdown(ManagedChannel channel) {
+            this.channel = channel;
+        }
+        
+        public void run() {
+            System.out.println("Shutting down...");
+            SystemExit exit = new SystemExit(5000);
+            exit.setDaemon(true);
+            exit.start();
+            try {
+                channel.stop(channel.DEFAULT);
+                
+            }catch ( Exception x ) {
+                x.printStackTrace();
+            }
+            System.out.println("Channel stopped.");
+        }
+    }
+    public static class SystemExit extends Thread {
+        private long delay;
+        public SystemExit(long delay) {
+            this.delay = delay;
+        }
+        public void run () {
+            try {
+                Thread.sleep(delay);
+            }catch ( Exception x ) {
+                x.printStackTrace();
+            }
+            System.exit(0);
+
+        }
+    }
+    
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/test/java/org/apache/catalina/tribes/demos/MapDemo.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/test/java/org/apache/catalina/tribes/demos/MapDemo.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/test/java/org/apache/catalina/tribes/demos/MapDemo.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,415 @@
+package org.apache.catalina.tribes.demos;
+
+import java.io.Serializable;
+import java.util.Map;
+
+import java.awt.ComponentOrientation;
+import java.awt.Dimension;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import javax.swing.BoxLayout;
+import javax.swing.JButton;
+import javax.swing.JFrame;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JTable;
+import javax.swing.JTextField;
+import javax.swing.table.AbstractTableModel;
+import javax.swing.table.TableModel;
+
+import org.apache.catalina.tribes.Channel;
+import org.apache.catalina.tribes.ChannelListener;
+import org.apache.catalina.tribes.ManagedChannel;
+import org.apache.catalina.tribes.Member;
+import org.apache.catalina.tribes.MembershipListener;
+import org.apache.catalina.tribes.tipis.AbstractReplicatedMap;
+import org.apache.catalina.tribes.tipis.LazyReplicatedMap;
+import javax.swing.table.DefaultTableCellRenderer;
+import java.awt.Color;
+import java.awt.Component;
+import javax.swing.table.TableColumn;
+import org.apache.catalina.tribes.util.UUIDGenerator;
+import org.apache.catalina.tribes.util.Arrays;
+
+/**
+ * <p>Title: </p>
+ *
+ * <p>Description: </p>
+ *
+ * <p>Copyright: Copyright (c) 2005</p>
+ *
+ * <p>Company: </p>
+ *
+ * @author not attributable
+ * @version 1.0
+ */
+public class MapDemo implements ChannelListener, MembershipListener{
+    
+    protected LazyReplicatedMap map;
+    protected SimpleTableDemo table;
+    
+    public MapDemo(Channel channel, String mapName ) {
+        map = new LazyReplicatedMap(null,channel,5000, mapName,null);
+        table = SimpleTableDemo.createAndShowGUI(map,channel.getLocalMember(false).getName());
+        channel.addChannelListener(this);
+        channel.addMembershipListener(this);
+//        for ( int i=0; i<1000; i++ ) {
+//            map.put("MyKey-"+i,"My String Value-"+i);
+//        }
+        this.messageReceived(null,null);
+    }
+    
+    public boolean accept(Serializable msg, Member source) {
+        table.dataModel.getValueAt(-1,-1);
+        return false;
+    }
+    
+    public void messageReceived(Serializable msg, Member source) {
+        
+    }
+    
+    public void memberAdded(Member member) {
+    }
+    public void memberDisappeared(Member member) {
+        table.dataModel.getValueAt(-1,-1);
+    }
+    
+    public static void usage() {
+        System.out.println("Tribes MapDemo.");
+        System.out.println("Usage:\n\t" + 
+                           "java MapDemo [channel options] mapName\n\t" +
+                           "\tChannel options:" +
+                           ChannelCreator.usage());
+    }
+
+    public static void main(String[] args) throws Exception {
+        long start = System.currentTimeMillis();
+        ManagedChannel channel = (ManagedChannel) ChannelCreator.createChannel(args);
+        String mapName = "MapDemo";
+        if ( args.length > 0 && (!args[args.length-1].startsWith("-"))) {
+            mapName = args[args.length-1];
+        }
+        channel.start(channel.DEFAULT);
+        Runtime.getRuntime().addShutdownHook(new Shutdown(channel));
+        MapDemo demo = new MapDemo(channel,mapName);
+        
+        System.out.println("System test complete, time to start="+(System.currentTimeMillis()-start)+" ms. Sleeping to let threads finish.");
+        Thread.sleep(60 * 1000 * 60);
+    }
+
+    public static class Shutdown
+        extends Thread {
+        ManagedChannel channel = null;
+        public Shutdown(ManagedChannel channel) {
+            this.channel = channel;
+        }
+
+        public void run() {
+            System.out.println("Shutting down...");
+            SystemExit exit = new SystemExit(5000);
+            exit.setDaemon(true);
+            exit.start();
+            try {
+                channel.stop(channel.DEFAULT);
+
+            } catch (Exception x) {
+                x.printStackTrace();
+            }
+            System.out.println("Channel stopped.");
+        }
+    }
+
+    public static class SystemExit
+        extends Thread {
+        private long delay;
+        public SystemExit(long delay) {
+            this.delay = delay;
+        }
+
+        public void run() {
+            try {
+                Thread.sleep(delay);
+            } catch (Exception x) {
+                x.printStackTrace();
+            }
+            System.exit(0);
+
+        }
+    }
+
+    public static class SimpleTableDemo
+        extends JPanel implements ActionListener{
+        private static int WIDTH = 550;
+        
+        private LazyReplicatedMap map;
+        private boolean DEBUG = false;
+        AbstractTableModel dataModel = new AbstractTableModel() {
+            
+            
+            String[] columnNames = {
+                                   "Key",
+                                   "Value",
+                                   "Backup Node",
+                                   "isPrimary",
+                                   "isProxy",
+                                   "isBackup"};
+
+            public int getColumnCount() { return columnNames.length; }
+    
+            public int getRowCount() {return map.sizeFull() +1; }
+            
+            public StringBuffer getMemberNames(Member[] members){
+                StringBuffer buf = new StringBuffer();
+                if ( members!=null ) {
+                    for (int i=0;i<members.length; i++ ) {
+                        buf.append(members[i].getName());
+                        buf.append("; ");
+                    }
+                }
+                return buf;
+            }
+            
+            public Object getValueAt(int row, int col) {
+                if ( row==-1 ) {
+                    update();
+                    return "";
+                }
+                if ( row == 0 ) return columnNames[col];
+                Object[] entries = map.entrySetFull().toArray();
+                Map.Entry e = (Map.Entry)entries [row-1];
+                LazyReplicatedMap.MapEntry entry = (LazyReplicatedMap.MapEntry)e.getValue();
+                switch (col) {
+                    case 0: return entry.getKey();
+                    case 1: return entry.getValue();
+                    case 2: return getMemberNames(entry.getBackupNodes());
+                    case 3: return new Boolean(entry.isPrimary());
+                    case 4: return new Boolean(entry.isProxy());
+                    case 5: return new Boolean(entry.isBackup());
+                    default: return "";
+                }
+                
+            }
+            
+            public void update() {
+                fireTableDataChanged();
+            }
+        };
+        
+        JTextField txtAddKey = new JTextField(20);
+        JTextField txtAddValue = new JTextField(20);
+        JTextField txtRemoveKey = new JTextField(20);
+        JTextField txtChangeKey = new JTextField(20);
+        JTextField txtChangeValue = new JTextField(20);
+        
+        JTable table = null;
+        public SimpleTableDemo(LazyReplicatedMap map) {
+            super();
+            this.map = map;
+            
+            this.setComponentOrientation(ComponentOrientation.LEFT_TO_RIGHT);
+
+            //final JTable table = new JTable(data, columnNames);
+            table = new JTable(dataModel);
+
+            table.setPreferredScrollableViewportSize(new Dimension(WIDTH, 150));
+            for ( int i=0; i<table.getColumnCount(); i++ ) {
+                TableColumn tm = table.getColumnModel().getColumn(i);
+                tm.setCellRenderer(new ColorRenderer());
+            }
+
+
+            if (DEBUG) {
+                table.addMouseListener(new MouseAdapter() {
+                    public void mouseClicked(MouseEvent e) {
+                        printDebugData(table);
+                    }
+                });
+            }
+            
+            //setLayout(new GridLayout(5, 0));
+            setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
+
+            //Create the scroll pane and add the table to it.
+            JScrollPane scrollPane = new JScrollPane(table);
+
+            //Add the scroll pane to this panel.
+            add(scrollPane);
+            
+            //create a add value button
+            JPanel addpanel = new JPanel();
+            addpanel.setPreferredSize(new Dimension(WIDTH,30));
+            addpanel.add(createButton("Add","add"));
+            addpanel.add(txtAddKey);
+            addpanel.add(txtAddValue);
+            addpanel.setMaximumSize(new Dimension(WIDTH,30));
+            add(addpanel);
+            
+            //create a remove value button
+            JPanel removepanel = new JPanel( );
+            removepanel.setPreferredSize(new Dimension(WIDTH,30));
+            removepanel.add(createButton("Remove","remove"));
+            removepanel.add(txtRemoveKey);
+            removepanel.setMaximumSize(new Dimension(WIDTH,30));
+            add(removepanel);
+
+            //create a change value button
+            JPanel changepanel = new JPanel( );
+            changepanel.add(createButton("Change","change"));
+            changepanel.add(txtChangeKey);
+            changepanel.add(txtChangeValue);
+            changepanel.setPreferredSize(new Dimension(WIDTH,30));
+            changepanel.setMaximumSize(new Dimension(WIDTH,30));
+            add(changepanel);
+
+
+            //create sync button
+            JPanel syncpanel = new JPanel( );
+            syncpanel.add(createButton("Synchronize","sync"));
+            syncpanel.add(createButton("Replicate","replicate"));
+            syncpanel.add(createButton("Random","random"));
+            syncpanel.setPreferredSize(new Dimension(WIDTH,30));
+            syncpanel.setMaximumSize(new Dimension(WIDTH,30));
+            add(syncpanel);
+
+
+        }
+        
+        public JButton createButton(String text, String command) {
+            JButton button = new JButton(text);
+            button.setActionCommand(command);
+            button.addActionListener(this);
+            return button;
+        }
+        
+        public void actionPerformed(ActionEvent e) {
+            System.out.println(e.getActionCommand());
+            if ( "add".equals(e.getActionCommand()) ) {
+                System.out.println("Add key:"+txtAddKey.getText()+" value:"+txtAddValue.getText());
+                map.put(txtAddKey.getText(),new StringBuffer(txtAddValue.getText()));
+            }
+            if ( "change".equals(e.getActionCommand()) ) {
+                System.out.println("Change key:"+txtChangeKey.getText()+" value:"+txtChangeValue.getText());
+                StringBuffer buf = (StringBuffer)map.get(txtChangeKey.getText());
+                if ( buf!=null ) {
+                    buf.delete(0,buf.length());
+                    buf.append(txtChangeValue.getText());
+                    map.replicate(txtChangeKey.getText(),true);
+                } else {
+                    buf = new StringBuffer();
+                    buf.append(txtChangeValue.getText());
+                    map.put(txtChangeKey.getText(),buf);
+                }
+            }
+            if ( "remove".equals(e.getActionCommand()) ) {
+                System.out.println("Remove key:"+txtRemoveKey.getText());
+                map.remove(txtRemoveKey.getText());
+            }
+            if ( "sync".equals(e.getActionCommand()) ) {
+                System.out.println("Syncing from another node.");
+                map.transferState();
+            }
+            if ( "random".equals(e.getActionCommand()) ) {
+                Thread t = new Thread() {
+                    public void run() {
+                        for (int i = 0; i < 100; i++) {
+                            String key = Arrays.toString(UUIDGenerator.randomUUID(false));
+                            map.put(key, key);
+                            dataModel.fireTableDataChanged();
+                            table.paint(table.getGraphics());
+                            try {
+                                Thread.sleep(500);
+                            } catch (InterruptedException x) {
+                                Thread.currentThread().interrupted();
+                            }
+                        }
+                    }
+                };
+                t.start();
+            }
+            
+            if ( "replicate".equals(e.getActionCommand()) ) {
+                System.out.println("Replicating out to the other nodes.");
+                map.replicate(true);
+            }
+            dataModel.getValueAt(-1,-1);
+        }
+
+        private void printDebugData(JTable table) {
+            int numRows = table.getRowCount();
+            int numCols = table.getColumnCount();
+            javax.swing.table.TableModel model = table.getModel();
+
+            System.out.println("Value of data: ");
+            for (int i = 0; i < numRows; i++) {
+                System.out.print("    row " + i + ":");
+                for (int j = 0; j < numCols; j++) {
+                    System.out.print("  " + model.getValueAt(i, j));
+                }
+                System.out.println();
+            }
+            System.out.println("--------------------------");
+        }
+
+        /**
+         * Create the GUI and show it.  For thread safety,
+         * this method should be invoked from the
+         * event-dispatching thread.
+         */
+        public static SimpleTableDemo createAndShowGUI(LazyReplicatedMap map, String title) {
+            //Make sure we have nice window decorations.
+            JFrame.setDefaultLookAndFeelDecorated(true);
+
+            //Create and set up the window.
+            JFrame frame = new JFrame("SimpleTableDemo - "+title);
+            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+
+            //Create and set up the content pane.
+            SimpleTableDemo newContentPane = new SimpleTableDemo(map);
+            newContentPane.setOpaque(true); //content panes must be opaque
+            frame.setContentPane(newContentPane);
+
+            //Display the window.
+            frame.setSize(450,250);
+            newContentPane.setSize(450,300);
+            frame.pack();
+            frame.setVisible(true);
+            return newContentPane;
+        }
+    }
+    
+    static class ColorRenderer extends DefaultTableCellRenderer {
+        
+        public ColorRenderer() {
+            super();
+        }
+
+        public Component getTableCellRendererComponent
+            (JTable table, Object value, boolean isSelected,
+             boolean hasFocus, int row, int column) {
+            Component cell = super.getTableCellRendererComponent
+                             (table, value, isSelected, hasFocus, row, column);
+            cell.setBackground(Color.WHITE);
+            if ( row > 0 ) {
+                Color color = null;
+                boolean primary = ( (Boolean) table.getValueAt(row, 3)).booleanValue();
+                boolean proxy = ( (Boolean) table.getValueAt(row, 4)).booleanValue();
+                boolean backup = ( (Boolean) table.getValueAt(row, 5)).booleanValue();
+                if (primary) color = Color.GREEN;
+                else if (proxy) color = Color.RED;
+                else if (backup) color = Color.BLUE;
+                if ( color != null ) cell.setBackground(color);
+            }
+//            System.out.println("Row:"+row+" Column:"+column+" Color:"+cell.getBackground());
+//            cell.setBackground(bkgndColor);
+//            cell.setForeground(fgndColor);
+
+            return cell;
+        }
+        
+        
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/test/java/org/apache/catalina/tribes/test/TestNioSender.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/test/java/org/apache/catalina/tribes/test/TestNioSender.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/test/java/org/apache/catalina/tribes/test/TestNioSender.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,106 @@
+package org.apache.catalina.tribes.test;
+
+import java.io.IOException;
+import java.nio.channels.SelectionKey;
+import java.util.Iterator;
+import java.nio.channels.Selector;
+import org.apache.catalina.tribes.transport.nio.NioSender;
+import org.apache.catalina.tribes.membership.MemberImpl;
+import org.apache.catalina.tribes.io.ChannelData;
+import org.apache.catalina.tribes.io.XByteBuffer;
+import org.apache.catalina.tribes.Member;
+import org.apache.catalina.tribes.Channel;
+
+/**
+ * <p>Title: </p>
+ *
+ * <p>Description: </p>
+ *
+ * <p>Copyright: Copyright (c) 2005</p>
+ *
+ * <p>Company: </p>
+ *
+ * @author not attributable
+ * @version 1.0
+ */
+public class TestNioSender {
+    private Selector selector = null;
+    private int counter = 0;
+    MemberImpl mbr;
+    private static int testOptions = Channel.SEND_OPTIONS_DEFAULT;
+    public TestNioSender()  {
+        
+    }
+    
+    public synchronized int inc() {
+        return ++counter;
+    }
+    
+    public synchronized ChannelData getMessage(Member mbr) {
+        String msg = new String("Thread-"+Thread.currentThread().getName()+" Message:"+inc());
+        ChannelData data = new ChannelData(true);
+        data.setMessage(new XByteBuffer(msg.getBytes(),false));
+        data.setAddress(mbr);
+        
+        return data;
+    }
+
+    public void init() throws Exception {
+        selector = Selector.open();
+        mbr = new MemberImpl("localhost",4444,0);
+        NioSender sender = new NioSender();
+        sender.setDestination(mbr);
+        sender.setDirectBuffer(true);
+        sender.setSelector(selector);
+        sender.setMessage(XByteBuffer.createDataPackage(getMessage(mbr)));
+        sender.connect();
+    }
+
+    public void run() {
+        while (true) {
+
+            int selectedKeys = 0;
+            try {
+                selectedKeys = selector.select(100);
+                //               if ( selectedKeys == 0 ) {
+                //                   System.out.println("No registered interests. Sleeping for a second.");
+                //                   Thread.sleep(100);
+            } catch (Exception e) {
+                e.printStackTrace();
+                continue;
+            }
+
+            if (selectedKeys == 0) {
+                continue;
+            }
+
+            Iterator it = selector.selectedKeys().iterator();
+            while (it.hasNext()) {
+                SelectionKey sk = (SelectionKey) it.next();
+                it.remove();
+                try {
+                    int readyOps = sk.readyOps();
+                    sk.interestOps(sk.interestOps() & ~readyOps);
+                    NioSender sender = (NioSender) sk.attachment();
+                    if ( sender.process(sk, (testOptions&Channel.SEND_OPTIONS_USE_ACK)==Channel.SEND_OPTIONS_USE_ACK) ) {
+                        System.out.println("Message completed for handler:"+sender);
+                        Thread.currentThread().sleep(2000);
+                        sender.reset();
+                        sender.setMessage(XByteBuffer.createDataPackage(getMessage(mbr)));
+                    }
+                    
+
+                } catch (Throwable t) {
+                    t.printStackTrace();
+                    return;
+                }
+            }
+        }
+    }
+
+    public static void main(String[] args) throws Exception {
+        TestNioSender sender = new TestNioSender();
+        sender.init();
+        sender.run();
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/test/java/org/apache/catalina/tribes/test/TribesTestSuite.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/test/java/org/apache/catalina/tribes/test/TribesTestSuite.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/test/java/org/apache/catalina/tribes/test/TribesTestSuite.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,24 @@
+package org.apache.catalina.tribes.test;
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+
+public class TribesTestSuite
+    extends TestCase {
+
+    public TribesTestSuite(String s) {
+        super(s);
+    }
+
+    public static Test suite() {
+        TestSuite suite = new TestSuite();
+        suite.addTestSuite(org.apache.catalina.tribes.test.channel.ChannelStartStop.class);
+        suite.addTestSuite(org.apache.catalina.tribes.test.channel.TestChannelOptionFlag.class);
+        suite.addTestSuite(org.apache.catalina.tribes.test.membership.MemberSerialization.class);
+        suite.addTestSuite(org.apache.catalina.tribes.test.membership.TestMemberArrival.class);
+        suite.addTestSuite(org.apache.catalina.tribes.test.membership.TestTcpFailureDetector.class);
+        suite.addTestSuite(org.apache.catalina.tribes.test.channel.TestDataIntegrity.class);
+        return suite;
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/test/java/org/apache/catalina/tribes/test/channel/ChannelStartStop.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/test/java/org/apache/catalina/tribes/test/channel/ChannelStartStop.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/test/java/org/apache/catalina/tribes/test/channel/ChannelStartStop.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,118 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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
+ */
+package org.apache.catalina.tribes.test.channel;
+
+import org.apache.catalina.tribes.group.GroupChannel;
+import junit.framework.TestCase;
+
+/**
+ * @author Filip Hanik
+ * @version 1.0
+ */
+public class ChannelStartStop extends TestCase {
+    GroupChannel channel = null;
+    protected void setUp() throws Exception {
+        super.setUp();
+        channel = new GroupChannel();
+    }
+
+    protected void tearDown() throws Exception {
+        super.tearDown();
+        try {channel.stop(channel.DEFAULT);}catch (Exception ignore){}
+    }
+    
+    public void testDoubleFullStart() throws Exception {
+        int count = 0;
+        try {
+            channel.start(channel.DEFAULT);
+            count++;
+        } catch ( Exception x){x.printStackTrace();}
+        try {
+            channel.start(channel.DEFAULT);
+            count++;
+        } catch ( Exception x){x.printStackTrace();}
+        assertEquals(count,2);
+        channel.stop(channel.DEFAULT);
+    }
+
+    public void testDoublePartialStart() throws Exception {
+        //try to double start the RX 
+        int count = 0;
+        try {
+            channel.start(channel.SND_RX_SEQ);
+            channel.start(channel.MBR_RX_SEQ);
+            count++;
+        } catch ( Exception x){x.printStackTrace();}
+        try {
+            channel.start(channel.MBR_RX_SEQ);
+            count++;
+        } catch ( Exception x){/*expected*/}
+        assertEquals(count,1);
+        channel.stop(channel.DEFAULT);
+        //double the membership sender
+        count = 0;
+        try {
+            channel.start(channel.SND_RX_SEQ);
+            channel.start(channel.MBR_TX_SEQ);
+            count++;
+        } catch ( Exception x){x.printStackTrace();}
+        try {
+            channel.start(channel.MBR_TX_SEQ);
+            count++;
+        } catch ( Exception x){/*expected*/}
+        assertEquals(count,1);
+        channel.stop(channel.DEFAULT);
+        
+        count = 0;
+        try {
+            channel.start(channel.SND_RX_SEQ);
+            count++;
+        } catch ( Exception x){x.printStackTrace();}
+        try {
+            channel.start(channel.SND_RX_SEQ);
+            count++;
+        } catch ( Exception x){/*expected*/}
+        assertEquals(count,1);
+        channel.stop(channel.DEFAULT);
+
+        count = 0;
+        try {
+            channel.start(channel.SND_TX_SEQ);
+            count++;
+        } catch ( Exception x){x.printStackTrace();}
+        try {
+            channel.start(channel.SND_TX_SEQ);
+            count++;
+        } catch ( Exception x){/*expected*/}
+        assertEquals(count,1);
+        channel.stop(channel.DEFAULT);
+    }
+    
+    public void testFalseOption() throws Exception {
+        int flag = 0xFFF0;//should get ignored by the underlying components
+        int count = 0;
+        try {
+            channel.start(flag);
+            count++;
+        } catch ( Exception x){x.printStackTrace();}
+        try {
+            channel.start(flag);
+            count++;
+        } catch ( Exception x){/*expected*/}
+        assertEquals(count,2);
+        channel.stop(channel.DEFAULT);
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/test/java/org/apache/catalina/tribes/test/channel/TestChannelOptionFlag.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/test/java/org/apache/catalina/tribes/test/channel/TestChannelOptionFlag.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/test/java/org/apache/catalina/tribes/test/channel/TestChannelOptionFlag.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,76 @@
+package org.apache.catalina.tribes.test.channel;
+
+import junit.framework.*;
+import org.apache.catalina.tribes.group.*;
+import org.apache.catalina.tribes.ChannelInterceptor;
+import org.apache.catalina.tribes.ChannelException;
+
+/**
+ * <p>Title: </p> 
+ * 
+ * <p>Description: </p> 
+ * 
+ * <p>Copyright: Copyright (c) 2005</p> 
+ * 
+ * <p>Company: </p>
+ * 
+ * @author not attributable
+ * @version 1.0
+ */
+public class TestChannelOptionFlag extends TestCase {
+    GroupChannel channel = null;
+    protected void setUp() throws Exception {
+        super.setUp();
+        channel = new GroupChannel();
+    }
+
+    protected void tearDown() throws Exception {
+        super.tearDown();
+        if ( channel != null ) try {channel.stop(channel.DEFAULT);}catch ( Exception ignore) {}
+        channel = null;
+    }
+    
+    
+    public void testOptionConflict() throws Exception {
+        boolean error = false;
+        channel.setOptionCheck(true);
+        ChannelInterceptor i = new TestInterceptor();
+        i.setOptionFlag(128);
+        channel.addInterceptor(i);
+        i = new TestInterceptor();
+        i.setOptionFlag(128);
+        channel.addInterceptor(i);
+        try {
+            channel.start(channel.DEFAULT);
+        }catch ( ChannelException x ) {
+            if ( x.getMessage().indexOf("option flag conflict") >= 0 ) error = true;
+        }
+        assertEquals(true,error);
+    }
+
+    public void testOptionNoConflict() throws Exception {
+        boolean error = false;
+        channel.setOptionCheck(true);
+        ChannelInterceptor i = new TestInterceptor();
+        i.setOptionFlag(128);
+        channel.addInterceptor(i);
+        i = new TestInterceptor();
+        i.setOptionFlag(64);
+        channel.addInterceptor(i);
+        i = new TestInterceptor();
+        i.setOptionFlag(256);
+        channel.addInterceptor(i);
+        try {
+            channel.start(channel.DEFAULT);
+        }catch ( ChannelException x ) {
+            if ( x.getMessage().indexOf("option flag conflict") >= 0 ) error = true;
+        }
+        assertEquals(false,error);
+    }
+    
+    public static class TestInterceptor extends ChannelInterceptorBase {
+        
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/test/java/org/apache/catalina/tribes/test/channel/TestDataIntegrity.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/test/java/org/apache/catalina/tribes/test/channel/TestDataIntegrity.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/test/java/org/apache/catalina/tribes/test/channel/TestDataIntegrity.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,173 @@
+package org.apache.catalina.tribes.test.channel;
+
+import junit.framework.TestCase;
+import java.io.Serializable;
+import java.util.Random;
+import java.util.Arrays;
+import org.apache.catalina.tribes.ChannelListener;
+import org.apache.catalina.tribes.Member;
+import org.apache.catalina.tribes.group.GroupChannel;
+import org.apache.catalina.tribes.test.channel.TestDataIntegrity.Listener;
+import org.apache.catalina.tribes.group.interceptors.MessageDispatchInterceptor;
+import org.apache.catalina.tribes.group.interceptors.MessageDispatch15Interceptor;
+
+/**
+ * <p>Title: </p> 
+ * 
+ * <p>Description: </p> 
+ * 
+ * <p>Copyright: Copyright (c) 2005</p> 
+ * 
+ * <p>Company: </p>
+ * 
+ * @author not attributable
+ * @version 1.0
+ */
+public class TestDataIntegrity extends TestCase {
+    int msgCount = 1000;
+    int threadCount = 20;
+    GroupChannel channel1;
+    GroupChannel channel2;
+    Listener listener1;
+    int threadCounter = 0;
+    protected void setUp() throws Exception {
+        super.setUp();
+        channel1 = new GroupChannel();
+        channel1.addInterceptor(new MessageDispatch15Interceptor());
+        channel2 = new GroupChannel();
+        channel2.addInterceptor(new MessageDispatch15Interceptor());
+        listener1 = new Listener();
+        channel2.addChannelListener(listener1);
+        channel1.start(GroupChannel.DEFAULT);
+        channel2.start(GroupChannel.DEFAULT);
+    }
+
+    protected void tearDown() throws Exception {
+        super.tearDown();
+        channel1.stop(GroupChannel.DEFAULT);
+        channel2.stop(GroupChannel.DEFAULT);
+    }
+    
+    public void testDataSendNO_ACK() throws Exception {
+        System.err.println("Starting NO_ACK");
+        Thread[] threads = new Thread[threadCount];
+        for (int x=0; x<threads.length; x++ ) {
+            threads[x] = new Thread() {
+                public void run() {
+                    try {
+                        for (int i = 0; i < msgCount; i++) channel1.send(new Member[] {channel2.getLocalMember(false)}, Data.createRandomData(),0);
+                    }catch ( Exception x ) {
+                        x.printStackTrace();
+                        return;
+                    } finally {
+                        threadCounter++;
+                    }
+                }
+            };
+        }
+        for (int x=0; x<threads.length; x++ ) { threads[x].start();}
+        for (int x=0; x<threads.length; x++ ) { threads[x].join();}
+        //sleep for 50 sec, let the other messages in
+        long start = System.currentTimeMillis();
+        while ( (System.currentTimeMillis()-start)<15000 && msgCount*threadCount!=listener1.count) Thread.sleep(500);
+        System.err.println("Finished NO_ACK");
+        assertEquals("Checking success messages.",msgCount*threadCount,listener1.count);
+    }
+    
+    public void testDataSendASYNCM() throws Exception {
+            System.err.println("Starting ASYNC MULTI THREAD");
+            Thread[] threads = new Thread[threadCount];
+            for (int x=0; x<threads.length; x++ ) {
+                threads[x] = new Thread() {
+                    public void run() {
+                        try {
+                            for (int i = 0; i < msgCount; i++) channel1.send(new Member[] {channel2.getLocalMember(false)}, Data.createRandomData(),GroupChannel.SEND_OPTIONS_ASYNCHRONOUS);
+                        }catch ( Exception x ) {
+                            x.printStackTrace();
+                            return;
+                        } finally {
+                            threadCounter++;
+                        }
+                    }
+                };
+            }
+            for (int x=0; x<threads.length; x++ ) { threads[x].start();}
+            for (int x=0; x<threads.length; x++ ) { threads[x].join();}
+            //sleep for 50 sec, let the other messages in
+            long start = System.currentTimeMillis();
+            while ( (System.currentTimeMillis()-start)<15000 && msgCount*threadCount!=listener1.count) Thread.sleep(500);
+            System.err.println("Finished ASYNC MULTI THREAD");
+            assertEquals("Checking success messages.",msgCount*threadCount,listener1.count);
+    }
+    public void testDataSendASYNC() throws Exception {
+        System.err.println("Starting ASYNC");
+        for (int i=0; i<msgCount; i++) channel1.send(new Member[] {channel2.getLocalMember(false)},Data.createRandomData(),GroupChannel.SEND_OPTIONS_ASYNCHRONOUS);
+        //sleep for 50 sec, let the other messages in
+        long start = System.currentTimeMillis();
+        while ( (System.currentTimeMillis()-start)<5000 && msgCount!=listener1.count) Thread.sleep(500);
+        System.err.println("Finished ASYNC");
+        assertEquals("Checking success messages.",msgCount,listener1.count);
+    }
+
+    public void testDataSendACK() throws Exception {
+        System.err.println("Starting ACK");
+        for (int i=0; i<msgCount; i++) channel1.send(new Member[] {channel2.getLocalMember(false)},Data.createRandomData(),GroupChannel.SEND_OPTIONS_USE_ACK);
+        Thread.sleep(250);
+        System.err.println("Finished ACK");
+        assertEquals("Checking success messages.",msgCount,listener1.count);
+    }
+
+    public void testDataSendSYNCACK() throws Exception {
+        System.err.println("Starting SYNC_ACK");
+        for (int i=0; i<msgCount; i++) channel1.send(new Member[] {channel2.getLocalMember(false)},Data.createRandomData(),GroupChannel.SEND_OPTIONS_SYNCHRONIZED_ACK|GroupChannel.SEND_OPTIONS_USE_ACK);
+        Thread.sleep(250);
+        System.err.println("Finished SYNC_ACK");
+        assertEquals("Checking success messages.",msgCount,listener1.count);
+    }
+
+    public static class Listener implements ChannelListener {
+        long count = 0;
+        public boolean accept(Serializable s, Member m) {
+            return (s instanceof Data);
+        }
+        
+        public void messageReceived(Serializable s, Member m) {
+            Data d = (Data)s;
+            if ( !Data.verify(d) ) {
+                System.err.println("ERROR");
+            } else {
+                count++;
+                if ((count %1000) ==0 ) {
+                    System.err.println("SUCCESS:"+count);
+                }
+            }
+        }
+    }
+    
+    public static class Data implements Serializable {
+        public int length;
+        public byte[] data;
+        public byte key;
+        public static Random r = new Random(System.currentTimeMillis());
+        public static Data createRandomData() {
+            int i = r.nextInt();
+            i = ( i % 127 );
+            int length = Math.abs(r.nextInt() % 65555);
+            Data d = new Data();
+            d.length = length;
+            d.key = (byte)i;
+            d.data = new byte[length];
+            Arrays.fill(d.data,d.key);
+            return d;
+        }
+        
+        public static boolean verify(Data d) {
+            boolean result = (d.length == d.data.length);
+            for ( int i=0; result && (i<d.data.length); i++ ) result = result && d.data[i] == d.key;
+            return result;
+        }
+    }
+    
+    
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/test/java/org/apache/catalina/tribes/test/channel/TestRemoteProcessException.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/test/java/org/apache/catalina/tribes/test/channel/TestRemoteProcessException.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/test/java/org/apache/catalina/tribes/test/channel/TestRemoteProcessException.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,123 @@
+package org.apache.catalina.tribes.test.channel;
+
+import junit.framework.TestCase;
+import java.io.Serializable;
+import java.util.Random;
+import java.util.Arrays;
+import org.apache.catalina.tribes.ChannelListener;
+import org.apache.catalina.tribes.Member;
+import org.apache.catalina.tribes.group.GroupChannel;
+import java.io.PrintStream;
+
+/**
+ * <p>Title: </p> 
+ * 
+ * <p>Description: </p> 
+ * 
+ * <p>Copyright: Copyright (c) 2005</p> 
+ * 
+ * <p>Company: </p>
+ * 
+ * @author not attributable
+ * @version 1.0
+ */
+public class TestRemoteProcessException extends TestCase {
+    int msgCount = 10000;
+    GroupChannel channel1;
+    GroupChannel channel2;
+    Listener listener1;
+    protected void setUp() throws Exception {
+        super.setUp();
+        channel1 = new GroupChannel();
+        channel2 = new GroupChannel();
+        listener1 = new Listener();
+        channel2.addChannelListener(listener1);
+        channel1.start(GroupChannel.DEFAULT);
+        channel2.start(GroupChannel.DEFAULT);
+    }
+
+    protected void tearDown() throws Exception {
+        super.tearDown();
+        channel1.stop(GroupChannel.DEFAULT);
+        channel2.stop(GroupChannel.DEFAULT);
+    }
+
+    public void testDataSendSYNCACK() throws Exception {
+        System.err.println("Starting SYNC_ACK");
+        int errC=0, nerrC=0;
+        for (int i=0; i<msgCount; i++) {
+            boolean error = Data.r.nextBoolean();
+            channel1.send(channel1.getMembers(),Data.createRandomData(error),GroupChannel.SEND_OPTIONS_SYNCHRONIZED_ACK|GroupChannel.SEND_OPTIONS_USE_ACK);
+            if ( error ) errC++; else nerrC++;
+        }
+        System.err.println("Finished SYNC_ACK");
+        assertEquals("Checking failure messages.",errC,listener1.errCnt);
+        assertEquals("Checking success messages.",nerrC,listener1.noErrCnt);
+        assertEquals("Checking all messages.",msgCount,listener1.noErrCnt+listener1.errCnt);
+        System.out.println("Listener 1 stats:");
+        listener1.printStats(System.out);
+    }
+
+    public static class Listener implements ChannelListener {
+        long noErrCnt = 0;
+        long errCnt = 0;
+        public boolean accept(Serializable s, Member m) {
+            return (s instanceof Data);
+        }
+
+        public void messageReceived(Serializable s, Member m) {
+            Data d = (Data)s;
+            if ( !Data.verify(d) ) {
+                System.err.println("ERROR");
+            } else {
+                if (d.error) {
+                    errCnt++;
+                    if ( (errCnt % 100) == 0) {
+                        printStats(System.err);
+                    }
+                    throw new IllegalArgumentException();
+                } else {
+                    noErrCnt++;
+                    if ( (noErrCnt % 100) == 0) {
+                        printStats(System.err);
+                    }
+                }
+            }
+        }
+
+        public void printStats(PrintStream stream) {
+            stream.println("NORMAL:" + noErrCnt);
+            stream.println("FAILURES:" + errCnt);
+            stream.println("TOTAL:" + (errCnt+noErrCnt));
+        }
+    }
+
+    public static class Data implements Serializable {
+        public int length;
+        public byte[] data;
+        public byte key;
+        public boolean error = false;
+        public static Random r = new Random(System.currentTimeMillis());
+        public static Data createRandomData(boolean error) {
+            int i = r.nextInt();
+            i = ( i % 127 );
+            int length = Math.abs(r.nextInt() % 65555);
+            Data d = new Data();
+            d.length = length;
+            d.key = (byte)i;
+            d.data = new byte[length];
+            Arrays.fill(d.data,d.key);
+            d.error = error;
+            return d;
+        }
+
+        public static boolean verify(Data d) {
+            boolean result = (d.length == d.data.length);
+            for ( int i=0; result && (i<d.data.length); i++ ) result = result && d.data[i] == d.key;
+            return result;
+        }
+    }
+
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/test/java/org/apache/catalina/tribes/test/interceptors/TestNonBlockingCoordinator.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/test/java/org/apache/catalina/tribes/test/interceptors/TestNonBlockingCoordinator.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/test/java/org/apache/catalina/tribes/test/interceptors/TestNonBlockingCoordinator.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,95 @@
+package org.apache.catalina.tribes.test.interceptors;
+
+import org.apache.catalina.tribes.Channel;
+import org.apache.catalina.tribes.Member;
+import org.apache.catalina.tribes.group.GroupChannel;
+import org.apache.catalina.tribes.group.interceptors.NonBlockingCoordinator;
+import org.apache.catalina.tribes.group.interceptors.TcpFailureDetector;
+import junit.framework.TestCase;
+import junit.framework.TestResult;
+import junit.framework.TestSuite;
+
+public class TestNonBlockingCoordinator extends TestCase {
+
+    GroupChannel[] channels = null;
+    NonBlockingCoordinator[] coordinators = null;
+    int channelCount = 10;
+    Thread[] threads = null;
+    protected void setUp() throws Exception {
+        System.out.println("Setup");
+        super.setUp();
+        channels = new GroupChannel[channelCount];
+        coordinators = new NonBlockingCoordinator[channelCount];
+        threads = new Thread[channelCount];
+        for ( int i=0; i<channelCount; i++ ) {
+            channels[i] = new GroupChannel();
+            coordinators[i] = new NonBlockingCoordinator();
+            channels[i].addInterceptor(coordinators[i]);
+            channels[i].addInterceptor(new TcpFailureDetector());
+            final int j = i;
+            threads[i] = new Thread() {
+                public void run() {
+                    try {
+                        channels[j].start(Channel.DEFAULT);
+                        Thread.sleep(50);
+                    } catch (Exception x) {
+                        x.printStackTrace();
+                    }
+                }
+            };
+        }
+        for ( int i=0; i<channelCount; i++ ) threads[i].start();
+        for ( int i=0; i<channelCount; i++ ) threads[i].join();
+        Thread.sleep(1000);
+    }
+    
+    public void testCoord1() throws Exception {
+        for (int i=1; i<channelCount; i++ ) 
+            assertEquals("Message count expected to be equal.",channels[i-1].getMembers().length,channels[i].getMembers().length);
+        Member member = coordinators[0].getCoordinator();
+        int cnt = 0;
+        while ( member == null && (cnt++ < 100 ) ) try {Thread.sleep(100); member = coordinators[0].getCoordinator();}catch ( Exception x){}
+        for (int i=0; i<channelCount; i++ ) super.assertEquals(member,coordinators[i].getCoordinator());
+        System.out.println("Coordinator[1] is:"+member);
+        
+    }
+    
+    public void testCoord2() throws Exception {
+        Member member = coordinators[1].getCoordinator();
+        System.out.println("Coordinator[2a] is:" + member);
+        int index = -1;
+        for ( int i=0; i<channelCount; i++ ) {
+            if ( channels[i].getLocalMember(false).equals(member) ) {
+                System.out.println("Shutting down:" + channels[i].getLocalMember(true).toString());
+                channels[i].stop(Channel.DEFAULT);
+                index = i;
+            }
+        }
+        int dead = index;
+        Thread.sleep(1000);
+        if ( index == 0 ) index = 1; else index = 0;
+        System.out.println("Member count:"+channels[index].getMembers().length);
+        member = coordinators[index].getCoordinator();
+        for (int i = 1; i < channelCount; i++) if ( i != dead ) super.assertEquals(member, coordinators[i].getCoordinator());
+        System.out.println("Coordinator[2b] is:" + member);
+    }
+
+    protected void tearDown() throws Exception {
+        System.out.println("tearDown");
+        super.tearDown();
+        for ( int i=0; i<channelCount; i++ ) {
+            channels[i].stop(Channel.DEFAULT);
+        }
+    }
+    
+    public static void main(String[] args) throws Exception {
+        TestSuite suite = new TestSuite();
+        suite.addTestSuite(TestNonBlockingCoordinator.class);
+        suite.run(new TestResult());
+    }
+    
+    
+    
+    
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/test/java/org/apache/catalina/tribes/test/interceptors/TestTwoPhaseCommit.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/test/java/org/apache/catalina/tribes/test/interceptors/TestTwoPhaseCommit.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/test/java/org/apache/catalina/tribes/test/interceptors/TestTwoPhaseCommit.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,42 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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
+ */
+
+package org.apache.catalina.tribes.test.interceptors;
+
+import junit.framework.TestCase;
+
+/**
+ * <p>Title: </p> 
+ * 
+ * <p>Description: </p> 
+ * 
+ * <p>Copyright: Copyright (c) 2005</p> 
+ * 
+ * <p>Company: </p>
+ * 
+ * @author not attributable
+ * @version 1.0
+ */
+public class TestTwoPhaseCommit extends TestCase {
+
+    protected void setUp() throws Exception {
+        super.setUp();
+    }
+
+    protected void tearDown() throws Exception {
+        super.tearDown();
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/test/java/org/apache/catalina/tribes/test/io/TestSenderConnections.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/test/java/org/apache/catalina/tribes/test/io/TestSenderConnections.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/test/java/org/apache/catalina/tribes/test/io/TestSenderConnections.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,112 @@
+package org.apache.catalina.tribes.test.io;
+
+import java.util.ArrayList;
+
+import org.apache.catalina.tribes.Channel;
+import org.apache.catalina.tribes.ManagedChannel;
+import org.apache.catalina.tribes.Member;
+import org.apache.catalina.tribes.MembershipListener;
+import org.apache.catalina.tribes.group.GroupChannel;
+import junit.framework.TestCase;
+import org.apache.catalina.tribes.ChannelListener;
+import java.io.Serializable;
+import java.util.Random;
+import java.util.HashMap;
+import org.apache.catalina.tribes.transport.ReplicationTransmitter;
+
+public class TestSenderConnections extends TestCase {
+    private static int count = 2;
+    private ManagedChannel[] channels = new ManagedChannel[count];
+    private TestMsgListener[] listeners = new TestMsgListener[count];
+
+    protected void setUp() throws Exception {
+        super.setUp();
+        for (int i = 0; i < channels.length; i++) {
+            channels[i] = new GroupChannel();
+            channels[i].getMembershipService().setPayload( ("Channel-" + (i + 1)).getBytes("ASCII"));
+            listeners[i] = new TestMsgListener( ("Listener-" + (i + 1)));
+            channels[i].addChannelListener(listeners[i]);
+            channels[i].start(Channel.SND_RX_SEQ|Channel.SND_TX_SEQ);
+
+        }
+    }
+
+    public void clear() {
+    }
+
+    public void sendMessages(long delay, long sleep) throws Exception {
+        Member local = channels[0].getLocalMember(true);
+        Member dest = channels[1].getLocalMember(true);
+        int n = 3;
+        System.out.println("Sending " + n + " messages from [" + local.getName() + "] to [" + dest.getName() + "]");
+        for (int i = 0; i < n; i++) {
+            channels[0].send(new Member[] {dest}, new TestMsg(), 0);
+            if ( delay > 0 ) Thread.sleep(delay);
+        }
+        System.out.println("Messages sent. Sleeping for "+(sleep/1000)+" seconds to inspect connections");
+        if ( sleep > 0 ) Thread.sleep(sleep);
+
+    }
+
+    public void testConnectionLinger() throws Exception {
+        sendMessages(0,15000);
+    }
+    
+    public void testKeepAliveCount() throws Exception {
+        System.out.println("Setting keep alive count to 0");
+        for (int i = 0; i < channels.length; i++) {
+            ReplicationTransmitter t = (ReplicationTransmitter)channels[0].getChannelSender();
+            t.getTransport().setKeepAliveCount(0);
+        }
+        sendMessages(1000,15000);
+    }
+
+    public void testKeepAliveTime() throws Exception {
+        System.out.println("Setting keep alive count to 1 second");
+        for (int i = 0; i < channels.length; i++) {
+            ReplicationTransmitter t = (ReplicationTransmitter)channels[0].getChannelSender();
+            t.getTransport().setKeepAliveTime(1000);
+        }
+        sendMessages(2000,15000);
+    }
+
+    protected void tearDown() throws Exception {
+        for (int i = 0; i < channels.length; i++) {
+            channels[i].stop(Channel.DEFAULT);
+        }
+
+    }
+    
+    public static class TestMsg implements Serializable {
+        static Random r = new Random(System.currentTimeMillis());
+        HashMap map = new HashMap();
+        public TestMsg() {
+            int size = Math.abs(r.nextInt() % 200);
+            for (int i=0; i<size; i++ ) {
+                int length = Math.abs(r.nextInt() %65000);
+                ArrayList list = new ArrayList(length);
+                map.put(new Integer(i),list);
+            }
+        }
+    }
+
+    public class TestMsgListener implements ChannelListener {
+        public String name = null;
+        public TestMsgListener(String name) {
+            this.name = name;
+        }
+        
+        public void messageReceived(Serializable msg, Member sender) {
+            System.out.println("["+name+"] Received message:"+msg+" from " + sender.getName());
+        }
+
+    
+        public boolean accept(Serializable msg, Member sender) {
+            return true;
+        }
+
+
+        
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/test/java/org/apache/catalina/tribes/test/io/TestSerialization.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/test/java/org/apache/catalina/tribes/test/io/TestSerialization.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/test/java/org/apache/catalina/tribes/test/io/TestSerialization.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,24 @@
+package org.apache.catalina.tribes.test.io;
+
+import org.apache.catalina.tribes.io.XByteBuffer;
+import junit.framework.TestCase;
+
+public class TestSerialization extends TestCase {
+    protected void setUp() throws Exception {
+        super.setUp();
+    }
+    
+    public void testEmptyArray() throws Exception {
+        
+    }
+
+    protected void tearDown() throws Exception {
+        super.tearDown();
+    }
+    
+    public static void main(String[] args) throws Exception {
+        //XByteBuffer.deserialize(new byte[0]);
+        XByteBuffer.deserialize(new byte[] {-84, -19, 0, 5, 115, 114, 0, 17, 106});
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/test/java/org/apache/catalina/tribes/test/membership/MemberSerialization.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/test/java/org/apache/catalina/tribes/test/membership/MemberSerialization.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/test/java/org/apache/catalina/tribes/test/membership/MemberSerialization.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,100 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ *
+ * Licensed 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
+ */
+package org.apache.catalina.tribes.test.membership;
+
+import junit.framework.TestCase;
+import org.apache.catalina.tribes.membership.MemberImpl;
+import java.util.Arrays;
+
+/**
+ * <p>Title: </p>
+ *
+ * <p>Description: </p>
+ *
+ * <p>Copyright: Copyright (c) 2005</p>
+ *
+ * <p>Company: </p>
+ *
+ * @author not attributable
+ * @version 1.0
+ */
+public class MemberSerialization extends TestCase {
+    MemberImpl m1, m2, p1,p2;
+    byte[] payload = null;
+    protected void setUp() throws Exception {
+        super.setUp();
+        payload = new byte[333];
+        Arrays.fill(payload,(byte)1);
+        m1 = new MemberImpl("localhost",3333,1,payload);
+        m2 = new MemberImpl("localhost",3333,1);
+        payload = new byte[333];
+        Arrays.fill(payload,(byte)2);
+        p1 = new MemberImpl("127.0.0.1",3333,1,payload);
+        p2 = new MemberImpl("localhost",3331,1,payload);
+        m1.setDomain(new byte[] {1,2,3,4,5,6,7,8,9});
+        m2.setDomain(new byte[] {1,2,3,4,5,6,7,8,9});
+        m1.setCommand(new byte[] {1,2,4,5,6,7,8,9});
+        m2.setCommand(new byte[] {1,2,4,5,6,7,8,9});
+    }
+    
+    public void testCompare() throws Exception {
+        assertTrue(m1.equals(m2));
+        assertTrue(m2.equals(m1));
+        assertTrue(p1.equals(m2));
+        assertFalse(m1.equals(p2));
+        assertFalse(m1.equals(p2));
+        assertFalse(m2.equals(p2));
+        assertFalse(p1.equals(p2));
+    }
+    
+    public void testSerializationOne() throws Exception {
+        MemberImpl m = m1;
+        byte[] md1 = m.getData(false,true);
+        byte[] mda1 = m.getData(false,false);
+        assertTrue(Arrays.equals(md1,mda1));
+        assertTrue(md1==mda1);
+        mda1 = m.getData(true,true);
+        MemberImpl ma1 = MemberImpl.getMember(mda1);
+        assertTrue(compareMembers(m,ma1));
+        mda1 = p1.getData(false);
+        assertFalse(Arrays.equals(md1,mda1));
+        ma1 = MemberImpl.getMember(mda1);
+        assertTrue(compareMembers(p1,ma1));
+        
+        md1 = m.getData(true,true);
+        Thread.sleep(5);
+        mda1 = m.getData(true,true);
+        MemberImpl a1 = MemberImpl.getMember(md1);
+        MemberImpl a2 = MemberImpl.getMember(mda1);
+        assertTrue(a1.equals(a2));
+        assertFalse(Arrays.equals(md1,mda1));
+        
+        
+    }
+    
+    public boolean compareMembers(MemberImpl impl1, MemberImpl impl2) {
+        boolean result = true;
+        result = result && Arrays.equals(impl1.getHost(),impl2.getHost());
+        result = result && Arrays.equals(impl1.getPayload(),impl2.getPayload());
+        result = result && Arrays.equals(impl1.getUniqueId(),impl2.getUniqueId());
+        result = result && impl1.getPort() == impl2.getPort();
+        return result;
+    }
+
+    protected void tearDown() throws Exception {
+        super.tearDown();
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/test/java/org/apache/catalina/tribes/test/membership/TestDomainFilter.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/test/java/org/apache/catalina/tribes/test/membership/TestDomainFilter.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/test/java/org/apache/catalina/tribes/test/membership/TestDomainFilter.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,104 @@
+package org.apache.catalina.tribes.test.membership;
+
+import java.util.ArrayList;
+
+import org.apache.catalina.tribes.Channel;
+import org.apache.catalina.tribes.ManagedChannel;
+import org.apache.catalina.tribes.Member;
+import org.apache.catalina.tribes.MembershipListener;
+import org.apache.catalina.tribes.group.GroupChannel;
+import junit.framework.TestCase;
+import org.apache.catalina.tribes.group.interceptors.DomainFilterInterceptor;
+import org.apache.catalina.tribes.util.UUIDGenerator;
+
+public class TestDomainFilter
+    extends TestCase {
+    private static int count = 10;
+    private ManagedChannel[] channels = new ManagedChannel[count];
+    private TestMbrListener[] listeners = new TestMbrListener[count];
+
+    protected void setUp() throws Exception {
+        super.setUp();
+        for (int i = 0; i < channels.length; i++) {
+            channels[i] = new GroupChannel();
+            channels[i].getMembershipService().setPayload( ("Channel-" + (i + 1)).getBytes("ASCII"));
+            listeners[i] = new TestMbrListener( ("Listener-" + (i + 1)));
+            channels[i].addMembershipListener(listeners[i]);
+            DomainFilterInterceptor filter = new DomainFilterInterceptor();
+            filter.setDomain(UUIDGenerator.randomUUID(false));
+            channels[i].addInterceptor(filter);
+        }
+    }
+
+    public void clear() {
+        for (int i = 0; i < channels.length; i++) {
+            listeners[i].members.clear();
+        }
+    }
+
+    public void testMemberArrival() throws Exception {
+        //purpose of this test is to make sure that we have received all the members
+        //that we can expect before the start method returns
+        Thread[] threads = new Thread[channels.length];
+        for (int i=0; i<channels.length; i++ ) {
+            final Channel channel = channels[i];
+            Thread t = new Thread() {
+                public void run() {
+                    try {
+                        channel.start(Channel.DEFAULT);
+                    }catch ( Exception x ) {
+                        throw new RuntimeException(x);
+                    }
+                }
+            };
+            threads[i] = t;
+        }
+        for (int i=0; i<threads.length; i++ ) threads[i].start();
+        for (int i=0; i<threads.length; i++ ) threads[i].join();
+        System.out.println("All channels started.");
+        for (int i=listeners.length-1; i>=0; i-- ) assertEquals("Checking member arrival length",0,listeners[i].members.size());
+    }
+
+    protected void tearDown() throws Exception {
+
+        for (int i = 0; i < channels.length; i++) {
+            try {
+                channels[i].stop(Channel.DEFAULT);
+            } catch (Exception ignore) {}
+        }
+        super.tearDown();
+    }
+
+    public class TestMbrListener
+        implements MembershipListener {
+        public String name = null;
+        public TestMbrListener(String name) {
+            this.name = name;
+        }
+
+        public ArrayList members = new ArrayList();
+        public void memberAdded(Member member) {
+            if (!members.contains(member)) {
+                members.add(member);
+                try {
+                    System.out.println(name + ":member added[" + new String(member.getPayload(), "ASCII") + "; Thread:"+Thread.currentThread().getName()+"]");
+                } catch (Exception x) {
+                    System.out.println(name + ":member added[unknown]");
+                }
+            }
+        }
+
+        public void memberDisappeared(Member member) {
+            if (members.contains(member)) {
+                members.remove(member);
+                try {
+                    System.out.println(name + ":member disappeared[" + new String(member.getPayload(), "ASCII") + "; Thread:"+Thread.currentThread().getName()+"]");
+                } catch (Exception x) {
+                    System.out.println(name + ":member disappeared[unknown]");
+                }
+            }
+        }
+
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/test/java/org/apache/catalina/tribes/test/membership/TestMemberArrival.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/test/java/org/apache/catalina/tribes/test/membership/TestMemberArrival.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/test/java/org/apache/catalina/tribes/test/membership/TestMemberArrival.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,100 @@
+package org.apache.catalina.tribes.test.membership;
+
+import java.util.ArrayList;
+
+import org.apache.catalina.tribes.Channel;
+import org.apache.catalina.tribes.ManagedChannel;
+import org.apache.catalina.tribes.Member;
+import org.apache.catalina.tribes.MembershipListener;
+import org.apache.catalina.tribes.group.GroupChannel;
+import junit.framework.TestCase;
+
+public class TestMemberArrival
+    extends TestCase {
+    private static int count = 10;
+    private ManagedChannel[] channels = new ManagedChannel[count];
+    private TestMbrListener[] listeners = new TestMbrListener[count];
+
+    protected void setUp() throws Exception {
+        super.setUp();
+        for (int i = 0; i < channels.length; i++) {
+            channels[i] = new GroupChannel();
+            channels[i].getMembershipService().setPayload( ("Channel-" + (i + 1)).getBytes("ASCII"));
+            listeners[i] = new TestMbrListener( ("Listener-" + (i + 1)));
+            channels[i].addMembershipListener(listeners[i]);
+
+        }
+    }
+
+    public void clear() {
+        for (int i = 0; i < channels.length; i++) {
+            listeners[i].members.clear();
+        }
+    }
+
+    public void testMemberArrival() throws Exception {
+        //purpose of this test is to make sure that we have received all the members
+        //that we can expect before the start method returns
+        Thread[] threads = new Thread[channels.length];
+        for (int i=0; i<channels.length; i++ ) {
+            final Channel channel = channels[i];
+            Thread t = new Thread() {
+                public void run() {
+                    try {
+                        channel.start(Channel.DEFAULT);
+                    }catch ( Exception x ) {
+                        throw new RuntimeException(x);
+                    }
+                }
+            };
+            threads[i] = t;
+        }
+        for (int i=0; i<threads.length; i++ ) threads[i].start();
+        for (int i=0; i<threads.length; i++ ) threads[i].join();
+        System.out.println("All channels started.");
+        for (int i=listeners.length-1; i>=0; i-- ) assertEquals("Checking member arrival length",channels.length-1,listeners[i].members.size());
+    }
+
+    protected void tearDown() throws Exception {
+
+        for (int i = 0; i < channels.length; i++) {
+            try {
+                channels[i].stop(Channel.DEFAULT);
+            } catch (Exception ignore) {}
+        }
+        super.tearDown();
+    }
+
+    public class TestMbrListener
+        implements MembershipListener {
+        public String name = null;
+        public TestMbrListener(String name) {
+            this.name = name;
+        }
+
+        public ArrayList members = new ArrayList();
+        public void memberAdded(Member member) {
+            if (!members.contains(member)) {
+                members.add(member);
+                try {
+                    System.out.println(name + ":member added[" + new String(member.getPayload(), "ASCII") + "; Thread:"+Thread.currentThread().getName()+"]");
+                } catch (Exception x) {
+                    System.out.println(name + ":member added[unknown]");
+                }
+            }
+        }
+
+        public void memberDisappeared(Member member) {
+            if (members.contains(member)) {
+                members.remove(member);
+                try {
+                    System.out.println(name + ":member disappeared[" + new String(member.getPayload(), "ASCII") + "; Thread:"+Thread.currentThread().getName()+"]");
+                } catch (Exception x) {
+                    System.out.println(name + ":member disappeared[unknown]");
+                }
+            }
+        }
+
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/test/java/org/apache/catalina/tribes/test/membership/TestTcpFailureDetector.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/test/java/org/apache/catalina/tribes/test/membership/TestTcpFailureDetector.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/test/java/org/apache/catalina/tribes/test/membership/TestTcpFailureDetector.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,151 @@
+package org.apache.catalina.tribes.test.membership;
+
+import java.util.ArrayList;
+
+import org.apache.catalina.tribes.ByteMessage;
+import org.apache.catalina.tribes.Channel;
+import org.apache.catalina.tribes.ChannelException;
+import org.apache.catalina.tribes.ManagedChannel;
+import org.apache.catalina.tribes.Member;
+import org.apache.catalina.tribes.MembershipListener;
+import org.apache.catalina.tribes.group.GroupChannel;
+import org.apache.catalina.tribes.group.interceptors.TcpFailureDetector;
+import junit.framework.TestCase;
+
+/**
+ * <p>Title: </p> 
+ * 
+ * <p>Description: </p> 
+ * 
+ * <p>Copyright: Copyright (c) 2005</p> 
+ * 
+ * <p>Company: </p>
+ * 
+ * @author not attributable
+ * @version 1.0
+ */
+public class TestTcpFailureDetector extends TestCase {
+    private TcpFailureDetector tcpFailureDetector1 = null;
+    private TcpFailureDetector tcpFailureDetector2 = null;
+    private ManagedChannel channel1 = null;
+    private ManagedChannel channel2 = null;
+    private TestMbrListener mbrlist1 = null;
+    private TestMbrListener mbrlist2 = null;
+    protected void setUp() throws Exception {
+        super.setUp();
+        channel1 = new GroupChannel();
+        channel2 = new GroupChannel();
+        channel1.getMembershipService().setPayload("Channel-1".getBytes("ASCII"));
+        channel2.getMembershipService().setPayload("Channel-2".getBytes("ASCII"));
+        mbrlist1 = new TestMbrListener("Channel-1");
+        mbrlist2 = new TestMbrListener("Channel-2");
+        tcpFailureDetector1 = new TcpFailureDetector();
+        tcpFailureDetector2 = new TcpFailureDetector();
+        channel1.addInterceptor(tcpFailureDetector1);
+        channel2.addInterceptor(tcpFailureDetector2);
+        channel1.addMembershipListener(mbrlist1);
+        channel2.addMembershipListener(mbrlist2);
+    }
+    
+    public void clear() {
+        mbrlist1.members.clear();
+        mbrlist2.members.clear();
+    }
+    
+    public void testTcpSendFailureMemberDrop() throws Exception {
+        System.out.println("testTcpSendFailureMemberDrop()");
+        clear();
+        channel1.start(channel1.DEFAULT);
+        channel2.start(channel2.DEFAULT);
+        //Thread.sleep(1000);
+        assertEquals("Expecting member count to be equal",mbrlist1.members.size(),mbrlist2.members.size());
+        channel2.stop(channel2.SND_RX_SEQ);
+        ByteMessage msg = new ByteMessage(new byte[1024]);
+        try {
+            channel1.send(channel1.getMembers(), msg, 0);
+            assertEquals("Message send should have failed.",true,false);
+        } catch ( ChannelException x ) {
+            
+        }
+        assertEquals("Expecting member count to not be equal",mbrlist1.members.size()+1,mbrlist2.members.size());
+        channel1.stop(Channel.DEFAULT);
+        channel2.stop(Channel.DEFAULT);
+    }
+    
+    public void testTcpFailureMemberAdd() throws Exception {
+        System.out.println("testTcpFailureMemberAdd()");
+        clear();
+        channel1.start(channel1.DEFAULT);
+        channel2.start(channel2.SND_RX_SEQ);
+        channel2.start(channel2.SND_TX_SEQ);
+        channel2.start(channel2.MBR_RX_SEQ);
+        channel2.stop(channel2.SND_RX_SEQ);
+        channel2.start(channel2.MBR_TX_SEQ);
+        //Thread.sleep(1000);
+        assertEquals("Expecting member count to not be equal",mbrlist1.members.size()+1,mbrlist2.members.size());
+        channel1.stop(Channel.DEFAULT);
+        channel2.stop(Channel.DEFAULT);
+    }
+
+    public void testTcpMcastFail() throws Exception {
+        System.out.println("testTcpMcastFail()");
+        clear();
+        channel1.start(channel1.DEFAULT);
+        channel2.start(channel2.DEFAULT);
+        //Thread.sleep(1000);
+        assertEquals("Expecting member count to be equal",mbrlist1.members.size(),mbrlist2.members.size());
+        channel2.stop(channel2.MBR_TX_SEQ);
+        ByteMessage msg = new ByteMessage(new byte[1024]);
+        try {
+            Thread.sleep(5000);
+            assertEquals("Expecting member count to be equal",mbrlist1.members.size(),mbrlist2.members.size());
+            channel1.send(channel1.getMembers(), msg, 0);
+        } catch ( ChannelException x ) {
+            assertEquals("Message send should have succeeded.",true,false);
+        }
+        channel1.stop(Channel.DEFAULT);
+        channel2.stop(Channel.DEFAULT);
+    }
+
+
+    protected void tearDown() throws Exception {
+        tcpFailureDetector1 = null;
+        tcpFailureDetector2 = null;
+        try { channel1.stop(Channel.DEFAULT);}catch (Exception ignore){}
+        channel1 = null;
+        try { channel2.stop(Channel.DEFAULT);}catch (Exception ignore){}
+        channel2 = null;
+        super.tearDown();
+    }
+    
+    public class TestMbrListener implements MembershipListener {
+        public String name = null;
+        public TestMbrListener(String name) {
+            this.name = name;
+        }
+        public ArrayList members = new ArrayList();
+        public void memberAdded(Member member) {
+            if ( !members.contains(member) ) {
+                members.add(member);
+                try{
+                    System.out.println(name + ":member added[" + new String(member.getPayload(), "ASCII") + "]");
+                }catch ( Exception x ) {
+                    System.out.println(name + ":member added[unknown]");
+                }
+            }
+        }
+        
+        public void memberDisappeared(Member member) {
+            if ( members.contains(member) ) {
+                members.remove(member);
+                try{
+                    System.out.println(name + ":member disappeared[" + new String(member.getPayload(), "ASCII") + "]");
+                }catch ( Exception x ) {
+                    System.out.println(name + ":member disappeared[unknown]");
+                }
+            }
+        }
+        
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/test/java/org/apache/catalina/tribes/test/transport/SocketNioReceive.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/test/java/org/apache/catalina/tribes/test/transport/SocketNioReceive.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/test/java/org/apache/catalina/tribes/test/transport/SocketNioReceive.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,76 @@
+package org.apache.catalina.tribes.test.transport;
+
+import java.text.DecimalFormat;
+
+import org.apache.catalina.tribes.ChannelMessage;
+import org.apache.catalina.tribes.Member;
+import org.apache.catalina.tribes.MessageListener;
+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.transport.nio.NioReceiver;
+
+public class SocketNioReceive {
+    static int count = 0;
+    static int accept = 0;
+    static long start = 0;
+    static double mb = 0;
+    static int len = 0;
+    static DecimalFormat df = new DecimalFormat("##.00");
+    static double seconds = 0;
+
+    protected static Object mutex = new Object();
+    public static void main(String[] args) throws Exception {
+        Member mbr = new MemberImpl("localhost", 9999, 0);
+        ChannelData data = new ChannelData();
+        data.setAddress(mbr);
+        byte[] buf = new byte[8192 * 4];
+        data.setMessage(new XByteBuffer(buf, false));
+        buf = XByteBuffer.createDataPackage(data);
+        len = buf.length;
+        NioReceiver receiver = new NioReceiver();
+        receiver.setPort(9999);
+        receiver.setHost("localhost");
+        MyList list = new MyList();
+        receiver.setMessageListener(list);
+        receiver.start();
+        System.out.println("Listening on 9999");
+        while (true) {
+            try {
+                synchronized (mutex) {
+                    mutex.wait(5000);
+                    if ( start != 0 ) {
+                        System.out.println("Throughput " + df.format(mb / seconds) + " MB/seconds, messages "+count+" accepts "+accept+", total "+mb+" MB.");
+                    }
+                }
+            }catch (Throwable x) {
+                x.printStackTrace();
+            }
+        }
+    }
+    
+    public static class MyList implements MessageListener {
+        boolean first = true;
+        
+        
+        public void messageReceived(ChannelMessage msg) {
+            if (first) {
+                first = false;
+                start = System.currentTimeMillis();
+            }
+            mb += ( (double) len) / 1024 / 1024;
+            synchronized (this) {count++;}
+            if ( ( (count) % 10000) == 0) {
+                long time = System.currentTimeMillis();
+                seconds = ( (double) (time - start)) / 1000;
+                System.out.println("Throughput " + df.format(mb / seconds) + " MB/seconds, messages "+count+", total "+mb+" MB.");
+            }
+        }        
+
+        public boolean accept(ChannelMessage msg) {
+            synchronized (this) {accept++;}
+            return true;
+        }
+
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/test/java/org/apache/catalina/tribes/test/transport/SocketNioSend.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/test/java/org/apache/catalina/tribes/test/transport/SocketNioSend.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/test/java/org/apache/catalina/tribes/test/transport/SocketNioSend.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,91 @@
+package org.apache.catalina.tribes.test.transport;
+
+import java.io.OutputStream;
+import java.net.Socket;
+import java.text.DecimalFormat;
+import org.apache.catalina.tribes.transport.nio.NioSender;
+import org.apache.catalina.tribes.membership.MemberImpl;
+import java.nio.channels.Selector;
+import org.apache.catalina.tribes.io.XByteBuffer;
+import org.apache.catalina.tribes.Member;
+import java.nio.channels.SelectionKey;
+import java.util.Iterator;
+import org.apache.catalina.tribes.Channel;
+import org.apache.catalina.tribes.io.ChannelData;
+import java.math.BigDecimal;
+
+public class SocketNioSend {
+
+    public static void main(String[] args) throws Exception {
+        Selector selector = Selector.open();
+        Member mbr = new MemberImpl("localhost", 9999, 0);
+        ChannelData data = new ChannelData();
+        data.setOptions(Channel.SEND_OPTIONS_BYTE_MESSAGE);
+        data.setAddress(mbr);
+        byte[] buf = new byte[8192 * 4];
+        data.setMessage(new XByteBuffer(buf,false));
+        buf = XByteBuffer.createDataPackage(data);
+        int len = buf.length;
+        BigDecimal total = new BigDecimal((double)0);
+        BigDecimal bytes = new BigDecimal((double)len);
+        NioSender sender = new NioSender();
+        sender.setDestination(mbr);
+        sender.setDirectBuffer(true);
+        sender.setSelector(selector);
+        sender.setTxBufSize(1024*1024);
+        sender.connect();
+        sender.setMessage(buf);
+        System.out.println("Writing to 9999");
+        long start = 0;
+        double mb = 0;
+        boolean first = true;
+        int count = 0;
+        DecimalFormat df = new DecimalFormat("##.00");
+        while (count<100000) {
+            if (first) {
+                first = false;
+                start = System.currentTimeMillis();
+            }
+            sender.setMessage(buf);
+            int selectedKeys = 0;
+            try {
+                selectedKeys = selector.select(0);
+            } catch (Exception e) {
+                e.printStackTrace();
+                continue;
+            }
+
+            if (selectedKeys == 0) {
+                continue;
+            }
+
+            Iterator it = selector.selectedKeys().iterator();
+            while (it.hasNext()) {
+                SelectionKey sk = (SelectionKey) it.next();
+                it.remove();
+                try {
+                    int readyOps = sk.readyOps();
+                    sk.interestOps(sk.interestOps() & ~readyOps);
+                    if (sender.process(sk, false)) {
+                        total = total.add(bytes);
+                        sender.reset();
+                        sender.setMessage(buf);
+                        mb += ( (double) len) / 1024 / 1024;
+                        if ( ( (++count) % 10000) == 0) {
+                            long time = System.currentTimeMillis();
+                            double seconds = ( (double) (time - start)) / 1000;
+                            System.out.println("Throughput " + df.format(mb / seconds) + " MB/seconds, total "+mb+" MB, total "+total+" bytes.");
+                        }
+                    }
+
+                } catch (Throwable t) {
+                    t.printStackTrace();
+                    return;
+                }
+            }
+            selector.selectedKeys().clear();
+        }
+        System.out.println("Complete, sleeping 15 seconds");
+        Thread.sleep(15000);
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/test/java/org/apache/catalina/tribes/test/transport/SocketNioValidateSend.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/test/java/org/apache/catalina/tribes/test/transport/SocketNioValidateSend.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/test/java/org/apache/catalina/tribes/test/transport/SocketNioValidateSend.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,90 @@
+package org.apache.catalina.tribes.test.transport;
+
+import java.io.OutputStream;
+import java.net.Socket;
+import java.text.DecimalFormat;
+import org.apache.catalina.tribes.transport.nio.NioSender;
+import org.apache.catalina.tribes.membership.MemberImpl;
+import java.nio.channels.Selector;
+import org.apache.catalina.tribes.io.XByteBuffer;
+import org.apache.catalina.tribes.Member;
+import java.nio.channels.SelectionKey;
+import java.util.Iterator;
+import org.apache.catalina.tribes.Channel;
+import org.apache.catalina.tribes.io.ChannelData;
+import java.math.BigDecimal;
+import java.util.Arrays;
+
+public class SocketNioValidateSend {
+
+    public static void main(String[] args) throws Exception {
+        Selector selector = Selector.open();
+        Member mbr = new MemberImpl("localhost", 9999, 0);
+        byte seq = 0;
+        byte[] buf = new byte[50000];
+        Arrays.fill(buf,seq);
+        int len = buf.length;
+        BigDecimal total = new BigDecimal((double)0);
+        BigDecimal bytes = new BigDecimal((double)len);
+        NioSender sender = new NioSender();
+        sender.setDestination(mbr);
+        sender.setDirectBuffer(true);
+        sender.setSelector(selector);
+        sender.connect();
+        sender.setMessage(buf);
+        System.out.println("Writing to 9999");
+        long start = 0;
+        double mb = 0;
+        boolean first = true;
+        int count = 0;
+        
+        DecimalFormat df = new DecimalFormat("##.00");
+        while (count<100000) {
+            if (first) {
+                first = false;
+                start = System.currentTimeMillis();
+            }
+            sender.setMessage(buf);
+            int selectedKeys = 0;
+            try {
+                selectedKeys = selector.select(0);
+            } catch (Exception e) {
+                e.printStackTrace();
+                continue;
+            }
+
+            if (selectedKeys == 0) {
+                continue;
+            }
+
+            Iterator it = selector.selectedKeys().iterator();
+            while (it.hasNext()) {
+                SelectionKey sk = (SelectionKey) it.next();
+                it.remove();
+                try {
+                    int readyOps = sk.readyOps();
+                    sk.interestOps(sk.interestOps() & ~readyOps);
+                    if (sender.process(sk, false)) {
+                        total = total.add(bytes);
+                        sender.reset();
+                        seq++;
+                        Arrays.fill(buf,seq);
+                        sender.setMessage(buf);
+                        mb += ( (double) len) / 1024 / 1024;
+                        if ( ( (++count) % 10000) == 0) {
+                            long time = System.currentTimeMillis();
+                            double seconds = ( (double) (time - start)) / 1000;
+                            System.out.println("Throughput " + df.format(mb / seconds) + " MB/seconds, total "+mb+" MB, total "+total+" bytes.");
+                        }
+                    }
+
+                } catch (Throwable t) {
+                    t.printStackTrace();
+                    return;
+                }
+            }
+        }
+        System.out.println("Complete, sleeping 15 seconds");
+        Thread.sleep(15000);
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/test/java/org/apache/catalina/tribes/test/transport/SocketReceive.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/test/java/org/apache/catalina/tribes/test/transport/SocketReceive.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/test/java/org/apache/catalina/tribes/test/transport/SocketReceive.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,62 @@
+package org.apache.catalina.tribes.test.transport;
+
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.io.InputStream;
+import java.text.DecimalFormat;
+import java.math.BigDecimal;
+
+public class SocketReceive {
+    static long start = 0;
+    static double mb = 0;
+    static byte[] buf = new byte[8192 * 4];
+    static boolean first = true;
+    static int count = 0;
+    static DecimalFormat df = new DecimalFormat("##.00");
+    static BigDecimal total = new BigDecimal(0);
+    static BigDecimal bytes = new BigDecimal(32871);
+
+    
+    public static void main(String[] args) throws Exception {
+    
+        ServerSocket srvSocket = new ServerSocket(9999);
+        System.out.println("Listening on 9999");
+        Socket socket = srvSocket.accept();
+        socket.setReceiveBufferSize(43800);
+        InputStream in = socket.getInputStream();
+        Thread t = new Thread() {
+            public void run() {
+                while ( true ) {
+                    try {
+                        Thread.sleep(1000);
+                        printStats(start, mb, count, df, total);
+                    }catch ( Exception x ) {}
+                }
+            }
+        };
+        t.setDaemon(true);
+        t.start();
+
+        while ( true ) {
+            if ( first ) { first = false; start = System.currentTimeMillis();}
+            int len = in.read(buf);
+            if ( len == -1 ) {
+                printStats(start, mb, count, df, total);
+                System.exit(1);
+            }
+            if ( bytes.intValue() != len ) bytes = new BigDecimal((double)len);
+            total = total.add(bytes);
+            mb += ( (double) len) / 1024 / 1024;
+            if ( ((++count) % 10000) == 0 ) {
+                printStats(start, mb, count, df, total);
+            }
+        }
+        
+    }
+
+    private static void printStats(long start, double mb, int count, DecimalFormat df, BigDecimal total) {
+        long time = System.currentTimeMillis();
+        double seconds = ((double)(time-start))/1000;
+        System.out.println("Throughput "+df.format(mb/seconds)+" MB/seconds messages "+count+", total "+mb+" MB, total "+total+" bytes.");
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/test/java/org/apache/catalina/tribes/test/transport/SocketSend.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/test/java/org/apache/catalina/tribes/test/transport/SocketSend.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/test/java/org/apache/catalina/tribes/test/transport/SocketSend.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,53 @@
+package org.apache.catalina.tribes.test.transport;
+
+import java.io.OutputStream;
+import java.net.Socket;
+import java.text.DecimalFormat;
+import org.apache.catalina.tribes.membership.MemberImpl;
+import org.apache.catalina.tribes.io.XByteBuffer;
+import org.apache.catalina.tribes.Member;
+import org.apache.catalina.tribes.io.ChannelData;
+import org.apache.catalina.tribes.Channel;
+import java.math.BigDecimal;
+
+public class SocketSend {
+
+    public static void main(String[] args) throws Exception {
+        
+        
+        Member mbr = new MemberImpl("localhost", 9999, 0);
+        ChannelData data = new ChannelData();
+        data.setOptions(Channel.SEND_OPTIONS_BYTE_MESSAGE);
+        data.setAddress(mbr);
+        byte[] buf = new byte[8192 * 4];
+        data.setMessage(new XByteBuffer(buf,false));
+        buf = XByteBuffer.createDataPackage(data);
+        int len = buf.length;
+        System.out.println("Message size:"+len+" bytes");
+        BigDecimal total = new BigDecimal((double)0);
+        BigDecimal bytes = new BigDecimal((double)len);
+        Socket socket = new Socket("localhost",9999);
+        System.out.println("Writing to 9999");
+        OutputStream out = socket.getOutputStream();
+        long start = 0;
+        double mb = 0;
+        boolean first = true;
+        int count = 0;
+        DecimalFormat df = new DecimalFormat("##.00");
+        while ( count<100000 ) {
+            if ( first ) { first = false; start = System.currentTimeMillis();}
+            out.write(buf,0,buf.length);
+            mb += ( (double) buf.length) / 1024 / 1024;
+            total = total.add(bytes);
+            if ( ((++count) % 10000) == 0 ) {
+                long time = System.currentTimeMillis();
+                double seconds = ((double)(time-start))/1000;
+                System.out.println("Throughput "+df.format(mb/seconds)+" MB/seconds messages "+count+", total "+mb+" MB, total "+total+" bytes.");
+            }
+        }
+        out.flush(); 
+        System.out.println("Complete, sleeping 5 seconds");
+        Thread.sleep(5000);
+
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/test/java/org/apache/catalina/tribes/test/transport/SocketTribesReceive.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/test/java/org/apache/catalina/tribes/test/transport/SocketTribesReceive.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/test/java/org/apache/catalina/tribes/test/transport/SocketTribesReceive.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,71 @@
+package org.apache.catalina.tribes.test.transport;
+
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.io.InputStream;
+import java.text.DecimalFormat;
+import java.math.BigDecimal;
+import org.apache.catalina.tribes.io.XByteBuffer;
+
+public class SocketTribesReceive {
+    static long start = 0;
+    static double mb = 0;
+    //static byte[] buf = new byte[32871];
+    static byte[] buf = new byte[32871];
+    static boolean first = true;
+    static int count = 0;
+    static DecimalFormat df = new DecimalFormat("##.00");
+    static BigDecimal total = new BigDecimal((double)0);
+    static BigDecimal bytes = new BigDecimal((double)32871);
+
+    
+    public static void main(String[] args) throws Exception {
+        int size = 43800;
+        if (args.length > 0 ) try {size=Integer.parseInt(args[0]);}catch(Exception x){}
+        XByteBuffer xbuf = new XByteBuffer(43800,true);
+        ServerSocket srvSocket = new ServerSocket(9999);
+        System.out.println("Listening on 9999");
+        Socket socket = srvSocket.accept();
+        socket.setReceiveBufferSize(size);
+        InputStream in = socket.getInputStream();
+        Thread t = new Thread() {
+            public void run() {
+                while ( true ) {
+                    try {
+                        Thread.sleep(1000);
+                        printStats(start, mb, count, df, total);
+                    }catch ( Exception x ) {}
+                }
+            }
+        };
+        t.setDaemon(true);
+        t.start();
+
+        while ( true ) {
+            if ( first ) { first = false; start = System.currentTimeMillis();}
+            int len = in.read(buf);
+            if ( len == -1 ) {
+                printStats(start, mb, count, df, total);
+                System.exit(1);
+            }
+            xbuf.append(buf,0,len);
+            if ( bytes.intValue() != len ) bytes = new BigDecimal((double)len);
+            total = total.add(bytes);
+            while ( xbuf.countPackages(true) > 0 ) {
+                xbuf.extractPackage(true);
+                count++;
+            }
+            mb += ( (double) len) / 1024 / 1024;
+            if ( ((count) % 10000) == 0 ) {
+                printStats(start, mb, count, df, total);
+            }
+        }
+        
+    }
+
+    private static void printStats(long start, double mb, int count, DecimalFormat df, BigDecimal total) {
+        long time = System.currentTimeMillis();
+        double seconds = ((double)(time-start))/1000;
+        System.out.println("Throughput "+df.format(mb/seconds)+" MB/seconds messages "+count+", total "+mb+" MB, total "+total+" bytes.");
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/test/java/org/apache/catalina/tribes/test/transport/SocketValidateReceive.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/test/java/org/apache/catalina/tribes/test/transport/SocketValidateReceive.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/test/java/org/apache/catalina/tribes/test/transport/SocketValidateReceive.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,91 @@
+package org.apache.catalina.tribes.test.transport;
+
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.io.InputStream;
+import java.text.DecimalFormat;
+import java.math.BigDecimal;
+
+public class SocketValidateReceive {
+    static long start = 0;
+    static double mb = 0;
+    static byte[] buf = new byte[8192 * 4];
+    static boolean first = true;
+    static int count = 0;
+    static DecimalFormat df = new DecimalFormat("##.00");
+    static BigDecimal total = new BigDecimal(0);
+    static BigDecimal bytes = new BigDecimal(32871);
+
+    
+    public static void main(String[] args) throws Exception {
+        int size = 43800;
+        if (args.length > 0 ) try {size=Integer.parseInt(args[0]);}catch(Exception x){}
+   
+        ServerSocket srvSocket = new ServerSocket(9999);
+        System.out.println("Listening on 9999");
+        Socket socket = srvSocket.accept();
+        socket.setReceiveBufferSize(size);
+        InputStream in = socket.getInputStream();
+        MyDataReader reader = new MyDataReader(50000);
+        Thread t = new Thread() {
+            public void run() {
+                while ( true ) {
+                    try {
+                        Thread.sleep(1000);
+                        printStats(start, mb, count, df, total);
+                    }catch ( Exception x ) {}
+                }
+            }
+        };
+        t.setDaemon(true);
+        t.start();
+
+        while ( true ) {
+            if ( first ) { first = false; start = System.currentTimeMillis();}
+            int len = in.read(buf);
+            if ( len == -1 ) {
+                printStats(start, mb, count, df, total);
+                System.exit(1);
+            }
+            count += reader.append(buf,0,len);
+            
+            if ( bytes.intValue() != len ) bytes = new BigDecimal((double)len);
+            total = total.add(bytes);
+            mb += ( (double) len) / 1024 / 1024;
+            if ( ((count) % 10000) == 0 ) {
+                printStats(start, mb, count, df, total);
+            }
+        }
+        
+    }
+
+    private static void printStats(long start, double mb, int count, DecimalFormat df, BigDecimal total) {
+        long time = System.currentTimeMillis();
+        double seconds = ((double)(time-start))/1000;
+        System.out.println("Throughput "+df.format(mb/seconds)+" MB/seconds messages "+count+", total "+mb+" MB, total "+total+" bytes.");
+    }
+    
+    public static class MyDataReader {
+        byte[] data = new byte[43800];
+        int length = 10;
+        int cur = 0;
+        byte seq = 0;
+        public MyDataReader(int len) {
+            length = len;
+        }
+        
+        public int append(byte[] b, int off, int len) throws Exception {
+            int packages = 0;
+            for ( int i=off; i<len; i++ ) { 
+                if ( cur == length ) {
+                    cur = 0;
+                    seq++;
+                    packages++;
+                }
+                if ( b[i] != seq ) throw new Exception("mismatch on seq:"+seq+" and byte nr:"+cur+" count:"+count+" packages:"+packages);
+                cur++;
+            }
+            return packages;
+        }
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/test-cases.txt
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/test-cases.txt	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/test-cases.txt	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,31 @@
+Categories
+  -- Membership
+  -- Sending data
+  -- Receiving data
+  
+
+Membership Testcase
+
+I. Membership 
+   - all data transferred
+   - discovery
+   - startup listen only
+   - startup broadcast only
+   - timeouts
+   - member leaves
+   - test failure detector, stop broadcasting, but everything else stays alive
+
+II. Message accuracy
+
+III. Message throughput
+
+IV. Tipis
+   - ReplicatedMap - state transfer
+   - Add element
+   - Remove element
+   - Change element
+   
+V. Channel
+   - Start/stop levels
+   - bogus flags in start/stop
+   

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/to-do.txt
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/to-do.txt	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/groupcom/to-do.txt	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,317 @@
+To Do:
+===========================================
+
+Documentation:
+===========================================
+ Why is tribes unique compared to JGroups/Appia and other group comm protocols
+
+ 1. Uses NIO and TCP for guaranteed delivery and the ability to join large groups
+
+ 2. Guarantees messages the following way
+    a) TCP messaging, with a following READ for NIO to ensure non broken channel
+    b) ACK messages from the receiver
+    c) ACK after processing
+
+ 3. Same (single) channel can handle all types of guarantees (a,b,c) at the same time
+    and both process synchronous and asynchronous messaging.
+    This is key to support different requirements for messaging through
+    the same channel to save system resources.
+
+ 4. For async messaging, errors are reported through an error handler, callback
+
+ 5. Ability to send on multiple streams at the same time, in parallel, to improve performance
+
+ 6. Designed with replication in mind, that some pieces of data don't need to be totally ordered.
+
+ 7. Its not built with the uniform group model in mind, but it can be accomplished using interceptors.
+
+ 8. Future version will have WAN membership and replication
+
+ 9. Silent members, the ability to send messages to a node not in the membership
+
+10. Sender burst, concurrent messaging between two or more nodes
+
+11. Multicasting can still be done on a per message basis using a MulticastInterceptor
+
+Bugs:
+===========================================
+ a) Somehow the first NIO connection made, always closes down, why
+
+ b) pull the network cord and watch the membership layer freak out
+ 
+ c) AbstractReplicatedMap.size() throws ConcurrentModificationException,
+    implement a size counter instead
+
+Code Tasks:
+===========================================
+51. NioSender.setData should not expand the byte buffer if its too large
+    instead just refill it from the XByteBuffer
+
+50. On top of versioning, implement version syncs from primary to backup
+    Or when a backup receives an update that is out of sync
+
+49. Implement versioning on the AbstractReplicatedMap
+
+48. Periodic refresh of the replicated map (primary ->backup)
+
+47. Delta(session) versioning. increase version number each time, easier to keep maps in sync
+
+41. Build a tipi that is a soft membership
+
+38. Make the AbstractReplicatedMap accept non serializable elements, but just don't replicate them
+
+36. UDP Sender and Receiver, initially without flow control and guaranteed delivery.
+    This can be easily done as an interceptor, and operate in parallel with the TCP sender.
+    It can implement an auto detect, so that if the message is going to a destination in the same network
+    patch, then send it over UDP.
+
+35. The ability to share one channel amongst multiple processes
+
+32. Replicated JNDI entries in Tomcat in the format
+    cluster:<map name>/<entry key> for example
+    cluster:myapps/db/shared/dbinfo
+
+31. A layer on top of the GroupChannel, to allow multiple processes share
+    a channel to send/receive message to conserve system resources - this is way in the future.
+
+30. CookieBasedReplicationMap - a very simple extension to the LazyReplicatedMap
+    but instead of randomly selecting a backup node and then publishing the PROXY to all
+    the other nodes in the group, this will simply
+    read/write a cookie, for a backup location, so the nodes will
+    never know until the request comes in.
+    This is useful in extremely large clusters, and essentially reduces
+    very much of the network chatter, this task is dependent on task25
+    Question to be answered: How does the map know of the cookie?
+    Potential answer: Use a thread local and bind the request/response to it
+    Question: is there one cookie per map, or one cookie per server.
+    Potential answer: One cookie per app allows for heterogenous instances
+                      is there a limit on number of cookies
+                      per netscape and RFC 2109, section 6.3,, its 20
+                      http://wp.netscape.com/newsref/std/cookie_spec.html
+    To work around the cookie limit problem there would be a suggested setting
+    of storing the preferred backup order, or simply require homogeneous instances.
+
+29. Thread pool, shrink dynamically
+
+27. XmlConfigurator - read an XML file to configure the channel.
+
+26. JNDIChannel - a way to bind the group channel in a JNDI tree,
+    so that shared resources can access it.
+
+23. TotalOrderInterceptor - fairly straight forward implementation
+    This interceptor would depend on the fact that there is some sort of
+    membership coordinator, see task 9.
+    Once there is a coordinator in the group, the total order protocol is the same
+    as the OrderInterceptor, except that it gets its message number from
+    the coordinator, prior to sending it out.
+    The TotalOrderInterceptor, will keep a order number per member,
+    this way, ordering is kept intact when different messages are sent
+    two different members, ie
+    Message A - all members - total order (mbrA-2, mbrB-2, mbrC-2, mbrD-2)
+    Message B - mbrC,mbrD only - total order (mbrA-2, mbrB-2, mbrC-3, mbrD-3)
+    - The combination of Member uniqueId,orderId is unique, nothing else
+      this way, if a member crashes, we don't hold the queue, instead we start over.
+    - A TotalOrder token, will contain the coordinator uniqueId as well.
+    - One parameter should be "receive sequence timeout" incase the coordinator is not responding.
+    - OPTION A)
+      the coordinator doesn't forward the message
+      since the app will not receive the proper error message,
+      instead the sequencer just returns the sequence, then the member itself sends the message
+      pros: the app will find out if the send failed/succeeded
+      cons: if the send fails, the sequencer is out of sync for the failed member
+      OPTION B)
+      The coordinator, receives the message, adds on the sequence number
+      then sends the message on behalf of the requesting members
+      pros: sequencer is in charge of the sequence
+      cons: the sequence can become overloaded, since it has to do all the trafficing
+            the requesting member will not know if the message failed/succeeded
+      OPTION C) Research papers on total order, better algorithms exist.
+      NOTES! THIS CANT BE DONE USING A SEQUENCER THAT SENDS THE MESSAGE SINCE WE
+      LOSE THE ABILITY TO REPORT FEEDBACK
+
+21. Implement a WAN membership layer, using a WANMbrInterceptor and a
+    WAN Router/Forwarder (Tipi on top of a ManagedChannel)
+
+20. Implement a TCP membership interceptor, for guaranteed functionality, not just discovery
+
+18. Implement SSL encryption over message transfers, BIO and NIO
+
+8. WaitForCompletionInterceptor - waits for the message to get processed by all receivers before returning
+   (This is useful when synchronized=false and waitForAck=false, to improve
+   parallel processing, but you want to have all messages sent in parallel and
+   don't return until all have been processed on the remote end.)
+
+11. Code a ReplicatedFileSystem example, package org.apache.catalina.tipis
+
+13. StateTransfer interceptor
+    the ideas just come up in my head. the state transfer interceptor
+    will hold all incoming messages until it has received a message
+    with a STATE_TRANSFER header as the first of the bytes.
+    Once it has received state, it will pretty much take itself out of the loop
+    The benefit of the new ParallelNioSender is that it doesn't require to know about
+    a member to transfer state, all it has to do is to reply to a message that came in.
+    State is a one time deal for the entire channel, so a
+    session replication cluster, would transfer state as one block, not one per context
+
+14. Keepalive count and idle kill off for Nio senders
+
+17. Implement transactions - the ability to start a transaction, send several messages,
+                             and then commit the transaction
+
+Tasks Completed
+===========================================
+1. True synchronized/asynchronized replication enabled using flags
+Sender.sendAck/Receiver.waitForAck/Receiver.synchronized
+Task Desc: waitForAck - should only mean, we received the message, not for the
+message to get processesed. This should improve throughput, and an interceptor
+can do waitForCompletion
+Status: Complete
+Notes:
+
+2. Unique id, send it in byte array instead of string
+
+3. DataSender or ReplicationTransmitter swallows IOException, this should be
+Notes: This has only been fixed for the pooled synchronized. the fastasynch
+aint working that well
+
+4. ChannelMessage.getMessage should return streamable, that way we can wrap,
+pass it around and all those good things without having to copy byte arrays
+left and right
+Notes: Instead of using a streamable, this is implemented using the XByteBuffer,
+       which is very easy to use. It also becomes a single spot for optimizations.
+       Ideally, there would be a pool of XByteBuffers, that all use direct ByteBuffers
+       for its data handling.
+
+5. OrderInterceptor - guarantees the order of messages
+Notes: completed
+
+6. NIO and IO DataSender, since the IO is blocking
+Notes: completed. works very well, have not implemented suspect error logging.
+
+7. FragmentationInterceptor - splits up messages that are larger than X bytes.
+Notes: complated
+
+15. remove DataSenderFactory and DataSender.properties -
+    these cause the settings to be hard coded ant not pluggable.
+Notes: Completed, now you can initialize a transport class
+
+12. LazyReplicatedHashMap - memory efficient clustered map.
+    This map can be used for PRIMARY/SECONDARY session replication
+    Ahh, the beauty of storing data in remote locations
+    The lazy hash map will only replicate its attribute names to all members in the group
+    with that name, it will also replicate the source (where to get the object)
+    and the backup member where it can find a backup if the source is gone.
+    If the source disappears, the backup node will replicate attributes that
+    are stored to a new primary backups can be chosen on round robin.
+    When a new member arrives and requests state, that member will get all the attribute
+    names and the locations.
+    It can replicate every X seconds, or on dirty flags by the objects stored,
+    or a request to scan for dirty flags, or a request with the objects.
+Notes: the map has been completed
+
+22. sendAck and synchronized should not have to be a XML config,
+    it can be configured on a per packet basis using ClusterData.getOptions()
+Notes: see Channel.SEND_OPT_XXXX variables
+
+28. Thread pool should have maxThreads and minThreads and grow dynamically
+
+24. MessageDispatchInterceptor - for asynchronous sending
+    - looks at the options flag SEND_OPTIONS_ASYNCHRONOUS
+    - has two modes
+      a) async parallel send - each message to all destinations before next message
+      b) async per/member - one thread per member using the FastAsyncQueue (good for groups with slow receivers)
+    - Callback error handler - for when messages fail, and the application wishes to become notified
+    - MUST HAVE A LIMIT QUEUE SIZE IN MB, to avoid OOM errors or persist the queue.
+    - MUST USE ClusterData.deepclone() to ensure thread safety if ClusterData objects get recycled
+Notes: Simple implementation, one thread, invokes all senders in parallel.
+       Deep cloning is configurable as optimization.
+
+37. Interceptor.getOptionFlag() - lets the system configure a flag to be used
+    for the interceptor. that way, all constants don't have to be configured
+    in Channel.SEND_FLAG_XXXX.
+    Also, the GroupChannel will make a conflict check upon startup,
+    so that there is no conflict. I will change options to a long,
+    so that we can have 63 flags, hence up to 60 interceptors.
+Notes: Completed, remained an int, so 31 flags
+
+ b) State synchronization for the map - will need to add in MSG_INIT
+ Fixed map bug
+
+ c) RpcChannel - collect "no reply" replies, so that we don't have to time out
+The RpcChannel now works together with the group channel, so that when it receives an RPC message
+and no one accepts it, then it can reply immediately. this way the rpc sender doesn't have to time out.
+
+39. Support for IPv6
+Notes: Completed. The membership now carries a variable length host address to support IPv6
+
+40. channel.stop() - should broadcast a stop message, to avoid timeout
+Notes: Completed.
+
+42. When the option SEND_OPTIONS_SYNCHRONIZED_ACK, and an error happens during
+    processing on the remote node, a FAIL_ACK command should be sent
+    so that the sending node doesn't have to time out
+Notes: Completed. The error will be wrapped in a ChannelException and marked as a
+       RemoteProcessException for that node.
+       To receive this exception, one must turn on
+
+43. Silent member, node discovery.
+    Add in the ability to start up tribes, but don't start the membership broadcast
+    component, only the listener
+Notes: Completed. added in correct startup sequences.
+
+46. Heartbeat Interface, to notify listeners as well
+Notes: Implemented
+
+44. Soft membership failure detection, ie if a webapp is stopped, but
+    the AbstractReplicatedMap doesn't broadcast a stop message
+    This is one potential solution:
+    1. keep a static WeakHashMap of all map implementations running
+       so that we can share one heartbeat thread for timeouts
+    2. everytime a message is received, update the last check time for that
+       member so that we don't need the thread to actively check
+    3. when the thread wakes up, it will check maps that are outside
+       the valid range for check time,
+    4. send a RPC message, if no reply, remove the map from itself
+    Other solution, use the TcpFailureDetector, catch send errors
+Notes: Implemented using a periodic ping in the AbstractReplicatedMap
+
+45. McastServiceImpl.receive should have a SO_TIMEOUT so that we can check
+    for members dropping on the same thread
+Notes: Completed
+
+33. TcpFailureDetector, when a member is reported missing, first check TCP path too.
+Notes: Completed
+
+34. Configurable payload for the membership heartbeat, so that the app can decide what to heartbeat.
+    such as JMX management port, ala Andy Piper's suggestion.
+Notes: Completed
+
+49. Make sure that membership is established before the start process returns.
+Notes: Completed
+
+16. Guaranteed delivery of messages, ie either all get it or none get it.
+    Meaning, that all receivers get it, then wait for a process command.
+    ala Gossip protocol - this is fairly redundant with a Xa2PhaseCommitInterceptor
+    except it doesn't keep a transaction log.
+Notes: Completed in another task
+
+10. Xa2PhaseCommitInterceptor - make sure the message doesn't reach the receiver unless all members got it
+Notes: Completed
+
+25. Member.uniqueId - 16 bytes unique for a member, UUID
+    Needed to not confuse a crashed member with a revived member on the same port
+Notes: Completed
+
+19. Implement a hardcoded tcp membership
+Notes: Completed
+
+9. CoordinatorInterceptor - manages the selection of a cluster coordinator
+   just had a brilliant idea, if GroupChannel keeps its own view of members,
+   the coordinator interceptor can hold on to the member added/disappared event
+   It can also intercept down going messages if the coordinator disappeared
+   while a new coordinator is chosen
+   It can also intercept down going messages for members disappeared that the
+   calling app not yet knows about, to avoid a ChannelException
+   The coordinator is needed because of the mixup when two channels startup instantly
+Notes: Completed. org.apache.catalina.tribes.group.interceptors.NonBlockingCoordinatorInterceptor
+       implements an automerging algorithm.

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/ha/build.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/ha/build.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/ha/build.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,157 @@
+<project name="Cluster" default="dist" basedir=".">
+
+
+  <!-- ===================== Initialize Property Values =================== -->
+
+  <property file="../../../build.properties" />
+  <property file="../../../build/build.properties" />
+  <property file="../../../build/build.properties.default" />
+
+  <!-- Build Defaults -->
+  <property name="catalina.home"  location="../.."/>
+  <property name="catalina.build" location="../../../build/build"/>
+  <property name="ha.build"  value="${catalina.home}/modules/ha/build"/>
+  <property name="ha.dist"   value="${catalina.home}/modules/ha/dist"/>
+  
+  <property name="groupcom.dist"   value="${catalina.home}/modules/groupcom/dist"/>
+
+    <!-- Construct Catalina classpath -->
+  <path id="ha.classpath">
+    <pathelement location="${catalina.build}/server/lib/catalina.jar"/>
+    <pathelement location="${catalina.build}/server/lib/tomcat-util.jar"/>
+    <pathelement location="${catalina.build}/server/lib/catalina-groups.jar"/>
+    <pathelement location="${commons-modeler.jar}"/>
+    <pathelement location="${commons-logging.jar}"/>
+    <pathelement location="${jmx.jar}"/>
+    <pathelement location="${catalina.build}/common/lib/servlet-api.jar"/>
+  </path>
+
+    <!-- Source path -->
+  <path id="javadoc.sourcepath">
+    <pathelement location="src/share"/>
+  </path>
+  
+  
+  <!-- =================== BUILD: Set compile flags ======================= -->
+  <target name="build-groups">
+      <ant antfile="../groupcom/build.xml" dir="../groupcom/"/>
+  </target>
+  
+
+  <!-- =================== BUILD: Set compile flags ======================= -->
+  <target name="flags">
+    <!-- JDK flags -->
+    <available property="jdk.1.2.present" classname="java.util.HashMap" />
+    <available property="jdk.1.3.present" classname="java.lang.reflect.Proxy" />
+    <available property="jdk.1.4.present" classname="java.nio.Buffer" />
+  </target>
+
+
+  <!-- =================== BUILD: Set compile flags ======================= -->
+  <target name="flags.display" depends="flags" unless="flags.hide">
+
+    <echo message="--- Build environment for Catalina ---" />
+
+    <echo message="If ${property_name} is displayed, then the property is not set)" />
+
+    <echo message="--- Build options ---" />
+    <echo message="full.dist=${full.dist}" />
+    <echo message="build.sysclasspath=${build.sysclasspath}" />
+    <echo message="compile.debug=${compile.debug}" />
+    <echo message="compile.deprecation=${compile.deprecation}" />
+    <echo message="compile.optimize=${compile.optimize}" />
+
+    <echo message="--- Ant Flags ---" />
+    <echo message="&lt;style&gt; task available (required)=${style.available}" />
+
+    <echo message="--- JDK ---" />
+    <echo message="jdk.1.2.present=${jdk.1.2.present}" />
+    <echo message="jdk.1.3.present=${jdk.1.3.present}" />
+    <echo message="jdk.1.4.present=${jdk.1.4.present}" />
+
+  </target>
+
+  <!-- =================== BUILD: Create Directories ====================== -->
+  <target name="build-prepare">
+    <mkdir dir="${catalina.build}"/>
+    <mkdir dir="${catalina.build}/classes"/>
+    <mkdir dir="${ha.dist}"/>
+  </target>
+
+
+
+
+  <!-- ================ BUILD: Compile Catalina Components ================ -->
+  
+  <target name="build-catalina-ha" depends="build-prepare, build-groups">
+    <!-- Compile internal server components -->
+    <javac srcdir="${basedir}/src/share" destdir="${catalina.build}/classes"
+           debug="${compile.debug}" deprecation="${compile.deprecation}"
+           optimize="${compile.optimize}"
+           excludes="**/CVS/**"  	   
+    	>
+        <classpath refid="ha.classpath" />
+    </javac>
+    <copy file="${basedir}/src/share/org/apache/catalina/ha/LocalStrings.properties"
+    	  tofile="${catalina.build}/classes/org/apache/catalina/ha/LocalStrings.properties"/>
+    <copy file="${basedir}/src/share/org/apache/catalina/ha/session/LocalStrings.properties"
+    	  tofile="${catalina.build}/classes/org/apache/catalina/ha/session/LocalStrings.properties"/>
+    <copy file="${basedir}/src/share/org/apache/catalina/ha/tcp/LocalStrings.properties"
+    	  tofile="${catalina.build}/classes/org/apache/catalina/ha/tcp/LocalStrings.properties"/>
+    <copy file="${basedir}/src/share/org/apache/catalina/ha/session/mbeans-descriptors.xml"
+    	  tofile="${catalina.build}/classes/org/apache/catalina/ha/session/mbeans-descriptors.xml"/>
+    <copy file="${basedir}/src/share/org/apache/catalina/ha/tcp/mbeans-descriptors.xml"
+    	  tofile="${catalina.build}/classes/org/apache/catalina/ha/tcp/mbeans-descriptors.xml"/>
+   </target>
+
+
+  <!-- ================ BUILD: Create Catalina Javadocs =================== -->
+  <target name="javadoc">
+    <delete dir="${catalina.build}/javadoc"/>
+    <mkdir dir="${catalina.build}/javadoc"/>
+    <javadoc packagenames="org.apache.catalina.*,org.apache.naming.*"
+      classpathref="catalina.classpath"
+      sourcepathref="javadoc.sourcepath"
+      destdir="${catalina.build}/javadoc"
+      author="true"
+      version="true"
+      windowtitle="Catalina Internal API Documentation"
+      doctitle="Catalina API"
+      bottom="Copyright &#169; 2000-2002 Apache Software Foundation.  All Rights Reserved."
+    />
+  </target>
+
+
+  <!-- ======================= BUILD: Clean Directory ===================== -->
+  <target name="build-clean">
+    <delete dir="${catalina.build}"/>
+  </target>
+
+
+  <!-- ==================== BUILD: Rebuild Everything ===================== -->
+
+
+
+
+  <!-- ================ DIST: Create Distribution ========================= -->
+  <target name="dist" depends="build-catalina-ha">
+    
+    <jar destfile="${ha.dist}/catalina-cluster.jar"
+         basedir="${catalina.build}/classes">
+       <include name="org/apache/catalina/ha/**" />
+       <exclude name="**/package.html" />
+       <exclude name="**/LocalStrings_*" />
+    </jar>
+  </target>
+
+  <target name="copy" depends="dist" >
+     <copy file="${ha.dist}/catalina-cluster.jar" todir="${catalina.build}/server/lib" />
+  </target>
+  
+  <!-- ======================== DIST: Clean Directory ===================== -->
+
+
+  <!-- ====================== Convenient Synonyms ========================= -->
+
+
+</project>

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/ha/etc/cluster-server.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/ha/etc/cluster-server.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/ha/etc/cluster-server.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,394 @@
+<!-- Example Server Configuration File -->
+<!-- Note that component elements are nested corresponding to their
+     parent-child relationships with each other -->
+
+<!-- A "Server" is a singleton element that represents the entire JVM,
+     which may contain one or more "Service" instances.  The Server
+     listens for a shutdown command on the indicated port.
+
+     Note:  A "Server" is not itself a "Container", so you may not
+     define subcomponents such as "Valves" or "Loggers" at this level.
+ -->
+
+<Server port="7005" shutdown="SHUTDOWN">
+
+  <!-- Comment these entries out to disable JMX MBeans support used for the 
+       administration web application -->
+  <Listener className="org.apache.catalina.core.AprLifecycleListener" />
+  <Listener className="org.apache.catalina.mbeans.ServerLifecycleListener" />
+  <Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" />
+  <Listener className="org.apache.catalina.storeconfig.StoreConfigLifecycleListener"/>
+
+  <!-- Global JNDI resources -->
+  <GlobalNamingResources>
+
+    <!-- Test entry for demonstration purposes -->
+    <Environment name="simpleValue" type="java.lang.Integer" value="30"/>
+
+    <!-- Editable user database that can also be used by
+         UserDatabaseRealm to authenticate users -->
+    <Resource name="UserDatabase" auth="Container"
+              type="org.apache.catalina.UserDatabase"
+       description="User database that can be updated and saved"
+           factory="org.apache.catalina.users.MemoryUserDatabaseFactory"
+          pathname="conf/tomcat-users.xml" />
+
+  </GlobalNamingResources>
+
+  <!-- A "Service" is a collection of one or more "Connectors" that share
+       a single "Container" (and therefore the web applications visible
+       within that Container).  Normally, that Container is an "Engine",
+       but this is not required.
+
+       Note:  A "Service" is not itself a "Container", so you may not
+       define subcomponents such as "Valves" or "Loggers" at this level.
+   -->
+
+  <!-- Define the Tomcat Stand-Alone Service -->
+  <Service name="Catalina">
+
+    <!-- A "Connector" represents an endpoint by which requests are received
+         and responses are returned.  Each Connector passes requests on to the
+         associated "Container" (normally an Engine) for processing.
+
+         By default, a non-SSL HTTP/1.1 Connector is established on port 8080.
+         You can also enable an SSL HTTP/1.1 Connector on port 8443 by
+         following the instructions below and uncommenting the second Connector
+         entry.  SSL support requires the following steps (see the SSL Config
+         HOWTO in the Tomcat 5 documentation bundle for more detailed
+         instructions):
+         * If your JDK version 1.3 or prior, download and install JSSE 1.0.2 or
+           later, and put the JAR files into "$JAVA_HOME/jre/lib/ext".
+         * Execute:
+             %JAVA_HOME%\bin\keytool -genkey -alias tomcat -keyalg RSA (Windows)
+             $JAVA_HOME/bin/keytool -genkey -alias tomcat -keyalg RSA  (Unix)
+           with a password value of "changeit" for both the certificate and
+           the keystore itself.
+
+         By default, DNS lookups are enabled when a web application calls
+         request.getRemoteHost().  This can have an adverse impact on
+         performance, so you can disable it by setting the
+         "enableLookups" attribute to "false".  When DNS lookups are disabled,
+         request.getRemoteHost() will return the String version of the
+         IP address of the remote client.
+    -->
+
+    <!-- Define a non-SSL HTTP/1.1 Connector on port 8080 -->
+    <Connector port="7080" maxHttpHeaderSize="8192"
+               maxThreads="150" minSpareThreads="25" maxSpareThreads="75"
+               enableLookups="false" redirectPort="8443" acceptCount="100"
+               connectionTimeout="20000" disableUploadTimeout="true" />
+    <!-- Note : To disable connection timeouts, set connectionTimeout value
+     to 0 -->
+	
+	<!-- Note : To use gzip compression you could set the following properties :
+	
+			   compression="on" 
+			   compressionMinSize="2048" 
+			   noCompressionUserAgents="gozilla, traviata" 
+			   compressableMimeType="text/html,text/xml"
+	-->
+
+    <!-- Define a SSL HTTP/1.1 Connector on port 8443 -->
+    <!--
+    <Connector port="8443" maxHttpHeaderSize="8192"
+               maxThreads="150" minSpareThreads="25" maxSpareThreads="75"
+               enableLookups="false" disableUploadTimeout="true"
+               acceptCount="100" scheme="https" secure="true"
+               clientAuth="false" sslProtocol="TLS" />
+    -->
+
+    <!-- Define an AJP 1.3 Connector on port 8009 -->
+    <Connector port="7009" 
+               enableLookups="false" redirectPort="8443" protocol="AJP/1.3" />
+
+    <!-- Define a Proxied HTTP/1.1 Connector on port 8082 -->
+    <!-- See proxy documentation for more information about using this. -->
+    <!--
+    <Connector port="7082" 
+               maxThreads="150" minSpareThreads="25" maxSpareThreads="75"
+               enableLookups="false" acceptCount="100" connectionTimeout="20000"
+               proxyPort="80" disableUploadTimeout="true" />
+    -->
+
+    <!-- An Engine represents the entry point (within Catalina) that processes
+         every request.  The Engine implementation for Tomcat stand alone
+         analyzes the HTTP headers included with the request, and passes them
+         on to the appropriate Host (virtual host). -->
+
+    <!-- You should set jvmRoute to support load-balancing via AJP ie :
+    <Engine name="Standalone" defaultHost="localhost" jvmRoute="jvm1">         
+    --> 
+         
+    <!-- Define the top level container in our container hierarchy -->
+    <Engine name="Catalina" defaultHost="localhost">
+
+      <!-- The request dumper valve dumps useful debugging information about
+           the request headers and cookies that were received, and the response
+           headers and cookies that were sent, for all requests received by
+           this instance of Tomcat.  If you care only about requests to a
+           particular virtual host, or a particular application, nest this
+           element inside the corresponding <Host> or <Context> entry instead.
+
+           For a similar mechanism that is portable to all Servlet 2.4
+           containers, check out the "RequestDumperFilter" Filter in the
+           example application (the source for this filter may be found in
+           "$CATALINA_HOME/webapps/examples/WEB-INF/classes/filters").
+
+           Request dumping is disabled by default.  Uncomment the following
+           element to enable it. -->
+      <!--
+      <Valve className="org.apache.catalina.valves.RequestDumperValve"/>
+      -->
+
+      <!-- Because this Realm is here, an instance will be shared globally -->
+
+      <!-- This Realm uses the UserDatabase configured in the global JNDI
+           resources under the key "UserDatabase".  Any edits
+           that are performed against this UserDatabase are immediately
+           available for use by the Realm.  -->
+      <Realm className="org.apache.catalina.realm.UserDatabaseRealm"
+             resourceName="UserDatabase"/>
+
+      <!-- Comment out the old realm but leave here for now in case we
+           need to go back quickly -->
+      <!--
+      <Realm className="org.apache.catalina.realm.MemoryRealm" />
+      -->
+
+      <!-- Replace the above Realm with one of the following to get a Realm
+           stored in a database and accessed via JDBC -->
+
+      <!--
+      <Realm  className="org.apache.catalina.realm.JDBCRealm"
+             driverName="org.gjt.mm.mysql.Driver"
+          connectionURL="jdbc:mysql://localhost/authority"
+         connectionName="test" connectionPassword="test"
+              userTable="users" userNameCol="user_name" userCredCol="user_pass"
+          userRoleTable="user_roles" roleNameCol="role_name" />
+      -->
+
+      <!--
+      <Realm  className="org.apache.catalina.realm.JDBCRealm"
+             driverName="oracle.jdbc.driver.OracleDriver"
+          connectionURL="jdbc:oracle:thin:@ntserver:1521:ORCL"
+         connectionName="scott" connectionPassword="tiger"
+              userTable="users" userNameCol="user_name" userCredCol="user_pass"
+          userRoleTable="user_roles" roleNameCol="role_name" />
+      -->
+
+      <!--
+      <Realm  className="org.apache.catalina.realm.JDBCRealm"
+             driverName="sun.jdbc.odbc.JdbcOdbcDriver"
+          connectionURL="jdbc:odbc:CATALINA"
+              userTable="users" userNameCol="user_name" userCredCol="user_pass"
+          userRoleTable="user_roles" roleNameCol="role_name" />
+      -->
+
+      <!-- Define the default virtual host
+           Note: XML Schema validation will not work with Xerces 2.2.
+       -->
+      <Host name="localhost" appBase="webapps"
+       unpackWARs="true" autoDeploy="true"
+       xmlValidation="false" xmlNamespaceAware="false">
+
+        <!-- Defines a cluster for this node,
+             By defining this element, means that every manager will be changed.
+             So when running a cluster, only make sure that you have webapps in there
+             that need to be clustered and remove the other ones.
+             A cluster has the following parameters:
+
+             className = the fully qualified name of the cluster class
+
+             clusterName = a descriptive name for your cluster, can be anything
+
+             mcastAddr = the multicast address, has to be the same for all the nodes
+
+             mcastPort = the multicast port, has to be the same for all the nodes
+             
+             mcastBindAddr = bind the multicast socket to a specific address
+             
+             mcastTTL = the multicast TTL if you want to limit your broadcast
+             
+             mcastSoTimeout = the multicast readtimeout 
+
+             mcastFrequency = the number of milliseconds in between sending a "I'm alive" heartbeat
+
+             mcastDropTime = the number a milliseconds before a node is considered "dead" if no heartbeat is received
+
+             tcpThreadCount = the number of threads to handle incoming replication requests, optimal would be the same amount of threads as nodes 
+
+             tcpListenAddress = the listen address (bind address) for TCP cluster request on this host, 
+                                in case of multiple ethernet cards.
+                                auto means that address becomes
+                                InetAddress.getLocalHost().getHostAddress()
+
+             tcpListenPort = the tcp listen port
+
+             tcpSelectorTimeout = the timeout (ms) for the Selector.select() method in case the OS
+                                  has a wakup bug in java.nio. Set to 0 for no timeout
+
+             printToScreen = true means that managers will also print to std.out
+
+             expireSessionsOnShutdown = true means that 
+
+             useDirtyFlag = true means that we only replicate a session after setAttribute,removeAttribute has been called.
+                            false means to replicate the session after each request.
+                            false means that replication would work for the following piece of code: (only for SimpleTcpReplicationManager)
+                            <%
+                            HashMap map = (HashMap)session.getAttribute("map");
+                            map.put("key","value");
+                            %>
+             replicationMode = can be either 'pooled', 'synchronous' or 'asynchronous'.
+                               * Pooled means that the replication happens using several sockets in a synchronous way. Ie, the data gets replicated, then the request return. This is the same as the 'synchronous' setting except it uses a pool of sockets, hence it is multithreaded. This is the fastest and safest configuration. To use this, also increase the nr of tcp threads that you have dealing with replication.
+                               * Synchronous means that the thread that executes the request, is also the
+                               thread the replicates the data to the other nodes, and will not return until all
+                               nodes have received the information.
+                               * Asynchronous means that there is a specific 'sender' thread for each cluster node,
+                               so the request thread will queue the replication request into a "smart" queue,
+                               and then return to the client.
+                               The "smart" queue is a queue where when a session is added to the queue, and the same session
+                               already exists in the queue from a previous request, that session will be replaced
+                               in the queue instead of replicating two requests. This almost never happens, unless there is a 
+                               large network delay.
+        -->             
+        <!--
+            When configuring for clustering, you also add in a valve to catch all the requests
+            coming in, at the end of the request, the session may or may not be replicated.
+            A session is replicated if and only if all the conditions are met:
+            1. useDirtyFlag is true or setAttribute or removeAttribute has been called AND
+            2. a session exists (has been created)
+            3. the request is not trapped by the "filter" attribute
+
+            The filter attribute is to filter out requests that could not modify the session,
+            hence we don't replicate the session after the end of this request.
+            The filter is negative, ie, anything you put in the filter, you mean to filter out,
+            ie, no replication will be done on requests that match one of the filters.
+            The filter attribute is delimited by ;, so you can't escape out ; even if you wanted to.
+
+            filter=".*\.gif;.*\.js;" means that we will not replicate the session after requests with the URI
+            ending with .gif and .js are intercepted.
+            
+            The deployer element can be used to deploy apps cluster wide.
+            Currently the deployment only deploys/undeploys to working members in the cluster
+            so no WARs are copied upons startup of a broken node.
+            The deployer watches a directory (watchDir) for WAR files when watchEnabled="true"
+            When a new war file is added the war gets deployed to the local instance,
+            and then deployed to the other instances in the cluster.
+            When a war file is deleted from the watchDir the war is undeployed locally 
+            and cluster wide
+        -->
+        
+        <Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"
+                 managerClassName="org.apache.catalina.ha.session.BackupManager"
+                 expireSessionsOnShutdown="false"
+                 notifyListenersOnReplication="true"
+                 channelSendOptions="11"
+                 manager.mapSendOptions="11">
+
+            <Channel className="org.apache.catalina.tribes.group.GroupChannel">
+                <Membership 
+                    className="org.apache.catalina.tribes.membership.McastService"
+                    mcastAddr="228.0.0.4"
+                    mcastPort="45564"
+                    mcastFrequency="500"
+                    mcastDropTime="3000"/>
+
+                <Receiver 
+                    className="org.apache.catalina.tribes.transport.nio.NioReceiver"
+                    tcpListenAddress="auto"
+                    tcpListenPort="4001"
+                    minThreads="6"
+                    maxThreads="25"
+                    rxBufSize="43800"
+                    txBufSize="25188"
+                    autoBind="10"/>
+
+                <Sender
+                    className="org.apache.catalina.tribes.transport.ReplicationTransmitter">
+                    <Transport className="org.apache.catalina.tribes.transport.nio.PooledParallelSender"
+                        rxBufSize="43800"
+                        txBufSize="25188"/>
+                </Sender>
+                <!--
+                <Interceptor className="org.apache.catalina.tribes.group.interceptors.GzipInterceptor"/>
+                <Interceptor className="org.apache.catalina.tribes.group.interceptors.FragmentationInterceptor"/>
+                <Interceptor className="org.apache.catalina.tribes.group.interceptors.OrderInterceptor"/>
+                <Interceptor className="org.apache.catalina.tribes.group.interceptors.MessageDispatchInterceptor"/>
+                -->
+            </Channel>
+            
+            <Valve className="org.apache.catalina.ha.tcp.ReplicationValve"
+                   filter=".*\.gif;.*\.js;.*\.jpg;.*\.png;.*\.htm;.*\.html;.*\.css;.*\.txt;"/>
+                   
+            <Deployer className="org.apache.catalina.ha.deploy.FarmWarDeployer"
+                      tempDir="/tmp/war-temp/"
+                      deployDir="/tmp/war-deploy/"
+                      watchDir="/tmp/war-listen/"
+                      watchEnabled="false"/>
+                      
+            <ClusterListener className="org.apache.catalina.ha.session.ClusterSessionListener"/>
+        </Cluster>
+    
+
+
+
+        <!-- Normally, users must authenticate themselves to each web app
+             individually.  Uncomment the following entry if you would like
+             a user to be authenticated the first time they encounter a
+             resource protected by a security constraint, and then have that
+             user identity maintained across *all* web applications contained
+             in this virtual host. -->
+        <!--
+        <Valve className="org.apache.catalina.authenticator.SingleSignOn" />
+        -->
+
+        <!-- Access log processes all requests for this virtual host.  By
+             default, log files are created in the "logs" directory relative to
+             $CATALINA_HOME.  If you wish, you can specify a different
+             directory with the "directory" attribute.  Specify either a relative
+             (to $CATALINA_HOME) or absolute path to the desired directory.
+        -->
+        <!--
+        <Valve className="org.apache.catalina.valves.AccessLogValve"
+                 directory="logs"  prefix="localhost_access_log." suffix=".txt"
+                 pattern="common" resolveHosts="false"/>
+        -->
+
+        <!-- Access log processes all requests for this virtual host.  By
+             default, log files are created in the "logs" directory relative to
+             $CATALINA_HOME.  If you wish, you can specify a different
+             directory with the "directory" attribute.  Specify either a relative
+             (to $CATALINA_HOME) or absolute path to the desired directory.
+             This access log implementation is optimized for maximum performance,
+             but is hardcoded to support only the "common" and "combined" patterns.
+        -->
+        <!--
+        <Valve className="org.apache.catalina.valves.FastCommonAccessLogValve"
+                 directory="logs"  prefix="localhost_access_log." suffix=".txt"
+                 pattern="common" resolveHosts="false"/>
+        -->
+        <!-- Access log processes all requests for this virtual host.  By
+             default, log files are created in the "logs" directory relative to
+             $CATALINA_HOME.  If you wish, you can specify a different
+             directory with the "directory" attribute.  Specify either a relative
+             (to $CATALINA_HOME) or absolute path to the desired directory.
+             This access log implementation is optimized for maximum performance,
+             but is hardcoded to support only the "common" and "combined" patterns.
+
+             This valve use NIO direct Byte Buffer to asynchornously store the
+             log.
+        -->
+        <!--
+        <Valve className="org.apache.catalina.valves.ByteBufferAccessLogValve"
+                 directory="logs"  prefix="localhost_access_log." suffix=".txt"
+                 pattern="common" resolveHosts="false"/>
+        -->
+
+      </Host>
+
+    </Engine>
+
+  </Service>
+
+</Server>

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/CatalinaCluster.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/CatalinaCluster.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/CatalinaCluster.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,130 @@
+/*
+ * Copyright 1999,2004-2005 The Apache Software Foundation.
+ * 
+ * Licensed 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.ha;
+
+import java.util.Map;
+
+import org.apache.catalina.Cluster;
+import org.apache.catalina.LifecycleException;
+import org.apache.catalina.Manager;
+import org.apache.catalina.Valve;
+import org.apache.catalina.tribes.Channel;
+import org.apache.catalina.tribes.Member;
+import org.apache.commons.logging.Log;
+
+
+
+/**
+ * A <b>CatalinaCluster</b> interface allows to plug in and out the 
+ * different cluster implementations
+ *
+ * @author Filip Hanik
+ * @version $Revision: 379550 $, $Date: 2006-02-21 12:06:35 -0600 (Tue, 21 Feb 2006) $
+ */
+
+public interface CatalinaCluster extends Cluster {
+    // ----------------------------------------------------- Instance Variables
+
+    /**
+     * Descriptive information about this component implementation.
+     */
+    public String info = "CatalinaCluster/2.0";
+    
+    /**
+     * Start the cluster, the owning container will invoke this
+     * @throws Exception - if failure to start cluster
+     */
+    public void start() throws Exception;
+    
+    /**
+     * Stops the cluster, the owning container will invoke this
+     * @throws LifecycleException
+     */
+    public void stop() throws LifecycleException;
+    
+    /**
+     * Returns the associates logger with this cluster.
+     *
+     * @return Log
+     */
+    public Log getLogger();
+    
+    /**
+     * Sends a message to all the members in the cluster
+     * @param msg ClusterMessage
+     */
+    public void send(ClusterMessage msg);
+    
+    /**
+     * Sends a message to a specific member in the cluster.
+     *
+     * @param msg ClusterMessage
+     * @param dest Member
+     */
+    public void send(ClusterMessage msg, Member dest);
+    
+    /**
+     * Sends a message to a all members at local cluster domain
+     *
+     * @param msg ClusterMessage
+     */
+    public void sendClusterDomain(ClusterMessage msg);
+
+    /**
+     * Returns that cluster has members.
+     */
+    public boolean hasMembers();
+
+    /**
+     * Returns all the members currently participating in the cluster.
+     *
+     * @return Member[]
+     */
+    public Member[] getMembers();
+    
+    /**
+     * Return the member that represents this node.
+     *
+     * @return Member
+     */
+    public Member getLocalMember();
+    
+    public void addValve(Valve valve);
+    
+    public void addClusterListener(ClusterListener listener);
+    
+    public void removeClusterListener(ClusterListener listener);
+    
+    public void setClusterDeployer(ClusterDeployer deployer);
+    
+    public ClusterDeployer getClusterDeployer();
+    
+    /**
+     * @return The map of managers
+     */
+    public Map getManagers();
+
+    public Manager getManager(String name);
+    public void removeManager(String name,Manager manager);
+    public void addManager(String name,Manager manager);
+    public String getManagerName(String name, Manager manager);
+    public Valve[] getValves();
+    
+    public void setChannel(Channel channel);
+    public Channel getChannel();
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/ClusterDeployer.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/ClusterDeployer.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/ClusterDeployer.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,120 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ *
+ * Licensed 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.ha;
+
+/**
+ * A <b>ClusterDeployer</b> interface allows to plug in and out the
+ * different deployment implementations
+ *
+ * @author Filip Hanik
+ * @version $Revision: 378050 $, $Date: 2006-02-15 12:30:02 -0600 (Wed, 15 Feb 2006) $
+ */
+import org.apache.catalina.LifecycleException;
+import java.io.IOException;
+import java.net.URL;
+import org.apache.catalina.tribes.ChannelListener;
+
+public interface ClusterDeployer extends ChannelListener {
+    /**
+     * Descriptive information about this component implementation.
+     */
+    public String info = "ClusterDeployer/1.0";
+    /**
+     * Start the cluster deployer, the owning container will invoke this
+     * @throws Exception - if failure to start cluster
+     */
+    public void start() throws Exception;
+
+    /**
+     * Stops the cluster deployer, the owning container will invoke this
+     * @throws LifecycleException
+     */
+    public void stop() throws LifecycleException;
+
+    /**
+     * Sets the deployer for this cluster deployer to use.
+     * @param deployer Deployer
+     */
+    // FIXME
+    //public void setDeployer(Deployer deployer);
+
+    /**
+     * Install a new web application, whose web application archive is at the
+     * specified URL, into this container and all the other
+     * members of the cluster with the specified context path.
+     * A context path of "" (the empty string) should be used for the root
+     * application for this container.  Otherwise, the context path must
+     * start with a slash.
+     * <p>
+     * If this application is successfully installed locally, 
+     * a ContainerEvent of type
+     * <code>INSTALL_EVENT</code> will be sent to all registered listeners,
+     * with the newly created <code>Context</code> as an argument.
+     *
+     * @param contextPath The context path to which this application should
+     *  be installed (must be unique)
+     * @param war A URL of type "jar:" that points to a WAR file, or type
+     *  "file:" that points to an unpacked directory structure containing
+     *  the web application to be installed
+     *
+     * @exception IllegalArgumentException if the specified context path
+     *  is malformed (it must be "" or start with a slash)
+     * @exception IllegalStateException if the specified context path
+     *  is already attached to an existing web application
+     * @exception IOException if an input/output error was encountered
+     *  during installation
+     */
+    public void install(String contextPath, URL war) throws IOException;
+
+    /**
+     * Remove an existing web application, attached to the specified context
+     * path.  If this application is successfully removed, a
+     * ContainerEvent of type <code>REMOVE_EVENT</code> will be sent to all
+     * registered listeners, with the removed <code>Context</code> as
+     * an argument. Deletes the web application war file and/or directory
+     * if they exist in the Host's appBase.
+     *
+     * @param contextPath The context path of the application to be removed
+     * @param undeploy boolean flag to remove web application from server
+     *
+     * @exception IllegalArgumentException if the specified context path
+     *  is malformed (it must be "" or start with a slash)
+     * @exception IllegalArgumentException if the specified context path does
+     *  not identify a currently installed web application
+     * @exception IOException if an input/output error occurs during
+     *  removal
+     */
+    public void remove(String contextPath, boolean undeploy) throws IOException;
+
+    /**
+     * call from container Background Process
+     */
+    public void backgroundProcess();
+    
+    /**
+     * Returns the cluster the cluster deployer is associated with
+     * @return CatalinaCluster
+     */
+    public CatalinaCluster getCluster();
+
+    /**
+     * Associates the cluster deployer with a cluster
+     * @param cluster CatalinaCluster
+     */
+    public void setCluster(CatalinaCluster cluster);
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/ClusterListener.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/ClusterListener.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/ClusterListener.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,113 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ *
+ * Licensed 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.ha;
+
+
+
+
+import org.apache.catalina.tribes.ChannelListener;
+import org.apache.catalina.tribes.ChannelMessage;
+import org.apache.catalina.util.StringManager;
+import java.io.Serializable;
+import org.apache.catalina.tribes.Member;
+
+
+/**
+ * Receive SessionID cluster change from other backup node after primary session
+ * node is failed.
+ * 
+ * @author Peter Rossbach
+ * @author Filip Hanik
+ * @version $Revision: 378258 $ $Date: 2006-02-16 08:42:35 -0600 (Thu, 16 Feb 2006) $
+ */
+public abstract class ClusterListener implements ChannelListener {
+
+    public static org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory.getLog(ClusterListener.class);
+
+
+    //--Instance Variables--------------------------------------
+
+    /**
+     * The string manager for this package.
+     */
+    protected StringManager sm = StringManager.getManager(Constants.Package);
+
+    protected CatalinaCluster cluster = null;
+
+    //--Constructor---------------------------------------------
+
+    public ClusterListener() {
+    }
+    
+    //--Instance Getters/Setters--------------------------------
+    
+    public CatalinaCluster getCluster() {
+        return cluster;
+    }
+
+    public void setCluster(CatalinaCluster cluster) {
+        if (log.isDebugEnabled()) {
+            if (cluster != null)
+                log.debug("add ClusterListener " + this.toString() + " to cluster" + cluster);
+            else
+                log.debug("remove ClusterListener " + this.toString() + " from cluster");
+        }
+        this.cluster = cluster;
+    }
+
+    public boolean equals(Object listener) {
+        return super.equals(listener);
+    }
+
+    public int hashCode() {
+        return super.hashCode();
+    }
+
+    //--Logic---------------------------------------------------
+
+    public final void messageReceived(Serializable msg, Member member) {
+        if ( msg instanceof ClusterMessage ) messageReceived((ClusterMessage)msg);
+    }
+    public final boolean accept(Serializable msg, Member member) {
+        if ( msg instanceof ClusterMessage ) return true;
+        return false;
+    }
+
+
+
+    /**
+     * Callback from the cluster, when a message is received, The cluster will
+     * broadcast it invoking the messageReceived on the receiver.
+     * 
+     * @param msg
+     *            ClusterMessage - the message received from the cluster
+     */
+    public abstract void messageReceived(ClusterMessage msg) ;
+    
+
+    /**
+     * Accept only SessionIDMessages
+     * 
+     * @param msg
+     *            ClusterMessage
+     * @return boolean - returns true to indicate that messageReceived should be
+     *         invoked. If false is returned, the messageReceived method will
+     *         not be invoked.
+     */
+    public abstract boolean accept(ClusterMessage msg) ;
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/ClusterManager.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/ClusterManager.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/ClusterManager.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,110 @@
+/*
+ * Copyright 1999,2004-2005 The Apache Software Foundation.
+ * 
+ * Licensed 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.ha;
+
+
+import org.apache.catalina.Manager;
+import java.io.IOException;
+import org.apache.catalina.tribes.io.ReplicationStream;
+
+
+/**
+ * The common interface used by all cluster manager.
+ * This is so that we can have a more pluggable way
+ * of swapping session managers for different algorithms.
+ *
+ * @author Filip Hanik
+ * @author Peter Rossbach
+ */
+public interface ClusterManager extends Manager {
+
+   /**
+    * A message was received from another node, this
+    * is the callback method to implement if you are interested in
+    * receiving replication messages.
+    * @param msg - the message received.
+    */
+   public void messageDataReceived(ClusterMessage msg);
+
+   /**
+    * When the request has been completed, the replication valve
+    * will notify the manager, and the manager will decide whether
+    * any replication is needed or not.
+    * If there is a need for replication, the manager will
+    * create a session message and that will be replicated.
+    * The cluster determines where it gets sent.
+    * @param sessionId - the sessionId that just completed.
+    * @return a SessionMessage to be sent.
+    */
+   public ClusterMessage requestCompleted(String sessionId);
+
+   /**
+    * When the manager expires session not tied to a request.
+    * The cluster will periodically ask for a list of sessions
+    * that should expire and that should be sent across the wire.
+    * @return String[] The invalidated sessions
+    */
+   public String[] getInvalidatedSessions();
+   
+   /**
+    * Return the name of the manager, at host /context name and at engine hostname+/context.
+    * @return String
+    * @since 5.5.10
+    */
+   public String getName();
+   
+   /**
+    * Set the name of the manager, at host /context name and at engine hostname+/context
+    * @param name
+    * @since 5.5.10
+    */
+   public void setName(String name);
+         
+   public CatalinaCluster getCluster();
+
+   public void setCluster(CatalinaCluster cluster);
+   
+   /**
+    * @return Manager send only to same cluster domain.
+    * @since 5.5.10
+    */
+   public boolean isSendClusterDomainOnly();
+
+   /**
+    * @param sendClusterDomainOnly Flag value.
+    * @since 5.5.10
+    */
+   public void setSendClusterDomainOnly(boolean sendClusterDomainOnly);
+
+   /**
+    * @param mode The mode
+    * @since 5.5.10
+    */
+   public void setDefaultMode(boolean mode);
+
+   /**
+    * @since 5.5.10
+    */
+   public boolean isDefaultMode();
+   
+   public ReplicationStream getReplicationStream(byte[] data) throws IOException;
+
+   public ReplicationStream getReplicationStream(byte[] data, int offset, int length) throws IOException;
+   
+   public boolean isNotifyListenersOnReplication();
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/ClusterMessage.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/ClusterMessage.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/ClusterMessage.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,33 @@
+/*
+ * Copyright 1999,2005 The Apache Software Foundation.
+ *
+ * Licensed 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.ha;
+
+import java.io.Serializable;
+import org.apache.catalina.tribes.Member;
+
+
+/**
+ * @author Filip Hanik
+ * 
+ */
+public interface ClusterMessage extends Serializable {
+    public Member getAddress();
+    public void setAddress(Member member);
+    public String getUniqueId();
+    public void setUniqueId(String id);
+    public long getTimestamp();
+    public void setTimestamp(long timestamp);
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/ClusterMessageBase.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/ClusterMessageBase.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/ClusterMessageBase.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,61 @@
+package org.apache.catalina.ha;
+
+import org.apache.catalina.tribes.Member;
+
+
+/**
+ * <p>Title: </p>
+ *
+ * <p>Description: </p>
+ *
+ * <p>Copyright: Copyright (c) 2005</p>
+ *
+ * <p>Company: </p>
+ *
+ * @author not attributable
+ * @version 1.0
+ */
+public class ClusterMessageBase implements ClusterMessage {
+    
+    protected transient Member address;
+    private String uniqueId;
+    private long timestamp;
+    public ClusterMessageBase() {
+    }
+
+    /**
+     * getAddress
+     *
+     * @return Member
+     * @todo Implement this org.apache.catalina.ha.ClusterMessage method
+     */
+    public Member getAddress() {
+        return address;
+    }
+
+    public String getUniqueId() {
+        return uniqueId;
+    }
+
+    public long getTimestamp() {
+        return timestamp;
+    }
+
+    /**
+     * setAddress
+     *
+     * @param member Member
+     * @todo Implement this org.apache.catalina.ha.ClusterMessage method
+     */
+    public void setAddress(Member member) {
+        this.address = member;
+    }
+
+    public void setUniqueId(String uniqueId) {
+        this.uniqueId = uniqueId;
+    }
+
+    public void setTimestamp(long timestamp) {
+        this.timestamp = timestamp;
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/ClusterRuleSet.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/ClusterRuleSet.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/ClusterRuleSet.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,176 @@
+/*
+ * Copyright 1999-2001,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.ha;
+
+
+import org.apache.tomcat.util.digester.Digester;
+import org.apache.tomcat.util.digester.RuleSetBase;
+
+
+/**
+ * <p><strong>RuleSet</strong> for processing the contents of a
+ * Cluster definition element.  </p>
+ *
+ * @author Filip Hanik
+ * @author Peter Rossbach
+ * @version $Revision: 387285 $ $Date: 2006-03-20 13:30:50 -0600 (Mon, 20 Mar 2006) $
+ */
+
+public class ClusterRuleSet extends RuleSetBase {
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The matching pattern prefix to use for recognizing our elements.
+     */
+    protected String prefix = null;
+
+
+    // ------------------------------------------------------------ Constructor
+
+
+    /**
+     * Construct an instance of this <code>RuleSet</code> with the default
+     * matching pattern prefix.
+     */
+    public ClusterRuleSet() {
+
+        this("");
+
+    }
+
+
+    /**
+     * Construct an instance of this <code>RuleSet</code> with the specified
+     * matching pattern prefix.
+     *
+     * @param prefix Prefix for matching pattern rules (including the
+     *  trailing slash character)
+     */
+    public ClusterRuleSet(String prefix) {
+        super();
+        this.namespaceURI = null;
+        this.prefix = prefix;
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * <p>Add the set of Rule instances defined in this RuleSet to the
+     * specified <code>Digester</code> instance, associating them with
+     * our namespace URI (if any).  This method should only be called
+     * by a Digester instance.</p>
+     *
+     * @param digester Digester instance to which the new Rule instances
+     *  should be added.
+     */
+    public void addRuleInstances(Digester digester) {
+        //Cluster configuration start
+        
+        digester.addObjectCreate(prefix + "Channel",
+                                 null, // MUST be specified in the element
+                                 "className");
+        digester.addSetProperties(prefix + "Channel");
+        digester.addSetNext(prefix + "Channel",
+                            "setChannel",
+                            "org.apache.catalina.tribes.Channel");
+
+
+        String channelPrefix = prefix + "Channel/";
+        { //channel properties
+            digester.addObjectCreate(channelPrefix + "Membership",
+                                     null, // MUST be specified in the element
+                                     "className");
+            digester.addSetProperties(channelPrefix + "Membership");
+            digester.addSetNext(channelPrefix + "Membership",
+                                "setMembershipService",
+                                "org.apache.catalina.tribes.MembershipService");
+
+            digester.addObjectCreate(channelPrefix + "Sender",
+                                     null, // MUST be specified in the element
+                                     "className");
+            digester.addSetProperties(channelPrefix + "Sender");
+            digester.addSetNext(channelPrefix + "Sender",
+                                "setChannelSender",
+                                "org.apache.catalina.tribes.ChannelSender");
+
+            digester.addObjectCreate(channelPrefix + "Sender/Transport",
+                                     null, // MUST be specified in the element
+                                     "className");
+            digester.addSetProperties(channelPrefix + "Sender/Transport");
+            digester.addSetNext(channelPrefix + "Sender/Transport",
+                                "setTransport",
+                                "org.apache.catalina.tribes.tcp.MultiPointSender");
+
+
+            digester.addObjectCreate(channelPrefix + "Receiver",
+                                     null, // MUST be specified in the element
+                                     "className");
+            digester.addSetProperties(channelPrefix + "Receiver");
+            digester.addSetNext(channelPrefix + "Receiver",
+                                "setChannelReceiver",
+                                "org.apache.catalina.tribes.ChannelReceiver");
+
+            digester.addObjectCreate(channelPrefix + "Interceptor",
+                                     null, // MUST be specified in the element
+                                     "className");
+            digester.addSetProperties(channelPrefix + "Interceptor");
+            digester.addSetNext(channelPrefix + "Interceptor",
+                                "addInterceptor",
+                                "org.apache.catalina.tribes.ChannelInterceptor");
+        }
+
+        digester.addObjectCreate(prefix + "Valve",
+                                 null, // MUST be specified in the element
+                                 "className");
+        digester.addSetProperties(prefix + "Valve");
+        digester.addSetNext(prefix + "Valve",
+                            "addValve",
+                            "org.apache.catalina.Valve");
+        
+        digester.addObjectCreate(prefix + "Deployer",
+                                 null, // MUST be specified in the element
+                                 "className");
+        digester.addSetProperties(prefix + "Deployer");
+        digester.addSetNext(prefix + "Deployer",
+                            "setClusterDeployer",
+                            "org.apache.catalina.ha.ClusterDeployer");
+        
+        digester.addObjectCreate(prefix + "Listener",
+                null, // MUST be specified in the element
+                "className");
+        digester.addSetProperties(prefix + "Listener");
+        digester.addSetNext(prefix + "Listener",
+                            "addLifecycleListener",
+                            "org.apache.catalina.LifecycleListener");
+        
+        digester.addObjectCreate(prefix + "ClusterListener",
+                null, // MUST be specified in the element
+                "className");
+        digester.addSetProperties(prefix + "ClusterListener");
+        digester.addSetNext(prefix + "ClusterListener",
+                            "addClusterListener",
+                            "org.apache.catalina.ha.ClusterListener");
+        //Cluster configuration end
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/ClusterSession.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/ClusterSession.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/ClusterSession.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,39 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.ha;
+
+import org.apache.catalina.Session;
+import javax.servlet.http.HttpSession;
+
+public interface ClusterSession extends Session, HttpSession {
+   /**
+    * returns true if this session is the primary session, if that is the
+    * case, the manager can expire it upon timeout.
+    * @return True if this session is primary
+    */
+   public boolean isPrimarySession();
+
+   /**
+    * Sets whether this is the primary session or not.
+    * @param primarySession Flag value
+    */
+   public void setPrimarySession(boolean primarySession);
+   
+   
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/ClusterValve.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/ClusterValve.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/ClusterValve.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,36 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.ha;
+
+/**
+ * Cluster Valve Interface to mark all Cluster Valves 
+ * Only those Valve can'be configured as Cluster Valves
+ * @author Peter Rossbach
+ * @version $Revision: 303842 $, $Date: 2005-04-10 11:20:46 -0500 (Sun, 10 Apr 2005) $
+ */
+public interface ClusterValve {
+    /**
+     * Returns the cluster the cluster deployer is associated with
+     * @return CatalinaCluster
+     */
+    public CatalinaCluster getCluster();
+
+    /**
+     * Associates the cluster deployer with a cluster
+     * @param cluster CatalinaCluster
+     */
+    public void setCluster(CatalinaCluster cluster);
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/Constants.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/Constants.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/Constants.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,30 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.ha;
+
+/**
+ * Manifest constants for the <code>org.apache.catalina.ha</code>
+ * package.
+ *
+ * @author Bip Thelin
+ * @version $Revision: 302726 $, $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public final class Constants {
+    public static final String Package = "org.apache.catalina.ha";
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/LocalStrings.properties
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/LocalStrings.properties	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/LocalStrings.properties	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1 @@
+cluster.mbean.register.already=MBean {0} already registered!

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/context/ReplicatedContext.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/context/ReplicatedContext.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/context/ReplicatedContext.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,125 @@
+/*
+ * Copyright 1999,2004-2005 The Apache Software Foundation.
+ * 
+ * Licensed 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.ha.context;
+
+import org.apache.catalina.core.StandardContext;
+import org.apache.catalina.LifecycleException;
+import org.apache.catalina.ha.CatalinaCluster;
+import org.apache.catalina.tribes.tipis.ReplicatedMap;
+import org.apache.catalina.tribes.Channel;
+import org.apache.catalina.Loader;
+import org.apache.catalina.core.ApplicationContext;
+import org.apache.catalina.Globals;
+import javax.servlet.ServletContext;
+import java.util.HashMap;
+import org.apache.catalina.tribes.tipis.LazyReplicatedMap;
+
+/**
+ * @author Filip Hanik
+ * @version 1.0
+ */
+public class ReplicatedContext extends StandardContext {
+    private int mapSendOptions = Channel.SEND_OPTIONS_DEFAULT;
+    public static org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory.getLog( ReplicatedContext.class );
+
+    protected static long DEFAULT_REPL_TIMEOUT = 15000;//15 seconds
+    
+
+
+    public synchronized void start() throws LifecycleException {
+        if ( this.started ) return;
+        try {
+            CatalinaCluster catclust = (CatalinaCluster)this.getCluster();
+            if (this.context == null) this.context = new ReplApplContext(this.getBasePath(), this);
+            if ( catclust != null ) {
+                ReplicatedMap map = new ReplicatedMap(this,catclust.getChannel(),DEFAULT_REPL_TIMEOUT,
+                                                      getName(),getClassLoaders());
+                map.setChannelSendOptions(mapSendOptions);
+                ((ReplApplContext)this.context).setAttributeMap(map);
+                if (getAltDDName() != null) context.setAttribute(Globals.ALT_DD_ATTR, getAltDDName());
+            }
+            super.start();
+        }  catch ( Exception x ) {
+            log.error("Unable to start ReplicatedContext",x);
+            throw new LifecycleException("Failed to start ReplicatedContext",x);
+        }
+    }
+    
+    public synchronized void stop() throws LifecycleException
+    {
+        ReplicatedMap map = (ReplicatedMap)((ReplApplContext)this.context).getAttributeMap();
+        if ( map!=null ) {
+            map.breakdown();
+        }
+        if ( !this.started ) return;
+        try {
+        } catch ( Exception x ){
+            log.error("Unable to stop ReplicatedContext",x);
+            throw new LifecycleException("Failed to stop ReplicatedContext",x);
+        } finally {
+            super.stop();
+        }
+
+    }
+
+
+    public void setMapSendOptions(int mapSendOptions) {
+        this.mapSendOptions = mapSendOptions;
+    }
+
+    public int getMapSendOptions() {
+        return mapSendOptions;
+    }
+    
+    public ClassLoader[] getClassLoaders() {
+        Loader loader = null;
+        ClassLoader classLoader = null;
+        loader = this.getLoader();
+        if (loader != null) classLoader = loader.getClassLoader();
+        if ( classLoader == null ) classLoader = Thread.currentThread().getContextClassLoader();
+        if ( classLoader == Thread.currentThread().getContextClassLoader() ) {
+            return new ClassLoader[] {classLoader};
+        } else {
+            return new ClassLoader[] {classLoader,Thread.currentThread().getContextClassLoader()};
+        }
+    }
+    
+    public ServletContext getServletContext() {
+        return ((ReplApplContext)context).getFacade();
+
+    }
+
+    
+    protected static class ReplApplContext extends ApplicationContext {
+        public ReplApplContext(String basePath, StandardContext context) {
+            super(basePath,context);
+        }
+        
+         protected ServletContext getFacade() {
+             return super.getFacade();
+        }
+        
+        public HashMap getAttributeMap() {
+            return this.attributes;
+        }
+        public void setAttributeMap(HashMap map) {
+            this.attributes = map;
+        }
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/deploy/FarmWarDeployer.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/deploy/FarmWarDeployer.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/deploy/FarmWarDeployer.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,740 @@
+/*
+ * Copyright 1999,2004-2005 The Apache Software Foundation.
+ *
+ * Licensed 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.ha.deploy;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URL;
+import java.util.HashMap;
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+
+import org.apache.catalina.Context;
+import org.apache.catalina.Engine;
+import org.apache.catalina.Host;
+import org.apache.catalina.Lifecycle;
+import org.apache.catalina.LifecycleException;
+import org.apache.catalina.ha.CatalinaCluster;
+import org.apache.catalina.ha.ClusterDeployer;
+import org.apache.catalina.ha.ClusterListener;
+import org.apache.catalina.ha.ClusterMessage;
+import org.apache.catalina.tribes.Member;
+import org.apache.commons.modeler.Registry;
+
+/**
+ * <p>
+ * A farm war deployer is a class that is able to deploy/undeploy web
+ * applications in WAR form within the cluster.
+ * </p>
+ * Any host can act as the admin, and will have three directories
+ * <ul>
+ * <li>deployDir - the directory where we watch for changes</li>
+ * <li>applicationDir - the directory where we install applications</li>
+ * <li>tempDir - a temporaryDirectory to store binary data when downloading a
+ * war from the cluster</li>
+ * </ul>
+ * Currently we only support deployment of WAR files since they are easier to
+ * send across the wire.
+ * 
+ * @author Filip Hanik
+ * @author Peter Rossbach
+ * @version $Revision: 390639 $
+ */
+public class FarmWarDeployer extends ClusterListener implements ClusterDeployer, FileChangeListener {
+    /*--Static Variables----------------------------------------*/
+    public static org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory
+            .getLog(FarmWarDeployer.class);
+    /**
+     * The descriptive information about this implementation.
+     */
+    private static final String info = "FarmWarDeployer/1.2";
+
+    /*--Instance Variables--------------------------------------*/
+    protected CatalinaCluster cluster = null;
+
+    protected boolean started = false; //default 5 seconds
+
+    protected HashMap fileFactories = new HashMap();
+
+    protected String deployDir;
+
+    protected String tempDir;
+
+    protected String watchDir;
+
+    protected boolean watchEnabled = false;
+
+    protected WarWatcher watcher = null;
+
+    /**
+     * Iteration count for background processing.
+     */
+    private int count = 0;
+
+    /**
+     * Frequency of the Farm watchDir check. Cluster wide deployment will be
+     * done once for the specified amount of backgrondProcess calls (ie, the
+     * lower the amount, the most often the checks will occur).
+     */
+    protected int processDeployFrequency = 2;
+
+    /**
+     * Path where context descriptors should be deployed.
+     */
+    protected File configBase = null;
+
+    /**
+     * The associated host.
+     */
+    protected Host host = null;
+
+    /**
+     * The host appBase.
+     */
+    protected File appBase = null;
+
+    /**
+     * MBean server.
+     */
+    protected MBeanServer mBeanServer = null;
+
+    /**
+     * The associated deployer ObjectName.
+     */
+    protected ObjectName oname = null;
+
+    /*--Constructor---------------------------------------------*/
+    public FarmWarDeployer() {
+    }
+
+    /**
+     * Return descriptive information about this deployer implementation and the
+     * corresponding version number, in the format
+     * <code>&lt;description&gt;/&lt;version&gt;</code>.
+     */
+    public String getInfo() {
+
+        return (info);
+
+    }
+
+    /*--Logic---------------------------------------------------*/
+    public void start() throws Exception {
+        if (started)
+            return;
+        getCluster().addClusterListener(this);
+        if (watchEnabled) {
+            watcher = new WarWatcher(this, new File(getWatchDir()));
+            if (log.isInfoEnabled())
+                log.info("Cluster deployment is watching " + getWatchDir()
+                        + " for changes.");
+        }
+
+        // Check to correct engine and host setup
+        host = (Host) getCluster().getContainer();
+        Engine engine = (Engine) host.getParent();
+        try {
+            oname = new ObjectName(engine.getName() + ":type=Deployer,host="
+                    + host.getName());
+        } catch (Exception e) {
+            log.error("Can't construct MBean object name" + e);
+        }
+        configBase = new File(System.getProperty("catalina.base"), "conf");
+        if (engine != null) {
+            configBase = new File(configBase, engine.getName());
+        }
+        if (host != null) {
+            configBase = new File(configBase, host.getName());
+        }
+
+        // Retrieve the MBean server
+        mBeanServer = Registry.getRegistry(null, null).getMBeanServer();
+
+        started = true;
+        count = 0;
+        if (log.isInfoEnabled())
+            log.info("Cluster FarmWarDeployer started.");
+    }
+
+    /*
+     * stop cluster wide deployments
+     * 
+     * @see org.apache.catalina.cluster.ClusterDeployer#stop()
+     */
+    public void stop() throws LifecycleException {
+        started = false;
+        getCluster().removeClusterListener(this);
+        count = 0;
+        if (watcher != null) {
+            watcher.clear();
+            watcher = null;
+
+        }
+        if (log.isInfoEnabled())
+            log.info("Cluster FarmWarDeployer stopped.");
+    }
+
+    public void cleanDeployDir() {
+        throw new java.lang.UnsupportedOperationException(
+                "Method cleanDeployDir() not yet implemented.");
+    }
+
+    /**
+     * Callback from the cluster, when a message is received, The cluster will
+     * broadcast it invoking the messageReceived on the receiver.
+     * 
+     * @param msg
+     *            ClusterMessage - the message received from the cluster
+     */
+    public void messageReceived(ClusterMessage msg) {
+        try {
+            if (msg instanceof FileMessage && msg != null) {
+                FileMessage fmsg = (FileMessage) msg;
+                if (log.isDebugEnabled())
+                    log.debug("receive cluster deployment [ path: "
+                            + fmsg.getContextPath() + " war:  "
+                            + fmsg.getFileName() + " ]");
+                FileMessageFactory factory = getFactory(fmsg);
+                // TODO correct second try after app is in service!
+                if (factory.writeMessage(fmsg)) {
+                    //last message received war file is completed
+                    String name = factory.getFile().getName();
+                    if (!name.endsWith(".war"))
+                        name = name + ".war";
+                    File deployable = new File(getDeployDir(), name);
+                    try {
+                        String path = fmsg.getContextPath();
+                        if (!isServiced(path)) {
+                            addServiced(path);
+                            try {
+                                remove(path);
+                                factory.getFile().renameTo(deployable);
+                                check(path);
+                            } finally {
+                                removeServiced(path);
+                            }
+                            if (log.isDebugEnabled())
+                                log.debug("deployment from " + path
+                                        + " finished.");
+                        } else
+                            log.error("Application " + path
+                                    + " in used. touch war file " + name
+                                    + " again!");
+                    } catch (Exception ex) {
+                        log.error(ex);
+                    } finally {
+                        removeFactory(fmsg);
+                    }
+                }
+            } else if (msg instanceof UndeployMessage && msg != null) {
+                try {
+                    UndeployMessage umsg = (UndeployMessage) msg;
+                    String path = umsg.getContextPath();
+                    if (log.isDebugEnabled())
+                        log.debug("receive cluster undeployment from " + path);
+                    if (!isServiced(path)) {
+                        addServiced(path);
+                        try {
+                            remove(path);
+                        } finally {
+                            removeServiced(path);
+                        }
+                        if (log.isDebugEnabled())
+                            log.debug("undeployment from " + path
+                                    + " finished.");
+                    } else
+                        log.error("Application "
+                            + path
+                            + " in used. Sorry not remove from backup cluster nodes!");
+                } catch (Exception ex) {
+                    log.error(ex);
+                }
+            }
+        } catch (java.io.IOException x) {
+            log.error("Unable to read farm deploy file message.", x);
+        }
+    }
+
+    /**
+     * create factory for all transported war files
+     * 
+     * @param msg
+     * @return Factory for all app message (war files)
+     * @throws java.io.FileNotFoundException
+     * @throws java.io.IOException
+     */
+    public synchronized FileMessageFactory getFactory(FileMessage msg)
+            throws java.io.FileNotFoundException, java.io.IOException {
+        File tmpFile = new File(msg.getFileName());
+        File writeToFile = new File(getTempDir(), tmpFile.getName());
+        FileMessageFactory factory = (FileMessageFactory) fileFactories.get(msg
+                .getFileName());
+        if (factory == null) {
+            factory = FileMessageFactory.getInstance(writeToFile, true);
+            fileFactories.put(msg.getFileName(), factory);
+        }
+        return factory;
+    }
+
+    /**
+     * Remove file (war) from messages)
+     * 
+     * @param msg
+     */
+    public void removeFactory(FileMessage msg) {
+        fileFactories.remove(msg.getFileName());
+    }
+
+    /**
+     * Before the cluster invokes messageReceived the cluster will ask the
+     * receiver to accept or decline the message, In the future, when messages
+     * get big, the accept method will only take a message header
+     * 
+     * @param msg
+     *            ClusterMessage
+     * @return boolean - returns true to indicate that messageReceived should be
+     *         invoked. If false is returned, the messageReceived method will
+     *         not be invoked.
+     */
+    public boolean accept(ClusterMessage msg) {
+        return (msg instanceof FileMessage) || (msg instanceof UndeployMessage);
+    }
+
+    /**
+     * Install a new web application, whose web application archive is at the
+     * specified URL, into this container and all the other members of the
+     * cluster with the specified context path. A context path of "" (the empty
+     * string) should be used for the root application for this container.
+     * Otherwise, the context path must start with a slash.
+     * <p>
+     * If this application is successfully installed locally, a ContainerEvent
+     * of type <code>INSTALL_EVENT</code> will be sent to all registered
+     * listeners, with the newly created <code>Context</code> as an argument.
+     * 
+     * @param contextPath
+     *            The context path to which this application should be installed
+     *            (must be unique)
+     * @param war
+     *            A URL of type "jar:" that points to a WAR file, or type
+     *            "file:" that points to an unpacked directory structure
+     *            containing the web application to be installed
+     * 
+     * @exception IllegalArgumentException
+     *                if the specified context path is malformed (it must be ""
+     *                or start with a slash)
+     * @exception IllegalStateException
+     *                if the specified context path is already attached to an
+     *                existing web application
+     * @exception IOException
+     *                if an input/output error was encountered during
+     *                installation
+     */
+    public void install(String contextPath, URL war) throws IOException {
+        Member[] members = getCluster().getMembers();
+        Member localMember = getCluster().getLocalMember();
+        FileMessageFactory factory = FileMessageFactory.getInstance(new File(
+                war.getFile()), false);
+        FileMessage msg = new FileMessage(localMember, war.getFile(),
+                contextPath);
+        if(log.isDebugEnabled())
+            log.debug("Send cluster war deployment [ path:"
+                    + contextPath + " war: " + war + " ] started.");
+        msg = factory.readMessage(msg);
+        while (msg != null) {
+            for (int i = 0; i < members.length; i++) {
+                if (log.isDebugEnabled())
+                    log.debug("Send cluster war fragment [ path: "
+                            + contextPath + " war: " + war + " to: " +  members[i] + " ]");
+                getCluster().send(msg, members[i]);
+            }
+            msg = factory.readMessage(msg);
+        }
+        if(log.isDebugEnabled())
+            log.debug("Send cluster war deployment [ path: "
+                    + contextPath + " war: " + war + " ] finished.");
+    }
+
+    /**
+     * Remove an existing web application, attached to the specified context
+     * path. If this application is successfully removed, a ContainerEvent of
+     * type <code>REMOVE_EVENT</code> will be sent to all registered
+     * listeners, with the removed <code>Context</code> as an argument.
+     * Deletes the web application war file and/or directory if they exist in
+     * the Host's appBase.
+     * 
+     * @param contextPath
+     *            The context path of the application to be removed
+     * @param undeploy
+     *            boolean flag to remove web application from server
+     * 
+     * @exception IllegalArgumentException
+     *                if the specified context path is malformed (it must be ""
+     *                or start with a slash)
+     * @exception IllegalArgumentException
+     *                if the specified context path does not identify a
+     *                currently installed web application
+     * @exception IOException
+     *                if an input/output error occurs during removal
+     */
+    public void remove(String contextPath, boolean undeploy) throws IOException {
+        if (log.isInfoEnabled())
+            log.info("Cluster wide remove of web app " + contextPath);
+        Member localMember = getCluster().getLocalMember();
+        UndeployMessage msg = new UndeployMessage(localMember, System
+                .currentTimeMillis(), "Undeploy:" + contextPath + ":"
+                + System.currentTimeMillis(), contextPath, undeploy);
+        if (log.isDebugEnabled())
+            log.debug("Send cluster wide undeployment from "
+                    + contextPath );
+        cluster.send(msg);
+        // remove locally
+        if (undeploy) {
+            try {
+                if (!isServiced(contextPath)) {
+                    addServiced(contextPath);
+                    try {
+                        remove(contextPath);
+                    } finally {
+                        removeServiced(contextPath);
+                    }
+                } else
+                    log.error("Local remove from " + contextPath
+                            + "failed, other manager has app in service!");
+
+            } catch (Exception ex) {
+                log.error("local remove from " + contextPath + " failed", ex);
+            }
+        }
+
+    }
+
+    /*
+     * Modifcation from watchDir war detected!
+     * 
+     * @see org.apache.catalina.cluster.deploy.FileChangeListener#fileModified(java.io.File)
+     */
+    public void fileModified(File newWar) {
+        try {
+            File deployWar = new File(getDeployDir(), newWar.getName());
+            copy(newWar, deployWar);
+            String contextName = getContextName(deployWar);
+            if (log.isInfoEnabled())
+                log.info("Installing webapp[" + contextName + "] from "
+                        + deployWar.getAbsolutePath());
+            try {
+                remove(contextName, false);
+            } catch (Exception x) {
+                log.error("No removal", x);
+            }
+            install(contextName, deployWar.toURL());
+        } catch (Exception x) {
+            log.error("Unable to install WAR file", x);
+        }
+    }
+
+    /*
+     * War remvoe from watchDir
+     * 
+     * @see org.apache.catalina.cluster.deploy.FileChangeListener#fileRemoved(java.io.File)
+     */
+    public void fileRemoved(File removeWar) {
+        try {
+            String contextName = getContextName(removeWar);
+            if (log.isInfoEnabled())
+                log.info("Removing webapp[" + contextName + "]");
+            remove(contextName, true);
+        } catch (Exception x) {
+            log.error("Unable to remove WAR file", x);
+        }
+    }
+
+    /**
+     * Create a context path from war
+     * @param war War filename
+     * @return '/filename' or if war name is ROOT.war context name is empty string '' 
+     */
+    protected String getContextName(File war) {
+        String contextName = "/"
+        + war.getName().substring(0,
+                war.getName().lastIndexOf(".war"));
+        if("/ROOT".equals(contextName))
+            contextName= "" ;
+        return contextName ;
+    }
+    
+    /**
+     * Given a context path, get the config file name.
+     */
+    protected String getConfigFile(String path) {
+        String basename = null;
+        if (path.equals("")) {
+            basename = "ROOT";
+        } else {
+            basename = path.substring(1).replace('/', '#');
+        }
+        return (basename);
+    }
+
+    /**
+     * Given a context path, get the config file name.
+     */
+    protected String getDocBase(String path) {
+        String basename = null;
+        if (path.equals("")) {
+            basename = "ROOT";
+        } else {
+            basename = path.substring(1);
+        }
+        return (basename);
+    }
+
+    /**
+     * Return a File object representing the "application root" directory for
+     * our associated Host.
+     */
+    protected File getAppBase() {
+
+        if (appBase != null) {
+            return appBase;
+        }
+
+        File file = new File(host.getAppBase());
+        if (!file.isAbsolute())
+            file = new File(System.getProperty("catalina.base"), host
+                    .getAppBase());
+        try {
+            appBase = file.getCanonicalFile();
+        } catch (IOException e) {
+            appBase = file;
+        }
+        return (appBase);
+
+    }
+
+    /**
+     * Invoke the remove method on the deployer.
+     */
+    protected void remove(String path) throws Exception {
+        // TODO Handle remove also work dir content !
+        // Stop the context first to be nicer
+        Context context = (Context) host.findChild(path);
+        if (context != null) {
+            if(log.isDebugEnabled())
+                log.debug("Undeploy local context " +path );
+            ((Lifecycle) context).stop();
+            File war = new File(getAppBase(), getDocBase(path) + ".war");
+            File dir = new File(getAppBase(), getDocBase(path));
+            File xml = new File(configBase, getConfigFile(path) + ".xml");
+            if (war.exists()) {
+                war.delete();
+            } else if (dir.exists()) {
+                undeployDir(dir);
+            } else {
+                xml.delete();
+            }
+            // Perform new deployment and remove internal HostConfig state
+            check(path);
+        }
+
+    }
+
+    /**
+     * Delete the specified directory, including all of its contents and
+     * subdirectories recursively.
+     * 
+     * @param dir
+     *            File object representing the directory to be deleted
+     */
+    protected void undeployDir(File dir) {
+
+        String files[] = dir.list();
+        if (files == null) {
+            files = new String[0];
+        }
+        for (int i = 0; i < files.length; i++) {
+            File file = new File(dir, files[i]);
+            if (file.isDirectory()) {
+                undeployDir(file);
+            } else {
+                file.delete();
+            }
+        }
+        dir.delete();
+
+    }
+
+    /*
+     * Call watcher to check for deploy changes
+     * 
+     * @see org.apache.catalina.cluster.ClusterDeployer#backgroundProcess()
+     */
+    public void backgroundProcess() {
+        if (started) {
+            count = (count + 1) % processDeployFrequency;
+            if (count == 0 && watchEnabled) {
+                watcher.check();
+            }
+        }
+
+    }
+
+    /*--Deployer Operations ------------------------------------*/
+
+    /**
+     * Invoke the check method on the deployer.
+     */
+    protected void check(String name) throws Exception {
+        String[] params = { name };
+        String[] signature = { "java.lang.String" };
+        mBeanServer.invoke(oname, "check", params, signature);
+    }
+
+    /**
+     * Invoke the check method on the deployer.
+     */
+    protected boolean isServiced(String name) throws Exception {
+        String[] params = { name };
+        String[] signature = { "java.lang.String" };
+        Boolean result = (Boolean) mBeanServer.invoke(oname, "isServiced",
+                params, signature);
+        return result.booleanValue();
+    }
+
+    /**
+     * Invoke the check method on the deployer.
+     */
+    protected void addServiced(String name) throws Exception {
+        String[] params = { name };
+        String[] signature = { "java.lang.String" };
+        mBeanServer.invoke(oname, "addServiced", params, signature);
+    }
+
+    /**
+     * Invoke the check method on the deployer.
+     */
+    protected void removeServiced(String name) throws Exception {
+        String[] params = { name };
+        String[] signature = { "java.lang.String" };
+        mBeanServer.invoke(oname, "removeServiced", params, signature);
+    }
+
+    /*--Instance Getters/Setters--------------------------------*/
+    public CatalinaCluster getCluster() {
+        return cluster;
+    }
+
+    public void setCluster(CatalinaCluster cluster) {
+        this.cluster = cluster;
+    }
+
+    public boolean equals(Object listener) {
+        return super.equals(listener);
+    }
+
+    public int hashCode() {
+        return super.hashCode();
+    }
+
+    public String getDeployDir() {
+        return deployDir;
+    }
+
+    public void setDeployDir(String deployDir) {
+        this.deployDir = deployDir;
+    }
+
+    public String getTempDir() {
+        return tempDir;
+    }
+
+    public void setTempDir(String tempDir) {
+        this.tempDir = tempDir;
+    }
+
+    public String getWatchDir() {
+        return watchDir;
+    }
+
+    public void setWatchDir(String watchDir) {
+        this.watchDir = watchDir;
+    }
+
+    public boolean isWatchEnabled() {
+        return watchEnabled;
+    }
+
+    public boolean getWatchEnabled() {
+        return watchEnabled;
+    }
+
+    public void setWatchEnabled(boolean watchEnabled) {
+        this.watchEnabled = watchEnabled;
+    }
+
+    /**
+     * Return the frequency of watcher checks.
+     */
+    public int getProcessDeployFrequency() {
+
+        return (this.processDeployFrequency);
+
+    }
+
+    /**
+     * Set the watcher checks frequency.
+     * 
+     * @param processExpiresFrequency
+     *            the new manager checks frequency
+     */
+    public void setProcessDeployFrequency(int processExpiresFrequency) {
+
+        if (processExpiresFrequency <= 0) {
+            return;
+        }
+        this.processDeployFrequency = processExpiresFrequency;
+    }
+
+    /**
+     * Copy a file to the specified temp directory.
+     * @param from copy from temp
+     * @param to   to host appBase directory
+     * @return true, copy successful
+     */
+    protected boolean copy(File from, File to) {
+        try {
+            if (!to.exists())
+                to.createNewFile();
+            java.io.FileInputStream is = new java.io.FileInputStream(from);
+            java.io.FileOutputStream os = new java.io.FileOutputStream(to,
+                    false);
+            byte[] buf = new byte[4096];
+            while (true) {
+                int len = is.read(buf);
+                if (len < 0)
+                    break;
+                os.write(buf, 0, len);
+            }
+            is.close();
+            os.close();
+        } catch (IOException e) {
+            log.error("Unable to copy file from:" + from + " to:" + to, e);
+            return false;
+        }
+        return true;
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/deploy/FileChangeListener.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/deploy/FileChangeListener.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/deploy/FileChangeListener.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,23 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.ha.deploy;
+import java.io.File;
+
+public interface FileChangeListener {
+    public void fileModified(File f);
+    public void fileRemoved(File f);
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/deploy/FileMessage.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/deploy/FileMessage.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/deploy/FileMessage.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,112 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.ha.deploy;
+
+import java.io.Serializable;
+
+import org.apache.catalina.ha.ClusterMessage;
+import org.apache.catalina.tribes.Member;
+import org.apache.catalina.ha.ClusterMessageBase;
+
+/**
+ * Contains the data for a file being transferred over TCP, this is 
+ * essentially a fragment of a file, read and written by the FileMessageFactory
+ * @author Filip Hanik
+ * @version 1.0
+ */
+
+public class FileMessage extends ClusterMessageBase implements ClusterMessage, Serializable {
+    private int messageNumber;
+    private byte[] data;
+    private int dataLength;
+    
+    private long totalLength;
+    private long totalNrOfMsgs;
+    private String fileName;
+    private String contextPath;
+    
+    public FileMessage(Member source,
+                       String fileName,
+                       String contextPath) {
+        this.address=source;
+        this.fileName=fileName;
+        this.contextPath=contextPath;
+    }
+    
+    /*
+    public void writeExternal(ObjectOutput out) throws IOException {
+                   
+    }
+    
+    public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
+                  
+    }
+    */
+   
+    public int getMessageNumber() {
+        return messageNumber;
+    }
+    public void setMessageNumber(int messageNumber) {
+        this.messageNumber = messageNumber;
+    }
+    public long getTotalNrOfMsgs() {
+        return totalNrOfMsgs;
+    }
+    public void setTotalNrOfMsgs(long totalNrOfMsgs) {
+        this.totalNrOfMsgs = totalNrOfMsgs;
+    }
+    public byte[] getData() {
+        return data;
+    }
+    public void setData(byte[] data, int length) {
+        this.data = data;
+        this.dataLength = length;
+    }
+    public int getDataLength() {
+        return dataLength;
+    }
+    public void setDataLength(int dataLength) {
+        this.dataLength = dataLength;
+    }
+    public long getTotalLength() {
+        return totalLength;
+    }
+    public void setTotalLength(long totalLength) {
+        this.totalLength = totalLength;
+    }
+
+    public String getUniqueId() {
+        StringBuffer result = new StringBuffer(getFileName());
+        result.append("#-#");
+        result.append(getMessageNumber());
+        result.append("#-#");
+        result.append(System.currentTimeMillis());
+        return result.toString();
+    }
+
+    
+    public String getFileName() {
+        return fileName;
+    }
+    public void setFileName(String fileName) {
+        this.fileName = fileName;
+    }
+    public String getContextPath() {
+        return contextPath;
+    }
+    
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/deploy/FileMessageFactory.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/deploy/FileMessageFactory.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/deploy/FileMessageFactory.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,311 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.ha.deploy;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.FileNotFoundException;
+
+/**
+ * This factory is used to read files and write files by splitting them up into
+ * smaller messages. So that entire files don't have to be read into memory.
+ * <BR>
+ * The factory can be used as a reader or writer but not both at the same time.
+ * When done reading or writing the factory will close the input or output
+ * streams and mark the factory as closed. It is not possible to use it after
+ * that. <BR>
+ * To force a cleanup, call cleanup() from the calling object. <BR>
+ * This class is not thread safe.
+ * 
+ * @author Filip Hanik
+ * @version 1.0
+ */
+public class FileMessageFactory {
+    /*--Static Variables----------------------------------------*/
+    public static org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory
+            .getLog(FileMessageFactory.class);
+
+    /**
+     * The number of bytes that we read from file
+     */
+    public static final int READ_SIZE = 1024 * 10; //10kb
+
+    /**
+     * The file that we are reading/writing
+     */
+    protected File file = null;
+
+    /**
+     * True means that we are writing with this factory. False means that we are
+     * reading with this factory
+     */
+    protected boolean openForWrite;
+
+    /**
+     * Once the factory is used, it can not be reused.
+     */
+    protected boolean closed = false;
+
+    /**
+     * When openForWrite=false, the input stream is held by this variable
+     */
+    protected FileInputStream in;
+
+    /**
+     * When openForWrite=true, the output stream is held by this variable
+     */
+    protected FileOutputStream out;
+
+    /**
+     * The number of messages we have read or written
+     */
+    protected int nrOfMessagesProcessed = 0;
+
+    /**
+     * The total size of the file
+     */
+    protected long size = 0;
+
+    /**
+     * The total number of packets that we split this file into
+     */
+    protected long totalNrOfMessages = 0;
+
+    /**
+     * The bytes that we hold the data in, not thread safe.
+     */
+    protected byte[] data = new byte[READ_SIZE];
+
+    /**
+     * Private constructor, either instantiates a factory to read or write. <BR>
+     * When openForWrite==true, then a the file, f, will be created and an
+     * output stream is opened to write to it. <BR>
+     * When openForWrite==false, an input stream is opened, the file has to
+     * exist.
+     * 
+     * @param f
+     *            File - the file to be read/written
+     * @param openForWrite
+     *            boolean - true means we are writing to the file, false means
+     *            we are reading from the file
+     * @throws FileNotFoundException -
+     *             if the file to be read doesn't exist
+     * @throws IOException -
+     *             if the system fails to open input/output streams to the file
+     *             or if it fails to create the file to be written to.
+     */
+    private FileMessageFactory(File f, boolean openForWrite)
+            throws FileNotFoundException, IOException {
+        this.file = f;
+        this.openForWrite = openForWrite;
+        if (log.isDebugEnabled())
+            log.debug("open file " + f + " write " + openForWrite);
+        if (openForWrite) {
+            if (!file.exists())
+                file.createNewFile();
+            out = new FileOutputStream(f);
+        } else {
+            size = file.length();
+            totalNrOfMessages = (size / READ_SIZE) + 1;
+            in = new FileInputStream(f);
+        }//end if
+
+    }
+
+    /**
+     * Creates a factory to read or write from a file. When opening for read,
+     * the readMessage can be invoked, and when opening for write the
+     * writeMessage can be invoked.
+     * 
+     * @param f
+     *            File - the file to be read or written
+     * @param openForWrite
+     *            boolean - true, means we are writing to the file, false means
+     *            we are reading from it
+     * @throws FileNotFoundException -
+     *             if the file to be read doesn't exist
+     * @throws IOException -
+     *             if it fails to create the file that is to be written
+     * @return FileMessageFactory
+     */
+    public static FileMessageFactory getInstance(File f, boolean openForWrite)
+            throws FileNotFoundException, IOException {
+        return new FileMessageFactory(f, openForWrite);
+    }
+
+    /**
+     * Reads file data into the file message and sets the size, totalLength,
+     * totalNrOfMsgs and the message number <BR>
+     * If EOF is reached, the factory returns null, and closes itself, otherwise
+     * the same message is returned as was passed in. This makes sure that not
+     * more memory is ever used. To remember, neither the file message or the
+     * factory are thread safe. dont hand off the message to one thread and read
+     * the same with another.
+     * 
+     * @param f
+     *            FileMessage - the message to be populated with file data
+     * @throws IllegalArgumentException -
+     *             if the factory is for writing or is closed
+     * @throws IOException -
+     *             if a file read exception occurs
+     * @return FileMessage - returns the same message passed in as a parameter,
+     *         or null if EOF
+     */
+    public FileMessage readMessage(FileMessage f)
+            throws IllegalArgumentException, IOException {
+        checkState(false);
+        int length = in.read(data);
+        if (length == -1) {
+            cleanup();
+            return null;
+        } else {
+            f.setData(data, length);
+            f.setTotalLength(size);
+            f.setTotalNrOfMsgs(totalNrOfMessages);
+            f.setMessageNumber(++nrOfMessagesProcessed);
+            return f;
+        }//end if
+    }
+
+    /**
+     * Writes a message to file. If (msg.getMessageNumber() ==
+     * msg.getTotalNrOfMsgs()) the output stream will be closed after writing.
+     * 
+     * @param msg
+     *            FileMessage - message containing data to be written
+     * @throws IllegalArgumentException -
+     *             if the factory is opened for read or closed
+     * @throws IOException -
+     *             if a file write error occurs
+     * @return returns true if the file is complete and outputstream is closed,
+     *         false otherwise.
+     */
+    public boolean writeMessage(FileMessage msg)
+            throws IllegalArgumentException, IOException {
+        if (!openForWrite)
+            throw new IllegalArgumentException(
+                    "Can't write message, this factory is reading.");
+        if (log.isDebugEnabled())
+            log.debug("Message " + msg + " data " + msg.getData()
+                    + " data length " + msg.getDataLength() + " out " + out);
+        if (out != null) {
+            out.write(msg.getData(), 0, msg.getDataLength());
+            nrOfMessagesProcessed++;
+            out.flush();
+            if (msg.getMessageNumber() == msg.getTotalNrOfMsgs()) {
+                out.close();
+                cleanup();
+                return true;
+            }//end if
+        } else {
+            if (log.isWarnEnabled())
+                log.warn("Receive Message again -- Sender ActTimeout to short [ path: "
+                                + msg.getContextPath()
+                                + " war: "
+                                + msg.getFileName()
+                                + " data: "
+                                + msg.getData()
+                                + " data length: " + msg.getDataLength() + " ]");
+        }
+        return false;
+    }//writeMessage
+
+    /**
+     * Closes the factory, its streams and sets all its references to null
+     */
+    public void cleanup() {
+        if (in != null)
+            try {
+                in.close();
+            } catch (Exception ignore) {
+            }
+        if (out != null)
+            try {
+                out.close();
+            } catch (Exception ignore) {
+            }
+        in = null;
+        out = null;
+        size = 0;
+        closed = true;
+        data = null;
+        nrOfMessagesProcessed = 0;
+        totalNrOfMessages = 0;
+    }
+
+    /**
+     * Check to make sure the factory is able to perform the function it is
+     * asked to do. Invoked by readMessage/writeMessage before those methods
+     * proceed.
+     * 
+     * @param openForWrite
+     *            boolean
+     * @throws IllegalArgumentException
+     */
+    protected void checkState(boolean openForWrite)
+            throws IllegalArgumentException {
+        if (this.openForWrite != openForWrite) {
+            cleanup();
+            if (openForWrite)
+                throw new IllegalArgumentException(
+                        "Can't write message, this factory is reading.");
+            else
+                throw new IllegalArgumentException(
+                        "Can't read message, this factory is writing.");
+        }
+        if (this.closed) {
+            cleanup();
+            throw new IllegalArgumentException("Factory has been closed.");
+        }
+    }
+
+    /**
+     * Example usage.
+     * 
+     * @param args
+     *            String[], args[0] - read from filename, args[1] write to
+     *            filename
+     * @throws Exception
+     */
+    public static void main(String[] args) throws Exception {
+
+        System.out
+                .println("Usage: FileMessageFactory fileToBeRead fileToBeWritten");
+        System.out
+                .println("Usage: This will make a copy of the file on the local file system");
+        FileMessageFactory read = getInstance(new File(args[0]), false);
+        FileMessageFactory write = getInstance(new File(args[1]), true);
+        FileMessage msg = new FileMessage(null, args[0], args[0]);
+        msg = read.readMessage(msg);
+        System.out.println("Expecting to write " + msg.getTotalNrOfMsgs()
+                + " messages.");
+        int cnt = 0;
+        while (msg != null) {
+            write.writeMessage(msg);
+            cnt++;
+            msg = read.readMessage(msg);
+        }//while
+        System.out.println("Actually wrote " + cnt + " messages.");
+    }///main
+
+    public File getFile() {
+        return file;
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/deploy/UndeployMessage.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/deploy/UndeployMessage.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/deploy/UndeployMessage.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,113 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ *
+ * Licensed 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.ha.deploy;
+
+import org.apache.catalina.ha.ClusterMessage;
+import org.apache.catalina.tribes.Member;
+import java.io.Serializable;
+public class UndeployMessage implements ClusterMessage,Serializable {
+    private Member address;
+    private long timestamp;
+    private String uniqueId;
+    private String contextPath;
+    private boolean undeploy;
+    private int resend = 0;
+    private int compress = 0;
+
+    public UndeployMessage() {} //for serialization
+    public UndeployMessage(Member address,
+                           long timestamp,
+                           String uniqueId,
+                           String contextPath,
+                           boolean undeploy) {
+        this.address  = address;
+        this.timestamp= timestamp;
+        this.undeploy = undeploy;
+        this.uniqueId = uniqueId;
+        this.undeploy = undeploy;
+        this.contextPath = contextPath;
+    }
+
+    public Member getAddress() {
+        return address;
+    }
+
+    public void setAddress(Member address) {
+        this.address = address;
+    }
+
+    public long getTimestamp() {
+        return timestamp;
+    }
+
+    public void setTimestamp(long timestamp) {
+        this.timestamp = timestamp;
+    }
+
+    public String getUniqueId() {
+        return uniqueId;
+    }
+
+    public void setUniqueId(String uniqueId) {
+        this.uniqueId = uniqueId;
+    }
+
+    public String getContextPath() {
+        return contextPath;
+    }
+
+    public void setContextPath(String contextPath) {
+        this.contextPath = contextPath;
+    }
+
+    public boolean getUndeploy() {
+        return undeploy;
+    }
+
+    public void setUndeploy(boolean undeploy) {
+        this.undeploy = undeploy;
+    }
+    /**
+     * @return Returns the compress.
+     * @since 5.5.10 
+     */
+    public int getCompress() {
+        return compress;
+    }
+    /**
+     * @param compress The compress to set.
+     * @since 5.5.10
+     */
+    public void setCompress(int compress) {
+        this.compress = compress;
+    }
+    /**
+     * @return Returns the resend.
+     * @since 5.5.10
+     */
+    public int getResend() {
+        return resend;
+    }
+    /**
+     * @param resend The resend to set.
+     * @since 5.5.10
+     */
+    public void setResend(int resend) {
+        this.resend = resend;
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/deploy/WarWatcher.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/deploy/WarWatcher.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/deploy/WarWatcher.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,238 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.ha.deploy;
+
+import java.io.File;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Iterator;
+
+/**
+ * <p>
+ * The <b>WarWatcher </b> watches the deployDir for changes made to the
+ * directory (adding new WAR files->deploy or remove WAR files->undeploy) And
+ * notifies a listener of the changes made
+ * </p>
+ * 
+ * @author Filip Hanik
+ * @author Peter Rossbach
+ * @version 1.1
+ */
+
+public class WarWatcher {
+
+    /*--Static Variables----------------------------------------*/
+    public static org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory
+            .getLog(WarWatcher.class);
+
+    /*--Instance Variables--------------------------------------*/
+    /**
+     * Directory to watch for war files
+     */
+    protected File watchDir = null;
+
+    /**
+     * Parent to be notified of changes
+     */
+    protected FileChangeListener listener = null;
+
+    /**
+     * Currently deployed files
+     */
+    protected Map currentStatus = new HashMap();
+
+    /*--Constructor---------------------------------------------*/
+
+    public WarWatcher() {
+    }
+
+    public WarWatcher(FileChangeListener listener, File watchDir) {
+        this.listener = listener;
+        this.watchDir = watchDir;
+    }
+
+    /*--Logic---------------------------------------------------*/
+
+    /**
+     * check for modification and send notifcation to listener
+     */
+    public void check() {
+        if (log.isInfoEnabled())
+            log.info("check cluster wars at " + watchDir);
+        File[] list = watchDir.listFiles(new WarFilter());
+        if (list == null)
+            list = new File[0];
+        //first make sure all the files are listed in our current status
+        for (int i = 0; i < list.length; i++) {
+            addWarInfo(list[i]);
+        }
+
+        //check all the status codes and update the FarmDeployer
+        for (Iterator i = currentStatus.entrySet().iterator(); i.hasNext();) {
+            Map.Entry entry = (Map.Entry) i.next();
+            WarInfo info = (WarInfo) entry.getValue();
+            int check = info.check();
+            if (check == 1) {
+                listener.fileModified(info.getWar());
+            } else if (check == -1) {
+                listener.fileRemoved(info.getWar());
+                //no need to keep in memory
+                currentStatus.remove(info.getWar());
+            }
+        }
+
+    }
+
+    /**
+     * add cluster war to the watcher state
+     * @param warfile
+     */
+    protected void addWarInfo(File warfile) {
+        WarInfo info = (WarInfo) currentStatus.get(warfile.getAbsolutePath());
+        if (info == null) {
+            info = new WarInfo(warfile);
+            info.setLastState(-1); //assume file is non existent
+            currentStatus.put(warfile.getAbsolutePath(), info);
+        }
+    }
+
+    /**
+     * clear watcher state
+     */
+    public void clear() {
+        currentStatus.clear();
+    }
+
+    /**
+     * @return Returns the watchDir.
+     */
+    public File getWatchDir() {
+        return watchDir;
+    }
+
+    /**
+     * @param watchDir
+     *            The watchDir to set.
+     */
+    public void setWatchDir(File watchDir) {
+        this.watchDir = watchDir;
+    }
+
+    /**
+     * @return Returns the listener.
+     */
+    public FileChangeListener getListener() {
+        return listener;
+    }
+
+    /**
+     * @param listener
+     *            The listener to set.
+     */
+    public void setListener(FileChangeListener listener) {
+        this.listener = listener;
+    }
+
+    /*--Inner classes-------------------------------------------*/
+
+    /**
+     * File name filter for war files
+     */
+    protected class WarFilter implements java.io.FilenameFilter {
+        public boolean accept(File path, String name) {
+            if (name == null)
+                return false;
+            return name.endsWith(".war");
+        }
+    }
+
+    /**
+     * File information on existing WAR files
+     */
+    protected class WarInfo {
+        protected File war = null;
+
+        protected long lastChecked = 0;
+
+        protected long lastState = 0;
+
+        public WarInfo(File war) {
+            this.war = war;
+            this.lastChecked = war.lastModified();
+            if (!war.exists())
+                lastState = -1;
+        }
+
+        public boolean modified() {
+            return war.exists() && war.lastModified() > lastChecked;
+        }
+
+        public boolean exists() {
+            return war.exists();
+        }
+
+        /**
+         * Returns 1 if the file has been added/modified, 0 if the file is
+         * unchanged and -1 if the file has been removed
+         * 
+         * @return int 1=file added; 0=unchanged; -1=file removed
+         */
+        public int check() {
+            //file unchanged by default
+            int result = 0;
+
+            if (modified()) {
+                //file has changed - timestamp
+                result = 1;
+                lastState = result;
+            } else if ((!exists()) && (!(lastState == -1))) {
+                //file was removed
+                result = -1;
+                lastState = result;
+            } else if ((lastState == -1) && exists()) {
+                //file was added
+                result = 1;
+                lastState = result;
+            }
+            this.lastChecked = System.currentTimeMillis();
+            return result;
+        }
+
+        public File getWar() {
+            return war;
+        }
+
+        public int hashCode() {
+            return war.getAbsolutePath().hashCode();
+        }
+
+        public boolean equals(Object other) {
+            if (other instanceof WarInfo) {
+                WarInfo wo = (WarInfo) other;
+                return wo.getWar().equals(getWar());
+            } else {
+                return false;
+            }
+        }
+
+        protected void setLastState(int lastState) {
+            this.lastState = lastState;
+        }
+
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/mbeans-descriptors.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/mbeans-descriptors.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/mbeans-descriptors.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,94 @@
+<?xml version="1.0"?>
+<mbeans-descriptors>
+
+  <mbean         name="SimpleTcpCluster"
+            className="org.apache.catalina.mbeans.ClassNameMBean"
+          description="Tcp Cluster implementation"
+               domain="Catalina"
+                group="Cluster"
+                 type="org.apache.catalina.ha.tcp.SimpleTcpCluster">
+
+    <attribute   name="protocolStack"
+          description="JavaGroups protocol stack selection"
+                 type="java.lang.String"/>
+
+  </mbean>
+
+
+  <mbean         name="SimpleTcpReplicationManager"
+            className="org.apache.catalina.mbeans.ClassNameMBean"
+          description="Clustered implementation of the Manager interface"
+               domain="Catalina"
+                group="Manager"
+                 type="org.apache.catalina.ha.tcp.SimpleTcpReplicationManager">
+
+    <attribute   name="algorithm"
+          description="The message digest algorithm to be used when generating
+                       session identifiers"
+                 type="java.lang.String"/>
+
+    <attribute   name="checkInterval"
+          description="The interval (in seconds) between checks for expired
+                       sessions"
+                 type="int"/>
+
+    <attribute   name="className"
+          description="Fully qualified class name of the managed object"
+                 type="java.lang.String"
+            writeable="false"/>
+
+    <attribute   name="distributable"
+          description="The distributable flag for Sessions created by this
+                       Manager"
+                 type="boolean"/>
+
+    <attribute   name="entropy"
+          description="A String initialization parameter used to increase the
+                       entropy of the initialization of our random number
+                       generator"
+                 type="java.lang.String"/>
+
+    <attribute   name="managedResource"
+          description="The managed resource this MBean is associated with"
+                 type="java.lang.Object"/>
+
+    <attribute   name="maxActiveSessions"
+          description="The maximum number of active Sessions allowed, or -1
+                       for no limit"
+                 type="int"/>
+
+    <attribute   name="maxInactiveInterval"
+          description="The default maximum inactive interval for Sessions
+                       created by this Manager"
+                 type="int"/>
+
+    <attribute   name="name"
+          description="The descriptive name of this Manager implementation
+                       (for logging)"
+                 type="java.lang.String"
+            writeable="false"/>
+
+  </mbean>
+
+
+
+<mbean         name="ReplicationValve"
+            className="org.apache.catalina.mbeans.ClassNameMBean"
+          description="Valve for simple tcp replication"
+               domain="Catalina"
+                group="Valve"
+                 type="org.apache.catalina.ha.tcp.ReplicationValve">
+
+    <attribute   name="className"
+          description="Fully qualified class name of the managed object"
+                 type="java.lang.String"
+            writeable="false"/>
+
+    <attribute   name="debug"
+          description="The debugging detail level for this component"
+                 type="int"/>
+
+  </mbean>
+
+
+</mbeans-descriptors>

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/package.html
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/package.html	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/package.html	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,11 @@
+<body>
+
+<p>This package contains code for Clustering, the base class
+of a Cluster is <code>org.apache.catalina.Cluster</code> implementations
+of this class is done when implementing a new Cluster protocol</p>
+
+<p>The only Cluster protocol currently implemented is a JavaGroups based<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<b>JGCluster.java</b>
+</p>
+
+</body>

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/session/BackupManager.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/session/BackupManager.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/session/BackupManager.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,271 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.ha.session;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+
+import org.apache.catalina.LifecycleException;
+import org.apache.catalina.Loader;
+import org.apache.catalina.Session;
+import org.apache.catalina.ha.CatalinaCluster;
+import org.apache.catalina.ha.ClusterManager;
+import org.apache.catalina.ha.ClusterMessage;
+import org.apache.catalina.session.StandardManager;
+import org.apache.catalina.tribes.Member;
+import org.apache.catalina.tribes.io.ReplicationStream;
+import org.apache.catalina.tribes.tipis.LazyReplicatedMap;
+import org.apache.catalina.tribes.Channel;
+
+/**
+ *@author Filip Hanik
+ *@version 1.0
+ */
+public class BackupManager extends StandardManager implements ClusterManager
+{
+    public static org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory.getLog( BackupManager.class );
+
+    protected static long DEFAULT_REPL_TIMEOUT = 15000;//15 seconds
+
+    /** Set to true if we don't want the sessions to expire on shutdown */
+    protected boolean mExpireSessionsOnShutdown = true;
+    
+    /**
+     * The name of this manager
+     */
+    protected String name;
+
+    /**
+     * A reference to the cluster
+     */
+    protected CatalinaCluster cluster;
+    
+    /**
+     * Should listeners be notified?
+     */
+    private boolean notifyListenersOnReplication;
+    /**
+     * 
+     */
+    private int mapSendOptions = Channel.SEND_OPTIONS_SYNCHRONIZED_ACK|Channel.SEND_OPTIONS_USE_ACK;
+
+    /**
+     * Constructor, just calls super()
+     *
+     */
+    public BackupManager() {
+        super();
+    }
+
+
+//******************************************************************************/
+//      ClusterManager Interface     
+//******************************************************************************/
+
+    public void messageDataReceived(ClusterMessage msg) {
+    }
+
+    public boolean isSendClusterDomainOnly() {
+        return false;
+    }
+
+    /**
+     * @param sendClusterDomainOnly The sendClusterDomainOnly to set.
+     */
+    public void setSendClusterDomainOnly(boolean sendClusterDomainOnly) {
+    }
+
+    /**
+     * @return Returns the defaultMode.
+     */
+    public boolean isDefaultMode() {
+        return false;
+    }
+    /**
+     * @param defaultMode The defaultMode to set.
+     */
+    public void setDefaultMode(boolean defaultMode) {
+    }
+
+    public void setExpireSessionsOnShutdown(boolean expireSessionsOnShutdown)
+    {
+        mExpireSessionsOnShutdown = expireSessionsOnShutdown;
+    }
+
+    public void setCluster(CatalinaCluster cluster) {
+        if(log.isDebugEnabled())
+            log.debug("Cluster associated with SimpleTcpReplicationManager");
+        this.cluster = cluster;
+    }
+
+    public boolean getExpireSessionsOnShutdown()
+    {
+        return mExpireSessionsOnShutdown;
+    }
+
+
+    /**
+     * Override persistence since they don't go hand in hand with replication for now.
+     */
+    public void unload() throws IOException {
+    }
+    
+    public ClusterMessage requestCompleted(String sessionId) {
+        if ( !this.started ) return null;
+        LazyReplicatedMap map = (LazyReplicatedMap)sessions;
+        map.replicate(sessionId,false);
+        return null;
+    }
+
+
+//=========================================================================
+// OVERRIDE THESE METHODS TO IMPLEMENT THE REPLICATION
+//=========================================================================
+
+    public Session createEmptySession() {
+        return new DeltaSession(this);
+    }
+    
+    public ClassLoader[] getClassLoaders() {
+        return ClusterManagerBase.getClassLoaders(this.container);
+    }
+
+    /**
+     * Open Stream and use correct ClassLoader (Container) Switch
+     * ThreadClassLoader
+     * 
+     * @param data
+     * @return The object input stream
+     * @throws IOException
+     */
+    public ReplicationStream getReplicationStream(byte[] data) throws IOException {
+        return getReplicationStream(data,0,data.length);
+    }
+
+    public ReplicationStream getReplicationStream(byte[] data, int offset, int length) throws IOException {
+        ByteArrayInputStream fis = new ByteArrayInputStream(data, offset, length);
+        return new ReplicationStream(fis, getClassLoaders());
+    }    
+
+
+
+
+    public String getName() {
+        return this.name;
+    }
+    /**
+     * Prepare for the beginning of active use of the public methods of this
+     * component.  This method should be called after <code>configure()</code>,
+     * and before any of the public methods of the component are utilized.<BR>
+     * Starts the cluster communication channel, this will connect with the other nodes
+     * in the cluster, and request the current session state to be transferred to this node.
+     * @exception IllegalStateException if this component has already been
+     *  started
+     * @exception LifecycleException if this component detects a fatal error
+     *  that prevents this component from being used
+     */
+    public void start() throws LifecycleException {
+        if ( this.started ) return;
+        try {
+            CatalinaCluster catclust = (CatalinaCluster)cluster;
+            catclust.addManager(getName(), this);
+            LazyReplicatedMap map = new LazyReplicatedMap(this,
+                                                          catclust.getChannel(),
+                                                          DEFAULT_REPL_TIMEOUT,
+                                                          getMapName(),
+                                                          getClassLoaders());
+            map.setChannelSendOptions(mapSendOptions);
+            this.sessions = map;
+            super.start();
+        }  catch ( Exception x ) {
+            log.error("Unable to start BackupManager",x);
+            throw new LifecycleException("Failed to start BackupManager",x);
+        }
+    }
+    
+    public String getMapName() {
+        CatalinaCluster catclust = (CatalinaCluster)cluster;
+        String name = catclust.getManagerName(getName(),this)+"-"+"";
+        if ( log.isDebugEnabled() ) log.debug("Backup manager, Setting map name to:"+name);
+        return name;
+    }
+
+    /**
+     * Gracefully terminate the active use of the public methods of this
+     * component.  This method should be the last one called on a given
+     * instance of this component.<BR>
+     * This will disconnect the cluster communication channel and stop the listener thread.
+     * @exception IllegalStateException if this component has not been started
+     * @exception LifecycleException if this component detects a fatal error
+     *  that needs to be reported
+     */
+    public void stop() throws LifecycleException
+    {
+        
+        LazyReplicatedMap map = (LazyReplicatedMap)sessions;
+        if ( map!=null ) {
+            map.breakdown();
+        }
+        if ( !this.started ) return;
+        try {
+        } catch ( Exception x ){
+            log.error("Unable to stop BackupManager",x);
+            throw new LifecycleException("Failed to stop BackupManager",x);
+        } finally {
+            super.stop();
+        }
+        cluster.removeManager(getName(),this);
+
+    }
+
+    public void setDistributable(boolean dist) {
+        this.distributable = dist;
+    }
+
+    public boolean getDistributable() {
+        return distributable;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+    public boolean isNotifyListenersOnReplication() {
+        return notifyListenersOnReplication;
+    }
+    public void setNotifyListenersOnReplication(boolean notifyListenersOnReplication) {
+        this.notifyListenersOnReplication = notifyListenersOnReplication;
+    }
+
+    public void setMapSendOptions(int mapSendOptions) {
+        this.mapSendOptions = mapSendOptions;
+    }
+
+    /* 
+     * @see org.apache.catalina.ha.ClusterManager#getCluster()
+     */
+    public CatalinaCluster getCluster() {
+        return cluster;
+    }
+
+    public int getMapSendOptions() {
+        return mapSendOptions;
+    }
+
+    public String[] getInvalidatedSessions() {
+        return new String[0];
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/session/ClusterManagerBase.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/session/ClusterManagerBase.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/session/ClusterManagerBase.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,74 @@
+/*
+ * Copyright 1999,2004-2005 The Apache Software Foundation.
+ * 
+ * Licensed 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.ha.session;
+
+import org.apache.catalina.ha.ClusterManager;
+import java.beans.PropertyChangeListener;
+import org.apache.catalina.Lifecycle;
+import org.apache.catalina.session.ManagerBase;
+import org.apache.catalina.Loader;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import org.apache.catalina.tribes.io.ReplicationStream;
+import org.apache.catalina.Container;
+
+/**
+ * 
+ * @author Filip Hanik
+ * @version $Revision: 380100 $ $Date: 2006-02-23 06:08:14 -0600 (Thu, 23 Feb 2006) $
+ */
+
+public abstract class ClusterManagerBase extends ManagerBase implements Lifecycle, PropertyChangeListener, ClusterManager{
+    
+
+    public static ClassLoader[] getClassLoaders(Container container) {
+        Loader loader = null;
+        ClassLoader classLoader = null;
+        if (container != null) loader = container.getLoader();
+        if (loader != null) classLoader = loader.getClassLoader();
+        else classLoader = Thread.currentThread().getContextClassLoader();
+        if ( classLoader == Thread.currentThread().getContextClassLoader() ) {
+            return new ClassLoader[] {classLoader};
+        } else {
+            return new ClassLoader[] {classLoader,Thread.currentThread().getContextClassLoader()};
+        }
+    }
+
+
+    public ClassLoader[] getClassLoaders() {
+        return getClassLoaders(container);
+    }
+
+    /**
+     * Open Stream and use correct ClassLoader (Container) Switch
+     * ThreadClassLoader
+     * 
+     * @param data
+     * @return The object input stream
+     * @throws IOException
+     */
+    public ReplicationStream getReplicationStream(byte[] data) throws IOException {
+        return getReplicationStream(data,0,data.length);
+    }
+
+    public ReplicationStream getReplicationStream(byte[] data, int offset, int length) throws IOException {
+        ByteArrayInputStream fis = new ByteArrayInputStream(data, offset, length);
+        return new ReplicationStream(fis, getClassLoaders());
+    }    
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/session/ClusterSessionListener.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/session/ClusterSessionListener.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/session/ClusterSessionListener.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,107 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ *
+ * Licensed 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.ha.session;
+
+import java.util.Map;
+
+import org.apache.catalina.ha.ClusterManager;
+import org.apache.catalina.ha.ClusterMessage;
+import org.apache.catalina.ha.*;
+
+/**
+ * Receive replicated SessionMessage form other cluster node.
+ * @author Filip Hanik
+ * @author Peter Rossbach
+ * @version $Revision: 378258 $ $Date: 2006-02-16 08:42:35 -0600 (Thu, 16 Feb 2006) $
+ */
+public class ClusterSessionListener extends ClusterListener {
+ 
+    /**
+     * The descriptive information about this implementation.
+     */
+    protected static final String info = "org.apache.catalina.session.ClusterSessionListener/1.1";
+
+    //--Constructor---------------------------------------------
+
+    public ClusterSessionListener() {
+    }
+
+    //--Logic---------------------------------------------------
+
+    /**
+     * Return descriptive information about this implementation.
+     */
+    public String getInfo() {
+
+        return (info);
+
+    }
+
+    /**
+     * Callback from the cluster, when a message is received, The cluster will
+     * broadcast it invoking the messageReceived on the receiver.
+     * 
+     * @param myobj
+     *            ClusterMessage - the message received from the cluster
+     */
+    public void messageReceived(ClusterMessage myobj) {
+        if (myobj != null && myobj instanceof SessionMessage) {
+            SessionMessage msg = (SessionMessage) myobj;
+            String ctxname = msg.getContextName();
+            //check if the message is a EVT_GET_ALL_SESSIONS,
+            //if so, wait until we are fully started up
+            Map managers = cluster.getManagers() ;
+            if (ctxname == null) {
+                java.util.Iterator i = managers.keySet().iterator();
+                while (i.hasNext()) {
+                    String key = (String) i.next();
+                    ClusterManager mgr = (ClusterManager) managers.get(key);
+                    if (mgr != null)
+                        mgr.messageDataReceived(msg);
+                    else {
+                        //this happens a lot before the system has started
+                        // up
+                        if (log.isDebugEnabled())
+                            log.debug("Context manager doesn't exist:"
+                                    + key);
+                    }
+                }
+            } else {
+                ClusterManager mgr = (ClusterManager) managers.get(ctxname);
+                if (mgr != null)
+                    mgr.messageDataReceived(msg);
+                else if (log.isWarnEnabled())
+                    log.warn("Context manager doesn't exist:" + ctxname);
+            }
+        }
+        return;
+    }
+
+    /**
+     * Accept only SessionMessage
+     * 
+     * @param msg
+     *            ClusterMessage
+     * @return boolean - returns true to indicate that messageReceived should be
+     *         invoked. If false is returned, the messageReceived method will
+     *         not be invoked.
+     */
+    public boolean accept(ClusterMessage msg) {
+        return (msg instanceof SessionMessage);
+    }
+}
+

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/session/Constants.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/session/Constants.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/session/Constants.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,31 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.ha.session;
+
+/**
+ * Manifest constants for the <code>org.apache.catalina.ha.session</code>
+ * package.
+ *
+ * @author Peter Rossbach Pero
+ */
+
+public class Constants {
+
+    public static final String Package = "org.apache.catalina.ha.session";
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/session/DeltaManager.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/session/DeltaManager.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/session/DeltaManager.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,1499 @@
+/*
+ * Copyright 1999,2004-2005 The Apache Software Foundation.
+ * 
+ * Licensed 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.ha.session;
+
+import java.beans.PropertyChangeEvent;
+import java.io.BufferedOutputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.Iterator;
+
+import org.apache.catalina.Cluster;
+import org.apache.catalina.Container;
+import org.apache.catalina.Context;
+import org.apache.catalina.Engine;
+import org.apache.catalina.Host;
+import org.apache.catalina.LifecycleException;
+import org.apache.catalina.LifecycleListener;
+import org.apache.catalina.Session;
+import org.apache.catalina.Valve;
+import org.apache.catalina.core.StandardContext;
+import org.apache.catalina.ha.CatalinaCluster;
+import org.apache.catalina.ha.ClusterMessage;
+import org.apache.catalina.ha.tcp.ReplicationValve;
+import org.apache.catalina.tribes.Member;
+import org.apache.catalina.tribes.io.ReplicationStream;
+import org.apache.catalina.util.LifecycleSupport;
+import org.apache.catalina.util.StringManager;
+
+/**
+ * The DeltaManager manages replicated sessions by only replicating the deltas
+ * in data. For applications written to handle this, the DeltaManager is the
+ * optimal way of replicating data.
+ * 
+ * This code is almost identical to StandardManager with a difference in how it
+ * persists sessions and some modifications to it.
+ * 
+ * <b>IMPLEMENTATION NOTE </b>: Correct behavior of session storing and
+ * reloading depends upon external calls to the <code>start()</code> and
+ * <code>stop()</code> methods of this class at the correct times.
+ * 
+ * @author Filip Hanik
+ * @author Craig R. McClanahan
+ * @author Jean-Francois Arcand
+ * @author Peter Rossbach
+ * @version $Revision: 380100 $ $Date: 2006-02-23 06:08:14 -0600 (Thu, 23 Feb 2006) $
+ */
+
+public class DeltaManager extends ClusterManagerBase{
+
+    // ---------------------------------------------------- Security Classes
+    public static org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory.getLog(DeltaManager.class);
+
+    /**
+     * The string manager for this package.
+     */
+    protected static StringManager sm = StringManager.getManager(Constants.Package);
+
+    // ----------------------------------------------------- Instance Variables
+
+    /**
+     * The descriptive information about this implementation.
+     */
+    private static final String info = "DeltaManager/2.1";
+
+    /**
+     * Has this component been started yet?
+     */
+    private boolean started = false;
+
+    /**
+     * The descriptive name of this Manager implementation (for logging).
+     */
+    protected static String managerName = "DeltaManager";
+    protected String name = null;
+    protected boolean defaultMode = false;
+    private CatalinaCluster cluster = null;
+
+    /**
+     * cached replication valve cluster container!
+     */
+    private ReplicationValve replicationValve = null ;
+    
+    /**
+     * The lifecycle event support for this component.
+     */
+    protected LifecycleSupport lifecycle = new LifecycleSupport(this);
+
+    /**
+     * The maximum number of active Sessions allowed, or -1 for no limit.
+     */
+    private int maxActiveSessions = -1;
+    private boolean expireSessionsOnShutdown = false;
+    private boolean notifyListenersOnReplication = true;
+    private boolean notifySessionListenersOnReplication = true;
+    private boolean stateTransfered = false ;
+    private int stateTransferTimeout = 60;
+    private boolean sendAllSessions = true;
+    private boolean sendClusterDomainOnly = true ;
+    private int sendAllSessionsSize = 1000 ;
+    
+    /**
+     * wait time between send session block (default 2 sec) 
+     */
+    private int sendAllSessionsWaitTime = 2 * 1000 ; 
+    private ArrayList receivedMessageQueue = new ArrayList() ;
+    private boolean receiverQueue = false ;
+    private boolean stateTimestampDrop = true ;
+    private long stateTransferCreateSendTime; 
+    
+    // ------------------------------------------------------------------ stats attributes
+    
+    int rejectedSessions = 0;
+    private long sessionReplaceCounter = 0 ;
+    long processingTime = 0;
+    private long counterReceive_EVT_GET_ALL_SESSIONS = 0 ;
+    private long counterSend_EVT_ALL_SESSION_DATA = 0 ;
+    private long counterReceive_EVT_ALL_SESSION_DATA = 0 ;
+    private long counterReceive_EVT_SESSION_CREATED = 0 ;
+    private long counterReceive_EVT_SESSION_EXPIRED = 0;
+    private long counterReceive_EVT_SESSION_ACCESSED = 0 ;
+    private long counterReceive_EVT_SESSION_DELTA = 0;
+    private long counterSend_EVT_GET_ALL_SESSIONS = 0 ;
+    private long counterSend_EVT_SESSION_CREATED = 0;
+    private long counterSend_EVT_SESSION_DELTA = 0 ;
+    private long counterSend_EVT_SESSION_ACCESSED = 0;
+    private long counterSend_EVT_SESSION_EXPIRED = 0;
+    private int counterSend_EVT_ALL_SESSION_TRANSFERCOMPLETE = 0 ;
+    private int counterReceive_EVT_ALL_SESSION_TRANSFERCOMPLETE = 0 ;
+    private int counterNoStateTransfered = 0 ;
+
+
+    // ------------------------------------------------------------- Constructor
+    public DeltaManager() {
+        super();
+    }
+
+    // ------------------------------------------------------------- Properties
+    
+    /**
+     * Return descriptive information about this Manager implementation and the
+     * corresponding version number, in the format
+     * <code>&lt;description&gt;/&lt;version&gt;</code>.
+     */
+    public String getInfo() {
+        return info;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    /**
+     * Return the descriptive short name of this Manager implementation.
+     */
+    public String getName() {
+        return name;
+    }
+
+    /**
+     * @return Returns the counterSend_EVT_GET_ALL_SESSIONS.
+     */
+    public long getCounterSend_EVT_GET_ALL_SESSIONS() {
+        return counterSend_EVT_GET_ALL_SESSIONS;
+    }
+    
+    /**
+     * @return Returns the counterSend_EVT_SESSION_ACCESSED.
+     */
+    public long getCounterSend_EVT_SESSION_ACCESSED() {
+        return counterSend_EVT_SESSION_ACCESSED;
+    }
+    
+    /**
+     * @return Returns the counterSend_EVT_SESSION_CREATED.
+     */
+    public long getCounterSend_EVT_SESSION_CREATED() {
+        return counterSend_EVT_SESSION_CREATED;
+    }
+
+    /**
+     * @return Returns the counterSend_EVT_SESSION_DELTA.
+     */
+    public long getCounterSend_EVT_SESSION_DELTA() {
+        return counterSend_EVT_SESSION_DELTA;
+    }
+
+    /**
+     * @return Returns the counterSend_EVT_SESSION_EXPIRED.
+     */
+    public long getCounterSend_EVT_SESSION_EXPIRED() {
+        return counterSend_EVT_SESSION_EXPIRED;
+    }
+ 
+    /**
+     * @return Returns the counterSend_EVT_ALL_SESSION_DATA.
+     */
+    public long getCounterSend_EVT_ALL_SESSION_DATA() {
+        return counterSend_EVT_ALL_SESSION_DATA;
+    }
+
+    /**
+     * @return Returns the counterSend_EVT_ALL_SESSION_TRANSFERCOMPLETE.
+     */
+    public int getCounterSend_EVT_ALL_SESSION_TRANSFERCOMPLETE() {
+        return counterSend_EVT_ALL_SESSION_TRANSFERCOMPLETE;
+    }
+ 
+    /**
+     * @return Returns the counterReceive_EVT_ALL_SESSION_DATA.
+     */
+    public long getCounterReceive_EVT_ALL_SESSION_DATA() {
+        return counterReceive_EVT_ALL_SESSION_DATA;
+    }
+    
+    /**
+     * @return Returns the counterReceive_EVT_GET_ALL_SESSIONS.
+     */
+    public long getCounterReceive_EVT_GET_ALL_SESSIONS() {
+        return counterReceive_EVT_GET_ALL_SESSIONS;
+    }
+    
+    /**
+     * @return Returns the counterReceive_EVT_SESSION_ACCESSED.
+     */
+    public long getCounterReceive_EVT_SESSION_ACCESSED() {
+        return counterReceive_EVT_SESSION_ACCESSED;
+    }
+    
+    /**
+     * @return Returns the counterReceive_EVT_SESSION_CREATED.
+     */
+    public long getCounterReceive_EVT_SESSION_CREATED() {
+        return counterReceive_EVT_SESSION_CREATED;
+    }
+    
+    /**
+     * @return Returns the counterReceive_EVT_SESSION_DELTA.
+     */
+    public long getCounterReceive_EVT_SESSION_DELTA() {
+        return counterReceive_EVT_SESSION_DELTA;
+    }
+    
+    /**
+     * @return Returns the counterReceive_EVT_SESSION_EXPIRED.
+     */
+    public long getCounterReceive_EVT_SESSION_EXPIRED() {
+        return counterReceive_EVT_SESSION_EXPIRED;
+    }
+    
+    
+    /**
+     * @return Returns the counterReceive_EVT_ALL_SESSION_TRANSFERCOMPLETE.
+     */
+    public int getCounterReceive_EVT_ALL_SESSION_TRANSFERCOMPLETE() {
+        return counterReceive_EVT_ALL_SESSION_TRANSFERCOMPLETE;
+    }
+    
+    /**
+     * @return Returns the processingTime.
+     */
+    public long getProcessingTime() {
+        return processingTime;
+    }
+ 
+    /**
+     * @return Returns the sessionReplaceCounter.
+     */
+    public long getSessionReplaceCounter() {
+        return sessionReplaceCounter;
+    }
+    
+    /**
+     * Number of session creations that failed due to maxActiveSessions
+     * 
+     * @return The count
+     */
+    public int getRejectedSessions() {
+        return rejectedSessions;
+    }
+
+    public void setRejectedSessions(int rejectedSessions) {
+        this.rejectedSessions = rejectedSessions;
+    }
+
+    /**
+     * @return Returns the counterNoStateTransfered.
+     */
+    public int getCounterNoStateTransfered() {
+        return counterNoStateTransfered;
+    }
+    
+    public int getReceivedQueueSize() {
+        return receivedMessageQueue.size() ;
+    }
+    
+    /**
+     * @return Returns the stateTransferTimeout.
+     */
+    public int getStateTransferTimeout() {
+        return stateTransferTimeout;
+    }
+    /**
+     * @param timeoutAllSession The timeout
+     */
+    public void setStateTransferTimeout(int timeoutAllSession) {
+        this.stateTransferTimeout = timeoutAllSession;
+    }
+
+    /**
+     * is session state transfered complete?
+     * 
+     */
+    public boolean getStateTransfered() {
+        return stateTransfered;
+    }
+
+    /**
+     * set that state ist complete transfered  
+     * @param stateTransfered
+     */
+    public void setStateTransfered(boolean stateTransfered) {
+        this.stateTransfered = stateTransfered;
+    }
+    
+    /**
+     * @return Returns the sendAllSessionsWaitTime in msec
+     */
+    public int getSendAllSessionsWaitTime() {
+        return sendAllSessionsWaitTime;
+    }
+    
+    /**
+     * @param sendAllSessionsWaitTime The sendAllSessionsWaitTime to set at msec.
+     */
+    public void setSendAllSessionsWaitTime(int sendAllSessionsWaitTime) {
+        this.sendAllSessionsWaitTime = sendAllSessionsWaitTime;
+    }
+    
+    /**
+     * @return Returns the sendClusterDomainOnly.
+     */
+    public boolean isSendClusterDomainOnly() {
+        return sendClusterDomainOnly;
+    }
+    
+    /**
+     * @param sendClusterDomainOnly The sendClusterDomainOnly to set.
+     */
+    public void setSendClusterDomainOnly(boolean sendClusterDomainOnly) {
+        this.sendClusterDomainOnly = sendClusterDomainOnly;
+    }
+
+    /**
+     * @return Returns the stateTimestampDrop.
+     */
+    public boolean isStateTimestampDrop() {
+        return stateTimestampDrop;
+    }
+    
+    /**
+     * @param isTimestampDrop The new flag value
+     */
+    public void setStateTimestampDrop(boolean isTimestampDrop) {
+        this.stateTimestampDrop = isTimestampDrop;
+    }
+    
+    /**
+     * Return the maximum number of active Sessions allowed, or -1 for no limit.
+     */
+    public int getMaxActiveSessions() {
+        return (this.maxActiveSessions);
+    }
+
+    /**
+     * Set the maximum number of actives Sessions allowed, or -1 for no limit.
+     * 
+     * @param max
+     *            The new maximum number of sessions
+     */
+    public void setMaxActiveSessions(int max) {
+        int oldMaxActiveSessions = this.maxActiveSessions;
+        this.maxActiveSessions = max;
+        support.firePropertyChange("maxActiveSessions", new Integer(oldMaxActiveSessions), new Integer(this.maxActiveSessions));
+    }
+    
+    /**
+     * 
+     * @return Returns the sendAllSessions.
+     */
+    public boolean isSendAllSessions() {
+        return sendAllSessions;
+    }
+    
+    /**
+     * @param sendAllSessions The sendAllSessions to set.
+     */
+    public void setSendAllSessions(boolean sendAllSessions) {
+        this.sendAllSessions = sendAllSessions;
+    }
+    
+    /**
+     * @return Returns the sendAllSessionsSize.
+     */
+    public int getSendAllSessionsSize() {
+        return sendAllSessionsSize;
+    }
+    
+    /**
+     * @param sendAllSessionsSize The sendAllSessionsSize to set.
+     */
+    public void setSendAllSessionsSize(int sendAllSessionsSize) {
+        this.sendAllSessionsSize = sendAllSessionsSize;
+    }
+    
+    /**
+     * @return Returns the notifySessionListenersOnReplication.
+     */
+    public boolean isNotifySessionListenersOnReplication() {
+        return notifySessionListenersOnReplication;
+    }
+    
+    /**
+     * @param notifyListenersCreateSessionOnReplication The notifySessionListenersOnReplication to set.
+     */
+    public void setNotifySessionListenersOnReplication(boolean notifyListenersCreateSessionOnReplication) {
+        this.notifySessionListenersOnReplication = notifyListenersCreateSessionOnReplication;
+    }
+    
+    
+    public boolean isExpireSessionsOnShutdown() {
+        return expireSessionsOnShutdown;
+    }
+
+    public void setExpireSessionsOnShutdown(boolean expireSessionsOnShutdown) {
+        this.expireSessionsOnShutdown = expireSessionsOnShutdown;
+    }
+    
+    public boolean isNotifyListenersOnReplication() {
+        return notifyListenersOnReplication;
+    }
+
+    public void setNotifyListenersOnReplication(boolean notifyListenersOnReplication) {
+        this.notifyListenersOnReplication = notifyListenersOnReplication;
+    }
+
+    
+    /**
+     * @return Returns the defaultMode.
+     */
+    public boolean isDefaultMode() {
+        return defaultMode;
+    }
+    /**
+     * @param defaultMode The defaultMode to set.
+     */
+    public void setDefaultMode(boolean defaultMode) {
+        this.defaultMode = defaultMode;
+    }
+    
+    public CatalinaCluster getCluster() {
+        return cluster;
+    }
+
+    public void setCluster(CatalinaCluster cluster) {
+        this.cluster = cluster;
+    }
+
+    /**
+     * Set the Container with which this Manager has been associated. If it is a
+     * Context (the usual case), listen for changes to the session timeout
+     * property.
+     * 
+     * @param container
+     *            The associated Container
+     */
+    public void setContainer(Container container) {
+        // De-register from the old Container (if any)
+        if ((this.container != null) && (this.container instanceof Context))
+            ((Context) this.container).removePropertyChangeListener(this);
+
+        // Default processing provided by our superclass
+        super.setContainer(container);
+
+        // Register with the new Container (if any)
+        if ((this.container != null) && (this.container instanceof Context)) {
+            setMaxInactiveInterval(((Context) this.container).getSessionTimeout() * 60);
+            ((Context) this.container).addPropertyChangeListener(this);
+        }
+
+    }
+    
+    // --------------------------------------------------------- Public Methods
+
+    /**
+     * Construct and return a new session object, based on the default settings
+     * specified by this Manager's properties. The session id will be assigned
+     * by this method, and available via the getId() method of the returned
+     * session. If a new session cannot be created for any reason, return
+     * <code>null</code>.
+     * 
+     * @exception IllegalStateException
+     *                if a new session cannot be instantiated for any reason
+     * 
+     * Construct and return a new session object, based on the default settings
+     * specified by this Manager's properties. The session id will be assigned
+     * by this method, and available via the getId() method of the returned
+     * session. If a new session cannot be created for any reason, return
+     * <code>null</code>.
+     * 
+     * @exception IllegalStateException
+     *                if a new session cannot be instantiated for any reason
+     */
+    public Session createSession(String sessionId) {
+        return createSession(sessionId, true);
+    }
+
+    /**
+     * create new session with check maxActiveSessions and send session creation
+     * to other cluster nodes.
+     * 
+     * @param distribute
+     * @return The session
+     */
+    public Session createSession(String sessionId, boolean distribute) {
+        if ((maxActiveSessions >= 0) && (sessions.size() >= maxActiveSessions)) {
+            rejectedSessions++;
+            throw new IllegalStateException(sm.getString("deltaManager.createSession.ise"));
+        }
+        DeltaSession session = (DeltaSession) super.createSession(sessionId) ;
+        if (distribute) {
+            sendCreateSession(session.getId(), session);
+        }
+        if (log.isDebugEnabled())
+            log.debug(sm.getString("deltaManager.createSession.newSession",session.getId(), new Integer(sessions.size())));
+        return (session);
+
+    }
+
+    /**
+     * Send create session evt to all backup node
+     * @param sessionId
+     * @param session
+     */
+    protected void sendCreateSession(String sessionId, DeltaSession session) {
+        if(cluster.getMembers().length > 0 ) {
+            SessionMessage msg = 
+                new SessionMessageImpl(getName(),
+                                       SessionMessage.EVT_SESSION_CREATED, 
+                                       null, 
+                                       sessionId,
+                                       sessionId + "-" + System.currentTimeMillis());
+            if (log.isDebugEnabled()) log.debug(sm.getString("deltaManager.sendMessage.newSession",name, sessionId));
+            msg.setTimestamp(session.getCreationTime());
+            counterSend_EVT_SESSION_CREATED++;
+            send(msg);
+        }
+    }
+    
+    /**
+     * Send messages to other backup member (domain or all)
+     * @param msg Session message
+     */
+    protected void send(SessionMessage msg) {
+        if(cluster != null) {
+            if(isSendClusterDomainOnly())
+                cluster.sendClusterDomain(msg);
+            else
+                cluster.send(msg);
+        }
+    }
+
+    /**
+     * Create DeltaSession
+     * @see org.apache.catalina.Manager#createEmptySession()
+     */
+    public Session createEmptySession() {
+        return getNewDeltaSession() ;
+    }
+    
+    /**
+     * Get new session class to be used in the doLoad() method.
+     */
+    protected DeltaSession getNewDeltaSession() {
+        return new DeltaSession(this);
+    }
+
+    /**
+     * Load Deltarequest from external node
+     * Load the Class at container classloader
+     * @see DeltaRequest#readExternal(java.io.ObjectInput)
+     * @param session
+     * @param data message data
+     * @return The request
+     * @throws ClassNotFoundException
+     * @throws IOException
+     */
+    protected DeltaRequest deserializeDeltaRequest(DeltaSession session, byte[] data) throws ClassNotFoundException, IOException {
+        ReplicationStream ois = getReplicationStream(data);
+        session.getDeltaRequest().readExternal(ois);
+        ois.close();
+        return session.getDeltaRequest();
+    }
+
+    /**
+     * serialize DeltaRequest
+     * @see DeltaRequest#writeExternal(java.io.ObjectOutput)
+     * 
+     * @param deltaRequest
+     * @return serialized delta request
+     * @throws IOException
+     */
+    protected byte[] serializeDeltaRequest(DeltaRequest deltaRequest) throws IOException {
+        return deltaRequest.serialize();
+    }
+
+    /**
+     * Load sessions from other cluster node.
+     * FIXME replace currently sessions with same id without notifcation.
+     * FIXME SSO handling is not really correct with the session replacement!
+     * @exception ClassNotFoundException
+     *                if a serialized class cannot be found during the reload
+     * @exception IOException
+     *                if an input/output error occurs
+     */
+    protected void deserializeSessions(byte[] data) throws ClassNotFoundException,IOException {
+
+        // Initialize our internal data structures
+        //sessions.clear(); //should not do this
+        // Open an input stream to the specified pathname, if any
+        ClassLoader originalLoader = Thread.currentThread().getContextClassLoader();
+        ObjectInputStream ois = null;
+        // Load the previously unloaded active sessions
+        try {
+            ois = getReplicationStream(data);
+            Integer count = (Integer) ois.readObject();
+            int n = count.intValue();
+            for (int i = 0; i < n; i++) {
+                DeltaSession session = (DeltaSession) createEmptySession();
+                session.readObjectData(ois);
+                session.setManager(this);
+                session.setValid(true);
+                session.setPrimarySession(false);
+                //in case the nodes in the cluster are out of
+                //time synch, this will make sure that we have the
+                //correct timestamp, isValid returns true, cause
+                // accessCount=1
+                session.access();
+                //make sure that the session gets ready to expire if
+                // needed
+                session.setAccessCount(0);
+                session.resetDeltaRequest();
+                // FIXME How inform other session id cache like SingleSignOn
+                // increment sessionCounter to correct stats report
+                if (findSession(session.getIdInternal()) == null ) {
+                    sessionCounter++;
+                } else {
+                    sessionReplaceCounter++;
+                    // FIXME better is to grap this sessions again !
+                    if (log.isWarnEnabled()) log.warn(sm.getString("deltaManager.loading.existing.session",session.getIdInternal()));
+                }
+                add(session);
+            }
+        } catch (ClassNotFoundException e) {
+            log.error(sm.getString("deltaManager.loading.cnfe", e), e);
+            throw e;
+        } catch (IOException e) {
+            log.error(sm.getString("deltaManager.loading.ioe", e), e);
+            throw e;
+        } finally {
+            // Close the input stream
+            try {
+                if (ois != null) ois.close();
+            } catch (IOException f) {
+                // ignored
+            }
+            ois = null;
+            if (originalLoader != null) Thread.currentThread().setContextClassLoader(originalLoader);
+        }
+
+    }
+
+    
+
+    /**
+     * Save any currently active sessions in the appropriate persistence
+     * mechanism, if any. If persistence is not supported, this method returns
+     * without doing anything.
+     * 
+     * @exception IOException
+     *                if an input/output error occurs
+     */
+    protected byte[] serializeSessions(Session[] currentSessions) throws IOException {
+
+        // Open an output stream to the specified pathname, if any
+        ByteArrayOutputStream fos = null;
+        ObjectOutputStream oos = null;
+
+        try {
+            fos = new ByteArrayOutputStream();
+            oos = new ObjectOutputStream(new BufferedOutputStream(fos));
+            oos.writeObject(new Integer(currentSessions.length));
+            for(int i=0 ; i < currentSessions.length;i++) {
+                ((DeltaSession)currentSessions[i]).writeObjectData(oos);                
+            }
+            // Flush and close the output stream
+            oos.flush();
+        } catch (IOException e) {
+            log.error(sm.getString("deltaManager.unloading.ioe", e), e);
+            throw e;
+        } finally {
+            if (oos != null) {
+                try {
+                    oos.close();
+                } catch (IOException f) {
+                    ;
+                }
+                oos = null;
+            }
+        }
+        // send object data as byte[]
+        return fos.toByteArray();
+    }
+
+    // ------------------------------------------------------ Lifecycle Methods
+
+    /**
+     * Add a lifecycle event listener to this component.
+     * 
+     * @param listener
+     *            The listener to add
+     */
+    public void addLifecycleListener(LifecycleListener listener) {
+        lifecycle.addLifecycleListener(listener);
+    }
+
+    /**
+     * Get the lifecycle listeners associated with this lifecycle. If this
+     * Lifecycle has no listeners registered, a zero-length array is returned.
+     */
+    public LifecycleListener[] findLifecycleListeners() {
+        return lifecycle.findLifecycleListeners();
+    }
+
+    /**
+     * Remove a lifecycle event listener from this component.
+     * 
+     * @param listener
+     *            The listener to remove
+     */
+    public void removeLifecycleListener(LifecycleListener listener) {
+        lifecycle.removeLifecycleListener(listener);
+    }
+
+    /**
+     * Prepare for the beginning of active use of the public methods of this
+     * component. This method should be called after <code>configure()</code>,
+     * and before any of the public methods of the component are utilized.
+     * 
+     * @exception LifecycleException
+     *                if this component detects a fatal error that prevents this
+     *                component from being used
+     */
+    public void start() throws LifecycleException {
+        if (!initialized) init();
+
+        // Validate and update our current component state
+        if (started) {
+            return;
+        }
+        started = true;
+        lifecycle.fireLifecycleEvent(START_EVENT, null);
+
+        // Force initialization of the random number generator
+        generateSessionId();
+
+        // Load unloaded sessions, if any
+        try {
+            //the channel is already running
+            Cluster cluster = getCluster() ;
+            // stop remove cluster binding
+            //wow, how many nested levels of if statements can we have ;)
+            if(cluster == null) {
+                Container context = getContainer() ;
+                if(context != null && context instanceof Context) {
+                     Container host = context.getParent() ;
+                     if(host != null && host instanceof Host) {
+                         cluster = host.getCluster();
+                         if(cluster != null && cluster instanceof CatalinaCluster) {
+                             setCluster((CatalinaCluster) cluster) ;
+                         } else {
+                             Container engine = host.getParent() ;
+                             if(engine != null && engine instanceof Engine) {
+                                 cluster = engine.getCluster();
+                                 if(cluster != null && cluster instanceof CatalinaCluster) {
+                                     setCluster((CatalinaCluster) cluster) ;
+                                 }
+                             } else {
+                                     cluster = null ;
+                             }
+                         }
+                     }
+                }
+            }
+            if (cluster == null) {
+                log.error(sm.getString("deltaManager.noCluster", getName()));
+                return;
+            } else {
+                if (log.isInfoEnabled()) {
+                    String type = "unknown" ;
+                    if( cluster.getContainer() instanceof Host){
+                        type = "Host" ;
+                    } else if( cluster.getContainer() instanceof Engine){
+                        type = "Engine" ;
+                    }
+                    log.info(sm.getString("deltaManager.registerCluster", getName(), type, cluster.getClusterName()));
+                }
+            }
+            if (log.isInfoEnabled()) log.info(sm.getString("deltaManager.startClustering", getName()));
+            //to survice context reloads, as only a stop/start is called, not
+            // createManager
+            ((CatalinaCluster)cluster).addManager(getName(), this);
+
+            getAllClusterSessions();
+
+        } catch (Throwable t) {
+            log.error(sm.getString("deltaManager.managerLoad"), t);
+        }
+    }
+
+    /**
+     * get from first session master the backup from all clustered sessions
+     * @see #findSessionMasterMember()
+     */
+    public synchronized void getAllClusterSessions() {
+        if (cluster != null && cluster.getMembers().length > 0) {
+            long beforeSendTime = System.currentTimeMillis();
+            Member mbr = findSessionMasterMember();
+            if(mbr == null) { // No domain member found
+                 return;
+            }
+            SessionMessage msg = new SessionMessageImpl(this.getName(),SessionMessage.EVT_GET_ALL_SESSIONS, null, "GET-ALL","GET-ALL-" + getName());
+            // set reference time
+            stateTransferCreateSendTime = beforeSendTime ;
+            // request session state
+            counterSend_EVT_GET_ALL_SESSIONS++;
+            stateTransfered = false ;
+            // FIXME This send call block the deploy thread, when sender waitForAck is enabled
+            try {
+                synchronized(receivedMessageQueue) {
+                     receiverQueue = true ;
+                }
+                cluster.send(msg, mbr);
+                if (log.isWarnEnabled()) log.warn(sm.getString("deltaManager.waitForSessionState",getName(), mbr));
+                // FIXME At sender ack mode this method check only the state transfer and resend is a problem!
+                waitForSendAllSessions(beforeSendTime);
+            } finally {
+                synchronized(receivedMessageQueue) {
+                    for (Iterator iter = receivedMessageQueue.iterator(); iter.hasNext();) {
+                        SessionMessage smsg = (SessionMessage) iter.next();
+                        if (!stateTimestampDrop) {
+                            messageReceived(smsg, smsg.getAddress() != null ? (Member) smsg.getAddress() : null);
+                        } else {
+                            if (smsg.getEventType() != SessionMessage.EVT_GET_ALL_SESSIONS && smsg.getTimestamp() >= stateTransferCreateSendTime) {
+                                // FIXME handle EVT_GET_ALL_SESSIONS later
+                                messageReceived(smsg,smsg.getAddress() != null ? (Member) smsg.getAddress() : null);
+                            } else {
+                                if (log.isWarnEnabled()) {
+                                    log.warn(sm.getString("deltaManager.dropMessage",getName(), smsg.getEventTypeString(),new Date(stateTransferCreateSendTime), new Date(smsg.getTimestamp())));
+                                }
+                            }
+                        }
+                    }        
+                    receivedMessageQueue.clear();
+                    receiverQueue = false ;
+                }
+           }
+        } else {
+            if (log.isInfoEnabled()) log.info(sm.getString("deltaManager.noMembers", getName()));
+        }
+    }
+
+    /**
+     * Register cross context session at replication valve thread local
+     * @param session cross context session
+     */
+    protected void registerSessionAtReplicationValve(DeltaSession session) {
+        if(replicationValve == null) {
+            if(container instanceof StandardContext && ((StandardContext)container).getCrossContext()) {
+                Cluster cluster = getCluster() ;
+                if(cluster != null && cluster instanceof CatalinaCluster) {
+                    Valve[] valves = ((CatalinaCluster)cluster).getValves();
+                    if(valves != null && valves.length > 0) {
+                        for(int i=0; replicationValve == null && i < valves.length ; i++ ){
+                            if(valves[i] instanceof ReplicationValve) replicationValve = (ReplicationValve)valves[i] ;
+                        }//for
+
+                        if(replicationValve == null && log.isDebugEnabled()) {
+                            log.debug("no ReplicationValve found for CrossContext Support");
+                        }//endif 
+                    }//end if
+                }//endif
+            }//end if
+        }//end if
+        if(replicationValve != null) {
+            replicationValve.registerReplicationSession(session);
+        }
+    }
+    
+    /**
+     * Find the master of the session state
+     * @return master member of sessions 
+     */
+    protected Member findSessionMasterMember() {
+        Member mbr = null;
+        Member mbrs[] = cluster.getMembers();
+        if(mbrs.length != 0 ) mbr = mbrs[0];
+        if(mbr == null && log.isWarnEnabled()) log.warn(sm.getString("deltaManager.noMasterMember",getName(), ""));
+        if(mbr != null && log.isDebugEnabled()) log.warn(sm.getString("deltaManager.foundMasterMember",getName(), mbr));
+        return mbr;
+    }
+
+    /**
+     * Wait that cluster session state is transfer or timeout after 60 Sec
+     * With stateTransferTimeout == -1 wait that backup is transfered (forever mode)
+     */
+    protected void waitForSendAllSessions(long beforeSendTime) {
+        long reqStart = System.currentTimeMillis();
+        long reqNow = reqStart ;
+        boolean isTimeout = false;
+        if(getStateTransferTimeout() > 0) {
+            // wait that state is transfered with timeout check
+            do {
+                try {
+                    Thread.sleep(100);
+                } catch (Exception sleep) {
+                    //
+                }
+                reqNow = System.currentTimeMillis();
+                isTimeout = ((reqNow - reqStart) > (1000 * getStateTransferTimeout()));
+            } while ((!getStateTransfered()) && (!isTimeout));
+        } else {
+            if(getStateTransferTimeout() == -1) {
+                // wait that state is transfered
+                do {
+                    try {
+                        Thread.sleep(100);
+                    } catch (Exception sleep) {
+                    }
+                } while ((!getStateTransfered()));
+                reqNow = System.currentTimeMillis();
+            }
+        }
+        if (isTimeout || (!getStateTransfered())) {
+            counterNoStateTransfered++ ;
+            log.error(sm.getString("deltaManager.noSessionState",getName(),new Date(beforeSendTime),new Long(reqNow - beforeSendTime)));
+        } else {
+            if (log.isInfoEnabled())
+                log.info(sm.getString("deltaManager.sessionReceived",getName(), new Date(beforeSendTime), new Long(reqNow - beforeSendTime)));
+        }
+    }
+
+    /**
+     * Gracefully terminate the active use of the public methods of this
+     * component. This method should be the last one called on a given instance
+     * of this component.
+     * 
+     * @exception LifecycleException
+     *                if this component detects a fatal error that needs to be
+     *                reported
+     */
+    public void stop() throws LifecycleException {
+
+        if (log.isDebugEnabled())
+            log.debug(sm.getString("deltaManager.stopped", getName()));
+
+
+        // Validate and update our current component state
+        if (!started)
+            throw new LifecycleException(sm.getString("deltaManager.notStarted"));
+        lifecycle.fireLifecycleEvent(STOP_EVENT, null);
+        started = false;
+
+        // Expire all active sessions
+        if (log.isInfoEnabled()) log.info(sm.getString("deltaManager.expireSessions", getName()));
+        Session sessions[] = findSessions();
+        for (int i = 0; i < sessions.length; i++) {
+            DeltaSession session = (DeltaSession) sessions[i];
+            if (!session.isValid())
+                continue;
+            try {
+                session.expire(true, isExpireSessionsOnShutdown());
+            } catch (Throwable ignore) {
+                ;
+            } 
+        }
+
+        // Require a new random number generator if we are restarted
+        this.random = null;
+        getCluster().removeManager(getName(),this);
+        replicationValve = null;
+        if (initialized) {
+            destroy();
+        }
+    }
+
+    // ----------------------------------------- PropertyChangeListener Methods
+
+    /**
+     * Process property change events from our associated Context.
+     * 
+     * @param event
+     *            The property change event that has occurred
+     */
+    public void propertyChange(PropertyChangeEvent event) {
+
+        // Validate the source of this event
+        if (!(event.getSource() instanceof Context))
+            return;
+        // Process a relevant property change
+        if (event.getPropertyName().equals("sessionTimeout")) {
+            try {
+                setMaxInactiveInterval(((Integer) event.getNewValue()).intValue() * 60);
+            } catch (NumberFormatException e) {
+                log.error(sm.getString("deltaManager.sessionTimeout", event.getNewValue()));
+            }
+        }
+
+    }
+
+    // -------------------------------------------------------- Replication
+    // Methods
+
+    /**
+     * A message was received from another node, this is the callback method to
+     * implement if you are interested in receiving replication messages.
+     * 
+     * @param cmsg -
+     *            the message received.
+     */
+    public void messageDataReceived(ClusterMessage cmsg) {
+        if (cmsg != null && cmsg instanceof SessionMessage) {
+            SessionMessage msg = (SessionMessage) cmsg;
+            switch (msg.getEventType()) {
+                case SessionMessage.EVT_GET_ALL_SESSIONS:
+                case SessionMessage.EVT_SESSION_CREATED: 
+                case SessionMessage.EVT_SESSION_EXPIRED: 
+                case SessionMessage.EVT_SESSION_ACCESSED:
+                case SessionMessage.EVT_SESSION_DELTA: {
+                    synchronized(receivedMessageQueue) {
+                        if(receiverQueue) {
+                            receivedMessageQueue.add(msg);
+                            return ;
+                        }
+                    }
+                   break;
+                }
+                default: {
+                    //we didn't queue, do nothing
+                    break;
+                }
+            } //switch
+            
+            messageReceived(msg, msg.getAddress() != null ? (Member) msg.getAddress() : null);
+        }
+    }
+
+    /**
+     * When the request has been completed, the replication valve will notify
+     * the manager, and the manager will decide whether any replication is
+     * needed or not. If there is a need for replication, the manager will
+     * create a session message and that will be replicated. The cluster
+     * determines where it gets sent.
+     * 
+     * @param sessionId -
+     *            the sessionId that just completed.
+     * @return a SessionMessage to be sent,
+     */
+    public ClusterMessage requestCompleted(String sessionId) {
+        try {
+            DeltaSession session = (DeltaSession) findSession(sessionId);
+            DeltaRequest deltaRequest = session.getDeltaRequest();
+            SessionMessage msg = null;
+            boolean isDeltaRequest = false ;
+            synchronized(deltaRequest) {
+                isDeltaRequest = deltaRequest.getSize() > 0 ;
+                if (isDeltaRequest) {    
+                    counterSend_EVT_SESSION_DELTA++;
+                    byte[] data = serializeDeltaRequest(deltaRequest);
+                    msg = new SessionMessageImpl(getName(),
+                                                 SessionMessage.EVT_SESSION_DELTA, 
+                                                 data, 
+                                                 sessionId,
+                                                 sessionId + "-" + System.currentTimeMillis());
+                    session.resetDeltaRequest();
+                }  
+            }
+            if(!isDeltaRequest) {
+                if(!session.isPrimarySession()) {               
+                    counterSend_EVT_SESSION_ACCESSED++;
+                    msg = new SessionMessageImpl(getName(),
+                                                 SessionMessage.EVT_SESSION_ACCESSED, 
+                                                 null, 
+                                                 sessionId,
+                                                 sessionId + "-" + System.currentTimeMillis());
+                    if (log.isDebugEnabled()) {
+                        log.debug(sm.getString("deltaManager.createMessage.accessChangePrimary",getName(), sessionId));
+                    }
+                }    
+            } else { // log only outside synch block!
+                if (log.isDebugEnabled()) {
+                    log.debug(sm.getString("deltaManager.createMessage.delta",getName(), sessionId));
+                }
+            }
+            session.setPrimarySession(true);
+            //check to see if we need to send out an access message
+            if ((msg == null)) {
+                long replDelta = System.currentTimeMillis() - session.getLastTimeReplicated();
+                if (replDelta > (getMaxInactiveInterval() * 1000)) {
+                    counterSend_EVT_SESSION_ACCESSED++;
+                    msg = new SessionMessageImpl(getName(),
+                                                 SessionMessage.EVT_SESSION_ACCESSED, 
+                                                 null,
+                                                 sessionId, 
+                                                 sessionId + "-" + System.currentTimeMillis());
+                    if (log.isDebugEnabled()) {
+                        log.debug(sm.getString("deltaManager.createMessage.access", getName(),sessionId));
+                    }
+                }
+
+            }
+
+            //update last replicated time
+            if (msg != null) session.setLastTimeReplicated(System.currentTimeMillis());
+            return msg;
+        } catch (IOException x) {
+            log.error(sm.getString("deltaManager.createMessage.unableCreateDeltaRequest",sessionId), x);
+            return null;
+        }
+
+    }
+    /**
+     * Reset manager statistics
+     */
+    public synchronized void resetStatistics() {
+        processingTime = 0 ;
+        expiredSessions = 0 ;
+        rejectedSessions = 0 ;
+        sessionReplaceCounter = 0 ;
+        counterNoStateTransfered = 0 ;
+        maxActive = getActiveSessions() ;
+        sessionCounter = getActiveSessions() ;
+        counterReceive_EVT_ALL_SESSION_DATA = 0;
+        counterReceive_EVT_GET_ALL_SESSIONS = 0;
+        counterReceive_EVT_SESSION_ACCESSED = 0 ;
+        counterReceive_EVT_SESSION_CREATED = 0 ;
+        counterReceive_EVT_SESSION_DELTA = 0 ;
+        counterReceive_EVT_SESSION_EXPIRED = 0 ;
+        counterReceive_EVT_ALL_SESSION_TRANSFERCOMPLETE = 0;
+        counterSend_EVT_ALL_SESSION_DATA = 0;
+        counterSend_EVT_GET_ALL_SESSIONS = 0;
+        counterSend_EVT_SESSION_ACCESSED = 0 ;
+        counterSend_EVT_SESSION_CREATED = 0 ;
+        counterSend_EVT_SESSION_DELTA = 0 ;
+        counterSend_EVT_SESSION_EXPIRED = 0 ;
+        counterSend_EVT_ALL_SESSION_TRANSFERCOMPLETE = 0;
+        
+    }
+   
+    //  -------------------------------------------------------- persistence handler
+
+    public void load() {
+
+    }
+
+    public void unload() {
+
+    }
+
+    //  -------------------------------------------------------- expire
+
+    /**
+     * send session expired to other cluster nodes
+     * 
+     * @param id
+     *            session id
+     */
+    protected void sessionExpired(String id) {
+        counterSend_EVT_SESSION_EXPIRED++ ;
+        SessionMessage msg = new SessionMessageImpl(getName(),SessionMessage.EVT_SESSION_EXPIRED, null, id, id+ "-EXPIRED-MSG");
+        if (log.isDebugEnabled()) log.debug(sm.getString("deltaManager.createMessage.expire",getName(), id));
+        send(msg);
+    }
+
+    /**
+     * Exipre all find sessions.
+     */
+    public void expireAllLocalSessions()
+    {
+        long timeNow = System.currentTimeMillis();
+        Session sessions[] = findSessions();
+        int expireDirect  = 0 ;
+        int expireIndirect = 0 ;
+        
+        if(log.isDebugEnabled()) log.debug("Start expire all sessions " + getName() + " at " + timeNow + " sessioncount " + sessions.length);
+        for (int i = 0; i < sessions.length; i++) {
+            if (sessions[i] instanceof DeltaSession) {
+                DeltaSession session = (DeltaSession) sessions[i];
+                if (session.isPrimarySession()) {
+                    if (session.isValid()) {
+                        session.expire();
+                        expireDirect++;
+                    } else {
+                        expireIndirect++;
+                    }//end if
+                }//end if
+            }//end if
+        }//for
+        long timeEnd = System.currentTimeMillis();
+        if(log.isDebugEnabled()) log.debug("End expire sessions " + getName() + " exipre processingTime " + (timeEnd - timeNow) + " expired direct sessions: " + expireDirect + " expired direct sessions: " + expireIndirect);
+      
+    }
+    
+    /**
+     * When the manager expires session not tied to a request. The cluster will
+     * periodically ask for a list of sessions that should expire and that
+     * should be sent across the wire.
+     * 
+     * @return The invalidated sessions array
+     */
+    public String[] getInvalidatedSessions() {
+        return new String[0];
+    }
+
+    //  -------------------------------------------------------- message receive
+
+    /**
+     * Test that sender and local domain is the same
+     */
+    protected boolean checkSenderDomain(SessionMessage msg,Member sender) {
+        boolean sameDomain= true;
+        if (!sameDomain && log.isWarnEnabled()) {
+                log.warn(sm.getString("deltaManager.receiveMessage.fromWrongDomain",
+                         new Object[] {getName(), 
+                         msg.getEventTypeString(), 
+                         sender,
+                         "",
+                         "" }));
+        }
+        return sameDomain ;
+    }
+
+    /**
+     * This method is called by the received thread when a SessionMessage has
+     * been received from one of the other nodes in the cluster.
+     * 
+     * @param msg -
+     *            the message received
+     * @param sender -
+     *            the sender of the message, this is used if we receive a
+     *            EVT_GET_ALL_SESSION message, so that we only reply to the
+     *            requesting node
+     */
+    protected void messageReceived(SessionMessage msg, Member sender) {
+        if(isSendClusterDomainOnly() && !checkSenderDomain(msg,sender)) {
+            return;
+        }
+        ClassLoader contextLoader = Thread.currentThread().getContextClassLoader();
+        try {
+            
+            ClassLoader[] loaders = getClassLoaders();
+            if ( loaders != null && loaders.length > 0) Thread.currentThread().setContextClassLoader(loaders[0]);
+            if (log.isDebugEnabled()) log.debug(sm.getString("deltaManager.receiveMessage.eventType",getName(), msg.getEventTypeString(), sender));
+ 
+            switch (msg.getEventType()) {
+                case SessionMessage.EVT_GET_ALL_SESSIONS: {
+                    handleGET_ALL_SESSIONS(msg,sender);
+                    break;
+                }
+                case SessionMessage.EVT_ALL_SESSION_DATA: {
+                    handleALL_SESSION_DATA(msg,sender);
+                    break;
+                }
+                case SessionMessage.EVT_ALL_SESSION_TRANSFERCOMPLETE: {
+                    handleALL_SESSION_TRANSFERCOMPLETE(msg,sender);
+                    break;
+                }
+                case SessionMessage.EVT_SESSION_CREATED: {
+                    handleSESSION_CREATED(msg,sender);
+                    break;
+                }
+                case SessionMessage.EVT_SESSION_EXPIRED: {
+                    handleSESSION_EXPIRED(msg,sender);
+                    break;
+                }
+                case SessionMessage.EVT_SESSION_ACCESSED: {
+                    handleSESSION_ACCESSED(msg,sender);
+                    break;
+                }
+                case SessionMessage.EVT_SESSION_DELTA: {
+                   handleSESSION_DELTA(msg,sender);
+                   break;
+                }
+                default: {
+                    //we didn't recognize the message type, do nothing
+                    break;
+                }
+            } //switch
+        } catch (Exception x) {
+            log.error(sm.getString("deltaManager.receiveMessage.error",getName()), x);
+        } finally {
+            Thread.currentThread().setContextClassLoader(contextLoader);
+        }
+    }
+
+    // -------------------------------------------------------- message receiver handler
+
+
+    /**
+     * handle receive session state is complete transfered
+     * @param msg
+     * @param sender
+     */
+    protected void handleALL_SESSION_TRANSFERCOMPLETE(SessionMessage msg, Member sender) {
+        counterReceive_EVT_ALL_SESSION_TRANSFERCOMPLETE++ ;
+        if (log.isDebugEnabled()) log.debug(sm.getString("deltaManager.receiveMessage.transfercomplete",getName(), sender.getHost(), new Integer(sender.getPort())));
+        stateTransferCreateSendTime = msg.getTimestamp() ;
+        stateTransfered = true ;
+    }
+
+    /**
+     * handle receive session delta
+     * @param msg
+     * @param sender
+     * @throws IOException
+     * @throws ClassNotFoundException
+     */
+    protected void handleSESSION_DELTA(SessionMessage msg, Member sender) throws IOException, ClassNotFoundException {
+        counterReceive_EVT_SESSION_DELTA++;
+        byte[] delta = msg.getSession();
+        DeltaSession session = (DeltaSession) findSession(msg.getSessionID());
+        if (session != null) {
+            if (log.isDebugEnabled()) log.debug(sm.getString("deltaManager.receiveMessage.delta",getName(), msg.getSessionID()));
+            DeltaRequest dreq = deserializeDeltaRequest(session, delta);
+            dreq.execute(session, notifyListenersOnReplication);
+            session.setPrimarySession(false);
+        }
+    }
+
+    /**
+     * handle receive session is access at other node ( primary session is now false)
+     * @param msg
+     * @param sender
+     * @throws IOException
+     */
+    protected void handleSESSION_ACCESSED(SessionMessage msg,Member sender) throws IOException {
+        counterReceive_EVT_SESSION_ACCESSED++;
+        DeltaSession session = (DeltaSession) findSession(msg.getSessionID());
+        if (session != null) {
+            if (log.isDebugEnabled()) log.debug(sm.getString("deltaManager.receiveMessage.accessed",getName(), msg.getSessionID()));
+            session.access();
+            session.setPrimarySession(false);
+            session.endAccess();
+        }
+    }
+
+    /**
+     * handle receive session is expire at other node ( expire session also here)
+     * @param msg
+     * @param sender
+     * @throws IOException
+     */
+    protected void handleSESSION_EXPIRED(SessionMessage msg,Member sender) throws IOException {
+        counterReceive_EVT_SESSION_EXPIRED++;
+        DeltaSession session = (DeltaSession) findSession(msg.getSessionID());
+        if (session != null) {
+            if (log.isDebugEnabled()) log.debug(sm.getString("deltaManager.receiveMessage.expired",getName(), msg.getSessionID()));
+            session.expire(notifySessionListenersOnReplication, false);
+        }
+    }
+
+    /**
+     * handle receive new session is created at other node (create backup - primary false)
+     * @param msg
+     * @param sender
+     */
+    protected void handleSESSION_CREATED(SessionMessage msg,Member sender) {
+        counterReceive_EVT_SESSION_CREATED++;
+        if (log.isDebugEnabled()) log.debug(sm.getString("deltaManager.receiveMessage.createNewSession",getName(), msg.getSessionID()));
+        DeltaSession session = (DeltaSession) createEmptySession();
+        session.setManager(this);
+        session.setValid(true);
+        session.setPrimarySession(false);
+        session.setCreationTime(msg.getTimestamp());
+        session.access();
+        if(notifySessionListenersOnReplication)
+            session.setId(msg.getSessionID());
+        else
+            session.setIdInternal(msg.getSessionID());
+        session.resetDeltaRequest();
+        session.endAccess();
+
+    }
+
+    /**
+     * handle receive sessions from other not ( restart )
+     * @param msg
+     * @param sender
+     * @throws ClassNotFoundException
+     * @throws IOException
+     */
+    protected void handleALL_SESSION_DATA(SessionMessage msg,Member sender) throws ClassNotFoundException, IOException {
+        counterReceive_EVT_ALL_SESSION_DATA++;
+        if (log.isDebugEnabled()) log.debug(sm.getString("deltaManager.receiveMessage.allSessionDataBegin",getName()));
+        byte[] data = msg.getSession();
+        deserializeSessions(data);
+        if (log.isDebugEnabled()) log.debug(sm.getString("deltaManager.receiveMessage.allSessionDataAfter",getName()));
+        //stateTransferred = true;
+    }
+
+    /**
+     * handle receive that other node want all sessions ( restart )
+     * a) send all sessions with one message
+     * b) send session at blocks
+     * After sending send state is complete transfered
+     * @param msg
+     * @param sender
+     * @throws IOException
+     */
+    protected void handleGET_ALL_SESSIONS(SessionMessage msg, Member sender) throws IOException {
+        counterReceive_EVT_GET_ALL_SESSIONS++;
+        //get a list of all the session from this manager
+        if (log.isDebugEnabled()) log.debug(sm.getString("deltaManager.receiveMessage.unloadingBegin", getName()));
+        // Write the number of active sessions, followed by the details
+        // get all sessions and serialize without sync
+        Session[] currentSessions = findSessions();
+        long findSessionTimestamp = System.currentTimeMillis() ;
+        if (isSendAllSessions()) {
+            sendSessions(sender, currentSessions, findSessionTimestamp);
+        } else {
+            // send session at blocks
+            int len = currentSessions.length < getSendAllSessionsSize() ? currentSessions.length : getSendAllSessionsSize();
+            Session[] sendSessions = new Session[len];
+            for (int i = 0; i < currentSessions.length; i += getSendAllSessionsSize()) {
+                len = i + getSendAllSessionsSize() > currentSessions.length ? currentSessions.length - i : getSendAllSessionsSize();
+                System.arraycopy(currentSessions, i, sendSessions, 0, len);
+                sendSessions(sender, sendSessions,findSessionTimestamp);
+                if (getSendAllSessionsWaitTime() > 0) {
+                    try {
+                        Thread.sleep(getSendAllSessionsWaitTime());
+                    } catch (Exception sleep) {
+                    }
+                }//end if
+            }//for
+        }//end if
+        
+        SessionMessage newmsg = new SessionMessageImpl(name,SessionMessage.EVT_ALL_SESSION_TRANSFERCOMPLETE, null,"SESSION-STATE-TRANSFERED", "SESSION-STATE-TRANSFERED"+ getName());
+        newmsg.setTimestamp(findSessionTimestamp);
+        if (log.isDebugEnabled()) log.debug(sm.getString("deltaManager.createMessage.allSessionTransfered",getName()));
+        counterSend_EVT_ALL_SESSION_TRANSFERCOMPLETE++;
+        cluster.send(newmsg, sender);
+    }
+
+
+    /**
+     * send a block of session to sender
+     * @param sender
+     * @param currentSessions
+     * @param sendTimestamp
+     * @throws IOException
+     */
+    protected void sendSessions(Member sender, Session[] currentSessions,long sendTimestamp) throws IOException {
+        byte[] data = serializeSessions(currentSessions);
+        if (log.isDebugEnabled()) log.debug(sm.getString("deltaManager.receiveMessage.unloadingAfter",getName()));
+        SessionMessage newmsg = new SessionMessageImpl(name,SessionMessage.EVT_ALL_SESSION_DATA, data,"SESSION-STATE", "SESSION-STATE-" + getName());
+        newmsg.setTimestamp(sendTimestamp);
+        if (log.isDebugEnabled()) log.debug(sm.getString("deltaManager.createMessage.allSessionData",getName()));
+        counterSend_EVT_ALL_SESSION_DATA++;
+        cluster.send(newmsg, sender);
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/session/DeltaRequest.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/session/DeltaRequest.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/session/DeltaRequest.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,386 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.ha.session;
+
+/**
+ * This class is used to track the series of actions that happens when
+ * a request is executed. These actions will then translate into invokations of methods 
+ * on the actual session.
+ * This class is NOT thread safe. One DeltaRequest per session
+ * @author <a href="mailto:fhanik at apache.org">Filip Hanik</a>
+ * @version 1.0
+ */
+
+import java.io.Externalizable;
+import java.security.Principal;
+import java.util.LinkedList;
+
+import org.apache.catalina.realm.GenericPrincipal;
+import org.apache.catalina.util.StringManager;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.ObjectOutputStream;
+
+
+public class DeltaRequest implements Externalizable {
+
+    public static org.apache.commons.logging.Log log =
+        org.apache.commons.logging.LogFactory.getLog( DeltaRequest.class );
+
+    /**
+     * The string manager for this package.
+     */
+    protected static StringManager sm = StringManager
+            .getManager(Constants.Package);
+
+    public static final int TYPE_ATTRIBUTE = 0;
+    public static final int TYPE_PRINCIPAL = 1;
+    public static final int TYPE_ISNEW = 2;
+    public static final int TYPE_MAXINTERVAL = 3;
+
+    public static final int ACTION_SET = 0;
+    public static final int ACTION_REMOVE = 1;
+
+    public static final String NAME_PRINCIPAL = "__SET__PRINCIPAL__";
+    public static final String NAME_MAXINTERVAL = "__SET__MAXINTERVAL__";
+    public static final String NAME_ISNEW = "__SET__ISNEW__";
+
+    private String sessionId;
+    private LinkedList actions = new LinkedList();
+    private LinkedList actionPool = new LinkedList();
+    
+    private boolean recordAllActions = false;
+
+    public DeltaRequest() {
+        
+    }
+    
+    public DeltaRequest(String sessionId, boolean recordAllActions) {
+        this.recordAllActions=recordAllActions;
+        if(sessionId != null)
+            setSessionId(sessionId);
+    }
+
+
+    public void setAttribute(String name, Object value) {
+        int action = (value==null)?ACTION_REMOVE:ACTION_SET;
+        addAction(TYPE_ATTRIBUTE,action,name,value);
+    }
+
+    public void removeAttribute(String name) {
+        int action = ACTION_REMOVE;
+        addAction(TYPE_ATTRIBUTE,action,name,null);
+    }
+
+    public void setMaxInactiveInterval(int interval) {
+        int action = ACTION_SET;
+        addAction(TYPE_MAXINTERVAL,action,NAME_MAXINTERVAL,new Integer(interval));
+    }
+    
+    /**
+     * convert principal at SerializablePrincipal for backup nodes.
+     * Only support principals from type {@link GenericPrincipal GenericPrincipal}
+     * @param p Session principal
+     * @see GenericPrincipal
+     */
+    public void setPrincipal(Principal p) {
+        int action = (p==null)?ACTION_REMOVE:ACTION_SET;
+        SerializablePrincipal sp = null;
+        if ( p != null ) {
+            if(p instanceof GenericPrincipal) {
+                sp = SerializablePrincipal.createPrincipal((GenericPrincipal)p);
+                if(log.isDebugEnabled())
+                    log.debug(sm.getString("deltaRequest.showPrincipal", p.getName() , getSessionId()));
+            } else
+                log.error(sm.getString("deltaRequest.wrongPrincipalClass",p.getClass().getName()));
+        }
+        addAction(TYPE_PRINCIPAL,action,NAME_PRINCIPAL,sp);
+    }
+
+    public void setNew(boolean n) {
+        int action = ACTION_SET;
+        addAction(TYPE_ISNEW,action,NAME_ISNEW,new Boolean(n));
+    }
+
+    protected synchronized void addAction(int type,
+                             int action,
+                             String name,
+                             Object value) {
+        AttributeInfo info = null;
+        if ( this.actionPool.size() > 0 ) {
+            try {
+                info = (AttributeInfo) actionPool.removeFirst();
+            }catch ( Exception x ) {
+                log.error("Unable to remove element:",x);
+                info = new AttributeInfo(type, action, name, value);
+            }
+            info.init(type,action,name,value);
+        } else {
+            info = new AttributeInfo(type, action, name, value);
+        }
+        //if we have already done something to this attribute, make sure
+        //we don't send multiple actions across the wire
+        if ( !recordAllActions) {
+            try {
+                actions.remove(info);
+            } catch (java.util.NoSuchElementException x) {
+                //do nothing, we wanted to remove it anyway
+            }
+        }
+        //add the action
+        actions.addLast(info);
+    }
+    
+    public void execute(DeltaSession session) {
+        execute(session,true);
+    }
+
+    public synchronized void execute(DeltaSession session, boolean notifyListeners) {
+        if ( !this.sessionId.equals( session.getId() ) )
+            throw new java.lang.IllegalArgumentException("Session id mismatch, not executing the delta request");
+        session.access();
+        for ( int i=0; i<actions.size(); i++ ) {
+            AttributeInfo info = (AttributeInfo)actions.get(i);
+            switch ( info.getType() ) {
+                case TYPE_ATTRIBUTE: {
+                    if ( info.getAction() == ACTION_SET ) {
+                        if ( log.isTraceEnabled() ) log.trace("Session.setAttribute('"+info.getName()+"', '"+info.getValue()+"')");
+                        session.setAttribute(info.getName(), info.getValue(),notifyListeners,false);
+                    }  else {
+                        if ( log.isTraceEnabled() ) log.trace("Session.removeAttribute('"+info.getName()+"')");
+                        session.removeAttribute(info.getName(),notifyListeners,false);
+                    }
+                        
+                    break;
+                }//case
+                case TYPE_ISNEW: {
+                if ( log.isTraceEnabled() ) log.trace("Session.setNew('"+info.getValue()+"')");
+                    session.setNew(((Boolean)info.getValue()).booleanValue(),false);
+                    break;
+                }//case
+                case TYPE_MAXINTERVAL: {
+                    if ( log.isTraceEnabled() ) log.trace("Session.setMaxInactiveInterval('"+info.getValue()+"')");
+                    session.setMaxInactiveInterval(((Integer)info.getValue()).intValue(),false);
+                    break;
+                }//case
+                case TYPE_PRINCIPAL: {
+                    Principal p = null;
+                    if ( info.getAction() == ACTION_SET ) {
+                        SerializablePrincipal sp = (SerializablePrincipal)info.getValue();
+                        p = (Principal)sp.getPrincipal(session.getManager().getContainer().getRealm());
+                    }
+                    session.setPrincipal(p,false);
+                    break;
+                }//case
+                default : throw new java.lang.IllegalArgumentException("Invalid attribute info type="+info);
+            }//switch
+        }//for
+        session.endAccess();
+        reset();
+    }
+
+    public synchronized void reset() {
+        while ( actions.size() > 0 ) {
+            try {
+                AttributeInfo info = (AttributeInfo) actions.removeFirst();
+                info.recycle();
+                actionPool.addLast(info);
+            }catch  ( Exception x ) {
+                log.error("Unable to remove element",x);
+            }
+        }
+        actions.clear();
+    }
+    
+    public String getSessionId() {
+        return sessionId;
+    }
+    public void setSessionId(String sessionId) {
+        this.sessionId = sessionId;
+        if ( sessionId == null ) {
+            new Exception("Session Id is null for setSessionId").fillInStackTrace().printStackTrace();
+        }
+    }
+    public int getSize() {
+        return actions.size();
+    }
+    
+    public synchronized void clear() {
+        actions.clear();
+        actionPool.clear();
+    }
+    
+    public synchronized void readExternal(java.io.ObjectInput in) throws IOException,ClassNotFoundException {
+        //sessionId - String
+        //recordAll - boolean
+        //size - int
+        //AttributeInfo - in an array
+        reset();
+        sessionId = in.readUTF();
+        recordAllActions = in.readBoolean();
+        int cnt = in.readInt();
+        if (actions == null)
+            actions = new LinkedList();
+        else
+            actions.clear();
+        for (int i = 0; i < cnt; i++) {
+            AttributeInfo info = null;
+            if (this.actionPool.size() > 0) {
+                try {
+                    info = (AttributeInfo) actionPool.removeFirst();
+                } catch ( Exception x )  {
+                    log.error("Unable to remove element",x);
+                    info = new AttributeInfo(-1,-1,null,null);
+                }
+            }
+            else {
+                info = new AttributeInfo(-1,-1,null,null);
+            }
+            info.readExternal(in);
+            actions.addLast(info);
+        }//for
+    }
+        
+
+
+    public synchronized void writeExternal(java.io.ObjectOutput out ) throws java.io.IOException {
+        //sessionId - String
+        //recordAll - boolean
+        //size - int
+        //AttributeInfo - in an array
+        out.writeUTF(getSessionId());
+        out.writeBoolean(recordAllActions);
+        out.writeInt(getSize());
+        for ( int i=0; i<getSize(); i++ ) {
+            AttributeInfo info = (AttributeInfo)actions.get(i);
+            info.writeExternal(out);
+        }
+    }
+    
+    /**
+     * serialize DeltaRequest
+     * @see DeltaRequest#writeExternal(java.io.ObjectOutput)
+     * 
+     * @param deltaRequest
+     * @return serialized delta request
+     * @throws IOException
+     */
+    protected byte[] serialize() throws IOException {
+        ByteArrayOutputStream bos = new ByteArrayOutputStream();
+        ObjectOutputStream oos = new ObjectOutputStream(bos);
+        writeExternal(oos);
+        oos.flush();
+        oos.close();
+        return bos.toByteArray();
+    }
+    
+    private static class AttributeInfo implements java.io.Externalizable {
+        private String name = null;
+        private Object value = null;
+        private int action;
+        private int type;
+
+        public AttributeInfo() {}
+
+        public AttributeInfo(int type,
+                             int action,
+                             String name,
+                             Object value) {
+            super();
+            init(type,action,name,value);
+        }
+
+        public void init(int type,
+                         int action,
+                         String name,
+                         Object value) {
+            this.name = name;
+            this.value = value;
+            this.action = action;
+            this.type = type;
+        }
+
+        public int getType() {
+            return type;
+        }
+
+        public int getAction() {
+            return action;
+        }
+
+        public Object getValue() {
+            return value;
+        }
+        public int hashCode() {
+            return name.hashCode();
+        }
+
+        public String getName() {
+            return name;
+        }
+        
+        public void recycle() {
+            name = null;
+            value = null;
+            type=-1;
+            action=-1;
+        }
+
+        public boolean equals(Object o) {
+            if ( ! (o instanceof AttributeInfo ) ) return false;
+            AttributeInfo other =  (AttributeInfo)o;
+            return other.getName().equals(this.getName());
+        }
+        
+        public synchronized void readExternal(java.io.ObjectInput in ) throws IOException,ClassNotFoundException {
+            //type - int
+            //action - int
+            //name - String
+            //hasvalue - boolean
+            //value - object
+            type = in.readInt();
+            action = in.readInt();
+            name = in.readUTF();
+            boolean hasValue = in.readBoolean();
+            if ( hasValue ) value = in.readObject();
+        }
+
+        public synchronized void writeExternal(java.io.ObjectOutput out) throws IOException {
+            //type - int
+            //action - int
+            //name - String
+            //hasvalue - boolean
+            //value - object
+            out.writeInt(getType());
+            out.writeInt(getAction());
+            out.writeUTF(getName());
+            out.writeBoolean(getValue()!=null);
+            if (getValue()!=null) out.writeObject(getValue());
+        }
+        
+        public String toString() {
+            StringBuffer buf = new StringBuffer("AttributeInfo[type=");
+            buf.append(getType()).append(", action=").append(getAction());
+            buf.append(", name=").append(getName()).append(", value=").append(getValue());
+            buf.append(", addr=").append(super.toString()).append("]");
+            return buf.toString();
+        }
+
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/session/DeltaSession.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/session/DeltaSession.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/session/DeltaSession.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,749 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ *
+ * Licensed 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.ha.session;
+
+import java.io.Externalizable;
+import java.io.IOException;
+import java.io.NotSerializableException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+import java.io.Serializable;
+import java.security.Principal;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+import javax.servlet.http.HttpSession;
+import javax.servlet.http.HttpSessionContext;
+
+import org.apache.catalina.Manager;
+import org.apache.catalina.ha.ClusterManager;
+import org.apache.catalina.ha.ClusterSession;
+import org.apache.catalina.realm.GenericPrincipal;
+import org.apache.catalina.session.StandardSession;
+import org.apache.catalina.tribes.io.ReplicationStream;
+import org.apache.catalina.tribes.tipis.ReplicatedMapEntry;
+import org.apache.catalina.util.Enumerator;
+import org.apache.catalina.util.StringManager;
+import org.apache.catalina.session.StandardManager;
+import org.apache.catalina.session.ManagerBase;
+
+/**
+ *
+ * Similar to the StandardSession except that this session will keep
+ * track of deltas during a request.
+ *
+ * @author Filip Hanik
+ * @version $Revision: 372887 $ $Date: 2006-01-27 09:58:58 -0600 (Fri, 27 Jan 2006) $
+ */
+
+public class DeltaSession extends StandardSession implements Externalizable,ClusterSession,ReplicatedMapEntry {
+
+    public static org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory.getLog(DeltaSession.class);
+
+    /**
+     * The string manager for this package.
+     */
+    protected static StringManager sm = StringManager.getManager(Constants.Package);
+
+    // ----------------------------------------------------- Instance Variables
+
+    /**
+     * only the primary session will expire, or be able to expire due to
+     * inactivity. This is set to false as soon as I receive this session over
+     * the wire in a session message. That means that someone else has made a
+     * request on another server.
+     */
+    private transient boolean isPrimarySession = true;
+
+    /**
+     * The delta request contains all the action info
+     *
+     */
+    private transient DeltaRequest deltaRequest = null;
+
+    /**
+     * Last time the session was replicatd, used for distributed expiring of
+     * session
+     */
+    private transient long lastTimeReplicated = System.currentTimeMillis();
+
+
+    protected Lock diffLock = new ReentrantReadWriteLock().writeLock();
+
+    private long version;
+
+    // ----------------------------------------------------------- Constructors
+
+    /**
+     * Construct a new Session associated with the specified Manager.
+     *
+     * @param manager
+     *            The manager with which this Session is associated
+     */
+    public DeltaSession() {
+        this(null);
+    }
+
+    public DeltaSession(Manager manager) {
+        super(manager);
+        this.resetDeltaRequest();
+    }
+
+    // ----------------------------------------------------- ReplicatedMapEntry
+
+    /**
+         * Has the object changed since last replication
+         * and is not in a locked state
+         * @return boolean
+         */
+        public boolean isDirty() {
+            return getDeltaRequest().getSize()>0;
+        }
+
+        /**
+         * If this returns true, the map will extract the diff using getDiff()
+         * Otherwise it will serialize the entire object.
+         * @return boolean
+         */
+        public boolean isDiffable() {
+            return true;
+        }
+
+        /**
+         * Returns a diff and sets the dirty map to false
+         * @return byte[]
+         * @throws IOException
+         */
+        public byte[] getDiff() throws IOException {
+            return getDeltaRequest().serialize();
+        }
+
+        public ClassLoader[] getClassLoaders() {
+            if ( manager instanceof BackupManager ) return ((BackupManager)manager).getClassLoaders();
+            else if ( manager instanceof ClusterManagerBase ) return ((ClusterManagerBase)manager).getClassLoaders();
+            else if ( manager instanceof StandardManager ) {
+                StandardManager sm = (StandardManager)manager;
+                return ClusterManagerBase.getClassLoaders(sm.getContainer());
+            } else if ( manager instanceof ManagerBase ) {
+                ManagerBase mb = (ManagerBase)manager;
+                return ClusterManagerBase.getClassLoaders(mb.getContainer());
+            }//end if
+            return null;
+        }
+
+        /**
+         * Applies a diff to an existing object.
+         * @param diff byte[]
+         * @param offset int
+         * @param length int
+         * @throws IOException
+         */
+        public void applyDiff(byte[] diff, int offset, int length) throws IOException, ClassNotFoundException {
+            ReplicationStream stream = ((ClusterManager)getManager()).getReplicationStream(diff,offset,length);
+            getDeltaRequest().readExternal(stream);
+            ClassLoader contextLoader = Thread.currentThread().getContextClassLoader();
+            try {
+                ClassLoader[] loaders = getClassLoaders();
+                if ( loaders != null && loaders.length >0 ) Thread.currentThread().setContextClassLoader(loaders[0]);
+                getDeltaRequest().execute(this);
+            }finally {
+                Thread.currentThread().setContextClassLoader(contextLoader);
+            }
+        }
+
+        /**
+         * Resets the current diff state and resets the dirty flag
+         */
+        public void resetDiff() {
+            resetDeltaRequest();
+        }
+
+        /**
+         * Lock during serialization
+         */
+        public void lock() {
+            diffLock.lock();
+        }
+
+        /**
+         * Unlock after serialization
+         */
+        public void unlock() {
+            diffLock.unlock();
+        }
+
+        public void setOwner(Object owner) {
+            if ( owner instanceof ClusterManager && getManager()==null) {
+                ClusterManager cm = (ClusterManager)owner;
+                this.setManager(cm);
+                this.setValid(true);
+                this.setPrimarySession(false);
+                this.access();
+                if (cm.isNotifyListenersOnReplication()) this.setId(getIdInternal());
+                this.resetDeltaRequest();
+                this.endAccess();
+            }
+        }
+    // ----------------------------------------------------- Session Properties
+
+    /**
+     * returns true if this session is the primary session, if that is the case,
+     * the manager can expire it upon timeout.
+     */
+    public boolean isPrimarySession() {
+        return isPrimarySession;
+    }
+
+    /**
+     * Sets whether this is the primary session or not.
+     *
+     * @param primarySession
+     *            Flag value
+     */
+    public void setPrimarySession(boolean primarySession) {
+        this.isPrimarySession = primarySession;
+    }
+
+    /**
+     * Set the session identifier for this session without notify listeners.
+     *
+     * @param id
+     *            The new session identifier
+     */
+    public void setIdInternal(String id) {
+        super.setId(id);
+        resetDeltaRequest();
+    }
+
+    /**
+     * Set the session identifier for this session.
+     *
+     * @param id
+     *            The new session identifier
+     */
+    public void setId(String id) {
+        setIdInternal(id);
+    }
+
+   
+
+    /**
+     * Return the last client access time without invalidation check
+     * @see #getLastAccessedTime().
+     */
+    public long getLastAccessedTimeInternal() {
+        return (this.lastAccessedTime);
+    }
+
+
+   
+    public void setMaxInactiveInterval(int interval, boolean addDeltaRequest) {
+        super.maxInactiveInterval = interval;
+        if (isValid && interval == 0) {
+            expire();
+        } else {
+            if (addDeltaRequest && (deltaRequest != null))
+                deltaRequest.setMaxInactiveInterval(interval);
+        }
+    }
+
+    /**
+     * Set the <code>isNew</code> flag for this session.
+     *
+     * @param isNew
+     *            The new value for the <code>isNew</code> flag
+     */
+    public void setNew(boolean isNew) {
+        setNew(isNew, true);
+    }
+
+    public void setNew(boolean isNew, boolean addDeltaRequest) {
+        super.setNew(isNew);
+        if (addDeltaRequest && (deltaRequest != null))
+            deltaRequest.setNew(isNew);
+    }
+
+    /**
+     * Set the authenticated Principal that is associated with this Session.
+     * This provides an <code>Authenticator</code> with a means to cache a
+     * previously authenticated Principal, and avoid potentially expensive
+     * <code>Realm.authenticate()</code> calls on every request.
+     *
+     * @param principal
+     *            The new Principal, or <code>null</code> if none
+     */
+    public void setPrincipal(Principal principal) {
+        setPrincipal(principal, true);
+    }
+
+    public void setPrincipal(Principal principal, boolean addDeltaRequest) {
+        try { 
+            lock();
+            super.setPrincipal(principal);
+            if (addDeltaRequest && (deltaRequest != null))
+                deltaRequest.setPrincipal(principal);
+        } finally {
+            unlock();
+        }
+    }
+
+    /**
+     * Return the <code>isValid</code> flag for this session.
+     */
+    public boolean isValid() {
+        if (this.expiring) {
+            return true;
+        }
+        if (!this.isValid) {
+            return false;
+        }
+        if (accessCount > 0) {
+            return true;
+        }
+        if (maxInactiveInterval >= 0) {
+            long timeNow = System.currentTimeMillis();
+            int timeIdle = (int) ( (timeNow - thisAccessedTime) / 1000L);
+            if (isPrimarySession()) {
+                if (timeIdle >= maxInactiveInterval) {
+                    expire(true);
+                }
+            } else {
+                if (timeIdle >= (2 * maxInactiveInterval)) {
+                    //if the session has been idle twice as long as allowed,
+                    //the primary session has probably crashed, and no other
+                    //requests are coming in. that is why we do this. otherwise
+                    //we would have a memory leak
+                    expire(true, false);
+                }
+            }
+        }
+        return (this.isValid);
+    }
+
+    // ------------------------------------------------- Session Public Methods
+
+    /**
+     * Perform the internal processing required to invalidate this session,
+     * without triggering an exception if the session has already expired.
+     *
+     * @param notify
+     *            Should we notify listeners about the demise of this session?
+     */
+    public void expire(boolean notify) {
+        expire(notify, true);
+    }
+
+    public void expire(boolean notify, boolean notifyCluster) {
+        String expiredId = getIdInternal();
+        super.expire(notify);
+
+        if (notifyCluster) {
+            if (log.isDebugEnabled())
+                log.debug(sm.getString("deltaSession.notifying",
+                                       ((DeltaManager)manager).getName(), 
+                                       new Boolean(isPrimarySession()), 
+                                       expiredId));
+            if ( manager instanceof DeltaManager ) {
+                ( (DeltaManager) manager).sessionExpired(expiredId);
+            }
+        }
+    }
+
+    /**
+     * Release all object references, and initialize instance variables, in
+     * preparation for reuse of this object.
+     */
+    public void recycle() {
+        super.recycle();
+        deltaRequest.clear();
+    }
+
+
+    /**
+     * Return a string representation of this object.
+     */
+    public String toString() {
+        StringBuffer sb = new StringBuffer();
+        sb.append("DeltaSession[");
+        sb.append(id);
+        sb.append("]");
+        return (sb.toString());
+    }
+
+    // ------------------------------------------------ Session Package Methods
+
+    public synchronized void readExternal(ObjectInput in) throws IOException,ClassNotFoundException {
+        readObjectData(in);
+    }
+
+
+    /**
+     * Read a serialized version of the contents of this session object from the
+     * specified object input stream, without requiring that the StandardSession
+     * itself have been serialized.
+     *
+     * @param stream
+     *            The object input stream to read from
+     *
+     * @exception ClassNotFoundException
+     *                if an unknown class is specified
+     * @exception IOException
+     *                if an input/output error occurs
+     */
+    public void readObjectData(ObjectInput stream) throws ClassNotFoundException, IOException {
+        readObject(stream);
+    }
+
+    /**
+     * Write a serialized version of the contents of this session object to the
+     * specified object output stream, without requiring that the
+     * StandardSession itself have been serialized.
+     *
+     * @param stream
+     *            The object output stream to write to
+     *
+     * @exception IOException
+     *                if an input/output error occurs
+     */
+    public void writeObjectData(ObjectOutput stream) throws IOException {
+        writeObject(stream);
+    }
+
+    public void resetDeltaRequest() {
+        if (deltaRequest == null) {
+            deltaRequest = new DeltaRequest(getIdInternal(), false);
+        } else {
+            deltaRequest.reset();
+            deltaRequest.setSessionId(getIdInternal());
+        }
+    }
+
+    public DeltaRequest getDeltaRequest() {
+        if (deltaRequest == null) resetDeltaRequest();
+        return deltaRequest;
+    }
+
+    // ------------------------------------------------- HttpSession Properties
+
+    // ----------------------------------------------HttpSession Public Methods
+
+
+
+    /**
+     * Remove the object bound with the specified name from this session. If the
+     * session does not have an object bound with this name, this method does
+     * nothing.
+     * <p>
+     * After this method executes, and if the object implements
+     * <code>HttpSessionBindingListener</code>, the container calls
+     * <code>valueUnbound()</code> on the object.
+     *
+     * @param name
+     *            Name of the object to remove from this session.
+     * @param notify
+     *            Should we notify interested listeners that this attribute is
+     *            being removed?
+     *
+     * @exception IllegalStateException
+     *                if this method is called on an invalidated session
+     */
+    public void removeAttribute(String name, boolean notify) {
+        removeAttribute(name, notify, true);
+    }
+
+    public void removeAttribute(String name, boolean notify,boolean addDeltaRequest) {
+        // Validate our current state
+        if (!isValid()) throw new IllegalStateException(sm.getString("standardSession.removeAttribute.ise"));
+        removeAttributeInternal(name, notify, addDeltaRequest);
+    }
+
+    /**
+     * Bind an object to this session, using the specified name. If an object of
+     * the same name is already bound to this session, the object is replaced.
+     * <p>
+     * After this method executes, and if the object implements
+     * <code>HttpSessionBindingListener</code>, the container calls
+     * <code>valueBound()</code> on the object.
+     *
+     * @param name
+     *            Name to which the object is bound, cannot be null
+     * @param value
+     *            Object to be bound, cannot be null
+     *
+     * @exception IllegalArgumentException
+     *                if an attempt is made to add a non-serializable object in
+     *                an environment marked distributable.
+     * @exception IllegalStateException
+     *                if this method is called on an invalidated session
+     */
+    public void setAttribute(String name, Object value) {
+        setAttribute(name, value, true, true);
+    }
+
+    public void setAttribute(String name, Object value, boolean notify,boolean addDeltaRequest) {
+
+        // Name cannot be null
+        if (name == null) throw new IllegalArgumentException(sm.getString("standardSession.setAttribute.namenull"));
+
+        // Null value is the same as removeAttribute()
+        if (value == null) {
+            removeAttribute(name);
+            return;
+        }
+
+        try {
+            lock();
+            super.setAttribute(name,value, notify);
+            if (addDeltaRequest && (deltaRequest != null)) deltaRequest.setAttribute(name, value);
+        } finally {
+            unlock();
+        }
+    }
+
+    // -------------------------------------------- HttpSession Private Methods
+
+    /**
+     * Read a serialized version of this session object from the specified
+     * object input stream.
+     * <p>
+     * <b>IMPLEMENTATION NOTE </b>: The reference to the owning Manager is not
+     * restored by this method, and must be set explicitly.
+     *
+     * @param stream
+     *            The input stream to read from
+     *
+     * @exception ClassNotFoundException
+     *                if an unknown class is specified
+     * @exception IOException
+     *                if an input/output error occurs
+     */
+    private void readObject(ObjectInput stream) throws ClassNotFoundException, IOException {
+
+        // Deserialize the scalar instance variables (except Manager)
+        authType = null; // Transient only
+        creationTime = ( (Long) stream.readObject()).longValue();
+        lastAccessedTime = ( (Long) stream.readObject()).longValue();
+        maxInactiveInterval = ( (Integer) stream.readObject()).intValue();
+        isNew = ( (Boolean) stream.readObject()).booleanValue();
+        isValid = ( (Boolean) stream.readObject()).booleanValue();
+        thisAccessedTime = ( (Long) stream.readObject()).longValue();
+        version = ( (Long) stream.readObject()).longValue();
+        boolean hasPrincipal = stream.readBoolean();
+        principal = null;
+        if (hasPrincipal) {
+            principal = SerializablePrincipal.readPrincipal(stream,getManager().getContainer().getRealm());
+        }
+
+        //        setId((String) stream.readObject());
+        id = (String) stream.readObject();
+        if (log.isDebugEnabled()) log.debug(sm.getString("deltaSession.readSession", id));
+
+        // Deserialize the attribute count and attribute values
+        if (attributes == null) attributes = new Hashtable();
+        int n = ( (Integer) stream.readObject()).intValue();
+        boolean isValidSave = isValid;
+        isValid = true;
+        for (int i = 0; i < n; i++) {
+            String name = (String) stream.readObject();
+            Object value = (Object) stream.readObject();
+            if ( (value instanceof String) && (value.equals(NOT_SERIALIZED)))
+                continue;
+            attributes.put(name, value);
+        }
+        isValid = isValidSave;
+
+        if (listeners == null) {
+            listeners = new ArrayList();
+        }
+
+        if (notes == null) {
+            notes = new Hashtable();
+        }
+    }
+
+    public synchronized void writeExternal(ObjectOutput out ) throws java.io.IOException {
+        writeObject(out);
+    }
+
+
+    /**
+     * Write a serialized version of this session object to the specified object
+     * output stream.
+     * <p>
+     * <b>IMPLEMENTATION NOTE </b>: The owning Manager will not be stored in the
+     * serialized representation of this Session. After calling
+     * <code>readObject()</code>, you must set the associated Manager
+     * explicitly.
+     * <p>
+     * <b>IMPLEMENTATION NOTE </b>: Any attribute that is not Serializable will
+     * be unbound from the session, with appropriate actions if it implements
+     * HttpSessionBindingListener. If you do not want any such attributes, be
+     * sure the <code>distributable</code> property of the associated Manager
+     * is set to <code>true</code>.
+     *
+     * @param stream
+     *            The output stream to write to
+     *
+     * @exception IOException
+     *                if an input/output error occurs
+     */
+    private void writeObject(ObjectOutput stream) throws IOException {
+
+        // Write the scalar instance variables (except Manager)
+        stream.writeObject(new Long(creationTime));
+        stream.writeObject(new Long(lastAccessedTime));
+        stream.writeObject(new Integer(maxInactiveInterval));
+        stream.writeObject(new Boolean(isNew));
+        stream.writeObject(new Boolean(isValid));
+        stream.writeObject(new Long(thisAccessedTime));
+        stream.writeObject(new Long(version));
+        stream.writeBoolean(getPrincipal() != null);
+        if (getPrincipal() != null) {
+            SerializablePrincipal.writePrincipal((GenericPrincipal) principal,stream);
+        }
+
+        stream.writeObject(id);
+        if (log.isDebugEnabled()) log.debug(sm.getString("deltaSession.writeSession", id));
+
+        // Accumulate the names of serializable and non-serializable attributes
+        String keys[] = keys();
+        ArrayList saveNames = new ArrayList();
+        ArrayList saveValues = new ArrayList();
+        for (int i = 0; i < keys.length; i++) {
+            Object value = null;
+            value = attributes.get(keys[i]);
+            if (value == null)
+                continue;
+            else if (value instanceof Serializable) {
+                saveNames.add(keys[i]);
+                saveValues.add(value);
+            }
+        }
+
+        // Serialize the attribute count and the Serializable attributes
+        int n = saveNames.size();
+        stream.writeObject(new Integer(n));
+        for (int i = 0; i < n; i++) {
+            stream.writeObject( (String) saveNames.get(i));
+            try {
+                stream.writeObject(saveValues.get(i));
+            } catch (NotSerializableException e) {
+                log.error(sm.getString("standardSession.notSerializable",saveNames.get(i), id), e);
+                stream.writeObject(NOT_SERIALIZED);
+                log.error("  storing attribute '" + saveNames.get(i)+ "' with value NOT_SERIALIZED");
+            }
+        }
+
+    }
+
+    // -------------------------------------------------------- Private Methods
+
+    
+
+    /**
+     * Return the value of an attribute without a check for validity.
+     */
+    protected Object getAttributeInternal(String name) {
+        return (attributes.get(name));
+    }
+
+    protected void removeAttributeInternal(String name, boolean notify,
+                                           boolean addDeltaRequest) {
+        try {
+            lock();
+            // Remove this attribute from our collection
+            Object value = attributes.get(name);
+            if (value == null) return;
+
+            super.removeAttributeInternal(name,notify);
+            if (addDeltaRequest && (deltaRequest != null)) deltaRequest.removeAttribute(name);
+
+        }finally {
+            unlock();
+        }
+    }
+
+    protected long getLastTimeReplicated() {
+        return lastTimeReplicated;
+    }
+
+    public long getVersion() {
+        return version;
+    }
+
+    protected void setLastTimeReplicated(long lastTimeReplicated) {
+        this.lastTimeReplicated = lastTimeReplicated;
+    }
+
+    public void setVersion(long version) {
+        this.version = version;
+    }
+
+    protected void setAccessCount(int count) {
+        super.accessCount = count;
+    }
+}
+
+// -------------------------------------------------------------- Private Class
+
+/**
+ * This class is a dummy implementation of the <code>HttpSessionContext</code>
+ * interface, to conform to the requirement that such an object be returned when
+ * <code>HttpSession.getSessionContext()</code> is called.
+ *
+ * @author Craig R. McClanahan
+ *
+ * @deprecated As of Java Servlet API 2.1 with no replacement. The interface
+ *             will be removed in a future version of this API.
+ */
+
+final class StandardSessionContext
+    implements HttpSessionContext {
+
+    private HashMap dummy = new HashMap();
+
+    /**
+     * Return the session identifiers of all sessions defined within this
+     * context.
+     *
+     * @deprecated As of Java Servlet API 2.1 with no replacement. This method
+     *             must return an empty <code>Enumeration</code> and will be
+     *             removed in a future version of the API.
+     */
+    public Enumeration getIds() {
+        return (new Enumerator(dummy));
+    }
+
+    /**
+     * Return the <code>HttpSession</code> associated with the specified
+     * session identifier.
+     *
+     * @param id
+     *            Session identifier for which to look up a session
+     *
+     * @deprecated As of Java Servlet API 2.1 with no replacement. This method
+     *             must return null and will be removed in a future version of
+     *             the API.
+     */
+    public HttpSession getSession(String id) {
+        return (null);
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/session/JvmRouteBinderValve.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/session/JvmRouteBinderValve.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/session/JvmRouteBinderValve.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,543 @@
+/*
+ * Copyright 1999,2004-2005 The Apache Software Foundation.
+ * 
+ * Licensed 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.ha.session;
+
+import java.io.IOException;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.Cookie;
+
+import org.apache.catalina.Container;
+import org.apache.catalina.Context;
+import org.apache.catalina.Engine;
+import org.apache.catalina.Globals;
+import org.apache.catalina.Host;
+import org.apache.catalina.Lifecycle;
+import org.apache.catalina.LifecycleException;
+import org.apache.catalina.LifecycleListener;
+import org.apache.catalina.Manager;
+import org.apache.catalina.Session;
+import org.apache.catalina.ha.CatalinaCluster;
+import org.apache.catalina.ha.ClusterManager;
+import org.apache.catalina.ha.ClusterMessage;
+import org.apache.catalina.ha.ClusterValve;
+import org.apache.catalina.connector.Request;
+import org.apache.catalina.connector.Response;
+import org.apache.catalina.session.ManagerBase;
+import org.apache.catalina.util.LifecycleSupport;
+import org.apache.catalina.util.StringManager;
+import org.apache.catalina.valves.ValveBase;
+
+/**
+ * Valve to handle Tomcat jvmRoute takeover using mod_jk module after node
+ * failure. After a node crashed the next request going to other cluster node.
+ * Now the answering from apache is slower ( make some error handshaking. Very
+ * bad with apache at my windows.). We rewrite now the cookie jsessionid
+ * information to the backup cluster node. After the next response all client
+ * request goes direct to the backup node. The change sessionid send also to all
+ * other cluster nodes. Well, now the session stickyness work directly to the
+ * backup node and traffic don't go back too restarted cluster nodes!
+ * 
+ * At all cluster node you must configure the as ClusterListener since 5.5.10
+ * {@link org.apache.catalina.ha.session.JvmRouteSessionIDBinderListener JvmRouteSessionIDBinderListener}
+ * or before with
+ * org.apache.catalina.ha.session.JvmRouteSessionIDBinderListenerLifecycle.
+ * 
+ * Add this Valve to your host definition at conf/server.xml .
+ * 
+ * Since 5.5.10 as direct cluster valve:<br/>
+ * <pre>
+ *  &lt;Cluster&gt;
+ *  &lt;Valve className=&quot;org.apache.catalina.ha.session.JvmRouteBinderValve&quot; /&gt;  
+ *  &lt;/Cluster&gt;
+ * </pre>
+ * <br />
+ * Before 5.5.10 as Host element:<br/>
+ * <pre>
+ *  &lt;Hostr&gt;
+ *  &lt;Valve className=&quot;org.apache.catalina.ha.session.JvmRouteBinderValve&quot; /&gt;  
+ *  &lt;/Hostr&gt;
+ * </pre>
+ * 
+ * Trick:<br/>
+ * You can enable this mod_jk turnover mode via JMX before you drop a node to all backup nodes!
+ * Set enable true on all JvmRouteBinderValve backups, disable worker at mod_jk 
+ * and then drop node and restart it! Then enable mod_jk Worker and disable JvmRouteBinderValves again. 
+ * This use case means that only requested session are migrated.
+ * 
+ * @author Peter Rossbach
+ * @version $Revision: 326110 $ $Date: 2005-10-18 09:08:36 -0500 (Tue, 18 Oct 2005) $
+ */
+public class JvmRouteBinderValve extends ValveBase implements ClusterValve, Lifecycle {
+
+    /*--Static Variables----------------------------------------*/
+    public static org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory
+            .getLog(JvmRouteBinderValve.class);
+
+    /**
+     * The descriptive information about this implementation.
+     */
+    protected static final String info = "org.apache.catalina.ha.session.JvmRouteBinderValve/1.2";
+
+    /*--Instance Variables--------------------------------------*/
+
+    /**
+     * the cluster
+     */
+    protected CatalinaCluster cluster;
+
+    /**
+     * The string manager for this package.
+     */
+    protected StringManager sm = StringManager.getManager(Constants.Package);
+
+    /**
+     * Has this component been started yet?
+     */
+    protected boolean started = false;
+
+    /**
+     * enabled this component
+     */
+    protected boolean enabled = true;
+
+    /**
+     * number of session that no at this tomcat instanz hosted
+     */
+    protected long numberOfSessions = 0;
+
+    protected String sessionIdAttribute = "org.apache.catalina.ha.session.JvmRouteOrignalSessionID";
+
+    /**
+     * The lifecycle event support for this component.
+     */
+    protected LifecycleSupport lifecycle = new LifecycleSupport(this);
+
+    /*--Logic---------------------------------------------------*/
+
+    /**
+     * Return descriptive information about this implementation.
+     */
+    public String getInfo() {
+
+        return (info);
+
+    }
+
+    /**
+     * set session id attribute to failed node for request.
+     * 
+     * @return Returns the sessionIdAttribute.
+     */
+    public String getSessionIdAttribute() {
+        return sessionIdAttribute;
+    }
+
+    /**
+     * get name of failed reqeust session attribute
+     * 
+     * @param sessionIdAttribute
+     *            The sessionIdAttribute to set.
+     */
+    public void setSessionIdAttribute(String sessionIdAttribute) {
+        this.sessionIdAttribute = sessionIdAttribute;
+    }
+
+    /**
+     * @return Returns the number of migrated sessions.
+     */
+    public long getNumberOfSessions() {
+        return numberOfSessions;
+    }
+
+    /**
+     * @return Returns the enabled.
+     */
+    public boolean getEnabled() {
+        return enabled;
+    }
+
+    /**
+     * @param enabled
+     *            The enabled to set.
+     */
+    public void setEnabled(boolean enabled) {
+        this.enabled = enabled;
+    }
+
+    /**
+     * Detect possible the JVMRoute change at cluster backup node..
+     * 
+     * @param request
+     *            tomcat request being processed
+     * @param response
+     *            tomcat response being processed
+     * @exception IOException
+     *                if an input/output error has occurred
+     * @exception ServletException
+     *                if a servlet error has occurred
+     */
+    public void invoke(Request request, Response response) throws IOException,
+            ServletException {
+
+         if (getEnabled() 
+             && getCluster() != null
+             && request.getContext() != null
+             && request.getContext().getDistributable() ) {
+             // valve cluster can access manager - other cluster handle turnover 
+             // at host level - hopefully!
+             Manager manager = request.getContext().getManager();
+             if (manager != null && manager instanceof ClusterManager
+                     && getCluster().getManager(((ClusterManager)manager).getName()) != null)
+                 handlePossibleTurnover(request, response);
+        }
+        // Pass this request on to the next valve in our pipeline
+        getNext().invoke(request, response);
+    }
+
+    /**
+     * handle possible session turn over.
+     * 
+     * @see JvmRouteBinderValve#handleJvmRoute(Request, Response, String, String)
+     * @param request current request
+     * @param response current response
+     */
+    protected void handlePossibleTurnover(Request request, Response response) {
+        Session session = request.getSessionInternal(false);
+        if (session != null) {
+            long t1 = System.currentTimeMillis();
+            String jvmRoute = getLocalJvmRoute(request);
+            if (jvmRoute == null) {
+                if (log.isWarnEnabled())
+                    log.warn(sm.getString("jvmRoute.missingJvmRouteAttribute"));
+                return;
+            }
+            handleJvmRoute( request, response,session.getIdInternal(), jvmRoute);
+            if (log.isDebugEnabled()) {
+                long t2 = System.currentTimeMillis();
+                long time = t2 - t1;
+                log.debug(sm.getString("jvmRoute.turnoverInfo", new Long(time)));
+            }
+        }
+    }
+
+    /**
+     * get jvmroute from engine
+     * 
+     * @param request current request
+     * @return return jvmRoute from ManagerBase or null
+     */
+    protected String getLocalJvmRoute(Request request) {
+        Manager manager = getManager(request);
+        if(manager instanceof ManagerBase)
+            return ((ManagerBase) manager).getJvmRoute();
+        return null ;
+    }
+
+    /**
+     * get Cluster DeltaManager
+     * 
+     * @param request current request
+     * @return manager or null
+     */
+    protected Manager getManager(Request request) {
+        Manager manager = request.getContext().getManager();
+        if (log.isDebugEnabled()) {
+            if(manager != null)
+                log.debug(sm.getString("jvmRoute.foundManager", manager,  request.getContext().getName()));
+            else 
+                log.debug(sm.getString("jvmRoute.notFoundManager", manager,  request.getContext().getName()));
+        }
+        return manager;
+    }
+
+    /**
+     * @return Returns the cluster.
+     */
+    public CatalinaCluster getCluster() {
+        return cluster;
+    }
+    
+    /**
+     * @param cluster The cluster to set.
+     */
+    public void setCluster(CatalinaCluster cluster) {
+        this.cluster = cluster;
+    }
+    
+    /**
+     * Handle jvmRoute stickyness after tomcat instance failed. After this
+     * correction a new Cookie send to client with new jvmRoute and the
+     * SessionID change propage to the other cluster nodes.
+     * 
+     * @param request current request
+     * @param response
+     *            Tomcat Response
+     * @param sessionId
+     *            request SessionID from Cookie
+     * @param localJvmRoute
+     *            local jvmRoute
+     */
+    protected void handleJvmRoute(
+            Request request, Response response,String sessionId, String localJvmRoute) {
+        // get requested jvmRoute.
+        String requestJvmRoute = null;
+        int index = sessionId.indexOf(".");
+        if (index > 0) {
+            requestJvmRoute = sessionId
+                    .substring(index + 1, sessionId.length());
+        }
+        if (requestJvmRoute != null && !requestJvmRoute.equals(localJvmRoute)) {
+            if (log.isDebugEnabled()) {
+                log.debug(sm.getString("jvmRoute.failover", requestJvmRoute,
+                        localJvmRoute, sessionId));
+            }
+            // OK - turnover the session ?
+            String newSessionID = sessionId.substring(0, index) + "."
+                    + localJvmRoute;
+            Session catalinaSession = null;
+            try {
+                catalinaSession = getManager(request).findSession(sessionId);
+            } catch (IOException e) {
+                // Hups!
+            }
+            if (catalinaSession != null) {
+                changeSessionID(request, response, sessionId, newSessionID,
+                        catalinaSession);
+                numberOfSessions++;
+            } else {
+                if (log.isDebugEnabled()) {
+                    log.debug(sm.getString("jvmRoute.cannotFindSession",
+                            sessionId));
+                }
+            }
+        }
+    }
+
+    /**
+     * change session id and send to all cluster nodes
+     * 
+     * @param request current request
+     * @param response current response
+     * @param sessionId
+     *            original session id
+     * @param newSessionID
+     *            new session id for node migration
+     * @param catalinaSession
+     *            current session with original session id
+     */
+    protected void changeSessionID(Request request,
+            Response response, String sessionId, String newSessionID, Session catalinaSession) {
+        lifecycle.fireLifecycleEvent("Before session migration",
+                catalinaSession);
+        request.setRequestedSessionId(newSessionID);
+        catalinaSession.setId(newSessionID);
+        if (catalinaSession instanceof DeltaSession)
+            ((DeltaSession) catalinaSession).resetDeltaRequest();
+        if(request.isRequestedSessionIdFromCookie()) setNewSessionCookie(request, response,newSessionID);
+        // set orginal sessionid at request, to allow application detect the
+        // change
+        if (sessionIdAttribute != null && !"".equals(sessionIdAttribute)) {
+            if (log.isDebugEnabled()) {
+                log.debug(sm.getString("jvmRoute.set.orignalsessionid",sessionIdAttribute,sessionId));
+            }
+            request.setAttribute(sessionIdAttribute, sessionId);
+        }
+        // now sending the change to all other clusternode!
+        ClusterManager manager = (ClusterManager)catalinaSession.getManager();
+        sendSessionIDClusterBackup(manager,request,sessionId, newSessionID);
+        lifecycle
+                .fireLifecycleEvent("After session migration", catalinaSession);
+        if (log.isDebugEnabled()) {
+            log.debug(sm.getString("jvmRoute.changeSession", sessionId,
+                    newSessionID));
+        }
+    }
+
+    /**
+     * Send the changed Sessionid to all clusternodes.
+     * 
+     * @see JvmRouteSessionIDBinderListener#messageReceived(ClusterMessage)
+     * @param manager
+     *            ClusterManager
+     * @param sessionId
+     *            current failed sessionid
+     * @param newSessionID
+     *            new session id, bind to the new cluster node
+     */
+    protected void sendSessionIDClusterBackup(ClusterManager manager,Request request,String sessionId,
+            String newSessionID) {
+        SessionIDMessage msg = new SessionIDMessage();
+        msg.setOrignalSessionID(sessionId);
+        msg.setBackupSessionID(newSessionID);
+        Context context = request.getContext();
+        msg.setContextPath(context.getPath());
+        msg.setHost(context.getParent().getName());
+        if(manager.isSendClusterDomainOnly())
+            cluster.sendClusterDomain(msg);
+        else
+            cluster.send(msg);
+    }
+
+    /**
+     * Sets a new cookie for the given session id and response and see
+     * {@link org.apache.catalina.connector.Request#configureSessionCookie(javax.servlet.http.Cookie)}
+     * 
+     * @param request current request
+     * @param response Tomcat Response
+     * @param sessionId The session id
+     */
+    protected void setNewSessionCookie(Request request,
+                                       Response response, String sessionId) {
+        if (response != null) {
+            Context context = request.getContext();
+            if (context.getCookies()) {
+                // set a new session cookie
+                Cookie newCookie = new Cookie(Globals.SESSION_COOKIE_NAME,
+                        sessionId);
+                newCookie.setMaxAge(-1);
+                String contextPath = null;
+                if (!response.getConnector().getEmptySessionPath()
+                        && (context != null)) {
+                    contextPath = context.getEncodedPath();
+                }
+                if ((contextPath != null) && (contextPath.length() > 0)) {
+                    newCookie.setPath(contextPath);
+                } else {
+                    newCookie.setPath("/");
+                }
+                if (request.isSecure()) {
+                    newCookie.setSecure(true);
+                }
+                if (log.isDebugEnabled()) {
+                    log.debug(sm.getString("jvmRoute.newSessionCookie",
+                            sessionId, Globals.SESSION_COOKIE_NAME, newCookie
+                                    .getPath(), new Boolean(newCookie
+                                    .getSecure())));
+                }
+                response.addCookie(newCookie);
+            }
+        }
+    }
+
+    // ------------------------------------------------------ Lifecycle Methods
+
+    /**
+     * Add a lifecycle event listener to this component.
+     * 
+     * @param listener
+     *            The listener to add
+     */
+    public void addLifecycleListener(LifecycleListener listener) {
+
+        lifecycle.addLifecycleListener(listener);
+
+    }
+
+    /**
+     * Get the lifecycle listeners associated with this lifecycle. If this
+     * Lifecycle has no listeners registered, a zero-length array is returned.
+     */
+    public LifecycleListener[] findLifecycleListeners() {
+
+        return lifecycle.findLifecycleListeners();
+
+    }
+
+    /**
+     * Remove a lifecycle event listener from this component.
+     * 
+     * @param listener
+     *            The listener to add
+     */
+    public void removeLifecycleListener(LifecycleListener listener) {
+
+        lifecycle.removeLifecycleListener(listener);
+
+    }
+
+    /**
+     * Prepare for the beginning of active use of the public methods of this
+     * component. This method should be called after <code>configure()</code>,
+     * and before any of the public methods of the component are utilized.
+     * 
+     * @exception LifecycleException
+     *                if this component detects a fatal error that prevents this
+     *                component from being used
+     */
+    public void start() throws LifecycleException {
+
+        // Validate and update our current component state
+        if (started)
+            throw new LifecycleException(sm
+                    .getString("jvmRoute.valve.alreadyStarted"));
+        lifecycle.fireLifecycleEvent(START_EVENT, null);
+        started = true;
+        if (cluster == null) {
+            Container hostContainer = getContainer();
+            // compatibility with JvmRouteBinderValve version 1.1
+            // ( setup at context.xml or context.xml.default )
+            if (!(hostContainer instanceof Host)) {
+                if (log.isWarnEnabled())
+                    log.warn(sm.getString("jvmRoute.configure.warn"));
+                hostContainer = hostContainer.getParent();
+            }
+            if (hostContainer instanceof Host
+                    && ((Host) hostContainer).getCluster() != null) {
+                cluster = (CatalinaCluster) ((Host) hostContainer).getCluster();
+            } else {
+                Container engine = hostContainer.getParent() ;
+                if (engine instanceof Engine
+                        && ((Engine) engine).getCluster() != null) {
+                    cluster = (CatalinaCluster) ((Engine) engine).getCluster();
+                }
+            }
+        }
+        if (cluster == null) {
+            throw new RuntimeException("No clustering support at container "
+                    + container.getName());
+        }
+        
+        if (log.isInfoEnabled())
+            log.info(sm.getString("jvmRoute.valve.started"));
+
+    }
+
+    /**
+     * Gracefully terminate the active use of the public methods of this
+     * component. This method should be the last one called on a given instance
+     * of this component.
+     * 
+     * @exception LifecycleException
+     *                if this component detects a fatal error that needs to be
+     *                reported
+     */
+    public void stop() throws LifecycleException {
+
+        // Validate and update our current component state
+        if (!started)
+            throw new LifecycleException(sm
+                    .getString("jvmRoute.valve.notStarted"));
+        lifecycle.fireLifecycleEvent(STOP_EVENT, null);
+        started = false;
+        cluster = null;
+        numberOfSessions = 0;
+        if (log.isInfoEnabled())
+            log.info(sm.getString("jvmRoute.valve.stopped"));
+
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/session/JvmRouteSessionIDBinderLifecycleListener.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/session/JvmRouteSessionIDBinderLifecycleListener.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/session/JvmRouteSessionIDBinderLifecycleListener.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,216 @@
+/*
+ * Copyright 1999,2004-2005 The Apache Software Foundation.
+ *
+ * Licensed 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.ha.session;
+
+import javax.management.MBeanServer;
+import javax.management.MBeanServerFactory;
+import javax.management.MalformedObjectNameException;
+import javax.management.ObjectName;
+import javax.management.modelmbean.ModelMBean;
+
+import org.apache.catalina.Lifecycle;
+import org.apache.catalina.LifecycleEvent;
+import org.apache.catalina.LifecycleListener;
+import org.apache.catalina.ha.CatalinaCluster;
+
+import org.apache.catalina.core.StandardHost;
+import org.apache.catalina.util.StringManager;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.commons.modeler.ManagedBean;
+import org.apache.commons.modeler.Registry;
+import org.apache.catalina.ha.*;
+
+/**
+ * Register new JvmRouteSessionIDBinderListener to receive Session ID changes.
+ * 
+ * add following at your server.xml Host section
+ * 
+ * <pre>
+ *        &lt;Host &gt;... 
+ *          &lt;Listener className=&quot;org.apache.catalina.ha.session.JvmRouteSessionIDBinderLifecycleListener&quot; /&gt;
+ *          &lt;Cluster ...&gt;
+ *        &lt;/Host&gt;
+ * </pre>
+ * FIXME add Engine support
+ * @deprecated
+ * @author Peter Rossbach
+ */
+public class JvmRouteSessionIDBinderLifecycleListener implements
+        LifecycleListener {
+    private static Log log = LogFactory
+            .getLog(JvmRouteSessionIDBinderLifecycleListener.class);
+
+    /**
+     * The descriptive information string for this implementation.
+     */
+    private static final String info = "org.apache.catalina.ha.session.JvmRouteSessionIDBinderLifecycleListener/1.0";
+
+    /**
+     * The string resources for this package.
+     */
+    protected static final StringManager sm = StringManager
+            .getManager(Constants.Package);
+
+    private boolean enabled = true;
+
+    private MBeanServer mserver = null;
+
+    private Registry registry = null;
+
+    private ClusterListener sessionMoverListener;
+
+    /*
+     * start and stop cluster
+     * 
+     * @see org.apache.catalina.LifecycleListener#lifecycleEvent(org.apache.catalina.LifecycleEvent)
+     */
+    public void lifecycleEvent(LifecycleEvent event) {
+
+        if (enabled && event.getSource() instanceof StandardHost) {
+
+            if (Lifecycle.AFTER_START_EVENT.equals(event.getType())) {
+                if (log.isDebugEnabled())
+                    log.debug(sm.getString("jvmRoute.listener.started"));
+                startSessionIDListener((StandardHost) event.getSource());
+            } else if (Lifecycle.BEFORE_STOP_EVENT.equals(event.getType())) {
+                if (log.isDebugEnabled())
+                    log.debug(sm.getString("jvmRoute.listener.stopped"));
+                stopSessionIDListener((StandardHost) event.getSource());
+            }
+        }
+    }
+
+    /**
+     * stop sessionID binder at cluster
+     * 
+     * @param host
+     *            clustered host
+     */
+    protected void stopSessionIDListener(StandardHost host) {
+        if (sessionMoverListener != null) {
+            CatalinaCluster cluster = (CatalinaCluster) host.getCluster();
+            cluster.removeClusterListener(sessionMoverListener);
+            if (mserver != null) {
+                try {
+                    ObjectName objectName = getObjectName(host);
+                    mserver.unregisterMBean(objectName);
+                } catch (Exception e) {
+                    log.error(e);
+                }
+            }
+        }
+    }
+
+    /**
+     * @param host
+     * @return The object name
+     * @throws MalformedObjectNameException
+     */
+    protected ObjectName getObjectName(StandardHost host) throws MalformedObjectNameException {
+        ObjectName objectName = new ObjectName(
+                host.getDomain()
+                        + ":type=Listener,name=JvmRouteSessionIDBinderListener,host=" + host.getName());
+        return objectName;
+    }
+
+    /**
+     * start sessionID mover at cluster
+     * 
+     * @param host
+     *            clustered host
+     */
+    protected void startSessionIDListener(StandardHost host) {
+        try {
+            ObjectName objectName = null;
+            getMBeanServer();
+            objectName = getObjectName(host);
+            if (mserver.isRegistered(objectName)) {
+                if (log.isInfoEnabled())
+                    log.info(sm.getString("jvmRoute.run.already"));
+                return;
+            }
+            sessionMoverListener = new JvmRouteSessionIDBinderListener();
+            mserver.registerMBean(getManagedBean(sessionMoverListener),
+                    objectName);
+            CatalinaCluster cluster = (CatalinaCluster) host.getCluster();
+            sessionMoverListener.setCluster(cluster);
+            ((JvmRouteSessionIDBinderListener) sessionMoverListener).start();
+        } catch (Exception ex) {
+            log.error(ex.getMessage(), ex);
+        }
+    }
+
+    protected MBeanServer getMBeanServer() throws Exception {
+        if (mserver == null) {
+            if (MBeanServerFactory.findMBeanServer(null).size() > 0) {
+                mserver = (MBeanServer) MBeanServerFactory
+                        .findMBeanServer(null).get(0);
+            } else {
+                mserver = MBeanServerFactory.createMBeanServer();
+            }
+            registry = Registry.getRegistry(null, null);
+            registry.loadMetadata(this.getClass().getResourceAsStream(
+                    "mbeans-descriptors.xml"));
+        }
+        return (mserver);
+    }
+
+    /**
+     * Returns the ModelMBean
+     * 
+     * @param object
+     *            The Object to get the ModelMBean for
+     * @return The ModelMBean
+     * @throws Exception
+     *             If an error occurs this constructors throws this exception
+     */
+    protected ModelMBean getManagedBean(Object object) throws Exception {
+        ModelMBean mbean = null;
+        if (registry != null) {
+            ManagedBean managedBean = registry.findManagedBean(object
+                    .getClass().getName());
+            mbean = managedBean.createMBean(object);
+        }
+        return mbean;
+    }
+
+    /**
+     * @return Returns the enabled.
+     */
+    public boolean isEnabled() {
+        return enabled;
+    }
+
+    /**
+     * @param enabled
+     *            The enabled to set.
+     */
+    public void setEnabled(boolean enabled) {
+        this.enabled = enabled;
+    }
+
+    /**
+     * Return descriptive information about this Listener implementation and the
+     * corresponding version number, in the format
+     * <code>&lt;description&gt;/&lt;version&gt;</code>.
+     */
+    public String getInfo() {
+
+        return (info);
+
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/session/JvmRouteSessionIDBinderListener.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/session/JvmRouteSessionIDBinderListener.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/session/JvmRouteSessionIDBinderListener.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,166 @@
+/*
+ * Copyright 1999,2004-2005 The Apache Software Foundation.
+ *
+ * Licensed 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.ha.session;
+
+import java.io.IOException;
+
+import org.apache.catalina.Container;
+import org.apache.catalina.Context;
+import org.apache.catalina.Engine;
+import org.apache.catalina.LifecycleException;
+import org.apache.catalina.Session;
+import org.apache.catalina.ha.ClusterMessage;
+import org.apache.catalina.core.StandardEngine;
+import org.apache.catalina.ha.*;
+
+/**
+ * Receive SessionID cluster change from other backup node after primary session
+ * node is failed.
+ * 
+ * @author Peter Rossbach
+ * @version $Revision: 378258 $ $Date: 2006-02-16 08:42:35 -0600 (Thu, 16 Feb 2006) $
+ */
+public class JvmRouteSessionIDBinderListener extends ClusterListener {
+ 
+    /**
+     * The descriptive information about this implementation.
+     */
+    protected static final String info = "org.apache.catalina.ha.session.JvmRouteSessionIDBinderListener/1.1";
+
+    //--Instance Variables--------------------------------------
+
+
+    protected boolean started = false;
+
+    /**
+     * number of session that goes to this cluster node
+     */
+    private long numberOfSessions = 0;
+
+    //--Constructor---------------------------------------------
+
+    public JvmRouteSessionIDBinderListener() {
+    }
+
+    //--Logic---------------------------------------------------
+
+    /**
+     * Return descriptive information about this implementation.
+     */
+    public String getInfo() {
+
+        return (info);
+
+    }
+
+    /**
+     * @return Returns the numberOfSessions.
+     */
+    public long getNumberOfSessions() {
+        return numberOfSessions;
+    }
+
+    /**
+     * Add this Mover as Cluster Listener ( receiver)
+     * 
+     * @throws LifecycleException
+     */
+    public void start() throws LifecycleException {
+        if (started)
+            return;
+        getCluster().addClusterListener(this);
+        started = true;
+        if (log.isInfoEnabled())
+            log.info(sm.getString("jvmRoute.clusterListener.started"));
+    }
+
+    /**
+     * Remove this from Cluster Listener
+     * 
+     * @throws LifecycleException
+     */
+    public void stop() throws LifecycleException {
+        started = false;
+        getCluster().removeClusterListener(this);
+        if (log.isInfoEnabled())
+            log.info(sm.getString("jvmRoute.clusterListener.stopped"));
+    }
+
+    /**
+     * Callback from the cluster, when a message is received, The cluster will
+     * broadcast it invoking the messageReceived on the receiver.
+     * 
+     * @param msg
+     *            ClusterMessage - the message received from the cluster
+     */
+    public void messageReceived(ClusterMessage msg) {
+        if (msg instanceof SessionIDMessage && msg != null) {
+            SessionIDMessage sessionmsg = (SessionIDMessage) msg;
+            if (log.isDebugEnabled())
+                log.debug(sm.getString(
+                        "jvmRoute.receiveMessage.sessionIDChanged", sessionmsg
+                                .getOrignalSessionID(), sessionmsg
+                                .getBackupSessionID(), sessionmsg
+                                .getContextPath()));
+            Container container = getCluster().getContainer();
+            Container host = null ;
+            if(container instanceof Engine) {
+                host = container.findChild(sessionmsg.getHost());
+            } else {
+                host = container ;
+            }
+            if (host != null) {
+                Context context = (Context) host.findChild(sessionmsg
+                        .getContextPath());
+                if (context != null) {
+                    try {
+                        Session session = context.getManager().findSession(
+                                sessionmsg.getOrignalSessionID());
+                        if (session != null) {
+                            session.setId(sessionmsg.getBackupSessionID());
+                        } else if (log.isInfoEnabled())
+                            log.info(sm.getString("jvmRoute.lostSession",
+                                    sessionmsg.getOrignalSessionID(),
+                                    sessionmsg.getContextPath()));
+                    } catch (IOException e) {
+                        log.error(e);
+                    }
+
+                } else if (log.isErrorEnabled())
+                    log.error(sm.getString("jvmRoute.contextNotFound",
+                            sessionmsg.getContextPath(), ((StandardEngine) host
+                                    .getParent()).getJvmRoute()));
+            } else if (log.isErrorEnabled())
+                log.error(sm.getString("jvmRoute.hostNotFound", sessionmsg.getContextPath()));
+        }
+        return;
+    }
+
+    /**
+     * Accept only SessionIDMessages
+     * 
+     * @param msg
+     *            ClusterMessage
+     * @return boolean - returns true to indicate that messageReceived should be
+     *         invoked. If false is returned, the messageReceived method will
+     *         not be invoked.
+     */
+    public boolean accept(ClusterMessage msg) {
+        return (msg instanceof SessionIDMessage);
+    }
+}
+

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/session/LocalStrings.properties
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/session/LocalStrings.properties	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/session/LocalStrings.properties	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,96 @@
+deltaManager.createSession.ise=createSession: Too many active sessions
+deltaManager.createSession.newSession=Created a DeltaSession with Id [{0}] Total count={1}
+deltaManager.createMessage.access=Manager [{0}]: create session message [{1}] access.
+deltaManager.createMessage.accessChangePrimary=Manager [{0}]: create session message [{1}] access to change primary.
+deltaManager.createMessage.allSessionData=Manager [{0}] send all session data.
+deltaManager.createMessage.allSessionTransfered=Manager [{0}] send all session data transfered
+deltaManager.createMessage.delta=Manager [{0}]: create session message [{1}] delta request.
+deltaManager.createMessage.expire=Manager [{0}]: create session message [{1}] expire.
+deltaManager.createMessage.unableCreateDeltaRequest=Unable to serialize delta request for sessionid [{0}]
+deltaManager.dropMessage=Manager [{0}]: Drop message {1} inside GET_ALL_SESSIONS sync phase start date {2} message date {3}
+deltaManager.foundMasterMember=Found for context [{0}] the replication master member [{1}]
+deltaManager.loading.cnfe=ClassNotFoundException while loading persisted sessions: {0}
+deltaManager.loading.existing.session=overload existing session {0} 
+deltaManager.loading.ioe=IOException while loading persisted sessions: {0}
+deltaManager.loading.withContextClassLoader=Manager [{0}]: Loading the object data with a context class loader.
+deltaManager.loading.withoutClassLoader=Manager [{0}]: Loading the object data without a context class loader.
+deltaManager.managerLoad=Exception loading sessions from persistent storage
+deltaManager.noCluster=Starting... no cluster associated with this context: [{0}]
+deltaManager.noMasterMember=Starting... with no other member for context [{0}] at domain [{1}]
+deltaManager.noMembers=Manager [{0}]: skipping state transfer. No members active in cluster group.
+deltaManager.noSessionState=Manager [{0}]: No session state send at {1} received, timing out after {2} ms.
+deltaManager.notStarted=Manager has not yet been started
+deltaManager.sendMessage.newSession=Manager [{0}] send new session ({1})
+deltaManager.expireSessions=Manager [{0}] expiring sessions upon shutdown
+deltaManager.receiveMessage.accessed=Manager [{0}]: received session [{1}] accessed.
+deltaManager.receiveMessage.createNewSession=Manager [{0}]: received session [{1}] created.
+deltaManager.receiveMessage.delta=Manager [{0}]: received session [{1}] delta.
+deltaManager.receiveMessage.error=Manager [{0}]: Unable to receive message through TCP channel
+deltaManager.receiveMessage.eventType=Manager [{0}]: Received SessionMessage of type=({1}) from [{2}]
+deltaManager.receiveMessage.expired=Manager [{0}]: received session [{1}] expired.
+deltaManager.receiveMessage.transfercomplete=Manager [{0}] received from node [{1}:{2}] session state transfered.
+deltaManager.receiveMessage.unloadingAfter=Manager [{0}]: unloading sessions complete
+deltaManager.receiveMessage.unloadingBegin=Manager [{0}]: start unloading sessions
+deltaManager.receiveMessage.allSessionDataAfter=Manager [{0}]: session state deserialized
+deltaManager.receiveMessage.allSessionDataBegin=Manager [{0}]: received session state data
+deltaManager.receiveMessage.fromWrongDomain=Manager [{0}]: Received wrong SessionMessage of type=({1}) from [{2}] with domain [{3}] (localdomain [{4}] 
+deltaManager.registerCluster=Register manager {0} to cluster element {1} with name {2}
+deltaManager.sessionReceived=Manager [{0}]; session state send at {1} received in {2} ms.
+deltaManager.sessionTimeout=Invalid session timeout setting {0}
+deltaManager.startClustering=Starting clustering manager at {0}
+deltaManager.stopped=Manager [{0}] is stopping
+deltaManager.unloading.ioe=IOException while saving persisted sessions: {0}
+deltaManager.waitForSessionState=Manager [{0}], requesting session state from {1}. This operation will timeout if no session state has been received within 60 seconds.
+deltaRequest.showPrincipal=Principal [{0}] is set to session {1}
+deltaRequest.wrongPrincipalClass=DeltaManager only support GenericPrincipal. Your realm used principal class {0}.
+deltaSession.notifying=Notifying cluster of expiration primary={0} sessionId [{1}]
+deltaSession.valueBound.ex=Session bound listener throw an exception
+deltaSession.valueBinding.ex=Session binding listener throw an exception
+deltaSession.valueUnbound.ex=Session unbound listener throw an exception
+deltaSession.readSession=readObject() loading session [{0}]
+deltaSession.readAttribute=session [{0}] loading attribute '{1}' with value '{2}'
+deltaSession.writeSession=writeObject() storing session [{0}]
+jvmRoute.cannotFindSession=Can't find session [{0}]
+jvmRoute.changeSession=Changed session from [{0}] to [{1}]
+jvmRoute.clusterListener.started=Cluster JvmRouteSessionIDBinderListener started
+jvmRoute.clusterListener.stopped=Cluster JvmRouteSessionIDBinderListener stopped
+jvmRoute.configure.warn=Please, setup your JvmRouteBinderValve at host valve, not at context valve!
+jvmRoute.contextNotFound=Context [{0}] not found at node [{1}]!
+jvmRoute.failover=Detected a failover with different jvmRoute - orginal route: [{0}] new one: [{1}] at session id [{2}]
+jvmRoute.foundManager=Found Cluster DeltaManager {0} at {1}
+jvmRoute.hostNotFound=No host found [{0}]
+jvmRoute.listener.started=SessionID Binder Listener started
+jvmRoute.listener.stopped=SessionID Binder Listener stopped
+jvmRoute.lostSession=Lost Session [{0}] at path [{1}]
+jvmRoute.missingJvmRouteAttribute=No engine jvmRoute attribute configured!
+jvmRoute.newSessionCookie=Setting cookie with session id [{0}] name: [{1}] path: [{2}] secure: [{3}]
+jvmRoute.notFoundManager=Not found Cluster DeltaManager {0} at {1}
+jvmRoute.receiveMessage.sessionIDChanged=Cluster JvmRouteSessionIDBinderListener received orginal session ID [{0}] set to new id [{1}] for context path [{2}]
+jvmRoute.run.already=jvmRoute SessionID receiver run already
+jvmRoute.skipURLSessionIDs=Skip reassign jvm route check, sessionid comes from URL!
+jvmRoute.turnoverInfo=Turnover Check time {0} msec
+jvmRoute.valve.alreadyStarted=jvmRoute backup sessionID correction is started
+jvmRoute.valve.notStarted=jvmRoute backup sessionID correction run already
+jvmRoute.valve.started=JvmRouteBinderValve started
+jvmRoute.valve.stopped=JvmRouteBinderValve stopped
+jvmRoute.set.orignalsessionid=Set Orginal Session id at request attriute {0} value: {1}
+standardSession.getId.ise=getId: Session already invalidated
+standardSession.attributeEvent=Session attribute event listener threw exception
+standardSession.attributeEvent=Session attribute event listener threw exception
+standardSession.bindingEvent=Session binding event listener threw exception
+standardSession.invalidate.ise=invalidate: Session already invalidated
+standardSession.isNew.ise=isNew: Session already invalidated
+standardSession.getAttribute.ise=getAttribute: Session already invalidated
+standardSession.getAttributeNames.ise=getAttributeNames: Session already invalidated
+standardSession.getCreationTime.ise=getCreationTime: Session already invalidated
+standardSession.getLastAccessedTime.ise=getLastAccessedTime: Session already invalidated
+standardSession.getId.ise=getId: Session already invalidated
+standardSession.getMaxInactiveInterval.ise=getMaxInactiveInterval: Session already invalidated
+standardSession.getValueNames.ise=getValueNames: Session already invalidated
+standardSession.notSerializable=Cannot serialize session attribute {0} for session {1}
+standardSession.removeAttribute.ise=removeAttribute: Session already invalidated
+standardSession.sessionEvent=Session event listener threw exception
+standardSession.setAttribute.iae=setAttribute: Non-serializable attribute
+standardSession.setAttribute.ise=setAttribute: Session already invalidated
+standardSession.setAttribute.namenull=setAttribute: name parameter cannot be null
+standardSession.sessionCreated=Created Session id = {0}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/session/ReplicatedSession.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/session/ReplicatedSession.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/session/ReplicatedSession.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,285 @@
+
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.ha.session;
+
+/**
+ * Title:        Tomcat Session Replication for Tomcat 4.0 <BR>
+ * Description:  A very simple straight forward implementation of
+ *               session replication of servers in a cluster.<BR>
+ *               This session replication is implemented "live". By live
+ *               I mean, when a session attribute is added into a session on Node A
+ *               a message is broadcasted to other messages and setAttribute is called on the replicated
+ *               sessions.<BR>
+ *               A full description of this implementation can be found under
+ *               <href="http://www.filip.net/tomcat/">Filip's Tomcat Page</a><BR>
+ *
+ * Copyright:    See apache license
+ * @author  Filip Hanik
+ * @version $Revision: 303842 $ $Date: 2005-04-10 11:20:46 -0500 (Sun, 10 Apr 2005) $
+ * Description:<BR>
+ * The ReplicatedSession class is a simple extension of the StandardSession class
+ * It overrides a few methods (setAttribute, removeAttribute, expire, access) and has
+ * hooks into the InMemoryReplicationManager to broadcast and receive events from the cluster.<BR>
+ * This class inherits the readObjectData and writeObject data methods from the StandardSession
+ * and does not contain any serializable elements in addition to the inherited ones from the StandardSession
+ *
+ */
+import org.apache.catalina.Manager;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.security.Principal;
+
+public class ReplicatedSession extends org.apache.catalina.session.StandardSession
+implements org.apache.catalina.ha.ClusterSession{
+
+    private transient Manager mManager = null;
+    protected boolean isDirty = false;
+    private transient long lastAccessWasDistributed = System.currentTimeMillis();
+    private boolean isPrimarySession=true;
+    
+
+    public ReplicatedSession(Manager manager) {
+        super(manager);
+        mManager = manager;
+    }
+
+
+    public boolean isDirty()
+    {
+        return isDirty;
+    }
+
+    public void setIsDirty(boolean dirty)
+    {
+        isDirty = dirty;
+    }
+
+
+    public void setLastAccessWasDistributed(long time) {
+        lastAccessWasDistributed = time;
+    }
+
+    public long getLastAccessWasDistributed() {
+        return lastAccessWasDistributed;
+    }
+
+
+    public void removeAttribute(String name) {
+        setIsDirty(true);
+        super.removeAttribute(name);
+    }
+
+    /**
+     * see parent description,
+     * plus we also notify other nodes in the cluster
+     */
+    public void removeAttribute(String name, boolean notify) {
+        setIsDirty(true);
+        super.removeAttribute(name,notify);
+    }
+
+
+    /**
+     * Sets an attribute and notifies the other nodes in the cluster
+     */
+    public void setAttribute(String name, Object value)
+    {
+        if ( value == null ) {
+          removeAttribute(name);
+          return;
+        }
+        if (!(value instanceof java.io.Serializable))
+            throw new java.lang.IllegalArgumentException("Value for attribute "+name+" is not serializable.");
+        setIsDirty(true);
+        super.setAttribute(name,value);
+    }
+
+    public void setMaxInactiveInterval(int interval) {
+        setIsDirty(true);
+        super.setMaxInactiveInterval(interval);
+    }
+
+
+    /**
+     * Sets the manager for this session
+     * @param mgr - the servers InMemoryReplicationManager
+     */
+    public void setManager(SimpleTcpReplicationManager mgr)
+    {
+        mManager = mgr;
+        super.setManager(mgr);
+    }
+
+
+    /**
+     * Set the authenticated Principal that is associated with this Session.
+     * This provides an <code>Authenticator</code> with a means to cache a
+     * previously authenticated Principal, and avoid potentially expensive
+     * <code>Realm.authenticate()</code> calls on every request.
+     *
+     * @param principal The new Principal, or <code>null</code> if none
+     */
+    public void setPrincipal(Principal principal) {
+        super.setPrincipal(principal);
+        setIsDirty(true);
+    }
+
+    public void expire() {
+        SimpleTcpReplicationManager mgr =(SimpleTcpReplicationManager)getManager();
+        mgr.sessionInvalidated(getIdInternal());
+        setIsDirty(true);
+        super.expire();
+    }
+
+    public void invalidate() {
+        SimpleTcpReplicationManager mgr =(SimpleTcpReplicationManager)getManager();
+        mgr.sessionInvalidated(getIdInternal());
+        setIsDirty(true);
+        super.invalidate();
+    }
+
+
+    /**
+     * Read a serialized version of the contents of this session object from
+     * the specified object input stream, without requiring that the
+     * StandardSession itself have been serialized.
+     *
+     * @param stream The object input stream to read from
+     *
+     * @exception ClassNotFoundException if an unknown class is specified
+     * @exception IOException if an input/output error occurs
+     */
+    public void readObjectData(ObjectInputStream stream)
+        throws ClassNotFoundException, IOException {
+
+        super.readObjectData(stream);
+
+    }
+
+
+    /**
+     * Write a serialized version of the contents of this session object to
+     * the specified object output stream, without requiring that the
+     * StandardSession itself have been serialized.
+     *
+     * @param stream The object output stream to write to
+     *
+     * @exception IOException if an input/output error occurs
+     */
+    public void writeObjectData(ObjectOutputStream stream)
+        throws IOException {
+
+        super.writeObjectData(stream);
+
+    }
+    
+    public void setId(String id, boolean tellNew) {
+
+        if ((this.id != null) && (manager != null))
+            manager.remove(this);
+
+        this.id = id;
+
+        if (manager != null)
+            manager.add(this);
+        if (tellNew) tellNew();
+    }
+    
+    
+
+
+
+
+
+
+    /**
+     * returns true if this session is the primary session, if that is the
+     * case, the manager can expire it upon timeout.
+     */
+    public boolean isPrimarySession() {
+        return isPrimarySession;
+    }
+
+    /**
+     * Sets whether this is the primary session or not.
+     * @param primarySession Flag value
+     */
+    public void setPrimarySession(boolean primarySession) {
+        this.isPrimarySession=primarySession;
+    }
+
+
+
+
+    /**
+     * Implements a log method to log through the manager
+     */
+    protected void log(String message) {
+
+        if ((mManager != null) && (mManager instanceof SimpleTcpReplicationManager)) {
+            ((SimpleTcpReplicationManager) mManager).log.debug("ReplicatedSession: " + message);
+        } else {
+            System.out.println("ReplicatedSession: " + message);
+        }
+
+    }
+
+    protected void log(String message, Throwable x) {
+
+        if ((mManager != null) && (mManager instanceof SimpleTcpReplicationManager)) {
+            ((SimpleTcpReplicationManager) mManager).log.error("ReplicatedSession: " + message,x);
+        } else {
+            System.out.println("ReplicatedSession: " + message);
+            x.printStackTrace();
+        }
+
+    }
+
+    public String toString() {
+        StringBuffer buf = new StringBuffer("ReplicatedSession id=");
+        buf.append(getIdInternal()).append(" ref=").append(super.toString()).append("\n");
+        java.util.Enumeration e = getAttributeNames();
+        while ( e.hasMoreElements() ) {
+            String name = (String)e.nextElement();
+            Object value = getAttribute(name);
+            buf.append("\tname=").append(name).append("; value=").append(value).append("\n");
+        }
+        buf.append("\tLastAccess=").append(getLastAccessedTime()).append("\n");
+        return buf.toString();
+    }
+    public int getAccessCount() {
+        return accessCount;
+    }
+    public void setAccessCount(int accessCount) {
+        this.accessCount = accessCount;
+    }
+    public long getLastAccessedTime() {
+        return lastAccessedTime;
+    }
+    public void setLastAccessedTime(long lastAccessedTime) {
+        this.lastAccessedTime = lastAccessedTime;
+    }
+    public long getThisAccessedTime() {
+        return thisAccessedTime;
+    }
+    public void setThisAccessedTime(long thisAccessedTime) {
+        this.thisAccessedTime = thisAccessedTime;
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/session/SerializablePrincipal.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/session/SerializablePrincipal.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/session/SerializablePrincipal.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,192 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.ha.session;
+
+
+import java.util.Arrays;
+import java.util.List;
+import org.apache.catalina.Realm;
+
+
+/**
+ * Generic implementation of <strong>java.security.Principal</strong> that
+ * is available for use by <code>Realm</code> implementations.
+ * The GenericPrincipal does NOT implement serializable and I didn't want to change that implementation
+ * hence I implemented this one instead.
+ * @author Filip Hanik
+ * @version $Revision: 303587 $ $Date: 2004-12-09 08:36:43 -0600 (Thu, 09 Dec 2004) $
+ */
+import org.apache.catalina.realm.GenericPrincipal;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+public class SerializablePrincipal  implements java.io.Serializable {
+
+
+    // ----------------------------------------------------------- Constructors
+
+    public SerializablePrincipal()
+    {
+        super();
+    }
+    /**
+     * Construct a new Principal, associated with the specified Realm, for the
+     * specified username and password.
+     *
+     * @param realm The Realm that owns this Principal
+     * @param name The username of the user represented by this Principal
+     * @param password Credentials used to authenticate this user
+     */
+    public SerializablePrincipal(Realm realm, String name, String password) {
+
+        this(realm, name, password, null);
+
+    }
+
+
+    /**
+     * Construct a new Principal, associated with the specified Realm, for the
+     * specified username and password, with the specified role names
+     * (as Strings).
+     *
+     * @param realm The Realm that owns this principal
+     * @param name The username of the user represented by this Principal
+     * @param password Credentials used to authenticate this user
+     * @param roles List of roles (must be Strings) possessed by this user
+     */
+    public SerializablePrincipal(Realm realm, String name, String password,
+                            List roles) {
+
+        super();
+        this.realm = realm;
+        this.name = name;
+        this.password = password;
+        if (roles != null) {
+            this.roles = new String[roles.size()];
+            this.roles = (String[]) roles.toArray(this.roles);
+            if (this.roles.length > 0)
+                Arrays.sort(this.roles);
+        }
+
+    }
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * The username of the user represented by this Principal.
+     */
+    protected String name = null;
+
+    public String getName() {
+        return (this.name);
+    }
+
+
+    /**
+     * The authentication credentials for the user represented by
+     * this Principal.
+     */
+    protected String password = null;
+
+    public String getPassword() {
+        return (this.password);
+    }
+
+
+    /**
+     * The Realm with which this Principal is associated.
+     */
+    protected transient Realm realm = null;
+
+    public Realm getRealm() {
+        return (this.realm);
+    }
+
+    public void setRealm(Realm realm) {
+        this.realm = realm;
+    }
+
+
+
+
+    /**
+     * The set of roles associated with this user.
+     */
+    protected String roles[] = new String[0];
+
+    public String[] getRoles() {
+        return (this.roles);
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+
+
+    /**
+     * Return a String representation of this object, which exposes only
+     * information that should be public.
+     */
+    public String toString() {
+
+        StringBuffer sb = new StringBuffer("SerializablePrincipal[");
+        sb.append(this.name);
+        sb.append("]");
+        return (sb.toString());
+
+    }
+
+    public static SerializablePrincipal createPrincipal(GenericPrincipal principal)
+    {
+        if ( principal==null) return null;
+        return new SerializablePrincipal(principal.getRealm(),
+                                         principal.getName(),
+                                         principal.getPassword(),
+                                         principal.getRoles()!=null?Arrays.asList(principal.getRoles()):null);
+    }
+
+    public GenericPrincipal getPrincipal( Realm realm )
+    {
+        return new GenericPrincipal(realm,name,password,getRoles()!=null?Arrays.asList(getRoles()):null);
+    }
+    
+    public static GenericPrincipal readPrincipal(ObjectInput in, Realm realm) throws java.io.IOException{
+        String name = in.readUTF();
+        boolean hasPwd = in.readBoolean();
+        String pwd = null;
+        if ( hasPwd ) pwd = in.readUTF();
+        int size = in.readInt();
+        String[] roles = new String[size];
+        for ( int i=0; i<size; i++ ) roles[i] = in.readUTF();
+        return new GenericPrincipal(realm,name,pwd,Arrays.asList(roles));
+    }
+    
+    public static void writePrincipal(GenericPrincipal p, ObjectOutput out) throws java.io.IOException {
+        out.writeUTF(p.getName());
+        out.writeBoolean(p.getPassword()!=null);
+        if ( p.getPassword()!= null ) out.writeUTF(p.getPassword());
+        String[] roles = p.getRoles();
+        if ( roles == null ) roles = new String[0];
+        out.writeInt(roles.length);
+        for ( int i=0; i<roles.length; i++ ) out.writeUTF(roles[i]);
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/session/SessionIDMessage.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/session/SessionIDMessage.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/session/SessionIDMessage.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,128 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ *
+ * Licensed 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.ha.session;
+
+import org.apache.catalina.ha.ClusterMessage;
+import org.apache.catalina.ha.ClusterMessageBase;
+
+/**
+ * Session id change cluster message
+ * 
+ * @author Peter Rossbach
+ * 
+ * @version $Revision: 326110 $ $Date: 2005-10-18 09:08:36 -0500 (Tue, 18 Oct 2005) $
+ */
+public class SessionIDMessage extends ClusterMessageBase implements ClusterMessage {
+
+	private int messageNumber;
+
+	private String orignalSessionID;
+
+	private String backupSessionID;
+
+	private String host ;
+	private String contextPath;
+
+	public String getUniqueId() {
+		StringBuffer result = new StringBuffer(getOrignalSessionID());
+		result.append("#-#");
+		result.append(getHost());
+                result.append("#-#");
+                result.append(getContextPath());
+		result.append("#-#");
+		result.append(getMessageNumber());
+		result.append("#-#");
+		result.append(System.currentTimeMillis());
+		return result.toString();
+	}
+
+    /**
+     * @return Returns the host.
+     */
+    public String getHost() {
+        return host;
+    }
+
+    /**
+     * @param host The host to set.
+     */
+    public void setHost(String host) {
+        this.host = host;
+    }
+    
+	/**
+	 * @return Returns the contextPath.
+	 */
+	public String getContextPath() {
+		return contextPath;
+	}
+	/**
+	 * @param contextPath The contextPath to set.
+	 */
+	public void setContextPath(String contextPath) {
+		this.contextPath = contextPath;
+	}
+	/**
+	 * @return Returns the messageNumber.
+	 */
+	public int getMessageNumber() {
+		return messageNumber;
+	}
+
+	/**
+	 * @param messageNumber
+	 *            The messageNumber to set.
+	 */
+	public void setMessageNumber(int messageNumber) {
+		this.messageNumber = messageNumber;
+	}
+
+	
+	/**
+	 * @return Returns the backupSessionID.
+	 */
+	public String getBackupSessionID() {
+		return backupSessionID;
+	}
+
+	/**
+	 * @param backupSessionID
+	 *            The backupSessionID to set.
+	 */
+	public void setBackupSessionID(String backupSessionID) {
+		this.backupSessionID = backupSessionID;
+	}
+
+	/**
+	 * @return Returns the orignalSessionID.
+	 */
+	public String getOrignalSessionID() {
+		return orignalSessionID;
+	}
+
+	/**
+	 * @param orignalSessionID
+	 *            The orignalSessionID to set.
+	 */
+	public void setOrignalSessionID(String orignalSessionID) {
+		this.orignalSessionID = orignalSessionID;
+	}
+
+    
+
+
+}
+

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/session/SessionMessage.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/session/SessionMessage.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/session/SessionMessage.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,103 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.ha.session;
+import org.apache.catalina.ha.ClusterMessage;
+
+/**
+ *
+ * <B>Class Description:</B><BR>
+ * The SessionMessage class is a class that is used when a session has been
+ * created, modified, expired in a Tomcat cluster node.<BR>
+ *
+ * The following events are currently available:
+ * <ul>
+ *   <li><pre>public static final int EVT_SESSION_CREATED</pre><li>
+ *   <li><pre>public static final int EVT_SESSION_ACCESSED</pre><li>
+ *   <li><pre>public static final int EVT_ATTRIBUTE_ADDED</pre><li>
+ *   <li><pre>public static final int EVT_ATTRIBUTE_REMOVED</pre><li>
+ *   <li><pre>public static final int EVT_SESSION_EXPIRED_WONOTIFY</pre><li>
+ *   <li><pre>public static final int EVT_SESSION_EXPIRED_WNOTIFY</pre><li>
+ *   <li><pre>public static final int EVT_GET_ALL_SESSIONS</pre><li>
+ *   <li><pre>public static final int EVT_SET_USER_PRINCIPAL</pre><li>
+ *   <li><pre>public static final int EVT_SET_SESSION_NOTE</pre><li>
+ *   <li><pre>public static final int EVT_REMOVE_SESSION_NOTE</pre><li>
+ * </ul>
+ *
+ */
+
+public interface SessionMessage extends ClusterMessage, java.io.Serializable
+{
+
+    /**
+     * Event type used when a session has been created on a node
+     */
+    public static final int EVT_SESSION_CREATED = 1;
+    /**
+     * Event type used when a session has expired
+     */
+    public static final int EVT_SESSION_EXPIRED = 2;
+
+    /**
+     * Event type used when a session has been accessed (ie, last access time
+     * has been updated. This is used so that the replicated sessions will not expire
+     * on the network
+     */
+    public static final int EVT_SESSION_ACCESSED = 3;
+    /**
+     * Event type used when a server comes online for the first time.
+     * The first thing the newly started server wants to do is to grab the
+     * all the sessions from one of the nodes and keep the same state in there
+     */
+    public static final int EVT_GET_ALL_SESSIONS = 4;
+    /**
+     * Event type used when an attribute has been added to a session,
+     * the attribute will be sent to all the other nodes in the cluster
+     */
+    public static final int EVT_SESSION_DELTA  = 13;
+
+    /**
+     * When a session state is transferred, this is the event.
+     */
+    public static final int EVT_ALL_SESSION_DATA = 12;
+    
+    /**
+     * When a session state is complete transferred, this is the event.
+     */
+    public static final int EVT_ALL_SESSION_TRANSFERCOMPLETE = 14;
+    
+
+    
+    public String getContextName();
+    
+    public String getEventTypeString();
+    
+    /**
+     * returns the event type
+     * @return one of the event types EVT_XXXX
+     */
+    public int getEventType(); 
+    /**
+     * @return the serialized data for the session
+     */
+    public byte[] getSession();
+    /**
+     * @return the session ID for the session
+     */
+    public String getSessionID();
+    
+
+
+}//SessionMessage

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/session/SessionMessageImpl.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/session/SessionMessageImpl.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/session/SessionMessageImpl.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,157 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.ha.session;
+
+
+import org.apache.catalina.ha.ClusterMessage;
+import org.apache.catalina.tribes.Member;
+import org.apache.catalina.ha.ClusterMessageBase;
+
+/**
+ * Session cluster message
+ * 
+ * @author Filip Hanik
+ * @author Peter Rossbach
+ * 
+ * @version $Revision: 326110 $ $Date: 2005-10-18 09:08:36 -0500 (Tue, 18 Oct 2005) $
+ */
+public class SessionMessageImpl extends ClusterMessageBase implements SessionMessage, java.io.Serializable {
+    
+    public SessionMessageImpl() {
+    }
+    
+    
+    /*
+
+     * Private serializable variables to keep the messages state
+     */
+    private int mEvtType = -1;
+    private byte[] mSession;
+    private String mSessionID;
+
+    private String mContextName;
+    private long serializationTimestamp;
+    private boolean timestampSet = false ;
+    private String uniqueId;
+
+
+    private SessionMessageImpl( String contextName,
+                           int eventtype,
+                           byte[] session,
+                           String sessionID)
+    {
+        mEvtType = eventtype;
+        mSession = session;
+        mSessionID = sessionID;
+        mContextName = contextName;
+        uniqueId = sessionID;
+    }
+
+    /**
+     * Creates a session message. Depending on what event type you want this
+     * message to represent, you populate the different parameters in the constructor<BR>
+      * The following rules apply dependent on what event type argument you use:<BR>
+     * <B>EVT_SESSION_CREATED</B><BR>
+     *    The parameters: session, sessionID must be set.<BR>
+     * <B>EVT_SESSION_EXPIRED</B><BR>
+     *    The parameters: sessionID must be set.<BR>
+     * <B>EVT_SESSION_ACCESSED</B><BR>
+     *    The parameters: sessionID must be set.<BR>
+     * <B>EVT_SESSION_EXPIRED_XXXX</B><BR>
+     *    The parameters: sessionID must be set.<BR>
+     * <B>EVT_SESSION_DELTA</B><BR>
+     *    Send attribute delta (add,update,remove attribute or principal, ...).<BR>
+     * <B>EVT_ALL_SESSION_DATA</B><BR>
+     *    Send complete serializes session list<BR>
+     * <B>EVT_ALL_SESSION_TRANSFERCOMPLETE</B><BR>
+     *    send that all session state information are transfered
+     *    after GET_ALL_SESSION received from this sender.<BR>
+     * @param contextName - the name of the context (application
+     * @param eventtype - one of the 8 event type defined in this class
+     * @param session - the serialized byte array of the session itself
+     * @param sessionID - the id that identifies this session
+     * @param uniqueID - the id that identifies this message
+     */
+    public SessionMessageImpl( String contextName,
+                           int eventtype,
+                           byte[] session,
+                           String sessionID,
+                           String uniqueID)
+    {
+        this(contextName,eventtype,session,sessionID);
+        uniqueId = uniqueID;
+    }
+
+    /**
+     * returns the event type
+     * @return one of the event types EVT_XXXX
+     */
+    public int getEventType() { return mEvtType; }
+
+    /**
+     * @return the serialized data for the session
+     */
+    public byte[] getSession() { return mSession;}
+
+    /**
+     * @return the session ID for the session
+     */
+    public String getSessionID(){ return mSessionID; }
+    
+    /**
+     * set message send time but only the first setting works (one shot)
+     */
+    public void setTimestamp(long time) {
+        synchronized(this) {
+            if(!timestampSet) {
+                serializationTimestamp=time;
+                timestampSet = true ;
+            }
+        }
+    }
+    
+    public long getTimestamp() { return serializationTimestamp;}
+    
+    /**
+     * clear text event type name (for logging purpose only) 
+     * @return the event type in a string representating, useful for debugging
+     */
+    public String getEventTypeString()
+    {
+        switch (mEvtType)
+        {
+            case EVT_SESSION_CREATED : return "SESSION-MODIFIED";
+            case EVT_SESSION_EXPIRED : return "SESSION-EXPIRED";
+            case EVT_SESSION_ACCESSED : return "SESSION-ACCESSED";
+            case EVT_GET_ALL_SESSIONS : return "SESSION-GET-ALL";
+            case EVT_SESSION_DELTA : return "SESSION-DELTA";
+            case EVT_ALL_SESSION_DATA : return "ALL-SESSION-DATA";
+            case EVT_ALL_SESSION_TRANSFERCOMPLETE : return "SESSION-STATE-TRANSFERED";
+            default : return "UNKNOWN-EVENT-TYPE";
+        }
+    }
+
+    public String getContextName() {
+       return mContextName;
+    }
+    public String getUniqueId() {
+        return uniqueId;
+    }
+    public void setUniqueId(String uniqueId) {
+        this.uniqueId = uniqueId;
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/session/SimpleTcpReplicationManager.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/session/SimpleTcpReplicationManager.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/session/SimpleTcpReplicationManager.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,690 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.ha.session;
+
+import java.io.IOException;
+
+import org.apache.catalina.LifecycleException;
+import org.apache.catalina.Session;
+import org.apache.catalina.ha.CatalinaCluster;
+import org.apache.catalina.ha.ClusterManager;
+import org.apache.catalina.ha.ClusterMessage;
+import org.apache.catalina.tribes.Member;
+import org.apache.catalina.realm.GenericPrincipal;
+import org.apache.catalina.session.StandardManager;
+import org.apache.catalina.tribes.io.ReplicationStream;
+import java.io.ByteArrayInputStream;
+import org.apache.catalina.Loader;
+
+/**
+ * Title:        Tomcat Session Replication for Tomcat 4.0 <BR>
+ * Description:  A very simple straight forward implementation of
+ *               session replication of servers in a cluster.<BR>
+ *               This session replication is implemented "live". By live
+ *               I mean, when a session attribute is added into a session on Node A
+ *               a message is broadcasted to other messages and setAttribute is called on the
+ *               replicated sessions.<BR>
+ *               A full description of this implementation can be found under
+ *               <href="http://www.filip.net/tomcat/">Filip's Tomcat Page</a><BR>
+ *
+ * Copyright:    See apache license
+ * Company:      www.filip.net
+ * @author  <a href="mailto:mail at filip.net">Filip Hanik</a>
+ * @author Bela Ban (modifications for synchronous replication)
+ * @version 1.0 for TC 4.0
+ * Description: The InMemoryReplicationManager is a session manager that replicated
+ * session information in memory. It uses <a href="www.javagroups.com">JavaGroups</a> as
+ * a communication protocol to ensure guaranteed and ordered message delivery.
+ * JavaGroups also provides a very flexible protocol stack to ensure that the replication
+ * can be used in any environment.
+ * <BR><BR>
+ * The InMemoryReplicationManager extends the StandardManager hence it allows for us
+ * to inherit all the basic session management features like expiration, session listeners etc
+ * <BR><BR>
+ * To communicate with other nodes in the cluster, the InMemoryReplicationManager sends out 7 different type of multicast messages
+ * all defined in the SessionMessage class.<BR>
+ * When a session is replicated (not an attribute added/removed) the session is serialized into
+ * a byte array using the StandardSession.readObjectData, StandardSession.writeObjectData methods.
+ */
+public class SimpleTcpReplicationManager extends StandardManager implements ClusterManager
+{
+    public static org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory.getLog( SimpleTcpReplicationManager.class );
+
+    //the channel configuration
+    protected String mChannelConfig = null;
+
+    //the group name
+    protected String mGroupName = "TomcatReplication";
+
+    //somehow start() gets called more than once
+    protected boolean mChannelStarted = false;
+
+    //log to screen
+    protected boolean mPrintToScreen = true;
+
+    protected boolean defaultMode = false;
+
+    protected boolean mManagerRunning = false;
+
+    /** Use synchronous rather than asynchronous replication. Every session modification (creation, change, removal etc)
+     * will be sent to all members. The call will then wait for max milliseconds, or forever (if timeout is 0) for
+     * all responses.
+     */
+    protected boolean synchronousReplication=true;
+
+    /** Set to true if we don't want the sessions to expire on shutdown */
+    protected boolean mExpireSessionsOnShutdown = true;
+
+    protected boolean useDirtyFlag = false;
+
+    protected String name;
+
+    protected boolean distributable = true;
+
+    protected CatalinaCluster cluster;
+
+    protected java.util.HashMap invalidatedSessions = new java.util.HashMap();
+
+    /**
+     * Flag to keep track if the state has been transferred or not
+     * Assumes false.
+     */
+    protected boolean stateTransferred = false;
+    private boolean notifyListenersOnReplication;
+    private boolean sendClusterDomainOnly = true ;
+
+    /**
+     * Constructor, just calls super()
+     *
+     */
+    public SimpleTcpReplicationManager()
+    {
+        super();
+    }
+
+    public boolean isSendClusterDomainOnly() {
+        return sendClusterDomainOnly;
+    }
+    
+    /**
+     * @param sendClusterDomainOnly The sendClusterDomainOnly to set.
+     */
+    public void setSendClusterDomainOnly(boolean sendClusterDomainOnly) {
+        this.sendClusterDomainOnly = sendClusterDomainOnly;
+    }
+  
+    /**
+     * @return Returns the defaultMode.
+     */
+    public boolean isDefaultMode() {
+        return defaultMode;
+    }
+    /**
+     * @param defaultMode The defaultMode to set.
+     */
+    public void setDefaultMode(boolean defaultMode) {
+        this.defaultMode = defaultMode;
+    }
+    
+    public boolean isManagerRunning()
+    {
+        return mManagerRunning;
+    }
+
+    public void setUseDirtyFlag(boolean usedirtyflag)
+    {
+        this.useDirtyFlag = usedirtyflag;
+    }
+
+    public void setExpireSessionsOnShutdown(boolean expireSessionsOnShutdown)
+    {
+        mExpireSessionsOnShutdown = expireSessionsOnShutdown;
+    }
+
+    public void setCluster(CatalinaCluster cluster) {
+        if(log.isDebugEnabled())
+            log.debug("Cluster associated with SimpleTcpReplicationManager");
+        this.cluster = cluster;
+    }
+
+    public boolean getExpireSessionsOnShutdown()
+    {
+        return mExpireSessionsOnShutdown;
+    }
+
+    public void setPrintToScreen(boolean printtoscreen)
+    {
+        if(log.isDebugEnabled())
+            log.debug("Setting screen debug to:"+printtoscreen);
+        mPrintToScreen = printtoscreen;
+    }
+
+    public void setSynchronousReplication(boolean flag)
+    {
+        synchronousReplication=flag;
+    }
+
+    /**
+     * Override persistence since they don't go hand in hand with replication for now.
+     */
+    public void unload() throws IOException {
+        if ( !getDistributable() ) {
+            super.unload();
+        }
+    }
+
+    /**
+     * Creates a HTTP session.
+     * Most of the code in here is copied from the StandardManager.
+     * This is not pretty, yeah I know, but it was necessary since the
+     * StandardManager had hard coded the session instantiation to the a
+     * StandardSession, when we actually want to instantiate a ReplicatedSession<BR>
+     * If the call comes from the Tomcat servlet engine, a SessionMessage goes out to the other
+     * nodes in the cluster that this session has been created.
+     * @param notify - if set to true the other nodes in the cluster will be notified.
+     *                 This flag is needed so that we can create a session before we deserialize
+     *                 a replicated one
+     *
+     * @see ReplicatedSession
+     */
+    protected Session createSession(String sessionId, boolean notify, boolean setId)
+    {
+
+        //inherited from the basic manager
+        if ((getMaxActiveSessions() >= 0) &&
+           (sessions.size() >= getMaxActiveSessions()))
+            throw new IllegalStateException(sm.getString("standardManager.createSession.ise"));
+
+
+        Session session = new ReplicatedSession(this);
+
+        // Initialize the properties of the new session and return it
+        session.setNew(true);
+        session.setValid(true);
+        session.setCreationTime(System.currentTimeMillis());
+        session.setMaxInactiveInterval(this.maxInactiveInterval);
+        if(sessionId == null)
+            sessionId = generateSessionId();
+        if ( setId ) session.setId(sessionId);
+        if ( notify && (cluster!=null) ) {
+            ((ReplicatedSession)session).setIsDirty(true);
+        }
+        return (session);
+    }//createSession
+
+    //=========================================================================
+    // OVERRIDE THESE METHODS TO IMPLEMENT THE REPLICATION
+    //=========================================================================
+
+    /**
+     * Construct and return a new session object, based on the default
+     * settings specified by this Manager's properties.  The session
+     * id will be assigned by this method, and available via the getId()
+     * method of the returned session.  If a new session cannot be created
+     * for any reason, return <code>null</code>.
+     *
+     * @exception IllegalStateException if a new session cannot be
+     *  instantiated for any reason
+     */
+    public Session createSession(String sessionId)
+    {
+        //create a session and notify the other nodes in the cluster
+        Session session =  createSession(sessionId,getDistributable(),true);
+        add(session);
+        return session;
+    }
+
+    public void sessionInvalidated(String sessionId) {
+        synchronized ( invalidatedSessions ) {
+            invalidatedSessions.put(sessionId, sessionId);
+        }
+    }
+
+    public String[] getInvalidatedSessions() {
+        synchronized ( invalidatedSessions ) {
+            String[] result = new String[invalidatedSessions.size()];
+            invalidatedSessions.values().toArray(result);
+            return result;
+        }
+
+    }
+
+    public ClusterMessage requestCompleted(String sessionId)
+    {
+        if (  !getDistributable() ) {
+            log.warn("Received requestCompleted message, although this context["+
+                     getName()+"] is not distributable. Ignoring message");
+            return null;
+        }
+        //notify javagroups
+        try
+        {
+            if ( invalidatedSessions.get(sessionId) != null ) {
+                synchronized ( invalidatedSessions ) {
+                    invalidatedSessions.remove(sessionId);
+                    SessionMessage msg = new SessionMessageImpl(name,
+                    SessionMessage.EVT_SESSION_EXPIRED,
+                    null,
+                    sessionId,
+                    sessionId);
+                return msg;
+                }
+            } else {
+                ReplicatedSession session = (ReplicatedSession) findSession(
+                    sessionId);
+                if (session != null) {
+                    //return immediately if the session is not dirty
+                    if (useDirtyFlag && (!session.isDirty())) {
+                        //but before we return doing nothing,
+                        //see if we should send
+                        //an updated last access message so that
+                        //sessions across cluster dont expire
+                        long interval = session.getMaxInactiveInterval();
+                        long lastaccdist = System.currentTimeMillis() -
+                            session.getLastAccessWasDistributed();
+                        if ( ((interval*1000) / lastaccdist)< 3 ) {
+                            SessionMessage accmsg = new SessionMessageImpl(name,
+                                SessionMessage.EVT_SESSION_ACCESSED,
+                                null,
+                                sessionId,
+                                sessionId);
+                            session.setLastAccessWasDistributed(System.currentTimeMillis());
+                            return accmsg;
+                        }
+                        return null;
+                    }
+
+                    session.setIsDirty(false);
+                    if (log.isDebugEnabled()) {
+                        try {
+                            log.debug("Sending session to cluster=" + session);
+                        }
+                        catch (Exception ignore) {}
+                    }
+                    SessionMessage msg = new SessionMessageImpl(name,
+                        SessionMessage.EVT_SESSION_CREATED,
+                        writeSession(session),
+                        session.getIdInternal(),
+                        session.getIdInternal());
+                    return msg;
+                } //end if
+            }//end if
+        }
+        catch (Exception x )
+        {
+            log.error("Unable to replicate session",x);
+        }
+        return null;
+    }
+
+    /**
+     * Serialize a session into a byte array<BR>
+     * This method simple calls the writeObjectData method on the session
+     * and returns the byte data from that call
+     * @param session - the session to be serialized
+     * @return a byte array containing the session data, null if the serialization failed
+     */
+    protected byte[] writeSession( Session session )
+    {
+        try
+        {
+            java.io.ByteArrayOutputStream session_data = new java.io.ByteArrayOutputStream();
+            java.io.ObjectOutputStream session_out = new java.io.ObjectOutputStream(session_data);
+            session_out.flush();
+            boolean hasPrincipal = session.getPrincipal() != null;
+            session_out.writeBoolean(hasPrincipal);
+            if ( hasPrincipal )
+            {
+                session_out.writeObject(SerializablePrincipal.createPrincipal((GenericPrincipal)session.getPrincipal()));
+            }//end if
+            ((ReplicatedSession)session).writeObjectData(session_out);
+            return session_data.toByteArray();
+
+        }
+        catch ( Exception x )
+        {
+            log.error("Failed to serialize the session!",x);
+        }
+        return null;
+    }
+    
+    /**
+     * Open Stream and use correct ClassLoader (Container) Switch
+     * ThreadClassLoader
+     * 
+     * @param data
+     * @return The object input stream
+     * @throws IOException
+     */
+    public ReplicationStream getReplicationStream(byte[] data) throws IOException {
+        return getReplicationStream(data,0,data.length);
+    }
+    
+    public ReplicationStream getReplicationStream(byte[] data, int offset, int length) throws IOException {
+        ByteArrayInputStream fis =null;
+        ReplicationStream ois = null;
+        Loader loader = null;
+        ClassLoader classLoader = null;
+        //fix to be able to run the DeltaManager
+        //stand alone without a container.
+        //use the Threads context class loader
+        if (container != null)
+            loader = container.getLoader();
+        if (loader != null)
+            classLoader = loader.getClassLoader();
+        else
+            classLoader = Thread.currentThread().getContextClassLoader();
+        //end fix
+        fis = new ByteArrayInputStream(data, offset, length);
+        if ( classLoader == Thread.currentThread().getContextClassLoader() ) {
+            ois = new ReplicationStream(fis, new ClassLoader[] {classLoader});
+        } else {
+            ois = new ReplicationStream(fis, new ClassLoader[] {classLoader,Thread.currentThread().getContextClassLoader()});
+        }
+        return ois;
+    }    
+
+
+    
+
+    /**
+     * Reinstantiates a serialized session from the data passed in.
+     * This will first call createSession() so that we get a fresh instance with all
+     * the managers set and all the transient fields validated.
+     * Then it calls Session.readObjectData(byte[]) to deserialize the object
+     * @param data - a byte array containing session data
+     * @return a valid Session object, null if an error occurs
+     *
+     */
+    protected Session readSession( byte[] data, String sessionId )
+    {
+        try
+        {
+            ReplicationStream session_in = getReplicationStream(data);
+
+            Session session = sessionId!=null?this.findSession(sessionId):null;
+            boolean isNew = (session==null);
+            //clear the old values from the existing session
+            if ( session!=null ) {
+                ReplicatedSession rs = (ReplicatedSession)session;
+                rs.expire(false);  //cleans up the previous values, since we are not doing removes
+                session = null;
+            }//end if
+
+            if (session==null) {
+                session = createSession(null,false, false);
+                sessions.remove(session.getIdInternal());
+            }
+            
+            
+            boolean hasPrincipal = session_in.readBoolean();
+            SerializablePrincipal p = null;
+            if ( hasPrincipal )
+                p = (SerializablePrincipal)session_in.readObject();
+            ((ReplicatedSession)session).readObjectData(session_in);
+            if ( hasPrincipal )
+                session.setPrincipal(p.getPrincipal(getContainer().getRealm()));
+            ((ReplicatedSession)session).setId(sessionId,isNew);
+            ReplicatedSession rsession = (ReplicatedSession)session; 
+            rsession.setAccessCount(1);
+            session.setManager(this);
+            session.setValid(true);
+            rsession.setLastAccessedTime(System.currentTimeMillis());
+            rsession.setThisAccessedTime(System.currentTimeMillis());
+            ((ReplicatedSession)session).setAccessCount(0);
+            session.setNew(false);
+            if(log.isTraceEnabled())
+                 log.trace("Session loaded id="+sessionId +
+                               " actualId="+session.getId()+ 
+                               " exists="+this.sessions.containsKey(sessionId)+
+                               " valid="+rsession.isValid());
+            return session;
+
+        }
+        catch ( Exception x )
+        {
+            log.error("Failed to deserialize the session!",x);
+        }
+        return null;
+    }
+
+    public String getName() {
+        return this.name;
+    }
+    /**
+     * Prepare for the beginning of active use of the public methods of this
+     * component.  This method should be called after <code>configure()</code>,
+     * and before any of the public methods of the component are utilized.<BR>
+     * Starts the cluster communication channel, this will connect with the other nodes
+     * in the cluster, and request the current session state to be transferred to this node.
+     * @exception IllegalStateException if this component has already been
+     *  started
+     * @exception LifecycleException if this component detects a fatal error
+     *  that prevents this component from being used
+     */
+    public void start() throws LifecycleException {
+        mManagerRunning = true;
+        super.start();
+        //start the javagroups channel
+        try {
+            //the channel is already running
+            if ( mChannelStarted ) return;
+            if(log.isInfoEnabled())
+                log.info("Starting clustering manager...:"+getName());
+            if ( cluster == null ) {
+                log.error("Starting... no cluster associated with this context:"+getName());
+                return;
+            }
+            cluster.addManager(getName(),this);
+
+            if (cluster.getMembers().length > 0) {
+                Member mbr = cluster.getMembers()[0];
+                SessionMessage msg =
+                    new SessionMessageImpl(this.getName(),
+                                       SessionMessage.EVT_GET_ALL_SESSIONS,
+                                       null,
+                                       "GET-ALL",
+                                       "GET-ALL-"+this.getName());
+                cluster.send(msg, mbr);
+                if(log.isWarnEnabled())
+                     log.warn("Manager["+getName()+"], requesting session state from "+mbr+
+                         ". This operation will timeout if no session state has been received within "+
+                         "60 seconds");
+                long reqStart = System.currentTimeMillis();
+                long reqNow = 0;
+                boolean isTimeout=false;
+                do {
+                    try {
+                        Thread.sleep(100);
+                    }catch ( Exception sleep) {}
+                    reqNow = System.currentTimeMillis();
+                    isTimeout=((reqNow-reqStart)>(1000*60));
+                } while ( (!isStateTransferred()) && (!isTimeout));
+                if ( isTimeout || (!isStateTransferred()) ) {
+                    log.error("Manager["+getName()+"], No session state received, timing out.");
+                }else {
+                    if(log.isInfoEnabled())
+                        log.info("Manager["+getName()+"], session state received in "+(reqNow-reqStart)+" ms.");
+                }
+            } else {
+                if(log.isInfoEnabled())
+                    log.info("Manager["+getName()+"], skipping state transfer. No members active in cluster group.");
+            }//end if
+            mChannelStarted = true;
+        }  catch ( Exception x ) {
+            log.error("Unable to start SimpleTcpReplicationManager",x);
+        }
+    }
+
+    /**
+     * Gracefully terminate the active use of the public methods of this
+     * component.  This method should be the last one called on a given
+     * instance of this component.<BR>
+     * This will disconnect the cluster communication channel and stop the listener thread.
+     * @exception IllegalStateException if this component has not been started
+     * @exception LifecycleException if this component detects a fatal error
+     *  that needs to be reported
+     */
+    public void stop() throws LifecycleException
+    {
+        mManagerRunning = false;
+        mChannelStarted = false;
+        super.stop();
+        //stop the javagroup channel
+        try
+        {
+            this.sessions.clear();
+            cluster.removeManager(getName(),this);
+//            mReplicationListener.stopListening();
+//            mReplicationTransmitter.stop();
+//            service.stop();
+//            service = null;
+        }
+        catch ( Exception x )
+        {
+            log.error("Unable to stop SimpleTcpReplicationManager",x);
+        }
+    }
+
+    public void setDistributable(boolean dist) {
+        this.distributable = dist;
+    }
+
+    public boolean getDistributable() {
+        return distributable;
+    }
+
+    /**
+     * This method is called by the received thread when a SessionMessage has
+     * been received from one of the other nodes in the cluster.
+     * @param msg - the message received
+     * @param sender - the sender of the message, this is used if we receive a
+     *                 EVT_GET_ALL_SESSION message, so that we only reply to
+     *                 the requesting node
+     */
+    protected void messageReceived( SessionMessage msg, Member sender ) {
+        try  {
+            if(log.isInfoEnabled()) {
+                log.debug("Received SessionMessage of type="+msg.getEventTypeString());
+                log.debug("Received SessionMessage sender="+sender);
+            }
+            switch ( msg.getEventType() ) {
+                case SessionMessage.EVT_GET_ALL_SESSIONS: {
+                    //get a list of all the session from this manager
+                    Object[] sessions = findSessions();
+                    java.io.ByteArrayOutputStream bout = new java.io.ByteArrayOutputStream();
+                    java.io.ObjectOutputStream oout = new java.io.ObjectOutputStream(bout);
+                    oout.writeInt(sessions.length);
+                    for (int i=0; i<sessions.length; i++){
+                        ReplicatedSession ses = (ReplicatedSession)sessions[i];
+                        oout.writeUTF(ses.getIdInternal());
+                        byte[] data = writeSession(ses);
+                        oout.writeObject(data);
+                    }//for
+                    //don't send a message if we don't have to
+                    oout.flush();
+                    oout.close();
+                    byte[] data = bout.toByteArray();
+                    SessionMessage newmsg = new SessionMessageImpl(name,
+                        SessionMessage.EVT_ALL_SESSION_DATA,
+                        data, "SESSION-STATE","SESSION-STATE-"+getName());
+                    cluster.send(newmsg, sender);
+                    break;
+                }
+                case SessionMessage.EVT_ALL_SESSION_DATA: {
+                    java.io.ByteArrayInputStream bin =
+                        new java.io.ByteArrayInputStream(msg.getSession());
+                    java.io.ObjectInputStream oin = new java.io.ObjectInputStream(bin);
+                    int size = oin.readInt();
+                    for ( int i=0; i<size; i++) {
+                        String id = oin.readUTF();
+                        byte[] data = (byte[])oin.readObject();
+                        Session session = readSession(data,id);
+                    }//for
+                    stateTransferred=true;
+                    break;
+                }
+                case SessionMessage.EVT_SESSION_CREATED: {
+                    Session session = this.readSession(msg.getSession(),msg.getSessionID());
+                    if ( log.isDebugEnabled() ) {
+                        log.debug("Received replicated session=" + session +
+                            " isValid=" + session.isValid());
+                    }
+                    break;
+                }
+                case SessionMessage.EVT_SESSION_EXPIRED: {
+                    Session session = findSession(msg.getSessionID());
+                    if ( session != null ) {
+                        session.expire();
+                        this.remove(session);
+                    }//end if
+                    break;
+                }
+                case SessionMessage.EVT_SESSION_ACCESSED :{
+                    Session session = findSession(msg.getSessionID());
+                    if ( session != null ) {
+                        session.access();
+                        session.endAccess();
+                    }
+                    break;
+                }
+                default:  {
+                    //we didn't recognize the message type, do nothing
+                    break;
+                }
+            }//switch
+        }
+        catch ( Exception x )
+        {
+            log.error("Unable to receive message through TCP channel",x);
+        }
+    }
+
+    public void messageDataReceived(ClusterMessage cmsg) {
+        try {
+            if ( cmsg instanceof SessionMessage ) {
+                SessionMessage msg = (SessionMessage)cmsg;
+                messageReceived(msg,
+                                msg.getAddress() != null ? (Member) msg.getAddress() : null);
+            }
+        } catch(Throwable ex){
+            log.error("InMemoryReplicationManager.messageDataReceived()", ex);
+        }//catch
+    }
+
+    public boolean isStateTransferred() {
+        return stateTransferred;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+    public boolean isNotifyListenersOnReplication() {
+        return notifyListenersOnReplication;
+    }
+    public void setNotifyListenersOnReplication(boolean notifyListenersOnReplication) {
+        this.notifyListenersOnReplication = notifyListenersOnReplication;
+    }
+
+
+    /* 
+     * @see org.apache.catalina.ha.ClusterManager#getCluster()
+     */
+    public CatalinaCluster getCluster() {
+        return cluster;
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/session/mbeans-descriptors.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/session/mbeans-descriptors.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/session/mbeans-descriptors.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,320 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mbeans-descriptors PUBLIC
+   "-//Apache Software Foundation//DTD Model MBeans Configuration File"
+   "http://jakarta.apache.org/commons/dtds/mbeans-descriptors.dtd">
+<mbeans-descriptors>
+    <mbean name="JvmRouteBinderValve" description="mod_jk jvmRoute jsessionid cookie backup correction" domain="Catalina"
+        group="Valve" type="org.apache.catalina.ha.session.JvmRouteBinderValve">
+        <attribute name="className"
+               description="Fully qualified class name of the managed object"
+               type="java.lang.String"
+               writeable="false"/>        
+        <attribute name="info" 
+		           description="describe version" type="java.lang.String" writeable="false"/>
+        <attribute name="enabled" 
+		           description="enable a jvm Route check" type="boolean"/>
+        <attribute name="numberOfSessions"
+		           description="number of jvmRoute session corrections" type="long" writeable="false"/>
+        <attribute name="sessionIdAttribute" 
+		    description="Name of attribute with sessionid value before turnover a session" 
+		    type="java.lang.String" 
+		    />
+        <operation name="start" description="Stops the Cluster JvmRouteBinderValve" 
+		           impact="ACTION" returnType="void"/>
+        <operation name="stop" description="Stops the Cluster JvmRouteBinderValve" 
+		           impact="ACTION" returnType="void"/>
+    </mbean>
+	<mbean name="JvmRouteSessionIDBinderListener"
+		description="Monitors the jvmRoute activity"
+		domain="Catalina"
+        group="Listener"
+		type="org.apache.catalina.ha.session.JvmRouteSessionIDBinderListener">
+        <attribute name="info" 
+		           description="describe version" type="java.lang.String" writeable="false"/>
+        <attribute name="numberOfSessions" 
+		    description="number of jvmRoute session corrections" 
+		    type="long" 
+		    writeable="false"/>
+    </mbean>
+    
+   <mbean        name="DeltaManager"
+          description="Cluster Manager implementation of the Manager interface"
+               domain="Catalina"
+                group="Manager"
+                 type="org.apache.catalina.ha.session.DeltaManager">
+
+    <attribute   name="info" 
+		  description="describe version"
+		         type="java.lang.String"
+		    writeable="false"/>
+		    
+    <attribute   name="algorithm"
+          description="The message digest algorithm to be used when generating
+                       session identifiers"
+                 type="java.lang.String"/>
+                 
+    <attribute   name="randomFile"
+          description="File source of random - /dev/urandom or a pipe"
+                 type="java.lang.String"/>
+
+    <attribute   name="className"
+          description="Fully qualified class name of the managed object"
+                 type="java.lang.String"
+            writeable="false"/>
+
+    <attribute   name="distributable"
+          description="The distributable flag for Sessions created by this
+                       Manager"
+                 type="boolean"/>
+
+    <attribute   name="entropy"
+          description="A String initialization parameter used to increase the
+                       entropy of the initialization of our random number
+                       generator"
+                 type="java.lang.String"/>
+
+    <attribute   name="maxActiveSessions"
+          description="The maximum number of active Sessions allowed, or -1
+                       for no limit"
+                 type="int"/>
+
+    <attribute   name="maxInactiveInterval"
+          description="The default maximum inactive interval for Sessions
+                       created by this Manager"
+                 type="int"/>
+
+    <attribute name="processExpiresFrequency"
+               description="The frequency of the manager checks (expiration and passivation)"
+               type="int"/>
+               
+    <attribute   name="sessionIdLength"
+          description="The session id length (in bytes) of Sessions
+                       created by this Manager"
+                 type="int"/>
+
+    <attribute   name="name"
+          description="The descriptive name of this Manager implementation
+                       (for logging)"
+                 type="java.lang.String"
+            writeable="false"/>
+
+    <attribute   name="activeSessions"
+          description="Number of active sessions at this moment"
+                 type="int" 
+            writeable="false"/>
+
+    <attribute   name="sessionCounter"
+          description="Total number of sessions created by this manager"
+                 type="int" />
+
+    <attribute   name="sessionReplaceCounter"
+          description="Total number of replaced sessions that load from external nodes"
+                 type="long" />
+
+    <attribute   name="maxActive"
+          description="Maximum number of active sessions so far"
+                 type="int" />
+
+    <attribute   name="sessionMaxAliveTime"
+          description="Longest time an expired session had been alive"
+                 type="int" />
+
+    <attribute   name="sessionAverageAliveTime"
+          description="Average time an expired session had been alive"
+                 type="int" />
+
+    <attribute   name="sendClusterDomainOnly"
+                   is="true"
+          description="The sendClusterDomainOnly flag send sessions only to members as same cluster domain"
+                 type="boolean"/>
+
+    <attribute   name="rejectedSessions"
+          description="Number of sessions we rejected due to maxActive beeing reached"
+                 type="int" />
+
+    <attribute   name="expiredSessions"
+          description="Number of sessions that expired ( doesn't include explicit invalidations )"
+                 type="int" />
+
+    <attribute   name="stateTransferTimeout"
+          description="state transfer timeout in sec"
+                 type="int"/>
+
+    <attribute   name="processingTime"
+          description="Time spent doing housekeeping and expiration"
+                 type="long" />
+
+    <attribute   name="duplicates"
+          description="Number of duplicated session ids generated"
+                 type="int" />
+
+    <attribute   name="counterReceive_EVT_GET_ALL_SESSIONS"
+          description="Count receive EVT_GET_ALL_SESSIONS messages"
+                 type="long"
+            writeable="false" />
+
+    <attribute   name="counterReceive_EVT_ALL_SESSION_DATA"
+          description="Count receive EVT_ALL_SESSION_DATA messages"
+                 type="long"
+            writeable="false" />
+
+    <attribute   name="counterReceive_EVT_SESSION_CREATED"
+          description="Count receive EVT_SESSION_CREATED messages"
+                 type="long"
+            writeable="false" />
+
+    <attribute   name="counterReceive_EVT_SESSION_DELTA"
+          description="Count receive EVT_SESSION_DELTA messages"
+                 type="long"
+            writeable="false" />
+
+    <attribute   name="counterReceive_EVT_SESSION_ACCESSED"
+          description="Count receive EVT_SESSION_ACCESSED messages"
+                 type="long"
+            writeable="false" />
+
+    <attribute   name="counterReceive_EVT_SESSION_EXPIRED"
+          description="Count receive EVT_SESSION_EXPIRED messages"
+                 type="long"
+            writeable="false" />
+
+    <attribute   name="counterReceive_EVT_ALL_SESSION_TRANSFERCOMPLETE"
+          description="Count receive EVT_ALL_SESSION_TRANSFERCOMPLETE messages"
+                 type="long"
+            writeable="false" />
+
+    <attribute   name="counterSend_EVT_GET_ALL_SESSIONS"
+          description="Count send EVT_GET_ALL_SESSIONS messages"
+                 type="long"
+            writeable="false" />
+
+    <attribute   name="counterSend_EVT_ALL_SESSION_DATA"
+          description="Count send EVT_ALL_SESSION_DATA messages"
+                 type="long"
+            writeable="false" />
+
+    <attribute   name="counterSend_EVT_SESSION_CREATED"
+          description="Count send EVT_SESSION_CREATED messages"
+                 type="long"
+            writeable="false" />
+
+    <attribute   name="counterSend_EVT_SESSION_DELTA"
+          description="Count send EVT_SESSION_DELTA messages"
+                 type="long"
+            writeable="false" />
+
+    <attribute   name="counterSend_EVT_SESSION_ACCESSED"
+          description="Count send EVT_SESSION_ACCESSED messages"
+                 type="long"
+            writeable="false" />
+
+    <attribute   name="counterSend_EVT_SESSION_EXPIRED"
+          description="Count send EVT_SESSION_EXPIRED messages"
+                 type="long"
+            writeable="false" />
+
+    <attribute   name="counterSend_EVT_ALL_SESSION_TRANSFERCOMPLETE"
+          description="Count send EVT_ALL_SESSION_TRANSFERCOMPLETE messages"
+                 type="long"
+            writeable="false" />
+
+    <attribute   name="counterNoStateTransfered"
+          description="Count the failed session transfers noStateTransfered"
+                 type="int"
+            writeable="false" />
+            
+    <attribute   name="receivedQueueSize"
+          description="length of receive queue size when session received from other node"
+                 type="int"
+            writeable="false" />            
+
+    <attribute   name="expireSessionsOnShutdown"
+                   is="true"
+          description="exipre all sessions cluster wide as one node goes down"
+                 type="boolean" />
+
+    <attribute   name="notifyListenersOnReplication"
+                   is="true"
+          description="Send session attribute change events on backup nodes"
+                 type="boolean" />
+
+    <attribute   name="notifySessionListenersOnReplication"
+                   is="true"
+          description="Send session start/stop events on backup nodes"
+                 type="boolean" />
+
+    <attribute   name="sendAllSessions"
+                   is="true"
+          description="Send all sessions at one big block"
+                 type="boolean" />
+
+    <attribute   name="sendAllSessionsSize"
+          description="session block size when sendAllSessions=false (default=1000)"
+                 type="int" />
+
+    <attribute   name="sendAllSessionsWaitTime"
+          description="wait time between send session block (default 2 sec)"
+                 type="int" />
+
+    <operation   name="listSessionIds"
+          description="Return the list of active session ids"
+               impact="ACTION"
+           returnType="java.lang.String">
+    </operation>
+
+    <operation   name="getSessionAttribute"
+          description="Return a session attribute"
+               impact="ACTION"
+           returnType="java.lang.String">
+      <parameter name="sessionId"
+          description="Id of the session"
+                 type="java.lang.String"/>
+      <parameter name="key"
+          description="key of the attribute"
+                 type="java.lang.String"/>
+    </operation>
+
+    <operation   name="expireSession"
+          description="Expire a session"
+               impact="ACTION"
+           returnType="void">
+      <parameter name="sessionId"
+          description="Id of the session"
+                 type="java.lang.String"/>
+    </operation>
+
+    <operation   name="getLastAccessedTime"
+          description="Get the last access time"
+               impact="ACTION"
+           returnType="java.lang.String">
+      <parameter name="sessionId"
+          description="Id of the session"
+                 type="java.lang.String"/>
+    </operation>
+    
+	<operation name="expireAllLocalSessions"
+               description="Exipre all active local sessions and replicate the invalid sessions"
+               impact="ACTION"
+               returnType="void">
+    </operation>
+
+	<operation name="processExpires"
+               description="force process to expire sessions"
+               impact="ACTION"
+               returnType="void">
+    </operation>
+    
+	<operation name="resetStatistics"
+               description="Reset all statistics"
+               impact="ACTION"
+               returnType="void">
+    </operation>
+	<operation name="getAllClusterSessions"
+               description="send to oldest cluster member that this node need all cluster sessions (resync member)"
+               impact="ACTION"
+               returnType="void">
+    </operation>
+
+  </mbean>
+
+</mbeans-descriptors>

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/tcp/Constants.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/tcp/Constants.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/tcp/Constants.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,32 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.ha.tcp;
+
+/**
+ * Manifest constants for the <code>org.apache.catalina.ha.tcp</code>
+ * package.
+ *
+ * @author Peter Rossbach
+ * @version $Revision: 303753 $ $Date: 2005-03-14 15:24:30 -0600 (Mon, 14 Mar 2005) $
+ */
+
+public class Constants {
+
+    public static final String Package = "org.apache.catalina.ha.tcp";
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/tcp/LocalStrings.properties
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/tcp/LocalStrings.properties	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/tcp/LocalStrings.properties	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,72 @@
+AsyncSocketSender.create.thread=Create sender [{0}:{1,number,integer}] queue thread to tcp background replication
+AsyncSocketSender.queue.message=Queue message to [{0}:{1,number,integer}] id=[{2}] size={3}
+AsyncSocketSender.send.error=Unable to asynchronously send session with id=[{0}] - message will be ignored.
+AsyncSocketSender.queue.empty=Queue in sender [{0}:{1,number,integer}] returned null element!
+cluster.mbean.register.already=MBean {0} already registered!
+FastAsyncSocketSender.setThreadPriority=[{0}:{1,number,integer}] set priority to {2}
+FastAsyncSocketSender.min.exception=[{0}:{1,number,integer}] new priority {2} < MIN_PRIORITY
+FastAsyncSocketSender.max.exception=[{0}:{1,number,integer}] new priority {2} > MAX_PRIORITY
+IDataSender.ack.eof=EOF reached at local port [{0}:{1,number,integer}]
+IDataSender.ack.receive=Got ACK at local port [{0}:{1,number,integer}]
+IDataSender.ack.missing=Unable to read acknowledgement from [{0}:{1,number,integer}] in {2,number,integer} ms. Disconnecting socket, and trying again.
+IDataSender.ack.read=Read wait ack char '{2}' [{0}:{1,number,integer}]
+IDataSender.ack.start=Waiting for ACK message [{0}:{1,number,integer}]
+IDataSender.ack.wrong=Missing correct ACK after 10 bytes read at local port [{0}:{1,number,integer}]
+IDataSender.closeSocket=Sender close socket to [{0}:{1,number,integer}] (close count {2,number,integer})
+IDataSender.connect=Sender connect to [{0}:{1,number,integer}] (connect count {2,number,integer})
+IDataSender.create=Create sender [{0}:{1,number,integer}]
+IDataSender.disconnect=Sender disconnect from [{0}:{1,number,integer}] (disconnect count {2,number,integer})
+IDataSender.message.disconnect=Message transfered: Sender can't disconnect from [{0}:{1,number,integer}]
+IDataSender.message.create=Message transfered: Sender can't create current socket [{0}:{1,number,integer}]
+IDataSender.openSocket=Sender open socket to [{0}:{1,number,integer}] (open count {2,number,integer})
+IDataSender.openSocket.failure=Open sender socket [{0}:{1,number,integer}] failure! (open failure count {2,number,integer})
+IDataSender.send.again=Send data again to [{0}:{1,number,integer}]
+IDataSender.send.crash=Send message crashed [{0}:{1,number,integer}] type=[{2}], id=[{3}]
+IDataSender.send.message=Send message to [{0}:{1,number,integer}] id=[{2}] size={3,number,integer}
+IDataSender.send.lost=Message lost: [{0}:{1,number,integer}] type=[{2}], id=[{3}]
+IDataSender.senderModes.Configured=Configured a data replication sender for mode {0}
+IDataSender.senderModes.Instantiate=Can't instantiate a data replication sender of class {0}
+IDataSender.senderModes.Missing=Can't configure a data replication sender for mode {0}
+IDataSender.senderModes.Resources=Can't load data replication sender mapping list
+IDataSender.stats=Send stats from [{0}:{1,number,integer}], Nr of bytes sent={2,number,integer} over {3} = {4,number,integer} bytes/request, processing time {5,number,integer} msec, avg processing time {6,number,integer} msec
+PoolSocketSender.senderQueue.sender.failed=PoolSocketSender create new sender to [{0}:{1,number,integer}] failed
+PoolSocketSender.noMoreSender=No socket sender available for client [{0}:{1,number,integer}] did it disappeared?
+ReplicationTransmitter.getProperty=get property {0}
+ReplicationTransmitter.setProperty=set property {0}: {1} old value {2}
+ReplicationTransmitter.started=Start ClusterSender at cluster {0} with name {1}
+ReplicationTransmitter.stopped=Stopped ClusterSender at cluster {0} with name {1}
+ReplicationValve.crossContext.add=add Cross Context session replication container to replicationValve threadlocal
+ReplicationValve.crossContext.registerSession=register Cross context session id={0} from context {1}
+ReplicationValve.crossContext.remove=remove Cross Context session replication container from replicationValve threadlocal
+ReplicationValve.crossContext.sendDelta=send Cross Context session delta from context {0}.
+ReplicationValve.filter.loading=Loading request filters={0}
+ReplicationValve.filter.token=Request filter={0}
+ReplicationValve.filter.token.failure=Unable to compile filter={0}
+ReplicationValve.invoke.uri=Invoking replication request on {0}
+ReplicationValve.nocluster=No cluster configured for this request.
+ReplicationValve.resetDeltaRequest=Cluster is standalone: reset Session Request Delta at context {0}
+ReplicationValve.send.failure=Unable to perform replication request.
+ReplicationValve.send.invalid.failure=Unable to send session [id={0}] invalid message over cluster.
+ReplicationValve.session.found=Context {0}: Found session {1} but it isn't a ClusterSession.
+ReplicationValve.session.indicator=Context {0}: Primarity of session {0} in request attribute {1} is {2}.
+ReplicationValve.session.invalid=Context {0}: Requested session {1} is invalid, removed or not replicated at this node.
+ReplicationValve.stats=Average request time= {0} ms for Cluster overhead time={1} ms for {2} requests {3} filter requests {4} send requests {5} cross context requests (Request={6} ms Cluster={7} ms).
+SimpleTcpCluster.event.log=Cluster receive listener event {0} with data {1}
+SimpleTcpCluster.getProperty=get property {0}
+SimpleTcpCluster.setProperty=set property {0}: {1} old value {2}
+SimpleTcpCluster.default.addClusterListener=Add Default ClusterListener at cluster {0}
+SimpleTcpCluster.default.addClusterValves=Add Default ClusterValves at cluster {0}
+SimpleTcpCluster.default.addClusterReceiver=Add Default ClusterReceiver at cluster {0}
+SimpleTcpCluster.default.addClusterSender=Add Default ClusterSender at cluster {0}
+SimpleTcpCluster.default.addMembershipService=Add Default Membership Service at cluster {0}
+SimpleTcpCluster.log.receive=RECEIVE {0,date}:{0,time} {1,number} {2}:{3,number,integer} {4} {5}
+SimpleTcpCluster.log.send=SEND {0,date}:{0,time} {1,number} {2}:{3,number,integer} {4} 
+SimpleTcpCluster.log.send.all=SEND {0,date}:{0,time} {1,number} - {2}
+SocketReplictionListener.allreadyExists=ServerSocket [{0}:{1}] allready started!
+SocketReplictionListener.accept.failure=ServerSocket [{0}:{1}] - Exception to start thread or accept server socket
+SocketReplictionListener.open=Open Socket at [{0}:{1}]
+SocketReplictionListener.openclose.failure=ServerSocket [{0}:{1}] - Exception to open or close server socket
+SocketReplictionListener.portbusy=Port busy at [{0}:{i}] - reason [{2}]
+SocketReplictionListener.serverSocket.notExists=Fatal error: Receiver socket not bound address={0} port={1} maxport={2}
+SocketReplictionListener.timeout=Receiver ServerSocket no started [{0}:{1}] - reason: timeout={2} or listen={3}
+SocketReplictionListener.unlockSocket.failure=UnLocksocket failure at ServerSocket [{0:{1}]

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/tcp/ReplicationValve.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/tcp/ReplicationValve.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/tcp/ReplicationValve.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,658 @@
+/*
+ * Copyright 1999,2004-2005 The Apache Software Foundation.
+ * 
+ * Licensed 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.ha.tcp;
+
+import java.io.IOException;
+import java.util.StringTokenizer;
+import java.util.regex.Pattern;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Iterator;
+import javax.servlet.ServletException;
+
+import org.apache.catalina.Manager;
+import org.apache.catalina.Session;
+import org.apache.catalina.Context;
+import org.apache.catalina.core.StandardContext;
+import org.apache.catalina.ha.CatalinaCluster;
+import org.apache.catalina.ha.ClusterManager;
+import org.apache.catalina.ha.ClusterMessage;
+import org.apache.catalina.ha.ClusterSession;
+import org.apache.catalina.ha.ClusterValve;
+import org.apache.catalina.ha.session.DeltaManager;
+import org.apache.catalina.ha.session.DeltaSession;
+import org.apache.catalina.connector.Request;
+import org.apache.catalina.connector.Response;
+import org.apache.catalina.util.StringManager;
+import org.apache.catalina.valves.ValveBase;
+
+/**
+ * <p>Implementation of a Valve that logs interesting contents from the
+ * specified Request (before processing) and the corresponding Response
+ * (after processing).  It is especially useful in debugging problems
+ * related to headers and cookies.</p>
+ *
+ * <p>This Valve may be attached to any Container, depending on the granularity
+ * of the logging you wish to perform.</p>
+ *
+ * <p>primaryIndicator=true, then the request attribute <i>org.apache.catalina.ha.tcp.isPrimarySession.</i>
+ * is set true, when request processing is at sessions primary node.
+ * </p>
+ *
+ * @author Craig R. McClanahan
+ * @author Filip Hanik
+ * @author Peter Rossbach
+ * @version $Revision: 375709 $ $Date: 2006-02-07 15:13:25 -0600 (Tue, 07 Feb 2006) $
+ */
+
+public class ReplicationValve
+    extends ValveBase implements ClusterValve {
+    
+    private static org.apache.commons.logging.Log log =
+        org.apache.commons.logging.LogFactory.getLog( ReplicationValve.class );
+
+    // ----------------------------------------------------- Instance Variables
+
+    /**
+     * The descriptive information related to this implementation.
+     */
+    private static final String info =
+        "org.apache.catalina.ha.tcp.ReplicationValve/2.0";
+
+
+    /**
+     * The StringManager for this package.
+     */
+    protected static StringManager sm =
+        StringManager.getManager(Constants.Package);
+
+    private CatalinaCluster cluster = null ;
+
+    /**
+     * holds file endings to not call for like images and others
+     */
+    protected java.util.regex.Pattern[] reqFilters = new java.util.regex.Pattern[0];
+    
+    /**
+     * Orginal filter 
+     */
+    protected String filter ;
+    
+    /**
+     * crossContext session container 
+     */
+    protected ThreadLocal crossContextSessions = new ThreadLocal() ;
+    
+    /**
+     * doProcessingStats (default = off)
+     */
+    protected boolean doProcessingStats = false;
+    
+    protected long totalRequestTime = 0;
+    protected long totalSendTime = 0;
+    protected long nrOfRequests = 0;
+    protected long lastSendTime = 0;
+    protected long nrOfFilterRequests = 0;
+    protected long nrOfSendRequests = 0;
+    protected long nrOfCrossContextSendRequests = 0;
+    
+    /**
+     * must primary change indicator set 
+     */
+    protected boolean primaryIndicator = false ;
+    
+    /**
+     * Name of primary change indicator as request attribute
+     */
+    protected String primaryIndicatorName = "org.apache.catalina.ha.tcp.isPrimarySession";
+   
+    // ------------------------------------------------------------- Properties
+
+    public ReplicationValve() {
+    }
+    
+    /**
+     * Return descriptive information about this Valve implementation.
+     */
+    public String getInfo() {
+
+        return (info);
+
+    }
+    
+    /**
+     * @return Returns the cluster.
+     */
+    public CatalinaCluster getCluster() {
+        return cluster;
+    }
+    
+    /**
+     * @param cluster The cluster to set.
+     */
+    public void setCluster(CatalinaCluster cluster) {
+        this.cluster = cluster;
+    }
+ 
+    /**
+     * @return Returns the filter
+     */
+    public String getFilter() {
+       return filter ;
+    }
+
+    /**
+     * compile filter string to regular expressions
+     * @see Pattern#compile(java.lang.String)
+     * @param filter
+     *            The filter to set.
+     */
+    public void setFilter(String filter) {
+        if (log.isDebugEnabled())
+            log.debug(sm.getString("ReplicationValve.filter.loading", filter));
+        this.filter = filter;
+        StringTokenizer t = new StringTokenizer(filter, ";");
+        this.reqFilters = new Pattern[t.countTokens()];
+        int i = 0;
+        while (t.hasMoreTokens()) {
+            String s = t.nextToken();
+            if (log.isTraceEnabled())
+                log.trace(sm.getString("ReplicationValve.filter.token", s));
+            try {
+                reqFilters[i++] = Pattern.compile(s);
+            } catch (Exception x) {
+                log.error(sm.getString("ReplicationValve.filter.token.failure",
+                        s), x);
+            }
+        }
+    }
+
+    /**
+     * @return Returns the primaryIndicator.
+     */
+    public boolean isPrimaryIndicator() {
+        return primaryIndicator;
+    }
+
+    /**
+     * @param primaryIndicator The primaryIndicator to set.
+     */
+    public void setPrimaryIndicator(boolean primaryIndicator) {
+        this.primaryIndicator = primaryIndicator;
+    }
+    
+    /**
+     * @return Returns the primaryIndicatorName.
+     */
+    public String getPrimaryIndicatorName() {
+        return primaryIndicatorName;
+    }
+    
+    /**
+     * @param primaryIndicatorName The primaryIndicatorName to set.
+     */
+    public void setPrimaryIndicatorName(String primaryIndicatorName) {
+        this.primaryIndicatorName = primaryIndicatorName;
+    }
+    
+    /**
+     * Calc processing stats
+     */
+    public boolean isDoProcessingStats() {
+        return doProcessingStats;
+    }
+
+    /**
+     * Set Calc processing stats
+     * @see #resetStatistics()
+     */
+    public void setDoProcessingStats(boolean doProcessingStats) {
+        this.doProcessingStats = doProcessingStats;
+    }
+
+    /**
+     * @return Returns the lastSendTime.
+     */
+    public long getLastSendTime() {
+        return lastSendTime;
+    }
+    
+    /**
+     * @return Returns the nrOfRequests.
+     */
+    public long getNrOfRequests() {
+        return nrOfRequests;
+    }
+    
+    /**
+     * @return Returns the nrOfFilterRequests.
+     */
+    public long getNrOfFilterRequests() {
+        return nrOfFilterRequests;
+    }
+
+    /**
+     * @return Returns the nrOfCrossContextSendRequests.
+     */
+    public long getNrOfCrossContextSendRequests() {
+        return nrOfCrossContextSendRequests;
+    }
+
+    /**
+     * @return Returns the nrOfSendRequests.
+     */
+    public long getNrOfSendRequests() {
+        return nrOfSendRequests;
+    }
+
+    /**
+     * @return Returns the totalRequestTime.
+     */
+    public long getTotalRequestTime() {
+        return totalRequestTime;
+    }
+    
+    /**
+     * @return Returns the totalSendTime.
+     */
+    public long getTotalSendTime() {
+        return totalSendTime;
+    }
+
+    /**
+     * @return Returns the reqFilters.
+     */
+    protected java.util.regex.Pattern[] getReqFilters() {
+        return reqFilters;
+    }
+    
+    /**
+     * @param reqFilters The reqFilters to set.
+     */
+    protected void setReqFilters(java.util.regex.Pattern[] reqFilters) {
+        this.reqFilters = reqFilters;
+    }
+    
+    
+    // --------------------------------------------------------- Public Methods
+    
+    /**
+     * Register all cross context sessions inside endAccess.
+     * Use a list with contains check, that the Portlet API can include a lot of fragments from same or
+     * different applications with session changes.
+     *
+     * @param session cross context session
+     */
+    public void registerReplicationSession(DeltaSession session) {
+        List sessions = (List)crossContextSessions.get();
+        if(sessions != null) {
+            if(!sessions.contains(session)) {
+                if(log.isDebugEnabled())
+                    log.debug(sm.getString("ReplicationValve.crossContext.registerSession",
+                        session.getIdInternal(),
+                        session.getManager().getContainer().getName()));
+                sessions.add(session);
+            }
+        }
+    }
+
+    /**
+     * Log the interesting request parameters, invoke the next Valve in the
+     * sequence, and log the interesting response parameters.
+     *
+     * @param request The servlet request to be processed
+     * @param response The servlet response to be created
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception ServletException if a servlet error occurs
+     */
+    public void invoke(Request request, Response response)
+        throws IOException, ServletException
+    {
+        long totalstart = 0;
+
+        //this happens before the request
+        if(isDoProcessingStats()) {
+            totalstart = System.currentTimeMillis();
+        }
+        if (primaryIndicator) {
+            createPrimaryIndicator(request) ;
+        }
+        Context context = request.getContext();
+        boolean isCrossContext = context != null
+                && context instanceof StandardContext
+                && ((StandardContext) context).getCrossContext();
+        try {
+            if(isCrossContext) {
+                if(log.isDebugEnabled())
+                    log.debug(sm.getString("ReplicationValve.crossContext.add"));
+                //FIXME add Pool of Arraylists
+                crossContextSessions.set(new ArrayList());
+            }
+            getNext().invoke(request, response);
+            Manager manager = request.getContext().getManager();
+            if (manager != null && manager instanceof ClusterManager) {
+                ClusterManager clusterManager = (ClusterManager) manager;
+                CatalinaCluster containerCluster = (CatalinaCluster) getContainer().getCluster();
+                if (containerCluster == null) {
+                    if (log.isWarnEnabled())
+                        log.warn(sm.getString("ReplicationValve.nocluster"));
+                    return;
+                }
+                // valve cluster can access manager - other cluster handle replication 
+                // at host level - hopefully!
+                if(containerCluster.getManager(clusterManager.getName()) == null)
+                    return ;
+                if(containerCluster.hasMembers()) {
+                    sendReplicationMessage(request, totalstart, isCrossContext, clusterManager, containerCluster);
+                } else {
+                    resetReplicationRequest(request,isCrossContext);
+                }        
+            }
+        } finally {
+            // Array must be remove: Current master request send endAccess at recycle. 
+            // Don't register this request session again!
+            if(isCrossContext) {
+                if(log.isDebugEnabled())
+                    log.debug(sm.getString("ReplicationValve.crossContext.remove"));
+                // crossContextSessions.remove() only exist at Java 5
+                // register ArrayList at a pool
+                crossContextSessions.set(null);
+            }
+        }
+    }
+
+    
+    /**
+     * reset the active statitics 
+     */
+    public void resetStatistics() {
+        totalRequestTime = 0 ;
+        totalSendTime = 0 ;
+        lastSendTime = 0 ;
+        nrOfFilterRequests = 0 ;
+        nrOfRequests = 0 ;
+        nrOfSendRequests = 0;
+        nrOfCrossContextSendRequests = 0;
+    }
+    
+    /**
+     * Return a String rendering of this object.
+     */
+    public String toString() {
+
+        StringBuffer sb = new StringBuffer("ReplicationValve[");
+        if (container != null)
+            sb.append(container.getName());
+        sb.append("]");
+        return (sb.toString());
+
+    }
+
+    // --------------------------------------------------------- Protected Methods
+
+    /**
+     * @param request
+     * @param totalstart
+     * @param isCrossContext
+     * @param clusterManager
+     * @param containerCluster
+     */
+    protected void sendReplicationMessage(Request request, long totalstart, boolean isCrossContext, ClusterManager clusterManager, CatalinaCluster containerCluster) {
+        //this happens after the request
+        long start = 0;
+        if(isDoProcessingStats()) {
+            start = System.currentTimeMillis();
+        }
+        try {
+            // send invalid sessions
+            // DeltaManager returns String[0]
+            if (!(clusterManager instanceof DeltaManager))
+                sendInvalidSessions(clusterManager, containerCluster);
+            // send replication
+            sendSessionReplicationMessage(request, clusterManager, containerCluster);
+            if(isCrossContext)
+                sendCrossContextSession(containerCluster);
+        } catch (Exception x) {
+            // FIXME we have a lot of sends, but the trouble with one node stops the correct replication to other nodes!
+            log.error(sm.getString("ReplicationValve.send.failure"), x);
+        } finally {
+            // FIXME this stats update are not cheap!!
+            if(isDoProcessingStats()) {
+                updateStats(totalstart,start);
+            }
+        }
+    }
+
+    /**
+     * Send all changed cross context sessions to backups
+     * @param containerCluster
+     */
+    protected void sendCrossContextSession(CatalinaCluster containerCluster) {
+        Object sessions = crossContextSessions.get();
+        if(sessions != null && sessions instanceof List
+                && ((List)sessions).size() >0) {
+            for(Iterator iter = ((List)sessions).iterator(); iter.hasNext() ;) {          
+                Session session = (Session)iter.next();
+                if(log.isDebugEnabled())
+                    log.debug(sm.getString("ReplicationValve.crossContext.sendDelta",  
+                            session.getManager().getContainer().getName() ));
+                sendMessage(session,(ClusterManager)session.getManager(),containerCluster);
+                if(isDoProcessingStats()) {
+                    nrOfCrossContextSendRequests++;
+                }
+            }
+        }
+    }
+  
+    /**
+     * Fix memory leak for long sessions with many changes, when no backup member exists!
+     * @param request current request after responce is generated
+     * @param isCrossContext check crosscontext threadlocal
+     */
+    protected void resetReplicationRequest(Request request, boolean isCrossContext) {
+        Session contextSession = request.getSessionInternal(false);
+        if(contextSession != null & contextSession instanceof DeltaSession){
+            resetDeltaRequest(contextSession);
+            ((DeltaSession)contextSession).setPrimarySession(true);
+        }
+        if(isCrossContext) {
+            Object sessions = crossContextSessions.get();
+            if(sessions != null && sessions instanceof List
+               && ((List)sessions).size() >0) {
+                Iterator iter = ((List)sessions).iterator();
+                for(; iter.hasNext() ;) {          
+                    Session session = (Session)iter.next();
+                    resetDeltaRequest(session);
+                    if(session instanceof DeltaSession)
+                        ((DeltaSession)contextSession).setPrimarySession(true);
+
+                }
+            }
+        }                     
+    }
+
+    /**
+     * Reset DeltaRequest from session
+     * @param session HttpSession from current request or cross context session
+     */
+    protected void resetDeltaRequest(Session session) {
+        if(log.isDebugEnabled()) {
+            log.debug(sm.getString("ReplicationValve.resetDeltaRequest" , 
+                session.getManager().getContainer().getName() ));
+        }
+        ((DeltaSession)session).resetDeltaRequest();
+    }
+
+    /**
+     * Send Cluster Replication Request
+     * @param request current request
+     * @param manager session manager
+     * @param cluster replication cluster
+     */
+    protected void sendSessionReplicationMessage(Request request,
+            ClusterManager manager, CatalinaCluster cluster) {
+        Session session = request.getSessionInternal(false);
+        if (session != null) {
+            String uri = request.getDecodedRequestURI();
+            // request without session change
+            if (!isRequestWithoutSessionChange(uri)) {
+                if (log.isDebugEnabled())
+                    log.debug(sm.getString("ReplicationValve.invoke.uri", uri));
+                sendMessage(session,manager,cluster);
+            } else
+                if(isDoProcessingStats())
+                    nrOfFilterRequests++;
+        }
+
+    }
+
+   /**
+    * Send message delta message from request session 
+    * @param request current request
+    * @param manager session manager
+    * @param cluster replication cluster
+    */
+    protected void sendMessage(Session session,
+             ClusterManager manager, CatalinaCluster cluster) {
+        String id = session.getIdInternal();
+        if (id != null) {
+            send(manager, cluster, id);
+        }
+    }
+
+    /**
+     * send manager requestCompleted message to cluster
+     * @param manager SessionManager
+     * @param cluster replication cluster
+     * @param sessionId sessionid from the manager
+     * @see DeltaManager#requestCompleted(String)
+     * @see SimpleTcpCluster#send(ClusterMessage)
+     */
+    protected void send(ClusterManager manager, CatalinaCluster cluster, String sessionId) {
+        ClusterMessage msg = manager.requestCompleted(sessionId);
+        if (msg != null) {
+            if(manager.isSendClusterDomainOnly()) {
+                cluster.sendClusterDomain(msg);
+            } else {
+                cluster.send(msg);
+            }
+            if(isDoProcessingStats())
+                nrOfSendRequests++;
+        }
+    }
+    
+    /**
+     * check for session invalidations
+     * @param manager
+     * @param cluster
+     */
+    protected void sendInvalidSessions(ClusterManager manager, CatalinaCluster cluster) {
+        String[] invalidIds=manager.getInvalidatedSessions();
+        if ( invalidIds.length > 0 ) {
+            for ( int i=0;i<invalidIds.length; i++ ) {
+                try {
+                    send(manager,cluster,invalidIds[i]);
+                } catch ( Exception x ) {
+                    log.error(sm.getString("ReplicationValve.send.invalid.failure",invalidIds[i]),x);
+                }
+            }
+        }
+    }
+    
+    /**
+     * is request without possible session change
+     * @param uri The request uri
+     * @return True if no session change
+     */
+    protected boolean isRequestWithoutSessionChange(String uri) {
+
+        boolean filterfound = false;
+
+        for (int i = 0; (i < reqFilters.length) && (!filterfound); i++) {
+            java.util.regex.Matcher matcher = reqFilters[i].matcher(uri);
+            filterfound = matcher.matches();
+        }
+        return filterfound;
+    }
+
+    /**
+     * protocol cluster replications stats
+     * @param requestTime
+     * @param clusterTime
+     */
+    protected  void updateStats(long requestTime, long clusterTime) {
+        synchronized(this) {
+            lastSendTime=System.currentTimeMillis();
+            totalSendTime+=lastSendTime - clusterTime;
+            totalRequestTime+=lastSendTime - requestTime;
+            nrOfRequests++;
+        }
+        if(log.isInfoEnabled()) {
+            if ( (nrOfRequests % 100) == 0 ) {
+                 log.info(sm.getString("ReplicationValve.stats",
+                     new Object[]{
+                         new Long(totalRequestTime/nrOfRequests),
+                         new Long(totalSendTime/nrOfRequests),
+                         new Long(nrOfRequests),
+                         new Long(nrOfSendRequests),
+                         new Long(nrOfCrossContextSendRequests),
+                         new Long(nrOfFilterRequests),
+                         new Long(totalRequestTime),
+                         new Long(totalSendTime)}));
+             }
+        }
+    }
+
+
+    /**
+     * Mark Request that processed at primary node with attribute
+     * primaryIndicatorName
+     * 
+     * @param request
+     * @throws IOException
+     */
+    protected void createPrimaryIndicator(Request request) throws IOException {
+        String id = request.getRequestedSessionId();
+        if ((id != null) && (id.length() > 0)) {
+            Manager manager = request.getContext().getManager();
+            Session session = manager.findSession(id);
+            if (session instanceof ClusterSession) {
+                ClusterSession cses = (ClusterSession) session;
+                if (cses != null) {
+                    Boolean isPrimary = new Boolean(cses.isPrimarySession());
+                    if (log.isDebugEnabled())
+                        log.debug(sm.getString(
+                                "ReplicationValve.session.indicator", request.getContext().getName(),id,
+                                primaryIndicatorName, isPrimary));
+                    request.setAttribute(primaryIndicatorName, isPrimary);
+                }
+            } else {
+                if (log.isDebugEnabled()) {
+                    if (session != null) {
+                        log.debug(sm.getString(
+                                "ReplicationValve.session.found", request.getContext().getName(),id));
+                    } else {
+                        log.debug(sm.getString(
+                                "ReplicationValve.session.invalid", request.getContext().getName(),id));
+                    }
+                }
+            }
+        }
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/tcp/SendMessageData.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/tcp/SendMessageData.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/tcp/SendMessageData.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,81 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.ha.tcp;
+
+import org.apache.catalina.tribes.Member;
+
+/**
+ * @author Peter Rossbach
+ * @version $Revision: 303987 $ $Date: 2005-07-08 15:50:30 -0500 (Fri, 08 Jul 2005) $
+ */
+public class SendMessageData {
+
+    private Object message ;
+    private Member destination ;
+    private Exception exception ;
+    
+    
+    /**
+     * @param message
+     * @param destination
+     * @param exception
+     */
+    public SendMessageData(Object message, Member destination,
+            Exception exception) {
+        super();
+        this.message = message;
+        this.destination = destination;
+        this.exception = exception;
+    }
+    
+    /**
+     * @return Returns the destination.
+     */
+    public Member getDestination() {
+        return destination;
+    }
+    /**
+     * @param destination The destination to set.
+     */
+    public void setDestination(Member destination) {
+        this.destination = destination;
+    }
+    /**
+     * @return Returns the exception.
+     */
+    public Exception getException() {
+        return exception;
+    }
+    /**
+     * @param exception The exception to set.
+     */
+    public void setException(Exception exception) {
+        this.exception = exception;
+    }
+    /**
+     * @return Returns the message.
+     */
+    public Object getMessage() {
+        return message;
+    }
+    /**
+     * @param message The message to set.
+     */
+    public void setMessage(Object message) {
+        this.message = message;
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/tcp/SimpleTcpCluster.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/tcp/SimpleTcpCluster.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/tcp/SimpleTcpCluster.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,932 @@
+/*
+ * Copyright 1999,2004-2005 The Apache Software Foundation.
+ * 
+ * Licensed 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.ha.tcp;
+
+import java.beans.PropertyChangeSupport;
+import java.io.IOException;
+import java.io.Serializable;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.catalina.Container;
+import org.apache.catalina.Context;
+import org.apache.catalina.Engine;
+import org.apache.catalina.Host;
+import org.apache.catalina.Lifecycle;
+import org.apache.catalina.LifecycleEvent;
+import org.apache.catalina.LifecycleException;
+import org.apache.catalina.LifecycleListener;
+import org.apache.catalina.Manager;
+import org.apache.catalina.Valve;
+import org.apache.catalina.ha.CatalinaCluster;
+import org.apache.catalina.tribes.Channel;
+import org.apache.catalina.tribes.ChannelListener;
+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.tribes.Member;
+import org.apache.catalina.tribes.MembershipListener;
+import org.apache.catalina.tribes.group.GroupChannel;
+
+import org.apache.catalina.ha.session.DeltaManager;
+import org.apache.catalina.ha.util.IDynamicProperty;
+import org.apache.catalina.util.LifecycleSupport;
+import org.apache.catalina.util.StringManager;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.tomcat.util.IntrospectionUtils;
+
+/**
+ * A <b>Cluster </b> implementation using simple multicast. Responsible for
+ * 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 $Revision: 379550 $, $Date: 2006-02-21 12:06:35 -0600 (Tue, 21 Feb 2006) $
+ */
+public class SimpleTcpCluster 
+    implements CatalinaCluster, Lifecycle, LifecycleListener, IDynamicProperty,
+               MembershipListener, ChannelListener{
+
+    public static Log log = LogFactory.getLog(SimpleTcpCluster.class);
+
+    // ----------------------------------------------------- Instance Variables
+
+    /**
+     * Descriptive information about this component implementation.
+     */
+    protected static final String info = "SimpleTcpCluster/2.2";
+
+    public static final String BEFORE_MEMBERREGISTER_EVENT = "before_member_register";
+
+    public static final String AFTER_MEMBERREGISTER_EVENT = "after_member_register";
+
+    public static final String BEFORE_MANAGERREGISTER_EVENT = "before_manager_register";
+
+    public static final String AFTER_MANAGERREGISTER_EVENT = "after_manager_register";
+
+    public static final String BEFORE_MANAGERUNREGISTER_EVENT = "before_manager_unregister";
+
+    public static final String AFTER_MANAGERUNREGISTER_EVENT = "after_manager_unregister";
+
+    public static final String BEFORE_MEMBERUNREGISTER_EVENT = "before_member_unregister";
+
+    public static final String AFTER_MEMBERUNREGISTER_EVENT = "after_member_unregister";
+
+    public static final String SEND_MESSAGE_FAILURE_EVENT = "send_message_failure";
+
+    public static final String RECEIVE_MESSAGE_FAILURE_EVENT = "receive_message_failure";
+    
+    /**
+     * Group channel.
+     */
+    protected Channel channel = new GroupChannel();
+
+
+    /**
+     * Name for logging purpose
+     */
+    protected String clusterImpName = "SimpleTcpCluster";
+
+    /**
+     * The string manager for this package.
+     */
+    protected StringManager sm = StringManager.getManager(Constants.Package);
+
+    /**
+     * The cluster name to join
+     */
+    protected String clusterName ;
+
+    /**
+     * The Container associated with this Cluster.
+     */
+    protected Container container = null;
+
+    /**
+     * The lifecycle event support for this component.
+     */
+    protected LifecycleSupport lifecycle = new LifecycleSupport(this);
+
+    /**
+     * Has this component been started?
+     */
+    protected boolean started = false;
+
+    /**
+     * The property change support for this component.
+     */
+    protected PropertyChangeSupport support = new PropertyChangeSupport(this);
+
+    /**
+     * The context name <->manager association for distributed contexts.
+     */
+    protected Map managers = new HashMap();
+
+    private String managerClassName = "org.apache.catalina.ha.session.DeltaManager";
+
+
+    private List valves = new ArrayList();
+
+    private org.apache.catalina.ha.ClusterDeployer clusterDeployer;
+
+    /**
+     * Listeners of messages
+     */
+    protected List clusterListeners = new ArrayList();
+
+    /**
+     * Comment for <code>notifyLifecycleListenerOnFailure</code>
+     */
+    private boolean notifyLifecycleListenerOnFailure = false;
+
+    /**
+     * dynamic sender <code>properties</code>
+     */
+    private Map properties = new HashMap();
+    
+    private int channelSendOptions = 
+        Channel.SEND_OPTIONS_ASYNCHRONOUS |
+        Channel.SEND_OPTIONS_SYNCHRONIZED_ACK |
+        Channel.SEND_OPTIONS_USE_ACK;
+
+    // ------------------------------------------------------------- Properties
+
+    public SimpleTcpCluster() {
+    }
+
+    /**
+     * Return descriptive information about this Cluster implementation and the
+     * corresponding version number, in the format
+     * <code>&lt;description&gt;/&lt;version&gt;</code>.
+     */
+    public String getInfo() {
+        return (info);
+    }
+
+    /**
+     * Set the name of the cluster to join, if no cluster with this name is
+     * present create one.
+     * 
+     * @param clusterName
+     *            The clustername to join
+     */
+    public void setClusterName(String clusterName) {
+        this.clusterName = clusterName;
+    }
+
+    /**
+     * Return the name of the cluster that this Server is currently configured
+     * to operate within.
+     * 
+     * @return The name of the cluster associated with this server
+     */
+    public String getClusterName() {
+        if(clusterName == null && container != null)
+            return container.getName() ;
+        return clusterName;
+    }
+
+    /**
+     * Set the Container associated with our Cluster
+     * 
+     * @param container
+     *            The Container to use
+     */
+    public void setContainer(Container container) {
+        Container oldContainer = this.container;
+        this.container = container;
+        support.firePropertyChange("container", oldContainer, this.container);
+    }
+
+    /**
+     * Get the Container associated with our Cluster
+     * 
+     * @return The Container associated with our Cluster
+     */
+    public Container getContainer() {
+        return (this.container);
+    }
+
+    /**
+     * @return Returns the notifyLifecycleListenerOnFailure.
+     */
+    public boolean isNotifyLifecycleListenerOnFailure() {
+        return notifyLifecycleListenerOnFailure;
+    }
+
+    /**
+     * @param notifyListenerOnFailure
+     *            The notifyLifecycleListenerOnFailure to set.
+     */
+    public void setNotifyLifecycleListenerOnFailure(
+            boolean notifyListenerOnFailure) {
+        boolean oldNotifyListenerOnFailure = this.notifyLifecycleListenerOnFailure;
+        this.notifyLifecycleListenerOnFailure = notifyListenerOnFailure;
+        support.firePropertyChange("notifyLifecycleListenerOnFailure",
+                oldNotifyListenerOnFailure,
+                this.notifyLifecycleListenerOnFailure);
+    }
+
+    public String getManagerClassName() {
+        if(managerClassName != null)
+            return managerClassName;
+        return (String)getProperty("manager.className");
+    }
+
+    public void setManagerClassName(String managerClassName) {
+        this.managerClassName = managerClassName;
+    }
+
+    /**
+     * Add cluster valve 
+     * Cluster Valves are only add to container when cluster is started!
+     * @param valve The new cluster Valve.
+     */
+    public void addValve(Valve valve) {
+        if (valve instanceof ClusterValve)
+            valves.add(valve);
+    }
+
+    /**
+     * get all cluster valves
+     * @return current cluster valves
+     */
+    public Valve[] getValves() {
+        return (Valve[]) valves.toArray(new Valve[valves.size()]);
+    }
+
+    /**
+     * Get the cluster listeners associated with this cluster. If this Array has
+     * no listeners registered, a zero-length array is returned.
+     */
+    public ClusterListener[] findClusterListeners() {
+        if (clusterListeners.size() > 0) {
+            ClusterListener[] listener = new ClusterListener[clusterListeners.size()];
+            clusterListeners.toArray(listener);
+            return listener;
+        } else
+            return new ClusterListener[0];
+
+    }
+
+    /**
+     * add cluster message listener and register cluster to this listener
+     * 
+     * @see org.apache.catalina.ha.CatalinaCluster#addClusterListener(org.apache.catalina.ha.MessageListener)
+     */
+    public void addClusterListener(ClusterListener listener) {
+        if (listener != null && !clusterListeners.contains(listener)) {
+            clusterListeners.add(listener);
+            listener.setCluster(this);
+        }
+    }
+
+    /**
+     * remove message listener and deregister Cluster from listener
+     * 
+     * @see org.apache.catalina.ha.CatalinaCluster#removeClusterListener(org.apache.catalina.ha.MessageListener)
+     */
+    public void removeClusterListener(ClusterListener listener) {
+        if (listener != null) {
+            clusterListeners.remove(listener);
+            listener.setCluster(null);
+        }
+    }
+
+    /**
+     * get current Deployer
+     */
+    public org.apache.catalina.ha.ClusterDeployer getClusterDeployer() {
+        return clusterDeployer;
+    }
+
+    /**
+     * set a new Deployer, must be set before cluster started!
+     */
+    public void setClusterDeployer(
+            org.apache.catalina.ha.ClusterDeployer clusterDeployer) {
+        this.clusterDeployer = clusterDeployer;
+    }
+
+    public void setChannel(Channel channel) {
+        this.channel = channel;
+    }
+
+    /**
+     * has members
+     */
+    protected boolean hasMembers = false;
+    public boolean hasMembers() {
+        return hasMembers;
+    }
+    
+    /**
+     * Get all current cluster members
+     * @return all members or empty array 
+     */
+    public Member[] getMembers() {
+        return channel.getMembers();
+    }
+
+    /**
+     * Return the member that represents this node.
+     * 
+     * @return Member
+     */
+    public Member getLocalMember() {
+        return channel.getLocalMember(true);
+    }
+
+    // ------------------------------------------------------------- dynamic
+    // manager property handling
+
+    /**
+     * JMX hack to direct use at jconsole
+     * 
+     * @param name
+     * @param value
+     */
+    public void setProperty(String name, String value) {
+        setProperty(name, (Object) value);
+    }
+
+    /**
+     * set config attributes with reflect and propagate to all managers
+     * 
+     * @param name
+     * @param value
+     */
+    public void setProperty(String name, Object value) {
+        if (log.isTraceEnabled())
+            log.trace(sm.getString("SimpleTcpCluster.setProperty", name, value,
+                    properties.get(name)));
+
+        properties.put(name, value);
+        if(started) {
+            // FIXME Hmm, is that correct when some DeltaManagers are direct configured inside Context?
+            // Why we not support it for other elements, like sender, receiver or membership?
+            // Must we restart element after change?
+            if (name.startsWith("manager")) {
+                String key = name.substring("manager".length() + 1);
+                String pvalue = value.toString();
+                for (Iterator iter = managers.values().iterator(); iter.hasNext();) {
+                    Manager manager = (Manager) iter.next();
+                    if(manager instanceof DeltaManager && ((ClusterManager) manager).isDefaultMode()) {
+                        IntrospectionUtils.setProperty(manager, key, pvalue );
+                    }
+                }
+            } 
+        }
+    }
+
+    /**
+     * get current config
+     * 
+     * @param key
+     * @return The property
+     */
+    public Object getProperty(String key) {
+        if (log.isTraceEnabled())
+            log.trace(sm.getString("SimpleTcpCluster.getProperty", key));
+        return properties.get(key);
+    }
+
+    /**
+     * Get all properties keys
+     * 
+     * @return An iterator over the property names.
+     */
+    public Iterator getPropertyNames() {
+        return properties.keySet().iterator();
+    }
+
+    /**
+     * remove a configured property.
+     * 
+     * @param key
+     */
+    public void removeProperty(String key) {
+        properties.remove(key);
+    }
+
+    /**
+     * transfer properties from cluster configuration to subelement bean.
+     * @param prefix
+     * @param bean
+     */
+    protected void transferProperty(String prefix, Object bean) {
+        if (prefix != null) {
+            for (Iterator iter = getPropertyNames(); iter.hasNext();) {
+                String pkey = (String) iter.next();
+                if (pkey.startsWith(prefix)) {
+                    String key = pkey.substring(prefix.length() + 1);
+                    Object value = getProperty(pkey);
+                    IntrospectionUtils.setProperty(bean, key, value.toString());
+                }
+            }
+        }
+    }
+
+    // --------------------------------------------------------- Public Methods
+
+    /**
+     * @return Returns the managers.
+     */
+    public Map getManagers() {
+        return managers;
+    }
+
+    public Channel getChannel() {
+        return channel;
+    }
+
+    /**
+     * Create new Manager without add to cluster (comes with start the manager)
+     * 
+     * @param name
+     *            Context Name of this manager
+     * @see org.apache.catalina.Cluster#createManager(java.lang.String)
+     * @see #addManager(String, Manager)
+     * @see DeltaManager#start()
+     */
+    public synchronized Manager createManager(String name) {
+        if (log.isDebugEnabled()) log.debug("Creating ClusterManager for context " + name + " using class " + getManagerClassName());
+        Manager manager = null;
+        ClassLoader oldCtxLoader = Thread.currentThread().getContextClassLoader();
+        try {
+            Thread.currentThread().setContextClassLoader(SimpleTcpCluster.class.getClassLoader());
+            manager = (Manager) getClass().getClassLoader().loadClass(getManagerClassName()).newInstance();
+        } catch (Exception x) {
+            log.error("Unable to load class for replication manager", x);
+            manager = new org.apache.catalina.ha.session.DeltaManager();
+        } finally {
+            Thread.currentThread().setContextClassLoader(oldCtxLoader);
+            if(manager != null) {
+                manager.setDistributable(true);
+                if (manager instanceof ClusterManager) {
+                    ClusterManager cmanager = (ClusterManager) manager ;
+                    cmanager.setDefaultMode(true);
+                    cmanager.setName(getManagerName(name,manager));
+                    cmanager.setCluster(this);
+                }
+            }
+        }
+        return manager;
+    }
+
+    /**
+     * remove an application form cluster replication bus
+     * 
+     * @see org.apache.catalina.ha.CatalinaCluster#removeManager(java.lang.String,Manager)
+     */
+    public void removeManager(String name,Manager manager) {
+        if (manager != null) {
+            // Notify our interested LifecycleListeners
+            lifecycle.fireLifecycleEvent(BEFORE_MANAGERUNREGISTER_EVENT,manager);
+            managers.remove(getManagerName(name,manager));
+            if (manager instanceof ClusterManager) ((ClusterManager) manager).setCluster(null);
+            // Notify our interested LifecycleListeners
+            lifecycle.fireLifecycleEvent(AFTER_MANAGERUNREGISTER_EVENT, manager);
+        }
+    }
+
+    /**
+     * add an application to cluster replication bus
+     * 
+     * @param name
+     *            of the context
+     * @param manager
+     *            manager to register
+     * @see org.apache.catalina.ha.CatalinaCluster#addManager(java.lang.String,
+     *      org.apache.catalina.Manager)
+     */
+    public void addManager(String name, Manager manager) {
+        if (!manager.getDistributable()) {
+            log.warn("Manager with name " + name + " is not distributable, can't add as cluster manager");
+            return;
+        }
+        // Notify our interested LifecycleListeners
+        lifecycle.fireLifecycleEvent(BEFORE_MANAGERREGISTER_EVENT, manager);
+        String clusterName = getManagerName(name, manager);
+        if (manager instanceof ClusterManager) {
+            ClusterManager cmanager = (ClusterManager) manager ;
+            cmanager.setName(clusterName);
+            cmanager.setCluster(this);
+            if(cmanager.isDefaultMode()) transferProperty("manager",cmanager);
+        }
+        managers.put(clusterName, manager);
+        // Notify our interested LifecycleListeners
+        lifecycle.fireLifecycleEvent(AFTER_MANAGERREGISTER_EVENT, manager);
+    }
+
+    /**
+     * @param name
+     * @param manager
+     * @return
+     */
+    public String getManagerName(String name, Manager manager) {
+        String clusterName = name ;
+        if(getContainer() instanceof Engine) {
+            Container context = manager.getContainer() ;
+            if(context != null && context instanceof Context) {
+                Container host = ((Context)context).getParent();
+                if(host != null && host instanceof Host)
+                    clusterName = host.getName()  + name ;
+            }
+        }
+        return clusterName;
+    }
+
+    /*
+     * Get Manager
+     * 
+     * @see org.apache.catalina.ha.CatalinaCluster#getManager(java.lang.String)
+     */
+    public Manager getManager(String name) {
+        return (Manager) managers.get(name);
+    }
+    
+    // ------------------------------------------------------ Lifecycle Methods
+
+    /**
+     * Execute a periodic task, such as reloading, etc. This method will be
+     * invoked inside the classloading context of this container. Unexpected
+     * throwables will be caught and logged.
+     * @see org.apache.catalina.ha.deploy.FarmWarDeployer#backgroundProcess()
+     * @see ReplicationTransmitter#backgroundProcess()
+     */
+    public void backgroundProcess() {
+        if (clusterDeployer != null) clusterDeployer.backgroundProcess();
+        //send a heartbeat through the channel
+        if ( channel !=null ) channel.heartbeat();
+    }
+
+    /**
+     * Add a lifecycle event listener to this component.
+     * 
+     * @param listener
+     *            The listener to add
+     */
+    public void addLifecycleListener(LifecycleListener listener) {
+        lifecycle.addLifecycleListener(listener);
+    }
+
+    /**
+     * Get the lifecycle listeners associated with this lifecycle. If this
+     * Lifecycle has no listeners registered, a zero-length array is returned.
+     */
+    public LifecycleListener[] findLifecycleListeners() {
+
+        return lifecycle.findLifecycleListeners();
+
+    }
+
+    /**
+     * Remove a lifecycle event listener from this component.
+     * 
+     * @param listener
+     *            The listener to remove
+     */
+    public void removeLifecycleListener(LifecycleListener listener) {
+        lifecycle.removeLifecycleListener(listener);
+    }
+
+    /**
+     * Use as base to handle start/stop/periodic Events from host. Currently
+     * only log the messages as trace level.
+     * 
+     * @see org.apache.catalina.LifecycleListener#lifecycleEvent(org.apache.catalina.LifecycleEvent)
+     */
+    public void lifecycleEvent(LifecycleEvent lifecycleEvent) {
+        if (log.isTraceEnabled())
+            log.trace(sm.getString("SimpleTcpCluster.event.log", lifecycleEvent.getType(), lifecycleEvent.getData()));
+    }
+
+    // ------------------------------------------------------ public
+
+    /**
+     * Prepare for the beginning of active use of the public methods of this
+     * component. This method should be called after <code>configure()</code>,
+     * and before any of the public methods of the component are utilized. <BR>
+     * Starts the cluster communication channel, this will connect with the
+     * other nodes in the cluster, and request the current session state to be
+     * transferred to this node.
+     * 
+     * @exception IllegalStateException
+     *                if this component has already been started
+     * @exception LifecycleException
+     *                if this component detects a fatal error that prevents this
+     *                component from being used
+     */
+    public void start() throws LifecycleException {
+        if (started)
+            throw new LifecycleException(sm.getString("cluster.alreadyStarted"));
+        if (log.isInfoEnabled()) log.info("Cluster is about to start");
+
+        // Notify our interested LifecycleListeners
+        lifecycle.fireLifecycleEvent(BEFORE_START_EVENT, this);
+        try {
+            if ( clusterDeployer != null ) clusterDeployer.setCluster(this);
+            this.registerClusterValve();
+            if ( channel == null ) channel = new GroupChannel();
+            channel.addMembershipListener(this);
+            channel.addChannelListener(this);
+            channel.start(channel.DEFAULT);
+            if (clusterDeployer != null) clusterDeployer.start();
+            this.started = true;
+            // Notify our interested LifecycleListeners
+            lifecycle.fireLifecycleEvent(AFTER_START_EVENT, this);
+        } catch (Exception x) {
+            log.error("Unable to start cluster.", x);
+            throw new LifecycleException(x);
+        }
+    }
+
+    /**
+     * register all cluster valve to host or engine
+     * @throws Exception
+     * @throws ClassNotFoundException
+     */
+    protected void registerClusterValve() throws Exception {
+        if(container != null ) {
+            for (Iterator iter = valves.iterator(); iter.hasNext();) {
+                ClusterValve valve = (ClusterValve) iter.next();
+                if (log.isDebugEnabled())
+                    log.debug("Invoking addValve on " + getContainer()
+                            + " with class=" + valve.getClass().getName());
+                if (valve != null) {
+                    IntrospectionUtils.callMethodN(getContainer(), "addValve",
+                            new Object[] { valve },
+                            new Class[] { org.apache.catalina.Valve.class });
+
+                }
+                valve.setCluster(this);
+            }
+        }
+    }
+
+    /**
+     * unregister all cluster valve to host or engine
+     * @throws Exception
+     * @throws ClassNotFoundException
+     */
+    protected void unregisterClusterValve() throws Exception {
+        for (Iterator iter = valves.iterator(); iter.hasNext();) {
+            ClusterValve valve = (ClusterValve) iter.next();
+            if (log.isDebugEnabled())
+                log.debug("Invoking removeValve on " + getContainer()
+                        + " with class=" + valve.getClass().getName());
+            if (valve != null) {
+                    IntrospectionUtils.callMethodN(getContainer(), "removeValve",
+                        new Object[] { valve }, new Class[] { org.apache.catalina.Valve.class });
+            }
+            valve.setCluster(this);
+        }
+    }
+
+    /**
+     * Gracefully terminate the active cluster component.<br/>
+     * This will disconnect the cluster communication channel, stop the
+     * listener and deregister the valves from host or engine.<br/><br/>
+     * <b>Note:</b><br/>The sub elements receiver, sender, membership,
+     * listener or valves are not removed. You can easily start the cluster again.
+     * 
+     * @exception IllegalStateException
+     *                if this component has not been started
+     * @exception LifecycleException
+     *                if this component detects a fatal error that needs to be
+     *                reported
+     */
+    public void stop() throws LifecycleException {
+
+        if (!started)
+            throw new IllegalStateException(sm.getString("cluster.notStarted"));
+        // Notify our interested LifecycleListeners
+        lifecycle.fireLifecycleEvent(BEFORE_STOP_EVENT, this);
+
+        if (clusterDeployer != null) clusterDeployer.stop();
+        this.managers.clear();
+        try {
+            if ( clusterDeployer != null ) clusterDeployer.setCluster(null);
+            channel.stop(Channel.DEFAULT);
+            channel.removeChannelListener(this);
+            channel.removeMembershipListener(this);
+            this.unregisterClusterValve();
+        } catch (Exception x) {
+            log.error("Unable to stop cluster valve.", x);
+        }
+        started = false;
+        // Notify our interested LifecycleListeners
+        lifecycle.fireLifecycleEvent(AFTER_STOP_EVENT, this);
+   }
+
+    
+
+
+    /**
+     * send message to all cluster members
+     * @param msg message to transfer
+     * 
+     * @see org.apache.catalina.ha.CatalinaCluster#send(org.apache.catalina.ha.ClusterMessage)
+     */
+    public void send(ClusterMessage msg) {
+        send(msg, null);
+    }
+
+    /**
+     * send message to all cluster members same cluster domain
+     * 
+     * @see org.apache.catalina.ha.CatalinaCluster#send(org.apache.catalina.ha.ClusterMessage)
+     */
+    public void sendClusterDomain(ClusterMessage msg) {
+        send(msg,null);
+    } 
+
+    
+    /**
+     * send a cluster message to one member
+     * 
+     * @param msg message to transfer
+     * @param dest Receiver member
+     * @see org.apache.catalina.ha.CatalinaCluster#send(org.apache.catalina.ha.ClusterMessage,
+     *      org.apache.catalina.ha.Member)
+     */
+    public void send(ClusterMessage msg, Member dest) {
+        try {
+            msg.setAddress(getLocalMember());
+            if (dest != null) {
+                if (!getLocalMember().equals(dest)) {
+                    channel.send(new Member[] {dest}, msg,channelSendOptions);
+                } else
+                    log.error("Unable to send message to local member " + msg);
+            } else {
+                channel.send(channel.getMembers(),msg,channelSendOptions);
+            }
+        } catch (Exception x) {
+            log.error("Unable to send message through cluster sender.", x);
+        }
+    }
+
+    /**
+     * New cluster member is registered
+     * 
+     * @see org.apache.catalina.ha.MembershipListener#memberAdded(org.apache.catalina.ha.Member)
+     */
+    public void memberAdded(Member member) {
+        try {
+            hasMembers = channel.hasMembers();
+            if (log.isInfoEnabled()) log.info("Replication member added:" + member);
+            // Notify our interested LifecycleListeners
+            lifecycle.fireLifecycleEvent(BEFORE_MEMBERREGISTER_EVENT, member);
+            // Notify our interested LifecycleListeners
+            lifecycle.fireLifecycleEvent(AFTER_MEMBERREGISTER_EVENT, member);
+        } catch (Exception x) {
+            log.error("Unable to connect to replication system.", x);
+        }
+
+    }
+
+    /**
+     * Cluster member is gone
+     * 
+     * @see org.apache.catalina.ha.MembershipListener#memberDisappeared(org.apache.catalina.ha.Member)
+     */
+    public void memberDisappeared(Member member) {
+        try {
+            hasMembers = channel.hasMembers();            
+            if (log.isInfoEnabled()) log.info("Received member disappeared:" + member);
+            // Notify our interested LifecycleListeners
+            lifecycle.fireLifecycleEvent(BEFORE_MEMBERUNREGISTER_EVENT, member);
+            // Notify our interested LifecycleListeners
+            lifecycle.fireLifecycleEvent(AFTER_MEMBERUNREGISTER_EVENT, member);
+        } catch (Exception x) {
+            log.error("Unable remove cluster node from replication system.", x);
+        }
+    }
+
+    // --------------------------------------------------------- receiver
+    // messages
+
+    /**
+     * notify all listeners from receiving a new message is not ClusterMessage
+     * emitt Failure Event to LifecylceListener
+     * 
+     * @param message
+     *            receveived Message
+     */
+    public boolean accept(Serializable msg, Member sender) {
+        return (msg instanceof ClusterMessage);
+    }
+    
+    
+    public void messageReceived(Serializable message, Member sender) {
+        ClusterMessage fwd = (ClusterMessage)message;
+        fwd.setAddress(sender);
+        messageReceived(fwd);
+    }
+
+    public void messageReceived(ClusterMessage message) {
+
+        long start = 0;
+        if (log.isDebugEnabled() && message != null)
+            log.debug("Assuming clocks are synched: Replication for "
+                    + message.getUniqueId() + " took="
+                    + (System.currentTimeMillis() - (message).getTimestamp())
+                    + " ms.");
+
+        //invoke all the listeners
+        boolean accepted = false;
+        if (message != null) {
+            for (Iterator iter = clusterListeners.iterator(); iter.hasNext();) {
+                ClusterListener listener = (ClusterListener) iter.next();
+                if (listener.accept(message)) {
+                    accepted = true;
+                    listener.messageReceived(message);
+                }
+            }
+        }
+        if (!accepted && log.isDebugEnabled()) {
+            if (notifyLifecycleListenerOnFailure) {
+                Member dest = message.getAddress();
+                // Notify our interested LifecycleListeners
+                lifecycle.fireLifecycleEvent(RECEIVE_MESSAGE_FAILURE_EVENT,
+                        new SendMessageData(message, dest, null));
+            }
+            log.debug("Message " + message.toString() + " from type "
+                    + message.getClass().getName()
+                    + " transfered but no listener registered");
+        }
+        return;
+    }
+
+    // --------------------------------------------------------- Logger
+
+    public Log getLogger() {
+        return log;
+    }
+
+
+
+    
+    // ------------------------------------------------------------- deprecated
+
+    /**
+     * 
+     * @see org.apache.catalina.Cluster#setProtocol(java.lang.String)
+     */
+    public void setProtocol(String protocol) {
+    }
+
+    /**
+     * @see org.apache.catalina.Cluster#getProtocol()
+     */
+    public String getProtocol() {
+        return null;
+    }
+
+    /**
+     * @see org.apache.catalina.Cluster#startContext(java.lang.String)
+     */
+    public void startContext(String contextPath) throws IOException {
+        
+    }
+
+    /**
+     * @see org.apache.catalina.Cluster#installContext(java.lang.String, java.net.URL)
+     */
+    public void installContext(String contextPath, URL war) {
+        
+    }
+
+    /**
+     * @see org.apache.catalina.Cluster#stop(java.lang.String)
+     */
+    public void stop(String contextPath) throws IOException {
+        
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/tcp/mbeans-descriptors.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/tcp/mbeans-descriptors.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/tcp/mbeans-descriptors.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,1046 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mbeans-descriptors PUBLIC
+   "-//Apache Software Foundation//DTD Model MBeans Configuration File"
+   "http://jakarta.apache.org/commons/dtds/mbeans-descriptors.dtd">
+<mbeans-descriptors>
+
+  <mbean         name="SimpleTcpCluster"
+           description="Tcp Cluster implementation"
+               domain="Catalina"
+                group="Cluster"
+                 type="org.apache.catalina.ha.tcp.SimpleTcpCluster">
+    <attribute   name="info"
+          description="Class version info"
+                 type="java.lang.String"
+                 writeable="false"/>
+    <attribute   name="notifyLifecycleListenerOnFailure"
+          description="notify lifecycleListener from message transfer failure"
+			     is="true"
+                 type="boolean"/>                 
+    <attribute   name="clusterName"
+          description="name of cluster"
+                 type="java.lang.String"/>
+    <attribute   name="managerClassName"
+          description="session mananager classname"
+                 type="java.lang.String"/>
+    <attribute   name="clusterLogName"
+          description="Name of cluster transfer log device"
+                 type="java.lang.String"/>
+    <attribute   name="doClusterLog"
+			     is="true"
+          description="enable cluster log transfer logging"
+                 type="boolean"/>
+    <operation   name="setProperty"
+               description="set a property to all cluster managers (with prefix 'manager.')"
+               impact="ACTION"
+               returnType="void">
+      <parameter name="key"
+                 description="Property name"
+                 type="java.lang.String"/>
+      <parameter name="value"
+                 description="Property value"
+                 type="java.lang.String"/>
+    </operation>
+
+    <operation   name="send"
+               description="send message to all cluster members"
+               impact="ACTION"
+               returnType="void">
+      <parameter name="message"
+                 description="replication message"
+                 type="org.apache.catalina.ha.ClusterMessage"/>
+    </operation>
+    
+    <operation   name="sendClusterDomain"
+               description="send message to all cluster members with same domain"
+               impact="ACTION"
+               returnType="void">
+      <parameter name="message"
+                 description="replication message"
+                 type="org.apache.catalina.ha.ClusterMessage"/>
+    </operation>
+        
+    <operation   name="sendToMember"
+               description="send message to one cluster member"
+               impact="ACTION"
+               returnType="void">
+      <parameter name="message"
+                 description="replication message"
+                 type="org.apache.catalina..cluster.ClusterMessage"/>
+      <parameter name="member"
+                 description="cluster member"
+                 type="java.lang.String"/>
+    </operation>
+
+    <operation   name="start"
+               description="Start the cluster"
+               impact="ACTION"
+               returnType="void">
+    </operation>
+    
+    <operation name="stop"
+               description="Stop the cluster"
+               impact="ACTION"
+               returnType="void">
+    </operation>
+                 
+  </mbean>
+
+  <mbean         name="ClusterReceiverBase"
+           description="Tcp Cluster ReplicationListener implementation"
+               domain="Catalina"
+                group="Cluster"
+                 type="org.apache.catalina.ha.tcp.ClusterReceiverBase">
+    <attribute   name="info"
+          description="Class version info"
+                 type="java.lang.String"
+                 writeable="false"/>
+    <attribute   name="tcpListenAddress"
+          description="tcp listener address"
+                 type="java.lang.String"/>
+    <attribute   name="tcpListenPort"
+          description="tcp listener port"
+                 type="int"/>
+    <attribute   name="tcpThreadCount"
+          description="number of tcp listener worker threads"
+                 type="int"/>
+    <attribute   name="tcpSelectorTimeout"
+          description="tcp listener Selector timeout"
+                 type="long"/>
+    <attribute   name="nrOfMsgsReceived"
+          description="number of messages received from other nodes"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="receivedTime"
+          description="total time message send time"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="receivedProcessingTime"
+          description="received processing time"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="minReceivedProcessingTime"
+          description="minimal received processing time"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="avgReceivedProcessingTime"
+          description="received processing time / nrOfRequests"
+                 type="double"
+                 writeable="false"/>
+    <attribute   name="maxReceivedProcessingTime"
+          description="maximal received processing time"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="doReceivedProcessingStats"
+          description="create received processing time stats"
+			     is="true"
+                 type="boolean" />                
+    <attribute   name="avgTotalReceivedBytes"
+          description="received totalReceivedBytes / nrOfMsgsReceived"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="totalReceivedBytes"
+          description="number of bytes received"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="sendAck"
+          description="send ack after data received"
+			     is="true"
+                 type="boolean"
+                 writeable="false" />
+    <attribute   name="compress"
+          description="data received compressed"
+			     is="true"
+                 type="boolean"
+                 writeable="false" />
+    <attribute   name="doListen"
+          description="is port really started"
+			     is="true"
+                 type="boolean"
+                 writeable="false" />
+                 
+	<operation name="resetStatistics"
+               description="Reset all statistics"
+               impact="ACTION"
+               returnType="void">
+    </operation>	
+
+    <operation   name="start"
+               description="Start the cluster"
+               impact="ACTION"
+               returnType="void">
+    </operation>
+    
+    <operation name="stop"
+               description="Stop the cluster"
+               impact="ACTION"
+               returnType="void">
+    </operation>
+                 
+  </mbean>
+
+  <mbean         name="SocketReplicationListener"
+           description="Tcp Cluster SocketReplicationListener implementation"
+               domain="Catalina"
+                group="Cluster"
+                 type="org.apache.catalina.ha.tcp.SocketReplicationListener">
+    <attribute   name="info"
+          description="Class version info"
+                 type="java.lang.String"
+                 writeable="false"/>
+    <attribute   name="tcpListenAddress"
+          description="tcp listener address"
+                 type="java.lang.String"/>
+    <attribute   name="tcpListenPort"
+          description="tcp listener port"
+                 type="int"/>
+    <attribute   name="tcpListenMaxPort"
+          description="max tcp listen used port"
+                 type="int"/>
+    <attribute   name="tcpListenTimeout"
+          description="max tcp listen timeout (sec) wait for ServerSocket start"
+                 type="int"/>                
+    <attribute   name="nrOfMsgsReceived"
+          description="number of messages received from other nodes"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="receivedTime"
+          description="total time message send time"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="receivedProcessingTime"
+          description="received processing time"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="minReceivedProcessingTime"
+          description="minimal received processing time"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="avgReceivedProcessingTime"
+          description="received processing time / nrOfRequests"
+                 type="double"
+                 writeable="false"/>
+    <attribute   name="maxReceivedProcessingTime"
+          description="maximal received processing time"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="doReceivedProcessingStats"
+          description="create received processing time stats"
+			     is="true"
+                 type="boolean" />                
+    <attribute   name="avgTotalReceivedBytes"
+          description="received totalReceivedBytes / nrOfMsgsReceived"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="totalReceivedBytes"
+          description="number of bytes received"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="sendAck"
+          description="send ack after data received"
+			     is="true"
+                 type="boolean"
+                 writeable="false" />
+   <attribute   name="compress"
+          description="data received compressed"
+			     is="true"
+                 type="boolean"
+                 writeable="false" />
+   <attribute   name="doListen"
+          description="is port really started"
+			     is="true"
+                 type="boolean"
+                 writeable="false" />
+                 
+	<operation name="resetStatistics"
+               description="Reset all statistics"
+               impact="ACTION"
+               returnType="void">
+    </operation>	
+
+    <operation   name="start"
+               description="Start the cluster"
+               impact="ACTION"
+               returnType="void">
+    </operation>
+    
+    <operation name="stop"
+               description="Stop the cluster"
+               impact="ACTION"
+               returnType="void">
+    </operation>
+                 
+  </mbean>
+  
+  <mbean         name="ReplicationTransmitter"
+          description="Tcp replication transmitter"
+               domain="Catalina"
+                group="ClusterSender"
+                 type="org.apache.catalina.ha.tcp.ReplicationTransmitter">
+    <attribute   name="info"
+          description="Class version info"
+                 type="java.lang.String"
+                 writeable="false"/>
+    <attribute   name="replicationMode"
+          description="replication mode (synchnous,pooled.asynchnous,fastasyncqueue)"
+                 type="java.lang.String"/>
+    <attribute   name="ackTimeout"
+          description="acknowledge timeout"
+                 type="long"/>
+    <attribute   name="autoConnect"
+          description="is sender disabled, fork a new socket"
+			     is="true"
+                 type="boolean" />
+    <attribute   name="waitForAck"
+          description="Wait for ack after data send"
+			     is="true"
+                 type="boolean"
+                 writeable="false" />
+    <attribute   name="processingTime"
+          description="sending processing time"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="minProcessingTime"
+          description="minimal sending processing time"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="avgProcessingTime"
+          description="processing time / nrOfRequests"
+                 type="double"
+                 writeable="false"/>
+    <attribute   name="maxProcessingTime"
+          description="maximal sending processing time"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="doTransmitterProcessingStats"
+          description="create processing time stats"
+			     is="true"
+                 type="boolean" />                
+    <attribute   name="nrOfRequests"
+          description="number of send messages to other members"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="totalBytes"
+          description="number of bytes transfered"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="failureCounter"
+          description="number of wrong transfers"
+                 type="long"
+                 writeable="false"/>
+	<attribute name="senderObjectNames"
+               description="get all sender object names"
+               type="[Ljavax.management.ObjectName;"
+               writeable="false"/>
+    <operation   name="start"
+               description="Start the cluster"
+               impact="ACTION"
+               returnType="void">
+    </operation>    
+    <operation name="stop"
+               description="Stop the cluster"
+               impact="ACTION"
+               returnType="void">
+    </operation>
+	<operation name="resetStatistics"
+               description="Reset all statistics"
+               impact="ACTION"
+               returnType="void">
+    </operation>	
+	<operation name="checkKeepAlive"
+               description="Check all sender connection for close socket (keepalive)"
+               impact="ACTION"
+               returnType="void">
+    </operation>
+  </mbean>
+
+  <mbean         name="AsyncSocketSender"
+          description="Async Cluster Sender"
+               domain="Catalina"
+                group="IDataSender"
+                 type="org.apache.catalina.ha.tcp.AsyncSocketSender">
+    <attribute   name="info"
+          description="Class version info"
+                 type="java.lang.String"
+                 writeable="false"/>
+    <attribute   name="address"
+          description="sender ip address"
+                 type="java.net.InetAddress"
+                 writeable="false"/>
+    <attribute   name="port"
+          description="sender port"
+                 type="int"
+                 writeable="false" />
+    <attribute   name="suspect"
+          description="Socket is gone"
+                 type="boolean"/>
+    <attribute   name="waitForAck"
+          description="Wait for ack after data send"
+			     is="true"
+                 type="boolean"
+                 writeable="false"/>
+    <attribute   name="ackTimeout"
+          description="acknowledge timeout"
+                 type="long"/>                 
+    <attribute   name="avgMessageSize"
+                 writeable="false"
+          description="avg message size (totalbytes/nrOfRequests"
+                 type="long"/>
+    <attribute   name="queueSize"
+                 writeable="false"
+          description="queue size"
+                 type="int"/>
+    <attribute   name="queuedNrOfBytes"
+                 writeable="false"
+          description="number of bytes over all queued messages"
+                 type="long"/>
+    <attribute   name="messageTransferStarted"
+          description="message is in transfer"
+                 type="boolean"
+                 is="true"
+                 writeable="false"/>
+    <attribute   name="keepAliveTimeout"
+          description="active socket keep alive timeout"
+                 type="long"/>
+    <attribute   name="keepAliveMaxRequestCount"
+          description="max request over this socket"
+                 type="int"/>
+    <attribute   name="keepAliveCount"
+          description="keep Alive request count"
+                 type="int"
+                 writeable="false"/>
+    <attribute   name="keepAliveConnectTime"
+          description="Connect time for keep alive"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="resend"
+          description="after send failure make a resend"
+			     is="true"
+                 type="boolean" />
+    <attribute   name="connected"
+                 is="true"
+          description="socket connected"
+                 type="boolean"
+                 writeable="false"/>
+    <attribute   name="nrOfRequests"
+          description="number of send messages to other members"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="totalBytes"
+          description="number of bytes transfered"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="processingTime"
+          description="sending processing time"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="minProcessingTime"
+          description="minimal sending processing time"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="avgProcessingTime"
+          description="processing time / nrOfRequests"
+                 type="double"
+                 writeable="false"/>
+    <attribute   name="maxProcessingTime"
+          description="maximal sending processing time"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="doProcessingStats"
+          description="create processing time stats"
+			     is="true"
+                 type="boolean" />
+    <attribute   name="waitAckTime"
+          description="sending waitAck time"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="minWaitAckTime"
+          description="minimal sending waitAck time"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="avgWaitAckTime"
+          description="waitAck time / nrOfRequests"
+                 type="double"
+                 writeable="false"/>
+    <attribute   name="maxWaitAckTime"
+          description="maximal sending waitAck time"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="doWaitAckStats"
+          description="create waitAck time stats"
+			     is="true"
+                 type="boolean" />
+    <attribute   name="connectCounter"
+          description="counts connects"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="disconnectCounter"
+          description="counts disconnects"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="socketOpenCounter"
+          description="counts open socket (KeepAlive and connects)"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="socketOpenFailureCounter"
+          description="counts open socket failures"
+                 type="long"
+                 writeable="false"/>                 				 
+    <attribute   name="socketCloseCounter"
+          description="counts closed socket (KeepAlive and disconnects)"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="missingAckCounter"
+          description="counts missing ack"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="dataResendCounter"
+          description="counts data resends"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="dataFailureCounter"
+          description="counts data send failures"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="inQueueCounter"
+          description="counts all queued messages"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="outQueueCounter"
+          description="counts all successfully sended messages"
+                 type="long"
+                 writeable="false"/>
+	<operation name="connect"
+               description="connect to other replication node"
+               impact="ACTION"
+               returnType="void">
+    </operation>
+	<operation name="disconnect"
+               description="disconnect to other replication node"
+               impact="ACTION"
+               returnType="void">
+    </operation>
+	<operation name="checkKeepAlive"
+               description="Check connection for close socket"
+               impact="ACTION"
+               returnType="boolean">
+    </operation>
+	<operation name="resetStatistics"
+               description="Reset all statistics"
+               impact="ACTION"
+               returnType="void">
+    </operation>
+				 
+  </mbean>
+
+ <mbean         name="FastAsyncSocketSender"
+          description="Fast Async Cluster Sender"
+               domain="Catalina"
+                group="IDataSender"
+                 type="org.apache.catalina.ha.tcp.FastAsyncSocketSender">
+    <attribute   name="info"
+          description="Class version info"
+                 type="java.lang.String"
+                 writeable="false"/>
+    <attribute   name="threadPriority"
+          description="change queue thread priority"
+                 type="int"/>                 
+    <attribute   name="address"
+          description="sender ip address"
+                 type="java.net.InetAddress"
+                 writeable="false"/>
+    <attribute   name="port"
+          description="sender port"
+                 type="int"
+                 writeable="false" />
+    <attribute   name="suspect"
+          description="Socket is gone"
+                 type="boolean"/>
+    <attribute   name="waitForAck"
+          description="Wait for ack after data send"
+			     is="true"
+                 type="boolean"
+                 writeable="false"/>
+    <attribute   name="ackTimeout"
+          description="acknowledge timeout"
+                 type="long"/>
+    <attribute   name="avgMessageSize"
+                 writeable="false"
+          description="avg message size (totalbytes/nrOfRequests"
+                 type="long" />
+    <attribute   name="queueSize"
+                 writeable="false"
+          description="queue size"
+                 type="int"/>
+    <attribute   name="queuedNrOfBytes"
+                 writeable="false"
+          description="number of bytes over all queued messages"
+                 type="long"/>
+    <attribute   name="messageTransferStarted"
+          description="message is in transfer"
+                 type="boolean"
+                 is="true"
+                 writeable="false"/>
+    <attribute   name="keepAliveTimeout"
+          description="active socket keep alive timeout"
+                 type="long"/>
+    <attribute   name="keepAliveMaxRequestCount"
+          description="max request over this socket"
+                 type="int"/>
+    <attribute   name="queueAddWaitTimeout"
+          description="add wait timeout (default 10000 msec)"
+                 type="long"/>
+    <attribute   name="queueRemoveWaitTimeout"
+          description="remove wait timeout (default 30000 msec)"
+                 type="long"/>
+    <attribute   name="maxQueueLength"
+          description="max queue length"
+                 type="int"/>
+    <attribute   name="queueTimeWait"
+          description="remember queue wait times"
+                 is="true"
+                 type="boolean"/>
+    <attribute   name="queueCheckLock"
+          description="check to lost locks"
+                 is="true"
+                 type="boolean"/>
+    <attribute   name="queueDoStats"
+          description="activated queue stats"
+                 is="true"
+                 type="boolean"/>
+    <attribute   name="keepAliveCount"
+          description="keep Alive request count"
+                 type="int"
+                 writeable="false"/>
+    <attribute   name="keepAliveConnectTime"
+          description="Connect time for keep alive"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="resend"
+          description="after send failure make a resend"
+			     is="true"
+                 type="boolean" />
+    <attribute   name="connected"
+                 is="true"
+          description="socket connected"
+                 type="boolean"
+                 writeable="false"/>
+    <attribute   name="nrOfRequests"
+          description="number of send messages to other members"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="totalBytes"
+          description="number of bytes transfered"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="processingTime"
+          description="sending processing time"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="minProcessingTime"
+          description="minimal sending processing time"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="avgProcessingTime"
+          description="processing time / nrOfRequests"
+                 type="double"
+                 writeable="false"/>
+    <attribute   name="maxProcessingTime"
+          description="maximal sending processing time"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="doProcessingStats"
+          description="create Processing time stats"
+			     is="true"
+                 type="boolean" />                 
+    <attribute   name="waitAckTime"
+          description="sending waitAck time"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="minWaitAckTime"
+          description="minimal sending waitAck time"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="avgWaitAckTime"
+          description="waitAck time / nrOfRequests"
+                 type="double"
+                 writeable="false"/>
+    <attribute   name="maxWaitAckTime"
+          description="maximal sending waitAck time"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="doWaitAckStats"
+          description="create waitAck time stats"
+			     is="true"
+                 type="boolean" />
+    <attribute   name="connectCounter"
+          description="counts connects"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="disconnectCounter"
+          description="counts disconnects"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="socketOpenCounter"
+          description="counts open socket (KeepAlive and connects)"
+                 type="long"
+                 writeable="false"/>				 
+    <attribute   name="socketOpenFailureCounter"
+          description="counts open socket failures"
+                 type="long"
+                 writeable="false"/>                 				 
+    <attribute   name="socketCloseCounter"
+          description="counts closed socket (KeepAlive and disconnects)"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="missingAckCounter"
+          description="counts missing ack"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="dataResendCounter"
+          description="counts data resends"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="dataFailureCounter"
+          description="counts data send failures"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="inQueueCounter"
+          description="counts all queued messages"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="outQueueCounter"
+          description="counts all successfully sended messages"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="queueAddWaitTime"
+          description="queue add wait time (tomcat thread waits)"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="queueRemoveWaitTime"
+          description="queue remove wait time (queue thread waits)"
+                 type="long"
+                 writeable="false"/>
+ 	<operation name="connect"
+               description="connect to other replication node"
+               impact="ACTION"
+               returnType="void">
+    </operation>
+	<operation name="disconnect"
+               description="disconnect to other replication node"
+               impact="ACTION"
+               returnType="void">
+    </operation>
+	<operation name="checkKeepAlive"
+               description="Check connection for close socket"
+               impact="ACTION"
+               returnType="boolean">
+    </operation>
+	<operation name="resetStatistics"
+               description="Reset all statistics"
+               impact="ACTION"
+               returnType="void">
+    </operation>
+				 
+  </mbean>
+
+  <mbean         name="PooledSocketSender"
+          description="Pooled Cluster Sender"
+               domain="Catalina"
+                group="IDataSender"
+                 type="org.apache.catalina.ha.tcp.PooledSocketSender">
+    <attribute   name="address"
+          description="sender ip address"
+                 type="java.net.InetAddress"
+                 writeable="false"/>
+    <attribute   name="port"
+          description="sender port"
+                 type="int"
+                 writeable="false" />
+    <attribute   name="suspect"
+          description="Socket is gone"
+                 type="boolean"/>
+    <attribute   name="ackTimeout"
+          description="acknowledge timeout"
+                 type="long"/>
+    <attribute   name="waitForAck"
+          description="Wait for ack after data send"
+			     is="true"
+                 type="boolean"
+                 writeable="false" />
+    <attribute   name="maxPoolSocketLimit"
+          description="Max parallel sockets"
+                 type="int"/>
+    <attribute   name="keepAliveTimeout"
+          description="active socket keep alive timeout"
+                 type="long"/>
+    <attribute   name="keepAliveMaxRequestCount"
+          description="max request over this socket"
+                 type="int"/>
+    <attribute   name="resend"
+          description="after send failure make a resend"
+			     is="true"
+                 type="boolean" />
+    <attribute   name="connected"
+                 is="true"
+          description="socket connected"
+                 type="boolean"
+                 writeable="false"/>
+    <attribute   name="avgMessageSize"
+                 writeable="false"
+          description="avg message size (totalbytes/nrOfRequests"
+                 type="long"/>
+    <attribute   name="nrOfRequests"
+          description="number of send messages to other members"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="totalBytes"
+          description="number of bytes transfered"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="connectCounter"
+          description="counts connects"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="disconnectCounter"
+          description="counts disconnects"
+                 type="long"
+                 writeable="false"/>
+	<operation name="connect"
+               description="start Queue to connect to ohter replication node"
+               impact="ACTION"
+               returnType="void">
+    </operation>
+	<operation name="disconnect"
+               description="stop Queue to other replication node"
+               impact="ACTION"
+               returnType="void">
+    </operation>
+	<operation name="resetStatistics"
+               description="Reset all statistics"
+               impact="ACTION"
+               returnType="void">
+    </operation>
+				 
+  </mbean>
+
+  <mbean         name="SocketSender"
+          description="Sync Cluster Sender"
+               domain="Catalina"
+                group="IDataSender"
+                 type="org.apache.catalina.ha.tcp.SocketSender">
+    <attribute   name="address"
+          description="sender ip address"
+                 type="java.net.InetAddress"
+                 writeable="false"/>
+    <attribute   name="port"
+          description="sender port"
+                 type="int"
+                 writeable="false" />
+    <attribute   name="suspect"
+          description="Socket is gone"
+                 type="boolean"/>
+    <attribute   name="ackTimeout"
+          description="acknowledge timeout"
+                 type="long"/>
+    <attribute   name="waitForAck"
+          description="Wait for ack after data send"
+			     is="true"
+                 type="boolean"
+                 writeable="false" />
+    <attribute   name="keepAliveTimeout"
+          description="active socket keep alive timeout"
+                 type="long"/>
+    <attribute   name="keepAliveMaxRequestCount"
+          description="max request over this socket"
+                 type="int"/>
+    <attribute   name="messageTransferStarted"
+          description="message is in transfer"
+                 type="boolean"
+                 is="true"
+                 writeable="false"/>
+    <attribute   name="keepAliveCount"
+          description="keep Alive request count"
+                 type="int"
+                 writeable="false"/>
+    <attribute   name="keepAliveConnectTime"
+          description="Connect time for keep alive"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="resend"
+          description="after send failure make a resend"
+			     is="true"
+                 type="boolean" />
+    <attribute   name="connected"
+                 is="true"
+          description="socket connected"
+                 type="boolean"
+                 writeable="false"/>
+    <attribute   name="avgMessageSize"
+                 writeable="false"
+          description="avg message size (totalbytes/nrOfRequests"
+                 type="long"/>
+    <attribute   name="nrOfRequests"
+          description="number of send messages to other members"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="totalBytes"
+          description="number of bytes transfered"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="processingTime"
+          description="sending processing time"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="minProcessingTime"
+          description="minimal sending processing time"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="avgProcessingTime"
+          description="processing time / nrOfRequests"
+                 type="double"
+                 writeable="false"/>
+    <attribute   name="maxProcessingTime"
+          description="maximal sending processing time"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="doProcessingStats"
+          description="create Processing time stats"
+			     is="true"
+                 type="boolean" />
+    <attribute   name="waitAckTime"
+          description="sending waitAck time"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="minWaitAckTime"
+          description="minimal sending waitAck time"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="avgWaitAckTime"
+          description="waitAck time / nrOfRequests"
+                 type="double"
+                 writeable="false"/>
+    <attribute   name="maxWaitAckTime"
+          description="maximal sending waitAck time"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="doWaitAckStats"
+          description="create waitAck time stats"
+			     is="true"
+                 type="boolean" />
+    <attribute   name="connectCounter"
+          description="counts connects"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="disconnectCounter"
+          description="counts disconnects"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="socketCloseCounter"
+          description="counts closed socket (KeepAlive and disconnects)"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="socketOpenFailureCounter"
+          description="counts open socket failures"
+                 type="long"
+                 writeable="false"/>                 				 
+    <attribute   name="socketOpenCounter"
+          description="counts open socket (KeepAlive and connects)"
+                 type="long"
+                 writeable="false"/>				 
+    <attribute   name="missingAckCounter"
+          description="counts missing ack"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="dataResendCounter"
+          description="counts data resends"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="dataFailureCounter"
+          description="counts data send failures"
+                 type="long"
+                 writeable="false"/>
+	<operation name="connect"
+               description="connect to other replication node"
+               impact="ACTION"
+               returnType="void">
+    </operation>
+	<operation name="disconnect"
+               description="disconnect to other replication node"
+               impact="ACTION"
+               returnType="void">
+    </operation>
+	<operation name="checkKeepAlive"
+               description="Check connection for close socket"
+               impact="ACTION"
+               returnType="boolean">
+    </operation>
+	<operation name="resetStatistics"
+               description="Reset all statistics"
+               impact="ACTION"
+               returnType="void">
+    </operation>
+				 
+  </mbean>
+    
+  <mbean         name="ReplicationValve"
+          description="Valve for simple tcp replication"
+               domain="Catalina"
+                group="Valve"
+                 type="org.apache.catalina.ha.tcp.ReplicationValve">
+    <attribute   name="info"
+          description="Class version info"
+                 type="java.lang.String"
+                 writeable="false"/>
+    <attribute   name="filter"
+          description="resource filter to disable session replication check"
+                 type="java.lang.String"/>
+    <attribute   name="primaryIndicator"
+ 			     is="true"
+          description="set indicator that request processing is at primary session node"
+                 type="boolean"/>
+    <attribute   name="primaryIndicatorName"
+          description="Request attribute name to indicate that request processing is at primary session node"
+                 type="java.lang.String"/>
+    <attribute   name="doProcessingStats"
+ 			     is="true"
+          description="active statistics counting"
+                 type="boolean"/>
+	<attribute   name="nrOfRequests"
+          description="number of replicated requests"
+                 type="long"
+                 writeable="false"/>
+	<attribute   name="nrOfFilterRequests"
+          description="number of filtered requests"
+                 type="long"
+                 writeable="false"/>
+	<attribute   name="nrOfSendRequests"
+          description="number of send requests"
+                 type="long"
+                 writeable="false"/>
+	<attribute   name="nrOfCrossContextSendRequests"
+          description="number of send cross context session requests"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="totalRequestTime"
+          description="total replicated request time"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="totalSendTime"
+          description="total replicated send time"
+                 type="long"
+                 writeable="false"/>
+    <attribute   name="lastSendTime"
+          description="last replicated request time"
+                 type="long"
+                 writeable="false"/>
+    <operation name="resetStatistics"
+               description="Reset all statistics"
+               impact="ACTION"
+               returnType="void">
+    </operation>
+                 
+  </mbean>
+
+
+</mbeans-descriptors>

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/util/IDynamicProperty.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/util/IDynamicProperty.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/ha/src/share/org/apache/catalina/ha/util/IDynamicProperty.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,57 @@
+/*
+ * Copyright 1999,2004-2005 The Apache Software Foundation.
+ * 
+ * Licensed 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.ha.util;
+
+import java.util.Iterator;
+
+/**
+ * @author Peter Rossbach
+ * @version $Revision: 304032 $, $Date: 2005-07-27 10:11:55 -0500 (Wed, 27 Jul 2005) $
+ */
+
+public interface IDynamicProperty {
+
+    /**
+     * set config attributes with reflect
+     * 
+     * @param name
+     * @param value
+     */
+    public void setProperty(String name, Object value) ;
+
+    /**
+     * get current config
+     * 
+     * @param key
+     * @return The property
+     */
+    public Object getProperty(String key) ;
+    /**
+     * Get all properties keys
+     * 
+     * @return An iterator over the property names
+     */
+    public Iterator getPropertyNames() ;
+
+    /**
+     * remove a configured property.
+     * 
+     * @param key
+     */
+    public void removeProperty(String key) ;
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/build.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/build.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/build.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,138 @@
+<project name="StoreConfig" default="dist" basedir=".">
+
+
+	<!-- ===================== Initialize Property Values =================== -->
+
+	<!-- See "build.properties.sample" in the top level directory for all     -->
+	<!-- property values you must customize for successful building!!!        -->
+    <property file="../../../build/build.properties" />
+    <property file="../../../build/build.properties.default" />
+
+    <!-- Build Defaults -->
+    <property name="catalina.home"  location="../.."/>
+    <property name="catalina.build" location="../../../build/build"/>
+    <property name="config.build" value="${catalina.home}/modules/storeconfig/build" />
+	<property name="config.dist" value="${catalina.home}/modules/storeconfig/dist" />
+
+	<!-- Construct Catalina classpath -->
+	<path id="config.classpath">
+		<pathelement location="${catalina.build}/server/lib/catalina.jar" />
+		<pathelement location="${catalina.build}/server/lib/tomcat-util.jar" />
+		<pathelement location="${commons-logging.jar}" />
+		<pathelement location="${commons-modeler.jar}" />
+		<pathelement location="${jmx.jar}" />
+		<pathelement location="${catalina.build}/common/lib/servlet-api.jar" />
+	</path>
+
+	<!-- Source path -->
+	<path id="javadoc.sourcepath">
+		<pathelement location="src/share" />
+	</path>
+
+
+	<!-- =================== BUILD: Set compile flags ======================= -->
+	<target name="flags">
+		<!-- JDK flags -->
+		<available property="jdk.1.2.present" classname="java.util.HashMap" />
+		<available property="jdk.1.3.present" classname="java.lang.reflect.Proxy" />
+		<available property="jdk.1.4.present" classname="java.nio.Buffer" />
+	</target>
+
+
+	<!-- =================== BUILD: Set compile flags ======================= -->
+	<target name="flags.display" depends="flags" unless="flags.hide">
+
+		<echo message="--- Build environment for Catalina ---" />
+
+		<echo message="If ${property_name} is displayed, then the property is not set)" />
+
+		<echo message="--- Build options ---" />
+		<echo message="full.dist=${full.dist}" />
+		<echo message="build.sysclasspath=${build.sysclasspath}" />
+		<echo message="compile.debug=${compile.debug}" />
+		<echo message="compile.deprecation=${compile.deprecation}" />
+		<echo message="compile.optimize=${compile.optimize}" />
+		<echo message="compile.source=${compile.source}" />
+
+		<echo message="--- Ant Flags ---" />
+		<echo message="&lt;style&gt; task available (required)=${style.available}" />
+
+		<echo message="--- JDK ---" />
+		<echo message="jdk.1.2.present=${jdk.1.2.present}" />
+		<echo message="jdk.1.3.present=${jdk.1.3.present}" />
+		<echo message="jdk.1.4.present=${jdk.1.4.present}" />
+
+	</target>
+
+	<!-- =================== BUILD: Create Directories ====================== -->
+	<target name="build-prepare">
+		<mkdir dir="${catalina.build}" />
+		<mkdir dir="${catalina.build}/classes" />
+		<mkdir dir="${config.dist}" />
+	</target>
+
+
+
+
+	<!-- ================ BUILD: Compile Catalina Components ================ -->
+
+	<target name="build-catalina-config" depends="build-prepare">
+		<!-- Compile internal server components -->
+		<javac srcdir="${basedir}/src/share" destdir="${catalina.build}/classes" deprecation="${compile.deprecation}" debug="${compile.debug}" source="${compile.source}" optimize="${compile.optimize}" excludes="**/CVS/**">
+			<classpath refid="config.classpath" />
+		</javac>
+		<copy todir="${catalina.build}/classes/org/apache/catalina/storeconfig">
+			<fileset dir="${basedir}/src/share/org/apache/catalina/storeconfig">
+				<include name="*.properties" />
+				<include name="*.xml" />
+			</fileset>
+		</copy>
+	</target>
+
+
+	<!-- ================ BUILD: Create Catalina Javadocs =================== -->
+	<target name="javadoc">
+		<delete dir="${config.build}/javadoc" />
+		<mkdir dir="${config.build}/javadoc" />
+		<javadoc packagenames="org.apache.catalina.storeconfig.*" classpathref="config.classpath" sourcepathref="javadoc.sourcepath" destdir="${config.build}/javadoc" author="true" version="true" windowtitle="Catalina Internal StoreConfig API Documentation" doctitle="Catalina StoreConfig API" bottom="Copyright &#169; 2000-2004 Apache Software Foundation.  All Rights Reserved." />
+	</target>
+
+
+	<!-- ======================= BUILD: Clean Directory ===================== -->
+	<target name="build-clean">
+		<delete dir="${config.build}" />
+		<delete dir="${config.dist}" />
+        <delete>
+            <fileset dir="${catalina.build}/classes">
+                <include name="org/apache/catalina/storeconfig/**/*" />
+            </fileset>
+        </delete>
+	</target>
+
+
+	<!-- ==================== BUILD: Rebuild Everything ===================== -->
+
+
+
+
+	<!-- ================ DIST: Create Distribution ========================= -->
+	<target name="dist" depends="build-catalina-config">
+
+		<jar destfile="${config.dist}/catalina-storeconfig.jar" basedir="${catalina.build}/classes">
+			<include name="org/apache/catalina/storeconfig/**" />
+			<exclude name="**/package.html" />
+            <exclude name="**/LocalStrings_*" />
+		</jar>
+	</target>
+
+    <target name="copy" depends="dist" >
+       <copy file="${config.dist}/catalina-storeconfig.jar" todir="${catalina.build}/server/lib" />
+   </target>
+
+	<!-- ======================== DIST: Clean Directory ===================== -->
+
+
+	<!-- ====================== Convenient Synonyms ========================= -->
+
+
+</project>

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/docs/Readme.txt
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/docs/Readme.txt	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/docs/Readme.txt	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,63 @@
+Status:
+
+Peter Roßbach
+29.11.2004
+	
+Feature
+=========================
+	Backup context.xml
+	Backup für server.xml
+	Cluster Handling
+	Store all 5.5.5 elements
+	Context workDir default Handling
+	WatchedResource Default Handling
+	Write your own Registry
+		System Property -Dcatalina.storeconfig=file:../xxx.xml
+		${catalina.base}/conf bzw ${catalina.home}/conf
+		Classpath org.apache.catalina.storeconfig
+	JMX StoreConfig MBean
+		Store context.xml and server.xmls
+	Store Format is changeable with StoreAppenders
+	Easy extendable 
+	Connector support
+		AJP
+		HTTP
+		HTTPS
+	Context.xml and server.xml with backup				
+		 
+Example
+=========================
+	
+	<Server ...>
+	      <Listener className="org.apache.catalina.storeconfig.StoreConfigLifecycleListener"/>
+          <Service ...
+		  </Service>
+    </Server>
+	
+	Usages with JMX Adaptor 
+		ObjectName : Catalina:type=StoreConfig
+		
+		important operations:
+			storeConfig			Store complete server
+			storeServer			Store Server with ObjectName"               
+			   parameter name="objectname"
+                 description="Objectname from Server"
+                 default="Catalina:type=Server"
+			   parameter name="backup"
+                 description="store Context with backup"
+               parameter name="externalAllowed"
+                 description="store all Context external that have a configFile"
+            storeContext 		Store Context from ObjectName 
+               parameter name="objectname"
+                 description="ObjectName from Context"
+                 example="Catalina:j2eeType=WebModule,name=//localhost/manager,J2EEApplication=none,J2EEServer=none
+			   parameter name="backup"
+                 description="store with Backup"
+               parameter name="externalAllowed"
+                 description="store all or store only internal server.xml context (configFile == null)"
+			
+Have fun
+Peter Rossbach
+
+
+	

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/src/share/org/apache/catalina/storeconfig/CatalinaClusterSF.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/src/share/org/apache/catalina/storeconfig/CatalinaClusterSF.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/src/share/org/apache/catalina/storeconfig/CatalinaClusterSF.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,96 @@
+/*
+ * Copyright 1999-2001,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.storeconfig;
+
+import java.io.PrintWriter;
+
+import org.apache.catalina.LifecycleListener;
+import org.apache.catalina.Valve;
+import org.apache.catalina.cluster.CatalinaCluster;
+import org.apache.catalina.cluster.ClusterDeployer;
+import org.apache.catalina.cluster.ClusterReceiver;
+import org.apache.catalina.cluster.ClusterSender;
+import org.apache.catalina.cluster.MembershipService;
+import org.apache.catalina.cluster.MessageListener;
+import org.apache.catalina.cluster.tcp.SimpleTcpCluster;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * Generate Cluster Element with Membership,Sender,Receiver,Deployer and
+ * ReplicationValve
+ * 
+ * @author Peter Rossbach
+ */
+public class CatalinaClusterSF extends StoreFactoryBase {
+
+    private static Log log = LogFactory.getLog(CatalinaClusterSF.class);
+
+    /**
+     * Store the specified Cluster childs.
+     * 
+     * @param aWriter
+     *            PrintWriter to which we are storing
+     * @param indent
+     *            Number of spaces to indent this element
+     * @param aCluster
+     *            Cluster whose properties are being stored
+     * 
+     * @exception Exception
+     *                if an exception occurs while storing
+     */
+    public void storeChilds(PrintWriter aWriter, int indent, Object aCluster,
+            StoreDescription parentDesc) throws Exception {
+        if (aCluster instanceof CatalinaCluster) {
+            CatalinaCluster cluster = (CatalinaCluster) aCluster;
+
+            // Store nested <Membership> element
+            MembershipService service = cluster.getMembershipService();
+            if (service != null) {
+                storeElement(aWriter, indent, service);
+            }
+            // Store nested <Sender> element
+            ClusterSender sender = cluster.getClusterSender();
+            if (sender != null) {
+                storeElement(aWriter, indent, sender);
+            }
+            // Store nested <Receiver> element
+            ClusterReceiver receiver = cluster.getClusterReceiver();
+            if (receiver != null) {
+                storeElement(aWriter, indent, receiver);
+            }
+            // Store nested <Deployer> element
+            ClusterDeployer deployer = cluster.getClusterDeployer();
+            if (deployer != null) {
+                storeElement(aWriter, indent, deployer);
+            }
+            // Store nested <Valve> element
+            // ClusterValve are not store at Hosts element, see
+            Valve valves[] = cluster.getValves();
+            storeElementArray(aWriter, indent, valves);
+ 
+            if (aCluster instanceof SimpleTcpCluster) {
+                // Store nested <Listener> elements
+                LifecycleListener listeners[] = ((SimpleTcpCluster)cluster).findLifecycleListeners();
+                storeElementArray(aWriter, indent, listeners);
+                // Store nested <ClusterListener> elements
+                MessageListener mlisteners[] = ((SimpleTcpCluster)cluster).findClusterListeners();
+                storeElementArray(aWriter, indent, mlisteners);
+            }            
+        }
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/src/share/org/apache/catalina/storeconfig/ConnectorSF.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/src/share/org/apache/catalina/storeconfig/ConnectorSF.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/src/share/org/apache/catalina/storeconfig/ConnectorSF.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,91 @@
+/**
+ * Copyright 1999-2001,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.storeconfig;
+
+import java.io.PrintWriter;
+
+import org.apache.catalina.Lifecycle;
+import org.apache.catalina.LifecycleListener;
+import org.apache.catalina.connector.Connector;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * Store Connector and Listeners
+ * 
+ * @author Peter Rossbach
+ */
+public class ConnectorSF extends StoreFactoryBase {
+
+    private static Log log = LogFactory.getLog(ConnectorSF.class);
+
+    /**
+     * Store Connector description
+     * 
+     * @param aWriter
+     * @param indent
+     * @param aConnector
+     * @throws Exception
+     */
+    public void storeChilds(PrintWriter aWriter, int indent, Object aConnector,
+            StoreDescription parentDesc) throws Exception {
+
+        if (aConnector instanceof Connector) {
+            Connector connector = (Connector) aConnector;
+            // Store nested <Listener> elements
+            if (connector instanceof Lifecycle) {
+                LifecycleListener listeners[] = ((Lifecycle) connector)
+                        .findLifecycleListeners();
+                storeElementArray(aWriter, indent, listeners);
+            }
+        }
+    }
+
+    protected void printOpenTag(PrintWriter aWriter, int indent, Object bean,
+            StoreDescription aDesc) throws Exception {
+        aWriter.print("<");
+        aWriter.print(aDesc.getTag());
+        storeConnectorAttribtues(aWriter, indent, bean, aDesc);
+        aWriter.println(">");
+    }
+
+    protected void storeConnectorAttribtues(PrintWriter aWriter, int indent,
+            Object bean, StoreDescription aDesc) throws Exception {
+        if (aDesc.isAttributes()) {
+            getStoreAppender().printAttributes(aWriter, indent, false, bean,
+                    aDesc);
+            /*
+             * if (bean instanceof Connector) { StoreDescription elementDesc =
+             * getRegistry().findDescription( bean.getClass().getName() +
+             * ".[ProtocolHandler]"); if (elementDesc != null) { ProtocolHandler
+             * protocolHandler = ((Connector) bean) .getProtocolHandler(); if
+             * (protocolHandler != null)
+             * getStoreAppender().printAttributes(aWriter, indent, false,
+             * protocolHandler, elementDesc); } }
+             */
+        }
+    }
+
+    protected void printTag(PrintWriter aWriter, int indent, Object bean,
+            StoreDescription aDesc) throws Exception {
+        aWriter.print("<");
+        aWriter.print(aDesc.getTag());
+        storeConnectorAttribtues(aWriter, indent, bean, aDesc);
+        aWriter.println("/>");
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/src/share/org/apache/catalina/storeconfig/ConnectorStoreAppender.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/src/share/org/apache/catalina/storeconfig/ConnectorStoreAppender.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/src/share/org/apache/catalina/storeconfig/ConnectorStoreAppender.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,281 @@
+/**
+ * Copyright 1999-2001,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.storeconfig;
+
+import java.beans.IndexedPropertyDescriptor;
+import java.beans.IntrospectionException;
+import java.beans.Introspector;
+import java.beans.PropertyDescriptor;
+import java.io.File;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.catalina.connector.Connector;
+import org.apache.coyote.ProtocolHandler;
+import org.apache.tomcat.util.IntrospectionUtils;
+
+/**
+ * Store the Connector attributes. Connector has really special design. A
+ * Connector is only a startup Wrapper for a ProtocolHandler. This meant that
+ * ProtocolHandler get all there attribtues from the Connector attribtue map.
+ * Strange is that some attributes change there name and the attribute
+ * sslProtocol need a sepzial handling
+ * 
+ * @author Peter Rossbach
+ *  
+ */
+public class ConnectorStoreAppender extends StoreAppender {
+
+    protected static HashMap replacements = new HashMap();
+    static {
+        replacements.put("backlog", "acceptCount");
+        replacements.put("soLinger", "connectionLinger");
+        replacements.put("soTimeout", "connectionTimeout");
+        replacements.put("timeout", "connectionUploadTimeout");
+        replacements.put("clientauth", "clientAuth");
+        replacements.put("keystore", "keystoreFile");
+        replacements.put("randomfile", "randomFile");
+        replacements.put("rootfile", "rootFile");
+        replacements.put("keypass", "keystorePass");
+        replacements.put("keytype", "keystoreType");
+        replacements.put("protocol", "sslProtocol");
+        replacements.put("protocols", "sslProtocols");
+    }
+
+    /**
+     * Store the relevant attributes of the specified JavaBean.
+     * 
+     * @param writer
+     *            PrintWriter to which we are storing
+     * @param include
+     *            Should we include a <code>className</code> attribute?
+     * @param bean
+     *            Bean whose properties are to be rendered as attributes,
+     * @param desc
+     *            RegistryDescrpitor from this bean
+     * 
+     * @exception Exception
+     *                if an exception occurs while storing
+     */
+    public void printAttributes(PrintWriter writer, int indent,
+            boolean include, Object bean, StoreDescription desc)
+            throws Exception {
+
+        // Render the relevant properties of this bean
+        String className = bean.getClass().getName();
+
+        // Render a className attribute if requested
+        if (include && desc != null && !desc.isStandard()) {
+            writer.print(" className=\"");
+            writer.print(bean.getClass().getName());
+            writer.print("\"");
+        }
+
+        List propertyKeys = getPropertyKeys((Connector) bean);
+        // Create blank instance
+        Object bean2 = defaultInstance(bean);
+        for (Iterator propertyIterator = propertyKeys.iterator(); propertyIterator
+                .hasNext();) {
+            String key = (String) propertyIterator.next();
+            if (replacements.get(key) != null) {
+                key = (String) replacements.get(key);
+            }
+            Object value = (Object) IntrospectionUtils.getProperty(bean, key);
+
+            if (desc.isTransientAttribute(key)) {
+                continue; // Skip the specified exceptions
+            }
+            if (value == null) {
+                continue; // Null values are not persisted
+            }
+            if (!isPersistable(value.getClass())) {
+                continue;
+            }
+            Object value2 = IntrospectionUtils.getProperty(bean2, key);
+            if (value.equals(value2)) {
+                // The property has its default value
+                continue;
+            }
+            if (isPrintValue(bean, bean2, key, desc))
+                printValue(writer, indent, key, value);
+        }
+        String protocol = ((Connector) bean).getProtocol();
+        if (protocol != null && !"HTTP/1.1".equals(protocol))
+            super.printValue(writer, indent, "protocol", protocol);
+
+    }
+
+    /**
+     * Get all properties from Connector and current ProtocolHandler
+     * 
+     * @param bean
+     * @return List of Connector Properties
+     * @throws IntrospectionException
+     */
+    protected List getPropertyKeys(Connector bean)
+            throws IntrospectionException {
+        ArrayList propertyKeys = new ArrayList();
+        // Acquire the list of properties for this bean
+        ProtocolHandler protocolHandler = bean.getProtocolHandler();
+        // Acquire the list of properties for this bean
+        PropertyDescriptor descriptors[] = Introspector.getBeanInfo(
+                bean.getClass()).getPropertyDescriptors();
+        if (descriptors == null) {
+            descriptors = new PropertyDescriptor[0];
+        }
+        for (int i = 0; i < descriptors.length; i++) {
+            if (descriptors[i] instanceof IndexedPropertyDescriptor) {
+                continue; // Indexed properties are not persisted
+            }
+            if (!isPersistable(descriptors[i].getPropertyType())
+                    || (descriptors[i].getReadMethod() == null)
+                    || (descriptors[i].getWriteMethod() == null)) {
+                continue; // Must be a read-write primitive or String
+            }
+            if ("protocol".equals(descriptors[i].getName())
+                    || "protocolHandlerClassName".equals(descriptors[i]
+                            .getName()))
+                continue;
+            propertyKeys.add(descriptors[i].getName());
+        }
+        for (Iterator propertyIterator = protocolHandler.getAttributeNames(); propertyIterator
+                .hasNext();) {
+            Object key = propertyIterator.next();
+            if (propertyKeys.contains(key))
+                continue;
+            propertyKeys.add(key);
+        }
+        return propertyKeys;
+    }
+
+    /**
+     * print Attributes
+     * 
+     * @param aWriter
+     * @param indent
+     * @param bean
+     * @param aDesc
+     * @throws Exception
+     */
+    protected void storeConnectorAttribtues(PrintWriter aWriter, int indent,
+            Object bean, StoreDescription aDesc) throws Exception {
+        if (aDesc.isAttributes()) {
+            printAttributes(aWriter, indent, false, bean, aDesc);
+        }
+    }
+
+    /*
+     * Print the open tag for connector attributes (override)
+     * 
+     * @see org.apache.catalina.storeconfig.StoreAppender#printOpenTag(java.io.PrintWriter,
+     *      int, java.lang.Object,
+     *      org.apache.catalina.storeconfig.StoreDescription)
+     */
+    public void printOpenTag(PrintWriter aWriter, int indent, Object bean,
+            StoreDescription aDesc) throws Exception {
+        aWriter.print("<");
+        aWriter.print(aDesc.getTag());
+        storeConnectorAttribtues(aWriter, indent, bean, aDesc);
+        aWriter.println(">");
+    }
+
+    /**
+     * print a tag for connector attributes (override)
+     * 
+     * @see org.apache.catalina.storeconfig.StoreAppender#printTag(java.io.PrintWriter,
+     *      int, java.lang.Object,
+     *      org.apache.catalina.storeconfig.StoreDescription)
+     */
+    public void printTag(PrintWriter aWriter, int indent, Object bean,
+            StoreDescription aDesc) throws Exception {
+        aWriter.print("<");
+        aWriter.print(aDesc.getTag());
+        storeConnectorAttribtues(aWriter, indent, bean, aDesc);
+        aWriter.println("/>");
+    }
+
+    /**
+     * print a value but replace attribute name
+     * 
+     * @param writer
+     * @param name
+     * @param value
+     * @see org.apache.catalina.storeconfig.StoreAppender#printValue(java.io.PrintWriter,
+     *      int, java.lang.String, java.lang.Object)
+     */
+    public void printValue(PrintWriter writer, int indent, String name,
+            Object value) {
+        String repl = name;
+        if (replacements.get(name) != null) {
+            repl = (String) replacements.get(name);
+        }
+        super.printValue(writer, indent, repl, value);
+    }
+    
+    /*
+     * Print Connector Values. <ul><li> Spezial handling to default jkHome.
+     * </li><li> Don't save catalina.base path at server.xml</li><li></ul>
+     * 
+     * @see org.apache.catalina.config.StoreAppender#isPrintValue(java.lang.Object,
+     *      java.lang.Object, java.lang.String,
+     *      org.apache.catalina.config.StoreDescription)
+     */
+    public boolean isPrintValue(Object bean, Object bean2, String attrName,
+            StoreDescription desc) {
+        boolean isPrint = super.isPrintValue(bean, bean2, attrName, desc);
+        if (isPrint) {
+            if ("jkHome".equals(attrName)) {
+                Connector connector = ((Connector) bean);
+                File catalinaBase = getCatalinaBase();
+                File jkHomeBase = getJkHomeBase((String) connector
+                        .getProperty("jkHome"), catalinaBase);
+                isPrint = !catalinaBase.equals(jkHomeBase);
+
+            }
+        }
+        return isPrint;
+    }
+
+    protected File getCatalinaBase() {
+
+        File appBase;
+        File file = new File(System.getProperty("catalina.base"));
+        try {
+            file = file.getCanonicalFile();
+        } catch (IOException e) {
+        }
+        return (file);
+    }
+
+    protected File getJkHomeBase(String jkHome, File appBase) {
+
+        File jkHomeBase;
+        File file = new File(jkHome);
+        if (!file.isAbsolute())
+            file = new File(appBase, jkHome);
+        try {
+            jkHomeBase = file.getCanonicalFile();
+        } catch (IOException e) {
+            jkHomeBase = file;
+        }
+        return (jkHomeBase);
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/src/share/org/apache/catalina/storeconfig/Constants.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/src/share/org/apache/catalina/storeconfig/Constants.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/src/share/org/apache/catalina/storeconfig/Constants.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,27 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.storeconfig;
+
+/**
+ * @author Peter Rossbach
+ *  
+ */
+public class Constants {
+
+    public static final String Package = "org.apache.catalina.storeconfig";
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/src/share/org/apache/catalina/storeconfig/GlobalNamingResourcesSF.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/src/share/org/apache/catalina/storeconfig/GlobalNamingResourcesSF.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/src/share/org/apache/catalina/storeconfig/GlobalNamingResourcesSF.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,77 @@
+/*
+ * Copyright 1999-2001,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.storeconfig;
+
+import java.io.PrintWriter;
+
+import org.apache.catalina.deploy.NamingResources;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * store server.xml GlobalNamingResource.
+ * 
+ * @author Peter Rossbach 
+ *  
+ */
+public class GlobalNamingResourcesSF extends StoreFactoryBase {
+    private static Log log = LogFactory.getLog(GlobalNamingResourcesSF.class);
+
+    /*
+     * Store with NamingResource Factory
+     * 
+     * @see org.apache.catalina.storeconfig.IStoreFactory#store(java.io.PrintWriter,
+     *      int, java.lang.Object)
+     */
+    public void store(PrintWriter aWriter, int indent, Object aElement)
+            throws Exception {
+
+        if (aElement instanceof NamingResources) {
+
+            StoreDescription elementDesc = getRegistry().findDescription(
+                    NamingResources.class.getName()
+                            + ".[GlobalNamingResources]");
+
+            if (elementDesc != null) {
+                getStoreAppender().printIndent(aWriter, indent + 2);
+                getStoreAppender().printOpenTag(aWriter, indent + 2, aElement,
+                        elementDesc);
+                NamingResources resources = (NamingResources) aElement;
+                StoreDescription resourcesdesc = getRegistry().findDescription(
+                        NamingResources.class.getName());
+                if (resourcesdesc != null) {
+                    resourcesdesc.getStoreFactory().store(aWriter, indent + 2,
+                            resources);
+                } else {
+                    if(log.isWarnEnabled())
+                        log.warn("Can't find NamingRsources Store Factory!");
+                }
+                    
+                getStoreAppender().printIndent(aWriter, indent + 2);
+                getStoreAppender().printCloseTag(aWriter, elementDesc);
+            } else {
+                if (log.isWarnEnabled())
+                    log.warn("Descriptor for element" + aElement.getClass()
+                            + " not configured!");
+            }
+        } else {
+            if (log.isWarnEnabled())
+                log.warn("wrong element " + aElement.getClass());
+
+        }
+    }
+}
+

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/src/share/org/apache/catalina/storeconfig/IDynamicPropertyStoreAppender.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/src/share/org/apache/catalina/storeconfig/IDynamicPropertyStoreAppender.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/src/share/org/apache/catalina/storeconfig/IDynamicPropertyStoreAppender.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,136 @@
+/**
+ * Copyright 1999-2001,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.storeconfig;
+
+import java.beans.IndexedPropertyDescriptor;
+import java.beans.IntrospectionException;
+import java.beans.Introspector;
+import java.beans.PropertyDescriptor;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.catalina.cluster.util.IDynamicProperty;
+import org.apache.tomcat.util.IntrospectionUtils;
+
+/**
+ * Store the IDynamicProperty attributes. 
+ * 
+ * @author Peter Rossbach
+ *  
+ */
+public class IDynamicPropertyStoreAppender extends StoreAppender {
+
+    /**
+     * Store the relevant attributes of the specified JavaBean.
+     * 
+     * @param writer
+     *            PrintWriter to which we are storing
+     * @param include
+     *            Should we include a <code>className</code> attribute?
+     * @param bean
+     *            Bean whose properties are to be rendered as attributes,
+     * @param desc
+     *            RegistryDescrpitor from this bean
+     * 
+     * @exception Exception
+     *                if an exception occurs while storing
+     */
+    public void printAttributes(PrintWriter writer, int indent,
+            boolean include, Object bean, StoreDescription desc)
+            throws Exception {
+
+        // Render the relevant properties of this bean
+        String className = bean.getClass().getName();
+
+        // Render a className attribute if requested
+        if (include && desc != null && !desc.isStandard()) {
+            writer.print(" className=\"");
+            writer.print(bean.getClass().getName());
+            writer.print("\"");
+        }
+
+        if (bean instanceof IDynamicProperty) {
+            List propertyKeys = getPropertyKeys((IDynamicProperty) bean);
+            // Create blank instance
+            Object bean2 = defaultInstance(bean);
+            for (Iterator propertyIterator = propertyKeys.iterator(); propertyIterator
+                    .hasNext();) {
+                String key = (String) propertyIterator.next();
+                Object value = (Object) IntrospectionUtils.getProperty(bean,
+                        key);
+
+                if (desc.isTransientAttribute(key)) {
+                    continue; // Skip the specified exceptions
+                }
+                if (value == null) {
+                    continue; // Null values are not persisted
+                }
+                if (!isPersistable(value.getClass())) {
+                    continue;
+                }
+                Object value2 = IntrospectionUtils.getProperty(bean2, key);
+                if (value.equals(value2)) {
+                    // The property has its default value
+                    continue;
+                }
+                if (isPrintValue(bean, bean2, key, desc))
+                    printValue(writer, indent, key, value);
+            }
+        }
+    }
+
+    /**
+     * Get all properties from ReplicationTransmitter (also dynamic properties)
+     * 
+     * @param bean
+     * @return List of Connector Properties
+     * @throws IntrospectionException
+     */
+    protected List getPropertyKeys(IDynamicProperty bean)
+            throws IntrospectionException {
+        ArrayList propertyKeys = new ArrayList();
+        // Acquire the list of properties for this bean
+        PropertyDescriptor descriptors[] = Introspector.getBeanInfo(
+                bean.getClass()).getPropertyDescriptors();
+        if (descriptors == null) {
+            descriptors = new PropertyDescriptor[0];
+        }
+        for (int i = 0; i < descriptors.length; i++) {
+            if (descriptors[i] instanceof IndexedPropertyDescriptor) {
+                continue; // Indexed properties are not persisted
+            }
+            if (!isPersistable(descriptors[i].getPropertyType())
+                    || (descriptors[i].getReadMethod() == null)
+                    || (descriptors[i].getWriteMethod() == null)) {
+                continue; // Must be a read-write primitive or String
+            }
+            propertyKeys.add(descriptors[i].getName());
+        }
+        for (Iterator propertyIterator = bean.getPropertyNames(); propertyIterator
+                .hasNext();) {
+            Object key = propertyIterator.next();
+            if (propertyKeys.contains(key))
+                continue;
+            if ("className".equals(key))
+                continue;
+            propertyKeys.add(key);
+        }
+        return propertyKeys;
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/src/share/org/apache/catalina/storeconfig/IStoreConfig.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/src/share/org/apache/catalina/storeconfig/IStoreConfig.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/src/share/org/apache/catalina/storeconfig/IStoreConfig.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,136 @@
+/*
+ * Copyright 1999-2001,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.storeconfig;
+
+import java.io.PrintWriter;
+
+import org.apache.catalina.Context;
+import org.apache.catalina.Host;
+import org.apache.catalina.Server;
+import org.apache.catalina.Service;
+
+/**
+ * @author Peter Rossbach 
+ *  
+ */
+public interface IStoreConfig {
+
+    /**
+     * Get Configuration Registry
+     * 
+     * @return aRegistry that handle the store operations
+     */
+    StoreRegistry getRegistry();
+
+    /**
+     * Set Configuration Registry
+     * 
+     * @param aRegistry
+     *            aregistry that handle the store operations
+     */
+    void setRegistry(StoreRegistry aRegistry);
+
+    /**
+     * Store the current StoreFactory Server.
+     * 
+     * @exception Exception
+     *                if an exception occurs while storing
+     */
+    void storeConfig() throws Exception;
+
+    /**
+     * Store the specified Server properties.
+     * 
+     * @param aServer
+     *            Object to be stored
+     * 
+     * @exception Exception
+     *                if an exception occurs while storing
+     */
+    void store(Server aServer) throws Exception;
+
+    /**
+     * Store the specified Server properties.
+     * 
+     * @param aWriter
+     *            PrintWriter to which we are storing
+     * @param indent
+     *            Number of spaces to indent this element
+     * @param aServer
+     *            Object to be stored
+     * 
+     * @exception Exception
+     *                if an exception occurs while storing
+     */
+    void store(PrintWriter aWriter, int indent, Server aServer);
+
+    /**
+     * Store the specified Service properties.
+     * 
+     * @param aWriter
+     *            PrintWriter to which we are storing
+     * @param indent
+     *            Number of spaces to indent this element
+     * @param aService
+     *            Object to be stored
+     * 
+     * @exception Exception
+     *                if an exception occurs while storing
+     */
+    void store(PrintWriter aWriter, int indent, Service aService);
+
+    /**
+     * Store the specified Host properties.
+     * 
+     * @param aWriter
+     *            PrintWriter to which we are storing
+     * @param indent
+     *            Number of spaces to indent this element
+     * @param aHost
+     *            Object to be stored
+     * 
+     * @exception Exception
+     *                if an exception occurs while storing
+     */
+    void store(PrintWriter aWriter, int indent, Host aHost);
+
+    /**
+     * Store the specified Context properties.
+     * 
+     * @param aContext
+     *            Object to be stored
+     * 
+     * @exception Exception
+     *                if an exception occurs while storing
+     */
+    void store(Context aContext);
+
+    /**
+     * Store the specified Context properties.
+     * 
+     * @param aWriter
+     *            PrintWriter to which we are storing
+     * @param indent
+     *            Number of spaces to indent this element
+     * @param aContext
+     *            Object to be stored
+     * 
+     * @exception Exception
+     *                if an exception occurs while storing
+     */
+    void store(PrintWriter aWriter, int indent, Context aContext);
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/src/share/org/apache/catalina/storeconfig/IStoreFactory.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/src/share/org/apache/catalina/storeconfig/IStoreFactory.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/src/share/org/apache/catalina/storeconfig/IStoreFactory.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,37 @@
+/*
+ * Copyright 1999-2001,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.storeconfig;
+
+import java.io.PrintWriter;
+
+/**
+ * @author Peter Rossbach 
+ *  
+ */
+public interface IStoreFactory {
+    StoreAppender getStoreAppender();
+
+    void setStoreAppender(StoreAppender storeWriter);
+
+    void setRegistry(StoreRegistry aRegistry);
+
+    StoreRegistry getRegistry();
+
+    void store(PrintWriter aWriter, int indent, Object aElement)
+            throws Exception;
+
+    void storeXMLHead(PrintWriter aWriter);
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/src/share/org/apache/catalina/storeconfig/InstanceListenerSF.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/src/share/org/apache/catalina/storeconfig/InstanceListenerSF.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/src/share/org/apache/catalina/storeconfig/InstanceListenerSF.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,60 @@
+/*
+ * Copyright 1999-2001,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.storeconfig;
+
+import java.io.PrintWriter;
+
+import org.apache.catalina.core.StandardContext;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * Store Context InstanceListener
+ * 
+ * @author Peter Rossbach 
+ *  
+ */
+public class InstanceListenerSF extends StoreFactoryBase {
+    private static Log log = LogFactory.getLog(InstanceListenerSF.class);
+
+    /*
+     * Store nested Element Value Arrays
+     * 
+     * @see org.apache.catalina.config.IStoreFactory#store(java.io.PrintWriter,
+     *      int, java.lang.Object)
+     */
+    public void store(PrintWriter aWriter, int indent, Object aElement)
+            throws Exception {
+        if (aElement instanceof StandardContext) {
+            StoreDescription elementDesc = getRegistry().findDescription(
+                    aElement.getClass().getName() + ".[InstanceListener]");
+            String[] listeners = ((StandardContext) aElement)
+                    .findInstanceListeners();
+            if (elementDesc != null) {
+                if (log.isDebugEnabled())
+                    log.debug("store " + elementDesc.getTag() + "( " + aElement
+                            + " )");
+                getStoreAppender().printTagArray(aWriter, "InstanceListener",
+                        indent, listeners);
+            }
+        } else {
+            if (log.isWarnEnabled())
+                log.warn("Descriptor for element" + aElement.getClass()
+                        + ".[InstanceListener] not configured!");
+        }
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/src/share/org/apache/catalina/storeconfig/LoaderSF.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/src/share/org/apache/catalina/storeconfig/LoaderSF.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/src/share/org/apache/catalina/storeconfig/LoaderSF.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2004-2005 The Apache Software Foundation.
+ * 
+ * Licensed 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.storeconfig;
+
+import java.io.PrintWriter;
+
+import org.apache.catalina.Loader;
+import org.apache.catalina.loader.WebappLoader;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * Store Loader Element.
+ * 
+ * @author Peter Rossbach
+ */
+public class LoaderSF extends StoreFactoryBase {
+
+    private static Log log = LogFactory.getLog(LoaderSF.class);
+
+    /**
+     * Store the only the Loader elements, when not default
+     * 
+     * @see NamingResourcesSF#storeChilds(PrintWriter, int, Object, StoreDescription)
+     */
+    public void store(PrintWriter aWriter, int indent, Object aElement)
+            throws Exception {
+        StoreDescription elementDesc = getRegistry().findDescription(
+                aElement.getClass());
+        if (elementDesc != null) {
+            Loader loader = (Loader) aElement;
+            if (!isDefaultLoader(loader)) {
+                if (log.isDebugEnabled())
+                    log.debug("store " + elementDesc.getTag() + "( " + aElement
+                            + " )");
+                getStoreAppender().printIndent(aWriter, indent + 2);
+                getStoreAppender().printTag(aWriter, indent + 2, loader,
+                        elementDesc);
+            }
+        } else {
+            if (log.isWarnEnabled()) {
+                log
+                        .warn("Descriptor for element"
+                                + aElement.getClass()
+                                + " not configured or element class not StandardManager!");
+            }
+        }
+    }
+
+    /**
+     * Is this an instance of the default <code>Loader</code> configuration,
+     * with all-default properties?
+     * 
+     * @param loader
+     *            Loader to be tested
+     */
+    protected boolean isDefaultLoader(Loader loader) {
+
+        if (!(loader instanceof WebappLoader)) {
+            return (false);
+        }
+        WebappLoader wloader = (WebappLoader) loader;
+        if ((wloader.getDelegate() != false)
+                || !wloader.getLoaderClass().equals(
+                        "org.apache.catalina.loader.WebappClassLoader")) {
+            return (false);
+        }
+        return (true);
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/src/share/org/apache/catalina/storeconfig/LocalStrings.properties
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/src/share/org/apache/catalina/storeconfig/LocalStrings.properties	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/src/share/org/apache/catalina/storeconfig/LocalStrings.properties	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,2 @@
+factory.storeTag=store tag {0} ( Object: {1} )
+factory.storeNoDescriptor=Descriptor for element class {0} not configured!

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/src/share/org/apache/catalina/storeconfig/ManagerSF.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/src/share/org/apache/catalina/storeconfig/ManagerSF.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/src/share/org/apache/catalina/storeconfig/ManagerSF.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2004-2005 The Apache Software Foundation.
+ * 
+ * Licensed 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.storeconfig;
+
+import java.io.PrintWriter;
+
+import org.apache.catalina.session.StandardManager;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * Store server.xml Manager element
+ * 
+ * @author Peter Rossbach
+ */
+public class ManagerSF extends StoreFactoryBase {
+
+    private static Log log = LogFactory.getLog(ManagerSF.class);
+
+    /**
+     * Store the only the Manager elements
+     * 
+     * @see NamingResourcesSF#storeChilds(PrintWriter, int, Object, StoreDescription)
+     */
+    public void store(PrintWriter aWriter, int indent, Object aElement)
+            throws Exception {
+        StoreDescription elementDesc = getRegistry().findDescription(
+                aElement.getClass());
+        if (elementDesc != null && aElement instanceof StandardManager) {
+            StandardManager manager = (StandardManager) aElement;
+            if (!isDefaultManager(manager)) {
+                if (log.isDebugEnabled())
+                    log.debug(sm.getString("factory.storeTag", elementDesc
+                            .getTag(), aElement));
+                getStoreAppender().printIndent(aWriter, indent + 2);
+                getStoreAppender().printTag(aWriter, indent + 2, manager,
+                        elementDesc);
+            }
+        } else {
+            if (log.isWarnEnabled())
+                log.warn(sm.getString("factory.storeNoDescriptor", aElement
+                        .getClass()));
+        }
+    }
+
+    /**
+     * Is this an instance of the default <code>Manager</code> configuration,
+     * with all-default properties?
+     * 
+     * @param smanager
+     *            Manager to be tested
+     */
+    protected boolean isDefaultManager(StandardManager smanager) {
+
+        if (!"SESSIONS.ser".equals(smanager.getPathname())
+                || !"java.security.SecureRandom".equals(smanager
+                        .getRandomClass())
+                || (smanager.getMaxActiveSessions() != -1)
+                || !"MD5".equals(smanager.getAlgorithm())) {
+            return (false);
+        }
+        return (true);
+
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/src/share/org/apache/catalina/storeconfig/NamingResourcesSF.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/src/share/org/apache/catalina/storeconfig/NamingResourcesSF.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/src/share/org/apache/catalina/storeconfig/NamingResourcesSF.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,107 @@
+/*
+ * Copyright 2004-2005 The Apache Software Foundation.
+ * 
+ * Licensed 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.storeconfig;
+
+import java.io.PrintWriter;
+
+import org.apache.catalina.deploy.ContextEjb;
+import org.apache.catalina.deploy.ContextEnvironment;
+import org.apache.catalina.deploy.ContextLocalEjb;
+import org.apache.catalina.deploy.ContextResource;
+import org.apache.catalina.deploy.ContextResourceEnvRef;
+import org.apache.catalina.deploy.ContextResourceLink;
+import org.apache.catalina.deploy.NamingResources;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * Store server.xml elements Resources at context and GlobalNamingResources
+ * 
+ * @author Peter Rossbach
+ *  
+ */
+public class NamingResourcesSF extends StoreFactoryBase {
+    private static Log log = LogFactory.getLog(NamingResourcesSF.class);
+
+    /**
+     * Store the only the NamingResources elements
+     * 
+     * @see NamingResourcesSF#storeChilds(PrintWriter, int, Object, StoreDescription)
+     */
+    public void store(PrintWriter aWriter, int indent, Object aElement)
+            throws Exception {
+        StoreDescription elementDesc = getRegistry().findDescription(
+                aElement.getClass());
+        if (elementDesc != null) {
+            if (log.isDebugEnabled())
+                log.debug("store " + elementDesc.getTag() + "( " + aElement
+                        + " )");
+            storeChilds(aWriter, indent, aElement, elementDesc);
+        } else {
+            if (log.isWarnEnabled())
+                log.warn("Descriptor for element" + aElement.getClass()
+                        + " not configured!");
+        }
+    }
+
+    /**
+     * Store the specified NamingResources properties.
+     * 
+     * @param aWriter
+     *            PrintWriter to which we are storing
+     * @param indent
+     *            Number of spaces to indent this element
+     * @param aElement
+     *            Object whose properties are being stored
+     * @param elementDesc
+     *            element descriptor
+     * 
+     * @exception Exception
+     *                if an exception occurs while storing
+     * 
+     * @see org.apache.catalina.storeconfig.StoreFactoryBase#storeChilds(java.io.PrintWriter,
+     *      int, java.lang.Object, StoreDescription)
+     */
+    public void storeChilds(PrintWriter aWriter, int indent, Object aElement,
+            StoreDescription elementDesc) throws Exception {
+
+        if (aElement instanceof NamingResources) {
+            NamingResources resources = (NamingResources) aElement;
+            // Store nested <Ejb> elements
+            ContextEjb[] ejbs = resources.findEjbs();
+            storeElementArray(aWriter, indent, ejbs);
+            // Store nested <Environment> elements
+            ContextEnvironment[] envs = resources.findEnvironments();
+            storeElementArray(aWriter, indent, envs);
+            // Store nested <LocalEjb> elements
+            ContextLocalEjb[] lejbs = resources.findLocalEjbs();
+            storeElementArray(aWriter, indent, lejbs);
+
+            // Store nested <Resource> elements
+            ContextResource[] dresources = resources.findResources();
+            storeElementArray(aWriter, indent, dresources);
+
+            // Store nested <ResourceEnvRef> elements
+            ContextResourceEnvRef[] resEnv = resources.findResourceEnvRefs();
+            storeElementArray(aWriter, indent, resEnv);
+
+            // Store nested <ResourceLink> elements
+            ContextResourceLink[] resourceLinks = resources.findResourceLinks();
+            storeElementArray(aWriter, indent, resourceLinks);
+        }
+    }
+}
+

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/src/share/org/apache/catalina/storeconfig/PersistentManagerSF.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/src/share/org/apache/catalina/storeconfig/PersistentManagerSF.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/src/share/org/apache/catalina/storeconfig/PersistentManagerSF.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,60 @@
+/*
+ * Copyright 1999-2001,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.storeconfig;
+
+import java.io.PrintWriter;
+
+import org.apache.catalina.Store;
+import org.apache.catalina.session.PersistentManager;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * store server.xml PersistentManager element with nested "Store"
+ * 
+ * @author Peter Rossbach
+ */
+public class PersistentManagerSF extends StoreFactoryBase {
+
+    private static Log log = LogFactory.getLog(PersistentManagerSF.class);
+
+    /**
+     * Store the specified PersistentManager properties.
+     * 
+     * @param aWriter
+     *            PrintWriter to which we are storing
+     * @param indent
+     *            Number of spaces to indent this element
+     * @param aManager
+     *            PersistentManager whose properties are being stored
+     * 
+     * @exception Exception
+     *                if an exception occurs while storing
+     */
+    public void storeChilds(PrintWriter aWriter, int indent, Object aManager,
+            StoreDescription parentDesc) throws Exception {
+        if (aManager instanceof PersistentManager) {
+            PersistentManager manager = (PersistentManager) aManager;
+
+            // Store nested <Manager> elements
+            Store store = manager.getStore();
+            storeElement(aWriter, indent, store);
+
+        }
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/src/share/org/apache/catalina/storeconfig/StandardContextSF.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/src/share/org/apache/catalina/storeconfig/StandardContextSF.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/src/share/org/apache/catalina/storeconfig/StandardContextSF.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,374 @@
+/*
+ * Copyright 2004-2006 The Apache Software Foundation.
+ * 
+ * Licensed 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.storeconfig;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.naming.directory.DirContext;
+
+import org.apache.catalina.Container;
+import org.apache.catalina.Context;
+import org.apache.catalina.Engine;
+import org.apache.catalina.Host;
+import org.apache.catalina.Lifecycle;
+import org.apache.catalina.LifecycleListener;
+import org.apache.catalina.Loader;
+import org.apache.catalina.Manager;
+import org.apache.catalina.Pipeline;
+import org.apache.catalina.Realm;
+import org.apache.catalina.Valve;
+import org.apache.catalina.core.StandardContext;
+import org.apache.catalina.deploy.ApplicationParameter;
+import org.apache.catalina.deploy.NamingResources;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.naming.resources.ProxyDirContext;
+
+/**
+ * Store server.xml Context element with all childs
+ * <ul>
+ * <li>Store all context at server.xml</li>
+ * <li>Store existing app.xml context a conf/enginename/hostname/app.xml</li>
+ * <li>Store with backup</li>
+ * </ul>
+ * 
+ * @author Peter Rossbach
+ */
+public class StandardContextSF extends StoreFactoryBase {
+
+    private static Log log = LogFactory.getLog(StandardContextSF.class);
+
+    /*
+     * Store a Context as Separate file as configFile value from context exists.
+     * filename can be relative to catalina.base.
+     * 
+     * @see org.apache.catalina.config.IStoreFactory#store(java.io.PrintWriter,
+     *      int, java.lang.Object)
+     */
+    public void store(PrintWriter aWriter, int indent, Object aContext)
+            throws Exception {
+
+        if (aContext instanceof StandardContext) {
+            StoreDescription desc = getRegistry().findDescription(
+                    aContext.getClass());
+            if (desc.isStoreSeparate()) {
+                String configFile = ((StandardContext) aContext)
+                        .getConfigFile();
+                if (configFile != null) {
+                    if (desc.isExternalAllowed()) {
+                        if (desc.isBackup())
+                            storeWithBackup((StandardContext) aContext);
+                        else
+                            storeContextSeparate(aWriter, indent,
+                                    (StandardContext) aContext);
+                        return;
+                    }
+                }
+            }
+        }
+        super.store(aWriter, indent, aContext);
+
+    }
+
+    /**
+     * Store a Context without backup add separate file or when configFile =
+     * null a aWriter.
+     * 
+     * @param aWriter
+     * @param indent
+     * @param aContext
+     * @throws Exception
+     */
+    protected void storeContextSeparate(PrintWriter aWriter, int indent,
+            StandardContext aContext) throws Exception {
+        String configFile = aContext.getConfigFile();
+        PrintWriter writer = null;
+        if (configFile != null) {
+            File config = new File(configFile);
+            if (!config.isAbsolute()) {
+                config = new File(System.getProperty("catalina.base"),
+                        configFile);
+            }            
+            if( (!config.isFile()) || (!config.canWrite())) {
+                log.error("Cannot write context output file at "
+                            + configFile + ", not saving.");
+                throw new IOException("Context save file at "
+                                      + configFile
+                                      + " not a file, or not writable.");
+            }
+            if (log.isInfoEnabled())
+                log.info("Store Context " + aContext.getPath()
+                        + " separate at file " + config);
+            try {
+                writer = new PrintWriter(new OutputStreamWriter(
+                        new FileOutputStream(config), getRegistry()
+                                .getEncoding()));
+                storeXMLHead(writer);
+                super.store(writer, -2, aContext);
+            } finally {
+                if (writer != null) {
+                    try {
+                        writer.flush();
+                    } catch (Exception e) {
+                        ;
+                    }
+                    try {
+                        writer.close();
+                    } catch (Throwable t) {
+                        ;
+                    }
+                }
+            }
+        } else {
+            super.store(aWriter, indent, aContext);
+        }
+    }
+
+    /**
+     * Store the Context with a Backup
+     * 
+     * @param aContext
+     * @throws Exception
+     */
+    protected void storeWithBackup(StandardContext aContext) throws Exception {
+        StoreFileMover mover = getConfigFileWriter((Context) aContext);
+        if (mover != null) {
+            // Bugzilla 37781 Check to make sure we can write this output file
+            if ((mover.getConfigOld() == null)
+                    || (!mover.getConfigOld().isFile())
+                    || (!mover.getConfigOld().canWrite())) {
+                log.error("Cannot move orignal context output file at "
+                        + mover.getConfigOld());
+                throw new IOException("Context orginal file at "
+                        + mover.getConfigOld()
+                        + " is null, not a file or not writable.");
+            }
+            File dir = mover.getConfigSave().getParentFile();
+            if (dir != null && dir.isDirectory() && (!dir.canWrite())) {
+                log.error("Cannot save context output file at "
+                        + mover.getConfigSave());
+                throw new IOException("Context save file at "
+                        + mover.getConfigSave() + " is not writable.");
+            }
+            if (log.isInfoEnabled())
+                log.info("Store Context " + aContext.getPath()
+                        + " separate with backup (at file "
+                        + mover.getConfigSave() + " )");
+
+            PrintWriter writer = mover.getWriter();
+            try {
+                storeXMLHead(writer);
+                super.store(writer, -2, aContext);
+            } finally {
+                // Flush and close the output file
+                try {
+                    writer.flush();
+                } catch (Exception e) {
+                    log.error(e);
+                }
+                try {
+                    writer.close();
+                } catch (Exception e) {
+                    throw (e);
+                }
+            }
+            mover.move();
+        }
+    }
+
+    /**
+     * Get explicit writer for context (context.getConfigFile()).
+     * 
+     * @param context
+     * @return The file mover
+     * @throws IOException
+     */
+    protected StoreFileMover getConfigFileWriter(Context context)
+            throws IOException {
+        String configFile = context.getConfigFile();
+        PrintWriter writer = null;
+        StoreFileMover mover = null;
+        if (configFile != null) {
+            File config = new File(configFile);
+            if (!config.isAbsolute()) {
+                config = new File(System.getProperty("catalina.base"),
+                        configFile);
+            }
+            // Open an output writer for the new configuration file
+            mover = new StoreFileMover("", config.getCanonicalPath(),
+                    getRegistry().getEncoding());
+        }
+        return mover;
+    }
+
+    /**
+     * Store the specified Host properties.
+     * 
+     * @param aWriter
+     *            PrintWriter to which we are storing
+     * @param indent
+     *            Number of spaces to indent this element
+     * @param aContext
+     *            Context whose properties are being stored
+     * 
+     * @exception Exception
+     *                if an exception occurs while storing
+     */
+    public void storeChilds(PrintWriter aWriter, int indent, Object aContext,
+            StoreDescription parentDesc) throws Exception {
+        if (aContext instanceof StandardContext) {
+            StandardContext context = (StandardContext) aContext;
+            // Store nested <Listener> elements
+            if (context instanceof Lifecycle) {
+                LifecycleListener listeners[] = context
+                        .findLifecycleListeners();
+                storeElementArray(aWriter, indent, listeners);
+            }
+            // Store nested <Valve> elements
+            if (context instanceof Pipeline) {
+                Valve valves[] = ((Pipeline) context).getValves();
+                storeElementArray(aWriter, indent, valves);
+            }
+
+            // Store nested <Loader> elements
+            Loader loader = context.getLoader();
+            storeElement(aWriter, indent, loader);
+
+            // Store nested <Manager> elements
+            Manager manager = context.getManager();
+            storeElement(aWriter, indent, manager);
+
+            // Store nested <Realm> element
+            Realm realm = context.getRealm();
+            if (realm != null) {
+                Realm parentRealm = null;
+                // @TODO is this case possible?
+                if (context.getParent() != null) {
+                    parentRealm = context.getParent().getRealm();
+                }
+                if (realm != parentRealm) {
+                    storeElement(aWriter, indent, realm);
+
+                }
+            }
+            // Store nested resources
+            DirContext resources = context.getResources();
+            if (resources instanceof ProxyDirContext)
+                resources = ((ProxyDirContext) resources).getDirContext();
+            storeElement(aWriter, indent, resources);
+
+            // Store nested <InstanceListener> elements
+            String iListeners[] = context.findInstanceListeners();
+            getStoreAppender().printTagArray(aWriter, "InstanceListener",
+                    indent + 2, iListeners);
+
+            // Store nested <WrapperListener> elements
+            String wLifecycles[] = context.findWrapperLifecycles();
+            getStoreAppender().printTagArray(aWriter, "WrapperListener",
+                    indent + 2, wLifecycles);
+            // Store nested <WrapperLifecycle> elements
+            String wListeners[] = context.findWrapperListeners();
+            getStoreAppender().printTagArray(aWriter, "WrapperLifecycle",
+                    indent + 2, wListeners);
+
+            // Store nested <Parameter> elements
+            ApplicationParameter[] appParams = context
+                    .findApplicationParameters();
+            storeElementArray(aWriter, indent, appParams);
+
+            // Store nested naming resources elements (EJB,Resource,...)
+            NamingResources nresources = context.getNamingResources();
+            storeElement(aWriter, indent, nresources);
+
+            // Store nested watched resources <WatchedResource>
+            String[] wresources = context.findWatchedResources();
+            wresources = filterWatchedResources(context, wresources);
+            getStoreAppender().printTagArray(aWriter, "WatchedResource",
+                    indent + 2, wresources);
+        }
+    }
+
+    /**
+     * Return a File object representing the "configuration root" directory for
+     * our associated Host.
+     */
+    protected File configBase(Context context) {
+
+        File file = new File(System.getProperty("catalina.base"), "conf");
+        Container host = (Host) context.getParent();
+
+        if ((host != null) && (host instanceof Host)) {
+            Container engine = host.getParent();
+            if ((engine != null) && (engine instanceof Engine)) {
+                file = new File(file, engine.getName());
+            }
+            file = new File(file, host.getName());
+            try {
+                file = file.getCanonicalFile();
+            } catch (IOException e) {
+                log.error(e);
+            }
+        }
+        return (file);
+
+    }
+
+    /**
+     * filter out the default watched resources
+     * 
+     * @param context
+     * @param wresources
+     * @return The watched resources
+     * @throws IOException
+     * TODO relative watchedresource
+     * TODO absolute handling configFile
+     * TODO Filename case handling for Windows?
+     * TODO digester variable subsitution $catalina.base, $catalina.home
+     */
+    protected String[] filterWatchedResources(StandardContext context,
+            String[] wresources) throws IOException {
+        File configBase = configBase(context);
+        String confContext = new File(System.getProperty("catalina.base"),
+                "conf/context.xml").getCanonicalPath();
+        String confHostDefault = new File(configBase, "context.xml.default")
+                .getCanonicalPath();
+        String configFile = context.getConfigFile();
+        String webxml = "WEB-INF/web.xml" ;
+        
+        List resource = new ArrayList();
+        for (int i = 0; i < wresources.length; i++) {
+
+            if (wresources[i].equals(confContext))
+                continue;
+            if (wresources[i].equals(confHostDefault))
+                continue;
+            if (wresources[i].equals(configFile))
+                continue;
+            if (wresources[i].equals(webxml))
+                continue;
+            resource.add(wresources[i]);
+        }
+        return (String[]) resource.toArray(new String[resource.size()]);
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/src/share/org/apache/catalina/storeconfig/StandardEngineSF.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/src/share/org/apache/catalina/storeconfig/StandardEngineSF.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/src/share/org/apache/catalina/storeconfig/StandardEngineSF.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,89 @@
+/*
+ * Copyright 1999-2001,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.storeconfig;
+
+import java.io.PrintWriter;
+
+import org.apache.catalina.Container;
+import org.apache.catalina.Lifecycle;
+import org.apache.catalina.LifecycleListener;
+import org.apache.catalina.Pipeline;
+import org.apache.catalina.Realm;
+import org.apache.catalina.Valve;
+import org.apache.catalina.core.StandardEngine;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * Store server.xml Element Engine
+ * 
+ * @author Peter Rossbach
+ */
+public class StandardEngineSF extends StoreFactoryBase {
+
+    private static Log log = LogFactory.getLog(StandardEngineSF.class);
+
+    /**
+     * Store the specified Engine properties.
+     * 
+     * @param aWriter
+     *            PrintWriter to which we are storing
+     * @param indent
+     *            Number of spaces to indent this element
+     * @param aEngine
+     *            Object whose properties are being stored
+     * 
+     * @exception Exception
+     *                if an exception occurs while storing
+     */
+    public void storeChilds(PrintWriter aWriter, int indent, Object aEngine,
+            StoreDescription parentDesc) throws Exception {
+        if (aEngine instanceof StandardEngine) {
+            StandardEngine engine = (StandardEngine) aEngine;
+            // Store nested <Listener> elements
+            if (engine instanceof Lifecycle) {
+                LifecycleListener listeners[] = ((Lifecycle) engine)
+                        .findLifecycleListeners();
+                storeElementArray(aWriter, indent, listeners);
+            }
+
+            // Store nested <Realm> element
+            Realm realm = engine.getRealm();
+            if (realm != null) {
+                Realm parentRealm = null;
+                // TODO is this case possible? (see it a old Server 5.0 impl)
+                if (engine.getParent() != null) {
+                    parentRealm = engine.getParent().getRealm();
+                }
+                if (realm != parentRealm) {
+                    storeElement(aWriter, indent, realm);
+
+                }
+            }
+
+            // Store nested <Valve> elements
+            if (engine instanceof Pipeline) {
+                Valve valves[] = ((Pipeline) engine).getValves();
+                storeElementArray(aWriter, indent, valves);
+
+            }
+            // store all <Host> elements
+            Container children[] = engine.findChildren();
+            storeElementArray(aWriter, indent, children);
+        }
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/src/share/org/apache/catalina/storeconfig/StandardHostSF.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/src/share/org/apache/catalina/storeconfig/StandardHostSF.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/src/share/org/apache/catalina/storeconfig/StandardHostSF.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,111 @@
+/*
+ * Copyright 1999-2001,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.storeconfig;
+
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.catalina.Cluster;
+import org.apache.catalina.Container;
+import org.apache.catalina.Lifecycle;
+import org.apache.catalina.LifecycleListener;
+import org.apache.catalina.Pipeline;
+import org.apache.catalina.Realm;
+import org.apache.catalina.Valve;
+import org.apache.catalina.cluster.ClusterValve;
+import org.apache.catalina.core.StandardHost;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * Store server.xml Element Host
+ * 
+ * @author Peter Rossbach
+ */
+public class StandardHostSF extends StoreFactoryBase {
+
+    private static Log log = LogFactory.getLog(StandardHostSF.class);
+
+    /**
+     * Store the specified Host properties and childs
+     * (Listener,Alias,Realm,Valve,Cluster, Context)
+     * 
+     * @param aWriter
+     *            PrintWriter to which we are storing
+     * @param indent
+     *            Number of spaces to indent this element
+     * @param aHost
+     *            Host whose properties are being stored
+     * 
+     * @exception Exception
+     *                if an exception occurs while storing
+     */
+    public void storeChilds(PrintWriter aWriter, int indent, Object aHost,
+            StoreDescription parentDesc) throws Exception {
+        if (aHost instanceof StandardHost) {
+            StandardHost host = (StandardHost) aHost;
+            // Store nested <Listener> elements
+            if (host instanceof Lifecycle) {
+                LifecycleListener listeners[] = ((Lifecycle) host)
+                        .findLifecycleListeners();
+                storeElementArray(aWriter, indent, listeners);
+            }
+
+            // Store nested <Alias> elements
+            String aliases[] = host.findAliases();
+            getStoreAppender().printTagArray(aWriter, "Alias", indent + 2,
+                    aliases);
+
+            // Store nested <Realm> element
+            Realm realm = host.getRealm();
+            if (realm != null) {
+                Realm parentRealm = null;
+                if (host.getParent() != null) {
+                    parentRealm = host.getParent().getRealm();
+                }
+                if (realm != parentRealm) {
+                    storeElement(aWriter, indent, realm);
+                }
+            }
+
+            // Store nested <Valve> elements
+            if (host instanceof Pipeline) {
+                Valve valves[] = ((Pipeline) host).getValves();
+                if(valves != null && valves.length > 0 ) {
+                    List hostValves = new ArrayList() ;
+                    for(int i = 0 ; i < valves.length ; i++ ) {
+                        if(!( valves[i] instanceof ClusterValve))
+                            hostValves.add(valves[i]);
+                    }                
+                    storeElementArray(aWriter, indent, hostValves.toArray());
+                }
+            }
+
+            // store all <Cluster> elements
+            Cluster cluster = host.getCluster();
+            if (cluster != null) {
+                storeElement(aWriter, indent, cluster);
+            }
+
+            // store all <Context> elements
+            Container children[] = host.findChildren();
+            storeElementArray(aWriter, indent, children);
+        }
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/src/share/org/apache/catalina/storeconfig/StandardServerSF.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/src/share/org/apache/catalina/storeconfig/StandardServerSF.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/src/share/org/apache/catalina/storeconfig/StandardServerSF.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,110 @@
+/*
+ * Copyright 2004-2005 The Apache Software Foundation.
+ * 
+ * Licensed 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.storeconfig;
+
+import java.io.PrintWriter;
+
+import org.apache.catalina.Lifecycle;
+import org.apache.catalina.LifecycleListener;
+import org.apache.catalina.Service;
+import org.apache.catalina.core.StandardServer;
+import org.apache.catalina.deploy.NamingResources;
+import org.apache.catalina.mbeans.ServerLifecycleListener;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * Store server.xml Server element and childs (
+ * Listener,GlobalNamingResource,Service)
+ * 
+ * @author Peter Rossbach
+ */
+public class StandardServerSF extends StoreFactoryBase {
+
+    private static Log log = LogFactory.getLog(StandardServerSF.class);
+
+    /**
+     * Store the specified Server properties.
+     * 
+     * @param aWriter
+     *            PrintWriter to which we are storing
+     * @param indent
+     *            Number of spaces to indent this element
+     * @param aServer
+     *            Object to be stored
+     * 
+     * @exception Exception
+     *                if an exception occurs while storing
+     * @see org.apache.catalina.storeconfig.IStoreFactory#store(java.io.PrintWriter,
+     *      int, java.lang.Object)
+     */
+    public void store(PrintWriter aWriter, int indent, Object aServer)
+            throws Exception {
+        storeXMLHead(aWriter);
+        super.store(aWriter, indent, aServer);
+    }
+
+    /**
+     * Store Childs from this StandardServer descrition
+     * 
+     * @param aWriter
+     * @param indent
+     * @param aObject
+     * @param parentDesc
+     * @throws Exception
+     */
+    public void storeChilds(PrintWriter aWriter, int indent, Object aObject,
+            StoreDescription parentDesc) throws Exception {
+        if (aObject instanceof StandardServer) {
+            StandardServer server = (StandardServer) aObject;
+            // Store nested <Listener> elements
+            if (server instanceof Lifecycle) {
+                LifecycleListener listeners[] = ((Lifecycle) server)
+                        .findLifecycleListeners();
+                storeElementArray(aWriter, indent, listeners);
+                LifecycleListener listener = null;
+                for (int i = 0; listener == null && i < listeners.length; i++)
+                    if (listeners[i] instanceof ServerLifecycleListener)
+                        listener = listeners[i];
+                if (listener != null) {
+                    StoreDescription elementDesc = getRegistry()
+                            .findDescription(
+                                    StandardServer.class.getName()
+                                            + ".[ServerLifecycleListener]");
+                    if (elementDesc != null) {
+                        elementDesc.getStoreFactory().store(aWriter, indent,
+                                listener);
+                    }
+                }
+            }
+            // Store nested <GlobalNamingResources> element
+            NamingResources globalNamingResources = server
+                    .getGlobalNamingResources();
+            StoreDescription elementDesc = getRegistry().findDescription(
+                    NamingResources.class.getName()
+                            + ".[GlobalNamingResources]");
+            if (elementDesc != null) {
+                elementDesc.getStoreFactory().store(aWriter, indent,
+                        globalNamingResources);
+            }
+            // Store nested <Service> elements
+            Service services[] = server.findServices();
+            storeElementArray(aWriter, indent, services);
+        }
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/src/share/org/apache/catalina/storeconfig/StandardServiceSF.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/src/share/org/apache/catalina/storeconfig/StandardServiceSF.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/src/share/org/apache/catalina/storeconfig/StandardServiceSF.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,73 @@
+/*
+ * Copyright 1999-2001,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.storeconfig;
+
+import java.io.PrintWriter;
+
+import org.apache.catalina.Container;
+import org.apache.catalina.Lifecycle;
+import org.apache.catalina.LifecycleListener;
+import org.apache.catalina.connector.Connector;
+import org.apache.catalina.core.StandardService;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * Store server.xml Element Service and all childs 
+ * @author Peter Rossbach (pero at apache.org)
+ */
+public class StandardServiceSF extends StoreFactoryBase {
+
+    private static Log log = LogFactory.getLog(StandardServiceSF.class);
+
+    /**
+     * Store Childs from this StandardService description
+     * 
+     * @param aWriter
+     * @param indent
+     * @param aService
+     * @throws Exception
+     */
+    public void storeChilds(PrintWriter aWriter, int indent, Object aService,
+            StoreDescription parentDesc) throws Exception {
+        if (aService instanceof StandardService) {
+            StandardService service = (StandardService) aService;
+            // Store nested <Listener> elements
+            if (service instanceof Lifecycle) {
+                LifecycleListener listeners[] = ((Lifecycle) service)
+                        .findLifecycleListeners();
+                storeElementArray(aWriter, indent, listeners);
+            }
+
+            Connector connectors[] = service.findConnectors();
+            storeElementArray(aWriter, indent, connectors);
+
+            // Store nested <Engine> element (or other appropriate container)
+            Container container = service.getContainer();
+            if (container != null) {
+                StoreDescription elementDesc = getRegistry().findDescription(
+                        container.getClass());
+                if (elementDesc != null) {
+                    IStoreFactory factory = elementDesc.getStoreFactory();
+                    factory.store(aWriter, indent, container);
+                }
+            }
+        }
+
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/src/share/org/apache/catalina/storeconfig/StoreAppender.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/src/share/org/apache/catalina/storeconfig/StoreAppender.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/src/share/org/apache/catalina/storeconfig/StoreAppender.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,395 @@
+/*
+ * Copyright 2004-2005 The Apache Software Foundation.
+ * 
+ * Licensed 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.storeconfig;
+
+import java.beans.IndexedPropertyDescriptor;
+import java.beans.Introspector;
+import java.beans.PropertyDescriptor;
+import java.io.PrintWriter;
+import java.util.Iterator;
+
+import org.apache.catalina.deploy.ResourceBase;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.tomcat.util.IntrospectionUtils;
+
+/**
+ * StoreAppends generate really the xml tag elements
+ * 
+ * @author Peter Rossbach
+ *  
+ */
+public class StoreAppender {
+    private static Log log = LogFactory.getLog(StoreAppender.class);
+
+    /**
+     * The set of classes that represent persistable properties.
+     */
+    private static Class persistables[] = { String.class, Integer.class,
+            Integer.TYPE, Boolean.class, Boolean.TYPE, Byte.class, Byte.TYPE,
+            Character.class, Character.TYPE, Double.class, Double.TYPE,
+            Float.class, Float.TYPE, Long.class, Long.TYPE, Short.class,
+            Short.TYPE, };
+
+    /**
+     * print the closing tag
+     * 
+     * @param aWriter
+     * @param aDesc
+     * @throws Exception
+     */
+    public void printCloseTag(PrintWriter aWriter, StoreDescription aDesc)
+            throws Exception {
+        aWriter.print("</");
+        aWriter.print(aDesc.getTag());
+        aWriter.println(">");
+    }
+
+    /**
+     * print only the open tag with all attributes
+     * 
+     * @param aWriter
+     * @param indent
+     * @param bean
+     * @param aDesc
+     * @throws Exception
+     */
+    public void printOpenTag(PrintWriter aWriter, int indent, Object bean,
+            StoreDescription aDesc) throws Exception {
+        aWriter.print("<");
+        aWriter.print(aDesc.getTag());
+        if (aDesc.isAttributes() && bean != null)
+            printAttributes(aWriter, indent, bean, aDesc);
+        aWriter.println(">");
+    }
+
+    /**
+     * Print tag with all attributes
+     * 
+     * @param aWriter
+     * @param indent
+     * @param bean
+     * @param aDesc
+     * @throws Exception
+     */
+    public void printTag(PrintWriter aWriter, int indent, Object bean,
+            StoreDescription aDesc) throws Exception {
+        aWriter.print("<");
+        aWriter.print(aDesc.getTag());
+        if (aDesc.isAttributes() && bean != null)
+            printAttributes(aWriter, indent, bean, aDesc);
+        aWriter.println("/>");
+    }
+
+    /**
+     * print the value from tag as content
+     * 
+     * @param aWriter
+     * @param tag
+     * @param content
+     * @throws Exception
+     */
+    public void printTagContent(PrintWriter aWriter, String tag, String content)
+            throws Exception {
+        aWriter.print("<");
+        aWriter.print(tag);
+        aWriter.print(">");
+        aWriter.print(convertStr(content));
+        aWriter.print("</");
+        aWriter.print(tag);
+        aWriter.println(">");
+    }
+
+    /**
+     * print an array of values
+     * 
+     * @param aWriter
+     * @param tag
+     * @param indent
+     * @param elements
+     */
+    public void printTagValueArray(PrintWriter aWriter, String tag, int indent,
+            String[] elements) {
+        if (elements != null && elements.length > 0) {
+            printIndent(aWriter, indent + 2);
+            aWriter.print("<");
+            aWriter.print(tag);
+            aWriter.print(">");
+            for (int i = 0; i < elements.length; i++) {
+                printIndent(aWriter, indent + 4);
+                aWriter.print(elements[i]);
+                if (i + 1 < elements.length)
+                    aWriter.println(",");
+            }
+            printIndent(aWriter, indent + 2);
+            aWriter.print("</");
+            aWriter.print(tag);
+            aWriter.println(">");
+        }
+    }
+
+    /**
+     * print a array of elements
+     * 
+     * @param aWriter
+     * @param tag
+     * @param indent
+     * @param elements
+     */
+    public void printTagArray(PrintWriter aWriter, String tag, int indent,
+            String[] elements) throws Exception {
+        if (elements != null) {
+            for (int i = 0; i < elements.length; i++) {
+                printIndent(aWriter, indent);
+                printTagContent(aWriter, tag, elements[i]);
+            }
+        }
+    }
+
+    /**
+     * Print some spaces
+     * 
+     * @param aWriter
+     * @param indent
+     *            number of spaces
+     */
+    public void printIndent(PrintWriter aWriter, int indent) {
+        for (int i = 0; i < indent; i++) {
+            aWriter.print(' ');
+        }
+    }
+
+    /**
+     * Store the relevant attributes of the specified JavaBean, plus a
+     * <code>className</code> attribute defining the fully qualified Java
+     * class name of the bean.
+     * 
+     * @param writer
+     *            PrintWriter to which we are storing
+     * @param bean
+     *            Bean whose properties are to be rendered as attributes,
+     * 
+     * @exception Exception
+     *                if an exception occurs while storing
+     */
+    public void printAttributes(PrintWriter writer, int indent, Object bean,
+            StoreDescription desc) throws Exception {
+
+        printAttributes(writer, indent, true, bean, desc);
+
+    }
+
+    /**
+     * Store the relevant attributes of the specified JavaBean.
+     * 
+     * @param writer
+     *            PrintWriter to which we are storing
+     * @param include
+     *            Should we include a <code>className</code> attribute?
+     * @param bean
+     *            Bean whose properties are to be rendered as attributes,
+     * @param desc
+     *            RegistryDescrpitor from this bean
+     * 
+     * @exception Exception
+     *                if an exception occurs while storing
+     */
+    public void printAttributes(PrintWriter writer, int indent,
+            boolean include, Object bean, StoreDescription desc)
+            throws Exception {
+
+        // Render the relevant properties of this bean
+        String className = bean.getClass().getName();
+
+        // Render a className attribute if requested
+        if (include && desc != null && !desc.isStandard()) {
+            writer.print(" className=\"");
+            writer.print(bean.getClass().getName());
+            writer.print("\"");
+        }
+
+        // Acquire the list of properties for this bean
+        PropertyDescriptor descriptors[] = Introspector.getBeanInfo(
+                bean.getClass()).getPropertyDescriptors();
+        if (descriptors == null) {
+            descriptors = new PropertyDescriptor[0];
+        }
+
+        // Create blank instance
+        Object bean2 = defaultInstance(bean);
+        for (int i = 0; i < descriptors.length; i++) {
+            if (descriptors[i] instanceof IndexedPropertyDescriptor) {
+                continue; // Indexed properties are not persisted
+            }
+            if (!isPersistable(descriptors[i].getPropertyType())
+                    || (descriptors[i].getReadMethod() == null)
+                    || (descriptors[i].getWriteMethod() == null)) {
+                continue; // Must be a read-write primitive or String
+            }
+            if (desc.isTransientAttribute(descriptors[i].getName())) {
+                continue; // Skip the specified exceptions
+            }
+            Object value = IntrospectionUtils.getProperty(bean, descriptors[i]
+                    .getName());
+            if (value == null) {
+                continue; // Null values are not persisted
+            }
+            Object value2 = IntrospectionUtils.getProperty(bean2,
+                    descriptors[i].getName());
+            if (value.equals(value2)) {
+                // The property has its default value
+                continue;
+            }
+            printAttribute(writer, indent, bean, desc, descriptors[i].getName(), bean2, value);
+        }
+
+        if (bean instanceof ResourceBase) {
+            ResourceBase resource = (ResourceBase) bean;
+            for (Iterator iter = resource.listProperties(); iter.hasNext();) {
+                String name = (String) iter.next();
+                Object value = resource.getProperty(name);
+                if (!isPersistable(value.getClass())) {
+                    continue;
+                }
+                if (desc.isTransientAttribute(name)) {
+                    continue; // Skip the specified exceptions
+                }
+                printValue(writer, indent, name, value);
+
+            }
+        }
+    }
+
+    /**
+     * @param writer
+     * @param indent
+     * @param bean
+     * @param desc
+     * @param attributeName
+     * @param bean2
+     * @param value
+     */
+    protected void printAttribute(PrintWriter writer, int indent, Object bean, StoreDescription desc, String attributeName, Object bean2, Object value) {
+        if (isPrintValue(bean, bean2, attributeName, desc))
+            printValue(writer, indent, attributeName, value);
+    }
+
+    /**
+     * print this Attribute value or not
+     * 
+     * @param bean
+     *            orginal bean
+     * @param bean2
+     *            default bean
+     * @param attrName
+     *            attribute name
+     * @param desc
+     *            StoreDescription from bean
+     * @return True if it's a printing value
+     */
+    public boolean isPrintValue(Object bean, Object bean2, String attrName,
+            StoreDescription desc) {
+        boolean printValue = false;
+
+        Object value = IntrospectionUtils.getProperty(bean, attrName);
+        if (value != null) {
+            Object value2 = IntrospectionUtils.getProperty(bean2, attrName);
+            printValue = !value.equals(value2);
+
+        }
+        return printValue;
+    }
+
+    /**
+     * generate default Instance
+     * 
+     * @param bean
+     * @return an object from same class as bean parameter
+     * @throws InstantiationException
+     * @throws IllegalAccessException
+     */
+    public Object defaultInstance(Object bean) throws InstantiationException,
+            IllegalAccessException {
+        return bean.getClass().newInstance();
+    }
+
+    /**
+     * print an attribute value
+     * 
+     * @param writer
+     * @param name
+     * @param value
+     */
+    public void printValue(PrintWriter writer, int indent, String name,
+            Object value) {
+        if (!(value instanceof String)) {
+            value = value.toString();
+        }
+        writer.println();
+        printIndent(writer, indent + 4);
+        writer.print(name);
+        writer.print("=\"");
+        String strValue = convertStr((String) value);
+        writer.print(strValue);
+        writer.print("\"");
+    }
+
+    /**
+     * Given a string, this method replaces all occurrences of ' <', '>', '&',
+     * and '"'.
+     */
+    public String convertStr(String input) {
+
+        StringBuffer filtered = new StringBuffer(input.length());
+        char c;
+        for (int i = 0; i < input.length(); i++) {
+            c = input.charAt(i);
+            if (c == '<') {
+                filtered.append("&lt;");
+            } else if (c == '>') {
+                filtered.append("&gt;");
+            } else if (c == '\'') {
+                filtered.append("&apos;");
+            } else if (c == '"') {
+                filtered.append("&quot;");
+            } else if (c == '&') {
+                filtered.append("&amp;");
+            } else {
+                filtered.append(c);
+            }
+        }
+        return (filtered.toString());
+    }
+
+    /**
+     * Is the specified property type one for which we should generate a
+     * persistence attribute?
+     * 
+     * @param clazz
+     *            Java class to be tested
+     */
+    protected boolean isPersistable(Class clazz) {
+
+        for (int i = 0; i < persistables.length; i++) {
+            if (persistables[i] == clazz) {
+                return (true);
+            }
+        }
+        return (false);
+
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/src/share/org/apache/catalina/storeconfig/StoreConfig.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/src/share/org/apache/catalina/storeconfig/StoreConfig.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/src/share/org/apache/catalina/storeconfig/StoreConfig.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,346 @@
+/*
+ * Copyright 2004-2006 The Apache Software Foundation.
+ * 
+ * Licensed 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.storeconfig;
+
+import java.io.PrintWriter;
+
+import javax.management.MBeanServer;
+import javax.management.MalformedObjectNameException;
+import javax.management.ObjectName;
+
+import org.apache.catalina.Context;
+import org.apache.catalina.Host;
+import org.apache.catalina.Server;
+import org.apache.catalina.ServerFactory;
+import org.apache.catalina.Service;
+import org.apache.catalina.core.StandardContext;
+import org.apache.catalina.mbeans.MBeanUtils;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * Store Server/Service/Host/Context at file or PrintWriter. Default server.xml
+ * is at $catalina.base/conf/server.xml
+ * 
+ * @author Peter Rossbach
+ *  
+ */
+public class StoreConfig implements IStoreConfig {
+    private static Log log = LogFactory.getLog(StoreConfig.class);
+
+    private String serverFilename = "conf/server.xml";
+
+    private StoreRegistry registry;
+
+    /**
+     * get server.xml location
+     * 
+     * @return The server file name
+     */
+    public String getServerFilename() {
+        return serverFilename;
+    }
+
+    /**
+     * set new server.xml location
+     * 
+     * @param string
+     */
+    public void setServerFilename(String string) {
+        serverFilename = string;
+    }
+
+    /*
+     * Get the StoreRegistry with all factory to generate the
+     * server.xml/context.xml files
+     * 
+     * @see org.apache.catalina.config.IStoreConfig#getRegistry()
+     */
+    public StoreRegistry getRegistry() {
+        return registry;
+    }
+
+    /*
+     * set StoreRegistry
+     * 
+     * @see org.apache.catalina.config.IStoreConfig#setRegistry(org.apache.catalina.config.ConfigurationRegistry)
+     */
+    public void setRegistry(StoreRegistry aRegistry) {
+        registry = aRegistry;
+    }
+
+    /**
+     * Store current Server
+     * 
+     * @see org.apache.catalina.ServerFactory#getServer()
+     */
+    public synchronized void storeConfig() {
+        store(ServerFactory.getServer());
+    }
+
+    /**
+     * Store Server from Object Name (Catalina:type=Server)
+     * 
+     * @param aServerName
+     *            Server ObjectName
+     * @param backup
+     * @param externalAllowed
+     *            s *
+     * @throws MalformedObjectNameException
+     */
+    public synchronized void storeServer(String aServerName, boolean backup,
+            boolean externalAllowed) throws MalformedObjectNameException {
+        if (aServerName == null || aServerName.length() == 0) {
+            if (log.isErrorEnabled())
+                log.error("Please, call with a correct server ObjectName!");
+            return;
+        }
+        MBeanServer mserver = MBeanUtils.createServer();
+        ObjectName objectName = new ObjectName(aServerName);
+        if (mserver.isRegistered(objectName)) {
+            try {
+                Server aServer = (Server) mserver.getAttribute(objectName,
+                        "managedResource");
+                StoreDescription desc = null;
+                desc = getRegistry().findDescription(StandardContext.class);
+                if (desc != null) {
+                    boolean oldSeparate = desc.isStoreSeparate();
+                    boolean oldBackup = desc.isBackup();
+                    boolean oldExternalAllowed = desc.isExternalAllowed();
+                    try {
+                        desc.setStoreSeparate(true);
+                        desc.setBackup(backup);
+                        desc.setExternalAllowed(externalAllowed);
+                        store((Server) aServer);
+                    } finally {
+                        desc.setStoreSeparate(oldSeparate);
+                        desc.setBackup(oldBackup);
+                        desc.setExternalAllowed(oldExternalAllowed);
+                    }
+                } else
+                    store((Server) aServer);
+            } catch (Exception e) {
+                if (log.isInfoEnabled())
+                    log.info("Object " + aServerName
+                            + " is no a Server instance or store exception", e);
+            }
+        } else if (log.isInfoEnabled())
+            log.info("Server " + aServerName + " not found!");
+    }
+
+    /**
+     * Store a Context from ObjectName
+     * 
+     * @param aContextName
+     *            MBean ObjectName
+     * @param backup
+     * @param externalAllowed
+     * @throws MalformedObjectNameException
+     */
+    public synchronized void storeContext(String aContextName, boolean backup,
+            boolean externalAllowed) throws MalformedObjectNameException {
+        if (aContextName == null || aContextName.length() == 0) {
+            if (log.isErrorEnabled())
+                log.error("Please, call with a correct context ObjectName!");
+            return;
+        }
+        MBeanServer mserver = MBeanUtils.createServer();
+        ObjectName objectName = new ObjectName(aContextName);
+        if (mserver.isRegistered(objectName)) {
+            try {
+                Context aContext = (Context) mserver.getAttribute(objectName,
+                        "managedResource");
+                String configFile = aContext.getConfigFile();
+                if (configFile != null) {
+                    try {
+                        StoreDescription desc = null;
+                        desc = getRegistry().findDescription(
+                                aContext.getClass());
+                        if (desc != null) {
+                            boolean oldSeparate = desc.isStoreSeparate();
+                            boolean oldBackup = desc.isBackup();
+                            boolean oldExternalAllowed = desc
+                                    .isExternalAllowed();
+                            try {
+                                desc.setStoreSeparate(true);
+                                desc.setBackup(backup);
+                                desc.setExternalAllowed(externalAllowed);
+                                desc.getStoreFactory()
+                                        .store(null, -2, aContext);
+                            } finally {
+                                desc.setStoreSeparate(oldSeparate);
+                                desc.setBackup(oldBackup);
+                                desc.setBackup(oldExternalAllowed);
+                            }
+                        }
+                    } catch (Exception e) {
+                        log.error(e);
+                    }
+                } else
+                    log.error("Missing configFile at Context "
+                            + aContext.getPath() + " to store!");
+            } catch (Exception e) {
+                if (log.isInfoEnabled())
+                    log
+                            .info(
+                                    "Object "
+                                            + aContextName
+                                            + " is no a context instance or store exception",
+                                    e);
+            }
+        } else if (log.isInfoEnabled())
+            log.info("Context " + aContextName + " not found!");
+    }
+
+    /**
+     * Write the configuration information for this entire <code>Server</code>
+     * out to the server.xml configuration file.
+     *  
+     */
+    public synchronized void store(Server aServer) {
+
+        StoreFileMover mover = new StoreFileMover(System
+                .getProperty("catalina.base"), getServerFilename(),
+                getRegistry().getEncoding());
+        // Open an output writer for the new configuration file
+        try {
+            PrintWriter writer = mover.getWriter();
+
+            try {
+                store(writer, -2, aServer);
+            } finally {
+                // Flush and close the output file
+                try {
+                    writer.flush();
+                } catch (Exception e) {
+                    log.error(e);
+                }
+                try {
+                    writer.close();
+                } catch (Exception e) {
+                    throw (e);
+                }
+            }
+            mover.move();
+        } catch (Exception e) {
+            log.error(e);
+        }
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see org.apache.catalina.config.IStoreConfig#store(org.apache.catalina.Context)
+     */
+    public synchronized void store(Context aContext) {
+        String configFile = aContext.getConfigFile();
+        if (configFile != null) {
+            try {
+                StoreDescription desc = null;
+                desc = getRegistry().findDescription(aContext.getClass());
+                if (desc != null) {
+                    boolean old = desc.isStoreSeparate();
+                    try {
+                        desc.setStoreSeparate(true);
+                        desc.getStoreFactory().store(null, -2, aContext);
+                    } finally {
+                        desc.setStoreSeparate(old);
+                    }
+                }
+            } catch (Exception e) {
+                log.error(e);
+            }
+        } else
+            log.error("Missing configFile at Context " + aContext.getPath());
+
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see org.apache.catalina.config.IStoreConfig#store(java.io.PrintWriter,
+     *      int, org.apache.catalina.Context)
+     */
+    public synchronized void store(PrintWriter aWriter, int indent,
+            Context aContext) {
+        boolean oldSeparate = true;
+        StoreDescription desc = null;
+        try {
+            desc = getRegistry().findDescription(aContext.getClass());
+            oldSeparate = desc.isStoreSeparate();
+            desc.setStoreSeparate(false);
+            desc.getStoreFactory().store(aWriter, indent, aContext);
+        } catch (Exception e) {
+            log.error(e);
+        } finally {
+            if (desc != null)
+                desc.setStoreSeparate(oldSeparate);
+        }
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see org.apache.catalina.config.IStoreConfig#store(java.io.PrintWriter,
+     *      int, org.apache.catalina.Host)
+     */
+    public synchronized void store(PrintWriter aWriter, int indent, Host aHost) {
+        try {
+            StoreDescription desc = getRegistry().findDescription(
+                    aHost.getClass());
+            desc.getStoreFactory().store(aWriter, indent, aHost);
+        } catch (Exception e) {
+            log.error(e);
+        }
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see org.apache.catalina.config.IStoreConfig#store(java.io.PrintWriter,
+     *      int, org.apache.catalina.Service)
+     */
+    public synchronized void store(PrintWriter aWriter, int indent,
+            Service aService) {
+        try {
+            StoreDescription desc = getRegistry().findDescription(
+                    aService.getClass());
+            desc.getStoreFactory().store(aWriter, indent, aService);
+        } catch (Exception e) {
+            log.error(e);
+        }
+    }
+
+    /**
+     * Store the state of this Server MBean (which will recursively store
+     * everything)
+     * 
+     * @param writer
+     * @param indent
+     * @param aServer
+     */
+    public synchronized void store(PrintWriter writer, int indent,
+            Server aServer) {
+        try {
+            StoreDescription desc = getRegistry().findDescription(
+                    aServer.getClass());
+            desc.getStoreFactory().store(writer, indent, aServer);
+        } catch (Exception e) {
+            log.error(e);
+        }
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/src/share/org/apache/catalina/storeconfig/StoreConfigLifecycleListener.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/src/share/org/apache/catalina/storeconfig/StoreConfigLifecycleListener.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/src/share/org/apache/catalina/storeconfig/StoreConfigLifecycleListener.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,167 @@
+/*
+ * Copyright 2004-2005 The Apache Software Foundation.
+ * 
+ * Licensed 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.storeconfig;
+
+import java.io.InputStream;
+
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+import javax.management.modelmbean.ModelMBean;
+
+import org.apache.catalina.Lifecycle;
+import org.apache.catalina.LifecycleEvent;
+import org.apache.catalina.LifecycleListener;
+import org.apache.catalina.core.StandardServer;
+import org.apache.catalina.mbeans.MBeanUtils;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.commons.modeler.ManagedBean;
+import org.apache.commons.modeler.Registry;
+
+/**
+ * Load and Register StoreConfig MBean <i>Catalina:type=StoreConfig,resource="url"</i>
+ * 
+ * @author Peter Rossbach
+ */
+public class StoreConfigLifecycleListener implements LifecycleListener {
+    private static Log log = LogFactory
+            .getLog(StoreConfigLifecycleListener.class);
+
+    IStoreConfig storeConfig;
+
+    private String storeConfigClass = "org.apache.catalina.storeconfig.StoreConfig";
+
+    private String storeRegistry = null;
+
+    /*
+     * register StoreRegistry after Start the complete Server
+     * 
+     * @see org.apache.catalina.LifecycleListener#lifecycleEvent(org.apache.catalina.LifecycleEvent)
+     */
+    public void lifecycleEvent(LifecycleEvent event) {
+        if (Lifecycle.AFTER_START_EVENT.equals(event.getType())) {
+            if (event.getSource() instanceof StandardServer) {
+                createMBean();
+            }
+        }
+    }
+
+    /**
+     * create StoreConfig MBean and load StoreRgistry MBeans name is
+     * <i>Catalina:type=StoreConfig </i>
+     */
+    protected void createMBean() {
+        StoreLoader loader = new StoreLoader();
+        try {
+            Class clazz = Class.forName(getStoreConfigClass(), true, this
+                    .getClass().getClassLoader());
+            storeConfig = (IStoreConfig) clazz.newInstance();
+            if (null == getStoreRegistry())
+                // default Loading
+                loader.load();
+            else
+                // load a spezial file registry (url)
+                loader.load(getStoreRegistry());
+            // use the loader Registry
+            storeConfig.setRegistry(loader.getRegistry());
+        } catch (Exception e) {
+            log.error("createMBean load", e);
+            return;
+        }
+        MBeanServer mserver = MBeanUtils.createServer();
+        InputStream descriptor = null;
+        try {
+            ObjectName objectName = new ObjectName("Catalina:type=StoreConfig" );
+            if (!mserver.isRegistered(objectName)) {
+                descriptor = this.getClass().getResourceAsStream(
+                        "mbeans-descriptors.xml");
+                Registry registry = MBeanUtils.createRegistry();
+                registry.loadMetadata(descriptor);
+                mserver.registerMBean(getManagedBean(storeConfig), objectName);
+            }
+        } catch (Exception ex) {
+            log.error("createMBean register MBean", ex);
+
+        } finally {
+            if (descriptor != null) {
+                try {
+                    descriptor.close();
+                    descriptor = null;
+                } catch (Exception ex) {
+                    log.error("createMBean register MBean", ex);
+                }
+            }
+        }
+    }
+
+    /**
+     * Create a ManagedBean (StoreConfig)
+     * 
+     * @param object
+     * @return The bean
+     * @throws Exception
+     */
+    protected ModelMBean getManagedBean(Object object) throws Exception {
+        ManagedBean managedBean = Registry.getRegistry(null, null)
+                .findManagedBean(object.getClass().getName());
+        return managedBean.createMBean(object);
+    }
+
+    /**
+     * @return Returns the storeConfig.
+     */
+    public IStoreConfig getStoreConfig() {
+        return storeConfig;
+    }
+
+    /**
+     * @param storeConfig
+     *            The storeConfig to set.
+     */
+    public void setStoreConfig(IStoreConfig storeConfig) {
+        this.storeConfig = storeConfig;
+    }
+
+    /**
+     * @return Returns the storeConfigClass.
+     */
+    public String getStoreConfigClass() {
+        return storeConfigClass;
+    }
+
+    /**
+     * @param storeConfigClass
+     *            The storeConfigClass to set.
+     */
+    public void setStoreConfigClass(String storeConfigClass) {
+        this.storeConfigClass = storeConfigClass;
+    }
+
+    /**
+     * @return Returns the storeRegistry.
+     */
+    public String getStoreRegistry() {
+        return storeRegistry;
+    }
+
+    /**
+     * @param storeRegistry
+     *            The storeRegistry to set.
+     */
+    public void setStoreRegistry(String storeRegistry) {
+        this.storeRegistry = storeRegistry;
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/src/share/org/apache/catalina/storeconfig/StoreContextAppender.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/src/share/org/apache/catalina/storeconfig/StoreContextAppender.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/src/share/org/apache/catalina/storeconfig/StoreContextAppender.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,180 @@
+/*
+ * Copyright 2004-2005 The Apache Software Foundation.
+ * 
+ * Licensed 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.storeconfig;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.PrintWriter;
+
+import org.apache.catalina.Container;
+import org.apache.catalina.core.StandardContext;
+import org.apache.catalina.core.StandardHost;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * store StandardContext Attributes ... 
+ * 
+ * @author Peter Rossbach
+ *  
+ */
+public class StoreContextAppender extends StoreAppender {
+
+    private static Log log = LogFactory.getLog(StoreContextAppender.class);
+
+    /**
+     * @param writer
+     * @param indent
+     * @param bean
+     * @param desc
+     * @param attributeName
+     * @param bean2
+     * @param value
+     */
+    protected void printAttribute(PrintWriter writer, int indent, Object bean, StoreDescription desc, String attributeName, Object bean2, Object value) {
+        if (isPrintValue(bean, bean2, attributeName, desc)) {
+            if(attributeName.equals("docBase")) {
+                if(bean instanceof StandardContext) {
+                    String docBase = ((StandardContext)bean).getOriginalDocBase() ;
+                    if(docBase != null)
+                        value = docBase ;
+                }
+            }
+            printValue(writer, indent, attributeName, value);
+        }
+    }
+
+    /*
+     * Print Context Values. <ul><li> Spezial handling to default workDir.
+     * </li><li> Don't save path at external context.xml </li><li> Don't
+     * generate docBase for host.appBase webapps <LI></ul>
+     * 
+     * @see org.apache.catalina.config.StoreAppender#isPrintValue(java.lang.Object,
+     *      java.lang.Object, java.lang.String,
+     *      org.apache.catalina.config.StoreDescription)
+     */
+    public boolean isPrintValue(Object bean, Object bean2, String attrName,
+            StoreDescription desc) {
+        boolean isPrint = super.isPrintValue(bean, bean2, attrName, desc);
+        if (isPrint) {
+            StandardContext context = ((StandardContext) bean);
+            if ("workDir".equals(attrName)) {
+                String defaultWorkDir = getDefaultWorkDir(context);
+                isPrint = !defaultWorkDir.equals(context.getWorkDir());
+            } else if ("path".equals(attrName)) {
+                isPrint = desc.isStoreSeparate() 
+                            && desc.isExternalAllowed()
+                            && context.getConfigFile() == null;
+            } else if ("docBase".equals(attrName)) {
+                Container host = context.getParent();
+                if (host instanceof StandardHost) {
+                    File appBase = getAppBase(((StandardHost) host));
+                    File docBase = getDocBase(context,appBase);
+                    isPrint = !appBase.equals(docBase.getParentFile());
+                }
+            }
+        }
+        return isPrint;
+    }
+
+    protected File getAppBase(StandardHost host) {
+
+        File appBase;
+        File file = new File(host.getAppBase());
+        if (!file.isAbsolute())
+            file = new File(System.getProperty("catalina.base"), host
+                    .getAppBase());
+        try {
+            appBase = file.getCanonicalFile();
+        } catch (IOException e) {
+            appBase = file;
+        }
+        return (appBase);
+
+    }
+
+    protected File getDocBase(StandardContext context, File appBase) {
+
+        File docBase;
+        String contextDocBase = context.getOriginalDocBase() ;
+        if(contextDocBase == null)
+            contextDocBase = context.getDocBase() ;
+        File file = new File(contextDocBase);
+        if (!file.isAbsolute())
+            file = new File(appBase, contextDocBase);
+        try {
+            docBase = file.getCanonicalFile();
+        } catch (IOException e) {
+            docBase = file;
+        }
+        return (docBase);
+
+    }
+
+    /**
+     * Make default Work Dir.
+     * 
+     * @param context
+     * @return The default working directory for the context.
+     */
+    protected String getDefaultWorkDir(StandardContext context) {
+        String defaultWorkDir = null;
+        String contextPath = context.getPath().length() == 0 ? "_" : context
+                .getPath().substring(1);
+        Container host = context.getParent();
+        if (host instanceof StandardHost) {
+            String hostWorkDir = ((StandardHost) host).getWorkDir();
+            if (hostWorkDir != null) {
+                defaultWorkDir = hostWorkDir + File.separator + contextPath;
+            } else {
+                String engineName = context.getParent().getParent().getName();
+                String hostName = context.getParent().getName();
+                defaultWorkDir = "work" + File.separator + engineName
+                        + File.separator + hostName + File.separator
+                        + contextPath;
+            }
+        }
+        return defaultWorkDir;
+    }
+
+    /*
+     * Generate a real default StandardContext TODO read and interpret the
+     * default context.xml and context.xml.default TODO Cache a Default
+     * StandardContext ( with reloading strategy) TODO remove really all
+     * elements, but detection is hard... To Listener or Valve from same class?>
+     * 
+     * @see org.apache.catalina.storeconfig.StoreAppender#defaultInstance(java.lang.Object)
+     */
+    public Object defaultInstance(Object bean) throws InstantiationException,
+            IllegalAccessException {
+        if (bean instanceof StandardContext) {
+            StandardContext defaultContext = new StandardContext();
+            /*
+             * if (!((StandardContext) bean).getOverride()) {
+             * defaultContext.setParent(((StandardContext)bean).getParent());
+             * ContextConfig contextConfig = new ContextConfig();
+             * defaultContext.addLifecycleListener(contextConfig);
+             * contextConfig.setContext(defaultContext);
+             * contextConfig.processContextConfig(new File(contextConfig
+             * .getBaseDir(), "conf/context.xml"));
+             * contextConfig.processContextConfig(new File(contextConfig
+             * .getConfigBase(), "context.xml.default")); }
+             */
+            return defaultContext;
+        } else
+            return super.defaultInstance(bean);
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/src/share/org/apache/catalina/storeconfig/StoreDescription.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/src/share/org/apache/catalina/storeconfig/StoreDescription.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/src/share/org/apache/catalina/storeconfig/StoreDescription.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,361 @@
+/*
+ * Copyright 2004-2005 The Apache Software Foundation.
+ * 
+ * Licensed 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.storeconfig;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Bean of a StoreDescription 
+ * @author Peter Rossbach 
+ * 
+ * <pre>
+ * 
+ *  &lt;Description
+ *  tag=&quot;Context&quot;
+ *  standard=&quot;true&quot;
+ *  default=&quot;true&quot; 
+ *  externalAllowed=&quot;true&quot; 
+ *  storeSeparate=&quot;true&quot;
+ *  backup=&quot;true&quot; 
+ *  childs=&quot;true&quot;
+ *  tagClass=&quot;org.apache.catalina.core.StandardContext&quot;
+ *  storeFactoryClass=&quot;org.apache.catalina.storeconfig.StandardContextSF&quot;
+ *  storeAppenderClass=&quot;org.apache.catalina.storeconfig.StoreContextAppender&quot;&gt;
+ *     &lt;TransientAttribute&gt;available&lt;/TransientAttribute&gt;
+ *     &lt;TransientAttribute&gt;configFile&lt;/TransientAttribute&gt;
+ *     &lt;TransientAttribute&gt;configured&lt;/TransientAttribute&gt;
+ *     &lt;TransientAttribute&gt;displayName&lt;/TransientAttribute&gt;
+ *     &lt;TransientAttribute&gt;distributable&lt;/TransientAttribute&gt;
+ *     &lt;TransientAttribute&gt;domain&lt;/TransientAttribute&gt;
+ *     &lt;TransientAttribute&gt;engineName&lt;/TransientAttribute&gt;
+ *     &lt;TransientAttribute&gt;name&lt;/TransientAttribute&gt;
+ *     &lt;TransientAttribute&gt;publicId&lt;/TransientAttribute&gt;
+ *     &lt;TransientAttribute&gt;replaceWelcomeFiles&lt;/TransientAttribute&gt;
+ *     &lt;TransientAttribute&gt;saveConfig&lt;/TransientAttribute&gt;
+ *     &lt;TransientAttribute&gt;sessionTimeout&lt;/TransientAttribute&gt;
+ *     &lt;TransientAttribute&gt;startupTime&lt;/TransientAttribute&gt;
+ *     &lt;TransientAttribute&gt;tldScanTime&lt;/TransientAttribute&gt;
+ *  &lt;/Description&gt;
+ * 
+ *  
+ * </pre>
+ */
+public class StoreDescription {
+
+    private String id;
+
+    private String tag;
+
+    private String tagClass;
+
+    private boolean standard = false;
+
+    private boolean backup = false;
+
+    private boolean externalAllowed = false;
+
+    private boolean myDefault = false;
+
+    private boolean attributes = true;
+
+    private String storeFactoryClass;
+
+    private IStoreFactory storeFactory;
+
+    private String storeWriterClass;
+
+    private boolean childs = false;
+
+    private List transientAttributes;
+
+    private List transientChilds;
+
+    private boolean storeSeparate = false;
+
+    /**
+     * @return Returns the external.
+     */
+    public boolean isExternalAllowed() {
+        return externalAllowed;
+    }
+
+    /**
+     * @param external
+     *            The external to set.
+     */
+    public void setExternalAllowed(boolean external) {
+        this.externalAllowed = external;
+    }
+
+    /**
+     * @return Returns the standard.
+     */
+    public boolean isStandard() {
+        return standard;
+    }
+
+    /**
+     * @param standard
+     *            The standard to set.
+     */
+    public void setStandard(boolean standard) {
+        this.standard = standard;
+    }
+
+    /**
+     * @return Returns the backup.
+     */
+    public boolean isBackup() {
+        return backup;
+    }
+
+    /**
+     * @param backup
+     *            The backup to set.
+     */
+    public void setBackup(boolean backup) {
+        this.backup = backup;
+    }
+
+    /**
+     * @return Returns the myDefault.
+     */
+    public boolean isDefault() {
+        return myDefault;
+    }
+
+    /**
+     * @param aDefault
+     *            The myDefault to set.
+     */
+    public void setDefault(boolean aDefault) {
+        this.myDefault = aDefault;
+    }
+
+    /**
+     * @return Returns the storeFactory.
+     */
+    public String getStoreFactoryClass() {
+        return storeFactoryClass;
+    }
+
+    /**
+     * @param storeFactoryClass
+     *            The storeFactory to set.
+     */
+    public void setStoreFactoryClass(String storeFactoryClass) {
+        this.storeFactoryClass = storeFactoryClass;
+    }
+
+    /**
+     * @return Returns the storeFactory.
+     */
+    public IStoreFactory getStoreFactory() {
+        return storeFactory;
+    }
+
+    /**
+     * @param storeFactory
+     *            The storeFactory to set.
+     */
+    public void setStoreFactory(IStoreFactory storeFactory) {
+        this.storeFactory = storeFactory;
+    }
+
+    /**
+     * @return Returns the storeWriterClass.
+     */
+    public String getStoreWriterClass() {
+        return storeWriterClass;
+    }
+
+    /**
+     * @param storeWriterClass
+     *            The storeWriterClass to set.
+     */
+    public void setStoreWriterClass(String storeWriterClass) {
+        this.storeWriterClass = storeWriterClass;
+    }
+
+    /**
+     * @return Returns the tagClass.
+     */
+    public String getTag() {
+        return tag;
+    }
+
+    /**
+     * @param tag
+     *            The tag to set.
+     */
+    public void setTag(String tag) {
+        this.tag = tag;
+    }
+
+    /**
+     * @return Returns the tagClass.
+     */
+    public String getTagClass() {
+        return tagClass;
+    }
+
+    /**
+     * @param tagClass
+     *            The tagClass to set.
+     */
+    public void setTagClass(String tagClass) {
+        this.tagClass = tagClass;
+    }
+
+    /**
+     * @return Returns the transientAttributes.
+     */
+    public List getTransientAttributes() {
+        return transientAttributes;
+    }
+
+    /**
+     * @param transientAttributes
+     *            The transientAttributes to set.
+     */
+    public void setTransientAttributes(List transientAttributes) {
+        this.transientAttributes = transientAttributes;
+    }
+
+    public void addTransientAttribute(String attribute) {
+        if (transientAttributes == null)
+            transientAttributes = new ArrayList();
+        transientAttributes.add(attribute);
+    }
+
+    public void removeTransientAttribute(String attribute) {
+        if (transientAttributes != null)
+            transientAttributes.remove(attribute);
+    }
+
+    /**
+     * @return Returns the transientChilds.
+     */
+    public List getTransientChilds() {
+        return transientChilds;
+    }
+
+    /**
+     * @param transientChilds
+     *            The transientChilds to set.
+     */
+    public void setTransientChilds(List transientChilds) {
+        this.transientChilds = transientChilds;
+    }
+
+    public void addTransientChild(String classname) {
+        if (transientChilds == null)
+            transientChilds = new ArrayList();
+        transientChilds.add(classname);
+    }
+
+    public void removeTransientChild(String classname) {
+        if (transientChilds != null)
+            transientChilds.remove(classname);
+    }
+
+    /**
+     * is child transient, please don't save this.
+     * 
+     * @param classname
+     * @return is classname attribute?
+     */
+    public boolean isTransientChild(String classname) {
+        if (transientChilds != null)
+            return transientChilds.contains(classname);
+        return false;
+    }
+
+    /**
+     * is attribute transient, please don't save this.
+     * 
+     * @param attribute
+     * @return is transient attribute?
+     */
+    public boolean isTransientAttribute(String attribute) {
+        if (transientAttributes != null)
+            return transientAttributes.contains(attribute);
+        return false;
+    }
+
+    /**
+     * Return the real id or TagClass
+     * 
+     * @return Returns the id.
+     */
+    public String getId() {
+        if (id != null)
+            return id;
+        else
+            return getTagClass();
+    }
+
+    /**
+     * @param id
+     *            The id to set.
+     */
+    public void setId(String id) {
+        this.id = id;
+    }
+
+    /**
+     * @return Returns the attributes.
+     */
+    public boolean isAttributes() {
+        return attributes;
+    }
+
+    /**
+     * @param attributes
+     *            The attributes to set.
+     */
+    public void setAttributes(boolean attributes) {
+        this.attributes = attributes;
+    }
+
+    /**
+     * @return True if it's a separate store
+     */
+    public boolean isStoreSeparate() {
+        return storeSeparate;
+    }
+
+    public void setStoreSeparate(boolean storeSeparate) {
+        this.storeSeparate = storeSeparate;
+    }
+
+    /**
+     * @return Returns the childs.
+     */
+    public boolean isChilds() {
+        return childs;
+    }
+
+    /**
+     * @param childs
+     *            The childs to set.
+     */
+    public void setChilds(boolean childs) {
+        this.childs = childs;
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/src/share/org/apache/catalina/storeconfig/StoreFactoryBase.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/src/share/org/apache/catalina/storeconfig/StoreFactoryBase.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/src/share/org/apache/catalina/storeconfig/StoreFactoryBase.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,195 @@
+/*
+ * Copyright 1999-2001,2004-2006 The Apache Software Foundation.
+ * 
+ * Licensed 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.storeconfig;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+
+import org.apache.catalina.util.StringManager;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * StoreFactory saves spezial elements.
+ * Output was generate with StoreAppenders.
+ * 
+ * @author Peter Rossbach
+ * @version 1.0
+ *  
+ */
+public class StoreFactoryBase implements IStoreFactory {
+    private static Log log = LogFactory.getLog(StoreFactoryBase.class);
+
+    private StoreRegistry registry;
+
+    private StoreAppender storeAppender = new StoreAppender();
+
+    /**
+     * The string manager for this package.
+     */
+    protected static final StringManager sm = StringManager
+            .getManager(Constants.Package);
+
+    /**
+     * The descriptive information string for this implementation.
+     */
+    private static final String info = "org.apache.catalina.config.StoreFactoryBase/1.0";
+
+    /**
+     * Return descriptive information about this Facotry implementation and the
+     * corresponding version number, in the format
+     * <code>&lt;description&gt;/&lt;version&gt;</code>.
+     */
+    public String getInfo() {
+
+        return (info);
+
+    }
+
+    /**
+     * @return Returns the storeAppender.
+     */
+    public StoreAppender getStoreAppender() {
+        return storeAppender;
+    }
+
+    /**
+     * @param storeAppender
+     *            The storeAppender to set.
+     */
+    public void setStoreAppender(StoreAppender storeAppender) {
+        this.storeAppender = storeAppender;
+    }
+
+    /*
+     * set Registry
+     * 
+     * @see org.apache.catalina.config.IStoreFactory#setRegistry(org.apache.catalina.config.ConfigurationRegistry)
+     */
+    public void setRegistry(StoreRegistry aRegistry) {
+        registry = aRegistry;
+
+    }
+
+    /*
+     * get Registry
+     * 
+     * @see org.apache.catalina.config.IStoreFactory#getRegistry()
+     */
+    public StoreRegistry getRegistry() {
+
+        return registry;
+    }
+
+    public void storeXMLHead(PrintWriter aWriter) {
+        // Store the beginning of this element
+        aWriter.print("<?xml version=\"1.0\" encoding=\"");
+        aWriter.print(getRegistry().getEncoding());
+        aWriter.println("\"?>");
+    }
+
+    /*
+     * Store a server.xml element with attributes and childs
+     * 
+     * @see org.apache.catalina.storeconfig.IStoreFactory#store(java.io.PrintWriter,
+     *      int, java.lang.Object)
+     */
+    public void store(PrintWriter aWriter, int indent, Object aElement)
+            throws Exception {
+
+        StoreDescription elementDesc = getRegistry().findDescription(
+                aElement.getClass());
+
+        if (elementDesc != null) {
+            if (log.isDebugEnabled())
+                log.debug(sm.getString("factory.storeTag",
+                        elementDesc.getTag(), aElement));
+            getStoreAppender().printIndent(aWriter, indent + 2);
+            if (!elementDesc.isChilds()) {
+                getStoreAppender().printTag(aWriter, indent, aElement,
+                        elementDesc);
+            } else {
+                getStoreAppender().printOpenTag(aWriter, indent + 2, aElement,
+                        elementDesc);
+                storeChilds(aWriter, indent + 2, aElement, elementDesc);
+                getStoreAppender().printIndent(aWriter, indent + 2);
+                getStoreAppender().printCloseTag(aWriter, elementDesc);
+            }
+        } else
+            log.warn(sm.getString("factory.storeNoDescriptor", aElement
+                    .getClass()));
+    }
+
+    /**
+     * Must Implement at subclass for sepzial store childs handling
+     * 
+     * @param aWriter
+     * @param indent
+     * @param aElement
+     * @param elementDesc
+     */
+    public void storeChilds(PrintWriter aWriter, int indent, Object aElement,
+            StoreDescription elementDesc) throws Exception {
+    }
+
+    /**
+     * Store only elements from storeChilds methods that are not a transient
+     * child.
+     * 
+     * @param aWriter current output writer
+     * @param indent indentation level
+     * @param aTagElement current tomcat element
+     * @throws Exception
+     */
+    protected void storeElement(PrintWriter aWriter, int indent,
+            Object aTagElement) throws Exception {
+        if (aTagElement != null) {
+            IStoreFactory elementFactory = getRegistry().findStoreFactory(
+                    aTagElement.getClass());
+
+            if (elementFactory != null) {
+                StoreDescription desc = getRegistry().findDescription(
+                        aTagElement.getClass());
+                if (!desc.isTransientChild(aTagElement.getClass().getName()))
+                    elementFactory.store(aWriter, indent, aTagElement);
+            } else {
+                log.warn(sm.getString("factory.storeNoDescriptor", aTagElement
+                        .getClass()));
+            }
+        }
+    }
+
+    /*
+     * Save a array of elements
+     * @param aWriter current output writer
+     * @param indent indentation level
+     * @param elements list of child elments to store!
+     */
+    protected void storeElementArray(PrintWriter aWriter, int indent,
+            Object[] elements) throws Exception {
+        if (elements != null) {
+            for (int i = 0; i < elements.length; i++) {
+                try {
+                    storeElement(aWriter, indent, elements[i]);
+                } catch (IOException ioe) {
+                    // ingore childs report error them self!
+                    // see StandartContext.storeWithBackup()
+                }
+            }
+        }
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/src/share/org/apache/catalina/storeconfig/StoreFactoryRule.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/src/share/org/apache/catalina/storeconfig/StoreFactoryRule.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/src/share/org/apache/catalina/storeconfig/StoreFactoryRule.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,124 @@
+/*
+ * Copyright 1999-2001,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.storeconfig;
+
+import org.apache.tomcat.util.digester.Rule;
+import org.xml.sax.Attributes;
+
+/**
+ * <p>
+ * Rule that creates a new <code>IStoreFactory</code> instance, and associates
+ * it with the top object on the stack (which must implement
+ * <code>IStoreFactory</code>).
+ * </p>
+ * 
+ * @author Peter Rossbach
+ */
+
+public class StoreFactoryRule extends Rule {
+
+    // ----------------------------------------------------------- Constructors
+
+    /**
+     * Construct a new instance of this Rule.
+     * 
+     * @param storeFactoryClass
+     *            Default name of the StoreFactory implementation class to be
+     *            created
+     * @param attributeName
+     *            Name of the attribute that optionally includes an override
+     *            name of the IStoreFactory class
+     */
+    public StoreFactoryRule(String storeFactoryClass, String attributeName,
+            String storeAppenderClass, String appenderAttributeName) {
+
+        this.storeFactoryClass = storeFactoryClass;
+        this.attributeName = attributeName;
+        this.appenderAttributeName = appenderAttributeName;
+        this.storeAppenderClass = storeAppenderClass;
+
+    }
+
+    // ----------------------------------------------------- Instance Variables
+
+    /**
+     * The attribute name of an attribute that can override the implementation
+     * class name.
+     */
+    private String attributeName;
+
+    private String appenderAttributeName;
+
+    /**
+     * The name of the <code>IStoreFactory</code> implementation class.
+     */
+    private String storeFactoryClass;
+
+    private String storeAppenderClass;
+
+    // --------------------------------------------------------- Public Methods
+
+    /**
+     * Handle the beginning of an XML element.
+     * 
+     * @param attributes
+     *            The attributes of this element
+     * 
+     * @exception Exception
+     *                if a processing error occurs
+     */
+    public void begin(String namespace, String name, Attributes attributes)
+            throws Exception {
+
+        IStoreFactory factory = (IStoreFactory) newInstance(attributeName,
+                storeFactoryClass, attributes);
+        StoreAppender storeAppender = (StoreAppender) newInstance(
+                appenderAttributeName, storeAppenderClass, attributes);
+        factory.setStoreAppender(storeAppender);
+
+        // Add this StoreFactory to our associated component
+        StoreDescription desc = (StoreDescription) digester.peek(0);
+        StoreRegistry registry = (StoreRegistry) digester.peek(1);
+        factory.setRegistry(registry);
+        desc.setStoreFactory(factory);
+
+    }
+
+    /**
+     * create new instance from attribte className!
+     * 
+     * @param attr class Name attribute
+     * @param defaultName Default Class
+     * @param attributes current digester attribute elements
+     * @return new config object instance
+     * @throws ClassNotFoundException
+     * @throws InstantiationException
+     * @throws IllegalAccessException
+     */
+    protected Object newInstance(String attr, String defaultName,
+            Attributes attributes) throws ClassNotFoundException,
+            InstantiationException, IllegalAccessException {
+        String className = defaultName;
+        if (attr != null) {
+            String value = attributes.getValue(attr);
+            if (value != null)
+                className = value;
+        }
+        Class clazz = Class.forName(className);
+        return clazz.newInstance();
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/src/share/org/apache/catalina/storeconfig/StoreFileMover.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/src/share/org/apache/catalina/storeconfig/StoreFileMover.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/src/share/org/apache/catalina/storeconfig/StoreFileMover.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,222 @@
+/*
+ * Copyright 2004-2005 The Apache Software Foundation.
+ * 
+ * Licensed 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.storeconfig;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+import java.sql.Timestamp;
+
+/**
+ * Move server.xml or context.xml as backup
+ * 
+ * @author Peter Rossbach
+ * 
+ * TODO Get Encoding from Registry
+ */
+public class StoreFileMover {
+
+    private String filename = "conf/server.xml";
+
+    private String encoding = "UTF-8";
+
+    private String basename = System.getProperty("catalina.base");
+
+    private File configOld;
+
+    private File configNew;
+
+    private File configSave;
+
+    /**
+     * @return Returns the configNew.
+     */
+    public File getConfigNew() {
+        return configNew;
+    }
+
+    /**
+     * @return Returns the configOld.
+     */
+    public File getConfigOld() {
+        return configOld;
+    }
+
+    /**
+     * @return Returns the configSave.
+     */
+    public File getConfigSave() {
+        return configSave;
+    }
+
+    /**
+     * @return Returns the basename.
+     */
+    public String getBasename() {
+        return basename;
+    }
+
+    /**
+     * @param basename
+     *            The basename to set.
+     */
+    public void setBasename(String basename) {
+        this.basename = basename;
+    }
+
+    /**
+     * @return The file name
+     */
+    public String getFilename() {
+        return filename;
+    }
+
+    /**
+     * @param string
+     */
+    public void setFilename(String string) {
+        filename = string;
+    }
+
+    /**
+     * @return The encoding
+     */
+    public String getEncoding() {
+        return encoding;
+    }
+
+    /**
+     * @param string
+     */
+    public void setEncoding(String string) {
+        encoding = string;
+    }
+
+    /**
+     * Calculate file objects for the old and new configuration files.
+     */
+    public StoreFileMover(String basename, String filename, String encoding) {
+        setBasename(basename);
+        setEncoding(encoding);
+        setFilename(filename);
+        init();
+    }
+
+    /**
+     * Calculate file objects for the old and new configuration files.
+     */
+    public StoreFileMover() {
+        init();
+    }
+
+    /**
+     * generate the Filename to new with TimeStamp
+     */
+    public void init() {
+        String configFile = getFilename();
+        configOld = new File(configFile);
+        if (!configOld.isAbsolute()) {
+            configOld = new File(getBasename(), configFile);
+        }
+        configNew = new File(configFile + ".new");
+        if (!configNew.isAbsolute()) {
+            configNew = new File(getBasename(), configFile + ".new");
+        }
+        if (!configNew.getParentFile().exists()) {
+            configNew.getParentFile().mkdirs();
+        }
+        String sb = getTimeTag();
+        configSave = new File(configFile + sb);
+        if (!configSave.isAbsolute()) {
+            configSave = new File(getBasename(), configFile + sb);
+        }
+    }
+
+    /**
+     * Shuffle old->save and new->old
+     * 
+     * @throws IOException
+     */
+    public void move() throws IOException {
+        if (configOld.renameTo(configSave)) {
+            if (!configNew.renameTo(configOld)) {
+                configSave.renameTo(configOld);
+                throw new IOException("Cannot rename "
+                        + configNew.getAbsolutePath() + " to "
+                        + configOld.getAbsolutePath());
+            }
+        } else {
+            if (!configOld.exists()) {
+                if (!configNew.renameTo(configOld)) {
+                    throw new IOException("Cannot move "
+                            + configNew.getAbsolutePath() + " to "
+                            + configOld.getAbsolutePath());
+                }
+            } else {
+                throw new IOException("Cannot rename "
+                    + configOld.getAbsolutePath() + " to "
+                    + configSave.getAbsolutePath());
+            }
+        }
+    }
+
+    /**
+     * Open an output writer for the new configuration file
+     * 
+     * @return The writer
+     * @throws IOException
+     */
+    public PrintWriter getWriter() throws IOException {
+        PrintWriter writer = null;
+        try {
+            writer = new PrintWriter(new OutputStreamWriter(
+                    new FileOutputStream(configNew), getEncoding()));
+        } catch (IOException e) {
+            if (writer != null) {
+                try {
+                    writer.close();
+                } catch (Throwable t) {
+                    ;
+                }
+            }
+            throw (e);
+        }
+        return writer;
+    }
+
+    /**
+     * Time value for backup yyyy-mm-dd.hh-mm-ss
+     * 
+     * @return The time
+     */
+    protected String getTimeTag() {
+        String ts = (new Timestamp(System.currentTimeMillis())).toString();
+        //        yyyy-mm-dd hh:mm:ss
+        //        0123456789012345678
+        StringBuffer sb = new StringBuffer(".");
+        sb.append(ts.substring(0, 10));
+        sb.append('.');
+        sb.append(ts.substring(11, 13));
+        sb.append('-');
+        sb.append(ts.substring(14, 16));
+        sb.append('-');
+        sb.append(ts.substring(17, 19));
+        return sb.toString();
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/src/share/org/apache/catalina/storeconfig/StoreLoader.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/src/share/org/apache/catalina/storeconfig/StoreLoader.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/src/share/org/apache/catalina/storeconfig/StoreLoader.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,287 @@
+/*
+ * Copyright 2004-2005 The Apache Software Foundation.
+ * 
+ * Licensed 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.storeconfig;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.tomcat.util.digester.Digester;
+import org.xml.sax.SAXException;
+
+/**
+ * 
+ * @author Peter Rossbach
+ * 
+ * <b>XML Format </b>
+ * 
+ * <pre>
+ *    
+ *       &lt;Registry name=&quot;&quot; encoding=&quot;UTF8&quot; &gt;
+ *       &lt;Description tag=&quot;Server&quot; standard=&quot;true&quot; default=&quot;true&quot;/&gt; 
+ *          tagClass=&quot;org.apache.catalina.core.StandardServer&quot;
+ *          storeFactory=&quot;org.apache.catalina.storeconfig.StandardServerSF&quot;&gt;
+ *        &lt;TransientAttributes&gt;
+ *          &lt;Attribute&gt;&lt;/Attribute&gt;
+ *        &lt;/TransientAttributes&gt;
+ *        &lt;TransientChilds&gt;
+ *          &lt;Child&gt;&lt;/Child&gt;
+ *        &lt;/TransientChilds&gt;
+ *       &lt;/Description&gt;
+ *   ...
+ *       &lt;/Tegistry&gt;
+ *     
+ * </pre>
+ * 
+ * 
+ * Convention:
+ * <ul>
+ * <li>Factories at subpackage <i>org.apache.catalina.core.storeconfig.xxxSF
+ * </i>.</li>
+ * <li>Element name are the unique Class name</li>
+ * <li>SF for StoreFactory</li>
+ * <li>standard implementation is false</li>
+ * </ul>
+ * other things:
+ * <ul>
+ * <li>Registry XML format is a very good option</li>
+ * <li>Store format is not fix</li>
+ * <li>We hope with the parent declaration we can build recursive child store
+ * operation //dream</li>
+ * <li>Problem is to access child data from array,collections or normal detail
+ * object</li>
+ * <li>Default definitions for Listener, Valve Resource? - Based on interface
+ * type!</li>
+ * </ul>
+ */
+public class StoreLoader {
+    private static Log log = LogFactory.getLog(StoreLoader.class);
+
+    /**
+     * The <code>Digester</code> instance used to parse registry descriptors.
+     */
+    protected static Digester digester = createDigester();
+
+    private StoreRegistry registry;
+    
+    private URL registryResource ;
+
+    /**
+     * @return Returns the registry.
+     */
+    public StoreRegistry getRegistry() {
+        return registry;
+    }
+
+    /**
+     * @param registry
+     *            The registry to set.
+     */
+    public void setRegistry(StoreRegistry registry) {
+        this.registry = registry;
+    }
+
+    /**
+     * Create and configure the Digester we will be using for setup store
+     * registry.
+     */
+    protected static Digester createDigester() {
+        long t1 = System.currentTimeMillis();
+        // Initialize the digester
+        Digester digester = new Digester();
+        digester.setValidating(false);
+        digester.setClassLoader(StoreRegistry.class.getClassLoader());
+
+        // Configure the actions we will be using
+        digester.addObjectCreate("Registry",
+                "org.apache.catalina.storeconfig.StoreRegistry", "className");
+        digester.addSetProperties("Registry");
+        digester
+                .addObjectCreate("Registry/Description",
+                        "org.apache.catalina.storeconfig.StoreDescription",
+                        "className");
+        digester.addSetProperties("Registry/Description");
+        digester.addRule("Registry/Description", new StoreFactoryRule(
+                "org.apache.catalina.storeconfig.StoreFactoryBase",
+                "storeFactoryClass",
+                "org.apache.catalina.storeconfig.StoreAppender",
+                "storeAppenderClass"));
+        digester.addSetNext("Registry/Description", "registerDescription",
+                "org.apache.catalina.storeconfig.StoreDescription");
+        digester.addCallMethod("Registry/Description/TransientAttribute",
+                "addTransientAttribute", 0);
+        digester.addCallMethod("Registry/Description/TransientChild",
+                "addTransientChild", 0);
+
+        long t2 = System.currentTimeMillis();
+        if (log.isDebugEnabled())
+            log.debug("Digester for server-registry.xml created " + (t2 - t1));
+        return (digester);
+
+    }
+
+    /**
+     * 
+     * @param aFile
+     * @return The server file
+     */
+    protected File serverFile(String aFile) {
+
+        if (aFile == null || (aFile != null && aFile.length() < 1))
+            aFile = "server-registry.xml";
+        File file = new File(aFile);
+        if (!file.isAbsolute())
+            file = new File(System.getProperty("catalina.base") + "/conf",
+                    aFile);
+        try {
+            file = file.getCanonicalFile();
+        } catch (IOException e) {
+            log.error(e);
+        }
+        return (file);
+    }
+
+    /**
+     * Load Description from external source
+     * 
+     * @param aURL
+     */
+    public void load(String aURL) {
+        synchronized (digester) {
+            File aRegistryFile = serverFile(aURL);
+            try {
+                registry = (StoreRegistry) digester.parse(aRegistryFile);
+                registryResource = aRegistryFile.toURL();
+            } catch (IOException e) {
+                log.error(e);
+            } catch (SAXException e) {
+                log.error(e);
+            }
+        }
+
+    }
+
+    /**
+     * Load from defaults
+     * <ul>
+     * <li>System Property URL catalina.storeregistry</li>
+     * <li>File $catalina.base/conf/server-registry.xml</li>
+     * <li>class resource org/apache/catalina/storeconfig/server-registry.xml
+     * </li>
+     * </ul>
+     */
+    public void load() {
+
+        InputStream is = null;
+        Throwable error = null;
+        registryResource = null ;
+        try {
+            String configUrl = getConfigUrl();
+            if (configUrl != null) {
+                is = (new URL(configUrl)).openStream();
+                if (log.isInfoEnabled())
+                    log
+                            .info("Find registry server-registry.xml from system property at url "
+                                    + configUrl);
+                ;
+                registryResource = new URL(configUrl);
+            }
+        } catch (Throwable t) {
+            // Ignore
+        }
+        if (is == null) {
+            try {
+                File home = new File(getCatalinaBase());
+                File conf = new File(home, "conf");
+                File reg = new File(conf, "server-registry.xml");
+                is = new FileInputStream(reg);
+                if (log.isInfoEnabled())
+                    log.info("Find registry server-registry.xml at file "
+                            + reg.getCanonicalPath());
+                ;
+                registryResource = reg.toURL() ;
+            } catch (Throwable t) {
+                // Ignore
+            }
+        }
+        if (is == null) {
+            try {
+                is = StoreLoader.class
+                        .getResourceAsStream("/org/apache/catalina/storeconfig/server-registry.xml");
+                if (log.isInfoEnabled())
+                    log
+                            .info("Find registry server-registry.xml at classpath resource");
+                registryResource = StoreLoader.class
+                    .getResource("/org/apache/catalina/storeconfig/server-registry.xml");
+                
+            } catch (Throwable t) {
+                // Ignore
+            }
+        }
+        if (is != null) {
+            try {
+                synchronized (digester) {
+                    registry = (StoreRegistry) digester.parse(is);
+                }
+            } catch (Throwable t) {
+                error = t;
+            } finally {
+                try {
+                    is.close();
+                } catch (IOException e) {
+                }
+            }
+        }
+        if ((is == null) || (error != null)) {
+            log.error(error);
+        }
+    }
+
+    /**
+     * Get the value of the catalina.home environment variable.
+     */
+    private static String getCatalinaHome() {
+        return System.getProperty("catalina.home", System
+                .getProperty("user.dir"));
+    }
+
+    /**
+     * Get the value of the catalina.base environment variable.
+     */
+    private static String getCatalinaBase() {
+        return System.getProperty("catalina.base", getCatalinaHome());
+    }
+
+    /**
+     * Get the value of the configuration URL.
+     */
+    private static String getConfigUrl() {
+        return System.getProperty("catalina.storeconfig");
+    }
+    
+    
+
+    /**
+     * @return Returns the registryResource.
+     */
+    public URL getRegistryResource() {
+        return registryResource;
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/src/share/org/apache/catalina/storeconfig/StoreRegistry.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/src/share/org/apache/catalina/storeconfig/StoreRegistry.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/src/share/org/apache/catalina/storeconfig/StoreRegistry.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,202 @@
+/*
+ * Copyright 2004-2005 The Apache Software Foundation.
+ * 
+ * Licensed 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.storeconfig;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.naming.directory.DirContext;
+
+import org.apache.catalina.LifecycleListener;
+import org.apache.catalina.Manager;
+import org.apache.catalina.Realm;
+import org.apache.catalina.Valve;
+import org.apache.catalina.cluster.CatalinaCluster;
+import org.apache.catalina.cluster.ClusterDeployer;
+import org.apache.catalina.cluster.ClusterReceiver;
+import org.apache.catalina.cluster.ClusterSender;
+import org.apache.catalina.cluster.MembershipService;
+import org.apache.catalina.cluster.MessageListener;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * Central StoreRegistry for all server.xml elements
+ * 
+ * @author Peter Rossbach
+ *  
+ */
+public class StoreRegistry {
+    private static Log log = LogFactory.getLog(StoreRegistry.class);
+
+    private Map descriptors = new HashMap();
+
+    private String encoding = "UTF-8";
+
+    private String name;
+
+    private String version;
+
+    // Access Information
+    private static Class interfaces[] = { CatalinaCluster.class,
+            ClusterSender.class, ClusterReceiver.class,
+            MembershipService.class, ClusterDeployer.class, Realm.class,
+            Manager.class, DirContext.class, LifecycleListener.class,
+            Valve.class, MessageListener.class };
+
+    /**
+     * @return Returns the name.
+     */
+    public String getName() {
+        return name;
+    }
+
+    /**
+     * @param name
+     *            The name to set.
+     */
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    /**
+     * @return Returns the version.
+     */
+    public String getVersion() {
+        return version;
+    }
+
+    /**
+     * @param version
+     *            The version to set.
+     */
+    public void setVersion(String version) {
+        this.version = version;
+    }
+
+    /**
+     * Find a description for id. Handle interface search when no direct match
+     * found.
+     * 
+     * @param id
+     * @return The description
+     */
+    public StoreDescription findDescription(String id) {
+        if (log.isDebugEnabled())
+            log.debug("search descriptor " + id);
+        StoreDescription desc = (StoreDescription) descriptors.get(id);
+        if (desc == null) {
+            Class aClass = null;
+            try {
+                aClass = Class.forName(id, true, this.getClass()
+                        .getClassLoader());
+            } catch (ClassNotFoundException e) {
+                log.error("ClassName:" + id, e);
+            }
+            if (aClass != null) {
+                desc = (StoreDescription) descriptors.get(aClass.getName());
+                for (int i = 0; desc == null && i < interfaces.length; i++) {
+                    if (interfaces[i].isAssignableFrom(aClass)) {
+                        desc = (StoreDescription) descriptors.get(interfaces[i]
+                                .getName());
+                    }
+                }
+            }
+        }
+        if (log.isDebugEnabled())
+            if (desc != null)
+                log.debug("find descriptor " + id + "#" + desc.getTag() + "#"
+                        + desc.getStoreFactoryClass());
+            else
+                log.debug(("Can't find descriptor for key " + id));
+        return desc;
+    }
+
+    /**
+     * Find Description by class
+     * 
+     * @param aClass
+     * @return The description
+     */
+    public StoreDescription findDescription(Class aClass) {
+        return findDescription(aClass.getName());
+    }
+
+    /**
+     * Find factory from classname
+     * 
+     * @param aClassName
+     * @return The factory
+     */
+    public IStoreFactory findStoreFactory(String aClassName) {
+        StoreDescription desc = findDescription(aClassName);
+        if (desc != null)
+            return desc.getStoreFactory();
+        else
+            return null;
+
+    }
+
+    /**
+     * find factory from class
+     * 
+     * @param aClass
+     * @return The factory
+     */
+    public IStoreFactory findStoreFactory(Class aClass) {
+        return findStoreFactory(aClass.getName());
+    }
+
+    /**
+     * Register a new description
+     * 
+     * @param desc
+     */
+    public void registerDescription(StoreDescription desc) {
+        String key = desc.getId();
+        if (key == null || "".equals(key))
+            key = desc.getTagClass();
+        descriptors.put(key, desc);
+        if (log.isDebugEnabled())
+            log.debug("register store descriptor " + key + "#" + desc.getTag()
+                    + "#" + desc.getTagClass());
+    }
+
+    public StoreDescription unregisterDescription(StoreDescription desc) {
+        String key = desc.getId();
+        if (key == null || "".equals(key))
+            key = desc.getTagClass();
+        return (StoreDescription) descriptors.remove(key);
+    }
+
+    // Attributes
+
+    /**
+     * @return The encoding
+     */
+    public String getEncoding() {
+        return encoding;
+    }
+
+    /**
+     * @param string
+     */
+    public void setEncoding(String string) {
+        encoding = string;
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/src/share/org/apache/catalina/storeconfig/WatchedResourceSF.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/src/share/org/apache/catalina/storeconfig/WatchedResourceSF.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/src/share/org/apache/catalina/storeconfig/WatchedResourceSF.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,56 @@
+/*
+ * Copyright 1999-2001,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.storeconfig;
+
+import java.io.PrintWriter;
+
+import org.apache.catalina.core.StandardContext;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * @author Peter Rossbach
+ *  
+ */
+public class WatchedResourceSF extends StoreFactoryBase {
+    private static Log log = LogFactory.getLog(WatchedResourceSF.class);
+
+    /*
+     * Store nested Element Value Arrays WatchedResource
+     * 
+     * @see org.apache.catalina.config.IStoreFactory#store(java.io.PrintWriter,
+     *      int, java.lang.Object)
+     */
+    public void store(PrintWriter aWriter, int indent, Object aElement)
+            throws Exception {
+        if (aElement instanceof StandardContext) {
+            StoreDescription elementDesc = getRegistry().findDescription(
+                    aElement.getClass().getName() + ".[WatchedResource]");
+            String[] resources = ((StandardContext) aElement)
+                    .findWatchedResources();
+            if (elementDesc != null) {
+                if (log.isDebugEnabled())
+                    log.debug("store " + elementDesc.getTag() + "( " + aElement
+                            + " )");
+                getStoreAppender().printTagArray(aWriter, "WatchedResource",
+                        indent, resources);
+            }
+        } else
+            log.warn("Descriptor for element" + aElement.getClass()
+                    + ".[WatchedResource] not configured!");
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/src/share/org/apache/catalina/storeconfig/WrapperLifecycleSF.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/src/share/org/apache/catalina/storeconfig/WrapperLifecycleSF.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/src/share/org/apache/catalina/storeconfig/WrapperLifecycleSF.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,56 @@
+/*
+ * Copyright 1999-2001,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.storeconfig;
+
+import java.io.PrintWriter;
+
+import org.apache.catalina.core.StandardContext;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * @author Peter Rossbach
+ *  
+ */
+public class WrapperLifecycleSF extends StoreFactoryBase {
+    private static Log log = LogFactory.getLog(WrapperLifecycleSF.class);
+
+    /*
+     * Store nested Element Value Arrays
+     * 
+     * @see org.apache.catalina.config.IStoreFactory#store(java.io.PrintWriter,
+     *      int, java.lang.Object)
+     */
+    public void store(PrintWriter aWriter, int indent, Object aElement)
+            throws Exception {
+        if (aElement instanceof StandardContext) {
+            StoreDescription elementDesc = getRegistry().findDescription(
+                    aElement.getClass().getName() + ".[WrapperLifecycle]");
+            String[] listeners = ((StandardContext) aElement)
+                    .findWrapperLifecycles();
+            if (elementDesc != null) {
+                if (log.isDebugEnabled())
+                    log.debug("store " + elementDesc.getTag() + "( " + aElement
+                            + " )");
+                getStoreAppender().printTagArray(aWriter, "WrapperLifecycle",
+                        indent, listeners);
+            }
+        } else
+            log.warn("Descriptor for element" + aElement.getClass()
+                    + ".[WrapperLifecycle] not configured!");
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/src/share/org/apache/catalina/storeconfig/WrapperListenerSF.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/src/share/org/apache/catalina/storeconfig/WrapperListenerSF.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/src/share/org/apache/catalina/storeconfig/WrapperListenerSF.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,56 @@
+/*
+ * Copyright 1999-2001,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.storeconfig;
+
+import java.io.PrintWriter;
+
+import org.apache.catalina.core.StandardContext;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * @author Peter Rossbach (pero at apache.org)
+ *  
+ */
+public class WrapperListenerSF extends StoreFactoryBase {
+    private static Log log = LogFactory.getLog(WrapperListenerSF.class);
+
+    /*
+     * Store nested Element Value Arrays
+     * 
+     * @see org.apache.catalina.config.IStoreFactory#store(java.io.PrintWriter,
+     *      int, java.lang.Object)
+     */
+    public void store(PrintWriter aWriter, int indent, Object aElement)
+            throws Exception {
+        if (aElement instanceof StandardContext) {
+            StoreDescription elementDesc = getRegistry().findDescription(
+                    aElement.getClass().getName() + ".[WrapperListener]");
+            String[] listeners = ((StandardContext) aElement)
+                    .findWrapperListeners();
+            if (elementDesc != null) {
+                if (log.isDebugEnabled())
+                    log.debug("store " + elementDesc.getTag() + "( " + aElement
+                            + " )");
+                getStoreAppender().printTagArray(aWriter, "WrapperListener",
+                        indent, listeners);
+            }
+        } else
+            log.warn("Descriptor for element" + aElement.getClass()
+                    + ".[WrapperListener] not configured!");
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/src/share/org/apache/catalina/storeconfig/mbeans-descriptors.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/src/share/org/apache/catalina/storeconfig/mbeans-descriptors.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/src/share/org/apache/catalina/storeconfig/mbeans-descriptors.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,77 @@
+<?xml version="1.0"?>
+<mbeans-descriptors>
+
+  <mbean         name="StoreConfig"
+          description="Implementation of a store server.xml config"
+               domain="Catalina"
+                group="StoreConfig"
+                 type="org.apache.catalina.storeconfig.StoreConfig">
+    <operation name="storeConfig" 
+               description="Store Server" 
+               impact="ACTION" returnType="void" />
+    <operation name="storeServer" 
+               description="Store Server from ObjectName" 
+               impact="ACTION" returnType="void" >
+         <parameter name="objectname"
+                 description="Objectname from Server"
+                 type="java.lang.String"
+                 default="Catalina:type=Server"/>
+         <parameter name="backup"
+                 description="store Context with backup"
+                 type="boolean"/>
+         <parameter name="externalAllowed"
+                 description="store all Context external that have a configFile"
+                 type="boolean"/>
+    </operation>
+
+<!--
+   Catalina:j2eeType=WebModule,name=//localhost/manager,J2EEApplication=none,J2EEServer=none
+-->
+   <operation name="storeContext" 
+               description="Store Context from ObjectName" 
+               impact="ACTION" returnType="void" >
+         <parameter name="objectname"
+                 description="ObjectName from Context"
+                 type="java.lang.String"/>
+         <parameter name="backup"
+                 description="store with Backup"
+                 type="boolean"/>
+         <parameter name="externalAllowed"
+                 description="store all or store only internal server.xml context (configFile == null)"
+                 type="boolean"/>
+    </operation>           
+    <operation name="store" 
+               description="Store Server" 
+               impact="ACTION" returnType="void" >
+          <parameter name="server"
+                 description="Server"
+                 type="org.apache.catalina.Server"
+                 />
+    </operation>           
+    <operation name="store" 
+               description="Store Context" 
+               impact="ACTION" returnType="void" >
+          <parameter name="context"
+                 description="Context"
+                 type="org.apache.catalina.context"/>
+    </operation>           
+    <operation name="store" 
+               description="Store Host" 
+               impact="ACTION" returnType="void" >
+          <parameter name="host"
+                 description="Host"
+                 type="org.apache.catalina.Host"/>
+    </operation>           
+    <operation name="store" 
+               description="Store Service" 
+               impact="ACTION" returnType="void" >
+          <parameter name="service"
+                 description="service"
+                 type="org.apache.catalina.Service"/>
+    </operation>           
+ 
+  </mbean>
+
+</mbeans-descriptors>
+
+

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/src/share/org/apache/catalina/storeconfig/server-registry.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/src/share/org/apache/catalina/storeconfig/server-registry.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/src/share/org/apache/catalina/storeconfig/server-registry.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,340 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Registry name="Tomcat" version="5.5.18" encoding="UTF-8" >
+     <Description
+	    tag="Server"
+		standard="true"
+		default="true" 
+		externalAllowed="true" 
+        childs="true"
+        tagClass="org.apache.catalina.core.StandardServer"
+        storeFactoryClass="org.apache.catalina.storeconfig.StandardServerSF">
+     </Description>
+     <Description
+	    tag="Service"
+		standard="true"
+		default="true" 
+        childs="true"
+        tagClass="org.apache.catalina.core.StandardService"
+        storeFactoryClass="org.apache.catalina.storeconfig.StandardServiceSF">
+     </Description>
+     <Description
+	    tag="Engine"
+		standard="true"
+		default="true" 
+        childs="true"
+        tagClass="org.apache.catalina.core.StandardEngine"
+        storeFactoryClass="org.apache.catalina.storeconfig.StandardEngineSF">
+	    <TransientAttribute>domain</TransientAttribute>
+     </Description>
+     <Description
+	    tag="Host"
+		standard="true"
+		default="true" 
+        childs="true"
+        tagClass="org.apache.catalina.core.StandardHost"
+        storeFactoryClass="org.apache.catalina.storeconfig.StandardHostSF">
+	    <TransientAttribute>domain</TransientAttribute>
+     </Description>
+     <Description
+	    tag="Context"
+		standard="true"
+		default="true" 
+		externalAllowed="true" 
+ 		storeSeparate="true"
+		backup="true" 
+        childs="true"
+        tagClass="org.apache.catalina.core.StandardContext"
+        storeFactoryClass="org.apache.catalina.storeconfig.StandardContextSF"
+        storeAppenderClass="org.apache.catalina.storeconfig.StoreContextAppender">
+	    <TransientAttribute>available</TransientAttribute>
+	    <TransientAttribute>configFile</TransientAttribute>
+	    <TransientAttribute>configured</TransientAttribute>
+	    <TransientAttribute>displayName</TransientAttribute>
+	    <TransientAttribute>distributable</TransientAttribute>
+	    <TransientAttribute>domain</TransientAttribute>
+	    <TransientAttribute>engineName</TransientAttribute>
+	    <TransientAttribute>name</TransientAttribute>
+	    <TransientAttribute>publicId</TransientAttribute>
+	    <TransientAttribute>originalDocBase</TransientAttribute>	    
+	    <TransientAttribute>replaceWelcomeFiles</TransientAttribute>
+	    <TransientAttribute>saveConfig</TransientAttribute>
+	    <TransientAttribute>sessionTimeout</TransientAttribute>
+	    <TransientAttribute>startupTime</TransientAttribute>
+	    <TransientAttribute>tldScanTime</TransientAttribute>
+     </Description>
+     <Description
+        id="org.apache.catalina.deploy.NamingResources.[GlobalNamingResources]"
+	    tag="GlobalNamingResources"
+		standard="true"
+		default="false"
+		attributes="false"
+        childs="true"
+        tagClass="org.apache.catalina.deploy.NamingResources"
+        storeFactoryClass="org.apache.catalina.storeconfig.GlobalNamingResourcesSF">
+     </Description>
+      <Description
+	    tag="Connector"
+		standard="true"
+		default="true" 
+        tagClass="org.apache.catalina.connector.Connector"
+        childs="true"
+        storeFactoryClass="org.apache.catalina.storeconfig.ConnectorSF"
+        storeAppenderClass="org.apache.catalina.storeconfig.ConnectorStoreAppender">
+	    <TransientAttribute>URIEncoding</TransientAttribute>
+	    <TransientAttribute>maxProcessor</TransientAttribute>
+ 	    <TransientAttribute>minProcessor</TransientAttribute>
+     </Description>
+     <Description
+	    tag="NamingResources"
+		standard="true"
+		default="false"
+		attributes="false"
+        childs="true"
+        tagClass="org.apache.catalina.deploy.NamingResources"
+        storeFactoryClass="org.apache.catalina.storeconfig.NamingResourcesSF">
+     </Description>
+	 <Description
+	    tag="Manager"
+		standard="false"
+		default="false" 
+		tagClass="org.apache.catalina.Manager"
+        storeFactoryClass="org.apache.catalina.storeconfig.ManagerSF">
+	    <TransientAttribute>entropy</TransientAttribute>
+	    <TransientAttribute>distributable</TransientAttribute>
+        <TransientChild>org.apache.catalina.cluster.session.DeltaManager</TransientChild>
+        <TransientChild>org.apache.catalina.cluster.session.SimpleTcpReplicationManager</TransientChild>
+    </Description>
+    <Description
+	    tag="Manager"
+		standard="false"
+		default="false" 
+        childs="true"
+		tagClass="org.apache.catalina.session.PersistentManager"
+        storeFactoryClass="org.apache.catalina.storeconfig.PersistentManagerSF">
+        <TransientAttribute>entropy</TransientAttribute>
+	    <TransientAttribute>distributable</TransientAttribute>
+     </Description>
+     <Description
+	    tag="Store"
+		standard="false"
+		default="false" 
+		tagClass="org.apache.catalina.session.FileStore"
+        storeFactoryClass="org.apache.catalina.storeconfig.StoreFactoryBase">
+     </Description>
+     <Description
+	    tag="Store"
+		standard="false"
+		default="false" 
+		tagClass="org.apache.catalina.session.JDBCStore"
+        storeFactoryClass="org.apache.catalina.storeconfig.StoreFactoryBase">
+     </Description>
+     <Description
+	    tag="Cluster"
+		standard="false"
+		default="false" 
+        childs="true"
+		tagClass="org.apache.catalina.cluster.CatalinaCluster"
+        storeFactoryClass="org.apache.catalina.storeconfig.CatalinaClusterSF"
+        storeAppenderClass="org.apache.catalina.storeconfig.IDynamicPropertyStoreAppender">
+     </Description>
+     <Description
+	    tag="Realm"
+		standard="false"
+		default="false" 
+		tagClass="org.apache.catalina.Realm"
+        storeFactoryClass="org.apache.catalina.storeconfig.StoreFactoryBase">
+     </Description>
+     <Description
+	    tag="Parameter"
+		standard="true"
+		default="false"
+		tagClass="org.apache.catalina.deploy.ApplicationParameter"
+        storeFactoryClass="org.apache.catalina.storeconfig.StoreFactoryBase">
+     </Description>
+     <Description
+	    tag="Loader"
+		standard="true"
+		default="false" 
+		tagClass="org.apache.catalina.loader.WebappLoader"
+        storeFactoryClass="org.apache.catalina.storeconfig.LoaderSF">
+     </Description>
+      <Description
+	    tag="Listener"
+		standard="false"
+		default="false" 
+		tagClass="org.apache.catalina.LifecycleListener"
+        storeFactoryClass="org.apache.catalina.storeconfig.StoreFactoryBase">
+       <TransientChild>org.apache.catalina.mbeans.ServerLifecycleListener</TransientChild>
+       <TransientChild>org.apache.catalina.core.NamingContextListener</TransientChild>
+       <TransientChild>org.apache.catalina.startup.ContextConfig</TransientChild>
+       <TransientChild>org.apache.catalina.startup.EngineConfig</TransientChild>
+       <TransientChild>org.apache.catalina.startup.HostConfig</TransientChild>
+     </Description>
+     <Description
+        id="org.apache.catalina.core.StandardServer.[ServerLifecycleListener]"
+	    tag="Listener"
+		standard="false"
+		default="false" 
+        tagClass="org.apache.catalina.mbeans.ServerLifecycleListener"
+        storeFactoryClass="org.apache.catalina.storeconfig.StoreFactoryBase">
+     </Description>
+     <Description
+	    tag="Valve"
+		standard="false"
+		default="false" 
+		tagClass="org.apache.catalina.Valve"
+        storeFactoryClass="org.apache.catalina.storeconfig.StoreFactoryBase">
+	     <TransientChild>org.apache.catalina.authenticator.BasicAuthenticator</TransientChild>
+	     <TransientChild>org.apache.catalina.authenticator.DigestAuthenticator</TransientChild>
+	     <TransientChild>org.apache.catalina.authenticator.FormAuthenticator</TransientChild>
+	     <TransientChild>org.apache.catalina.authenticator.NonLoginAuthenticator</TransientChild>
+	     <TransientChild>org.apache.catalina.authenticator.SSLAuthenticator</TransientChild>
+	     <TransientChild>org.apache.catalina.core.StandardContextValve</TransientChild>
+	     <TransientChild>org.apache.catalina.core.StandardEngineValve</TransientChild>
+	     <TransientChild>org.apache.catalina.core.StandardHostValve</TransientChild>
+	     <TransientChild>org.apache.catalina.valves.CertificatesValve</TransientChild>
+	     <TransientChild>org.apache.catalina.valves.ErrorReportValve</TransientChild>
+	     <TransientChild>org.apache.catalina.valves.RequestListenerValve</TransientChild>
+	 </Description>
+     <Description
+	    tag="Environment"
+		standard="true"
+		default="false" 
+		tagClass="org.apache.catalina.deploy.ContextEnvironment"
+        storeFactoryClass="org.apache.catalina.storeconfig.StoreFactoryBase">
+     </Description>
+     <Description
+	    tag="EJB"
+		standard="true"
+		default="false" 
+		tagClass="org.apache.catalina.deploy.ContextEjb"
+        storeFactoryClass="org.apache.catalina.storeconfig.StoreFactoryBase">
+     </Description>
+     <Description
+	    tag="LocalEjb"
+		standard="true"
+		default="false" 
+		tagClass="org.apache.catalina.deploy.ContextLocalEjb"
+        storeFactoryClass="org.apache.catalina.storeconfig.StoreFactoryBase">
+     </Description>
+     <Description
+	    tag="Resource"
+		standard="true"
+		default="false" 
+		tagClass="org.apache.catalina.deploy.ContextResource"
+        storeFactoryClass="org.apache.catalina.storeconfig.StoreFactoryBase">
+     </Description>
+    <Description
+	    tag="Resources"
+		standard="false"
+		default="false" 
+		tagClass="javax.naming.directory.DirContext"
+        storeFactoryClass="org.apache.catalina.storeconfig.StoreFactoryBase">
+        <TransientAttribute>docBase</TransientAttribute>
+        <TransientAttribute>allowLinking</TransientAttribute>
+        <TransientAttribute>cacheMaxSize</TransientAttribute>
+        <TransientAttribute>cacheTTL</TransientAttribute>
+        <TransientAttribute>cached</TransientAttribute>
+        <TransientAttribute>caseSensitive</TransientAttribute>
+        <TransientChild>org.apache.naming.resources.WARDirContext</TransientChild>
+        <TransientChild>org.apache.naming.resources.FileDirContext</TransientChild>
+        <TransientChild>org.apache.naming.resources.ProxyDirContext</TransientChild>
+     </Description>
+     <Description
+	    tag="ResourceEnvRef"
+		standard="true"
+		default="false" 
+		tagClass="org.apache.catalina.deploy.ContextResourceEnvRef"
+        storeFactoryClass="org.apache.catalina.storeconfig.StoreFactoryBase">
+     </Description>
+     <Description
+	    tag="ResourceLink"
+		standard="true"
+		default="false" 
+		tagClass="org.apache.catalina.deploy.ContextResourceLink"
+        storeFactoryClass="org.apache.catalina.storeconfig.StoreFactoryBase">
+     </Description>
+     <Description
+	    tag="Transaction"
+		standard="true"
+		default="false" 
+		tagClass="org.apache.catalina.deploy.ContextTransaction"
+        storeFactoryClass="org.apache.catalina.storeconfig.StoreFactoryBase">
+     </Description>
+     <Description
+	    id="org.apache.catalina.core.StandardContext.[InstanceListener]"
+	    tag="InstanceListener"
+		standard="true"
+		default="false" 
+		attributes="false"
+        storeFactoryClass="org.apache.catalina.storeconfig.InstanceListenerSF">
+     </Description>
+     <Description
+	    id="org.apache.catalina.core.StandardContext.[WrapperLifecycle]"
+	    tag="WrapperLifecycle"
+		standard="true"
+		default="false" 
+		attributes="false"
+        storeFactoryClass="org.apache.catalina.storeconfig.WrapperLifecycleSF">
+     </Description>
+     <Description
+	    id="org.apache.catalina.core.StandardContext.[WrapperListener]"
+	    tag="WrapperListener"
+		standard="true"
+		default="false" 
+		attributes="false"
+        storeFactoryClass="org.apache.catalina.storeconfig.WrapperListenerSF">
+     </Description>
+     <Description
+	    id="org.apache.catalina.core.StandardContext.[WatchedResource]"
+	    tag="WatchedResource"
+		standard="true"
+		default="false" 
+		attributes="false"
+        storeFactoryClass="org.apache.catalina.storeconfig.WatchedResourceSF">
+     </Description>
+     <Description
+	    tag="Sender"
+		standard="false"
+		default="false" 
+		tagClass="org.apache.catalina.cluster.tcp.ReplicationTransmitter"
+        storeFactoryClass="org.apache.catalina.storeconfig.StoreFactoryBase"
+        storeAppenderClass="org.apache.catalina.storeconfig.IDynamicPropertyStoreAppender">
+     </Description>
+     <Description
+	    tag="Sender"
+		standard="false"
+		default="false" 
+		tagClass="org.apache.catalina.cluster.ClusterSender"
+        storeFactoryClass="org.apache.catalina.storeconfig.StoreFactoryBase">
+     </Description>
+     <Description
+	    tag="Receiver"
+		standard="false"
+		default="false" 
+		tagClass="org.apache.catalina.cluster.ClusterReceiver"
+        storeFactoryClass="org.apache.catalina.storeconfig.StoreFactoryBase">
+     </Description>
+     <Description
+	    tag="Membership"
+		standard="false"
+		default="false"
+		tagClass="org.apache.catalina.cluster.MembershipService"
+        storeFactoryClass="org.apache.catalina.storeconfig.StoreFactoryBase">
+     </Description>
+     <Description
+	    tag="Deployer"
+		standard="false"
+		default="false" 
+		tagClass="org.apache.catalina.cluster.ClusterDeployer"
+        storeFactoryClass="org.apache.catalina.storeconfig.StoreFactoryBase">
+     </Description> 
+     <Description
+	    tag="ClusterListener"
+		standard="false"
+		default="false" 
+		tagClass="org.apache.catalina.cluster.MessageListener"
+        storeFactoryClass="org.apache.catalina.storeconfig.StoreFactoryBase">
+     </Description>
+</Registry>
+

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/test/build.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/test/build.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/test/build.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,111 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!-- @author Peter Rossbach -->
+<project name="Tomcat: StoreConfig Testcases" basedir="." default="test">
+	<property file="../../../../build.properties" />
+	<property file="../../../../jakarta-tomcat-5/build.properties.default" />
+	<property name="test.report.logs" value="logs/reports" />
+	<property name="test.results" value="logs/test-results" />
+
+	<property name="compile.optimize" value="true" />
+	<property name="compile.debug" value="true" />
+	<property name="compile.source" value="1.4" />
+	<property name="compile.deprecation" value="true" />
+	<property name="compile.nowarn" value="off" />
+	<property name="compile.encoding" value="ISO-8859-1" />
+	<property name="build.dir" value="build/test" />
+	<property name="src.dir" value="src/share" />
+	<property name="catalina.home" value="../../../../jakarta-tomcat-5/build" />
+
+	<!-- Build the classpath -->
+	<path id="project.classpath">
+		<pathelement location="${jmx.jar}" />
+		<pathelement location="${commons-logging.jar}" />
+		<pathelement location="${log4j.jar}" />
+		<fileset dir="${catalina.home}/common/endorsed">
+			<include name="*.jar" />
+		</fileset>
+		<fileset dir="${catalina.home}/common/lib">
+			<include name="*.jar" />
+		</fileset>
+		<fileset dir="${catalina.home}/server/lib">
+			<include name="*.jar" />
+		</fileset>
+	</path>
+
+	<target name="build-prepare">
+		<available property="certstore.present" file="conf/catalina.keystore" />
+		<mkdir dir="${build.dir}" />
+		<mkdir dir="webapps/myapps" />
+		<mkdir dir="conf/Catalina/localhost" />
+	</target>
+
+	<target name="info" description="Shows a information about this ant script">
+		<echo>
+			This ant script implements some testcases to verify the key functions of store tomcat server.xml .
+			You find this script at: ${ant.file}
+		</echo>
+	</target>
+
+	<!-- This target compiles all sources out of the 
+			projects source tree -->
+	<target name="compile" depends="build-prepare" description="This target compiles all sources out of the projects source tree">
+
+		<!-- Copies the static resources out of the src tree
+				to the build/classes dir -->
+		<copy todir="${build.dir}/classes">
+			<fileset dir="${src.dir}">
+				<include name="**" />
+				<exclude name="**/*.java" />
+			</fileset>
+		</copy>
+
+		<!-- Compiles all sources -->
+		<javac destdir="${build.dir}/classes" srcdir="${src.dir}" includes="**/*.java" excludes="**/CVS/**" deprecation="${compile.deprecation}" debug="${compile.debug}" source="${compile.source}" optimize="${compile.optimize}" nowarn="${compile.nowarn}" encoding="${compile.encoding}">
+			<classpath>
+				<path refid="project.classpath" />
+			</classpath>
+		</javac>
+	</target>
+
+	<target name="test" depends="compile,genstore" description="Run unit tests">
+		<delete dir="${test.results}" />
+		<mkdir dir="${test.results}" />
+		<junit fork="yes" failureProperty="test.failure" filtertrace="false" >
+			<jvmarg value="-Dcatalina.base=${basedir}" />
+			<jvmarg value="-Dcatalina.home=${catalina.home}" />
+			<jvmarg value="-Dlog4j.configuration=file:conf/log4j.xml" />
+			<classpath>
+				<pathelement location="${build.dir}/classes" />
+				<path refid="project.classpath" />
+			</classpath>
+			<formatter type="plain" usefile="false" />
+			<formatter type="xml" />
+			<batchtest todir="${test.results}">
+				<fileset dir="${build.dir}/classes" includes="**/*Test.class" />
+			</batchtest>
+		</junit>
+		<mkdir dir="${test.report.logs}" />
+		<junitreport todir="${test.report.logs}">
+			<fileset dir="${test.results}" />
+			<report format="frames" todir="${test.report.logs}" />
+		</junitreport>
+		<antcall target="checktest" />
+	</target>
+
+	<target name="genstore" unless="certstore.present">
+		<ant antfile="genstore.xml" target="store" />
+	</target>
+
+	<target name="checktest" if="test.failure">
+		<fail message="some test failed" />
+	</target>
+
+	<target name="clean">
+		<delete dir="${build}/dir" />
+		<delete dir="webapps" />
+		<delete dir="build" />
+		<delete dir="${test.report.logs}" />
+		<delete dir="${test.results}" />
+		<delete dir="logs" />
+	</target>
+</project>

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/test/conf/catalina.keystore
===================================================================
(Binary files differ)


Property changes on: branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/test/conf/catalina.keystore
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/test/conf/context.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/test/conf/context.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/test/conf/context.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Context
+    cookies="false"
+    reloadable="true">
+	<Listener className="org.apache.catalina.storeconfig.InfoLifecycleListener" />
+</Context>

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/test/conf/log4j.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/test/conf/log4j.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/test/conf/log4j.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
+<!-- ===================================================================== -->
+<!-- -->
+<!-- Log4j Configuration -->
+<!-- -->
+<!-- ===================================================================== -->
+<!-- $Id: log4j.xml 303623 2005-01-08 11:15:00Z pero $ -->
+<!--
+| For more configuration infromation and examples see the Jakarta Log4j
+| owebsite: http://jakarta.apache.org/log4j
+-->
+<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/" debug="false">
+
+<!-- ============================== -->
+<!-- Append messages to the console -->
+<!-- ==============================-->
+
+<appender name="CONSOLE" class="org.apache.log4j.ConsoleAppender">
+<param name="Target" value="System.out"/>
+<param name="Threshold" value="debug"/>
+<layout class="org.apache.log4j.PatternLayout">
+<!--The default pattern: Date Priority [Category] Message\n-->
+<param name="ConversionPattern" value="%d{ABSOLUTE} %-5p [%c{1}] %m%n"/>
+</layout>
+</appender>
+
+
+<category name="org.apache.catalina.storeconfig" 
+           additivity="false"> 
+   <priority value="info" />
+   <appender-ref ref="CONSOLE" />
+</category>
+
+<category name="org.apache.catalina" 
+           additivity="false"> 
+   <priority value="info" />
+   <appender-ref ref="CONSOLE" />
+</category>
+<category name="org.apache.tomcat" 
+           additivity="false"> 
+   <priority value="error" />
+   <appender-ref ref="CONSOLE" />
+</category>
+<category name="org.apache.naming" 
+           additivity="false"> 
+   <priority value="info" />
+   <appender-ref ref="CONSOLE" />
+</category>
+
+<!-- Setup the Root c  -->
+<root>
+   <priority value="info" />
+   <appender-ref ref="CONSOLE"/>
+</root>
+</log4j:configuration> 
+

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/test/conf/server-registry-test.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/test/conf/server-registry-test.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/test/conf/server-registry-test.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,314 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Registry name="Tomcat" version="5.1.0" encoding="UTF-8" >
+     <Description
+	    tag="Server"
+		standard="true"
+		default="true" 
+        childs="true"
+        tagClass="org.apache.catalina.core.StandardServer"
+        storeFactoryClass="org.apache.catalina.storeconfig.StandardServerSF">
+     </Description>
+     <Description
+	    tag="Service"
+		standard="true"
+		default="true" 
+        childs="true"
+        tagClass="org.apache.catalina.core.StandardService"
+        storeFactoryClass="org.apache.catalina.storeconfig.StandardServiceSF">
+     </Description>
+     <Description
+	    tag="Engine"
+		standard="true"
+		default="true" 
+        childs="true"
+        tagClass="org.apache.catalina.core.StandardEngine"
+        storeFactoryClass="org.apache.catalina.storeconfig.StandardEngineSF">
+	    <TransientAttribute>domain</TransientAttribute>
+     </Description>
+     <Description
+	    tag="Host"
+		standard="true"
+		default="true" 
+        childs="true"
+        tagClass="org.apache.catalina.core.StandardHost"
+        storeFactoryClass="org.apache.catalina.storeconfig.StandardHostSF">
+	    <TransientAttribute>domain</TransientAttribute>
+     </Description>
+     <Description
+	    tag="Context"
+		standard="true"
+		default="true" 
+		storeSeparate="true"
+		backup="true" 
+        childs="true"
+        tagClass="org.apache.catalina.core.StandardContext"
+        storeFactoryClass="org.apache.catalina.storeconfig.StandardContextSF"
+        storeAppenderClass="org.apache.catalina.storeconfig.StoreContextAppender">
+	    <TransientAttribute>available</TransientAttribute>
+	    <TransientAttribute>configFile</TransientAttribute>
+	    <TransientAttribute>configured</TransientAttribute>
+	    <TransientAttribute>displayName</TransientAttribute>
+	    <TransientAttribute>distributable</TransientAttribute>
+	    <TransientAttribute>domain</TransientAttribute>
+	    <TransientAttribute>engineName</TransientAttribute>
+	    <TransientAttribute>name</TransientAttribute>
+	    <TransientAttribute>publicId</TransientAttribute>
+	    <TransientAttribute>replaceWelcomeFiles</TransientAttribute>
+	    <TransientAttribute>saveConfig</TransientAttribute>
+	    <TransientAttribute>sessionTimeout</TransientAttribute>
+	    <TransientAttribute>startupTime</TransientAttribute>
+	    <TransientAttribute>tldScanTime</TransientAttribute>
+     </Description>
+     <Description
+        id="org.apache.catalina.deploy.NamingResources.[GlobalNamingResources]"
+	    tag="GlobalNamingResources"
+		standard="true"
+		default="false"
+		attributes="false"
+        childs="true"
+        tagClass="org.apache.catalina.deploy.NamingResources"
+        storeFactoryClass="org.apache.catalina.storeconfig.GlobalNamingResourcesSF">
+     </Description>
+      <Description
+	    tag="Connector"
+		standard="true"
+		default="true" 
+        tagClass="org.apache.catalina.connector.Connector"
+        childs="true"
+        storeFactoryClass="org.apache.catalina.storeconfig.ConnectorSF"
+        storeWriterClass="org.apache.catalina.storeconfig.ConnectorStoreAppender">
+	    <TransientAttribute>maxProcessor</TransientAttribute>
+ 	    <TransientAttribute>minProcessor</TransientAttribute>
+     </Description>
+      <Description
+        id="org.apache.catalina.connector.Connector.[ProtocolHandler]"
+	    tag="ProtocolHandler"
+		standard="true"
+		default="false" 
+        tagClass="org.apache.coyote.ProtocolHandler"
+        storeFactoryClass="org.apache.catalina.storeconfig.StoreFactoryBase">
+	    <TransientAttribute>clientauth</TransientAttribute>
+ 	    <TransientAttribute>keypass</TransientAttribute>
+	    <TransientAttribute>keystore</TransientAttribute>
+	    <TransientAttribute>keytype</TransientAttribute>
+	    <TransientAttribute>name</TransientAttribute>
+	    <TransientAttribute>port</TransientAttribute>
+	    <TransientAttribute>protocol</TransientAttribute>
+	    <TransientAttribute>protocols</TransientAttribute>
+	    <TransientAttribute>randomfile</TransientAttribute>
+	    <TransientAttribute>secure</TransientAttribute>
+	 </Description>
+     <Description
+	    tag="NamingResources"
+		standard="true"
+		default="false"
+		attributes="false"
+        childs="true"
+        tagClass="org.apache.catalina.deploy.NamingResources"
+        storeFactoryClass="org.apache.catalina.storeconfig.NamingResourcesSF">
+     </Description>
+	 <Description
+	    tag="Manager"
+		standard="false"
+		default="false" 
+		tagClass="org.apache.catalina.session.StandardManager"
+        storeFactoryClass="org.apache.catalina.storeconfig.ManagerSF">
+	    <TransientAttribute>entropy</TransientAttribute>
+	    <TransientAttribute>distributable</TransientAttribute>
+    </Description>
+    <Description
+	    tag="Manager"
+		standard="false"
+		default="false" 
+        childs="true"
+		tagClass="org.apache.catalina.session.PersistentManager"
+        storeFactoryClass="org.apache.catalina.storeconfig.PersistentManagerSF">
+        <TransientAttribute>entropy</TransientAttribute>
+	    <TransientAttribute>distributable</TransientAttribute>
+     </Description>
+     <Description
+	    tag="Store"
+		standard="false"
+		default="false" 
+		tagClass="org.apache.catalina.session.FileStore"
+        storeFactoryClass="org.apache.catalina.storeconfig.StoreFactoryBase">
+     </Description>
+     <Description
+	    tag="Store"
+		standard="false"
+		default="false" 
+		tagClass="org.apache.catalina.session.JDBCStore"
+        storeFactoryClass="org.apache.catalina.storeconfig.StoreFactoryBase">
+     </Description>
+     <Description
+	    tag="Cluster"
+		standard="false"
+		default="false" 
+        childs="true"
+		tagClass="org.apache.catalina.cluster.CatalinaCluster"
+        storeFactoryClass="org.apache.catalina.storeconfig.CatalinaClusterSF">
+     </Description>
+     <Description
+	    tag="Realm"
+		standard="false"
+		default="false" 
+		tagClass="org.apache.catalina.Realm"
+        storeFactoryClass="org.apache.catalina.storeconfig.StoreFactoryBase">
+     </Description>
+     <Description
+	    tag="Parameter"
+		standard="true"
+		default="false"
+		tagClass="org.apache.catalina.deploy.ApplicationParameter"
+        storeFactoryClass="org.apache.catalina.storeconfig.StoreFactoryBase">
+     </Description>
+     <Description
+	    tag="Loader"
+		standard="true"
+		default="false" 
+		tagClass="org.apache.catalina.loader.WebappLoader"
+        storeFactoryClass="org.apache.catalina.storeconfig.LoaderSF">
+     </Description>
+      <Description
+	    tag="Listener"
+		standard="false"
+		default="false" 
+		tagClass="org.apache.catalina.LifecycleListener"
+        storeFactoryClass="org.apache.catalina.storeconfig.StoreFactoryBase">
+       <TransientChild>org.apache.catalina.mbeans.ServerLifecycleListener</TransientChild>
+       <TransientChild>org.apache.catalina.core.NamingContextListener</TransientChild>
+       <TransientChild>org.apache.catalina.startup.ContextConfig</TransientChild>
+       <TransientChild>org.apache.catalina.startup.EngineConfig</TransientChild>
+       <TransientChild>org.apache.catalina.startup.HostConfig</TransientChild>
+     </Description>
+     <Description
+        id="org.apache.catalina.core.StandardServer.[ServerLifecycleListener]"
+	    tag="Listener"
+		standard="false"
+		default="false" 
+        tagClass="org.apache.catalina.mbeans.ServerLifecycleListener"
+        storeFactoryClass="org.apache.catalina.storeconfig.StoreFactoryBase">
+     </Description>
+     <Description
+	    tag="Valve"
+		standard="false"
+		default="false" 
+		tagClass="org.apache.catalina.Valve"
+        storeFactoryClass="org.apache.catalina.storeconfig.StoreFactoryBase">
+	     <TransientChild>org.apache.catalina.authenticator.BasicAuthenticator</TransientChild>
+	     <TransientChild>org.apache.catalina.authenticator.DigestAuthenticator</TransientChild>
+	     <TransientChild>org.apache.catalina.authenticator.FormAuthenticator</TransientChild>
+	     <TransientChild>org.apache.catalina.authenticator.NonLoginAuthenticator</TransientChild>
+	     <TransientChild>org.apache.catalina.authenticator.SSLAuthenticator</TransientChild>
+	     <TransientChild>org.apache.catalina.core.StandardContextValve</TransientChild>
+	     <TransientChild>org.apache.catalina.core.StandardEngineValve</TransientChild>
+	     <TransientChild>org.apache.catalina.core.StandardHostValve</TransientChild>
+	     <TransientChild>org.apache.catalina.valves.CertificatesValve</TransientChild>
+	     <TransientChild>org.apache.catalina.valves.ErrorReportValve</TransientChild>
+	     <TransientChild>org.apache.catalina.valves.RequestListenerValve</TransientChild>
+	     <TransientChild>org.apache.catalina.cluster.tcp.ReplicationValve</TransientChild>
+	 </Description>
+     <Description
+	    tag="Environment"
+		standard="true"
+		default="false" 
+		tagClass="org.apache.catalina.deploy.ContextEnvironment"
+        storeFactoryClass="org.apache.catalina.storeconfig.StoreFactoryBase">
+     </Description>
+     <Description
+	    tag="EJB"
+		standard="true"
+		default="false" 
+		tagClass="org.apache.catalina.deploy.ContextEjb"
+        storeFactoryClass="org.apache.catalina.storeconfig.StoreFactoryBase">
+     </Description>
+     <Description
+	    tag="LocalEjb"
+		standard="true"
+		default="false" 
+		tagClass="org.apache.catalina.deploy.ContextLocalEjb"
+        storeFactoryClass="org.apache.catalina.storeconfig.StoreFactoryBase">
+     </Description>
+     <Description
+	    tag="Resource"
+		standard="true"
+		default="false" 
+		tagClass="org.apache.catalina.deploy.ContextResource"
+        storeFactoryClass="org.apache.catalina.storeconfig.StoreFactoryBase">
+     </Description>
+     <Description
+	    tag="ResourceEnvRef"
+		standard="true"
+		default="false" 
+		tagClass="org.apache.catalina.deploy.ContextResourceEnvRef"
+        storeFactoryClass="org.apache.catalina.storeconfig.StoreFactoryBase">
+     </Description>
+     <Description
+	    tag="ResourceLink"
+		standard="true"
+		default="false" 
+		tagClass="org.apache.catalina.deploy.ContextResourceLink"
+        storeFactoryClass="org.apache.catalina.storeconfig.StoreFactoryBase">
+     </Description>
+     <Description
+		id="org.apache.catalina.core.StandardContext.[InstanceListener]"
+	    tag="InstanceListener"
+		standard="true"
+		default="false" 
+		attributes="false"
+        storeFactoryClass="org.apache.catalina.storeconfig.InstanceListenerSF">
+     </Description>
+     <Description
+		id="org.apache.catalina.core.StandardContext.[WrapperLifecycle]"
+	    tag="WrapperLifecycle"
+		standard="true"
+		default="false" 
+		attributes="false"
+        storeFactoryClass="org.apache.catalina.storeconfig.WrapperLifecycleSF">
+     </Description>
+     <Description
+		id="org.apache.catalina.core.StandardContext.[WrapperListener]"
+	    tag="WrapperListener"
+		standard="true"
+		default="false" 
+		attributes="false"
+        storeFactoryClass="org.apache.catalina.storeconfig.WrapperListenerSF">
+     </Description>
+     <Description
+		id="org.apache.catalina.core.StandardContext.[WatchedResource]"
+	    tag="WatchedResource"
+		standard="true"
+		default="false" 
+		attributes="false"
+        storeFactoryClass="org.apache.catalina.storeconfig.WatchedResourceSF">
+     </Description>
+     <Description
+	    tag="Sender"
+		standard="false"
+		default="false" 
+		tagClass="org.apache.catalina.cluster.ClusterSender"
+        storeFactoryClass="org.apache.catalina.storeconfig.StoreFactoryBase">
+     </Description>
+     <Description
+	    tag="Receiver"
+		standard="false"
+		default="false" 
+		tagClass="org.apache.catalina.cluster.ClusterReceiver"
+        storeFactoryClass="org.apache.catalina.storeconfig.StoreFactoryBase">
+     </Description>
+     <Description
+	    tag="Membership"
+		standard="false"
+		default="false" 
+		tagClass="org.apache.catalina.cluster.ClusterMembership"
+        storeFactoryClass="org.apache.catalina.storeconfig.StoreFactoryBase">
+     </Description>
+     <Description
+	    tag="Deployer"
+		standard="false"
+		default="false" 
+		tagClass="org.apache.catalina.cluster.ClusterDeployer"
+        storeFactoryClass="org.apache.catalina.storeconfig.StoreFactoryBase">
+     </Description> 
+</Registry>
+

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/test/conf/server.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/test/conf/server.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/test/conf/server.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,359 @@
+<!-- Example Server Configuration File -->
+<!-- Note that component elements are nested corresponding to their
+     parent-child relationships with each other -->
+
+<!-- A "Server" is a singleton element that represents the entire JVM,
+     which may contain one or more "Service" instances.  The Server
+     listens for a shutdown command on the indicated port.
+
+     Note:  A "Server" is not itself a "Container", so you may not
+     define subcomponents such as "Valves" or "Loggers" at this level.
+ -->
+
+<Server port="8005" shutdown="SHUTDOWN" debug="0">
+
+
+  <!-- Comment these entries out to disable JMX MBeans support -->
+  <!-- You may also configure custom components (e.g. Valves/Realms) by 
+       including your own mbean-descriptor file(s), and setting the 
+       "descriptors" attribute to point to a ';' seperated list of paths
+       (in the ClassLoader sense) of files to add to the default list.
+       e.g. descriptors="/com/myfirm/mypackage/mbean-descriptor.xml"
+  -->
+  <Listener className="org.apache.catalina.mbeans.ServerLifecycleListener"
+            debug="0"/>
+  <Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener"
+            debug="0"/>
+
+  <!-- Global JNDI resources -->
+  <GlobalNamingResources>
+
+    <!-- Test entry for demonstration purposes -->
+    <Environment name="simpleValue" type="java.lang.Integer" value="30"/>
+
+    <!-- Editable user database that can also be used by
+         UserDatabaseRealm to authenticate users -->
+    <Resource name="UserDatabase" auth="Container"
+              type="org.apache.catalina.UserDatabase"
+       description="User database that can be updated and saved"
+           factory="org.apache.catalina.users.MemoryUserDatabaseFactory"
+          pathname="conf/tomcat-users.xml" />
+
+  </GlobalNamingResources>
+
+  <!-- A "Service" is a collection of one or more "Connectors" that share
+       a single "Container" (and therefore the web applications visible
+       within that Container).  Normally, that Container is an "Engine",
+       but this is not required.
+
+       Note:  A "Service" is not itself a "Container", so you may not
+       define subcomponents such as "Valves" or "Loggers" at this level.
+   -->
+
+  <!-- Define the Tomcat Stand-Alone Service -->
+  <Service name="Catalina">
+
+    <!-- A "Connector" represents an endpoint by which requests are received
+         and responses are returned.  Each Connector passes requests on to the
+         associated "Container" (normally an Engine) for processing.
+
+         By default, a non-SSL HTTP/1.1 Connector is established on port 8080.
+         You can also enable an SSL HTTP/1.1 Connector on port 8443 by
+         following the instructions below and uncommenting the second Connector
+         entry.  SSL support requires the following steps (see the SSL Config
+         HOWTO in the Tomcat 5 documentation bundle for more detailed
+         instructions):
+         * If your JDK version 1.3 or prior, download and install JSSE 1.0.2 or
+           later, and put the JAR files into "$JAVA_HOME/jre/lib/ext".
+         * Execute:
+             %JAVA_HOME%\bin\keytool -genkey -alias tomcat -keyalg RSA (Windows)
+             $JAVA_HOME/bin/keytool -genkey -alias tomcat -keyalg RSA  (Unix)
+           with a password value of "changeit" for both the certificate and
+           the keystore itself.
+
+         By default, DNS lookups are enabled when a web application calls
+         request.getRemoteHost().  This can have an adverse impact on
+         performance, so you can disable it by setting the
+         "enableLookups" attribute to "false".  When DNS lookups are disabled,
+         request.getRemoteHost() will return the String version of the
+         IP address of the remote client.
+    -->
+
+    <!-- Define a non-SSL HTTP/1.1 Connector on port 8080 -->
+    <Connector port="8080"
+               maxThreads="150" minSpareThreads="25" maxSpareThreads="75"
+               enableLookups="false" redirectPort="8443" acceptCount="100"
+               debug="0" connectionTimeout="20000" 
+               disableUploadTimeout="true" />
+    <!-- Note : To disable connection timeouts, set connectionTimeout value
+     to 0 -->
+	
+	<!-- Note : To use gzip compression you could set the following properties :
+	
+			   compression="on" 
+			   compressionMinSize="2048" 
+			   noCompressionUserAgents="gozilla, traviata" 
+			   compressableMimeType="text/html,text/xml"
+	-->
+
+    <!-- Define a SSL HTTP/1.1 Connector on port 8443 -->
+    <!--
+    <Connector port="8443" 
+               maxThreads="150" minSpareThreads="25" maxSpareThreads="75"
+               enableLookups="false" disableUploadTimeout="true"
+               acceptCount="100" debug="0" scheme="https" secure="true"
+               clientAuth="false" sslProtocol="TLS" />
+    -->
+
+    <!-- Define an AJP 1.3 Connector on port 8009 -->
+    <Connector port="8009" 
+               enableLookups="false" redirectPort="8443" debug="0"
+               protocol="AJP/1.3" />
+
+    <!-- Define a Proxied HTTP/1.1 Connector on port 8082 -->
+    <!-- See proxy documentation for more information about using this. -->
+    <!--
+    <Connector port="8082" 
+               maxThreads="150" minSpareThreads="25" maxSpareThreads="75"
+               enableLookups="false"
+               acceptCount="100" debug="0" connectionTimeout="20000"
+               proxyPort="80" disableUploadTimeout="true" />
+    -->
+
+    <!-- An Engine represents the entry point (within Catalina) that processes
+         every request.  The Engine implementation for Tomcat stand alone
+         analyzes the HTTP headers included with the request, and passes them
+         on to the appropriate Host (virtual host). -->
+
+    <!-- You should set jvmRoute to support load-balancing via AJP ie :
+    <Engine name="Standalone" defaultHost="localhost" debug="0" jvmRoute="jvm1">         
+    --> 
+         
+    <!-- Define the top level container in our container hierarchy -->
+    <Engine name="Catalina" defaultHost="localhost" debug="0">
+
+      <!-- The request dumper valve dumps useful debugging information about
+           the request headers and cookies that were received, and the response
+           headers and cookies that were sent, for all requests received by
+           this instance of Tomcat.  If you care only about requests to a
+           particular virtual host, or a particular application, nest this
+           element inside the corresponding <Host> or <Context> entry instead.
+
+           For a similar mechanism that is portable to all Servlet 2.4
+           containers, check out the "RequestDumperFilter" Filter in the
+           example application (the source for this filter may be found in
+           "$CATALINA_HOME/webapps/examples/WEB-INF/classes/filters").
+
+           Request dumping is disabled by default.  Uncomment the following
+           element to enable it. -->
+      <!--
+      <Valve className="org.apache.catalina.valves.RequestDumperValve"/>
+      -->
+
+      <!-- Because this Realm is here, an instance will be shared globally -->
+
+      <!-- This Realm uses the UserDatabase configured in the global JNDI
+           resources under the key "UserDatabase".  Any edits
+           that are performed against this UserDatabase are immediately
+           available for use by the Realm.  -->
+      <Realm className="org.apache.catalina.realm.UserDatabaseRealm"
+                 debug="0" resourceName="UserDatabase"/>
+
+      <!-- Comment out the old realm but leave here for now in case we
+           need to go back quickly -->
+      <!--
+      <Realm className="org.apache.catalina.realm.MemoryRealm" />
+      -->
+
+      <!-- Replace the above Realm with one of the following to get a Realm
+           stored in a database and accessed via JDBC -->
+
+      <!--
+      <Realm  className="org.apache.catalina.realm.JDBCRealm" debug="99"
+             driverName="org.gjt.mm.mysql.Driver"
+          connectionURL="jdbc:mysql://localhost/authority"
+         connectionName="test" connectionPassword="test"
+              userTable="users" userNameCol="user_name" userCredCol="user_pass"
+          userRoleTable="user_roles" roleNameCol="role_name" />
+      -->
+
+      <!--
+      <Realm  className="org.apache.catalina.realm.JDBCRealm" debug="99"
+             driverName="oracle.jdbc.driver.OracleDriver"
+          connectionURL="jdbc:oracle:thin:@ntserver:1521:ORCL"
+         connectionName="scott" connectionPassword="tiger"
+              userTable="users" userNameCol="user_name" userCredCol="user_pass"
+          userRoleTable="user_roles" roleNameCol="role_name" />
+      -->
+
+      <!--
+      <Realm  className="org.apache.catalina.realm.JDBCRealm" debug="99"
+             driverName="sun.jdbc.odbc.JdbcOdbcDriver"
+          connectionURL="jdbc:odbc:CATALINA"
+              userTable="users" userNameCol="user_name" userCredCol="user_pass"
+          userRoleTable="user_roles" roleNameCol="role_name" />
+      -->
+
+      <!-- Define the default virtual host
+           Note: XML Schema validation will not work with Xerces 2.2.
+       -->
+      <Host name="localhost" debug="0" appBase="webapps"
+       unpackWARs="true" autoDeploy="true"
+       xmlValidation="false" xmlNamespaceAware="false">
+
+        <!-- Defines a cluster for this node,
+             By defining this element, means that every manager will be changed.
+             So when running a cluster, only make sure that you have webapps in there
+             that need to be clustered and remove the other ones.
+             A cluster has the following parameters:
+
+             className = the fully qualified name of the cluster class
+
+             name = a descriptive name for your cluster, can be anything
+
+             debug = the debug level, higher means more output
+
+             mcastAddr = the multicast address, has to be the same for all the nodes
+
+             mcastPort = the multicast port, has to be the same for all the nodes
+             
+             mcastBindAddr = bind the multicast socket to a specific address
+             
+             mcastTTL = the multicast TTL if you want to limit your broadcast
+             
+             mcastSoTimeout = the multicast readtimeout 
+
+             mcastFrequency = the number of milliseconds in between sending a "I'm alive" heartbeat
+
+             mcastDropTime = the number a milliseconds before a node is considered "dead" if no heartbeat is received
+
+             tcpThreadCount = the number of threads to handle incoming replication requests, optimal would be the same amount of threads as nodes 
+
+             tcpListenAddress = the listen address (bind address) for TCP cluster request on this host, 
+                                in case of multiple ethernet cards.
+                                auto means that address becomes
+                                InetAddress.getLocalHost().getHostAddress()
+
+             tcpListenPort = the tcp listen port
+
+             tcpSelectorTimeout = the timeout (ms) for the Selector.select() method in case the OS
+                                  has a wakup bug in java.nio. Set to 0 for no timeout
+
+             printToScreen = true means that managers will also print to std.out
+
+             expireSessionsOnShutdown = true means that 
+
+             useDirtyFlag = true means that we only replicate a session after setAttribute,removeAttribute has been called.
+                            false means to replicate the session after each request.
+                            false means that replication would work for the following piece of code:
+                            <%
+                            HashMap map = (HashMap)session.getAttribute("map");
+                            map.put("key","value");
+                            %>
+             replicationMode = can be either 'pooled', 'synchronous' or 'asynchronous'.
+                               * Pooled means that the replication happens using several sockets in a synchronous way. Ie, the data gets replicated, then the request return. This is the same as the 'synchronous' setting except it uses a pool of sockets, hence it is multithreaded. This is the fastest and safest configuration. To use this, also increase the nr of tcp threads that you have dealing with replication.
+                               * Synchronous means that the thread that executes the request, is also the
+                               thread the replicates the data to the other nodes, and will not return until all
+                               nodes have received the information.
+                               * Asynchronous means that there is a specific 'sender' thread for each cluster node,
+                               so the request thread will queue the replication request into a "smart" queue,
+                               and then return to the client.
+                               The "smart" queue is a queue where when a session is added to the queue, and the same session
+                               already exists in the queue from a previous request, that session will be replaced
+                               in the queue instead of replicating two requests. This almost never happens, unless there is a 
+                               large network delay.
+        -->             
+        <!--
+            When configuring for clustering, you also add in a valve to catch all the requests
+            coming in, at the end of the request, the session may or may not be replicated.
+            A session is replicated if and only if all the conditions are met:
+            1. useDirtyFlag is true or setAttribute or removeAttribute has been called AND
+            2. a session exists (has been created)
+            3. the request is not trapped by the "filter" attribute
+
+            The filter attribute is to filter out requests that could not modify the session,
+            hence we don't replicate the session after the end of this request.
+            The filter is negative, ie, anything you put in the filter, you mean to filter out,
+            ie, no replication will be done on requests that match one of the filters.
+            The filter attribute is delimited by ;, so you can't escape out ; even if you wanted to.
+
+            filter=".*\.gif;.*\.js;" means that we will not replicate the session after requests with the URI
+            ending with .gif and .js are intercepted.
+            
+            The deployer element can be used to deploy apps cluster wide.
+            Currently the deployment only deploys/undeploys to working members in the cluster
+            so no WARs are copied upons startup of a broken node.
+            The deployer watches a directory (watchDir) for WAR files when watchEnabled="true"
+            When a new war file is added the war gets deployed to the local instance,
+            and then deployed to the other instances in the cluster.
+            When a war file is deleted from the watchDir the war is undeployed locally 
+            and cluster wide
+        -->
+        
+        <!--
+        <Cluster className="org.apache.catalina.cluster.tcp.SimpleTcpCluster"
+                 managerClassName="org.apache.catalina.cluster.session.DeltaManager"
+                 expireSessionsOnShutdown="false"
+                 useDirtyFlag="true">
+
+            <Membership 
+                className="org.apache.catalina.cluster.mcast.McastService"
+                mcastAddr="228.0.0.4"
+                mcastPort="45564"
+                mcastFrequency="500"
+                mcastDropTime="3000"/>
+
+            <Receiver 
+                className="org.apache.catalina.cluster.tcp.ReplicationListener"
+                tcpListenAddress="auto"
+                tcpListenPort="4001"
+                tcpSelectorTimeout="100"
+                tcpThreadCount="6"/>
+
+            <Sender
+                className="org.apache.catalina.cluster.tcp.ReplicationTransmitter"
+                replicationMode="pooled"/>
+
+            <Valve className="org.apache.catalina.cluster.tcp.ReplicationValve"
+                   filter=".*\.gif;.*\.js;.*\.jpg;.*\.htm;.*\.html;.*\.txt;"/>
+                   
+            <Deployer className="org.apache.catalina.cluster.deploy.FarmWarDeployer"
+                      tempDir="/tmp/war-temp/"
+                      deployDir="/tmp/war-deploy/"
+                      watchDir="/tmp/war-listen/"
+                      watchEnabled="false"/>
+        </Cluster>
+        -->        
+
+
+
+        <!-- Normally, users must authenticate themselves to each web app
+             individually.  Uncomment the following entry if you would like
+             a user to be authenticated the first time they encounter a
+             resource protected by a security constraint, and then have that
+             user identity maintained across *all* web applications contained
+             in this virtual host. -->
+        <!--
+        <Valve className="org.apache.catalina.authenticator.SingleSignOn"
+                   debug="0"/>
+        -->
+
+        <!-- Access log processes all requests for this virtual host.  By
+             default, log files are created in the "logs" directory relative to
+             $CATALINA_HOME.  If you wish, you can specify a different
+             directory with the "directory" attribute.  Specify either a relative
+             (to $CATALINA_HOME) or absolute path to the desired directory.
+        -->
+        <!--
+        <Valve className="org.apache.catalina.valves.AccessLogValve"
+                 directory="logs"  prefix="localhost_access_log." suffix=".txt"
+                 pattern="common" resolveHosts="false"/>
+        -->
+
+      </Host>
+
+    </Engine>
+
+  </Service>
+
+</Server>

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/test/genstore.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/test/genstore.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/test/genstore.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<project name="store" default="store" basedir=".">
+
+     <target name="store">
+        <delete file="conf/catalina.keystore"/>
+		<genkey alias="tomcat" storepass="changeit" keypass="changeit" 
+			keystore="conf/catalina.keystore" keyalg="rsa">
+			<dname>
+				<param name="CN" value="localhost"/>
+				<param name="OU" value="Software Deveploment Tomcat"/>
+				<param name="O" value="Apache Foundation"/>
+				<param name="L" value="Bochum"/>
+				<param name="C" value="DE"/>
+			</dname>
+		</genkey>
+    </target>
+
+</project>

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/test/src/share/org/apache/catalina/storeconfig/ConnectorSFTest.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/test/src/share/org/apache/catalina/storeconfig/ConnectorSFTest.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/test/src/share/org/apache/catalina/storeconfig/ConnectorSFTest.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,161 @@
+/*
+ * Copyright 1999-2001,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.storeconfig;
+
+import java.beans.IntrospectionException;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.List;
+
+import junit.framework.TestCase;
+
+import org.apache.catalina.LifecycleListener;
+import org.apache.catalina.connector.Connector;
+
+/**
+ * @author Peter Rossbach
+ *  
+ */
+public class ConnectorSFTest extends TestCase {
+    StoreRegistry registry;
+
+    StringWriter writer = new StringWriter();
+
+    PrintWriter pWriter = new PrintWriter(writer);
+
+    Connector connector;
+
+    ConnectorSF factory;
+
+    StoreDescription desc;
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see junit.framework.TestCase#setUp()
+     */
+    protected void setUp() throws Exception {
+
+        super.setUp();
+        registry = new StoreRegistry();
+        desc = new StoreDescription();
+        desc.setTag("Connector");
+        desc.setTagClass("org.apache.catalina.connector.Connector");
+        desc.setStandard(false);
+        desc
+                .setStoreFactoryClass("org.apache.catalina.storeconfig.ConnectorSF");
+        registry.registerDescription(desc);
+        factory = new ConnectorSF();
+        desc.setStoreFactory(factory);
+        desc.getStoreFactory().setStoreAppender(new ConnectorStoreAppender());
+        factory.setRegistry(registry);
+        desc.addTransientAttribute("minProcessor");
+        desc.addTransientAttribute("maxProcessor");
+        registerDescriptor("Listener", LifecycleListener.class);
+        connector = new Connector("HTTP/1.1");
+    }
+
+    private StoreDescription registerDescriptor(String tag, Class aClass) {
+        return registerDescriptor(tag, aClass,
+                "org.apache.catalina.storeconfig.StoreFactoryBase", false,
+                false);
+    }
+
+    private StoreDescription registerDescriptor(String tag, Class aClass,
+            String factoryClass, boolean fstandard, boolean fdefault) {
+        return DescriptorHelper.registerDescriptor(desc, registry, aClass
+                .getName(), tag, aClass.getName(), factoryClass, fstandard,
+                fdefault);
+    }
+
+    public void testListener() throws Exception {
+        connector
+                .addLifecycleListener(new org.apache.catalina.mbeans.ServerLifecycleListener());
+        String aspectedResult = "<Connector>"
+                + LF.LINE_SEPARATOR
+                + "  <Listener className=\"org.apache.catalina.mbeans.ServerLifecycleListener\"/>"
+                + LF.LINE_SEPARATOR + "</Connector>" + LF.LINE_SEPARATOR;
+        check(aspectedResult);
+    }
+
+    public void testWithProtocolHandler() throws Exception {
+        connector.setProperty("acceptCount", "10");
+        connector.setProperty("maxSpareThreads", "74");
+        String aspectedResult = "<Connector" + LF.LINE_SEPARATOR
+                + "    maxSpareThreads=\"74\"" + LF.LINE_SEPARATOR
+                + "    acceptCount=\"10\">" + LF.LINE_SEPARATOR
+                + "</Connector>" + LF.LINE_SEPARATOR;
+        check(aspectedResult);
+    }
+
+    public void testStoreAJP() throws Exception {
+        connector.setProtocol("AJP/1.3");
+        String aspectedResult = "<Connector" + LF.LINE_SEPARATOR
+                + "    protocol=\"AJP/1.3\">" + LF.LINE_SEPARATOR
+                + "</Connector>" + LF.LINE_SEPARATOR;
+        check(aspectedResult);
+    }
+
+    public void testSSL() throws Exception {
+        setupSecureConnector();
+        String aspectedResult = "<Connector" + LF.LINE_SEPARATOR
+                + "    port=\"8443\"" + LF.LINE_SEPARATOR
+                + "    scheme=\"https\"" + LF.LINE_SEPARATOR
+                + "    secure=\"true\"" + LF.LINE_SEPARATOR
+                + "    minSpareThreads=\"30\"" + LF.LINE_SEPARATOR
+                + "    clientAuth=\"false\"" + LF.LINE_SEPARATOR
+                + "    keystorePass=\"changeit\"" + LF.LINE_SEPARATOR
+                + "    keystoreFile=\"conf/catalina.keystore\""
+                + LF.LINE_SEPARATOR + "    maxSpareThreads=\"175\""
+                + LF.LINE_SEPARATOR + "    sslProtocol=\"TLS\">"
+                + LF.LINE_SEPARATOR + "</Connector>" + LF.LINE_SEPARATOR;
+        check(aspectedResult);
+    }
+
+    protected void setupSecureConnector() {
+        connector.setPort(8443);
+        connector.setProperty("minSpareThreads", "30");
+        connector.setProperty("maxSpareThreads", "175");
+        connector.setEnableLookups(false);
+        connector.setProperty("disableUploadTimeout", "true");
+        connector.setSecure(true);
+        connector.setProperty("backlog", "100");
+        connector.setScheme("https");
+        connector.setProperty("clientAuth", "false");
+        connector.setProperty("sslProtocol", "TLS");
+        connector.setProperty("keystoreFile", "conf/catalina.keystore");
+        connector.setProperty("keystorePass", "changeit");
+    }
+
+    public void testConnectorAppender() throws IntrospectionException {
+        setupSecureConnector();
+        ConnectorStoreAppender appender = (ConnectorStoreAppender)desc.getStoreFactory().getStoreAppender();
+        List propertyList = appender.getPropertyKeys(connector);
+        assertTrue(propertyList.contains("protocol"));   
+    }
+    
+    public void testStoreEmpty() throws Exception {
+        String aspectedResult = "<Connector>" + LF.LINE_SEPARATOR
+                + "</Connector>" + LF.LINE_SEPARATOR;
+        check(aspectedResult);
+    }
+
+    protected void check(String aspectedResult) throws Exception {
+        factory.store(pWriter, -2, connector);
+        assertEquals(aspectedResult, writer.toString());
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/test/src/share/org/apache/catalina/storeconfig/ConnectorStoreAppenderTest.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/test/src/share/org/apache/catalina/storeconfig/ConnectorStoreAppenderTest.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/test/src/share/org/apache/catalina/storeconfig/ConnectorStoreAppenderTest.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,104 @@
+/*
+ * Copyright 1999-2001,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.storeconfig;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.List;
+
+import junit.framework.TestCase;
+
+import org.apache.catalina.LifecycleListener;
+import org.apache.catalina.connector.Connector;
+
+/**
+ * @author Peter Rossbach
+ *  
+ */
+public class ConnectorStoreAppenderTest extends TestCase {
+    StoreRegistry registry;
+
+    StringWriter writer = new StringWriter();
+
+    PrintWriter pWriter = new PrintWriter(writer);
+
+    Connector connector;
+
+    ConnectorSF factory;
+
+    StoreDescription desc;
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see junit.framework.TestCase#setUp()
+     */
+    protected void setUp() throws Exception {
+
+        super.setUp();
+        registry = new StoreRegistry();
+        desc = new StoreDescription();
+        desc.setTag("Connector");
+        desc.setTagClass("org.apache.catalina.connector.Connector");
+        desc.setStandard(false);
+        desc
+                .setStoreFactoryClass("org.apache.catalina.storeconfig.ConnectorSF");
+        registry.registerDescription(desc);
+        factory = new ConnectorSF();
+        desc.setStoreFactory(factory);
+        desc.getStoreFactory().setStoreAppender(new ConnectorStoreAppender());
+        factory.setRegistry(registry);
+        registerDescriptor("Listener", LifecycleListener.class);
+        connector = new Connector("HTTP/1.1");
+    }
+
+    private StoreDescription registerDescriptor(String tag, Class aClass) {
+        return registerDescriptor(tag, aClass,
+                "org.apache.catalina.storeconfig.StoreFactoryBase", false,
+                false);
+    }
+
+    private StoreDescription registerDescriptor(String tag, Class aClass,
+            String factoryClass, boolean fstandard, boolean fdefault) {
+        return DescriptorHelper.registerDescriptor(desc, registry, aClass
+                .getName(), tag, aClass.getName(), factoryClass, fstandard,
+                fdefault);
+    }
+
+    public void testGetProperties() throws Exception {
+        ConnectorStoreAppender appender = new ConnectorStoreAppender();
+        List properties = appender.getPropertyKeys(connector);
+        assertTrue(properties.contains("emptySessionPath"));
+        assertFalse(properties.contains("protocol"));
+        assertFalse(properties.contains("protocolHandlerClassName"));
+        // HTTP/1.1 SSL Protocol Test
+        connector.setProperty("sslProtocol", "TLS");
+        properties = appender.getPropertyKeys(connector);
+        assertTrue(properties.contains("protocol"));
+    }
+
+    public void testPrintAttributes() throws Exception {
+        ConnectorStoreAppender appender = new ConnectorStoreAppender();
+        connector.setProxyPort(80);
+        connector.setProperty("acceptCount", "110");
+        appender.printAttributes(pWriter, -2, false, connector, desc);
+
+        String aspectedResult = LF.LINE_SEPARATOR + "  proxyPort=\"80\""
+                + LF.LINE_SEPARATOR + "  acceptCount=\"110\"";
+        assertEquals(aspectedResult, writer.toString());
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/test/src/share/org/apache/catalina/storeconfig/DescriptorHelper.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/test/src/share/org/apache/catalina/storeconfig/DescriptorHelper.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/test/src/share/org/apache/catalina/storeconfig/DescriptorHelper.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,181 @@
+/*
+ * Copyright 1999-2001,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.storeconfig;
+
+import org.apache.catalina.cluster.CatalinaCluster;
+import org.apache.catalina.cluster.ClusterDeployer;
+import org.apache.catalina.cluster.ClusterReceiver;
+import org.apache.catalina.cluster.ClusterSender;
+import org.apache.catalina.cluster.MembershipService;
+import org.apache.catalina.cluster.MessageListener;
+import org.apache.catalina.deploy.ContextEjb;
+import org.apache.catalina.deploy.ContextEnvironment;
+import org.apache.catalina.deploy.ContextLocalEjb;
+import org.apache.catalina.deploy.ContextResource;
+import org.apache.catalina.deploy.ContextResourceEnvRef;
+import org.apache.catalina.deploy.ContextResourceLink;
+import org.apache.catalina.deploy.NamingResources;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * @author Peter Rossbach
+ *  
+ */
+public class DescriptorHelper {
+    private static Log log = LogFactory.getLog(DescriptorHelper.class);
+
+    public static StoreDescription registerDescriptor(
+            StoreDescription parentdesc, StoreRegistry registry, String tag,
+            Class aClass) {
+        return registerDescriptor(parentdesc, registry, aClass.getName(), tag,
+                aClass.getName(),
+                "org.apache.catalina.storeconfig.StoreFactoryBase", false,
+                false);
+    }
+
+    public static StoreDescription registerDescriptor(
+            StoreDescription parentdesc, StoreRegistry registry, String tag,
+            String aClassToken, String factoryClass, boolean fstandard,
+            boolean fdefault) {
+        return registerDescriptor(parentdesc, registry, aClassToken, tag,
+                aClassToken,
+                "org.apache.catalina.storeconfig.StoreFactoryBase", false,
+                false);
+    }
+
+    /**
+     * Generate a descriptor and register this to another parent descriptor.
+     * 
+     * @param parentdesc
+     * @param registry
+     * @param id
+     * @param tag
+     * @param aClassToken
+     * @param factoryClass
+     * @param fstandard
+     * @param fdefault
+     * @return
+     */
+    public static StoreDescription registerDescriptor(
+            StoreDescription parentdesc, StoreRegistry registry, String id,
+            String tag, String aClassToken, String factoryClass,
+            boolean fstandard, boolean fdefault) {
+        // add Listener
+        StoreDescription descChild = new StoreDescription();
+        descChild.setId(id);
+        descChild.setTag(tag);
+        descChild.setTagClass(aClassToken);
+        descChild.setStandard(fstandard);
+        descChild.setDefault(fdefault);
+        descChild.setStoreFactoryClass(factoryClass);
+        Object factory = null;
+        try {
+            Class aFactoryClass = Class.forName(factoryClass);
+            factory = aFactoryClass.newInstance();
+        } catch (Exception e) {
+            log.error(e);
+        }
+        if (factory != null) {
+            ((IStoreFactory) factory).setRegistry(registry);
+            descChild.setStoreFactory((IStoreFactory) factory);
+        }
+        if (parentdesc != null)
+            parentdesc.setChilds(true);
+        registry.registerDescription(descChild);
+        return descChild;
+    }
+
+    /**
+     * register all Registery descriptors on naming support to context!
+     * 
+     * @param parent
+     * @param registry
+     * @return
+     * @throws Exception
+     */
+    public static StoreDescription registerNamingDescriptor(
+            StoreDescription parent, StoreRegistry registry) throws Exception {
+
+        StoreDescription nameingDesc = DescriptorHelper.registerDescriptor(
+                parent, registry, NamingResources.class.getName(),
+                "NamingResources", NamingResources.class.getName(),
+                "org.apache.catalina.storeconfig.NamingResourcesSF", true,
+                false);
+        registerDescriptor(nameingDesc, registry, ContextEjb.class.getName(),
+                "EJB", ContextEjb.class.getName(),
+                "org.apache.catalina.storeconfig.StoreFactoryBase", true, false);
+        registerDescriptor(nameingDesc, registry, ContextEnvironment.class
+                .getName(), "Environment", ContextEnvironment.class.getName(),
+                "org.apache.catalina.storeconfig.StoreFactoryBase", true, false);
+        registerDescriptor(nameingDesc, registry, ContextLocalEjb.class
+                .getName(), "LocalEjb", ContextLocalEjb.class.getName(),
+                "org.apache.catalina.storeconfig.StoreFactoryBase", true, false);
+        registerDescriptor(nameingDesc, registry, ContextResource.class
+                .getName(), "Resource", ContextResource.class.getName(),
+                "org.apache.catalina.storeconfig.StoreFactoryBase", true, false);
+        registerDescriptor(nameingDesc, registry, ContextResourceLink.class
+                .getName(), "ResourceLink",
+                ContextResourceLink.class.getName(),
+                "org.apache.catalina.storeconfig.StoreFactoryBase", true, false);
+        registerDescriptor(nameingDesc, registry, ContextResourceEnvRef.class
+                .getName(), "ResourceEnvRef", ContextResourceEnvRef.class
+                .getName(), "org.apache.catalina.storeconfig.StoreFactoryBase",
+                true, false);
+        return nameingDesc;
+    }
+
+    /**
+     * register all cluster and subelement descriptors to registery
+     * 
+     * @param parent
+     * @param registry
+     * @return
+     * @throws Exception
+     */
+    public static StoreDescription registerClusterDescriptor(
+            StoreDescription parent, StoreRegistry registry) throws Exception {
+
+        StoreDescription clusterDesc = DescriptorHelper.registerDescriptor(
+                parent, registry, CatalinaCluster.class.getName(), "Cluster",
+                CatalinaCluster.class.getName(),
+                "org.apache.catalina.storeconfig.CatalinaClusterSF", false,
+                false);
+        registerDescriptor(clusterDesc, registry,
+                ClusterSender.class.getName(), "Sender", ClusterSender.class
+                        .getName(),
+                "org.apache.catalina.storeconfig.StoreFactoryBase", false,
+                false);
+        registerDescriptor(clusterDesc, registry, ClusterReceiver.class
+                .getName(), "Receiver", ClusterReceiver.class.getName(),
+                "org.apache.catalina.storeconfig.StoreFactoryBase", false,
+                false);
+        registerDescriptor(clusterDesc, registry, MembershipService.class
+                .getName(), "Membership", MembershipService.class.getName(),
+                "org.apache.catalina.storeconfig.StoreFactoryBase", false,
+                false);
+        registerDescriptor(clusterDesc, registry, ClusterDeployer.class
+                .getName(), "Deployer", ClusterDeployer.class.getName(),
+                "org.apache.catalina.storeconfig.StoreFactoryBase", false,
+                false);
+        registerDescriptor(clusterDesc, registry, MessageListener.class
+                .getName(), "ClusterListener", MessageListener.class.getName(),
+                "org.apache.catalina.storeconfig.StoreFactoryBase", false,
+                false);
+        return clusterDesc;
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/test/src/share/org/apache/catalina/storeconfig/GlobalNamingResourcesSFTest.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/test/src/share/org/apache/catalina/storeconfig/GlobalNamingResourcesSFTest.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/test/src/share/org/apache/catalina/storeconfig/GlobalNamingResourcesSFTest.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,216 @@
+/*
+ * Copyright 1999-2001,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.storeconfig;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+import junit.framework.TestCase;
+
+import org.apache.catalina.deploy.ContextEjb;
+import org.apache.catalina.deploy.ContextEnvironment;
+import org.apache.catalina.deploy.ContextLocalEjb;
+import org.apache.catalina.deploy.ContextResource;
+import org.apache.catalina.deploy.ContextResourceEnvRef;
+import org.apache.catalina.deploy.ContextResourceLink;
+import org.apache.catalina.deploy.NamingResources;
+import org.apache.catalina.storeconfig.GlobalNamingResourcesSF;
+import org.apache.catalina.storeconfig.StoreDescription;
+import org.apache.catalina.storeconfig.StoreRegistry;
+
+/**
+ * @author Peter Rossbach
+ *  
+ */
+public class GlobalNamingResourcesSFTest extends TestCase {
+    StoreRegistry registry;
+
+    StringWriter writer = new StringWriter();
+
+    PrintWriter pWriter = new PrintWriter(writer);
+
+    NamingResources reource = new NamingResources();
+
+    GlobalNamingResourcesSF factory;
+
+    StoreDescription desc;
+
+    StoreDescription nameingDesc;
+
+    /*
+     * create registery and configure naming decriptors
+     * 
+     * @see junit.framework.TestCase#setUp()
+     */
+    protected void setUp() throws Exception {
+        registry = new StoreRegistry();
+        desc = DescriptorHelper.registerDescriptor(null, registry,
+                NamingResources.class.getName() + ".[GlobalNamingResources]",
+                "GlobalNamingResources", NamingResources.class.getName(),
+                "org.apache.catalina.storeconfig.GlobalNamingResourcesSF",
+                true, false);
+        factory = (GlobalNamingResourcesSF) desc.getStoreFactory();
+        nameingDesc = DescriptorHelper.registerNamingDescriptor(desc, registry);
+        super.setUp();
+    }
+
+    protected void registerDescriptor(String tag, Class aClass,
+            String factoryClass, boolean fstandard, boolean fdefault) {
+        DescriptorHelper.registerDescriptor(nameingDesc, registry, aClass
+                .getName(), tag, aClass.getName(), factoryClass, fstandard,
+                fdefault);
+    }
+
+    public void testStore() throws Exception {
+        assertNotNull(registry.findDescription(NamingResources.class));
+        assertNotNull(registry.findDescription(ContextResourceEnvRef.class
+                .getName()));
+        assertEquals("ResourceEnvRef", registry.findDescription(
+                ContextResourceEnvRef.class.getName()).getTag());
+
+        NamingResources resources = new NamingResources();
+        ContextResourceEnvRef ref = new ContextResourceEnvRef();
+        ref.setName("peter");
+        ref.setType("type");
+        resources.addResourceEnvRef(ref);
+        String aspectedResult = "<GlobalNamingResources>" + LF.LINE_SEPARATOR
+                + "  <ResourceEnvRef" + LF.LINE_SEPARATOR
+                + "    name=\"peter\"" + LF.LINE_SEPARATOR
+                + "    type=\"type\"/>" + LF.LINE_SEPARATOR
+                + "</GlobalNamingResources>" + LF.LINE_SEPARATOR;
+        check(resources, aspectedResult);
+
+    }
+
+    public void testEJBStore() throws Exception {
+
+        NamingResources resources = new NamingResources();
+        ContextEjb ejb = new ContextEjb();
+        ejb.setName("ejb/Service");
+        ejb.setType("org.super.Bean");
+        ejb.setHome("org.super.BeanHome");
+        resources.addEjb(ejb);
+        String aspectedResult = "<GlobalNamingResources>" + LF.LINE_SEPARATOR
+                + "  <EJB" + LF.LINE_SEPARATOR
+                + "    home=\"org.super.BeanHome\"" + LF.LINE_SEPARATOR
+                + "    name=\"ejb/Service\"" + LF.LINE_SEPARATOR
+                + "    type=\"org.super.Bean\"/>" + LF.LINE_SEPARATOR
+                + "</GlobalNamingResources>" + LF.LINE_SEPARATOR;
+        check(resources, aspectedResult);
+    }
+
+    public void testLocalEjbStore() throws Exception {
+
+        NamingResources resources = new NamingResources();
+        ContextLocalEjb ejb = new ContextLocalEjb();
+        ejb.setName("ejb/Service");
+        ejb.setType("org.super.Bean");
+        ejb.setHome("org.super.BeanHome");
+        resources.addLocalEjb(ejb);
+        String aspectedResult = "<GlobalNamingResources>" + LF.LINE_SEPARATOR
+                + "  <LocalEjb" + LF.LINE_SEPARATOR
+                + "    home=\"org.super.BeanHome\"" + LF.LINE_SEPARATOR
+                + "    name=\"ejb/Service\"" + LF.LINE_SEPARATOR
+                + "    type=\"org.super.Bean\"/>" + LF.LINE_SEPARATOR
+                + "</GlobalNamingResources>" + LF.LINE_SEPARATOR;
+        check(resources, aspectedResult);
+    }
+
+    public void testEnvironmentStore() throws Exception {
+
+        NamingResources resources = new NamingResources();
+        ContextEnvironment env = new ContextEnvironment();
+        env.setName("env/SelectEmp");
+        env.setType("java.lang.String");
+        env.setValue("select * from emp");
+        resources.addEnvironment(env);
+        String aspectedResult = "<GlobalNamingResources>" + LF.LINE_SEPARATOR
+                + "  <Environment" + LF.LINE_SEPARATOR
+                + "    name=\"env/SelectEmp\"" + LF.LINE_SEPARATOR
+                + "    type=\"java.lang.String\"" + LF.LINE_SEPARATOR
+                + "    value=\"select * from emp\"/>" + LF.LINE_SEPARATOR
+                + "</GlobalNamingResources>" + LF.LINE_SEPARATOR;
+        check(resources, aspectedResult);
+    }
+
+    public void testResourceStore() throws Exception {
+
+        NamingResources resources = new NamingResources();
+        ContextResource res = new ContextResource();
+        res.setName("jdbc/Emp");
+        res.setType("javax.sql.DataSource");
+        res.setAuth("Container");
+        resources.addResource(res);
+        String aspectedResult = "<GlobalNamingResources>" + LF.LINE_SEPARATOR
+                + "  <Resource" + LF.LINE_SEPARATOR + "    auth=\"Container\""
+                + LF.LINE_SEPARATOR + "    name=\"jdbc/Emp\""
+                + LF.LINE_SEPARATOR + "    type=\"javax.sql.DataSource\"/>"
+                + LF.LINE_SEPARATOR + "</GlobalNamingResources>"
+                + LF.LINE_SEPARATOR;
+        check(resources, aspectedResult);
+    }
+
+    public void testResourceStoreProperty() throws Exception {
+
+        NamingResources resources = new NamingResources();
+        ContextResource res = new ContextResource();
+        res.setName("mail/MailSession");
+        res.setType("javax.mail.Session");
+        res.setAuth("Container");
+        res.setProperty("mail.host", "localhost");
+        resources.addResource(res);
+        String aspectedResult = "<GlobalNamingResources>" + LF.LINE_SEPARATOR
+                + "  <Resource" + LF.LINE_SEPARATOR + "    auth=\"Container\""
+                + LF.LINE_SEPARATOR + "    name=\"mail/MailSession\""
+                + LF.LINE_SEPARATOR + "    type=\"javax.mail.Session\""
+                + LF.LINE_SEPARATOR + "    mail.host=\"localhost\"/>"
+                + LF.LINE_SEPARATOR + "</GlobalNamingResources>"
+                + LF.LINE_SEPARATOR;
+        check(resources, aspectedResult);
+    }
+
+    // @TODO ResourceLink can only be exists at Context Tag
+    public void testResourceLinkStore() throws Exception {
+
+        NamingResources resources = new NamingResources();
+        ContextResourceLink res = new ContextResourceLink();
+        res.setName("jdbc/Emp1");
+        res.setType("javax.sql.DataSource");
+        res.setGlobal("jdbc/Emp");
+        resources.addResourceLink(res);
+        String aspectedResult = "<GlobalNamingResources>" + LF.LINE_SEPARATOR
+                + "  <ResourceLink" + LF.LINE_SEPARATOR
+                + "    global=\"jdbc/Emp\"" + LF.LINE_SEPARATOR
+                + "    name=\"jdbc/Emp1\"" + LF.LINE_SEPARATOR
+                + "    type=\"javax.sql.DataSource\"/>" + LF.LINE_SEPARATOR
+                + "</GlobalNamingResources>" + LF.LINE_SEPARATOR;
+        check(resources, aspectedResult);
+    }
+
+    public void testStoreEmpty() throws Exception {
+        NamingResources resources = new NamingResources();
+        String aspectedResult = "<GlobalNamingResources>" + LF.LINE_SEPARATOR
+                + "</GlobalNamingResources>" + LF.LINE_SEPARATOR;
+        check(resources, aspectedResult);
+    }
+
+    protected void check(NamingResources resources, String aspectedResult)
+            throws Exception {
+        factory.store(pWriter, -2, resources);
+        assertEquals(aspectedResult, writer.toString());
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/test/src/share/org/apache/catalina/storeconfig/InfoLifecycleListener.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/test/src/share/org/apache/catalina/storeconfig/InfoLifecycleListener.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/test/src/share/org/apache/catalina/storeconfig/InfoLifecycleListener.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,47 @@
+/*
+ * Copyright 1999-2001,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.storeconfig;
+
+import org.apache.catalina.LifecycleEvent;
+import org.apache.catalina.LifecycleListener;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * @author Peter Rossbach
+ *  
+ */
+public class InfoLifecycleListener implements LifecycleListener {
+
+    private static Log log = LogFactory.getLog(InfoLifecycleListener.class);
+
+    /**
+     * The descriptive information string for this implementation.
+     */
+    private static final String info = "org.apache.catalina.listener.InfoLifecycleListener/1.0";
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see org.apache.catalina.LifecycleListener#lifecycleEvent(org.apache.catalina.LifecycleEvent)
+     */
+    public void lifecycleEvent(LifecycleEvent arg0) {
+        if (log.isInfoEnabled())
+            log.info(arg0.getSource().toString() + ": " + arg0.getType());
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/test/src/share/org/apache/catalina/storeconfig/LF.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/test/src/share/org/apache/catalina/storeconfig/LF.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/test/src/share/org/apache/catalina/storeconfig/LF.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,29 @@
+/*
+ * Copyright 1999-2001,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.storeconfig;
+
+/**
+ * @author Peter Rossbach
+ *  
+ */
+
+public class LF {
+
+    // -------------------------------------------------------------- Constants
+
+    public static String LINE_SEPARATOR = System.getProperty("line.separator");
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/test/src/share/org/apache/catalina/storeconfig/LoaderSFTest.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/test/src/share/org/apache/catalina/storeconfig/LoaderSFTest.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/test/src/share/org/apache/catalina/storeconfig/LoaderSFTest.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,86 @@
+/*
+ * Copyright 1999-2001,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.storeconfig;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+import junit.framework.TestCase;
+
+import org.apache.catalina.Loader;
+import org.apache.catalina.loader.WebappLoader;
+import org.apache.catalina.storeconfig.LoaderSF;
+import org.apache.catalina.storeconfig.StoreDescription;
+import org.apache.catalina.storeconfig.StoreRegistry;
+
+/**
+ * @author Peter Rossbach
+ *  
+ */
+public class LoaderSFTest extends TestCase {
+    StoreRegistry registry;
+
+    StringWriter writer = new StringWriter();
+
+    PrintWriter pWriter = new PrintWriter(writer);
+
+    Loader loader;
+
+    LoaderSF factory;
+
+    StoreDescription desc;
+
+    /*
+     * create Registry and register Loader
+     * 
+     * @see junit.framework.TestCase#setUp()
+     */
+    protected void setUp() throws Exception {
+
+        super.setUp();
+        registry = new StoreRegistry();
+        desc = DescriptorHelper.registerDescriptor(null, registry,
+                WebappLoader.class.getName(), "Loader", WebappLoader.class
+                        .getName(), "org.apache.catalina.storeconfig.LoaderSF",
+                false, false);
+        factory = (LoaderSF) desc.getStoreFactory();
+        loader = new WebappLoader();
+
+    }
+
+    public void testManagerNonStandardStore() throws Exception {
+        assertTrue(factory.isDefaultLoader(loader));
+        loader.setDelegate(true);
+        assertFalse(factory.isDefaultLoader(loader));
+        String aspectedResult = "<Loader className=\"org.apache.catalina.loader.WebappLoader\""
+                + LF.LINE_SEPARATOR
+                + "    delegate=\"true\"/>"
+                + LF.LINE_SEPARATOR;
+        check(aspectedResult);
+    }
+
+    public void testStoreEmpty() throws Exception {
+        assertTrue(factory.isDefaultLoader(loader));
+        String aspectedResult = "";
+        check(aspectedResult);
+    }
+
+    protected void check(String aspectedResult) throws Exception {
+        factory.store(pWriter, -2, loader);
+        assertEquals(aspectedResult, writer.toString());
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/test/src/share/org/apache/catalina/storeconfig/ManagerSFTest.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/test/src/share/org/apache/catalina/storeconfig/ManagerSFTest.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/test/src/share/org/apache/catalina/storeconfig/ManagerSFTest.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,90 @@
+/*
+ * Copyright 1999-2001,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.storeconfig;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+import junit.framework.TestCase;
+
+import org.apache.catalina.Manager;
+import org.apache.catalina.session.StandardManager;
+
+/**
+ * @author Peter Rossbach
+ *  
+ */
+public class ManagerSFTest extends TestCase {
+    StoreRegistry registry;
+
+    StringWriter writer = new StringWriter();
+
+    PrintWriter pWriter = new PrintWriter(writer);
+
+    StandardManager manager;
+
+    ManagerSF factory;
+
+    StoreDescription desc;
+
+    /*
+     * create registery and register Manager descriptor
+     * 
+     * @see junit.framework.TestCase#setUp()
+     */
+    protected void setUp() throws Exception {
+
+        super.setUp();
+        registry = new StoreRegistry();
+        desc = DescriptorHelper.registerDescriptor(null, registry,
+                Manager.class.getName(), "Manager",
+                Manager.class.getName(),
+                "org.apache.catalina.storeconfig.ManagerSF", false, false);
+        desc.addTransientAttribute("entropy");
+        desc.addTransientAttribute("distributable");
+        factory = (ManagerSF) desc.getStoreFactory();
+        manager = new StandardManager();
+
+    }
+
+    public void testFindStandardManager() {
+        StoreDescription managerdesc = registry.findDescription(manager.getClass());
+        assertEquals(desc,managerdesc);
+    }
+    
+    public void testManagerNonStandardStore() throws Exception {
+        assertTrue(factory.isDefaultManager(manager));
+        manager.setMaxActiveSessions(100);
+        assertFalse(factory.isDefaultManager(manager));
+        String aspectedResult = "<Manager className=\"org.apache.catalina.session.StandardManager\""
+                + LF.LINE_SEPARATOR
+                + "    maxActiveSessions=\"100\"/>"
+                + LF.LINE_SEPARATOR;
+        check(aspectedResult);
+    }
+
+    public void testStoreEmpty() throws Exception {
+        assertTrue(factory.isDefaultManager(manager));
+        String aspectedResult = "";
+        check(aspectedResult);
+    }
+
+    protected void check(String aspectedResult) throws Exception {
+        factory.store(pWriter, -2, manager);
+        assertEquals(aspectedResult, writer.toString());
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/test/src/share/org/apache/catalina/storeconfig/ServerChildsTest.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/test/src/share/org/apache/catalina/storeconfig/ServerChildsTest.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/test/src/share/org/apache/catalina/storeconfig/ServerChildsTest.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,134 @@
+/*
+ * Copyright 1999-2001,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.storeconfig;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+import junit.framework.TestCase;
+
+import org.apache.catalina.Lifecycle;
+import org.apache.catalina.LifecycleListener;
+import org.apache.catalina.core.StandardServer;
+import org.apache.catalina.core.StandardService;
+import org.apache.catalina.deploy.NamingResources;
+import org.apache.catalina.storeconfig.StandardServerSF;
+import org.apache.catalina.storeconfig.StoreDescription;
+import org.apache.catalina.storeconfig.StoreRegistry;
+
+/**
+ * @author Peter Rossbach
+ *  
+ */
+public class ServerChildsTest extends TestCase {
+
+    StoreRegistry registry;
+
+    StringWriter writer = new StringWriter();
+
+    PrintWriter pWriter = new PrintWriter(writer);
+
+    StandardServer standardServer = new StandardServer();
+
+    StandardServerSF factory;
+
+    StoreDescription desc;
+
+    /*
+     * create registery and register Server and direct subelement descriptors
+     * 
+     * @see junit.framework.TestCase#setUp()
+     */
+    protected void setUp() throws Exception {
+
+        super.setUp();
+        registry = new StoreRegistry();
+        desc = new StoreDescription();
+        desc.setTag("Server");
+        desc.setTagClass("org.apache.catalina.core.StandardServer");
+        desc.setStandard(true);
+        desc
+                .setStoreFactoryClass("org.apache.catalina.storeconfig.StandardServerSF");
+        registry.registerDescription(desc);
+        factory = new StandardServerSF();
+        desc.setStoreFactory(factory);
+        factory.setRegistry(registry);
+        StoreDescription listdesc = registerDescriptor("Listener",
+                LifecycleListener.class);
+        listdesc
+                .addTransientChild("org.apache.catalina.core.NamingContextListener");
+        listdesc
+                .addTransientChild("org.apache.catalina.mbeans.ServerLifecycleListener");
+        standardServer
+                .addLifecycleListener(new org.apache.catalina.mbeans.ServerLifecycleListener());
+        // add GlobalNamingResource
+        DescriptorHelper.registerDescriptor(desc, registry,
+                NamingResources.class.getName() + ".[GlobalNamingResources]",
+                "GlobalNamingResources", NamingResources.class.getName(),
+                "org.apache.catalina.storeconfig.GlobalNamingResourcesSF",
+                true, false);
+        DescriptorHelper.registerNamingDescriptor(desc, registry);
+        registerDescriptor("Service", StandardService.class,
+                "org.apache.catalina.storeconfig.StandardServiceSF", true,
+                false);
+        DescriptorHelper.registerDescriptor(desc, registry,
+                StandardServer.class.getName() + ".[ServerLifecycleListener]",
+                "ServerLifecycleListener", StandardServer.class.getName(),
+                "org.apache.catalina.storeconfig.StoreFactoryBase", false,
+                false);
+        standardServer.addService(new StandardService());
+
+    }
+
+    private StoreDescription registerDescriptor(String tag, Class aClass) {
+        return registerDescriptor(tag, aClass,
+                "org.apache.catalina.storeconfig.StoreFactoryBase", false,
+                false);
+    }
+
+    private StoreDescription registerDescriptor(String tag, Class aClass,
+            String factoryClass, boolean fstandard, boolean fdefault) {
+        return DescriptorHelper.registerDescriptor(desc, registry, aClass
+                .getName(), tag, aClass.getName(), factoryClass, fstandard,
+                fdefault);
+    }
+
+    public void testSaveListenerAddServer() throws Exception {
+        assertTrue(standardServer instanceof Lifecycle);
+        assertNotNull(
+                "No Listener Descriptor",
+                registry
+                        .findDescription("org.apache.catalina.mbeans.ServerLifecycleListener"));
+        assertNotNull(
+                "No Listener StoreFactory",
+                registry
+                        .findStoreFactory("org.apache.catalina.mbeans.ServerLifecycleListener"));
+        factory.store(pWriter, -2, standardServer);
+ 
+        String aspectedResult = "<?xml version=\"1.0\" encoding=\""
+                + registry.getEncoding()
+                + "\"?>"
+                + LF.LINE_SEPARATOR
+                + "<Server>"
+                + LF.LINE_SEPARATOR
+                + "  <Listener className=\"org.apache.catalina.mbeans.ServerLifecycleListener\"/>"
+                + LF.LINE_SEPARATOR + "  <GlobalNamingResources>"
+                + LF.LINE_SEPARATOR + "  </GlobalNamingResources>"
+                + LF.LINE_SEPARATOR + "  <Service/>" + LF.LINE_SEPARATOR
+                + "</Server>" + LF.LINE_SEPARATOR;
+        assertEquals(aspectedResult, writer.toString());
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/test/src/share/org/apache/catalina/storeconfig/StandardContextSFTest.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/test/src/share/org/apache/catalina/storeconfig/StandardContextSFTest.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/test/src/share/org/apache/catalina/storeconfig/StandardContextSFTest.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,350 @@
+/*
+ * Copyright 1999-2001,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.storeconfig;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+import javax.naming.directory.DirContext;
+
+import junit.framework.TestCase;
+
+import org.apache.catalina.LifecycleListener;
+import org.apache.catalina.Valve;
+import org.apache.catalina.core.StandardContext;
+import org.apache.catalina.core.StandardHost;
+import org.apache.catalina.deploy.ContextResourceEnvRef;
+import org.apache.catalina.deploy.ContextResourceLink;
+import org.apache.catalina.deploy.NamingResources;
+import org.apache.catalina.realm.JAASRealm;
+import org.apache.catalina.session.FileStore;
+import org.apache.catalina.session.JDBCStore;
+import org.apache.catalina.session.PersistentManager;
+import org.apache.catalina.session.StandardManager;
+import org.apache.catalina.storeconfig.StandardContextSF;
+import org.apache.catalina.storeconfig.StoreDescription;
+import org.apache.catalina.storeconfig.StoreRegistry;
+import org.apache.naming.resources.FileDirContext;
+import org.apache.naming.resources.ProxyDirContext;
+import org.apache.naming.resources.WARDirContext;
+
+/**
+ * @author Peter Rossbach
+ *  
+ */
+public class StandardContextSFTest extends TestCase {
+    StoreRegistry registry;
+
+    StringWriter writer = new StringWriter();
+
+    PrintWriter pWriter = new PrintWriter(writer);
+
+    StandardContext standardContext;
+
+    StandardContextSF factory;
+
+    StoreDescription desc;
+
+    /*
+     * create registery and register Context and all subelements
+     * 
+     * @see junit.framework.TestCase#setUp()
+     */
+    protected void setUp() throws Exception {
+
+        super.setUp();
+        registry = new StoreRegistry();
+        desc = new StoreDescription();
+        desc.setTag("Context");
+        desc.setTagClass("org.apache.catalina.core.StandardContext");
+        desc.setStandard(true);
+        desc
+                .setStoreFactoryClass("org.apache.catalina.storeconfig.StandardContextSF");
+        String exceptions[] = { "available", "configFile", "configured",
+                "distributable", "domain", "engineName", "name", "override",
+                "publicId", "replaceWelcomeFiles", "sessionTimeout",
+                "startupTime", "tldScanTime" };
+        for (int i = 0; i < exceptions.length; i++)
+            desc.addTransientAttribute(exceptions[i]);
+
+        registry.registerDescription(desc);
+        factory = new StandardContextSF();
+        desc.setStoreFactory(factory);
+        factory.setRegistry(registry);
+
+        StoreDescription listenerdesc = registerDescriptor("Listener",
+                LifecycleListener.class);
+
+        String listenerskippables[] = {
+                "org.apache.catalina.core.NamingContextListener",
+                "org.apache.catalina.startup.ContextConfig", };
+        for (int i = 0; i < listenerskippables.length; i++)
+            listenerdesc.addTransientChild(listenerskippables[i]);
+
+        StoreDescription realmdesc = registerDescriptor("Realm",
+                JAASRealm.class,
+                "org.apache.catalina.storeconfig.StoreFactoryBase", false,
+                false);
+        StoreDescription managerdesc = registerDescriptor("Manager",
+                StandardManager.class,
+                "org.apache.catalina.storeconfig.ManagerSF", false, false);
+        managerdesc.addTransientAttribute("entropy");
+        managerdesc.addTransientAttribute("distributable");
+        StoreDescription pmanagerdesc = registerDescriptor("Manager",
+                PersistentManager.class,
+                "org.apache.catalina.storeconfig.PersistentManagerSF", false,
+                false);
+        pmanagerdesc.addTransientAttribute("entropy");
+        pmanagerdesc.addTransientAttribute("distributable");
+        DescriptorHelper.registerDescriptor(pmanagerdesc, registry,
+                FileStore.class.getName(), "Store", FileStore.class.getName(),
+                "org.apache.catalina.storeconfig.StoreFactoryBase", false,
+                false);
+        DescriptorHelper.registerDescriptor(pmanagerdesc, registry,
+                JDBCStore.class.getName(), "Store", JDBCStore.class.getName(),
+                "org.apache.catalina.storeconfig.StoreFactoryBase", false,
+                false);
+        DescriptorHelper.registerNamingDescriptor(desc, registry);
+        StoreDescription valvedesc = registerDescriptor("Valve", Valve.class,
+                "org.apache.catalina.storeconfig.StoreFactoryBase", false,
+                false);
+        String skippables[] = {
+                "org.apache.catalina.authenticator.BasicAuthenticator",
+                "org.apache.catalina.authenticator.DigestAuthenticator",
+                "org.apache.catalina.authenticator.FormAuthenticator",
+                "org.apache.catalina.authenticator.NonLoginAuthenticator",
+                "org.apache.catalina.authenticator.SSLAuthenticator",
+                "org.apache.catalina.core.StandardContextValve",
+                "org.apache.catalina.valves.CertificatesValve" };
+        for (int i = 0; i < skippables.length; i++)
+            valvedesc.addTransientChild(skippables[i]);
+
+        StoreDescription resdesc = registerDescriptor("Resources",
+                DirContext.class,
+                "org.apache.catalina.storeconfig.StoreFactoryBase", false,
+                false);
+        resdesc.addTransientAttribute("docBase");
+        resdesc.addTransientAttribute("allowLinking");
+        resdesc.addTransientAttribute("cacheMaxSize");
+        resdesc.addTransientAttribute("cacheTTL");
+        resdesc.addTransientAttribute("caseSensitive");
+        resdesc.addTransientChild(FileDirContext.class.getName());
+        resdesc.addTransientChild(ProxyDirContext.class.getName());
+        resdesc.addTransientChild(WARDirContext.class.getName());
+        standardContext = new StandardContext();
+        standardContext.setPath("/myapps");
+        standardContext.setDocBase("myapps");
+
+    }
+
+    private StoreDescription registerDescriptor(String tag, Class aClass) {
+        return registerDescriptor(tag, aClass,
+                "org.apache.catalina.storeconfig.StoreFactoryBase", false,
+                false);
+    }
+
+    private StoreDescription registerDescriptor(String tag, Class aClass,
+            String factoryClass, boolean fstandard, boolean fdefault) {
+        return DescriptorHelper.registerDescriptor(desc, registry, aClass
+                .getName(), tag, aClass.getName(), factoryClass, fstandard,
+                fdefault);
+    }
+
+    /**
+     * @TODO Listener only saved at real context. Wrong when next Context
+     *       deployed! see Changes.txt
+     * @throws Exception
+     */
+    public void testListenerStore() throws Exception {
+        standardContext
+                .addLifecycleListener(new org.apache.catalina.storeconfig.InfoLifecycleListener());
+        standardContext
+                .addInstanceListener("org.apache.catalina.ContainerListener");
+        standardContext
+                .addWrapperListener("org.apache.catalina.ContainerListener");
+        standardContext
+                .addWrapperLifecycle("org.apache.catalina.ContainerListener");
+        standardContext.addWatchedResource("/tmp/reloaded");
+        String aspectedResult = "<Context"
+                + LF.LINE_SEPARATOR
+                + "    docBase=\"myapps\""
+                + LF.LINE_SEPARATOR
+                + "    path=\"/myapps\">"
+                + LF.LINE_SEPARATOR
+                + "  <Listener className=\"org.apache.catalina.storeconfig.InfoLifecycleListener\"/>"
+                + LF.LINE_SEPARATOR
+                + "  <InstanceListener>org.apache.catalina.ContainerListener</InstanceListener>"
+                + LF.LINE_SEPARATOR
+                + "  <WrapperListener>org.apache.catalina.ContainerListener</WrapperListener>"
+                + LF.LINE_SEPARATOR
+                + "  <WrapperLifecycle>org.apache.catalina.ContainerListener</WrapperLifecycle>"
+                + LF.LINE_SEPARATOR
+                + "  <WatchedResource>/tmp/reloaded</WatchedResource>"
+                + LF.LINE_SEPARATOR + "</Context>" + LF.LINE_SEPARATOR;
+        check(aspectedResult);
+    }
+
+    public void testNamingStore() throws Exception {
+        standardContext
+                .addLifecycleListener(new org.apache.catalina.storeconfig.InfoLifecycleListener());
+        NamingResources resources = standardContext.getNamingResources();
+        ContextResourceEnvRef ref = new ContextResourceEnvRef();
+        ref.setName("foo");
+        ref.setType("type");
+        resources.addResourceEnvRef(ref);
+        ContextResourceLink res = new ContextResourceLink();
+        res.setName("jdbc/Barlocal");
+        res.setType("javax.sql.DataSource");
+        res.setGlobal("jdbc/Bar");
+        resources.addResourceLink(res);
+        String aspectedResult = "<Context"
+                + LF.LINE_SEPARATOR
+                + "    docBase=\"myapps\""
+                + LF.LINE_SEPARATOR
+                + "    path=\"/myapps\">"
+                + LF.LINE_SEPARATOR
+                + "  <Listener className=\"org.apache.catalina.storeconfig.InfoLifecycleListener\"/>"
+                + LF.LINE_SEPARATOR + "  <ResourceEnvRef" + LF.LINE_SEPARATOR
+                + "    name=\"foo\"" + LF.LINE_SEPARATOR
+                + "    type=\"type\"/>" + LF.LINE_SEPARATOR + "  <ResourceLink"
+                + LF.LINE_SEPARATOR + "    global=\"jdbc/Bar\""
+                + LF.LINE_SEPARATOR + "    name=\"jdbc/Barlocal\""
+                + LF.LINE_SEPARATOR + "    type=\"javax.sql.DataSource\"/>"
+                + LF.LINE_SEPARATOR + "</Context>" + LF.LINE_SEPARATOR;
+        check(aspectedResult);
+    }
+
+    public void testManagerStore() throws Exception {
+        standardContext.setManager(new StandardManager());
+        String aspectedResult = "<Context" + LF.LINE_SEPARATOR
+                + "    docBase=\"myapps\"" + LF.LINE_SEPARATOR
+                + "    path=\"/myapps\">" + LF.LINE_SEPARATOR
+                + "</Context>\r\n";
+        check(aspectedResult);
+    }
+
+    public void testRealmStore() throws Exception {
+        standardContext.setManager(new StandardManager());
+        JAASRealm realm = new JAASRealm();
+        standardContext.setRealm(realm);
+        String aspectedResult = "<Context" + LF.LINE_SEPARATOR
+                + "    docBase=\"myapps\"" + LF.LINE_SEPARATOR
+                + "    path=\"/myapps\">" + LF.LINE_SEPARATOR
+                + "  <Realm className=\"org.apache.catalina.realm.JAASRealm\""
+                + LF.LINE_SEPARATOR + "    appName=\"myapps\"/>"
+                + LF.LINE_SEPARATOR + "</Context>" + LF.LINE_SEPARATOR;
+        check(aspectedResult);
+    }
+
+    // @TODO Why the MaxInactiveInterval is after setManager set to 1800 sec?
+    public void testManagerNonStandardStore() throws Exception {
+        StandardManager manager = new StandardManager();
+        manager.setMaxActiveSessions(100);
+        assertEquals(60, manager.getMaxInactiveInterval());
+        standardContext.setManager(manager);
+        assertEquals(1800, manager.getMaxInactiveInterval());
+        String aspectedResult = "<Context"
+                + LF.LINE_SEPARATOR
+                + "    docBase=\"myapps\""
+                + LF.LINE_SEPARATOR
+                + "    path=\"/myapps\">"
+                + LF.LINE_SEPARATOR
+                + "  <Manager className=\"org.apache.catalina.session.StandardManager\""
+                + LF.LINE_SEPARATOR + "      maxActiveSessions=\"100\""
+                + LF.LINE_SEPARATOR + "      maxInactiveInterval=\"1800\"/>"
+                + LF.LINE_SEPARATOR + "</Context>\r\n";
+        check(aspectedResult);
+    }
+
+    public void testPersistentManagerStore() throws Exception {
+        PersistentManager manager = new PersistentManager();
+        manager.setSaveOnRestart(false);
+        standardContext.setManager(manager);
+        String aspectedResult = "<Context"
+                + LF.LINE_SEPARATOR
+                + "    docBase=\"myapps\""
+                + LF.LINE_SEPARATOR
+                + "    path=\"/myapps\">"
+                + LF.LINE_SEPARATOR
+                + "  <Manager className=\"org.apache.catalina.session.PersistentManager\""
+                + LF.LINE_SEPARATOR + "      maxInactiveInterval=\"1800\""
+                + LF.LINE_SEPARATOR + "      saveOnRestart=\"false\">"
+                + LF.LINE_SEPARATOR + "  </Manager>" + LF.LINE_SEPARATOR
+                + "</Context>" + LF.LINE_SEPARATOR;
+        check(aspectedResult);
+    }
+
+    public void testPersistentManagerFileStore() throws Exception {
+        PersistentManager manager = new PersistentManager();
+        manager.setSaveOnRestart(false);
+        FileStore store = new FileStore();
+        manager.setStore(store);
+        standardContext.setManager(manager);
+        String aspectedResult = "<Context"
+                + LF.LINE_SEPARATOR
+                + "    docBase=\"myapps\""
+                + LF.LINE_SEPARATOR
+                + "    path=\"/myapps\">"
+                + LF.LINE_SEPARATOR
+                + "  <Manager className=\"org.apache.catalina.session.PersistentManager\""
+                + LF.LINE_SEPARATOR
+                + "      maxInactiveInterval=\"1800\""
+                + LF.LINE_SEPARATOR
+                + "      saveOnRestart=\"false\">"
+                + LF.LINE_SEPARATOR
+                + "    <Store className=\"org.apache.catalina.session.FileStore\"/>"
+                + LF.LINE_SEPARATOR + "  </Manager>" + LF.LINE_SEPARATOR
+                + "</Context>" + LF.LINE_SEPARATOR;
+        check(aspectedResult);
+
+    }
+
+    public void testDefaultResources() throws Exception {
+        FileDirContext dirC = new FileDirContext();
+        standardContext.setAllowLinking(true);
+        standardContext.setResources(dirC);
+        StandardHost host = new StandardHost();
+        host.addChild(standardContext);
+        host.setName("localhost");
+        host.setAppBase("webapps");
+        standardContext.resourcesStart();
+        assertNotNull(standardContext.getResources());
+        String aspectedResult = "<Context" + LF.LINE_SEPARATOR
+                + "    docBase=\"myapps\"" + LF.LINE_SEPARATOR
+                + "    path=\"/myapps\">" + LF.LINE_SEPARATOR + "</Context>"
+                + LF.LINE_SEPARATOR;
+        check(aspectedResult);
+    }
+
+    /*
+     * + " <Resources className=\"org.apache.naming.resources.FileDirContext\"" +
+     * Constants.LINE_SEPARATOR + " allowLinking=\"true\"/>" +
+     * Constants.LINE_SEPARATOR
+     */
+    public void testStoreEmpty() throws Exception {
+        String aspectedResult = "<Context" + LF.LINE_SEPARATOR
+                + "    docBase=\"myapps\"" + LF.LINE_SEPARATOR
+                + "    path=\"/myapps\">" + LF.LINE_SEPARATOR + "</Context>"
+                + LF.LINE_SEPARATOR;
+        check(aspectedResult);
+    }
+
+    protected void check(String aspectedResult) throws Exception {
+        factory.store(pWriter, -2, standardContext);
+        assertEquals(aspectedResult, writer.toString());
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/test/src/share/org/apache/catalina/storeconfig/StandardEngineSFTest.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/test/src/share/org/apache/catalina/storeconfig/StandardEngineSFTest.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/test/src/share/org/apache/catalina/storeconfig/StandardEngineSFTest.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,210 @@
+/*
+ * Copyright 1999-2001,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.storeconfig;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+import junit.framework.TestCase;
+
+import org.apache.catalina.LifecycleListener;
+import org.apache.catalina.Valve;
+import org.apache.catalina.core.StandardEngine;
+import org.apache.catalina.core.StandardHost;
+import org.apache.catalina.realm.JAASRealm;
+import org.apache.catalina.storeconfig.StandardEngineSF;
+import org.apache.catalina.storeconfig.StoreDescription;
+import org.apache.catalina.storeconfig.StoreRegistry;
+
+/**
+ * @author Peter Rossbach
+ *  
+ */
+public class StandardEngineSFTest extends TestCase {
+    StoreRegistry registry;
+
+    StringWriter writer = new StringWriter();
+
+    PrintWriter pWriter = new PrintWriter(writer);
+
+    StandardEngine standardEngine;
+
+    StandardEngineSF factory;
+
+    StoreDescription desc;
+
+    /*
+     * create registery and register Engine and direct subelement descriptors
+     * 
+     * @see junit.framework.TestCase#setUp()
+     */
+    protected void setUp() throws Exception {
+
+        super.setUp();
+        registry = new StoreRegistry();
+        desc = new StoreDescription();
+        desc.setTag("Engine");
+        desc.setTagClass("org.apache.catalina.core.StandardEngine");
+        desc.setStandard(true);
+        desc
+                .setStoreFactoryClass("org.apache.catalina.storeconfig.StandardEngineSF");
+        desc.addTransientAttribute("domain");
+        registry.registerDescription(desc);
+        factory = new StandardEngineSF();
+        desc.setStoreFactory(factory);
+        factory.setRegistry(registry);
+        StoreDescription listenerdesc = registerDescriptor("Listener",
+                LifecycleListener.class);
+
+        String listenerskippables[] = {
+                "org.apache.catalina.core.NamingContextListener",
+                "org.apache.catalina.startup.ContextConfig",
+                "org.apache.catalina.startup.EngineConfig",
+                "org.apache.catalina.startup.HostConfig", };
+        for (int i = 0; i < listenerskippables.length; i++)
+            listenerdesc.addTransientChild(listenerskippables[i]);
+
+        StoreDescription realmdesc = registerDescriptor("Realm",
+                JAASRealm.class,
+                "org.apache.catalina.storeconfig.StoreFactoryBase", true, false);
+        StoreDescription hostdesc = registerDescriptor("Host",
+                StandardHost.class,
+                "org.apache.catalina.storeconfig.StoreFactoryBase", true, false);
+        hostdesc.addTransientAttribute("domain");
+        StoreDescription valvedesc = registerDescriptor("Valve", Valve.class,
+                "org.apache.catalina.storeconfig.StoreFactoryBase", false,
+                false);
+
+        String skippables[] = {
+                "org.apache.catalina.authenticator.BasicAuthenticator",
+                "org.apache.catalina.authenticator.DigestAuthenticator",
+                "org.apache.catalina.authenticator.FormAuthenticator",
+                "org.apache.catalina.authenticator.NonLoginAuthenticator",
+                "org.apache.catalina.authenticator.SSLAuthenticator",
+                "org.apache.catalina.core.StandardContextValve",
+                "org.apache.catalina.core.StandardEngineValve",
+                "org.apache.catalina.core.StandardHostValve",
+                "org.apache.catalina.valves.CertificatesValve",
+                "org.apache.catalina.valves.ErrorReportValve",
+                "org.apache.catalina.valves.RequestListenerValve", };
+        for (int i = 0; i < skippables.length; i++)
+            valvedesc.addTransientChild(skippables[i]);
+
+        standardEngine = new StandardEngine();
+        standardEngine.setName("Catalina");
+
+    }
+
+    private StoreDescription registerDescriptor(String tag, Class aClass) {
+        return registerDescriptor(tag, aClass,
+                "org.apache.catalina.storeconfig.StoreFactoryBase", false,
+                false);
+    }
+
+    /**
+     *  
+     */
+    private StoreDescription registerDescriptor(String tag, Class aClass,
+            String factoryClass, boolean fstandard, boolean fdefault) {
+        return DescriptorHelper.registerDescriptor(desc, registry, aClass
+                .getName(), tag, aClass.getName(), factoryClass, fstandard,
+                fdefault);
+    }
+
+    public void testStore() throws Exception {
+        standardEngine
+                .addLifecycleListener(new org.apache.catalina.storeconfig.InfoLifecycleListener());
+        StandardHost host = new StandardHost();
+        host.setName("localhost");
+        standardEngine.addChild(host);
+        String aspectedResult = "<Engine"
+                + LF.LINE_SEPARATOR
+                + "    name=\"Catalina\">"
+                + LF.LINE_SEPARATOR
+                + "  <Listener className=\"org.apache.catalina.storeconfig.InfoLifecycleListener\"/>"
+                + LF.LINE_SEPARATOR + "  <Realm" + LF.LINE_SEPARATOR
+                + "    appName=\"Catalina\"/>" + LF.LINE_SEPARATOR + "  <Host"
+                + LF.LINE_SEPARATOR + "    name=\"localhost\"/>"
+                + LF.LINE_SEPARATOR + "</Engine>" + LF.LINE_SEPARATOR;
+
+        check(aspectedResult);
+    }
+
+    public void testElements() throws Exception {
+        standardEngine.setName("Catalina");
+        standardEngine
+                .addLifecycleListener(new org.apache.catalina.storeconfig.InfoLifecycleListener());
+        standardEngine
+                .addLifecycleListener(new org.apache.catalina.startup.EngineConfig());
+        StandardHost host = new StandardHost();
+        host.setName("localhost");
+        standardEngine.addChild(host);
+        String aspectedResult = "<Engine"
+                + LF.LINE_SEPARATOR
+                + "    name=\"Catalina\">"
+                + LF.LINE_SEPARATOR
+                + "  <Listener className=\"org.apache.catalina.storeconfig.InfoLifecycleListener\"/>"
+                + LF.LINE_SEPARATOR + "  <Realm" + LF.LINE_SEPARATOR
+                + "    appName=\"Catalina\"/>" + LF.LINE_SEPARATOR + "  <Host"
+                + LF.LINE_SEPARATOR + "    name=\"localhost\"/>"
+                + LF.LINE_SEPARATOR + "</Engine>" + LF.LINE_SEPARATOR;
+        check(aspectedResult);
+    }
+
+    public void testValve() throws Exception {
+        standardEngine.setName("Catalina");
+        standardEngine
+                .addLifecycleListener(new org.apache.catalina.storeconfig.InfoLifecycleListener());
+        standardEngine
+                .addLifecycleListener(new org.apache.catalina.startup.EngineConfig());
+        StandardHost host = new StandardHost();
+        host.setName("localhost");
+        standardEngine.addChild(host);
+        standardEngine
+                .addValve(new org.apache.catalina.valves.ErrorReportValve());
+        standardEngine
+                .addValve(new org.apache.catalina.valves.RequestDumperValve());
+        String aspectedResult = "<Engine"
+                + LF.LINE_SEPARATOR
+                + "    name=\"Catalina\">"
+                + LF.LINE_SEPARATOR
+                + "  <Listener className=\"org.apache.catalina.storeconfig.InfoLifecycleListener\"/>"
+                + LF.LINE_SEPARATOR
+                + "  <Realm"
+                + LF.LINE_SEPARATOR
+                + "    appName=\"Catalina\"/>"
+                + LF.LINE_SEPARATOR
+                + "  <Valve className=\"org.apache.catalina.valves.RequestDumperValve\"/>"
+                + LF.LINE_SEPARATOR + "  <Host" + LF.LINE_SEPARATOR
+                + "    name=\"localhost\"/>" + LF.LINE_SEPARATOR + "</Engine>"
+                + LF.LINE_SEPARATOR;
+        check(aspectedResult);
+    }
+
+    public void testStoreEmpty() throws Exception {
+        String aspectedResult = "<Engine" + LF.LINE_SEPARATOR
+                + "    name=\"Catalina\">" + LF.LINE_SEPARATOR + "  <Realm"
+                + LF.LINE_SEPARATOR + "    appName=\"Catalina\"/>"
+                + LF.LINE_SEPARATOR + "</Engine>" + LF.LINE_SEPARATOR;
+        check(aspectedResult);
+    }
+
+    protected void check(String aspectedResult) throws Exception {
+        factory.store(pWriter, -2, standardEngine);
+        assertEquals(aspectedResult, writer.toString());
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/test/src/share/org/apache/catalina/storeconfig/StandardHostSFTest.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/test/src/share/org/apache/catalina/storeconfig/StandardHostSFTest.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/test/src/share/org/apache/catalina/storeconfig/StandardHostSFTest.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,296 @@
+/*
+ * Copyright 1999-2001,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.storeconfig;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+import junit.framework.TestCase;
+
+import org.apache.catalina.LifecycleListener;
+import org.apache.catalina.Valve;
+import org.apache.catalina.cluster.CatalinaCluster;
+import org.apache.catalina.cluster.deploy.FarmWarDeployer;
+import org.apache.catalina.cluster.mcast.McastService;
+import org.apache.catalina.cluster.session.JvmRouteSessionIDBinderListener;
+import org.apache.catalina.cluster.tcp.ReplicationListener;
+import org.apache.catalina.cluster.tcp.ReplicationTransmitter;
+import org.apache.catalina.cluster.tcp.ReplicationValve;
+import org.apache.catalina.cluster.tcp.SimpleTcpCluster;
+import org.apache.catalina.core.StandardContext;
+import org.apache.catalina.core.StandardHost;
+import org.apache.catalina.realm.JAASRealm;
+
+/**
+ * @author Peter Rossbach
+ *  
+ */
+public class StandardHostSFTest extends TestCase {
+    StoreRegistry registry;
+
+    StringWriter writer = new StringWriter();
+
+    PrintWriter pWriter = new PrintWriter(writer);
+
+    StandardHost standardHost;
+
+    StandardHostSF factory;
+
+    StoreDescription desc;
+
+    /*
+     * create registry and register Host and all subelement descriptors
+     * 
+     * @see junit.framework.TestCase#setUp()
+     */
+    protected void setUp() throws Exception {
+
+        super.setUp();
+        registry = new StoreRegistry();
+        desc = new StoreDescription();
+        desc.setTag("Host");
+        desc.setTagClass("org.apache.catalina.core.StandardHost");
+        desc.setStandard(true);
+        desc.setStoreFactoryClass("org.apache.catalina.core.StandardHostSF");
+        desc.addTransientAttribute("domain");
+        registry.registerDescription(desc);
+        factory = new StandardHostSF();
+        desc.setStoreFactory(factory);
+        factory.setRegistry(registry);
+        StoreDescription listenerdesc = registerDescriptor("Listener",
+                LifecycleListener.class);
+
+        String listenerskippables[] = {
+                "org.apache.catalina.core.NamingContextListener",
+                "org.apache.catalina.startup.HostConfig", };
+        for (int i = 0; i < listenerskippables.length; i++)
+            listenerdesc.addTransientChild(listenerskippables[i]);
+
+        StoreDescription realmdesc = registerDescriptor("Realm",
+                JAASRealm.class,
+                "org.apache.catalina.storeconfig.StoreFactoryBase", false,
+                false);
+        StoreDescription contextdesc = registerDescriptor("Context",
+                StandardContext.class,
+                "org.apache.catalina.storeconfig.StoreFactoryBase", true, false);
+        String exceptions[] = { "available", "configFile", "configured",
+                "distributable", "domain", "engineName", "name", "publicId",
+                "sessionTimeout", "startupTime", "tldScanTime" };
+        for (int i = 0; i < exceptions.length; i++)
+            contextdesc.addTransientAttribute(exceptions[i]);
+
+        StoreDescription valvedesc = registerDescriptor("Valve", Valve.class,
+                "org.apache.catalina.storeconfig.StoreFactoryBase", false,
+                false);
+
+        String skippables[] = { "org.apache.catalina.core.StandardHostValve",
+                "org.apache.catalina.valves.CertificatesValve",
+                "org.apache.catalina.valves.ErrorReportValve",
+                "org.apache.catalina.valves.RequestListenerValve", };
+        for (int i = 0; i < skippables.length; i++)
+            valvedesc.addTransientChild(skippables[i]);
+
+        DescriptorHelper.registerClusterDescriptor(desc, registry);
+        standardHost = new StandardHost();
+        standardHost.setName("localhost");
+
+    }
+
+    private StoreDescription registerDescriptor(String tag, Class aClass) {
+        return registerDescriptor(tag, aClass,
+                "org.apache.catalina.storeconfig.StoreFactoryBase", false,
+                false);
+    }
+
+    private StoreDescription registerDescriptor(String tag, Class aClass,
+            String factoryClass, boolean fstandard, boolean fdefault) {
+        return DescriptorHelper.registerDescriptor(desc, registry, aClass
+                .getName(), tag, aClass.getName(), factoryClass, fstandard,
+                fdefault);
+    }
+
+    public void testStore() throws Exception {
+        standardHost
+                .addLifecycleListener(new org.apache.catalina.storeconfig.InfoLifecycleListener());
+        String aspectedResult = "<Host"
+                + LF.LINE_SEPARATOR
+                + "    name=\"localhost\">"
+                + LF.LINE_SEPARATOR
+                + "  <Listener className=\"org.apache.catalina.storeconfig.InfoLifecycleListener\"/>"
+                + LF.LINE_SEPARATOR + "</Host>" + LF.LINE_SEPARATOR;
+
+        check(aspectedResult);
+    }
+
+    public void testElements() throws Exception {
+        standardHost
+                .addLifecycleListener(new org.apache.catalina.storeconfig.InfoLifecycleListener());
+        standardHost
+                .addLifecycleListener(new org.apache.catalina.startup.HostConfig());
+        standardHost.setRealm(new JAASRealm());
+        StandardContext context = new StandardContext();
+        context.setDocBase("myapps");
+        context.setPath("/myapps");
+        standardHost.addChild(context);
+        standardHost.addAlias("jovi");
+        String aspectedResult = "<Host"
+                + LF.LINE_SEPARATOR
+                + "    name=\"localhost\">"
+                + LF.LINE_SEPARATOR
+                + "  <Listener className=\"org.apache.catalina.storeconfig.InfoLifecycleListener\"/>"
+                + LF.LINE_SEPARATOR + "  <Alias>jovi</Alias>"
+                + LF.LINE_SEPARATOR
+                + "  <Realm className=\"org.apache.catalina.realm.JAASRealm\""
+                + LF.LINE_SEPARATOR + "    appName=\"localhost\"/>"
+                + LF.LINE_SEPARATOR + "  <Context" + LF.LINE_SEPARATOR
+                + "    docBase=\"myapps\"" + LF.LINE_SEPARATOR
+                + "    path=\"/myapps\"/>" + LF.LINE_SEPARATOR + "</Host>"
+                + LF.LINE_SEPARATOR;
+        check(aspectedResult);
+    }
+
+    public void testValve() throws Exception {
+        standardHost
+                .addLifecycleListener(new org.apache.catalina.storeconfig.InfoLifecycleListener());
+        standardHost
+                .addValve(new org.apache.catalina.valves.ErrorReportValve());
+        standardHost
+                .addValve(new org.apache.catalina.valves.RequestDumperValve());
+        standardHost.addValve(new ReplicationValve());
+        String aspectedResult = "<Host"
+                + LF.LINE_SEPARATOR
+                + "    name=\"localhost\">"
+                + LF.LINE_SEPARATOR
+                + "  <Listener className=\"org.apache.catalina.storeconfig.InfoLifecycleListener\"/>"
+                + LF.LINE_SEPARATOR
+                + "  <Valve className=\"org.apache.catalina.valves.RequestDumperValve\"/>"
+                + LF.LINE_SEPARATOR + "</Host>" + LF.LINE_SEPARATOR;
+        check(aspectedResult);
+    }
+
+    public void testClusterEmpty() throws Exception {
+        CatalinaCluster cluster = new SimpleTcpCluster();
+        standardHost.setCluster(cluster);
+        String aspectedResult = "<Host"
+                + LF.LINE_SEPARATOR
+                + "    name=\"localhost\">"
+                + LF.LINE_SEPARATOR
+                + "  <Cluster className=\"org.apache.catalina.cluster.tcp.SimpleTcpCluster\">"
+                + LF.LINE_SEPARATOR + "  </Cluster>" + LF.LINE_SEPARATOR
+                + "</Host>" + LF.LINE_SEPARATOR;
+        check(aspectedResult);
+    }
+
+    public void testCluster() throws Exception {
+        SimpleTcpCluster cluster = new SimpleTcpCluster();
+        cluster.setClusterName("cluster");
+        cluster.setProperty("expireSessionsOnShutdown","false");
+        cluster
+                .setManagerClassName("org.apache.catalina.cluster.session.DeltaManager");
+        McastService service = new McastService();
+        service.setMcastAddr("228.0.0.4");
+        service.setMcastPort(45564);
+        service.setMcastFrequency(500l);
+        service.setMcastDropTime(3000l);
+        cluster.setMembershipService(service);
+        ReplicationListener receiver = new ReplicationListener();
+        receiver.setTcpListenAddress("auto");
+        receiver.setTcpListenPort(4001);
+        receiver.setTcpSelectorTimeout(100l);
+        receiver.setTcpThreadCount(6);
+        cluster.setClusterReceiver(receiver);
+        ReplicationTransmitter sender = new ReplicationTransmitter();
+        sender.setReplicationMode("pooled");
+        cluster.setClusterSender(sender);
+        ReplicationValve valve = new ReplicationValve();
+        valve
+                .setFilter(".*\\.gif;.*\\.js;.*\\.jpg;.*\\.jpeg;.*\\.htm;.*\\.html;.*\\.txt;");
+        cluster.addValve(valve);
+        FarmWarDeployer deployer = new FarmWarDeployer();
+        deployer.setTempDir("/tmp/war-temp/");
+        deployer.setDeployDir("/tmp/war-deploy/");
+        deployer.setWatchDir("/tmp/war-listen/");
+        deployer.setWatchEnabled(false);
+        cluster.setClusterDeployer(deployer);
+        standardHost.setCluster(cluster);
+        cluster.addLifecycleListener(new InfoLifecycleListener());
+        cluster.addClusterListener(new JvmRouteSessionIDBinderListener());
+        // DeltaManager is default!
+        String aspectedResult = "<Host"
+                + LF.LINE_SEPARATOR
+                + "    name=\"localhost\">"
+                + LF.LINE_SEPARATOR
+                + "  <Cluster className=\"org.apache.catalina.cluster.tcp.SimpleTcpCluster\""
+                + LF.LINE_SEPARATOR
+                + "      clusterName=\"cluster\">"
+                + LF.LINE_SEPARATOR
+                + "    <Membership className=\"org.apache.catalina.cluster.mcast.McastService\""
+                + LF.LINE_SEPARATOR
+                + "      mcastAddr=\"228.0.0.4\""
+                + LF.LINE_SEPARATOR
+                + "      mcastDropTime=\"3000\""
+                + LF.LINE_SEPARATOR
+                + "      mcastFrequency=\"500\""
+                + LF.LINE_SEPARATOR
+                + "      mcastPort=\"45564\"/>"
+                + LF.LINE_SEPARATOR
+                + "    <Sender className=\"org.apache.catalina.cluster.tcp.ReplicationTransmitter\""
+                + LF.LINE_SEPARATOR
+                + "      replicationMode=\"pooled\"/>"
+                + LF.LINE_SEPARATOR
+                + "    <Receiver className=\"org.apache.catalina.cluster.tcp.ReplicationListener\""
+                + LF.LINE_SEPARATOR
+                + "      tcpListenAddress=\"auto\""
+                + LF.LINE_SEPARATOR
+                + "      tcpListenPort=\"4001\""
+                + LF.LINE_SEPARATOR
+                + "      tcpSelectorTimeout=\"100\""
+                + LF.LINE_SEPARATOR
+                + "      tcpThreadCount=\"6\"/>"
+                + LF.LINE_SEPARATOR
+                + "    <Deployer className=\"org.apache.catalina.cluster.deploy.FarmWarDeployer\""
+                + LF.LINE_SEPARATOR
+                + "      deployDir=\"/tmp/war-deploy/\""
+                + LF.LINE_SEPARATOR
+                + "      tempDir=\"/tmp/war-temp/\""
+                + LF.LINE_SEPARATOR
+                + "      watchDir=\"/tmp/war-listen/\"/>"
+                + LF.LINE_SEPARATOR
+                + "    <Valve className=\"org.apache.catalina.cluster.tcp.ReplicationValve\""
+                + LF.LINE_SEPARATOR
+                + "      filter=\".*\\.gif;.*\\.js;.*\\.jpg;.*\\.jpeg;.*\\.htm;.*\\.html;.*\\.txt;\"/>"
+                + LF.LINE_SEPARATOR
+                + "    <Listener className=\"org.apache.catalina.storeconfig.InfoLifecycleListener\"/>"
+                + LF.LINE_SEPARATOR
+                + "    <ClusterListener className=\"org.apache.catalina.cluster.session.JvmRouteSessionIDBinderListener\"/>"
+                + LF.LINE_SEPARATOR + "  </Cluster>" + LF.LINE_SEPARATOR
+                + "</Host>" + LF.LINE_SEPARATOR;
+        check(aspectedResult);
+    }
+
+    public void testStoreEmpty() throws Exception {
+        String aspectedResult = "<Host" + LF.LINE_SEPARATOR
+                + "    name=\"localhost\">" + LF.LINE_SEPARATOR + "</Host>"
+                + LF.LINE_SEPARATOR;
+        check(aspectedResult);
+    }
+
+    protected void check(String aspectedResult) throws Exception {
+        factory.store(pWriter, -2, standardHost);
+        assertEquals(aspectedResult, writer.toString());
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/test/src/share/org/apache/catalina/storeconfig/StandardServiceSFTest.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/test/src/share/org/apache/catalina/storeconfig/StandardServiceSFTest.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/test/src/share/org/apache/catalina/storeconfig/StandardServiceSFTest.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,128 @@
+/*
+ * Copyright 1999-2001,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.storeconfig;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+import junit.framework.TestCase;
+
+import org.apache.catalina.LifecycleListener;
+import org.apache.catalina.connector.Connector;
+import org.apache.catalina.core.StandardEngine;
+import org.apache.catalina.core.StandardService;
+
+/**
+ * @author Peter Rossbach
+ *  
+ */
+public class StandardServiceSFTest extends TestCase {
+    StoreRegistry registry;
+
+    StringWriter writer = new StringWriter();
+
+    PrintWriter pWriter = new PrintWriter(writer);
+
+    StandardService standardService = new StandardService();
+
+    StandardServiceSF factory;
+
+    StoreDescription desc;
+
+    /*
+     * create registry and register Service and all direct subelement
+     * descriptors
+     * 
+     * @see junit.framework.TestCase#setUp()
+     */
+    protected void setUp() throws Exception {
+
+        super.setUp();
+        registry = new StoreRegistry();
+        desc = new StoreDescription();
+        desc.setTag("Service");
+        desc.setTagClass("org.apache.catalina.core.StandardService");
+        desc.setStandard(true);
+        desc.setStoreFactoryClass("org.apache.catalina.core.StandardServiceSF");
+        registry.registerDescription(desc);
+        factory = new StandardServiceSF();
+        desc.setStoreFactory(factory);
+        factory.setRegistry(registry);
+        registerDescriptor("Listener", LifecycleListener.class);
+        registerDescriptor("Engine", StandardEngine.class,
+                "org.apache.catalina.storeconfig.StoreFactoryBase", true, false);
+        StoreDescription cdesc = registerDescriptor("Connector",
+                Connector.class, "org.apache.catalina.storeconfig.ConnectorSF",
+                true, true);
+        cdesc.getStoreFactory().setStoreAppender(new ConnectorStoreAppender());
+        StoreDescription pdesc = DescriptorHelper
+                .registerDescriptor(null, registry, Connector.class.getName()
+                        + ".[ProtocolHandler]", "ProtocolHandler",
+                        Connector.class.getName(),
+                        "org.apache.catalina.storeconfig.StoreFactoryBase",
+                        true, false);
+        pdesc.addTransientAttribute("keystore");
+        pdesc.addTransientAttribute("keypass");
+        pdesc.addTransientAttribute("keytype");
+        pdesc.addTransientAttribute("randomfile");
+        pdesc.addTransientAttribute("protocols");
+        pdesc.addTransientAttribute("clientauth");
+        pdesc.addTransientAttribute("protocol");
+        pdesc.addTransientAttribute("port");
+        pdesc.addTransientAttribute("secure");
+
+    }
+
+    private StoreDescription registerDescriptor(String tag, Class aClass) {
+        return registerDescriptor(tag, aClass,
+                "org.apache.catalina.storeconfig.StoreFactoryBase", false,
+                false);
+    }
+
+    private StoreDescription registerDescriptor(String tag, Class aClass,
+            String factoryClass, boolean fstandard, boolean fdefault) {
+        return DescriptorHelper.registerDescriptor(desc, registry, aClass
+                .getName(), tag, aClass.getName(), factoryClass, fstandard,
+                fdefault);
+    }
+
+    public void testStoreAJP() throws Exception {
+        standardService
+                .addLifecycleListener(new org.apache.catalina.mbeans.ServerLifecycleListener());
+        Connector connector = new Connector();
+        standardService.addConnector(connector);
+        standardService.setContainer(new StandardEngine());
+        String aspectedResult = "<Service>"
+                + LF.LINE_SEPARATOR
+                + "  <Listener className=\"org.apache.catalina.mbeans.ServerLifecycleListener\"/>"
+                + LF.LINE_SEPARATOR + "  <Connector/>" + LF.LINE_SEPARATOR
+                + "  <Engine/>" + LF.LINE_SEPARATOR + "</Service>"
+                + LF.LINE_SEPARATOR;
+        check(aspectedResult);
+    }
+
+    public void testStoreEmpty() throws Exception {
+        String aspectedResult = "<Service>" + LF.LINE_SEPARATOR + "</Service>"
+                + LF.LINE_SEPARATOR;
+        check(aspectedResult);
+    }
+
+    protected void check(String aspectedResult) throws Exception {
+        factory.store(pWriter, -2, standardService);
+        assertEquals(aspectedResult, writer.toString());
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/test/src/share/org/apache/catalina/storeconfig/StoreAppenderTest.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/test/src/share/org/apache/catalina/storeconfig/StoreAppenderTest.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/test/src/share/org/apache/catalina/storeconfig/StoreAppenderTest.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,91 @@
+/*
+ * Copyright 1999-2001,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.storeconfig;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.StringReader;
+import java.io.StringWriter;
+
+import junit.framework.TestCase;
+
+import org.apache.catalina.cluster.tcp.ReplicationTransmitter;
+import org.apache.catalina.core.StandardServer;
+import org.apache.catalina.deploy.ContextResource;
+import org.apache.catalina.startup.SetAllPropertiesRule;
+import org.apache.tomcat.util.digester.Digester;
+import org.xml.sax.SAXException;
+
+/**
+ * @author Peter Rossbach
+ */
+public class StoreAppenderTest extends TestCase {
+
+    /**
+     * Create the digester which will be used to parse context config files.
+     */
+    protected Digester createDigester() {
+        Digester digester = new Digester();
+        digester.setValidating(false);
+        digester.addObjectCreate("Resource",
+                "org.apache.catalina.deploy.ContextResource");
+        digester.addRule("Resource", new SetAllPropertiesRule());
+        return digester;
+    }
+
+    public void testNormalResource() throws IOException, SAXException {
+        Digester digester = createDigester();
+        String example = "<Resource auth=\"Container\" name=\"jdbc/Emp\" type=\"javax.sql.DataSource\"/>";
+        StringReader reader = new StringReader(example);
+        ContextResource resource = (ContextResource) digester.parse(reader);
+        assertNotNull(resource);
+        assertEquals("javax.sql.DataSource", resource.getType());
+    }
+
+    public void testPropertyResouce() throws IOException, SAXException {
+        Digester digester = createDigester();
+        String example = "<Resource auth=\"Container\" name=\"mail/MailSession\" type=\"javax.mail.session\" mail.host=\"localhost\"/>";
+        StringReader reader = new StringReader(example);
+        ContextResource resource = (ContextResource) digester.parse(reader);
+        assertNotNull(resource);
+        assertEquals("localhost", resource.getProperty("mail.host"));
+    }
+
+    public void testStoreStandard() throws Exception {
+        StoreDescription desc = new StoreDescription();
+        desc.setStandard(true);
+        PrintWriter writer = new PrintWriter(new StringWriter());
+        StandardServer bean = new StandardServer();
+        new StoreAppender().printAttributes(writer, 0, true, bean, desc);
+    }
+
+    public void testStoreReplicationTransmitter() throws Exception {
+        StoreDescription desc = new StoreDescription();
+        desc.setStandard(true);
+        StringWriter swriter = new StringWriter();
+        PrintWriter writer = new PrintWriter(swriter);
+        ReplicationTransmitter bean = new ReplicationTransmitter();
+        bean.setReplicationMode("asynchronous");
+        bean.setProperty("keepAliveTimeout","80000");
+        new IDynamicPropertyStoreAppender().printAttributes(writer, 0, true, bean, desc);
+        String aspectedResult =LF.LINE_SEPARATOR           
+           + "    replicationMode=\"asynchronous\"" + LF.LINE_SEPARATOR 
+           + "    keepAliveTimeout=\"80000\"" ;
+        assertEquals(aspectedResult, swriter.getBuffer().toString());
+
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/test/src/share/org/apache/catalina/storeconfig/StoreContextAppenderTest.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/test/src/share/org/apache/catalina/storeconfig/StoreContextAppenderTest.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/test/src/share/org/apache/catalina/storeconfig/StoreContextAppenderTest.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,134 @@
+/*
+ * Created on 24.08.2004
+ *
+ * TODO To change the template for this generated file go to
+ * Window - Preferences - Java - Code Style - Code Templates
+ */
+package org.apache.catalina.storeconfig;
+
+import junit.framework.TestCase;
+
+import org.apache.catalina.core.StandardContext;
+import org.apache.catalina.core.StandardEngine;
+import org.apache.catalina.core.StandardHost;
+import org.apache.catalina.startup.ContextConfig;
+import java.io.File ;
+
+/**
+ * @author Peter Rossbach
+ *  
+ */
+public class StoreContextAppenderTest extends TestCase {
+
+    StoreContextAppender appender = new StoreContextAppender();
+
+    StandardContext context = new StandardContext();
+
+    StandardHost host = new StandardHost();
+
+    /*
+     * setup default Engine, Host and Context
+     * 
+     * @see junit.framework.TestCase#setUp()
+     */
+    protected void setUp() throws Exception {
+        host.setName("localhost");
+        context.setParent(host);
+        StandardEngine engine = new StandardEngine();
+        engine.setName("Catalina");
+        host.setParent(engine);
+        super.setUp();
+    }
+
+    public void testWorkDirManager() {
+        context.setPath("/manager");
+        String defaultDir = appender.getDefaultWorkDir(context);
+        assertEquals("work\\Catalina\\localhost\\manager", defaultDir);
+
+    }
+
+    public void testWorkDirRoot() {
+        context.setPath("");
+        String defaultDir = appender.getDefaultWorkDir(context);
+        assertEquals("work\\Catalina\\localhost\\_", defaultDir);
+    }
+
+    public void testHostWorkDirRoot() {
+        context.setPath("");
+        host.setWorkDir("hostwork");
+        String defaultDir = appender.getDefaultWorkDir(context);
+        assertEquals("hostwork\\_", defaultDir);
+    }
+
+    public void testIsPrintValueDefault() {
+        StandardContext context2 = new StandardContext();
+        context.setPath("");
+        context.setWorkDir("work\\Catalina\\localhost\\_");
+        assertFalse(appender.isPrintValue(context, context2, "workDir", null));
+    }
+
+    public void testIsPrintValue() {
+        StandardContext context2 = new StandardContext();
+        context.setPath("");
+        context.setWorkDir("C:\\work\\Catalina\\localhost\\_");
+        assertTrue(appender.isPrintValue(context, context2, "workDir", null));
+    }
+
+    public void testHostIsPrintValuedefault() {
+        StandardContext context2 = new StandardContext();
+        context.setPath("");
+        host.setWorkDir("hostwork");
+        context.setWorkDir("hostwork\\_");
+        assertFalse(appender.isPrintValue(context, context2, "workDir", null));
+    }
+
+    public void _testDefaultInstance() throws Exception {
+        assertTrue(context.getCookies());
+        assertFalse(context.getReloadable());
+        StandardContext defaultContext = (StandardContext) appender
+                .defaultInstance(context);
+        assertFalse(defaultContext.getCookies());
+        assertTrue(defaultContext.getReloadable());
+        assertEquals(2, defaultContext.findLifecycleListeners().length);
+        assertTrue(defaultContext.findLifecycleListeners()[0] instanceof ContextConfig);
+        assertTrue(defaultContext.findLifecycleListeners()[1] instanceof InfoLifecycleListener);
+    }
+
+    public void _testDefaultInstanceWithoutOverride() throws Exception {
+        context.setOverride(true);
+        StandardContext defaultContext = (StandardContext) appender
+                .defaultInstance(context);
+        assertEquals(0, defaultContext.findLifecycleListeners().length);
+
+    }
+    
+    public void testPath() throws Exception {
+        StandardContext defaultContext = (StandardContext) appender
+        .defaultInstance(context);
+        context.setPath("/myapps");
+        assertNull(context.getConfigFile());
+        StoreDescription desc = new StoreDescription();
+        desc.setExternalAllowed(true);
+        desc.setStoreSeparate(true);
+        assertTrue(appender.isPrintValue(context, defaultContext, "path", desc));
+        context.setConfigFile("conf/Catalina/locahost/myapps.xml");
+        assertFalse(appender.isPrintValue(context, defaultContext, "path", desc));
+        desc.setExternalAllowed(false);
+        assertFalse(appender.isPrintValue(context, defaultContext, "path", desc));
+        desc.setExternalAllowed(true);
+        desc.setStoreSeparate(false);
+        assertFalse(appender.isPrintValue(context, defaultContext, "path", desc));
+    }
+    
+    public void testDocBase() throws Exception {
+        StandardContext defaultContext = (StandardContext) appender
+        .defaultInstance(context);
+        context.setPath("/myapps");
+        context.setDocBase("myapps");
+        host.setAppBase("webapps");
+        assertFalse(appender.isPrintValue(context, defaultContext, "docBase", null));
+        context.setDocBase(System.getProperty("java.io.tmpdir") + "/myapps");
+        assertTrue(appender.isPrintValue(context, defaultContext, "docBase", null));
+        
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/test/src/share/org/apache/catalina/storeconfig/StoreLoaderTest.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/test/src/share/org/apache/catalina/storeconfig/StoreLoaderTest.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/test/src/share/org/apache/catalina/storeconfig/StoreLoaderTest.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,88 @@
+/*
+ * Copyright 1999-2001,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.storeconfig;
+
+import java.io.IOException;
+import java.io.StringReader;
+
+import junit.framework.TestCase;
+
+import org.apache.catalina.cluster.tcp.ReplicationTransmitter;
+import org.apache.catalina.core.StandardContext;
+import org.apache.catalina.core.StandardServer;
+import org.apache.catalina.mbeans.ServerLifecycleListener;
+import org.apache.tomcat.util.digester.Digester;
+import org.xml.sax.SAXException;
+
+/**
+ * @author Peter Rossbach
+ *  
+ */
+public class StoreLoaderTest extends TestCase {
+
+    public void testDigester() throws IOException, SAXException {
+        Digester digester = StoreLoader.createDigester();
+        String example = "<Registry name=\"Tomcat\" version=\"5.5.0\" encoding=\"UTF-8\" >"
+                + " <Description "
+                + "  tag=\"Server\""
+                + "	standard=\"true\""
+                + "	default=\"true\""
+                + "  tagClass=\"org.apache.catalina.core.StandardServer\""
+                + "  storeFactoryClass=\"org.apache.catalina.storeconfig.StandardServerSF\">"
+                + " </Description>" + "</Registry>";
+        StringReader reader = new StringReader(example);
+        StoreRegistry registry = (StoreRegistry) digester.parse(reader);
+        assertNotNull(registry);
+        assertEquals("Tomcat", registry.getName());
+        assertEquals("5.5.0", registry.getVersion());
+        StoreDescription desc = registry.findDescription(StandardServer.class);
+        assertNotNull(desc);
+        assertEquals("org.apache.catalina.core.StandardServer", desc
+                .getTagClass());
+        assertEquals("Server", desc.getTag());
+    }
+
+    public void testLoadRegistry() {
+        StoreLoader loader = new StoreLoader();
+        loader.load();
+        StoreRegistry registry = loader.getRegistry();
+        assertNotNull(registry);
+        assertEquals("UTF-8", registry.getEncoding());
+        StoreDescription desc = registry.findDescription(StandardServer.class);
+        assertNotNull(desc);
+        assertEquals("org.apache.catalina.core.StandardServer", desc
+                .getTagClass());
+        desc = registry.findDescription(StandardContext.class);
+        assertNotNull(desc);
+        assertEquals(StandardContext.class.getName(), desc.getTagClass());
+        assertTrue(desc.isStoreSeparate());
+        assertNotNull(desc.getStoreFactory());
+        assertEquals(registry, desc.getStoreFactory().getRegistry());
+        assertEquals(StandardContextSF.class, desc.getStoreFactory().getClass());
+        desc = registry
+                .findDescription("org.apache.catalina.core.StandardServer.[ServerLifecycleListener]");
+        assertEquals(ServerLifecycleListener.class.getName(), desc
+                .getTagClass());
+        desc = registry.findDescription(ReplicationTransmitter.class);
+        assertNotNull(desc);
+        assertEquals(ReplicationTransmitter.class.getName(), desc
+                .getTagClass());
+        assertNotNull(desc.getStoreFactory());
+        assertEquals(IDynamicPropertyStoreAppender.class, desc.getStoreFactory().getStoreAppender().getClass()
+                );
+        
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/test/src/share/org/apache/catalina/storeconfig/StoreRegistryTest.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/test/src/share/org/apache/catalina/storeconfig/StoreRegistryTest.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/test/src/share/org/apache/catalina/storeconfig/StoreRegistryTest.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,78 @@
+/*
+ * Copyright 1999-2001,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.storeconfig;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+import junit.framework.TestCase;
+
+import org.apache.catalina.core.StandardServer;
+
+/**
+ * @author Peter Rossbach
+ *  
+ */
+public class StoreRegistryTest extends TestCase {
+
+    StoreRegistry registry;
+
+    StringWriter writer = new StringWriter();
+
+    PrintWriter pWriter = new PrintWriter(writer);
+
+    StandardServer standardServer = new StandardServer();
+
+    IStoreFactory factory;
+
+    StoreDescription desc;
+
+    /*
+     * create registry and register Server 
+     * 
+     * @see junit.framework.TestCase#setUp()
+     */
+    protected void setUp() throws Exception {
+
+        super.setUp();
+        registry = new StoreRegistry();
+        desc = new StoreDescription();
+        desc.setTag("Server");
+        desc.setTagClass("org.apache.catalina.core.StandardServer");
+        desc.setStandard(true);
+        desc
+                .setStoreFactoryClass("org.apache.catalina.storeconfig.StoreFactoryBase");
+        registry.registerDescription(desc);
+        factory = new StoreFactoryBase();
+        factory.setRegistry(registry);
+    }
+
+    public void testSaveServer() throws Exception {
+        assertNotNull(registry.findDescription(StandardServer.class));
+        factory.store(pWriter, -2, standardServer);
+        assertEquals("XML Diff", "<Server/>" + LF.LINE_SEPARATOR, writer
+                .toString());
+    }
+
+    public void testAttributes() throws Exception {
+        standardServer.setPort(7305);
+        factory.store(pWriter, -2, standardServer);
+        assertEquals("XML Diff", "<Server" + LF.LINE_SEPARATOR
+                + "  port=\"7305\"/>" + LF.LINE_SEPARATOR, writer.toString());
+
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/to-do.txt
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/to-do.txt	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig/to-do.txt	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,9 @@
+1. Fix new connector properties and protocolhandler for 5.5 (testcases)
+	 Work!
+2. Fix context default handling (hard stuff)
+3. Check cluster transient attributes
+4. add documentation
+5. replace old server implementation instead current listener implementation
+6. Context path attribute handling ( delete at external context.xml and used inside server.xml!)
+7. Test with Admin App
+

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/build.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/build.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/build.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,138 @@
+<project name="StoreConfig" default="dist" basedir=".">
+
+
+	<!-- ===================== Initialize Property Values =================== -->
+
+	<!-- See "build.properties.sample" in the top level directory for all     -->
+	<!-- property values you must customize for successful building!!!        -->
+    <property file="../../../build/build.properties" />
+    <property file="../../../build/build.properties.default" />
+
+    <!-- Build Defaults -->
+    <property name="catalina.home"  location="../.."/>
+    <property name="catalina.build" location="../../../build/build"/>
+    <property name="config.build" value="${catalina.home}/modules/storeconfig/build" />
+	<property name="config.dist" value="${catalina.home}/modules/storeconfig/dist" />
+
+	<!-- Construct Catalina classpath -->
+	<path id="config.classpath">
+		<pathelement location="${catalina.build}/server/lib/catalina.jar" />
+		<pathelement location="${catalina.build}/server/lib/tomcat-util.jar" />
+		<pathelement location="${commons-logging.jar}" />
+		<pathelement location="${commons-modeler.jar}" />
+		<pathelement location="${jmx.jar}" />
+		<pathelement location="${catalina.build}/common/lib/servlet-api.jar" />
+	</path>
+
+	<!-- Source path -->
+	<path id="javadoc.sourcepath">
+		<pathelement location="src/share" />
+	</path>
+
+
+	<!-- =================== BUILD: Set compile flags ======================= -->
+	<target name="flags">
+		<!-- JDK flags -->
+		<available property="jdk.1.2.present" classname="java.util.HashMap" />
+		<available property="jdk.1.3.present" classname="java.lang.reflect.Proxy" />
+		<available property="jdk.1.4.present" classname="java.nio.Buffer" />
+	</target>
+
+
+	<!-- =================== BUILD: Set compile flags ======================= -->
+	<target name="flags.display" depends="flags" unless="flags.hide">
+
+		<echo message="--- Build environment for Catalina ---" />
+
+		<echo message="If ${property_name} is displayed, then the property is not set)" />
+
+		<echo message="--- Build options ---" />
+		<echo message="full.dist=${full.dist}" />
+		<echo message="build.sysclasspath=${build.sysclasspath}" />
+		<echo message="compile.debug=${compile.debug}" />
+		<echo message="compile.deprecation=${compile.deprecation}" />
+		<echo message="compile.optimize=${compile.optimize}" />
+		<echo message="compile.source=${compile.source}" />
+
+		<echo message="--- Ant Flags ---" />
+		<echo message="&lt;style&gt; task available (required)=${style.available}" />
+
+		<echo message="--- JDK ---" />
+		<echo message="jdk.1.2.present=${jdk.1.2.present}" />
+		<echo message="jdk.1.3.present=${jdk.1.3.present}" />
+		<echo message="jdk.1.4.present=${jdk.1.4.present}" />
+
+	</target>
+
+	<!-- =================== BUILD: Create Directories ====================== -->
+	<target name="build-prepare">
+		<mkdir dir="${catalina.build}" />
+		<mkdir dir="${catalina.build}/classes" />
+		<mkdir dir="${config.dist}" />
+	</target>
+
+
+
+
+	<!-- ================ BUILD: Compile Catalina Components ================ -->
+
+	<target name="build-catalina-config" depends="build-prepare">
+		<!-- Compile internal server components -->
+		<javac srcdir="${basedir}/src/share" destdir="${catalina.build}/classes" deprecation="${compile.deprecation}" debug="${compile.debug}" source="${compile.source}" optimize="${compile.optimize}" excludes="**/CVS/**">
+			<classpath refid="config.classpath" />
+		</javac>
+		<copy todir="${catalina.build}/classes/org/apache/catalina/storeconfig">
+			<fileset dir="${basedir}/src/share/org/apache/catalina/storeconfig">
+				<include name="*.properties" />
+				<include name="*.xml" />
+			</fileset>
+		</copy>
+	</target>
+
+
+	<!-- ================ BUILD: Create Catalina Javadocs =================== -->
+	<target name="javadoc">
+		<delete dir="${config.build}/javadoc" />
+		<mkdir dir="${config.build}/javadoc" />
+		<javadoc packagenames="org.apache.catalina.storeconfig.*" classpathref="config.classpath" sourcepathref="javadoc.sourcepath" destdir="${config.build}/javadoc" author="true" version="true" windowtitle="Catalina Internal StoreConfig API Documentation" doctitle="Catalina StoreConfig API" bottom="Copyright &#169; 2000-2004 Apache Software Foundation.  All Rights Reserved." />
+	</target>
+
+
+	<!-- ======================= BUILD: Clean Directory ===================== -->
+	<target name="build-clean">
+		<delete dir="${config.build}" />
+		<delete dir="${config.dist}" />
+        <delete>
+            <fileset dir="${catalina.build}/classes">
+                <include name="org/apache/catalina/storeconfig/**/*" />
+            </fileset>
+        </delete>
+	</target>
+
+
+	<!-- ==================== BUILD: Rebuild Everything ===================== -->
+
+
+
+
+	<!-- ================ DIST: Create Distribution ========================= -->
+	<target name="dist" depends="build-catalina-config">
+
+		<jar destfile="${config.dist}/catalina-storeconfig.jar" basedir="${catalina.build}/classes">
+			<include name="org/apache/catalina/storeconfig/**" />
+			<exclude name="**/package.html" />
+            <exclude name="**/LocalStrings_*" />
+		</jar>
+	</target>
+
+    <target name="copy" depends="dist" >
+       <copy file="${config.dist}/catalina-storeconfig.jar" todir="${catalina.build}/server/lib" />
+   </target>
+
+	<!-- ======================== DIST: Clean Directory ===================== -->
+
+
+	<!-- ====================== Convenient Synonyms ========================= -->
+
+
+</project>

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/docs/Readme.txt
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/docs/Readme.txt	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/docs/Readme.txt	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,63 @@
+Status:
+
+Peter Roßbach
+29.11.2004
+	
+Feature
+=========================
+	Backup context.xml
+	Backup für server.xml
+	Cluster Handling
+	Store all 5.5.5 elements
+	Context workDir default Handling
+	WatchedResource Default Handling
+	Write your own Registry
+		System Property -Dcatalina.storeconfig=file:../xxx.xml
+		${catalina.base}/conf bzw ${catalina.home}/conf
+		Classpath org.apache.catalina.storeconfig
+	JMX StoreConfig MBean
+		Store context.xml and server.xmls
+	Store Format is changeable with StoreAppenders
+	Easy extendable 
+	Connector support
+		AJP
+		HTTP
+		HTTPS
+	Context.xml and server.xml with backup				
+		 
+Example
+=========================
+	
+	<Server ...>
+	      <Listener className="org.apache.catalina.storeconfig.StoreConfigLifecycleListener"/>
+          <Service ...
+		  </Service>
+    </Server>
+	
+	Usages with JMX Adaptor 
+		ObjectName : Catalina:type=StoreConfig
+		
+		important operations:
+			storeConfig			Store complete server
+			storeServer			Store Server with ObjectName"               
+			   parameter name="objectname"
+                 description="Objectname from Server"
+                 default="Catalina:type=Server"
+			   parameter name="backup"
+                 description="store Context with backup"
+               parameter name="externalAllowed"
+                 description="store all Context external that have a configFile"
+            storeContext 		Store Context from ObjectName 
+               parameter name="objectname"
+                 description="ObjectName from Context"
+                 example="Catalina:j2eeType=WebModule,name=//localhost/manager,J2EEApplication=none,J2EEServer=none
+			   parameter name="backup"
+                 description="store with Backup"
+               parameter name="externalAllowed"
+                 description="store all or store only internal server.xml context (configFile == null)"
+			
+Have fun
+Peter Rossbach
+
+
+	

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/src/share/org/apache/catalina/storeconfig/CatalinaClusterSF.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/src/share/org/apache/catalina/storeconfig/CatalinaClusterSF.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/src/share/org/apache/catalina/storeconfig/CatalinaClusterSF.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,110 @@
+/*
+ * Copyright 1999-2001,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.storeconfig;
+
+import java.io.PrintWriter;
+
+import org.apache.catalina.LifecycleListener;
+import org.apache.catalina.Valve;
+import org.apache.catalina.ha.CatalinaCluster;
+import org.apache.catalina.ha.ClusterDeployer;
+import org.apache.catalina.tribes.ChannelReceiver;
+import org.apache.catalina.tribes.ChannelSender;
+import org.apache.catalina.tribes.MembershipService;
+import org.apache.catalina.tribes.MessageListener;
+import org.apache.catalina.ha.tcp.SimpleTcpCluster;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.catalina.tribes.ManagedChannel;
+import java.util.Iterator;
+import org.apache.catalina.ha.ClusterListener;
+
+/**
+ * Generate Cluster Element with Membership,Sender,Receiver,Deployer and
+ * ReplicationValve
+ * 
+ * @author Peter Rossbach
+ */
+public class CatalinaClusterSF extends StoreFactoryBase {
+
+    private static Log log = LogFactory.getLog(CatalinaClusterSF.class);
+
+    /**
+     * Store the specified Cluster childs.
+     * 
+     * @param aWriter
+     *            PrintWriter to which we are storing
+     * @param indent
+     *            Number of spaces to indent this element
+     * @param aCluster
+     *            Cluster whose properties are being stored
+     * 
+     * @exception Exception
+     *                if an exception occurs while storing
+     */
+    public void storeChilds(PrintWriter aWriter, int indent, Object aCluster,
+            StoreDescription parentDesc) throws Exception {
+        if (aCluster instanceof CatalinaCluster) {
+            CatalinaCluster cluster = (CatalinaCluster) aCluster;
+            
+            //store nested <Group> element
+            ManagedChannel channel = (ManagedChannel)cluster.getChannel();
+            if (channel != null ) {
+                storeElement(aWriter, indent, channel);
+
+                // Store nested <Membership> element
+                MembershipService service = channel.getMembershipService();
+                if (service != null) {
+                    storeElement(aWriter, indent, service);
+                }
+                // Store nested <Sender> element
+                ChannelSender sender = channel.getChannelSender();
+                if (sender != null) {
+                    storeElement(aWriter, indent, sender);
+                }
+                // Store nested <Receiver> element
+                ChannelReceiver receiver = channel.getChannelReceiver();
+                if (receiver != null) {
+                    storeElement(aWriter, indent, receiver);
+                }
+                
+                Iterator inti = channel.getInterceptors();
+                while ( inti.hasNext() ) {
+                    storeElement(aWriter,indent,inti.next());
+                }
+            }
+            // Store nested <Deployer> element
+            ClusterDeployer deployer = cluster.getClusterDeployer();
+            if (deployer != null) {
+                storeElement(aWriter, indent, deployer);
+            }
+            // Store nested <Valve> element
+            // ClusterValve are not store at Hosts element, see
+            Valve valves[] = cluster.getValves();
+            storeElementArray(aWriter, indent, valves);
+ 
+            if (aCluster instanceof SimpleTcpCluster) {
+                // Store nested <Listener> elements
+                LifecycleListener listeners[] = ((SimpleTcpCluster)cluster).findLifecycleListeners();
+                storeElementArray(aWriter, indent, listeners);
+                // Store nested <ClusterListener> elements
+                ClusterListener mlisteners[] = ((SimpleTcpCluster)cluster).findClusterListeners();
+                storeElementArray(aWriter, indent, mlisteners);
+            }            
+        }
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/src/share/org/apache/catalina/storeconfig/ConnectorSF.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/src/share/org/apache/catalina/storeconfig/ConnectorSF.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/src/share/org/apache/catalina/storeconfig/ConnectorSF.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,91 @@
+/**
+ * Copyright 1999-2001,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.storeconfig;
+
+import java.io.PrintWriter;
+
+import org.apache.catalina.Lifecycle;
+import org.apache.catalina.LifecycleListener;
+import org.apache.catalina.connector.Connector;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * Store Connector and Listeners
+ * 
+ * @author Peter Rossbach
+ */
+public class ConnectorSF extends StoreFactoryBase {
+
+    private static Log log = LogFactory.getLog(ConnectorSF.class);
+
+    /**
+     * Store Connector description
+     * 
+     * @param aWriter
+     * @param indent
+     * @param aConnector
+     * @throws Exception
+     */
+    public void storeChilds(PrintWriter aWriter, int indent, Object aConnector,
+            StoreDescription parentDesc) throws Exception {
+
+        if (aConnector instanceof Connector) {
+            Connector connector = (Connector) aConnector;
+            // Store nested <Listener> elements
+            if (connector instanceof Lifecycle) {
+                LifecycleListener listeners[] = ((Lifecycle) connector)
+                        .findLifecycleListeners();
+                storeElementArray(aWriter, indent, listeners);
+            }
+        }
+    }
+
+    protected void printOpenTag(PrintWriter aWriter, int indent, Object bean,
+            StoreDescription aDesc) throws Exception {
+        aWriter.print("<");
+        aWriter.print(aDesc.getTag());
+        storeConnectorAttribtues(aWriter, indent, bean, aDesc);
+        aWriter.println(">");
+    }
+
+    protected void storeConnectorAttribtues(PrintWriter aWriter, int indent,
+            Object bean, StoreDescription aDesc) throws Exception {
+        if (aDesc.isAttributes()) {
+            getStoreAppender().printAttributes(aWriter, indent, false, bean,
+                    aDesc);
+            /*
+             * if (bean instanceof Connector) { StoreDescription elementDesc =
+             * getRegistry().findDescription( bean.getClass().getName() +
+             * ".[ProtocolHandler]"); if (elementDesc != null) { ProtocolHandler
+             * protocolHandler = ((Connector) bean) .getProtocolHandler(); if
+             * (protocolHandler != null)
+             * getStoreAppender().printAttributes(aWriter, indent, false,
+             * protocolHandler, elementDesc); } }
+             */
+        }
+    }
+
+    protected void printTag(PrintWriter aWriter, int indent, Object bean,
+            StoreDescription aDesc) throws Exception {
+        aWriter.print("<");
+        aWriter.print(aDesc.getTag());
+        storeConnectorAttribtues(aWriter, indent, bean, aDesc);
+        aWriter.println("/>");
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/src/share/org/apache/catalina/storeconfig/ConnectorStoreAppender.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/src/share/org/apache/catalina/storeconfig/ConnectorStoreAppender.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/src/share/org/apache/catalina/storeconfig/ConnectorStoreAppender.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,281 @@
+/**
+ * Copyright 1999-2001,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.storeconfig;
+
+import java.beans.IndexedPropertyDescriptor;
+import java.beans.IntrospectionException;
+import java.beans.Introspector;
+import java.beans.PropertyDescriptor;
+import java.io.File;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.catalina.connector.Connector;
+import org.apache.coyote.ProtocolHandler;
+import org.apache.tomcat.util.IntrospectionUtils;
+
+/**
+ * Store the Connector attributes. Connector has really special design. A
+ * Connector is only a startup Wrapper for a ProtocolHandler. This meant that
+ * ProtocolHandler get all there attribtues from the Connector attribtue map.
+ * Strange is that some attributes change there name and the attribute
+ * sslProtocol need a sepzial handling
+ * 
+ * @author Peter Rossbach
+ *  
+ */
+public class ConnectorStoreAppender extends StoreAppender {
+
+    protected static HashMap replacements = new HashMap();
+    static {
+        replacements.put("backlog", "acceptCount");
+        replacements.put("soLinger", "connectionLinger");
+        replacements.put("soTimeout", "connectionTimeout");
+        replacements.put("timeout", "connectionUploadTimeout");
+        replacements.put("clientauth", "clientAuth");
+        replacements.put("keystore", "keystoreFile");
+        replacements.put("randomfile", "randomFile");
+        replacements.put("rootfile", "rootFile");
+        replacements.put("keypass", "keystorePass");
+        replacements.put("keytype", "keystoreType");
+        replacements.put("protocol", "sslProtocol");
+        replacements.put("protocols", "sslProtocols");
+    }
+
+    /**
+     * Store the relevant attributes of the specified JavaBean.
+     * 
+     * @param writer
+     *            PrintWriter to which we are storing
+     * @param include
+     *            Should we include a <code>className</code> attribute?
+     * @param bean
+     *            Bean whose properties are to be rendered as attributes,
+     * @param desc
+     *            RegistryDescrpitor from this bean
+     * 
+     * @exception Exception
+     *                if an exception occurs while storing
+     */
+    public void printAttributes(PrintWriter writer, int indent,
+            boolean include, Object bean, StoreDescription desc)
+            throws Exception {
+
+        // Render the relevant properties of this bean
+        String className = bean.getClass().getName();
+
+        // Render a className attribute if requested
+        if (include && desc != null && !desc.isStandard()) {
+            writer.print(" className=\"");
+            writer.print(bean.getClass().getName());
+            writer.print("\"");
+        }
+
+        List propertyKeys = getPropertyKeys((Connector) bean);
+        // Create blank instance
+        Object bean2 = defaultInstance(bean);
+        for (Iterator propertyIterator = propertyKeys.iterator(); propertyIterator
+                .hasNext();) {
+            String key = (String) propertyIterator.next();
+            if (replacements.get(key) != null) {
+                key = (String) replacements.get(key);
+            }
+            Object value = (Object) IntrospectionUtils.getProperty(bean, key);
+
+            if (desc.isTransientAttribute(key)) {
+                continue; // Skip the specified exceptions
+            }
+            if (value == null) {
+                continue; // Null values are not persisted
+            }
+            if (!isPersistable(value.getClass())) {
+                continue;
+            }
+            Object value2 = IntrospectionUtils.getProperty(bean2, key);
+            if (value.equals(value2)) {
+                // The property has its default value
+                continue;
+            }
+            if (isPrintValue(bean, bean2, key, desc))
+                printValue(writer, indent, key, value);
+        }
+        String protocol = ((Connector) bean).getProtocol();
+        if (protocol != null && !"HTTP/1.1".equals(protocol))
+            super.printValue(writer, indent, "protocol", protocol);
+
+    }
+
+    /**
+     * Get all properties from Connector and current ProtocolHandler
+     * 
+     * @param bean
+     * @return List of Connector Properties
+     * @throws IntrospectionException
+     */
+    protected List getPropertyKeys(Connector bean)
+            throws IntrospectionException {
+        ArrayList propertyKeys = new ArrayList();
+        // Acquire the list of properties for this bean
+        ProtocolHandler protocolHandler = bean.getProtocolHandler();
+        // Acquire the list of properties for this bean
+        PropertyDescriptor descriptors[] = Introspector.getBeanInfo(
+                bean.getClass()).getPropertyDescriptors();
+        if (descriptors == null) {
+            descriptors = new PropertyDescriptor[0];
+        }
+        for (int i = 0; i < descriptors.length; i++) {
+            if (descriptors[i] instanceof IndexedPropertyDescriptor) {
+                continue; // Indexed properties are not persisted
+            }
+            if (!isPersistable(descriptors[i].getPropertyType())
+                    || (descriptors[i].getReadMethod() == null)
+                    || (descriptors[i].getWriteMethod() == null)) {
+                continue; // Must be a read-write primitive or String
+            }
+            if ("protocol".equals(descriptors[i].getName())
+                    || "protocolHandlerClassName".equals(descriptors[i]
+                            .getName()))
+                continue;
+            propertyKeys.add(descriptors[i].getName());
+        }
+        for (Iterator propertyIterator = protocolHandler.getAttributeNames(); propertyIterator
+                .hasNext();) {
+            Object key = propertyIterator.next();
+            if (propertyKeys.contains(key))
+                continue;
+            propertyKeys.add(key);
+        }
+        return propertyKeys;
+    }
+
+    /**
+     * print Attributes
+     * 
+     * @param aWriter
+     * @param indent
+     * @param bean
+     * @param aDesc
+     * @throws Exception
+     */
+    protected void storeConnectorAttribtues(PrintWriter aWriter, int indent,
+            Object bean, StoreDescription aDesc) throws Exception {
+        if (aDesc.isAttributes()) {
+            printAttributes(aWriter, indent, false, bean, aDesc);
+        }
+    }
+
+    /*
+     * Print the open tag for connector attributes (override)
+     * 
+     * @see org.apache.catalina.storeconfig.StoreAppender#printOpenTag(java.io.PrintWriter,
+     *      int, java.lang.Object,
+     *      org.apache.catalina.storeconfig.StoreDescription)
+     */
+    public void printOpenTag(PrintWriter aWriter, int indent, Object bean,
+            StoreDescription aDesc) throws Exception {
+        aWriter.print("<");
+        aWriter.print(aDesc.getTag());
+        storeConnectorAttribtues(aWriter, indent, bean, aDesc);
+        aWriter.println(">");
+    }
+
+    /**
+     * print a tag for connector attributes (override)
+     * 
+     * @see org.apache.catalina.storeconfig.StoreAppender#printTag(java.io.PrintWriter,
+     *      int, java.lang.Object,
+     *      org.apache.catalina.storeconfig.StoreDescription)
+     */
+    public void printTag(PrintWriter aWriter, int indent, Object bean,
+            StoreDescription aDesc) throws Exception {
+        aWriter.print("<");
+        aWriter.print(aDesc.getTag());
+        storeConnectorAttribtues(aWriter, indent, bean, aDesc);
+        aWriter.println("/>");
+    }
+
+    /**
+     * print a value but replace attribute name
+     * 
+     * @param writer
+     * @param name
+     * @param value
+     * @see org.apache.catalina.storeconfig.StoreAppender#printValue(java.io.PrintWriter,
+     *      int, java.lang.String, java.lang.Object)
+     */
+    public void printValue(PrintWriter writer, int indent, String name,
+            Object value) {
+        String repl = name;
+        if (replacements.get(name) != null) {
+            repl = (String) replacements.get(name);
+        }
+        super.printValue(writer, indent, repl, value);
+    }
+    
+    /*
+     * Print Connector Values. <ul><li> Spezial handling to default jkHome.
+     * </li><li> Don't save catalina.base path at server.xml</li><li></ul>
+     * 
+     * @see org.apache.catalina.config.StoreAppender#isPrintValue(java.lang.Object,
+     *      java.lang.Object, java.lang.String,
+     *      org.apache.catalina.config.StoreDescription)
+     */
+    public boolean isPrintValue(Object bean, Object bean2, String attrName,
+            StoreDescription desc) {
+        boolean isPrint = super.isPrintValue(bean, bean2, attrName, desc);
+        if (isPrint) {
+            if ("jkHome".equals(attrName)) {
+                Connector connector = ((Connector) bean);
+                File catalinaBase = getCatalinaBase();
+                File jkHomeBase = getJkHomeBase((String) connector
+                        .getProperty("jkHome"), catalinaBase);
+                isPrint = !catalinaBase.equals(jkHomeBase);
+
+            }
+        }
+        return isPrint;
+    }
+
+    protected File getCatalinaBase() {
+
+        File appBase;
+        File file = new File(System.getProperty("catalina.base"));
+        try {
+            file = file.getCanonicalFile();
+        } catch (IOException e) {
+        }
+        return (file);
+    }
+
+    protected File getJkHomeBase(String jkHome, File appBase) {
+
+        File jkHomeBase;
+        File file = new File(jkHome);
+        if (!file.isAbsolute())
+            file = new File(appBase, jkHome);
+        try {
+            jkHomeBase = file.getCanonicalFile();
+        } catch (IOException e) {
+            jkHomeBase = file;
+        }
+        return (jkHomeBase);
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/src/share/org/apache/catalina/storeconfig/Constants.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/src/share/org/apache/catalina/storeconfig/Constants.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/src/share/org/apache/catalina/storeconfig/Constants.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,27 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.storeconfig;
+
+/**
+ * @author Peter Rossbach
+ *  
+ */
+public class Constants {
+
+    public static final String Package = "org.apache.catalina.storeconfig";
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/src/share/org/apache/catalina/storeconfig/GlobalNamingResourcesSF.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/src/share/org/apache/catalina/storeconfig/GlobalNamingResourcesSF.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/src/share/org/apache/catalina/storeconfig/GlobalNamingResourcesSF.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,77 @@
+/*
+ * Copyright 1999-2001,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.storeconfig;
+
+import java.io.PrintWriter;
+
+import org.apache.catalina.deploy.NamingResources;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * store server.xml GlobalNamingResource.
+ * 
+ * @author Peter Rossbach 
+ *  
+ */
+public class GlobalNamingResourcesSF extends StoreFactoryBase {
+    private static Log log = LogFactory.getLog(GlobalNamingResourcesSF.class);
+
+    /*
+     * Store with NamingResource Factory
+     * 
+     * @see org.apache.catalina.storeconfig.IStoreFactory#store(java.io.PrintWriter,
+     *      int, java.lang.Object)
+     */
+    public void store(PrintWriter aWriter, int indent, Object aElement)
+            throws Exception {
+
+        if (aElement instanceof NamingResources) {
+
+            StoreDescription elementDesc = getRegistry().findDescription(
+                    NamingResources.class.getName()
+                            + ".[GlobalNamingResources]");
+
+            if (elementDesc != null) {
+                getStoreAppender().printIndent(aWriter, indent + 2);
+                getStoreAppender().printOpenTag(aWriter, indent + 2, aElement,
+                        elementDesc);
+                NamingResources resources = (NamingResources) aElement;
+                StoreDescription resourcesdesc = getRegistry().findDescription(
+                        NamingResources.class.getName());
+                if (resourcesdesc != null) {
+                    resourcesdesc.getStoreFactory().store(aWriter, indent + 2,
+                            resources);
+                } else {
+                    if(log.isWarnEnabled())
+                        log.warn("Can't find NamingRsources Store Factory!");
+                }
+                    
+                getStoreAppender().printIndent(aWriter, indent + 2);
+                getStoreAppender().printCloseTag(aWriter, elementDesc);
+            } else {
+                if (log.isWarnEnabled())
+                    log.warn("Descriptor for element" + aElement.getClass()
+                            + " not configured!");
+            }
+        } else {
+            if (log.isWarnEnabled())
+                log.warn("wrong element " + aElement.getClass());
+
+        }
+    }
+}
+

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/src/share/org/apache/catalina/storeconfig/IDynamicPropertyStoreAppender.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/src/share/org/apache/catalina/storeconfig/IDynamicPropertyStoreAppender.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/src/share/org/apache/catalina/storeconfig/IDynamicPropertyStoreAppender.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,136 @@
+/**
+ * Copyright 1999-2001,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.storeconfig;
+
+import java.beans.IndexedPropertyDescriptor;
+import java.beans.IntrospectionException;
+import java.beans.Introspector;
+import java.beans.PropertyDescriptor;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.catalina.ha.util.IDynamicProperty;
+import org.apache.tomcat.util.IntrospectionUtils;
+
+/**
+ * Store the IDynamicProperty attributes. 
+ * 
+ * @author Peter Rossbach
+ *  
+ */
+public class IDynamicPropertyStoreAppender extends StoreAppender {
+
+    /**
+     * Store the relevant attributes of the specified JavaBean.
+     * 
+     * @param writer
+     *            PrintWriter to which we are storing
+     * @param include
+     *            Should we include a <code>className</code> attribute?
+     * @param bean
+     *            Bean whose properties are to be rendered as attributes,
+     * @param desc
+     *            RegistryDescrpitor from this bean
+     * 
+     * @exception Exception
+     *                if an exception occurs while storing
+     */
+    public void printAttributes(PrintWriter writer, int indent,
+            boolean include, Object bean, StoreDescription desc)
+            throws Exception {
+
+        // Render the relevant properties of this bean
+        String className = bean.getClass().getName();
+
+        // Render a className attribute if requested
+        if (include && desc != null && !desc.isStandard()) {
+            writer.print(" className=\"");
+            writer.print(bean.getClass().getName());
+            writer.print("\"");
+        }
+
+        if (bean instanceof IDynamicProperty) {
+            List propertyKeys = getPropertyKeys((IDynamicProperty) bean);
+            // Create blank instance
+            Object bean2 = defaultInstance(bean);
+            for (Iterator propertyIterator = propertyKeys.iterator(); propertyIterator
+                    .hasNext();) {
+                String key = (String) propertyIterator.next();
+                Object value = (Object) IntrospectionUtils.getProperty(bean,
+                        key);
+
+                if (desc.isTransientAttribute(key)) {
+                    continue; // Skip the specified exceptions
+                }
+                if (value == null) {
+                    continue; // Null values are not persisted
+                }
+                if (!isPersistable(value.getClass())) {
+                    continue;
+                }
+                Object value2 = IntrospectionUtils.getProperty(bean2, key);
+                if (value.equals(value2)) {
+                    // The property has its default value
+                    continue;
+                }
+                if (isPrintValue(bean, bean2, key, desc))
+                    printValue(writer, indent, key, value);
+            }
+        }
+    }
+
+    /**
+     * Get all properties from ReplicationTransmitter (also dynamic properties)
+     * 
+     * @param bean
+     * @return List of Connector Properties
+     * @throws IntrospectionException
+     */
+    protected List getPropertyKeys(IDynamicProperty bean)
+            throws IntrospectionException {
+        ArrayList propertyKeys = new ArrayList();
+        // Acquire the list of properties for this bean
+        PropertyDescriptor descriptors[] = Introspector.getBeanInfo(
+                bean.getClass()).getPropertyDescriptors();
+        if (descriptors == null) {
+            descriptors = new PropertyDescriptor[0];
+        }
+        for (int i = 0; i < descriptors.length; i++) {
+            if (descriptors[i] instanceof IndexedPropertyDescriptor) {
+                continue; // Indexed properties are not persisted
+            }
+            if (!isPersistable(descriptors[i].getPropertyType())
+                    || (descriptors[i].getReadMethod() == null)
+                    || (descriptors[i].getWriteMethod() == null)) {
+                continue; // Must be a read-write primitive or String
+            }
+            propertyKeys.add(descriptors[i].getName());
+        }
+        for (Iterator propertyIterator = bean.getPropertyNames(); propertyIterator
+                .hasNext();) {
+            Object key = propertyIterator.next();
+            if (propertyKeys.contains(key))
+                continue;
+            if ("className".equals(key))
+                continue;
+            propertyKeys.add(key);
+        }
+        return propertyKeys;
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/src/share/org/apache/catalina/storeconfig/IStoreConfig.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/src/share/org/apache/catalina/storeconfig/IStoreConfig.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/src/share/org/apache/catalina/storeconfig/IStoreConfig.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,136 @@
+/*
+ * Copyright 1999-2001,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.storeconfig;
+
+import java.io.PrintWriter;
+
+import org.apache.catalina.Context;
+import org.apache.catalina.Host;
+import org.apache.catalina.Server;
+import org.apache.catalina.Service;
+
+/**
+ * @author Peter Rossbach 
+ *  
+ */
+public interface IStoreConfig {
+
+    /**
+     * Get Configuration Registry
+     * 
+     * @return aRegistry that handle the store operations
+     */
+    StoreRegistry getRegistry();
+
+    /**
+     * Set Configuration Registry
+     * 
+     * @param aRegistry
+     *            aregistry that handle the store operations
+     */
+    void setRegistry(StoreRegistry aRegistry);
+
+    /**
+     * Store the current StoreFactory Server.
+     * 
+     * @exception Exception
+     *                if an exception occurs while storing
+     */
+    void storeConfig() throws Exception;
+
+    /**
+     * Store the specified Server properties.
+     * 
+     * @param aServer
+     *            Object to be stored
+     * 
+     * @exception Exception
+     *                if an exception occurs while storing
+     */
+    void store(Server aServer) throws Exception;
+
+    /**
+     * Store the specified Server properties.
+     * 
+     * @param aWriter
+     *            PrintWriter to which we are storing
+     * @param indent
+     *            Number of spaces to indent this element
+     * @param aServer
+     *            Object to be stored
+     * 
+     * @exception Exception
+     *                if an exception occurs while storing
+     */
+    void store(PrintWriter aWriter, int indent, Server aServer);
+
+    /**
+     * Store the specified Service properties.
+     * 
+     * @param aWriter
+     *            PrintWriter to which we are storing
+     * @param indent
+     *            Number of spaces to indent this element
+     * @param aService
+     *            Object to be stored
+     * 
+     * @exception Exception
+     *                if an exception occurs while storing
+     */
+    void store(PrintWriter aWriter, int indent, Service aService);
+
+    /**
+     * Store the specified Host properties.
+     * 
+     * @param aWriter
+     *            PrintWriter to which we are storing
+     * @param indent
+     *            Number of spaces to indent this element
+     * @param aHost
+     *            Object to be stored
+     * 
+     * @exception Exception
+     *                if an exception occurs while storing
+     */
+    void store(PrintWriter aWriter, int indent, Host aHost);
+
+    /**
+     * Store the specified Context properties.
+     * 
+     * @param aContext
+     *            Object to be stored
+     * 
+     * @exception Exception
+     *                if an exception occurs while storing
+     */
+    void store(Context aContext);
+
+    /**
+     * Store the specified Context properties.
+     * 
+     * @param aWriter
+     *            PrintWriter to which we are storing
+     * @param indent
+     *            Number of spaces to indent this element
+     * @param aContext
+     *            Object to be stored
+     * 
+     * @exception Exception
+     *                if an exception occurs while storing
+     */
+    void store(PrintWriter aWriter, int indent, Context aContext);
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/src/share/org/apache/catalina/storeconfig/IStoreFactory.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/src/share/org/apache/catalina/storeconfig/IStoreFactory.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/src/share/org/apache/catalina/storeconfig/IStoreFactory.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,37 @@
+/*
+ * Copyright 1999-2001,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.storeconfig;
+
+import java.io.PrintWriter;
+
+/**
+ * @author Peter Rossbach 
+ *  
+ */
+public interface IStoreFactory {
+    StoreAppender getStoreAppender();
+
+    void setStoreAppender(StoreAppender storeWriter);
+
+    void setRegistry(StoreRegistry aRegistry);
+
+    StoreRegistry getRegistry();
+
+    void store(PrintWriter aWriter, int indent, Object aElement)
+            throws Exception;
+
+    void storeXMLHead(PrintWriter aWriter);
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/src/share/org/apache/catalina/storeconfig/InstanceListenerSF.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/src/share/org/apache/catalina/storeconfig/InstanceListenerSF.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/src/share/org/apache/catalina/storeconfig/InstanceListenerSF.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,60 @@
+/*
+ * Copyright 1999-2001,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.storeconfig;
+
+import java.io.PrintWriter;
+
+import org.apache.catalina.core.StandardContext;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * Store Context InstanceListener
+ * 
+ * @author Peter Rossbach 
+ *  
+ */
+public class InstanceListenerSF extends StoreFactoryBase {
+    private static Log log = LogFactory.getLog(InstanceListenerSF.class);
+
+    /*
+     * Store nested Element Value Arrays
+     * 
+     * @see org.apache.catalina.config.IStoreFactory#store(java.io.PrintWriter,
+     *      int, java.lang.Object)
+     */
+    public void store(PrintWriter aWriter, int indent, Object aElement)
+            throws Exception {
+        if (aElement instanceof StandardContext) {
+            StoreDescription elementDesc = getRegistry().findDescription(
+                    aElement.getClass().getName() + ".[InstanceListener]");
+            String[] listeners = ((StandardContext) aElement)
+                    .findInstanceListeners();
+            if (elementDesc != null) {
+                if (log.isDebugEnabled())
+                    log.debug("store " + elementDesc.getTag() + "( " + aElement
+                            + " )");
+                getStoreAppender().printTagArray(aWriter, "InstanceListener",
+                        indent, listeners);
+            }
+        } else {
+            if (log.isWarnEnabled())
+                log.warn("Descriptor for element" + aElement.getClass()
+                        + ".[InstanceListener] not configured!");
+        }
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/src/share/org/apache/catalina/storeconfig/LoaderSF.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/src/share/org/apache/catalina/storeconfig/LoaderSF.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/src/share/org/apache/catalina/storeconfig/LoaderSF.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2004-2005 The Apache Software Foundation.
+ * 
+ * Licensed 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.storeconfig;
+
+import java.io.PrintWriter;
+
+import org.apache.catalina.Loader;
+import org.apache.catalina.loader.WebappLoader;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * Store Loader Element.
+ * 
+ * @author Peter Rossbach
+ */
+public class LoaderSF extends StoreFactoryBase {
+
+    private static Log log = LogFactory.getLog(LoaderSF.class);
+
+    /**
+     * Store the only the Loader elements, when not default
+     * 
+     * @see NamingResourcesSF#storeChilds(PrintWriter, int, Object, StoreDescription)
+     */
+    public void store(PrintWriter aWriter, int indent, Object aElement)
+            throws Exception {
+        StoreDescription elementDesc = getRegistry().findDescription(
+                aElement.getClass());
+        if (elementDesc != null) {
+            Loader loader = (Loader) aElement;
+            if (!isDefaultLoader(loader)) {
+                if (log.isDebugEnabled())
+                    log.debug("store " + elementDesc.getTag() + "( " + aElement
+                            + " )");
+                getStoreAppender().printIndent(aWriter, indent + 2);
+                getStoreAppender().printTag(aWriter, indent + 2, loader,
+                        elementDesc);
+            }
+        } else {
+            if (log.isWarnEnabled()) {
+                log
+                        .warn("Descriptor for element"
+                                + aElement.getClass()
+                                + " not configured or element class not StandardManager!");
+            }
+        }
+    }
+
+    /**
+     * Is this an instance of the default <code>Loader</code> configuration,
+     * with all-default properties?
+     * 
+     * @param loader
+     *            Loader to be tested
+     */
+    protected boolean isDefaultLoader(Loader loader) {
+
+        if (!(loader instanceof WebappLoader)) {
+            return (false);
+        }
+        WebappLoader wloader = (WebappLoader) loader;
+        if ((wloader.getDelegate() != false)
+                || !wloader.getLoaderClass().equals(
+                        "org.apache.catalina.loader.WebappClassLoader")) {
+            return (false);
+        }
+        return (true);
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/src/share/org/apache/catalina/storeconfig/LocalStrings.properties
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/src/share/org/apache/catalina/storeconfig/LocalStrings.properties	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/src/share/org/apache/catalina/storeconfig/LocalStrings.properties	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,2 @@
+factory.storeTag=store tag {0} ( Object: {1} )
+factory.storeNoDescriptor=Descriptor for element class {0} not configured!

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/src/share/org/apache/catalina/storeconfig/ManagerSF.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/src/share/org/apache/catalina/storeconfig/ManagerSF.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/src/share/org/apache/catalina/storeconfig/ManagerSF.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2004-2005 The Apache Software Foundation.
+ * 
+ * Licensed 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.storeconfig;
+
+import java.io.PrintWriter;
+
+import org.apache.catalina.session.StandardManager;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * Store server.xml Manager element
+ * 
+ * @author Peter Rossbach
+ */
+public class ManagerSF extends StoreFactoryBase {
+
+    private static Log log = LogFactory.getLog(ManagerSF.class);
+
+    /**
+     * Store the only the Manager elements
+     * 
+     * @see NamingResourcesSF#storeChilds(PrintWriter, int, Object, StoreDescription)
+     */
+    public void store(PrintWriter aWriter, int indent, Object aElement)
+            throws Exception {
+        StoreDescription elementDesc = getRegistry().findDescription(
+                aElement.getClass());
+        if (elementDesc != null && aElement instanceof StandardManager) {
+            StandardManager manager = (StandardManager) aElement;
+            if (!isDefaultManager(manager)) {
+                if (log.isDebugEnabled())
+                    log.debug(sm.getString("factory.storeTag", elementDesc
+                            .getTag(), aElement));
+                getStoreAppender().printIndent(aWriter, indent + 2);
+                getStoreAppender().printTag(aWriter, indent + 2, manager,
+                        elementDesc);
+            }
+        } else {
+            if (log.isWarnEnabled())
+                log.warn(sm.getString("factory.storeNoDescriptor", aElement
+                        .getClass()));
+        }
+    }
+
+    /**
+     * Is this an instance of the default <code>Manager</code> configuration,
+     * with all-default properties?
+     * 
+     * @param smanager
+     *            Manager to be tested
+     */
+    protected boolean isDefaultManager(StandardManager smanager) {
+
+        if (!"SESSIONS.ser".equals(smanager.getPathname())
+                || !"java.security.SecureRandom".equals(smanager
+                        .getRandomClass())
+                || (smanager.getMaxActiveSessions() != -1)
+                || !"MD5".equals(smanager.getAlgorithm())) {
+            return (false);
+        }
+        return (true);
+
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/src/share/org/apache/catalina/storeconfig/NamingResourcesSF.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/src/share/org/apache/catalina/storeconfig/NamingResourcesSF.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/src/share/org/apache/catalina/storeconfig/NamingResourcesSF.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,107 @@
+/*
+ * Copyright 2004-2005 The Apache Software Foundation.
+ * 
+ * Licensed 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.storeconfig;
+
+import java.io.PrintWriter;
+
+import org.apache.catalina.deploy.ContextEjb;
+import org.apache.catalina.deploy.ContextEnvironment;
+import org.apache.catalina.deploy.ContextLocalEjb;
+import org.apache.catalina.deploy.ContextResource;
+import org.apache.catalina.deploy.ContextResourceEnvRef;
+import org.apache.catalina.deploy.ContextResourceLink;
+import org.apache.catalina.deploy.NamingResources;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * Store server.xml elements Resources at context and GlobalNamingResources
+ * 
+ * @author Peter Rossbach
+ *  
+ */
+public class NamingResourcesSF extends StoreFactoryBase {
+    private static Log log = LogFactory.getLog(NamingResourcesSF.class);
+
+    /**
+     * Store the only the NamingResources elements
+     * 
+     * @see NamingResourcesSF#storeChilds(PrintWriter, int, Object, StoreDescription)
+     */
+    public void store(PrintWriter aWriter, int indent, Object aElement)
+            throws Exception {
+        StoreDescription elementDesc = getRegistry().findDescription(
+                aElement.getClass());
+        if (elementDesc != null) {
+            if (log.isDebugEnabled())
+                log.debug("store " + elementDesc.getTag() + "( " + aElement
+                        + " )");
+            storeChilds(aWriter, indent, aElement, elementDesc);
+        } else {
+            if (log.isWarnEnabled())
+                log.warn("Descriptor for element" + aElement.getClass()
+                        + " not configured!");
+        }
+    }
+
+    /**
+     * Store the specified NamingResources properties.
+     * 
+     * @param aWriter
+     *            PrintWriter to which we are storing
+     * @param indent
+     *            Number of spaces to indent this element
+     * @param aElement
+     *            Object whose properties are being stored
+     * @param elementDesc
+     *            element descriptor
+     * 
+     * @exception Exception
+     *                if an exception occurs while storing
+     * 
+     * @see org.apache.catalina.storeconfig.StoreFactoryBase#storeChilds(java.io.PrintWriter,
+     *      int, java.lang.Object, StoreDescription)
+     */
+    public void storeChilds(PrintWriter aWriter, int indent, Object aElement,
+            StoreDescription elementDesc) throws Exception {
+
+        if (aElement instanceof NamingResources) {
+            NamingResources resources = (NamingResources) aElement;
+            // Store nested <Ejb> elements
+            ContextEjb[] ejbs = resources.findEjbs();
+            storeElementArray(aWriter, indent, ejbs);
+            // Store nested <Environment> elements
+            ContextEnvironment[] envs = resources.findEnvironments();
+            storeElementArray(aWriter, indent, envs);
+            // Store nested <LocalEjb> elements
+            ContextLocalEjb[] lejbs = resources.findLocalEjbs();
+            storeElementArray(aWriter, indent, lejbs);
+
+            // Store nested <Resource> elements
+            ContextResource[] dresources = resources.findResources();
+            storeElementArray(aWriter, indent, dresources);
+
+            // Store nested <ResourceEnvRef> elements
+            ContextResourceEnvRef[] resEnv = resources.findResourceEnvRefs();
+            storeElementArray(aWriter, indent, resEnv);
+
+            // Store nested <ResourceLink> elements
+            ContextResourceLink[] resourceLinks = resources.findResourceLinks();
+            storeElementArray(aWriter, indent, resourceLinks);
+        }
+    }
+}
+

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/src/share/org/apache/catalina/storeconfig/PersistentManagerSF.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/src/share/org/apache/catalina/storeconfig/PersistentManagerSF.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/src/share/org/apache/catalina/storeconfig/PersistentManagerSF.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,60 @@
+/*
+ * Copyright 1999-2001,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.storeconfig;
+
+import java.io.PrintWriter;
+
+import org.apache.catalina.Store;
+import org.apache.catalina.session.PersistentManager;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * store server.xml PersistentManager element with nested "Store"
+ * 
+ * @author Peter Rossbach
+ */
+public class PersistentManagerSF extends StoreFactoryBase {
+
+    private static Log log = LogFactory.getLog(PersistentManagerSF.class);
+
+    /**
+     * Store the specified PersistentManager properties.
+     * 
+     * @param aWriter
+     *            PrintWriter to which we are storing
+     * @param indent
+     *            Number of spaces to indent this element
+     * @param aManager
+     *            PersistentManager whose properties are being stored
+     * 
+     * @exception Exception
+     *                if an exception occurs while storing
+     */
+    public void storeChilds(PrintWriter aWriter, int indent, Object aManager,
+            StoreDescription parentDesc) throws Exception {
+        if (aManager instanceof PersistentManager) {
+            PersistentManager manager = (PersistentManager) aManager;
+
+            // Store nested <Manager> elements
+            Store store = manager.getStore();
+            storeElement(aWriter, indent, store);
+
+        }
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/src/share/org/apache/catalina/storeconfig/StandardContextSF.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/src/share/org/apache/catalina/storeconfig/StandardContextSF.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/src/share/org/apache/catalina/storeconfig/StandardContextSF.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,349 @@
+/*
+ * Copyright 2004-2005 The Apache Software Foundation.
+ * 
+ * Licensed 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.storeconfig;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.naming.directory.DirContext;
+
+import org.apache.catalina.Container;
+import org.apache.catalina.Context;
+import org.apache.catalina.Engine;
+import org.apache.catalina.Host;
+import org.apache.catalina.Lifecycle;
+import org.apache.catalina.LifecycleListener;
+import org.apache.catalina.Loader;
+import org.apache.catalina.Manager;
+import org.apache.catalina.Pipeline;
+import org.apache.catalina.Realm;
+import org.apache.catalina.Valve;
+import org.apache.catalina.core.StandardContext;
+import org.apache.catalina.deploy.ApplicationParameter;
+import org.apache.catalina.deploy.NamingResources;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.naming.resources.ProxyDirContext;
+
+/**
+ * Store server.xml Context element with all childs
+ * <ul>
+ * <li>Store all context at server.xml</li>
+ * <li>Store existing app.xml context a conf/enginename/hostname/app.xml</li>
+ * <li>Store with backup</li>
+ * </ul>
+ * 
+ * @author Peter Rossbach
+ */
+public class StandardContextSF extends StoreFactoryBase {
+
+    private static Log log = LogFactory.getLog(StandardContextSF.class);
+
+    /*
+     * Store a Context as Separate file as configFile value from context exists.
+     * filename can be relative to catalina.base.
+     * 
+     * @see org.apache.catalina.config.IStoreFactory#store(java.io.PrintWriter,
+     *      int, java.lang.Object)
+     */
+    public void store(PrintWriter aWriter, int indent, Object aContext)
+            throws Exception {
+
+        if (aContext instanceof StandardContext) {
+            StoreDescription desc = getRegistry().findDescription(
+                    aContext.getClass());
+            if (desc.isStoreSeparate()) {
+                String configFile = ((StandardContext) aContext)
+                        .getConfigFile();
+                if (configFile != null) {
+                    if (desc.isExternalAllowed()) {
+                        if (desc.isBackup())
+                            storeWithBackup((StandardContext) aContext);
+                        else
+                            storeContextSeparate(aWriter, indent,
+                                    (StandardContext) aContext);
+                        return;
+                    }
+                }
+            }
+        }
+        super.store(aWriter, indent, aContext);
+
+    }
+
+    /**
+     * Store a Context without backup add separate file or when configFile =
+     * null a aWriter.
+     * 
+     * @param aWriter
+     * @param indent
+     * @param aContext
+     * @throws Exception
+     */
+    protected void storeContextSeparate(PrintWriter aWriter, int indent,
+            StandardContext aContext) throws Exception {
+        String configFile = aContext.getConfigFile();
+        PrintWriter writer = null;
+        if (configFile != null) {
+            File config = new File(configFile);
+            if (!config.isAbsolute()) {
+                config = new File(System.getProperty("catalina.base"),
+                        configFile);
+            }
+            if (log.isInfoEnabled())
+                log.info("Store Context " + aContext.getPath()
+                        + " separate at file " + config);
+            try {
+                writer = new PrintWriter(new OutputStreamWriter(
+                        new FileOutputStream(config), getRegistry()
+                                .getEncoding()));
+                storeXMLHead(writer);
+                super.store(writer, -2, aContext);
+            } finally {
+                if (writer != null) {
+                    try {
+                        writer.flush();
+                    } catch (Exception e) {
+                        ;
+                    }
+                    try {
+                        writer.close();
+                    } catch (Throwable t) {
+                        ;
+                    }
+                }
+            }
+        } else {
+            super.store(aWriter, indent, aContext);
+        }
+    }
+
+    /**
+     * Store the Context with a Backup
+     * 
+     * @param aContext
+     * @throws Exception
+     */
+    protected void storeWithBackup(StandardContext aContext) throws Exception {
+        StoreFileMover mover = getConfigFileWriter((Context) aContext);
+        if (mover != null) {
+            if (log.isInfoEnabled())
+                log.info("Store Context " + aContext.getPath()
+                        + " separate with backup (at file "
+                        + mover.getConfigSave() + " )");
+            PrintWriter writer = mover.getWriter();
+            try {
+                storeXMLHead(writer);
+                super.store(writer, -2, aContext);
+            } finally {
+                // Flush and close the output file
+                try {
+                    writer.flush();
+                } catch (Exception e) {
+                    log.error(e);
+                }
+                try {
+                    writer.close();
+                } catch (Exception e) {
+                    throw (e);
+                }
+            }
+            mover.move();
+        }
+    }
+
+    /**
+     * Get explicit writer for context (context.getConfigFile()).
+     * 
+     * @param context
+     * @return The file mover
+     * @throws IOException
+     */
+    protected StoreFileMover getConfigFileWriter(Context context)
+            throws IOException {
+        String configFile = context.getConfigFile();
+        PrintWriter writer = null;
+        StoreFileMover mover = null;
+        if (configFile != null) {
+            File config = new File(configFile);
+            if (!config.isAbsolute()) {
+                config = new File(System.getProperty("catalina.base"),
+                        configFile);
+            }
+            // Open an output writer for the new configuration file
+            mover = new StoreFileMover("", config.getCanonicalPath(),
+                    getRegistry().getEncoding());
+        }
+        return mover;
+    }
+
+    /**
+     * Store the specified Host properties.
+     * 
+     * @param aWriter
+     *            PrintWriter to which we are storing
+     * @param indent
+     *            Number of spaces to indent this element
+     * @param aContext
+     *            Context whose properties are being stored
+     * 
+     * @exception Exception
+     *                if an exception occurs while storing
+     */
+    public void storeChilds(PrintWriter aWriter, int indent, Object aContext,
+            StoreDescription parentDesc) throws Exception {
+        if (aContext instanceof StandardContext) {
+            StandardContext context = (StandardContext) aContext;
+            // Store nested <Listener> elements
+            if (context instanceof Lifecycle) {
+                LifecycleListener listeners[] = context
+                        .findLifecycleListeners();
+                storeElementArray(aWriter, indent, listeners);
+            }
+            // Store nested <Valve> elements
+            if (context instanceof Pipeline) {
+                Valve valves[] = ((Pipeline) context).getValves();
+                storeElementArray(aWriter, indent, valves);
+            }
+
+            // Store nested <Loader> elements
+            Loader loader = context.getLoader();
+            storeElement(aWriter, indent, loader);
+
+            // Store nested <Manager> elements
+            Manager manager = context.getManager();
+            storeElement(aWriter, indent, manager);
+
+            // Store nested <Realm> element
+            Realm realm = context.getRealm();
+            if (realm != null) {
+                Realm parentRealm = null;
+                // @TODO is this case possible?
+                if (context.getParent() != null) {
+                    parentRealm = context.getParent().getRealm();
+                }
+                if (realm != parentRealm) {
+                    storeElement(aWriter, indent, realm);
+
+                }
+            }
+            // Store nested resources
+            DirContext resources = context.getResources();
+            if (resources instanceof ProxyDirContext)
+                resources = ((ProxyDirContext) resources).getDirContext();
+            storeElement(aWriter, indent, resources);
+
+            // Store nested <InstanceListener> elements
+            String iListeners[] = context.findInstanceListeners();
+            getStoreAppender().printTagArray(aWriter, "InstanceListener",
+                    indent + 2, iListeners);
+
+            // Store nested <WrapperListener> elements
+            String wLifecycles[] = context.findWrapperLifecycles();
+            getStoreAppender().printTagArray(aWriter, "WrapperListener",
+                    indent + 2, wLifecycles);
+            // Store nested <WrapperLifecycle> elements
+            String wListeners[] = context.findWrapperListeners();
+            getStoreAppender().printTagArray(aWriter, "WrapperLifecycle",
+                    indent + 2, wListeners);
+
+            // Store nested <Parameter> elements
+            ApplicationParameter[] appParams = context
+                    .findApplicationParameters();
+            storeElementArray(aWriter, indent, appParams);
+
+            // Store nested naming resources elements (EJB,Resource,...)
+            NamingResources nresources = context.getNamingResources();
+            storeElement(aWriter, indent, nresources);
+
+            // Store nested watched resources <WatchedResource>
+            String[] wresources = context.findWatchedResources();
+            wresources = filterWatchedResources(context, wresources);
+            getStoreAppender().printTagArray(aWriter, "WatchedResource",
+                    indent + 2, wresources);
+        }
+    }
+
+    /**
+     * Return a File object representing the "configuration root" directory for
+     * our associated Host.
+     */
+    protected File configBase(Context context) {
+
+        File file = new File(System.getProperty("catalina.base"), "conf");
+        Container host = (Host) context.getParent();
+
+        if ((host != null) && (host instanceof Host)) {
+            Container engine = host.getParent();
+            if ((engine != null) && (engine instanceof Engine)) {
+                file = new File(file, engine.getName());
+            }
+            file = new File(file, host.getName());
+            try {
+                file = file.getCanonicalFile();
+            } catch (IOException e) {
+                log.error(e);
+            }
+        }
+        return (file);
+
+    }
+
+    /**
+     * filter out the default watched resources
+     * 
+     * @param context
+     * @param wresources
+     * @return The watched resources
+     * @throws IOException
+     * TODO relative watchedresource
+     * TODO absolute handling configFile
+     * TODO Filename case handling for Windows?
+     * TODO digester variable subsitution $catalina.base, $catalina.home
+     */
+    protected String[] filterWatchedResources(StandardContext context,
+            String[] wresources) throws IOException {
+        File configBase = configBase(context);
+        String confContext = new File(System.getProperty("catalina.base"),
+                "conf/context.xml").getCanonicalPath();
+        String confHostDefault = new File(configBase, "context.xml.default")
+                .getCanonicalPath();
+        String configFile = context.getConfigFile();
+        String webxml = "WEB-INF/web.xml" ;
+        
+        List resource = new ArrayList();
+        for (int i = 0; i < wresources.length; i++) {
+
+            if (wresources[i].equals(confContext))
+                continue;
+            if (wresources[i].equals(confHostDefault))
+                continue;
+            if (wresources[i].equals(configFile))
+                continue;
+            if (wresources[i].equals(webxml))
+                continue;
+            resource.add(wresources[i]);
+        }
+        return (String[]) resource.toArray(new String[resource.size()]);
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/src/share/org/apache/catalina/storeconfig/StandardEngineSF.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/src/share/org/apache/catalina/storeconfig/StandardEngineSF.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/src/share/org/apache/catalina/storeconfig/StandardEngineSF.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,89 @@
+/*
+ * Copyright 1999-2001,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.storeconfig;
+
+import java.io.PrintWriter;
+
+import org.apache.catalina.Container;
+import org.apache.catalina.Lifecycle;
+import org.apache.catalina.LifecycleListener;
+import org.apache.catalina.Pipeline;
+import org.apache.catalina.Realm;
+import org.apache.catalina.Valve;
+import org.apache.catalina.core.StandardEngine;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * Store server.xml Element Engine
+ * 
+ * @author Peter Rossbach
+ */
+public class StandardEngineSF extends StoreFactoryBase {
+
+    private static Log log = LogFactory.getLog(StandardEngineSF.class);
+
+    /**
+     * Store the specified Engine properties.
+     * 
+     * @param aWriter
+     *            PrintWriter to which we are storing
+     * @param indent
+     *            Number of spaces to indent this element
+     * @param aEngine
+     *            Object whose properties are being stored
+     * 
+     * @exception Exception
+     *                if an exception occurs while storing
+     */
+    public void storeChilds(PrintWriter aWriter, int indent, Object aEngine,
+            StoreDescription parentDesc) throws Exception {
+        if (aEngine instanceof StandardEngine) {
+            StandardEngine engine = (StandardEngine) aEngine;
+            // Store nested <Listener> elements
+            if (engine instanceof Lifecycle) {
+                LifecycleListener listeners[] = ((Lifecycle) engine)
+                        .findLifecycleListeners();
+                storeElementArray(aWriter, indent, listeners);
+            }
+
+            // Store nested <Realm> element
+            Realm realm = engine.getRealm();
+            if (realm != null) {
+                Realm parentRealm = null;
+                // TODO is this case possible? (see it a old Server 5.0 impl)
+                if (engine.getParent() != null) {
+                    parentRealm = engine.getParent().getRealm();
+                }
+                if (realm != parentRealm) {
+                    storeElement(aWriter, indent, realm);
+
+                }
+            }
+
+            // Store nested <Valve> elements
+            if (engine instanceof Pipeline) {
+                Valve valves[] = ((Pipeline) engine).getValves();
+                storeElementArray(aWriter, indent, valves);
+
+            }
+            // store all <Host> elements
+            Container children[] = engine.findChildren();
+            storeElementArray(aWriter, indent, children);
+        }
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/src/share/org/apache/catalina/storeconfig/StandardHostSF.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/src/share/org/apache/catalina/storeconfig/StandardHostSF.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/src/share/org/apache/catalina/storeconfig/StandardHostSF.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,111 @@
+/*
+ * Copyright 1999-2001,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.storeconfig;
+
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.catalina.Cluster;
+import org.apache.catalina.Container;
+import org.apache.catalina.Lifecycle;
+import org.apache.catalina.LifecycleListener;
+import org.apache.catalina.Pipeline;
+import org.apache.catalina.Realm;
+import org.apache.catalina.Valve;
+import org.apache.catalina.ha.ClusterValve;
+import org.apache.catalina.core.StandardHost;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * Store server.xml Element Host
+ * 
+ * @author Peter Rossbach
+ */
+public class StandardHostSF extends StoreFactoryBase {
+
+    private static Log log = LogFactory.getLog(StandardHostSF.class);
+
+    /**
+     * Store the specified Host properties and childs
+     * (Listener,Alias,Realm,Valve,Cluster, Context)
+     * 
+     * @param aWriter
+     *            PrintWriter to which we are storing
+     * @param indent
+     *            Number of spaces to indent this element
+     * @param aHost
+     *            Host whose properties are being stored
+     * 
+     * @exception Exception
+     *                if an exception occurs while storing
+     */
+    public void storeChilds(PrintWriter aWriter, int indent, Object aHost,
+            StoreDescription parentDesc) throws Exception {
+        if (aHost instanceof StandardHost) {
+            StandardHost host = (StandardHost) aHost;
+            // Store nested <Listener> elements
+            if (host instanceof Lifecycle) {
+                LifecycleListener listeners[] = ((Lifecycle) host)
+                        .findLifecycleListeners();
+                storeElementArray(aWriter, indent, listeners);
+            }
+
+            // Store nested <Alias> elements
+            String aliases[] = host.findAliases();
+            getStoreAppender().printTagArray(aWriter, "Alias", indent + 2,
+                    aliases);
+
+            // Store nested <Realm> element
+            Realm realm = host.getRealm();
+            if (realm != null) {
+                Realm parentRealm = null;
+                if (host.getParent() != null) {
+                    parentRealm = host.getParent().getRealm();
+                }
+                if (realm != parentRealm) {
+                    storeElement(aWriter, indent, realm);
+                }
+            }
+
+            // Store nested <Valve> elements
+            if (host instanceof Pipeline) {
+                Valve valves[] = ((Pipeline) host).getValves();
+                if(valves != null && valves.length > 0 ) {
+                    List hostValves = new ArrayList() ;
+                    for(int i = 0 ; i < valves.length ; i++ ) {
+                        if(!( valves[i] instanceof ClusterValve))
+                            hostValves.add(valves[i]);
+                    }                
+                    storeElementArray(aWriter, indent, hostValves.toArray());
+                }
+            }
+
+            // store all <Cluster> elements
+            Cluster cluster = host.getCluster();
+            if (cluster != null) {
+                storeElement(aWriter, indent, cluster);
+            }
+
+            // store all <Context> elements
+            Container children[] = host.findChildren();
+            storeElementArray(aWriter, indent, children);
+        }
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/src/share/org/apache/catalina/storeconfig/StandardServerSF.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/src/share/org/apache/catalina/storeconfig/StandardServerSF.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/src/share/org/apache/catalina/storeconfig/StandardServerSF.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,110 @@
+/*
+ * Copyright 2004-2005 The Apache Software Foundation.
+ * 
+ * Licensed 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.storeconfig;
+
+import java.io.PrintWriter;
+
+import org.apache.catalina.Lifecycle;
+import org.apache.catalina.LifecycleListener;
+import org.apache.catalina.Service;
+import org.apache.catalina.core.StandardServer;
+import org.apache.catalina.deploy.NamingResources;
+import org.apache.catalina.mbeans.ServerLifecycleListener;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * Store server.xml Server element and childs (
+ * Listener,GlobalNamingResource,Service)
+ * 
+ * @author Peter Rossbach
+ */
+public class StandardServerSF extends StoreFactoryBase {
+
+    private static Log log = LogFactory.getLog(StandardServerSF.class);
+
+    /**
+     * Store the specified Server properties.
+     * 
+     * @param aWriter
+     *            PrintWriter to which we are storing
+     * @param indent
+     *            Number of spaces to indent this element
+     * @param aServer
+     *            Object to be stored
+     * 
+     * @exception Exception
+     *                if an exception occurs while storing
+     * @see org.apache.catalina.storeconfig.IStoreFactory#store(java.io.PrintWriter,
+     *      int, java.lang.Object)
+     */
+    public void store(PrintWriter aWriter, int indent, Object aServer)
+            throws Exception {
+        storeXMLHead(aWriter);
+        super.store(aWriter, indent, aServer);
+    }
+
+    /**
+     * Store Childs from this StandardServer descrition
+     * 
+     * @param aWriter
+     * @param indent
+     * @param aObject
+     * @param parentDesc
+     * @throws Exception
+     */
+    public void storeChilds(PrintWriter aWriter, int indent, Object aObject,
+            StoreDescription parentDesc) throws Exception {
+        if (aObject instanceof StandardServer) {
+            StandardServer server = (StandardServer) aObject;
+            // Store nested <Listener> elements
+            if (server instanceof Lifecycle) {
+                LifecycleListener listeners[] = ((Lifecycle) server)
+                        .findLifecycleListeners();
+                storeElementArray(aWriter, indent, listeners);
+                LifecycleListener listener = null;
+                for (int i = 0; listener == null && i < listeners.length; i++)
+                    if (listeners[i] instanceof ServerLifecycleListener)
+                        listener = listeners[i];
+                if (listener != null) {
+                    StoreDescription elementDesc = getRegistry()
+                            .findDescription(
+                                    StandardServer.class.getName()
+                                            + ".[ServerLifecycleListener]");
+                    if (elementDesc != null) {
+                        elementDesc.getStoreFactory().store(aWriter, indent,
+                                listener);
+                    }
+                }
+            }
+            // Store nested <GlobalNamingResources> element
+            NamingResources globalNamingResources = server
+                    .getGlobalNamingResources();
+            StoreDescription elementDesc = getRegistry().findDescription(
+                    NamingResources.class.getName()
+                            + ".[GlobalNamingResources]");
+            if (elementDesc != null) {
+                elementDesc.getStoreFactory().store(aWriter, indent,
+                        globalNamingResources);
+            }
+            // Store nested <Service> elements
+            Service services[] = server.findServices();
+            storeElementArray(aWriter, indent, services);
+        }
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/src/share/org/apache/catalina/storeconfig/StandardServiceSF.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/src/share/org/apache/catalina/storeconfig/StandardServiceSF.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/src/share/org/apache/catalina/storeconfig/StandardServiceSF.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,73 @@
+/*
+ * Copyright 1999-2001,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.storeconfig;
+
+import java.io.PrintWriter;
+
+import org.apache.catalina.Container;
+import org.apache.catalina.Lifecycle;
+import org.apache.catalina.LifecycleListener;
+import org.apache.catalina.connector.Connector;
+import org.apache.catalina.core.StandardService;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * Store server.xml Element Service and all childs 
+ * @author Peter Rossbach (pero at apache.org)
+ */
+public class StandardServiceSF extends StoreFactoryBase {
+
+    private static Log log = LogFactory.getLog(StandardServiceSF.class);
+
+    /**
+     * Store Childs from this StandardService description
+     * 
+     * @param aWriter
+     * @param indent
+     * @param aService
+     * @throws Exception
+     */
+    public void storeChilds(PrintWriter aWriter, int indent, Object aService,
+            StoreDescription parentDesc) throws Exception {
+        if (aService instanceof StandardService) {
+            StandardService service = (StandardService) aService;
+            // Store nested <Listener> elements
+            if (service instanceof Lifecycle) {
+                LifecycleListener listeners[] = ((Lifecycle) service)
+                        .findLifecycleListeners();
+                storeElementArray(aWriter, indent, listeners);
+            }
+
+            Connector connectors[] = service.findConnectors();
+            storeElementArray(aWriter, indent, connectors);
+
+            // Store nested <Engine> element (or other appropriate container)
+            Container container = service.getContainer();
+            if (container != null) {
+                StoreDescription elementDesc = getRegistry().findDescription(
+                        container.getClass());
+                if (elementDesc != null) {
+                    IStoreFactory factory = elementDesc.getStoreFactory();
+                    factory.store(aWriter, indent, container);
+                }
+            }
+        }
+
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/src/share/org/apache/catalina/storeconfig/StoreAppender.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/src/share/org/apache/catalina/storeconfig/StoreAppender.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/src/share/org/apache/catalina/storeconfig/StoreAppender.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,382 @@
+/*
+ * Copyright 2004-2005 The Apache Software Foundation.
+ * 
+ * Licensed 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.storeconfig;
+
+import java.beans.IndexedPropertyDescriptor;
+import java.beans.Introspector;
+import java.beans.PropertyDescriptor;
+import java.io.PrintWriter;
+import java.util.Iterator;
+
+import org.apache.catalina.deploy.ResourceBase;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.tomcat.util.IntrospectionUtils;
+
+/**
+ * StoreAppends generate really the xml tag elements
+ * 
+ * @author Peter Rossbach
+ *  
+ */
+public class StoreAppender {
+    private static Log log = LogFactory.getLog(StoreAppender.class);
+
+    /**
+     * The set of classes that represent persistable properties.
+     */
+    private static Class persistables[] = { String.class, Integer.class,
+            Integer.TYPE, Boolean.class, Boolean.TYPE, Byte.class, Byte.TYPE,
+            Character.class, Character.TYPE, Double.class, Double.TYPE,
+            Float.class, Float.TYPE, Long.class, Long.TYPE, Short.class,
+            Short.TYPE, };
+
+    /**
+     * print the closing tag
+     * 
+     * @param aWriter
+     * @param aDesc
+     * @throws Exception
+     */
+    public void printCloseTag(PrintWriter aWriter, StoreDescription aDesc)
+            throws Exception {
+        aWriter.print("</");
+        aWriter.print(aDesc.getTag());
+        aWriter.println(">");
+    }
+
+    /**
+     * print only the open tag with all attributes
+     * 
+     * @param aWriter
+     * @param indent
+     * @param bean
+     * @param aDesc
+     * @throws Exception
+     */
+    public void printOpenTag(PrintWriter aWriter, int indent, Object bean,
+            StoreDescription aDesc) throws Exception {
+        aWriter.print("<");
+        aWriter.print(aDesc.getTag());
+        if (aDesc.isAttributes() && bean != null)
+            printAttributes(aWriter, indent, bean, aDesc);
+        aWriter.println(">");
+    }
+
+    /**
+     * Print tag with all attributes
+     * 
+     * @param aWriter
+     * @param indent
+     * @param bean
+     * @param aDesc
+     * @throws Exception
+     */
+    public void printTag(PrintWriter aWriter, int indent, Object bean,
+            StoreDescription aDesc) throws Exception {
+        aWriter.print("<");
+        aWriter.print(aDesc.getTag());
+        if (aDesc.isAttributes() && bean != null)
+            printAttributes(aWriter, indent, bean, aDesc);
+        aWriter.println("/>");
+    }
+
+    /**
+     * print the value from tag as content
+     * 
+     * @param aWriter
+     * @param tag
+     * @param content
+     * @throws Exception
+     */
+    public void printTagContent(PrintWriter aWriter, String tag, String content)
+            throws Exception {
+        aWriter.print("<");
+        aWriter.print(tag);
+        aWriter.print(">");
+        aWriter.print(convertStr(content));
+        aWriter.print("</");
+        aWriter.print(tag);
+        aWriter.println(">");
+    }
+
+    /**
+     * print an array of values
+     * 
+     * @param aWriter
+     * @param tag
+     * @param indent
+     * @param elements
+     */
+    public void printTagValueArray(PrintWriter aWriter, String tag, int indent,
+            String[] elements) {
+        if (elements != null && elements.length > 0) {
+            printIndent(aWriter, indent + 2);
+            aWriter.print("<");
+            aWriter.print(tag);
+            aWriter.print(">");
+            for (int i = 0; i < elements.length; i++) {
+                printIndent(aWriter, indent + 4);
+                aWriter.print(elements[i]);
+                if (i + 1 < elements.length)
+                    aWriter.println(",");
+            }
+            printIndent(aWriter, indent + 2);
+            aWriter.print("</");
+            aWriter.print(tag);
+            aWriter.println(">");
+        }
+    }
+
+    /**
+     * print a array of elements
+     * 
+     * @param aWriter
+     * @param tag
+     * @param indent
+     * @param elements
+     */
+    public void printTagArray(PrintWriter aWriter, String tag, int indent,
+            String[] elements) throws Exception {
+        if (elements != null) {
+            for (int i = 0; i < elements.length; i++) {
+                printIndent(aWriter, indent);
+                printTagContent(aWriter, tag, elements[i]);
+            }
+        }
+    }
+
+    /**
+     * Print some spaces
+     * 
+     * @param aWriter
+     * @param indent
+     *            number of spaces
+     */
+    public void printIndent(PrintWriter aWriter, int indent) {
+        for (int i = 0; i < indent; i++) {
+            aWriter.print(' ');
+        }
+    }
+
+    /**
+     * Store the relevant attributes of the specified JavaBean, plus a
+     * <code>className</code> attribute defining the fully qualified Java
+     * class name of the bean.
+     * 
+     * @param writer
+     *            PrintWriter to which we are storing
+     * @param bean
+     *            Bean whose properties are to be rendered as attributes,
+     * 
+     * @exception Exception
+     *                if an exception occurs while storing
+     */
+    public void printAttributes(PrintWriter writer, int indent, Object bean,
+            StoreDescription desc) throws Exception {
+
+        printAttributes(writer, indent, true, bean, desc);
+
+    }
+
+    /**
+     * Store the relevant attributes of the specified JavaBean.
+     * 
+     * @param writer
+     *            PrintWriter to which we are storing
+     * @param include
+     *            Should we include a <code>className</code> attribute?
+     * @param bean
+     *            Bean whose properties are to be rendered as attributes,
+     * @param desc
+     *            RegistryDescrpitor from this bean
+     * 
+     * @exception Exception
+     *                if an exception occurs while storing
+     */
+    public void printAttributes(PrintWriter writer, int indent,
+            boolean include, Object bean, StoreDescription desc)
+            throws Exception {
+
+        // Render the relevant properties of this bean
+        String className = bean.getClass().getName();
+
+        // Render a className attribute if requested
+        if (include && desc != null && !desc.isStandard()) {
+            writer.print(" className=\"");
+            writer.print(bean.getClass().getName());
+            writer.print("\"");
+        }
+
+        // Acquire the list of properties for this bean
+        PropertyDescriptor descriptors[] = Introspector.getBeanInfo(
+                bean.getClass()).getPropertyDescriptors();
+        if (descriptors == null) {
+            descriptors = new PropertyDescriptor[0];
+        }
+
+        // Create blank instance
+        Object bean2 = defaultInstance(bean);
+        for (int i = 0; i < descriptors.length; i++) {
+            if (descriptors[i] instanceof IndexedPropertyDescriptor) {
+                continue; // Indexed properties are not persisted
+            }
+            if (!isPersistable(descriptors[i].getPropertyType())
+                    || (descriptors[i].getReadMethod() == null)
+                    || (descriptors[i].getWriteMethod() == null)) {
+                continue; // Must be a read-write primitive or String
+            }
+            if (desc.isTransientAttribute(descriptors[i].getName())) {
+                continue; // Skip the specified exceptions
+            }
+            Object value = IntrospectionUtils.getProperty(bean, descriptors[i]
+                    .getName());
+            if (value == null) {
+                continue; // Null values are not persisted
+            }
+            Object value2 = IntrospectionUtils.getProperty(bean2,
+                    descriptors[i].getName());
+            if (value.equals(value2)) {
+                // The property has its default value
+                continue;
+            }
+            if (isPrintValue(bean, bean2, descriptors[i].getName(), desc))
+                printValue(writer, indent, descriptors[i].getName(), value);
+        }
+
+        if (bean instanceof ResourceBase) {
+            ResourceBase resource = (ResourceBase) bean;
+            for (Iterator iter = resource.listProperties(); iter.hasNext();) {
+                String name = (String) iter.next();
+                Object value = resource.getProperty(name);
+                if (!isPersistable(value.getClass())) {
+                    continue;
+                }
+                if (desc.isTransientAttribute(name)) {
+                    continue; // Skip the specified exceptions
+                }
+                printValue(writer, indent, name, value);
+
+            }
+        }
+    }
+
+    /**
+     * print this Attribute value or not
+     * 
+     * @param bean
+     *            orginal bean
+     * @param bean2
+     *            default bean
+     * @param attrName
+     *            attribute name
+     * @param desc
+     *            StoreDescription from bean
+     * @return True if it's a printing value
+     */
+    public boolean isPrintValue(Object bean, Object bean2, String attrName,
+            StoreDescription desc) {
+        boolean printValue = false;
+
+        Object value = IntrospectionUtils.getProperty(bean, attrName);
+        if (value != null) {
+            Object value2 = IntrospectionUtils.getProperty(bean2, attrName);
+            printValue = !value.equals(value2);
+
+        }
+        return printValue;
+    }
+
+    /**
+     * generate default Instance
+     * 
+     * @param bean
+     * @return an object from same class as bean parameter
+     * @throws InstantiationException
+     * @throws IllegalAccessException
+     */
+    public Object defaultInstance(Object bean) throws InstantiationException,
+            IllegalAccessException {
+        return bean.getClass().newInstance();
+    }
+
+    /**
+     * print an attribute value
+     * 
+     * @param writer
+     * @param name
+     * @param value
+     */
+    public void printValue(PrintWriter writer, int indent, String name,
+            Object value) {
+        if (!(value instanceof String)) {
+            value = value.toString();
+        }
+        writer.println();
+        printIndent(writer, indent + 4);
+        writer.print(name);
+        writer.print("=\"");
+        String strValue = convertStr((String) value);
+        writer.print(strValue);
+        writer.print("\"");
+    }
+
+    /**
+     * Given a string, this method replaces all occurrences of ' <', '>', '&',
+     * and '"'.
+     */
+    public String convertStr(String input) {
+
+        StringBuffer filtered = new StringBuffer(input.length());
+        char c;
+        for (int i = 0; i < input.length(); i++) {
+            c = input.charAt(i);
+            if (c == '<') {
+                filtered.append("&lt;");
+            } else if (c == '>') {
+                filtered.append("&gt;");
+            } else if (c == '\'') {
+                filtered.append("&apos;");
+            } else if (c == '"') {
+                filtered.append("&quot;");
+            } else if (c == '&') {
+                filtered.append("&amp;");
+            } else {
+                filtered.append(c);
+            }
+        }
+        return (filtered.toString());
+    }
+
+    /**
+     * Is the specified property type one for which we should generate a
+     * persistence attribute?
+     * 
+     * @param clazz
+     *            Java class to be tested
+     */
+    protected boolean isPersistable(Class clazz) {
+
+        for (int i = 0; i < persistables.length; i++) {
+            if (persistables[i] == clazz) {
+                return (true);
+            }
+        }
+        return (false);
+
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/src/share/org/apache/catalina/storeconfig/StoreConfig.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/src/share/org/apache/catalina/storeconfig/StoreConfig.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/src/share/org/apache/catalina/storeconfig/StoreConfig.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,346 @@
+/*
+ * Copyright 2004-2005 The Apache Software Foundation.
+ * 
+ * Licensed 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.storeconfig;
+
+import java.io.PrintWriter;
+
+import javax.management.MBeanServer;
+import javax.management.MalformedObjectNameException;
+import javax.management.ObjectName;
+
+import org.apache.catalina.Context;
+import org.apache.catalina.Host;
+import org.apache.catalina.Server;
+import org.apache.catalina.ServerFactory;
+import org.apache.catalina.Service;
+import org.apache.catalina.core.StandardContext;
+import org.apache.catalina.mbeans.MBeanUtils;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * Store Server/Service/Host/Context at file or PrintWriter. Default server.xml
+ * is at $catalina.base/conf/server.xml
+ * 
+ * @author Peter Rossbach
+ *  
+ */
+public class StoreConfig implements IStoreConfig {
+    private static Log log = LogFactory.getLog(StoreConfig.class);
+
+    private String serverFilename = "conf/server.xml";
+
+    private StoreRegistry registry;
+
+    /**
+     * get server.xml location
+     * 
+     * @return The server file name
+     */
+    public String getServerFilename() {
+        return serverFilename;
+    }
+
+    /**
+     * set new server.xml location
+     * 
+     * @param string
+     */
+    public void setServerFilename(String string) {
+        serverFilename = string;
+    }
+
+    /*
+     * Get the StoreRegistry with all factory to generate the
+     * server.xml/context.xml files
+     * 
+     * @see org.apache.catalina.config.IStoreConfig#getRegistry()
+     */
+    public StoreRegistry getRegistry() {
+        return registry;
+    }
+
+    /*
+     * set StoreRegistry
+     * 
+     * @see org.apache.catalina.config.IStoreConfig#setRegistry(org.apache.catalina.config.ConfigurationRegistry)
+     */
+    public void setRegistry(StoreRegistry aRegistry) {
+        registry = aRegistry;
+    }
+
+    /**
+     * Store current Server
+     * 
+     * @see org.apache.catalina.ServerFactory#getServer()
+     */
+    public synchronized void storeConfig() {
+        store(ServerFactory.getServer());
+    }
+
+    /**
+     * Store Server from Object Name (Catalina:type=Server)
+     * 
+     * @param aServerName
+     *            Server ObjectName
+     * @param backup
+     * @param externalAllowed
+     *            s *
+     * @throws MalformedObjectNameException
+     */
+    public synchronized void storeServer(String aServerName, boolean backup,
+            boolean externalAllowed) throws MalformedObjectNameException {
+        if (aServerName == null || aServerName.length() == 0) {
+            if (log.isErrorEnabled())
+                log.error("Please, call with a correct server ObjectName!");
+            return;
+        }
+        MBeanServer mserver = MBeanUtils.createServer();
+        ObjectName objectName = new ObjectName(aServerName);
+        if (mserver.isRegistered(objectName)) {
+            try {
+                Server aServer = (Server) mserver.getAttribute(objectName,
+                        "managedResource");
+                StoreDescription desc = null;
+                desc = getRegistry().findDescription(StandardContext.class);
+                if (desc != null) {
+                    boolean oldSeparate = desc.isStoreSeparate();
+                    boolean oldBackup = desc.isBackup();
+                    boolean oldExternalAllowed = desc.isExternalAllowed();
+                    try {
+                        desc.setStoreSeparate(true);
+                        desc.setBackup(backup);
+                        desc.setExternalAllowed(externalAllowed);
+                        store((Server) aServer);
+                    } finally {
+                        desc.setStoreSeparate(oldSeparate);
+                        desc.setBackup(oldBackup);
+                        desc.setExternalAllowed(oldExternalAllowed);
+                    }
+                } else
+                    store((Server) aServer);
+            } catch (Exception e) {
+                if (log.isInfoEnabled())
+                    log.info("Object " + aServerName
+                            + " is no a Server instance or store exception", e);
+            }
+        } else if (log.isInfoEnabled())
+            log.info("Server " + aServerName + " not found!");
+    }
+
+    /**
+     * Store a Context from ObjectName
+     * 
+     * @param aContextName
+     *            MBean ObjectName
+     * @param backup
+     * @param externalAllowed
+     * @throws MalformedObjectNameException
+     */
+    public synchronized void storeContext(String aContextName, boolean backup,
+            boolean externalAllowed) throws MalformedObjectNameException {
+        if (aContextName == null || aContextName.length() == 0) {
+            if (log.isErrorEnabled())
+                log.error("Please, call with a correct context ObjectName!");
+            return;
+        }
+        MBeanServer mserver = MBeanUtils.createServer();
+        ObjectName objectName = new ObjectName(aContextName);
+        if (mserver.isRegistered(objectName)) {
+            try {
+                Context aContext = (Context) mserver.getAttribute(objectName,
+                        "managedResource");
+                String configFile = aContext.getConfigFile();
+                if (configFile != null) {
+                    try {
+                        StoreDescription desc = null;
+                        desc = getRegistry().findDescription(
+                                aContext.getClass());
+                        if (desc != null) {
+                            boolean oldSeparate = desc.isStoreSeparate();
+                            boolean oldBackup = desc.isBackup();
+                            boolean oldExternalAllowed = desc
+                                    .isExternalAllowed();
+                            try {
+                                desc.setStoreSeparate(true);
+                                desc.setBackup(backup);
+                                desc.setExternalAllowed(externalAllowed);
+                                desc.getStoreFactory()
+                                        .store(null, -2, aContext);
+                            } finally {
+                                desc.setStoreSeparate(oldSeparate);
+                                desc.setBackup(oldBackup);
+                                desc.setBackup(oldExternalAllowed);
+                            }
+                        }
+                    } catch (Exception e) {
+                        log.error(e);
+                    }
+                } else
+                    log.error("Missing configFile at Context "
+                            + aContext.getPath() + " to store!");
+            } catch (Exception e) {
+                if (log.isInfoEnabled())
+                    log
+                            .info(
+                                    "Object "
+                                            + aContextName
+                                            + " is no a context instance or store exception",
+                                    e);
+            }
+        } else if (log.isInfoEnabled())
+            log.info("Context " + aContextName + " not found!");
+    }
+
+    /**
+     * Write the configuration information for this entire <code>Server</code>
+     * out to the server.xml configuration file.
+     *  
+     */
+    public synchronized void store(Server aServer) {
+
+        StoreFileMover mover = new StoreFileMover(System
+                .getProperty("catalina.base"), getServerFilename(),
+                getRegistry().getEncoding());
+        // Open an output writer for the new configuration file
+        try {
+            PrintWriter writer = mover.getWriter();
+
+            try {
+                store(writer, -2, aServer);
+            } finally {
+                // Flush and close the output file
+                try {
+                    writer.flush();
+                } catch (Exception e) {
+                    log.error(e);
+                }
+                try {
+                    writer.close();
+                } catch (Exception e) {
+                    throw (e);
+                }
+            }
+            mover.move();
+        } catch (Exception e) {
+            log.error(e);
+        }
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see org.apache.catalina.config.IStoreConfig#store(org.apache.catalina.Context)
+     */
+    public synchronized void store(Context aContext) {
+        String configFile = aContext.getConfigFile();
+        if (configFile != null) {
+            try {
+                StoreDescription desc = null;
+                desc = getRegistry().findDescription(aContext.getClass());
+                if (desc != null) {
+                    boolean old = desc.isStoreSeparate();
+                    try {
+                        desc.setStoreSeparate(true);
+                        desc.getStoreFactory().store(null, -2, aContext);
+                    } finally {
+                        desc.setStoreSeparate(old);
+                    }
+                }
+            } catch (Exception e) {
+                log.error(e);
+            }
+        } else
+            log.error("Missing configFile at Context " + aContext.getPath());
+
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see org.apache.catalina.config.IStoreConfig#store(java.io.PrintWriter,
+     *      int, org.apache.catalina.Context)
+     */
+    public synchronized void store(PrintWriter aWriter, int indent,
+            Context aContext) {
+        boolean oldSeparate = true;
+        StoreDescription desc = null;
+        try {
+            desc = getRegistry().findDescription(aContext.getClass());
+            oldSeparate = desc.isStoreSeparate();
+            desc.setStoreSeparate(false);
+            desc.getStoreFactory().store(aWriter, indent, aContext);
+        } catch (Exception e) {
+            log.error(e);
+        } finally {
+            if (desc != null)
+                desc.setStoreSeparate(oldSeparate);
+        }
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see org.apache.catalina.config.IStoreConfig#store(java.io.PrintWriter,
+     *      int, org.apache.catalina.Host)
+     */
+    public synchronized void store(PrintWriter aWriter, int indent, Host aHost) {
+        try {
+            StoreDescription desc = getRegistry().findDescription(
+                    aHost.getClass());
+            desc.getStoreFactory().store(aWriter, indent, aHost);
+        } catch (Exception e) {
+            log.error(e);
+        }
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see org.apache.catalina.config.IStoreConfig#store(java.io.PrintWriter,
+     *      int, org.apache.catalina.Service)
+     */
+    public synchronized void store(PrintWriter aWriter, int indent,
+            Service aService) {
+        try {
+            StoreDescription desc = getRegistry().findDescription(
+                    aService.getClass());
+            desc.getStoreFactory().store(aWriter, indent, aService);
+        } catch (Exception e) {
+            log.error(e);
+        }
+    }
+
+    /**
+     * Store the state of this Server MBean (which will recursively store
+     * everything)
+     * 
+     * @param writer
+     * @param indent
+     * @param aServer
+     */
+    public synchronized void store(PrintWriter writer, int indent,
+            Server aServer) {
+        try {
+            StoreDescription desc = getRegistry().findDescription(
+                    aServer.getClass());
+            desc.getStoreFactory().store(writer, indent, aServer);
+        } catch (Exception e) {
+            log.error(e);
+        }
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/src/share/org/apache/catalina/storeconfig/StoreConfigLifecycleListener.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/src/share/org/apache/catalina/storeconfig/StoreConfigLifecycleListener.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/src/share/org/apache/catalina/storeconfig/StoreConfigLifecycleListener.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,167 @@
+/*
+ * Copyright 2004-2005 The Apache Software Foundation.
+ * 
+ * Licensed 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.storeconfig;
+
+import java.io.InputStream;
+
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+import javax.management.modelmbean.ModelMBean;
+
+import org.apache.catalina.Lifecycle;
+import org.apache.catalina.LifecycleEvent;
+import org.apache.catalina.LifecycleListener;
+import org.apache.catalina.core.StandardServer;
+import org.apache.catalina.mbeans.MBeanUtils;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.commons.modeler.ManagedBean;
+import org.apache.commons.modeler.Registry;
+
+/**
+ * Load and Register StoreConfig MBean <i>Catalina:type=StoreConfig,resource="url"</i>
+ * 
+ * @author Peter Rossbach
+ */
+public class StoreConfigLifecycleListener implements LifecycleListener {
+    private static Log log = LogFactory
+            .getLog(StoreConfigLifecycleListener.class);
+
+    IStoreConfig storeConfig;
+
+    private String storeConfigClass = "org.apache.catalina.storeconfig.StoreConfig";
+
+    private String storeRegistry = null;
+
+    /*
+     * register StoreRegistry after Start the complete Server
+     * 
+     * @see org.apache.catalina.LifecycleListener#lifecycleEvent(org.apache.catalina.LifecycleEvent)
+     */
+    public void lifecycleEvent(LifecycleEvent event) {
+        if (Lifecycle.AFTER_START_EVENT.equals(event.getType())) {
+            if (event.getSource() instanceof StandardServer) {
+                createMBean();
+            }
+        }
+    }
+
+    /**
+     * create StoreConfig MBean and load StoreRgistry MBeans name is
+     * <i>Catalina:type=StoreConfig </i>
+     */
+    protected void createMBean() {
+        StoreLoader loader = new StoreLoader();
+        try {
+            Class clazz = Class.forName(getStoreConfigClass(), true, this
+                    .getClass().getClassLoader());
+            storeConfig = (IStoreConfig) clazz.newInstance();
+            if (null == getStoreRegistry())
+                // default Loading
+                loader.load();
+            else
+                // load a spezial file registry (url)
+                loader.load(getStoreRegistry());
+            // use the loader Registry
+            storeConfig.setRegistry(loader.getRegistry());
+        } catch (Exception e) {
+            log.error("createMBean load", e);
+            return;
+        }
+        MBeanServer mserver = MBeanUtils.createServer();
+        InputStream descriptor = null;
+        try {
+            ObjectName objectName = new ObjectName("Catalina:type=StoreConfig" );
+            if (!mserver.isRegistered(objectName)) {
+                descriptor = this.getClass().getResourceAsStream(
+                        "mbeans-descriptors.xml");
+                Registry registry = MBeanUtils.createRegistry();
+                registry.loadMetadata(descriptor);
+                mserver.registerMBean(getManagedBean(storeConfig), objectName);
+            }
+        } catch (Exception ex) {
+            log.error("createMBean register MBean", ex);
+
+        } finally {
+            if (descriptor != null) {
+                try {
+                    descriptor.close();
+                    descriptor = null;
+                } catch (Exception ex) {
+                    log.error("createMBean register MBean", ex);
+                }
+            }
+        }
+    }
+
+    /**
+     * Create a ManagedBean (StoreConfig)
+     * 
+     * @param object
+     * @return The bean
+     * @throws Exception
+     */
+    protected ModelMBean getManagedBean(Object object) throws Exception {
+        ManagedBean managedBean = Registry.getRegistry(null, null)
+                .findManagedBean(object.getClass().getName());
+        return managedBean.createMBean(object);
+    }
+
+    /**
+     * @return Returns the storeConfig.
+     */
+    public IStoreConfig getStoreConfig() {
+        return storeConfig;
+    }
+
+    /**
+     * @param storeConfig
+     *            The storeConfig to set.
+     */
+    public void setStoreConfig(IStoreConfig storeConfig) {
+        this.storeConfig = storeConfig;
+    }
+
+    /**
+     * @return Returns the storeConfigClass.
+     */
+    public String getStoreConfigClass() {
+        return storeConfigClass;
+    }
+
+    /**
+     * @param storeConfigClass
+     *            The storeConfigClass to set.
+     */
+    public void setStoreConfigClass(String storeConfigClass) {
+        this.storeConfigClass = storeConfigClass;
+    }
+
+    /**
+     * @return Returns the storeRegistry.
+     */
+    public String getStoreRegistry() {
+        return storeRegistry;
+    }
+
+    /**
+     * @param storeRegistry
+     *            The storeRegistry to set.
+     */
+    public void setStoreRegistry(String storeRegistry) {
+        this.storeRegistry = storeRegistry;
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/src/share/org/apache/catalina/storeconfig/StoreContextAppender.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/src/share/org/apache/catalina/storeconfig/StoreContextAppender.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/src/share/org/apache/catalina/storeconfig/StoreContextAppender.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,150 @@
+/*
+ * Copyright 2004-2005 The Apache Software Foundation.
+ * 
+ * Licensed 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.storeconfig;
+
+import java.io.File;
+import java.io.IOException;
+
+import org.apache.catalina.Container;
+import org.apache.catalina.core.StandardContext;
+import org.apache.catalina.core.StandardHost;
+
+/**
+ * store StandardContext Attributes ... TODO DefaultContext Handling
+ * 
+ * @author Peter Rossbach
+ *  
+ */
+public class StoreContextAppender extends StoreAppender {
+
+    /*
+     * Print Context Values. <ul><li> Spezial handling to default workDir.
+     * </li><li> Don't save path at external context.xml </li><li> Don't
+     * generate docBase for host.appBase webapps <LI></ul>
+     * 
+     * @see org.apache.catalina.config.StoreAppender#isPrintValue(java.lang.Object,
+     *      java.lang.Object, java.lang.String,
+     *      org.apache.catalina.config.StoreDescription)
+     */
+    public boolean isPrintValue(Object bean, Object bean2, String attrName,
+            StoreDescription desc) {
+        boolean isPrint = super.isPrintValue(bean, bean2, attrName, desc);
+        if (isPrint) {
+            StandardContext context = ((StandardContext) bean);
+            if ("workDir".equals(attrName)) {
+                String defaultWorkDir = getDefaultWorkDir(context);
+                isPrint = !defaultWorkDir.equals(context.getWorkDir());
+            } else if ("path".equals(attrName)) {
+                isPrint = desc.isStoreSeparate() 
+                            && desc.isExternalAllowed()
+                            && context.getConfigFile() == null;
+            } else if ("docBase".equals(attrName)) {
+                Container host = context.getParent();
+                if (host instanceof StandardHost) {
+                    File appBase = getAppBase(((StandardHost) host));
+                    File docBase = getDocBase(context,appBase);
+                    isPrint = !appBase.equals(docBase.getParentFile());
+                }
+            }
+        }
+        return isPrint;
+    }
+
+    protected File getAppBase(StandardHost host) {
+
+        File appBase;
+        File file = new File(host.getAppBase());
+        if (!file.isAbsolute())
+            file = new File(System.getProperty("catalina.base"), host
+                    .getAppBase());
+        try {
+            appBase = file.getCanonicalFile();
+        } catch (IOException e) {
+            appBase = file;
+        }
+        return (appBase);
+
+    }
+
+    protected File getDocBase(StandardContext context, File appBase) {
+
+        File docBase;
+        File file = new File(context.getDocBase());
+        if (!file.isAbsolute())
+            file = new File(appBase, context.getDocBase());
+        try {
+            docBase = file.getCanonicalFile();
+        } catch (IOException e) {
+            docBase = file;
+        }
+        return (docBase);
+
+    }
+
+    /**
+     * Make default Work Dir.
+     * 
+     * @param context
+     * @return The default working directory for the context.
+     */
+    protected String getDefaultWorkDir(StandardContext context) {
+        String defaultWorkDir = null;
+        String contextPath = context.getPath().length() == 0 ? "_" : context
+                .getPath().substring(1);
+        Container host = context.getParent();
+        if (host instanceof StandardHost) {
+            String hostWorkDir = ((StandardHost) host).getWorkDir();
+            if (hostWorkDir != null) {
+                defaultWorkDir = hostWorkDir + File.separator + contextPath;
+            } else {
+                String engineName = context.getParent().getParent().getName();
+                String hostName = context.getParent().getName();
+                defaultWorkDir = "work" + File.separator + engineName
+                        + File.separator + hostName + File.separator
+                        + contextPath;
+            }
+        }
+        return defaultWorkDir;
+    }
+
+    /*
+     * Generate a real default StandardContext TODO read and interpret the
+     * default context.xml and context.xml.default TODO Cache a Default
+     * StandardContext ( with reloading strategy) TODO remove really all
+     * elements, but detection is hard... To Listener or Valve from same class?>
+     * 
+     * @see org.apache.catalina.storeconfig.StoreAppender#defaultInstance(java.lang.Object)
+     */
+    public Object defaultInstance(Object bean) throws InstantiationException,
+            IllegalAccessException {
+        if (bean instanceof StandardContext) {
+            StandardContext defaultContext = new StandardContext();
+            /*
+             * if (!((StandardContext) bean).getOverride()) {
+             * defaultContext.setParent(((StandardContext)bean).getParent());
+             * ContextConfig contextConfig = new ContextConfig();
+             * defaultContext.addLifecycleListener(contextConfig);
+             * contextConfig.setContext(defaultContext);
+             * contextConfig.processContextConfig(new File(contextConfig
+             * .getBaseDir(), "conf/context.xml"));
+             * contextConfig.processContextConfig(new File(contextConfig
+             * .getConfigBase(), "context.xml.default")); }
+             */
+            return defaultContext;
+        } else
+            return super.defaultInstance(bean);
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/src/share/org/apache/catalina/storeconfig/StoreDescription.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/src/share/org/apache/catalina/storeconfig/StoreDescription.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/src/share/org/apache/catalina/storeconfig/StoreDescription.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,361 @@
+/*
+ * Copyright 2004-2005 The Apache Software Foundation.
+ * 
+ * Licensed 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.storeconfig;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Bean of a StoreDescription 
+ * @author Peter Rossbach 
+ * 
+ * <pre>
+ * 
+ *  &lt;Description
+ *  tag=&quot;Context&quot;
+ *  standard=&quot;true&quot;
+ *  default=&quot;true&quot; 
+ *  externalAllowed=&quot;true&quot; 
+ *  storeSeparate=&quot;true&quot;
+ *  backup=&quot;true&quot; 
+ *  childs=&quot;true&quot;
+ *  tagClass=&quot;org.apache.catalina.core.StandardContext&quot;
+ *  storeFactoryClass=&quot;org.apache.catalina.storeconfig.StandardContextSF&quot;
+ *  storeAppenderClass=&quot;org.apache.catalina.storeconfig.StoreContextAppender&quot;&gt;
+ *     &lt;TransientAttribute&gt;available&lt;/TransientAttribute&gt;
+ *     &lt;TransientAttribute&gt;configFile&lt;/TransientAttribute&gt;
+ *     &lt;TransientAttribute&gt;configured&lt;/TransientAttribute&gt;
+ *     &lt;TransientAttribute&gt;displayName&lt;/TransientAttribute&gt;
+ *     &lt;TransientAttribute&gt;distributable&lt;/TransientAttribute&gt;
+ *     &lt;TransientAttribute&gt;domain&lt;/TransientAttribute&gt;
+ *     &lt;TransientAttribute&gt;engineName&lt;/TransientAttribute&gt;
+ *     &lt;TransientAttribute&gt;name&lt;/TransientAttribute&gt;
+ *     &lt;TransientAttribute&gt;publicId&lt;/TransientAttribute&gt;
+ *     &lt;TransientAttribute&gt;replaceWelcomeFiles&lt;/TransientAttribute&gt;
+ *     &lt;TransientAttribute&gt;saveConfig&lt;/TransientAttribute&gt;
+ *     &lt;TransientAttribute&gt;sessionTimeout&lt;/TransientAttribute&gt;
+ *     &lt;TransientAttribute&gt;startupTime&lt;/TransientAttribute&gt;
+ *     &lt;TransientAttribute&gt;tldScanTime&lt;/TransientAttribute&gt;
+ *  &lt;/Description&gt;
+ * 
+ *  
+ * </pre>
+ */
+public class StoreDescription {
+
+    private String id;
+
+    private String tag;
+
+    private String tagClass;
+
+    private boolean standard = false;
+
+    private boolean backup = false;
+
+    private boolean externalAllowed = false;
+
+    private boolean myDefault = false;
+
+    private boolean attributes = true;
+
+    private String storeFactoryClass;
+
+    private IStoreFactory storeFactory;
+
+    private String storeWriterClass;
+
+    private boolean childs = false;
+
+    private List transientAttributes;
+
+    private List transientChilds;
+
+    private boolean storeSeparate = false;
+
+    /**
+     * @return Returns the external.
+     */
+    public boolean isExternalAllowed() {
+        return externalAllowed;
+    }
+
+    /**
+     * @param external
+     *            The external to set.
+     */
+    public void setExternalAllowed(boolean external) {
+        this.externalAllowed = external;
+    }
+
+    /**
+     * @return Returns the standard.
+     */
+    public boolean isStandard() {
+        return standard;
+    }
+
+    /**
+     * @param standard
+     *            The standard to set.
+     */
+    public void setStandard(boolean standard) {
+        this.standard = standard;
+    }
+
+    /**
+     * @return Returns the backup.
+     */
+    public boolean isBackup() {
+        return backup;
+    }
+
+    /**
+     * @param backup
+     *            The backup to set.
+     */
+    public void setBackup(boolean backup) {
+        this.backup = backup;
+    }
+
+    /**
+     * @return Returns the myDefault.
+     */
+    public boolean isDefault() {
+        return myDefault;
+    }
+
+    /**
+     * @param aDefault
+     *            The myDefault to set.
+     */
+    public void setDefault(boolean aDefault) {
+        this.myDefault = aDefault;
+    }
+
+    /**
+     * @return Returns the storeFactory.
+     */
+    public String getStoreFactoryClass() {
+        return storeFactoryClass;
+    }
+
+    /**
+     * @param storeFactoryClass
+     *            The storeFactory to set.
+     */
+    public void setStoreFactoryClass(String storeFactoryClass) {
+        this.storeFactoryClass = storeFactoryClass;
+    }
+
+    /**
+     * @return Returns the storeFactory.
+     */
+    public IStoreFactory getStoreFactory() {
+        return storeFactory;
+    }
+
+    /**
+     * @param storeFactory
+     *            The storeFactory to set.
+     */
+    public void setStoreFactory(IStoreFactory storeFactory) {
+        this.storeFactory = storeFactory;
+    }
+
+    /**
+     * @return Returns the storeWriterClass.
+     */
+    public String getStoreWriterClass() {
+        return storeWriterClass;
+    }
+
+    /**
+     * @param storeWriterClass
+     *            The storeWriterClass to set.
+     */
+    public void setStoreWriterClass(String storeWriterClass) {
+        this.storeWriterClass = storeWriterClass;
+    }
+
+    /**
+     * @return Returns the tagClass.
+     */
+    public String getTag() {
+        return tag;
+    }
+
+    /**
+     * @param tag
+     *            The tag to set.
+     */
+    public void setTag(String tag) {
+        this.tag = tag;
+    }
+
+    /**
+     * @return Returns the tagClass.
+     */
+    public String getTagClass() {
+        return tagClass;
+    }
+
+    /**
+     * @param tagClass
+     *            The tagClass to set.
+     */
+    public void setTagClass(String tagClass) {
+        this.tagClass = tagClass;
+    }
+
+    /**
+     * @return Returns the transientAttributes.
+     */
+    public List getTransientAttributes() {
+        return transientAttributes;
+    }
+
+    /**
+     * @param transientAttributes
+     *            The transientAttributes to set.
+     */
+    public void setTransientAttributes(List transientAttributes) {
+        this.transientAttributes = transientAttributes;
+    }
+
+    public void addTransientAttribute(String attribute) {
+        if (transientAttributes == null)
+            transientAttributes = new ArrayList();
+        transientAttributes.add(attribute);
+    }
+
+    public void removeTransientAttribute(String attribute) {
+        if (transientAttributes != null)
+            transientAttributes.remove(attribute);
+    }
+
+    /**
+     * @return Returns the transientChilds.
+     */
+    public List getTransientChilds() {
+        return transientChilds;
+    }
+
+    /**
+     * @param transientChilds
+     *            The transientChilds to set.
+     */
+    public void setTransientChilds(List transientChilds) {
+        this.transientChilds = transientChilds;
+    }
+
+    public void addTransientChild(String classname) {
+        if (transientChilds == null)
+            transientChilds = new ArrayList();
+        transientChilds.add(classname);
+    }
+
+    public void removeTransientChild(String classname) {
+        if (transientChilds != null)
+            transientChilds.remove(classname);
+    }
+
+    /**
+     * is child transient, please don't save this.
+     * 
+     * @param classname
+     * @return is classname attribute?
+     */
+    public boolean isTransientChild(String classname) {
+        if (transientChilds != null)
+            return transientChilds.contains(classname);
+        return false;
+    }
+
+    /**
+     * is attribute transient, please don't save this.
+     * 
+     * @param attribute
+     * @return is transient attribute?
+     */
+    public boolean isTransientAttribute(String attribute) {
+        if (transientAttributes != null)
+            return transientAttributes.contains(attribute);
+        return false;
+    }
+
+    /**
+     * Return the real id or TagClass
+     * 
+     * @return Returns the id.
+     */
+    public String getId() {
+        if (id != null)
+            return id;
+        else
+            return getTagClass();
+    }
+
+    /**
+     * @param id
+     *            The id to set.
+     */
+    public void setId(String id) {
+        this.id = id;
+    }
+
+    /**
+     * @return Returns the attributes.
+     */
+    public boolean isAttributes() {
+        return attributes;
+    }
+
+    /**
+     * @param attributes
+     *            The attributes to set.
+     */
+    public void setAttributes(boolean attributes) {
+        this.attributes = attributes;
+    }
+
+    /**
+     * @return True if it's a separate store
+     */
+    public boolean isStoreSeparate() {
+        return storeSeparate;
+    }
+
+    public void setStoreSeparate(boolean storeSeparate) {
+        this.storeSeparate = storeSeparate;
+    }
+
+    /**
+     * @return Returns the childs.
+     */
+    public boolean isChilds() {
+        return childs;
+    }
+
+    /**
+     * @param childs
+     *            The childs to set.
+     */
+    public void setChilds(boolean childs) {
+        this.childs = childs;
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/src/share/org/apache/catalina/storeconfig/StoreFactoryBase.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/src/share/org/apache/catalina/storeconfig/StoreFactoryBase.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/src/share/org/apache/catalina/storeconfig/StoreFactoryBase.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,186 @@
+/*
+ * Copyright 1999-2001,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.storeconfig;
+
+import java.io.PrintWriter;
+
+import org.apache.catalina.util.StringManager;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * StoreFactory saves spezial elements.
+ * Output was generate with StoreAppenders.
+ * 
+ * @author Peter Rossbach
+ * @version 1.0
+ *  
+ */
+public class StoreFactoryBase implements IStoreFactory {
+    private static Log log = LogFactory.getLog(StoreFactoryBase.class);
+
+    private StoreRegistry registry;
+
+    private StoreAppender storeAppender = new StoreAppender();
+
+    /**
+     * The string manager for this package.
+     */
+    protected static final StringManager sm = StringManager
+            .getManager(Constants.Package);
+
+    /**
+     * The descriptive information string for this implementation.
+     */
+    private static final String info = "org.apache.catalina.config.StoreFactoryBase/1.0";
+
+    /**
+     * Return descriptive information about this Facotry implementation and the
+     * corresponding version number, in the format
+     * <code>&lt;description&gt;/&lt;version&gt;</code>.
+     */
+    public String getInfo() {
+
+        return (info);
+
+    }
+
+    /**
+     * @return Returns the storeAppender.
+     */
+    public StoreAppender getStoreAppender() {
+        return storeAppender;
+    }
+
+    /**
+     * @param storeAppender
+     *            The storeAppender to set.
+     */
+    public void setStoreAppender(StoreAppender storeAppender) {
+        this.storeAppender = storeAppender;
+    }
+
+    /*
+     * set Registry
+     * 
+     * @see org.apache.catalina.config.IStoreFactory#setRegistry(org.apache.catalina.config.ConfigurationRegistry)
+     */
+    public void setRegistry(StoreRegistry aRegistry) {
+        registry = aRegistry;
+
+    }
+
+    /*
+     * get Registry
+     * 
+     * @see org.apache.catalina.config.IStoreFactory#getRegistry()
+     */
+    public StoreRegistry getRegistry() {
+
+        return registry;
+    }
+
+    public void storeXMLHead(PrintWriter aWriter) {
+        // Store the beginning of this element
+        aWriter.print("<?xml version=\"1.0\" encoding=\"");
+        aWriter.print(getRegistry().getEncoding());
+        aWriter.println("\"?>");
+    }
+
+    /*
+     * Store a server.xml element with attributes and childs
+     * 
+     * @see org.apache.catalina.storeconfig.IStoreFactory#store(java.io.PrintWriter,
+     *      int, java.lang.Object)
+     */
+    public void store(PrintWriter aWriter, int indent, Object aElement)
+            throws Exception {
+
+        StoreDescription elementDesc = getRegistry().findDescription(
+                aElement.getClass());
+
+        if (elementDesc != null) {
+            if (log.isDebugEnabled())
+                log.debug(sm.getString("factory.storeTag",
+                        elementDesc.getTag(), aElement));
+            getStoreAppender().printIndent(aWriter, indent + 2);
+            if (!elementDesc.isChilds()) {
+                getStoreAppender().printTag(aWriter, indent, aElement,
+                        elementDesc);
+            } else {
+                getStoreAppender().printOpenTag(aWriter, indent + 2, aElement,
+                        elementDesc);
+                storeChilds(aWriter, indent + 2, aElement, elementDesc);
+                getStoreAppender().printIndent(aWriter, indent + 2);
+                getStoreAppender().printCloseTag(aWriter, elementDesc);
+            }
+        } else
+            log.warn(sm.getString("factory.storeNoDescriptor", aElement
+                    .getClass()));
+    }
+
+    /**
+     * Must Implement at subclass for sepzial store childs handling
+     * 
+     * @param aWriter
+     * @param indent
+     * @param aElement
+     * @param elementDesc
+     */
+    public void storeChilds(PrintWriter aWriter, int indent, Object aElement,
+            StoreDescription elementDesc) throws Exception {
+    }
+
+    /**
+     * Store only elements from storeChilds methods that are not a transient
+     * child.
+     * 
+     * @param aWriter
+     * @param indent
+     * @param aTagElement
+     * @throws Exception
+     */
+    protected void storeElement(PrintWriter aWriter, int indent,
+            Object aTagElement) throws Exception {
+        if (aTagElement != null) {
+            IStoreFactory elementFactory = getRegistry().findStoreFactory(
+                    aTagElement.getClass());
+
+            if (elementFactory != null) {
+                StoreDescription desc = getRegistry().findDescription(
+                        aTagElement.getClass());
+                if (!desc.isTransientChild(aTagElement.getClass().getName()))
+                    elementFactory.store(aWriter, indent, aTagElement);
+            } else {
+                log.warn(sm.getString("factory.storeNoDescriptor", aTagElement
+                        .getClass()));
+            }
+        }
+    }
+
+    /*
+     * Save a array of elements @param aWriter @param indent @param elements
+     */
+    protected void storeElementArray(PrintWriter aWriter, int indent,
+            Object[] elements) throws Exception {
+        if (elements != null) {
+            for (int i = 0; i < elements.length; i++) {
+                storeElement(aWriter, indent, elements[i]);
+            }
+        }
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/src/share/org/apache/catalina/storeconfig/StoreFactoryRule.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/src/share/org/apache/catalina/storeconfig/StoreFactoryRule.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/src/share/org/apache/catalina/storeconfig/StoreFactoryRule.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,124 @@
+/*
+ * Copyright 1999-2001,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.storeconfig;
+
+import org.apache.tomcat.util.digester.Rule;
+import org.xml.sax.Attributes;
+
+/**
+ * <p>
+ * Rule that creates a new <code>IStoreFactory</code> instance, and associates
+ * it with the top object on the stack (which must implement
+ * <code>IStoreFactory</code>).
+ * </p>
+ * 
+ * @author Peter Rossbach
+ */
+
+public class StoreFactoryRule extends Rule {
+
+    // ----------------------------------------------------------- Constructors
+
+    /**
+     * Construct a new instance of this Rule.
+     * 
+     * @param storeFactoryClass
+     *            Default name of the StoreFactory implementation class to be
+     *            created
+     * @param attributeName
+     *            Name of the attribute that optionally includes an override
+     *            name of the IStoreFactory class
+     */
+    public StoreFactoryRule(String storeFactoryClass, String attributeName,
+            String storeAppenderClass, String appenderAttributeName) {
+
+        this.storeFactoryClass = storeFactoryClass;
+        this.attributeName = attributeName;
+        this.appenderAttributeName = appenderAttributeName;
+        this.storeAppenderClass = storeAppenderClass;
+
+    }
+
+    // ----------------------------------------------------- Instance Variables
+
+    /**
+     * The attribute name of an attribute that can override the implementation
+     * class name.
+     */
+    private String attributeName;
+
+    private String appenderAttributeName;
+
+    /**
+     * The name of the <code>IStoreFactory</code> implementation class.
+     */
+    private String storeFactoryClass;
+
+    private String storeAppenderClass;
+
+    // --------------------------------------------------------- Public Methods
+
+    /**
+     * Handle the beginning of an XML element.
+     * 
+     * @param attributes
+     *            The attributes of this element
+     * 
+     * @exception Exception
+     *                if a processing error occurs
+     */
+    public void begin(String namespace, String name, Attributes attributes)
+            throws Exception {
+
+        IStoreFactory factory = (IStoreFactory) newInstance(attributeName,
+                storeFactoryClass, attributes);
+        StoreAppender storeAppender = (StoreAppender) newInstance(
+                appenderAttributeName, storeAppenderClass, attributes);
+        factory.setStoreAppender(storeAppender);
+
+        // Add this StoreFactory to our associated component
+        StoreDescription desc = (StoreDescription) digester.peek(0);
+        StoreRegistry registry = (StoreRegistry) digester.peek(1);
+        factory.setRegistry(registry);
+        desc.setStoreFactory(factory);
+
+    }
+
+    /**
+     * create new instance from attribte className!
+     * 
+     * @param attr class Name attribute
+     * @param defaultName Default Class
+     * @param attributes current digester attribute elements
+     * @return new config object instance
+     * @throws ClassNotFoundException
+     * @throws InstantiationException
+     * @throws IllegalAccessException
+     */
+    protected Object newInstance(String attr, String defaultName,
+            Attributes attributes) throws ClassNotFoundException,
+            InstantiationException, IllegalAccessException {
+        String className = defaultName;
+        if (attr != null) {
+            String value = attributes.getValue(attr);
+            if (value != null)
+                className = value;
+        }
+        Class clazz = Class.forName(className);
+        return clazz.newInstance();
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/src/share/org/apache/catalina/storeconfig/StoreFileMover.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/src/share/org/apache/catalina/storeconfig/StoreFileMover.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/src/share/org/apache/catalina/storeconfig/StoreFileMover.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,222 @@
+/*
+ * Copyright 2004-2005 The Apache Software Foundation.
+ * 
+ * Licensed 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.storeconfig;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+import java.sql.Timestamp;
+
+/**
+ * Move server.xml or context.xml as backup
+ * 
+ * @author Peter Rossbach
+ * 
+ * TODO Get Encoding from Registry
+ */
+public class StoreFileMover {
+
+    private String filename = "conf/server.xml";
+
+    private String encoding = "UTF-8";
+
+    private String basename = System.getProperty("catalina.base");
+
+    private File configOld;
+
+    private File configNew;
+
+    private File configSave;
+
+    /**
+     * @return Returns the configNew.
+     */
+    public File getConfigNew() {
+        return configNew;
+    }
+
+    /**
+     * @return Returns the configOld.
+     */
+    public File getConfigOld() {
+        return configOld;
+    }
+
+    /**
+     * @return Returns the configSave.
+     */
+    public File getConfigSave() {
+        return configSave;
+    }
+
+    /**
+     * @return Returns the basename.
+     */
+    public String getBasename() {
+        return basename;
+    }
+
+    /**
+     * @param basename
+     *            The basename to set.
+     */
+    public void setBasename(String basename) {
+        this.basename = basename;
+    }
+
+    /**
+     * @return The file name
+     */
+    public String getFilename() {
+        return filename;
+    }
+
+    /**
+     * @param string
+     */
+    public void setFilename(String string) {
+        filename = string;
+    }
+
+    /**
+     * @return The encoding
+     */
+    public String getEncoding() {
+        return encoding;
+    }
+
+    /**
+     * @param string
+     */
+    public void setEncoding(String string) {
+        encoding = string;
+    }
+
+    /**
+     * Calculate file objects for the old and new configuration files.
+     */
+    public StoreFileMover(String basename, String filename, String encoding) {
+        setBasename(basename);
+        setEncoding(encoding);
+        setFilename(filename);
+        init();
+    }
+
+    /**
+     * Calculate file objects for the old and new configuration files.
+     */
+    public StoreFileMover() {
+        init();
+    }
+
+    /**
+     * generate the Filename to new with TimeStamp
+     */
+    public void init() {
+        String configFile = getFilename();
+        configOld = new File(configFile);
+        if (!configOld.isAbsolute()) {
+            configOld = new File(getBasename(), configFile);
+        }
+        configNew = new File(configFile + ".new");
+        if (!configNew.isAbsolute()) {
+            configNew = new File(getBasename(), configFile + ".new");
+        }
+        if (!configNew.getParentFile().exists()) {
+            configNew.getParentFile().mkdirs();
+        }
+        String sb = getTimeTag();
+        configSave = new File(configFile + sb);
+        if (!configSave.isAbsolute()) {
+            configSave = new File(getBasename(), configFile + sb);
+        }
+    }
+
+    /**
+     * Shuffle old->save and new->old
+     * 
+     * @throws IOException
+     */
+    public void move() throws IOException {
+        if (configOld.renameTo(configSave)) {
+            if (!configNew.renameTo(configOld)) {
+                configSave.renameTo(configOld);
+                throw new IOException("Cannot rename "
+                        + configNew.getAbsolutePath() + " to "
+                        + configOld.getAbsolutePath());
+            }
+        } else {
+            if (!configOld.exists()) {
+                if (!configNew.renameTo(configOld)) {
+                    throw new IOException("Cannot move "
+                            + configNew.getAbsolutePath() + " to "
+                            + configOld.getAbsolutePath());
+                }
+            } else {
+                throw new IOException("Cannot rename "
+                    + configOld.getAbsolutePath() + " to "
+                    + configSave.getAbsolutePath());
+            }
+        }
+    }
+
+    /**
+     * Open an output writer for the new configuration file
+     * 
+     * @return The writer
+     * @throws IOException
+     */
+    public PrintWriter getWriter() throws IOException {
+        PrintWriter writer = null;
+        try {
+            writer = new PrintWriter(new OutputStreamWriter(
+                    new FileOutputStream(configNew), getEncoding()));
+        } catch (IOException e) {
+            if (writer != null) {
+                try {
+                    writer.close();
+                } catch (Throwable t) {
+                    ;
+                }
+            }
+            throw (e);
+        }
+        return writer;
+    }
+
+    /**
+     * Time value for backup yyyy-mm-dd.hh-mm-ss
+     * 
+     * @return The time
+     */
+    protected String getTimeTag() {
+        String ts = (new Timestamp(System.currentTimeMillis())).toString();
+        //        yyyy-mm-dd hh:mm:ss
+        //        0123456789012345678
+        StringBuffer sb = new StringBuffer(".");
+        sb.append(ts.substring(0, 10));
+        sb.append('.');
+        sb.append(ts.substring(11, 13));
+        sb.append('-');
+        sb.append(ts.substring(14, 16));
+        sb.append('-');
+        sb.append(ts.substring(17, 19));
+        return sb.toString();
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/src/share/org/apache/catalina/storeconfig/StoreLoader.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/src/share/org/apache/catalina/storeconfig/StoreLoader.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/src/share/org/apache/catalina/storeconfig/StoreLoader.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,287 @@
+/*
+ * Copyright 2004-2005 The Apache Software Foundation.
+ * 
+ * Licensed 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.storeconfig;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.tomcat.util.digester.Digester;
+import org.xml.sax.SAXException;
+
+/**
+ * 
+ * @author Peter Rossbach
+ * 
+ * <b>XML Format </b>
+ * 
+ * <pre>
+ *    
+ *       &lt;Registry name=&quot;&quot; encoding=&quot;UTF8&quot; &gt;
+ *       &lt;Description tag=&quot;Server&quot; standard=&quot;true&quot; default=&quot;true&quot;/&gt; 
+ *          tagClass=&quot;org.apache.catalina.core.StandardServer&quot;
+ *          storeFactory=&quot;org.apache.catalina.storeconfig.StandardServerSF&quot;&gt;
+ *        &lt;TransientAttributes&gt;
+ *          &lt;Attribute&gt;&lt;/Attribute&gt;
+ *        &lt;/TransientAttributes&gt;
+ *        &lt;TransientChilds&gt;
+ *          &lt;Child&gt;&lt;/Child&gt;
+ *        &lt;/TransientChilds&gt;
+ *       &lt;/Description&gt;
+ *   ...
+ *       &lt;/Tegistry&gt;
+ *     
+ * </pre>
+ * 
+ * 
+ * Convention:
+ * <ul>
+ * <li>Factories at subpackage <i>org.apache.catalina.core.storeconfig.xxxSF
+ * </i>.</li>
+ * <li>Element name are the unique Class name</li>
+ * <li>SF for StoreFactory</li>
+ * <li>standard implementation is false</li>
+ * </ul>
+ * other things:
+ * <ul>
+ * <li>Registry XML format is a very good option</li>
+ * <li>Store format is not fix</li>
+ * <li>We hope with the parent declaration we can build recursive child store
+ * operation //dream</li>
+ * <li>Problem is to access child data from array,collections or normal detail
+ * object</li>
+ * <li>Default definitions for Listener, Valve Resource? - Based on interface
+ * type!</li>
+ * </ul>
+ */
+public class StoreLoader {
+    private static Log log = LogFactory.getLog(StoreLoader.class);
+
+    /**
+     * The <code>Digester</code> instance used to parse registry descriptors.
+     */
+    protected static Digester digester = createDigester();
+
+    private StoreRegistry registry;
+    
+    private URL registryResource ;
+
+    /**
+     * @return Returns the registry.
+     */
+    public StoreRegistry getRegistry() {
+        return registry;
+    }
+
+    /**
+     * @param registry
+     *            The registry to set.
+     */
+    public void setRegistry(StoreRegistry registry) {
+        this.registry = registry;
+    }
+
+    /**
+     * Create and configure the Digester we will be using for setup store
+     * registry.
+     */
+    protected static Digester createDigester() {
+        long t1 = System.currentTimeMillis();
+        // Initialize the digester
+        Digester digester = new Digester();
+        digester.setValidating(false);
+        digester.setClassLoader(StoreRegistry.class.getClassLoader());
+
+        // Configure the actions we will be using
+        digester.addObjectCreate("Registry",
+                "org.apache.catalina.storeconfig.StoreRegistry", "className");
+        digester.addSetProperties("Registry");
+        digester
+                .addObjectCreate("Registry/Description",
+                        "org.apache.catalina.storeconfig.StoreDescription",
+                        "className");
+        digester.addSetProperties("Registry/Description");
+        digester.addRule("Registry/Description", new StoreFactoryRule(
+                "org.apache.catalina.storeconfig.StoreFactoryBase",
+                "storeFactoryClass",
+                "org.apache.catalina.storeconfig.StoreAppender",
+                "storeAppenderClass"));
+        digester.addSetNext("Registry/Description", "registerDescription",
+                "org.apache.catalina.storeconfig.StoreDescription");
+        digester.addCallMethod("Registry/Description/TransientAttribute",
+                "addTransientAttribute", 0);
+        digester.addCallMethod("Registry/Description/TransientChild",
+                "addTransientChild", 0);
+
+        long t2 = System.currentTimeMillis();
+        if (log.isDebugEnabled())
+            log.debug("Digester for server-registry.xml created " + (t2 - t1));
+        return (digester);
+
+    }
+
+    /**
+     * 
+     * @param aFile
+     * @return The server file
+     */
+    protected File serverFile(String aFile) {
+
+        if (aFile == null || (aFile != null && aFile.length() < 1))
+            aFile = "server-registry.xml";
+        File file = new File(aFile);
+        if (!file.isAbsolute())
+            file = new File(System.getProperty("catalina.base") + "/conf",
+                    aFile);
+        try {
+            file = file.getCanonicalFile();
+        } catch (IOException e) {
+            log.error(e);
+        }
+        return (file);
+    }
+
+    /**
+     * Load Description from external source
+     * 
+     * @param aURL
+     */
+    public void load(String aURL) {
+        synchronized (digester) {
+            File aRegistryFile = serverFile(aURL);
+            try {
+                registry = (StoreRegistry) digester.parse(aRegistryFile);
+                registryResource = aRegistryFile.toURL();
+            } catch (IOException e) {
+                log.error(e);
+            } catch (SAXException e) {
+                log.error(e);
+            }
+        }
+
+    }
+
+    /**
+     * Load from defaults
+     * <ul>
+     * <li>System Property URL catalina.storeregistry</li>
+     * <li>File $catalina.base/conf/server-registry.xml</li>
+     * <li>class resource org/apache/catalina/storeconfig/server-registry.xml
+     * </li>
+     * </ul>
+     */
+    public void load() {
+
+        InputStream is = null;
+        Throwable error = null;
+        registryResource = null ;
+        try {
+            String configUrl = getConfigUrl();
+            if (configUrl != null) {
+                is = (new URL(configUrl)).openStream();
+                if (log.isInfoEnabled())
+                    log
+                            .info("Find registry server-registry.xml from system property at url "
+                                    + configUrl);
+                ;
+                registryResource = new URL(configUrl);
+            }
+        } catch (Throwable t) {
+            // Ignore
+        }
+        if (is == null) {
+            try {
+                File home = new File(getCatalinaBase());
+                File conf = new File(home, "conf");
+                File reg = new File(conf, "server-registry.xml");
+                is = new FileInputStream(reg);
+                if (log.isInfoEnabled())
+                    log.info("Find registry server-registry.xml at file "
+                            + reg.getCanonicalPath());
+                ;
+                registryResource = reg.toURL() ;
+            } catch (Throwable t) {
+                // Ignore
+            }
+        }
+        if (is == null) {
+            try {
+                is = StoreLoader.class
+                        .getResourceAsStream("/org/apache/catalina/storeconfig/server-registry.xml");
+                if (log.isInfoEnabled())
+                    log
+                            .info("Find registry server-registry.xml at classpath resource");
+                registryResource = StoreLoader.class
+                    .getResource("/org/apache/catalina/storeconfig/server-registry.xml");
+                
+            } catch (Throwable t) {
+                // Ignore
+            }
+        }
+        if (is != null) {
+            try {
+                synchronized (digester) {
+                    registry = (StoreRegistry) digester.parse(is);
+                }
+            } catch (Throwable t) {
+                error = t;
+            } finally {
+                try {
+                    is.close();
+                } catch (IOException e) {
+                }
+            }
+        }
+        if ((is == null) || (error != null)) {
+            log.error(error);
+        }
+    }
+
+    /**
+     * Get the value of the catalina.home environment variable.
+     */
+    private static String getCatalinaHome() {
+        return System.getProperty("catalina.home", System
+                .getProperty("user.dir"));
+    }
+
+    /**
+     * Get the value of the catalina.base environment variable.
+     */
+    private static String getCatalinaBase() {
+        return System.getProperty("catalina.base", getCatalinaHome());
+    }
+
+    /**
+     * Get the value of the configuration URL.
+     */
+    private static String getConfigUrl() {
+        return System.getProperty("catalina.storeconfig");
+    }
+    
+    
+
+    /**
+     * @return Returns the registryResource.
+     */
+    public URL getRegistryResource() {
+        return registryResource;
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/src/share/org/apache/catalina/storeconfig/StoreRegistry.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/src/share/org/apache/catalina/storeconfig/StoreRegistry.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/src/share/org/apache/catalina/storeconfig/StoreRegistry.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,202 @@
+/*
+ * Copyright 2004-2005 The Apache Software Foundation.
+ * 
+ * Licensed 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.storeconfig;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.naming.directory.DirContext;
+
+import org.apache.catalina.LifecycleListener;
+import org.apache.catalina.Manager;
+import org.apache.catalina.Realm;
+import org.apache.catalina.Valve;
+import org.apache.catalina.ha.CatalinaCluster;
+import org.apache.catalina.ha.ClusterDeployer;
+import org.apache.catalina.tribes.ChannelReceiver;
+import org.apache.catalina.tribes.ChannelSender;
+import org.apache.catalina.tribes.MembershipService;
+import org.apache.catalina.tribes.MessageListener;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * Central StoreRegistry for all server.xml elements
+ * 
+ * @author Peter Rossbach
+ *  
+ */
+public class StoreRegistry {
+    private static Log log = LogFactory.getLog(StoreRegistry.class);
+
+    private Map descriptors = new HashMap();
+
+    private String encoding = "UTF-8";
+
+    private String name;
+
+    private String version;
+
+    // Access Information
+    private static Class interfaces[] = { CatalinaCluster.class,
+            ChannelSender.class, ChannelReceiver.class,
+            MembershipService.class, ClusterDeployer.class, Realm.class,
+            Manager.class, DirContext.class, LifecycleListener.class,
+            Valve.class, MessageListener.class };
+
+    /**
+     * @return Returns the name.
+     */
+    public String getName() {
+        return name;
+    }
+
+    /**
+     * @param name
+     *            The name to set.
+     */
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    /**
+     * @return Returns the version.
+     */
+    public String getVersion() {
+        return version;
+    }
+
+    /**
+     * @param version
+     *            The version to set.
+     */
+    public void setVersion(String version) {
+        this.version = version;
+    }
+
+    /**
+     * Find a description for id. Handle interface search when no direct match
+     * found.
+     * 
+     * @param id
+     * @return The description
+     */
+    public StoreDescription findDescription(String id) {
+        if (log.isDebugEnabled())
+            log.debug("search descriptor " + id);
+        StoreDescription desc = (StoreDescription) descriptors.get(id);
+        if (desc == null) {
+            Class aClass = null;
+            try {
+                aClass = Class.forName(id, true, this.getClass()
+                        .getClassLoader());
+            } catch (ClassNotFoundException e) {
+                log.error("ClassName:" + id, e);
+            }
+            if (aClass != null) {
+                desc = (StoreDescription) descriptors.get(aClass.getName());
+                for (int i = 0; desc == null && i < interfaces.length; i++) {
+                    if (interfaces[i].isAssignableFrom(aClass)) {
+                        desc = (StoreDescription) descriptors.get(interfaces[i]
+                                .getName());
+                    }
+                }
+            }
+        }
+        if (log.isDebugEnabled())
+            if (desc != null)
+                log.debug("find descriptor " + id + "#" + desc.getTag() + "#"
+                        + desc.getStoreFactoryClass());
+            else
+                log.debug(("Can't find descriptor for key " + id));
+        return desc;
+    }
+
+    /**
+     * Find Description by class
+     * 
+     * @param aClass
+     * @return The description
+     */
+    public StoreDescription findDescription(Class aClass) {
+        return findDescription(aClass.getName());
+    }
+
+    /**
+     * Find factory from classname
+     * 
+     * @param aClassName
+     * @return The factory
+     */
+    public IStoreFactory findStoreFactory(String aClassName) {
+        StoreDescription desc = findDescription(aClassName);
+        if (desc != null)
+            return desc.getStoreFactory();
+        else
+            return null;
+
+    }
+
+    /**
+     * find factory from class
+     * 
+     * @param aClass
+     * @return The factory
+     */
+    public IStoreFactory findStoreFactory(Class aClass) {
+        return findStoreFactory(aClass.getName());
+    }
+
+    /**
+     * Register a new description
+     * 
+     * @param desc
+     */
+    public void registerDescription(StoreDescription desc) {
+        String key = desc.getId();
+        if (key == null || "".equals(key))
+            key = desc.getTagClass();
+        descriptors.put(key, desc);
+        if (log.isDebugEnabled())
+            log.debug("register store descriptor " + key + "#" + desc.getTag()
+                    + "#" + desc.getTagClass());
+    }
+
+    public StoreDescription unregisterDescription(StoreDescription desc) {
+        String key = desc.getId();
+        if (key == null || "".equals(key))
+            key = desc.getTagClass();
+        return (StoreDescription) descriptors.remove(key);
+    }
+
+    // Attributes
+
+    /**
+     * @return The encoding
+     */
+    public String getEncoding() {
+        return encoding;
+    }
+
+    /**
+     * @param string
+     */
+    public void setEncoding(String string) {
+        encoding = string;
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/src/share/org/apache/catalina/storeconfig/WatchedResourceSF.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/src/share/org/apache/catalina/storeconfig/WatchedResourceSF.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/src/share/org/apache/catalina/storeconfig/WatchedResourceSF.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,56 @@
+/*
+ * Copyright 1999-2001,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.storeconfig;
+
+import java.io.PrintWriter;
+
+import org.apache.catalina.core.StandardContext;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * @author Peter Rossbach
+ *  
+ */
+public class WatchedResourceSF extends StoreFactoryBase {
+    private static Log log = LogFactory.getLog(WatchedResourceSF.class);
+
+    /*
+     * Store nested Element Value Arrays WatchedResource
+     * 
+     * @see org.apache.catalina.config.IStoreFactory#store(java.io.PrintWriter,
+     *      int, java.lang.Object)
+     */
+    public void store(PrintWriter aWriter, int indent, Object aElement)
+            throws Exception {
+        if (aElement instanceof StandardContext) {
+            StoreDescription elementDesc = getRegistry().findDescription(
+                    aElement.getClass().getName() + ".[WatchedResource]");
+            String[] resources = ((StandardContext) aElement)
+                    .findWatchedResources();
+            if (elementDesc != null) {
+                if (log.isDebugEnabled())
+                    log.debug("store " + elementDesc.getTag() + "( " + aElement
+                            + " )");
+                getStoreAppender().printTagArray(aWriter, "WatchedResource",
+                        indent, resources);
+            }
+        } else
+            log.warn("Descriptor for element" + aElement.getClass()
+                    + ".[WatchedResource] not configured!");
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/src/share/org/apache/catalina/storeconfig/WrapperLifecycleSF.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/src/share/org/apache/catalina/storeconfig/WrapperLifecycleSF.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/src/share/org/apache/catalina/storeconfig/WrapperLifecycleSF.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,56 @@
+/*
+ * Copyright 1999-2001,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.storeconfig;
+
+import java.io.PrintWriter;
+
+import org.apache.catalina.core.StandardContext;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * @author Peter Rossbach
+ *  
+ */
+public class WrapperLifecycleSF extends StoreFactoryBase {
+    private static Log log = LogFactory.getLog(WrapperLifecycleSF.class);
+
+    /*
+     * Store nested Element Value Arrays
+     * 
+     * @see org.apache.catalina.config.IStoreFactory#store(java.io.PrintWriter,
+     *      int, java.lang.Object)
+     */
+    public void store(PrintWriter aWriter, int indent, Object aElement)
+            throws Exception {
+        if (aElement instanceof StandardContext) {
+            StoreDescription elementDesc = getRegistry().findDescription(
+                    aElement.getClass().getName() + ".[WrapperLifecycle]");
+            String[] listeners = ((StandardContext) aElement)
+                    .findWrapperLifecycles();
+            if (elementDesc != null) {
+                if (log.isDebugEnabled())
+                    log.debug("store " + elementDesc.getTag() + "( " + aElement
+                            + " )");
+                getStoreAppender().printTagArray(aWriter, "WrapperLifecycle",
+                        indent, listeners);
+            }
+        } else
+            log.warn("Descriptor for element" + aElement.getClass()
+                    + ".[WrapperLifecycle] not configured!");
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/src/share/org/apache/catalina/storeconfig/WrapperListenerSF.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/src/share/org/apache/catalina/storeconfig/WrapperListenerSF.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/src/share/org/apache/catalina/storeconfig/WrapperListenerSF.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,56 @@
+/*
+ * Copyright 1999-2001,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.storeconfig;
+
+import java.io.PrintWriter;
+
+import org.apache.catalina.core.StandardContext;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * @author Peter Rossbach (pero at apache.org)
+ *  
+ */
+public class WrapperListenerSF extends StoreFactoryBase {
+    private static Log log = LogFactory.getLog(WrapperListenerSF.class);
+
+    /*
+     * Store nested Element Value Arrays
+     * 
+     * @see org.apache.catalina.config.IStoreFactory#store(java.io.PrintWriter,
+     *      int, java.lang.Object)
+     */
+    public void store(PrintWriter aWriter, int indent, Object aElement)
+            throws Exception {
+        if (aElement instanceof StandardContext) {
+            StoreDescription elementDesc = getRegistry().findDescription(
+                    aElement.getClass().getName() + ".[WrapperListener]");
+            String[] listeners = ((StandardContext) aElement)
+                    .findWrapperListeners();
+            if (elementDesc != null) {
+                if (log.isDebugEnabled())
+                    log.debug("store " + elementDesc.getTag() + "( " + aElement
+                            + " )");
+                getStoreAppender().printTagArray(aWriter, "WrapperListener",
+                        indent, listeners);
+            }
+        } else
+            log.warn("Descriptor for element" + aElement.getClass()
+                    + ".[WrapperListener] not configured!");
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/src/share/org/apache/catalina/storeconfig/mbeans-descriptors.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/src/share/org/apache/catalina/storeconfig/mbeans-descriptors.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/src/share/org/apache/catalina/storeconfig/mbeans-descriptors.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,77 @@
+<?xml version="1.0"?>
+<mbeans-descriptors>
+
+  <mbean         name="StoreConfig"
+          description="Implementation of a store server.xml config"
+               domain="Catalina"
+                group="StoreConfig"
+                 type="org.apache.catalina.storeconfig.StoreConfig">
+    <operation name="storeConfig" 
+               description="Store Server" 
+               impact="ACTION" returnType="void" />
+    <operation name="storeServer" 
+               description="Store Server from ObjectName" 
+               impact="ACTION" returnType="void" >
+         <parameter name="objectname"
+                 description="Objectname from Server"
+                 type="java.lang.String"
+                 default="Catalina:type=Server"/>
+         <parameter name="backup"
+                 description="store Context with backup"
+                 type="boolean"/>
+         <parameter name="externalAllowed"
+                 description="store all Context external that have a configFile"
+                 type="boolean"/>
+    </operation>
+
+<!--
+   Catalina:j2eeType=WebModule,name=//localhost/manager,J2EEApplication=none,J2EEServer=none
+-->
+   <operation name="storeContext" 
+               description="Store Context from ObjectName" 
+               impact="ACTION" returnType="void" >
+         <parameter name="objectname"
+                 description="ObjectName from Context"
+                 type="java.lang.String"/>
+         <parameter name="backup"
+                 description="store with Backup"
+                 type="boolean"/>
+         <parameter name="externalAllowed"
+                 description="store all or store only internal server.xml context (configFile == null)"
+                 type="boolean"/>
+    </operation>           
+    <operation name="store" 
+               description="Store Server" 
+               impact="ACTION" returnType="void" >
+          <parameter name="server"
+                 description="Server"
+                 type="org.apache.catalina.Server"
+                 />
+    </operation>           
+    <operation name="store" 
+               description="Store Context" 
+               impact="ACTION" returnType="void" >
+          <parameter name="context"
+                 description="Context"
+                 type="org.apache.catalina.context"/>
+    </operation>           
+    <operation name="store" 
+               description="Store Host" 
+               impact="ACTION" returnType="void" >
+          <parameter name="host"
+                 description="Host"
+                 type="org.apache.catalina.Host"/>
+    </operation>           
+    <operation name="store" 
+               description="Store Service" 
+               impact="ACTION" returnType="void" >
+          <parameter name="service"
+                 description="service"
+                 type="org.apache.catalina.Service"/>
+    </operation>           
+ 
+  </mbean>
+
+</mbeans-descriptors>
+
+

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/src/share/org/apache/catalina/storeconfig/server-registry.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/src/share/org/apache/catalina/storeconfig/server-registry.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/src/share/org/apache/catalina/storeconfig/server-registry.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,338 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Registry name="Tomcat" version="5.5.5" encoding="UTF-8" >
+     <Description
+	    tag="Server"
+		standard="true"
+		default="true" 
+		externalAllowed="true" 
+        childs="true"
+        tagClass="org.apache.catalina.core.StandardServer"
+        storeFactoryClass="org.apache.catalina.storeconfig.StandardServerSF">
+     </Description>
+     <Description
+	    tag="Service"
+		standard="true"
+		default="true" 
+        childs="true"
+        tagClass="org.apache.catalina.core.StandardService"
+        storeFactoryClass="org.apache.catalina.storeconfig.StandardServiceSF">
+     </Description>
+     <Description
+	    tag="Engine"
+		standard="true"
+		default="true" 
+        childs="true"
+        tagClass="org.apache.catalina.core.StandardEngine"
+        storeFactoryClass="org.apache.catalina.storeconfig.StandardEngineSF">
+	    <TransientAttribute>domain</TransientAttribute>
+     </Description>
+     <Description
+	    tag="Host"
+		standard="true"
+		default="true" 
+        childs="true"
+        tagClass="org.apache.catalina.core.StandardHost"
+        storeFactoryClass="org.apache.catalina.storeconfig.StandardHostSF">
+	    <TransientAttribute>domain</TransientAttribute>
+     </Description>
+     <Description
+	    tag="Context"
+		standard="true"
+		default="true" 
+		externalAllowed="true" 
+ 		storeSeparate="true"
+		backup="true" 
+        childs="true"
+        tagClass="org.apache.catalina.core.StandardContext"
+        storeFactoryClass="org.apache.catalina.storeconfig.StandardContextSF"
+        storeAppenderClass="org.apache.catalina.storeconfig.StoreContextAppender">
+	    <TransientAttribute>available</TransientAttribute>
+	    <TransientAttribute>configFile</TransientAttribute>
+	    <TransientAttribute>configured</TransientAttribute>
+	    <TransientAttribute>displayName</TransientAttribute>
+	    <TransientAttribute>distributable</TransientAttribute>
+	    <TransientAttribute>domain</TransientAttribute>
+	    <TransientAttribute>engineName</TransientAttribute>
+	    <TransientAttribute>name</TransientAttribute>
+	    <TransientAttribute>publicId</TransientAttribute>
+	    <TransientAttribute>replaceWelcomeFiles</TransientAttribute>
+	    <TransientAttribute>saveConfig</TransientAttribute>
+	    <TransientAttribute>sessionTimeout</TransientAttribute>
+	    <TransientAttribute>startupTime</TransientAttribute>
+	    <TransientAttribute>tldScanTime</TransientAttribute>
+     </Description>
+     <Description
+        id="org.apache.catalina.deploy.NamingResources.[GlobalNamingResources]"
+	    tag="GlobalNamingResources"
+		standard="true"
+		default="false"
+		attributes="false"
+        childs="true"
+        tagClass="org.apache.catalina.deploy.NamingResources"
+        storeFactoryClass="org.apache.catalina.storeconfig.GlobalNamingResourcesSF">
+     </Description>
+      <Description
+	    tag="Connector"
+		standard="true"
+		default="true" 
+        tagClass="org.apache.catalina.connector.Connector"
+        childs="true"
+        storeFactoryClass="org.apache.catalina.storeconfig.ConnectorSF"
+        storeAppenderClass="org.apache.catalina.storeconfig.ConnectorStoreAppender">
+	    <TransientAttribute>maxProcessor</TransientAttribute>
+ 	    <TransientAttribute>minProcessor</TransientAttribute>
+     </Description>
+     <Description
+	    tag="NamingResources"
+		standard="true"
+		default="false"
+		attributes="false"
+        childs="true"
+        tagClass="org.apache.catalina.deploy.NamingResources"
+        storeFactoryClass="org.apache.catalina.storeconfig.NamingResourcesSF">
+     </Description>
+	 <Description
+	    tag="Manager"
+		standard="false"
+		default="false" 
+		tagClass="org.apache.catalina.Manager"
+        storeFactoryClass="org.apache.catalina.storeconfig.ManagerSF">
+	    <TransientAttribute>entropy</TransientAttribute>
+	    <TransientAttribute>distributable</TransientAttribute>
+        <TransientChild>org.apache.catalina.ha.session.DeltaManager</TransientChild>
+        <TransientChild>org.apache.catalina.ha.session.SimpleTcpReplicationManager</TransientChild>
+    </Description>
+    <Description
+	    tag="Manager"
+		standard="false"
+		default="false" 
+        childs="true"
+		tagClass="org.apache.catalina.session.PersistentManager"
+        storeFactoryClass="org.apache.catalina.storeconfig.PersistentManagerSF">
+        <TransientAttribute>entropy</TransientAttribute>
+	    <TransientAttribute>distributable</TransientAttribute>
+     </Description>
+     <Description
+	    tag="Store"
+		standard="false"
+		default="false" 
+		tagClass="org.apache.catalina.session.FileStore"
+        storeFactoryClass="org.apache.catalina.storeconfig.StoreFactoryBase">
+     </Description>
+     <Description
+	    tag="Store"
+		standard="false"
+		default="false" 
+		tagClass="org.apache.catalina.session.JDBCStore"
+        storeFactoryClass="org.apache.catalina.storeconfig.StoreFactoryBase">
+     </Description>
+     <Description
+	    tag="Cluster"
+		standard="false"
+		default="false" 
+        childs="true"
+		tagClass="org.apache.catalina.ha.CatalinaCluster"
+        storeFactoryClass="org.apache.catalina.storeconfig.CatalinaClusterSF"
+        storeAppenderClass="org.apache.catalina.storeconfig.IDynamicPropertyStoreAppender">
+     </Description>
+     <Description
+	    tag="Realm"
+		standard="false"
+		default="false" 
+		tagClass="org.apache.catalina.Realm"
+        storeFactoryClass="org.apache.catalina.storeconfig.StoreFactoryBase">
+     </Description>
+     <Description
+	    tag="Parameter"
+		standard="true"
+		default="false"
+		tagClass="org.apache.catalina.deploy.ApplicationParameter"
+        storeFactoryClass="org.apache.catalina.storeconfig.StoreFactoryBase">
+     </Description>
+     <Description
+	    tag="Loader"
+		standard="true"
+		default="false" 
+		tagClass="org.apache.catalina.loader.WebappLoader"
+        storeFactoryClass="org.apache.catalina.storeconfig.LoaderSF">
+     </Description>
+      <Description
+	    tag="Listener"
+		standard="false"
+		default="false" 
+		tagClass="org.apache.catalina.LifecycleListener"
+        storeFactoryClass="org.apache.catalina.storeconfig.StoreFactoryBase">
+       <TransientChild>org.apache.catalina.mbeans.ServerLifecycleListener</TransientChild>
+       <TransientChild>org.apache.catalina.core.NamingContextListener</TransientChild>
+       <TransientChild>org.apache.catalina.startup.ContextConfig</TransientChild>
+       <TransientChild>org.apache.catalina.startup.EngineConfig</TransientChild>
+       <TransientChild>org.apache.catalina.startup.HostConfig</TransientChild>
+     </Description>
+     <Description
+        id="org.apache.catalina.core.StandardServer.[ServerLifecycleListener]"
+	    tag="Listener"
+		standard="false"
+		default="false" 
+        tagClass="org.apache.catalina.mbeans.ServerLifecycleListener"
+        storeFactoryClass="org.apache.catalina.storeconfig.StoreFactoryBase">
+     </Description>
+     <Description
+	    tag="Valve"
+		standard="false"
+		default="false" 
+		tagClass="org.apache.catalina.Valve"
+        storeFactoryClass="org.apache.catalina.storeconfig.StoreFactoryBase">
+	     <TransientChild>org.apache.catalina.authenticator.BasicAuthenticator</TransientChild>
+	     <TransientChild>org.apache.catalina.authenticator.DigestAuthenticator</TransientChild>
+	     <TransientChild>org.apache.catalina.authenticator.FormAuthenticator</TransientChild>
+	     <TransientChild>org.apache.catalina.authenticator.NonLoginAuthenticator</TransientChild>
+	     <TransientChild>org.apache.catalina.authenticator.SSLAuthenticator</TransientChild>
+	     <TransientChild>org.apache.catalina.core.StandardContextValve</TransientChild>
+	     <TransientChild>org.apache.catalina.core.StandardEngineValve</TransientChild>
+	     <TransientChild>org.apache.catalina.core.StandardHostValve</TransientChild>
+	     <TransientChild>org.apache.catalina.valves.CertificatesValve</TransientChild>
+	     <TransientChild>org.apache.catalina.valves.ErrorReportValve</TransientChild>
+	     <TransientChild>org.apache.catalina.valves.RequestListenerValve</TransientChild>
+	 </Description>
+     <Description
+	    tag="Environment"
+		standard="true"
+		default="false" 
+		tagClass="org.apache.catalina.deploy.ContextEnvironment"
+        storeFactoryClass="org.apache.catalina.storeconfig.StoreFactoryBase">
+     </Description>
+     <Description
+	    tag="EJB"
+		standard="true"
+		default="false" 
+		tagClass="org.apache.catalina.deploy.ContextEjb"
+        storeFactoryClass="org.apache.catalina.storeconfig.StoreFactoryBase">
+     </Description>
+     <Description
+	    tag="LocalEjb"
+		standard="true"
+		default="false" 
+		tagClass="org.apache.catalina.deploy.ContextLocalEjb"
+        storeFactoryClass="org.apache.catalina.storeconfig.StoreFactoryBase">
+     </Description>
+     <Description
+	    tag="Resource"
+		standard="true"
+		default="false" 
+		tagClass="org.apache.catalina.deploy.ContextResource"
+        storeFactoryClass="org.apache.catalina.storeconfig.StoreFactoryBase">
+     </Description>
+    <Description
+	    tag="Resources"
+		standard="false"
+		default="false" 
+		tagClass="javax.naming.directory.DirContext"
+        storeFactoryClass="org.apache.catalina.storeconfig.StoreFactoryBase">
+        <TransientAttribute>docBase</TransientAttribute>
+        <TransientAttribute>allowLinking</TransientAttribute>
+        <TransientAttribute>cacheMaxSize</TransientAttribute>
+        <TransientAttribute>cacheTTL</TransientAttribute>
+        <TransientAttribute>cached</TransientAttribute>
+        <TransientAttribute>caseSensitive</TransientAttribute>
+        <TransientChild>org.apache.naming.resources.WARDirContext</TransientChild>
+        <TransientChild>org.apache.naming.resources.FileDirContext</TransientChild>
+        <TransientChild>org.apache.naming.resources.ProxyDirContext</TransientChild>
+     </Description>
+     <Description
+	    tag="ResourceEnvRef"
+		standard="true"
+		default="false" 
+		tagClass="org.apache.catalina.deploy.ContextResourceEnvRef"
+        storeFactoryClass="org.apache.catalina.storeconfig.StoreFactoryBase">
+     </Description>
+     <Description
+	    tag="ResourceLink"
+		standard="true"
+		default="false" 
+		tagClass="org.apache.catalina.deploy.ContextResourceLink"
+        storeFactoryClass="org.apache.catalina.storeconfig.StoreFactoryBase">
+     </Description>
+     <Description
+	    tag="Transaction"
+		standard="true"
+		default="false" 
+		tagClass="org.apache.catalina.deploy.ContextTransaction"
+        storeFactoryClass="org.apache.catalina.storeconfig.StoreFactoryBase">
+     </Description>
+     <Description
+	    id="org.apache.catalina.core.StandardContext.[InstanceListener]"
+	    tag="InstanceListener"
+		standard="true"
+		default="false" 
+		attributes="false"
+        storeFactoryClass="org.apache.catalina.storeconfig.InstanceListenerSF">
+     </Description>
+     <Description
+	    id="org.apache.catalina.core.StandardContext.[WrapperLifecycle]"
+	    tag="WrapperLifecycle"
+		standard="true"
+		default="false" 
+		attributes="false"
+        storeFactoryClass="org.apache.catalina.storeconfig.WrapperLifecycleSF">
+     </Description>
+     <Description
+	    id="org.apache.catalina.core.StandardContext.[WrapperListener]"
+	    tag="WrapperListener"
+		standard="true"
+		default="false" 
+		attributes="false"
+        storeFactoryClass="org.apache.catalina.storeconfig.WrapperListenerSF">
+     </Description>
+     <Description
+	    id="org.apache.catalina.core.StandardContext.[WatchedResource]"
+	    tag="WatchedResource"
+		standard="true"
+		default="false" 
+		attributes="false"
+        storeFactoryClass="org.apache.catalina.storeconfig.WatchedResourceSF">
+     </Description>
+     <Description
+	    tag="Sender"
+		standard="false"
+		default="false" 
+		tagClass="org.apache.catalina.ha.tcp.ReplicationTransmitter"
+        storeFactoryClass="org.apache.catalina.storeconfig.StoreFactoryBase"
+        storeAppenderClass="org.apache.catalina.storeconfig.IDynamicPropertyStoreAppender">
+     </Description>
+     <Description
+	    tag="Sender"
+		standard="false"
+		default="false" 
+		tagClass="org.apache.catalina.ha.ClusterSender"
+        storeFactoryClass="org.apache.catalina.storeconfig.StoreFactoryBase">
+     </Description>
+     <Description
+	    tag="Receiver"
+		standard="false"
+		default="false" 
+		tagClass="org.apache.catalina.ha.ClusterReceiver"
+        storeFactoryClass="org.apache.catalina.storeconfig.StoreFactoryBase">
+     </Description>
+     <Description
+	    tag="Membership"
+		standard="false"
+		default="false"
+		tagClass="org.apache.catalina.ha.MembershipService"
+        storeFactoryClass="org.apache.catalina.storeconfig.StoreFactoryBase">
+     </Description>
+     <Description
+	    tag="Deployer"
+		standard="false"
+		default="false" 
+		tagClass="org.apache.catalina.ha.ClusterDeployer"
+        storeFactoryClass="org.apache.catalina.storeconfig.StoreFactoryBase">
+     </Description> 
+     <Description
+	    tag="ClusterListener"
+		standard="false"
+		default="false" 
+		tagClass="org.apache.catalina.ha.MessageListener"
+        storeFactoryClass="org.apache.catalina.storeconfig.StoreFactoryBase">
+     </Description>
+</Registry>
+

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/test/build.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/test/build.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/test/build.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,111 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!-- @author Peter Rossbach -->
+<project name="Tomcat: StoreConfig Testcases" basedir="." default="test">
+	<property file="../../../../build.properties" />
+	<property file="../../../../jakarta-tomcat-5/build.properties.default" />
+	<property name="test.report.logs" value="logs/reports" />
+	<property name="test.results" value="logs/test-results" />
+
+	<property name="compile.optimize" value="true" />
+	<property name="compile.debug" value="true" />
+	<property name="compile.source" value="1.4" />
+	<property name="compile.deprecation" value="true" />
+	<property name="compile.nowarn" value="off" />
+	<property name="compile.encoding" value="ISO-8859-1" />
+	<property name="build.dir" value="build/test" />
+	<property name="src.dir" value="src/share" />
+	<property name="catalina.home" value="../../../../jakarta-tomcat-5/build" />
+
+	<!-- Build the classpath -->
+	<path id="project.classpath">
+		<pathelement location="${jmx.jar}" />
+		<pathelement location="${commons-logging.jar}" />
+		<pathelement location="${log4j.jar}" />
+		<fileset dir="${catalina.home}/common/endorsed">
+			<include name="*.jar" />
+		</fileset>
+		<fileset dir="${catalina.home}/common/lib">
+			<include name="*.jar" />
+		</fileset>
+		<fileset dir="${catalina.home}/server/lib">
+			<include name="*.jar" />
+		</fileset>
+	</path>
+
+	<target name="build-prepare">
+		<available property="certstore.present" file="conf/catalina.keystore" />
+		<mkdir dir="${build.dir}" />
+		<mkdir dir="webapps/myapps" />
+		<mkdir dir="conf/Catalina/localhost" />
+	</target>
+
+	<target name="info" description="Shows a information about this ant script">
+		<echo>
+			This ant script implements some testcases to verify the key functions of store tomcat server.xml .
+			You find this script at: ${ant.file}
+		</echo>
+	</target>
+
+	<!-- This target compiles all sources out of the 
+			projects source tree -->
+	<target name="compile" depends="build-prepare" description="This target compiles all sources out of the projects source tree">
+
+		<!-- Copies the static resources out of the src tree
+				to the build/classes dir -->
+		<copy todir="${build.dir}/classes">
+			<fileset dir="${src.dir}">
+				<include name="**" />
+				<exclude name="**/*.java" />
+			</fileset>
+		</copy>
+
+		<!-- Compiles all sources -->
+		<javac destdir="${build.dir}/classes" srcdir="${src.dir}" includes="**/*.java" excludes="**/CVS/**" deprecation="${compile.deprecation}" debug="${compile.debug}" source="${compile.source}" optimize="${compile.optimize}" nowarn="${compile.nowarn}" encoding="${compile.encoding}">
+			<classpath>
+				<path refid="project.classpath" />
+			</classpath>
+		</javac>
+	</target>
+
+	<target name="test" depends="compile,genstore" description="Run unit tests">
+		<delete dir="${test.results}" />
+		<mkdir dir="${test.results}" />
+		<junit fork="yes" failureProperty="test.failure" filtertrace="false" >
+			<jvmarg value="-Dcatalina.base=${basedir}" />
+			<jvmarg value="-Dcatalina.home=${catalina.home}" />
+			<jvmarg value="-Dlog4j.configuration=file:conf/log4j.xml" />
+			<classpath>
+				<pathelement location="${build.dir}/classes" />
+				<path refid="project.classpath" />
+			</classpath>
+			<formatter type="plain" usefile="false" />
+			<formatter type="xml" />
+			<batchtest todir="${test.results}">
+				<fileset dir="${build.dir}/classes" includes="**/*Test.class" />
+			</batchtest>
+		</junit>
+		<mkdir dir="${test.report.logs}" />
+		<junitreport todir="${test.report.logs}">
+			<fileset dir="${test.results}" />
+			<report format="frames" todir="${test.report.logs}" />
+		</junitreport>
+		<antcall target="checktest" />
+	</target>
+
+	<target name="genstore" unless="certstore.present">
+		<ant antfile="genstore.xml" target="store" />
+	</target>
+
+	<target name="checktest" if="test.failure">
+		<fail message="some test failed" />
+	</target>
+
+	<target name="clean">
+		<delete dir="${build}/dir" />
+		<delete dir="webapps" />
+		<delete dir="build" />
+		<delete dir="${test.report.logs}" />
+		<delete dir="${test.results}" />
+		<delete dir="logs" />
+	</target>
+</project>

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/test/conf/catalina.keystore
===================================================================
(Binary files differ)


Property changes on: branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/test/conf/catalina.keystore
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/test/conf/context.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/test/conf/context.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/test/conf/context.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Context
+    cookies="false"
+    reloadable="true">
+	<Listener className="org.apache.catalina.storeconfig.InfoLifecycleListener" />
+</Context>

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/test/conf/log4j.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/test/conf/log4j.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/test/conf/log4j.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
+<!-- ===================================================================== -->
+<!-- -->
+<!-- Log4j Configuration -->
+<!-- -->
+<!-- ===================================================================== -->
+<!-- $Id: log4j.xml 303623 2005-01-08 11:15:00Z pero $ -->
+<!--
+| For more configuration infromation and examples see the Jakarta Log4j
+| owebsite: http://jakarta.apache.org/log4j
+-->
+<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/" debug="false">
+
+<!-- ============================== -->
+<!-- Append messages to the console -->
+<!-- ==============================-->
+
+<appender name="CONSOLE" class="org.apache.log4j.ConsoleAppender">
+<param name="Target" value="System.out"/>
+<param name="Threshold" value="debug"/>
+<layout class="org.apache.log4j.PatternLayout">
+<!--The default pattern: Date Priority [Category] Message\n-->
+<param name="ConversionPattern" value="%d{ABSOLUTE} %-5p [%c{1}] %m%n"/>
+</layout>
+</appender>
+
+
+<category name="org.apache.catalina.storeconfig" 
+           additivity="false"> 
+   <priority value="info" />
+   <appender-ref ref="CONSOLE" />
+</category>
+
+<category name="org.apache.catalina" 
+           additivity="false"> 
+   <priority value="info" />
+   <appender-ref ref="CONSOLE" />
+</category>
+<category name="org.apache.tomcat" 
+           additivity="false"> 
+   <priority value="error" />
+   <appender-ref ref="CONSOLE" />
+</category>
+<category name="org.apache.naming" 
+           additivity="false"> 
+   <priority value="info" />
+   <appender-ref ref="CONSOLE" />
+</category>
+
+<!-- Setup the Root c  -->
+<root>
+   <priority value="info" />
+   <appender-ref ref="CONSOLE"/>
+</root>
+</log4j:configuration> 
+

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/test/conf/server-registry-test.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/test/conf/server-registry-test.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/test/conf/server-registry-test.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,314 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Registry name="Tomcat" version="5.1.0" encoding="UTF-8" >
+     <Description
+	    tag="Server"
+		standard="true"
+		default="true" 
+        childs="true"
+        tagClass="org.apache.catalina.core.StandardServer"
+        storeFactoryClass="org.apache.catalina.storeconfig.StandardServerSF">
+     </Description>
+     <Description
+	    tag="Service"
+		standard="true"
+		default="true" 
+        childs="true"
+        tagClass="org.apache.catalina.core.StandardService"
+        storeFactoryClass="org.apache.catalina.storeconfig.StandardServiceSF">
+     </Description>
+     <Description
+	    tag="Engine"
+		standard="true"
+		default="true" 
+        childs="true"
+        tagClass="org.apache.catalina.core.StandardEngine"
+        storeFactoryClass="org.apache.catalina.storeconfig.StandardEngineSF">
+	    <TransientAttribute>domain</TransientAttribute>
+     </Description>
+     <Description
+	    tag="Host"
+		standard="true"
+		default="true" 
+        childs="true"
+        tagClass="org.apache.catalina.core.StandardHost"
+        storeFactoryClass="org.apache.catalina.storeconfig.StandardHostSF">
+	    <TransientAttribute>domain</TransientAttribute>
+     </Description>
+     <Description
+	    tag="Context"
+		standard="true"
+		default="true" 
+		storeSeparate="true"
+		backup="true" 
+        childs="true"
+        tagClass="org.apache.catalina.core.StandardContext"
+        storeFactoryClass="org.apache.catalina.storeconfig.StandardContextSF"
+        storeAppenderClass="org.apache.catalina.storeconfig.StoreContextAppender">
+	    <TransientAttribute>available</TransientAttribute>
+	    <TransientAttribute>configFile</TransientAttribute>
+	    <TransientAttribute>configured</TransientAttribute>
+	    <TransientAttribute>displayName</TransientAttribute>
+	    <TransientAttribute>distributable</TransientAttribute>
+	    <TransientAttribute>domain</TransientAttribute>
+	    <TransientAttribute>engineName</TransientAttribute>
+	    <TransientAttribute>name</TransientAttribute>
+	    <TransientAttribute>publicId</TransientAttribute>
+	    <TransientAttribute>replaceWelcomeFiles</TransientAttribute>
+	    <TransientAttribute>saveConfig</TransientAttribute>
+	    <TransientAttribute>sessionTimeout</TransientAttribute>
+	    <TransientAttribute>startupTime</TransientAttribute>
+	    <TransientAttribute>tldScanTime</TransientAttribute>
+     </Description>
+     <Description
+        id="org.apache.catalina.deploy.NamingResources.[GlobalNamingResources]"
+	    tag="GlobalNamingResources"
+		standard="true"
+		default="false"
+		attributes="false"
+        childs="true"
+        tagClass="org.apache.catalina.deploy.NamingResources"
+        storeFactoryClass="org.apache.catalina.storeconfig.GlobalNamingResourcesSF">
+     </Description>
+      <Description
+	    tag="Connector"
+		standard="true"
+		default="true" 
+        tagClass="org.apache.catalina.connector.Connector"
+        childs="true"
+        storeFactoryClass="org.apache.catalina.storeconfig.ConnectorSF"
+        storeWriterClass="org.apache.catalina.storeconfig.ConnectorStoreAppender">
+	    <TransientAttribute>maxProcessor</TransientAttribute>
+ 	    <TransientAttribute>minProcessor</TransientAttribute>
+     </Description>
+      <Description
+        id="org.apache.catalina.connector.Connector.[ProtocolHandler]"
+	    tag="ProtocolHandler"
+		standard="true"
+		default="false" 
+        tagClass="org.apache.coyote.ProtocolHandler"
+        storeFactoryClass="org.apache.catalina.storeconfig.StoreFactoryBase">
+	    <TransientAttribute>clientauth</TransientAttribute>
+ 	    <TransientAttribute>keypass</TransientAttribute>
+	    <TransientAttribute>keystore</TransientAttribute>
+	    <TransientAttribute>keytype</TransientAttribute>
+	    <TransientAttribute>name</TransientAttribute>
+	    <TransientAttribute>port</TransientAttribute>
+	    <TransientAttribute>protocol</TransientAttribute>
+	    <TransientAttribute>protocols</TransientAttribute>
+	    <TransientAttribute>randomfile</TransientAttribute>
+	    <TransientAttribute>secure</TransientAttribute>
+	 </Description>
+     <Description
+	    tag="NamingResources"
+		standard="true"
+		default="false"
+		attributes="false"
+        childs="true"
+        tagClass="org.apache.catalina.deploy.NamingResources"
+        storeFactoryClass="org.apache.catalina.storeconfig.NamingResourcesSF">
+     </Description>
+	 <Description
+	    tag="Manager"
+		standard="false"
+		default="false" 
+		tagClass="org.apache.catalina.session.StandardManager"
+        storeFactoryClass="org.apache.catalina.storeconfig.ManagerSF">
+	    <TransientAttribute>entropy</TransientAttribute>
+	    <TransientAttribute>distributable</TransientAttribute>
+    </Description>
+    <Description
+	    tag="Manager"
+		standard="false"
+		default="false" 
+        childs="true"
+		tagClass="org.apache.catalina.session.PersistentManager"
+        storeFactoryClass="org.apache.catalina.storeconfig.PersistentManagerSF">
+        <TransientAttribute>entropy</TransientAttribute>
+	    <TransientAttribute>distributable</TransientAttribute>
+     </Description>
+     <Description
+	    tag="Store"
+		standard="false"
+		default="false" 
+		tagClass="org.apache.catalina.session.FileStore"
+        storeFactoryClass="org.apache.catalina.storeconfig.StoreFactoryBase">
+     </Description>
+     <Description
+	    tag="Store"
+		standard="false"
+		default="false" 
+		tagClass="org.apache.catalina.session.JDBCStore"
+        storeFactoryClass="org.apache.catalina.storeconfig.StoreFactoryBase">
+     </Description>
+     <Description
+	    tag="Cluster"
+		standard="false"
+		default="false" 
+        childs="true"
+		tagClass="org.apache.catalina.cluster.CatalinaCluster"
+        storeFactoryClass="org.apache.catalina.storeconfig.CatalinaClusterSF">
+     </Description>
+     <Description
+	    tag="Realm"
+		standard="false"
+		default="false" 
+		tagClass="org.apache.catalina.Realm"
+        storeFactoryClass="org.apache.catalina.storeconfig.StoreFactoryBase">
+     </Description>
+     <Description
+	    tag="Parameter"
+		standard="true"
+		default="false"
+		tagClass="org.apache.catalina.deploy.ApplicationParameter"
+        storeFactoryClass="org.apache.catalina.storeconfig.StoreFactoryBase">
+     </Description>
+     <Description
+	    tag="Loader"
+		standard="true"
+		default="false" 
+		tagClass="org.apache.catalina.loader.WebappLoader"
+        storeFactoryClass="org.apache.catalina.storeconfig.LoaderSF">
+     </Description>
+      <Description
+	    tag="Listener"
+		standard="false"
+		default="false" 
+		tagClass="org.apache.catalina.LifecycleListener"
+        storeFactoryClass="org.apache.catalina.storeconfig.StoreFactoryBase">
+       <TransientChild>org.apache.catalina.mbeans.ServerLifecycleListener</TransientChild>
+       <TransientChild>org.apache.catalina.core.NamingContextListener</TransientChild>
+       <TransientChild>org.apache.catalina.startup.ContextConfig</TransientChild>
+       <TransientChild>org.apache.catalina.startup.EngineConfig</TransientChild>
+       <TransientChild>org.apache.catalina.startup.HostConfig</TransientChild>
+     </Description>
+     <Description
+        id="org.apache.catalina.core.StandardServer.[ServerLifecycleListener]"
+	    tag="Listener"
+		standard="false"
+		default="false" 
+        tagClass="org.apache.catalina.mbeans.ServerLifecycleListener"
+        storeFactoryClass="org.apache.catalina.storeconfig.StoreFactoryBase">
+     </Description>
+     <Description
+	    tag="Valve"
+		standard="false"
+		default="false" 
+		tagClass="org.apache.catalina.Valve"
+        storeFactoryClass="org.apache.catalina.storeconfig.StoreFactoryBase">
+	     <TransientChild>org.apache.catalina.authenticator.BasicAuthenticator</TransientChild>
+	     <TransientChild>org.apache.catalina.authenticator.DigestAuthenticator</TransientChild>
+	     <TransientChild>org.apache.catalina.authenticator.FormAuthenticator</TransientChild>
+	     <TransientChild>org.apache.catalina.authenticator.NonLoginAuthenticator</TransientChild>
+	     <TransientChild>org.apache.catalina.authenticator.SSLAuthenticator</TransientChild>
+	     <TransientChild>org.apache.catalina.core.StandardContextValve</TransientChild>
+	     <TransientChild>org.apache.catalina.core.StandardEngineValve</TransientChild>
+	     <TransientChild>org.apache.catalina.core.StandardHostValve</TransientChild>
+	     <TransientChild>org.apache.catalina.valves.CertificatesValve</TransientChild>
+	     <TransientChild>org.apache.catalina.valves.ErrorReportValve</TransientChild>
+	     <TransientChild>org.apache.catalina.valves.RequestListenerValve</TransientChild>
+	     <TransientChild>org.apache.catalina.cluster.tcp.ReplicationValve</TransientChild>
+	 </Description>
+     <Description
+	    tag="Environment"
+		standard="true"
+		default="false" 
+		tagClass="org.apache.catalina.deploy.ContextEnvironment"
+        storeFactoryClass="org.apache.catalina.storeconfig.StoreFactoryBase">
+     </Description>
+     <Description
+	    tag="EJB"
+		standard="true"
+		default="false" 
+		tagClass="org.apache.catalina.deploy.ContextEjb"
+        storeFactoryClass="org.apache.catalina.storeconfig.StoreFactoryBase">
+     </Description>
+     <Description
+	    tag="LocalEjb"
+		standard="true"
+		default="false" 
+		tagClass="org.apache.catalina.deploy.ContextLocalEjb"
+        storeFactoryClass="org.apache.catalina.storeconfig.StoreFactoryBase">
+     </Description>
+     <Description
+	    tag="Resource"
+		standard="true"
+		default="false" 
+		tagClass="org.apache.catalina.deploy.ContextResource"
+        storeFactoryClass="org.apache.catalina.storeconfig.StoreFactoryBase">
+     </Description>
+     <Description
+	    tag="ResourceEnvRef"
+		standard="true"
+		default="false" 
+		tagClass="org.apache.catalina.deploy.ContextResourceEnvRef"
+        storeFactoryClass="org.apache.catalina.storeconfig.StoreFactoryBase">
+     </Description>
+     <Description
+	    tag="ResourceLink"
+		standard="true"
+		default="false" 
+		tagClass="org.apache.catalina.deploy.ContextResourceLink"
+        storeFactoryClass="org.apache.catalina.storeconfig.StoreFactoryBase">
+     </Description>
+     <Description
+		id="org.apache.catalina.core.StandardContext.[InstanceListener]"
+	    tag="InstanceListener"
+		standard="true"
+		default="false" 
+		attributes="false"
+        storeFactoryClass="org.apache.catalina.storeconfig.InstanceListenerSF">
+     </Description>
+     <Description
+		id="org.apache.catalina.core.StandardContext.[WrapperLifecycle]"
+	    tag="WrapperLifecycle"
+		standard="true"
+		default="false" 
+		attributes="false"
+        storeFactoryClass="org.apache.catalina.storeconfig.WrapperLifecycleSF">
+     </Description>
+     <Description
+		id="org.apache.catalina.core.StandardContext.[WrapperListener]"
+	    tag="WrapperListener"
+		standard="true"
+		default="false" 
+		attributes="false"
+        storeFactoryClass="org.apache.catalina.storeconfig.WrapperListenerSF">
+     </Description>
+     <Description
+		id="org.apache.catalina.core.StandardContext.[WatchedResource]"
+	    tag="WatchedResource"
+		standard="true"
+		default="false" 
+		attributes="false"
+        storeFactoryClass="org.apache.catalina.storeconfig.WatchedResourceSF">
+     </Description>
+     <Description
+	    tag="Sender"
+		standard="false"
+		default="false" 
+		tagClass="org.apache.catalina.cluster.ClusterSender"
+        storeFactoryClass="org.apache.catalina.storeconfig.StoreFactoryBase">
+     </Description>
+     <Description
+	    tag="Receiver"
+		standard="false"
+		default="false" 
+		tagClass="org.apache.catalina.cluster.ClusterReceiver"
+        storeFactoryClass="org.apache.catalina.storeconfig.StoreFactoryBase">
+     </Description>
+     <Description
+	    tag="Membership"
+		standard="false"
+		default="false" 
+		tagClass="org.apache.catalina.cluster.ClusterMembership"
+        storeFactoryClass="org.apache.catalina.storeconfig.StoreFactoryBase">
+     </Description>
+     <Description
+	    tag="Deployer"
+		standard="false"
+		default="false" 
+		tagClass="org.apache.catalina.cluster.ClusterDeployer"
+        storeFactoryClass="org.apache.catalina.storeconfig.StoreFactoryBase">
+     </Description> 
+</Registry>
+

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/test/conf/server.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/test/conf/server.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/test/conf/server.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,359 @@
+<!-- Example Server Configuration File -->
+<!-- Note that component elements are nested corresponding to their
+     parent-child relationships with each other -->
+
+<!-- A "Server" is a singleton element that represents the entire JVM,
+     which may contain one or more "Service" instances.  The Server
+     listens for a shutdown command on the indicated port.
+
+     Note:  A "Server" is not itself a "Container", so you may not
+     define subcomponents such as "Valves" or "Loggers" at this level.
+ -->
+
+<Server port="8005" shutdown="SHUTDOWN" debug="0">
+
+
+  <!-- Comment these entries out to disable JMX MBeans support -->
+  <!-- You may also configure custom components (e.g. Valves/Realms) by 
+       including your own mbean-descriptor file(s), and setting the 
+       "descriptors" attribute to point to a ';' seperated list of paths
+       (in the ClassLoader sense) of files to add to the default list.
+       e.g. descriptors="/com/myfirm/mypackage/mbean-descriptor.xml"
+  -->
+  <Listener className="org.apache.catalina.mbeans.ServerLifecycleListener"
+            debug="0"/>
+  <Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener"
+            debug="0"/>
+
+  <!-- Global JNDI resources -->
+  <GlobalNamingResources>
+
+    <!-- Test entry for demonstration purposes -->
+    <Environment name="simpleValue" type="java.lang.Integer" value="30"/>
+
+    <!-- Editable user database that can also be used by
+         UserDatabaseRealm to authenticate users -->
+    <Resource name="UserDatabase" auth="Container"
+              type="org.apache.catalina.UserDatabase"
+       description="User database that can be updated and saved"
+           factory="org.apache.catalina.users.MemoryUserDatabaseFactory"
+          pathname="conf/tomcat-users.xml" />
+
+  </GlobalNamingResources>
+
+  <!-- A "Service" is a collection of one or more "Connectors" that share
+       a single "Container" (and therefore the web applications visible
+       within that Container).  Normally, that Container is an "Engine",
+       but this is not required.
+
+       Note:  A "Service" is not itself a "Container", so you may not
+       define subcomponents such as "Valves" or "Loggers" at this level.
+   -->
+
+  <!-- Define the Tomcat Stand-Alone Service -->
+  <Service name="Catalina">
+
+    <!-- A "Connector" represents an endpoint by which requests are received
+         and responses are returned.  Each Connector passes requests on to the
+         associated "Container" (normally an Engine) for processing.
+
+         By default, a non-SSL HTTP/1.1 Connector is established on port 8080.
+         You can also enable an SSL HTTP/1.1 Connector on port 8443 by
+         following the instructions below and uncommenting the second Connector
+         entry.  SSL support requires the following steps (see the SSL Config
+         HOWTO in the Tomcat 5 documentation bundle for more detailed
+         instructions):
+         * If your JDK version 1.3 or prior, download and install JSSE 1.0.2 or
+           later, and put the JAR files into "$JAVA_HOME/jre/lib/ext".
+         * Execute:
+             %JAVA_HOME%\bin\keytool -genkey -alias tomcat -keyalg RSA (Windows)
+             $JAVA_HOME/bin/keytool -genkey -alias tomcat -keyalg RSA  (Unix)
+           with a password value of "changeit" for both the certificate and
+           the keystore itself.
+
+         By default, DNS lookups are enabled when a web application calls
+         request.getRemoteHost().  This can have an adverse impact on
+         performance, so you can disable it by setting the
+         "enableLookups" attribute to "false".  When DNS lookups are disabled,
+         request.getRemoteHost() will return the String version of the
+         IP address of the remote client.
+    -->
+
+    <!-- Define a non-SSL HTTP/1.1 Connector on port 8080 -->
+    <Connector port="8080"
+               maxThreads="150" minSpareThreads="25" maxSpareThreads="75"
+               enableLookups="false" redirectPort="8443" acceptCount="100"
+               debug="0" connectionTimeout="20000" 
+               disableUploadTimeout="true" />
+    <!-- Note : To disable connection timeouts, set connectionTimeout value
+     to 0 -->
+	
+	<!-- Note : To use gzip compression you could set the following properties :
+	
+			   compression="on" 
+			   compressionMinSize="2048" 
+			   noCompressionUserAgents="gozilla, traviata" 
+			   compressableMimeType="text/html,text/xml"
+	-->
+
+    <!-- Define a SSL HTTP/1.1 Connector on port 8443 -->
+    <!--
+    <Connector port="8443" 
+               maxThreads="150" minSpareThreads="25" maxSpareThreads="75"
+               enableLookups="false" disableUploadTimeout="true"
+               acceptCount="100" debug="0" scheme="https" secure="true"
+               clientAuth="false" sslProtocol="TLS" />
+    -->
+
+    <!-- Define an AJP 1.3 Connector on port 8009 -->
+    <Connector port="8009" 
+               enableLookups="false" redirectPort="8443" debug="0"
+               protocol="AJP/1.3" />
+
+    <!-- Define a Proxied HTTP/1.1 Connector on port 8082 -->
+    <!-- See proxy documentation for more information about using this. -->
+    <!--
+    <Connector port="8082" 
+               maxThreads="150" minSpareThreads="25" maxSpareThreads="75"
+               enableLookups="false"
+               acceptCount="100" debug="0" connectionTimeout="20000"
+               proxyPort="80" disableUploadTimeout="true" />
+    -->
+
+    <!-- An Engine represents the entry point (within Catalina) that processes
+         every request.  The Engine implementation for Tomcat stand alone
+         analyzes the HTTP headers included with the request, and passes them
+         on to the appropriate Host (virtual host). -->
+
+    <!-- You should set jvmRoute to support load-balancing via AJP ie :
+    <Engine name="Standalone" defaultHost="localhost" debug="0" jvmRoute="jvm1">         
+    --> 
+         
+    <!-- Define the top level container in our container hierarchy -->
+    <Engine name="Catalina" defaultHost="localhost" debug="0">
+
+      <!-- The request dumper valve dumps useful debugging information about
+           the request headers and cookies that were received, and the response
+           headers and cookies that were sent, for all requests received by
+           this instance of Tomcat.  If you care only about requests to a
+           particular virtual host, or a particular application, nest this
+           element inside the corresponding <Host> or <Context> entry instead.
+
+           For a similar mechanism that is portable to all Servlet 2.4
+           containers, check out the "RequestDumperFilter" Filter in the
+           example application (the source for this filter may be found in
+           "$CATALINA_HOME/webapps/examples/WEB-INF/classes/filters").
+
+           Request dumping is disabled by default.  Uncomment the following
+           element to enable it. -->
+      <!--
+      <Valve className="org.apache.catalina.valves.RequestDumperValve"/>
+      -->
+
+      <!-- Because this Realm is here, an instance will be shared globally -->
+
+      <!-- This Realm uses the UserDatabase configured in the global JNDI
+           resources under the key "UserDatabase".  Any edits
+           that are performed against this UserDatabase are immediately
+           available for use by the Realm.  -->
+      <Realm className="org.apache.catalina.realm.UserDatabaseRealm"
+                 debug="0" resourceName="UserDatabase"/>
+
+      <!-- Comment out the old realm but leave here for now in case we
+           need to go back quickly -->
+      <!--
+      <Realm className="org.apache.catalina.realm.MemoryRealm" />
+      -->
+
+      <!-- Replace the above Realm with one of the following to get a Realm
+           stored in a database and accessed via JDBC -->
+
+      <!--
+      <Realm  className="org.apache.catalina.realm.JDBCRealm" debug="99"
+             driverName="org.gjt.mm.mysql.Driver"
+          connectionURL="jdbc:mysql://localhost/authority"
+         connectionName="test" connectionPassword="test"
+              userTable="users" userNameCol="user_name" userCredCol="user_pass"
+          userRoleTable="user_roles" roleNameCol="role_name" />
+      -->
+
+      <!--
+      <Realm  className="org.apache.catalina.realm.JDBCRealm" debug="99"
+             driverName="oracle.jdbc.driver.OracleDriver"
+          connectionURL="jdbc:oracle:thin:@ntserver:1521:ORCL"
+         connectionName="scott" connectionPassword="tiger"
+              userTable="users" userNameCol="user_name" userCredCol="user_pass"
+          userRoleTable="user_roles" roleNameCol="role_name" />
+      -->
+
+      <!--
+      <Realm  className="org.apache.catalina.realm.JDBCRealm" debug="99"
+             driverName="sun.jdbc.odbc.JdbcOdbcDriver"
+          connectionURL="jdbc:odbc:CATALINA"
+              userTable="users" userNameCol="user_name" userCredCol="user_pass"
+          userRoleTable="user_roles" roleNameCol="role_name" />
+      -->
+
+      <!-- Define the default virtual host
+           Note: XML Schema validation will not work with Xerces 2.2.
+       -->
+      <Host name="localhost" debug="0" appBase="webapps"
+       unpackWARs="true" autoDeploy="true"
+       xmlValidation="false" xmlNamespaceAware="false">
+
+        <!-- Defines a cluster for this node,
+             By defining this element, means that every manager will be changed.
+             So when running a cluster, only make sure that you have webapps in there
+             that need to be clustered and remove the other ones.
+             A cluster has the following parameters:
+
+             className = the fully qualified name of the cluster class
+
+             name = a descriptive name for your cluster, can be anything
+
+             debug = the debug level, higher means more output
+
+             mcastAddr = the multicast address, has to be the same for all the nodes
+
+             mcastPort = the multicast port, has to be the same for all the nodes
+             
+             mcastBindAddr = bind the multicast socket to a specific address
+             
+             mcastTTL = the multicast TTL if you want to limit your broadcast
+             
+             mcastSoTimeout = the multicast readtimeout 
+
+             mcastFrequency = the number of milliseconds in between sending a "I'm alive" heartbeat
+
+             mcastDropTime = the number a milliseconds before a node is considered "dead" if no heartbeat is received
+
+             tcpThreadCount = the number of threads to handle incoming replication requests, optimal would be the same amount of threads as nodes 
+
+             tcpListenAddress = the listen address (bind address) for TCP cluster request on this host, 
+                                in case of multiple ethernet cards.
+                                auto means that address becomes
+                                InetAddress.getLocalHost().getHostAddress()
+
+             tcpListenPort = the tcp listen port
+
+             tcpSelectorTimeout = the timeout (ms) for the Selector.select() method in case the OS
+                                  has a wakup bug in java.nio. Set to 0 for no timeout
+
+             printToScreen = true means that managers will also print to std.out
+
+             expireSessionsOnShutdown = true means that 
+
+             useDirtyFlag = true means that we only replicate a session after setAttribute,removeAttribute has been called.
+                            false means to replicate the session after each request.
+                            false means that replication would work for the following piece of code:
+                            <%
+                            HashMap map = (HashMap)session.getAttribute("map");
+                            map.put("key","value");
+                            %>
+             replicationMode = can be either 'pooled', 'synchronous' or 'asynchronous'.
+                               * Pooled means that the replication happens using several sockets in a synchronous way. Ie, the data gets replicated, then the request return. This is the same as the 'synchronous' setting except it uses a pool of sockets, hence it is multithreaded. This is the fastest and safest configuration. To use this, also increase the nr of tcp threads that you have dealing with replication.
+                               * Synchronous means that the thread that executes the request, is also the
+                               thread the replicates the data to the other nodes, and will not return until all
+                               nodes have received the information.
+                               * Asynchronous means that there is a specific 'sender' thread for each cluster node,
+                               so the request thread will queue the replication request into a "smart" queue,
+                               and then return to the client.
+                               The "smart" queue is a queue where when a session is added to the queue, and the same session
+                               already exists in the queue from a previous request, that session will be replaced
+                               in the queue instead of replicating two requests. This almost never happens, unless there is a 
+                               large network delay.
+        -->             
+        <!--
+            When configuring for clustering, you also add in a valve to catch all the requests
+            coming in, at the end of the request, the session may or may not be replicated.
+            A session is replicated if and only if all the conditions are met:
+            1. useDirtyFlag is true or setAttribute or removeAttribute has been called AND
+            2. a session exists (has been created)
+            3. the request is not trapped by the "filter" attribute
+
+            The filter attribute is to filter out requests that could not modify the session,
+            hence we don't replicate the session after the end of this request.
+            The filter is negative, ie, anything you put in the filter, you mean to filter out,
+            ie, no replication will be done on requests that match one of the filters.
+            The filter attribute is delimited by ;, so you can't escape out ; even if you wanted to.
+
+            filter=".*\.gif;.*\.js;" means that we will not replicate the session after requests with the URI
+            ending with .gif and .js are intercepted.
+            
+            The deployer element can be used to deploy apps cluster wide.
+            Currently the deployment only deploys/undeploys to working members in the cluster
+            so no WARs are copied upons startup of a broken node.
+            The deployer watches a directory (watchDir) for WAR files when watchEnabled="true"
+            When a new war file is added the war gets deployed to the local instance,
+            and then deployed to the other instances in the cluster.
+            When a war file is deleted from the watchDir the war is undeployed locally 
+            and cluster wide
+        -->
+        
+        <!--
+        <Cluster className="org.apache.catalina.cluster.tcp.SimpleTcpCluster"
+                 managerClassName="org.apache.catalina.cluster.session.DeltaManager"
+                 expireSessionsOnShutdown="false"
+                 useDirtyFlag="true">
+
+            <Membership 
+                className="org.apache.catalina.cluster.mcast.McastService"
+                mcastAddr="228.0.0.4"
+                mcastPort="45564"
+                mcastFrequency="500"
+                mcastDropTime="3000"/>
+
+            <Receiver 
+                className="org.apache.catalina.cluster.tcp.ReplicationListener"
+                tcpListenAddress="auto"
+                tcpListenPort="4001"
+                tcpSelectorTimeout="100"
+                tcpThreadCount="6"/>
+
+            <Sender
+                className="org.apache.catalina.cluster.tcp.ReplicationTransmitter"
+                replicationMode="pooled"/>
+
+            <Valve className="org.apache.catalina.cluster.tcp.ReplicationValve"
+                   filter=".*\.gif;.*\.js;.*\.jpg;.*\.htm;.*\.html;.*\.txt;"/>
+                   
+            <Deployer className="org.apache.catalina.cluster.deploy.FarmWarDeployer"
+                      tempDir="/tmp/war-temp/"
+                      deployDir="/tmp/war-deploy/"
+                      watchDir="/tmp/war-listen/"
+                      watchEnabled="false"/>
+        </Cluster>
+        -->        
+
+
+
+        <!-- Normally, users must authenticate themselves to each web app
+             individually.  Uncomment the following entry if you would like
+             a user to be authenticated the first time they encounter a
+             resource protected by a security constraint, and then have that
+             user identity maintained across *all* web applications contained
+             in this virtual host. -->
+        <!--
+        <Valve className="org.apache.catalina.authenticator.SingleSignOn"
+                   debug="0"/>
+        -->
+
+        <!-- Access log processes all requests for this virtual host.  By
+             default, log files are created in the "logs" directory relative to
+             $CATALINA_HOME.  If you wish, you can specify a different
+             directory with the "directory" attribute.  Specify either a relative
+             (to $CATALINA_HOME) or absolute path to the desired directory.
+        -->
+        <!--
+        <Valve className="org.apache.catalina.valves.AccessLogValve"
+                 directory="logs"  prefix="localhost_access_log." suffix=".txt"
+                 pattern="common" resolveHosts="false"/>
+        -->
+
+      </Host>
+
+    </Engine>
+
+  </Service>
+
+</Server>

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/test/genstore.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/test/genstore.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/test/genstore.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<project name="store" default="store" basedir=".">
+
+     <target name="store">
+        <delete file="conf/catalina.keystore"/>
+		<genkey alias="tomcat" storepass="changeit" keypass="changeit" 
+			keystore="conf/catalina.keystore" keyalg="rsa">
+			<dname>
+				<param name="CN" value="localhost"/>
+				<param name="OU" value="Software Deveploment Tomcat"/>
+				<param name="O" value="Apache Foundation"/>
+				<param name="L" value="Bochum"/>
+				<param name="C" value="DE"/>
+			</dname>
+		</genkey>
+    </target>
+
+</project>

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/test/src/share/org/apache/catalina/storeconfig/ConnectorSFTest.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/test/src/share/org/apache/catalina/storeconfig/ConnectorSFTest.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/test/src/share/org/apache/catalina/storeconfig/ConnectorSFTest.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,161 @@
+/*
+ * Copyright 1999-2001,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.storeconfig;
+
+import java.beans.IntrospectionException;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.List;
+
+import junit.framework.TestCase;
+
+import org.apache.catalina.LifecycleListener;
+import org.apache.catalina.connector.Connector;
+
+/**
+ * @author Peter Rossbach
+ *  
+ */
+public class ConnectorSFTest extends TestCase {
+    StoreRegistry registry;
+
+    StringWriter writer = new StringWriter();
+
+    PrintWriter pWriter = new PrintWriter(writer);
+
+    Connector connector;
+
+    ConnectorSF factory;
+
+    StoreDescription desc;
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see junit.framework.TestCase#setUp()
+     */
+    protected void setUp() throws Exception {
+
+        super.setUp();
+        registry = new StoreRegistry();
+        desc = new StoreDescription();
+        desc.setTag("Connector");
+        desc.setTagClass("org.apache.catalina.connector.Connector");
+        desc.setStandard(false);
+        desc
+                .setStoreFactoryClass("org.apache.catalina.storeconfig.ConnectorSF");
+        registry.registerDescription(desc);
+        factory = new ConnectorSF();
+        desc.setStoreFactory(factory);
+        desc.getStoreFactory().setStoreAppender(new ConnectorStoreAppender());
+        factory.setRegistry(registry);
+        desc.addTransientAttribute("minProcessor");
+        desc.addTransientAttribute("maxProcessor");
+        registerDescriptor("Listener", LifecycleListener.class);
+        connector = new Connector("HTTP/1.1");
+    }
+
+    private StoreDescription registerDescriptor(String tag, Class aClass) {
+        return registerDescriptor(tag, aClass,
+                "org.apache.catalina.storeconfig.StoreFactoryBase", false,
+                false);
+    }
+
+    private StoreDescription registerDescriptor(String tag, Class aClass,
+            String factoryClass, boolean fstandard, boolean fdefault) {
+        return DescriptorHelper.registerDescriptor(desc, registry, aClass
+                .getName(), tag, aClass.getName(), factoryClass, fstandard,
+                fdefault);
+    }
+
+    public void testListener() throws Exception {
+        connector
+                .addLifecycleListener(new org.apache.catalina.mbeans.ServerLifecycleListener());
+        String aspectedResult = "<Connector>"
+                + LF.LINE_SEPARATOR
+                + "  <Listener className=\"org.apache.catalina.mbeans.ServerLifecycleListener\"/>"
+                + LF.LINE_SEPARATOR + "</Connector>" + LF.LINE_SEPARATOR;
+        check(aspectedResult);
+    }
+
+    public void testWithProtocolHandler() throws Exception {
+        connector.setProperty("acceptCount", "10");
+        connector.setProperty("maxSpareThreads", "74");
+        String aspectedResult = "<Connector" + LF.LINE_SEPARATOR
+                + "    maxSpareThreads=\"74\"" + LF.LINE_SEPARATOR
+                + "    acceptCount=\"10\">" + LF.LINE_SEPARATOR
+                + "</Connector>" + LF.LINE_SEPARATOR;
+        check(aspectedResult);
+    }
+
+    public void testStoreAJP() throws Exception {
+        connector.setProtocol("AJP/1.3");
+        String aspectedResult = "<Connector" + LF.LINE_SEPARATOR
+                + "    protocol=\"AJP/1.3\">" + LF.LINE_SEPARATOR
+                + "</Connector>" + LF.LINE_SEPARATOR;
+        check(aspectedResult);
+    }
+
+    public void testSSL() throws Exception {
+        setupSecureConnector();
+        String aspectedResult = "<Connector" + LF.LINE_SEPARATOR
+                + "    port=\"8443\"" + LF.LINE_SEPARATOR
+                + "    scheme=\"https\"" + LF.LINE_SEPARATOR
+                + "    secure=\"true\"" + LF.LINE_SEPARATOR
+                + "    minSpareThreads=\"30\"" + LF.LINE_SEPARATOR
+                + "    clientAuth=\"false\"" + LF.LINE_SEPARATOR
+                + "    keystorePass=\"changeit\"" + LF.LINE_SEPARATOR
+                + "    keystoreFile=\"conf/catalina.keystore\""
+                + LF.LINE_SEPARATOR + "    maxSpareThreads=\"175\""
+                + LF.LINE_SEPARATOR + "    sslProtocol=\"TLS\">"
+                + LF.LINE_SEPARATOR + "</Connector>" + LF.LINE_SEPARATOR;
+        check(aspectedResult);
+    }
+
+    protected void setupSecureConnector() {
+        connector.setPort(8443);
+        connector.setProperty("minSpareThreads", "30");
+        connector.setProperty("maxSpareThreads", "175");
+        connector.setEnableLookups(false);
+        connector.setProperty("disableUploadTimeout", "true");
+        connector.setSecure(true);
+        connector.setProperty("backlog", "100");
+        connector.setScheme("https");
+        connector.setProperty("clientAuth", "false");
+        connector.setProperty("sslProtocol", "TLS");
+        connector.setProperty("keystoreFile", "conf/catalina.keystore");
+        connector.setProperty("keystorePass", "changeit");
+    }
+
+    public void testConnectorAppender() throws IntrospectionException {
+        setupSecureConnector();
+        ConnectorStoreAppender appender = (ConnectorStoreAppender)desc.getStoreFactory().getStoreAppender();
+        List propertyList = appender.getPropertyKeys(connector);
+        assertTrue(propertyList.contains("protocol"));   
+    }
+    
+    public void testStoreEmpty() throws Exception {
+        String aspectedResult = "<Connector>" + LF.LINE_SEPARATOR
+                + "</Connector>" + LF.LINE_SEPARATOR;
+        check(aspectedResult);
+    }
+
+    protected void check(String aspectedResult) throws Exception {
+        factory.store(pWriter, -2, connector);
+        assertEquals(aspectedResult, writer.toString());
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/test/src/share/org/apache/catalina/storeconfig/ConnectorStoreAppenderTest.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/test/src/share/org/apache/catalina/storeconfig/ConnectorStoreAppenderTest.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/test/src/share/org/apache/catalina/storeconfig/ConnectorStoreAppenderTest.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,104 @@
+/*
+ * Copyright 1999-2001,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.storeconfig;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.List;
+
+import junit.framework.TestCase;
+
+import org.apache.catalina.LifecycleListener;
+import org.apache.catalina.connector.Connector;
+
+/**
+ * @author Peter Rossbach
+ *  
+ */
+public class ConnectorStoreAppenderTest extends TestCase {
+    StoreRegistry registry;
+
+    StringWriter writer = new StringWriter();
+
+    PrintWriter pWriter = new PrintWriter(writer);
+
+    Connector connector;
+
+    ConnectorSF factory;
+
+    StoreDescription desc;
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see junit.framework.TestCase#setUp()
+     */
+    protected void setUp() throws Exception {
+
+        super.setUp();
+        registry = new StoreRegistry();
+        desc = new StoreDescription();
+        desc.setTag("Connector");
+        desc.setTagClass("org.apache.catalina.connector.Connector");
+        desc.setStandard(false);
+        desc
+                .setStoreFactoryClass("org.apache.catalina.storeconfig.ConnectorSF");
+        registry.registerDescription(desc);
+        factory = new ConnectorSF();
+        desc.setStoreFactory(factory);
+        desc.getStoreFactory().setStoreAppender(new ConnectorStoreAppender());
+        factory.setRegistry(registry);
+        registerDescriptor("Listener", LifecycleListener.class);
+        connector = new Connector("HTTP/1.1");
+    }
+
+    private StoreDescription registerDescriptor(String tag, Class aClass) {
+        return registerDescriptor(tag, aClass,
+                "org.apache.catalina.storeconfig.StoreFactoryBase", false,
+                false);
+    }
+
+    private StoreDescription registerDescriptor(String tag, Class aClass,
+            String factoryClass, boolean fstandard, boolean fdefault) {
+        return DescriptorHelper.registerDescriptor(desc, registry, aClass
+                .getName(), tag, aClass.getName(), factoryClass, fstandard,
+                fdefault);
+    }
+
+    public void testGetProperties() throws Exception {
+        ConnectorStoreAppender appender = new ConnectorStoreAppender();
+        List properties = appender.getPropertyKeys(connector);
+        assertTrue(properties.contains("emptySessionPath"));
+        assertFalse(properties.contains("protocol"));
+        assertFalse(properties.contains("protocolHandlerClassName"));
+        // HTTP/1.1 SSL Protocol Test
+        connector.setProperty("sslProtocol", "TLS");
+        properties = appender.getPropertyKeys(connector);
+        assertTrue(properties.contains("protocol"));
+    }
+
+    public void testPrintAttributes() throws Exception {
+        ConnectorStoreAppender appender = new ConnectorStoreAppender();
+        connector.setProxyPort(80);
+        connector.setProperty("acceptCount", "110");
+        appender.printAttributes(pWriter, -2, false, connector, desc);
+
+        String aspectedResult = LF.LINE_SEPARATOR + "  proxyPort=\"80\""
+                + LF.LINE_SEPARATOR + "  acceptCount=\"110\"";
+        assertEquals(aspectedResult, writer.toString());
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/test/src/share/org/apache/catalina/storeconfig/DescriptorHelper.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/test/src/share/org/apache/catalina/storeconfig/DescriptorHelper.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/test/src/share/org/apache/catalina/storeconfig/DescriptorHelper.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,181 @@
+/*
+ * Copyright 1999-2001,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.storeconfig;
+
+import org.apache.catalina.cluster.CatalinaCluster;
+import org.apache.catalina.cluster.ClusterDeployer;
+import org.apache.catalina.cluster.ClusterReceiver;
+import org.apache.catalina.cluster.ClusterSender;
+import org.apache.catalina.cluster.MembershipService;
+import org.apache.catalina.cluster.MessageListener;
+import org.apache.catalina.deploy.ContextEjb;
+import org.apache.catalina.deploy.ContextEnvironment;
+import org.apache.catalina.deploy.ContextLocalEjb;
+import org.apache.catalina.deploy.ContextResource;
+import org.apache.catalina.deploy.ContextResourceEnvRef;
+import org.apache.catalina.deploy.ContextResourceLink;
+import org.apache.catalina.deploy.NamingResources;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * @author Peter Rossbach
+ *  
+ */
+public class DescriptorHelper {
+    private static Log log = LogFactory.getLog(DescriptorHelper.class);
+
+    public static StoreDescription registerDescriptor(
+            StoreDescription parentdesc, StoreRegistry registry, String tag,
+            Class aClass) {
+        return registerDescriptor(parentdesc, registry, aClass.getName(), tag,
+                aClass.getName(),
+                "org.apache.catalina.storeconfig.StoreFactoryBase", false,
+                false);
+    }
+
+    public static StoreDescription registerDescriptor(
+            StoreDescription parentdesc, StoreRegistry registry, String tag,
+            String aClassToken, String factoryClass, boolean fstandard,
+            boolean fdefault) {
+        return registerDescriptor(parentdesc, registry, aClassToken, tag,
+                aClassToken,
+                "org.apache.catalina.storeconfig.StoreFactoryBase", false,
+                false);
+    }
+
+    /**
+     * Generate a descriptor and register this to another parent descriptor.
+     * 
+     * @param parentdesc
+     * @param registry
+     * @param id
+     * @param tag
+     * @param aClassToken
+     * @param factoryClass
+     * @param fstandard
+     * @param fdefault
+     * @return
+     */
+    public static StoreDescription registerDescriptor(
+            StoreDescription parentdesc, StoreRegistry registry, String id,
+            String tag, String aClassToken, String factoryClass,
+            boolean fstandard, boolean fdefault) {
+        // add Listener
+        StoreDescription descChild = new StoreDescription();
+        descChild.setId(id);
+        descChild.setTag(tag);
+        descChild.setTagClass(aClassToken);
+        descChild.setStandard(fstandard);
+        descChild.setDefault(fdefault);
+        descChild.setStoreFactoryClass(factoryClass);
+        Object factory = null;
+        try {
+            Class aFactoryClass = Class.forName(factoryClass);
+            factory = aFactoryClass.newInstance();
+        } catch (Exception e) {
+            log.error(e);
+        }
+        if (factory != null) {
+            ((IStoreFactory) factory).setRegistry(registry);
+            descChild.setStoreFactory((IStoreFactory) factory);
+        }
+        if (parentdesc != null)
+            parentdesc.setChilds(true);
+        registry.registerDescription(descChild);
+        return descChild;
+    }
+
+    /**
+     * register all Registery descriptors on naming support to context!
+     * 
+     * @param parent
+     * @param registry
+     * @return
+     * @throws Exception
+     */
+    public static StoreDescription registerNamingDescriptor(
+            StoreDescription parent, StoreRegistry registry) throws Exception {
+
+        StoreDescription nameingDesc = DescriptorHelper.registerDescriptor(
+                parent, registry, NamingResources.class.getName(),
+                "NamingResources", NamingResources.class.getName(),
+                "org.apache.catalina.storeconfig.NamingResourcesSF", true,
+                false);
+        registerDescriptor(nameingDesc, registry, ContextEjb.class.getName(),
+                "EJB", ContextEjb.class.getName(),
+                "org.apache.catalina.storeconfig.StoreFactoryBase", true, false);
+        registerDescriptor(nameingDesc, registry, ContextEnvironment.class
+                .getName(), "Environment", ContextEnvironment.class.getName(),
+                "org.apache.catalina.storeconfig.StoreFactoryBase", true, false);
+        registerDescriptor(nameingDesc, registry, ContextLocalEjb.class
+                .getName(), "LocalEjb", ContextLocalEjb.class.getName(),
+                "org.apache.catalina.storeconfig.StoreFactoryBase", true, false);
+        registerDescriptor(nameingDesc, registry, ContextResource.class
+                .getName(), "Resource", ContextResource.class.getName(),
+                "org.apache.catalina.storeconfig.StoreFactoryBase", true, false);
+        registerDescriptor(nameingDesc, registry, ContextResourceLink.class
+                .getName(), "ResourceLink",
+                ContextResourceLink.class.getName(),
+                "org.apache.catalina.storeconfig.StoreFactoryBase", true, false);
+        registerDescriptor(nameingDesc, registry, ContextResourceEnvRef.class
+                .getName(), "ResourceEnvRef", ContextResourceEnvRef.class
+                .getName(), "org.apache.catalina.storeconfig.StoreFactoryBase",
+                true, false);
+        return nameingDesc;
+    }
+
+    /**
+     * register all cluster and subelement descriptors to registery
+     * 
+     * @param parent
+     * @param registry
+     * @return
+     * @throws Exception
+     */
+    public static StoreDescription registerClusterDescriptor(
+            StoreDescription parent, StoreRegistry registry) throws Exception {
+
+        StoreDescription clusterDesc = DescriptorHelper.registerDescriptor(
+                parent, registry, CatalinaCluster.class.getName(), "Cluster",
+                CatalinaCluster.class.getName(),
+                "org.apache.catalina.storeconfig.CatalinaClusterSF", false,
+                false);
+        registerDescriptor(clusterDesc, registry,
+                ClusterSender.class.getName(), "Sender", ClusterSender.class
+                        .getName(),
+                "org.apache.catalina.storeconfig.StoreFactoryBase", false,
+                false);
+        registerDescriptor(clusterDesc, registry, ClusterReceiver.class
+                .getName(), "Receiver", ClusterReceiver.class.getName(),
+                "org.apache.catalina.storeconfig.StoreFactoryBase", false,
+                false);
+        registerDescriptor(clusterDesc, registry, MembershipService.class
+                .getName(), "Membership", MembershipService.class.getName(),
+                "org.apache.catalina.storeconfig.StoreFactoryBase", false,
+                false);
+        registerDescriptor(clusterDesc, registry, ClusterDeployer.class
+                .getName(), "Deployer", ClusterDeployer.class.getName(),
+                "org.apache.catalina.storeconfig.StoreFactoryBase", false,
+                false);
+        registerDescriptor(clusterDesc, registry, MessageListener.class
+                .getName(), "ClusterListener", MessageListener.class.getName(),
+                "org.apache.catalina.storeconfig.StoreFactoryBase", false,
+                false);
+        return clusterDesc;
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/test/src/share/org/apache/catalina/storeconfig/GlobalNamingResourcesSFTest.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/test/src/share/org/apache/catalina/storeconfig/GlobalNamingResourcesSFTest.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/test/src/share/org/apache/catalina/storeconfig/GlobalNamingResourcesSFTest.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,216 @@
+/*
+ * Copyright 1999-2001,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.storeconfig;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+import junit.framework.TestCase;
+
+import org.apache.catalina.deploy.ContextEjb;
+import org.apache.catalina.deploy.ContextEnvironment;
+import org.apache.catalina.deploy.ContextLocalEjb;
+import org.apache.catalina.deploy.ContextResource;
+import org.apache.catalina.deploy.ContextResourceEnvRef;
+import org.apache.catalina.deploy.ContextResourceLink;
+import org.apache.catalina.deploy.NamingResources;
+import org.apache.catalina.storeconfig.GlobalNamingResourcesSF;
+import org.apache.catalina.storeconfig.StoreDescription;
+import org.apache.catalina.storeconfig.StoreRegistry;
+
+/**
+ * @author Peter Rossbach
+ *  
+ */
+public class GlobalNamingResourcesSFTest extends TestCase {
+    StoreRegistry registry;
+
+    StringWriter writer = new StringWriter();
+
+    PrintWriter pWriter = new PrintWriter(writer);
+
+    NamingResources reource = new NamingResources();
+
+    GlobalNamingResourcesSF factory;
+
+    StoreDescription desc;
+
+    StoreDescription nameingDesc;
+
+    /*
+     * create registery and configure naming decriptors
+     * 
+     * @see junit.framework.TestCase#setUp()
+     */
+    protected void setUp() throws Exception {
+        registry = new StoreRegistry();
+        desc = DescriptorHelper.registerDescriptor(null, registry,
+                NamingResources.class.getName() + ".[GlobalNamingResources]",
+                "GlobalNamingResources", NamingResources.class.getName(),
+                "org.apache.catalina.storeconfig.GlobalNamingResourcesSF",
+                true, false);
+        factory = (GlobalNamingResourcesSF) desc.getStoreFactory();
+        nameingDesc = DescriptorHelper.registerNamingDescriptor(desc, registry);
+        super.setUp();
+    }
+
+    protected void registerDescriptor(String tag, Class aClass,
+            String factoryClass, boolean fstandard, boolean fdefault) {
+        DescriptorHelper.registerDescriptor(nameingDesc, registry, aClass
+                .getName(), tag, aClass.getName(), factoryClass, fstandard,
+                fdefault);
+    }
+
+    public void testStore() throws Exception {
+        assertNotNull(registry.findDescription(NamingResources.class));
+        assertNotNull(registry.findDescription(ContextResourceEnvRef.class
+                .getName()));
+        assertEquals("ResourceEnvRef", registry.findDescription(
+                ContextResourceEnvRef.class.getName()).getTag());
+
+        NamingResources resources = new NamingResources();
+        ContextResourceEnvRef ref = new ContextResourceEnvRef();
+        ref.setName("peter");
+        ref.setType("type");
+        resources.addResourceEnvRef(ref);
+        String aspectedResult = "<GlobalNamingResources>" + LF.LINE_SEPARATOR
+                + "  <ResourceEnvRef" + LF.LINE_SEPARATOR
+                + "    name=\"peter\"" + LF.LINE_SEPARATOR
+                + "    type=\"type\"/>" + LF.LINE_SEPARATOR
+                + "</GlobalNamingResources>" + LF.LINE_SEPARATOR;
+        check(resources, aspectedResult);
+
+    }
+
+    public void testEJBStore() throws Exception {
+
+        NamingResources resources = new NamingResources();
+        ContextEjb ejb = new ContextEjb();
+        ejb.setName("ejb/Service");
+        ejb.setType("org.super.Bean");
+        ejb.setHome("org.super.BeanHome");
+        resources.addEjb(ejb);
+        String aspectedResult = "<GlobalNamingResources>" + LF.LINE_SEPARATOR
+                + "  <EJB" + LF.LINE_SEPARATOR
+                + "    home=\"org.super.BeanHome\"" + LF.LINE_SEPARATOR
+                + "    name=\"ejb/Service\"" + LF.LINE_SEPARATOR
+                + "    type=\"org.super.Bean\"/>" + LF.LINE_SEPARATOR
+                + "</GlobalNamingResources>" + LF.LINE_SEPARATOR;
+        check(resources, aspectedResult);
+    }
+
+    public void testLocalEjbStore() throws Exception {
+
+        NamingResources resources = new NamingResources();
+        ContextLocalEjb ejb = new ContextLocalEjb();
+        ejb.setName("ejb/Service");
+        ejb.setType("org.super.Bean");
+        ejb.setHome("org.super.BeanHome");
+        resources.addLocalEjb(ejb);
+        String aspectedResult = "<GlobalNamingResources>" + LF.LINE_SEPARATOR
+                + "  <LocalEjb" + LF.LINE_SEPARATOR
+                + "    home=\"org.super.BeanHome\"" + LF.LINE_SEPARATOR
+                + "    name=\"ejb/Service\"" + LF.LINE_SEPARATOR
+                + "    type=\"org.super.Bean\"/>" + LF.LINE_SEPARATOR
+                + "</GlobalNamingResources>" + LF.LINE_SEPARATOR;
+        check(resources, aspectedResult);
+    }
+
+    public void testEnvironmentStore() throws Exception {
+
+        NamingResources resources = new NamingResources();
+        ContextEnvironment env = new ContextEnvironment();
+        env.setName("env/SelectEmp");
+        env.setType("java.lang.String");
+        env.setValue("select * from emp");
+        resources.addEnvironment(env);
+        String aspectedResult = "<GlobalNamingResources>" + LF.LINE_SEPARATOR
+                + "  <Environment" + LF.LINE_SEPARATOR
+                + "    name=\"env/SelectEmp\"" + LF.LINE_SEPARATOR
+                + "    type=\"java.lang.String\"" + LF.LINE_SEPARATOR
+                + "    value=\"select * from emp\"/>" + LF.LINE_SEPARATOR
+                + "</GlobalNamingResources>" + LF.LINE_SEPARATOR;
+        check(resources, aspectedResult);
+    }
+
+    public void testResourceStore() throws Exception {
+
+        NamingResources resources = new NamingResources();
+        ContextResource res = new ContextResource();
+        res.setName("jdbc/Emp");
+        res.setType("javax.sql.DataSource");
+        res.setAuth("Container");
+        resources.addResource(res);
+        String aspectedResult = "<GlobalNamingResources>" + LF.LINE_SEPARATOR
+                + "  <Resource" + LF.LINE_SEPARATOR + "    auth=\"Container\""
+                + LF.LINE_SEPARATOR + "    name=\"jdbc/Emp\""
+                + LF.LINE_SEPARATOR + "    type=\"javax.sql.DataSource\"/>"
+                + LF.LINE_SEPARATOR + "</GlobalNamingResources>"
+                + LF.LINE_SEPARATOR;
+        check(resources, aspectedResult);
+    }
+
+    public void testResourceStoreProperty() throws Exception {
+
+        NamingResources resources = new NamingResources();
+        ContextResource res = new ContextResource();
+        res.setName("mail/MailSession");
+        res.setType("javax.mail.Session");
+        res.setAuth("Container");
+        res.setProperty("mail.host", "localhost");
+        resources.addResource(res);
+        String aspectedResult = "<GlobalNamingResources>" + LF.LINE_SEPARATOR
+                + "  <Resource" + LF.LINE_SEPARATOR + "    auth=\"Container\""
+                + LF.LINE_SEPARATOR + "    name=\"mail/MailSession\""
+                + LF.LINE_SEPARATOR + "    type=\"javax.mail.Session\""
+                + LF.LINE_SEPARATOR + "    mail.host=\"localhost\"/>"
+                + LF.LINE_SEPARATOR + "</GlobalNamingResources>"
+                + LF.LINE_SEPARATOR;
+        check(resources, aspectedResult);
+    }
+
+    // @TODO ResourceLink can only be exists at Context Tag
+    public void testResourceLinkStore() throws Exception {
+
+        NamingResources resources = new NamingResources();
+        ContextResourceLink res = new ContextResourceLink();
+        res.setName("jdbc/Emp1");
+        res.setType("javax.sql.DataSource");
+        res.setGlobal("jdbc/Emp");
+        resources.addResourceLink(res);
+        String aspectedResult = "<GlobalNamingResources>" + LF.LINE_SEPARATOR
+                + "  <ResourceLink" + LF.LINE_SEPARATOR
+                + "    global=\"jdbc/Emp\"" + LF.LINE_SEPARATOR
+                + "    name=\"jdbc/Emp1\"" + LF.LINE_SEPARATOR
+                + "    type=\"javax.sql.DataSource\"/>" + LF.LINE_SEPARATOR
+                + "</GlobalNamingResources>" + LF.LINE_SEPARATOR;
+        check(resources, aspectedResult);
+    }
+
+    public void testStoreEmpty() throws Exception {
+        NamingResources resources = new NamingResources();
+        String aspectedResult = "<GlobalNamingResources>" + LF.LINE_SEPARATOR
+                + "</GlobalNamingResources>" + LF.LINE_SEPARATOR;
+        check(resources, aspectedResult);
+    }
+
+    protected void check(NamingResources resources, String aspectedResult)
+            throws Exception {
+        factory.store(pWriter, -2, resources);
+        assertEquals(aspectedResult, writer.toString());
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/test/src/share/org/apache/catalina/storeconfig/InfoLifecycleListener.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/test/src/share/org/apache/catalina/storeconfig/InfoLifecycleListener.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/test/src/share/org/apache/catalina/storeconfig/InfoLifecycleListener.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,47 @@
+/*
+ * Copyright 1999-2001,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.storeconfig;
+
+import org.apache.catalina.LifecycleEvent;
+import org.apache.catalina.LifecycleListener;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * @author Peter Rossbach
+ *  
+ */
+public class InfoLifecycleListener implements LifecycleListener {
+
+    private static Log log = LogFactory.getLog(InfoLifecycleListener.class);
+
+    /**
+     * The descriptive information string for this implementation.
+     */
+    private static final String info = "org.apache.catalina.listener.InfoLifecycleListener/1.0";
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see org.apache.catalina.LifecycleListener#lifecycleEvent(org.apache.catalina.LifecycleEvent)
+     */
+    public void lifecycleEvent(LifecycleEvent arg0) {
+        if (log.isInfoEnabled())
+            log.info(arg0.getSource().toString() + ": " + arg0.getType());
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/test/src/share/org/apache/catalina/storeconfig/LF.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/test/src/share/org/apache/catalina/storeconfig/LF.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/test/src/share/org/apache/catalina/storeconfig/LF.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,29 @@
+/*
+ * Copyright 1999-2001,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.storeconfig;
+
+/**
+ * @author Peter Rossbach
+ *  
+ */
+
+public class LF {
+
+    // -------------------------------------------------------------- Constants
+
+    public static String LINE_SEPARATOR = System.getProperty("line.separator");
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/test/src/share/org/apache/catalina/storeconfig/LoaderSFTest.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/test/src/share/org/apache/catalina/storeconfig/LoaderSFTest.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/test/src/share/org/apache/catalina/storeconfig/LoaderSFTest.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,86 @@
+/*
+ * Copyright 1999-2001,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.storeconfig;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+import junit.framework.TestCase;
+
+import org.apache.catalina.Loader;
+import org.apache.catalina.loader.WebappLoader;
+import org.apache.catalina.storeconfig.LoaderSF;
+import org.apache.catalina.storeconfig.StoreDescription;
+import org.apache.catalina.storeconfig.StoreRegistry;
+
+/**
+ * @author Peter Rossbach
+ *  
+ */
+public class LoaderSFTest extends TestCase {
+    StoreRegistry registry;
+
+    StringWriter writer = new StringWriter();
+
+    PrintWriter pWriter = new PrintWriter(writer);
+
+    Loader loader;
+
+    LoaderSF factory;
+
+    StoreDescription desc;
+
+    /*
+     * create Registry and register Loader
+     * 
+     * @see junit.framework.TestCase#setUp()
+     */
+    protected void setUp() throws Exception {
+
+        super.setUp();
+        registry = new StoreRegistry();
+        desc = DescriptorHelper.registerDescriptor(null, registry,
+                WebappLoader.class.getName(), "Loader", WebappLoader.class
+                        .getName(), "org.apache.catalina.storeconfig.LoaderSF",
+                false, false);
+        factory = (LoaderSF) desc.getStoreFactory();
+        loader = new WebappLoader();
+
+    }
+
+    public void testManagerNonStandardStore() throws Exception {
+        assertTrue(factory.isDefaultLoader(loader));
+        loader.setDelegate(true);
+        assertFalse(factory.isDefaultLoader(loader));
+        String aspectedResult = "<Loader className=\"org.apache.catalina.loader.WebappLoader\""
+                + LF.LINE_SEPARATOR
+                + "    delegate=\"true\"/>"
+                + LF.LINE_SEPARATOR;
+        check(aspectedResult);
+    }
+
+    public void testStoreEmpty() throws Exception {
+        assertTrue(factory.isDefaultLoader(loader));
+        String aspectedResult = "";
+        check(aspectedResult);
+    }
+
+    protected void check(String aspectedResult) throws Exception {
+        factory.store(pWriter, -2, loader);
+        assertEquals(aspectedResult, writer.toString());
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/test/src/share/org/apache/catalina/storeconfig/ManagerSFTest.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/test/src/share/org/apache/catalina/storeconfig/ManagerSFTest.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/test/src/share/org/apache/catalina/storeconfig/ManagerSFTest.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,90 @@
+/*
+ * Copyright 1999-2001,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.storeconfig;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+import junit.framework.TestCase;
+
+import org.apache.catalina.Manager;
+import org.apache.catalina.session.StandardManager;
+
+/**
+ * @author Peter Rossbach
+ *  
+ */
+public class ManagerSFTest extends TestCase {
+    StoreRegistry registry;
+
+    StringWriter writer = new StringWriter();
+
+    PrintWriter pWriter = new PrintWriter(writer);
+
+    StandardManager manager;
+
+    ManagerSF factory;
+
+    StoreDescription desc;
+
+    /*
+     * create registery and register Manager descriptor
+     * 
+     * @see junit.framework.TestCase#setUp()
+     */
+    protected void setUp() throws Exception {
+
+        super.setUp();
+        registry = new StoreRegistry();
+        desc = DescriptorHelper.registerDescriptor(null, registry,
+                Manager.class.getName(), "Manager",
+                Manager.class.getName(),
+                "org.apache.catalina.storeconfig.ManagerSF", false, false);
+        desc.addTransientAttribute("entropy");
+        desc.addTransientAttribute("distributable");
+        factory = (ManagerSF) desc.getStoreFactory();
+        manager = new StandardManager();
+
+    }
+
+    public void testFindStandardManager() {
+        StoreDescription managerdesc = registry.findDescription(manager.getClass());
+        assertEquals(desc,managerdesc);
+    }
+    
+    public void testManagerNonStandardStore() throws Exception {
+        assertTrue(factory.isDefaultManager(manager));
+        manager.setMaxActiveSessions(100);
+        assertFalse(factory.isDefaultManager(manager));
+        String aspectedResult = "<Manager className=\"org.apache.catalina.session.StandardManager\""
+                + LF.LINE_SEPARATOR
+                + "    maxActiveSessions=\"100\"/>"
+                + LF.LINE_SEPARATOR;
+        check(aspectedResult);
+    }
+
+    public void testStoreEmpty() throws Exception {
+        assertTrue(factory.isDefaultManager(manager));
+        String aspectedResult = "";
+        check(aspectedResult);
+    }
+
+    protected void check(String aspectedResult) throws Exception {
+        factory.store(pWriter, -2, manager);
+        assertEquals(aspectedResult, writer.toString());
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/test/src/share/org/apache/catalina/storeconfig/ServerChildsTest.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/test/src/share/org/apache/catalina/storeconfig/ServerChildsTest.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/test/src/share/org/apache/catalina/storeconfig/ServerChildsTest.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,134 @@
+/*
+ * Copyright 1999-2001,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.storeconfig;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+import junit.framework.TestCase;
+
+import org.apache.catalina.Lifecycle;
+import org.apache.catalina.LifecycleListener;
+import org.apache.catalina.core.StandardServer;
+import org.apache.catalina.core.StandardService;
+import org.apache.catalina.deploy.NamingResources;
+import org.apache.catalina.storeconfig.StandardServerSF;
+import org.apache.catalina.storeconfig.StoreDescription;
+import org.apache.catalina.storeconfig.StoreRegistry;
+
+/**
+ * @author Peter Rossbach
+ *  
+ */
+public class ServerChildsTest extends TestCase {
+
+    StoreRegistry registry;
+
+    StringWriter writer = new StringWriter();
+
+    PrintWriter pWriter = new PrintWriter(writer);
+
+    StandardServer standardServer = new StandardServer();
+
+    StandardServerSF factory;
+
+    StoreDescription desc;
+
+    /*
+     * create registery and register Server and direct subelement descriptors
+     * 
+     * @see junit.framework.TestCase#setUp()
+     */
+    protected void setUp() throws Exception {
+
+        super.setUp();
+        registry = new StoreRegistry();
+        desc = new StoreDescription();
+        desc.setTag("Server");
+        desc.setTagClass("org.apache.catalina.core.StandardServer");
+        desc.setStandard(true);
+        desc
+                .setStoreFactoryClass("org.apache.catalina.storeconfig.StandardServerSF");
+        registry.registerDescription(desc);
+        factory = new StandardServerSF();
+        desc.setStoreFactory(factory);
+        factory.setRegistry(registry);
+        StoreDescription listdesc = registerDescriptor("Listener",
+                LifecycleListener.class);
+        listdesc
+                .addTransientChild("org.apache.catalina.core.NamingContextListener");
+        listdesc
+                .addTransientChild("org.apache.catalina.mbeans.ServerLifecycleListener");
+        standardServer
+                .addLifecycleListener(new org.apache.catalina.mbeans.ServerLifecycleListener());
+        // add GlobalNamingResource
+        DescriptorHelper.registerDescriptor(desc, registry,
+                NamingResources.class.getName() + ".[GlobalNamingResources]",
+                "GlobalNamingResources", NamingResources.class.getName(),
+                "org.apache.catalina.storeconfig.GlobalNamingResourcesSF",
+                true, false);
+        DescriptorHelper.registerNamingDescriptor(desc, registry);
+        registerDescriptor("Service", StandardService.class,
+                "org.apache.catalina.storeconfig.StandardServiceSF", true,
+                false);
+        DescriptorHelper.registerDescriptor(desc, registry,
+                StandardServer.class.getName() + ".[ServerLifecycleListener]",
+                "ServerLifecycleListener", StandardServer.class.getName(),
+                "org.apache.catalina.storeconfig.StoreFactoryBase", false,
+                false);
+        standardServer.addService(new StandardService());
+
+    }
+
+    private StoreDescription registerDescriptor(String tag, Class aClass) {
+        return registerDescriptor(tag, aClass,
+                "org.apache.catalina.storeconfig.StoreFactoryBase", false,
+                false);
+    }
+
+    private StoreDescription registerDescriptor(String tag, Class aClass,
+            String factoryClass, boolean fstandard, boolean fdefault) {
+        return DescriptorHelper.registerDescriptor(desc, registry, aClass
+                .getName(), tag, aClass.getName(), factoryClass, fstandard,
+                fdefault);
+    }
+
+    public void testSaveListenerAddServer() throws Exception {
+        assertTrue(standardServer instanceof Lifecycle);
+        assertNotNull(
+                "No Listener Descriptor",
+                registry
+                        .findDescription("org.apache.catalina.mbeans.ServerLifecycleListener"));
+        assertNotNull(
+                "No Listener StoreFactory",
+                registry
+                        .findStoreFactory("org.apache.catalina.mbeans.ServerLifecycleListener"));
+        factory.store(pWriter, -2, standardServer);
+ 
+        String aspectedResult = "<?xml version=\"1.0\" encoding=\""
+                + registry.getEncoding()
+                + "\"?>"
+                + LF.LINE_SEPARATOR
+                + "<Server>"
+                + LF.LINE_SEPARATOR
+                + "  <Listener className=\"org.apache.catalina.mbeans.ServerLifecycleListener\"/>"
+                + LF.LINE_SEPARATOR + "  <GlobalNamingResources>"
+                + LF.LINE_SEPARATOR + "  </GlobalNamingResources>"
+                + LF.LINE_SEPARATOR + "  <Service/>" + LF.LINE_SEPARATOR
+                + "</Server>" + LF.LINE_SEPARATOR;
+        assertEquals(aspectedResult, writer.toString());
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/test/src/share/org/apache/catalina/storeconfig/StandardContextSFTest.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/test/src/share/org/apache/catalina/storeconfig/StandardContextSFTest.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/test/src/share/org/apache/catalina/storeconfig/StandardContextSFTest.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,350 @@
+/*
+ * Copyright 1999-2001,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.storeconfig;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+import javax.naming.directory.DirContext;
+
+import junit.framework.TestCase;
+
+import org.apache.catalina.LifecycleListener;
+import org.apache.catalina.Valve;
+import org.apache.catalina.core.StandardContext;
+import org.apache.catalina.core.StandardHost;
+import org.apache.catalina.deploy.ContextResourceEnvRef;
+import org.apache.catalina.deploy.ContextResourceLink;
+import org.apache.catalina.deploy.NamingResources;
+import org.apache.catalina.realm.JAASRealm;
+import org.apache.catalina.session.FileStore;
+import org.apache.catalina.session.JDBCStore;
+import org.apache.catalina.session.PersistentManager;
+import org.apache.catalina.session.StandardManager;
+import org.apache.catalina.storeconfig.StandardContextSF;
+import org.apache.catalina.storeconfig.StoreDescription;
+import org.apache.catalina.storeconfig.StoreRegistry;
+import org.apache.naming.resources.FileDirContext;
+import org.apache.naming.resources.ProxyDirContext;
+import org.apache.naming.resources.WARDirContext;
+
+/**
+ * @author Peter Rossbach
+ *  
+ */
+public class StandardContextSFTest extends TestCase {
+    StoreRegistry registry;
+
+    StringWriter writer = new StringWriter();
+
+    PrintWriter pWriter = new PrintWriter(writer);
+
+    StandardContext standardContext;
+
+    StandardContextSF factory;
+
+    StoreDescription desc;
+
+    /*
+     * create registery and register Context and all subelements
+     * 
+     * @see junit.framework.TestCase#setUp()
+     */
+    protected void setUp() throws Exception {
+
+        super.setUp();
+        registry = new StoreRegistry();
+        desc = new StoreDescription();
+        desc.setTag("Context");
+        desc.setTagClass("org.apache.catalina.core.StandardContext");
+        desc.setStandard(true);
+        desc
+                .setStoreFactoryClass("org.apache.catalina.storeconfig.StandardContextSF");
+        String exceptions[] = { "available", "configFile", "configured",
+                "distributable", "domain", "engineName", "name", "override",
+                "publicId", "replaceWelcomeFiles", "sessionTimeout",
+                "startupTime", "tldScanTime" };
+        for (int i = 0; i < exceptions.length; i++)
+            desc.addTransientAttribute(exceptions[i]);
+
+        registry.registerDescription(desc);
+        factory = new StandardContextSF();
+        desc.setStoreFactory(factory);
+        factory.setRegistry(registry);
+
+        StoreDescription listenerdesc = registerDescriptor("Listener",
+                LifecycleListener.class);
+
+        String listenerskippables[] = {
+                "org.apache.catalina.core.NamingContextListener",
+                "org.apache.catalina.startup.ContextConfig", };
+        for (int i = 0; i < listenerskippables.length; i++)
+            listenerdesc.addTransientChild(listenerskippables[i]);
+
+        StoreDescription realmdesc = registerDescriptor("Realm",
+                JAASRealm.class,
+                "org.apache.catalina.storeconfig.StoreFactoryBase", false,
+                false);
+        StoreDescription managerdesc = registerDescriptor("Manager",
+                StandardManager.class,
+                "org.apache.catalina.storeconfig.ManagerSF", false, false);
+        managerdesc.addTransientAttribute("entropy");
+        managerdesc.addTransientAttribute("distributable");
+        StoreDescription pmanagerdesc = registerDescriptor("Manager",
+                PersistentManager.class,
+                "org.apache.catalina.storeconfig.PersistentManagerSF", false,
+                false);
+        pmanagerdesc.addTransientAttribute("entropy");
+        pmanagerdesc.addTransientAttribute("distributable");
+        DescriptorHelper.registerDescriptor(pmanagerdesc, registry,
+                FileStore.class.getName(), "Store", FileStore.class.getName(),
+                "org.apache.catalina.storeconfig.StoreFactoryBase", false,
+                false);
+        DescriptorHelper.registerDescriptor(pmanagerdesc, registry,
+                JDBCStore.class.getName(), "Store", JDBCStore.class.getName(),
+                "org.apache.catalina.storeconfig.StoreFactoryBase", false,
+                false);
+        DescriptorHelper.registerNamingDescriptor(desc, registry);
+        StoreDescription valvedesc = registerDescriptor("Valve", Valve.class,
+                "org.apache.catalina.storeconfig.StoreFactoryBase", false,
+                false);
+        String skippables[] = {
+                "org.apache.catalina.authenticator.BasicAuthenticator",
+                "org.apache.catalina.authenticator.DigestAuthenticator",
+                "org.apache.catalina.authenticator.FormAuthenticator",
+                "org.apache.catalina.authenticator.NonLoginAuthenticator",
+                "org.apache.catalina.authenticator.SSLAuthenticator",
+                "org.apache.catalina.core.StandardContextValve",
+                "org.apache.catalina.valves.CertificatesValve" };
+        for (int i = 0; i < skippables.length; i++)
+            valvedesc.addTransientChild(skippables[i]);
+
+        StoreDescription resdesc = registerDescriptor("Resources",
+                DirContext.class,
+                "org.apache.catalina.storeconfig.StoreFactoryBase", false,
+                false);
+        resdesc.addTransientAttribute("docBase");
+        resdesc.addTransientAttribute("allowLinking");
+        resdesc.addTransientAttribute("cacheMaxSize");
+        resdesc.addTransientAttribute("cacheTTL");
+        resdesc.addTransientAttribute("caseSensitive");
+        resdesc.addTransientChild(FileDirContext.class.getName());
+        resdesc.addTransientChild(ProxyDirContext.class.getName());
+        resdesc.addTransientChild(WARDirContext.class.getName());
+        standardContext = new StandardContext();
+        standardContext.setPath("/myapps");
+        standardContext.setDocBase("myapps");
+
+    }
+
+    private StoreDescription registerDescriptor(String tag, Class aClass) {
+        return registerDescriptor(tag, aClass,
+                "org.apache.catalina.storeconfig.StoreFactoryBase", false,
+                false);
+    }
+
+    private StoreDescription registerDescriptor(String tag, Class aClass,
+            String factoryClass, boolean fstandard, boolean fdefault) {
+        return DescriptorHelper.registerDescriptor(desc, registry, aClass
+                .getName(), tag, aClass.getName(), factoryClass, fstandard,
+                fdefault);
+    }
+
+    /**
+     * @TODO Listener only saved at real context. Wrong when next Context
+     *       deployed! see Changes.txt
+     * @throws Exception
+     */
+    public void testListenerStore() throws Exception {
+        standardContext
+                .addLifecycleListener(new org.apache.catalina.storeconfig.InfoLifecycleListener());
+        standardContext
+                .addInstanceListener("org.apache.catalina.ContainerListener");
+        standardContext
+                .addWrapperListener("org.apache.catalina.ContainerListener");
+        standardContext
+                .addWrapperLifecycle("org.apache.catalina.ContainerListener");
+        standardContext.addWatchedResource("/tmp/reloaded");
+        String aspectedResult = "<Context"
+                + LF.LINE_SEPARATOR
+                + "    docBase=\"myapps\""
+                + LF.LINE_SEPARATOR
+                + "    path=\"/myapps\">"
+                + LF.LINE_SEPARATOR
+                + "  <Listener className=\"org.apache.catalina.storeconfig.InfoLifecycleListener\"/>"
+                + LF.LINE_SEPARATOR
+                + "  <InstanceListener>org.apache.catalina.ContainerListener</InstanceListener>"
+                + LF.LINE_SEPARATOR
+                + "  <WrapperListener>org.apache.catalina.ContainerListener</WrapperListener>"
+                + LF.LINE_SEPARATOR
+                + "  <WrapperLifecycle>org.apache.catalina.ContainerListener</WrapperLifecycle>"
+                + LF.LINE_SEPARATOR
+                + "  <WatchedResource>/tmp/reloaded</WatchedResource>"
+                + LF.LINE_SEPARATOR + "</Context>" + LF.LINE_SEPARATOR;
+        check(aspectedResult);
+    }
+
+    public void testNamingStore() throws Exception {
+        standardContext
+                .addLifecycleListener(new org.apache.catalina.storeconfig.InfoLifecycleListener());
+        NamingResources resources = standardContext.getNamingResources();
+        ContextResourceEnvRef ref = new ContextResourceEnvRef();
+        ref.setName("foo");
+        ref.setType("type");
+        resources.addResourceEnvRef(ref);
+        ContextResourceLink res = new ContextResourceLink();
+        res.setName("jdbc/Barlocal");
+        res.setType("javax.sql.DataSource");
+        res.setGlobal("jdbc/Bar");
+        resources.addResourceLink(res);
+        String aspectedResult = "<Context"
+                + LF.LINE_SEPARATOR
+                + "    docBase=\"myapps\""
+                + LF.LINE_SEPARATOR
+                + "    path=\"/myapps\">"
+                + LF.LINE_SEPARATOR
+                + "  <Listener className=\"org.apache.catalina.storeconfig.InfoLifecycleListener\"/>"
+                + LF.LINE_SEPARATOR + "  <ResourceEnvRef" + LF.LINE_SEPARATOR
+                + "    name=\"foo\"" + LF.LINE_SEPARATOR
+                + "    type=\"type\"/>" + LF.LINE_SEPARATOR + "  <ResourceLink"
+                + LF.LINE_SEPARATOR + "    global=\"jdbc/Bar\""
+                + LF.LINE_SEPARATOR + "    name=\"jdbc/Barlocal\""
+                + LF.LINE_SEPARATOR + "    type=\"javax.sql.DataSource\"/>"
+                + LF.LINE_SEPARATOR + "</Context>" + LF.LINE_SEPARATOR;
+        check(aspectedResult);
+    }
+
+    public void testManagerStore() throws Exception {
+        standardContext.setManager(new StandardManager());
+        String aspectedResult = "<Context" + LF.LINE_SEPARATOR
+                + "    docBase=\"myapps\"" + LF.LINE_SEPARATOR
+                + "    path=\"/myapps\">" + LF.LINE_SEPARATOR
+                + "</Context>\r\n";
+        check(aspectedResult);
+    }
+
+    public void testRealmStore() throws Exception {
+        standardContext.setManager(new StandardManager());
+        JAASRealm realm = new JAASRealm();
+        standardContext.setRealm(realm);
+        String aspectedResult = "<Context" + LF.LINE_SEPARATOR
+                + "    docBase=\"myapps\"" + LF.LINE_SEPARATOR
+                + "    path=\"/myapps\">" + LF.LINE_SEPARATOR
+                + "  <Realm className=\"org.apache.catalina.realm.JAASRealm\""
+                + LF.LINE_SEPARATOR + "    appName=\"myapps\"/>"
+                + LF.LINE_SEPARATOR + "</Context>" + LF.LINE_SEPARATOR;
+        check(aspectedResult);
+    }
+
+    // @TODO Why the MaxInactiveInterval is after setManager set to 1800 sec?
+    public void testManagerNonStandardStore() throws Exception {
+        StandardManager manager = new StandardManager();
+        manager.setMaxActiveSessions(100);
+        assertEquals(60, manager.getMaxInactiveInterval());
+        standardContext.setManager(manager);
+        assertEquals(1800, manager.getMaxInactiveInterval());
+        String aspectedResult = "<Context"
+                + LF.LINE_SEPARATOR
+                + "    docBase=\"myapps\""
+                + LF.LINE_SEPARATOR
+                + "    path=\"/myapps\">"
+                + LF.LINE_SEPARATOR
+                + "  <Manager className=\"org.apache.catalina.session.StandardManager\""
+                + LF.LINE_SEPARATOR + "      maxActiveSessions=\"100\""
+                + LF.LINE_SEPARATOR + "      maxInactiveInterval=\"1800\"/>"
+                + LF.LINE_SEPARATOR + "</Context>\r\n";
+        check(aspectedResult);
+    }
+
+    public void testPersistentManagerStore() throws Exception {
+        PersistentManager manager = new PersistentManager();
+        manager.setSaveOnRestart(false);
+        standardContext.setManager(manager);
+        String aspectedResult = "<Context"
+                + LF.LINE_SEPARATOR
+                + "    docBase=\"myapps\""
+                + LF.LINE_SEPARATOR
+                + "    path=\"/myapps\">"
+                + LF.LINE_SEPARATOR
+                + "  <Manager className=\"org.apache.catalina.session.PersistentManager\""
+                + LF.LINE_SEPARATOR + "      maxInactiveInterval=\"1800\""
+                + LF.LINE_SEPARATOR + "      saveOnRestart=\"false\">"
+                + LF.LINE_SEPARATOR + "  </Manager>" + LF.LINE_SEPARATOR
+                + "</Context>" + LF.LINE_SEPARATOR;
+        check(aspectedResult);
+    }
+
+    public void testPersistentManagerFileStore() throws Exception {
+        PersistentManager manager = new PersistentManager();
+        manager.setSaveOnRestart(false);
+        FileStore store = new FileStore();
+        manager.setStore(store);
+        standardContext.setManager(manager);
+        String aspectedResult = "<Context"
+                + LF.LINE_SEPARATOR
+                + "    docBase=\"myapps\""
+                + LF.LINE_SEPARATOR
+                + "    path=\"/myapps\">"
+                + LF.LINE_SEPARATOR
+                + "  <Manager className=\"org.apache.catalina.session.PersistentManager\""
+                + LF.LINE_SEPARATOR
+                + "      maxInactiveInterval=\"1800\""
+                + LF.LINE_SEPARATOR
+                + "      saveOnRestart=\"false\">"
+                + LF.LINE_SEPARATOR
+                + "    <Store className=\"org.apache.catalina.session.FileStore\"/>"
+                + LF.LINE_SEPARATOR + "  </Manager>" + LF.LINE_SEPARATOR
+                + "</Context>" + LF.LINE_SEPARATOR;
+        check(aspectedResult);
+
+    }
+
+    public void testDefaultResources() throws Exception {
+        FileDirContext dirC = new FileDirContext();
+        standardContext.setAllowLinking(true);
+        standardContext.setResources(dirC);
+        StandardHost host = new StandardHost();
+        host.addChild(standardContext);
+        host.setName("localhost");
+        host.setAppBase("webapps");
+        standardContext.resourcesStart();
+        assertNotNull(standardContext.getResources());
+        String aspectedResult = "<Context" + LF.LINE_SEPARATOR
+                + "    docBase=\"myapps\"" + LF.LINE_SEPARATOR
+                + "    path=\"/myapps\">" + LF.LINE_SEPARATOR + "</Context>"
+                + LF.LINE_SEPARATOR;
+        check(aspectedResult);
+    }
+
+    /*
+     * + " <Resources className=\"org.apache.naming.resources.FileDirContext\"" +
+     * Constants.LINE_SEPARATOR + " allowLinking=\"true\"/>" +
+     * Constants.LINE_SEPARATOR
+     */
+    public void testStoreEmpty() throws Exception {
+        String aspectedResult = "<Context" + LF.LINE_SEPARATOR
+                + "    docBase=\"myapps\"" + LF.LINE_SEPARATOR
+                + "    path=\"/myapps\">" + LF.LINE_SEPARATOR + "</Context>"
+                + LF.LINE_SEPARATOR;
+        check(aspectedResult);
+    }
+
+    protected void check(String aspectedResult) throws Exception {
+        factory.store(pWriter, -2, standardContext);
+        assertEquals(aspectedResult, writer.toString());
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/test/src/share/org/apache/catalina/storeconfig/StandardEngineSFTest.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/test/src/share/org/apache/catalina/storeconfig/StandardEngineSFTest.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/test/src/share/org/apache/catalina/storeconfig/StandardEngineSFTest.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,210 @@
+/*
+ * Copyright 1999-2001,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.storeconfig;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+import junit.framework.TestCase;
+
+import org.apache.catalina.LifecycleListener;
+import org.apache.catalina.Valve;
+import org.apache.catalina.core.StandardEngine;
+import org.apache.catalina.core.StandardHost;
+import org.apache.catalina.realm.JAASRealm;
+import org.apache.catalina.storeconfig.StandardEngineSF;
+import org.apache.catalina.storeconfig.StoreDescription;
+import org.apache.catalina.storeconfig.StoreRegistry;
+
+/**
+ * @author Peter Rossbach
+ *  
+ */
+public class StandardEngineSFTest extends TestCase {
+    StoreRegistry registry;
+
+    StringWriter writer = new StringWriter();
+
+    PrintWriter pWriter = new PrintWriter(writer);
+
+    StandardEngine standardEngine;
+
+    StandardEngineSF factory;
+
+    StoreDescription desc;
+
+    /*
+     * create registery and register Engine and direct subelement descriptors
+     * 
+     * @see junit.framework.TestCase#setUp()
+     */
+    protected void setUp() throws Exception {
+
+        super.setUp();
+        registry = new StoreRegistry();
+        desc = new StoreDescription();
+        desc.setTag("Engine");
+        desc.setTagClass("org.apache.catalina.core.StandardEngine");
+        desc.setStandard(true);
+        desc
+                .setStoreFactoryClass("org.apache.catalina.storeconfig.StandardEngineSF");
+        desc.addTransientAttribute("domain");
+        registry.registerDescription(desc);
+        factory = new StandardEngineSF();
+        desc.setStoreFactory(factory);
+        factory.setRegistry(registry);
+        StoreDescription listenerdesc = registerDescriptor("Listener",
+                LifecycleListener.class);
+
+        String listenerskippables[] = {
+                "org.apache.catalina.core.NamingContextListener",
+                "org.apache.catalina.startup.ContextConfig",
+                "org.apache.catalina.startup.EngineConfig",
+                "org.apache.catalina.startup.HostConfig", };
+        for (int i = 0; i < listenerskippables.length; i++)
+            listenerdesc.addTransientChild(listenerskippables[i]);
+
+        StoreDescription realmdesc = registerDescriptor("Realm",
+                JAASRealm.class,
+                "org.apache.catalina.storeconfig.StoreFactoryBase", true, false);
+        StoreDescription hostdesc = registerDescriptor("Host",
+                StandardHost.class,
+                "org.apache.catalina.storeconfig.StoreFactoryBase", true, false);
+        hostdesc.addTransientAttribute("domain");
+        StoreDescription valvedesc = registerDescriptor("Valve", Valve.class,
+                "org.apache.catalina.storeconfig.StoreFactoryBase", false,
+                false);
+
+        String skippables[] = {
+                "org.apache.catalina.authenticator.BasicAuthenticator",
+                "org.apache.catalina.authenticator.DigestAuthenticator",
+                "org.apache.catalina.authenticator.FormAuthenticator",
+                "org.apache.catalina.authenticator.NonLoginAuthenticator",
+                "org.apache.catalina.authenticator.SSLAuthenticator",
+                "org.apache.catalina.core.StandardContextValve",
+                "org.apache.catalina.core.StandardEngineValve",
+                "org.apache.catalina.core.StandardHostValve",
+                "org.apache.catalina.valves.CertificatesValve",
+                "org.apache.catalina.valves.ErrorReportValve",
+                "org.apache.catalina.valves.RequestListenerValve", };
+        for (int i = 0; i < skippables.length; i++)
+            valvedesc.addTransientChild(skippables[i]);
+
+        standardEngine = new StandardEngine();
+        standardEngine.setName("Catalina");
+
+    }
+
+    private StoreDescription registerDescriptor(String tag, Class aClass) {
+        return registerDescriptor(tag, aClass,
+                "org.apache.catalina.storeconfig.StoreFactoryBase", false,
+                false);
+    }
+
+    /**
+     *  
+     */
+    private StoreDescription registerDescriptor(String tag, Class aClass,
+            String factoryClass, boolean fstandard, boolean fdefault) {
+        return DescriptorHelper.registerDescriptor(desc, registry, aClass
+                .getName(), tag, aClass.getName(), factoryClass, fstandard,
+                fdefault);
+    }
+
+    public void testStore() throws Exception {
+        standardEngine
+                .addLifecycleListener(new org.apache.catalina.storeconfig.InfoLifecycleListener());
+        StandardHost host = new StandardHost();
+        host.setName("localhost");
+        standardEngine.addChild(host);
+        String aspectedResult = "<Engine"
+                + LF.LINE_SEPARATOR
+                + "    name=\"Catalina\">"
+                + LF.LINE_SEPARATOR
+                + "  <Listener className=\"org.apache.catalina.storeconfig.InfoLifecycleListener\"/>"
+                + LF.LINE_SEPARATOR + "  <Realm" + LF.LINE_SEPARATOR
+                + "    appName=\"Catalina\"/>" + LF.LINE_SEPARATOR + "  <Host"
+                + LF.LINE_SEPARATOR + "    name=\"localhost\"/>"
+                + LF.LINE_SEPARATOR + "</Engine>" + LF.LINE_SEPARATOR;
+
+        check(aspectedResult);
+    }
+
+    public void testElements() throws Exception {
+        standardEngine.setName("Catalina");
+        standardEngine
+                .addLifecycleListener(new org.apache.catalina.storeconfig.InfoLifecycleListener());
+        standardEngine
+                .addLifecycleListener(new org.apache.catalina.startup.EngineConfig());
+        StandardHost host = new StandardHost();
+        host.setName("localhost");
+        standardEngine.addChild(host);
+        String aspectedResult = "<Engine"
+                + LF.LINE_SEPARATOR
+                + "    name=\"Catalina\">"
+                + LF.LINE_SEPARATOR
+                + "  <Listener className=\"org.apache.catalina.storeconfig.InfoLifecycleListener\"/>"
+                + LF.LINE_SEPARATOR + "  <Realm" + LF.LINE_SEPARATOR
+                + "    appName=\"Catalina\"/>" + LF.LINE_SEPARATOR + "  <Host"
+                + LF.LINE_SEPARATOR + "    name=\"localhost\"/>"
+                + LF.LINE_SEPARATOR + "</Engine>" + LF.LINE_SEPARATOR;
+        check(aspectedResult);
+    }
+
+    public void testValve() throws Exception {
+        standardEngine.setName("Catalina");
+        standardEngine
+                .addLifecycleListener(new org.apache.catalina.storeconfig.InfoLifecycleListener());
+        standardEngine
+                .addLifecycleListener(new org.apache.catalina.startup.EngineConfig());
+        StandardHost host = new StandardHost();
+        host.setName("localhost");
+        standardEngine.addChild(host);
+        standardEngine
+                .addValve(new org.apache.catalina.valves.ErrorReportValve());
+        standardEngine
+                .addValve(new org.apache.catalina.valves.RequestDumperValve());
+        String aspectedResult = "<Engine"
+                + LF.LINE_SEPARATOR
+                + "    name=\"Catalina\">"
+                + LF.LINE_SEPARATOR
+                + "  <Listener className=\"org.apache.catalina.storeconfig.InfoLifecycleListener\"/>"
+                + LF.LINE_SEPARATOR
+                + "  <Realm"
+                + LF.LINE_SEPARATOR
+                + "    appName=\"Catalina\"/>"
+                + LF.LINE_SEPARATOR
+                + "  <Valve className=\"org.apache.catalina.valves.RequestDumperValve\"/>"
+                + LF.LINE_SEPARATOR + "  <Host" + LF.LINE_SEPARATOR
+                + "    name=\"localhost\"/>" + LF.LINE_SEPARATOR + "</Engine>"
+                + LF.LINE_SEPARATOR;
+        check(aspectedResult);
+    }
+
+    public void testStoreEmpty() throws Exception {
+        String aspectedResult = "<Engine" + LF.LINE_SEPARATOR
+                + "    name=\"Catalina\">" + LF.LINE_SEPARATOR + "  <Realm"
+                + LF.LINE_SEPARATOR + "    appName=\"Catalina\"/>"
+                + LF.LINE_SEPARATOR + "</Engine>" + LF.LINE_SEPARATOR;
+        check(aspectedResult);
+    }
+
+    protected void check(String aspectedResult) throws Exception {
+        factory.store(pWriter, -2, standardEngine);
+        assertEquals(aspectedResult, writer.toString());
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/test/src/share/org/apache/catalina/storeconfig/StandardHostSFTest.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/test/src/share/org/apache/catalina/storeconfig/StandardHostSFTest.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/test/src/share/org/apache/catalina/storeconfig/StandardHostSFTest.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,296 @@
+/*
+ * Copyright 1999-2001,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.storeconfig;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+import junit.framework.TestCase;
+
+import org.apache.catalina.LifecycleListener;
+import org.apache.catalina.Valve;
+import org.apache.catalina.cluster.CatalinaCluster;
+import org.apache.catalina.cluster.deploy.FarmWarDeployer;
+import org.apache.catalina.cluster.mcast.McastService;
+import org.apache.catalina.cluster.session.JvmRouteSessionIDBinderListener;
+import org.apache.catalina.cluster.tcp.ReplicationListener;
+import org.apache.catalina.cluster.tcp.ReplicationTransmitter;
+import org.apache.catalina.cluster.tcp.ReplicationValve;
+import org.apache.catalina.cluster.tcp.SimpleTcpCluster;
+import org.apache.catalina.core.StandardContext;
+import org.apache.catalina.core.StandardHost;
+import org.apache.catalina.realm.JAASRealm;
+
+/**
+ * @author Peter Rossbach
+ *  
+ */
+public class StandardHostSFTest extends TestCase {
+    StoreRegistry registry;
+
+    StringWriter writer = new StringWriter();
+
+    PrintWriter pWriter = new PrintWriter(writer);
+
+    StandardHost standardHost;
+
+    StandardHostSF factory;
+
+    StoreDescription desc;
+
+    /*
+     * create registry and register Host and all subelement descriptors
+     * 
+     * @see junit.framework.TestCase#setUp()
+     */
+    protected void setUp() throws Exception {
+
+        super.setUp();
+        registry = new StoreRegistry();
+        desc = new StoreDescription();
+        desc.setTag("Host");
+        desc.setTagClass("org.apache.catalina.core.StandardHost");
+        desc.setStandard(true);
+        desc.setStoreFactoryClass("org.apache.catalina.core.StandardHostSF");
+        desc.addTransientAttribute("domain");
+        registry.registerDescription(desc);
+        factory = new StandardHostSF();
+        desc.setStoreFactory(factory);
+        factory.setRegistry(registry);
+        StoreDescription listenerdesc = registerDescriptor("Listener",
+                LifecycleListener.class);
+
+        String listenerskippables[] = {
+                "org.apache.catalina.core.NamingContextListener",
+                "org.apache.catalina.startup.HostConfig", };
+        for (int i = 0; i < listenerskippables.length; i++)
+            listenerdesc.addTransientChild(listenerskippables[i]);
+
+        StoreDescription realmdesc = registerDescriptor("Realm",
+                JAASRealm.class,
+                "org.apache.catalina.storeconfig.StoreFactoryBase", false,
+                false);
+        StoreDescription contextdesc = registerDescriptor("Context",
+                StandardContext.class,
+                "org.apache.catalina.storeconfig.StoreFactoryBase", true, false);
+        String exceptions[] = { "available", "configFile", "configured",
+                "distributable", "domain", "engineName", "name", "publicId",
+                "sessionTimeout", "startupTime", "tldScanTime" };
+        for (int i = 0; i < exceptions.length; i++)
+            contextdesc.addTransientAttribute(exceptions[i]);
+
+        StoreDescription valvedesc = registerDescriptor("Valve", Valve.class,
+                "org.apache.catalina.storeconfig.StoreFactoryBase", false,
+                false);
+
+        String skippables[] = { "org.apache.catalina.core.StandardHostValve",
+                "org.apache.catalina.valves.CertificatesValve",
+                "org.apache.catalina.valves.ErrorReportValve",
+                "org.apache.catalina.valves.RequestListenerValve", };
+        for (int i = 0; i < skippables.length; i++)
+            valvedesc.addTransientChild(skippables[i]);
+
+        DescriptorHelper.registerClusterDescriptor(desc, registry);
+        standardHost = new StandardHost();
+        standardHost.setName("localhost");
+
+    }
+
+    private StoreDescription registerDescriptor(String tag, Class aClass) {
+        return registerDescriptor(tag, aClass,
+                "org.apache.catalina.storeconfig.StoreFactoryBase", false,
+                false);
+    }
+
+    private StoreDescription registerDescriptor(String tag, Class aClass,
+            String factoryClass, boolean fstandard, boolean fdefault) {
+        return DescriptorHelper.registerDescriptor(desc, registry, aClass
+                .getName(), tag, aClass.getName(), factoryClass, fstandard,
+                fdefault);
+    }
+
+    public void testStore() throws Exception {
+        standardHost
+                .addLifecycleListener(new org.apache.catalina.storeconfig.InfoLifecycleListener());
+        String aspectedResult = "<Host"
+                + LF.LINE_SEPARATOR
+                + "    name=\"localhost\">"
+                + LF.LINE_SEPARATOR
+                + "  <Listener className=\"org.apache.catalina.storeconfig.InfoLifecycleListener\"/>"
+                + LF.LINE_SEPARATOR + "</Host>" + LF.LINE_SEPARATOR;
+
+        check(aspectedResult);
+    }
+
+    public void testElements() throws Exception {
+        standardHost
+                .addLifecycleListener(new org.apache.catalina.storeconfig.InfoLifecycleListener());
+        standardHost
+                .addLifecycleListener(new org.apache.catalina.startup.HostConfig());
+        standardHost.setRealm(new JAASRealm());
+        StandardContext context = new StandardContext();
+        context.setDocBase("myapps");
+        context.setPath("/myapps");
+        standardHost.addChild(context);
+        standardHost.addAlias("jovi");
+        String aspectedResult = "<Host"
+                + LF.LINE_SEPARATOR
+                + "    name=\"localhost\">"
+                + LF.LINE_SEPARATOR
+                + "  <Listener className=\"org.apache.catalina.storeconfig.InfoLifecycleListener\"/>"
+                + LF.LINE_SEPARATOR + "  <Alias>jovi</Alias>"
+                + LF.LINE_SEPARATOR
+                + "  <Realm className=\"org.apache.catalina.realm.JAASRealm\""
+                + LF.LINE_SEPARATOR + "    appName=\"localhost\"/>"
+                + LF.LINE_SEPARATOR + "  <Context" + LF.LINE_SEPARATOR
+                + "    docBase=\"myapps\"" + LF.LINE_SEPARATOR
+                + "    path=\"/myapps\"/>" + LF.LINE_SEPARATOR + "</Host>"
+                + LF.LINE_SEPARATOR;
+        check(aspectedResult);
+    }
+
+    public void testValve() throws Exception {
+        standardHost
+                .addLifecycleListener(new org.apache.catalina.storeconfig.InfoLifecycleListener());
+        standardHost
+                .addValve(new org.apache.catalina.valves.ErrorReportValve());
+        standardHost
+                .addValve(new org.apache.catalina.valves.RequestDumperValve());
+        standardHost.addValve(new ReplicationValve());
+        String aspectedResult = "<Host"
+                + LF.LINE_SEPARATOR
+                + "    name=\"localhost\">"
+                + LF.LINE_SEPARATOR
+                + "  <Listener className=\"org.apache.catalina.storeconfig.InfoLifecycleListener\"/>"
+                + LF.LINE_SEPARATOR
+                + "  <Valve className=\"org.apache.catalina.valves.RequestDumperValve\"/>"
+                + LF.LINE_SEPARATOR + "</Host>" + LF.LINE_SEPARATOR;
+        check(aspectedResult);
+    }
+
+    public void testClusterEmpty() throws Exception {
+        CatalinaCluster cluster = new SimpleTcpCluster();
+        standardHost.setCluster(cluster);
+        String aspectedResult = "<Host"
+                + LF.LINE_SEPARATOR
+                + "    name=\"localhost\">"
+                + LF.LINE_SEPARATOR
+                + "  <Cluster className=\"org.apache.catalina.cluster.tcp.SimpleTcpCluster\">"
+                + LF.LINE_SEPARATOR + "  </Cluster>" + LF.LINE_SEPARATOR
+                + "</Host>" + LF.LINE_SEPARATOR;
+        check(aspectedResult);
+    }
+
+    public void testCluster() throws Exception {
+        SimpleTcpCluster cluster = new SimpleTcpCluster();
+        cluster.setClusterName("cluster");
+        cluster.setProperty("expireSessionsOnShutdown","false");
+        cluster
+                .setManagerClassName("org.apache.catalina.cluster.session.DeltaManager");
+        McastService service = new McastService();
+        service.setMcastAddr("228.0.0.4");
+        service.setMcastPort(45564);
+        service.setMcastFrequency(500l);
+        service.setMcastDropTime(3000l);
+        cluster.setMembershipService(service);
+        ReplicationListener receiver = new ReplicationListener();
+        receiver.setTcpListenAddress("auto");
+        receiver.setTcpListenPort(4001);
+        receiver.setTcpSelectorTimeout(100l);
+        receiver.setTcpThreadCount(6);
+        cluster.setClusterReceiver(receiver);
+        ReplicationTransmitter sender = new ReplicationTransmitter();
+        sender.setReplicationMode("pooled");
+        cluster.setClusterSender(sender);
+        ReplicationValve valve = new ReplicationValve();
+        valve
+                .setFilter(".*\\.gif;.*\\.js;.*\\.jpg;.*\\.jpeg;.*\\.htm;.*\\.html;.*\\.txt;");
+        cluster.addValve(valve);
+        FarmWarDeployer deployer = new FarmWarDeployer();
+        deployer.setTempDir("/tmp/war-temp/");
+        deployer.setDeployDir("/tmp/war-deploy/");
+        deployer.setWatchDir("/tmp/war-listen/");
+        deployer.setWatchEnabled(false);
+        cluster.setClusterDeployer(deployer);
+        standardHost.setCluster(cluster);
+        cluster.addLifecycleListener(new InfoLifecycleListener());
+        cluster.addClusterListener(new JvmRouteSessionIDBinderListener());
+        // DeltaManager is default!
+        String aspectedResult = "<Host"
+                + LF.LINE_SEPARATOR
+                + "    name=\"localhost\">"
+                + LF.LINE_SEPARATOR
+                + "  <Cluster className=\"org.apache.catalina.cluster.tcp.SimpleTcpCluster\""
+                + LF.LINE_SEPARATOR
+                + "      clusterName=\"cluster\">"
+                + LF.LINE_SEPARATOR
+                + "    <Membership className=\"org.apache.catalina.cluster.mcast.McastService\""
+                + LF.LINE_SEPARATOR
+                + "      mcastAddr=\"228.0.0.4\""
+                + LF.LINE_SEPARATOR
+                + "      mcastDropTime=\"3000\""
+                + LF.LINE_SEPARATOR
+                + "      mcastFrequency=\"500\""
+                + LF.LINE_SEPARATOR
+                + "      mcastPort=\"45564\"/>"
+                + LF.LINE_SEPARATOR
+                + "    <Sender className=\"org.apache.catalina.cluster.tcp.ReplicationTransmitter\""
+                + LF.LINE_SEPARATOR
+                + "      replicationMode=\"pooled\"/>"
+                + LF.LINE_SEPARATOR
+                + "    <Receiver className=\"org.apache.catalina.cluster.tcp.ReplicationListener\""
+                + LF.LINE_SEPARATOR
+                + "      tcpListenAddress=\"auto\""
+                + LF.LINE_SEPARATOR
+                + "      tcpListenPort=\"4001\""
+                + LF.LINE_SEPARATOR
+                + "      tcpSelectorTimeout=\"100\""
+                + LF.LINE_SEPARATOR
+                + "      tcpThreadCount=\"6\"/>"
+                + LF.LINE_SEPARATOR
+                + "    <Deployer className=\"org.apache.catalina.cluster.deploy.FarmWarDeployer\""
+                + LF.LINE_SEPARATOR
+                + "      deployDir=\"/tmp/war-deploy/\""
+                + LF.LINE_SEPARATOR
+                + "      tempDir=\"/tmp/war-temp/\""
+                + LF.LINE_SEPARATOR
+                + "      watchDir=\"/tmp/war-listen/\"/>"
+                + LF.LINE_SEPARATOR
+                + "    <Valve className=\"org.apache.catalina.cluster.tcp.ReplicationValve\""
+                + LF.LINE_SEPARATOR
+                + "      filter=\".*\\.gif;.*\\.js;.*\\.jpg;.*\\.jpeg;.*\\.htm;.*\\.html;.*\\.txt;\"/>"
+                + LF.LINE_SEPARATOR
+                + "    <Listener className=\"org.apache.catalina.storeconfig.InfoLifecycleListener\"/>"
+                + LF.LINE_SEPARATOR
+                + "    <ClusterListener className=\"org.apache.catalina.cluster.session.JvmRouteSessionIDBinderListener\"/>"
+                + LF.LINE_SEPARATOR + "  </Cluster>" + LF.LINE_SEPARATOR
+                + "</Host>" + LF.LINE_SEPARATOR;
+        check(aspectedResult);
+    }
+
+    public void testStoreEmpty() throws Exception {
+        String aspectedResult = "<Host" + LF.LINE_SEPARATOR
+                + "    name=\"localhost\">" + LF.LINE_SEPARATOR + "</Host>"
+                + LF.LINE_SEPARATOR;
+        check(aspectedResult);
+    }
+
+    protected void check(String aspectedResult) throws Exception {
+        factory.store(pWriter, -2, standardHost);
+        assertEquals(aspectedResult, writer.toString());
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/test/src/share/org/apache/catalina/storeconfig/StandardServiceSFTest.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/test/src/share/org/apache/catalina/storeconfig/StandardServiceSFTest.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/test/src/share/org/apache/catalina/storeconfig/StandardServiceSFTest.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,128 @@
+/*
+ * Copyright 1999-2001,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.storeconfig;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+import junit.framework.TestCase;
+
+import org.apache.catalina.LifecycleListener;
+import org.apache.catalina.connector.Connector;
+import org.apache.catalina.core.StandardEngine;
+import org.apache.catalina.core.StandardService;
+
+/**
+ * @author Peter Rossbach
+ *  
+ */
+public class StandardServiceSFTest extends TestCase {
+    StoreRegistry registry;
+
+    StringWriter writer = new StringWriter();
+
+    PrintWriter pWriter = new PrintWriter(writer);
+
+    StandardService standardService = new StandardService();
+
+    StandardServiceSF factory;
+
+    StoreDescription desc;
+
+    /*
+     * create registry and register Service and all direct subelement
+     * descriptors
+     * 
+     * @see junit.framework.TestCase#setUp()
+     */
+    protected void setUp() throws Exception {
+
+        super.setUp();
+        registry = new StoreRegistry();
+        desc = new StoreDescription();
+        desc.setTag("Service");
+        desc.setTagClass("org.apache.catalina.core.StandardService");
+        desc.setStandard(true);
+        desc.setStoreFactoryClass("org.apache.catalina.core.StandardServiceSF");
+        registry.registerDescription(desc);
+        factory = new StandardServiceSF();
+        desc.setStoreFactory(factory);
+        factory.setRegistry(registry);
+        registerDescriptor("Listener", LifecycleListener.class);
+        registerDescriptor("Engine", StandardEngine.class,
+                "org.apache.catalina.storeconfig.StoreFactoryBase", true, false);
+        StoreDescription cdesc = registerDescriptor("Connector",
+                Connector.class, "org.apache.catalina.storeconfig.ConnectorSF",
+                true, true);
+        cdesc.getStoreFactory().setStoreAppender(new ConnectorStoreAppender());
+        StoreDescription pdesc = DescriptorHelper
+                .registerDescriptor(null, registry, Connector.class.getName()
+                        + ".[ProtocolHandler]", "ProtocolHandler",
+                        Connector.class.getName(),
+                        "org.apache.catalina.storeconfig.StoreFactoryBase",
+                        true, false);
+        pdesc.addTransientAttribute("keystore");
+        pdesc.addTransientAttribute("keypass");
+        pdesc.addTransientAttribute("keytype");
+        pdesc.addTransientAttribute("randomfile");
+        pdesc.addTransientAttribute("protocols");
+        pdesc.addTransientAttribute("clientauth");
+        pdesc.addTransientAttribute("protocol");
+        pdesc.addTransientAttribute("port");
+        pdesc.addTransientAttribute("secure");
+
+    }
+
+    private StoreDescription registerDescriptor(String tag, Class aClass) {
+        return registerDescriptor(tag, aClass,
+                "org.apache.catalina.storeconfig.StoreFactoryBase", false,
+                false);
+    }
+
+    private StoreDescription registerDescriptor(String tag, Class aClass,
+            String factoryClass, boolean fstandard, boolean fdefault) {
+        return DescriptorHelper.registerDescriptor(desc, registry, aClass
+                .getName(), tag, aClass.getName(), factoryClass, fstandard,
+                fdefault);
+    }
+
+    public void testStoreAJP() throws Exception {
+        standardService
+                .addLifecycleListener(new org.apache.catalina.mbeans.ServerLifecycleListener());
+        Connector connector = new Connector();
+        standardService.addConnector(connector);
+        standardService.setContainer(new StandardEngine());
+        String aspectedResult = "<Service>"
+                + LF.LINE_SEPARATOR
+                + "  <Listener className=\"org.apache.catalina.mbeans.ServerLifecycleListener\"/>"
+                + LF.LINE_SEPARATOR + "  <Connector/>" + LF.LINE_SEPARATOR
+                + "  <Engine/>" + LF.LINE_SEPARATOR + "</Service>"
+                + LF.LINE_SEPARATOR;
+        check(aspectedResult);
+    }
+
+    public void testStoreEmpty() throws Exception {
+        String aspectedResult = "<Service>" + LF.LINE_SEPARATOR + "</Service>"
+                + LF.LINE_SEPARATOR;
+        check(aspectedResult);
+    }
+
+    protected void check(String aspectedResult) throws Exception {
+        factory.store(pWriter, -2, standardService);
+        assertEquals(aspectedResult, writer.toString());
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/test/src/share/org/apache/catalina/storeconfig/StoreAppenderTest.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/test/src/share/org/apache/catalina/storeconfig/StoreAppenderTest.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/test/src/share/org/apache/catalina/storeconfig/StoreAppenderTest.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,91 @@
+/*
+ * Copyright 1999-2001,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.storeconfig;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.StringReader;
+import java.io.StringWriter;
+
+import junit.framework.TestCase;
+
+import org.apache.catalina.cluster.tcp.ReplicationTransmitter;
+import org.apache.catalina.core.StandardServer;
+import org.apache.catalina.deploy.ContextResource;
+import org.apache.catalina.startup.SetAllPropertiesRule;
+import org.apache.tomcat.util.digester.Digester;
+import org.xml.sax.SAXException;
+
+/**
+ * @author Peter Rossbach
+ */
+public class StoreAppenderTest extends TestCase {
+
+    /**
+     * Create the digester which will be used to parse context config files.
+     */
+    protected Digester createDigester() {
+        Digester digester = new Digester();
+        digester.setValidating(false);
+        digester.addObjectCreate("Resource",
+                "org.apache.catalina.deploy.ContextResource");
+        digester.addRule("Resource", new SetAllPropertiesRule());
+        return digester;
+    }
+
+    public void testNormalResource() throws IOException, SAXException {
+        Digester digester = createDigester();
+        String example = "<Resource auth=\"Container\" name=\"jdbc/Emp\" type=\"javax.sql.DataSource\"/>";
+        StringReader reader = new StringReader(example);
+        ContextResource resource = (ContextResource) digester.parse(reader);
+        assertNotNull(resource);
+        assertEquals("javax.sql.DataSource", resource.getType());
+    }
+
+    public void testPropertyResouce() throws IOException, SAXException {
+        Digester digester = createDigester();
+        String example = "<Resource auth=\"Container\" name=\"mail/MailSession\" type=\"javax.mail.session\" mail.host=\"localhost\"/>";
+        StringReader reader = new StringReader(example);
+        ContextResource resource = (ContextResource) digester.parse(reader);
+        assertNotNull(resource);
+        assertEquals("localhost", resource.getProperty("mail.host"));
+    }
+
+    public void testStoreStandard() throws Exception {
+        StoreDescription desc = new StoreDescription();
+        desc.setStandard(true);
+        PrintWriter writer = new PrintWriter(new StringWriter());
+        StandardServer bean = new StandardServer();
+        new StoreAppender().printAttributes(writer, 0, true, bean, desc);
+    }
+
+    public void testStoreReplicationTransmitter() throws Exception {
+        StoreDescription desc = new StoreDescription();
+        desc.setStandard(true);
+        StringWriter swriter = new StringWriter();
+        PrintWriter writer = new PrintWriter(swriter);
+        ReplicationTransmitter bean = new ReplicationTransmitter();
+        bean.setReplicationMode("asynchronous");
+        bean.setProperty("keepAliveTimeout","80000");
+        new IDynamicPropertyStoreAppender().printAttributes(writer, 0, true, bean, desc);
+        String aspectedResult =LF.LINE_SEPARATOR           
+           + "    replicationMode=\"asynchronous\"" + LF.LINE_SEPARATOR 
+           + "    keepAliveTimeout=\"80000\"" ;
+        assertEquals(aspectedResult, swriter.getBuffer().toString());
+
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/test/src/share/org/apache/catalina/storeconfig/StoreContextAppenderTest.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/test/src/share/org/apache/catalina/storeconfig/StoreContextAppenderTest.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/test/src/share/org/apache/catalina/storeconfig/StoreContextAppenderTest.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,134 @@
+/*
+ * Created on 24.08.2004
+ *
+ * TODO To change the template for this generated file go to
+ * Window - Preferences - Java - Code Style - Code Templates
+ */
+package org.apache.catalina.storeconfig;
+
+import junit.framework.TestCase;
+
+import org.apache.catalina.core.StandardContext;
+import org.apache.catalina.core.StandardEngine;
+import org.apache.catalina.core.StandardHost;
+import org.apache.catalina.startup.ContextConfig;
+import java.io.File ;
+
+/**
+ * @author Peter Rossbach
+ *  
+ */
+public class StoreContextAppenderTest extends TestCase {
+
+    StoreContextAppender appender = new StoreContextAppender();
+
+    StandardContext context = new StandardContext();
+
+    StandardHost host = new StandardHost();
+
+    /*
+     * setup default Engine, Host and Context
+     * 
+     * @see junit.framework.TestCase#setUp()
+     */
+    protected void setUp() throws Exception {
+        host.setName("localhost");
+        context.setParent(host);
+        StandardEngine engine = new StandardEngine();
+        engine.setName("Catalina");
+        host.setParent(engine);
+        super.setUp();
+    }
+
+    public void testWorkDirManager() {
+        context.setPath("/manager");
+        String defaultDir = appender.getDefaultWorkDir(context);
+        assertEquals("work\\Catalina\\localhost\\manager", defaultDir);
+
+    }
+
+    public void testWorkDirRoot() {
+        context.setPath("");
+        String defaultDir = appender.getDefaultWorkDir(context);
+        assertEquals("work\\Catalina\\localhost\\_", defaultDir);
+    }
+
+    public void testHostWorkDirRoot() {
+        context.setPath("");
+        host.setWorkDir("hostwork");
+        String defaultDir = appender.getDefaultWorkDir(context);
+        assertEquals("hostwork\\_", defaultDir);
+    }
+
+    public void testIsPrintValueDefault() {
+        StandardContext context2 = new StandardContext();
+        context.setPath("");
+        context.setWorkDir("work\\Catalina\\localhost\\_");
+        assertFalse(appender.isPrintValue(context, context2, "workDir", null));
+    }
+
+    public void testIsPrintValue() {
+        StandardContext context2 = new StandardContext();
+        context.setPath("");
+        context.setWorkDir("C:\\work\\Catalina\\localhost\\_");
+        assertTrue(appender.isPrintValue(context, context2, "workDir", null));
+    }
+
+    public void testHostIsPrintValuedefault() {
+        StandardContext context2 = new StandardContext();
+        context.setPath("");
+        host.setWorkDir("hostwork");
+        context.setWorkDir("hostwork\\_");
+        assertFalse(appender.isPrintValue(context, context2, "workDir", null));
+    }
+
+    public void _testDefaultInstance() throws Exception {
+        assertTrue(context.getCookies());
+        assertFalse(context.getReloadable());
+        StandardContext defaultContext = (StandardContext) appender
+                .defaultInstance(context);
+        assertFalse(defaultContext.getCookies());
+        assertTrue(defaultContext.getReloadable());
+        assertEquals(2, defaultContext.findLifecycleListeners().length);
+        assertTrue(defaultContext.findLifecycleListeners()[0] instanceof ContextConfig);
+        assertTrue(defaultContext.findLifecycleListeners()[1] instanceof InfoLifecycleListener);
+    }
+
+    public void _testDefaultInstanceWithoutOverride() throws Exception {
+        context.setOverride(true);
+        StandardContext defaultContext = (StandardContext) appender
+                .defaultInstance(context);
+        assertEquals(0, defaultContext.findLifecycleListeners().length);
+
+    }
+    
+    public void testPath() throws Exception {
+        StandardContext defaultContext = (StandardContext) appender
+        .defaultInstance(context);
+        context.setPath("/myapps");
+        assertNull(context.getConfigFile());
+        StoreDescription desc = new StoreDescription();
+        desc.setExternalAllowed(true);
+        desc.setStoreSeparate(true);
+        assertTrue(appender.isPrintValue(context, defaultContext, "path", desc));
+        context.setConfigFile("conf/Catalina/locahost/myapps.xml");
+        assertFalse(appender.isPrintValue(context, defaultContext, "path", desc));
+        desc.setExternalAllowed(false);
+        assertFalse(appender.isPrintValue(context, defaultContext, "path", desc));
+        desc.setExternalAllowed(true);
+        desc.setStoreSeparate(false);
+        assertFalse(appender.isPrintValue(context, defaultContext, "path", desc));
+    }
+    
+    public void testDocBase() throws Exception {
+        StandardContext defaultContext = (StandardContext) appender
+        .defaultInstance(context);
+        context.setPath("/myapps");
+        context.setDocBase("myapps");
+        host.setAppBase("webapps");
+        assertFalse(appender.isPrintValue(context, defaultContext, "docBase", null));
+        context.setDocBase(System.getProperty("java.io.tmpdir") + "/myapps");
+        assertTrue(appender.isPrintValue(context, defaultContext, "docBase", null));
+        
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/test/src/share/org/apache/catalina/storeconfig/StoreLoaderTest.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/test/src/share/org/apache/catalina/storeconfig/StoreLoaderTest.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/test/src/share/org/apache/catalina/storeconfig/StoreLoaderTest.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,88 @@
+/*
+ * Copyright 1999-2001,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.storeconfig;
+
+import java.io.IOException;
+import java.io.StringReader;
+
+import junit.framework.TestCase;
+
+import org.apache.catalina.cluster.tcp.ReplicationTransmitter;
+import org.apache.catalina.core.StandardContext;
+import org.apache.catalina.core.StandardServer;
+import org.apache.catalina.mbeans.ServerLifecycleListener;
+import org.apache.tomcat.util.digester.Digester;
+import org.xml.sax.SAXException;
+
+/**
+ * @author Peter Rossbach
+ *  
+ */
+public class StoreLoaderTest extends TestCase {
+
+    public void testDigester() throws IOException, SAXException {
+        Digester digester = StoreLoader.createDigester();
+        String example = "<Registry name=\"Tomcat\" version=\"5.5.0\" encoding=\"UTF-8\" >"
+                + " <Description "
+                + "  tag=\"Server\""
+                + "	standard=\"true\""
+                + "	default=\"true\""
+                + "  tagClass=\"org.apache.catalina.core.StandardServer\""
+                + "  storeFactoryClass=\"org.apache.catalina.storeconfig.StandardServerSF\">"
+                + " </Description>" + "</Registry>";
+        StringReader reader = new StringReader(example);
+        StoreRegistry registry = (StoreRegistry) digester.parse(reader);
+        assertNotNull(registry);
+        assertEquals("Tomcat", registry.getName());
+        assertEquals("5.5.0", registry.getVersion());
+        StoreDescription desc = registry.findDescription(StandardServer.class);
+        assertNotNull(desc);
+        assertEquals("org.apache.catalina.core.StandardServer", desc
+                .getTagClass());
+        assertEquals("Server", desc.getTag());
+    }
+
+    public void testLoadRegistry() {
+        StoreLoader loader = new StoreLoader();
+        loader.load();
+        StoreRegistry registry = loader.getRegistry();
+        assertNotNull(registry);
+        assertEquals("UTF-8", registry.getEncoding());
+        StoreDescription desc = registry.findDescription(StandardServer.class);
+        assertNotNull(desc);
+        assertEquals("org.apache.catalina.core.StandardServer", desc
+                .getTagClass());
+        desc = registry.findDescription(StandardContext.class);
+        assertNotNull(desc);
+        assertEquals(StandardContext.class.getName(), desc.getTagClass());
+        assertTrue(desc.isStoreSeparate());
+        assertNotNull(desc.getStoreFactory());
+        assertEquals(registry, desc.getStoreFactory().getRegistry());
+        assertEquals(StandardContextSF.class, desc.getStoreFactory().getClass());
+        desc = registry
+                .findDescription("org.apache.catalina.core.StandardServer.[ServerLifecycleListener]");
+        assertEquals(ServerLifecycleListener.class.getName(), desc
+                .getTagClass());
+        desc = registry.findDescription(ReplicationTransmitter.class);
+        assertNotNull(desc);
+        assertEquals(ReplicationTransmitter.class.getName(), desc
+                .getTagClass());
+        assertNotNull(desc.getStoreFactory());
+        assertEquals(IDynamicPropertyStoreAppender.class, desc.getStoreFactory().getStoreAppender().getClass()
+                );
+        
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/test/src/share/org/apache/catalina/storeconfig/StoreRegistryTest.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/test/src/share/org/apache/catalina/storeconfig/StoreRegistryTest.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/test/src/share/org/apache/catalina/storeconfig/StoreRegistryTest.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,78 @@
+/*
+ * Copyright 1999-2001,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.storeconfig;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+import junit.framework.TestCase;
+
+import org.apache.catalina.core.StandardServer;
+
+/**
+ * @author Peter Rossbach
+ *  
+ */
+public class StoreRegistryTest extends TestCase {
+
+    StoreRegistry registry;
+
+    StringWriter writer = new StringWriter();
+
+    PrintWriter pWriter = new PrintWriter(writer);
+
+    StandardServer standardServer = new StandardServer();
+
+    IStoreFactory factory;
+
+    StoreDescription desc;
+
+    /*
+     * create registry and register Server 
+     * 
+     * @see junit.framework.TestCase#setUp()
+     */
+    protected void setUp() throws Exception {
+
+        super.setUp();
+        registry = new StoreRegistry();
+        desc = new StoreDescription();
+        desc.setTag("Server");
+        desc.setTagClass("org.apache.catalina.core.StandardServer");
+        desc.setStandard(true);
+        desc
+                .setStoreFactoryClass("org.apache.catalina.storeconfig.StoreFactoryBase");
+        registry.registerDescription(desc);
+        factory = new StoreFactoryBase();
+        factory.setRegistry(registry);
+    }
+
+    public void testSaveServer() throws Exception {
+        assertNotNull(registry.findDescription(StandardServer.class));
+        factory.store(pWriter, -2, standardServer);
+        assertEquals("XML Diff", "<Server/>" + LF.LINE_SEPARATOR, writer
+                .toString());
+    }
+
+    public void testAttributes() throws Exception {
+        standardServer.setPort(7305);
+        factory.store(pWriter, -2, standardServer);
+        assertEquals("XML Diff", "<Server" + LF.LINE_SEPARATOR
+                + "  port=\"7305\"/>" + LF.LINE_SEPARATOR, writer.toString());
+
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/to-do.txt
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/to-do.txt	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/modules/storeconfig-ha/to-do.txt	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,9 @@
+1. Fix new connector properties and protocolhandler for 5.5 (testcases)
+	 Work!
+2. Fix context default handling (hard stuff)
+3. Check cluster transient attributes
+4. add documentation
+5. replace old server implementation instead current listener implementation
+6. Context path attribute handling ( delete at external context.xml and used inside server.xml!)
+7. Test with Admin App
+

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/build.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/build.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/build.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,226 @@
+<project name="Tester" default="build-main" basedir=".">
+
+
+  <!-- ===================== Initialize Property Values =================== -->
+
+  <property file="build.properties"/>
+  <property file="../build.properties"/>
+  <property file="${user.home}/build.properties"/>
+
+  <property name="build.compiler"  value="modern"/>
+  <property name="api.home" value="../../jakarta-servletapi-5/dist"/>
+  <property name="tester.build"    value="${basedir}/build"/>
+  <property name="tester.deploy"   value="${basedir}/../build"/>
+  <property name="tester.dist"     value="${basedir}/dist"/>
+
+  <!-- ================== Derived Property Values ========================= -->
+  <property name="ant.jar"         value="${ant.home}/lib/ant.jar"/>
+  <property name="servlet-api.jar" value="${api.home}/jsr154/dist/lib/servlet-api.jar"/>
+
+  <!-- =================== BUILD: Create Directories ====================== -->
+  <target name="build-prepare">
+    <mkdir dir="${tester.build}"/>
+    <mkdir dir="${tester.build}/bin"/>
+    <mkdir dir="${tester.build}/classes"/>
+    <mkdir dir="${tester.build}/conf"/>
+    <mkdir dir="${tester.build}/lib"/>
+  </target>
+
+
+  <!-- =================== BUILD: Copy Static Files ======================= -->
+  <target name="build-static" depends="build-prepare">
+
+    <!-- Executable Commands -->
+    <mkdir  dir="${tester.build}/bin"/>
+    <copy todir="${tester.build}/bin">
+      <fileset dir="src/bin" />
+    </copy>
+    <fixcrlf srcdir="${tester.build}/bin" includes="*.sh"  eol="lf"/>
+    <fixcrlf srcdir="${tester.build}/bin" includes="*.bat" eol="crlf"/>
+    <chmod perm="+x" file="${tester.build}/bin/tester.sh"/>
+    <copy todir="${tester.build}/conf">
+      <fileset dir="src/conf" />
+    </copy>
+
+    <!-- Compiled Classes -->
+    <mkdir  dir="${tester.build}/classes"/>
+
+    <!-- Web Application -->
+    <mkdir  dir="${tester.build}/web"/>
+    <copy todir="${tester.build}/web">
+      <fileset dir="web"/>
+    </copy>
+    <mkdir  dir="${tester.build}/web/WEB-INF/classes"/>
+
+  </target>
+
+
+  <!-- ================= BUILD: Compile Server Components ================= -->
+  <target name="build-main" depends="build-static">
+
+    <!-- Compile tester components and tools -->
+    <javac srcdir="src/tester" destdir="${tester.build}/classes"
+     classpath="${ant.jar}:${servlet-api.jar}:${xercesImpl.jar}"
+     deprecation="${compile.deprecation}"
+     debug="${compile.debug}" optimize="off"
+     excludes="**/CVS/**"/>
+
+    <!-- Copy static resource files -->
+    <copy todir="${tester.build}/classes">
+      <fileset dir="src/tester">
+        <include name="**/*.properties"/>
+      </fileset>
+      <fileset dir="src/tester">
+        <include name="**/*.txt"/>
+      </fileset>
+    </copy>
+    <copy file="${tester.build}/classes/org/apache/tester/unshared/UnsharedSessionBean.class"
+        tofile="${tester.build}/web/WEB-INF/classes/org/apache/tester/unshared/UnsharedSessionBean.class"/>
+    <copy file="src/tester/org/apache/tester/Resources01.txt"
+        tofile="${tester.build}/web/WEB-INF/classes/org/apache/tester/Unpacked01.txt"/>
+    <copy file="src/tester/org/apache/tester/Resources01.txt"
+        tofile="${tester.build}/classes/org/apache/tester/shared/Shared01.txt"/>
+    <copy file="src/tester/org/apache/tester/Resources01.txt"
+        tofile="${tester.build}/classes/org/apache/tester/unpshared/UnpShared01.txt"/>
+    <copy file="src/tester/org/apache/tester/Resources03.txt"
+        tofile="${tester.build}/web/WEB-INF/classes/org/apache/tester/Unpacked03.txt"/>
+    <copy file="src/tester/org/apache/tester/Resources03.txt"
+        tofile="${tester.build}/classes/org/apache/tester/shared/Shared03.txt"/>
+    <copy file="src/tester/org/apache/tester/Resources03.txt"
+        tofile="${tester.build}/classes/org/apache/tester/unpshared/UnpShared03.txt"/>
+    <copy file="src/tester/org/apache/tester/Resources05.txt"
+        tofile="${tester.build}/web/WEB-INF/classes/org/apache/tester/Unpacked05.txt"/>
+
+    <!-- Install Xerces -->
+    <copy  todir="${tester.build}/web/WEB-INF/lib" file="${xercesImpl.jar}"/>
+    <copy  todir="${tester.build}/web/WEB-INF/lib" file="${xml-apis.jar}"/>
+
+    <!-- Create and install tester library -->
+    <mkdir   dir="${tester.build}/web/WEB-INF/lib"/>
+    <jar jarfile="${tester.build}/web/WEB-INF/lib/tester.jar">
+      <fileset dir="${tester.build}/classes">
+        <exclude name="**/shared/*"/>
+        <exclude name="**/unshared/*"/>
+      </fileset>
+    </jar>
+
+  </target>
+
+
+  <!-- ================ BUILD: Create Tester Javadocs ===================== -->
+  <target name="javadoc" depends="build-main">
+    <delete dir="${tester.build}/javadoc"/>
+    <mkdir dir="${tester.build}/javadoc"/>
+    <javadoc packagenames="org.apache.tester.*"
+     classpath="${ant.jar}:${tester.build}/classes"
+     sourcepath="src/tester"
+     destdir="${tester.build}/javadoc"
+     author="true"
+     version="true"
+     windowtitle="Tester Internal API Documentation"
+     doctitle="Tester Tools and Tests API"
+     bottom="Copyright &#169; 2000-2004 Apache Software Foundation.  All Rights Reserved."
+    />
+  </target>
+
+
+  <!-- ======================= BUILD: Clean Directory ===================== -->
+  <target name="build-clean">
+    <delete dir="${tester.build}"/>
+  </target>
+
+
+  <!-- ==================== BUILD: Rebuild Everything ===================== -->
+  <target name="all" depends="build-clean,build-main"/>
+
+
+  <!-- ====================== DEPLOY: Create Directories ================== -->
+  <target name="deploy-prepare">
+    <mkdir dir="${tester.deploy}"/>
+    <mkdir dir="${tester.deploy}/bin"/>
+    <mkdir dir="${tester.deploy}/conf"/>
+  </target>
+
+
+  <!-- ====================== DEPLOY: Copy Static Files =================== -->
+  <target name="deploy-static" depends="build-main,deploy-prepare">
+
+    <!-- Executable Commands -->
+    <copy todir="${tester.deploy}/bin">
+      <fileset dir="${tester.build}/bin" />
+    </copy>
+    <fixcrlf srcdir="${tester.deploy}/bin" includes="*.sh"  eol="lf"/>
+    <fixcrlf srcdir="${tester.deploy}/bin" includes="*.bat" eol="crlf"/>
+    <chmod perm="+x" file="${tester.deploy}/bin/tester.sh"/>
+    <copy todir="${tester.deploy}/conf" overwrite="true">
+      <fileset dir="${tester.build}/conf" />
+    </copy>
+
+    <!-- Unpacked Shared Classes -->
+    <mkdir   dir="${tester.deploy}/shared/classes"/>
+    <copy  todir="${tester.deploy}/shared/classes">
+      <fileset dir="${tester.build}/classes">
+        <include name="**/unpshared/*"/>
+      </fileset>
+    </copy>
+
+    <!-- Shared Library -->
+    <mkdir   dir="${tester.deploy}/shared/lib"/>
+    <jar jarfile="${tester.deploy}/shared/lib/tester-shared.jar">
+      <fileset dir="${tester.build}/classes">
+        <include name="**/shared/*"/>
+      </fileset>
+    </jar>
+
+    <!-- Web Application -->
+    <mkdir  dir="${tester.deploy}/webapps/tester"/>
+    <copy todir="${tester.deploy}/webapps/tester">
+      <fileset dir="${tester.build}/web"/>
+    </copy>
+
+  </target>
+
+
+  <!-- ====================== DEPLOY: Create Tester JAR =================== -->
+  <target name="deploy-main" depends="deploy-static"/>
+
+
+  <!-- ====================== DEPLOY: Deploy Tester Build ================= -->
+  <target name="deploy" depends="deploy-main"/>
+
+
+  <!-- ====================== DEPLOY: Clean Directories =================== -->
+  <target name="deploy-clean">
+    <delete dir="${tester.deploy}/webapps/tester"/>
+  </target>
+
+
+  <!-- ================ DIST: Create Distribution ========================= -->
+  <target name="dist" depends="build-main">
+
+    <mkdir dir="${tester.dist}/bin"/>
+    <copy todir="${tester.dist}/bin">
+      <fileset dir="${tester.build}/bin" />
+    </copy>
+    <fixcrlf srcdir="${tester.dist}/bin" includes="*.sh"  eol="lf"/>
+    <fixcrlf srcdir="${tester.dist}/bin" includes="*.bat" eol="crlf"/>
+    <chmod perm="+x" file="${tester.dist}/bin/tester.sh"/>
+
+    <mkdir   dir="${tester.dist}/webapps"/>
+    <jar jarfile="${tester.dist}/webapps/tester.war"
+         basedir="${tester.build}/web"/>
+
+  </target>
+
+
+  <!-- ======================== DIST: Clean Directory ===================== -->
+  <target name="dist-clean">
+    <delete dir="${tester.dist}"/>
+  </target>
+
+
+  <!-- ====================== Convenient Synonyms ========================= -->
+  <target name="clean" depends="build-clean, dist-clean"/>
+
+
+</project>

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/src/bin/tester.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/src/bin/tester.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/src/bin/tester.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,1939 @@
+<project name="Tester" default="all">
+
+  <!-- ========== Global Properties ======================================= -->
+  <property name="catalina.home"  value="../../build/tomcat-4.0"/>
+  <property name="debug"          value="0"/>
+  <property name="host"           value="localhost"/>
+  <property name="port"           value="8080"/>
+<!--  <property name="protocol"       value="HTTP/1.0"/> -->
+  <property name="protocol"       value="HTTP/1.0"/> <!-- Use HttpURLConnection -->
+  <property name="context.path"   value="/tester"/>
+  <property name="jsp-examples.path"  value="/jsp-examples"/>
+  <property name="servlets-examples.path"  value="/servlets-examples"/>
+  <property name="golden.path"    value="${context.path}/golden"/>
+  <property name="manager.path"   value="/manager"/>
+  <property name="reload.path"    value="/tester"/>
+  <taskdef  name="tester"     classname="org.apache.tester.TestClient">
+    <classpath>
+      <pathelement location="${catalina.home}/webapps/tester/WEB-INF/lib/tester.jar"/>
+    </classpath>
+  </taskdef>
+
+
+  <target name="all" depends="ROOT,Authentication,CaseSensitive,Decoding,ErrorPage,FilterRequest,FilterResponse,Jndi,Jsp,Lifecycle,RequestDispatcher,Resources,Security,ServletContext,ServletRequest,ServletResponse,HttpSession,XercesTest"/>
+
+  <target name="ROOT">
+
+    <!-- ========== Basic Run State ======================================= -->
+
+    <!-- Should be able to see the home page -->
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="/index.jsp" debug="${debug}"
+          status="200"/>
+
+    <!-- Should be able to use relative path to document root -->
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${jsp-examples.path}/.." debug="${debug}"
+          status="200"/>
+
+    <!-- Should be able to successfully retrieve a golden file -->
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/Golden01"
+          golden="${golden.path}/Golden01.txt"/>
+
+    <!-- Should be able to successfully retrieve a golden file -->
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/WrappedGolden01"
+          golden="${golden.path}/Golden01.txt"/>
+
+  </target>
+
+
+  <target name="Authentication">
+
+    <!-- ========== Authentication ======================================== -->
+
+    <!-- Once a user has been authenticated, the corresponding user identity
+         should be visible to all other requests in this web application, even
+         for URIs that are not protected by security constraints.  This is
+         tested by invoking a protected URI followed by a non-protected URI
+    -->
+
+    <!-- ========== Basic Access to Authenticated Resources =============== -->
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+          debug="${debug}"
+         request="${context.path}/protected/Authentication01"
+       inHeaders="Authorization:Basic dG9tY2F0OnRvbWNhdA=="
+      outContent="Authentication01 PASSED"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+          debug="${debug}"
+         request="${context.path}/protected/Authentication02"
+       inHeaders="Authorization:Basic dG9tY2F0OnRvbWNhdA=="
+      outContent="Authentication02 PASSED"/>
+
+    <!-- Test isUserInRole() on actual role and on an alias (servlet) -->
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+          debug="${debug}"
+         request="${context.path}/protected/Authentication03"
+       inHeaders="Authorization:Basic dG9tY2F0OnRvbWNhdA=="
+      outContent="Authentication03 PASSED"/>
+
+    <!-- Test isUserInRole() on actual role and on an alias (JSP page) -->
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+          debug="${debug}"
+         request="${context.path}/protected/Authentication04"
+       inHeaders="Authorization:Basic dG9tY2F0OnRvbWNhdA=="
+      outContent="Authentication04 PASSED"/>
+
+    <!-- ========== "All Allowed" and "All Disallowed" Access ============= -->
+
+    <tester host="${host}" port="${port}" protocol="HTTP/1.0"
+          debug="${debug}"
+         request="${context.path}/allowed/Authentication05"
+       inHeaders="Authorization:Basic dG9tY2F0OnRvbWNhdA=="
+      outContent="Authentication05 PASSED"/>
+
+    <tester host="${host}" port="${port}" protocol="HTTP/1.0"
+          debug="${debug}"
+         request="${context.path}/disallowed/Authentication05"
+       inHeaders="Authorization:Basic dG9tY2F0OnRvbWNhdA=="
+          status="403"/>
+
+    <!-- ========== Combining Constraint Access ============= -->
+    <tester host="${host}" port="${port}" protocol="HTTP/1.0"
+          debug="${debug}"
+         request="${context.path}/disallowed/private/Authentication05"
+       inHeaders="Authorization:Basic dG9tY2F0OnRvbWNhdA=="
+          status="403"/>
+    <tester host="${host}" port="${port}" protocol="HTTP/1.0"
+          debug="${debug}"
+         request="${context.path}/allowed/public/Authentication06"
+      outContent="Authentication06 PASSED"/>
+    <tester host="${host}" port="${port}" protocol="HTTP/1.0"
+          debug="${debug}"
+         request="${context.path}/allowed/private/Authentication05"
+       inHeaders="Authorization:Basic dG9tY2F0OnRvbWNhdA=="
+          status="403"/>
+
+  </target>
+
+
+  <target name="CaseSensitive">
+
+    <!-- ========== Case Sensitive Request URI Matching =================== -->
+
+    <!-- Make sure that static resources are matched case sensitively -->
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="/index.HTML" debug="${debug}"
+          status="404"/>
+
+    <!-- Should be able to execute the Date example -->
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${jsp-examples.path}/dates/date.jsp" debug="${debug}"
+          status="200"/>
+
+    <!-- Should not be able to view the source of the Date example -->
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${jsp-examples.path}/dates/date.Jsp" debug="${debug}"
+          status="404"/>
+
+    <!-- Should not be able to view the source of the Date example -->
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${jsp-examples.path}/dates/Date.jsp" debug="${debug}"
+          status="404"/>
+
+    <!-- Should not be able to view the source of the Date example -->
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${jsp-examples.path}/Dates/date.jsp" debug="${debug}"
+          status="404"/>
+
+    <!-- Should be able to execute the HelloWorld servlet example -->
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${servlets-examples.path}/servlet/HelloWorldExample" debug="${debug}"
+          status="200"/>
+
+    <!-- Should not be able to execute HelloWorld with different cases -->
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${servlets-examples.path}/servlet/helloWorldExample" debug="${debug}"
+          status="404"/>
+
+    <!-- Should not be able to execute HelloWorld with different cases -->
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${servlets-examples.path}/Servlet/HelloWorldExample" debug="${debug}"
+          status="404"/>
+
+  </target>
+
+
+  <target name="Decoding">
+
+    <!-- ========== URL Decoding Tests ==================================== -->
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/Decoding01?servlet=/Decoding01"
+      outContent="Decoding01 PASSED"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/Decoding01/extra?servlet=/Decoding01&amp;path=/extra"
+      outContent="Decoding01 PASSED"/>
+ 
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/Decoding0%31?servlet=/Decoding01"
+      outContent="Decoding01 PASSED"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/Decoding01/extr%61?servlet=/Decoding01&amp;path=/extra"
+      outContent="Decoding01 PASSED"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/Decoding0%31/extr%61?servlet=/Decoding01&amp;path=/extra"
+      outContent="Decoding01 PASSED"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/WrappedDecoding01?servlet=/WrappedDecoding01"
+      outContent="Decoding01 PASSED"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/WrappedDecoding01/extra?servlet=/WrappedDecoding01&amp;path=/extra"
+      outContent="Decoding01 PASSED"/>
+ 
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/WrappedDecoding0%31?servlet=/WrappedDecoding01"
+      outContent="Decoding01 PASSED"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/WrappedDecoding01/extr%61?servlet=/WrappedDecoding01&amp;path=/extra"
+      outContent="Decoding01 PASSED"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/WrappedDecoding0%31/extr%61?servlet=/WrappedDecoding01&amp;path=/extra"
+      outContent="Decoding01 PASSED"/>
+
+    <!-- Verify we can access the JSP page normally -->
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${jsp-examples.path}/snp/snoop.jsp"
+          status="200"/>
+
+  </target>
+
+
+  <target name="ErrorPage">
+
+    <!-- ========== Error Code Mapping ==================================== -->
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/ErrorPage01" debug="${debug}"
+      outContent="ErrorPage02 PASSED"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/WrappedErrorPage01" debug="${debug}"
+      outContent="ErrorPage02 PASSED"/>
+
+
+    <!-- ========== Exception Mapping (Servlet Source) ==================== -->
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/ErrorPage03" debug="${debug}"
+          status="200"
+      outContent="ErrorPage04 PASSED"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/WrappedErrorPage03" debug="${debug}"
+          status="200"
+      outContent="ErrorPage04 PASSED"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/ErrorPage05?type=Arithmetic"
+           debug="${debug}"
+          status="200"
+      outContent="ErrorPage06 PASSED - SERVLET"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/WrappedErrorPage05?type=Arithmetic"
+           debug="${debug}"
+          status="200"
+      outContent="ErrorPage06 PASSED - SERVLET"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/ErrorPage05?type=Array"
+           debug="${debug}"
+          status="500"
+      outContent="ErrorPage06 PASSED - JSP"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/WrappedErrorPage05?type=Array"
+           debug="${debug}"
+          status="500"
+      outContent="ErrorPage06 PASSED - JSP"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/ErrorPage05?type=Number"
+           debug="${debug}"
+          status="500"
+      outContent="ErrorPage06 PASSED - HTML"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/WrappedErrorPage05?type=Number"
+           debug="${debug}"
+          status="500"
+      outContent="ErrorPage06 PASSED - HTML"/>
+
+    <!-- ========== Load On Startup Exception Handling ==================== -->
+
+    <!-- NOTE: HttpURLConnection throws FileNotFoundException on 503s -->
+    <tester host="${host}" port="${port}" protocol="HTTP/1.0"
+         request="${context.path}/ErrorPage07"
+           debug="${debug}"
+          status="404"/>
+
+    <tester host="${host}" port="${port}" protocol="HTTP/1.0"
+         request="${context.path}/WrappedErrorPage07"
+           debug="${debug}"
+          status="404"/>
+
+    <!-- ========== Exception Mapping (JSP Source) ======================== -->
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/ErrorPage08?type=Arithmetic"
+           debug="${debug}"
+          status="200"
+      outContent="ErrorPage06 PASSED - SERVLET"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/WrappedErrorPage08?type=Arithmetic"
+           debug="${debug}"
+          status="200"
+      outContent="ErrorPage06 PASSED - SERVLET"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/ErrorPage08?type=Array"
+           debug="${debug}"
+          status="500"
+      outContent="ErrorPage06 PASSED - JSP"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/WrappedErrorPage08?type=Array"
+           debug="${debug}"
+          status="500"
+      outContent="ErrorPage06 PASSED - JSP"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/ErrorPage08?type=Number"
+           debug="${debug}"
+          status="500"
+      outContent="ErrorPage06 PASSED - HTML"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/WrappedErrorPage08?type=Number"
+           debug="${debug}"
+          status="500"
+      outContent="ErrorPage06 PASSED - HTML"/>
+
+    <!-- ========== Exception Mapping (JSP Error Page) ==================== -->
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/ErrorPage09"
+           debug="${debug}"
+          status="500"
+      outContent="ErrorPage10 PASSED"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/WrappedErrorPage09"
+           debug="${debug}"
+          status="500"
+      outContent="ErrorPage10 PASSED"/>
+
+  </target>
+
+
+  <target name="FilterRequest">
+
+    <!-- ========== Apply Upper Case Filter =============================== -->
+
+    <!-- Input via buffered reader -->
+    <tester host="${host}" port="${port}" protocol="HTTP/1.0"
+         request="${context.path}/FilterRequest01?type=reader"
+           debug="${debug}"
+          status="200"
+       inContent="FilterRequest01 Unwrapped Reader PASSED"
+      outContent="FILTERREQUEST01 UNWRAPPED READER PASSED"/>
+
+    <tester host="${host}" port="${port}" protocol="HTTP/1.0"
+         request="${context.path}/WrappedFilterRequest01?type=reader"
+           debug="${debug}"
+          status="200"
+       inContent="FilterRequest01 Wrapped Reader PASSED"
+      outContent="FILTERREQUEST01 WRAPPED READER PASSED"/>
+
+    <!-- Input via servlet input stream -->
+    <tester host="${host}" port="${port}" protocol="HTTP/1.0"
+         request="${context.path}/FilterRequest01?type=reader"
+           debug="${debug}"
+          status="200"
+       inContent="FilterRequest01 Unwrapped Stream PASSED"
+      outContent="FILTERREQUEST01 UNWRAPPED STREAM PASSED"/>
+
+    <tester host="${host}" port="${port}" protocol="HTTP/1.0"
+         request="${context.path}/WrappedFilterRequest01?type=reader"
+           debug="${debug}"
+          status="200"
+       inContent="FilterRequest01 Wrapped Stream PASSED"
+      outContent="FILTERREQUEST01 WRAPPED STREAM PASSED"/>
+
+    <!-- ========== Servlet Sees Application Wrapper ===================== -->
+
+    <tester host="${host}" port="${port}" protocol="HTTP/1.0" debug="${debug}"
+         request="${context.path}/FilterRequest02?wrap=false"
+      outContent="FilterRequest02 PASSED"/>
+
+    <tester host="${host}" port="${port}" protocol="HTTP/1.0" debug="${debug}"
+         request="${context.path}/WrappedFilterRequest02?wrap=true"
+      outContent="FilterRequest02 PASSED"/>
+
+    <tester host="${host}" port="${port}" protocol="HTTP/1.0" debug="${debug}"
+         request="${context.path}/FilterRequest02?wrap=false&amp;dispatch=F"
+      outContent="FilterRequest02 PASSED"/>
+
+    <tester host="${host}" port="${port}" protocol="HTTP/1.0" debug="${debug}"
+         request="${context.path}/WrappedFilterRequest02?wrap=true&amp;dispatch=F"
+      outContent="FilterRequest02 PASSED"/>
+
+    <tester host="${host}" port="${port}" protocol="HTTP/1.0" debug="${debug}"
+         request="${context.path}/FilterRequest02?wrap=false&amp;dispatch=I"
+      outContent="FilterRequest02 PASSED"/>
+
+    <tester host="${host}" port="${port}" protocol="HTTP/1.0" debug="${debug}"
+         request="${context.path}/WrappedFilterRequest02?wrap=true&amp;dispatch=I"
+      outContent="FilterRequest02 PASSED"/>
+
+  </target>
+
+
+  <target name="FilterResponse">
+
+    <!-- ========== Apply Upper Case Filter =============================== -->
+
+    <!-- Output from a servlet -->
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/FilterResponse01"
+           debug="${debug}"
+          status="200"
+      outContent="FILTERRESPONSE01 PASSED"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/WrappedFilterResponse01"
+           debug="${debug}"
+          status="200"
+      outContent="FILTERRESPONSE01 PASSED"/>
+
+    <!-- Output from a JSP Page -->
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/FilterResponse02.jsp"
+           debug="${debug}"
+          status="200"
+      outContent="FILTERRESPONSE02 PASSED"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/WrappedFilterResponse02.jsp"
+           debug="${debug}"
+          status="200"
+      outContent="FILTERRESPONSE02 PASSED"/>
+
+    <!-- Output from a static page -->
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/FilterResponse03.txt"
+           debug="${debug}"
+          status="200"
+      outContent="FILTERRESPONSE03 PASSED"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/WrappedFilterResponse03.txt"
+           debug="${debug}"
+          status="200"
+      outContent="FILTERRESPONSE03 PASSED"/>
+
+    <!-- ========== Servlet Sees Application Wrapper ===================== -->
+
+    <tester host="${host}" port="${port}" protocol="HTTP/1.0"
+         request="${context.path}/FilterResponse04?wrap=false" debug="${debug}"
+      outContent="FilterResponse04 PASSED"/>
+
+    <tester host="${host}" port="${port}" protocol="HTTP/1.0" debug="${debug}"
+         request="${context.path}/WrappedFilterResponse04?wrap=true"
+      outContent="FilterResponse04 PASSED"/>
+
+    <tester host="${host}" port="${port}" protocol="HTTP/1.0" debug="${debug}"
+         request="${context.path}/FilterResponse04?wrap=false&amp;dispatch=F"
+      outContent="FilterResponse04 PASSED"/>
+
+    <tester host="${host}" port="${port}" protocol="HTTP/1.0" debug="${debug}"
+         request="${context.path}/WrappedFilterResponse04?wrap=true&amp;dispatch=F"
+      outContent="FilterResponse04 PASSED"/>
+
+    <tester host="${host}" port="${port}" protocol="HTTP/1.0" debug="${debug}"
+         request="${context.path}/FilterResponse04?wrap=false&amp;dispatch=I"
+      outContent="FilterResponse04 PASSED"/>
+
+    <tester host="${host}" port="${port}" protocol="HTTP/1.0" debug="${debug}"
+         request="${context.path}/WrappedFilterResponse04?wrap=true&amp;dispatch=I"
+      outContent="FilterResponse04 PASSED"/>
+
+  </target>
+
+
+  <target name="Internals">
+
+
+    <!-- ========== Access Internals Via Reflection ======================= -->
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/Reflection01"
+           debug="${debug}"
+      outContent="Reflection01 PASSED"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/WrappedReflection01"
+           debug="${debug}"
+      outContent="Reflection01 PASSED"/>
+
+  </target>
+
+
+  <target name="Jndi">
+
+    <!-- ========== JNDI Naming Context =================================== -->
+
+    <!-- Perform the tests before restarting the application -->
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/Jndi01" debug="${debug}"
+      outContent="Jndi01 PASSED"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/WrappedJndi01" debug="${debug}"
+      outContent="Jndi01 PASSED"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/Jndi02" debug="${debug}"
+      outContent="Jndi02 PASSED"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/WrappedJndi02" debug="${debug}"
+      outContent="Jndi02 PASSED"/>
+
+    <!-- Restart this web application -->
+    <!-- NOTE: Assign role "manager" to user "tomcat" for this to work -->
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+           debug="${debug}"
+       inHeaders="Authorization:Basic dG9tY2F0OnRvbWNhdA=="
+         request="${manager.path}/reload?path=${reload.path}"
+      outContent="OK - "/>
+
+    <!-- Repeat the tests to ensure the naming context is reinitialized -->
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/Jndi01" debug="${debug}"
+      outContent="Jndi01 PASSED"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/WrappedJndi01" debug="${debug}"
+      outContent="Jndi01 PASSED"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/Jndi02" debug="${debug}"
+      outContent="Jndi02 PASSED"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/WrappedJndi02" debug="${debug}"
+      outContent="Jndi02 PASSED"/>
+
+  </target>
+
+
+  <target name="Jsp">
+
+    <echo message="----- JSP Access To Bean Classes -----"/>
+
+    <tester host="${host}" port="${port}" protocol="HTTP/1.0"
+         request="${context.path}/JspBeans01.jsp" debug="${debug}"
+      outContent="JspBeans01 PASSED"/>
+
+    <tester host="${host}" port="${port}" protocol="HTTP/1.0"
+         request="${context.path}/JspBeans02.jsp" debug="${debug}"
+      outContent="JspBeans02 PASSED"/>
+
+    <tester host="${host}" port="${port}" protocol="HTTP/1.0"
+         request="${context.path}/JspBeans03.jsp" debug="${debug}"
+      outContent="JspBeans03 PASSED"/>
+
+    <echo message="----- jsp:params not legal in jsp:include/forward -----"/>
+
+    <tester host="${host}" port="${port}" protocol="HTTP/1.0"
+         request="${context.path}/JspParams01.jsp" debug="${debug}"
+          status="500"/>
+
+    <tester host="${host}" port="${port}" protocol="HTTP/1.0"
+         request="${context.path}/JspParams02.jsp" debug="${debug}"
+          status="500"/>
+
+    <echo message="----- Character Encoding and Escaping Tests -----"/>
+
+    <tester host="${host}" port="${port}" protocol="HTTP/1.0"
+         request="${context.path}/Encoding01.jsp" debug="${debug}"
+          golden="${golden.path}/Encoding01.txt"/>
+
+    <tester host="${host}" port="${port}" protocol="HTTP/1.0"
+         request="${context.path}/Encoding02.jsp" debug="${debug}"
+          golden="${golden.path}/Encoding02.txt"/>
+
+    <tester host="${host}" port="${port}" protocol="HTTP/1.0"
+         request="${context.path}/Encoding03.jsp" debug="${debug}"
+          golden="${golden.path}/Encoding03.txt"/>
+
+    <echo message="----- PropertyEditor Support -----"/>
+
+<!-- Cannot test PropertyEditor support under security manager
+     unless catalina.policy grants read/write access to
+     system properties -->
+<!--
+    <tester host="${host}" port="${port}" protocol="HTTP/1.0"
+         request="${context.path}/Property01.jsp" debug="${debug}"
+          golden="${golden.path}/Property01.txt"/>
+-->
+
+    <tester host="${host}" port="${port}" protocol="HTTP/1.0"
+         request="${context.path}/Property02.jsp" debug="${debug}"
+          status="500"/>
+
+    <echo message="----- JSP Document Parsing -----"/>
+
+    <tester host="${host}" port="${port}" protocol="HTTP/1.0"
+         request="${context.path}/JspDoc01.jsp" debug="${debug}"
+          golden="${golden.path}/JspDoc01.txt"/>
+
+    <tester host="${host}" port="${port}" protocol="HTTP/1.0"
+         request="${context.path}/JspDoc02.jsp" debug="${debug}"
+          golden="${golden.path}/JspDoc02.txt"/>
+
+    <echo message="----- jsp:forward -----"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/JspForward01.jsp?path=/JspForward01a.jsp" debug="${debug}"
+      outContent="JspForward01a PASSED"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/JspForward01.jsp?path=/Forward00a" debug="${debug}"
+      outContent="Forward00a PASSED"/>
+
+    <echo message="----- jsp:include flush=true -----"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/JspInclude01.jsp?path=/JspInclude01a.jsp" debug="${debug}"
+          golden="${golden.path}/JspInclude01.txt"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/JspInclude01.jsp?path=/Include00a"
+           debug="${debug}"
+          golden="${golden.path}/JspInclude01a.txt"/>
+
+    <echo message="----- jsp:include flush=false -----"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/JspInclude02.jsp?path=/JspInclude02a.jsp" debug="${debug}"
+          golden="${golden.path}/JspInclude02.txt"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/JspInclude02.jsp?path=/Include00a"
+           debug="${debug}"
+          golden="${golden.path}/JspInclude02a.txt"/>
+
+  </target>
+
+
+  <target name="Lifecycle">
+
+    <!-- ========== Lifecycle Management ================================== -->
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/Lifecycle01"
+      outContent="Lifecycle01 PASSED" debug="${debug}"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/WrappedLifecycle01"
+      outContent="Lifecycle01 PASSED" debug="${debug}"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/Lifecycle02" method="POST"
+      outContent="Lifecycle02 PASSED" debug="${debug}"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/WrappedLifecycle02" method="POST"
+      outContent="Lifecycle02 PASSED" debug="${debug}"/>
+
+    <tester host="${host}" port="${port}" protocol="HTTP/1.0"
+         request="${context.path}/Lifecycle03?step=1" debug="${debug}"
+          status="404"/>
+
+<!-- NOTE - cannot do this as originally intended, because the
+     servlet was marked as permanently unavailable, so just
+     check for another 503 instead!
+
+    <tester host="${host}" port="${port}" protocol="HTTP/1.0"
+         request="${context.path}/Lifecycle03?step=2"
+      outContent="Lifecycle03 PASSED" debug="${debug}"/>
+-->
+
+    <tester host="${host}" port="${port}" protocol="HTTP/1.0"
+         request="${context.path}/Lifecycle03?step=2" debug="${debug}"
+          status="404"/>
+
+  </target>
+
+
+  <target name="RequestDispatcher">
+
+    <echo message="----- Basic Forward Functionality -----"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/Forward00?path=/Forward00a"
+      outContent="Forward00a PASSED" debug="${debug}"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/WrappedForward00?path=/Forward00a"
+      outContent="Forward00a PASSED" debug="${debug}"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/Forward00?path=/Forward00b"
+      outContent="Forward00b PASSED" debug="${debug}"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/WrappedForward00?path=/Forward00b"
+      outContent="Forward00b PASSED" debug="${debug}"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/Forward00?path=/Forward00c.jsp"
+      outContent="Forward00c PASSED" debug="${debug}"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/WrappedForward00?path=/Forward00c.jsp"
+      outContent="Forward00c PASSED" debug="${debug}"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/Forward00?path=!Forward00d"
+      outContent="Forward00d PASSED" debug="${debug}"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/WrappedForward00?path=!Forward00d"
+      outContent="Forward00d PASSED" debug="${debug}"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/Forward00?path=!Forward00e"
+      outContent="Forward00e PASSED" debug="${debug}"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/WrappedForward00?path=!Forward00e"
+      outContent="Forward00e PASSED" debug="${debug}"/>
+
+    <echo message="----- Basic Include Functionality (flush=false) -----"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/Include00?path=/Include00a&amp;flush=false"
+      outContent="Include00a PASSED" debug="${debug}"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/WrappedInclude00?path=/Include00a&amp;flush=false"
+      outContent="Include00a PASSED" debug="${debug}"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/Include00?path=/Include00b&amp;flush=false"
+      outContent="Include00b PASSED" debug="${debug}"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/WrappedInclude00?path=/Include00b&amp;flush=false"
+      outContent="Include00b PASSED" debug="${debug}"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/Include00?path=/Include00c.jsp&amp;flush=false"
+      outContent="Include00c PASSED" debug="${debug}"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/WrappedInclude00?path=/Include00c.jsp&amp;flush=false"
+      outContent="Include00c PASSED" debug="${debug}"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/Include00?path=!Include00d&amp;flush=false"
+      outContent="Include00d PASSED" debug="${debug}"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/WrappedInclude00?path=!Include00d&amp;flush=false"
+      outContent="Include00d PASSED" debug="${debug}"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/Include00?path=!Include00e&amp;flush=false"
+      outContent="Include00e PASSED" debug="${debug}"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/WrappedInclude00?path=!Include00e&amp;flush=false"
+      outContent="Include00e PASSED" debug="${debug}"/>
+
+    <echo message="----- Basic Include (flush=true, create=true) -----"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/Include00?path=/Include00a&amp;flush=true&amp;create=true"
+      outContent="Include00a PASSED" debug="${debug}"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/WrappedInclude00?path=/Include00a&amp;flush=true&amp;create=true"
+      outContent="Include00a PASSED" debug="${debug}"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/Include00?path=/Include00b&amp;flush=true&amp;create=true"
+      outContent="Include00b PASSED" debug="${debug}"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/WrappedInclude00?path=/Include00b&amp;flush=true&amp;create=true"
+      outContent="Include00b PASSED" debug="${debug}"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/Include00?path=/Include00c.jsp&amp;flush=true&amp;create=true"
+      outContent="Include00c PASSED" debug="${debug}"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/WrappedInclude00?path=/Include00c.jsp&amp;flush=true&amp;create=true"
+      outContent="Include00c PASSED" debug="${debug}"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/Include00?path=!Include00d&amp;flush=true&amp;create=true"
+      outContent="Include00d PASSED" debug="${debug}"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/WrappedInclude00?path=!Include00d&amp;flush=true&amp;create=true"
+      outContent="Include00d PASSED" debug="${debug}"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/Include00?path=!Include00e&amp;flush=true&amp;create=true"
+      outContent="Include00e PASSED" debug="${debug}"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/WrappedInclude00?path=!Include00e&amp;flush=true&amp;create=true"
+      outContent="Include00e PASSED" debug="${debug}"/>
+
+    <echo message="----- Basic Include (flush=true, create=false) -----"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/Include00?path=/Include00a&amp;flush=true&amp;create=false"
+      outContent="Include00a PASSED" debug="${debug}"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/WrappedInclude00?path=/Include00a&amp;flush=true&amp;create=false"
+      outContent="Include00a PASSED" debug="${debug}"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/Include00?path=/Include00b&amp;flush=true&amp;create=false"
+      outContent="Include00b PASSED" debug="${debug}"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/WrappedInclude00?path=/Include00b&amp;flush=true&amp;create=false"
+      outContent="Include00b PASSED" debug="${debug}"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/Include00?path=/Include00c.jsp&amp;flush=true&amp;create=false"
+      outContent="Include00c PASSED" debug="${debug}"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/WrappedInclude00?path=/Include00c.jsp&amp;flush=true&amp;create=false"
+      outContent="Include00c PASSED" debug="${debug}"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/Include00?path=!Include00d&amp;flush=true&amp;create=false"
+      outContent="Include00d PASSED" debug="${debug}"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/WrappedInclude00?path=!Include00d&amp;flush=true&amp;create=false"
+      outContent="Include00d PASSED" debug="${debug}"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/Include00?path=!Include00e&amp;flush=true&amp;create=false"
+      outContent="Include00e PASSED" debug="${debug}"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/WrappedInclude00?path=!Include00e&amp;flush=true&amp;create=false"
+      outContent="Include00e PASSED" debug="${debug}"/>
+
+    <echo message="----- Forward and Include to Static Resource -----"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/Forward01" debug="${debug}"
+      outContent="Forward01 PASSED"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/WrappedForward01" debug="${debug}"
+      outContent="Forward01 PASSED"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/Include01" debug="${debug}"
+      outContent="Include01 PASSED"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/Include01" debug="${debug}"
+       inHeaders="If-modified-since: Mon, 20 Dec 2010 12:12:54 GMT"
+      outContent="Include01 PASSED"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/WrappedInclude01" debug="${debug}"
+      outContent="Include01 PASSED"/>
+
+    <echo message="----- Included Servlet Throwing Exceptions -----"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/Include02?exception=IOException"
+      outContent="Include02 PASSED" debug="${debug}"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/Include02?exception=ServletException"
+      outContent="Include02 PASSED" debug="${debug}"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/Include02?exception=NullPointerException"
+      outContent="Include02 PASSED" debug="${debug}"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/WrappedInclude02?exception=IOException"
+      outContent="Include02 PASSED" debug="${debug}"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/WrappedInclude02?exception=ServletException"
+      outContent="Include02 PASSED" debug="${debug}"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/WrappedInclude02?exception=NullPointerException"
+      outContent="Include02 PASSED" debug="${debug}"/>
+
+    <echo message="----- Forwarded Servlet/Page Sets Attribute -----"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/Forward03?path=/Forward03a"
+      outContent="Forward03 PASSED" debug="${debug}"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/WrappedForward03?path=/Forward03a"
+      outContent="Forward03 PASSED" debug="${debug}"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/Forward03?path=/Forward03b.jsp"
+      outContent="Forward03 PASSED" debug="${debug}"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/WrappedForward03?path=/Forward03b.jsp"
+      outContent="Forward03 PASSED" debug="${debug}"/>
+
+    <echo message="----- Included Servlet/Page Sets Attribute -----"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/Include03?path=/Include03a"
+      outContent="Include03 PASSED" debug="${debug}"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/WrappedInclude03?path=/Include03a"
+      outContent="Include03 PASSED" debug="${debug}"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/Include03?path=/Include03b.jsp"
+      outContent="Include03 PASSED" debug="${debug}"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/WrappedInclude03?path=/Include03b.jsp"
+      outContent="Include03 PASSED" debug="${debug}"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/Include03c.jsp?path=/Include03a"
+      outContent="Include03c.jsp PASSED" debug="${debug}"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/Include03c.jsp?path=/Include03b.jsp"
+      outContent="Include03c.jsp PASSED" debug="${debug}"/>
+
+    <echo message="----- Include Then Forward -----"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/Include04"
+      outContent="Include04b PASSED" debug="${debug}"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/WrappedInclude04"
+      outContent="Include04b PASSED" debug="${debug}"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/Include05.jsp"
+      outContent="Include05b PASSED" debug="${debug}"/>
+
+    <echo message="----- Include Then Include -----"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/Include06.jsp" debug="${debug}"
+          golden="${golden.path}/Include06.txt"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/Include07" debug="${debug}"
+          golden="${golden.path}/Include07.txt"/>
+
+    <echo message="----- Forward Then Forward -----"/>
+
+    <!-- Servlet to Servlet to Servlet -->
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/Forward04"
+      outContent="Forward04b PASSED" debug="${debug}"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/WrappedForward04"
+      outContent="Forward04b PASSED" debug="${debug}"/>
+
+    <!-- JSP to JSP to JSP -->
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/Forward04.jsp"
+      outContent="Forward04b.jsp PASSED" debug="${debug}"/>
+
+    <!-- Servlet to JSP to Servlet -->
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/Forward05"
+      outContent="Forward05b PASSED" debug="${debug}"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/WrappedForward05"
+      outContent="Forward05b PASSED" debug="${debug}"/>
+
+    <!-- JSP to Servlet to JSP -->
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/Forward05.jsp"
+      outContent="Forward05b.jsp PASSED" debug="${debug}"/>
+
+    <!-- Invoker to JSP to Invoker -->
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/servlet/Forward06"
+      outContent="Forward06b PASSED" debug="${debug}"/>
+
+    <!-- JSP to Invoker to JSP -->
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/Forward06.jsp"
+      outContent="Forward06b.jsp PASSED" debug="${debug}"/>
+
+    <!-- Servlet to Invoker to Servlet -->
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/Forward07"
+      outContent="Forward07b PASSED" debug="${debug}"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/WrappedForward07"
+      outContent="Forward07b PASSED" debug="${debug}"/>
+
+    <!-- Invoker to Servlet to Invoker -->
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/servlet/Forward08"
+      outContent="Forward08b PASSED" debug="${debug}"/>
+
+    <echo message="----- ServletRequest.getRequestDispatcher() -----"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/Forward09?path=/Forward00a"
+      outContent="Forward00a PASSED" debug="${debug}"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/WrappedForward09?path=/Forward00a"
+      outContent="Forward00a PASSED" debug="${debug}"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/Forward09?path=/Forward00b"
+      outContent="Forward00b PASSED" debug="${debug}"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/WrappedForward09?path=/Forward00b"
+      outContent="Forward00b PASSED" debug="${debug}"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/Forward09?path=/Forward00c.jsp"
+      outContent="Forward00c PASSED" debug="${debug}"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/WrappedForward09?path=/Forward00c.jsp"
+      outContent="Forward00c PASSED" debug="${debug}"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/Forward09?path=Forward00a"
+      outContent="Forward00a PASSED" debug="${debug}"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/WrappedForward09?path=Forward00a"
+      outContent="Forward00a PASSED" debug="${debug}"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/Forward09?path=Forward00b"
+      outContent="Forward00b PASSED" debug="${debug}"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/WrappedForward09?path=Forward00b"
+      outContent="Forward00b PASSED" debug="${debug}"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/Forward09?path=Forward00c.jsp"
+      outContent="Forward00c PASSED" debug="${debug}"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/WrappedForward09?path=Forward00c.jsp"
+      outContent="Forward00c PASSED" debug="${debug}"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/Include09?path=/Include00a"
+      outContent="Include00a PASSED" debug="${debug}"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/WrappedInclude09?path=/Include00a"
+      outContent="Include00a PASSED" debug="${debug}"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/Include09?path=/Include00b"
+      outContent="Include00b PASSED" debug="${debug}"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/WrappedInclude09?path=/Include00b"
+      outContent="Include00b PASSED" debug="${debug}"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/Include09?path=/Include00c.jsp"
+      outContent="Include00c PASSED" debug="${debug}"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/WrappedInclude09?path=/Include00c.jsp"
+      outContent="Include00c PASSED" debug="${debug}"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/Include09?path=Include00a"
+      outContent="Include00a PASSED" debug="${debug}"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/WrappedInclude09?path=Include00a"
+      outContent="Include00a PASSED" debug="${debug}"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/Include09?path=Include00b"
+      outContent="Include00b PASSED" debug="${debug}"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/WrappedInclude09?path=Include00b"
+      outContent="Include00b PASSED" debug="${debug}"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/Include09?path=Include00c.jsp"
+      outContent="Include00c PASSED" debug="${debug}"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/WrappedInclude09?path=Include00c.jsp"
+      outContent="Include00c PASSED" debug="${debug}"/>
+
+    <echo message="----- Container-Created Include Attributes -----"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/Include10/extra/path?name1=value1"
+      outContent="Include10a PASSED" debug="${debug}"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/WrappedInclude10/extra/path?name1=value1"
+      outContent="Include10a PASSED" debug="${debug}"/>
+
+    <echo message="----- Response Wrapping -----"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/ResponseWrap01?type=F&amp;page=/ResponseWrap01a"
+      outContent="RESPONSEWRAP01A PASSED" debug="${debug}" />
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/ResponseWrap01?type=F&amp;page=/ResponseWrap01b.jsp"
+      outContent="RESPONSEWRAP01B PASSED" debug="${debug}" />
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/ResponseWrap01?type=I&amp;page=/ResponseWrap01c"
+      outContent="RESPONSEWRAP01C PASSED" debug="${debug}" />
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/ResponseWrap01?type=I&amp;page=/ResponseWrap01d.jsp"
+      outContent="RESPONSEWRAP01D PASSED" debug="${debug}" />
+
+  </target>
+
+
+  <target name="Resources">
+
+    <!-- ========== Positive ServletContext.getResource() Tests =========== -->
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+           debug="${debug}"
+         request="${context.path}/Resources01?mode=context&amp;path=/WEB-INF/web.xml"
+      outContent="Resources01 PASSED"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+           debug="${debug}"
+         request="${context.path}/Resources01?mode=context&amp;path=/Forward01.txt"
+      outContent="Resources01 PASSED"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+           debug="${debug}"
+         request="${context.path}/Resources01?mode=context&amp;path=/Include01.txt"
+      outContent="Resources01 PASSED"/>
+
+    <!-- ========== Positive Class.getResource() Tests ==================== -->
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+           debug="${debug}"
+         request="${context.path}/Resources01?mode=class&amp;path=/org/apache/tester/Resources01.txt"
+      outContent="Resources01 PASSED"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+           debug="${debug}"
+         request="${context.path}/Resources01?mode=class&amp;path=/org/apache/tester/Unpacked01.txt"
+      outContent="Resources01 PASSED"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+           debug="${debug}"
+         request="${context.path}/Resources01?mode=class&amp;path=/org/apache/tester/shared/Shared01.txt"
+      outContent="Resources01 PASSED"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+           debug="${debug}"
+         request="${context.path}/Resources01?mode=class&amp;path=/org/apache/tester/unpshared/UnpShared01.txt"
+      outContent="Resources01 PASSED"/>
+
+    <!-- ========== Negative ServletContext.getResource() Tests =========== -->
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+           debug="${debug}"
+         request="${context.path}/Resources02?mode=context&amp;path=/WEB-INF/web.xml.bad"
+      outContent="Resources02 PASSED"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+           debug="${debug}"
+         request="${context.path}/Resources02?mode=context&amp;path=/Forward02.txt.bad"
+      outContent="Resources02 PASSED"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+           debug="${debug}"
+         request="${context.path}/Resources02?mode=context&amp;path=/Include02.txt.bad"
+      outContent="Resources02 PASSED"/>
+
+    <!-- ========== Negative Class.getResource() Tests ==================== -->
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+           debug="${debug}"
+         request="${context.path}/Resources02?mode=class&amp;path=/org/apache/tester/Resources02.txt.bad"
+      outContent="Resources02 PASSED"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+           debug="${debug}"
+         request="${context.path}/Resources02?mode=class&amp;path=/org/apache/tester/Unpacked02.txt.bad"
+      outContent="Resources02 PASSED"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+           debug="${debug}"
+         request="${context.path}/Resources02?mode=class&amp;path=/org/apache/tester/shared/Shared01.txt.bad"
+      outContent="Resources02 PASSED"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+           debug="${debug}"
+         request="${context.path}/Resources02?mode=class&amp;path=/org/apache/tester/unpshared/UnpShared01.txt.bad"
+      outContent="Resources02 PASSED"/>
+
+    <!-- ========== Positive ServletContext.getResourceAsStream() Tests === -->
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+           debug="${debug}"
+         request="${context.path}/Resources03?mode=context&amp;path=/WEB-INF/web.xml"
+      outContent="&lt;?xml version=&quot;1.0&quot; encoding=&quot;ISO-8859-1&quot;?&gt;"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+           debug="${debug}"
+         request="${context.path}/Resources03?mode=context&amp;path=/Forward01.txt"
+      outContent="Forward01 PASSED"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+           debug="${debug}"
+         request="${context.path}/Resources03?mode=context&amp;path=/Include01.txt"
+      outContent="Include01 PASSED"/>
+
+    <!-- ========== Positive Class.getResourceAsStream() Tests ============ -->
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+           debug="${debug}"
+         request="${context.path}/Resources03?mode=class&amp;path=/org/apache/tester/Resources03.txt"
+      outContent="Resources03 PASSED"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+           debug="${debug}"
+         request="${context.path}/Resources03?mode=class&amp;path=/org/apache/tester/Unpacked03.txt"
+      outContent="Resources03 PASSED"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+           debug="${debug}"
+         request="${context.path}/Resources03?mode=class&amp;path=/org/apache/tester/shared/Shared03.txt"
+      outContent="Resources03 PASSED"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+           debug="${debug}"
+         request="${context.path}/Resources03?mode=class&amp;path=/org/apache/tester/unpshared/UnpShared03.txt"
+      outContent="Resources03 PASSED"/>
+
+    <!-- ========== Negative ServletContext.getResourceAsStream() Tests === -->
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+           debug="${debug}"
+         request="${context.path}/Resources04?mode=context&amp;path=/WEB-INF/web.xml.bad"
+      outContent="Resources04 PASSED"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+           debug="${debug}"
+         request="${context.path}/Resources04?mode=context&amp;path=/Forward04.txt.bad"
+      outContent="Resources04 PASSED"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+           debug="${debug}"
+         request="${context.path}/Resources04?mode=context&amp;path=/Include04.txt.bad"
+      outContent="Resources04 PASSED"/>
+
+    <!-- ========== Negative Class.getResourceAsStream() Tests ============ -->
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+           debug="${debug}"
+         request="${context.path}/Resources04?mode=class&amp;path=/org/apache/tester/Resources04.txt.bad"
+      outContent="Resources04 PASSED"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+           debug="${debug}"
+         request="${context.path}/Resources04?mode=class&amp;path=/org/apache/tester/Unpacked04.txt.bad"
+      outContent="Resources04 PASSED"/>
+
+    <!-- ========== Positive Combined getResource/Open Tests ============== -->
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+           debug="${debug}"
+         request="${context.path}/Resources05?mode=context&amp;path=/WEB-INF/web.xml"
+      outContent="&lt;?xml version=&quot;1.0&quot; encoding=&quot;ISO-8859-1&quot;?&gt;"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+           debug="${debug}"
+         request="${context.path}/Resources05?mode=context&amp;path=/Forward01.txt"
+      outContent="Forward01 PASSED"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+           debug="${debug}"
+         request="${context.path}/Resources05?mode=context&amp;path=/Include01.txt"
+      outContent="Include01 PASSED"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+           debug="${debug}"
+         request="${context.path}/Resources05?mode=class&amp;path=/org/apache/tester/Resources05.txt"
+      outContent="Resources05 PASSED"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+           debug="${debug}"
+         request="${context.path}/Resources05?mode=class&amp;path=/org/apache/tester/Unpacked05.txt"
+      outContent="Resources05 PASSED"/>
+
+    <!-- ========== Positive Combined getResource/Open/Stringify Tests ==== -->
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+           debug="${debug}"
+         request="${context.path}/Resources05?mode=context&amp;path=/WEB-INF/web.xml&amp;stringify=true"
+      outContent="&lt;?xml version=&quot;1.0&quot; encoding=&quot;ISO-8859-1&quot;?&gt;"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+           debug="${debug}"
+         request="${context.path}/Resources05?mode=context&amp;path=/Forward01.txt&amp;stringify=true"
+      outContent="Forward01 PASSED"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+           debug="${debug}"
+         request="${context.path}/Resources05?mode=context&amp;path=/Include01.txt&amp;stringify=true"
+      outContent="Include01 PASSED"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+           debug="${debug}"
+         request="${context.path}/Resources05?mode=class&amp;path=/org/apache/tester/Resources05.txt&amp;stringify=true"
+      outContent="Resources05 PASSED"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+           debug="${debug}"
+         request="${context.path}/Resources05?mode=class&amp;path=/org/apache/tester/Unpacked05.txt&amp;stringify=true"
+      outContent="Resources05 PASSED"/>
+
+    <!-- ========== getResourcePaths() ==================================== -->
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+           debug="${debug}"
+         request="${context.path}/Resources06?path=/"
+      outContent="Resources06 PASSED"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+           debug="${debug}"
+         request="${context.path}/Resources06?path=/golden"
+      outContent="Resources06 PASSED"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+           debug="${debug}"
+         request="${context.path}/Resources06?path=/WEB-INF"
+      outContent="Resources06 PASSED"/>
+
+  </target>
+
+
+  <target name="Security">
+
+    <!-- ========== Security Tests ======================================== -->
+
+    <!-- Should not be able to use relative path above document root -->
+    <tester host="${host}" port="${port}" protocol="HTTP/1.0"
+         request="${jsp-examples.path}/../.." debug="${debug}"
+          status="400"/>
+
+    <!-- Should not be able to use specially crafted URLs to get around 
+         security constraints -->
+    <tester host="${host}" port="${port}" protocol="HTTP/1.0"
+         request="/tester//./protected//Authentication01" 
+         debug="${debug}" status="401"/>
+
+    <!-- DefaultServlet should not decode the path again -->
+    <tester host="${host}" port="${port}" protocol="HTTP/1.0"
+         request="${jsp-examples.path}/snp/snoop%252ejsp"
+          status="404"/>
+
+  </target>
+
+
+  <target name="ServletContext">
+
+    <!-- ========== Servlet Context Attributes ============================ -->
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+           debug="${debug}"
+         request="${context.path}/Context00"
+      outContent="Context00 PASSED"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+           debug="${debug}"
+         request="${context.path}/Context01"
+      outContent="Context01 PASSED"/>
+
+    <!-- NOTE: Assign role "manager" to user "tomcat" for this to work -->
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+           debug="${debug}"
+       inHeaders="Authorization:Basic dG9tY2F0OnRvbWNhdA=="
+         request="${manager.path}/reload?path=${reload.path}"
+      outContent="OK - "/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+           debug="${debug}"
+         request="${context.path}/Context02"
+      outContent="Context02 PASSED"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+           debug="${debug}"
+         request="${context.path}/WrappedContext00"
+      outContent="Context00 PASSED"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+           debug="${debug}"
+         request="${context.path}/WrappedContext01"
+      outContent="Context01 PASSED"/>
+
+    <!-- NOTE: Assign role "manager" to user "tomcat" for this to work -->
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+           debug="${debug}"
+       inHeaders="Authorization:Basic dG9tY2F0OnRvbWNhdA=="
+         request="${manager.path}/reload?path=${reload.path}"
+      outContent="OK - "/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+           debug="${debug}"
+         request="${context.path}/WrappedContext02"
+      outContent="Context02 PASSED"/>
+
+  </target>
+
+
+  <target name="ServletRequest">
+
+    <!-- ========== Parameters and Query Strings ========================== -->
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/GetParameter01?foo=1" debug="${debug}"
+      outContent="GetParameter01 PASSED"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/WrappedGetParameter01?foo=1" debug="${debug}"
+      outContent="GetParameter01 PASSED"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/GetParameterMap00?BestLanguage=Java&amp;BestJSP=Java2"
+      outContent="GetParameterMap00 PASSED" debug="${debug}"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/WrappedGetParameterMap00?BestLanguage=Java&amp;BestJSP=Java2"
+      outContent="GetParameterMap00 PASSED" debug="${debug}"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/GetQueryString01?foo=1"
+      outContent="GetQueryString01 PASSED" debug="${debug}"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/WrappedGetQueryString01?foo=1"
+      outContent="GetQueryString01 PASSED" debug="${debug}"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+           debug="${debug}" method="POST"
+       inHeaders="Content-Type:application/x-www-form-urlencoded"
+       inContent="b=3&amp;a=2"
+         request="${context.path}/Aggregate01?a=1"
+      outContent="Aggregate01 PASSED"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+           debug="${debug}" method="POST"
+       inHeaders="Content-Type:application/x-www-form-urlencoded"
+       inContent="b=3&amp;a=2"
+         request="${context.path}/WrappedAggregate01?a=1"
+      outContent="Aggregate01 PASSED"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+           debug="${debug}" method="POST"
+       inHeaders="Content-Type:application/x-www-form-urlencoded"
+       inContent="b=3&amp;a=2"
+         request="${context.path}/Aggregate02?a=1"
+      outContent="Aggregate02 PASSED"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+           debug="${debug}" method="POST"
+       inHeaders="Content-Type:application/x-www-form-urlencoded"
+       inContent="b=3&amp;a=2"
+         request="${context.path}/WrappedAggregate02?a=1"
+      outContent="Aggregate02 PASSED"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+           debug="${debug}"
+         request="${context.path}/Request01"
+      outContent="Request01 PASSED"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+           debug="${debug}"
+         request="${context.path}/WrappedRequest01"
+      outContent="Request01 PASSED"/>
+
+    <!-- ========== Other ServletRequest Tests ============================ -->
+
+    <!-- HttpURLConnection does not handle multiple headers for the same
+         name correctly, so use native socket connections, selected by
+         setting the protocol to "HTTP/1.0" -->
+
+    <tester host="${host}" port="${port}" protocol="HTTP/1.0"
+         request="${context.path}/GetHeaders01" debug="${debug}"
+       inHeaders="Accept-Language:en-us##Accept-Language:en-gb"
+      outContent="GetHeaders01 PASSED"/>
+
+    <tester host="${host}" port="${port}" protocol="HTTP/1.0"
+         request="${context.path}/WrappedGetHeaders01" debug="${debug}"
+       inHeaders="Accept-Language:en-us##Accept-Language:en-gb"
+      outContent="GetHeaders01 PASSED"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/GetInputStream01" debug="${debug}"
+      outContent="GetInputStream01 PASSED"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/WrappedGetInputStream01" debug="${debug}"
+      outContent="GetInputStream01 PASSED"/>
+
+    <tester host="${host}" port="${port}" protocol="HTTP/1.0"
+         request="${context.path}/GetLocales01" debug="${debug}"
+       inHeaders="Accept-Language:en-ca##Accept-Language:en-gb"
+      outContent="GetLocales01 PASSED"/>
+
+    <tester host="${host}" port="${port}" protocol="HTTP/1.0"
+         request="${context.path}/WrappedGetLocales01" debug="${debug}"
+       inHeaders="Accept-Language:en-ca##Accept-Language:en-gb"
+      outContent="GetLocales01 PASSED"/>
+
+    <tester host="${host}" port="${port}" protocol="HTTP/1.0"
+         request="${context.path}/GetLocales01" debug="${debug}"
+       inHeaders="Accept-Language:en-ca,en-gb"
+      outContent="GetLocales01 PASSED"/>
+
+    <tester host="${host}" port="${port}" protocol="HTTP/1.0"
+         request="${context.path}/WrappedGetLocales01" debug="${debug}"
+       inHeaders="Accept-Language:en-ca,en-gb"
+      outContent="GetLocales01 PASSED"/>
+
+    <tester host="${host}" port="${port}" protocol="HTTP/1.0"
+         request="${context.path}/GetLocales02" debug="${debug}"
+       inHeaders="Accept-Language:en-ca##Accept-Language:en-gb"
+      outContent="GetLocales02 PASSED"/>
+
+    <tester host="${host}" port="${port}" protocol="HTTP/1.0"
+         request="${context.path}/WrappedGetLocales02" debug="${debug}"
+       inHeaders="Accept-Language:en-ca##Accept-Language:en-gb"
+      outContent="GetLocales02 PASSED"/>
+
+    <tester host="${host}" port="${port}" protocol="HTTP/1.0"
+         request="${context.path}/GetLocales02" debug="${debug}"
+       inHeaders="Accept-Language:en-ca,en-gb"
+      outContent="GetLocales02 PASSED"/>
+
+    <tester host="${host}" port="${port}" protocol="HTTP/1.0"
+         request="${context.path}/WrappedGetLocales02" debug="${debug}"
+       inHeaders="Accept-Language:en-ca,en-gb"
+      outContent="GetLocales02 PASSED"/>
+
+  </target>
+
+
+  <target name="ServletResponse">
+
+
+    <!-- ========== Other ServletResponse Tests =========================== -->
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/Reset01" debug="${debug}"
+      outContent="Reset01 PASSED"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/WrappedReset01" debug="${debug}"
+      outContent="Reset01 PASSED"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/SetBufferSize01" debug="${debug}"
+      outContent="SetBufferSize01 PASSED"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/WrappedSetBufferSize01" debug="${debug}"
+      outContent="SetBufferSize01 PASSED"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/SetLocale01" debug="${debug}"
+      outContent="SetLocale01 PASSED"
+      outHeaders="Content-Language:en-US"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/WrappedSetLocale01" debug="${debug}"
+      outContent="SetLocale01 PASSED"
+      outHeaders="Content-Language:en-US"/>
+
+
+    <!-- ========== SendRedirect Handling ================================= -->
+
+    <!-- Also check debug output to make sure no extra content was included -->
+    <tester host="${host}" port="${port}" protocol=""
+         request="${context.path}/Redirect01" debug="${debug}"
+      outContent=""
+          status="302" redirect="false"/>
+
+    <tester host="${host}" port="${port}" protocol=""
+         request="${context.path}/Redirect01" debug="${debug}"
+      outContent="Redirect01a PASSED" redirect="true"/>
+
+    <tester host="${host}" port="${port}" protocol=""
+         request="${context.path}/WrappedRedirect01" debug="${debug}"
+      outContent="Redirect01a PASSED" redirect="true"/>
+
+    <!-- JSP page includes "return" after redirect -->
+    <tester host="${host}" port="${port}" protocol=""
+         request="${context.path}/Redirect02.jsp" debug="${debug}"
+      outContent="Redirect02a.jsp PASSED" redirect="true"/>
+
+    <!-- Same as "Redirect02.jsp" except without the "return" -->
+    <tester host="${host}" port="${port}" protocol=""
+         request="${context.path}/Redirect03.jsp" debug="${debug}"
+      outContent="Redirect03a.jsp PASSED" redirect="true"/>
+
+  </target>
+
+
+  <target name="HttpSession">
+
+    <!-- ========== Session Attribute Persistence ========================= -->
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/Session01" debug="${debug}"
+      outContent="Session01 PASSED"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/Session02" debug="${debug}"
+     joinSession="true"
+      outContent="Session02 PASSED"/>
+
+    <!-- NOTE: Assign role "manager" to user "tomcat" for this to work -->
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+           debug="${debug}"
+       inHeaders="Authorization:Basic dG9tY2F0OnRvbWNhdA=="
+         request="${manager.path}/reload?path=${reload.path}"
+      outContent="OK - "/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/Session03" debug="${debug}"
+     joinSession="true"
+      outContent="Session03 PASSED"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/Session04" debug="${debug}"
+     joinSession="true"
+      outContent="Session04 PASSED"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/WrappedSession01" debug="${debug}"
+      outContent="Session01 PASSED"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/WrappedSession02" debug="${debug}"
+     joinSession="true"
+      outContent="Session02 PASSED"/>
+
+    <!-- NOTE: Assign role "manager" to user "tomcat" for this to work -->
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+           debug="${debug}"
+       inHeaders="Authorization:Basic dG9tY2F0OnRvbWNhdA=="
+         request="${manager.path}/reload?path=${reload.path}"
+      outContent="OK - "/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/WrappedSession03" debug="${debug}"
+     joinSession="true"
+      outContent="Session03 PASSED"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/WrappedSession04" debug="${debug}"
+     joinSession="true"
+      outContent="Session04 PASSED"/>
+
+    <!-- Exercise session event listeners -->
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/Session05" debug="${debug}"
+          golden="${golden.path}/Session05.txt"/>
+
+    <!-- Exercise session event listeners -->
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/WrappedSession05" debug="${debug}"
+          golden="${golden.path}/WrappedSession05.txt"/>
+
+    <!-- Session creation after response has been committed -->
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/Session06" debug="${debug}"
+      outContent="Session06 PASSED"/>
+
+    <!-- Session creation after response has been committed -->
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/WrappedSession06" debug="${debug}"
+      outContent="Session06 PASSED"/>
+
+    <!-- ========== Pass Attributes Across Redirect ======================= -->
+
+    <!-- Session maintained across redirect -->
+    <!-- NOTE:  The following two-step pattern is required because
+         HttpURLConnection does not forward the session cookie it
+         receives on to the redirected location (the way that a
+         browser will do so) -->
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/Session07a.jsp" debug="${debug}"
+          status="302"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/Session07b.jsp" debug="${debug}"
+     joinSession="true"
+      outContent="Session07 PASSED"/>
+
+  </target>
+
+
+  <target name="XercesTest">
+
+    <!-- ========== Xerces Sealing Violation Test ========================= -->
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/Xerces00.jsp" debug="${debug}"
+      outContent="Xerces00 PASSED"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/Xerces00" debug="${debug}"
+      outContent="Xerces00 PASSED"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/WrappedXerces00" debug="${debug}"
+      outContent="Xerces00 PASSED"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/Xerces01" debug="${debug}"
+      outContent="Xerces01 PASSED"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/WrappedXerces01" debug="${debug}"
+      outContent="Xerces01 PASSED"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/Xerces02.jsp" debug="${debug}"
+      outContent="Xerces02 PASSED"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/Xerces02" debug="${debug}"
+      outContent="Xerces02 PASSED"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/WrappedXerces02" debug="${debug}"
+      outContent="Xerces02 PASSED"/>
+
+  </target>
+
+<!--
+<target name="SSITest">
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/SSIInclude01.shtml" debug="${debug}"
+          golden="${golden.path}/SSIInclude01.txt"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/SSIInclude02.shtml" debug="${debug}"
+          golden="${golden.path}/SSIInclude02.txt"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/SSIInclude03.shtml" debug="${debug}"
+          golden="${golden.path}/SSIInclude02.txt"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/SSIInclude04.shtml" debug="${debug}"
+          golden="${golden.path}/SSIInclude02.txt"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/SSIInclude05.shtml" debug="${debug}"
+          golden="${golden.path}/SSIInclude02.txt"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/SSIInclude06.shtml" debug="${debug}"
+          golden="${golden.path}/SSIInclude02.txt"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/SSIInclude07.shtml" debug="${debug}"
+          golden="${golden.path}/SSIInclude02.txt"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/SSIInclude08.shtml" debug="${debug}"
+          golden="${golden.path}/SSIInclude02.txt"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/SSIInclude09.shtml" debug="${debug}"
+          golden="${golden.path}/SSIInclude03.txt"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/SSIConfig01.shtml" debug="${debug}"
+          golden="${golden.path}/SSIConfig01.txt"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/SSIConfig03.shtml" debug="${debug}"
+          golden="${golden.path}/SSIConfig03.txt"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/SSIFsize01.shtml" debug="${debug}"
+          golden="${golden.path}/SSIInclude01.txt"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/SSIFsize02.shtml" debug="${debug}"
+          golden="${golden.path}/SSIFsize02.txt"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/SSIFsize03.shtml" debug="${debug}"
+          golden="${golden.path}/SSIFsize02.txt"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/SSIFsize04.shtml" debug="${debug}"
+          golden="${golden.path}/SSIFsize02.txt"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/SSIFsize05.shtml" debug="${debug}"
+          golden="${golden.path}/SSIFsize02.txt"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/SSIFsize06.shtml" debug="${debug}"
+          golden="${golden.path}/SSIFsize02.txt"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/SSIFsize07.shtml" debug="${debug}"
+          golden="${golden.path}/SSIFsize02.txt"/>
+
+    <tester host="${host}" port="${port}" protocol="${protocol}"
+         request="${context.path}/SSIFsize08.shtml" debug="${debug}"
+          golden="${golden.path}/SSIFsize02.txt"/>
+
+  </target>
+-->
+
+<!--
+  <target name="CGITest">
+
+  <tester host="${host}" port="${port}" protocol="${protocol}"
+        request="${context.path}/cgi-bin/array.pl" debug="${debug}"
+        golden="${golden.path}/array.txt"/>
+
+  <tester host="${host}" port="${port}" protocol="${protocol}"
+        request="${context.path}/cgi-bin/binary.pl?counter=102" debug="${debug}"
+        golden="${golden.path}/binary.txt"/>
+
+  <tester host="${host}" port="${port}" protocol="${protocol}"
+        request="${context.path}/cgi-bin/concat.pl?first_name=jane&amp;last_name=johnson&amp;fiance_first=john&amp;fiance_last=smith" debug="${debug}"
+        golden="${golden.path}/concat.txt"/>
+
+  <tester host="${host}" port="${port}" protocol="${protocol}"
+        request="${context.path}/cgi-bin/days.pl" debug="${debug}"
+        golden="${golden.path}/days.txt"/>
+
+  <tester host="${host}" port="${port}" protocol="${protocol}"
+        request="${context.path}/cgi-bin/dowhile.pl?start=10" debug="${debug}"
+        golden="${golden.path}/dowhile.txt"/>
+
+  <tester host="${host}" port="${port}" protocol="${protocol}"
+        request="${context.path}/cgi-bin/else.pl?food=spinach" debug="${debug}"
+        golden="${golden.path}/else.txt"/>
+
+  <tester host="${host}" port="${port}" protocol="${protocol}"
+        request="${context.path}/cgi-bin/elsif.pl?food=chocolate" debug="${debug}"
+        golden="${golden.path}/elsif.txt"/>
+
+  <tester host="${host}" port="${port}" protocol="${protocol}"
+        request="${context.path}/cgi-bin/exponents.pl?number=2&amp;power=4" debug="${debug}"
+        golden="${golden.path}/exponents.txt"/>
+
+  <tester host="${host}" port="${port}" protocol="${protocol}"
+        request="${context.path}/cgi-bin/for.pl?start=10" debug="${debug}"
+        golden="${golden.path}/dowhile.txt"/>
+
+  <tester host="${host}" port="${port}" protocol="${protocol}"
+        request="${context.path}/cgi-bin/getday.pl" debug="${debug}"
+        golden="${golden.path}/getday.txt"/>
+
+  <tester host="${host}" port="${port}" protocol="${protocol}"
+        request="${context.path}/cgi-bin/helloperl.pl" debug="${debug}"
+        golden="${golden.path}/helloperl.txt"/>
+
+  <tester host="${host}" port="${port}" protocol="${protocol}"
+        request="${context.path}/cgi-bin/if.pl?food=spinach" debug="${debug}"
+        golden="${golden.path}/else.txt"/>
+
+  <tester host="${host}" port="${port}" protocol="${protocol}"
+        request="${context.path}/cgi-bin/increment.pl?counter=7" debug="${debug}"
+        golden="${golden.path}/increment.txt"/>
+
+  <tester host="${host}" port="${port}" protocol="${protocol}"
+        request="${context.path}/cgi-bin/modifyall.pl?number=289" debug="${debug}"
+        golden="${golden.path}/modifyall.txt"/>
+
+  </target>
+-->
+
+</project>

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/src/conf/tomcat-users.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/src/conf/tomcat-users.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/src/conf/tomcat-users.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,8 @@
+<?xml version='1.0' encoding='utf-8'?>
+<tomcat-users>
+  <role rolename="tomcat"/>
+  <role rolename="role1"/>
+  <user username="tomcat" password="tomcat" roles="tomcat,admin,manager"/>
+  <user username="role1" password="tomcat" roles="role1"/>
+  <user username="both" password="tomcat" roles="tomcat,role1"/>
+</tomcat-users>

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Aggregate01.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Aggregate01.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Aggregate01.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,96 @@
+/*
+ * Copyright 1999, 2000, 2001 ,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tester;
+
+
+import java.io.*;
+import java.util.Enumeration;
+import javax.servlet.*;
+import javax.servlet.http.*;
+
+/**
+ * Test aggregation of query string and POST parameters.  According to
+ * Servlet 2.4 PFD, Section 4.1, all such parameters should be aggregated,
+ * and if there are duplicate parameter names from both sources, the
+ * parameter value(s) from the query string should appear first in the
+ * values returned by request.getParameterValues().
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class Aggregate01 extends HttpServlet {
+
+    public void doPost(HttpServletRequest request, HttpServletResponse response)
+        throws IOException, ServletException {
+
+        response.setContentType("text/plain");
+        PrintWriter writer = response.getWriter();
+
+        // Accumulate any errors that are noticed
+        StringBuffer errors = new StringBuffer();
+        String values[] = request.getParameterValues("a");
+        if (values == null)
+            errors.append("  Received no parameter values for 'a'.");
+        else if (values.length != 2)
+            errors.append("  Received " + values.length +
+                          " parameter values for 'a' instead of 2.");
+        else {
+            if (!"1".equals(values[0]))
+                errors.append("  First value for 'a' was '" + values[0] +
+                              "' instead of '1'.");
+            if (!"2".equals(values[1]))
+                errors.append("  Second value for 'a' was '" + values[1] +
+                              "' instead of '2'.");
+        }
+        values = request.getParameterValues("b");
+        if (values == null)
+            errors.append("  Received no parameter values for 'b'.");
+        else if (values.length != 1)
+            errors.append("  Received " + values.length +
+                          " parameter values for 'b' instead of 1.");
+        else {
+            if (!"3".equals(values[0]))
+                errors.append("  Value for 'b' was '" + values[0] +
+                              "' instead of '3'.");
+        }
+        Enumeration names = request.getParameterNames();
+        while (names.hasMoreElements()) {
+            String name = (String) names.nextElement();
+            if ("a".equals(name))
+                continue;
+            if ("b".equals(name))
+                continue;
+            errors.append("  Received parameter '" + name + "'.");
+        }
+
+        // Report the results
+        if (errors.length() < 1)
+            writer.println("Aggregate01 PASSED");
+        else
+            writer.println("Aggregate01 FAILED -" + errors.toString());
+        while (true) {
+            String message = StaticLogger.read();
+            if (message == null)
+                break;
+            writer.println(message);
+        }
+        StaticLogger.reset();
+
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Aggregate02.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Aggregate02.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Aggregate02.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,106 @@
+/*
+ * Copyright 1999, 2000, 2001 ,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tester;
+
+
+import java.io.*;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import javax.servlet.*;
+import javax.servlet.http.*;
+
+/**
+ * Test aggregation of query string and POST parameters.  According to
+ * Servlet 2.4 PFD, Section 4.1, all such parameters should be aggregated,
+ * and if there are duplicate parameter names from both sources, the
+ * parameter value(s) from the query string should appear first in the
+ * values returned by request.getParameterValues().
+ * <p>
+ * This test is the same as Aggregate01, except that it uses the new
+ * <code>getParameterMap()</code> method to retrieve parameter values.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class Aggregate02 extends HttpServlet {
+
+    public void doPost(HttpServletRequest request, HttpServletResponse response)
+        throws IOException, ServletException {
+
+        response.setContentType("text/plain");
+        PrintWriter writer = response.getWriter();
+
+        // Accumulate any errors that are noticed
+        StringBuffer errors = new StringBuffer();
+        Map map = request.getParameterMap();
+        if (map == null) {
+            errors.append("  No parameter map returned.");
+            map = new HashMap();
+        }
+        String values[] = (String[]) map.get("a");
+        if (values == null)
+            errors.append("  Received no parameter values for 'a'.");
+        else if (values.length != 2)
+            errors.append("  Received " + values.length +
+                          " parameter values for 'a' instead of 2.");
+        else {
+            if (!"1".equals(values[0]))
+                errors.append("  First value for 'a' was '" + values[0] +
+                              "' instead of '1'.");
+            if (!"2".equals(values[1]))
+                errors.append("  Second value for 'a' was '" + values[1] +
+                              "' instead of '2'.");
+        }
+        values = (String[]) map.get("b");
+        if (values == null)
+            errors.append("  Received no parameter values for 'b'.");
+        else if (values.length != 1)
+            errors.append("  Received " + values.length +
+                          " parameter values for 'b' instead of 1.");
+        else {
+            if (!"3".equals(values[0]))
+                errors.append("  Value for 'b' was '" + values[0] +
+                              "' instead of '3'.");
+        }
+        Iterator names = map.keySet().iterator();
+        while (names.hasNext()) {
+            String name = (String) names.next();
+            if ("a".equals(name))
+                continue;
+            if ("b".equals(name))
+                continue;
+            errors.append("  Received parameter '" + name + "'.");
+        }
+
+        // Report the results
+        if (errors.length() < 1)
+            writer.println("Aggregate02 PASSED");
+        else
+            writer.println("Aggregate02 FAILED -" + errors.toString());
+        while (true) {
+            String message = StaticLogger.read();
+            if (message == null)
+                break;
+            writer.println(message);
+        }
+        StaticLogger.reset();
+
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Authentication01.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Authentication01.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Authentication01.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,64 @@
+/*
+ * Copyright 1999, 2000 ,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tester;
+
+
+import java.io.*;
+import java.security.Principal;
+import javax.servlet.*;
+import javax.servlet.http.*;
+
+/**
+ * Ensure that the "tomcat" user has been successfully authenticated.  This
+ * should be guaranteed by the fact that this URI is protected by a security
+ * constraint in the deployment descriptor.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class Authentication01 extends HttpServlet {
+
+    public void doGet(HttpServletRequest request, HttpServletResponse response)
+        throws IOException, ServletException {
+
+        response.setContentType("text/plain");
+        PrintWriter writer = response.getWriter();
+        String remoteUser = request.getRemoteUser();
+        Principal userPrincipal = request.getUserPrincipal();
+        String errors = "";
+        if (remoteUser == null)
+            errors += "  getRemoteUser() returned NULL.";
+        else if (!remoteUser.equals("tomcat"))
+            errors += "  remoteUser=" + remoteUser + ".";
+        if (userPrincipal == null)
+            errors += "  getUserPrincpal() returned NULL.";
+        else if (!userPrincipal.getName().equals("tomcat"))
+            errors += "  userPrincipal=" + userPrincipal.getName() + ".";
+        if ((remoteUser != null) &&
+            (userPrincipal != null) &&
+            !remoteUser.equals(userPrincipal.getName()))
+            errors += "  remoteUser=" + remoteUser + " userPrincipal=" +
+                userPrincipal.getName();
+        if (errors.length() > 0)
+            writer.println("Authentication01 FAILED:" + errors);
+        else
+            writer.println("Authentication01 PASSED");
+
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Authentication02.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Authentication02.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Authentication02.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,64 @@
+/*
+ * Copyright 1999, 2000 ,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tester;
+
+
+import java.io.*;
+import java.security.Principal;
+import javax.servlet.*;
+import javax.servlet.http.*;
+
+/**
+ * Ensure that the "tomcat" user has been successfully authenticated.  Although
+ * this URI is not protected by a security constraint, the test client will
+ * have authenticated a user previously by calling "/Authentication01".
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class Authentication02 extends HttpServlet {
+
+    public void doGet(HttpServletRequest request, HttpServletResponse response)
+        throws IOException, ServletException {
+
+        response.setContentType("text/plain");
+        PrintWriter writer = response.getWriter();
+        String remoteUser = request.getRemoteUser();
+        Principal userPrincipal = request.getUserPrincipal();
+        String errors = "";
+        if (remoteUser == null)
+            errors += "  getRemoteUser() returned NULL.";
+        else if (!remoteUser.equals("tomcat"))
+            errors += "  remoteUser=" + remoteUser + ".";
+        if (userPrincipal == null)
+            errors += "  getUserPrincpal() returned NULL.";
+        else if (!userPrincipal.getName().equals("tomcat"))
+            errors += "  userPrincipal=" + userPrincipal.getName() + ".";
+        if ((remoteUser != null) &&
+            (userPrincipal != null) &&
+            !remoteUser.equals(userPrincipal.getName()))
+            errors += "  remoteUser=" + remoteUser + " userPrincipal=" +
+                userPrincipal.getName();
+        if (errors.length() > 0)
+            writer.println("Authentication02 FAILED:" + errors);
+        else
+            writer.println("Authentication02 PASSED");
+
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Authentication03.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Authentication03.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Authentication03.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,91 @@
+/*
+ * Copyright 1999, 2000, 2001 ,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tester;
+
+
+import java.io.*;
+import java.security.Principal;
+import javax.servlet.*;
+import javax.servlet.http.*;
+
+/**
+ * Ensure that we get the correct results from <code>isUserInRole()</code>
+ * for an actual role, a role aliased with a
+ * <code>&lt;security-role-ref&gt;</code> element, and for a role that is
+ * not assigned to the specified user.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class Authentication03 extends HttpServlet {
+
+    public void doGet(HttpServletRequest request, HttpServletResponse response)
+        throws IOException, ServletException {
+
+        // Prepare to create this response
+        response.setContentType("text/plain");
+        PrintWriter writer = response.getWriter();
+        StringBuffer results = new StringBuffer();
+
+        // Validate that we have been authenticated correctly
+        String remoteUser = request.getRemoteUser();
+        if (remoteUser == null) {
+            results.append("  Not Authenticated/");
+        } else if (!"tomcat".equals(remoteUser)) {
+            results.append("  Authenticated as '");
+            results.append(remoteUser);
+            results.append("'/");
+        }
+
+        // Validate that this user is part of the "tomcat" role
+        if (!request.isUserInRole("tomcat")) {
+            results.append("  Not in role 'tomcat'/");
+        }
+
+        // Validate that this user is part of the "alias" role
+        // (mapped to "tomcat" in a <security-role-ref> element
+        if (!request.isUserInRole("alias")) {
+            results.append("  Not in role 'alias'/");
+        }
+
+        // Validate that this user is NOT part of the "unknown" role
+        if (request.isUserInRole("unknown")) {
+            results.append("  In role 'unknown'/");
+        }
+
+        // Generate our response
+        if (results.length() < 1) {
+            writer.println("Authentication03 PASSED");
+        } else {
+            writer.print("Authentication03 FAILED -");
+            writer.println(results.toString());
+        }
+
+        // Add wrapper messages as required
+        while (true) {
+            String message = StaticLogger.read();
+            if (message == null)
+                break;
+            writer.println(message);
+        }
+        StaticLogger.reset();
+
+
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Authentication05.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Authentication05.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Authentication05.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,81 @@
+/*
+ * Copyright 1999, 2000, 2001 ,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tester;
+
+
+import java.io.*;
+import java.security.Principal;
+import javax.servlet.*;
+import javax.servlet.http.*;
+
+/**
+ * Ensure that a resource protected a a security constratint that allows all
+ * roles will permit access to an authenticated user.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class Authentication05 extends HttpServlet {
+
+    public void doGet(HttpServletRequest request, HttpServletResponse response)
+        throws IOException, ServletException {
+
+        response.setContentType("text/plain");
+        PrintWriter writer = response.getWriter();
+        StringBuffer sb = new StringBuffer();
+
+        String remoteUser = request.getRemoteUser();
+        if (remoteUser == null)
+            sb.append(" No remote user returned/");
+        else if (!"tomcat".equals(remoteUser)) {
+            sb.append(" Remote user is '");
+            sb.append(remoteUser);
+            sb.append("'/");
+        }
+
+        Principal userPrincipal = request.getUserPrincipal();
+        if (userPrincipal == null)
+            sb.append(" No user principal returned/");
+        else if (!"tomcat".equals(userPrincipal.getName())) {
+            sb.append(" User principal is '");
+            sb.append(userPrincipal);
+            sb.append("'/");
+        }
+
+        if (!request.isUserInRole("tomcat"))
+            sb.append(" Not in role 'tomcat'/");
+
+        if (sb.length() < 1)
+            writer.println("Authentication05 PASSED");
+        else {
+            writer.print("Authentication05 FAILED -");
+            writer.println(sb.toString());
+        }
+
+        while (true) {
+            String message = StaticLogger.read();
+            if (message == null)
+                break;
+            writer.println(message);
+        }
+        StaticLogger.reset();
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Authentication06.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Authentication06.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Authentication06.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,53 @@
+/*
+ * Copyright 1999, 2000, 2001 ,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tester;
+
+
+import java.io.*;
+import java.security.Principal;
+import javax.servlet.*;
+import javax.servlet.http.*;
+
+/**
+ * Ensure that a resource protected a a security constratint that allows all
+ * roles will permit access to an authenticated user.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision$ $Date: 2004-02-27 06:59:07 -0800 (Fri, 27 Feb 2004) $
+ */
+
+public class Authentication06 extends HttpServlet {
+
+    public void doGet(HttpServletRequest request, HttpServletResponse response)
+        throws IOException, ServletException {
+
+        response.setContentType("text/plain");
+        PrintWriter writer = response.getWriter();
+
+        writer.println("Authentication06 PASSED");
+        while (true) {
+            String message = StaticLogger.read();
+            if (message == null)
+                break;
+            writer.println(message);
+        }
+        StaticLogger.reset();
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/CharArrayResponse.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/CharArrayResponse.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/CharArrayResponse.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,71 @@
+/*
+ * Copyright 1999, 2000, 2001 ,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tester;
+
+
+import java.io.*;
+import java.util.*;
+import javax.servlet.*;
+import javax.servlet.http.*;
+
+
+/**
+ * HttpServletResponse wrapper that converts all output characters to
+ * upper case via an intermediate buffer.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class CharArrayResponse extends HttpServletResponseWrapper {
+
+
+    CharArrayWriterUpperCase writer = null;
+
+    public CharArrayResponse(HttpServletResponse response) {
+        super(response);
+        writer = new CharArrayWriterUpperCase();
+    }
+
+    public void flushBuffer() throws IOException {
+        int n = 0;
+        Reader reader = getReader();
+        PrintWriter writer = getResponse().getWriter();
+        while (true) {
+            int ch = reader.read();
+            if (ch < 0)
+                break;
+            n++;
+            writer.print((char) ch);
+        }
+        writer.println("[" + n + "]");
+        this.writer.reset();
+    }
+
+    public Reader getReader() {
+        return (new CharArrayReader(writer.toCharArray()));
+    }
+
+    public PrintWriter getWriter() throws IOException {
+        return (new PrintWriter(writer, true));
+    }
+
+
+}
+
+
+

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/CharArrayWriterUpperCase.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/CharArrayWriterUpperCase.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/CharArrayWriterUpperCase.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,92 @@
+/*
+ * Copyright 1999, 2000, 2001 ,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tester;
+
+
+import java.io.*;
+import java.util.*;
+import javax.servlet.*;
+import javax.servlet.http.*;
+
+
+/**
+ * Implementation of CharArrayWriter that upper cases its output.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class CharArrayWriterUpperCase extends CharArrayWriter {
+
+
+    CharArrayWriter writer = new CharArrayWriter();
+
+    public void close() {
+        writer.close();
+    }
+
+    public void flush() {
+        writer.flush();
+    }
+
+    public void reset() {
+        writer.reset();
+    }
+
+    public int size() {
+        return (writer.size());
+    }
+
+    public char[] toCharArray() {
+        return (writer.toCharArray());
+    }
+
+    public String toString() {
+        return (writer.toString());
+    }
+
+    public void write(int c) {
+        char ch = (char) c;
+        if (Character.isLowerCase(ch))
+            ch = Character.toUpperCase(ch);
+        writer.write((int) ch);
+    }
+
+    public void write(char c[]) throws IOException {
+        write(c, 0, c.length);
+    }
+
+    public void write(char c[], int off, int len) {
+        for (int i = off; i < (off + len); i++)
+            write(c[i]);
+    }
+
+    public void write(String str) throws IOException {
+        write(str, 0, str.length());
+    }
+
+    public void write(String str, int off, int len) {
+        for (int i = off; i < (off + len); i++)
+            write(str.charAt(i));
+    }
+
+    public void writeTo(Writer out) throws IOException {
+        writer.writeTo(out);
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Context00.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Context00.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Context00.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,68 @@
+/*
+ * Copyright 1999, 2000 ,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tester;
+
+
+import java.io.*;
+import javax.servlet.*;
+import javax.servlet.http.*;
+import org.apache.tester.shared.SharedSessionBean;
+import org.apache.tester.unshared.UnsharedSessionBean;
+
+
+/**
+ * Part 0 of Context Tests.  This servlet is never executed directly.  Its
+ * purpose is to create a servlet context attribute at <code>init()</code>
+ * time, and remove it at <code>destroy()</code> time.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class Context00 extends HttpServlet {
+
+
+    public void destroy() {
+        getServletContext().log("Context00: Removing attribute 'context00'");
+        getServletContext().removeAttribute("context00");
+    }
+
+
+    public void init() throws ServletException {
+        getServletContext().log("Context00: Setting attribute 'context00'");
+        ContextBean cb = new ContextBean();
+        cb.setStringProperty("Context00");
+        getServletContext().setAttribute("context00", cb);
+    }
+
+
+    public void doGet(HttpServletRequest request, HttpServletResponse response)
+        throws IOException, ServletException {
+        response.setContentType("text/plain");
+        PrintWriter writer = response.getWriter();
+        writer.println("Context00 PASSED");
+        while (true) {
+            String message = StaticLogger.read();
+            if (message == null)
+                break;
+            writer.println(message);
+        }
+        StaticLogger.reset();
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Context01.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Context01.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Context01.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,142 @@
+/*
+ * Copyright 1999, 2000 ,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tester;
+
+
+import java.io.*;
+import javax.servlet.*;
+import javax.servlet.http.*;
+import org.apache.tester.shared.SharedSessionBean;
+import org.apache.tester.unshared.UnsharedSessionBean;
+
+
+/**
+ * Part 1 of Context Tests.  Exercise various methods for dealing with
+ * servlet context attributes.  Leave an attribute named "context01"
+ * present, which should be erased after a web application restart.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class Context01 extends HttpServlet {
+
+    public void doGet(HttpServletRequest request, HttpServletResponse response)
+        throws IOException, ServletException {
+
+        response.setContentType("text/plain");
+        boolean ok = true;
+        PrintWriter writer = response.getWriter();
+        ServletContext context = getServletContext();
+
+        // Ensure that there is no existing attribute
+        if (ok) {
+            if (context.getAttribute("context01") != null) {
+                writer.println("Context01 FAILED - Attribute already exists");
+                ok = false;
+            }
+        }
+
+        // Create and stash a context attribute
+        if (ok) {
+            ContextBean bean = new ContextBean();
+            bean.setStringProperty("Context01");
+            context.setAttribute("context01", bean);
+        }
+
+        // Ensure that we can retrieve the attribute successfully
+        if (ok) {
+            Object bean = context.getAttribute("context01");
+            if (bean == null) {
+                writer.println("Context01 FAILED - Cannot retrieve attribute");
+                ok = false;
+            }
+            if (ok) {
+                if (!(bean instanceof ContextBean)) {
+                    writer.println("Context01 FAILED - Bean instance of " +
+                                   bean.getClass().getName());
+                    ok = false;
+                }
+            }
+            if (ok) {
+                String value = ((ContextBean) bean).getStringProperty();
+                if (!"Context01".equals(value)) {
+                    writer.println("Context01 FAILED - Value = " + value);
+                    ok = false;
+                }
+            }
+            if (ok) {
+                String lifecycle = ((ContextBean) bean).getLifecycle();
+                if (!"/add".equals(lifecycle)) {
+                    writer.println("Context01 FAILED - Bean lifecycle is " +
+                                   lifecycle);
+                    ok = false;
+                }
+            }
+        }
+
+        // Ensure that we can update this attribute and check its lifecycle
+        if (ok) {
+            ContextBean bean = (ContextBean) context.getAttribute("context01");
+            context.setAttribute("context01", bean);
+            String lifecycle = bean.getLifecycle();
+            if (!"/add/rep".equals(lifecycle)) {
+                writer.println("Context01 FAILED - Bean lifecycle is " +
+                               lifecycle);
+                ok = false;
+            }
+        }
+
+        // Ensure that we can remove this attribute and check its lifecycle
+        if (ok) {
+            ContextBean bean = (ContextBean) context.getAttribute("context01");
+            context.removeAttribute("context01");
+            String lifecycle = bean.getLifecycle();
+            if (!"/add/rep/rem".equals(lifecycle)) {
+                writer.println("Context01 FAILED - Bean lifecycle is " +
+                               lifecycle);
+                ok = false;
+            }
+        }
+
+        // Add a bean back for the restart application test
+        context.setAttribute("context01", new ContextBean());
+
+        // Ensure that setAttribute("name", null) works correctly
+        if (ok) {
+            context.setAttribute("FOO", "BAR");
+            context.setAttribute("FOO", null);
+            if (context.getAttribute("FOO") != null) {
+                writer.println("Context01 FAILED - setAttribute(name,null)");
+                ok = false;
+            }
+        }
+
+        // Report success if everything is still ok
+        if (ok)
+            writer.println("Context01 PASSED");
+        while (true) {
+            String message = StaticLogger.read();
+            if (message == null)
+                break;
+            writer.println(message);
+        }
+        StaticLogger.reset();
+
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Context02.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Context02.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Context02.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,129 @@
+/*
+ * Copyright 1999, 2000 ,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tester;
+
+
+import java.io.*;
+import javax.servlet.*;
+import javax.servlet.http.*;
+import org.apache.tester.shared.SharedSessionBean;
+import org.apache.tester.unshared.UnsharedSessionBean;
+
+
+/**
+ * Part 2 of Context Tests.  The context attribute from Context00 should
+ * still be here after a restart (because Context00 is a load-on-startup
+ * servlet, so the <code>init()</code> method should have been triggered
+ * during the restart).  However, the context attribute from Context01
+ * should <strong>not</strong> be here, because context attributes should
+ * be cleaned up during a restart.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class Context02 extends HttpServlet {
+
+    public void doGet(HttpServletRequest request, HttpServletResponse response)
+        throws IOException, ServletException {
+
+        response.setContentType("text/plain");
+        boolean ok = true;
+        PrintWriter writer = response.getWriter();
+        ServletContext context = getServletContext();
+
+        // Check for the attribute from Context01
+        if (ok) {
+            Object bean = context.getAttribute("context01");
+            if (bean != null) {
+                writer.println("Context02 FAILED - context01 value " +
+                               bean);
+                ok = false;
+                context.removeAttribute("context01");
+            }
+        }
+
+        // Check for the attribute from Context00
+        if (ok) {
+            Object bean = context.getAttribute("context00");
+            if (bean == null) {
+                writer.println("Context02 FAILED - context00 missing");
+                ok = false;
+            } else if (!(bean instanceof ContextBean)) {
+                writer.println("Context02 FAILED - context00 class " +
+                               bean.getClass().getName());
+                ok = false;
+            } else {
+                String value = ((ContextBean) bean).getStringProperty();
+                if (!"Context00".equals(value)) {
+                    writer.println("Context02 FAILED - context00 value " +
+                                   value);
+                    ok = false;
+                } else {
+                    String lifecycle = ((ContextBean) bean).getLifecycle();
+                    if (!"/add".equals(lifecycle)) {
+                        writer.println("Context02 FAILED -" +
+                                       " context00 lifecycle " +
+                                       lifecycle);
+                        ok = false;
+                    }
+                }
+            }
+        }
+
+        // Check for the attribute from ContextListener01
+        if (ok) {
+            Object bean = context.getAttribute("contextListener01");
+            if (bean == null) {
+                writer.println("Context02 FAILED - contextListener01 missing");
+                ok = false;
+            } else if (!(bean instanceof ContextBean)) {
+                writer.println("Context02 FAILED - contextListener01 class " +
+                               bean.getClass().getName());
+                ok = false;
+            } else {
+                String value = ((ContextBean) bean).getStringProperty();
+                if (!"ContextListener01".equals(value)) {
+                    writer.println("Context02 FAILED - contextListener01 " +
+                                   "value " + value);
+                    ok = false;
+                } else {
+                    String lifecycle = ((ContextBean) bean).getLifecycle();
+                    if (!"/add".equals(lifecycle)) {
+                        writer.println("Context02 FAILED -" +
+                                       " contextListener01 lifecycle " +
+                                       lifecycle);
+                        ok = false;
+                    }
+                }
+            }
+        }
+
+        // Report success if everything is still ok
+        if (ok)
+            writer.println("Context02 PASSED");
+        while (true) {
+            String message = StaticLogger.read();
+            if (message == null)
+                break;
+            writer.println(message);
+        }
+        StaticLogger.reset();
+
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/ContextBean.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/ContextBean.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/ContextBean.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,83 @@
+/*
+ * Copyright 1999, 2000 ,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tester;
+
+
+import java.io.Serializable;
+
+
+/**
+ * Simple JavaBean to use for context attribute tests.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class ContextBean implements Serializable {
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * The lifecycle events that have happened on this bean instance.
+     */
+    protected String lifecycle = "";
+
+    public String getLifecycle() {
+        return (this.lifecycle);
+    }
+
+    public void setLifecycle(String lifecycle) {
+        this.lifecycle = lifecycle;
+    }
+
+
+    /**
+     * A string property.
+     */
+    protected String stringProperty = "Default String Property Value";
+
+    public String getStringProperty() {
+        return (this.stringProperty);
+    }
+
+    public void setStringProperty(String stringProperty) {
+        this.stringProperty = stringProperty;
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Return a string representation of this bean.
+     */
+    public String toString() {
+
+        StringBuffer sb = new StringBuffer("ContextBean[lifecycle=");
+        sb.append(lifecycle);
+        sb.append(", stringProperty=");
+        sb.append(this.stringProperty);
+        sb.append("]");
+        return (sb.toString());
+
+    }
+
+
+}
+

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/ContextListener01.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/ContextListener01.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/ContextListener01.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,89 @@
+/*
+ * Copyright 1999, 2000, 2001 ,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tester;
+
+
+import java.io.*;
+import javax.servlet.*;
+import javax.servlet.http.*;
+
+/**
+ * Application event listener for context events.  All events that occur
+ * are logged appropriately to the static logger..
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class ContextListener01
+    implements ServletContextAttributeListener, ServletContextListener {
+
+
+    public void attributeAdded(ServletContextAttributeEvent event) {
+        StaticLogger.write("ContextListener01: attributeAdded(" +
+                           event.getName() + "," + event.getValue() + ")");
+        ServletContext context = (ServletContext) event.getSource();
+        context.log("ContextListener01: attributeAdded(" +
+                    event.getName() + "," + event.getValue() + ")");
+        if (event.getValue() instanceof ContextBean) {
+            ContextBean bean = (ContextBean) event.getValue();
+            bean.setLifecycle(bean.getLifecycle() + "/add");
+        }
+    }
+
+    public void attributeRemoved(ServletContextAttributeEvent event) {
+        StaticLogger.write("ContextListener01: attributeRemoved(" +
+                           event.getName() + "," + event.getValue() + ")");
+        ServletContext context = (ServletContext) event.getSource();
+        context.log("ContextListener01: attributeRemoved(" +
+                    event.getName() + "," + event.getValue() + ")");
+        if (event.getValue() instanceof ContextBean) {
+            ContextBean bean = (ContextBean) event.getValue();
+            bean.setLifecycle(bean.getLifecycle() + "/rem");
+        }
+    }
+
+    public void attributeReplaced(ServletContextAttributeEvent event) {
+        StaticLogger.write("ContextListener01: attributeReplaced(" +
+                           event.getName() + "," + event.getValue() + ")");
+        ServletContext context = (ServletContext) event.getSource();
+        context.log("ContextListener01: attributeReplaced(" +
+                    event.getName() + "," + event.getValue() + ")");
+        if (event.getValue() instanceof ContextBean) {
+            ContextBean bean = (ContextBean) event.getValue();
+            bean.setLifecycle(bean.getLifecycle() + "/rep");
+        }
+    }
+
+    public void contextDestroyed(ServletContextEvent event) {
+        StaticLogger.write("ContextListener01: contextDestroyed()");
+        ServletContext context = (ServletContext) event.getSource();
+        context.log("ContextListener01: contextDestroyed()");
+        context.removeAttribute("contextListener01");
+    }
+
+    public void contextInitialized(ServletContextEvent event) {
+        StaticLogger.write("ContextListener01: contextInitialized()");
+        ServletContext context = (ServletContext) event.getSource();
+        context.log("ContextListener01: contextInitialized()");
+        ContextBean bean = new ContextBean();
+        bean.setStringProperty("ContextListener01");
+        context.setAttribute("contextListener01", bean);
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/ContextListener02.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/ContextListener02.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/ContextListener02.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,64 @@
+/*
+ * Copyright 1999, 2000, 2001 ,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tester;
+
+
+import java.beans.PropertyEditorManager;
+import java.sql.Date;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletContextEvent;
+import javax.servlet.ServletContextListener;
+
+
+/**
+ * Application event listener for context events.  Ensures that the property
+ * editor classes for this web application are appropriately registered.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class ContextListener02
+    implements ServletContextListener {
+
+
+    private ServletContext context = null;
+
+
+    public void contextDestroyed(ServletContextEvent event) {
+        context.log("ContextListener02: contextDestroyed()");
+        context = null;
+    }
+
+    public void contextInitialized(ServletContextEvent event) {
+        context = (ServletContext) event.getSource();
+        context.log("ContextListener02: contextInitialized()");
+        PropertyEditorManager.registerEditor(Date.class,
+                                             DatePropertyEditor.class);
+        context.log("ContextListener02: getEditorSearchPath() -->");
+        String search[] = PropertyEditorManager.getEditorSearchPath();
+        if (search == null)
+            search = new String[0];
+        for (int i = 0; i < search.length; i++)
+            context.log("ContextListener02:   " + search[i]);
+        context.log("ContextListener02: findEditor() --> " +
+                    PropertyEditorManager.findEditor(Date.class));
+               
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/DatePropertyEditor.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/DatePropertyEditor.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/DatePropertyEditor.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,105 @@
+/*
+ * Copyright 1999, 2000 ,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tester;
+
+import java.beans.PropertyEditorSupport;
+import java.text.ParsePosition;
+import java.text.SimpleDateFormat;
+import java.sql.Date;
+
+/**
+ * PropertyEditor implementation for a java.sql.Date property.
+ *
+ * @author Craig R. McClanahan
+ * @revision $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $ $Revision: 302726 $
+ */
+public class DatePropertyEditor extends PropertyEditorSupport {
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The date format to which dates converted by this property editor
+     * must conform.
+     */
+    private SimpleDateFormat format = new SimpleDateFormat("MM/dd/yyyy");
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Convert our Date object into a String that conforms to our
+     * specified <code>format</code>, and return it.  If this is not
+     * possible, return <code>null</code>.
+     */
+    public String getAsText() {
+
+        try {
+            Date date = (Date) getValue();
+            return (format.format(date));
+        } catch (ClassCastException e) {
+            return (null);
+        } catch (IllegalArgumentException e) {
+            return (null);
+        }
+
+    }
+
+
+    /**
+     * Convert the specified String value into a Date, if it conforms to
+     * our specified <code>format</code> , else throw IllegalArgumentException.
+     *
+     * @param value String value to be converted
+     *
+     * @exception IllegalArgumentException if a conversion error occurs
+     */
+    public void setAsText(String value) throws IllegalArgumentException {
+
+        // Validate the format of the input string
+        if (value == null)
+            throw new IllegalArgumentException
+                ("Cannot convert null String to a Date");
+        if (value.length() != 10)
+            throw new IllegalArgumentException
+                ("String '" + value + "' has invalid length " +
+                 value.length());
+        for (int i = 0; i < 10; i++) {
+            char ch = value.charAt(i);
+            if ((i == 2) || (i == 5)) {
+                if (ch != '/')
+                    throw new IllegalArgumentException
+                        ("String '" + value + "' missing slash at index " +
+                         i);
+            } else {
+                if (!Character.isDigit(ch))
+                    throw new IllegalArgumentException
+                        ("String '" + value + "' missing digit at index " +
+                         i);
+            }
+        }
+
+        // Convert the incoming value to a java.sql.Date
+        java.util.Date temp = format.parse(value, new ParsePosition(0)); 
+        java.sql.Date date = new java.sql.Date(temp.getTime());
+        setValue(date);
+    }
+
+        
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Decoding01.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Decoding01.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Decoding01.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,98 @@
+/*
+ * Copyright 1999, 2000, 2001 ,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tester;
+
+
+import java.io.*;
+import javax.servlet.*;
+import javax.servlet.http.*;
+
+
+/**
+ * Test for proper URL decoding of the getServletPath() and getPathInfo()
+ * methods of HttpServletRequest.  The desired values are specified by the
+ * <strong>servlet</strong> and <strong>path</strong> request parameters,
+ * respectively.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class Decoding01 extends HttpServlet {
+
+    public void doGet(HttpServletRequest request, HttpServletResponse response)
+        throws IOException, ServletException {
+
+        // Identify our configuration parameters
+        String desiredServlet = request.getParameter("servlet");
+        String desiredPath = request.getParameter("path");
+
+        // Prepare for the desired test
+        response.setContentType("text/plain");
+        PrintWriter writer = response.getWriter();
+        StringBuffer results = new StringBuffer();
+
+        // Check the value returned by getServletPath()
+        String servletPath = request.getServletPath();
+        if (desiredServlet == null) {
+            if (servletPath != null)
+                results.append(" servletPath is '" + servletPath +
+                               "' instead of NULL/");
+        } else {
+            if (servletPath == null)
+                results.append(" servletPath is NULL instead of '" +
+                               desiredPath + "'/");
+            else if (!servletPath.equals(desiredServlet))
+                results.append(" servletPath is '" + servletPath +
+                               "' instead of '" + desiredServlet + "'/");
+        }
+
+        // Check the value returned by getPathInfo()
+        String pathInfo = request.getPathInfo();
+        if (desiredPath == null) {
+            if (pathInfo != null)
+                results.append(" pathInfo is '" + pathInfo +
+                               "' instead of NULL/");
+        } else {
+            if (pathInfo == null)
+                results.append(" pathInfo is NULL instead of '" +
+                               desiredPath + "'/");
+            else if (!pathInfo.equals(desiredPath))
+                results.append(" pathInfo is '" + pathInfo +
+                               "' instead of '" + desiredPath + "'/");
+        }
+
+        // Report success or failure
+        if (results.length() < 1)
+            writer.println("Decoding01 PASSED");
+        else {
+            writer.print("Decoding01 FAILED -");
+            writer.println(results.toString());
+        }
+
+        // Add wrapper messages as required
+        while (true) {
+            String message = StaticLogger.read();
+            if (message == null)
+                break;
+            writer.println(message);
+        }
+        StaticLogger.reset();
+
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/ErrorPage01.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/ErrorPage01.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/ErrorPage01.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,50 @@
+/*
+ * Copyright 1999, 2000, 2001 ,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tester;
+
+
+import java.io.*;
+import javax.servlet.*;
+import javax.servlet.http.*;
+
+/**
+ * Part 1 of the ErrorPage Tests.  Returns a response status code of 412
+ * (HttpServletResponse.SC_PRECONDITION_FAILED) which is mapped to the
+ * ErrorPage02 servlet in the deployment descriptor.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class ErrorPage01 extends HttpServlet {
+
+    public void doGet(HttpServletRequest request, HttpServletResponse response)
+        throws IOException, ServletException {
+
+        response.setContentType("text/plain");
+        PrintWriter writer = response.getWriter();
+
+        // Write a FAILED message that should get replaced by the error text
+        writer.println("ErrorPage01 FAILED - Original response returned");
+
+        // Return the appropriate response code
+        response.sendError(HttpServletResponse.SC_PRECONDITION_FAILED,
+                           "ErrorPage01 Returned Status Code 412");
+
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/ErrorPage02.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/ErrorPage02.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/ErrorPage02.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,129 @@
+/*
+ * Copyright 1999, 2000, 2001 ,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tester;
+
+
+import java.io.*;
+import javax.servlet.*;
+import javax.servlet.http.*;
+
+/**
+ * Part 2 of the ErrorPage Tests.  Should be mapped by the container when
+ * the ErrorPage01 servlet returns the appropriate status code.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class ErrorPage02 extends HttpServlet {
+
+
+    public void doGet(HttpServletRequest request, HttpServletResponse response)
+        throws IOException, ServletException {
+
+        response.reset();
+        response.setContentType("text/plain");
+        PrintWriter writer = response.getWriter();
+
+        // Accumulate all the reasons this request might fail
+        StringBuffer sb = new StringBuffer();
+        Object value = null;
+
+        value = request.getAttribute("javax.servlet.error.status_code");
+        if (value == null)
+            sb.append(" status_code is missing/");
+        else if (!(value instanceof Integer)) {
+            sb.append(" status_code class is ");
+            sb.append(value.getClass().getName());
+            sb.append("/");
+        } else {
+            int intValue = ((Integer) value).intValue();
+            if (intValue != HttpServletResponse.SC_PRECONDITION_FAILED) {
+                sb.append(" status_code is ");
+                sb.append(value);
+                sb.append("/");
+            }
+        }
+
+        value = request.getAttribute("javax.servlet.error.message");
+        if (value == null)
+            sb.append(" message is missing/");
+        else if (!(value instanceof String)) {
+            sb.append(" message class is ");
+            sb.append(value.getClass().getName());
+            sb.append("/");
+        } else {
+            String message = (String) value;
+            if (!"ErrorPage01 Returned Status Code 412".equals(message)) {
+                sb.append(" message is ");
+                sb.append(message);
+                sb.append("/");
+            }
+        }
+
+        value = request.getAttribute("javax.servlet.error.request_uri");
+        if (value == null)
+            sb.append(" request_uri is missing/");
+        else if (!(value instanceof String)) {
+            sb.append(" request_uri class is ");
+            sb.append(value.getClass().getName());
+            sb.append("/");
+        } else {
+            String request_uri = (String) value;
+            String test1 = request.getContextPath() + "/ErrorPage01";
+            String test2 = request.getContextPath() + "/WrappedErrorPage01";
+            if (!request_uri.equals(test1) && !request_uri.equals(test2)) {
+                sb.append(" request_uri is ");
+                sb.append(request_uri);
+                sb.append("/");
+            }
+        }
+
+        value = request.getAttribute("javax.servlet.error.servlet_name");
+        if (value == null)
+            sb.append(" servlet_name is missing/");
+        else if (!(value instanceof String)) {
+            sb.append(" servlet_name class is ");
+            sb.append(value.getClass().getName());
+            sb.append("/");
+        } else {
+            String servlet_name = (String) value;
+            if (!"ErrorPage01".equals(servlet_name)) {
+                sb.append(" servlet_name is ");
+                sb.append(servlet_name);
+                sb.append("/");
+            }
+        }
+
+        // Report ultimate success or failure
+        if (sb.length() < 1)
+            writer.println("ErrorPage02 PASSED");
+        else
+            writer.println("ErrorPage02 FAILED -" + sb.toString());
+
+        while (true) {
+            String message = StaticLogger.read();
+            if (message == null)
+                break;
+            writer.println(message);
+        }
+        StaticLogger.reset();
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/ErrorPage03.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/ErrorPage03.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/ErrorPage03.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,50 @@
+/*
+ * Copyright 1999, 2000, 2001 ,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tester;
+
+
+import java.io.*;
+import javax.servlet.*;
+import javax.servlet.http.*;
+
+/**
+ * Part 3 of the ErrorPage Tests.  Throws an exception of a specified type
+ * (wrapped in a servlet exception as required by the throws clause), which
+ * is mapped to the ErrorPage04 servlet in the deployment descriptor.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class ErrorPage03 extends HttpServlet {
+
+    public void doGet(HttpServletRequest request, HttpServletResponse response)
+        throws IOException, ServletException {
+
+        response.setContentType("text/plain");
+        PrintWriter writer = response.getWriter();
+
+        // Write a FAILED message that should get replaced by the error text
+        writer.println("ErrorPage03 FAILED - Original response returned");
+
+        // Throw the specified exception
+        throw new ServletException
+            (new TesterException("ErrorPage03 Threw Exception"));
+
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/ErrorPage04.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/ErrorPage04.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/ErrorPage04.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,146 @@
+/*
+ * Copyright 1999, 2000, 2001 ,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tester;
+
+
+import java.io.*;
+import javax.servlet.*;
+import javax.servlet.http.*;
+
+/**
+ * Part 4 of the ErrorPage Tests.  Should be mapped by the container when
+ * the ErrorPage01 servlet returns the appropriate exception.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class ErrorPage04 extends HttpServlet {
+
+
+    public void doGet(HttpServletRequest request, HttpServletResponse response)
+        throws IOException, ServletException {
+
+        response.reset();
+        response.setContentType("text/plain");
+        PrintWriter writer = response.getWriter();
+
+        // Accumulate all the reasons this request might fail
+        ServletException exception = null;
+        StringBuffer sb = new StringBuffer();
+        Object value = null;
+
+        value = request.getAttribute("javax.servlet.error.exception");
+        if (value == null)
+            sb.append(" exception is missing/");
+        else if (!(value instanceof org.apache.tester.TesterException)) {
+            sb.append(" exception class is ");
+            sb.append(value.getClass().getName());
+            sb.append("/");
+        } else {
+            TesterException te = (TesterException) value;
+            if (!"ErrorPage03 Threw Exception".equals(te.getMessage())) {
+                sb.append(" exception message is ");
+                sb.append(te.getMessage());
+                sb.append("/");
+            }
+        }
+
+        value = request.getAttribute("javax.servlet.error.exception_type");
+        if (value == null)
+            sb.append(" exception_type is missing/");
+        else if (!(value instanceof Class)) {
+            sb.append(" exception_type class is ");
+            sb.append(value.getClass().getName());
+            sb.append("/");
+        } else {
+            Class clazz = (Class) value;
+            if (!"org.apache.tester.TesterException".equals(clazz.getName())) {
+                sb.append(" exception_type class is ");
+                sb.append(clazz.getName());
+                sb.append("/");
+            }
+        }
+
+        value = request.getAttribute("javax.servlet.error.message");
+        if (value == null)
+            sb.append(" message is missing/");
+        else if (!(value instanceof String)) {
+            sb.append(" message class is ");
+            sb.append(value.getClass().getName());
+            sb.append("/");
+        } else {
+            String message = (String) value;
+            if (!"ErrorPage03 Threw Exception".equals(message)) {
+                sb.append(" message is ");
+                sb.append(message);
+                sb.append("/");
+            }
+        }
+
+        value = request.getAttribute("javax.servlet.error.request_uri");
+        if (value == null)
+            sb.append(" request_uri is missing/");
+        else if (!(value instanceof String)) {
+            sb.append(" request_uri class is ");
+            sb.append(value.getClass().getName());
+            sb.append("/");
+        } else {
+            String request_uri = (String) value;
+            String test1 = request.getContextPath() + "/ErrorPage03";
+            String test2 = request.getContextPath() + "/WrappedErrorPage03";
+            if (!request_uri.equals(test1) && !request_uri.equals(test2)) {
+                sb.append(" request_uri is ");
+                sb.append(request_uri);
+                sb.append("/");
+            }
+        }
+
+        value = request.getAttribute("javax.servlet.error.servlet_name");
+        if (value == null)
+            sb.append(" servlet_name is missing/");
+        else if (!(value instanceof String)) {
+            sb.append(" servlet_name class is ");
+            sb.append(value.getClass().getName());
+            sb.append("/");
+        } else {
+            String servlet_name = (String) value;
+            if (!"ErrorPage03".equals(servlet_name)) {
+                sb.append(" servlet_name is ");
+                sb.append(servlet_name);
+                sb.append("/");
+            }
+        }
+
+        // Report ultimate success or failure
+        if (sb.length() < 1)
+            writer.println("ErrorPage04 PASSED");
+        else
+            writer.println("ErrorPage04 FAILED -" + sb.toString());
+
+        while (true) {
+            String message = StaticLogger.read();
+            if (message == null)
+                break;
+            writer.println(message);
+        }
+        StaticLogger.reset();
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/ErrorPage05.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/ErrorPage05.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/ErrorPage05.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,66 @@
+/*
+ * Copyright 1999, 2000, 2001 ,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tester;
+
+
+import java.io.*;
+import javax.servlet.*;
+import javax.servlet.http.*;
+
+/**
+ * Part 5 of the ErrorPage Tests.  Throws a RuntimeException of a type
+ * specified by the <code>type</code> query parameter, which must be one
+ * of the following:
+ * <ul>
+ * <li><strong>ArithmeticException</strong> - Forwarded to "/ErrorPage06".</li>
+ * <li><strong>ArrayIndexOutOfBoundsException</strong> -
+ *     Forwarded to "/ErrorPage06.jsp".</li>
+ * <li><strong>NumberFormatException</strong> -
+ *     Forwarded to "/ErrorPage06.html".</li>
+ * </ul>
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class ErrorPage05 extends HttpServlet {
+
+    public void doGet(HttpServletRequest request, HttpServletResponse response)
+        throws IOException, ServletException {
+
+        response.setContentType("text/plain");
+        PrintWriter writer = response.getWriter();
+
+        // Write a FAILED message that should get replaced by the error text
+        writer.println("ErrorPage05 FAILED - Original response returned");
+
+        // Throw the specified exception
+        String type = request.getParameter("type");
+        if ("Arithmetic".equals(type)) {
+            throw new ArithmeticException
+                ("ErrorPage05 Threw ArithmeticException");
+        } else if ("Array".equals(type)) {
+            throw new ArrayIndexOutOfBoundsException
+                ("ErrorPage05 Threw ArrayIndexOutOfBoundsException");
+        } else if ("Number".equals(type)) {
+            throw new NumberFormatException
+                ("ErrorPage05 Threw NumberFormatException");
+        }
+
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/ErrorPage06.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/ErrorPage06.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/ErrorPage06.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,147 @@
+/*
+ * Copyright 1999, 2000, 2001 ,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tester;
+
+
+import java.io.*;
+import javax.servlet.*;
+import javax.servlet.http.*;
+
+/**
+ * Part 6 of the ErrorPage Tests.  Should be mapped by the container when
+ * the ErrorPage05 servlet returns the appropriate exception.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class ErrorPage06 extends HttpServlet {
+
+
+    public void doGet(HttpServletRequest request, HttpServletResponse response)
+        throws IOException, ServletException {
+
+        response.reset();
+        response.setContentType("text/plain");
+        PrintWriter writer = response.getWriter();
+
+        // Accumulate all the reasons this request might fail
+        StringBuffer sb = new StringBuffer();
+        Object value = null;
+
+        value = request.getAttribute("javax.servlet.error.exception");
+        StaticLogger.write("exception is '" + value + "'");
+        if (value == null) {
+            sb.append(" exception is missing/");
+        } else if (!(value instanceof java.lang.ArithmeticException)) {
+            sb.append(" exception class is ");
+            sb.append(value.getClass().getName());
+            sb.append("/");
+        }
+
+        value = request.getAttribute("javax.servlet.error.exception_type");
+        StaticLogger.write("exception_type is '" + value + "'");
+        if (value != null)
+            StaticLogger.write("exception_type class is '" +
+                               value.getClass().getName() + "'");
+        if (value == null)
+            sb.append(" exception_type is missing/");
+        else if (!(value instanceof Class)) {
+            sb.append(" exception_type class is ");
+            sb.append(value.getClass().getName());
+            sb.append("/");
+        } else {
+            Class clazz = (Class) value;
+            String name = clazz.getName();
+            if (!"java.lang.ArithmeticException".equals(name)) {
+                sb.append(" exception_type is ");
+                sb.append(name);
+                sb.append("/");
+            }
+        }
+
+        value = request.getAttribute("javax.servlet.error.message");
+        StaticLogger.write("message is '" + value + "'");
+        if (value == null)
+            sb.append(" message is missing/");
+        else if (!(value instanceof String)) {
+            sb.append(" message class is ");
+            sb.append(value.getClass().getName());
+            sb.append("/");
+        } else if (!"ErrorPage05 Threw ArithmeticException".equals(value) &&
+                   !"ErrorPage08 Threw ArithmeticException".equals(value)) {
+            sb.append(" message is not correct");
+        }
+
+        value = request.getAttribute("javax.servlet.error.request_uri");
+        StaticLogger.write("request_uri is '" + value + "'");
+        if (value == null)
+            sb.append(" request_uri is missing/");
+        else if (!(value instanceof String)) {
+            sb.append(" request_uri class is ");
+            sb.append(value.getClass().getName());
+            sb.append("/");
+        } else {
+            String request_uri = (String) value;
+            String test1 = request.getContextPath() + "/ErrorPage05";
+            String test2 = request.getContextPath() + "/WrappedErrorPage05";
+            String test3 = request.getContextPath() + "/ErrorPage08";
+            String test4 = request.getContextPath() + "/WrappedErrorPage08";
+            if (!request_uri.equals(test1) && !request_uri.equals(test2) &&
+                !request_uri.equals(test3) && !request_uri.equals(test4)) {
+                sb.append(" request_uri is ");
+                sb.append(request_uri);
+                sb.append("/");
+            }
+        }
+
+        value = request.getAttribute("javax.servlet.error.servlet_name");
+        StaticLogger.write("servlet_name is '" + value + "'");
+        if (value == null)
+            sb.append(" servlet_name is missing/");
+        else if (!(value instanceof String)) {
+            sb.append(" servlet_name class is ");
+            sb.append(value.getClass().getName());
+            sb.append("/");
+        } else {
+            String servlet_name = (String) value;
+            if (!"ErrorPage05".equals(servlet_name) &&
+                !"ErrorPage08".equals(servlet_name)) {
+                sb.append(" servlet_name is ");
+                sb.append(servlet_name);
+                sb.append("/");
+            }
+        }
+
+        // Report ultimate success or failure
+        if (sb.length() < 1)
+            writer.println("ErrorPage06 PASSED - SERVLET");
+        else
+            writer.println("ErrorPage06 FAILED -" + sb.toString());
+
+        while (true) {
+            String message = StaticLogger.read();
+            if (message == null)
+                break;
+            writer.println(message);
+        }
+        StaticLogger.reset();
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/ErrorPage07.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/ErrorPage07.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/ErrorPage07.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,58 @@
+/*
+ * Copyright 1999, 2000, 2001 ,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tester;
+
+
+import java.io.*;
+import javax.servlet.*;
+import javax.servlet.http.*;
+
+/**
+ * Part 7 of the error page tests.  This servlet is configured as
+ * <code>load-on-startup</code> in the web.xml file, and should return
+ * status 503 (service unavailable) when it is called later.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class ErrorPage07 extends HttpServlet {
+
+    public void init() throws ServletException {
+        throw new UnavailableException
+            ("ErrorPage07 Threw UnavailableException in init()");
+    }
+
+
+    public void doGet(HttpServletRequest request, HttpServletResponse response)
+        throws IOException, ServletException {
+
+        response.setContentType("text/plain");
+        PrintWriter writer = response.getWriter();
+        writer.println("ErrorPage07 FAILED - Called unavailable servlet");
+
+        while (true) {
+            String message = StaticLogger.read();
+            if (message == null)
+                break;
+            writer.println(message);
+        }
+        StaticLogger.reset();
+
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/FilterRequest01.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/FilterRequest01.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/FilterRequest01.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,81 @@
+/*
+ * Copyright 1999, 2000, 2001 ,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tester;
+
+
+import java.io.*;
+import java.lang.reflect.*;
+import java.util.*;
+import javax.servlet.*;
+import javax.servlet.http.*;
+
+
+/**
+ * Positive test for being able to filter input.  The input will be echoed
+ * back in the response, after having been converted to upper case by the
+ * associated filter.  Use request parameter <code>type</code> to determine
+ * whether to call getReader() ("reader") or getInputStream() ("stream").
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class FilterRequest01 extends HttpServlet {
+
+    public void service(HttpServletRequest request,
+                        HttpServletResponse response)
+        throws IOException, ServletException {
+
+        response.setContentType("text/plain");
+        PrintWriter writer = response.getWriter();
+        StringBuffer sb = new StringBuffer();
+
+        String type = request.getParameter("type");
+        if (type == null)
+            type = "reader";
+        if (type.equalsIgnoreCase("reader")) {
+            BufferedReader br = request.getReader();
+            while (true) {
+                int c = br.read();
+                if (c < 0)
+                    break;
+                sb.append((char) c);
+            }
+            br.close();
+        } else {
+            ServletInputStream sis = request.getInputStream();
+            while (true) {
+                int c = sis.read();
+                if (c < 0)
+                    break;
+                sb.append((char) c);
+            }
+            sis.close();
+        }
+
+        writer.println(sb.toString());
+        while (true) {
+            String message = StaticLogger.read();
+            if (message == null)
+                break;
+            writer.println(message);
+        }
+        StaticLogger.reset();
+
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/FilterRequest02.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/FilterRequest02.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/FilterRequest02.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,85 @@
+/*
+ * Copyright 1999, 2000, 2001 ,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tester;
+
+
+import java.io.*;
+import java.lang.reflect.*;
+import java.util.*;
+import javax.servlet.*;
+import javax.servlet.http.*;
+
+
+/**
+ * Verify that request and response wrappers added by a Filter are in fact
+ * visible to the called servlet.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class FilterRequest02 extends HttpServlet {
+
+    public void service(HttpServletRequest request,
+                        HttpServletResponse response)
+        throws IOException, ServletException {
+
+        response.setContentType("text/plain");
+        PrintWriter writer = response.getWriter();
+
+        String dispatch = request.getParameter("dispatch");
+        if ("F".equals(dispatch)) {
+            RequestDispatcher rd =
+                getServletContext().getRequestDispatcher("/FilterRequest02a");
+            if (rd == null)
+                writer.println("FilterRequest02 FAILED - No forward request dispatcher");
+            else
+                rd.forward(request, response);
+        } else if ("I".equals(dispatch)) {
+            RequestDispatcher rd =
+                getServletContext().getRequestDispatcher("/FilterRequest02a");
+            if (rd == null)
+                writer.println("FilterRequest02 FAILED - No include request dispatcher");
+            else
+                rd.include(request, response);
+        } else {
+            String wrap = request.getParameter("wrap");
+            if ("false".equals(wrap)) {
+                if (request instanceof TesterHttpServletRequestWrapper)
+                    writer.println("FilterRequest02 FAILED - Request was wrapped");
+                else
+                    writer.println("FilterRequest02 PASSED");
+            } else if ("/WrappedFilterRequest02".equals(request.getServletPath())) {
+                if (request instanceof TesterHttpServletRequestWrapper)
+                    writer.println("FilterRequest02 PASSED");
+                else
+                    writer.println("FilterRequest02 FAILED - Wrapper class is "
+                                   + request.getClass().getName());
+            }
+        }
+
+        while (true) {
+            String message = StaticLogger.read();
+            if (message == null)
+                break;
+            writer.println(message);
+        }
+        StaticLogger.reset();
+
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/FilterRequest02a.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/FilterRequest02a.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/FilterRequest02a.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,62 @@
+/*
+ * Copyright 1999, 2000, 2001 ,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tester;
+
+
+import java.io.*;
+import java.lang.reflect.*;
+import java.util.*;
+import javax.servlet.*;
+import javax.servlet.http.*;
+
+
+/**
+ * Verify that request and response wrappers added by a Filter are in fact
+ * visible to the called servlet.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class FilterRequest02a extends HttpServlet {
+
+
+    public void service(HttpServletRequest request,
+                        HttpServletResponse response)
+        throws IOException, ServletException {
+
+        response.setContentType("text/plain");
+        PrintWriter writer = response.getWriter();
+        String wrap = request.getParameter("wrap");
+
+        if ("false".equals(wrap)) {
+            if (request instanceof TesterHttpServletRequestWrapper)
+                writer.println("FilterRequest02 FAILED - Request was wrapped");
+            else
+                writer.println("FilterRequest02 PASSED");
+        } else {
+            if (request instanceof TesterHttpServletRequestWrapper)
+                writer.println("FilterRequest02 PASSED");
+            else
+                writer.println("FilterRequest02 FAILED - Wrapper class is "
+                               + request.getClass().getName());
+        }
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/FilterResponse01.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/FilterResponse01.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/FilterResponse01.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,55 @@
+/*
+ * Copyright 1999, 2000, 2001 ,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tester;
+
+
+import java.io.*;
+import java.lang.reflect.*;
+import java.util.*;
+import javax.servlet.*;
+import javax.servlet.http.*;
+
+
+/**
+ * Positive test for being able to filter output.  The output should be
+ * filtered and converted to upper case before return to the client.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class FilterResponse01 extends HttpServlet {
+
+    public void service(HttpServletRequest request,
+                        HttpServletResponse response)
+        throws IOException, ServletException {
+
+        response.setContentType("text/plain");
+        PrintWriter writer = response.getWriter();
+
+        writer.println("FilterResponse01 PASSED");
+        while (true) {
+            String message = StaticLogger.read();
+            if (message == null)
+                break;
+            writer.println(message);
+        }
+        StaticLogger.reset();
+
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/FilterResponse04.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/FilterResponse04.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/FilterResponse04.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,85 @@
+/*
+ * Copyright 1999, 2000, 2001 ,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tester;
+
+
+import java.io.*;
+import java.lang.reflect.*;
+import java.util.*;
+import javax.servlet.*;
+import javax.servlet.http.*;
+
+
+/**
+ * Verify that request and response wrappers added by a Filter are in fact
+ * visible to the called servlet.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class FilterResponse04 extends HttpServlet {
+
+    public void service(HttpServletRequest request,
+                        HttpServletResponse response)
+        throws IOException, ServletException {
+
+        response.setContentType("text/plain");
+        PrintWriter writer = response.getWriter();
+
+        String dispatch = request.getParameter("dispatch");
+        if ("F".equals(dispatch)) {
+            RequestDispatcher rd =
+                getServletContext().getRequestDispatcher("/FilterResponse04a");
+            if (rd == null)
+                writer.println("FilterResponse04 FAILED - No forward request dispatcher");
+            else
+                rd.forward(request, response);
+        } else if ("I".equals(dispatch)) {
+            RequestDispatcher rd =
+                getServletContext().getRequestDispatcher("/FilterResponse04a");
+            if (rd == null)
+                writer.println("FilterResponse04 FAILED - No include request dispatcher");
+            else
+                rd.include(request, response);
+        } else {
+            String wrap = request.getParameter("wrap");
+            if ("false".equals(wrap)) {
+                if (response instanceof TesterHttpServletResponseWrapper)
+                    writer.println("FilterResponse04 FAILED - Response was wrapped");
+                else
+                    writer.println("FilterResponse04 PASSED");
+            } else if ("/WrappedFilterResponse04".equals(request.getServletPath())) {
+                if (response instanceof TesterHttpServletResponseWrapper)
+                    writer.println("FilterResponse04 PASSED");
+                else
+                    writer.println("FilterResponse04 FAILED - Wrapper class is "
+                                   + response.getClass().getName());
+            }
+        }
+
+        while (true) {
+            String message = StaticLogger.read();
+            if (message == null)
+                break;
+            writer.println(message);
+        }
+        StaticLogger.reset();
+
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/FilterResponse04a.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/FilterResponse04a.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/FilterResponse04a.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,62 @@
+/*
+ * Copyright 1999, 2000, 2001 ,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tester;
+
+
+import java.io.*;
+import java.lang.reflect.*;
+import java.util.*;
+import javax.servlet.*;
+import javax.servlet.http.*;
+
+
+/**
+ * Verify that request and response wrappers added by a Filter are in fact
+ * visible to the called servlet.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class FilterResponse04a extends HttpServlet {
+
+
+    public void service(HttpServletRequest request,
+                        HttpServletResponse response)
+        throws IOException, ServletException {
+
+        response.setContentType("text/plain");
+        PrintWriter writer = response.getWriter();
+        String wrap = request.getParameter("wrap");
+
+        if ("false".equals(wrap)) {
+            if (response instanceof TesterHttpServletResponseWrapper)
+                writer.println("FilterResponse04 FAILED - Response was wrapped");
+            else
+                writer.println("FilterResponse04 PASSED");
+        } else {
+            if (response instanceof TesterHttpServletResponseWrapper)
+                writer.println("FilterResponse04 PASSED");
+            else
+                writer.println("FilterResponse04 FAILED - Wrapper class is "
+                               + response.getClass().getName());
+        }
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Forward00.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Forward00.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Forward00.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,75 @@
+/*
+ * Copyright 1999, 2000, 2001 ,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tester;
+
+
+import java.io.*;
+import javax.servlet.*;
+import javax.servlet.http.*;
+
+/**
+ * Exercise basic forwarding functionality.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class Forward00 extends HttpServlet {
+
+
+    public void doGet(HttpServletRequest request, HttpServletResponse response)
+        throws IOException, ServletException {
+
+        // Prepare this response
+        StringBuffer sb = new StringBuffer();
+        response.setContentType("text/plain");
+	PrintWriter writer = response.getWriter();
+
+        // Acquire the path to which we will issue a forward
+        String path = request.getParameter("path");
+        if (path == null)
+            path = "/Forward00a";
+
+        // Create a request dispatcher and call forward() on it
+        RequestDispatcher rd = null;
+        if (path.startsWith("!"))
+            rd = getServletContext().getNamedDispatcher(path.substring(1));
+        else
+            rd = getServletContext().getRequestDispatcher(path);
+        if (rd == null) {
+            sb.append(" No RequestDispatcher returned/");
+        } else {
+            if (sb.length() < 1)
+                rd.forward(request, response);
+        }
+
+        // Write our response if an error occurred
+        if (sb.length() >= 1) {
+            writer.print("Forward00 FAILED -");
+            writer.println(sb.toString());
+            while (true) {
+                String message = StaticLogger.read();
+                if (message == null)
+                    break;
+                writer.println(message);
+            }
+        }
+        StaticLogger.reset();
+
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Forward00a.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Forward00a.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Forward00a.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,54 @@
+/*
+ * Copyright 1999, 2000, 2001 ,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tester;
+
+
+import java.io.*;
+import javax.servlet.*;
+import javax.servlet.http.*;
+
+/**
+ * Exercise basic forwarding functionality.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class Forward00a extends HttpServlet {
+
+
+    public void doGet(HttpServletRequest request, HttpServletResponse response)
+        throws IOException, ServletException {
+
+        // Prepare this response
+        StringBuffer sb = new StringBuffer();
+        response.setContentType("text/plain");
+	PrintWriter writer = response.getWriter();
+
+        // Write our response if an error occurred
+        writer.print("Forward00a PASSED");
+        while (true) {
+            String message = StaticLogger.read();
+            if (message == null)
+                break;
+            writer.println(message);
+        }
+        StaticLogger.reset();
+
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Forward00d.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Forward00d.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Forward00d.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,54 @@
+/*
+ * Copyright 1999, 2000, 2001 ,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tester;
+
+
+import java.io.*;
+import javax.servlet.*;
+import javax.servlet.http.*;
+
+/**
+ * Exercise basic forwarding functionality.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class Forward00d extends HttpServlet {
+
+
+    public void doGet(HttpServletRequest request, HttpServletResponse response)
+        throws IOException, ServletException {
+
+        // Prepare this response
+        StringBuffer sb = new StringBuffer();
+        response.setContentType("text/plain");
+	PrintWriter writer = response.getWriter();
+
+        // Write our response if an error occurred
+        writer.print("Forward00d PASSED");
+        while (true) {
+            String message = StaticLogger.read();
+            if (message == null)
+                break;
+            writer.println(message);
+        }
+        StaticLogger.reset();
+
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Forward01.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Forward01.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Forward01.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,50 @@
+/*
+ * Copyright 1999, 2000 ,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tester;
+
+
+import java.io.*;
+import java.security.Principal;
+import javax.servlet.*;
+import javax.servlet.http.*;
+
+/**
+ * Positive test for forwarding to a static resource.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class Forward01 extends HttpServlet {
+
+    public void doGet(HttpServletRequest request, HttpServletResponse response)
+        throws IOException, ServletException {
+
+        response.setContentType("text/plain");
+        RequestDispatcher rd =
+            getServletContext().getRequestDispatcher("/Forward01.txt");
+        if (rd == null) {
+            PrintWriter writer = response.getWriter();
+            writer.println("Forward01 FAILED - No RequestDispatcher returned");
+            return;
+        }
+        rd.forward(request, response);
+        StaticLogger.reset();
+
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Forward03.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Forward03.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Forward03.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,82 @@
+/*
+ * Copyright 1999, 2000, 2001 ,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tester;
+
+
+import java.io.*;
+import javax.servlet.*;
+import javax.servlet.http.*;
+
+/**
+ * Test to ensure that a forwarded-to servlet can receive request attributes
+ * set by the calling servlet, as well as set their own request attributes.
+ *
+ * The test forwards to either a servlet ("/Forward03a") or a JSP page
+ * ("/Forward03b.jsp") depending on the value specified for the "path"
+ * parameter.  The default is the servlet.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class Forward03 extends HttpServlet {
+
+
+    public void doGet(HttpServletRequest request, HttpServletResponse response)
+        throws IOException, ServletException {
+
+        // Prepare this response
+        StringBuffer sb = new StringBuffer();
+        response.setContentType("text/plain");
+	PrintWriter writer = response.getWriter();
+
+        // Acquire the path to which we will issue a forward
+        String path = request.getParameter("path");
+        if (path == null)
+            path = "/Forward03a";
+
+        // Write the request attribute we will be forwarding
+        request.setAttribute("Forward03", "This is the forwarded attribute");
+        if (request.getAttribute("Forward03") == null)
+            sb.append(" Cannot retrieve attribute to forward/");
+
+        // Create a request dispatcher and call forward() on it
+        RequestDispatcher rd =
+            getServletContext().getRequestDispatcher(path);
+        if (rd == null) {
+            sb.append(" No RequestDispatcher returned/");
+        } else {
+            if (sb.length() < 1)
+                rd.forward(request, response);
+        }
+
+        // Write our response if an error occurred
+        if (sb.length() >= 1) {
+            writer.print("Include03 FAILED -");
+            writer.println(sb.toString());
+            while (true) {
+                String message = StaticLogger.read();
+                if (message == null)
+                    break;
+                writer.println(message);
+            }
+        }
+        StaticLogger.reset();
+
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Forward03a.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Forward03a.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Forward03a.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,90 @@
+/*
+ * Copyright 1999, 2000, 2001 ,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tester;
+
+
+import java.io.*;
+import javax.servlet.*;
+import javax.servlet.http.*;
+
+/**
+ * Test to ensure that a forwarded-to servlet can receive request attributes
+ * set by the calling servlet, as well as set their own request attributes.
+ *
+ * The test forwards to either a servlet ("/Forward03a") or a JSP page
+ * ("/Forward03b.jsp") depending on the value specified for the "path"
+ * parameter.  The default is the servlet.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class Forward03a extends HttpServlet {
+
+    private static final String specials[] =
+    { "javax.servlet.include.request_uri",
+      "javax.servlet.include.context_path",
+      "javax.servlet.include.servlet_path",
+      "javax.servlet.include.path_info",
+      "javax.servlet.include.query_string" };
+
+
+    public void doGet(HttpServletRequest request, HttpServletResponse response)
+        throws IOException, ServletException {
+
+        // Prepare this response
+        StringBuffer sb = new StringBuffer();
+        response.setContentType("text/plain");
+	PrintWriter writer = response.getWriter();
+
+        // Verify that we can retrieve the forwarded attribute
+        if (request.getAttribute("Forward03") == null)
+            sb.append(" Cannot retrieve forwarded attribute/");
+
+        // Verify that we can set and retrieve our own attribute
+        request.setAttribute("Forward03a", "This is our own attribute");
+        if (request.getAttribute("Forward03a") == null)
+            sb.append(" Cannot retrieve our own attribute");
+
+        // Verify that no special attributes are present
+        for (int i = 0; i < specials.length; i++) {
+            if (request.getAttribute(specials[i]) != null) {
+                sb.append(" Returned attribute ");
+                sb.append(specials[i]);
+                sb.append("/");
+            }
+        }
+
+        // Write our response
+        if (sb.length() < 1)
+            writer.println("Forward03 PASSED");
+        else {
+            writer.print("Forward03 FAILED -");
+            writer.println(sb.toString());
+        }
+
+        while (true) {
+            String message = StaticLogger.read();
+            if (message == null)
+                break;
+            writer.println(message);
+        }
+        StaticLogger.reset();
+
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Forward04.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Forward04.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Forward04.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,62 @@
+/*
+ * Copyright 1999, 2000, 2001 ,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tester;
+
+
+import java.io.*;
+import javax.servlet.*;
+import javax.servlet.http.*;
+
+/**
+ * Testing for double forwarding.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class Forward04 extends HttpServlet {
+
+    public void doGet(HttpServletRequest request, HttpServletResponse response)
+        throws IOException, ServletException {
+
+        // Prepare this response
+        response.setContentType("text/plain");
+        PrintWriter writer = response.getWriter();
+
+        // Forward to the first servlet
+        RequestDispatcher rd =
+            getServletContext().getRequestDispatcher("/Forward04a");
+        if (rd == null) {
+            writer.println("Forward04 FAILED - No request dispatcher" +
+                           " for /Forward04a");
+        } else {
+            rd.forward(request, response);
+            writer.println("Forward04 text should NOT be present");
+        }
+
+        // Static logger output (should not actually be rendered)
+        while (true) {
+            String message = StaticLogger.read();
+            if (message == null)
+                break;
+            writer.println(message);
+        }
+        StaticLogger.reset();
+
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Forward04a.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Forward04a.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Forward04a.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,53 @@
+/*
+ * Copyright 1999, 2000, 2001 ,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tester;
+
+
+import java.io.*;
+import javax.servlet.*;
+import javax.servlet.http.*;
+
+/**
+ * Testing for double forwarding.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class Forward04a extends HttpServlet {
+
+    public void doGet(HttpServletRequest request, HttpServletResponse response)
+        throws IOException, ServletException {
+
+        // Prepare this response
+        response.setContentType("text/plain");
+        PrintWriter writer = response.getWriter();
+
+        // Forward to the second servlet
+        RequestDispatcher rd =
+            getServletContext().getRequestDispatcher("/Forward04b");
+        if (rd == null) {
+            writer.println("Forward04a FAILED - No request dispatcher" +
+                           " for /Forward04b");
+        } else {
+            rd.forward(request, response);
+            writer.println("Forward04a text should NOT be present");
+        }
+
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Forward04b.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Forward04b.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Forward04b.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,43 @@
+/*
+ * Copyright 1999, 2000, 2001 ,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tester;
+
+
+import java.io.*;
+import javax.servlet.*;
+import javax.servlet.http.*;
+
+/**
+ * Testing for double forwarding.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class Forward04b extends HttpServlet {
+
+    public void doGet(HttpServletRequest request, HttpServletResponse response)
+        throws IOException, ServletException {
+
+        // Prepare this response
+        response.setContentType("text/plain");
+        PrintWriter writer = response.getWriter();
+        writer.println("Forward04b PASSED");
+
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Forward05.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Forward05.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Forward05.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,62 @@
+/*
+ * Copyright 1999, 2000, 2001 ,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tester;
+
+
+import java.io.*;
+import javax.servlet.*;
+import javax.servlet.http.*;
+
+/**
+ * Testing for double forwarding.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class Forward05 extends HttpServlet {
+
+    public void doGet(HttpServletRequest request, HttpServletResponse response)
+        throws IOException, ServletException {
+
+        // Prepare this response
+        response.setContentType("text/plain");
+        PrintWriter writer = response.getWriter();
+
+        // Forward to the first servlet
+        RequestDispatcher rd =
+            getServletContext().getRequestDispatcher("/Forward05a.jsp");
+        if (rd == null) {
+            writer.println("Forward05 FAILED - No request dispatcher" +
+                           " for /Forward05a.jsp");
+        } else {
+            rd.forward(request, response);
+            writer.println("Forward05 text should NOT be present");
+        }
+
+        // Static logger output (should not actually be rendered)
+        while (true) {
+            String message = StaticLogger.read();
+            if (message == null)
+                break;
+            writer.println(message);
+        }
+        StaticLogger.reset();
+
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Forward05a.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Forward05a.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Forward05a.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,53 @@
+/*
+ * Copyright 1999, 2000, 2001 ,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tester;
+
+
+import java.io.*;
+import javax.servlet.*;
+import javax.servlet.http.*;
+
+/**
+ * Testing for double forwarding.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class Forward05a extends HttpServlet {
+
+    public void doGet(HttpServletRequest request, HttpServletResponse response)
+        throws IOException, ServletException {
+
+        // Prepare this response
+        response.setContentType("text/plain");
+        PrintWriter writer = response.getWriter();
+
+        // Forward to the second servlet
+        RequestDispatcher rd =
+            getServletContext().getRequestDispatcher("/Forward05b.jsp");
+        if (rd == null) {
+            writer.println("Forward05a FAILED - No request dispatcher" +
+                           " for /Forward05b.jsp");
+        } else {
+            rd.forward(request, response);
+            writer.println("Forward05a text should NOT be present");
+        }
+
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Forward05b.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Forward05b.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Forward05b.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,43 @@
+/*
+ * Copyright 1999, 2000, 2001 ,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tester;
+
+
+import java.io.*;
+import javax.servlet.*;
+import javax.servlet.http.*;
+
+/**
+ * Testing for double forwarding.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class Forward05b extends HttpServlet {
+
+    public void doGet(HttpServletRequest request, HttpServletResponse response)
+        throws IOException, ServletException {
+
+        // Prepare this response
+        response.setContentType("text/plain");
+        PrintWriter writer = response.getWriter();
+        writer.println("Forward05b PASSED");
+
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Forward06.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Forward06.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Forward06.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,62 @@
+/*
+ * Copyright 1999, 2000, 2001 ,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tester;
+
+
+import java.io.*;
+import javax.servlet.*;
+import javax.servlet.http.*;
+
+/**
+ * Testing for double forwarding.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class Forward06 extends HttpServlet {
+
+    public void doGet(HttpServletRequest request, HttpServletResponse response)
+        throws IOException, ServletException {
+
+        // Prepare this response
+        response.setContentType("text/plain");
+        PrintWriter writer = response.getWriter();
+
+        // Forward to the first servlet
+        RequestDispatcher rd =
+            getServletContext().getRequestDispatcher("/Forward06a.jsp");
+        if (rd == null) {
+            writer.println("Forward05 FAILED - No request dispatcher" +
+                           " for /Forward06a.jsp");
+        } else {
+            rd.forward(request, response);
+            writer.println("Forward06 text should NOT be present");
+        }
+
+        // Static logger output (should not actually be rendered)
+        while (true) {
+            String message = StaticLogger.read();
+            if (message == null)
+                break;
+            writer.println(message);
+        }
+        StaticLogger.reset();
+
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Forward06a.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Forward06a.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Forward06a.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,53 @@
+/*
+ * Copyright 1999, 2000, 2001 ,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tester;
+
+
+import java.io.*;
+import javax.servlet.*;
+import javax.servlet.http.*;
+
+/**
+ * Testing for double forwarding.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class Forward06a extends HttpServlet {
+
+    public void doGet(HttpServletRequest request, HttpServletResponse response)
+        throws IOException, ServletException {
+
+        // Prepare this response
+        response.setContentType("text/plain");
+        PrintWriter writer = response.getWriter();
+
+        // Forward to the second servlet
+        RequestDispatcher rd =
+            getServletContext().getRequestDispatcher("/Forward06b.jsp");
+        if (rd == null) {
+            writer.println("Forward06a FAILED - No request dispatcher" +
+                           " for /Forward06b.jsp");
+        } else {
+            rd.forward(request, response);
+            writer.println("Forward06a text should NOT be present");
+        }
+
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Forward06b.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Forward06b.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Forward06b.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,43 @@
+/*
+ * Copyright 1999, 2000, 2001 ,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tester;
+
+
+import java.io.*;
+import javax.servlet.*;
+import javax.servlet.http.*;
+
+/**
+ * Testing for double forwarding.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class Forward06b extends HttpServlet {
+
+    public void doGet(HttpServletRequest request, HttpServletResponse response)
+        throws IOException, ServletException {
+
+        // Prepare this response
+        response.setContentType("text/plain");
+        PrintWriter writer = response.getWriter();
+        writer.println("Forward06b PASSED");
+
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Forward07.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Forward07.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Forward07.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,62 @@
+/*
+ * Copyright 1999, 2000, 2001 ,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tester;
+
+
+import java.io.*;
+import javax.servlet.*;
+import javax.servlet.http.*;
+
+/**
+ * Testing for double forwarding.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class Forward07 extends HttpServlet {
+
+    public void doGet(HttpServletRequest request, HttpServletResponse response)
+        throws IOException, ServletException {
+
+        // Prepare this response
+        response.setContentType("text/plain");
+        PrintWriter writer = response.getWriter();
+
+        // Forward to the first servlet
+        RequestDispatcher rd =
+            getServletContext().getRequestDispatcher("/servlet/Forward07a");
+        if (rd == null) {
+            writer.println("Forward07 FAILED - No request dispatcher" +
+                           " for /servlet/Forward07a");
+        } else {
+            rd.forward(request, response);
+            writer.println("Forward07 text should NOT be present");
+        }
+
+        // Static logger output (should not actually be rendered)
+        while (true) {
+            String message = StaticLogger.read();
+            if (message == null)
+                break;
+            writer.println(message);
+        }
+        StaticLogger.reset();
+
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Forward07a.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Forward07a.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Forward07a.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,53 @@
+/*
+ * Copyright 1999, 2000, 2001 ,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tester;
+
+
+import java.io.*;
+import javax.servlet.*;
+import javax.servlet.http.*;
+
+/**
+ * Testing for double forwarding.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class Forward07a extends HttpServlet {
+
+    public void doGet(HttpServletRequest request, HttpServletResponse response)
+        throws IOException, ServletException {
+
+        // Prepare this response
+        response.setContentType("text/plain");
+        PrintWriter writer = response.getWriter();
+
+        // Forward to the second servlet
+        RequestDispatcher rd =
+            getServletContext().getRequestDispatcher("/Forward07b");
+        if (rd == null) {
+            writer.println("Forward07a FAILED - No request dispatcher" +
+                           " for /Forward07b");
+        } else {
+            rd.forward(request, response);
+            writer.println("Forward07a text should NOT be present");
+        }
+
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Forward07b.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Forward07b.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Forward07b.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,43 @@
+/*
+ * Copyright 1999, 2000, 2001 ,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tester;
+
+
+import java.io.*;
+import javax.servlet.*;
+import javax.servlet.http.*;
+
+/**
+ * Testing for double forwarding.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class Forward07b extends HttpServlet {
+
+    public void doGet(HttpServletRequest request, HttpServletResponse response)
+        throws IOException, ServletException {
+
+        // Prepare this response
+        response.setContentType("text/plain");
+        PrintWriter writer = response.getWriter();
+        writer.println("Forward07b PASSED");
+
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Forward08.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Forward08.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Forward08.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,66 @@
+/*
+ * Copyright 1999, 2000, 2001 ,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tester;
+
+
+import java.io.*;
+import javax.servlet.*;
+import javax.servlet.http.*;
+
+/**
+ * Testing for double forwarding.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class Forward08 extends HttpServlet {
+
+    public void doGet(HttpServletRequest request, HttpServletResponse response)
+        throws IOException, ServletException {
+
+        // Prepare this response
+        response.setContentType("text/plain");
+        PrintWriter writer = response.getWriter();
+
+        // Forward to the first servlet
+        log("Getting RD for /Forward08a");
+        RequestDispatcher rd =
+            getServletContext().getRequestDispatcher("/Forward08a");
+        if (rd == null) {
+            log("Missing RD for /Forward08a");
+            writer.println("Forward08 FAILED - No request dispatcher" +
+                           " for /Forward08a");
+        } else {
+            log("Forwarding to /Forward08a");
+            rd.forward(request, response);
+            log("Returned from /Forward08a");
+            writer.println("Forward08 text should NOT be present");
+        }
+
+        // Static logger output (should not actually be rendered)
+        while (true) {
+            String message = StaticLogger.read();
+            if (message == null)
+                break;
+            writer.println(message);
+        }
+        StaticLogger.reset();
+
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Forward08a.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Forward08a.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Forward08a.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,57 @@
+/*
+ * Copyright 1999, 2000, 2001 ,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tester;
+
+
+import java.io.*;
+import javax.servlet.*;
+import javax.servlet.http.*;
+
+/**
+ * Testing for double forwarding.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class Forward08a extends HttpServlet {
+
+    public void doGet(HttpServletRequest request, HttpServletResponse response)
+        throws IOException, ServletException {
+
+        // Prepare this response
+        response.setContentType("text/plain");
+        PrintWriter writer = response.getWriter();
+
+        // Forward to the second servlet
+        log("Getting RD for /servlet/Forward08b");
+        RequestDispatcher rd =
+            getServletContext().getRequestDispatcher("/servlet/Forward08b");
+        if (rd == null) {
+            log("Missing RD for /servlet/Forward08b");
+            writer.println("Forward08a FAILED - No request dispatcher" +
+                           " for /servlet/Forward08b");
+        } else {
+            log("Forwarding to /servlet/Forward08b");
+            rd.forward(request, response);
+            log("Returned from /servlet/Forward08b");
+            writer.println("Forward08a text should NOT be present");
+        }
+
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Forward08b.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Forward08b.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Forward08b.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,43 @@
+/*
+ * Copyright 1999, 2000, 2001 ,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tester;
+
+
+import java.io.*;
+import javax.servlet.*;
+import javax.servlet.http.*;
+
+/**
+ * Testing for double forwarding.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class Forward08b extends HttpServlet {
+
+    public void doGet(HttpServletRequest request, HttpServletResponse response)
+        throws IOException, ServletException {
+
+        // Prepare this response
+        response.setContentType("text/plain");
+        PrintWriter writer = response.getWriter();
+        writer.println("Forward08b PASSED");
+
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Forward09.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Forward09.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Forward09.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,72 @@
+/*
+ * Copyright 1999, 2000, 2001 ,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tester;
+
+
+import java.io.*;
+import javax.servlet.*;
+import javax.servlet.http.*;
+
+/**
+ * Exercise basic forwarding functionality using
+ * <code>request.getRequestDispatcher()</code>.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class Forward09 extends HttpServlet {
+
+
+    public void doGet(HttpServletRequest request, HttpServletResponse response)
+        throws IOException, ServletException {
+
+        // Prepare this response
+        StringBuffer sb = new StringBuffer();
+        response.setContentType("text/plain");
+	PrintWriter writer = response.getWriter();
+
+        // Acquire the path to which we will issue a forward
+        String path = request.getParameter("path");
+        if (path == null)
+            path = "/Forward00a";
+
+        // Create a request dispatcher and call forward() on it
+        RequestDispatcher rd = request.getRequestDispatcher(path);
+        if (rd == null) {
+            sb.append(" No RequestDispatcher returned/");
+        } else {
+            if (sb.length() < 1)
+                rd.forward(request, response);
+        }
+
+        // Write our response if an error occurred
+        if (sb.length() >= 1) {
+            writer.print("Forward09 FAILED -");
+            writer.println(sb.toString());
+            while (true) {
+                String message = StaticLogger.read();
+                if (message == null)
+                    break;
+                writer.println(message);
+            }
+        }
+        StaticLogger.reset();
+
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/GetHeaders01.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/GetHeaders01.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/GetHeaders01.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,84 @@
+/*
+ * Copyright 1999, 2000 ,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tester;
+
+
+import java.io.*;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import javax.servlet.*;
+import javax.servlet.http.*;
+
+/**
+ * Test retrieval of headers.  The client is expected to send two
+ * "Accept-Language" headers.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class GetHeaders01 extends HttpServlet {
+
+    public void doGet(HttpServletRequest request, HttpServletResponse response)
+        throws IOException, ServletException {
+
+        response.setContentType("text/plain");
+        PrintWriter writer = response.getWriter();
+        ArrayList values = new ArrayList();
+        Enumeration headers = request.getHeaders("Accept-Language");
+        while (headers.hasMoreElements()) {
+            String header = (String) headers.nextElement() + ",";
+            while (true) {
+                int comma = header.indexOf(",");
+                if (comma < 0)
+                    break;
+                String value = header.substring(0, comma).trim();
+                values.add(value);
+                header = header.substring(comma + 1).trim();
+            }
+        }
+        if (values.size() != 2)
+            writer.println("GetHeaders01 FAILED - Returned " + values.size()
+                           + " headers instead of 2");
+        else if (values.get(0) == values.get(1))
+            writer.println("GetHeaders01 FAILED - Returned identical values "
+                           + values.get(0));
+        else {
+            int n = 0;
+            for (int i = 0; i < values.size(); i++) {
+                if ("en-us".equals((String) values.get(i)))
+                    n++;
+                else if ("en-gb".equals((String) values.get(i)))
+                    n++;
+            }
+            if (n != 2)
+                writer.println("GetHeaders01 FAILED - Returned unknown values "
+                               + values.get(0) + " and " + values.get(1));
+            else
+                writer.println("GetHeaders01 PASSED");
+        }
+        while (true) {
+            String message = StaticLogger.read();
+            if (message == null)
+                break;
+            writer.println(message);
+        }
+        StaticLogger.reset();
+
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/GetInputStream01.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/GetInputStream01.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/GetInputStream01.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,57 @@
+/*
+ * Copyright 1999, 2000 ,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tester;
+
+
+import java.io.*;
+import javax.servlet.*;
+import javax.servlet.http.*;
+
+/**
+ * Test getting the servlet input stream after we have retrieved the reader.
+ * This should throw an IllegalStateException.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class GetInputStream01 extends GenericServlet {
+
+    public void service(ServletRequest request, ServletResponse response)
+        throws IOException, ServletException {
+
+        response.setContentType("text/plain");
+        PrintWriter writer = response.getWriter();
+        BufferedReader reader = request.getReader();
+        try {
+            ServletInputStream sis = request.getInputStream();
+            writer.println("GetInputStream01 FAILED - Did not throw " +
+                           "IllegalStateException");
+        } catch (IllegalStateException e) {
+            writer.println("GetInputStream01 PASSED");
+        }
+        while (true) {
+            String message = StaticLogger.read();
+            if (message == null)
+                break;
+            writer.println(message);
+        }
+        StaticLogger.reset();
+
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/GetLocales01.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/GetLocales01.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/GetLocales01.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,65 @@
+/*
+ * Copyright 1999, 2000, 2001 ,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tester;
+
+
+import java.io.*;
+import java.util.*;
+import javax.servlet.*;
+import javax.servlet.http.*;
+
+/**
+ * Part 1 of the request locale tests.  Should receive a Locale that
+ * corresponds to "en_CA" Accept-Language header that is sent first.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class GetLocales01 extends HttpServlet {
+
+
+    public void doGet(HttpServletRequest request, HttpServletResponse response)
+        throws IOException, ServletException {
+
+        response.reset();
+        response.setContentType("text/plain");
+        PrintWriter writer = response.getWriter();
+
+        Locale expected = new Locale("en", "CA");
+        Locale received = request.getLocale();
+        if (received == null)
+            writer.println("GetLocales01 FAILED - No locale was received");
+        else if (!expected.equals(received))
+            writer.println("GetLocales01 FAILED - Expected='" +
+                           expected.toString() + "' Received='" +
+                           received.toString() + "'");
+        else
+            writer.println("GetLocales01 PASSED");
+
+        while (true) {
+            String message = StaticLogger.read();
+            if (message == null)
+                break;
+            writer.println(message);
+        }
+        StaticLogger.reset();
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/GetLocales02.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/GetLocales02.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/GetLocales02.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,108 @@
+/*
+ * Copyright 1999, 2000, 2001 ,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tester;
+
+
+import java.io.*;
+import java.util.*;
+import javax.servlet.*;
+import javax.servlet.http.*;
+
+/**
+ * Part 2 of the request locale tests.  Should receive a Locale that
+ * corresponds to "en_CA" and then "en_GB" as sent by the client in
+ * "Accept-Language" headers.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class GetLocales02 extends HttpServlet {
+
+
+    public void doGet(HttpServletRequest request, HttpServletResponse response)
+        throws IOException, ServletException {
+
+        response.reset();
+        response.setContentType("text/plain");
+        PrintWriter writer = response.getWriter();
+        StringBuffer sb = new StringBuffer();
+        boolean ok = true;
+
+        Enumeration locales = request.getLocales();
+        if (locales == null) {
+            sb.append(" No locales returned/");
+            ok = false;
+        }
+
+        if (ok) {
+            if (locales.hasMoreElements()) {
+                Locale expected = new Locale("en", "CA");
+                Locale received = (Locale) locales.nextElement();
+                if (!expected.equals(received)) {
+                    sb.append(" Expected1='" +
+                           expected.toString() + "' Received1='" +
+                           received.toString() + "'");
+                }
+            } else {
+                sb.append(" Zero locales returned/");
+                ok = false;
+            }
+        }
+
+        if (ok) {
+            if (locales.hasMoreElements()) {
+                Locale expected = new Locale("en", "GB");
+                Locale received = (Locale) locales.nextElement();
+                if (!expected.equals(received)) {
+                    sb.append(" Expected2='" +
+                           expected.toString() + "' Received2='" +
+                           received.toString() + "'");
+                }
+            } else {
+                sb.append(" One locale returned/");
+                ok = false;
+            }
+        }
+
+        if (ok) {
+            if (locales.hasMoreElements()) {
+                sb.append(" More than two locales returned/");
+                ok = false;
+            }
+        }
+
+        if (ok && (sb.length() < 1)) {
+            writer.println("GetLocales02 PASSED");
+        } else {
+            writer.print("GetLocales02 FAILED -");
+            writer.println(sb.toString());
+        }
+
+
+        while (true) {
+            String message = StaticLogger.read();
+            if (message == null)
+                break;
+            writer.println(message);
+        }
+        StaticLogger.reset();
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/GetParameter01.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/GetParameter01.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/GetParameter01.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,57 @@
+/*
+ * Copyright 1999, 2000 ,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tester;
+
+
+import java.io.*;
+import javax.servlet.*;
+import javax.servlet.http.*;
+
+/**
+ * Test retrieval of parameters.  The client is expected to send a request
+ * URI like "/tester/GetParameter01?foo=1".
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class GetParameter01 extends GenericServlet {
+
+    public void service(ServletRequest request, ServletResponse response)
+        throws IOException, ServletException {
+
+        response.setContentType("text/plain");
+        PrintWriter writer = response.getWriter();
+        String expected = "1";
+        String result = request.getParameter("foo");
+        if (expected.equals(result)) {
+            writer.println("GetParameter01 PASSED");
+        } else {
+            writer.println("GetParameter01 FAILED - Received '" + result +
+                           "' instead of '" + expected + "'");
+        }
+        while (true) {
+            String message = StaticLogger.read();
+            if (message == null)
+                break;
+            writer.println(message);
+        }
+        StaticLogger.reset();
+
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/GetParameterMap00.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/GetParameterMap00.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/GetParameterMap00.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,86 @@
+/*
+ * Copyright 1999, 2000 ,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tester;
+
+
+import java.io.*;
+import java.util.Map;
+import javax.servlet.*;
+import javax.servlet.http.*;
+
+/**
+ * Test getting the servlet input stream after we have retrieved the reader.
+ * This should throw an IllegalStateException.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class GetParameterMap00 extends GenericServlet {
+
+    public void service(ServletRequest request, ServletResponse response)
+        throws IOException, ServletException {
+
+        response.setContentType("text/plain");
+        PrintWriter writer = response.getWriter();
+        String errors = "";
+        Map map = request.getParameterMap();
+        if (map == null)
+            errors += "  getParameterMap() returned null.";
+        else {
+            if (map.size() != 2)
+                errors += "  map size is " + map.size() + ".";
+            String value1[] = (String[]) map.get("BestLanguage");
+            if (value1 == null)
+                errors += "  BestLanguage is NULL.";
+            else if (value1.length != 1)
+                errors += "  BestLanguage has " + value1.length + " values.";
+            else if (!value1[0].equals("Java"))
+                errors += "  BestLanguage is " + value1 + ".";
+            String value2[] = (String[]) map.get("BestJSP");
+            if (value2 == null)
+                errors += "  BestJSP is NULL.";
+            else if (value2.length != 1)
+                errors += "  BestJSP has " + value2.length + " values.";
+            else if (!value2[0].equals("Java2"))
+                errors += "  BestJSP is " + value2 + ".";
+            try {
+                map.put("ABC", "XYZ");
+                errors += "   map.put() was allowed.";
+                if (map.get("ABC") != null)
+                    errors += "  map is not immutable.";
+            } catch (Throwable t) {
+                ;
+            }
+        }
+
+        if (errors.equals(""))
+            writer.println("GetParameterMap00 PASSED");
+        else {
+            writer.println("GetParameterMap00 FAILED:" + errors);
+        }
+        while (true) {
+            String message = StaticLogger.read();
+            if (message == null)
+                break;
+            writer.println(message);
+        }
+        StaticLogger.reset();
+
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/GetQueryString01.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/GetQueryString01.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/GetQueryString01.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,57 @@
+/*
+ * Copyright 1999, 2000 ,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tester;
+
+
+import java.io.*;
+import javax.servlet.*;
+import javax.servlet.http.*;
+
+/**
+ * Test retrieval of query string.  The client is expected to send a request
+ * URI like "/tester/GetQueryString01?foo=1".
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class GetQueryString01 extends HttpServlet {
+
+    public void doGet(HttpServletRequest request, HttpServletResponse response)
+        throws IOException, ServletException {
+
+        response.setContentType("text/plain");
+        PrintWriter writer = response.getWriter();
+        String expected = "foo=1";
+        String result = request.getQueryString();
+        if (expected.equals(result)) {
+            writer.println("GetQueryString01 PASSED");
+        } else {
+            writer.println("GetQueryString01 FAILED - Received '" + result +
+                           "' instead of '" + expected + "'");
+        }
+        while (true) {
+            String message = StaticLogger.read();
+            if (message == null)
+                break;
+            writer.println(message);
+        }
+        StaticLogger.reset();
+
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Golden01.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Golden01.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Golden01.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,48 @@
+/*
+ * Copyright 1999, 2000, 2001 ,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tester;
+
+
+import java.io.*;
+import javax.servlet.*;
+import javax.servlet.http.*;
+
+/**
+ * Simple test for the golden file mechanism.  This test generates a response
+ * with known contents for comparison to the golden file.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class Golden01 extends HttpServlet {
+
+
+    public void doGet(HttpServletRequest request, HttpServletResponse response)
+        throws IOException, ServletException {
+
+        response.setContentType("text/plain");
+        PrintWriter writer = response.getWriter();
+
+        writer.println("This is the");
+        writer.println("first golden file");
+        writer.println("to be tested.");
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Include00.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Include00.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Include00.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,92 @@
+/*
+ * Copyright 1999, 2000, 2001 ,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tester;
+
+
+import java.io.*;
+import javax.servlet.*;
+import javax.servlet.http.*;
+
+/**
+ * Exercise basic including functionality.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class Include00 extends HttpServlet {
+
+
+    public void doGet(HttpServletRequest request, HttpServletResponse response)
+        throws IOException, ServletException {
+
+        // Prepare this response
+        StringBuffer sb = new StringBuffer();
+        response.setContentType("text/plain");
+	PrintWriter writer = response.getWriter();
+
+        // Acquire the path to which we will issue a include
+        String path = request.getParameter("path");
+        if (path == null)
+            path = "/Include00a";
+
+        // Acquire the flush flag
+        boolean flush = "true".equals(request.getParameter("flush"));
+
+        // Acquire the "create a session" flag
+        boolean create = "true".equals(request.getParameter("create"));
+
+        // Create a request dispatcher and call include() on it
+        RequestDispatcher rd = null;
+        if (path.startsWith("!"))
+            rd = getServletContext().getNamedDispatcher(path.substring(1));
+        else
+            rd = getServletContext().getRequestDispatcher(path);
+        if (rd == null) {
+            sb.append(" No RequestDispatcher returned/");
+        } else {
+            HttpSession session;
+            if (create) {
+                session = request.getSession();
+            }
+            if (flush) {
+                try {
+                    response.flushBuffer();
+                } catch (IOException e) {
+                    sb.append(" Flush threw IOException/");
+                }
+            }
+            if (sb.length() < 1)
+                rd.include(request, response);
+        }
+
+        // Write our response if an error occurred
+        if (sb.length() >= 1) {
+            writer.print("Include00 FAILED -");
+            writer.println(sb.toString());
+            while (true) {
+                String message = StaticLogger.read();
+                if (message == null)
+                    break;
+                writer.println(message);
+            }
+        }
+        StaticLogger.reset();
+
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Include00a.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Include00a.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Include00a.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,54 @@
+/*
+ * Copyright 1999, 2000, 2001 ,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tester;
+
+
+import java.io.*;
+import javax.servlet.*;
+import javax.servlet.http.*;
+
+/**
+ * Exercise basic including functionality.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class Include00a extends HttpServlet {
+
+
+    public void doGet(HttpServletRequest request, HttpServletResponse response)
+        throws IOException, ServletException {
+
+        // Prepare this response
+        StringBuffer sb = new StringBuffer();
+        response.setContentType("text/plain");
+	PrintWriter writer = response.getWriter();
+
+        // Write our response if an error occurred
+        writer.print("Include00a PASSED");
+        while (true) {
+            String message = StaticLogger.read();
+            if (message == null)
+                break;
+            writer.println(message);
+        }
+        StaticLogger.reset();
+
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Include00d.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Include00d.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Include00d.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,54 @@
+/*
+ * Copyright 1999, 2000, 2001 ,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tester;
+
+
+import java.io.*;
+import javax.servlet.*;
+import javax.servlet.http.*;
+
+/**
+ * Exercise basic including functionality.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class Include00d extends HttpServlet {
+
+
+    public void doGet(HttpServletRequest request, HttpServletResponse response)
+        throws IOException, ServletException {
+
+        // Prepare this response
+        StringBuffer sb = new StringBuffer();
+        response.setContentType("text/plain");
+	PrintWriter writer = response.getWriter();
+
+        // Write our response if an error occurred
+        writer.print("Include00d PASSED");
+        while (true) {
+            String message = StaticLogger.read();
+            if (message == null)
+                break;
+            writer.println(message);
+        }
+        StaticLogger.reset();
+
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Include01.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Include01.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Include01.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,50 @@
+/*
+ * Copyright 1999, 2000 ,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tester;
+
+
+import java.io.*;
+import java.security.Principal;
+import javax.servlet.*;
+import javax.servlet.http.*;
+
+/**
+ * Positive test for including a static resource.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class Include01 extends HttpServlet {
+
+    public void doGet(HttpServletRequest request, HttpServletResponse response)
+        throws IOException, ServletException {
+
+        response.setContentType("text/plain");
+        RequestDispatcher rd =
+            getServletContext().getRequestDispatcher("/Include01.txt");
+        if (rd == null) {
+            PrintWriter writer = response.getWriter();
+            writer.println("Include01 FAILED - No RequestDispatcher returned");
+            return;
+        }
+        rd.include(request, response);
+        StaticLogger.reset();
+
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Include02.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Include02.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Include02.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,128 @@
+/*
+ * Copyright 1999, 2000 ,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tester;
+
+
+import java.io.*;
+import javax.servlet.*;
+import javax.servlet.http.*;
+
+/**
+ * Positive test for handling exceptions thrown by an included servlet.
+ * Request parameter <strong>exception</strong> is used to indicate the type
+ * of exception that should be thrown, which must be one of
+ * <code>IOException</code>, <code>ServletException</code>, or
+ * <code>ServletException</code>.  According to the spec, any exceptions of
+ * these types should be propogated back to the caller unchanged.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class Include02 extends HttpServlet {
+
+    public void doGet(HttpServletRequest request, HttpServletResponse response)
+        throws IOException, ServletException {
+
+        boolean ok = true;
+        response.setContentType("text/plain");
+	PrintWriter writer = response.getWriter();
+        RequestDispatcher rd =
+            getServletContext().getRequestDispatcher("/Include02a");
+        if (rd == null) {
+            writer.println("Include02 FAILED - No RequestDispatcher returned");
+	    ok = false;
+        }
+	String type = request.getParameter("exception");
+	if (ok) {
+	    if (type == null) {
+	        writer.println("Include02 FAILED - No exception type specified");
+		ok = false;
+	    } else if (!type.equals("IOException") &&
+		       !type.equals("ServletException") &&
+		       !type.equals("NullPointerException")) {
+	        writer.println("Include02 FAILED - Invalid exception type " +
+			       type + " requested");
+		ok = false;
+	    }
+	}
+
+	IOException ioException = null;
+	ServletException servletException = null;
+	Throwable throwable = null;
+	try {
+            if (ok)
+                rd.include(request, response);
+	} catch (IOException e) {
+	    ioException = e;
+	} catch (ServletException e) {
+	    servletException = e;
+	} catch (Throwable e) {
+	    throwable = e;
+	}
+
+	if (ok) {
+            if (type.equals("IOException")) {
+                if (ioException == null) {
+		    writer.println("Include02 FAILED - No IOException thrown");
+		    ok = false;
+		} else {
+		    String message = ioException.getMessage();
+		    if (!"Include02 IOException".equals(message)) {
+		        writer.println("Include02 FAILED - IOException was " +
+				       message);
+			ok = false;
+		    }
+		}
+	    } else if (type.equals("ServletException")) {
+                if (servletException == null) {
+		    writer.println("Include02 FAILED - No ServletException thrown");
+		    ok = false;
+		} else {
+		    String message = servletException.getMessage();
+		    if (!"Include02 ServletException".equals(message)) {
+		        writer.println("Include02 FAILED - ServletException was " +
+				       message);
+			ok = false;
+		    }
+		}
+	    } else if (type.equals("NullPointerException")) {
+                if (throwable == null) {
+		    writer.println("Include02 FAILED - No NullPointerException thrown");
+		    ok = false;
+		} else if (!(throwable instanceof NullPointerException)) {
+		    writer.println("Include02 FAILED - Thrown Exception was " +
+				   throwable.getClass().getName());
+		    ok = false;
+		} else {
+		    String message = throwable.getMessage();
+		    if (!"Include02 NullPointerException".equals(message)) {
+		        writer.println("Include02 FAILED - NullPointerException was " +
+				       message);
+			ok = false;
+		    }
+		}
+	    }
+	}
+
+	if (ok)
+	    writer.println("Include02 PASSED");
+        StaticLogger.reset();
+
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Include02a.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Include02a.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Include02a.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,48 @@
+/*
+ * Copyright 1999, 2000 ,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tester;
+
+
+import java.io.*;
+import javax.servlet.*;
+import javax.servlet.http.*;
+
+/**
+ * Included servlet for the test performed by Include02.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class Include02a extends HttpServlet {
+
+    public void doGet(HttpServletRequest request, HttpServletResponse response)
+        throws IOException, ServletException {
+
+        String type = request.getParameter("exception");
+	if (type == null)
+	    return;
+	else if (type.equals("IOException"))
+	    throw new IOException("Include02 IOException");
+	else if (type.equals("ServletException"))
+	    throw new ServletException("Include02 ServletException");
+	else if (type.equals("NullPointerException"))
+	    throw new NullPointerException("Include02 NullPointerException");
+
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Include03.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Include03.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Include03.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,110 @@
+/*
+ * Copyright 1999, 2000, 2001 ,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tester;
+
+
+import java.io.*;
+import javax.servlet.*;
+import javax.servlet.http.*;
+
+/**
+ * Test to insure that an included servlet can set request attributes that are
+ * visible to the calling servlet after the <code>include()</code> returns.
+ * The spec is silent on this topic, but it seems consistent with the overall
+ * intent to behave in this manner.
+ *
+ * The test includes either a servlet ("/Include03a") or a JSP page
+ * ("/Include03b.jsp") depending on the value specified for the "path"
+ * parameter.  The default is the servlet.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class Include03 extends HttpServlet {
+
+    private static final String specials[] =
+    { "javax.servlet.include.request_uri",
+      "javax.servlet.include.context_path",
+      "javax.servlet.include.servlet_path",
+      "javax.servlet.include.path_info",
+      "javax.servlet.include.query_string" };
+
+
+    public void doGet(HttpServletRequest request, HttpServletResponse response)
+        throws IOException, ServletException {
+
+        // Prepare this response
+        StringBuffer sb = new StringBuffer();
+        response.setContentType("text/plain");
+	PrintWriter writer = response.getWriter();
+
+        // Acquire the path to which we will issue an include
+        String path = request.getParameter("path");
+        if (path == null)
+            path = "/Include03a";
+
+        // Create a request dispatcher and call include() on it
+        RequestDispatcher rd =
+            getServletContext().getRequestDispatcher(path);
+        if (rd == null) {
+            sb.append(" No RequestDispatcher returned/");
+        } else {
+            rd.include(request, response);
+        }
+        response.resetBuffer();
+
+        // We MUST be able to see the attribute created by the includee
+        String value = null;
+        try {
+            value = (String)
+                request.getAttribute(path.substring(1));
+        } catch (ClassCastException e) {
+            sb.append(" Returned attribute not of type String/");
+        }
+        if ((sb.length() < 1) && (value == null)) {
+            sb.append(" No includee-created attribute was returned/");
+        }
+
+        // We MUST NOT see the special attributes created by the container
+        for (int i = 0; i < specials.length; i++) {
+            if (request.getAttribute(specials[i]) != null) {
+                sb.append(" Returned attribute ");
+                sb.append(specials[i]);
+                sb.append("/");
+            }
+        }
+
+        // Write our response
+        if (sb.length() < 1)
+            writer.println("Include03 PASSED");
+        else {
+            writer.print("Include03 FAILED -");
+            writer.println(sb.toString());
+        }
+
+        while (true) {
+            String message = StaticLogger.read();
+            if (message == null)
+                break;
+            writer.println(message);
+        }
+        StaticLogger.reset();
+
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Include03a.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Include03a.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Include03a.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,44 @@
+/*
+ * Copyright 1999, 2000, 2001 ,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tester;
+
+
+import java.io.*;
+import javax.servlet.*;
+import javax.servlet.http.*;
+
+/**
+ * Test to insure that an included servlet can set request attributes that are
+ * visible to the calling servlet after the <code>include()</code> returns.
+ * The spec is silent on this topic, but it seems consistent with the overall
+ * intent to behave in this manner.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class Include03a extends HttpServlet {
+
+
+    public void doGet(HttpServletRequest request, HttpServletResponse response)
+        throws IOException, ServletException {
+
+        request.setAttribute("Include03a", "This is a new attribute");
+
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Include04.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Include04.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Include04.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,77 @@
+/*
+ * Copyright 1999, 2000, 2001 ,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tester;
+
+
+import java.io.*;
+import javax.servlet.*;
+import javax.servlet.http.*;
+
+/**
+ * Test to ensure that we can include a servlet (without flushing the buffer),
+ * then forward to another servlet that replaces the original contents.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class Include04 extends HttpServlet {
+
+    public void doGet(HttpServletRequest request, HttpServletResponse response)
+        throws IOException, ServletException {
+
+        // Prepare this response
+        response.setBufferSize(8192);
+        StringBuffer sb = new StringBuffer();
+        response.setContentType("text/plain");
+	PrintWriter writer = response.getWriter();
+
+        // Include our first subservlet
+        RequestDispatcher rd1 =
+          getServletContext().getRequestDispatcher("/Include04a");
+        if (rd1 == null) {
+            sb.append(" No RD for '/Include04a'/");
+        } else {
+            rd1.include(request, response);
+        }
+
+        // Forward to our second subservlet
+        RequestDispatcher rd2 =
+          getServletContext().getRequestDispatcher("/Include04b");
+        if (rd2 == null) {
+            sb.append("No RD for '/Include04b'/");
+        } else {
+          rd2.forward(request, response);
+        }
+
+        // Append error messages if necessary
+        if (sb.length() > 0) {
+            writer.print("Include04 FAILED -");
+            writer.println(sb.toString());
+        }
+
+        while (true) {
+            String message = StaticLogger.read();
+            if (message == null)
+                break;
+            writer.println(message);
+        }
+        StaticLogger.reset();
+
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Include04a.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Include04a.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Include04a.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,42 @@
+/*
+ * Copyright 1999, 2000, 2001 ,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tester;
+
+
+import java.io.*;
+import javax.servlet.*;
+import javax.servlet.http.*;
+
+/**
+ * First subservlet for "include then forward" test.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class Include04a extends HttpServlet {
+
+
+    public void doGet(HttpServletRequest request, HttpServletResponse response)
+        throws IOException, ServletException {
+
+	PrintWriter writer = response.getWriter();
+        writer.println("Include04a PASSED");
+
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Include04b.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Include04b.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Include04b.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,42 @@
+/*
+ * Copyright 1999, 2000, 2001 ,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tester;
+
+
+import java.io.*;
+import javax.servlet.*;
+import javax.servlet.http.*;
+
+/**
+ * Second subservlet for "include then forward" test.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class Include04b extends HttpServlet {
+
+
+    public void doGet(HttpServletRequest request, HttpServletResponse response)
+        throws IOException, ServletException {
+
+	PrintWriter writer = response.getWriter();
+        writer.println("Include04b PASSED");
+
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Include06a.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Include06a.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Include06a.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,42 @@
+/*
+ * Copyright 1999, 2000, 2001 ,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tester;
+
+
+import java.io.*;
+import javax.servlet.*;
+import javax.servlet.http.*;
+
+/**
+ * First subservlet for "include then include" test.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class Include06a extends HttpServlet {
+
+
+    public void doGet(HttpServletRequest request, HttpServletResponse response)
+        throws IOException, ServletException {
+
+	PrintWriter writer = response.getWriter();
+        writer.println("Include06a output");
+
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Include07.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Include07.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Include07.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,73 @@
+/*
+ * Copyright 1999, 2000, 2001 ,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tester;
+
+
+import java.io.*;
+import javax.servlet.*;
+import javax.servlet.http.*;
+
+/**
+ * Test that insures we can include a servlet that does a forward, then
+ * includes another servlet, and we see all of the output in the right order.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class Include07 extends HttpServlet {
+
+    public void doGet(HttpServletRequest request, HttpServletResponse response)
+        throws IOException, ServletException {
+
+        // Prepare this response
+        response.setBufferSize(8192);
+        response.setContentType("text/plain");
+	PrintWriter writer = response.getWriter();
+        writer.println("Output from Include07");
+
+        // Include our first subservlet
+        RequestDispatcher rd1 =
+          getServletContext().getRequestDispatcher("/Include07a");
+        if (rd1 == null) {
+            writer.println("No RD for '/Include07a'");
+        } else {
+            rd1.include(request, response);
+        }
+
+        // Include our second subservlet
+        RequestDispatcher rd2 =
+          getServletContext().getRequestDispatcher("/Include07c");
+        if (rd2 == null) {
+            writer.println("No RD for '/Include07c'");
+        } else {
+            rd2.include(request, response);
+        }
+
+        // Finish this response
+        writer.println("Output from Include07");
+        while (true) {
+            String message = StaticLogger.read();
+            if (message == null)
+                break;
+            writer.println(message);
+        }
+        StaticLogger.reset();
+
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Include07a.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Include07a.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Include07a.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,51 @@
+/*
+ * Copyright 1999, 2000, 2001 ,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tester;
+
+
+import java.io.*;
+import javax.servlet.*;
+import javax.servlet.http.*;
+
+/**
+ * Test that insures we can include a servlet that does a forward, then
+ * includes another servlet, and we see all of the output in the right order.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class Include07a extends HttpServlet {
+
+    public void doGet(HttpServletRequest request, HttpServletResponse response)
+        throws IOException, ServletException {
+
+        // Prepare this response
+	PrintWriter writer = response.getWriter();
+
+        // Forward to our subsubservlet
+        RequestDispatcher rd =
+          getServletContext().getRequestDispatcher("/Include07b");
+        if (rd == null) {
+            writer.println("No RD for '/Include07b'");
+        } else {
+            rd.include(request, response);
+        }
+
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Include07b.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Include07b.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Include07b.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,43 @@
+/*
+ * Copyright 1999, 2000, 2001 ,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tester;
+
+
+import java.io.*;
+import javax.servlet.*;
+import javax.servlet.http.*;
+
+/**
+ * Test that insures we can include a servlet that does a forward, then
+ * includes another servlet, and we see all of the output in the right order.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class Include07b extends HttpServlet {
+
+    public void doGet(HttpServletRequest request, HttpServletResponse response)
+        throws IOException, ServletException {
+
+        // Prepare this response
+	PrintWriter writer = response.getWriter();
+        writer.println("Output from Include07b");
+
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Include07c.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Include07c.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Include07c.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,43 @@
+/*
+ * Copyright 1999, 2000, 2001 ,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tester;
+
+
+import java.io.*;
+import javax.servlet.*;
+import javax.servlet.http.*;
+
+/**
+ * Test that insures we can include a servlet that does a forward, then
+ * includes another servlet, and we see all of the output in the right order.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class Include07c extends HttpServlet {
+
+    public void doGet(HttpServletRequest request, HttpServletResponse response)
+        throws IOException, ServletException {
+
+        // Prepare this response
+	PrintWriter writer = response.getWriter();
+        writer.println("Output from Include07c");
+
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Include09.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Include09.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Include09.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,72 @@
+/*
+ * Copyright 1999, 2000, 2001 ,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tester;
+
+
+import java.io.*;
+import javax.servlet.*;
+import javax.servlet.http.*;
+
+/**
+ * Exercise basic including functionality using
+ * <code>request.getRequestDispatcher()</code>.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class Include09 extends HttpServlet {
+
+
+    public void doGet(HttpServletRequest request, HttpServletResponse response)
+        throws IOException, ServletException {
+
+        // Prepare this response
+        StringBuffer sb = new StringBuffer();
+        response.setContentType("text/plain");
+	PrintWriter writer = response.getWriter();
+
+        // Acquire the path to which we will issue a include
+        String path = request.getParameter("path");
+        if (path == null)
+            path = "/Include00a";
+
+        // Create a request dispatcher and call include() on it
+        RequestDispatcher rd = request.getRequestDispatcher(path);
+        if (rd == null) {
+            sb.append(" No RequestDispatcher returned/");
+        } else {
+            if (sb.length() < 1)
+                rd.include(request, response);
+        }
+
+        // Write our response if an error occurred
+        if (sb.length() >= 1) {
+            writer.print("Include00 FAILED -");
+            writer.println(sb.toString());
+            while (true) {
+                String message = StaticLogger.read();
+                if (message == null)
+                    break;
+                writer.println(message);
+            }
+        }
+        StaticLogger.reset();
+
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Include10.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Include10.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Include10.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,80 @@
+/*
+ * Copyright 1999, 2000, 2001 ,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tester;
+
+
+import java.io.*;
+import javax.servlet.*;
+import javax.servlet.http.*;
+
+/**
+ * Make sure container sets up include reques attributes.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class Include10 extends HttpServlet {
+
+
+    public void doGet(HttpServletRequest request, HttpServletResponse response)
+        throws IOException, ServletException {
+
+        // Prepare this response
+        StringBuffer sb = new StringBuffer();
+        response.setContentType("text/plain");
+	PrintWriter writer = response.getWriter();
+
+        // Pass copies of the original request properties
+        request.setAttribute("original.request_uri",
+                             request.getRequestURI());
+        request.setAttribute("original.context_path",
+                             request.getContextPath());
+        request.setAttribute("original.servlet_path",
+                             request.getServletPath());
+        request.setAttribute("original.path_info",
+                             request.getPathInfo());
+        request.setAttribute("original.query_string",
+                             request.getQueryString());
+
+        // Create a request dispatcher and call include() on it
+        RequestDispatcher rd =
+            getServletContext().getRequestDispatcher
+            ("/Include10a/include/path?name2=value2");
+        if (rd == null) {
+            sb.append(" No RequestDispatcher returned/");
+        } else {
+            if (sb.length() < 1)
+                rd.include(request, response);
+        }
+
+        // Write our response if an error occurred
+        if (sb.length() >= 1) {
+            writer.print("Include00 FAILED -");
+            writer.println(sb.toString());
+            while (true) {
+                String message = StaticLogger.read();
+                if (message == null)
+                    break;
+                writer.println(message);
+            }
+        }
+        StaticLogger.reset();
+
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Include10a.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Include10a.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Include10a.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,107 @@
+/*
+ * Copyright 1999, 2000, 2001 ,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tester;
+
+
+import java.io.*;
+import javax.servlet.*;
+import javax.servlet.http.*;
+
+/**
+ * Ensure the correct container managed request attributes are set.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class Include10a extends HttpServlet {
+
+    private static final String specials[] =
+    { "javax.servlet.include.request_uri",
+      "javax.servlet.include.context_path",
+      "javax.servlet.include.servlet_path",
+      "javax.servlet.include.path_info",
+      "javax.servlet.include.query_string" };
+
+
+    public void doGet(HttpServletRequest request, HttpServletResponse response)
+        throws IOException, ServletException {
+
+        // Prepare this response
+        StringBuffer sb = new StringBuffer();
+	PrintWriter writer = response.getWriter();
+
+        // Validate the original request properties
+        String value = null;
+        value = (String) request.getAttribute("original.request_uri");
+        if (!value.equals(request.getRequestURI()))
+            sb.append(" getRequestURI() is " + request.getRequestURI() +
+                      " but should be " + value + "|");
+        value = (String) request.getAttribute("original.context_path");
+        if (!value.equals(request.getContextPath()))
+            sb.append(" getContextPath() is " + request.getContextPath() +
+                      " but should be " + value + "|");
+        value = (String) request.getAttribute("original.servlet_path");
+        if (!value.equals(request.getServletPath()))
+            sb.append(" getServletPath() is " + request.getServletPath() +
+                      " but should be " + value + "|");
+        value = (String) request.getAttribute("original.path_info");
+        if (!value.equals(request.getPathInfo()))
+            sb.append(" getPathInfo() is " + request.getPathInfo() +
+                      " but should be " + value + "|");
+        value = (String) request.getAttribute("original.query_string");
+        if (!value.equals(request.getQueryString()))
+            sb.append(" getQueryString() is " + request.getQueryString() +
+                      " but should be " + value + "|");
+
+        // Validate the container provided request attributes
+        value = (String)
+            request.getAttribute("javax.servlet.include.request_uri");
+        if (!(request.getContextPath() + "/Include10a/include/path").equals(value))
+            sb.append(" request_uri is " + value +
+                      " but should be " + request.getContextPath() +
+                      "/Include10a/include/path|");
+        value = (String)
+            request.getAttribute("javax.servlet.include.context_path");
+        if (!request.getContextPath().equals(value))
+            sb.append(" context_path is " + value +
+                      " but should be " + request.getContextPath() + "|");
+        value = (String)
+            request.getAttribute("javax.servlet.include.servlet_path");
+        if (!"/Include10a".equals(value))
+            sb.append(" servlet_path is " + value +
+                      " but should be /Include10a|");
+        value = (String)
+            request.getAttribute("javax.servlet.include.path_info");
+        if (!"/include/path".equals(value))
+            sb.append(" path_info is " + value +
+                      " but should be /include/path|");
+        value = (String)
+            request.getAttribute("javax.servlet.include.query_string");
+        if (!"name2=value2".equals(value))
+            sb.append(" query_string is " + value +
+                      " but should be name2=value2|");
+
+        // Generate our success or failure report
+        if (sb.length() < 1)
+            writer.println("Include10a PASSED");
+        else
+            writer.println("Include10a FAILED -" + sb.toString());
+
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Jndi01.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Jndi01.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Jndi01.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,205 @@
+/*
+ * Copyright 1999, 2000, 2001 ,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tester;
+
+
+import java.io.*;
+import javax.naming.Binding;
+import javax.naming.Context;
+import javax.naming.InitialContext;
+import javax.naming.NamingEnumeration;
+import javax.naming.NamingException;
+import javax.servlet.*;
+import javax.servlet.http.*;
+import org.apache.tester.SessionBean;
+import org.apache.tester.shared.SharedSessionBean;
+import org.apache.tester.unpshared.UnpSharedSessionBean;
+import org.apache.tester.unshared.UnsharedSessionBean;
+
+
+/**
+ * Negative test for ensuring that the naming context provided by the servlet
+ * container is immutable.  No attempt to add, modify, or delete any binding
+ * should succeed.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class Jndi01 extends HttpServlet {
+
+    public void init() throws ServletException {
+
+        // Access the naming context from init()
+        Context ctx = null;
+        try {
+            ctx = new InitialContext();
+            ctx.lookup("java:/comp");
+            log("initialized successfully in init()");
+        } catch (NamingException e) {
+            e.printStackTrace();
+            log("Cannot create context in init()", e);
+            throw new ServletException(e);
+        }
+
+        // Access some application beans from init()
+
+        try {
+            SessionBean sb = new SessionBean();
+            log("OK Accessing SessionBean");
+        } catch (Throwable t) {
+            log("FAIL Accessing SessionBean", t);
+        }
+
+        try {
+            SharedSessionBean sb = new SharedSessionBean();
+            log("OK Accessing SharedSessionBean");
+        } catch (Throwable t) {
+            log("FAIL Accessing SharedSessionBean", t);
+        }
+
+        try {
+            UnpSharedSessionBean sb = new UnpSharedSessionBean();
+            log("OK Accessing UnpSharedSessionBean");
+        } catch (Throwable t) {
+            log("FAIL Accessing UnpSharedSessionBean", t);
+        }
+
+        try {
+            UnsharedSessionBean sb = new UnsharedSessionBean();
+            log("OK Accessing UnsharedSessionBean");
+        } catch (Throwable t) {
+            log("FAIL Accessing UnsharedSessionBean", t);
+        }
+
+    }
+
+    public void destroy() {
+        Context ctx = null;
+        try {
+            ctx = new InitialContext();
+            ctx.lookup("java:/comp");
+            log("initialized successfully in destroy()");
+        } catch (NamingException e) {
+            e.printStackTrace();
+            log("Cannot create context in destroy()", e);
+        }
+    }
+
+    public void doGet(HttpServletRequest request, HttpServletResponse response)
+        throws IOException, ServletException {
+
+        // Prepare to render our output
+        response.setContentType("text/plain");
+        PrintWriter writer = response.getWriter();
+        StringBuffer sb = new StringBuffer();
+        boolean ok = true;
+        Object value = null;
+
+        // Look up the initial context provided by our servlet container
+        Context initContext = null;
+        try {
+            initContext = new InitialContext();
+        } catch (NamingException e) {
+            log("Create initContext", e);
+            sb.append("  Cannot create initContext.");
+            ok = false;
+        }
+
+        // Look up the environment context provided to our web application
+        Context envContext = null;
+        try {
+            if (ok) {
+                value = initContext.lookup("java:comp/env");
+                envContext = (Context) value;
+                if (envContext == null) {
+                    sb.append("  Missing envContext.");
+                    ok = false;
+                }
+            }
+        } catch (ClassCastException e) {
+            sb.append("  envContext class is ");
+            sb.append(value.getClass().getName());
+            sb.append(".");
+            ok = false;
+        } catch (NamingException e) {
+            log("Create envContext", e);
+            sb.append("  Cannot create envContext.");
+            ok = false;
+        }
+
+        // Attempt to add a new binding to our environment context
+        try {
+            if (ok) {
+                envContext.bind("newEntry", "New Value");
+                sb.append("  Allowed bind().");
+                value = envContext.lookup("newEntry");
+                if (value != null)
+                    sb.append("  Allowed lookup() of added entry.");
+            }
+        } catch (Throwable e) {
+            log("Add binding", e);
+        }
+
+        // Attempt to change the value of an existing binding
+        try {
+            if (ok) {
+                envContext.rebind("stringEntry", "Changed Value");
+                sb.append("  Allowed rebind().");
+                value = envContext.lookup("stringEntry");
+                if ((value != null) &&
+                    (value instanceof String) &&
+                    "Changed Value".equals((String) value))
+                    sb.append("  Allowed lookup() of changed entry.");
+            }
+        } catch (Throwable e) {
+            log("Change binding", e);
+        }
+
+        // Attempt to delete an existing binding
+        try {
+            if (ok) {
+                envContext.unbind("byteEntry");
+                sb.append("  Allowed unbind().");
+                value = envContext.lookup("byteEntry");
+                if (value == null)
+                    sb.append("  Allowed unbind of deleted entry.");
+            }
+        } catch (Throwable e) {
+            log("Delete binding", e);
+        }
+
+        // Report our ultimate success or failure
+        if (sb.length() < 1)
+            writer.println("Jndi01 PASSED");
+        else {
+            writer.print("Jndi01 FAILED -");
+            writer.println(sb);
+        }
+
+        // Add wrapper messages as required
+        while (true) {
+            String message = StaticLogger.read();
+            if (message == null)
+                break;
+            writer.println(message);
+        }
+        StaticLogger.reset();
+
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Jndi02.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Jndi02.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Jndi02.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,367 @@
+/*
+ * Copyright 1999, 2000, 2001 ,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tester;
+
+
+import java.io.*;
+import javax.naming.Binding;
+import javax.naming.Context;
+import javax.naming.InitialContext;
+import javax.naming.NamingEnumeration;
+import javax.naming.NamingException;
+import javax.servlet.*;
+import javax.servlet.http.*;
+import org.apache.tester.SessionBean;
+import org.apache.tester.shared.SharedSessionBean;
+import org.apache.tester.unpshared.UnpSharedSessionBean;
+import org.apache.tester.unshared.UnsharedSessionBean;
+
+
+/**
+ * Positive test for looking up environment entries from the naming context
+ * provided by the servlet container.  The looked-up values are initialized
+ * via <code>&lt;env-entry&gt;</code> elements in the web application
+ * deployment descriptor.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 303152 $ $Date: 2004-08-31 09:41:22 -0500 (Tue, 31 Aug 2004) $
+ */
+
+public class Jndi02 extends HttpServlet {
+
+    // Names of the known <env-entry> elements
+    String names[] =
+    { "booleanEntry", "byteEntry", "doubleEntry", "floatEntry",
+      "integerEntry", "longEntry", "stringEntry", "nested" };
+
+
+    // Reference some application classes for the first time in destroy()
+    // and log the results
+    public void destroy() {
+
+        try {
+            SessionBean sb = new SessionBean();
+            log("OK Accessing SessionBean");
+        } catch (Throwable t) {
+            log("FAIL Accessing SessionBean", t);
+        }
+
+        try {
+            SharedSessionBean sb = new SharedSessionBean();
+            log("OK Accessing SharedSessionBean");
+        } catch (Throwable t) {
+            log("FAIL Accessing SharedSessionBean", t);
+        }
+
+        try {
+            UnpSharedSessionBean sb = new UnpSharedSessionBean();
+            log("OK Accessing UnpSharedSessionBean");
+        } catch (Throwable t) {
+            log("FAIL Accessing UnpSharedSessionBean", t);
+        }
+
+        try {
+            UnsharedSessionBean sb = new UnsharedSessionBean();
+            log("OK Accessing UnsharedSessionBean");
+        } catch (Throwable t) {
+            log("FAIL Accessing UnsharedSessionBean", t);
+        }
+
+    }
+
+
+    public void doGet(HttpServletRequest request, HttpServletResponse response)
+        throws IOException, ServletException {
+
+        // Prepare to render our output
+        response.setContentType("text/plain");
+        PrintWriter writer = response.getWriter();
+        StringBuffer sb = new StringBuffer();
+        boolean ok = true;
+        Object value = null;
+
+        // Look up the initial context provided by our servlet container
+        Context initContext = null;
+        try {
+            initContext = new InitialContext();
+        } catch (NamingException e) {
+            log("Create initContext", e);
+            sb.append("  Cannot create initContext.");
+            ok = false;
+        }
+
+        // Look up the environment context provided to our web application
+        Context envContext = null;
+        try {
+            if (ok) {
+                value = initContext.lookup("java:comp/env");
+                envContext = (Context) value;
+                if (envContext == null) {
+                    sb.append("  Missing envContext.");
+                    ok = false;
+                }
+            }
+        } catch (ClassCastException e) {
+            sb.append("  envContext class is ");
+            sb.append(value.getClass().getName());
+            sb.append(".");
+            ok = false;
+        } catch (NamingException e) {
+            log("Create envContext", e);
+            sb.append("  Cannot create envContext.");
+            ok = false;
+        }
+
+        // Validate the booleanEntry environment entry
+        try {
+            if (ok) {
+                value = envContext.lookup("booleanEntry");
+                Boolean booleanValue = (Boolean) value;
+                if (!(booleanValue.booleanValue() == true)) {
+                    sb.append("  booleanValue is ");
+                    sb.append(booleanValue);
+                    sb.append(".");
+                }
+            }
+        } catch (ClassCastException e) {
+            sb.append("  booleanValue class is ");
+            sb.append(value.getClass().getName());
+            sb.append(".");                      
+        } catch (NullPointerException e) {
+            sb.append("  booleanValue is missing.");
+        } catch (NamingException e) {
+            log("Get booleanValue", e);
+            sb.append("  Cannot get booleanValue.");
+        }
+
+        // Validate the byteEntry environment entry
+        try {
+            if (ok) {
+                value = envContext.lookup("byteEntry");
+                Byte byteValue = (Byte) value;
+                if (!(byteValue.byteValue() == 123)) {
+                    sb.append("  byteValue is ");
+                    sb.append(byteValue);
+                    sb.append(".");
+                }
+            }
+        } catch (ClassCastException e) {
+            sb.append("  byteValue class is ");
+            sb.append(value.getClass().getName());
+            sb.append(".");                      
+        } catch (NullPointerException e) {
+            sb.append("  byteValue is missing.");
+        } catch (NamingException e) {
+            log("Get byteValue", e);
+            sb.append("  Cannot get byteValue.");
+        }
+
+        // Validate the doubleEntry environment entry
+        try {
+            if (ok) {
+                value = envContext.lookup("doubleEntry");
+                Double doubleValue = (Double) value;
+                if (!(doubleValue.doubleValue() == 123.45)) {
+                    sb.append("  doubleValue is ");
+                    sb.append(doubleValue);
+                    sb.append(".");
+                }
+            }
+        } catch (ClassCastException e) {
+            sb.append("  doubleValue class is ");
+            sb.append(value.getClass().getName());
+            sb.append(".");                      
+        } catch (NullPointerException e) {
+            sb.append("  doubleValue is missing.");
+        } catch (NamingException e) {
+            log("Get doubleValue", e);
+            sb.append("  Cannot get doubleValue.");
+        }
+
+        // Validate the floatEntry environment entry
+        try {
+            if (ok) {
+                value = envContext.lookup("floatEntry");
+                Float floatValue = (Float) value;
+                float difference = floatValue.floatValue() - ((float) 54.32);
+                if ((difference < ((float) -0.01)) ||
+                    (difference > ((float)  0.01))) {
+                    sb.append("  floatValue is ");
+                    sb.append(floatValue);
+                    sb.append(".");
+                }
+            }
+        } catch (ClassCastException e) {
+            sb.append("  floatValue class is ");
+            sb.append(value.getClass().getName());
+            sb.append(".");                      
+        } catch (NullPointerException e) {
+            sb.append("  floatValue is missing.");
+        } catch (NamingException e) {
+            log("Get floatValue", e);
+            sb.append("  Cannot get floatValue.");
+        }
+
+        // Validate the integerEntry environment entry
+        try {
+            if (ok) {
+                value = envContext.lookup("integerEntry");
+                Integer integerValue = (Integer) value;
+                if (!(integerValue.intValue() == 12345)) {
+                    sb.append("  integerValue is ");
+                    sb.append(integerValue);
+                    sb.append(".");
+                }
+            }
+        } catch (ClassCastException e) {
+            sb.append("  integerValue class is ");
+            sb.append(value.getClass().getName());
+            sb.append(".");                      
+        } catch (NullPointerException e) {
+            sb.append("  integerValue is missing.");
+        } catch (NamingException e) {
+            log("Get integerValue", e);
+            sb.append("  Cannot get integerValue.");
+        }
+
+        // Validate the longEntry environment entry
+        try {
+            if (ok) {
+                value = envContext.lookup("longEntry");
+                Long longValue = (Long) value;
+                if (!(longValue.longValue() == 54321)) {
+                    sb.append("  longValue is ");
+                    sb.append(longValue);
+                    sb.append(".");
+                }
+            }
+        } catch (ClassCastException e) {
+            sb.append("  longValue class is ");
+            sb.append(value.getClass().getName());
+            sb.append(".");                      
+        } catch (NullPointerException e) {
+            sb.append("  longValue is missing.");
+        } catch (NamingException e) {
+            log("Get longValue", e);
+            sb.append("  Cannot get longValue.");
+        }
+
+        // Validate the stringEntry environment entry
+        try {
+            if (ok) {
+                value = envContext.lookup("stringEntry");
+                String stringValue = (String) value;
+                if (!"String Value".equals(stringValue)) {
+                    sb.append("  stringValue is ");
+                    sb.append(stringValue);
+                    sb.append(".");
+                }
+            }
+        } catch (ClassCastException e) {
+            sb.append("  stringValue class is ");
+            sb.append(value.getClass().getName());
+            sb.append(".");                      
+        } catch (NullPointerException e) {
+            sb.append("  stringValue is missing.");
+        } catch (NamingException e) {
+            log("Get stringValue", e);
+            sb.append("  Cannot get stringValue.");
+        }
+
+        // Validate the nestedEntry environment entry
+        try {
+            if (ok) {
+                value = envContext.lookup("nested/nestedEntry");
+                String stringValue = (String) value;
+                if (!"Nested Value".equals(stringValue)) {
+                    sb.append("  stringValue is ");
+                    sb.append(stringValue);
+                    sb.append(".");
+                }
+            }
+        } catch (ClassCastException e) {
+            sb.append("  stringValue class is ");
+            sb.append(value.getClass().getName());
+            sb.append(".");                      
+        } catch (NullPointerException e) {
+            sb.append("  stringValue is missing.");
+        } catch (NamingException e) {
+            log("Get stringValue", e);
+            sb.append("  Cannot get stringValue.");
+        }
+
+        // Validate that we can enumerate the contents of our environment
+        try {
+            if (ok) {
+                int counts[] = new int[names.length];
+                for (int i = 0; i < names.length; i++)
+                    counts[i] = 0;
+                NamingEnumeration namingEnum =
+                    initContext.listBindings("java:comp/env");
+                while (namingEnum.hasMore()) {
+                    Binding binding = (Binding) namingEnum.next();
+                    String name = binding.getName();
+                    boolean found = false;
+                    for (int i = 0; i < names.length; i++) {
+                        if (name.equals(names[i])) {
+                            counts[i]++;
+                            found = true;
+                            break;
+                        }
+                    }
+                    if (!found)
+                        StaticLogger.write("Found binding for '" + name + "'");
+                }
+                for (int i = 0; i < names.length; i++) {
+                    if (counts[i] < 1) {
+                        sb.append("  Missing binding for ");
+                        sb.append(names[i]);
+                        sb.append(".");
+                    } else if (counts[i] > 1) {
+                        sb.append("  Found ");
+                        sb.append(counts[i]);
+                        sb.append(" bindings for ");
+                        sb.append(names[i]);
+                        sb.append(".");
+                    }
+                }
+            }
+        } catch (NamingException e) {
+            log("Enumerate envContext", e);
+            sb.append("  Cannot enumerate envContext");
+        }
+
+        // Report our ultimate success or failure
+        if (sb.length() < 1)
+            writer.println("Jndi02 PASSED");
+        else {
+            writer.print("Jndi02 FAILED -");
+            writer.println(sb);
+        }
+
+        // Add wrapper messages as required
+        while (true) {
+            String message = StaticLogger.read();
+            if (message == null)
+                break;
+            writer.println(message);
+        }
+        StaticLogger.reset();
+
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Lifecycle01.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Lifecycle01.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Lifecycle01.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,100 @@
+/*
+ * Copyright 1999, 2000, 2001 ,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tester;
+
+
+import java.io.*;
+import java.net.MalformedURLException;
+import java.net.URL;
+import javax.servlet.*;
+import javax.servlet.http.*;
+
+
+/**
+ * Positive test for servlet lifecycle management.  This servlet is
+ * <strong>not</strong> declared to be load-on-startup, and the first request
+ * made to it should be a "GET".
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class Lifecycle01 extends HttpServlet {
+
+    private boolean doubled = false;
+
+    private boolean initialized = false;
+
+    public void init() throws ServletException {
+        if (initialized)
+            doubled = true;
+        else
+            initialized = true;
+    }
+
+    public void destroy() {
+        initialized = false;
+    }
+
+    public void doGet(HttpServletRequest request, HttpServletResponse response)
+        throws IOException, ServletException {
+
+        response.setContentType("text/plain");
+        PrintWriter writer = response.getWriter();
+        if (doubled) {
+            writer.println("Lifecycle01 FAILED - Double initialization");
+        } else if (initialized) {
+            writer.println("Lifecycle01 PASSED");
+        } else {
+            writer.println("Lifecycle01 FAILED - GET but not initialized");
+        }
+
+        while (true) {
+            String message = StaticLogger.read();
+            if (message == null)
+                break;
+            writer.println(message);
+        }
+        StaticLogger.reset();
+
+    }
+
+    public void doPost(HttpServletRequest request, HttpServletResponse response)
+        throws IOException, ServletException {
+
+        response.setContentType("text/plain");
+        PrintWriter writer = response.getWriter();
+        if (doubled) {
+            writer.println("Lifecycle01 FAILED - POST and double initialization");
+        } else if (initialized) {
+            writer.println("Lifecycle01 FAILED - POST called");
+        } else {
+            writer.println("Lifecycle01 FAILED - POST and not initialized");
+        }
+
+        while (true) {
+            String message = StaticLogger.read();
+            if (message == null)
+                break;
+            writer.println(message);
+        }
+        StaticLogger.reset();
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Lifecycle02.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Lifecycle02.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Lifecycle02.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,100 @@
+/*
+ * Copyright 1999, 2000, 2001 ,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tester;
+
+
+import java.io.*;
+import java.net.MalformedURLException;
+import java.net.URL;
+import javax.servlet.*;
+import javax.servlet.http.*;
+
+
+/**
+ * Positive test for servlet lifecycle management.  This servlet is
+ * <strong>not</strong> declared to be load-on-startup, and the first request
+ * made to it should be a "POST".
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class Lifecycle02 extends HttpServlet {
+
+    private boolean doubled = false;
+
+    private boolean initialized = false;
+
+    public void init() throws ServletException {
+        if (initialized)
+            doubled = true;
+        else
+            initialized = true;
+    }
+
+    public void destroy() {
+        initialized = false;
+    }
+
+    public void doGet(HttpServletRequest request, HttpServletResponse response)
+        throws IOException, ServletException {
+
+        response.setContentType("text/plain");
+        PrintWriter writer = response.getWriter();
+        if (doubled) {
+            writer.println("Lifecycle02 FAILED - GET and double initialization");
+        } else if (initialized) {
+            writer.println("Lifecycle02 FAILED - GET called");
+        } else {
+            writer.println("Lifecycle02 FAILED - GET and not initialized");
+        }
+
+        while (true) {
+            String message = StaticLogger.read();
+            if (message == null)
+                break;
+            writer.println(message);
+        }
+        StaticLogger.reset();
+
+    }
+
+    public void doPost(HttpServletRequest request, HttpServletResponse response)
+        throws IOException, ServletException {
+
+        response.setContentType("text/plain");
+        PrintWriter writer = response.getWriter();
+        if (doubled) {
+            writer.println("Lifecycle02 FAILED - Double initialization");
+        } else if (initialized) {
+            writer.println("Lifecycle02 PASSED");
+        } else {
+            writer.println("Lifecycle02 FAILED - POST but not initialized");
+        }
+
+        while (true) {
+            String message = StaticLogger.read();
+            if (message == null)
+                break;
+            writer.println(message);
+        }
+        StaticLogger.reset();
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Lifecycle03.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Lifecycle03.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Lifecycle03.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,91 @@
+/*
+ * Copyright 1999, 2000, 2001 ,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tester;
+
+
+import java.io.*;
+import java.net.MalformedURLException;
+import java.net.URL;
+import javax.servlet.*;
+import javax.servlet.http.*;
+
+
+/**
+ * Test for servlet lifecycle management.  It's behavior is controlled by
+ * a request parameter <strong>step</strong>, which must be set to one of
+ * the following values:
+ * <ul>
+ * <li><em>1</em> - Throw an <code>UnavailableException</code> that indicates
+ *     permanent unavailablility, which should cause this servlet instance
+ *     to be destroyed and thrown away.</li>
+ * <li><em>2</em> - Check the lifecycle variables to ensure that the old
+ *     instance was not reused.</li>
+ * </ul>
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class Lifecycle03 extends HttpServlet {
+
+    private static String staticTrail = "";
+
+    private String instanceTrail = "";
+
+    public void init() throws ServletException {
+        staticTrail += "I";
+        instanceTrail += "I";
+    }
+
+    public void destroy() {
+        staticTrail += "D";
+        instanceTrail += "D";
+    }
+
+    public void doGet(HttpServletRequest request, HttpServletResponse response)
+        throws IOException, ServletException {
+
+        staticTrail += "S";
+        instanceTrail += "S";
+
+        // For step=1, throw an exception
+        if ("1".equals(request.getParameter("step"))) {
+            staticTrail = "IS";
+            throw new UnavailableException("Lifecycle03 is permanently unavailable");
+        }
+
+        // For step=2, evaluate the results.
+        response.setContentType("text/plain");
+        PrintWriter writer = response.getWriter();
+        if (staticTrail.equals("ISDIS") && instanceTrail.equals("IS"))
+            writer.println("Lifecycle03 PASSED");
+        else
+            writer.println("Lifecycle03 FAILED - staticTrail=" + staticTrail +
+                           ", instanceTrail=" + instanceTrail);
+
+        while (true) {
+            String message = StaticLogger.read();
+            if (message == null)
+                break;
+            writer.println(message);
+        }
+        StaticLogger.reset();
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Redirect01.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Redirect01.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Redirect01.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,79 @@
+/*
+ * Copyright 1999, 2000, 2001 ,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tester;
+
+
+import java.io.*;
+import java.util.*;
+import javax.servlet.*;
+import javax.servlet.http.*;
+
+
+/**
+ * Positive test for HttpServletResponse.sendRedirect().
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class Redirect01 extends HttpServlet {
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Process a servlet request and create the corresponding response.
+     *
+     * @param request The request we are processing
+     * @param response The response we are creating
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception ServletException if a servlet error occurs
+     */
+    public void doGet(HttpServletRequest request,
+                      HttpServletResponse response)
+        throws IOException, ServletException {
+
+        response.setContentType("text/plain");
+        PrintWriter writer = response.getWriter();
+
+        try {
+            response.sendRedirect(request.getContextPath() + "/Redirect01a");
+            return;
+        } catch (IllegalStateException e) {
+            writer.println("Redirect01 FAILED - Threw IllegaStateException");
+            e.printStackTrace(writer);
+        }
+        try {
+            writer.println("Redirect01 FAILED - Output text after redirect");
+        } catch (Throwable t) {
+            throw new ServletException("Redirect01 Post-Redirect Output Error",
+                                       t);
+        }
+        while (true) {
+            String message = StaticLogger.read();
+            if (message == null)
+                break;
+            writer.println(message);
+        }
+        StaticLogger.reset();
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Redirect01a.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Redirect01a.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Redirect01a.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,66 @@
+/*
+ * Copyright 1999, 2000, 2001 ,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tester;
+
+
+import java.io.*;
+import java.util.*;
+import javax.servlet.*;
+import javax.servlet.http.*;
+
+
+/**
+ * Positive test for HttpServletResponse.sendRedirect().
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class Redirect01a extends HttpServlet {
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Process a servlet request and create the corresponding response.
+     *
+     * @param request The request we are processing
+     * @param response The response we are creating
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception ServletException if a servlet error occurs
+     */
+    public void doGet(HttpServletRequest request,
+                      HttpServletResponse response)
+        throws IOException, ServletException {
+
+        response.setContentType("text/plain");
+        PrintWriter writer = response.getWriter();
+        writer.println("Redirect01a PASSED");
+        while (true) {
+            String message = StaticLogger.read();
+            if (message == null)
+                break;
+            writer.println(message);
+        }
+        StaticLogger.reset();
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Reflection01.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Reflection01.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Reflection01.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,130 @@
+/*
+ * Copyright 1999, 2000, 2001 ,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tester;
+
+
+import java.io.*;
+import java.lang.reflect.*;
+import java.util.*;
+import javax.servlet.*;
+import javax.servlet.http.*;
+
+
+/**
+ * Negative test for access to Catalina internals through the objects that
+ * are exposed to this servlet by the container.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class Reflection01 extends HttpServlet {
+
+    public void service(HttpServletRequest request,
+                        HttpServletResponse response)
+        throws IOException, ServletException {
+
+        response.setContentType("text/plain");
+        PrintWriter writer = response.getWriter();
+        StringBuffer results = new StringBuffer();
+
+        // Check the ServletConfig object
+        try {
+            ServletConfig servletConfig = getServletConfig();
+            Method method = servletConfig.getClass().getMethod
+                ("getParent", new Class[] {});
+            Object parent = method.invoke(servletConfig,
+                                          new Object[] {});
+            results.append(" Can reflect on ServletConfig/");
+        } catch (Throwable t) {
+            StaticLogger.write("ServletConfig: " + t);
+        }
+
+        // Check the ServletContext object
+        try {
+            ServletContext servletContext = getServletContext();
+            Method method = servletContext.getClass().getMethod
+                ("getResources", new Class[] {});
+            Object resources = method.invoke(servletContext,
+                                             new Object[] {});
+            results.append(" Can reflect on ServletContext/");
+        } catch (Throwable t) {
+            StaticLogger.write("ServletContext: " + t);
+        }
+
+        // Check the HttpServletRequest object
+        try {
+            Method method = request.getClass().getMethod
+                ("getInfo", new Class[] {});
+            Object info = method.invoke(request,
+                                        new Object[] {});
+            results.append(" Can reflect on HttpServletRequest/");
+        } catch (Throwable t) {
+            StaticLogger.write("HttpServletRequest: " + t);
+        }
+
+        // Check the HttpServletResponse object
+        try {
+            Method method = request.getClass().getMethod
+                ("getInfo", new Class[] {});
+            Object info = method.invoke(request,
+                                        new Object[] {});
+            results.append(" Can reflect on HttpServletResponse/");
+        } catch (Throwable t) {
+            StaticLogger.write("HttpServletResponse: " + t);
+        }
+
+        // Check the HttpSession object
+        try {
+            HttpSession session = request.getSession(true);
+            Method method = session.getClass().getMethod
+                ("getInfo", new Class[] {});
+            results.append(" Can reflect on HttpSession/");
+        } catch (Throwable t) {
+            StaticLogger.write("HttpSession: " + t);
+        }
+
+        // Check the RequestDispatcher object
+        try {
+            RequestDispatcher rd =
+                getServletContext().getRequestDispatcher("/index.shtml");
+            Method method = rd.getClass().getMethod
+                ("getInfo", new Class[] {});
+            results.append(" Can reflect on RequestDispatcher/");
+        } catch (Throwable t) {
+            StaticLogger.write("RequestDispatcher: " + t);
+        }
+
+        // Report final results
+        if (results.length() < 1)
+            writer.println("Reflection01 PASSED");
+        else {
+            writer.print("Reflection01 FAILED -");
+            writer.println(results.toString());
+        }
+
+        while (true) {
+            String message = StaticLogger.read();
+            if (message == null)
+                break;
+            writer.println(message);
+        }
+        StaticLogger.reset();
+
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Request01.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Request01.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Request01.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,140 @@
+/*
+ * Copyright 1999, 2000 ,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tester;
+
+
+import java.io.*;
+import javax.servlet.*;
+import javax.servlet.http.*;
+
+
+/**
+ * Request listener test.  Exercise various methods for dealing with
+ * servlet request attributes.  Leave an attribute named "request01"
+ * present, which should be erased after a web application restart.
+ *
+ * @author Justyna Horwat
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class Request01 extends HttpServlet {
+
+    public void doGet(HttpServletRequest request, HttpServletResponse response)
+        throws IOException, ServletException {
+
+        response.setContentType("text/plain");
+        boolean ok = true;
+        PrintWriter writer = response.getWriter();
+        ServletContext context = getServletContext();
+
+        // Ensure that there is no existing attribute
+        if (ok) {
+            if (request.getAttribute("request01") != null) {
+                writer.println("Request01 FAILED - Attribute already exists");
+                ok = false;
+            }
+        }
+
+        // Create and stash a request attribute
+        if (ok) {
+            ContextBean bean = new ContextBean();
+            bean.setStringProperty("Request01");
+            request.setAttribute("request01", bean);
+        }
+
+        // Ensure that we can retrieve the attribute successfully
+        if (ok) {
+            Object bean = request.getAttribute("request01");
+            if (bean == null) {
+                writer.println("Request01 FAILED - Cannot retrieve attribute");
+                ok = false;
+            }
+            if (ok) {
+                if (!(bean instanceof ContextBean)) {
+                    writer.println("Request01 FAILED - Bean instance of " +
+                                   bean.getClass().getName());
+                    ok = false;
+                }
+            }
+            if (ok) {
+                String value = ((ContextBean) bean).getStringProperty();
+                if (!"Request01".equals(value)) {
+                    writer.println("Request01 FAILED - Value = " + value);
+                    ok = false;
+                }
+            }
+            if (ok) {
+                String lifecycle = ((ContextBean) bean).getLifecycle();
+                if (!"/add".equals(lifecycle)) {
+                    writer.println("Request01 FAILED - Bean lifecycle is " +
+                                   lifecycle);
+                    ok = false;
+                }
+            }
+        }
+
+        // Ensure that we can update this attribute and check its lifecycle
+        if (ok) {
+            ContextBean bean = (ContextBean) request.getAttribute("request01");
+            request.setAttribute("request01", bean);
+            String lifecycle = bean.getLifecycle();
+            if (!"/add/rep".equals(lifecycle)) {
+                writer.println("Request01 FAILED - Bean lifecycle is " +
+                               lifecycle);
+                ok = false;
+            }
+        }
+
+        // Ensure that we can remove this attribute and check its lifecycle
+        if (ok) {
+            ContextBean bean = (ContextBean) request.getAttribute("request01");
+            request.removeAttribute("request01");
+            String lifecycle = bean.getLifecycle();
+            if (!"/add/rep/rem".equals(lifecycle)) {
+                writer.println("Request01 FAILED - Bean lifecycle is " +
+                               lifecycle);
+                ok = false;
+            }
+        }
+
+        // Add a bean back for the restart application test
+        request.setAttribute("request01", new ContextBean());
+
+        // Ensure that setAttribute("name", null) works correctly
+        if (ok) {
+            request.setAttribute("FOO", "BAR");
+            request.setAttribute("FOO", null);
+            if (request.getAttribute("FOO") != null) {
+                writer.println("Request01 FAILED - setAttribute(name,null)");
+                ok = false;
+            }
+        }
+
+        // Report success if everything is still ok
+        if (ok)
+            writer.println("Request01 PASSED");
+        while (true) {
+            String message = StaticLogger.read();
+            if (message == null)
+                break;
+            writer.println(message);
+        }
+        StaticLogger.reset();
+
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/RequestListener01.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/RequestListener01.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/RequestListener01.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,85 @@
+/*
+ * Copyright 1999, 2000, 2001 ,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tester;
+
+
+import java.io.*;
+import javax.servlet.*;
+import javax.servlet.http.*;
+
+/**
+ * Application event listener for request events.  All events that occur
+ * are logged appropriately to the static logger..
+ *
+ * @author Justyna Horwat
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class RequestListener01
+    implements ServletRequestAttributeListener, ServletRequestListener {
+
+
+    public void attributeAdded(ServletRequestAttributeEvent event) {
+        StaticLogger.write("RequestListener01: attributeAdded(" +
+                           event.getName() + "," + event.getValue() + ")");
+        ServletContext context = (ServletContext) event.getSource();
+        context.log("RequestListener01: attributeAdded(" +
+                    event.getName() + "," + event.getValue() + ")");
+        if (event.getValue() instanceof ContextBean) {
+            ContextBean bean = (ContextBean) event.getValue();
+            bean.setLifecycle(bean.getLifecycle() + "/add");
+        }
+    }
+
+    public void attributeRemoved(ServletRequestAttributeEvent event) {
+        StaticLogger.write("RequestListener01: attributeRemoved(" +
+                           event.getName() + "," + event.getValue() + ")");
+        ServletContext context = (ServletContext) event.getSource();
+        context.log("RequestListener01: attributeRemoved(" +
+                    event.getName() + "," + event.getValue() + ")");
+        if (event.getValue() instanceof ContextBean) {
+            ContextBean bean = (ContextBean) event.getValue();
+            bean.setLifecycle(bean.getLifecycle() + "/rem");
+        }
+    }
+
+    public void attributeReplaced(ServletRequestAttributeEvent event) {
+        StaticLogger.write("RequestListener01: attributeReplaced(" +
+                           event.getName() + "," + event.getValue() + ")");
+        ServletContext context = (ServletContext) event.getSource();
+        context.log("RequestListener01: attributeReplaced(" +
+                    event.getName() + "," + event.getValue() + ")");
+        if (event.getValue() instanceof ContextBean) {
+            ContextBean bean = (ContextBean) event.getValue();
+            bean.setLifecycle(bean.getLifecycle() + "/rep");
+        }
+    }
+
+    public void requestDestroyed(ServletRequestEvent event) {
+        StaticLogger.write("RequestListener01: requestDestroyed() -- probably cached from previous request");
+        ServletContext context = (ServletContext) event.getSource();
+        context.log("RequestListener01: requestDestroyed()");
+    }
+
+    public void requestInitialized(ServletRequestEvent event) {
+        StaticLogger.write("RequestListener01: requestInitialized()");
+        ServletContext context = (ServletContext) event.getSource();
+        context.log("RequestListener01: requestInitialized()");
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Reset01.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Reset01.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Reset01.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,73 @@
+/*
+ * Copyright 1999, 2000 ,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tester;
+
+
+import java.io.*;
+import java.util.*;
+import javax.servlet.*;
+import javax.servlet.http.*;
+
+
+/**
+ * Positive test for ServletResponse.reset().
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class Reset01 extends GenericServlet {
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Process a servlet request and create the corresponding response.
+     *
+     * @param request The request we are processing
+     * @param response The response we are creating
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception ServletException if a servlet error occurs
+     */
+    public void service(ServletRequest request, ServletResponse response)
+        throws IOException, ServletException {
+
+        response.setContentType("text/plain");
+        PrintWriter writer = response.getWriter();
+        try {
+            writer.println("Reset01 FAILED - Did not reset buffer");
+            response.reset();
+            response.setContentType("text/plain");
+            writer.println("Reset01 PASSED");
+        } catch (IllegalStateException e) {
+            writer.println("Reset01 FAILED - Threw IllegaStateException");
+            e.printStackTrace(writer);
+        }
+        while (true) {
+            String message = StaticLogger.read();
+            if (message == null)
+                break;
+            writer.println(message);
+        }
+        StaticLogger.reset();
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Resources01.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Resources01.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Resources01.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,86 @@
+/*
+ * Copyright 1999, 2000, 2001 ,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tester;
+
+
+import java.io.*;
+import java.net.MalformedURLException;
+import java.net.URL;
+import javax.servlet.*;
+import javax.servlet.http.*;
+
+
+/**
+ * Positive test for <code>ServletContext.getResource()</code> as well as
+ * <code>ClassLoader.getResource()</code>.  Operation is controlled by query
+ * parameters:
+ * <ul>
+ * <li><strong>mode</strong> - Use <code>context</code> for servlet context
+ *     test, or <code>class</code> for class loader test.  [context]</li>
+ * <li><strong>path</strong> - Resource path to the requested resource,
+ *     starting with a slash.  [/WEB-INF/web.xml]</li>
+ * </ul>
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class Resources01 extends HttpServlet {
+
+    public void doGet(HttpServletRequest request, HttpServletResponse response)
+        throws IOException, ServletException {
+
+        // Identify our configuration parameters
+        String mode = request.getParameter("mode");
+        if (mode == null)
+            mode = "context";
+        String path = request.getParameter("path");
+        if (path == null)
+            path = "/WEB-INF/web.xml";
+
+        // Execute the desired test
+        response.setContentType("text/plain");
+        PrintWriter writer = response.getWriter();
+        URL url = null;
+        try {
+            if ("context".equals(mode))
+                url = getServletContext().getResource(path);
+            else
+                url = this.getClass().getResource(path);
+            if (url == null)
+                writer.println("Resources01 FAILED - No URL was returned");
+            else {
+                writer.println("Resources01 PASSED");
+                writer.println("url = " + url.toString());
+            }
+        } catch (MalformedURLException e) {
+            writer.println("Resources01 FAILED - MalformedURLException: "
+                           + e);
+        }
+
+        // Add wrapper messages as required
+        while (true) {
+            String message = StaticLogger.read();
+            if (message == null)
+                break;
+            writer.println(message);
+        }
+        StaticLogger.reset();
+
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Resources01.txt
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Resources01.txt	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Resources01.txt	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1 @@
+Resources01 PASSED

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Resources02.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Resources02.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Resources02.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,85 @@
+/*
+ * Copyright 1999, 2000, 2001 ,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tester;
+
+
+import java.io.*;
+import java.net.MalformedURLException;
+import java.net.URL;
+import javax.servlet.*;
+import javax.servlet.http.*;
+
+
+/**
+ * Negative test for <code>ServletContext.getResource()</code> as well as
+ * <code>ClassLoader.getResource()</code>.  Operation is controlled by query
+ * parameters:
+ * <ul>
+ * <li><strong>mode</strong> - Use <code>context</code> for servlet context
+ *     test, or <code>class</code> for class loader test.  [context]</li>
+ * <li><strong>path</strong> - Resource path to the requested resource,
+ *     starting with a slash.  [/WEB-INF/web.xml]</li>
+ * </ul>
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class Resources02 extends HttpServlet {
+
+    public void doGet(HttpServletRequest request, HttpServletResponse response)
+        throws IOException, ServletException {
+
+        // Identify our configuration parameters
+        String mode = request.getParameter("mode");
+        if (mode == null)
+            mode = "context";
+        String path = request.getParameter("path");
+        if (path == null)
+            path = "/WEB-INF/web.xml";
+
+        // Execute the desired test
+        response.setContentType("text/plain");
+        PrintWriter writer = response.getWriter();
+        URL url = null;
+        try {
+            if ("context".equals(mode))
+                url = getServletContext().getResource(path);
+            else
+                url = this.getClass().getResource(path);
+            if (url == null)
+                writer.println("Resources02 PASSED");
+            else
+                writer.println("Resources02 FAILED - Returned URL " +
+                               url.toString());
+        } catch (MalformedURLException e) {
+            writer.println("Resources02 FAILED - MalformedURLException: "
+                           + e);
+        }
+
+        // Add wrapper messages as required
+        while (true) {
+            String message = StaticLogger.read();
+            if (message == null)
+                break;
+            writer.println(message);
+        }
+        StaticLogger.reset();
+
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Resources03.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Resources03.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Resources03.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,110 @@
+/*
+ * Copyright 1999, 2000, 2001 ,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tester;
+
+
+import java.io.*;
+import java.net.MalformedURLException;
+import java.net.URL;
+import javax.servlet.*;
+import javax.servlet.http.*;
+
+
+/**
+ * Positive test for <code>ServletContext.getResourceAsStream()</code> as well
+ * as <code>ClassLoader.getResourceAsStream()</code>.  Operation is controlled
+ * by query parameters:
+ * <ul>
+ * <li><strong>mode</strong> - Use <code>context</code> for servlet context
+ *     test, or <code>class</code> for class loader test.  [context]</li>
+ * <li><strong>path</strong> - Resource path to the requested resource,
+ *     starting with a slash.  [/WEB-INF/web.xml]</li>
+ * </ul>
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class Resources03 extends HttpServlet {
+
+    public void doGet(HttpServletRequest request, HttpServletResponse response)
+        throws IOException, ServletException {
+
+        // Identify our configuration parameters
+        String mode = request.getParameter("mode");
+        if (mode == null)
+            mode = "context";
+        String path = request.getParameter("path");
+        if (path == null)
+            path = "/WEB-INF/web.xml";
+
+        // Execute the desired test
+        response.setContentType("text/plain");
+        PrintWriter writer = response.getWriter();
+        InputStream is = null;
+        URL url = null;
+        try {
+            if ("context".equals(mode)) {
+                is = getServletContext().getResourceAsStream(path);
+                url = getServletContext().getResource(path);
+            } else {
+                is = this.getClass().getResourceAsStream(path);
+                url = this.getClass().getResource(path);
+            }
+            if (url == null) {
+                if (is == null)
+                    writer.println("Resources03 FAILED - No IS or URL was returned");
+                else
+                    writer.println("Resources03 FAILED - Returned IS but no URL");
+            } else {
+                if (is == null)
+                    writer.println("Resources03 FAILED - Returned URL but no IS");
+                else {
+                    InputStreamReader isr = new InputStreamReader(is);
+                    while (true) {
+                        int c = isr.read();
+                        if (c < 0)
+                            break;
+                        char ch = (char) c;
+                        if (ch < ' ')
+                            break;
+                        writer.print(ch);
+                    }
+                    isr.close();
+                }
+                writer.println();
+                writer.println("url = " + url.toString());
+            }
+        } catch (MalformedURLException e) {
+            writer.println("Resources03 FAILED - MalformedURLException: "
+                           + e);
+        } catch (IOException e) {
+            writer.println("Resources03 FAILED - IOException: " + e);
+        }
+
+        // Add wrapper messages as required
+        while (true) {
+            String message = StaticLogger.read();
+            if (message == null)
+                break;
+            writer.println(message);
+        }
+        StaticLogger.reset();
+
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Resources03.txt
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Resources03.txt	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Resources03.txt	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1 @@
+Resources03 PASSED

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Resources04.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Resources04.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Resources04.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,95 @@
+/*
+ * Copyright 1999, 2000, 2001 ,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tester;
+
+
+import java.io.*;
+import java.net.MalformedURLException;
+import java.net.URL;
+import javax.servlet.*;
+import javax.servlet.http.*;
+
+
+/**
+ * Negative test for <code>ServletContext.getResourceAsStream()</code> as well
+ * as <code>ClassLoader.getResourceAsStream()</code>.  Operation is controlled
+ * by query parameters:
+ * <ul>
+ * <li><strong>mode</strong> - Use <code>context</code> for servlet context
+ *     test, or <code>class</code> for class loader test.  [context]</li>
+ * <li><strong>path</strong> - Resource path to the requested resource,
+ *     starting with a slash.  [/WEB-INF/web.xml]</li>
+ * </ul>
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class Resources04 extends HttpServlet {
+
+    public void doGet(HttpServletRequest request, HttpServletResponse response)
+        throws IOException, ServletException {
+
+        // Identify our configuration parameters
+        String mode = request.getParameter("mode");
+        if (mode == null)
+            mode = "context";
+        String path = request.getParameter("path");
+        if (path == null)
+            path = "/WEB-INF/web.xml";
+
+        // Execute the desired test
+        response.setContentType("text/plain");
+        PrintWriter writer = response.getWriter();
+        InputStream is = null;
+        URL url = null;
+        try {
+            if ("context".equals(mode)) {
+                is = getServletContext().getResourceAsStream(path);
+                url = getServletContext().getResource(path);
+            } else {
+                is = this.getClass().getResourceAsStream(path);
+                url = this.getClass().getResource(path);
+            }
+            if (is == null) {
+                if (url == null)
+                    writer.println("Resources04 PASSED");
+                else
+                    writer.println("Resources04 FAILED - Stream is null but URL is " + url);
+            } else {
+                if (url != null)
+                    writer.println("Resources04 FAILED - Stream is not null and  URL is " + url);
+                else
+                    writer.println("Resources04 FAILED - Stream is not null and URL is null");
+            }
+        } catch (MalformedURLException e) {
+            writer.println("Resources04 FAILED - MalformedURLException: "
+                           + e);
+        }
+
+        // Add wrapper messages as required
+        while (true) {
+            String message = StaticLogger.read();
+            if (message == null)
+                break;
+            writer.println(message);
+        }
+        StaticLogger.reset();
+
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Resources05.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Resources05.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Resources05.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,148 @@
+/*
+ * Copyright 1999, 2000, 2001 ,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tester;
+
+
+import java.io.*;
+import java.net.MalformedURLException;
+import java.net.URL;
+import javax.servlet.*;
+import javax.servlet.http.*;
+
+
+/**
+ * Positive test for <code>ServletContext.getResource()</code> as well as
+ * <code>ClassLoader.getResource()</code>.  The URL returned by
+ * these calls is then opened with <code>url.openStream()</code>
+ * in order to ensure that the correct data is actually read.
+ * Operation is controlled by query parameters:
+ * <ul>
+ * <li><strong>mode</strong> - Use <code>context</code> for servlet context
+ *     test, or <code>class</code> for class loader test.  [context]</li>
+ * <li><strong>path</strong> - Resource path to the requested resource,
+ *     starting with a slash.  [/WEB-INF/web.xml]</li>
+ * <li><strong>stringify</strong> - If set to any arbitrary value, the URL
+ *     returned by getResource() will be converted to a String and then back
+ *     to a URL before being opened.  [not set]</li>
+ * </ul>
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class Resources05 extends HttpServlet {
+
+    public void doGet(HttpServletRequest request, HttpServletResponse response)
+        throws IOException, ServletException {
+
+        // Identify our configuration parameters
+        String mode = request.getParameter("mode");
+        if (mode == null)
+            mode = "context";
+        String path = request.getParameter("path");
+        if (path == null)
+            path = "/WEB-INF/web.xml";
+        boolean stringify = (request.getParameter("stringify") != null);
+
+        // Prepare for the desired test
+        response.setContentType("text/plain");
+        PrintWriter writer = response.getWriter();
+        InputStream is = null;
+        InputStreamReader isr = null;
+        URL url = null;
+        StringBuffer results = new StringBuffer();
+        boolean ok = true;
+
+        // Acquire the appropriate URL
+        try {
+            if ("context".equals(mode))
+                url = getServletContext().getResource(path);
+            else
+                url = this.getClass().getResource(path);
+            if (url == null) {
+                results.append(" No URL returned");
+                ok = false;
+            }
+        } catch (MalformedURLException e) {
+            results.append(" getResource MalformedURLException");
+            ok = false;
+        }
+
+        // Stringify the URL if requested
+        try {
+            if (ok) {
+                StaticLogger.write("Stringifying the URL");
+                String urlString = url.toString();
+                url = new URL(urlString);
+            }
+        } catch (MalformedURLException e) {
+            results.append(" stringify MalformedURLException");
+        }
+
+        // Open an input stream and input stream reader on this URL
+        try {
+            if (ok) {
+                is = url.openStream();
+                isr = new InputStreamReader(is);
+            }
+        } catch (IOException e) {
+            results.append(" Open IOException: " + e);
+            ok = false;
+        }
+
+        // Copy the contents of this stream to our output
+        try {
+            if (ok) {
+                while (true) {
+                    int ch = isr.read();
+                    if (ch < 0)
+                        break;
+                    writer.print((char) ch);
+                }
+            }
+        } catch (IOException e) {
+            results.append(" Copy IOException: " + e);
+            ok = false;
+        }
+
+        // Close the input stream
+        try {
+            if (ok) {
+                isr.close();
+            }
+        } catch (IOException e) {
+            results.append(" Close IOException: " + e);
+        }
+
+        // Report any failures we have encountered
+        if (!ok) {
+            writer.print("Resources05 FAILED -");
+            writer.println(results.toString());
+        }
+
+        // Add wrapper messages as required
+        while (true) {
+            String message = StaticLogger.read();
+            if (message == null)
+                break;
+            writer.println(message);
+        }
+        StaticLogger.reset();
+
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Resources05.txt
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Resources05.txt	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Resources05.txt	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1 @@
+Resources05 PASSED

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Resources06.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Resources06.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Resources06.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,170 @@
+/*
+ * Copyright 1999, 2000, 2001 ,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tester;
+
+
+import java.io.*;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.*;
+import javax.servlet.*;
+import javax.servlet.http.*;
+
+
+/**
+ * Positive test for <code>getResourcePaths()</code>, which will specify the
+ * directory path indicated by the <strong>path</strong> request parameter.
+ * For known paths, at least the known set of included resources must be
+ * found in order to pass.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class Resources06 extends HttpServlet {
+
+    // Resource Lists (incomplete) for known directory paths
+    String rootPaths[] =
+    { "/ErrorPage06.html", "/ErrorPage06.jsp", "/Forward01.txt",
+      "/Include01.txt", "/WEB-INF/", "/Xerces00.jsp", "/Xerces01.xml",
+      "/Xerces02.jsp", "/golden/", "/includeme.txt", "/index.shtml",
+      "/ssidir/" };
+
+    String goldenPaths[] =
+    { "/golden/Golden01.txt", "/golden/SSIConfig01.txt",
+      "/golden/SSIConfig03.txt", "/golden/SSIFsize02.txt",
+      "/golden/SSIInclude01.txt", "/golden/SSIInclude02.txt",
+      "/golden/Session05.txt" };
+
+    String webinfPaths[] =
+    { "/WEB-INF/classes/", "/WEB-INF/lib/", "/WEB-INF/web.xml" };
+
+
+    public void doGet(HttpServletRequest request, HttpServletResponse response)
+        throws IOException, ServletException {
+
+        // Prepare our output writer
+        response.setContentType("text/plain");
+        PrintWriter writer = response.getWriter();
+
+        // Identify our configuration parameters
+        StringBuffer sb = new StringBuffer();
+        String path = request.getParameter("path");
+        if (path == null)
+            path = "/";
+        String paths[] = null;
+        if ("/".equals(path))
+            paths = rootPaths;
+        else if ("/golden".equals(path))
+            paths = goldenPaths;
+        else if ("/WEB-INF".equals(path))
+            paths = webinfPaths;
+        else {
+            sb.append(" Unknown path '");
+            sb.append(path);
+            sb.append("'/");
+        }
+        int counts[] = null;
+        if (paths != null)
+            counts = new int[paths.length];
+
+        // Request the set of resources in the specified path
+        StaticLogger.write("Processing path '" + path + "'");
+        String first = null;
+        Set set = getServletContext().getResourcePaths(path);
+        if (set == null) {
+            sb.append(" No resources returned/");
+            set = new HashSet();
+        }
+
+        // Count the occurrences of the resources we know about
+        Iterator resources = set.iterator();
+        while (resources.hasNext()) {
+            String resource = (String) resources.next();
+            if (first == null)
+                first = resource;
+            StaticLogger.write("Found resource '" + resource + "'");
+            for (int i = 0; i < paths.length; i++) {
+                if (paths[i].equals(resource)) {
+                    counts[i]++;
+                    break;
+                }
+            }
+        }
+
+        // Report on any missing or duplicated resources
+        for (int i = 0; i < paths.length; i++) {
+            if (counts[i] < 1) {
+                sb.append(" Missing resource '");
+                sb.append(paths[i]);
+                sb.append("'/");
+            } else if (counts[i] > 2) {
+                sb.append(" Resource '");
+                sb.append(paths[i]);
+                sb.append("' occurred ");
+                sb.append(counts[i]);
+                sb.append(" times/");
+            }
+        }
+
+        // Verify that the returned set is immutable
+        try {
+            String newElement = "NEW FOO";
+            set.add(newElement);
+            if (set.contains(newElement))
+              sb.append(" Set allowed add()/");
+        } catch (Throwable t) {
+            ;
+        }
+        try {
+            if (first != null) {
+                set.remove(first);
+                if (!set.contains(first))
+                  sb.append(" Set allowed remove()/");
+            }
+        } catch (Throwable t) {
+            ;
+        }
+        try {
+            set.clear();
+            if (set.size() == 0)
+                sb.append(" Set allowed clear()/");
+        } catch (Throwable t) {
+            ;
+        }
+
+
+        // Report any failures we have encountered
+        if (sb.length() > 0) {
+            writer.print("Resources06 FAILED -");
+            writer.println(sb.toString());
+        } else {
+            writer.println("Resources06 PASSED");
+        }
+
+        // Add wrapper messages as required
+        while (true) {
+            String message = StaticLogger.read();
+            if (message == null)
+                break;
+            writer.println(message);
+        }
+        StaticLogger.reset();
+
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/ResponseWrap01.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/ResponseWrap01.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/ResponseWrap01.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,69 @@
+/*
+ * Copyright 1999, 2000, 2001 ,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tester;
+
+
+import java.io.*;
+import javax.servlet.*;
+import javax.servlet.http.*;
+
+/**
+ * Basis for testing wrapped responses with combinations of forwarding to
+ * or including both servlets and JSP pages.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class ResponseWrap01 extends HttpServlet {
+
+    public void doGet(HttpServletRequest request, HttpServletResponse response)
+        throws IOException, ServletException {
+
+        // Acquire request parameters
+        String type = request.getParameter("type");
+        String page = request.getParameter("page");
+
+        // Prepare this response
+        response.setContentType("text/plain");
+        //	PrintWriter writer = response.getWriter();
+
+        // Forward or include as requested
+        RequestDispatcher rd =
+            getServletContext().getRequestDispatcher(page);
+        if (rd == null) {
+            PrintWriter writer = response.getWriter();
+            writer.println("ResponseWrap01 FAILED - No request dispatcher" +
+                           " for " + page);
+        } else if ("F".equals(type)) {
+            HttpServletResponseWrapper wrapper =
+                new CharArrayResponse(response);
+            rd.forward(request, wrapper);
+            wrapper.flushBuffer();
+        } else {
+            HttpServletResponseWrapper wrapper =
+                new CharArrayResponse(response);
+            rd.include(request, wrapper);
+            wrapper.flushBuffer();
+        }
+
+        // No filter wrapping for this test series
+        StaticLogger.reset();
+
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/ResponseWrap01a.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/ResponseWrap01a.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/ResponseWrap01a.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,44 @@
+/*
+ * Copyright 1999, 2000, 2001 ,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tester;
+
+
+import java.io.*;
+import javax.servlet.*;
+import javax.servlet.http.*;
+
+/**
+ * Basis for testing wrapped responses with combinations of forwarding to
+ * or including both servlets and JSP pages.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class ResponseWrap01a extends HttpServlet {
+
+    public void doGet(HttpServletRequest request, HttpServletResponse response)
+        throws IOException, ServletException {
+
+        // Prepare this response
+        response.setContentType("text/plain");
+        PrintWriter writer = response.getWriter();
+        writer.println("ResponseWrap01a PASSED");
+
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/ResponseWrap01c.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/ResponseWrap01c.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/ResponseWrap01c.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,44 @@
+/*
+ * Copyright 1999, 2000, 2001 ,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tester;
+
+
+import java.io.*;
+import javax.servlet.*;
+import javax.servlet.http.*;
+
+/**
+ * Basis for testing wrapped responses with combinations of forwarding to
+ * or including both servlets and JSP pages.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class ResponseWrap01c extends HttpServlet {
+
+    public void doGet(HttpServletRequest request, HttpServletResponse response)
+        throws IOException, ServletException {
+
+        // Prepare this response
+        response.setContentType("text/plain");
+        PrintWriter writer = response.getWriter();
+        writer.println("ResponseWrap01c PASSED");
+
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Session01.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Session01.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Session01.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,139 @@
+/*
+ * Copyright 1999, 2000 ,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tester;
+
+
+import java.io.*;
+import javax.servlet.*;
+import javax.servlet.http.*;
+import org.apache.tester.shared.SharedSessionBean;
+import org.apache.tester.unpshared.UnpSharedSessionBean;
+import org.apache.tester.unshared.UnsharedSessionBean;
+
+
+/**
+ * Part 1 of Session Tests.  Ensures that there is no current session, then
+ * creates a new session and sets a session attribute.  Also, ensure that
+ * calling setAttribute("name", null) acts like removeAttribute().
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class Session01 extends HttpServlet {
+
+    public void doGet(HttpServletRequest request, HttpServletResponse response)
+        throws IOException, ServletException {
+
+        response.setContentType("text/plain");
+        PrintWriter writer = response.getWriter();
+
+        // Ensure that there is no current session
+        boolean ok = true;
+        HttpSession session = request.getSession(false);
+        if (session != null) {
+            writer.println("Session01 FAILED - Requested existing session " +
+                           session.getId());
+            ok = false;
+        }
+
+        // Create a new session
+        if (ok) {
+            session = request.getSession(true);
+            if (session == null) {
+                writer.println("Session01 FAILED - No session created");
+                ok = false;
+            }
+        }
+
+        // Store an activation event listener in the session
+        if (ok) {
+            session.setAttribute("activationListener",
+                                 new SessionListener03());
+        }
+
+        // Ensure that there is no existing attribute
+        if (ok) {
+            if (session.getAttribute("sessionBean") != null) {
+                writer.println("Session01 FAILED - Attribute already exists");
+                ok = false;
+            }
+        }
+
+        // Create and stash a session attribute
+        if (ok) {
+            SessionBean bean = new SessionBean();
+            bean.setStringProperty("Session01");
+            session.setAttribute("sessionBean", bean);
+        }
+
+        // Ensure that we can retrieve the attribute successfully
+        if (ok) {
+            Object bean = session.getAttribute("sessionBean");
+            if (bean == null) {
+                writer.println("Session01 FAILED - Cannot retrieve attribute");
+                ok = false;
+            } else if (!(bean instanceof SessionBean)) {
+                writer.println("Session01 FAILED - Attribute instance of " +
+                               bean.getClass().getName());
+                ok = false;
+            } else {
+                String value = ((SessionBean) bean).getStringProperty();
+                if (!"Session01".equals(value)) {
+                    writer.println("Session01 FAILED - Property = " + value);
+                    ok = false;
+                }
+            }
+        }
+
+        // Ensure that setAttribute("name", null) works correctly
+        if (ok) {
+            session.setAttribute("FOO", "BAR");
+            session.setAttribute("FOO", null);
+            if (session.getAttribute("FOO") != null) {
+                writer.println("Session01 FAILED - setAttribute(name,null)");
+                ok = false;
+            }
+        }
+
+        // Create more beans that will be used to test application restart
+        if (ok) {
+            SharedSessionBean ssb = new SharedSessionBean();
+            ssb.setStringProperty("Session01");
+            session.setAttribute("sharedSessionBean", ssb);
+            UnpSharedSessionBean ussb = new UnpSharedSessionBean();
+            ussb.setStringProperty("Session01");
+            session.setAttribute("unpSharedSessionBean", ussb);
+            UnsharedSessionBean usb = new UnsharedSessionBean();
+            usb.setStringProperty("Session01");
+            session.setAttribute("unsharedSessionBean", usb);
+        }
+
+        // Report success if everything is still ok
+        if (ok)
+            writer.println("Session01 PASSED");
+        while (true) {
+            String message = StaticLogger.read();
+            if (message == null)
+                break;
+            writer.println(message);
+        }
+        StaticLogger.reset();
+
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Session02.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Session02.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Session02.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,81 @@
+/*
+ * Copyright 1999, 2000 ,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tester;
+
+
+import java.io.*;
+import javax.servlet.*;
+import javax.servlet.http.*;
+
+/**
+ * Part 2 of Session Tests.  Ensures that there is an existing session, and
+ * that the session bean stashed in Part 1 can be retrieved successfully.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class Session02 extends HttpServlet {
+
+    public void doGet(HttpServletRequest request, HttpServletResponse response)
+        throws IOException, ServletException {
+
+        response.setContentType("text/plain");
+        PrintWriter writer = response.getWriter();
+
+        // Ensure that there is a current session
+        boolean ok = true;
+        HttpSession session = request.getSession(false);
+        if (session == null) {
+            writer.println("Session02 FAILED - No existing session " +
+                           request.getRequestedSessionId());
+            ok = false;
+        }
+
+        // Ensure that we can retrieve the attribute successfully
+        if (ok) {
+            Object bean = session.getAttribute("sessionBean");
+            if (bean == null) {
+                writer.println("Session02 FAILED - Cannot retrieve attribute");
+                ok = false;
+            } else if (!(bean instanceof SessionBean)) {
+                writer.println("Session02 FAILED - Attribute instance of " +
+                               bean.getClass().getName());
+                ok = false;
+            } else {
+                String value = ((SessionBean) bean).getStringProperty();
+                if (!"Session01".equals(value)) {
+                    writer.println("Session02 FAILED - Property = " + value);
+                    ok = false;
+                }
+            }
+        }
+
+        // Report success if everything is still ok
+        if (ok)
+            writer.println("Session02 PASSED");
+        while (true) {
+            String message = StaticLogger.read();
+            if (message == null)
+                break;
+            writer.println(message);
+        }
+        StaticLogger.reset();
+
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Session03.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Session03.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Session03.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,198 @@
+/*
+ * Copyright 1999, 2000 ,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tester;
+
+
+import java.io.*;
+import javax.servlet.*;
+import javax.servlet.http.*;
+import org.apache.tester.shared.SharedSessionBean;
+import org.apache.tester.unpshared.UnpSharedSessionBean;
+import org.apache.tester.unshared.UnsharedSessionBean;
+
+
+/**
+ * Part 3 of Session Tests.  Ensures that there is an existing session, and
+ * that the session bean stashed in Part 1 can be retrieved successfully.
+ * Then, it removes that attribute and verifies successful removal.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class Session03 extends HttpServlet {
+
+    public void doGet(HttpServletRequest request, HttpServletResponse response)
+        throws IOException, ServletException {
+
+        response.setContentType("text/plain");
+        PrintWriter writer = response.getWriter();
+
+        // Ensure that there is a current session
+        boolean ok = true;
+        HttpSession session = request.getSession(false);
+        if (session == null) {
+            writer.println("Session03 FAILED - No existing session " +
+                           request.getRequestedSessionId());
+            ok = false;
+        }
+
+        // Ensure that we can retrieve the attribute successfully
+	SessionBean bean = null;
+        if (ok) {
+            Object object = session.getAttribute("sessionBean");
+            if (object == null) {
+                writer.println("Session03 FAILED - Cannot retrieve attribute");
+                ok = false;
+            } else if (!(object instanceof SessionBean)) {
+                writer.println("Session03 FAILED - Attribute instance of " +
+                               object.getClass().getName());
+                ok = false;
+            } else {
+                bean = (SessionBean) object;
+                String value = bean.getStringProperty();
+                if (!"Session01".equals(value)) {
+                    writer.println("Session03 FAILED - Property = " + value);
+                    ok = false;
+                }
+            }
+        }
+
+        // Remove the attribute and guarantee that this was successful
+        if (ok) {
+            session.removeAttribute("sessionBean");
+            if (session.getAttribute("sessionBean") != null) {
+                writer.println("Session03 FAILED - Removal failed");
+                ok = false;
+            }
+        }
+
+	// Validate the bean lifecycle of this bean
+	if (ok) {
+	    String lifecycle = bean.getLifecycle();
+	    if (!"/vb/swp/sda/vu".equals(lifecycle)) {
+	        writer.println("Session03 FAILED - Invalid bean lifecycle '" +
+			       lifecycle + "'");
+		ok = false;
+	    }
+	}
+
+        // Retrieve and validate the shared session bean
+        SharedSessionBean ssb = null;
+        if (ok) {
+            Object object = session.getAttribute("sharedSessionBean");
+            if (object == null) {
+                writer.println("Session03 FAILED - Cannot retrieve ssb");
+                ok = false;
+            } else if (!(object instanceof SharedSessionBean)) {
+                writer.println("Session03 FAILED - Shared attribute class "
+                               + object.getClass().getName());
+                ok = false;
+            } else {
+                ssb = (SharedSessionBean) object;
+                String value = ssb.getStringProperty();
+                if (!"Session01".equals(value)) {
+                    writer.println("Session03 FAILED - Shared property ="
+                                   + value);
+                    ok = false;
+                } else {
+                    session.removeAttribute("sharedSessionBean");
+                    String lifecycle = ssb.getLifecycle();
+                    if (!"/vb/swp/sda/vu".equals(lifecycle)) {
+                        writer.println("Session03 FAILED - Shared lifecycle ="
+                                       + lifecycle);
+                        ok = false;
+                    }
+                }
+            }
+        }
+
+        // Retrieve and validate the unpacked shared session bean
+        UnpSharedSessionBean ussb = null;
+        if (ok) {
+            Object object = session.getAttribute("unpSharedSessionBean");
+            if (object == null) {
+                writer.println("Session03 FAILED - Cannot retrieve ussb");
+                ok = false;
+            } else if (!(object instanceof UnpSharedSessionBean)) {
+                writer.println("Session03 FAILED - unpShared attribute class "
+                               + object.getClass().getName());
+                ok = false;
+            } else {
+                ussb = (UnpSharedSessionBean) object;
+                String value = ussb.getStringProperty();
+                if (!"Session01".equals(value)) {
+                    writer.println("Session03 FAILED - unpShared property ="
+                                   + value);
+                    ok = false;
+                } else {
+                    session.removeAttribute("unpSharedSessionBean");
+                    String lifecycle = ssb.getLifecycle();
+                    if (!"/vb/swp/sda/vu".equals(lifecycle)) {
+                        writer.println("Session03 FAILED - unpShared lifecycle ="
+                                       + lifecycle);
+                        ok = false;
+                    }
+                }
+            }
+        }
+
+        // Retrieve and validate the unshared session bean
+        UnsharedSessionBean usb = null;
+        if (ok) {
+            Object object = session.getAttribute("unsharedSessionBean");
+            if (object == null) {
+                writer.println("Session03 FAILED - Cannot retrieve usb");
+                ok = false;
+            } else if (!(object instanceof UnsharedSessionBean)) {
+                writer.println("Session03 FAILED - Unshared attribute class "
+                               + object.getClass().getName());
+                ok = false;
+            } else {
+                usb = (UnsharedSessionBean) object;
+                String value = usb.getStringProperty();
+                if (!"Session01".equals(value)) {
+                    writer.println("Session03 FAILED - Unshared property = "
+                                   + value);
+                    ok = false;
+                } else {
+                    session.removeAttribute("unsharedSessionBean");
+                    String lifecycle = usb.getLifecycle();
+                    if (!"/vb/swp/sda/vu".equals(lifecycle)) {
+                        writer.println("Session03 FAILED - Unshared lifecycle"
+                                       + " = " + lifecycle);
+                        ok = false;
+                    }
+                }
+            }
+        }
+
+
+        // Report success if everything is still ok
+        if (ok)
+            writer.println("Session03 PASSED");
+        while (true) {
+            String message = StaticLogger.read();
+            if (message == null)
+                break;
+            writer.println(message);
+        }
+        StaticLogger.reset();
+
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Session04.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Session04.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Session04.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,156 @@
+/*
+ * Copyright 1999, 2000 ,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tester;
+
+
+import java.io.*;
+import javax.servlet.*;
+import javax.servlet.http.*;
+
+/**
+ * Part 4 of Session Tests.  Ensures that there is an existing session, and
+ * that the requested session information matches it.  Also, ensure that we
+ * can invalidate this session and create a new one (with a different session
+ * identifier) while processing this request.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class Session04 extends HttpServlet {
+
+    public void doGet(HttpServletRequest request, HttpServletResponse response)
+        throws IOException, ServletException {
+
+        log("Session04 - Starting, requestedSessionId = " +
+            request.getRequestedSessionId());
+        response.setContentType("text/plain");
+        PrintWriter writer = response.getWriter();
+
+        // Ensure that there is a current session
+        StringBuffer results = new StringBuffer();
+        HttpSession oldSession = request.getSession(false);
+        if (oldSession == null)
+            results.append(" No existing session/");
+
+        // Acquire the session identifier of the old session
+        String oldSessionId = null;
+        if (oldSession != null) {
+            try {
+                oldSessionId = oldSession.getId();
+            } catch (IllegalStateException e) {
+                results.append(" Old session is expired/");
+            }
+        }
+
+        // Match against the requested session identifier
+        String requestedSessionId = null;
+        if (oldSessionId != null) {
+            requestedSessionId = request.getRequestedSessionId();
+            if (requestedSessionId == null) {
+                results.append(" No requested session id/");
+            } else {
+                if (!request.isRequestedSessionIdValid())
+                    results.append(" Requested session id is not valid/");
+                if (!oldSessionId.equals(requestedSessionId)) {
+                    results.append(" Requested session=");
+                    results.append(requestedSessionId);
+                    results.append(" Old session=");
+                    results.append(oldSessionId);
+                    results.append("/");
+                }
+            }
+        }
+
+        // Verify that we received the requested session identifier correctly
+        if (requestedSessionId != null) {
+            if (!request.isRequestedSessionIdFromCookie())
+                results.append(" Requested session not from cookie/");
+            if (request.isRequestedSessionIdFromURL())
+                results.append(" Requested session from URL/");
+        }
+
+        // Verify that we can create an attribute in the old session
+        if (oldSession != null) {
+            SessionBean bean = new SessionBean();
+            bean.setStringProperty("Session04");
+            oldSession.setAttribute("sessionBean", bean);
+        }
+
+        // Verify that we can invalidate the old session
+        if (oldSession != null) {
+            try {
+                oldSession.invalidate();
+            } catch (IllegalStateException e) {
+                results.append(" Old session is already invalidated/");
+            }
+        }
+
+        // Verify that we can create a new session
+        HttpSession newSession = request.getSession(true);
+        if (newSession == null) {
+            results.append(" Cannot create new session/");
+        } else {
+            String newSessionId = null;
+            try {
+                newSessionId = newSession.getId();
+            } catch (IllegalStateException e) {
+                results.append(" New session is already invalidated/");
+            }
+            if ((oldSession != null) && (newSession != null)) {
+                if (oldSession == newSession)
+                    results.append(" oldSession == newSession/");
+                if (oldSession.equals(newSession))
+                    results.append(" oldSession equals newSession/");
+            }
+            if ((oldSessionId != null) && (newSessionId != null) &&
+                oldSessionId.equals(newSessionId)) {
+                results.append(" New session id = old session id/");
+            }
+        }
+
+        // Verify that the old session's attribute did not carry forward
+        if (newSession != null) {
+            SessionBean bean =
+                (SessionBean) newSession.getAttribute("sessionBean");
+            if (bean != null)
+                results.append(" New session has attribute already/");
+        }
+
+        // Store an activation event listener in the session
+        newSession.setAttribute("activationListener",
+                                    new SessionListener03());
+
+        // Report success if everything is still ok
+        if (results.length() == 0)
+            writer.println("Session04 PASSED");
+        else {
+            writer.print("Session04 FAILED -");
+            writer.println(results.toString());
+        }
+        while (true) {
+            String message = StaticLogger.read();
+            if (message == null)
+                break;
+            writer.println(message);
+        }
+        StaticLogger.reset();
+        log("Session04 - Stopping");
+
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Session05.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Session05.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Session05.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,62 @@
+/*
+ * Copyright 1999, 2000, 2001 ,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tester;
+
+
+import java.io.*;
+import javax.servlet.*;
+import javax.servlet.http.*;
+
+/**
+ * Part 5 of Session Tests.  Ensures that the appropriate session listener
+ * events get called in the appropriate order.  Relies on proper configuration
+ * of SessionListener01 and SessionListener02 in the web.xml file
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class Session05 extends HttpServlet {
+
+    public void doGet(HttpServletRequest request, HttpServletResponse response)
+        throws IOException, ServletException {
+
+        // Reset the static logger to ensure no leftovers exist
+        StaticLogger.reset();
+
+        // Perform session management activities to trigger listener events
+        HttpSession session = request.getSession(true);
+        session.setAttribute("attribute1", "value1");
+        session.setAttribute("attribute1", "value2");
+        session.removeAttribute("attribute1");
+        session.removeAttribute("attribute2"); // Not present, so no logging
+        session.invalidate();
+
+        // Render the response (to be compared as a golden file)
+        response.setContentType("text/plain");
+        PrintWriter writer = response.getWriter();
+        while (true) {
+            String message = StaticLogger.read();
+            if (message == null)
+                break;
+            writer.println(message);
+        }
+        StaticLogger.reset();
+
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Session06.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Session06.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Session06.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,68 @@
+/*
+ * Copyright 1999, 2000, 2001 ,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tester;
+
+
+import java.io.*;
+import javax.servlet.*;
+import javax.servlet.http.*;
+
+/**
+ * Part 6 of Session Tests.  Ensures that an attempt to create a new session
+ * after the response has been committed throws IllegalStateException.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class Session06 extends HttpServlet {
+
+    public void doGet(HttpServletRequest request, HttpServletResponse response)
+        throws IOException, ServletException {
+
+        // Prepare and commit our response
+        response.setContentType("text/plain");
+        PrintWriter writer = response.getWriter();
+        writer.print("Session06 ");
+        response.flushBuffer();
+
+        // Attempt to create a new session
+        try {
+            HttpSession session = request.getSession(true);
+            if (session == null)
+                writer.println("FAILED - Did not throw IllegalStateException");
+            else
+                writer.println("FAILED - Returned new session");
+        } catch (IllegalStateException e) {
+            writer.println("PASSED");
+        } catch (Throwable t) {
+            writer.println("FAILED - Threw " + t);
+            t.printStackTrace(writer);
+        }
+
+        while (true) {
+            String message = StaticLogger.read();
+            if (message == null)
+                break;
+            writer.println(message);
+        }
+        StaticLogger.reset();
+        response.flushBuffer();
+
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/SessionBean.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/SessionBean.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/SessionBean.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,161 @@
+/*
+ * Copyright 1999, 2000 ,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tester;
+
+
+import java.io.Serializable;
+import java.sql.Date;
+import javax.servlet.http.HttpSessionActivationListener;
+import javax.servlet.http.HttpSessionBindingEvent;
+import javax.servlet.http.HttpSessionBindingListener;
+import javax.servlet.http.HttpSessionEvent;
+
+
+/**
+ * Simple JavaBean to use for session attribute tests.  It is Serializable
+ * so that instances can be saved and restored across server restarts.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class SessionBean implements
+    HttpSessionActivationListener, HttpSessionBindingListener, Serializable {
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * A date property for use with property editor tests.
+     */
+    protected Date dateProperty =
+        new Date(System.currentTimeMillis());
+
+    public Date getDateProperty() {
+        return (this.dateProperty);
+    }
+
+    public void setDateProperty(Date dateProperty) {
+        this.dateProperty = dateProperty;
+    }
+
+
+    /**
+     * The lifecycle events that have happened on this bean instance.
+     */
+    protected String lifecycle = "";
+
+    public String getLifecycle() {
+        return (this.lifecycle);
+    }
+
+    public void setLifecycle(String lifecycle) {
+        this.lifecycle = lifecycle;
+    }
+
+
+    /**
+     * A string property.
+     */
+    protected String stringProperty = "Default String Property Value";
+
+    public String getStringProperty() {
+        return (this.stringProperty);
+    }
+
+    public void setStringProperty(String stringProperty) {
+        this.stringProperty = stringProperty;
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Return a string representation of this bean.
+     */
+    public String toString() {
+
+        StringBuffer sb = new StringBuffer("SessionBean[lifecycle=");
+        sb.append(this.lifecycle);
+        sb.append(",dateProperty=");
+        sb.append(dateProperty);
+        sb.append(",stringProperty=");
+        sb.append(this.stringProperty);
+        sb.append("]");
+        return (sb.toString());
+
+    }
+
+
+    // ---------------------------------- HttpSessionActivationListener Methods
+
+
+    /**
+     * Receive notification that this session was activated.
+     *
+     * @param event The session event that has occurred
+     */
+    public void sessionDidActivate(HttpSessionEvent event) {
+
+        lifecycle += "/sda";
+
+    }
+
+
+    /**
+     * Receive notification that this session will be passivated.
+     *
+     * @param event The session event that has occurred
+     */
+    public void sessionWillPassivate(HttpSessionEvent event) {
+
+        lifecycle += "/swp";
+
+    }
+
+
+    // ------------------------------------- HttpSessionBindingListener Methods
+
+
+    /**
+     * Receive notification that this attribute has been bound.
+     *
+     * @param event The session event that has occurred
+     */
+    public void valueBound(HttpSessionBindingEvent event) {
+
+        lifecycle += "/vb";
+
+    }
+
+
+    /**
+     * Receive notification that this attribute has been unbound.
+     *
+     * @param event The session event that has occurred
+     */
+    public void valueUnbound(HttpSessionBindingEvent event) {
+
+        lifecycle += "/vu";
+
+    }
+
+
+}
+

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/SessionListener01.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/SessionListener01.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/SessionListener01.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,76 @@
+/*
+ * Copyright 1999, 2000, 2001 ,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tester;
+
+
+import java.io.*;
+import javax.servlet.*;
+import javax.servlet.http.*;
+
+/**
+ * Application event listener for session events.  All events that occur
+ * are logged appropriately to the static logger.  In addition, session
+ * creation and destruction events are logged to the servlet context log.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class SessionListener01
+    implements HttpSessionListener, HttpSessionAttributeListener {
+
+
+    public void attributeAdded(HttpSessionBindingEvent event) {
+        StaticLogger.write("SessionListener01: attributeAdded(" +
+                           event.getName() + "," + event.getValue() + ")");
+        event.getSession().getServletContext().log
+            ("SessionListener01: attributeAdded(" + event.getSession().getId()
+             + "," + event.getName() + ")");
+    }
+
+    public void attributeRemoved(HttpSessionBindingEvent event) {
+        StaticLogger.write("SessionListener01: attributeRemoved(" +
+                           event.getName() + "," + event.getValue() + ")");
+        event.getSession().getServletContext().log
+            ("SessionListener01: attributeRemoved(" +
+             event.getSession().getId() + "," + event.getName() + ")");
+    }
+
+    public void attributeReplaced(HttpSessionBindingEvent event) {
+        StaticLogger.write("SessionListener01: attributeReplaced(" +
+                           event.getName() + "," + event.getValue() + ")");
+        event.getSession().getServletContext().log
+            ("SessionListener01: attributeReplaced(" +
+             event.getSession().getId() + "," + event.getName() + ")");
+    }
+
+    public void sessionCreated(HttpSessionEvent event) {
+        StaticLogger.write("SessionListener01: sessionCreated()");
+        HttpSession session = event.getSession();
+        session.getServletContext().log("SessionListener01: sessionCreated(" +
+                                        session.getId() + ")");
+    }
+
+    public void sessionDestroyed(HttpSessionEvent event) {
+        StaticLogger.write("SessionListener01: sessionDestroyed()");
+        HttpSession session = event.getSession();
+        session.getServletContext().log("SessionListener01: sessionDestroyed("
+                                        + session.getId() + ")");
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/SessionListener02.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/SessionListener02.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/SessionListener02.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,60 @@
+/*
+ * Copyright 1999, 2000, 2001 ,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tester;
+
+
+import java.io.*;
+import javax.servlet.*;
+import javax.servlet.http.*;
+
+/**
+ * Application event listener for session events.  All events that occur
+ * are logged appropriately to the static logger.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class SessionListener02
+    implements HttpSessionListener, HttpSessionAttributeListener {
+
+
+    public void attributeAdded(HttpSessionBindingEvent event) {
+        StaticLogger.write("SessionListener02: attributeAdded(" +
+                           event.getName() + "," + event.getValue() + ")");
+    }
+
+    public void attributeRemoved(HttpSessionBindingEvent event) {
+        StaticLogger.write("SessionListener02: attributeRemoved(" +
+                           event.getName() + "," + event.getValue() + ")");
+    }
+
+    public void attributeReplaced(HttpSessionBindingEvent event) {
+        StaticLogger.write("SessionListener02: attributeReplaced(" +
+                           event.getName() + "," + event.getValue() + ")");
+    }
+
+    public void sessionCreated(HttpSessionEvent event) {
+        StaticLogger.write("SessionListener02: sessionCreated()");
+    }
+
+    public void sessionDestroyed(HttpSessionEvent event) {
+        StaticLogger.write("SessionListener02: sessionDestroyed()");
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/SessionListener03.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/SessionListener03.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/SessionListener03.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,63 @@
+/*
+ * Copyright 1999, 2000, 2001, 2002 ,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tester;
+
+
+import java.io.*;
+import javax.servlet.*;
+import javax.servlet.http.*;
+
+
+/**
+ * Session attribute that listens to passivation and activation events.
+ * All events that occur are logged to the servlet context log.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 304039 $ $Date: 2005-08-01 11:55:47 -0500 (Mon, 01 Aug 2005) $
+ */
+
+public class SessionListener03
+    implements HttpSessionActivationListener, HttpSessionBindingListener,
+               Serializable {
+
+    public void sessionDidActivate(HttpSessionEvent event) {
+        event.getSession().getServletContext().log
+            ("SessionListener03: sessionDidActivate(" +
+             event.getSession().getId() + ")");
+    }
+
+    public void sessionWillPassivate(HttpSessionEvent event) {
+        event.getSession().getServletContext().log
+            ("SessionListener03: sessionWillPassivate(" +
+             event.getSession().getId() + ")");
+    }
+
+    public void valueBound(HttpSessionBindingEvent event) {
+        event.getSession().getServletContext().log
+            ("SessionListener03: valueBound(" +
+             event.getSession().getId() + "," +
+             event.getName() + ")");
+    }
+
+    public void valueUnbound(HttpSessionBindingEvent event) {
+        event.getSession().getServletContext().log
+            ("SessionListener03: valueUnbound(" +
+             event.getName() + ")");
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/SetBufferSize01.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/SetBufferSize01.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/SetBufferSize01.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,75 @@
+/*
+ * Copyright 1999, 2000 ,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tester;
+
+
+import java.io.*;
+import java.util.*;
+import javax.servlet.*;
+import javax.servlet.http.*;
+
+
+/**
+ * Negative test for ServletResponse.setBufferSize().
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class SetBufferSize01 extends GenericServlet {
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Process a servlet request and create the corresponding response.
+     *
+     * @param request The request we are processing
+     * @param response The response we are creating
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception ServletException if a servlet error occurs
+     */
+    public void service(ServletRequest request, ServletResponse response)
+        throws IOException, ServletException {
+
+        response.setContentType("text/plain");
+        PrintWriter writer = response.getWriter();
+        try {
+            writer.print("SetBufferSize01 ");
+            response.flushBuffer();
+            response.setBufferSize(100);
+            writer.println("FAILED - Did not throw IllegalStateException");
+        } catch (IllegalStateException e) {
+            writer.println("PASSED");
+        } catch (IOException e) {
+            writer.println("FAILED - flushBuffer() threw IOException");
+            throw e;
+        }
+        while (true) {
+            String message = StaticLogger.read();
+            if (message == null)
+                break;
+            writer.println(message);
+        }
+        StaticLogger.reset();
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/SetLocale01.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/SetLocale01.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/SetLocale01.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,66 @@
+/*
+ * Copyright 1999, 2000 ,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tester;
+
+
+import java.io.*;
+import java.util.*;
+import javax.servlet.*;
+import javax.servlet.http.*;
+
+
+/**
+ * Positive test for ServletResponse.setLocale().
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class SetLocale01 extends GenericServlet {
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Process a servlet request and create the corresponding response.
+     *
+     * @param request The request we are processing
+     * @param response The response we are creating
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception ServletException if a servlet error occurs
+     */
+    public void service(ServletRequest request, ServletResponse response)
+        throws IOException, ServletException {
+
+        response.setContentType("text/plain");
+        response.setLocale(new Locale("en", "US"));
+        PrintWriter writer = response.getWriter();
+        writer.println("SetLocale01 PASSED");
+        while (true) {
+            String message = StaticLogger.read();
+            if (message == null)
+                break;
+            writer.println(message);
+        }
+        StaticLogger.reset();
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/StaticFilter.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/StaticFilter.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/StaticFilter.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,88 @@
+/*
+ * Copyright 1999, 2000, 2001 ,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tester;
+
+
+import java.io.*;
+import java.util.*;
+import javax.servlet.*;
+import javax.servlet.http.*;
+
+/**
+ * Simple filter to reset the static log at the beginning of each request,
+ * so that no leftovers from the previous request are inadvertently included.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class StaticFilter implements Filter {
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The filter configuration object for this filter.
+     */
+    protected FilterConfig config = null;
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Release this Filter instance from service.
+     */
+    public void destroy() {
+
+        config = null;
+
+    }
+
+
+    /**
+     * Wrap this request and/or response as configured and pass it on.
+     */
+    public void doFilter(ServletRequest inRequest, ServletResponse inResponse,
+                         FilterChain chain)
+        throws IOException, ServletException {
+
+        // Reset our logger and perform this request
+        StaticLogger.reset();
+        chain.doFilter(inRequest, inResponse);
+
+    }
+
+
+    /**
+     * Place this Filter instance into service.
+     *
+     * @param config The filter configuration object
+     */
+    public void init(FilterConfig config) throws ServletException {
+
+        this.config = config;
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/StaticLogger.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/StaticLogger.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/StaticLogger.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,101 @@
+/*
+ * Copyright 1999, 2000 ,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tester;
+
+
+import java.io.*;
+import java.util.*;
+import javax.servlet.*;
+import javax.servlet.http.*;
+
+
+/**
+ * Logger that uses a static message buffer to facilitate intra-web-app
+ * recording and retrieval of log messages.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class StaticLogger {
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    // ------------------------------------------------------- Static Variables
+
+
+    /**
+     * The set of messages that have been logged.
+     */
+    protected static ArrayList messages = new ArrayList();
+
+
+    /**
+     * The index of the next message that will be retrieved by a read() call.
+     */
+    protected static int position = 0;
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Return the next message that has been logged, or <code>null</code>
+     * if there are no more messages.
+     */
+    public static String read() {
+
+        synchronized (messages) {
+            if (position < messages.size())
+                return ((String) messages.get(position++));
+            else
+                return (null);
+        }
+
+    }
+
+
+    /**
+     * Reset the messages buffer and position.
+     */
+    public static void reset() {
+
+        synchronized (messages) {
+            messages.clear();
+            position = 0;
+        }
+
+    }
+
+
+    /**
+     * Write a new message to the end of the messages buffer.
+     *
+     * @param message The message to be added
+     */
+    public static void write(String message) {
+
+        synchronized (messages) {
+            messages.add(message);
+        }
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/TestClient.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/TestClient.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/TestClient.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,1046 @@
+/*
+ * Copyright 1999, 2000 ,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tester;
+
+
+import java.io.FileNotFoundException;
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.PrintWriter;
+import java.net.ConnectException;
+import java.net.HttpURLConnection;
+import java.net.Socket;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Task;
+
+
+/**
+ * <p>This class contains a <strong>Task</strong> for Ant that is used to
+ * send HTTP requests to a servlet container, and examine the responses.
+ * It is similar in purpose to the <code>GTest</code> task in Watchdog,
+ * but uses the JDK's HttpURLConnection for underlying connectivity.</p>
+ *
+ * <p>The task is registered with Ant using a <code>taskdef</code> directive:
+ * <pre>
+ *   &lt;taskdef name="tester" classname="org.apache.tester.TestClient"&gt;
+ * </pre>
+ * and accepts the following configuration properties:</p>
+ * <ul>
+ * <li><strong>golden</strong> - The server-relative path of the static
+ *     resource containing the golden file for this request.</li>
+ * <li><strong>host</strong> - The server name to which this request will be
+ *     sent.  Defaults to <code>localhost</code> if not specified.</li>
+ * <li><strong>inContent</strong> - The data content that will be submitted
+ *     with this request.  The test client will transparently add a carriage
+ *     return and line feed, and set the content length header, if this is
+ *     specified.  Otherwise, no content will be included in the request.</li>
+ * <li><strong>inHeaders</strong> - The set of one or more HTTP headers that
+ *     will be included on the request.</li>
+ * <li><strong>message</strong> - The HTTP response message that is expected
+ *     in the response from the server.  No check is made if no message
+ *     is specified.</li>
+ * <li><strong>method</strong> - The HTTP request method to be used on this
+ *     request.  Defaults to <ocde>GET</code> if not specified.</li>
+ * <li><strong>outContent</strong> - The first line of the response data
+ *     content that we expect to receive.  No check is made if no content is
+ *     specified.</li>
+ * <li><strong>outHeaders</strong> - The set of one or more HTTP headers that
+ *     are expected in the response (order independent).</li>
+ * <li><strong>port</strong> - The port number to which this request will be
+ *     sent.  Defaults to <code>8080</code> if not specified.</li>
+ * <li><strong>redirect</strong> - If set to true, follow any redirect that
+ *     is returned by the server.  (Only works when using HttpURLConnection).
+ *     </li>
+ * <li><strong>request</strong> - The request URI to be transmitted for this
+ *     request.  This value should start with a slash character ("/"), and
+ *     be the server-relative URI of the requested resource.</li>
+ * <li><strong>status</strong> - The HTTP status code that is expected in the
+ *     response from the server.  Defaults to <code>200</code> if not
+ *     specified.  Set to zero to disable checking the return value.</li>
+ * </ul>
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 303278 $ $Date: 2004-09-25 16:27:31 -0500 (Sat, 25 Sep 2004) $
+ */
+
+public class TestClient extends Task {
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The saved golden file we will compare to the response.  Each element
+     * contains a line of text without any line delimiters.
+     */
+    protected ArrayList saveGolden = new ArrayList();
+
+
+    /**
+     * The saved headers we received in our response.  The key is the header
+     * name (converted to lower case), and the value is an ArrayList of the
+     * string value(s) received for that header.
+     */
+    protected HashMap saveHeaders = new HashMap();
+
+
+    /**
+     * The response file to be compared to the golden file.  Each element
+     * contains a line of text without any line delimiters.
+     */
+    protected ArrayList saveResponse = new ArrayList();
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * The debugging detail level for this execution.
+     */
+    protected int debug = 0;
+
+    public int getDebug() {
+        return (this.debug);
+    }
+
+    public void setDebug(int debug) {
+        this.debug = debug;
+    }
+
+
+    /**
+     * The server-relative request URI of the golden file for this request.
+     */
+    protected String golden = null;
+
+    public String getGolden() {
+        return (this.golden);
+    }
+
+    public void setGolden(String golden) {
+        this.golden = golden;
+    }
+
+
+    /**
+     * The host name to which we will connect.
+     */
+    protected String host = "localhost";
+
+    public String getHost() {
+        return (this.host);
+    }
+
+    public void setHost(String host) {
+        this.host = host;
+    }
+
+
+    /**
+     * The first line of the request data that will be included on this
+     * request.
+     */
+    protected String inContent = null;
+
+    public String getInContent() {
+        return (this.inContent);
+    }
+
+    public void setInContent(String inContent) {
+        this.inContent = inContent;
+    }
+
+
+    /**
+     * The HTTP headers to be included on the request.  Syntax is
+     * <code>{name}:{value}[##{name}:{value}] ...</code>.
+     */
+    protected String inHeaders = null;
+
+    public String getInHeaders() {
+        return (this.inHeaders);
+    }
+
+    public void setInHeaders(String inHeaders) {
+        this.inHeaders = inHeaders;
+    }
+
+
+    /**
+     * Should we join the session whose session identifier was returned
+     * on the previous request.
+     */
+    protected boolean joinSession = false;
+
+    public boolean getJoinSession() {
+        return (this.joinSession);
+    }
+
+    public void setJoinSession(boolean joinSession) {
+        this.joinSession = true;
+    }
+
+
+    /**
+     * The HTTP response message to be expected in the response.
+     */
+    protected String message = null;
+
+    public String getMessage() {
+        return (this.message);
+    }
+
+    public void setMessage(String message) {
+        this.message = message;
+    }
+
+
+    /**
+     * The HTTP request method that will be used.
+     */
+    protected String method = "GET";
+
+    public String getMethod() {
+        return (this.method);
+    }
+
+    public void setMethod(String method) {
+        this.method = method;
+    }
+
+
+    /**
+     * The first line of the response data content that we expect to receive.
+     */
+    protected String outContent = null;
+
+    public String getOutContent() {
+        return (this.outContent);
+    }
+
+    public void setOutContent(String outContent) {
+        this.outContent = outContent;
+    }
+
+
+    /**
+     * The HTTP headers to be checked on the response.  Syntax is
+     * <code>{name}:{value}[##{name}:{value}] ...</code>.
+     */
+    protected String outHeaders = null;
+
+    public String getOutHeaders() {
+        return (this.outHeaders);
+    }
+
+    public void setOutHeaders(String outHeaders) {
+        this.outHeaders = outHeaders;
+    }
+
+
+    /**
+     * The port number to which we will connect.
+     */
+    protected int port = 8080;
+
+    public int getPort() {
+        return (this.port);
+    }
+
+    public void setPort(int port) {
+        this.port = port;
+    }
+
+
+    /**
+     * The protocol and version to include in the request, if executed as
+     * a direct socket connection.  Lack of a value here indicates that an
+     * HttpURLConnection should be used instead.
+     */
+    protected String protocol = null;
+
+    public String getProtocol() {
+        return (this.protocol);
+    }
+
+    public void setProtocol(String protocol) {
+        this.protocol = protocol;
+    }
+
+
+    /**
+     * Should we follow redirects returned by the server?
+     */
+    protected boolean redirect = false;
+
+    public boolean getRedirect() {
+        return (this.redirect);
+    }
+
+    public void setRedirect(boolean redirect) {
+        this.redirect = redirect;
+    }
+
+
+    /**
+     * The request URI to be sent to the server.  This value is required.
+     */
+    protected String request = null;
+
+    public String getRequest() {
+        return (this.request);
+    }
+
+    public void setRequest(String request) {
+        this.request = request;
+    }
+
+
+    /**
+     * The HTTP status code expected on the response.
+     */
+    protected int status = 200;
+
+    public int getStatus() {
+        return (this.status);
+    }
+
+    public void setStatus(int status) {
+        this.status = status;
+    }
+
+
+    // ------------------------------------------------------- Static Variables
+
+
+    /**
+     * The session identifier returned by the most recent request, or
+     * <code>null</code> if the previous request did not specify a session
+     * identifier.
+     */
+    protected static String sessionId = null;
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Execute the test that has been configured by our property settings.
+     *
+     * @exception BuildException if an exception occurs
+     */
+    public void execute() throws BuildException {
+
+        saveHeaders.clear();
+        try {
+            readGolden();
+        } catch (IOException e) {
+            log("FAIL:  readGolden(" + golden + ")");
+            e.printStackTrace(System.out);
+        }
+        if ((protocol == null) || (protocol.length() == 0))
+            executeHttp();
+        else
+            executeSocket();
+
+    }
+
+
+    // ------------------------------------------------------ Protected Methods
+
+
+    /**
+     * Execute the test via use of an HttpURLConnection.
+     *
+     * @exception BuildException if an exception occurs
+     */
+    protected void executeHttp() throws BuildException {
+
+        // Construct a summary of the request we will be sending
+        String summary = "[" + method + " " + request + "]";
+        if (debug >= 1)
+            log("RQST: " + summary);
+        boolean success = true;
+        String result = null;
+        Throwable throwable = null;
+        HttpURLConnection conn = null;
+
+        try {
+
+            // Configure an HttpURLConnection for this request
+            URL url = new URL("http", host, port, request);
+            conn = (HttpURLConnection) url.openConnection();
+            conn.setAllowUserInteraction(false);
+            conn.setDoInput(true);
+            if (inContent != null) {
+                conn.setDoOutput(true);
+                conn.setRequestProperty("Content-Length",
+                                        "" + inContent.length());
+                if (debug >= 1)
+                    log("INPH: Content-Length: " +
+                                       inContent.length());
+            } else {
+                conn.setDoOutput(false);
+            }
+
+            // Send the session id cookie (if any)
+            if (joinSession && (sessionId != null)) {
+                conn.setRequestProperty("Cookie",
+                                        "JSESSIONID=" + sessionId);
+                if (debug >= 1)
+                    log("INPH: Cookie: JSESSIONID=" +
+                                       sessionId);
+            }
+
+            if (this.redirect && (debug >= 1))
+                log("FLAG: setInstanceFollowRedirects(" +
+                                   this.redirect + ")");
+            conn.setInstanceFollowRedirects(this.redirect);
+            conn.setRequestMethod(method);
+            if (inHeaders != null) {
+                String headers = inHeaders;
+                while (headers.length() > 0) {
+                    int delimiter = headers.indexOf("##");
+                    String header = null;
+                    if (delimiter < 0) {
+                        header = headers;
+                        headers = "";
+                    } else {
+                        header = headers.substring(0, delimiter);
+                        headers = headers.substring(delimiter + 2);
+                    }
+                    int colon = header.indexOf(":");
+                    if (colon < 0)
+                        break;
+                    String name = header.substring(0, colon).trim();
+                    String value = header.substring(colon + 1).trim();
+                    conn.setRequestProperty(name, value);
+                    if (debug >= 1)
+                        log("INPH: " + name + ": " + value);
+                }
+            }
+
+            // Connect to the server and send our output if necessary
+            conn.connect();
+            if (inContent != null) {
+                if (debug >= 1)
+                    log("INPD: " + inContent);
+                OutputStream os = conn.getOutputStream();
+                for (int i = 0; i < inContent.length(); i++)
+                    os.write(inContent.charAt(i));
+                os.close();
+            }
+
+            // Acquire the response data, if there is any
+            String outData = "";
+            String outText = "";
+            boolean eol = false;
+            InputStream is = conn.getInputStream();
+            int lines = 0;
+            while (true) {
+                String line = read(is);
+                if (line == null)
+                    break;                
+                if (lines == 0)
+                    outData = line;
+                else
+                    outText += line + "\r\n";
+                saveResponse.add(line);
+                lines++;
+            }
+            is.close();
+
+            // Dump out the response stuff
+            if (debug >= 1)
+                log("RESP: " + conn.getResponseCode() + " " +
+                                   conn.getResponseMessage());
+            for (int i = 1; i < 1000; i++) {
+                String name = conn.getHeaderFieldKey(i);
+                String value = conn.getHeaderField(i);
+                if ((name == null) || (value == null))
+                    break;
+                if (debug >= 1)
+                    log("HEAD: " + name + ": " + value);
+                save(name, value);
+                if ("Set-Cookie".equals(name))
+                    parseSession(value);
+            }
+            if (debug >= 1) {
+                log("DATA: " + outData);
+                if (outText.length() > 2)
+                    log("TEXT: " + outText);
+            }
+
+            // Validate the response against our criteria
+            if (success) {
+                result = validateStatus(conn.getResponseCode());
+                if (result != null)
+                    success = false;
+            }
+            if (success) {
+                result = validateMessage(conn.getResponseMessage());
+                if (result != null)
+                    success = false;
+            }
+            if (success) {
+                result = validateHeaders();
+                if (result != null)
+                    success = false;
+            }
+            if (success) {
+                result = validateData(outData);
+                if (result != null)
+                    success = false;
+            }
+            if (success) {
+                result = validateGolden();
+                if (result != null)
+                    success = false;
+            }
+
+        } catch (Throwable t) {
+            if (t instanceof FileNotFoundException) {
+                if (status == 404) {
+                    success = true;
+                    result = "Not Found";
+                    throwable = null;
+                } else {
+                    success = false;
+                    try {
+                        result = "Status=" + conn.getResponseCode() +
+                            ", Message=" + conn.getResponseMessage();
+                    } catch (IOException e) {
+                        result = e.toString();
+                    }
+                    throwable = null;
+                }
+            } else if (t instanceof ConnectException) {
+                success = false;
+                result = t.getMessage();
+                throwable = null;
+            } else {
+                success = false;
+                result = t.getMessage();
+                throwable = t;
+            }
+        }
+
+        // Log the results of executing this request
+        if (success)
+            log("OK " + summary);
+        else {
+            log("FAIL " + summary + " " + result);
+            if (throwable != null)
+                throwable.printStackTrace(System.out);
+        }
+
+    }
+
+
+    /**
+     * Execute the test via use of a socket with direct input/output.
+     *
+     * @exception BuildException if an exception occurs
+     */
+    protected void executeSocket() throws BuildException {
+
+        // Construct a summary of the request we will be sending
+        String command = method + " " + request + " " + protocol;
+        String summary = "[" + command + "]";
+        if (debug >= 1)
+            log("RQST: " + summary);
+        boolean success = true;
+        String result = null;
+        Socket socket = null;
+        OutputStream os = null;
+        PrintWriter pw = null;
+        InputStream is = null;
+        Throwable throwable = null;
+        int outStatus = 0;
+        String outMessage = null;
+
+        try {
+
+            // Open a client socket for this request
+            socket = new Socket(host, port);
+            os = socket.getOutputStream();
+            pw = new PrintWriter(os);
+            is = socket.getInputStream();
+
+            // Send the command and content length header (if any)
+            pw.print(command + "\r\n");
+            if (inContent != null) {
+                if (debug >= 1)
+                    log("INPH: " + "Content-Length: " +
+                                       inContent.length());
+                pw.print("Content-Length: " + inContent.length() + "\r\n");
+            }
+
+            // Send the session id cookie (if any)
+            if (joinSession && (sessionId != null)) {
+                pw.println("Cookie: JSESSIONID=" + sessionId);
+                if (debug >= 1)
+                    log("INPH: Cookie: JSESSIONID=" +
+                                       sessionId);
+            }
+
+            // Send the specified headers (if any)
+            if (inHeaders != null) {
+                String headers = inHeaders;
+                while (headers.length() > 0) {
+                    int delimiter = headers.indexOf("##");
+                    String header = null;
+                    if (delimiter < 0) {
+                        header = headers;
+                        headers = "";
+                    } else {
+                        header = headers.substring(0, delimiter);
+                        headers = headers.substring(delimiter + 2);
+                    }
+                    int colon = header.indexOf(":");
+                    if (colon < 0)
+                        break;
+                    String name = header.substring(0, colon).trim();
+                    String value = header.substring(colon + 1).trim();
+                    if (debug >= 1)
+                        log("INPH: " + name + ": " + value);
+                    pw.print(name + ": " + value + "\r\n");
+                }
+            }
+            pw.print("\r\n");
+
+            // Send our content (if any)
+            if (inContent != null) {
+                if (debug >= 1)
+                    log("INPD: " + inContent);
+                for (int i = 0; i < inContent.length(); i++)
+                    pw.print(inContent.charAt(i));
+            }
+            pw.flush();
+
+            // Read the response status and associated message
+            String line = read(is);
+            if (line == null) {
+                outStatus = -1;
+                outMessage = "NO RESPONSE";
+            } else {
+                line = line.trim();
+                if (debug >= 1)
+                    System.out.println("RESP: " + line);
+                int space = line.indexOf(" ");
+                if (space >= 0) {
+                    line = line.substring(space + 1).trim();
+                    space = line.indexOf(" ");
+                }
+                try {
+                    if (space < 0) {
+                        outStatus = Integer.parseInt(line);
+                        outMessage = "";
+                    } else {
+                        outStatus = Integer.parseInt(line.substring(0, space));
+                        outMessage = line.substring(space + 1).trim();
+                    }
+                } catch (NumberFormatException e) {
+                    outStatus = -1;
+                    outMessage = "NUMBER FORMAT EXCEPTION";
+                }
+            }
+            if (debug >= 1)
+                System.out.println("STAT: " + outStatus + " MESG: " +
+                                   outMessage);
+
+            // Read the response headers (if any)
+            String headerName = null;
+            String headerValue = null;
+            while (true) {
+                line = read(is);
+                if ((line == null) || (line.length() == 0))
+                    break;
+                int colon = line.indexOf(":");
+                if (colon < 0) {
+                    if (debug >= 1)
+                        System.out.println("????: " + line);
+                } else {
+                    headerName = line.substring(0, colon).trim();
+                    headerValue = line.substring(colon + 1).trim();
+                    if (debug >= 1)
+                        System.out.println("HEAD: " + headerName + ": " +
+                                           headerValue);
+                    save(headerName, headerValue);
+                    if ("Set-Cookie".equals(headerName))
+                        parseSession(headerValue);
+                }
+            }
+
+            // Acquire the response data (if any)
+            String outData = "";
+            String outText = "";
+            int lines = 0;
+            while (true) {
+                line = read(is);
+                if (line == null)
+                    break;                
+                if (lines == 0)
+                    outData = line;
+                else
+                    outText += line + "\r\n";
+                saveResponse.add(line);
+                lines++;
+            }
+            is.close();
+            if (debug >= 1) {
+                System.out.println("DATA: " + outData);
+                if (outText.length() > 2)
+                    System.out.println("TEXT: " + outText);
+            }
+
+            // Validate the response against our criteria
+            if (success) {
+                result = validateStatus(outStatus);
+                if (result != null)
+                    success = false;
+            }
+            if (success) {
+                result = validateMessage(message);
+                if (result != null)
+                    success = false;
+            }
+            if (success) {
+                result = validateHeaders();
+                if (result != null)
+                    success = false;
+            }
+            if (success) {
+                result = validateData(outData);
+                if (result != null)
+                    success = false;
+            }
+            if (success) {
+                result = validateGolden();
+                if (result != null)
+                    success = false;
+            }
+
+        } catch (Throwable t) {
+            success = false;
+            result = "Status=" + outStatus +
+                ", Message=" + outMessage;
+            throwable = null;
+        } finally {
+            if (pw != null) {
+                try {
+                    pw.close();
+                } catch (Throwable w) {
+                    ;
+                }
+            }
+            if (os != null) {
+                try {
+                    os.close();
+                } catch (Throwable w) {
+                    ;
+                }
+            }
+            if (is != null) {
+                try {
+                    is.close();
+                } catch (Throwable w) {
+                    ;
+                }
+            }
+            if (socket != null) {
+                try {
+                    socket.close();
+                } catch (Throwable w) {
+                    ;
+                }
+            }
+        }
+
+        if (success)
+            System.out.println("OK " + summary);
+        else {
+            System.out.println("FAIL " + summary + " " + result);
+            if (throwable != null)
+                throwable.printStackTrace(System.out);
+        }
+
+    }
+
+
+    /**
+     * Parse the session identifier from the specified Set-Cookie value.
+     *
+     * @param value The Set-Cookie value to parse
+     */
+    protected void parseSession(String value) {
+
+        if (value == null)
+            return;
+        int equals = value.indexOf("JSESSIONID=");
+        if (equals < 0)
+            return;
+        value = value.substring(equals + "JSESSIONID=".length());
+        int semi = value.indexOf(";");
+        if (semi >= 0)
+            value = value.substring(0, semi);
+
+        if (debug >= 1)
+            System.out.println("SESSION ID: " + value);
+        sessionId = value;
+
+    }
+
+
+    /**
+     * Read and return the next line from the specified input stream, with
+     * no carriage return or line feed delimiters.  If
+     * end of file is reached, return <code>null</code> instead.
+     *
+     * @param stream The input stream to read from
+     *
+     * @exception IOException if an input/output error occurs
+     */
+    protected String read(InputStream stream) throws IOException {
+
+        StringBuffer result = new StringBuffer();
+        while (true) {
+            int b = stream.read();
+            if (b < 0) {
+                if (result.length() == 0)
+                    return (null);
+                else
+                    break;
+            }
+            char c = (char) b;
+            if (c == '\r')
+                continue;
+            else if (c == '\n')
+                break;
+            else
+                result.append(c);
+        }
+        return (result.toString());
+
+    }
+
+
+    /**
+     * Read and save the contents of the golden file for this test, if any.
+     * Otherwise, the <code>saveGolden</code> list will be empty.
+     *
+     * @exception IOException if an input/output error occurs
+     */
+    protected void readGolden() throws IOException {
+
+        // Was a golden file specified?
+        saveGolden.clear();
+        if (golden == null)
+            return;
+
+        // Create a connection to receive the golden file contents
+        URL url = new URL("http", host, port, golden);
+        HttpURLConnection conn =
+            (HttpURLConnection) url.openConnection();
+        conn.setAllowUserInteraction(false);
+        conn.setDoInput(true);
+        conn.setDoOutput(false);
+        conn.setFollowRedirects(true);
+        conn.setRequestMethod("GET");
+
+        // Connect to the server and retrieve the golden file
+        conn.connect();
+        InputStream is = conn.getInputStream();
+        while (true) {
+            String line = read(is);
+            if (line == null)
+                break;
+            saveGolden.add(line);
+        }
+        is.close();
+        conn.disconnect();
+
+    }
+
+
+    /**
+     * Save the specified header name and value in our collection.
+     *
+     * @param name Header name to save
+     * @param value Header value to save
+     */
+    protected void save(String name, String value) {
+
+        String key = name.toLowerCase();
+        ArrayList list = (ArrayList) saveHeaders.get(key);
+        if (list == null) {
+            list = new ArrayList();
+            saveHeaders.put(key, list);
+        }
+        list.add(value);
+
+    }
+
+
+    /**
+     * Validate the output data against what we expected.  Return
+     * <code>null</code> for no problems, or an error message.
+     *
+     * @param data The output data to be tested
+     */
+    protected String validateData(String data) {
+
+        if (outContent == null)
+            return (null);
+        else if (data.startsWith(outContent))
+            return (null);
+        else
+            return ("Expected data '" + outContent + "', got data '" +
+                    data + "'");
+
+    }
+
+
+    /**
+     * Validate the response against the golden file (if any).  Return
+     * <code>null</code> for no problems, or an error message.
+     */
+    protected String validateGolden() {
+
+        if (golden == null)
+            return (null);
+        boolean ok = true;
+        if (saveGolden.size() != saveResponse.size())
+            ok = false;
+        if (ok) {
+            for (int i = 0; i < saveGolden.size(); i++) {
+                String golden = (String) saveGolden.get(i);
+                String response = (String) saveResponse.get(i);
+                if (!golden.equals(response)) {
+                    ok = false;
+                    break;
+                }
+            }
+        }
+        if (ok)
+            return (null);
+        System.out.println("EXPECTED: ======================================");
+        for (int i = 0; i < saveGolden.size(); i++)
+            System.out.println((String) saveGolden.get(i));
+        System.out.println("================================================");
+        System.out.println("RECEIVED: ======================================");
+        for (int i = 0; i < saveResponse.size(); i++)
+            System.out.println((String) saveResponse.get(i));
+        System.out.println("================================================");
+        return ("Failed Golden File Comparison");
+
+    }
+
+
+    /**
+     * Validate the saved headers against the <code>outHeaders</code>
+     * property, and return an error message if there is anything missing.
+     * If all of the expected headers are present, return <code>null</code>.
+     */
+    protected String validateHeaders() {
+
+        // Do we have any headers to check for?
+        if (outHeaders == null)
+            return (null);
+
+        // Check each specified name:value combination
+        String headers = outHeaders;
+        while (headers.length() > 0) {
+            // Parse the next name:value combination
+            int delimiter = headers.indexOf("##");
+            String header = null;
+            if (delimiter < 0) {
+                header = headers;
+                headers = "";
+            } else {
+                header = headers.substring(0, delimiter);
+                headers = headers.substring(delimiter + 2);
+            }
+            int colon = header.indexOf(":");
+            String name = header.substring(0, colon).trim();
+            String value = header.substring(colon + 1).trim();
+            // Check for the occurrence of this header
+            ArrayList list = (ArrayList) saveHeaders.get(name.toLowerCase());
+            if (list == null)
+                return ("Missing header name '" + name + "'");
+            boolean found = false;
+            for (int i = 0; i < list.size(); i++) {
+                if (value.equals((String) list.get(i))) {
+                    found = true;
+                    break;
+                }
+            }
+            if (!found)
+                return ("Missing header name '" + name + "' with value '" +
+                        value + "'");
+        }
+
+        // Everything was found successfully
+        return (null);
+
+    }
+
+
+    /**
+     * Validate the returned response message against what we expected.
+     * Return <code>null</code> for no problems, or an error message.
+     *
+     * @param message The returned response message
+     */
+    protected String validateMessage(String message) {
+
+        if (this.message == null)
+            return (null);
+        else if (this.message.equals(message))
+            return (null);
+        else
+            return ("Expected message='" + this.message + "', got message='" +
+                    message + "'");
+
+    }
+
+
+    /**
+     * Validate the returned status code against what we expected.  Return
+     * <code>null</code> for no problems, or an error message.
+     *
+     * @param status The returned status code
+     */
+    protected String validateStatus(int status) {
+
+        if (this.status == 0)
+            return (null);
+        if (this.status == status)
+            return (null);
+        else
+            return ("Expected status=" + this.status + ", got status=" +
+                    status);
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/TesterException.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/TesterException.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/TesterException.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,56 @@
+/*
+ * Copyright 1999, 2000, 2001 ,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tester;
+
+
+import java.io.*;
+import javax.servlet.*;
+import javax.servlet.http.*;
+
+/**
+ * Generic exception class to use for testing error page assertions.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class TesterException extends Exception {
+
+
+    /**
+     * Construct an exception with no associated message.
+     */
+    public TesterException() {
+
+        super();
+
+    }
+
+
+    /**
+     * Construct an exception with the associated message.
+     *
+     * @param message The associated message
+     */
+    public TesterException(String message) {
+
+        super(message);
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/TesterHttpServletRequestWrapper.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/TesterHttpServletRequestWrapper.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/TesterHttpServletRequestWrapper.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,363 @@
+/*
+ * Copyright 1999, 2000 ,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tester;
+
+
+import java.io.*;
+import java.security.Principal;
+import java.util.*;
+import javax.servlet.*;
+import javax.servlet.http.*;
+
+/**
+ * Tester request wrapper that logs all calls to the configured logger,
+ * before passing them on to the underlying request.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class TesterHttpServletRequestWrapper
+    extends HttpServletRequestWrapper {
+
+
+    // ------------------------------------------------------------ Constructor
+
+
+    /**
+     * Configure a new request wrapper.
+     *
+     * @param request The request we are wrapping
+     */
+    public TesterHttpServletRequestWrapper(HttpServletRequest request) {
+
+        super(request);
+
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    // For each public method, log the call and pass it to the wrapped response
+
+
+    public Object getAttribute(String name) {
+        StaticLogger.write("TesterHttpServletRequestWrapper.getAttribute()");
+        return (getRequest().getAttribute(name));
+    }
+
+
+    public Enumeration getAttributeNames() {
+        StaticLogger.write("TesterHttpServletRequestWrapper.getAttributeNames()");
+        return (getRequest().getAttributeNames());
+    }
+
+
+    public String getAuthType() {
+        StaticLogger.write("TesterHttpServletRequestWrapper.getAuthType()");
+        return (((HttpServletRequest) getRequest()).getAuthType());
+    }
+
+
+    public String getCharacterEncoding() {
+        StaticLogger.write("TesterHttpServletRequestWrapper.getCharacterEncoding()");
+        return (getRequest().getCharacterEncoding());
+    }
+
+
+    public int getContentLength() {
+        StaticLogger.write("TesterHttpServletRequestWrapper.getContentLength()");
+        return (getRequest().getContentLength());
+    }
+
+
+    public String getContentType() {
+        StaticLogger.write("TesterHttpServletRequestWrapper.getContentType()");
+        return (getRequest().getContentType());
+    }
+
+
+    public String getContextPath() {
+        StaticLogger.write("TesterHttpServletRequestWrapper.getContextPath()");
+        return (((HttpServletRequest) getRequest()).getContextPath());
+    }
+
+
+    public Cookie[] getCookies() {
+        StaticLogger.write("TesterHttpServletRequestWrapper.getCookies()");
+        return (((HttpServletRequest) getRequest()).getCookies());
+    }
+
+
+    public long getDateHeader(String name) {
+        StaticLogger.write("TesterHttpServletRequestWrapper.getDateHeader()");
+        return (((HttpServletRequest) getRequest()).getDateHeader(name));
+    }
+
+
+    public String getHeader(String name) {
+        StaticLogger.write("TesterHttpServletRequestWrapper.getHeader()");
+        return (((HttpServletRequest) getRequest()).getHeader(name));
+    }
+
+
+    public Enumeration getHeaders(String name) {
+        StaticLogger.write("TesterHttpServletRequestWrapper.getHeaders()");
+        return (((HttpServletRequest) getRequest()).getHeaders(name));
+    }
+
+
+    public Enumeration getHeaderNames() {
+        StaticLogger.write("TesterHttpServletRequestWrapper.getHeaderNames()");
+        return (((HttpServletRequest) getRequest()).getHeaderNames());
+    }
+
+
+    public ServletInputStream getInputStream() throws IOException {
+        StaticLogger.write("TesterHttpServletRequestWrapper.getInputStream()");
+        return (getRequest().getInputStream());
+    }
+
+
+    public int getIntHeader(String name) {
+        StaticLogger.write("TesterHttpServletRequestWrapper.getIntHeader()");
+        return (((HttpServletRequest) getRequest()).getIntHeader(name));
+    }
+
+
+    public Locale getLocale() {
+        StaticLogger.write("TesterHttpServletRequestWrapper.getLocale()");
+        return (getRequest().getLocale());
+    }
+
+
+    public Enumeration getLocales() {
+        StaticLogger.write("TesterHttpServletRequestWrapper.getLocales()");
+        return (getRequest().getLocales());
+    }
+
+
+    public String getMethod() {
+        StaticLogger.write("TesterHttpServletRequestWrapper.getMethod()");
+        return (((HttpServletRequest) getRequest()).getMethod());
+    }
+
+
+    public String getParameter(String name) {
+        StaticLogger.write("TesterHttpServletRequestWrapper.getParameter()");
+        return (getRequest().getParameter(name));
+    }
+
+
+    public Map getParameterMap() {
+        StaticLogger.write("TesterHttpServletRequestWrapper.getParameterMap()");
+        return (getRequest().getParameterMap());
+    }
+
+
+    public Enumeration getParameterNames() {
+        StaticLogger.write("TesterHttpServletRequestWrapper.getParameterNames()");
+        return (getRequest().getParameterNames());
+    }
+
+
+    public String[] getParameterValues(String name) {
+        StaticLogger.write("TesterHttpServletRequestWrapper.getParameterValues()");
+        return (getRequest().getParameterValues(name));
+    }
+
+
+    public String getPathInfo() {
+        StaticLogger.write("TesterHttpServletRequestWrapper.getPathInfo()");
+        return (((HttpServletRequest) getRequest()).getPathInfo());
+    }
+
+
+    public String getPathTranslated() {
+        StaticLogger.write("TesterHttpServletRequestWrapper.getPathTranslated()");
+        return (((HttpServletRequest) getRequest()).getPathTranslated());
+    }
+
+
+    public String getProtocol() {
+        StaticLogger.write("TesterHttpServletRequestWrapper.getProtocol()");
+        return (getRequest().getProtocol());
+    }
+
+
+    public String getQueryString() {
+        StaticLogger.write("TesterHttpServletRequestWrapper.getQueryString()");
+        return (((HttpServletRequest) getRequest()).getQueryString());
+    }
+
+
+    public BufferedReader getReader() throws IOException {
+        StaticLogger.write("TesterHttpServletRequestWrapper.getReader()");
+        return (getRequest().getReader());
+    }
+
+
+    public String getRealPath(String path) {
+        StaticLogger.write("TesterHttpServletRequestWrapper.getRealPath()");
+        return (getRequest().getRealPath(path));
+    }
+
+
+    public String getRemoteAddr() {
+        StaticLogger.write("TesterHttpServletRequestWrapper.getRemoteAddr()");
+        return (getRequest().getRemoteAddr());
+    }
+
+
+    public String getRemoteHost() {
+        StaticLogger.write("TesterHttpServletRequestWrapper.getRemoteHost()");
+        return (getRequest().getRemoteHost());
+    }
+
+
+    public String getRemoteUser() {
+        StaticLogger.write("TesterHttpServletRequestWrapper.getRemoteUser()");
+        return (((HttpServletRequest) getRequest()).getRemoteUser());
+    }
+
+
+    public RequestDispatcher getRequestDispatcher(String path) {
+        StaticLogger.write("TesterHttpServletRequestWrapper.getRequestDispatcher()");
+        return (getRequest().getRequestDispatcher(path));
+    }
+
+
+    public String getRequestURI() {
+        StaticLogger.write("TesterHttpServletRequestWrapper.getRequestURI()");
+        return (((HttpServletRequest) getRequest()).getRequestURI());
+    }
+
+
+    public StringBuffer getRequestURL() {
+        StaticLogger.write("TesterHttpServletRequestWrapper.getRequestURL()");
+        return (((HttpServletRequest) getRequest()).getRequestURL());
+    }
+
+
+    public String getRequestedSessionId() {
+        StaticLogger.write("TesterHttpServletRequestWrapper.getRequestedSessionId()");
+        return (((HttpServletRequest) getRequest()).getRequestedSessionId());
+    }
+
+
+    public String getScheme() {
+        StaticLogger.write("TesterHttpServletRequestWrapper.getScheme()");
+        return (getRequest().getScheme());
+    }
+
+
+    public String getServerName() {
+        StaticLogger.write("TesterHttpServletRequestWrapper.getServerName()");
+        return (getRequest().getServerName());
+    }
+
+
+    public int getServerPort() {
+        StaticLogger.write("TesterHttpServletRequestWrapper.getServerPort()");
+        return (getRequest().getServerPort());
+    }
+
+
+    public String getServletPath() {
+        StaticLogger.write("TesterHttpServletRequestWrapper.getServletPath()");
+        return (((HttpServletRequest) getRequest()).getServletPath());
+    }
+
+
+    public HttpSession getSession() {
+        StaticLogger.write("TesterHttpServletRequestWrapper.getSession()");
+        return (((HttpServletRequest) getRequest()).getSession());
+    }
+
+
+    public HttpSession getSession(boolean create) {
+        StaticLogger.write("TesterHttpServletRequestWrapper.getSession(b)");
+        return (((HttpServletRequest) getRequest()).getSession(create));
+    }
+
+
+    public Principal getUserPrincipal() {
+        StaticLogger.write("TesterHttpServletRequestWrapper.getUserPrincipal()");
+        return (((HttpServletRequest) getRequest()).getUserPrincipal());
+    }
+
+
+    public boolean isRequestedSessionIdFromCookie() {
+        StaticLogger.write("TesterHttpServletRequestWrapper.isRequestedSessionIdFromCookie()");
+        return (((HttpServletRequest) getRequest()).isRequestedSessionIdFromCookie());
+    }
+
+
+    public boolean isRequestedSessionIdFromUrl() {
+        StaticLogger.write("TesterHttpServletRequestWrapper.isRequestedSessionIdFromUrl()");
+        return (((HttpServletRequest) getRequest()).isRequestedSessionIdFromUrl());
+    }
+
+
+    public boolean isRequestedSessionIdFromURL() {
+        StaticLogger.write("TesterHttpServletRequestWrapper.isRequestedSessionIdFromURL()");
+        return (((HttpServletRequest) getRequest()).isRequestedSessionIdFromURL());
+    }
+
+
+    public boolean isRequestedSessionIdValid() {
+        StaticLogger.write("TesterHttpServletRequestWrapper.isRequestedSessionIdValid()");
+        return (((HttpServletRequest) getRequest()).isRequestedSessionIdValid());
+    }
+
+
+    public boolean isSecure() {
+        StaticLogger.write("TesterHttpServletRequestWrapper.isSecure()");
+        return (getRequest().isSecure());
+    }
+
+
+    public boolean isUserInRole(String role) {
+        StaticLogger.write("TesterHttpServletRequestWrapper.isUserInRole()");
+        return (((HttpServletRequest) getRequest()).isUserInRole(role));
+    }
+
+
+    public void removeAttribute(String name) {
+        StaticLogger.write("TesterHttpServletRequestWrapper.removeAttribute()");
+        getRequest().removeAttribute(name);
+    }
+
+
+    public void setAttribute(String name, Object value) {
+        StaticLogger.write("TesterHttpServletRequestWrapper.setAttribute()");
+        getRequest().setAttribute(name, value);
+    }
+
+
+    public void setCharacterEncoding(String enc)
+        throws UnsupportedEncodingException {
+        StaticLogger.write("TesterHttpServletRequestWrapper.setCharacterEncoding()");
+        getRequest().setCharacterEncoding(enc);
+    }
+
+
+
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/TesterHttpServletResponseWrapper.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/TesterHttpServletResponseWrapper.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/TesterHttpServletResponseWrapper.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,238 @@
+/*
+ * Copyright 1999, 2000 ,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tester;
+
+
+import java.io.*;
+import java.util.*;
+import javax.servlet.*;
+import javax.servlet.http.*;
+
+/**
+ * Tester response wrapper that logs all calls to the configured logger,
+ * before passing them on to the underlying response.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class TesterHttpServletResponseWrapper
+    extends HttpServletResponseWrapper {
+
+
+    // ------------------------------------------------------------ Constructor
+
+
+    /**
+     * Configure a new response wrapper.
+     *
+     * @param response The response we are wrapping
+     */
+    public TesterHttpServletResponseWrapper(HttpServletResponse response) {
+
+        super(response);
+
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    // For each public method, log the call and pass it to the wrapped response
+
+
+    public void addCookie(Cookie cookie) {
+        StaticLogger.write("TesterHttpServletResponseWrapper.addCookie()");
+        ((HttpServletResponse) getResponse()).addCookie(cookie);
+    }
+
+
+    public void addDateHeader(String name, long value) {
+        StaticLogger.write("TesterHttpServletResponseWrapper.addDateHeader()");
+        ((HttpServletResponse) getResponse()).addDateHeader(name, value);
+    }
+
+
+    public void addHeader(String name, String value) {
+        StaticLogger.write("TesterHttpServletResponseWrapper.addHeader()");
+        ((HttpServletResponse) getResponse()).addHeader(name, value);
+    }
+
+
+    public void addIntHeader(String name, int value) {
+        StaticLogger.write("TesterHttpServletResponseWrapper.addIntHeader()");
+        ((HttpServletResponse) getResponse()).addIntHeader(name, value);
+    }
+
+
+    public boolean containsHeader(String name) {
+        StaticLogger.write("TesterHttpServletResponseWrapper.containsHeader()");
+        return (((HttpServletResponse) getResponse()).containsHeader(name));
+    }
+
+
+    public String encodeURL(String url) {
+        StaticLogger.write("TesterHttpServletResponseWrapper.encodeURL()");
+        return (((HttpServletResponse) getResponse()).encodeURL(url));
+    }
+
+
+    public String encodeUrl(String url) {
+        StaticLogger.write("TesterHttpServletResponseWrapper.encodeUrl()");
+        return (((HttpServletResponse) getResponse()).encodeUrl(url));
+    }
+
+
+    public String encodeRedirectURL(String url) {
+        StaticLogger.write("TesterHttpServletResponseWrapper.encodeRedirectURL()");
+        return (((HttpServletResponse) getResponse()).encodeRedirectURL(url));
+    }
+
+
+    public String encodeRedirectUrl(String url) {
+        StaticLogger.write("TesterHttpServletResponseWrapper.encodeRedirectUrl()");
+        return (((HttpServletResponse) getResponse()).encodeRedirectUrl(url));
+    }
+
+
+    public void flushBuffer() throws IOException {
+        StaticLogger.write("TesterHttpServletResponseWrapper.flushBuffer()");
+        getResponse().flushBuffer();
+    }
+
+
+    public int getBufferSize() {
+        StaticLogger.write("TesterHttpServletResponseWrapper.getBufferSize()");
+        return (getResponse().getBufferSize());
+    }
+
+
+    public String getCharacterEncoding() {
+        StaticLogger.write("TesterHttpServletResponseWrapper.getCharacterEncoding()");
+        return (getResponse().getCharacterEncoding());
+    }
+
+
+    public Locale getLocale() {
+        StaticLogger.write("TesterHttpServletResponseWrapper.getLocale()");
+        return (getResponse().getLocale());
+    }
+
+
+    public ServletOutputStream getOutputStream() throws IOException {
+        StaticLogger.write("TesterHttpServletResponseWrapper.getOutputStream()");
+        return (getResponse().getOutputStream());
+    }
+
+
+    public PrintWriter getWriter() throws IOException {
+        StaticLogger.write("TesterHttpServletResponseWrapper.getWriter()");
+        return (getResponse().getWriter());
+    }
+
+
+    public boolean isCommitted() {
+        StaticLogger.write("TesterHttpServletResponseWrapper.isCommitted()");
+        return (getResponse().isCommitted());
+    }
+
+
+    public void reset() {
+        StaticLogger.write("TesterHttpServletResponseWrapper.reset()");
+        getResponse().reset();
+    }
+
+
+    public void resetBuffer() {
+        StaticLogger.write("TesterHttpServletResponseWrapper.resetBuffer()");
+        getResponse().resetBuffer();
+    }
+
+
+    public void sendError(int sc) throws IOException {
+        StaticLogger.write("TesterHttpServletResponseWrapper.sendError(i)");
+        ((HttpServletResponse) getResponse()).sendError(sc);
+    }
+
+
+    public void sendError(int sc, String msg) throws IOException {
+        StaticLogger.write("TesterHttpServletResponseWrapper.sendError(i,s)");
+        ((HttpServletResponse) getResponse()).sendError(sc, msg);
+    }
+
+
+    public void sendRedirect(String location) throws IOException {
+        StaticLogger.write("TesterHttpServletResponseWrapper.sendRedirect()");
+        ((HttpServletResponse) getResponse()).sendRedirect(location);
+    }
+
+
+    public void setBufferSize(int size) {
+        StaticLogger.write("TesterHttpServletResponseWrapper.setBufferSize()");
+        getResponse().setBufferSize(size);
+    }
+
+
+    public void setContentLength(int len) {
+        StaticLogger.write("TesterHttpServletResponseWrapper.setContentLength()");
+        getResponse().setContentLength(len);
+    }
+
+
+    public void setContentType(String type) {
+        StaticLogger.write("TesterHttpServletResponseWrapper.setContentType()");
+        getResponse().setContentType(type);
+    }
+
+
+    public void setDateHeader(String name, long value) {
+        StaticLogger.write("TesterHttpServletResponseWrapper.setDateHeader()");
+        ((HttpServletResponse) getResponse()).setDateHeader(name, value);
+    }
+
+
+    public void setHeader(String name, String value) {
+        StaticLogger.write("TesterHttpServletResponseWrapper.setHeader()");
+        ((HttpServletResponse) getResponse()).setHeader(name, value);
+    }
+
+
+    public void setIntHeader(String name, int value) {
+        StaticLogger.write("TesterHttpServletResponseWrapper.setIntHeader()");
+        ((HttpServletResponse) getResponse()).setIntHeader(name, value);
+    }
+
+
+    public void setLocale(Locale locale) {
+        StaticLogger.write("TesterHttpServletResponseWrapper.setLocale()");
+        getResponse().setLocale(locale);
+    }
+
+
+    public void setStatus(int sc) {
+        StaticLogger.write("TesterHttpServletResponseWrapper.setStatus(i)");
+        ((HttpServletResponse) getResponse()).setStatus(sc);
+    }
+
+
+    public void setStatus(int sc, String msg) {
+        StaticLogger.write("TesterHttpServletResponseWrapper.setStatus(i,s)");
+        ((HttpServletResponse) getResponse()).setStatus(sc, msg);
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/TesterServletRequestWrapper.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/TesterServletRequestWrapper.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/TesterServletRequestWrapper.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,211 @@
+/*
+ * Copyright 1999, 2000 ,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tester;
+
+
+import java.io.*;
+import java.util.*;
+import javax.servlet.*;
+import javax.servlet.http.*;
+
+/**
+ * Tester request wrapper that logs all calls to the configured logger,
+ * before passing them on to the underlying request.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class TesterServletRequestWrapper extends ServletRequestWrapper {
+
+
+    // ------------------------------------------------------------ Constructor
+
+
+    /**
+     * Configure a new request wrapper.
+     *
+     * @param request The request we are wrapping
+     */
+    public TesterServletRequestWrapper(ServletRequest request) {
+
+        super(request);
+
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    // For each public method, log the call and pass it to the wrapped response
+
+
+    public Object getAttribute(String name) {
+        StaticLogger.write("TesterServletRequestWrapper.getAttribute()");
+        return (getRequest().getAttribute(name));
+    }
+
+
+    public Enumeration getAttributeNames() {
+        StaticLogger.write("TesterServletRequestWrapper.getAttributeNames()");
+        return (getRequest().getAttributeNames());
+    }
+
+
+    public String getCharacterEncoding() {
+        StaticLogger.write("TesterServletRequestWrapper.getCharacterEncoding()");
+        return (getRequest().getCharacterEncoding());
+    }
+
+
+    public int getContentLength() {
+        StaticLogger.write("TesterServletRequestWrapper.getContentLength()");
+        return (getRequest().getContentLength());
+    }
+
+
+    public String getContentType() {
+        StaticLogger.write("TesterServletRequestWrapper.getContentType()");
+        return (getRequest().getContentType());
+    }
+
+
+    public ServletInputStream getInputStream() throws IOException {
+        StaticLogger.write("TesterServletRequestWrapper.getInputStream()");
+        return (getRequest().getInputStream());
+    }
+
+
+    public Locale getLocale() {
+        StaticLogger.write("TesterServletRequestWrapper.getLocale()");
+        return (getRequest().getLocale());
+    }
+
+
+    public Enumeration getLocales() {
+        StaticLogger.write("TesterServletRequestWrapper.getLocales()");
+        return (getRequest().getLocales());
+    }
+
+
+    public String getParameter(String name) {
+        StaticLogger.write("TesterServletRequestWrapper.getParameter()");
+        return (getRequest().getParameter(name));
+    }
+
+
+    public Map getParameterMap() {
+        StaticLogger.write("TesterServletRequestWrapper.getParameterMap()");
+        return (getRequest().getParameterMap());
+    }
+
+
+    public Enumeration getParameterNames() {
+        StaticLogger.write("TesterServletRequestWrapper.getParameterNames()");
+        return (getRequest().getParameterNames());
+    }
+
+
+    public String[] getParameterValues(String name) {
+        StaticLogger.write("TesterServletRequestWrapper.getParameterValues()");
+        return (getRequest().getParameterValues(name));
+    }
+
+
+    public String getProtocol() {
+        StaticLogger.write("TesterServletRequestWrapper.getProtocol()");
+        return (getRequest().getProtocol());
+    }
+
+
+    public BufferedReader getReader() throws IOException {
+        StaticLogger.write("TesterServletRequestWrapper.getReader()");
+        return (getRequest().getReader());
+    }
+
+
+    public String getRealPath(String path) {
+        StaticLogger.write("TesterServletRequestWrapper.getRealPath()");
+        return (getRequest().getRealPath(path));
+    }
+
+
+    public String getRemoteAddr() {
+        StaticLogger.write("TesterServletRequestWrapper.getRemoteAddr()");
+        return (getRequest().getRemoteAddr());
+    }
+
+
+    public String getRemoteHost() {
+        StaticLogger.write("TesterServletRequestWrapper.getRemoteHost()");
+        return (getRequest().getRemoteHost());
+    }
+
+
+    public RequestDispatcher getRequestDispatcher(String path) {
+        StaticLogger.write("TesterServletRequestWrapper.getRequestDispatcher()");
+        return (getRequest().getRequestDispatcher(path));
+    }
+
+
+    public String getScheme() {
+        StaticLogger.write("TesterServletRequestWrapper.getScheme()");
+        return (getRequest().getScheme());
+    }
+
+
+    public String getServerName() {
+        StaticLogger.write("TesterServletRequestWrapper.getServerName()");
+        return (getRequest().getServerName());
+    }
+
+
+    public int getServerPort() {
+        StaticLogger.write("TesterServletRequestWrapper.getServerPort()");
+        return (getRequest().getServerPort());
+    }
+
+
+    public boolean isSecure() {
+        StaticLogger.write("TesterServletRequestWrapper.isSecure()");
+        return (getRequest().isSecure());
+    }
+
+
+    public void removeAttribute(String name) {
+        StaticLogger.write("TesterServletRequestWrapper.removeAttribute()");
+        getRequest().removeAttribute(name);
+    }
+
+
+    public void setAttribute(String name, Object value) {
+        StaticLogger.write("TesterServletRequestWrapper.setAttribute()");
+        getRequest().setAttribute(name, value);
+    }
+
+
+    public void setCharacterEncoding(String enc)
+        throws UnsupportedEncodingException {
+        StaticLogger.write("TesterServletRequestWrapper.setCharacterEncoding()");
+        getRequest().setCharacterEncoding(enc);
+    }
+
+
+
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/TesterServletResponseWrapper.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/TesterServletResponseWrapper.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/TesterServletResponseWrapper.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,135 @@
+/*
+ * Copyright 1999, 2000 ,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tester;
+
+
+import java.io.*;
+import java.util.*;
+import javax.servlet.*;
+import javax.servlet.http.*;
+
+/**
+ * Tester response wrapper that logs all calls to the configured logger,
+ * before passing them on to the underlying response.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class TesterServletResponseWrapper extends ServletResponseWrapper {
+
+
+    // ------------------------------------------------------------ Constructor
+
+
+    /**
+     * Configure a new response wrapper.
+     *
+     * @param response The response we are wrapping
+     */
+    public TesterServletResponseWrapper(ServletResponse response) {
+
+        super(response);
+
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    // For each public method, log the call and pass it to the wrapped response
+
+
+    public void flushBuffer() throws IOException {
+        StaticLogger.write("TesterServletResponseWrapper.flushBuffer()");
+        getResponse().flushBuffer();
+    }
+
+
+    public int getBufferSize() {
+        StaticLogger.write("TesterServletResponseWrapper.getBufferSize()");
+        return (getResponse().getBufferSize());
+    }
+
+
+    public String getCharacterEncoding() {
+        StaticLogger.write("TesterServletResponseWrapper.getCharacterEncoding()");
+        return (getResponse().getCharacterEncoding());
+    }
+
+
+    public Locale getLocale() {
+        StaticLogger.write("TesterServletResponseWrapper.getLocale()");
+        return (getResponse().getLocale());
+    }
+
+
+    public ServletOutputStream getOutputStream() throws IOException {
+        StaticLogger.write("TesterServletResponseWrapper.getOutputStream()");
+        return (getResponse().getOutputStream());
+    }
+
+
+    public PrintWriter getWriter() throws IOException {
+        StaticLogger.write("TesterServletResponseWrapper.getWriter()");
+        return (getResponse().getWriter());
+    }
+
+
+    public boolean isCommitted() {
+        StaticLogger.write("TesterServletResponseWrapper.isCommitted()");
+        return (getResponse().isCommitted());
+    }
+
+
+    public void reset() {
+        StaticLogger.write("TesterServletResponseWrapper.reset()");
+        getResponse().reset();
+    }
+
+
+    public void resetBuffer() {
+        StaticLogger.write("TesterServletResponseWrapper.resetBuffer()");
+        getResponse().resetBuffer();
+    }
+
+
+    public void setBufferSize(int size) {
+        StaticLogger.write("TesterServletResponseWrapper.setBufferSize()");
+        getResponse().setBufferSize(size);
+    }
+
+
+    public void setContentLength(int len) {
+        StaticLogger.write("TesterServletResponseWrapper.setContentLength()");
+        getResponse().setContentLength(len);
+    }
+
+
+    public void setContentType(String type) {
+        StaticLogger.write("TesterServletResponseWrapper.setContentType()");
+        getResponse().setContentType(type);
+    }
+
+
+    public void setLocale(Locale locale) {
+        StaticLogger.write("TesterServletResponseWrapper.setLocale()");
+        getResponse().setLocale(locale);
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/UpperCaseFilter.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/UpperCaseFilter.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/UpperCaseFilter.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,61 @@
+/*
+ * Copyright 1999, 2000, 2001 ,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tester;
+
+
+import java.io.*;
+import java.util.*;
+import javax.servlet.*;
+import javax.servlet.http.*;
+
+
+/**
+ * Filter that simply transforms its output to upper case.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class UpperCaseFilter implements Filter {
+
+
+    private FilterConfig config = null;
+
+    public void destroy() {
+        ; // No action required
+    }
+
+    public void init(FilterConfig config) throws ServletException {
+        this.config = config;
+    }
+
+    public void doFilter(ServletRequest request, ServletResponse response,
+                         FilterChain chain)
+        throws IOException, ServletException {
+
+        HttpServletRequest wrequest =
+            new UpperCaseRequest((HttpServletRequest) request);
+        HttpServletResponse wresponse =
+            new UpperCaseResponse((HttpServletResponse) response);
+        StaticLogger.write("UpperCaseFilter.doFilter() begin");
+        chain.doFilter(wrequest, wresponse);
+        StaticLogger.write("UpperCaseFilter.doFilter() end");
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/UpperCaseInputStream.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/UpperCaseInputStream.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/UpperCaseInputStream.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,98 @@
+/*
+ * Copyright 1999, 2000, 2001 ,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tester;
+
+
+import java.io.*;
+import java.util.*;
+import javax.servlet.*;
+import javax.servlet.http.*;
+
+
+/**
+ * ServletInputStream that converts all characters to upper case.
+ * WARNING:  This will only work on 8-bit character sets!
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class UpperCaseInputStream extends ServletInputStream {
+
+    ServletInputStream stream = null;
+
+    public UpperCaseInputStream(ServletInputStream stream)
+      throws IOException {
+        super();
+        this.stream = stream;
+    }
+
+
+    public int read() throws IOException {
+        int c = stream.read();
+        if (c < 0)
+            return (c);
+        char ch = (char) c;
+        if (Character.isLowerCase(ch))
+            ch = Character.toUpperCase(ch);
+        return ((int) ch);
+    }
+
+    public int read(byte buf[], int off, int len) throws IOException {
+        int n = 0;
+        for (int i = off; i < (off + len); i++) {
+            int c = stream.read();
+            if (c < 0) {
+                if (n == 0)
+                    return (-1);
+                break;
+            }
+            char ch = (char) c;
+            if (Character.isLowerCase(ch))
+                ch = Character.toUpperCase(ch);
+            buf[i] = (byte) ch;
+            n++;
+        }
+        return (n);
+    }
+
+    public int read(byte buf[]) throws IOException {
+        return (read(buf, 0, buf.length));
+    }
+
+    public int readLine(byte buf[], int off, int len) throws IOException {
+        int n = 0;
+        for (int i = off; i < (off + len); i++) {
+            int c = stream.read();
+            if (c < 0) {
+                if (n == 0)
+                    return (-1);
+                break;
+            }
+            char ch = (char) c;
+            if (Character.isLowerCase(ch))
+                ch = Character.toUpperCase(ch);
+            buf[i] = (byte) ch;
+            n++;
+            if (ch == '\n')
+                break;
+        }
+        return (n);
+    }
+
+}
+

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/UpperCaseOutputStream.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/UpperCaseOutputStream.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/UpperCaseOutputStream.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,65 @@
+/*
+ * Copyright 1999, 2000, 2001 ,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tester;
+
+
+import java.io.*;
+import java.util.*;
+import javax.servlet.*;
+import javax.servlet.http.*;
+
+
+/**
+ * ServletOutputStream that converts all characters to upper case.
+ * WARNING:  This will only work on 8-bit character sets!
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class UpperCaseOutputStream extends ServletOutputStream {
+
+    ServletOutputStream stream = null;
+
+    public UpperCaseOutputStream(ServletOutputStream stream)
+      throws IOException {
+        super();
+        this.stream = stream;
+    }
+
+    public void write(int c) throws IOException {
+        char ch = (char) c;
+        if (Character.isLowerCase(ch))
+            ch = Character.toUpperCase(ch);
+        stream.write((int) ch);
+    }
+
+    public void write(byte buf[], int off, int len) throws IOException {
+        for (int i = off; i < (off + len); i++) {
+            char ch = (char) buf[i];
+            if (Character.isLowerCase(ch))
+                ch = Character.toUpperCase(ch);
+            stream.write((int) ch);
+        }
+    }
+
+    public void write(byte buf[]) throws IOException {
+        write(buf, 0, buf.length);
+    }
+
+}
+

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/UpperCaseReader.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/UpperCaseReader.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/UpperCaseReader.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,72 @@
+/*
+ * Copyright 1999, 2000, 2001 ,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tester;
+
+
+import java.io.*;
+import java.util.*;
+import javax.servlet.*;
+import javax.servlet.http.*;
+
+
+/**
+ * BufferedReader that converts all characters to upper case.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class UpperCaseReader extends BufferedReader {
+
+    public UpperCaseReader(BufferedReader reader) throws IOException {
+        super(reader);
+    }
+
+    public int read() throws IOException {
+        int c = super.read();
+        if (c < 0)
+            return (c);
+        char ch = (char) c;
+        if (Character.isLowerCase(ch))
+            ch = Character.toUpperCase(ch);
+        return ((int) ch);
+    }
+
+    public int read(char buf[], int off, int len) throws IOException {
+        int n = 0;
+        for (int i = off; i < (off + len); i++) {
+            int c = super.read();
+            if (c < 0) {
+                if (n == 0)
+                    return (-1);
+                break;
+            }
+            char ch = (char) c;
+            if (Character.isLowerCase(ch))
+                ch = Character.toUpperCase(ch);
+            buf[i] = ch;
+            n++;
+        }
+        return (n);
+    }
+
+    public int read(char buf[]) throws IOException {
+        return (read(buf, 0, buf.length));
+    }
+
+}
+

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/UpperCaseRequest.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/UpperCaseRequest.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/UpperCaseRequest.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,56 @@
+/*
+ * Copyright 1999, 2000, 2001 ,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tester;
+
+
+import java.io.*;
+import java.util.*;
+import javax.servlet.*;
+import javax.servlet.http.*;
+
+
+/**
+ * HttpServletRequest wrapper that converts all input characters to
+ * upper case.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class UpperCaseRequest extends HttpServletRequestWrapper {
+
+
+    HttpServletRequest request = null;
+
+    public UpperCaseRequest(HttpServletRequest request) {
+        super(request);
+        this.request = request;
+    }
+
+    public ServletInputStream getInputStream() throws IOException {
+        return (new UpperCaseInputStream(request.getInputStream()));
+    }
+
+    public BufferedReader getReader() throws IOException {
+        return (new UpperCaseReader(request.getReader()));
+    }
+
+
+}
+
+
+

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/UpperCaseResponse.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/UpperCaseResponse.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/UpperCaseResponse.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,66 @@
+/*
+ * Copyright 1999, 2000, 2001 ,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tester;
+
+
+import java.io.*;
+import java.util.*;
+import javax.servlet.*;
+import javax.servlet.http.*;
+
+
+/**
+ * HttpServletResponse wrapper that converts all output characters to
+ * upper case.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class UpperCaseResponse extends HttpServletResponseWrapper {
+
+
+    HttpServletResponse response = null;
+
+    boolean stream = false; // Wrap our own output stream
+
+    public UpperCaseResponse(HttpServletResponse response) {
+        this(response, false);
+    }
+
+    public UpperCaseResponse(HttpServletResponse response, boolean stream) {
+        super(response);
+        this.response = response;
+        this.stream = stream;
+    }
+
+    public ServletOutputStream getOutputStream() throws IOException {
+        return (new UpperCaseOutputStream(response.getOutputStream()));
+    }
+
+    public PrintWriter getWriter() throws IOException {
+        if (stream)
+            return (new PrintWriter(getOutputStream(), true));
+        else
+            return (new UpperCaseWriter(response.getWriter()));
+    }
+
+
+}
+
+
+

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/UpperCaseWriter.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/UpperCaseWriter.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/UpperCaseWriter.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,75 @@
+/*
+ * Copyright 1999, 2000, 2001 ,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tester;
+
+
+import java.io.*;
+import java.util.*;
+import javax.servlet.*;
+import javax.servlet.http.*;
+
+
+/**
+ * PrintWriter that converts all characters to upper case.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class UpperCaseWriter extends PrintWriter {
+
+
+    public UpperCaseWriter(PrintWriter writer) throws IOException {
+        super(writer);
+    }
+
+    public void write(int c) {
+        char ch = (char) c;
+        if (Character.isLowerCase(ch))
+            ch = Character.toUpperCase(ch);
+        super.write((int) ch);
+    }
+
+    public void write(char buf[], int off, int len) {
+        for (int i = off; i < (off + len); i++) {
+            char ch = buf[i];
+            if (Character.isLowerCase(ch))
+                ch = Character.toUpperCase(ch);
+            super.write((int) ch);
+        }
+    }
+
+    public void write(char buf[]) {
+        write(buf, 0, buf.length);
+    }
+
+    public void write(String s, int off, int len) {
+        for (int i = off; i < (off + len); i++) {
+            char ch = s.charAt(i);
+            if (Character.isLowerCase(ch))
+                ch = Character.toUpperCase(ch);
+            super.write((int) ch);
+        }
+    }
+
+    public void write(String s) {
+        write(s, 0, s.length());
+    }
+
+
+}
+

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/WrapperFilter.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/WrapperFilter.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/WrapperFilter.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,124 @@
+/*
+ * Copyright 1999, 2000 ,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tester;
+
+
+import java.io.*;
+import java.util.*;
+import javax.servlet.*;
+import javax.servlet.http.*;
+
+/**
+ * Configurable filter that will wrap the request and/or response objects
+ * it passes on with either generic or HTTP-specific wrappers.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class WrapperFilter implements Filter {
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The filter configuration object for this filter.
+     */
+    protected FilterConfig config = null;
+
+
+    /**
+     * The type of wrapper for each request ("none", "generic", "http").
+     */
+    protected String requestWrapper = "none";
+
+
+    /**
+     * The type of wrapper for each response ("none", "generic", "http").
+     */
+    protected String responseWrapper = "none";
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Release this Filter instance from service.
+     */
+    public void destroy() {
+
+        config = null;
+        requestWrapper = "none";
+        responseWrapper = "none";
+
+    }
+
+
+    /**
+     * Wrap this request and/or response as configured and pass it on.
+     */
+    public void doFilter(ServletRequest inRequest, ServletResponse inResponse,
+                         FilterChain chain)
+        throws IOException, ServletException {
+
+        // Create the appropriate wrappers
+        ServletRequest outRequest = inRequest;
+        ServletResponse outResponse = inResponse;
+        if (requestWrapper.equals("generic")) {
+            outRequest = new TesterServletRequestWrapper(inRequest);
+        } else if (requestWrapper.equals("http")) {
+            outRequest = new TesterHttpServletRequestWrapper
+                ((HttpServletRequest) inRequest);
+        }
+        if (responseWrapper.equals("generic")) {
+            outResponse = new TesterServletResponseWrapper(inResponse);
+        } else if (responseWrapper.equals("http")) {
+            outResponse = new TesterHttpServletResponseWrapper
+                ((HttpServletResponse) inResponse);
+        }
+
+        // Perform this request
+        chain.doFilter(outRequest, outResponse);
+
+    }
+
+
+    /**
+     * Place this Filter instance into service.
+     *
+     * @param config The filter configuration object
+     */
+    public void init(FilterConfig config) throws ServletException {
+
+        this.config = config;
+        String value = null;
+        value = config.getInitParameter("request");
+        if (value != null)
+            requestWrapper = value;
+        value = config.getInitParameter("response");
+        if (value != null)
+            responseWrapper = value;
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Xerces01.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Xerces01.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Xerces01.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,97 @@
+/*
+ * Copyright 1999, 2000, 2001 ,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tester;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.net.MalformedURLException;
+import java.net.URL;
+import javax.servlet.*;
+import javax.servlet.http.*;
+
+
+/**
+ * Ensure that we can use the Xerces parser while included in a web application
+ * even though the servlet container might utilize its own parser for internal
+ * use.
+ *
+ * @author Amy Roh
+ * @author Craig McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class Xerces01 extends HttpServlet {
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Perform a simple SAX parse using Xerces (based on the SAXCount
+     * example application).
+     *
+     * @param request The servlet request we are processing
+     * @param response The servlet response we are creating
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception ServletException if a servlet error occurs
+     */
+    public void service(HttpServletRequest request,
+                        HttpServletResponse response)
+        throws ServletException, IOException
+    {
+
+        // Prepare our output stream
+        response.setContentType("text/plain");
+        PrintWriter writer = response.getWriter();
+        boolean ok = true;
+
+        // Construct a new instance of our parser driver
+        URL url = null;
+        try {
+            url = getServletContext().getResource("/Xerces01.xml");
+        } catch (MalformedURLException e) {
+            writer.println("Xerces01 FAILED - " + e);
+            e.printStackTrace(writer);
+            ok = false;
+        }
+        Xerces01Parser parser = new Xerces01Parser();
+        try {
+            if (ok)
+                parser.parse(url);
+        } catch (Exception e) {
+            writer.println("Xerces01 FAILED - " + e);
+            e.printStackTrace(writer);
+            ok = false;
+        }
+
+        // Report successful completion if OK
+        if (ok)
+            writer.println("Xerces01 PASSED");
+        while (true) {
+            String message = StaticLogger.read();
+            if (message == null)
+                break;
+            writer.println(message);
+        }
+        StaticLogger.reset();
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Xerces01Parser.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Xerces01Parser.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/Xerces01Parser.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,234 @@
+/*
+ * Copyright 1999, 2000, 2001 ,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tester;
+
+
+import java.net.URL;
+import org.xml.sax.AttributeList;
+import org.xml.sax.HandlerBase;
+import org.xml.sax.Parser;
+import org.xml.sax.SAXException;
+import org.xml.sax.SAXParseException;
+import org.xml.sax.helpers.ParserFactory;
+
+
+/**
+ * SAX parser (based on SAXCount) that exercises the Xerces parser within the
+ * environment of a web application.
+ *
+ * @author Amy Roh
+ * @author Craig McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class Xerces01Parser extends HandlerBase {
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The number of XML attributes we have encountered.
+     */
+    protected int attributes = 0;
+
+
+    /**
+     * The number of characters we have encountered.
+     */
+    protected int characters = 0;
+
+
+    /**
+     * The number of XML elements we have encountered.
+     */
+    protected int elements = 0;
+
+
+    /**
+     * The amount of ignorable whitespace we have encountered.
+     */
+    protected int whitespace = 0;
+
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Execute the requested parse.
+     *
+     * @param url The URL of the XML resource to be parsed
+     *
+     * @exception Exception if any processing exception occurs
+     */
+    public void parse(URL url) throws Exception {
+
+        // Construct a parser for our use
+        Parser parser =
+            ParserFactory.makeParser("org.apache.xerces.parsers.SAXParser");
+        parser.setDocumentHandler(this);
+        parser.setErrorHandler(this);
+
+        // Perform the requested parse
+        long before = System.currentTimeMillis();
+        parser.parse(url.toString());
+        long after = System.currentTimeMillis();
+
+        // Log the results
+        StaticLogger.write("Parsing time = " + (after - before) +
+                           " milliseconds");
+        StaticLogger.write("Processed " + elements + " elements");
+        StaticLogger.write("Processed " + attributes + " attributes");
+        StaticLogger.write("Processed " + characters + " characters");
+        StaticLogger.write("Processed " + whitespace + " whitespaces");
+
+    }
+
+
+    // ------------------------------------------------------ SAX Error Methods
+
+
+    /**
+     * Receive notification of a parser error.
+     *
+     * @param e The parser exception being reported
+     *
+     * @exception SAXException if a parsing error occurs
+     */
+    public void error(SAXParseException e) throws SAXException {
+
+        StaticLogger.write("[Error] " +
+                           getLocationString(e) + ": " +
+                           e.getMessage());
+
+    }
+
+
+    /**
+     * Receive notification of a fatal error.
+     *
+     * @param e The parser exception being reported
+     *
+     * @exception SAXException if a parsing error occurs
+     */
+    public void fatalError(SAXParseException e) throws SAXException {
+
+        StaticLogger.write("[Fatal] " +
+                           getLocationString(e) + ": " +
+                           e.getMessage());
+
+    }
+
+
+    /**
+     * Receive notification of a parser warning.
+     *
+     * @param e The parser exception being reported
+     *
+     * @exception SAXException if a parsing error occurs
+     */
+    public void warning(SAXParseException e) throws SAXException {
+
+        StaticLogger.write("[Warning] " +
+                           getLocationString(e) + ": " +
+                           e.getMessage());
+
+    }
+
+
+    /**
+     * Return the location at which this exception occurred.
+     *
+     * @param e The SAXParseException we are reporting on
+     */
+    private String getLocationString(SAXParseException e) {
+
+        StringBuffer sb = new StringBuffer();
+        String systemId = e.getSystemId();
+        if (systemId != null) {
+            int index = systemId.lastIndexOf('/');
+            if (index != -1)
+                systemId = systemId.substring(index + 1);
+            sb.append(systemId);
+        }
+        sb.append(':');
+        sb.append(e.getLineNumber());
+        sb.append(':');
+        sb.append(e.getColumnNumber());
+        return (sb.toString());
+
+    }
+
+
+    // ------------------------------------------------------ SAX Event Methods
+
+
+    /**
+     * Character data event handler.
+     *
+     * @param ch Character array containing the characters
+     * @param start Starting position in the array
+     * @param length Number of characters to process
+     *
+     * @exception SAXException if a parsing error occurs
+     */
+    public void characters(char ch[], int start, int length)
+        throws SAXException {
+
+        characters += length;
+
+    }
+
+
+    /**
+     * Ignorable whitespace event handler.
+     *
+     * @param ch Character array containing the characters
+     * @param start Starting position in the array
+     * @param length Number of characters to process
+     *
+     * @exception SAXException if a parsing error occurs
+     */
+    public void ignorableWhitespace(char ch[], int start, int length)
+        throws SAXException {
+
+        whitespace += length;
+
+    }
+
+
+    /**
+     * Start of element event handler.
+     *
+     * @param name The element type name
+     * @param attrs The specified or defaulted attributes
+     *
+     * @exception SAXException if a parsing error occurs
+     */
+    public void startElement(String name, AttributeList attrs) {
+
+        elements++;
+        if (attrs != null)
+            attributes += attrs.getLength();
+
+    }
+
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/shared/SharedSessionBean.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/shared/SharedSessionBean.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/shared/SharedSessionBean.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,165 @@
+/*
+ * Copyright 1999, 2000 ,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tester.shared;
+
+
+import java.io.Serializable;
+import java.sql.Date;
+import javax.servlet.http.HttpSessionActivationListener;
+import javax.servlet.http.HttpSessionBindingEvent;
+import javax.servlet.http.HttpSessionBindingListener;
+import javax.servlet.http.HttpSessionEvent;
+
+
+/**
+ * Simple JavaBean to use for session attribute tests.  It is Serializable
+ * so that instances can be saved and restored across server restarts.
+ * <p>
+ * This is functionally equivalent to <code>SessionBean</code>, but stored
+ * in a different package so that it gets deployed into a JAR file under
+ * <code>$CATALINA_HOME/lib</code>.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class SharedSessionBean implements
+    HttpSessionActivationListener, HttpSessionBindingListener, Serializable {
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * A date property for use with property editor tests.
+     */
+    protected Date dateProperty =
+        new Date(System.currentTimeMillis());
+
+    public Date getDateProperty() {
+        return (this.dateProperty);
+    }
+
+    public void setDateProperty(Date dateProperty) {
+        this.dateProperty = dateProperty;
+    }
+
+
+    /**
+     * The lifecycle events that have happened on this bean instance.
+     */
+    protected String lifecycle = "";
+
+    public String getLifecycle() {
+        return (this.lifecycle);
+    }
+
+    public void setLifecycle(String lifecycle) {
+        this.lifecycle = lifecycle;
+    }
+
+
+    /**
+     * A string property.
+     */
+    protected String stringProperty = "Default String Property Value";
+
+    public String getStringProperty() {
+        return (this.stringProperty);
+    }
+
+    public void setStringProperty(String stringProperty) {
+        this.stringProperty = stringProperty;
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Return a string representation of this bean.
+     */
+    public String toString() {
+
+        StringBuffer sb = new StringBuffer("SharedSessionBean[lifecycle=");
+        sb.append(this.lifecycle);
+        sb.append(",dateProperty=");
+        sb.append(dateProperty);
+        sb.append(",stringProperty=");
+        sb.append(this.stringProperty);
+        sb.append("]");
+        return (sb.toString());
+
+    }
+
+
+    // ---------------------------------- HttpSessionActivationListener Methods
+
+
+    /**
+     * Receive notification that this session was activated.
+     *
+     * @param event The session event that has occurred
+     */
+    public void sessionDidActivate(HttpSessionEvent event) {
+
+        lifecycle += "/sda";
+
+    }
+
+
+    /**
+     * Receive notification that this session will be passivated.
+     *
+     * @param event The session event that has occurred
+     */
+    public void sessionWillPassivate(HttpSessionEvent event) {
+
+        lifecycle += "/swp";
+
+    }
+
+
+    // ------------------------------------- HttpSessionBindingListener Methods
+
+
+    /**
+     * Receive notification that this attribute has been bound.
+     *
+     * @param event The session event that has occurred
+     */
+    public void valueBound(HttpSessionBindingEvent event) {
+
+        lifecycle += "/vb";
+
+    }
+
+
+    /**
+     * Receive notification that this attribute has been unbound.
+     *
+     * @param event The session event that has occurred
+     */
+    public void valueUnbound(HttpSessionBindingEvent event) {
+
+        lifecycle += "/vu";
+
+    }
+
+
+}
+

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/unpshared/UnpSharedSessionBean.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/unpshared/UnpSharedSessionBean.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/unpshared/UnpSharedSessionBean.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,165 @@
+/*
+ * Copyright 1999, 2000 ,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tester.unpshared;
+
+
+import java.io.Serializable;
+import java.sql.Date;
+import javax.servlet.http.HttpSessionActivationListener;
+import javax.servlet.http.HttpSessionBindingEvent;
+import javax.servlet.http.HttpSessionBindingListener;
+import javax.servlet.http.HttpSessionEvent;
+
+
+/**
+ * Simple JavaBean to use for session attribute tests.  It is Serializable
+ * so that instances can be saved and restored across server restarts.
+ * <p>
+ * This is functionally equivalent to <code>SessionBean</code>, but stored
+ * in a different package so that it gets deployed unpacked under
+ * <code>$CATALINA_HOME/classes</code>.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class UnpSharedSessionBean implements
+    HttpSessionActivationListener, HttpSessionBindingListener, Serializable {
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * A date property for use with property editor tests.
+     */
+    protected Date dateProperty =
+        new Date(System.currentTimeMillis());
+
+    public Date getDateProperty() {
+        return (this.dateProperty);
+    }
+
+    public void setDateProperty(Date dateProperty) {
+        this.dateProperty = dateProperty;
+    }
+
+
+    /**
+     * The lifecycle events that have happened on this bean instance.
+     */
+    protected String lifecycle = "";
+
+    public String getLifecycle() {
+        return (this.lifecycle);
+    }
+
+    public void setLifecycle(String lifecycle) {
+        this.lifecycle = lifecycle;
+    }
+
+
+    /**
+     * A string property.
+     */
+    protected String stringProperty = "Default String Property Value";
+
+    public String getStringProperty() {
+        return (this.stringProperty);
+    }
+
+    public void setStringProperty(String stringProperty) {
+        this.stringProperty = stringProperty;
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Return a string representation of this bean.
+     */
+    public String toString() {
+
+        StringBuffer sb = new StringBuffer("SharedSessionBean[lifecycle=");
+        sb.append(this.lifecycle);
+        sb.append(",dateProperty=");
+        sb.append(dateProperty);
+        sb.append(",stringProperty=");
+        sb.append(this.stringProperty);
+        sb.append("]");
+        return (sb.toString());
+
+    }
+
+
+    // ---------------------------------- HttpSessionActivationListener Methods
+
+
+    /**
+     * Receive notification that this session was activated.
+     *
+     * @param event The session event that has occurred
+     */
+    public void sessionDidActivate(HttpSessionEvent event) {
+
+        lifecycle += "/sda";
+
+    }
+
+
+    /**
+     * Receive notification that this session will be passivated.
+     *
+     * @param event The session event that has occurred
+     */
+    public void sessionWillPassivate(HttpSessionEvent event) {
+
+        lifecycle += "/swp";
+
+    }
+
+
+    // ------------------------------------- HttpSessionBindingListener Methods
+
+
+    /**
+     * Receive notification that this attribute has been bound.
+     *
+     * @param event The session event that has occurred
+     */
+    public void valueBound(HttpSessionBindingEvent event) {
+
+        lifecycle += "/vb";
+
+    }
+
+
+    /**
+     * Receive notification that this attribute has been unbound.
+     *
+     * @param event The session event that has occurred
+     */
+    public void valueUnbound(HttpSessionBindingEvent event) {
+
+        lifecycle += "/vu";
+
+    }
+
+
+}
+

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/unshared/UnsharedSessionBean.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/unshared/UnsharedSessionBean.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/src/tester/org/apache/tester/unshared/UnsharedSessionBean.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,61 @@
+/*
+ * Copyright 1999, 2000 ,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tester.unshared;
+
+
+import java.io.Serializable;
+import javax.servlet.http.HttpSessionActivationListener;
+import javax.servlet.http.HttpSessionBindingEvent;
+import javax.servlet.http.HttpSessionBindingListener;
+import javax.servlet.http.HttpSessionEvent;
+import org.apache.tester.SessionBean;
+
+
+/**
+ * Simple JavaBean to use for session attribute tests.  It is Serializable
+ * so that instances can be saved and restored across server restarts.
+ * <p>
+ * This bean is functionally equivalent to
+ * <code>org.apache.tester.SessionBean</code>, but will be deployed under
+ * <code>/WEB-INF/classes</code> instead of inside
+ * <code>/WEB-INF/lib/tester.jar</code>.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class UnsharedSessionBean extends SessionBean implements
+    HttpSessionActivationListener, HttpSessionBindingListener, Serializable {
+
+
+    /**
+     * Return a string representation of this bean.
+     */
+    public String toString() {
+
+        StringBuffer sb = new StringBuffer("UnsharedSessionBean[lifecycle=");
+        sb.append(this.lifecycle);
+        sb.append(",stringProperty=");
+        sb.append(this.stringProperty);
+        sb.append("]");
+        return (sb.toString());
+
+    }
+
+
+}
+

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/Authentication04.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/Authentication04.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/Authentication04.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,26 @@
+<%@ page contentType="text/plain" %><%
+  StringBuffer results = new StringBuffer();
+  String remoteUser = request.getRemoteUser();
+  if (remoteUser == null) {
+    results.append(" Not Authenticated/");
+  } else if (!"tomcat".equals(remoteUser)) {
+    results.append(" Authenticated as '");
+    results.append(remoteUser);
+    results.append("'/");
+  }
+  if (!request.isUserInRole("tomcat")) {
+    results.append(" Not in role 'tomcat'/");
+  }
+  if (!request.isUserInRole("alias")) {
+    results.append(" Not in role 'alias'/");
+  }
+  if (request.isUserInRole("unknown")) {
+    results.append(" In role 'unknown'/");
+  }
+  if (results.length() < 1) {
+    out.println("Authentication04 PASSED");
+  } else {
+    out.print("Authentication04 FAILED -");
+    out.println(results.toString());
+  }
+%>

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/Encoding01.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/Encoding01.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/Encoding01.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,5 @@
+
+<%@ page contentType="text/html;charset=SJIS" %>
+
+<h2>Test Character</h2>
+<h2><%="\u9b5a"%> Unicode = 9b5a</hr>

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/Encoding02.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/Encoding02.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/Encoding02.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,9 @@
+<html>
+<head>
+<title>Encoding02.jsp</title>
+</head>
+<body bgcolor="white">
+This is legal in the spec:<br>
+<%= "Joe said %\> foo" %>.
+</body>
+</html>

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/Encoding03.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/Encoding03.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/Encoding03.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,9 @@
+<html>
+<head>
+<title>Encoding03.jsp</title>
+</head>
+<body bgcolor="white">
+This is not recognized as a delimiter either:<br>
+<%= "Joe said %\\> bar" %>.
+</body>
+</html>

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/ErrorPage06.html
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/ErrorPage06.html	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/ErrorPage06.html	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1 @@
+ErrorPage06 PASSED - HTML

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/ErrorPage06.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/ErrorPage06.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/ErrorPage06.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,106 @@
+<%@ page contentType="text/plain" %><%
+
+        // Accumulate all the reasons this request might fail
+        StringBuffer sb = new StringBuffer();
+        Object value = null;
+
+        value = request.getAttribute("javax.servlet.error.exception");
+        if (value == null) {
+            sb.append(" exception is missing/");
+        } else if (!(value instanceof java.lang.ArrayIndexOutOfBoundsException)) {
+            sb.append(" exception class is ");
+            sb.append(value.getClass().getName());
+            sb.append("/");
+        }
+
+        value = request.getAttribute("javax.servlet.error.exception_type");
+        if (value == null)
+            sb.append(" exception_type is missing/");
+        else if (!(value instanceof Class)) {
+            sb.append(" exception_type class is ");
+            sb.append(value.getClass().getName());
+            sb.append("/");
+        } else {
+            Class clazz = (Class) value;
+            String name = clazz.getName();
+            if (!"java.lang.ArrayIndexOutOfBoundsException".equals(name)) {
+                sb.append(" exception_type is ");
+                sb.append(name);
+                sb.append("/");
+            }
+        }
+
+        value = request.getAttribute("javax.servlet.error.message");
+        if (value == null)
+            sb.append(" message is missing/");
+        else if (!(value instanceof String)) {
+            sb.append(" message class is ");
+            sb.append(value.getClass().getName());
+            sb.append("/");
+        } else if (!"ErrorPage05 Threw ArrayIndexOutOfBoundsException".equals(value) &&
+                   !"ErrorPage08 Threw ArrayIndexOutOfBoundsException".equals(value)) {
+            sb.append(" message is not correct");
+        }
+
+        value = request.getAttribute("javax.servlet.error.request_uri");
+        if (value == null)
+            sb.append(" request_uri is missing/");
+        else if (!(value instanceof String)) {
+            sb.append(" request_uri class is ");
+            sb.append(value.getClass().getName());
+            sb.append("/");
+        } else {
+            String request_uri = (String) value;
+            String test1 = request.getContextPath() + "/ErrorPage05";
+            String test2 = request.getContextPath() + "/WrappedErrorPage05";
+            String test3 = request.getContextPath() + "/ErrorPage08";
+            String test4 = request.getContextPath() + "/WrappedErrorPage08";
+            if (!request_uri.equals(test1) && !request_uri.equals(test2) &&
+                !request_uri.equals(test3) && !request_uri.equals(test4)) {
+                sb.append(" request_uri is ");
+                sb.append(request_uri);
+                sb.append("/");
+            }
+        }
+
+        value = request.getAttribute("javax.servlet.error.servlet_name");
+        if (value == null)
+            sb.append(" servlet_name is missing/");
+        else if (!(value instanceof String)) {
+            sb.append(" servlet_name class is ");
+            sb.append(value.getClass().getName());
+            sb.append("/");
+        } else {
+            String servlet_name = (String) value;
+            if (!"ErrorPage05".equals(servlet_name) &&
+                !"ErrorPage08".equals(servlet_name)) {
+                sb.append(" servlet_name is ");
+                sb.append(servlet_name);
+                sb.append("/");
+            }
+        }
+
+        // Report ultimate success or failure
+        if (sb.length() < 1)
+            out.println("ErrorPage06 PASSED - JSP");
+        else
+            out.println("ErrorPage06 FAILED -" + sb.toString());
+
+%>
+<%
+  Exception e = (Exception)
+   request.getAttribute("javax.servlet.error.exception");
+  out.println("EXCEPTION:  " + e);
+  Class et = (Class)
+   request.getAttribute("javax.servlet.error.exception_type");
+  out.println("EXCEPTION_TYPE:  " + et.getName());
+  String m = (String)
+   request.getAttribute("javax.servlet.error.message");
+  out.println("MESSAGE:  " + m);
+  String ru = (String)
+   request.getAttribute("javax.servlet.error.request_uri");
+  out.println("REQUEST_URI:  " + ru);
+  String sn = (String)
+   request.getAttribute("javax.servlet.error.servlet_name");
+  out.println("SERVLET_NAME:  " + sn);
+%>

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/ErrorPage08.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/ErrorPage08.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/ErrorPage08.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,19 @@
+<%@ page contentType="text/plain" %><%
+
+        // Write a FAILED message that should get replaced by the error text
+        out.println("ErrorPage08 FAILED - Original response returned");
+
+        // Throw the specified exception
+        String type = request.getParameter("type");
+        if ("Arithmetic".equals(type)) {
+            throw new ArithmeticException
+                ("ErrorPage08 Threw ArithmeticException");
+        } else if ("Array".equals(type)) {
+            throw new ArrayIndexOutOfBoundsException
+                ("ErrorPage08 Threw ArrayIndexOutOfBoundsException");
+        } else if ("Number".equals(type)) {
+            throw new NumberFormatException
+                ("ErrorPage08 Threw NumberFormatException");
+        }
+
+%>

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/ErrorPage09.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/ErrorPage09.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/ErrorPage09.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,13 @@
+<%@ page contentType="text/plain" errorPage="/ErrorPage10.jsp" %><%
+
+        // Write a FAILED message that should get replaced by the error text
+        out.println("ErrorPage09 FAILED - Original response returned");
+
+        // Throw the specified exception
+        int i = 1;
+        if (i > 0) {
+            throw new ArrayIndexOutOfBoundsException
+                ("ErrorPage09 Threw ArrayIndexOutOfBoundsException");
+        }
+
+%>

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/ErrorPage10.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/ErrorPage10.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/ErrorPage10.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,31 @@
+<%@ page contentType="text/plain" isErrorPage="true" %><%
+
+        // Accumulate all the reasons this request might fail
+        StringBuffer sb = new StringBuffer();
+        Object value = null;
+
+        if (exception == null) {
+            sb.append(" exception is missing/");
+        } else {
+            if (!(exception instanceof java.lang.ArrayIndexOutOfBoundsException)) {
+                sb.append(" exception class is ");
+                sb.append(exception.getClass().getName());
+                sb.append("/");
+            }
+            if (!"ErrorPage09 Threw ArrayIndexOutOfBoundsException".equals(exception.getMessage())) {
+                sb.append(" exception message is ");
+                sb.append(exception.getMessage());
+                sb.append("/");
+            }
+        }
+
+        // Report ultimate success or failure
+        if (sb.length() < 1)
+            out.println("ErrorPage10 PASSED");
+        else
+            out.println("ErrorPage10 FAILED -" + sb.toString());
+
+%>
+<%
+  out.println("EXCEPTION:  " + exception);
+%>

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/FilterResponse02.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/FilterResponse02.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/FilterResponse02.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,10 @@
+<%@ page contentType="text/plain" %>FilterResponse02 PASSED
+<%
+        while (true) {
+            String message = org.apache.tester.StaticLogger.read();
+            if (message == null)
+                break;
+            out.println(message);
+        }
+        org.apache.tester.StaticLogger.reset();
+%>

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/FilterResponse03.txt
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/FilterResponse03.txt	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/FilterResponse03.txt	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1 @@
+FilterResponse03 PASSED

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/Forward00b.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/Forward00b.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/Forward00b.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,6 @@
+<%@ page contentType="text/plain" %>Forward00b PASSED
+requestURI=<%= request.getRequestURI() %>
+contextPath=<%= request.getContextPath() %>
+servletPath=<%= request.getServletPath() %>
+pathInfo=<%= request.getPathInfo() %>
+queryString=<%= request.getQueryString() %>

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/Forward00c.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/Forward00c.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/Forward00c.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,6 @@
+<%@ page contentType="text/plain" %>Forward00c PASSED
+requestURI=<%= request.getRequestURI() %>
+contextPath=<%= request.getContextPath() %>
+servletPath=<%= request.getServletPath() %>
+pathInfo=<%= request.getPathInfo() %>
+queryString=<%= request.getQueryString() %>

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/Forward00e.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/Forward00e.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/Forward00e.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,6 @@
+<%@ page contentType="text/plain" %>Forward00e PASSED
+requestURI=<%= request.getRequestURI() %>
+contextPath=<%= request.getContextPath() %>
+servletPath=<%= request.getServletPath() %>
+pathInfo=<%= request.getPathInfo() %>
+queryString=<%= request.getQueryString() %>

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/Forward01.txt
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/Forward01.txt	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/Forward01.txt	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1 @@
+Forward01 PASSED

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/Forward03b.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/Forward03b.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/Forward03b.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,30 @@
+<%
+  String specials[] =
+    { "javax.servlet.include.request_uri",
+      "javax.servlet.include.context_path",
+      "javax.servlet.include.servlet_path",
+      "javax.servlet.include.path_info",
+      "javax.servlet.include.query_string" };
+
+  StringBuffer sb = new StringBuffer();
+  if (request.getAttribute("Forward03") == null)
+    sb.append(" Cannot retrieve forwarded attribute/");
+  request.setAttribute("Forward03b", "This is our very own attribute");
+  if (request.getAttribute("Forward03b") == null)
+    sb.append(" Cannot retrieve our own attribute/");
+
+  for (int i = 0; i < specials.length; i++) {
+    if (request.getAttribute(specials[i]) != null) {
+      sb.append(" Exposed attribute ");
+      sb.append(specials[i]);
+      sb.append("/");
+    }
+  }
+
+  if (sb.length() < 1) {
+    out.println("Forward03 PASSED");
+  } else {
+    out.print("Forward03 FAILED - ");
+    out.println(sb.toString());
+  }
+%>

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/Forward04.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/Forward04.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/Forward04.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1 @@
+<%@ page contentType="text/plain" %><jsp:forward page="/Forward04a.jsp"/>Forward04.jsp FAILED - Content should not be visible

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/Forward04a.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/Forward04a.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/Forward04a.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1 @@
+<%@ page contentType="text/plain" %><jsp:forward page="/Forward04b.jsp"/>Forward04a.jsp FAILED - Content should not be visible

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/Forward04b.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/Forward04b.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/Forward04b.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1 @@
+<%@ page contentType="text/plain" %>Forward04b.jsp PASSED

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/Forward05.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/Forward05.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/Forward05.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1 @@
+<%@ page contentType="text/plain" %><jsp:forward page="/Forward05a"/>Forward05.jsp FAILED - Content should not be visible

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/Forward05a.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/Forward05a.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/Forward05a.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1 @@
+<%@ page contentType="text/plain" %><jsp:forward page="/Forward05b"/>Forward05a.jsp FAILED - Content should not be visible

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/Forward05b.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/Forward05b.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/Forward05b.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1 @@
+<%@ page contentType="text/plain" %>Forward05b.jsp PASSED

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/Forward06.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/Forward06.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/Forward06.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1 @@
+<%@ page contentType="text/plain" %><jsp:forward page="/servlet/Forward06a"/>Forward06.jsp FAILED - Content should not be visible

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/Forward06a.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/Forward06a.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/Forward06a.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1 @@
+<%@ page contentType="text/plain" %><jsp:forward page="/servlet/Forward06b"/>Forward06a.jsp FAILED - Content should not be visible

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/Forward06b.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/Forward06b.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/Forward06b.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1 @@
+<%@ page contentType="text/plain" %>Forward06b.jsp PASSED

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/Include00b.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/Include00b.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/Include00b.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,6 @@
+<%@ page contentType="text/plain" session="false" %>Include00b PASSED
+requestURI=<%= request.getRequestURI() %>
+contextPath=<%= request.getContextPath() %>
+servletPath=<%= request.getServletPath() %>
+pathInfo=<%= request.getPathInfo() %>
+queryString=<%= request.getQueryString() %>

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/Include00c.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/Include00c.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/Include00c.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,6 @@
+<%@ page contentType="text/plain" session="false"%>Include00c PASSED
+requestURI=<%= request.getRequestURI() %>
+contextPath=<%= request.getContextPath() %>
+servletPath=<%= request.getServletPath() %>
+pathInfo=<%= request.getPathInfo() %>
+queryString=<%= request.getQueryString() %>

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/Include00e.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/Include00e.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/Include00e.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,6 @@
+<%@ page contentType="text/plain" session="false" %>Include00e PASSED
+requestURI=<%= request.getRequestURI() %>
+contextPath=<%= request.getContextPath() %>
+servletPath=<%= request.getServletPath() %>
+pathInfo=<%= request.getPathInfo() %>
+queryString=<%= request.getQueryString() %>

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/Include01.txt
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/Include01.txt	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/Include01.txt	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1 @@
+Include01 PASSED

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/Include03b.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/Include03b.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/Include03b.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1 @@
+<% request.setAttribute("Include03b.jsp", "This is a new attribute"); %>

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/Include03c.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/Include03c.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/Include03c.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,30 @@
+<%@ page contentType="text/plain" %><%
+  // Duplicate logic from "Include03.java"
+  StringBuffer sb = new StringBuffer();
+  String path = request.getParameter("path");
+  if (path == null)
+    path = "/Include03a";
+  RequestDispatcher rd =
+    getServletContext().getRequestDispatcher(path);
+  if (rd == null) {
+    sb.append(" No RequestDispatcher returned/");
+  } else {
+    rd.include(request, response);
+  }
+  response.resetBuffer();
+  String value = null;
+  try {
+    value = (String) request.getAttribute(path.substring(1));
+  } catch (ClassCastException e) {
+      sb.append(" Returned attribute not of type String/");
+  }
+  if ((sb.length() < 1) && (value == null)) {
+      sb.append(" No includee-created attribute was returned/");
+  }
+  if (sb.length() < 1)
+    out.println("Include03c.jsp PASSED");
+  else {
+    out.print("Include03c.jsp FAILED -");
+    out.println(sb.toString());
+  }
+%>

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/Include05.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/Include05.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/Include05.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1 @@
+<%@ page contentType="text/plain" %><jsp:include page="/Include05a.jsp" flush="false"/><jsp:forward page="/Include05b.jsp"/>

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/Include05a.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/Include05a.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/Include05a.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1 @@
+Include05a PASSED

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/Include05b.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/Include05b.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/Include05b.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1 @@
+Include05b PASSED

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/Include06.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/Include06.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/Include06.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,3 @@
+<%@ page contentType="text/plain" %>==========
+<jsp:include page="servlet/org.apache.tester.Include06a" flush="false"/>==========
+<jsp:include page="/Include06b.jsp"/>==========

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/Include06b.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/Include06b.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/Include06b.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1 @@
+Include06b.jsp output

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/JspBeans01.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/JspBeans01.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/JspBeans01.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,4 @@
+<%@ page contentType="text/plain" %><jsp:useBean id="bean" class="org.apache.tester.SessionBean"/>JspBeans01 PASSED
+lifecycle = <%= bean.getLifecycle() %>
+stringProperty= <%= bean.getStringProperty() %>
+toString = <%= bean.toString() %>

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/JspBeans02.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/JspBeans02.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/JspBeans02.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,4 @@
+<%@ page contentType="text/plain" %><jsp:useBean id="bean" class="org.apache.tester.shared.SharedSessionBean"/>JspBeans02 PASSED
+lifecycle = <%= bean.getLifecycle() %>
+stringProperty= <%= bean.getStringProperty() %>
+toString = <%= bean.toString() %>

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/JspBeans03.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/JspBeans03.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/JspBeans03.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,4 @@
+<%@ page contentType="text/plain" %><jsp:useBean id="bean" class="org.apache.tester.unshared.UnsharedSessionBean"/>JspBeans03 PASSED
+lifecycle = <%= bean.getLifecycle() %>
+stringProperty= <%= bean.getStringProperty() %>
+toString = <%= bean.toString() %>

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/JspDoc01.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/JspDoc01.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/JspDoc01.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,9 @@
+<?xml version="1.0"?>
+<jsp:root xmlns:jsp="http://java.sun.com/JSP/Page" version="1.2">
+  <a>text<b></b></a>
+  <jsp:text>&lt;a&gt;text&lt;b&gt;&lt;/b&gt;&lt;/a&gt;</jsp:text>
+  <c><d>text</d></c>
+  <jsp:text>&lt;c&gt;&lt;d&gt;text&lt;/d&gt;&lt;/c&gt;</jsp:text>
+  <e><f></f>text<f></f></e>
+  <jsp:text>&lt;e&gt;&lt;f&gt;&lt;/f&gt;text&lt;f&gt;&lt;/f&gt;&lt;/e&gt;</jsp:text>
+</jsp:root>

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/JspDoc02.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/JspDoc02.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/JspDoc02.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,53 @@
+<?xml version="1.0"?>
+<jsp:root xmlns:jsp="http://java.sun.com/JSP/Page"
+  version="1.2">
+<jsp:directive.page contentType="text/html"/>
+<jsp:directive.page import="java.util.Date, java.util.Locale"/>
+<jsp:directive.page import="java.text.*"/>
+
+<jsp:declaration>
+  String getData() {
+    return "foo";
+  }
+</jsp:declaration>
+
+<html>
+<head>
+  <title>Example JSP in XML format</title>
+</head>
+
+<body>
+This is the output of a simple JSP using XML format. 
+<br />
+
+<div>Use a jsp:scriptlet to loop from 1 to 10: </div>
+<jsp:scriptlet>
+// Note we need to declare CDATA because we don't escape the less than symbol
+<![CDATA[
+  for (int i = 1; i<=10; i++) {
+    out.print(i);
+    if (i < 10) {
+      out.print(", ");
+    }
+  }
+]]>
+</jsp:scriptlet>
+
+<!-- Because I omit br's end tag, declare it as CDATA -->
+<![CDATA[
+  <br><br>
+]]>
+
+<div align="left">
+  Use a jsp:expression to write something: 
+  <jsp:expression>getData()</jsp:expression>
+</div>
+
+
+<jsp:text>
+  &lt;p&gt;This sentence is enclosed in a jsp:text element.&lt;/p&gt;
+</jsp:text>
+
+</body>
+</html>
+</jsp:root>

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/JspForward01.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/JspForward01.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/JspForward01.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,2 @@
+<%@ page contentType="text/plain" %><jsp:forward page="<%= request.getParameter(\"path\") %>"/>
+JspForward01 FAILED - Content from forwarded-to page not included

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/JspForward01a.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/JspForward01a.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/JspForward01a.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1 @@
+<%@ page contentType="text/plain" %>JspForward01a PASSED

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/JspInclude01.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/JspInclude01.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/JspInclude01.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,4 @@
+<%@ page contentType="text/plain" %>This is before the include
+<jsp:include page="<%= request.getParameter(\"path\") %>" flush="true"/>
+This is after the include
+

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/JspInclude01a.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/JspInclude01a.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/JspInclude01a.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1 @@
+<%@ page contentType="text/plain" %>This is the include

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/JspInclude02.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/JspInclude02.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/JspInclude02.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,4 @@
+<%@ page contentType="text/plain" %>This is before the include
+<jsp:include page="<%= request.getParameter(\"path\") %>" flush="false"/>
+This is after the include
+

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/JspInclude02a.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/JspInclude02a.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/JspInclude02a.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1 @@
+<%@ page contentType="text/plain" %>This is the include

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/JspParams01.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/JspParams01.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/JspParams01.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,5 @@
+<jsp:include page="JspParams01a.jsp" flush="true">
+  <jsp:params>
+    <jsp:param name="foo" value="bar"/>
+  </jsp:params>
+</jsp:include>

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/JspParams02.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/JspParams02.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/JspParams02.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,5 @@
+<jsp:forward page="JspParams01a.jsp">
+  <jsp:params>
+    <jsp:param name="foo" value="bar"/>
+  </jsp:params>
+</jsp:forward>

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/Property01.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/Property01.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/Property01.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,12 @@
+<html>
+<head>
+<title>Property01.jsp - Positive PropertyEditor Test</title>
+</head>
+<body bgcolor="white">
+<jsp:useBean id="bean" scope="request"
+          class="org.apache.tester.SessionBean"/>
+<jsp:setProperty name="bean" property="dateProperty"
+                value="07/25/2001"/>
+Date property is '<jsp:getProperty name="bean" property="dateProperty"/>'.
+</body>
+</html>

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/Property02.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/Property02.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/Property02.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,12 @@
+<html>
+<head>
+<title>Property02.jsp - Negative PropertyEditor Test</title>
+</head>
+<body bgcolor="white">
+<jsp:useBean id="bean" scope="request"
+          class="org.apache.tester.SessionBean"/>
+<jsp:setProperty name="bean" property="dateProperty"
+                value="07/25/200A"/>
+Date property is '<jsp:getProperty name="bean" property="dateProperty"/>'.
+</body>
+</html>

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/Redirect02.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/Redirect02.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/Redirect02.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1 @@
+<%@ page contentType="text/plain" %><% String dummy = null; if (dummy == null) { response.sendRedirect(request.getContextPath() + "/Redirect02a.jsp"); return; } %>Redirect02.jsp FAILED - Content should not be visible

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/Redirect02a.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/Redirect02a.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/Redirect02a.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1 @@
+<%@ page contentType="text/plain" %>Redirect02a.jsp PASSED

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/Redirect03.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/Redirect03.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/Redirect03.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1 @@
+<%@ page contentType="text/plain" %><% String dummy = null; if (dummy == null) { response.sendRedirect(request.getContextPath() + "/Redirect03a.jsp");  } %>Redirect03.jsp FAILED - Content should not be visible

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/Redirect03a.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/Redirect03a.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/Redirect03a.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1 @@
+<%@ page contentType="text/plain" %>Redirect03a.jsp PASSED

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/ResponseWrap01b.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/ResponseWrap01b.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/ResponseWrap01b.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1 @@
+<%@ page contentType="text/plain"%>ResponseWrap01b PASSED

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/ResponseWrap01d.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/ResponseWrap01d.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/ResponseWrap01d.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1 @@
+<%@ page contentType="text/plain"%>ResponseWrap01d PASSED

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/SSIConditional01.shtml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/SSIConditional01.shtml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/SSIConditional01.shtml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,10 @@
+Before if block.
+<!--#set var="test" value="value1" -->
+<!--#if expr="\"$test\" = \"value1\"" -->
+test = value1
+<!--#elif expr="\"$test\" = \"value2\"" -->
+test = value2
+<!--#else -->
+test = neither value1 or value2
+<!--#endif -->
+After if block.

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/SSIConditional02.shtml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/SSIConditional02.shtml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/SSIConditional02.shtml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,10 @@
+Before if block.
+<!--#set var="test" value="value2" -->
+<!--#if expr="\"$test\" = \"value1\"" -->
+test = value1
+<!--#elif expr="\"$test\" = \"value2\"" -->
+test = value2
+<!--#else -->
+test = neither value1 or value2
+<!--#endif -->
+After if block.

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/SSIConditional03.shtml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/SSIConditional03.shtml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/SSIConditional03.shtml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,8 @@
+Before if block.
+<!--#set var="test" value="unquoted multi-word value" -->
+<!--#if expr="\"$test\" = unquoted multi-word value" -->
+test = "unquoted multi-word value"
+<!--#else -->
+test = not "unquoted multi-word value"
+<!--#endif -->
+After if block.

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/SSIConditional04.shtml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/SSIConditional04.shtml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/SSIConditional04.shtml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,8 @@
+<!--#set var="test1" value="not one" -->
+<!--#set var="test2" value="two" -->
+<!--#set var="test3" value="three" -->
+<!--#if expr="\"$test1\" = \"one\" && \"$test2\" = \"two\" || \"$test3\" = \"three\"" -->
+true
+<!--#else -->
+false
+<!--#endif -->

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/SSIConditional05.shtml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/SSIConditional05.shtml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/SSIConditional05.shtml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,8 @@
+<!--#set var="test1" value="not one" -->
+<!--#set var="test2" value="two" -->
+<!--#set var="test3" value="three" -->
+<!--#if expr="\"$test1\" = \"one\" && (\"$test2\" = \"two\" || \"$test3\" = \"three\")" -->
+true
+<!--#else -->
+false
+<!--#endif -->

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/SSIConditional06.shtml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/SSIConditional06.shtml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/SSIConditional06.shtml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,16 @@
+<!--#set var="test1" value="not one" -->
+<!--#set var="test2" value="two" -->
+<!--#set var="test3" value="three" -->
+<!--#if expr="\"$test1\" = \"one\" || \"$test2\" = \"two\"" -->
+<!--#if expr="\"$test1\" = \"one\"" -->
+one
+<!--#elif expr="\"$test1\" = \"not one\"" -->
+not one
+<!--#endif -->
+<!--#else -->
+<!--#if expr="\"$test2\" = \"two\"" -->
+two
+<!--#elif expr="\"$test2\" = \"not two\"" -->
+not two
+<!--#endif -->
+<!--#endif -->

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/SSIConditional07.shtml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/SSIConditional07.shtml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/SSIConditional07.shtml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,16 @@
+<!--#set var="test1" value="not one" -->
+<!--#set var="test2" value="not two" -->
+<!--#set var="test3" value="three" -->
+<!--#if expr="\"$test1\" = \"one\" || \"$test2\" = \"two\"" -->
+<!--#if expr="\"$test1\" = \"one\"" -->
+one
+<!--#elif expr="\"$test1\" = \"not one\"" -->
+not one
+<!--#endif -->
+<!--#else -->
+<!--#if expr="\"$test2\" = \"two\"" -->
+two
+<!--#elif expr="\"$test2\" = \"not two\"" -->
+not two
+<!--#endif -->
+<!--#endif -->

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/SSIConditional08.shtml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/SSIConditional08.shtml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/SSIConditional08.shtml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,7 @@
+<!--#set var="test" value="one" -->
+<!--#if expr="\"$test\" = \"one\"" -->
+<!--#set var="test" value="two" -->
+<!--#else -->
+<!--#set var="test" value="three" -->
+<!--#endif -->
+<!--#echo var="test" -->

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/SSIConfig01.shtml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/SSIConfig01.shtml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/SSIConfig01.shtml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,2 @@
+<!--#config errmsg="errmsg:Sorry this command won't work." -->
+<!--#fsize file="foo.shtml" -->

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/SSIConfig03.shtml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/SSIConfig03.shtml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/SSIConfig03.shtml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,4 @@
+<!--#config sizefmt="bytes" -->
+<!--#fsize file="includeme.txt" -->
+<!--#config sizefmt="abbrev" -->
+<!--#fsize file="includeme.txt" -->

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/SSIExecCGI.shtml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/SSIExecCGI.shtml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/SSIExecCGI.shtml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,38 @@
+<html> 
+  <head> 
+ <title>exec command  test examples </title> 
+ </head> 
+ <body>
+
+ <!--#exec cgi="/cgi-bin/array.pl" --><br>
+
+ <!--#exec cgi="/cgi-bin/binary.pl?counter=102" --><br>
+
+ <!--#exec cgi="/cgi-bin/chores.pl" --><br>
+
+ <!--#exec cgi="/cgi-bin/concat.pl?first_name=jane&last_name=johnson&fiance_first=john&fiance_last=smith" --><br>
+
+ <!--#exec cgi="/cgi-bin/days.pl" --><br>
+
+ <!--#exec cgi="/cgi-bin/dowhile.pl?start=10" --><br>
+
+ <!--#exec cgi="/cgi-bin/else.pl?food=spinach" --><br>
+
+ <!--#exec cgi="/cgi-bin/elsif.pl?food=chocolate" --><br>
+
+ <!--#exec cgi="/cgi-bin/exponents.pl?number=2&power=4" --><br>
+
+ <!--#exec cgi="/cgi-bin/for.pl?start=10" --><br>
+
+ <!--#exec cgi="/cgi-bin/getday.pl" --><br>
+
+ <!--#exec cgi="/cgi-bin/helloperl.cgi" --><br>
+
+ <!--#exec cgi="/cgi-bin/if.pl?food=spinach" --><br>
+
+ <!--#exec cgi="/cgi-bin/increment.pl?counter=7" --><br>
+
+ <!--#exec cgi="/cgi-bin/modifyall.pl?number=289" --><br>
+
+ </body> 
+ </html>

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/SSIExecCmd.shtml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/SSIExecCmd.shtml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/SSIExecCmd.shtml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,23 @@
+<html>
+  <head>
+ <title>exec command  test examples </title>
+ </head>
+ <body>
+ 
+ <h3>hello.exe
+      <!--#exec cmd="hello.exe" --> </h3>
+       using &lt;!--#exec cmd="hello.exe" --&gt; <br>
+       
+ <h3> The UNIX date of the server ::
+      <!--#exec cmd="date" --> </h3>
+      using &lt;!--#exec cmd="date" --&gt; <br>
+
+ <hr>
+
+ <h3>The current working directory ::
+      <!--#exec cmd="pwd" --> </h3>
+       using &lt;!--#exec cmd="pwd" --&gt; <br>
+
+
+ </body>
+ </html>

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/SSIFsize01.shtml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/SSIFsize01.shtml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/SSIFsize01.shtml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1 @@
+<!--#fsize -->

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/SSIFsize02.shtml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/SSIFsize02.shtml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/SSIFsize02.shtml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1 @@
+<!--#fsize file="includeme.txt" -->

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/SSIFsize03.shtml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/SSIFsize03.shtml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/SSIFsize03.shtml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1 @@
+<!--#fsize file="./includeme.txt" -->

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/SSIFsize04.shtml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/SSIFsize04.shtml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/SSIFsize04.shtml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1 @@
+<!--#fsize virtual="includeme.txt" -->

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/SSIFsize05.shtml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/SSIFsize05.shtml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/SSIFsize05.shtml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1 @@
+<!--#fsize virtual="/tester/includeme.txt" -->

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/SSIFsize06.shtml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/SSIFsize06.shtml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/SSIFsize06.shtml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1 @@
+<!--#fsize virtual="ssidir/includeme.txt" -->

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/SSIFsize07.shtml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/SSIFsize07.shtml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/SSIFsize07.shtml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1 @@
+<!--#fsize virtual="./ssidir/includeme.txt" -->

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/SSIFsize08.shtml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/SSIFsize08.shtml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/SSIFsize08.shtml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,2 @@
+<!--#fsize file="includeme.txt"
+  -->

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/SSIInclude01.shtml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/SSIInclude01.shtml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/SSIInclude01.shtml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1 @@
+<!--#include -->

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/SSIInclude02.shtml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/SSIInclude02.shtml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/SSIInclude02.shtml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1 @@
+<!--#include file="includeme.txt" -->

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/SSIInclude03.shtml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/SSIInclude03.shtml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/SSIInclude03.shtml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1 @@
+<!--#include file="./includeme.txt" -->

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/SSIInclude04.shtml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/SSIInclude04.shtml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/SSIInclude04.shtml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1 @@
+<!--#include virtual="includeme.txt" -->

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/SSIInclude05.shtml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/SSIInclude05.shtml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/SSIInclude05.shtml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1 @@
+<!--#include virtual="/tester/includeme.txt" -->

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/SSIInclude06.shtml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/SSIInclude06.shtml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/SSIInclude06.shtml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1 @@
+<!--#include virtual="ssidir/includeme.txt" -->

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/SSIInclude07.shtml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/SSIInclude07.shtml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/SSIInclude07.shtml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1 @@
+<!--#include virtual="./ssidir/includeme.txt" -->

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/SSIInclude08.shtml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/SSIInclude08.shtml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/SSIInclude08.shtml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,2 @@
+<!--#include file="includeme.txt"
+  -->

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/SSIInclude09.shtml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/SSIInclude09.shtml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/SSIInclude09.shtml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,6 @@
+<!--#include file="includeme.txt"
+  -->
+<!--#include file="SSIInclude08.shtml"
+  -->
+<!--#include file="includeme.txt"
+  -->

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/SSIVarSub01.shtml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/SSIVarSub01.shtml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/SSIVarSub01.shtml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,3 @@
+<!--#set var="test" value="$DOCUMENT_URI" -->
+<!--#echo var="test" -->
+

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/SSIVarSub02.shtml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/SSIVarSub02.shtml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/SSIVarSub02.shtml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,4 @@
+<!--#set var="test" value="value of test" -->
+<!--#set var="test2" value="${test}" -->
+<!--#echo var="test2" -->
+

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/SSIVarSub03.shtml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/SSIVarSub03.shtml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/SSIVarSub03.shtml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,5 @@
+<!--#set var="test" value="value of test" -->
+<!--#set var="test2" value="value of test2" -->
+<!--#set var="test3" value="$test $test2" -->
+<!--#echo var="test3" -->
+

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/SSIVarSub04.shtml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/SSIVarSub04.shtml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/SSIVarSub04.shtml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,5 @@
+<!--#set var="test" value="value of test" -->
+<!--#set var="test2" value="value of test2" -->
+<!--#set var="test3" value="${test} ${test2}" -->
+<!--#echo var="test3" -->
+

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/SSIVarSub05.shtml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/SSIVarSub05.shtml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/SSIVarSub05.shtml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,5 @@
+<!--#set var="test" value="value of test" -->
+<!--#set var="test2" value="value of test2" -->
+<!--#set var="test3" value="${test}|${test2}" -->
+<!--#echo var="test3" -->
+

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/SSIVarSub06.shtml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/SSIVarSub06.shtml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/SSIVarSub06.shtml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,3 @@
+<!--#set var="test" value="value of test" -->
+<!--#set var="test3" value="${test}\${test2}" -->
+<!--#echo var="test3" -->

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/Session07a.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/Session07a.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/Session07a.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,5 @@
+<%@ page contentType="text/plain" %><jsp:useBean id="simpleBean"
+    scope="session" class="org.apache.tester.SessionBean"/><%
+  simpleBean.setStringProperty("From Session07a");
+  response.sendRedirect("Session07b.jsp");
+%>

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/Session07b.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/Session07b.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/Session07b.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,9 @@
+<%@ page contentType="text/plain" %><jsp:useBean id="simpleBean"
+    scope="session" class="org.apache.tester.SessionBean"/><%
+  if ("From Session07a".equals(simpleBean.getStringProperty())) {
+    out.println("Session07 PASSED");
+  } else {
+    out.println("Session07 FAILED - Property = '" +
+                simpleBean.getStringProperty() + "'");
+  }
+%>

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/WEB-INF/cgi/array.pl
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/WEB-INF/cgi/array.pl	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/WEB-INF/cgi/array.pl	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,16 @@
+#!/usr/bin/perl
+
+print "Content-type: text/html\n\n";
+
+ at days = ("Monday", 
+         "Tuesday", 
+         "Wednesday", 
+         "Thursday", 
+         "Friday", 
+         "Saturday", 
+         "Sunday");
+
+print "These are the days of the week:";
+
+print "<p>";
+print "@days";

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/WEB-INF/cgi/binary.pl
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/WEB-INF/cgi/binary.pl	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/WEB-INF/cgi/binary.pl	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,14 @@
+#!/usr/bin/perl
+
+require "subparseform.lib";
+&Parse_Form;
+
+$counter = $formdata{'counter'};
+
+$counter +=1;
+
+print "Content-type: text/html\n\n";
+print "<FONT SIZE=+2>If you add one to your number, the result is <B>$counter</B>";
+
+$counter +=5;
+print "<P>If you add 5 to that, the result is <B>$counter</B></FONT>";

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/WEB-INF/cgi/concat.pl
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/WEB-INF/cgi/concat.pl	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/WEB-INF/cgi/concat.pl	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,12 @@
+#!/usr/bin/perl
+
+require "subparseform.lib";
+&Parse_Form;
+
+$first = $formdata{'first_name'};
+$married = $formdata{'fiance_last'};
+
+$fullname = $first . " " . $married;
+
+print "Content-type: text/html\n\n";
+print "Congratulations! Your married name would be $fullname.";

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/WEB-INF/cgi/days.pl
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/WEB-INF/cgi/days.pl	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/WEB-INF/cgi/days.pl	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,8 @@
+#!/usr/bin/perl
+
+ at days = ("Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday");
+
+print "Content-type: text/html\n\n";
+print "These are the days of the week:";
+print "<P>";
+print "@days";

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/WEB-INF/cgi/dowhile.pl
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/WEB-INF/cgi/dowhile.pl	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/WEB-INF/cgi/dowhile.pl	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,16 @@
+#!/usr/bin/perl
+
+require "subparseform.lib";
+&Parse_Form;
+
+$start = $formdata{'start'};
+
+print "Content-type: text/html\n\n";
+print "<P>Starting countdown...";
+
+do {
+	print "$start... ";
+	--$start;
+} while ($start > 0);
+
+print "KABOOM!";

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/WEB-INF/cgi/else.pl
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/WEB-INF/cgi/else.pl	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/WEB-INF/cgi/else.pl	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,15 @@
+#!/usr/bin/perl
+
+require "subparseform.lib";
+&Parse_Form;
+
+$food = $formdata{'food'};
+
+print "Content-type: text/html\n\n";
+
+if ($food eq "spinach") {
+	
+	print "You ate spinach, so you get dessert!";
+} else {
+	print "No spinach, no dessert!";
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/WEB-INF/cgi/elsif.pl
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/WEB-INF/cgi/elsif.pl	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/WEB-INF/cgi/elsif.pl	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,17 @@
+#!/usr/bin/perl
+
+require "subparseform.lib";
+&Parse_Form;
+
+$food = $formdata{'food'};
+
+print "Content-type: text/html\n\n";
+
+if ($food eq "spinach") {
+	
+	print "You ate spinach, so you get dessert!";
+} elsif ($food eq "broccoli") {
+	print "Broccoli's OK. Maybe you'll get dessert.";
+} else {
+	print "No spinach, no dessert!";
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/WEB-INF/cgi/exponents.pl
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/WEB-INF/cgi/exponents.pl	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/WEB-INF/cgi/exponents.pl	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,13 @@
+#!/usr/bin/perl
+
+require "subparseform.lib";
+&Parse_Form;
+
+$number = $formdata{'number'};
+$power = $formdata{'power'};
+
+$result = $number ** $power;
+
+print "Content-type: text/html\n\n";
+print "<P>You entered $number with an exponent of $power";
+print "<P>$number raised to the $power power is $result.";

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/WEB-INF/cgi/for.pl
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/WEB-INF/cgi/for.pl	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/WEB-INF/cgi/for.pl	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,15 @@
+#!/usr/bin/perl
+
+require "subparseform.lib";
+&Parse_Form;
+
+$start = $formdata{'start'};
+
+print "Content-type: text/html\n\n";
+print "<P>Starting countdown...";
+
+for ($i = $start; $i > 0; --$i) {
+	print "$i... ";
+} 
+
+print "KABOOM!";

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/WEB-INF/cgi/getday.pl
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/WEB-INF/cgi/getday.pl	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/WEB-INF/cgi/getday.pl	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,8 @@
+#!/usr/bin/perl
+
+ at days = qw(Sunday Monday Tuesday Wednesday Thursday Friday Saturday);
+
+print "Content-type: text/html\n\n";
+print "The first day of the week is $days[0]";
+
+print "<P>The third day of the week is $days[2]";

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/WEB-INF/cgi/helloperl.pl
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/WEB-INF/cgi/helloperl.pl	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/WEB-INF/cgi/helloperl.pl	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,9 @@
+#!/usr/bin/perl
+
+	$t	= "Hello World!";
+	print	<<EOT;
+Content-type: text/html
+
+	<Title> $t </Title>
+	<H1>	$t </H1>
+EOT

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/WEB-INF/cgi/if.pl
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/WEB-INF/cgi/if.pl	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/WEB-INF/cgi/if.pl	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,13 @@
+#!/usr/bin/perl
+
+require "subparseform.lib";
+&Parse_Form;
+
+$food = $formdata{'food'};
+
+
+
+if ($food eq "spinach") {
+	print "Content-type: text/html\n\n";
+	print "You ate spinach, so you get dessert!\n";
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/WEB-INF/cgi/increment.pl
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/WEB-INF/cgi/increment.pl	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/WEB-INF/cgi/increment.pl	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,19 @@
+#!/usr/bin/perl
+
+require "subparseform.lib";
+&Parse_Form;
+print "Content-type: text/html\n\n";
+
+$counter = $formdata{'counter'};
+
+++$counter;
+print "Your number incremented by 1 is $counter";
+$watch = ++$counter;
+print "<BR>Your number, incremented again by 1, is now $counter. If we store that operation, its value is also $watch.";
+
+$counter = $formdata{'counter'};
+print "<HR>Let's start over, with your original number $counter";
+$counter++;
+print "<BR>Again, your number incremented by 1 is $counter";
+$watch = $counter++;
+print "<BR>Now we store the value of your number in a second variable, which is now equal to $watch, and then we increment your number again. It's now $counter.";

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/WEB-INF/cgi/modifyall.pl
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/WEB-INF/cgi/modifyall.pl	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/WEB-INF/cgi/modifyall.pl	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,22 @@
+#!/usr/bin/perl
+
+require "subparseform.lib";
+&Parse_Form;
+
+ at numbers = split(/,/, $formdata{'number'});
+print "Content-type: text/html\n\n";
+
+print "The numbers you entered were:";
+foreach $number (@numbers) {
+	print "<LI>$number";
+	}
+	
+foreach $number(@numbers) {
+	$number = sqrt($number);
+	}
+
+print "<P>The square roots of those numbers are: ";
+
+foreach $number(@numbers) {
+	print "<LI>$number";
+	}

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/WEB-INF/cgi/preference.pl
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/WEB-INF/cgi/preference.pl	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/WEB-INF/cgi/preference.pl	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,9 @@
+#!/usr/bin/perl
+
+$div = 40 / 5 + 3;
+$parens = 40 / (5 + 3);
+$subadd = 9 - 3 + 5;
+$parens_subadd = 9 - (3 + 5);
+
+print "Content-type: text/html\n\n";
+print "div is $div, parens is $parens, subadd is $subadd and parens_subadd is $parens_subadd";

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/WEB-INF/cgi/subparseform.lib
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/WEB-INF/cgi/subparseform.lib	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/WEB-INF/cgi/subparseform.lib	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,43 @@
+sub Parse_Form 
+{
+if ($ENV{'REQUEST_METHOD'} eq 'GET') 
+{
+        @pairs = split(/&/, $ENV{'QUERY_STRING'});
+} 
+elsif ($ENV{'REQUEST_METHOD'} eq 'POST') 
+{
+    read (STDIN, $buffer, $ENV{'CONTENT_LENGTH'});
+    @pairs = split(/&/, $buffer);
+		
+    if ($ENV{'QUERY_STRING'}) 
+    {
+        @getpairs =split(/&/, $ENV{'QUERY_STRING'});
+        push(@pairs, at getpairs);
+    }
+} 
+else 
+{
+    print "Content-type: text/html\n\n";
+    print "<P>Use Post or Get";
+}
+
+foreach $pair (@pairs) 
+{
+    ($key, $value) = split (/=/, $pair);
+    $key =~ tr/+/ /;
+    $key =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;
+    $value =~ tr/+/ /;
+    $value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;
+    $value =~s/<!--(.|\n)*-->//g;
+	
+    if ($formdata{$key}) 
+    {
+        $formdata{$key} .= ", $value";
+    } 
+    else 
+    {
+        $formdata{$key} = $value;
+    }
+}
+}	
+1;

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/WEB-INF/cgi/subroutines.lib
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/WEB-INF/cgi/subroutines.lib	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/WEB-INF/cgi/subroutines.lib	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,34 @@
+#!/usr/local/bin/perl;
+
+sub cap {
+	$captext = $_[0];
+	$captext =~ tr/a-z/A-Z/;
+	return $captext;
+}
+
+sub which {
+	$browser = $ENV{'HTTP_USER_AGENT'};
+	if ($browser =~ /MSIE/) {
+		$browser = "Explorer";
+	} elsif ($browser =~/Mozilla/) {
+		$browser = "Netscape";
+	} else {
+		$browser = "something besides Netscape and Explorer";
+	}
+}
+
+sub header {
+	print "<HTML><HEAD><TITLE>";
+	print "$_[0]";
+	print "<TITLE><HEAD><BODY>"
+}
+
+sub footer {
+	print "<BODY><HTML>";
+}
+
+sub mime {
+	print "Content-type: text/html\n\n";
+}
+
+1;

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/WEB-INF/cgi/test-cgi.pl
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/WEB-INF/cgi/test-cgi.pl	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/WEB-INF/cgi/test-cgi.pl	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,93 @@
+#!/usr/local/bin/perl
+#
+# ========================================================================= *
+#                                                                           *
+#                 The Apache Software License,  Version 1.1                 *
+#                                                                           *
+#     Copyright (c) 1999, 2000, 2001  The Apache Software Foundation.       *
+#                           All rights reserved.                            *
+#                                                                           *
+# ========================================================================= *
+#                                                                           *
+# Redistribution and use in source and binary forms,  with or without modi- *
+# fication, are permitted provided that the following conditions are met:   *
+#                                                                           *
+# 1. Redistributions of source code  must retain the above copyright notice *
+#    notice, this list of conditions and the following disclaimer.          *
+#                                                                           *
+# 2. Redistributions  in binary  form  must  reproduce the  above copyright *
+#    notice,  this list of conditions  and the following  disclaimer in the *
+#    documentation and/or other materials provided with the distribution.   *
+#                                                                           *
+# 3. The end-user documentation  included with the redistribution,  if any, *
+#    must include the following acknowlegement:                             *
+#                                                                           *
+#       "This product includes  software developed  by the Apache  Software *
+#        Foundation <http://www.apache.org/>."                              *
+#                                                                           *
+#    Alternately, this acknowlegement may appear in the software itself, if *
+#    and wherever such third-party acknowlegements normally appear.         *
+#                                                                           *
+# 4. The names  "The  Jakarta  Project",  "Tomcat",  and  "Apache  Software *
+#    Foundation"  must not be used  to endorse or promote  products derived *
+#    from this  software without  prior  written  permission.  For  written *
+#    permission, please contact <apache at apache.org>.                        *
+#                                                                           *
+# 5. Products derived from this software may not be called "Apache" nor may *
+#    "Apache" appear in their names without prior written permission of the *
+#    Apache Software Foundation.                                            *
+#                                                                           *
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES *
+# INCLUDING, BUT NOT LIMITED TO,  THE IMPLIED WARRANTIES OF MERCHANTABILITY *
+# AND FITNESS FOR  A PARTICULAR PURPOSE  ARE DISCLAIMED.  IN NO EVENT SHALL *
+# THE APACHE  SOFTWARE  FOUNDATION OR  ITS CONTRIBUTORS  BE LIABLE  FOR ANY *
+# DIRECT,  INDIRECT,   INCIDENTAL,  SPECIAL,  EXEMPLARY,  OR  CONSEQUENTIAL *
+# DAMAGES (INCLUDING,  BUT NOT LIMITED TO,  PROCUREMENT OF SUBSTITUTE GOODS *
+# OR SERVICES;  LOSS OF USE,  DATA,  OR PROFITS;  OR BUSINESS INTERRUPTION) *
+# HOWEVER CAUSED AND  ON ANY  THEORY  OF  LIABILITY,  WHETHER IN  CONTRACT, *
+# STRICT LIABILITY, OR TORT  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN *
+# ANY  WAY  OUT OF  THE  USE OF  THIS  SOFTWARE,  EVEN  IF  ADVISED  OF THE *
+# POSSIBILITY OF SUCH DAMAGE.                                               *
+#                                                                           *
+# ========================================================================= *
+#                                                                           *
+# This software  consists of voluntary  contributions made  by many indivi- *
+# duals on behalf of the  Apache Software Foundation.  For more information *
+# on the Apache Software Foundation, please see <http://www.apache.org/>.   *
+#                                                                           *
+# ========================================================================= */
+#
+
+print <<EOM;
+Content-type: text/html
+
+<html>
+<head><title>CGI Test</title></head>
+<body>
+<h1>CGI Test</h1>
+<pre>
+EOM
+
+print "argc is " . ($#ARGV + 1) . "\n\n";
+
+print "argv is\n";
+
+for($i = 0; $i<($#ARGV+1); $i++) {
+	print $ARGV[$i] . "\n";
+}
+
+print "\n";
+	
+foreach $key (sort keys %ENV) {
+
+	print("$key: $ENV{$key}\n");
+
+}
+
+print <<EOM;
+</pre>
+</body>
+</html>
+EOM
+
+close OUT;

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/WEB-INF/web.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/WEB-INF/web.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/WEB-INF/web.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,2126 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<web-app 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-app_2_4.xsd"
+    version="2.4">
+
+    <!-- ========== Filter Definitions ==================================== -->
+
+    <filter>
+        <filter-name>GenericFilter</filter-name>
+        <filter-class>org.apache.tester.WrapperFilter</filter-class>
+        <init-param>
+            <param-name>request</param-name>
+            <param-value>generic</param-value>
+        </init-param>
+        <init-param>
+            <param-name>response</param-name>
+            <param-value>generic</param-value>
+        </init-param>
+    </filter>
+
+
+    <filter>
+        <filter-name>HttpFilter</filter-name>
+        <filter-class>org.apache.tester.WrapperFilter</filter-class>
+        <init-param>
+            <param-name>request</param-name>
+            <param-value>http</param-value>
+        </init-param>
+        <init-param>
+            <param-name>response</param-name>
+            <param-value>http</param-value>
+        </init-param>
+    </filter>
+
+
+    <filter>
+        <filter-name>StaticFilter</filter-name>
+        <filter-class>org.apache.tester.StaticFilter</filter-class>
+    </filter>
+
+
+    <filter>
+        <filter-name>UpperCaseFilter</filter-name>
+        <filter-class>org.apache.tester.UpperCaseFilter</filter-class>
+    </filter>
+
+
+    <!-- ========== Filter Mappings ======================================= -->
+
+    <!-- Use StaticFilter on *all* requests to clear static log -->
+    <filter-mapping>
+        <filter-name>StaticFilter</filter-name>
+        <url-pattern>/*</url-pattern>
+    </filter-mapping>
+
+    <filter-mapping>
+        <filter-name>HttpFilter</filter-name>
+        <url-pattern>/WrappedAggregate01</url-pattern>
+    </filter-mapping>
+
+    <filter-mapping>
+        <filter-name>HttpFilter</filter-name>
+        <url-pattern>/WrappedAggregate02</url-pattern>
+    </filter-mapping>
+
+    <filter-mapping>
+        <filter-name>HttpFilter</filter-name>
+        <url-pattern>/WrappedContext00</url-pattern>
+    </filter-mapping>
+
+    <filter-mapping>
+        <filter-name>HttpFilter</filter-name>
+        <url-pattern>/WrappedContext01</url-pattern>
+    </filter-mapping>
+
+    <filter-mapping>
+        <filter-name>HttpFilter</filter-name>
+        <url-pattern>/WrappedContext02</url-pattern>
+    </filter-mapping>
+
+    <filter-mapping>
+        <filter-name>HttpFilter</filter-name>
+        <url-pattern>/WrappedDecoding01</url-pattern>
+    </filter-mapping>
+
+    <filter-mapping>
+        <filter-name>HttpFilter</filter-name>
+        <url-pattern>/WrappedErrorPage01</url-pattern>
+    </filter-mapping>
+
+    <filter-mapping>
+        <filter-name>HttpFilter</filter-name>
+        <url-pattern>/WrappedErrorPage02</url-pattern>
+    </filter-mapping>
+
+    <filter-mapping>
+        <filter-name>HttpFilter</filter-name>
+        <url-pattern>/WrappedErrorPage03</url-pattern>
+    </filter-mapping>
+
+    <filter-mapping>
+        <filter-name>HttpFilter</filter-name>
+        <url-pattern>/WrappedErrorPage04</url-pattern>
+    </filter-mapping>
+
+    <filter-mapping>
+        <filter-name>HttpFilter</filter-name>
+        <url-pattern>/WrappedErrorPage05</url-pattern>
+    </filter-mapping>
+
+    <filter-mapping>
+        <filter-name>HttpFilter</filter-name>
+        <url-pattern>/WrappedErrorPage06</url-pattern>
+    </filter-mapping>
+
+    <filter-mapping>
+        <filter-name>HttpFilter</filter-name>
+        <url-pattern>/WrappedErrorPage07</url-pattern>
+    </filter-mapping>
+
+    <filter-mapping>
+        <filter-name>HttpFilter</filter-name>
+        <url-pattern>/WrappedErrorPage08</url-pattern>
+    </filter-mapping>
+
+    <filter-mapping>
+        <filter-name>HttpFilter</filter-name>
+        <url-pattern>/WrappedErrorPage09</url-pattern>
+    </filter-mapping>
+
+    <filter-mapping>
+        <filter-name>UpperCaseFilter</filter-name>
+        <url-pattern>/FilterRequest01</url-pattern>
+    </filter-mapping>
+
+    <filter-mapping>
+        <filter-name>HttpFilter</filter-name>
+        <url-pattern>/WrappedFilterRequest01</url-pattern>
+    </filter-mapping>
+
+    <filter-mapping>
+        <filter-name>UpperCaseFilter</filter-name>
+        <url-pattern>/WrappedFilterRequest01</url-pattern>
+    </filter-mapping>
+
+    <filter-mapping>
+        <filter-name>HttpFilter</filter-name>
+        <url-pattern>/WrappedFilterRequest02</url-pattern>
+    </filter-mapping>
+
+    <filter-mapping>
+        <filter-name>UpperCaseFilter</filter-name>
+        <url-pattern>/FilterResponse01</url-pattern>
+    </filter-mapping>
+
+    <filter-mapping>
+        <filter-name>HttpFilter</filter-name>
+        <url-pattern>/WrappedFilterResponse01</url-pattern>
+    </filter-mapping>
+
+    <filter-mapping>
+        <filter-name>UpperCaseFilter</filter-name>
+        <url-pattern>/WrappedFilterResponse01</url-pattern>
+    </filter-mapping>
+
+    <filter-mapping>
+        <filter-name>UpperCaseFilter</filter-name>
+        <url-pattern>/FilterResponse02.jsp</url-pattern>
+    </filter-mapping>
+
+    <filter-mapping>
+        <filter-name>HttpFilter</filter-name>
+        <url-pattern>/WrappedFilterResponse02.jsp</url-pattern>
+    </filter-mapping>
+
+    <filter-mapping>
+        <filter-name>UpperCaseFilter</filter-name>
+        <url-pattern>/WrappedFilterResponse02.jsp</url-pattern>
+    </filter-mapping>
+
+    <filter-mapping>
+        <filter-name>UpperCaseFilter</filter-name>
+        <url-pattern>/FilterResponse03.txt</url-pattern>
+    </filter-mapping>
+
+    <filter-mapping>
+        <filter-name>HttpFilter</filter-name>
+        <url-pattern>/WrappedFilterResponse03.txt</url-pattern>
+    </filter-mapping>
+
+    <filter-mapping>
+        <filter-name>UpperCaseFilter</filter-name>
+        <url-pattern>/WrappedFilterResponse03.txt</url-pattern>
+    </filter-mapping>
+
+    <filter-mapping>
+        <filter-name>HttpFilter</filter-name>
+        <url-pattern>/WrappedFilterResponse04</url-pattern>
+    </filter-mapping>
+
+    <filter-mapping>
+        <filter-name>HttpFilter</filter-name>
+        <url-pattern>/WrappedForward00</url-pattern>
+    </filter-mapping>
+
+    <filter-mapping>
+        <filter-name>HttpFilter</filter-name>
+        <url-pattern>/WrappedForward01</url-pattern>
+    </filter-mapping>
+
+    <filter-mapping>
+        <filter-name>HttpFilter</filter-name>
+        <url-pattern>/WrappedForward03</url-pattern>
+    </filter-mapping>
+
+    <filter-mapping>
+        <filter-name>HttpFilter</filter-name>
+        <url-pattern>/WrappedForward04</url-pattern>
+    </filter-mapping>
+
+    <filter-mapping>
+        <filter-name>HttpFilter</filter-name>
+        <url-pattern>/WrappedForward05</url-pattern>
+    </filter-mapping>
+
+    <filter-mapping>
+        <filter-name>HttpFilter</filter-name>
+        <url-pattern>/WrappedForward09</url-pattern>
+    </filter-mapping>
+
+    <filter-mapping>
+        <filter-name>HttpFilter</filter-name>
+        <url-pattern>/WrappedGetHeaders01</url-pattern>
+    </filter-mapping>
+
+    <filter-mapping>
+        <filter-name>GenericFilter</filter-name>
+        <url-pattern>/WrappedGetInputStream01</url-pattern>
+    </filter-mapping>
+
+    <filter-mapping>
+        <filter-name>HttpFilter</filter-name>
+        <url-pattern>/WrappedGetLocales01</url-pattern>
+    </filter-mapping>
+
+    <filter-mapping>
+        <filter-name>HttpFilter</filter-name>
+        <url-pattern>/WrappedGetLocales02</url-pattern>
+    </filter-mapping>
+
+    <filter-mapping>
+        <filter-name>GenericFilter</filter-name>
+        <url-pattern>/WrappedGetParameter01</url-pattern>
+    </filter-mapping>
+
+    <filter-mapping>
+        <filter-name>GenericFilter</filter-name>
+        <url-pattern>/WrappedGetParameterMap00</url-pattern>
+    </filter-mapping>
+
+    <filter-mapping>
+        <filter-name>HttpFilter</filter-name>
+        <url-pattern>/WrappedGetQueryString01</url-pattern>
+    </filter-mapping>
+
+    <filter-mapping>
+        <filter-name>HttpFilter</filter-name>
+        <url-pattern>/WrappedGolden01</url-pattern>
+    </filter-mapping>
+
+    <filter-mapping>
+        <filter-name>HttpFilter</filter-name>
+        <url-pattern>/WrappedInclude00</url-pattern>
+    </filter-mapping>
+
+    <filter-mapping>
+        <filter-name>HttpFilter</filter-name>
+        <url-pattern>/WrappedInclude01</url-pattern>
+    </filter-mapping>
+
+    <filter-mapping>
+        <filter-name>HttpFilter</filter-name>
+        <url-pattern>/WrappedInclude02</url-pattern>
+    </filter-mapping>
+
+    <filter-mapping>
+        <filter-name>HttpFilter</filter-name>
+        <url-pattern>/WrappedInclude03</url-pattern>
+    </filter-mapping>
+
+    <filter-mapping>
+        <filter-name>HttpFilter</filter-name>
+        <url-pattern>/WrappedInclude04</url-pattern>
+    </filter-mapping>
+
+    <filter-mapping>
+        <filter-name>HttpFilter</filter-name>
+        <url-pattern>/WrappedInclude09</url-pattern>
+    </filter-mapping>
+
+    <filter-mapping>
+        <filter-name>HttpFilter</filter-name>
+        <url-pattern>/WrappedInclude10</url-pattern>
+    </filter-mapping>
+
+    <filter-mapping>
+        <filter-name>HttpFilter</filter-name>
+        <url-pattern>/WrappedJndi01</url-pattern>
+    </filter-mapping>
+
+    <filter-mapping>
+        <filter-name>HttpFilter</filter-name>
+        <url-pattern>/WrappedJndi02</url-pattern>
+    </filter-mapping>
+
+    <filter-mapping>
+        <filter-name>HttpFilter</filter-name>
+        <url-pattern>/WrappedLifecycle01</url-pattern>
+    </filter-mapping>
+
+    <filter-mapping>
+        <filter-name>HttpFilter</filter-name>
+        <url-pattern>/WrappedLifecycle02</url-pattern>
+    </filter-mapping>
+
+    <filter-mapping>
+        <filter-name>HttpFilter</filter-name>
+        <url-pattern>/WrappedLifecycle03</url-pattern>
+    </filter-mapping>
+
+    <filter-mapping>
+        <filter-name>HttpFilter</filter-name>
+        <url-pattern>/WrappedRedirect01</url-pattern>
+    </filter-mapping>
+
+    <filter-mapping>
+        <filter-name>HttpFilter</filter-name>
+        <url-pattern>/WrappedReflection01</url-pattern>
+    </filter-mapping>
+
+    <filter-mapping>
+        <filter-name>HttpFilter</filter-name>
+        <url-pattern>/WrappedRequest01</url-pattern>
+    </filter-mapping>
+
+    <filter-mapping>
+        <filter-name>GenericFilter</filter-name>
+        <url-pattern>/WrappedReset01</url-pattern>
+    </filter-mapping>
+
+    <filter-mapping>
+        <filter-name>HttpFilter</filter-name>
+        <url-pattern>/WrappedResources01</url-pattern>
+    </filter-mapping>
+
+    <filter-mapping>
+        <filter-name>HttpFilter</filter-name>
+        <url-pattern>/WrappedResources02</url-pattern>
+    </filter-mapping>
+
+    <filter-mapping>
+        <filter-name>HttpFilter</filter-name>
+        <url-pattern>/WrappedResources03</url-pattern>
+    </filter-mapping>
+
+    <filter-mapping>
+        <filter-name>HttpFilter</filter-name>
+        <url-pattern>/WrappedResources04</url-pattern>
+    </filter-mapping>
+
+    <filter-mapping>
+        <filter-name>HttpFilter</filter-name>
+        <url-pattern>/WrappedResources05</url-pattern>
+    </filter-mapping>
+
+    <filter-mapping>
+        <filter-name>HttpFilter</filter-name>
+        <url-pattern>/WrappedResources06</url-pattern>
+    </filter-mapping>
+
+    <filter-mapping>
+        <filter-name>HttpFilter</filter-name>
+        <url-pattern>/WrappedSession01</url-pattern>
+    </filter-mapping>
+
+    <filter-mapping>
+        <filter-name>HttpFilter</filter-name>
+        <url-pattern>/WrappedSession02</url-pattern>
+    </filter-mapping>
+
+    <filter-mapping>
+        <filter-name>HttpFilter</filter-name>
+        <url-pattern>/WrappedSession03</url-pattern>
+    </filter-mapping>
+
+    <filter-mapping>
+        <filter-name>HttpFilter</filter-name>
+        <url-pattern>/WrappedSession04</url-pattern>
+    </filter-mapping>
+
+    <filter-mapping>
+        <filter-name>HttpFilter</filter-name>
+        <url-pattern>/WrappedSession05</url-pattern>
+    </filter-mapping>
+
+    <filter-mapping>
+        <filter-name>HttpFilter</filter-name>
+        <url-pattern>/WrappedSession06</url-pattern>
+    </filter-mapping>
+
+    <filter-mapping>
+        <filter-name>GenericFilter</filter-name>
+        <url-pattern>/WrappedSetBufferSize01</url-pattern>
+    </filter-mapping>
+
+    <filter-mapping>
+        <filter-name>GenericFilter</filter-name>
+        <url-pattern>/WrappedSetLocale01</url-pattern>
+    </filter-mapping>
+
+    <filter-mapping>
+        <filter-name>HttpFilter</filter-name>
+        <url-pattern>/WrappedXerces00</url-pattern>
+    </filter-mapping>
+
+    <filter-mapping>
+        <filter-name>HttpFilter</filter-name>
+        <url-pattern>/WrappedXerces01</url-pattern>
+    </filter-mapping>
+
+    <filter-mapping>
+        <filter-name>HttpFilter</filter-name>
+        <url-pattern>/WrappedXerces02</url-pattern>
+    </filter-mapping>
+
+
+    <!-- ========== Listener Definitions ================================== -->
+
+    <listener>
+        <listener-class>org.apache.tester.ContextListener01</listener-class>
+    </listener>
+
+<!-- Can not run PropertyEditor tests under security manager unless
+     catalina.policy allows read/write access to system properties -->
+<!--
+    <listener>
+        <listener-class>org.apache.tester.ContextListener02</listener-class>
+    </listener>
+-->
+
+    <listener>
+        <listener-class>org.apache.tester.RequestListener01</listener-class>
+    </listener>
+
+    <listener>
+        <listener-class>org.apache.tester.SessionListener01</listener-class>
+    </listener>
+
+    <listener>
+        <listener-class>org.apache.tester.SessionListener02</listener-class>
+    </listener>
+
+
+    <!-- ========== Servlet Definitions =================================== -->
+
+    <servlet>
+        <servlet-name>Aggregate01</servlet-name>
+        <servlet-class>org.apache.tester.Aggregate01</servlet-class>
+    </servlet>
+
+    <servlet>
+        <servlet-name>Aggregate02</servlet-name>
+        <servlet-class>org.apache.tester.Aggregate02</servlet-class>
+    </servlet>
+
+    <servlet>
+        <servlet-name>Authentication01</servlet-name>
+        <servlet-class>org.apache.tester.Authentication01</servlet-class>
+    </servlet>
+
+    <servlet>
+        <servlet-name>Authentication02</servlet-name>
+        <servlet-class>org.apache.tester.Authentication02</servlet-class>
+    </servlet>
+
+    <servlet>
+        <servlet-name>Authentication03</servlet-name>
+        <servlet-class>org.apache.tester.Authentication03</servlet-class>
+        <security-role-ref>
+            <role-name>alias</role-name>
+            <role-link>tomcat</role-link>
+        </security-role-ref>
+    </servlet>
+
+    <servlet>
+        <servlet-name>Authentication04</servlet-name>
+        <jsp-file>/Authentication04.jsp</jsp-file>
+        <security-role-ref>
+            <role-name>alias</role-name>
+            <role-link>tomcat</role-link>
+        </security-role-ref>
+    </servlet>
+
+    <servlet>
+        <servlet-name>Authentication05</servlet-name>
+        <servlet-class>org.apache.tester.Authentication05</servlet-class>
+    </servlet>
+
+    <servlet>
+        <servlet-name>Authentication06</servlet-name>
+        <servlet-class>org.apache.tester.Authentication06</servlet-class>
+    </servlet>
+
+    <servlet>
+        <servlet-name>Context00</servlet-name>
+        <servlet-class>org.apache.tester.Context00</servlet-class>
+        <load-on-startup>99</load-on-startup>
+    </servlet>
+
+    <servlet>
+        <servlet-name>Context01</servlet-name>
+        <servlet-class>org.apache.tester.Context01</servlet-class>
+    </servlet>
+
+    <servlet>
+        <servlet-name>Context02</servlet-name>
+        <servlet-class>org.apache.tester.Context02</servlet-class>
+    </servlet>
+
+    <servlet>
+        <servlet-name>Decoding01</servlet-name>
+        <servlet-class>org.apache.tester.Decoding01</servlet-class>
+    </servlet>
+
+    <servlet>
+        <servlet-name>ErrorPage01</servlet-name>
+        <servlet-class>org.apache.tester.ErrorPage01</servlet-class>
+    </servlet>
+
+    <servlet>
+        <servlet-name>ErrorPage02</servlet-name>
+        <servlet-class>org.apache.tester.ErrorPage02</servlet-class>
+    </servlet>
+
+    <servlet>
+        <servlet-name>ErrorPage03</servlet-name>
+        <servlet-class>org.apache.tester.ErrorPage03</servlet-class>
+    </servlet>
+
+    <servlet>
+        <servlet-name>ErrorPage04</servlet-name>
+        <servlet-class>org.apache.tester.ErrorPage04</servlet-class>
+    </servlet>
+
+    <servlet>
+        <servlet-name>ErrorPage05</servlet-name>
+        <servlet-class>org.apache.tester.ErrorPage05</servlet-class>
+    </servlet>
+
+    <servlet>
+        <servlet-name>ErrorPage06</servlet-name>
+        <servlet-class>org.apache.tester.ErrorPage06</servlet-class>
+    </servlet>
+
+    <servlet>
+        <servlet-name>ErrorPage07</servlet-name>
+        <servlet-class>org.apache.tester.ErrorPage07</servlet-class>
+        <load-on-startup>1</load-on-startup>
+    </servlet>
+
+    <servlet>
+        <servlet-name>ErrorPage08</servlet-name>
+        <jsp-file>/ErrorPage08.jsp</jsp-file>
+    </servlet>
+
+    <servlet>
+        <servlet-name>ErrorPage09</servlet-name>
+        <jsp-file>/ErrorPage09.jsp</jsp-file>
+    </servlet>
+
+    <servlet>
+        <servlet-name>FilterRequest01</servlet-name>
+        <servlet-class>org.apache.tester.FilterRequest01</servlet-class>
+    </servlet>
+
+    <servlet>
+        <servlet-name>FilterRequest02</servlet-name>
+        <servlet-class>org.apache.tester.FilterRequest02</servlet-class>
+    </servlet>
+
+    <servlet>
+        <servlet-name>FilterRequest02a</servlet-name>
+        <servlet-class>org.apache.tester.FilterRequest02a</servlet-class>
+    </servlet>
+
+    <servlet>
+        <servlet-name>FilterResponse01</servlet-name>
+        <servlet-class>org.apache.tester.FilterResponse01</servlet-class>
+    </servlet>
+
+    <servlet>
+        <servlet-name>FilterResponse04</servlet-name>
+        <servlet-class>org.apache.tester.FilterResponse04</servlet-class>
+    </servlet>
+
+    <servlet>
+        <servlet-name>FilterResponse04a</servlet-name>
+        <servlet-class>org.apache.tester.FilterResponse04a</servlet-class>
+    </servlet>
+
+    <servlet>
+        <servlet-name>Forward00</servlet-name>
+        <servlet-class>org.apache.tester.Forward00</servlet-class>
+    </servlet>
+
+    <servlet>
+        <servlet-name>Forward00a</servlet-name>
+        <servlet-class>org.apache.tester.Forward00a</servlet-class>
+    </servlet>
+
+    <servlet>
+        <servlet-name>Forward00b</servlet-name>
+        <jsp-file>/Forward00b.jsp</jsp-file>
+    </servlet>
+
+    <servlet>
+        <servlet-name>Forward00d</servlet-name>
+        <servlet-class>org.apache.tester.Forward00d</servlet-class>
+    </servlet>
+
+    <servlet>
+        <servlet-name>Forward00e</servlet-name>
+        <jsp-file>/Forward00e.jsp</jsp-file>
+    </servlet>
+
+    <servlet>
+        <servlet-name>Forward01</servlet-name>
+        <servlet-class>org.apache.tester.Forward01</servlet-class>
+    </servlet>
+
+    <servlet>
+        <servlet-name>Forward03</servlet-name>
+        <servlet-class>org.apache.tester.Forward03</servlet-class>
+    </servlet>
+
+    <servlet>
+        <servlet-name>Forward03a</servlet-name>
+        <servlet-class>org.apache.tester.Forward03a</servlet-class>
+    </servlet>
+
+    <servlet>
+        <servlet-name>Forward04</servlet-name>
+        <servlet-class>org.apache.tester.Forward04</servlet-class>
+    </servlet>
+
+    <servlet>
+        <servlet-name>Forward04a</servlet-name>
+        <servlet-class>org.apache.tester.Forward04a</servlet-class>
+    </servlet>
+
+    <servlet>
+        <servlet-name>Forward04b</servlet-name>
+        <servlet-class>org.apache.tester.Forward04b</servlet-class>
+    </servlet>
+
+    <servlet>
+        <servlet-name>Forward05</servlet-name>
+        <servlet-class>org.apache.tester.Forward05</servlet-class>
+    </servlet>
+
+    <servlet>
+        <servlet-name>Forward05a</servlet-name>
+        <servlet-class>org.apache.tester.Forward05a</servlet-class>
+    </servlet>
+
+    <servlet>
+        <servlet-name>Forward05b</servlet-name>
+        <servlet-class>org.apache.tester.Forward05b</servlet-class>
+    </servlet>
+
+    <servlet>
+        <servlet-name>Forward06</servlet-name>
+        <servlet-class>org.apache.tester.Forward06</servlet-class>
+    </servlet>
+
+    <servlet>
+        <servlet-name>Forward06a</servlet-name>
+        <servlet-class>org.apache.tester.Forward06a</servlet-class>
+    </servlet>
+
+    <servlet>
+        <servlet-name>Forward06b</servlet-name>
+        <servlet-class>org.apache.tester.Forward06b</servlet-class>
+    </servlet>
+
+    <servlet>
+        <servlet-name>Forward07</servlet-name>
+        <servlet-class>org.apache.tester.Forward07</servlet-class>
+    </servlet>
+
+    <servlet>
+        <servlet-name>Forward07a</servlet-name>
+        <servlet-class>org.apache.tester.Forward07a</servlet-class>
+    </servlet>
+
+    <servlet>
+        <servlet-name>Forward07b</servlet-name>
+        <servlet-class>org.apache.tester.Forward07b</servlet-class>
+    </servlet>
+
+    <servlet>
+        <servlet-name>Forward08</servlet-name>
+        <servlet-class>org.apache.tester.Forward08</servlet-class>
+    </servlet>
+
+    <servlet>
+        <servlet-name>Forward08a</servlet-name>
+        <servlet-class>org.apache.tester.Forward08a</servlet-class>
+    </servlet>
+
+    <servlet>
+        <servlet-name>Forward08b</servlet-name>
+        <servlet-class>org.apache.tester.Forward08b</servlet-class>
+    </servlet>
+
+    <servlet>
+        <servlet-name>Forward09</servlet-name>
+        <servlet-class>org.apache.tester.Forward09</servlet-class>
+    </servlet>
+
+    <servlet>
+        <servlet-name>GetHeaders01</servlet-name>
+        <servlet-class>org.apache.tester.GetHeaders01</servlet-class>
+    </servlet>
+
+    <servlet>
+        <servlet-name>GetInputStream01</servlet-name>
+        <servlet-class>org.apache.tester.GetInputStream01</servlet-class>
+    </servlet>
+
+    <servlet>
+        <servlet-name>GetLocales01</servlet-name>
+        <servlet-class>org.apache.tester.GetLocales01</servlet-class>
+    </servlet>
+
+    <servlet>
+        <servlet-name>GetLocales02</servlet-name>
+        <servlet-class>org.apache.tester.GetLocales02</servlet-class>
+    </servlet>
+
+    <servlet>
+        <servlet-name>GetParameter01</servlet-name>
+        <servlet-class>org.apache.tester.GetParameter01</servlet-class>
+    </servlet>
+
+    <servlet>
+        <servlet-name>GetParameterMap00</servlet-name>
+        <servlet-class>org.apache.tester.GetParameterMap00</servlet-class>
+    </servlet>
+
+    <servlet>
+        <servlet-name>GetQueryString01</servlet-name>
+        <servlet-class>org.apache.tester.GetQueryString01</servlet-class>
+    </servlet>
+
+    <servlet>
+        <servlet-name>Golden01</servlet-name>
+        <servlet-class>org.apache.tester.Golden01</servlet-class>
+    </servlet>
+
+    <servlet>
+        <servlet-name>Include00</servlet-name>
+        <servlet-class>org.apache.tester.Include00</servlet-class>
+    </servlet>
+
+    <servlet>
+        <servlet-name>Include00a</servlet-name>
+        <servlet-class>org.apache.tester.Include00a</servlet-class>
+    </servlet>
+
+    <servlet>
+        <servlet-name>Include00b</servlet-name>
+        <jsp-file>/Include00b.jsp</jsp-file>
+    </servlet>
+
+    <servlet>
+        <servlet-name>Include00d</servlet-name>
+        <servlet-class>org.apache.tester.Include00d</servlet-class>
+    </servlet>
+
+    <servlet>
+        <servlet-name>Include00e</servlet-name>
+        <jsp-file>/Include00e.jsp</jsp-file>
+    </servlet>
+
+    <servlet>
+        <servlet-name>Include01</servlet-name>
+        <servlet-class>org.apache.tester.Include01</servlet-class>
+    </servlet>
+
+    <servlet>
+        <servlet-name>Include02</servlet-name>
+        <servlet-class>org.apache.tester.Include02</servlet-class>
+    </servlet>
+
+    <servlet>
+        <servlet-name>Include02a</servlet-name>
+        <servlet-class>org.apache.tester.Include02a</servlet-class>
+    </servlet>
+
+    <servlet>
+        <servlet-name>Include03</servlet-name>
+        <servlet-class>org.apache.tester.Include03</servlet-class>
+    </servlet>
+
+    <servlet>
+        <servlet-name>Include03a</servlet-name>
+        <servlet-class>org.apache.tester.Include03a</servlet-class>
+    </servlet>
+
+    <servlet>
+        <servlet-name>Include04</servlet-name>
+        <servlet-class>org.apache.tester.Include04</servlet-class>
+    </servlet>
+
+    <servlet>
+        <servlet-name>Include04a</servlet-name>
+        <servlet-class>org.apache.tester.Include04a</servlet-class>
+    </servlet>
+
+    <servlet>
+        <servlet-name>Include04b</servlet-name>
+        <servlet-class>org.apache.tester.Include04b</servlet-class>
+    </servlet>
+
+    <servlet>
+        <servlet-name>Include06a</servlet-name>
+        <servlet-class>org.apache.tester.Include06a</servlet-class>
+    </servlet>
+
+    <servlet>
+        <servlet-name>Include07</servlet-name>
+        <servlet-class>org.apache.tester.Include07</servlet-class>
+    </servlet>
+
+    <servlet>
+        <servlet-name>Include07a</servlet-name>
+        <servlet-class>org.apache.tester.Include07a</servlet-class>
+    </servlet>
+
+    <servlet>
+        <servlet-name>Include07b</servlet-name>
+        <servlet-class>org.apache.tester.Include07b</servlet-class>
+    </servlet>
+
+    <servlet>
+        <servlet-name>Include07c</servlet-name>
+        <servlet-class>org.apache.tester.Include07c</servlet-class>
+    </servlet>
+
+    <servlet>
+        <servlet-name>Include09</servlet-name>
+        <servlet-class>org.apache.tester.Include09</servlet-class>
+    </servlet>
+
+    <servlet>
+        <servlet-name>Include10</servlet-name>
+        <servlet-class>org.apache.tester.Include10</servlet-class>
+    </servlet>
+
+    <servlet>
+        <servlet-name>Include10a</servlet-name>
+        <servlet-class>org.apache.tester.Include10a</servlet-class>
+    </servlet>
+
+    <servlet>
+        <servlet-name>Jndi01</servlet-name>
+        <servlet-class>org.apache.tester.Jndi01</servlet-class>
+        <load-on-startup>1</load-on-startup>
+    </servlet>
+
+    <servlet>
+        <servlet-name>Jndi02</servlet-name>
+        <servlet-class>org.apache.tester.Jndi02</servlet-class>
+    </servlet>
+
+    <servlet>
+        <servlet-name>Lifecycle01</servlet-name>
+        <servlet-class>org.apache.tester.Lifecycle01</servlet-class>
+    </servlet>
+
+    <servlet>
+        <servlet-name>Lifecycle02</servlet-name>
+        <servlet-class>org.apache.tester.Lifecycle02</servlet-class>
+    </servlet>
+
+    <servlet>
+        <servlet-name>Lifecycle03</servlet-name>
+        <servlet-class>org.apache.tester.Lifecycle03</servlet-class>
+    </servlet>
+
+    <servlet>
+        <servlet-name>Redirect01</servlet-name>
+        <servlet-class>org.apache.tester.Redirect01</servlet-class>
+    </servlet>
+
+    <servlet>
+        <servlet-name>Redirect01a</servlet-name>
+        <servlet-class>org.apache.tester.Redirect01a</servlet-class>
+    </servlet>
+
+    <servlet>
+        <servlet-name>Reflection01</servlet-name>
+        <servlet-class>org.apache.tester.Reflection01</servlet-class>
+    </servlet>
+
+    <servlet>
+        <servlet-name>Request01</servlet-name>
+        <servlet-class>org.apache.tester.Request01</servlet-class>
+    </servlet>
+
+    <servlet>
+        <servlet-name>Reset01</servlet-name>
+        <servlet-class>org.apache.tester.Reset01</servlet-class>
+    </servlet>
+
+    <servlet>
+        <servlet-name>Resources01</servlet-name>
+        <servlet-class>org.apache.tester.Resources01</servlet-class>
+    </servlet>
+
+    <servlet>
+        <servlet-name>Resources02</servlet-name>
+        <servlet-class>org.apache.tester.Resources02</servlet-class>
+    </servlet>
+
+    <servlet>
+        <servlet-name>Resources03</servlet-name>
+        <servlet-class>org.apache.tester.Resources03</servlet-class>
+    </servlet>
+
+    <servlet>
+        <servlet-name>Resources04</servlet-name>
+        <servlet-class>org.apache.tester.Resources04</servlet-class>
+    </servlet>
+
+    <servlet>
+        <servlet-name>Resources05</servlet-name>
+        <servlet-class>org.apache.tester.Resources05</servlet-class>
+    </servlet>
+
+    <servlet>
+        <servlet-name>Resources06</servlet-name>
+        <servlet-class>org.apache.tester.Resources06</servlet-class>
+    </servlet>
+
+    <servlet>
+        <servlet-name>ResponseWrap01</servlet-name>
+        <servlet-class>org.apache.tester.ResponseWrap01</servlet-class>
+    </servlet>
+
+    <servlet>
+        <servlet-name>ResponseWrap01a</servlet-name>
+        <servlet-class>org.apache.tester.ResponseWrap01a</servlet-class>
+    </servlet>
+
+    <servlet>
+        <servlet-name>ResponseWrap01c</servlet-name>
+        <servlet-class>org.apache.tester.ResponseWrap01c</servlet-class>
+    </servlet>
+
+    <servlet>
+        <servlet-name>Session01</servlet-name>
+        <servlet-class>org.apache.tester.Session01</servlet-class>
+    </servlet>
+
+    <servlet>
+        <servlet-name>Session02</servlet-name>
+        <servlet-class>org.apache.tester.Session02</servlet-class>
+    </servlet>
+
+    <servlet>
+        <servlet-name>Session03</servlet-name>
+        <servlet-class>org.apache.tester.Session03</servlet-class>
+    </servlet>
+
+    <servlet>
+        <servlet-name>Session04</servlet-name>
+        <servlet-class>org.apache.tester.Session04</servlet-class>
+    </servlet>
+
+    <servlet>
+        <servlet-name>Session05</servlet-name>
+        <servlet-class>org.apache.tester.Session05</servlet-class>
+    </servlet>
+
+    <servlet>
+        <servlet-name>Session06</servlet-name>
+        <servlet-class>org.apache.tester.Session06</servlet-class>
+    </servlet>
+
+    <servlet>
+        <servlet-name>SetBufferSize01</servlet-name>
+        <servlet-class>org.apache.tester.SetBufferSize01</servlet-class>
+    </servlet>
+
+    <servlet>
+        <servlet-name>SetLocale01</servlet-name>
+        <servlet-class>org.apache.tester.SetLocale01</servlet-class>
+    </servlet>
+
+    <servlet>
+        <servlet-name>Xerces00</servlet-name>
+        <jsp-file>/Xerces00.jsp</jsp-file>
+    </servlet>
+
+    <servlet>
+        <servlet-name>Xerces01</servlet-name>
+        <servlet-class>org.apache.tester.Xerces01</servlet-class>
+    </servlet>
+
+    <servlet>
+        <servlet-name>Xerces02</servlet-name>
+        <jsp-file>/Xerces02.jsp</jsp-file>
+    </servlet>
+
+
+    <servlet>
+        <servlet-name>invoker</servlet-name>
+        <servlet-class>
+          org.apache.catalina.servlets.InvokerServlet
+        </servlet-class>
+        <init-param>
+            <param-name>debug</param-name>
+            <param-value>0</param-value>
+        </init-param>
+        <load-on-startup>2</load-on-startup>
+    </servlet>
+
+
+    <!-- ========== Servlet Mappings ====================================== -->
+
+
+    <servlet-mapping>
+        <servlet-name>invoker</servlet-name>
+        <url-pattern>/servlet/*</url-pattern>
+    </servlet-mapping>
+
+    <!-- Map CGI Gateway Service for this Web App -->
+<!--
+    <servlet-mapping>
+        <servlet-name>cgi</servlet-name>
+        <url-pattern>/cgi-bin/*</url-pattern>
+    </servlet-mapping>
+-->
+
+    <!-- Map SSI Service for this Web App -->
+<!--
+    <servlet-mapping>
+        <servlet-name>ssi</servlet-name>
+        <url-pattern>*.shtml</url-pattern>
+    </servlet-mapping>
+-->
+
+    <servlet-mapping>
+        <servlet-name>Aggregate01</servlet-name>
+        <url-pattern>/Aggregate01</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>Aggregate01</servlet-name>
+        <url-pattern>/WrappedAggregate01</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>Aggregate02</servlet-name>
+        <url-pattern>/Aggregate02</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>Aggregate02</servlet-name>
+        <url-pattern>/WrappedAggregate02</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>Authentication01</servlet-name>
+        <url-pattern>/protected/Authentication01</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>Authentication02</servlet-name>
+        <url-pattern>/protected/Authentication02</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>Authentication03</servlet-name>
+        <url-pattern>/protected/Authentication03</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>Authentication04</servlet-name>
+        <url-pattern>/protected/Authentication04</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>Authentication05</servlet-name>
+        <url-pattern>/allowed/Authentication05</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>Authentication05</servlet-name>
+        <url-pattern>/disallowed/Authentication05</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>Authentication05</servlet-name>
+        <url-pattern>/disallowed/private/Authentication05</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>Authentication06</servlet-name>
+        <url-pattern>/allowed/public/Authentication06</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>Authentication05</servlet-name>
+        <url-pattern>/allowed/private/Authentication05</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>Context00</servlet-name>
+        <url-pattern>/Context00</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>Context00</servlet-name>
+        <url-pattern>/WrappedContext00</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>Context01</servlet-name>
+        <url-pattern>/Context01</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>Context01</servlet-name>
+        <url-pattern>/WrappedContext01</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>Context02</servlet-name>
+        <url-pattern>/Context02</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>Context02</servlet-name>
+        <url-pattern>/WrappedContext02</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>Decoding01</servlet-name>
+        <url-pattern>/Decoding01/*</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>Decoding01</servlet-name>
+        <url-pattern>/WrappedDecoding01/*</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>ErrorPage01</servlet-name>
+        <url-pattern>/ErrorPage01</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>ErrorPage01</servlet-name>
+        <url-pattern>/WrappedErrorPage01</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>ErrorPage02</servlet-name>
+        <url-pattern>/ErrorPage02</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>ErrorPage02</servlet-name>
+        <url-pattern>/WrappedErrorPage02</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>ErrorPage03</servlet-name>
+        <url-pattern>/ErrorPage03</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>ErrorPage03</servlet-name>
+        <url-pattern>/WrappedErrorPage03</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>ErrorPage04</servlet-name>
+        <url-pattern>/ErrorPage04</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>ErrorPage04</servlet-name>
+        <url-pattern>/WrappedErrorPage04</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>ErrorPage05</servlet-name>
+        <url-pattern>/ErrorPage05</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>ErrorPage05</servlet-name>
+        <url-pattern>/WrappedErrorPage05</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>ErrorPage06</servlet-name>
+        <url-pattern>/ErrorPage06</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>ErrorPage06</servlet-name>
+        <url-pattern>/WrappedErrorPage06</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>ErrorPage07</servlet-name>
+        <url-pattern>/ErrorPage07</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>ErrorPage07</servlet-name>
+        <url-pattern>/WrappedErrorPage07</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>ErrorPage08</servlet-name>
+        <url-pattern>/ErrorPage08</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>ErrorPage08</servlet-name>
+        <url-pattern>/WrappedErrorPage08</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>ErrorPage09</servlet-name>
+        <url-pattern>/ErrorPage09</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>ErrorPage09</servlet-name>
+        <url-pattern>/WrappedErrorPage09</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>FilterRequest01</servlet-name>
+        <url-pattern>/FilterRequest01</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>FilterRequest01</servlet-name>
+        <url-pattern>/WrappedFilterRequest01</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>FilterRequest02</servlet-name>
+        <url-pattern>/FilterRequest02/*</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>FilterRequest02</servlet-name>
+        <url-pattern>/WrappedFilterRequest02/*</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>FilterRequest02a</servlet-name>
+        <url-pattern>/FilterRequest02a</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>FilterResponse01</servlet-name>
+        <url-pattern>/FilterResponse01</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>FilterResponse01</servlet-name>
+        <url-pattern>/WrappedFilterResponse01</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>FilterResponse04</servlet-name>
+        <url-pattern>/FilterResponse04/*</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>FilterResponse04</servlet-name>
+        <url-pattern>/WrappedFilterResponse04/*</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>FilterResponse04a</servlet-name>
+        <url-pattern>/FilterResponse04a</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>Forward00</servlet-name>
+        <url-pattern>/Forward00</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>Forward00</servlet-name>
+        <url-pattern>/WrappedForward00</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>Forward00a</servlet-name>
+        <url-pattern>/Forward00a</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>Forward00b</servlet-name>
+        <url-pattern>/Forward00b</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>Forward01</servlet-name>
+        <url-pattern>/Forward01</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>Forward01</servlet-name>
+        <url-pattern>/WrappedForward01</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>Forward03</servlet-name>
+        <url-pattern>/Forward03</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>Forward03</servlet-name>
+        <url-pattern>/WrappedForward03</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>Forward03a</servlet-name>
+        <url-pattern>/Forward03a</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>Forward04</servlet-name>
+        <url-pattern>/Forward04</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>Forward04</servlet-name>
+        <url-pattern>/WrappedForward04</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>Forward04a</servlet-name>
+        <url-pattern>/Forward04a</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>Forward04b</servlet-name>
+        <url-pattern>/Forward04b</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>Forward05</servlet-name>
+        <url-pattern>/Forward05</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>Forward05</servlet-name>
+        <url-pattern>/WrappedForward05</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>Forward05a</servlet-name>
+        <url-pattern>/Forward05a</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>Forward05b</servlet-name>
+        <url-pattern>/Forward05b</url-pattern>
+    </servlet-mapping>
+
+    <!-- No mappings for Forward06 series, using invoker to access them -->
+
+    <servlet-mapping>
+        <servlet-name>Forward07</servlet-name>
+        <url-pattern>/Forward07</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>Forward07</servlet-name>
+        <url-pattern>/WrappedForward07</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>Forward07a</servlet-name>
+        <url-pattern>/Forward07a</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>Forward07b</servlet-name>
+        <url-pattern>/Forward07b</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>Forward08</servlet-name>
+        <url-pattern>/WrappedForward08</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>Forward08a</servlet-name>
+        <url-pattern>/Forward08a</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>Forward08b</servlet-name>
+        <url-pattern>/Forward08b</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>Forward09</servlet-name>
+        <url-pattern>/Forward09</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>Forward09</servlet-name>
+        <url-pattern>/WrappedForward09</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>GetHeaders01</servlet-name>
+        <url-pattern>/GetHeaders01</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>GetHeaders01</servlet-name>
+        <url-pattern>/WrappedGetHeaders01</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>GetInputStream01</servlet-name>
+        <url-pattern>/GetInputStream01</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>GetInputStream01</servlet-name>
+        <url-pattern>/WrappedGetInputStream01</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>GetLocales01</servlet-name>
+        <url-pattern>/GetLocales01</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>GetLocales01</servlet-name>
+        <url-pattern>/WrappedGetLocales01</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>GetLocales02</servlet-name>
+        <url-pattern>/GetLocales02</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>GetLocales02</servlet-name>
+        <url-pattern>/WrappedGetLocales02</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>GetParameter01</servlet-name>
+        <url-pattern>/WrappedGetParameter01</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>GetParameter01</servlet-name>
+        <url-pattern>/GetParameter01</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>GetParameter01</servlet-name>
+        <url-pattern>/WrappedGetParameter01</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>GetParameterMap00</servlet-name>
+        <url-pattern>/GetParameterMap00</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>GetParameterMap00</servlet-name>
+        <url-pattern>/WrappedGetParameterMap00</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>GetQueryString01</servlet-name>
+        <url-pattern>/GetQueryString01</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>GetQueryString01</servlet-name>
+        <url-pattern>/WrappedGetQueryString01</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>Golden01</servlet-name>
+        <url-pattern>/Golden01</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>Golden01</servlet-name>
+        <url-pattern>/WrappedGolden01</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>Include00</servlet-name>
+        <url-pattern>/Include00</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>Include00</servlet-name>
+        <url-pattern>/WrappedInclude00</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>Include00a</servlet-name>
+        <url-pattern>/Include00a</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>Include00b</servlet-name>
+        <url-pattern>/Include00b</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>Include01</servlet-name>
+        <url-pattern>/Include01</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>Include01</servlet-name>
+        <url-pattern>/WrappedInclude01</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>Include02</servlet-name>
+        <url-pattern>/Include02</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>Include02</servlet-name>
+        <url-pattern>/WrappedInclude02</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>Include02a</servlet-name>
+        <url-pattern>/Include02a</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>Include02a</servlet-name>
+        <url-pattern>/WrappedInclude02a</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>Include03</servlet-name>
+        <url-pattern>/Include03</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>Include03</servlet-name>
+        <url-pattern>/WrappedInclude03</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>Include03a</servlet-name>
+        <url-pattern>/Include03a</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>Include04</servlet-name>
+        <url-pattern>/Include04</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>Include04</servlet-name>
+        <url-pattern>/WrappedInclude04</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>Include04a</servlet-name>
+        <url-pattern>/Include04a</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>Include04b</servlet-name>
+        <url-pattern>/Include04b</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>Include06a</servlet-name>
+        <url-pattern>/Include06a</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>Include07</servlet-name>
+        <url-pattern>/Include07</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>Include07a</servlet-name>
+        <url-pattern>/Include07a</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>Include07b</servlet-name>
+        <url-pattern>/Include07b</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>Include07c</servlet-name>
+        <url-pattern>/Include07c</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>Include09</servlet-name>
+        <url-pattern>/Include09</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>Include09</servlet-name>
+        <url-pattern>/WrappedInclude09</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>Include10</servlet-name>
+        <url-pattern>/Include10/*</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>Include10</servlet-name>
+        <url-pattern>/WrappedInclude10/*</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>Include10a</servlet-name>
+        <url-pattern>/Include10a/*</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>Jndi01</servlet-name>
+        <url-pattern>/Jndi01</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>Jndi01</servlet-name>
+        <url-pattern>/WrappedJndi01</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>Jndi02</servlet-name>
+        <url-pattern>/Jndi02</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>Jndi02</servlet-name>
+        <url-pattern>/WrappedJndi02</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>Lifecycle01</servlet-name>
+        <url-pattern>/Lifecycle01</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>Lifecycle01</servlet-name>
+        <url-pattern>/WrappedLifecycle01</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>Lifecycle02</servlet-name>
+        <url-pattern>/Lifecycle02</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>Lifecycle02</servlet-name>
+        <url-pattern>/WrappedLifecycle02</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>Lifecycle03</servlet-name>
+        <url-pattern>/Lifecycle03</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>Lifecycle03</servlet-name>
+        <url-pattern>/WrappedLifecycle03</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>Redirect01</servlet-name>
+        <url-pattern>/Redirect01</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>Redirect01</servlet-name>
+        <url-pattern>/WrappedRedirect01</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>Redirect01a</servlet-name>
+        <url-pattern>/Redirect01a</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>Redirect01a</servlet-name>
+        <url-pattern>/WrappedRedirect01a</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>Reflection01</servlet-name>
+        <url-pattern>/Reflection01</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>Reflection01</servlet-name>
+        <url-pattern>/WrappedReflection01</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>Request01</servlet-name>
+        <url-pattern>/Request01</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>Request01</servlet-name>
+        <url-pattern>/WrappedRequest01</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>Reset01</servlet-name>
+        <url-pattern>/Reset01</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>Reset01</servlet-name>
+        <url-pattern>/WrappedReset01</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>Resources01</servlet-name>
+        <url-pattern>/Resources01</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>Resources01</servlet-name>
+        <url-pattern>/WrappedResources01</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>Resources02</servlet-name>
+        <url-pattern>/Resources02</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>Resources02</servlet-name>
+        <url-pattern>/WrappedResources02</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>Resources03</servlet-name>
+        <url-pattern>/Resources03</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>Resources03</servlet-name>
+        <url-pattern>/WrappedResources03</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>Resources04</servlet-name>
+        <url-pattern>/Resources04</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>Resources04</servlet-name>
+        <url-pattern>/WrappedResources04</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>Resources05</servlet-name>
+        <url-pattern>/Resources05</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>Resources05</servlet-name>
+        <url-pattern>/WrappedResources05</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>Resources06</servlet-name>
+        <url-pattern>/Resources06</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>Resources06</servlet-name>
+        <url-pattern>/WrappedResources06</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>ResponseWrap01</servlet-name>
+        <url-pattern>/ResponseWrap01</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>ResponseWrap01a</servlet-name>
+        <url-pattern>/ResponseWrap01a</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>ResponseWrap01c</servlet-name>
+        <url-pattern>/ResponseWrap01c</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>Session01</servlet-name>
+        <url-pattern>/Session01</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>Session01</servlet-name>
+        <url-pattern>/WrappedSession01</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>Session02</servlet-name>
+        <url-pattern>/Session02</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>Session02</servlet-name>
+        <url-pattern>/WrappedSession02</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>Session03</servlet-name>
+        <url-pattern>/Session03</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>Session03</servlet-name>
+        <url-pattern>/WrappedSession03</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>Session04</servlet-name>
+        <url-pattern>/Session04</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>Session04</servlet-name>
+        <url-pattern>/WrappedSession04</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>Session05</servlet-name>
+        <url-pattern>/Session05</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>Session05</servlet-name>
+        <url-pattern>/WrappedSession05</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>Session06</servlet-name>
+        <url-pattern>/Session06</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>Session06</servlet-name>
+        <url-pattern>/WrappedSession06</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>SetBufferSize01</servlet-name>
+        <url-pattern>/SetBufferSize01</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>SetBufferSize01</servlet-name>
+        <url-pattern>/WrappedSetBufferSize01</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>SetLocale01</servlet-name>
+        <url-pattern>/SetLocale01</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>SetLocale01</servlet-name>
+        <url-pattern>/WrappedSetLocale01</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>Xerces00</servlet-name>
+        <url-pattern>/Xerces00</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>Xerces00</servlet-name>
+        <url-pattern>/WrappedXerces00</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>Xerces01</servlet-name>
+        <url-pattern>/Xerces01</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>Xerces01</servlet-name>
+        <url-pattern>/WrappedXerces01</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>Xerces02</servlet-name>
+        <url-pattern>/Xerces02</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>Xerces02</servlet-name>
+        <url-pattern>/WrappedXerces02</url-pattern>
+    </servlet-mapping>
+
+
+    <!-- ========== Session Configuration ================================= -->
+
+    <session-config>
+        <session-timeout>5</session-timeout>
+    </session-config>
+
+
+    <!-- ========== Error Page Mappings =================================== -->
+
+    <error-page>
+        <error-code>412</error-code>  <!-- SC_PRECONDITION_FAILED -->
+        <location>/ErrorPage02</location>
+    </error-page>
+
+    <error-page>
+        <exception-type>org.apache.tester.TesterException</exception-type>
+        <location>/ErrorPage04</location>
+    </error-page>
+
+    <error-page>
+        <exception-type>java.lang.ArithmeticException</exception-type>
+        <location>/ErrorPage06</location>
+    </error-page>
+
+    <error-page>
+        <exception-type>java.lang.ArrayIndexOutOfBoundsException</exception-type>
+        <location>/ErrorPage06.jsp</location>
+    </error-page>
+
+    <error-page>
+        <exception-type>java.lang.NumberFormatException</exception-type>
+        <location>/ErrorPage06.html</location>
+    </error-page>
+
+
+    <!-- ========== Security Constraints ================================== -->
+
+    <security-constraint>
+        <web-resource-collection>
+            <web-resource-name>General Protected Area</web-resource-name>
+            <url-pattern>/protected/*</url-pattern>
+        </web-resource-collection>
+        <auth-constraint>
+            <role-name>tomcat</role-name>
+        </auth-constraint>
+    </security-constraint>
+
+    <security-constraint>
+        <web-resource-collection>
+            <web-resource-name>All Users Allowed Area</web-resource-name>
+            <url-pattern>/allowed/*</url-pattern>
+        </web-resource-collection>
+        <auth-constraint>
+            <role-name>*</role-name>
+        </auth-constraint>
+    </security-constraint>
+
+    <security-constraint>
+        <web-resource-collection>
+            <web-resource-name>No Users Allowed Area</web-resource-name>
+            <url-pattern>/disallowed/*</url-pattern>
+        </web-resource-collection>
+        <auth-constraint>
+        </auth-constraint>
+    </security-constraint>
+    <security-constraint>
+        <web-resource-collection>
+            <web-resource-name>Really No Users Allowed Area</web-resource-name>
+            <url-pattern>/disallowed/private/*</url-pattern>
+        </web-resource-collection>
+        <auth-constraint>
+        </auth-constraint>
+    </security-constraint>
+    <security-constraint>
+        <web-resource-collection>
+            <web-resource-name>Really No Users Allowed Area</web-resource-name>
+            <url-pattern>/disallowed/private/*</url-pattern>
+        </web-resource-collection>
+        <auth-constraint>
+            <role-name>*</role-name>
+        </auth-constraint>
+    </security-constraint>
+
+    <security-constraint>
+        <web-resource-collection>
+            <web-resource-name>All Users Allowed Area</web-resource-name>
+            <url-pattern>/allowed/public/*</url-pattern>
+        </web-resource-collection>
+        <auth-constraint>
+            <role-name>*</role-name>
+        </auth-constraint>
+    </security-constraint>
+    <security-constraint>
+        <web-resource-collection>
+            <web-resource-name>All Users Allowed Area</web-resource-name>
+            <url-pattern>/allowed/public/*</url-pattern>
+        </web-resource-collection>
+    </security-constraint>
+    <security-constraint>
+        <web-resource-collection>
+            <web-resource-name>All Users Allowed Area</web-resource-name>
+            <url-pattern>/allowed/private/*</url-pattern>
+        </web-resource-collection>
+        <auth-constraint>
+            <role-name>*</role-name>
+        </auth-constraint>
+    </security-constraint>
+    <security-constraint>
+        <web-resource-collection>
+            <web-resource-name>All Users Allowed Area</web-resource-name>
+            <url-pattern>/allowed/private/*</url-pattern>
+        </web-resource-collection>
+        <auth-constraint>
+        </auth-constraint>
+    </security-constraint>
+
+    <login-config>
+        <auth-method>BASIC</auth-method>
+        <realm-name>Authentication Servlet</realm-name>
+    </login-config>
+
+    <security-role>
+        <description>Security role we are testing for</description>
+        <role-name>tomcat</role-name>
+    </security-role>
+
+
+    <!-- ========== Environment Entries =================================== -->
+
+    <env-entry>
+        <env-entry-name>booleanEntry</env-entry-name>
+        <env-entry-value>true</env-entry-value>
+        <env-entry-type>java.lang.Boolean</env-entry-type>
+    </env-entry>
+
+    <env-entry>
+        <env-entry-name>byteEntry</env-entry-name>
+        <env-entry-value>123</env-entry-value>
+        <env-entry-type>java.lang.Byte</env-entry-type>
+    </env-entry>
+
+    <env-entry>
+        <env-entry-name>doubleEntry</env-entry-name>
+        <env-entry-value>123.45</env-entry-value>
+        <env-entry-type>java.lang.Double</env-entry-type>
+    </env-entry>
+
+    <env-entry>
+        <env-entry-name>floatEntry</env-entry-name>
+        <env-entry-value>54.32</env-entry-value>
+        <env-entry-type>java.lang.Float</env-entry-type>
+    </env-entry>
+
+    <env-entry>
+        <env-entry-name>integerEntry</env-entry-name>
+        <env-entry-value>12345</env-entry-value>
+        <env-entry-type>java.lang.Integer</env-entry-type>
+    </env-entry>
+
+    <env-entry>
+        <env-entry-name>longEntry</env-entry-name>
+        <env-entry-value>54321</env-entry-value>
+        <env-entry-type>java.lang.Long</env-entry-type>
+    </env-entry>
+
+    <env-entry>
+        <env-entry-name>stringEntry</env-entry-name>
+        <env-entry-value>String Value</env-entry-value>
+        <env-entry-type>java.lang.String</env-entry-type>
+    </env-entry>
+
+    <env-entry>
+        <env-entry-name>nested/nestedEntry</env-entry-name>
+        <env-entry-value>Nested Value</env-entry-value>
+        <env-entry-type>java.lang.String</env-entry-type>
+    </env-entry>
+
+</web-app>

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/WrappedFilterResponse02.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/WrappedFilterResponse02.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/WrappedFilterResponse02.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1 @@
+<%@ page contentType="text/plain" %>FilterResponse02 PASSED

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/WrappedFilterResponse03.txt
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/WrappedFilterResponse03.txt	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/WrappedFilterResponse03.txt	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1 @@
+FilterResponse03 PASSED

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/Xerces00.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/Xerces00.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/Xerces00.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,8 @@
+<!-- This File is generated automatically by jsp2XML converter tool --> 
+<!-- Written By Ramesh Mandava/Santosh Singh -->
+<jsp:root
+xmlns:jsp="http://java.sun.com/JSP/Page" version="1.2"
+><jsp:directive.page contentType="text/plain"
+/><jsp:text><![CDATA[Xerces00 PASSED]]></jsp:text>
+</jsp:root>
+

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/Xerces01.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/Xerces01.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/Xerces01.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<personnel>
+
+  <person id="Big.Boss">
+    <name><family>Boss</family> <given>Big</given></name>
+    <email>chief at foo.com</email>
+    <link subordinates="one.worker two.worker three.worker four.worker five.worker"/>
+  </person>
+
+  <person id="one.worker">
+    <name><family>Worker</family> <given>One</given></name>
+    <email>one at foo.com</email>
+    <link manager="Big.Boss"/>
+  </person>
+
+  <person id="two.worker">
+    <name><family>Worker</family> <given>Two</given></name>
+    <email>two at foo.com</email>
+    <link manager="Big.Boss"/>
+  </person>
+
+  <person id="three.worker">
+    <name><family>Worker</family> <given>Three</given></name>
+    <email>three at foo.com</email>
+    <link manager="Big.Boss"/>
+  </person>
+
+  <person id="four.worker">
+    <name><family>Worker</family> <given>Four</given></name>
+    <email>four at foo.com</email>
+    <link manager="Big.Boss"/>
+  </person>
+
+  <person id="five.worker">
+    <name><family>Worker</family> <given>Five</given></name>
+    <email>five at foo.com</email>
+    <link manager="Big.Boss"/>
+  </person>
+
+</personnel>

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/Xerces02.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/Xerces02.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/Xerces02.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1 @@
+<%@ page contentType="text/plain"%>Xerces02 PASSED

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/Encoding01.txt
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/Encoding01.txt	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/Encoding01.txt	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,5 @@
+
+
+
+<h2>Test Character</h2>
+<h2>‹› Unicode = 9b5a</hr>

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/Encoding02.txt
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/Encoding02.txt	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/Encoding02.txt	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,9 @@
+<html>
+<head>
+<title>Encoding02.jsp</title>
+</head>
+<body bgcolor="white">
+This is legal in the spec:<br>
+Joe said %> foo.
+</body>
+</html>

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/Encoding03.txt
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/Encoding03.txt	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/Encoding03.txt	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,9 @@
+<html>
+<head>
+<title>Encoding03.jsp</title>
+</head>
+<body bgcolor="white">
+This is not recognized as a delimiter either:<br>
+Joe said %\> bar.
+</body>
+</html>

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/Golden01.txt
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/Golden01.txt	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/Golden01.txt	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,3 @@
+This is the
+first golden file
+to be tested.

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/Include06.txt
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/Include06.txt	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/Include06.txt	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,5 @@
+==========
+Include06a output
+==========
+Include06b.jsp output
+==========

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/Include07.txt
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/Include07.txt	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/Include07.txt	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,4 @@
+Output from Include07
+Output from Include07b
+Output from Include07c
+Output from Include07

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/JspDoc01.txt
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/JspDoc01.txt	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/JspDoc01.txt	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1 @@
+<a>text<b/></a><a>text<b></b></a><c><d>text</d></c><c><d>text</d></c><e><f/>text<f/></e><e><f></f>text<f></f></e>

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/JspDoc02.txt
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/JspDoc02.txt	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/JspDoc02.txt	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,9 @@
+<html><head><title>Example JSP in XML format</title></head><body>
+This is the output of a simple JSP using XML format. 
+<br/><div>Use a jsp:scriptlet to loop from 1 to 10: </div>1, 2, 3, 4, 5, 6, 7, 8, 9, 10
+  <br><br>
+<div align="left">
+  Use a jsp:expression to write something: 
+  foo</div>
+  <p>This sentence is enclosed in a jsp:text element.</p>
+</body></html>

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/JspInclude01.txt
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/JspInclude01.txt	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/JspInclude01.txt	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,5 @@
+This is before the include
+This is the include
+
+This is after the include
+

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/JspInclude01a.txt
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/JspInclude01a.txt	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/JspInclude01a.txt	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,6 @@
+This is before the include
+Include00a PASSEDSessionListener01: sessionCreated()
+SessionListener02: sessionCreated()
+
+This is after the include
+

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/JspInclude02.txt
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/JspInclude02.txt	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/JspInclude02.txt	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,5 @@
+This is before the include
+This is the include
+
+This is after the include
+

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/JspInclude02a.txt
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/JspInclude02a.txt	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/JspInclude02a.txt	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,6 @@
+This is before the include
+Include00a PASSEDSessionListener01: sessionCreated()
+SessionListener02: sessionCreated()
+
+This is after the include
+

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/Property01.txt
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/Property01.txt	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/Property01.txt	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,10 @@
+<html>
+<head>
+<title>Property01.jsp - Positive PropertyEditor Test</title>
+</head>
+<body bgcolor="white">
+
+
+Date property is '2001-07-25'.
+</body>
+</html>

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/SSIConditional01.txt
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/SSIConditional01.txt	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/SSIConditional01.txt	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,6 @@
+Before if block.
+
+
+test = value1
+
+After if block.

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/SSIConditional02.txt
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/SSIConditional02.txt	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/SSIConditional02.txt	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,6 @@
+Before if block.
+
+
+test = value2
+
+After if block.

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/SSIConditional03.txt
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/SSIConditional03.txt	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/SSIConditional03.txt	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,6 @@
+Before if block.
+
+
+test = "unquoted multi-word value"
+
+After if block.

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/SSIConditional04.txt
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/SSIConditional04.txt	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/SSIConditional04.txt	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,6 @@
+
+
+
+
+true
+

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/SSIConditional05.txt
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/SSIConditional05.txt	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/SSIConditional05.txt	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,6 @@
+
+
+
+
+false
+

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/SSIConditional06.txt
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/SSIConditional06.txt	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/SSIConditional06.txt	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,8 @@
+
+
+
+
+
+not one
+
+

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/SSIConditional07.txt
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/SSIConditional07.txt	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/SSIConditional07.txt	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,8 @@
+
+
+
+
+
+not two
+
+

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/SSIConditional08.txt
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/SSIConditional08.txt	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/SSIConditional08.txt	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,5 @@
+
+
+
+
+two

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/SSIConfig01.txt
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/SSIConfig01.txt	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/SSIConfig01.txt	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,2 @@
+
+errmsg:Sorry this command won't work.

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/SSIConfig03.txt
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/SSIConfig03.txt	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/SSIConfig03.txt	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,4 @@
+
+34
+
+   1k

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/SSIExecCGI.txt
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/SSIExecCGI.txt	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/SSIExecCGI.txt	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,41 @@
+<html> 
+  <head> 
+ <title>exec command  test examples </title> 
+ </head> 
+ <body>
+
+ These are the days of the week:<p>Monday Tuesday Wednesday Thursday Friday Saturday Sunday<br>
+
+ <FONT SIZE=+2>If you add one to your number, the result is <B>103</B><P>If you add 5 to that, the result is <B>108</B></FONT><br>
+
+ <P>On Wednesday, we have to mop<P>On Friday, we have to wash windows<P>On Monday, we have to vacuum<br>
+
+ Congratulations! Your married name would be jane smith.<br>
+
+ These are the days of the week:<P>Monday Tuesday Wednesday Thursday Friday Saturday Sunday<br>
+
+ <P>Starting countdown...10... 9... 8... 7... 6... 5... 4... 3... 2... 1... KABOOM!<br>
+
+ You ate spinach, so you get dessert!<br>
+
+ No spinach, no dessert!<br>
+
+ <P>You entered 2 with an exponent of 4<P>2 raised to the 4 power is 16.<br>
+
+ <P>Starting countdown...10... 9... 8... 7... 6... 5... 4... 3... 2... 1... KABOOM!<br>
+
+ The first day of the week is Sunday<P>The third day of the week is Tuesday<br>
+
+ 	<Title> Hello World! </Title>
+	<H1>	Hello World! </H1>
+<br>
+
+ You ate spinach, so you get dessert!
+<br>
+
+ Your number incremented by 1 is 8<BR>Your number, incremented again by 1, is now 9. If we store that operation, its value is also 9.<HR>Let's start over, with your original number 7<BR>Again, your number incremented by 1 is 8<BR>Now we store the value of your number in a second variable, which is now equal to 8, and then we increment your number again. It's now 9.<br>
+
+ The numbers you entered were:<LI>289<P>The square roots of those numbers are: <LI>17<br>
+
+ </body> 
+ </html>

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/SSIFsize02.txt
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/SSIFsize02.txt	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/SSIFsize02.txt	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1 @@
+   1k

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/SSIInclude01.txt
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/SSIInclude01.txt	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/SSIInclude01.txt	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1 @@
+

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/SSIInclude02.txt
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/SSIInclude02.txt	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/SSIInclude02.txt	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1 @@
+This is Content of "includeme.txt"

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/SSIInclude03.txt
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/SSIInclude03.txt	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/SSIInclude03.txt	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,4 @@
+This is Content of "includeme.txt"
+This is Content of "includeme.txt"
+
+This is Content of "includeme.txt"

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/SSIVarSub01.txt
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/SSIVarSub01.txt	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/SSIVarSub01.txt	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,3 @@
+
+/SSIVarSub01.shtml
+

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/SSIVarSub02.txt
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/SSIVarSub02.txt	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/SSIVarSub02.txt	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,4 @@
+
+
+value of test
+

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/SSIVarSub03.txt
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/SSIVarSub03.txt	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/SSIVarSub03.txt	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,5 @@
+
+
+
+value of test value of test2
+

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/SSIVarSub04.txt
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/SSIVarSub04.txt	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/SSIVarSub04.txt	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,5 @@
+
+
+
+value of test|value of test2
+

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/SSIVarSub05.txt
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/SSIVarSub05.txt	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/SSIVarSub05.txt	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,3 @@
+
+
+value of test\${test2}

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/Session05.txt
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/Session05.txt	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/Session05.txt	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,10 @@
+SessionListener01: sessionCreated()
+SessionListener02: sessionCreated()
+SessionListener01: attributeAdded(attribute1,value1)
+SessionListener02: attributeAdded(attribute1,value1)
+SessionListener01: attributeReplaced(attribute1,value1)
+SessionListener02: attributeReplaced(attribute1,value1)
+SessionListener01: attributeRemoved(attribute1,value2)
+SessionListener02: attributeRemoved(attribute1,value2)
+SessionListener02: sessionDestroyed()
+SessionListener01: sessionDestroyed()

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/WrappedSession05.txt
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/WrappedSession05.txt	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/WrappedSession05.txt	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,13 @@
+TesterHttpServletRequestWrapper.getSession(b)
+SessionListener01: sessionCreated()
+SessionListener02: sessionCreated()
+SessionListener01: attributeAdded(attribute1,value1)
+SessionListener02: attributeAdded(attribute1,value1)
+SessionListener01: attributeReplaced(attribute1,value1)
+SessionListener02: attributeReplaced(attribute1,value1)
+SessionListener01: attributeRemoved(attribute1,value2)
+SessionListener02: attributeRemoved(attribute1,value2)
+SessionListener02: sessionDestroyed()
+SessionListener01: sessionDestroyed()
+TesterHttpServletResponseWrapper.setContentType()
+TesterHttpServletResponseWrapper.getWriter()

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/array.txt
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/array.txt	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/array.txt	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1 @@
+These are the days of the week:<p>Monday Tuesday Wednesday Thursday Friday Saturday Sunday

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/binary.txt
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/binary.txt	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/binary.txt	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1 @@
+<FONT SIZE=+2>If you add one to your number, the result is <B>103</B><P>If you add 5 to that, the result is <B>108</B></FONT>

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/concat.txt
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/concat.txt	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/concat.txt	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1 @@
+Congratulations! Your married name would be jane smith.

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/days.txt
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/days.txt	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/days.txt	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1 @@
+These are the days of the week:<P>Monday Tuesday Wednesday Thursday Friday Saturday Sunday

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/dowhile.txt
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/dowhile.txt	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/dowhile.txt	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1 @@
+<P>Starting countdown...10... 9... 8... 7... 6... 5... 4... 3... 2... 1... KABOOM!

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/else.txt
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/else.txt	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/else.txt	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1 @@
+You ate spinach, so you get dessert!

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/elsif.txt
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/elsif.txt	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/elsif.txt	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1 @@
+No spinach, no dessert!

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/exponents.txt
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/exponents.txt	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/exponents.txt	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1 @@
+<P>You entered 2 with an exponent of 4<P>2 raised to the 4 power is 16.

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/getday.txt
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/getday.txt	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/getday.txt	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1 @@
+The first day of the week is Sunday<P>The third day of the week is Tuesday

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/helloperl.txt
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/helloperl.txt	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/helloperl.txt	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,2 @@
+	<Title> Hello World! </Title>
+	<H1>	Hello World! </H1>

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/increment.txt
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/increment.txt	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/increment.txt	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1 @@
+Your number incremented by 1 is 8<BR>Your number, incremented again by 1, is now 9. If we store that operation, its value is also 9.<HR>Let's start over, with your original number 7<BR>Again, your number incremented by 1 is 8<BR>Now we store the value of your number in a second variable, which is now equal to 8, and then we increment your number again. It's now 9.

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/modifyall.txt
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/modifyall.txt	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/modifyall.txt	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1 @@
+The numbers you entered were:<LI>289<P>The square roots of those numbers are: <LI>17

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/preference.txt
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/preference.txt	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/golden/preference.txt	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1 @@
+div is 11, parens is 5, subadd is 11 and parens_subadd is 1

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/includeme.shtml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/includeme.shtml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/includeme.shtml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1 @@
+This is Content of "includeme.shtml"

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/includeme.txt
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/includeme.txt	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/includeme.txt	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1 @@
+This is Content of "includeme.txt"

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/index.shtml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/index.shtml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/index.shtml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,139 @@
+<html> 
+ <head> 
+ <title>Config command examples </title>
+ </head> 
+ <body bgcolor=white> 
+
+
+Setting errormsg using: &lt;!--#config errmsg="..." --&gt; <br>
+<!--#config errmsg="errormsg: Sorry this command won't work." --> 
+
+Trying to access non-existent "foo.shtml" using  
+&lt;!--#fsize file="foo.shtml" --&gt;
+<br>
+
+<!--#fsize file="foo.shtml" -->
+<br>
+<br>
+
+Using &lt;!--#config sizefmt="bytes" --&gt;
+<br>
+              This file ( index.shtml::size-> 2665) is 
+ <!--#config sizefmt="bytes" --> 
+ <!--#fsize file="index.shtml" -->
+              bytes in size. 
+
+<br>
+<br>
+  Setting sizefmt to abbrev using : &lt;!--#config sizefmt="abbrev" --&gt;
+<br>
+
+
+<!--#config sizefmt="abbrev" -->
+
+Size of file "index.shtml ( size->2665)" using sizefmt=abbrev ->
+<!--#fsize   file="index.shtml" -->
+
+<br> <br>
+Size of file "saveindex.shtml(size->464)" using  : &lt;!--#fsize file="saveindex.shtml" --&gt;  ->
+<!--#fsize   file="saveindex.shtml" -->
+<br><br>
+
+Size of file "check1.shtml(size->1000)" using  : &lt;!--#fsize file="check1.shtml" --&gt;  ->
+<!--#fsize   file="check1.shtml" -->
+<br><br>
+
+Size of file "check2.html(size->1001)" using  : &lt;!--#fsize file="check2.html" --&gt;  ->
+<!--#fsize   file="check2.html" -->
+<br><br>
+
+Size of file "check3.shtml(size->1499)" using  : &lt;!--#fsize file="check3.shtml" --&gt;  ->
+<!--#fsize   file="check3.shtml" -->
+<br><br>
+
+Size of file "check4.shtml(size->1500)" using  : &lt;!--#fsize file="check4.shtml" --&gt;  ->
+<!--#fsize   file="check4.shtml" -->
+<br><br>
+
+Size of file "check5.shtml(size->1501)" using  : &lt;!--#fsize file="check5.shtml" --&gt;  ->
+<!--#fsize   file="check5.shtml" -->
+<br><br>
+
+Size of file "checkme ( size->1535)" using : &lt;!--#fsize file"checkme" --&gt; -> 
+<!--#fsize   file="checkme" -->
+<br><br>
+
+Size of file "check5.html(size->1536)" using  : &lt;!--#fsize file="check5.html" --&gt;  ->
+<!--#fsize   file="check5.html" -->
+<br><br>
+
+Size of file "check55.html(size->1537)" using  : &lt;!--#fsize file="check55.html" --&gt;  ->
+<!--#fsize   file="check55.html" -->
+<br><br>
+
+Size of file "check555.html(size->1538)" using  : &lt;!--#fsize file="check555.html" --&gt;  ->
+<!--#fsize   file="check555.html" -->
+<br><br>
+
+Size of file "check5555.html(size->1539)" using  : &lt;!--#fsize file="check5555.html" --&gt;  ->
+<!--#fsize   file="check5555.html" -->
+<br><br>
+
+Size of file "check6.shtml(size->1988)" using  : &lt;!--#fsize file="check6.shtml" --&gt;  ->
+<!--#fsize   file="check6.shtml" -->
+<br><br>
+
+Size of file "check7.shtml(size->1999)" using  : &lt;!--#fsize file="check7.shtml" --&gt;  ->
+<!--#fsize   file="check7.shtml" -->
+<br><br>
+ <p> 
+
+
+
+
+ <FONT SIZE=+2 Color=blue> timefmt Tests : </FONT>
+
+<br> <br>
+  Using &lt;!--#config timefmt="%A" --&gt; 
+          &lt;!--#echo var="DATE_LOCAL" --&gt;
+<br>
+  Day ->  <!--#config timefmt="%A" -->
+              <!--#echo var="DATE_LOCAL" -->, 
+<br> <br>
+  Using &lt;!--#config timefmt="%d" --&gt;<br>
+          &lt;!--#echo var="DATE_LOCAL" --&gt; 
+  <br>
+  Day of Month -> <!--#config timefmt="%d" -->
+              <!--#echo var="DATE_LOCAL" --> 
+
+ <br> <br>
+  Using &lt;!--#config timefmt="%B" --&gt;<br>
+          &lt;!--#echo var="DATE_LOCAL" --&gt; 
+  <br>
+  Month(full) -> <!--#config timefmt="%B" --> 
+		<!--#echo var="DATE_LOCAL" --> 
+
+  <br> <br>
+  Using &lt;!--#config timefmt="%b" --&gt;<br>
+          &lt;!--#echo var="DATE_LOCAL" --&gt; 
+  <br>
+  Month(abbreviated) -> <!--#config timefmt="%b" --> 
+			<!--#echo var="DATE_LOCAL" --> 
+
+  <br> <br>
+  Using &lt;!--#config timefmt="%Y" --&gt;<br>
+          &lt;!--#echo var="DATE_LOCAL" --&gt; 
+  <br>
+   Year ->  <!--#config timefmt="%Y"
+              --> <!--#echo var="DATE_LOCAL" -->. 
+
+  <br> <br>
+  Using &lt;!--#config timefmt="%W" --&gt;<br>
+          &lt;!--#echo var="DATE_LOCAL" --&gt; 
+
+  <br>
+  Week number of year as a decimal  number: <!--#config timefmt="%W" --> 
+					<!--#echo var="DATE_LOCAL" -->. 
+
+</body> 
+</html> 

Added: branches/tomcat5.5/upstream/5.5.20/container/tester/web/ssidir/includeme.txt
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/tester/web/ssidir/includeme.txt	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/tester/web/ssidir/includeme.txt	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1 @@
+This is Content of "includeme.txt"

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/ROOT/WEB-INF/web.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/ROOT/WEB-INF/web.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/ROOT/WEB-INF/web.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!--
+  Copyright 2004 The Apache Software Foundation
+
+  Licensed 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.
+-->
+
+<web-app 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-app_2_4.xsd"
+    version="2.4">
+
+  <display-name>Welcome to Tomcat</display-name>
+  <description>
+     Welcome to Tomcat
+  </description>
+
+</web-app>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/ROOT/admin/index.html
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/ROOT/admin/index.html	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/ROOT/admin/index.html	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,14 @@
+<!doctype html public "-//w3c//dtd html 4.0 transitional//en" "http://www.w3.org/TR/REC-html40/strict.dtd">
+<html>
+    <head>
+    <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+    <title>Administration</title>
+</head>
+
+<body>
+
+Tomcat's administration web application is no longer installed by default. Download and install 
+the "admin" package to use it.
+
+</body>
+</html>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/ROOT/asf-logo-wide.gif
===================================================================
(Binary files differ)


Property changes on: branches/tomcat5.5/upstream/5.5.20/container/webapps/ROOT/asf-logo-wide.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/ROOT/build.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/ROOT/build.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/ROOT/build.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,76 @@
+<project name="ROOT" default="build-main" basedir=".">
+
+
+  <!-- ===================== Initialize Property Values =================== -->
+
+  <!-- See "build.properties.sample" in the top level directory for all     -->
+  <!-- property values you must customize for successful building!!!        -->
+  <property file="build.properties"/>
+  <property file="../build.properties"/>
+  <property file="../../build.properties"/>
+  <property file="${user.home}/build.properties"/>
+
+  <property name="build.compiler"  value="modern"/>
+  <property name="webapps.build"   value="../build"/>
+  <property name="webapps.dist"    value="../dist"/>
+  <property name="webapp.name"     value="ROOT"/>
+
+
+  <!-- =================== BUILD: Create Directories ====================== -->
+  <target name="build-prepare">
+    <mkdir dir="${webapps.build}"/>
+    <mkdir dir="${webapps.build}/${webapp.name}"/>
+  </target>
+
+
+  <!-- ================ BUILD: Copy Static Files ========================== -->
+  <target name="build-static" depends="build-prepare">
+    <copy todir="${webapps.build}/${webapp.name}">
+      <fileset dir=".">
+        <exclude name="build.*"/>
+      </fileset>
+    </copy>
+  </target>
+
+
+  <!-- ================= BUILD: Compile Server Components ================= -->
+  <target name="build-main" depends="build-static"/>
+
+
+  <!-- ==================== BUILD: Rebuild Everything ===================== -->
+  <target name="all" depends="build-clean,build-main"
+   description="Clean and build ROOT webapp"/>
+
+
+  <!-- ======================= BUILD: Clean Directory ===================== -->
+  <target name="build-clean">
+    <delete dir="${webapps.build}/${webapp.name}"/>
+  </target>
+
+
+  <!-- ======================= DIST: Create Directories =================== -->
+  <target name="dist-prepare">
+    <mkdir dir="${webapps.dist}"/>
+  </target>
+
+
+  <!-- ======================= DIST: Create Distribution Files ============ -->
+  <target name="dist" depends="build-main,dist-prepare"
+   description="Create ROOT webapp binary distribution">
+      <jar   jarfile="${webapps.dist}/${webapp.name}.war"
+             basedir="${webapps.build}/${webapp.name}" includes="**"/>
+  </target>
+
+
+  <!-- ======================= DIST: Clean Directory ====================== -->
+  <target name="dist-clean">
+    <delete dir="${webapps.dist}/${webapp.name}"/>
+  </target>
+
+
+  <!-- ====================== Convenient Synonyms ========================= -->
+  <target name="clean" depends="build-clean,dist-clean"
+   description="Clean build and dist directories"/>
+
+
+</project>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/ROOT/favicon.ico
===================================================================
(Binary files differ)


Property changes on: branches/tomcat5.5/upstream/5.5.20/container/webapps/ROOT/favicon.ico
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/ROOT/index.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/ROOT/index.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/ROOT/index.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,218 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+   "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<%@ page session="false" %>
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+    <head>
+    <title><%= application.getServerInfo() %></title>
+    <style type="text/css">
+    /*<![CDATA[*/
+      body {
+          color: #000000;
+          background-color: #FFFFFF;
+	  font-family: Arial, "Times New Roman", Times, serif;
+          margin: 10px 0px;
+      }
+
+    img {
+       border: none;
+    }
+    
+    a:link, a:visited {
+        color: blue
+    }
+
+    th {
+        font-family: Verdana, "Times New Roman", Times, serif;
+        font-size: 110%;
+        font-weight: normal;
+        font-style: italic;
+        background: #D2A41C;
+        text-align: left;
+    }
+
+    td {
+        color: #000000;
+	font-family: Arial, Helvetica, sans-serif;
+    }
+    
+    td.menu {
+        background: #FFDC75;
+    }
+
+    .center {
+        text-align: center;
+    }
+
+    .code {
+        color: #000000;
+        font-family: "Courier New", Courier, monospace;
+        font-size: 110%;
+        margin-left: 2.5em;
+    }
+    
+     #banner {
+        margin-bottom: 12px;
+     }
+
+     p#congrats {
+         margin-top: 0;
+         font-weight: bold;
+         text-align: center;
+     }
+
+     p#footer {
+         text-align: right;
+         font-size: 80%;
+     }
+     /*]]>*/
+   </style>
+</head>
+
+<body>
+
+<!-- Header -->
+<table id="banner" width="100%">
+    <tr>
+      <td align="left" style="width:130px">
+        <a href="http://tomcat.apache.org/">
+	  <img src="tomcat.gif" height="92" width="130" alt="The Mighty Tomcat - MEOW!"/>
+	</a>
+      </td>
+      <td align="left" valign="top"><b><%= application.getServerInfo() %></b></td>
+      <td align="right">
+        <a href="http://jakarta.apache.org/">
+	  <img src="asf-logo-wide.gif" height="51" width="537" alt="The Apache Software Foundation"/>
+	</a>
+       </td>
+     </tr>
+</table>
+
+<table>
+    <tr>
+
+        <!-- Table of Contents -->
+        <td valign="top">
+            <table width="100%" border="1" cellspacing="0" cellpadding="3">
+                <tr>
+		  <th>Administration</th>
+                </tr>
+                <tr>
+		  <td class="menu">
+		    <a href="manager/status">Status</a><br/>
+                    <a href="admin">Tomcat&nbsp;Administration</a><br/>
+                    <a href="manager/html">Tomcat&nbsp;Manager</a><br/>
+                    &nbsp;
+                  </td>
+                </tr>
+            </table>
+
+	    <br />
+            <table width="100%" border="1" cellspacing="0" cellpadding="3">
+                <tr>
+		  <th>Documentation</th>
+                </tr>
+                <tr>
+                  <td class="menu">
+                    <a href="RELEASE-NOTES.txt">Release&nbsp;Notes</a><br/>
+                    <a href="tomcat-docs/changelog.html">Change&nbsp;Log</a><br/>
+                    <a href="tomcat-docs">Tomcat&nbsp;Documentation</a><br/>                        &nbsp;
+                    &nbsp;
+		    </td>
+                </tr>
+            </table>
+	    
+            <br/>
+            <table width="100%" border="1" cellspacing="0" cellpadding="3">
+                <tr>
+                  <th>Tomcat Online</th>
+                </tr>
+                <tr>
+                  <td class="menu">
+                    <a href="http://tomcat.apache.org/">Home&nbsp;Page</a><br/>
+		    <a href="http://tomcat.apache.org/faq/">FAQ</a><br/>
+                    <a href="http://tomcat.apache.org/bugreport.html">Bug&nbsp;Database</a><br/>
+                    <a href="http://issues.apache.org/bugzilla/buglist.cgi?bug_status=UNCONFIRMED&amp;bug_status=NEW&amp;bug_status=ASSIGNED&amp;bug_status=REOPENED&amp;bug_status=RESOLVED&amp;resolution=LATER&amp;resolution=REMIND&amp;resolution=---&amp;bugidtype=include&amp;product=Tomcat+5&amp;cmdtype=doit&amp;order=Importance">Open Bugs</a><br/>
+                    <a href="http://mail-archives.apache.org/mod_mbox/tomcat-users/">Users&nbsp;Mailing&nbsp;List</a><br/>
+                    <a href="http://mail-archives.apache.org/mod_mbox/tomcat-dev/">Developers&nbsp;Mailing&nbsp;List</a><br/>
+                    <a href="irc://irc.freenode.net/#tomcat">IRC</a><br/>
+		    &nbsp;
+                  </td>
+                </tr>
+            </table>
+	    
+            <br/>
+            <table width="100%" border="1" cellspacing="0" cellpadding="3">
+                <tr>
+                  <th>Examples</th>
+                </tr>
+                <tr>
+                  <td class="menu">
+                    <a href="jsp-examples/">JSP&nbsp;Examples</a><br/>
+                    <a href="servlets-examples/">Servlet&nbsp;Examples</a><br/>
+                    <a href="webdav/">WebDAV&nbsp;capabilities</a><br/>
+     		    &nbsp;
+                  </td>
+                </tr>
+            </table>
+	    
+            <br/>
+            <table width="100%" border="1" cellspacing="0" cellpadding="3">
+                <tr>
+		  <th>Miscellaneous</th>
+                </tr>
+                <tr>
+                  <td class="menu">
+                    <a href="http://java.sun.com/products/jsp">Sun's&nbsp;Java&nbsp;Server&nbsp;Pages&nbsp;Site</a><br/>
+                    <a href="http://java.sun.com/products/servlet">Sun's&nbsp;Servlet&nbsp;Site</a><br/>
+    		    &nbsp;
+                  </td>
+                </tr>
+            </table>
+        </td>
+
+        <td style="width:20px">&nbsp;</td>
+	
+        <!-- Body -->
+        <td align="left" valign="top">
+          <p id="congrats">If you're seeing this page via a web browser, it means you've setup Tomcat successfully. Congratulations!</p>
+ 
+          <p>As you may have guessed by now, this is the default Tomcat home page. It can be found on the local filesystem at:</p>
+          <p class="code">$CATALINA_HOME/webapps/ROOT/index.jsp</p>
+	  
+          <p>where "$CATALINA_HOME" is the root of the Tomcat installation directory. If you're seeing this page, and you don't think you should be, then either you're either a user who has arrived at new installation of Tomcat, or you're an administrator who hasn't got his/her setup quite right. Providing the latter is the case, please refer to the <a href="tomcat-docs">Tomcat Documentation</a> for more detailed setup and administration information than is found in the INSTALL file.</p>
+
+            <p><b>NOTE:</b> This page is precompiled. If you change it, this page will not change since
+                  it was compiled into a servlet at build time.
+                  (See <tt>$CATALINA_HOME/webapps/ROOT/WEB-INF/web.xml</tt> as to how it was mapped.)
+            </p>
+
+            <p><b>NOTE: For security reasons, using the administration webapp
+            is restricted to users with role "admin". The manager webapp
+            is restricted to users with role "manager".</b>
+            Users are defined in <code>$CATALINA_HOME/conf/tomcat-users.xml</code>.</p>
+
+            <p>Included with this release are a host of sample Servlets and JSPs (with associated source code), extensive documentation (including the Servlet 2.4 and JSP 2.0 API JavaDoc), and an introductory guide to developing web applications.</p>
+
+            <p>Tomcat mailing lists are available at the Tomcat project web site:</p>
+
+           <ul>
+               <li><b><a href="mailto:users at tomcat.apache.org">users at tomcat.apache.org</a></b> for general questions related to configuring and using Tomcat</li>
+               <li><b><a href="mailto:dev at tomcat.apache.org">dev at tomcat.apache.org</a></b> for developers working on Tomcat</li>
+           </ul>
+
+            <p>Thanks for using Tomcat!</p>
+
+            <p id="footer"><img src="tomcat-power.gif" width="77" height="80" alt="Powered by Tomcat"/><br/>
+	    &nbsp;
+
+	    Copyright &copy; 1999-2005 Apache Software Foundation<br/>
+            All Rights Reserved
+            </p>
+        </td>
+
+    </tr>
+</table>
+
+</body>
+</html>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/ROOT/tomcat-power.gif
===================================================================
(Binary files differ)


Property changes on: branches/tomcat5.5/upstream/5.5.20/container/webapps/ROOT/tomcat-power.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/ROOT/tomcat.gif
===================================================================
(Binary files differ)


Property changes on: branches/tomcat5.5/upstream/5.5.20/container/webapps/ROOT/tomcat.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/ActionTag.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/ActionTag.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/ActionTag.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,195 @@
+/*
+ * Copyright 2001,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.admin;
+
+
+import java.io.IOException;
+import java.net.URLEncoder;
+import java.util.ArrayList;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.jsp.JspException;
+import javax.servlet.jsp.JspWriter;
+import javax.servlet.jsp.PageContext;
+import javax.servlet.jsp.tagext.BodyTagSupport;
+import javax.servlet.jsp.tagext.Tag;
+
+
+/**
+ * <p>Nested tag that represents an individual "instant action".  This tag
+ * is valid <strong>only</strong> when nested within an ActoinsTag tag.
+ * This tag has the following user-settable attributes:</p>
+ * <ul>
+ * <li><strong>selected</strong> - Set to <code>true</code> if this action
+ *     should be selected when the control is initially displayed.</li>
+ * <li><strong>url</strong> - URL to which control should be transferred
+ *     (in the current frame or window) if this action is selected.</li>
+ * </ul>
+ *
+ * <p>In addition, the body content of this tag is used as the user-visible
+ * label for the action, so that it may be conveniently localized.</p>
+ *
+ * <strong>FIXME</strong> - Internationalize the exception messages!
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class ActionTag extends BodyTagSupport {
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The label that will be rendered for this action.
+     */
+    protected String label = null;
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * Should this action be selected when the control is initially displayed?
+     */
+    protected boolean selected = false;
+
+    public boolean getSelected() {
+        return (this.selected);
+    }
+
+    public void setSelected(boolean selected) {
+        this.selected = selected;
+    }
+
+    /**
+     * Should this action selection be disabled? 
+     * e.g. Action separators should be disabled.
+     */
+    protected boolean disabled = false;
+
+    public boolean getDisabled() {
+        return (this.disabled);
+    }
+
+    public void setDisabled(boolean disabled) {
+        this.disabled = disabled;
+    }
+
+    /**
+     * The URL to which control is transferred if this action is selected.
+     */
+    protected String url = null;
+
+    public String getUrl() {
+        return (this.url);
+    }
+
+    public void setUrl(String url) {
+        this.url = url;
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Process the start of this tag.
+     *
+     * @exception JspException if a JSP exception has occurred
+     */
+    public int doStartTag() throws JspException {
+
+        // Initialize the holder for our label text
+        this.label = null;
+
+        // Do no further processing for now
+        return (EVAL_BODY_TAG);
+
+    }
+
+
+    /**
+     * Process the body text of this tag (if any).
+     *
+     * @exception JspException if a JSP exception has occurred
+     */
+    public int doAfterBody() throws JspException {
+
+        String label = bodyContent.getString();
+        if (label != null) {
+            label = label.trim();
+            if (label.length() > 0)
+                this.label = label;
+        }
+        return (SKIP_BODY);
+
+    }
+
+
+    /**
+     * Record this action with our surrounding ActionsTag instance.
+     *
+     * @exception JspException if a processing error occurs
+     */
+    public int doEndTag() throws JspException {
+
+        // Find our parent ActionsTag instance
+        Tag parent = getParent();
+        while ((parent != null) && !(parent instanceof ActionsTag)) {
+            parent = parent.getParent();
+        }
+        if ((parent == null) || !(parent instanceof ActionsTag))
+            throw new JspException("Must be nested in an ActionsTag isntance");
+        ActionsTag actions = (ActionsTag) parent;
+
+        // Register the information for the action represented by
+        // this action
+        HttpServletRequest request =
+            (HttpServletRequest) pageContext.getRequest();
+        HttpServletResponse response =
+            (HttpServletResponse) pageContext.getResponse();
+        String path = null;
+        if ((url != null) && (url.startsWith("/"))) {
+            path = request.getContextPath() + url;
+        } else {
+            path = url;
+        }
+        actions.addAction(label, selected, disabled,
+                          response.encodeURL(path));
+
+        return (EVAL_PAGE);
+
+    }
+
+
+    /**
+     * Release all state information set by this tag.
+     */
+    public void release() {
+
+        this.label = null;
+        this.selected = false;
+        this.disabled = false;
+        this.url = null;
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/ActionsTag.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/ActionsTag.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/ActionsTag.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,279 @@
+/*
+ * Copyright 2001,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.admin;
+
+
+import java.io.IOException;
+import java.net.URLEncoder;
+import java.util.ArrayList;
+import javax.servlet.jsp.JspException;
+import javax.servlet.jsp.JspWriter;
+import javax.servlet.jsp.PageContext;
+import javax.servlet.jsp.tagext.BodyTagSupport;
+
+
+/**
+ * <p>JSP custom tag that renders an "instant actions" control.  To the user,
+ * it appears as an HTML &lt;select&gt; element (i.e. a combo box), with
+ * the behavior of selecting a new page for the current frame or window when
+ * a different option is selected, without requiring a submit action.
+ * This tag has the following user-settable attributes:</p>
+ * <ul>
+ * <li><strong>size</strong> - (Integer) number of rows that will be visible
+ *     to the user.  If not specified, one row will be visible.</li>
+ * <li><strong>style</strong> - The CSS style class to be applied to the
+ *     entire rendered output of the instant actions control, if any.</li>
+ * </ul>
+ *
+ * <strong>FIXME</strong> - Internationalize the exception messages!
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class ActionsTag extends BodyTagSupport {
+
+
+    // ----------------------------------------------------- Manifest Constants
+
+
+    /**
+     * Attribute name used to indicate that we have generated the JavaScript
+     * function already on the current page.  The value stored for this
+     * attribute is arbitrary - only its existence is relevant.
+     */
+    protected static final String FUNCTION_TAG =
+        "org.apache.webapp.admin.ActionsTag.FUNCTION_TAG";
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The set of labels for the Actions displayed by this control.
+     */
+    protected ArrayList labels = new ArrayList();
+
+
+    /**
+     * The set of "selected" flags for Actions displayed by this control.
+     */
+    protected ArrayList selecteds = new ArrayList();
+
+    /**
+     * The set of "disabled" flags for Actions displayed by this control.
+     */
+    protected ArrayList disableds = new ArrayList();
+
+    /**
+     * The set of URLs for the Actions displayed by this control.
+     */
+    protected ArrayList urls = new ArrayList();
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * The number of elements that will be displayed to the user.
+     */
+    protected int size = 1;
+
+    public int getSize() {
+        return (this.size);
+    }
+
+    public void setSize(int size) {
+        this.size = size;
+    }
+
+
+    /**
+     * The CSS style class to be applied to the entire rendered output
+     * of this "instant actions" object.
+     */
+    protected String style = null;
+
+    public String getStyle() {
+        return (this.style);
+    }
+
+    public void setStyle(String style) {
+        this.style = style;
+    }
+
+
+    /**
+     *  HTML Label tag text.
+     */
+    protected String label = null;
+
+    public String getLabel() {
+        return (this.label);
+    }
+
+    public void setLabel(String label) {
+        this.label = label;
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+    public int doStartTag() throws JspException {
+
+        this.labels.clear();
+        this.selecteds.clear();
+        this.urls.clear();
+
+        return (EVAL_BODY_TAG);
+       
+    }
+    
+    
+    /**
+     * Render this instant actions control.
+     *
+     * @exception JspException if a processing error occurs
+     */
+    public int doEndTag() throws JspException {
+
+        JspWriter out = pageContext.getOut();
+
+        try {
+
+            // Render (once only) the JavaScript function we need
+            if (pageContext.getAttribute(FUNCTION_TAG) == null) {
+                out.println();
+                out.println("<script language=\"JavaScript\">");
+                out.println("<!--");
+                out.println("function IA_jumpMenu(targ,selObj) {");
+                out.println("  dest = selObj.options[selObj.selectedIndex].value;");
+                out.println("  if (dest.length > 0) {");
+                out.println("    eval(targ+\".location='\"+dest+\"'\");");
+                out.println("  }");
+                out.println("}");
+                out.println("//-->");
+                out.println("</script>");
+                out.println();
+                pageContext.setAttribute(FUNCTION_TAG, Boolean.TRUE);
+            }
+
+            // Render LABEL element for section 508 accessibility
+            
+            if (label != null) {
+                out.print("<label for=\"labelId\">");
+                out.print(label);
+                out.println("</label>");
+            }
+            // Render the beginning of this element
+            out.println();
+            out.print("<select");
+            if (size > 1) {
+                out.print(" size=\"");
+                out.print(size);
+                out.print("\"");
+            }
+            if (style != null) {
+                out.print(" class=\"");
+                out.print(style);
+                out.print("\"");
+            }
+            if (label != null) {
+                out.print(" id=\"");
+                out.print("labelId");
+                out.print("\"");
+            }
+            
+            out.print(" onchange=\"IA_jumpMenu('self',this)\"");
+            out.println(">");
+
+            // Render each defined action
+            int n = labels.size();
+            for (int i = 0; i < n; i++) {
+                String label = (String) labels.get(i);
+                boolean selected = ((Boolean) selecteds.get(i)).booleanValue();
+                boolean disabled = ((Boolean) disableds.get(i)).booleanValue();             
+                String url = (String) urls.get(i);
+                out.print("<option");
+                if (selected)
+                    out.print(" selected=\"selected\"");
+                if (disabled)
+                    out.print(" disabled=\"true\"");                
+                out.print(" value=\"");
+                if (url != null)
+                    out.print(url);
+                out.print("\"");
+                out.print(">");
+                if (label != null)
+                    out.print(label);
+                out.println("</option>");
+            }
+
+            // Render the end of this element
+            out.println("</select>");
+            out.println();
+
+        } catch (IOException e) {
+            throw new JspException(e);
+        }
+
+        return (EVAL_PAGE);
+
+    }
+
+
+    /**
+     * Release all state information set by this tag.
+     */
+    public void release() {
+
+        this.labels.clear();
+        this.selecteds.clear();
+        this.urls.clear();
+
+        this.size = 1;
+        this.style = null;
+
+    }
+
+
+    // -------------------------------------------------------- Package Methods
+
+
+    /**
+     * Add a new Action to the set that will be rendered by this control.
+     *
+     * @param label Localized label visible to the user
+     * @param selected Initial selected state of this option
+     * @param disabled Ability to be selected state of this option
+     * @param url URL to which control should be transferred if selected
+     */
+    void addAction(String label, boolean selected, boolean disabled, String url) {
+
+        labels.add(label);
+        selecteds.add(new Boolean(selected));
+        disableds.add(new Boolean(disabled));
+        urls.add(url);
+
+    }
+
+
+    // ------------------------------------------------------ Protected Methods
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/ApplicationLocales.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/ApplicationLocales.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/ApplicationLocales.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,135 @@
+/*
+ * Copyright 2001,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.admin;
+
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Locale;
+import java.util.ResourceBundle;
+import org.apache.struts.Globals;
+import org.apache.struts.action.ActionServlet;
+import org.apache.struts.util.MessageResources;
+
+
+/**
+ * Class to hold the Locales supported by this package.
+ *
+ * @author Patrick Luby
+ * @author Craig R. McClanahan
+ * @version $Revision: 302997 $ $Date: 2004-07-10 01:56:16 -0500 (Sat, 10 Jul 2004) $
+ */
+
+public final class ApplicationLocales {
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Initialize the set of Locales supported by this application.
+     *
+     * @param servlet ActionServlet we are associated with
+     */
+    public ApplicationLocales(ActionServlet servlet) {
+
+        super();
+        Locale list[] = Locale.getAvailableLocales();
+        MessageResources resources = (MessageResources)
+                servlet.getServletContext().getAttribute(Globals.MESSAGES_KEY);
+        if (resources == null)
+            return;
+        String config = resources.getConfig();
+        if (config == null)
+            return;
+
+        for (int i = 0; i < list.length; i++) {
+            try {
+                ResourceBundle bundle =
+                    ResourceBundle.getBundle(config, list[i]);
+                if (bundle == null)
+                    continue;
+                if (list[i].equals(bundle.getLocale())) {
+                    localeLabels.add(list[i].getDisplayName());
+                    localeValues.add(list[i].toString());
+                    supportedLocales.add(list[i]);
+                }
+            } catch( Exception ex ) {
+                servlet.log("Missing locale " + list[i] );
+                continue;
+            }
+        }
+
+    }
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The set of Locale labels supported by this application.
+     */
+    protected ArrayList localeLabels = new ArrayList();
+
+
+    /**
+     * The set of Locale values supported by this application.
+     */
+    protected ArrayList localeValues = new ArrayList();
+
+
+    /**
+     * The set of supported Locales for this application.
+     */
+    protected ArrayList supportedLocales = new ArrayList();
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Return the set of Locale labels supported by this application.
+     */
+    public List getLocaleLabels() {
+
+        return (localeLabels);
+
+    }
+
+
+    /**
+     * Return the set of Locale values supported by this application.
+     */
+    public List getLocaleValues() {
+
+        return (localeValues);
+
+    }
+
+
+    /**
+     * Return the set of Locales supported by this application.
+     */
+    public List getSupportedLocales() {
+
+        return (supportedLocales);
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/ApplicationResources.properties
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/ApplicationResources.properties	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/ApplicationResources.properties	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,449 @@
+application.title=Tomcat Server Administration
+errors.header=<h2><font color="red">Validation Errors</font></h2>You must correct the following errors before proceeding:<ul>
+errors.footer=</ul><hr>
+error.login=<li>Invalid username or password</li>
+prompt.username=User Name
+prompt.password=Password
+button.login=Login
+button.reset=Reset
+button.save=Save
+button.change=Change
+button.cancel=Reset
+button.commit=Commit Changes
+button.logout=Log Out
+login.enter=Enter a username and password to start a new session
+login.changeLanguage=Change the language
+error.login=Invalid username or password
+error.tryagain=To try again, click
+error.here=here
+prompt.someText=Some Text
+prompt.moreText=More Text
+sample.someText.required=<li>"Some Text" cannot be empty</li>
+sample.moreText.required=<li>"More Text" cannot be empty</li>
+save.success=Save sucessful!
+save.fail=Save failed!
+server.portnumber=Port Number
+server.debuglevel=Debug Level
+server.shutdown=Shutdown
+server.properties=Server Properties
+warning.header=<center><h4><font color="red">Warning!</font></h4></center> <ul>
+server.port.warning=<li>Port number less than 1024 requires special software capabilities.
+error.portNumber.required=<li>PortNumber cannot be empty</li>
+error.portNumber.format=<li>PortNumber not a valid integer!</li>
+error.portNumber.range=<li>PortNumber seems out of range. Valid range is 1-65535. </li>
+error.shutdownText.length=<li>Shutdown Text must be atleast 6 characters</li>
+error.engineName.required=<li>Engine name is required</li>
+error.acceptCountText.required=<li>Accept count required</li>
+error.acceptCountText.format=<li>Accept count not a valid integer!</li>
+error.acceptCountText.range=<li>Accept count seems out of range. Valid range is 0-128. </li>
+error.connTimeOutText.required=<li>Connection time out required</li>
+error.connTimeOutText.format=<li>Connection time out not a valid integer!</li>
+error.connTimeOutText.range=<li>Connection time out seems out of range. Valid range is 0-60000. </li>
+error.bufferSizeText.required=<li>Buffer Size required</li>
+error.bufferSizeText.format=<li>Buffer Size not a valid integer!</li>
+error.bufferSizeText.range=<li>Buffer Size seems out of range. Valid range is 1-8192. </li>
+error.address.invalid=<li>IP Address invalid</li>
+error.redirectPortText.required=<li>Redirect Port Number cannot be empty</li>
+error.redirectPortText.format=<li>Redirect Port Number not a valid integer!</li>
+error.redirectPortText.range=<li>Redirect Port Number seems out of range. Valid range is 1-65535. </li>
+error.minProcessorsText.required=<li>Minimum Processors cannot be empty</li>
+error.minProcessorsText.format=<li>Minimum Processors not a valid integer!</li>
+error.minProcessorsText.range=<li>Minimum Processors seems out of range. Valid range is 1-512. </li>
+error.maxProcessorsText.required=<li>Maximum Processors cannot be empty</li>
+error.maxProcessorsText.format=<li>Maximum Processors not a valid integer!</li>
+error.maxProcessorsText.range=<li>Maximum Processors seems out of range. Valid range is 1-512. Also, maximum >= minimum. </li>
+error.proxyName.invalid=<li>Proxy name is invalid</li>
+error.proxyPortText.required=<li>Proxy Port Number cannot be empty</li>
+error.proxyPortText.format=<li>Proxy Port Number not a valid integer!</li>
+error.proxyPortText.range=<li>Proxy Port Number seems out of range. Valid range is 1-65535. </li>
+error.hostName.bad=Invalid host name {0}
+error.hostName.required=<li>Hostname is required</li>
+error.hostName.exists=<li>Hostname already exists</li>
+error.appBase.required=<li>Application Base is required</li>
+service.name=Name
+service.engine.props=Engine Properties
+service.defaulthostname=Default Hostname
+service.properties=Service Properties
+service.property=Property
+service.value=Value
+service.create.new=Create New Service
+actions.available.actions=Available Actions
+actions.services.create=Create New Service
+actions.services.delete=Delete This Service
+actions.services.deletes=Delete Existing Services
+actions.services.edit=Edit Existing Service
+actions.accesslogger.create=Create New Access Logger
+actions.accesslogger.delete=Delete Access Logger
+actions.connectors.create=Create New Connector
+actions.connectors.delete=Delete This Connector
+actions.connectors.deletes=Delete Existing Connectors
+actions.connectors.edit=Edit Existing Connector
+actions.contexts.create=Create New Context
+actions.contexts.delete=Delete This Context
+actions.contexts.deletes=Delete Existing Contexts
+actions.contexts.edit=Edit Existing Context
+actions.defaultcontexts.create=Create New DefaultContext
+actions.defaultcontexts.delete=Delete This DefaultContext
+actions.defaultcontexts.deletes=Delete Existing DefaultContext
+actions.defaultcontexts.edit=Edit Existing DefaultContext
+actions.group.create=Create New Group
+actions.group.delete=Delete Existing Group
+actions.hosts.create=Create New Host
+actions.hosts.delete=Delete This Host
+actions.hosts.deletes=Delete Existing Hosts
+actions.hosts.edit=Edit Existing Host
+actions.loggers.create=Create New Logger
+actions.loggers.delete=Delete This Logger
+actions.loggers.deletes=Delete Existing Loggers
+actions.loggers.edit=Edit Existing Logger
+actions.realms.create=Create New User Realm
+actions.realms.delete=Delete This User Realm
+actions.realms.deletes=Delete User Realms
+actions.realms.edit=Edit Existing Realm
+actions.requestfilter.create=Create New Request Filter
+actions.requestfilter.delete=Delete Request Filters
+actions.user.create=Create New User
+actions.user.delete=Delete Existing User
+actions.valves.create=Create New Valve
+actions.valves.edit=Edit Valve
+actions.valves.delete=Delete This Valve
+actions.valves.deletes=Delete Existing Valves
+actions.alias.create=Create New Aliases
+actions.alias.delete=Delete Aliases
+new.alias=New Alias
+connector.type=Type
+connector.scheme=Scheme
+connector.accept.count=Accept Count
+connector.compression=Compression
+connector.connection.linger=Connection Linger
+connector.connection.timeout=Connection Timeout
+connector.connection.uploadTimeout=Connection Upload Timeout
+connector.default.buffer=Default Buffer Size
+connector.connection.disableUploadTimeout=Disable Upload Timeout
+connector.enable.dns=Enable DNS Lookups
+connector.uriencoding=URI Encoding
+connector.useBodyEncodingForURI=Use Body Encoding For URI Query Parameters
+connector.allowTrace=Allow TRACE Method
+connector.address.ip=IP Address
+connector.redirect.portnumber=Redirect Port Number
+connector.min=Minimum
+connector.milliseconds=milliseconds
+connector.max=Maximum
+connector.maxkeepalive=Max KeepAlive Requests
+connector.maxspare=Max Spare Threads
+connector.maxthreads=Max Threads
+connector.minspare=Min Spare Threads
+connector.threadpriority=Processor Thread Priority
+connector.proxy.name=Proxy Name
+connector.proxy.portnumber=Proxy Port Number
+connector.algorithm=Algorithm
+connector.ciphers=Ciphers
+connector.client.auth=Client Authentication
+connector.keystore.filename=Keystore Filename
+connector.keystore.password=Keystore Password
+connector.keystore.type=Keystore Type
+connector.sslProtocol=SSL Protocol
+connector.keyPass.warning=<li>Please use keytool to generate certificate.</li>
+connector.secure=Secure
+connector.tcpNoDelay=TCP No Delay 
+connector.xpoweredby=X Powered By 
+host.properties=Host Properties
+host.name=Name
+host.base=Application Base
+host.autoDeploy=Auto Deploy
+host.deployXML=Deploy XML
+host.deployOnStartup=Deploy On Startup
+host.wars=Unpack WARs
+host.aliases=Aliases
+host.alias.name=Alias Name
+host.xmlNamespaceAware=XML Namespace Aware
+host.xmlValidation=XML Validation
+error.aliasName.exists=<li>Alias already exists</li>
+error.aliasName.required=<li>Alias name is required</li>
+context.properties=Context Properties
+context.cookies=Cookies
+context.cross.context=Cross Context
+context.docBase=Document Base
+context.override=Override
+context.privileged=Privileged
+context.path=Path
+context.reloadable=Reloadable
+context.swallowOutput=Swallow Output
+context.usenaming=Use Naming
+context.workdir=Working Directory
+context.loader.properties=Loader Properties
+context.sessionmgr.properties=Session Manager Properties
+context.checkInterval=Check interval
+context.sessionId=Session ID Initializer
+context.max.sessions=Maximum Active Sessions
+context.antiResourceLocking=Prevent Locking Resources
+context.antiJarLocking=Prevent Jar Locking
+defaultcontext.properties=DefaultContext Properties
+error.context.directory=Document base does not exist or is not a readable directory
+error.docBase.required=<li>Document base cannot be null</li>
+error.path.required=<li>Path cannot be null</li>
+error.workDir.required=<li>Working directory cannot be null</li>
+error.ldrCheckInterval.required=<li>Loader check interval cannot be empty</li>
+error.ldrCheckInterval.format=<li>Loader check interval not a valid integer!</li>
+error.ldrCheckInterval.range=<li>Loader check interval seems out of range. Valid range is 1-1000. </li>
+error.mgrCheckInterval.required=<li>Manager check interval cannot be empty</li>
+error.mgrCheckInterval.format=<li>Manager check interval not a valid integer!</li>
+error.mgrCheckInterval.range=<li>Manager check interval seems out of range. Valid range is 1-1000. </li>
+error.mgrSessionIDInit.required=<li>Session Manager Initialization ID cannot be empty</li>
+error.mgrMaxSessions.required=<li>Maximum sessions cannot be empty</li>
+error.mgrMaxSessions.format=<li>Maximum sessions not a valid integer!</li>
+error.mgrMaxSessions.range=<li>Maximum sessions seems out of range. Valid range is -1 to 100. </li>
+list.none=(None)
+logger.directory=Directory
+logger.prefix=Prefix
+logger.suffix=Suffix
+logger.timestamp=Timestamp
+logger.filelogger.properties=Filelogger specific Properties
+logger.verbositylevel=Verbosity Level
+error.loggerName.bad=Invalid logger name {0}
+error.loggerName.exists=<li>A Logger already exists.</li>
+error.directory.required=<li>Directory cannot be empty.</li>
+error.prefix.required=<li>Prefix cannot be empty.</li>
+error.suffix.required=<li>Suffix cannot be empty.</li>
+error.valveName.bad=Invalid valve name {0}
+error.vavlveName.exists=<li>Valve already exists</li>
+error.singleSignOn.exists=<li>SingleSignOn Valve already exists</li>
+user.fullName=Full Name
+user.groups=Member in Groups
+user.newUser=Create New User Properties
+user.oldUser=Edit Existing User Properties
+user.password=Password
+user.properties=User Properties
+user.roles=Security Roles
+user.username=Username
+error.password.required=<li>Password is required</li>
+error.username.required=<li>Username is required</li>
+error.get.attributes=Error retrieving information properties.
+error.set.attributes=Error setting information properties.
+actions.delete=Delete
+error.defaultHost.required=<li>Default Hostname required</li>
+error.engineName.bad=Invalid engine name {0}
+error.engineName.exists=<li>Engine Name already exists</li>
+error.serviceName.bad=Invalid service name {0}
+error.serviceName.required=<li>Service Name required</li>
+error.serviceName.exists=<li>Service Name already exists</li>
+error.jdbcrealm=Error occured during setting JDBCRealm.
+error.jndirealm=Error occured during setting JNDIRealm.
+error.userdbrealm=Error occured during setting UserdatabaseRealm.
+error.datasourcerealm=Error occured during setting DataSourceRealm.
+error.realmName.bad=Invalid realm name {0}
+error.realmName.required=<li>Realm Name required.</li>
+error.realmName.exists=<li>A realm already exists.</li>
+error.contextName.bad=Invalid context name {0}
+error.contextName.exists=<li>Context already exists.</li>
+error.defaultcontextName.exists=<li>DefaultContext already exists.</li>
+error.path.prefix=<li>Path must begin with a '/'.</li>
+error.loaderName.bad=Invalid loader name {0}
+error.managerName.bad=Invalid manager name {0}
+error.connectorName.bad=Invalid connector name {0}
+error.connectorName.exists=<li>Connector already exists</li>
+error.pattern.required=<li>Pattern is required</li>
+error.valveName.bad=Invalid valve name {0}
+error.valveName.exists=<li>Valve already exists</li>
+realm.driver=Database Driver
+realm.passwd=Database Password
+realm.url=Database URL
+realm.userName=Database User Name
+realm.digest=Digest Algorithm
+realm.passwordCol=Password Column
+realm.roleNameCol=Role Name Column
+realm.userNameCol=User Name Column
+realm.userRoleTable=User Role Table
+realm.userTable=User Table
+realm.resource=Resource Name
+realm.pathName=Path Name
+realm.connName=Connection Name
+realm.connPassword=Connection Password
+realm.connURL=Connection URL
+realm.connFactory=Context Factory
+realm.roleBase=Role Base Element
+realm.roleName=Role Name
+realm.user.roleName=User Role Name
+realm.pattern=Role Search Pattern
+realm.role.subtree=Search Role Subtree
+realm.userBase=User Base Element
+realm.user.subtree=Search User Subtree
+realm.userPassword=User Password
+realm.userPattern=User Pattern
+realm.userSearch=User Search
+realm.dataSourceName=DataSource Name
+realm.localDataSource=Local DataSource
+realm.userCredCol=User Credential Column 
+valve.access.properties=Access Logger Properties
+valve.request.properties=Request Filter Properties
+valve.single.properties=Single SignOn Valve Properties
+valve.remotehost.properties=Remote Host Valve Properties
+valve.remoteaddress.properties=Remote Address Valve Properties
+valve.resolveHosts=Resolve Hosts
+valve.rotatable=Rotatable
+valve.pattern=Pattern
+valve.allowHosts=Allow these Hosts
+valve.denyHosts=Deny these Hosts
+valve.allowIPs=Allow IP addresses
+valve.denyIPs=Deny IP addresses
+error.allowHost=<li>Allow is invalid.  Need to include the admin's Hostname.</li>
+error.denyHost=<li>Deny is invalid.  Need to exclude the admin's Hostname.</li>
+error.allowIP=<li>Allow is invalid.  Need to include the admin's IP address.</li>
+error.denyIP=<li>Deny is invalid.  Need to exclude the admin's IP address.</li>
+error.allow.deny.required=<li>Allow or deny is required.</li>
+error.syntax=<li>Syntax error in request filter pattern.</li>
+error.resource.required=<li>Resource Name is required.</li>
+error.resource.javaprefix=<li>Resource must have "java:" prefix.</li>
+error.pathName.required=<li>Path Name is required.</li>
+error.driver.required=<li>Database driver is required.</li>
+error.roleNameCol.required=<li>Role name column is required.</li>
+error.userNameCol.required=<li>User name column is required.</li>
+error.passwordCol.required=<li>Password column is required.</li>
+error.userTable.required=<li>User table is required.</li>
+error.roleTable.required=<li>User role table is required.</li>
+error.connectionPassword.required=<li>Database password is required.</li>
+error.connectionURL.required=<li>Database URL is required.</li>
+error.connectionName.required=<li>Database username is required.</li>
+error.roleName.required=<li>Role name is required.</li>
+error.userRoleName.required=<li>User Role name is required.</li>
+error.digest.required=<li>Digest algorithm is required.</li>
+error.roleBase.required=<li>Role base element is required.</li>
+error.rolePattern.required=<li>Role search pattern is required.</li>
+error.userBase.required=<li>User base element is required.</li>
+error.userPassword.required=<li>User Password is required.</li>
+error.userPattern.required=<li>User pattern is required.</li>
+error.userSearch.required=<li>User search is required.</li>
+error.userPattern.userSearch.defined=<li>Either userPattern or userSearch must be specified not both.</li>
+error.contextFactory.required=<li>Context Factory is required.</li>
+error.connPassword.required=<li>Connection password is required.</li>
+error.connURL.required=<li>Connection URL is required.</li>
+error.connName.required=<li>Connection name is required.</li>
+error.dataSourceName.required=<li>DataSource name is required.</li>
+error.userCredCol.required=<li>User credential is required.</li>
+error.userRoleTable.required=<li>User role table is required.</li>
+
+# ---------- Server Module ----------
+server.service.treeBuilder.subtreeNode=Service
+server.service.treeBuilder.connector=Connector
+server.service.treeBuilder.host=Host
+server.service.treeBuilder.context=Context 
+server.service.treeBuilder.loggerFor=Logger for {0}
+server.service.treeBuilder.realmFor=Realm for {0} 
+server.service.treeBuilder.logger=Logger
+server.service.treeBuilder.realm=Realm
+
+# ---------- Resources Module ----------
+resources.treeBuilder.subtreeNode=Resources
+resources.treeBuilder.datasources=Data Sources
+resources.treeBuilder.mailsessions=Mail Sessions
+resources.treeBuilder.resourcelinks=Resource Links
+resources.env.entries=Environment Entries
+resources.env.entry=Entry Name
+resources.env.props=Environment Entry Properties
+resources.env.override=Override Application Level Entries
+resources.actions.env.create=Create New Env Entry
+resources.actions.env.edit=Edit Environment Entry
+resources.actions.env.delete=Delete Environment Entries
+resources.actions.env.list=List Existing Entries
+resources.datasrc.jdbc=JDBC Driver
+resources.actions.datasrc=Data Sources
+resources.actions.datasrc.create=Create New Data Source
+resources.actions.datasrc.delete=Delete Data Sources
+resources.actions.datasrc.edit=Edit Data Source
+resources.datasrc.url=Data Source URL
+resources.datasrc.jdbcclass=JDBC Driver Class
+resources.datasrc.connections=Connections
+resources.datasrc.active=Max. Active Connections
+resources.datasrc.idle=Max. Idle Connections
+resources.datasrc.wait=Max. Wait for Connection
+resources.datasrc.validation=Validation Query
+resources.datasrc.jndi=JNDI Name
+resources.actions.mailsession=Mail Sessions
+resources.actions.mailsession.create=Create New Mail Session
+resources.actions.mailsession.delete=Delete Mail Session
+resources.actions.mailsession.edit=Edit Mail Session
+resources.mailsession.name=Name
+resources.mailsession.mailhost=mail.smtp.host
+resources.actions.resourcelk=Resource Links
+resources.actions.resourcelk.create=Create New Resource Link
+resources.actions.resourcelk.delete=Delete Resource Link
+resources.actions.resourcelk.edit=Edit Resource Link
+resources.resourcelk.name=Name
+resources.resourcelk.global=Global
+resources.resourcelk.type=Type
+resources.error.name.required=<li>Name is required.</li>
+resources.error.global.required=<li>Global is required.</li>
+resources.error.type.required=<li>Type is required.</li>
+resources.error.value.required=<li>Value is required.</li>
+resources.error.value.mismatch=<li>Type and value do not seem to match.</li>
+resources.error.entryType.invalid=<li>Entry Type not recognized.</li>
+resources.error.entryType.notimpl=<li>Validation for this type not implemented yet.</li>
+resources.error.url.required=<li>Data Source URL is required.</li>
+resources.error.driverClass.required=<li>JDBC Driver Class is required.</li>
+resources.error.active.required=<li>Max Active Connections is required.</li>
+resources.error.idle.required=<li>Max Idle Connections is required.</li>
+resources.error.wait.required=<li>Max Wait for a Connection is required.</li>
+resources.error.mailhost.required=<li>mail.smtp.host is required.</li>
+resources.integer.error=<li>Invalid integer error.</li>
+resources.actions.userdb.create=Create New User Database
+resources.actions.userdb.edit=Edit User Database
+resources.actions.userdb.delete=Delete User Databases
+resources.userdb.location=Location
+resources.userdb.factory=Factory
+resources.treeBuilder.databases=User Databases
+resources.error.path.required=<li>Path is required</li>
+resources.error.jndiName.required=<li>JNDI Name is required</li>
+resources.invalid.name=<li>Invalid resource name - Name already exists.</li>
+resources.invalid.env=<li>Invalid environment name - Name already exists.</li>
+
+# ---------- User Database Module ----------
+users.actions.group.create=Create New Group
+users.actions.group.delete=Delete Existing Groups
+users.actions.group.list=List Existing Groups
+users.actions.role.create=Create New Role
+users.actions.role.delete=Delete Existing Roles
+users.actions.role.list=List Existing Roles
+users.actions.user.create=Create New User
+users.actions.user.delete=Delete Existing Users
+users.actions.user.list=List Existing Users
+users.deleteGroups.title=Delete Existing Groups
+users.deleteRoles.title=Delete Existing Roles
+users.deleteUsers.title=Delete Existing Users
+users.error.attribute.get=Error retrieving attribute {0}
+users.error.attribute.set=Error modifying attribute {0}
+users.error.invoke=Error invoking operation {0}
+users.error.groupname.required=Group Name is required
+users.error.password.required=Password is required
+users.error.quotes=Double quote characters are not allowed in field values
+users.error.rolename.required=Role Name is required
+users.error.select=Error selecting managed objects
+users.error.token=Transaction submitted out of order
+users.error.username.required=<li>User Name is required</li>
+users.group.newGroup=Create New Group Properties
+users.group.oldGroup=Edit Existing Group Properties
+users.group.properties=Group Properties
+users.list.description=Description
+users.list.fullName=Full Name
+users.list.groupname=Group Name
+users.list.rolename=Role Name
+users.list.username=User Name
+users.listGroups.title=Groups List
+users.listRoles.title=Roles List
+users.listUsers.title=Users List
+users.prompt.description=Description:
+users.prompt.fullName=Full Name:
+users.prompt.groupname=Group Name:
+users.prompt.password=Password:
+users.prompt.rolename=Role Name:
+users.prompt.username=User Name:
+users.role.newRole=Create New Role Properties
+users.role.oldRole=Edit Existing Role Properties
+users.role.properties=Role Properties
+users.treeBuilder.groupsNode=Groups
+users.treeBuilder.rolesNode=Roles
+users.treeBuilder.subtreeNode=User Definition
+users.treeBuilder.usersNode=Users
+users.user.newUser=Create New User Properties
+users.user.oldUser=Edit Existing User Properties
+users.user.properties=User Properties
+# ---------- -------------------- ----------

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/ApplicationResources_es.properties
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/ApplicationResources_es.properties	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/ApplicationResources_es.properties	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,439 @@
+application.title=Administración del Servidor Tomcat
+errors.header=<h3><font color="red">Error(es) de Validación</font></h3>Debe corregir el/los siguiente(s) error(es) antes de continuar:<ul>
+errors.footer=</ul><hr>
+error.login=<li>Nombre de usuario o contraseña inválidos</li>
+prompt.username=Nombre de Usuario
+prompt.password=Contraseña
+button.login=Login
+button.reset=Limpiar
+button.save=Guardar
+button.change=Cambiar
+button.cancel=Cancelar
+button.commit=Acometer Cambios
+button.logout=Salir
+login.enter=Introduzca un nombre de usuario y una contraseña para iniciar una nueva sesión
+login.changeLanguage=Cambio de idioma
+error.login=Nombre de usuario o contraseña inválidos
+error.tryagain=Para intentar de nuevo, haga click
+error.here=aquí
+prompt.someText=Algún Texto
+prompt.moreText=Más Texto
+sample.someText.required=<li>"Algún Texto" no puede estar vacío</li>
+sample.moreText.required=<li>"Más Texto" no puede estar vacío</li>
+save.success=¡Guardardo con éxito!
+save.fail=¡Fallo al guardar!
+server.portnumber=Número de Puerto
+server.debuglevel=Nivel de Depuración
+server.shutdown=Apagar
+server.properties=Propiedades del Servidor
+warning.header=<center><h4><font color="red">¡Aviso!</font></h4></center> <ul>
+server.port.warning=<li>El número de puerto inferior a 1024 requiere capacidades especiales del software.</li>
+error.portNumber.required=<li>El número del puerto no puede estar vacío.</li>
+error.portNumber.format=<li>¡El número del puerto no es un entero válido! </li>
+error.portNumber.range=<li>El número del puerto esta fuera del rango. El rango válido es 1-65535.</li>
+error.shutdownText.length=<li>¡La longitud del Texto para Apagar debe ser de al menos 6 caracteres!</li>
+error.engineName.required=<li>Se requiere el nombre del Motor</li>
+error.acceptCountText.required=<li>Se requiere contador de Aceptación</li>
+error.acceptCountText.format=<li>¡El contador de Aceptación no es un entero váido!</li>
+error.acceptCountText.range=<li>El contador de aceptación parece estar fuera de rango. El rango válido va de 0-128. </li>
+error.connTimeOutText.required=<li>El tiempo de espera de la conexión no puede estar vacío.</li>
+error.connTimeOutText.format=<li>¡El tiempo de espera de la conexión no es un entero válido! </li>
+error.connTimeOutText.range=<li>El tiempo de espera de la conexión parece estar fuera de rango. El rango válido va de 0-60000. </li>
+error.bufferSizeText.required=<li>Tamaño del Búfer requerido</li>
+error.bufferSizeText.format=<li>¡El Tamaño del Búfer no es un entero! </li>
+error.bufferSizeText.range=<li>Tamaño del Búfer parece estar fuera del rango. El rango válido va de 1-8192. </li>
+error.address.invalid=<li>Dirección IP inválida</li>
+error.redirectPortText.required=<li>Número del puerto de redireccionamiento no puede estar vacío </li>
+error.redirectPortText.format=<li>¡El Número del puerto de redireccionamiento no es un entero válido! </li>
+error.redirectPortText.range=<li>Número del puerto de redireccionamiento parece estar fuera de rango. El rango válido va de 1-65535.</li>
+error.minProcessorsText.required=<li>El mínimo de procesadores no puede estar vacío</li>
+error.minProcessorsText.format=<li>¡El Mínimo de procesadores no es un entero válido!</li>
+error.minProcessorsText.range=<li>El mínimo de procesadores parece estar fuera de rango. El rango válido va de 1-512.</li>
+error.maxProcessorsText.required=<li>El máximo de procesadores no puede estar vacído</li>
+error.maxProcessorsText.format=<li>¡El Máximo de procesadores no es un entero válido!</li>
+error.maxProcessorsText.range=<li>El máximo de procesadores parece estar fuera de rango. El rango válido va de 1-512. También, máximo > = mínimo.</li>
+error.proxyName.invalid=<li>El nombre del apoderado (proxy) es inválido</li>
+error.proxyPortText.required=<li>El número del puerto del apoderado (proxy) no puede estar vacío</li>
+error.proxyPortText.format=<li>¡El Número del puerto del apoderado (proxy) no es un entero válido!</li>
+error.proxyPortText.range=<li>El número del puerto del apoderado (proxy) parece estar fuera de rango. El rango válido va de 1-65535.</li>
+error.hostName.bad=nombre de máquina inválida {0}
+error.hostName.required=<li>Se requiere el nombre de máquina</li>
+error.hostName.exists=<li>Ya existe el Nombre de Máquina</li>
+error.appBase.required=<li>Se requiere la Base de la Aplicación</li>
+service.name=Nombre
+service.engine.props=Propiedades del Motor
+service.defaulthostname=Nombre de Máquina por defecto
+service.properties=Propiedades del Servicio
+service.property=Propiedad
+service.value=Valor
+service.create.new=Crear Nuevo Servicio
+actions.available.actions=Acciones Disponibles
+actions.services.create=Crear Nuevo Servicio
+actions.services.delete=Eliminar Este Servicio
+actions.services.deletes=Eliminar Servicios Existentes
+actions.services.edit=Editar Servicio Existente
+actions.accesslogger.create=Crear Nuevo (Access Logger) Registrador de Acceso
+actions.accesslogger.delete=Eliminar (Access Logger) Registrador de Acceso
+actions.connectors.create=Crear Nuevo Conector
+actions.connectors.delete=Eliminar este Conector
+actions.connectors.deletes=Eliminar Conectores Existentes
+actions.connectors.edit=Editar Conector Existente
+actions.contexts.create=Crear Nuevo Contexto
+actions.contexts.delete=Borrar este Contexto
+actions.contexts.deletes=Borrar Contextos Existentes
+actions.contexts.edit=Editar Contexto Existente
+actions.defaultcontexts.create=Crear DefaultContext Nuevo
+actions.defaultcontexts.delete=Borrar Este DefaultContext
+actions.defaultcontexts.deletes=Borrar DefaultContext Existente
+actions.defaultcontexts.edit=Editar DefaultContext Existente 
+actions.group.create=Crear Nuevo Grupo
+actions.group.delete=Borrar Grupo Existente
+actions.hosts.create=Crear Nueva Máquina
+actions.hosts.delete=Borrar Esta Máquina
+actions.hosts.deletes=Borrar Máquinas Existentes
+actions.hosts.edit=Editar Máquina Existente
+actions.loggers.create=Crear Nuevo (Logger) Registrador
+actions.loggers.delete=Borrar Este (Logger) Registrador
+actions.loggers.deletes=Borrar (Loggers) Registradores Existentes
+actions.loggers.edit=Editar (Logger) Registrador Existente
+actions.realms.create=Crear Nuevo Reino (Realm) de Usuario
+actions.realms.delete=Borrar Este Reino (Realm) de Usuario
+actions.realms.deletes=Borrar Reinos (Realms) de Usuario
+actions.realms.edit=Editar Reino (Realm) Existente
+actions.requestfilter.create=Crear Nuevo Filtro de Petición
+actions.requestfilter.delete=Borrar Filtros de Petición
+actions.user.create=Crear Nuevo Usuario
+actions.user.delete=Eliminar Usuario Existente
+actions.valves.create=Crear Nueva Válvula
+actions.valves.edit=Editar Válvula
+actions.valves.delete=Borrar Esta Válvula
+actions.valves.deletes=Borrar Vávulas Existentes
+actions.alias.create=Crear Nuevo Alias
+actions.alias.delete=Borrar Alias
+new.alias=Nuevo Alias
+connector.type=Tipo
+connector.scheme=Esquema
+connector.accept.count=Contador de Aceptación
+connector.compression=Compresión
+connector.connection.linger=Demora de la Conexión
+connector.connection.timeout=Tiempo de Espera de la Conexión
+connector.connection.uploadTimeout=Tiempo de Espera de Conexión en la Carga
+connector.default.buffer=Tamaño por defecto del Búfer
+connector.connection.disableUploadTimeout=Desactivar Tiempo de Espera de la Carga
+connector.enable.dns=Permitir Búsquedas en el DNS
+connector.uriencoding=Codificación de URI
+connector.useBodyEncodingForURI=Usar Codificación de Cuerpo (Body) para Parámetros de Consulta de URI
+connector.allowTrace=Permitir Método de TRAZA
+connector.address.ip=Dirección IP
+connector.redirect.portnumber=Número del puerto de redireccionamiento
+connector.min=Mínimo
+connector.milliseconds=milisegundos
+connector.max=Máximo
+connector.maxkeepalive=Peticiones Máximas de Maneter Viva (KeepAlive)
+connector.maxspare=Máx. Hilos de Repuesto
+connector.maxthreads=Máx. Hilos
+connector.minspare=Mín. Hilos de Repuesto
+connector.threadpriority=Processor Thread Priority
+connector.proxy.name=Nombre del Apoderado (Proxy)
+connector.proxy.portnumber=Número de Puerto del Apoderado (Proxy)
+connector.algorithm=Algoritmo
+connector.ciphers=Cifrados
+connector.client.auth=Autenticación de Cliente
+connector.keystore.filename=Nombre de Archivo de Almacén de Claves
+connector.keystore.password=Contraseña de Almacén de Claves
+connector.keystore.type=Tipo de Almacén de Claves
+connector.sslProtocol=Protocolo SSL
+connector.keyPass.warning=<li>Utilice por favor keytool para generar el certificado.</li>
+connector.secure=Seguro
+connector.tcpNoDelay=TCP Sin Retardo
+connector.xpoweredby=X Potenciado Mediante
+host.properties=Propiedades de la Máquina
+host.name=Nombre
+host.base=Base De la Aplicación
+host.autoDeploy=Desplegar Automáticamente
+host.deployXML=Despliegue XML 
+host.deployOnStartup=Despliegue En Arranque 
+host.wars=Desempaquetar WARs
+host.aliases=Aliases
+host.alias.name=Nombre de Alias
+host.xmlNamespaceAware=Conocedor de Espacio de Nombres XML
+host.xmlValidation=Validación XML
+error.aliasName.exists=<li>El Alias ya existe</li>
+error.aliasName.required=<li>Se requiere el nombre de Alias</li>
+context.properties=Propiedades del contexto
+context.cookies=Cookies
+context.cross.context=Contexto Cruzado
+context.docBase=Base Del Documento
+context.override=Pasar por Alto
+context.path=Trayectoria
+context.reloadable=Recargable
+context.swallowOutput=Salida del Trago (Swallow)
+context.usenaming=Utilizar el Nombramiento (Naming)
+context.workdir=Directorio de Trabajo
+context.loader.properties=Propiedades del cargador
+context.sessionmgr.properties=Propiedades del gestor de Sesión
+context.checkInterval=Intervalo de Chequeo
+context.sessionId=Inicializador de la Identificación De la Sesión
+context.max.sessions=Máximas Sesiones Activas
+defaultcontext.properties=Propiedades de DefaultContext 
+error.context.directory=La base del documento ni existe ni es un directorio legible 
+error.docBase.required=<li>La base del documento no puede ser nula</li>
+error.path.required=<li>La trayectoria no puede ser nula</li>
+error.workDir.required=<li>El directorio de trabajo no puede ser nulo</li>
+error.ldrCheckInterval.required=<li>El intervalo de chequeo del cargador no puede estar vacío</li>
+error.ldrCheckInterval.format=<li>¡El Intervalo de chequeo del cargador no un número entero válido!</li>
+error.ldrCheckInterval.range=<li>El intervalo de chequeo del cargador parece fuera de rango. El rango válido va de 1-1000.</li>
+error.mgrCheckInterval.required=<li>El intervalo de chequeo del gestor no puede estar vacío</li>
+error.mgrCheckInterval.format=<li>¡El Intervalo del chequeo del gestor no es un número entero válido!</li>
+error.mgrCheckInterval.range=<li>El intervalo de chequeo del gestor parece fuera de rango. El rango valido va de 1-1000.</li>
+error.mgrSessionIDInit.required=<li>La identificación de la inicialización del gestor de la sesión no puede estar vacía</li>
+error.mgrMaxSessions.required=<li>Las sesiones máximas no pueden estar vacías</li>
+error.mgrMaxSessions.format=<li>¡Las Sesiones máximas no son un entero válido!</li>
+error.mgrMaxSessions.range=<li>Las sesiones máximas parecen estar fuera de rango. El rango válido va de -1 a 100.</li>
+list.none=(Nada)
+logger.directory=Directorio
+logger.prefix=Prefijo
+logger.suffix=Sufijo
+logger.timestamp=Sello temporal (timestamp)
+logger.filelogger.properties=Propiedades específicas del Registrador de Archivo (FileLogger)
+logger.verbositylevel=Nivel de Detalle
+error.loggerName.bad=Nombre de registrador inválido {0}
+error.loggerName.exists=<li>El registrador ya existe.</li>
+error.directory.required=<li>El Directorio no puede estar vacío.</li>
+error.prefix.required=<li>El prefijo no puede estar vacío.</li>
+error.suffix.required=<li>El sufijo no puede estar vacío.</li>
+error.valveName.bad=Nombre de válvula inválido {0}
+error.valveName.exists=<li>Ya existe la válvula</li>
+error.singleSignOn.exists=<li>Ya existe la válvula de Login Único (SingleSignOn)</li>
+user.fullName=Nombre Completo
+user.groups=Miembro en los Grupos
+user.newUser=Crear Nuevas Propiedades de Usuario
+user.oldUser=Editar Propiedades ya existentes de Usuario
+user.password=Contraseña
+user.properties=Propiedades de Usuario
+user.roles=Papeles Desempeñados de Seguridad
+user.username=Nombre de Usuario
+error.password.required=<li>Se requiere la contraseña</li>
+error.username.required=<li>Se requiere el nombre de usuario</li>
+error.get.attributes=Error extrayendo propiedades de información.
+error.set.attributes=Error poniendo propiedades de información.
+actions.delete=Borrar
+error.defaultHost.required=<li>Es necesaro el Nombre de Máquina por defecto</li>
+error.engineName.bad=Nombre de motor inválido{0}
+error.engineName.exists=<li>Ya existe el Nombre de Motor</li>
+error.serviceName.bad=Nombre de servicio inválido {0}
+error.serviceName.required=<li>Es necesario el Nombre del Servicio</li>
+error.serviceName.exists=<li>Ya existe el Nombre del Servicio</li>
+error.jdbcrealm=Ha tenido lugar un error al poner valor de JDBCRealm.
+error.jndirealm=Ha tenido lugar un error al poner valor de JNDIRealm.
+error.userdbrealm=Ha tenido lugar un error al poner valor de UserdatabaseRealm.
+error.realmName.bad=Nombre de reino inválido {0}
+error.realmName.required=<li>Es necesario el nombre de Reino.</li>
+error.realmName.exists=<li>Ya existe un Reino.</li>
+error.contextName.bad=Nombre de contexto inválido {0}
+error.contextName.exists=<li>Ya existe el Contexto.</li>
+error.defaultcontextName.exists=<li>Ya existe Contexto por Defecto (DefaultContext).</li>
+error.path.prefix=<li>La trayectoria debe de comenzar con '/'.</li>
+error.loaderName.bad=Nombre de cargador inválido {0}
+error.managerName.bad=Nombre de gestor inválido {0}
+error.connectorName.bad=Nombre de conector inválido {0}
+error.connectorName.exists=<li>Ya existe el Conector</li>
+error.pattern.required=<li>Es necesario el Patrón (Pattern)</li>
+error.valveName.bad=Nombre de válvula inválido {0}
+error.valveName.exists=<li>Ya existe la Válvula</li>
+realm.driver=Manejador (Driver) de Base de Datos
+realm.passwd=Contraseña de la Base de Datos
+realm.url=URL de la Base de Datos
+realm.userName=Nombre de Usuario de la Base de Datos
+realm.digest=Algoritmo Resumen (Digest)
+realm.passwordCol=Columna de Contraseña
+realm.roleNameCol=Columna del Nombre del Papel Desempeñado (Role)
+realm.userNameCol=Columna del Nombre del Usuario
+realm.userRoleTable=Tabla del Papel desempeñado por el Usuario
+realm.userTable=Tabla de Usuario
+realm.resource=Nombre del Recurso
+realm.pathName=Nombre de la Trayectoria
+realm.connName=Nombre de la Conexión
+realm.connPassword=Contraseña de la Conexión
+realm.connURL=URL de la Conexión
+realm.connFactory=Fábrica del Contexto
+realm.roleBase=Elemento Base del Papel Desempeñado
+realm.roleName=Nombre del Papel Desempeñado
+realm.user.roleName=Nombre del Papel Desempeñado
+realm.pattern=Patrón de la Búsqueda del Papel Desempeñado
+realm.role.subtree=Buscar Subárbol del Papel Desempeñado
+realm.userBase=Elemento Base de Usuario
+realm.user.subtree=Buscar Subárbol de Usuario
+realm.userPassword=Contraseña del Usuario
+realm.userPattern=Patrón de Usuario
+realm.userSearch=Búsqueda de Usuario
+valve.access.properties=Propiedades del Registrador de Acceso
+valve.request.properties=Propiedades del Filtro de Requerimiento
+valve.single.properties=Propiedades de la válvula de SignOn Único
+valve.remotehost.properties=Propiedades de la Válvula de Máquina Remota
+valve.remoteaddress.properties=Propiedades de la Válvula de Dirección Remota
+valve.resolveHosts=Resolver Máquinas
+valve.rotatable=Rotativo
+valve.pattern=Patrón
+valve.allowHosts=Permitir a estas Máquinas
+valve.denyHosts=Denegar a estas Máquinas
+valve.allowIPs=Permitir a direcciones IP
+valve.denyIPs=Denegar a direcciones IP
+error.allowHost=<li>Permitir es inválido. Es necesario incluir el nombre de máquina del administrador.</li>
+error.denyHost=<li>Denegar es inválido. Es necesario excluir el nombre de máquina del administrador.</li>
+error.allowIP=<li>Permitir es inválido. Es necesario incluir la dirección IP del administrador.</li>
+error.denyIP=<li>Denegar es inválido. Es necesario excluir la dirección IP del administrador.</li>
+error.allow.deny.required=<li>Es necesario poner Permitir o Denegar.</li>
+error.syntax=<li>Error de sintáxis en patrón del filtro de la petición.</li>
+error.resource.required=<li>Se requiere el Nombre del Recurso.</li>
+error.resource.javaprefix=<li>El recurso debe de tener el prefijo "java:"</li>
+error.pathName.required=<li>Es necesario poner el nombre de la trayectoria.</li>
+error.driver.required=<li>Es necesario poner el manejador (driver) de la base de datos.</li>
+error.roleNameCol.required=<li>Es necesario poner la columna del nombre de Papel Desempeñado.</li>
+error.userNameCol.required=<li>Es necesario poner la columna del nombre de Usuario.</li>
+error.passwordCol.required=<li>Es necesario poner la columna de la Contraseña.</li>
+error.userTable.required=<li>Es necesario poner la Tabla de Usuario.</li>
+error.roleTable.required=<li>Es necesario poner la Tabla del Papel Desempeñado por el Usuario.</li>
+error.connectionPassword.required=<li>Es necesario poner la contraseña de la base de datos.</li>
+error.connectionURL.required=<li>Es necesario poner la URL de la Base de Datos.</li>
+error.connectionName.required=<li>Es necesario poner el nombre de usuario de la Base de Datos.</li>
+error.roleName.required=<li>Es necesario poner el nombre del Papel Desempeñadoo.</li>
+error.userRoleName.required=<li>Es necesario poner el nombre del Papel Desempeñado por el Usuario.</li>
+error.digest.required=<li>Es necesario poner el algoritmo de resumen (digest).</li>
+error.roleBase.required=<li>Es necesario poner el elemento base del Papel Desempeñado.</li>
+error.rolePattern.required=<li>Es necesario poner el patrón de búsqueda del Papel Desempeñado.</li>
+error.userBase.required=<li>Es necesario poner el elemento base del usuario.</li>
+error.userPassword.required=<li>Es necesario poner la Contraseña del Usuario.</li>
+error.userPattern.required=<li>Es necesario poner el patrón del Usuario.</li>
+error.userSearch.required=<li>Es necesario poner la búsqueda del usuario.</li>
+error.userPattern.userSearch.defined=<li>Se debe de especificar UserPattern o userSearch, pero no ambos.</li>
+error.contextFactory.required=<li>Es necesario poner la Fábrica del Contexto.</li>
+error.connPassword.required=<li>Es necesario poner la Contraseña de la Conexión.</li>
+error.connURL.required=<li>Es necesario poner la URL de la Conexión.</li>
+error.connName.required=<li>Es necesario poner el nombre de Conexión.</li>
+
+# ---------- Server Module ----------
+server.service.treeBuilder.subtreeNode=Servicio
+server.service.treeBuilder.connector=Conectador
+server.service.treeBuilder.host=Host
+server.service.treeBuilder.context=Context 
+server.service.treeBuilder.loggerFor=Logger for {0}
+server.service.treeBuilder.realmFor=Realm for {0} 
+server.service.treeBuilder.logger=Logger
+server.service.treeBuilder.realm=Realm
+
+# ---------- Resources Module ----------
+resources.treeBuilder.subtreeNode=Recursos
+resources.treeBuilder.datasources=Fuentes de Datos
+resources.treeBuilder.mailsessions=Sesiones de Correo
+resources.treeBuilder.resourcelinks=Enlaces de Recurso
+resources.env.entries=Entradas de Entorno
+resources.env.entry=Nombre de Entrada
+resources.env.props=Propiedades de la Entrada de Entorno
+resources.env.override=Pasar por alto Entradas de Nivel de Aplicación
+resources.actions.env.create=Crear Nueva Entrada de Entorno
+resources.actions.env.edit=Editar Entrada de Entorno
+resources.actions.env.delete=Borrar Entradas de Entorno
+resources.actions.env.list=Listar Entradas Existentes
+resources.datasrc.jdbc=Manejador JDBC
+resources.actions.datasrc=Fuentes de Datos
+resources.actions.datasrc.create=Crear Nueva Fuente de Datos
+resources.actions.datasrc.delete=Borrar Funtes de Datos
+resources.actions.datasrc.edit=Editar Fuente de Datos
+resources.datasrc.url=URL de Fuente de Datos
+resources.datasrc.jdbcclass=Clase de Manejador JDBC
+resources.datasrc.connections=Conexiones
+resources.datasrc.active=Máx. Conexiones Activas
+resources.datasrc.idle=Máx. Conexiones Ociosas
+resources.datasrc.wait=Máx. Espera por conexión
+resources.datasrc.validation=Consulta de Validación
+resources.datasrc.jndi=Nombre JNDI
+resources.actions.mailsession=Sesiones De Correo
+resources.actions.mailsession.create=Crear Nueva Sesión de Correo
+resources.actions.mailsession.delete=Borrar Sesión de Correo
+resources.actions.mailsession.edit=Editar Sesión de Correo
+resources.mailsession.name=Nombre
+resources.mailsession.mailhost=mail.smtp.host
+resources.actions.resourcelk=Enlaces de Recurso
+resources.actions.resourcelk.create=Crear Nuevo Enlace de Recurso
+resources.actions.resourcelk.delete=Borrar Enlace de Recurso
+resources.actions.resourcelk.edit=Edtiar Enlace de Recurso
+resources.resourcelk.name=Nombre
+resources.resourcelk.global=Global
+resources.resourcelk.type=Tipo
+resources.error.name.required=<li>Nombre requerido.</li>
+resources.error.global.required=<li>Global requerido.</li>
+resources.error.type.required=<li>Tipo requerido.</li>
+resources.error.value.required=<li>Valor requerido.</li>
+resources.error.value.mismatch=<li>El tipo y el valor no parecen coincidir.</li>
+resources.error.entryType.invalid=<li>El tipo de Entrada no se reconoce.</li>
+resources.error.entryType.notimpl=<li>La Validación para este tipo no ha sido implementada aún.</li>
+resources.error.url.required=<li>Se requiere la URL de Fuente de Datos.</li>
+resources.error.driverClass.required=<li>Se requiere la Clase del Conductor (driver) de JDBC.</li>
+resources.error.active.required=<li>Se requieren las conexiones activas máximas.</li>
+resources.error.idle.required=<li>Se requieren las conexiones ociosas máximas.</li>
+resources.error.wait.required=<li>La espera máxima por una conexión se requiere.</li>
+resources.error.mailhost.required=<li>mail.smtp.host se requiere.</li>
+resources.integer.error=<li>Error de número entero inválido.</li>
+resources.actions.userdb.create=Crear Nueva Base de Datos de Usuario
+resources.actions.userdb.edit=Editar Base de Datos de Usuario
+resources.actions.userdb.delete=Borrar Bases de Datos de Usuario
+resources.userdb.location=Localización
+resources.userdb.factory=Fábrica
+resources.treeBuilder.userdbs=Bases de Datos de Usuario
+resources.error.path.required=<li>Se requiere la Trayectoria</li>
+resources.error.jndiName.required=<li>Se requiere el Nombre JNDI</li>
+resources.invalid.name=<li>Nombre inválido de recurso - el nombre ya existe.</li>
+resources.invalid.env=<li>Nombre inválido de entorno - el nombre ya existe.</li>
+
+# ---------- User Database Module ----------
+users.actions.group.create=Crear Nuevo Grupo
+users.actions.group.delete=Borrar Grupos Existentes
+users.actions.group.list=Listar Grupos Existentes
+users.actions.role.create=Crear Nuevo Papel a Desempeñar
+users.actions.role.delete=Borrar Papeles a Desempeñar ya Existentes
+users.actions.role.list=Listar Papeles a Desempeñar ya Existentes
+users.actions.user.create=Crear Nuevo Usuario
+users.actions.user.delete=Borrar Usuarios ya Existentes
+users.actions.user.list=Listar Usuarios ya Existentes
+users.deleteGroups.title=Borrar Grupos ya Existentes
+users.deleteRoles.title=Borrar Papeles a Desempeñar ya Existentes
+users.deleteUsers.title=Borrar Usuarios ya Existentes
+users.error.attribute.get=Error recuperando atributo {0}
+users.error.attribute.set=Error modificando atributo {0}
+users.error.invoke=Error invocando operación {0}
+users.error.groupname.required=Se requiere el Nombre de Grupo
+users.error.password.required=Contraseña Requerida
+users.error.quotes=La doble comilla no esta permitida en los valores de campo
+users.error.rolename.required=Se requiere el Nombre del Papel a Desempeñar
+users.error.select=Error seleccionando objetos gestionados
+users.error.token=Transacción enviada fuera de servicio
+users.error.username.required=<li>Se requiere el nombre del usuario</li>
+users.group.newGroup=Crear Propiedades de Nuevo Grupo
+users.group.oldGroup=Editar Propiedades de Grupo ya Existente
+users.group.properties=Propiedades de Grupo
+users.list.description=Descripción
+users.list.fullName=Nombre Completo
+users.list.groupname=Nombre de Grupo
+users.list.rolename=Nombre de Papel a Desempeñar
+users.list.username=Nombre de Usuario
+users.listGroups.title=Lista de Grupos
+users.listRoles.title=Lista de Papeles a Desempeñar
+users.listUsers.title=Lista de Usuarios
+users.prompt.description=Descripción:
+users.prompt.fullName=Nombre Completo:
+users.prompt.groupname=Nombre de Grupo:
+users.prompt.password=Contraseña:
+users.prompt.rolename=Nombre de Papel a Desempeñar:
+users.prompt.username=Nombre de Usuario:
+users.role.newRole=Crear Nuevas Propiedades de Papel a Desempeñar
+users.role.oldRole=Editar Propiedades de Papel a Desempeñar Existente
+users.role.properties=Propiedades del Papel a Desempeñar
+users.treeBuilder.groupsNode=Grupos
+users.treeBuilder.rolesNode=Papeles a Desempeñar
+users.treeBuilder.subtreeNode=Definición de Usuario
+users.treeBuilder.usersNode=Usuarios
+users.user.newUser=Crear Nuevas Propiedades de Usuario
+users.user.oldUser=Editar Propiedades de Usuario Existente
+users.user.properties=Propiedades de Usuario
+# ---------- -------------------- ----------

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/ApplicationResources_ja.properties
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/ApplicationResources_ja.properties	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/ApplicationResources_ja.properties	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,444 @@
+application.title=Tomcat\u30b5\u30fc\u30d0\u30fc\u7ba1\u7406\u30b3\u30f3\u30bd\u30fc\u30eb
+errors.header=<h2><fontcolor="red">\u4e0d\u6b63\u306a\u30a8\u30e9\u30fc</font></h2>\u5b9f\u884c\u3059\u308b\u524d\u306b\u3001\u4e0b\u8a18\u306e\u30a8\u30e9\u30fc\u3092\u4fee\u6b63\u3057\u3066\u4e0b\u3055\u3044:<ul>
+errors.footer=</ul><hr>
+error.login=<li>\u30e6\u30fc\u30b6\u540d\u307e\u305f\u306f\u30d1\u30b9\u30ef\u30fc\u30c9\u304c\u9055\u3044\u307e\u3059</li>
+prompt.username=\u30e6\u30fc\u30b6\u540d
+prompt.password=\u30d1\u30b9\u30ef\u30fc\u30c9
+button.login=\u30ed\u30b0\u30a4\u30f3
+button.reset=\u30ea\u30bb\u30c3\u30c8
+button.save=\u4fdd\u5b58
+button.change=\u5909\u66f4
+button.cancel=\u30ea\u30bb\u30c3\u30c8
+button.commit=\u5909\u66f4\u3092\u53cd\u6620
+button.logout=\u30ed\u30b0\u30a2\u30a6\u30c8
+login.enter=\u65b0\u3057\u3044\u30bb\u30c3\u30b7\u30e7\u30f3\u3092\u958b\u59cb\u3059\u308b\u305f\u3081\u306b\u30e6\u30fc\u30b6\u540d\u3068\u30d1\u30b9\u30ef\u30fc\u30c9\u3092\u5165\u529b\u3057\u3066\u304f\u3060\u3055\u3044
+login.changeLanguage=\u8a00\u8a9e\u306e\u5909\u66f4
+error.login=\u30e6\u30fc\u30b6\u540d\u307e\u305f\u306f\u30d1\u30b9\u30ef\u30fc\u30c9\u304c\u9055\u3044\u307e\u3059
+error.tryagain=\u3082\u3046\u4e00\u5ea6\u5b9f\u884c\u3059\u308b\u305f\u3081\u306b\u30af\u30ea\u30c3\u30af\u3057\u3066\u304f\u3060\u3055\u3044
+error.here=\u3053\u3053
+prompt.someText=Some Text
+prompt.moreText=More Text
+sample.someText.required=<li>"Some Text"\u306f\u7a7a\u306b\u3067\u304d\u307e\u305b\u3093</li>
+sample.moreText.required=<li>"More Text"\u306f\u7a7a\u306b\u3067\u304d\u307e\u305b\u3093</li>
+save.success=\u4fdd\u5b58\u6210\u529f!
+save.fail=\u4fdd\u5b58\u5931\u6557!
+server.portnumber=\u30dd\u30fc\u30c8\u756a\u53f7
+server.debuglevel=\u30c7\u30d0\u30c3\u30b0\u30ec\u30d9\u30eb
+server.shutdown=\u30b7\u30e3\u30c3\u30c8\u30c0\u30a6\u30f3
+server.properties=\u30b5\u30fc\u30d0\u30fc\u30d7\u30ed\u30d1\u30c6\u30a3
+warning.header=<center><h4><fontcolor="red">\u8b66\u544a!</font></h4></center><ul>
+server.port.warning=<li>1024\u756a\u4ee5\u4e0b\u306e\u30dd\u30fc\u30c8\u756a\u53f7\u306e\u5229\u7528\u306b\u306f\u3001\u7279\u5225\u306a\u30bd\u30d5\u30c8\u30a6\u30a7\u30a2\u6a29\u9650\u304c\u5fc5\u8981\u3067\u3059\u3002
+error.portNumber.required=<li>\u30dd\u30fc\u30c8\u756a\u53f7\u304c\u6307\u5b9a\u3055\u308c\u3066\u3044\u307e\u305b\u3093</li>
+error.portNumber.format=<li>\u30dd\u30fc\u30c8\u756a\u53f7\u304c\u59a5\u5f53\u306a\u6574\u6570\u3067\u306f\u3042\u308a\u307e\u305b\u3093</li>
+error.portNumber.range=<li>\u30dd\u30fc\u30c8\u756a\u53f7\u304c\u7bc4\u56f2\u5916\u3067\u3059\u3002\u7bc4\u56f2\u306f1-65535\u3067\u3059\u3002</li>
+error.shutdownText.length=<li>\u30b7\u30e3\u30c3\u30c8\u30c0\u30a6\u30f3\u306e\u30d1\u30b9\u30ef\u30fc\u30c9\u306f6\u5b57\u4ee5\u4e0a\u3067\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093</li>
+error.engineName.required=<li>\u30a8\u30f3\u30b8\u30f3\u540d\u306f\u7701\u7565\u3067\u304d\u307e\u305b\u3093</li>
+error.acceptCountText.required=<li>\u540c\u6642\u63a5\u7d9a\u6570\u304c\u5fc5\u8981\u3067\u3059</li>
+error.acceptCountText.format=<li>\u540c\u6642\u63a5\u7d9a\u6570\u304c\u59a5\u5f53\u306a\u6574\u6570\u3067\u306f\u3042\u308a\u307e\u305b\u3093</li>
+error.acceptCountText.range=<li>\u540c\u6642\u63a5\u7d9a\u6570\u304c\u7bc4\u56f2\u5916\u3067\u3059. \u7bc4\u56f2\u306f0-128\u3067\u3059\u3002</li>
+error.connTimeOutText.required=<li>\u63a5\u7d9a\u30bf\u30a4\u30e0\u30a2\u30a6\u30c8\u304c\u5fc5\u8981\u3067\u3059</li>
+error.connTimeOutText.format=<li>\u63a5\u7d9a\u30bf\u30a4\u30e0\u30a2\u30a6\u30c8\u304c\u59a5\u5f53\u306a\u6574\u6570\u3067\u306f\u3042\u308a\u307e\u305b\u3093</li>
+error.connTimeOutText.range=<li>\u63a5\u7d9a\u30bf\u30a4\u30e0\u30a2\u30a6\u30c8\u304c\u7bc4\u56f2\u5916\u3067\u3059\u3002\u7bc4\u56f2\u306f0-60000\u3067\u3059\u3002</li>
+error.bufferSizeText.required=<li>\u30d0\u30c3\u30d5\u30a1\u30b5\u30a4\u30ba\u304c\u5fc5\u8981\u3067\u3059</li>
+error.bufferSizeText.format=<li>\u30d0\u30c3\u30d5\u30a1\u30b5\u30a4\u30ba\u304c\u59a5\u5f53\u306a\u6574\u6570\u3067\u306f\u3042\u308a\u307e\u305b\u3093</li>
+error.bufferSizeText.range=<li>\u30d0\u30c3\u30d5\u30a1\u30b5\u30a4\u30ba\u304c\u7bc4\u56f2\u5916\u3067\u3059\u3002\u7bc4\u56f2\u306f1-8192\u3067\u3059\u3002</li>
+error.address.invalid=<li>IP\u30a2\u30c9\u30ec\u30b9\u304c\u4e0d\u6b63\u3067\u3059</li>
+error.redirectPortText.required=<li>\u30ea\u30c0\u30a4\u30ec\u30af\u30c8\u30dd\u30fc\u30c8\u756a\u53f7\u304c\u6307\u5b9a\u3055\u308c\u3066\u3044\u307e\u305b\u3093</li>
+error.redirectPortText.format=<li>\u30ea\u30c0\u30a4\u30ec\u30af\u30c8\u30dd\u30fc\u30c8\u756a\u53f7\u304c\u59a5\u5f53\u306a\u6574\u6570\u3067\u306f\u3042\u308a\u307e\u305b\u3093</li>
+error.redirectPortText.range=<li>\u30ea\u30c0\u30a4\u30ec\u30af\u30c8\u30dd\u30fc\u30c8\u756a\u53f7\u304c\u7bc4\u56f2\u5916\u3067\u3059\u3002\u7bc4\u56f2\u306f1-65535\u3067\u3059\u3002</li>
+error.minProcessorsText.required=<li>\u6700\u5c0f\u30d7\u30ed\u30bb\u30b9\u6570\u304c\u6307\u5b9a\u3055\u308c\u3066\u3044\u307e\u305b\u3093</li>
+error.minProcessorsText.format=<li>\u6700\u5c0f\u30d7\u30ed\u30bb\u30b9\u6570\u304c\u59a5\u5f53\u306a\u6574\u6570\u3067\u306f\u3042\u308a\u307e\u305b\u3093</li>
+error.minProcessorsText.range=<li>\u6700\u5c0f\u30d7\u30ed\u30bb\u30b9\u6570\u304c\u7bc4\u56f2\u5916\u3067\u3059\u3002\u7bc4\u56f2\u306f1-512\u3067\u3059\u3002</li>
+error.maxProcessorsText.required=<li>\u6700\u5927\u30d7\u30ed\u30bb\u30b9\u6570\u304c\u6307\u5b9a\u3055\u308c\u3066\u3044\u307e\u305b\u3093</li>
+error.maxProcessorsText.format=<li>\u6700\u5927\u30d7\u30ed\u30bb\u30b9\u6570\u304c\u59a5\u5f53\u306a\u6574\u6570\u3067\u306f\u3042\u308a\u307e\u305b\u3093</li>
+error.maxProcessorsText.range=<li>\u6700\u5927\u30d7\u30ed\u30bb\u30b9\u6570\u304c\u7bc4\u56f2\u5916\u3067\u3059\u3002\u7bc4\u56f2\u306f1-512\u3067\u3059. \u307e\u305f\u3001\u6700\u5927\u30d7\u30ed\u30bb\u30b9\u6570 >= \u6700\u5c0f\u30d7\u30ed\u30bb\u30b9\u6570\u3001\u3067\u306a\u3051\u308c\u3070\u306a\u308a\u307e\u305b\u3093\u3002</li>
+error.proxyName.invalid=<li>\u30d7\u30ed\u30ad\u30b7\u540d\u304c\u4e0d\u6b63\u3067\u3059</li>
+error.proxyPortText.required=<li>\u30d7\u30ed\u30ad\u30b7\u30dd\u30fc\u30c8\u756a\u53f7\u304c\u6307\u5b9a\u3055\u308c\u3066\u3044\u307e\u305b\u3093</li>
+error.proxyPortText.format=<li>\u30d7\u30ed\u30ad\u30b7\u30dd\u30fc\u30c8\u756a\u53f7\u304c\u59a5\u5f53\u306a\u6574\u6570\u3067\u306f\u3042\u308a\u307e\u305b\u3093</li>
+error.proxyPortText.range=<li>\u30d7\u30ed\u30ad\u30b7\u30dd\u30fc\u30c8\u756a\u53f7\u304c\u7bc4\u56f2\u5916\u3067\u3059\u3002\u7bc4\u56f2\u306f1-65535\u3067\u3059\u3002</li>
+error.hostName.bad=\u30db\u30b9\u30c8\u540d {0} \u304c\u4e0d\u6b63\u3067\u3059
+error.hostName.required=<li>\u30db\u30b9\u30c8\u540d\u306f\u7701\u7565\u3067\u304d\u307e\u305b\u3093</li>
+error.hostName.exists=<li>\u540c\u540d\u306e\u30db\u30b9\u30c8\u540d\u304c\u65e2\u306b\u5b58\u5728\u3057\u307e\u3059</li>
+error.appBase.required=<li>\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u30d9\u30fc\u30b9\u306f\u7701\u7565\u3067\u304d\u307e\u305b\u3093</li>
+service.name=\u540d\u524d
+service.engine.props=\u30a8\u30f3\u30b8\u30f3\u30d7\u30ed\u30d1\u30c6\u30a3
+service.defaulthostname=\u30c7\u30d5\u30a9\u30eb\u30c8\u30db\u30b9\u30c8\u540d
+service.properties=\u30b5\u30fc\u30d3\u30b9\u30d7\u30ed\u30d1\u30c6\u30a3
+service.property=\u30d7\u30ed\u30d1\u30c6\u30a3
+service.value=\u5024
+service.create.new=\u65b0\u3057\u3044\u30b5\u30fc\u30d3\u30b9\u306e\u4f5c\u6210
+actions.available.actions=\u5229\u7528\u53ef\u80fd\u306a\u30a2\u30af\u30b7\u30e7\u30f3
+actions.services.create=\u65b0\u3057\u3044\u30b5\u30fc\u30d3\u30b9\u306e\u4f5c\u6210
+actions.services.delete=\u73fe\u5728\u306e\u30b5\u30fc\u30d3\u30b9\u3092\u524a\u9664
+actions.services.deletes=\u65e2\u5b58\u306e\u30b5\u30fc\u30d3\u30b9\u306e\u524a\u9664
+actions.services.edit=\u65e2\u5b58\u306e\u30b5\u30fc\u30d3\u30b9\u306e\u7de8\u96c6
+actions.accesslogger.create=\u65b0\u3057\u3044\u30a2\u30af\u30bb\u30b9Logger\u306e\u4f5c\u6210
+actions.accesslogger.delete=\u30a2\u30af\u30bb\u30b9Logger\u306e\u524a\u9664
+actions.connectors.create=\u65b0\u3057\u3044\u30b3\u30cd\u30af\u30bf\u306e\u4f5c\u6210
+actions.connectors.delete=\u73fe\u5728\u306e\u30b3\u30cd\u30af\u30bf\u3092\u524a\u9664
+actions.connectors.deletes=\u65e2\u5b58\u306e\u30b3\u30cd\u30af\u30bf\u306e\u524a\u9664
+actions.connectors.edit=\u65e2\u5b58\u306e\u30b3\u30cd\u30af\u30bf\u306e\u7de8\u96c6
+actions.contexts.create=\u65b0\u3057\u3044\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u306e\u4f5c\u6210
+actions.contexts.delete=\u73fe\u5728\u306e\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u3092\u524a\u9664
+actions.contexts.deletes=\u65e2\u5b58\u306e\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u306e\u524a\u9664
+actions.contexts.edit=\u65e2\u5b58\u306e\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u306e\u7de8\u96c6
+actions.defaultcontexts.create=\u65b0\u3057\u3044\u30c7\u30d5\u30a9\u30eb\u30c8\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u306e\u4f5c\u6210
+actions.defaultcontexts.delete=\u73fe\u5728\u306e\u30c7\u30d5\u30a9\u30eb\u30c8\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u3092\u524a\u9664
+actions.defaultcontexts.deletes=\u65e2\u5b58\u306e\u30c7\u30d5\u30a9\u30eb\u30c8\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u306e\u524a\u9664
+actions.defaultcontexts.edit=\u65e2\u5b58\u306e\u30c7\u30d5\u30a9\u30eb\u30c8\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u306e\u7de8\u96c6
+actions.group.create=\u65b0\u3057\u3044\u30b0\u30eb\u30fc\u30d7\u306e\u4f5c\u6210
+actions.group.delete=\u65e2\u5b58\u306e\u30b0\u30eb\u30fc\u30d7\u306e\u524a\u9664
+actions.hosts.create=\u65b0\u3057\u3044\u30db\u30b9\u30c8\u306e\u4f5c\u6210
+actions.hosts.delete=\u73fe\u5728\u306e\u30db\u30b9\u30c8\u3092\u524a\u9664
+actions.hosts.deletes=\u65e2\u5b58\u306e\u30db\u30b9\u30c8\u306e\u524a\u9664
+actions.hosts.edit=\u65e2\u5b58\u306e\u30db\u30b9\u30c8\u306e\u7de8\u96c6
+actions.loggers.create=\u65b0\u3057\u3044Logger\u306e\u4f5c\u6210
+actions.loggers.delete=\u73fe\u5728\u306eLogger\u3092\u524a\u9664
+actions.loggers.deletes=\u65e2\u5b58\u306eLoggers\u306e\u524a\u9664
+actions.loggers.edit=\u65e2\u5b58\u306eLogger\u306e\u7de8\u96c6
+actions.realms.create=\u65b0\u3057\u3044\u30e6\u30fc\u30b6\u30ec\u30eb\u30e0\u306e\u4f5c\u6210
+actions.realms.delete=\u73fe\u5728\u306e\u30e6\u30fc\u30b6\u30ec\u30eb\u30e0\u306e\u524a\u9664
+actions.realms.deletes=\u30e6\u30fc\u30b6\u30ec\u30eb\u30e0\u306e\u524a\u9664
+actions.realms.edit=\u65e2\u5b58\u306e\u30ec\u30eb\u30e0\u306e\u7de8\u96c6
+actions.requestfilter.create=\u65b0\u3057\u3044\u30ea\u30af\u30a8\u30b9\u30c8\u30d5\u30a3\u30eb\u30bf\u306e\u4f5c\u6210
+actions.requestfilter.delete=\u30ea\u30af\u30a8\u30b9\u30c8\u30d5\u30a3\u30eb\u30bf\u306e\u524a\u9664
+actions.user.create=\u65b0\u3057\u3044\u30e6\u30fc\u30b6\u306e\u4f5c\u6210
+actions.user.delete=\u65e2\u5b58\u306e\u30e6\u30fc\u30b6\u306e\u524a\u9664
+actions.valves.create=\u65b0\u3057\u3044\u30d0\u30eb\u30d6\u306e\u4f5c\u6210
+actions.valves.edit=\u30d0\u30eb\u30d6\u306e\u7de8\u96c6
+actions.valves.delete=\u73fe\u5728\u306e\u30d0\u30eb\u30d6\u3092\u524a\u9664
+actions.valves.deletes=\u65e2\u5b58\u306e\u30d0\u30eb\u30d6\u306e\u524a\u9664
+actions.alias.create=\u65b0\u3057\u3044\u30a8\u30a4\u30ea\u30a2\u30b9\u306e\u4f5c\u6210
+actions.alias.delete=\u30a8\u30a4\u30ea\u30a2\u30b9\u306e\u524a\u9664
+new.alias=\u65b0\u3057\u3044\u30a8\u30a4\u30ea\u30a2\u30b9
+connector.type=\u7a2e\u985e
+connector.scheme=\u30b9\u30ad\u30fc\u30e0
+connector.accept.count=\u540c\u6642\u63a5\u7d9a\u6570
+connector.compression=\u5727\u7e2e
+connector.connection.linger=\u63a5\u7d9a\u306e\u6b8b\u5b58[linger]
+connector.connection.timeout=\u63a5\u7d9a\u30bf\u30a4\u30e0\u30a2\u30a6\u30c8
+connector.connection.uploadTimeout=\u30a2\u30c3\u30d7\u30ed\u30fc\u30c9\u30bf\u30a4\u30e0\u30a2\u30a6\u30c8
+connector.default.buffer=\u30c7\u30d5\u30a9\u30eb\u30c8\u30d0\u30c3\u30d5\u30a1\u30b5\u30a4\u30ba
+connector.connection.disableUploadTimeout=\u30a2\u30c3\u30d7\u30ed\u30fc\u30c9\u30bf\u30a4\u30e0\u30a2\u30a6\u30c8\u306e\u7121\u52b9\u5316
+connector.enable.dns=DNS\u306e\u30eb\u30c3\u30af\u30a2\u30c3\u30d7
+connector.uriencoding=URI \u30a8\u30f3\u30b3\u30fc\u30c7\u30a3\u30f3\u30b0
+connector.useBodyEncodingForURI=URI\u30af\u30a8\u30ea\u30d1\u30e9\u30e1\u30fc\u30bf\u306b\u30dc\u30c7\u30a3\u306e\u30a8\u30f3\u30b3\u30fc\u30c7\u30a3\u30f3\u30b0\u3092\u4f7f\u7528
+connector.allowTrace=TRACE\u30e1\u30bd\u30c3\u30c9\u3092\u8a31\u53ef
+connector.address.ip=IP\u30a2\u30c9\u30ec\u30b9
+connector.redirect.portnumber=\u30ea\u30c0\u30a4\u30ec\u30af\u30c8\u30dd\u30fc\u30c8\u756a\u53f7
+connector.min=\u6700\u5c0f
+connector.milliseconds=\u30df\u30ea\u79d2
+connector.max=\u6700\u5927
+connector.maxkeepalive=\u30ad\u30fc\u30d7\u30a2\u30e9\u30a4\u30d6\u30ea\u30af\u30a8\u30b9\u30c8\u6700\u5927\u6570
+connector.maxspare=\u4e88\u5099\u30b9\u30ec\u30c3\u30c9\u6700\u5927\u6570
+connector.maxthreads=\u30b9\u30ec\u30c3\u30c9\u6700\u5927\u6570
+connector.minspare=\u4e88\u5099\u30b9\u30ec\u30c3\u30c9\u6700\u5c0f\u6570
+connector.threadpriority=Processor Thread Priority
+connector.proxy.name=\u30d7\u30ed\u30ad\u30b7\u540d
+connector.proxy.portnumber=\u30d7\u30ed\u30ad\u30b7\u30dd\u30fc\u30c8\u756a\u53f7
+connector.algorithm=\u30a2\u30eb\u30b4\u30ea\u30ba\u30e0
+connector.ciphers=\u6697\u53f7\u5316\u65b9\u5f0f
+connector.client.auth=\u30af\u30e9\u30a4\u30a2\u30f3\u30c8\u8a8d\u8a3c
+connector.keystore.filename=\u30ad\u30fc\u30b9\u30c8\u30a2\u30d5\u30a1\u30a4\u30eb\u540d
+connector.keystore.password=\u30ad\u30fc\u30b9\u30c8\u30a2\u30d1\u30b9\u30ef\u30fc\u30c9
+connector.keystore.type=\u30ad\u30fc\u30b9\u30c8\u30a2\u306e\u7a2e\u985e
+connector.sslProtocol=SSL\u30d7\u30ed\u30c8\u30b3\u30eb
+connector.keyPass.warning=<li>keytool\u3092\u4f7f\u3063\u3066\u8a3c\u660e\u66f8\u3092\u4f5c\u6210\u3057\u3066\u4e0b\u3055\u3044\u3002</li>
+connector.secure=SSL\u901a\u4fe1
+connector.tcpNoDelay=TCP\u9045\u5ef6\u7121\u3057
+connector.xpoweredby=X Powered By \u30d8\u30c3\u30c0
+host.properties=\u30db\u30b9\u30c8\u30d7\u30ed\u30d1\u30c6\u30a3
+host.name=\u540d\u524d
+host.base=\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u30d9\u30fc\u30b9
+host.autoDeploy=\u81ea\u52d5\u914d\u5099
+host.deployXML=\u914d\u5099XML
+host.deployOnStartup=\u8d77\u52d5\u6642\u306e\u914d\u5099
+host.wars=WAR\u30d5\u30a1\u30a4\u30eb\u3092\u5c55\u958b\u3059\u308b
+host.aliases=\u30a8\u30a4\u30ea\u30a2\u30b9
+host.alias.name=\u30a8\u30a4\u30ea\u30a2\u30b9\u540d
+host.xmlNamespaceAware=XML\u540d\u524d\u7a7a\u9593\u5bfe\u5fdc
+host.xmlValidation=XML\u691c\u8a3c
+error.aliasName.exists=<li>\u540c\u540d\u306e\u30a8\u30a4\u30ea\u30a2\u30b9\u304c\u65e2\u306b\u5b58\u5728\u3057\u307e\u3059</li>
+error.aliasName.required=<li>\u30a8\u30a4\u30ea\u30a2\u30b9\u540d\u306f\u7701\u7565\u3067\u304d\u307e\u305b\u3093</li>
+context.properties=\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u30d7\u30ed\u30d1\u30c6\u30a3
+context.cookies=\u30af\u30c3\u30ad\u30fc
+context.cross.context=\u30af\u30ed\u30b9\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8
+context.docBase=\u30c9\u30ad\u30e5\u30e1\u30f3\u30c8\u30d9\u30fc\u30b9
+context.override=\u4e0a\u66f8\u304d
+context.path=\u30d1\u30b9
+context.reloadable=\u518d\u30ed\u30fc\u30c9\u53ef\u80fd
+context.swallowOutput=\u6a19\u6e96\u51fa\u529b\u30fb\u6a19\u6e96\u30a8\u30e9\u30fc\u51fa\u529b\u3092\u30ed\u30b0\u30d5\u30a1\u30a4\u30eb\u306b\u51fa\u529b
+context.usenaming=\u30cd\u30fc\u30e0\u30b5\u30fc\u30d3\u30b9\u306e\u5229\u7528
+context.workdir=\u30ef\u30fc\u30ad\u30f3\u30b0\u30c7\u30a3\u30ec\u30af\u30c8\u30ea
+context.loader.properties=\u30ed\u30fc\u30c0\u30d7\u30ed\u30d1\u30c6\u30a3
+context.sessionmgr.properties=\u30bb\u30c3\u30b7\u30e7\u30f3\u30de\u30cd\u30fc\u30b8\u30e3\u30d7\u30ed\u30d1\u30c6\u30a3
+context.checkInterval=\u30c1\u30a7\u30c3\u30af\u9593\u9694
+context.sessionId=\u30bb\u30c3\u30b7\u30e7\u30f3ID\u30a4\u30cb\u30b7\u30e3\u30e9\u30a4\u30b6
+context.max.sessions=\u6700\u5927\u6709\u52b9\u30bb\u30c3\u30b7\u30e7\u30f3\u6570
+defaultcontext.properties=\u30c7\u30d5\u30a9\u30eb\u30c8\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u30d7\u30ed\u30d1\u30c6\u30a3
+error.context.directory=\u30c9\u30ad\u30e5\u30e1\u30f3\u30c8\u30d9\u30fc\u30b9\u304c\u5b58\u5728\u3057\u306a\u3044\uff0c\u53c8\u306f\u8aad\u3081\u306a\u3044\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u3067\u3059
+error.docBase.required=<li>\u30c9\u30ad\u30e5\u30e1\u30f3\u30c8\u30d9\u30fc\u30b9\u306fnull\u306b\u3067\u304d\u307e\u305b\u3093</li>
+error.path.required=<li>\u30d1\u30b9\u306fnull\u306b\u3067\u304d\u307e\u305b\u3093</li>
+error.workDir.required=<li>\u30ef\u30fc\u30ad\u30f3\u30b0\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u306fnull\u306b\u3067\u304d\u307e\u305b\u3093</li>
+error.ldrCheckInterval.required=<li>\u30ed\u30fc\u30c0\u30c1\u30a7\u30c3\u30af\u9593\u9694\u304c\u6307\u5b9a\u3055\u308c\u3066\u3044\u307e\u305b\u3093</li>
+error.ldrCheckInterval.format=<li>\u30ed\u30fc\u30c0\u30c1\u30a7\u30c3\u30af\u9593\u9694\u304c\u59a5\u5f53\u306a\u6574\u6570\u3067\u306f\u3042\u308a\u307e\u305b\u3093</li>
+error.ldrCheckInterval.range=<li>\u30ed\u30fc\u30c0\u30c1\u30a7\u30c3\u30af\u9593\u9694\u304c\u7bc4\u56f2\u5916\u3067\u3059\u3002\u7bc4\u56f2\u306f1-1000\u3067\u3059\u3002</li>
+error.mgrCheckInterval.required=<li>\u30de\u30cd\u30fc\u30b8\u30e3\u30c1\u30a7\u30c3\u30af\u9593\u9694\u304c\u6307\u5b9a\u3055\u308c\u3066\u3044\u307e\u305b\u3093</li>
+error.mgrCheckInterval.format=<li>\u30de\u30cd\u30fc\u30b8\u30e3\u30c1\u30a7\u30c3\u30af\u9593\u9694\u304c\u59a5\u5f53\u306a\u6574\u6570\u3067\u306f\u3042\u308a\u307e\u305b\u3093</li>
+error.mgrCheckInterval.range=<li>\u30de\u30cd\u30fc\u30b8\u30e3\u30c1\u30a7\u30c3\u30af\u9593\u9694\u304c\u7bc4\u56f2\u5916\u3067\u3059\u3002\u7bc4\u56f2\u306f1-1000\u3067\u3059\u3002</li>
+error.mgrSessionIDInit.required=<li>\u30bb\u30c3\u30b7\u30e7\u30f3\u30de\u30cd\u30fc\u30b8\u30e3\u521d\u671f\u5316ID\u304c\u6307\u5b9a\u3055\u308c\u3066\u3044\u307e\u305b\u3093</li>
+error.mgrMaxSessions.required=<li>\u6700\u5927\u30bb\u30c3\u30b7\u30e7\u30f3\u6570\u304c\u6307\u5b9a\u3055\u308c\u3066\u3044\u307e\u305b\u3093</li>
+error.mgrMaxSessions.format=<li>\u6700\u5927\u30bb\u30c3\u30b7\u30e7\u30f3\u6570\u304c\u59a5\u5f53\u306a\u6574\u6570\u3067\u306f\u3042\u308a\u307e\u305b\u3093</li>
+error.mgrMaxSessions.range=<li>\u6700\u5927\u30bb\u30c3\u30b7\u30e7\u30f3\u6570\u304c\u7bc4\u56f2\u5916\u3067\u3059\u3002\u7bc4\u56f2\u306f-1\u304b\u3089100\u3067\u3059\u3002</li>
+list.none=(None)
+logger.directory=\u30c7\u30a3\u30ec\u30af\u30c8\u30ea
+logger.prefix=\u30d7\u30ea\u30d5\u30a3\u30c3\u30af\u30b9
+logger.suffix=\u30b5\u30d5\u30a3\u30c3\u30af\u30b9
+logger.timestamp=\u30bf\u30a4\u30e0\u30b9\u30bf\u30f3\u30d7
+logger.filelogger.properties=FileLogger\u56fa\u6709\u306e\u30d7\u30ed\u30d1\u30c6\u30a3
+logger.verbositylevel=\u5197\u9577\u30ec\u30d9\u30eb
+error.loggerName.bad=\u4e0d\u6b63\u306aLogger\u540d {0}
+error.loggerName.exists=<li>\u540c\u540d\u306eLogger\u304c\u65e2\u306b\u5b58\u5728\u3057\u307e\u3059\u3002</li>
+error.directory.required=<li>\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u304c\u6307\u5b9a\u3055\u308c\u3066\u3044\u307e\u305b\u3093\u3002</li>
+error.prefix.required=<li>\u30d7\u30ea\u30d5\u30a3\u30c3\u30af\u30b9\u304c\u6307\u5b9a\u3055\u308c\u3066\u3044\u307e\u305b\u3093\u3002</li>
+error.suffix.required=<li>\u30b5\u30d5\u30a3\u30c3\u30af\u30b9\u304c\u6307\u5b9a\u3055\u308c\u3066\u3044\u307e\u305b\u3093\u3002</li>
+error.valveName.bad=\u4e0d\u6b63\u306a\u30d0\u30eb\u30d6\u540d {0}
+error.vavlveName.exists=<li>\u540c\u540d\u306e\u30d0\u30eb\u30d6\u304c\u65e2\u306b\u5b58\u5728\u3057\u307e\u3059</li>
+error.singleSignOn.exists=<li>SingleSignOn\u30d0\u30eb\u30d6\u304c\u65e2\u306b\u5b58\u5728\u3057\u307e\u3059</li>
+user.fullName=\u30d5\u30eb\u30cd\u30fc\u30e0
+user.groups=\u30b0\u30eb\u30fc\u30d7\u4e2d\u306e\u30e1\u30f3\u30d0
+user.newUser=\u65b0\u3057\u3044\u30e6\u30fc\u30b6\u30d7\u30ed\u30d1\u30c6\u30a3\u306e\u4f5c\u6210
+user.oldUser=\u65e2\u5b58\u306e\u30e6\u30fc\u30b6\u30d7\u30ed\u30d1\u30c6\u30a3\u306e\u7de8\u96c6
+user.password=\u30d1\u30b9\u30ef\u30fc\u30c9
+user.properties=\u30e6\u30fc\u30b6\u30d7\u30ed\u30d1\u30c6\u30a3
+user.roles=\u30bb\u30ad\u30e5\u30ea\u30c6\u30a3\u30ed\u30fc\u30eb
+user.username=\u30e6\u30fc\u30b6\u540d
+error.password.required=<li>\u30d1\u30b9\u30ef\u30fc\u30c9\u306f\u7701\u7565\u3067\u304d\u307e\u305b\u3093</li>
+error.username.required=<li>\u30e6\u30fc\u30b6\u540d\u306f\u7701\u7565\u3067\u304d\u307e\u305b\u3093</li>
+error.get.attributes=\u30d7\u30ed\u30d1\u30c6\u30a3\u306e\u56de\u5fa9\u6642\u306b\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f\u3002
+error.set.attributes=\u30d7\u30ed\u30d1\u30c6\u30a3\u306e\u8a2d\u5b9a\u6642\u306b\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f\u3002
+actions.delete=\u524a\u9664
+error.defaultHost.required=<li>\u30c7\u30d5\u30a9\u30eb\u30c8\u30db\u30b9\u30c8\u540d\u304c\u5fc5\u8981\u3067\u3059</li>
+error.engineName.bad=\u30a8\u30f3\u30b8\u30f3\u540d {0} \u304c\u4e0d\u6b63\u3067\u3059
+error.engineName.exists=<li>\u30a8\u30f3\u30b8\u30f3\u540d\u304c\u65e2\u306b\u5b58\u5728\u3057\u307e\u3059</li>
+error.serviceName.bad=\u30b5\u30fc\u30d3\u30b9\u540d {0} \u304c\u4e0d\u6b63\u3067\u3059
+error.serviceName.required=<li>\u30b5\u30fc\u30d3\u30b9\u540d\u304c\u5fc5\u8981\u3067\u3059</li>
+error.serviceName.exists=<li>\u540c\u540d\u306e\u30b5\u30fc\u30d3\u30b9\u540d\u304c\u65e2\u306b\u5b58\u5728\u3057\u307e\u3059</li>
+error.jdbcrealm=JDBCRealm\u306e\u8a2d\u5b9a\u4e2d\u306b\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f\u3002
+error.jndirealm=JNDIRealm\u306e\u8a2d\u5b9a\u4e2d\u306b\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f\u3002
+error.userdbrealm=UserdatabaseRealm\u306e\u8a2d\u5b9a\u4e2d\u306b\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f\u3002
+error.realmName.bad=\u30ec\u30eb\u30e0\u540d {0} \u304c\u4e0d\u6b63\u3067\u3059
+error.realmName.required=<li>\u30ec\u30eb\u30e0\u540d\u304c\u5fc5\u8981\u3067\u3059\u3002</li>
+error.realmName.exists=<li>\u540c\u540d\u306e\u30ec\u30eb\u30e0\u304c\u65e2\u306b\u5b58\u5728\u3057\u307e\u3059\u3002</li>
+error.contextName.bad=\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u540d {0} \u304c\u4e0d\u6b63\u3067\u3059
+error.contextName.exists=<li>\u540c\u540d\u306e\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u304c\u65e2\u306b\u5b58\u5728\u3057\u307e\u3059\u3002</li>
+error.defaultcontextName.exists=<li>\u540c\u540d\u306e\u30c7\u30d5\u30a9\u30eb\u30c8\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u304c\u65e2\u306b\u5b58\u5728\u3057\u307e\u3059\u3002</li>
+error.path.prefix=<li>\u30d1\u30b9\u306f'/'\u3067\u59cb\u307e\u3089\u306a\u3051\u308c\u3070\u306a\u308a\u307e\u305b\u3093\u3002</li>
+error.loaderName.bad=\u30ed\u30fc\u30c0\u540d {0} \u304c\u4e0d\u6b63\u3067\u3059
+error.managerName.bad=\u30de\u30cd\u30fc\u30b8\u30e3\u540d {0} \u304c\u4e0d\u6b63\u3067\u3059
+error.connectorName.bad=\u30b3\u30cd\u30af\u30bf\u540d {0} \u304c\u4e0d\u6b63\u3067\u3059
+error.connectorName.exists=<li>\u540c\u540d\u306e\u30b3\u30cd\u30af\u30bf\u304c\u65e2\u306b\u5b58\u5728\u3057\u307e\u3059</li>
+error.pattern.required=<li>\u30d1\u30bf\u30fc\u30f3\u306f\u7701\u7565\u3067\u304d\u307e\u305b\u3093</li>
+error.valveName.bad=\u4e0d\u6b63\u306a\u30d0\u30eb\u30d6\u540d {0}
+error.valveName.exists=<li>\u540c\u540d\u306e\u30d0\u30eb\u30d6\u304c\u65e2\u306b\u5b58\u5728\u3057\u307e\u3059</li>
+realm.driver=\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u30c9\u30e9\u30a4\u30d0
+realm.passwd=\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u30d1\u30b9\u30ef\u30fc\u30c9
+realm.url=\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9URL
+realm.userName=\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u30e6\u30fc\u30b6\u540d
+realm.digest=\u30c0\u30a4\u30b8\u30a7\u30b9\u30c8\u30a2\u30eb\u30b4\u30ea\u30ba\u30e0
+realm.passwordCol=\u30d1\u30b9\u30ef\u30fc\u30c9\u30ab\u30e9\u30e0
+realm.roleNameCol=\u30ed\u30fc\u30eb\u540d\u30ab\u30e9\u30e0
+realm.userNameCol=\u30e6\u30fc\u30b6\u540d\u30ab\u30e9\u30e0
+realm.userRoleTable=\u30e6\u30fc\u30b6\u30ed\u30fc\u30eb\u30c6\u30fc\u30d6\u30eb
+realm.userTable=\u30e6\u30fc\u30b6\u30c6\u30fc\u30d6\u30eb
+realm.resource=\u30ea\u30bd\u30fc\u30b9\u540d
+realm.pathName=\u30d1\u30b9\u540d
+realm.connName=\u63a5\u7d9a\u540d
+realm.connPassword=\u63a5\u7d9a\u30d1\u30b9\u30ef\u30fc\u30c9
+realm.connURL=\u63a5\u7d9aURL
+realm.connFactory=\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u30d5\u30a1\u30af\u30c8\u30ea
+realm.roleBase=\u30ed\u30fc\u30eb\u57fa\u672c\u8981\u7d20
+realm.roleName=\u30ed\u30fc\u30eb\u540d
+realm.user.roleName=\u30e6\u30fc\u30b6\u30ed\u30fc\u30eb\u540d
+realm.pattern=\u30ed\u30fc\u30eb\u691c\u7d22\u30d1\u30bf\u30fc\u30f3
+realm.role.subtree=\u30ed\u30fc\u30eb\u306e\u30b5\u30d6\u30c4\u30ea\u30fc\u306e\u691c\u7d22
+realm.userBase=\u30e6\u30fc\u30b6\u57fa\u672c\u8981\u7d20
+realm.user.subtree=\u30e6\u30fc\u30b6\u306e\u30b5\u30d6\u30c4\u30ea\u30fc\u306e\u691c\u7d22
+realm.userPassword=\u30e6\u30fc\u30b6\u30d1\u30b9\u30ef\u30fc\u30c9
+realm.userPattern=\u30e6\u30fc\u30b6\u30d1\u30bf\u30fc\u30f3
+realm.userSearch=\u30e6\u30fc\u30b6\u691c\u7d22
+realm.dataSourceName=\u30c7\u30fc\u30bf\u30bd\u30fc\u30b9\u540d
+realm.localDataSource=\u30ed\u30fc\u30ab\u30eb\u30c7\u30fc\u30bf\u30bd\u30fc\u30b9
+realm.userCredCol==\u30e6\u30fc\u30b6\u30af\u30ec\u30c7\u30f3\u30b7\u30e3\u30eb\u30b3\u30e9\u30e0
+valve.access.properties=\u30a2\u30af\u30bb\u30b9Logger\u30d7\u30ed\u30d1\u30c6\u30a3
+valve.request.properties=\u30ea\u30af\u30a8\u30b9\u30c8\u30d5\u30a3\u30eb\u30bf\u30d7\u30ed\u30d1\u30c6\u30a3
+valve.single.properties=\u30b7\u30f3\u30b0\u30eb\u30b5\u30a4\u30f3\u30aa\u30f3\u30d0\u30eb\u30d6\u30d7\u30ed\u30d1\u30c6\u30a3
+valve.remotehost.properties=\u30ea\u30e2\u30fc\u30c8\u30db\u30b9\u30c8\u30d0\u30eb\u30d6\u30d7\u30ed\u30d1\u30c6\u30a3
+valve.remoteaddress.properties=\u30ea\u30e2\u30fc\u30c8\u30a2\u30c9\u30ec\u30b9\u30d0\u30eb\u30d6\u30d7\u30ed\u30d1\u30c6\u30a3
+valve.resolveHosts=\u30db\u30b9\u30c8\u540d\u306e\u89e3\u6c7a
+valve.rotatable=\u30ed\u30fc\u30c6\u30fc\u30c8\u53ef\u80fd
+valve.pattern=\u30d1\u30bf\u30fc\u30f3
+valve.allowHosts=\u8a31\u53ef\u3059\u308b\u30db\u30b9\u30c8
+valve.denyHosts=\u62d2\u5426\u3059\u308b\u30db\u30b9\u30c8
+valve.allowIPs=\u8a31\u53ef\u3059\u308bIP\u30a2\u30c9\u30ec\u30b9
+valve.denyIPs=\u62d2\u5426\u3059\u308bIP\u30a2\u30c9\u30ec\u30b9
+error.allowHost=<li>allow\u304c\u7121\u52b9\u3067\u3059\u3002\u7ba1\u7406\u8005\u306e\u30db\u30b9\u30c8\u540d\u3092\u542b\u3081\u308b\u5fc5\u8981\u304c\u3042\u308a\u307e\u3059\u3002</li>+error.denyHost=<li>deny\u304c\u7121\u52b9\u3067\u3059\u3002\u7ba1\u7406\u8005\u306e\u30db\u30b9\u30c8\u540d\u3092\u9664\u304f\u5fc5\u8981\u304c\u3042\u308a\u307e\u3059\u3002</li>
+error.allowIP=<li>allow\u304c\u7121\u52b9\u3067\u3059\u3002\u7ba1\u7406\u8005\u306eIP\u30a2\u30c9\u30ec\u30b9\u3092\u542b\u3081\u308b\u5fc5\u8981\u304c\u3042\u308a\u307e\u3059\u3002</li>
+error.denyIP=<li>deny\u304c\u7121\u52b9\u3067\u3059\u3002\u7ba1\u7406\u8005\u306eIP\u30a2\u30c9\u30ec\u30b9\u3092\u9664\u304f\u5fc5\u8981\u304c\u3042\u308a\u307e\u3059\u3002</li>
+error.allow.deny.required=<li>allow\u53c8\u306fdeny\u304c\u5fc5\u8981\u3067\u3059\u3002</li>
+error.syntax=<li>\u30ea\u30af\u30a8\u30b9\u30c8\u30d5\u30a3\u30eb\u30bf\u30d1\u30bf\u30fc\u30f3\u306e\u4e2d\u3067\u69cb\u6587\u30a8\u30e9\u30fc\u3067\u3059\u3002</li>
+error.resource.required=<li>\u30ea\u30bd\u30fc\u30b9\u540d\u306f\u7701\u7565\u3067\u304d\u307e\u305b\u3093\u3002</li>
+error.resource.javaprefix=<li>\u30ea\u30bd\u30fc\u30b9\u306b\u306f"java:"\u306e\u30d7\u30ea\u30d5\u30a3\u30af\u30b9\u304c\u5fc5\u8981\u3067\u3059\u3002</li>
+error.pathName.required=<li>\u30d1\u30b9\u540d\u306f\u7701\u7565\u3067\u304d\u307e\u305b\u3093\u3002</li>
+error.driver.required=<li>\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u30c9\u30e9\u30a4\u30d0\u306f\u7701\u7565\u3067\u304d\u307e\u305b\u3093\u3002</li>
+error.roleNameCol.required=<li>\u30ed\u30fc\u30eb\u540d\u30ab\u30e9\u30e0\u306f\u7701\u7565\u3067\u304d\u307e\u305b\u3093\u3002</li>
+error.userNameCol.required=<li>\u30e6\u30fc\u30b6\u540d\u30ab\u30e9\u30e0\u306f\u7701\u7565\u3067\u304d\u307e\u305b\u3093\u3002</li>
+error.passwordCol.required=<li>\u30d1\u30b9\u30ef\u30fc\u30c9\u30ab\u30e9\u30e0\u306f\u7701\u7565\u3067\u304d\u307e\u305b\u3093\u3002</li>
+error.userTable.required=<li>\u30e6\u30fc\u30b6\u30c6\u30fc\u30d6\u30eb\u306f\u7701\u7565\u3067\u304d\u307e\u305b\u3093\u3002</li>
+error.roleTable.required=<li>\u30e6\u30fc\u30b6\u30ed\u30fc\u30eb\u30c6\u30fc\u30d6\u30eb\u306f\u7701\u7565\u3067\u304d\u307e\u305b\u3093\u3002</li>
+error.connectionPassword.required=<li>\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u30d1\u30b9\u30ef\u30fc\u30c9\u306f\u7701\u7565\u3067\u304d\u307e\u305b\u3093\u3002</li>
+error.connectionURL.required=<li>\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9URL\u306f\u7701\u7565\u3067\u304d\u307e\u305b\u3093\u3002</li>
+error.connectionName.required=<li>\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u30e6\u30fc\u30b6\u540d\u306f\u7701\u7565\u3067\u304d\u307e\u305b\u3093\u3002</li>
+error.roleName.required=<li>\u30ed\u30fc\u30eb\u540d\u306f\u7701\u7565\u3067\u304d\u307e\u305b\u3093\u3002</li>
+error.userRoleName.required=<li>\u30e6\u30fc\u30b6\u30ed\u30fc\u30eb\u540d\u306f\u7701\u7565\u3067\u304d\u307e\u305b\u3093\u3002</li>
+error.digest.required=<li>\u30c0\u30a4\u30b8\u30a7\u30b9\u30c8\u30a2\u30eb\u30b4\u30ea\u30ba\u30e0\u306f\u7701\u7565\u3067\u304d\u307e\u305b\u3093\u3002</li>
+error.roleBase.required=<li>\u30ed\u30fc\u30eb\u57fa\u672c\u8981\u7d20\u306f\u7701\u7565\u3067\u304d\u307e\u305b\u3093\u3002</li>
+error.rolePattern.required=<li>\u30ed\u30fc\u30eb\u691c\u7d22\u30d1\u30bf\u30fc\u30f3\u306f\u7701\u7565\u3067\u304d\u307e\u305b\u3093\u3002</li>
+error.userBase.required=<li>\u30e6\u30fc\u30b6\u57fa\u672c\u8981\u7d20\u306f\u7701\u7565\u3067\u304d\u307e\u305b\u3093\u3002</li>
+error.userPassword.required=<li>\u30e6\u30fc\u30b6\u30d1\u30b9\u30ef\u30fc\u30c9\u306f\u7701\u7565\u3067\u304d\u307e\u305b\u3093\u3002</li>
+error.userPattern.required=<li>\u30e6\u30fc\u30b6\u30d1\u30bf\u30fc\u30f3\u306f\u7701\u7565\u3067\u304d\u307e\u305b\u3093\u3002</li>
+error.userSearch.required=<li>\u30e6\u30fc\u30b6\u691c\u7d22\u306f\u7701\u7565\u3067\u304d\u307e\u305b\u3093\u3002</li>
+error.userPattern.userSearch.defined=<li>\u30e6\u30fc\u30b6\u30d1\u30bf\u30fc\u30f3\u307e\u305f\u306f\u30e6\u30fc\u30b6\u691c\u7d22\u306e\u3044\u305a\u308c\u304b\u4e00\u65b9\u306e\u307f\u3092\u6307\u5b9a\u3057\u307e\u3059. \u4e21\u65b9\u6307\u5b9a\u3059\u308b\u3053\u3068\u306f\u3067\u304d\u307e\u305b\u3093\u3002</li>
+error.contextFactory.required=<li>\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u30d5\u30a1\u30af\u30c8\u30ea\u306f\u7701\u7565\u3067\u304d\u307e\u305b\u3093\u3002</li>
+error.connPassword.required=<li>\u63a5\u7d9a\u30d1\u30b9\u30ef\u30fc\u30c9\u306f\u7701\u7565\u3067\u304d\u307e\u305b\u3093\u3002</li>
+error.connURL.required=<li>\u63a5\u7d9aURL\u306f\u7701\u7565\u3067\u304d\u307e\u305b\u3093\u3002</li>
+error.connName.required=<li>\u63a5\u7d9a\u540d\u306f\u7701\u7565\u3067\u304d\u307e\u305b\u3093\u3002</li>
+error.dataSourceName.required=<li>\u30c7\u30fc\u30bf\u30bd\u30fc\u30b9\u540d\u304c\u5fc5\u8981\u3067\u3059\u3002</li>
+error.userCredCol.required=<li>\u30e6\u30fc\u30b6\u30af\u30ec\u30c7\u30f3\u30b7\u30e3\u30eb\u304c\u5fc5\u8981\u3067\u3059\u3002</li>
+error.userRoleTable.required=<li>\u30e6\u30fc\u30b6\u306e\u30ed\u30fc\u30eb\u30c6\u30fc\u30d6\u30eb\u304c\u5fc5\u8981\u3067\u3059\u3002</li>
+
+# ---------- Server Module ----------
+server.service.treeBuilder.subtreeNode=\u30b5\u30fc\u30d3\u30b9
+server.service.treeBuilder.connector=\u30b3\u30cd\u30af\u30bf
+server.service.treeBuilder.host=\u30db\u30b9\u30c8
+server.service.treeBuilder.context=\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8
+server.service.treeBuilder.loggerFor={0}\u306e\u30ed\u30ac\u30fc 
+server.service.treeBuilder.realmFor={0}\u306e\u30ec\u30eb\u30e0
+server.service.treeBuilder.logger=\u30ed\u30ac\u30fc 
+server.service.treeBuilder.realm=\u30ec\u30eb\u30e0
+
+# ---------- Resources Module ----------
+resources.treeBuilder.subtreeNode=\u30ea\u30bd\u30fc\u30b9
+resources.treeBuilder.datasources=\u30c7\u30fc\u30bf\u30bd\u30fc\u30b9
+resources.treeBuilder.mailsessions=\u30e1\u30fc\u30eb\u30bb\u30c3\u30b7\u30e7\u30f3
+resources.treeBuilder.resourcelinks=\u30ea\u30bd\u30fc\u30b9\u30ea\u30f3\u30af
+resources.env.entries=\u74b0\u5883\u30a8\u30f3\u30c8\u30ea
+resources.env.entry=\u30a8\u30f3\u30c8\u30ea\u540d
+resources.env.props=\u74b0\u5883\u30a8\u30f3\u30c8\u30ea\u30d7\u30ed\u30d1\u30c6\u30a3
+resources.env.override=\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u30ec\u30d9\u30eb\u30a8\u30f3\u30c8\u30ea\u3092\u4e0a\u66f8\u304d
+resources.actions.env.create=\u65b0\u3057\u3044\u74b0\u5883\u30a8\u30f3\u30c8\u30ea\u306e\u4f5c\u6210
+resources.actions.env.edit=\u74b0\u5883\u30a8\u30f3\u30c8\u30ea\u306e\u7de8\u96c6
+resources.actions.env.delete=\u74b0\u5883\u30a8\u30f3\u30c8\u30ea\u306e\u524a\u9664
+resources.actions.env.list=\u65e2\u5b58\u306e\u30a8\u30f3\u30c8\u30ea\u306e\u4e00\u89a7
+resources.datasrc.jdbc=JDBC\u30c9\u30e9\u30a4\u30d0
+resources.actions.datasrc=\u30c7\u30fc\u30bf\u30bd\u30fc\u30b9
+resources.actions.datasrc.create=\u65b0\u3057\u3044\u30c7\u30fc\u30bf\u30bd\u30fc\u30b9\u306e\u4f5c\u6210
+resources.actions.datasrc.delete=\u30c7\u30fc\u30bf\u30bd\u30fc\u30b9\u306e\u524a\u9664
+resources.actions.datasrc.edit=\u30c7\u30fc\u30bf\u30bd\u30fc\u30b9\u306e\u7de8\u96c6
+resources.datasrc.url=\u30c7\u30fc\u30bf\u30bd\u30fc\u30b9URL
+resources.datasrc.jdbcclass=JDBC\u30c9\u30e9\u30a4\u30d0\u30af\u30e9\u30b9
+resources.datasrc.connections=\u63a5\u7d9a
+resources.datasrc.active=\u6709\u52b9\u306a\u6700\u5927\u63a5\u7d9a\u6570
+resources.datasrc.idle=\u30a2\u30a4\u30c9\u30eb\u72b6\u614b\u306e\u6700\u5927\u63a5\u7d9a\u6570
+resources.datasrc.wait=\u6700\u5927\u63a5\u7d9a\u5f85\u3061\u6642\u9593
+resources.datasrc.validation=\u30af\u30a8\u30ea\u306e\u691c\u8a3c
+resources.datasrc.jndi=JNDI\u540d
+resources.actions.mailsession=\u30e1\u30fc\u30eb\u30bb\u30c3\u30b7\u30e7\u30f3
+resources.actions.mailsession.create=\u65b0\u3057\u3044\u30e1\u30fc\u30eb\u30bb\u30c3\u30b7\u30e7\u30f3\u306e\u4f5c\u6210
+resources.actions.mailsession.delete=\u30e1\u30fc\u30eb\u30bb\u30c3\u30b7\u30e7\u30f3\u306e\u524a\u9664
+resources.actions.mailsession.edit=\u30e1\u30fc\u30eb\u30bb\u30c3\u30b7\u30e7\u30f3\u306e\u7de8\u96c6
+resources.mailsession.name=\u540d\u524d
+resources.mailsession.mailhost=SMTP\u30db\u30b9\u30c8\u540d
+resources.actions.resourcelk=\u30ea\u30bd\u30fc\u30b9\u30ea\u30f3\u30af
+resources.actions.resourcelk.create=\u65b0\u3057\u3044\u30ea\u30bd\u30fc\u30b9\u30ea\u30f3\u30af\u306e\u4f5c\u6210
+resources.actions.resourcelk.delete=\u30ea\u30bd\u30fc\u30b9\u30ea\u30f3\u30af\u306e\u524a\u9664
+resources.actions.resourcelk.edit=\u30ea\u30bd\u30fc\u30b9\u30ea\u30f3\u30af\u306e\u7de8\u96c6
+resources.resourcelk.name=\u540d\u524d
+resources.resourcelk.global=\u30b0\u30ed\u30fc\u30d0\u30eb
+resources.resourcelk.type=\u578b
+resources.error.name.required=<li>\u540d\u524d\u306f\u7701\u7565\u3067\u304d\u307e\u305b\u3093\u3002</li>
+resources.error.global.required=<li>\u30b0\u30ed\u30fc\u30d0\u30eb\u306f\u7701\u7565\u3067\u304d\u307e\u305b\u3093\u3002</li>
+resources.error.type.required=<li>\u578b\u306f\u7701\u7565\u3067\u304d\u307e\u305b\u3093\u3002</li>
+resources.error.value.required=<li>\u5024\u306f\u7701\u7565\u3067\u304d\u307e\u305b\u3093\u3002</li>
+resources.error.value.mismatch=<li>\u578b\u3068\u5024\u304c\u9069\u5408\u3057\u307e\u305b\u3093\u3002</li>
+resources.error.entryType.invalid=<li>\u30a8\u30f3\u30c8\u30ea\u30bf\u30a4\u30d7\u3092\u8a8d\u8b58\u3067\u304d\u307e\u305b\u3093\u3002</li>
+resources.error.entryType.notimpl=<li>\u3053\u306e\u578b\u306b\u5bfe\u3059\u308b\u59a5\u5f53\u6027\u30c1\u30a7\u30c3\u30ab\u306f\u307e\u3060\u5b9f\u88c5\u3055\u308c\u3066\u3044\u307e\u305b\u3093\u3002</li>
+resources.error.url.required=<li>\u30c7\u30fc\u30bf\u30bd\u30fc\u30b9URL\u306f\u7701\u7565\u3067\u304d\u307e\u305b\u3093\u3002</li>
+resources.error.driverClass.required=<li>JDBC\u30c9\u30e9\u30a4\u30d0\u30af\u30e9\u30b9\u306f\u7701\u7565\u3067\u304d\u307e\u305b\u3093\u3002</li>
+resources.error.active.required=<li>\u6709\u52b9\u306a\u6700\u5927\u63a5\u7d9a\u6570\u306f\u7701\u7565\u3067\u304d\u307e\u305b\u3093\u3002</li>
+resources.error.idle.required=<li>\u30a2\u30a4\u30c9\u30eb\u72b6\u614b\u306e\u6700\u5927\u63a5\u7d9a\u6570\u306f\u7701\u7565\u3067\u304d\u307e\u305b\u3093\u3002</li>
+resources.error.wait.required=<li>\u6700\u5927\u63a5\u7d9a\u5f85\u3061\u6642\u9593\u306f\u7701\u7565\u3067\u304d\u307e\u305b\u3093\u3002</li>
+resources.error.mailhost.required=<li>SMTP\u30db\u30b9\u30c8\u540d\u306f\u7701\u7565\u3067\u304d\u307e\u305b\u3093\u3002</li>
+resources.integer.error=<li>\u4e0d\u6b63\u306a\u6574\u6570\u3067\u3059\u3002</li>
+resources.actions.userdb.create=\u65b0\u3057\u3044\u30e6\u30fc\u30b6\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u306e\u4f5c\u6210
+resources.actions.userdb.edit=\u30e6\u30fc\u30b6\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u306e\u7de8\u96c6
+resources.actions.userdb.delete=\u30e6\u30fc\u30b6\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u306e\u524a\u9664
+resources.userdb.location=\u30ed\u30b1\u30fc\u30b7\u30e7\u30f3
+resources.userdb.factory=\u30d5\u30a1\u30af\u30c8\u30ea
+resources.treeBuilder.databases=\u30e6\u30fc\u30b6\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9
+resources.error.path.required=<li>\u30d1\u30b9\u306f\u7701\u7565\u3067\u304d\u307e\u305b\u3093</li>
+resources.error.jndiName.required=<li>JNDI\u540d\u306f\u7701\u7565\u3067\u304d\u307e\u305b\u3093</li>
+resources.invalid.name=<li>\u7121\u52b9\u306a\u30ea\u30bd\u30fc\u30b9\u540d - \u540d\u524d\u306f\u65e2\u306b\u5b58\u5728\u3057\u307e\u3059\u3002</li>
+resources.invalid.env=<li>\u7121\u52b9\u306a\u74b0\u5883\u540d - \u540d\u524d\u306f\u65e2\u306b\u5b58\u5728\u3057\u307e\u3059\u3002</li>
+
+# ---------- User Database Module ----------
+users.actions.group.create=\u65b0\u3057\u3044\u30b0\u30eb\u30fc\u30d7\u306e\u4f5c\u6210
+users.actions.group.delete=\u65e2\u5b58\u306e\u30b0\u30eb\u30fc\u30d7\u306e\u524a\u9664
+users.actions.group.list=\u65e2\u5b58\u306e\u30b0\u30eb\u30fc\u30d7\u306e\u4e00\u89a7
+users.actions.role.create=\u65b0\u3057\u3044\u30ed\u30fc\u30eb\u306e\u4f5c\u6210
+users.actions.role.delete=\u65e2\u5b58\u306e\u30ed\u30fc\u30eb\u306e\u524a\u9664
+users.actions.role.list=\u65e2\u5b58\u306e\u30ed\u30fc\u30eb\u306e\u4e00\u89a7
+users.actions.user.create=\u65b0\u3057\u3044\u30e6\u30fc\u30b6\u306e\u4f5c\u6210
+users.actions.user.delete=\u65e2\u5b58\u306e\u30e6\u30fc\u30b6\u306e\u524a\u9664
+users.actions.user.list=\u65e2\u5b58\u306e\u30e6\u30fc\u30b6\u306e\u4e00\u89a7
+users.deleteGroups.title=\u65e2\u5b58\u306e\u30b0\u30eb\u30fc\u30d7\u306e\u524a\u9664
+users.deleteRoles.title=\u65e2\u5b58\u306e\u30ed\u30fc\u30eb\u306e\u524a\u9664
+users.deleteUsers.title=\u65e2\u5b58\u306e\u30e6\u30fc\u30b6\u306e\u524a\u9664
+users.error.attribute.get=\u5c5e\u6027\u306e\u56de\u5fa9\u6642\u306b\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f {0}
+users.error.attribute.set=\u5c5e\u6027\u306e\u5909\u66f4\u6642\u306b\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f {0}
+users.error.invoke=\u30aa\u30da\u30ec\u30fc\u30b7\u30e7\u30f3\u306e\u8d77\u52d5\u6642\u306b\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f {0}
+users.error.groupname.required=\u30b0\u30eb\u30fc\u30d7\u540d\u306f\u7701\u7565\u3067\u304d\u307e\u305b\u3093
+users.error.password.required=\u30d1\u30b9\u30ef\u30fc\u30c9\u306f\u7701\u7565\u3067\u304d\u307e\u305b\u3093
+users.error.quotes=\u30c0\u30d6\u30eb\u30af\u30a9\u30fc\u30c8\u306f\u3001\u30d5\u30a3\u30fc\u30eb\u30c9\u5024\u306b\u5229\u7528\u3067\u304d\u307e\u305b\u3093
+users.error.rolename.required=\u30ed\u30fc\u30eb\u540d\u306f\u7701\u7565\u3067\u304d\u307e\u305b\u3093
+users.error.select=\u7ba1\u7406\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u306e\u9078\u629e\u6642\u306b\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f
+users.error.token=\u4e0d\u9069\u5207\u306a\u30c8\u30e9\u30f3\u30b6\u30af\u30b7\u30e7\u30f3\u304c\u767a\u884c\u3055\u308c\u307e\u3057\u305f
+users.error.username.required=<li>\u30e6\u30fc\u30b6\u540d\u306f\u7701\u7565\u3067\u304d\u307e\u305b\u3093</li>
+users.group.newGroup=\u65b0\u3057\u3044\u30b0\u30eb\u30fc\u30d7\u30d7\u30ed\u30d1\u30c6\u30a3\u306e\u4f5c\u6210
+users.group.oldGroup=\u65e2\u5b58\u306e\u30b0\u30eb\u30fc\u30d7\u30d7\u30ed\u30d1\u30c6\u30a3\u306e\u7de8\u96c6
+users.group.properties=\u30b0\u30eb\u30fc\u30d7\u30d7\u30ed\u30d1\u30c6\u30a3
+users.list.description=\u8aac\u660e
+users.list.fullName=\u30d5\u30eb\u30cd\u30fc\u30e0
+users.list.groupname=\u30b0\u30eb\u30fc\u30d7\u540d
+users.list.rolename=\u30ed\u30fc\u30eb\u540d
+users.list.username=\u30e6\u30fc\u30b6\u540d
+users.listGroups.title=\u30b0\u30eb\u30fc\u30d7\u4e00\u89a7
+users.listRoles.title=\u30ed\u30fc\u30eb\u4e00\u89a7
+users.listUsers.title=\u30e6\u30fc\u30b6\u4e00\u89a7
+users.prompt.description=\u8aac\u660e:
+users.prompt.fullName=\u30d5\u30eb\u30cd\u30fc\u30e0:
+users.prompt.groupname=\u30b0\u30eb\u30fc\u30d7\u540d:
+users.prompt.password=\u30d1\u30b9\u30ef\u30fc\u30c9:
+users.prompt.rolename=\u30ed\u30fc\u30eb\u540d:
+users.prompt.username=\u30e6\u30fc\u30b6\u540d:
+users.role.newRole=\u65b0\u3057\u3044\u30ed\u30fc\u30eb\u30d7\u30ed\u30d1\u30c6\u30a3\u306e\u4f5c\u6210
+users.role.oldRole=\u65e2\u5b58\u306e\u30ed\u30fc\u30eb\u30d7\u30ed\u30d1\u30c6\u30a3\u306e\u7de8\u96c6
+users.role.properties=\u30ed\u30fc\u30eb\u30d7\u30ed\u30d1\u30c6\u30a3
+users.treeBuilder.groupsNode=\u30b0\u30eb\u30fc\u30d7
+users.treeBuilder.rolesNode=\u30ed\u30fc\u30eb
+users.treeBuilder.subtreeNode=\u30e6\u30fc\u30b6\u5b9a\u7fa9
+users.treeBuilder.usersNode=\u30e6\u30fc\u30b6
+users.user.newUser=\u65b0\u3057\u3044\u30e6\u30fc\u30b6\u30d7\u30ed\u30d1\u30c6\u30a3\u306e\u4f5c\u6210
+users.user.oldUser=\u65e2\u5b58\u306e\u30e6\u30fc\u30b6\u30d7\u30ed\u30d1\u30c6\u30a3\u306e\u7de8\u96c6
+users.user.properties=\u30e6\u30fc\u30b6\u30d7\u30ed\u30d1\u30c6\u30a3
+# ---------- -------------------- ----------

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/ApplicationServlet.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/ApplicationServlet.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/ApplicationServlet.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,163 @@
+/*
+ * Copyright 2001,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.admin;
+
+import java.text.DateFormat;
+import java.util.HashSet;
+import java.util.Locale;
+import java.util.ResourceBundle;
+import javax.management.MBeanServer;
+import javax.servlet.ServletException;
+import javax.servlet.UnavailableException;
+import org.apache.commons.modeler.Registry;
+import org.apache.struts.action.ActionServlet;
+import org.apache.struts.util.MessageResources;
+
+
+/**
+ * Subclass of ActionServlet that adds caching of the supported locales in the
+ * ApplicationLocales class.
+ *
+ * @author Patrick Luby
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class ApplicationServlet extends ActionServlet {
+
+
+    // ----------------------------------------------------- Manifest Constants
+
+
+    /**
+     * The application scope key under which we store our
+     * <code>ApplicationLocales</code> instance.
+     */
+    public static final String LOCALES_KEY = "applicationLocales";
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The managed beans Registry used to look up metadata.
+     */
+    protected Registry registry = null;
+
+
+    /**
+     * The JMX MBeanServer we will use to look up management beans.
+     */
+    protected MBeanServer server = null;
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Convenience method to make the managed beans Registry available.
+     *
+     * @exception ServletException if the Registry is not available
+     */
+    public Registry getRegistry() throws ServletException {
+
+        if (registry == null)
+            initRegistry();
+        return (this.registry);
+
+    }
+
+
+    /**
+     * Convenience method to make the JMX MBeanServer available.
+     *
+     * @exception ServletException if the MBeanServer is not available
+     */
+    public MBeanServer getServer() throws ServletException {
+
+        if (server == null)
+            initServer();
+        return (this.server);
+
+    }
+
+
+    /**
+     * Initialize this servlet.
+     *
+     * @exception ServletException if an initialization error occurs.
+     */
+    public void init() throws javax.servlet.ServletException {
+        super.init();
+        initApplicationLocales();
+    }
+
+
+    // ---------------------------------------------------- Protected Methods
+
+
+    /**
+     * Create and initialize the ApplicationLocales object, and make it
+     * available as a servlet context attribute.
+     */
+    protected void initApplicationLocales() {
+
+        ApplicationLocales locales = new ApplicationLocales(this);
+        getServletContext().setAttribute(LOCALES_KEY, locales);
+
+    }
+
+
+    /**
+     * Validate the existence of the Registry that should have been
+     * provided to us by an instance of
+     * <code>org.apache.catalina.mbean.ServerLifecycleListener</code>
+     * enabled at startup time.
+     *
+     * @exception ServletException if we cannot find the Registry
+     */
+    protected void initRegistry() throws ServletException {
+
+        registry = Registry.getRegistry();
+        //(Registry) getServletContext().getAttribute
+        //    ("org.apache.catalina.Registry");
+        if (registry == null)
+            throw new UnavailableException("Registry is not available");
+
+    }
+
+
+    /**
+     * Validate the existence of the MBeanServer that should have been
+     * provided to us by an instance of
+     * <code>org.apache.catalina.mbean.ServerLifecycleListener</code>
+     * enabled at startup time.
+     *
+     * @exception ServletException if we cannot find the MBeanServer
+     */
+    protected void initServer() throws ServletException {
+
+        server = Registry.getRegistry().getMBeanServer();
+        //(MBeanServer) getServletContext().getAttribute
+        //    ("org.apache.catalina.MBeanServer");
+        if (server == null)
+            throw new UnavailableException("MBeanServer is not available");
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/AttributeTag.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/AttributeTag.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/AttributeTag.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,204 @@
+/*
+ * Copyright 2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.admin;
+
+
+import java.io.IOException;
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+import javax.servlet.jsp.JspException;
+import javax.servlet.jsp.JspWriter;
+import javax.servlet.jsp.PageContext;
+import javax.servlet.jsp.tagext.TagSupport;
+import org.apache.commons.beanutils.PropertyUtils;
+
+
+
+/**
+ * Custom tag that retrieves a JMX MBean attribute value, and writes it
+ * out to the current output stream.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 303952 $ $Date: 2005-06-11 10:53:16 -0500 (Sat, 11 Jun 2005) $
+ */
+
+public class AttributeTag extends TagSupport {
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * The attribute name on the JMX MBean to be retrieved.
+     */
+    protected String attribute = null;
+
+    public String getAttribute() {
+        return (this.attribute);
+    }
+
+    public void setAttribute(String attribute) {
+        this.attribute = attribute;
+    }
+
+
+    /**
+     * The bean name to be retrieved.
+     */
+    protected String name = null;
+
+    public String getName() {
+        return (this.name);
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+
+    /**
+     * The property name to be retrieved.
+     */
+    protected String property = null;
+
+    public String getProperty() {
+        return (this.property);
+    }
+
+    public void setProperty(String property) {
+        this.property = property;
+    }
+
+
+    /**
+     * The scope in which the bean should be searched.
+     */
+    protected String scope = null;
+
+    public String getScope() {
+        return (this.scope);
+    }
+
+    public void setScope(String scope) {
+        this.scope = scope;
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Render the JMX MBean attribute identified by this tag
+     *
+     * @exception JspException if a processing exception occurs
+     */
+    public int doEndTag() throws JspException {
+
+        // Retrieve the object name identified by our attributes
+        Object bean = null;
+        if (scope == null) {
+            bean = pageContext.findAttribute(name);
+        } else if ("page".equalsIgnoreCase(scope)) {
+            bean = pageContext.getAttribute(name, PageContext.PAGE_SCOPE);
+        } else if ("request".equalsIgnoreCase(scope)) {
+            bean = pageContext.getAttribute(name, PageContext.REQUEST_SCOPE);
+        } else if ("session".equalsIgnoreCase(scope)) {
+            bean = pageContext.getAttribute(name, PageContext.SESSION_SCOPE);
+        } else if ("application".equalsIgnoreCase(scope)) {
+            bean = pageContext.getAttribute(name,
+                                            PageContext.APPLICATION_SCOPE);
+        } else {
+            throw new JspException("Invalid scope value '" + scope + "'");
+        }
+        if (bean == null) {
+            throw new JspException("No bean '" + name + "' found");
+        }
+        if (property != null) {
+            try {
+                bean = PropertyUtils.getProperty(bean, property);
+            } catch (Throwable t) {
+                throw new JspException
+                    ("Exception retrieving property '" + property + "': " + t);
+            }
+            if (bean == null) {
+                throw new JspException("No property '" + property + "' found");
+            }
+        }
+
+        // Convert to an object name as necessary
+        ObjectName oname = null;
+        try {
+            if (bean instanceof ObjectName) {
+                oname = (ObjectName) bean;
+            } else if (bean instanceof String) {
+                oname = new ObjectName((String) bean);
+            } else {
+                oname = new ObjectName(bean.toString());
+            }
+        } catch (Throwable t) {
+            throw new JspException("Exception creating object name for '" +
+                                   bean + "': " + t);
+        }
+
+        // Acquire a reference to our MBeanServer
+        MBeanServer mserver =
+            (MBeanServer) pageContext.getAttribute
+            ("org.apache.catalina.MBeanServer", PageContext.APPLICATION_SCOPE);
+        if (mserver == null)
+            throw new JspException("MBeanServer is not available");
+
+        // Retrieve the specified attribute from the specified MBean
+        Object value = null;
+        try {
+            value = mserver.getAttribute(oname, attribute);
+        } catch (Throwable t) {
+            throw new JspException("Exception retrieving attribute '" +
+                                   attribute + "' from mbean '" +
+                                   oname.toString() + "'");
+        }
+
+        // Render this value to our current output writer
+        if (value != null) {
+            JspWriter out = pageContext.getOut();
+            try {
+                out.print(value);
+            } catch (IOException e) {
+                throw new JspException("IOException: " + e);
+            }
+        }
+
+        // Evaluate the remainder of this page
+        return (EVAL_PAGE);
+
+    }
+
+
+    /**
+     * Release all current state.
+     */
+    public void release() {
+
+        attribute = null;
+        name = null;
+        property = null;
+        scope = null;
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/CommitChangesAction.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/CommitChangesAction.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/CommitChangesAction.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,127 @@
+/*
+ * Copyright 2001,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.admin;
+
+
+import java.io.IOException;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Locale;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+import org.apache.struts.action.Action;
+import org.apache.struts.action.ActionErrors;
+import org.apache.struts.action.ActionForm;
+import org.apache.struts.action.ActionForward;
+import org.apache.struts.action.ActionMapping;
+
+import org.apache.struts.util.MessageResources;
+
+import javax.management.MBeanServer;
+import javax.management.ObjectInstance;
+import javax.management.ObjectName;
+import javax.management.JMException;
+
+/**
+ * Implementation of <strong>Action</strong> that saves the current settings
+ * and writes them out to server.xml
+ *
+ * @author Manveen Kaur
+ * @version $Revision: 303390 $ $Date: 2004-10-18 01:37:56 -0500 (Mon, 18 Oct 2004) $
+ */
+
+public final class CommitChangesAction extends Action {
+
+    /**
+     * The MBeanServer we will be interacting with.
+     */
+    private MBeanServer mBServer = null;
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Process the specified HTTP request, and create the corresponding HTTP
+     * response (or forward to another web component that will create it).
+     * Return an <code>ActionForward</code> instance describing where and how
+     * control should be forwarded, or <code>null</code> if the response has
+     * already been completed.
+     *
+     * @param mapping The ActionMapping used to select this instance
+     * @param actionForm The optional ActionForm bean for this request (if any)
+     * @param request The HTTP request we are processing
+     * @param response The HTTP response we are creating
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception ServletException if a servlet exception occurs
+     */
+    public ActionForward execute(ActionMapping mapping,
+                                 ActionForm form,
+                                 HttpServletRequest request,
+                                 HttpServletResponse response)
+        throws IOException, ServletException {
+
+        // Acquire a reference to the MBeanServer containing our MBeans
+        try {
+            mBServer = ((ApplicationServlet) getServlet()).getServer();
+        } catch (Throwable t) {
+            throw new ServletException
+            ("Cannot acquire MBeanServer reference", t);
+        }
+
+       // Acquire the resources that we need
+        HttpSession session = request.getSession();
+        Locale locale = getLocale(request);
+        MessageResources resources = getResources(request);
+        
+       ObjectName sname = null;    
+        try {
+           sname = new ObjectName(TomcatTreeBuilder.DEFAULT_DOMAIN +
+                                    TomcatTreeBuilder.SERVER_TYPE);
+        } catch (Exception e) {
+            String message = "Could not get Server Object";
+            getServlet().log(message);
+            response.sendError(HttpServletResponse.SC_BAD_REQUEST, message);
+            return (null);
+        }
+        
+       String operation = "storeConfig";
+       try {           
+            mBServer.invoke(sname, operation, null, null);            
+        } catch (Throwable t) {
+            getServlet().log
+            (resources.getMessage(locale, "users.error.invoke",
+                                  operation), t);
+            response.sendError
+                (HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
+                resources.getMessage(locale, "users.error.invoke",
+                                     operation));
+            return (null);            
+        }
+ 
+
+        getServlet().log("Debugging -- changes saved to conf/server.xml");
+        // Forward control back to the banner
+        return (mapping.findForward("Banner"));
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/DataTag.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/DataTag.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/DataTag.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,127 @@
+/*
+ * Copyright 2001,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.admin;
+
+
+import java.io.IOException;
+import java.net.URLEncoder;
+import java.util.ArrayList;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.jsp.JspException;
+import javax.servlet.jsp.JspWriter;
+import javax.servlet.jsp.PageContext;
+import javax.servlet.jsp.tagext.BodyTagSupport;
+import javax.servlet.jsp.tagext.Tag;
+
+
+/**
+ * <p>Nested tag that represents an individual "data" for a row.  This tag
+ * is valid <strong>only</strong> when nested within a RowTag tag.
+ *
+ * <p>In addition, the body content of this tag is used as the user-visible
+ * data for the action, so that it may be conveniently localized.</p>
+ *
+ * <strong>FIXME</strong> - Internationalize the exception messages!
+ *
+ * @author Manveen Kaur
+ * @version $Revision: 302726 $
+ */
+
+public class DataTag extends BodyTagSupport {
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The data that will be rendered for this table row.
+     */
+    protected String data = null;
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Process the start of this tag.
+     *
+     * @exception JspException if a JSP exception has occurred
+     */
+    public int doStartTag() throws JspException {
+
+        // Initialize the holder for our data text
+        this.data = null;
+
+        // Do no further processing for now
+        return (EVAL_BODY_TAG);
+
+    }
+
+
+    /**
+     * Process the body text of this tag (if any).
+     *
+     * @exception JspException if a JSP exception has occurred
+     */
+    public int doAfterBody() throws JspException {
+
+        String data = bodyContent.getString();
+        if (data != null) {
+            data = data.trim();
+            if (data.length() > 0)
+                this.data = data;
+        }
+        return (SKIP_BODY);
+
+    }
+
+
+    /**
+     * Record this action with our surrounding ActionsTag instance.
+     *
+     * @exception JspException if a processing error occurs
+     */
+    public int doEndTag() throws JspException {
+
+        // Find our parent ActionsTag instance
+        Tag parent = getParent();
+        if ((parent == null) || !(parent instanceof RowTag))
+            throw new JspException("Must be nested in a rowTag isntance");
+        RowTag row = (RowTag) parent;
+
+        // Register the information for the action represented by
+        // this action
+        HttpServletResponse response =
+            (HttpServletResponse) pageContext.getResponse();
+        row.setData(data);
+        
+        return (EVAL_PAGE);
+
+    }
+
+
+    /**
+     * Release all state information set by this tag.
+     */
+    public void release() {
+
+        this.data = null;
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/DumpRegistryAction.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/DumpRegistryAction.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/DumpRegistryAction.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2001,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.admin;
+
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.Arrays;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+import org.apache.commons.modeler.ManagedBean;
+import org.apache.commons.modeler.Registry;
+import org.apache.struts.action.Action;
+import org.apache.struts.action.ActionErrors;
+import org.apache.struts.action.ActionForm;
+import org.apache.struts.action.ActionForward;
+import org.apache.struts.action.ActionMapping;
+
+
+/**
+ * Simple debugging action that dumps a list of the managed beans that are
+ * visible in our Registry.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 303390 $ $Date: 2004-10-18 01:37:56 -0500 (Mon, 18 Oct 2004) $
+ */
+
+public final class DumpRegistryAction extends Action {
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Process the specified HTTP request, and create the corresponding HTTP
+     * response (or forward to another web component that will create it).
+     * Return an <code>ActionForward</code> instance describing where and how
+     * control should be forwarded, or <code>null</code> if the response has
+     * already been completed.
+     *
+     * @param mapping The ActionMapping used to select this instance
+     * @param actionForm The optional ActionForm bean for this request (if any)
+     * @param request The HTTP request we are processing
+     * @param response The HTTP response we are creating
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception ServletException if a servlet exception occurs
+     */
+    public ActionForward execute(ActionMapping mapping,
+                                 ActionForm form,
+                                 HttpServletRequest request,
+                                 HttpServletResponse response)
+        throws IOException, ServletException {
+
+        // Create a request attribute with our collection of beans
+        Registry registry = ((ApplicationServlet) getServlet()).getRegistry();
+        String names[] = registry.findManagedBeans();
+        Arrays.sort(names);
+        ManagedBean beans[] = new ManagedBean[names.length];
+        for (int i = 0; i < names.length; i++)
+            beans[i] = registry.findManagedBean(names[i]);
+        request.setAttribute("beans", beans);
+
+        // Forward to the corresponding display page
+        return (mapping.findForward("Dump Registry Results"));
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/DumpServerAction.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/DumpServerAction.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/DumpServerAction.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,90 @@
+/*
+ * Copyright 2001,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.admin;
+
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+import org.apache.struts.action.Action;
+import org.apache.struts.action.ActionErrors;
+import org.apache.struts.action.ActionForm;
+import org.apache.struts.action.ActionForward;
+import org.apache.struts.action.ActionMapping;
+
+
+/**
+ * Simple debugging action that dumps a list of the MBeans that are
+ * visible in our MBeanServer.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 303390 $ $Date: 2004-10-18 01:37:56 -0500 (Mon, 18 Oct 2004) $
+ */
+
+public final class DumpServerAction extends Action {
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Process the specified HTTP request, and create the corresponding HTTP
+     * response (or forward to another web component that will create it).
+     * Return an <code>ActionForward</code> instance describing where and how
+     * control should be forwarded, or <code>null</code> if the response has
+     * already been completed.
+     *
+     * @param mapping The ActionMapping used to select this instance
+     * @param actionForm The optional ActionForm bean for this request (if any)
+     * @param request The HTTP request we are processing
+     * @param response The HTTP response we are creating
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception ServletException if a servlet exception occurs
+     */
+    public ActionForward execute(ActionMapping mapping,
+                                 ActionForm form,
+                                 HttpServletRequest request,
+                                 HttpServletResponse response)
+        throws IOException, ServletException {
+
+        // Create a request attribute with our collection of MBeans
+        MBeanServer server = ((ApplicationServlet) getServlet()).getServer();
+        Iterator names = server.queryNames(null, null).iterator();
+        ArrayList list = new ArrayList();
+        while (names.hasNext()) {
+            list.add(names.next().toString());
+        }
+        Collections.sort(list);
+        request.setAttribute("names", list);
+
+        // Forward to the corresponding display page
+        return (mapping.findForward("Dump Server Results"));
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/LabelTag.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/LabelTag.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/LabelTag.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,127 @@
+/*
+ * Copyright 2001,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.admin;
+
+
+import java.io.IOException;
+import java.net.URLEncoder;
+import java.util.ArrayList;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.jsp.JspException;
+import javax.servlet.jsp.JspWriter;
+import javax.servlet.jsp.PageContext;
+import javax.servlet.jsp.tagext.BodyTagSupport;
+import javax.servlet.jsp.tagext.Tag;
+
+
+/**
+ * <p>Nested tag that represents an individual "labels" for a row.  This tag
+ * is valid <strong>only</strong> when nested within a RowTag tag.
+ *
+ * <p>In addition, the body content of this tag is used as the user-visible
+ * label for the action, so that it may be conveniently localized.</p>
+ *
+ * <strong>FIXME</strong> - Internationalize the exception messages!
+ *
+ * @author Manveen Kaur
+ * @version $Revision: 302726 $
+ */
+
+public class LabelTag extends BodyTagSupport {
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The label that will be rendered for this action.
+     */
+    protected String label = null;
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Process the start of this tag.
+     *
+     * @exception JspException if a JSP exception has occurred
+     */
+    public int doStartTag() throws JspException {
+
+        // Initialize the holder for our label text
+        this.label = null;
+
+        // Do no further processing for now
+        return (EVAL_BODY_TAG);
+
+    }
+
+
+    /**
+     * Process the body text of this tag (if any).
+     *
+     * @exception JspException if a JSP exception has occurred
+     */
+    public int doAfterBody() throws JspException {
+
+        String label = bodyContent.getString();
+        if (label != null) {
+            label = label.trim();
+            if (label.length() > 0)
+                this.label = label;
+        }
+        return (SKIP_BODY);
+
+    }
+
+
+    /**
+     * Record this action with our surrounding ActionsTag instance.
+     *
+     * @exception JspException if a processing error occurs
+     */
+    public int doEndTag() throws JspException {
+
+        // Find our parent ActionsTag instance
+        Tag parent = getParent();
+        if ((parent == null) || !(parent instanceof RowTag))
+            throw new JspException("Must be nested in a rowTag isntance");
+        RowTag row = (RowTag) parent;
+
+        // Register the information for the action represented by
+        // this action
+        HttpServletResponse response =
+            (HttpServletResponse) pageContext.getResponse();
+        row.setLabel(label);
+        
+        return (EVAL_PAGE);
+
+    }
+
+
+    /**
+     * Release all state information set by this tag.
+     */
+    public void release() {
+
+        this.label = null;
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/LabelValueBean.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/LabelValueBean.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/LabelValueBean.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,87 @@
+/*
+ * Copyright 1999-2001,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.admin;
+
+import java.io.Serializable;
+
+/**
+ * Simple JavaBean to represent label-value pairs for use in collections
+ * that are utilized by the <code>&lt;form:options&gt;</code> tag.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class LabelValueBean implements Serializable {
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Construct a new LabelValueBean with the specified values.
+     *
+     * @param label The label to be displayed to the user
+     * @param value The value to be returned to the server
+     */
+    public LabelValueBean(String label, String value) {
+        this.label = label;
+        this.value = value;
+    }
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * The label to be displayed to the user.
+     */
+    protected String label = null;
+
+    public String getLabel() {
+        return (this.label);
+    }
+
+
+    /**
+     * The value to be returned to the server.
+     */
+    protected String value = null;
+
+    public String getValue() {
+        return (this.value);
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Return a string representation of this object.
+     */
+    public String toString() {
+        StringBuffer sb = new StringBuffer("LabelValueBean[");
+        sb.append(this.label);
+        sb.append(", ");
+        sb.append(this.value);
+        sb.append("]");
+        return (sb.toString());
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/Lists.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/Lists.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/Lists.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,623 @@
+/*
+ * Copyright 2001-2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.admin;
+
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import javax.servlet.http.HttpServletRequest;
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+
+
+/**
+ * General purpose utility methods to create lists of objects that are
+ * commonly required in building the user interface.  In all cases, if there
+ * are no matching elements, a zero-length list (rather than <code>null</code>)
+ * is returned.
+ *
+ * @author Craig R. McClanahan
+ * @author Amy Roh
+ * @version $Revision: 440953 $ $Date: 2006-09-06 21:47:31 -0500 (Wed, 06 Sep 2006) $
+ */
+
+public class Lists {
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Protected constructor to prevent instantiation.
+     */
+    protected Lists() { }
+
+
+    // ------------------------------------------------------- Static Variables
+
+
+    /**
+     * Precomputed list of verbosity level labels and values.
+     */
+    private static List verbosityLevels = new ArrayList();
+
+    static {
+        verbosityLevels.add(new LabelValueBean("0", "0"));
+        verbosityLevels.add(new LabelValueBean("1", "1"));
+        verbosityLevels.add(new LabelValueBean("2", "2"));
+        verbosityLevels.add(new LabelValueBean("3", "3"));
+        verbosityLevels.add(new LabelValueBean("4", "4"));
+    }
+
+    /**
+     * Precomputed list of (true,false) labels and values.
+     */
+    private static List booleanValues = new ArrayList();
+
+    static {
+            booleanValues.add(new LabelValueBean("True", "true"));
+            booleanValues.add(new LabelValueBean("False", "false"));
+    }
+
+    /**
+     * Precomputed list of clientAuth lables and values.
+     */
+    private static List clientAuthValues = new ArrayList();
+
+    static {
+            clientAuthValues.add(new LabelValueBean("True","true"));
+            clientAuthValues.add(new LabelValueBean("False","false"));
+            clientAuthValues.add(new LabelValueBean("Want","want"));
+    }
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Return a <code>List</code> of {@link LabelValueBean}s for the legal
+     * settings for <code>verbosity</code> properties.
+     */
+    public static List getVerbosityLevels() {
+
+        return (verbosityLevels);
+
+    }
+
+    /**
+     * Return a <code>List</code> of {@link LabelValueBean}s for the legal
+     * settings for <code>boolean</code> properties.
+     */
+    public static List getBooleanValues() {
+
+        return (booleanValues);
+
+    }
+    /**
+     * Return a <code>List</code> of {@link LabelValueBean}s for the legal
+     * settings for <code>clientAuth</code> properties.
+     */
+    public static List getClientAuthValues() {
+
+        return (clientAuthValues);
+
+    }
+
+    /**
+     * Return a list of <code>Connector</code> object name strings
+     * for the specified <code>Service</code> object name.
+     *
+     * @param mbserver MBeanServer from which to retrieve the list
+     * @param service Object name of the service for which to select connectors
+     *
+     * @exception Exception if thrown while retrieving the list
+     */
+    public static List getConnectors(MBeanServer mbserver, ObjectName service)
+        throws Exception {
+
+        StringBuffer sb = new StringBuffer(service.getDomain());
+        sb.append(":type=Connector,*");
+        ObjectName search = new ObjectName(sb.toString());
+        ArrayList connectors = new ArrayList();
+        Iterator names = mbserver.queryNames(search, null).iterator();
+        while (names.hasNext()) {
+            connectors.add(names.next().toString());
+        }
+        Collections.sort(connectors);
+        return (connectors);
+
+    }
+
+
+    /**
+     * Return a list of <code>Connector</code> object name strings
+     * for the specified <code>Service</code> object name.
+     *
+     * @param mbserver MBeanServer from which to retrieve the list
+     * @param service Object name of the service for which to select connectors
+     *
+     * @exception Exception if thrown while retrieving the list
+     */
+    public static List getConnectors(MBeanServer mbserver, String service)
+        throws Exception {
+
+        return (getConnectors(mbserver, new ObjectName(service)));
+
+    }
+
+
+    /**
+     * Return a list of <code>Context</code> object name strings
+     * for the specified <code>Host</code> object name.
+     *
+     * @param mbserver MBeanServer from which to retrieve the list
+     * @param host Object name of the host for which to select contexts
+     *
+     * @exception Exception if thrown while retrieving the list
+     */
+    public static List getContexts(MBeanServer mbserver, ObjectName host)
+        throws Exception {
+
+        StringBuffer sb = new StringBuffer(host.getDomain());
+        sb.append(":j2eeType=WebModule,*");
+        ObjectName search = new ObjectName(sb.toString());
+        ArrayList contexts = new ArrayList();
+        Iterator names = mbserver.queryNames(search, null).iterator();
+        String name = null;
+        ObjectName oname = null;
+        String hostPrefix = "//"+host.getKeyProperty("host");
+        String hostAttr = null;
+        while (names.hasNext()) {
+            name = names.next().toString();
+            oname = new ObjectName(name);
+            hostAttr = oname.getKeyProperty("name");
+            if (hostAttr.startsWith(hostPrefix)) {
+                contexts.add(name);
+            }
+        }
+        Collections.sort(contexts);
+        return (contexts);
+
+    }
+
+
+    /**
+     * Return a list of <code>DefaultContext</code> object name strings
+     * for the specified <code>Host</code> object name.
+     *
+     * @param mbserver MBeanServer from which to retrieve the list
+     * @param container Object name of the container for which to select default
+     * contexts
+     * @param containerType The type of the container for which to select 
+     * default contexts
+     *
+     * @exception Exception if thrown while retrieving the list
+     */
+    public static List getDefaultContexts(MBeanServer mbserver, String 
+        container) throws Exception {
+
+        return (getDefaultContexts(mbserver, new ObjectName(container)));
+
+    }
+    
+    
+    /**
+     * Return a list of <code>DefaultContext</code> object name strings
+     * for the specified <code>Host</code> object name.
+     *
+     * @param mbserver MBeanServer from which to retrieve the list
+     * @param container Object name of the container for which to select default
+     * contexts
+     * @param containerType The type of the container for which to select 
+     * default contexts
+     *
+     * @exception Exception if thrown while retrieving the list
+     */
+    public static List getDefaultContexts(MBeanServer mbserver, ObjectName 
+        container) throws Exception {
+
+        // FIXME
+        StringBuffer sb = new StringBuffer(container.getDomain());
+        sb.append(":type=DefaultContext");
+        String type = container.getKeyProperty("type");
+        String host = container.getKeyProperty("host");
+        if ("Host".equals(type)) {
+            host = container.getKeyProperty("host");
+        }
+        if (host != null) {
+            sb.append(",host=");
+            sb.append(host);
+        }
+        ObjectName search = new ObjectName(sb.toString());
+        ArrayList defaultContexts = new ArrayList();
+        Iterator names = mbserver.queryNames(search, null).iterator();
+        while (names.hasNext()) {
+            String name = names.next().toString();
+            defaultContexts.add(name);
+        }
+        Collections.sort(defaultContexts);
+        return (defaultContexts);
+
+    }
+
+
+    /**
+     * Return a list of <code>Context</code> object name strings
+     * for the specified <code>Host</code> object name.
+     *
+     * @param mbserver MBeanServer from which to retrieve the list
+     * @param host Object name of the host for which to select contexts
+     *
+     * @exception Exception if thrown while retrieving the list
+     */
+    public static List getContexts(MBeanServer mbserver, String host)
+        throws Exception {
+
+        return (getContexts(mbserver, new ObjectName(host)));
+
+    }
+
+    /**
+     * Return a list of <code>Host</code> object name strings
+     * for the specified <code>Service</code> object name.
+     *
+     * @param mbserver MBeanServer from which to retrieve the list
+     * @param service Object name of the service for which to select hosts
+     *
+     * @exception Exception if thrown while retrieving the list
+     */
+    public static List getHosts(MBeanServer mbserver, ObjectName service)
+        throws Exception {
+
+        StringBuffer sb = new StringBuffer(service.getDomain());
+        sb.append(":type=Host,*");
+        ObjectName search = new ObjectName(sb.toString());
+        ArrayList hosts = new ArrayList();
+        Iterator names = mbserver.queryNames(search, null).iterator();
+        while (names.hasNext()) {
+            hosts.add(names.next().toString());
+        }
+        Collections.sort(hosts);
+        return (hosts);
+
+    }
+
+
+    /**
+     * Return a list of <code>Host</code> object name strings
+     * for the specified <code>Service</code> object name.
+     *
+     * @param mbserver MBeanServer from which to retrieve the list
+     * @param service Object name of the service for which to select hosts
+     *
+     * @exception Exception if thrown while retrieving the list
+     */
+    public static List getHosts(MBeanServer mbserver, String service)
+        throws Exception {
+
+        return (getHosts(mbserver, new ObjectName(service)));
+
+    }
+
+
+    /**
+     * Return a list of <code>Realm</code> object name strings
+     * for the specified container (service, host, or context) object name.
+     *
+     * @param mbserver MBeanServer from which to retrieve the list
+     * @param container Object name of the container for which to select
+     *                  realms
+     *
+     * @exception Exception if thrown while retrieving the list
+     */
+    public static List getRealms(MBeanServer mbserver, ObjectName container)
+        throws Exception {
+
+        ObjectName search = getSearchObject(container, "Realm");
+        ArrayList realms = new ArrayList();
+        Iterator names = mbserver.queryNames(search, null).iterator();
+        while (names.hasNext()) {
+            realms.add(names.next().toString());
+        }
+        Collections.sort(realms);
+        return (realms);
+
+    }
+
+
+    /**
+     * Return a list of <code>Realm</code> object name strings
+     * for the specified container (service, host, or context) object name.
+     *
+     * @param mbserver MBeanServer from which to retrieve the list
+     * @param container Object name of the container for which to select
+     *                  realms
+     *
+     * @exception Exception if thrown while retrieving the list
+     */
+    public static List getRealms(MBeanServer mbserver, String container)
+        throws Exception {
+
+        return (getRealms(mbserver, new ObjectName(container)));
+
+    }
+
+    /**
+     * Return a list of <code>Valve</code> object name strings
+     * for the specified container (service, host, or context) object name.
+     *
+     * @param mbserver MBeanServer from which to retrieve the list
+     * @param container Object name of the container for which to select
+     *                  Valves
+     *
+     * @exception Exception if thrown while retrieving the list
+     */
+    public static List getValves(MBeanServer mbserver, ObjectName container)
+        throws Exception {
+
+        StringBuffer sb = new StringBuffer(container.getDomain());
+        sb.append(":type=Valve");
+        String type = container.getKeyProperty("type");
+        String j2eeType = container.getKeyProperty("j2eeType");
+        sb.append(TomcatTreeBuilder.WILDCARD);
+        String host = "";
+        String path = "";
+        String name = container.getKeyProperty("name");
+        if ((name != null) && (name.length() > 0)) {
+            // parent is context
+            name = name.substring(2);
+            int i = name.indexOf("/");
+            host = name.substring(0,i);
+            path = name.substring(i);
+        } else if ("Host".equals(type)) {
+            // parent is host
+            host = container.getKeyProperty("host");
+        }    
+        
+        ObjectName search = new ObjectName(sb.toString());        
+        ArrayList valves = new ArrayList();
+        Iterator names = mbserver.queryNames(search, null).iterator();
+        while (names.hasNext()) {
+            ObjectName valve = (ObjectName) names.next();
+            String vpath = valve.getKeyProperty("path");            
+            String vhost = valve.getKeyProperty("host");
+            
+            String valveType = null;
+            String className = (String) 
+                    mbserver.getAttribute(valve, "className");
+            int period = className.lastIndexOf(".");
+            if (period >= 0)
+                valveType = className.substring(period + 1);
+
+           // Return only user-configurable valves.
+           if ("AccessLogValve".equalsIgnoreCase(valveType) ||
+               "RemoteAddrValve".equalsIgnoreCase(valveType) ||
+               "RemoteHostValve".equalsIgnoreCase(valveType) || 
+               "RequestDumperValve".equalsIgnoreCase(valveType) ||
+               "SingleSignOn".equalsIgnoreCase(valveType)) {
+            // if service is the container, then the valve name
+            // should not contain path or host                   
+            if ("Service".equalsIgnoreCase(type)) {
+                if ((vpath == null) && (vhost == null)) {
+                    valves.add(valve.toString());
+                }
+            } 
+            
+            if ("Host".equalsIgnoreCase(type)) {
+                if ((vpath == null) && (host.equalsIgnoreCase(vhost))) { 
+                    valves.add(valve.toString());      
+                }
+            }
+            
+            if ("WebModule".equalsIgnoreCase(j2eeType)) {
+                if ((path.equalsIgnoreCase(vpath)) && (host.equalsIgnoreCase(vhost))) {
+                    valves.add(valve.toString());      
+                }
+            }
+           }
+        }        
+        Collections.sort(valves);
+        return (valves);
+    }
+
+    
+    /**
+     * Return a list of <code>Valve</code> object name strings
+     * for the specified container (service, host, or context) object name.
+     *
+     * @param mbserver MBeanServer from which to retrieve the list
+     * @param container Object name of the container for which to select
+     *                  valves
+     *
+     * @exception Exception if thrown while retrieving the list
+     */
+    public static List getValves(MBeanServer mbserver, String container)
+        throws Exception {
+
+        return (getValves(mbserver, new ObjectName(container)));
+
+    }
+    
+    /**
+     * Return a list of <code>Server</code> object name strings.
+     *
+     * @param mbserver MBeanServer from which to retrieve the list
+     *
+     * @exception Exception if thrown while retrieving the list
+     */
+    public static List getServers(MBeanServer mbserver, String domain)
+        throws Exception {
+
+        ObjectName search = new ObjectName(domain+":type=Server,*");
+        ArrayList servers = new ArrayList();
+        Iterator names = mbserver.queryNames(search, null).iterator();
+        while (names.hasNext()) {
+            servers.add(names.next().toString());
+        }
+        Collections.sort(servers);
+        return (servers);
+
+    }
+
+
+    /**
+     * Return a list of <code>Service</code> object name strings
+     * for the specified <code>Server</code> object name.
+     *
+     * @param mbserver MBeanServer from which to retrieve the list
+     * @param server Object name of the server for which to select services
+     *
+     * @exception Exception if thrown while retrieving the list
+     */
+    public static List getServices(MBeanServer mbserver, ObjectName server)
+        throws Exception {
+
+        //StringBuffer sb = new StringBuffer(server.getDomain());
+        StringBuffer sb = new StringBuffer("*:type=Service,*");
+        //sb.append(":type=Service,*");
+        ObjectName search = new ObjectName(sb.toString());
+        ArrayList services = new ArrayList();
+        Iterator names = mbserver.queryNames(search, null).iterator();
+        while (names.hasNext()) {
+            services.add(names.next().toString());
+        }
+        Collections.sort(services);
+        return (services);
+
+    }
+
+
+    /**
+     * Return a list of <code>Service</code> object name strings
+     * for the specified <code>Server</code> object name.
+     *
+     * @param mbserver MBeanServer from which to retrieve the list
+     * @param server Object name of the server for which to select services
+     *
+     * @exception Exception if thrown while retrieving the list
+     */
+    public static List getServices(MBeanServer mbserver, String server)
+        throws Exception {
+
+        return (getServices(mbserver, new ObjectName(server)));
+
+    }
+
+
+    /**
+     * Return the  <code>Service</code> object name string
+     * that the admin app belongs to.
+     *
+     * @param mbserver MBeanServer from which to retrieve the list
+     * @param request Http request
+     *
+     * @exception Exception if thrown while retrieving the list
+     */
+    public static String getAdminAppService
+        (MBeanServer mbserver, String domain, HttpServletRequest request)
+        throws Exception {
+
+        // Get the admin app's service name
+        StringBuffer sb = new StringBuffer(domain);
+        sb.append(":type=Service,*");
+        ObjectName search = new ObjectName(sb.toString());
+        Iterator names = mbserver.queryNames(search, null).iterator();
+        String service = null;
+        while (names.hasNext()) {
+            service = ((ObjectName)names.next()).getKeyProperty("serviceName");
+        }
+        return service;
+
+    }
+
+
+    /**
+     * Return the  <code>Host</code> object name string
+     * that the admin app belongs to.
+     *
+     * @param mbserver MBeanServer from which to retrieve the list
+     * @param request Http request
+     *
+     * @exception Exception if thrown while retrieving the list
+     */
+    public static String getAdminAppHost
+        (MBeanServer mbserver, String domain, HttpServletRequest request)
+        throws Exception {
+        
+        // Get the admin app's host name
+        StringBuffer sb = new StringBuffer(domain);
+        sb.append(":j2eeType=WebModule,*"); 
+        ObjectName search = new ObjectName(sb.toString());
+        Iterator names = mbserver.queryNames(search, null).iterator();
+        String contextPath = request.getContextPath();
+        String host = null;
+        String name = null;
+        ObjectName oname = null;
+        while (names.hasNext()) {       
+            name = names.next().toString();
+            oname = new ObjectName(name);
+            host = oname.getKeyProperty("name");
+            host = host.substring(2);
+            int i = host.indexOf("/");
+            if (contextPath.equals(host.substring(i))) {
+                host = host.substring(0,i);
+                return host;
+            }
+        }
+        return host;
+
+    }
+
+    
+    /**
+     * Return search object name to be used to query.
+     *
+     * @param container object name to query
+     * @param type type of the component
+     *
+     * @exception MalformedObjectNameException if thrown while retrieving the list
+     */
+    public static ObjectName getSearchObject(ObjectName container, String type)  
+            throws Exception {
+        
+        StringBuffer sb = new StringBuffer(container.getDomain());
+        sb.append(":type="+type);
+        String containerType = container.getKeyProperty("type");
+        String name = container.getKeyProperty("name");
+        if ((name != null) && (name.length() > 0)) {
+            // parent is context
+            name = name.substring(2);
+            int i = name.indexOf("/");
+            String host = name.substring(0,i);
+            String path = name.substring(i);
+            sb.append(",path=");
+            sb.append(path);
+            sb.append(",host=");
+            sb.append(host);
+        } else if ("Host".equals(containerType)) {
+            // parent is host
+            String host = container.getKeyProperty("host");
+            sb.append(",host=");
+            sb.append(host);
+        }    
+        
+        return new ObjectName(sb.toString());
+        
+    }
+    
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/LogOutAction.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/LogOutAction.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/LogOutAction.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2001,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.admin;
+
+
+import java.io.IOException;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Locale;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+import org.apache.struts.action.Action;
+import org.apache.struts.action.ActionErrors;
+import org.apache.struts.action.ActionForm;
+import org.apache.struts.action.ActionForward;
+import org.apache.struts.action.ActionMapping;
+
+
+/**
+ * Implementation of <strong>Action</strong> that logs out of the current
+ * session and returns to the main menu (which will trigger the login form).
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 303390 $ $Date: 2004-10-18 01:37:56 -0500 (Mon, 18 Oct 2004) $
+ */
+
+public final class LogOutAction extends Action {
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Process the specified HTTP request, and create the corresponding HTTP
+     * response (or forward to another web component that will create it).
+     * Return an <code>ActionForward</code> instance describing where and how
+     * control should be forwarded, or <code>null</code> if the response has
+     * already been completed.
+     *
+     * @param mapping The ActionMapping used to select this instance
+     * @param actionForm The optional ActionForm bean for this request (if any)
+     * @param request The HTTP request we are processing
+     * @param response The HTTP response we are creating
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception ServletException if a servlet exception occurs
+     */
+    public ActionForward execute(ActionMapping mapping,
+                                 ActionForm form,
+                                 HttpServletRequest request,
+                                 HttpServletResponse response)
+        throws IOException, ServletException {
+
+        // Invalidate the current session and create a new one
+        HttpSession session = request.getSession();
+        session.invalidate();
+        session = request.getSession(true);
+
+        // Forward control back to the main menu
+        return (mapping.findForward("Main Menu"));
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/RowTag.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/RowTag.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/RowTag.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,199 @@
+/*
+ * Copyright 2001,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.admin;
+
+
+import java.io.IOException;
+import java.net.URLEncoder;
+import java.util.ArrayList;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.jsp.JspException;
+import javax.servlet.jsp.JspWriter;
+import javax.servlet.jsp.PageContext;
+import javax.servlet.jsp.tagext.BodyTagSupport;
+import javax.servlet.jsp.tagext.Tag;
+
+
+/**
+ * <p>Nested tag that represents an individual "instant table".  This tag
+ * is valid <strong>only</strong> when nested within an TableTag tag.
+ * This tag has the following user-settable attributes:</p>
+ * <ul>
+ * <li><strong>header</strong> - Is this  a header row?</li>
+ * <li><strong>label</strong> - label to be displayed.</li>
+ * <li><strong>data</strong> - data of the table data element.</li>
+ * <li><strong>labelStyle</strong> - Style to be applied to the
+ * label table data element.</li>
+ * <li><strong>dataStyle</strong> - Style to be applied to the data table
+ * data element.</li>
+ *
+ * </ul>
+ *
+ * @author Manveen Kaur
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class RowTag extends BodyTagSupport {
+    
+    /**
+     * Is this the header row?
+     */
+    protected boolean header = false;
+    
+    public boolean getHeader() {
+        return (this.header);
+    }
+    
+    public void setHeader(boolean header) {
+        this.header = header;
+    }    
+    
+    /**
+     * The label that will be rendered for this row's table data element.
+     */
+    protected String label = null;
+   
+    public void setLabel(String label) {
+        this.label = label;
+    }
+    
+    
+    /**
+     * The data of the table data element of this row.
+     */
+    protected String data = null;
+    
+    public void setData(String data) {
+        this.data = data;
+    }
+    
+    /**
+     * The style of the label.
+     */
+    protected String labelStyle = null;
+    
+    public String getLabelStyle() {
+        return (this.labelStyle);
+    }
+    
+    public void setLabelStyle(String labelStyle) {
+        this.labelStyle = labelStyle;
+    }
+    
+    
+    /**
+     * The style of the data.
+     */
+    protected String dataStyle = null;
+    
+    public String getdataStyle() {
+        return (this.dataStyle);
+    }
+    
+    public void setdataStyle(String dataStyle) {
+        this.dataStyle = dataStyle;
+    }
+ 
+    /**
+     * The styleId for the label.
+     */
+    protected String styleId = null;
+    
+    public String getStyleId() {
+        return (this.styleId);
+    }
+    
+    public void setStyleId(String styleId) {
+        this.styleId = styleId;
+    }
+    
+        
+    // --------------------------------------------------------- Public Methods
+    
+    
+    /**
+     * Process the start of this tag.
+     *
+     * @exception JspException if a JSP exception has occurred
+     */
+    public int doStartTag() throws JspException {
+        
+         // Do no further processing for now
+        return (EVAL_BODY_TAG);
+        
+    }
+    
+    
+    /**
+     * Process the body text of this tag (if any).
+     *
+     * @exception JspException if a JSP exception has occurred
+     */
+    public int doAfterBody() throws JspException {
+       
+        return (SKIP_BODY);
+        
+    }
+    
+    
+    /**
+     * Record this action with our surrounding ActionsTag instance.
+     *
+     * @exception JspException if a processing error occurs
+     */
+    public int doEndTag() throws JspException {
+        
+        // Find our parent TableTag instance
+        Tag parent = getParent();
+        while ((parent != null) && !(parent instanceof TableTag)) {
+            parent = parent.getParent();
+        }
+        if (parent == null) {
+            throw new JspException("Must be nested in a TableTag instance");
+        }
+        TableTag table = (TableTag) parent;
+        
+        // Register the information for the row represented by
+        // this row
+        HttpServletResponse response =
+        (HttpServletResponse) pageContext.getResponse();
+        table.addRow(header, label, data, labelStyle, dataStyle, styleId);
+        
+        return (EVAL_PAGE);
+        
+    }
+    
+    
+    /**
+     * Release all state information set by this tag.
+     */
+    public void release() {
+        
+        //super.release();
+        
+        this.header= false;
+        this.label = null;
+        this.data = null;
+        this.labelStyle = null;
+        this.dataStyle = null;
+        this.styleId = null;
+        
+    }
+    
+    
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/SetLocaleAction.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/SetLocaleAction.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/SetLocaleAction.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2001,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.admin;
+
+
+import java.io.IOException;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Locale;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+import org.apache.struts.Globals;
+import org.apache.struts.action.Action;
+import org.apache.struts.action.ActionErrors;
+import org.apache.struts.action.ActionForm;
+import org.apache.struts.action.ActionForward;
+import org.apache.struts.action.ActionMapping;
+
+
+/**
+ * Implementation of <strong>Action</strong> that sets the current Locale
+ * to the one specified by the <code>locale</code> request parameter.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 303390 $ $Date: 2004-10-18 01:37:56 -0500 (Mon, 18 Oct 2004) $
+ */
+
+public final class SetLocaleAction extends Action {
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Process the specified HTTP request, and create the corresponding HTTP
+     * response (or forward to another web component that will create it).
+     * Return an <code>ActionForward</code> instance describing where and how
+     * control should be forwarded, or <code>null</code> if the response has
+     * already been completed.
+     *
+     * @param mapping The ActionMapping used to select this instance
+     * @param actionForm The optional ActionForm bean for this request (if any)
+     * @param request The HTTP request we are processing
+     * @param response The HTTP response we are creating
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception ServletException if a servlet exception occurs
+     */
+    public ActionForward execute(ActionMapping mapping,
+                                 ActionForm form,
+                                 HttpServletRequest request,
+                                 HttpServletResponse response)
+        throws IOException, ServletException {
+
+        // What locale does the user want to switch to?
+        String requestedLocale = ((SetLocaleForm) form).getLocale();
+
+        // Switch to the specified locale, if it exists
+        if (requestedLocale != null) {
+            ApplicationLocales locales = (ApplicationLocales)
+                getServlet().getServletContext().getAttribute
+                (ApplicationServlet.LOCALES_KEY);
+            Iterator iterator = locales.getSupportedLocales().iterator();
+            Locale currentLocale = null;
+            while (iterator.hasNext()) {
+                currentLocale = (Locale) iterator.next();
+                if (requestedLocale.equals(currentLocale.toString())) {
+                    HttpSession session = request.getSession();
+                    session.setAttribute(Globals.LOCALE_KEY, currentLocale);
+                    // Remove form bean so it will get recreated next time
+                    session.removeAttribute(mapping.getAttribute());
+                    break;
+                }
+            }
+        }
+
+        // Forward control back to the main menu
+        return (mapping.findForward("Main Menu"));
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/SetLocaleForm.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/SetLocaleForm.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/SetLocaleForm.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2001,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.admin;
+
+
+import java.util.Locale;
+import javax.servlet.http.HttpSession;
+import javax.servlet.http.HttpSessionBindingEvent;
+import javax.servlet.http.HttpSessionBindingListener;
+import org.apache.struts.Globals;
+import org.apache.struts.action.ActionForm;
+
+
+/**
+ * Form bean for the set locale page.  The actual value is copied when this
+ * bean is added as a session attribute.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302997 $ $Date: 2004-07-10 01:56:16 -0500 (Sat, 10 Jul 2004) $
+ */
+
+public final class SetLocaleForm
+    extends ActionForm
+    implements HttpSessionBindingListener {
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * The name of the locale we are currently running.
+     */
+    String locale = null;
+
+    public String getLocale() {
+        return (this.locale);
+    }
+
+    public void setLocale(String locale) {
+        this.locale = locale;
+    }
+
+
+    // ------------------------------------- HttpSessionBindingListener Methods
+
+
+    /**
+     * When this form bean is bound into the session, pick up the user's
+     * current Locale object and set the current value.
+     */
+    public void valueBound(HttpSessionBindingEvent event) {
+
+        HttpSession session = event.getSession();
+        Locale current = (Locale) session.getAttribute(Globals.LOCALE_KEY);
+        if (current != null)
+            locale = current.toString();
+
+    }
+
+
+    /**
+     * No action is required when this object is unbound.
+     */
+    public void valueUnbound(HttpSessionBindingEvent event) {
+
+        locale = null;
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/SetUpTreeAction.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/SetUpTreeAction.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/SetUpTreeAction.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,145 @@
+/*
+ * Copyright 2001,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.admin;
+
+
+import java.io.IOException;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Locale;
+import java.util.StringTokenizer;
+import java.util.ArrayList;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+import org.apache.struts.action.Action;
+import org.apache.struts.action.ActionErrors;
+import org.apache.struts.action.ActionForm;
+import org.apache.struts.action.ActionForward;
+import org.apache.struts.action.ActionMapping;
+
+
+/**
+ * Test <code>Action</code> sets up  tree control data structure
+ * for tree widget
+ *
+ * @author Jazmin Jonson
+ * @author Manveen Kaur
+ * @version $Revision: 303390 $ $Date: 2004-10-18 01:37:56 -0500 (Mon, 18 Oct 2004) $
+ */
+
+public class SetUpTreeAction extends Action {
+
+    public static final String DOMAIN_KEY = "domain";
+    public static final int INIT_PLUGIN_MAX = 10;
+    public static final String TREEBUILDER_KEY = "treebuilders";
+    public static final String ROOTNODENAME_KEY = "rootnodename";
+
+    // --------------------------------------------------------- Public Methods
+
+    /**
+     * Process the specified HTTP request, and create the corresponding HTTP
+     * response (or forward to another web component that will create it).
+     * Return an <code>ActionForward</code> instance describing where and how
+     * control should be forwarded, or <code>null</code> if the response has
+     * already been completed.
+     *
+     * @param mapping The ActionMapping used to select this instance
+     * @param actionForm The optional ActionForm bean for this request (if any)
+     * @param request The HTTP request we are processing
+     * @param response The HTTP response we are creating
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception ServletException if a servlet exception occurs
+     */
+    public ActionForward execute(ActionMapping mapping,
+                                 ActionForm form,
+                                 HttpServletRequest request,
+                                 HttpServletResponse response)
+        throws IOException, ServletException {
+
+        ApplicationServlet servlet = (ApplicationServlet)getServlet();
+
+        // Getting init parms from web.xml
+
+        // Get the string to be displayed as root node while rendering the tree
+        String rootnodeName = 
+            (String)servlet.getServletConfig().getInitParameter(ROOTNODENAME_KEY);
+        
+        String treeBuildersStr  =
+            (String)servlet.getServletConfig().getInitParameter(TREEBUILDER_KEY);
+        
+        String domain  =
+            (String)servlet.getServletConfig().getInitParameter(DOMAIN_KEY);
+        
+        
+        // Make the root node and tree control
+        
+        // The root node gets rendered only if its value 
+        // is set as an init-param in web.xml
+        
+        TreeControlNode root =
+            new TreeControlNode("ROOT-NODE",
+                                null, rootnodeName,
+                                "setUpTree.do?select=ROOT-NODE",
+                                "content", true, domain);
+                
+        TreeControl control = new TreeControl(root);
+        
+        if(treeBuildersStr != null) {
+            Class treeBuilderImpl;
+            TreeBuilder treeBuilderBase;
+
+            ArrayList treeBuilders = new ArrayList(INIT_PLUGIN_MAX);
+            int i = 0;
+            StringTokenizer st = new StringTokenizer(treeBuildersStr, ",");
+            while (st.hasMoreTokens()) {
+                treeBuilders.add(st.nextToken().trim());
+            }
+
+            if(treeBuilders.size() == 0)
+                treeBuilders.add(treeBuildersStr.trim());
+
+            for(i = 0; i < treeBuilders.size(); i++) {
+
+                try{
+                    treeBuilderImpl = Class.forName((String)treeBuilders.get(i));
+                    treeBuilderBase =
+                        (TreeBuilder)treeBuilderImpl.newInstance();
+                    treeBuilderBase.buildTree(control, servlet, request);
+                }catch(Throwable t){
+                    t.printStackTrace(System.out);
+                }
+            }
+        }
+
+        HttpSession session = request.getSession();
+        session.setAttribute("treeControlTest", control);
+
+         String  name = request.getParameter("select");
+         if (name != null) {
+            control.selectNode(name);
+            // Forward back to the Blank page
+            return (mapping.findForward("Blank"));
+        }
+
+         return (mapping.findForward("Tree Control Test"));
+
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/TableTag.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/TableTag.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/TableTag.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,327 @@
+/*
+ * Copyright 2001,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.admin;
+
+
+import java.io.IOException;
+import java.net.URLEncoder;
+import java.util.ArrayList;
+import javax.servlet.jsp.JspException;
+import javax.servlet.jsp.JspWriter;
+import javax.servlet.jsp.PageContext;
+import javax.servlet.jsp.tagext.BodyTagSupport;
+
+
+/**
+ * <p>JSP custom tag that renders an "instant table" control.  To the user,
+ * it appears as an HTML &lt;table&gt; element
+ * This tag has the following user-settable attributes:</p>
+ * <ul>
+ * <li><strong>columns</strong> - (Integer) number of columns in the table.
+ * If not specified, one two columns will be created.</li>
+ * <li><strong>table-class</strong> - The CSS style class to be applied to the
+ *     entire rendered output of the entire table, if any.</li>
+ * <li><strong>header-row-class</strong> - The CSS style class to be applied to the
+ *     entire rendered output of the table header-row, if any.</li>
+ *
+ * </ul>
+ *
+ * <strong>FIXME</strong> - Internationalize the exception messages!
+ *
+ * @author Manveen Kaur
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class TableTag extends BodyTagSupport {
+    
+    
+    // ----------------------------------------------------- Manifest Constants
+    
+    
+    /**
+     * Attribute name used to indicate that we have generated the JavaScript
+     * function already on the current page.  The data stored for this
+     * attribute is arbitrary - only its existence is relevant.
+     */
+    //   protected static final String FUNCTION_TAG =
+    //       "org.apache.webapp.admin.TableTag.FUNCTION_TAG";
+    
+    
+    // ----------------------------------------------------- Instance Variables
+    
+    
+    /**
+     * The set of labels for the rows displayed by this control.
+     */
+    protected ArrayList labels = new ArrayList();
+    
+    
+    /**
+     * The set of datas for the rows displayed by this control.
+     */
+    protected ArrayList datas = new ArrayList();
+    
+    
+    /**
+     * The set of labelStyles for the rows displayed by this control.
+     */
+    protected ArrayList labelStyles = new ArrayList();
+    
+    
+    /**
+     * The set of dataStyles for the rows displayed by this control.
+     */
+    protected ArrayList dataStyles = new ArrayList();
+    
+    /**
+     * The set of "headers" flags for rows displayed by this control.
+     */
+    protected ArrayList headers = new ArrayList();
+    
+    /**
+     * The set of styleIds for the rows displayed by this control.
+     */
+    protected ArrayList styleIds = new ArrayList();
+        
+    
+    // ------------------------------------------------------------- Properties
+    
+    
+    /**
+     * The number of elements that will be displayed to the user.
+     */
+    protected int columns = 2;
+    
+    public int getColumns() {
+        return (this.columns);
+    }
+    
+    public void setColumns(int columns) {
+        this.columns = columns;
+    }
+    
+    
+    /**
+     * The CSS style class to be applied to the entire rendered output
+     * of this "instant table" object.
+     */
+    protected String tableStyle = null;
+    
+    public String getTableStyle() {
+        return (this.tableStyle);
+    }
+    
+    public void setTableStyle(String tableStyle) {
+        this.tableStyle = tableStyle;
+    }
+    
+    /**
+     * The CSS Style for the lines between table rows.
+     */
+    protected String lineStyle = null;
+    
+    public String getLineStyle() {
+        return (this.lineStyle);
+    }
+    
+    public void setLineStyle(String lineStyle) {
+        this.lineStyle = lineStyle;
+    }
+    
+    // --------------------------------------------------------- Public Methods
+
+
+    public int doStartTag() throws JspException {
+ 
+        this.headers.clear();
+        this.labels.clear();
+        this.datas.clear();
+        this.labelStyles.clear();
+        this.dataStyles.clear();
+        this.styleIds.clear();
+        
+        return (EVAL_BODY_TAG);
+ 
+     }    
+
+    
+    /**
+     * Render this instant actions control.
+     *
+     * @exception JspException if a processing error occurs
+     */
+    public int doEndTag() throws JspException {
+        
+        JspWriter out = pageContext.getOut();
+        
+        try {
+            
+            // Render the beginning of this element
+            out.println();
+            out.print("<table ");
+            if (columns > 2) {
+                out.print(" columns=\"");
+                out.print(columns);
+                out.print("\"");
+            }
+            if (tableStyle != null) {
+                out.print(" class=\"");
+                out.print(tableStyle);
+                out.print("\"");
+                out.print(" border=\"1\" cellspacing=\"0\" ");
+                out.print(" cellpadding=\"0\" width=\"100%\" ");
+            }
+            out.println(">");
+            
+            
+            // Render each defined row
+            int n = labels.size();
+            for (int i = 0; i < n; i++) {
+                String label = (String) labels.get(i);
+                boolean header = ((Boolean) headers.get(i)).booleanValue();
+                String data = (String) datas.get(i);
+                String labelStyle = (String) labelStyles.get(i);
+                String dataStyle = (String) dataStyles.get(i);
+                String styleId = (String) styleIds.get(i);
+                
+                if (header) {
+                    out.println("<tr class=\"header-row\" >");
+                    out.println("  <th scope=\"col\" width=\"27%\"> ");
+                
+                    out.print("    <div align=\"left\"");
+                    if (labelStyle != null)
+                        out.print( " class=\"" + labelStyle +"\"");
+                    out.print(">");
+                    if (styleId != null) {
+                        out.print("<label for=\"" + styleId + "\">");
+                    }
+                    out.print(label);
+                    if (styleId != null) {
+                        out.print("</label>");
+                    }
+                    out.println("    </div>");
+                    out.println("  </th>");
+                
+                    out.println("  <th scope=\"col\" width=\"73%\"> ");
+                    out.print("    <div align=\"left\"" );
+                    if (dataStyle != null)
+                        out.print(" class=\"" + dataStyle + "\"");
+                    out.print(">");
+                    out.print(data);
+                    out.println("    </div>");
+                    out.print("  </th>");
+                    out.println("</tr>");
+                } else {
+                    out.println("<tr>");
+                
+                    out.println("  <td scope=\"row\" width=\"27%\"> ");
+                
+                    out.print("    <div align=\"left\"");
+                    if (labelStyle != null)
+                        out.print( " class=\"" + labelStyle +"\"");
+                    out.print(">");
+                    if (styleId != null) {
+                        out.print("<label for=\"" + styleId + "\">");
+                    }
+                    out.print(label);
+                    if (styleId != null) {
+                        out.print("</label>");
+                    }
+                    out.println("    </div>");
+                    out.println("  </td>");
+                
+                    out.println("  <td width=\"73%\"> ");
+                    out.print("    <div align=\"left\"" );
+                    if (dataStyle != null)
+                        out.print(" class=\"" + dataStyle + "\"");
+                    out.print(">");
+                    out.print(data);
+                    out.println("    </div>");
+                    out.print("  </td>");
+                    out.println("</tr>");
+                }
+                
+                /*
+                if (!header) {
+                    out.println("<tr height=\"1\">");
+                    out.println("  <td class=\""+ lineStyle + "\" colspan=\"2\">");
+                    out.println("    <img src=\"\" alt=\"\" width=\"1\" height=\"1\" border=\"0\">");
+                    out.println("  </td>");
+                    out.println("</tr>");
+                }
+                 */
+            }
+            
+            // Render the end of this element
+            out.println("</table>");
+            out.println();
+            
+        } catch (IOException e) {
+            throw new JspException(e);
+        }
+        
+        return (EVAL_PAGE);
+        
+    }
+    
+    
+    /**
+     * Release all state information set by this tag.
+     */
+    public void release() {
+        
+        this.headers.clear();
+        this.labels.clear();
+        this.datas.clear();
+        this.labelStyles.clear();
+        this.dataStyles.clear();
+        this.columns = 2;
+        this.tableStyle = null;
+        this.lineStyle = null;
+        this.styleIds.clear();
+        
+    }
+    
+    
+    // -------------------------------------------------------- Package Methods
+    
+    
+    /**
+     * Add a new Action to the set that will be rendered by this control.
+     *
+     * @param label Localized label visible to the user
+     * @param selected Initial selected state of this option
+     * @param url URL to which control should be transferred if selected
+     */
+    
+    void addRow(boolean header, String label, String data,
+    String labelStyle, String dataStyle, String styleId) {
+        
+        headers.add(new Boolean(header));
+        labels.add(label);
+        datas.add(data);
+        labelStyles.add(labelStyle);
+        dataStyles.add(dataStyle);
+        styleIds.add(styleId);
+        
+    }
+    
+    // ------------------------------------------------------ Protected Methods
+    
+    
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/TomcatTreeBuilder.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/TomcatTreeBuilder.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/TomcatTreeBuilder.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,483 @@
+/*
+ * Copyright 2001,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.admin;
+
+import java.io.IOException;
+import java.util.Iterator;
+import java.util.List;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Locale;
+import java.net.URLEncoder;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+import org.apache.commons.modeler.ManagedBean;
+import org.apache.commons.modeler.Registry;
+import org.apache.struts.Globals;
+import org.apache.struts.action.Action;
+import org.apache.struts.action.ActionErrors;
+import org.apache.struts.action.ActionForm;
+import org.apache.struts.action.ActionForward;
+import org.apache.struts.action.ActionMapping;
+import org.apache.struts.util.MessageResources;
+import javax.management.AttributeNotFoundException;
+import javax.management.MalformedObjectNameException;
+import javax.management.MBeanServer;
+import javax.management.MBeanServerFactory;
+import javax.management.QueryExp;
+import javax.management.Query;
+import javax.management.ObjectInstance;
+import javax.management.ObjectName;
+import javax.management.JMException;
+import javax.management.MBeanAttributeInfo;
+import javax.management.MBeanInfo;
+
+/**
+ * <p> Implementation of TreeBuilder interface for Tomcat Tree Controller
+ *     to build plugin components into the tree
+ *
+ * @author Jazmin Jonson
+ * @author Manveen Kaur
+ * @author Amy Roh
+ * @version $Revision: 303390 $ $Date: 2004-10-18 01:37:56 -0500 (Mon, 18 Oct 2004) $
+ */
+
+
+public class TomcatTreeBuilder implements TreeBuilder{
+    
+    // This SERVER_LABEL needs to be localized
+    private final static String SERVER_LABEL = "Tomcat Server";
+    
+    public final static String DEFAULT_DOMAIN = "Catalina";
+    public final static String SERVER_TYPE = ":type=Server";
+    public final static String FACTORY_TYPE = 
+                        DEFAULT_DOMAIN + ":type=MBeanFactory";
+    public final static String SERVICE_TYPE = ":type=Service";
+    public final static String ENGINE_TYPE = ":type=Engine";
+    public final static String CONNECTOR_TYPE = ":type=Connector";
+    public final static String HOST_TYPE = ":type=Host";
+    public final static String CONTEXT_TYPE = ":type=Context";
+    public final static String LOADER_TYPE = ":type=Loader";
+    public final static String MANAGER_TYPE = ":type=Manager";
+    public final static String LOGGER_TYPE = ":type=Logger";
+    public final static String REALM_TYPE = ":type=Realm";
+    public final static String VALVE_TYPE = ":type=Valve";
+
+    public final static String WILDCARD = ",*";
+
+    public final static String URL_ENCODING="UTF-8";
+    
+    private static MBeanServer mBServer = null;
+    private MessageResources resources = null;
+    private Locale locale = null;
+
+    public void buildTree(TreeControl treeControl,
+                          ApplicationServlet servlet,
+                          HttpServletRequest request) {
+
+        try {
+            HttpSession session = request.getSession();
+            locale = (Locale) session.getAttribute(Globals.LOCALE_KEY);
+            mBServer = servlet.getServer();
+            TreeControlNode root = treeControl.getRoot();
+            resources = (MessageResources)
+                servlet.getServletContext().getAttribute(Globals.MESSAGES_KEY);
+            getServers(root);
+        } catch(Throwable t){
+            t.printStackTrace(System.out);
+        }
+
+    }
+    
+    public static ObjectName getMBeanFactory() 
+            throws MalformedObjectNameException {
+        
+        return new ObjectName(FACTORY_TYPE);
+    }
+    
+
+    /**
+     * Append nodes for all defined servers.
+     *
+     * @param rootNode Root node for the tree control 
+     * @param resources The MessageResources for our localized messages
+     *  messages
+     *
+     * @exception Exception if an exception occurs building the tree
+     */
+    public void getServers(TreeControlNode rootNode) throws Exception {
+        
+        String domain = rootNode.getDomain();
+        Iterator serverNames =
+            Lists.getServers(mBServer,domain).iterator();
+        while (serverNames.hasNext()) {
+            String serverName = (String) serverNames.next();
+            ObjectName objectName = new ObjectName(serverName);
+            String nodeLabel = SERVER_LABEL;
+            TreeControlNode serverNode =
+                new TreeControlNode(serverName,
+                                    "Server.gif",
+                                    nodeLabel,
+                                    "EditServer.do?select=" +
+                                    URLEncoder.encode(serverName,URL_ENCODING) +
+                                    "&nodeLabel=" +
+                                    URLEncoder.encode(nodeLabel,URL_ENCODING),
+                                    "content",
+                                    true, domain);
+            rootNode.addChild(serverNode);
+            getServices(serverNode, serverName);
+        }
+        
+    }
+    
+
+    /**
+     * Append nodes for all defined services for the specified server.
+     *
+     * @param serverNode Server node for the tree control
+     * @param serverName Object name of the parent server
+     * @param resources The MessageResources for our localized messages
+     *  messages
+     *
+     * @exception Exception if an exception occurs building the tree
+     */
+    public void getServices(TreeControlNode serverNode, String serverName) 
+        throws Exception {
+
+        String domain = serverNode.getDomain();
+        Iterator serviceNames =
+            Lists.getServices(mBServer, serverName).iterator();
+        while (serviceNames.hasNext()) {
+            String serviceName = (String) serviceNames.next();
+            ObjectName objectName = new ObjectName(serviceName);
+            String nodeLabel =
+                resources.getMessage(locale, 
+                    "server.service.treeBuilder.subtreeNode") + " (" +
+                    objectName.getKeyProperty("serviceName") + ")";
+            TreeControlNode serviceNode =
+                new TreeControlNode(serviceName,
+                                    "Service.gif",
+                                    nodeLabel,
+                                    "EditService.do?select=" +
+                                    URLEncoder.encode(serviceName,URL_ENCODING) +
+                                    "&nodeLabel=" +
+                                    URLEncoder.encode(nodeLabel,URL_ENCODING),
+                                    "content",
+                                    false, domain);
+            serverNode.addChild(serviceNode);
+            getConnectors(serviceNode, serviceName);
+            getHosts(serviceNode, serviceName);
+            getRealms(serviceNode, serviceName);
+            getValves(serviceNode, serviceName);
+        }
+
+    }
+    
+
+    /**
+     * Append nodes for all defined connectors for the specified service.
+     *
+     * @param serviceNode Service node for the tree control
+     * @param serviceName Object name of the parent service
+     *
+     * @exception Exception if an exception occurs building the tree
+     */
+    public void getConnectors(TreeControlNode serviceNode, String serviceName)
+                        throws Exception{
+        
+        String domain = serviceNode.getDomain();
+        Iterator connectorNames =
+            Lists.getConnectors(mBServer, serviceName).iterator();
+        while (connectorNames.hasNext()) {
+            String connectorName = (String) connectorNames.next();
+            ObjectName objectName = new ObjectName(connectorName);
+            String nodeLabel =
+                resources.getMessage(locale, 
+                    "server.service.treeBuilder.connector") + " (" +  
+                    objectName.getKeyProperty("port") + ")";
+            TreeControlNode connectorNode =
+                new TreeControlNode(connectorName,
+                                    "Connector.gif",
+                                    nodeLabel,
+                                    "EditConnector.do?select=" +
+                                    URLEncoder.encode(connectorName,URL_ENCODING) +
+                                    "&nodeLabel=" +
+                                    URLEncoder.encode(nodeLabel,URL_ENCODING),
+                                    "content",
+                                    false, domain);
+            serviceNode.addChild(connectorNode);
+        }
+    }
+    
+
+    /**
+     * Append nodes for all defined hosts for the specified service.
+     *
+     * @param serviceNode Service node for the tree control
+     * @param serviceName Object name of the parent service
+     * @param resources The MessageResources for our localized messages
+     *  messages
+     *
+     * @exception Exception if an exception occurs building the tree
+     */
+    public void getHosts(TreeControlNode serviceNode, String serviceName) 
+        throws Exception {
+        
+        String domain = serviceNode.getDomain();
+        Iterator hostNames =
+            Lists.getHosts(mBServer, serviceName).iterator();
+        while (hostNames.hasNext()) {
+            String hostName = (String) hostNames.next();
+            ObjectName objectName = new ObjectName(hostName);
+            String nodeLabel =
+                resources.getMessage(locale, 
+                    "server.service.treeBuilder.host") + " (" +
+                    objectName.getKeyProperty("host") + ")";
+            TreeControlNode hostNode =
+                new TreeControlNode(hostName,
+                                    "Host.gif",
+                                    nodeLabel,
+                                    "EditHost.do?select=" +
+                                    URLEncoder.encode(hostName,URL_ENCODING) +
+                                    "&nodeLabel=" +
+                                    URLEncoder.encode(nodeLabel,URL_ENCODING),
+                                    "content",
+                                    false, domain);
+            serviceNode.addChild(hostNode);
+            getContexts(hostNode, hostName);            
+            getRealms(hostNode, hostName);
+            getValves(hostNode, hostName);
+        }
+
+    }    
+
+    
+    /**
+     * Append nodes for all defined contexts for the specified host.
+     *
+     * @param hostNode Host node for the tree control
+     * @param hostName Object name of the parent host
+     * @param resources The MessageResources for our localized messages
+     *  messages
+     *
+     * @exception Exception if an exception occurs building the tree
+     */
+    public void getContexts(TreeControlNode hostNode, String hostName) 
+        throws Exception {
+        
+        String domain = hostNode.getDomain();
+        Iterator contextNames =
+            Lists.getContexts(mBServer, hostName).iterator();
+        while (contextNames.hasNext()) {
+            String contextName = (String) contextNames.next();
+            ObjectName objectName = new ObjectName(contextName);
+            String name = objectName.getKeyProperty("name");
+            name = name.substring(2);
+            int i = name.indexOf("/");
+            String path = name.substring(i);
+            String nodeLabel =
+                resources.getMessage(locale, 
+                    "server.service.treeBuilder.context") + " (" + path + ")";
+            TreeControlNode contextNode =
+                new TreeControlNode(contextName,
+                                    "Context.gif",
+                                    nodeLabel,
+                                    "EditContext.do?select=" +
+                                    URLEncoder.encode(contextName,URL_ENCODING) +
+                                    "&nodeLabel=" +
+                                    URLEncoder.encode(nodeLabel,URL_ENCODING),
+                                    "content",
+                                    false, domain);
+            hostNode.addChild(contextNode);
+            getResources(contextNode, contextName);
+            getRealms(contextNode, contextName);
+            getValves(contextNode, contextName);
+        }
+    }
+    
+    /**
+     * Append nodes for any defined realms for the specified container.
+     *
+     * @param containerNode Container node for the tree control
+     * @param containerName Object name of the parent container
+     *
+     * @exception Exception if an exception occurs building the tree
+     */
+    public void getRealms(TreeControlNode containerNode,
+                          String containerName) throws Exception {
+
+        String domain = containerNode.getDomain();
+        Iterator realmNames =
+            Lists.getRealms(mBServer, containerName).iterator();
+        while (realmNames.hasNext()) {
+            String realmName = (String) realmNames.next();
+	    ObjectName objectName = new ObjectName(realmName);
+            // Create tree nodes for non JAASRealm only
+            try {
+                mBServer.getAttribute(objectName, "validate");
+            } catch (AttributeNotFoundException e) {
+                String nodeLabel = resources.getMessage(locale, 
+                    "server.service.treeBuilder.realmFor", 
+                    containerNode.getLabel());
+	        TreeControlNode realmNode =
+		    new TreeControlNode(realmName,
+                                    "Realm.gif",
+                                    nodeLabel,
+                                    "EditRealm.do?select=" +
+                                    URLEncoder.encode(realmName,URL_ENCODING) +
+                                    "&nodeLabel=" +
+                                    URLEncoder.encode(nodeLabel,URL_ENCODING),
+                                    "content",
+                                    false, domain);
+                containerNode.addChild(realmNode);
+            }
+        }
+        
+    }   
+        
+    
+    /**
+     * Append nodes for any define resources for the specified Context.
+     *
+     * @param containerNode Container node for the tree control
+     * @param containerName Object name of the parent container
+     * @param resources The MessageResources for our localized messages
+     *  messages
+     */
+    public void getResources(TreeControlNode containerNode, String containerName) 
+        throws Exception {
+
+        String domain = containerNode.getDomain();
+        ObjectName oname = new ObjectName(containerName);
+        String type = oname.getKeyProperty("type");
+        if (type == null) {
+            type = oname.getKeyProperty("j2eeType");
+            if (type.equals("WebModule")) {
+                type = "Context";
+            } else {
+                type = "";
+            }
+        }
+        String path = "";
+        String host = "";
+        String name = oname.getKeyProperty("name");
+        if ((name != null) && (name.length() > 0)) {
+            // context resource
+            name = name.substring(2);
+            int i = name.indexOf("/");
+            host = name.substring(0,i);
+            path = name.substring(i);
+        }     
+        TreeControlNode subtree = new TreeControlNode
+            ("Context Resource Administration " + containerName,
+             "folder_16_pad.gif",
+             resources.getMessage(locale, "resources.treeBuilder.subtreeNode"),
+             null,
+             "content",
+             true, domain);        
+        containerNode.addChild(subtree);
+        TreeControlNode datasources = new TreeControlNode
+            ("Context Data Sources " + containerName,
+            "Datasource.gif",
+            resources.getMessage(locale, "resources.treeBuilder.datasources"),
+            "resources/listDataSources.do?resourcetype=" + 
+                URLEncoder.encode(type,URL_ENCODING) + "&path=" +
+                URLEncoder.encode(path,URL_ENCODING) + "&host=" + 
+                URLEncoder.encode(host,URL_ENCODING) + "&domain=" + 
+                URLEncoder.encode(domain,URL_ENCODING) + "&forward=" +
+                URLEncoder.encode("DataSources List Setup",URL_ENCODING),
+            "content",
+            false, domain);
+        TreeControlNode mailsessions = new TreeControlNode
+            ("Context Mail Sessions " + containerName,
+            "Mailsession.gif",
+            resources.getMessage(locale, "resources.treeBuilder.mailsessions"),
+            "resources/listMailSessions.do?resourcetype=" + 
+                URLEncoder.encode(type,URL_ENCODING) + "&path=" +
+                URLEncoder.encode(path,URL_ENCODING) + "&host=" + 
+                URLEncoder.encode(host,URL_ENCODING) + "&domain=" + 
+                URLEncoder.encode(domain,URL_ENCODING) + "&forward=" +
+                URLEncoder.encode("MailSessions List Setup",URL_ENCODING),
+            "content",
+            false, domain);
+        TreeControlNode resourcelinks = new TreeControlNode
+            ("Resource Links " + containerName,
+            "ResourceLink.gif",
+            resources.getMessage(locale, "resources.treeBuilder.resourcelinks"),
+            "resources/listResourceLinks.do?resourcetype=" + 
+                URLEncoder.encode(type,URL_ENCODING) + "&path=" +
+                URLEncoder.encode(path,URL_ENCODING) + "&host=" + 
+                URLEncoder.encode(host,URL_ENCODING) + "&domain=" + 
+                URLEncoder.encode(domain,URL_ENCODING) + "&forward=" +
+                URLEncoder.encode("ResourceLinks List Setup",URL_ENCODING),
+            "content",
+            false, domain);
+        TreeControlNode envs = new TreeControlNode
+            ("Context Environment Entries "+ containerName,
+            "EnvironmentEntries.gif",
+            resources.getMessage(locale, "resources.env.entries"),
+            "resources/listEnvEntries.do?resourcetype=" + 
+                URLEncoder.encode(type,URL_ENCODING) + "&path=" +
+                URLEncoder.encode(path,URL_ENCODING) + "&host=" + 
+                URLEncoder.encode(host,URL_ENCODING) + "&domain=" + 
+                URLEncoder.encode(domain,URL_ENCODING) + "&forward=" +
+                URLEncoder.encode("EnvEntries List Setup",URL_ENCODING),
+            "content",
+            false, domain);
+        subtree.addChild(datasources);
+        subtree.addChild(mailsessions);
+        subtree.addChild(resourcelinks);
+        subtree.addChild(envs);
+    }
+    
+    
+   /**
+     * Append nodes for any defined valves for the specified container.
+     *
+     * @param containerNode Container node for the tree control
+     * @param containerName Object name of the parent container
+     *
+     * @exception Exception if an exception occurs building the tree
+     */
+    public void getValves(TreeControlNode containerNode,
+                          String containerName) throws Exception {
+
+        String domain = containerNode.getDomain();
+        Iterator valveNames =
+                Lists.getValves(mBServer, containerName).iterator();        
+        while (valveNames.hasNext()) {
+            String valveName = (String) valveNames.next();
+            ObjectName objectName = new ObjectName(valveName);
+            String nodeLabel = "Valve for " + containerNode.getLabel();
+            TreeControlNode valveNode =
+                new TreeControlNode(valveName,
+                                    "Valve.gif",
+                                    nodeLabel,
+                                    "EditValve.do?select=" +
+                                    URLEncoder.encode(valveName,URL_ENCODING) +
+                                    "&nodeLabel=" +
+                                    URLEncoder.encode(nodeLabel,URL_ENCODING) +
+                                    "&parent=" +
+                                    URLEncoder.encode(containerName,URL_ENCODING),
+                                    "content",
+                                    false, domain);
+            containerNode.addChild(valveNode);
+        }
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/TreeBuilder.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/TreeBuilder.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/TreeBuilder.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2001,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.admin;
+
+/**
+ * <p> Interface for Admin Tree Controller to build plugin components
+ * into the tree
+ *
+ * @author Jazmin Jonson
+ * @version
+ */
+
+import javax.servlet.http.HttpServletRequest;
+
+public interface TreeBuilder {
+
+    public void buildTree(TreeControl treeControl,
+                          ApplicationServlet servlet,
+                          HttpServletRequest request);
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/TreeControl.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/TreeControl.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/TreeControl.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,229 @@
+/*
+ * Copyright 2001,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.admin;
+
+
+import java.io.Serializable;
+import java.util.HashMap;
+
+
+/**
+ * <p>The overall data structure representing a <em>tree control</em>
+ * that can be rendered by the <code>TreeControlTag</code> custom tag.
+ * Each node of the tree is represented by an instance of
+ * <code>TreeControlNode</code>.</p>
+ *
+ * @author Jazmin Jonson
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class TreeControl implements Serializable {
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Construct a new instance with no predefined root node.
+     */
+    public TreeControl() {
+
+        super();
+        setRoot(null);
+
+    }
+
+
+    /**
+     * Construct a new instance with the specified root node.
+     *
+     * @param root The new root node
+     */
+    public TreeControl(TreeControlNode root) {
+
+        super();
+        setRoot(root);
+
+    }
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The collection of nodes that represent this tree, keyed by name.
+     */
+    protected HashMap registry = new HashMap();
+
+
+    /**
+     * The most recently selected node.
+     */
+    protected TreeControlNode selected = null;
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * The root node of the entire tree.
+     */
+    protected TreeControlNode root = null;
+
+    public TreeControlNode getRoot() {
+        return (this.root);
+    }
+
+    protected void setRoot(TreeControlNode root) {
+        if (this.root != null)
+            removeNode(this.root);
+        if (root != null)
+            addNode(root);
+        root.setLast(true);
+        this.root = root;
+    }
+
+
+    /**
+     * The current displayable "width" of this tree (that is, the maximum
+     * depth of the visible part of the tree).
+     */
+    public int getWidth() {
+
+        if (root == null)
+            return (0);
+        else
+            return (getWidth(root));
+
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Find and return the <code>TreeControlNode</code> for the specified
+     * node name, if it exists; otherwise, return <code>null</code>.
+     *
+     * @param name Name of the <code>TreeControlNode</code> to be returned
+     */
+    public TreeControlNode findNode(String name) {
+
+        synchronized (registry) {
+            return ((TreeControlNode) registry.get(name));
+        }
+
+    }
+
+
+    /**
+     * Mark the specified node as the one-and-only currently selected one,
+     * deselecting any previous node that was so marked.
+     *
+     * @param node Name of the node to mark as selected, or <code>null</code>
+     *  if there should be no currently selected node
+     */
+    public void selectNode(String name) {
+
+        if (selected != null) {
+            selected.setSelected(false);
+            selected = null;
+        }
+        selected = findNode(name);
+        if (selected != null)
+            selected.setSelected(true);
+
+    }
+
+
+    // -------------------------------------------------------- Package Methods
+
+
+    /**
+     * Register the specified node in our registry of the complete tree.
+     *
+     * @param node The <code>TreeControlNode</code> to be registered
+     *
+     * @exception IllegalArgumentException if the name of this node
+     *  is not unique
+     */
+    void addNode(TreeControlNode node) throws IllegalArgumentException {
+
+        synchronized (registry) {
+            String name = node.getName();
+            if (registry.containsKey(name))
+                throw new IllegalArgumentException("Name '" + name +
+                                                   "' is not unique");
+            node.setTree(this);
+            registry.put(name, node);
+        }
+
+    }
+
+
+    /**
+     * Calculate the width of the subtree below the specified node.
+     *
+     * @param node The node for which to calculate the width
+     */
+    int getWidth(TreeControlNode node) {
+
+        int width = node.getWidth();
+        if (!node.isExpanded())
+            return (width);
+        TreeControlNode children[] = node.findChildren();
+        for (int i = 0; i < children.length; i++) {
+            int current = getWidth(children[i]);
+            if (current > width)
+                width = current;
+        }
+        return (width);
+
+    }
+
+
+    /**
+     * Deregister the specified node, as well as all child nodes of this
+     * node, from our registry of the complete tree.  If this node is not
+     * present, no action is taken.
+     *
+     * @param node The <code>TreeControlNode</code> to be deregistered
+     */
+    void removeNode(TreeControlNode node) {
+
+        synchronized (registry) {
+            TreeControlNode children[] = node.findChildren();
+            for (int i = 0; i < children.length; i++)
+                removeNode(children[i]);
+            TreeControlNode parent = node.getParent();
+            if (parent != null) {
+                parent.removeChild(node);
+            }
+            node.setParent(null);
+            node.setTree(null);
+            if (node == this.root) {
+                this.root = null;
+            }
+            registry.remove(node.getName());
+        }
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/TreeControlNode.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/TreeControlNode.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/TreeControlNode.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,372 @@
+/*
+ * Copyright 2001,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.admin;
+
+
+import java.io.Serializable;
+import java.util.ArrayList;
+
+
+/**
+ * <p>An individual node of a tree control represented by an instance of
+ * <code>TreeControl</code>, and rendered by an instance of
+ * <code>TreeControlTag</code>.</p>
+ *
+ * @author Jazmin Jonson
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class TreeControlNode implements Serializable {
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Construct a new TreeControlNode with the specified parameters.
+     *
+     * @param name Internal name of this node (must be unique within
+     *  the entire tree)
+     * @param icon Pathname of the image file for the icon to be displayed
+     *  when this node is visible, relative to the image directory
+     *  for our images
+     * @param label The label that will be displayed to the user if
+     *  this node is visible
+     * @param action The hyperlink to be selected if the user
+     *  selects this node, or <code>null</code> if this node's label should
+     *  not be a hyperlink
+     * @param target The window target in which the <code>action</code>
+     *  hyperlink's results will be displayed, or <code>null</code> for
+     *  the current window
+     * @param expanded Should this node be expanded?
+     */
+    public TreeControlNode(String name,
+                           String icon, String label,
+                           String action, String target,
+                           boolean expanded, String domain) {
+
+        super();
+        this.name = name;
+        this.icon = icon;
+        this.label = label;
+        this.action = action;
+        this.target = target;
+        this.expanded = expanded;
+        this.domain = domain;
+
+    }
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The set of child <code>TreeControlNodes</code> for this node, in the
+     * order that they should be displayed.
+     */
+    protected ArrayList children = new ArrayList();
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * The hyperlink to which control will be directed if this node
+     * is selected by the user.
+     */
+    protected String action = null;
+
+    public String getAction() {
+        return (this.action);
+    }
+
+    /**
+     * The domain of this node.
+     */
+    protected String domain = null;
+
+    public String getDomain() {
+        return (this.domain);
+    }
+
+    /**
+     * Is this node currently expanded?
+     */
+    protected boolean expanded = false;
+
+    public boolean isExpanded() {
+        return (this.expanded);
+    }
+
+    public void setExpanded(boolean expanded) {
+        this.expanded = expanded;
+    }
+
+
+    /**
+     * The pathname to the icon file displayed when this node is visible,
+     * relative to the image directory for our images.
+     */
+    protected String icon = null;
+
+    public String getIcon() {
+        return (this.icon);
+    }
+
+
+    /**
+     * The label that will be displayed when this node is visible.
+     */
+    protected String label = null;
+
+    public String getLabel() {
+        return (this.label);
+    }
+
+
+    /**
+     * Is this the last node in the set of children for our parent node?
+     */
+    protected boolean last = false;
+
+    public boolean isLast() {
+        return (this.last);
+    }
+
+    void setLast(boolean last) {
+        this.last = last;
+    }
+
+
+    /**
+     * Is this a "leaf" node (i.e. one with no children)?
+     */
+    public boolean isLeaf() {
+        synchronized (children) {
+            return (children.size() < 1);
+        }
+    }
+
+
+    /**
+     * The unique (within the entire tree) name of this node.
+     */
+    protected String name = null;
+
+    public String getName() {
+        return (this.name);
+    }
+
+
+    /**
+     * The parent node of this node, or <code>null</code> if this
+     * is the root node.
+     */
+    protected TreeControlNode parent = null;
+
+    public TreeControlNode getParent() {
+        return (this.parent);
+    }
+
+    void setParent(TreeControlNode parent) {
+        this.parent = parent;
+        if (parent == null)
+            width = 1;
+        else
+            width = parent.getWidth() + 1;
+    }
+
+
+    /**
+     * Is this node currently selected?
+     */
+    protected boolean selected = false;
+
+    public boolean isSelected() {
+        return (this.selected);
+    }
+
+    public void setSelected(boolean selected) {
+        this.selected = selected;
+    }
+
+
+    /**
+     * The window target for the hyperlink identified by the
+     * <code>action</code> property, if this node is selected
+     * by the user.
+     */
+    protected String target = null;
+
+    public String getTarget() {
+        return (this.target);
+    }
+
+
+    /**
+     * The <code>TreeControl</code> instance representing the
+     * entire tree.
+     */
+    protected TreeControl tree = null;
+
+    public TreeControl getTree() {
+        return (this.tree);
+    }
+
+    void setTree(TreeControl tree) {
+        this.tree = tree;
+    }
+
+
+    /**
+     * The display width necessary to display this item (if it is visible).
+     * If this item is not visible, the calculated width will be that of our
+     * most immediately visible parent.
+     */
+    protected int width = 0;
+
+    public int getWidth() {
+        return (this.width);
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Add a new child node to the end of the list.
+     *
+     * @param child The new child node
+     *
+     * @exception IllegalArgumentException if the name of the new child
+     *  node is not unique
+     */
+    public void addChild(TreeControlNode child)
+        throws IllegalArgumentException {
+
+        tree.addNode(child);
+        child.setParent(this);
+        synchronized (children) {
+            int n = children.size();
+            if (n > 0) {
+                TreeControlNode node = (TreeControlNode) children.get(n - 1);
+                node.setLast(false);
+            }
+            child.setLast(true);
+            children.add(child);
+        }
+
+    }
+
+
+    /**
+     * Add a new child node at the specified position in the child list.
+     *
+     * @param offset Zero-relative offset at which the new node
+     *  should be inserted
+     * @param child The new child node
+     *
+     * @exception IllegalArgumentException if the name of the new child
+     *  node is not unique
+     */
+    public void addChild(int offset, TreeControlNode child)
+        throws IllegalArgumentException {
+
+        tree.addNode(child);
+        child.setParent(this);
+        synchronized (children) {
+            children.add(offset, child);
+        }
+
+    }
+
+
+    /**
+     * Return the set of child nodes for this node.
+     */
+    public TreeControlNode[] findChildren() {
+
+        synchronized (children) {
+            TreeControlNode results[] = new TreeControlNode[children.size()];
+            return ((TreeControlNode[]) children.toArray(results));
+        }
+
+    }
+
+
+    /**
+     * Remove this node from the tree.
+     */
+    public void remove() {
+
+        if (tree != null) {
+            tree.removeNode(this);
+        }
+
+    }
+
+
+    /**
+     * Remove the child node (and all children of that child) at the
+     * specified position in the child list.
+     *
+     * @param offset Zero-relative offset at which the existing
+     *  node should be removed
+     */
+    public void removeChild(int offset) {
+
+        synchronized (children) {
+            TreeControlNode child =
+                (TreeControlNode) children.get(offset);
+            tree.removeNode(child);
+            child.setParent(null);
+            children.remove(offset);
+        }
+
+    }
+
+
+    // -------------------------------------------------------- Package Methods
+
+
+    /**
+     * Remove the specified child node.  It is assumed that all of the
+     * children of this child node have already been removed.
+     *
+     * @param child Child node to be removed
+     */
+    void removeChild(TreeControlNode child) {
+
+        if (child == null) {
+            return;
+        }
+        synchronized (children) {
+            int n = children.size();
+            for (int i = 0; i < n; i++) {
+                if (child == (TreeControlNode) children.get(i)) {
+                    children.remove(i);
+                    return;
+                }
+            }
+        }
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/TreeControlTag.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/TreeControlTag.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/TreeControlTag.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,520 @@
+/*
+ * Copyright 2001,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.admin;
+
+
+import java.io.IOException;
+import java.net.URLEncoder;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.jsp.JspException;
+import javax.servlet.jsp.JspWriter;
+import javax.servlet.jsp.PageContext;
+import javax.servlet.jsp.tagext.TagSupport;
+
+
+/**
+ * <p>JSP custom tag that renders a tree control represented by the
+ * <code>TreeControl</code> and <code>TreeControlNode</code> classes.
+ * This tag has the following user-settable attributes:</p>
+ * <ul>
+ * <li><strong>action</strong> - Hyperlink to which expand/contract actions
+ *     should be sent, with a string "<code>{name}</code> marking where
+ *     the node name of the affected node should be included.</li>
+ * <li><strong>images</strong> - Name of the directory containing the images
+ *     for our icons, relative to the page including this tag.  If not
+ *     specified, defaults to "images".</li>
+ * <li><strong>scope</strong> - Attribute scope in which the <code>tree</code>
+ *     attribute is to be found (page, request, session, application).  If
+ *     not specified, the attribute is searched for in all scopes.</li>
+ * <li><strong>style</strong> - CSS style <code>class</code> to be applied
+ *     to be applied to the entire rendered output of the tree control.
+ *     If not specified, no style class is applied.</li>
+ * <li><strong>styleSelected</strong> - CSS style <code>class</code> to be
+ *     applied to the text of any element that is currently selected.  If not
+ *     specified, no additional style class is applied.</li>
+ * <li><strong>styleUnselected</strong> - CSS style <code>class</code> to be
+ *     applied to the text of any element that is not currently selected.
+ *     If not specified, no additional style class is applied.</li>
+ * <li><strong>tree</strong> - Attribute name under which the
+ *     <code>TreeControl</code> bean of the tree we are rendering
+ *     is stored, in the scope specified by the <code>scope</code>
+ *     attribute.  This attribute is required.</li>
+ * </ul>
+ *
+ * <strong>FIXME</strong> - Internationalize the exception messages!
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 303561 $ $Date: 2004-12-01 21:49:01 -0600 (Wed, 01 Dec 2004) $
+ */
+
+public class TreeControlTag extends TagSupport {
+
+
+    /**
+     * The default directory name for icon images.
+     */
+    static final String DEFAULT_IMAGES = "images";
+
+
+    /**
+     * The names of tree state images that we need.
+     */
+    static final String IMAGE_HANDLE_DOWN_LAST =    "handledownlast.gif";
+    static final String IMAGE_HANDLE_DOWN_MIDDLE =  "handledownmiddle.gif";
+    static final String IMAGE_HANDLE_RIGHT_LAST =   "handlerightlast.gif";
+    static final String IMAGE_HANDLE_RIGHT_MIDDLE = "handlerightmiddle.gif";
+    static final String IMAGE_LINE_LAST =           "linelastnode.gif";
+    static final String IMAGE_LINE_MIDDLE =         "linemiddlenode.gif";
+    static final String IMAGE_LINE_VERTICAL =       "linevertical.gif";
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * The hyperlink to be used for submitting requests to expand and
+     * contract tree nodes.  The placeholder "<code>{name}</code>" will
+     * be replaced by the <code>name</code> property of the current
+     * tree node.
+     */
+    protected String action = null;
+
+    public String getAction() {
+        return (this.action);
+    }
+
+    public void setAction(String action) {
+        this.action = action;
+    }
+
+
+    /**
+     * The name of the directory containing the images for our icons,
+     * relative to the page including this tag.
+     */
+    protected String images = DEFAULT_IMAGES;
+
+    public String getImages() {
+        return (this.images);
+    }
+
+    public void setImages(String images) {
+        this.images = images;
+    }
+
+
+    /**
+     * The name of the scope in which to search for the <code>tree</code>
+     * attribute.  Must be "page", "request", "session", or "application"
+     * (or <code>null</code> for an ascending-visibility search).
+     */
+    protected String scope = null;
+
+    public String getScope() {
+        return (this.scope);
+    }
+
+    public void setScope(String scope) {
+        if (!"page".equals(scope) &&
+            !"request".equals(scope) &&
+            !"session".equals(scope) &&
+            !"application".equals(scope))
+            throw new IllegalArgumentException("Invalid scope '" +
+                                               scope + "'");
+        this.scope = scope;
+    }
+
+
+    /**
+     * The CSS style <code>class</code> to be applied to the entire tree.
+     */
+    protected String style = null;
+
+    public String getStyle() {
+        return (this.style);
+    }
+
+    public void setStyle(String style) {
+        this.style = style;
+    }
+
+
+    /**
+     * The CSS style <code>class</code> to be applied to the text
+     * of selected nodes.
+     */
+    protected String styleSelected = null;
+
+    public String getStyleSelected() {
+        return (this.styleSelected);
+    }
+
+    public void setStyleSelected(String styleSelected) {
+        this.styleSelected = styleSelected;
+    }
+
+
+    /**
+     * The CSS style <code>class</code> to be applied to the text
+     * of unselected nodes.
+     */
+    protected String styleUnselected = null;
+
+    public String getStyleUnselected() {
+        return (this.styleUnselected);
+    }
+
+    public void setStyleUnselected(String styleUnselected) {
+        this.styleUnselected = styleUnselected;
+    }
+
+
+    /**
+     * The name of the attribute (in the specified scope) under which our
+     * <code>TreeControl</code> instance is stored.
+     */
+    protected String tree = null;
+
+    public String getTree() {
+        return (this.tree);
+    }
+
+    public void setTree(String tree) {
+        this.tree = tree;
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Render this tree control.
+     *
+     * @exception JspException if a processing error occurs
+     */
+    public int doEndTag() throws JspException {
+
+        TreeControl treeControl = getTreeControl();
+        JspWriter out = pageContext.getOut();
+        try {
+            out.print
+                ("<table border=\"0\" cellspacing=\"0\" cellpadding=\"0\"");
+            if (style != null) {
+                out.print(" class=\"");
+                out.print(style);
+                out.print("\"");
+            }
+            out.println(">");
+            int level = 0;
+            TreeControlNode node = treeControl.getRoot();
+            render(out, node, level, treeControl.getWidth(), true);
+            out.println("</table>");
+        } catch (IOException e) {
+            throw new JspException(e);
+        }
+
+        return (EVAL_PAGE);
+
+    }
+
+
+    /**
+     * Release all state information set by this tag.
+     */
+    public void release() {
+
+        this.action = null;
+        this.images = DEFAULT_IMAGES;
+        this.scope = null;
+        this.style = null;
+        this.styleSelected = null;
+        this.styleUnselected = null;
+        this.tree = null;
+
+    }
+
+
+    // ------------------------------------------------------ Protected Methods
+
+
+    /**
+     * Return the <code>TreeControl</code> instance for the tree control that
+     * we are rendering.
+     *
+     * @exception JspException if no TreeControl instance can be found
+     */
+    protected TreeControl getTreeControl() throws JspException {
+
+        Object treeControl = null;
+        if (scope == null)
+            treeControl = pageContext.findAttribute(tree);
+        else if ("page".equals(scope))
+            treeControl =
+                pageContext.getAttribute(tree, PageContext.PAGE_SCOPE);
+        else if ("request".equals(scope))
+            treeControl =
+                pageContext.getAttribute(tree, PageContext.REQUEST_SCOPE);
+        else if ("session".equals(scope))
+            treeControl =
+                pageContext.getAttribute(tree, PageContext.SESSION_SCOPE);
+        else if ("application".equals(scope))
+            treeControl =
+                pageContext.getAttribute(tree, PageContext.APPLICATION_SCOPE);
+        if (treeControl == null)
+            throw new JspException("Cannot find tree control attribute '" +
+                                   tree + "'");
+        else if (!(treeControl instanceof TreeControl))
+            throw new JspException("Invalid tree control attribute '" +
+                                   tree + "'");
+        else
+            return ((TreeControl) treeControl);
+
+    }
+
+
+    /**
+     * Render the specified node, as controlled by the specified parameters.
+     *
+     * @param out The <code>JspWriter</code> to which we are writing
+     * @param node The <code>TreeControlNode</code> we are currently
+     *  rendering
+     * @param level The indentation level of this node in the tree
+     * @param width Total displayable width of the tree
+     * @param last Is this the last node in a list?
+     *
+     * @exception IOException if an input/output error occurs
+     */
+    protected void render(JspWriter out, TreeControlNode node,
+                          int level, int width, boolean last)
+        throws IOException {
+
+        HttpServletResponse response =
+            (HttpServletResponse) pageContext.getResponse();
+    
+        // if the node is root node and the label value is
+        // null, then do not render root node in the tree.
+        
+        if ("ROOT-NODE".equalsIgnoreCase(node.getName()) &&
+        (node.getLabel() == null)) {
+            // Render the children of this node
+            TreeControlNode children[] = node.findChildren();
+            int lastIndex = children.length - 1;
+            int newLevel = level + 1;
+            for (int i = 0; i < children.length; i++) {
+                render(out, children[i], newLevel, width, i == lastIndex);
+            }
+            return;
+        }
+        
+        // Render the beginning of this node
+        out.println("  <tr valign=\"middle\">");
+
+        // Create the appropriate number of indents
+        for (int i = 0; i < level; i++) {
+            int levels = level - i;
+            TreeControlNode parent = node;
+            for (int j = 1; j <= levels; j++)
+                parent = parent.getParent();
+            if (parent.isLast())
+                out.print("    <td></td>");
+            else {
+                out.print("    <td><img src=\"");
+                out.print(images);
+                out.print("/");
+                out.print(IMAGE_LINE_VERTICAL);
+                out.print("\" alt=\"\" border=\"0\"></td>");
+            }
+            out.println();
+        }
+
+        // Render the tree state image for this node
+
+        // HACK to take into account special characters like = and &
+        // in the node name, could remove this code if encode URL
+        // and later request.getParameter() could deal with = and &
+        // character in parameter values. 
+        String encodedNodeName = URLEncoder.encode(node.getName(),TomcatTreeBuilder.URL_ENCODING);
+
+        String action = replace(getAction(), "{name}", encodedNodeName);
+
+        
+        String updateTreeAction =
+            replace(getAction(), "tree={name}", "select=" + encodedNodeName);
+        updateTreeAction =
+            ((HttpServletResponse) pageContext.getResponse()).
+            encodeURL(updateTreeAction);
+
+        out.print("    <td>");
+        if ((action != null) && !node.isLeaf()) {
+            out.print("<a href=\"");
+            out.print(response.encodeURL(action));
+            out.print("\">");
+        }
+        out.print("<img src=\"");
+        out.print(images);
+        out.print("/");
+        if (node.isLeaf()) {
+            if (node.isLast())
+                out.print(IMAGE_LINE_LAST);
+            else
+                out.print(IMAGE_LINE_MIDDLE);
+            out.print("\" alt=\"");
+        } else if (node.isExpanded()) {
+            if (node.isLast())
+                out.print(IMAGE_HANDLE_DOWN_LAST);
+            else
+                out.print(IMAGE_HANDLE_DOWN_MIDDLE);
+            out.print("\" alt=\"close node");
+        } else {
+            if (node.isLast())
+                out.print(IMAGE_HANDLE_RIGHT_LAST);
+            else
+                out.print(IMAGE_HANDLE_RIGHT_MIDDLE);
+            out.print("\" alt=\"expand node");
+        }
+        out.print("\" border=\"0\">");
+        if ((action != null) && !node.isLeaf())
+            out.print("</a>");
+        out.println("</td>");
+
+        // Calculate the hyperlink for this node (if any)
+        String hyperlink = null;
+        if (node.getAction() != null)
+            hyperlink = ((HttpServletResponse) pageContext.getResponse()).
+                encodeURL(node.getAction());
+
+        // Render the icon for this node (if any)
+        out.print("    <td colspan=\"");
+        out.print(width - level + 1);
+        out.print("\">");
+        if (node.getIcon() != null) {
+            if (hyperlink != null) {
+                out.print("<a href=\"");
+                out.print(hyperlink);
+                out.print("\"");
+                String target = node.getTarget();
+                if(target != null) {
+                    out.print(" target=\"");
+                    out.print(target);
+                    out.print("\"");
+                }
+                // to refresh the tree in the same 'self' frame
+                out.print(" onclick=\"");
+                out.print("self.location.href='" + updateTreeAction + "'");
+                out.print("\"");
+                out.print(">");
+            }
+            out.print("<img src=\"");
+            out.print(images);
+            out.print("/");
+            out.print(node.getIcon());
+            out.print("\" alt=\"");
+            out.print("\" border=\"0\">");
+            if (hyperlink != null)
+                out.print("</a>");
+        }
+
+        // Render the label for this node (if any)
+
+        if (node.getLabel() != null) {
+            String labelStyle = null;
+            if (node.isSelected() && (styleSelected != null))
+                labelStyle = styleSelected;
+            else if (!node.isSelected() && (styleUnselected != null))
+                labelStyle = styleUnselected;
+            if (hyperlink != null) {
+                // Note the leading space so that the text has some space
+                // between it and any preceding images
+                out.print(" <a href=\"");
+                out.print(hyperlink);
+                out.print("\"");
+                String target = node.getTarget();
+                if(target != null) {
+                    out.print(" target=\"");
+                    out.print(target);
+                    out.print("\"");
+                }
+                if (labelStyle != null) {
+                    out.print(" class=\"");
+                    out.print(labelStyle);
+                    out.print("\"");
+                }
+                // to refresh the tree in the same 'self' frame
+                out.print(" onclick=\"");
+                out.print("self.location.href='" + updateTreeAction + "'");
+                out.print("\"");
+                out.print(">");
+            } else if (labelStyle != null) {
+                out.print("<span class=\"");
+                out.print(labelStyle);
+                out.print("\">");
+            }
+            out.print(node.getLabel());
+            if (hyperlink != null)
+                out.print("</a>");
+            else if (labelStyle != null)
+                out.print("</span>");
+        }
+        out.println("</td>");
+
+        // Render the end of this node
+        out.println("  </tr>");
+
+        // Render the children of this node
+        if (node.isExpanded()) {
+            TreeControlNode children[] = node.findChildren();
+            int lastIndex = children.length - 1;
+            int newLevel = level + 1;
+            for (int i = 0; i < children.length; i++) {
+                render(out, children[i], newLevel, width, i == lastIndex);
+            }
+        }
+
+    }
+
+
+    /**
+     * Replace any occurrence of the specified placeholder in the specified
+     * template string with the specified replacement value.
+     *
+     * @param template Pattern string possibly containing the placeholder
+     * @param placeholder Placeholder expression to be replaced
+     * @param value Replacement value for the placeholder
+     */
+    protected String replace(String template, String placeholder,
+                             String value) {
+
+        if (template == null)
+            return (null);
+        if ((placeholder == null) || (value == null))
+            return (template);
+        while (true) {
+            int index = template.indexOf(placeholder);
+            if (index < 0)
+                break;
+            StringBuffer temp = new StringBuffer(template.substring(0, index));
+            temp.append(value);
+            temp.append(template.substring(index + placeholder.length()));
+            template = temp.toString();
+        }
+        return (template);
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/TreeControlTestAction.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/TreeControlTestAction.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/TreeControlTestAction.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,108 @@
+/*
+ * Copyright 2001,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.admin;
+
+
+import java.io.IOException;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Locale;
+import java.net.URLDecoder;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+import org.apache.struts.action.Action;
+import org.apache.struts.action.ActionErrors;
+import org.apache.struts.action.ActionForm;
+import org.apache.struts.action.ActionForward;
+import org.apache.struts.action.ActionMapping;
+
+
+/**
+ * Test <code>Action</code> that handles events from the tree control test
+ * page.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 303390 $ $Date: 2004-10-18 01:37:56 -0500 (Mon, 18 Oct 2004) $
+ */
+
+public class TreeControlTestAction extends Action {
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Process the specified HTTP request, and create the corresponding HTTP
+     * response (or forward to another web component that will create it).
+     * Return an <code>ActionForward</code> instance describing where and how
+     * control should be forwarded, or <code>null</code> if the response has
+     * already been completed.
+     *
+     * @param mapping The ActionMapping used to select this instance
+     * @param actionForm The optional ActionForm bean for this request (if any)
+     * @param request The HTTP request we are processing
+     * @param response The HTTP response we are creating
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception ServletException if a servlet exception occurs
+     */
+    public ActionForward execute(ActionMapping mapping,
+                                 ActionForm form,
+                                 HttpServletRequest request,
+                                 HttpServletResponse response)
+        throws IOException, ServletException {
+
+        getServlet().log("Entered TreeControlTestAction:perform()");
+
+        String name = null;
+        HttpSession session = request.getSession();
+        TreeControl control =
+            (TreeControl) session.getAttribute("treeControlTest");
+
+        // Handle a tree expand/contract event
+        name = request.getParameter("tree");
+
+        if (name != null) {
+            getServlet().log("Tree expand/contract on " + name);
+
+            TreeControlNode node = control.findNode(name);
+
+            if (node != null){
+                getServlet().log("Found Node: " + name);
+                node.setExpanded(!node.isExpanded());
+            }
+        }else{
+            getServlet().log("tree param is null");
+        }
+
+        // Handle a select item event
+        name = request.getParameter("select");
+        if (name != null) {
+            getServlet().log("Select event on " + name);
+            control.selectNode(name);
+        }
+
+        // Forward back to the test page
+        return (mapping.findForward("Tree Control Test"));
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/connector/AddConnectorAction.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/connector/AddConnectorAction.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/connector/AddConnectorAction.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,156 @@
+/*
+ * Copyright 2001-2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.admin.connector;
+
+import java.io.IOException;
+import java.net.URLEncoder;
+import java.util.Locale;
+import java.util.ArrayList;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+import org.apache.struts.action.Action;
+import org.apache.struts.action.ActionErrors;
+import org.apache.struts.action.ActionForm;
+import org.apache.struts.action.ActionForward;
+import org.apache.struts.action.ActionMapping;
+import org.apache.struts.util.MessageResources;
+import org.apache.webapp.admin.TomcatTreeBuilder;
+import org.apache.webapp.admin.LabelValueBean;
+import org.apache.webapp.admin.Lists;
+
+/**
+ * The <code>Action</code> that sets up <em>Add Connector</em> transactions.
+ *
+ * @author Manveen Kaur
+ * @version $Revision: 303390 $ $Date: 2004-10-18 01:37:56 -0500 (Mon, 18 Oct 2004) $
+ */
+
+public class AddConnectorAction extends Action {
+    
+    
+    // --------------------------------------------------------- Public Methods
+    
+    /**
+     * Process the specified HTTP request, and create the corresponding HTTP
+     * response (or forward to another web component that will create it).
+     * Return an <code>ActionForward</code> instance describing where and how
+     * control should be forwarded, or <code>null</code> if the response has
+     * already been completed.
+     *
+     * @param mapping The ActionMapping used to select this instance
+     * @param actionForm The optional ActionForm bean for this request (if any)
+     * @param request The HTTP request we are processing
+     * @param response The HTTP response we are creating
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception ServletException if a servlet exception occurs
+     */
+    public ActionForward execute(ActionMapping mapping,
+    ActionForm form,
+    HttpServletRequest request,
+    HttpServletResponse response)
+    throws IOException, ServletException {
+        
+        // Acquire the resources that we need
+        HttpSession session = request.getSession();
+        
+        // the service Name is needed to retrieve the engine mBean to
+        // which the new connector mBean will be added.
+        String serviceName = request.getParameter("select");
+        
+        // Fill in the form values for display and editing
+        ConnectorForm connectorFm = new ConnectorForm();
+        session.setAttribute("connectorForm", connectorFm);
+        connectorFm.setAdminAction("Create");
+        connectorFm.setObjectName("");
+        connectorFm.setConnectorName("");
+        String type = request.getParameter("type");
+        if (type == null)
+            type = "HTTP";    // default type is HTTP
+        connectorFm.setConnectorType(type);
+        connectorFm.setServiceName(serviceName);
+        if ("HTTPS".equalsIgnoreCase(type)) {
+            connectorFm.setScheme("https");
+        } else {
+            connectorFm.setScheme("http");       
+        }
+        connectorFm.setAcceptCountText("10");
+        connectorFm.setCompression("off");
+        connectorFm.setConnLingerText("-1");
+        connectorFm.setConnTimeOutText("60000");
+        connectorFm.setConnUploadTimeOutText("300000");
+        connectorFm.setBufferSizeText("2048");
+        connectorFm.setDisableUploadTimeout("false");
+        connectorFm.setEnableLookups("true");
+        connectorFm.setAddress("");
+        connectorFm.setPortText("");
+        connectorFm.setRedirectPortText("-1");
+        connectorFm.setMinProcessorsText("5");
+        connectorFm.setMaxProcessorsText("20");
+        connectorFm.setMaxKeepAliveText("100");
+        connectorFm.setMaxSpare("50");
+        connectorFm.setMaxThreads("200");
+        connectorFm.setMinSpare("4");
+        connectorFm.setThreadPriority(String.valueOf(Thread.NORM_PRIORITY));
+        connectorFm.setSecure("false");
+        connectorFm.setTcpNoDelay("true");
+        connectorFm.setXpoweredBy("false");
+
+        //supported only by HTTPS
+        connectorFm.setAlgorithm("SunX509");
+        connectorFm.setClientAuthentication("false");
+        connectorFm.setCiphers("");
+        connectorFm.setKeyStoreFileName("");
+        connectorFm.setKeyStorePassword("");
+        connectorFm.setKeyStoreType("JKS");
+        connectorFm.setSslProtocol("TLS");
+                       
+        // supported only by Coyote connectors
+        connectorFm.setProxyName("");
+        connectorFm.setProxyPortText("0");        
+        
+        connectorFm.setBooleanVals(Lists.getBooleanValues());                
+        connectorFm.setClientAuthVals(Lists.getClientAuthValues());
+        
+        String schemeTypes[]= new String[3];
+        schemeTypes[0] = "HTTP";
+        schemeTypes[1] = "HTTPS";                
+        schemeTypes[2] = "AJP";
+        
+        ArrayList types = new ArrayList();    
+        // the first element in the select list should be the type selected
+        types.add(new LabelValueBean(type,
+                "AddConnector.do?select=" + 
+                URLEncoder.encode(serviceName,TomcatTreeBuilder.URL_ENCODING) 
+                + "&type=" + type));        
+         for (int i=0; i< schemeTypes.length; i++) {
+            if (!type.equalsIgnoreCase(schemeTypes[i])) {
+                types.add(new LabelValueBean(schemeTypes[i],
+                "AddConnector.do?select=" + 
+                URLEncoder.encode(serviceName,TomcatTreeBuilder.URL_ENCODING)
+                + "&type=" + schemeTypes[i]));        
+            }
+        }
+        connectorFm.setConnectorTypeVals(types);
+        
+        // Forward to the connector display page
+        return (mapping.findForward("Connector"));
+        
+    }        
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/connector/ConnectorForm.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/connector/ConnectorForm.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/connector/ConnectorForm.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,1205 @@
+/*
+ * Copyright 2001,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.admin.connector;
+
+import javax.servlet.http.HttpServletRequest;
+import org.apache.struts.action.ActionError;
+import org.apache.struts.action.ActionErrors;
+import org.apache.struts.action.ActionForm;
+import org.apache.struts.action.ActionMapping;
+import java.net.InetAddress;
+import java.util.List;
+
+/**
+ * Form bean for the connector page.
+ *
+ * @author Manveen Kaur
+ * @version $Revision: 302986 $ $Date: 2004-06-27 21:14:52 -0500 (Sun, 27 Jun 2004) $
+ */
+
+public final class ConnectorForm extends ActionForm {
+    
+    // ----------------------------------------------------- Instance Variables
+    
+     /**
+     * The administrative action represented by this form.
+     */
+    private String adminAction = "Edit";
+
+    /**
+     * The object name of the Connector this bean refers to.
+     */
+    private String objectName = null;
+    
+    /**
+     * The object name of the service this connector belongs to.
+     */
+    private String serviceName = null;
+   
+    /**
+     * The text for the scheme.
+     */
+    private String scheme = null;
+
+    /**
+     * The text for the connector type. 
+     * Specifies if it is a CoyoteConnector or AJP13Connector etc.
+     */
+    private String connectorType = null;    
+    
+     /**
+     * The text for the node label.
+     */
+    private String nodeLabel = null;
+    
+    /**
+     * The text for the accept Count.
+     */
+    private String acceptCountText = null;
+    
+    /**
+     * The text for the algorithm.
+     */
+    private String algorithm = null;
+    
+    /**
+     * The text for the ciphers.
+     */
+    private String ciphers = null;
+    
+    /**
+     * The text for the Connection Linger.
+     */
+    private String connLingerText = null;
+    
+    /**
+     * The text for the Connection Time Out.
+     */
+    private String connTimeOutText = null;
+    
+    /**
+     * The text for the Connection Upload Time Out.
+     */
+    private String connUploadTimeOutText = null;
+    
+    /**
+     * The text for the buffer size.
+     */
+    private String bufferSizeText = null;
+    
+    /**
+     * The value of disable upload timeout.
+     */
+    private String disableUploadTimeout = "false";
+    
+    /**
+     * The value of enable Lookups.
+     */
+    private String enableLookups = "false";
+    
+    /**
+     * The value of compression.
+     */
+    private String compression = "off";
+    
+    /**
+     * The text for the address.
+     */
+    private String address = null;
+    
+    /**
+     * The text for the minProcessors.
+     */
+    private String minProcessorsText = null;
+    
+    /**
+     * The text for the max Processors.
+     */
+    private String maxProcessorsText = null;
+    
+    /**
+     * The text for the maxKeepAlive.
+     */
+    private String maxKeepAliveText = null;
+    
+    /**
+     * The text for the maxSpare.
+     */
+    private String maxSpare = null;
+    
+    /**
+     * The text for the maxThreads.
+     */
+    private String maxThreads = null;
+    
+    /**
+     * The text for the minSpare.
+     */
+    private String minSpare = null;
+
+    /**
+     * The text for the threadPriority.
+     */
+    private String threadPriority = null;
+    
+    /**
+     * The text for the URIEncoding.
+     */
+    private String uriEncodingText = null;
+    
+    /**
+     * The value of useBodyEncodingForURI.
+     */
+    private String useBodyEncodingForURI = "false";
+
+    /**
+     * The value of allowTrace.
+     */
+    private String allowTrace = "false";
+
+    /**
+     * The text for the port.
+     */
+    private String portText = null;
+    
+    /**
+     * The text for the redirect port.
+     */
+    private String redirectPortText = null;
+    
+    /**
+     * The text for the proxyName.
+     */
+    private String proxyName = null;
+    
+    /**
+     * The text for the proxy Port Number.
+     */
+    private String proxyPortText = null;
+    
+    
+    /**
+     * The text for the connectorName.
+     */
+    private String connectorName = null;
+        
+    /**
+     * Whether client authentication is supported.
+     */
+    private String clientAuthentication = "false";
+        
+    /**
+     * The keyStore Filename.
+     */
+    private String keyStoreFileName = null;
+        
+    /**
+     * The keyStore Password.
+     */
+    private String keyStorePassword = null;
+    
+    /**
+     * The keyStore Type.
+     */
+    private String keyStoreType = null;
+
+    /**
+     * The text for the Ssl Protocol.
+     */
+    private String sslProtocol= null;
+    
+    /*
+     * Represent boolean (true, false) values for enableLookups etc.
+     */    
+    private List booleanVals = null;
+
+    /*
+     * Represent supported connector types.
+     */    
+    private List connectorTypeVals = null;
+
+    /**
+     * Represent supported clientAuth values.
+     */
+    private List clientAuthVals = null;
+
+    /**
+     * The value of secure.
+     */
+    private String secure = "false";
+    /**
+     * The value of tcpNoDelay.
+     */
+    private String tcpNoDelay = "true";
+    
+    /**
+     * The value of xpoweredBy.
+     */
+    private String xpoweredBy = "false";
+    
+    // ------------------------------------------------------------- Properties
+    
+   /**
+     * Return the administrative action represented by this form.
+     */
+    public String getAdminAction() {
+
+        return this.adminAction;
+
+    }
+
+
+    /**
+     * Set the administrative action represented by this form.
+     */
+    public void setAdminAction(String adminAction) {
+
+        this.adminAction = adminAction;
+
+    }
+
+    /**
+     * Return the object name of the Connector this bean refers to.
+     */
+    public String getObjectName() {
+
+        return this.objectName;
+
+    }
+
+
+    /**
+     * Set the object name of the Connector this bean refers to.
+     */
+    public void setObjectName(String objectName) {
+
+        this.objectName = objectName;
+
+    }
+    
+      /**
+     * Return the object name of the service this connector belongs to.
+     */
+    public String getServiceName() {
+
+        return this.serviceName;
+
+    }
+
+
+    /**
+     * Set the object name of the Service this connector belongs to.
+     */
+    public void setServiceName(String serviceName) {
+
+        this.serviceName = serviceName;
+
+    }
+    
+    /**
+     * Return the Scheme.
+     */
+    public String getScheme() {
+        
+        return this.scheme;
+        
+    }
+    
+    /**
+     * Set the Scheme.
+     */
+    public void setScheme(String scheme) {
+        
+        this.scheme = scheme;
+        
+    }
+    
+    /**
+     * Return the Connector type.
+     */
+    public String getConnectorType() {
+        
+        return this.connectorType;
+        
+    }
+    
+    /**
+     * Set the Connector type.
+     */
+    public void setConnectorType(String connectorType) {
+        
+        this.connectorType = connectorType;
+        
+    }
+    
+    /**
+     * Return the label of the node that was clicked.
+     */
+    public String getNodeLabel() {
+        
+        return this.nodeLabel;
+        
+    }
+    
+    /**
+     * Set the node label.
+     */
+    public void setNodeLabel(String nodeLabel) {
+        
+        this.nodeLabel = nodeLabel;
+        
+    }
+    
+    /**
+     * Return the acceptCountText.
+     */
+    public String getAcceptCountText() {
+        
+        return this.acceptCountText;
+        
+    }
+    
+    
+    /**
+     * Set the acceptCountText.
+     */
+    
+    public void setAcceptCountText(String acceptCountText) {
+        
+        this.acceptCountText = acceptCountText;
+        
+    }
+    
+    /**
+     * Return the algorithm.
+     */
+    public String getAlgorithm() {
+        
+        return this.algorithm;
+        
+    }
+    
+    
+    /**
+     * Set the algorithm.
+     */
+    
+    public void setAlgorithm(String algorithm) {
+        
+        this.algorithm = algorithm;
+        
+    }
+    
+    /**
+     * Return the ciphers.
+     */
+    public String getCiphers() {
+        
+        return this.ciphers;
+        
+    }
+    
+    /**
+     * Set the ciphers.
+     */
+    
+    public void setCiphers(String ciphers) {
+        
+        this.ciphers = ciphers;
+        
+    }
+    
+    /**
+     * Return the connLingerText.
+     */
+    public String getConnLingerText() {
+        
+        return this.connLingerText;
+        
+    }
+    
+    /**
+     * Set the connLingerText.
+     */
+    
+    public void setConnLingerText(String connLingerText) {
+        
+        this.connLingerText = connLingerText;
+        
+    }
+    
+    /**
+     * Return the connTimeOutText.
+     */
+    public String getConnTimeOutText() {
+        
+        return this.connTimeOutText;
+        
+    }
+    
+    /**
+     * Set the connTimeOutText.
+     */
+    
+    public void setConnTimeOutText(String connTimeOutText) {
+        
+        this.connTimeOutText = connTimeOutText;
+        
+    }
+       
+    /**
+     * Return the connUploadTimeOutText.
+     */
+    public String getConnUploadTimeOutText() {
+        
+        return this.connUploadTimeOutText;
+        
+    }
+    
+    /**
+     * Set the connUploadTimeOutText.
+     */
+    
+    public void setConnUploadTimeOutText(String connUploadTimeOutText) {
+        
+        this.connUploadTimeOutText = connUploadTimeOutText;
+        
+    }
+    /**
+     * Return the bufferSizeText.
+     */
+    public String getBufferSizeText() {
+        
+        return this.bufferSizeText;
+        
+    }
+    
+    /**
+     * Set the bufferSizeText.
+     */
+    
+    public void setBufferSizeText(String bufferSizeText) {
+        
+        this.bufferSizeText = bufferSizeText;
+        
+    }
+    
+    /**
+     * Return the address.
+     */
+    public String getAddress() {
+        
+        return this.address;
+        
+    }
+    
+    /**
+     * Set the address.
+     */
+    
+    public void setAddress(String address) {
+        
+        this.address = address;
+        
+    }
+    
+    
+    /**
+     * Return the proxy Name.
+     */
+    public String getProxyName() {
+        
+        return this.proxyName;
+        
+    }
+    
+    /**
+     * Set the proxy Name.
+     */
+    
+    public void setProxyName(String proxyName) {
+        
+        this.proxyName = proxyName;
+        
+    }
+    
+    /**
+     * Return the proxy Port NumberText.
+     */
+    public String getProxyPortText() {
+        
+        return this.proxyPortText;
+        
+    }
+    
+    /**
+     * Set the proxy Port NumberText.
+     */
+    
+    public void setProxyPortText(String proxyPortText) {
+        
+        this.proxyPortText = proxyPortText;
+        
+    }
+
+   /**
+     * Return the true/false value of client authentication.
+     */
+    public String getClientAuthentication() {
+
+        return this.clientAuthentication;
+
+    }
+
+
+    /**
+     * Set whether client authentication is supported or not.
+     */
+    public void setClientAuthentication(String clientAuthentication) {
+
+        this.clientAuthentication = clientAuthentication;
+
+    }
+
+    /**
+     * Return the object name of the service this connector belongs to.
+     */
+    public String getKeyStoreFileName() {
+
+        return this.keyStoreFileName;
+
+    }
+
+
+    /**
+     * Set the object name of the Service this connector belongs to.
+     */
+    public void setKeyStoreFileName(String keyStoreFileName) {
+
+        this.keyStoreFileName = keyStoreFileName;
+
+    }
+
+    /**
+     * Return the object name of the service this connector belongs to.
+     */
+    public String getKeyStorePassword() {
+
+        return this.keyStorePassword;
+
+    }
+
+
+    /**
+     * Set the object name of the Service this connector belongs to.
+     */
+    public void setKeyStorePassword(String keyStorePassword) {
+
+        this.keyStorePassword = keyStorePassword;
+
+    }
+
+    /**
+     * Return the keystore type.
+     */
+    public String getKeyStoreType() {
+
+        return this.keyStoreType;
+
+    }
+
+
+    /**
+     * Set the keystore type.
+     */
+    public void setKeyStoreType(String keyStoreType) {
+
+        this.keyStoreType = keyStoreType;
+
+    }
+    /**
+     * Return the sslProtocol
+     */
+    public String getSslProtocol() {
+
+        return this.sslProtocol;
+
+    }
+
+
+    /**
+     * Set the sslProtocol.
+     */
+    public void setSslProtocol(String sslProtocol) {
+
+        this.sslProtocol = sslProtocol;
+
+    }
+    
+    /**
+     * Return the Enable lookup Text.
+     */
+    
+    public String getEnableLookups() {
+        
+        return this.enableLookups;
+        
+    }
+    
+    /**
+     * Set the Enable Lookup Text.
+     */
+    public void setEnableLookups(String enableLookups) {
+        
+        this.enableLookups = enableLookups;
+        
+    }
+    
+    /**
+     * Return the disableUploadTimeout.
+     */
+    
+    public String getDisableUploadTimeout() {
+        
+        return this.disableUploadTimeout;
+        
+    }
+    
+    /**
+     * Set the disableUploadTimeout.
+     */
+    public void setDisableUploadTimeout(String disableUploadTimeout) {
+        
+        this.disableUploadTimeout = disableUploadTimeout;
+        
+    }
+    
+    /**
+     * Return the compression Text.
+     */
+    
+    public String getCompression() {
+        
+        return this.compression;
+        
+    }
+    
+    /**
+     * Set the Compression Text.
+     */
+    public void setCompression(String compression) {
+        
+        this.compression = compression;
+        
+    }
+    
+    /**
+     * Return the booleanVals.
+     */
+    public List getBooleanVals() {
+        
+        return this.booleanVals;
+        
+    }
+    
+    /**
+     * Set the debugVals.
+     */
+    public void setBooleanVals(List booleanVals) {
+        
+        this.booleanVals = booleanVals;
+        
+    }
+
+    /**
+     * Return the clientAuth values.
+     */
+    public List getClientAuthVals() {
+        return clientAuthVals;
+    }
+    /**
+     * Set the clientAuth vaues.
+     */
+    public void setClientAuthVals(List clientAuthVals) {
+        this.clientAuthVals = clientAuthVals;
+    }
+    
+    /**
+     * Return the min Processors Text.
+     */
+    public String getMinProcessorsText() {
+        
+        return this.minProcessorsText;
+        
+    }
+    
+    /**
+     * Set the minProcessors Text.
+     */
+    public void setMinProcessorsText(String minProcessorsText) {
+        
+        this.minProcessorsText = minProcessorsText;
+        
+    }
+    
+    /**
+     * Return the max processors Text.
+     */
+    public String getMaxProcessorsText() {
+        
+        return this.maxProcessorsText;
+        
+    }
+    
+    /**
+     * Set the Max Processors Text.
+     */
+    public void setMaxProcessorsText(String maxProcessorsText) {
+        
+        this.maxProcessorsText = maxProcessorsText;
+        
+    }
+    
+    /**
+     * Return the maxKeepAliveText.
+     */
+    public String getMaxKeepAliveText() {
+        
+        return this.maxKeepAliveText;
+        
+    }
+    
+    /**
+     * Set the maxKeepAliveText.
+     */
+    
+    public void setMaxKeepAliveText(String maxKeepAliveText) {
+        
+        this.maxKeepAliveText = maxKeepAliveText;
+        
+    }
+    
+    /**
+     * Return the maxSpare.
+     */
+    public String getMaxSpare() {
+        
+        return this.maxSpare;
+        
+    }
+    
+    /**
+     * Set the maxSpare.
+     */
+    
+    public void setMaxSpare(String maxSpare) {
+        
+        this.maxSpare = maxSpare;
+        
+    } 
+    
+    /**
+     * Return the maxThreads.
+     */
+    public String getMaxThreads() {
+        
+        return this.maxThreads;
+        
+    }
+    
+    /**
+     * Set the maxThreads.
+     */
+    
+    public void setMaxThreads(String maxThreads) {
+        
+        this.maxThreads = maxThreads;
+        
+    } 
+    
+    /**
+     * Return the minSpare.
+     */
+    public String getMinSpare() {
+        
+        return this.minSpare;
+        
+    }
+    
+    /**
+     * Set the minSpare.
+     */
+    
+    public void setMinSpare(String minSpare) {
+        
+        this.minSpare = minSpare;
+        
+    }
+
+    /**
+     * Return the threadPriority.
+     */
+    public String getThreadPriority() {
+
+      return this.threadPriority;
+
+    }
+
+    /**
+     * Set the threadPriority.
+     */
+    
+    public void setThreadPriority(String threadPriority) {
+      
+      this.threadPriority = threadPriority;
+    
+    }
+    
+    /**
+     * Return the URIEncoding text.
+     */
+    public String getURIEncodingText() {
+        
+        return this.uriEncodingText;
+        
+    }
+    
+    /**
+     * Set the URIEncoding Text.
+     */
+    public void setURIEncodingText(String uriEncodingText) {
+        
+        this.uriEncodingText = uriEncodingText;
+        
+    }
+    
+    /**
+     * Return the useBodyEncodingForURI Text.
+     */
+    public String getUseBodyEncodingForURIText() {
+        
+        return this.useBodyEncodingForURI;
+        
+    }
+    
+    /**
+     * Set the useBodyEncodingForURI Text.
+     */
+    public void setUseBodyEncodingForURIText(String useBodyEncodingForURI) {
+        
+        this.useBodyEncodingForURI = useBodyEncodingForURI;
+        
+    }    
+    
+    /**
+     * Return the allowTrace Text.
+     */
+    public String getAllowTraceText() {
+        
+        return this.allowTrace;
+        
+    }
+    
+    /**
+     * Set the allowTrace Text.
+     */
+    public void setAllowTraceText(String allowTrace) {
+        
+        this.allowTrace = allowTrace;
+        
+    }    
+    
+    /**
+     * Return the port text.
+     */
+    public String getPortText() {
+        
+        return this.portText;
+        
+    }
+    
+    /**
+     * Set the port Text.
+     */
+    public void setPortText(String portText) {
+        
+        this.portText = portText;
+        
+    }
+    
+    
+    /**
+     * Return the port.
+     */
+    public String getRedirectPortText() {
+        
+        return this.redirectPortText;
+        
+    }
+    
+    /**
+     * Set the Redirect Port Text.
+     */
+    public void setRedirectPortText(String redirectPortText) {
+        
+        this.redirectPortText = redirectPortText;
+        
+    }
+    
+    /**
+     * Return the Service Name.
+     */
+    public String getConnectorName() {
+        
+        return this.connectorName;
+        
+    }
+    
+    /**
+     * Set the Service Name.
+     */
+    public void setConnectorName(String connectorName) {
+        
+        this.connectorName = connectorName;
+        
+    }
+    
+    /**
+     * Return the connectorTypeVals.
+     */
+    public List getConnectorTypeVals() {
+        
+        return this.connectorTypeVals;
+        
+    }
+    
+    /**
+     * Set the connectorTypeVals.
+     */
+    public void setConnectorTypeVals(List connectorTypeVals) {
+        
+        this.connectorTypeVals = connectorTypeVals;
+        
+    }
+    
+     /**
+     * Return the secure Text.
+     */
+    public String getSecure() {
+        
+        return this.secure;
+        
+    }
+    
+    /**
+     * Set the secure Text.
+     */
+    public void setSecure(String secure) {
+        
+        this.secure = secure;
+        
+    }    
+    
+    /**
+     * Return the tcpNoDelay Text.
+     */
+    public String getTcpNoDelay() {
+        
+        return this.tcpNoDelay;
+        
+    }
+    
+    /**
+     * Set the tcpNoDelay Text.
+     */
+    public void setTcpNoDelay(String tcpNoDelay) {
+        
+        this.tcpNoDelay = tcpNoDelay;
+        
+    }   
+    
+    /**
+     * Return the xpoweredBy Text.
+     */
+    public String getXpoweredBy() {
+        
+        return this.xpoweredBy;
+        
+    }
+    
+    /**
+     * Set the xpoweredBy Text.
+     */
+    public void setXpoweredBy(String xpoweredBy) {
+        
+        this.xpoweredBy = xpoweredBy;
+        
+    }
+    
+    // --------------------------------------------------------- Public Methods
+    
+    /**
+     * Reset all properties to their default values.
+     *
+     * @param mapping The mapping used to select this instance
+     * @param request The servlet request we are processing
+     */
+    public void reset(ActionMapping mapping, HttpServletRequest request) {
+    
+        this.objectName = null;
+        this.connectorType = null;
+        this.portText = null;
+        this.acceptCountText = null;
+        this.connLingerText = null;
+        this.connTimeOutText = null;
+        this.connUploadTimeOutText = null;
+        this.bufferSizeText = null;
+        this.address = null;
+        this.enableLookups = "false";
+        this.compression = "off";
+        this.minProcessorsText = null;
+        this.maxProcessorsText = null;
+        this.maxKeepAliveText = null;
+        this.maxSpare = null;
+        this.maxThreads = null;
+        this.minSpare = null;
+        this.threadPriority = null;
+        this.uriEncodingText = null;
+        this.useBodyEncodingForURI = "false";
+        this.allowTrace = "false";
+        this.portText = null;
+        this.redirectPortText = null;
+        this.proxyName = null;
+        this.proxyPortText = null;
+        this.keyStoreFileName = null;
+        this.keyStorePassword = null;        
+        this.clientAuthentication = "false";
+        this.secure = "false";
+        this.tcpNoDelay = "false";
+        this.xpoweredBy = "false";
+        
+    }
+    
+    /**
+     * Validate the properties that have been set from this HTTP request,
+     * and return an <code>ActionErrors</code> object that encapsulates any
+     * validation errors that have been found.  If no errors are found, return
+     * <code>null</code> or an <code>ActionErrors</code> object with no
+     * recorded error messages.
+     *
+     * @param mapping The mapping used to select this instance
+     * @param request The servlet request we are processing
+     */
+    
+    private ActionErrors errors;
+    
+    public ActionErrors validate(ActionMapping mapping,
+    HttpServletRequest request) {
+    
+        errors = new ActionErrors();
+        
+        String submit = request.getParameter("submit");
+        // front end validation when save is clicked.
+        //if (submit != null) {
+  
+            /* The IP address can also be null -- which means open the
+             server socket on *all* IP addresses for this host */
+            if ((address.length() > 0) && !address.equalsIgnoreCase(" ")) {
+                try {
+                    InetAddress.getByName(address);
+                } catch (Exception e) {
+                    errors.add("address", new ActionError("error.address.invalid"));
+                }
+            } else {
+                address = " ";
+            }
+            
+            /* ports */
+            numberCheck("portNumber",  portText, true, 1, 65535);
+            numberCheck("redirectPortText",  redirectPortText, true, -1, 65535);
+            
+            /* processors*/
+            //numberCheck("minProcessorsText",  minProcessorsText, true, 1, 512);
+            //try {
+                // if min is a valid integer, then check that max >= min
+                //int min = Integer.parseInt(minProcessorsText);
+                //numberCheck("maxProcessorsText",  maxProcessorsText, true, min, 512);
+            //} catch (Exception e) {
+                // check for the complete range
+                //numberCheck("maxProcessorsText",  maxProcessorsText, true, 1, 512);
+            //}
+            
+            // proxy                  
+            if ((proxyName!= null) && (proxyName.length() > 0)) {
+                try {
+                    InetAddress.getByName(proxyName);
+                } catch (Exception e) {
+                    errors.add("proxyName", new ActionError("error.proxyName.invalid"));
+                }
+            }   
+            
+            // supported only by Coyote HTTP and HTTPS connectors
+            if (!("AJP".equalsIgnoreCase(connectorType))) {
+                numberCheck("acceptCountText", acceptCountText, true, 0, 128);
+                //numberCheck("connTimeOutText", connTimeOutText, true, -1, 60000);
+                numberCheck("bufferSizeText", bufferSizeText, true, 1, 8192);
+                numberCheck("proxyPortText",  proxyPortText, true, 0, 65535);  
+            }
+        //}
+        
+        return errors;
+    }
+    
+    /*
+     * Helper method to check that it is a required number and
+     * is a valid integer within the given range. (min, max).
+     *
+     * @param  field  The field name in the form for which this error occured.
+     * @param  numText  The string representation of the number.
+     * @param rangeCheck  Boolean value set to true of reange check should be performed.
+     *
+     * @param  min  The lower limit of the range
+     * @param  max  The upper limit of the range
+     *
+     */
+    
+    public void numberCheck(String field, String numText, boolean rangeCheck,
+    int min, int max) {
+        
+        /* Check for 'is required' */
+        if ((numText == null) || (numText.length() < 1)) {
+            errors.add(field, new ActionError("error."+field+".required"));
+        } else {
+            
+        /*check for 'must be a number' in the 'valid range'*/
+            try {
+                int num = Integer.parseInt(numText);
+                // perform range check only if required
+                if (rangeCheck) {
+                    if ((num < min) || (num > max ))
+                        errors.add( field,
+                        new ActionError("error."+ field +".range"));
+                }
+            } catch (NumberFormatException e) {
+                errors.add(field,
+                new ActionError("error."+ field + ".format"));
+            }
+        }
+    }
+    
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/connector/ConnectorsForm.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/connector/ConnectorsForm.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/connector/ConnectorsForm.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.admin.connector;
+
+import javax.servlet.http.HttpServletRequest;
+import org.apache.struts.action.ActionForm;
+import org.apache.struts.action.ActionMapping;
+
+
+/**
+ * Form bean for deleting connectors.
+ *
+ * @author Manveen Kaur
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class ConnectorsForm extends ActionForm {
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * The object names of the connectors to be deleted.
+     */
+    private String connectors[] = new String[0];
+
+    public String[] getConnectors() {
+        return (this.connectors);
+    }
+
+    public void setConnectors(String connectors[]) {
+        this.connectors = connectors;
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Reset all properties to their default values.
+     *
+     * @param mapping The mapping used to select this instance
+     * @param request The servlet request we are processing
+     */
+    public void reset(ActionMapping mapping, HttpServletRequest request) {
+
+        this.connectors = new String[0];
+
+    }
+        
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/connector/DeleteConnectorAction.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/connector/DeleteConnectorAction.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/connector/DeleteConnectorAction.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,149 @@
+/*
+ * Copyright 2001-2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.admin.connector;
+
+import java.io.IOException;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Locale;
+import java.util.TreeSet;
+import java.util.Set;
+import java.util.ArrayList;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+import org.apache.struts.action.Action;
+import org.apache.struts.action.ActionErrors;
+import org.apache.struts.action.ActionForm;
+import org.apache.struts.action.ActionForward;
+import org.apache.struts.action.ActionMapping;
+
+import javax.management.MBeanServer;
+import javax.management.MBeanServerFactory;
+import javax.management.QueryExp;
+import javax.management.Query;
+import javax.management.ObjectInstance;
+import javax.management.ObjectName;
+import javax.management.JMException;
+import org.apache.struts.util.MessageResources;
+
+import org.apache.webapp.admin.ApplicationServlet;
+import org.apache.webapp.admin.TomcatTreeBuilder;
+
+/**
+ * The <code>Action</code> that sets up <em>Delete Connectors</em> transactions.
+ *
+ * @author Manveen Kaur
+ * @version $Revision: 303390 $ $Date: 2004-10-18 01:37:56 -0500 (Mon, 18 Oct 2004) $
+ */
+
+public class DeleteConnectorAction extends Action {
+        
+    /**
+     * The MBeanServer we will be interacting with.
+     */
+    private MBeanServer mBServer = null;
+    
+    
+    
+    
+    
+    // --------------------------------------------------------- Public Methods
+    
+    /**
+     * Process the specified HTTP request, and create the corresponding HTTP
+     * response (or forward to another web component that will create it).
+     * Return an <code>ActionForward</code> instance describing where and how
+     * control should be forwarded, or <code>null</code> if the response has
+     * already been completed.
+     *
+     * @param mapping The ActionMapping used to select this instance
+     * @param actionForm The optional ActionForm bean for this request (if any)
+     * @param request The HTTP request we are processing
+     * @param response The HTTP response we are creating
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception ServletException if a servlet exception occurs
+     */
+    public ActionForward execute(ActionMapping mapping,
+    ActionForm form,
+    HttpServletRequest request,
+    HttpServletResponse response)
+    throws IOException, ServletException {
+        
+        
+        // Acquire the resources that we need
+        HttpSession session = request.getSession();
+        Locale locale = getLocale(request);
+        MessageResources resources = getResources(request);    
+        
+        // Acquire a reference to the MBeanServer containing our MBeans
+        try {
+            mBServer = ((ApplicationServlet) getServlet()).getServer();
+        } catch (Throwable t) {
+            throw new ServletException
+            ("Cannot acquire MBeanServer reference", t);
+        }
+        
+        String domain = null;
+        // Set up a form bean containing the currently selected
+        // objects to be deleted
+        ConnectorsForm connectorsForm = new ConnectorsForm();
+        String select = request.getParameter("select");
+        if (select != null) {
+            String connectors[] = new String[1];
+            connectors[0] = select;
+            connectorsForm.setConnectors(connectors);
+                        
+            // get the service Name this selected host belongs to
+            try {
+                domain = (new ObjectName(select)).getDomain();
+            } catch (Exception e) {
+                throw new ServletException
+                ("Error extracting service name from the connector to be deleted", e);
+            }        
+        }
+        request.setAttribute("connectorsForm", connectorsForm);
+        
+        // Accumulate a list of all available connectors
+        ArrayList list = new ArrayList();
+         try {
+            String pattern = domain + TomcatTreeBuilder.CONNECTOR_TYPE +
+                TomcatTreeBuilder.WILDCARD;          
+            Iterator items =
+                mBServer.queryNames(new ObjectName(pattern), null).iterator();
+            while (items.hasNext()) {
+                Object item = items.next();
+                list.add(item.toString());
+            }
+        } catch (Exception e) {
+            getServlet().log
+                (resources.getMessage(locale, "users.error.select"));
+            response.sendError
+                (HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
+                 resources.getMessage(locale, "users.error.select"));
+            return (null);
+        }      
+        Collections.sort(list);
+        request.setAttribute("connectorsList", list);
+        
+        // Forward to the list display page
+        return (mapping.findForward("Connectors"));        
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/connector/DeleteConnectorsAction.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/connector/DeleteConnectorsAction.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/connector/DeleteConnectorsAction.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,165 @@
+/*
+ * Copyright 2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.admin.connector;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.Locale;
+import java.util.Set;
+import java.util.TreeSet;
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+import javax.management.ObjectInstance;
+import javax.management.modelmbean.ModelMBean;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpSession;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import org.apache.struts.action.Action;
+import org.apache.struts.action.ActionForm;
+import org.apache.struts.action.ActionForward;
+import org.apache.struts.action.ActionMapping;
+import org.apache.struts.util.MessageResources;
+
+import org.apache.webapp.admin.ApplicationServlet;
+import org.apache.webapp.admin.TomcatTreeBuilder;
+import org.apache.webapp.admin.TreeControl;
+import org.apache.webapp.admin.TreeControlNode;
+
+
+/**
+ * The <code>Action</code> that completes <em>Delete Connectors</em>
+ * transactions.
+ *
+ * @author Manveen Kaur
+ * @version $Revision: 303390 $ $Date: 2004-10-18 01:37:56 -0500 (Mon, 18 Oct 2004) $
+ */
+
+public class DeleteConnectorsAction extends Action {
+
+
+    /**
+     * Signature for the <code>removeConnector</code> operation.
+     */
+    private String removeConnectorTypes[] =
+    { "java.lang.String",      // Object name
+    };
+
+
+    /**
+     * The MBeanServer we will be interacting with.
+     */
+    private MBeanServer mBServer = null;
+    
+
+
+    // --------------------------------------------------------- Public Methods
+    
+    
+    /**
+     * Process the specified HTTP request, and create the corresponding HTTP
+     * response (or forward to another web component that will create it).
+     * Return an <code>ActionForward</code> instance describing where and how
+     * control should be forwarded, or <code>null</code> if the response has
+     * already been completed.
+     *
+     * @param mapping The ActionMapping used to select this instance
+     * @param actionForm The optional ActionForm bean for this request (if any)
+     * @param request The HTTP request we are processing
+     * @param response The HTTP response we are creating
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception ServletException if a servlet exception occurs
+     */
+    public ActionForward execute(ActionMapping mapping,
+                                 ActionForm form,
+                                 HttpServletRequest request,
+                                 HttpServletResponse response)
+        throws IOException, ServletException {
+        
+        
+        // Look up the components we will be using as needed
+        HttpSession session = request.getSession();
+        Locale locale = getLocale(request);
+        MessageResources resources = getResources(request);
+
+        // Acquire a reference to the MBeanServer containing our MBeans
+        try {
+            mBServer = ((ApplicationServlet) getServlet()).getServer();
+        } catch (Throwable t) {
+            throw new ServletException
+            ("Cannot acquire MBeanServer reference", t);
+        }
+        
+        // Delete the specified Connectors
+        String connectors[]  = ((ConnectorsForm) form).getConnectors();
+        String values[] = new String[1];
+        String operation = "removeConnector";
+        try {
+
+            // Look up our tree control data structure
+            TreeControl control = (TreeControl)
+                session.getAttribute("treeControlTest");
+                
+            // Look up our MBeanFactory MBean
+            ObjectName fname = null;
+            String domain = null;
+            TreeControlNode node = null;
+
+            // Remove the specified connectors
+            for (int i = 0; i < connectors.length; i++) {
+                values[0] = connectors[i];
+                if (control != null) {
+                    control.selectNode(null);
+                    node = control.findNode(connectors[i]);
+                    domain = node.getDomain();
+                    // Look up our MBeanFactory MBean
+                    fname = TomcatTreeBuilder.getMBeanFactory();
+                    mBServer.invoke(fname, operation,
+                                values, removeConnectorTypes);
+                    if (node != null) {
+                        node.remove();
+                    } else {
+                        getServlet().log("Missing TreeControlNode for " +
+                                         connectors[i]);
+                    }
+                } else {
+                    getServlet().log("Missing TreeControl attribute");
+                }
+            }
+
+        } catch (Exception e) {
+
+            getServlet().log
+                (resources.getMessage(locale, "users.error.invoke",
+                                      operation), e);
+            response.sendError
+                (HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
+                 resources.getMessage(locale, "users.error.invoke",
+                                      operation));
+            return (null);
+
+        }
+
+        // Report successful completion of this transaction
+        return (mapping.findForward("Save Successful"));
+
+    }
+    
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/connector/EditConnectorAction.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/connector/EditConnectorAction.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/connector/EditConnectorAction.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,277 @@
+/*
+ * Copyright 2001-2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.admin.connector;
+
+import java.io.IOException;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Locale;
+import java.util.ArrayList;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+import org.apache.struts.action.Action;
+import org.apache.struts.action.ActionErrors;
+import org.apache.struts.action.ActionForm;
+import org.apache.struts.action.ActionForward;
+import org.apache.struts.action.ActionMapping;
+import org.apache.struts.util.MessageResources;
+
+import javax.management.MBeanServer;
+import javax.management.ObjectInstance;
+import javax.management.ObjectName;
+import javax.management.JMException;
+
+import org.apache.webapp.admin.ApplicationServlet;
+import org.apache.webapp.admin.LabelValueBean;
+import org.apache.webapp.admin.Lists;
+import org.apache.webapp.admin.TomcatTreeBuilder;
+import java.net.InetAddress;
+/**
+ * The <code>Action</code> that sets up <em>Edit Connector</em> transactions.
+ *
+ * @author Manveen Kaur
+ * @version $Revision: 394493 $ $Date: 2006-04-16 09:27:59 -0500 (Sun, 16 Apr 2006) $
+ */
+
+public class EditConnectorAction extends Action {
+    
+
+    /**
+     * The MBeanServer we will be interacting with.
+     */
+    private MBeanServer mBServer = null;
+    
+
+    // --------------------------------------------------------- Public Methods
+    
+    /**
+     * Process the specified HTTP request, and create the corresponding HTTP
+     * response (or forward to another web component that will create it).
+     * Return an <code>ActionForward</code> instance describing where and how
+     * control should be forwarded, or <code>null</code> if the response has
+     * already been completed.
+     *
+     * @param mapping The ActionMapping used to select this instance
+     * @param actionForm The optional ActionForm bean for this request (if any)
+     * @param request The HTTP request we are processing
+     * @param response The HTTP response we are creating
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception ServletException if a servlet exception occurs
+     */
+    public ActionForward execute(ActionMapping mapping,
+                                 ActionForm form,
+                                 HttpServletRequest request,
+                                 HttpServletResponse response)
+        throws IOException, ServletException {
+        
+        // Acquire the resources that we need
+        HttpSession session = request.getSession();
+        Locale locale = getLocale(request);
+        MessageResources resources = getResources(request);
+        
+        // Acquire a reference to the MBeanServer containing our MBeans
+        try {
+            mBServer = ((ApplicationServlet) getServlet()).getServer();
+        } catch (Throwable t) {
+            throw new ServletException
+            ("Cannot acquire MBeanServer reference", t);
+        }
+        
+        // Set up the object names of the MBeans we are manipulating
+        ObjectName cname = null;
+        StringBuffer sb = null;
+        try {
+            cname = new ObjectName(request.getParameter("select"));
+        } catch (Exception e) {
+            String message =
+                resources.getMessage(locale, "error.connectorName.bad",
+                                     request.getParameter("select"));
+            getServlet().log(message);
+            response.sendError(HttpServletResponse.SC_BAD_REQUEST, message);
+            return (null);
+        }
+
+        // Fill in the form values for display and editing
+        ConnectorForm connectorFm = new ConnectorForm();
+        session.setAttribute("connectorForm", connectorFm);
+        connectorFm.setAdminAction("Edit");
+        connectorFm.setObjectName(cname.toString());
+        sb = new StringBuffer();
+        sb.append(resources.getMessage(locale, "server.service.treeBuilder.connector"));
+        sb.append(" (");
+        sb.append(cname.getKeyProperty("port"));
+        sb.append(")");
+        connectorFm.setNodeLabel(sb.toString());
+        connectorFm.setBooleanVals(Lists.getBooleanValues());        
+        connectorFm.setClientAuthVals(Lists.getClientAuthValues());
+        
+        String attribute = null;
+        try {
+
+            // Copy scalar properties
+            // General properties
+            attribute = "scheme";
+            String scheme = (String) mBServer.getAttribute(cname, attribute);
+            connectorFm.setScheme(scheme);
+
+            attribute = "protocolHandlerClassName";
+            String handlerClassName = 
+                (String) mBServer.getAttribute(cname, attribute);
+            int period = handlerClassName.lastIndexOf('.');
+            String connType = handlerClassName.substring(period + 1);
+            String connectorType = "HTTPS";
+            if ("JkCoyoteHandler".equalsIgnoreCase(connType)) {
+                connectorType = "AJP";
+            } else if ("Http11Protocol".equalsIgnoreCase(connType) && 
+                      ("http".equalsIgnoreCase(scheme))) {
+                connectorType = "HTTP";
+            }             
+            connectorFm.setConnectorType(connectorType);            
+            
+            attribute = "acceptCount";
+            connectorFm.setAcceptCountText
+                (String.valueOf(mBServer.getAttribute(cname, attribute)));          
+            attribute = "compression";
+            connectorFm.setCompression
+                ((String) mBServer.getAttribute(cname, attribute));          
+            attribute = "connectionLinger";
+            connectorFm.setConnLingerText
+                (String.valueOf(mBServer.getAttribute(cname, attribute)));            
+            attribute = "connectionTimeout";
+            connectorFm.setConnTimeOutText
+                (String.valueOf(mBServer.getAttribute(cname, attribute)));             
+            attribute = "connectionUploadTimeout";
+            connectorFm.setConnUploadTimeOutText
+                (String.valueOf(mBServer.getAttribute(cname, attribute)));              
+            attribute = "disableUploadTimeout";
+            connectorFm.setDisableUploadTimeout
+                (String.valueOf(mBServer.getAttribute(cname, attribute)));       
+            attribute = "bufferSize";
+            connectorFm.setBufferSizeText
+                (String.valueOf(mBServer.getAttribute(cname, attribute)));            
+            attribute = "enableLookups";
+            connectorFm.setEnableLookups
+                (String.valueOf(mBServer.getAttribute(cname, attribute)));            
+            attribute = "address";
+            Object addressObject = mBServer.getAttribute(cname, attribute);
+            String addressStr = "";
+            if (addressObject instanceof InetAddress){
+	        addressStr = ((InetAddress)addressObject).getHostAddress();
+            } else if (addressObject instanceof String) {
+                addressStr = (String) addressObject;
+            }
+            connectorFm.setAddress(addressStr);
+            attribute = "maxKeepAliveRequests";
+            connectorFm.setMaxKeepAliveText
+                (String.valueOf(mBServer.getAttribute(cname, attribute)));       
+            attribute = "maxSpareThreads";
+            connectorFm.setMaxSpare
+                (String.valueOf(mBServer.getAttribute(cname, attribute)));         
+            attribute = "maxThreads";
+            connectorFm.setMaxThreads
+                (String.valueOf(mBServer.getAttribute(cname, attribute)));       
+            attribute = "minSpareThreads";
+            connectorFm.setMinSpare
+                (String.valueOf(mBServer.getAttribute(cname, attribute)));        
+            attribute = "threadPriority";
+            connectorFm.setThreadPriority
+                (String.valueOf(mBServer.getAttribute(cname, attribute)));
+            attribute = "secure";
+            connectorFm.setSecure
+                (((Boolean) mBServer.getAttribute(cname, attribute)).toString());
+            attribute = "tcpNoDelay";
+            connectorFm.setTcpNoDelay
+                (String.valueOf(mBServer.getAttribute(cname, attribute)));
+            attribute = "xpoweredBy";
+            connectorFm.setXpoweredBy
+                (((Boolean) mBServer.getAttribute(cname, attribute)).toString());
+            attribute = "URIEncoding";
+            connectorFm.setURIEncodingText
+                ((String) mBServer.getAttribute(cname, attribute));
+            attribute = "useBodyEncodingForURI";
+            connectorFm.setUseBodyEncodingForURIText
+                (((Boolean) mBServer.getAttribute(cname, attribute)).toString());
+            attribute = "allowTrace";
+            connectorFm.setAllowTraceText
+                (((Boolean) mBServer.getAttribute(cname, attribute)).toString());
+          
+            // Ports
+            attribute = "port";
+            connectorFm.setPortText
+                (((Integer) mBServer.getAttribute(cname, attribute)).toString());            
+            attribute = "redirectPort";
+            connectorFm.setRedirectPortText
+                (((Integer) mBServer.getAttribute(cname, attribute)).toString());            
+            
+            // Supported by HTTP and HTTPS only
+            if (!("AJP".equalsIgnoreCase(connectorType))) {
+                attribute = "proxyName";
+                connectorFm.setProxyName
+                    ((String) mBServer.getAttribute(cname, attribute));
+                attribute = "proxyPort";
+                connectorFm.setProxyPortText
+                    (((Integer) mBServer.getAttribute(cname, attribute)).toString());            
+            }
+            
+            if ("HTTPS".equalsIgnoreCase(connectorType)) {
+                // Initialize rest of variables. 
+                // These are set only for SSL connectors.
+                attribute = "algorithm";
+                connectorFm.setAlgorithm
+                    ((String) mBServer.getAttribute(cname, attribute));
+                attribute = "clientAuth";
+                connectorFm.setClientAuthentication
+                    (((String) mBServer.getAttribute(cname, attribute)));
+                attribute = "ciphers";
+                connectorFm.setCiphers
+                    ((String) mBServer.getAttribute(cname, attribute));   
+                attribute = "keystoreFile";
+                connectorFm.setKeyStoreFileName
+                    ((String) mBServer.getAttribute(cname, attribute));
+                attribute = "keystorePass";
+                connectorFm.setKeyStorePassword
+                    ((String) mBServer.getAttribute(cname, attribute));     
+                attribute = "keystoreType";
+                connectorFm.setKeyStoreType
+                    ((String) mBServer.getAttribute(cname, attribute));   
+                attribute = "sslProtocol";
+                connectorFm.setSslProtocol
+                    ((String) mBServer.getAttribute(cname, attribute));          
+            }     
+                
+                        
+        } catch (Throwable t) {
+            getServlet().log
+                (resources.getMessage(locale, "users.error.attribute.get",
+                                      attribute), t);
+            response.sendError
+                (HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
+                 resources.getMessage(locale, "users.error.attribute.get",
+                                      attribute));
+            return (null);
+        }
+        
+        // Forward to the connector display page
+        return (mapping.findForward("Connector"));
+        
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/connector/SaveConnectorAction.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/connector/SaveConnectorAction.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/connector/SaveConnectorAction.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,476 @@
+/*
+ * Copyright 2001-2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.admin.connector;
+
+import java.net.URLEncoder;
+import java.util.Iterator;
+import java.util.Locale;
+import java.io.IOException;
+import javax.management.Attribute;
+import javax.management.MBeanServer;
+import javax.management.MBeanServerFactory;
+import javax.management.QueryExp;
+import javax.management.Query;
+import javax.management.ObjectInstance;
+import javax.management.ObjectName;
+import javax.management.JMException;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+import org.apache.struts.action.Action;
+import org.apache.struts.action.ActionError;
+import org.apache.struts.action.ActionErrors;
+import org.apache.struts.action.ActionForm;
+import org.apache.struts.action.ActionForward;
+import org.apache.struts.action.ActionMapping;
+import org.apache.struts.util.MessageResources;
+import org.apache.webapp.admin.ApplicationServlet;
+import org.apache.webapp.admin.TomcatTreeBuilder;
+import org.apache.webapp.admin.TreeControl;
+import org.apache.webapp.admin.TreeControlNode;
+
+
+/**
+ * The <code>Action</code> that completes <em>Add Connector</em> and
+ * <em>Edit Connector</em> transactions.
+ *
+ * @author Manveen Kaur
+ * @version $Revision: 303390 $ $Date: 2004-10-18 01:37:56 -0500 (Mon, 18 Oct 2004) $
+ */
+
+public final class SaveConnectorAction extends Action {
+
+
+    // ----------------------------------------------------- Instance Variables
+
+    /**
+     * Signature for the <code>createStandardConnector</code> operation.
+     */
+    private String createStandardConnectorTypes[] =
+    { "java.lang.String",    // parent
+      "java.lang.String",    // address
+      "int"                  // port      
+    };
+
+    /**
+     * The MBeanServer we will be interacting with.
+     */
+    private MBeanServer mBServer = null;
+    
+    // --------------------------------------------------------- Public Methods
+    
+    
+    /**
+     * Process the specified HTTP request, and create the corresponding HTTP
+     * response (or forward to another web component that will create it).
+     * Return an <code>ActionForward</code> instance describing where and how
+     * control should be forwarded, or <code>null</code> if the response has
+     * already been completed.
+     *
+     * @param mapping The ActionMapping used to select this instance
+     * @param actionForm The optional ActionForm bean for this request (if any)
+     * @param request The HTTP request we are processing
+     * @param response The HTTP response we are creating
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception ServletException if a servlet exception occurs
+     */
+    public ActionForward execute(ActionMapping mapping,
+                                 ActionForm form,
+                                 HttpServletRequest request,
+                                 HttpServletResponse response)
+        throws IOException, ServletException {
+        
+        // Acquire the resources that we need
+        HttpSession session = request.getSession();
+        Locale locale = getLocale(request);
+        MessageResources resources = getResources(request);
+        
+        // Acquire a reference to the MBeanServer containing our MBeans
+        try {
+            mBServer = ((ApplicationServlet) getServlet()).getServer();
+        } catch (Throwable t) {
+            throw new ServletException
+            ("Cannot acquire MBeanServer reference", t);
+        }    
+        
+        // Identify the requested action
+        ConnectorForm cform = (ConnectorForm) form;
+        String adminAction = cform.getAdminAction();
+        String cObjectName = cform.getObjectName();
+        String connectorType = cform.getConnectorType();
+        ObjectName coname = null;
+
+        // Perform a "Create Connector" transaction (if requested)
+        if ("Create".equals(adminAction)) {
+
+            String operation = null;
+            Object values[] = null;
+
+            try {
+                // get service name which is same as domain
+                String serviceName = cform.getServiceName();
+                ObjectName soname = new ObjectName(serviceName);
+                String domain = soname.getDomain();
+                StringBuffer sb = new StringBuffer(domain);
+                StringBuffer searchSB = new StringBuffer("*");
+                sb.append(TomcatTreeBuilder.CONNECTOR_TYPE);
+                searchSB.append(TomcatTreeBuilder.CONNECTOR_TYPE);
+                sb.append(",port=" + cform.getPortText());
+                searchSB.append(",port=" + cform.getPortText());
+                
+                ObjectName search = new ObjectName(searchSB.toString()+",*");
+                
+                String address = cform.getAddress();
+                if ((address!=null) && (address.length()>0) && 
+                        (!address.equalsIgnoreCase(" "))) {
+                    sb.append(",address=" + address);
+                } else {
+                    address = null;
+                }
+                ObjectName oname = new ObjectName(sb.toString());
+                                                
+                // Ensure that the requested connector name and port is unique
+                if (mBServer.isRegistered(oname) ||
+                    (!mBServer.queryNames(search, null).isEmpty())) {
+                    ActionErrors errors = new ActionErrors();
+                    errors.add("connectorName",
+                               new ActionError("error.connectorName.exists"));
+                    saveErrors(request, errors);
+                    return (new ActionForward(mapping.getInput()));
+                }
+
+                // Look up our MBeanFactory MBean
+                ObjectName fname = TomcatTreeBuilder.getMBeanFactory();
+
+                // Create a new Connector object
+                values = new Object[3];                
+                values[0] = serviceName;  //service parent object name
+                values[1] = address;
+                values[2] = new Integer(cform.getPortText());
+
+                if ("HTTP".equalsIgnoreCase(connectorType)) {
+                        operation = "createHttpConnector"; // HTTP
+                } else if ("HTTPS".equalsIgnoreCase(connectorType)) { 
+                        operation = "createHttpsConnector";   // HTTPS
+                } else {
+                        operation = "createAjpConnector";   // AJP(HTTP)                  
+                }
+                
+                cObjectName = (String)
+                    mBServer.invoke(fname, operation,
+                                    values, createStandardConnectorTypes);
+                
+                // Add the new Connector to our tree control node
+                TreeControl control = (TreeControl)
+                    session.getAttribute("treeControlTest");
+                if (control != null) {
+                    String parentName = serviceName;
+                    TreeControlNode parentNode = control.findNode(parentName);
+                    if (parentNode != null) {
+                        String nodeLabel = resources.getMessage(locale, 
+                            "server.service.treeBuilder.connector") + " (" + 
+                            cform.getPortText() + ")";
+                        String encodedName =
+                            URLEncoder.encode(cObjectName,TomcatTreeBuilder.URL_ENCODING);
+                        TreeControlNode childNode =
+                            new TreeControlNode(cObjectName,
+                                                "Connector.gif",
+                                                nodeLabel,
+                                                "EditConnector.do?select=" +
+                                                encodedName,
+                                                "content",
+                                                true, domain);
+                        // FIXME--the node should be next to the rest of 
+                        // the Connector nodes..
+                        parentNode.addChild(childNode);
+                        // FIXME - force a redisplay
+                    } else {
+                        getServlet().log
+                            ("Cannot find parent node '" + parentName + "'");
+                    }
+                } else {
+                    getServlet().log
+                        ("Cannot find TreeControlNode!");
+                }
+
+            } catch (Exception e) {
+
+                getServlet().log
+                    (resources.getMessage(locale, "users.error.invoke",
+                                          operation), e);
+                response.sendError
+                    (HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
+                     resources.getMessage(locale, "users.error.invoke",
+                                          operation));
+                return (null);
+
+            }
+
+        }
+
+        // Perform attribute updates as requested
+        String attribute = null;
+        try {
+
+            coname = new ObjectName(cObjectName);
+
+            attribute = "acceptCount";
+            int acceptCount = 60000;
+            try {
+                acceptCount = Integer.parseInt(cform.getAcceptCountText());
+            } catch (Throwable t) {
+                acceptCount = 60000;
+            }
+            mBServer.setAttribute(coname,
+                                  new Attribute("acceptCount", new Integer(acceptCount)));    
+            attribute = "compression";  
+            String compression = cform.getCompression();
+            if ((compression != null) && (compression.length()>0)) { 
+                mBServer.setAttribute(coname,
+                                      new Attribute("compression", compression));
+            }        
+            attribute = "connectionLinger";
+            int connectionLinger = -1;
+            try {
+                connectionLinger = Integer.parseInt(cform.getConnLingerText());
+            } catch (Throwable t) {
+                connectionLinger = 0;
+            }
+            mBServer.setAttribute(coname,
+                                  new Attribute("connectionLinger", new Integer(connectionLinger))); 
+            attribute = "connectionTimeout";
+            int connectionTimeout = 0;
+            try {
+                connectionTimeout = Integer.parseInt(cform.getConnTimeOutText());
+            } catch (Throwable t) {
+                connectionTimeout = 0;
+            }
+            mBServer.setAttribute(coname,
+                                  new Attribute("connectionTimeout", new Integer(connectionTimeout)));            
+            attribute = "connectionUploadTimeout";
+            int connectionUploadTimeout = 0;
+            try {
+                connectionUploadTimeout = Integer.parseInt(cform.getConnUploadTimeOutText());
+            } catch (Throwable t) {
+                connectionUploadTimeout = 0;
+            }
+            mBServer.setAttribute(coname,
+                                  new Attribute("connectionUploadTimeout", new Integer(connectionUploadTimeout)));        
+            attribute = "bufferSize";
+            int bufferSize = 2048;
+            try {
+                bufferSize = Integer.parseInt(cform.getBufferSizeText());
+            } catch (Throwable t) {
+                bufferSize = 2048;
+            }
+            mBServer.setAttribute(coname,
+                                  new Attribute("bufferSize", new Integer(bufferSize)));    
+            attribute = "disableUploadTimeout";
+            mBServer.setAttribute(coname,
+                                  new Attribute("disableUploadTimeout", new Boolean(cform.getDisableUploadTimeout())));                        
+            attribute = "enableLookups";
+            mBServer.setAttribute(coname,
+                                  new Attribute("enableLookups", new Boolean(cform.getEnableLookups())));                        
+
+            attribute = "redirectPort";
+            int redirectPort = 0;
+            try {
+                redirectPort = Integer.parseInt(cform.getRedirectPortText());
+            } catch (Throwable t) {
+                redirectPort = 0;
+            }
+            mBServer.setAttribute(coname,
+                                  new Attribute("redirectPort", new Integer(redirectPort))); 
+            attribute = "minProcessors";
+            int minProcessors = 5;
+            try {
+                minProcessors = Integer.parseInt(cform.getMinProcessorsText());
+            } catch (Throwable t) {
+                minProcessors = 5;
+            }
+            //mBServer.setAttribute(coname,
+            //                      new Attribute("minProcessors", new Integer(minProcessors))); 
+            attribute = "maxProcessors";
+            int maxProcessors = 20;
+            try {
+                maxProcessors = Integer.parseInt(cform.getMaxProcessorsText());
+            } catch (Throwable t) {
+                maxProcessors = 20;
+            }
+            //mBServer.setAttribute(coname,
+            //                      new Attribute("maxProcessors", new Integer(maxProcessors))); 
+       
+            attribute = "maxKeepAliveRequests";
+            int maxKeepAliveRequests = 100;
+            try {
+                maxKeepAliveRequests = Integer.parseInt(cform.getMaxKeepAliveText());
+            } catch (Throwable t) {
+                maxKeepAliveRequests = 100;
+            }
+            mBServer.setAttribute(coname,
+                                  new Attribute("maxKeepAliveRequests", new Integer(maxKeepAliveRequests))); 
+            attribute = "maxSpareThreads";
+            int maxSpare = 50;
+            try {
+                maxSpare = Integer.parseInt(cform.getMaxSpare());
+            } catch (Throwable t) {
+                maxSpare = 50;
+            }
+            mBServer.setAttribute(coname,
+                                  new Attribute(attribute, (new Integer(maxSpare)).toString())); 
+            attribute = "maxThreads";
+            int maxThreads = 200;
+            try {
+                maxThreads = Integer.parseInt(cform.getMaxThreads());
+            } catch (Throwable t) {
+                maxThreads = 200;
+            }
+            mBServer.setAttribute(coname,
+                                  new Attribute(attribute, (new Integer(maxThreads)).toString())); 
+			
+            attribute = "minSpareThreads";
+            int minSpare = 4;
+            try {
+                minSpare = Integer.parseInt(cform.getMinSpare());
+            } catch (Throwable t) {
+                minSpare = 4;
+            }
+            mBServer.setAttribute(coname,
+                                  new Attribute(attribute, (new Integer(minSpare)).toString())); 
+
+            attribute = "threadPriority";
+            int threadPriority = Thread.NORM_PRIORITY;
+            try {
+                threadPriority = Integer.parseInt(cform.getThreadPriority());
+            } catch (Throwable t) {
+                threadPriority = Thread.NORM_PRIORITY;
+            }
+            mBServer.setAttribute(coname,
+                                  new Attribute(attribute, (new Integer(threadPriority))));
+				  
+            attribute = "secure";
+            mBServer.setAttribute(coname,
+                                  new Attribute("secure", new Boolean(cform.getSecure())));    
+            attribute = "tcpNoDelay";
+            mBServer.setAttribute(coname,
+                                  new Attribute("tcpNoDelay", new Boolean(cform.getTcpNoDelay())));    
+            
+            attribute = "xpoweredBy";
+            mBServer.setAttribute(coname,
+                                  new Attribute("xpoweredBy", new Boolean(cform.getXpoweredBy())));                        
+
+            attribute = "URIEncoding";
+            String uriEnc = cform.getURIEncodingText();
+            if ((uriEnc != null) && (uriEnc.length()==0)) {
+                uriEnc = null;
+            }
+            mBServer.setAttribute(coname,
+                                  new Attribute(attribute, uriEnc));            
+
+            attribute = "useBodyEncodingForURI";
+            mBServer.setAttribute(coname,
+                                  new Attribute(attribute, new Boolean(cform.getUseBodyEncodingForURIText())));
+
+            attribute = "allowTrace";
+            mBServer.setAttribute(coname,
+                                  new Attribute(attribute, new Boolean(cform.getAllowTraceText())));
+
+            // proxy name and port do not exist for AJP connector
+            if (!("AJP".equalsIgnoreCase(connectorType))) {
+                attribute = "proxyName";  
+                String proxyName = cform.getProxyName();
+                if ((proxyName != null) && (proxyName.length()>0)) { 
+                    mBServer.setAttribute(coname,
+                                  new Attribute("proxyName", proxyName));
+                }
+                
+                attribute = "proxyPort";
+                int proxyPort = 0;
+                try {
+                    proxyPort = Integer.parseInt(cform.getProxyPortText());
+                } catch (Throwable t) {
+                    proxyPort = 0;
+                }
+                mBServer.setAttribute(coname,
+                              new Attribute("proxyPort", new Integer(proxyPort))); 
+            }
+            
+            // HTTPS specific properties
+            if("HTTPS".equalsIgnoreCase(connectorType)) {
+                attribute = "algorithm";
+                String algorithm = cform.getAlgorithm();
+                if ((algorithm != null) && (algorithm.length()>0)) 
+                    mBServer.setAttribute(coname,
+                              new Attribute("algorithm", algorithm));  
+                
+                attribute = "clientAuth";              
+                mBServer.setAttribute(coname,
+                              new Attribute("clientAuth", 
+                                             cform.getClientAuthentication()));   
+                
+                attribute = "ciphers";
+                String ciphers = cform.getCiphers();
+                if ((ciphers != null) && (ciphers.length()>0)) 
+                    mBServer.setAttribute(coname,
+                              new Attribute("ciphers", ciphers));           
+                
+                attribute = "keystoreFile";
+                String keyFile = cform.getKeyStoreFileName();
+                if ((keyFile != null) && (keyFile.length()>0)) 
+                    mBServer.setAttribute(coname,
+                              new Attribute("keystoreFile", keyFile));            
+                
+                attribute = "keystorePass";
+                String keyPass = cform.getKeyStorePassword();
+                if ((keyPass != null) && (keyPass.length()>0)) 
+                    mBServer.setAttribute(coname,
+                              new Attribute("keystorePass", keyPass));                 
+                // request.setAttribute("warning", "connector.keyPass.warning");  
+                
+                attribute = "keystoreType";
+                String keyType = cform.getKeyStoreType();
+                if ((keyType != null) && (keyType.length()>0)) 
+                    mBServer.setAttribute(coname,
+                              new Attribute("keystoreType", keyType));   
+                
+                attribute = "sslProtocol";
+                String sslProtocol = cform.getSslProtocol();
+                if ((sslProtocol != null) && (sslProtocol.length()>0)) 
+                    mBServer.setAttribute(coname,
+                              new Attribute("sslProtocol", sslProtocol));                    
+             }
+ 
+        } catch (Exception e) {
+
+            getServlet().log
+                (resources.getMessage(locale, "users.error.attribute.set",
+                                      attribute), e);
+            response.sendError
+                (HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
+                 resources.getMessage(locale, "users.error.attribute.set",
+                                      attribute));
+            return (null);
+        }
+        // Forward to the success reporting page
+        session.removeAttribute(mapping.getAttribute());
+        return (mapping.findForward("Save Successful"));
+        
+    }
+    
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/connector/patch.txt
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/connector/patch.txt	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/connector/patch.txt	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,52 @@
+Index: EditConnectorAction.java
+===================================================================
+--- EditConnectorAction.java	(revision 379367)
++++ EditConnectorAction.java	(working copy)
+@@ -21,6 +21,7 @@
+ import java.util.List;
+ import java.util.Locale;
+ import java.util.ArrayList;
++import java.net.Inet4Address;
+ import javax.servlet.ServletException;
+ import javax.servlet.http.HttpServletRequest;
+ import javax.servlet.http.HttpServletResponse;
+@@ -80,12 +81,12 @@
+                                  HttpServletRequest request,
+                                  HttpServletResponse response)
+         throws IOException, ServletException {
+-        
++
+         // Acquire the resources that we need
+         HttpSession session = request.getSession();
+         Locale locale = getLocale(request);
+         MessageResources resources = getResources(request);
+-        
++
+         // Acquire a reference to the MBeanServer containing our MBeans
+         try {
+             mBServer = ((ApplicationServlet) getServlet()).getServer();
+@@ -121,7 +122,7 @@
+         connectorFm.setNodeLabel(sb.toString());
+         connectorFm.setBooleanVals(Lists.getBooleanValues());        
+         connectorFm.setClientAuthVals(Lists.getClientAuthValues());
+-        
++
+         String attribute = null;
+         try {
+ 
+@@ -168,10 +169,11 @@
+                 (String.valueOf(mBServer.getAttribute(cname, attribute)));            
+             attribute = "enableLookups";
+             connectorFm.setEnableLookups
+-                (String.valueOf(mBServer.getAttribute(cname, attribute)));            
++                (String.valueOf(mBServer.getAttribute(cname, attribute)));
+             attribute = "address";
+-            connectorFm.setAddress
+-                ((String) mBServer.getAttribute(cname, attribute));          
++            Inet4Address inet4Address =
++                    (Inet4Address) mBServer.getAttribute(cname, attribute);
++            connectorFm.setAddress(inet4Address.getHostAddress());
+             attribute = "maxKeepAliveRequests";
+             connectorFm.setMaxKeepAliveText
+                 (String.valueOf(mBServer.getAttribute(cname, attribute)));   
+

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/context/AddContextAction.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/context/AddContextAction.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/context/AddContextAction.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,109 @@
+/*
+ * Copyright 2001-2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.admin.context;
+
+import java.io.IOException;
+import java.util.Locale;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+import org.apache.struts.action.Action;
+import org.apache.struts.action.ActionForm;
+import org.apache.struts.action.ActionForward;
+import org.apache.struts.action.ActionMapping;
+import org.apache.struts.util.MessageResources;
+import org.apache.webapp.admin.Lists;
+import org.apache.webapp.admin.TomcatTreeBuilder;
+/**
+ * The <code>Action</code> that sets up <em>Add Context</em> transactions.
+ *
+ * @author Manveen Kaur
+ * @version $Revision: 413761 $ $Date: 2006-06-12 18:04:18 -0500 (Mon, 12 Jun 2006) $
+ */
+
+public class AddContextAction extends Action {
+    
+    // --------------------------------------------------------- Public Methods
+    
+    /**
+     * Process the specified HTTP request, and create the corresponding HTTP
+     * response (or forward to another web component that will create it).
+     * Return an <code>ActionForward</code> instance describing where and how
+     * control should be forwarded, or <code>null</code> if the response has
+     * already been completed.
+     *
+     * @param mapping The ActionMapping used to select this instance
+     * @param actionForm The optional ActionForm bean for this request (if any)
+     * @param request The HTTP request we are processing
+     * @param response The HTTP response we are creating
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception ServletException if a servlet exception occurs
+     */
+    public ActionForward execute(ActionMapping mapping,
+    ActionForm form,
+    HttpServletRequest request,
+    HttpServletResponse response)
+    throws IOException, ServletException {
+        
+        // Acquire the resources that we need
+        HttpSession session = request.getSession();
+        
+        // Fill in the form values for display and editing
+        ContextForm contextFm = new ContextForm();
+        session.setAttribute("contextForm", contextFm);
+        contextFm.setAdminAction("Create");
+        contextFm.setObjectName("");
+        String parent = request.getParameter("parent");
+        contextFm.setParentObjectName(parent);
+        int i = parent.indexOf(":");
+        String domain = parent.substring(0, i);
+        int position = parent.indexOf(",");
+        String loader = domain + TomcatTreeBuilder.LOADER_TYPE + 
+                parent.substring(position, parent.length());
+        String manager = domain + TomcatTreeBuilder.MANAGER_TYPE + 
+                parent.substring(position, parent.length());
+        contextFm.setLoaderObjectName(loader);
+        contextFm.setManagerObjectName(manager); 
+        contextFm.setNodeLabel("");
+        contextFm.setCookies("");
+        contextFm.setCrossContext("false");
+        contextFm.setDocBase("");
+        contextFm.setOverride("false");
+        contextFm.setPrivileged("false");
+        contextFm.setPath("");
+        contextFm.setReloadable("false");
+        contextFm.setSwallowOutput("false");
+        contextFm.setUseNaming("true");
+        contextFm.setWorkDir("");        
+        contextFm.setPath("");
+        //loader initialization
+        //contextFm.setLdrCheckInterval("15");
+        contextFm.setLdrReloadable("false");
+        //manager initialization
+        //contextFm.setMgrCheckInterval("60");
+        contextFm.setMgrMaxSessions("-1");
+        contextFm.setMgrSessionIDInit("");
+        
+        contextFm.setBooleanVals(Lists.getBooleanValues());        
+        
+        // Forward to the context display page
+        return (mapping.findForward("Context"));
+        
+    }    
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/context/ContextForm.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/context/ContextForm.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/context/ContextForm.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,780 @@
+/*
+ * Copyright 2001,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.admin.context;
+
+import javax.servlet.http.HttpServletRequest;
+import org.apache.struts.action.ActionError;
+import org.apache.struts.action.ActionErrors;
+import org.apache.struts.action.ActionForm;
+import org.apache.struts.action.ActionMapping;
+import java.util.List;
+
+/**
+ * Form bean for the context page.
+ *
+ * @author Manveen Kaur
+ * @version $Revision: 303641 $ $Date: 2005-01-14 17:55:41 -0600 (Fri, 14 Jan 2005) $
+ */
+
+public final class ContextForm extends ActionForm {
+    
+    // ----------------------------------------------------- Instance Variables
+    
+   /**
+     * The administrative action represented by this form.
+     */
+    private String adminAction = "Edit";
+
+    /**
+     * The object name of the Context this bean refers to.
+     */
+    private String objectName = null;
+   
+    /**
+     * The object name of the parent of this Context.
+     */
+    private String parentObjectName = null;
+   
+   /**
+     * The object name of the loader of this Context.
+     */
+    private String loaderObjectName = null;
+   
+    /**
+     * The object name of the manager of this Context.
+     */
+    private String managerObjectName = null;
+   
+    /**
+     * The text for the node label.
+     */
+    private String nodeLabel = null;
+    
+    /**
+     * The value of cookies.
+     */
+    private String cookies = "false";
+    
+    /**
+     * The value of cross context.
+     */
+    private String crossContext = "false";
+    
+    /**
+     * The text for the document Base.
+     */
+    private String docBase = null;
+    
+    /**
+     * The text for override boolean.
+     */
+    private String override = "false";
+    
+    /**
+     * The text for privileged boolean.
+     */
+    private String privileged = "false";
+    
+    /**
+     * The text for the context path for this context.
+     */
+    private String path = null;
+    
+    /**
+     * The text for reloadable boolean.
+     */
+    private String reloadable = "false";
+
+    /**
+     * The text for swallowOutput boolean.
+     */
+    private String swallowOutput = "false";
+
+    /**
+     * The text for use naming boolean.
+     */
+    private String useNaming = "false";
+    
+    /**
+     * The text for the working directory for this context.
+     */
+    private String workDir = null;
+    
+    /**
+     * The text for the loader check interval.
+     */
+    private String ldrCheckInterval = "15";
+    
+    /**
+     * The text for the boolean value of loader reloadable.
+     */
+    private String ldrReloadable = "false";
+    
+    /**
+     * The text for the session manager check interval.
+     */
+    private String mgrCheckInterval = "60";
+    
+    
+    /**
+     * The text for the session mgr session ID initializer.
+     */
+    private String mgrSessionIDInit = "";
+    
+    /**
+     * The text for the session mgr max active sessions.
+     */
+    private String mgrMaxSessions = "0";
+    
+    /**
+     * The text for the anti resource locking flag.
+     */
+    private String antiResourceLocking = "false";
+
+    /**
+     * The text for the anti jar locking flag.
+     */
+    private String antiJarLocking = "false";
+
+    /*
+     * Represent boolean (true, false) values for cookies etc.
+     */
+    private List booleanVals = null;
+    
+    // ------------------------------------------------------------- Properties
+     
+   /**
+     * Return the administrative action represented by this form.
+     */
+    public String getAdminAction() {
+
+        return this.adminAction;
+
+    }
+
+
+    /**
+     * Set the administrative action represented by this form.
+     */
+    public void setAdminAction(String adminAction) {
+
+        this.adminAction = adminAction;
+
+    }
+
+    /**
+     * Return the object name of the Context this bean refers to.
+     */
+    public String getObjectName() {
+
+        return this.objectName;
+
+    }
+
+    /**
+     * Set the object name of the Context this bean refers to.
+     */
+    public void setObjectName(String objectName) {
+
+        this.objectName = objectName;
+
+    }    
+    
+    /**
+     * Return the parent object name of the Context this bean refers to.
+     */
+    public String getParentObjectName() {
+
+        return this.parentObjectName;
+
+    }
+
+    /**
+     * Set the parent object name of the Context this bean refers to.
+     */
+    public void setParentObjectName(String parentObjectName) {
+
+        this.parentObjectName = parentObjectName;
+
+    }
+    
+      /**
+     * Return the loader object name of the Context this bean refers to.
+     */
+    public String getLoaderObjectName() {
+
+        return this.loaderObjectName;
+
+    }
+
+    /**
+     * Set the loader object name of the Context this bean refers to.
+     */
+    public void setLoaderObjectName(String loaderObjectName) {
+
+        this.loaderObjectName = loaderObjectName;
+
+    }
+    
+      /**
+     * Return the manager object name of the Context this bean refers to.
+     */
+    public String getManagerObjectName() {
+
+        return this.managerObjectName;
+
+    }
+
+    /**
+     * Set the manager object name of the Context this bean refers to.
+     */
+    public void setManagerObjectName(String managerObjectName) {
+
+        this.managerObjectName = managerObjectName;
+
+    }
+    
+    /**
+     * Return the label of the node that was clicked.
+     */
+    public String getNodeLabel() {
+        
+        return this.nodeLabel;
+        
+    }
+    
+    /**
+     * Set the node label.
+     */
+    public void setNodeLabel(String nodeLabel) {
+        
+        this.nodeLabel = nodeLabel;
+        
+    }
+    
+    
+    /**
+     * Return the booleanVals.
+     */
+    public List getBooleanVals() {
+        
+        return this.booleanVals;
+        
+    }
+    
+    /**
+     * Set the debugVals.
+     */
+    public void setBooleanVals(List booleanVals) {
+        
+        this.booleanVals = booleanVals;
+        
+    }
+    
+    
+    /**
+     * Return the Cookies.
+     */
+    
+    public String getCookies() {
+        
+        return this.cookies;
+        
+    }
+    
+    /**
+     * Set the Cookies.
+     */
+    public void setCookies(String cookies) {
+        
+        this.cookies = cookies;
+        
+    }
+    
+    /**
+     * Return the Cross Context.
+     */
+    
+    public String getCrossContext() {
+        
+        return this.crossContext;
+        
+    }
+    
+    /**
+     * Set the Cross Context.
+     */
+    public void setCrossContext(String crossContext) {
+        
+        this.crossContext = crossContext;
+        
+    }
+    
+    
+    /**
+     * Return the Document Base Text.
+     */
+    
+    public String getDocBase() {
+        
+        return this.docBase;
+        
+    }
+    
+    /**
+     * Set the document Base text.
+     */
+    public void setDocBase(String docBase) {
+        
+        this.docBase = docBase;
+        
+    }
+    
+    
+    /**
+     * Return the Override boolean value.
+     */
+    
+    public String getOverride() {
+        
+        return this.override;
+        
+    }
+    
+    /**
+     * Set the override value.
+     */
+    public void setOverride(String override) {
+        
+        this.override = override;
+        
+    }
+    
+    
+    /**
+     * Return the privileged boolean value.
+     */
+    
+    public String getPrivileged() {
+        
+        return this.privileged;
+        
+    }
+    
+    /**
+     * Set the privileged value.
+     */
+    public void setPrivileged(String privileged) {
+        
+        this.privileged = privileged;
+        
+    }
+    
+    
+    /**
+     * Return the context path.
+     */
+    
+    public String getPath() {
+        
+        return this.path;
+        
+    }
+    
+    /**
+     * Set the context path text.
+     */
+    public void setPath(String path) {
+        
+        this.path = path;
+        
+    }
+    
+    
+    /**
+     * Return the reloadable boolean value.
+     */
+    
+    public String getReloadable() {
+        
+        return this.reloadable;
+        
+    }
+    
+    /**
+     * Set the reloadable value.
+     */
+    public void setReloadable(String reloadable) {
+        
+        this.reloadable = reloadable;
+        
+    }
+    
+    /**
+     * Return the swallowOutput boolean value.
+     */
+
+    public String getSwallowOutput() {
+
+        return this.swallowOutput;
+
+    }
+
+    /**
+     * Set the swallowOutput value.
+     */
+    public void setSwallowOutput(String swallowOutput) {
+
+        this.swallowOutput = swallowOutput;
+
+    }
+
+    /**
+     * Return the use naming boolean value.
+     */
+    
+    public String getUseNaming() {
+        
+        return this.useNaming;
+        
+    }
+    
+    /**
+     * Set the useNaming value.
+     */
+    public void setUseNaming(String useNaming) {
+        
+        this.useNaming = useNaming;
+        
+    }
+    
+    /**
+     * Return the Working Directory.
+     */
+    public String getWorkDir() {
+        
+        return this.workDir;
+        
+    }
+    
+    /**
+     * Set the working directory.
+     */
+    public void setWorkDir(String workDir) {
+        
+        this.workDir = workDir;
+        
+    }
+    
+    
+    /**
+     * Return the loader check interval.
+     */
+    public String getLdrCheckInterval() {
+        
+        return this.ldrCheckInterval;
+        
+    }
+    
+    /**
+     * Set the loader Check Interval.
+     */
+    public void setLdrCheckInterval(String ldrCheckInterval) {
+        
+        this.ldrCheckInterval = ldrCheckInterval;
+        
+    }
+    
+    
+    /**
+     * Return the loader reloadable boolean value.
+     */
+    public String getLdrReloadable() {
+        
+        return this.ldrReloadable;
+        
+    }
+    
+    /**
+     * Set the loader reloadable value.
+     */
+    public void setLdrReloadable(String ldrReloadable) {
+        
+        this.ldrReloadable = ldrReloadable;
+        
+    }
+    
+    /**
+     * Return the session manager check interval.
+     */
+    public String getMgrCheckInterval() {
+        
+        return this.mgrCheckInterval;
+        
+    }
+    
+    /**
+     * Set the session manager Check Interval.
+     */
+    public void setMgrCheckInterval(String mgrCheckInterval) {
+        
+        this.mgrCheckInterval = mgrCheckInterval;
+        
+    }
+    
+    /**
+     * Return the session ID initializer.
+     */
+    public String getMgrSessionIDInit() {
+        
+        return this.mgrSessionIDInit;
+        
+    }
+    
+    /**
+     * Set the mgr Session ID Initizializer.
+     */
+    public void setMgrSessionIDInit(String mgrSessionIDInit) {
+        
+        this.mgrSessionIDInit = mgrSessionIDInit;
+        
+    }
+    
+    /**
+     * Return the Session mgr maximum active sessions.
+     */
+    
+    public String getMgrMaxSessions() {
+        
+        return this.mgrMaxSessions;
+        
+    }
+    
+    /**
+     * Set the Session mgr maximum active sessions.
+     */
+    public void setMgrMaxSessions(String mgrMaxSessions) {
+        
+        this.mgrMaxSessions = mgrMaxSessions;
+        
+    }
+
+    /**
+     * Get the anti resouce locking flag
+     */
+    public String getAntiResourceLocking() {
+        return antiResourceLocking;
+    }
+
+    /**
+     * Set the anti resource locking flag
+     */
+    public void setAntiResourceLocking(String arl) {
+	antiResourceLocking = arl;
+    }
+
+
+    /**
+     * Get the anti jar locking flag
+     */
+    public String getAntiJarLocking() {
+        return antiJarLocking;
+    }
+
+    /**
+     * Set the anti jar locking flag
+     */
+    public void setAntiJarLocking(String ajl) {
+        antiJarLocking = ajl;
+    }
+
+    // --------------------------------------------------------- Public Methods
+    
+    /**
+     * Reset all properties to their default values.
+     *
+     * @param mapping The mapping used to select this instance
+     * @param request The servlet request we are processing
+     */
+    public void reset(ActionMapping mapping, HttpServletRequest request) {
+        
+        this.objectName = null;
+        this.parentObjectName = null;
+        this.loaderObjectName = null;
+        this.managerObjectName = null;
+        
+        // context properties
+        this.cookies = "false";
+        this.crossContext = "false";
+        this.docBase = null;
+        this.override= "false";
+        this.path = null;
+        this.reloadable = "false";
+        this.swallowOutput = "false";
+        this.antiResourceLocking = "false";
+        this.antiJarLocking = "false";
+
+        // loader properties
+        this.ldrCheckInterval = "15";
+        this.ldrReloadable = "true";
+        
+        // session manager properties
+        this.mgrCheckInterval = "60";
+        this.mgrSessionIDInit = "0";
+        this.mgrMaxSessions = "-1";
+    }
+    
+    /**
+     * Render this object as a String.
+     */
+    public String toString() {
+
+        StringBuffer sb = new StringBuffer("ContextForm[adminAction=");
+        sb.append(adminAction);
+        sb.append(",docBase=");
+        sb.append(docBase);
+        sb.append(",path=");
+        sb.append(path);
+        sb.append(",cookies=");
+        sb.append(cookies);
+        sb.append(",crossContext=");
+        sb.append(crossContext);
+        sb.append(",override=");
+        sb.append(override);
+        sb.append(",reloadable=");
+        sb.append(reloadable);
+        sb.append(",swallowOutput=");
+        sb.append(swallowOutput);
+
+        // loader properties
+        sb.append(",ldrCheckInterval=");
+        sb.append(ldrCheckInterval);        
+        sb.append(",ldrReloadable=");
+        sb.append(ldrReloadable);
+        // manager properties
+        sb.append(",mgrCheckInterval=");
+        sb.append(mgrCheckInterval);
+        sb.append(",mgrSessionIDInit=");
+        sb.append(mgrSessionIDInit);
+        sb.append(",mgrMaxSessions=");
+        sb.append(mgrMaxSessions);
+        // object names
+        sb.append("',objectName='");
+        sb.append(objectName);
+        sb.append("',parentObjectName=");
+        sb.append(parentObjectName);
+        sb.append("',loaderObjectName=");
+        sb.append(loaderObjectName);
+        sb.append("',managerObjectName=");
+        sb.append(managerObjectName);
+        sb.append("]");
+        return (sb.toString());
+
+    }
+    /**
+     * Validate the properties that have been set from this HTTP request,
+     * and return an <code>ActionErrors</code> object that encapsulates any
+     * validation errors that have been found.  If no errors are found, return
+     * <code>null</code> or an <code>ActionErrors</code> object with no
+     * recorded error messages.
+     *
+     * @param mapping The mapping used to select this instance
+     * @param request The servlet request we are processing
+     */
+    
+    private ActionErrors errors;
+    
+    public ActionErrors validate(ActionMapping mapping,
+    HttpServletRequest request) {
+        
+        errors = new ActionErrors();
+        
+        String submit = request.getParameter("submit");
+        
+        // front end validation when save is clicked.
+        //if (submit != null) {
+            
+            // docBase cannot be null
+            if ((docBase == null) || (docBase.length() < 1)) {
+                errors.add("docBase", new ActionError("error.docBase.required"));
+            }
+            
+            // if path is empty, it's root context
+            // validate context starting with "/" only at the time of context creation.
+            if ("Create".equalsIgnoreCase(adminAction) && !path.startsWith("/")) {
+                errors.add("path", new ActionError("error.path.prefix"));                
+            }
+                        
+            //if ((workDir == null) || (workDir.length() < 1)) {
+            //    errors.add("workDir", new ActionError("error.workDir.required"));
+            //}
+            
+            // loader properties
+            // FIXME-- verify if these ranges are ok.
+            numberCheck("ldrCheckInterval", ldrCheckInterval  , true, 0, 10000);
+            
+            // session manager properties            
+            numberCheck("mgrCheckInterval",  mgrCheckInterval, true, 0, 10000);
+            numberCheck("mgrMaxSessions",  mgrMaxSessions, false, -1, 100);
+            
+            //if ((mgrSessionIDInit == null) || (mgrSessionIDInit.length() < 1)) {
+            //    errors.add("mgrSessionIDInit", new ActionError("error.mgrSessionIDInit.required"));
+            //}
+        //}
+        
+        return errors;
+    }
+    
+    /*
+     * Helper method to check that it is a required number and
+     * is a valid integer within the given range. (min, max).
+     *
+     * @param  field  The field name in the form for which this error occured.
+     * @param  numText  The string representation of the number.
+     * @param rangeCheck  Boolean value set to true of reange check should be performed.
+     *
+     * @param  min  The lower limit of the range
+     * @param  max  The upper limit of the range
+     *
+     */
+    
+    private void numberCheck(String field, String numText, boolean rangeCheck,
+    int min, int max) {
+        
+        // Check for 'is required'
+        if ((numText == null) || (numText.length() < 1)) {
+            errors.add(field, new ActionError("error."+field+".required"));
+        } else {
+            
+            // check for 'must be a number' in the 'valid range'
+            try {
+                int num = Integer.parseInt(numText);
+                // perform range check only if required
+                if (rangeCheck) {
+                    if ((num < min) || (num > max ))
+                        errors.add( field,
+                        new ActionError("error."+ field +".range"));
+                }
+            } catch (NumberFormatException e) {
+                errors.add(field,
+                new ActionError("error."+ field + ".format"));
+            }
+        }
+    }
+    
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/context/ContextsForm.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/context/ContextsForm.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/context/ContextsForm.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.admin.context;
+
+
+import javax.servlet.http.HttpServletRequest;
+import org.apache.struts.action.ActionForm;
+import org.apache.struts.action.ActionMapping;
+
+
+/**
+ * Form bean for deleting contexts.
+ *
+ * @author Manveen Kaur
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class ContextsForm extends ActionForm {
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * The object names of the contexts to be deleted.
+     */
+    private String contexts[] = new String[0];
+
+    public String[] getContexts() {
+        return (this.contexts);
+    }
+
+    public void setContexts(String contexts[]) {
+        this.contexts = contexts;
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Reset all properties to their default values.
+     *
+     * @param mapping The mapping used to select this instance
+     * @param request The servlet request we are processing
+     */
+    public void reset(ActionMapping mapping, HttpServletRequest request) {
+
+        this.contexts = new String[0];
+
+    }
+        
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/context/DeleteContextAction.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/context/DeleteContextAction.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/context/DeleteContextAction.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,162 @@
+/*
+ * Copyright 2001-2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.admin.context;
+
+import java.io.IOException;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.Locale;
+import java.util.ArrayList;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+import org.apache.struts.action.Action;
+import org.apache.struts.action.ActionForm;
+import org.apache.struts.action.ActionForward;
+import org.apache.struts.action.ActionMapping;
+
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+import org.apache.struts.util.MessageResources;
+
+import org.apache.webapp.admin.ApplicationServlet;
+
+/**
+ * The <code>Action</code> that sets up <em>Delete Contexts</em> transactions.
+ *
+ * @author Manveen Kaur
+ * @version $Revision: 303641 $ $Date: 2005-01-14 17:55:41 -0600 (Fri, 14 Jan 2005) $
+ */
+
+public class DeleteContextAction extends Action {
+    
+
+    /**
+     * The MBeanServer we will be interacting with.
+     */
+    private MBeanServer mBServer = null;
+    
+
+    // --------------------------------------------------------- Public Methods
+    
+    /**
+     * Process the specified HTTP request, and create the corresponding HTTP
+     * response (or forward to another web component that will create it).
+     * Return an <code>ActionForward</code> instance describing where and how
+     * control should be forwarded, or <code>null</code> if the response has
+     * already been completed.
+     *
+     * @param mapping The ActionMapping used to select this instance
+     * @param actionForm The optional ActionForm bean for this request (if any)
+     * @param request The HTTP request we are processing
+     * @param response The HTTP response we are creating
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception ServletException if a servlet exception occurs
+     */
+    public ActionForward execute(ActionMapping mapping,
+                                 ActionForm form,
+                                 HttpServletRequest request,
+                                 HttpServletResponse response)
+        throws IOException, ServletException {
+        
+
+        // Acquire the resources that we need
+        HttpSession session = request.getSession();
+        Locale locale = getLocale(request);
+        MessageResources resources = getResources(request);
+        
+        // Acquire a reference to the MBeanServer containing our MBeans
+        try {
+            mBServer = ((ApplicationServlet) getServlet()).getServer();
+        } catch (Throwable t) {
+            throw new ServletException
+            ("Cannot acquire MBeanServer reference", t);
+        }
+        
+        // object name that forms the basis of the search pattern
+        // to get list of all available contexts
+        String patternObject = null;
+        
+        // Set up a form bean containing the currently selected
+        // objects to be deleted
+        ContextsForm contextsForm = new ContextsForm();
+        String select = request.getParameter("select");
+        if (select != null) {
+            String contexts[] = new String[1];
+            contexts[0] = select;
+            contextsForm.setContexts(contexts);
+            patternObject = select;
+        }        
+        request.setAttribute("contextsForm", contextsForm);
+                
+        // get the parent host object name
+        String parent = request.getParameter("parent");
+        if (parent != null) {                
+            patternObject = parent;
+        } 
+        
+        // Accumulate a list of all available contexts
+        ArrayList list = new ArrayList();
+        try {
+            ObjectName poname = new ObjectName(patternObject);
+            String domain = poname.getDomain();
+            StringBuffer sb = new StringBuffer(domain);
+            sb.append(":j2eeType=WebModule,*");
+            ObjectName search = new ObjectName(sb.toString());
+            // get all available contexts only for this host
+            Iterator items =
+                mBServer.queryNames(search, null).iterator();
+            String item = null;
+            String host = poname.getKeyProperty("host");
+            if (host==null) {
+                String name = poname.getKeyProperty("name");
+                if ((name != null) && (name.length() > 0)) {
+                    name = name.substring(2);
+                    int i = name.indexOf("/");
+                    host = name.substring(0,i);
+                }
+            }
+            String hostPrefix = "//"+host;
+            String hostAttr = null;
+            while (items.hasNext()) {
+                item = items.next().toString();
+                ObjectName oname = new ObjectName(item);
+                hostAttr = oname.getKeyProperty("name");
+                if (hostAttr.startsWith(hostPrefix)) {
+                    list.add(item);
+                }
+            }
+        } catch (Exception e) {
+            getServlet().log
+                (resources.getMessage(locale, "users.error.select"));
+            response.sendError
+                (HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
+                 resources.getMessage(locale, "users.error.select"));
+            return (null);
+        }
+        Collections.sort(list);
+        request.setAttribute("contextsList", list);
+        
+        // Forward to the list display page
+        return (mapping.findForward("Contexts"));
+
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/context/DeleteContextsAction.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/context/DeleteContextsAction.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/context/DeleteContextsAction.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,152 @@
+/*
+ * Copyright 2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.admin.context;
+
+import java.io.IOException;
+import java.util.Locale;
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpSession;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import org.apache.struts.action.Action;
+import org.apache.struts.action.ActionForm;
+import org.apache.struts.action.ActionForward;
+import org.apache.struts.action.ActionMapping;
+import org.apache.struts.util.MessageResources;
+
+import org.apache.webapp.admin.ApplicationServlet;
+import org.apache.webapp.admin.TomcatTreeBuilder;
+import org.apache.webapp.admin.TreeControl;
+import org.apache.webapp.admin.TreeControlNode;
+
+
+/**
+ * The <code>Action</code> that completes <em>Delete Contexts</em>
+ * transactions.
+ *
+ * @author Manveen Kaur
+ * @version $Revision: 303641 $ $Date: 2005-01-14 17:55:41 -0600 (Fri, 14 Jan 2005) $
+ */
+
+public class DeleteContextsAction extends Action {
+
+
+    /**
+     * Signature for the <code>removeContext</code> operation.
+     */
+    private String removeContextTypes[] =
+    { "java.lang.String",      // Object name
+    };
+
+
+    /**
+     * The MBeanServer we will be interacting with.
+     */
+    private MBeanServer mBServer = null;
+    
+
+    // --------------------------------------------------------- Public Methods
+    
+    
+    /**
+     * Process the specified HTTP request, and create the corresponding HTTP
+     * response (or forward to another web component that will create it).
+     * Return an <code>ActionForward</code> instance describing where and how
+     * control should be forwarded, or <code>null</code> if the response has
+     * already been completed.
+     *
+     * @param mapping The ActionMapping used to select this instance
+     * @param actionForm The optional ActionForm bean for this request (if any)
+     * @param request The HTTP request we are processing
+     * @param response The HTTP response we are creating
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception ServletException if a servlet exception occurs
+     */
+    public ActionForward execute(ActionMapping mapping,
+                                 ActionForm form,
+                                 HttpServletRequest request,
+                                 HttpServletResponse response)
+        throws IOException, ServletException {
+        
+        
+        // Look up the components we will be using as needed
+        HttpSession session = request.getSession();
+        Locale locale = getLocale(request);
+        MessageResources resources = getResources(request);
+
+        // Acquire a reference to the MBeanServer containing our MBeans
+        try {
+            mBServer = ((ApplicationServlet) getServlet()).getServer();
+        } catch (Throwable t) {
+            throw new ServletException
+            ("Cannot acquire MBeanServer reference", t);
+        }
+        
+        // Delete the specified Contexts
+        String contexts[]  = ((ContextsForm) form).getContexts();
+        String values[] = new String[1];
+        String operation = "removeContext";
+
+        try {
+
+            // Look up our tree control data structure
+            TreeControl control = (TreeControl)
+                session.getAttribute("treeControlTest");
+
+            // Remove the specified contexts
+            for (int i = 0; i < contexts.length; i++) {
+                values[0] = contexts[i];
+                if (control != null) {
+                    control.selectNode(null);
+                    TreeControlNode node = control.findNode(contexts[i]);
+                    String domain = node.getDomain();
+                    ObjectName fname = TomcatTreeBuilder.getMBeanFactory();
+                    mBServer.invoke(fname, operation,
+                                values, removeContextTypes);
+                    if (node != null) {
+                        node.remove();
+                    } else {
+                        getServlet().log("Missing TreeControlNode for " +
+                                         contexts[i]);
+                    }
+                } else {
+                    getServlet().log("Missing TreeControl attribute");
+                }
+            }
+
+        } catch (Exception e) {
+            getServlet().log
+                (resources.getMessage(locale, "users.error.invoke",
+                                      operation), e);
+            response.sendError
+                (HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
+                 resources.getMessage(locale, "users.error.invoke",
+                                      operation));
+            return (null);
+
+        }
+
+        // Report successful completion of this transaction
+        return (mapping.findForward("Save Successful"));
+
+    }
+    
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/context/EditContextAction.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/context/EditContextAction.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/context/EditContextAction.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,238 @@
+/*
+ * Copyright 2001-2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.admin.context;
+
+import java.io.IOException;
+import java.util.Locale;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+import org.apache.struts.action.Action;
+import org.apache.struts.action.ActionForm;
+import org.apache.struts.action.ActionForward;
+import org.apache.struts.action.ActionMapping;
+import org.apache.struts.util.MessageResources;
+
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+
+import org.apache.webapp.admin.ApplicationServlet;
+import org.apache.webapp.admin.Lists;
+
+/**
+ * The <code>Action</code> that sets up <em>Edit Context</em> transactions.
+ *
+ * @author Manveen Kaur
+ * @version $Revision: 303641 $ $Date: 2005-01-14 17:55:41 -0600 (Fri, 14 Jan 2005) $
+ */
+
+public class EditContextAction extends Action {
+    
+
+    /**
+     * The MBeanServer we will be interacting with.
+     */
+    private MBeanServer mBServer = null;
+    
+
+    // --------------------------------------------------------- Public Methods
+    
+    /**
+     * Process the specified HTTP request, and create the corresponding HTTP
+     * response (or forward to another web component that will create it).
+     * Return an <code>ActionForward</code> instance describing where and how
+     * control should be forwarded, or <code>null</code> if the response has
+     * already been completed.
+     *
+     * @param mapping The ActionMapping used to select this instance
+     * @param actionForm The optional ActionForm bean for this request (if any)
+     * @param request The HTTP request we are processing
+     * @param response The HTTP response we are creating
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception ServletException if a servlet exception occurs
+     */
+    public ActionForward execute(ActionMapping mapping,
+                                 ActionForm form,
+                                 HttpServletRequest request,
+                                 HttpServletResponse response)
+        throws IOException, ServletException {
+        
+        // Acquire the resources that we need
+        HttpSession session = request.getSession();
+        Locale locale = getLocale(request);
+        MessageResources resources = getResources(request);
+        
+        // Acquire a reference to the MBeanServer containing our MBeans
+        try {
+            mBServer = ((ApplicationServlet) getServlet()).getServer();
+        } catch (Throwable t) {
+            throw new ServletException
+            ("Cannot acquire MBeanServer reference", t);
+        }
+        
+        // Set up the object names of the MBeans we are manipulating
+        // Context mBean
+        ObjectName cname = null;
+        // Loader mBean
+        ObjectName lname = null;
+        // Manager mBean 
+        ObjectName mname = null;
+        
+        StringBuffer sb = null;
+        try {
+            cname = new ObjectName(request.getParameter("select"));
+        } catch (Exception e) {
+            String message =
+                resources.getMessage(locale, "error.contextName.bad",
+                                     request.getParameter("select"));
+            getServlet().log(message);
+            response.sendError(HttpServletResponse.SC_BAD_REQUEST, message);
+            return (null);
+        }
+        String name = cname.getKeyProperty("name");
+        name = name.substring(2);
+        int i = name.indexOf("/");
+        String host = name.substring(0,i);
+        String path = name.substring(i);
+        // Get the corresponding loader
+        try {
+            sb = new StringBuffer(cname.getDomain());
+            sb.append(":type=Loader");
+            sb.append(",path="+path);
+            sb.append(",host="+host);
+            lname = new ObjectName(sb.toString());
+         } catch (Exception e) {
+            String message =
+                resources.getMessage(locale, "error.managerName.bad",
+                                 sb.toString());
+            getServlet().log(message);
+            response.sendError(HttpServletResponse.SC_BAD_REQUEST, message);
+            return (null);
+        }
+
+        // Session manager properties
+        // Get the corresponding Session Manager mBean
+        try {
+            sb = new StringBuffer(cname.getDomain());
+            sb.append(":type=Manager");
+            sb.append(",path="+path);
+            sb.append(",host="+host);
+            mname = new ObjectName(sb.toString());
+        } catch (Exception e) {
+            String message =
+                resources.getMessage("error.managerName.bad",
+                                 sb.toString());
+            getServlet().log(message);
+            response.sendError(HttpServletResponse.SC_BAD_REQUEST, message);
+            return (null);
+        }
+
+        // Fill in the form values for display and editing
+        ContextForm contextFm = new ContextForm();
+        session.setAttribute("contextForm", contextFm);
+        contextFm.setAdminAction("Edit");
+        contextFm.setObjectName(cname.toString());
+        contextFm.setLoaderObjectName(lname.toString());
+        contextFm.setManagerObjectName(mname.toString());
+        sb = new StringBuffer();
+        sb.append(resources.getMessage(locale, "server.service.treeBuilder.context"));
+        sb.append(" (");
+        sb.append(path);
+        sb.append(")");
+        contextFm.setNodeLabel(sb.toString());
+        contextFm.setBooleanVals(Lists.getBooleanValues());
+       
+        String attribute = null;
+        try {
+
+            // Copy scalar properties
+            attribute = "path";
+            contextFm.setPath
+                ((String) mBServer.getAttribute(cname, attribute));
+            attribute = "cookies";
+            contextFm.setCookies
+                (((Boolean) mBServer.getAttribute(cname, attribute)).toString());
+            attribute = "crossContext";
+            contextFm.setCrossContext
+                (((Boolean) mBServer.getAttribute(cname, attribute)).toString());
+            attribute = "docBase";
+            contextFm.setDocBase
+                ((String) mBServer.getAttribute(cname, attribute));
+            attribute = "workDir";
+            contextFm.setWorkDir
+                ((String) mBServer.getAttribute(cname, attribute));
+            attribute = "useNaming";
+            contextFm.setUseNaming
+                (((Boolean) mBServer.getAttribute(cname, attribute)).toString());
+            attribute = "reloadable";
+            contextFm.setReloadable
+                (((Boolean) mBServer.getAttribute(cname, attribute)).toString());
+            attribute = "swallowOutput";
+            contextFm.setSwallowOutput
+                (((Boolean) mBServer.getAttribute(cname, attribute)).toString());
+            attribute = "override";
+            contextFm.setOverride
+                (((Boolean) mBServer.getAttribute(cname, attribute)).toString());
+            attribute = "privileged";
+            contextFm.setPrivileged
+                (((Boolean) mBServer.getAttribute(cname, attribute)).toString());
+
+	    attribute = "antiJARLocking";
+	    contextFm.setAntiJarLocking
+		(((Boolean) mBServer.getAttribute(cname, attribute)).toString());
+	    attribute = "antiResourceLocking";
+	    contextFm.setAntiResourceLocking
+		(((Boolean) mBServer.getAttribute(cname, attribute)).toString());
+            // loader properties
+            //attribute = "checkInterval";
+            //contextFm.setLdrCheckInterval
+            //    (((Integer) mBServer.getAttribute(lname, attribute)).toString());
+            attribute = "reloadable";
+            contextFm.setLdrReloadable
+                (((Boolean) mBServer.getAttribute(lname, attribute)).toString());
+
+            // manager properties
+            attribute = "entropy";
+            contextFm.setMgrSessionIDInit
+                ((String) mBServer.getAttribute(mname, attribute));
+            attribute = "maxActiveSessions";
+            contextFm.setMgrMaxSessions
+                (((Integer) mBServer.getAttribute(mname, attribute)).toString());
+            //attribute = "checkInterval";
+            //contextFm.setMgrCheckInterval
+            //    (((Integer) mBServer.getAttribute(mname, attribute)).toString());
+
+        } catch (Throwable t) {
+            getServlet().log
+                (resources.getMessage(locale, "users.error.attribute.get",
+                                      attribute), t);
+            response.sendError
+                (HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
+                 resources.getMessage(locale, "users.error.attribute.get",
+                                      attribute));
+            return (null);
+        }
+        
+        // Forward to the context display page
+        return (mapping.findForward("Context"));
+        
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/context/SaveContextAction.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/context/SaveContextAction.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/context/SaveContextAction.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,514 @@
+/*
+ * Copyright 2001-2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.admin.context;
+
+
+import java.net.URLEncoder;
+import java.util.Locale;
+import java.io.IOException;
+import javax.management.Attribute;
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+import org.apache.commons.modeler.Registry;
+import org.apache.struts.action.Action;
+import org.apache.struts.action.ActionError;
+import org.apache.struts.action.ActionErrors;
+import org.apache.struts.action.ActionForm;
+import org.apache.struts.action.ActionForward;
+import org.apache.struts.action.ActionMapping;
+import org.apache.struts.util.MessageResources;
+import org.apache.webapp.admin.ApplicationServlet;
+import org.apache.webapp.admin.TomcatTreeBuilder;
+import org.apache.webapp.admin.TreeControl;
+import org.apache.webapp.admin.TreeControlNode;
+
+
+
+/**
+ * The <code>Action</code> that completes <em>Add Context</em> and
+ * <em>Edit Context</em> transactions.
+ *
+ * @author Manveen Kaur
+ * @version $Revision: 303641 $ $Date: 2005-01-14 17:55:41 -0600 (Fri, 14 Jan 2005) $
+ */
+
+public final class SaveContextAction extends Action {
+
+
+    // ----------------------------------------------------- Instance Variables
+
+    /**
+     * Signature for the <code>createStandardContext</code> operation.
+     */
+    private String createStandardContextTypes[] =
+    { "java.lang.String",     // parent
+      "java.lang.String",     // path
+      "java.lang.String",     // docBase
+    };
+
+   /**
+     * Signature for the <code>createStandardLoader</code> operation.
+     */
+    private String createStandardLoaderTypes[] =
+    { "java.lang.String",     // parent
+    };
+
+   /**
+     * Signature for the <code>createStandardManager</code> operation.
+     */
+    private String createStandardManagerTypes[] =
+    { "java.lang.String",     // parent
+    };
+
+    /**
+     * Signature for the <code>removeContext</code> operation.
+     */
+    private String removeContextTypes[] =
+    { "java.lang.String",      // Object name
+    };
+        
+    /**
+     * The MBeanServer we will be interacting with.
+     */
+    private MBeanServer mBServer = null;
+    
+
+    // --------------------------------------------------------- Public Methods
+    
+    
+    /**
+     * Process the specified HTTP request, and create the corresponding HTTP
+     * response (or forward to another web component that will create it).
+     * Return an <code>ActionForward</code> instance describing where and how
+     * control should be forwarded, or <code>null</code> if the response has
+     * already been completed.
+     *
+     * @param mapping The ActionMapping used to select this instance
+     * @param actionForm The optional ActionForm bean for this request (if any)
+     * @param request The HTTP request we are processing
+     * @param response The HTTP response we are creating
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception ServletException if a servlet exception occurs
+     */
+    public ActionForward execute(ActionMapping mapping,
+                                 ActionForm form,
+                                 HttpServletRequest request,
+                                 HttpServletResponse response)
+        throws IOException, ServletException {
+        
+        // Acquire the resources that we need
+        HttpSession session = request.getSession();
+        Locale locale = getLocale(request);
+        MessageResources resources = getResources(request);
+        
+        // Acquire a reference to the MBeanServer containing our MBeans
+        try {
+            mBServer = ((ApplicationServlet) getServlet()).getServer();
+        } catch (Throwable t) {
+            throw new ServletException
+            ("Cannot acquire MBeanServer reference", t);
+        }
+        
+        // Identify the requested action
+        ContextForm cform = (ContextForm) form;
+        String adminAction = cform.getAdminAction();
+        String cObjectName = cform.getObjectName();
+        String lObjectName = cform.getLoaderObjectName();
+        String mObjectName = cform.getManagerObjectName();
+        if ((cform.getPath() == null) || (cform.getPath().length()<1)) {
+            cform.setPath("/");
+        }
+       
+        // Perform a "Create Context" transaction (if requested)
+        if ("Create".equals(adminAction)) {
+
+            String operation = null;
+            Object values[] = null;
+            
+            try {                
+                // get the parent host name
+                String parentName = cform.getParentObjectName();
+                ObjectName honame = new ObjectName(parentName);
+                
+                // Ensure that the requested context name is unique
+                ObjectName oname = 
+                        new ObjectName(honame.getDomain() + 
+                                    ":j2eeType=WebModule,name=//" +
+                                    honame.getKeyProperty("host") + 
+                                    cform.getPath() +
+                                    // FIXME set J2EEApplication and J2EEServer
+                                    ",J2EEApplication=none,J2EEServer=none");                   
+                
+                if (mBServer.isRegistered(oname)) {
+                    ActionErrors errors = new ActionErrors();
+                    errors.add("contextName",
+                               new ActionError("error.contextName.exists"));
+                    saveErrors(request, errors);
+                    return (new ActionForward(mapping.getInput()));
+                }
+                
+                // Look up our MBeanFactory MBean
+                ObjectName fname = 
+                    TomcatTreeBuilder.getMBeanFactory();
+
+                // Create a new StandardContext object
+                values = new Object[3];
+                values[0] = parentName;
+                values[1] = cform.getPath();
+                values[2] = cform.getDocBase();
+                
+                operation = "createStandardContext";
+                cObjectName = (String)
+                    mBServer.invoke(fname, operation,
+                                    values, createStandardContextTypes);
+                // Create a new Loader object
+                values = new String[1];
+                // parent of loader is the newly created context
+                values[0] = cObjectName.toString();
+                operation = "createWebappLoader";
+                lObjectName = (String)
+                    mBServer.invoke(fname, operation,
+                                    values, createStandardLoaderTypes);                
+                
+                // Create a new StandardManager object
+                values = new String[1];
+                // parent of manager is the newly created Context
+                values[0] = cObjectName.toString();
+                operation = "createStandardManager";
+                mObjectName = (String)
+                    mBServer.invoke(fname, operation,
+                                    values, createStandardManagerTypes);
+                                                                       
+                if (mObjectName==null) {
+                    operation = "removeLoader";
+                    values[0] = lObjectName;
+                    mBServer.invoke(fname, operation, values, 
+                        removeContextTypes);
+                    operation = "removeContext";
+                    values[0] = cObjectName;
+                    mBServer.invoke(fname, operation, values, 
+                        removeContextTypes);
+                    Registry.getRegistry().unregisterComponent(new ObjectName(cObjectName));
+                    request.setAttribute("warning", "error.context.directory");
+                    return (mapping.findForward("Save Unsuccessful"));
+                }
+                
+                // Add the new Context to our tree control node
+                addToTreeControlNode(oname, cObjectName, parentName, 
+                                    resources, session, locale);                     
+
+            } catch (Exception e) {
+                getServlet().log
+                    (resources.getMessage(locale, "users.error.invoke",
+                                          operation), e);
+                response.sendError
+                    (HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
+                     resources.getMessage(locale, "users.error.invoke",
+                                          operation));
+                return (null);
+
+            }
+
+        }
+
+        // Perform attribute updates as requested
+        String attribute = null;
+        try {
+
+            ObjectName coname = new ObjectName(cObjectName);
+            ObjectName loname = new ObjectName(lObjectName);
+            ObjectName moname = new ObjectName(mObjectName);
+
+            attribute = "path";
+            String path = "";
+            try {
+                path = cform.getPath();
+            } catch (Throwable t) {
+                path = "";
+            }
+            mBServer.setAttribute(coname,
+                                  new Attribute("path", path));
+            
+            attribute = "workDir";
+            String workDir = "";
+            workDir = cform.getWorkDir();
+            if ((workDir!=null) && (workDir.length()>=1)) {
+                mBServer.setAttribute(coname,
+                                  new Attribute("workDir", workDir));
+            }
+ 
+            attribute = "cookies";
+            String cookies = "false";
+            try {
+                cookies = cform.getCookies();
+            } catch (Throwable t) {
+                cookies = "false";
+            }
+            mBServer.setAttribute(coname,
+                                  new Attribute("cookies", new Boolean(cookies)));
+
+            attribute = "crossContext";
+            String crossContext = "false";
+            try {
+                crossContext = cform.getCrossContext();
+            } catch (Throwable t) {
+                crossContext = "false";
+            }
+            mBServer.setAttribute(coname,
+                                  new Attribute("crossContext", new Boolean(crossContext)));
+
+            attribute = "override";
+            String override = "false";
+            try {
+                override = cform.getOverride();
+            } catch (Throwable t) {
+                override = "false";
+            }
+            mBServer.setAttribute(coname,
+                                  new Attribute("override", new Boolean(override)));
+
+            attribute = "privileged";
+            String privileged = "false";
+            try {
+                privileged = cform.getPrivileged();
+            } catch (Throwable t) {
+                privileged = "false";
+            }
+            mBServer.setAttribute(coname,
+                                  new Attribute("privileged", new Boolean(privileged)));
+
+            attribute = "reloadable";
+            String reloadable = "false";
+            try {
+                reloadable = cform.getReloadable();
+            } catch (Throwable t) {
+                reloadable = "false";
+            }
+            mBServer.setAttribute(coname,
+                                  new Attribute("reloadable", new Boolean(reloadable)));
+
+            attribute = "swallowOutput";
+            String swallowOutput = "false";
+            try {
+                swallowOutput = cform.getSwallowOutput();
+            } catch (Throwable t) {
+                swallowOutput = "false";
+            }
+            mBServer.setAttribute(coname,
+                                  new Attribute("swallowOutput", new Boolean(swallowOutput)));
+
+            attribute = "useNaming";
+            String useNaming = "false";
+            try {
+                useNaming = cform.getUseNaming();
+            } catch (Throwable t) {
+                useNaming = "false";
+            }
+            mBServer.setAttribute(coname,
+                                  new Attribute("useNaming", new Boolean(useNaming)));
+
+            attribute = "antiJARLocking";
+            String antiJarLocking = cform.getAntiJarLocking();
+            mBServer.setAttribute(coname,
+                                  new Attribute("antiJARLocking", new Boolean(antiJarLocking)));
+
+            attribute = "antiResourceLocking";
+            String antiResourceLocking = cform.getAntiResourceLocking();
+            mBServer.setAttribute(coname,
+                                  new Attribute("antiResourceLocking", new Boolean(antiResourceLocking)));
+
+	    
+            // Loader properties            
+            attribute = "reloadable";
+            try {
+                reloadable = cform.getLdrReloadable();
+            } catch (Throwable t) {
+                reloadable = "false";
+            }
+            mBServer.setAttribute(loname,
+                                  new Attribute("reloadable", new Boolean(reloadable)));
+            
+            //attribute = "checkInterval";
+            //int checkInterval = 15;
+            //try {
+            //    checkInterval = Integer.parseInt(cform.getLdrCheckInterval());
+            //} catch (Throwable t) {
+            //    checkInterval = 15;
+            //}
+            //mBServer.setAttribute(loname,
+            //                      new Attribute("checkInterval", new Integer(checkInterval)));
+
+            // Manager properties            
+            attribute = "entropy";
+            String entropy = cform.getMgrSessionIDInit();
+            if ((entropy!=null) && (entropy.length()>=1)) {
+                mBServer.setAttribute(moname,
+                                  new Attribute("entropy",entropy));
+            }
+            
+            //attribute = "checkInterval";
+            //try {
+            //    checkInterval = Integer.parseInt(cform.getMgrCheckInterval());
+            //} catch (Throwable t) {
+            //    checkInterval = 60;
+            //}
+            //mBServer.setAttribute(moname,
+            //                      new Attribute("checkInterval", new Integer(checkInterval)));
+            
+            attribute = "maxActiveSessions";
+            int maxActiveSessions = -1;
+            try {
+                maxActiveSessions = Integer.parseInt(cform.getMgrMaxSessions());
+            } catch (Throwable t) {
+                maxActiveSessions = -1;
+            }
+            mBServer.setAttribute(moname,
+                                  new Attribute("maxActiveSessions", new Integer(maxActiveSessions)));
+
+        } catch (Exception e) {
+
+            getServlet().log
+                (resources.getMessage(locale, "users.error.attribute.set",
+                                      attribute), e);
+            response.sendError
+                (HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
+                 resources.getMessage(locale, "users.error.attribute.set",
+                                      attribute));
+            return (null);
+        }
+        
+        // Forward to the success reporting page
+        session.removeAttribute(mapping.getAttribute());
+        return (mapping.findForward("Save Successful"));
+        
+    }
+    
+    
+    /**
+     * Append nodes for any define resources for the specified Context.
+     *
+     * @param containerNode Container node for the tree control
+     * @param containerName Object name of the parent container
+     * @param resources The MessageResources for our localized messages
+     *  messages
+     */
+    public void addToTreeControlNode(ObjectName oname, String containerName, 
+                                    String parentName, MessageResources resources, 
+                                    HttpSession session, Locale locale) 
+        throws Exception {
+                              
+        String domain = oname.getDomain();
+        TreeControl control = (TreeControl) session.getAttribute("treeControlTest");
+        if (control != null) {
+            TreeControlNode parentNode = control.findNode(parentName);
+            if (parentNode != null) {
+                String type = "Context";
+                String path = "";
+                String host = "";
+                String name = oname.getKeyProperty("name");
+                if ((name != null) && (name.length() > 0)) {
+                    name = name.substring(2);
+                    int i = name.indexOf("/");
+                    host = name.substring(0,i);
+                    path = name.substring(i); 
+                }
+                String nodeLabel = 
+                    resources.getMessage(locale, "server.service.treeBuilder.context") + 
+                    " (" + path + ")";
+                String encodedName = URLEncoder.encode(oname.toString(),TomcatTreeBuilder.URL_ENCODING);
+                TreeControlNode childNode = 
+                    new TreeControlNode(oname.toString(),
+                                        "Context.gif",
+                                        nodeLabel,
+                                        "EditContext.do?select=" +
+                                        encodedName,
+                                        "content",
+                                        true, domain);
+                parentNode.addChild(childNode);
+        
+                // FIXME - force a redisplay
+                TreeControlNode subtree = new TreeControlNode
+                    ("Context Resource Administration " + containerName,
+                    "folder_16_pad.gif",
+                    resources.getMessage(locale, "resources.treeBuilder.subtreeNode"),
+                    null,
+                    "content",
+                    true, domain);        
+                childNode.addChild(subtree);
+                TreeControlNode datasources = new TreeControlNode
+                    ("Context Data Sources " + containerName,
+                    "Datasource.gif",
+                    resources.getMessage(locale, "resources.treeBuilder.datasources"),
+                    "resources/listDataSources.do?resourcetype=" + 
+                    URLEncoder.encode(type,TomcatTreeBuilder.URL_ENCODING) + "&path=" +
+                    URLEncoder.encode(path,TomcatTreeBuilder.URL_ENCODING) + "&host=" + 
+                    URLEncoder.encode(host,TomcatTreeBuilder.URL_ENCODING) + "&forward=" +
+                    URLEncoder.encode("DataSources List Setup",TomcatTreeBuilder.URL_ENCODING),
+                    "content",
+                    false, domain);
+                TreeControlNode mailsessions = new TreeControlNode
+                    ("Context Mail Sessions " + containerName,
+                    "Mailsession.gif",
+                    resources.getMessage(locale, "resources.treeBuilder.mailsessions"),
+                    "resources/listMailSessions.do?resourcetype=" + 
+                    URLEncoder.encode(type,TomcatTreeBuilder.URL_ENCODING) + "&path=" +
+                    URLEncoder.encode(path,TomcatTreeBuilder.URL_ENCODING) + "&host=" + 
+                    URLEncoder.encode(host,TomcatTreeBuilder.URL_ENCODING) + "&forward=" +
+                    URLEncoder.encode("MailSessions List Setup",TomcatTreeBuilder.URL_ENCODING),
+                    "content",
+                    false, domain);
+                TreeControlNode resourcelinks = new TreeControlNode
+                    ("Resource Links " + containerName,
+                    "ResourceLink.gif",
+                    resources.getMessage(locale, "resources.treeBuilder.resourcelinks"),
+                    "resources/listResourceLinks.do?resourcetype=" + 
+                    URLEncoder.encode(type,TomcatTreeBuilder.URL_ENCODING) + "&path=" +
+                    URLEncoder.encode(path,TomcatTreeBuilder.URL_ENCODING) + "&host=" + 
+                    URLEncoder.encode(host,TomcatTreeBuilder.URL_ENCODING) + "&forward=" +
+                    URLEncoder.encode("ResourceLinks List Setup",TomcatTreeBuilder.URL_ENCODING),
+                    "content",
+                    false, domain);
+                TreeControlNode envs = new TreeControlNode
+                    ("Context Environment Entries "+ containerName,
+                    "EnvironmentEntries.gif",
+                    resources.getMessage(locale ,"resources.env.entries"),
+                    "resources/listEnvEntries.do?resourcetype=" + 
+                    URLEncoder.encode(type,TomcatTreeBuilder.URL_ENCODING) + "&path=" +
+                    URLEncoder.encode(path,TomcatTreeBuilder.URL_ENCODING) + "&host=" + 
+                    URLEncoder.encode(host,TomcatTreeBuilder.URL_ENCODING) + "&forward=" +
+                    URLEncoder.encode("EnvEntries List Setup",TomcatTreeBuilder.URL_ENCODING),
+                    "content",
+                    false, domain);
+                subtree.addChild(datasources);
+                subtree.addChild(mailsessions);
+                subtree.addChild(resourcelinks);
+                subtree.addChild(envs);                    
+            } else {
+                    getServlet().log
+                        ("Cannot find parent node '" + parentName + "'");
+            } 
+        }else {
+            getServlet().log("Cannot find TreeControlNode!");
+        }                              
+    }    
+        
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/filters/SetCharacterEncodingFilter.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/filters/SetCharacterEncodingFilter.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/filters/SetCharacterEncodingFilter.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,172 @@
+/*
+ * Copyright 1999-2001,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.admin.filters;
+
+
+import java.io.IOException;
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.UnavailableException;
+
+
+/**
+ * <p>Example filter that sets the character encoding to be used in parsing the
+ * incoming request, either unconditionally or only if the client did not
+ * specify a character encoding.  Configuration of this filter is based on
+ * the following initialization parameters:</p>
+ * <ul>
+ * <li><strong>encoding</strong> - The character encoding to be configured
+ *     for this request, either conditionally or unconditionally based on
+ *     the <code>ignore</code> initialization parameter.  This parameter
+ *     is required, so there is no default.</li>
+ * <li><strong>ignore</strong> - If set to "true", any character encoding
+ *     specified by the client is ignored, and the value returned by the
+ *     <code>selectEncoding()</code> method is set.  If set to "false,
+ *     <code>selectEncoding()</code> is called <strong>only</strong> if the
+ *     client has not already specified an encoding.  By default, this
+ *     parameter is set to "true".</li>
+ * </ul>
+ *
+ * <p>Although this filter can be used unchanged, it is also easy to
+ * subclass it and make the <code>selectEncoding()</code> method more
+ * intelligent about what encoding to choose, based on characteristics of
+ * the incoming request (such as the values of the <code>Accept-Language</code>
+ * and <code>User-Agent</code> headers, or a value stashed in the current
+ * user's session.</p>
+ *
+ * @author Craig McClanahan
+ * @version $Revision: 303019 $ $Date: 2004-07-23 09:02:17 -0500 (Fri, 23 Jul 2004) $
+ */
+
+public class SetCharacterEncodingFilter implements Filter {
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The default character encoding to set for requests that pass through
+     * this filter.
+     */
+    protected String encoding = null;
+
+
+    /**
+     * The filter configuration object we are associated with.  If this value
+     * is null, this filter instance is not currently configured.
+     */
+    protected FilterConfig filterConfig = null;
+
+
+    /**
+     * Should a character encoding specified by the client be ignored?
+     */
+    protected boolean ignore = true;
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Take this filter out of service.
+     */
+    public void destroy() {
+
+        this.encoding = null;
+        this.filterConfig = null;
+
+    }
+
+
+    /**
+     * Select and set (if specified) the character encoding to be used to
+     * interpret request parameters for this request.
+     *
+     * @param request The servlet request we are processing
+     * @param result The servlet response we are creating
+     * @param chain The filter chain we are processing
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception ServletException if a servlet error occurs
+     */
+    public void doFilter(ServletRequest request, ServletResponse response,
+                         FilterChain chain)
+	throws IOException, ServletException {
+
+        // Conditionally select and set the character encoding to be used
+        if (ignore || (request.getCharacterEncoding() == null)) {
+            String encoding = selectEncoding(request);
+            if (encoding != null)
+                request.setCharacterEncoding(encoding);
+        }
+
+	// Pass control on to the next filter
+        chain.doFilter(request, response);
+
+    }
+
+
+    /**
+     * Place this filter into service.
+     *
+     * @param filterConfig The filter configuration object
+     */
+    public void init(FilterConfig filterConfig) throws ServletException {
+
+	this.filterConfig = filterConfig;
+        this.encoding = filterConfig.getInitParameter("encoding");
+        String value = filterConfig.getInitParameter("ignore");
+        if (value == null)
+            this.ignore = true;
+        else if (value.equalsIgnoreCase("true"))
+            this.ignore = true;
+        else if (value.equalsIgnoreCase("yes"))
+            this.ignore = true;
+        else
+            this.ignore = false;
+
+    }
+
+
+    // ------------------------------------------------------ Protected Methods
+
+
+    /**
+     * Select an appropriate character encoding to be used, based on the
+     * characteristics of the current request and/or filter initialization
+     * parameters.  If no character encoding should be set, return
+     * <code>null</code>.
+     * <p>
+     * The default implementation unconditionally returns the value configured
+     * by the <strong>encoding</strong> initialization parameter for this
+     * filter.
+     *
+     * @param request The servlet request we are processing
+     */
+    protected String selectEncoding(ServletRequest request) {
+
+        return (this.encoding);
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/host/AddAliasAction.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/host/AddAliasAction.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/host/AddAliasAction.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,127 @@
+/*
+ * Copyright 2001-2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.admin.host;
+
+import java.io.IOException;
+import java.util.Locale;
+import java.util.Arrays;
+import java.util.ArrayList;
+import javax.servlet.ServletException;
+import javax.management.MBeanServer;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+import org.apache.struts.action.Action;
+import org.apache.struts.action.ActionErrors;
+import org.apache.struts.action.ActionForm;
+import org.apache.struts.action.ActionForward;
+import org.apache.struts.action.ActionMapping;
+import org.apache.struts.util.MessageResources;
+import org.apache.webapp.admin.ApplicationServlet;
+import org.apache.webapp.admin.LabelValueBean;
+import org.apache.webapp.admin.Lists;
+import javax.management.ObjectName;
+
+/**
+ * The <code>Action</code> that sets up <em>Add Alias</em> transactions.
+ *
+ * @author Manveen Kaur
+ * @version $Revision: 303390 $ $Date: 2004-10-18 01:37:56 -0500 (Mon, 18 Oct 2004) $
+ */
+
+public class AddAliasAction extends Action {
+    
+    /**
+     * The MBeanServer we will be interacting with.
+     */
+    private MBeanServer mBServer = null;
+    
+    // --------------------------------------------------------- Public Methods
+    
+    /**
+     * Process the specified HTTP request, and create the corresponding HTTP
+     * response (or forward to another web component that will create it).
+     * Return an <code>ActionForward</code> instance describing where and how
+     * control should be forwarded, or <code>null</code> if the response has
+     * already been completed.
+     *
+     * @param mapping The ActionMapping used to select this instance
+     * @param actionForm The optional ActionForm bean for this request (if any)
+     * @param request The HTTP request we are processing
+     * @param response The HTTP response we are creating
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception ServletException if a servlet exception occurs
+     */
+    public ActionForward execute(ActionMapping mapping,
+    ActionForm form,
+    HttpServletRequest request,
+    HttpServletResponse response)
+    throws IOException, ServletException {
+        
+        // Acquire the resources that we need
+        HttpSession session = request.getSession();
+        Locale locale = getLocale(request);
+        MessageResources resources = getResources(request);
+        
+        // Acquire a reference to the MBeanServer containing our MBeans
+        try {
+            mBServer = ((ApplicationServlet) getServlet()).getServer();
+        } catch (Throwable t) {
+            throw new ServletException
+            ("Cannot acquire MBeanServer reference", t);
+        }
+        
+
+        // the host Name is needed to retrieve the existing aliases
+        // and add new aliases to
+        String hostName = request.getParameter("hostName");
+        // Fill in the form values for display and editing
+        AliasForm aliasFm = new AliasForm();
+        session.setAttribute("aliasForm", aliasFm);
+        
+        // retrieve all aliases
+        String operation = null;
+        try {
+            ObjectName hname = new ObjectName(hostName);
+
+            operation = "findAliases";
+            String aliases[] = 
+                (String[]) mBServer.invoke(hname, operation, null, null);
+            
+            aliasFm.setAliasVals(new ArrayList(Arrays.asList(aliases)));
+
+        } catch (Throwable t) {
+            getServlet().log
+            (resources.getMessage(locale, "users.error.invoke",
+                                  operation), t);
+            response.sendError
+                (HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
+                resources.getMessage(locale, "users.error.invoke",
+                                     operation));
+            return (null);            
+        }
+        
+        aliasFm.setAliasName("");
+        aliasFm.setHostName(hostName);
+
+        // Forward to the host display page
+        return (mapping.findForward("Alias"));
+        
+    }
+        
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/host/AddHostAction.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/host/AddHostAction.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/host/AddHostAction.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,98 @@
+/*
+ * Copyright 2001-2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.admin.host;
+
+import java.io.IOException;
+import java.util.Locale;
+import java.util.ArrayList;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+import org.apache.struts.action.Action;
+import org.apache.struts.action.ActionErrors;
+import org.apache.struts.action.ActionForm;
+import org.apache.struts.action.ActionForward;
+import org.apache.struts.action.ActionMapping;
+import org.apache.struts.util.MessageResources;
+import org.apache.webapp.admin.LabelValueBean;
+import org.apache.webapp.admin.Lists;
+
+/**
+ * The <code>Action</code> that sets up <em>Add Host</em> transactions.
+ *
+ * @author Manveen Kaur
+ * @version $Revision: 303390 $ $Date: 2004-10-18 01:37:56 -0500 (Mon, 18 Oct 2004) $
+ */
+
+public class AddHostAction extends Action {
+
+    // --------------------------------------------------------- Public Methods
+
+    /**
+     * Process the specified HTTP request, and create the corresponding HTTP
+     * response (or forward to another web component that will create it).
+     * Return an <code>ActionForward</code> instance describing where and how
+     * control should be forwarded, or <code>null</code> if the response has
+     * already been completed.
+     *
+     * @param mapping The ActionMapping used to select this instance
+     * @param actionForm The optional ActionForm bean for this request (if any)
+     * @param request The HTTP request we are processing
+     * @param response The HTTP response we are creating
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception ServletException if a servlet exception occurs
+     */
+    public ActionForward execute(ActionMapping mapping,
+    ActionForm form,
+    HttpServletRequest request,
+    HttpServletResponse response)
+    throws IOException, ServletException {
+
+        // Acquire the resources that we need
+        HttpSession session = request.getSession();
+        Locale locale = getLocale(request);
+        MessageResources resources = getResources(request);
+
+        // the service Name is needed to retrieve the engine mBean to
+        // which the new host mBean will be added.
+        String serviceName = request.getParameter("select");
+
+        // Fill in the form values for display and editing
+        HostForm hostFm = new HostForm();
+        session.setAttribute("hostForm", hostFm);
+        hostFm.setAdminAction("Create");
+        hostFm.setObjectName("");
+        hostFm.setHostName("");
+        hostFm.setServiceName(serviceName);
+        hostFm.setAppBase("");
+        hostFm.setAutoDeploy("true");
+        hostFm.setDeployXML("true");
+        hostFm.setDeployOnStartup("true");
+        hostFm.setUnpackWARs("true");   
+        hostFm.setXmlNamespaceAware("false");
+        hostFm.setXmlValidation("false");
+        hostFm.setBooleanVals(Lists.getBooleanValues());
+
+        // Forward to the host display page
+        return (mapping.findForward("Host"));
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/host/AliasForm.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/host/AliasForm.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/host/AliasForm.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,166 @@
+/*
+ * Copyright 2001,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.admin.host;
+
+import javax.servlet.http.HttpServletRequest;
+import org.apache.struts.action.ActionError;
+import org.apache.struts.action.ActionErrors;
+import org.apache.struts.action.ActionForm;
+import org.apache.struts.action.ActionMapping;
+import java.util.List;
+
+/**
+ * Form bean for the alias page.
+ *
+ * @author Manveen Kaur
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public final class AliasForm extends ActionForm {
+    
+    // ----------------------------------------------------- Instance Variables
+
+    /**
+     * The text for the hostName.
+     */
+    private String hostName = null;
+
+    /**
+     * The text for the aliasName.
+     */
+    private String aliasName = null;
+
+    /*
+     * Represent aliases as a List.
+     */    
+    private List aliasVals = null;
+   
+    // ------------------------------------------------------------- Properties
+    
+    /**
+     * Return the host name.
+     */
+    public String getHostName() {
+        
+        return this.hostName;
+        
+    }
+    
+    /**
+     * Set the host name.
+     */
+    public void setHostName(String hostName) {
+        
+        this.hostName = hostName;
+        
+    }
+
+    /**
+     * Return the alias name.
+     */
+    public String getAliasName() {
+        
+        return this.aliasName;
+        
+    }
+    
+    /**
+     * Set the alias name.
+     */
+    public void setAliasName(String aliasName) {
+        
+        this.aliasName = aliasName;
+        
+    }
+
+    /**
+     * Return the List of alias Vals.
+     */
+    public List getAliasVals() {
+        
+        return this.aliasVals;
+        
+    }
+    
+    /**
+     * Set the alias Vals.
+     */
+    public void setAliasVals(List aliasVals) {
+        
+        this.aliasVals = aliasVals;
+        
+    }
+    
+    // --------------------------------------------------------- Public Methods
+    
+    /**
+     * Reset all properties to their default values.
+     *
+     * @param mapping The mapping used to select this instance
+     * @param request The servlet request we are processing
+     */
+    public void reset(ActionMapping mapping, HttpServletRequest request) {
+        
+        this.aliasName = null;
+        this.hostName = null;
+
+    }
+    
+     /**
+     * Render this object as a String.
+     */
+    public String toString() {
+
+        StringBuffer sb = new StringBuffer("AliasForm[hostName=");
+        sb.append(hostName);
+        sb.append("]");
+        return (sb.toString());
+
+    }
+
+    /**
+     * Validate the properties that have been set from this HTTP request,
+     * and return an <code>ActionErrors</code> object that encapsulates any
+     * validation errors that have been found.  If no errors are found, return
+     * <code>null</code> or an <code>ActionErrors</code> object with no
+     * recorded error messages.
+     *
+     * @param mapping The mapping used to select this instance
+     * @param request The servlet request we are processing
+     */
+    
+    public ActionErrors validate(ActionMapping mapping,
+    HttpServletRequest request) {
+        
+        ActionErrors errors = new ActionErrors();
+        
+        String submit = request.getParameter("submit");
+        
+        // front end validation when save is clicked.
+        //if (submit != null) {
+            
+            // aliasName cannot be null
+            if ((aliasName== null) || (aliasName.length() < 1)) {
+                errors.add("aliasName", new ActionError("error.aliasName.required"));
+            }
+                        
+        //}        
+        return errors;       
+    }
+    
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/host/AliasesForm.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/host/AliasesForm.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/host/AliasesForm.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.admin.host;
+
+import javax.servlet.http.HttpServletRequest;
+import org.apache.struts.action.ActionForm;
+import org.apache.struts.action.ActionMapping;
+
+
+/**
+ * Form bean for deleting aliases.
+ *
+ * @author Manveen Kaur
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class AliasesForm extends ActionForm {
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * The object names of the aliases to be deleted.
+     */
+    private String aliases[] = new String[0];
+
+    public String[] getAliases() {
+        return (this.aliases);
+    }
+
+    public void setAliases(String aliases[]) {
+        this.aliases = aliases;
+    }
+
+    /**
+     * The text for the hostName.
+     */
+    private String hostName = null;
+
+    /**
+     * Return the host name.
+     */
+    public String getHostName() {
+        
+        return this.hostName;
+        
+    }
+    
+    /**
+     * Set the host name.
+     */
+    public void setHostName(String hostName) {
+        
+        this.hostName = hostName;
+        
+    }
+    
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Reset all properties to their default values.
+     *
+     * @param mapping The mapping used to select this instance
+     * @param request The servlet request we are processing
+     */
+    public void reset(ActionMapping mapping, HttpServletRequest request) {
+
+        this.aliases = new String[0];
+        this.hostName = null;        
+    }
+        
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/host/DeleteAliasAction.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/host/DeleteAliasAction.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/host/DeleteAliasAction.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,143 @@
+/*
+ * Copyright 2001-2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.admin.host;
+
+import java.io.IOException;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Arrays;
+import java.util.Locale;
+import java.util.TreeSet;
+import java.util.Set;
+import java.util.ArrayList;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+import org.apache.struts.action.Action;
+import org.apache.struts.action.ActionErrors;
+import org.apache.struts.action.ActionForm;
+import org.apache.struts.action.ActionForward;
+import org.apache.struts.action.ActionMapping;
+
+import javax.management.MBeanServer;
+import javax.management.MBeanServerFactory;
+import javax.management.QueryExp;
+import javax.management.Query;
+import javax.management.ObjectInstance;
+import javax.management.ObjectName;
+import javax.management.JMException;
+import org.apache.struts.util.MessageResources;
+
+import org.apache.webapp.admin.ApplicationServlet;
+import org.apache.webapp.admin.TomcatTreeBuilder;
+
+/**
+ * The <code>Action</code> that sets up <em>Delete Aliases</em> transactions.
+ *
+ * @author Manveen Kaur
+ * @version $Revision: 303390 $ $Date: 2004-10-18 01:37:56 -0500 (Mon, 18 Oct 2004) $
+ */
+
+public class DeleteAliasAction extends Action {
+    
+
+    /**
+     * The MBeanServer we will be interacting with.
+     */
+    private MBeanServer mBServer = null;
+    
+
+    // --------------------------------------------------------- Public Methods
+    
+    /**
+     * Process the specified HTTP request, and create the corresponding HTTP
+     * response (or forward to another web component that will create it).
+     * Return an <code>ActionForward</code> instance describing where and how
+     * control should be forwarded, or <code>null</code> if the response has
+     * already been completed.
+     *
+     * @param mapping The ActionMapping used to select this instance
+     * @param actionForm The optional ActionForm bean for this request (if any)
+     * @param request The HTTP request we are processing
+     * @param response The HTTP response we are creating
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception ServletException if a servlet exception occurs
+     */
+    public ActionForward execute(ActionMapping mapping,
+                                 ActionForm form,
+                                 HttpServletRequest request,
+                                 HttpServletResponse response)
+        throws IOException, ServletException {
+        
+
+        // Acquire the resources that we need
+        HttpSession session = request.getSession();
+        Locale locale = getLocale(request);
+        MessageResources resources = getResources(request);
+        
+        // Acquire a reference to the MBeanServer containing our MBeans
+        try {
+            mBServer = ((ApplicationServlet) getServlet()).getServer();
+        } catch (Throwable t) {
+            throw new ServletException
+            ("Cannot acquire MBeanServer reference", t);
+        }
+        
+        // Set up a form bean containing the currently selected
+        // objects to be deleted
+        AliasesForm aliasesFm = new AliasesForm();
+        ArrayList aliasesList = null;
+        
+        String hostName = request.getParameter("hostName");
+        aliasesFm.setHostName(hostName);
+        
+        // retrieve all aliases
+        String operation = null;
+        try {
+            ObjectName hname = new ObjectName(hostName);
+
+            operation = "findAliases";
+            String aliases[] = 
+                (String[]) mBServer.invoke(hname, operation, null, null);
+            aliasesFm.setAliases(aliases);
+            aliasesList = new ArrayList(Arrays.asList(aliases));
+
+        } catch (Throwable t) {
+            getServlet().log
+            (resources.getMessage(locale, "users.error.invoke",
+                                  operation), t);
+            response.sendError
+                (HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
+                resources.getMessage(locale, "users.error.invoke",
+                                     operation));
+            return (null);            
+        }
+                
+        Collections.sort(aliasesList);        
+        request.setAttribute("aliasesForm", aliasesFm);        
+        request.setAttribute("aliasesList", aliasesList);
+        
+        // Forward to the list display page
+        return (mapping.findForward("Aliases"));
+
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/host/DeleteAliasForm.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/host/DeleteAliasForm.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/host/DeleteAliasForm.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.admin.host;
+
+import javax.servlet.http.HttpServletRequest;
+import org.apache.struts.action.ActionForm;
+import org.apache.struts.action.ActionMapping;
+
+/**
+ * Form bean for the "Delete Alias" page.
+ *
+ * @author Manveen Kaur
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class DeleteAliasForm extends ActionForm {
+    
+  // No extensions needed
+    
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/host/DeleteAliasesAction.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/host/DeleteAliasesAction.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/host/DeleteAliasesAction.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,141 @@
+/*
+ * Copyright 2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.admin.host;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.Locale;
+import java.util.Set;
+import java.util.TreeSet;
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+import javax.management.ObjectInstance;
+import javax.management.modelmbean.ModelMBean;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpSession;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import org.apache.struts.action.Action;
+import org.apache.struts.action.ActionForm;
+import org.apache.struts.action.ActionForward;
+import org.apache.struts.action.ActionMapping;
+import org.apache.struts.util.MessageResources;
+
+import org.apache.webapp.admin.ApplicationServlet;
+
+/**
+ * The <code>Action</code> that completes <em>Delete Aliases</em>
+ * transactions.
+ *
+ * @author Manveen Kaur
+ * @version $Revision: 303390 $ $Date: 2004-10-18 01:37:56 -0500 (Mon, 18 Oct 2004) $
+ */
+
+public class DeleteAliasesAction extends Action {
+
+
+    /**
+     * Signature for the <code>removeAlias</code> operation.
+     */
+    private String removeAliasTypes[] =
+    { "java.lang.String",      // Object name
+    };
+
+
+    /**
+     * The MBeanServer we will be interacting with.
+     */
+    private MBeanServer mBServer = null;
+    
+
+    // --------------------------------------------------------- Public Methods
+    
+    
+    /**
+     * Process the specified HTTP request, and create the corresponding HTTP
+     * response (or forward to another web component that will create it).
+     * Return an <code>ActionForward</code> instance describing where and how
+     * control should be forwarded, or <code>null</code> if the response has
+     * already been completed.
+     *
+     * @param mapping The ActionMapping used to select this instance
+     * @param actionForm The optional ActionForm bean for this request (if any)
+     * @param request The HTTP request we are processing
+     * @param response The HTTP response we are creating
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception ServletException if a servlet exception occurs
+     */
+    public ActionForward execute(ActionMapping mapping,
+                                 ActionForm form,
+                                 HttpServletRequest request,
+                                 HttpServletResponse response)
+        throws IOException, ServletException {
+        
+        
+        // Look up the components we will be using as needed
+        HttpSession session = request.getSession();
+        Locale locale = getLocale(request);
+        MessageResources resources = getResources(request);
+
+        // Acquire a reference to the MBeanServer containing our MBeans
+        try {
+            mBServer = ((ApplicationServlet) getServlet()).getServer();
+        } catch (Throwable t) {
+            throw new ServletException
+            ("Cannot acquire MBeanServer reference", t);
+        }
+        
+        AliasesForm aliasesFm = (AliasesForm) form;
+        // the host Name is needed to delete the existing aliases from
+        String hostName = aliasesFm.getHostName();
+        
+        // Delete the specified Aliases
+        String aliases[]  = aliasesFm.getAliases();
+        String values[] = new String[1];
+        String operation = "removeAlias";
+
+        try {
+            
+            ObjectName hname = new ObjectName(hostName);
+
+            // Remove the specified hosts
+            for (int i = 0; i < aliases.length; i++) {
+                values[0] = aliases[i];         
+                mBServer.invoke(hname, operation, values, removeAliasTypes);
+            }
+
+        } catch (Exception e) {
+            getServlet().log
+                (resources.getMessage(locale, "users.error.invoke",
+                                      operation), e);
+            response.sendError
+                (HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
+                 resources.getMessage(locale, "users.error.invoke",
+                                      operation));
+            return (null);
+
+        }
+
+        // Report successful completion of this transaction
+        return (mapping.findForward("Save Successful"));
+
+    }
+    
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/host/DeleteHostAction.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/host/DeleteHostAction.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/host/DeleteHostAction.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,164 @@
+/*
+ * Copyright 2001-2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.admin.host;
+
+import java.io.IOException;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Locale;
+import java.util.TreeSet;
+import java.util.Set;
+import java.util.ArrayList;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+import org.apache.struts.action.Action;
+import org.apache.struts.action.ActionErrors;
+import org.apache.struts.action.ActionForm;
+import org.apache.struts.action.ActionForward;
+import org.apache.struts.action.ActionMapping;
+
+import javax.management.MBeanServer;
+import javax.management.MBeanServerFactory;
+import javax.management.QueryExp;
+import javax.management.Query;
+import javax.management.ObjectInstance;
+import javax.management.ObjectName;
+import javax.management.JMException;
+import org.apache.struts.util.MessageResources;
+
+import org.apache.webapp.admin.ApplicationServlet;
+import org.apache.webapp.admin.Lists;
+import org.apache.webapp.admin.TomcatTreeBuilder;
+
+/**
+ * The <code>Action</code> that sets up <em>Delete Hosts</em> transactions.
+ *
+ * @author Manveen Kaur
+ * @version $Revision: 303390 $ $Date: 2004-10-18 01:37:56 -0500 (Mon, 18 Oct 2004) $
+ */
+
+public class DeleteHostAction extends Action {
+    
+
+    /**
+     * The MBeanServer we will be interacting with.
+     */
+    private MBeanServer mBServer = null;
+    
+
+    // --------------------------------------------------------- Public Methods
+    
+    /**
+     * Process the specified HTTP request, and create the corresponding HTTP
+     * response (or forward to another web component that will create it).
+     * Return an <code>ActionForward</code> instance describing where and how
+     * control should be forwarded, or <code>null</code> if the response has
+     * already been completed.
+     *
+     * @param mapping The ActionMapping used to select this instance
+     * @param actionForm The optional ActionForm bean for this request (if any)
+     * @param request The HTTP request we are processing
+     * @param response The HTTP response we are creating
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception ServletException if a servlet exception occurs
+     */
+    public ActionForward execute(ActionMapping mapping,
+                                 ActionForm form,
+                                 HttpServletRequest request,
+                                 HttpServletResponse response)
+        throws IOException, ServletException {
+        
+
+        // Acquire the resources that we need
+        HttpSession session = request.getSession();
+        Locale locale = getLocale(request);
+        MessageResources resources = getResources(request);
+        
+        // Acquire a reference to the MBeanServer containing our MBeans
+        try {
+            mBServer = ((ApplicationServlet) getServlet()).getServer();
+        } catch (Throwable t) {
+            throw new ServletException
+            ("Cannot acquire MBeanServer reference", t);
+        }
+        
+        // Set up a form bean containing the currently selected
+        // objects to be deleted
+        HostsForm hostsForm = new HostsForm();
+        String select = request.getParameter("select");
+        String domain = null;
+        if (select != null) {
+            String hosts[] = new String[1];
+            hosts[0] = select;
+            hostsForm.setHosts(hosts);
+                        
+            try {
+                domain = (new ObjectName(select)).getDomain();
+            } catch (Exception e) {
+                throw new ServletException
+                ("Error extracting service name from the host to be deleted", e);
+            }        
+        }
+        String adminHost = null;
+        // Get the host name the admin app runs on
+        // this host cannot be deleted from the admin tool
+        try {
+            adminHost = Lists.getAdminAppHost(
+                                  mBServer, "domain" ,request);
+        } catch (Exception e) {
+            String message =
+                resources.getMessage(locale, "error.hostName.bad",
+                                        adminHost);
+            getServlet().log(message);
+            response.sendError(HttpServletResponse.SC_BAD_REQUEST, message);
+            return (null);
+        }
+        request.setAttribute("adminAppHost", adminHost);       
+        request.setAttribute("hostsForm", hostsForm);
+        
+        // Accumulate a list of all available hosts
+        ArrayList list = new ArrayList();
+        try {
+            String pattern = domain + TomcatTreeBuilder.HOST_TYPE +
+                TomcatTreeBuilder.WILDCARD;         
+            Iterator items =
+                mBServer.queryNames(new ObjectName(pattern), null).iterator();
+            while (items.hasNext()) {
+                list.add(items.next().toString());
+            }
+        } catch (Exception e) {
+            getServlet().log
+                (resources.getMessage(locale, "users.error.select"));
+            response.sendError
+                (HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
+                 resources.getMessage(locale, "users.error.select"));
+            return (null);
+        }
+        Collections.sort(list);
+        request.setAttribute("hostsList", list);
+        
+        // Forward to the list display page
+        return (mapping.findForward("Hosts"));
+
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/host/DeleteHostsAction.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/host/DeleteHostsAction.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/host/DeleteHostsAction.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,161 @@
+/*
+ * Copyright 2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.admin.host;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.Locale;
+import java.util.Set;
+import java.util.TreeSet;
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+import javax.management.ObjectInstance;
+import javax.management.modelmbean.ModelMBean;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpSession;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import org.apache.struts.action.Action;
+import org.apache.struts.action.ActionForm;
+import org.apache.struts.action.ActionForward;
+import org.apache.struts.action.ActionMapping;
+import org.apache.struts.util.MessageResources;
+
+import org.apache.webapp.admin.ApplicationServlet;
+import org.apache.webapp.admin.TomcatTreeBuilder;
+import org.apache.webapp.admin.TreeControl;
+import org.apache.webapp.admin.TreeControlNode;
+
+
+/**
+ * The <code>Action</code> that completes <em>Delete Hosts</em>
+ * transactions.
+ *
+ * @author Manveen Kaur
+ * @version $Revision: 303664 $ $Date: 2005-01-29 13:36:06 -0600 (Sat, 29 Jan 2005) $
+ */
+
+public class DeleteHostsAction extends Action {
+
+
+    /**
+     * Signature for the <code>removeHost</code> operation.
+     */
+    private String removeHostTypes[] =
+    { "java.lang.String",      // Object name
+    };
+
+
+    /**
+     * The MBeanServer we will be interacting with.
+     */
+    private MBeanServer mBServer = null;
+    
+
+    // --------------------------------------------------------- Public Methods
+    
+    
+    /**
+     * Process the specified HTTP request, and create the corresponding HTTP
+     * response (or forward to another web component that will create it).
+     * Return an <code>ActionForward</code> instance describing where and how
+     * control should be forwarded, or <code>null</code> if the response has
+     * already been completed.
+     *
+     * @param mapping The ActionMapping used to select this instance
+     * @param actionForm The optional ActionForm bean for this request (if any)
+     * @param request The HTTP request we are processing
+     * @param response The HTTP response we are creating
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception ServletException if a servlet exception occurs
+     */
+    public ActionForward execute(ActionMapping mapping,
+                                 ActionForm form,
+                                 HttpServletRequest request,
+                                 HttpServletResponse response)
+        throws IOException, ServletException {
+        
+        
+        // Look up the components we will be using as needed
+        HttpSession session = request.getSession();
+        Locale locale = getLocale(request);
+        MessageResources resources = getResources(request);
+
+        // Acquire a reference to the MBeanServer containing our MBeans
+        try {
+            mBServer = ((ApplicationServlet) getServlet()).getServer();
+        } catch (Throwable t) {
+            throw new ServletException
+            ("Cannot acquire MBeanServer reference", t);
+        }
+               
+        // Delete the specified Hosts
+        String hosts[]  = ((HostsForm) form).getHosts();
+        String values[] = new String[1];
+        String operation = "removeHost";
+        
+        getServlet().log("enter DeleteHosts " + hosts);
+
+        try {
+
+            // Look up our tree control data structure
+            TreeControl control = (TreeControl)
+                session.getAttribute("treeControlTest");
+
+            // Remove the specified hosts
+            for (int i = 0; i < hosts.length; i++) {
+                values[0] = hosts[i];
+                getServlet().log("remove host " + hosts[i]);
+                if (control != null) {
+                    control.selectNode(null);
+                    TreeControlNode node = control.findNode(hosts[i]);
+                    String domain = node.getDomain();
+                    ObjectName fname = TomcatTreeBuilder.getMBeanFactory();
+                    mBServer.invoke(fname, operation,
+                                values, removeHostTypes);
+                    if (node != null) {
+                        node.remove();
+                    } else {
+                        getServlet().log("Missing TreeControlNode for " +
+                                         hosts[i]);
+                    }
+                } else {
+                    getServlet().log("Missing TreeControl attribute");
+                }
+            }
+
+        } catch (Exception e) {
+            getServlet().log
+                (resources.getMessage(locale, "users.error.invoke",
+                                      operation), e);
+            response.sendError
+                (HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
+                 resources.getMessage(locale, "users.error.invoke",
+                                      operation));
+            return (null);
+
+        }
+
+        // Report successful completion of this transaction
+        return (mapping.findForward("Save Successful"));
+
+    }
+    
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/host/EditHostAction.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/host/EditHostAction.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/host/EditHostAction.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,206 @@
+/*
+ * Copyright 2001-2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.admin.host;
+
+import java.io.IOException;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Locale;
+import java.util.Arrays;
+import java.util.ArrayList;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+import org.apache.struts.action.Action;
+import org.apache.struts.action.ActionErrors;
+import org.apache.struts.action.ActionForm;
+import org.apache.struts.action.ActionForward;
+import org.apache.struts.action.ActionMapping;
+import org.apache.struts.util.MessageResources;
+
+import javax.management.MBeanServer;
+import javax.management.ObjectInstance;
+import javax.management.ObjectName;
+import javax.management.JMException;
+
+import org.apache.webapp.admin.ApplicationServlet;
+import org.apache.webapp.admin.LabelValueBean;
+import org.apache.webapp.admin.Lists;
+import org.apache.webapp.admin.TomcatTreeBuilder;
+
+/**
+ * The <code>Action</code> that sets up <em>Edit Host</em> transactions.
+ *
+ * @author Manveen Kaur
+ * @version $Revision: 303390 $ $Date: 2004-10-18 01:37:56 -0500 (Mon, 18 Oct 2004) $
+ */
+
+public class EditHostAction extends Action {
+
+    /**
+     * The MBeanServer we will be interacting with.
+     */
+    private MBeanServer mBServer = null;
+
+
+    // --------------------------------------------------------- Public Methods
+
+    /**
+     * Process the specified HTTP request, and create the corresponding HTTP
+     * response (or forward to another web component that will create it).
+     * Return an <code>ActionForward</code> instance describing where and how
+     * control should be forwarded, or <code>null</code> if the response has
+     * already been completed.
+     *
+     * @param mapping The ActionMapping used to select this instance
+     * @param actionForm The optional ActionForm bean for this request (if any)
+     * @param request The HTTP request we are processing
+     * @param response The HTTP response we are creating
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception ServletException if a servlet exception occurs
+     */
+    public ActionForward execute(ActionMapping mapping,
+                                 ActionForm form,
+                                 HttpServletRequest request,
+                                 HttpServletResponse response)
+        throws IOException, ServletException {
+
+        // Acquire the resources that we need
+        HttpSession session = request.getSession();
+        Locale locale = getLocale(request);
+        MessageResources resources = getResources(request);
+
+        // Acquire a reference to the MBeanServer containing our MBeans
+        try {
+            mBServer = ((ApplicationServlet) getServlet()).getServer();
+        } catch (Throwable t) {
+            throw new ServletException
+            ("Cannot acquire MBeanServer reference", t);
+        }
+
+        // Set up the object names of the MBeans we are manipulating
+        ObjectName hname = null;
+        StringBuffer sb = null;
+        try {
+            hname = new ObjectName(request.getParameter("select"));
+        } catch (Exception e) {
+            String message =
+                resources.getMessage(locale, "error.hostName.bad",
+                                     request.getParameter("select"));
+            getServlet().log(message);
+            response.sendError(HttpServletResponse.SC_BAD_REQUEST, message);
+            return (null);
+        }
+        
+        String adminHost = null;
+        String domain = hname.getDomain();
+        // Get the host name the admin app runs on
+        // this host cannot be deleted from the admin tool
+        try {
+            adminHost = Lists.getAdminAppHost(
+                                  mBServer, domain ,request);
+        } catch (Exception e) {
+            String message =
+                resources.getMessage(locale, "error.hostName.bad",
+                                        adminHost);
+            getServlet().log(message);
+            response.sendError(HttpServletResponse.SC_BAD_REQUEST, message);
+            return (null);
+        }
+        request.setAttribute("adminAppHost", adminHost);
+
+        // Fill in the form values for display and editing
+        HostForm hostFm = new HostForm();
+        session.setAttribute("hostForm", hostFm);
+        hostFm.setAdminAction("Edit");
+        hostFm.setObjectName(hname.toString());
+        sb = new StringBuffer();
+        sb.append(resources.getMessage(locale, "server.service.treeBuilder.host"));
+        sb.append(" (");
+        sb.append(hname.getKeyProperty("host"));
+        sb.append(")");
+        hostFm.setNodeLabel(sb.toString());
+        hostFm.setBooleanVals(Lists.getBooleanValues());
+
+        String attribute = null;
+        try {
+
+            // Copy scalar properties
+            attribute = "name";
+            hostFm.setHostName
+                ((String) mBServer.getAttribute(hname, attribute));
+
+            attribute = "appBase";
+            hostFm.setAppBase
+                ((String) mBServer.getAttribute(hname, attribute));
+            attribute = "autoDeploy";
+            hostFm.setAutoDeploy
+                (((Boolean) mBServer.getAttribute(hname, attribute)).toString());
+            attribute = "deployXML";
+            hostFm.setDeployXML
+                (((Boolean) mBServer.getAttribute(hname, attribute)).toString());
+            attribute = "deployOnStartup";
+            hostFm.setDeployOnStartup
+                (((Boolean) mBServer.getAttribute(hname, attribute)).toString());                
+            attribute = "unpackWARs";
+            hostFm.setUnpackWARs
+                (((Boolean) mBServer.getAttribute(hname, attribute)).toString());
+            attribute = "xmlNamespaceAware";
+            hostFm.setXmlNamespaceAware
+                (((Boolean) mBServer.getAttribute(hname, attribute)).toString());
+            attribute = "xmlValidation";
+            hostFm.setXmlValidation
+                (((Boolean) mBServer.getAttribute(hname, attribute)).toString());
+
+        } catch (Throwable t) {
+            getServlet().log
+                (resources.getMessage(locale, "users.error.attribute.get",
+                                      attribute), t);
+            response.sendError
+                (HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
+                 resources.getMessage(locale, "users.error.attribute.get",
+                                      attribute));
+            return (null);
+        }
+
+        // retrieve all aliases
+        String operation = null;
+        try {
+            operation = "findAliases";
+            String aliases[] =
+                (String[]) mBServer.invoke(hname, operation, null, null);
+
+            hostFm.setAliasVals(new ArrayList(Arrays.asList(aliases)));
+
+        } catch (Throwable t) {
+            getServlet().log
+            (resources.getMessage(locale, "users.error.invoke",
+                                  operation), t);
+            response.sendError
+                (HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
+                resources.getMessage(locale, "users.error.invoke",
+                                     operation));
+            return (null);
+        }
+
+        // Forward to the host display page
+        return (mapping.findForward("Host"));
+
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/host/HostForm.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/host/HostForm.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/host/HostForm.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,464 @@
+/*
+ * Copyright 2001,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.admin.host;
+
+import javax.servlet.http.HttpServletRequest;
+import org.apache.struts.action.ActionError;
+import org.apache.struts.action.ActionErrors;
+import org.apache.struts.action.ActionForm;
+import org.apache.struts.action.ActionMapping;
+import java.util.List;
+
+/**
+ * Form bean for the host page.
+ *
+ * @author Manveen Kaur
+ * @version $Revision: 302986 $ $Date: 2004-06-27 21:14:52 -0500 (Sun, 27 Jun 2004) $
+ */
+
+public final class HostForm extends ActionForm {
+
+    // ----------------------------------------------------- Instance Variables
+
+    /**
+     * The administrative action represented by this form.
+     */
+    private String adminAction = "Edit";
+
+    /**
+     * The object name of this Host bean refers to.
+     */
+    private String objectName = null;
+
+    /**
+     * The text for the node label. This is of the form 'Host(name)'
+     * and is picked up from the node of the tree that is clicked on.
+     */
+    private String nodeLabel = null;
+
+    /**
+     * The text for the hostName.
+     */
+    private String hostName = null;
+
+    /**
+     * The object name of the service this host belongs to.
+     */
+    private String serviceName = null;
+
+    /**
+     * The directory for the appBase.
+     */
+    private String appBase = null;
+
+    /**
+     * Boolean for autoDeploy.
+     */
+    private String autoDeploy = "true";
+
+    /**
+     * Boolean for deployXML.
+     */
+    private String deployXML = "true";
+
+    /**
+     * Boolean for deployOnStartup.
+     */
+    private String deployOnStartup = "true";
+    
+    /**
+     * Boolean for unpack WARs.
+     */
+    private String unpackWARs = "false";
+
+    /**
+     * The text for the port. -- TBD
+     */
+    private String findAliases = null;
+
+    /*
+     * Represent boolean (true, false) values for unpackWARs etc.
+     */
+    private List booleanVals = null;
+
+    /*
+     * Represent aliases as a List.
+     */
+    private List aliasVals = null;
+
+    /**
+     * Boolean for xmlNamespaceAware.
+     */
+    private String xmlNamespaceAware = "false";
+
+    /**
+     * Boolean for xmlValidation.
+     */
+    private String xmlValidation = "false";
+
+    // ------------------------------------------------------------- Properties
+
+    /**
+     * Return the administrative action represented by this form.
+     */
+    public String getAdminAction() {
+
+        return this.adminAction;
+
+    }
+
+
+    /**
+     * Set the administrative action represented by this form.
+     */
+    public void setAdminAction(String adminAction) {
+
+        this.adminAction = adminAction;
+
+    }
+
+    /**
+     * Return the object name of the Host this bean refers to.
+     */
+    public String getObjectName() {
+
+        return this.objectName;
+
+    }
+
+
+    /**
+     * Set the object name of the Host this bean refers to.
+     */
+    public void setObjectName(String objectName) {
+
+        this.objectName = objectName;
+
+    }
+    
+
+    /**
+     * Return the object name of the service this host belongs to.
+     */
+    public String getServiceName() {
+
+        return this.serviceName;
+
+    }
+
+
+    /**
+     * Set the object name of the Service this host belongs to.
+     */
+    public void setServiceName(String serviceName) {
+
+        this.serviceName = serviceName;
+
+    }
+
+    /**
+     * Return the label of the node that was clicked.
+     */
+    public String getNodeLabel() {
+
+        return this.nodeLabel;
+
+    }
+
+    /**
+     * Set the node label.
+     */
+    public void setNodeLabel(String nodeLabel) {
+
+        this.nodeLabel = nodeLabel;
+
+    }
+
+    /**
+     * Return the host name.
+     */
+    public String getHostName() {
+
+        return this.hostName;
+
+    }
+
+    /**
+     * Set the host name.
+     */
+    public void setHostName(String hostName) {
+
+        this.hostName = hostName;
+
+    }
+
+    /**
+     * Return the appBase.
+     */
+    public String getAppBase() {
+
+        return this.appBase;
+
+    }
+    
+    /**
+     * Return the autoDeploy.
+     */
+    public String getAutoDeploy() {
+        
+        return this.autoDeploy;
+        
+    }
+    
+    /**
+     * Set the autoDeploy.
+     */
+    
+    public void setAutoDeploy(String autoDeploy) {
+        
+        this.autoDeploy = autoDeploy;
+        
+    }
+
+    /**
+     * Return the deployXML.
+     */
+    public String getDeployXML() {
+        
+        return this.deployXML;
+        
+    }
+    
+    /**
+     * Set the deployXML.
+     */
+    
+    public void setDeployXML(String deployXML) {
+        
+        this.deployXML = deployXML;
+        
+    }
+
+    /**
+     * Return the deployOnStartup.
+     */
+    public String getDeployOnStartup() {
+        
+        return this.deployOnStartup;
+        
+    }
+    
+    /**
+     * Set the deployOnStartup.
+     */
+    
+    public void setDeployOnStartup(String deployOnStartup) {
+        
+        this.deployOnStartup = deployOnStartup;
+        
+    }
+
+    /**
+     * Set the appBase.
+     */
+
+    public void setAppBase(String appBase) {
+
+        this.appBase = appBase;
+
+    }
+
+    /**
+     * Return the unpackWARs.
+     */
+    public String getUnpackWARs() {
+
+        return this.unpackWARs;
+
+    }
+
+    /**
+     * Set the unpackWARs.
+     */
+
+    public void setUnpackWARs(String unpackWARs) {
+
+        this.unpackWARs = unpackWARs;
+
+    }
+
+    /**
+     * Return the booleanVals.
+     */
+    public List getBooleanVals() {
+
+        return this.booleanVals;
+
+    }
+
+    /**
+     * Set the booleanVals.
+     */
+    public void setBooleanVals(List booleanVals) {
+
+        this.booleanVals = booleanVals;
+
+    }
+
+    /**
+     * Return the List of alias Vals.
+     */
+    public List getAliasVals() {
+
+        return this.aliasVals;
+
+    }
+
+    /**
+     * Set the alias Vals.
+     */
+    public void setAliasVals(List aliasVals) {
+
+        this.aliasVals = aliasVals;
+
+    }
+
+    /**
+     * Return the xmlNamespaceAware.
+     */
+    public String getXmlNamespaceAware() {
+
+        return this.xmlNamespaceAware;
+
+    }
+
+    /**
+     * Set the xmlNamespaceAware.
+     */
+
+    public void setXmlNamespaceAware(String xmlNamespaceAware) {
+
+        this.xmlNamespaceAware = xmlNamespaceAware;
+
+    }
+
+    /**
+     * Return the xmlValidation.
+     */
+    public String getXmlValidation() {
+
+        return this.xmlValidation;
+
+    }
+
+    /**
+     * Set the xmlValidation.
+     */
+
+    public void setXmlValidation(String xmlValidation) {
+
+        this.xmlValidation = xmlValidation;
+
+    }
+
+    // --------------------------------------------------------- Public Methods
+
+    /**
+     * Reset all properties to their default values.
+     *
+     * @param mapping The mapping used to select this instance
+     * @param request The servlet request we are processing
+     */
+    public void reset(ActionMapping mapping, HttpServletRequest request) {
+
+        this.objectName = null;        
+        this.serviceName = null;
+        this.hostName = null;
+        this.appBase = null;
+        this.autoDeploy = "true";
+        this.deployXML = "true";
+        this.deployOnStartup = "true";
+        this.unpackWARs = "true";
+
+    }
+
+     /**
+     * Render this object as a String.
+     */
+    public String toString() {
+
+        StringBuffer sb = new StringBuffer("HostForm[adminAction=");
+        sb.append(adminAction);
+        sb.append(",appBase=");
+        sb.append(appBase);
+        sb.append(",autoDeploy=");
+        sb.append(autoDeploy);
+        sb.append(",deployXML=");
+        sb.append(deployXML);
+        sb.append(",deployOnStartup=");
+        sb.append(deployOnStartup);
+        sb.append(",unpackWARs=");
+        sb.append(unpackWARs);
+        sb.append("',objectName='");
+        sb.append(objectName);
+        sb.append("',hostName=");
+        sb.append(hostName);
+        sb.append("',serviceName=");
+        sb.append(serviceName);
+        sb.append("]");
+        return (sb.toString());
+
+    }
+
+    /**
+     * Validate the properties that have been set from this HTTP request,
+     * and return an <code>ActionErrors</code> object that encapsulates any
+     * validation errors that have been found.  If no errors are found, return
+     * <code>null</code> or an <code>ActionErrors</code> object with no
+     * recorded error messages.
+     *
+     * @param mapping The mapping used to select this instance
+     * @param request The servlet request we are processing
+     */
+
+    public ActionErrors validate(ActionMapping mapping,
+    HttpServletRequest request) {
+
+        ActionErrors errors = new ActionErrors();
+
+        String submit = request.getParameter("submit");
+
+        // front end validation when save is clicked.
+        //if (submit != null) {
+
+            // hostName cannot be null
+            if ((hostName== null) || (hostName.length() < 1)) {
+                errors.add("hostName", new ActionError("error.hostName.required"));
+            }
+
+            // appBase cannot be null
+            if ((appBase == null) || (appBase.length() < 1)) {
+                errors.add("appBase", new ActionError("error.appBase.required"));
+            }
+
+        //}
+        return errors;
+
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/host/HostsForm.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/host/HostsForm.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/host/HostsForm.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.admin.host;
+
+
+import javax.servlet.http.HttpServletRequest;
+import org.apache.struts.action.ActionForm;
+import org.apache.struts.action.ActionMapping;
+
+
+/**
+ * Form bean for deleting hosts.
+ *
+ * @author Manveen Kaur
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class HostsForm extends ActionForm {
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * The object names of the hosts to be deleted.
+     */
+    private String hosts[] = new String[0];
+
+    public String[] getHosts() {
+        return (this.hosts);
+    }
+
+    public void setHosts(String hosts[]) {
+        this.hosts = hosts;
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Reset all properties to their default values.
+     *
+     * @param mapping The mapping used to select this instance
+     * @param request The servlet request we are processing
+     */
+    public void reset(ActionMapping mapping, HttpServletRequest request) {
+
+        this.hosts = new String[0];
+
+    }
+        
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/host/SaveAliasAction.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/host/SaveAliasAction.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/host/SaveAliasAction.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,157 @@
+/*
+ * Copyright 2001-2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.admin.host;
+
+import java.net.URLEncoder;
+import java.util.Iterator;
+import java.util.Locale;
+import java.util.List;
+import java.io.IOException;
+import javax.management.Attribute;
+import javax.management.MBeanServer;
+import javax.management.MBeanServerFactory;
+import javax.management.QueryExp;
+import javax.management.Query;
+import javax.management.ObjectInstance;
+import javax.management.ObjectName;
+import javax.management.JMException;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+import org.apache.struts.action.Action;
+import org.apache.struts.action.ActionError;
+import org.apache.struts.action.ActionErrors;
+import org.apache.struts.action.ActionForm;
+import org.apache.struts.action.ActionForward;
+import org.apache.struts.action.ActionMapping;
+import org.apache.struts.util.MessageResources;
+import org.apache.webapp.admin.ApplicationServlet;
+import org.apache.webapp.admin.TomcatTreeBuilder;
+import org.apache.webapp.admin.TreeControl;
+import org.apache.webapp.admin.TreeControlNode;
+
+
+
+/**
+ * The <code>Action</code> that completes <em>Add Alias</em> and
+ * <em>Edit Alias</em> transactions.
+ *
+ * @author Manveen Kaur
+ * @version $Revision: 303390 $ $Date: 2004-10-18 01:37:56 -0500 (Mon, 18 Oct 2004) $
+ */
+
+public final class SaveAliasAction extends Action {
+
+
+    // ----------------------------------------------------- Instance Variables
+
+    /**
+     * Signature for the <code>createStandardAlias</code> operation.
+     */
+    private String createStandardAliasTypes[] =
+    { "java.lang.String",     // host
+    };
+
+    /**
+     * The MBeanServer we will be interacting with.
+     */
+    private MBeanServer mBServer = null;
+    
+
+    // --------------------------------------------------------- Public Methods
+    
+    
+    /**
+     * Process the specified HTTP request, and create the corresponding HTTP
+     * response (or forward to another web component that will create it).
+     * Return an <code>ActionForward</code> instance describing where and how
+     * control should be forwarded, or <code>null</code> if the response has
+     * already been completed.
+     *
+     * @param mapping The ActionMapping used to select this instance
+     * @param actionForm The optional ActionForm bean for this request (if any)
+     * @param request The HTTP request we are processing
+     * @param response The HTTP response we are creating
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception ServletException if a servlet exception occurs
+     */
+    public ActionForward execute(ActionMapping mapping,
+                                 ActionForm form,
+                                 HttpServletRequest request,
+                                 HttpServletResponse response)
+        throws IOException, ServletException {
+        
+        // Acquire the resources that we need
+        HttpSession session = request.getSession();
+        Locale locale = getLocale(request);
+        MessageResources resources = getResources(request);
+        
+        // Acquire a reference to the MBeanServer containing our MBeans
+        try {
+            mBServer = ((ApplicationServlet) getServlet()).getServer();
+        } catch (Throwable t) {
+            throw new ServletException
+            ("Cannot acquire MBeanServer reference", t);
+        }
+        
+        // Identify the requested action
+        AliasForm aform = (AliasForm) form;
+
+        // Perform a "Create Alias" transaction (if requested)
+        String operation = "addAlias";
+        
+        //alias to be added
+        Object values[] = new String[1];
+        values[0] = aform.getAliasName();
+
+        String hostName = aform.getHostName();
+
+        // validate if this alias already exists.
+        List aliasVals = aform.getAliasVals();
+        if (aliasVals.contains(values[0])) {
+           ActionErrors errors = new ActionErrors();
+            errors.add("aliasName",
+                       new ActionError("error.aliasName.exists"));
+            saveErrors(request, errors);
+            return (new ActionForward(mapping.getInput()));
+        }
+        
+        try {
+            
+            ObjectName hname = new ObjectName(hostName);
+            mBServer.invoke(hname, operation, values, createStandardAliasTypes);
+
+        } catch (Throwable t) {
+            getServlet().log
+            (resources.getMessage(locale, "users.error.invoke",
+                                  operation), t);
+            response.sendError
+                (HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
+                resources.getMessage(locale, "users.error.invoke",
+                                     operation));
+            return (null);            
+        }
+                        
+        // Forward to the success reporting page
+        session.removeAttribute(mapping.getAttribute());
+        return (mapping.findForward("Save Successful"));
+        
+    }
+    
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/host/SaveHostAction.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/host/SaveHostAction.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/host/SaveHostAction.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,310 @@
+/*
+ * Copyright 2001-2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.admin.host;
+
+
+import java.net.URLEncoder;
+import java.util.Iterator;
+import java.util.Locale;
+import java.io.IOException;
+import javax.management.Attribute;
+import javax.management.MBeanServer;
+import javax.management.MBeanServerFactory;
+import javax.management.QueryExp;
+import javax.management.Query;
+import javax.management.ObjectInstance;
+import javax.management.ObjectName;
+import javax.management.JMException;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+import org.apache.struts.action.Action;
+import org.apache.struts.action.ActionError;
+import org.apache.struts.action.ActionErrors;
+import org.apache.struts.action.ActionForm;
+import org.apache.struts.action.ActionForward;
+import org.apache.struts.action.ActionMapping;
+import org.apache.struts.util.MessageResources;
+import org.apache.webapp.admin.ApplicationServlet;
+import org.apache.webapp.admin.TomcatTreeBuilder;
+import org.apache.webapp.admin.TreeControl;
+import org.apache.webapp.admin.TreeControlNode;
+
+
+
+/**
+ * The <code>Action</code> that completes <em>Add Host</em> and
+ * <em>Edit Host</em> transactions.
+ *
+ * @author Manveen Kaur
+ * @version $Revision: 303664 $ $Date: 2005-01-29 13:36:06 -0600 (Sat, 29 Jan 2005) $
+ */
+
+public final class SaveHostAction extends Action {
+
+
+    // ----------------------------------------------------- Instance Variables
+
+    /**
+     * Signature for the <code>createStandardHost</code> operation.
+     */
+    private String createStandardHostTypes[] =
+    { "java.lang.String",     // parent
+      "java.lang.String",     // name
+      "java.lang.String",     // appBase
+      "boolean",              // autoDeploy
+      "boolean",              // deployOnStartup
+      "boolean",              // deployXML
+      "boolean",              // unpackWARs
+      "boolean",              // xmlNamespaceAware
+      "boolean",              // xmlValidation
+    };
+
+    /**
+     * The MBeanServer we will be interacting with.
+     */
+    private MBeanServer mBServer = null;
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Process the specified HTTP request, and create the corresponding HTTP
+     * response (or forward to another web component that will create it).
+     * Return an <code>ActionForward</code> instance describing where and how
+     * control should be forwarded, or <code>null</code> if the response has
+     * already been completed.
+     *
+     * @param mapping The ActionMapping used to select this instance
+     * @param actionForm The optional ActionForm bean for this request (if any)
+     * @param request The HTTP request we are processing
+     * @param response The HTTP response we are creating
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception ServletException if a servlet exception occurs
+     */
+    public ActionForward execute(ActionMapping mapping,
+                                 ActionForm form,
+                                 HttpServletRequest request,
+                                 HttpServletResponse response)
+        throws IOException, ServletException {
+
+        // Acquire the resources that we need
+        HttpSession session = request.getSession();
+        Locale locale = getLocale(request);
+        MessageResources resources = getResources(request);
+
+        // Acquire a reference to the MBeanServer containing our MBeans
+        try {
+            mBServer = ((ApplicationServlet) getServlet()).getServer();
+        } catch (Throwable t) {
+            throw new ServletException
+            ("Cannot acquire MBeanServer reference", t);
+        }
+
+        // Identify the requested action
+        HostForm hform = (HostForm) form;
+        String adminAction = hform.getAdminAction();
+        String hObjectName = hform.getObjectName();
+        ObjectName honame = null;
+
+        // Perform a "Create Host" transaction (if requested)
+        if ("Create".equals(adminAction)) {
+
+            String operation = null;
+            Object values[] = null;
+
+            try {
+                String serviceName = hform.getServiceName();
+                ObjectName soname = new ObjectName(serviceName);
+                String domain = soname.getDomain();
+                // Ensure that the requested host name is unique
+                ObjectName oname =
+                    new ObjectName(domain + 
+                                   TomcatTreeBuilder.HOST_TYPE +
+                                   ",host=" + hform.getHostName());
+                if (mBServer.isRegistered(oname)) {
+                    ActionErrors errors = new ActionErrors();
+                    errors.add("hostName",
+                               new ActionError("error.hostName.exists"));
+                    saveErrors(request, errors);
+                    return (new ActionForward(mapping.getInput()));
+                }
+
+                // Look up our MBeanFactory MBean
+                ObjectName fname = TomcatTreeBuilder.getMBeanFactory();
+
+                // Create a new StandardHost object
+                values = new Object[9];
+                values[0] = domain + TomcatTreeBuilder.ENGINE_TYPE;
+                values[1] = hform.getHostName();
+                values[2] = hform.getAppBase();
+                values[3] = new Boolean(hform.getAutoDeploy());
+                values[4] = new Boolean(hform.getDeployOnStartup());
+                values[5] = new Boolean(hform.getDeployXML());
+                values[6] = new Boolean(hform.getUnpackWARs());
+                values[7] = new Boolean(hform.getXmlNamespaceAware());
+                values[8] = new Boolean(hform.getXmlValidation());
+
+
+                operation = "createStandardHost";
+                hObjectName = (String)
+                    mBServer.invoke(fname, operation,
+                                    values, createStandardHostTypes);
+
+                // Add the new Host to our tree control node
+                TreeControl control = (TreeControl)
+                    session.getAttribute("treeControlTest");
+                if (control != null) {
+                    String parentName = serviceName;
+                    TreeControlNode parentNode = control.findNode(parentName);
+                    if (parentNode != null) {
+                        String nodeLabel =
+                            resources.getMessage(locale, "server.service.treeBuilder.host") +
+                            " (" + hform.getHostName() + ")";
+                        String encodedName =
+                            URLEncoder.encode(hObjectName,TomcatTreeBuilder.URL_ENCODING);
+                        TreeControlNode childNode =
+                            new TreeControlNode(hObjectName,
+                                                "Host.gif",
+                                                nodeLabel,
+                                                "EditHost.do?select=" +
+                                                encodedName,
+                                                "content",
+                                                true, domain);
+                        parentNode.addChild(childNode);
+                        // FIXME - force a redisplay
+                    } else {
+                        getServlet().log
+                            ("Cannot find parent node '" + parentName + "'");
+                    }
+                } else {
+                    getServlet().log
+                        ("Cannot find TreeControlNode!");
+                }
+
+            } catch (Exception e) {
+                getServlet().log
+                    (resources.getMessage(locale, "users.error.invoke",
+                                          operation), e);
+                response.sendError
+                    (HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
+                     resources.getMessage(locale, "users.error.invoke",
+                                          operation));
+                return (null);
+
+            }
+
+        }
+
+        // Perform attribute updates as requested
+        String attribute = null;
+        try {
+
+            honame = new ObjectName(hObjectName);
+
+            attribute = "appBase";
+            String appBase = "";
+            try {
+                appBase = hform.getAppBase();
+            } catch (Throwable t) {
+                appBase = "";
+            }
+            mBServer.setAttribute(honame,
+                                  new Attribute("appBase", appBase));
+
+            attribute = "autoDeploy";
+            String autoDeploy = "true";
+            try {
+                autoDeploy = hform.getAutoDeploy();
+            } catch (Throwable t) {
+                autoDeploy = "true";
+            }
+            mBServer.setAttribute(honame,
+                                  new Attribute("autoDeploy", new Boolean(autoDeploy)));
+
+            attribute = "deployXML";
+            String deployXML = "true";
+            try {
+                deployXML = hform.getDeployXML();
+            } catch (Throwable t) {
+                deployXML = "true";
+            }
+            mBServer.setAttribute(honame,
+                                  new Attribute("deployXML", new Boolean(deployXML)));
+
+            attribute = "deployOnStartup";
+            String deployOnStartup = "true";
+            try {
+                deployOnStartup = hform.getDeployOnStartup();
+            } catch (Throwable t) {
+                deployOnStartup = "true";
+            }
+            mBServer.setAttribute(honame,
+                                  new Attribute("deployOnStartup", new Boolean(deployOnStartup)));
+                                  
+            attribute = "unpackWARs";
+            String unpackWARs = "false";
+            try {
+                unpackWARs = hform.getUnpackWARs();
+            } catch (Throwable t) {
+                unpackWARs = "false";
+            }
+            mBServer.setAttribute(honame,
+                                  new Attribute("unpackWARs", new Boolean(unpackWARs)));
+
+            attribute = "xmlNamespaceAware";
+            String xmlNamespaceAware = "false";
+            try {
+                xmlNamespaceAware = hform.getXmlNamespaceAware();
+            } catch (Throwable t) {
+                xmlNamespaceAware = "false";
+            }
+            mBServer.setAttribute(honame,
+                                  new Attribute("xmlNamespaceAware", new Boolean(xmlNamespaceAware)));
+
+            attribute = "xmlValidation";
+            String xmlValidation = "false";
+            try {
+                xmlValidation = hform.getXmlValidation();
+            } catch (Throwable t) {
+                xmlValidation = "false";
+            }
+            mBServer.setAttribute(honame,
+                                  new Attribute("xmlValidation", new Boolean(xmlValidation)));
+
+        } catch (Exception e) {
+
+            getServlet().log
+                (resources.getMessage(locale, "users.error.attribute.set",
+                                      attribute), e);
+            response.sendError
+                (HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
+                 resources.getMessage(locale, "users.error.attribute.set",
+                                      attribute));
+            return (null);
+        }
+
+        // Forward to the success reporting page
+        session.removeAttribute(mapping.getAttribute());
+        return (mapping.findForward("Save Successful"));
+
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/realm/AddRealmAction.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/realm/AddRealmAction.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/realm/AddRealmAction.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,223 @@
+/*
+ * Copyright 2001-2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.admin.realm;
+
+import java.io.IOException;
+import java.net.URLEncoder;
+import java.util.Locale;
+import java.util.ArrayList;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+import org.apache.struts.action.Action;
+import org.apache.struts.action.ActionErrors;
+import org.apache.struts.action.ActionForm;
+import org.apache.struts.action.ActionForward;
+import org.apache.struts.action.ActionMapping;
+import org.apache.struts.util.MessageResources;
+import org.apache.webapp.admin.TomcatTreeBuilder;
+import org.apache.webapp.admin.LabelValueBean;
+import org.apache.webapp.admin.Lists;
+
+/**
+ * The <code>Action</code> that sets up <em>Add Realm</em> transactions.
+ *
+ * @author Manveen Kaur
+ * @version $Revision: 303390 $ $Date: 2004-10-18 01:37:56 -0500 (Mon, 18 Oct 2004) $
+ */
+
+public class AddRealmAction extends Action {
+
+    // the list for types of realms
+    private ArrayList types = null;
+
+    // --------------------------------------------------------- Public Methods
+
+    /**
+     * Process the specified HTTP request, and create the corresponding HTTP
+     * response (or forward to another web component that will create it).
+     * Return an <code>ActionForward</code> instance describing where and how
+     * control should be forwarded, or <code>null</code> if the response has
+     * already been completed.
+     *
+     * @param mapping The ActionMapping used to select this instance
+     * @param actionForm The optional ActionForm bean for this request (if any)
+     * @param request The HTTP request we are processing
+     * @param response The HTTP response we are creating
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception ServletException if a servlet exception occurs
+     */
+    public ActionForward execute(ActionMapping mapping,
+                                 ActionForm form,
+                                 HttpServletRequest request,
+                                 HttpServletResponse response)
+        throws IOException, ServletException {
+
+        // Acquire the resources that we need
+        HttpSession session = request.getSession();
+        Locale locale = getLocale(request);
+        MessageResources resources = getResources(request);
+        // Fill in the form values for display and editing
+
+        String realmTypes[] = new String[5];
+        realmTypes[0] = "UserDatabaseRealm";
+        realmTypes[1] = "JNDIRealm";
+        realmTypes[2] = "MemoryRealm";
+        realmTypes[3] = "JDBCRealm";
+        realmTypes[4] = "DataSourceRealm";
+
+        String parent = request.getParameter("parent");
+        String type = request.getParameter("type");
+        if (type == null)
+            type = "UserDatabaseRealm";    // default type is UserDatabaseRealm
+        
+        types = new ArrayList();
+        // the first element in the select list should be the type selected
+        types.add(new LabelValueBean(type,
+                "AddRealm.do?parent=" + 
+                URLEncoder.encode(parent,TomcatTreeBuilder.URL_ENCODING)
+                + "&type=" + type));
+        for (int i=0; i< realmTypes.length; i++) {
+            if (!type.equalsIgnoreCase(realmTypes[i])) {
+                types.add(new LabelValueBean(realmTypes[i],
+                "AddRealm.do?parent=" + 
+                URLEncoder.encode(parent,TomcatTreeBuilder.URL_ENCODING)
+                + "&type=" + realmTypes[i]));
+            }
+        }
+
+        if ("UserDatabaseRealm".equalsIgnoreCase(type)) {
+            createUserDatabaseRealm(session, parent);
+        } else if ("JNDIRealm".equalsIgnoreCase(type)) {
+            createJNDIRealm(session, parent);
+        } else if ("MemoryRealm".equalsIgnoreCase(type)) {
+            createMemoryRealm(session, parent);
+        } else if ("JDBCRealm".equalsIgnoreCase(type)){
+            createJDBCRealm(session, parent);
+        } else if ("DataSourceRealm".equalsIgnoreCase(type)) {
+            createDataSourceRealm(session, parent);
+        }
+        // Forward to the realm display page
+        return (mapping.findForward(type));
+
+    }
+
+    private void createUserDatabaseRealm(HttpSession session, String parent) {
+
+        UserDatabaseRealmForm realmFm = new UserDatabaseRealmForm();
+        session.setAttribute("userDatabaseRealmForm", realmFm);
+        realmFm.setAdminAction("Create");
+        realmFm.setObjectName("");
+        realmFm.setParentObjectName(parent);
+        String realmType = "UserDatabaseRealm";
+        realmFm.setNodeLabel("Realm (" + realmType + ")");
+        realmFm.setRealmType(realmType);
+        realmFm.setResource("");
+        realmFm.setRealmTypeVals(types);
+    }
+
+    private void createJNDIRealm(HttpSession session, String parent) {
+
+        JNDIRealmForm realmFm = new JNDIRealmForm();
+        session.setAttribute("jndiRealmForm", realmFm);
+        realmFm.setAdminAction("Create");
+        realmFm.setObjectName("");
+        realmFm.setParentObjectName(parent);
+        String realmType = "JNDIRealm";
+        realmFm.setNodeLabel("Realm (" + realmType + ")");
+        realmFm.setRealmType(realmType);
+        realmFm.setDigest("");
+        realmFm.setRoleBase("");
+        realmFm.setUserSubtree("false");
+        realmFm.setRoleSubtree("false");
+        realmFm.setRolePattern("");
+        realmFm.setUserRoleName("");
+        realmFm.setRoleName("");
+        realmFm.setRoleBase("");
+        realmFm.setContextFactory("");
+        realmFm.setUserPattern("");
+        realmFm.setUserSearch("");
+        realmFm.setUserPassword("");
+        realmFm.setConnectionName("");
+        realmFm.setConnectionPassword("");
+        realmFm.setConnectionURL("");
+        realmFm.setSearchVals(Lists.getBooleanValues());
+        realmFm.setRealmTypeVals(types);
+    }
+
+    private void createMemoryRealm(HttpSession session, String parent) {
+
+        MemoryRealmForm realmFm = new MemoryRealmForm();
+        session.setAttribute("memoryRealmForm", realmFm);
+        realmFm.setAdminAction("Create");
+        realmFm.setObjectName("");
+        realmFm.setParentObjectName(parent);
+        String realmType = "MemoryRealm";
+        realmFm.setNodeLabel("Realm (" + realmType + ")");
+        realmFm.setRealmType(realmType);
+        realmFm.setPathName("");
+        realmFm.setRealmTypeVals(types);
+    }
+
+    private void createJDBCRealm(HttpSession session, String parent) {
+
+        JDBCRealmForm realmFm = new JDBCRealmForm();
+        session.setAttribute("jdbcRealmForm", realmFm);
+        realmFm.setAdminAction("Create");
+        realmFm.setObjectName("");
+        realmFm.setParentObjectName(parent);
+        String realmType = "JDBCRealm";
+        realmFm.setNodeLabel("Realm (" + realmType + ")");
+        realmFm.setRealmType(realmType);
+        realmFm.setDigest("");
+        realmFm.setDriver("");
+        realmFm.setRoleNameCol("");
+        realmFm.setPasswordCol("");
+        realmFm.setUserTable("");
+        realmFm.setRoleTable("");
+        realmFm.setConnectionName("");
+        realmFm.setConnectionPassword("");
+        realmFm.setConnectionURL("");
+        realmFm.setRealmTypeVals(types);
+    }
+    
+    private void createDataSourceRealm(HttpSession session, String parent) {
+
+        DataSourceRealmForm realmFm = new DataSourceRealmForm();
+        session.setAttribute("dataSourceRealmForm", realmFm);
+        realmFm.setAdminAction("Create");
+        realmFm.setObjectName("");
+        realmFm.setParentObjectName(parent);
+        String realmType = "DataSourceRealm";
+        realmFm.setNodeLabel("Realm (" + realmType + ")");
+        realmFm.setRealmType(realmType);
+        realmFm.setDataSourceName("");
+        realmFm.setDigest("");
+        realmFm.setLocalDataSource("false");
+        realmFm.setRoleNameCol("");
+        realmFm.setUserCredCol("");
+        realmFm.setUserNameCol("");
+        realmFm.setUserRoleTable("");
+        realmFm.setUserTable("");
+        realmFm.setRealmTypeVals(types);
+        realmFm.setBooleanVals(Lists.getBooleanValues());
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/realm/DataSourceRealmForm.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/realm/DataSourceRealmForm.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/realm/DataSourceRealmForm.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,363 @@
+/*
+ * Copyright 2001,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.admin.realm;
+
+import javax.servlet.http.HttpServletRequest;
+import org.apache.struts.action.ActionError;
+import org.apache.struts.action.ActionErrors;
+import org.apache.struts.action.ActionForm;
+import org.apache.struts.action.ActionMapping;
+import java.net.InetAddress;
+import java.util.List;
+
+import org.apache.webapp.admin.ApplicationServlet;
+import org.apache.webapp.admin.LabelValueBean;
+
+/**
+ * Form bean for the datasource realm page.
+ *
+ * @author Amy Roh
+ * @version $Revision: 302986 $ $Date: 2004-06-27 21:14:52 -0500 (Sun, 27 Jun 2004) $
+ */
+
+public final class DataSourceRealmForm extends RealmForm {
+    
+    // ----------------------------------------------------- Instance Variables
+    
+    /**
+     * The text for the JNDI named JDBC DataSource for your database.
+     */
+    private String dataSourceName = null;
+      
+    /**
+     * The text for the digest.
+     */
+    private String digest = null;
+    
+    /** 
+     * The text for if the DataSource is local to the webapp.
+     */
+    private String localDataSource = "false";
+    
+    /**
+     * The text for the roleNameCol.
+     */
+    private String roleNameCol = null;
+    
+    /**
+     * The text for the userCredCol.
+     */
+    private String userCredCol = null;
+    
+    /**
+     * The text for the userNameCol.
+     */
+    private String userNameCol = null;
+        
+    /**
+     * The text for the userRoleTable.
+     */
+    private String userRoleTable = null;
+    
+    /**
+     * The text for the user table.
+     */
+    private String userTable = null;
+        
+    /*
+     * Represent boolean (true, false) values for unpackWARs etc.
+     */
+    private List booleanVals = null;
+    
+    // ------------------------------------------------------------- Properties
+    
+    
+    /**
+     * Return the dataSourceName.
+     */
+    public String getDataSourceName() {
+        
+        return this.dataSourceName;
+        
+    }
+    
+    /**
+     * Set the dataSourceName.
+     */
+    public void setDataSourceName(String dataSourceName) {
+        
+        this.dataSourceName = dataSourceName;
+        
+    }
+    
+    /**
+     * Return the digest.
+     */
+    public String getDigest() {
+        
+        return this.digest;
+        
+    }
+    
+    /**
+     * Set the digest.
+     */
+    public void setDigest(String digest) {
+        
+        this.digest = digest;
+        
+    }
+    
+    /**
+     * Return the localDataSource.
+     */
+    public String getLocalDataSource() {
+        
+        return this.localDataSource;
+        
+    }
+    
+    /**
+     * Set the localDataSource.
+     */
+    public void setLocalDataSource(String localDataSource) {
+        
+        this.localDataSource = localDataSource;
+        
+    }
+    
+    /**
+     * Return the roleNameCol.
+     */
+    public String getRoleNameCol() {
+        
+        return this.roleNameCol;
+        
+    }
+    
+    /**
+     * Set the roleNameCol.
+     */
+    public void setRoleNameCol(String roleNameCol) {
+        
+        this.roleNameCol = roleNameCol;
+        
+    }
+    
+    /**
+     * Return the userCredCol.
+     */
+    public String getUserCredCol() {
+        
+        return this.userCredCol;
+        
+    }
+    
+    /**
+     * Set the userCredCol.
+     */
+    public void setUserCredCol(String userCredCol) {
+        
+        this.userCredCol = userCredCol;
+        
+    }
+    
+    /**
+     * Return the userNameCol.
+     */
+    public String getUserNameCol() {
+        
+        return this.userNameCol;
+        
+    }
+    
+    /**
+     * Set the userNameCol.
+     */
+    public void setUserNameCol(String userNameCol) {
+        
+        this.userNameCol = userNameCol;
+        
+    }
+    
+    /**
+     * Return the user role table.
+     */
+    public String getUserRoleTable() {
+        
+        return this.userRoleTable;
+        
+    }
+    
+    /**
+     * Set the user role table.
+     */
+    public void setUserRoleTable(String userRoleTable) {
+        
+        this.userRoleTable = userRoleTable;
+        
+    }
+    
+    /**
+     * Return the user table.
+     */
+    public String getUserTable() {
+        
+        return this.userTable;
+        
+    }
+    
+    /**
+     * Set the user Table.
+     */
+    public void setUserTable(String userTable) {
+        
+        this.userTable = userTable;
+        
+    }
+    
+    /**
+     * Return the booleanVals.
+     */
+    public List getBooleanVals() {
+
+        return this.booleanVals;
+
+    }
+
+    /**
+     * Set the booleanVals.
+     */
+    public void setBooleanVals(List booleanVals) {
+
+        this.booleanVals = booleanVals;
+
+    }
+    
+    // --------------------------------------------------------- Public Methods
+    
+    /**
+     * Reset all properties to their default values.
+     *
+     * @param mapping The mapping used to select this instance
+     * @param request The servlet request we are processing
+     */
+    public void reset(ActionMapping mapping, HttpServletRequest request) {
+        
+        super.reset(mapping, request);   
+        this.dataSourceName = null;
+        this.digest = null;
+        this.localDataSource = "false";
+        
+        this.roleNameCol = null;
+        this.userCredCol = null;
+        this.userNameCol = null;
+        this.userTable = null;
+        this.userRoleTable = null;
+        
+    }
+    
+    /**
+     * Render this object as a String.
+     */
+    public String toString() {
+
+        StringBuffer sb = new StringBuffer("DataSourceRealmForm[adminAction=");
+        sb.append(getAdminAction());
+        sb.append(",dataSourceName=");
+        sb.append(dataSourceName);
+        sb.append(",digest=");
+        sb.append(digest);
+        sb.append("',localDataSource='");
+        sb.append(localDataSource);
+        sb.append("',roleNameCol=");
+        sb.append(roleNameCol);
+        sb.append("',userCredCol=");
+        sb.append(userCredCol);
+        sb.append("',userNameCol=");
+        sb.append(userNameCol);
+        sb.append("',userRoleTable=");
+        sb.append(userRoleTable);
+        sb.append("',userTable='");
+        sb.append(userTable);
+        sb.append("',objectName='");
+        sb.append(getObjectName());
+        sb.append("',realmType=");
+        sb.append(getRealmType());
+        sb.append("]");
+        return (sb.toString());
+
+    }
+    
+    /**
+     * Validate the properties that have been set from this HTTP request,
+     * and return an <code>ActionErrors</code> object that encapsulates any
+     * validation errors that have been found.  If no errors are found, return
+     * <code>null</code> or an <code>ActionErrors</code> object with no
+     * recorded error messages.
+     *
+     * @param mapping The mapping used to select this instance
+     * @param request The servlet request we are processing
+     */
+    
+    public ActionErrors validate(ActionMapping mapping,
+    HttpServletRequest request) {
+        
+        ActionErrors errors = new ActionErrors();
+        
+        String submit = request.getParameter("submit");
+        //String type = request.getParameter("realmType");
+        
+        // front end validation when save is clicked.        
+         //if (submit != null) {
+             // the following fields are required.
+            
+            if ((dataSourceName == null) || (dataSourceName.length() < 1)) {
+                errors.add("dataSourceName",
+                new ActionError("error.dataSourceName.required"));
+            }
+         
+            if ((roleNameCol == null) || (roleNameCol.length() < 1)) {
+                errors.add("roleNameCol",
+                new ActionError("error.roleNameCol.required"));
+            }
+
+            if ((userCredCol == null) || (userCredCol.length() < 1)) {
+                errors.add("userCredCol",
+                new ActionError("error.userCredCol.required"));
+            }
+        
+            if ((userNameCol == null) || (userNameCol.length() < 1)) {
+                errors.add("userNameCol",
+                new ActionError("error.userNameCol.required"));
+            }
+            
+            if ((userRoleTable == null) || (userRoleTable.length() < 1)) {
+                errors.add("userRoleTable",
+                new ActionError("error.userRoleTable.required"));
+            }
+        
+            if ((userTable == null) || (userTable.length() < 1)) {
+                errors.add("userTable",
+                new ActionError("error.userTable.required"));
+            }
+            
+        //}
+                 
+        return errors;
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/realm/DeleteRealmAction.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/realm/DeleteRealmAction.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/realm/DeleteRealmAction.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,158 @@
+/*
+ * Copyright 2001-2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.admin.realm;
+
+import java.io.IOException;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Locale;
+import java.util.TreeSet;
+import java.util.Set;
+import java.util.ArrayList;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+import org.apache.struts.action.Action;
+import org.apache.struts.action.ActionErrors;
+import org.apache.struts.action.ActionForm;
+import org.apache.struts.action.ActionForward;
+import org.apache.struts.action.ActionMapping;
+
+import javax.management.MBeanServer;
+import javax.management.MBeanServerFactory;
+import javax.management.QueryExp;
+import javax.management.Query;
+import javax.management.ObjectInstance;
+import javax.management.ObjectName;
+import javax.management.JMException;
+import org.apache.struts.util.MessageResources;
+
+import org.apache.webapp.admin.ApplicationServlet;
+import org.apache.webapp.admin.TomcatTreeBuilder;
+import org.apache.webapp.admin.valve.ValveUtil;
+
+/**
+ * The <code>Action</code> that sets up <em>Delete Realms</em> transactions.
+ *
+ * @author Manveen Kaur
+ * @version $Revision: 303390 $ $Date: 2004-10-18 01:37:56 -0500 (Mon, 18 Oct 2004) $
+ */
+
+public class DeleteRealmAction extends Action {
+    
+    
+    /**
+     * The MBeanServer we will be interacting with.
+     */
+    private MBeanServer mBServer = null;
+    
+    
+    // --------------------------------------------------------- Public Methods
+    
+    /**
+     * Process the specified HTTP request, and create the corresponding HTTP
+     * response (or forward to another web component that will create it).
+     * Return an <code>ActionForward</code> instance describing where and how
+     * control should be forwarded, or <code>null</code> if the response has
+     * already been completed.
+     *
+     * @param mapping The ActionMapping used to select this instance
+     * @param actionForm The optional ActionForm bean for this request (if any)
+     * @param request The HTTP request we are processing
+     * @param response The HTTP response we are creating
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception ServletException if a servlet exception occurs
+     */
+    public ActionForward execute(ActionMapping mapping,
+    ActionForm form,
+    HttpServletRequest request,
+    HttpServletResponse response)
+    throws IOException, ServletException {
+        
+        
+        // Acquire the resources that we need
+        HttpSession session = request.getSession();
+        Locale locale = getLocale(request);
+        MessageResources resources = getResources(request);
+        
+        // Acquire a reference to the MBeanServer containing our MBeans
+        try {
+            mBServer = ((ApplicationServlet) getServlet()).getServer();
+        } catch (Throwable t) {
+            throw new ServletException
+            ("Cannot acquire MBeanServer reference", t);
+        }
+        
+        String pattern = null;
+        // Set up a form bean containing the currently selected
+        // objects to be deleted
+        RealmsForm realmsForm = new RealmsForm();
+        String select = request.getParameter("select");
+        if (select != null) {
+            String realms[] = new String[1];
+            realms[0] = select;
+            realmsForm.setRealms(realms);
+            pattern = select;
+        }
+        request.setAttribute("realmsForm", realmsForm);
+        
+        // Accumulate a list of all available realms
+        ArrayList list = new ArrayList();
+        String parent = request.getParameter("parent");
+        
+        if (parent != null) {
+            try {
+                pattern = ValveUtil.getObjectName(
+                             parent,TomcatTreeBuilder.REALM_TYPE);
+            } catch (Exception e) {
+                getServlet().log
+                (resources.getMessage(locale, "users.error.select"));
+                response.sendError
+                (HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
+                resources.getMessage(locale, "users.error.select"));
+                return (null);
+            }
+        }
+        
+        try {
+            Iterator items =
+            mBServer.queryNames(new ObjectName(pattern), null).iterator();
+            while (items.hasNext()) {
+                list.add(items.next().toString());
+            }
+        } catch (Exception e) {
+            getServlet().log
+            (resources.getMessage(locale, "users.error.select"));
+            response.sendError
+            (HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
+            resources.getMessage(locale, "users.error.select"));
+            return (null);
+        }
+        
+        Collections.sort(list);
+        request.setAttribute("realmsList", list);
+        
+        // Forward to the list display page
+        return (mapping.findForward("Realms"));
+        
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/realm/DeleteRealmsAction.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/realm/DeleteRealmsAction.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/realm/DeleteRealmsAction.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,158 @@
+/*
+ * Copyright 2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.admin.realm;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.Locale;
+import java.util.Set;
+import java.util.TreeSet;
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+import javax.management.ObjectInstance;
+import javax.management.modelmbean.ModelMBean;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpSession;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import org.apache.struts.action.Action;
+import org.apache.struts.action.ActionForm;
+import org.apache.struts.action.ActionForward;
+import org.apache.struts.action.ActionMapping;
+import org.apache.struts.util.MessageResources;
+
+import org.apache.webapp.admin.ApplicationServlet;
+import org.apache.webapp.admin.TomcatTreeBuilder;
+import org.apache.webapp.admin.TreeControl;
+import org.apache.webapp.admin.TreeControlNode;
+
+
+/**
+ * The <code>Action</code> that completes <em>Delete Realms</em>
+ * transactions.
+ *
+ * @author Manveen Kaur
+ * @version $Revision: 303390 $ $Date: 2004-10-18 01:37:56 -0500 (Mon, 18 Oct 2004) $
+ */
+
+public class DeleteRealmsAction extends Action {
+
+
+    /**
+     * Signature for the <code>removeRealm</code> operation.
+     */
+    private String removeRealmTypes[] =
+    { "java.lang.String",      // Object name
+    };
+
+
+    /**
+     * The MBeanServer we will be interacting with.
+     */
+    private MBeanServer mBServer = null;
+    
+    // --------------------------------------------------------- Public Methods
+    
+    
+    /**
+     * Process the specified HTTP request, and create the corresponding HTTP
+     * response (or forward to another web component that will create it).
+     * Return an <code>ActionForward</code> instance describing where and how
+     * control should be forwarded, or <code>null</code> if the response has
+     * already been completed.
+     *
+     * @param mapping The ActionMapping used to select this instance
+     * @param actionForm The optional ActionForm bean for this request (if any)
+     * @param request The HTTP request we are processing
+     * @param response The HTTP response we are creating
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception ServletException if a servlet exception occurs
+     */
+    public ActionForward execute(ActionMapping mapping,
+                                 ActionForm form,
+                                 HttpServletRequest request,
+                                 HttpServletResponse response)
+        throws IOException, ServletException {
+        
+        
+        // Look up the components we will be using as needed
+        HttpSession session = request.getSession();
+        Locale locale = getLocale(request);
+        MessageResources resources = getResources(request);
+
+        // Acquire a reference to the MBeanServer containing our MBeans
+        try {
+            mBServer = ((ApplicationServlet) getServlet()).getServer();
+        } catch (Throwable t) {
+            throw new ServletException
+            ("Cannot acquire MBeanServer reference", t);
+        }
+        
+        // Delete the specified Realms
+        String realms[]  = ((RealmsForm) form).getRealms();
+        String values[] = new String[1];
+        String operation = "removeRealm";
+        try {
+
+            // Look up our tree control data structure
+            TreeControl control = (TreeControl)
+                session.getAttribute("treeControlTest");
+
+            // Remove the specified realms
+            for (int i = 0; i < realms.length; i++) {
+                values[0] = realms[i];
+                if (control != null) {
+                    control.selectNode(null);
+                    TreeControlNode node = control.findNode(realms[i]);
+                    String domain = node.getDomain();
+                    ObjectName fname = 
+                        TomcatTreeBuilder.getMBeanFactory();
+                    mBServer.invoke(fname, operation,
+                                values, removeRealmTypes);
+                    if (node != null) {
+                        node.remove();
+                    } else {
+                        getServlet().log("Missing TreeControlNode for " +
+                                         realms[i]);
+                    }
+                } else {
+                    getServlet().log("Missing TreeControl attribute");
+                }
+            }
+
+        } catch (Exception e) {
+
+            getServlet().log
+                (resources.getMessage(locale, "users.error.invoke",
+                                      operation), e);
+            response.sendError
+                (HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
+                 resources.getMessage(locale, "users.error.invoke",
+                                      operation));
+            return (null);
+
+        }
+
+        // Report successful completion of this transaction
+        return (mapping.findForward("Save Successful"));
+
+    }
+    
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/realm/EditRealmAction.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/realm/EditRealmAction.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/realm/EditRealmAction.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,487 @@
+/*
+ * Copyright 2001-2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.admin.realm;
+
+import java.io.IOException;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Locale;
+import java.util.ArrayList;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+import org.apache.struts.action.Action;
+import org.apache.struts.action.ActionErrors;
+import org.apache.struts.action.ActionForm;
+import org.apache.struts.action.ActionForward;
+import org.apache.struts.action.ActionMapping;
+import org.apache.struts.util.MessageResources;
+
+import javax.management.MBeanServer;
+import javax.management.ObjectInstance;
+import javax.management.ObjectName;
+import javax.management.JMException;
+
+import org.apache.webapp.admin.ApplicationServlet;
+import org.apache.webapp.admin.LabelValueBean;
+import org.apache.webapp.admin.Lists;
+import org.apache.webapp.admin.TomcatTreeBuilder;
+
+/**
+ * A generic <code>Action</code> that sets up <em>Edit
+ * Realm </em> transactions, based on the type of Realm.
+ *
+ * @author Manveen Kaur
+ * @version $Revision: 303390 $ $Date: 2004-10-18 01:37:56 -0500 (Mon, 18 Oct 2004) $
+ */
+
+public class EditRealmAction extends Action {
+
+
+    /**
+     * The MBeanServer we will be interacting with.
+     */
+    private MBeanServer mBServer = null;
+
+
+    // --------------------------------------------------------- Public Methods
+
+    /**
+     * Process the specified HTTP request, and create the corresponding HTTP
+     * response (or forward to another web component that will create it).
+     * Return an <code>ActionForward</code> instance describing where and how
+     * control should be forwarded, or <code>null</code> if the response has
+     * already been completed.
+     *
+     * @param mapping The ActionMapping used to select this instance
+     * @param actionForm The optional ActionForm bean for this request (if any)
+     * @param request The HTTP request we are processing
+     * @param response The HTTP response we are creating
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception ServletException if a servlet exception occurs
+     */
+    public ActionForward execute(ActionMapping mapping,
+                                 ActionForm form,
+                                 HttpServletRequest request,
+                                 HttpServletResponse response)
+        throws IOException, ServletException {
+
+        // Acquire the resources that we need
+        HttpSession session = request.getSession();
+        Locale locale = getLocale(request);
+        MessageResources resources = getResources(request);
+
+        // Acquire a reference to the MBeanServer containing our MBeans
+        try {
+            mBServer = ((ApplicationServlet) getServlet()).getServer();
+        } catch (Throwable t) {
+            throw new ServletException
+            ("Cannot acquire MBeanServer reference", t);
+        }
+
+        // Set up the object names of the MBeans we are manipulating
+        ObjectName rname = null;
+        StringBuffer sb = null;
+        try {
+            rname = new ObjectName(request.getParameter("select"));
+        } catch (Exception e) {
+            String message =
+                resources.getMessage(locale, "error.realmName.bad",
+                                     request.getParameter("select"));
+            getServlet().log(message);
+            response.sendError(HttpServletResponse.SC_BAD_REQUEST, message);
+            return (null);
+        }
+
+       String realmType = null;
+       String attribute = null;
+
+       // Find what type of Realm this is
+       try {
+            attribute = "className";
+            String className = (String)
+                mBServer.getAttribute(rname, attribute);
+            int period = className.lastIndexOf(".");
+            if (period >= 0)
+                realmType = className.substring(period + 1);
+        } catch (Throwable t) {
+          getServlet().log
+                (resources.getMessage(locale, "users.error.attribute.get",
+                                      attribute), t);
+            response.sendError
+                (HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
+                 resources.getMessage(locale, "users.error.attribute.get",
+                                      attribute));
+            return (null);
+        }
+
+        // Forward to the appropriate realm display page
+
+        if ("UserDatabaseRealm".equalsIgnoreCase(realmType)) {
+               setUpUserDatabaseRealm(rname, request, response);
+        } else if ("MemoryRealm".equalsIgnoreCase(realmType)) {
+               setUpMemoryRealm(rname, request, response);
+        } else if ("JDBCRealm".equalsIgnoreCase(realmType)) {
+               setUpJDBCRealm(rname, request, response);
+        } else if ("JNDIRealm".equalsIgnoreCase(realmType)) {
+               setUpJNDIRealm(rname, request, response);
+        } else if ("DataSourceRealm".equalsIgnoreCase(realmType)) {
+                setUpDataSourceRealm(rname, request, response);
+        }
+
+        return (mapping.findForward(realmType));
+
+    }
+
+    private void setUpUserDatabaseRealm(ObjectName rname, 
+                                        HttpServletRequest request,
+                                        HttpServletResponse response)
+    throws IOException {
+        // Fill in the form values for display and editing
+        MessageResources resources = getResources(request);
+        HttpSession session = request.getSession();
+        Locale locale = getLocale(request);
+        UserDatabaseRealmForm realmFm = new UserDatabaseRealmForm();
+        session.setAttribute("userDatabaseRealmForm", realmFm);
+        realmFm.setAdminAction("Edit");
+        realmFm.setObjectName(rname.toString());
+        String realmType = "UserDatabaseRealm";
+        StringBuffer sb = new StringBuffer("");
+        String host = rname.getKeyProperty("host");
+        String context = rname.getKeyProperty("path");
+        if (host!=null) {
+            sb.append("Host (" + host + ") > ");
+        }
+        if (context!=null) {
+            sb.append("Context (" + context + ") > ");
+        }
+        sb.append(resources.getMessage(locale, "server.service.treeBuilder.realm"));
+        realmFm.setNodeLabel(sb.toString());
+        realmFm.setRealmType(realmType);
+        realmFm.setAllowDeletion(allowDeletion(rname,request));
+
+        String attribute = null;
+        try {
+
+            // Copy scalar properties
+            attribute = "resourceName";
+            realmFm.setResource
+                ((String) mBServer.getAttribute(rname, attribute));
+
+        } catch (Throwable t) {
+            getServlet().log
+                (resources.getMessage(locale, "users.error.attribute.get",
+                                      attribute), t);
+            response.sendError
+                (HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
+                 resources.getMessage(locale, "users.error.attribute.get",
+                                      attribute));
+        }
+    }
+
+    private void setUpMemoryRealm(ObjectName rname, HttpServletRequest request,
+                                        HttpServletResponse response)
+    throws IOException {
+        // Fill in the form values for display and editing
+        MessageResources resources = getResources(request);
+        HttpSession session = request.getSession();
+        Locale locale = getLocale(request);
+        MemoryRealmForm realmFm = new MemoryRealmForm();
+        session.setAttribute("memoryRealmForm", realmFm);
+        realmFm.setAdminAction("Edit");
+        realmFm.setObjectName(rname.toString());
+        String realmType = "MemoryRealm";
+        StringBuffer sb = new StringBuffer();
+        sb.append(resources.getMessage(locale, "server.service.treeBuilder.realm"));
+        sb.append(" (");
+        sb.append(realmType);
+        sb.append(")");
+        realmFm.setNodeLabel(sb.toString());
+        realmFm.setRealmType(realmType);
+        realmFm.setAllowDeletion(allowDeletion(rname,request));
+
+        String attribute = null;
+        try {
+
+            // Copy scalar properties
+            attribute = "pathname";
+            realmFm.setPathName
+                ((String) mBServer.getAttribute(rname, attribute));
+
+        } catch (Throwable t) {
+            getServlet().log
+                (resources.getMessage(locale, "users.error.attribute.get",
+                                      attribute), t);
+            response.sendError
+                (HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
+                 resources.getMessage(locale, "users.error.attribute.get",
+                                      attribute));
+        }
+    }
+
+    private void setUpJDBCRealm(ObjectName rname, HttpServletRequest request,
+                                        HttpServletResponse response)
+    throws IOException {
+        // Fill in the form values for display and editing
+        MessageResources resources = getResources(request);
+        HttpSession session = request.getSession();
+        Locale locale = getLocale(request);
+        JDBCRealmForm realmFm = new JDBCRealmForm();
+        session.setAttribute("jdbcRealmForm", realmFm);
+        realmFm.setAdminAction("Edit");
+        realmFm.setObjectName(rname.toString());
+        String realmType = "JDBCRealm";
+        StringBuffer sb = new StringBuffer();
+        sb.append(resources.getMessage(locale, "server.service.treeBuilder.realm"));
+        sb.append(" (");
+        sb.append(realmType);
+        sb.append(")");
+        realmFm.setNodeLabel(sb.toString());
+        realmFm.setRealmType(realmType);
+        realmFm.setAllowDeletion(allowDeletion(rname,request));
+
+        String attribute = null;
+        try {
+
+            // Copy scalar properties
+            attribute = "digest";
+            realmFm.setDigest
+                ((String) mBServer.getAttribute(rname, attribute));
+            attribute = "driverName";
+            realmFm.setDriver
+                ((String) mBServer.getAttribute(rname, attribute));
+            attribute = "roleNameCol";
+            realmFm.setRoleNameCol
+                ((String) mBServer.getAttribute(rname, attribute));
+            attribute = "userNameCol";
+            realmFm.setUserNameCol
+                ((String) mBServer.getAttribute(rname, attribute));
+            attribute = "userCredCol";
+            realmFm.setPasswordCol
+                ((String) mBServer.getAttribute(rname, attribute));
+            attribute = "userTable";
+            realmFm.setUserTable
+                ((String) mBServer.getAttribute(rname, attribute));
+            attribute = "userRoleTable";
+            realmFm.setRoleTable
+                ((String) mBServer.getAttribute(rname, attribute));
+            attribute = "connectionName";
+            realmFm.setConnectionName
+                ((String) mBServer.getAttribute(rname, attribute));
+            attribute = "connectionPassword";
+            realmFm.setConnectionPassword
+                ((String) mBServer.getAttribute(rname, attribute));
+            attribute = "connectionURL";
+            realmFm.setConnectionURL
+                ((String) mBServer.getAttribute(rname, attribute));
+
+        } catch (Throwable t) {
+            getServlet().log
+                (resources.getMessage(locale, "users.error.attribute.get",
+                                      attribute), t);
+            response.sendError
+                (HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
+                 resources.getMessage(locale, "users.error.attribute.get",
+                                      attribute));
+        }
+    }
+
+    private void setUpJNDIRealm(ObjectName rname, HttpServletRequest request,
+                                        HttpServletResponse response)
+    throws IOException {
+        // Fill in the form values for display and editing
+        MessageResources resources = getResources(request);
+        HttpSession session = request.getSession();
+        Locale locale = getLocale(request);
+        JNDIRealmForm realmFm = new JNDIRealmForm();
+        session.setAttribute("jndiRealmForm", realmFm);
+        realmFm.setAdminAction("Edit");
+        realmFm.setObjectName(rname.toString());
+        String realmType = "JNDIRealm";
+        StringBuffer sb = new StringBuffer();
+        sb.append(resources.getMessage(locale, "server.service.treeBuilder.realm"));
+        sb.append(" (");
+        sb.append(realmType);
+        sb.append(")");
+        realmFm.setNodeLabel(sb.toString());
+        realmFm.setRealmType(realmType);
+        realmFm.setSearchVals(Lists.getBooleanValues());
+        realmFm.setAllowDeletion(allowDeletion(rname,request));
+
+        String attribute = null;
+        try {
+
+            // Copy scalar properties
+            attribute = "digest";
+            realmFm.setDigest
+                ((String) mBServer.getAttribute(rname, attribute));
+            attribute = "userSubtree";
+            realmFm.setUserSubtree
+                    (((Boolean) mBServer.getAttribute(rname, attribute)).toString());
+            attribute = "roleSubtree";
+            realmFm.setRoleSubtree
+                    (((Boolean) mBServer.getAttribute(rname, attribute)).toString());
+            attribute = "userRoleName";
+            realmFm.setUserRoleName
+                ((String) mBServer.getAttribute(rname, attribute));
+            attribute = "roleName";
+            realmFm.setRoleName
+                ((String) mBServer.getAttribute(rname, attribute));
+            attribute = "roleBase";
+            realmFm.setRoleBase
+                ((String) mBServer.getAttribute(rname, attribute));
+            attribute = "roleSearch";
+            realmFm.setRolePattern
+                ((String) mBServer.getAttribute(rname, attribute));
+            attribute = "contextFactory";
+            realmFm.setContextFactory
+                ((String) mBServer.getAttribute(rname, attribute));
+            attribute = "userPassword";
+            realmFm.setUserPassword
+                ((String) mBServer.getAttribute(rname, attribute));
+            attribute = "userPattern";
+            realmFm.setUserPattern
+                ((String) mBServer.getAttribute(rname, attribute));
+            attribute = "userSearch";
+            realmFm.setUserSearch
+                ((String) mBServer.getAttribute(rname, attribute));
+            attribute = "connectionName";
+            realmFm.setConnectionName
+                ((String) mBServer.getAttribute(rname, attribute));
+            attribute = "connectionPassword";
+            realmFm.setConnectionPassword
+                ((String) mBServer.getAttribute(rname, attribute));
+            attribute = "connectionURL";
+            realmFm.setConnectionURL
+                ((String) mBServer.getAttribute(rname, attribute));
+
+        } catch (Throwable t) {
+            getServlet().log
+                (resources.getMessage(locale, "users.error.attribute.get",
+                                      attribute), t);
+            response.sendError
+                (HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
+                 resources.getMessage(locale, "users.error.attribute.get",
+                                      attribute));
+        }
+    }
+
+    private void setUpDataSourceRealm(ObjectName rname, HttpServletRequest request,
+                                        HttpServletResponse response)
+    throws IOException {
+        // Fill in the form values for display and editing
+        MessageResources resources = getResources(request);
+        HttpSession session = request.getSession();
+        Locale locale = getLocale(request);
+        DataSourceRealmForm realmFm = new DataSourceRealmForm();
+        session.setAttribute("dataSourceRealmForm", realmFm);
+        realmFm.setAdminAction("Edit");
+        realmFm.setObjectName(rname.toString());
+        String realmType = "DataSourceRealm";
+        StringBuffer sb = new StringBuffer();
+        sb.append(resources.getMessage(locale, "server.service.treeBuilder.realm"));
+        sb.append(" (");
+        sb.append(realmType);
+        sb.append(")");
+        realmFm.setNodeLabel(sb.toString());
+        realmFm.setRealmType(realmType);
+        realmFm.setAllowDeletion(allowDeletion(rname,request));
+        realmFm.setBooleanVals(Lists.getBooleanValues());
+
+        String attribute = null;
+        try {
+
+            // Copy scalar properties
+            attribute = "dataSourceName";
+            realmFm.setDataSourceName
+                ((String) mBServer.getAttribute(rname, attribute));
+            attribute = "digest";
+            realmFm.setDigest
+                ((String) mBServer.getAttribute(rname, attribute));
+            attribute = "localDataSource";
+            realmFm.setLocalDataSource
+                (((Boolean) mBServer.getAttribute(rname, attribute)).toString());
+            attribute = "roleNameCol";
+            realmFm.setRoleNameCol
+                ((String) mBServer.getAttribute(rname, attribute));
+            attribute = "userCredCol";
+            realmFm.setUserCredCol
+                ((String) mBServer.getAttribute(rname, attribute));
+            attribute = "userNameCol";
+            realmFm.setUserNameCol
+                ((String) mBServer.getAttribute(rname, attribute));
+            attribute = "userRoleTable";
+            realmFm.setUserRoleTable
+                ((String) mBServer.getAttribute(rname, attribute));
+            attribute = "userTable";
+            realmFm.setUserTable
+                ((String) mBServer.getAttribute(rname, attribute));
+
+        } catch (Throwable t) {
+            getServlet().log
+                (resources.getMessage(locale, "users.error.attribute.get",
+                                      attribute), t);
+            response.sendError
+                (HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
+                 resources.getMessage(locale, "users.error.attribute.get",
+                                      attribute));
+        }
+    }
+
+    /*
+     * Check if "delete this realm" operation should be enabled.
+     * this operation is not allowed in case the realm is under service,
+     * host or context that the admin app runs on.
+     * return "true" if deletion is allowed.
+     */
+
+    private String allowDeletion(ObjectName rname, HttpServletRequest request) {
+
+     boolean retVal = true;
+     try{
+        // admin app's values
+        String adminService = Lists.getAdminAppService(
+                              mBServer, rname.getDomain(),request);
+        String adminHost = request.getServerName();
+        String adminContext = request.getContextPath();
+
+        //String thisService = rname.getKeyProperty("service");
+        String domain = rname.getDomain();
+        String thisHost = rname.getKeyProperty("host");
+        String thisContext = rname.getKeyProperty("path");
+
+        // realm is under context
+        if (thisContext!=null) {
+            retVal = !(thisContext.equalsIgnoreCase(adminContext));
+        } else if (thisHost != null) {
+            // realm is under host
+            retVal = !(thisHost.equalsIgnoreCase(adminHost));
+        } else {
+            // XXX FIXME
+            // realm is under service
+            return "false";
+            //retVal = !(thisService.equalsIgnoreCase(adminService));
+        }
+
+     } catch (Exception e) {
+           getServlet().log("Error getting admin service, host or context", e);
+     }
+        return new Boolean(retVal).toString();
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/realm/JDBCRealmForm.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/realm/JDBCRealmForm.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/realm/JDBCRealmForm.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,415 @@
+/*
+ * Copyright 2001,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.admin.realm;
+
+import javax.servlet.http.HttpServletRequest;
+import org.apache.struts.action.ActionError;
+import org.apache.struts.action.ActionErrors;
+import org.apache.struts.action.ActionForm;
+import org.apache.struts.action.ActionMapping;
+import java.net.InetAddress;
+import java.util.List;
+
+import org.apache.webapp.admin.ApplicationServlet;
+import org.apache.webapp.admin.LabelValueBean;
+
+/**
+ * Form bean for the jdbc realm page.
+ *
+ * @author Manveen Kaur
+ * @version $Revision: 302986 $ $Date: 2004-06-27 21:14:52 -0500 (Sun, 27 Jun 2004) $
+ */
+
+public final class JDBCRealmForm extends RealmForm {
+    
+    // ----------------------------------------------------- Instance Variables
+    
+    /**
+     * The text for the realm name, used to retrieve
+     * the corresponding realm mBean.
+     */
+    private String realmName = null;
+      
+    /**
+     * The text for the digest.
+     */
+    private String digest = null;
+    
+    /**
+     * The text for the roleNameCol.
+     */
+    private String roleNameCol = null;
+
+    /**
+     * The text for the userNameCol.
+     */
+    private String userNameCol = null;
+
+    /**
+     * The text for the passwordCol.
+     */
+    private String passwordCol = null;
+    
+    /**
+     * The text for the driver.
+     */
+    private String driver = null;
+        
+    /**
+     * The text for the role table.
+     */
+    private String roleTable = null;
+    
+    /**
+     * The text for the user table.
+     */
+    private String userTable = null;
+        
+    /**
+     * The text for the connection user name.
+     */
+    private String connectionName = null;
+    
+    /**
+     * The text for the connection Password.
+     */
+    private String connectionPassword = null;
+    
+    /**
+     * The text for the connection URL.
+     */
+    private String connectionURL = null;
+    
+    // ------------------------------------------------------------- Properties
+    
+    
+    /**
+     * Return the digest.
+     */
+    public String getDigest() {
+        
+        return this.digest;
+        
+    }
+    
+    /**
+     * Set the digest.
+     */
+    public void setDigest(String digest) {
+        
+        this.digest = digest;
+        
+    }
+    
+    /**
+     * Return the roleNameCol.
+     */
+    public String getRoleNameCol() {
+        
+        return this.roleNameCol;
+        
+    }
+    
+    /**
+     * Set the roleNameCol.
+     */
+    public void setRoleNameCol(String roleNameCol) {
+        
+        this.roleNameCol = roleNameCol;
+        
+    }
+    
+    /**
+     * Return the userNameCol.
+     */
+    public String getUserNameCol() {
+        
+        return this.userNameCol;
+        
+    }
+    
+    /**
+     * Set the userNameCol.
+     */
+    public void setUserNameCol(String userNameCol) {
+        
+        this.userNameCol = userNameCol;
+        
+    }
+    /**
+     * Return the driver.
+     */
+    public String getDriver() {
+        
+        return this.driver;
+        
+    }
+    
+    /**
+     * Set the driver.
+     */
+    public void setDriver(String driver) {
+        
+        this.driver = driver;
+        
+    }
+    
+    /**
+     * Return the role table.
+     */
+    public String getRoleTable() {
+        
+        return this.roleTable;
+        
+    }
+    
+    /**
+     * Set the roleTable.
+     */
+    public void setRoleTable(String roleTable) {
+        
+        this.roleTable = roleTable;
+        
+    }
+    
+    /**
+     * Return the user table.
+     */
+    public String getUserTable() {
+        
+        return this.userTable;
+        
+    }
+    
+    /**
+     * Set the user Table.
+     */
+    public void setUserTable(String userTable) {
+        
+        this.userTable = userTable;
+        
+    }
+    
+    /**
+     * Return the passwordCol.
+     */
+    public String getPasswordCol() {
+        
+        return this.passwordCol;
+        
+    }
+    
+    /**
+     * Set the passwordCol.
+     */
+    public void setPasswordCol(String passwordCol) {
+        
+        this.passwordCol = passwordCol;
+        
+    }
+    
+    
+    /**
+     * Return the connection name.
+     */
+    public String getConnectionName() {
+        
+        return this.connectionName;
+        
+    }
+    
+    /**
+     * Set the connectionName.
+     */
+    public void setConnectionName(String connectionName) {
+        
+        this.connectionName = connectionName;
+        
+    }
+    
+    
+    /**
+     * Return the connection password.
+     */
+    public String getConnectionPassword() {
+        
+        return this.connectionPassword;
+        
+    }
+    
+    /**
+     * Set the connection password.
+     */
+    public void setConnectionPassword(String connectionPassword) {
+        
+        this.connectionPassword = connectionPassword;
+        
+    }
+    
+    
+    /**
+     * Return the connection URL.
+     */
+    public String getConnectionURL() {
+        
+        return this.connectionURL;
+        
+    }
+    
+    /**
+     * Set the connectionURL.
+     */
+    public void setConnectionURL(String connectionURL) {
+        
+        this.connectionURL = connectionURL;
+        
+    }    
+    
+    // --------------------------------------------------------- Public Methods
+    
+    /**
+     * Reset all properties to their default values.
+     *
+     * @param mapping The mapping used to select this instance
+     * @param request The servlet request we are processing
+     */
+    public void reset(ActionMapping mapping, HttpServletRequest request) {
+        
+        super.reset(mapping, request);   
+        this.digest = null;
+        this.driver = null;
+        
+        this.roleNameCol = null;
+        this.userNameCol = null;
+        this.passwordCol = null;
+        this.userTable = null;
+        this.roleTable = null;
+        
+        this.connectionName = null;
+        this.connectionPassword = null;
+        this.connectionURL = null;
+        
+    }
+    
+    /**
+     * Render this object as a String.
+     */
+    public String toString() {
+
+        StringBuffer sb = new StringBuffer("UserDatabaseRealmForm[adminAction=");
+        sb.append(getAdminAction());
+        sb.append(",digest=");
+        sb.append(digest);
+        sb.append("',driver='");
+        sb.append(driver);
+        sb.append("',roleNameCol=");
+        sb.append(roleNameCol);
+        sb.append("',userNameCol=");
+        sb.append(userNameCol);
+        sb.append(",passwordCol=");
+        sb.append(passwordCol);
+        sb.append("',userTable='");
+        sb.append(userTable);
+        sb.append("',roleTable=");
+        sb.append(roleTable);
+        sb.append(",connectionName=");
+        sb.append(connectionName);        
+        sb.append("',connectionPassword=");
+        sb.append(connectionPassword);
+        sb.append(",connectionURL=");
+        sb.append(connectionURL);
+        sb.append("',objectName='");
+        sb.append(getObjectName());
+        sb.append("',realmType=");
+        sb.append(getRealmType());
+        sb.append("]");
+        return (sb.toString());
+
+    }
+    
+    /**
+     * Validate the properties that have been set from this HTTP request,
+     * and return an <code>ActionErrors</code> object that encapsulates any
+     * validation errors that have been found.  If no errors are found, return
+     * <code>null</code> or an <code>ActionErrors</code> object with no
+     * recorded error messages.
+     *
+     * @param mapping The mapping used to select this instance
+     * @param request The servlet request we are processing
+     */
+    
+    public ActionErrors validate(ActionMapping mapping,
+    HttpServletRequest request) {
+        
+        ActionErrors errors = new ActionErrors();
+        
+        String submit = request.getParameter("submit");
+        //String type = request.getParameter("realmType");
+        
+        // front end validation when save is clicked.        
+         //if (submit != null) {
+             // the following fields are required.
+            
+            if ((driver == null) || (driver.length() < 1)) {
+                errors.add("driver",
+                new ActionError("error.driver.required"));
+            }
+         
+            if ((roleNameCol == null) || (roleNameCol.length() < 1)) {
+                errors.add("roleNameCol",
+                new ActionError("error.roleNameCol.required"));
+            }
+
+            if ((userNameCol == null) || (userNameCol.length() < 1)) {
+                errors.add("userNameCol",
+                new ActionError("error.userNameCol.required"));
+            }
+
+             if ((passwordCol == null) || (passwordCol.length() < 1)) {
+                errors.add("passwordCol",
+                new ActionError("error.passwordCol.required"));
+            }
+            
+            if ((userTable == null) || (userTable.length() < 1)) {
+                errors.add("userTable",
+                new ActionError("error.userTable.required"));
+            }
+            
+            if ((roleTable == null) || (roleTable.length() < 1)) {
+                errors.add("roleTable",
+                new ActionError("error.roleTable.required"));
+            }
+            
+            if ((connectionName == null) || (connectionName.length() < 1)) {
+                errors.add("connectionName",
+                new ActionError("error.connectionName.required"));
+            }
+            
+            if ((connectionPassword == null) || (connectionPassword.length() < 1)) {
+                errors.add("connectionPassword",
+                new ActionError("error.connectionPassword.required"));
+            }
+            
+             if ((connectionURL == null) || (connectionURL.length() < 1)) {
+                errors.add("connectionURL",
+                new ActionError("error.connectionURL.required"));
+            }
+        //}
+                 
+        return errors;
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/realm/JNDIRealmForm.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/realm/JNDIRealmForm.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/realm/JNDIRealmForm.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,598 @@
+/*
+ * Copyright 2001,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.admin.realm;
+
+import javax.servlet.http.HttpServletRequest;
+import org.apache.struts.action.ActionError;
+import org.apache.struts.action.ActionErrors;
+import org.apache.struts.action.ActionForm;
+import org.apache.struts.action.ActionMapping;
+import java.net.InetAddress;
+import java.util.List;
+
+import org.apache.webapp.admin.ApplicationServlet;
+import org.apache.webapp.admin.LabelValueBean;
+
+/**
+ * Form bean for the JNDI realm page.
+ *
+ * @author Manveen Kaur
+ * @version $Revision: 302986 $ $Date: 2004-06-27 21:14:52 -0500 (Sun, 27 Jun 2004) $
+ */
+
+public final class JNDIRealmForm extends RealmForm {
+
+    // ----------------------------------------------------- Instance Variables
+
+    /**
+     * The text for the connection user name.
+     */
+    private String connectionName = null;
+
+    /**
+     * The text for the connection Password.
+     */
+    private String connectionPassword = null;
+
+    /**
+     * The text for the connection URL.
+     */
+    private String connectionURL = null;
+
+    /**
+     * The text for the context Factory.
+     */
+    private String contextFactory = null;
+
+    /**
+     * The text for the digest algorithm.
+     */
+    private String digest = null;
+
+    /**
+     * The text for the role Base.
+     */
+    private String roleBase = null;
+
+    /**
+     * The text for the role name.
+     */
+    private String roleName = null;
+
+    /**
+     * The text for the role Pattern.
+     */
+    private String rolePattern = null;
+
+    /**
+     * Should we search the entire subtree for matching roles?
+     */
+    private String roleSubtree = "false";
+
+    /**
+     * The text for the user Base.
+     */
+    private String userBase = null;
+
+    /**
+     * The text for the user Password.
+     */
+    private String userPassword = null;
+
+    /**
+     * The text for the user Pattern.
+     */
+    private String userPattern = null;
+
+    /**
+     * The text for the user role name.
+     */
+    private String userRoleName = null;
+
+    /**
+     * The text for the user Search.
+     */
+    private String userSearch = null;
+
+    /**
+     * Should we search the entire subtree for matching users?
+     */
+    private String userSubtree = "false";
+
+    /**
+     * Set of valid values for search subtrees(true/false).
+     */
+    private List searchVals = null;
+
+
+    // ------------------------------------------------------------- Properties
+
+    /**
+     * Return the search Vals.
+     */
+    public List getSearchVals() {
+
+        return this.searchVals;
+
+    }
+
+    /**
+     * Set the search Vals.
+     */
+    public void setSearchVals(List searchVals) {
+
+        this.searchVals = searchVals;
+
+    }
+
+    /**
+     * Return the roleSubtree boolean Text.
+     */
+    public String getRoleSubtree() {
+
+        return this.roleSubtree;
+
+    }
+
+    /**
+     * Set the roleSubtree Text.
+     */
+    public void setRoleSubtree(String roleSubtree) {
+
+        this.roleSubtree = roleSubtree;
+
+    }
+
+    /**
+     * Return the userSubtree boolean Text.
+     */
+    public String getUserSubtree() {
+
+        return this.userSubtree;
+
+    }
+
+    /**
+     * Set the userSubtree Text.
+     */
+    public void setUserSubtree(String userSubtree) {
+
+        this.userSubtree = userSubtree;
+
+    }
+
+    /**
+     * Return the digest.
+     */
+    public String getDigest() {
+
+        return this.digest;
+
+    }
+
+    /**
+     * Set the digest.
+     */
+    public void setDigest(String digest) {
+
+        this.digest = digest;
+
+    }
+
+    /**
+     * Return the roleBase .
+     */
+    public String getRoleBase() {
+
+        return this.roleBase ;
+
+    }
+
+    /**
+     * Set the roleBase .
+     */
+    public void setRoleBase(String roleBase ) {
+
+        this.roleBase  = roleBase ;
+
+    }
+
+    /**
+     * Return the role name.
+     */
+    public String getRoleName() {
+
+        return this.roleName ;
+
+    }
+
+    /**
+     * Set the role name Attribute .
+     */
+    public void setRoleName(String roleName) {
+
+        this.roleName  = roleName ;
+
+    }
+
+    /**
+     * Return the userBase.
+     */
+    public String getUserBase() {
+
+        return this.userBase ;
+
+    }
+
+    /**
+     * Set the userBase.
+     */
+    public void setUserBase(String userBase ) {
+
+        this.userBase  = userBase ;
+
+    }
+
+    /**
+     * Return the user role name.
+     */
+    public String getUserRoleName() {
+
+        return this.userRoleName ;
+
+    }
+
+    /**
+     * Set the user role name Attribute .
+     */
+    public void setUserRoleName(String userRoleName) {
+
+        this.userRoleName  = userRoleName ;
+
+    }
+
+    /**
+     * Return the role Pattern
+     */
+    public String getRolePattern() {
+
+        return this.rolePattern ;
+
+    }
+
+    /**
+     * Set the role Pattern.
+     */
+    public void setRolePattern(String rolePattern ) {
+
+        this.rolePattern  = rolePattern ;
+
+    }
+
+    /**
+     * Return the user Password .
+     */
+    public String getUserPassword() {
+
+        return this.userPassword ;
+
+    }
+
+    /**
+     * Set the user Password .
+     */
+    public void setUserPassword(String userPassword ) {
+
+        this.userPassword  = userPassword ;
+
+    }
+
+
+    /**
+     * Return the user Pattern .
+     */
+    public String getUserPattern() {
+
+        return this.userPattern  ;
+
+    }
+
+    /**
+     * Set the user user Pattern  .
+     */
+    public void setUserPattern(String userPattern) {
+
+        this.userPattern   = userPattern  ;
+
+    }
+
+    /**
+     * Return the user Search.
+     */
+    public String getUserSearch() {
+
+        return this.userSearch;
+
+    }
+
+    /**
+     * Set the user user Search.
+     */
+    public void setUserSearch(String userSearch) {
+
+        this.userSearch  = userSearch;
+
+    }
+
+    /**
+     * Return the connection name.
+     */
+    public String getConnectionName() {
+
+        return this.connectionName;
+
+    }
+
+    /**
+     * Set the connectionName.
+     */
+    public void setConnectionName(String connectionName) {
+
+        this.connectionName = connectionName;
+
+    }
+
+
+    /**
+     * Return the connection password.
+     */
+    public String getConnectionPassword() {
+
+        return this.connectionPassword;
+
+    }
+
+    /**
+     * Set the connection password.
+     */
+    public void setConnectionPassword(String connectionPassword) {
+
+        this.connectionPassword = connectionPassword;
+
+    }
+
+
+    /**
+     * Return the connection URL.
+     */
+    public String getConnectionURL() {
+
+        return this.connectionURL;
+
+    }
+
+    /**
+     * Set the connectionURL.
+     */
+    public void setConnectionURL(String connectionURL) {
+
+        this.connectionURL = connectionURL;
+
+    }
+
+    /**
+     * Return the context Factory .
+     */
+    public String getContextFactory() {
+
+        return this.contextFactory ;
+
+    }
+
+    /**
+     * Set the context Factory .
+     */
+    public void setContextFactory(String contextFactory ) {
+
+        this.contextFactory  = contextFactory ;
+
+    }
+
+    // --------------------------------------------------------- Public Methods
+
+    /**
+     * Reset all properties to their default values.
+     *
+     * @param mapping The mapping used to select this instance
+     * @param request The servlet request we are processing
+     */
+    public void reset(ActionMapping mapping, HttpServletRequest request) {
+
+        super.reset(mapping, request);
+        this.roleSubtree="false";
+        this.userSubtree="false";
+
+        this.digest = null;
+        this.roleName = null;
+        this.userRoleName = null;
+
+        this.connectionName = null;
+        this.connectionPassword = null;
+        this.connectionURL = null;
+
+        this.rolePattern = null;
+        this.roleBase = null;
+        this.userBase = null;
+        this.userPassword = null;
+        this.userPattern = null;
+        this.userSearch = null;
+        this.contextFactory = null;
+    }
+
+    /**
+     * Render this object as a String.
+     */
+    public String toString() {
+
+        StringBuffer sb = new StringBuffer("UserDatabaseRealmForm[adminAction=");
+        sb.append(getAdminAction());
+        sb.append(",userSubtree=");
+        sb.append(userSubtree);
+        sb.append(",roleSubtree=");
+        sb.append(roleSubtree);
+        sb.append(",digest=");
+        sb.append(digest);
+        sb.append("',userRoleName='");
+        sb.append(userRoleName);
+        sb.append("',roleName='");
+        sb.append(roleName);
+        sb.append("',connectionName=");
+        sb.append(connectionName);
+        sb.append(",connectionPassword=");
+        sb.append(connectionPassword);
+        sb.append("',connectionURL='");
+        sb.append(connectionURL);
+        sb.append("',rolePattern=");
+        sb.append(rolePattern);
+        sb.append(",roleBase=");
+        sb.append(roleBase);
+        sb.append("',userPassword='");
+        sb.append(userPassword);
+        sb.append(",userBase=");
+        sb.append(userBase);
+        sb.append("',userPattern=");
+        sb.append(userPattern);
+        sb.append("',userSearch=");
+        sb.append(userSearch);
+        sb.append(",contextFactory=");
+        sb.append(contextFactory);
+        sb.append("',objectName='");
+        sb.append(getObjectName());
+        sb.append("',realmType=");
+        sb.append(getRealmType());
+        sb.append("]");
+        return (sb.toString());
+
+    }
+
+    /**
+     * Validate the properties that have been set from this HTTP request,
+     * and return an <code>ActionErrors</code> object that encapsulates any
+     * validation errors that have been found.  If no errors are found, return
+     * <code>null</code> or an <code>ActionErrors</code> object with no
+     * recorded error messages.
+     *
+     * @param mapping The mapping used to select this instance
+     * @param request The servlet request we are processing
+     */
+
+    public ActionErrors validate(ActionMapping mapping,
+    HttpServletRequest request) {
+
+        ActionErrors errors = new ActionErrors();
+
+        String submit = request.getParameter("submit");
+
+        // front end validation when save is clicked.
+        //if (submit != null) {
+            // the following fields are required.
+
+            if ((connectionURL == null) || (connectionURL.length() < 1)) {
+                errors.add("connectionURL",
+                new ActionError("error.connURL.required"));
+            }
+
+            // Either userPattern or userSearch should be specified not both
+            boolean isUserPatternSpecified = false;
+            boolean isUserSearchSpecified = false;
+            if ((userPattern != null) && (userPattern.length() > 0)) {
+                isUserPatternSpecified = true;
+            }
+
+            if ((userSearch != null) && (userSearch.length() > 0)) {
+                isUserSearchSpecified = true;
+            }
+
+            if (isUserPatternSpecified && isUserSearchSpecified) {
+                errors.add("userPattern" ,
+                new ActionError("error.userPattern.userSearch.defined"));
+            }
+
+            /*if ((digest == null) || (digest.length() < 1)) {
+                errors.add("digest",
+                new ActionError("error.digest.required"));
+            } */
+
+            /*if ((roleName == null) || (roleName.length() < 1)) {
+                errors.add("roleName",
+                new ActionError("error.roleName.required"));
+            }
+
+            if ((userRoleName == null) || (userRoleName.length() < 1)) {
+                errors.add("userRoleName",
+                new ActionError("error.userRoleName.required"));
+            }
+
+            if ((rolePattern == null) || (rolePattern.length() < 1)) {
+                errors.add("rolePattern",
+                new ActionError("error.rolePattern.required"));
+            }
+
+            if ((roleBase == null) || (roleBase.length() < 1)) {
+                errors.add("roleBase",
+                new ActionError("error.roleBase.required"));
+            }
+
+            if ((userBase == null) || (userBase.length() < 1)) {
+                errors.add("userBase",
+                new ActionError("error.userBase.required"));
+            }
+
+            if ((userPassword == null) || (userPassword.length() < 1)) {
+                errors.add("userPassword",
+                new ActionError("error.userPassword.required"));
+            }
+
+            if ((userPattern == null) || (userPattern.length() < 1)) {
+                errors.add("userPattern",
+                new ActionError("error.userPattern.required"));
+            }
+
+            if ((userSearch == null) || (userSearch.length() < 1)) {
+                errors.add("userSearch",
+                new ActionError("error.userSearch.required"));
+            }
+
+            if ((connectionName == null) || (connectionName.length() < 1)) {
+                errors.add("connectionName",
+                new ActionError("error.connName.required"));
+            }
+
+            if ((connectionPassword == null) || (connectionPassword.length() < 1)) {
+                errors.add("connectionPassword",
+                new ActionError("error.connPassword.required"));
+            }
+
+            if ((contextFactory == null) || (contextFactory.length() < 1)) {
+                errors.add("contextFactory",
+                new ActionError("error.contextFactory.required"));
+            } */
+        //}
+
+        return errors;
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/realm/MemoryRealmForm.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/realm/MemoryRealmForm.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/realm/MemoryRealmForm.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,126 @@
+/*
+ * Copyright 2001,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.admin.realm;
+
+import javax.servlet.http.HttpServletRequest;
+import org.apache.struts.action.ActionError;
+import org.apache.struts.action.ActionErrors;
+import org.apache.struts.action.ActionForm;
+import org.apache.struts.action.ActionMapping;
+import java.util.List;
+import java.util.Enumeration;
+
+import org.apache.webapp.admin.ApplicationServlet;
+import org.apache.webapp.admin.LabelValueBean;
+
+/**
+ * Form bean for the memory realm page.
+ *
+ * @author Manveen Kaur
+ * @version $Revision: 302986 $ $Date: 2004-06-27 21:14:52 -0500 (Sun, 27 Jun 2004) $
+ */
+
+public final class MemoryRealmForm extends RealmForm {
+    
+    // ----------------------------------------------------- Instance Variables
+        
+    /**
+     * The text for the path Name.
+     */
+    private String pathName = null;
+       
+    // ------------------------------------------------------------- Properties
+        
+    /**
+     * Return the path Name.
+     */
+    public String getPathName() {
+        
+        return this.pathName;
+        
+    }
+    
+    /**
+     * Set the path Name.
+     */
+    public void setPathName(String pathName) {
+        
+        this.pathName = pathName;
+        
+    }
+        
+    // --------------------------------------------------------- Public Methods
+    
+    /**
+     * Reset all properties to their default values.
+     *
+     * @param mapping The mapping used to select this instance
+     * @param request The servlet request we are processing
+     */
+    public void reset(ActionMapping mapping, HttpServletRequest request) {
+   
+        super.reset(mapping, request);
+        this.pathName = null;
+        
+    }
+    
+   /**
+     * Render this object as a String.
+     */
+    public String toString() {
+
+        StringBuffer sb = new StringBuffer("UserDatabaseRealmForm[adminAction=");
+        sb.append(getAdminAction());
+        sb.append(",pathname=");
+        sb.append(pathName);
+        sb.append("',objectName='");
+        sb.append(getObjectName());
+        sb.append("',realmType=");
+        sb.append(getRealmType());
+        sb.append("]");
+        return (sb.toString());
+
+    }
+
+    /**
+     * Validate the properties that have been set from this HTTP request,
+     * and return an <code>ActionErrors</code> object that encapsulates any
+     * validation errors that have been found.  If no errors are found, return
+     * <code>null</code> or an <code>ActionErrors</code> object with no
+     * recorded error messages.
+     *
+     * @param mapping The mapping used to select this instance
+     * @param request The servlet request we are processing
+     */
+    
+    public ActionErrors validate(ActionMapping mapping,
+    HttpServletRequest request) {
+        
+        ActionErrors errors = new ActionErrors();
+
+        String submit = request.getParameter("submit");
+        
+        // front end validation when save is clicked.
+        //if (submit != null) {
+            if ((pathName == null) || (pathName.length()<1)) {
+                errors.add("pathName",
+                new ActionError("error.pathName.required"));
+            }
+        //}        
+        return errors;
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/realm/RealmForm.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/realm/RealmForm.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/realm/RealmForm.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,223 @@
+/*
+ * Copyright 2001,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.admin.realm;
+
+import javax.servlet.http.HttpServletRequest;
+import org.apache.struts.action.ActionError;
+import org.apache.struts.action.ActionErrors;
+import org.apache.struts.action.ActionForm;
+import org.apache.struts.action.ActionMapping;
+import java.net.InetAddress;
+import java.util.List;
+
+import org.apache.webapp.admin.ApplicationServlet;
+import org.apache.webapp.admin.LabelValueBean;
+
+/**
+ * Form bean for the generic realm page.
+ *
+ * @author Manveen Kaur
+ * @version $Revision: 302986 $ $Date: 2004-06-27 21:14:52 -0500 (Sun, 27 Jun 2004) $
+ */
+
+public class RealmForm extends ActionForm {
+    
+    // ----------------------------------------------------- Instance Variables
+    
+   /**
+     * The administrative action represented by this form.
+     */
+    private String adminAction = "Edit";
+
+    /**
+     * The object name of the realm this bean refers to.
+     */
+    private String objectName = null;
+    
+    /**
+     * The text for the realm type.
+     */
+    private String realmType = null;
+        
+    /**
+     * The text for the node label.
+     */
+    private String nodeLabel = null;
+    
+    /**
+     * The object name of the parent of this realm.
+     */
+    private String parentObjectName = null;
+        
+    /**
+     * Set of valid values for realms.
+     */
+    private List realmTypeVals = null;
+
+    /**
+     * The text for whether "delete this realm" operation is allowed
+     * on the realm or not.
+     */
+    private String allowDeletion = null;
+
+    // ------------------------------------------------------------- Properties
+
+   /**
+     * Return the administrative action represented by this form.
+     */
+    public String getAdminAction() {
+
+        return this.adminAction;
+
+    }
+
+    /**
+     * Set the administrative action represented by this form.
+     */
+    public void setAdminAction(String adminAction) {
+
+        this.adminAction = adminAction;
+
+    }
+
+    /**
+     * Return the Object Name.
+     */
+    public String getObjectName() {
+        
+        return this.objectName;
+        
+    }
+    
+    /**
+     * Set the Object Name.
+     */
+    public void setObjectName(String objectName) {
+        
+        this.objectName = objectName;
+        
+    }
+    
+    /**
+     * Return the realm type.
+     */
+    public String getRealmType() {
+        
+        return this.realmType;
+        
+    }
+    
+    /**
+     * Set the realm type.
+     */
+    public void setRealmType(String realmType) {
+        
+        this.realmType = realmType;
+        
+    }
+    
+    /**
+     * Return the label of the node that was clicked.
+     */
+    public String getNodeLabel() {
+        
+        return this.nodeLabel;
+        
+    }
+    
+    /**
+     * Set the node label.
+     */
+    public void setNodeLabel(String nodeLabel) {
+        
+        this.nodeLabel = nodeLabel;
+        
+    }
+    
+    /**
+     * Return the parent object name of the realm this bean refers to.
+     */
+    public String getParentObjectName() {
+
+        return this.parentObjectName;
+
+    }
+
+
+    /**
+     * Set the parent object name of the realm this bean refers to.
+     */
+    public void setParentObjectName(String parentObjectName) {
+
+        this.parentObjectName = parentObjectName;
+
+    }
+    
+        
+   /**
+     * Return the realmTypeVals.
+     */
+    public List getRealmTypeVals() {
+        
+        return this.realmTypeVals;
+        
+    }
+    
+    /**
+     * Set the realmTypeVals.
+     */
+    public void setRealmTypeVals(List realmTypeVals) {
+        
+        this.realmTypeVals = realmTypeVals;
+        
+    }
+    
+    /**
+     * Return the allow deletion value.
+     */
+    public String getAllowDeletion() {
+        
+        return this.allowDeletion;
+        
+    }
+    
+    /**
+     * Set the allow Deletion value.
+     */
+    public void setAllowDeletion(String allowDeletion) {
+        
+        this.allowDeletion = allowDeletion;
+        
+    }
+   
+    
+    // --------------------------------------------------------- Public Methods
+    
+    /**
+     * Reset all properties to their default values.
+     *
+     * @param mapping The mapping used to select this instance
+     * @param request The servlet request we are processing
+     */
+    public void reset(ActionMapping mapping, HttpServletRequest request) {
+        
+        objectName = null;
+        adminAction = "Edit";
+        
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/realm/RealmsForm.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/realm/RealmsForm.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/realm/RealmsForm.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.admin.realm;
+
+
+import javax.servlet.http.HttpServletRequest;
+import org.apache.struts.action.ActionForm;
+import org.apache.struts.action.ActionMapping;
+
+
+/**
+ * Form bean for deleting realms.
+ *
+ * @author Manveen Kaur
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class RealmsForm extends ActionForm {
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * The object names of the realms to be deleted.
+     */
+    private String realms[] = new String[0];
+
+    public String[] getRealms() {
+        return (this.realms);
+    }
+
+    public void setRealms(String realms[]) {
+        this.realms = realms;
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Reset all properties to their default values.
+     *
+     * @param mapping The mapping used to select this instance
+     * @param request The servlet request we are processing
+     */
+    public void reset(ActionMapping mapping, HttpServletRequest request) {
+
+        this.realms = new String[0];
+
+    }
+        
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/realm/SaveDataSourceRealmAction.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/realm/SaveDataSourceRealmAction.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/realm/SaveDataSourceRealmAction.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,285 @@
+/*
+ * Copyright 2001-2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.admin.realm;
+
+
+import java.net.URLEncoder;
+import java.util.Iterator;
+import java.util.Locale;
+import java.io.IOException;
+import javax.management.Attribute;
+import javax.management.MBeanServer;
+import javax.management.MBeanServerFactory;
+import javax.management.QueryExp;
+import javax.management.Query;
+import javax.management.ObjectInstance;
+import javax.management.ObjectName;
+import javax.management.JMException;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+import org.apache.struts.action.Action;
+import org.apache.struts.action.ActionError;
+import org.apache.struts.action.ActionErrors;
+import org.apache.struts.action.ActionForm;
+import org.apache.struts.action.ActionForward;
+import org.apache.struts.action.ActionMapping;
+import org.apache.struts.util.MessageResources;
+import org.apache.webapp.admin.ApplicationServlet;
+import org.apache.webapp.admin.TomcatTreeBuilder;
+import org.apache.webapp.admin.TreeControl;
+import org.apache.webapp.admin.TreeControlNode;
+import org.apache.webapp.admin.valve.ValveUtil;
+
+/**
+ * The <code>Action</code> that completes <em>Add Realm</em> and
+ * <em>Edit Realm</em> transactions for DataSource realm.
+ *
+ * @author Amy Roh
+ * @version $Revision: 303390 $ $Date: 2004-10-18 01:37:56 -0500 (Mon, 18 Oct 2004) $
+ */
+
+public final class SaveDataSourceRealmAction extends Action {
+
+
+    // ----------------------------------------------------- Instance Variables
+
+    /**
+     * Signature for the <code>createDataSourceRealm</code> operation.
+     */
+    private String createDataSourceRealmTypes[] =
+    { "java.lang.String",     // parent
+      "java.lang.String",     // dataSourceName
+      "java.lang.String",     // roleNameCol
+      "java.lang.String",     // userCredCol
+      "java.lang.String",     // userNameCol
+      "java.lang.String",     // userRoleTable
+      "java.lang.String",     // userTable
+    };
+
+
+    /**
+     * The MBeanServer we will be interacting with.
+     */
+    private MBeanServer mBServer = null;
+    
+
+    // --------------------------------------------------------- Public Methods
+    
+    
+    /**
+     * Process the specified HTTP request, and create the corresponding HTTP
+     * response (or forward to another web component that will create it).
+     * Return an <code>ActionForward</code> instance describing where and how
+     * control should be forwarded, or <code>null</code> if the response has
+     * already been completed.
+     *
+     * @param mapping The ActionMapping used to select this instance
+     * @param actionForm The optional ActionForm bean for this request (if any)
+     * @param request The HTTP request we are processing
+     * @param response The HTTP response we are creating
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception ServletException if a servlet exception occurs
+     */
+    public ActionForward execute(ActionMapping mapping,
+                                 ActionForm form,
+                                 HttpServletRequest request,
+                                 HttpServletResponse response)
+        throws IOException, ServletException {
+        
+        // Acquire the resources that we need
+        HttpSession session = request.getSession();
+        Locale locale = getLocale(request);
+        MessageResources resources = getResources(request);
+        
+        // Acquire a reference to the MBeanServer containing our MBeans
+        try {
+            mBServer = ((ApplicationServlet) getServlet()).getServer();
+        } catch (Throwable t) {
+            throw new ServletException
+            ("Cannot acquire MBeanServer reference", t);
+        }
+        
+        // Identify the requested action
+        DataSourceRealmForm rform = (DataSourceRealmForm) form;
+        String adminAction = rform.getAdminAction();
+        String rObjectName = rform.getObjectName();
+
+        // Perform a "Create DataSource Realm" transaction (if requested)
+        if ("Create".equals(adminAction)) {
+
+            String operation = null;
+            String values[] = null;
+
+            try {
+
+                String parent = rform.getParentObjectName();                
+                String objectName = ValveUtil.getObjectName(parent,
+                                    TomcatTreeBuilder.REALM_TYPE);
+                
+                ObjectName pname = new ObjectName(parent);
+                StringBuffer sb = new StringBuffer(pname.getDomain());                    
+                
+                // For service, create the corresponding Engine mBean  
+                // Parent in this case needs to be the container mBean for the service 
+                try {                                                        
+                    if ("Service".equalsIgnoreCase(pname.getKeyProperty("type"))) {
+                        sb.append(":type=Engine");
+                        parent = sb.toString();
+                    }
+                } catch (Exception e) {
+                    String message =
+                        resources.getMessage(locale, "error.engineName.bad",
+                                         sb.toString());
+                    getServlet().log(message);
+                    response.sendError(HttpServletResponse.SC_BAD_REQUEST, message);
+                    return (null);
+                }
+                                                
+                // Ensure that the requested user database name is unique
+                ObjectName oname =
+                    new ObjectName(objectName);
+                if (mBServer.isRegistered(oname)) {
+                    ActionErrors errors = new ActionErrors();
+                    errors.add("realmName",
+                               new ActionError("error.realmName.exists"));
+                    saveErrors(request, errors);
+                    return (new ActionForward(mapping.getInput()));
+                }
+
+                String domain = oname.getDomain();
+                // Look up our MBeanFactory MBean
+                ObjectName fname = 
+                    TomcatTreeBuilder.getMBeanFactory();
+
+                // Create a new DataSourceRealm object
+                values = new String[7];
+                values[0] = parent;
+		values[1] = rform.getDataSourceName();
+		values[2] = rform.getRoleNameCol();
+		values[3] = rform.getUserCredCol();
+		values[4] = rform.getUserNameCol();
+		values[5] = rform.getUserRoleTable();
+                values[6] = rform.getUserTable();
+                operation = "createDataSourceRealm";
+                rObjectName = (String)
+                    mBServer.invoke(fname, operation,
+                                    values, createDataSourceRealmTypes);
+                                    
+                if (rObjectName==null) {
+                    request.setAttribute("warning", "error.datasourcerealm");
+                    return (mapping.findForward("Save Unsuccessful"));
+                }
+
+                // Add the new Realm to our tree control node
+                TreeControl control = (TreeControl)
+                    session.getAttribute("treeControlTest");
+                if (control != null) {
+                    TreeControlNode parentNode = control.findNode(rform.getParentObjectName());
+                    if (parentNode != null) {
+                        String nodeLabel = rform.getNodeLabel();                        
+                        String encodedName =
+                            URLEncoder.encode(rObjectName,TomcatTreeBuilder.URL_ENCODING);
+                        TreeControlNode childNode =
+                            new TreeControlNode(rObjectName,
+                                                "Realm.gif",
+                                                nodeLabel,
+                                                "EditRealm.do?select=" +
+                                                encodedName,
+                                                "content",
+                                                true, domain);
+                        parentNode.addChild(childNode);
+                        // FIXME - force a redisplay
+                    } else {
+                        getServlet().log
+                            ("Cannot find parent node '" + parent + "'");
+                    }
+                } else {
+                    getServlet().log
+                        ("Cannot find TreeControlNode!");
+                }
+
+            } catch (Exception e) {
+
+                getServlet().log
+                    (resources.getMessage(locale, "users.error.invoke",
+                                          operation), e);
+                response.sendError
+                    (HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
+                     resources.getMessage(locale, "users.error.invoke",
+                                          operation));
+                return (null);
+
+            }
+
+        }
+
+        // Perform attribute updates as requested
+        String attribute = null;
+        try {
+
+            ObjectName roname = new ObjectName(rObjectName);
+
+            attribute = "dataSourceName";
+            mBServer.setAttribute(roname,
+                                  new Attribute(attribute, rform.getDataSourceName()));
+
+            attribute = "digest";
+            mBServer.setAttribute(roname,
+                                  new Attribute("digest",  rform.getDigest()));
+
+            attribute = "roleNameCol";
+            mBServer.setAttribute(roname,
+                                  new Attribute("roleNameCol",  rform.getRoleNameCol()));
+
+            attribute = "userCredCol";
+            mBServer.setAttribute(roname,
+                                  new Attribute("userCredCol",  rform.getUserCredCol()));
+
+            attribute = "userNameCol";
+            mBServer.setAttribute(roname,
+                                  new Attribute("userNameCol",  rform.getUserNameCol()));
+
+            attribute = "userRoleTable";
+            mBServer.setAttribute(roname,
+                                  new Attribute("userRoleTable",  rform.getUserRoleTable()));
+
+            attribute = "userTable";
+            mBServer.setAttribute(roname,
+                                  new Attribute("userTable",  rform.getUserTable()));
+            
+        } catch (Exception e) {
+
+            getServlet().log
+                (resources.getMessage(locale, "users.error.attribute.set",
+                                      attribute), e);
+            response.sendError
+                (HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
+                 resources.getMessage(locale, "users.error.attribute.set",
+                                      attribute));
+            return (null);
+        }
+        
+        // Forward to the success reporting page
+        session.removeAttribute(mapping.getAttribute());
+        return (mapping.findForward("Save Successful"));
+        
+    }
+    
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/realm/SaveJDBCRealmAction.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/realm/SaveJDBCRealmAction.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/realm/SaveJDBCRealmAction.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,319 @@
+/*
+ * Copyright 2001-2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.admin.realm;
+
+
+import java.net.URLEncoder;
+import java.util.Iterator;
+import java.util.Locale;
+import java.io.IOException;
+import javax.management.Attribute;
+import javax.management.MBeanServer;
+import javax.management.MBeanServerFactory;
+import javax.management.QueryExp;
+import javax.management.Query;
+import javax.management.ObjectInstance;
+import javax.management.ObjectName;
+import javax.management.JMException;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+import org.apache.struts.action.Action;
+import org.apache.struts.action.ActionError;
+import org.apache.struts.action.ActionErrors;
+import org.apache.struts.action.ActionForm;
+import org.apache.struts.action.ActionForward;
+import org.apache.struts.action.ActionMapping;
+import org.apache.struts.util.MessageResources;
+import org.apache.webapp.admin.ApplicationServlet;
+import org.apache.webapp.admin.TomcatTreeBuilder;
+import org.apache.webapp.admin.TreeControl;
+import org.apache.webapp.admin.TreeControlNode;
+import org.apache.webapp.admin.valve.ValveUtil;
+
+/**
+ * The <code>Action</code> that completes <em>Add Realm</em> and
+ * <em>Edit Realm</em> transactions for JDBC realm.
+ *
+ * @author Manveen Kaur
+ * @version $Revision: 304016 $ $Date: 2005-07-22 08:47:53 -0500 (Fri, 22 Jul 2005) $
+ */
+
+public final class SaveJDBCRealmAction extends Action {
+
+
+    // ----------------------------------------------------- Instance Variables
+
+    /**
+     * Signature for the <code>createStandardRealm</code> operation.
+     */
+    private String createStandardRealmTypes[] =
+    { "java.lang.String",     // parent
+      "java.lang.String",     // driverName
+      "java.lang.String",     // connectionName
+      "java.lang.String",     // connectionPassword
+      "java.lang.String",     // connectionURL
+    };
+
+
+    /**
+     * The MBeanServer we will be interacting with.
+     */
+    private MBeanServer mBServer = null;
+    
+
+    // --------------------------------------------------------- Public Methods
+    
+    
+    /**
+     * Process the specified HTTP request, and create the corresponding HTTP
+     * response (or forward to another web component that will create it).
+     * Return an <code>ActionForward</code> instance describing where and how
+     * control should be forwarded, or <code>null</code> if the response has
+     * already been completed.
+     *
+     * @param mapping The ActionMapping used to select this instance
+     * @param actionForm The optional ActionForm bean for this request (if any)
+     * @param request The HTTP request we are processing
+     * @param response The HTTP response we are creating
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception ServletException if a servlet exception occurs
+     */
+    public ActionForward execute(ActionMapping mapping,
+                                 ActionForm form,
+                                 HttpServletRequest request,
+                                 HttpServletResponse response)
+        throws IOException, ServletException {
+        
+        // Acquire the resources that we need
+        HttpSession session = request.getSession();
+        Locale locale = getLocale(request);
+        MessageResources resources = getResources(request);
+        
+        // Acquire a reference to the MBeanServer containing our MBeans
+        try {
+            mBServer = ((ApplicationServlet) getServlet()).getServer();
+        } catch (Throwable t) {
+            throw new ServletException
+            ("Cannot acquire MBeanServer reference", t);
+        }
+        
+        // Identify the requested action
+        JDBCRealmForm rform = (JDBCRealmForm) form;
+        String adminAction = rform.getAdminAction();
+        String rObjectName = rform.getObjectName();
+
+        // Perform a "Create JDBC Realm" transaction (if requested)
+        if ("Create".equals(adminAction)) {
+
+            String operation = null;
+            String values[] = null;
+
+            try {
+
+                String parent = rform.getParentObjectName();                
+                String objectName = ValveUtil.getObjectName(parent,
+                                    TomcatTreeBuilder.REALM_TYPE);
+                
+                ObjectName pname = new ObjectName(parent);
+                StringBuffer sb = new StringBuffer(pname.getDomain());                    
+                
+                // For service, create the corresponding Engine mBean  
+                // Parent in this case needs to be the container mBean for the service 
+                try {                                                        
+                    if ("Service".equalsIgnoreCase(pname.getKeyProperty("type"))) {
+                        sb.append(":type=Engine");
+                        parent = sb.toString();
+                    }
+                } catch (Exception e) {
+                    String message =
+                        resources.getMessage(locale, "error.engineName.bad",
+                                         sb.toString());
+                    getServlet().log(message);
+                    response.sendError(HttpServletResponse.SC_BAD_REQUEST, message);
+                    return (null);
+                }
+                                                
+                // Ensure that the requested user database name is unique
+                ObjectName oname =
+                    new ObjectName(objectName);
+                if (mBServer.isRegistered(oname)) {
+                    ActionErrors errors = new ActionErrors();
+                    errors.add("realmName",
+                               new ActionError("error.realmName.exists"));
+                    saveErrors(request, errors);
+                    return (new ActionForward(mapping.getInput()));
+                }
+
+                String domain = oname.getDomain();
+                // Look up our MBeanFactory MBean
+                ObjectName fname = 
+                    TomcatTreeBuilder.getMBeanFactory();
+
+                // Create a new StandardRealm object
+                values = new String[5];
+                values[0] = parent;
+		values[1] = rform.getDriver();
+		values[2] = rform.getConnectionName();
+		values[3] = rform.getConnectionPassword();
+		values[4] = rform.getConnectionURL();
+                operation = "createJDBCRealm";
+                rObjectName = (String)
+                    mBServer.invoke(fname, operation,
+                                    values, createStandardRealmTypes);
+                                    
+                if (rObjectName==null) {
+                    request.setAttribute("warning", "error.jdbcrealm");
+                    return (mapping.findForward("Save Unsuccessful"));
+                }
+
+                // Add the new Realm to our tree control node
+                TreeControl control = (TreeControl)
+                    session.getAttribute("treeControlTest");
+                if (control != null) {
+                    TreeControlNode parentNode = control.findNode(rform.getParentObjectName());
+                    if (parentNode != null) {
+                        String nodeLabel = rform.getNodeLabel();                        
+                        String encodedName =
+                            URLEncoder.encode(rObjectName,TomcatTreeBuilder.URL_ENCODING);
+                        TreeControlNode childNode =
+                            new TreeControlNode(rObjectName,
+                                                "Realm.gif",
+                                                nodeLabel,
+                                                "EditRealm.do?select=" +
+                                                encodedName,
+                                                "content",
+                                                true, domain);
+                        parentNode.addChild(childNode);
+                        // FIXME - force a redisplay
+                    } else {
+                        getServlet().log
+                            ("Cannot find parent node '" + parent + "'");
+                    }
+                } else {
+                    getServlet().log
+                        ("Cannot find TreeControlNode!");
+                }
+
+            } catch (Exception e) {
+
+                getServlet().log
+                    (resources.getMessage(locale, "users.error.invoke",
+                                          operation), e);
+                response.sendError
+                    (HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
+                     resources.getMessage(locale, "users.error.invoke",
+                                          operation));
+                return (null);
+
+            }
+
+        }
+
+        // Perform attribute updates as requested
+        String attribute = null;
+        String value = null;
+
+        try {
+
+            ObjectName roname = new ObjectName(rObjectName);
+
+            attribute = "digest";
+            value = rform.getDigest();
+            setAttributeIfPresent(mBServer, roname, attribute, value);
+
+            attribute = "driverName";
+            value = rform.getDriver();
+            setAttributeIfPresent(mBServer, roname, attribute, value);
+
+            attribute = "roleNameCol";
+            value = rform.getRoleNameCol();
+            setAttributeIfPresent(mBServer, roname, attribute, value);
+
+            attribute = "userNameCol";
+            value = rform.getUserNameCol();
+            setAttributeIfPresent(mBServer, roname, attribute, value);
+
+            attribute = "userCredCol";
+            value = rform.getPasswordCol();
+            setAttributeIfPresent(mBServer, roname, attribute, value);
+
+            attribute = "userTable";
+            value = rform.getUserTable();
+            setAttributeIfPresent(mBServer, roname, attribute, value);
+
+            attribute = "userRoleTable";
+            value = rform.getRoleTable();
+            setAttributeIfPresent(mBServer, roname, attribute, value);
+
+            attribute = "connectionName";
+            value = rform.getConnectionName();
+            setAttributeIfPresent(mBServer, roname, attribute, value);
+
+            attribute = "connectionURL";
+            value = rform.getConnectionURL();
+            setAttributeIfPresent(mBServer, roname, attribute, value);
+
+            attribute = "connectionPassword";
+            value = rform.getConnectionPassword();
+            setAttributeIfPresent(mBServer, roname, attribute, value);
+
+        } catch (Exception e) {
+
+            getServlet().log
+                (resources.getMessage(locale, "users.error.attribute.set",
+                                      attribute), e);
+            response.sendError
+                (HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
+                 resources.getMessage(locale, "users.error.attribute.set",
+                                      attribute));
+            return (null);
+        }
+        
+        // Forward to the success reporting page
+        session.removeAttribute(mapping.getAttribute());
+        return (mapping.findForward("Save Successful"));
+        
+    }
+
+    /**
+     * Sets the given attribute to the given value
+     * in the given server's object name, if the value
+     * is not null or empty.
+     *
+     * @param theServer The server
+     * @param roname The object name
+     * @param attribute The attribute name
+     * @param value The attribute value
+     * @throws JMException If a JMX error occurs
+     */
+    protected void setAttributeIfPresent(MBeanServer mBServer, ObjectName roname, String attribute, String value)
+        throws JMException {
+
+        if((mBServer == null) || (roname == null) || (attribute == null)) {
+            throw new IllegalArgumentException("MBeanServer, ObjectName, attribute required.");
+        }
+
+        if((value != null) && (value.trim().length() > 0)) {
+            mBServer.setAttribute(roname,
+                                  new Attribute(attribute,  value));
+        }
+    }
+    
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/realm/SaveJNDIRealmAction.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/realm/SaveJNDIRealmAction.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/realm/SaveJNDIRealmAction.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,357 @@
+/*
+ * Copyright 2001-2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.admin.realm;
+
+
+import java.net.URLEncoder;
+import java.util.Iterator;
+import java.util.Locale;
+import java.io.IOException;
+import javax.management.Attribute;
+import javax.management.MBeanServer;
+import javax.management.MBeanServerFactory;
+import javax.management.QueryExp;
+import javax.management.Query;
+import javax.management.ObjectInstance;
+import javax.management.ObjectName;
+import javax.management.JMException;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+import org.apache.struts.action.Action;
+import org.apache.struts.action.ActionError;
+import org.apache.struts.action.ActionErrors;
+import org.apache.struts.action.ActionForm;
+import org.apache.struts.action.ActionForward;
+import org.apache.struts.action.ActionMapping;
+import org.apache.struts.util.MessageResources;
+import org.apache.webapp.admin.ApplicationServlet;
+import org.apache.webapp.admin.TomcatTreeBuilder;
+import org.apache.webapp.admin.TreeControl;
+import org.apache.webapp.admin.TreeControlNode;
+import org.apache.webapp.admin.valve.ValveUtil;
+
+/**
+ * The <code>Action</code> that completes <em>Add Realm</em> and
+ * <em>Edit Realm</em> transactions for JNDI realm.
+ *
+ * @author Manveen Kaur
+ * @author Amy Roh
+ * @version $Revision: 440749 $ $Date: 2006-09-06 11:06:18 -0500 (Wed, 06 Sep 2006) $
+ */
+
+public final class SaveJNDIRealmAction extends Action {
+
+
+    // ----------------------------------------------------- Instance Variables
+
+    /**
+     * Signature for the <code>createStandardRealm</code> operation.
+     */
+    private String createStandardRealmTypes[] =
+    { "java.lang.String",     // parent
+      "java.lang.String", //Connection URL
+      "java.lang.String", //Connection name
+      "java.lang.String", //Connection password
+    };
+
+
+    /**
+     * The MBeanServer we will be interacting with.
+     */
+    private MBeanServer mBServer = null;
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Process the specified HTTP request, and create the corresponding HTTP
+     * response (or forward to another web component that will create it).
+     * Return an <code>ActionForward</code> instance describing where and how
+     * control should be forwarded, or <code>null</code> if the response has
+     * already been completed.
+     *
+     * @param mapping The ActionMapping used to select this instance
+     * @param actionForm The optional ActionForm bean for this request (if any)
+     * @param request The HTTP request we are processing
+     * @param response The HTTP response we are creating
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception ServletException if a servlet exception occurs
+     */
+    public ActionForward execute(ActionMapping mapping,
+                                 ActionForm form,
+                                 HttpServletRequest request,
+                                 HttpServletResponse response)
+        throws IOException, ServletException {
+
+        // Acquire the resources that we need
+        HttpSession session = request.getSession();
+        Locale locale = getLocale(request);
+        MessageResources resources = getResources(request);
+
+        // Acquire a reference to the MBeanServer containing our MBeans
+        try {
+            mBServer = ((ApplicationServlet) getServlet()).getServer();
+        } catch (Throwable t) {
+            throw new ServletException
+            ("Cannot acquire MBeanServer reference", t);
+        }
+
+        // Identify the requested action
+        JNDIRealmForm rform = (JNDIRealmForm) form;
+        String adminAction = rform.getAdminAction();
+        String rObjectName = rform.getObjectName();
+
+        // Perform a "Create JNDI Realm" transaction (if requested)
+        if ("Create".equals(adminAction)) {
+
+            String operation = null;
+            String values[] = null;
+
+            try {
+
+                String parent = rform.getParentObjectName();
+                String objectName = ValveUtil.getObjectName(parent,
+                                    TomcatTreeBuilder.REALM_TYPE);
+
+                ObjectName pname = new ObjectName(parent);
+                StringBuffer sb = new StringBuffer(pname.getDomain());
+
+                // For service, create the corresponding Engine mBean
+                // Parent in this case needs to be the container mBean for the service
+                try {
+                    if ("Service".equalsIgnoreCase(pname.getKeyProperty("type"))) {
+                        sb.append(":type=Engine");
+                        parent = sb.toString();
+                    }
+                } catch (Exception e) {
+                    String message =
+                        resources.getMessage("error.engineName.bad",
+                                         sb.toString());
+                    getServlet().log(message);
+                    response.sendError(HttpServletResponse.SC_BAD_REQUEST, message);
+                    return (null);
+                }
+
+                // Ensure that the requested user database name is unique
+                ObjectName oname =
+                    new ObjectName(objectName);
+                if (mBServer.isRegistered(oname)) {
+                    ActionErrors errors = new ActionErrors();
+                    errors.add("realmName",
+                               new ActionError("error.realmName.exists"));
+                    saveErrors(request, errors);
+                    return (new ActionForward(mapping.getInput()));
+                }
+
+                String domain = oname.getDomain();
+                // Look up our MBeanFactory MBean
+                ObjectName fname = 
+                    TomcatTreeBuilder.getMBeanFactory();
+
+                // Create a new StandardRealm object
+                values = new String[4];
+                values[0] = parent;
+                values[1] = rform.getConnectionURL();
+                values[2] = rform.getConnectionName();
+                values[3] = rform.getConnectionPassword();
+                operation = "createJNDIRealm";
+                rObjectName = (String)
+                    mBServer.invoke(fname, operation,
+                                    values, createStandardRealmTypes);
+
+                if (rObjectName==null) {
+                    request.setAttribute("warning", "error.jndirealm");
+                    return (mapping.findForward("Save Unsuccessful"));
+                }
+                
+                // Add the new Realm to our tree control node
+                TreeControl control = (TreeControl)
+                    session.getAttribute("treeControlTest");
+                if (control != null) {
+                    TreeControlNode parentNode = control.findNode(rform.getParentObjectName());
+                    if (parentNode != null) {
+                        String nodeLabel = rform.getNodeLabel();
+                        String encodedName =
+                            URLEncoder.encode(rObjectName,TomcatTreeBuilder.URL_ENCODING);
+                        TreeControlNode childNode =
+                            new TreeControlNode(rObjectName,
+                                                "Realm.gif",
+                                                nodeLabel,
+                                                "EditRealm.do?select=" +
+                                                encodedName,
+                                                "content",
+                                                true, domain);
+                        parentNode.addChild(childNode);
+                        // FIXME - force a redisplay
+                    } else {
+                        getServlet().log
+                            ("Cannot find parent node '" + parent + "'");
+                    }
+                } else {
+                    getServlet().log
+                        ("Cannot find TreeControlNode!");
+                }
+
+            } catch (Exception e) {
+
+                getServlet().log
+                    (resources.getMessage(locale, "users.error.invoke",
+                                          operation), e);
+                response.sendError
+                    (HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
+                     resources.getMessage(locale, "users.error.invoke",
+                                          operation));
+                return (null);
+
+            }
+
+        }
+
+        // Perform attribute updates as requested
+        String attribute = null;
+        try {
+
+            ObjectName roname = new ObjectName(rObjectName);
+
+            attribute = "connectionName";
+            String connectionName = rform.getConnectionName();
+            if ((connectionName != null) && (connectionName.length()>0)) {
+                mBServer.setAttribute(roname,
+                        new Attribute("connectionName",  connectionName));
+            }
+
+            attribute = "connectionPassword";
+            String connectionPassword = rform.getConnectionPassword();
+            if ((connectionPassword != null) && (connectionPassword.length()>0)) {
+                mBServer.setAttribute(roname,
+                        new Attribute("connectionPassword",  connectionPassword));
+            }
+
+            attribute = "connectionURL";
+            String connectionURL = rform.getConnectionURL();
+            if ((connectionURL != null) && (connectionURL.length()>0)) {
+                mBServer.setAttribute(roname,
+                        new Attribute("connectionURL",  connectionURL));
+            }
+
+            attribute = "contextFactory";
+            String contextFactory = rform.getContextFactory();
+            if ((contextFactory != null) && (contextFactory.length()>0)) {
+                mBServer.setAttribute(roname,
+                        new Attribute("contextFactory",  contextFactory));
+            }
+
+            attribute = "digest";
+            String digest = rform.getDigest();
+            if ((digest != null) && (digest.length()>0)) {
+                mBServer.setAttribute(roname,
+                                        new Attribute("digest", digest));
+            }
+
+            attribute = "roleBase";
+            String roleBase = rform.getRoleBase();
+            if ((roleBase != null) && (roleBase.length()>0)) {
+                mBServer.setAttribute(roname,
+                        new Attribute("roleBase",  roleBase));
+            }
+
+            attribute = "roleName";
+            String roleName = rform.getRoleName();
+            if ((roleName != null) && (roleName.length()>0)) {
+                mBServer.setAttribute(roname,
+                        new Attribute("roleName",  roleName));
+            }
+
+            attribute = "roleSearch";
+            String rolePattern = rform.getRolePattern();
+            if ((rolePattern != null) && (rolePattern.length()>0)) {
+                mBServer.setAttribute(roname,
+                        new Attribute("roleSearch",  rolePattern));
+            }
+
+            attribute = "roleSubtree";
+            String roleSubtree = rform.getRoleSubtree();
+            if ((roleSubtree != null) && (roleSubtree.length()>0)) {
+                mBServer.setAttribute(roname,
+                    new Attribute("roleSubtree",  new Boolean(roleSubtree)));
+            }
+
+            attribute = "userBase";
+            String userBase = rform.getUserBase();
+            if ((userBase != null) && (userBase.length()>0)) {
+                mBServer.setAttribute(roname,
+                        new Attribute("userBase",  userBase));
+            }
+
+            attribute = "userPassword";
+            String userPassword = rform.getUserPassword();
+            if ((userPassword != null) && (userPassword.length()>0)) {
+                mBServer.setAttribute(roname,
+                        new Attribute("userPassword",  userPassword));
+            }
+
+            attribute = "userPattern";
+            String userPattern = rform.getUserPattern();
+            if ((userPattern != null) && (userPattern.length()>0)) {
+                mBServer.setAttribute(roname,
+                        new Attribute("userPattern",  userPattern));
+            }
+
+            attribute = "userRoleName";
+            String userRoleName = rform.getUserRoleName();
+            if ((userRoleName != null) && (userRoleName.length()>0)) {
+                mBServer.setAttribute(roname,
+                        new Attribute("userRoleName",  userRoleName));
+            }
+
+            attribute = "userSearch";
+            String userSearch = rform.getUserSearch();
+            if ((userSearch != null) && (userSearch.length()>0)) {
+                mBServer.setAttribute(roname,
+                        new Attribute("userSearch",  userSearch));
+            }
+
+            attribute = "userSubtree";
+            String userSubtree = rform.getUserSubtree();
+            if ((userSubtree != null) && (userSubtree.length()>0)) {
+                mBServer.setAttribute(roname,
+                    new Attribute("userSubtree",  new Boolean(userSubtree)));
+            }
+
+        } catch (Exception e) {
+
+            getServlet().log
+                (resources.getMessage(locale, "users.error.attribute.set",
+                                      attribute), e);
+            response.sendError
+                (HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
+                 resources.getMessage(locale, "users.error.attribute.set",
+                                      attribute));
+            return (null);
+        }
+
+        // Forward to the success reporting page
+        session.removeAttribute(mapping.getAttribute());
+        return (mapping.findForward("Save Successful"));
+
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/realm/SaveMemoryRealmAction.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/realm/SaveMemoryRealmAction.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/realm/SaveMemoryRealmAction.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,243 @@
+/*
+ * Copyright 2001-2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.admin.realm;
+
+
+import java.net.URLEncoder;
+import java.util.Iterator;
+import java.util.Locale;
+import java.io.IOException;
+import javax.management.Attribute;
+import javax.management.MBeanServer;
+import javax.management.MBeanServerFactory;
+import javax.management.QueryExp;
+import javax.management.Query;
+import javax.management.ObjectInstance;
+import javax.management.ObjectName;
+import javax.management.JMException;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+import org.apache.struts.action.Action;
+import org.apache.struts.action.ActionError;
+import org.apache.struts.action.ActionErrors;
+import org.apache.struts.action.ActionForm;
+import org.apache.struts.action.ActionForward;
+import org.apache.struts.action.ActionMapping;
+import org.apache.struts.util.MessageResources;
+import org.apache.webapp.admin.ApplicationServlet;
+import org.apache.webapp.admin.TomcatTreeBuilder;
+import org.apache.webapp.admin.TreeControl;
+import org.apache.webapp.admin.TreeControlNode;
+import org.apache.webapp.admin.valve.ValveUtil;
+
+/**
+ * The <code>Action</code> that completes <em>Add Realm</em> and
+ * <em>Edit Realm</em> transactions for Memory realm.
+ *
+ * @author Manveen Kaur
+ * @version $Revision: 303390 $ $Date: 2004-10-18 01:37:56 -0500 (Mon, 18 Oct 2004) $
+ */
+
+public final class SaveMemoryRealmAction extends Action {
+
+
+    // ----------------------------------------------------- Instance Variables
+
+    /**
+     * Signature for the <code>createStandardRealm</code> operation.
+     */
+    private String createStandardRealmTypes[] =
+    { "java.lang.String",     // parent
+    };
+
+
+    /**
+     * The MBeanServer we will be interacting with.
+     */
+    private MBeanServer mBServer = null;
+    
+
+    // --------------------------------------------------------- Public Methods
+    
+    
+    /**
+     * Process the specified HTTP request, and create the corresponding HTTP
+     * response (or forward to another web component that will create it).
+     * Return an <code>ActionForward</code> instance describing where and how
+     * control should be forwarded, or <code>null</code> if the response has
+     * already been completed.
+     *
+     * @param mapping The ActionMapping used to select this instance
+     * @param actionForm The optional ActionForm bean for this request (if any)
+     * @param request The HTTP request we are processing
+     * @param response The HTTP response we are creating
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception ServletException if a servlet exception occurs
+     */
+    public ActionForward execute(ActionMapping mapping,
+                                 ActionForm form,
+                                 HttpServletRequest request,
+                                 HttpServletResponse response)
+        throws IOException, ServletException {
+        
+        // Acquire the resources that we need
+        HttpSession session = request.getSession();
+        Locale locale = getLocale(request);
+        MessageResources resources = getResources(request);
+        
+        // Acquire a reference to the MBeanServer containing our MBeans
+        try {
+            mBServer = ((ApplicationServlet) getServlet()).getServer();
+        } catch (Throwable t) {
+            throw new ServletException
+            ("Cannot acquire MBeanServer reference", t);
+        }
+        
+        // Identify the requested action
+        MemoryRealmForm rform = (MemoryRealmForm) form;
+        String adminAction = rform.getAdminAction();
+        String rObjectName = rform.getObjectName();
+
+        // Perform a "Create Memory Realm" transaction (if requested)
+        if ("Create".equals(adminAction)) {
+
+            String operation = null;
+            String values[] = null;
+
+            try {
+
+                String parent = rform.getParentObjectName();                
+                String objectName = ValveUtil.getObjectName(parent,
+                                    TomcatTreeBuilder.REALM_TYPE);
+                
+                ObjectName pname = new ObjectName(parent);
+                StringBuffer sb = new StringBuffer(pname.getDomain());                    
+                
+                // For service, create the corresponding Engine mBean  
+                // Parent in this case needs to be the container mBean for the service 
+                try {                                                        
+                    if ("Service".equalsIgnoreCase(pname.getKeyProperty("type"))) {
+                        sb.append(":type=Engine");
+                        parent = sb.toString();
+                    }
+                } catch (Exception e) {
+                    String message =
+                        resources.getMessage(locale, "error.engineName.bad",
+                                         sb.toString());
+                    getServlet().log(message);
+                    response.sendError(HttpServletResponse.SC_BAD_REQUEST, message);
+                    return (null);
+                }
+                                                
+                // Ensure that the requested user database name is unique
+                ObjectName oname =
+                    new ObjectName(objectName);
+                if (mBServer.isRegistered(oname)) {
+                    ActionErrors errors = new ActionErrors();
+                    errors.add("realmName",
+                               new ActionError("error.realmName.exists"));
+                    saveErrors(request, errors);
+                    return (new ActionForward(mapping.getInput()));
+                }
+
+                String domain = oname.getDomain();
+                // Look up our MBeanFactory MBean
+                ObjectName fname = TomcatTreeBuilder.getMBeanFactory();
+
+                // Create a new StandardRealm object
+                values = new String[1];
+                values[0] = parent;
+                operation = "createMemoryRealm";
+                rObjectName = (String)
+                    mBServer.invoke(fname, operation,
+                                    values, createStandardRealmTypes);
+                                    
+                // Add the new Realm to our tree control node
+                TreeControl control = (TreeControl)
+                    session.getAttribute("treeControlTest");
+                if (control != null) {
+                    TreeControlNode parentNode = control.findNode(rform.getParentObjectName());
+                    if (parentNode != null) {
+                        String nodeLabel = rform.getNodeLabel();                        
+                        String encodedName =
+                            URLEncoder.encode(rObjectName,TomcatTreeBuilder.URL_ENCODING);
+                        TreeControlNode childNode =
+                            new TreeControlNode(rObjectName,
+                                                "Realm.gif",
+                                                nodeLabel,
+                                                "EditRealm.do?select=" +
+                                                encodedName,
+                                                "content",
+                                                true, domain);
+                        parentNode.addChild(childNode);
+                        // FIXME - force a redisplay
+                    } else {
+                        getServlet().log
+                            ("Cannot find parent node '" + parent + "'");
+                    }
+                } else {
+                    getServlet().log
+                        ("Cannot find TreeControlNode!");
+                }
+
+            } catch (Exception e) {
+
+                getServlet().log
+                    (resources.getMessage(locale, "users.error.invoke",
+                                          operation), e);
+                response.sendError
+                    (HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
+                     resources.getMessage(locale, "users.error.invoke",
+                                          operation));
+                return (null);
+
+            }
+
+        }
+
+        // Perform attribute updates as requested
+        String attribute = null;
+        try {
+
+            ObjectName roname = new ObjectName(rObjectName);
+
+            attribute = "pathname";
+            mBServer.setAttribute(roname,
+                                  new Attribute("pathname",  rform.getPathName()));
+
+        } catch (Exception e) {
+
+            getServlet().log
+                (resources.getMessage(locale, "users.error.attribute.set",
+                                      attribute), e);
+            response.sendError
+                (HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
+                 resources.getMessage(locale, "users.error.attribute.set",
+                                      attribute));
+            return (null);
+        }
+        
+        // Forward to the success reporting page
+        session.removeAttribute(mapping.getAttribute());
+        return (mapping.findForward("Save Successful"));
+        
+    }
+    
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/realm/SaveUserDatabaseRealmAction.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/realm/SaveUserDatabaseRealmAction.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/realm/SaveUserDatabaseRealmAction.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,249 @@
+/*
+ * Copyright 2001-2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.admin.realm;
+
+
+import java.net.URLEncoder;
+import java.util.Iterator;
+import java.util.Locale;
+import java.io.IOException;
+import javax.management.Attribute;
+import javax.management.MBeanServer;
+import javax.management.MBeanServerFactory;
+import javax.management.QueryExp;
+import javax.management.Query;
+import javax.management.ObjectInstance;
+import javax.management.ObjectName;
+import javax.management.JMException;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+import org.apache.struts.action.Action;
+import org.apache.struts.action.ActionError;
+import org.apache.struts.action.ActionErrors;
+import org.apache.struts.action.ActionForm;
+import org.apache.struts.action.ActionForward;
+import org.apache.struts.action.ActionMapping;
+import org.apache.struts.util.MessageResources;
+import org.apache.webapp.admin.ApplicationServlet;
+import org.apache.webapp.admin.TomcatTreeBuilder;
+import org.apache.webapp.admin.TreeControl;
+import org.apache.webapp.admin.TreeControlNode;
+import org.apache.webapp.admin.valve.ValveUtil;
+
+/**
+ * The <code>Action</code> that completes <em>Add Realm</em> and
+ * <em>Edit Realm</em> transactions for UserDatabase realm.
+ *
+ * @author Manveen Kaur
+ * @version $Revision: 303390 $ $Date: 2004-10-18 01:37:56 -0500 (Mon, 18 Oct 2004) $
+ */
+
+public final class SaveUserDatabaseRealmAction extends Action {
+
+
+    // ----------------------------------------------------- Instance Variables
+
+    /**
+     * Signature for the <code>createUserDatabaseRealm</code> operation.
+     */
+    private String createUserDatabaseRealmTypes[] =
+    { "java.lang.String",     // parent
+      "java.lang.String",     // name
+    };
+
+
+    /**
+     * The MBeanServer we will be interacting with.
+     */
+    private MBeanServer mBServer = null;
+    
+
+    // --------------------------------------------------------- Public Methods
+    
+    
+    /**
+     * Process the specified HTTP request, and create the corresponding HTTP
+     * response (or forward to another web component that will create it).
+     * Return an <code>ActionForward</code> instance describing where and how
+     * control should be forwarded, or <code>null</code> if the response has
+     * already been completed.
+     *
+     * @param mapping The ActionMapping used to select this instance
+     * @param actionForm The optional ActionForm bean for this request (if any)
+     * @param request The HTTP request we are processing
+     * @param response The HTTP response we are creating
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception ServletException if a servlet exception occurs
+     */
+    public ActionForward execute(ActionMapping mapping,
+                                 ActionForm form,
+                                 HttpServletRequest request,
+                                 HttpServletResponse response)
+        throws IOException, ServletException {
+        
+        // Acquire the resources that we need
+        HttpSession session = request.getSession();
+        Locale locale = getLocale(request);
+        MessageResources resources = getResources(request);
+        
+        // Acquire a reference to the MBeanServer containing our MBeans
+        try {
+            mBServer = ((ApplicationServlet) getServlet()).getServer();
+        } catch (Throwable t) {
+            throw new ServletException
+            ("Cannot acquire MBeanServer reference", t);
+        }
+        
+        // Identify the requested action
+        UserDatabaseRealmForm rform = (UserDatabaseRealmForm) form;
+        String adminAction = rform.getAdminAction();
+        String rObjectName = rform.getObjectName();
+
+        // Perform a "Create UserDatabase Realm" transaction (if requested)
+        if ("Create".equals(adminAction)) {
+
+            String operation = null;
+            String values[] = null;
+
+            try {
+
+                String parent = rform.getParentObjectName();                
+                String objectName = ValveUtil.getObjectName(parent,
+                                    TomcatTreeBuilder.REALM_TYPE);
+                
+                ObjectName pname = new ObjectName(parent);
+                StringBuffer sb = new StringBuffer(pname.getDomain());                    
+                
+                // For service, create the corresponding Engine mBean  
+                // Parent in this case needs to be the container mBean for the service 
+                try {                                                        
+                    if ("Service".equalsIgnoreCase(pname.getKeyProperty("type"))) {
+                        sb.append(":type=Engine");
+                        parent = sb.toString();
+                    }
+                } catch (Exception e) {
+                    String message =
+                        resources.getMessage(locale, "error.engineName.bad",
+                                         sb.toString());
+                    getServlet().log(message);
+                    response.sendError(HttpServletResponse.SC_BAD_REQUEST, message);
+                    return (null);
+                }
+                                                
+                // Ensure that the requested user database name is unique
+                ObjectName oname =
+                    new ObjectName(objectName);
+                if (mBServer.isRegistered(oname)) {
+                    ActionErrors errors = new ActionErrors();
+                    errors.add("realmName",
+                               new ActionError("error.realmName.exists"));
+                    saveErrors(request, errors);
+                    return (new ActionForward(mapping.getInput()));
+                }
+                
+                String domain = oname.getDomain();
+                // Look up our MBeanFactory MBean
+                ObjectName fname = TomcatTreeBuilder.getMBeanFactory();
+
+                // Create a new StandardRealm object
+                values = new String[2];
+                values[0] = parent;
+                values[1] = rform.getResource();
+                operation = "createUserDatabaseRealm";
+                rObjectName = (String)
+                    mBServer.invoke(fname, operation,
+                                    values, createUserDatabaseRealmTypes);
+                if (rObjectName==null) {
+                    request.setAttribute("warning", "error.userdbrealm");
+                    return (mapping.findForward("Save Unsuccessful"));
+                }
+
+                // Add the new Realm to our tree control node
+                TreeControl control = (TreeControl)
+                    session.getAttribute("treeControlTest");
+                if (control != null) {
+                    TreeControlNode parentNode = control.findNode(rform.getParentObjectName());
+                    if (parentNode != null) {
+                        String nodeLabel = rform.getNodeLabel();                        
+                        String encodedName =
+                            URLEncoder.encode(rObjectName,TomcatTreeBuilder.URL_ENCODING);
+                        TreeControlNode childNode =
+                            new TreeControlNode(rObjectName,
+                                                "Realm.gif",
+                                                nodeLabel,
+                                                "EditRealm.do?select=" +
+                                                encodedName,
+                                                "content",
+                                                true, domain);
+                        parentNode.addChild(childNode);
+                        // FIXME - force a redisplay
+                    } else {
+                        getServlet().log
+                            ("Cannot find parent node '" + parent + "'");
+                    }
+                } else {
+                    getServlet().log
+                        ("Cannot find TreeControlNode!");
+                }
+
+            } catch (Exception e) {
+
+                getServlet().log
+                    (resources.getMessage(locale, "users.error.invoke",
+                                          operation), e);
+                response.sendError
+                    (HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
+                     resources.getMessage(locale, "users.error.invoke",
+                                          operation));
+                return (null);
+
+            }
+
+        }
+
+        // Perform attribute updates as requested
+        String attribute = null;
+        try {
+
+            ObjectName roname = new ObjectName(rObjectName);
+
+            attribute = "resourceName";
+            mBServer.setAttribute(roname,
+                                  new Attribute("resourceName",  rform.getResource()));
+
+        } catch (Exception e) {
+
+            getServlet().log
+                (resources.getMessage(locale, "users.error.attribute.set",
+                                      attribute), e);
+            response.sendError
+                (HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
+                 resources.getMessage(locale, "users.error.attribute.set",
+                                      attribute));
+            return (null);
+        }
+        
+        // Forward to the success reporting page
+        session.removeAttribute(mapping.getAttribute());
+        return (mapping.findForward("Save Successful"));
+        
+    }
+    
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/realm/UserDatabaseRealmForm.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/realm/UserDatabaseRealmForm.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/realm/UserDatabaseRealmForm.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,127 @@
+/*
+ * Copyright 2001,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.admin.realm;
+
+import javax.servlet.http.HttpServletRequest;
+import org.apache.struts.action.ActionError;
+import org.apache.struts.action.ActionErrors;
+import org.apache.struts.action.ActionForm;
+import org.apache.struts.action.ActionMapping;
+import java.net.InetAddress;
+import java.util.List;
+
+import org.apache.webapp.admin.ApplicationServlet;
+import org.apache.webapp.admin.LabelValueBean;
+
+/**
+ * Form bean for the User Database realm page.
+ *
+ * @author Manveen Kaur
+ * @version $Revision: 302986 $ $Date: 2004-06-27 21:14:52 -0500 (Sun, 27 Jun 2004) $
+ */
+
+public final class UserDatabaseRealmForm extends RealmForm {
+    
+    // ----------------------------------------------------- Instance Variables
+
+    /**
+     * The text for the resource name.
+     */
+    private String resource = null;
+        
+    // ------------------------------------------------------------- Properties
+    
+    
+    /**
+     * Return the resource Name.
+     */
+    public String getResource() {
+        
+        return this.resource;
+        
+    }
+    
+    /**
+     * Set the resource Name.
+     */
+    public void setResource(String resource) {
+        
+        this.resource = resource;
+        
+    }
+        
+    // --------------------------------------------------------- Public Methods
+    
+    /**
+     * Reset all properties to their default values.
+     *
+     * @param mapping The mapping used to select this instance
+     * @param request The servlet request we are processing
+     */
+    public void reset(ActionMapping mapping, HttpServletRequest request) {
+        
+        super.reset(mapping, request);
+        this.resource = null;
+        
+    }
+    
+   /**
+     * Render this object as a String.
+     */
+    public String toString() {
+
+        StringBuffer sb = new StringBuffer("UserDatabaseRealmForm[adminAction=");
+        sb.append(getAdminAction());
+        sb.append(",resource=");
+        sb.append(getResource());
+        sb.append("',objectName='");
+        sb.append(getObjectName());
+        sb.append("',realmType=");
+        sb.append(getRealmType());
+        sb.append("]");
+        return (sb.toString());
+
+    }
+
+    /**
+     * Validate the properties that have been set from this HTTP request,
+     * and return an <code>ActionErrors</code> object that encapsulates any
+     * validation errors that have been found.  If no errors are found, return
+     * <code>null</code> or an <code>ActionErrors</code> object with no
+     * recorded error messages.
+     *
+     * @param mapping The mapping used to select this instance
+     * @param request The servlet request we are processing
+     */
+    
+    public ActionErrors validate(ActionMapping mapping,
+    HttpServletRequest request) {
+        
+        ActionErrors errors = new ActionErrors();
+        
+        String submit = request.getParameter("submit");
+        
+        // front end validation when save is clicked.
+        //if (submit != null) {
+            if ((resource == null) || (resource.length() < 1)) {
+                errors.add("resource",
+                new ActionError("error.resource.required"));
+            }
+        //}
+        return errors;
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/resources/BaseForm.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/resources/BaseForm.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/resources/BaseForm.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.admin.resources;
+
+
+import javax.management.ObjectName;
+import javax.servlet.http.HttpServletRequest;
+import org.apache.struts.action.ActionError;
+import org.apache.struts.action.ActionErrors;
+import org.apache.struts.action.ActionForm;
+import org.apache.struts.action.ActionMapping;
+
+
+/**
+ * Base class for form beans for the resource administration.
+ *
+ * @author Manveen Kaur
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ * @since 4.1
+ */
+
+public class BaseForm extends ActionForm {
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    // ------------------------------------------------------------- Properties
+
+    /**
+     * The node label to be displayed in the user interface.
+     */
+    private String nodeLabel = null;
+
+    public String getNodeLabel() {
+        return (this.nodeLabel);
+    }
+
+    public void setNodeLabel(String nodeLabel) {
+        this.nodeLabel = nodeLabel;
+    }
+
+
+    /**
+     * The MBean object name of this object.  A null or zero-length
+     * value indicates that this is a new object.
+     */
+    private String objectName = null;
+
+    public String getObjectName() {
+        return (this.objectName);
+    }
+
+    public void setObjectName(String objectName) {
+        if ((objectName != null) && (objectName.length() < 1)) {
+            this.objectName = null;
+        } else {
+            this.objectName = objectName;
+        }
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+    /**
+     * Reset all properties to their default values.
+     *
+     * @param mapping The mapping used to select this instance
+     * @param request The servlet request we are processing
+     */
+    public void reset(ActionMapping mapping, HttpServletRequest request) {
+
+        nodeLabel = null;
+        objectName = null;
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/resources/DataSourceForm.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/resources/DataSourceForm.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/resources/DataSourceForm.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,390 @@
+/*
+ * Copyright 2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.admin.resources;
+
+import java.util.List;
+import java.util.ArrayList;
+
+import javax.servlet.http.HttpServletRequest;
+import org.apache.struts.action.ActionError;
+import org.apache.struts.action.ActionErrors;
+import org.apache.struts.action.ActionForm;
+import org.apache.struts.action.ActionMapping;
+import org.apache.webapp.admin.LabelValueBean;
+
+/**
+ * Form bean for the individual data source page.
+ *
+ * @author Manveen Kaur
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ * @since 4.1
+ */
+
+public final class DataSourceForm extends BaseForm {
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * The url of the data source.
+     */
+    private String url = null;
+
+    public String getUrl() {
+        return (this.url);
+    }
+
+    public void setUrl(String url) {
+        this.url = url;
+    }
+
+    /**
+     * The JNDI name of the data source.
+     */
+    private String jndiName = null;
+
+    public String getJndiName() {
+        return (this.jndiName);
+    }
+
+    public void setJndiName(String jndiName) {
+        this.jndiName = jndiName;
+    }
+    
+    /**
+     * The JDBC driver class of the data source.
+     */
+    private String driverClass = null;
+
+    public String getDriverClass() {
+        return (this.driverClass);
+    }
+
+    public void setDriverClass(String driverClass) {
+        this.driverClass = driverClass;
+    }
+
+    
+    /**
+     * The username of the databse corresponding to the data source.
+     */
+    private String username = null;
+
+    public String getUsername() {
+        return (this.username);
+    }
+
+    public void setUsername(String username) {
+        this.username = username;
+    }
+
+    
+    /**
+     * The password of the database corresponding to the data source.
+     */
+    private String password = null;
+
+    public String getPassword() {
+        return (this.password);
+    }
+
+    public void setPassword(String password) {
+        this.password = password;
+    }
+
+    
+    /**
+     * The max number of active sessions to the data source.
+     */
+    private String active = null;
+
+    public String getActive() {
+        return (this.active);
+    }
+
+    public void setActive(String active) {
+        this.active = active;
+    }
+
+    /**
+     * The max number of idle connections to the data source.
+     */
+    private String idle = null;
+
+    public String getIdle() {
+        return (this.idle);
+    }
+
+    public void setIdle(String idle) {
+        this.idle = idle;
+    }
+
+    /**
+     * The maximum wait for a connection to the data source.
+     */
+    private String wait = null;
+
+    public String getWait() {
+        return (this.wait);
+    }
+
+    public void setWait(String wait) {
+        this.wait = wait;
+    }
+
+    /**
+     * The resource type of this data source.
+     */
+    private String resourcetype = null;
+    
+    /**
+     * Return the resource type of the data source this bean refers to.
+     */
+    public String getResourcetype() {
+        return this.resourcetype;
+    }
+
+    /**
+     * Set the resource type of the data source this bean refers to.
+     */
+    public void setResourcetype(String resourcetype) {
+        this.resourcetype = resourcetype;
+    }
+       
+    /**
+     * The path of this data source.
+     */
+    private String path = null;
+    
+    /**
+     * Return the path of the data source this bean refers to.
+     */
+    public String getPath() {
+        return this.path;
+    }
+
+    /**
+     * Set the path of the data source this bean refers to.
+     */
+    public void setPath(String path) {
+        this.path = path;
+    }
+       
+    /**
+     * The host of this data source.
+     */
+    private String host = null;
+    
+    /**
+     * Return the host of the data source this bean refers to.
+     */
+    public String getHost() {
+        return this.host;
+    }
+
+    /**
+     * Set the host of the data source this bean refers to.
+     */
+    public void setHost(String host) {
+        this.host = host;
+    }    
+    
+       
+    /**
+     * The domain of this data source.
+     */
+    private String domain = null;
+    
+    /**
+     * Return the domain of the data source this bean refers to.
+     */
+    public String getDomain() {
+        return this.domain;
+    }
+
+    /**
+     * Set the domain of the data source this bean refers to.
+     */
+    public void setDomain(String domain) {
+        this.domain = domain;
+    }
+    
+    /**
+     * The validation query to the data source.
+     */
+    private String query = null;
+
+    public String getQuery() {
+        return (this.query);
+    }
+
+    public void setQuery(String query) {
+        this.query = query;
+    }
+    
+    /**
+     * The type of the resource.
+     */
+    private String type = null;
+
+    public String getType() {
+        return (this.type);
+    }
+
+    public void setType(String type) {
+        this.type = type;
+    }
+
+    // --------------------------------------------------------- Public Methods
+
+    /**
+     * Reset all properties to their default values.
+     *
+     * @param mapping The mapping used to select this instance
+     * @param request The servlet request we are processing
+     */
+    public void reset(ActionMapping mapping, HttpServletRequest request) {
+
+        super.reset(mapping, request);
+        url = null;        
+        jndiName = null;
+        driverClass = null;
+        username = null;
+        password = null;
+        type = null;
+    
+        active = null;
+        idle = null;
+        wait = null;
+        query = null;
+    }
+
+    /**
+     * Validate the properties that have been set from this HTTP request,
+     * and return an <code>ActionErrors</code> object that encapsulates any
+     * validation errors that have been found.  If no errors are found, return
+     * <code>null</code> or an <code>ActionErrors</code> object with no
+     * recorded error messages.
+     *
+     * @param mapping The mapping used to select this instance
+     * @param request The servlet request we are processing
+     */
+    
+    private ActionErrors errors = null;
+    
+    public ActionErrors validate(ActionMapping mapping,
+    HttpServletRequest request) {
+
+        errors = new ActionErrors();
+
+        String submit = request.getParameter("submit");
+
+        //if (submit != null) {
+
+            // url is a required field
+            if ((url == null) || (url.length() < 1)) {
+                errors.add("url",
+                           new ActionError("resources.error.url.required"));
+            }
+
+            // jndiName is a required field
+            if (( jndiName == null) || (jndiName.length() < 1)) {
+                errors.add("jndiName",
+                           new ActionError("resources.error.jndiName.required"));
+            }
+
+            // driverClass is a required field
+            if ((driverClass == null) || (driverClass.length() < 1)) {
+                errors.add("driverClass",
+                           new ActionError("resources.error.driverClass.required"));
+            }
+            
+            // username is a required field
+            if ((username == null) || (username.length() < 1)) {
+                errors.add("username",
+                           new ActionError("users.error.username.required"));
+            }
+            
+            // commented out password can be an empty string
+            // password is a required field
+            //if ((password == null) || (password.length() < 1)) {
+            //    errors.add("password",
+            //               new ActionError("error.userPassword.required"));
+            //
+            
+            // FIX ME -- need to do a range check
+            numberCheck("active", active , false, 0, 10000);
+            numberCheck("idle", idle , false, 0, 10000);
+            numberCheck("wait", wait , false, 0, 10000);
+
+            // Quotes not allowed in username
+            if ((username != null) && (username.indexOf('"') >= 0)) {
+                errors.add("username",
+                           new ActionError("users.error.quotes"));
+            }
+
+            // Quotes not allowed in password
+            if ((password != null) && (password.indexOf('"') > 0)) {
+                errors.add("password",
+                           new ActionError("users.error.quotes"));
+            }
+         //}
+        return (errors);
+    }
+ 
+    /*
+     * Helper method to check that it is a required number and
+     * is a valid integer within the given range. (min, max).
+     *
+     * @param  field  The field name in the form for which this error occured.
+     * @param  numText  The string representation of the number.
+     * @param rangeCheck  Boolean value set to true of reange check should be performed.
+     *
+     * @param  min  The lower limit of the range
+     * @param  max  The upper limit of the range
+     *
+     */
+    
+    private void numberCheck(String field, String numText, boolean rangeCheck,
+                             int min, int max) {
+        
+        // Check for 'is required'
+        if ((numText == null) || (numText.length() < 1)) {
+            errors.add(field, new ActionError("resources.error."+field+".required"));
+        } else {
+            
+            // check for 'must be a number' in the 'valid range'
+            try {
+                int num = Integer.parseInt(numText);
+                // perform range check only if required
+                if (rangeCheck) {
+                    if ((num < min) || (num > max ))
+                        errors.add( field,
+                        new ActionError("resources.error."+ field +".range"));
+                }
+            } catch (NumberFormatException e) {
+                errors.add(field,
+                new ActionError("resources.integer.error"));
+            }
+        }
+    }
+    
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/resources/DataSourcesForm.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/resources/DataSourcesForm.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/resources/DataSourcesForm.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,150 @@
+/*
+ * Copyright 2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.admin.resources;
+
+import javax.servlet.http.HttpServletRequest;
+import org.apache.struts.action.ActionError;
+import org.apache.struts.action.ActionErrors;
+import org.apache.struts.action.ActionForm;
+import org.apache.struts.action.ActionMapping;
+
+
+/**
+ * Form bean for the delete data sources page.
+ *
+ * @author Manveen Kaur
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ * @since 4.1
+ */
+
+public final class DataSourcesForm extends BaseForm {
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * The object names of the specified environment entries.
+     */
+    private String dataSources[] = null;
+
+    public String[] getDataSources() {
+        return (this.dataSources);
+    }
+
+    public void setDataSources(String dataSources[]) {
+        this.dataSources = dataSources;
+    }
+
+    /**
+     * The resource type of this data source.
+     */
+    private String resourcetype = null;
+    
+    /**
+     * Return the resource type of the data source this bean refers to.
+     */
+    public String getResourcetype() {
+        return this.resourcetype;
+    }
+
+    /**
+     * Set the resource type of the data source this bean refers to.
+     */
+    public void setResourcetype(String resourcetype) {
+        this.resourcetype = resourcetype;
+    }
+       
+    /**
+     * The path of this data source.
+     */
+    private String path = null;
+    
+    /**
+     * Return the path of the data source this bean refers to.
+     */
+    public String getPath() {
+        return this.path;
+    }
+
+    /**
+     * Set the path of the data source this bean refers to.
+     */
+    public void setPath(String path) {
+        this.path = path;
+    }
+       
+    /**
+     * The host of this data source.
+     */
+    private String host = null;
+    
+    /**
+     * Return the host of the data source this bean refers to.
+     */
+    public String getHost() {
+        return this.host;
+    }
+
+    /**
+     * Set the host of the data source this bean refers to.
+     */
+    public void setHost(String host) {
+        this.host = host;
+    }    
+    
+       
+    /**
+     * The domain of this data source.
+     */
+    private String domain = null;
+    
+    /**
+     * Return the domain of the data source this bean refers to.
+     */
+    public String getDomain() {
+        return this.domain;
+    }
+
+    /**
+     * Set the domain of the data source this bean refers to.
+     */
+    public void setDomain(String domain) {
+        this.domain = domain;
+    }
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Reset all properties to their default values.
+     *
+     * @param mapping The mapping used to select this instance
+     * @param request The servlet request we are processing
+     */
+    public void reset(ActionMapping mapping, HttpServletRequest request) {
+
+        super.reset(mapping, request);
+        this.dataSources = null;
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/resources/DeleteDataSourcesAction.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/resources/DeleteDataSourcesAction.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/resources/DeleteDataSourcesAction.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,163 @@
+/*
+ * Copyright 2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.admin.resources;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.Locale;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+import org.apache.struts.action.Action;
+import org.apache.struts.action.ActionErrors;
+import org.apache.struts.action.ActionForm;
+import org.apache.struts.action.ActionForward;
+import org.apache.struts.action.ActionMapping;
+import javax.management.Attribute;
+import javax.management.MBeanServer;
+import javax.management.MBeanServerFactory;
+import javax.management.QueryExp;
+import javax.management.Query;
+import javax.management.ObjectInstance;
+import javax.management.ObjectName;
+import javax.management.JMException;
+import javax.management.MBeanAttributeInfo;
+import javax.management.MBeanOperationInfo;
+import javax.management.MBeanInfo;
+import org.apache.struts.util.MessageResources;
+import org.apache.webapp.admin.ApplicationServlet;
+
+
+/**
+ * <p>Implementation of <strong>Action</strong> that deletes the
+ * specified set of dataSource entries.</p>
+ *
+ * @author Manveen Kaur
+ * @version $Revision: 303390 $ $Date: 2004-10-18 01:37:56 -0500 (Mon, 18 Oct 2004) $
+ * @since 4.1
+ */
+
+public final class DeleteDataSourcesAction extends Action {
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The MBeanServer we will be interacting with.
+     */
+    private MBeanServer mserver = null;
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Process the specified HTTP request, and create the corresponding HTTP
+     * response (or forward to another web component that will create it).
+     * Return an <code>ActionForward</code> instance describing where and how
+     * control should be forwarded, or <code>null</code> if the response has
+     * already been completed.
+     *
+     * @param mapping The ActionMapping used to select this instance
+     * @param actionForm The optional ActionForm bean for this request (if any)
+     * @param request The HTTP request we are processing
+     * @param response The HTTP response we are creating
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception ServletException if a servlet exception occurs
+     */
+    public ActionForward execute(ActionMapping mapping,
+                                 ActionForm form,
+                                 HttpServletRequest request,
+                                 HttpServletResponse response)
+        throws IOException, ServletException {
+
+        // Look up the components we will be using as needed
+        if (mserver == null) {
+            mserver = ((ApplicationServlet) getServlet()).getServer();
+        }
+        MessageResources resources = getResources(request);
+        HttpSession session = request.getSession();
+        Locale locale = getLocale(request);
+
+        // Has this transaction been cancelled?
+        if (isCancelled(request)) {
+            return (mapping.findForward("List DataSources Setup"));
+        }
+
+        // Check the transaction token
+        if (!isTokenValid(request)) {
+            response.sendError
+                (HttpServletResponse.SC_BAD_REQUEST,
+                 resources.getMessage(locale, "users.error.token"));
+            return (null);
+        }
+
+        // Perform any extra validation that is required
+        DataSourcesForm dataSourcesForm = (DataSourcesForm) form;
+        String dataSources[] = dataSourcesForm.getDataSources();
+        if (dataSources == null) {
+            dataSources = new String[0];
+        }
+
+        // Perform "Delete EnvEntry" transactions as required
+        try {
+            
+            String resourcetype = dataSourcesForm.getResourcetype();
+            String path = dataSourcesForm.getPath();
+            String host = dataSourcesForm.getHost();
+            //String domain = dataSourcesForm.getDomain();
+            
+            ObjectName dname = null;
+
+            String signature[] = new String[1];
+            signature[0] = "java.lang.String";
+            Object params[] = new String[1];
+             
+            for (int i = 0; i < dataSources.length; i++) {
+                ObjectName oname = new ObjectName(dataSources[i]);
+                String domain = oname.getDomain();
+                dname = ResourceUtils.getNamingResourceObjectName(domain,
+                            resourcetype, path, host);
+                params[0] = oname.getKeyProperty("name");
+                mserver.invoke(dname, "removeResource",
+                               params, signature);
+            }
+          
+        } catch (Throwable t) {
+
+            getServlet().log
+                (resources.getMessage(locale, "users.error.invoke",
+                                      "removeResource"), t);
+            response.sendError
+                (HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
+                 resources.getMessage(locale, "users.error.invoke",
+                                      "removeResource"));
+            return (null);
+
+        }
+
+        // Proceed to the list envEntrys screen
+        return (mapping.findForward("DataSources List Setup"));
+
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/resources/DeleteEnvEntriesAction.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/resources/DeleteEnvEntriesAction.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/resources/DeleteEnvEntriesAction.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,162 @@
+/*
+ * Copyright 2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.admin.resources;
+
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.Locale;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+import org.apache.struts.action.Action;
+import org.apache.struts.action.ActionErrors;
+import org.apache.struts.action.ActionForm;
+import org.apache.struts.action.ActionForward;
+import org.apache.struts.action.ActionMapping;
+import javax.management.Attribute;
+import javax.management.MBeanServer;
+import javax.management.MBeanServerFactory;
+import javax.management.QueryExp;
+import javax.management.Query;
+import javax.management.ObjectInstance;
+import javax.management.ObjectName;
+import javax.management.JMException;
+import javax.management.MBeanAttributeInfo;
+import javax.management.MBeanOperationInfo;
+import javax.management.MBeanInfo;
+import org.apache.struts.util.MessageResources;
+import org.apache.webapp.admin.ApplicationServlet;
+
+
+/**
+ * <p>Implementation of <strong>Action</strong> that deletes the
+ * specified set of env entries.</p>
+ *
+ * @author Manveen Kaur
+ * @version $Revision: 303390 $ $Date: 2004-10-18 01:37:56 -0500 (Mon, 18 Oct 2004) $
+ * @since 4.1
+ */
+
+public final class DeleteEnvEntriesAction extends Action {
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The MBeanServer we will be interacting with.
+     */
+    private MBeanServer mserver = null;
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Process the specified HTTP request, and create the corresponding HTTP
+     * response (or forward to another web component that will create it).
+     * Return an <code>ActionForward</code> instance describing where and how
+     * control should be forwarded, or <code>null</code> if the response has
+     * already been completed.
+     *
+     * @param mapping The ActionMapping used to select this instance
+     * @param actionForm The optional ActionForm bean for this request (if any)
+     * @param request The HTTP request we are processing
+     * @param response The HTTP response we are creating
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception ServletException if a servlet exception occurs
+     */
+    public ActionForward execute(ActionMapping mapping,
+                                 ActionForm form,
+                                 HttpServletRequest request,
+                                 HttpServletResponse response)
+        throws IOException, ServletException {
+
+        // Look up the components we will be using as needed
+        if (mserver == null) {
+            mserver = ((ApplicationServlet) getServlet()).getServer();
+        }
+        MessageResources resources = getResources(request);
+        HttpSession session = request.getSession();
+        Locale locale = getLocale(request);
+        
+        // Has this transaction been cancelled?
+        if (isCancelled(request)) {
+            return (mapping.findForward("List EnvEntries Setup"));
+        }
+
+        // Check the transaction token
+        if (!isTokenValid(request)) {
+            response.sendError
+                (HttpServletResponse.SC_BAD_REQUEST,
+                 resources.getMessage(locale, "users.error.token"));
+            return (null);
+        }
+
+        // Perform any extra validation that is required
+        EnvEntriesForm envEntriesForm = (EnvEntriesForm) form;
+        String envEntries[] = envEntriesForm.getEnvEntries();
+        String resourcetype = envEntriesForm.getResourcetype();
+        String path = envEntriesForm.getPath();
+        String host = envEntriesForm.getHost();
+        
+        if (envEntries == null) {
+            envEntries = new String[0];
+        }
+
+        // Perform "Delete EnvEntry" transactions as required
+        try {
+            ObjectName dname = null;
+            
+            String signature[] = new String[1];
+            signature[0] = "java.lang.String";
+            Object params[] = new String[1];
+
+            for (int i = 0; i < envEntries.length; i++) {
+                ObjectName oname = new ObjectName(envEntries[i]);
+                String domain = oname.getDomain();
+                dname = ResourceUtils.getNamingResourceObjectName(domain,
+                            resourcetype, path, host);
+                params[0] = oname.getKeyProperty("name");
+                mserver.invoke(dname, "removeEnvironment",
+                               params, signature);
+            }
+            
+        } catch (Throwable t) {
+
+            getServlet().log
+                (resources.getMessage(locale, "users.error.invoke",
+                                      "removeEnvironment"), t);
+            response.sendError
+                (HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
+                 resources.getMessage(locale, "users.error.invoke",
+                                      "removeEnvironment"));
+            return (null);
+
+        }
+
+        // Proceed to the list envEntrys screen
+        return (mapping.findForward("EnvEntries List Setup"));
+
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/resources/DeleteMailSessionsAction.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/resources/DeleteMailSessionsAction.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/resources/DeleteMailSessionsAction.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,162 @@
+/*
+ * Copyright 2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.admin.resources;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.Locale;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+import org.apache.struts.action.Action;
+import org.apache.struts.action.ActionErrors;
+import org.apache.struts.action.ActionForm;
+import org.apache.struts.action.ActionForward;
+import org.apache.struts.action.ActionMapping;
+import javax.management.Attribute;
+import javax.management.MBeanServer;
+import javax.management.MBeanServerFactory;
+import javax.management.QueryExp;
+import javax.management.Query;
+import javax.management.ObjectInstance;
+import javax.management.ObjectName;
+import javax.management.JMException;
+import javax.management.MBeanAttributeInfo;
+import javax.management.MBeanOperationInfo;
+import javax.management.MBeanInfo;
+import org.apache.struts.util.MessageResources;
+import org.apache.webapp.admin.ApplicationServlet;
+
+
+/**
+ * <p>Implementation of <strong>Action</strong> that deletes the
+ * specified set of mailSession entries.</p>
+ *
+ * @author Amy Roh
+ * @version $Revision: 303390 $ $Date: 2004-10-18 01:37:56 -0500 (Mon, 18 Oct 2004) $
+ * @since 4.1
+ */
+
+public final class DeleteMailSessionsAction extends Action {
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The MBeanServer we will be interacting with.
+     */
+    private MBeanServer mserver = null;
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Process the specified HTTP request, and create the corresponding HTTP
+     * response (or forward to another web component that will create it).
+     * Return an <code>ActionForward</code> instance describing where and how
+     * control should be forwarded, or <code>null</code> if the response has
+     * already been completed.
+     *
+     * @param mapping The ActionMapping used to select this instance
+     * @param actionForm The optional ActionForm bean for this request (if any)
+     * @param request The HTTP request we are processing
+     * @param response The HTTP response we are creating
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception ServletException if a servlet exception occurs
+     */
+    public ActionForward execute(ActionMapping mapping,
+                                 ActionForm form,
+                                 HttpServletRequest request,
+                                 HttpServletResponse response)
+        throws IOException, ServletException {
+
+        // Look up the components we will be using as needed
+        if (mserver == null) {
+            mserver = ((ApplicationServlet) getServlet()).getServer();
+        }
+        MessageResources resources = getResources(request);
+        HttpSession session = request.getSession();
+        Locale locale = getLocale(request);
+
+        // Has this transaction been cancelled?
+        if (isCancelled(request)) {
+            return (mapping.findForward("List MailSessions Setup"));
+        }
+
+        // Check the transaction token
+        if (!isTokenValid(request)) {
+            response.sendError
+                (HttpServletResponse.SC_BAD_REQUEST,
+                 resources.getMessage(locale, "users.error.token"));
+            return (null);
+        }
+
+        // Perform any extra validation that is required
+        MailSessionsForm mailSessionsForm = (MailSessionsForm) form;
+        String mailSessions[] = mailSessionsForm.getMailSessions();
+        if (mailSessions == null) {
+            mailSessions = new String[0];
+        }
+
+        // Perform "Delete EnvEntry" transactions as required
+        try {
+            
+            String resourcetype = mailSessionsForm.getResourcetype();
+            String path = mailSessionsForm.getPath();
+            String host = mailSessionsForm.getHost();
+            
+            ObjectName dname = null;
+
+            String signature[] = new String[1];
+            signature[0] = "java.lang.String";
+            Object params[] = new String[1];
+             
+            for (int i = 0; i < mailSessions.length; i++) {
+                ObjectName oname = new ObjectName(mailSessions[i]);
+                String domain = oname.getDomain();
+                dname = ResourceUtils.getNamingResourceObjectName(domain,
+                            resourcetype, path, host);
+                params[0] = oname.getKeyProperty("name");
+                mserver.invoke(dname, "removeResource",
+                               params, signature);
+            }
+          
+        } catch (Throwable t) {
+
+            getServlet().log
+                (resources.getMessage(locale, "users.error.invoke",
+                                      "removeResource"), t);
+            response.sendError
+                (HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
+                 resources.getMessage(locale, "users.error.invoke",
+                                      "removeResource"));
+            return (null);
+
+        }
+
+        // Proceed to the list envEntrys screen
+        return (mapping.findForward("MailSessions List Setup"));
+
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/resources/DeleteResourceLinksAction.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/resources/DeleteResourceLinksAction.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/resources/DeleteResourceLinksAction.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,162 @@
+/*
+ * Copyright 2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.admin.resources;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.Locale;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+import org.apache.struts.action.Action;
+import org.apache.struts.action.ActionErrors;
+import org.apache.struts.action.ActionForm;
+import org.apache.struts.action.ActionForward;
+import org.apache.struts.action.ActionMapping;
+import javax.management.Attribute;
+import javax.management.MBeanServer;
+import javax.management.MBeanServerFactory;
+import javax.management.QueryExp;
+import javax.management.Query;
+import javax.management.ObjectInstance;
+import javax.management.ObjectName;
+import javax.management.JMException;
+import javax.management.MBeanAttributeInfo;
+import javax.management.MBeanOperationInfo;
+import javax.management.MBeanInfo;
+import org.apache.struts.util.MessageResources;
+import org.apache.webapp.admin.ApplicationServlet;
+
+
+/**
+ * <p>Implementation of <strong>Action</strong> that deletes the
+ * specified set of resource links entries.</p>
+ *
+ * @author Amy Roh
+ * @version $Revision: 303390 $ $Date: 2004-10-18 01:37:56 -0500 (Mon, 18 Oct 2004) $
+ * @since 4.1
+ */
+
+public final class DeleteResourceLinksAction extends Action {
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The MBeanServer we will be interacting with.
+     */
+    private MBeanServer mserver = null;
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Process the specified HTTP request, and create the corresponding HTTP
+     * response (or forward to another web component that will create it).
+     * Return an <code>ActionForward</code> instance describing where and how
+     * control should be forwarded, or <code>null</code> if the response has
+     * already been completed.
+     *
+     * @param mapping The ActionMapping used to select this instance
+     * @param actionForm The optional ActionForm bean for this request (if any)
+     * @param request The HTTP request we are processing
+     * @param response The HTTP response we are creating
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception ServletException if a servlet exception occurs
+     */
+    public ActionForward execute(ActionMapping mapping,
+                                 ActionForm form,
+                                 HttpServletRequest request,
+                                 HttpServletResponse response)
+        throws IOException, ServletException {
+
+        // Look up the components we will be using as needed
+        if (mserver == null) {
+            mserver = ((ApplicationServlet) getServlet()).getServer();
+        }
+        MessageResources resources = getResources(request);
+        HttpSession session = request.getSession();
+        Locale locale = getLocale(request);
+
+        // Has this transaction been cancelled?
+        if (isCancelled(request)) {
+            return (mapping.findForward("List Resource Links Setup"));
+        }
+
+        // Check the transaction token
+        if (!isTokenValid(request)) {
+            response.sendError
+                (HttpServletResponse.SC_BAD_REQUEST,
+                 resources.getMessage(locale, "users.error.token"));
+            return (null);
+        }
+
+        // Perform any extra validation that is required
+        ResourceLinksForm resourceLinksForm = (ResourceLinksForm) form;
+        String resourceLinks[] = resourceLinksForm.getResourceLinks();
+        if (resourceLinks == null) {
+            resourceLinks = new String[0];
+        }
+
+        // Perform "Delete Resource Link" transactions as required
+        try {
+            
+            String resourcetype = resourceLinksForm.getResourcetype();
+            String path = resourceLinksForm.getPath();
+            String host = resourceLinksForm.getHost();
+            
+            ObjectName dname = null;
+
+            String signature[] = new String[1];
+            signature[0] = "java.lang.String";
+            Object params[] = new String[1];
+            
+            for (int i = 0; i < resourceLinks.length; i++) {
+                ObjectName oname = new ObjectName(resourceLinks[i]);
+                String domain = oname.getDomain();  
+                dname = ResourceUtils.getNamingResourceObjectName(domain,
+                            resourcetype, path, host);
+                params[0] = oname.getKeyProperty("name");
+                mserver.invoke(dname, "removeResourceLink",
+                               params, signature);
+            }
+
+        } catch (Throwable t) {
+
+            getServlet().log
+                (resources.getMessage(locale, "users.error.invoke",
+                                      "removeResource"), t);
+            response.sendError
+                (HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
+                 resources.getMessage(locale, "users.error.invoke",
+                                      "removeResource"));
+            return (null);
+
+        }
+
+        // Proceed to the list envEntrys screen
+        return (mapping.findForward("ResourceLinks List Setup"));
+
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/resources/DeleteUserDatabasesAction.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/resources/DeleteUserDatabasesAction.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/resources/DeleteUserDatabasesAction.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,158 @@
+/*
+ * Copyright 2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.admin.resources;
+
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.Locale;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+import org.apache.struts.action.Action;
+import org.apache.struts.action.ActionErrors;
+import org.apache.struts.action.ActionForm;
+import org.apache.struts.action.ActionForward;
+import org.apache.struts.action.ActionMapping;
+import javax.management.Attribute;
+import javax.management.MBeanServer;
+import javax.management.MBeanServerFactory;
+import javax.management.QueryExp;
+import javax.management.Query;
+import javax.management.ObjectInstance;
+import javax.management.ObjectName;
+import javax.management.JMException;
+import javax.management.MBeanAttributeInfo;
+import javax.management.MBeanOperationInfo;
+import javax.management.MBeanInfo;
+import org.apache.struts.util.MessageResources;
+import org.apache.webapp.admin.ApplicationServlet;
+
+
+/**
+ * <p>Implementation of <strong>Action</strong> that deletes the
+ * specified set of user databases.</p>
+ *
+ * @author Manveen Kaur
+ * @version $Revision: 303390 $ $Date: 2004-10-18 01:37:56 -0500 (Mon, 18 Oct 2004) $
+ * @since 4.1
+ */
+
+public final class DeleteUserDatabasesAction extends Action {
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The MBeanServer we will be interacting with.
+     */
+    private MBeanServer mserver = null;
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Process the specified HTTP request, and create the corresponding HTTP
+     * response (or forward to another web component that will create it).
+     * Return an <code>ActionForward</code> instance describing where and how
+     * control should be forwarded, or <code>null</code> if the response has
+     * already been completed.
+     *
+     * @param mapping The ActionMapping used to select this instance
+     * @param actionForm The optional ActionForm bean for this request (if any)
+     * @param request The HTTP request we are processing
+     * @param response The HTTP response we are creating
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception ServletException if a servlet exception occurs
+     */
+    public ActionForward execute(ActionMapping mapping,
+                                 ActionForm form,
+                                 HttpServletRequest request,
+                                 HttpServletResponse response)
+        throws IOException, ServletException {
+
+        // Look up the components we will be using as needed
+        if (mserver == null) {
+            mserver = ((ApplicationServlet) getServlet()).getServer();
+        }
+        MessageResources resources = getResources(request);
+        HttpSession session = request.getSession();
+        Locale locale = getLocale(request);
+
+        // Has this transaction been cancelled?
+        if (isCancelled(request)) {
+            return (mapping.findForward("List UserDatabases Setup"));
+        }
+
+        // Check the transaction token
+        if (!isTokenValid(request)) {
+            response.sendError
+                (HttpServletResponse.SC_BAD_REQUEST,
+                 resources.getMessage(locale, "users.error.token"));
+            return (null);
+        }
+
+        // Perform any extra validation that is required
+        UserDatabasesForm userDatabasesForm = (UserDatabasesForm) form;
+        String userDatabases[] = userDatabasesForm.getUserDatabases();
+        if (userDatabases == null) {
+            userDatabases = new String[0];
+        }
+
+        // Perform "Delete User Database" transactions as required
+        try {
+
+            String signature[] = new String[1];
+            signature[0] = "java.lang.String";
+            Object params[] = new String[1];
+
+            for (int i = 0; i < userDatabases.length; i++) {
+                ObjectName oname = new ObjectName(userDatabases[i]);
+                // Construct the MBean Name for the naming source
+                ObjectName dname = new ObjectName(oname.getDomain() +
+                                    ResourceUtils.NAMINGRESOURCES_TYPE + 
+                                    ResourceUtils.GLOBAL_TYPE);
+                params[0] = oname.getKeyProperty("name");
+                mserver.invoke(dname, "removeResource",
+                               params, signature);
+            }
+
+        } catch (Throwable t) {
+
+            getServlet().log
+                (resources.getMessage(locale, "users.error.invoke",
+                                      "removeResource"), t);
+            response.sendError
+                (HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
+                 resources.getMessage(locale, "users.error.invoke",
+                                      "removeResource"));
+            return (null);
+
+        }
+
+        // Proceed to the list envEntrys screen
+        return (mapping.findForward("UserDatabases List Setup"));
+
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/resources/EnvEntriesForm.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/resources/EnvEntriesForm.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/resources/EnvEntriesForm.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,151 @@
+/*
+ * Copyright 2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.admin.resources;
+
+
+import javax.servlet.http.HttpServletRequest;
+import org.apache.struts.action.ActionError;
+import org.apache.struts.action.ActionErrors;
+import org.apache.struts.action.ActionForm;
+import org.apache.struts.action.ActionMapping;
+
+
+/**
+ * Form bean for the delete env entries page.
+ *
+ * @author Manveen Kaur
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ * @since 4.1
+ */
+
+public final class EnvEntriesForm extends BaseForm {
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * The object names of the specified environment entries.
+     */
+    private String envEntries[] = null;
+
+    public String[] getEnvEntries() {
+        return (this.envEntries);
+    }
+
+    public void setEnvEntries(String envEntries[]) {
+        this.envEntries = envEntries;
+    }
+    
+    /**
+     * The resource type of this environment entry.
+     */
+    private String resourcetype = null;
+    
+    /**
+     * Return the resource type of the environment entry this bean refers to.
+     */
+    public String getResourcetype() {
+        return this.resourcetype;
+    }
+
+    /**
+     * Set the resource type of the environment entry this bean refers to.
+     */
+    public void setResourcetype(String resourcetype) {
+        this.resourcetype = resourcetype;
+    }
+       
+    /**
+     * The path of this environment entry.
+     */
+    private String path = null;
+    
+    /**
+     * Return the path of the environment entry this bean refers to.
+     */
+    public String getPath() {
+        return this.path;
+    }
+
+    /**
+     * Set the path of the environment entry this bean refers to.
+     */
+    public void setPath(String path) {
+        this.path = path;
+    }
+       
+    /**
+     * The host of this environment entry.
+     */
+    private String host = null;
+    
+    /**
+     * Return the host of the environment entry this bean refers to.
+     */
+    public String getHost() {
+        return this.host;
+    }
+
+    /**
+     * Set the host of the environment entry this bean refers to.
+     */
+    public void setHost(String host) {
+        this.host = host;
+    }    
+    
+       
+    /**
+     * The domain of this environment entry.
+     */
+    private String domain = null;
+    
+    /**
+     * Return the domain of the environment entry this bean refers to.
+     */
+    public String getDomain() {
+        return this.domain;
+    }
+
+    /**
+     * Set the domain of the environment entry this bean refers to.
+     */
+    public void setDomain(String domain) {
+        this.domain = domain;
+    }
+    
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Reset all properties to their default values.
+     *
+     * @param mapping The mapping used to select this instance
+     * @param request The servlet request we are processing
+     */
+    public void reset(ActionMapping mapping, HttpServletRequest request) {
+
+        super.reset(mapping, request);
+        this.envEntries = null;
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/resources/EnvEntryForm.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/resources/EnvEntryForm.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/resources/EnvEntryForm.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,358 @@
+/*
+ * Copyright 2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.admin.resources;
+
+import java.util.List;
+import java.util.ArrayList;
+
+import javax.servlet.http.HttpServletRequest;
+import org.apache.struts.action.ActionError;
+import org.apache.struts.action.ActionErrors;
+import org.apache.struts.action.ActionForm;
+import org.apache.struts.action.ActionMapping;
+import org.apache.webapp.admin.LabelValueBean;
+
+import java.lang.reflect.Constructor;
+
+/**
+ * Form bean for the individual environment entry page.
+ *
+ * @author Manveen Kaur
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ * @since 4.1
+ */
+
+public final class EnvEntryForm extends BaseForm {
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * The name of the associated entry.
+     */
+    private String name = null;
+
+    public String getName() {
+        return (this.name);
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    /**
+     * The type of the associated entry.
+     */
+    private String entryType = null;
+
+    public String getEntryType() {
+        return (this.entryType);
+    }
+
+    public void setEntryType(String entryType) {
+        this.entryType = entryType;
+    }
+
+
+    /**
+     * The value of the associated entry.
+     */
+    private String value = null;
+
+    public String getValue() {
+        return (this.value);
+    }
+
+    public void setValue(String value) {
+        this.value = value;
+    }
+
+    /**
+     * The description of the associated entry.
+     */
+    private String description = null;
+
+    public String getDescription() {
+        return (this.description);
+    }
+
+    public void setDescription(String description) {
+        this.description = description;
+    }
+
+    /**
+     * The value of override appl level entries.
+     */
+    private boolean override = true;
+
+    public boolean getOverride() {
+        return (this.override);
+    }
+
+    public void setOverride(boolean override) {
+        this.override = override;
+    }
+    
+    /**
+     * The resource type of this environment entry.
+     */
+    private String resourcetype = null;
+    
+    /**
+     * Return the resource type of the environment entry this bean refers to.
+     */
+    public String getResourcetype() {
+        return this.resourcetype;
+    }
+
+    /**
+     * Set the resource type of the environment entry this bean refers to.
+     */
+    public void setResourcetype(String resourcetype) {
+        this.resourcetype = resourcetype;
+    }
+       
+    /**
+     * The path of this environment entry.
+     */
+    private String path = null;
+    
+    /**
+     * Return the path of the environment entry this bean refers to.
+     */
+    public String getPath() {
+        return this.path;
+    }
+
+    /**
+     * Set the path of the environment entry this bean refers to.
+     */
+    public void setPath(String path) {
+        this.path = path;
+    }
+       
+    /**
+     * The host of this environment entry.
+     */
+    private String host = null;
+    
+    /**
+     * Return the host of the environment entry this bean refers to.
+     */
+    public String getHost() {
+        return this.host;
+    }
+
+    /**
+     * Set the host of the environment entry this bean refers to.
+     */
+    public void setHost(String host) {
+        this.host = host;
+    }    
+    
+       
+    /**
+     * The domain of this environment entry.
+     */
+    private String domain = null;
+    
+    /**
+     * Return the domain of the environment entry this bean refers to.
+     */
+    public String getDomain() {
+        return this.domain;
+    }
+
+    /**
+     * Set the domain of the environment entry this bean refers to.
+     */
+    public void setDomain(String domain) {
+        this.domain = domain;
+    }
+    
+    /**
+     * Precomputed list of entry type labels and values.
+     */
+    private static List typeVals = new ArrayList();
+
+    static {
+        typeVals.add(new LabelValueBean("java.lang.Boolean", "java.lang.Boolean"));
+        typeVals.add(new LabelValueBean("java.lang.Byte", "java.lang.Byte"));
+        typeVals.add(new LabelValueBean("java.lang.Character", "java.lang.Character"));
+        typeVals.add(new LabelValueBean("java.lang.Double", "java.lang.Double"));
+        typeVals.add(new LabelValueBean("java.lang.Float", "java.lang.Float"));
+        typeVals.add(new LabelValueBean("java.lang.Integer", "java.lang.Integer"));    
+        typeVals.add(new LabelValueBean("java.lang.Long", "java.lang.Long"));
+        typeVals.add(new LabelValueBean("java.lang.Short", "java.lang.Short"));        
+        typeVals.add(new LabelValueBean("java.lang.String", "java.lang.String"));           
+        
+    }
+
+    /**
+     * Return the typeVals.
+     */
+    public List getTypeVals() {
+        
+        return this.typeVals;
+        
+    }
+    
+    /**
+     * Set the typeVals.
+     */
+    public void setTypeVals(List typeVals) {
+        
+        this.typeVals = typeVals;
+        
+    }
+    
+    // --------------------------------------------------------- Public Methods
+
+    /**
+     * Reset all properties to their default values.
+     *
+     * @param mapping The mapping used to select this instance
+     * @param request The servlet request we are processing
+     */
+    public void reset(ActionMapping mapping, HttpServletRequest request) {
+
+        super.reset(mapping, request);
+        name = null;
+        entryType = null;
+        value = null;
+        description = null;
+        override = false;
+
+    }
+
+    /**
+     * Validate the properties that have been set from this HTTP request,
+     * and return an <code>ActionErrors</code> object that encapsulates any
+     * validation errors that have been found.  If no errors are found, return
+     * <code>null</code> or an <code>ActionErrors</code> object with no
+     * recorded error messages.
+     *
+     * @param mapping The mapping used to select this instance
+     * @param request The servlet request we are processing
+     */
+    
+    private ActionErrors errors = null;
+    
+    public ActionErrors validate(ActionMapping mapping,
+    HttpServletRequest request) {
+
+        errors = new ActionErrors();
+
+        String submit = request.getParameter("submit");
+        //if (submit != null) {
+
+            // name is a required field
+            if ((name == null) || (name.length() < 1)) {
+                errors.add("name",
+                           new ActionError("resources.error.name.required"));
+            }
+
+            // value is a required field
+            if ((value == null) || (value.length() < 1)) {
+                errors.add("value",
+                           new ActionError("resources.error.value.required"));
+            }
+
+            // Quotes not allowed in name
+            if ((name != null) && (name.indexOf('"') >= 0)) {
+                errors.add("name",
+                           new ActionError("users.error.quotes"));
+            }
+
+            // Quotes not allowed in value
+            if ((value != null) && (value.indexOf('"') > 0)) {
+                errors.add("value",
+                           new ActionError("users.error.quotes"));
+            }
+
+            // Quotes not allowed in description
+            if ((description != null) && (description.indexOf('"') > 0)) {
+                errors.add("description",
+                           new ActionError("users.error.quotes"));
+            }
+            
+            // if cehcked, override will be sent as a request parameter
+            override = (request.getParameter("override") != null);
+            
+            if (validateType(entryType, value)) {
+                   errors.add("value",
+                           new ActionError("resources.error.value.mismatch"));
+            }
+        //}
+        return (errors);
+    }
+
+    /**
+     * Entry type must match type of value.
+     */
+    private boolean validateType(String entryType, String value) {
+        Class cls = null;
+        boolean mismatch = false;
+        try {
+            cls = Class.forName(entryType);
+            
+            if (Character.class.isAssignableFrom(cls)) {
+                // Special handling is needed because the UI returns
+                // a string even if it is a character (single length string).
+                if (value.length() != 1) {
+                    mismatch = true;
+                }
+            } else if (Boolean.class.isAssignableFrom(cls)) {
+                // Special handling is needed because Boolean
+                // string constructor accepts anything other than
+                // true to be false
+                if (!("true".equalsIgnoreCase(value) ||
+                "false".equalsIgnoreCase(value))) {
+                    mismatch = true;
+                }
+            } else if (Number.class.isAssignableFrom(cls)) {
+                // all numbers throw NumberFormatException if they are
+                // constructed with an incorrect number string
+                // We use the general string constructor to do this job
+                try {
+                    Class[] parameterTypes = {String.class};
+                    Constructor ct = cls.getConstructor(parameterTypes);
+                    Object arglist1[] = {value};
+                    Object retobj = ct.newInstance(arglist1);
+                } catch (Exception e) {
+                    mismatch = true;
+                }
+            } else if (String.class.isAssignableFrom(cls)) {
+                // all strings are allowed
+            } else {
+                // validation for other types not implemented yet
+               errors.add("entryType",
+                       new ActionError("resources.error.entryType.notimpl"));
+            }
+        } catch (ClassNotFoundException cnfe) {
+            // entry type has an invalid entry
+           errors.add("entryType",
+                       new ActionError("resources.error.entryType.invalid"));
+         }        
+        return mismatch;
+    }
+    
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/resources/ListDataSourcesAction.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/resources/ListDataSourcesAction.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/resources/ListDataSourcesAction.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,139 @@
+/*
+ * Copyright 2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.admin.resources;
+
+
+import java.io.IOException;
+import java.net.URLDecoder;
+import java.util.Locale;
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+import org.apache.struts.action.Action;
+import org.apache.struts.action.ActionForm;
+import org.apache.struts.action.ActionForward;
+import org.apache.struts.action.ActionMapping;
+import org.apache.struts.util.MessageResources;
+import org.apache.webapp.admin.ApplicationServlet;
+import org.apache.webapp.admin.TomcatTreeBuilder;
+
+/**
+ * <p>Retrieve the set of MBean names for all currently defined data sources,
+ * and expose them in a request attribute named "dataSourcesForm".  This action
+ * requires the following request parameters to be set:</p>
+ * <ul>
+ * <li><strong>forward</strong> - Global forward to which we should
+ *     go after stashing the dataSources list.</li>
+ * </ul>
+ *
+ * @author Manveen Kaur
+ * @author Amy Roh
+ * @version $Revision: 303390 $ $Date: 2004-10-18 01:37:56 -0500 (Mon, 18 Oct 2004) $
+ * @since 4.1
+ */
+
+public class ListDataSourcesAction extends Action {
+
+    // ----------------------------------------------------- Instance Variables
+
+    /**
+     * The MBeanServer we will be interacting with.
+     */
+    private MBeanServer mserver = null;
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Process the specified HTTP request, and create the corresponding HTTP
+     * response (or forward to another web component that will create it).
+     * Return an <code>ActionForward</code> instance describing where and how
+     * control should be forwarded, or <code>null</code> if the response has
+     * already been completed.
+     *
+     * @param mapping The ActionMapping used to select this instance
+     * @param actionForm The optional ActionForm bean for this request (if any)
+     * @param request The HTTP request we are processing
+     * @param response The HTTP response we are creating
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception ServletException if a servlet exception occurs
+     */
+    public ActionForward execute(ActionMapping mapping,
+                                 ActionForm form,
+                                 HttpServletRequest request,
+                                 HttpServletResponse response)
+        throws IOException, ServletException {
+
+
+        // Look up the components we will be using as needed
+        if (mserver == null) {
+            mserver = ((ApplicationServlet) getServlet()).getServer();
+        }
+        MessageResources resources = getResources(request);
+        HttpSession session = request.getSession();
+        Locale locale = getLocale(request);
+        
+        String resourcetype = request.getParameter("resourcetype");
+        String path = request.getParameter("path");
+        String host = request.getParameter("host");
+        String domain = request.getParameter("domain");
+        
+        if (resourcetype != null) {
+            resourcetype = URLDecoder.decode(resourcetype,TomcatTreeBuilder.URL_ENCODING);
+        }
+        if (path != null) {
+            path = URLDecoder.decode(path,TomcatTreeBuilder.URL_ENCODING);
+        }
+        if (host != null) {
+            host = URLDecoder.decode(host,TomcatTreeBuilder.URL_ENCODING);
+        }
+        if (domain != null) {
+            domain = URLDecoder.decode(domain,TomcatTreeBuilder.URL_ENCODING);
+        }
+        
+        // Create a form bean containing the requested MBean Names
+        DataSourcesForm dataSourcesForm = null;
+        try {
+              dataSourcesForm = 
+                ResourceUtils.getDataSourcesForm(mserver, resourcetype,
+                                        path, host, domain);
+        } catch (Exception e) {
+            getServlet().log(resources.getMessage
+                             (locale,
+                              "users.error.attribute.get", "resources"), e);
+            response.sendError
+                (HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
+                 resources.getMessage
+                 (locale, "users.error.attribute.get", "resources"));
+        }
+
+        // Stash the results in request scope
+        request.setAttribute("dataSourcesForm", dataSourcesForm);
+        saveToken(request);
+        String forward =
+            URLDecoder.decode(request.getParameter("forward"),TomcatTreeBuilder.URL_ENCODING);
+        
+        return (mapping.findForward(forward));
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/resources/ListEnvEntriesAction.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/resources/ListEnvEntriesAction.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/resources/ListEnvEntriesAction.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,139 @@
+/*
+ * Copyright 2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.admin.resources;
+
+
+import java.io.IOException;
+import java.net.URLDecoder;
+import java.util.Locale;
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+import org.apache.struts.action.Action;
+import org.apache.struts.action.ActionForm;
+import org.apache.struts.action.ActionForward;
+import org.apache.struts.action.ActionMapping;
+import org.apache.struts.util.MessageResources;
+import org.apache.webapp.admin.ApplicationServlet;
+import org.apache.webapp.admin.TomcatTreeBuilder;
+
+/**
+ * <p>Retrieve the set of MBean names for all currently defined environment entries,
+ * and expose them in a request attribute named "enventriesForm".  This action
+ * requires the following request parameters to be set:</p>
+ * <ul>
+ * <li><strong>forward</strong> - Global forward to which we should
+ *     go after stashing the env entries list.</li>
+ * </ul>
+ *
+ * @author Manveen Kaur
+ * @version $Revision: 303390 $ $Date: 2004-10-18 01:37:56 -0500 (Mon, 18 Oct 2004) $
+ * @since 4.1
+ */
+
+public class ListEnvEntriesAction extends Action {
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The MBeanServer we will be interacting with.
+     */
+    private MBeanServer mserver = null;
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Process the specified HTTP request, and create the corresponding HTTP
+     * response (or forward to another web component that will create it).
+     * Return an <code>ActionForward</code> instance describing where and how
+     * control should be forwarded, or <code>null</code> if the response has
+     * already been completed.
+     *
+     * @param mapping The ActionMapping used to select this instance
+     * @param actionForm The optional ActionForm bean for this request (if any)
+     * @param request The HTTP request we are processing
+     * @param response The HTTP response we are creating
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception ServletException if a servlet exception occurs
+     */
+    public ActionForward execute(ActionMapping mapping,
+                                 ActionForm form,
+                                 HttpServletRequest request,
+                                 HttpServletResponse response)
+        throws IOException, ServletException {
+
+
+        // Look up the components we will be using as needed
+        if (mserver == null) {
+            mserver = ((ApplicationServlet) getServlet()).getServer();
+        }
+        MessageResources resources = getResources(request);
+        HttpSession session = request.getSession();
+        Locale locale = getLocale(request);
+        
+        String resourcetype = request.getParameter("resourcetype");
+        String path = request.getParameter("path");
+        String host = request.getParameter("host");
+        String domain = request.getParameter("domain");
+        
+        if (resourcetype != null) {
+            resourcetype = URLDecoder.decode(resourcetype,TomcatTreeBuilder.URL_ENCODING);
+        }
+        if (path != null) {
+            path = URLDecoder.decode(path,TomcatTreeBuilder.URL_ENCODING);
+        }
+        if (host != null) {
+            host = URLDecoder.decode(host,TomcatTreeBuilder.URL_ENCODING);
+        }
+        if (domain != null) {
+            domain = URLDecoder.decode(domain,TomcatTreeBuilder.URL_ENCODING);
+        }
+        // Create a form bean containing the requested MBean Names
+        EnvEntriesForm envEntriesForm = null;
+        try {
+           envEntriesForm = 
+                    ResourceUtils.getEnvEntriesForm(mserver, resourcetype,
+                                        path, host, domain);
+        } catch (Exception e) {
+            getServlet().log(resources.getMessage
+                             (locale,
+                              "users.error.attribute.get", "environments"), e);
+            response.sendError
+                (HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
+                 resources.getMessage
+                 (locale, "users.error.attribute.get", "environments"));
+        }
+
+        // Stash the results in request scope
+        request.setAttribute("envEntriesForm", envEntriesForm);
+        saveToken(request);
+        String forward =
+            URLDecoder.decode(request.getParameter("forward"),TomcatTreeBuilder.URL_ENCODING);
+        
+        return (mapping.findForward(forward));
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/resources/ListMailSessionsAction.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/resources/ListMailSessionsAction.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/resources/ListMailSessionsAction.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,138 @@
+/*
+ * Copyright 2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.admin.resources;
+
+
+import java.io.IOException;
+import java.net.URLDecoder;
+import java.util.Locale;
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+import org.apache.struts.action.Action;
+import org.apache.struts.action.ActionForm;
+import org.apache.struts.action.ActionForward;
+import org.apache.struts.action.ActionMapping;
+import org.apache.struts.util.MessageResources;
+import org.apache.webapp.admin.ApplicationServlet;
+import org.apache.webapp.admin.TomcatTreeBuilder;
+
+/**
+ * <p>Retrieve the set of MBean names for all currently defined mail sessions,
+ * and expose them in a request attribute named "mailSessionsForm".  This action
+ * requires the following request parameters to be set:</p>
+ * <ul>
+ * <li><strong>forward</strong> - Global forward to which we should
+ *     go after stashing the mailSessions list.</li>
+ * </ul>
+ *
+ * @author Amy Roh
+ * @version $Revision: 303390 $ $Date: 2004-10-18 01:37:56 -0500 (Mon, 18 Oct 2004) $
+ * @since 4.1
+ */
+
+public class ListMailSessionsAction extends Action {
+
+    // ----------------------------------------------------- Instance Variables
+
+    /**
+     * The MBeanServer we will be interacting with.
+     */
+    private MBeanServer mserver = null;
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Process the specified HTTP request, and create the corresponding HTTP
+     * response (or forward to another web component that will create it).
+     * Return an <code>ActionForward</code> instance describing where and how
+     * control should be forwarded, or <code>null</code> if the response has
+     * already been completed.
+     *
+     * @param mapping The ActionMapping used to select this instance
+     * @param actionForm The optional ActionForm bean for this request (if any)
+     * @param request The HTTP request we are processing
+     * @param response The HTTP response we are creating
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception ServletException if a servlet exception occurs
+     */
+    public ActionForward execute(ActionMapping mapping,
+                                 ActionForm form,
+                                 HttpServletRequest request,
+                                 HttpServletResponse response)
+        throws IOException, ServletException {
+
+
+        // Look up the components we will be using as needed
+        if (mserver == null) {
+            mserver = ((ApplicationServlet) getServlet()).getServer();
+        }
+        MessageResources resources = getResources(request);
+        HttpSession session = request.getSession();
+        Locale locale = getLocale(request);
+        
+        String resourcetype = request.getParameter("resourcetype");
+        String path = request.getParameter("path");
+        String host = request.getParameter("host");
+        String domain = request.getParameter("domain");
+        
+        if (resourcetype != null) {
+            resourcetype = URLDecoder.decode(resourcetype,TomcatTreeBuilder.URL_ENCODING);
+        }
+        if (path != null) {
+            path = URLDecoder.decode(path,TomcatTreeBuilder.URL_ENCODING);
+        }
+        if (host != null) {
+            host = URLDecoder.decode(host,TomcatTreeBuilder.URL_ENCODING);
+        }
+        if (domain != null) {
+            domain = URLDecoder.decode(domain,TomcatTreeBuilder.URL_ENCODING);
+        }
+        
+        // Create a form bean containing the requested MBean Names
+        MailSessionsForm mailSessionsForm = null;
+        try {
+              mailSessionsForm = 
+                ResourceUtils.getMailSessionsForm(mserver, resourcetype,
+                                        path, host, domain);
+        } catch (Exception e) {
+            getServlet().log(resources.getMessage
+                             (locale,
+                              "users.error.attribute.get", "resources"), e);
+            response.sendError
+                (HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
+                 resources.getMessage
+                 (locale, "users.error.attribute.get", "resources"));
+        }
+
+        // Stash the results in request scope
+        request.setAttribute("mailSessionsForm", mailSessionsForm);
+        saveToken(request);
+        String forward =
+            URLDecoder.decode(request.getParameter("forward"),TomcatTreeBuilder.URL_ENCODING);
+        
+        return (mapping.findForward(forward));
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/resources/ListResourceLinksAction.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/resources/ListResourceLinksAction.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/resources/ListResourceLinksAction.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,138 @@
+/*
+ * Copyright 2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.admin.resources;
+
+
+import java.io.IOException;
+import java.net.URLDecoder;
+import java.util.Locale;
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+import org.apache.struts.action.Action;
+import org.apache.struts.action.ActionForm;
+import org.apache.struts.action.ActionForward;
+import org.apache.struts.action.ActionMapping;
+import org.apache.struts.util.MessageResources;
+import org.apache.webapp.admin.ApplicationServlet;
+import org.apache.webapp.admin.TomcatTreeBuilder;
+
+/**
+ * <p>Retrieve the set of MBean names for all currently defined resource links,
+ * and expose them in a request attribute named "resourceLinksForm".  This action
+ * requires the following request parameters to be set:</p>
+ * <ul>
+ * <li><strong>forward</strong> - Global forward to which we should
+ *     go after stashing the resourceLinks list.</li>
+ * </ul>
+ *
+ * @author Amy Roh
+ * @version $Revision: 303390 $ $Date: 2004-10-18 01:37:56 -0500 (Mon, 18 Oct 2004) $
+ * @since 4.1
+ */
+
+public class ListResourceLinksAction extends Action {
+
+    // ----------------------------------------------------- Instance Variables
+
+    /**
+     * The MBeanServer we will be interacting with.
+     */
+    private MBeanServer mserver = null;
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Process the specified HTTP request, and create the corresponding HTTP
+     * response (or forward to another web component that will create it).
+     * Return an <code>ActionForward</code> instance describing where and how
+     * control should be forwarded, or <code>null</code> if the response has
+     * already been completed.
+     *
+     * @param mapping The ActionMapping used to select this instance
+     * @param actionForm The optional ActionForm bean for this request (if any)
+     * @param request The HTTP request we are processing
+     * @param response The HTTP response we are creating
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception ServletException if a servlet exception occurs
+     */
+    public ActionForward execute(ActionMapping mapping,
+                                 ActionForm form,
+                                 HttpServletRequest request,
+                                 HttpServletResponse response)
+        throws IOException, ServletException {
+
+
+        // Look up the components we will be using as needed
+        if (mserver == null) {
+            mserver = ((ApplicationServlet) getServlet()).getServer();
+        }
+        MessageResources resources = getResources(request);
+        HttpSession session = request.getSession();
+        Locale locale = getLocale(request);
+        
+        String resourcetype = request.getParameter("resourcetype");
+        String path = request.getParameter("path");
+        String host = request.getParameter("host");
+        String domain = request.getParameter("domain");
+            
+        if (resourcetype != null) {
+            resourcetype = URLDecoder.decode(resourcetype,TomcatTreeBuilder.URL_ENCODING);
+        }
+        if (path != null) {
+            path = URLDecoder.decode(path,TomcatTreeBuilder.URL_ENCODING);
+        }
+        if (host != null) {
+            host = URLDecoder.decode(host,TomcatTreeBuilder.URL_ENCODING);
+        }
+        if (domain != null) {
+            domain = URLDecoder.decode(domain,TomcatTreeBuilder.URL_ENCODING);
+        }
+        
+        // Create a form bean containing the requested MBean Names
+        ResourceLinksForm resourceLinksForm = null;
+        try {
+              resourceLinksForm = 
+                ResourceUtils.getResourceLinksForm(mserver, resourcetype,
+                                        path, host, domain);
+        } catch (Exception e) {
+            getServlet().log(resources.getMessage
+                             (locale,
+                              "users.error.attribute.get", "resources"), e);
+            response.sendError
+                (HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
+                 resources.getMessage
+                 (locale, "users.error.attribute.get", "resources"));
+        }
+
+        // Stash the results in request scope
+        request.setAttribute("resourceLinksForm", resourceLinksForm);
+        saveToken(request);
+        String forward =
+            URLDecoder.decode(request.getParameter("forward"),TomcatTreeBuilder.URL_ENCODING);
+        
+        return (mapping.findForward(forward));
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/resources/ListUserDatabasesAction.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/resources/ListUserDatabasesAction.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/resources/ListUserDatabasesAction.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,125 @@
+/*
+ * Copyright 2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.admin.resources;
+
+
+import java.io.IOException;
+import java.net.URLDecoder;
+import java.util.Locale;
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+import org.apache.struts.action.Action;
+import org.apache.struts.action.ActionForm;
+import org.apache.struts.action.ActionForward;
+import org.apache.struts.action.ActionMapping;
+import org.apache.struts.util.MessageResources;
+import org.apache.webapp.admin.ApplicationServlet;
+import org.apache.webapp.admin.TomcatTreeBuilder;
+
+/**
+ * <p>Retrieve the set of MBean names for all currently defined environment entries,
+ * and expose them in a request attribute named "enventriesForm".  This action
+ * requires the following request parameters to be set:</p>
+ * <ul>
+ * <li><strong>forward</strong> - Global forward to which we should
+ *     go after stashing the env entries list.</li>
+ * </ul>
+ *
+ * @author Manveen Kaur
+ * @version $Revision: 303390 $ $Date: 2004-10-18 01:37:56 -0500 (Mon, 18 Oct 2004) $
+ * @since 4.1
+ */
+
+public class ListUserDatabasesAction extends Action {
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The MBeanServer we will be interacting with.
+     */
+    private MBeanServer mserver = null;
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Process the specified HTTP request, and create the corresponding HTTP
+     * response (or forward to another web component that will create it).
+     * Return an <code>ActionForward</code> instance describing where and how
+     * control should be forwarded, or <code>null</code> if the response has
+     * already been completed.
+     *
+     * @param mapping The ActionMapping used to select this instance
+     * @param actionForm The optional ActionForm bean for this request (if any)
+     * @param request The HTTP request we are processing
+     * @param response The HTTP response we are creating
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception ServletException if a servlet exception occurs
+     */
+    public ActionForward execute(ActionMapping mapping,
+                                 ActionForm form,
+                                 HttpServletRequest request,
+                                 HttpServletResponse response)
+        throws IOException, ServletException {
+
+
+        // Look up the components we will be using as needed
+        if (mserver == null) {
+            mserver = ((ApplicationServlet) getServlet()).getServer();
+        }
+        MessageResources resources = getResources(request);
+        HttpSession session = request.getSession();
+        Locale locale = getLocale(request);
+
+        String domain = request.getParameter("domain");
+        if (domain != null) {
+            domain = URLDecoder.decode(domain,TomcatTreeBuilder.URL_ENCODING);
+        }
+        // Create a form bean containing the requested MBean Names
+        UserDatabasesForm userDatabasesForm = null;
+        try {
+              userDatabasesForm = 
+                        ResourceUtils.getUserDatabasesForm(mserver, domain);
+              userDatabasesForm.setDomain(domain);
+        } catch (Exception e) {
+            getServlet().log(resources.getMessage
+                             (locale,
+                              "users.error.attribute.get", "resources"), e);
+            response.sendError
+                (HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
+                 resources.getMessage
+                 (locale, "users.error.attribute.get", "resources"));
+        }
+        
+        // Stash the results in request scope
+        request.setAttribute("userDatabasesForm", userDatabasesForm);
+        saveToken(request);
+        String forward =
+            URLDecoder.decode(request.getParameter("forward"),TomcatTreeBuilder.URL_ENCODING);
+        return (mapping.findForward(forward));
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/resources/MailSessionForm.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/resources/MailSessionForm.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/resources/MailSessionForm.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,209 @@
+/*
+ * Copyright 2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.admin.resources;
+
+import java.util.List;
+import java.util.ArrayList;
+
+import javax.servlet.http.HttpServletRequest;
+import org.apache.struts.action.ActionError;
+import org.apache.struts.action.ActionErrors;
+import org.apache.struts.action.ActionForm;
+import org.apache.struts.action.ActionMapping;
+import org.apache.webapp.admin.LabelValueBean;
+
+/**
+ * Form bean for the individual mail session page.
+ *
+ * @author Amy Roh
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ * @since 4.1
+ */
+
+public final class MailSessionForm extends BaseForm {
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    // ------------------------------------------------------------- Properties
+
+    
+    /**
+     * The name of the mail session.
+     */
+    private String name = null;
+
+    public String getName() {
+        return (this.name);
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+    
+    /**
+     * The mail.smtp.host of the mail session.
+     */
+    private String mailhost = null;
+
+    public String getMailhost() {
+        return (this.mailhost);
+    }
+
+    public void setMailhost(String mailhost) {
+        this.mailhost = mailhost;
+    }
+
+    /**
+     * The resource type of this mail session.
+     */
+    private String resourcetype = null;
+    
+    /**
+     * Return the resource type of the mail session this bean refers to.
+     */
+    public String getResourcetype() {
+        return this.resourcetype;
+    }
+
+    /**
+     * Set the resource type of the mail session this bean refers to.
+     */
+    public void setResourcetype(String resourcetype) {
+        this.resourcetype = resourcetype;
+    }
+       
+    /**
+     * The path of this mail session.
+     */
+    private String path = null;
+    
+    /**
+     * Return the path of the mail session this bean refers to.
+     */
+    public String getPath() {
+        return this.path;
+    }
+
+    /**
+     * Set the path of the mail session this bean refers to.
+     */
+    public void setPath(String path) {
+        this.path = path;
+    }
+       
+    /**
+     * The host of this mail session.
+     */
+    private String host = null;
+    
+    /**
+     * Return the host of the mail session this bean refers to.
+     */
+    public String getHost() {
+        return this.host;
+    }
+
+    /**
+     * Set the host of the mail session this bean refers to.
+     */
+    public void setHost(String host) {
+        this.host = host;
+    }    
+    
+       
+    /**
+     * The domain of this mail session.
+     */
+    private String domain = null;
+    
+    /**
+     * Return the domain of the mail session this bean refers to.
+     */
+    public String getDomain() {
+        return this.domain;
+    }
+
+    /**
+     * Set the domain of the mail session this bean refers to.
+     */
+    public void setDomain(String domain) {
+        this.domain = domain;
+    }
+    
+    /**
+     * The type of the resource.
+     */
+    private String type = null;
+
+    public String getType() {
+        return (this.type);
+    }
+
+    public void setType(String type) {
+        this.type = type;
+    }
+
+    // --------------------------------------------------------- Public Methods
+
+    /**
+     * Reset all properties to their default values.
+     *
+     * @param mapping The mapping used to select this instance
+     * @param request The servlet request we are processing
+     */
+    public void reset(ActionMapping mapping, HttpServletRequest request) {
+
+        super.reset(mapping, request);
+        mailhost = null;   
+        type = null;
+    }
+
+    /**
+     * Validate the properties that have been set from this HTTP request,
+     * and return an <code>ActionErrors</code> object that encapsulates any
+     * validation errors that have been found.  If no errors are found, return
+     * <code>null</code> or an <code>ActionErrors</code> object with no
+     * recorded error messages.
+     *
+     * @param mapping The mapping used to select this instance
+     * @param request The servlet request we are processing
+     */
+    
+    private ActionErrors errors = null;
+    
+    public ActionErrors validate(ActionMapping mapping,
+    HttpServletRequest request) {
+
+        errors = new ActionErrors();
+
+        String submit = request.getParameter("submit");
+
+        //if (submit != null) {
+
+            // mailSmtpHost is a required field
+            if ((mailhost == null) || (mailhost.length() < 1)) {
+                errors.add("mailhost",
+                      new ActionError("resources.error.mailhost.required"));
+            }
+         //}
+        
+        return (errors);
+    }
+    
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/resources/MailSessionsForm.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/resources/MailSessionsForm.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/resources/MailSessionsForm.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,150 @@
+/*
+ * Copyright 2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.admin.resources;
+
+import javax.servlet.http.HttpServletRequest;
+import org.apache.struts.action.ActionError;
+import org.apache.struts.action.ActionErrors;
+import org.apache.struts.action.ActionForm;
+import org.apache.struts.action.ActionMapping;
+
+
+/**
+ * Form bean for the delete mail sessions page.
+ *
+ * @author Amy Roh
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ * @since 4.1
+ */
+
+public final class MailSessionsForm extends BaseForm {
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * The object names of the specified environment entries.
+     */
+    private String mailSessions[] = null;
+
+    public String[] getMailSessions() {
+        return (this.mailSessions);
+    }
+
+    public void setMailSessions(String mailSessions[]) {
+        this.mailSessions = mailSessions;
+    }
+
+    /**
+     * The resource type of this mail session.
+     */
+    private String resourcetype = null;
+    
+    /**
+     * Return the resource type of the mail session this bean refers to.
+     */
+    public String getResourcetype() {
+        return this.resourcetype;
+    }
+
+    /**
+     * Set the resource type of the mail session this bean refers to.
+     */
+    public void setResourcetype(String resourcetype) {
+        this.resourcetype = resourcetype;
+    }
+       
+    /**
+     * The path of this mail session.
+     */
+    private String path = null;
+    
+    /**
+     * Return the path of the mail session this bean refers to.
+     */
+    public String getPath() {
+        return this.path;
+    }
+
+    /**
+     * Set the path of the mail session this bean refers to.
+     */
+    public void setPath(String path) {
+        this.path = path;
+    }
+       
+    /**
+     * The host of this mail session.
+     */
+    private String host = null;
+    
+    /**
+     * Return the host of the mail session this bean refers to.
+     */
+    public String getHost() {
+        return this.host;
+    }
+
+    /**
+     * Set the host of the mail session this bean refers to.
+     */
+    public void setHost(String host) {
+        this.host = host;
+    }    
+    
+       
+    /**
+     * The domain of this mail session.
+     */
+    private String domain = null;
+    
+    /**
+     * Return the domain of the mail session this bean refers to.
+     */
+    public String getDomain() {
+        return this.domain;
+    }
+
+    /**
+     * Set the domain of the mail session this bean refers to.
+     */
+    public void setDomain(String domain) {
+        this.domain = domain;
+    }
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Reset all properties to their default values.
+     *
+     * @param mapping The mapping used to select this instance
+     * @param request The servlet request we are processing
+     */
+    public void reset(ActionMapping mapping, HttpServletRequest request) {
+
+        super.reset(mapping, request);
+        this.mailSessions = null;
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/resources/ResourceLinkForm.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/resources/ResourceLinkForm.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/resources/ResourceLinkForm.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,224 @@
+/*
+ * Copyright 2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.admin.resources;
+
+import java.util.List;
+import java.util.ArrayList;
+
+import javax.servlet.http.HttpServletRequest;
+import org.apache.struts.action.ActionError;
+import org.apache.struts.action.ActionErrors;
+import org.apache.struts.action.ActionForm;
+import org.apache.struts.action.ActionMapping;
+import org.apache.webapp.admin.LabelValueBean;
+
+/**
+ * Form bean for the individual resource link page.
+ *
+ * @author Amy Roh
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ * @since 4.1
+ */
+
+public final class ResourceLinkForm extends BaseForm {
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * The name of the resource link.
+     */
+    private String name = null;
+
+    public String getName() {
+        return (this.name);
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    /**
+     * The global name of the resource link.
+     */
+    private String global = null;
+
+    public String getGlobal() {
+        return (this.global);
+    }
+
+    public void setGlobal(String global) {
+        this.global = global;
+    }
+    
+    /**
+     * The resource type of this resource link.
+     */
+    private String resourcetype = null;
+    
+    /**
+     * Return the resource type of the resource link this bean refers to.
+     */
+    public String getResourcetype() {
+        return this.resourcetype;
+    }
+
+    /**
+     * Set the resource type of the resource link this bean refers to.
+     */
+    public void setResourcetype(String resourcetype) {
+        this.resourcetype = resourcetype;
+    }
+       
+    /**
+     * The path of this resource link.
+     */
+    private String path = null;
+    
+    /**
+     * Return the path of the resource link this bean refers to.
+     */
+    public String getPath() {
+        return this.path;
+    }
+
+    /**
+     * Set the path of the resource link this bean refers to.
+     */
+    public void setPath(String path) {
+        this.path = path;
+    }
+       
+    /**
+     * The host of this resource link.
+     */
+    private String host = null;
+    
+    /**
+     * Return the host of the resource link this bean refers to.
+     */
+    public String getHost() {
+        return this.host;
+    }
+
+    /**
+     * Set the host of the resource link this bean refers to.
+     */
+    public void setHost(String host) {
+        this.host = host;
+    }    
+    
+       
+    /**
+     * The domain of this resource link.
+     */
+    private String domain = null;
+    
+    /**
+     * Return the domain of the resource link this bean refers to.
+     */
+    public String getDomain() {
+        return this.domain;
+    }
+
+    /**
+     * Set the domain of the resource link this bean refers to.
+     */
+    public void setDomain(String domain) {
+        this.domain = domain;
+    }
+    
+    /**
+     * The type of the resource link link.
+     */
+    private String type = null;
+
+    public String getType() {
+        return (this.type);
+    }
+
+    public void setType(String type) {
+        this.type = type;
+    }
+
+    // --------------------------------------------------------- Public Methods
+
+    /**
+     * Reset all properties to their default values.
+     *
+     * @param mapping The mapping used to select this instance
+     * @param request The servlet request we are processing
+     */
+    public void reset(ActionMapping mapping, HttpServletRequest request) {
+
+        super.reset(mapping, request);
+        name = null;
+        global = null;
+        type = null;
+    }
+
+    /**
+     * Validate the properties that have been set from this HTTP request,
+     * and return an <code>ActionErrors</code> object that encapsulates any
+     * validation errors that have been found.  If no errors are found, return
+     * <code>null</code> or an <code>ActionErrors</code> object with no
+     * recorded error messages.
+     *
+     * @param mapping The mapping used to select this instance
+     * @param request The servlet request we are processing
+     */
+    
+    private ActionErrors errors = null;
+    
+    public ActionErrors validate(ActionMapping mapping,
+    HttpServletRequest request) {
+        errors = new ActionErrors();
+
+        String submit = request.getParameter("submit");
+
+        //if (submit != null) {
+
+            // name is a required field
+            if ((name == null) || (name.length() < 1)) {
+                errors.add("name",
+                           new ActionError("resources.error.name.required"));
+            }
+
+            // global is a required field
+            if (( global == null) || (global.length() < 1)) {
+                errors.add("global",
+                           new ActionError("resources.error.global.required"));
+            }
+            
+            // type is a required field
+            if ((type == null) || (type.length() < 1)) {
+                errors.add("type",
+                           new ActionError("resources.error.type.required"));
+            }
+            
+         //}
+
+        return (errors);
+
+    }
+ 
+    
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/resources/ResourceLinksForm.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/resources/ResourceLinksForm.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/resources/ResourceLinksForm.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,151 @@
+/*
+ * Copyright 2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.admin.resources;
+
+import javax.servlet.http.HttpServletRequest;
+import org.apache.struts.action.ActionError;
+import org.apache.struts.action.ActionErrors;
+import org.apache.struts.action.ActionForm;
+import org.apache.struts.action.ActionMapping;
+
+
+/**
+ * Form bean for the delete resource links page.
+ *
+ * @author Amy Roh
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ * @since 4.1
+ */
+
+public final class ResourceLinksForm extends BaseForm {
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * The object names of the specified resource links.
+     */
+    private String resourceLinks[] = null;
+
+    public String[] getResourceLinks() {
+        return (this.resourceLinks);
+    }
+
+    public void setResourceLinks(String resourceLinks[]) {
+        this.resourceLinks = resourceLinks;
+    }
+    
+    
+    /**
+     * The resource type of this resource link.
+     */
+    private String resourcetype = null;
+    
+    /**
+     * Return the resource type of the resource link this bean refers to.
+     */
+    public String getResourcetype() {
+        return this.resourcetype;
+    }
+
+    /**
+     * Set the resource type of the resource link this bean refers to.
+     */
+    public void setResourcetype(String resourcetype) {
+        this.resourcetype = resourcetype;
+    }
+       
+    /**
+     * The path of this resource link.
+     */
+    private String path = null;
+    
+    /**
+     * Return the path of the resource link this bean refers to.
+     */
+    public String getPath() {
+        return this.path;
+    }
+
+    /**
+     * Set the path of the resource link this bean refers to.
+     */
+    public void setPath(String path) {
+        this.path = path;
+    }
+       
+    /**
+     * The host of this resource link.
+     */
+    private String host = null;
+    
+    /**
+     * Return the host of the resource link this bean refers to.
+     */
+    public String getHost() {
+        return this.host;
+    }
+
+    /**
+     * Set the host of the resource link this bean refers to.
+     */
+    public void setHost(String host) {
+        this.host = host;
+    }    
+    
+       
+    /**
+     * The domain of this resource link.
+     */
+    private String domain = null;
+    
+    /**
+     * Return the domain of the resource link this bean refers to.
+     */
+    public String getDomain() {
+        return this.domain;
+    }
+
+    /**
+     * Set the domain of the resource link this bean refers to.
+     */
+    public void setDomain(String domain) {
+        this.domain = domain;
+    }
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Reset all properties to their default values.
+     *
+     * @param mapping The mapping used to select this instance
+     * @param request The servlet request we are processing
+     */
+    public void reset(ActionMapping mapping, HttpServletRequest request) {
+
+        super.reset(mapping, request);
+        this.resourceLinks = null;
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/resources/ResourceUtils.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/resources/ResourceUtils.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/resources/ResourceUtils.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,418 @@
+/*
+ * Copyright 2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.admin.resources;
+
+import java.util.Arrays;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.Collections;
+
+import javax.management.Attribute;
+import javax.management.AttributeNotFoundException;
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+import javax.management.ObjectInstance;
+
+
+/**
+ * <p>Shared utility methods for the resource administration module.</p>
+ *
+ * @author Manveen Kaur
+ * @author Amy Roh
+ * @version $Revision: 302868 $ $Date: 2004-04-30 12:53:59 -0500 (Fri, 30 Apr 2004) $
+ * @since 4.1
+ */
+
+public class ResourceUtils {
+
+    public final static String ENVIRONMENT_TYPE = ":type=Environment";
+    public final static String RESOURCE_TYPE = ":type=Resource";
+    public final static String RESOURCELINK_TYPE = ":type=ResourceLink";
+    public final static String NAMINGRESOURCES_TYPE = ":type=NamingResources";
+    public final static String GLOBAL_TYPE = ",resourcetype=Global";
+    public final static String CONTEXT_TYPE = ",resourcetype=Context";
+    public final static String SERVICE_DEFAULTCONTEXT_TYPE = 
+                                                ",resourcetype=ServiceDefaultContext";
+    public final static String HOST_DEFAULTCONTEXT_TYPE = 
+                                                ",resourcetype=HostDefaultContext";                                                
+    
+    // resource class names
+    public final static String USERDB_CLASS = "org.apache.catalina.UserDatabase";
+    public final static String DATASOURCE_CLASS = "javax.sql.DataSource";
+    public final static String MAILSESSION_CLASS = "javax.mail.Session";
+
+    // --------------------------------------------------------- Public Methods
+
+
+    public static ObjectName getNamingResourceObjectName(String domain,
+            String resourcetype, String path, String host) throws Exception {
+
+        ObjectName oname = null;
+        if ((resourcetype==null) || (domain==null)) {
+            return null;
+        }
+        // Construct the MBean Name for the naming source
+        if (resourcetype.equals("Global")) {
+            oname = new ObjectName(domain + NAMINGRESOURCES_TYPE +
+                                GLOBAL_TYPE);
+        } else if (resourcetype.equals("Context")) {
+            oname = new ObjectName(domain + NAMINGRESOURCES_TYPE +
+                                CONTEXT_TYPE + 
+                                ",path=" + path + ",host=" + host);
+        } else if (resourcetype.equals("DefaultContext")) {
+            if (host.length() > 0) {
+                oname = new ObjectName(domain + NAMINGRESOURCES_TYPE +
+                                        HOST_DEFAULTCONTEXT_TYPE + 
+                                        ",host=" + host);
+            } else {
+                oname = new ObjectName(domain + NAMINGRESOURCES_TYPE +
+                                        SERVICE_DEFAULTCONTEXT_TYPE);            
+            }
+        }
+        
+        return oname;
+        
+    }
+    
+    /**
+     * Construct and return a ResourcesForm identifying all currently defined
+     * resources in the specified resource database.
+     *
+     * @param mserver MBeanServer to be consulted
+     *
+     * @exception Exception if an error occurs
+     */
+    public static EnvEntriesForm getEnvEntriesForm(MBeanServer mserver, 
+        String resourcetype, String path, String host, String domain) 
+        throws Exception {
+                           
+        ObjectName ename = null;
+        StringBuffer sb = null;        
+        if (resourcetype!=null) {
+            if (resourcetype.equals("Global")) {
+                ename = new ObjectName( domain + ENVIRONMENT_TYPE + 
+                                        GLOBAL_TYPE + ",*");
+            } else if (resourcetype.equals("Context")) {
+                ename = new ObjectName ( domain + ENVIRONMENT_TYPE + 
+                                        CONTEXT_TYPE + ",path=" + path + 
+                                        ",host=" + host + ",*");
+            } else if (resourcetype.equals("DefaultContext")) {
+                if (host.length() > 0) {
+                    ename = new ObjectName( domain + ENVIRONMENT_TYPE + 
+                        HOST_DEFAULTCONTEXT_TYPE + ",host=" + host + ",*");
+                } else {
+                    ename = new ObjectName( domain + ENVIRONMENT_TYPE + 
+                        SERVICE_DEFAULTCONTEXT_TYPE + ",*");
+                }
+            }
+        }
+        
+        Iterator iterator = (mserver.queryMBeans(ename, null).iterator());
+        
+        ArrayList results = new ArrayList();        
+        while (iterator.hasNext()) {
+            ObjectInstance instance = (ObjectInstance) iterator.next(); 
+            results.add(instance.getObjectName().toString());
+        }
+
+        Collections.sort(results);        
+        
+        EnvEntriesForm envEntriesForm = new EnvEntriesForm();
+        envEntriesForm.setEnvEntries((String[]) 
+                        results.toArray(new String[results.size()]));
+        
+        if (resourcetype != null) {
+            envEntriesForm.setResourcetype(resourcetype);
+        } else {
+            envEntriesForm.setResourcetype("");
+        }
+         if (path != null) {
+            envEntriesForm.setPath(path);
+        } else {
+            envEntriesForm.setPath("");
+        }        
+        if (host != null) {
+            envEntriesForm.setHost(host);
+        } else {
+            envEntriesForm.setHost("");
+        }          
+        if (domain != null) {
+            envEntriesForm.setDomain(domain);
+        } else {
+            envEntriesForm.setDomain("");
+        }          
+        
+        return (envEntriesForm);
+
+    }
+
+    /**
+     * Construct and return a DataSourcesForm identifying all currently defined
+     * datasources in the specified resource database.
+     *
+     * @param mserver MBeanServer to be consulted
+     *
+     * @exception Exception if an error occurs
+     */
+    public static DataSourcesForm getDataSourcesForm(MBeanServer mserver, 
+        String resourcetype, String path, String host, String domain) 
+        throws Exception {
+                            
+        ObjectName rname = null;
+        if (resourcetype!=null) {
+            if (resourcetype.equals("Global")) {
+                rname = new ObjectName( domain + RESOURCE_TYPE + GLOBAL_TYPE + 
+                                        ",class=" + DATASOURCE_CLASS + ",*");
+            } else if (resourcetype.equals("Context")) {
+                rname = new ObjectName ( domain + RESOURCE_TYPE + CONTEXT_TYPE + 
+                    ",path=" + path + ",host=" + host + ",class=" + 
+                    DATASOURCE_CLASS + ",*");
+            } else if (resourcetype.equals("DefaultContext")) {
+                if (host.length() > 0) {
+                    rname = new ObjectName( domain + RESOURCE_TYPE + 
+                        HOST_DEFAULTCONTEXT_TYPE + ",host=" + host + 
+                        ",class=" + DATASOURCE_CLASS + ",*");
+                } else {
+                    rname = new ObjectName( domain + RESOURCE_TYPE + 
+                        SERVICE_DEFAULTCONTEXT_TYPE +  
+                        ",class=" + DATASOURCE_CLASS + ",*");
+                }
+            }
+        }
+        Iterator iterator = (mserver.queryMBeans(rname, null).iterator());
+        
+        ArrayList results = new ArrayList();        
+        while (iterator.hasNext()) {
+            
+            ObjectInstance instance = (ObjectInstance) iterator.next(); 
+            ObjectName oname = instance.getObjectName();
+            try {
+                // only add resource mbean if definition exists
+                mserver.getAttribute(oname, "driverClassName");
+                results.add(oname.toString());
+            } catch (AttributeNotFoundException ex) {
+                mserver.setAttribute(oname, 
+                    new Attribute("driverClassName", ""));
+            }
+        }
+
+        Collections.sort(results);        
+        DataSourcesForm dataSourcesForm = new DataSourcesForm();
+        dataSourcesForm.setDataSources((String[]) 
+                        results.toArray(new String[results.size()]));        
+        
+        if (resourcetype != null) {
+            dataSourcesForm.setResourcetype(resourcetype);
+        } else {
+            dataSourcesForm.setResourcetype("");
+        }
+         if (path != null) {
+            dataSourcesForm.setPath(path);
+        } else {
+            dataSourcesForm.setPath("");
+        }        
+        if (host != null) {
+            dataSourcesForm.setHost(host);
+        } else {
+            dataSourcesForm.setHost("");
+        }        
+        if (domain != null) {
+            dataSourcesForm.setDomain(domain);
+        } else {
+            dataSourcesForm.setDomain("");
+        }          
+        return (dataSourcesForm);
+
+    }
+    
+    /**
+     * Construct and return a MailSessionsForm identifying all currently defined
+     * mailsessions in the specified resource database.
+     *
+     * @param mserver MBeanServer to be consulted
+     *
+     * @exception Exception if an error occurs
+     */
+    public static MailSessionsForm getMailSessionsForm(MBeanServer mserver, 
+        String resourcetype, String path, String host, String domain) 
+        throws Exception {
+                            
+        ObjectName rname = null;
+        if (resourcetype!=null) {
+            if (resourcetype.equals("Global")) {
+                rname = new ObjectName( domain + RESOURCE_TYPE + GLOBAL_TYPE + 
+                                        ",class=" + MAILSESSION_CLASS + ",*");
+            } else if (resourcetype.equals("Context")) {
+                rname = new ObjectName (domain + RESOURCE_TYPE + CONTEXT_TYPE + 
+                    ",path=" + path + ",host=" + host + ",class=" + 
+                    MAILSESSION_CLASS + ",*");
+            } else if (resourcetype.equals("DefaultContext")) {
+                if (host.length() > 0) {
+                    rname = new ObjectName(domain + RESOURCE_TYPE + 
+                        HOST_DEFAULTCONTEXT_TYPE + ",host=" + host + 
+                        ",class=" + MAILSESSION_CLASS + ",*");
+                } else {
+                    rname = new ObjectName(domain + RESOURCE_TYPE + 
+                        SERVICE_DEFAULTCONTEXT_TYPE +
+                        ",class=" + MAILSESSION_CLASS + ",*");
+                }
+            }
+        }
+       
+        Iterator iterator = (mserver.queryMBeans(rname, null).iterator());
+        
+        ArrayList results = new ArrayList();        
+        while (iterator.hasNext()) {
+            
+            ObjectInstance instance = (ObjectInstance) iterator.next(); 
+            results.add(instance.getObjectName().toString());
+        }
+
+        Collections.sort(results);        
+        MailSessionsForm mailSessionsForm = new MailSessionsForm();
+        mailSessionsForm.setMailSessions((String[]) 
+                        results.toArray(new String[results.size()]));        
+        
+        if (resourcetype != null) {
+            mailSessionsForm.setResourcetype(resourcetype);
+        } else {
+            mailSessionsForm.setResourcetype("");
+        }
+         if (path != null) {
+            mailSessionsForm.setPath(path);
+        } else {
+            mailSessionsForm.setPath("");
+        }        
+        if (host != null) {
+            mailSessionsForm.setHost(host);
+        } else {
+            mailSessionsForm.setHost("");
+        }        
+        if (domain != null) {
+            mailSessionsForm.setDomain(domain);
+        } else {
+            mailSessionsForm.setDomain("");
+        }          
+        
+        return (mailSessionsForm);
+
+    }
+    
+    /**
+     * Construct and return a ResourceLinksForm identifying all currently defined
+     * resourcelinks in the specified resource database.
+     *
+     * @param mserver MBeanServer to be consulted
+     *
+     * @exception Exception if an error occurs
+     */
+    public static ResourceLinksForm getResourceLinksForm(MBeanServer mserver, 
+        String resourcetype, String path, String host, String domain) 
+        throws Exception {
+
+        ObjectName rname = null;
+        if (resourcetype!=null) {
+            if (resourcetype.equals("Global")) {
+                rname = new ObjectName( domain + RESOURCELINK_TYPE + 
+                                        GLOBAL_TYPE + ",*");
+            } else if (resourcetype.equals("Context")) {
+                rname = new ObjectName ( domain + RESOURCELINK_TYPE + 
+                            CONTEXT_TYPE + ",path=" + path + 
+                            ",host=" + host + ",*");
+            } else if (resourcetype.equals("DefaultContext")) {
+                if (host.length() > 0) {
+                    rname = new ObjectName( domain + RESOURCELINK_TYPE + 
+                                HOST_DEFAULTCONTEXT_TYPE + 
+                                ",host=" + host + ",*");
+                } else {
+                    rname = new ObjectName( domain + RESOURCELINK_TYPE + 
+                                SERVICE_DEFAULTCONTEXT_TYPE + ",*");
+                }
+            }
+        }
+       
+        Iterator iterator = (mserver.queryMBeans(rname, null).iterator());
+        
+        ArrayList results = new ArrayList();        
+        while (iterator.hasNext()) {
+            ObjectInstance instance = (ObjectInstance) iterator.next(); 
+            results.add(instance.getObjectName().toString());
+        }
+
+        Collections.sort(results);        
+        ResourceLinksForm resourceLinksForm = new ResourceLinksForm();
+        resourceLinksForm.setResourceLinks((String[]) 
+                        results.toArray(new String[results.size()]));        
+        
+        if (resourcetype != null) {
+            resourceLinksForm.setResourcetype(resourcetype);
+        } else {
+            resourceLinksForm.setResourcetype("");
+        }
+         if (path != null) {
+            resourceLinksForm.setPath(path);
+        } else {
+            resourceLinksForm.setPath("");
+        }        
+        if (host != null) {
+            resourceLinksForm.setHost(host);
+        } else {
+            resourceLinksForm.setHost("");
+        }        
+        if (domain != null) {
+            resourceLinksForm.setDomain(domain);
+        } else {
+            resourceLinksForm.setDomain("");
+        }          
+        
+        return (resourceLinksForm);
+        
+    }
+    
+    /**
+     * Construct and return a UserDatabaseForm identifying all currently defined
+     * user databases in the specified resource database.
+     *
+     * @param mserver MBeanServer to be consulted
+     *
+     * @exception Exception if an error occurs
+     */
+    public static UserDatabasesForm getUserDatabasesForm(MBeanServer mserver,String domain)
+        throws Exception {
+            
+        ObjectName rname = new ObjectName( domain + RESOURCE_TYPE + GLOBAL_TYPE +
+                            ",class=" + USERDB_CLASS + ",*");
+        
+        Iterator iterator = (mserver.queryMBeans(rname, null).iterator());
+        
+        ArrayList results = new ArrayList();        
+        while (iterator.hasNext()) {
+            ObjectInstance instance = (ObjectInstance) iterator.next(); 
+            results.add(instance.getObjectName().toString());
+        }
+
+        Collections.sort(results);
+
+        UserDatabasesForm userDatabasesForm = new UserDatabasesForm();
+        userDatabasesForm.setUserDatabases((String[]) 
+                        results.toArray(new String[results.size()]));  
+        return (userDatabasesForm);
+
+    }
+    
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/resources/ResourcesTreeBuilder.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/resources/ResourcesTreeBuilder.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/resources/ResourcesTreeBuilder.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,139 @@
+/*
+ * Copyright 2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.admin.resources;
+
+import java.net.URLEncoder;
+import java.util.Locale;
+import java.io.UnsupportedEncodingException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpSession;
+import org.apache.struts.Globals;
+import org.apache.struts.util.MessageResources;
+import org.apache.webapp.admin.ApplicationServlet;
+import org.apache.webapp.admin.TreeBuilder;
+import org.apache.webapp.admin.TreeControl;
+import org.apache.webapp.admin.TreeControlNode;
+import org.apache.webapp.admin.TomcatTreeBuilder;
+
+/**
+ * Implementation of <code>TreeBuilder</code> that adds the nodes required
+ * for administering the resources (data sources).
+ *
+ * @author Manveen Kaur
+ * @author Amy Roh
+ * @version $Revision: 303390 $ $Date: 2004-10-18 01:37:56 -0500 (Mon, 18 Oct 2004) $
+ * @since 4.1
+ */
+
+public class ResourcesTreeBuilder implements TreeBuilder {
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    // ---------------------------------------------------- TreeBuilder Methods
+
+
+    /**
+     * Add the required nodes to the specified <code>treeControl</code>
+     * instance.
+     *
+     * @param treeControl The <code>TreeControl</code> to which we should
+     *  add our nodes
+     * @param servlet The controller servlet for the admin application
+     * @param request The servlet request we are processing
+     */
+    public void buildTree(TreeControl treeControl,
+                          ApplicationServlet servlet,
+                          HttpServletRequest request) {
+
+        MessageResources resources = (MessageResources)
+            servlet.getServletContext().getAttribute(Globals.MESSAGES_KEY);
+        HttpSession session = request.getSession();
+        Locale locale = (Locale) session.getAttribute(Globals.LOCALE_KEY);
+        addSubtree(treeControl.getRoot(), resources, locale);
+
+    }
+
+
+    // ------------------------------------------------------ Protected Methods
+
+
+    /**
+     * Add the subtree of nodes required for user administration.
+     *
+     * @param root The root node of our tree control
+     * @param resources The MessageResources for our localized messages
+     *  messages
+     */
+    protected void addSubtree(TreeControlNode root, MessageResources resources,
+                              Locale locale) {
+        try {
+            String domain = root.getDomain();
+            TreeControlNode subtree = new TreeControlNode
+                ("Global Resource Administration",
+                 "folder_16_pad.gif",
+                 resources.getMessage(locale, "resources.treeBuilder.subtreeNode"),
+                 null,
+                 "content",
+                 true, domain);        
+            TreeControlNode datasources = new TreeControlNode
+                ("Globally Administer Data Sources",
+                 "Datasource.gif",
+                 resources.getMessage(locale, "resources.treeBuilder.datasources"),
+                 "resources/listDataSources.do?resourcetype=Global&domain=" +
+                 domain + "&forward=" + 
+                 URLEncoder.encode("DataSources List Setup",TomcatTreeBuilder.URL_ENCODING),
+                 "content",
+                 false, domain);
+            TreeControlNode mailsessions = new TreeControlNode
+                ("Globally Administer Mail Sessions ",
+                 "Mailsession.gif",
+                 resources.getMessage(locale, "resources.treeBuilder.mailsessions"),
+                 "resources/listMailSessions.do?resourcetype=Global&domain=" +
+                 domain + "&forward=" + 
+                 URLEncoder.encode("MailSessions List Setup",TomcatTreeBuilder.URL_ENCODING),
+                 "content",
+                 false, domain);
+            TreeControlNode userdbs = new TreeControlNode
+                ("Globally Administer UserDatabase Entries",
+                 "Realm.gif",
+                 resources.getMessage(locale, "resources.treeBuilder.databases"),
+                 "resources/listUserDatabases.do?domain=" + domain + 
+                 "&forward=" + 
+                 URLEncoder.encode("UserDatabases List Setup",TomcatTreeBuilder.URL_ENCODING),
+                 "content",
+                 false, domain);
+            TreeControlNode envs = new TreeControlNode
+                ("Globally Administer Environment Entries",
+                 "EnvironmentEntries.gif",
+                 resources.getMessage(locale, "resources.env.entries"),
+                 "resources/listEnvEntries.do?resourcetype=Global&domain=" +
+                 domain+"&forward="+
+                 URLEncoder.encode("EnvEntries List Setup",TomcatTreeBuilder.URL_ENCODING),
+                 "content",
+                 false, domain);
+            root.addChild(subtree);
+            subtree.addChild(datasources);
+            subtree.addChild(mailsessions);
+            subtree.addChild(envs);
+            subtree.addChild(userdbs);
+        } catch(UnsupportedEncodingException ex) {
+            // can't happen
+        }
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/resources/SaveDataSourceAction.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/resources/SaveDataSourceAction.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/resources/SaveDataSourceAction.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,255 @@
+/*
+ * Copyright 2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.admin.resources;
+
+import java.io.IOException;
+import java.net.URLEncoder;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.Locale;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+import org.apache.struts.action.Action;
+import org.apache.struts.action.ActionError;
+import org.apache.struts.action.ActionErrors;
+import org.apache.struts.action.ActionForm;
+import org.apache.struts.action.ActionForward;
+import org.apache.struts.action.ActionMapping;
+import javax.management.Attribute;
+import javax.management.MBeanServer;
+import javax.management.MBeanServerFactory;
+import javax.management.QueryExp;
+import javax.management.Query;
+import javax.management.ObjectInstance;
+import javax.management.ObjectName;
+import javax.management.JMException;
+import javax.management.MBeanAttributeInfo;
+import javax.management.MBeanOperationInfo;
+import javax.management.MBeanInfo;
+import org.apache.struts.util.MessageResources;
+import org.apache.webapp.admin.ApplicationServlet;
+
+
+/**
+ * <p>Implementation of <strong>Action</strong> that saves a new or
+ * updated data source entry.</p>
+ *
+ * @author Manveen Kaur
+ * @version $Revision: 303390 $ $Date: 2004-10-18 01:37:56 -0500 (Mon, 18 Oct 2004) $
+ * @since 4.1
+ */
+
+public final class SaveDataSourceAction extends Action {
+
+
+    // ----------------------------------------------------- Instance Variables
+
+    /**
+     * The MBeanServer we will be interacting with.
+     */
+    private MBeanServer mserver = null;
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Process the specified HTTP request, and create the corresponding HTTP
+     * response (or forward to another web component that will create it).
+     * Return an <code>ActionForward</code> instance describing where and how
+     * control should be forwarded, or <code>null</code> if the response has
+     * already been completed.
+     *
+     * @param mapping The ActionMapping used to select this instance
+     * @param actionForm The optional ActionForm bean for this request (if any)
+     * @param request The HTTP request we are processing
+     * @param response The HTTP response we are creating
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception ServletException if a servlet exception occurs
+     */
+    public ActionForward execute(ActionMapping mapping,
+                                 ActionForm form,
+                                 HttpServletRequest request,
+                                 HttpServletResponse response)
+        throws IOException, ServletException {
+
+        // Look up the components we will be using as needed
+        if (mserver == null) {
+            mserver = ((ApplicationServlet) getServlet()).getServer();
+        }
+        MessageResources resources = getResources(request);
+        HttpSession session = request.getSession();
+        Locale locale = getLocale(request);
+
+        // Has this transaction been cancelled?
+        if (isCancelled(request)) {
+            return (mapping.findForward("List DataSources Setup"));
+        }
+
+        // Check the transaction token
+        if (!isTokenValid(request)) {
+            response.sendError
+                (HttpServletResponse.SC_BAD_REQUEST,
+                 resources.getMessage(locale, "users.error.token"));
+            return (null);
+        }
+
+        // Perform any extra validation that is required
+        DataSourceForm dataSourceForm = (DataSourceForm) form;
+        String objectName = dataSourceForm.getObjectName();
+
+        // Perform an "Add DataSource" transaction
+        if (objectName == null) {
+
+            String signature[] = new String[2];
+            signature[0] = "java.lang.String";
+            signature[1] = "java.lang.String";
+
+            Object params[] = new Object[2];
+            params[0] = dataSourceForm.getJndiName();
+            params[1] = ResourceUtils.DATASOURCE_CLASS;
+            String encodedJndiName = URLEncoder.encode(params[0].toString(), 
+                                                       "UTF-8");
+
+            String resourcetype = dataSourceForm.getResourcetype();
+            String path = dataSourceForm.getPath();
+            String host = dataSourceForm.getHost();
+            String domain = dataSourceForm.getDomain();
+
+            ObjectName oname = null;
+            ObjectName encodedOName = null;
+
+            try {
+            
+                if (resourcetype.equals("Global")) {
+                    oname = new ObjectName( domain + ResourceUtils.RESOURCE_TYPE + 
+                                            ResourceUtils.GLOBAL_TYPE + 
+                                            ",class=" + params[1] + 
+                                            ",name=" + params[0]);
+                    encodedOName = new ObjectName( domain + 
+                                            ResourceUtils.RESOURCE_TYPE + 
+                                            ResourceUtils.GLOBAL_TYPE + 
+                                            ",class=" + params[1] + 
+                                            ",name=" + encodedJndiName);
+                } else if (resourcetype.equals("Context")) {
+                    oname = new ObjectName( domain + ResourceUtils.RESOURCE_TYPE + 
+                                            ResourceUtils.CONTEXT_TYPE + 
+                                            ",path=" + path + ",host=" + host + 
+                                            ",class=" + params[1] + 
+                                            ",name=" + params[0]);
+                    encodedOName = new ObjectName( domain + 
+                                            ResourceUtils.RESOURCE_TYPE + 
+                                            ResourceUtils.CONTEXT_TYPE + 
+                                            ",path=" + path + ",host=" + host + 
+                                            ",class=" + params[1] + 
+                                            ",name=" + encodedJndiName);
+                }
+                
+                if (mserver.isRegistered(oname) || 
+                                        mserver.isRegistered(encodedOName)) {
+                    ActionErrors errors = new ActionErrors();
+                    errors.add("jndiName",
+                               new ActionError("resources.invalid.name"));
+                    saveErrors(request, errors);
+                    return (new ActionForward(mapping.getInput()));
+                }        
+                
+                oname = ResourceUtils.getNamingResourceObjectName(domain,
+                            resourcetype, path, host);                                
+                            
+                // Create the new object and associated MBean
+                objectName = (String) mserver.invoke(oname, "addResource",
+                                                     params, signature);
+
+            } catch (Exception e) {
+
+                getServlet().log
+                    (resources.getMessage(locale, "users.error.invoke",
+                                          "addResource"), e);
+                response.sendError
+                    (HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
+                     resources.getMessage(locale, "users.error.invoke",
+                                          "addResource"));
+                return (null);
+            }
+
+        }
+
+        // Perform an "Update User database" transaction
+        String attribute = null;
+        try {
+
+            ObjectName oname = new ObjectName(objectName);
+
+            attribute = "url";
+            mserver.setAttribute
+                (oname,
+                 new Attribute(attribute, dataSourceForm.getUrl()));
+            attribute = "driverClassName";
+            mserver.setAttribute
+                (oname,
+                 new Attribute(attribute, dataSourceForm.getDriverClass()));
+            attribute = "username";
+            mserver.setAttribute
+                (oname,
+                 new Attribute(attribute, dataSourceForm.getUsername()));
+            attribute = "password";
+            mserver.setAttribute
+                (oname,
+                 new Attribute(attribute, dataSourceForm.getPassword()));
+            attribute = "maxActive";
+            mserver.setAttribute
+                (oname,
+                 new Attribute(attribute, dataSourceForm.getActive()));
+            attribute = "maxIdle";
+            mserver.setAttribute
+                (oname,
+                 new Attribute(attribute, dataSourceForm.getIdle()));
+            attribute = "maxWait";
+            mserver.setAttribute
+                (oname,
+                 new Attribute(attribute, dataSourceForm.getWait()));
+            attribute = "validationQuery";
+            String validationQuery = dataSourceForm.getQuery();
+            if ((validationQuery != null) && (validationQuery.length()>0)) {
+                mserver.setAttribute(oname,
+                                new Attribute(attribute, validationQuery));
+            }
+
+        } catch (Exception e) {
+
+            getServlet().log
+                (resources.getMessage(locale, "users.error.set.attribute",
+                                      attribute), e);
+            response.sendError
+                (HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
+                 resources.getMessage(locale, "users.error.set.attribute",
+                                      attribute));
+            return (null);
+
+        }
+
+        // Proceed to the list entries screen
+        return (mapping.findForward("DataSources List Setup"));
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/resources/SaveEnvEntryAction.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/resources/SaveEnvEntryAction.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/resources/SaveEnvEntryAction.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,227 @@
+/*
+ * Copyright 2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.admin.resources;
+
+import java.io.IOException;
+import java.net.URLDecoder;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.Locale;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+import org.apache.struts.action.Action;
+import org.apache.struts.action.ActionError;
+import org.apache.struts.action.ActionErrors;
+import org.apache.struts.action.ActionForm;
+import org.apache.struts.action.ActionForward;
+import org.apache.struts.action.ActionMapping;
+import javax.management.Attribute;
+import javax.management.MBeanServer;
+import javax.management.MBeanServerFactory;
+import javax.management.QueryExp;
+import javax.management.Query;
+import javax.management.ObjectInstance;
+import javax.management.ObjectName;
+import javax.management.JMException;
+import javax.management.MBeanAttributeInfo;
+import javax.management.MBeanOperationInfo;
+import javax.management.MBeanInfo;
+import org.apache.struts.util.MessageResources;
+import org.apache.webapp.admin.ApplicationServlet;
+
+
+/**
+ * <p>Implementation of <strong>Action</strong> that saves a new or
+ * updated Env Entry.</p>
+ *
+ * @author Manveen Kaur
+ * @version $Revision: 303390 $ $Date: 2004-10-18 01:37:56 -0500 (Mon, 18 Oct 2004) $
+ * @since 4.1
+ */
+
+public final class SaveEnvEntryAction extends Action {
+
+
+    // ----------------------------------------------------- Instance Variables
+
+    /**
+     * The MBeanServer we will be interacting with.
+     */
+    private MBeanServer mserver = null;
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Process the specified HTTP request, and create the corresponding HTTP
+     * response (or forward to another web component that will create it).
+     * Return an <code>ActionForward</code> instance describing where and how
+     * control should be forwarded, or <code>null</code> if the response has
+     * already been completed.
+     *
+     * @param mapping The ActionMapping used to select this instance
+     * @param actionForm The optional ActionForm bean for this request (if any)
+     * @param request The HTTP request we are processing
+     * @param response The HTTP response we are creating
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception ServletException if a servlet exception occurs
+     */
+    public ActionForward execute(ActionMapping mapping,
+                                 ActionForm form,
+                                 HttpServletRequest request,
+                                 HttpServletResponse response)
+        throws IOException, ServletException {
+
+        // Look up the components we will be using as needed
+        if (mserver == null) {
+            mserver = ((ApplicationServlet) getServlet()).getServer();
+        }
+        MessageResources resources = getResources(request);
+        HttpSession session = request.getSession();
+        Locale locale = getLocale(request);
+
+        // Has this transaction been cancelled?
+        if (isCancelled(request)) {
+            return (mapping.findForward("List EnvEntries Setup"));
+        }
+
+        // Check the transaction token
+        if (!isTokenValid(request)) {
+            response.sendError
+                (HttpServletResponse.SC_BAD_REQUEST,
+                 resources.getMessage(locale, "users.error.token"));
+            return (null);
+        }
+
+        // Perform any extra validation that is required
+        EnvEntryForm envEntryForm = (EnvEntryForm) form;
+        String objectName = envEntryForm.getObjectName();
+
+        // Perform an "Add Entry" transaction
+        if (objectName == null) {
+
+            String signature[] = new String[3];
+            signature[0] = "java.lang.String";
+            signature[1] = "java.lang.String";
+            signature[2] = "java.lang.String";
+
+            Object params[] = new Object[3];
+            params[0] = envEntryForm.getName();
+            params[1] = envEntryForm.getEntryType();
+            params[2] = envEntryForm.getValue();
+            
+            String resourcetype = envEntryForm.getResourcetype();
+            String path = envEntryForm.getPath();
+            String host = envEntryForm.getHost();
+            String domain = envEntryForm.getDomain();
+            
+            ObjectName oname = null;
+
+            try {
+            
+                if (resourcetype.equals("Global")) {
+                    oname = new ObjectName( domain + 
+                                            ResourceUtils.ENVIRONMENT_TYPE + 
+                                            ResourceUtils.GLOBAL_TYPE + 
+                                            ",name=" + params[0]);
+                } else if (resourcetype.equals("Context")) {
+                    oname = new ObjectName( domain + 
+                                            ResourceUtils.ENVIRONMENT_TYPE + 
+                                            ResourceUtils.CONTEXT_TYPE + 
+                                            ",path=" + path + ",host=" + host + 
+                                            ",name=" + params[0]);
+                }         
+                            
+                if (mserver.isRegistered(oname)) {
+                    ActionErrors errors = new ActionErrors();
+                    errors.add("name",
+                               new ActionError("resources.invalid.env"));
+                    saveErrors(request, errors);
+                    return (new ActionForward(mapping.getInput()));
+                }  
+                
+                oname = ResourceUtils.getNamingResourceObjectName(domain,
+                            resourcetype, path, host);
+                
+                // Create the new object and associated MBean
+                objectName = (String) mserver.invoke(oname, "addEnvironment",
+                                                     params, signature);
+                                                                     
+            } catch (Exception e) {
+
+                getServlet().log
+                    (resources.getMessage(locale, "users.error.invoke",
+                                          "addEnvironment"), e);
+                response.sendError
+                    (HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
+                     resources.getMessage(locale, "users.error.invoke",
+                                          "addEnvironment"));
+                return (null);
+            }
+
+        }
+
+        // Perform an "Update Environment Entry" transaction
+        String attribute = null;
+        try {
+            
+            // Construct an object name for this object
+            ObjectName oname = new ObjectName(objectName);
+
+            // Update the specified env entry
+            attribute = "override";
+            mserver.setAttribute
+                (oname,
+                 new Attribute(attribute, new Boolean(envEntryForm.getOverride())));
+            attribute = "description";
+            mserver.setAttribute
+                (oname,
+                 new Attribute(attribute, envEntryForm.getDescription()));
+            attribute = "type";
+            mserver.setAttribute
+                (oname,
+                 new Attribute(attribute, envEntryForm.getEntryType()));
+            attribute = "value";
+            mserver.setAttribute
+                (oname,
+                 new Attribute(attribute, envEntryForm.getValue()));
+
+        } catch (Exception e) {
+
+            getServlet().log
+                (resources.getMessage(locale, "users.error.set.attribute",
+                                      attribute), e);
+            response.sendError
+                (HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
+                 resources.getMessage(locale, "users.error.set.attribute",
+                                      attribute));
+            return (null);
+
+        }
+        
+        // Proceed to the list entries screen
+        return (mapping.findForward("EnvEntries List Setup"));
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/resources/SaveMailSessionAction.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/resources/SaveMailSessionAction.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/resources/SaveMailSessionAction.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,210 @@
+/*
+ * Copyright 2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.admin.resources;
+
+import java.io.IOException;
+import java.net.URLDecoder;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.Locale;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+import org.apache.struts.action.Action;
+import org.apache.struts.action.ActionError;
+import org.apache.struts.action.ActionErrors;
+import org.apache.struts.action.ActionForm;
+import org.apache.struts.action.ActionForward;
+import org.apache.struts.action.ActionMapping;
+import javax.management.Attribute;
+import javax.management.MBeanServer;
+import javax.management.MBeanServerFactory;
+import javax.management.QueryExp;
+import javax.management.Query;
+import javax.management.ObjectInstance;
+import javax.management.ObjectName;
+import javax.management.JMException;
+import javax.management.MBeanAttributeInfo;
+import javax.management.MBeanOperationInfo;
+import javax.management.MBeanInfo;
+import org.apache.struts.util.MessageResources;
+import org.apache.webapp.admin.ApplicationServlet;
+
+
+/**
+ * <p>Implementation of <strong>Action</strong> that saves a new or
+ * updated mail session entry.</p>
+ *
+ * @author Amy Roh
+ * @version $Revision: 303390 $ $Date: 2004-10-18 01:37:56 -0500 (Mon, 18 Oct 2004) $
+ * @since 4.1
+ */
+
+public final class SaveMailSessionAction extends Action {
+
+
+    // ----------------------------------------------------- Instance Variables
+
+    /**
+     * The MBeanServer we will be interacting with.
+     */
+    private MBeanServer mserver = null;
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Process the specified HTTP request, and create the corresponding HTTP
+     * response (or forward to another web component that will create it).
+     * Return an <code>ActionForward</code> instance describing where and how
+     * control should be forwarded, or <code>null</code> if the response has
+     * already been completed.
+     *
+     * @param mapping The ActionMapping used to select this instance
+     * @param actionForm The optional ActionForm bean for this request (if any)
+     * @param request The HTTP request we are processing
+     * @param response The HTTP response we are creating
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception ServletException if a servlet exception occurs
+     */
+    public ActionForward execute(ActionMapping mapping,
+                                 ActionForm form,
+                                 HttpServletRequest request,
+                                 HttpServletResponse response)
+        throws IOException, ServletException {
+
+        // Look up the components we will be using as needed
+        if (mserver == null) {
+            mserver = ((ApplicationServlet) getServlet()).getServer();
+        }
+        MessageResources resources = getResources(request);
+        HttpSession session = request.getSession();
+        Locale locale = getLocale(request);
+
+        // Has this transaction been cancelled?
+        if (isCancelled(request)) {
+            return (mapping.findForward("List MailSessions Setup"));
+        }
+
+        // Check the transaction token
+        if (!isTokenValid(request)) {
+            response.sendError
+                (HttpServletResponse.SC_BAD_REQUEST,
+                 resources.getMessage(locale, "users.error.token"));
+            return (null);
+        }
+
+        // Perform any extra validation that is required
+        MailSessionForm mailSessionForm = (MailSessionForm) form;
+        String objectName = mailSessionForm.getObjectName();
+
+        // Perform an "Add MailSession" transaction
+        if (objectName == null) {
+
+            String signature[] = new String[2];
+            signature[0] = "java.lang.String";
+            signature[1] = "java.lang.String";
+
+            Object params[] = new Object[2];
+            params[0] = mailSessionForm.getName();
+            params[1] = ResourceUtils.MAILSESSION_CLASS;     
+            
+            String resourcetype = mailSessionForm.getResourcetype();
+            String path = mailSessionForm.getPath();
+            String host = mailSessionForm.getHost();
+            String domain = mailSessionForm.getDomain();
+            
+            ObjectName oname = null;
+
+            try {
+            
+                if (resourcetype.equals("Global")) {
+                    oname = new ObjectName( domain + ResourceUtils.RESOURCE_TYPE + 
+                                            ResourceUtils.GLOBAL_TYPE + 
+                                            ",class=" + params[1] + 
+                                            ",name=" + params[0]);
+                } else if (resourcetype.equals("Context")) {
+                    oname = new ObjectName( domain + ResourceUtils.RESOURCE_TYPE + 
+                                            ResourceUtils.CONTEXT_TYPE + 
+                                            ",path=" + path + ",host=" + host + 
+                                            ",class=" + params[1] + 
+                                            ",name=" + params[0]);
+                }         
+                            
+                if (mserver.isRegistered(oname)) {
+                    ActionErrors errors = new ActionErrors();
+                    errors.add("name",
+                               new ActionError("resources.invalid.name"));
+                    saveErrors(request, errors);
+                    return (new ActionForward(mapping.getInput()));
+                }   
+                
+                oname = ResourceUtils.getNamingResourceObjectName(domain,
+                            resourcetype, path, host);
+                            
+                // Create the new object and associated MBean
+                objectName = (String) mserver.invoke(oname, "addResource",
+                                                     params, signature);
+                                     
+            } catch (Exception e) {
+
+                getServlet().log
+                    (resources.getMessage(locale, "users.error.invoke",
+                                          "addResource"), e);
+                response.sendError
+                    (HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
+                     resources.getMessage(locale, "users.error.invoke",
+                                          "addResource"));
+                return (null);
+            }
+
+        }
+        
+        // Perform an "Update User database" transaction
+        String attribute = null;
+        try {
+            
+            ObjectName oname = new ObjectName(objectName);
+
+            attribute = "mail.smtp.host";
+            mserver.setAttribute
+                (oname,
+                 new Attribute(attribute, mailSessionForm.getMailhost()));
+
+        } catch (Exception e) {
+
+            getServlet().log
+                (resources.getMessage(locale, "users.error.set.attribute",
+                                      attribute), e);
+            response.sendError
+                (HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
+                 resources.getMessage(locale, "users.error.set.attribute",
+                                      attribute));
+            return (null);
+
+        }
+        
+        // Proceed to the list entries screen
+        return (mapping.findForward("MailSessions List Setup"));
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/resources/SaveResourceLinkAction.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/resources/SaveResourceLinkAction.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/resources/SaveResourceLinkAction.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,214 @@
+/*
+ * Copyright 2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.admin.resources;
+
+import java.io.IOException;
+import java.net.URLDecoder;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.Locale;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+import org.apache.struts.action.Action;
+import org.apache.struts.action.ActionError;
+import org.apache.struts.action.ActionErrors;
+import org.apache.struts.action.ActionForm;
+import org.apache.struts.action.ActionForward;
+import org.apache.struts.action.ActionMapping;
+import javax.management.Attribute;
+import javax.management.MBeanServer;
+import javax.management.MBeanServerFactory;
+import javax.management.QueryExp;
+import javax.management.Query;
+import javax.management.ObjectInstance;
+import javax.management.ObjectName;
+import javax.management.JMException;
+import javax.management.MBeanAttributeInfo;
+import javax.management.MBeanOperationInfo;
+import javax.management.MBeanInfo;
+import org.apache.struts.util.MessageResources;
+import org.apache.webapp.admin.ApplicationServlet;
+
+
+/**
+ * <p>Implementation of <strong>Action</strong> that saves a new or
+ * updated resource link entry.</p>
+ *
+ * @author Amy Roh
+ * @version $Revision: 303390 $ $Date: 2004-10-18 01:37:56 -0500 (Mon, 18 Oct 2004) $
+ * @since 4.1
+ */
+
+public final class SaveResourceLinkAction extends Action {
+
+
+    // ----------------------------------------------------- Instance Variables
+
+    /**
+     * The MBeanServer we will be interacting with.
+     */
+    private MBeanServer mserver = null;
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Process the specified HTTP request, and create the corresponding HTTP
+     * response (or forward to another web component that will create it).
+     * Return an <code>ActionForward</code> instance describing where and how
+     * control should be forwarded, or <code>null</code> if the response has
+     * already been completed.
+     *
+     * @param mapping The ActionMapping used to select this instance
+     * @param actionForm The optional ActionForm bean for this request (if any)
+     * @param request The HTTP request we are processing
+     * @param response The HTTP response we are creating
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception ServletException if a servlet exception occurs
+     */
+    public ActionForward execute(ActionMapping mapping,
+                                 ActionForm form,
+                                 HttpServletRequest request,
+                                 HttpServletResponse response)
+        throws IOException, ServletException {
+
+        // Look up the components we will be using as needed
+        if (mserver == null) {
+            mserver = ((ApplicationServlet) getServlet()).getServer();
+        }
+        MessageResources resources = getResources(request);
+        HttpSession session = request.getSession();
+        Locale locale = getLocale(request);
+
+        // Has this transaction been cancelled?
+        if (isCancelled(request)) {
+            return (mapping.findForward("List ResourceLinks Setup"));
+        }
+
+        // Check the transaction token
+        if (!isTokenValid(request)) {
+            response.sendError
+                (HttpServletResponse.SC_BAD_REQUEST,
+                 resources.getMessage(locale, "users.error.token"));
+            return (null);
+        }
+
+        // Perform any extra validation that is required
+        ResourceLinkForm resourceLinkForm = (ResourceLinkForm) form;
+        String objectName = resourceLinkForm.getObjectName();
+     
+        // Perform an "Add ResourceLink" transaction
+        if (objectName == null) {
+
+            String signature[] = new String[2];
+            signature[0] = "java.lang.String";
+            signature[1] = "java.lang.String";
+
+            Object params[] = new Object[2];
+            params[0] = resourceLinkForm.getName();
+            params[1] = resourceLinkForm.getType();   
+            
+            String resourcetype = resourceLinkForm.getResourcetype();
+            String path = resourceLinkForm.getPath();
+            String host = resourceLinkForm.getHost();
+            String domain = resourceLinkForm.getDomain();
+                       
+            ObjectName oname = null;
+
+            try {
+            
+                if (resourcetype.equals("Global")) {
+                    oname = new ObjectName( domain + 
+                                            ResourceUtils.RESOURCELINK_TYPE + 
+                                            ResourceUtils.GLOBAL_TYPE + 
+                                            ",name=" + params[0]);
+                } else if (resourcetype.equals("Context")) {
+                    oname = new ObjectName( domain + 
+                                            ResourceUtils.RESOURCELINK_TYPE + 
+                                            ResourceUtils.CONTEXT_TYPE + 
+                                            ",path=" + path + ",host=" + host + 
+                                            ",name=" + params[0]);
+                }         
+                            
+                if (mserver.isRegistered(oname)) {
+                    ActionErrors errors = new ActionErrors();
+                    errors.add("name",
+                               new ActionError("resources.invalid.name"));
+                    saveErrors(request, errors);
+                    return (new ActionForward(mapping.getInput()));
+                }   
+                
+                oname = ResourceUtils.getNamingResourceObjectName(domain,
+                            resourcetype, path, host);
+                            
+                // Create the new object and associated MBean
+                objectName = (String) mserver.invoke(oname, "addResourceLink",
+                                                     params, signature);
+                                     
+            } catch (Exception e) {
+
+                getServlet().log
+                    (resources.getMessage(locale, "users.error.invoke",
+                                          "addResourceLink"), e);
+                response.sendError
+                    (HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
+                     resources.getMessage(locale, "users.error.invoke",
+                                          "addResourceLink"));
+                return (null);
+            }
+
+        }
+        
+        // Perform an "Update User database" transaction
+        String attribute = null;
+        try {
+            
+            ObjectName oname = new ObjectName(objectName);
+            
+            attribute = "global";
+            mserver.setAttribute
+                (oname,
+                 new Attribute(attribute, resourceLinkForm.getGlobal()));
+            attribute = "type";
+            mserver.setAttribute
+                (oname,
+                 new Attribute(attribute, resourceLinkForm.getType()));
+
+        } catch (Exception e) {
+
+            getServlet().log
+                (resources.getMessage(locale, "users.error.set.attribute",
+                                      attribute), e);
+            response.sendError
+                (HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
+                 resources.getMessage(locale, "users.error.set.attribute",
+                                      attribute));
+            return (null);
+
+        }
+        
+        // Proceed to the list entries screen
+        return (mapping.findForward("ResourceLinks List Setup"));
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/resources/SaveUserDatabaseAction.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/resources/SaveUserDatabaseAction.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/resources/SaveUserDatabaseAction.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,213 @@
+/*
+ * Copyright 2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.admin.resources;
+
+import java.io.IOException;
+import java.net.URLDecoder;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.Locale;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+import org.apache.struts.action.Action;
+import org.apache.struts.action.ActionError;
+import org.apache.struts.action.ActionErrors;
+import org.apache.struts.action.ActionForm;
+import org.apache.struts.action.ActionForward;
+import org.apache.struts.action.ActionMapping;
+import javax.management.Attribute;
+import javax.management.MBeanServer;
+import javax.management.MBeanServerFactory;
+import javax.management.QueryExp;
+import javax.management.Query;
+import javax.management.ObjectInstance;
+import javax.management.ObjectName;
+import javax.management.JMException;
+import javax.management.MBeanAttributeInfo;
+import javax.management.MBeanOperationInfo;
+import javax.management.MBeanInfo;
+import org.apache.struts.util.MessageResources;
+import org.apache.webapp.admin.ApplicationServlet;
+
+
+/**
+ * <p>Implementation of <strong>Action</strong> that saves a new or
+ * updated User database entry.</p>
+ *
+ * @author Manveen Kaur
+ * @version $Revision: 303390 $ $Date: 2004-10-18 01:37:56 -0500 (Mon, 18 Oct 2004) $
+ * @since 4.1
+ */
+
+public final class SaveUserDatabaseAction extends Action {
+
+
+    // ----------------------------------------------------- Instance Variables
+
+    /**
+     * The MBeanServer we will be interacting with.
+     */
+    private MBeanServer mserver = null;
+
+    /*
+     * Only one implementation of factory allowed to start with.
+     */
+    public static String USERDB_FACTORY = "org.apache.catalina.users.MemoryUserDatabaseFactory";
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Process the specified HTTP request, and create the corresponding HTTP
+     * response (or forward to another web component that will create it).
+     * Return an <code>ActionForward</code> instance describing where and how
+     * control should be forwarded, or <code>null</code> if the response has
+     * already been completed.
+     *
+     * @param mapping The ActionMapping used to select this instance
+     * @param actionForm The optional ActionForm bean for this request (if any)
+     * @param request The HTTP request we are processing
+     * @param response The HTTP response we are creating
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception ServletException if a servlet exception occurs
+     */
+    public ActionForward execute(ActionMapping mapping,
+                                 ActionForm form,
+                                 HttpServletRequest request,
+                                 HttpServletResponse response)
+        throws IOException, ServletException {
+
+        // Look up the components we will be using as needed
+        if (mserver == null) {
+            mserver = ((ApplicationServlet) getServlet()).getServer();
+        }
+        MessageResources resources = getResources(request);
+        HttpSession session = request.getSession();
+        Locale locale = getLocale(request);
+
+        // Has this transaction been cancelled?
+        if (isCancelled(request)) {
+            return (mapping.findForward("List UserDatabases Setup"));
+        }
+
+        // Check the transaction token
+        if (!isTokenValid(request)) {
+            response.sendError
+                (HttpServletResponse.SC_BAD_REQUEST,
+                 resources.getMessage(locale, "users.error.token"));
+            return (null);
+        }
+
+        // Perform any extra validation that is required
+        UserDatabaseForm userDatabaseForm = (UserDatabaseForm) form;
+        String objectName = userDatabaseForm.getObjectName();
+
+        // Perform an "Add UserDatabase" transaction
+        if (objectName == null) {
+
+            String signature[] = new String[2];
+            signature[0] = "java.lang.String";
+            signature[1] = "java.lang.String";
+
+            Object params[] = new Object[2];
+            params[0] = userDatabaseForm.getName();
+            params[1] = ResourceUtils.USERDB_CLASS;     
+           
+            ObjectName oname = null;
+
+            try {
+                String domain = userDatabaseForm.getDomain();
+                oname = new ObjectName( domain + 
+                            ResourceUtils.RESOURCE_TYPE + 
+                            ResourceUtils.GLOBAL_TYPE +
+                            ",class=" + ResourceUtils.USERDB_CLASS + 
+                            ",name=" + params[0]);
+                            
+                if (mserver.isRegistered(oname)) {
+                    ActionErrors errors = new ActionErrors();
+                    errors.add("name",
+                               new ActionError("resources.invalid.name"));
+                    saveErrors(request, errors);
+                    return (new ActionForward(mapping.getInput()));
+                }   
+                
+                // Construct the MBean Name for the naming source
+                oname = new ObjectName(domain + 
+                            ResourceUtils.NAMINGRESOURCES_TYPE + 
+                            ResourceUtils.GLOBAL_TYPE);
+ 
+                // Create the new object and associated MBean
+                objectName = (String) mserver.invoke(oname, "addResource",
+                                                     params, signature);
+                                     
+            } catch (Exception e) {
+
+                getServlet().log
+                    (resources.getMessage(locale, "users.error.invoke",
+                                          "addResource"), e);
+                response.sendError
+                    (HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
+                     resources.getMessage(locale, "users.error.invoke",
+                                          "addResource"));
+                return (null);
+            }
+
+        }
+        
+        // Perform an "Update User database" transaction
+        String attribute = null;
+        try {
+            
+            ObjectName oname = new ObjectName(objectName);
+
+            attribute = "pathname";
+            mserver.setAttribute
+                (oname,
+                 new Attribute(attribute, userDatabaseForm.getPath()));
+            attribute = "factory";
+            mserver.setAttribute
+                (oname,
+                 new Attribute(attribute, userDatabaseForm.getFactory()));
+            attribute = "description";
+            mserver.setAttribute
+                (oname,
+                 new Attribute(attribute, userDatabaseForm.getDescription()));
+
+        } catch (Exception e) {
+
+            getServlet().log
+                (resources.getMessage(locale, "users.error.set.attribute",
+                                      attribute), e);
+            response.sendError
+                (HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
+                 resources.getMessage(locale, "users.error.set.attribute",
+                                      attribute));
+            return (null);
+
+        }
+        
+        // Proceed to the list entries screen
+        return (mapping.findForward("UserDatabases List Setup"));
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/resources/SetUpDataSourceAction.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/resources/SetUpDataSourceAction.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/resources/SetUpDataSourceAction.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,197 @@
+/*
+ * Copyright 2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.admin.resources;
+
+import java.io.IOException;
+import java.net.URLDecoder;
+import java.util.Iterator;
+import java.util.Locale;
+import javax.management.Attribute;
+import javax.management.AttributeNotFoundException;
+import javax.management.MBeanServer;
+import javax.management.MBeanServerFactory;
+import javax.management.QueryExp;
+import javax.management.Query;
+import javax.management.ObjectInstance;
+import javax.management.ObjectName;
+import javax.management.JMException;
+import javax.management.MBeanAttributeInfo;
+import javax.management.MBeanOperationInfo;
+import javax.management.MBeanInfo;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+import org.apache.struts.action.Action;
+import org.apache.struts.action.ActionErrors;
+import org.apache.struts.action.ActionForm;
+import org.apache.struts.action.ActionForward;
+import org.apache.struts.action.ActionMapping;
+import org.apache.struts.util.MessageResources;
+import org.apache.webapp.admin.ApplicationServlet;
+
+
+/**
+ * <p>Implementation of <strong>Action</strong> that sets up and stashes
+ * a <code>DataSourceForm</code> bean in request scope.  The form bean will have
+ * a null <code>objectName</code> property if this form represents a DataSource
+ * being added, or a non-null value for an existing DataSource.</p>
+ *
+ * @author Manveen Kaur
+ * @version $Revision: 303390 $ $Date: 2004-10-18 01:37:56 -0500 (Mon, 18 Oct 2004) $
+ * @since 4.1
+ */
+
+public final class SetUpDataSourceAction extends Action {
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The MBeanServer we will be interacting with.
+     */
+    private MBeanServer mserver = null;
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Process the specified HTTP request, and create the corresponding HTTP
+     * response (or forward to another web component that will create it).
+     * Return an <code>ActionForward</code> instance describing where and how
+     * control should be forwarded, or <code>null</code> if the response has
+     * already been completed.
+     *
+     * @param mapping The ActionMapping used to select this instance
+     * @param actionForm The optional ActionForm bean for this request (if any)
+     * @param request The HTTP request we are processing
+     * @param response The HTTP response we are creating
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception ServletException if a servlet exception occurs
+     */
+    public ActionForward execute(ActionMapping mapping,
+                                 ActionForm form,
+                                 HttpServletRequest request,
+                                 HttpServletResponse response)
+        throws IOException, ServletException {
+
+        // Look up the components we will be using as needed
+        if (mserver == null) {
+            mserver = ((ApplicationServlet) getServlet()).getServer();
+        }
+        MessageResources resources = getResources(request);
+        HttpSession session = request.getSession();
+        Locale locale = getLocale(request);
+
+        // Set up the form bean based on the creating or editing state
+        String objectName = request.getParameter("objectName");
+        String resourcetype = request.getParameter("resourcetype");
+        String path = request.getParameter("path");
+        String host = request.getParameter("host");
+        String domain = request.getParameter("domain");
+
+        DataSourceForm dataSourceForm = new DataSourceForm();
+        dataSourceForm.setResourcetype(resourcetype);
+        dataSourceForm.setPath(path);
+        dataSourceForm.setHost(host);
+        dataSourceForm.setDomain(domain);
+        dataSourceForm.setType(ResourceUtils.DATASOURCE_CLASS);
+
+        if (objectName == null) {
+            dataSourceForm.setNodeLabel
+                (resources.getMessage(locale, "resources.actions.datasrc.create"));
+            dataSourceForm.setObjectName(null);
+            dataSourceForm.setActive("4");
+            dataSourceForm.setIdle("2");
+            dataSourceForm.setWait("5000");
+            dataSourceForm.setType(ResourceUtils.DATASOURCE_CLASS);
+
+        } else {
+            dataSourceForm.setNodeLabel
+                (resources.getMessage(locale, "resources.actions.datasrc.edit"));
+            dataSourceForm.setObjectName(objectName);
+
+            String attribute = null;
+            try {
+                ObjectName oname = new ObjectName(objectName);
+                try {
+                    attribute = "name";
+                    dataSourceForm.setJndiName
+                        ((String) mserver.getAttribute(oname, attribute));
+                    attribute = "url";
+                    dataSourceForm.setUrl
+                        ((String) mserver.getAttribute(oname, attribute));
+                    attribute = "driverClassName";
+                    dataSourceForm.setDriverClass
+                        ((String) mserver.getAttribute(oname, attribute));
+                    attribute = "username";
+                    dataSourceForm.setUsername
+                        ((String) mserver.getAttribute(oname, attribute));
+                    attribute = "password";
+                    dataSourceForm.setPassword
+                        ((String) mserver.getAttribute(oname, attribute));
+                    attribute = "validationQuery";
+                    dataSourceForm.setQuery
+                        ((String) mserver.getAttribute(oname, attribute));
+                } catch (AttributeNotFoundException ex) {
+                    // disply empty if attribute is not set yet
+                }
+                try {
+                    attribute = "maxActive";
+                    dataSourceForm.setActive
+                        ((String) mserver.getAttribute(oname, attribute));
+                } catch (AttributeNotFoundException e) {
+                    // if maxActive not defined, display default value
+                    dataSourceForm.setActive("4");
+                }
+                try {
+                    attribute = "maxIdle";
+                    dataSourceForm.setIdle
+                        ((String) mserver.getAttribute(oname, attribute));
+                } catch (AttributeNotFoundException e) {
+                    // if maxIdle not defined, display default value
+                    dataSourceForm.setIdle("2");
+                }
+                try {
+                    attribute = "maxWait";
+                    dataSourceForm.setWait
+                        ((String) mserver.getAttribute(oname, attribute));
+                } catch (AttributeNotFoundException e) {
+                    // if maxWait not defined, display default value
+                    dataSourceForm.setWait("5000");
+                }
+            } catch (Exception e) {
+                getServlet().log
+                    (resources.getMessage(locale,
+                        "users.error.attribute.get", attribute), e);
+                response.sendError
+                    (HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
+                     resources.getMessage
+                         (locale, "users.error.attribute.get", attribute));
+                return (null);
+            }
+        }
+
+        // Stash the form bean and forward to the display page
+        saveToken(request);
+        request.setAttribute("dataSourceForm", dataSourceForm);
+        return (mapping.findForward("DataSource"));
+
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/resources/SetUpEnvEntryAction.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/resources/SetUpEnvEntryAction.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/resources/SetUpEnvEntryAction.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,158 @@
+/*
+ * Copyright 2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.admin.resources;
+
+import java.io.IOException;
+import java.net.URLDecoder;
+import java.util.Iterator;
+import java.util.Locale;
+import javax.management.Attribute;
+import javax.management.MBeanServer;
+import javax.management.MBeanServerFactory;
+import javax.management.QueryExp;
+import javax.management.Query;
+import javax.management.ObjectInstance;
+import javax.management.ObjectName;
+import javax.management.JMException;
+import javax.management.MBeanAttributeInfo;
+import javax.management.MBeanOperationInfo;
+import javax.management.MBeanInfo;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+import org.apache.struts.action.Action;
+import org.apache.struts.action.ActionErrors;
+import org.apache.struts.action.ActionForm;
+import org.apache.struts.action.ActionForward;
+import org.apache.struts.action.ActionMapping;
+import org.apache.struts.util.MessageResources;
+import org.apache.webapp.admin.ApplicationServlet;
+
+
+/**
+ * <p>Implementation of <strong>Action</strong> that sets up and stashes
+ * a <code>EnvEntryForm</code> bean in request scope.  The form bean will have
+ * a null <code>objectName</code> property if this form represents a EnvEntry
+ * being added, or a non-null value for an existing EnvEntry.</p>
+ *
+ * @author Manveen Kaur
+ * @version $Revision: 303390 $ $Date: 2004-10-18 01:37:56 -0500 (Mon, 18 Oct 2004) $
+ * @since 4.1
+ */
+
+public final class SetUpEnvEntryAction extends Action {
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The MBeanServer we will be interacting with.
+     */
+    private MBeanServer mserver = null;
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Process the specified HTTP request, and create the corresponding HTTP
+     * response (or forward to another web component that will create it).
+     * Return an <code>ActionForward</code> instance describing where and how
+     * control should be forwarded, or <code>null</code> if the response has
+     * already been completed.
+     *
+     * @param mapping The ActionMapping used to select this instance
+     * @param actionForm The optional ActionForm bean for this request (if any)
+     * @param request The HTTP request we are processing
+     * @param response The HTTP response we are creating
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception ServletException if a servlet exception occurs
+     */
+    public ActionForward execute(ActionMapping mapping,
+                                 ActionForm form,
+                                 HttpServletRequest request,
+                                 HttpServletResponse response)
+        throws IOException, ServletException {
+
+        // Look up the components we will be using as needed
+        if (mserver == null) {
+            mserver = ((ApplicationServlet) getServlet()).getServer();
+        }
+        MessageResources resources = getResources(request);
+        HttpSession session = request.getSession();
+        Locale locale = getLocale(request);
+
+        // Set up the form bean based on the creating or editing state
+        String objectName = request.getParameter("objectName");
+        String resourcetype = request.getParameter("resourcetype");
+        String path = request.getParameter("path");
+        String host = request.getParameter("host");
+        String domain = request.getParameter("domain");
+        
+        EnvEntryForm envEntryForm = new EnvEntryForm();           
+        envEntryForm.setResourcetype(resourcetype);
+        envEntryForm.setPath(path);
+        envEntryForm.setHost(host);
+        envEntryForm.setDomain(domain);
+        if (objectName == null) {
+            envEntryForm.setNodeLabel
+                (resources.getMessage(locale, "resources.actions.env.create"));
+            envEntryForm.setObjectName(null); 
+        } else {
+            envEntryForm.setNodeLabel
+                (resources.getMessage(locale, "resources.actions.env.edit"));
+            envEntryForm.setObjectName(objectName);
+            
+            String attribute = null;
+            try {
+                ObjectName oname = new ObjectName(objectName);
+                attribute = "name";
+                envEntryForm.setName
+                    ((String) mserver.getAttribute(oname, attribute));
+                attribute = "type";
+                envEntryForm.setEntryType
+                    ((String) mserver.getAttribute(oname, attribute));
+                attribute = "value";
+                envEntryForm.setValue
+                    ((String) mserver.getAttribute(oname, attribute));
+                attribute = "override";
+                envEntryForm.setOverride(
+                    ((Boolean) mserver.getAttribute(oname, attribute)).booleanValue());
+                attribute = "description";
+                envEntryForm.setDescription
+                    ((String) mserver.getAttribute(oname, attribute));
+            } catch (Exception e) {
+                getServlet().log
+                    (resources.getMessage(locale,
+                        "users.error.attribute.get", attribute), e);
+                response.sendError
+                    (HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
+                     resources.getMessage
+                         (locale, "users.error.attribute.get", attribute));
+                return (null);
+            } 
+        }
+            
+        // Stash the form bean and forward to the display page
+        saveToken(request);
+        request.setAttribute("envEntryForm", envEntryForm);
+        return (mapping.findForward("EnvEntry"));
+
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/resources/SetUpMailSessionAction.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/resources/SetUpMailSessionAction.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/resources/SetUpMailSessionAction.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,155 @@
+/*
+ * Copyright 2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.admin.resources;
+
+import java.io.IOException;
+import java.net.URLDecoder;
+import java.util.Iterator;
+import java.util.Locale;
+import javax.management.Attribute;
+import javax.management.MBeanServer;
+import javax.management.MBeanServerFactory;
+import javax.management.QueryExp;
+import javax.management.Query;
+import javax.management.ObjectInstance;
+import javax.management.ObjectName;
+import javax.management.JMException;
+import javax.management.MBeanAttributeInfo;
+import javax.management.MBeanOperationInfo;
+import javax.management.MBeanInfo;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+import org.apache.struts.action.Action;
+import org.apache.struts.action.ActionErrors;
+import org.apache.struts.action.ActionForm;
+import org.apache.struts.action.ActionForward;
+import org.apache.struts.action.ActionMapping;
+import org.apache.struts.util.MessageResources;
+import org.apache.webapp.admin.ApplicationServlet;
+
+
+/**
+ * <p>Implementation of <strong>Action</strong> that sets up and stashes
+ * a <code>MailSessionForm</code> bean in request scope.  The form bean will have
+ * a null <code>objectName</code> property if this form represents a MailSession
+ * being added, or a non-null value for an existing MailSession.</p>
+ *
+ * @author Amy Roh
+ * @version $Revision: 303390 $ $Date: 2004-10-18 01:37:56 -0500 (Mon, 18 Oct 2004) $
+ * @since 4.1
+ */
+
+public final class SetUpMailSessionAction extends Action {
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The MBeanServer we will be interacting with.
+     */
+    private MBeanServer mserver = null;
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Process the specified HTTP request, and create the corresponding HTTP
+     * response (or forward to another web component that will create it).
+     * Return an <code>ActionForward</code> instance describing where and how
+     * control should be forwarded, or <code>null</code> if the response has
+     * already been completed.
+     *
+     * @param mapping The ActionMapping used to select this instance
+     * @param actionForm The optional ActionForm bean for this request (if any)
+     * @param request The HTTP request we are processing
+     * @param response The HTTP response we are creating
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception ServletException if a servlet exception occurs
+     */
+    public ActionForward execute(ActionMapping mapping,
+                                 ActionForm form,
+                                 HttpServletRequest request,
+                                 HttpServletResponse response)
+        throws IOException, ServletException {
+
+        // Look up the components we will be using as needed
+        if (mserver == null) {
+            mserver = ((ApplicationServlet) getServlet()).getServer();
+        }
+        MessageResources resources = getResources(request);
+        HttpSession session = request.getSession();
+        Locale locale = getLocale(request);
+
+        // Set up the form bean based on the creating or editing state
+        String objectName = request.getParameter("objectName");
+        String resourcetype = request.getParameter("resourcetype");
+        String path = request.getParameter("path");
+        String host = request.getParameter("host");
+        String domain = request.getParameter("domain");
+        
+        MailSessionForm mailSessionForm = new MailSessionForm();       
+        mailSessionForm.setResourcetype(resourcetype);
+        mailSessionForm.setPath(path);
+        mailSessionForm.setHost(host);
+        mailSessionForm.setDomain(domain);
+        mailSessionForm.setType(ResourceUtils.MAILSESSION_CLASS);
+
+        if (objectName == null) {
+            mailSessionForm.setNodeLabel
+                (resources.getMessage(locale, "resources.actions.mailsession.create"));
+            mailSessionForm.setObjectName(null);
+            mailSessionForm.setType(ResourceUtils.MAILSESSION_CLASS);
+            
+        } else {
+            mailSessionForm.setNodeLabel
+                (resources.getMessage(locale, "resources.actions.mailsession.edit"));
+            mailSessionForm.setObjectName(objectName);
+            
+            String attribute = null;
+            try {
+                
+                ObjectName oname = new ObjectName(objectName);
+                attribute = "name";
+                mailSessionForm.setName
+                    ((String) mserver.getAttribute(oname, attribute));
+                attribute = "mail.smtp.host";
+                mailSessionForm.setMailhost
+                    ((String) mserver.getAttribute(oname, attribute));
+        
+            } catch (Exception e) {
+                getServlet().log
+                    (resources.getMessage(locale,
+                        "users.error.attribute.get", attribute), e);
+                response.sendError
+                    (HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
+                     resources.getMessage
+                         (locale, "users.error.attribute.get", attribute));
+                return (null);
+            } 
+        }
+            
+        // Stash the form bean and forward to the display page
+        saveToken(request);
+        request.setAttribute("mailSessionForm", mailSessionForm);
+        return (mapping.findForward("MailSession"));
+
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/resources/SetUpResourceLinkAction.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/resources/SetUpResourceLinkAction.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/resources/SetUpResourceLinkAction.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,155 @@
+/*
+ * Copyright 2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.admin.resources;
+
+import java.io.IOException;
+import java.net.URLDecoder;
+import java.util.Iterator;
+import java.util.Locale;
+import javax.management.Attribute;
+import javax.management.MBeanServer;
+import javax.management.MBeanServerFactory;
+import javax.management.QueryExp;
+import javax.management.Query;
+import javax.management.ObjectInstance;
+import javax.management.ObjectName;
+import javax.management.JMException;
+import javax.management.MBeanAttributeInfo;
+import javax.management.MBeanOperationInfo;
+import javax.management.MBeanInfo;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+import org.apache.struts.action.Action;
+import org.apache.struts.action.ActionErrors;
+import org.apache.struts.action.ActionForm;
+import org.apache.struts.action.ActionForward;
+import org.apache.struts.action.ActionMapping;
+import org.apache.struts.util.MessageResources;
+import org.apache.webapp.admin.ApplicationServlet;
+
+
+/**
+ * <p>Implementation of <strong>Action</strong> that sets up and stashes
+ * a <code>ResourceLinkForm</code> bean in request scope.  The form bean will have
+ * a null <code>objectName</code> property if this form represents a ResourceLink
+ * being added, or a non-null value for an existing ResourceLink.</p>
+ *
+ * @author Amy Roh
+ * @version $Revision: 303390 $ $Date: 2004-10-18 01:37:56 -0500 (Mon, 18 Oct 2004) $
+ * @since 4.1
+ */
+
+public final class SetUpResourceLinkAction extends Action {
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The MBeanServer we will be interacting with.
+     */
+    private MBeanServer mserver = null;
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Process the specified HTTP request, and create the corresponding HTTP
+     * response (or forward to another web component that will create it).
+     * Return an <code>ActionForward</code> instance describing where and how
+     * control should be forwarded, or <code>null</code> if the response has
+     * already been completed.
+     *
+     * @param mapping The ActionMapping used to select this instance
+     * @param actionForm The optional ActionForm bean for this request (if any)
+     * @param request The HTTP request we are processing
+     * @param response The HTTP response we are creating
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception ServletException if a servlet exception occurs
+     */
+    public ActionForward execute(ActionMapping mapping,
+                                 ActionForm form,
+                                 HttpServletRequest request,
+                                 HttpServletResponse response)
+        throws IOException, ServletException {
+
+        // Look up the components we will be using as needed
+        if (mserver == null) {
+            mserver = ((ApplicationServlet) getServlet()).getServer();
+        }
+        MessageResources resources = getResources(request);
+        HttpSession session = request.getSession();
+        Locale locale = getLocale(request);
+        
+        // Set up the form bean based on the creating or editing state
+        String objectName = request.getParameter("objectName");
+        String resourcetype = request.getParameter("resourcetype");
+        String path = request.getParameter("path");
+        String host = request.getParameter("host");
+        String domain = request.getParameter("domain");
+        
+        ResourceLinkForm resourceLinkForm = new ResourceLinkForm();       
+        resourceLinkForm.setResourcetype(resourcetype);
+        resourceLinkForm.setPath(path);
+        resourceLinkForm.setHost(host);
+        resourceLinkForm.setDomain(domain);
+            
+        if (objectName == null) {
+            resourceLinkForm.setNodeLabel
+                (resources.getMessage(locale, "resources.actions.resourcelk.create"));
+            resourceLinkForm.setObjectName(null);
+            
+        } else {
+            resourceLinkForm.setNodeLabel
+                (resources.getMessage(locale, "resources.actions.resourcelk.edit"));
+            resourceLinkForm.setObjectName(objectName);
+            
+            String attribute = null;
+            try {
+                ObjectName oname = new ObjectName(objectName);
+                attribute = "name";
+                resourceLinkForm.setName
+                    ((String) mserver.getAttribute(oname, attribute));
+                attribute = "global";
+                resourceLinkForm.setGlobal
+                    ((String) mserver.getAttribute(oname, attribute));
+                attribute = "type";
+                resourceLinkForm.setType
+                    ((String) mserver.getAttribute(oname, attribute));
+                
+            } catch (Exception e) {
+                getServlet().log
+                    (resources.getMessage(locale,
+                        "users.error.attribute.get", attribute), e);
+                response.sendError
+                    (HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
+                     resources.getMessage
+                         (locale, "users.error.attribute.get", attribute));
+                return (null);
+            } 
+        }
+            
+        // Stash the form bean and forward to the display page
+        saveToken(request);
+        request.setAttribute("resourceLinkForm", resourceLinkForm);
+        return (mapping.findForward("ResourceLink"));
+
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/resources/SetUpUserDatabaseAction.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/resources/SetUpUserDatabaseAction.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/resources/SetUpUserDatabaseAction.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,151 @@
+/*
+ * Copyright 2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.admin.resources;
+
+import java.io.IOException;
+import java.net.URLDecoder;
+import java.util.Iterator;
+import java.util.Locale;
+import javax.management.Attribute;
+import javax.management.MBeanServer;
+import javax.management.MBeanServerFactory;
+import javax.management.QueryExp;
+import javax.management.Query;
+import javax.management.ObjectInstance;
+import javax.management.ObjectName;
+import javax.management.JMException;
+import javax.management.MBeanAttributeInfo;
+import javax.management.MBeanOperationInfo;
+import javax.management.MBeanInfo;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+import org.apache.struts.action.Action;
+import org.apache.struts.action.ActionErrors;
+import org.apache.struts.action.ActionForm;
+import org.apache.struts.action.ActionForward;
+import org.apache.struts.action.ActionMapping;
+import org.apache.struts.util.MessageResources;
+import org.apache.webapp.admin.ApplicationServlet;
+
+
+/**
+ * <p>Implementation of <strong>Action</strong> that sets up and stashes
+ * a <code>UserDatabaseForm</code> bean in request scope.  The form bean will have
+ * a null <code>objectName</code> property if this form represents a UserDatabase
+ * being added, or a non-null value for an existing UserDatabase.</p>
+ *
+ * @author Manveen Kaur
+ * @version $Revision: 303390 $ $Date: 2004-10-18 01:37:56 -0500 (Mon, 18 Oct 2004) $
+ * @since 4.1
+ */
+
+public final class SetUpUserDatabaseAction extends Action {
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The MBeanServer we will be interacting with.
+     */
+    private MBeanServer mserver = null;
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Process the specified HTTP request, and create the corresponding HTTP
+     * response (or forward to another web component that will create it).
+     * Return an <code>ActionForward</code> instance describing where and how
+     * control should be forwarded, or <code>null</code> if the response has
+     * already been completed.
+     *
+     * @param mapping The ActionMapping used to select this instance
+     * @param actionForm The optional ActionForm bean for this request (if any)
+     * @param request The HTTP request we are processing
+     * @param response The HTTP response we are creating
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception ServletException if a servlet exception occurs
+     */
+    public ActionForward execute(ActionMapping mapping,
+                                 ActionForm form,
+                                 HttpServletRequest request,
+                                 HttpServletResponse response)
+        throws IOException, ServletException {
+
+        // Look up the components we will be using as needed
+        if (mserver == null) {
+            mserver = ((ApplicationServlet) getServlet()).getServer();
+        }
+        MessageResources resources = getResources(request);
+        HttpSession session = request.getSession();
+        Locale locale = getLocale(request);
+
+        // Set up the form bean based on the creating or editing state
+        String objectName = request.getParameter("objectName");
+        String domain = request.getParameter("domain");
+        
+        UserDatabaseForm userDatabaseForm = new UserDatabaseForm();
+        userDatabaseForm.setFactory
+                            (SaveUserDatabaseAction.USERDB_FACTORY);
+        userDatabaseForm.setType
+                            (ResourceUtils.USERDB_CLASS);  
+        userDatabaseForm.setDomain(domain);               
+
+        if (objectName == null) {
+            userDatabaseForm.setNodeLabel
+                (resources.getMessage(locale, "resources.actions.userdb.create"));
+            userDatabaseForm.setObjectName(null);
+        } else {
+            userDatabaseForm.setNodeLabel
+                (resources.getMessage(locale, "resources.actions.userdb.edit"));
+            userDatabaseForm.setObjectName(objectName);
+                           
+            String attribute = null;
+            try {
+                ObjectName oname = new ObjectName(objectName);
+                attribute = "name";
+                userDatabaseForm.setName
+                    ((String) mserver.getAttribute(oname, attribute));
+                attribute = "pathname";
+                userDatabaseForm.setPath
+                    ((String) mserver.getAttribute(oname, attribute));
+                attribute = "description";
+                userDatabaseForm.setDescription
+                    ((String) mserver.getAttribute(oname, attribute));
+            } catch (Exception e) {
+                getServlet().log
+                    (resources.getMessage(locale,
+                        "users.error.attribute.get", attribute), e);
+                response.sendError
+                    (HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
+                     resources.getMessage
+                         (locale, "users.error.attribute.get", attribute));
+                return (null);
+            } 
+        }
+            
+        // Stash the form bean and forward to the display page
+        saveToken(request);
+        request.setAttribute("userDatabaseForm", userDatabaseForm);
+        return (mapping.findForward("UserDatabase"));
+
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/resources/UserDatabaseForm.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/resources/UserDatabaseForm.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/resources/UserDatabaseForm.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,204 @@
+/*
+ * Copyright 2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.admin.resources;
+
+import java.util.List;
+import java.util.ArrayList;
+
+import javax.servlet.http.HttpServletRequest;
+import org.apache.struts.action.ActionError;
+import org.apache.struts.action.ActionErrors;
+import org.apache.struts.action.ActionForm;
+import org.apache.struts.action.ActionMapping;
+import org.apache.webapp.admin.LabelValueBean;
+
+import java.lang.reflect.Constructor;
+
+/**
+ * Form bean for the individual user database page.
+ *
+ * @author Manveen Kaur
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ * @since 4.1
+ */
+
+public final class UserDatabaseForm extends BaseForm {
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    // ------------------------------------------------------------- Properties
+
+    /**
+     * The domain of this data source.
+     */
+    private String domain = null;
+    
+    /**
+     * Return the domain of the data source this bean refers to.
+     */
+    public String getDomain() {
+        return this.domain;
+    }
+
+    /**
+     * Set the domain of the data source this bean refers to.
+     */
+    public void setDomain(String domain) {
+        this.domain = domain;
+    }
+
+    /**
+     * The name of the associated entry.
+     */
+    private String name = null;
+
+    public String getName() {
+        return (this.name);
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    /**
+     * The path of the associated user database entry.
+     */
+    private String path = null;
+
+    public String getPath() {
+        return (this.path);
+    }
+
+    public void setPath(String path) {
+        this.path = path;
+    }
+
+    /**
+     * The type of the resource.
+     */
+    private String type = null;
+
+    public String getType() {
+        return (this.type);
+    }
+
+    public void setType(String type) {
+        this.type = type;
+    }
+
+    /**
+     * The factory that implements the user database entry.
+     */
+    private String factory = null;
+
+    public String getFactory() {
+        return (this.factory);
+    }
+
+    public void setFactory(String factory) {
+        this.factory = factory;
+    }
+
+    /**
+     * The description of the associated entry.
+     */
+    private String description = null;
+
+    public String getDescription() {
+        return (this.description);
+    }
+
+    public void setDescription(String description) {
+        this.description = description;
+    }
+    
+    // --------------------------------------------------------- Public Methods
+
+    /**
+     * Reset all properties to their default values.
+     *
+     * @param mapping The mapping used to select this instance
+     * @param request The servlet request we are processing
+     */
+    public void reset(ActionMapping mapping, HttpServletRequest request) {
+
+        super.reset(mapping, request);
+        name = null;
+        type = null;
+        path = null;
+        factory = null;
+        description = null;
+
+    }
+
+    /**
+     * Validate the properties that have been set from this HTTP request,
+     * and return an <code>ActionErrors</code> object that encapsulates any
+     * validation errors that have been found.  If no errors are found, return
+     * <code>null</code> or an <code>ActionErrors</code> object with no
+     * recorded error messages.
+     *
+     * @param mapping The mapping used to select this instance
+     * @param request The servlet request we are processing
+     */
+    
+    private ActionErrors errors = null;
+    
+    public ActionErrors validate(ActionMapping mapping,
+    HttpServletRequest request) {
+
+        errors = new ActionErrors();
+
+        String submit = request.getParameter("submit");
+        //if (submit != null) {
+
+            // name is a required field
+            if ((name == null) || (name.length() < 1)) {
+                errors.add("name",
+                           new ActionError("resources.error.name.required"));
+            }
+
+            // path is a required field
+            if ((path == null) || (path.length() < 1)) {
+                errors.add("path",
+                           new ActionError("resources.error.path.required"));
+            }
+
+            // Quotes not allowed in name
+            if ((name != null) && (name.indexOf('"') >= 0)) {
+                errors.add("name",
+                           new ActionError("users.error.quotes"));
+            }
+
+            // Quotes not allowed in path
+            if ((path != null) && (path.indexOf('"') > 0)) {
+                errors.add("path",
+                           new ActionError("users.error.quotes"));
+            }
+
+            // Quotes not allowed in description
+            if ((description != null) && (description.indexOf('"') > 0)) {
+                errors.add("description",
+                           new ActionError("users.error.quotes"));
+            }
+        //}
+        return (errors);
+    }
+    
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/resources/UserDatabasesForm.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/resources/UserDatabasesForm.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/resources/UserDatabasesForm.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.admin.resources;
+
+
+import javax.servlet.http.HttpServletRequest;
+import org.apache.struts.action.ActionError;
+import org.apache.struts.action.ActionErrors;
+import org.apache.struts.action.ActionForm;
+import org.apache.struts.action.ActionMapping;
+
+
+/**
+ * Form bean for the delete env entries page.
+ *
+ * @author Manveen Kaur
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ * @since 4.1
+ */
+
+public final class UserDatabasesForm extends BaseForm {
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * The object names of the specified user databases.
+     */
+    private String userDatabases[] = null;
+
+    public String[] getUserDatabases() {
+        return (this.userDatabases);
+    }
+
+    public void setUserDatabases(String userDatabases[]) {
+        this.userDatabases = userDatabases;
+    }
+
+    /**
+     * The domain of this userdatabase.
+     */
+    private String domain = null;
+    
+    /**
+     * Return the domain of the userdatabase this bean refers to.
+     */
+    public String getDomain() {
+        return this.domain;
+    }
+
+    /**
+     * Set the domain of the userdatabase this bean refers to.
+     */
+    public void setDomain(String domain) {
+        this.domain = domain;
+    }
+    
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Reset all properties to their default values.
+     *
+     * @param mapping The mapping used to select this instance
+     * @param request The servlet request we are processing
+     */
+    public void reset(ActionMapping mapping, HttpServletRequest request) {
+
+        super.reset(mapping, request);
+        this.userDatabases = null;
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/server/EditServerAction.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/server/EditServerAction.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/server/EditServerAction.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,149 @@
+/*
+ * Copyright 2001,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.admin.server;
+
+import java.io.IOException;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Locale;
+import java.util.ArrayList;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+import org.apache.struts.action.Action;
+import org.apache.struts.action.ActionErrors;
+import org.apache.struts.action.ActionForm;
+import org.apache.struts.action.ActionForward;
+import org.apache.struts.action.ActionMapping;
+import javax.management.MBeanServer;
+import javax.management.MBeanServerFactory;
+import javax.management.QueryExp;
+import javax.management.Query;
+import javax.management.ObjectInstance;
+import javax.management.ObjectName;
+import javax.management.JMException;
+
+import javax.management.modelmbean.ModelMBean;
+import javax.management.modelmbean.ModelMBeanInfo;
+
+import org.apache.struts.util.MessageResources;
+import org.apache.webapp.admin.LabelValueBean;
+import org.apache.webapp.admin.Lists;
+import org.apache.webapp.admin.TomcatTreeBuilder;
+import org.apache.webapp.admin.ApplicationServlet;
+
+/**
+ * Test <code>Action</code> that handles events from the tree control test
+ * page.
+ *
+ * @author Jazmin Jonson
+ * @author Manveen Kaur
+ * @version $Revision: 303390 $ $Date: 2004-10-18 01:37:56 -0500 (Mon, 18 Oct 2004) $
+ */
+
+public class EditServerAction extends Action {
+    
+
+    /**
+     * The MBeanServer we will be interacting with.
+     */
+    private MBeanServer mBServer = null;
+    
+    // --------------------------------------------------------- Public Methods
+    
+    /**
+     * Process the specified HTTP request, and create the corresponding HTTP
+     * response (or forward to another web component that will create it).
+     * Return an <code>ActionForward</code> instance describing where and how
+     * control should be forwarded, or <code>null</code> if the response has
+     * already been completed.
+     *
+     * @param mapping The ActionMapping used to select this instance
+     * @param actionForm The optional ActionForm bean for this request (if any)
+     * @param request The HTTP request we are processing
+     * @param response The HTTP response we are creating
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception ServletException if a servlet exception occurs
+     */
+    public ActionForward execute(ActionMapping mapping,
+    ActionForm form,
+    HttpServletRequest request,
+    HttpServletResponse response)
+    throws IOException, ServletException {
+        
+         // Acquire the resources that we need
+        HttpSession session = request.getSession();
+        Locale locale = getLocale(request);
+        MessageResources resources = getResources(request);
+        // Acquire a reference to the MBeanServer containing our MBeans
+        try {
+            mBServer = ((ApplicationServlet) getServlet()).getServer();
+        } catch (Throwable t) {
+            throw new ServletException
+            ("Cannot acquire MBeanServer reference", t);
+        }
+
+        // label of the node that was clicked on.
+        String nodeLabel = request.getParameter("nodeLabel");  
+        String select = request.getParameter("select");        
+        
+        ServerForm serverFm = new ServerForm();
+        session.setAttribute("serverForm", serverFm);
+        serverFm.setNodeLabel(nodeLabel);        
+        serverFm.setObjectName(select);
+        
+        ObjectName sname = null;    
+        try {
+            sname = new ObjectName(select);
+        } catch (Exception e) {
+            String message =
+                resources.getMessage(locale, "error.serviceName.bad",
+                                     request.getParameter("select"));
+            getServlet().log(message);
+            response.sendError(HttpServletResponse.SC_BAD_REQUEST, message);
+            return (null);
+        }
+      
+        String attribute = null;
+        try {
+            // Copy scalar properties
+            attribute = "port";
+            serverFm.setPortNumberText
+                (((Integer) mBServer.getAttribute(sname, attribute)).toString());
+            attribute = "shutdown";
+            serverFm.setShutdownText
+                ((String) mBServer.getAttribute(sname, attribute));
+
+            } catch (Throwable t) {
+            getServlet().log
+                (resources.getMessage(locale, "users.error.attribute.get",
+                                      attribute), t);
+            response.sendError
+                (HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
+                 resources.getMessage(locale, "users.error.attribute.get",
+                                      attribute));
+            return (null);
+        }
+
+        //forward to the server jsp.
+        return (mapping.findForward("Server"));        
+    }
+        
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/server/SaveServerAction.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/server/SaveServerAction.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/server/SaveServerAction.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,152 @@
+/*
+ * Copyright 2001,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.admin.server;
+
+import java.util.Iterator;
+import java.util.Locale;
+import java.io.IOException;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+import org.apache.struts.action.Action;
+import org.apache.struts.action.ActionErrors;
+import org.apache.struts.action.ActionForm;
+import org.apache.struts.action.ActionForward;
+import org.apache.struts.action.ActionMapping;
+import javax.management.Attribute;
+import javax.management.MBeanServer;
+import javax.management.MBeanServerFactory;
+import javax.management.QueryExp;
+import javax.management.Query;
+import javax.management.ObjectInstance;
+import javax.management.ObjectName;
+import org.apache.webapp.admin.ApplicationServlet;
+import org.apache.webapp.admin.TomcatTreeBuilder;
+import org.apache.struts.util.MessageResources;
+
+/**
+ * Implementation of <strong>Action</strong> that saves server properties.
+ *
+ * @author Jazmin Jonson
+ * @author Manveen Kaur
+ * @version $Revision: 303390 $ $Date: 2004-10-18 01:37:56 -0500 (Mon, 18 Oct 2004) $
+ */
+
+public final class SaveServerAction extends Action {
+    
+    /**
+     * The MBeanServer we will be interacting with.
+     */
+    private MBeanServer mBServer = null;
+    
+    // --------------------------------------------------------- Public Methods
+    
+    
+    /**
+     * Process the specified HTTP request, and create the corresponding HTTP
+     * response (or forward to another web component that will create it).
+     * Return an <code>ActionForward</code> instance describing where and how
+     * control should be forwarded, or <code>null</code> if the response has
+     * already been completed.
+     *
+     * @param mapping The ActionMapping used to select this instance
+     * @param actionForm The optional ActionForm bean for this request (if any)
+     * @param request The HTTP request we are processing
+     * @param response The HTTP response we are creating
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception ServletException if a servlet exception occurs
+     */
+    public ActionForward execute(ActionMapping mapping,
+    ActionForm form,
+    HttpServletRequest request,
+    HttpServletResponse response)
+    throws IOException, ServletException {
+        
+       // Acquire the resources that we need
+        HttpSession session = request.getSession();
+        Locale locale = getLocale(request);
+        MessageResources resources = getResources(request);
+        
+        // Acquire a reference to the MBeanServer containing our MBeans
+        try {
+            mBServer = ((ApplicationServlet) getServlet()).getServer();
+        } catch (Throwable t) {
+            throw new ServletException
+            ("Cannot acquire MBeanServer reference", t);
+        }
+        
+        ActionErrors errors = new ActionErrors();
+        
+        // Report any errors we have discovered back to the original form
+        if (!errors.isEmpty()) {
+            saveErrors(request, errors);
+            return (new ActionForward(mapping.getInput()));
+        }
+        
+        ServerForm sform = (ServerForm) form;
+        String sObjectName = sform.getObjectName();
+        // Acquire a reference to the Server MBean
+        ObjectName soname = null;
+        try {            
+            soname = new ObjectName(sObjectName);
+        } catch (Throwable t) {
+            throw new ServletException
+            ("Cannot acquire Server MBean reference ", t);
+        }
+        
+
+        // Perform attribute updates as requested
+        String attribute = null;
+        try{          
+            attribute = "port";
+            int port = 0;
+            try {
+                port = Integer.parseInt(sform.getPortNumberText());
+            } catch (Throwable t) {
+                port = 0;
+            }
+            mBServer.setAttribute(soname,
+                                  new Attribute("port", new Integer(port)));   
+            // set port warning as port < 1024 requires
+            // special software capabilities
+            if (port < 1024) {    
+                request.setAttribute("warning", "server.port.warning");
+            }
+            
+            attribute = "shutdown";
+            mBServer.setAttribute(soname,
+                                  new Attribute("shutdown", sform.getShutdownText()));
+            
+        } catch(Exception e){
+            getServlet().log
+                (resources.getMessage(locale, "users.error.attribute.set",
+                                      attribute), e);
+            response.sendError
+                (HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
+                 resources.getMessage(locale, "users.error.attribute.set",
+                                      attribute));
+            return (null);
+       }
+        
+        // Forward to the success reporting page
+        session.removeAttribute(mapping.getAttribute());
+        return (mapping.findForward("Save Successful"));        
+    }  
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/server/ServerForm.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/server/ServerForm.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/server/ServerForm.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,199 @@
+/*
+ * Copyright 2001,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.admin.server;
+
+
+import javax.servlet.http.HttpServletRequest;
+import org.apache.struts.action.ActionError;
+import org.apache.struts.action.ActionErrors;
+import org.apache.struts.action.ActionForm;
+import org.apache.struts.action.ActionMapping;
+import org.apache.webapp.admin.ApplicationServlet;
+import org.apache.webapp.admin.TomcatTreeBuilder;
+
+import java.util.List;
+
+/**
+ * Form bean for the server form page.  
+ * @author Patrick Luby
+ * @author Manveen Kaur
+ * @version $Revision: 302986 $ $Date: 2004-06-27 21:14:52 -0500 (Sun, 27 Jun 2004) $
+ */
+
+public final class ServerForm extends ActionForm {
+    
+    // ----------------------------------------------------- Instance Variables
+    
+    /**
+     * The text for the node label.
+     */
+    private String nodeLabel = null;
+    
+    /**
+     * The text for the port number.
+     */    
+    private String portNumberText = "8080";
+    
+    /**
+     * The text for the shutdown text.
+     */    
+    private String shutdownText = null;
+    
+    /**
+     * The object name of the Connector this bean refers to.
+     */
+    private String objectName = null;
+    
+    // ------------------------------------------------------------- Properties
+    /**
+     * Return the label of the node that was clicked.
+     */
+    public String getNodeLabel() {
+        
+        return this.nodeLabel;
+        
+    }
+    
+    /**
+     * Set the node label.
+     */
+    public void setNodeLabel(String nodeLabel) {
+        
+        this.nodeLabel = nodeLabel;
+        
+    }    
+    
+    /**
+     * Return the portNumberText.
+     */
+    public String getPortNumberText() {
+        
+        return this.portNumberText;
+        
+    }
+    
+    /**
+     * Set the portNumberText.
+     */
+    public void setPortNumberText(String portNumberText) {
+        
+        this.portNumberText = portNumberText;
+        
+    }
+    
+    /**
+     * Return the Shutdown Text.
+     */
+    public String getShutdownText() {
+        
+        return this.shutdownText;
+        
+    }
+    
+    /**
+     * Set the Shut down  Text.
+     */
+    public void setShutdownText(String shutdownText) {
+        
+        this.shutdownText = shutdownText;
+        
+    }
+    
+    /**
+     * Return the object name of the Connector this bean refers to.
+     */
+    public String getObjectName() {
+
+        return this.objectName;
+
+    }
+
+
+    /**
+     * Set the object name of the Connector this bean refers to.
+     */
+    public void setObjectName(String objectName) {
+
+        this.objectName = objectName;
+
+    }
+    
+    // --------------------------------------------------------- Public Methods
+    
+    /**
+     * Reset all properties to their default values.
+     *
+     * @param mapping The mapping used to select this instance
+     * @param request The servlet request we are processing
+     */
+    public void reset(ActionMapping mapping, HttpServletRequest request) {
+        
+        this.portNumberText = null;
+        this.shutdownText = null;
+        
+    }
+    
+    
+    /**
+     * Validate the properties that have been set from this HTTP request,
+     * and return an <code>ActionErrors</code> object that encapsulates any
+     * validation errors that have been found.  If no errors are found, return
+     * <code>null</code> or an <code>ActionErrors</code> object with no
+     * recorded error messages.
+     *
+     * @param mapping The mapping used to select this instance
+     * @param request The servlet request we are processing
+     */
+    public ActionErrors validate(ActionMapping mapping,
+    HttpServletRequest request) {
+        
+        ActionErrors errors = new ActionErrors();
+        
+        String submit = request.getParameter("submit");
+        //if (submit != null) {
+            
+            // check for portNumber -- must not be blank, must be in
+            // the range 1 to 65535.
+            
+            if ((portNumberText == null) || (portNumberText.length() < 1)) {
+                errors.add("portNumberText",
+                new ActionError("error.portNumber.required"));
+            } else {
+                try {
+                    int port = Integer.parseInt(portNumberText);
+                    if ((port <= 0) || (port >65535 ))
+                        errors.add("portNumberText", 
+                            new ActionError("error.portNumber.range"));
+                } catch (NumberFormatException e) {
+                    errors.add("portNumberText", 
+                        new ActionError("error.portNumber.format"));
+                }
+            }
+        
+            // shutdown text can be any non-empty string of atleast 6 characters.
+            
+            if ((shutdownText == null) || (shutdownText.length() < 7))
+                errors.add("shutdownText",
+                new ActionError("error.shutdownText.length"));
+            
+        //}
+        
+        return errors;
+        
+    }
+    
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/service/AddServiceAction.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/service/AddServiceAction.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/service/AddServiceAction.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2001-2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.admin.service;
+
+import java.io.IOException;
+import java.util.Locale;
+import java.util.ArrayList;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+import org.apache.struts.action.Action;
+import org.apache.struts.action.ActionErrors;
+import org.apache.struts.action.ActionForm;
+import org.apache.struts.action.ActionForward;
+import org.apache.struts.action.ActionMapping;
+import org.apache.struts.util.MessageResources;
+import org.apache.webapp.admin.LabelValueBean;
+import org.apache.webapp.admin.Lists;
+
+/**
+ * The <code>Action</code> that sets up <em>Add Service</em> transactions.
+ *
+ * @author Manveen Kaur
+ * @version $Revision: 303390 $ $Date: 2004-10-18 01:37:56 -0500 (Mon, 18 Oct 2004) $
+ */
+
+public class AddServiceAction extends Action {
+        
+    // --------------------------------------------------------- Public Methods
+    
+    /**
+     * Process the specified HTTP request, and create the corresponding HTTP
+     * response (or forward to another web component that will create it).
+     * Return an <code>ActionForward</code> instance describing where and how
+     * control should be forwarded, or <code>null</code> if the response has
+     * already been completed.
+     *
+     * @param mapping The ActionMapping used to select this instance
+     * @param actionForm The optional ActionForm bean for this request (if any)
+     * @param request The HTTP request we are processing
+     * @param response The HTTP response we are creating
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception ServletException if a servlet exception occurs
+     */
+    public ActionForward execute(ActionMapping mapping,
+                                 ActionForm form,
+                                 HttpServletRequest request,
+                                 HttpServletResponse response)
+        throws IOException, ServletException {
+
+        // Acquire the resources that we need
+        HttpSession session = request.getSession();
+        Locale locale = getLocale(request);
+        MessageResources resources = getResources(request);
+        
+        String serverName = request.getParameter("select");
+        
+        // Fill in the form values for display and editing
+        ServiceForm serviceFm = new ServiceForm();
+        session.setAttribute("serviceForm", serviceFm);
+        serviceFm.setAdminAction("Create");
+        serviceFm.setObjectName("");
+        serviceFm.setEngineObjectName("");
+        serviceFm.setServiceName("");
+        serviceFm.setEngineName("");
+        serviceFm.setDefaultHost("localhost");        
+        serviceFm.setAdminServiceName("");
+        serviceFm.setServerObjectName(serverName);
+        ArrayList hosts = new ArrayList();
+        hosts.add(new LabelValueBean
+                  (resources.getMessage(locale, "list.none"), ""));
+        serviceFm.setHostNameVals(hosts);
+        
+        // Forward to the service display page
+        return (mapping.findForward("Service"));
+        
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/service/DeleteServiceAction.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/service/DeleteServiceAction.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/service/DeleteServiceAction.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,161 @@
+/*
+ * Copyright 2001-2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.admin.service;
+
+import java.io.IOException;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Locale;
+import java.util.TreeSet;
+import java.util.Set;
+import java.util.ArrayList;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+import org.apache.struts.action.Action;
+import org.apache.struts.action.ActionErrors;
+import org.apache.struts.action.ActionForm;
+import org.apache.struts.action.ActionForward;
+import org.apache.struts.action.ActionMapping;
+
+import javax.management.MBeanServer;
+import javax.management.MBeanServerFactory;
+import javax.management.QueryExp;
+import javax.management.Query;
+import javax.management.ObjectInstance;
+import javax.management.ObjectName;
+import javax.management.JMException;
+import org.apache.struts.util.MessageResources;
+
+import org.apache.webapp.admin.ApplicationServlet;
+import org.apache.webapp.admin.TomcatTreeBuilder;
+import org.apache.webapp.admin.Lists;
+
+/**
+ * The <code>Action</code> that sets up <em>Delete Services</em> transactions.
+ *
+ * @author Manveen Kaur
+ * @version $Revision: 303390 $ $Date: 2004-10-18 01:37:56 -0500 (Mon, 18 Oct 2004) $
+ */
+
+public class DeleteServiceAction extends Action {
+    
+
+    /**
+     * The MBeanServer we will be interacting with.
+     */
+    private MBeanServer mBServer = null;
+    
+
+    // --------------------------------------------------------- Public Methods
+    
+    /**
+     * Process the specified HTTP request, and create the corresponding HTTP
+     * response (or forward to another web component that will create it).
+     * Return an <code>ActionForward</code> instance describing where and how
+     * control should be forwarded, or <code>null</code> if the response has
+     * already been completed.
+     *
+     * @param mapping The ActionMapping used to select this instance
+     * @param actionForm The optional ActionForm bean for this request (if any)
+     * @param request The HTTP request we are processing
+     * @param response The HTTP response we are creating
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception ServletException if a servlet exception occurs
+     */
+    public ActionForward execute(ActionMapping mapping,
+                                 ActionForm form,
+                                 HttpServletRequest request,
+                                 HttpServletResponse response)
+        throws IOException, ServletException {
+        
+
+        // Acquire the resources that we need
+        HttpSession session = request.getSession();
+        Locale locale = getLocale(request);
+        MessageResources resources = getResources(request);
+        
+        // Acquire a reference to the MBeanServer containing our MBeans
+        try {
+            mBServer = ((ApplicationServlet) getServlet()).getServer();
+        } catch (Throwable t) {
+            throw new ServletException
+            ("Cannot acquire MBeanServer reference", t);
+        }
+        
+        String select = request.getParameter("select");
+        String adminService = null;
+        ObjectName oname = null;
+        String domain = null;
+        // Get the service name the admin app runs on
+        // this service cannot be deleted from the admin tool
+        try {
+            oname = new ObjectName(select);
+            domain = oname.getDomain();
+            adminService = Lists.getAdminAppService(
+                                  mBServer, domain ,request);
+         } catch (Exception e) {
+            String message =
+                resources.getMessage(locale, "error.serviceName.bad",
+                                 adminService);
+            getServlet().log(message);
+            response.sendError(HttpServletResponse.SC_BAD_REQUEST, message);
+            return (null);
+        }
+        request.setAttribute("adminAppService", adminService);
+ 
+        // Set up a form bean containing the currently selected
+        // objects to be deleted
+        ServicesForm servicesForm = new ServicesForm();
+        if (select != null) {
+            String services[] = new String[1];
+            services[0] = select;
+            servicesForm.setServices(services);
+        }
+        request.setAttribute("servicesForm", servicesForm);
+
+        // Accumulate a list of all available services
+        ArrayList list = new ArrayList();
+        try {
+            String pattern = "*" + TomcatTreeBuilder.SERVICE_TYPE +
+                TomcatTreeBuilder.WILDCARD;
+            Iterator items =
+                mBServer.queryNames(new ObjectName(pattern), null).iterator();
+            while (items.hasNext()) {
+                list.add(items.next().toString());
+            }
+        } catch (Exception e) {
+            getServlet().log
+                (resources.getMessage(locale, "users.error.select"));
+            response.sendError
+                (HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
+                 resources.getMessage(locale, "users.error.select"));
+            return (null);
+        }
+        Collections.sort(list);
+        request.setAttribute("servicesList", list);    
+        
+        // Forward to the list display page
+        return (mapping.findForward("Services"));
+
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/service/DeleteServicesAction.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/service/DeleteServicesAction.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/service/DeleteServicesAction.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,160 @@
+/*
+ * Copyright 2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.admin.service;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.Locale;
+import java.util.Set;
+import java.util.TreeSet;
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+import javax.management.ObjectInstance;
+import javax.management.modelmbean.ModelMBean;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpSession;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import org.apache.struts.action.Action;
+import org.apache.struts.action.ActionForm;
+import org.apache.struts.action.ActionForward;
+import org.apache.struts.action.ActionMapping;
+import org.apache.struts.util.MessageResources;
+
+import org.apache.webapp.admin.ApplicationServlet;
+import org.apache.webapp.admin.TomcatTreeBuilder;
+import org.apache.webapp.admin.TreeControl;
+import org.apache.webapp.admin.TreeControlNode;
+
+
+/**
+ * The <code>Action</code> that completes <em>Delete Services</em>
+ * transactions.
+ *
+ * @author Manveen Kaur
+ * @version $Revision: 303390 $ $Date: 2004-10-18 01:37:56 -0500 (Mon, 18 Oct 2004) $
+ */
+
+public class DeleteServicesAction extends Action {
+
+
+    /**
+     * Signature for the <code>removeService</code> operation.
+     */
+    private String removeServiceTypes[] =
+    { "java.lang.String",      // Object name
+    };
+
+
+    /**
+     * The MBeanServer we will be interacting with.
+     */
+    private MBeanServer mBServer = null;
+    
+
+    // --------------------------------------------------------- Public Methods
+    
+    
+    /**
+     * Process the specified HTTP request, and create the corresponding HTTP
+     * response (or forward to another web component that will create it).
+     * Return an <code>ActionForward</code> instance describing where and how
+     * control should be forwarded, or <code>null</code> if the response has
+     * already been completed.
+     *
+     * @param mapping The ActionMapping used to select this instance
+     * @param actionForm The optional ActionForm bean for this request (if any)
+     * @param request The HTTP request we are processing
+     * @param response The HTTP response we are creating
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception ServletException if a servlet exception occurs
+     */
+    public ActionForward execute(ActionMapping mapping,
+                                 ActionForm form,
+                                 HttpServletRequest request,
+                                 HttpServletResponse response)
+        throws IOException, ServletException {
+        
+        
+        // Look up the components we will be using as needed
+        HttpSession session = request.getSession();
+        Locale locale = getLocale(request);
+        MessageResources resources = getResources(request);
+
+        // Acquire a reference to the MBeanServer containing our MBeans
+        try {
+            mBServer = ((ApplicationServlet) getServlet()).getServer();
+        } catch (Throwable t) {
+            throw new ServletException
+            ("Cannot acquire MBeanServer reference", t);
+        }
+        
+        // Delete the specified Services
+        String services[]  = ((ServicesForm) form).getServices();
+        String values[] = new String[1];
+        String operation = "removeService";
+        try {
+
+            // Look up our tree control data structure
+            TreeControl control = (TreeControl)
+                session.getAttribute("treeControlTest");
+
+            // Remove the specified services
+            for (int i = 0; i < services.length; i++) {
+                values[0] = services[i];
+                ObjectName oname = new ObjectName(services[i]);
+                String domain = oname.getDomain();
+                ObjectName fname = 
+                        TomcatTreeBuilder.getMBeanFactory();
+                mBServer.invoke(fname, operation,
+                                values, removeServiceTypes);
+                if (control != null) {
+                    control.selectNode(null);
+                    TreeControlNode node = control.findNode(services[i]);
+                    if (node != null) {
+                        node.remove();
+                    } else {
+                        getServlet().log("Missing TreeControlNode for " +
+                                         services[i]);
+                    }
+                } else {
+                    getServlet().log("Missing TreeControl attribute");
+                }
+            }
+
+        } catch (Exception e) {
+
+            getServlet().log
+                (resources.getMessage(locale, "users.error.invoke",
+                                      operation), e);
+            response.sendError
+                (HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
+                 resources.getMessage(locale, "users.error.invoke",
+                                      operation));
+            return (null);
+
+        }
+
+        // Report successful completion of this transaction
+        return (mapping.findForward("Save Successful"));
+
+    }
+    
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/service/EditServiceAction.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/service/EditServiceAction.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/service/EditServiceAction.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,199 @@
+/*
+ * Copyright 2001-2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.admin.service;
+
+import java.io.IOException;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Locale;
+import java.util.ArrayList;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+import org.apache.struts.action.Action;
+import org.apache.struts.action.ActionErrors;
+import org.apache.struts.action.ActionForm;
+import org.apache.struts.action.ActionForward;
+import org.apache.struts.action.ActionMapping;
+import org.apache.struts.util.MessageResources;
+
+import javax.management.MBeanServer;
+import javax.management.ObjectInstance;
+import javax.management.ObjectName;
+import javax.management.JMException;
+
+import org.apache.webapp.admin.ApplicationServlet;
+import org.apache.webapp.admin.LabelValueBean;
+import org.apache.webapp.admin.Lists;
+import org.apache.webapp.admin.TomcatTreeBuilder;
+
+/**
+ * The <code>Action</code> that sets up <em>Edit Service</em> transactions.
+ *
+ * @author Manveen Kaur
+ * @version $Revision: 303390 $ $Date: 2004-10-18 01:37:56 -0500 (Mon, 18 Oct 2004) $
+ */
+
+public class EditServiceAction extends Action {
+    
+
+    /**
+     * The MBeanServer we will be interacting with.
+     */
+    private MBeanServer mBServer = null;
+    
+
+    // --------------------------------------------------------- Public Methods
+    
+    /**
+     * Process the specified HTTP request, and create the corresponding HTTP
+     * response (or forward to another web component that will create it).
+     * Return an <code>ActionForward</code> instance describing where and how
+     * control should be forwarded, or <code>null</code> if the response has
+     * already been completed.
+     *
+     * @param mapping The ActionMapping used to select this instance
+     * @param actionForm The optional ActionForm bean for this request (if any)
+     * @param request The HTTP request we are processing
+     * @param response The HTTP response we are creating
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception ServletException if a servlet exception occurs
+     */
+    public ActionForward execute(ActionMapping mapping,
+                                 ActionForm form,
+                                 HttpServletRequest request,
+                                 HttpServletResponse response)
+        throws IOException, ServletException {
+        
+        // Acquire the resources that we need
+        HttpSession session = request.getSession();
+        Locale locale = getLocale(request);
+        MessageResources resources = getResources(request);
+        
+        // Acquire a reference to the MBeanServer containing our MBeans
+        try {
+            mBServer = ((ApplicationServlet) getServlet()).getServer();
+        } catch (Throwable t) {
+            throw new ServletException
+            ("Cannot acquire MBeanServer reference", t);
+        }
+        
+        // Set up the object names of the MBeans we are manipulating
+        ObjectName sname = null;
+        ObjectName ename = null;
+        StringBuffer sb = null;
+        try {
+            sname = new ObjectName(request.getParameter("select"));
+        } catch (Exception e) {
+            String message =
+                resources.getMessage(locale, "error.serviceName.bad",
+                                     request.getParameter("select"));
+            getServlet().log(message);
+            response.sendError(HttpServletResponse.SC_BAD_REQUEST, message);
+            return (null);
+        }
+        try {
+            sb = new StringBuffer(sname.getDomain());
+            sb.append(":type=Engine");
+            ename = new ObjectName(sb.toString());
+        } catch (Exception e) {
+            String message =
+                resources.getMessage(locale, "error.engineName.bad",
+                                     sb.toString());
+            getServlet().log(message);
+            response.sendError(HttpServletResponse.SC_BAD_REQUEST, message);
+            return (null);
+        }
+
+        String adminService = null;
+        // Get the service name the admin app runs on
+        // this service cannot be deleted from the admin tool
+        try {
+            adminService = Lists.getAdminAppService(
+                                  mBServer, sname.getDomain(),request);
+         } catch (Exception e) {
+            String message =
+                resources.getMessage(locale, "error.serviceName.bad",
+                                 adminService);
+            getServlet().log(message);
+            response.sendError(HttpServletResponse.SC_BAD_REQUEST, message);
+            return (null);
+        }
+
+        
+        // Fill in the form values for display and editing
+        ServiceForm serviceFm = new ServiceForm();
+        session.setAttribute("serviceForm", serviceFm);
+        serviceFm.setAdminAction("Edit");
+        serviceFm.setObjectName(sname.toString());
+        serviceFm.setEngineObjectName(ename.toString());
+        sb = new StringBuffer();
+        sb.append(resources.getMessage(locale, "server.service.treeBuilder.subtreeNode"));
+        sb.append(" (");
+        sb.append(sname.getKeyProperty("serviceName"));
+        sb.append(")");
+        serviceFm.setNodeLabel(sb.toString());
+        serviceFm.setAdminServiceName(adminService);
+        String attribute = null;
+        try {
+
+            // Copy scalar properties
+            attribute = "name";
+            serviceFm.setServiceName
+                ((String) mBServer.getAttribute(sname, attribute));
+            attribute = "name";
+            serviceFm.setEngineName
+                ((String) mBServer.getAttribute(ename, attribute));
+            attribute = "defaultHost";
+            serviceFm.setDefaultHost
+                ((String) mBServer.getAttribute(ename, attribute));
+
+            // Build the list of available hosts
+            attribute = "hosts";
+            ArrayList hosts = new ArrayList();
+            hosts.add(new LabelValueBean
+                      (resources.getMessage(locale, "list.none"), ""));
+            Iterator items = Lists.getHosts(mBServer, sname).iterator();
+            while (items.hasNext()) {
+                ObjectName hname = new ObjectName((String) items.next());
+                String name = hname.getKeyProperty("host");
+                if (name!=null) {
+                    hosts.add(new LabelValueBean(name, name));
+                }
+            }
+            serviceFm.setHostNameVals(hosts);
+
+        } catch (Throwable t) {
+            getServlet().log
+                (resources.getMessage(locale, "users.error.attribute.get",
+                                      attribute), t);
+            response.sendError
+                (HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
+                 resources.getMessage(locale, "users.error.attribute.get",
+                                      attribute));
+            return (null);
+        }
+        
+        // Forward to the service display page
+        return (mapping.findForward("Service"));
+        
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/service/SaveServiceAction.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/service/SaveServiceAction.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/service/SaveServiceAction.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,358 @@
+/*
+ * Copyright 2001-2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.admin.service;
+
+
+import java.net.URLEncoder;
+import java.util.Iterator;
+import java.util.Locale;
+import java.util.Vector;
+import java.io.IOException;
+import javax.management.Attribute;
+import javax.management.MBeanServer;
+import javax.management.MBeanServerFactory;
+import javax.management.QueryExp;
+import javax.management.Query;
+import javax.management.ObjectInstance;
+import javax.management.ObjectName;
+import javax.management.JMException;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+import org.apache.struts.action.Action;
+import org.apache.struts.action.ActionError;
+import org.apache.struts.action.ActionErrors;
+import org.apache.struts.action.ActionForm;
+import org.apache.struts.action.ActionForward;
+import org.apache.struts.action.ActionMapping;
+import org.apache.struts.util.MessageResources;
+import org.apache.webapp.admin.ApplicationServlet;
+import org.apache.webapp.admin.Lists;
+import org.apache.webapp.admin.TomcatTreeBuilder;
+import org.apache.webapp.admin.TreeControl;
+import org.apache.webapp.admin.TreeControlNode;
+import org.apache.webapp.admin.valve.ValveUtil;
+
+
+
+/**
+ * The <code>Action</code> that completes <em>Add Service</em> and
+ * <em>Edit Service</em> transactions.
+ *
+ * @author Manveen Kaur
+ * @author Amy Roh
+ * @version $Revision: 303390 $ $Date: 2004-10-18 01:37:56 -0500 (Mon, 18 Oct 2004) $
+ */
+
+public final class SaveServiceAction extends Action {
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * Signature for the <code>createStandardEngine</code> operation.
+     */
+    private String createStandardEngineTypes[] =
+    { "java.lang.String",     // parent
+      "java.lang.String",     // name
+      "java.lang.String",     // defaultHost
+    };
+
+
+    /**
+     * Signature for the <code>createStandardService</code> operation.
+     */
+    private String createStandardServiceTypes[] =
+    { "java.lang.String",     // parent
+      "java.lang.String",     // name
+      "java.lang.String"      // domain
+    };
+
+
+    /**
+     * Signature for the <code>createStandardEngineService</code> operation.
+     */
+    private String createStandardEngineServiceTypes[] =
+    { "java.lang.String",     // parent
+      "java.lang.String",     // engineName
+      "java.lang.String",     // defaultHost
+      "java.lang.String"      // serviceName
+    };
+    
+    
+    /**
+     * Signature for the <code>createUserDatabaseRealm</code> operation.
+     */
+    private String createUserDatabaseRealmTypes[] =
+    { "java.lang.String",     // parent
+      "java.lang.String",     // name
+    };
+
+
+    /**
+     * The MBeanServer we will be interacting with.
+     */
+    private MBeanServer mBServer = null;
+    
+
+    // --------------------------------------------------------- Public Methods
+    
+    
+    /**
+     * Process the specified HTTP request, and create the corresponding HTTP
+     * response (or forward to another web component that will create it).
+     * Return an <code>ActionForward</code> instance describing where and how
+     * control should be forwarded, or <code>null</code> if the response has
+     * already been completed.
+     *
+     * @param mapping The ActionMapping used to select this instance
+     * @param actionForm The optional ActionForm bean for this request (if any)
+     * @param request The HTTP request we are processing
+     * @param response The HTTP response we are creating
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception ServletException if a servlet exception occurs
+     */
+    public ActionForward execute(ActionMapping mapping,
+                                 ActionForm form,
+                                 HttpServletRequest request,
+                                 HttpServletResponse response)
+        throws IOException, ServletException {
+        
+        // Acquire the resources that we need
+        HttpSession session = request.getSession();
+        Locale locale = getLocale(request);
+        MessageResources resources = getResources(request);
+        
+        // Acquire a reference to the MBeanServer containing our MBeans
+        try {
+            mBServer = ((ApplicationServlet) getServlet()).getServer();
+        } catch (Throwable t) {
+            throw new ServletException
+            ("Cannot acquire MBeanServer reference", t);
+        }
+        
+        // Identify the requested action
+        ServiceForm sform = (ServiceForm) form;
+        String adminAction = sform.getAdminAction();
+        String sObjectName = sform.getObjectName();
+        String eObjectName = sform.getEngineObjectName();
+        String serverObjectName = sform.getServerObjectName();
+        ObjectName eoname = null;
+        ObjectName soname = null;
+        // Perform a "Create Service" transaction (if requested)
+        if ("Create".equals(adminAction)) {
+
+            String operation = null;
+            String values[] = null;
+
+            try {
+                // engine name is domain
+                String engineName = sform.getEngineName();
+                //String domain = (new ObjectName(serverObjectName)).getDomain();
+                // Ensure that the requested service name is unique
+                ObjectName oname =
+                    new ObjectName("*" + TomcatTreeBuilder.SERVICE_TYPE + 
+                                ",serviceName="+sform.getServiceName());
+                Iterator names = mBServer.queryNames(oname, null).iterator();
+                while (names.hasNext()) {       
+                    if (mBServer.isRegistered((ObjectName)names.next())) {
+                        ActionErrors errors = new ActionErrors();
+                        errors.add("serviceName",
+                               new ActionError("error.serviceName.exists"));
+                        saveErrors(request, errors);
+                        return (new ActionForward(mapping.getInput()));
+                    }
+                }
+                
+                oname = new ObjectName(engineName + TomcatTreeBuilder.ENGINE_TYPE);
+                if (mBServer.isRegistered(oname)) {
+                    ActionErrors errors = new ActionErrors();
+                    errors.add("serviceName",
+                               new ActionError("error.engineName.exists"));
+                    saveErrors(request, errors);
+                    return (new ActionForward(mapping.getInput()));
+                }
+                
+                // Look up our MBeanFactory MBean
+                ObjectName fname = TomcatTreeBuilder.getMBeanFactory();
+
+                // Create a new StandardService and StandardEngine object
+                values = new String[4];
+                values[0] = TomcatTreeBuilder.SERVER_TYPE;
+                values[1] = engineName;
+                values[2] = sform.getDefaultHost();
+                values[3] = sform.getServiceName();
+                operation = "createStandardEngineService";
+                Vector onames = (Vector)
+                    mBServer.invoke(fname, operation,
+                                    values, createStandardEngineServiceTypes);
+                eoname = (ObjectName)onames.get(0);
+                soname = (ObjectName)onames.get(1);
+                sObjectName = soname.toString();
+                eObjectName = eoname.toString();
+                
+                String realmOName = ValveUtil.getObjectName(
+                                    eObjectName, TomcatTreeBuilder.REALM_TYPE);
+            
+                ObjectName roname = new ObjectName(realmOName);
+                if (mBServer.isRegistered(roname)) {
+                    mBServer.unregisterMBean(roname); 
+                }
+                
+                // Create a new UserDatabaseRealm object
+                values = new String[2];
+                values[0] = eObjectName;
+                values[1] = "UserDatabase";
+                operation = "createUserDatabaseRealm";
+                //realmOName = (String)
+                //    mBServer.invoke(fname, operation,
+                //                    values, createUserDatabaseRealmTypes);
+                                    
+                //Enumeration enum = onames.elements();
+                //while (enum.hasMoreElements()) {
+                //    getServlet().log("save service "+enum.nextElement());
+                //}
+                sObjectName = soname.toString();
+                eObjectName = eoname.toString();
+                
+                // Create a new StandardService object
+                //values = new String[3];
+                //values[0] = TomcatTreeBuilder.SERVER_TYPE;
+                //values[1] = sform.getServiceName();
+                //values[2] = engineName;
+                //operation = "createStandardService";
+                //sObjectName = (String)
+                //    mBServer.invoke(fname, operation,
+                //                    values, createStandardServiceTypes);
+
+                // Create a new StandardEngine object
+                //values = new String[3];
+                //values[0] = sObjectName;
+                //values[1] = sform.getEngineName();
+                //values[2] = sform.getDefaultHost();
+                //if ("".equals(values[2])) {
+                //    values[2] = null;
+                //}
+                //operation = "createStandardEngine";
+                //eObjectName = (String)
+                //    mBServer.invoke(fname, operation,
+                //                    values, createStandardEngineTypes);
+
+                // Add the new Service to our tree control node
+                TreeControl control = (TreeControl)
+                    session.getAttribute("treeControlTest");
+                if (control != null) {
+                    String parentName = TomcatTreeBuilder.DEFAULT_DOMAIN + 
+                                            TomcatTreeBuilder.SERVER_TYPE;
+                    TreeControlNode parentNode = control.findNode(parentName);
+                    if (parentNode != null) {
+                        String nodeLabel = resources.getMessage(locale, 
+                            "server.service.treeBuilder.subtreeNode") +" (" +
+                            soname.getKeyProperty("serviceName") + ")";
+                        String encodedName =
+                            URLEncoder.encode(sObjectName,TomcatTreeBuilder.URL_ENCODING);
+                        TreeControlNode childNode =
+                            new TreeControlNode(sObjectName,
+                                                "Service.gif",
+                                                nodeLabel,
+                                                "EditService.do?select=" +
+                                                encodedName,
+                                                "content",
+                                                true, engineName);
+                        parentNode.addChild(childNode);
+                        // update tree to display the newly added realm
+                        //Iterator realmNames =
+                        //    Lists.getRealms(mBServer, sObjectName).iterator();
+                        //while (realmNames.hasNext()) {
+                        //    String realmName = (String) realmNames.next();
+                        //    ObjectName objectName = new ObjectName(realmName);
+                        //    nodeLabel = "Realm for service (" + 
+                        //                        sform.getServiceName() + ")";
+                        //    TreeControlNode realmNode =
+                        //        new TreeControlNode(realmName,
+                        //                            "Realm.gif",
+                        //                            nodeLabel,
+                        //                            "EditRealm.do?select=" +
+                        //                            URLEncoder.encode(realmName) +
+                        //                            "&nodeLabel=" +
+                        //                            URLEncoder.encode(nodeLabel),
+                        //                            "content",
+                        //                            false, engineName);
+                        //    childNode.addChild(realmNode);               
+                        //}         
+                        // FIXME - force a redisplay
+                    } else {
+                        getServlet().log
+                            ("Cannot find parent node '" + parentName + "'");
+                    }
+                } else {
+                    getServlet().log
+                        ("Cannot find TreeControlNode!");
+                }
+
+            } catch (Exception e) {
+
+                getServlet().log
+                    (resources.getMessage(locale, "users.error.invoke",
+                                          operation), e);
+                response.sendError
+                    (HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
+                     resources.getMessage(locale, "users.error.invoke",
+                                          operation));
+                return (null);
+
+            }
+
+        }
+
+        // Perform attribute updates as requested
+        String attribute = null;
+        try {
+        
+            eoname = new ObjectName(eObjectName);
+            soname = new ObjectName(sObjectName);
+
+            attribute = "defaultHost";
+            String defaultHost = sform.getDefaultHost();
+            if ("".equals(defaultHost)) {
+                defaultHost = null;
+            }
+            mBServer.setAttribute(eoname,
+                                  new Attribute("defaultHost", defaultHost));
+
+        } catch (Exception e) {
+
+            getServlet().log
+                (resources.getMessage(locale, "users.error.attribute.set",
+                                      attribute), e);
+            response.sendError
+                (HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
+                 resources.getMessage(locale, "users.error.attribute.set",
+                                      attribute));
+            return (null);
+        }
+        
+        // Forward to the success reporting page
+        session.removeAttribute(mapping.getAttribute());
+        return (mapping.findForward("Save Successful"));
+        
+    }
+    
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/service/ServiceForm.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/service/ServiceForm.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/service/ServiceForm.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,363 @@
+/*
+ * Copyright 2001,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.admin.service;
+
+import javax.servlet.http.HttpServletRequest;
+import org.apache.struts.action.ActionError;
+import org.apache.struts.action.ActionErrors;
+import org.apache.struts.action.ActionForm;
+import org.apache.struts.action.ActionMapping;
+import java.util.List;
+
+/**
+ * Form bean for the service page.
+ *
+ * @author Manveen Kaur
+ * @version $Revision: 302986 $ $Date: 2004-06-27 21:14:52 -0500 (Sun, 27 Jun 2004) $
+ */
+
+public final class ServiceForm extends ActionForm {
+    
+    // ----------------------------------------------------- Instance Variables
+    
+
+    /**
+     * The administrative action represented by this form.
+     */
+    private String adminAction = "Edit";
+
+
+    /**
+     * The object name of the Engine this bean refers to.
+     */
+    private String engineObjectName = null;
+
+
+    /**
+     * The object name of the Service this bean refers to.
+     */
+    private String objectName = null;
+
+
+    /**
+     * The text for the serviceName.
+     */
+    private String serviceName = null;    
+
+    /**
+     * The text for the serverObjectName.
+     */
+    private String serverObjectName = null; 
+    
+   /**
+     * The text for the node label.
+    */
+    private String nodeLabel = null; 
+    
+    /**
+     * The text for the engine Name.
+     */
+    private String engineName = null;
+    
+    
+    /**
+     * The name of the service the admin app runs on.
+     */
+    private String adminServiceName = null;    
+
+    /**
+     * The text for the defaultHost Name.
+     */
+    private String defaultHost = null;
+    
+    private List hostNameVals = null;
+
+
+    // ------------------------------------------------------------- Properties
+    
+
+    /**
+     * Return the administrative action represented by this form.
+     */
+    public String getAdminAction() {
+
+        return this.adminAction;
+
+    }
+
+
+    /**
+     * Set the administrative action represented by this form.
+     */
+    public void setAdminAction(String adminAction) {
+
+        this.adminAction = adminAction;
+
+    }
+
+
+    /**
+     * Return the object name of the Engine this bean refers to.
+     */
+    public String getEngineObjectName() {
+
+        return this.engineObjectName;
+
+    }
+
+
+    /**
+     * Set the object name of the Engine this bean refers to.
+     */
+    public void setEngineObjectName(String engineObjectName) {
+
+        this.engineObjectName = engineObjectName;
+
+    }
+
+
+    /**
+     * Return the object name of the Service this bean refers to.
+     */
+    public String getObjectName() {
+
+        return this.objectName;
+
+    }
+
+
+    /**
+     * Set the object name of the Service this bean refers to.
+     */
+    public void setObjectName(String objectName) {
+
+        this.objectName = objectName;
+
+    }
+
+
+    /**
+     * Return the label of the node that was clicked.
+     */
+    public String getNodeLabel() {
+        
+        return this.nodeLabel;
+        
+    }
+    
+    /**
+     * Set the node label.
+     */
+    public void setNodeLabel(String nodeLabel) {
+        
+        this.nodeLabel = nodeLabel;
+        
+    }
+        
+    /**
+     * Return the host name values.
+     */
+    public List getHostNameVals() {
+        
+        return this.hostNameVals;
+        
+    }
+    
+    /**
+     * Set the hostName values.
+     */
+    public void setHostNameVals(List hostNameVals) {
+        
+        this.hostNameVals = hostNameVals;
+        
+    }
+    
+    /**
+     * Set the engineName.
+     */
+    
+    public void setEngineName(String engineName) {
+        
+        this.engineName = engineName;
+        
+    }
+    
+    
+    /**
+     * Return the engineName.
+     */
+    
+    public String getEngineName() {
+        
+        return this.engineName;
+        
+    }
+    
+    /**
+     * Return the Server ObjectName.
+     */
+    public String getServerObjectName() {
+        
+        return this.serverObjectName;
+        
+    }
+    
+    /**
+     * Set the Server Name.
+     */
+    public void setServerObjectName(String serverObjectName) {
+        
+        this.serverObjectName = serverObjectName;
+        
+    }
+    
+    /**
+     * Return the Service Name.
+     */
+    public String getServiceName() {
+        
+        return this.serviceName;
+        
+    }
+    
+    /**
+     * Set the Service Name.
+     */
+    public void setServiceName(String serviceName) {
+        
+        this.serviceName = serviceName;
+        
+    }
+
+    /**
+     * Return the name of the service the admin app runs on.
+     */
+    public String getAdminServiceName() {
+
+        return this.adminServiceName;
+
+    }
+
+    /**
+     * Set the name of the service the admin app runs on.
+     */
+    public void setAdminServiceName(String adminServiceName) {
+
+        this.adminServiceName = adminServiceName;
+
+    }
+
+    /**
+     * Return the default Host.
+     */
+    public String getDefaultHost() {
+        
+        return this.defaultHost;
+        
+    }
+    
+    /**
+     * Set the default Host.
+     */
+    public void setDefaultHost(String defaultHost) {
+
+        this.defaultHost = defaultHost;
+
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+    
+    /**
+     * Reset all properties to their default values.
+     *
+     * @param mapping The mapping used to select this instance
+     * @param request The servlet request we are processing
+     */
+    public void reset(ActionMapping mapping, HttpServletRequest request) {
+        
+        this.engineObjectName = null;
+        this.objectName = null;
+        this.serviceName = null;
+        this.engineName = null;
+        this.adminServiceName = null;
+        this.defaultHost = null;
+    }
+    
+
+    /**
+     * Render this object as a String.
+     */
+    public String toString() {
+
+        StringBuffer sb = new StringBuffer("ServiceForm[adminAction=");
+        sb.append(adminAction);
+        sb.append(",defaultHost=");
+        sb.append(defaultHost);
+        sb.append(",engineName=");
+        sb.append(engineName);
+        sb.append(",engineObjectName='");
+        sb.append(engineObjectName);
+        sb.append("',objectName='");
+        sb.append(objectName);
+        sb.append("',serviceName=");
+        sb.append(serviceName);
+        sb.append("',serverObjectName=");
+        sb.append(serverObjectName);
+        sb.append("',adminServiceName=");
+        sb.append(adminServiceName);
+        sb.append("]");
+        return (sb.toString());
+
+    }
+
+
+    /**
+     * Validate the properties that have been set from this HTTP request,
+     * and return an <code>ActionErrors</code> object that encapsulates any
+     * validation errors that have been found.  If no errors are found, return
+     * <code>null</code> or an <code>ActionErrors</code> object with no
+     * recorded error messages.
+     *
+     * @param mapping The mapping used to select this instance
+     * @param request The servlet request we are processing
+     */
+    public ActionErrors validate(ActionMapping mapping,
+    HttpServletRequest request) {
+        
+        ActionErrors errors = new ActionErrors();
+        String submit = request.getParameter("submit");
+        
+        //if (submit != null) {
+
+            if ((serviceName == null) || (serviceName.length() < 1)) {
+                errors.add("serviceName",
+                           new ActionError("error.serviceName.required"));
+            }
+            
+            if ((engineName == null) || (engineName.length() < 1)) {
+                errors.add("engineName",
+                           new ActionError("error.engineName.required"));
+            }
+
+        //}
+        
+        return errors;
+    }
+    
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/service/ServicesForm.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/service/ServicesForm.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/service/ServicesForm.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.admin.service;
+
+
+import javax.servlet.http.HttpServletRequest;
+import org.apache.struts.action.ActionForm;
+import org.apache.struts.action.ActionMapping;
+
+
+/**
+ * Form bean for deleting services.
+ *
+ * @author Manveen Kaur
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class ServicesForm extends ActionForm {
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * The object names of the services to be deleted.
+     */
+    private String services[] = new String[0];
+
+    public String[] getServices() {
+        return (this.services);
+    }
+
+    public void setServices(String services[]) {
+        this.services = services;
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Reset all properties to their default values.
+     *
+     * @param mapping The mapping used to select this instance
+     * @param request The servlet request we are processing
+     */
+    public void reset(ActionMapping mapping, HttpServletRequest request) {
+
+        this.services = new String[0];
+
+    }
+        
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/users/BaseForm.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/users/BaseForm.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/users/BaseForm.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,124 @@
+/*
+ * Copyright 2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.admin.users;
+
+
+import javax.management.ObjectName;
+import javax.servlet.http.HttpServletRequest;
+import org.apache.struts.action.ActionError;
+import org.apache.struts.action.ActionErrors;
+import org.apache.struts.action.ActionForm;
+import org.apache.struts.action.ActionMapping;
+
+
+/**
+ * Base class for form beans for the user administration
+ * options.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ * @since 4.1
+ */
+
+public class BaseForm extends ActionForm {
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * The MBean Name of UserDatabase containing this object.
+     */
+    private String databaseName = null;
+
+    public String getDatabaseName() {
+        if ((this.databaseName == null) && (this.objectName != null)) {
+            try {
+                ObjectName oname = new ObjectName(this.objectName);
+                this.databaseName = oname.getDomain() + ":" +
+                  "type=UserDatabase,database=" +
+                  oname.getKeyProperty("database");
+            } catch (Throwable t) {
+                this.databaseName = null;
+            }
+        }
+        return (this.databaseName);
+    }
+
+    public void setDatabaseName(String databaseName) {
+        if ((databaseName != null) && (databaseName.length() < 1)) {
+            this.databaseName = null;
+        } else {
+            this.databaseName = databaseName;
+        }
+    }
+
+
+    /**
+     * The node label to be displayed in the user interface.
+     */
+    private String nodeLabel = null;
+
+    public String getNodeLabel() {
+        return (this.nodeLabel);
+    }
+
+    public void setNodeLabel(String nodeLabel) {
+        this.nodeLabel = nodeLabel;
+    }
+
+
+    /**
+     * The MBean object name of this object.  A null or zero-length
+     * value indicates that this is a new object.
+     */
+    private String objectName = null;
+
+    public String getObjectName() {
+        return (this.objectName);
+    }
+
+    public void setObjectName(String objectName) {
+        if ((objectName != null) && (objectName.length() < 1)) {
+            this.objectName = null;
+        } else {
+            this.objectName = objectName;
+        }
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+    /**
+     * Reset all properties to their default values.
+     *
+     * @param mapping The mapping used to select this instance
+     * @param request The servlet request we are processing
+     */
+    public void reset(ActionMapping mapping, HttpServletRequest request) {
+
+        databaseName = null;
+        nodeLabel = null;
+        objectName = null;
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/users/DeleteGroupsAction.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/users/DeleteGroupsAction.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/users/DeleteGroupsAction.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,177 @@
+/*
+ * Copyright 2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.admin.users;
+
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.Locale;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+import org.apache.struts.action.Action;
+import org.apache.struts.action.ActionErrors;
+import org.apache.struts.action.ActionForm;
+import org.apache.struts.action.ActionForward;
+import org.apache.struts.action.ActionMapping;
+import javax.management.Attribute;
+import javax.management.MBeanServer;
+import javax.management.MBeanServerFactory;
+import javax.management.QueryExp;
+import javax.management.Query;
+import javax.management.ObjectInstance;
+import javax.management.ObjectName;
+import javax.management.JMException;
+import javax.management.MBeanAttributeInfo;
+import javax.management.MBeanOperationInfo;
+import javax.management.MBeanInfo;
+import org.apache.struts.util.MessageResources;
+import org.apache.webapp.admin.ApplicationServlet;
+
+
+/**
+ * <p>Implementation of <strong>Action</strong> that deletes the
+ * specified set of groups.</p>
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 303759 $ $Date: 2005-03-16 18:21:19 -0600 (Wed, 16 Mar 2005) $
+ * @since 4.1
+ */
+
+public final class DeleteGroupsAction extends Action {
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The MBeanServer we will be interacting with.
+     */
+    private MBeanServer mserver = null;
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Process the specified HTTP request, and create the corresponding HTTP
+     * response (or forward to another web component that will create it).
+     * Return an <code>ActionForward</code> instance describing where and how
+     * control should be forwarded, or <code>null</code> if the response has
+     * already been completed.
+     *
+     * @param mapping The ActionMapping used to select this instance
+     * @param actionForm The optional ActionForm bean for this request (if any)
+     * @param request The HTTP request we are processing
+     * @param response The HTTP response we are creating
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception ServletException if a servlet exception occurs
+     */
+    public ActionForward execute(ActionMapping mapping,
+                                 ActionForm form,
+                                 HttpServletRequest request,
+                                 HttpServletResponse response)
+        throws IOException, ServletException {
+
+        // Look up the components we will be using as needed
+        if (mserver == null) {
+            mserver = ((ApplicationServlet) getServlet()).getServer();
+        }
+        MessageResources resources = getResources(request);
+        HttpSession session = request.getSession();
+        Locale locale = getLocale(request);
+
+        // Has this transaction been cancelled?
+        if (isCancelled(request)) {
+            return (mapping.findForward("List Groups Setup"));
+        }
+
+        // Check the transaction token
+        if (!isTokenValid(request)) {
+            response.sendError
+                (HttpServletResponse.SC_BAD_REQUEST,
+                 resources.getMessage(locale, "users.error.token"));
+            return (null);
+        }
+
+        // Perform any extra validation that is required
+        GroupsForm groupsForm = (GroupsForm) form;
+        String databaseName = groupsForm.getDatabaseName();
+        String groups[] = groupsForm.getGroups();
+        if (groups == null) {
+            groups = new String[0];
+        }
+
+        // Perform "Delete Group" transactions as required
+        try {
+
+            ObjectName dname = new ObjectName(databaseName);
+            String signature[] = new String[1];
+            signature[0] = "java.lang.String";
+            Object params[] = new String[1];
+
+            for (int i = 0; i < groups.length; i++) {
+                ObjectName oname = new ObjectName(groups[i]);
+                params[0] = ObjectName.unquote(oname.getKeyProperty("groupname"));
+                mserver.invoke(dname, "removeGroup",
+                               params, signature);
+            }
+
+        } catch (Throwable t) {
+
+            getServlet().log
+                (resources.getMessage(locale, "users.error.invoke",
+                                      "removeGroup"), t);
+            response.sendError
+                (HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
+                 resources.getMessage(locale, "users.error.invoke",
+                                      "removeGroup"));
+            return (null);
+
+        }
+
+        // Save the updated database information
+        try {
+
+            ObjectName dname = new ObjectName(databaseName);
+            mserver.invoke(dname, "save",
+                           new Object[0], new String[0]);
+
+        } catch (Throwable t) {
+
+            getServlet().log
+                (resources.getMessage(locale, "users.error.invoke",
+                                      "save"), t);
+            response.sendError
+                (HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
+                 resources.getMessage(locale, "users.error.invoke",
+                                      "save"));
+            return (null);
+
+        }
+
+        // Proceed to the list groups screen
+        return (mapping.findForward("Groups List Setup"));
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/users/DeleteRolesAction.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/users/DeleteRolesAction.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/users/DeleteRolesAction.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,177 @@
+/*
+ * Copyright 2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.admin.users;
+
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.Locale;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+import org.apache.struts.action.Action;
+import org.apache.struts.action.ActionErrors;
+import org.apache.struts.action.ActionForm;
+import org.apache.struts.action.ActionForward;
+import org.apache.struts.action.ActionMapping;
+import javax.management.Attribute;
+import javax.management.MBeanServer;
+import javax.management.MBeanServerFactory;
+import javax.management.QueryExp;
+import javax.management.Query;
+import javax.management.ObjectInstance;
+import javax.management.ObjectName;
+import javax.management.JMException;
+import javax.management.MBeanAttributeInfo;
+import javax.management.MBeanOperationInfo;
+import javax.management.MBeanInfo;
+import org.apache.struts.util.MessageResources;
+import org.apache.webapp.admin.ApplicationServlet;
+
+
+/**
+ * <p>Implementation of <strong>Action</strong> that deletes the
+ * specified set of roles.</p>
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 303390 $ $Date: 2004-10-18 01:37:56 -0500 (Mon, 18 Oct 2004) $
+ * @since 4.1
+ */
+
+public final class DeleteRolesAction extends Action {
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The MBeanServer we will be interacting with.
+     */
+    private MBeanServer mserver = null;
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Process the specified HTTP request, and create the corresponding HTTP
+     * response (or forward to another web component that will create it).
+     * Return an <code>ActionForward</code> instance describing where and how
+     * control should be forwarded, or <code>null</code> if the response has
+     * already been completed.
+     *
+     * @param mapping The ActionMapping used to select this instance
+     * @param actionForm The optional ActionForm bean for this request (if any)
+     * @param request The HTTP request we are processing
+     * @param response The HTTP response we are creating
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception ServletException if a servlet exception occurs
+     */
+    public ActionForward execute(ActionMapping mapping,
+                                 ActionForm form,
+                                 HttpServletRequest request,
+                                 HttpServletResponse response)
+        throws IOException, ServletException {
+
+        // Look up the components we will be using as needed
+        if (mserver == null) {
+            mserver = ((ApplicationServlet) getServlet()).getServer();
+        }
+        MessageResources resources = getResources(request);
+        HttpSession session = request.getSession();
+        Locale locale = getLocale(request);
+
+        // Has this transaction been cancelled?
+        if (isCancelled(request)) {
+            return (mapping.findForward("List Roles Setup"));
+        }
+
+        // Check the transaction token
+        if (!isTokenValid(request)) {
+            response.sendError
+                (HttpServletResponse.SC_BAD_REQUEST,
+                 resources.getMessage(locale, "users.error.token"));
+            return (null);
+        }
+
+        // Perform any extra validation that is required
+        RolesForm rolesForm = (RolesForm) form;
+        String databaseName = rolesForm.getDatabaseName();
+        String roles[] = rolesForm.getRoles();
+        if (roles == null) {
+            roles = new String[0];
+        }
+
+        // Perform "Delete Role" transactions as required
+        try {
+
+            ObjectName dname = new ObjectName(databaseName);
+            String signature[] = new String[1];
+            signature[0] = "java.lang.String";
+            Object params[] = new String[1];
+
+            for (int i = 0; i < roles.length; i++) {
+                ObjectName oname = new ObjectName(roles[i]);
+                params[0] = oname.getKeyProperty("rolename");
+                mserver.invoke(dname, "removeRole",
+                               params, signature);
+            }
+
+        } catch (Throwable t) {
+
+            getServlet().log
+                (resources.getMessage(locale, "users.error.invoke",
+                                      "removeRole"), t);
+            response.sendError
+                (HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
+                 resources.getMessage(locale, "users.error.invoke",
+                                      "removeRole"));
+            return (null);
+
+        }
+
+        // Save the updated database information
+        try {
+
+            ObjectName dname = new ObjectName(databaseName);
+            mserver.invoke(dname, "save",
+                           new Object[0], new String[0]);
+
+        } catch (Throwable t) {
+
+            getServlet().log
+                (resources.getMessage(locale, "users.error.invoke",
+                                      "save"), t);
+            response.sendError
+                (HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
+                 resources.getMessage(locale, "users.error.invoke",
+                                      "save"));
+            return (null);
+
+        }
+
+        // Proceed to the list roles screen
+        return (mapping.findForward("Roles List Setup"));
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/users/DeleteUsersAction.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/users/DeleteUsersAction.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/users/DeleteUsersAction.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,177 @@
+/*
+ * Copyright 2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.admin.users;
+
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.Locale;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+import org.apache.struts.action.Action;
+import org.apache.struts.action.ActionErrors;
+import org.apache.struts.action.ActionForm;
+import org.apache.struts.action.ActionForward;
+import org.apache.struts.action.ActionMapping;
+import javax.management.Attribute;
+import javax.management.MBeanServer;
+import javax.management.MBeanServerFactory;
+import javax.management.QueryExp;
+import javax.management.Query;
+import javax.management.ObjectInstance;
+import javax.management.ObjectName;
+import javax.management.JMException;
+import javax.management.MBeanAttributeInfo;
+import javax.management.MBeanOperationInfo;
+import javax.management.MBeanInfo;
+import org.apache.struts.util.MessageResources;
+import org.apache.webapp.admin.ApplicationServlet;
+
+
+/**
+ * <p>Implementation of <strong>Action</strong> that deletes the
+ * specified set of users.</p>
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 303759 $ $Date: 2005-03-16 18:21:19 -0600 (Wed, 16 Mar 2005) $
+ * @since 4.1
+ */
+
+public final class DeleteUsersAction extends Action {
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The MBeanServer we will be interacting with.
+     */
+    private MBeanServer mserver = null;
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Process the specified HTTP request, and create the corresponding HTTP
+     * response (or forward to another web component that will create it).
+     * Return an <code>ActionForward</code> instance describing where and how
+     * control should be forwarded, or <code>null</code> if the response has
+     * already been completed.
+     *
+     * @param mapping The ActionMapping used to select this instance
+     * @param actionForm The optional ActionForm bean for this request (if any)
+     * @param request The HTTP request we are processing
+     * @param response The HTTP response we are creating
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception ServletException if a servlet exception occurs
+     */
+    public ActionForward execute(ActionMapping mapping,
+                                 ActionForm form,
+                                 HttpServletRequest request,
+                                 HttpServletResponse response)
+        throws IOException, ServletException {
+
+        // Look up the components we will be using as needed
+        if (mserver == null) {
+            mserver = ((ApplicationServlet) getServlet()).getServer();
+        }
+        MessageResources resources = getResources(request);
+        HttpSession session = request.getSession();
+        Locale locale = getLocale(request);
+
+        // Has this transaction been cancelled?
+        if (isCancelled(request)) {
+            return (mapping.findForward("List Users Setup"));
+        }
+
+        // Check the transaction token
+        if (!isTokenValid(request)) {
+            response.sendError
+                (HttpServletResponse.SC_BAD_REQUEST,
+                 resources.getMessage(locale, "users.error.token"));
+            return (null);
+        }
+
+        // Perform any extra validation that is required
+        UsersForm usersForm = (UsersForm) form;
+        String databaseName = usersForm.getDatabaseName();
+        String users[] = usersForm.getUsers();
+        if (users == null) {
+            users = new String[0];
+        }
+
+        // Perform "Delete User" transactions as required
+        try {
+
+            ObjectName dname = new ObjectName(databaseName);
+            String signature[] = new String[1];
+            signature[0] = "java.lang.String";
+            Object params[] = new String[1];
+
+            for (int i = 0; i < users.length; i++) {
+                ObjectName oname = new ObjectName(users[i]);
+                params[0] = ObjectName.unquote(oname.getKeyProperty("username"));
+                mserver.invoke(dname, "removeUser",
+                               params, signature);
+            }
+
+        } catch (Throwable t) {
+
+            getServlet().log
+                (resources.getMessage(locale, "users.error.invoke",
+                                      "removeUser"), t);
+            response.sendError
+                (HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
+                 resources.getMessage(locale, "users.error.invoke",
+                                      "removeUser"));
+            return (null);
+
+        }
+
+        // Save the updated database information
+        try {
+
+            ObjectName dname = new ObjectName(databaseName);
+            mserver.invoke(dname, "save",
+                           new Object[0], new String[0]);
+
+        } catch (Throwable t) {
+
+            getServlet().log
+                (resources.getMessage(locale, "users.error.invoke",
+                                      "save"), t);
+            response.sendError
+                (HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
+                 resources.getMessage(locale, "users.error.invoke",
+                                      "save"));
+            return (null);
+
+        }
+
+        // Proceed to the list users screen
+        return (mapping.findForward("Users List Setup"));
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/users/GroupForm.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/users/GroupForm.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/users/GroupForm.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,174 @@
+/*
+ * Copyright 2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.admin.users;
+
+import java.net.URLDecoder;
+import javax.management.MBeanServer;
+import javax.servlet.http.HttpServletRequest;
+import org.apache.struts.action.ActionError;
+import org.apache.struts.action.ActionErrors;
+import org.apache.struts.action.ActionForm;
+import org.apache.struts.action.ActionMapping;
+import org.apache.webapp.admin.ApplicationServlet;
+import org.apache.webapp.admin.TomcatTreeBuilder;
+
+/**
+ * Form bean for the individual group page.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 303390 $ $Date: 2004-10-18 01:37:56 -0500 (Mon, 18 Oct 2004) $
+ * @since 4.1
+ */
+
+public final class GroupForm extends BaseForm {
+
+
+    // ----------------------------------------------------- Instance Variables
+
+   /**
+     * The MBeanServer we will be interacting with.
+     */
+    private MBeanServer mserver = null;
+    
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * The description of this group.
+     */
+    private String description = null;
+
+    public String getDescription() {
+        return (this.description);
+    }
+
+    public void setDescription(String description) {
+        this.description = description;
+    }
+
+
+    /**
+     * The groupname of this group.
+     */
+    private String groupname = null;
+
+    public String getGroupname() {
+        return (this.groupname);
+    }
+
+    public void setGroupname(String groupname) {
+        this.groupname = groupname;
+    }
+
+
+    /**
+     * The MBean Names of the roles associated with this group.
+     */
+    private String roles[] = new String[0];
+
+    public String[] getRoles() {
+        return (this.roles);
+    }
+
+    public void setRoles(String roles[]) {
+        if (roles == null) {
+            roles = new String[0];
+        }
+        this.roles = roles;
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Reset all properties to their default values.
+     *
+     * @param mapping The mapping used to select this instance
+     * @param request The servlet request we are processing
+     */
+    public void reset(ActionMapping mapping, HttpServletRequest request) {
+
+        super.reset(mapping, request);
+        description = null;
+        groupname = null;
+        roles = new String[0];
+
+    }
+
+
+    /**
+     * Validate the properties that have been set from this HTTP request,
+     * and return an <code>ActionErrors</code> object that encapsulates any
+     * validation errors that have been found.  If no errors are found, return
+     * <code>null</code> or an <code>ActionErrors</code> object with no
+     * recorded error messages.
+     *
+     * @param mapping The mapping used to select this instance
+     * @param request The servlet request we are processing
+     */
+    public ActionErrors validate(ActionMapping mapping,
+    HttpServletRequest request) {
+        
+        try {
+            // Look up the components we will be using as needed
+            if (mserver == null) {
+                mserver = ((ApplicationServlet) getServlet()).getServer();
+            }
+         
+            // Set up beans containing all possible groups and roles
+            String databaseName =
+                URLDecoder.decode(request.getParameter("databaseName"),TomcatTreeBuilder.URL_ENCODING);
+            request.setAttribute("rolesForm",
+                                 UserUtils.getRolesForm(mserver,
+                                                        databaseName));
+        } catch (Exception e) {
+            // do nothing since the form returns validation error
+        }
+        
+        ActionErrors errors = new ActionErrors();
+
+        String submit = request.getParameter("submit");
+        //if (submit != null) {
+
+            // groupname is a required field
+            if ((groupname == null) || (groupname.length() < 1)) {
+                errors.add("groupname",
+                           new ActionError("users.error.groupname.required"));
+            }
+
+            // Quotes not allowed in groupname
+            if ((groupname != null) && (groupname.indexOf('"') >= 0)) {
+                errors.add("groupname",
+                           new ActionError("users.error.quotes"));
+            }
+
+            // Quotes not allowed in description
+            if ((description != null) && (description.indexOf('"') > 0)) {
+                errors.add("description",
+                           new ActionError("users.error.quotes"));
+            }
+
+        //}
+
+        return (errors);
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/users/GroupsForm.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/users/GroupsForm.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/users/GroupsForm.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.admin.users;
+
+
+import javax.servlet.http.HttpServletRequest;
+import org.apache.struts.action.ActionError;
+import org.apache.struts.action.ActionErrors;
+import org.apache.struts.action.ActionForm;
+import org.apache.struts.action.ActionMapping;
+
+
+/**
+ * Form bean for the delete groups page.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ * @since 4.1
+ */
+
+public final class GroupsForm extends BaseForm {
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * The object names of the specified groups.
+     */
+    private String groups[] = null;
+
+    public String[] getGroups() {
+        return (this.groups);
+    }
+
+    public void setGroups(String groups[]) {
+        this.groups = groups;
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Reset all properties to their default values.
+     *
+     * @param mapping The mapping used to select this instance
+     * @param request The servlet request we are processing
+     */
+    public void reset(ActionMapping mapping, HttpServletRequest request) {
+
+        super.reset(mapping, request);
+        this.groups = null;
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/users/ListGroupsAction.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/users/ListGroupsAction.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/users/ListGroupsAction.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,125 @@
+/*
+ * Copyright 2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.admin.users;
+
+
+import java.io.IOException;
+import java.net.URLDecoder;
+import java.util.Locale;
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+import org.apache.struts.action.Action;
+import org.apache.struts.action.ActionForm;
+import org.apache.struts.action.ActionForward;
+import org.apache.struts.action.ActionMapping;
+import org.apache.struts.util.MessageResources;
+import org.apache.webapp.admin.ApplicationServlet;
+import org.apache.webapp.admin.TomcatTreeBuilder;
+
+/**
+ * <p>Retrieve the set of MBean names for all currently defined groups,
+ * and expose them in a request attribute named "groupsForm".  This action
+ * requires the following request parameters to be set:</p>
+ * <ul>
+ * <li><strong>databaseName</strong> - Object name of the UserDatabase
+ *     MBean from which we should retrieve the groups list.</li>
+ * <li><strong>forward</strong> - Global forward to which we should
+ *     go after stashing the groups list.</li>
+ * </ul>
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 303390 $ $Date: 2004-10-18 01:37:56 -0500 (Mon, 18 Oct 2004) $
+ * @since 4.1
+ */
+
+public class ListGroupsAction extends Action {
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The MBeanServer we will be interacting with.
+     */
+    private MBeanServer mserver = null;
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Process the specified HTTP request, and create the corresponding HTTP
+     * response (or forward to another web component that will create it).
+     * Return an <code>ActionForward</code> instance describing where and how
+     * control should be forwarded, or <code>null</code> if the response has
+     * already been completed.
+     *
+     * @param mapping The ActionMapping used to select this instance
+     * @param actionForm The optional ActionForm bean for this request (if any)
+     * @param request The HTTP request we are processing
+     * @param response The HTTP response we are creating
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception ServletException if a servlet exception occurs
+     */
+    public ActionForward execute(ActionMapping mapping,
+                                 ActionForm form,
+                                 HttpServletRequest request,
+                                 HttpServletResponse response)
+        throws IOException, ServletException {
+
+
+        // Look up the components we will be using as needed
+        if (mserver == null) {
+            mserver = ((ApplicationServlet) getServlet()).getServer();
+        }
+        MessageResources resources = getResources(request);
+        HttpSession session = request.getSession();
+        Locale locale = getLocale(request);
+
+        // Create a form bean containing the requested MBean Names
+        String databaseName =
+            URLDecoder.decode(request.getParameter("databaseName"),TomcatTreeBuilder.URL_ENCODING);
+        GroupsForm groupsForm = null;
+        try {
+            groupsForm = UserUtils.getGroupsForm(mserver, databaseName);
+        } catch (Exception e) {
+            getServlet().log(resources.getMessage
+                             (locale,
+                              "users.error.attribute.get", "groups"), e);
+            response.sendError
+                (HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
+                 resources.getMessage
+                 (locale, "users.error.attribute.get", "groups"));
+            return null;
+        }
+
+        // Stash the results in request scope
+        request.setAttribute("groupsForm", groupsForm);
+        saveToken(request);
+        String forward =
+            URLDecoder.decode(request.getParameter("forward"),TomcatTreeBuilder.URL_ENCODING);
+        return (mapping.findForward(forward));
+
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/users/ListRolesAction.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/users/ListRolesAction.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/users/ListRolesAction.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,126 @@
+/*
+ * Copyright 2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.admin.users;
+
+
+import java.io.IOException;
+import java.net.URLDecoder;
+import java.util.Locale;
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+import org.apache.struts.action.Action;
+import org.apache.struts.action.ActionForm;
+import org.apache.struts.action.ActionForward;
+import org.apache.struts.action.ActionMapping;
+import org.apache.struts.util.MessageResources;
+import org.apache.webapp.admin.ApplicationServlet;
+import org.apache.webapp.admin.TomcatTreeBuilder;
+
+/**
+ * <p>Retrieve the set of MBean names for all currently defined roles,
+ * and expose them in a request attribute named "rolesForm".  This action
+ * requires the following request parameters to be set:</p>
+ * <ul>
+ * <li><strong>databaseName</strong> - Object name of the UserDatabase
+ *     MBean from which we should retrieve the roles list.</li>
+ * <li><strong>forward</strong> - Global forward to which we should
+ *     go after stashing the roles list.</li>
+ * </ul>
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 303390 $ $Date: 2004-10-18 01:37:56 -0500 (Mon, 18 Oct 2004) $
+ * @since 4.1
+ */
+
+public class ListRolesAction extends Action {
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The MBeanServer we will be interacting with.
+     */
+    private MBeanServer mserver = null;
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Process the specified HTTP request, and create the corresponding HTTP
+     * response (or forward to another web component that will create it).
+     * Return an <code>ActionForward</code> instance describing where and how
+     * control should be forwarded, or <code>null</code> if the response has
+     * already been completed.
+     *
+     * @param mapping The ActionMapping used to select this instance
+     * @param actionForm The optional ActionForm bean for this request (if any)
+     * @param request The HTTP request we are processing
+     * @param response The HTTP response we are creating
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception ServletException if a servlet exception occurs
+     */
+    public ActionForward execute(ActionMapping mapping,
+                                 ActionForm form,
+                                 HttpServletRequest request,
+                                 HttpServletResponse response)
+        throws IOException, ServletException {
+
+
+        // Look up the components we will be using as needed
+        if (mserver == null) {
+            mserver = ((ApplicationServlet) getServlet()).getServer();
+        }
+        MessageResources resources = getResources(request);
+        HttpSession session = request.getSession();
+        Locale locale = getLocale(request);
+
+
+        // Create a form bean containing the requested MBean Names
+        String databaseName =
+            URLDecoder.decode(request.getParameter("databaseName"),TomcatTreeBuilder.URL_ENCODING);
+        RolesForm rolesForm = null;
+        try {
+            rolesForm = UserUtils.getRolesForm(mserver, databaseName);
+        } catch (Exception e) {
+            getServlet().log(resources.getMessage
+                             (locale,
+                              "users.error.attribute.get", "roles"), e);
+            response.sendError
+                (HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
+                 resources.getMessage
+                 (locale, "users.error.attribute.get", "roles"));
+            return null;
+        }
+
+        // Stash the results in request scope
+        request.setAttribute("rolesForm", rolesForm);
+        saveToken(request);
+        String forward =
+            URLDecoder.decode(request.getParameter("forward"),TomcatTreeBuilder.URL_ENCODING);
+        return (mapping.findForward(forward));
+
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/users/ListUsersAction.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/users/ListUsersAction.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/users/ListUsersAction.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,126 @@
+/*
+ * Copyright 2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.admin.users;
+
+
+import java.io.IOException;
+import java.net.URLDecoder;
+import java.util.Locale;
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+import org.apache.struts.action.Action;
+import org.apache.struts.action.ActionForm;
+import org.apache.struts.action.ActionForward;
+import org.apache.struts.action.ActionMapping;
+import org.apache.struts.util.MessageResources;
+import org.apache.webapp.admin.ApplicationServlet;
+import org.apache.webapp.admin.TomcatTreeBuilder;
+
+/**
+ * <p>Retrieve the set of MBean names for all currently defined users,
+ * and expose them in a request attribute named "usersForm".  This action
+ * requires the following request parameters to be set:</p>
+ * <ul>
+ * <li><strong>databaseName</strong> - Object name of the UserDatabase
+ *     MBean from which we should retrieve the users list.</li>
+ * <li><strong>forward</strong> - Global forward to which we should
+ *     go after stashing the users list.</li>
+ * </ul>
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 303390 $ $Date: 2004-10-18 01:37:56 -0500 (Mon, 18 Oct 2004) $
+ * @since 4.1
+ */
+
+public class ListUsersAction extends Action {
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The MBeanServer we will be interacting with.
+     */
+    private MBeanServer mserver = null;
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Process the specified HTTP request, and create the corresponding HTTP
+     * response (or forward to another web component that will create it).
+     * Return an <code>ActionForward</code> instance describing where and how
+     * control should be forwarded, or <code>null</code> if the response has
+     * already been completed.
+     *
+     * @param mapping The ActionMapping used to select this instance
+     * @param actionForm The optional ActionForm bean for this request (if any)
+     * @param request The HTTP request we are processing
+     * @param response The HTTP response we are creating
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception ServletException if a servlet exception occurs
+     */
+    public ActionForward execute(ActionMapping mapping,
+                                 ActionForm form,
+                                 HttpServletRequest request,
+                                 HttpServletResponse response)
+        throws IOException, ServletException {
+
+
+        // Look up the components we will be using as needed
+        if (mserver == null) {
+            mserver = ((ApplicationServlet) getServlet()).getServer();
+        }
+        MessageResources resources = getResources(request);
+        HttpSession session = request.getSession();
+        Locale locale = getLocale(request);
+
+
+        // Create a form bean containing the requested MBean Names
+        String databaseName =
+            URLDecoder.decode(request.getParameter("databaseName"),TomcatTreeBuilder.URL_ENCODING);
+        UsersForm usersForm = null;
+        try {
+            usersForm = UserUtils.getUsersForm(mserver, databaseName);
+        } catch (Exception e) {
+            getServlet().log(resources.getMessage
+                             (locale,
+                              "users.error.attribute.get", "users"), e);
+            response.sendError
+                (HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
+                 resources.getMessage
+                 (locale, "users.error.attribute.get", "users"));
+            return null;
+        }
+
+        // Stash the results in request scope
+        request.setAttribute("usersForm", usersForm);
+        saveToken(request);
+        String forward =
+            URLDecoder.decode(request.getParameter("forward"),TomcatTreeBuilder.URL_ENCODING);
+        return (mapping.findForward(forward));
+
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/users/RoleForm.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/users/RoleForm.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/users/RoleForm.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,133 @@
+/*
+ * Copyright 2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.admin.users;
+
+
+import javax.servlet.http.HttpServletRequest;
+import org.apache.struts.action.ActionError;
+import org.apache.struts.action.ActionErrors;
+import org.apache.struts.action.ActionForm;
+import org.apache.struts.action.ActionMapping;
+
+
+/**
+ * Form bean for the individual role page.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ * @since 4.1
+ */
+
+public final class RoleForm extends BaseForm {
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * The description of this role.
+     */
+    private String description = null;
+
+    public String getDescription() {
+        return (this.description);
+    }
+
+    public void setDescription(String description) {
+        this.description = description;
+    }
+
+
+    /**
+     * The rolename of this role.
+     */
+    private String rolename = null;
+
+    public String getRolename() {
+        return (this.rolename);
+    }
+
+    public void setRolename(String rolename) {
+        this.rolename = rolename;
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Reset all properties to their default values.
+     *
+     * @param mapping The mapping used to select this instance
+     * @param request The servlet request we are processing
+     */
+    public void reset(ActionMapping mapping, HttpServletRequest request) {
+
+        super.reset(mapping, request);
+        description = null;
+        rolename = null;
+
+    }
+
+
+    /**
+     * Validate the properties that have been set from this HTTP request,
+     * and return an <code>ActionErrors</code> object that encapsulates any
+     * validation errors that have been found.  If no errors are found, return
+     * <code>null</code> or an <code>ActionErrors</code> object with no
+     * recorded error messages.
+     *
+     * @param mapping The mapping used to select this instance
+     * @param request The servlet request we are processing
+     */
+    public ActionErrors validate(ActionMapping mapping,
+    HttpServletRequest request) {
+
+        ActionErrors errors = new ActionErrors();
+
+        String submit = request.getParameter("submit");
+        //if (submit != null) {
+
+            // rolename is a required field
+            if ((rolename == null) || (rolename.length() < 1)) {
+                errors.add("rolename",
+                           new ActionError("users.error.rolename.required"));
+            }
+
+            // Quotes not allowed in rolename
+            if ((rolename != null) && (rolename.indexOf('"') >= 0)) {
+                errors.add("rolename",
+                           new ActionError("users.error.quotes"));
+            }
+
+            // Quotes not allowed in description
+            if ((description != null) && (description.indexOf('"') > 0)) {
+                errors.add("description",
+                           new ActionError("users.error.quotes"));
+            }
+
+        //}
+
+        return (errors);
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/users/RolesForm.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/users/RolesForm.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/users/RolesForm.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.admin.users;
+
+
+import javax.servlet.http.HttpServletRequest;
+import org.apache.struts.action.ActionError;
+import org.apache.struts.action.ActionErrors;
+import org.apache.struts.action.ActionForm;
+import org.apache.struts.action.ActionMapping;
+
+
+/**
+ * Form bean for the delete roles page.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ * @since 4.1
+ */
+
+public final class RolesForm extends BaseForm {
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * The object names of the specified roles.
+     */
+    private String roles[] = null;
+
+    public String[] getRoles() {
+        return (this.roles);
+    }
+
+    public void setRoles(String roles[]) {
+        this.roles = roles;
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Reset all properties to their default values.
+     *
+     * @param mapping The mapping used to select this instance
+     * @param request The servlet request we are processing
+     */
+    public void reset(ActionMapping mapping, HttpServletRequest request) {
+
+        super.reset(mapping, request);
+        this.roles = null;
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/users/SaveGroupAction.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/users/SaveGroupAction.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/users/SaveGroupAction.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,250 @@
+/*
+ * Copyright 2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.admin.users;
+
+
+import java.io.IOException;
+import java.net.URLDecoder;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.Locale;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+import org.apache.struts.action.Action;
+import org.apache.struts.action.ActionErrors;
+import org.apache.struts.action.ActionForm;
+import org.apache.struts.action.ActionForward;
+import org.apache.struts.action.ActionMapping;
+import javax.management.Attribute;
+import javax.management.MBeanServer;
+import javax.management.MBeanServerFactory;
+import javax.management.QueryExp;
+import javax.management.Query;
+import javax.management.ObjectInstance;
+import javax.management.ObjectName;
+import javax.management.JMException;
+import javax.management.MBeanAttributeInfo;
+import javax.management.MBeanOperationInfo;
+import javax.management.MBeanInfo;
+import org.apache.struts.util.MessageResources;
+import org.apache.webapp.admin.ApplicationServlet;
+import org.apache.webapp.admin.TomcatTreeBuilder;
+
+/**
+ * <p>Implementation of <strong>Action</strong> that saves a new or
+ * updated Group back to the underlying database.</p>
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 303390 $ $Date: 2004-10-18 01:37:56 -0500 (Mon, 18 Oct 2004) $
+ * @since 4.1
+ */
+
+public final class SaveGroupAction extends Action {
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The MBeanServer we will be interacting with.
+     */
+    private MBeanServer mserver = null;
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Process the specified HTTP request, and create the corresponding HTTP
+     * response (or forward to another web component that will create it).
+     * Return an <code>ActionForward</code> instance describing where and how
+     * control should be forwarded, or <code>null</code> if the response has
+     * already been completed.
+     *
+     * @param mapping The ActionMapping used to select this instance
+     * @param actionForm The optional ActionForm bean for this request (if any)
+     * @param request The HTTP request we are processing
+     * @param response The HTTP response we are creating
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception ServletException if a servlet exception occurs
+     */
+    public ActionForward execute(ActionMapping mapping,
+                                 ActionForm form,
+                                 HttpServletRequest request,
+                                 HttpServletResponse response)
+        throws IOException, ServletException {
+
+        // Look up the components we will be using as needed
+        if (mserver == null) {
+            mserver = ((ApplicationServlet) getServlet()).getServer();
+        }
+        MessageResources resources = getResources(request);
+        HttpSession session = request.getSession();
+        Locale locale = getLocale(request);
+
+        // Has this transaction been cancelled?
+        if (isCancelled(request)) {
+            return (mapping.findForward("List Roles Setup"));
+        }
+
+        // Check the transaction token
+        if (!isTokenValid(request)) {
+            response.sendError
+                (HttpServletResponse.SC_BAD_REQUEST,
+                 resources.getMessage(locale, "users.error.token"));
+            return (null);
+        }
+
+        // Perform any extra validation that is required
+        GroupForm groupForm = (GroupForm) form;
+        String databaseName =
+            URLDecoder.decode(groupForm.getDatabaseName(),TomcatTreeBuilder.URL_ENCODING);
+        String objectName = groupForm.getObjectName();
+
+        // Perform an "Add Group" transaction
+        if (objectName == null) {
+
+            String signature[] = new String[2];
+            signature[0] = "java.lang.String";
+            signature[1] = "java.lang.String";
+
+            Object params[] = new Object[2];
+            params[0] = groupForm.getGroupname();
+            params[1] = groupForm.getDescription();
+
+            ObjectName oname = null;
+
+            try {
+
+                // Construct the MBean Name for our UserDatabase
+                oname = new ObjectName(databaseName);
+
+                // Create the new object and associated MBean
+                objectName = (String) mserver.invoke(oname, "createGroup",
+                                                     params, signature);
+
+            } catch (Exception e) {
+
+                getServlet().log
+                    (resources.getMessage(locale, "users.error.invoke",
+                                          "createGroup"), e);
+                response.sendError
+                    (HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
+                     resources.getMessage(locale, "users.error.invoke",
+                                          "createGroup"));
+                return (null);
+            }
+
+        }
+
+        // Perform an "Update Group" transaction
+        else {
+
+            ObjectName oname = null;
+            String attribute = null;
+
+            try {
+
+                // Construct an object name for this object
+                oname = new ObjectName(objectName);
+
+                // Update the specified role
+                attribute = "description";
+                mserver.setAttribute
+                    (oname,
+                     new Attribute(attribute, groupForm.getDescription()));
+
+            } catch (Exception e) {
+
+                getServlet().log
+                    (resources.getMessage(locale, "users.error.set.attribute",
+                                          attribute), e);
+                response.sendError
+                    (HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
+                     resources.getMessage(locale, "users.error.set.attribute",
+                                          attribute));
+                return (null);
+
+            }
+
+        }
+
+
+        // Reset the roles associated with this group
+        try {
+
+            ObjectName oname = new ObjectName(objectName);
+            mserver.invoke(oname, "removeRoles",
+                           new Object[0], new String[0]);
+            String roles[] = groupForm.getRoles();
+            if (roles == null) {
+                roles = new String[0];
+            }
+            String addsig[] = new String[1];
+            addsig[0] = "java.lang.String";
+            Object addpar[] = new Object[1];
+            for (int i = 0; i < roles.length; i++) {
+                addpar[0] =
+                    (new ObjectName(roles[i])).getKeyProperty("rolename");
+                mserver.invoke(oname, "addRole",
+                               addpar, addsig);
+            }
+
+        } catch (Exception e) {
+
+            getServlet().log
+                (resources.getMessage(locale, "users.error.invoke",
+                                      "addRole"), e);
+            response.sendError
+                (HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
+                 resources.getMessage(locale, "users.error.invoke",
+                                      "addRole"));
+            return (null);
+
+        }
+
+        // Save the updated database information
+        try {
+
+            ObjectName dname = new ObjectName(databaseName);
+            mserver.invoke(dname, "save",
+                           new Object[0], new String[0]);
+
+        } catch (Exception e) {
+
+            getServlet().log
+                (resources.getMessage(locale, "users.error.invoke",
+                                      "save"), e);
+            response.sendError
+                (HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
+                 resources.getMessage(locale, "users.error.invoke",
+                                      "save"));
+            return (null);
+
+        }
+
+        // Proceed to the list roles screen
+        return (mapping.findForward("Groups List Setup"));
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/users/SaveRoleAction.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/users/SaveRoleAction.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/users/SaveRoleAction.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,216 @@
+/*
+ * Copyright 2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.admin.users;
+
+
+import java.io.IOException;
+import java.net.URLDecoder;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.Locale;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+import org.apache.struts.action.Action;
+import org.apache.struts.action.ActionErrors;
+import org.apache.struts.action.ActionForm;
+import org.apache.struts.action.ActionForward;
+import org.apache.struts.action.ActionMapping;
+import javax.management.Attribute;
+import javax.management.MBeanServer;
+import javax.management.MBeanServerFactory;
+import javax.management.QueryExp;
+import javax.management.Query;
+import javax.management.ObjectInstance;
+import javax.management.ObjectName;
+import javax.management.JMException;
+import javax.management.MBeanAttributeInfo;
+import javax.management.MBeanOperationInfo;
+import javax.management.MBeanInfo;
+import org.apache.struts.util.MessageResources;
+import org.apache.webapp.admin.ApplicationServlet;
+import org.apache.webapp.admin.TomcatTreeBuilder;
+
+/**
+ * <p>Implementation of <strong>Action</strong> that saves a new or
+ * updated Role back to the underlying database.</p>
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 303390 $ $Date: 2004-10-18 01:37:56 -0500 (Mon, 18 Oct 2004) $
+ * @since 4.1
+ */
+
+public final class SaveRoleAction extends Action {
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The MBeanServer we will be interacting with.
+     */
+    private MBeanServer mserver = null;
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Process the specified HTTP request, and create the corresponding HTTP
+     * response (or forward to another web component that will create it).
+     * Return an <code>ActionForward</code> instance describing where and how
+     * control should be forwarded, or <code>null</code> if the response has
+     * already been completed.
+     *
+     * @param mapping The ActionMapping used to select this instance
+     * @param actionForm The optional ActionForm bean for this request (if any)
+     * @param request The HTTP request we are processing
+     * @param response The HTTP response we are creating
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception ServletException if a servlet exception occurs
+     */
+    public ActionForward execute(ActionMapping mapping,
+                                 ActionForm form,
+                                 HttpServletRequest request,
+                                 HttpServletResponse response)
+        throws IOException, ServletException {
+
+        // Look up the components we will be using as needed
+        if (mserver == null) {
+            mserver = ((ApplicationServlet) getServlet()).getServer();
+        }
+        MessageResources resources = getResources(request);
+        HttpSession session = request.getSession();
+        Locale locale = getLocale(request);
+
+        // Has this transaction been cancelled?
+        if (isCancelled(request)) {
+            return (mapping.findForward("List Roles Setup"));
+        }
+
+        // Check the transaction token
+        if (!isTokenValid(request)) {
+            response.sendError
+                (HttpServletResponse.SC_BAD_REQUEST,
+                 resources.getMessage(locale, "users.error.token"));
+            return (null);
+        }
+
+        // Perform any extra validation that is required
+        RoleForm roleForm = (RoleForm) form;
+        String databaseName =
+            URLDecoder.decode(roleForm.getDatabaseName(),TomcatTreeBuilder.URL_ENCODING);
+        String objectName = roleForm.getObjectName();
+
+        // Perform an "Add Role" transaction
+        if (objectName == null) {
+
+            String signature[] = new String[2];
+            signature[0] = "java.lang.String";
+            signature[1] = "java.lang.String";
+
+            Object params[] = new Object[2];
+            params[0] = roleForm.getRolename();
+            params[1] = roleForm.getDescription();
+
+            ObjectName oname = null;
+
+            try {
+
+                // Construct the MBean Name for our UserDatabase
+                oname = new ObjectName(databaseName);
+
+                // Create the new object and associated MBean
+                mserver.invoke(oname, "createRole",
+                               params, signature);
+
+            } catch (Exception e) {
+
+                getServlet().log
+                    (resources.getMessage(locale, "users.error.invoke",
+                                          "createRole"), e);
+                response.sendError
+                    (HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
+                     resources.getMessage(locale, "users.error.invoke",
+                                          "createRole"));
+                return (null);
+            }
+
+        }
+
+        // Perform an "Update Role" transaction
+        else {
+
+            ObjectName oname = null;
+            String attribute = null;
+
+            try {
+
+                // Construct an object name for this object
+                oname = new ObjectName(objectName);
+
+                // Update the specified role
+                attribute = "description";
+                mserver.setAttribute
+                    (oname,
+                     new Attribute(attribute, roleForm.getDescription()));
+
+            } catch (Exception e) {
+
+                getServlet().log
+                    (resources.getMessage(locale, "users.error.set.attribute",
+                                          attribute), e);
+                response.sendError
+                    (HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
+                     resources.getMessage(locale, "users.error.set.attribute",
+                                          attribute));
+                return (null);
+
+            }
+
+        }
+
+        // Save the updated database information
+        try {
+
+            ObjectName dname = new ObjectName(databaseName);
+            mserver.invoke(dname, "save",
+                           new Object[0], new String[0]);
+
+        } catch (Exception e) {
+
+            getServlet().log
+                (resources.getMessage(locale, "users.error.invoke",
+                                      "save"), e);
+            response.sendError
+                (HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
+                 resources.getMessage(locale, "users.error.invoke",
+                                      "save"));
+            return (null);
+
+        }
+
+        // Proceed to the list roles screen
+        return (mapping.findForward("Roles List Setup"));
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/users/SaveUserAction.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/users/SaveUserAction.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/users/SaveUserAction.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,288 @@
+/*
+ * Copyright 2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.admin.users;
+
+
+import java.io.IOException;
+import java.net.URLDecoder;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.Locale;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+import org.apache.struts.action.Action;
+import org.apache.struts.action.ActionErrors;
+import org.apache.struts.action.ActionForm;
+import org.apache.struts.action.ActionForward;
+import org.apache.struts.action.ActionMapping;
+import javax.management.Attribute;
+import javax.management.MBeanServer;
+import javax.management.MBeanServerFactory;
+import javax.management.QueryExp;
+import javax.management.Query;
+import javax.management.ObjectInstance;
+import javax.management.ObjectName;
+import javax.management.JMException;
+import javax.management.MBeanAttributeInfo;
+import javax.management.MBeanOperationInfo;
+import javax.management.MBeanInfo;
+import org.apache.struts.util.MessageResources;
+import org.apache.webapp.admin.ApplicationServlet;
+import org.apache.webapp.admin.TomcatTreeBuilder;
+
+/**
+ * <p>Implementation of <strong>Action</strong> that saves a new or
+ * updated User back to the underlying database.</p>
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 303390 $ $Date: 2004-10-18 01:37:56 -0500 (Mon, 18 Oct 2004) $
+ * @since 4.1
+ */
+
+public final class SaveUserAction extends Action {
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The MBeanServer we will be interacting with.
+     */
+    private MBeanServer mserver = null;
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Process the specified HTTP request, and create the corresponding HTTP
+     * response (or forward to another web component that will create it).
+     * Return an <code>ActionForward</code> instance describing where and how
+     * control should be forwarded, or <code>null</code> if the response has
+     * already been completed.
+     *
+     * @param mapping The ActionMapping used to select this instance
+     * @param actionForm The optional ActionForm bean for this request (if any)
+     * @param request The HTTP request we are processing
+     * @param response The HTTP response we are creating
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception ServletException if a servlet exception occurs
+     */
+    public ActionForward execute(ActionMapping mapping,
+                                 ActionForm form,
+                                 HttpServletRequest request,
+                                 HttpServletResponse response)
+        throws IOException, ServletException {
+
+        // Look up the components we will be using as needed
+        if (mserver == null) {
+            mserver = ((ApplicationServlet) getServlet()).getServer();
+        }
+        MessageResources resources = getResources(request);
+        HttpSession session = request.getSession();
+        Locale locale = getLocale(request);
+
+        // Has this transaction been cancelled?
+        if (isCancelled(request)) {
+            return (mapping.findForward("List Users Setup"));
+        }
+
+        // Check the transaction token
+        if (!isTokenValid(request)) {
+            response.sendError
+                (HttpServletResponse.SC_BAD_REQUEST,
+                 resources.getMessage(locale, "users.error.token"));
+            return (null);
+        }
+
+        // Perform any extra validation that is required
+        UserForm userForm = (UserForm) form;
+        String databaseName =
+            URLDecoder.decode(userForm.getDatabaseName(),TomcatTreeBuilder.URL_ENCODING);
+        String objectName = userForm.getObjectName();
+
+        // Perform an "Add User" transaction
+        if (objectName == null) {
+
+            String signature[] = new String[3];
+            signature[0] = "java.lang.String";
+            signature[1] = "java.lang.String";
+            signature[2] = "java.lang.String";
+
+            Object params[] = new Object[3];
+            params[0] = userForm.getUsername();
+            params[1] = userForm.getPassword();
+            params[2] = userForm.getFullName();
+
+            ObjectName oname = null;
+
+            try {
+
+                // Construct the MBean Name for our UserDatabase
+                oname = new ObjectName(databaseName);
+
+                // Create the new object and associated MBean
+                objectName = (String) mserver.invoke(oname, "createUser",
+                                                     params, signature);
+
+            } catch (Exception e) {
+
+                getServlet().log
+                    (resources.getMessage(locale, "users.error.invoke",
+                                          "createUser"), e);
+                response.sendError
+                    (HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
+                     resources.getMessage(locale, "users.error.invoke",
+                                          "createUser"));
+                return (null);
+            }
+
+        }
+
+        // Perform an "Update User" transaction
+        else {
+
+            ObjectName oname = null;
+            String attribute = null;
+
+            try {
+
+                // Construct an object name for this object
+                oname = new ObjectName(objectName);
+
+                // Update the specified user
+                attribute = "fullName";
+                mserver.setAttribute
+                    (oname,
+                     new Attribute(attribute, userForm.getFullName()));
+                attribute = "password";
+                mserver.setAttribute
+                    (oname,
+                     new Attribute(attribute, userForm.getPassword()));
+
+            } catch (Exception e) {
+
+                getServlet().log
+                    (resources.getMessage(locale, "users.error.set.attribute",
+                                          attribute), e);
+                response.sendError
+                    (HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
+                     resources.getMessage(locale, "users.error.set.attribute",
+                                          attribute));
+                return (null);
+
+            }
+
+        }
+
+        // Reset the groups this user is a member of
+        try {
+
+            ObjectName oname = new ObjectName(objectName);
+            mserver.invoke(oname, "removeGroups",
+                           new Object[0], new String[0]);
+            String groups[] = userForm.getGroups();
+            if (groups == null) {
+                groups = new String[0];
+            }
+            String addsig[] = new String[1];
+            addsig[0] = "java.lang.String";
+            Object addpar[] = new Object[1];
+            for (int i = 0; i < groups.length; i++) {
+                addpar[0] =
+                    (new ObjectName(groups[i])).getKeyProperty("groupname");
+                mserver.invoke(oname, "addGroup",
+                               addpar, addsig);
+            }
+
+        } catch (Exception e) {
+
+            getServlet().log
+                (resources.getMessage(locale, "users.error.invoke",
+                                      "addGroup"), e);
+            response.sendError
+                (HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
+                 resources.getMessage(locale, "users.error.invoke",
+                                      "addGroup"));
+            return (null);
+
+        }
+
+        // Reset the roles associated with this user
+        try {
+
+            ObjectName oname = new ObjectName(objectName);
+            mserver.invoke(oname, "removeRoles",
+                           new Object[0], new String[0]);
+            String roles[] = userForm.getRoles();
+            if (roles == null) {
+                roles = new String[0];
+            }
+            String addsig[] = new String[1];
+            addsig[0] = "java.lang.String";
+            Object addpar[] = new Object[1];
+            for (int i = 0; i < roles.length; i++) {
+                addpar[0] =
+                    (new ObjectName(roles[i])).getKeyProperty("rolename");
+                mserver.invoke(oname, "addRole",
+                               addpar, addsig);
+            }
+
+        } catch (Exception e) {
+
+            getServlet().log
+                (resources.getMessage(locale, "users.error.invoke",
+                                      "addRole"), e);
+            response.sendError
+                (HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
+                 resources.getMessage(locale, "users.error.invoke",
+                                      "addRole"));
+            return (null);
+
+        }
+
+        // Save the updated database information
+        try {
+
+            ObjectName dname = new ObjectName(databaseName);
+            mserver.invoke(dname, "save",
+                           new Object[0], new String[0]);
+
+        } catch (Exception e) {
+
+            getServlet().log
+                (resources.getMessage(locale, "users.error.invoke",
+                                      "save"), e);
+            response.sendError
+                (HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
+                 resources.getMessage(locale, "users.error.invoke",
+                                      "save"));
+            return (null);
+
+        }
+
+        // Proceed to the list roles screen
+        return (mapping.findForward("Users List Setup"));
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/users/SetUpGroupAction.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/users/SetUpGroupAction.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/users/SetUpGroupAction.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,167 @@
+/*
+ * Copyright 2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.admin.users;
+
+
+import java.io.IOException;
+import java.net.URLDecoder;
+import java.util.Iterator;
+import java.util.Locale;
+import javax.management.Attribute;
+import javax.management.MBeanServer;
+import javax.management.MBeanServerFactory;
+import javax.management.QueryExp;
+import javax.management.Query;
+import javax.management.ObjectInstance;
+import javax.management.ObjectName;
+import javax.management.JMException;
+import javax.management.MBeanAttributeInfo;
+import javax.management.MBeanOperationInfo;
+import javax.management.MBeanInfo;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+import org.apache.struts.action.Action;
+import org.apache.struts.action.ActionErrors;
+import org.apache.struts.action.ActionForm;
+import org.apache.struts.action.ActionForward;
+import org.apache.struts.action.ActionMapping;
+import org.apache.struts.util.MessageResources;
+import org.apache.webapp.admin.ApplicationServlet;
+import org.apache.webapp.admin.TomcatTreeBuilder;
+
+
+/**
+ * <p>Implementation of <strong>Action</strong> that sets up and stashes
+ * a <code>GroupForm</code> bean in request scope.  The form bean will have
+ * a null <code>objectName</code> property if this form represents a group
+ * being added, or a non-null value for an existing group.</p>
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 303390 $ $Date: 2004-10-18 01:37:56 -0500 (Mon, 18 Oct 2004) $
+ * @since 4.1
+ */
+
+public final class SetUpGroupAction extends Action {
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The MBeanServer we will be interacting with.
+     */
+    private MBeanServer mserver = null;
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Process the specified HTTP request, and create the corresponding HTTP
+     * response (or forward to another web component that will create it).
+     * Return an <code>ActionForward</code> instance describing where and how
+     * control should be forwarded, or <code>null</code> if the response has
+     * already been completed.
+     *
+     * @param mapping The ActionMapping used to select this instance
+     * @param actionForm The optional ActionForm bean for this request (if any)
+     * @param request The HTTP request we are processing
+     * @param response The HTTP response we are creating
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception ServletException if a servlet exception occurs
+     */
+    public ActionForward execute(ActionMapping mapping,
+                                 ActionForm form,
+                                 HttpServletRequest request,
+                                 HttpServletResponse response)
+        throws IOException, ServletException {
+
+        // Look up the components we will be using as needed
+        if (mserver == null) {
+            mserver = ((ApplicationServlet) getServlet()).getServer();
+        }
+        MessageResources resources = getResources(request);
+        HttpSession session = request.getSession();
+        Locale locale = getLocale(request);
+
+        // Set up a bean containing all possible roles
+        String databaseName =
+            URLDecoder.decode(request.getParameter("databaseName"),TomcatTreeBuilder.URL_ENCODING);
+        try {
+            request.setAttribute("rolesForm",
+                                 UserUtils.getRolesForm(mserver,
+                                                        databaseName));
+        } catch (Exception e) {
+            getServlet().log
+                (resources.getMessage(locale,
+                                      "users.error.attribute.get",
+                                      "roles"), e);
+            response.sendError
+                (HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
+                 resources.getMessage
+                 (locale, "users.error.attribute.get", "roles"));
+            return (null);
+        }
+
+        // Set up the form bean based on the creating or editing state
+        String objectName = request.getParameter("objectName");
+        GroupForm groupForm = new GroupForm();
+        if (objectName == null) {
+            groupForm.setNodeLabel
+                (resources.getMessage(locale, "users.group.newGroup"));
+            groupForm.setObjectName(null);
+        } else {
+            groupForm.setNodeLabel
+                (resources.getMessage(locale, "users.group.oldGroup"));
+            groupForm.setObjectName(objectName);
+            String attribute = null;
+            try {
+                ObjectName oname = new ObjectName(objectName);
+                attribute = "groupname";
+                groupForm.setGroupname
+                    ((String) mserver.getAttribute(oname, attribute));
+                attribute = "description";
+                groupForm.setDescription
+                    ((String) mserver.getAttribute(oname, attribute));
+                attribute = "roles";
+                groupForm.setRoles
+                    ((String[]) mserver.getAttribute(oname, attribute));
+            } catch (Exception e) {
+                getServlet().log
+                    (resources.getMessage(locale,
+                        "users.error.attribute.get", attribute), e);
+                response.sendError
+                    (HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
+                     resources.getMessage
+                         (locale, "users.error.attribute.get", attribute));
+                return (null);
+            }
+        }
+        groupForm.setDatabaseName(databaseName);
+
+        // Stash the form bean and forward to the display page
+        saveToken(request);
+        request.setAttribute("groupForm", groupForm);
+        return (mapping.findForward("Group"));
+
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/users/SetUpRoleAction.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/users/SetUpRoleAction.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/users/SetUpRoleAction.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,146 @@
+/*
+ * Copyright 2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.admin.users;
+
+
+import java.io.IOException;
+import java.net.URLDecoder;
+import java.util.Iterator;
+import java.util.Locale;
+import javax.management.Attribute;
+import javax.management.MBeanServer;
+import javax.management.MBeanServerFactory;
+import javax.management.QueryExp;
+import javax.management.Query;
+import javax.management.ObjectInstance;
+import javax.management.ObjectName;
+import javax.management.JMException;
+import javax.management.MBeanAttributeInfo;
+import javax.management.MBeanOperationInfo;
+import javax.management.MBeanInfo;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+import org.apache.struts.action.Action;
+import org.apache.struts.action.ActionErrors;
+import org.apache.struts.action.ActionForm;
+import org.apache.struts.action.ActionForward;
+import org.apache.struts.action.ActionMapping;
+import org.apache.struts.util.MessageResources;
+import org.apache.webapp.admin.ApplicationServlet;
+import org.apache.webapp.admin.TomcatTreeBuilder;
+
+/**
+ * <p>Implementation of <strong>Action</strong> that sets up and stashes
+ * a <code>RoleForm</code> bean in request scope.  The form bean will have
+ * a null <code>objectName</code> property if this form represents a role
+ * being added, or a non-null value for an existing role.</p>
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 303390 $ $Date: 2004-10-18 01:37:56 -0500 (Mon, 18 Oct 2004) $
+ * @since 4.1
+ */
+
+public final class SetUpRoleAction extends Action {
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The MBeanServer we will be interacting with.
+     */
+    private MBeanServer mserver = null;
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Process the specified HTTP request, and create the corresponding HTTP
+     * response (or forward to another web component that will create it).
+     * Return an <code>ActionForward</code> instance describing where and how
+     * control should be forwarded, or <code>null</code> if the response has
+     * already been completed.
+     *
+     * @param mapping The ActionMapping used to select this instance
+     * @param actionForm The optional ActionForm bean for this request (if any)
+     * @param request The HTTP request we are processing
+     * @param response The HTTP response we are creating
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception ServletException if a servlet exception occurs
+     */
+    public ActionForward execute(ActionMapping mapping,
+                                 ActionForm form,
+                                 HttpServletRequest request,
+                                 HttpServletResponse response)
+        throws IOException, ServletException {
+
+        // Look up the components we will be using as needed
+        if (mserver == null) {
+            mserver = ((ApplicationServlet) getServlet()).getServer();
+        }
+        MessageResources resources = getResources(request);
+        HttpSession session = request.getSession();
+        Locale locale = getLocale(request);
+        String databaseName =
+            URLDecoder.decode(request.getParameter("databaseName"),TomcatTreeBuilder.URL_ENCODING);
+
+        // Set up the form bean based on the creating or editing state
+        String objectName = request.getParameter("objectName");
+        RoleForm roleForm = new RoleForm();
+        if (objectName == null) {
+            roleForm.setNodeLabel
+                (resources.getMessage(locale, "users.role.newRole"));
+            roleForm.setObjectName(null);
+        } else {
+            roleForm.setNodeLabel
+                (resources.getMessage(locale, "users.role.oldRole"));
+            roleForm.setObjectName(objectName);
+            String attribute = null;
+            try {
+                ObjectName oname = new ObjectName(objectName);
+                attribute = "rolename";
+                roleForm.setRolename
+                    ((String) mserver.getAttribute(oname, attribute));
+                attribute = "description";
+                roleForm.setDescription
+                    ((String) mserver.getAttribute(oname, attribute));
+            } catch (Exception e) {
+                getServlet().log
+                    (resources.getMessage(locale,
+                        "users.error.attribute.get", attribute), e);
+                response.sendError
+                    (HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
+                     resources.getMessage
+                         (locale, "users.error.attribute.get", attribute));
+                return (null);
+            }
+        }
+        roleForm.setDatabaseName(databaseName);
+
+        // Stash the form bean and forward to the display page
+        saveToken(request);
+        request.setAttribute("roleForm", roleForm);
+        return (mapping.findForward("Role"));
+
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/users/SetUpUserAction.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/users/SetUpUserAction.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/users/SetUpUserAction.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,187 @@
+/*
+ * Copyright 2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.admin.users;
+
+
+import java.io.IOException;
+import java.net.URLDecoder;
+import java.util.Iterator;
+import java.util.Locale;
+import javax.management.Attribute;
+import javax.management.MBeanServer;
+import javax.management.MBeanServerFactory;
+import javax.management.QueryExp;
+import javax.management.Query;
+import javax.management.ObjectInstance;
+import javax.management.ObjectName;
+import javax.management.JMException;
+import javax.management.MBeanAttributeInfo;
+import javax.management.MBeanOperationInfo;
+import javax.management.MBeanInfo;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+import org.apache.struts.action.Action;
+import org.apache.struts.action.ActionErrors;
+import org.apache.struts.action.ActionForm;
+import org.apache.struts.action.ActionForward;
+import org.apache.struts.action.ActionMapping;
+import org.apache.struts.util.MessageResources;
+import org.apache.webapp.admin.ApplicationServlet;
+import org.apache.webapp.admin.TomcatTreeBuilder;
+
+/**
+ * <p>Implementation of <strong>Action</strong> that sets up and stashes
+ * a <code>UserForm</code> bean in request scope.  The form bean will have
+ * a null <code>objectName</code> property if this form represents a user
+ * being added, or a non-null value for an existing user.</p>
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 303390 $ $Date: 2004-10-18 01:37:56 -0500 (Mon, 18 Oct 2004) $
+ * @since 4.1
+ */
+
+public final class SetUpUserAction extends Action {
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The MBeanServer we will be interacting with.
+     */
+    private MBeanServer mserver = null;
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Process the specified HTTP request, and create the corresponding HTTP
+     * response (or forward to another web component that will create it).
+     * Return an <code>ActionForward</code> instance describing where and how
+     * control should be forwarded, or <code>null</code> if the response has
+     * already been completed.
+     *
+     * @param mapping The ActionMapping used to select this instance
+     * @param actionForm The optional ActionForm bean for this request (if any)
+     * @param request The HTTP request we are processing
+     * @param response The HTTP response we are creating
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception ServletException if a servlet exception occurs
+     */
+    public ActionForward execute(ActionMapping mapping,
+                                 ActionForm form,
+                                 HttpServletRequest request,
+                                 HttpServletResponse response)
+        throws IOException, ServletException {
+
+        // Look up the components we will be using as needed
+        if (mserver == null) {
+            mserver = ((ApplicationServlet) getServlet()).getServer();
+        }
+        MessageResources resources = getResources(request);
+        HttpSession session = request.getSession();
+        Locale locale = getLocale(request);
+
+        // Set up beans containing all possible groups and roles
+        String databaseName =
+            URLDecoder.decode(request.getParameter("databaseName"),TomcatTreeBuilder.URL_ENCODING);
+        try {
+            request.setAttribute("groupsForm",
+                                 UserUtils.getGroupsForm(mserver,
+                                                         databaseName));
+        } catch (Exception e) {
+            getServlet().log
+                (resources.getMessage(locale,
+                                      "users.error.attribute.get",
+                                      "groups"), e);
+            response.sendError
+                (HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
+                 resources.getMessage
+                 (locale, "users.error.attribute.get", "groups"));
+            return (null);
+        }
+        try {
+            request.setAttribute("rolesForm",
+                                 UserUtils.getRolesForm(mserver,
+                                                        databaseName));
+        } catch (Exception e) {
+            getServlet().log
+                (resources.getMessage(locale,
+                                      "users.error.attribute.get",
+                                      "roles"), e);
+            response.sendError
+                (HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
+                 resources.getMessage
+                 (locale, "users.error.attribute.get", "roles"));
+            return (null);
+        }
+
+        // Set up the form bean based on the creating or editing state
+        String objectName = request.getParameter("objectName");
+        UserForm userForm = new UserForm();
+        if (objectName == null) {
+            userForm.setNodeLabel
+                (resources.getMessage(locale, "users.user.newUser"));
+            userForm.setObjectName(null);
+        } else {
+            userForm.setNodeLabel
+                (resources.getMessage(locale, "users.user.oldUser"));
+            userForm.setObjectName(objectName);
+            String attribute = null;
+            try {
+                ObjectName oname = new ObjectName(objectName);
+                attribute = "username";
+                userForm.setUsername
+                    ((String) mserver.getAttribute(oname, attribute));
+                attribute = "password";
+                userForm.setPassword
+                    ((String) mserver.getAttribute(oname, attribute));
+                attribute = "fullName";
+                userForm.setFullName
+                    ((String) mserver.getAttribute(oname, attribute));
+                attribute = "groups";
+                userForm.setGroups
+                    ((String[]) mserver.getAttribute(oname, attribute));
+                attribute = "roles";
+                userForm.setRoles
+                    ((String[]) mserver.getAttribute(oname, attribute));
+            } catch (Exception e) {
+                getServlet().log
+                    (resources.getMessage(locale,
+                        "users.error.attribute.get", attribute), e);
+                response.sendError
+                    (HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
+                     resources.getMessage
+                         (locale, "users.error.attribute.get", attribute));
+                return (null);
+            }
+        }
+        userForm.setDatabaseName(databaseName);
+
+        // Stash the form bean and forward to the display page
+        saveToken(request);
+        request.setAttribute("userForm", userForm);
+        return (mapping.findForward("User"));
+
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/users/UserForm.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/users/UserForm.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/users/UserForm.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,220 @@
+/*
+ * Copyright 2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.admin.users;
+
+
+import java.net.URLDecoder;
+import javax.management.MBeanServer;
+import javax.servlet.http.HttpServletRequest;
+import org.apache.struts.action.ActionError;
+import org.apache.struts.action.ActionErrors;
+import org.apache.struts.action.ActionForm;
+import org.apache.struts.action.ActionMapping;
+import org.apache.webapp.admin.ApplicationServlet;
+import org.apache.webapp.admin.TomcatTreeBuilder;
+
+/**
+ * Form bean for the individual user page.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 303390 $ $Date: 2004-10-18 01:37:56 -0500 (Mon, 18 Oct 2004) $
+ * @since 4.1
+ */
+
+public final class UserForm extends BaseForm {
+
+
+    // ----------------------------------------------------- Instance Variables
+
+   /**
+     * The MBeanServer we will be interacting with.
+     */
+    private MBeanServer mserver = null;
+
+    // ------------------------------------------------------------- Properties
+
+    /**
+     * The full name of the associated user.
+     */
+    private String fullName = null;
+
+    public String getFullName() {
+        return (this.fullName);
+    }
+
+    public void setFullName(String fullName) {
+        this.fullName = fullName;
+    }
+
+
+    /**
+     * The MBean Names of the groups associated with this user.
+     */
+    private String groups[] = new String[0];
+
+    public String[] getGroups() {
+        return (this.groups);
+    }
+
+    public void setGroups(String groups[]) {
+        if (groups == null) {
+            groups = new String[0];
+        }
+        this.groups = groups;
+    }
+
+
+    /**
+     * The password of the associated user.
+     */
+    private String password = null;
+
+    public String getPassword() {
+        return (this.password);
+    }
+
+    public void setPassword(String password) {
+        this.password = password;
+    }
+
+
+    /**
+     * The MBean Names of the roles associated with this user.
+     */
+    private String roles[] = new String[0];
+
+    public String[] getRoles() {
+        return (this.roles);
+    }
+
+    public void setRoles(String roles[]) {
+        if (roles == null) {
+            roles = new String[0];
+        }
+        this.roles = roles;
+    }
+
+
+    /**
+     * The username of the associated user.
+     */
+    private String username = null;
+
+    public String getUsername() {
+        return (this.username);
+    }
+
+    public void setUsername(String username) {
+        this.username = username;
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+    /**
+     * Reset all properties to their default values.
+     *
+     * @param mapping The mapping used to select this instance
+     * @param request The servlet request we are processing
+     */
+    public void reset(ActionMapping mapping, HttpServletRequest request) {
+
+        super.reset(mapping, request);
+        fullName = null;
+        groups = new String[0];
+        password = null;
+        roles = new String[0];
+        username = null;
+
+    }
+
+
+    /**
+     * Validate the properties that have been set from this HTTP request,
+     * and return an <code>ActionErrors</code> object that encapsulates any
+     * validation errors that have been found.  If no errors are found, return
+     * <code>null</code> or an <code>ActionErrors</code> object with no
+     * recorded error messages.
+     *
+     * @param mapping The mapping used to select this instance
+     * @param request The servlet request we are processing
+     */
+    public ActionErrors validate(ActionMapping mapping,
+    HttpServletRequest request) {
+        
+        try {
+            // Look up the components we will be using as needed
+            if (mserver == null) {
+                mserver = ((ApplicationServlet) getServlet()).getServer();
+            }
+         
+            // Set up beans containing all possible groups and roles
+            String databaseName =
+                URLDecoder.decode(request.getParameter("databaseName"),TomcatTreeBuilder.URL_ENCODING);
+            request.setAttribute("groupsForm",
+                                 UserUtils.getGroupsForm(mserver,
+                                                         databaseName));
+            request.setAttribute("rolesForm",
+                                 UserUtils.getRolesForm(mserver,
+                                                        databaseName));
+        } catch (Exception e) {
+            // do nothing since the form returns validation error
+        }
+        
+        ActionErrors errors = new ActionErrors();
+
+        String submit = request.getParameter("submit");
+        //if (submit != null) {
+
+            // username is a required field
+            if ((username == null) || (username.length() < 1)) {
+                errors.add("username",
+                           new ActionError("users.error.username.required"));
+            }
+
+            // uassword is a required field
+            if ((password == null) || (username.length() < 1)) {
+                errors.add("password",
+                           new ActionError("users.error.password.required"));
+            }
+
+            // Quotes not allowed in username
+            if ((username != null) && (username.indexOf('"') >= 0)) {
+                errors.add("username",
+                           new ActionError("users.error.quotes"));
+            }
+
+            // Quotes not allowed in password
+            if ((password != null) && (password.indexOf('"') > 0)) {
+                errors.add("description",
+                           new ActionError("users.error.quotes"));
+            }
+
+            // Quotes not allowed in fullName
+            if ((fullName != null) && (fullName.indexOf('"') > 0)) {
+                errors.add("fullName",
+                           new ActionError("users.error.quotes"));
+            }
+
+        //}
+
+        return (errors);
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/users/UserUtils.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/users/UserUtils.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/users/UserUtils.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,127 @@
+/*
+ * Copyright 2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.admin.users;
+
+
+import java.util.Arrays;
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+
+
+/**
+ * <p>Shared utility methods for the user database administration module.</p>
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ * @since 4.1
+ */
+
+public class UserUtils {
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Construct and return a GroupsForm identifying all currently defined
+     * groups in the specified user database.
+     *
+     * @param mserver MBeanServer to be consulted
+     * @param databaseName MBean Name of the user database to be consulted
+     *
+     * @exception Exception if an error occurs
+     */
+    public static GroupsForm getGroupsForm(MBeanServer mserver,
+                                           String databaseName)
+        throws Exception {
+
+        ObjectName dname = new ObjectName(databaseName);
+        String results[] =
+            (String[]) mserver.getAttribute(dname, "groups");
+        if (results == null) {
+            results = new String[0];
+        }
+        Arrays.sort(results);
+
+        GroupsForm groupsForm = new GroupsForm();
+        groupsForm.setDatabaseName(databaseName);
+        groupsForm.setGroups(results);
+        return (groupsForm);
+
+    }
+
+
+    /**
+     * Construct and return a RolesForm identifying all currently defined
+     * roles in the specified user database.
+     *
+     * @param mserver MBeanServer to be consulted
+     * @param databaseName MBean Name of the user database to be consulted
+     *
+     * @exception Exception if an error occurs
+     */
+    public static RolesForm getRolesForm(MBeanServer mserver,
+                                           String databaseName)
+        throws Exception {
+
+        ObjectName dname = new ObjectName(databaseName);
+        String results[] =
+            (String[]) mserver.getAttribute(dname, "roles");
+        if (results == null) {
+            results = new String[0];
+        }
+        Arrays.sort(results);
+
+        RolesForm rolesForm = new RolesForm();
+        rolesForm.setDatabaseName(databaseName);
+        rolesForm.setRoles(results);
+        return (rolesForm);
+
+    }
+
+
+    /**
+     * Construct and return a UsersForm identifying all currently defined
+     * users in the specified user database.
+     *
+     * @param mserver MBeanServer to be consulted
+     * @param databaseName MBean Name of the user database to be consulted
+     *
+     * @exception Exception if an error occurs
+     */
+    public static UsersForm getUsersForm(MBeanServer mserver,
+                                           String databaseName)
+        throws Exception {
+
+        ObjectName dname = new ObjectName(databaseName);
+        String results[] =
+            (String[]) mserver.getAttribute(dname, "users");
+        if (results == null) {
+            results = new String[0];
+        }
+        Arrays.sort(results);
+
+        UsersForm usersForm = new UsersForm();
+        usersForm.setDatabaseName(databaseName);
+        usersForm.setUsers(results);
+        return (usersForm);
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/users/UsersForm.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/users/UsersForm.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/users/UsersForm.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.admin.users;
+
+
+import javax.servlet.http.HttpServletRequest;
+import org.apache.struts.action.ActionError;
+import org.apache.struts.action.ActionErrors;
+import org.apache.struts.action.ActionForm;
+import org.apache.struts.action.ActionMapping;
+
+
+/**
+ * Form bean for the delete users page.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ * @since 4.1
+ */
+
+public final class UsersForm extends BaseForm {
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * The object names of the specified users.
+     */
+    private String users[] = null;
+
+    public String[] getUsers() {
+        return (this.users);
+    }
+
+    public void setUsers(String users[]) {
+        this.users = users;
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Reset all properties to their default values.
+     *
+     * @param mapping The mapping used to select this instance
+     * @param request The servlet request we are processing
+     */
+    public void reset(ActionMapping mapping, HttpServletRequest request) {
+
+        super.reset(mapping, request);
+        this.users = null;
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/users/UsersTreeBuilder.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/users/UsersTreeBuilder.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/users/UsersTreeBuilder.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,139 @@
+/*
+ * Copyright 2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.admin.users;
+
+
+import java.net.URLEncoder;
+import java.io.UnsupportedEncodingException;
+import java.util.Locale;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpSession;
+import org.apache.struts.Globals;
+import org.apache.struts.util.MessageResources;
+import org.apache.webapp.admin.ApplicationServlet;
+import org.apache.webapp.admin.TreeBuilder;
+import org.apache.webapp.admin.TreeControl;
+import org.apache.webapp.admin.TreeControlNode;
+import org.apache.webapp.admin.TomcatTreeBuilder;
+
+/**
+ * Implementation of <code>TreeBuilder</code> that adds the nodes required
+ * for administering the user database.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 303390 $ $Date: 2004-10-18 01:37:56 -0500 (Mon, 18 Oct 2004) $
+ * @since 4.1
+ */
+
+public class UsersTreeBuilder implements TreeBuilder {
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    // ---------------------------------------------------- TreeBuilder Methods
+
+
+    /**
+     * Add the required nodes to the specified <code>treeControl</code>
+     * instance.
+     *
+     * @param treeControl The <code>TreeControl</code> to which we should
+     *  add our nodes
+     * @param servlet The controller servlet for the admin application
+     * @param request The servlet request we are processing
+     */
+    public void buildTree(TreeControl treeControl,
+                          ApplicationServlet servlet,
+                          HttpServletRequest request) {
+
+        MessageResources resources = (MessageResources)
+            servlet.getServletContext().getAttribute(Globals.MESSAGES_KEY);
+        HttpSession session = request.getSession();
+        Locale locale = (Locale) session.getAttribute(Globals.LOCALE_KEY);
+        addSubtree(treeControl.getRoot(), resources, locale);
+
+    }
+
+
+    // ------------------------------------------------------ Protected Methods
+
+
+    /**
+     * Add the subtree of nodes required for user administration.
+     *
+     * @param root The root node of our tree control
+     * @param resources The MessageResources for our localized messages
+     *  messages
+     */
+    protected void addSubtree(TreeControlNode root,
+                              MessageResources resources, Locale locale) {
+
+        try {
+            String databaseName = URLEncoder.encode
+                ("Users:type=UserDatabase,database=UserDatabase",TomcatTreeBuilder.URL_ENCODING);
+
+            TreeControlNode subtree = new TreeControlNode
+                ("Global User and Group Administration",
+                 "folder_16_pad.gif",
+                 resources.getMessage(locale, "users.treeBuilder.subtreeNode"),
+                 null,
+                 "content",
+                 true, "Users");
+            TreeControlNode groups = new TreeControlNode
+                ("Global Administer Groups",
+                 "Groups.gif",
+                 resources.getMessage(locale, "users.treeBuilder.groupsNode"),
+                 "users/listGroups.do?databaseName=" +
+                 URLEncoder.encode(databaseName,TomcatTreeBuilder.URL_ENCODING) +
+                 "&forward=" +
+                 URLEncoder.encode("Groups List Setup",TomcatTreeBuilder.URL_ENCODING),
+                 "content",
+                 false, "Users");
+            TreeControlNode roles = new TreeControlNode
+                ("Global Administer Roles",
+                 "Roles.gif",
+                 resources.getMessage(locale, "users.treeBuilder.rolesNode"),
+                 "users/listRoles.do?databaseName=" +
+                 URLEncoder.encode(databaseName,TomcatTreeBuilder.URL_ENCODING) +
+                 "&forward=" +
+                 URLEncoder.encode("Roles List Setup",TomcatTreeBuilder.URL_ENCODING),
+                 "content",
+                 false, "Users");
+            TreeControlNode users = new TreeControlNode
+                ("Global Administer Users",
+                 "Users.gif",
+                 resources.getMessage(locale, "users.treeBuilder.usersNode"),
+                 "users/listUsers.do?databaseName=" +
+                 URLEncoder.encode(databaseName,TomcatTreeBuilder.URL_ENCODING) +
+                 "&forward=" +
+                 URLEncoder.encode("Users List Setup",TomcatTreeBuilder.URL_ENCODING),
+                 "content",
+                 false, "Users");
+
+            root.addChild(subtree);
+            subtree.addChild(users);
+            subtree.addChild(groups);
+            subtree.addChild(roles);
+        } catch(UnsupportedEncodingException ueex) {
+            // can't happen
+        }
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/valve/AccessLogValveForm.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/valve/AccessLogValveForm.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/valve/AccessLogValveForm.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,341 @@
+/*
+ * Copyright 2001,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.admin.valve;
+
+import javax.servlet.http.HttpServletRequest;
+import org.apache.struts.action.ActionError;
+import org.apache.struts.action.ActionErrors;
+import org.apache.struts.action.ActionForm;
+import org.apache.struts.action.ActionMapping;
+import java.util.List;
+
+/**
+ * Form bean for the accesslog valve page.
+ *
+ * @author Manveen Kaur
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public final class AccessLogValveForm extends ValveForm {
+    
+    // ----------------------------------------------------- Instance Variables
+    /**
+     * The text for the debug level.
+     */
+    private String debugLvl = "0";
+  
+    /**
+     * Set of valid values for debug level.
+     */
+    private List debugLvlVals = null;
+    
+    /**
+     * The text for the directory.
+     */
+    private String directory = null;
+    
+    /**
+     * The text for the pattern.
+     */
+    private String pattern = null;
+        
+    /**
+     * The text for the prefix.
+     */
+    private String prefix = null;
+    
+    /**
+     * The text for the suffix.
+     */
+    private String suffix = null;
+      
+    /**
+     * The text for the connection URL.
+     */
+    private String resolveHosts = "false";
+      
+    /**
+     * The text for the rotatable.
+     */
+    private String rotatable = "true";    
+       
+    /**
+     * Set of boolean values.
+     */
+    private List booleanVals = null;
+ 
+    // ------------------------------------------------------------- Properties
+
+    /**
+     * Return the debugVals.
+     */
+    public List getDebugLvlVals() {
+        
+        return this.debugLvlVals;
+        
+    }
+    
+    /**
+     * Set the debugVals.
+     */
+    public void setDebugLvlVals(List debugLvlVals) {
+        
+        this.debugLvlVals = debugLvlVals;
+        
+    }
+    
+    /**
+     * Return the booleanVals.
+     */
+    public List getBooleanVals() {
+        
+        return this.booleanVals;
+        
+    }
+    
+    /**
+     * Set the booleanVals.
+     */
+    public void setBooleanVals(List booleanVals) {
+        
+        this.booleanVals = booleanVals;
+        
+    }
+    
+    /**
+     * Return the Debug Level Text.
+     */
+    public String getDebugLvl() {
+        
+        return this.debugLvl;
+        
+    }
+    
+    /**
+     * Set the Debug Level Text.
+     */
+    public void setDebugLvl(String debugLvl) {
+        
+        this.debugLvl = debugLvl;
+        
+    }
+    
+    /**
+     * Return the directory.
+     */
+    public String getDirectory() {
+        
+        return this.directory;
+        
+    }
+    
+    /**
+     * Set the directory.
+     */
+    public void setDirectory(String directory) {
+        
+        this.directory = directory;
+        
+    }
+    
+    /**
+     * Return the pattern.
+     */
+    public String getPattern() {
+        
+        return this.pattern;
+        
+    }
+    
+    /**
+     * Set the pattern.
+     */
+    public void setPattern(String pattern) {
+        
+        this.pattern = pattern;
+        
+    }
+    
+    /**
+     * Return the prefix.
+     */
+    public String getPrefix() {
+        
+        return this.prefix;
+        
+    }
+    
+    /**
+     * Set the prefix.
+     */
+    public void setPrefix(String prefix) {
+        
+        this.prefix = prefix;
+        
+    }
+    
+    /**
+     * Return the suffix.
+     */
+    public String getSuffix() {
+        
+        return this.suffix;
+        
+    }
+    
+    /**
+     * Set the suffix.
+     */
+    public void setSuffix(String suffix) {
+        
+        this.suffix = suffix;
+        
+    }
+            
+    /**
+     * Return the resolve hosts.
+     */
+    public String getResolveHosts() {
+        
+        return this.resolveHosts;
+        
+    }
+    
+    /**
+     * Set the resolveHosts.
+     */
+    public void setResolveHosts(String resolveHosts) {
+        
+        this.resolveHosts = resolveHosts;
+        
+    }  
+    
+    /**
+     * Return the rotatable.
+     */
+    public String getRotatable() {
+        
+        return this.rotatable;
+        
+    }
+    
+    /**
+     * Set the rotatable.
+     */
+    public void setRotatable(String rotatable) {
+        
+        this.rotatable = rotatable;
+        
+    }
+    
+    // --------------------------------------------------------- Public Methods
+    
+    /**
+     * Reset all properties to their default values.
+     *
+     * @param mapping The mapping used to select this instance
+     * @param request The servlet request we are processing
+     */
+    public void reset(ActionMapping mapping, HttpServletRequest request) {
+    
+        super.reset(mapping, request);
+        this.debugLvl = "0";
+        
+        this.directory = null;
+        this.prefix = null;
+        this.suffix = null;
+        this.pattern = null;        
+        this.resolveHosts = "false";
+        this.rotatable = "true";
+        
+    }
+    
+    /**
+     * Render this object as a String.
+     */
+    public String toString() {
+
+        StringBuffer sb = new StringBuffer("AccessLogValveForm[adminAction=");
+        sb.append(getAdminAction());
+        sb.append("',valveType=");
+        sb.append(getValveType());
+        sb.append(",debugLvl=");
+        sb.append(debugLvl);
+        sb.append(",directory=");
+        sb.append(directory);
+        sb.append("',prefix='");
+        sb.append(prefix);
+        sb.append("',pattern=");
+        sb.append(pattern);
+        sb.append(",resolveHosts=");
+        sb.append(resolveHosts);
+        sb.append(",rotatable=");
+        sb.append(rotatable);
+        sb.append("',objectName='");
+        sb.append(getObjectName());
+        sb.append("]");
+        return (sb.toString());
+
+    }
+    
+    /**
+     * Validate the properties that have been set from this HTTP request,
+     * and return an <code>ActionErrors</code> object that encapsulates any
+     * validation errors that have been found.  If no errors are found, return
+     * <code>null</code> or an <code>ActionErrors</code> object with no
+     * recorded error messages.
+     *
+     * @param mapping The mapping used to select this instance
+     * @param request The servlet request we are processing
+     */
+    
+    public ActionErrors validate(ActionMapping mapping,
+    HttpServletRequest request) {
+        
+        ActionErrors errors = new ActionErrors();
+        
+        String submit = request.getParameter("submit");
+        
+        // front end validation when save is clicked.        
+         //if (submit != null) {
+            
+             // if not specified, default is access_log.
+             // to specify no prefix, specify a 0 length string...
+            if ((prefix == null) || (prefix.length() == 0)){
+                prefix = "access_log.";
+            }
+            
+            // default is a 0 length string
+            if ((suffix == null) || (suffix.length() < 1)) {
+                suffix = "";
+            }
+                                    
+            // If no directory attribute is specified, the default
+            // value is "logs".
+            if ((directory == null) || (directory.length() < 1)) {
+                directory = "logs";
+            }
+
+            if ((pattern == null) || (pattern.length() < 1)) {
+                errors.add("pattern",
+                new ActionError("error.pattern.required"));
+            }         
+        //}
+                 
+        return errors;
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/valve/AddValveAction.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/valve/AddValveAction.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/valve/AddValveAction.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,199 @@
+/*
+ * Copyright 2001-2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.admin.valve;
+
+import java.io.IOException;
+import java.net.URLEncoder;
+import java.util.Locale;
+import java.util.ArrayList;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+import org.apache.struts.action.Action;
+import org.apache.struts.action.ActionErrors;
+import org.apache.struts.action.ActionForm;
+import org.apache.struts.action.ActionForward;
+import org.apache.struts.action.ActionMapping;
+import org.apache.struts.util.MessageResources;
+import org.apache.webapp.admin.TomcatTreeBuilder;
+import org.apache.webapp.admin.LabelValueBean;
+import org.apache.webapp.admin.Lists;
+
+/**
+ * The <code>Action</code> that sets up <em>Add Valve</em> transactions.
+ *
+ * @author Manveen Kaur
+ * @version $Revision: 303390 $ $Date: 2004-10-18 01:37:56 -0500 (Mon, 18 Oct 2004) $
+ */
+
+public class AddValveAction extends Action {
+        
+    // the list for types of valves
+    private ArrayList types = null;
+
+    // --------------------------------------------------------- Public Methods
+    
+    /**
+     * Process the specified HTTP request, and create the corresponding HTTP
+     * response (or forward to another web component that will create it).
+     * Return an <code>ActionForward</code> instance describing where and how
+     * control should be forwarded, or <code>null</code> if the response has
+     * already been completed.
+     *
+     * @param mapping The ActionMapping used to select this instance
+     * @param actionForm The optional ActionForm bean for this request (if any)
+     * @param request The HTTP request we are processing
+     * @param response The HTTP response we are creating
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception ServletException if a servlet exception occurs
+     */
+    public ActionForward execute(ActionMapping mapping,
+                                 ActionForm form,
+                                 HttpServletRequest request,
+                                 HttpServletResponse response)
+        throws IOException, ServletException {
+
+        // Acquire the resources that we need
+        HttpSession session = request.getSession();
+        Locale locale = getLocale(request);
+        MessageResources resources = getResources(request);
+        
+        // Fill in the form values for display and editing
+        
+        String valveTypes[] = new String[5];
+        valveTypes[0] = "AccessLogValve";
+        valveTypes[1] = "RemoteAddrValve";
+        valveTypes[2] = "RemoteHostValve";
+        valveTypes[3] = "RequestDumperValve";       
+        valveTypes[4] = "SingleSignOn";
+                     
+        String parent = request.getParameter("parent");
+        String type = request.getParameter("type");        
+        if (type == null) 
+            type = "AccessLogValve";    // default type is AccessLog
+        
+        types = new ArrayList();    
+        // the first element in the select list should be the type selected
+        types.add(new LabelValueBean(type,
+                "AddValve.do?parent=" + 
+                URLEncoder.encode(parent,TomcatTreeBuilder.URL_ENCODING) 
+                + "&type=" + type));        
+        for (int i=0; i< valveTypes.length; i++) {
+            if (!type.equalsIgnoreCase(valveTypes[i])) {
+                types.add(new LabelValueBean(valveTypes[i],
+                "AddValve.do?parent=" + 
+                URLEncoder.encode(parent,TomcatTreeBuilder.URL_ENCODING) 
+                + "&type=" + valveTypes[i]));        
+            }
+        }
+       
+        if ("AccessLogValve".equalsIgnoreCase(type)) {
+            createAccessLogger(session, parent);
+        } else if ("RemoteAddrValve".equalsIgnoreCase(type)) {
+            createRemoteAddrValve(session, parent);
+        } else if ("RemoteHostValve".equalsIgnoreCase(type)) {
+            createRemoteHostValve(session, parent);
+        } else if ("RequestDumperValve".equalsIgnoreCase(type)) {
+            createRequestDumperValve(session, parent);
+        } else {
+            //SingleSignOn
+            createSingleSignOnValve(session, parent);
+        }
+        // Forward to the valve display page
+        return (mapping.findForward(type));
+        
+    }
+
+    private void createAccessLogger(HttpSession session, String parent) {
+
+        AccessLogValveForm valveFm = new AccessLogValveForm();
+        session.setAttribute("accessLogValveForm", valveFm);
+        valveFm.setAdminAction("Create");
+        valveFm.setObjectName("");
+        valveFm.setParentObjectName(parent);
+        String valveType = "AccessLogValve";
+        valveFm.setNodeLabel("Valve (" + valveType + ")");
+        valveFm.setValveType(valveType);
+        valveFm.setPattern("");
+        valveFm.setDirectory("logs");
+        valveFm.setPrefix("access_log.");
+        valveFm.setSuffix("");
+        valveFm.setResolveHosts("false");
+        valveFm.setRotatable("true");
+        valveFm.setBooleanVals(Lists.getBooleanValues());
+        valveFm.setValveTypeVals(types);        
+    }
+
+    private void createRemoteAddrValve(HttpSession session, String parent) {
+
+        RemoteAddrValveForm valveFm = new RemoteAddrValveForm();
+        session.setAttribute("remoteAddrValveForm", valveFm);
+        valveFm.setAdminAction("Create");
+        valveFm.setObjectName("");
+        valveFm.setParentObjectName(parent);
+        String valveType = "RemoteAddrValve";
+        valveFm.setNodeLabel("Valve (" + valveType + ")");
+        valveFm.setValveType(valveType);
+        valveFm.setAllow("");
+        valveFm.setDeny("");
+        valveFm.setValveTypeVals(types);        
+    }
+
+    private void createRemoteHostValve(HttpSession session, String parent) {
+
+        RemoteHostValveForm valveFm = new RemoteHostValveForm();
+        session.setAttribute("remoteHostValveForm", valveFm);
+        valveFm.setAdminAction("Create");
+        valveFm.setObjectName("");
+        valveFm.setParentObjectName(parent);
+        String valveType = "RemoteHostValve";
+        valveFm.setNodeLabel("Valve (" + valveType + ")");
+        valveFm.setValveType(valveType);
+        valveFm.setAllow("");
+        valveFm.setDeny("");
+        valveFm.setValveTypeVals(types);        
+    }
+
+    private void createRequestDumperValve(HttpSession session, String parent) {
+
+        RequestDumperValveForm valveFm = new RequestDumperValveForm();
+        session.setAttribute("requestDumperValveForm", valveFm);
+        valveFm.setAdminAction("Create");
+        valveFm.setObjectName("");
+        valveFm.setParentObjectName(parent);
+        String valveType = "RequestDumperValve";
+        valveFm.setNodeLabel("Valve (" + valveType + ")");
+        valveFm.setValveType(valveType);
+        valveFm.setValveTypeVals(types);        
+    }
+
+    private void createSingleSignOnValve(HttpSession session, String parent) {
+
+        SingleSignOnValveForm valveFm = new SingleSignOnValveForm();
+        session.setAttribute("singleSignOnValveForm", valveFm);
+        valveFm.setAdminAction("Create");
+        valveFm.setObjectName("");
+        valveFm.setParentObjectName(parent);
+        String valveType = "SingleSignOn";
+        valveFm.setNodeLabel("Valve (" + valveType + ")");
+        valveFm.setValveType(valveType);
+        valveFm.setValveTypeVals(types);        
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/valve/DeleteValveAction.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/valve/DeleteValveAction.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/valve/DeleteValveAction.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,144 @@
+/*
+ * Copyright 2001-2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.admin.valve;
+
+import java.io.IOException;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Locale;
+import java.util.TreeSet;
+import java.util.Set;
+import java.util.ArrayList;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+import org.apache.struts.action.Action;
+import org.apache.struts.action.ActionErrors;
+import org.apache.struts.action.ActionForm;
+import org.apache.struts.action.ActionForward;
+import org.apache.struts.action.ActionMapping;
+
+import javax.management.MBeanServer;
+import javax.management.MBeanServerFactory;
+import javax.management.QueryExp;
+import javax.management.Query;
+import javax.management.ObjectInstance;
+import javax.management.ObjectName;
+import javax.management.JMException;
+import org.apache.struts.util.MessageResources;
+
+import org.apache.webapp.admin.ApplicationServlet;
+import org.apache.webapp.admin.TomcatTreeBuilder;
+import org.apache.webapp.admin.Lists;
+
+/**
+ * The <code>Action</code> that sets up <em>Delete Valves</em> transactions.
+ *
+ * @author Manveen Kaur
+ * @version $Revision: 303390 $ $Date: 2004-10-18 01:37:56 -0500 (Mon, 18 Oct 2004) $
+ */
+
+public class DeleteValveAction extends Action {
+    
+    
+    /**
+     * The MBeanServer we will be interacting with.
+     */
+    private MBeanServer mBServer = null;
+    
+    
+    // --------------------------------------------------------- Public Methods
+    
+    /**
+     * Process the specified HTTP request, and create the corresponding HTTP
+     * response (or forward to another web component that will create it).
+     * Return an <code>ActionForward</code> instance describing where and how
+     * control should be forwarded, or <code>null</code> if the response has
+     * already been completed.
+     *
+     * @param mapping The ActionMapping used to select this instance
+     * @param actionForm The optional ActionForm bean for this request (if any)
+     * @param request The HTTP request we are processing
+     * @param response The HTTP response we are creating
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception ServletException if a servlet exception occurs
+     */
+    public ActionForward execute(ActionMapping mapping,
+    ActionForm form,
+    HttpServletRequest request,
+    HttpServletResponse response)
+    throws IOException, ServletException {
+        
+        
+        // Acquire the resources that we need
+        HttpSession session = request.getSession();
+        Locale locale = getLocale(request);
+        MessageResources resources = getResources(request);
+        
+        // Acquire a reference to the MBeanServer containing our MBeans
+        try {
+            mBServer = ((ApplicationServlet) getServlet()).getServer();
+        } catch (Throwable t) {
+            throw new ServletException
+            ("Cannot acquire MBeanServer reference", t);
+        }
+        
+        String pattern = null;
+        // Set up a form bean containing the currently selected
+        // objects to be deleted
+        ValvesForm valvesForm = new ValvesForm();
+        String select = request.getParameter("select");
+        if (select != null) {
+            String valves[] = new String[1];
+            valves[0] = select;
+            valvesForm.setValves(valves);
+            pattern = select;
+        }
+        request.setAttribute("valvesForm", valvesForm);
+        
+        // Accumulate a list of all available valves
+        ArrayList list = new ArrayList();
+        String parent = request.getParameter("parent");
+        valvesForm.setParentObjectName(parent);
+        
+        try {
+            Iterator items = (Lists.getValves(mBServer, parent)).iterator();
+            while (items.hasNext()) {
+                list.add(items.next().toString());
+            }
+        } catch (Exception e) {
+            getServlet().log
+            (resources.getMessage(locale, "users.error.select"));
+            response.sendError
+            (HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
+            resources.getMessage(locale, "users.error.select"));
+            return (null);
+        }
+        
+        Collections.sort(list);
+        request.setAttribute("valvesList", list);
+        
+        // Forward to the list display page
+        return (mapping.findForward("Valves"));
+        
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/valve/DeleteValvesAction.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/valve/DeleteValvesAction.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/valve/DeleteValvesAction.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,158 @@
+/*
+ * Copyright 2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.admin.valve;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.Locale;
+import java.util.Set;
+import java.util.TreeSet;
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+import javax.management.ObjectInstance;
+import javax.management.modelmbean.ModelMBean;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpSession;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import org.apache.struts.action.Action;
+import org.apache.struts.action.ActionForm;
+import org.apache.struts.action.ActionForward;
+import org.apache.struts.action.ActionMapping;
+import org.apache.struts.util.MessageResources;
+
+import org.apache.webapp.admin.ApplicationServlet;
+import org.apache.webapp.admin.TomcatTreeBuilder;
+import org.apache.webapp.admin.TreeControl;
+import org.apache.webapp.admin.TreeControlNode;
+
+
+/**
+ * The <code>Action</code> that completes <em>Delete Valves</em>
+ * transactions.
+ *
+ * @author Manveen Kaur
+ * @version $Revision: 303390 $ $Date: 2004-10-18 01:37:56 -0500 (Mon, 18 Oct 2004) $
+ */
+
+public class DeleteValvesAction extends Action {
+
+
+    /**
+     * Signature for the <code>removeValve</code> operation.
+     */
+    private String removeValveTypes[] =
+    { "java.lang.String",      // Object name
+    };
+
+
+    /**
+     * The MBeanServer we will be interacting with.
+     */
+    private MBeanServer mBServer = null;
+    
+
+    // --------------------------------------------------------- Public Methods
+    
+    
+    /**
+     * Process the specified HTTP request, and create the corresponding HTTP
+     * response (or forward to another web component that will create it).
+     * Return an <code>ActionForward</code> instance describing where and how
+     * control should be forwarded, or <code>null</code> if the response has
+     * already been completed.
+     *
+     * @param mapping The ActionMapping used to select this instance
+     * @param actionForm The optional ActionForm bean for this request (if any)
+     * @param request The HTTP request we are processing
+     * @param response The HTTP response we are creating
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception ServletException if a servlet exception occurs
+     */
+    public ActionForward execute(ActionMapping mapping,
+                                 ActionForm form,
+                                 HttpServletRequest request,
+                                 HttpServletResponse response)
+        throws IOException, ServletException {
+        
+        
+        // Look up the components we will be using as needed
+        HttpSession session = request.getSession();
+        Locale locale = getLocale(request);
+        MessageResources resources = getResources(request);
+
+        // Acquire a reference to the MBeanServer containing our MBeans
+        try {
+            mBServer = ((ApplicationServlet) getServlet()).getServer();
+        } catch (Throwable t) {
+            throw new ServletException
+            ("Cannot acquire MBeanServer reference", t);
+        }
+        
+        // Delete the specified Valves
+        String valves[]  = ((ValvesForm) form).getValves();
+        String values[] = new String[1];
+        String operation = "removeValve";
+        try {
+
+            // Look up our tree control data structure
+            TreeControl control = (TreeControl)
+                session.getAttribute("treeControlTest");
+
+            // Remove the specified valves
+            for (int i = 0; i < valves.length; i++) {
+                values[0] = valves[i];
+                String domain = (new ObjectName(valves[i])).getDomain();
+                ObjectName fname = TomcatTreeBuilder.getMBeanFactory();
+                mBServer.invoke(fname, operation,
+                                values, removeValveTypes);
+                if (control != null) {
+                    control.selectNode(null);
+                    TreeControlNode node = control.findNode(valves[i]);
+                    if (node != null) {
+                        node.remove();
+                    } else {
+                        getServlet().log("Missing TreeControlNode for " +
+                                         valves[i]);
+                    }
+                } else {
+                    getServlet().log("Missing TreeControl attribute");
+                }
+            }
+
+        } catch (Exception e) {
+
+            getServlet().log
+                (resources.getMessage(locale, "users.error.invoke",
+                                      operation), e);
+            response.sendError
+                (HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
+                 resources.getMessage(locale, "users.error.invoke",
+                                      operation));
+            return (null);
+
+        }
+
+        // Report successful completion of this transaction
+        return (mapping.findForward("Save Successful"));
+
+    }
+    
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/valve/EditValveAction.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/valve/EditValveAction.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/valve/EditValveAction.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,341 @@
+/*
+ * Copyright 2001-2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.admin.valve;
+
+import java.io.IOException;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Locale;
+import java.util.ArrayList;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+import org.apache.struts.action.Action;
+import org.apache.struts.action.ActionErrors;
+import org.apache.struts.action.ActionForm;
+import org.apache.struts.action.ActionForward;
+import org.apache.struts.action.ActionMapping;
+import org.apache.struts.util.MessageResources;
+
+import javax.management.MBeanServer;
+import javax.management.ObjectInstance;
+import javax.management.ObjectName;
+import javax.management.JMException;
+
+import org.apache.webapp.admin.ApplicationServlet;
+import org.apache.webapp.admin.LabelValueBean;
+import org.apache.webapp.admin.Lists;
+import org.apache.webapp.admin.TomcatTreeBuilder;
+
+/**
+ * A generic <code>Action</code> that sets up <em>Edit 
+ * Valve </em> transactions, based on the type of Valve.
+ *
+ * @author Manveen Kaur
+ * @version $Revision: 303390 $ $Date: 2004-10-18 01:37:56 -0500 (Mon, 18 Oct 2004) $
+ */
+
+public class EditValveAction extends Action {
+    
+
+    /**
+     * The MBeanServer we will be interacting with.
+     */
+    private MBeanServer mBServer = null;
+    
+
+    // --------------------------------------------------------- Public Methods
+    
+    /**
+     * Process the specified HTTP request, and create the corresponding HTTP
+     * response (or forward to another web component that will create it).
+     * Return an <code>ActionForward</code> instance describing where and how
+     * control should be forwarded, or <code>null</code> if the response has
+     * already been completed.
+     *
+     * @param mapping The ActionMapping used to select this instance
+     * @param actionForm The optional ActionForm bean for this request (if any)
+     * @param request The HTTP request we are processing
+     * @param response The HTTP response we are creating
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception ServletException if a servlet exception occurs
+     */
+    public ActionForward execute(ActionMapping mapping,
+                                 ActionForm form,
+                                 HttpServletRequest request,
+                                 HttpServletResponse response)
+        throws IOException, ServletException {
+        
+        // Acquire the resources that we need
+        HttpSession session = request.getSession();
+        Locale locale = getLocale(request);
+        MessageResources resources = getResources(request);
+        
+        // Acquire a reference to the MBeanServer containing our MBeans
+        try {
+            mBServer = ((ApplicationServlet) getServlet()).getServer();
+        } catch (Throwable t) {
+            throw new ServletException
+            ("Cannot acquire MBeanServer reference", t);
+        }
+        
+        // Set up the object names of the MBeans we are manipulating
+        ObjectName vname = null;
+        StringBuffer sb = null;
+        try {
+            vname = new ObjectName(request.getParameter("select"));
+        } catch (Exception e) {
+            String message =
+                resources.getMessage(locale, "error.valveName.bad",
+                                     request.getParameter("select"));
+            getServlet().log(message);
+            response.sendError(HttpServletResponse.SC_BAD_REQUEST, message);
+            return (null);
+        }
+        
+       String parent = request.getParameter("parent");
+       String valveType = null;
+       String attribute = null;
+       
+       // Find what type of Valve this is
+       try {    
+            attribute = "className";
+            String className = (String) 
+                mBServer.getAttribute(vname, attribute);
+            int period = className.lastIndexOf(".");
+            if (period >= 0)
+                valveType = className.substring(period + 1);
+        } catch (Throwable t) {
+          getServlet().log
+                (resources.getMessage(locale, "users.error.attribute.get",
+                                      attribute), t);
+            response.sendError
+                (HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
+                 resources.getMessage(locale, "users.error.attribute.get",
+                                      attribute));
+            return (null); 
+        }
+
+        // Forward to the appropriate valve display page        
+        if ("AccessLogValve".equalsIgnoreCase(valveType)) {
+               setUpAccessLogValve(vname, request, response);
+        } else if ("RemoteAddrValve".equalsIgnoreCase(valveType)) {
+               setUpRemoteAddrValve(vname, request, response);
+        } else if ("RemoteHostValve".equalsIgnoreCase(valveType)) {
+                setUpRemoteHostValve(vname, request, response);
+        } else if ("RequestDumperValve".equalsIgnoreCase(valveType)) {
+               setUpRequestDumperValve(vname, request, response);
+        } else if ("SingleSignOn".equalsIgnoreCase(valveType)) {
+               setUpSingleSignOnValve(vname, request, response);
+        }
+       
+        
+        return (mapping.findForward(valveType));
+                
+    }
+
+    private void setUpAccessLogValve(ObjectName vname, HttpServletRequest request,
+                                        HttpServletResponse response) 
+    throws IOException {
+        // Fill in the form values for display and editing
+        HttpSession session = request.getSession();
+        Locale locale = getLocale(request);
+        MessageResources resources = getResources(request);
+        String parent = request.getParameter("parent");
+        AccessLogValveForm valveFm = new AccessLogValveForm();
+        session.setAttribute("accessLogValveForm", valveFm);
+        valveFm.setAdminAction("Edit");
+        valveFm.setObjectName(vname.toString()); 
+        valveFm.setParentObjectName(parent);
+        String valveType = "AccessLogValve";
+        StringBuffer sb = new StringBuffer("");
+        String host = vname.getKeyProperty("host");
+        String context = vname.getKeyProperty("path");        
+        if (host!=null) {
+            sb.append("Host (" + host + ") > ");
+        }
+        if (context!=null) {
+            sb.append("Context (" + context + ") > ");
+        }
+        sb.append("Valve");
+        valveFm.setNodeLabel(sb.toString());
+        valveFm.setValveType(valveType);
+        valveFm.setBooleanVals(Lists.getBooleanValues());
+        String attribute = null;
+        try {
+            
+            // Copy scalar properties
+            attribute = "directory";
+            valveFm.setDirectory
+                ((String) mBServer.getAttribute(vname, attribute));
+            attribute = "pattern";
+            valveFm.setPattern
+                ((String) mBServer.getAttribute(vname, attribute));
+            attribute = "prefix";
+            valveFm.setPrefix
+                ((String) mBServer.getAttribute(vname, attribute));
+            attribute = "suffix";
+            valveFm.setSuffix
+                ((String) mBServer.getAttribute(vname, attribute));
+            attribute = "resolveHosts";
+            valveFm.setResolveHosts
+                (((Boolean) mBServer.getAttribute(vname, attribute)).toString());
+            attribute = "rotatable";
+            valveFm.setRotatable
+                (((Boolean) mBServer.getAttribute(vname, attribute)).toString());
+
+        } catch (Throwable t) {
+            getServlet().log
+                (resources.getMessage(locale, "users.error.attribute.get",
+                                      attribute), t);
+            response.sendError
+                (HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
+                 resources.getMessage(locale, "users.error.attribute.get",
+                                      attribute));
+        }     
+    }
+
+    private void setUpRequestDumperValve(ObjectName vname, HttpServletRequest request,
+                                        HttpServletResponse response) 
+    throws IOException {
+        // Fill in the form values for display and editing
+        HttpSession session = request.getSession();
+        Locale locale = getLocale(request);
+        MessageResources resources = getResources(request);
+        String parent = request.getParameter("parent");
+        RequestDumperValveForm valveFm = new RequestDumperValveForm();
+        session.setAttribute("requestDumperValveForm", valveFm);
+        valveFm.setAdminAction("Edit");
+        valveFm.setObjectName(vname.toString()); 
+        valveFm.setParentObjectName(parent);
+        String valveType = "RequestDumperValve";
+        StringBuffer sb = new StringBuffer("Valve (");
+        sb.append(valveType);
+        sb.append(")");
+        valveFm.setNodeLabel(sb.toString());
+        valveFm.setValveType(valveType);
+        String attribute = null;
+    }
+
+    private void setUpSingleSignOnValve(ObjectName vname, HttpServletRequest request,
+                                        HttpServletResponse response) 
+    throws IOException {
+        // Fill in the form values for display and editing
+        HttpSession session = request.getSession();
+        Locale locale = getLocale(request);
+        MessageResources resources = getResources(request);
+        String parent = request.getParameter("parent");
+        SingleSignOnValveForm valveFm = new SingleSignOnValveForm();
+        session.setAttribute("singleSignOnValveForm", valveFm);
+        valveFm.setAdminAction("Edit");
+        valveFm.setObjectName(vname.toString()); 
+        valveFm.setParentObjectName(parent);
+        String valveType = "SingleSignOn";
+        StringBuffer sb = new StringBuffer("Valve (");
+        sb.append(valveType);
+        sb.append(")");
+        valveFm.setNodeLabel(sb.toString());
+        valveFm.setValveType(valveType);
+        String attribute = null;
+    }
+
+
+    private void setUpRemoteAddrValve(ObjectName vname, HttpServletRequest request,
+                                        HttpServletResponse response) 
+    throws IOException {
+        // Fill in the form values for display and editing
+        HttpSession session = request.getSession();
+        Locale locale = getLocale(request);
+        MessageResources resources = getResources(request);
+        String parent = request.getParameter("parent");
+        RemoteAddrValveForm valveFm = new RemoteAddrValveForm();
+        session.setAttribute("remoteAddrValveForm", valveFm);
+        valveFm.setAdminAction("Edit");
+        valveFm.setObjectName(vname.toString()); 
+        valveFm.setParentObjectName(parent);
+        String valveType = "RemoteAddrValve";
+        StringBuffer sb = new StringBuffer("Valve (");
+        sb.append(valveType);
+        sb.append(")");
+        valveFm.setNodeLabel(sb.toString());
+        valveFm.setValveType(valveType);
+        String attribute = null;
+        try {
+            
+            // Copy scalar properties
+            attribute = "allow";
+            valveFm.setAllow
+                ((String) mBServer.getAttribute(vname, attribute));
+            attribute = "deny";
+            valveFm.setDeny
+                ((String) mBServer.getAttribute(vname, attribute));
+                        
+        } catch (Throwable t) {
+            getServlet().log
+                (resources.getMessage(locale, "users.error.attribute.get",
+                                      attribute), t);
+            response.sendError
+                (HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
+                 resources.getMessage(locale, "users.error.attribute.get",
+                                      attribute));
+        }     
+    }
+
+    private void setUpRemoteHostValve(ObjectName vname, HttpServletRequest request,
+                                        HttpServletResponse response) 
+    throws IOException {
+        // Fill in the form values for display and editing
+        HttpSession session = request.getSession();
+        Locale locale = getLocale(request);
+        MessageResources resources = getResources(request);
+        String parent = request.getParameter("parent");
+        RemoteHostValveForm valveFm = new RemoteHostValveForm();
+        session.setAttribute("remoteHostValveForm", valveFm);
+        valveFm.setAdminAction("Edit");
+        valveFm.setObjectName(vname.toString()); 
+        valveFm.setParentObjectName(parent);
+        String valveType = "RemoteHostValve";
+        StringBuffer sb = new StringBuffer("Valve (");
+        sb.append(valveType);
+        sb.append(")");
+        valveFm.setNodeLabel(sb.toString());
+        valveFm.setValveType(valveType);
+        String attribute = null;
+        try {
+            
+            // Copy scalar properties
+            attribute = "allow";
+            valveFm.setAllow
+                ((String) mBServer.getAttribute(vname, attribute));
+            attribute = "deny";
+            valveFm.setDeny
+                ((String) mBServer.getAttribute(vname, attribute));
+                        
+        } catch (Throwable t) {
+            getServlet().log
+                (resources.getMessage(locale, "users.error.attribute.get",
+                                      attribute), t);
+            response.sendError
+                (HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
+                 resources.getMessage(locale, "users.error.attribute.get",
+                                      attribute));
+        }     
+    }
+    
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/valve/RemoteAddrValveForm.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/valve/RemoteAddrValveForm.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/valve/RemoteAddrValveForm.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,224 @@
+/*
+ * Copyright 2001,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.admin.valve;
+
+import java.lang.IllegalArgumentException;
+import java.net.InetAddress;
+import java.util.List;
+import java.util.regex.Pattern;
+import javax.servlet.http.HttpServletRequest;
+
+import org.apache.struts.action.ActionError;
+import org.apache.struts.action.ActionErrors;
+import org.apache.struts.action.ActionForm;
+import org.apache.struts.action.ActionMapping;
+
+import org.apache.webapp.admin.ApplicationServlet;
+import org.apache.webapp.admin.LabelValueBean;
+
+/**
+ * Form bean for the remote addr valve page.
+ *
+ * @author Manveen Kaur
+ * @version $Revision: 303192 $ $Date: 2004-09-03 04:33:06 -0500 (Fri, 03 Sep 2004) $
+ */
+
+public final class RemoteAddrValveForm extends ValveForm {
+    
+    // ----------------------------------------------------- Instance Variables
+    
+    
+    /**
+     * The text for the allow IP addresses.
+     * A comma-separated list of regular expression patterns
+     * that the remote client's IP address is compared to. 
+     */
+    private String allow = "";
+
+    /**
+     * The text for the deny IP addresses.
+     */
+    private String deny = "";
+    
+    /**
+     * The set of <code>allow</code> regular expressions we will evaluate.
+     */
+    private Pattern allows[] = new Pattern[0];
+
+    /**
+     * The set of <code>deny</code> regular expressions we will evaluate.
+     */
+    private Pattern denies[] = new Pattern[0];
+
+
+    // ------------------------------------------------------------- Properties
+
+    /**
+     * Return the allow hosts IP adddresses.
+     */
+    public String getAllow() {
+        
+        return this.allow;
+        
+    }
+    
+    /**
+     * Set the allow hosts.
+     */
+    public void setAllow(String allow) {
+        
+        this.allow = allow;
+        
+    }
+    
+    /**
+     * Return the deny hosts IP adddresses.
+     */
+    public String getDeny() {
+        
+        return this.deny;
+        
+    }
+    
+    /**
+     * Set the deny hosts IP addresses.
+     */
+    public void setDeny(String deny) {
+        
+        this.deny = deny;
+        
+    }    
+
+    // --------------------------------------------------------- Public Methods
+    
+    
+    /**
+     * Reset all properties to their default values.
+     *
+     * @param mapping The mapping used to select this instance
+     * @param request The servlet request we are processing
+     */
+    public void reset(ActionMapping mapping, HttpServletRequest request) {
+                
+        super.reset(mapping, request);
+        this.allow = null;
+        this.deny = null;
+        this.allows = null;
+        this.denies = null;
+        
+    }
+    
+    /**
+     * Render this object as a String.
+     */
+    public String toString() {
+
+        StringBuffer sb = new StringBuffer("RemoteAddrValveForm[adminAction=");
+        sb.append(getAdminAction());
+        sb.append("',valveType=");
+        sb.append(getValveType());
+        sb.append(",allow=");
+        sb.append(getAllow());
+        sb.append(",deny=");
+        sb.append(getDeny());        
+        sb.append("',objectName='");
+        sb.append(getObjectName());
+        sb.append("]");
+        return (sb.toString());
+
+    }
+    
+    /**
+     * Validate the properties that have been set from this HTTP request,
+     * and return an <code>ActionErrors</code> object that encapsulates any
+     * validation errors that have been found.  If no errors are found, return
+     * <code>null</code> or an <code>ActionErrors</code> object with no
+     * recorded error messages.
+     *
+     * @param mapping The mapping used to select this instance
+     * @param request The servlet request we are processing
+     */
+    
+    public ActionErrors validate(ActionMapping mapping,
+    HttpServletRequest request) {
+        
+        ActionErrors errors = new ActionErrors();
+        
+        String submit = request.getParameter("submit");
+        
+        // front end validation when save is clicked.        
+        //if (submit != null) {
+            // validate allow/deny patterns
+            if ((allow == null) || (allow.length() < 1)) {
+                if ((deny == null) || (deny.length() < 1)) {
+                    errors.add("allow",
+                    new ActionError("error.allow.deny.required"));
+                }
+            }                
+        //}
+        
+        try {
+            allows = ValveUtil.precalculate(allow);            
+        } catch (IllegalArgumentException e) {
+            errors.add("allow", new ActionError("error.syntax"));
+            return errors;
+        }
+         
+        try {   
+            denies = ValveUtil.precalculate(deny);
+        } catch (IllegalArgumentException e) {
+            errors.add("allow", new ActionError("error.syntax"));
+            return errors;
+        }
+        
+        String ip = request.getRemoteAddr();
+        
+        if (ip == null) {
+            return errors;
+        }
+        
+        for (int i = 0; i < denies.length; i++) {
+            if (denies[i].matcher(ip).matches()) {
+                if (allows.length < 1) {
+                    errors.add("deny",
+                        new ActionError("error.denyIP"));
+                }
+                for (int j = 0; j < allows.length; j++) {
+                    if (!allows[j].matcher(ip).matches()) { 
+                        errors.add("deny",
+                        new ActionError("error.denyIP"));
+                    }
+                }
+            }    
+        }
+        
+        boolean allowMatch = true;
+        if (allows.length > 0) {
+            allowMatch = false;
+        }
+        for (int i = 0; i < allows.length; i++) {
+            if (allows[i].matcher(ip).matches()) {
+                allowMatch = true;       
+            }
+        }       
+        if (!allowMatch) {
+            errors.add("allow", new ActionError("error.allowIP"));
+        }
+        
+        return errors;
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/valve/RemoteHostValveForm.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/valve/RemoteHostValveForm.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/valve/RemoteHostValveForm.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,242 @@
+/*
+ * Copyright 2001,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.admin.valve;
+
+import java.lang.IllegalArgumentException;
+import java.net.InetAddress;
+import java.util.List;
+import java.util.regex.Pattern;
+import javax.servlet.http.HttpServletRequest;
+
+import org.apache.struts.action.ActionError;
+import org.apache.struts.action.ActionErrors;
+import org.apache.struts.action.ActionForm;
+import org.apache.struts.action.ActionMapping;
+
+import org.apache.webapp.admin.ApplicationServlet;
+import org.apache.webapp.admin.LabelValueBean;
+
+/**
+ * Form bean for the remote host valve page.
+ *
+ * @author Manveen Kaur
+ * @version $Revision: 303192 $ $Date: 2004-09-03 04:33:06 -0500 (Fri, 03 Sep 2004) $
+ */
+
+public final class RemoteHostValveForm extends ValveForm {
+    
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The text for the allow hosts IP addresses.
+     * A comma-separated list of regular expression patterns
+     * that the remote client's IP address is compared to. 
+     */
+    private String allow = "";
+
+    /**
+     * The text for the deny hosts IP addresses.
+     */
+    private String deny = "";
+
+    /**
+     * The set of <code>allow</code> regular expressions we will evaluate.
+     */
+    private Pattern allows[] = new Pattern[0];
+
+    /**
+     * The set of <code>deny</code> regular expressions we will evaluate.
+     */
+    private Pattern denies[] = new Pattern[0];
+    
+    
+    // ------------------------------------------------------------- Properties
+
+    /**
+     * Return the allow hosts IP adddresses.
+     */
+    public String getAllow() {
+        
+        return this.allow;
+        
+    }
+    
+    /**
+     * Set the allow hosts.
+     */
+    public void setAllow(String allow) {
+        
+        this.allow = allow;
+        
+    }
+    
+    /**
+     * Return the deny hosts IP adddresses.
+     */
+    public String getDeny() {
+        
+        return this.deny;
+        
+    }
+    
+    /**
+     * Set the deny hosts IP addresses.
+     */
+    public void setDeny(String deny) {
+        
+        this.deny = deny;
+        
+    }    
+    
+    // --------------------------------------------------------- Public Methods
+    
+    /**
+     * Reset all properties to their default values.
+     *
+     * @param mapping The mapping used to select this instance
+     * @param request The servlet request we are processing
+     */
+    public void reset(ActionMapping mapping, HttpServletRequest request) {
+
+        super.reset(mapping, request);
+        this.allow = null;
+        this.deny = null;
+        this.allows = null;
+        this.denies = null;
+        
+    }
+    
+    /**
+     * Render this object as a String.
+     */
+    public String toString() {
+
+        StringBuffer sb = new StringBuffer("RemoteHostValveForm[adminAction=");
+        sb.append(getAdminAction());
+        sb.append("',valveType=");
+        sb.append(getValveType());
+        sb.append(",allow=");
+        sb.append(allow);
+        sb.append(",deny=");
+        sb.append(deny);        
+        sb.append("',objectName='");
+        sb.append(getObjectName());
+        sb.append("]");
+        return (sb.toString());
+
+    }
+    
+    /**
+     * Validate the properties that have been set from this HTTP request,
+     * and return an <code>ActionErrors</code> object that encapsulates any
+     * validation errors that have been found.  If no errors are found, return
+     * <code>null</code> or an <code>ActionErrors</code> object with no
+     * recorded error messages.
+     *
+     * @param mapping The mapping used to select this instance
+     * @param request The servlet request we are processing
+     */
+    
+    public ActionErrors validate(ActionMapping mapping,
+    HttpServletRequest request) {
+        
+        ActionErrors errors = new ActionErrors();
+        
+        String submit = request.getParameter("submit");
+        
+        // front end validation when save is clicked.        
+        //if (submit != null) {
+             // TBD
+            // validate allow/deny IPs
+            if ((allow == null) || (allow.length() < 1)) {
+                if ((deny == null) || (deny.length() < 1)) {
+                    errors.add("allow",
+                    new ActionError("error.allow.deny.required"));
+                }
+            }              
+        //}
+        
+        try {
+            allows = ValveUtil.precalculate(allow);            
+        } catch (IllegalArgumentException e) {
+            errors.add("allow", new ActionError("error.syntax"));
+            return errors;
+        }
+         
+        try {   
+            denies = ValveUtil.precalculate(deny);
+        } catch (IllegalArgumentException e) {
+            errors.add("allow", new ActionError("error.syntax"));
+            return errors;
+        }
+                 
+        String host = request.getRemoteHost();
+        // check for IP address also in case DNS is not configured 
+        // to give a host name for the client machine
+        String ip = request.getRemoteAddr();
+    
+        if (host == null) {
+            return errors;
+        }
+        
+        for (int i = 0; i < denies.length; i++) {
+            if (denies[i].matcher(host).matches()) {
+                if (allows.length < 1) {
+                    errors.add("deny",
+                        new ActionError("error.denyHost"));
+                }    
+                for (int j = 0; j < allows.length; j++) {
+                    if (!allows[j].matcher(host).matches()) { 
+                        errors.add("deny",
+                        new ActionError("error.denyHost"));
+                    }
+                }
+            } else if (denies[i].matcher(ip).matches()) {
+                if (allows.length < 1) {
+                    errors.add("deny",
+                        new ActionError("error.denyHost"));
+                }               
+                for (int j = 0; j < allows.length; j++) {
+                    if (!allows[j].matcher(ip).matches()) { 
+                        errors.add("deny",
+                        new ActionError("error.denyHost"));
+                    }
+                }
+            }
+        }
+        
+        boolean allowMatch = true;
+        
+        if ((allows != null) && (allows.length > 0)) {
+            allowMatch = false;
+        }
+        
+        for (int i = 0; i < allows.length; i++) {
+            if (allows[i].matcher(host).matches()) {
+                allowMatch = true;       
+            }
+        }
+        
+        if (!allowMatch) {
+            errors.add("allow", new ActionError("error.allowHost"));
+        }        
+        
+        return errors;
+    }
+    
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/valve/RequestDumperValveForm.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/valve/RequestDumperValveForm.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/valve/RequestDumperValveForm.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2001,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.admin.valve;
+
+import javax.servlet.http.HttpServletRequest;
+import org.apache.struts.action.ActionError;
+import org.apache.struts.action.ActionErrors;
+import org.apache.struts.action.ActionForm;
+import org.apache.struts.action.ActionMapping;
+import java.util.List;
+
+/**
+ * Form bean for the Request Dumper valve page.
+ *
+ * @author Manveen Kaur
+ * @version $Revision: 302986 $ $Date: 2004-06-27 21:14:52 -0500 (Sun, 27 Jun 2004) $
+ */
+
+public final class RequestDumperValveForm extends ValveForm {
+        
+    // ----------------------------------------------------- Instance Variables
+
+    
+    // ------------------------------------------------------------- Properties
+    
+        
+    // --------------------------------------------------------- Public Methods
+    
+    /**
+     * Reset all properties to their default values.
+     *
+     * @param mapping The mapping used to select this instance
+     * @param request The servlet request we are processing
+     */
+    public void reset(ActionMapping mapping, HttpServletRequest request) {
+    
+        super.reset(mapping, request);
+    }
+    
+    
+    /**
+     * Render this object as a String.
+     */
+    public String toString() {
+
+        StringBuffer sb = new StringBuffer("RequestDumperValveForm[adminAction=");
+        sb.append(getAdminAction());
+        sb.append("',valveType=");
+        sb.append(getValveType());
+        sb.append("',objectName='");
+        sb.append(getObjectName());
+        sb.append("]");
+        return (sb.toString());
+
+    }
+    
+    /**
+     * Validate the properties that have been set from this HTTP request,
+     * and return an <code>ActionErrors</code> object that encapsulates any
+     * validation errors that have been found.  If no errors are found, return
+     * <code>null</code> or an <code>ActionErrors</code> object with no
+     * recorded error messages.
+     *
+     * @param mapping The mapping used to select this instance
+     * @param request The servlet request we are processing
+     */
+    
+    public ActionErrors validate(ActionMapping mapping,
+    HttpServletRequest request) {
+        
+        ActionErrors errors = new ActionErrors();
+        
+        String submit = request.getParameter("submit");
+        
+        // front end validation when save is clicked.        
+         if (submit != null) {
+         // no validation needed
+        }
+                 
+        return errors;
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/valve/SaveAccessLogValveAction.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/valve/SaveAccessLogValveAction.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/valve/SaveAccessLogValveAction.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,153 @@
+/*
+ * Copyright 2001-2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.admin.valve;
+
+import java.util.Locale;
+import java.io.IOException;
+import javax.management.Attribute;
+import javax.management.MBeanServer;
+import javax.management.MBeanServerFactory;
+import javax.management.QueryExp;
+import javax.management.Query;
+import javax.management.ObjectName;
+import javax.management.JMException;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+import org.apache.struts.action.Action;
+import org.apache.struts.action.ActionError;
+import org.apache.struts.action.ActionErrors;
+import org.apache.struts.action.ActionForm;
+import org.apache.struts.action.ActionForward;
+import org.apache.struts.action.ActionMapping;
+import org.apache.struts.util.MessageResources;
+import org.apache.webapp.admin.ApplicationServlet;
+
+/**
+ * The <code>Action</code> that completes <em>Add Valve</em> and
+ * <em>Edit Valve</em> transactions for AccessLog valve.
+ *
+ * @author Manveen Kaur
+ * @version $Revision: 303390 $ $Date: 2004-10-18 01:37:56 -0500 (Mon, 18 Oct 2004) $
+ */
+
+public final class SaveAccessLogValveAction extends Action {
+
+
+    // ----------------------------------------------------- Instance Variables
+
+    /**
+     * The MBeanServer we will be interacting with.
+     */
+    private MBeanServer mBServer = null;
+    
+    // --------------------------------------------------------- Public Methods
+    
+    
+    /**
+     * Process the specified HTTP request, and create the corresponding HTTP
+     * response (or forward to another web component that will create it).
+     * Return an <code>ActionForward</code> instance describing where and how
+     * control should be forwarded, or <code>null</code> if the response has
+     * already been completed.
+     *
+     * @param mapping The ActionMapping used to select this instance
+     * @param actionForm The optional ActionForm bean for this request (if any)
+     * @param request The HTTP request we are processing
+     * @param response The HTTP response we are creating
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception ServletException if a servlet exception occurs
+     */
+    public ActionForward execute(ActionMapping mapping,
+                                 ActionForm form,
+                                 HttpServletRequest request,
+                                 HttpServletResponse response)
+        throws IOException, ServletException {
+        
+        // Acquire the resources that we need
+        HttpSession session = request.getSession();
+        Locale locale = getLocale(request);
+        MessageResources resources = getResources(request);
+        
+        // Acquire a reference to the MBeanServer containing our MBeans
+        try {
+            mBServer = ((ApplicationServlet) getServlet()).getServer();
+        } catch (Throwable t) {
+            throw new ServletException
+            ("Cannot acquire MBeanServer reference", t);
+        }
+        
+        // Identify the requested action
+        AccessLogValveForm vform = (AccessLogValveForm) form;
+        String adminAction = vform.getAdminAction();
+        String vObjectName = vform.getObjectName();
+        String parent = vform.getParentObjectName();
+        String valveType = vform.getValveType();
+        
+        // Perform a "Create Valve" transaction (if requested)
+        if ("Create".equals(adminAction)) {
+        
+            vObjectName = ValveUtil.createValve(parent, valveType, 
+                                response, request, mapping, 
+                                (ApplicationServlet) getServlet());
+           
+        }
+
+        // Perform attribute updates as requested
+        String attribute = null;
+        try {
+        
+            ObjectName voname = new ObjectName(vObjectName);
+            
+            attribute = "directory";
+            mBServer.setAttribute(voname,
+                         new Attribute("directory", vform.getDirectory()));
+            attribute = "pattern";
+            mBServer.setAttribute(voname,
+                        new Attribute("pattern", vform.getPattern()));
+            attribute = "prefix";
+            mBServer.setAttribute(voname,
+                        new Attribute("prefix", vform.getPrefix()));
+            attribute = "suffix";
+            mBServer.setAttribute(voname,
+                        new Attribute("suffix", vform.getSuffix()));
+            attribute = "resolveHosts";
+            mBServer.setAttribute(voname,
+                        new Attribute("resolveHosts", new Boolean(vform.getResolveHosts())));
+            attribute = "rotatable";
+            mBServer.setAttribute(voname,
+                        new Attribute("rotatable", new Boolean(vform.getRotatable())));
+
+        } catch (Exception e) {
+
+            getServlet().log
+                (resources.getMessage(locale, "users.error.attribute.set",
+                                      attribute), e);
+            response.sendError
+                (HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
+                 resources.getMessage(locale, "users.error.attribute.set",
+                                      attribute));
+            return (null);
+        }
+    
+        // Forward to the success reporting page
+        session.removeAttribute(mapping.getAttribute());
+        return (mapping.findForward("Save Successful"));
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/valve/SaveRemoteAddrValveAction.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/valve/SaveRemoteAddrValveAction.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/valve/SaveRemoteAddrValveAction.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,141 @@
+/*
+ * Copyright 2001-2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.admin.valve;
+
+import java.util.Locale;
+import java.io.IOException;
+import javax.management.Attribute;
+import javax.management.MBeanServer;
+import javax.management.MBeanServerFactory;
+import javax.management.QueryExp;
+import javax.management.Query;
+import javax.management.ObjectName;
+import javax.management.JMException;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+import org.apache.struts.action.Action;
+import org.apache.struts.action.ActionError;
+import org.apache.struts.action.ActionErrors;
+import org.apache.struts.action.ActionForm;
+import org.apache.struts.action.ActionForward;
+import org.apache.struts.action.ActionMapping;
+import org.apache.struts.util.MessageResources;
+import org.apache.webapp.admin.ApplicationServlet;
+
+/**
+ * The <code>Action</code> that completes <em>Add Valve</em> and
+ * <em>Edit Valve</em> transactions for Remote Addr valve.
+ *
+ * @author Manveen Kaur
+ * @version $Revision: 303390 $ $Date: 2004-10-18 01:37:56 -0500 (Mon, 18 Oct 2004) $
+ */
+
+public final class SaveRemoteAddrValveAction extends Action {
+
+
+    // ----------------------------------------------------- Instance Variables
+
+    /**
+     * The MBeanServer we will be interacting with.
+     */
+    private MBeanServer mBServer = null;
+    
+    // --------------------------------------------------------- Public Methods
+    
+    
+    /**
+     * Process the specified HTTP request, and create the corresponding HTTP
+     * response (or forward to another web component that will create it).
+     * Return an <code>ActionForward</code> instance describing where and how
+     * control should be forwarded, or <code>null</code> if the response has
+     * already been completed.
+     *
+     * @param mapping The ActionMapping used to select this instance
+     * @param actionForm The optional ActionForm bean for this request (if any)
+     * @param request The HTTP request we are processing
+     * @param response The HTTP response we are creating
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception ServletException if a servlet exception occurs
+     */
+    public ActionForward execute(ActionMapping mapping,
+                                 ActionForm form,
+                                 HttpServletRequest request,
+                                 HttpServletResponse response)
+        throws IOException, ServletException {
+        
+        // Acquire the resources that we need
+        HttpSession session = request.getSession();
+        Locale locale = getLocale(request);
+        MessageResources resources = getResources(request);
+        
+        // Acquire a reference to the MBeanServer containing our MBeans
+        try {
+            mBServer = ((ApplicationServlet) getServlet()).getServer();
+        } catch (Throwable t) {
+            throw new ServletException
+            ("Cannot acquire MBeanServer reference", t);
+        }
+        
+        // Identify the requested action
+        RemoteAddrValveForm vform = (RemoteAddrValveForm) form;
+        String adminAction = vform.getAdminAction();
+        String vObjectName = vform.getObjectName();
+        String parent = vform.getParentObjectName();
+        String valveType = vform.getValveType();
+               
+        // Perform a "Create Valve" transaction (if requested)
+        if ("Create".equals(adminAction)) {
+
+            vObjectName = ValveUtil.createValve(parent, valveType, 
+                                response, request, mapping, 
+                                (ApplicationServlet) getServlet());
+           
+        }
+
+        // Perform attribute updates as requested
+        String attribute = null;
+        try {
+        
+            ObjectName voname = new ObjectName(vObjectName);
+            
+            attribute = "allow";
+            mBServer.setAttribute(voname,
+                                  new Attribute("allow", vform.getAllow()));
+            attribute = "deny";
+            mBServer.setAttribute(voname,
+                    new Attribute("deny", vform.getDeny()));
+
+        } catch (Exception e) {
+
+            getServlet().log
+                (resources.getMessage(locale, "users.error.attribute.set",
+                                      attribute), e);
+            response.sendError
+                (HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
+                 resources.getMessage(locale, "users.error.attribute.set",
+                                      attribute));
+            return (null);
+        }
+    
+        // Forward to the success reporting page
+        session.removeAttribute(mapping.getAttribute());
+        return (mapping.findForward("Save Successful"));
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/valve/SaveRemoteHostValveAction.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/valve/SaveRemoteHostValveAction.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/valve/SaveRemoteHostValveAction.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,141 @@
+/*
+ * Copyright 2001-2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.admin.valve;
+
+import java.util.Locale;
+import java.io.IOException;
+import javax.management.Attribute;
+import javax.management.MBeanServer;
+import javax.management.MBeanServerFactory;
+import javax.management.QueryExp;
+import javax.management.Query;
+import javax.management.ObjectInstance;
+import javax.management.ObjectName;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+import org.apache.struts.action.Action;
+import org.apache.struts.action.ActionError;
+import org.apache.struts.action.ActionErrors;
+import org.apache.struts.action.ActionForm;
+import org.apache.struts.action.ActionForward;
+import org.apache.struts.action.ActionMapping;
+import org.apache.struts.util.MessageResources;
+import org.apache.webapp.admin.ApplicationServlet;
+
+/**
+ * The <code>Action</code> that completes <em>Add Valve</em> and
+ * <em>Edit Valve</em> transactions for Remote Host valve.
+ *
+ * @author Manveen Kaur
+ * @version $Revision: 303390 $ $Date: 2004-10-18 01:37:56 -0500 (Mon, 18 Oct 2004) $
+ */
+
+public final class SaveRemoteHostValveAction extends Action {
+
+
+    // ----------------------------------------------------- Instance Variables
+
+    /**
+     * The MBeanServer we will be interacting with.
+     */
+    private MBeanServer mBServer = null;
+    
+    // --------------------------------------------------------- Public Methods
+    
+    
+    /**
+     * Process the specified HTTP request, and create the corresponding HTTP
+     * response (or forward to another web component that will create it).
+     * Return an <code>ActionForward</code> instance describing where and how
+     * control should be forwarded, or <code>null</code> if the response has
+     * already been completed.
+     *
+     * @param mapping The ActionMapping used to select this instance
+     * @param actionForm The optional ActionForm bean for this request (if any)
+     * @param request The HTTP request we are processing
+     * @param response The HTTP response we are creating
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception ServletException if a servlet exception occurs
+     */
+    public ActionForward execute(ActionMapping mapping,
+                                 ActionForm form,
+                                 HttpServletRequest request,
+                                 HttpServletResponse response)
+        throws IOException, ServletException {
+        
+        // Acquire the resources that we need
+        HttpSession session = request.getSession();
+        Locale locale = getLocale(request);
+        MessageResources resources = getResources(request);
+        
+        // Acquire a reference to the MBeanServer containing our MBeans
+        try {
+            mBServer = ((ApplicationServlet) getServlet()).getServer();
+        } catch (Throwable t) {
+            throw new ServletException
+            ("Cannot acquire MBeanServer reference", t);
+        }
+        
+        // Identify the requested action
+        RemoteHostValveForm vform = (RemoteHostValveForm) form;
+        String adminAction = vform.getAdminAction();
+        String vObjectName = vform.getObjectName();
+        String parent = vform.getParentObjectName();
+        String valveType = vform.getValveType();
+               
+        // Perform a "Create Valve" transaction (if requested)
+        if ("Create".equals(adminAction)) {
+
+            vObjectName = ValveUtil.createValve(parent, valveType, 
+                                response, request, mapping, 
+                                (ApplicationServlet) getServlet());
+           
+        }
+
+        // Perform attribute updates as requested
+        String attribute = null;
+        try {
+        
+            ObjectName voname = new ObjectName(vObjectName);
+            
+            attribute = "allow";
+            mBServer.setAttribute(voname,
+                                  new Attribute("allow", vform.getAllow()));
+            attribute = "deny";
+            mBServer.setAttribute(voname,
+                    new Attribute("deny", vform.getDeny()));
+
+        } catch (Exception e) {
+
+            getServlet().log
+                (resources.getMessage(locale, "users.error.attribute.set",
+                                      attribute), e);
+            response.sendError
+                (HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
+                 resources.getMessage(locale, "users.error.attribute.set",
+                                      attribute));
+            return (null);
+        }
+    
+        // Forward to the success reporting page
+        session.removeAttribute(mapping.getAttribute());
+        return (mapping.findForward("Save Successful"));
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/valve/SaveRequestDumperValveAction.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/valve/SaveRequestDumperValveAction.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/valve/SaveRequestDumperValveAction.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,119 @@
+/*
+ * Copyright 2001-2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.admin.valve;
+
+import java.util.Locale;
+import java.io.IOException;
+import javax.management.Attribute;
+import javax.management.MBeanServer;
+import javax.management.MBeanServerFactory;
+import javax.management.QueryExp;
+import javax.management.Query;
+import javax.management.ObjectName;
+import javax.management.JMException;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+import org.apache.struts.action.Action;
+import org.apache.struts.action.ActionError;
+import org.apache.struts.action.ActionErrors;
+import org.apache.struts.action.ActionForm;
+import org.apache.struts.action.ActionForward;
+import org.apache.struts.action.ActionMapping;
+import org.apache.struts.util.MessageResources;
+import org.apache.webapp.admin.ApplicationServlet;
+
+/**
+ * The <code>Action</code> that completes <em>Add Valve</em> and
+ * <em>Edit Valve</em> transactions for Request Dumper valve.
+ *
+ * @author Manveen Kaur
+ * @version $Revision: 303390 $ $Date: 2004-10-18 01:37:56 -0500 (Mon, 18 Oct 2004) $
+ */
+
+public final class SaveRequestDumperValveAction extends Action {
+
+
+    // ----------------------------------------------------- Instance Variables
+
+    /**
+     * The MBeanServer we will be interacting with.
+     */
+    private MBeanServer mBServer = null;
+    
+    // --------------------------------------------------------- Public Methods
+    
+    
+    /**
+     * Process the specified HTTP request, and create the corresponding HTTP
+     * response (or forward to another web component that will create it).
+     * Return an <code>ActionForward</code> instance describing where and how
+     * control should be forwarded, or <code>null</code> if the response has
+     * already been completed.
+     *
+     * @param mapping The ActionMapping used to select this instance
+     * @param actionForm The optional ActionForm bean for this request (if any)
+     * @param request The HTTP request we are processing
+     * @param response The HTTP response we are creating
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception ServletException if a servlet exception occurs
+     */
+    public ActionForward execute(ActionMapping mapping,
+                                 ActionForm form,
+                                 HttpServletRequest request,
+                                 HttpServletResponse response)
+        throws IOException, ServletException {
+        
+        // Acquire the resources that we need
+        HttpSession session = request.getSession();
+        Locale locale = getLocale(request);
+        MessageResources resources = getResources(request);
+        
+        // Acquire a reference to the MBeanServer containing our MBeans
+        try {
+            mBServer = ((ApplicationServlet) getServlet()).getServer();
+        } catch (Throwable t) {
+            throw new ServletException
+            ("Cannot acquire MBeanServer reference", t);
+        }
+        
+        // Identify the requested action
+        RequestDumperValveForm vform = (RequestDumperValveForm) form;
+        String adminAction = vform.getAdminAction();
+        String vObjectName = vform.getObjectName();
+        String parent = vform.getParentObjectName();
+        String valveType = vform.getValveType();
+            
+        // Perform a "Create Valve" transaction (if requested)
+        if ("Create".equals(adminAction)) {
+        
+            vObjectName = ValveUtil.createValve(parent, valveType, 
+                                response, request, mapping, 
+                                (ApplicationServlet) getServlet());
+           
+        }
+
+        // Perform attribute updates as requested
+        String attribute = null;
+                
+        // Forward to the success reporting page
+        session.removeAttribute(mapping.getAttribute());
+        return (mapping.findForward("Save Successful"));
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/valve/SaveSingleSignOnValveAction.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/valve/SaveSingleSignOnValveAction.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/valve/SaveSingleSignOnValveAction.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,146 @@
+/*
+ * Copyright 2001-2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.admin.valve;
+
+import java.util.Locale;
+import java.io.IOException;
+import javax.management.Attribute;
+import javax.management.MBeanServer;
+import javax.management.MBeanServerFactory;
+import javax.management.QueryExp;
+import javax.management.Query;
+import javax.management.ObjectInstance;
+import javax.management.ObjectName;
+import javax.management.JMException;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+import org.apache.struts.action.Action;
+import org.apache.struts.action.ActionError;
+import org.apache.struts.action.ActionErrors;
+import org.apache.struts.action.ActionForm;
+import org.apache.struts.action.ActionForward;
+import org.apache.struts.action.ActionMapping;
+import org.apache.struts.util.MessageResources;
+import org.apache.webapp.admin.ApplicationServlet;
+
+/**
+ * The <code>Action</code> that completes <em>Add Valve</em> and
+ * <em>Edit Valve</em> transactions for Single Sign On valve.
+ *
+ * @author Manveen Kaur
+ * @version $Revision: 303390 $ $Date: 2004-10-18 01:37:56 -0500 (Mon, 18 Oct 2004) $
+ */
+
+public final class SaveSingleSignOnValveAction extends Action {
+
+
+    // ----------------------------------------------------- Instance Variables
+
+    /**
+     * The MBeanServer we will be interacting with.
+     */
+    private MBeanServer mBServer = null;
+    
+    // --------------------------------------------------------- Public Methods
+    
+    
+    /**
+     * Process the specified HTTP request, and create the corresponding HTTP
+     * response (or forward to another web component that will create it).
+     * Return an <code>ActionForward</code> instance describing where and how
+     * control should be forwarded, or <code>null</code> if the response has
+     * already been completed.
+     *
+     * @param mapping The ActionMapping used to select this instance
+     * @param actionForm The optional ActionForm bean for this request (if any)
+     * @param request The HTTP request we are processing
+     * @param response The HTTP response we are creating
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception ServletException if a servlet exception occurs
+     */
+    public ActionForward execute(ActionMapping mapping,
+                                 ActionForm form,
+                                 HttpServletRequest request,
+                                 HttpServletResponse response)
+        throws IOException, ServletException {
+        
+        // Acquire the resources that we need
+        HttpSession session = request.getSession();
+        Locale locale = getLocale(request);
+        MessageResources resources = getResources(request);
+        
+        // Acquire a reference to the MBeanServer containing our MBeans
+        try {
+            mBServer = ((ApplicationServlet) getServlet()).getServer();
+        } catch (Throwable t) {
+            throw new ServletException
+            ("Cannot acquire MBeanServer reference", t);
+        }
+        
+        // Identify the requested action
+        SingleSignOnValveForm vform = (SingleSignOnValveForm) form;
+        String adminAction = vform.getAdminAction();
+        String vObjectName = vform.getObjectName();
+        String parent = vform.getParentObjectName();
+        String valveType = vform.getValveType();
+               
+        // Perform a "Create Valve" transaction (if requested)
+        if ("Create".equals(adminAction)) {
+
+            try {
+                // Ensure that only one single sign on valve exists
+                ObjectName pname = new ObjectName(parent); 
+                ObjectName oname = 
+                        new ObjectName(pname.getDomain() + 
+                                    ":type=Valve,name=SingleSignOn");               
+                
+                if (mBServer.isRegistered(oname)) {
+                    ActionErrors errors = new ActionErrors();
+                    errors.add("singleSignOnValve",
+                               new ActionError("error.singleSignOn.exists"));
+                    saveErrors(request, errors);
+                    return (new ActionForward(mapping.getInput()));
+                } 
+            } catch (Exception e) {
+                getServlet().log
+                    (resources.getMessage(locale, "users.error.invoke",
+                                          adminAction), e);
+                response.sendError
+                    (HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
+                     resources.getMessage(locale, "users.error.invoke",
+                                          adminAction));
+                return (null);
+
+            }
+            
+            vObjectName = ValveUtil.createValve(parent, valveType, 
+                                response, request, mapping, 
+                                (ApplicationServlet) getServlet());
+                      
+        }
+
+        // Perform attribute updates as requested
+        String attribute = null;
+    
+        // Forward to the success reporting page
+        session.removeAttribute(mapping.getAttribute());
+        return (mapping.findForward("Save Successful"));
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/valve/SingleSignOnValveForm.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/valve/SingleSignOnValveForm.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/valve/SingleSignOnValveForm.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,98 @@
+/*
+ * Copyright 2001,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.admin.valve;
+
+import javax.servlet.http.HttpServletRequest;
+import org.apache.struts.action.ActionError;
+import org.apache.struts.action.ActionErrors;
+import org.apache.struts.action.ActionForm;
+import org.apache.struts.action.ActionMapping;
+import java.net.InetAddress;
+import java.util.List;
+
+import org.apache.webapp.admin.ApplicationServlet;
+import org.apache.webapp.admin.LabelValueBean;
+
+/**
+ * Form bean for the single sign on valve page.
+ *
+ * @author Manveen Kaur
+ * @version $Revision: 302986 $ $Date: 2004-06-27 21:14:52 -0500 (Sun, 27 Jun 2004) $
+ */
+
+public final class SingleSignOnValveForm extends ValveForm {
+    
+    // ----------------------------------------------------- Instance Variables
+
+    // ------------------------------------------------------------- Properties
+    
+    // --------------------------------------------------------- Public Methods
+    
+    /**
+     * Reset all properties to their default values.
+     *
+     * @param mapping The mapping used to select this instance
+     * @param request The servlet request we are processing
+     */
+    public void reset(ActionMapping mapping, HttpServletRequest request) {
+    
+        super.reset(mapping, request);
+        
+    }
+    
+    /**
+     * Render this object as a String.
+     */
+    public String toString() {
+
+        StringBuffer sb = new StringBuffer("SingleSignOnValveForm[adminAction=");
+        sb.append(getAdminAction());
+        sb.append("',valveType=");
+        sb.append(getValveType());
+        sb.append("',objectName='");
+        sb.append(getObjectName());
+        sb.append("]");
+        return (sb.toString());
+
+    }
+    
+    /**
+     * Validate the properties that have been set from this HTTP request,
+     * and return an <code>ActionErrors</code> object that encapsulates any
+     * validation errors that have been found.  If no errors are found, return
+     * <code>null</code> or an <code>ActionErrors</code> object with no
+     * recorded error messages.
+     *
+     * @param mapping The mapping used to select this instance
+     * @param request The servlet request we are processing
+     */
+    
+    public ActionErrors validate(ActionMapping mapping,
+    HttpServletRequest request) {
+        
+        ActionErrors errors = new ActionErrors();
+        
+        String submit = request.getParameter("submit");
+        
+        // front end validation when save is clicked.        
+         if (submit != null) {
+             // no validation needed
+         }
+                 
+        return errors;
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/valve/ValveForm.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/valve/ValveForm.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/valve/ValveForm.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,203 @@
+/*
+ * Copyright 2001,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.admin.valve;
+
+import javax.servlet.http.HttpServletRequest;
+import org.apache.struts.action.ActionError;
+import org.apache.struts.action.ActionErrors;
+import org.apache.struts.action.ActionForm;
+import org.apache.struts.action.ActionMapping;
+import java.net.InetAddress;
+import java.util.List;
+
+import org.apache.webapp.admin.ApplicationServlet;
+import org.apache.webapp.admin.LabelValueBean;
+
+/**
+ * Form bean for the generic valve page.
+ *
+ * @author Manveen Kaur
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class ValveForm extends ActionForm {
+    
+    // ----------------------------------------------------- Instance Variables
+    
+   /**
+     * The administrative action represented by this form.
+     */
+    private String adminAction = "Edit";
+
+    /**
+     * The object name of the valve this bean refers to.
+     */
+    private String objectName = null;
+
+    /**
+     * The text for the valve name, used to retrieve
+     * the corresponding valve mBean.
+     */
+    private String valveName = null;
+    
+    /**
+     * The text for the valve type.
+     */
+    private String valveType = null;
+        
+    /**
+     * The text for the node label.
+     */
+    private String nodeLabel = null;
+    
+    /**
+     * The object name of the parent of this valve.
+     */
+    private String parentObjectName = null;
+
+    /**
+     * Set of valid values for valves.
+     */
+    private List valveTypeVals = null;
+    
+    // ------------------------------------------------------------- Properties
+
+       /**
+     * Return the administrative action represented by this form.
+     */
+    public String getAdminAction() {
+
+        return this.adminAction;
+
+    }
+
+    /**
+     * Set the administrative action represented by this form.
+     */
+    public void setAdminAction(String adminAction) {
+
+        this.adminAction = adminAction;
+
+    }
+
+    /**
+     * Return the Object Name.
+     */
+    public String getObjectName() {
+        
+        return this.objectName;
+        
+    }
+    
+    /**
+     * Set the Object Name.
+     */
+    public void setObjectName(String objectName) {
+        
+        this.objectName = objectName;
+        
+    }
+    
+    /**
+     * Return the valve type.
+     */
+    public String getValveType() {
+        
+        return this.valveType;
+        
+    }
+    
+    /**
+     * Set the valve type.
+     */
+    public void setValveType(String valveType) {
+        
+        this.valveType = valveType;
+        
+    }
+    
+    /**
+     * Return the label of the node that was clicked.
+     */
+    public String getNodeLabel() {
+        
+        return this.nodeLabel;
+        
+    }
+    
+    /**
+     * Set the node label.
+     */
+    public void setNodeLabel(String nodeLabel) {
+        
+        this.nodeLabel = nodeLabel;
+        
+    }
+    
+    /**
+     * Return the parent object name of the valve this bean refers to.
+     */
+    public String getParentObjectName() {
+
+        return this.parentObjectName;
+
+    }
+
+
+    /**
+     * Set the parent object name of the valve this bean refers to.
+     */
+    public void setParentObjectName(String parentObjectName) {
+
+        this.parentObjectName = parentObjectName;
+
+    }
+    
+        
+   /**
+     * Return the valveTypeVals.
+     */
+    public List getValveTypeVals() {
+        
+        return this.valveTypeVals;
+        
+    }
+    
+    /**
+     * Set the valveTypeVals.
+     */
+    public void setValveTypeVals(List valveTypeVals) {
+        
+        this.valveTypeVals = valveTypeVals;
+        
+    }
+    
+    // --------------------------------------------------------- Public Methods
+    
+    /**
+     * Reset all properties to their default values.
+     *
+     * @param mapping The mapping used to select this instance
+     * @param request The servlet request we are processing
+     */
+    public void reset(ActionMapping mapping, HttpServletRequest request) {
+        
+        objectName = null;
+        
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/valve/ValveUtil.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/valve/ValveUtil.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/valve/ValveUtil.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,272 @@
+/*
+ * Copyright 2001-2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.admin.valve;
+
+import java.net.URLEncoder;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.Locale;
+import java.io.IOException;
+import java.util.regex.Pattern;
+import java.util.regex.PatternSyntaxException;
+import javax.management.Attribute;
+import javax.management.MBeanServer;
+import javax.management.MBeanServerFactory;
+import javax.management.QueryExp;
+import javax.management.Query;
+import javax.management.ObjectInstance;
+import javax.management.ObjectName;
+import javax.management.JMException;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+import org.apache.struts.Globals;
+import org.apache.struts.action.Action;
+import org.apache.struts.action.ActionError;
+import org.apache.struts.action.ActionErrors;
+import org.apache.struts.action.ActionForm;
+import org.apache.struts.action.ActionForward;
+import org.apache.struts.action.ActionMapping;
+import org.apache.struts.util.MessageResources;
+import org.apache.webapp.admin.ApplicationServlet;
+import org.apache.webapp.admin.TomcatTreeBuilder;
+import org.apache.webapp.admin.TreeControl;
+import org.apache.webapp.admin.TreeControlNode;
+
+/**
+ * A utility class that contains methods common across valves.
+ *
+ * @author Manveen Kaur
+ * @version $Revision: 303390 $ $Date: 2004-10-18 01:37:56 -0500 (Mon, 18 Oct 2004) $
+ */
+
+public final class ValveUtil {
+    
+    
+    // ----------------------------------------------------- Instance Variables
+    
+    /**
+     * Signature for the <code>createStandardValve</code> operation.
+     */
+    private static String createStandardValveTypes[] =
+    { "java.lang.String",     // parent
+    };
+    
+    
+    // --------------------------------------------------------- Public Methods
+    
+    public static String createValve(String parent, String valveType,
+    HttpServletResponse response, HttpServletRequest request,
+    ActionMapping mapping, ApplicationServlet servlet)
+    throws IOException, ServletException {
+        
+        MessageResources resources = (MessageResources)
+            servlet.getServletContext().getAttribute(Globals.MESSAGES_KEY);
+        HttpSession session = request.getSession();
+        
+        MBeanServer mBServer = null;
+        Locale locale = (Locale) session.getAttribute(Globals.LOCALE_KEY);
+        // Acquire a reference to the MBeanServer containing our MBeans
+        try {
+            mBServer = servlet.getServer();
+        } catch (Throwable t) {
+            throw new ServletException
+            ("Cannot acquire MBeanServer reference", t);
+        }
+        
+        String operation = null;
+        String values[] = null;
+        String vObjectName = null;
+        
+        try {
+            
+            String objectName = ValveUtil.getObjectName(parent,
+            TomcatTreeBuilder.VALVE_TYPE);
+                        
+            String parentNodeName = parent;
+            ObjectName pname = new ObjectName(parent);
+            StringBuffer sb = new StringBuffer(pname.getDomain());
+            
+            // For service, create the corresponding Engine mBean
+            // Parent in this case needs to be the container mBean for the service
+            try {
+                if ("Service".equalsIgnoreCase(pname.getKeyProperty("type"))) {
+                    sb.append(":type=Engine");
+                    parent = sb.toString();
+                }
+            } catch (Exception e) {
+                String message = resources.getMessage("error.engineName.bad",
+                sb.toString());
+                servlet.log(message);
+                response.sendError(HttpServletResponse.SC_BAD_REQUEST, message);
+                return (null);
+            }    
+            // Ensure that the requested valve name is unique
+            
+            // TBD -- do we need this check?
+            /*
+            ObjectName oname =
+            new ObjectName(objectName);
+            if (mBServer.isRegistered(oname)) {
+                ActionErrors errors = new ActionErrors();
+                errors.add("valveName",
+                    new ActionError("error.valveName.exists"));
+                String message =
+                    resources.getMessage(locale, "error.valveName.exists", sb.toString());
+                response.sendError(HttpServletResponse.SC_BAD_REQUEST, message);                
+                return (new ActionForward(mapping.getInput()));
+            }
+            */
+            
+            String domain = pname.getDomain();
+            // Look up our MBeanFactory MBean
+            ObjectName fname = TomcatTreeBuilder.getMBeanFactory();
+            
+            // Create a new StandardValve object
+            values = new String[1];            
+            values[0] = parent;           
+            
+            operation = "create" + valveType;
+            if ("AccessLogValve".equalsIgnoreCase(valveType))
+                operation = "createAccessLoggerValve";
+                
+            vObjectName = (String)
+                        mBServer.invoke(fname, operation, values, createStandardValveTypes);
+            
+            // Add the new Valve to our tree control node
+            TreeControl control = (TreeControl)
+            session.getAttribute("treeControlTest");
+            if (control != null) {
+                TreeControlNode parentNode = control.findNode(parentNodeName);
+                if (parentNode != null) {
+                    String nodeLabel =
+                    "Valve for " + parentNode.getLabel();
+                    String encodedName =
+                    URLEncoder.encode(vObjectName,TomcatTreeBuilder.URL_ENCODING);
+                    TreeControlNode childNode =
+                    new TreeControlNode(vObjectName,
+                    "Valve.gif",
+                    nodeLabel,
+                    "EditValve.do?select=" + encodedName +
+                    "&nodeLabel=" + URLEncoder.encode(nodeLabel,TomcatTreeBuilder.URL_ENCODING) +
+                    "&parent=" + URLEncoder.encode(parentNodeName,TomcatTreeBuilder.URL_ENCODING),
+                    "content",
+                    true, domain);
+                    parentNode.addChild(childNode);
+                    // FIXME - force a redisplay
+                } else {
+                    servlet.log
+                    ("Cannot find parent node '" + parentNodeName + "'");
+                }
+            } else {
+                servlet.log
+                ("Cannot find TreeControlNode!");
+            }
+            
+        } catch (Exception e) {
+            
+            servlet.log
+            (resources.getMessage(locale, "users.error.invoke",
+            operation), e);
+            response.sendError
+            (HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
+            resources.getMessage(locale, "users.error.invoke",
+            operation));
+            return (null);
+            
+        }
+        
+        // Forward to the success reporting page
+        session.removeAttribute(mapping.getAttribute());
+        return vObjectName;
+    }
+
+    
+    /**
+     * Return an array of regular expression objects initialized from the
+     * specified argument, which must be <code>null</code> or a comma-delimited
+     * list of regular expression patterns.
+     *
+     * @param list The comma-separated list of patterns
+     *
+     * @exception IllegalArgumentException if one of the patterns has
+     *  invalid syntax
+     */
+    public static Pattern[] precalculate(String list) 
+                                    throws IllegalArgumentException {
+
+        if (list == null)
+            return (new Pattern[0]);
+        list = list.trim();
+        if (list.length() < 1)
+            return (new Pattern[0]);
+        list += ",";
+
+        ArrayList reList = new ArrayList();
+        while (list.length() > 0) {
+            int comma = list.indexOf(',');
+            if (comma < 0)
+                break;
+            String pattern = list.substring(0, comma).trim();
+            try {
+                reList.add(Pattern.compile(pattern));
+            } catch (PatternSyntaxException e) {
+                throw new IllegalArgumentException
+                    ("Syntax error in request filter pattern");
+            }
+            list = list.substring(comma + 1);
+        }
+
+        Pattern reArray[] = new Pattern[reList.size()];
+        return ((Pattern[]) reList.toArray(reArray));
+
+    }    
+
+    public static String getObjectName(String parent, String MBeanType)
+    throws Exception{
+        
+        // Form the pattern that gets the logger for this particular
+        // service, host or context.
+        ObjectName poname = new ObjectName(parent);
+        String domain = poname.getDomain();
+        StringBuffer sb = new StringBuffer(domain+MBeanType);
+        String type = poname.getKeyProperty("type");
+        String j2eeType = poname.getKeyProperty("j2eeType");
+        String path = "";
+        String host = "";
+        String name = poname.getKeyProperty("name");
+        if ((name != null) && (name.length() > 0)) {
+            name = name.substring(2);
+            int i = name.indexOf("/");
+            host = name.substring(0,i);
+            path = name.substring(i); 
+        }
+        if ("WebModule".equalsIgnoreCase(j2eeType)) { // container is context            
+            sb.append(",path="+path);
+            sb.append(",host="+host);
+        }
+        if ("Host".equalsIgnoreCase(type)) {    // container is host
+            sb.append(",host=");
+            sb.append(poname.getKeyProperty("host"));
+        }
+        if ("Service".equalsIgnoreCase(type)) {  // container is service
+        }
+        return sb.toString();  
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/valve/ValvesForm.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/valve/ValvesForm.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/classes/org/apache/webapp/admin/valve/ValvesForm.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.admin.valve;
+
+
+import javax.servlet.http.HttpServletRequest;
+import org.apache.struts.action.ActionForm;
+import org.apache.struts.action.ActionMapping;
+
+
+/**
+ * Form bean for deleting valves.
+ *
+ * @author Manveen Kaur
+ * @version $Revision: 302726 $ $Date: 2004-02-27 08:59:07 -0600 (Fri, 27 Feb 2004) $
+ */
+
+public class ValvesForm extends ActionForm {
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * The object names of the valves to be deleted.
+     */
+    private String valves[] = new String[0];
+
+    public String[] getValves() {
+        return (this.valves);
+    }
+
+    public void setValves(String valves[]) {
+        this.valves = valves;
+    }
+
+     /* 
+      * The parent object name of the valve to be deleted. 
+      */
+   
+    private String parentObjectName = null;
+    
+    public String getParentObjectName() {
+        return (this.parentObjectName);
+    }
+    
+    public void setParentObjectName(String parentObjectName) {
+        this.parentObjectName = parentObjectName;
+    }
+    
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Reset all properties to their default values.
+     *
+     * @param mapping The mapping used to select this instance
+     * @param request The servlet request we are processing
+     */
+    public void reset(ActionMapping mapping, HttpServletRequest request) {
+
+        this.valves = new String[0];
+        this.parentObjectName = null;
+    }
+        
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/controls.tld
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/controls.tld	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/controls.tld	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,419 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE taglib
+  PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN"
+         "http://java.sun.com/dtd/web-jsptaglibrary_1_2.dtd">
+
+<taglib>
+
+  <tlib-version>1.0</tlib-version>
+  <jsp-version>1.2</jsp-version>
+  <short-name>controls</short-name>
+  <description>
+    JSP tag library containing custom GUI controls used in the
+    Tomcat Administrative Application.
+  </description>
+
+  <!-- ========== Instant Table Tag ===================================== -->
+
+  <tag>
+
+    <name>table</name>
+    <tag-class>org.apache.webapp.admin.TableTag</tag-class>
+    <body-content>JSP</body-content>
+    <description>
+      Render a "table" object, which is rendered as an HTML
+      "table" element. 
+      
+      NOTE:  The only valid nested content for this tag is
+      "row" tags from this library.  Anything else will cause
+      the rendered HTML to be invalid.
+
+      NOTE:  To be usable, this tag must be nested inside an
+      HTML &lt;form&gt; element.
+    </description>
+
+    <attribute>
+      <name>columns</name>
+      <required>false</required>
+      <rtexprvalue>true</rtexprvalue>
+      <description>
+        (Integer) number of columns that the table contains.  If
+        not specified, only two columns will be visible.
+      </description>
+    </attribute>
+
+    <attribute>
+      <name>tableStyle</name>
+      <required>false</required>
+      <rtexprvalue>true</rtexprvalue>
+      <description>
+        The CSS style class to be applied to the entire rendered output
+        of the instant table.  If not specified, no overall
+        style class is applied.
+      </description>
+    </attribute>
+ 
+    <attribute>
+      <name>lineStyle</name>
+      <required>false</required>
+      <rtexprvalue>true</rtexprvalue>
+      <description>
+        The CSS style for the lines between rows.
+      </description>
+    </attribute>
+
+  </tag>
+
+    <tag>
+
+    <name>row</name>
+    <tag-class>org.apache.webapp.admin.RowTag</tag-class>
+    <body-content>JSP</body-content>
+    <description>
+      Define a single "instant table row" option for the surrounding "table"
+      tag.  It is not valid to use this tag *except* when nested inside an
+      "table" tag.
+
+      NOTE: This tag can nest only "label" and "data" tags.
+    </description>
+
+    <attribute>
+      <name>header</name>
+      <required>false</required>
+      <rtexprvalue>true</rtexprvalue>
+      <description>
+        (Boolean) variable set to "true" or "yes" if this row is
+        the header row.
+        </description>
+    </attribute>
+    
+     <attribute>
+      <name>labelStyle</name>
+      <required>false</required>
+      <rtexprvalue>true</rtexprvalue>
+      <description>
+        The style for the label table data element.
+      </description>
+    </attribute>
+    
+     <attribute>
+      <name>dataStyle</name>
+      <required>false</required>
+      <rtexprvalue>true</rtexprvalue>
+      <description>
+        The style for the value of the table data element.
+      </description>
+    </attribute>    
+    
+     <attribute>
+      <name>styleId</name>
+      <required>false</required>
+      <rtexprvalue>true</rtexprvalue>
+      <description>
+        The styleId for the label table data element.
+      </description>
+    </attribute>
+        
+  </tag>
+
+ <tag>
+
+    <name>label</name>
+    <tag-class>org.apache.webapp.admin.LabelTag</tag-class>
+    <body-content>JSP</body-content>
+    <description>
+      Render a "label" object, which is rendered as a label in the row of
+      an HTML "table" element. 
+
+      NOTE:  To be usable, this tag must be nested inside a "row" tag.
+    </description>
+  </tag>
+
+ <tag>
+
+    <name>data</name>
+    <tag-class>org.apache.webapp.admin.DataTag</tag-class>
+    <body-content>JSP</body-content>
+    <description>
+      Render a "data" object, which is rendered as a label in the row of
+      an HTML "table" element. 
+
+      NOTE:  To be usable, this tag must be nested inside a "row" tag.
+    </description>
+  </tag>
+
+  <!-- ========== Instant Actions Tag ===================================== -->
+
+   <tag>
+
+    <name>actions</name>
+    <tag-class>org.apache.webapp.admin.ActionsTag</tag-class>
+    <body-content>JSP</body-content>
+    <description>
+      Render an "instant actions" object, which is rendered as an HTML
+      "select" element, where the selection of a particular element from
+      the list immediately causes a JavaScript function to be executed
+      (with the available elements specified by "action" tag instances
+      nested within the body of the "actions" tag).
+
+      NOTE:  The only valid nested content for this tag is
+      "action" tags from this library.  Anything else will cause
+      the rendered HTML to be invalid.
+
+      NOTE:  To be usable, this tag must be nested inside an
+      HTML &lt;form&gt; element.
+    </description>
+
+    <attribute>
+      <name>size</name>
+      <required>false</required>
+      <rtexprvalue>true</rtexprvalue>
+      <description>
+        (Integer) number of rows that will be visible to the user.  If
+        not specified, only one row will be visible.
+      </description>
+    </attribute>
+
+    <attribute>
+      <name>style</name>
+      <required>false</required>
+      <rtexprvalue>true</rtexprvalue>
+      <description>
+        The CSS style class to be applied to the entire rendered output
+        of the instant actions control.  If not specified, no overall
+        style class is applied.
+      </description>
+    </attribute>
+
+    <attribute>
+      <name>label</name>
+      <required>false</required>
+      <rtexprvalue>true</rtexprvalue>
+      <description>
+        HTML Label tag generation.
+      </description>
+    </attribute>
+    
+  </tag>
+
+  <tag>
+
+    <name>action</name>
+    <tag-class>org.apache.webapp.admin.ActionTag</tag-class>
+    <body-content>JSP</body-content>
+    <description>
+      Define a single "instant action" option for the surrounding "actions"
+      tag.  It is not valid to use this tag *except* when nested inside an
+      "actions" tag.
+
+      NOTE:  The body content of this tag (which should be suitably
+      localized, if required by your application) is used as the
+      user-visible label for this action.
+    </description>
+
+    <attribute>
+      <name>selected</name>
+      <required>false</required>
+      <rtexprvalue>true</rtexprvalue>
+      <description>
+        (Boolean) variable set to "true" or "yes" if this action should
+        already be selected when the "instant actions" element is
+        initially displayed.
+      </description>
+    </attribute>
+
+    <attribute>
+      <name>disabled</name>
+      <required>false</required>
+      <rtexprvalue>true</rtexprvalue>
+      <description>
+        (Boolean) variable set to "true" or "yes" if the selection
+        for this action should be disabled.        
+      </description>
+    </attribute>
+
+    <attribute>
+      <name>url</name>
+      <required>false</required>
+      <rtexprvalue>true</rtexprvalue>
+      <description>
+        The URL to which the current frame or window will be transferred
+        if the "onchange" event handler of this "instant actions" element
+        is triggered, and this is the currently selected action.  If no
+        URL is specified, no action will be taken (useful for "(None)"
+        options and dividers).
+
+        If this URL starts with a slash, it will be assumed to be
+        context-relative, and will be prefixed with the context path
+        of this request.  Otherwise, it will be used unmodified.
+
+        NOTE:  This URL will be passed through URL rewriting so that it
+        will maintain session identity even in environments were cookies
+        are not being used.
+      </description>
+    </attribute>
+
+  </tag>
+
+
+  <!-- ========== Tree Control Tag ======================================== -->
+
+  <tag>
+
+    <name>tree</name>
+    <tag-class>org.apache.webapp.admin.TreeControlTag</tag-class>
+    <body-content>empty</body-content>
+    <description>
+      Render a "tree" control, based on the current state of a data object
+      of type org.apache.webapp.admin.TreeControl, which is identified
+      by the name specified in the "tree" attribute, in the JSP scope
+      specified by the "scope" attribute.
+    </description>
+
+    <attribute>
+      <name>action</name>
+      <required>false</required>
+      <rtexprvalue>true</rtexprvalue>
+      <description>
+        Hyperlink to which expand/contract actions should be sent,
+        with a string "${node}" marking where the node name of the
+        affected node should be included (which will usually be as
+        the value of a request parameter).
+      </description>
+    </attribute>
+
+    <attribute>
+      <name>images</name>
+      <required>false</required>
+      <rtexprvalue>true</rtexprvalue>
+      <description>
+        Name of a directory containing the images for our icons,
+        relative to the page including this tag.  If not specified,
+        defaults to "images".
+      </description>
+    </attribute>
+
+    <attribute>
+      <name>scope</name>
+      <required>false</required>
+      <rtexprvalue>true</rtexprvalue>
+      <description>
+        The JSP scope within which the "tree" attribute is to be found
+        (page, request, session, or application).  If not specified, the
+        "tree" attribute will be searched for in any scope.
+      </description>
+    </attribute>
+
+    <attribute>
+      <name>style</name>
+      <required>false</required>
+      <rtexprvalue>true</rtexprvalue>
+      <description>
+        The CSS style class to be applied to the entire rendered output
+        of the tree control.  If not specified, no overall style class
+        is applied.
+      </description>
+    </attribute>
+
+    <attribute>
+      <name>styleSelected</name>
+      <required>false</required>
+      <rtexprvalue>true</rtexprvalue>
+      <description>
+        The CSS style class to be applied to the text of any node that
+        is currently selected.  If not specified, no style class will be
+        applied to the text of the selected node.
+      </description>
+    </attribute>
+
+    <attribute>
+      <name>styleUnselected</name>
+      <required>false</required>
+      <rtexprvalue>true</rtexprvalue>
+      <description>
+        The CSS style class to be applied to the text of any node that
+        is *not* currently selected.  If not specified, no style class will
+         be applied to the text of non-selected nodes.
+      </description>
+    </attribute>
+
+    <attribute>
+      <name>tree</name>
+      <required>false</required>
+      <rtexprvalue>true</rtexprvalue>
+      <description>
+        Name of the attribute (in the scope specified by the "scope"
+        attribute, if any) under which an object of type
+        org.apache.webapp.admin.TreeControl is stored.  This object
+        represents the entire current state of the tree, including
+        a representation of the hierarchical representation of the
+        nodes, plus the current expanded/ or contracted state of
+        non-leaf nodes.
+      </description>
+    </attribute>
+
+  </tag>
+
+  <!-- ========== JMX Attribute Display Tag =============================== -->
+
+  <tag>
+
+    <name>attribute</name>
+    <tag-class>org.apache.webapp.admin.AttributeTag</tag-class>
+    <body-content>empty</body-content>
+    <description>
+      Look up an attribute on a JMX MBean, specified by an object name
+      specified by the "name" (and optional "property" and "scope")
+      attributes, and render it to the current JSP writer.  The object name
+      identified by these attributes can be either a java.lang.String version
+      of the name, or a javax.management.ObjectName instance.
+    </description>
+
+    <attribute>
+      <name>attribute</name>
+      <required>true</required>
+      <rtexprvalue>true</rtexprvalue>
+      <description>
+        Name of the attribute of the JMX MBean whose value is to be
+        retrieved and written to the current JSP writer.
+      </description>
+    </attribute>
+
+    <attribute>
+      <name>name</name>
+      <required>true</required>
+      <rtexprvalue>true</rtexprvalue>
+      <description>
+        Name of a bean, optionally in some scope identified by the "scope"
+        attribute.  If the "property" attribute is not specified, this bean
+        must by a String or an ObjectName.  Otherwise, this bean must have
+        a property getter for the property named by "property", which will
+        return the String or ObjectName.
+      </description>
+    </attribute>
+
+    <attribute>
+      <name>property</name>
+      <required>false</required>
+      <rtexprvalue>true</rtexprvalue>
+      <description>
+        Name of a bean property, on the bean identified by the "name"
+        (and optional "scope") attributes, that is either a String or an
+        ObjectName of the JMX MBean whose attribute is to be retrieved.
+      </description>
+    </attribute>
+
+    <attribute>
+      <name>scope</name>
+      <required>false</required>
+      <rtexprvalue>true</rtexprvalue>
+      <description>
+        Name of the scope ("page", "request", "session", or "application")
+        in which the bean identified by the "name" attribute is to be found.
+        If not specified, all scopes will be searched in ascending order.
+      </description>
+    </attribute>
+
+  </tag>
+
+</taglib>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/struts-config.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/struts-config.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/struts-config.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,970 @@
+<?xml version="1.0" encoding="ISO-8859-1" ?>
+
+<!DOCTYPE struts-config PUBLIC
+          "-//Apache Software Foundation//DTD Struts Configuration 1.2//EN"
+          "http://struts.apache.org/dtds/struts-config_1_2.dtd">
+
+
+<struts-config>
+
+
+  <!-- ========== Data Source Configuration =============================== -->
+
+
+  <!-- ========== Form Bean Definitions =================================== -->
+
+  <form-beans>
+
+    <!-- Set Locale form bean -->
+    <form-bean      name="setLocaleForm"
+                    type="org.apache.webapp.admin.SetLocaleForm"/>
+
+    <!-- ============= Server Module ============= -->
+
+    <form-bean      name="serverForm"
+                    type="org.apache.webapp.admin.server.ServerForm"/>
+                    
+    <!-- ============= Service Module ============= -->
+
+    <form-bean      name="serviceForm"
+                    type="org.apache.webapp.admin.service.ServiceForm"/>
+                    
+    <form-bean      name="servicesForm"
+                    type="org.apache.webapp.admin.service.ServicesForm"/>
+
+    <!-- ============= Host Module ============= -->
+
+    <form-bean      name="hostForm"
+                    type="org.apache.webapp.admin.host.HostForm"/>
+                    
+    <form-bean      name="hostsForm"
+                    type="org.apache.webapp.admin.host.HostsForm"/>
+
+    <form-bean      name="aliasForm"
+                    type="org.apache.webapp.admin.host.AliasForm"/>
+                    
+    <form-bean      name="aliasesForm"
+                    type="org.apache.webapp.admin.host.AliasesForm"/>
+
+    <!-- ============= Realm Module ============= -->
+
+    <form-bean      name="dataSourceRealmForm"
+                    type="org.apache.webapp.admin.realm.DataSourceRealmForm"/>
+
+    <form-bean      name="jdbcRealmForm"
+                    type="org.apache.webapp.admin.realm.JDBCRealmForm"/>
+
+    <form-bean      name="jndiRealmForm"
+                    type="org.apache.webapp.admin.realm.JNDIRealmForm"/>
+
+    <form-bean      name="memoryRealmForm"
+                    type="org.apache.webapp.admin.realm.MemoryRealmForm"/>
+
+    <form-bean      name="userDatabaseRealmForm"
+                    type="org.apache.webapp.admin.realm.UserDatabaseRealmForm"/>
+
+    <form-bean      name="realmsForm"
+                    type="org.apache.webapp.admin.realm.RealmsForm"/>
+
+    <!-- ============= Context Module ============= -->
+
+    <form-bean      name="contextForm"
+                    type="org.apache.webapp.admin.context.ContextForm"/>
+                    
+    <form-bean      name="contextsForm"
+                    type="org.apache.webapp.admin.context.ContextsForm"/>
+                    
+    <!-- ============= DefaultContext Module ============= -->
+                                        
+    <!-- ============= Connector Module ============= -->
+
+    <form-bean      name="connectorForm"
+                    type="org.apache.webapp.admin.connector.ConnectorForm"/>
+                    
+    <form-bean      name="connectorsForm"
+                    type="org.apache.webapp.admin.connector.ConnectorsForm"/>
+
+    <!-- ============= Valve Module ============= -->
+
+    <form-bean      name="accessLogValveForm"
+                    type="org.apache.webapp.admin.valve.AccessLogValveForm"/>
+
+    <form-bean      name="remoteAddrValveForm"
+                    type="org.apache.webapp.admin.valve.RemoteAddrValveForm"/>
+
+    <form-bean      name="remoteHostValveForm"
+                    type="org.apache.webapp.admin.valve.RemoteHostValveForm"/>
+
+    <form-bean      name="requestDumperValveForm"
+                    type="org.apache.webapp.admin.valve.RequestDumperValveForm"/>
+
+    <form-bean      name="singleSignOnValveForm"
+                    type="org.apache.webapp.admin.valve.SingleSignOnValveForm"/>
+
+    <form-bean      name="valvesForm"
+                    type="org.apache.webapp.admin.valve.ValvesForm"/>
+
+    <!-- ========== Resources Module ========== -->
+
+    <form-bean      name="envEntryForm"
+                    type="org.apache.webapp.admin.resources.EnvEntryForm"/>
+
+    <form-bean      name="envEntriesForm"
+                    type="org.apache.webapp.admin.resources.EnvEntriesForm"/>
+
+    <form-bean      name="userDatabaseForm"
+                    type="org.apache.webapp.admin.resources.UserDatabaseForm"/>
+
+    <form-bean      name="userDatabasesForm"
+                    type="org.apache.webapp.admin.resources.UserDatabasesForm"/>
+
+    <form-bean      name="dataSourceForm"
+                    type="org.apache.webapp.admin.resources.DataSourceForm"/>
+
+    <form-bean      name="dataSourcesForm"
+                    type="org.apache.webapp.admin.resources.DataSourcesForm"/>
+
+    <form-bean      name="mailSessionForm"
+                    type="org.apache.webapp.admin.resources.MailSessionForm"/>
+
+    <form-bean      name="mailSessionsForm"
+                    type="org.apache.webapp.admin.resources.MailSessionsForm"/>
+
+    <form-bean      name="resourceLinkForm"
+                    type="org.apache.webapp.admin.resources.ResourceLinkForm"/>
+
+    <form-bean      name="resourceLinksForm"
+                    type="org.apache.webapp.admin.resources.ResourceLinksForm"/>
+
+    <!-- ========== User Database Module ========== -->
+
+    <form-bean      name="databaseForm"
+                    type="org.apache.webapp.admin.users.BaseForm"/>
+
+    <form-bean      name="groupForm"
+                    type="org.apache.webapp.admin.users.GroupForm"/>
+
+    <form-bean      name="groupsForm"
+                    type="org.apache.webapp.admin.users.GroupsForm"/>
+
+    <form-bean      name="roleForm"
+                    type="org.apache.webapp.admin.users.RoleForm"/>
+
+    <form-bean      name="rolesForm"
+                    type="org.apache.webapp.admin.users.RolesForm"/>
+
+    <form-bean      name="userForm"
+                    type="org.apache.webapp.admin.users.UserForm"/>
+
+    <form-bean      name="usersForm"
+                    type="org.apache.webapp.admin.users.UsersForm"/>
+
+    <!-- ========== ==================== ========== -->
+
+
+  </form-beans>
+
+
+  <!-- ========== Global Forward Definitions ============================== -->
+
+  <global-forwards>
+
+    <forward        name="Dump Registry Results"
+                    path="/dumpRegistry.jsp"
+                redirect="false"/>
+
+    <forward        name="Dump Server Results"
+                    path="/dumpServer.jsp"
+                redirect="false"/>
+
+    <forward        name="Main Menu"
+                    path="/index.jsp"
+                redirect="false"/>
+
+    <forward        name="Tree Control Test"
+                    path="/tree-control-test.jsp"
+                redirect="false"/>
+                  
+    <forward        name="Save Successful"
+                    path="/saved.jsp"
+                redirect="false"/>
+
+    <forward        name="Save Unsuccessful"
+                    path="/savefail.jsp"
+                redirect="false"/>
+                
+    <forward        name="Blank"
+                    path="/blank.jsp"
+                redirect="false"/>
+
+    <forward        name="User"
+                    path="/user.jsp"
+                redirect="false"/>
+
+    <!-- ============ Server Module ============== -->
+
+    <forward        name="Server"
+                    path="/server/server.jsp"
+                redirect="false"/>
+    
+    <!-- ============ Service Module ============== -->
+
+    <forward        name="Service"
+                    path="/service/service.jsp"
+                redirect="false"/>
+
+    <forward        name="Services"
+                    path="/service/services.jsp"
+                redirect="false"/>
+
+    <!-- ============ Host Module ============== -->
+
+    <forward        name="Host"
+                    path="/host/host.jsp"
+                redirect="false"/>
+
+    <forward        name="Hosts"
+                    path="/host/hosts.jsp"
+                redirect="false"/>
+
+    <forward        name="Alias"
+                    path="/host/alias.jsp"
+                redirect="false"/>
+
+    <forward        name="Aliases"
+                    path="/host/aliases.jsp"
+                redirect="false"/>
+
+
+    <!-- ============ Context Module ============== -->
+
+    <forward        name="Context"
+                    path="/context/context.jsp"
+                redirect="false"/>
+
+    <forward        name="Contexts"
+                    path="/context/contexts.jsp"
+                redirect="false"/>
+
+    <!-- ============ DefaultContext Module ============== -->
+
+    <!-- ============ Connector Module ============== -->
+
+    <forward        name="Connector"
+                    path="/connector/connector.jsp"
+                redirect="false"/>
+
+    <forward        name="Connectors"
+                    path="/connector/connectors.jsp"
+                redirect="false"/>
+
+    <!-- ============ Realm Module ============== -->
+
+    <forward        name="DataSourceRealm"
+                    path="/realm/dataSourceRealm.jsp"
+                redirect="false"/>
+
+    <forward        name="JDBCRealm"
+                    path="/realm/jdbcRealm.jsp"
+                redirect="false"/>
+                
+    <forward        name="JNDIRealm"
+                    path="/realm/jndiRealm.jsp"
+                redirect="false"/>
+                
+    <forward        name="MemoryRealm"
+                    path="/realm/memoryRealm.jsp"
+                redirect="false"/>
+
+    <forward        name="UserDatabaseRealm"
+                    path="/realm/userDatabaseRealm.jsp"
+                redirect="false"/>
+
+    <forward        name="Realms"
+                    path="/realm/realms.jsp"
+                redirect="false"/>
+
+    <!-- ============ Context Module ============== -->
+
+    <forward        name="Context"
+                    path="/context/context.jsp"
+                redirect="false"/>
+
+    <forward        name="Contexts"
+                    path="/context/contexts.jsp"
+                redirect="false"/>
+
+    <!-- ============ Valve Module ============== -->
+
+    <forward        name="AccessLogValve"
+                    path="/valve/accessLogValve.jsp"
+                redirect="false"/>
+                
+    <forward        name="RemoteAddrValve"
+                    path="/valve/remoteAddrValve.jsp"
+                redirect="false"/>
+                
+    <forward        name="RemoteHostValve"
+                    path="/valve/remoteHostValve.jsp"
+                redirect="false"/>
+
+    <forward        name="RequestDumperValve"
+                    path="/valve/requestDumperValve.jsp"
+                redirect="false"/>
+
+    <forward        name="SingleSignOn"
+                    path="/valve/singleSignOnValve.jsp"
+                redirect="false"/>
+
+    <forward        name="Valves"
+                    path="/valve/valves.jsp"
+                redirect="false"/>
+
+    <!-- ========== Resources Module ========== -->
+
+    <forward        name="EnvEntry"
+                    path="/resources/envEntry.jsp"
+                redirect="false"/>
+
+    <forward        name="EnvEntries Delete List"
+                    path="/resources/deleteEnvEntries.jsp"
+                redirect="false"/>
+
+    <forward        name="EnvEntries List"
+                    path="/resources/listEnvEntries.jsp"
+                redirect="false"/>
+
+    <forward        name="EnvEntries List Setup"
+                    path="/resources/listEnvEntries.do?forward=EnvEntries+List"
+                redirect="false"/>
+
+    <forward        name="UserDatabase"
+                    path="/resources/userDatabase.jsp"
+                redirect="false"/>
+
+    <forward        name="UserDatabases Delete List"
+                    path="/resources/deleteUserDatabases.jsp"
+                redirect="false"/>
+
+    <forward        name="UserDatabases List"
+                    path="/resources/listUserDatabases.jsp"
+                redirect="false"/>
+
+    <forward        name="UserDatabases List Setup"
+                    path="/resources/listUserDatabases.do?forward=UserDatabases+List"
+                redirect="false"/>
+                
+    <forward        name="DataSource"
+                    path="/resources/dataSource.jsp"
+                redirect="false"/>
+
+    <forward        name="DataSources Delete List"
+                    path="/resources/deleteDataSources.jsp"
+                redirect="false"/>
+
+    <forward        name="DataSources List"
+                    path="/resources/listDataSources.jsp"
+                redirect="false"/>
+
+    <forward        name="DataSources List Setup"
+                    path="/resources/listDataSources.do?forward=DataSources+List"
+                redirect="false"/>
+
+    <forward        name="MailSession"
+                    path="/resources/mailSession.jsp"
+                redirect="false"/>
+
+    <forward        name="MailSessions Delete List"
+                    path="/resources/deleteMailSessions.jsp"
+                redirect="false"/>
+
+    <forward        name="MailSessions List"
+                    path="/resources/listMailSessions.jsp"
+                redirect="false"/>
+
+    <forward        name="MailSessions List Setup"
+                    path="/resources/listMailSessions.do?forward=MailSessions+List"
+                redirect="false"/>
+
+    <forward        name="ResourceLink"
+                    path="/resources/resourceLink.jsp"
+                redirect="false"/>
+
+    <forward        name="ResourceLinks Delete List"
+                    path="/resources/deleteResourceLinks.jsp"
+                redirect="false"/>
+
+    <forward        name="ResourceLinks List"
+                    path="/resources/listResourceLinks.jsp"
+                redirect="false"/>
+
+    <forward        name="ResourceLinks List Setup"
+                    path="/resources/listResourceLinks.do?forward=ResourceLinks+List"
+                redirect="false"/>
+                        
+    <!-- ========== User Database Module ========== -->
+
+    <forward        name="Group"
+                    path="/users/group.jsp"
+                redirect="false"/>
+
+    <forward        name="Groups Delete List"
+                    path="/users/deleteGroups.jsp"
+                redirect="false"/>
+
+    <forward        name="Groups List"
+                    path="/users/listGroups.jsp"
+                redirect="false"/>
+
+    <forward        name="Groups List Setup"
+                    path="/users/listGroups.do?forward=Groups+List"
+                redirect="false"/>
+
+    <forward        name="Role"
+                    path="/users/role.jsp"
+                redirect="false"/>
+
+    <forward        name="Roles Delete List"
+                    path="/users/deleteRoles.jsp"
+                redirect="false"/>
+
+    <forward        name="Roles List"
+                    path="/users/listRoles.jsp"
+                redirect="false"/>
+
+    <forward        name="Roles List Setup"
+                    path="/users/listRoles.do?forward=Roles+List"
+                redirect="false"/>
+
+    <forward        name="User"
+                    path="/users/user.jsp"
+                redirect="false"/>
+
+    <forward        name="Users Delete List"
+                    path="/users/deleteUsers.jsp"
+                redirect="false"/>
+
+    <forward        name="Users List"
+                    path="/users/listUsers.jsp"
+                redirect="false"/>
+
+    <forward        name="Users List Setup"
+                    path="/users/listUsers.do?forward=Users+List"
+                redirect="false"/>
+
+    <!-- ========== ==================== ========== -->
+
+
+  </global-forwards>
+
+
+  <!-- ========== Action Mapping Definitions ============================== -->
+
+  <action-mappings>
+
+    <!-- Dump registry information (debugging) -->
+    <action    path="/dumpRegistry"
+               type="org.apache.webapp.admin.DumpRegistryAction"/>
+
+    <!-- Dump MBean server information (debugging) -->
+    <action    path="/dumpServer"
+               type="org.apache.webapp.admin.DumpServerAction"/>
+
+    <!-- Set up Tree datastructure -->
+    <action    path="/setUpTree"
+               type="org.apache.webapp.admin.SetUpTreeAction">
+      <forward        name="SetUpTree"
+                      path="/tree-control-test.jsp"
+                  redirect="true"/>
+    </action>
+
+    <!-- Log out of the application -->
+    <action    path="/logOut"
+               type="org.apache.webapp.admin.LogOutAction">
+      <forward        name="Main Menu"
+                      path="/index.jsp"
+                  redirect="true"/>
+    </action>
+
+    <!-- Save current settings to server.xml -->
+    <action    path="/commitChanges"
+               type="org.apache.webapp.admin.CommitChangesAction">
+      <forward        name="Banner"
+                      path="/banner.jsp"
+                  redirect="true"/>
+    </action>
+
+    <!-- Process a set-locale action -->
+    <action    path="/setLocale"
+               type="org.apache.webapp.admin.SetLocaleAction"
+               name="setLocaleForm"
+              scope="session">
+    </action>
+
+    <!-- Tree control test action -->
+    <action    path="/treeControlTest"
+               type="org.apache.webapp.admin.TreeControlTestAction"/>
+
+   <!-- ============= Server Module ============== -->
+
+    <!-- Set up Edit Server transaction -->
+    <action    path="/EditServer"
+               type="org.apache.webapp.admin.server.EditServerAction">
+    </action>
+
+    <!-- Perform Save Server transaction -->
+    <action    path="/SaveServer"
+               type="org.apache.webapp.admin.server.SaveServerAction"
+               name="serverForm"
+              input="/server/server.jsp"
+               scope="session"/>
+
+    <!-- ============= Service Module ============== -->
+
+    <!-- Set up Add Service transaction -->
+    <action    path="/AddService"
+               type="org.apache.webapp.admin.service.AddServiceAction">
+    </action>
+
+    <!-- Set up Delete Services transaction -->
+    <action    path="/DeleteService"
+               type="org.apache.webapp.admin.service.DeleteServiceAction"
+               name="servicesForm"
+               scope="request"/>
+
+    <!-- Perform Delete Services transaction -->
+    <action    path="/DeleteServices"
+               type="org.apache.webapp.admin.service.DeleteServicesAction"
+               name="servicesForm"
+               scope="request"/>
+
+    <!-- Set up Edit Service transaction -->
+    <action    path="/EditService"
+               type="org.apache.webapp.admin.service.EditServiceAction">
+    </action>
+
+    <!-- Perform Save Service transaction -->
+    <action    path="/SaveService"
+               type="org.apache.webapp.admin.service.SaveServiceAction"
+               name="serviceForm"
+              input="/service/service.jsp"
+               scope="session"/>
+
+    <!-- ============= Host Module ============== -->
+
+    <!-- Set up Add Host transaction -->
+    <action    path="/AddHost"
+               type="org.apache.webapp.admin.host.AddHostAction">
+    </action>
+
+    <!-- Set up Delete Hosts transaction -->
+    <action    path="/DeleteHost"
+               type="org.apache.webapp.admin.host.DeleteHostAction"
+               name="hostsForm"
+               scope="request"/>
+
+    <!-- Perform Delete Hosts transaction -->
+    <action    path="/DeleteHosts"
+               type="org.apache.webapp.admin.host.DeleteHostsAction"
+               name="hostsForm"
+               scope="request"/>
+
+    <!-- Set up Edit Host transaction -->
+    <action    path="/EditHost"
+               type="org.apache.webapp.admin.host.EditHostAction">
+    </action>
+
+    <!-- Perform Save Host transaction -->
+    <action    path="/SaveHost"
+               type="org.apache.webapp.admin.host.SaveHostAction"
+               name="hostForm"
+              input="/host/host.jsp"
+               scope="session"/>
+               
+    <!-- Set up Add Alias transaction -->
+    <action    path="/AddAlias"
+               type="org.apache.webapp.admin.host.AddAliasAction">
+    </action>
+
+    <!-- Perform Delete Aliases transaction -->
+    <action    path="/DeleteAlias"
+               type="org.apache.webapp.admin.host.DeleteAliasAction"
+               name="aliasesForm"
+               scope="request"/>
+               
+    <!-- Perform Delete Aliases transaction -->
+    <action    path="/DeleteAliases"
+               type="org.apache.webapp.admin.host.DeleteAliasesAction"
+               name="aliasesForm"
+               scope="request"/>
+               
+    <!-- Perform Save Host transaction -->
+    <action    path="/SaveAlias"
+               type="org.apache.webapp.admin.host.SaveAliasAction"
+               name="aliasForm"
+              input="/host/alias.jsp"
+               scope="session"/>
+
+    <!-- ============= Realm Module ============== -->
+
+    <!-- Set up Add Realm transaction -->
+    <action    path="/AddRealm"
+               type="org.apache.webapp.admin.realm.AddRealmAction">
+    </action>
+
+    <!-- Set up Add Realm transaction -->
+    <action    path="/realm/AddRealm"
+               type="org.apache.webapp.admin.realm.AddRealmAction">
+    </action>
+
+    <!-- Set up Delete Realms transaction -->
+    <action    path="/DeleteRealm"
+               type="org.apache.webapp.admin.realm.DeleteRealmAction"
+               name="realmsForm"
+               scope="request"/>
+
+    <!-- Perform Delete Realms transaction -->
+    <action    path="/DeleteRealms"
+               type="org.apache.webapp.admin.realm.DeleteRealmsAction"
+               name="realmsForm"
+               scope="request"/>
+
+    <!-- Set up Edit Realm transaction (generic) -->
+    <action    path="/EditRealm"
+               type="org.apache.webapp.admin.realm.EditRealmAction">
+    </action>
+
+    <!-- Perform Save UserDatabase Realm transaction -->
+    <action    path="/SaveUserDatabaseRealm"
+               type="org.apache.webapp.admin.realm.SaveUserDatabaseRealmAction"
+               name="userDatabaseRealmForm"
+              input="/realm/userDatabaseRealm.jsp"
+               scope="session"/>
+
+   <!-- Perform Save DataSource Realm transaction -->
+    <action    path="/SaveDataSourceRealm"
+               type="org.apache.webapp.admin.realm.SaveDataSourceRealmAction"
+               name="dataSourceRealmForm"
+              input="/realm/dataSourceRealm.jsp"
+               scope="session"/>
+
+   <!-- Perform Save JDBC Realm transaction -->
+    <action    path="/SaveJDBCRealm"
+               type="org.apache.webapp.admin.realm.SaveJDBCRealmAction"
+               name="jdbcRealmForm"
+              input="/realm/jdbcRealm.jsp"
+               scope="session"/>
+
+    <!-- Perform Save JNDI Realm transaction -->
+    <action    path="/SaveJNDIRealm"
+               type="org.apache.webapp.admin.realm.SaveJNDIRealmAction"
+               name="jndiRealmForm"
+              input="/realm/jndiRealm.jsp"
+               scope="session"/>
+
+    <!-- Perform Save Memory transaction -->
+    <action    path="/SaveMemoryRealm"
+               type="org.apache.webapp.admin.realm.SaveMemoryRealmAction"
+               name="memoryRealmForm"
+              input="/realm/memoryRealm.jsp"
+               scope="session"/>
+               
+   <!-- ============= Context Module ============== -->
+
+    <!-- Set up Add Context transaction -->
+    <action    path="/AddContext"
+               type="org.apache.webapp.admin.context.AddContextAction">
+    </action>
+
+    <!-- Set up Delete Contexts transaction -->
+    <action    path="/DeleteContext"
+               type="org.apache.webapp.admin.context.DeleteContextAction"
+               name="contextsForm"
+               scope="request"/>
+
+    <!-- Perform Delete Contexts transaction -->
+    <action    path="/DeleteContexts"
+               type="org.apache.webapp.admin.context.DeleteContextsAction"
+               name="contextsForm"
+               scope="request"/>
+
+    <!-- Set up Edit Context transaction -->
+    <action    path="/EditContext"
+               type="org.apache.webapp.admin.context.EditContextAction">
+    </action>
+
+    <!-- Perform Save Context transaction -->
+    <action    path="/SaveContext"
+               type="org.apache.webapp.admin.context.SaveContextAction"
+               name="contextForm"
+              input="/context/context.jsp"
+               scope="session"/>
+               
+   <!-- ============= DefaultContext Module ============== -->
+
+   <!-- ============= Connector Module ============== -->
+
+    <!-- Set up Add Connector transaction -->
+    <action    path="/AddConnector"
+               type="org.apache.webapp.admin.connector.AddConnectorAction">
+    </action>
+
+    <!-- Set up Add Connector transaction -->
+    <action    path="/connector/AddConnector"
+               type="org.apache.webapp.admin.connector.AddConnectorAction">
+    </action>
+
+    <!-- Set up Delete Connectors transaction -->
+    <action    path="/DeleteConnector"
+               type="org.apache.webapp.admin.connector.DeleteConnectorAction"
+               name="connectorsForm"
+               scope="request"/>
+
+    <!-- Perform Delete Connectors transaction -->
+    <action    path="/DeleteConnectors"
+               type="org.apache.webapp.admin.connector.DeleteConnectorsAction"
+               name="connectorsForm"
+               scope="request"/>
+
+    <!-- Set up Edit Connector transaction -->
+    <action    path="/EditConnector"
+               type="org.apache.webapp.admin.connector.EditConnectorAction">
+    </action>
+
+    <!-- Perform Save Connector transaction -->
+    <action    path="/SaveConnector"
+               type="org.apache.webapp.admin.connector.SaveConnectorAction"
+               name="connectorForm"
+              input="/connector/connector.jsp"
+               scope="session"/>
+               
+   <!-- ============= Valve Module ============== -->
+
+    <!-- Set up Add Valve transaction -->
+    <action    path="/AddValve"
+               type="org.apache.webapp.admin.valve.AddValveAction">
+    </action>
+
+    <!-- Set up Add Valve transaction -->
+    <action    path="/valve/AddValve"
+               type="org.apache.webapp.admin.valve.AddValveAction">
+    </action>
+
+    <!-- Set up Delete Valves transaction -->
+    <action    path="/DeleteValve"
+               type="org.apache.webapp.admin.valve.DeleteValveAction"
+               name="valvesForm"
+               scope="request"/>
+
+    <!-- Perform Delete Valves transaction -->
+    <action    path="/DeleteValves"
+               type="org.apache.webapp.admin.valve.DeleteValvesAction"
+               name="valvesForm"
+               scope="request"/>
+
+    <!-- Set up Edit Valve transaction (generic) -->
+    <action    path="/EditValve"
+               type="org.apache.webapp.admin.valve.EditValveAction">
+    </action>
+    
+    <!-- Perform Save AccessLog Valve transaction -->
+    <action    path="/SaveAccessLogValve"
+               type="org.apache.webapp.admin.valve.SaveAccessLogValveAction"
+               name="accessLogValveForm"
+              input="/valve/accessLogValve.jsp"
+               scope="session"/>
+
+   <!-- Perform Save Remote Addr Valve transaction -->
+    <action    path="/SaveRemoteAddrValve"
+               type="org.apache.webapp.admin.valve.SaveRemoteAddrValveAction"
+               name="remoteAddrValveForm"
+              input="/valve/remoteAddrValve.jsp"
+               scope="session"/>
+
+    <!-- Perform Save Remote Host Valve transaction -->
+    <action    path="/SaveRemoteHostValve"
+               type="org.apache.webapp.admin.valve.SaveRemoteHostValveAction"
+               name="remoteHostValveForm"
+              input="/valve/remoteHostValve.jsp"
+               scope="session"/>
+
+    <!-- Perform Save Request Dumper Valve transaction -->
+    <action    path="/SaveRequestDumperValve"
+               type="org.apache.webapp.admin.valve.SaveRequestDumperValveAction"
+               name="requestDumperValveForm"
+              input="/valve/requestDumperValve.jsp"
+               scope="session"/>
+
+   <!-- Perform Save Single Sign On Valve transaction -->
+    <action    path="/SaveSingleSignOn"
+               type="org.apache.webapp.admin.valve.SaveSingleSignOnValveAction"
+               name="singleSignOnValveForm"
+              input="/valve/singleSignOnValve.jsp"
+               scope="session"/>
+               
+   <!-- ========== Resources Module ========== -->
+
+   <action    path="/resources/deleteEnvEntries"
+               name="envEntriesForm"
+              scope="request"
+               type="org.apache.webapp.admin.resources.DeleteEnvEntriesAction"/>
+
+   <action    path="/resources/deleteUserDatabases"
+               name="userDatabasesForm"
+              scope="request"
+               type="org.apache.webapp.admin.resources.DeleteUserDatabasesAction"/>
+      
+    <action    path="/resources/deleteDataSources"
+               name="dataSourcesForm"
+              scope="request"
+               type="org.apache.webapp.admin.resources.DeleteDataSourcesAction"/>
+
+    <action    path="/resources/deleteMailSessions"
+               name="mailSessionsForm"
+              scope="request"
+               type="org.apache.webapp.admin.resources.DeleteMailSessionsAction"/>
+
+    <action    path="/resources/deleteResourceLinks"
+               name="resourceLinksForm"
+              scope="request"
+               type="org.apache.webapp.admin.resources.DeleteResourceLinksAction"/>
+               
+    <action    path="/resources/listEnvEntries"
+               name="envEntriesForm"
+              scope="request"
+               type="org.apache.webapp.admin.resources.ListEnvEntriesAction"/>
+               
+    <action    path="/resources/listUserDatabases"
+               name="userDatabasesForm"
+              scope="request"
+               type="org.apache.webapp.admin.resources.ListUserDatabasesAction"/>
+
+    <action    path="/resources/listDataSources"
+               name="dataSourcesForm"
+              scope="request"
+               type="org.apache.webapp.admin.resources.ListDataSourcesAction"/>
+
+    <action    path="/resources/listMailSessions"
+               name="mailSessionsForm"
+              scope="request"
+               type="org.apache.webapp.admin.resources.ListMailSessionsAction"/>
+
+    <action    path="/resources/listResourceLinks"
+               name="resourceLinksForm"
+              scope="request"
+               type="org.apache.webapp.admin.resources.ListResourceLinksAction"/>
+
+   <action    path="/resources/saveEnvEntry"
+              input="/resources/envEntry.jsp"
+               name="envEntryForm"
+              scope="request"
+               type="org.apache.webapp.admin.resources.SaveEnvEntryAction"/>
+               
+   <action    path="/resources/saveUserDatabase"
+              input="/resources/userDatabase.jsp"
+               name="userDatabaseForm"
+              scope="request"
+               type="org.apache.webapp.admin.resources.SaveUserDatabaseAction"/>
+
+    <action    path="/resources/saveDataSource"
+              input="/resources/dataSource.jsp"
+               name="dataSourceForm"
+              scope="request"
+               type="org.apache.webapp.admin.resources.SaveDataSourceAction"/>
+
+    <action    path="/resources/saveMailSession"
+              input="/resources/mailSession.jsp"
+               name="mailSessionForm"
+              scope="request"
+               type="org.apache.webapp.admin.resources.SaveMailSessionAction"/>
+
+    <action    path="/resources/saveResourceLink"
+              input="/resources/resourceLink.jsp"
+               name="resourceLinkForm"
+              scope="request"
+               type="org.apache.webapp.admin.resources.SaveResourceLinkAction"/>
+
+   <action    path="/resources/setUpEnvEntry"
+               type="org.apache.webapp.admin.resources.SetUpEnvEntryAction"/>
+
+   <action    path="/resources/setUpUserDatabase"
+               type="org.apache.webapp.admin.resources.SetUpUserDatabaseAction"/>
+
+    <action    path="/resources/setUpDataSource"
+               type="org.apache.webapp.admin.resources.SetUpDataSourceAction"/>
+
+    <action    path="/resources/setUpMailSession"
+               type="org.apache.webapp.admin.resources.SetUpMailSessionAction"/>
+
+    <action    path="/resources/setUpResourceLink"
+               type="org.apache.webapp.admin.resources.SetUpResourceLinkAction"/>
+           
+    <!-- ========== User Database Module ========== -->
+
+    <action    path="/users/deleteGroups"
+               name="groupsForm"
+              scope="request"
+               type="org.apache.webapp.admin.users.DeleteGroupsAction"/>
+
+    <action    path="/users/deleteRoles"
+               name="rolesForm"
+              scope="request"
+                type="org.apache.webapp.admin.users.DeleteRolesAction"/>
+
+    <action    path="/users/deleteUsers"
+               name="usersForm"
+              scope="request"
+               type="org.apache.webapp.admin.users.DeleteUsersAction"/>
+
+    <action    path="/users/listGroups"
+               name="groupsForm"
+              scope="request"
+               type="org.apache.webapp.admin.users.ListGroupsAction"/>
+
+    <action    path="/users/listRoles"
+               name="rolesForm"
+              scope="request"
+               type="org.apache.webapp.admin.users.ListRolesAction"/>
+
+    <action    path="/users/listUsers"
+               name="usersForm"
+              scope="request"
+               type="org.apache.webapp.admin.users.ListUsersAction"/>
+
+    <action    path="/users/saveGroup"
+              input="/users/group.jsp"
+               name="groupForm"
+              scope="request"
+               type="org.apache.webapp.admin.users.SaveGroupAction"/>
+
+    <action    path="/users/saveRole"
+              input="/users/role.jsp"
+               name="roleForm"
+              scope="request"
+               type="org.apache.webapp.admin.users.SaveRoleAction"/>
+
+    <action    path="/users/saveUser"
+              input="/users/user.jsp"
+               name="userForm"
+              scope="request"
+               type="org.apache.webapp.admin.users.SaveUserAction"/>
+
+    <action    path="/users/setUpGroup"
+               type="org.apache.webapp.admin.users.SetUpGroupAction"/>
+
+    <action    path="/users/setUpRole"
+               type="org.apache.webapp.admin.users.SetUpRoleAction"/>
+
+    <action    path="/users/setUpUser"
+               type="org.apache.webapp.admin.users.SetUpUserAction"/>
+
+    <!-- ========== ==================== ========== -->
+
+
+  </action-mappings>  
+
+  <controller locale="true" nocache="true" />
+ 
+  <message-resources parameter="org.apache.webapp.admin.ApplicationResources" />
+
+</struts-config>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/web.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/web.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/WEB-INF/web.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,138 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<web-app 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-app_2_4.xsd"
+    version="2.4">
+
+  <display-name>Tomcat Administration Application</display-name>
+  <description>
+    Tomcat HTML based administration web application.
+  </description>
+
+  <!-- Example filter to set character encoding on each request.
+       Uncomment this filter definition and the mapping to use
+       the filter to decode post and get parameters -->
+
+  <filter>
+    <filter-name>Set Character Encoding</filter-name>
+    <filter-class>org.apache.webapp.admin.filters.SetCharacterEncodingFilter</filter-class>
+    <init-param>
+      <param-name>encoding</param-name>
+      <param-value>UTF8</param-value>
+    </init-param>
+  </filter>
+
+  <!-- Example filter mapping to apply the "Set Character Encoding" filter
+       to *all* requests processed by this web application -->
+
+  <filter-mapping>
+    <filter-name>Set Character Encoding</filter-name>
+    <url-pattern>/*</url-pattern>
+  </filter-mapping>
+
+  <!-- Action Servlet Configuration -->
+  <servlet>
+    <servlet-name>action</servlet-name>
+    <servlet-class>
+      org.apache.webapp.admin.ApplicationServlet
+    </servlet-class>
+<!-- Deprecated
+    <init-param>
+      <param-name>application</param-name>
+      <param-value>
+        org.apache.webapp.admin.ApplicationResources
+      </param-value>
+    </init-param>
+-->
+    <init-param>
+      <param-name>config</param-name>
+      <param-value>/WEB-INF/struts-config.xml</param-value>
+    </init-param>
+<!-- Deprecated   
+    <init-param>
+      <param-name>debug</param-name>
+      <param-value>0</param-value>
+    </init-param>
+-->
+    <init-param>
+      <param-name>detail</param-name>
+      <param-value>0</param-value>
+    </init-param>
+<!-- Deprecated
+    <init-param>
+      <param-name>locale</param-name>
+      <param-value>true</param-value>
+    </init-param>
+-->
+<!-- Deprecated
+    <init-param>
+      <param-name>nocache</param-name>
+      <param-value>true</param-value>
+    </init-param>
+-->
+    <init-param>
+      <param-name>validate</param-name>
+      <param-value>false</param-value>
+    </init-param>
+    <!-- Label to be displayed for rootnode. If absent, rootnode is not rendered -->
+    <!--
+    <init-param>
+      <param-name>rootnodename</param-name>
+      <param-value>Tomcat Root</param-value>
+    </init-param>
+    -->
+    <init-param>
+      <param-name>treebuilders</param-name>
+      <param-value>
+        org.apache.webapp.admin.TomcatTreeBuilder,
+        org.apache.webapp.admin.resources.ResourcesTreeBuilder,
+        org.apache.webapp.admin.users.UsersTreeBuilder
+    </param-value>
+    </init-param>
+    <init-param>
+      <param-name>domain</param-name>
+      <param-value>Catalina</param-value>
+    </init-param>
+  </servlet>
+
+  <!-- Action Servlet Mapping -->
+  <servlet-mapping>
+    <servlet-name>action</servlet-name>
+    <url-pattern>*.do</url-pattern>
+  </servlet-mapping>
+
+  <!-- Security is active on entire directory -->
+  <security-constraint>
+    <display-name>Tomcat Server Configuration Security Constraint</display-name>
+    <web-resource-collection>
+      <web-resource-name>Protected Area</web-resource-name>
+      <!-- Define the context-relative URL(s) to be protected -->
+      <url-pattern>*.jsp</url-pattern>
+      <url-pattern>*.do</url-pattern>
+      <url-pattern>*.html</url-pattern>
+    </web-resource-collection>
+    <auth-constraint>
+      <!-- Anyone with one of the listed roles may access this area -->
+      <role-name>admin</role-name>
+    </auth-constraint>
+  </security-constraint>
+
+  <!-- Login configuration uses form-based authentication -->
+  <login-config>
+    <auth-method>FORM</auth-method>
+    <realm-name>Tomcat Server Configuration Form-Based Authentication Area</realm-name>
+    <form-login-config>
+      <form-login-page>/login.jsp</form-login-page>
+      <form-error-page>/error.jsp</form-error-page>
+    </form-login-config>
+  </login-config>
+
+  <!-- Security roles referenced by this web application -->
+  <security-role>
+    <description>
+      The role that is required to log in to the Administration Application
+    </description>
+    <role-name>admin</role-name>
+  </security-role>
+
+</web-app>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/admin.css
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/admin.css	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/admin.css	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,95 @@
+.masthead-title-text {
+  color: #FFFFFF;
+  margin: 3px 5px 5px 3px;
+  font-size: large;
+  font-family:  Arial, Verdana,Helvetica, Sans-Serif;
+}
+
+.page-title-text {
+  color: #FFFFFF;
+  font-weight: bold;
+  margin: 3px 5px 5px 3px;
+  font-size: normal;
+  font-family: Arial, Verdana, Helvetica, Sans-Serif;
+}
+
+.table-title-text {
+  color: #000000;
+  font-weight: bold;
+  margin: 3px 5px 5px 4px;
+  font-family: Arial, Verdana, Helvetica, Sans-Serif;
+}
+
+.table-header-text {
+  color: #FFFFFF;
+  font-weight: normal;
+  margin: 3px 5px 1px 15px;
+  font-family:  Arial, Verdana,Helvetica, Sans-Serif;
+}
+
+.table-label-text {
+  color: #000000;
+  margin: 3px 5px 3px 15px;
+  font-family: Arial, Verdana, Helvetica, Sans-Serif;
+}
+
+.table-normal-text {
+  color: #000000;
+  margin: 3px 5px 3px 15px;
+  font-family: "Times New Roman", Times, serif;
+}
+
+.back-table {
+  background-color: #9999CC;
+  margin: 0px 5px 3px 5px;
+  font-family: Verdana, Arial, Helvetica, Sans-Serif;
+}
+
+.front-table {
+  background-color: #FFFFFF;
+  font-family: Arial, Verdana, Helvetica, Sans-Serif;
+}
+
+.page-title-row {
+  background-color: #7171A5;
+  text-align: right;
+  font-family: Arial, Verdana, Helvetica, Sans-Serif;
+}
+
+.header-row {
+  background-color: #9999CC;
+  text-align: center;
+  font-family: Arial, Verdana, Helvetica, Sans-Serif;
+}
+
+.sort-row {
+  background-color: #CECEFF;
+  text-align: center;
+  font-family: Arial, Verdana, Helvetica, Sans-Serif;
+}
+
+.line-row {
+  background-color: #CCCCCC;
+  font-family: Arial, Verdana, Helvetica, Sans-Serif;
+}
+
+.button {
+  background-color: #CCCCFF;
+  font-family: Arial, Verdana, Helvetica, Sans-Serif;
+}
+
+a.button-link-text:visited, a.button-link-text:link, a.button-link-text:active {
+  color: #000000;
+  background-color: #CCCCFF;
+  font-weight: bold;
+  font-family: Arial, Verdana, Geneva, Helvetica, Sans-Serif;
+  text-decoration: none;
+}
+
+a.button-link-text:hover {
+  color: #000000;
+  background-color: #CCCCFF;
+  font-weight: bold;
+  font-family: Arial, Verdana, Geneva, Helvetica, Sans-Serif;
+  text-decoration: underline;
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/admin.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/admin.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/admin.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,20 @@
+<!--
+
+    Context configuration file for the Tomcat Administration Web App
+
+    $Id: admin.xml 303123 2004-08-26 17:03:35Z remm $
+
+-->
+
+
+<Context docBase="${catalina.home}/server/webapps/admin" privileged="true"
+         antiResourceLocking="false" antiJARLocking="false">
+
+  <!-- Uncomment this Valve to limit access to the Admin app to localhost
+   for obvious security reasons. Allow may be a comma-separated list of
+   hosts (or even regular expressions).
+  <Valve className="org.apache.catalina.valves.RemoteAddrValve"
+    allow="127.0.0.1"/>
+  -->
+
+</Context>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/banner.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/banner.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/banner.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,78 @@
+<!-- Standard Struts Entries -->
+
+<%@ page language="java" contentType="text/html;charset=utf-8" %>
+<%@ taglib uri="http://struts.apache.org/tags-bean" prefix="bean" %>
+<%@ taglib uri="http://struts.apache.org/tags-html" prefix="html" %>
+<%@ taglib uri="http://struts.apache.org/tags-logic" prefix="logic" %>
+
+<html:html locale="true">
+
+<!-- Standard Content -->
+
+<%@ include file="header.jsp" %>
+
+<!-- Body -->
+
+<body leftmargin="0" topmargin="0" marginwidth="0" marginheight="0" bgcolor="7171A5" background="images/BlueTile.gif">
+
+<table width="100%" border="0" cellspacing="0" cellpadding="0">
+    <tr>
+      <td align="left" valign="middle">
+        <div class="masthead-title-text" align="left"><img src="images/TomcatBanner.jpg" alt="Tomcat Web Server Administration Tool" height="120"></div>
+      </td>
+      <form method='post' action='<%=request.getContextPath()%>/commitChanges.do' target='_self'>
+      <td align="right" valign="middle">
+        <html:submit onclick="if(confirm('Are you sure?  Committing changes will restart modified web applications.')) { return true; } else { return false; }">
+          <bean:message key="button.commit"/>
+        </html:submit>
+      </td>
+      </form>
+      <td width="1%">
+        <div class="table-normal-text" align="left">&nbsp </div>
+      </td>
+    <form method='post' action='<%=request.getContextPath()%>/logOut.do' target='_top'>
+      <td align="right" valign="middle">
+        <html:submit>
+          <bean:message key="button.logout"/>
+        </html:submit>
+      </td>
+      <td width="1%">
+        <div class="table-normal-text" align="left">&nbsp </div>
+      </td>
+    </form>
+  </tr>
+</table>
+
+<!-- Select language -->
+<!--
+
+<h2><bean:message key="login.changeLanguage"/></h2>
+
+<html:form action="/setLocale" method="POST" target="_self">
+  <table border="0" cellspacing="5">
+    <tr>
+      <td align="right">
+        <html:select property="locale">
+          <html:options name="applicationLocales"
+                    property="localeValues"
+                   labelName="applicationLocales"
+               labelProperty="localeLabels"/>
+        </html:select>
+      </td>
+      <td align="left">
+        <html:submit>
+          <bean:message key="button.change"/>
+        </html:submit>
+      </td>
+    </tr>
+  </table>
+</html:form>
+-->
+
+</body>
+
+<!-- Standard Footer -->
+
+<%@ include file="footer.jsp" %>
+
+</html:html>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/blank.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/blank.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/blank.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,24 @@
+<!-- Standard Struts Entries -->
+
+<%@ page language="java" contentType="text/html;charset=utf-8" %>
+<%@ taglib uri="http://struts.apache.org/tags-bean" prefix="bean" %>
+<%@ taglib uri="http://struts.apache.org/tags-html" prefix="html" %>
+<%@ taglib uri="http://struts.apache.org/tags-logic" prefix="logic" %>
+
+<html:html locale="true">
+
+<!-- Standard Content -->
+
+<%@ include file="header.jsp" %>
+
+<!-- Body -->
+
+<body bgcolor="white" background="images/PaperTexture.gif">
+
+</body>
+
+<!-- Standard Footer -->
+
+<%@ include file="footer.jsp" %>
+
+</html:html>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/build.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/build.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/build.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,241 @@
+<project name="admin" default="build-main" basedir=".">
+
+
+  <!-- ===================== Initialize Property Values =================== -->
+
+  <!-- See "build.properties.sample" in the top level directory for all     -->
+  <!-- property values you must customize for successful building!!!        -->
+  <property file="build.properties"/>
+  <property file="../build.properties"/>
+  <property file="../../build.properties"/>
+  <property file="${user.home}/build.properties"/>
+
+  <!-- Build Defaults -->
+  <property name="build.compiler"  value="modern"/>
+  <property name="webapps.build"   value="${basedir}/../build"/>
+  <property name="webapps.dist"    value="${basedir}/../dist"/>
+  <property name="webapp.name"     value="admin"/>
+
+  <!-- Dependent JARs and files -->
+  <property name="servlet-api.jar" value="${api.home}/jsr154/dist/lib/servlet-api.jar"/>
+  <property name="jsp-api.jar"     value="${api.home}/jsr152/dist/lib/jsp-api.jar"/>
+  <property name="struts-core.jar" value="${struts.jar}" />
+  <property name="struts-taglib.jar" value="${struts.jar}" />
+
+  <!-- Construct Admin classpath -->
+  <path id="admin.classpath">
+    <pathelement location="${commons-modeler.jar}"/>
+    <pathelement location="${jmx.jar}"/>
+    <pathelement location="${servlet-api.jar}"/>
+    <pathelement location="${jsp-api.jar}"/>
+    <pathelement location="${struts-core.jar}"/>
+    <pathelement location="${commons-beanutils.jar}"/>
+    <pathelement location="${commons-collections.jar}"/>
+    <pathelement location="${commons-digester.jar}"/>
+  </path>
+
+
+  <!-- =================== BUILD: Set compile flags ======================= -->
+  <target name="flags">
+
+    <!-- JDK flags -->
+    <available property="jdk.1.2.present" classname="java.util.HashMap" />
+    <available property="jdk.1.3.present"
+     classname="java.lang.reflect.Proxy" />
+    <available property="jdk.1.4.present" classname="java.nio.Buffer" />
+
+    <!-- Ant flags -->
+    <available property="style.available"
+     classname="org.apache.tools.ant.taskdefs.optional.TraXLiaison" />
+
+    <!-- Class availability flags -->
+    <condition property="jaxp.present">
+      <and>
+        <available classname="javax.xml.parsers.SAXParser"
+         classpath="${xerces.jar}" />
+        <available classname="org.xml.sax.ContentHandler"
+         classpath="${xerces.jar}" />
+      </and>
+    </condition>
+    <available property="jmx.present"
+     classname="javax.management.MBeanServer"
+     classpath="${jmx.jar}" />
+    <available property="modeler.present"
+     classname="org.apache.commons.modeler.Registry"
+     classpath="${commons-modeler.jar}:${jmx.jar}"/>
+    <available property="servlet.present"
+     classname="javax.servlet.Servlet"
+     classpath="${servlet-api.jar}" />
+    <available property="jsp.present"
+     classname="javax.servlet.jsp.JspPage"
+     classpath="${jsp-api.jar}" />
+    <available property="struts.present"
+     classname="org.apache.struts.action.ActionForm"
+     classpath="${struts-core.jar}" />
+    <available property="beanutils.present"
+     classname="org.apache.commons.beanutils.PropertyUtils"
+     classpath="${commons-beanutils.jar}" />
+
+
+    <!-- JAR files availability flags -->
+    <available property="jmx.jar.present"   file="${jmx.jar}" />
+    <available property="modeler.jar.present" file="${commons-modeler.jar}" />
+    <available property="servlet-api.jar.present" file="${servlet-api.jar}" />
+    <available property="jsp-api.jar.present" file="${jsp-api.jar}" />
+    <available property="struts.jar.present"  file="${struts-core.jar}" />
+    <available property="beanutils.jar.present" file="${commons-beanutils.jar}" />
+
+    <!-- Conditional compilation flags (determined from the flags above) -->
+    <condition property="compile.admin">
+      <or>
+        <equals arg1="${full.dist}" arg2="on" />
+        <and>
+          <equals arg1="${struts.present}" arg2="true" />
+          <equals arg1="${jmx.present}" arg2="true" />
+          <equals arg1="${modeler.present}" arg2="true" />
+        </and>
+      </or>
+    </condition>
+
+    <!-- Conditional copy flags (determined from the flags above) -->
+    <condition property="copy.struts.jar">
+      <or>
+        <equals arg1="${full.dist}" arg2="on" />
+        <equals arg1="${struts.jar.present}" arg2="true" />
+      </or>
+    </condition>
+
+  </target>
+
+
+  <!-- =================== BUILD: Set compile flags ======================= -->
+  <target name="flags.display" depends="flags" unless="flags.hide">
+
+    <echo message="--- Build environment for Tomcat Server Configuration Application ---" />
+
+    <echo message="If ${property_name} is displayed, then the property is not set)" />
+
+    <echo message="--- Build options ---" />
+    <echo message="full.dist=${full.dist}" />
+    <echo message="build.sysclasspath=${build.sysclasspath}" />
+    <echo message="compile.debug=${compile.debug}" />
+    <echo message="compile.deprecation=${compile.deprecation}" />
+    <echo message="compile.optimize=${compile.optimize}" />
+
+    <echo message="--- Ant Flags ---" />
+    <echo message="&lt;style&gt; task available (required)=${style.available}" />
+
+    <echo message="--- JDK ---" />
+    <echo message="jdk.1.2.present=${jdk.1.2.present}" />
+    <echo message="jdk.1.3.present=${jdk.1.3.present}" />
+    <echo message="jdk.1.4.present=${jdk.1.4.present}" />
+
+    <echo message="--- Required Libraries ---" />
+    <echo message="jaxp.present=${jaxp.present}" />
+    <echo message="jmx.present=${jmx.present}" />
+    <echo message="modeler.present=${modeler.present}" />
+    <echo message="servlet.present=${servlet.present}" />
+    <echo message="jsp.present=${jsp.present}" />
+
+    <echo message="--- Required JARs ---" />
+    <echo message="jmx.jar.present=${jmx.jar.present}" />
+    <echo message="modeler.jar.present=${modeler.jar.present}" />
+    <echo message="servlet-api.jar.present=${servlet-api.jar.present}" />
+    <echo message="jsp-api.jar.present=${jsp-api.jar.present}" />
+    <echo message="struts.jar.present=${struts.jar.present}" />
+    <echo message="beanutils.jar.present=${beanutils.jar.present}" />
+
+    <echo message="--- Optional JARs ---" />
+
+    <echo message="--- Conditional compilation flags ---" />
+    <echo message="compile.admin=${compile.admin}" />
+
+    <echo message="--- Distribution flags ---" />
+    <echo message="copy.struts.jar=${copy.struts.jar}" />
+
+  </target>
+
+
+  <!-- ======================== BUILD: Copy JARs ========================== -->
+  <target name="copy-struts.jar" if="struts.present">
+    <copy todir="${webapps.build}/${webapp.name}/WEB-INF/lib" file="${struts-core.jar}"/>
+    <copy todir="${webapps.build}/${webapp.name}/WEB-INF/lib" file="${struts-taglib.jar}" />
+  </target>
+
+
+  <!-- =================== BUILD: Create Directories ====================== -->
+  <target name="build-prepare">
+    <mkdir dir="${webapps.build}"/>
+    <mkdir dir="${webapps.build}/${webapp.name}"/>
+    <mkdir dir="${webapps.build}/${webapp.name}/WEB-INF"/>
+    <mkdir dir="${webapps.build}/${webapp.name}/WEB-INF/classes"/>
+    <mkdir dir="${webapps.build}/${webapp.name}/WEB-INF/lib"/>
+  </target>
+
+
+  <!-- ================ BUILD: Copy Static Files ========================== -->
+  <target name="build-static" depends="flags,flags.display,build-prepare,copy-struts.jar">
+    <copy todir="${webapps.build}/${webapp.name}/WEB-INF/lib" file="${commons-beanutils.jar}"/>
+    <copy tofile="${webapps.build}/${webapp.name}/WEB-INF/lib/commons-collections.jar" 
+    	file="${commons-collections.jar}"/>
+    <copy todir="${webapps.build}/${webapp.name}/WEB-INF/lib" file="${commons-digester.jar}"/>
+    <copy todir="${webapps.build}/${webapp.name}">
+      <fileset dir=".">
+        <exclude name="build.*"/>
+        <exclude name="**/*.java"/>
+      </fileset>
+    </copy>
+  </target>
+
+
+  <!-- ================= BUILD: Compile Server Components ================= -->
+  <target name="build-main" depends="build-static" if="compile.admin">
+  
+    <javac   srcdir="WEB-INF/classes"
+             destdir="${webapps.build}/${webapp.name}/WEB-INF/classes"
+             debug="${compile.debug}" deprecation="${compile.deprecation}"
+             optimize="${compile.optimize}"
+             excludes="**/CVS/**">
+      <classpath refid="admin.classpath" />
+    </javac>
+
+  </target>
+
+
+  <!-- ==================== BUILD: Rebuild Everything ===================== -->
+  <target name="all" depends="build-clean,build-main"
+   description="Clean and build admin webapp"/>
+
+
+  <!-- ======================= BUILD: Clean Directory ===================== -->
+  <target name="build-clean">
+    <delete dir="${webapps.build}"/>
+  </target>
+
+
+  <!-- ======================= DIST: Create Directories =================== -->
+  <target name="dist-prepare">
+    <mkdir dir="${webapps.dist}"/>
+  </target>
+
+
+  <!-- ======================= DIST: Create Distribution Files ============ -->
+  <target name="dist" depends="build-main,dist-prepare"
+   description="Create admin webapp binary distribution">
+      <jar   jarfile="${webapps.dist}/${webapp.name}.war"
+             basedir="${webapps.build}/${webapp.name}" includes="**"/>
+  </target>
+
+
+  <!-- ======================= DIST: Clean Directory ====================== -->
+  <target name="dist-clean">
+    <deltree dir="${dist.dir}"/>
+  </target>
+
+
+  <!-- ====================== Convenient Synonyms ========================= -->
+  <target name="clean" depends="build-clean,dist-clean"
+   description="Clean build and dist directories"/>
+
+
+</project>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/buttons.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/buttons.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/buttons.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,16 @@
+   <table width="100%" border="0" cellspacing="0" cellpadding="0">
+    <tr>
+      <td>&nbsp;</td>
+    </tr>
+    <tr>
+      <td colspan="2" align="right" nowrap>
+        <html:submit styleClass="button">
+           <bean:message key="button.save"/> 
+        </html:submit>          
+        &nbsp;
+        <html:reset styleClass="button">
+            <bean:message key="button.cancel"/> 
+        </html:reset> 
+      </td>
+    </tr>
+</table>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/connector/connector.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/connector/connector.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/connector/connector.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,439 @@
+<!-- Standard Struts Entries -->
+
+<%@ page language="java" import="java.net.URLEncoder" contentType="text/html;charset=utf-8" %>
+<%@ taglib uri="http://struts.apache.org/tags-bean" prefix="bean" %>
+<%@ taglib uri="http://struts.apache.org/tags-html" prefix="html" %>
+<%@ taglib uri="http://struts.apache.org/tags-logic" prefix="logic" %>
+<%@ taglib uri="/WEB-INF/controls.tld" prefix="controls" %>
+
+<html:html locale="true">
+
+<%@ include file="../users/header.jsp" %>
+
+<!-- Body -->
+<body bgcolor="white" background="../images/PaperTexture.gif">
+
+<!--Form -->
+
+<html:errors/>
+
+<html:form method="POST" action="/SaveConnector">
+
+  <bean:define id="thisObjectName" type="java.lang.String"
+               name="connectorForm" property="objectName"/>
+  <html:hidden property="connectorName"/>
+  <html:hidden property="adminAction"/>
+  <html:hidden property="objectName"/>
+  <html:hidden property="connectorType"/>
+  <html:hidden property="serviceName"/>
+
+  <table width="100%" border="0" cellspacing="0" cellpadding="0">
+    <tr bgcolor="7171A5">
+      <td width="81%">
+       <div class="page-title-text" align="left">
+          <logic:equal name="connectorForm" property="adminAction" value="Create">
+            <bean:message key="actions.connectors.create"/>
+          </logic:equal>
+          <logic:equal name="connectorForm" property="adminAction" value="Edit">
+           <bean:write name="connectorForm" property="nodeLabel"/>
+          </logic:equal>
+       </div>
+      </td>
+      <td align="right" nowrap>
+        <div class="page-title-text">
+      <controls:actions label="Connector Actions">
+            <controls:action selected="true"> ----<bean:message key="actions.available.actions"/>---- </controls:action>
+            <controls:action> --------------------------------- </controls:action>
+            <logic:notEqual name="connectorForm" property="adminAction" value="Create">
+            <logic:notEqual name="connectorForm" property="portText"
+                            value='<%= Integer.toString(request.getServerPort()) %>'>
+            <controls:action url='<%= "/DeleteConnector.do?select=" +
+                                        URLEncoder.encode(thisObjectName,"UTF-8") %>'>
+            <bean:message key="actions.connectors.delete"/>
+            </controls:action>
+            </logic:notEqual>
+            </logic:notEqual>
+       </controls:actions>
+         </div>
+      </td>
+    </tr>
+  </table>
+    <%@ include file="../buttons.jsp" %>
+  <br>
+
+  <table class="back-table" border="0" cellspacing="0" cellpadding="1" width="100%">
+    <tr>
+      <td>
+       <controls:table tableStyle="front-table" lineStyle="line-row">
+            <controls:row header="true"
+                labelStyle="table-header-text" dataStyle="table-header-text">
+            <controls:label>General</controls:label>
+            <controls:data>&nbsp;</controls:data>
+        </controls:row>
+
+        <controls:row labelStyle="table-label-text" dataStyle="table-normal-text" styleId="connectorType">
+            <controls:label><bean:message key="connector.type"/>:</controls:label>
+            <controls:data>
+                 <logic:equal name="connectorForm" property="adminAction" value="Create">
+                    <html:select property="connectorType" onchange="IA_jumpMenu('self',this)" styleId="connectorType">
+                     <bean:define id="connectorTypeVals" name="connectorForm" property="connectorTypeVals"/>
+                     <html:options collection="connectorTypeVals" property="value" labelProperty="label"/>
+                    </html:select>
+                </logic:equal>
+                <logic:equal name="connectorForm" property="adminAction" value="Edit">
+                  <bean:write name="connectorForm" property="connectorType" scope="session"/>
+                </logic:equal>
+            </controls:data>
+        </controls:row>
+
+    <%-- do not show scheme while creating a new connector --%>
+    <logic:notEqual name="connectorForm" property="adminAction" value="Create">
+        <controls:row labelStyle="table-label-text" dataStyle="table-normal-text">
+            <controls:label><bean:message key="connector.scheme"/>:</controls:label>
+            <controls:data>
+              <bean:write name="connectorForm" property="scheme" scope="session"/>
+            </controls:data>
+        </controls:row>
+     </logic:notEqual>
+
+        <controls:row labelStyle="table-label-text" dataStyle="table-normal-text" styleId="enableDNS">
+            <controls:label><bean:message key="connector.enable.dns"/>:</controls:label>
+            <controls:data>
+                <html:select property="enableLookups" styleId="enableDNS">
+                     <bean:define id="booleanVals" name="connectorForm" property="booleanVals"/>
+                     <html:options collection="booleanVals" property="value"
+                   labelProperty="label"/>
+                </html:select>
+            </controls:data>
+        </controls:row>
+
+        <controls:row labelStyle="table-label-text" dataStyle="table-normal-text" styleId="uriencoding">
+            <controls:label><bean:message key="connector.uriencoding"/>:</controls:label>
+            <controls:data>
+               <html:text property="URIEncodingText" size="30" styleId="uriencoding"/>
+            </controls:data>
+        </controls:row>
+
+        <controls:row labelStyle="table-label-text" dataStyle="table-normal-text" styleId="usebodyencoding">
+            <controls:label><bean:message key="connector.useBodyEncodingForURI"/>:</controls:label>
+            <controls:data>
+                <html:select property="useBodyEncodingForURIText" styleId="usebodyencoding">
+                     <bean:define id="booleanVals" name="connectorForm" property="booleanVals"/>
+                     <html:options collection="booleanVals" property="value"
+                   labelProperty="label"/>
+                </html:select>
+            </controls:data>
+        </controls:row>
+
+        <controls:row labelStyle="table-label-text" dataStyle="table-normal-text" styleId="allowTrace">
+            <controls:label><bean:message key="connector.allowTrace"/>:</controls:label>
+            <controls:data>
+                <html:select property="allowTraceText" styleId="allowTrace">
+                     <bean:define id="booleanVals" name="connectorForm" property="booleanVals"/>
+                     <html:options collection="booleanVals" property="value"
+                   labelProperty="label"/>
+                </html:select>
+            </controls:data>
+        </controls:row>
+
+        <%-- Input only allowed on create transaction --%>
+        <controls:row labelStyle="table-label-text" dataStyle="table-normal-text" styleId="address">
+            <controls:label><bean:message key="connector.address.ip"/>:</controls:label>
+            <controls:data>
+             <logic:equal name="connectorForm" property="adminAction" value="Create">
+               <html:text property="address" size="20" styleId="address"/>
+             </logic:equal>
+             <logic:equal name="connectorForm" property="adminAction" value="Edit">
+               &nbsp;<bean:write name="connectorForm" property="address"/>
+               <html:hidden property="address"/>
+             </logic:equal>
+            </controls:data>
+        </controls:row>
+
+        <controls:row labelStyle="table-label-text" dataStyle="table-normal-text" styleId="secure">
+            <controls:label><bean:message key="connector.secure"/>:</controls:label>
+            <controls:data>
+                <html:select property="secure" styleId="secure">
+                     <bean:define id="booleanVals" name="connectorForm" property="booleanVals"/>
+                     <html:options collection="booleanVals" property="value"
+                   labelProperty="label"/>
+                </html:select>
+            </controls:data>
+        </controls:row>
+
+        <%--controls:row header="true" labelStyle="table-header-text" dataStyle="table-header-text">
+            <controls:label>Processors</controls:label>
+            <controls:data>&nbsp;</controls:data>
+        </controls:row>
+
+        <controls:row labelStyle="table-label-text" dataStyle="table-normal-text" styleId="minProcessor">
+            <controls:label><bean:message key="connector.min"/>:</controls:label>
+            <controls:data>
+               <html:text property="minProcessorsText" size="5" styleId="minProcessor"/>
+            </controls:data>
+        </controls:row>
+
+        <controls:row labelStyle="table-label-text" dataStyle="table-normal-text" styleId="connectorMax">
+            <controls:label><bean:message key="connector.max"/>:</controls:label>
+            <controls:data>
+               <html:text property="maxProcessorsText" size="5" styleId="connectorMax"/>
+            </controls:data>
+        </controls:row--%>
+
+<%-- The following properties are supported only for Coyote HTTP/S 1.1 Connectors --%>
+
+     <logic:notEqual name="connectorForm" property="connectorType" scope="session"
+                  value="AJP">
+       <controls:row labelStyle="table-label-text" dataStyle="table-normal-text" styleId="acceptCount">
+            <controls:label><bean:message key="connector.accept.count"/>:</controls:label>
+            <controls:data>
+              <html:text property="acceptCountText" size="5" maxlength="5" styleId="acceptCount"/>
+            </controls:data>
+        </controls:row>
+
+        <controls:row labelStyle="table-label-text" dataStyle="table-normal-text" styleId="compression">
+            <controls:label><bean:message key="connector.compression"/>:</controls:label>
+            <controls:data>
+               <html:text property="compression" size="10" styleId="compression"/>
+            </controls:data>
+        </controls:row>
+
+       <controls:row labelStyle="table-label-text" dataStyle="table-normal-text" styleId="linger">
+            <controls:label><bean:message key="connector.connection.linger"/><br>
+                (<bean:message key="connector.milliseconds"/>) :</controls:label>
+            <controls:data>
+               <html:text property="connLingerText" size="10" styleId="linger"/>
+            </controls:data>
+        </controls:row>
+
+       <controls:row labelStyle="table-label-text" dataStyle="table-normal-text" styleId="timeout">
+            <controls:label><bean:message key="connector.connection.timeout"/><br>
+                (<bean:message key="connector.milliseconds"/>) :</controls:label>
+            <controls:data>
+               <html:text property="connTimeOutText" size="10" styleId="timeout"/>
+            </controls:data>
+        </controls:row>
+
+       <controls:row labelStyle="table-label-text" dataStyle="table-normal-text" styleId="upload">
+            <controls:label><bean:message key="connector.connection.uploadTimeout"/><br>
+                (<bean:message key="connector.milliseconds"/>) :</controls:label>
+            <controls:data>
+               <html:text property="connUploadTimeOutText" size="10" styleId="upload"/>
+            </controls:data>
+        </controls:row>
+
+        <controls:row labelStyle="table-label-text" dataStyle="table-normal-text" styleId="buffersize">
+            <controls:label><bean:message key="connector.default.buffer"/>:</controls:label>
+            <controls:data>
+               <html:text property="bufferSizeText" size="5" styleId="buffersize"/>
+            </controls:data>
+        </controls:row>
+
+        <controls:row labelStyle="table-label-text" dataStyle="table-normal-text" styleId="disableUpload">
+            <controls:label><bean:message key="connector.connection.disableUploadTimeout"/>:</controls:label>
+            <controls:data>
+                <html:select property="disableUploadTimeout" styleId="disableUpload">
+                     <bean:define id="booleanVals" name="connectorForm" property="booleanVals"/>
+                     <html:options collection="booleanVals" property="value"
+                   labelProperty="label"/>
+                </html:select>
+            </controls:data>
+        </controls:row>
+
+        <controls:row labelStyle="table-label-text" dataStyle="table-normal-text" styleId="maxkeepalive">
+            <controls:label><bean:message key="connector.maxkeepalive"/>:</controls:label>
+            <controls:data>
+              <html:text property="maxKeepAliveText" size="5" maxlength="5" styleId="maxkeepalive"/>
+            </controls:data>
+        </controls:row>
+
+        <controls:row labelStyle="table-label-text" dataStyle="table-normal-text" styleId="maxspare">
+            <controls:label><bean:message key="connector.maxspare"/>:</controls:label>
+            <controls:data>
+              <html:text property="maxSpare" size="5" maxlength="5" styleId="maxspare"/>
+            </controls:data>
+        </controls:row>
+	
+        <controls:row labelStyle="table-label-text" dataStyle="table-normal-text" styleId="maxthreads">
+            <controls:label><bean:message key="connector.maxthreads"/>:</controls:label>
+            <controls:data>
+              <html:text property="maxThreads" size="5" maxlength="5" styleId="maxthreads"/>
+            </controls:data>
+        </controls:row>
+
+        <controls:row labelStyle="table-label-text" dataStyle="table-normal-text" styleId="minspare">
+            <controls:label><bean:message key="connector.minspare"/>:</controls:label>
+            <controls:data>
+              <html:text property="minSpare" size="5" maxlength="5" styleId="minspare"/>
+            </controls:data>
+        </controls:row>
+
+        <controls:row labelStyle="table-label-text" dataStyle="table-normal-text" styleId="threadpriority">
+            <controls:label><bean:message key="connector.threadpriority"/>:</controls:label>
+            <controls:data>
+              <html:text property="threadPriority" size="5" maxlength="5" styleId="threadpriority"/>
+            </controls:data>
+        </controls:row>
+
+        <controls:row labelStyle="table-label-text" dataStyle="table-normal-text" styleId="tcpNoDelay">
+            <controls:label><bean:message key="connector.tcpNoDelay"/>:</controls:label>
+            <controls:data>
+                <html:select property="tcpNoDelay" styleId="tcpNoDelay">
+                     <bean:define id="booleanVals" name="connectorForm" property="booleanVals"/>
+                     <html:options collection="booleanVals" property="value"
+                   labelProperty="label"/>
+                </html:select>
+            </controls:data>
+        </controls:row>
+
+        <controls:row labelStyle="table-label-text" dataStyle="table-normal-text" styleId="xpoweredby">
+            <controls:label><bean:message key="connector.xpoweredby"/>:</controls:label>
+            <controls:data>
+                <html:select property="xpoweredBy" styleId="xpoweredby">
+                     <bean:define id="booleanVals" name="connectorForm" property="booleanVals"/>
+                     <html:options collection="booleanVals" property="value"
+                   labelProperty="label"/>
+                </html:select>
+            </controls:data>
+        </controls:row>
+     </logic:notEqual>
+
+        <controls:row header="true" labelStyle="table-header-text" dataStyle="table-header-text">
+            <controls:label>Ports</controls:label>
+            <controls:data>&nbsp;</controls:data>
+        </controls:row>
+
+        <%-- Input only allowed on create transaction --%>
+        <controls:row labelStyle="table-label-text" dataStyle="table-normal-text" styleId="portnumber">
+            <controls:label><bean:message key="server.portnumber"/>:</controls:label>
+            <controls:data>
+             <logic:equal name="connectorForm" property="adminAction" value="Create">
+               <html:text property="portText" size="5" styleId="portnumer"/>
+             </logic:equal>
+             <logic:equal name="connectorForm" property="adminAction" value="Edit">
+               <bean:write name="connectorForm" property="portText"/>
+               <html:hidden property="portText"/>
+             </logic:equal>
+            </controls:data>
+        </controls:row>
+
+        <controls:row labelStyle="table-label-text" dataStyle="table-normal-text" styleId="redirectport">
+            <controls:label><bean:message key="connector.redirect.portnumber"/>:</controls:label>
+            <controls:data>
+               <html:text property="redirectPortText" size="5" styleId="redirectport"/>
+            </controls:data>
+        </controls:row>
+
+        <controls:row header="true" labelStyle="table-header-text" dataStyle="table-header-text">
+            <controls:label>Proxy</controls:label>
+            <controls:data>&nbsp;</controls:data>
+        </controls:row>
+
+        <controls:row labelStyle="table-label-text" dataStyle="table-normal-text" styleId="proxyName">
+            <controls:label><bean:message key="connector.proxy.name"/>:</controls:label>
+            <controls:data>
+               <html:text property="proxyName" size="30" styleId="proxyName"/>
+            </controls:data>
+        </controls:row>
+
+        <controls:row labelStyle="table-label-text" dataStyle="table-normal-text" styleId="portNumber">
+            <controls:label><bean:message key="connector.proxy.portnumber"/>:</controls:label>
+            <controls:data>
+                <html:text property="proxyPortText" size="5" styleId="portNumber"/>
+            </controls:data>
+        </controls:row>
+
+<%-- The following properties are supported only on HTTPS Connector --%>
+     <logic:equal name="connectorForm" property="scheme" scope="session"
+                  value="https">
+        <br>
+        <controls:row header="true" labelStyle="table-header-text" dataStyle="table-header-text">
+            <controls:label>Factory Properties:</controls:label>
+            <controls:data>&nbsp;</controls:data>
+        </controls:row>
+
+        <controls:row labelStyle="table-label-text" dataStyle="table-normal-text" styleId="algorithm">
+            <controls:label><bean:message key="connector.algorithm"/>:</controls:label>
+            <controls:data>
+               <html:text property="algorithm" size="10" styleId="algorithm"/>
+            </controls:data>
+        </controls:row>
+
+        <controls:row labelStyle="table-label-text" dataStyle="table-normal-text" styleId="ciphers">
+            <controls:label><bean:message key="connector.ciphers"/>:</controls:label>
+            <controls:data>
+               <html:text property="ciphers" size="10" styleId="ciphers"/>
+            </controls:data>
+        </controls:row>
+
+        <controls:row labelStyle="table-label-text" dataStyle="table-normal-text" styleId="clientauth">
+            <controls:label><bean:message key="connector.client.auth"/>:</controls:label>
+            <controls:data>
+                <html:select property="clientAuthentication" styleId="clientauth">
+                     <bean:define id="clientAuthVals" name="connectorForm" property="clientAuthVals"/>
+                     <html:options collection="clientAuthVals" property="value"
+                   labelProperty="label"/>
+                </html:select>
+            </controls:data>
+        </controls:row>
+
+        <%-- Input allowed only on create --%>
+        <controls:row labelStyle="table-label-text" dataStyle="table-normal-text" styleId="keystore">
+            <controls:label><bean:message key="connector.keystore.filename"/>:</controls:label>
+            <controls:data>
+            <logic:equal name="connectorForm" property="adminAction" value="Create">
+                <html:text property="keyStoreFileName" size="30" styleId="keystore"/>
+             </logic:equal>
+             <logic:equal name="connectorForm" property="adminAction" value="Edit">
+               <bean:write name="connectorForm" property="keyStoreFileName"/>
+             </logic:equal>
+            </controls:data>
+        </controls:row>
+
+        <%-- input password allowed only while creating connector --%>
+        <logic:equal name="connectorForm" property="adminAction" value="Create">
+        <controls:row labelStyle="table-label-text" dataStyle="table-normal-text" styleId="password">
+            <controls:label><bean:message key="connector.keystore.password"/>:</controls:label>
+            <controls:data>
+                <html:password property="keyStorePassword" size="30" styleId="password"/>
+                <%--
+                <logic:equal name="connectorForm" property="adminAction" value="Edit">
+                   <bean:write name="connectorForm" property="keyStorePassword"/>
+                </logic:equal>
+                --%>
+            </controls:data>
+        </controls:row>
+        </logic:equal>
+
+        <%-- Input allowed only on create --%>
+        <controls:row labelStyle="table-label-text" dataStyle="table-normal-text" styleId="keytype">
+            <controls:label><bean:message key="connector.keystore.type"/>:</controls:label>
+            <controls:data>
+            <logic:equal name="connectorForm" property="adminAction" value="Create">
+                <html:text property="keyStoreType" size="30" styleId="keytype"/>
+             </logic:equal>
+             <logic:equal name="connectorForm" property="adminAction" value="Edit">
+               <bean:write name="connectorForm" property="keyStoreType"/>
+             </logic:equal>
+            </controls:data>
+        </controls:row>
+
+        <controls:row labelStyle="table-label-text" dataStyle="table-normal-text" styleId="sslProtocol">
+            <controls:label><bean:message key="connector.sslProtocol"/>:</controls:label>
+            <controls:data>
+               <html:text property="sslProtocol" size="10" styleId="sslProtocol"/>
+            </controls:data>
+        </controls:row>
+
+    </logic:equal>
+   </controls:table>
+
+      </td>
+    </tr>
+  </table>
+    <%@ include file="../buttons.jsp" %>
+  <br>
+  </html:form>
+<p>&nbsp;</p>
+</body>
+</html:html>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/connector/connectors.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/connector/connectors.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/connector/connectors.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,99 @@
+<!-- Standard Struts Entries -->
+<%@ page language="java" contentType="text/html;charset=utf-8" %>
+<%@ taglib uri="http://struts.apache.org/tags-bean" prefix="bean" %>
+<%@ taglib uri="http://struts.apache.org/tags-html" prefix="html" %>
+<%@ taglib uri="http://struts.apache.org/tags-logic" prefix="logic" %>
+<%@ taglib uri="/WEB-INF/controls.tld" prefix="controls" %>
+
+<html:html locale="true">
+
+<%@ include file="../users/header.jsp" %>
+
+<!-- Body -->
+<body bgcolor="white" background="../images/PaperTexture.gif">
+
+<!--Form -->
+
+<html:errors/>
+
+<html:form method="post" action="/DeleteConnectors">
+
+  <table width="100%" border="0" cellspacing="0" cellpadding="0">
+    <tr bgcolor="7171A5">
+      <td width="81%">
+        <div class="page-title-text" align="left">
+          <bean:message key="actions.connectors.delete"/>
+        </div>
+      </td>
+      <td align="right" nowrap>
+        <div class="page-title-text">
+            <controls:actions label="Connector Actions">
+              <controls:action selected="true">
+                ----<bean:message key="actions.available.actions"/>----
+              </controls:action>
+              <controls:action>
+                ---------------------------------
+              </controls:action>
+            </controls:actions>
+        </div>
+      </td>
+    </tr>
+  </table>
+
+<%@ include file="../buttons.jsp" %>
+  <br>
+
+  <%-- Connectors List --%>
+
+  <table class="back-table" border="0" cellspacing="0" cellpadding="1"
+         width="100%">
+    <tr><td>
+
+      <table class="front-table" border="1"
+       cellspacing="0" cellpadding="0" width="100%">
+
+        <tr class="header-row">
+          <td><div align="left" class="table-header-text">
+            <bean:message key="actions.delete"/>
+          </div></td>
+          <td><div align="left" class="table-header-text">
+            <bean:message key="host.name"/>
+          </div></td>
+        </tr>
+
+        <logic:iterate name="connectorsList" id="connector">
+          <tr class="line-row">
+            <td><div align="left" class="table-normal-text">&nbsp;
+            <%-- the connector the admin app is running on cannot be deleted
+                 through the tool --%>
+              <logic:match  name="connector" value='<%= Integer.toString(request.getServerPort()) %>'>
+                <font color='red'>*</font>
+              </logic:match>
+            <logic:notMatch name="connector" value='<%= Integer.toString(request.getServerPort()) %>'>
+              <label for="connectors"></label>
+              <html:multibox property="connectors"
+                                value="<%= connector.toString() %>" styleId="connectors"/>
+            </logic:notMatch>
+            </div></td>
+            <td><div align="left" class="table-normal-text">&nbsp;
+              <html:link page='<%= "/EditConnector.do?select=" +
+                         java.net.URLEncoder.encode(connector.toString(),"UTF-8") %>'>
+                Connector (<controls:attribute name="connector" attribute="port"/>)
+              </html:link>
+            </div></td>
+          </tr>
+        </logic:iterate>
+
+      </table>
+
+    </td></tr>
+  </table>
+
+<%@ include file="../buttons.jsp" %>
+
+  <br>
+</html:form>
+
+<p>&nbsp;</p>
+</body>
+</html:html>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/context/context.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/context/context.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/context/context.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,339 @@
+<!-- Standard Struts Entries -->
+<%@ page language="java" import="java.net.URLEncoder" contentType="text/html;charset=utf-8" %>
+<%@ taglib uri="http://struts.apache.org/tags-bean" prefix="bean" %>
+<%@ taglib uri="http://struts.apache.org/tags-html" prefix="html" %>
+<%@ taglib uri="http://struts.apache.org/tags-logic" prefix="logic" %>
+<%@ taglib uri="/WEB-INF/controls.tld" prefix="controls" %>
+
+<html:html locale="true">
+
+<%@ include file="../users/header.jsp" %>
+
+<!-- Body -->
+<body bgcolor="white" background="../images/PaperTexture.gif">
+
+<!--Form -->
+
+<html:errors/>
+
+<html:form method="POST" action="/SaveContext">
+  <bean:define id="thisObjectName" type="java.lang.String"
+               name="contextForm" property="objectName"/>
+  <html:hidden property="adminAction"/>
+  <html:hidden property="objectName"/>
+  <html:hidden property="parentObjectName"/>
+  <html:hidden property="loaderObjectName"/>
+  <html:hidden property="managerObjectName"/>
+
+  <table width="100%" border="0" cellspacing="0" cellpadding="0">
+    <tr bgcolor="7171A5">
+      <td width="81%">
+       <div class="page-title-text" align="left">
+          <logic:equal name="contextForm" property="adminAction" value="Create">
+            <bean:message key="actions.contexts.create"/>
+          </logic:equal>
+          <logic:equal name="contextForm" property="adminAction" value="Edit">
+            <bean:write name="contextForm" property="nodeLabel"/>
+          </logic:equal>
+       </div>
+      </td>
+      <td align="right" nowrap>
+        <div class="page-title-text">
+      <controls:actions label="Context Actions">
+            <controls:action selected="true"> ----<bean:message key="actions.available.actions"/>---- </controls:action>
+            <controls:action disabled="true"> --------------------------------- </controls:action>
+            <logic:notEqual name="contextForm" property="adminAction" value="Create">
+            <%-- cannot delete or add the realm of the context of the admin app --%>
+            <logic:notEqual name="contextForm" property="path"
+                            value='<%= request.getContextPath() %>'>
+            <controls:action url='<%= "/AddRealm.do?parent=" +
+                                  URLEncoder.encode(thisObjectName,"UTF-8") %>'>
+                <bean:message key="actions.realms.create"/>
+            </controls:action>
+            <controls:action url='<%= "/DeleteRealm.do?parent=" +
+                                  URLEncoder.encode(thisObjectName,"UTF-8") %>'>
+                <bean:message key="actions.realms.deletes"/>
+            </controls:action>
+            </logic:notEqual>
+            <controls:action disabled="true">  -------------------------------------  </controls:action>
+            <controls:action url='<%= "/AddValve.do?parent=" +
+                                  URLEncoder.encode(thisObjectName,"UTF-8") %>'>
+               <bean:message key="actions.valves.create"/>
+            </controls:action>
+            <controls:action url='<%= "/DeleteValve.do?parent=" +
+                                  URLEncoder.encode(thisObjectName,"UTF-8") %>'>
+               <bean:message key="actions.valves.deletes"/>
+            </controls:action>
+            <%-- cannot delete the context of the admin app  from the tool --%>
+            <logic:notEqual name="contextForm" property="path"
+                            value='<%= request.getContextPath() %>'>
+            <controls:action disabled="true">  -------------------------------------  </controls:action>
+            <controls:action url='<%= "/DeleteContext.do?select=" +
+                                        URLEncoder.encode(thisObjectName,"UTF-8") %>'>
+                <bean:message key="actions.contexts.delete"/>
+            </controls:action>
+            </logic:notEqual>
+            </logic:notEqual>
+        </controls:actions>
+         </div>
+      </td>
+    </tr>
+  </table>
+    <%@ include file="../buttons.jsp" %>
+  <br>
+
+ <%-- Context Properties table --%>
+
+ <table border="0" cellspacing="0" cellpadding="0" width="100%">
+    <tr> <td>  <div class="table-title-text">
+            <bean:message key="context.properties"/>
+    </div> </td> </tr>
+  </table>
+
+  <table class="back-table" border="0" cellspacing="0" cellpadding="1" width="100%">
+    <tr>
+      <td>
+       <controls:table tableStyle="front-table" lineStyle="line-row">
+            <controls:row header="true"
+                labelStyle="table-header-text" dataStyle="table-header-text">
+            <controls:label><bean:message key="service.property"/></controls:label>
+            <controls:data><bean:message key="service.value"/></controls:data>
+        </controls:row>
+
+        <controls:row labelStyle="table-label-text" dataStyle="table-normal-text" styleId="cookies">
+            <controls:label><bean:message key="context.cookies"/>:</controls:label>
+            <controls:data>
+                <html:select property="cookies" styleId="cookies">
+                     <bean:define id="booleanVals" name="contextForm" property="booleanVals"/>
+                     <html:options collection="booleanVals" property="value"
+                   labelProperty="label"/>
+                </html:select>
+            </controls:data>
+        </controls:row>
+
+        <controls:row labelStyle="table-label-text" dataStyle="table-normal-text" styleId="crossContext">
+            <controls:label><bean:message key="context.cross.context"/>:</controls:label>
+            <controls:data>
+                <html:select property="crossContext" styleId="crossContext">
+                     <bean:define id="booleanVals" name="contextForm" property="booleanVals"/>
+                     <html:options collection="booleanVals" property="value"
+                   labelProperty="label"/>
+                </html:select>
+            </controls:data>
+        </controls:row>
+
+<%-- input only allowed on create transaction --%>
+       <controls:row labelStyle="table-label-text" dataStyle="table-normal-text" styleId="docbase">
+            <controls:label><bean:message key="context.docBase"/>:</controls:label>
+            <controls:data>
+              <logic:equal name="contextForm" property="adminAction" value="Create">
+               <html:text property="docBase" size="30" styleId="docbase"/>
+              </logic:equal>
+              <logic:equal name="contextForm" property="adminAction" value="Edit">
+               <bean:write name="contextForm" property="docBase"/>
+               <html:hidden property="docBase"/>
+              </logic:equal>
+            </controls:data>
+        </controls:row>
+
+      <controls:row labelStyle="table-label-text" dataStyle="table-normal-text" styleId="override">
+            <controls:label><bean:message key="context.override"/>:</controls:label>
+            <controls:data>
+                <html:select property="override" styleId="override">
+                     <bean:define id="booleanVals" name="contextForm" property="booleanVals"/>
+                     <html:options collection="booleanVals" property="value"
+                   labelProperty="label"/>
+                </html:select>
+            </controls:data>
+        </controls:row>
+
+      <controls:row labelStyle="table-label-text" dataStyle="table-normal-text" styleId="privileged">
+            <controls:label><bean:message key="context.privileged"/>:</controls:label>
+            <controls:data>
+                <html:select property="privileged" styleId="privileged">
+                     <bean:define id="booleanVals" name="contextForm" property="booleanVals"/>
+                     <html:options collection="booleanVals" property="value"
+                   labelProperty="label"/>
+                </html:select>
+            </controls:data>
+        </controls:row>
+
+<%-- input only allowed on create transaction --%>
+       <controls:row labelStyle="table-label-text" dataStyle="table-normal-text" styleId="path">
+            <controls:label><bean:message key="context.path"/>:</controls:label>
+            <controls:data>
+             <logic:equal name="contextForm" property="adminAction" value="Create">
+               <html:text property="path" size="30" styleId="path"/>
+             </logic:equal>
+             <logic:equal name="contextForm" property="adminAction" value="Edit">
+               <bean:write name="contextForm" property="path"/>
+               <html:hidden property="path"/>
+             </logic:equal>
+            </controls:data>
+        </controls:row>
+
+      <controls:row labelStyle="table-label-text" dataStyle="table-normal-text" styleId="reloadable">
+            <controls:label><bean:message key="context.reloadable"/>:</controls:label>
+            <controls:data>
+                <html:select property="reloadable" styleId="reloadable">
+                     <bean:define id="booleanVals" name="contextForm" property="booleanVals"/>
+                     <html:options collection="booleanVals" property="value"
+                   labelProperty="label"/>
+                </html:select>
+            </controls:data>
+        </controls:row>
+
+      <controls:row labelStyle="table-label-text" dataStyle="table-normal-text" styleId="swallowOutput">
+            <controls:label><bean:message key="context.swallowOutput"/>:</controls:label>
+            <controls:data>
+                <html:select property="swallowOutput" styleId="swallowOutput">
+                     <bean:define id="booleanVals" name="contextForm" property="booleanVals"/>
+                     <html:options collection="booleanVals" property="value"
+                   labelProperty="label"/>
+                </html:select>
+            </controls:data>
+        </controls:row>
+
+      <controls:row labelStyle="table-label-text" dataStyle="table-normal-text" styleId="usernaming">
+            <controls:label><bean:message key="context.usenaming"/>:</controls:label>
+            <controls:data>
+                <html:select property="useNaming" styleId="usernaming">
+                     <bean:define id="booleanVals" name="contextForm" property="booleanVals"/>
+                     <html:options collection="booleanVals" property="value"
+                   labelProperty="label"/>
+                </html:select>
+            </controls:data>
+        </controls:row>
+
+      <controls:row labelStyle="table-label-text" dataStyle="table-normal-text" styleId="antiJarLocking">
+            <controls:label><bean:message key="context.antiJarLocking"/>:</controls:label>
+            <controls:data>
+                <html:select property="antiJarLocking" styleId="antiJarLocking">
+                     <bean:define id="booleanVals" name="contextForm" property="booleanVals"/>
+                     <html:options collection="booleanVals" property="value"
+                   labelProperty="label"/>
+                </html:select>
+            </controls:data>
+        </controls:row>
+
+      <controls:row labelStyle="table-label-text" dataStyle="table-normal-text" styleId="antiResourceLocking">
+            <controls:label><bean:message key="context.antiResourceLocking"/>:</controls:label>
+            <controls:data>
+                <html:select property="antiResourceLocking" styleId="antiResourceLocking">
+                     <bean:define id="booleanVals" name="contextForm" property="booleanVals"/>
+                     <html:options collection="booleanVals" property="value"
+                   labelProperty="label"/>
+                </html:select>
+            </controls:data>
+        </controls:row>
+
+<%-- input only allowed on create transaction >
+       <controls:row labelStyle="table-label-text" dataStyle="table-normal-text" styleId="workdir">
+            <controls:label><bean:message key="context.workdir"/>:</controls:label>
+            <controls:data>
+             <logic:equal name="contextForm" property="adminAction" value="Create">
+               <html:text property="workDir" size="30" styleId="workdir"/>
+             </logic:equal>
+             <logic:equal name="contextForm" property="adminAction" value="Edit">
+               <bean:write name="contextForm" property="workDir"/>
+               <html:hidden property="workDir"/>
+             </logic:equal>
+            </controls:data>
+        </controls:row--%>
+   </controls:table>
+    </td>
+  </tr>
+</table>
+
+<br>
+
+<%-- Loader Properties table --%>
+
+ <table border="0" cellspacing="0" cellpadding="0" width="100%">
+    <tr> <td>  <div class="table-title-text">
+            <bean:message key="context.loader.properties"/>
+    </div> </td> </tr>
+  </table>
+
+  <table class="back-table" border="0" cellspacing="0" cellpadding="1" width="100%">
+    <tr>
+      <td>
+       <controls:table tableStyle="front-table" lineStyle="line-row">
+            <controls:row header="true"
+                labelStyle="table-header-text" dataStyle="table-header-text">
+            <controls:label><bean:message key="service.property"/></controls:label>
+            <controls:data><bean:message key="service.value"/></controls:data>
+        </controls:row>
+
+        <%--controls:row labelStyle="table-label-text" dataStyle="table-normal-text" styleId="checkInterval">
+            <controls:label><bean:message key="context.checkInterval"/>:</controls:label>
+            <controls:data>
+                <html:text property="ldrCheckInterval" size="5" styleId="checkInterval"/>
+            </controls:data>
+        </controls:row--%>
+
+      <controls:row labelStyle="table-label-text" dataStyle="table-normal-text" styleId="reloadable">
+            <controls:label><bean:message key="context.reloadable"/>:</controls:label>
+            <controls:data>
+                <html:select property="ldrReloadable" styleId="reloadable">
+                     <bean:define id="booleanVals" name="contextForm" property="booleanVals"/>
+                     <html:options collection="booleanVals" property="value"
+                   labelProperty="label"/>
+                </html:select>
+            </controls:data>
+        </controls:row>
+   </controls:table>
+    </td>
+  </tr>
+</table>
+
+<BR>
+<%-- Session Manager Properties table --%>
+ <table border="0" cellspacing="0" cellpadding="0" width="100%">
+    <tr> <td>  <div class="table-title-text">
+            <bean:message key="context.sessionmgr.properties"/>
+    </div> </td> </tr>
+  </table>
+
+  <table class="back-table" border="0" cellspacing="0" cellpadding="1" width="100%">
+    <tr>
+      <td>
+       <controls:table tableStyle="front-table" lineStyle="line-row">
+            <controls:row header="true"
+                labelStyle="table-header-text" dataStyle="table-header-text">
+            <controls:label><bean:message key="service.property"/></controls:label>
+            <controls:data><bean:message key="service.value"/></controls:data>
+        </controls:row>
+
+        <%--controls:row labelStyle="table-label-text" dataStyle="table-normal-text" styleId="checkInterval">
+            <controls:label><bean:message key="context.checkInterval"/>:</controls:label>
+            <controls:data>
+                <html:text property="mgrCheckInterval" size="5" styleId="checkInterval"/>
+            </controls:data>
+        </controls:row--%>
+
+       <controls:row labelStyle="table-label-text" dataStyle="table-normal-text" styleId="sessionId">
+            <controls:label><bean:message key="context.sessionId"/>:</controls:label>
+            <controls:data>
+               <html:textarea property="mgrSessionIDInit" cols="30" rows="2" styleId="sessionId"/>
+            </controls:data>
+        </controls:row>
+
+       <controls:row labelStyle="table-label-text" dataStyle="table-normal-text" styleId="maxSessions">
+            <controls:label><bean:message key="context.max.sessions"/>:</controls:label>
+            <controls:data>
+               <html:text property="mgrMaxSessions" size="5" styleId="maxSessions"/>
+            </controls:data>
+        </controls:row>
+   </controls:table>
+    </td>
+  </tr>
+</table>
+
+    <%@ include file="../buttons.jsp" %>
+
+  <br>
+  </html:form>
+<p>&nbsp;</p>
+</body>
+</html:html>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/context/contexts.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/context/contexts.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/context/contexts.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,97 @@
+<!-- Standard Struts Entries -->
+<%@ page language="java" contentType="text/html;charset=utf-8" %>
+<%@ taglib uri="http://struts.apache.org/tags-bean" prefix="bean" %>
+<%@ taglib uri="http://struts.apache.org/tags-html" prefix="html" %>
+<%@ taglib uri="http://struts.apache.org/tags-logic" prefix="logic" %>
+<%@ taglib uri="/WEB-INF/controls.tld" prefix="controls" %>
+
+<html:html locale="true">
+
+<%@ include file="../users/header.jsp" %>
+
+<!-- Body -->
+<body bgcolor="white" background="../images/PaperTexture.gif">
+
+<!--Form -->
+
+<html:errors/>
+
+<html:form method="post" action="/DeleteContexts">
+
+  <table width="100%" border="0" cellspacing="0" cellpadding="0">
+    <tr bgcolor="7171A5">
+      <td width="81%">
+        <div class="page-title-text" align="left">
+          <bean:message key="actions.contexts.delete"/>
+        </div>
+      </td>
+      <td align="right" nowrap>
+        <div class="page-title-text">
+            <controls:actions label="Context Actions">
+              <controls:action selected="true">
+                ----<bean:message key="actions.available.actions"/>----
+              </controls:action>
+              <controls:action>
+                ---------------------------------
+              </controls:action>
+            </controls:actions>
+        </div>
+      </td>
+    </tr>
+  </table>
+
+<%@ include file="../buttons.jsp" %>
+  <br>
+
+  <%-- Contexts List --%>
+  <table class="back-table" border="0" cellspacing="0" cellpadding="1"
+         width="100%">
+    <tr><td>
+
+      <table class="front-table" border="1"
+       cellspacing="0" cellpadding="0" width="100%">
+
+        <tr class="header-row">
+          <td><div align="left" class="table-header-text">
+            <bean:message key="actions.delete"/>
+          </div></td>
+          <td><div align="left" class="table-header-text">
+            <bean:message key="host.name"/>
+          </div></td>
+        </tr>
+    
+        <logic:iterate name="contextsList" id="context">
+          <tr class="line-row">
+            <td><div align="left" class="table-normal-text">&nbsp;
+              <%-- admin context cannot be deleted from the tool --%>
+              <logic:match name="context" value='<%= request.getContextPath()+"," %>'>
+                <font color='red'>*</font>
+              </logic:match>
+              <logic:notMatch name="context" value='<%= request.getContextPath()+"," %>'>
+              <label for="contexts"></label>
+              <html:multibox property="contexts"
+                                value="<%= context.toString() %>" styleId="contexts"/>
+              </logic:notMatch>
+            </div></td>
+            <td><div align="left" class="table-normal-text">&nbsp;
+              <html:link page='<%= "/EditContext.do?select=" +
+                         java.net.URLEncoder.encode(context.toString(),"UTF-8") %>'>
+                <controls:attribute name="context" attribute="path"/>
+              </html:link>
+            </div></td>
+          </tr>
+        </logic:iterate>
+
+      </table>
+
+    </td></tr>
+  </table>
+
+<%@ include file="../buttons.jsp" %>
+
+  <br>
+</html:form>
+
+<p>&nbsp;</p>
+</body>
+</html:html>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/dumpRegistry.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/dumpRegistry.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/dumpRegistry.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,48 @@
+<!-- Standard Struts Entries -->
+
+<%@ page language="java" contentType="text/html;charset=utf-8" %>
+<%@ taglib uri="http://struts.apache.org/tags-bean" prefix="bean" %>
+<%@ taglib uri="http://struts.apache.org/tags-html" prefix="html" %>
+<%@ taglib uri="http://struts.apache.org/tags-logic" prefix="logic" %>
+
+<html:html locale="true">
+
+<!-- Standard Content -->
+
+<%@ include file="header.jsp" %>
+
+<!-- Body -->
+
+<body bgcolor="white">
+
+<table border="1" cellpadding="5">
+
+  <tr>
+    <th align="center" colspan="3">
+      Registered Managed Beans
+    </th>
+  </tr>
+
+  <tr>
+    <th align="center">Name</th>
+    <th align="center">Group</th>
+    <th align="center">Description</th>
+  </tr>
+
+  <logic:iterate id="bean" name="beans">
+    <tr>
+      <td><bean:write name="bean" property="name"/></td>
+      <td><bean:write name="bean" property="group"/></td>
+      <td><bean:write name="bean" property="description"/></td>
+    </tr>
+  </logic:iterate>
+
+</table>
+
+</body>
+
+<!-- Standard Footer -->
+
+<%@ include file="footer.jsp" %>
+
+</html:html>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/dumpServer.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/dumpServer.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/dumpServer.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,44 @@
+<!-- Standard Struts Entries -->
+
+<%@ page language="java" contentType="text/html;charset=utf-8" %>
+<%@ taglib uri="http://struts.apache.org/tags-bean" prefix="bean" %>
+<%@ taglib uri="http://struts.apache.org/tags-html" prefix="html" %>
+<%@ taglib uri="http://struts.apache.org/tags-logic" prefix="logic" %>
+
+<html:html locale="true">
+
+<!-- Standard Content -->
+
+<%@ include file="header.jsp" %>
+
+<!-- Body -->
+
+<body bgcolor="white">
+
+<table border="1" cellpadding="5">
+
+  <tr>
+    <th align="center" colspan="1">
+      Registered MBean Names
+    </th>
+  </tr>
+
+  <tr>
+    <th align="center">Name</th>
+  </tr>
+
+  <logic:iterate id="name" name="names">
+    <tr>
+      <td><bean:write name="name"/></td>
+    </tr>
+  </logic:iterate>
+
+</table>
+
+</body>
+
+<!-- Standard Footer -->
+
+<%@ include file="footer.jsp" %>
+
+</html:html>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/error.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/error.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/error.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,37 @@
+<!-- Standard Struts Entries -->
+
+<%@ page language="java" contentType="text/html;charset=utf-8" %>
+<%@ taglib uri="http://struts.apache.org/tags-bean" prefix="bean" %>
+<%@ taglib uri="http://struts.apache.org/tags-html" prefix="html" %>
+<%@ taglib uri="http://struts.apache.org/tags-logic" prefix="logic" %>
+
+<html:html locale="true">
+
+<!-- Standard Content -->
+
+<%@ include file="header.jsp" %>
+
+<!-- Body -->
+
+<body bgcolor="white" background="images/PaperTexture.gif">
+
+<center>
+
+<h2>
+  <bean:message key="error.login"/>
+  <br>
+  <bean:message key="error.tryagain"/>
+  <html:link page="/">
+    <bean:message key="error.here"/>
+  </html:link>
+</h2>
+
+</center>
+
+</body>
+
+<!-- Standard Footer -->
+
+<%@ include file="footer.jsp" %>
+
+</html:html>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/footer.jsp
===================================================================

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/frameset.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/frameset.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/frameset.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,31 @@
+<!-- Standard Struts Entries -->
+
+<%@ page language="java" contentType="text/html;charset=utf-8" %>
+<%@ taglib uri="http://struts.apache.org/tags-bean" prefix="bean" %>
+<%@ taglib uri="http://struts.apache.org/tags-html" prefix="html" %>
+<%@ taglib uri="http://struts.apache.org/tags-logic" prefix="logic" %>
+
+<% // Force the initialization of "action" servlet
+   getServletContext().getNamedDispatcher("action").include(request,response);
+%> 
+
+<html:html locale="true">
+
+<!-- Standard Content -->
+
+<%@ include file="header.jsp" %>
+
+<!-- Body -->
+<frameset rows="117,685*" cols="*" frameborder="NO" border="3" framespacing="3">
+  <frame name="banner" src='<%= response.encodeURL("banner.jsp") %>' scrolling="no" title="commit and logout banner">
+  <frameset cols="300,*" frameborder="YES" border="2">
+    <frame name="tree" src='<%= response.encodeURL("setUpTree.do") %>' scrolling="auto" title="application navigation tree">
+    <frame name="content" src='<%= response.encodeURL("blank.jsp") %>' scrolling="auto" title="content editing">
+  </frameset>
+</frameset>
+
+<!-- Standard Footer -->
+
+<%@ include file="footer.jsp" %>
+
+</html:html>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/header.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/header.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/header.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,11 @@
+<!--
+  Copyright (c) 1999-2001 The Apache Software Foundation.  All rights
+  reserved.
+-->
+
+<head>
+  <title><bean:message key="application.title"/></title>
+  <html:base/>
+  <link rel="stylesheet" type="text/css" href="tree-control-test.css">
+  <link rel="stylesheet" type="text/css" href="admin.css">
+</head>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/host/alias.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/host/alias.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/host/alias.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,104 @@
+<!-- Standard Struts Entries -->
+<%@ page language="java" import="java.net.URLEncoder" contentType="text/html;charset=utf-8" %>
+<%@ taglib uri="http://struts.apache.org/tags-bean" prefix="bean" %>
+<%@ taglib uri="http://struts.apache.org/tags-html" prefix="html" %>
+<%@ taglib uri="http://struts.apache.org/tags-logic" prefix="logic" %>
+<%@ taglib uri="/WEB-INF/controls.tld" prefix="controls" %>
+
+<html:html locale="true">
+
+<%@ include file="../users/header.jsp" %>
+
+<!-- Body -->
+<body bgcolor="white" background="../images/PaperTexture.gif">
+
+<!--Form -->
+
+<html:errors/>
+
+<html:form method="POST" action="/SaveAlias">
+
+  <html:hidden property="hostName"/>
+
+  <table width="100%" border="0" cellspacing="0" cellpadding="0">
+    <tr class="page-title-row">
+      <td align="left" nowrap>
+        <div class="page-title-text" align="left">
+            <bean:message key="actions.alias.create"/>
+        </div>
+      </td>
+    </tr>
+  </table>
+
+<br>
+
+ <table border="0" cellspacing="0" cellpadding="0" width="100%">
+    <tr> <td> <div class="table-title-text">
+        <bean:message key="new.alias"/>
+    </div> </td> </tr>
+  </table>
+
+  <table class="back-table" border="0" cellspacing="0" cellpadding="1" width="100%">
+    <tr>
+      <td>
+        <controls:table tableStyle="front-table" lineStyle="line-row">
+            <controls:row header="true"
+                labelStyle="table-header-text" dataStyle="table-header-text">
+            <controls:label>
+                <bean:message key="service.property"/>
+            </controls:label>
+            <controls:data>
+                <bean:message key="service.value"/>
+            </controls:data>
+        </controls:row>
+
+        <controls:row labelStyle="table-label-text" dataStyle="table-normal-text" styleId="aliasName">
+            <controls:label>
+                <bean:message key="host.alias.name"/>:
+            </controls:label>
+            <controls:data>
+              <html:text property="aliasName" size="24" maxlength="128" styleId="aliasName"/>
+            </controls:data>
+        </controls:row>
+      </controls:table>
+      </td>
+    </tr>
+  </table>
+
+  <%@ include file="../buttons.jsp" %>
+
+<br>
+
+<%-- Aliases List --%>
+ <table border="0" cellspacing="0" cellpadding="0" width="100%">
+    <tr> <td>
+        <div class="table-title-text">
+            <bean:message key="host.aliases"/>
+        </div>
+    </td> </tr>
+  </table>
+
+  <table class="back-table" border="0" cellspacing="0" cellpadding="1" width="100%">
+    <tr> <td>
+        <table class="front-table" border="1" cellspacing="0" cellpadding="0" width="100%">
+          <tr class="header-row">
+            <td width="27%">
+              <div class="table-header-text" align="left"><bean:message key="host.alias.name"/> </div>
+            </td> </tr>
+
+            <logic:iterate id="aliasVal" name="aliasForm" property="aliasVals">
+            <tr> <td width="27%" valign="top" colspan=2>
+                <div class="table-normal-text"> <%= aliasVal %> </div>
+            </td> </tr>
+            </logic:iterate>
+         </table>
+
+    </td> </tr>
+  </table>
+
+  <%@ include file="../buttons.jsp" %>
+
+</html:form>
+</body>
+
+</html:html>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/host/aliases.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/host/aliases.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/host/aliases.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,83 @@
+<!-- Standard Struts Entries -->
+<%@ page language="java" contentType="text/html;charset=utf-8" %>
+<%@ taglib uri="http://struts.apache.org/tags-bean" prefix="bean" %>
+<%@ taglib uri="http://struts.apache.org/tags-html" prefix="html" %>
+<%@ taglib uri="http://struts.apache.org/tags-logic" prefix="logic" %>
+<%@ taglib uri="/WEB-INF/controls.tld" prefix="controls" %>
+
+<html:html locale="true">
+
+<%@ include file="../users/header.jsp" %>
+
+<!-- Body -->
+<body bgcolor="white" background="../images/PaperTexture.gif">
+
+<!--Form -->
+
+<html:errors/>
+
+<html:form method="POST" action="/DeleteAliases">
+
+  <html:hidden property="hostName"/>
+  <table width="100%" border="0" cellspacing="0" cellpadding="0">
+    <tr bgcolor="7171A5">
+      <td width="81%">
+        <div class="page-title-text" align="left">
+          <bean:message key="actions.alias.delete"/>
+        </div>
+      </td>
+      <td align="right" nowrap>
+        <div class="page-title-text">
+            <controls:actions label="Alias Actions">
+              <controls:action selected="true"> ----<bean:message key="actions.available.actions"/>---- </controls:action>
+              <controls:action> --------------------------------- </controls:action>
+            </controls:actions>
+        </div>
+      </td>
+    </tr>
+  </table>
+
+<%@ include file="../buttons.jsp" %>
+  <br>
+
+  <%-- Aliases List --%>
+
+  <table class="back-table" border="0" cellspacing="0" cellpadding="1" width="100%">
+    <tr>
+      <td>
+        <table class="front-table" border="1"
+         cellspacing="0" cellpadding="0" width="100%">
+          <tr class="header-row">
+            <td><div align="left" class="table-header-text">
+              <bean:message key="actions.delete"/>
+            </div></td>
+            <td><div align="left" class="table-header-text">
+              <bean:message key="host.alias.name"/>
+            </div></td>
+          </tr>
+
+        <logic:iterate name="aliasesList" id="alias">
+          <tr class="line-row">
+            <td><div align="left" class="table-normal-text">&nbsp;
+            <label for="aliases"></label>
+              <html:multibox property="aliases"
+                                value="<%= alias.toString() %>" styleId="aliases"/>
+            </div></td>
+            <td><div align="left" class="table-normal-text">&nbsp;
+                <%= alias.toString() %>
+            </div></td>
+          </tr>
+        </logic:iterate>
+        </table>
+      </td>
+    </tr>
+  </table>
+
+<%@ include file="../buttons.jsp" %>
+
+  <br>
+</html:form>
+
+<p>&nbsp;</p>
+</body>
+</html:html>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/host/host.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/host/host.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/host/host.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,277 @@
+<!-- Standard Struts Entries -->
+<%@ page language="java" import="java.net.URLEncoder" contentType="text/html;charset=utf-8" %>
+<%@ taglib uri="http://struts.apache.org/tags-bean" prefix="bean" %>
+<%@ taglib uri="http://struts.apache.org/tags-html" prefix="html" %>
+<%@ taglib uri="http://struts.apache.org/tags-logic" prefix="logic" %>
+<%@ taglib uri="/WEB-INF/controls.tld" prefix="controls" %>
+
+<html:html locale="true">
+
+<%@ include file="../users/header.jsp" %>
+
+<!-- Body -->
+<body bgcolor="white" background="../images/PaperTexture.gif">
+
+<!--Form -->
+
+<html:errors/>
+
+<html:form method="POST" action="/SaveHost">
+
+  <bean:define id="hostName" name="hostForm" property="hostName"/>
+  <bean:define id="thisObjectName" type="java.lang.String"
+               name="hostForm" property="objectName"/>
+  <html:hidden property="adminAction"/>
+  <html:hidden property="objectName"/>
+  <html:hidden property="serviceName"/>
+
+  <table width="100%" border="0" cellspacing="0" cellpadding="0">
+    <tr class="page-title-row">
+      <td align="left" nowrap>
+        <div class="page-title-text" align="left">
+          <logic:equal name="hostForm" property="adminAction" value="Create">
+            <bean:message key="actions.hosts.create"/>
+          </logic:equal>
+          <logic:equal name="hostForm" property="adminAction" value="Edit">
+            <bean:write name="hostForm" property="nodeLabel"/>
+          </logic:equal>
+        </div>
+      </td>
+      <td align="right" nowrap>
+        <div class="page-title-text">
+        <controls:actions label="Host Actions">
+            <controls:action selected="true"> -----<bean:message key="actions.available.actions"/>----- </controls:action>
+            <controls:action disabled="true"> ------------------------------------- </controls:action>
+            <logic:notEqual name="hostForm" property="adminAction" value="Create">
+            <controls:action url='<%= "/AddAlias.do?hostName=" +
+                                  URLEncoder.encode(thisObjectName,"UTF-8") %>'>
+                <bean:message key="actions.alias.create"/>
+            </controls:action>
+            <controls:action url='<%= "/DeleteAlias.do?hostName=" +
+                                  URLEncoder.encode(thisObjectName,"UTF-8") %>'>
+                <bean:message key="actions.alias.delete"/>
+            </controls:action>
+            <controls:action disabled="true"> ------------------------------------- </controls:action>
+            <controls:action url='<%= "/AddContext.do?parent=" +
+                                  URLEncoder.encode(thisObjectName,"UTF-8") %>'>
+                <bean:message key="actions.contexts.create"/>
+            </controls:action>
+            <controls:action url='<%= "/DeleteContext.do?parent=" +
+                                  URLEncoder.encode(thisObjectName,"UTF-8") %>'>
+                <bean:message key="actions.contexts.deletes"/>
+            </controls:action>
+            <controls:action disabled="true"> ------------------------------------- </controls:action>
+            <!--FIXME add/remove defaultcontext-->
+<%--
+            <!--controls:action url='<%= "/AddDefaultContext.do?parent=" +
+                                  URLEncoder.encode(thisObjectName,"UTF-8") %>'>
+                <bean:message key="actions.defaultcontexts.create"/>
+            </controls:action-->
+            <!--controls:action url='<%= "/DeleteDefaultContext.do?parent=" +
+                                  URLEncoder.encode(thisObjectName,"UTF-8") %>'>
+                <bean:message key="actions.defaultcontexts.deletes"/>
+            </controls:action-->                        
+--%>
+            <logic:notEqual name="hostName" value='<%= (String)request.getAttribute("adminAppHost") %>'>
+            <controls:action disabled="true">
+                -------------------------------------
+            </controls:action>
+            <controls:action url='<%= "/AddRealm.do?parent=" +
+                                  URLEncoder.encode(thisObjectName,"UTF-8") %>'>
+                <bean:message key="actions.realms.create"/>
+            </controls:action>
+            <controls:action url='<%= "/DeleteRealm.do?parent=" +
+                                  URLEncoder.encode(thisObjectName,"UTF-8") %>'>
+                <bean:message key="actions.realms.deletes"/>
+            </controls:action>
+            </logic:notEqual>
+            <controls:action disabled="true">
+                -------------------------------------
+            </controls:action>
+            <controls:action url='<%= "/AddValve.do?parent=" +
+                                  URLEncoder.encode(thisObjectName,"UTF-8") %>'>
+                <bean:message key="actions.valves.create"/>
+            </controls:action>
+            <controls:action url='<%= "/DeleteValve.do?parent=" +
+                                  URLEncoder.encode(thisObjectName,"UTF-8") %>'>
+                <bean:message key="actions.valves.deletes"/>
+            </controls:action>
+            <logic:notEqual name="hostName" value='<%= request.getServerName() %>'>
+            <controls:action disabled="true">
+                -------------------------------------
+            </controls:action>
+            <controls:action url='<%= "/DeleteHost.do?select=" +
+                                        URLEncoder.encode(thisObjectName,"UTF-8") %>'>
+                <bean:message key="actions.hosts.delete"/>
+            </controls:action>
+           </logic:notEqual>
+           </logic:notEqual>
+         </controls:actions>
+       </div>
+      </td>
+    </tr>
+  </table>
+
+  <%@ include file="../buttons.jsp" %>
+  <br>
+
+ <%-- Host Properties --%>
+ <table border="0" cellspacing="0" cellpadding="0" width="100%">
+    <tr> <td> <div class="table-title-text">
+        <bean:message key="host.properties"/>
+    </div> </td> </tr>
+  </table>
+
+  <table class="back-table" border="0" cellspacing="0" cellpadding="1" width="100%">
+    <tr>
+      <td>
+        <controls:table tableStyle="front-table" lineStyle="line-row">
+            <controls:row header="true"
+                labelStyle="table-header-text" dataStyle="table-header-text">
+            <controls:label>
+                <bean:message key="service.property"/>
+            </controls:label>
+            <controls:data>
+                <bean:message key="service.value"/>
+            </controls:data>
+        </controls:row>
+
+        <controls:row labelStyle="table-label-text" dataStyle="table-normal-text" styleId="name">
+            <controls:label>
+                <bean:message key="host.name"/>:
+            </controls:label>
+            <controls:data>
+            <%-- input only allowed on create transaction --%>
+             <logic:equal name="hostForm" property="adminAction" value="Create">
+              <html:text property="hostName" size="50" maxlength="50" styleId="name"/>
+             </logic:equal>
+             <logic:equal name="hostForm" property="adminAction" value="Edit">
+              <bean:write name="hostForm" property="hostName"/>
+              <html:hidden property="hostName"/>
+             </logic:equal>
+            </controls:data>
+        </controls:row>
+
+
+        <controls:row labelStyle="table-label-text" dataStyle="table-normal-text" styleId="base">
+            <controls:label><bean:message key="host.base"/>:</controls:label>
+            <controls:data>
+             <logic:equal name="hostForm" property="adminAction" value="Create">
+              <html:text property="appBase" size="24" styleId="base"/>
+             </logic:equal>
+             <logic:equal name="hostForm" property="adminAction" value="Edit">
+              <bean:write name="hostForm" property="appBase"/>
+              <html:hidden property="appBase"/>
+             </logic:equal>
+            </controls:data>
+        </controls:row>
+        
+       <controls:row labelStyle="table-label-text" dataStyle="table-normal-text" styleId="autodeploy">
+            <controls:label><bean:message key="host.autoDeploy"/>:</controls:label>
+            <controls:data>
+               <html:select property="autoDeploy" styleId="autodeploy">
+                     <bean:define id="booleanVals" name="hostForm" property="booleanVals"/>
+                     <html:options collection="booleanVals" property="value"
+                   labelProperty="label"/>
+                </html:select>
+            </controls:data>
+        </controls:row>
+        
+       <controls:row labelStyle="table-label-text" dataStyle="table-normal-text" styleId="deployOnStartup">
+            <controls:label><bean:message key="host.deployOnStartup"/>:</controls:label>
+            <controls:data>
+               <html:select property="deployOnStartup" styleId="deployOnStartup">
+                     <bean:define id="booleanVals" name="hostForm" property="booleanVals"/>
+                     <html:options collection="booleanVals" property="value"
+                   labelProperty="label"/>
+                </html:select>
+            </controls:data>
+        </controls:row>
+
+       <controls:row labelStyle="table-label-text" dataStyle="table-normal-text" styleId="deployxml">
+            <controls:label><bean:message key="host.deployXML"/>:</controls:label>
+            <controls:data>
+               <html:select property="deployXML" styleId="deployxml">
+                     <bean:define id="booleanVals" name="hostForm" property="booleanVals"/>
+                     <html:options collection="booleanVals" property="value"
+                   labelProperty="label"/>
+                </html:select>
+            </controls:data>
+        </controls:row>
+        
+       <controls:row labelStyle="table-label-text" dataStyle="table-normal-text" styleId="wars">
+            <controls:label><bean:message key="host.wars"/>:</controls:label>
+            <controls:data>
+               <html:select property="unpackWARs" styleId="wars">
+                     <bean:define id="booleanVals" name="hostForm" property="booleanVals"/>
+                     <html:options collection="booleanVals" property="value"
+                   labelProperty="label"/>
+                </html:select>
+            </controls:data>
+        </controls:row>
+
+       <controls:row labelStyle="table-label-text" dataStyle="table-normal-text" styleId="xmlnamespace">
+            <controls:label><bean:message key="host.xmlNamespaceAware"/>:</controls:label>
+            <controls:data>
+               <html:select property="xmlNamespaceAware" styleId="xmlnamespace">
+                     <bean:define id="booleanVals" name="hostForm" property="booleanVals"/>
+                     <html:options collection="booleanVals" property="value"
+                   labelProperty="label"/>
+                </html:select>
+            </controls:data>
+        </controls:row>
+
+       <controls:row labelStyle="table-label-text" dataStyle="table-normal-text" styleId="xmlvalidation">
+            <controls:label><bean:message key="host.xmlValidation"/>:</controls:label>
+            <controls:data>
+               <html:select property="xmlValidation" styleId="xmlvalidation">
+                     <bean:define id="booleanVals" name="hostForm" property="booleanVals"/>
+                     <html:options collection="booleanVals" property="value"
+                   labelProperty="label"/>
+                </html:select>
+            </controls:data>
+        </controls:row>
+      </controls:table>
+
+      </td>
+    </tr>
+  </table>
+
+<br>
+<br>
+
+<%-- Aliases List --%>
+ <logic:notEqual name="hostForm" property="adminAction" value="Create">
+ <table border="0" cellspacing="0" cellpadding="0" width="100%">
+    <tr> <td>
+        <div class="table-title-text">
+            <bean:message key="host.aliases"/>
+        </div>
+    </td> </tr>
+  </table>
+
+  <table class="back-table" border="0" cellspacing="0" cellpadding="1" width="100%">
+    <tr> <td>
+        <table class="front-table" border="1" cellspacing="0" cellpadding="0" width="100%">
+          <tr class="header-row">
+            <td width="27%">
+              <div class="table-header-text" align="left"><bean:message key="host.alias.name"/> </div>
+            </td> </tr>
+
+            <logic:iterate id="aliasVal" name="hostForm" property="aliasVals">
+            <tr> <td width="27%" valign="top" colspan=2>
+                <div class="table-normal-text"> <%= aliasVal %> </div>
+            </td> </tr>
+            </logic:iterate>
+         </table>
+
+    </td> </tr>
+  </table>
+ </logic:notEqual>
+
+  <%@ include file="../buttons.jsp" %>
+
+</html:form>
+</body>
+
+</html:html>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/host/hosts.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/host/hosts.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/host/hosts.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,93 @@
+<!-- Standard Struts Entries -->
+<%@ page language="java" contentType="text/html;charset=utf-8" %>
+<%@ taglib uri="http://struts.apache.org/tags-bean" prefix="bean" %>
+<%@ taglib uri="http://struts.apache.org/tags-html" prefix="html" %>
+<%@ taglib uri="http://struts.apache.org/tags-logic" prefix="logic" %>
+<%@ taglib uri="/WEB-INF/controls.tld" prefix="controls" %>
+
+<html:html locale="true">
+
+<%@ include file="../users/header.jsp" %>
+
+<!-- Body -->
+<body bgcolor="white" background="../images/PaperTexture.gif">
+
+<!--Form -->
+
+<html:errors/>
+
+<html:form method="POST" action="/DeleteHosts">
+  <table width="100%" border="0" cellspacing="0" cellpadding="0">
+    <tr bgcolor="7171A5">
+      <td width="81%">
+        <div class="page-title-text" align="left">
+          <bean:message key="actions.hosts.delete"/>
+        </div>
+      </td>
+      <td align="right" nowrap>
+        <div class="page-title-text">
+            <controls:actions label="Host Actions">
+              <controls:action selected="true"> ----<bean:message key="actions.available.actions"/>---- </controls:action>
+              <controls:action> --------------------------------- </controls:action>
+            </controls:actions>
+        </div>
+      </td>
+    </tr>
+  </table>
+
+<%@ include file="../buttons.jsp" %>
+  <br>
+
+  <%-- Hosts List --%>
+
+  <table class="back-table" border="0" cellspacing="0" cellpadding="1" width="100%">
+    <tr>
+      <td>
+        <table class="front-table" border="1"
+         cellspacing="0" cellpadding="0" width="100%">
+          <tr class="header-row">
+            <td><div align="left" class="table-header-text">
+              <bean:message key="actions.delete"/>
+            </div></td>
+            <td><div align="left" class="table-header-text">
+              <bean:message key="host.name"/>
+            </div></td>
+          </tr>
+
+        <logic:iterate name="hostsList" id="host">
+          <tr class="line-row">
+            <td><div align="left" class="table-normal-text">&nbsp;
+            
+             <logic:match name="host"
+                        value='<%= (String)request.getAttribute("adminAppHost") %>'>
+             <font color='red'>*</font>
+             </logic:match>
+             <logic:notMatch name="host"
+                        value='<%= (String)request.getAttribute("adminAppHost") %>'>
+              <label for="hosts"></label>          
+              <html:multibox property="hosts"
+                                value="<%= host.toString() %>" styleId="hosts"/>
+              </logic:notMatch>
+              
+            </div></td>
+            <td><div align="left" class="table-normal-text">&nbsp;
+              <html:link page='<%= "/EditHost.do?select=" +
+                         java.net.URLEncoder.encode(host.toString(),"UTF-8") %>'>
+                <controls:attribute name="host" attribute="name"/>
+              </html:link>
+            </div></td>
+          </tr>
+        </logic:iterate>
+        </table>
+      </td>
+    </tr>
+  </table>
+
+<%@ include file="../buttons.jsp" %>
+
+  <br>
+</html:form>
+
+<p>&nbsp;</p>
+</body>
+</html:html>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/images/BlueTile.gif
===================================================================
(Binary files differ)


Property changes on: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/images/BlueTile.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/images/Connector.gif
===================================================================
(Binary files differ)


Property changes on: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/images/Connector.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/images/Context.gif
===================================================================
(Binary files differ)


Property changes on: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/images/Context.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/images/Datasource.gif
===================================================================
(Binary files differ)


Property changes on: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/images/Datasource.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/images/DefaultContext.gif
===================================================================
(Binary files differ)


Property changes on: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/images/DefaultContext.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/images/EnvironmentEntries.gif
===================================================================
(Binary files differ)


Property changes on: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/images/EnvironmentEntries.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/images/Groups.gif
===================================================================
(Binary files differ)


Property changes on: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/images/Groups.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/images/Host.gif
===================================================================
(Binary files differ)


Property changes on: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/images/Host.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/images/Logger.gif
===================================================================
(Binary files differ)


Property changes on: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/images/Logger.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/images/Login.jpg
===================================================================
(Binary files differ)


Property changes on: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/images/Login.jpg
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/images/LoginBackgroundTile.gif
===================================================================
(Binary files differ)


Property changes on: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/images/LoginBackgroundTile.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/images/Mailsession.gif
===================================================================
(Binary files differ)


Property changes on: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/images/Mailsession.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/images/PaperTexture.gif
===================================================================
(Binary files differ)


Property changes on: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/images/PaperTexture.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/images/Realm.gif
===================================================================
(Binary files differ)


Property changes on: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/images/Realm.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/images/ResourceLink.gif
===================================================================
(Binary files differ)


Property changes on: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/images/ResourceLink.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/images/Roles.gif
===================================================================
(Binary files differ)


Property changes on: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/images/Roles.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/images/Server.gif
===================================================================
(Binary files differ)


Property changes on: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/images/Server.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/images/Service.gif
===================================================================
(Binary files differ)


Property changes on: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/images/Service.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/images/Thumbs.db
===================================================================
(Binary files differ)


Property changes on: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/images/Thumbs.db
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/images/TomcatBanner.jpg
===================================================================
(Binary files differ)


Property changes on: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/images/TomcatBanner.jpg
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/images/Users.gif
===================================================================
(Binary files differ)


Property changes on: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/images/Users.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/images/Valve.gif
===================================================================
(Binary files differ)


Property changes on: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/images/Valve.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/images/folder_16_pad.gif
===================================================================
(Binary files differ)


Property changes on: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/images/folder_16_pad.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/images/handledownlast.gif
===================================================================
(Binary files differ)


Property changes on: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/images/handledownlast.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/images/handledownmiddle.gif
===================================================================
(Binary files differ)


Property changes on: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/images/handledownmiddle.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/images/handlerightlast.gif
===================================================================
(Binary files differ)


Property changes on: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/images/handlerightlast.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/images/handlerightmiddle.gif
===================================================================
(Binary files differ)


Property changes on: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/images/handlerightmiddle.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/images/linelastnode.gif
===================================================================
(Binary files differ)


Property changes on: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/images/linelastnode.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/images/linemiddlenode.gif
===================================================================
(Binary files differ)


Property changes on: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/images/linemiddlenode.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/images/linevertical.gif
===================================================================
(Binary files differ)


Property changes on: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/images/linevertical.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/index.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/index.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/index.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1 @@
+<% response.sendRedirect(response.encodeRedirectURL("frameset.jsp")); %>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/login.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/login.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/login.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,106 @@
+<!-- Standard Struts Entries -->
+
+<%@ page language="java" contentType="text/html;charset=utf-8" %>
+<%@ taglib uri="http://struts.apache.org/tags-bean" prefix="bean" %>
+<%@ taglib uri="http://struts.apache.org/tags-html" prefix="html" %>
+<%@ taglib uri="http://struts.apache.org/tags-logic" prefix="logic" %>
+
+<% // Force the initialization of "action" servlet
+   getServletContext().getNamedDispatcher("action").include(request,response);
+%> 
+
+<html:html locale="true">
+
+<!-- Make sure window is not in a frame -->
+
+<script language="JavaScript" type="text/javascript">
+
+  <!--
+    if (window.self != window.top) {
+      window.open(".", "_top");
+    }
+  // -->
+
+</script>
+
+<!-- Standard Content -->
+
+<%@ include file="header.jsp" %>
+
+<!-- Body -->
+
+<body background="images/LoginBackgroundTile.gif">
+
+<center>
+
+<!-- Login -->
+
+<form method="POST" action='<%= response.encodeURL("j_security_check") %>'
+ name="loginForm">
+  <table border="0" cellspacing="5" background="images/LoginBackgroundTile.gif">
+
+    <tr>
+    <!-- banner -->
+     <td height="183">
+        <div align="center"><img src="images/Login.jpg" alt="Tomcat Web Server Administration Tool" width="490" height="228"></div>
+      </td>
+    </tr>
+
+    <!-- username password prompts fields layout -->
+    <tr>
+    <td background="images/LoginBackgroundTile.gif">
+     <table width="100%" border="0" cellspacing="2" cellpadding="5">
+     <tr>
+      <th align="right">
+        <font color="#FFFFFF"><label for="username"><bean:message key="prompt.username"/></label></font>
+      </th>
+      <td align="left">
+        <input type="text" name="j_username" size="16" id="username"/>
+      </td>
+    </tr>
+    <p>
+    <tr>
+      <th align="right">
+        <font color="#FFFFFF"><label for="password"><bean:message key="prompt.password"/></label></font>
+      </th>
+      <td align="left">
+        <input type="password" name="j_password" size="16" id="password"/>
+      </td>
+    </tr>
+
+    <tr>
+      <td width="50%" valign="top"> <div align="right"></div> </td>
+      <td width="55%" valign="top">&nbsp;</td>
+     </tr>
+
+    <!-- login reset buttons layout -->
+    <tr>
+       <td width="50%" valign="top">
+            <div align="right">
+               <input type="submit" value='<bean:message key="button.login"/>'>&nbsp;&nbsp;
+            </div>
+       </td>
+       <td width="55%" valign="top">
+          &nbsp;&nbsp;<input type="reset" value='<bean:message key="button.reset"/>'>
+       </td>
+     </tr>
+  </table>
+  <p> &nbsp;
+  </td>
+  </tr>
+ </table>
+</form>
+
+<script language="JavaScript" type="text/javascript">
+  <!--
+    document.forms["loginForm"].elements["j_username"].focus()
+  // -->
+</script>
+
+</body>
+
+<!-- Standard Footer -->
+
+<%@ include file="footer.jsp" %>
+
+</html:html>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/realm/dataSourceRealm.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/realm/dataSourceRealm.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/realm/dataSourceRealm.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,155 @@
+<!-- Standard Struts Entries -->
+<%@ page language="java" import="java.net.URLEncoder" contentType="text/html;charset=utf-8" %>
+<%@ taglib uri="http://struts.apache.org/tags-bean" prefix="bean" %>
+<%@ taglib uri="http://struts.apache.org/tags-html" prefix="html" %>
+<%@ taglib uri="/WEB-INF/controls.tld" prefix="controls" %>
+<%@ taglib uri="http://struts.apache.org/tags-logic" prefix="logic" %>
+
+<html:html locale="true">
+
+<%@ include file="../users/header.jsp" %>
+
+<!-- Body -->
+<body bgcolor="white" background="../images/PaperTexture.gif">
+
+<!--Form -->
+
+<html:errors/>
+
+<html:form method="POST" action="/SaveDataSourceRealm">
+
+  <bean:define id="thisObjectName" type="java.lang.String"
+               name="dataSourceRealmForm" property="objectName"/>
+  <html:hidden property="adminAction"/>
+  <html:hidden property="parentObjectName"/>
+  <html:hidden property="objectName"/>
+  <html:hidden property="allowDeletion"/>
+
+  <table width="100%" border="0" cellspacing="0" cellpadding="0">
+    <tr bgcolor="7171A5">
+      <td width="81%">
+       <div class="page-title-text" align="left">
+         <logic:equal name="dataSourceRealmForm" property="adminAction" value="Create">
+            <bean:message key="actions.realms.create"/>
+          </logic:equal>
+          <logic:equal name="dataSourceRealmForm" property="adminAction" value="Edit">
+            <bean:write name="dataSourceRealmForm" property="nodeLabel"/>
+          </logic:equal>
+       </div>
+      </td>
+      <td align="right" nowrap>
+        <div class="page-title-text">
+      <controls:actions label="Realm Actions">
+            <controls:action selected="true"> ----<bean:message key="actions.available.actions"/>---- </controls:action>
+            <controls:action> --------------------------------- </controls:action>
+            <logic:notEqual name="dataSourceRealmForm" property="adminAction" value="Create">
+            <logic:notEqual name="dataSourceRealmForm" property="allowDeletion" value="false">
+             <controls:action url='<%= "/DeleteRealm.do?select=" +
+                                        URLEncoder.encode(thisObjectName,"UTF-8") %>'>
+                <bean:message key="actions.realms.delete"/>
+              </controls:action>
+               </logic:notEqual>
+             </logic:notEqual>
+       </controls:actions>
+         </div>
+      </td>
+    </tr>
+  </table>
+    <%@ include file="../buttons.jsp" %>
+  <br>
+
+  <table class="back-table" border="0" cellspacing="0" cellpadding="0" width="100%">
+    <tr>
+      <td>
+       <controls:table tableStyle="front-table" lineStyle="line-row">
+            <controls:row header="true"
+                labelStyle="table-header-text" dataStyle="table-header-text">
+            <controls:label><bean:message key="service.property"/></controls:label>
+            <controls:data><bean:message key="service.value"/></controls:data>
+        </controls:row>
+
+      <controls:row labelStyle="table-label-text" dataStyle="table-normal-text" styleId="type">
+            <controls:label><bean:message key="connector.type"/>:</controls:label>
+            <controls:data>
+                 <logic:equal name="dataSourceRealmForm" property="adminAction" value="Create">
+                    <html:select property="realmType" onchange="IA_jumpMenu('self',this)" styleId="type">
+                     <bean:define id="realmTypeVals" name="dataSourceRealmForm" property="realmTypeVals"/>
+                     <html:options collection="realmTypeVals" property="value" labelProperty="label"/>
+                    </html:select>
+                </logic:equal>
+                <logic:equal name="dataSourceRealmForm" property="adminAction" value="Edit">
+                  <bean:write name="dataSourceRealmForm" property="realmType" scope="session"/>
+                </logic:equal>
+            </controls:data>
+        </controls:row>
+
+        <controls:row labelStyle="table-label-text" dataStyle="table-normal-text" styleId="driver">
+            <controls:label><bean:message key="realm.dataSourceName"/>:</controls:label>
+            <controls:data>
+              <html:text property="dataSourceName" size="30" styleId="dataSourceName"/>
+            </controls:data>
+        </controls:row>
+
+        <controls:row labelStyle="table-label-text" dataStyle="table-normal-text" styleId="digest">
+            <controls:label><bean:message key="realm.digest"/>:</controls:label>
+            <controls:data>
+                <html:text property="digest" size="30" styleId="digest"/>
+            </controls:data>
+        </controls:row>
+        
+       <controls:row labelStyle="table-label-text" dataStyle="table-normal-text" styleId="localDataSource">
+            <controls:label><bean:message key="realm.localDataSource"/>:</controls:label>
+            <controls:data>
+               <html:select property="localDataSource" styleId="localDataSource">
+                     <bean:define id="booleanVals" name="dataSourceRealmForm" property="booleanVals"/>
+                     <html:options collection="booleanVals" property="value"
+                   labelProperty="label"/>
+                </html:select>
+            </controls:data>
+        </controls:row>
+
+        <controls:row labelStyle="table-label-text" dataStyle="table-normal-text" styleId="roleNameCol">
+            <controls:label><bean:message key="realm.roleNameCol"/>:</controls:label>
+            <controls:data>
+                <html:text property="roleNameCol" size="30" styleId="roleNameCol"/>
+            </controls:data>
+        </controls:row>
+
+        <controls:row labelStyle="table-label-text" dataStyle="table-normal-text" styleId="userCredCol">
+            <controls:label><bean:message key="realm.userCredCol"/>:</controls:label>
+            <controls:data>
+                <html:text property="userCredCol" size="30" styleId="userCredCol"/>
+            </controls:data>
+        </controls:row>
+
+        <controls:row labelStyle="table-label-text" dataStyle="table-normal-text" styleId="userNameCol">
+            <controls:label><bean:message key="realm.userNameCol"/>:</controls:label>
+            <controls:data>
+                <html:text property="userNameCol" size="30" styleId="userNameCol"/>
+            </controls:data>
+        </controls:row>
+
+        <controls:row labelStyle="table-label-text" dataStyle="table-normal-text" styleId="userRoleTable">
+            <controls:label><bean:message key="realm.userRoleTable"/>:</controls:label>
+            <controls:data>
+                <html:text property="userRoleTable" size="30" styleId="userRoleTable"/>
+            </controls:data>
+        </controls:row>
+
+        <controls:row labelStyle="table-label-text" dataStyle="table-normal-text" styleId="userTable">
+            <controls:label><bean:message key="realm.userTable"/>:</controls:label>
+            <controls:data>
+                <html:text property="userTable" size="30" styleId="userTable"/>
+            </controls:data>
+        </controls:row>
+
+      </controls:table>
+      </td>
+    </tr>
+  </table>
+    <%@ include file="../buttons.jsp" %>
+  <br>
+  </html:form>
+<p>&nbsp;</p>
+</body>
+</html:html>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/realm/jdbcRealm.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/realm/jdbcRealm.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/realm/jdbcRealm.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,165 @@
+<!-- Standard Struts Entries -->
+<%@ page language="java" import="java.net.URLEncoder" contentType="text/html;charset=utf-8" %>
+<%@ taglib uri="http://struts.apache.org/tags-bean" prefix="bean" %>
+<%@ taglib uri="http://struts.apache.org/tags-html" prefix="html" %>
+<%@ taglib uri="/WEB-INF/controls.tld" prefix="controls" %>
+<%@ taglib uri="http://struts.apache.org/tags-logic" prefix="logic" %>
+
+<html:html locale="true">
+
+<%@ include file="../users/header.jsp" %>
+
+<!-- Body -->
+<body bgcolor="white" background="../images/PaperTexture.gif">
+
+<!--Form -->
+
+<html:errors/>
+
+<html:form method="POST" action="/SaveJDBCRealm">
+
+  <bean:define id="thisObjectName" type="java.lang.String"
+               name="jdbcRealmForm" property="objectName"/>
+  <html:hidden property="adminAction"/>
+  <html:hidden property="parentObjectName"/>
+  <html:hidden property="objectName"/>
+  <html:hidden property="allowDeletion"/>
+
+  <table width="100%" border="0" cellspacing="0" cellpadding="0">
+    <tr bgcolor="7171A5">
+      <td width="81%">
+       <div class="page-title-text" align="left">
+         <logic:equal name="jdbcRealmForm" property="adminAction" value="Create">
+            <bean:message key="actions.realms.create"/>
+          </logic:equal>
+          <logic:equal name="jdbcRealmForm" property="adminAction" value="Edit">
+            <bean:write name="jdbcRealmForm" property="nodeLabel"/>
+          </logic:equal>
+       </div>
+      </td>
+      <td align="right" nowrap>
+        <div class="page-title-text">
+      <controls:actions label="Realm Actions">
+            <controls:action selected="true"> ----<bean:message key="actions.available.actions"/>---- </controls:action>
+            <controls:action> --------------------------------- </controls:action>
+            <logic:notEqual name="jdbcRealmForm" property="adminAction" value="Create">
+            <logic:notEqual name="jdbcRealmForm" property="allowDeletion" value="false">
+             <controls:action url='<%= "/DeleteRealm.do?select=" +
+                                        URLEncoder.encode(thisObjectName,"UTF-8") %>'>
+                <bean:message key="actions.realms.delete"/>
+              </controls:action>
+               </logic:notEqual>
+             </logic:notEqual>
+       </controls:actions>
+         </div>
+      </td>
+    </tr>
+  </table>
+    <%@ include file="../buttons.jsp" %>
+  <br>
+
+  <table class="back-table" border="0" cellspacing="0" cellpadding="0" width="100%">
+    <tr>
+      <td>
+       <controls:table tableStyle="front-table" lineStyle="line-row">
+            <controls:row header="true"
+                labelStyle="table-header-text" dataStyle="table-header-text">
+            <controls:label><bean:message key="service.property"/></controls:label>
+            <controls:data><bean:message key="service.value"/></controls:data>
+        </controls:row>
+
+      <controls:row labelStyle="table-label-text" dataStyle="table-normal-text" styleId="type">
+            <controls:label><bean:message key="connector.type"/>:</controls:label>
+            <controls:data>
+                 <logic:equal name="jdbcRealmForm" property="adminAction" value="Create">
+                    <html:select property="realmType" onchange="IA_jumpMenu('self',this)" styleId="type">
+                     <bean:define id="realmTypeVals" name="jdbcRealmForm" property="realmTypeVals"/>
+                     <html:options collection="realmTypeVals" property="value" labelProperty="label"/>
+                    </html:select>
+                </logic:equal>
+                <logic:equal name="jdbcRealmForm" property="adminAction" value="Edit">
+                  <bean:write name="jdbcRealmForm" property="realmType" scope="session"/>
+                </logic:equal>
+            </controls:data>
+        </controls:row>
+
+        <controls:row labelStyle="table-label-text" dataStyle="table-normal-text" styleId="driver">
+            <controls:label><bean:message key="realm.driver"/>:</controls:label>
+            <controls:data>
+              <html:text property="driver" size="30" styleId="driver"/>
+            </controls:data>
+        </controls:row>
+
+        <controls:row labelStyle="table-label-text" dataStyle="table-normal-text" styleId="passwd">
+            <controls:label><bean:message key="realm.passwd"/>:</controls:label>
+            <controls:data>
+                <html:text property="connectionPassword" size="30" styleId="passwd"/>
+            </controls:data>
+        </controls:row>
+
+        <controls:row labelStyle="table-label-text" dataStyle="table-normal-text" styleId="url">
+            <controls:label><bean:message key="realm.url"/>:</controls:label>
+            <controls:data>
+                <html:text property="connectionURL" size="30" styleId="url"/>
+            </controls:data>
+        </controls:row>
+
+        <controls:row labelStyle="table-label-text" dataStyle="table-normal-text" styleId="username">
+            <controls:label><bean:message key="realm.userName"/>:</controls:label>
+            <controls:data>
+                <html:text property="connectionName" size="30" styleId="username"/>
+            </controls:data>
+        </controls:row>
+
+        <controls:row labelStyle="table-label-text" dataStyle="table-normal-text" styleId="digest">
+            <controls:label><bean:message key="realm.digest"/>:</controls:label>
+            <controls:data>
+                <html:text property="digest" size="30" styleId="digest"/>
+            </controls:data>
+        </controls:row>
+
+        <controls:row labelStyle="table-label-text" dataStyle="table-normal-text" styleId="passwordCol">
+            <controls:label><bean:message key="realm.passwordCol"/>:</controls:label>
+            <controls:data>
+                <html:text property="passwordCol" size="30" styleId="passwordCol"/>
+            </controls:data>
+        </controls:row>
+
+        <controls:row labelStyle="table-label-text" dataStyle="table-normal-text" styleId="roleNameCol">
+            <controls:label><bean:message key="realm.roleNameCol"/>:</controls:label>
+            <controls:data>
+                <html:text property="roleNameCol" size="30" styleId="roleNameCol"/>
+            </controls:data>
+        </controls:row>
+
+        <controls:row labelStyle="table-label-text" dataStyle="table-normal-text" styleId="userNameCol">
+            <controls:label><bean:message key="realm.userNameCol"/>:</controls:label>
+            <controls:data>
+                <html:text property="userNameCol" size="30" styleId="userNameCol"/>
+            </controls:data>
+        </controls:row>
+
+        <controls:row labelStyle="table-label-text" dataStyle="table-normal-text" styleId="userRoleTable">
+            <controls:label><bean:message key="realm.userRoleTable"/>:</controls:label>
+            <controls:data>
+                <html:text property="roleTable" size="30" styleId="userRoleTable"/>
+            </controls:data>
+        </controls:row>
+
+        <controls:row labelStyle="table-label-text" dataStyle="table-normal-text" styleId="userTable">
+            <controls:label><bean:message key="realm.userTable"/>:</controls:label>
+            <controls:data>
+                <html:text property="userTable" size="30" styleId="userTable"/>
+            </controls:data>
+        </controls:row>
+
+      </controls:table>
+      </td>
+    </tr>
+  </table>
+    <%@ include file="../buttons.jsp" %>
+  <br>
+  </html:form>
+<p>&nbsp;</p>
+</body>
+</html:html>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/realm/jndiRealm.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/realm/jndiRealm.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/realm/jndiRealm.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,208 @@
+<!-- Standard Struts Entries -->
+<%@ page language="java" import="java.net.URLEncoder" contentType="text/html;charset=utf-8" %>
+<%@ taglib uri="http://struts.apache.org/tags-bean" prefix="bean" %>
+<%@ taglib uri="http://struts.apache.org/tags-html" prefix="html" %>
+<%@ taglib uri="/WEB-INF/controls.tld" prefix="controls" %>
+<%@ taglib uri="http://struts.apache.org/tags-logic" prefix="logic" %>
+
+<html:html locale="true">
+
+<%@ include file="../users/header.jsp" %>
+
+<!-- Body -->
+<body bgcolor="white" background="../images/PaperTexture.gif">
+
+<!--Form -->
+
+<html:errors/>
+
+<html:form method="POST" action="/SaveJNDIRealm">
+  <bean:define id="thisObjectName" type="java.lang.String"
+               name="jndiRealmForm" property="objectName"/>
+  <html:hidden property="adminAction"/>
+  <html:hidden property="objectName"/>
+  <html:hidden property="parentObjectName"/>
+  <html:hidden property="allowDeletion"/>
+
+  <table width="100%" border="0" cellspacing="0" cellpadding="0">
+    <tr bgcolor="7171A5">
+      <td width="81%">
+       <div class="page-title-text" align="left">
+         <logic:equal name="jndiRealmForm" property="adminAction" value="Create">
+            <bean:message key="actions.realms.create"/>
+          </logic:equal>
+          <logic:equal name="jndiRealmForm" property="adminAction" value="Edit">
+            <bean:write name="jndiRealmForm" property="nodeLabel"/>
+          </logic:equal>
+       </div>
+      </td>
+      <td align="right" nowrap>
+        <div class="page-title-text">
+      <controls:actions label="Realm Actions">
+            <controls:action selected="true"> ----<bean:message key="actions.available.actions"/>---- </controls:action>
+            <controls:action> --------------------------------- </controls:action>
+            <logic:notEqual name="jndiRealmForm" property="adminAction" value="Create">
+                <logic:notEqual name="jndiRealmForm" property="allowDeletion" value="false">
+                <controls:action url='<%= "/DeleteRealm.do?select=" +
+                                        URLEncoder.encode(thisObjectName,"UTF-8") %>'>
+                <bean:message key="actions.realms.delete"/>
+            </controls:action>
+           </logic:notEqual>
+        </logic:notEqual>
+       </controls:actions>
+         </div>
+      </td>
+    </tr>
+  </table>
+    <%@ include file="../buttons.jsp" %>
+  <br>
+
+  <table class="back-table" border="0" cellspacing="0" cellpadding="0" width="100%">
+    <tr>
+      <td>
+       <controls:table tableStyle="front-table" lineStyle="line-row">
+            <controls:row header="true"
+                labelStyle="table-header-text" dataStyle="table-header-text">
+            <controls:label><bean:message key="service.property"/></controls:label>
+            <controls:data><bean:message key="service.value"/></controls:data>
+        </controls:row>
+
+      <controls:row labelStyle="table-label-text" dataStyle="table-normal-text" styleId="type">
+            <controls:label><bean:message key="connector.type"/>:</controls:label>
+            <controls:data>
+                 <logic:equal name="jndiRealmForm" property="adminAction" value="Create">
+                    <html:select property="realmType" onchange="IA_jumpMenu('self',this)" styleId="type">
+                     <bean:define id="realmTypeVals" name="jndiRealmForm" property="realmTypeVals"/>
+                     <html:options collection="realmTypeVals" property="value" labelProperty="label"/>
+                    </html:select>
+                </logic:equal>
+                <logic:equal name="jndiRealmForm" property="adminAction" value="Edit">
+                  <bean:write name="jndiRealmForm" property="realmType" scope="session"/>
+                </logic:equal>
+            </controls:data>
+        </controls:row>
+
+        <controls:row labelStyle="table-label-text" dataStyle="table-normal-text" styleId="connName">
+            <controls:label><bean:message key="realm.connName"/>:</controls:label>
+            <controls:data>
+              <html:text property="connectionName" size="30" styleId="connName"/>
+            </controls:data>
+        </controls:row>
+
+        <controls:row labelStyle="table-label-text" dataStyle="table-normal-text" styleId="connPassword">
+            <controls:label><bean:message key="realm.connPassword"/>:</controls:label>
+            <controls:data>
+                <html:text property="connectionPassword" size="30" styleId="connPassword"/>
+            </controls:data>
+        </controls:row>
+
+        <controls:row labelStyle="table-label-text" dataStyle="table-normal-text" styleId="connURL">
+            <controls:label><bean:message key="realm.connURL"/>:</controls:label>
+            <controls:data>
+                <html:text property="connectionURL" size="30" styleId="connURL"/>
+            </controls:data>
+        </controls:row>
+
+        <controls:row labelStyle="table-label-text" dataStyle="table-normal-text" styleId="connFactory">
+            <controls:label><bean:message key="realm.connFactory"/>:</controls:label>
+            <controls:data>
+                <html:text property="contextFactory" size="30" styleId="connFactory"/>
+            </controls:data>
+        </controls:row>
+
+       <controls:row labelStyle="table-label-text" dataStyle="table-normal-text" styleId="digest">
+            <controls:label><bean:message key="realm.digest"/>:</controls:label>
+            <controls:data>
+                <html:text property="digest" size="30" styleId="digest"/>
+            </controls:data>
+        </controls:row>
+
+        <controls:row labelStyle="table-label-text" dataStyle="table-normal-text" styleId="roleBase">
+            <controls:label><bean:message key="realm.roleBase"/>:</controls:label>
+            <controls:data>
+                <html:text property="roleBase" size="30" styleId="roleBase"/>
+            </controls:data>
+        </controls:row>
+
+        <controls:row labelStyle="table-label-text" dataStyle="table-normal-text" styleId="roleName">
+            <controls:label><bean:message key="realm.roleName"/>:</controls:label>
+            <controls:data>
+                <html:text property="roleName" size="30" styleId="roleName"/>
+            </controls:data>
+        </controls:row>
+
+        <controls:row labelStyle="table-label-text" dataStyle="table-normal-text" styleId="pattern">
+            <controls:label><bean:message key="realm.pattern"/>:</controls:label>
+            <controls:data>
+                <html:text property="rolePattern" size="30" styleId="pattern"/>
+            </controls:data>
+        </controls:row>
+
+        <controls:row labelStyle="table-label-text" dataStyle="table-normal-text" styleId="rolesubtree">
+            <controls:label><bean:message key="realm.role.subtree"/>:</controls:label>
+            <controls:data>
+             <html:select property="roleSubtree" styleId="rolesubtree">
+                     <bean:define id="searchVals" name="jndiRealmForm" property="searchVals"/>
+                     <html:options collection="searchVals" property="value"
+                        labelProperty="label"/>
+                </html:select>
+              </controls:data>
+        </controls:row>
+
+        <controls:row labelStyle="table-label-text" dataStyle="table-normal-text" styleId="userBase">
+            <controls:label><bean:message key="realm.userBase"/>:</controls:label>
+            <controls:data>
+                <html:text property="userBase" size="30" styleId="userBase"/>
+            </controls:data>
+        </controls:row>
+
+        <controls:row labelStyle="table-label-text" dataStyle="table-normal-text" styleId="roleName">
+            <controls:label><bean:message key="realm.user.roleName"/>:</controls:label>
+            <controls:data>
+                <html:text property="userRoleName" size="30" styleId="roleName"/>
+            </controls:data>
+        </controls:row>
+
+        <controls:row labelStyle="table-label-text" dataStyle="table-normal-text" styleId="usersubtree">
+            <controls:label><bean:message key="realm.user.subtree"/>:</controls:label>
+            <controls:data>
+             <html:select property="userSubtree" styleId="usersubtree">
+                     <bean:define id="searchVals" name="jndiRealmForm" property="searchVals"/>
+                     <html:options collection="searchVals" property="value"
+                        labelProperty="label"/>
+                </html:select>
+              </controls:data>
+        </controls:row>
+
+        <controls:row labelStyle="table-label-text" dataStyle="table-normal-text" styleId="userPassword">
+            <controls:label><bean:message key="realm.userPassword"/>:</controls:label>
+            <controls:data>
+                <html:text property="userPassword" size="30" styleId="userPassword"/>
+            </controls:data>
+        </controls:row>
+
+        <controls:row labelStyle="table-label-text" dataStyle="table-normal-text" styleId="userPattern">
+            <controls:label><bean:message key="realm.userPattern"/>:</controls:label>
+            <controls:data>
+                <html:text property="userPattern" size="30" styleId="userPattern"/>
+            </controls:data>
+        </controls:row>
+
+       <controls:row labelStyle="table-label-text" dataStyle="table-normal-text" styleId="userSearch">
+           <controls:label><bean:message key="realm.userSearch"/>:</controls:label>
+           <controls:data>
+               <html:text property="userSearch" size="30" styleId="userSearch"/>
+           </controls:data>
+       </controls:row>
+
+      </controls:table>
+      </td>
+    </tr>
+  </table>
+
+    <%@ include file="../buttons.jsp" %>
+  <br>
+  </html:form>
+<p>&nbsp;</p>
+</body>
+</html:html>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/realm/memoryRealm.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/realm/memoryRealm.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/realm/memoryRealm.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,103 @@
+<!-- Standard Struts Entries -->
+<%@ page language="java" import="java.net.URLEncoder" contentType="text/html;charset=utf-8" %>
+<%@ taglib uri="http://struts.apache.org/tags-bean" prefix="bean" %>
+<%@ taglib uri="http://struts.apache.org/tags-html" prefix="html" %>
+<%@ taglib uri="http://struts.apache.org/tags-logic" prefix="logic" %>
+<%@ taglib uri="/WEB-INF/controls.tld" prefix="controls" %>
+
+<html:html locale="true">
+
+<%@ include file="../users/header.jsp" %>
+
+<!-- Body -->
+<body bgcolor="white" background="../images/PaperTexture.gif">
+
+<!--Form -->
+
+<html:errors/>
+
+<html:form method="GET" action="/SaveMemoryRealm">
+
+  <bean:define id="thisObjectName" type="java.lang.String"
+               name="memoryRealmForm" property="objectName"/>
+  <html:hidden property="parentObjectName"/>
+  <html:hidden property="adminAction"/>
+  <html:hidden property="objectName"/>
+  <html:hidden property="allowDeletion"/>
+
+  <table width="100%" border="0" cellspacing="0" cellpadding="0">
+    <tr bgcolor="7171A5">
+      <td width="81%">
+        <div class="page-title-text" align="left">
+         <logic:equal name="memoryRealmForm" property="adminAction" value="Create">
+            <bean:message key="actions.realms.create"/>
+          </logic:equal>
+          <logic:equal name="memoryRealmForm" property="adminAction" value="Edit">
+            <bean:write name="memoryRealmForm" property="nodeLabel"/>
+          </logic:equal>
+        </div>
+      </td>
+      <td align="right" nowrap>
+        <div class="page-title-text">
+      <controls:actions label="Label Actions">
+            <controls:action selected="true"> ----<bean:message key="actions.available.actions"/>---- </controls:action>
+            <controls:action> --------------------------------- </controls:action>
+            <logic:notEqual name="memoryRealmForm" property="adminAction" value="Create">
+                <logic:notEqual name="memoryRealmForm" property="allowDeletion" value="false">
+                <controls:action url='<%= "/DeleteRealm.do?select=" +
+                                        URLEncoder.encode(thisObjectName,"UTF-8") %>'>
+                <bean:message key="actions.realms.delete"/>
+                </controls:action>
+            </logic:notEqual>
+            </logic:notEqual>
+       </controls:actions>
+         </div>
+      </td>
+    </tr>
+  </table>
+    <%@ include file="../buttons.jsp" %>
+  <br>
+
+  <table class="back-table" border="0" cellspacing="0" cellpadding="0" width="100%">
+    <tr>
+      <td>
+       <controls:table tableStyle="front-table" lineStyle="line-row">
+        <controls:row header="true"
+                labelStyle="table-header-text" dataStyle="table-header-text">
+            <controls:label><bean:message key="service.property"/></controls:label>
+            <controls:data><bean:message key="service.value"/></controls:data>
+        </controls:row>
+
+      <controls:row labelStyle="table-label-text" dataStyle="table-normal-text" styleId="type">
+        <controls:label><bean:message key="connector.type"/>:</controls:label>
+            <controls:data>
+                 <logic:equal name="memoryRealmForm" property="adminAction" value="Create">
+                    <html:select property="realmType" onchange="IA_jumpMenu('self',this)" styleId="type">
+                     <bean:define id="realmTypeVals" name="memoryRealmForm" property="realmTypeVals"/>
+                     <html:options collection="realmTypeVals" property="value" labelProperty="label"/>
+                    </html:select>
+                </logic:equal>
+                <logic:equal name="memoryRealmForm" property="adminAction" value="Edit">
+                  <bean:write name="memoryRealmForm" property="realmType" scope="session"/>
+                </logic:equal>
+            </controls:data>
+        </controls:row>
+
+        <controls:row labelStyle="table-label-text" dataStyle="table-normal-text" styleId="pathName">
+            <controls:label><bean:message key="realm.pathName"/>:</controls:label>
+            <controls:data>
+                <html:text property="pathName" size="25" styleId="pathName"/>
+            </controls:data>
+        </controls:row>
+
+      </controls:table>
+      </td>
+    </tr>
+  </table>
+
+    <%@ include file="../buttons.jsp" %>
+  <br>
+  </html:form>
+<p>&nbsp;</p>
+</body>
+</html:html>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/realm/realms.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/realm/realms.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/realm/realms.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,92 @@
+<!-- Standard Struts Entries -->
+<%@ page language="java" contentType="text/html;charset=utf-8" %>
+<%@ taglib uri="http://struts.apache.org/tags-bean" prefix="bean" %>
+<%@ taglib uri="http://struts.apache.org/tags-html" prefix="html" %>
+<%@ taglib uri="http://struts.apache.org/tags-logic" prefix="logic" %>
+<%@ taglib uri="/WEB-INF/controls.tld" prefix="controls" %>
+
+<html:html locale="true">
+
+<%@ include file="../users/header.jsp" %>
+
+<!-- Body -->
+<body bgcolor="white" background="../images/PaperTexture.gif">
+
+<!--Form -->
+
+<html:errors/>
+
+<html:form method="post" action="/DeleteRealms">
+
+  <table width="100%" border="0" cellspacing="0" cellpadding="0">
+    <tr bgcolor="7171A5">
+      <td width="81%">
+        <div class="page-title-text" align="left">
+          <bean:message key="actions.realms.delete"/>
+        </div>
+      </td>
+      <td align="right" nowrap>
+        <div class="page-title-text">
+            <controls:actions label="Realm Actions">
+              <controls:action selected="true">
+                ----<bean:message key="actions.available.actions"/>----
+              </controls:action>
+              <controls:action disabled="true">
+                ---------------------------------
+              </controls:action>
+            </controls:actions>
+        </div>
+      </td>
+    </tr>
+  </table>
+
+<%@ include file="../buttons.jsp" %>
+  <br>
+
+  <%-- Realms List --%>
+
+  <table class="back-table" border="0" cellspacing="0" cellpadding="1"
+         width="100%">
+    <tr><td>
+
+      <table class="front-table" border="1"
+       cellspacing="0" cellpadding="0" width="100%">
+
+        <tr class="header-row">
+          <td><div align="left" class="table-header-text">
+            <bean:message key="actions.delete"/>
+          </div></td>
+          <td><div align="left" class="table-header-text">
+            <bean:message key="host.name"/>
+          </div></td>
+        </tr>
+
+        <logic:iterate name="realmsList" id="realm">
+          <tr class="line-row">
+            <td><div align="left" class="table-normal-text">&nbsp;
+            <label for="realms"></label>
+              <html:multibox property="realms"
+                                value="<%= realm.toString() %>" styleId="realms"/>
+            </div></td>
+            <td><div align="left" class="table-normal-text">&nbsp;
+              <html:link page='<%= "/EditRealm.do?select=" +
+                         java.net.URLEncoder.encode(realm.toString(),"UTF-8") %>'>
+                <controls:attribute name="realm" attribute="className"/>
+              </html:link>
+            </div></td>
+          </tr>
+        </logic:iterate>
+
+      </table>
+
+    </td></tr>
+  </table>
+
+<%@ include file="../buttons.jsp" %>
+
+  <br>
+</html:form>
+
+<p>&nbsp;</p>
+</body>
+</html:html>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/realm/userDatabaseRealm.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/realm/userDatabaseRealm.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/realm/userDatabaseRealm.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,109 @@
+<!-- Standard Struts Entries -->
+<%@ page language="java" import="java.net.URLEncoder" contentType="text/html;charset=utf-8" %>
+<%@ taglib uri="http://struts.apache.org/tags-bean" prefix="bean" %>
+<%@ taglib uri="http://struts.apache.org/tags-html" prefix="html" %>
+<%@ taglib uri="http://struts.apache.org/tags-logic" prefix="logic" %>
+<%@ taglib uri="/WEB-INF/controls.tld" prefix="controls" %>
+
+<html:html locale="true">
+
+<%@ include file="../users/header.jsp" %>
+
+<!-- Body -->
+<body bgcolor="white" background="../images/PaperTexture.gif">
+
+<!--Form -->
+
+<html:errors/>
+
+<html:form method="POST" action="/SaveUserDatabaseRealm">
+
+  <bean:define id="thisObjectName" type="java.lang.String"
+               name="userDatabaseRealmForm" property="objectName"/>
+  <html:hidden property="parentObjectName"/>
+  <html:hidden property="adminAction"/>
+  <html:hidden property="objectName"/>
+  <html:hidden property="allowDeletion"/>
+
+  <table width="100%" border="0" cellspacing="0" cellpadding="0">
+    <tr bgcolor="7171A5">
+      <td width="81%">
+        <div class="page-title-text" align="left">
+         <logic:equal name="userDatabaseRealmForm" property="adminAction" value="Create">
+            <bean:message key="actions.realms.create"/>
+          </logic:equal>
+          <logic:equal name="userDatabaseRealmForm" property="adminAction" value="Edit">
+            <bean:write name="userDatabaseRealmForm" property="nodeLabel"/>
+          </logic:equal>
+        </div>
+      </td>
+      <td align="right" nowrap>
+        <div class="page-title-text">
+      <controls:actions label="Realm Actions">
+            <controls:action selected="true"> ----<bean:message key="actions.available.actions"/>---- </controls:action>
+            <controls:action> --------------------------------- </controls:action>
+            <logic:notEqual name="userDatabaseRealmForm" property="adminAction" value="Create">
+                <logic:notEqual name="userDatabaseRealmForm" property="allowDeletion" value="false">
+                <controls:action url='<%= "/DeleteRealm.do?select=" +
+                                        URLEncoder.encode(thisObjectName,"UTF-8") %>'>
+                <bean:message key="actions.realms.delete"/>
+            </controls:action>
+           </logic:notEqual>
+           </logic:notEqual>
+       </controls:actions>
+         </div>
+      </td>
+    </tr>
+  </table>
+    <%@ include file="../buttons.jsp" %>
+  <br>
+
+  <table class="back-table" border="0" cellspacing="0" cellpadding="0" width="100%">
+    <tr>
+      <td>
+       <controls:table tableStyle="front-table" lineStyle="line-row">
+            <controls:row header="true"
+                labelStyle="table-header-text" dataStyle="table-header-text">
+            <controls:label><bean:message key="service.property"/></controls:label>
+            <controls:data><bean:message key="service.value"/></controls:data>
+        </controls:row>
+
+      <controls:row labelStyle="table-label-text" dataStyle="table-normal-text" styleId="type">
+        <controls:label><bean:message key="connector.type"/>:</controls:label>
+            <controls:data>
+                 <logic:equal name="userDatabaseRealmForm" property="adminAction" value="Create">
+                    <html:select property="realmType" onchange="IA_jumpMenu('self',this)" styleId="type">
+                     <bean:define id="realmTypeVals" name="userDatabaseRealmForm" property="realmTypeVals"/>
+                     <html:options collection="realmTypeVals" property="value" labelProperty="label"/>
+                    </html:select>
+                </logic:equal>
+                <logic:equal name="userDatabaseRealmForm" property="adminAction" value="Edit">
+                  <bean:write name="userDatabaseRealmForm" property="realmType" scope="session"/>
+                </logic:equal>
+            </controls:data>
+        </controls:row>
+
+        <controls:row labelStyle="table-label-text" dataStyle="table-normal-text" styleId="resource">
+            <controls:label><bean:message key="realm.resource"/>:</controls:label>
+            <controls:data>
+                <logic:equal name="userDatabaseRealmForm" property="adminAction" value="Create">
+                    <html:text property="resource" size="25" maxlength="25" styleId="resource"/>
+                </logic:equal>
+                <logic:equal name="userDatabaseRealmForm" property="adminAction" value="Edit">
+                    <html:hidden property="resource"/>
+                    <bean:write name="userDatabaseRealmForm" property="resource" scope="session"/>
+                </logic:equal>
+            </controls:data>
+        </controls:row>
+
+      </controls:table>
+      </td>
+    </tr>
+  </table>
+
+    <%@ include file="../buttons.jsp" %>
+  <br>
+  </html:form>
+<p>&nbsp;</p>
+</body>
+</html:html>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/resources/dataSource.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/resources/dataSource.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/resources/dataSource.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,212 @@
+<!-- Standard Struts Entries -->
+
+<%@ page language="java" import="java.net.URLEncoder" contentType="text/html;charset=utf-8" %>
+<%@ taglib uri="http://struts.apache.org/tags-bean" prefix="bean" %>
+<%@ taglib uri="http://struts.apache.org/tags-html" prefix="html" %>
+<%@ taglib uri="http://struts.apache.org/tags-logic" prefix="logic" %>
+<%@ taglib uri="/WEB-INF/controls.tld" prefix="controls" %>
+
+<html:html locale="true">
+
+<%@ include file="../users/header.jsp" %>
+
+<!-- Body -->
+<body bgcolor="white" background="../images/PaperTexture.gif">
+
+<!--Form -->
+
+<html:errors/>
+
+<html:form method="POST" action="/resources/saveDataSource">
+
+  <html:hidden property="objectName"/>
+
+  <bean:define id="resourcetypeInfo" type="java.lang.String"
+               name="dataSourceForm" property="resourcetype"/>
+  <html:hidden property="resourcetype"/>
+
+  <bean:define id="pathInfo" type="java.lang.String"
+               name="dataSourceForm" property="path"/>
+  <html:hidden property="path"/>
+
+  <bean:define id="hostInfo" type="java.lang.String"
+               name="dataSourceForm" property="host"/>
+  <html:hidden property="host"/>
+
+  <bean:define id="domainInfo" type="java.lang.String"
+               name="dataSourceForm" property="domain"/>
+  <html:hidden property="domain"/>
+
+  <table width="100%" border="0" cellspacing="0" cellpadding="0">
+    <tr class="page-title-row">
+      <td align="left" nowrap>
+        <div class="page-title-text">
+          <bean:write name="dataSourceForm" property="nodeLabel"/>
+        </div>
+      </td>
+      <td align="right" nowrap>
+        <div class="page-title-text">
+          <controls:actions label="Data Source Actions">
+            <controls:action selected="true">
+              ----<bean:message key="actions.available.actions"/>----
+            </controls:action>
+            <controls:action>
+              ---------------------------------
+            </controls:action>
+
+        <controls:action url='<%= "/resources/setUpDataSource.do?resourcetype=" +
+                            URLEncoder.encode(resourcetypeInfo,"UTF-8") + "&path="+
+                            URLEncoder.encode(pathInfo,"UTF-8") + "&host="+
+                            URLEncoder.encode(hostInfo,"UTF-8") + "&domain="+
+                            URLEncoder.encode(domainInfo,"UTF-8") %>'>
+                <bean:message key="resources.actions.datasrc.create"/>
+            </controls:action>
+            <controls:action url='<%= "/resources/listDataSources.do?resourcetype=" +
+                            URLEncoder.encode(resourcetypeInfo,"UTF-8") + "&path="+
+                            URLEncoder.encode(pathInfo,"UTF-8") + "&host="+
+                            URLEncoder.encode(hostInfo,"UTF-8") + "&domain="+
+                            URLEncoder.encode(domainInfo,"UTF-8") + "&forward=" +
+                            URLEncoder.encode("DataSources Delete List","UTF-8") %>'>
+                <bean:message key="resources.actions.datasrc.delete"/>
+            </controls:action>
+         </controls:actions>
+        </div>
+      </td>
+    </tr>
+  </table>
+
+  <%@ include file="../buttons.jsp" %>
+<br>
+
+  <table border="0" cellspacing="0" cellpadding="0" width="100%">
+    <tr><td><div class="table-title-text">
+        <bean:message key="resources.treeBuilder.datasources"/>
+    </div></td></tr>
+  </table>
+
+  <table class="back-table" border="0" cellspacing="0" cellpadding="1" width="100%">
+    <tr>
+      <td>
+
+        <controls:table tableStyle="front-table" lineStyle="line-row">
+          <controls:row header="true"
+                labelStyle="table-header-text" dataStyle="table-header-text">
+            <controls:label><bean:message key="service.property"/></controls:label>
+            <controls:data><bean:message key="service.value"/></controls:data>
+          </controls:row>
+
+          <controls:row labelStyle="table-label-text"
+                         dataStyle="table-normal-text" styleId="jndi">
+            <controls:label>
+              <bean:message key="resources.datasrc.jndi"/>:
+            </controls:label>
+            <controls:data>
+              <logic:present name="dataSourceForm" property="objectName">
+                <bean:write name="dataSourceForm" property="jndiName"/>
+                <html:hidden property="jndiName"/>
+              </logic:present>
+              <logic:notPresent name="dataSourceForm" property="objectName">
+                <html:text property="jndiName" size="35" maxlength="56" styleId="jndi"/>
+              </logic:notPresent>
+            </controls:data>
+          </controls:row>
+
+          <controls:row labelStyle="table-label-text"
+                         dataStyle="table-normal-text" styleId="url">
+            <controls:label>
+              <bean:message key="resources.datasrc.url"/>:
+            </controls:label>
+            <controls:data>
+                <html:textarea property="url" cols="35" rows="2" styleId="url"/>
+            </controls:data>
+          </controls:row>
+
+          <controls:row labelStyle="table-label-text"
+                         dataStyle="table-normal-text" styleId="jdbcclass">
+            <controls:label>
+              <bean:message key="resources.datasrc.jdbcclass"/>:
+            </controls:label>
+            <controls:data>
+              <html:text property="driverClass" size="45" maxlength="256" styleId="jdbcclass"/>
+            </controls:data>
+          </controls:row>
+
+          <controls:row labelStyle="table-label-text"
+                         dataStyle="table-normal-text" styleId="username">
+            <controls:label>
+              <bean:message key="users.prompt.username"/>
+            </controls:label>
+            <controls:data>
+              <html:text property="username" size="15" maxlength="25" styleId="username"/>
+            </controls:data>
+          </controls:row>
+
+          <controls:row labelStyle="table-label-text"
+                         dataStyle="table-normal-text" styleId="password">
+            <controls:label>
+              <bean:message key="users.prompt.password"/>
+            </controls:label>
+            <controls:data>
+              <html:password property="password" size="15" maxlength="25" styleId="password"/>
+            </controls:data>
+          </controls:row>
+
+          <controls:row labelStyle="table-label-text"
+                         dataStyle="table-normal-text" styleId="active">
+            <controls:label>
+              <bean:message key="resources.datasrc.active"/>:
+            </controls:label>
+            <controls:data>
+              <html:text property="active" size="5" maxlength="5" styleId="active"/>
+            </controls:data>
+          </controls:row>
+
+          <controls:row labelStyle="table-label-text"
+                         dataStyle="table-normal-text" styleId="idle">
+            <controls:label>
+              <bean:message key="resources.datasrc.idle"/>:
+            </controls:label>
+            <controls:data>
+              <html:text property="idle" size="5" maxlength="5" styleId="idle"/>
+            </controls:data>
+          </controls:row>
+
+          <controls:row labelStyle="table-label-text"
+                         dataStyle="table-normal-text" styleId="wait">
+            <controls:label>
+              <bean:message key="resources.datasrc.wait"/>:
+            </controls:label>
+            <controls:data>
+              <html:text property="wait" size="5" maxlength="5" styleId="wait"/>
+            </controls:data>
+          </controls:row>
+
+          <controls:row labelStyle="table-label-text"
+                         dataStyle="table-normal-text" styleId="validation">
+            <controls:label>
+              <bean:message key="resources.datasrc.validation"/>:
+            </controls:label>
+            <controls:data>
+              <html:textarea property="query" cols="35" rows="3" styleId="validation"/>
+            </controls:data>
+          </controls:row>
+
+        </controls:table>
+
+      </td>
+
+    </tr>
+
+  </table>
+
+  <%@ include file="../buttons.jsp" %>
+
+</html:form>
+
+<!-- Standard Footer -->
+
+<%@ include file="../users/footer.jsp" %>
+
+</body>
+
+</html:html>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/resources/dataSources.jspf
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/resources/dataSources.jspf	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/resources/dataSources.jspf	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,53 @@
+<%-- DataSources List --%>
+
+<table class="back-table" border="0" cellspacing="0" cellpadding="1"
+       width="100%"><tr><td> 
+
+  <table class="front-table" border="1"
+   cellspacing="0" cellpadding="0" width="100%">
+    <tr class="header-row">
+      <logic:present name="checkboxes">
+        <td width="5%"><div align="left" class="table-header-text">
+          &nbsp;
+        </td>
+      </logic:present>
+      <th scope="col" width="20%"><div align="left" class="table-header-text">
+        <bean:message key="resources.datasrc.jndi"/>
+      </div></th>
+      <th scope="col"><div align="left" class="table-header-text">
+        <bean:message key="resources.datasrc.jdbcclass"/>
+      </div></th>
+    </tr>
+
+    <logic:iterate name="dataSourcesForm" property="dataSources"
+                     id="dataSource" type="java.lang.String">
+      <tr class="line-row">
+        <logic:present name="checkboxes">
+          <td scope="row"><div align="center" class="table-normal-text">
+            <label for="dataSources"></label>
+
+            <!-- dataSource may contain internal double quotes, so single quote value -->
+            <!-- See Bugzilla 36673: http://issues.apache.org/bugzilla/show_bug.cgi?id=36673 -->
+            <input type="checkbox" name="dataSources" styleId="dataSources"
+                  value='<%= dataSource %>' />
+          </td>
+        </logic:present>
+        <td scope="row"><div align="left" class="table-normal-text">
+          <html:link page='<%= "/resources/setUpDataSource.do?objectName=" + 
+                               URLEncoder.encode(dataSource,"UTF-8") + "&resourcetype=" +
+                               URLEncoder.encode(resourcetypeInfo,"UTF-8") + "&path="+
+                               URLEncoder.encode(pathInfo,"UTF-8") + "&host="+
+                               URLEncoder.encode(hostInfo,"UTF-8") + "&domain="+
+                               URLEncoder.encode(domainInfo,"UTF-8")  %>'>
+            <controls:attribute name="dataSource" attribute="name"/>
+          </html:link>
+        </div></td>
+        <td scope="row"><div align="left" class="table-normal-text">&nbsp;
+          <controls:attribute name="dataSource" attribute="driverClassName"/>
+        </div></td>
+      </tr>
+    </logic:iterate>
+
+  </table>
+
+</td></tr></table>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/resources/deleteDataSources.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/resources/deleteDataSources.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/resources/deleteDataSources.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,86 @@
+<!-- Standard Struts Entries -->
+<%@ page language="java" import="java.net.URLEncoder" contentType="text/html;charset=utf-8" %>
+<%@ taglib uri="http://struts.apache.org/tags-bean" prefix="bean" %>
+<%@ taglib uri="http://struts.apache.org/tags-html" prefix="html" %>
+<%@ taglib uri="http://struts.apache.org/tags-logic" prefix="logic" %>
+<%@ taglib uri="/WEB-INF/controls.tld" prefix="controls" %>
+
+<html:html locale="true">
+
+<%@ include file="../users/header.jsp" %>
+
+<!-- Body -->
+<body bgcolor="white" background="../images/PaperTexture.gif">
+
+<!--Form -->
+
+<html:errors/>
+
+<html:form action="/resources/listDataSources">
+
+  <bean:define id="resourcetypeInfo" type="java.lang.String"
+               name="dataSourcesForm" property="resourcetype"/>
+  <html:hidden property="resourcetype"/>
+
+  <bean:define id="pathInfo" type="java.lang.String"
+               name="dataSourcesForm" property="path"/>
+  <html:hidden property="path"/>
+
+  <bean:define id="hostInfo" type="java.lang.String"
+               name="dataSourcesForm" property="host"/>
+  <html:hidden property="host"/>
+
+  <bean:define id="domainInfo" type="java.lang.String"
+               name="dataSourcesForm" property="domain"/>
+  <html:hidden property="domain"/>
+
+  <table width="100%" border="0" cellspacing="0" cellpadding="0">
+    <tr bgcolor="7171A5">
+      <td width="81%">
+        <div class="page-title-text" align="left">
+          <bean:message key="resources.actions.datasrc.delete"/>
+        </div>
+      </td>
+      <td width="19%">
+        <div align="right">
+          <%@ include file="listDataSources.jspf" %>
+        </div>
+      </td>
+    </tr>
+  </table>
+
+</html:form>
+
+<br>
+
+<bean:define id="checkboxes" scope="page" value="true"/>
+
+<html:form action="/resources/deleteDataSources">
+
+  <bean:define id="resourcetypeInfo" type="java.lang.String"
+               name="dataSourcesForm" property="resourcetype"/>
+  <html:hidden property="resourcetype"/>
+
+  <bean:define id="pathInfo" type="java.lang.String"
+               name="dataSourcesForm" property="path"/>
+  <html:hidden property="path"/>
+
+  <bean:define id="hostInfo" type="java.lang.String"
+               name="dataSourcesForm" property="host"/>
+  <html:hidden property="host"/>
+
+  <bean:define id="domainInfo" type="java.lang.String"
+               name="dataSourcesForm" property="domain"/>
+  <html:hidden property="domain"/>
+
+  <%@ include file="../buttons.jsp" %>
+  <br>
+  <%@ include file="dataSources.jspf" %>
+  <%@ include file="../buttons.jsp" %>
+</html:form>
+<br>
+
+<%@ include file="../users/footer.jsp" %>
+
+</body>
+</html:html>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/resources/deleteEnvEntries.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/resources/deleteEnvEntries.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/resources/deleteEnvEntries.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,86 @@
+<!-- Standard Struts Entries -->
+<%@ page language="java" import="java.net.URLEncoder" contentType="text/html;charset=utf-8" %>
+<%@ taglib uri="http://struts.apache.org/tags-bean" prefix="bean" %>
+<%@ taglib uri="http://struts.apache.org/tags-html" prefix="html" %>
+<%@ taglib uri="http://struts.apache.org/tags-logic" prefix="logic" %>
+<%@ taglib uri="/WEB-INF/controls.tld" prefix="controls" %>
+
+<html:html locale="true">
+
+<%@ include file="../users/header.jsp" %>
+
+<!-- Body -->
+<body bgcolor="white" background="../images/PaperTexture.gif">
+
+<!--Form -->
+
+<html:errors/>
+
+<html:form action="/resources/listEnvEntries">
+
+  <bean:define id="resourcetypeInfo" type="java.lang.String"
+               name="envEntriesForm" property="resourcetype"/>
+  <html:hidden property="resourcetype"/>
+
+  <bean:define id="pathInfo" type="java.lang.String"
+               name="envEntriesForm" property="path"/>
+  <html:hidden property="path"/>
+
+  <bean:define id="hostInfo" type="java.lang.String"
+               name="envEntriesForm" property="host"/>
+  <html:hidden property="host"/>
+
+  <bean:define id="domainInfo" type="java.lang.String"
+               name="envEntriesForm" property="domain"/>
+  <html:hidden property="domain"/>
+
+  <table width="100%" border="0" cellspacing="0" cellpadding="0">
+    <tr bgcolor="7171A5">
+      <td width="81%">
+        <div class="page-title-text" align="left">
+          <bean:message key="resources.actions.env.delete"/>
+        </div>
+      </td>
+      <td width="19%">
+        <div align="right">
+          <%@ include file="listEnvEntries.jspf" %>
+        </div>
+      </td>
+    </tr>
+  </table>
+
+</html:form>
+
+<br>
+
+<bean:define id="checkboxes" scope="page" value="true"/>
+
+<html:form action="/resources/deleteEnvEntries">
+
+  <bean:define id="resourcetypeInfo" type="java.lang.String"
+               name="envEntriesForm" property="resourcetype"/>
+  <html:hidden property="resourcetype"/>
+
+  <bean:define id="pathInfo" type="java.lang.String"
+               name="envEntriesForm" property="path"/>
+  <html:hidden property="path"/>
+
+  <bean:define id="hostInfo" type="java.lang.String"
+               name="envEntriesForm" property="host"/>
+  <html:hidden property="host"/>
+
+  <bean:define id="domainInfo" type="java.lang.String"
+               name="envEntriesForm" property="domain"/>
+  <html:hidden property="domain"/>
+
+  <%@ include file="../buttons.jsp" %>
+  <br>
+  <%@ include file="envEntries.jspf" %>
+  <%@ include file="../buttons.jsp" %>
+</html:form>
+<br>
+
+<%@ include file="../users/footer.jsp" %>
+
+</body>
+</html:html>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/resources/deleteMailSessions.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/resources/deleteMailSessions.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/resources/deleteMailSessions.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,86 @@
+<!-- Standard Struts Entries -->
+<%@ page language="java" import="java.net.URLEncoder" contentType="text/html;charset=utf-8" %>
+<%@ taglib uri="http://struts.apache.org/tags-bean" prefix="bean" %>
+<%@ taglib uri="http://struts.apache.org/tags-html" prefix="html" %>
+<%@ taglib uri="http://struts.apache.org/tags-logic" prefix="logic" %>
+<%@ taglib uri="/WEB-INF/controls.tld" prefix="controls" %>
+
+<html:html locale="true">
+
+<%@ include file="../users/header.jsp" %>
+
+<!-- Body -->
+<body bgcolor="white" background="../images/PaperTexture.gif">
+
+<!--Form -->
+
+<html:errors/>
+
+<html:form action="/resources/listMailSessions">
+
+  <bean:define id="resourcetypeInfo" type="java.lang.String"
+               name="mailSessionsForm" property="resourcetype"/>
+  <html:hidden property="resourcetype"/>
+
+  <bean:define id="pathInfo" type="java.lang.String"
+               name="mailSessionsForm" property="path"/>
+  <html:hidden property="path"/>
+
+  <bean:define id="hostInfo" type="java.lang.String"
+               name="mailSessionsForm" property="host"/>
+  <html:hidden property="host"/>
+
+  <bean:define id="domainInfo" type="java.lang.String"
+               name="mailSessionsForm" property="domain"/>
+  <html:hidden property="domain"/>
+
+  <table width="100%" border="0" cellspacing="0" cellpadding="0">
+    <tr bgcolor="7171A5">
+      <td width="81%">
+        <div class="page-title-text" align="left">
+          <bean:message key="resources.actions.mailsession.delete"/>
+        </div>
+      </td>
+      <td width="19%">
+        <div align="right">
+          <%@ include file="listMailSessions.jspf" %>
+        </div>
+      </td>
+    </tr>
+  </table>
+
+</html:form>
+
+<br>
+
+<bean:define id="checkboxes" scope="page" value="true"/>
+
+<html:form action="/resources/deleteMailSessions">
+
+  <bean:define id="resourcetypeInfo" type="java.lang.String"
+               name="mailSessionsForm" property="resourcetype"/>
+  <html:hidden property="resourcetype"/>
+
+  <bean:define id="pathInfo" type="java.lang.String"
+               name="mailSessionsForm" property="path"/>
+  <html:hidden property="path"/>
+
+  <bean:define id="hostInfo" type="java.lang.String"
+               name="mailSessionsForm" property="host"/>
+  <html:hidden property="host"/>
+
+  <bean:define id="domainInfo" type="java.lang.String"
+               name="mailSessionsForm" property="domain"/>
+  <html:hidden property="domain"/>
+
+  <%@ include file="../buttons.jsp" %>
+  <br>
+  <%@ include file="mailSessions.jspf" %>
+  <%@ include file="../buttons.jsp" %>
+</html:form>
+<br>
+
+<%@ include file="../users/footer.jsp" %>
+
+</body>
+</html:html>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/resources/deleteResourceLinks.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/resources/deleteResourceLinks.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/resources/deleteResourceLinks.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,84 @@
+<!-- Standard Struts Entries -->
+<%@ page language="java" import="java.net.URLEncoder" contentType="text/html;charset=utf-8" %>
+<%@ taglib uri="http://struts.apache.org/tags-bean" prefix="bean" %>
+<%@ taglib uri="http://struts.apache.org/tags-html" prefix="html" %>
+<%@ taglib uri="http://struts.apache.org/tags-logic" prefix="logic" %>
+<%@ taglib uri="/WEB-INF/controls.tld" prefix="controls" %>
+
+<html:html locale="true">
+
+<%@ include file="../users/header.jsp" %>
+
+<!-- Body -->
+<body bgcolor="white" background="../images/PaperTexture.gif">
+
+<!--Form -->
+
+<html:errors/>
+
+<html:form action="/resources/listResourceLinks">
+
+  <bean:define id="resourcetypeInfo" type="java.lang.String"
+               name="resourceLinksForm" property="resourcetype"/>
+  <html:hidden property="resourcetype"/>
+
+  <bean:define id="pathInfo" type="java.lang.String"
+               name="resourceLinksForm" property="path"/>
+  <html:hidden property="path"/>
+
+  <bean:define id="hostInfo" type="java.lang.String"
+               name="resourceLinksForm" property="host"/>
+  <html:hidden property="host"/>
+
+  <bean:define id="domainInfo" type="java.lang.String"
+               name="resourceLinksForm" property="domain"/>
+  <html:hidden property="domain"/>
+
+  <table width="100%" border="0" cellspacing="0" cellpadding="0">
+    <tr bgcolor="7171A5">
+      <td width="81%">
+        <div class="page-title-text" align="left">
+          <bean:message key="resources.actions.resourcelk.delete"/>
+        </div>
+      </td>
+      <td width="19%">
+        <div align="right">
+          <%@ include file="listResourceLinks.jspf" %>
+        </div>
+      </td>
+    </tr>
+  </table>
+
+</html:form>
+
+<br>
+<bean:define id="checkboxes" scope="page" value="true"/>
+<html:form action="/resources/deleteResourceLinks">
+
+  <bean:define id="resourcetypeInfo" type="java.lang.String"
+               name="resourceLinksForm" property="resourcetype"/>
+  <html:hidden property="resourcetype"/>
+
+  <bean:define id="pathInfo" type="java.lang.String"
+               name="resourceLinksForm" property="path"/>
+  <html:hidden property="path"/>
+
+  <bean:define id="hostInfo" type="java.lang.String"
+               name="resourceLinksForm" property="host"/>
+  <html:hidden property="host"/>
+
+  <bean:define id="domainInfo" type="java.lang.String"
+               name="resourceLinksForm" property="domain"/>
+  <html:hidden property="domain"/>
+
+  <%@ include file="../buttons.jsp" %>
+  <br>
+  <%@ include file="resourceLinks.jspf" %>
+  <%@ include file="../buttons.jsp" %>
+</html:form>
+<br>
+
+<%@ include file="../users/footer.jsp" %>
+
+</body>
+</html:html>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/resources/deleteUserDatabases.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/resources/deleteUserDatabases.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/resources/deleteUserDatabases.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,62 @@
+<!-- Standard Struts Entries -->
+<%@ page language="java" import="java.net.URLEncoder" contentType="text/html;charset=utf-8" %>
+<%@ taglib uri="http://struts.apache.org/tags-bean" prefix="bean" %>
+<%@ taglib uri="http://struts.apache.org/tags-html" prefix="html" %>
+<%@ taglib uri="http://struts.apache.org/tags-logic" prefix="logic" %>
+<%@ taglib uri="/WEB-INF/controls.tld" prefix="controls" %>
+
+<html:html locale="true">
+
+<%@ include file="../users/header.jsp" %>
+
+<!-- Body -->
+<body bgcolor="white" background="../images/PaperTexture.gif">
+
+<!--Form -->
+
+<html:errors/>
+
+<html:form action="/resources/listUserDatabases">
+
+  <bean:define id="domainInfo" type="java.lang.String"
+               name="userDatabasesForm" property="domain"/>
+  <html:hidden property="domain"/>
+
+  <table width="100%" border="0" cellspacing="0" cellpadding="0">
+    <tr bgcolor="7171A5">
+      <td width="81%">
+        <div class="page-title-text" align="left">
+          <bean:message key="resources.actions.userdb.delete"/>
+        </div>
+      </td>
+      <td width="19%">
+        <div align="right">
+          <%@ include file="listUserDatabases.jspf" %>
+        </div>
+      </td>
+    </tr>
+  </table>
+
+</html:form>
+
+<br>
+
+<bean:define id="checkboxes" scope="page" value="true"/>
+
+<html:form action="/resources/deleteUserDatabases">
+
+  <bean:define id="domainInfo" type="java.lang.String"
+               name="userDatabasesForm" property="domain"/>
+  <html:hidden property="domain"/>
+
+  <%@ include file="../buttons.jsp" %>
+  <br>
+  <%@ include file="userDatabases.jspf" %>
+  <%@ include file="../buttons.jsp" %>
+</html:form>
+<br>
+
+<%@ include file="../users/footer.jsp" %>
+
+</body>
+</html:html>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/resources/envEntries.jspf
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/resources/envEntries.jspf	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/resources/envEntries.jspf	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,56 @@
+<%-- Env Entries List --%>
+
+<table class="back-table" border="0" cellspacing="0" cellpadding="1"
+       width="100%"><tr><td> 
+
+  <table class="front-table" border="1"
+   cellspacing="0" cellpadding="0" width="100%">
+    <tr class="header-row">
+      <logic:present name="checkboxes">
+        <td width="5%"><div align="left" class="table-header-text">
+          &nbsp;
+        </td>
+      </logic:present>
+      <th scope="col" width="20%"><div align="left" class="table-header-text">
+        <bean:message key="resources.env.entry"/>
+      </div></th>
+      <th scope="col"><div align="left" class="table-header-text">
+        <bean:message key="service.value"/>
+      </div></th>
+      <th scop="col"><div align="left" class="table-header-text">
+        <bean:message key="users.list.description"/>
+      </div></th>
+    </tr>
+
+    <logic:iterate name="envEntriesForm" property="envEntries"
+                     id="envEntry" type="java.lang.String">
+      <tr class="line-row">
+        <logic:present name="checkboxes">
+          <td scope="row"><div align="center" class="table-normal-text">
+            <label for="envEntries"></label>
+            <input type="checkbox" name="envEntries"
+                  value="<%= envEntry %>" styleId="envEntries">
+          </td>
+        </logic:present>
+        <td><div align="left" class="table-normal-text">
+          <html:link page='<%= "/resources/setUpEnvEntry.do?objectName=" + 
+                               URLEncoder.encode(envEntry,"UTF-8") + "&resourcetype=" +
+                               URLEncoder.encode(resourcetypeInfo,"UTF-8") + "&path="+
+                               URLEncoder.encode(pathInfo,"UTF-8") + "&host="+
+                               URLEncoder.encode(hostInfo,"UTF-8") + "&domain="+
+                               URLEncoder.encode(domainInfo,"UTF-8") %>'>
+            <controls:attribute name="envEntry" attribute="name"/>
+          </html:link>
+        </div></td>
+        <td><div align="left" class="table-normal-text">&nbsp;
+          <controls:attribute name="envEntry" attribute="value"/>
+        </div></td>
+        <td><div align="left" class="table-normal-text">&nbsp;
+          <controls:attribute name="envEntry" attribute="description"/>
+        </div></td>
+      </tr>
+    </logic:iterate>
+
+  </table>
+
+</td></tr></table>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/resources/envEntry.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/resources/envEntry.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/resources/envEntry.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,176 @@
+<!-- Standard Struts Entries -->
+
+<%@ page language="java" import="java.net.URLEncoder" contentType="text/html;charset=utf-8" %>
+<%@ taglib uri="http://struts.apache.org/tags-bean" prefix="bean" %>
+<%@ taglib uri="http://struts.apache.org/tags-html" prefix="html" %>
+<%@ taglib uri="http://struts.apache.org/tags-logic" prefix="logic" %>
+<%@ taglib uri="/WEB-INF/controls.tld" prefix="controls" %>
+
+<html:html locale="true">
+
+<%@ include file="../users/header.jsp" %>
+
+<!-- Body -->
+<body bgcolor="white" background="../images/PaperTexture.gif">
+
+<!--Form -->
+
+<html:errors/>
+
+<html:form method="POST" action="/resources/saveEnvEntry">
+
+  <html:hidden property="objectName"/>
+
+  <bean:define id="resourcetypeInfo" type="java.lang.String"
+               name="envEntryForm" property="resourcetype"/>
+  <html:hidden property="resourcetype"/>
+
+  <bean:define id="pathInfo" type="java.lang.String"
+               name="envEntryForm" property="path"/>
+  <html:hidden property="path"/>
+
+  <bean:define id="hostInfo" type="java.lang.String"
+               name="envEntryForm" property="host"/>
+  <html:hidden property="host"/>
+
+  <bean:define id="domainInfo" type="java.lang.String"
+               name="envEntryForm" property="domain"/>
+  <html:hidden property="domain"/>
+
+  <table width="100%" border="0" cellspacing="0" cellpadding="0">
+    <tr class="page-title-row">
+      <td align="left" nowrap>
+        <div class="page-title-text">
+          <bean:write name="envEntryForm" property="nodeLabel"/>
+        </div>
+      </td>
+      <td align="right" nowrap>
+        <div class="page-title-text">
+          <controls:actions label="Environment Entry Actions">
+            <controls:action selected="true">
+              ----<bean:message key="actions.available.actions"/>----
+            </controls:action>
+            <controls:action>
+              ---------------------------------
+            </controls:action>
+
+        <controls:action url='<%= "/resources/setUpEnvEntry.do?resourcetype=" +
+                            URLEncoder.encode(resourcetypeInfo,"UTF-8") + "&path="+
+                            URLEncoder.encode(pathInfo,"UTF-8") + "&host="+
+                            URLEncoder.encode(hostInfo,"UTF-8") + "&domain="+
+                            URLEncoder.encode(domainInfo,"UTF-8") %>'>
+                <bean:message key="resources.actions.env.create"/>
+            </controls:action>
+            <controls:action url='<%= "/resources/listEnvEntries.do?resourcetype=" +
+                            URLEncoder.encode(resourcetypeInfo,"UTF-8") + "&path="+
+                            URLEncoder.encode(pathInfo,"UTF-8") + "&host="+
+                            URLEncoder.encode(hostInfo,"UTF-8") + "&domain="+
+                            URLEncoder.encode(domainInfo,"UTF-8") + "&forward=" +
+                            URLEncoder.encode("EnvEntries Delete List","UTF-8") %>'>
+                <bean:message key="resources.actions.env.delete"/>
+            </controls:action>
+         </controls:actions>
+        </div>
+      </td>
+    </tr>
+  </table>
+
+  <%@ include file="../buttons.jsp" %>
+<br>
+
+  <table border="0" cellspacing="0" cellpadding="0" width="100%">
+    <tr><td><div class="table-title-text">
+      <bean:message key="resources.env.props"/>
+    </div></td></tr>
+  </table>
+
+  <table class="back-table" border="0" cellspacing="0" cellpadding="1" width="100%">
+    <tr>
+      <td>
+
+        <controls:table tableStyle="front-table" lineStyle="line-row">
+          <controls:row header="true"
+                labelStyle="table-header-text" dataStyle="table-header-text">
+            <controls:label><bean:message key="service.property"/></controls:label>
+            <controls:data><bean:message key="service.value"/></controls:data>
+          </controls:row>
+
+          <controls:row labelStyle="table-label-text"
+                         dataStyle="table-normal-text" styleId="name">
+            <controls:label>
+              <bean:message key="service.name"/>:
+            </controls:label>
+            <controls:data>
+              <logic:present name="envEntryForm" property="objectName">
+                <bean:write name="envEntryForm" property="name"/>
+                <html:hidden property="name"/>
+              </logic:present>
+              <logic:notPresent name="envEntryForm" property="objectName">
+                <html:text property="name" size="24" styleId="name"/>
+              </logic:notPresent>
+            </controls:data>
+          </controls:row>
+
+          <controls:row labelStyle="table-label-text"
+                         dataStyle="table-normal-text" styleId="type">
+            <controls:label>
+              <bean:message key="connector.type"/>:
+            </controls:label>
+            <controls:data>
+              <html:select property="entryType" styleId="type">
+                     <bean:define id="typeVals" name="envEntryForm" property="typeVals"/>
+                     <html:options collection="typeVals" property="value"
+                                   labelProperty="label"/>
+                </html:select>
+            </controls:data>
+          </controls:row>
+
+          <controls:row labelStyle="table-label-text"
+                         dataStyle="table-normal-text" styleId="value">
+            <controls:label>
+              <bean:message key="service.value"/>:
+            </controls:label>
+            <controls:data>
+              <html:text property="value" size="24" styleId="value"/>
+            </controls:data>
+          </controls:row>
+
+          <controls:row labelStyle="table-label-text"
+                         dataStyle="table-normal-text" styleId="override">
+            <controls:label>
+              <bean:message key="resources.env.override"/>:
+            </controls:label>
+            <controls:data>
+              <html:checkbox property="override" value="override" styleId="override"/>
+            </controls:data>
+          </controls:row>
+
+          <controls:row labelStyle="table-label-text"
+                         dataStyle="table-normal-text" styleId="description">
+            <controls:label>
+              <bean:message key="users.prompt.description"/>
+            </controls:label>
+            <controls:data>
+              <html:text property="description" size="30" styleId="description"/>
+            </controls:data>
+          </controls:row>
+
+        </controls:table>
+
+      </td>
+
+    </tr>
+
+  </table>
+
+  <%@ include file="../buttons.jsp" %>
+
+</html:form>
+
+<!-- Standard Footer -->
+
+<%@ include file="../users/footer.jsp" %>
+
+</body>
+
+</html:html>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/resources/listDataSources.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/resources/listDataSources.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/resources/listDataSources.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,60 @@
+<!-- Standard Struts Entries -->
+<%@ page language="java" import="java.net.URLEncoder" contentType="text/html;charset=utf-8" %>
+<%@ taglib uri="http://struts.apache.org/tags-bean" prefix="bean" %>
+<%@ taglib uri="http://struts.apache.org/tags-html" prefix="html" %>
+<%@ taglib uri="http://struts.apache.org/tags-logic" prefix="logic" %>
+<%@ taglib uri="/WEB-INF/controls.tld" prefix="controls" %>
+
+<html:html locale="true">
+
+<%@ include file="../users/header.jsp" %>
+
+<!-- Body -->
+<body bgcolor="white" background="../images/PaperTexture.gif">
+
+<!--Form -->
+
+<html:errors/>
+
+<html:form action="/resources/listDataSources">
+
+  <bean:define id="resourcetypeInfo" type="java.lang.String"
+               name="dataSourcesForm" property="resourcetype"/>
+  <html:hidden property="resourcetype"/>
+
+  <bean:define id="pathInfo" type="java.lang.String"
+               name="dataSourcesForm" property="path"/>
+  <html:hidden property="path"/>
+
+  <bean:define id="hostInfo" type="java.lang.String"
+               name="dataSourcesForm" property="host"/>
+  <html:hidden property="host"/>
+
+  <bean:define id="domainInfo" type="java.lang.String"
+               name="dataSourcesForm" property="domain"/>
+  <html:hidden property="domain"/>
+
+  <table width="100%" border="0" cellspacing="0" cellpadding="0">
+    <tr bgcolor="7171A5">
+      <td width="81%">
+        <div class="page-title-text" align="left">
+          <bean:message key="resources.actions.datasrc"/>
+        </div>
+      </td>
+      <td width="19%">
+        <div align="right">
+          <%@ include file="listDataSources.jspf" %>
+        </div>
+      </td>
+    </tr>
+  </table>
+
+<br>
+
+<%@ include file="dataSources.jspf" %>
+
+<br>
+</html:form>
+
+</body>
+</html:html>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/resources/listDataSources.jspf
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/resources/listDataSources.jspf	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/resources/listDataSources.jspf	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,32 @@
+<td align="right" nowrap>
+<div class="page-title-text">
+<controls:actions label="Data Source Actions">
+
+  <controls:action selected="true">
+    ----<bean:message key="actions.available.actions"/>----
+  </controls:action>
+
+  <controls:action disabled="true">
+    ---------------------------------
+  </controls:action>
+
+  <controls:action url='<%= "/resources/setUpDataSource.do?resourcetype=" +
+                            URLEncoder.encode(resourcetypeInfo,"UTF-8") + "&path="+
+                            URLEncoder.encode(pathInfo,"UTF-8") + "&host="+
+                            URLEncoder.encode(hostInfo,"UTF-8") + "&domain="+
+                            URLEncoder.encode(domainInfo,"UTF-8")%>'>
+    <bean:message key="resources.actions.datasrc.create"/>
+  </controls:action>
+
+  <controls:action url='<%= "/resources/listDataSources.do?resourcetype=" +
+                            URLEncoder.encode(resourcetypeInfo,"UTF-8") + "&path="+
+                            URLEncoder.encode(pathInfo,"UTF-8") + "&host="+
+                            URLEncoder.encode(hostInfo,"UTF-8") + "&domain="+
+                            URLEncoder.encode(domainInfo,"UTF-8") + "&forward=" + 
+                            URLEncoder.encode("DataSources Delete List","UTF-8") %>'>
+    <bean:message key="resources.actions.datasrc.delete"/>
+  </controls:action>
+
+</controls:actions>
+</div>
+</td>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/resources/listEnvEntries.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/resources/listEnvEntries.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/resources/listEnvEntries.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,60 @@
+<!-- Standard Struts Entries -->
+<%@ page language="java" import="java.net.URLEncoder" contentType="text/html;charset=utf-8" %>
+<%@ taglib uri="http://struts.apache.org/tags-bean" prefix="bean" %>
+<%@ taglib uri="http://struts.apache.org/tags-html" prefix="html" %>
+<%@ taglib uri="http://struts.apache.org/tags-logic" prefix="logic" %>
+<%@ taglib uri="/WEB-INF/controls.tld" prefix="controls" %>
+
+<html:html locale="true">
+
+<%@ include file="../users/header.jsp" %>
+
+<!-- Body -->
+<body bgcolor="white" background="../images/PaperTexture.gif">
+
+<!--Form -->
+
+<html:errors/>
+
+<html:form action="/resources/listEnvEntries">
+
+  <bean:define id="resourcetypeInfo" type="java.lang.String"
+               name="envEntriesForm" property="resourcetype"/>
+  <html:hidden property="resourcetype"/>
+
+  <bean:define id="pathInfo" type="java.lang.String"
+               name="envEntriesForm" property="path"/>
+  <html:hidden property="path"/>
+
+  <bean:define id="hostInfo" type="java.lang.String"
+               name="envEntriesForm" property="host"/>
+  <html:hidden property="host"/>
+
+  <bean:define id="domainInfo" type="java.lang.String"
+               name="envEntriesForm" property="domain"/>
+  <html:hidden property="domain"/>
+
+  <table width="100%" border="0" cellspacing="0" cellpadding="0">
+    <tr bgcolor="7171A5">
+      <td width="81%">
+        <div class="page-title-text" align="left">
+          <bean:message key="resources.env.entries"/>
+        </div>
+      </td>
+      <td width="19%">
+        <div align="right">
+          <%@ include file="listEnvEntries.jspf" %>
+        </div>
+      </td>
+    </tr>
+  </table>
+
+<br>
+
+<%@ include file="envEntries.jspf" %>
+
+<br>
+</html:form>
+
+</body>
+</html:html>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/resources/listEnvEntries.jspf
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/resources/listEnvEntries.jspf	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/resources/listEnvEntries.jspf	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,32 @@
+<td align="right" nowrap>
+<div class="page-title-text">
+<controls:actions label="Environment Entry Actions">
+
+  <controls:action selected="true">
+    ----<bean:message key="actions.available.actions"/>----
+  </controls:action>
+
+  <controls:action disabled="true">
+    ---------------------------------
+  </controls:action>
+
+  <controls:action url='<%= "/resources/setUpEnvEntry.do?resourcetype=" +
+                            URLEncoder.encode(resourcetypeInfo,"UTF-8") + "&path="+
+                            URLEncoder.encode(pathInfo,"UTF-8") + "&host="+
+                            URLEncoder.encode(hostInfo,"UTF-8") + "&domain="+
+                            URLEncoder.encode(domainInfo,"UTF-8") %>'>
+    <bean:message key="resources.actions.env.create"/>
+  </controls:action>
+
+  <controls:action url='<%= "/resources/listEnvEntries.do?resourcetype=" +
+                            URLEncoder.encode(resourcetypeInfo,"UTF-8") + "&path="+
+                            URLEncoder.encode(pathInfo,"UTF-8") + "&host="+
+                            URLEncoder.encode(hostInfo,"UTF-8") + "&domain="+
+                            URLEncoder.encode(domainInfo,"UTF-8") + "&forward="+ 
+                            URLEncoder.encode("EnvEntries Delete List","UTF-8") %>'>
+    <bean:message key="resources.actions.env.delete"/>
+  </controls:action>
+
+</controls:actions>
+</div>
+</td>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/resources/listMailSessions.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/resources/listMailSessions.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/resources/listMailSessions.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,60 @@
+<!-- Standard Struts Entries -->
+<%@ page language="java" import="java.net.URLEncoder" contentType="text/html;charset=utf-8" %>
+<%@ taglib uri="http://struts.apache.org/tags-bean" prefix="bean" %>
+<%@ taglib uri="http://struts.apache.org/tags-html" prefix="html" %>
+<%@ taglib uri="http://struts.apache.org/tags-logic" prefix="logic" %>
+<%@ taglib uri="/WEB-INF/controls.tld" prefix="controls" %>
+
+<html:html locale="true">
+
+<%@ include file="../users/header.jsp" %>
+
+<!-- Body -->
+<body bgcolor="white" background="../images/PaperTexture.gif">
+
+<!--Form -->
+
+<html:errors/>
+
+<html:form action="/resources/listMailSessions">
+
+  <bean:define id="resourcetypeInfo" type="java.lang.String"
+               name="mailSessionsForm" property="resourcetype"/>
+  <html:hidden property="resourcetype"/>
+
+  <bean:define id="pathInfo" type="java.lang.String"
+               name="mailSessionsForm" property="path"/>
+  <html:hidden property="path"/>
+
+  <bean:define id="hostInfo" type="java.lang.String"
+               name="mailSessionsForm" property="host"/>
+  <html:hidden property="host"/>
+
+  <bean:define id="domainInfo" type="java.lang.String"
+               name="mailSessionsForm" property="domain"/>
+  <html:hidden property="domain"/>
+
+  <table width="100%" border="0" cellspacing="0" cellpadding="0">
+    <tr bgcolor="7171A5">
+      <td width="81%">
+        <div class="page-title-text" align="left">
+          <bean:message key="resources.actions.mailsession"/>
+        </div>
+      </td>
+      <td width="19%">
+        <div align="right">
+          <%@ include file="listMailSessions.jspf" %>
+        </div>
+      </td>
+    </tr>
+  </table>
+
+<br>
+
+<%@ include file="mailSessions.jspf" %>
+
+<br>
+</html:form>
+
+</body>
+</html:html>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/resources/listMailSessions.jspf
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/resources/listMailSessions.jspf	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/resources/listMailSessions.jspf	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,32 @@
+<td align="right" nowrap>
+<div class="page-title-text">
+<controls:actions label="Mail Session Actions">
+
+  <controls:action selected="true">
+    ----<bean:message key="actions.available.actions"/>----
+  </controls:action>
+
+  <controls:action disabled="true">
+    ---------------------------------
+  </controls:action>
+
+  <controls:action url='<%= "/resources/setUpMailSession.do?resourcetype=" +
+                            URLEncoder.encode(resourcetypeInfo,"UTF-8") + "&path="+
+                            URLEncoder.encode(pathInfo,"UTF-8") + "&host="+
+                            URLEncoder.encode(hostInfo,"UTF-8") + "&domain="+
+                            URLEncoder.encode(domainInfo,"UTF-8") %>'>
+    <bean:message key="resources.actions.mailsession.create"/>
+  </controls:action>
+
+  <controls:action url='<%= "/resources/listMailSessions.do?resourcetype=" +
+                            URLEncoder.encode(resourcetypeInfo,"UTF-8") + "&path="+
+                            URLEncoder.encode(pathInfo,"UTF-8") + "&host="+
+                            URLEncoder.encode(hostInfo,"UTF-8") + "&domain="+
+                            URLEncoder.encode(domainInfo,"UTF-8") + "&forward=" + 
+                            URLEncoder.encode("MailSessions Delete List","UTF-8") %>'>
+    <bean:message key="resources.actions.mailsession.delete"/>
+  </controls:action>
+
+</controls:actions>
+</div>
+</td>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/resources/listResourceLinks.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/resources/listResourceLinks.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/resources/listResourceLinks.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,60 @@
+<!-- Standard Struts Entries -->
+<%@ page language="java" import="java.net.URLEncoder" contentType="text/html;charset=utf-8" %>
+<%@ taglib uri="http://struts.apache.org/tags-bean" prefix="bean" %>
+<%@ taglib uri="http://struts.apache.org/tags-html" prefix="html" %>
+<%@ taglib uri="http://struts.apache.org/tags-logic" prefix="logic" %>
+<%@ taglib uri="/WEB-INF/controls.tld" prefix="controls" %>
+
+<html:html locale="true">
+
+<%@ include file="../users/header.jsp" %>
+
+<!-- Body -->
+<body bgcolor="white" background="../images/PaperTexture.gif">
+
+<!--Form -->
+
+<html:errors/>
+
+<html:form action="/resources/listResourceLinks">
+
+  <bean:define id="resourcetypeInfo" type="java.lang.String"
+               name="resourceLinksForm" property="resourcetype"/>
+  <html:hidden property="resourcetype"/>
+
+  <bean:define id="pathInfo" type="java.lang.String"
+               name="resourceLinksForm" property="path"/>
+  <html:hidden property="path"/>
+
+  <bean:define id="hostInfo" type="java.lang.String"
+               name="resourceLinksForm" property="host"/>
+  <html:hidden property="host"/>
+
+  <bean:define id="domainInfo" type="java.lang.String"
+               name="resourceLinksForm" property="domain"/>
+  <html:hidden property="domain"/>
+
+  <table width="100%" border="0" cellspacing="0" cellpadding="0">
+    <tr bgcolor="7171A5">
+      <td width="81%">
+        <div class="page-title-text" align="left">
+          <bean:message key="resources.actions.resourcelk"/>
+        </div>
+      </td>
+      <td width="19%">
+        <div align="right">
+          <%@ include file="listResourceLinks.jspf" %>
+        </div>
+      </td>
+    </tr>
+  </table>
+
+<br>
+
+<%@ include file="resourceLinks.jspf" %>
+
+<br>
+</html:form>
+
+</body>
+</html:html>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/resources/listResourceLinks.jspf
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/resources/listResourceLinks.jspf	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/resources/listResourceLinks.jspf	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,32 @@
+<td align="right" nowrap>
+<div class="page-title-text">
+<controls:actions label="Resource Link Actions">
+
+  <controls:action selected="true">
+    ----<bean:message key="actions.available.actions"/>----
+  </controls:action>
+
+  <controls:action disabled="true">
+    ---------------------------------
+  </controls:action>
+
+  <controls:action url='<%= "/resources/setUpResourceLink.do?resourcetype=" +
+                            URLEncoder.encode(resourcetypeInfo,"UTF-8") + "&path="+
+                            URLEncoder.encode(pathInfo,"UTF-8") + "&host="+
+                            URLEncoder.encode(hostInfo,"UTF-8") + "&domain="+
+                            URLEncoder.encode(domainInfo,"UTF-8") %>'>
+    <bean:message key="resources.actions.resourcelk.create"/>
+  </controls:action>
+
+  <controls:action url='<%= "/resources/listResourceLinks.do?resourcetype=" +
+                            URLEncoder.encode(resourcetypeInfo,"UTF-8") + "&path="+
+                            URLEncoder.encode(pathInfo,"UTF-8") + "&host="+
+                            URLEncoder.encode(hostInfo,"UTF-8") + "&domain="+
+                            URLEncoder.encode(domainInfo,"UTF-8") +"&forward=" + 
+                            URLEncoder.encode("ResourceLinks Delete List","UTF-8") %>'>
+    <bean:message key="resources.actions.resourcelk.delete"/>
+  </controls:action>
+
+</controls:actions>
+</div>
+</td>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/resources/listUserDatabases.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/resources/listUserDatabases.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/resources/listUserDatabases.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,49 @@
+<!-- Standard Struts Entries -->
+<%@ page language="java" import="java.net.URLEncoder" contentType="text/html;charset=utf-8" %>
+<%@ taglib uri="http://struts.apache.org/tags-bean" prefix="bean" %>
+<%@ taglib uri="http://struts.apache.org/tags-html" prefix="html" %>
+<%@ taglib uri="http://struts.apache.org/tags-logic" prefix="logic" %>
+<%@ taglib uri="/WEB-INF/controls.tld" prefix="controls" %>
+
+<html:html locale="true">
+
+<%@ include file="../users/header.jsp" %>
+
+<!-- Body -->
+<body bgcolor="white" background="../images/PaperTexture.gif">
+
+<!--Form -->
+
+<html:errors/>
+
+<html:form action="/resources/listUserDatabases">
+
+  <bean:define id="domainInfo" type="java.lang.String"
+               name="userDatabasesForm" property="domain"/>
+  <html:hidden property="domain"/>
+
+  <table width="100%" border="0" cellspacing="0" cellpadding="0">
+    <tr bgcolor="7171A5">
+      <td width="81%">
+        <div class="page-title-text" align="left">
+          <bean:message key="resources.treeBuilder.databases"/>
+        </div>
+      </td>
+      <td width="19%">
+        <div align="right">
+          <%@ include file="listUserDatabases.jspf" %>
+        </div>
+      </td>
+    </tr>
+  </table>
+
+<br>
+
+<%@ include file="userDatabases.jspf" %>
+
+</html:form>
+
+<br>
+
+</body>
+</html:html>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/resources/listUserDatabases.jspf
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/resources/listUserDatabases.jspf	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/resources/listUserDatabases.jspf	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,26 @@
+<td align="right" nowrap>
+<div class="page-title-text">
+<controls:actions label="User Database Actions">
+
+  <controls:action selected="true">
+    ----<bean:message key="actions.available.actions"/>----
+  </controls:action>
+
+  <controls:action disabled="true">
+    ---------------------------------
+  </controls:action>
+
+  <controls:action url='<%= "/resources/setUpUserDatabase.do?domain=" +
+                        URLEncoder.encode(domainInfo,"UTF-8") %>'>
+    <bean:message key="resources.actions.userdb.create"/>
+  </controls:action>
+
+  <controls:action url='<%= "/resources/listUserDatabases.do?domain=" +
+                        URLEncoder.encode(domainInfo,"UTF-8") + "&forward=" +
+                        URLEncoder.encode("UserDatabases Delete List","UTF-8") %>'>
+    <bean:message key="resources.actions.userdb.delete"/>
+  </controls:action>
+
+</controls:actions>
+</div>
+</td>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/resources/mailSession.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/resources/mailSession.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/resources/mailSession.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,142 @@
+<!-- Standard Struts Entries -->
+
+<%@ page language="java" import="java.net.URLEncoder" contentType="text/html;charset=utf-8" %>
+<%@ taglib uri="http://struts.apache.org/tags-bean" prefix="bean" %>
+<%@ taglib uri="http://struts.apache.org/tags-html" prefix="html" %>
+<%@ taglib uri="http://struts.apache.org/tags-logic" prefix="logic" %>
+<%@ taglib uri="/WEB-INF/controls.tld" prefix="controls" %>
+
+<html:html locale="true">
+
+<%@ include file="../users/header.jsp" %>
+
+<!-- Body -->
+<body bgcolor="white" background="../images/PaperTexture.gif">
+
+<!--Form -->
+
+<html:errors/>
+
+<html:form method="POST" action="/resources/saveMailSession">
+
+  <html:hidden property="objectName"/>
+
+  <bean:define id="resourcetypeInfo" type="java.lang.String"
+               name="mailSessionForm" property="resourcetype"/>
+  <html:hidden property="resourcetype"/>
+
+  <bean:define id="pathInfo" type="java.lang.String"
+               name="mailSessionForm" property="path"/>
+  <html:hidden property="path"/>
+
+  <bean:define id="hostInfo" type="java.lang.String"
+               name="mailSessionForm" property="host"/>
+  <html:hidden property="host"/>
+
+  <bean:define id="domainInfo" type="java.lang.String"
+               name="mailSessionForm" property="domain"/>
+  <html:hidden property="domain"/>
+
+  <table width="100%" border="0" cellspacing="0" cellpadding="0">
+    <tr class="page-title-row">
+      <td align="left" nowrap>
+        <div class="page-title-text">
+          <bean:write name="mailSessionForm" property="nodeLabel"/>
+        </div>
+      </td>
+      <td align="right" nowrap>
+        <div class="page-title-text">
+          <controls:actions label="Mail Session Actions">
+            <controls:action selected="true">
+              ----<bean:message key="actions.available.actions"/>----
+            </controls:action>
+            <controls:action>
+              ---------------------------------
+            </controls:action>
+
+        <controls:action url='<%= "/resources/setUpMailSession.do?resourcetype=" +
+                            URLEncoder.encode(resourcetypeInfo,"UTF-8") + "&path="+
+                            URLEncoder.encode(pathInfo,"UTF-8") + "&host="+
+                            URLEncoder.encode(hostInfo,"UTF-8") + "&domain="+
+                            URLEncoder.encode(domainInfo,"UTF-8") %>'>
+                <bean:message key="resources.actions.mailsession.create"/>
+            </controls:action>
+            <controls:action url='<%= "/resources/listMailSessions.do?resourcetype=" +
+                            URLEncoder.encode(resourcetypeInfo,"UTF-8") + "&path="+
+                            URLEncoder.encode(pathInfo,"UTF-8") + "&host="+
+                            URLEncoder.encode(hostInfo,"UTF-8") + "&domain="+
+                            URLEncoder.encode(domainInfo,"UTF-8") + "&forward=" +
+                            URLEncoder.encode("MailSessions Delete List","UTF-8") %>'>
+                <bean:message key="resources.actions.mailsession.delete"/>
+            </controls:action>
+         </controls:actions>
+        </div>
+      </td>
+    </tr>
+  </table>
+
+  <%@ include file="../buttons.jsp" %>
+<br>
+
+  <table border="0" cellspacing="0" cellpadding="0" width="100%">
+    <tr><td><div class="table-title-text">
+        <bean:message key="resources.treeBuilder.mailsessions"/>
+    </div></td></tr>
+  </table>
+
+  <table class="back-table" border="0" cellspacing="0" cellpadding="1" width="100%">
+    <tr>
+      <td>
+
+        <controls:table tableStyle="front-table" lineStyle="line-row">
+          <controls:row header="true"
+                labelStyle="table-header-text" dataStyle="table-header-text">
+            <controls:label><bean:message key="service.property"/></controls:label>
+            <controls:data><bean:message key="service.value"/></controls:data>
+          </controls:row>
+
+          <controls:row labelStyle="table-label-text"
+                         dataStyle="table-normal-text" styleId="name">
+            <controls:label>
+              <bean:message key="resources.mailsession.name"/>:
+            </controls:label>
+            <controls:data>
+              <logic:present name="mailSessionForm" property="objectName">
+                <bean:write name="mailSessionForm" property="name"/>
+                <html:hidden property="name"/>
+              </logic:present>
+              <logic:notPresent name="mailSessionForm" property="objectName">
+                <html:text property="name" size="35" maxlength="56" styleId="name"/>
+              </logic:notPresent>
+            </controls:data>
+          </controls:row>
+
+          <controls:row labelStyle="table-label-text"
+                         dataStyle="table-normal-text" styleId="mailhost">
+            <controls:label>
+              <bean:message key="resources.mailsession.mailhost"/>:
+            </controls:label>
+            <controls:data>
+                <html:textarea property="mailhost" cols="35" rows="2" styleId="mailhost"/>
+            </controls:data>
+          </controls:row>
+
+        </controls:table>
+
+      </td>
+
+    </tr>
+
+  </table>
+
+  <%@ include file="../buttons.jsp" %>
+
+</html:form>
+
+<!-- Standard Footer -->
+
+<%@ include file="../users/footer.jsp" %>
+
+</body>
+
+</html:html>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/resources/mailSessions.jspf
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/resources/mailSessions.jspf	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/resources/mailSessions.jspf	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,52 @@
+<%-- MailSessions List --%>
+
+<table class="back-table" border="0" cellspacing="0" cellpadding="1"
+       width="100%"><tr><td> 
+
+  <table class="front-table" border="1"
+   cellspacing="0" cellpadding="0" width="100%">
+    <tr class="header-row">
+      <logic:present name="checkboxes">
+        <td width="5%"><div align="left" class="table-header-text">
+          &nbsp;
+        </td>
+      </logic:present>
+      <th scope="col" width="20%"><div align="left" class="table-header-text">
+        <bean:message key="resources.mailsession.name"/>
+      </div></th>
+      <th scope="col"><div align="left" class="table-header-text">
+        <bean:message key="resources.mailsession.mailhost"/>
+      </div></th>
+    </tr>
+
+    <logic:iterate name="mailSessionsForm" property="mailSessions"
+                     id="mailSession" type="java.lang.String">
+      <tr class="line-row">
+        <logic:present name="checkboxes">
+          <td scope="row"><div align="center" class="table-normal-text">
+            <label for="mailSessions"></label>
+            <!-- mailSession has double quotes internally, use single quotes for value -->
+            <!-- See Bugzilla 35982: http://issues.apache.org/bugzilla/show_bug.cgi?id=35982 -->
+            <input type="checkbox" name="mailSessions" styleId="mailSession"
+                  value='<%= mailSession %>' />
+          </td>
+        </logic:present>
+        <td scope="row"><div align="left" class="table-normal-text">
+          <html:link page='<%= "/resources/setUpMailSession.do?objectName=" + 
+                               URLEncoder.encode(mailSession,"UTF-8") + "&resourcetype=" +
+                               URLEncoder.encode(resourcetypeInfo,"UTF-8") + "&path="+
+                               URLEncoder.encode(pathInfo,"UTF-8") + "&host="+
+                               URLEncoder.encode(hostInfo,"UTF-8") + "&domain="+
+                               URLEncoder.encode(domainInfo,"UTF-8") %>'>
+            <controls:attribute name="mailSession" attribute="name"/>
+          </html:link>
+        </div></td>
+        <td scope="row"><div align="left" class="table-normal-text">&nbsp;
+          <controls:attribute name="mailSession" attribute="mail.smtp.host"/>
+        </div></td>
+      </tr>
+    </logic:iterate>
+
+  </table>
+
+</td></tr></table>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/resources/resourceLink.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/resources/resourceLink.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/resources/resourceLink.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,153 @@
+<!-- Standard Struts Entries -->
+
+<%@ page language="java" import="java.net.URLEncoder" contentType="text/html;charset=utf-8" %>
+<%@ taglib uri="http://struts.apache.org/tags-bean" prefix="bean" %>
+<%@ taglib uri="http://struts.apache.org/tags-html" prefix="html" %>
+<%@ taglib uri="http://struts.apache.org/tags-logic" prefix="logic" %>
+<%@ taglib uri="/WEB-INF/controls.tld" prefix="controls" %>
+
+<html:html locale="true">
+
+<%@ include file="../users/header.jsp" %>
+
+<!-- Body -->
+<body bgcolor="white" background="../images/PaperTexture.gif">
+
+<!--Form -->
+
+<html:errors/>
+
+<html:form method="POST" action="/resources/saveResourceLink">
+
+  <html:hidden property="objectName"/>
+
+  <bean:define id="resourcetypeInfo" type="java.lang.String"
+               name="resourceLinkForm" property="resourcetype"/>
+  <html:hidden property="resourcetype"/>
+
+  <bean:define id="pathInfo" type="java.lang.String"
+               name="resourceLinkForm" property="path"/>
+  <html:hidden property="path"/>
+
+  <bean:define id="hostInfo" type="java.lang.String"
+               name="resourceLinkForm" property="host"/>
+  <html:hidden property="host"/>
+
+  <bean:define id="domainInfo" type="java.lang.String"
+               name="resourceLinkForm" property="domain"/>
+  <html:hidden property="domain"/>
+
+
+  <table width="100%" border="0" cellspacing="0" cellpadding="0">
+    <tr class="page-title-row">
+      <td align="left" nowrap>
+        <div class="page-title-text">
+          <bean:write name="resourceLinkForm" property="nodeLabel"/>
+        </div>
+      </td>
+      <td align="right" nowrap>
+        <div class="page-title-text">
+          <controls:actions label="Resource Link Actions">
+            <controls:action selected="true">
+              ----<bean:message key="actions.available.actions"/>----
+            </controls:action>
+            <controls:action>
+              ---------------------------------
+            </controls:action>
+
+            <controls:action url='<%= "/resources/setUpResourceLink.do?resourcetype=" +
+                            URLEncoder.encode(resourcetypeInfo,"UTF-8") + "&path="+
+                            URLEncoder.encode(pathInfo,"UTF-8") + "&host="+
+                            URLEncoder.encode(hostInfo,"UTF-8") + "&domain="+
+                            URLEncoder.encode(domainInfo,"UTF-8") %>'>
+                <bean:message key="resources.actions.resourcelk.create"/>
+            </controls:action>
+            <controls:action url='<%= "/resources/listResourceLinks.do?resourcetype=" +
+                            URLEncoder.encode(resourcetypeInfo,"UTF-8") + "&path="+
+                            URLEncoder.encode(pathInfo,"UTF-8") + "&host="+
+                            URLEncoder.encode(hostInfo,"UTF-8") + "&domain="+
+                            URLEncoder.encode(domainInfo,"UTF-8") + "&forward=" +
+                            URLEncoder.encode("ResourceLinks Delete List","UTF-8") %>'>
+                <bean:message key="resources.actions.resourcelk.delete"/>
+            </controls:action>
+         </controls:actions>
+        </div>
+      </td>
+    </tr>
+  </table>
+
+  <%@ include file="../buttons.jsp" %>
+<br>
+
+  <table border="0" cellspacing="0" cellpadding="0" width="100%">
+    <tr><td><div class="table-title-text">
+        <bean:message key="resources.treeBuilder.resourcelinks"/>
+    </div></td></tr>
+  </table>
+
+  <table class="back-table" border="0" cellspacing="0" cellpadding="1" width="100%">
+    <tr>
+      <td>
+
+        <controls:table tableStyle="front-table" lineStyle="line-row">
+          <controls:row header="true"
+                labelStyle="table-header-text" dataStyle="table-header-text">
+            <controls:label><bean:message key="service.property"/></controls:label>
+            <controls:data><bean:message key="service.value"/></controls:data>
+          </controls:row>
+
+          <controls:row labelStyle="table-label-text"
+                         dataStyle="table-normal-text" styleId="name">
+            <controls:label>
+              <bean:message key="resources.resourcelk.name"/>:
+            </controls:label>
+            <controls:data>
+              <logic:present name="resourceLinkForm" property="objectName">
+                <bean:write name="resourceLinkForm" property="name"/>
+                <html:hidden property="name"/>
+              </logic:present>
+              <logic:notPresent name="resourceLinkForm" property="objectName">
+                <html:text property="name" size="35" maxlength="56" styleId="name"/>
+              </logic:notPresent>
+            </controls:data>
+          </controls:row>
+
+          <controls:row labelStyle="table-label-text"
+                         dataStyle="table-normal-text" styleId="global">
+            <controls:label>
+              <bean:message key="resources.resourcelk.global"/>:
+            </controls:label>
+            <controls:data>
+                <html:text property="global" size="35" maxlength="56" styleId="global"/>
+            </controls:data>
+          </controls:row>
+
+          <controls:row labelStyle="table-label-text"
+                         dataStyle="table-normal-text" styleId="type">
+            <controls:label>
+              <bean:message key="resources.resourcelk.type"/>:
+            </controls:label>
+            <controls:data>
+              <html:text property="type" size="45" maxlength="256" styleId="type"/>
+            </controls:data>
+          </controls:row>
+
+    </controls:table>
+
+      </td>
+
+    </tr>
+
+  </table>
+
+  <%@ include file="../buttons.jsp" %>
+
+</html:form>
+
+<!-- Standard Footer -->
+
+<%@ include file="../users/footer.jsp" %>
+
+</body>
+
+</html:html>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/resources/resourceLinks.jspf
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/resources/resourceLinks.jspf	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/resources/resourceLinks.jspf	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,48 @@
+<%-- ResourceLinks List --%>
+
+<table class="back-table" border="0" cellspacing="0" cellpadding="1"
+       width="100%"><tr><td> 
+
+  <table class="front-table" border="1"
+   cellspacing="0" cellpadding="0" width="100%">
+    <tr class="header-row">
+      <logic:present name="checkboxes">
+        <td width="5%"><div align="left" class="table-header-text">
+          &nbsp;
+        </td>
+      </logic:present>
+      <th scope="col" width="20%"><div align="left" class="table-header-text">
+        <bean:message key="resources.resourcelk.name"/>
+      </div></th>
+      <th scope="col"><div align="left" class="table-header-text">
+        <bean:message key="resources.resourcelk.global"/>
+      </div></th>
+    </tr>
+    <logic:iterate name="resourceLinksForm" property="resourceLinks"
+                     id="resourceLink" type="java.lang.String">
+      <tr class="line-row">
+        <logic:present name="checkboxes">
+          <td scope="row"><div align="center" class="table-normal-text">
+            <label for="resourceLinks"></label>
+            <input type="checkbox" name="resourceLinks"
+                  value="<%= resourceLink %>" styleId="resourceLinks">
+          </td>
+        </logic:present>
+        <td scope="row"><div align="left" class="table-normal-text">
+          <html:link page='<%= "/resources/setUpResourceLink.do?objectName=" + 
+                               URLEncoder.encode(resourceLink,"UTF-8") + "&resourcetype=" +
+                               URLEncoder.encode(resourcetypeInfo,"UTF-8") + "&path="+
+                               URLEncoder.encode(pathInfo,"UTF-8") + "&host="+
+                               URLEncoder.encode(hostInfo,"UTF-8") + "&domain="+
+                               URLEncoder.encode(domainInfo,"UTF-8") %>'>
+            <controls:attribute name="resourceLink" attribute="name"/>
+          </html:link>
+        </div></td>
+        <td scope="row"><div align="left" class="table-normal-text">&nbsp;
+          <controls:attribute name="resourceLink" attribute="global"/>
+        </div></td>
+      </tr>
+    </logic:iterate>
+  </table>
+
+</td></tr></table>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/resources/userDatabase.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/resources/userDatabase.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/resources/userDatabase.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,145 @@
+<!-- Standard Struts Entries -->
+
+<%@ page language="java" import="java.net.URLEncoder" contentType="text/html;charset=utf-8" %>
+<%@ taglib uri="http://struts.apache.org/tags-bean" prefix="bean" %>
+<%@ taglib uri="http://struts.apache.org/tags-html" prefix="html" %>
+<%@ taglib uri="http://struts.apache.org/tags-logic" prefix="logic" %>
+<%@ taglib uri="/WEB-INF/controls.tld" prefix="controls" %>
+
+<html:html locale="true">
+
+<%@ include file="../users/header.jsp" %>
+
+<!-- Body -->
+<body bgcolor="white" background="../images/PaperTexture.gif">
+
+<!--Form -->
+
+<html:errors/>
+
+<html:form method="POST" action="/resources/saveUserDatabase">
+
+  <bean:define id="domainInfo" type="java.lang.String"
+               name="userDatabaseForm" property="domain"/>
+  <html:hidden property="domain"/>
+  <html:hidden property="objectName"/>
+  <html:hidden property="type"/>
+  <html:hidden property="factory"/>
+
+  <table width="100%" border="0" cellspacing="0" cellpadding="0">
+    <tr class="page-title-row">
+      <td align="left" nowrap>
+        <div class="page-title-text">
+          <bean:write name="userDatabaseForm" property="nodeLabel"/>
+        </div>
+      </td>
+      <td align="right" nowrap>
+        <div class="page-title-text">
+          <controls:actions label="User Database Actions">
+            <controls:action selected="true">
+              ----<bean:message key="actions.available.actions"/>----
+            </controls:action>
+            <controls:action>
+              ---------------------------------
+            </controls:action>
+            
+            <controls:action url='<%= "/resources/setUpUserDatabase.do?domain=" +
+                                    URLEncoder.encode(domainInfo,"UTF-8") %>'>
+                <bean:message key="resources.actions.userdb.create"/>
+            </controls:action>
+            <controls:action url='<%= "/resources/listUserDatabases.do?domain=" +
+                                    URLEncoder.encode(domainInfo,"UTF-8") + "&forward=" +
+                                    URLEncoder.encode("UserDatabases Delete List","UTF-8") %>'>
+                <bean:message key="resources.actions.userdb.delete"/>
+            </controls:action>
+         </controls:actions>
+        </div>
+      </td>
+    </tr>
+  </table>
+
+  <%@ include file="../buttons.jsp" %>
+<br>
+
+  <table border="0" cellspacing="0" cellpadding="0" width="100%">
+    <tr><td><div class="table-title-text">
+        <bean:message key="resources.treeBuilder.databases"/>
+    </div></td></tr>
+  </table>
+
+  <table class="back-table" border="0" cellspacing="0" cellpadding="1" width="100%">
+    <tr>
+      <td>
+
+        <controls:table tableStyle="front-table" lineStyle="line-row">
+          <controls:row header="true"
+                labelStyle="table-header-text" dataStyle="table-header-text">
+            <controls:label><bean:message key="service.property"/></controls:label>
+            <controls:data><bean:message key="service.value"/></controls:data>
+          </controls:row>
+
+          <controls:row labelStyle="table-label-text"
+                         dataStyle="table-normal-text" styleId="name">
+            <controls:label>
+              <bean:message key="service.name"/>:
+            </controls:label>
+            <controls:data>
+              <logic:present name="userDatabaseForm" property="objectName">
+                <bean:write name="userDatabaseForm" property="name"/>
+                <html:hidden property="name"/>
+              </logic:present>
+              <logic:notPresent name="userDatabaseForm" property="objectName">
+                <html:text property="name" size="24" maxlength="32" styleId="name"/>
+              </logic:notPresent>
+            </controls:data>
+          </controls:row>
+
+          <controls:row labelStyle="table-label-text"
+                         dataStyle="table-normal-text" styleId="location">
+            <controls:label>
+              <bean:message key="resources.userdb.location"/>:
+            </controls:label>
+            <controls:data>
+              <html:text property="path" size="32" maxlength="64" styleId="location"/>
+            </controls:data>
+          </controls:row>
+
+          <controls:row labelStyle="table-label-text"
+                         dataStyle="table-normal-text" styleId="factory">
+            <controls:label>
+              <bean:message key="resources.userdb.factory"/>:
+            </controls:label>
+            <controls:data>
+              <bean:write name="userDatabaseForm" property="factory"/>
+            </controls:data>
+          </controls:row>
+
+          <controls:row labelStyle="table-label-text"
+                         dataStyle="table-normal-text" styleId="description">
+            <controls:label>
+              <bean:message key="users.prompt.description"/>
+            </controls:label>
+            <controls:data>
+              <html:textarea property="description" cols="32" rows="3" styleId="description"/>
+            </controls:data>
+          </controls:row>
+
+        </controls:table>
+
+      </td>
+
+    </tr>
+
+  </table>
+
+  <%@ include file="../buttons.jsp" %>
+
+</html:form>
+
+<!-- Standard Footer -->
+
+<%@ include file="../users/footer.jsp" %>
+
+</body>
+
+</html:html>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/resources/userDatabases.jspf
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/resources/userDatabases.jspf	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/resources/userDatabases.jspf	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,65 @@
+<%-- Env Entries List --%>
+
+<table class="back-table" border="0" cellspacing="0" cellpadding="1"
+       width="100%"><tr><td> 
+
+  <table class="front-table" border="1"
+   cellspacing="0" cellpadding="0" width="100%">
+    <tr class="header-row">
+      <logic:present name="checkboxes">
+        <td width="5%"><div align="left" class="table-header-text">
+          &nbsp;
+        </td>
+      </logic:present>
+      <th scope="col" width="20%"><div align="left" class="table-header-text">
+        <bean:message key="service.name"/>
+      </div></th>
+      <%--
+      <th scope="col"><div align="left" class="table-header-text">
+        <bean:message key="resources.userdb.location"/>
+      </div></th>
+      --%>
+      <th scope="col"><div align="left" class="table-header-text">
+        <bean:message key="users.list.description"/>
+      </div></th>
+    </tr>
+    <logic:iterate name="userDatabasesForm" property="userDatabases"
+                     id="userDatabase" type="java.lang.String">
+      <tr class="line-row">
+        <logic:present name="checkboxes">
+          <td scope="row"><div align="center" class="table-normal-text">
+             <logic:match name="userDatabase"
+                        value="name=UserDatabase">
+             <font color='red'>*</font>
+             </logic:match>
+             <logic:notMatch name="userDatabase"
+                        value="name=UserDatabase">
+              <label for="userDatabases"></label>       
+              <html:multibox property="userDatabases"
+                                value="userDatabase" styleId="userDatabases"/>
+              </logic:notMatch>        
+        
+            <!--input type="checkbox" name="userDatabases"
+                  value="<%= userDatabase %>" styleId="userDatabases"-->
+          </td>
+        </logic:present>
+        <td scope="row"><div align="left" class="table-normal-text">
+          <html:link page='<%= "/resources/setUpUserDatabase.do?objectName=" + 
+                               URLEncoder.encode(userDatabase,"UTF-8") + "&domain=" + 
+                               URLEncoder.encode(domainInfo,"UTF-8") %>'>
+            <controls:attribute name="userDatabase" attribute="name"/>
+          </html:link>
+        </div></td>
+        <%-- FIX ME -- commentred out for now as the page was looking too crowded.
+        <td scope="row"><div align="left" class="table-normal-text">
+          <controls:attribute name="userDatabase" attribute="pathname"/>
+        </div></td>
+        --%>
+        <td scope="row"><div align="left" class="table-normal-text">
+          <controls:attribute name="userDatabase" attribute="description"/>
+        </div></td>
+      </tr>
+    </logic:iterate>
+  </table>
+
+</td></tr></table>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/saved.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/saved.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/saved.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,36 @@
+<!-- Standard Struts Entries -->
+
+<%@ page language="java" contentType="text/html;charset=utf-8" %>
+<%@ taglib uri="http://struts.apache.org/tags-bean" prefix="bean" %>
+<%@ taglib uri="http://struts.apache.org/tags-html" prefix="html" %>
+<%@ taglib uri="http://struts.apache.org/tags-logic" prefix="logic" %>
+
+<html:html locale="true">
+
+  <body bgcolor="white" background="images/PaperTexture.gif">
+
+    <%-- Cause our tree control to refresh itself --%>
+    <script language="JavaScript">
+      <!--
+        parent.tree.location='treeControlTest.do';
+      -->
+    </script>
+
+    <%@ include file="header.jsp" %>
+
+    <%-- display warnings if any --%>
+    <logic:present name="warning">
+            <bean:message key="warning.header"/>
+            <bean:message key='<%= (String) request.getAttribute("warning") %>'/>
+            <br>
+    </logic:present>
+
+    <center><h2>
+      <bean:message key="save.success"/>
+    </h2></center>
+
+    <%@ include file="footer.jsp" %>
+
+  </body>
+
+</html:html>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/savefail.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/savefail.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/savefail.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,38 @@
+<!-- Standard Struts Entries -->
+
+<%@ page language="java" contentType="text/html;charset=utf-8" %>
+<%@ taglib uri="http://struts.apache.org/tags-bean" prefix="bean" %>
+<%@ taglib uri="http://struts.apache.org/tags-html" prefix="html" %>
+<%@ taglib uri="http://struts.apache.org/tags-logic" prefix="logic" %>
+
+<html:html locale="true">
+
+  <body bgcolor="white" background="images/PaperTexture.gif">
+
+    <%-- Cause our tree control to refresh itself --%>
+    <script language="JavaScript">
+      <!--
+        parent.tree.location='treeControlTest.do';
+      -->
+    </script>
+
+    <%@ include file="header.jsp" %>
+    <center><h2>
+    <%-- display warnings if any --%>
+    <logic:present name="warning">
+            <bean:message key="warning.header"/>
+    </h2></center>
+    <h3><center>
+            <bean:message key='<%= (String) request.getAttribute("warning") %>'/>
+            <br>
+    </logic:present>
+    </h3></center>
+    <center><h2>
+      <bean:message key="save.fail"/>
+    </h2></center>
+
+    <%@ include file="footer.jsp" %>
+
+  </body>
+
+</html:html>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/server/server.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/server/server.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/server/server.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,107 @@
+<!-- Standard Struts Entries -->
+
+<%@ page language="java" import="java.net.URLEncoder" contentType="text/html;charset=utf-8" %>
+<%@ taglib uri="http://struts.apache.org/tags-bean" prefix="bean" %>
+<%@ taglib uri="http://struts.apache.org/tags-html" prefix="html" %>
+<%@ taglib uri="http://struts.apache.org/tags-logic" prefix="logic" %>
+<%@ taglib uri="/WEB-INF/controls.tld" prefix="controls" %>
+
+<html:html locale="true">
+
+<%@ include file="../users/header.jsp" %>
+
+<!-- Body -->
+<body bgcolor="white" background="../images/PaperTexture.gif">
+
+<!--Form -->
+
+<html:errors/>
+
+<html:form method="POST" action="/SaveServer" focus="portNumberText">
+  <bean:define id="thisObjectName" type="java.lang.String"
+               name="serverForm" property="objectName"/>
+  <html:hidden property="objectName"/>
+
+  <table width="100%" border="0" cellspacing="0" cellpadding="0">
+    <tr class="page-title-row">
+      <td align="left" nowrap>
+        <div class="page-title-text">
+           <bean:write name="serverForm" property="nodeLabel"/>
+        </div>
+      </td>
+      <td align="right" nowrap>
+        <div class="page-title-text">
+        <controls:actions label="Server Actions">
+          <controls:action selected="true">
+            ----<bean:message key="actions.available.actions"/>----
+          </controls:action>
+          <controls:action>
+            ---------------------------------
+          </controls:action>
+          <controls:action url='<%= "/AddService.do?select=" +
+                                      URLEncoder.encode(thisObjectName,"UTF-8") %>'>
+            <bean:message key="actions.services.create"/>
+          </controls:action>
+          <controls:action url='<%= "/DeleteService.do?select=" +
+                                      URLEncoder.encode(thisObjectName,"UTF-8") %>'>
+            <bean:message key="actions.services.deletes"/>
+          </controls:action>
+        </controls:actions>
+        </div>
+      </td>
+    </tr>
+  </table>
+
+  <%@ include file="../buttons.jsp" %>
+ <br>
+
+  <table border="0" cellspacing="0" cellpadding="0" width="100%">
+    <tr><td><div class="table-title-text">
+      <bean:message key="server.properties"/>
+    </div></td></tr>
+  </table>
+
+  <table class="back-table" border="0" cellspacing="0" cellpadding="1" width="100%">
+    <tr>
+      <td>
+         <controls:table tableStyle="front-table" lineStyle="line-row">
+          <controls:row header="true"
+              labelStyle="table-header-text" dataStyle="table-header-text">
+            <controls:label>
+              <bean:message key="service.property"/>
+            </controls:label>
+            <controls:data>
+              <bean:message key="service.value"/>
+            </controls:data>
+          </controls:row>
+
+        <controls:row labelStyle="table-label-text" dataStyle="table-normal-text" styleId="portNumber">
+            <controls:label><bean:message key="server.portnumber"/>:</controls:label>
+            <controls:data>
+              <html:text property="portNumberText" size="24" maxlength="24" styleId="portNumber"/>
+            </controls:data>
+        </controls:row>
+
+       <controls:row labelStyle="table-label-text" dataStyle="table-normal-text" styleId="shutdown">
+            <controls:label><bean:message key="server.shutdown"/>:</controls:label>
+            <controls:data>
+               <html:text property="shutdownText" size="24" maxlength="24" styleId="shutdown"/>
+            </controls:data>
+        </controls:row>
+      </controls:table>
+
+      </td>
+    </tr>
+  </table>
+
+  <%@ include file="../buttons.jsp" %>
+
+</html:form>
+
+<!-- Standard Footer -->
+
+<%@ include file="../footer.jsp" %>
+
+</body>
+
+</html:html>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/service/service.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/service/service.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/service/service.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,233 @@
+<!-- Standard Struts Entries -->
+
+<%@ page language="java" import="java.net.URLEncoder" contentType="text/html;charset=utf-8" %>
+<%@ taglib uri="http://struts.apache.org/tags-bean" prefix="bean" %>
+<%@ taglib uri="http://struts.apache.org/tags-html" prefix="html" %>
+<%@ taglib uri="http://struts.apache.org/tags-logic" prefix="logic" %>
+<%@ taglib uri="/WEB-INF/controls.tld" prefix="controls" %>
+
+<html:html locale="true">
+
+<%@ include file="../users/header.jsp" %>
+
+<!-- Body -->
+<body bgcolor="white" background="../images/PaperTexture.gif">
+
+<!--Form -->
+
+<html:errors/>
+
+<html:form method="POST" action="/SaveService">
+
+  <bean:define id="serviceName" name="serviceForm" property="serviceName"/>
+  <bean:define id="thisObjectName" type="java.lang.String"
+               name="serviceForm" property="objectName"/>
+  <bean:define id="thisServiceName" type="java.lang.String"
+               name="serviceForm" property="serviceName"/>
+  <html:hidden property="adminServiceName"/>
+  <html:hidden property="objectName"/>
+  <html:hidden property="engineObjectName"/>
+  <html:hidden property="adminAction"/>
+  <bean:define id="adminServiceName" type="java.lang.String"
+               name="serviceForm" property="adminServiceName"/>
+
+  <table width="100%" border="0" cellspacing="0" cellpadding="0">
+    <tr class="page-title-row">
+      <td width="81%">
+        <div class="page-title-text" align="left">
+          <logic:equal name="serviceForm" property="adminAction" value="Create">
+            <bean:message key="actions.services.create"/>
+          </logic:equal>
+          <logic:equal name="serviceForm" property="adminAction" value="Edit">
+            <bean:write name="serviceForm" property="nodeLabel"/>
+          </logic:equal>
+        </div>
+      </td>
+      <td align="right" nowrap>
+        <div class="page-title-text">
+          <controls:actions label="Service Actions">
+            <controls:action selected="true">
+              -----<bean:message key="actions.available.actions"/>-----
+            </controls:action>
+            <controls:action disabled="true">
+              -------------------------------------
+            </controls:action>
+            <logic:notEqual name="serviceForm" property="adminAction" value="Create">
+              <controls:action url='<%= "/AddConnector.do?select=" +
+                                        URLEncoder.encode(thisObjectName,"UTF-8") %>'>
+                <bean:message key="actions.connectors.create"/>
+              </controls:action>
+              <controls:action url='<%= "/DeleteConnector.do?select=" +
+                                        URLEncoder.encode(thisObjectName,"UTF-8")%>'>
+                <bean:message key="actions.connectors.deletes"/>
+              </controls:action>
+              <controls:action>
+                -------------------------------------
+              </controls:action>
+              <controls:action disabled="true">
+                -------------------------------------
+              </controls:action>
+              <controls:action url='<%= "/AddHost.do?select=" +
+                                        URLEncoder.encode(thisObjectName,"UTF-8") %>'>
+                <bean:message key="actions.hosts.create"/>
+              </controls:action>
+              <controls:action url='<%= "/DeleteHost.do?select=" +
+                                        URLEncoder.encode(thisObjectName,"UTF-8") %>'>
+                <bean:message key="actions.hosts.deletes"/>
+              </controls:action>
+              <controls:action disabled="true">
+                -------------------------------------
+              </controls:action>
+               <%-- cannot delete or add a Realm for the service the admin app runs on --%>
+              <logic:notEqual name="serviceName" value='<%= adminServiceName %>'>
+              <controls:action disabled="true">
+                -------------------------------------
+              </controls:action>
+              <%--
+              <controls:action url='<%= "/AddRealm.do?parent=" +
+                                  URLEncoder.encode(thisObjectName,"UTF-8") %>'>
+                <bean:message key="actions.realms.create"/>
+             </controls:action>
+             <controls:action url='<%= "/DeleteRealm.do?parent=" +
+                                  URLEncoder.encode(thisObjectName,"UTF-8") %>'>
+                <bean:message key="actions.realms.deletes"/>
+              </controls:action>
+              --%>
+              </logic:notEqual>
+              <controls:action disabled="true">
+                -------------------------------------
+              </controls:action>
+              <controls:action url='<%= "/AddValve.do?parent=" +
+                                  URLEncoder.encode(thisObjectName,"UTF-8") %>'>
+                <bean:message key="actions.valves.create"/>
+              </controls:action>
+              <controls:action url='<%= "/DeleteValve.do?parent=" +
+                                  URLEncoder.encode(thisObjectName,"UTF-8") %>'>
+                <bean:message key="actions.valves.deletes"/>
+               </controls:action>
+               <%-- cannot delete the service the admin app runs on --%>
+               <logic:notEqual name="serviceName" value='<%= adminServiceName %>'>
+               <controls:action disabled="true">
+                -------------------------------------
+                </controls:action>
+                 <controls:action url='<%= "/DeleteService.do?select=" +
+                                        URLEncoder.encode(thisObjectName,"UTF-8") %>'>
+                <bean:message key="actions.services.delete"/>
+              </controls:action>
+              </logic:notEqual>
+            </logic:notEqual>
+          </controls:actions>
+        </div>
+      </td>
+    </tr>
+  </table>
+
+  <%@ include file="../buttons.jsp" %>
+
+  <%-- Service Properties --%>
+
+  <table border="0" cellspacing="0" cellpadding="0" width="100%">
+    <tr><td><div class="table-title-text">
+      <bean:message key="service.properties"/>
+    </div></td></tr>
+  </table>
+
+  <table class="back-table" border="0"
+         cellspacing="0" cellpadding="1" width="100%">
+    <tr>
+      <td>
+        <controls:table tableStyle="front-table" lineStyle="line-row">
+          <controls:row header="true"
+              labelStyle="table-header-text" dataStyle="table-header-text">
+            <controls:label>
+              <bean:message key="service.property"/>
+            </controls:label>
+            <controls:data>
+              <bean:message key="service.value"/>
+            </controls:data>
+          </controls:row>
+          <controls:row header="false"
+              labelStyle="table-label-text" dataStyle="table-normal-text" styleId="serviceName">
+            <controls:label>
+              <bean:message key="service.name"/>:
+            </controls:label>
+            <controls:data>
+              <logic:equal name="serviceForm" property="adminAction" value="Create">
+                <html:text property="serviceName" size="50" maxlength="50" styleId="serviceName"/>
+              </logic:equal>
+              <logic:equal name="serviceForm" property="adminAction" value="Edit">
+                <html:hidden property="serviceName"/>
+                <bean:write name="serviceForm" property="serviceName"/>
+              </logic:equal>
+            </controls:data>
+          </controls:row>
+        </controls:table>
+      </td>
+    </tr>
+  </table>
+
+  <br>
+
+  <%-- Engine Properties --%>
+
+  <table border="0" cellspacing="0" cellpadding="0" width="100%">
+    <tr><td><div class="table-title-text">
+      <bean:message key="service.engine.props"/>
+    </div></td></tr>
+  </table>
+
+  <table class="back-table" border="0"
+         cellspacing="0" cellpadding="1" width="100%">
+    <tr>
+      <td>
+        <controls:table tableStyle="front-table" lineStyle="line-row">
+          <controls:row header="true"
+              labelStyle="table-header-text" dataStyle="table-header-text">
+            <controls:label>
+              <bean:message key="service.property"/>
+            </controls:label>
+            <controls:data>
+              <bean:message key="service.value"/>
+            </controls:data>
+          </controls:row>
+          <controls:row header="false"
+              labelStyle="table-label-text" dataStyle="table-normal-text" styleId="engineName">
+            <controls:label>
+              <bean:message key="service.name"/>:
+            </controls:label>
+            <controls:data>
+              <logic:equal name="serviceForm" property="adminAction" value="Create">
+                <html:text property="engineName" size="50" maxlength="50" styleId="engineName"/>
+              </logic:equal>
+              <logic:equal name="serviceForm" property="adminAction" value="Edit">
+                <html:hidden property="engineName"/>
+                <bean:write name="serviceForm" property="engineName"/>
+              </logic:equal>
+            </controls:data>
+          </controls:row>
+          <controls:row header="false"
+              labelStyle="table-label-text" dataStyle="table-normal-text" styleId="hostNameVals">
+            <controls:label>
+              <bean:message key="service.defaulthostname"/>:
+            </controls:label>
+            <controls:data>
+              <bean:define id="hostNameVals" name="serviceForm"
+                           property="hostNameVals"/>
+              <html:select property="defaultHost" styleId="hostNameVals">
+                <html:options collection="hostNameVals" property="value"
+                              labelProperty="label"/>
+              </html:select>
+            </controls:data>
+          </controls:row>
+        </controls:table>
+      </td>
+    </tr>
+  </table>
+
+  <br>
+
+  <%@ include file="../buttons.jsp" %>
+
+</html:form>
+</body>
+</html:html>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/service/services.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/service/services.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/service/services.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,105 @@
+<!-- Standard Struts Entries -->
+<%@ page language="java" contentType="text/html;charset=utf-8" %>
+<%@ taglib uri="http://struts.apache.org/tags-bean" prefix="bean" %>
+<%@ taglib uri="http://struts.apache.org/tags-html" prefix="html" %>
+<%@ taglib uri="http://struts.apache.org/tags-logic" prefix="logic" %>
+<%@ taglib uri="/WEB-INF/controls.tld" prefix="controls" %>
+
+<html:html locale="true">
+
+<%@ include file="../users/header.jsp" %>
+
+<!-- Body -->
+<body bgcolor="white" background="../images/PaperTexture.gif">
+
+<!--Form -->
+
+<html:errors/>
+
+<html:form method="post" action="/DeleteServices">
+
+  <table width="100%" border="0" cellspacing="0" cellpadding="0">
+    <tr bgcolor="7171A5">
+      <td width="81%">
+        <div class="page-title-text" align="left">
+          <bean:message key="actions.services.delete"/>
+        </div>
+      </td>
+      <td align="right" nowrap>
+        <div class="page-title-text">        
+            <controls:actions label="Service Actions">
+              <controls:action selected="true">
+                ----<bean:message key="actions.available.actions"/>----
+              </controls:action>
+              <controls:action>
+                ---------------------------------
+              </controls:action>
+            </controls:actions>
+        </div>
+      </td>
+    </tr>
+  </table>
+
+<%@ include file="../buttons.jsp" %>
+  <br>
+
+  <%-- Services List --%>
+
+  <table class="back-table" border="0" cellspacing="0" cellpadding="1"
+         width="100%">
+    <tr><td>
+
+      <table class="front-table" border="1"
+       cellspacing="0" cellpadding="0" width="100%">
+
+        <tr class="header-row">
+          <td><div align="left" class="table-header-text">
+            <bean:message key="actions.delete"/>
+          </div></td>
+          <td><div align="left" class="table-header-text">
+            <bean:message key="host.name"/>
+          </div></td>
+        </tr>
+
+        <logic:iterate name="servicesList" id="service">
+          <tr class="line-row">
+            <td><div align="left" class="table-normal-text">&nbsp;
+             <logic:match name="service"
+                        value='<%= (String)request.getAttribute("adminAppService") %>'>
+             <font color='red'>*</font>
+             </logic:match>
+             <logic:notMatch name="service"
+                        value='<%= (String)request.getAttribute("adminAppService") %>'>
+              <label for="services"></label>          
+              <html:multibox property="services"
+                                value="<%= service.toString() %>" styleId="services" styleId="services"/>
+              </logic:notMatch>
+            </div></td>
+            <td><div align="left" class="table-normal-text">&nbsp;
+              <html:link page='<%= "/EditService.do?select=" +
+                         java.net.URLEncoder.encode(service.toString(),"UTF-8") %>'>
+                <controls:attribute name="service" attribute="name"/>
+              </html:link>
+            </div></td>
+          </tr>
+        </logic:iterate>
+
+      </table>
+
+    </td></tr>
+  </table>
+
+<br>
+<font color='red'> * </font>
+Cannot delete the service the admin application is running on.
+
+<br>
+
+<%@ include file="../buttons.jsp" %>
+
+  <br>
+</html:form>
+
+<p>&nbsp;</p>
+</body>
+</html:html>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/tree-control-test.css
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/tree-control-test.css	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/tree-control-test.css	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,19 @@
+.tree-control {
+  font-family: arial, verdana, geneva, helvetica, sans-serif;
+  font-size: 80%;
+  line-height: 1.0;
+}
+
+.tree-control-selected {
+  color: black;
+  font-weight: bold;
+  text-decoration: none;
+}
+
+.tree-control-unselected {
+  color: black;
+  font-style: normal;
+  font-weight: normal;
+  text-decoration: none;
+}
+

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/tree-control-test.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/tree-control-test.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/tree-control-test.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,34 @@
+<!-- Standard Struts Entries -->
+
+<%@ page language="java" contentType="text/html;charset=utf-8" %>
+<%@ taglib uri="http://struts.apache.org/tags-bean" prefix="bean" %>
+<%@ taglib uri="http://struts.apache.org/tags-html" prefix="html" %>
+<%@ taglib uri="http://struts.apache.org/tags-logic" prefix="logic" %>
+<%@ taglib uri="/WEB-INF/controls.tld" prefix="controls" %>
+
+<html:html locale="true">
+
+<!-- Standard Content -->
+
+<%@ include file="header.jsp" %>
+
+<!-- Body -->
+
+<body bgcolor="white">
+
+<!-- Tree Component -->
+
+  <controls:tree tree="treeControlTest"
+               action="treeControlTest.do?tree={name}"
+                style="tree-control"
+        styleSelected="tree-control-selected"
+      styleUnselected="tree-control-unselected"
+  />
+
+</body>
+
+<!-- Standard Footer -->
+
+<%@ include file="footer.jsp" %>
+
+</html:html>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/users/deleteGroups.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/users/deleteGroups.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/users/deleteGroups.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,52 @@
+<!-- Standard Struts Entries -->
+<%@ page language="java" import="java.net.URLEncoder" contentType="text/html;charset=utf-8" %>
+<%@ taglib uri="http://struts.apache.org/tags-bean" prefix="bean" %>
+<%@ taglib uri="http://struts.apache.org/tags-html" prefix="html" %>
+<%@ taglib uri="http://struts.apache.org/tags-logic" prefix="logic" %>
+<%@ taglib uri="/WEB-INF/controls.tld" prefix="controls" %>
+
+<html:html locale="true">
+
+<%@ include file="header.jsp" %>
+
+<!-- Body -->
+<body bgcolor="white" background="../images/PaperTexture.gif">
+
+<!--Form -->
+
+<html:errors/>
+
+<html:form action="/users/listGroups">
+
+  <table width="100%" border="0" cellspacing="0" cellpadding="0">
+    <tr bgcolor="7171A5">
+      <td width="81%">
+        <div class="page-title-text" align="left">
+          <bean:message key="users.deleteGroups.title"/>
+        </div>
+      </td>
+      <td width="19%">
+        <div align="right">
+          <%@ include file="listGroups.jspf" %>
+        </div>
+      </td>
+    </tr>
+  </table>
+
+</html:form>
+
+<br>
+<bean:define id="checkboxes" scope="page" value="true"/>
+<html:form action="/users/deleteGroups">
+  <%@ include file="../buttons.jsp" %>
+  <br>
+  <html:hidden property="databaseName"/>
+  <%@ include file="groups.jspf" %>
+  <%@ include file="../buttons.jsp" %>
+</html:form>
+<br>
+
+<%@ include file="footer.jsp" %>
+
+</body>
+</html:html>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/users/deleteRoles.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/users/deleteRoles.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/users/deleteRoles.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,52 @@
+<!-- Standard Struts Entries -->
+<%@ page language="java" import="java.net.URLEncoder" contentType="text/html;charset=utf-8" %>
+<%@ taglib uri="http://struts.apache.org/tags-bean" prefix="bean" %>
+<%@ taglib uri="http://struts.apache.org/tags-html" prefix="html" %>
+<%@ taglib uri="http://struts.apache.org/tags-logic" prefix="logic" %>
+<%@ taglib uri="/WEB-INF/controls.tld" prefix="controls" %>
+
+<html:html locale="true">
+
+<%@ include file="header.jsp" %>
+
+<!-- Body -->
+<body bgcolor="white" background="../images/PaperTexture.gif">
+
+<!--Form -->
+
+<html:errors/>
+
+<html:form action="/users/listRoles">
+
+  <table width="100%" border="0" cellspacing="0" cellpadding="0">
+    <tr bgcolor="7171A5">
+      <td width="81%">
+        <div class="page-title-text" align="left">
+          <bean:message key="users.deleteRoles.title"/>
+        </div>
+      </td>
+      <td width="19%">
+        <div align="right">
+          <%@ include file="listRoles.jspf" %>
+        </div>
+      </td>
+    </tr>
+  </table>
+
+</html:form>
+
+<br>
+<bean:define id="checkboxes" scope="page" value="true"/>
+<html:form action="/users/deleteRoles">
+  <%@ include file="../buttons.jsp" %>
+  <br>
+  <html:hidden property="databaseName"/>
+  <%@ include file="roles.jspf" %>
+  <%@ include file="../buttons.jsp" %>
+</html:form>
+<br>
+
+<%@ include file="footer.jsp" %>
+
+</body>
+</html:html>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/users/deleteUsers.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/users/deleteUsers.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/users/deleteUsers.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,52 @@
+<!-- Standard Struts Entries -->
+<%@ page language="java" import="java.net.URLEncoder" contentType="text/html;charset=utf-8" %>
+<%@ taglib uri="http://struts.apache.org/tags-bean" prefix="bean" %>
+<%@ taglib uri="http://struts.apache.org/tags-html" prefix="html" %>
+<%@ taglib uri="http://struts.apache.org/tags-logic" prefix="logic" %>
+<%@ taglib uri="/WEB-INF/controls.tld" prefix="controls" %>
+
+<html:html locale="true">
+
+<%@ include file="header.jsp" %>
+
+<!-- Body -->
+<body bgcolor="white" background="../images/PaperTexture.gif">
+
+<!--Form -->
+
+<html:errors/>
+
+<html:form action="/users/listUsers">
+
+  <table width="100%" border="0" cellspacing="0" cellpadding="0">
+    <tr bgcolor="7171A5">
+      <td width="81%">
+        <div class="page-title-text" align="left">
+          <bean:message key="users.deleteUsers.title"/>
+        </div>
+      </td>
+      <td width="19%">
+        <div align="right">
+          <%@ include file="listUsers.jspf" %>
+        </div>
+      </td>
+    </tr>
+  </table>
+
+</html:form>
+
+<br>
+<bean:define id="checkboxes" scope="page" value="true"/>
+<html:form action="/users/deleteUsers">
+  <%@ include file="../buttons.jsp" %>
+  <br>
+  <html:hidden property="databaseName"/>
+  <%@ include file="users.jspf" %>
+  <%@ include file="../buttons.jsp" %>
+</html:form>
+<br>
+
+<%@ include file="footer.jsp" %>
+
+</body>
+</html:html>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/users/footer.jsp
===================================================================

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/users/group.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/users/group.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/users/group.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,124 @@
+<!-- Standard Struts Entries -->
+
+<%@ page language="java" import="java.net.URLEncoder" contentType="text/html;charset=utf-8" %>
+<%@ taglib uri="http://struts.apache.org/tags-bean" prefix="bean" %>
+<%@ taglib uri="http://struts.apache.org/tags-html" prefix="html" %>
+<%@ taglib uri="http://struts.apache.org/tags-logic" prefix="logic" %>
+<%@ taglib uri="/WEB-INF/controls.tld" prefix="controls" %>
+
+<html:html locale="true">
+
+<%@ include file="header.jsp" %>
+
+<!-- Body -->
+<body bgcolor="white" background="../images/PaperTexture.gif">
+
+<!--Form -->
+
+<html:errors/>
+
+<html:form method="POST" action="/users/saveGroup"> <!--focus="groupname"-->
+
+  <html:hidden property="databaseName"/>
+  <html:hidden property="objectName"/>
+
+  <table width="100%" border="0" cellspacing="0" cellpadding="0">
+    <tr class="page-title-row">
+      <td align="left" nowrap>
+        <div class="page-title-text">
+          <bean:write name="groupForm" property="nodeLabel"/>
+        </div>
+      </td>
+      <td align="right" nowrap>
+        <div class="page-title-text">
+          <controls:actions label="Group Actions">
+            <controls:action selected="true">
+              ----<bean:message key="actions.available.actions"/>----
+            </controls:action>
+            <controls:action>
+              ---------------------------------
+            </controls:action>
+            <!-- will add the urls later once those screens get implemented -->
+<%--
+            <controls:action url="">
+              <bean:message key="users.actions.group.create"/>
+            </controls:action>
+            <controls:action url="">
+              <bean:message key="users.actions.group.delete"/>
+            </controls:action>
+--%>
+          </controls:actions>
+        </div>
+      </td>
+    </tr>
+  </table>
+
+  <%@ include file="../buttons.jsp" %>
+<br>
+
+  <table class="back-table" border="0" cellspacing="0" cellpadding="1"
+         width="100%">
+    <tr>
+      <td>
+
+        <controls:table tableStyle="front-table" lineStyle="line-row">
+
+          <controls:row header="true"
+                labelStyle="table-header-text" dataStyle="table-header-text">
+            <controls:label>
+              <bean:message key="users.group.properties"/>
+            </controls:label>
+            <controls:data>
+              &nbsp;
+            </controls:data>
+          </controls:row>
+
+          <controls:row labelStyle="table-label-text"
+                         dataStyle="table-normal-text" styleId="groupname">
+            <controls:label>
+              <bean:message key="users.prompt.groupname"/>
+            </controls:label>
+            <controls:data>
+              <logic:present name="groupForm" property="objectName">
+                <bean:write name="groupForm" property="groupname"/>
+                <html:hidden property="groupname"/>
+              </logic:present>
+              <logic:notPresent name="groupForm" property="objectName">
+                <html:text property="groupname" size="24" maxlength="32" styleId="groupname"/>
+              </logic:notPresent>
+            </controls:data>
+          </controls:row>
+
+          <controls:row labelStyle="table-label-text"
+                         dataStyle="table-normal-text" styleId="description">
+            <controls:label>
+              <bean:message key="users.prompt.description"/>
+            </controls:label>
+            <controls:data>
+              <html:text property="description" size="24" maxlength="128" styleId="description"/>
+            </controls:data>
+          </controls:row>
+
+        </controls:table>
+
+      </td>
+
+    </tr>
+
+  </table>
+
+  <bean:define id="checkboxes" scope="page" value="true"/>
+  <br>
+  <%@ include file="roles.jspf" %>
+
+  <%@ include file="../buttons.jsp" %>
+
+</html:form>
+
+<!-- Standard Footer -->
+
+<%@ include file="footer.jsp" %>
+
+</body>
+
+</html:html>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/users/groups.jspf
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/users/groups.jspf	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/users/groups.jspf	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,54 @@
+<%-- Groups List --%>
+
+<table class="back-table" border="0" cellspacing="0" cellpadding="1"
+       width="100%"><tr><td> 
+
+  <table class="front-table" border="1"
+   cellspacing="0" cellpadding="0" width="100%">
+    <tr class="header-row">
+      <logic:present name="checkboxes">
+        <th scope="col" width="5%"><div align="left" class="table-header-text">
+          &nbsp;
+        </th>
+      </logic:present>
+      <th scope="col" width="20%"><div align="left" class="table-header-text">
+        <bean:message key="users.list.groupname"/>
+      </div></th>
+      <th scope="col"><div align="left" class="table-header-text">
+        <bean:message key="users.list.description"/>
+      </div></th>
+    </tr>
+    <logic:present name="groupsForm">
+    <logic:iterate name="groupsForm" property="groups"
+                     id="group" type="java.lang.String">
+      <tr class="line-row">
+        <logic:present name="checkboxes">
+          <td scope="row"><div align="center" class="table-normal-text">
+            <logic:present name="userForm">
+             <label for="groups"></label>
+              <html:multibox property="groups" value='<%= group %>' styleId="groups"/>
+            </logic:present>
+            <logic:notPresent name="userForm">
+              <label for="groups"></label>
+              <input type="checkbox" name="groups"
+                    value='<%= group %>' styleId="groups">
+            </logic:notPresent>
+          </td>
+        </logic:present>
+        <td scope="row"><div align="left" class="table-normal-text">&nbsp;
+          <html:link page='<%= "/users/setUpGroup.do?objectName=" + 
+                               URLEncoder.encode(group,"UTF-8") +
+                               "&databaseName=" +
+                               URLEncoder.encode(request.getParameter("databaseName"),"UTF-8") %>'>
+            <controls:attribute name="group" attribute="groupname"/>
+          </html:link>
+        </div></td>
+        <td scope="row"><div align="left" class="table-normal-text">&nbsp;
+          <controls:attribute name="group" attribute="description"/>
+        </div></td>
+      </tr>
+    </logic:iterate>
+    </logic:present>
+  </table>
+
+</td></tr></table>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/users/header.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/users/header.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/users/header.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,11 @@
+<!--
+  Copyright (c) 1999-2002 The Apache Software Foundation.  All rights
+  reserved.
+-->
+
+<head>
+  <title><bean:message key="application.title"/></title>
+  <html:base/>
+  <link rel="stylesheet" type="text/css" href="../tree-control-test.css">
+  <link rel="stylesheet" type="text/css" href="../admin.css">
+</head>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/users/listGroups.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/users/listGroups.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/users/listGroups.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,43 @@
+<!-- Standard Struts Entries -->
+<%@ page language="java" import="java.net.URLEncoder" contentType="text/html;charset=utf-8" %>
+<%@ taglib uri="http://struts.apache.org/tags-bean" prefix="bean" %>
+<%@ taglib uri="http://struts.apache.org/tags-html" prefix="html" %>
+<%@ taglib uri="http://struts.apache.org/tags-logic" prefix="logic" %>
+<%@ taglib uri="/WEB-INF/controls.tld" prefix="controls" %>
+
+<html:html locale="true">
+
+<%@ include file="header.jsp" %>
+
+<!-- Body -->
+<body bgcolor="white" background="../images/PaperTexture.gif">
+
+<!--Form -->
+
+<html:errors/>
+
+<html:form action="/users/listGroups">
+
+  <table width="100%" border="0" cellspacing="0" cellpadding="0">
+    <tr bgcolor="7171A5">
+      <td width="81%">
+        <div class="page-title-text" align="left">
+          <bean:message key="users.listGroups.title"/>
+        </div>
+      </td>
+      <td width="19%">
+        <div align="right">
+          <%@ include file="listGroups.jspf" %>
+        </div>
+      </td>
+    </tr>
+  </table>
+
+</html:form>
+
+<br>
+<%@ include file="groups.jspf" %>
+<br>
+
+</body>
+</html:html>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/users/listGroups.jspf
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/users/listGroups.jspf	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/users/listGroups.jspf	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,32 @@
+<td align="right" nowrap>
+<div class="page-title-text">
+<controls:actions label="Group Actions">
+
+  <controls:action selected="true">
+    ----<bean:message key="actions.available.actions"/>----
+  </controls:action>
+
+  <controls:action>
+    ---------------------------------
+  </controls:action>
+
+  <controls:action url='<%= "/users/setUpGroup.do?databaseName=" +
+       URLEncoder.encode(request.getParameter("databaseName"),"UTF-8") %>'>
+    <bean:message key="users.actions.group.create"/>
+  </controls:action>
+
+  <controls:action url='<%= "/users/listGroups.do?databaseName=" +
+       URLEncoder.encode(request.getParameter("databaseName"),"UTF-8") +
+       "&forward=" + URLEncoder.encode("Groups Delete List","UTF-8") %>'>
+    <bean:message key="users.actions.group.delete"/>
+  </controls:action>
+
+  <controls:action url='<%= "/users/listGroups.do?databaseName=" +
+       URLEncoder.encode(request.getParameter("databaseName"),"UTF-8") +
+       "&forward=" + URLEncoder.encode("Groups List","UTF-8") %>'>
+    <bean:message key="users.actions.group.list"/>
+  </controls:action>
+
+</controls:actions>
+</div>
+</td>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/users/listRoles.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/users/listRoles.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/users/listRoles.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,43 @@
+<!-- Standard Struts Entries -->
+<%@ page language="java" import="java.net.URLEncoder" contentType="text/html;charset=utf-8" %>
+<%@ taglib uri="http://struts.apache.org/tags-bean" prefix="bean" %>
+<%@ taglib uri="http://struts.apache.org/tags-html" prefix="html" %>
+<%@ taglib uri="http://struts.apache.org/tags-logic" prefix="logic" %>
+<%@ taglib uri="/WEB-INF/controls.tld" prefix="controls" %>
+
+<html:html locale="true">
+
+<%@ include file="header.jsp" %>
+
+<!-- Body -->
+<body bgcolor="white" background="../images/PaperTexture.gif">
+
+<!--Form -->
+
+<html:errors/>
+
+<html:form action="/users/listRoles">
+
+  <table width="100%" border="0" cellspacing="0" cellpadding="0">
+    <tr bgcolor="7171A5">
+      <td width="81%">
+        <div class="page-title-text" align="left">
+          <bean:message key="users.listRoles.title"/>
+        </div>
+      </td>
+      <td width="19%">
+        <div align="right">
+          <%@ include file="listRoles.jspf" %>
+        </div>
+      </td>
+    </tr>
+  </table>
+
+</html:form>
+
+<br>
+<%@ include file="roles.jspf" %>
+<br>
+
+</body>
+</html:html>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/users/listRoles.jspf
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/users/listRoles.jspf	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/users/listRoles.jspf	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,32 @@
+<td align="right" nowrap>
+<div class="page-title-text">
+<controls:actions label="Role Actions">
+
+  <controls:action selected="true">
+    ----<bean:message key="actions.available.actions"/>----
+  </controls:action>
+
+  <controls:action>
+    ---------------------------------
+  </controls:action>
+
+  <controls:action url='<%= "/users/setUpRole.do?databaseName=" +
+       URLEncoder.encode(request.getParameter("databaseName"),"UTF-8") %>'>
+    <bean:message key="users.actions.role.create"/>
+  </controls:action>
+
+  <controls:action url='<%= "/users/listRoles.do?databaseName=" +
+       URLEncoder.encode(request.getParameter("databaseName"),"UTF-8") +
+       "&forward=" + URLEncoder.encode("Roles Delete List","UTF-8") %>'>
+    <bean:message key="users.actions.role.delete"/>
+  </controls:action>
+
+  <controls:action url='<%= "/users/listRoles.do?databaseName=" +
+       URLEncoder.encode(request.getParameter("databaseName"),"UTF-8") +
+       "&forward=" + URLEncoder.encode("Roles List","UTF-8") %>'>
+    <bean:message key="users.actions.role.list"/>
+  </controls:action>
+
+</controls:actions>
+</div>
+</td>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/users/listUsers.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/users/listUsers.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/users/listUsers.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,43 @@
+<!-- Standard Struts Entries -->
+<%@ page language="java" import="java.net.URLEncoder" contentType="text/html;charset=utf-8" %>
+<%@ taglib uri="http://struts.apache.org/tags-bean" prefix="bean" %>
+<%@ taglib uri="http://struts.apache.org/tags-html" prefix="html" %>
+<%@ taglib uri="http://struts.apache.org/tags-logic" prefix="logic" %>
+<%@ taglib uri="/WEB-INF/controls.tld" prefix="controls" %>
+
+<html:html locale="true">
+
+<%@ include file="header.jsp" %>
+
+<!-- Body -->
+<body bgcolor="white" background="../images/PaperTexture.gif">
+
+<!--Form -->
+
+<html:errors/>
+
+<html:form action="/users/listUsers">
+
+  <table width="100%" border="0" cellspacing="0" cellpadding="0">
+    <tr bgcolor="7171A5">
+      <td width="81%">
+        <div class="page-title-text" align="left">
+          <bean:message key="users.listUsers.title"/>
+        </div>
+      </td>
+      <td width="19%">
+        <div align="right">
+          <%@ include file="listUsers.jspf" %>
+        </div>
+      </td>
+    </tr>
+  </table>
+
+</html:form>
+
+<br>
+<%@ include file="users.jspf" %>
+<br>
+
+</body>
+</html:html>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/users/listUsers.jspf
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/users/listUsers.jspf	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/users/listUsers.jspf	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,32 @@
+<td align="right" nowrap>
+<div class="page-title-text">
+<controls:actions label="User Actions">
+
+  <controls:action selected="true">
+    ----<bean:message key="actions.available.actions"/>----
+  </controls:action>
+
+  <controls:action>
+    ---------------------------------
+  </controls:action>
+
+  <controls:action url='<%= "/users/setUpUser.do?databaseName=" +
+       URLEncoder.encode(request.getParameter("databaseName"),"UTF-8") %>'>
+    <bean:message key="users.actions.user.create"/>
+  </controls:action>
+
+  <controls:action url='<%= "/users/listUsers.do?databaseName=" +
+       URLEncoder.encode(request.getParameter("databaseName"),"UTF-8") +
+       "&forward=" + URLEncoder.encode("Users Delete List","UTF-8") %>'>
+    <bean:message key="users.actions.user.delete"/>
+  </controls:action>
+
+  <controls:action url='<%= "/users/listUsers.do?databaseName=" +
+       URLEncoder.encode(request.getParameter("databaseName"),"UTF-8") +
+       "&forward=" + URLEncoder.encode("Users List","UTF-8") %>'>
+    <bean:message key="users.actions.user.list"/>
+  </controls:action>
+
+</controls:actions>
+</div>
+</td>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/users/role.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/users/role.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/users/role.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,120 @@
+<!-- Standard Struts Entries -->
+
+<%@ page language="java" import="java.net.URLEncoder" contentType="text/html;charset=utf-8" %>
+<%@ taglib uri="http://struts.apache.org/tags-bean" prefix="bean" %>
+<%@ taglib uri="http://struts.apache.org/tags-html" prefix="html" %>
+<%@ taglib uri="http://struts.apache.org/tags-logic" prefix="logic" %>
+<%@ taglib uri="/WEB-INF/controls.tld" prefix="controls" %>
+
+<html:html locale="true">
+
+<%@ include file="header.jsp" %>
+
+<!-- Body -->
+<body bgcolor="white" background="../images/PaperTexture.gif">
+
+<!--Form -->
+
+<html:errors/>
+
+<html:form method="POST" action="/users/saveRole"> <!--focus="rolename"-->
+
+  <html:hidden property="databaseName"/>
+  <html:hidden property="objectName"/>
+
+  <table width="100%" border="0" cellspacing="0" cellpadding="0">
+    <tr class="page-title-row">
+      <td align="left" nowrap>
+        <div class="page-title-text">
+          <bean:write name="roleForm" property="nodeLabel"/>
+        </div>
+      </td>
+      <td align="right" nowrap>
+        <div class="page-title-text">
+          <controls:actions label="Role Actions">
+            <controls:action selected="true">
+              ----<bean:message key="actions.available.actions"/>----
+            </controls:action>
+            <controls:action>
+              ---------------------------------
+            </controls:action>
+            <!-- will add the urls later once those screens get implemented -->
+<%--
+            <controls:action url="">
+              <bean:message key="users.actions.role.create"/>
+            </controls:action>
+            <controls:action url="">
+              <bean:message key="users.actions.role.delete"/>
+            </controls:action>
+--%>
+          </controls:actions>
+        </div>
+      </td>
+    </tr>
+  </table>
+
+  <%@ include file="../buttons.jsp" %>
+<br>
+
+  <table class="back-table" border="0" cellspacing="0" cellpadding="1"
+         width="100%">
+    <tr>
+      <td>
+
+        <controls:table tableStyle="front-table" lineStyle="line-row">
+
+          <controls:row header="true"
+                labelStyle="table-header-text" dataStyle="table-header-text">
+            <controls:label>
+              <bean:message key="users.role.properties"/>
+            </controls:label>
+            <controls:data>
+              &nbsp;
+            </controls:data>
+          </controls:row>
+
+          <controls:row labelStyle="table-label-text"
+                         dataStyle="table-normal-text" styleId="rolename">
+            <controls:label>
+              <bean:message key="users.prompt.rolename"/>
+            </controls:label>
+            <controls:data>
+              <logic:present name="roleForm" property="objectName">
+                <bean:write name="roleForm" property="rolename"/>
+                <html:hidden property="rolename"/>
+              </logic:present>
+              <logic:notPresent name="roleForm" property="objectName">
+                <html:text property="rolename" size="24" maxlength="32" styleId="rolename"/>
+              </logic:notPresent>
+            </controls:data>
+          </controls:row>
+
+          <controls:row labelStyle="table-label-text"
+                         dataStyle="table-normal-text" styleId="description">
+            <controls:label>
+              <bean:message key="users.prompt.description"/>:
+            </controls:label>
+            <controls:data>
+              <html:text property="description" size="24" maxlength="128" styleId="description"/>
+            </controls:data>
+          </controls:row>
+
+        </controls:table>
+
+      </td>
+
+    </tr>
+
+  </table>
+
+  <%@ include file="../buttons.jsp" %>
+
+</html:form>
+
+<!-- Standard Footer -->
+
+<%@ include file="footer.jsp" %>
+
+</body>
+
+</html:html>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/users/roles.jspf
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/users/roles.jspf	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/users/roles.jspf	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,60 @@
+<%-- Roles List --%>
+
+<table class="back-table" border="0" cellspacing="0" cellpadding="1"
+       width="100%"><tr><td> 
+
+  <table class="front-table" border="1"
+   cellspacing="0" cellpadding="0" width="100%">
+    <tr class="header-row">
+      <logic:present name="checkboxes">
+        <td width="5%"><div align="left" class="table-header-text">
+          &nbsp;
+        </td>
+      </logic:present>
+      <th scope="col" width="20%"><div align="left" class="table-header-text">
+        <bean:message key="users.list.rolename"/>
+      </div></th>
+      <th scope="col"><div align="left" class="table-header-text">
+        <bean:message key="users.list.description"/>
+      </div></th>
+    </tr>
+    <logic:present name="rolesForm">
+    <logic:iterate name="rolesForm" property="roles"
+                     id="role" type="java.lang.String">
+      <tr class="line-row">
+        <logic:present name="checkboxes">
+          <td scope="row"><div align="center" class="table-normal-text">
+            <logic:present name="groupForm">
+              <label for="roles"></label>
+              <html:multibox property="roles" value="<%= role %>" styleId="roles"/>
+            </logic:present>
+            <logic:present name="userForm">
+              <label for="roles"></label>
+              <html:multibox property="roles" value="<%= role %>" styleId="roles"/>
+            </logic:present>
+            <logic:notPresent name="groupForm">
+              <logic:notPresent name="userForm">
+                <label for="roles"></label>
+                <input type="checkbox" name="roles"
+                      value="<%= role %>" styleId="roles">
+              </logic:notPresent>
+            </logic:notPresent>
+          </td>
+        </logic:present>
+        <td scope="row"><div align="left" class="table-normal-text">&nbsp;
+          <html:link page='<%= "/users/setUpRole.do?objectName=" + 
+                               URLEncoder.encode(role,"UTF-8") +
+                               "&databaseName=" +
+                               URLEncoder.encode(request.getParameter("databaseName"),"UTF-8") %>'>
+            <controls:attribute name="role" attribute="rolename"/>
+          </html:link>
+        </div></td>
+        <td scope="row"><div align="left" class="table-normal-text">&nbsp;
+          <controls:attribute name="role" attribute="description"/>
+        </div></td>
+      </tr>
+    </logic:iterate>
+    </logic:present>
+  </table>
+
+</td></tr></table>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/users/user.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/users/user.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/users/user.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,137 @@
+<!-- Standard Struts Entries -->
+
+<%@ page language="java" import="java.net.URLEncoder" contentType="text/html;charset=utf-8" %>
+<%@ taglib uri="http://struts.apache.org/tags-bean" prefix="bean" %>
+<%@ taglib uri="http://struts.apache.org/tags-html" prefix="html" %>
+<%@ taglib uri="http://struts.apache.org/tags-logic" prefix="logic" %>
+<%@ taglib uri="/WEB-INF/controls.tld" prefix="controls" %>
+
+<html:html locale="true">
+
+<%@ include file="header.jsp" %>
+
+<!-- Body -->
+<body bgcolor="white" background="../images/PaperTexture.gif">
+
+<!--Form -->
+
+<html:errors/>
+
+<html:form method="POST" action="/users/saveUser"> <!--focus="username"-->
+
+  <html:hidden property="databaseName"/>
+  <html:hidden property="objectName"/>
+
+  <table width="100%" border="0" cellspacing="0" cellpadding="0">
+    <tr class="page-title-row">
+      <td align="left" nowrap>
+        <div class="page-title-text">
+          <bean:write name="userForm" property="nodeLabel"/>
+        </div>
+      </td>
+      <td align="right" nowrap>
+        <div class="page-title-text">
+          <controls:actions label="User Actions">
+            <controls:action selected="true">
+              ----<bean:message key="actions.available.actions"/>----
+            </controls:action>
+            <controls:action>
+              ---------------------------------
+            </controls:action>
+            <controls:action url='<%= "/users/setUpUser.do?databaseName=" +
+            URLEncoder.encode(request.getParameter("databaseName"),"UTF-8") %>'>
+                <bean:message key="users.actions.user.create"/>
+            </controls:action>
+
+            <controls:action url='<%= "/users/listUsers.do?databaseName=" +
+                URLEncoder.encode(request.getParameter("databaseName"),"UTF-8") +
+                "&forward=" + URLEncoder.encode("Users Delete List","UTF-8") %>'>
+                <bean:message key="users.actions.user.delete"/>
+            </controls:action>
+         </controls:actions>
+        </div>
+      </td>
+    </tr>
+  </table>
+
+  <%@ include file="../buttons.jsp" %>
+<br>
+
+  <table class="back-table" border="0" cellspacing="0" cellpadding="1"
+         width="100%">
+    <tr>
+      <td>
+
+        <controls:table tableStyle="front-table" lineStyle="line-row">
+
+          <controls:row header="true"
+                labelStyle="table-header-text" dataStyle="table-header-text">
+            <controls:label>
+              <bean:message key="users.user.properties"/>
+            </controls:label>
+            <controls:data>
+              &nbsp;
+            </controls:data>
+          </controls:row>
+
+          <controls:row labelStyle="table-label-text"
+                         dataStyle="table-normal-text" styleId="username">
+            <controls:label>
+              <bean:message key="users.prompt.username"/>
+            </controls:label>
+            <controls:data>
+              <logic:present name="userForm" property="objectName">
+                <bean:write name="userForm" property="username"/>
+                <html:hidden property="username"/>
+              </logic:present>
+              <logic:notPresent name="userForm" property="objectName">
+                <html:text property="username" size="24" styleId="username"/>
+              </logic:notPresent>
+            </controls:data>
+          </controls:row>
+
+          <controls:row labelStyle="table-label-text"
+                         dataStyle="table-normal-text" styleId="password">
+            <controls:label>
+              <bean:message key="users.prompt.password"/>
+            </controls:label>
+            <controls:data>
+              <html:password property="password" size="24" styleId="password"/>
+            </controls:data>
+          </controls:row>
+
+          <controls:row labelStyle="table-label-text"
+                         dataStyle="table-normal-text" styleId="fullname">
+            <controls:label>
+              <bean:message key="users.prompt.fullName"/>
+            </controls:label>
+            <controls:data>
+              <html:text property="fullName" size="24" maxlength="64" styleId="fullname"/>
+            </controls:data>
+          </controls:row>
+
+        </controls:table>
+
+      </td>
+
+    </tr>
+
+  </table>
+
+  <bean:define id="checkboxes" scope="page" value="true"/>
+  <br>
+  <%@ include file="groups.jspf" %>
+  <br>
+  <%@ include file="roles.jspf" %>
+
+  <%@ include file="../buttons.jsp" %>
+
+</html:form>
+
+<!-- Standard Footer -->
+
+<%@ include file="footer.jsp" %>
+
+</body>
+
+</html:html>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/users/users.jspf
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/users/users.jspf	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/users/users.jspf	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,46 @@
+<%-- Users List --%>
+
+<table class="back-table" border="0" cellspacing="0" cellpadding="1"
+       width="100%"><tr><td> 
+
+  <table class="front-table" border="1"
+   cellspacing="0" cellpadding="0" width="100%">
+    <tr class="header-row">
+      <logic:present name="checkboxes">
+        <td width="5%"><div align="left" class="table-header-text">
+          &nbsp;
+        </td>
+      </logic:present>
+      <th scope="col" width="20%"><div align="left" class="table-header-text">
+        <bean:message key="users.list.username"/>
+      </div></th>
+      <th scope="col"><div align="left" class="table-header-text">
+        <bean:message key="users.list.fullName"/>
+      </div></th>
+    </tr>
+    <logic:iterate name="usersForm" property="users"
+                     id="user" type="java.lang.String">
+      <tr class="line-row">
+        <logic:present name="checkboxes">
+          <td scope="row"><div align="center" class="table-normal-text">
+            <label for="users"></label>
+            <input type="checkbox" name="users"
+                  value='<%= user %>' styleId="users">
+          </td>
+        </logic:present>
+        <td scope="row"><div align="left" class="table-normal-text">&nbsp;
+          <html:link page='<%= "/users/setUpUser.do?objectName=" + 
+                               URLEncoder.encode(user,"UTF-8") +
+                               "&databaseName=" +
+                               URLEncoder.encode(request.getParameter("databaseName"),"UTF-8") %>'>
+            <controls:attribute name="user" attribute="username"/>
+          </html:link>
+        </div></td>
+        <td scope="row"><div align="left" class="table-normal-text">&nbsp;
+          <controls:attribute name="user" attribute="fullName"/>
+        </div></td>
+      </tr>
+    </logic:iterate>
+  </table>
+
+</td></tr></table>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/valve/accessLogValve.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/valve/accessLogValve.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/valve/accessLogValve.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,153 @@
+<!-- Standard Struts Entries -->
+<%@ page language="java" import="java.net.URLEncoder" contentType="text/html;charset=utf-8" %>
+<%@ taglib uri="http://struts.apache.org/tags-bean" prefix="bean" %>
+<%@ taglib uri="http://struts.apache.org/tags-html" prefix="html" %>
+<%@ taglib uri="/WEB-INF/controls.tld" prefix="controls" %>
+<%@ taglib uri="http://struts.apache.org/tags-logic" prefix="logic" %>
+
+<html:html locale="true">
+
+<%@ include file="../users/header.jsp" %>
+
+<!-- Body -->
+<body bgcolor="white" background="../images/PaperTexture.gif">
+
+<!--Form -->
+
+<html:errors/>
+
+<html:form method="POST" action="/SaveAccessLogValve">
+
+  <bean:define id="thisObjectName" type="java.lang.String"
+               name="accessLogValveForm" property="objectName"/>
+  <bean:define id="thisParentName" type="java.lang.String"
+               name="accessLogValveForm" property="parentObjectName"/>
+  <html:hidden property="adminAction"/>
+  <html:hidden property="parentObjectName"/>
+  <html:hidden property="objectName"/>
+  <html:hidden property="valveType"/>
+
+  <table width="100%" border="0" cellspacing="0" cellpadding="0">
+    <tr bgcolor="7171A5">
+      <td width="81%">
+       <div class="page-title-text" align="left">
+         <logic:equal name="accessLogValveForm" property="adminAction" value="Create">
+            <bean:message key="actions.valves.create"/>
+          </logic:equal>
+          <logic:equal name="accessLogValveForm" property="adminAction" value="Edit">
+            <bean:write name="accessLogValveForm" property="nodeLabel"/>
+          </logic:equal>
+       </div>
+      </td>
+      <td align="right" nowrap>
+        <div class="page-title-text">
+      <controls:actions label="Valve Actions">
+            <controls:action selected="true"> ----<bean:message key="actions.available.actions"/>---- </controls:action>
+            <controls:action> --------------------------------- </controls:action>
+            <logic:notEqual name="accessLogValveForm" property="adminAction" value="Create">
+             <controls:action url='<%= "/DeleteValve.do?"  +
+                                 "select=" + URLEncoder.encode(thisObjectName,"UTF-8") +
+                                 "&parent="+ URLEncoder.encode(thisParentName,"UTF-8") %>'>
+                <bean:message key="actions.valves.delete"/>
+              </controls:action>
+             </logic:notEqual>
+       </controls:actions>
+         </div>
+      </td>
+    </tr>
+  </table>
+    <%@ include file="../buttons.jsp" %>
+  <br>
+
+ <%-- Access Log Properties --%>
+ <table border="0" cellspacing="0" cellpadding="0" width="100%">
+    <tr> <td> <div class="table-title-text">
+        <bean:message key="valve.access.properties"/>
+    </div> </td> </tr>
+  </table>
+
+  <table class="back-table" border="0" cellspacing="0" cellpadding="0" width="100%">
+    <tr>
+      <td>
+       <controls:table tableStyle="front-table" lineStyle="line-row">
+            <controls:row header="true"
+                labelStyle="table-header-text" dataStyle="table-header-text">
+            <controls:label><bean:message key="service.property"/></controls:label>
+            <controls:data><bean:message key="service.value"/></controls:data>
+        </controls:row>
+
+      <controls:row labelStyle="table-label-text" dataStyle="table-normal-text" styleId="type">
+            <controls:label><bean:message key="connector.type"/>:</controls:label>
+            <controls:data>
+                 <logic:equal name="accessLogValveForm" property="adminAction" value="Create">
+                    <html:select property="valveType" onchange="IA_jumpMenu('self',this)" styleId="type">
+                     <bean:define id="valveTypeVals" name="accessLogValveForm" property="valveTypeVals"/>
+                     <html:options collection="valveTypeVals" property="value" labelProperty="label"/>
+                    </html:select>
+                </logic:equal>
+                <logic:equal name="accessLogValveForm" property="adminAction" value="Edit">
+                  <bean:write name="accessLogValveForm" property="valveType" scope="session"/>
+                </logic:equal>
+            </controls:data>
+        </controls:row>
+
+        <controls:row labelStyle="table-label-text" dataStyle="table-normal-text" styleId="directory">
+            <controls:label><bean:message key="logger.directory"/>:</controls:label>
+            <controls:data>
+              <html:text property="directory" size="30" styleId="directory"/>
+            </controls:data>
+        </controls:row>
+
+        <controls:row labelStyle="table-label-text" dataStyle="table-normal-text" styleId="pattern">
+            <controls:label><bean:message key="valve.pattern"/>:</controls:label>
+            <controls:data>
+                <html:textarea property="pattern" cols="30" rows="2" styleId="pattern"/>
+            </controls:data>
+        </controls:row>
+
+        <controls:row labelStyle="table-label-text" dataStyle="table-normal-text" styleId="prefix">
+            <controls:label><bean:message key="logger.prefix"/>:</controls:label>
+            <controls:data>
+                <html:text property="prefix" size="30" styleId="prefix"/>
+            </controls:data>
+        </controls:row>
+
+        <controls:row labelStyle="table-label-text" dataStyle="table-normal-text" styleId="resolveHosts">
+            <controls:label><bean:message key="valve.resolveHosts"/>:</controls:label>
+            <controls:data>
+                <html:select property="resolveHosts" styleId="resolveHosts">
+                     <bean:define id="booleanVals" name="accessLogValveForm" property="booleanVals"/>
+                     <html:options collection="booleanVals" property="value"
+                   labelProperty="label"/>
+                </html:select>
+            </controls:data>
+        </controls:row>
+
+        <controls:row labelStyle="table-label-text" dataStyle="table-normal-text" styleId="rotatable">
+            <controls:label><bean:message key="valve.rotatable"/>:</controls:label>
+            <controls:data>
+                <html:select property="rotatable" styleId="rotatable">
+                     <bean:define id="booleanVals" name="accessLogValveForm" property="booleanVals"/>
+                     <html:options collection="booleanVals" property="value"
+                   labelProperty="label"/>
+                </html:select>
+            </controls:data>
+        </controls:row>
+        
+        <controls:row labelStyle="table-label-text" dataStyle="table-normal-text" styleId="suffix">
+            <controls:label><bean:message key="logger.suffix"/>:</controls:label>
+            <controls:data>
+                <html:text property="suffix" size="30" styleId="suffix"/>
+            </controls:data>
+        </controls:row>
+
+      </controls:table>
+      </td>
+    </tr>
+  </table>
+    <%@ include file="../buttons.jsp" %>
+  <br>
+  </html:form>
+<p>&nbsp;</p>
+</body>
+</html:html>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/valve/remoteAddrValve.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/valve/remoteAddrValve.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/valve/remoteAddrValve.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,117 @@
+<!-- Standard Struts Entries -->
+<%@ page language="java" import="java.net.URLEncoder" contentType="text/html;charset=utf-8" %>
+<%@ taglib uri="http://struts.apache.org/tags-bean" prefix="bean" %>
+<%@ taglib uri="http://struts.apache.org/tags-html" prefix="html" %>
+<%@ taglib uri="/WEB-INF/controls.tld" prefix="controls" %>
+<%@ taglib uri="http://struts.apache.org/tags-logic" prefix="logic" %>
+
+<html:html locale="true">
+
+<%@ include file="../users/header.jsp" %>
+
+<!-- Body -->
+<body bgcolor="white" background="../images/PaperTexture.gif">
+
+<!--Form -->
+
+<html:errors/>
+
+<html:form method="POST" action="/SaveRemoteAddrValve">
+
+  <bean:define id="thisObjectName" type="java.lang.String"
+               name="remoteAddrValveForm" property="objectName"/>
+  <bean:define id="thisParentName" type="java.lang.String"
+               name="remoteAddrValveForm" property="parentObjectName"/>
+  <html:hidden property="adminAction"/>
+  <html:hidden property="parentObjectName"/>
+  <html:hidden property="objectName"/>
+  <html:hidden property="valveType"/>
+
+  <table width="100%" border="0" cellspacing="0" cellpadding="0">
+    <tr bgcolor="7171A5">
+      <td width="81%">
+       <div class="page-title-text" align="left">
+         <logic:equal name="remoteAddrValveForm" property="adminAction" value="Create">
+            <bean:message key="actions.valves.create"/>
+          </logic:equal>
+          <logic:equal name="remoteAddrValveForm" property="adminAction" value="Edit">
+            <bean:write name="remoteAddrValveForm" property="nodeLabel"/>
+          </logic:equal>
+       </div>
+      </td>
+      <td align="right" nowrap>
+        <div class="page-title-text">
+      <controls:actions label="Valve Actions">
+            <controls:action selected="true"> ----<bean:message key="actions.available.actions"/>---- </controls:action>
+            <controls:action> --------------------------------- </controls:action>
+            <logic:notEqual name="remoteAddrValveForm" property="adminAction" value="Create">
+             <controls:action url='<%= "/DeleteValve.do?"  +
+                                 "select=" + URLEncoder.encode(thisObjectName,"UTF-8") +
+                                 "&parent="+ URLEncoder.encode(thisParentName,"UTF-8") %>'>
+                <bean:message key="actions.valves.delete"/>
+              </controls:action>
+             </logic:notEqual>
+       </controls:actions>
+         </div>
+      </td>
+    </tr>
+  </table>
+    <%@ include file="../buttons.jsp" %>
+  <br>
+
+ <%-- Remote Addr Valve Properties --%>
+ <table border="0" cellspacing="0" cellpadding="0" width="100%">
+    <tr> <td> <div class="table-title-text">
+        <bean:message key="valve.remoteaddress.properties"/>
+    </div> </td> </tr>
+  </table>
+
+  <table class="back-table" border="0" cellspacing="0" cellpadding="0" width="100%">
+    <tr>
+      <td>
+       <controls:table tableStyle="front-table" lineStyle="line-row">
+            <controls:row header="true"
+                labelStyle="table-header-text" dataStyle="table-header-text">
+            <controls:label><bean:message key="service.property"/></controls:label>
+            <controls:data><bean:message key="service.value"/></controls:data>
+        </controls:row>
+
+      <controls:row labelStyle="table-label-text" dataStyle="table-normal-text" styleId="type">
+            <controls:label><bean:message key="connector.type"/>:</controls:label>
+            <controls:data>
+                 <logic:equal name="remoteAddrValveForm" property="adminAction" value="Create">
+                    <html:select property="valveType" onchange="IA_jumpMenu('self',this)" styleId="type">
+                     <bean:define id="valveTypeVals" name="remoteAddrValveForm" property="valveTypeVals"/>
+                     <html:options collection="valveTypeVals" property="value" labelProperty="label"/>
+                    </html:select>
+                </logic:equal>
+                <logic:equal name="remoteAddrValveForm" property="adminAction" value="Edit">
+                  <bean:write name="remoteAddrValveForm" property="valveType" scope="session"/>
+                </logic:equal>
+            </controls:data>
+        </controls:row>
+
+        <controls:row labelStyle="table-label-text" dataStyle="table-normal-text" styleId="allowIPs">
+            <controls:label><bean:message key="valve.allowIPs"/>:</controls:label>
+            <controls:data>
+                <html:textarea property="allow" cols="30" rows="3" styleId="allowIPs"/>
+            </controls:data>
+        </controls:row>
+
+        <controls:row labelStyle="table-label-text" dataStyle="table-normal-text" styleId="denyIPs">
+            <controls:label><bean:message key="valve.denyIPs"/>:</controls:label>
+            <controls:data>
+                <html:textarea property="deny" cols="30" rows="3" styleId="denyIPs"/>
+            </controls:data>
+        </controls:row>
+
+      </controls:table>
+      </td>
+    </tr>
+  </table>
+    <%@ include file="../buttons.jsp" %>
+  <br>
+  </html:form>
+<p>&nbsp;</p>
+</body>
+</html:html>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/valve/remoteHostValve.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/valve/remoteHostValve.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/valve/remoteHostValve.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,117 @@
+<!-- Standard Struts Entries -->
+<%@ page language="java" import="java.net.URLEncoder" contentType="text/html;charset=utf-8" %>
+<%@ taglib uri="http://struts.apache.org/tags-bean" prefix="bean" %>
+<%@ taglib uri="http://struts.apache.org/tags-html" prefix="html" %>
+<%@ taglib uri="/WEB-INF/controls.tld" prefix="controls" %>
+<%@ taglib uri="http://struts.apache.org/tags-logic" prefix="logic" %>
+
+<html:html locale="true">
+
+<%@ include file="../users/header.jsp" %>
+
+<!-- Body -->
+<body bgcolor="white" background="../images/PaperTexture.gif">
+
+<!--Form -->
+
+<html:errors/>
+
+<html:form method="POST" action="/SaveRemoteHostValve">
+
+  <bean:define id="thisObjectName" type="java.lang.String"
+               name="remoteHostValveForm" property="objectName"/>
+  <bean:define id="thisParentName" type="java.lang.String"
+               name="remoteHostValveForm" property="parentObjectName"/>
+  <html:hidden property="adminAction"/>
+  <html:hidden property="parentObjectName"/>
+  <html:hidden property="objectName"/>
+  <html:hidden property="valveType"/>
+
+  <table width="100%" border="0" cellspacing="0" cellpadding="0">
+    <tr bgcolor="7171A5">
+      <td width="81%">
+       <div class="page-title-text" align="left">
+         <logic:equal name="remoteHostValveForm" property="adminAction" value="Create">
+            <bean:message key="actions.valves.create"/>
+          </logic:equal>
+          <logic:equal name="remoteHostValveForm" property="adminAction" value="Edit">
+            <bean:write name="remoteHostValveForm" property="nodeLabel"/>
+          </logic:equal>
+       </div>
+      </td>
+      <td align="right" nowrap>
+        <div class="page-title-text">
+      <controls:actions label="Valve Actions">
+            <controls:action selected="true"> ----<bean:message key="actions.available.actions"/>---- </controls:action>
+            <controls:action> --------------------------------- </controls:action>
+            <logic:notEqual name="remoteHostValveForm" property="adminAction" value="Create">
+             <controls:action url='<%= "/DeleteValve.do?"  +
+                                 "select=" + URLEncoder.encode(thisObjectName,"UTF-8") +
+                                 "&parent="+ URLEncoder.encode(thisParentName,"UTF-8") %>'>
+                <bean:message key="actions.valves.delete"/>
+              </controls:action>
+              </logic:notEqual>
+       </controls:actions>
+         </div>
+      </td>
+    </tr>
+  </table>
+    <%@ include file="../buttons.jsp" %>
+  <br>
+
+ <%-- RemoteHost Valve Properties --%>
+ <table border="0" cellspacing="0" cellpadding="0" width="100%">
+    <tr> <td> <div class="table-title-text">
+        <bean:message key="valve.remotehost.properties"/>
+    </div> </td> </tr>
+  </table>
+
+  <table class="back-table" border="0" cellspacing="0" cellpadding="0" width="100%">
+    <tr>
+      <td>
+       <controls:table tableStyle="front-table" lineStyle="line-row">
+            <controls:row header="true"
+                labelStyle="table-header-text" dataStyle="table-header-text">
+            <controls:label><bean:message key="service.property"/></controls:label>
+            <controls:data><bean:message key="service.value"/></controls:data>
+        </controls:row>
+
+      <controls:row labelStyle="table-label-text" dataStyle="table-normal-text" styleId="type">
+            <controls:label><bean:message key="connector.type"/>:</controls:label>
+            <controls:data>
+                 <logic:equal name="remoteHostValveForm" property="adminAction" value="Create">
+                    <html:select property="valveType" onchange="IA_jumpMenu('self',this)" styleId="type">
+                     <bean:define id="valveTypeVals" name="remoteHostValveForm" property="valveTypeVals"/>
+                     <html:options collection="valveTypeVals" property="value" labelProperty="label"/>
+                    </html:select>
+                </logic:equal>
+                <logic:equal name="remoteHostValveForm" property="adminAction" value="Edit">
+                  <bean:write name="remoteHostValveForm" property="valveType" scope="session"/>
+                </logic:equal>
+            </controls:data>
+        </controls:row>
+
+        <controls:row labelStyle="table-label-text" dataStyle="table-normal-text" styleId="allowHosts">
+            <controls:label><bean:message key="valve.allowHosts"/>:</controls:label>
+            <controls:data>
+                <html:textarea property="allow" cols="30" rows="3" styleId="allowHosts"/>
+            </controls:data>
+        </controls:row>
+
+        <controls:row labelStyle="table-label-text" dataStyle="table-normal-text" styleId="denyHosts">
+            <controls:label><bean:message key="valve.denyHosts"/>:</controls:label>
+            <controls:data>
+                <html:textarea property="deny" cols="30" rows="3" styleId="denyHosts"/>
+            </controls:data>
+        </controls:row>
+
+      </controls:table>
+      </td>
+    </tr>
+  </table>
+    <%@ include file="../buttons.jsp" %>
+  <br>
+  </html:form>
+<p>&nbsp;</p>
+</body>
+</html:html>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/valve/requestDumperValve.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/valve/requestDumperValve.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/valve/requestDumperValve.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,104 @@
+<!-- Standard Struts Entries -->
+<%@ page language="java" import="java.net.URLEncoder" contentType="text/html;charset=utf-8" %>
+<%@ taglib uri="http://struts.apache.org/tags-bean" prefix="bean" %>
+<%@ taglib uri="http://struts.apache.org/tags-html" prefix="html" %>
+<%@ taglib uri="/WEB-INF/controls.tld" prefix="controls" %>
+<%@ taglib uri="http://struts.apache.org/tags-logic" prefix="logic" %>
+
+<html:html locale="true">
+
+<%@ include file="../users/header.jsp" %>
+
+<!-- Body -->
+<body bgcolor="white" background="../images/PaperTexture.gif">
+
+<!--Form -->
+
+<html:errors/>
+
+<html:form method="POST" action="/SaveRequestDumperValve">
+
+  <bean:define id="thisObjectName" type="java.lang.String"
+               name="requestDumperValveForm" property="objectName"/>
+  <bean:define id="thisParentName" type="java.lang.String"
+               name="requestDumperValveForm" property="parentObjectName"/>
+  <html:hidden property="adminAction"/>
+  <html:hidden property="parentObjectName"/>
+  <html:hidden property="objectName"/>
+  <html:hidden property="valveType"/>
+
+  <table width="100%" border="0" cellspacing="0" cellpadding="0">
+    <tr bgcolor="7171A5">
+      <td width="81%">
+       <div class="page-title-text" align="left">
+         <logic:equal name="requestDumperValveForm" property="adminAction" value="Create">
+            <bean:message key="actions.valves.create"/>
+          </logic:equal>
+          <logic:equal name="requestDumperValveForm" property="adminAction" value="Edit">
+            <bean:write name="requestDumperValveForm" property="nodeLabel"/>
+          </logic:equal>
+       </div>
+      </td>
+      <td align="right" nowrap>
+        <div class="page-title-text">
+      <controls:actions label="Valve Actions">
+            <controls:action selected="true"> ----<bean:message key="actions.available.actions"/>---- </controls:action>
+            <controls:action> --------------------------------- </controls:action>
+            <logic:notEqual name="requestDumperValveForm" property="adminAction" value="Create">
+             <controls:action url='<%= "/DeleteValve.do?"  +
+                                 "select=" + URLEncoder.encode(thisObjectName,"UTF-8") +
+                                 "&parent="+ URLEncoder.encode(thisParentName,"UTF-8") %>'>
+                <bean:message key="actions.valves.delete"/>
+              </controls:action>
+              </logic:notEqual>
+       </controls:actions>
+         </div>
+      </td>
+    </tr>
+  </table>
+
+    <%@ include file="../buttons.jsp" %>
+  <br>
+
+ <%-- Request Dumper Valve Properties --%>
+ <table border="0" cellspacing="0" cellpadding="0" width="100%">
+    <tr> <td> <div class="table-title-text">
+        <bean:message key="valve.request.properties"/>
+    </div> </td> </tr>
+  </table>
+
+  <table class="back-table" border="0" cellspacing="0" cellpadding="0" width="100%">
+    <tr>
+      <td>
+       <controls:table tableStyle="front-table" lineStyle="line-row">
+            <controls:row header="true"
+                labelStyle="table-header-text" dataStyle="table-header-text">
+            <controls:label><bean:message key="service.property"/></controls:label>
+            <controls:data><bean:message key="service.value"/></controls:data>
+        </controls:row>
+
+      <controls:row labelStyle="table-label-text" dataStyle="table-normal-text" styleId="type">
+            <controls:label><bean:message key="connector.type"/>:</controls:label>
+            <controls:data>
+                 <logic:equal name="requestDumperValveForm" property="adminAction" value="Create">
+                    <html:select property="valveType" onchange="IA_jumpMenu('self',this)" styleId="type">
+                     <bean:define id="valveTypeVals" name="requestDumperValveForm" property="valveTypeVals"/>
+                     <html:options collection="valveTypeVals" property="value" labelProperty="label"/>
+                    </html:select>
+                </logic:equal>
+                <logic:equal name="requestDumperValveForm" property="adminAction" value="Edit">
+                  <bean:write name="requestDumperValveForm" property="valveType" scope="session"/>
+                </logic:equal>
+            </controls:data>
+        </controls:row>
+
+      </controls:table>
+      </td>
+    </tr>
+  </table>
+    <%@ include file="../buttons.jsp" %>
+  <br>
+  </html:form>
+<p>&nbsp;</p>
+</body>
+</html:html>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/valve/singleSignOnValve.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/valve/singleSignOnValve.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/valve/singleSignOnValve.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,103 @@
+<!-- Standard Struts Entries -->
+<%@ page language="java" import="java.net.URLEncoder" contentType="text/html;charset=utf-8" %>
+<%@ taglib uri="http://struts.apache.org/tags-bean" prefix="bean" %>
+<%@ taglib uri="http://struts.apache.org/tags-html" prefix="html" %>
+<%@ taglib uri="/WEB-INF/controls.tld" prefix="controls" %>
+<%@ taglib uri="http://struts.apache.org/tags-logic" prefix="logic" %>
+
+<html:html locale="true">
+
+<%@ include file="../users/header.jsp" %>
+
+<!-- Body -->
+<body bgcolor="white" background="../images/PaperTexture.gif">
+
+<!--Form -->
+
+<html:errors/>
+
+<html:form method="POST" action="/SaveSingleSignOn">
+
+  <bean:define id="thisObjectName" type="java.lang.String"
+               name="singleSignOnValveForm" property="objectName"/>
+  <bean:define id="thisParentName" type="java.lang.String"
+               name="singleSignOnValveForm" property="parentObjectName"/>
+  <html:hidden property="adminAction"/>
+  <html:hidden property="parentObjectName"/>
+  <html:hidden property="objectName"/>
+  <html:hidden property="valveType"/>
+
+  <table width="100%" border="0" cellspacing="0" cellpadding="0">
+    <tr bgcolor="7171A5">
+      <td width="81%">
+       <div class="page-title-text" align="left">
+         <logic:equal name="singleSignOnValveForm" property="adminAction" value="Create">
+            <bean:message key="actions.valves.create"/>
+          </logic:equal>
+          <logic:equal name="singleSignOnValveForm" property="adminAction" value="Edit">
+            <bean:write name="singleSignOnValveForm" property="nodeLabel"/>
+          </logic:equal>
+       </div>
+      </td>
+      <td align="right" nowrap>
+        <div class="page-title-text">
+      <controls:actions label="Valve Actions">
+            <controls:action selected="true"> ----<bean:message key="actions.available.actions"/>---- </controls:action>
+            <controls:action> --------------------------------- </controls:action>
+            <logic:notEqual name="singleSignOnValveForm" property="adminAction" value="Create">
+             <controls:action url='<%= "/DeleteValve.do?"  +
+                                 "select=" + URLEncoder.encode(thisObjectName,"UTF-8") +
+                                 "&parent="+ URLEncoder.encode(thisParentName,"UTF-8") %>'>
+                <bean:message key="actions.valves.delete"/>
+              </controls:action>
+              </logic:notEqual>
+       </controls:actions>
+         </div>
+      </td>
+    </tr>
+  </table>
+    <%@ include file="../buttons.jsp" %>
+  <br>
+
+ <%-- Single Sign On Valve Properties --%>
+ <table border="0" cellspacing="0" cellpadding="0" width="100%">
+    <tr> <td> <div class="table-title-text">
+        <bean:message key="valve.single.properties"/>
+    </div> </td> </tr>
+  </table>
+
+  <table class="back-table" border="0" cellspacing="0" cellpadding="0" width="100%">
+    <tr>
+      <td>
+       <controls:table tableStyle="front-table" lineStyle="line-row">
+            <controls:row header="true"
+                labelStyle="table-header-text" dataStyle="table-header-text">
+            <controls:label><bean:message key="service.property"/></controls:label>
+            <controls:data><bean:message key="service.value"/></controls:data>
+        </controls:row>
+
+      <controls:row labelStyle="table-label-text" dataStyle="table-normal-text" styleId="type">
+            <controls:label><bean:message key="connector.type"/>:</controls:label>
+            <controls:data>
+                 <logic:equal name="singleSignOnValveForm" property="adminAction" value="Create">
+                    <html:select property="valveType" onchange="IA_jumpMenu('self',this)" styleId="type">
+                     <bean:define id="valveTypeVals" name="singleSignOnValveForm" property="valveTypeVals"/>
+                     <html:options collection="valveTypeVals" property="value" labelProperty="label"/>
+                    </html:select>
+                </logic:equal>
+                <logic:equal name="singleSignOnValveForm" property="adminAction" value="Edit">
+                  <bean:write name="singleSignOnValveForm" property="valveType" scope="session"/>
+                </logic:equal>
+            </controls:data>
+        </controls:row>
+
+      </controls:table>
+      </td>
+    </tr>
+  </table>
+    <%@ include file="../buttons.jsp" %>
+  <br>
+  </html:form>
+<p>&nbsp;</p>
+</body>
+</html:html>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/valve/valves.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/valve/valves.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/admin/valve/valves.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,97 @@
+<!-- Standard Struts Entries -->
+<%@ page language="java" import="java.net.URLEncoder" contentType="text/html;charset=utf-8" %>
+<%@ taglib uri="http://struts.apache.org/tags-bean" prefix="bean" %>
+<%@ taglib uri="http://struts.apache.org/tags-html" prefix="html" %>
+<%@ taglib uri="http://struts.apache.org/tags-logic" prefix="logic" %>
+<%@ taglib uri="/WEB-INF/controls.tld" prefix="controls" %>
+
+<html:html locale="true">
+
+<%@ include file="../users/header.jsp" %>
+
+<!-- Body -->
+<body bgcolor="white" background="../images/PaperTexture.gif">
+
+<!--Form -->
+
+<html:errors/>
+
+<html:form method="post" action="/DeleteValves">
+
+  <bean:define id="thisParentName" type="java.lang.String"
+               name="valvesForm" property="parentObjectName"/>
+  <html:hidden property="parentObjectName"/>
+
+  <table width="100%" border="0" cellspacing="0" cellpadding="0">
+    <tr bgcolor="7171A5">
+      <td width="81%">
+        <div class="page-title-text" align="left">
+          <bean:message key="actions.valves.delete"/>
+        </div>
+      </td>
+      <td align="right" nowrap>
+        <div class="page-title-text">
+            <controls:actions label="Valve Actions">
+              <controls:action selected="true">
+                ----<bean:message key="actions.available.actions"/>----
+              </controls:action>
+              <controls:action disabled="true">
+                ---------------------------------
+              </controls:action>
+            </controls:actions>
+        </div>
+      </td>
+    </tr>
+  </table>
+
+<%@ include file="../buttons.jsp" %>
+  <br>
+
+  <%-- Valves List --%>
+
+  <table class="back-table" border="0" cellspacing="0" cellpadding="1"
+         width="100%">
+    <tr><td>
+
+      <table class="front-table" border="1"
+       cellspacing="0" cellpadding="0" width="100%">
+
+        <tr class="header-row">
+          <td><div align="left" class="table-header-text">
+            <bean:message key="actions.delete"/>
+          </div></td>
+          <td><div align="left" class="table-header-text">
+            <bean:message key="host.name"/>
+          </div></td>
+        </tr>
+
+        <logic:iterate name="valvesList" id="valve">
+          <tr class="line-row">
+            <td><div align="left" class="table-normal-text">&nbsp;
+            <label for="valves"></label>
+              <html:multibox property="valves"
+                                value="<%= valve.toString() %>" styleId="valves"/>
+            </div></td>
+            <td><div align="left" class="table-normal-text">&nbsp;
+              <html:link page='<%= "/EditValve.do?select=" +
+                         java.net.URLEncoder.encode(valve.toString(),"UTF-8") +
+                         "&parent="+ URLEncoder.encode(thisParentName,"UTF-8") %>'>
+                <controls:attribute name="valve" attribute="className"/>
+              </html:link>
+            </div></td>
+          </tr>
+        </logic:iterate>
+
+      </table>
+
+    </td></tr>
+  </table>
+
+<%@ include file="../buttons.jsp" %>
+
+  <br>
+</html:form>
+
+<p>&nbsp;</p>
+</body>
+</html:html>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/balancer/META-INF/context.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/balancer/META-INF/context.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/balancer/META-INF/context.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,12 @@
+<!--
+
+    Context configuration file for the Tomcat Balancer Web App
+    This is only needed to keep the distribution small and avoid duplicating
+    commons libraries
+
+    $Id: context.xml 303123 2004-08-26 17:03:35Z remm $
+
+-->
+
+
+<Context privileged="true" antiResourceLocking="false" antiJARLocking="false" />

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/balancer/WEB-INF/classes/org/apache/webapp/balancer/BalancerFilter.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/balancer/WEB-INF/classes/org/apache/webapp/balancer/BalancerFilter.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/balancer/WEB-INF/classes/org/apache/webapp/balancer/BalancerFilter.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,146 @@
+/*
+ * Copyright 2000,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.balancer;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import java.net.URL;
+
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+
+/**
+ * The balancer filter redirects incoming requests
+ * based on what rules they match.  The rules
+ * are configurable via an XML document whose URL
+ * is specified as an init-param to this filter.
+ *
+ * @author Yoav Shapira
+ */
+public class BalancerFilter implements Filter {
+    /**
+     * The rules this filter consults.
+     */
+    private RuleChain ruleChain;
+
+    /**
+     * The servlet context.
+     */
+    private ServletContext context;
+
+    /**
+     * Returns the rule chain.
+     *
+     * @return The rule chain
+     */
+    protected RuleChain getRuleChain() {
+        return ruleChain;
+    }
+
+    /**
+     * Initialize this filter.
+     *
+     * @param filterConfig The filter config
+     * @throws ServletException If an error occurs
+     */
+    public void init(FilterConfig filterConfig) throws ServletException {
+        context = filterConfig.getServletContext();
+
+        String configUrlParam = filterConfig.getInitParameter("configUrl");
+
+        if (configUrlParam == null) {
+            throw new ServletException("configUrl is required.");
+        }
+
+        try {
+            InputStream input = context.getResourceAsStream(configUrlParam);
+            RulesParser parser = new RulesParser(input);
+            ruleChain = parser.getResult();
+            context.log(
+                getClass().getName() + ": init(): ruleChain: " + ruleChain);
+        } catch (Exception e) {
+            throw new ServletException(e);
+        }
+    }
+
+    /**
+     * Filter the incoming request.
+     * Consults the rule chain to see if
+     * any rules match this request, and if
+     * so redirects.  Otherwise simply
+     * let request through.
+     *
+     * @param request The request
+     * @param response The response
+     * @param chain The filter chain
+     * @throws IOException If an error occurs
+     * @throws ServletException If an error occurs
+     */
+    public void doFilter(
+        ServletRequest request, ServletResponse response, FilterChain chain)
+        throws IOException, ServletException {
+        if (response.isCommitted()) {
+            context.log(
+                getClass().getName()
+                + ": doFilter(): not inspecting committed response.");
+            chain.doFilter(request, response);
+        } else if (!(request instanceof HttpServletRequest)) {
+            context.log(
+                getClass().getName()
+                + ": doFilter(): not inspecting non-Http request.");
+            chain.doFilter(request, response);
+        } else {
+            HttpServletRequest hreq = (HttpServletRequest) request;
+            HttpServletResponse hres = (HttpServletResponse) response;
+
+            URL redirectUrl = getRuleChain().evaluate(hreq);
+
+            if (redirectUrl != null) {
+                String encoded =
+                    hres.encodeRedirectURL(redirectUrl.toString());
+
+                context.log(
+                    getClass().getName()
+                    + ": doFilter(): redirecting request for "
+                    + hreq.getRequestURL().toString() + " to " + encoded);
+
+                hres.sendRedirect(encoded);
+            } else {
+                chain.doFilter(request, response);
+            }
+        }
+    }
+
+    /**
+     * Destroy this filter.
+     */
+    public void destroy() {
+        context = null;
+        ruleChain = null;
+    }
+}
+
+
+// End of file: BalanceFilter.java

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/balancer/WEB-INF/classes/org/apache/webapp/balancer/Rule.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/balancer/WEB-INF/classes/org/apache/webapp/balancer/Rule.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/balancer/WEB-INF/classes/org/apache/webapp/balancer/Rule.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2000,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.balancer;
+
+import javax.servlet.http.HttpServletRequest;
+
+
+/**
+ * The Rule interface is implemented by
+ * load balancing rules.
+ *
+ * @author Yoav Shapira
+ */
+public interface Rule {
+    /**
+     * Determine if the given request
+     * matches the rule.
+     *
+     * @param request The request
+     * @return boolean True if matches, will be redirected.
+     */
+    boolean matches(HttpServletRequest request);
+
+    /**
+     * Returns the redirect URL for
+     * requests that match this rule.
+     *
+     * @return The redirect URL
+     */
+    String getRedirectUrl();
+}
+
+
+// End of file: Rule.java

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/balancer/WEB-INF/classes/org/apache/webapp/balancer/RuleChain.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/balancer/WEB-INF/classes/org/apache/webapp/balancer/RuleChain.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/balancer/WEB-INF/classes/org/apache/webapp/balancer/RuleChain.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,145 @@
+/*
+ * Copyright 2000,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.balancer;
+
+import java.net.URL;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import javax.servlet.http.HttpServletRequest;
+
+
+/**
+ * A RuleChain is a list of rules
+ * considered in order.  The first
+ * rule to succeed stops the evaluation
+ * of rules.
+ *
+ * @author Yoav Shapira
+ */
+public class RuleChain {
+    /**
+     * The list of rules to evaluate.
+     */
+    private List rules;
+
+    /**
+     * Constructor.
+     */
+    public RuleChain() {
+        rules = new ArrayList();
+    }
+
+    /**
+     * Returns the list of rules
+     * to evaluate.
+     *
+     * @return List
+     */
+    protected List getRules() {
+        return rules;
+    }
+
+    /**
+     * Returns an iterator over
+     * the list of rules to evaluate.
+     *
+     * @return Iterator
+     */
+    protected Iterator getRuleIterator() {
+        return getRules().iterator();
+    }
+
+    /**
+     * Adds a rule to evaluate.
+     *
+     * @param theRule The rule to add
+     */
+    public void addRule(Rule theRule) {
+        if (theRule == null) {
+            throw new IllegalArgumentException("The rule cannot be null.");
+        } else {
+            getRules().add(theRule);
+        }
+    }
+
+    /**
+     * Evaluates the given request to see if
+     * any of the rules matches.  Returns the
+     * redirect URL for the first matching
+     * rule.  Returns null if no rules match
+     * the request.
+     *
+     * @param request The request
+     * @return URL The first matching rule URL
+     * @see Rule#matches(HttpServletRequest)
+     */
+    public URL evaluate(HttpServletRequest request) {
+        Iterator iter = getRuleIterator();
+
+        Rule currentRule = null;
+        boolean currentMatches = false;
+
+        while (iter.hasNext()) {
+            currentRule = (Rule) iter.next();
+            currentMatches = currentRule.matches(request);
+
+            if (currentMatches) {
+                try {
+                    return new URL(currentRule.getRedirectUrl());
+                } catch (Exception e) {
+                    throw new RuntimeException(e);
+                }
+            }
+        }
+
+        return null;
+    }
+
+    /**
+     * Returns a String representation of this object.
+     *
+     * @return String
+     */
+    public String toString() {
+        StringBuffer buffer = new StringBuffer();
+
+        buffer.append("[");
+        buffer.append(getClass().getName());
+        buffer.append(": ");
+
+        Iterator iter = getRuleIterator();
+        Rule currentRule = null;
+
+        while (iter.hasNext()) {
+            currentRule = (Rule) iter.next();
+            buffer.append(currentRule);
+
+            if (iter.hasNext()) {
+                buffer.append(", ");
+            }
+        }
+
+        buffer.append("]");
+
+        return buffer.toString();
+    }
+}
+
+
+// End of file: RuleChain.java

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/balancer/WEB-INF/classes/org/apache/webapp/balancer/RulesParser.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/balancer/WEB-INF/classes/org/apache/webapp/balancer/RulesParser.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/balancer/WEB-INF/classes/org/apache/webapp/balancer/RulesParser.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2000,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.balancer;
+
+import org.apache.tomcat.util.digester.Digester;
+
+import java.io.InputStream;
+
+
+/**
+ * The rules parser uses Digester
+ * to parse the rules definition
+ * file and return a RuleChain object.
+ *
+ * @author Yoav Shapira
+ */
+public class RulesParser {
+    /**
+     * The resulting rule chain.
+     */
+    private RuleChain result;
+
+    /**
+     * Constructor.
+     *
+     * @param input To read the configuration
+     */
+    public RulesParser(InputStream input) {
+        try {
+            Digester digester = createDigester();
+            result = (RuleChain) digester.parse(input);
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Returns the parsed rule chain.
+     *
+     * @return The resulting RuleChain
+     */
+    public RuleChain getResult() {
+        return result;
+    }
+
+    /**
+     * Creates the digester instance.
+     *
+     * @return Digester
+     */
+    protected Digester createDigester() {
+        Digester digester = new Digester();
+        digester.setUseContextClassLoader(true);
+
+        String rules = "rules";
+        String rule = "/rule";
+
+        // Construct rule chain
+        digester.addObjectCreate(rules, RuleChain.class);
+
+        // Construct rule
+        digester.addObjectCreate(rules + rule, null, "className");
+
+        // Set rule properties
+        digester.addSetProperties(rules + rule);
+
+        // Add rule to chain
+        digester.addSetNext(rules + rule, "addRule", "org.apache.webapp.balancer.Rule");
+
+        return digester;
+    }
+}
+
+
+// End of class: RulesParser.java

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/balancer/WEB-INF/classes/org/apache/webapp/balancer/overview.html
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/balancer/WEB-INF/classes/org/apache/webapp/balancer/overview.html	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/balancer/WEB-INF/classes/org/apache/webapp/balancer/overview.html	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,50 @@
+<html>
+<head>
+<title>Balancer Webapp Overview</title>
+</head>
+<body>
+The balancer webapp is an implementation of a rules-based
+load balancer.  A number of rules are provided and the
+application is written for easy extensibility.  
+
+<p>
+A servlet filter is also provided along with a sample web.xml that
+maps that filter to all requests.  This is only one way
+to use the load balancer.  The user may configure multiple
+filters each with a different rule chain mapped to 
+(possibly multiple) different url-patterns or servlets.  It
+is also possible to use rule chains within a servlet.
+</p>
+
+<p>
+Please note that although this application is being distributed
+with Tomcat, it is compliant with the Servlet Specification v2.3
+and is therefore portable across servlet containers that support
+this specification.
+</p>
+
+<p>
+The balancer webapps uses the 
+<a href="http://jakarta.apache.org/commons/digester">Digester</a> 
+tool from Jakarta Commons.  Digester and its dependencies are
+included in this distribution.
+</p>
+
+<p>
+The balancer webapp uses 
+<a href="http://jalopy.sf.net">Jalopy</a> 
+for source-code formatting and 
+<a href="http://checkstyle.sf.net">CheckStyle</a> 
+for source-code checking.
+<br/>
+The <a href="../checkStyle/checkStyleReport.html">
+CheckStyle Report</a> is available.
+</p>
+
+<p>
+Any suggestions, comments, etc, are welcome: please
+post them to the tomcat-user mailing list.  Enjoy ;)
+</p>
+
+</body>
+</html>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/balancer/WEB-INF/classes/org/apache/webapp/balancer/package.html
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/balancer/WEB-INF/classes/org/apache/webapp/balancer/package.html	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/balancer/WEB-INF/classes/org/apache/webapp/balancer/package.html	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,26 @@
+<html>
+<head>
+<title>org.apache.webapp.balancer Package Overview</title>
+</head>
+<body>
+This package contains all classes used by the balancer
+webapp other than actual rule implementations.
+<p>
+The {@link org.apache.webapp.balancer.BalancerFilter Filter} is how the webapp
+is typically used: see the web.xml file in this distribution
+for an example.
+</p>
+
+<p>
+A {@link org.apache.webapp.balancer.RuleChain} is simply a list of rules to be
+evaluated in order.
+</p>
+
+<p>
+The {@link org.apache.webapp.balancer.RulesParser} uses 
+<a href="http://jakarta.apache.org/commons/digester">Digester</a> 
+to parse the rules configuration file.
+</p>
+
+</body>
+</html>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/balancer/WEB-INF/classes/org/apache/webapp/balancer/rules/AcceptEverythingRule.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/balancer/WEB-INF/classes/org/apache/webapp/balancer/rules/AcceptEverythingRule.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/balancer/WEB-INF/classes/org/apache/webapp/balancer/rules/AcceptEverythingRule.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2000,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.balancer.rules;
+
+import javax.servlet.http.HttpServletRequest;
+
+
+/**
+ * This rule matches every request
+ * passed to it, making it suitable
+ * for use as a catch-all or last
+ * rule in a chain.
+ *
+ * @author Yoav Shapira
+ */
+public class AcceptEverythingRule extends BaseRule {
+    /**
+     * @see org.apache.webapp.balancer.Rule#matches(HttpServletRequest)
+     *
+     * This implementation always matches.
+     */
+    public boolean matches(HttpServletRequest request) {
+        return true;
+    }
+}
+
+
+// End of file: AcceptEverythingRule.java

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/balancer/WEB-INF/classes/org/apache/webapp/balancer/rules/BaseRule.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/balancer/WEB-INF/classes/org/apache/webapp/balancer/rules/BaseRule.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/balancer/WEB-INF/classes/org/apache/webapp/balancer/rules/BaseRule.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,111 @@
+/*
+ * Copyright 2000,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.balancer.rules;
+
+import org.apache.webapp.balancer.Rule;
+
+import javax.servlet.http.HttpServletRequest;
+
+
+/**
+ * The BaseRule is an empty rule
+ * implementation which can be
+ * subclassed for extension.
+ *
+ * @author Yoav Shapira
+ */
+public abstract class BaseRule implements Rule {
+    /**
+     * The rule name.
+     */
+    private String name;
+
+    /**
+     * The URL where matching
+     * requested will be redirected.
+     */
+    private String redirectUrl;
+
+    /**
+     * Sets the rule name.
+     *
+     * @param theName The rule name.
+     */
+    public void setName(String theName) {
+        if (theName == null) {
+            throw new IllegalArgumentException("The name cannot be null.");
+        } else {
+            name = theName;
+        }
+    }
+
+    /**
+     * Returns the rule name.
+     *
+     * @return String
+     */
+    protected String getName() {
+        return name;
+    }
+
+    /**
+     * @see Rule#getRedirectUrl
+     */
+    public String getRedirectUrl() {
+        return redirectUrl;
+    }
+
+    /**
+     * Sets the redirect URL.
+     *
+     * @param theRedirectUrl Where matching requests will be redirected
+     */
+    public void setRedirectUrl(String theRedirectUrl) {
+        if (theRedirectUrl == null) {
+            throw new IllegalArgumentException("redirectUrl may not be null.");
+        } else {
+            redirectUrl = theRedirectUrl;
+        }
+    }
+
+    /**
+     * @see Rule#matches(HttpServletRequest)
+     */
+    public abstract boolean matches(HttpServletRequest request);
+
+    /**
+     * Returns a String representation of this object.
+     *
+     * @return String
+     */
+    public String toString() {
+        StringBuffer buffer = new StringBuffer();
+
+        buffer.append("[");
+        buffer.append(getClass().getName());
+        buffer.append(": ");
+
+        buffer.append("Redirect URL: ");
+        buffer.append(getRedirectUrl());
+
+        buffer.append("]");
+
+        return buffer.toString();
+    }
+}
+
+
+// End of file: BaseRule.java

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/balancer/WEB-INF/classes/org/apache/webapp/balancer/rules/CharacterEncodingRule.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/balancer/WEB-INF/classes/org/apache/webapp/balancer/rules/CharacterEncodingRule.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/balancer/WEB-INF/classes/org/apache/webapp/balancer/rules/CharacterEncodingRule.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,75 @@
+package org.apache.webapp.balancer.rules;
+
+import javax.servlet.http.HttpServletRequest;
+
+
+/**
+ * This rule redirects requests if they
+ * are for a specific character encoding.
+ *
+ * @author Yoav Shapira
+ */
+public class CharacterEncodingRule extends BaseRule {
+    /**
+     * The character encoding.
+     */
+    private String encoding;
+
+    /**
+     * Sets the character encoding.
+     *
+     * @param theEncoding The encoding value
+     */
+    public void setEncoding(String theEncoding) {
+        if (theEncoding == null) {
+            throw new IllegalArgumentException("The encoding cannot be null.");
+        } else {
+            encoding = theEncoding;
+        }
+    }
+
+    /**
+     * Returns the desired encoding.
+     *
+     * @return String
+     */
+    protected String getEncoding() {
+        return encoding;
+    }
+
+    /**
+     * @see org.apache.webapp.balancer.Rule#matches(HttpServletRequest request)
+     */
+    public boolean matches(HttpServletRequest request) {
+        String actualEncoding = request.getCharacterEncoding();
+
+        return (getEncoding().compareTo(actualEncoding) == 0);
+    }
+
+    /**
+     * Returns a String representation of this object.
+     *
+     * @return String
+     */
+    public String toString() {
+        StringBuffer buffer = new StringBuffer();
+
+        buffer.append("[");
+        buffer.append(getClass().getName());
+        buffer.append(": ");
+
+        buffer.append("Target encoding: ");
+        buffer.append(getEncoding());
+        buffer.append(" / ");
+
+        buffer.append("Redirect URL: ");
+        buffer.append(getRedirectUrl());
+
+        buffer.append("]");
+
+        return buffer.toString();
+    }
+}
+
+
+// End of file: CharacterEncodingRule.java

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/balancer/WEB-INF/classes/org/apache/webapp/balancer/rules/RemoteAddressRule.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/balancer/WEB-INF/classes/org/apache/webapp/balancer/rules/RemoteAddressRule.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/balancer/WEB-INF/classes/org/apache/webapp/balancer/rules/RemoteAddressRule.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2000,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.balancer.rules;
+
+import javax.servlet.http.HttpServletRequest;
+
+
+/**
+ * The remote access rule
+ * redirects if the request came
+ * from specified remote address.
+ *
+ * @author Yoav Shapira
+ */
+public class RemoteAddressRule extends BaseRule {
+    /**
+     * The target remote address.
+     */
+    private String remoteAddress;
+
+    /**
+     * Sets the target remote address.
+     *
+     * @param theAddress The address
+     */
+    public void setRemoteAddress(String theAddress) {
+        if (theAddress == null) {
+            throw new IllegalArgumentException("The address cannot be null.");
+        } else {
+            remoteAddress = theAddress;
+        }
+    }
+
+    /**
+     * Returns the target remote address.
+     *
+     * @return String
+     */
+    protected String getRemoteAddress() {
+        return remoteAddress;
+    }
+
+    /**
+     * @see org.apache.webapp.balancer.Rule#matches(HttpServletRequest)
+     *
+     * Looks for the request's remote address.
+     */
+    public boolean matches(HttpServletRequest request) {
+        String requestAddr = request.getRemoteAddr();
+
+        return (requestAddr.compareTo(getRemoteAddress()) == 0);
+    }
+
+    /**
+     * Returns a String representation of this object.
+     *
+     * @return String
+     */
+    public String toString() {
+        StringBuffer buffer = new StringBuffer();
+
+        buffer.append("[");
+        buffer.append(getClass().getName());
+        buffer.append(": ");
+
+        buffer.append("Target remote address: ");
+        buffer.append(getRemoteAddress());
+        buffer.append(" / ");
+
+        buffer.append("Redirect URL: ");
+        buffer.append(getRedirectUrl());
+
+        buffer.append("]");
+
+        return buffer.toString();
+    }
+}
+
+
+// End of file: RemoteAddressRule.java

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/balancer/WEB-INF/classes/org/apache/webapp/balancer/rules/RequestAttributeRule.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/balancer/WEB-INF/classes/org/apache/webapp/balancer/rules/RequestAttributeRule.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/balancer/WEB-INF/classes/org/apache/webapp/balancer/rules/RequestAttributeRule.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,128 @@
+/*
+ * Copyright 2000,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.balancer.rules;
+
+import javax.servlet.http.HttpServletRequest;
+
+
+/**
+ * This rule accepts or rejects requests
+ * based on the presence of a attribute
+ * in the request.
+ *
+ * @author Yoav Shapira
+ */
+public class RequestAttributeRule extends BaseRule {
+    /**
+     * The target attribute name (attribute
+     * must be present for match to succeed).
+     */
+    private String attributeName;
+
+    /**
+     * The target attribute value.  This
+     * is optional: null means any attribute
+     * value is OK for a match.  A non-null
+     * value will be matches exactly.
+     */
+    private Object attributeValue;
+
+    /**
+     * Sets the target attribute name.
+     *
+     * @param theAttributeName The attribute name
+     */
+    public void setAttributeName(String theAttributeName) {
+        if (theAttributeName == null) {
+            throw new IllegalArgumentException(
+                "attributeName cannot be null.");
+        } else {
+            attributeName = theAttributeName;
+        }
+    }
+
+    /**
+     * Returns the target attribute name.
+     *
+     * @return String The target attribute name.
+     */
+    protected String getAttributeName() {
+        return attributeName;
+    }
+
+    /**
+     * Sets the attribute value, which may be null.
+     *
+     * @param theAttributeValue The attribute value
+     */
+    public void setAttributeValue(Object theAttributeValue) {
+        attributeValue = theAttributeValue;
+    }
+
+    /**
+     * Returns the target attribute value,
+     * which may be null.
+     *
+     * @return Object The target attribute value
+     */
+    protected Object getAttributeValue() {
+        return attributeValue;
+    }
+
+    /**
+     * @see org.apache.webapp.balancer.Rule#matches(HttpServletRequest)
+     */
+    public boolean matches(HttpServletRequest request) {
+        Object actualAttributeValue = request.getAttribute(getAttributeName());
+
+        if (actualAttributeValue == null) {
+            return (getAttributeValue() == null);
+        } else {
+            return (actualAttributeValue.equals(getAttributeValue()));
+        }
+    }
+
+    /**
+     * Returns a String representation of this object.
+     *
+     * @return String
+     */
+    public String toString() {
+        StringBuffer buffer = new StringBuffer();
+
+        buffer.append("[");
+        buffer.append(getClass().getName());
+        buffer.append(": ");
+
+        buffer.append("Target attribute name: ");
+        buffer.append(getAttributeName());
+        buffer.append(" / ");
+
+        buffer.append("Target attribute value: ");
+        buffer.append(getAttributeValue());
+        buffer.append(" / ");
+
+        buffer.append("Redirect URL: ");
+        buffer.append(getRedirectUrl());
+
+        buffer.append("]");
+
+        return buffer.toString();
+    }
+}
+
+
+// End of file: RequestAttributeRule.java

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/balancer/WEB-INF/classes/org/apache/webapp/balancer/rules/RequestHeaderRule.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/balancer/WEB-INF/classes/org/apache/webapp/balancer/rules/RequestHeaderRule.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/balancer/WEB-INF/classes/org/apache/webapp/balancer/rules/RequestHeaderRule.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,126 @@
+/*
+ * Copyright 2000,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.balancer.rules;
+
+import javax.servlet.http.HttpServletRequest;
+
+
+/**
+ * This rule checks for the presence
+ * of a specific request header, optionally
+ * with a specific value.  The value may
+ * be null.
+ *
+ * @author Yoav Shapira
+ */
+public class RequestHeaderRule extends BaseRule {
+    /**
+     * The header name, cannot be null.
+     */
+    private String headerName;
+
+    /**
+     * The header value.  This may be
+     * null to indicate any value is OK.
+     */
+    private String headerValue;
+
+    /**
+     * Sets the header name.
+     *
+     * @param theName The name
+     */
+    public void setHeaderName(String theName) {
+        if (theName == null) {
+            throw new IllegalArgumentException(
+                "The header name cannot be null.");
+        } else {
+            headerName = theName;
+        }
+    }
+
+    /**
+     * Returns the header name to match.
+     *
+     * @return The header name
+     */
+    protected String getHeaderName() {
+        return headerName;
+    }
+
+    /**
+     * Sets the header value.
+     *
+     * @param theValue The header value
+     */
+    public void setHeaderValue(String theValue) {
+        headerValue = theValue;
+    }
+
+    /**
+     * Returns the desired header value,
+     * which may be null.
+     *
+     * @return String
+     */
+    protected String getHeaderValue() {
+        return headerValue;
+    }
+
+    /**
+     * @see org.apache.webapp.balancer.Rule#matches(HttpServletRequest request)
+     */
+    public boolean matches(HttpServletRequest request) {
+        String actualHeaderValue = request.getHeader(getHeaderName());
+
+        if (actualHeaderValue == null) {
+            return (getHeaderValue() == null);
+        } else {
+            return (actualHeaderValue.compareTo(getHeaderValue()) == 0);
+        }
+    }
+
+    /**
+     * Returns a String representation of this object.
+     *
+     * @return String
+     */
+    public String toString() {
+        StringBuffer buffer = new StringBuffer();
+
+        buffer.append("[");
+        buffer.append(getClass().getName());
+        buffer.append(": ");
+
+        buffer.append("Header name: ");
+        buffer.append(getHeaderName());
+        buffer.append(" / ");
+
+        buffer.append("Header value: ");
+        buffer.append(getHeaderValue());
+        buffer.append(" / ");
+
+        buffer.append("Redirect URL: ");
+        buffer.append(getRedirectUrl());
+
+        buffer.append("]");
+
+        return buffer.toString();
+    }
+}
+
+
+// End of file: RequestHeaderRule.java

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/balancer/WEB-INF/classes/org/apache/webapp/balancer/rules/RequestParameterRule.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/balancer/WEB-INF/classes/org/apache/webapp/balancer/rules/RequestParameterRule.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/balancer/WEB-INF/classes/org/apache/webapp/balancer/rules/RequestParameterRule.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,127 @@
+/*
+ * Copyright 2000,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.balancer.rules;
+
+import javax.servlet.http.HttpServletRequest;
+
+
+/**
+ * This rule accepts or rejects requests
+ * based on the presence of a parameter
+ * in the request.
+ *
+ * @author Yoav Shapira
+ */
+public class RequestParameterRule extends BaseRule {
+    /**
+     * The target parameter name (parameter
+     * must be present for match to succeed).
+     */
+    private String paramName;
+
+    /**
+     * The target parameter value.  This
+     * is optional: null means any parameter
+     * value is OK for a match.  A non-null
+     * value will be matches exactly.
+     */
+    private String paramValue;
+
+    /**
+     * Sets the target parameter name.
+     *
+     * @param theParamName The parameter name
+     */
+    public void setParamName(String theParamName) {
+        if (theParamName == null) {
+            throw new IllegalArgumentException("paramName cannot be null.");
+        } else {
+            paramName = theParamName;
+        }
+    }
+
+    /**
+     * Returns the target parameter name.
+     *
+     * @return String The target parameter name.
+     */
+    protected String getParamName() {
+        return paramName;
+    }
+
+    /**
+     * Sets the parameter value, which may be null.
+     *
+     * @param theParamValue The parameter value
+     */
+    public void setParamValue(String theParamValue) {
+        paramValue = theParamValue;
+    }
+
+    /**
+     * Returns the target parameter value,
+     * which may be null.
+     *
+     * @return String The target parameter value
+     */
+    protected String getParamValue() {
+        return paramValue;
+    }
+
+    /**
+     * @see org.apache.webapp.balancer.Rule#matches(HttpServletRequest)
+     */
+    public boolean matches(HttpServletRequest request) {
+        String actualParamValue = request.getParameter(getParamName());
+
+        if (actualParamValue == null) {
+            return (getParamValue() == null);
+        } else {
+            return (actualParamValue.compareTo(getParamValue()) == 0);
+        }
+    }
+
+    /**
+     * Returns a String representation of this object.
+     *
+     * @return String
+     */
+    public String toString() {
+        StringBuffer buffer = new StringBuffer();
+
+        buffer.append("[");
+        buffer.append(getClass().getName());
+        buffer.append(": ");
+
+        buffer.append("Target param name: ");
+        buffer.append(getParamName());
+        buffer.append(" / ");
+
+        buffer.append("Target param value: ");
+        buffer.append(getParamValue());
+        buffer.append(" / ");
+
+        buffer.append("Redirect URL: ");
+        buffer.append(getRedirectUrl());
+
+        buffer.append("]");
+
+        return buffer.toString();
+    }
+}
+
+
+// End of file: RequestParameterRule.java

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/balancer/WEB-INF/classes/org/apache/webapp/balancer/rules/SessionAttributeRule.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/balancer/WEB-INF/classes/org/apache/webapp/balancer/rules/SessionAttributeRule.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/balancer/WEB-INF/classes/org/apache/webapp/balancer/rules/SessionAttributeRule.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,130 @@
+/*
+ * Copyright 2000,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.balancer.rules;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpSession;
+
+
+/**
+ * This rule accepts or rejects requests
+ * based on the presence of a attribute
+ * in the request.
+ *
+ * @author Yoav Shapira
+ */
+public class SessionAttributeRule extends BaseRule {
+    /**
+     * The target attribute name (attribute
+     * must be present for match to succeed).
+     */
+    private String attributeName;
+
+    /**
+     * The target attribute value.  This
+     * is optional: null means any attribute
+     * value is OK for a match.  A non-null
+     * value will be matches exactly.
+     */
+    private Object attributeValue;
+
+    /**
+     * Sets the target attribute name.
+     *
+     * @param theAttributeName The attribute name
+     */
+    public void setAttributeName(String theAttributeName) {
+        if (theAttributeName == null) {
+            throw new IllegalArgumentException(
+                "attributeName cannot be null.");
+        } else {
+            attributeName = theAttributeName;
+        }
+    }
+
+    /**
+     * Returns the target attribute name.
+     *
+     * @return String The target attribute name.
+     */
+    protected String getAttributeName() {
+        return attributeName;
+    }
+
+    /**
+     * Sets the attribute value, which may be null.
+     *
+     * @param theAttributeValue The attribute value
+     */
+    public void setAttributeValue(Object theAttributeValue) {
+        attributeValue = theAttributeValue;
+    }
+
+    /**
+     * Returns the target attribute value,
+     * which may be null.
+     *
+     * @return Object The target attribute value
+     */
+    protected Object getAttributeValue() {
+        return attributeValue;
+    }
+
+    /**
+     * @see org.apache.webapp.balancer.Rule#matches(HttpServletRequest)
+     */
+    public boolean matches(HttpServletRequest request) {
+        HttpSession session = request.getSession();
+        Object actualAttributeValue = session.getAttribute(getAttributeName());
+
+        if (actualAttributeValue == null) {
+            return (getAttributeValue() == null);
+        } else {
+            return (actualAttributeValue.equals(getAttributeValue()));
+        }
+    }
+
+    /**
+     * Returns a String representation of this object.
+     *
+     * @return String
+     */
+    public String toString() {
+        StringBuffer buffer = new StringBuffer();
+
+        buffer.append("[");
+        buffer.append(getClass().getName());
+        buffer.append(": ");
+
+        buffer.append("Target attribute name: ");
+        buffer.append(getAttributeName());
+        buffer.append(" / ");
+
+        buffer.append("Target attribute value: ");
+        buffer.append(getAttributeValue());
+        buffer.append(" / ");
+
+        buffer.append("Redirect URL: ");
+        buffer.append(getRedirectUrl());
+
+        buffer.append("]");
+
+        return buffer.toString();
+    }
+}
+
+
+// End of file: SessionAttributeRule.java

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/balancer/WEB-INF/classes/org/apache/webapp/balancer/rules/URLStringMatchRule.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/balancer/WEB-INF/classes/org/apache/webapp/balancer/rules/URLStringMatchRule.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/balancer/WEB-INF/classes/org/apache/webapp/balancer/rules/URLStringMatchRule.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,97 @@
+/*
+ * Copyright 2000,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.balancer.rules;
+
+import javax.servlet.http.HttpServletRequest;
+
+
+/**
+ * This rule looks for a specific string
+ * in the URL for a positive match.
+ *
+ * @author Yoav Shapira
+ */
+public class URLStringMatchRule extends BaseRule {
+    /**
+     * The target string that must be present
+     * in the URL, may not be null.
+     */
+    private String targetString;
+
+    /**
+     * Sets the target string that must
+     * be present in the URL.
+     *
+     * @param theTargetString The target string
+     */
+    public void setTargetString(String theTargetString) {
+        if (theTargetString == null) {
+            throw new IllegalArgumentException(
+                "The target string cannot be null.");
+        } else {
+            targetString = theTargetString;
+        }
+    }
+
+    /**
+     * Returns the target string that must
+     * be present in the URL.
+     *
+     * @return The target string
+     */
+    protected String getTargetString() {
+        return targetString;
+    }
+
+    /**
+     * @see org.apache.webapp.balancer.Rule#matches(HttpServletRequest)
+     *
+     * Looks for the target string in the request URL.
+     */
+    public boolean matches(HttpServletRequest request) {
+        String requestUrl = request.getRequestURL().toString();
+        int index = requestUrl.indexOf(getTargetString());
+
+        return (index > -1);
+    }
+
+    /**
+     * Returns a String representation of this object.
+     *
+     * @return String
+     */
+    public String toString() {
+        StringBuffer buffer = new StringBuffer();
+
+        buffer.append("[");
+        buffer.append(getClass().getName());
+        buffer.append(": ");
+
+        buffer.append("Target string: ");
+        buffer.append(getTargetString());
+        buffer.append(" / ");
+
+        buffer.append("Redirect URL: ");
+        buffer.append(getRedirectUrl());
+
+        buffer.append("]");
+
+        return buffer.toString();
+    }
+}
+
+
+// End of file: URLStringMatchRule.java

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/balancer/WEB-INF/classes/org/apache/webapp/balancer/rules/UserRoleRule.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/balancer/WEB-INF/classes/org/apache/webapp/balancer/rules/UserRoleRule.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/balancer/WEB-INF/classes/org/apache/webapp/balancer/rules/UserRoleRule.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,90 @@
+/*
+ * Copyright 2000,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.webapp.balancer.rules;
+
+import javax.servlet.http.HttpServletRequest;
+
+
+/**
+ * This rule redirects the request based
+ * on the user's role.
+ *
+ * @author Yoav Shapira
+ */
+public class UserRoleRule extends BaseRule {
+    /**
+     * The desired role for the user.
+     * If the user is in this role, the
+     * match will succeed.
+     */
+    private String role;
+
+    /**
+     * Sets the desired role.
+     *
+     * @param theRole The desire role
+     */
+    public void setRole(String theRole) {
+        if (theRole == null) {
+            throw new IllegalArgumentException("The role cannot be null.");
+        } else {
+            role = theRole;
+        }
+    }
+
+    /**
+     * Returns the target role.
+     *
+     * @return The desired role
+     */
+    protected String getRole() {
+        return role;
+    }
+
+    /**
+     * @see org.apache.webapp.balancer.Rule#matches(HttpServletRequest)
+     */
+    public boolean matches(HttpServletRequest request) {
+        return request.isUserInRole(getRole());
+    }
+
+    /**
+     * Returns a String representation of this object.
+     *
+     * @return String
+     */
+    public String toString() {
+        StringBuffer buffer = new StringBuffer();
+
+        buffer.append("[");
+        buffer.append(getClass().getName());
+        buffer.append(": ");
+
+        buffer.append("Target role: ");
+        buffer.append(getRole());
+        buffer.append(" / ");
+
+        buffer.append("Redirect URL: ");
+        buffer.append(getRedirectUrl());
+
+        buffer.append("]");
+
+        return buffer.toString();
+    }
+}
+
+
+// End of file: UserRoleRule.java

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/balancer/WEB-INF/classes/org/apache/webapp/balancer/rules/package.html
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/balancer/WEB-INF/classes/org/apache/webapp/balancer/rules/package.html	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/balancer/WEB-INF/classes/org/apache/webapp/balancer/rules/package.html	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,11 @@
+<html>
+<head>
+<title>org.apache.webapp.balancer.rules Package Overview</title>
+</head>
+<body>
+This package contains all the {@link org.apache.webapp.balancer.Rule} 
+implementations that are distributed with the balancer webapp.  All 
+these rules extend {@link org.apache.webapp.balancer.rules.BaseRule} 
+but users are free to implement the Rule interface as needed.
+</body>
+</html>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/balancer/WEB-INF/config/rules.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/balancer/WEB-INF/config/rules.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/balancer/WEB-INF/config/rules.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<rules>
+  <!-- If the URL contains News (case-sensitive), go to CNN.com -->
+  <rule className="org.apache.webapp.balancer.rules.URLStringMatchRule"
+    targetString="News"
+    redirectUrl="http://www.cnn.com" />
+
+  <!-- If the request contains a parameter named paramName whose value
+       is paramValue, go to Yahoo.com. -->
+  <rule className="org.apache.webapp.balancer.rules.RequestParameterRule"
+    paramName="paramName"
+    paramValue="paramValue"
+    redirectUrl="http://www.yahoo.com" />
+
+  <!-- Redirect all requests to jakarta.apache.org. -->
+  <rule className="org.apache.webapp.balancer.rules.AcceptEverythingRule"
+    redirectUrl="http://jakarta.apache.org" />
+</rules>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/balancer/WEB-INF/web.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/balancer/WEB-INF/web.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/balancer/WEB-INF/web.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<web-app 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-app_2_4.xsd"
+    version="2.4">
+
+  <display-name>Tomcat Simple Load Balancer Example App</display-name>
+  <description>
+    Tomcat Simple Load Balancer Example App
+  </description>
+
+  <!-- BalancerFilter definition -->
+  <filter>
+    <filter-name>BalancerFilter</filter-name>
+    <filter-class>org.apache.webapp.balancer.BalancerFilter</filter-class>
+    <init-param>
+      <param-name>configUrl</param-name>
+      <param-value>/WEB-INF/config/rules.xml</param-value>
+    </init-param>
+  </filter>
+
+  <!-- BalancerFilter mapping -->
+  <filter-mapping>
+    <filter-name>BalancerFilter</filter-name>
+    <url-pattern>/*</url-pattern>
+  </filter-mapping>
+</web-app>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/balancer/build.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/balancer/build.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/balancer/build.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,117 @@
+<?xml version="1.0"?>
+
+<!-- 
+This is the build script for the balancer webapp.
+ at author Yoav Shapira
+-->
+
+<project name="balancer" default="build-main" basedir=".">
+
+
+  <!-- ===================== Initialize Property Values =================== -->
+
+  <!-- See "build.properties.sample" in the top level directory for all     -->
+  <!-- property values you must customize for successful building!!!        -->
+  <property file="build.properties"/>
+  <property file="../build.properties"/>
+  <property file="../../build.properties"/>
+  <property file="${user.home}/build.properties"/>
+
+  <property name="build.compiler"  value="modern"/>
+  <property name="webapps.build"   value="../build"/>
+  <property name="webapps.dist"    value="../dist"/>
+  <property name="webapp.name"     value="balancer"/>
+
+  <!-- Dependent JARs and files -->
+  <property name="servlet-api.jar" value="${api.home}/jsr154/dist/lib/servlet-api.jar"/>
+  <property name="jsp-api.jar"     value="${api.home}/jsr152/dist/lib/jsp-api.jar"/>
+
+  <!-- Compilation classpath -->
+  <path id="balancer.classpath">
+    <!-- Required by Digester -->
+    <pathelement location="${catalina.deploy}/classes"/>
+    <pathelement location="${servlet-api.jar}"/>
+    <pathelement location="${commons-logging-api.jar}" />
+  </path>
+
+
+  <!-- =================== BUILD: Create Directories ====================== -->
+  <target name="build-prepare">
+    <mkdir dir="${webapps.build}"/>
+    <mkdir dir="${webapps.build}/${webapp.name}"/>
+    <mkdir dir="${webapps.build}/${webapp.name}/images"/>
+    <mkdir dir="${webapps.build}/${webapp.name}/WEB-INF"/>
+    <mkdir dir="${webapps.build}/${webapp.name}/WEB-INF/classes"/>
+  </target>
+
+
+  <!-- ================ BUILD: Copy Static Files ========================== -->
+  <target name="build-static" depends="build-prepare">
+    <copy todir="${webapps.build}/${webapp.name}">
+      <fileset dir=".">
+        <exclude name="build.*"/>
+      </fileset>
+    </copy>
+  </target>
+
+
+  <!-- ================= BUILD: Compile Server Components ================= -->
+  <target name="build-main" depends="build-static">
+
+    <javac   srcdir="WEB-INF/classes" 
+             destdir="${webapps.build}/${webapp.name}/WEB-INF/classes"
+             debug="${compile.debug}" deprecation="${compile.deprecation}"
+             optimize="${compile.optimize}"
+             excludes="**/CVS/**">
+      <classpath refid="balancer.classpath" />
+    </javac>
+
+  </target>
+
+
+  <!-- ==================== BUILD: Rebuild Everything ===================== -->
+  <target name="all" depends="build-clean,build-main"
+   description="Clean and build balancer webapp"/>
+
+
+  <!-- ======================= BUILD: Clean Directory ===================== -->
+  <target name="build-clean">
+    <delete dir="${webapps.build}/${webapp.name}"/>
+  </target>
+
+
+  <!-- ======================= DIST: Create Directories =================== -->
+  <target name="dist-prepare">
+    <mkdir dir="${webapps.dist}"/>
+  </target>
+
+
+  <!-- ======================= DIST: Create Distribution Files ============ -->
+  <target name="dist" depends="build-main,dist-prepare"
+   description="Create balancer webapp binary distribution">
+      <jar   jarfile="${webapps.dist}/${webapp.name}.war"
+             basedir="${webapps.build}/${webapp.name}" includes="**"/>
+  </target>
+
+
+  <!-- ======================= DIST: Clean Directory ====================== -->
+  <target name="dist-clean">
+    <deltree dir="${dist.dir}/${webapp.name}"/>
+  </target>
+
+
+  <!-- ====================== Convenient Synonyms ========================= -->
+  <target name="clean" depends="build-clean,dist-clean"
+   description="Clean build and dist directories"/>
+
+
+
+
+</project>
+<!-- End build.xml -->
+
+
+
+
+
+

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/build.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/build.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/build.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,139 @@
+<project name="Webapps" default="dist" basedir=".">
+
+
+  <!-- ===================== Initialize Property Values =================== -->
+
+  <!-- See "build.properties.sample" in the top level directory for all     -->
+  <!-- property values you must customize for successful building!!!        -->
+  <!--property file="build.properties"/>
+  <property file="../build.properties"/>
+  <property file="${user.home}/build.properties"/-->
+
+  <property name="build.compiler"  value="modern"/>
+  <property name="webapps.build"   value="${basedir}/build"/>
+  <property name="webapps.deploy"  value="${basedir}/../build"/>
+  <property name="webapps.dist"    value="${basedir}/dist"/>
+
+
+  <!-- =================== BUILD: Create Directories ====================== -->
+  <target name="build-prepare">
+
+    <available classname="junit.framework.TestCase" property="junit.present" />
+
+    <mkdir dir="${webapps.build}"/>
+    <mkdir dir="${webapps.dist}"/>
+
+  </target>
+
+
+  <!-- =================== BUILD: Compile Subprojects ===================== -->
+  <!-- Add a new target for each webapp subproject -->
+
+  <target name="ROOT">
+    <ant dir="${basedir}/ROOT" target="dist"/>
+  </target>
+
+  <target name="admin">
+    <ant dir="${basedir}/admin" target="dist"/>
+  </target>
+
+  <target name="manager">
+    <ant dir="${basedir}/manager" target="dist"/>
+  </target>
+
+	<target name="host-manager">
+	    <ant dir="${basedir}/host-manager" target="dist"/>
+	  </target>
+
+  <target name="docs">
+    <ant dir="${basedir}/docs" target="dist"/>
+  </target>
+
+  <target name="balancer">
+    <ant dir="${basedir}/balancer" target="dist"/>
+  </target>
+
+  <target name="webdav">
+    <ant dir="${basedir}/webdav" target="dist"/>
+  </target>
+
+
+  <!-- ================= BUILD: Compile Server Components ================= -->
+  <!-- Update the depends list for each subproject -->
+  <target name="build" depends="build-prepare,ROOT,admin,manager,host-manager,docs,balancer,webdav" />
+
+
+  <!-- ======================= BUILD: Clean Directory ===================== -->
+  <target name="build-clean">
+    <delete dir="${webapps.build}"/>
+  </target>
+
+
+  <!-- ==================== BUILD: Rebuild Everything ===================== -->
+  <target name="all" depends="build-clean,dist"/>
+
+
+  <!-- ================= DEPLOY: Deploy Webapps Projects ================== -->
+  <target name="deploy" depends="dist"
+   description="Build and deploy Webapps component">
+
+    <!-- General Purpose Applications -->
+    <mkdir dir="${webapps.deploy}/webapps"/>
+    <copy todir="${webapps.deploy}/webapps">
+      <fileset dir="${webapps.build}" excludes="admin/**,manager/**"/>
+    </copy>
+
+    <!-- Administrative Applications -->
+    <mkdir     dir="${webapps.deploy}/server/webapps"/>
+
+    <copy    todir="${webapps.deploy}/webapps"
+              file="${webapps.build}/admin/admin.xml"/>
+    <mkdir     dir="${webapps.deploy}/server/webapps/admin"/>
+    <copy    todir="${webapps.deploy}/server/webapps/admin">
+      <fileset dir="${webapps.build}/admin" excludes="admin.xml"/>
+    </copy>
+
+    <copy    todir="${webapps.deploy}/webapps"
+              file="${webapps.build}/manager/manager.xml"/>
+    <mkdir     dir="${webapps.deploy}/server/webapps/manager"/>
+    <copy    todir="${webapps.deploy}/server/webapps/manager">
+      <fileset dir="${webapps.build}/manager" excludes="manager.xml"/>
+    </copy>
+
+    <copy    todir="${webapps.deploy}/webapps"
+              file="${webapps.build}/host-manager/host-manager.xml"/>
+    <mkdir     dir="${webapps.deploy}/server/webapps/host-manager"/>
+    <copy    todir="${webapps.deploy}/server/webapps/host-manager">
+      <fileset dir="${webapps.build}/host-manager" excludes="host-manager.xml"/>
+    </copy>
+
+  </target>
+
+
+  <!-- ================= DIST: Create Distribution Files ================== -->
+  <target name="dist" depends="build"/>
+
+
+  <!-- ======================= DIST: Clean Directory ====================== -->
+  <target name="dist-clean">
+    <delete dir="${webapps.dist}"/>
+  </target>
+
+
+  <!-- ====================== Convenient Synonyms ========================= -->
+  <target name="clean" depends="build-clean,dist-clean"
+   description="Clean build and dist directories"/>
+
+
+  <!-- ===================== TEST: Compile Unit Tests ===================== -->
+  <target name="build-tests" depends="dist" if="junit.present">
+  </target>
+
+
+  <!-- ===================== TEST: Execute Unit Tests ===================== -->
+  <target name="test" if="junit.present"
+   description="Run all unit test cases">
+  </target>
+
+
+</project>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/META-INF/context.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/META-INF/context.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/META-INF/context.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,12 @@
+<!--
+
+    Context configuration file for the Tomcat Balancer Web App
+    This is only needed to keep the distribution small and avoid duplicating
+    commons libraries
+
+    $Id: context.xml 303123 2004-08-26 17:03:35Z remm $
+
+-->
+
+
+<Context antiResourceLocking="false" />

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/WEB-INF/web.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/WEB-INF/web.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/WEB-INF/web.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<web-app 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-app_2_4.xsd"
+    version="2.4">
+
+  <display-name>Tomcat Documentation</display-name>
+  <description>
+     Tomcat Documentation.
+  </description>
+</web-app>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/appdev/build.xml.txt
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/appdev/build.xml.txt	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/appdev/build.xml.txt	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,503 @@
+<!--
+     General purpose build script for web applications and web services,
+     including enhanced support for deploying directly to a Tomcat 5
+     based server.
+
+     This build script assumes that the source code of your web application
+     is organized into the following subdirectories underneath the source
+     code directory from which you execute the build script:
+
+        docs                 Static documentation files to be copied to
+                             the "docs" subdirectory of your distribution.
+
+        src                  Java source code (and associated resource files)
+                             to be compiled to the "WEB-INF/classes"
+                             subdirectory of your web applicaiton.
+
+        web                  Static HTML, JSP, and other content (such as
+                             image files), including the WEB-INF subdirectory
+                             and its configuration file contents.
+
+     $Id: build.xml.txt 302898 2004-05-23 19:50:44Z markt $
+-->
+
+
+<!-- A "project" describes a set of targets that may be requested
+     when Ant is executed.  The "default" attribute defines the
+     target which is executed if no specific target is requested,
+     and the "basedir" attribute defines the current working directory
+     from which Ant executes the requested task.  This is normally
+     set to the current working directory.
+-->
+
+<project name="My Project" default="compile" basedir=".">
+
+
+
+<!-- ===================== Property Definitions =========================== -->
+
+
+<!--
+
+  Each of the following properties are used in the build script.
+  Values for these properties are set by the first place they are
+  defined, from the following list:
+
+  * Definitions on the "ant" command line (ant -Dfoo=bar compile).
+
+  * Definitions from a "build.properties" file in the top level
+    source directory of this application.
+
+  * Definitions from a "build.properties" file in the developer's
+    home directory.
+
+  * Default definitions in this build.xml file.
+
+  You will note below that property values can be composed based on the
+  contents of previously defined properties.  This is a powerful technique
+  that helps you minimize the number of changes required when your development
+  environment is modified.  Note that property composition is allowed within
+  "build.properties" files as well as in the "build.xml" script.
+
+-->
+
+  <property file="build.properties"/>
+  <property file="${user.home}/build.properties"/>
+
+
+<!-- ==================== File and Directory Names ======================== -->
+
+
+<!--
+
+  These properties generally define file and directory names (or paths) that
+  affect where the build process stores its outputs.
+
+  app.name             Base name of this application, used to
+                       construct filenames and directories.
+                       Defaults to "myapp".
+
+  app.path             Context path to which this application should be
+                       deployed (defaults to "/" plus the value of the
+                       "app.name" property).
+
+  app.version          Version number of this iteration of the application.
+
+  build.home           The directory into which the "prepare" and
+                       "compile" targets will generate their output.
+                       Defaults to "build".
+
+  catalina.home        The directory in which you have installed
+                       a binary distribution of Tomcat 5.  This will
+                       be used by the "deploy" target.
+
+  dist.home            The name of the base directory in which
+                       distribution files are created.
+                       Defaults to "dist".
+
+  manager.password     The login password of a user that is assigned the
+                       "manager" role (so that he or she can execute
+                       commands via the "/manager" web application)
+
+  manager.url          The URL of the "/manager" web application on the
+                       Tomcat installation to which we will deploy web
+                       applications and web services.
+
+  manager.username     The login username of a user that is assigned the
+                       "manager" role (so that he or she can execute
+                       commands via the "/manager" web application)
+
+-->
+
+  <property name="app.name"      value="myapp"/>
+  <property name="app.path"      value="/${app.name}"/>
+  <property name="app.version"   value="0.1-dev"/>
+  <property name="build.home"    value="${basedir}/build"/>
+  <property name="catalina.home" value="../../../.."/> <!-- UPDATE THIS! -->
+  <property name="dist.home"     value="${basedir}/dist"/>
+  <property name="docs.home"     value="${basedir}/docs"/>
+  <property name="manager.url"   value="http://localhost:8080/manager"/>
+  <property name="src.home"      value="${basedir}/src"/>
+  <property name="web.home"      value="${basedir}/web"/>
+
+
+<!-- ================== Custom Ant Task Definitions ======================= -->
+
+
+<!--
+
+  These properties define custom tasks for the Ant build tool that interact
+  with the "/manager" web application installed with Tomcat 5.  Before they
+  can be successfully utilized, you must perform the following steps:
+
+  - Copy the file "server/lib/catalina-ant.jar" from your Tomcat 5
+    installation into the "lib" directory of your Ant installation.
+
+  - Create a "build.properties" file in your application's top-level
+    source directory (or your user login home directory) that defines
+    appropriate values for the "manager.password", "manager.url", and
+    "manager.username" properties described above.
+
+  For more information about the Manager web application, and the functionality
+  of these tasks, see <http://localhost:8080/tomcat-docs/manager-howto.html>.
+
+-->
+
+  <taskdef name="deploy"   classname="org.apache.catalina.ant.DeployTask"/>
+  <taskdef name="list"     classname="org.apache.catalina.ant.ListTask"/>
+  <taskdef name="reload"   classname="org.apache.catalina.ant.ReloadTask"/>
+  <taskdef name="undeploy" classname="org.apache.catalina.ant.UndeployTask"/>
+
+
+<!--  ==================== Compilation Control Options ==================== -->
+
+<!--
+
+  These properties control option settings on the Javac compiler when it
+  is invoked using the <javac> task.
+
+  compile.debug        Should compilation include the debug option?
+
+  compile.deprecation  Should compilation include the deprecation option?
+
+  compile.optimize     Should compilation include the optimize option?
+
+-->
+
+  <property name="compile.debug"       value="true"/>
+  <property name="compile.deprecation" value="false"/>
+  <property name="compile.optimize"    value="true"/>
+
+
+
+<!-- ==================== External Dependencies =========================== -->
+
+
+<!--
+
+  Use property values to define the locations of external JAR files on which
+  your application will depend.  In general, these values will be used for
+  two purposes:
+  * Inclusion on the classpath that is passed to the Javac compiler
+  * Being copied into the "/WEB-INF/lib" directory during execution
+    of the "deploy" target.
+
+  Because we will automatically include all of the Java classes that Tomcat 5
+  exposes to web applications, we will not need to explicitly list any of those
+  dependencies.  You only need to worry about external dependencies for JAR
+  files that you are going to include inside your "/WEB-INF/lib" directory.
+
+-->
+
+<!-- Dummy external dependency -->
+<!--
+  <property name="foo.jar"
+           value="/path/to/foo.jar"/>
+-->
+
+
+<!-- ==================== Compilation Classpath =========================== -->
+
+<!--
+
+  Rather than relying on the CLASSPATH environment variable, Ant includes
+  features that makes it easy to dynamically construct the classpath you
+  need for each compilation.  The example below constructs the compile
+  classpath to include the servlet.jar file, as well as the other components
+  that Tomcat makes available to web applications automatically, plus anything
+  that you explicitly added.
+
+-->
+
+  <path id="compile.classpath">
+
+    <!-- Include all JAR files that will be included in /WEB-INF/lib -->
+    <!-- *** CUSTOMIZE HERE AS REQUIRED BY YOUR APPLICATION *** -->
+<!--
+    <pathelement location="${foo.jar}"/>
+-->
+
+    <!-- Include all elements that Tomcat exposes to applications -->
+    <pathelement location="${catalina.home}/common/classes"/>
+    <fileset dir="${catalina.home}/common/endorsed">
+      <include name="*.jar"/>
+    </fileset>
+    <fileset dir="${catalina.home}/common/lib">
+      <include name="*.jar"/>
+    </fileset>
+    <pathelement location="${catalina.home}/shared/classes"/>
+    <fileset dir="${catalina.home}/shared/lib">
+      <include name="*.jar"/>
+    </fileset>
+
+  </path>
+
+
+
+<!-- ==================== All Target ====================================== -->
+
+<!--
+
+  The "all" target is a shortcut for running the "clean" target followed
+  by the "compile" target, to force a complete recompile.
+
+-->
+
+  <target name="all" depends="clean,compile"
+   description="Clean build and dist directories, then compile"/>
+
+
+
+<!-- ==================== Clean Target ==================================== -->
+
+<!--
+
+  The "clean" target deletes any previous "build" and "dist" directory,
+  so that you can be ensured the application can be built from scratch.
+
+-->
+
+  <target name="clean"
+   description="Delete old build and dist directories">
+    <delete dir="${build.home}"/>
+    <delete dir="${dist.home}"/>
+  </target>
+
+
+
+<!-- ==================== Compile Target ================================== -->
+
+<!--
+
+  The "compile" target transforms source files (from your "src" directory)
+  into object files in the appropriate location in the build directory.
+  This example assumes that you will be including your classes in an
+  unpacked directory hierarchy under "/WEB-INF/classes".
+
+-->
+
+  <target name="compile" depends="prepare"
+   description="Compile Java sources">
+
+    <!-- Compile Java classes as necessary -->
+    <mkdir    dir="${build.home}/WEB-INF/classes"/>
+    <javac srcdir="${src.home}"
+          destdir="${build.home}/WEB-INF/classes"
+            debug="${compile.debug}"
+      deprecation="${compile.deprecation}"
+         optimize="${compile.optimize}">
+        <classpath refid="compile.classpath"/>
+    </javac>
+
+    <!-- Copy application resources -->
+    <copy  todir="${build.home}/WEB-INF/classes">
+      <fileset dir="${src.home}" excludes="**/*.java"/>
+    </copy>
+
+  </target>
+
+
+
+<!-- ==================== Dist Target ===================================== -->
+
+
+<!--
+
+  The "dist" target creates a binary distribution of your application
+  in a directory structure ready to be archived in a tar.gz or zip file.
+  Note that this target depends on two others:
+
+  * "compile" so that the entire web application (including external
+    dependencies) will have been assembled
+
+  * "javadoc" so that the application Javadocs will have been created
+
+-->
+
+  <target name="dist" depends="compile,javadoc"
+   description="Create binary distribution">
+
+    <!-- Copy documentation subdirectories -->
+    <mkdir   dir="${dist.home}/docs"/>
+    <copy    todir="${dist.home}/docs">
+      <fileset dir="${docs.home}"/>
+    </copy>
+
+    <!-- Create application JAR file -->
+    <jar jarfile="${dist.home}/${app.name}-${app.version}.war"
+         basedir="${build.home}"/>
+
+    <!-- Copy additional files to ${dist.home} as necessary -->
+
+  </target>
+
+
+
+<!-- ==================== Install Target ================================== -->
+
+<!--
+
+  The "install" target tells the specified Tomcat 5 installation to dynamically
+  install this web application and make it available for execution.  It does
+  *not* cause the existence of this web application to be remembered across
+  Tomcat restarts; if you restart the server, you will need to re-install all
+  this web application.
+
+  If you have already installed this application, and simply want Tomcat to
+  recognize that you have updated Java classes (or the web.xml file), use the
+  "reload" target instead.
+
+  NOTE:  This target will only succeed if it is run from the same server that
+  Tomcat is running on.
+
+  NOTE:  This is the logical opposite of the "remove" target.
+
+-->
+
+  <target name="install" depends="compile"
+   description="Install application to servlet container">
+
+    <deploy url="${manager.url}"
+       username="${manager.username}"
+       password="${manager.password}"
+           path="${app.path}"
+       localWar="file://${build.home}"/>
+
+  </target>
+
+
+<!-- ==================== Javadoc Target ================================== -->
+
+<!--
+
+  The "javadoc" target creates Javadoc API documentation for the Java
+  classes included in your application.  Normally, this is only required
+  when preparing a distribution release, but is available as a separate
+  target in case the developer wants to create Javadocs independently.
+
+-->
+
+  <target name="javadoc" depends="compile"
+   description="Create Javadoc API documentation">
+
+    <mkdir          dir="${dist.home}/docs/api"/>
+    <javadoc sourcepath="${src.home}"
+                destdir="${dist.home}/docs/api"
+           packagenames="*">
+      <classpath refid="compile.classpath"/>
+    </javadoc>
+
+  </target>
+
+
+
+<!-- ====================== List Target =================================== -->
+
+<!--
+
+  The "list" target asks the specified Tomcat 5 installation to list the
+  currently running web applications, either loaded at startup time or
+  installed dynamically.  It is useful to determine whether or not the
+  application you are currently developing has been installed.
+
+-->
+
+  <target name="list"
+   description="List installed applications on servlet container">
+
+    <list    url="${manager.url}"
+        username="${manager.username}"
+        password="${manager.password}"/>
+
+  </target>
+
+
+<!-- ==================== Prepare Target ================================== -->
+
+<!--
+
+  The "prepare" target is used to create the "build" destination directory,
+  and copy the static contents of your web application to it.  If you need
+  to copy static files from external dependencies, you can customize the
+  contents of this task.
+
+  Normally, this task is executed indirectly when needed.
+
+-->
+
+  <target name="prepare">
+
+    <!-- Create build directories as needed -->
+    <mkdir  dir="${build.home}"/>
+    <mkdir  dir="${build.home}/WEB-INF"/>
+    <mkdir  dir="${build.home}/WEB-INF/classes"/>
+
+
+    <!-- Copy static content of this web application -->
+    <copy todir="${build.home}">
+      <fileset dir="${web.home}"/>
+    </copy>
+
+    <!-- Copy external dependencies as required -->
+    <!-- *** CUSTOMIZE HERE AS REQUIRED BY YOUR APPLICATION *** -->
+    <mkdir  dir="${build.home}/WEB-INF/lib"/>
+<!--
+    <copy todir="${build.home}/WEB-INF/lib" file="${foo.jar}"/>
+-->
+
+    <!-- Copy static files from external dependencies as needed -->
+    <!-- *** CUSTOMIZE HERE AS REQUIRED BY YOUR APPLICATION *** -->
+
+  </target>
+
+
+<!-- ==================== Reload Target =================================== -->
+
+<!--
+
+  The "reload" signals the specified application Tomcat 5 to shut itself down
+  and reload. This can be useful when the web application context is not
+  reloadable and you have updated classes or property files in the
+  /WEB-INF/classes directory or when you have added or updated jar files in the
+  /WEB-INF/lib directory.
+
+  NOTE: The /WEB-INF/web.xml web application configuration file is not reread
+  on a reload. If you have made changes to your web.xml file you must stop
+  then start the web application. 
+
+-->
+
+  <target name="reload" depends="compile"
+   description="Reload application on servlet container">
+
+    <reload url="${manager.url}"
+       username="${manager.username}"
+       password="${manager.password}"
+           path="${app.path}"/>
+
+  </target>
+
+
+<!-- ==================== Remove Target =================================== -->
+
+<!--
+
+  The "remove" target tells the specified Tomcat 5 installation to dynamically
+  remove this web application from service.
+
+  NOTE:  This is the logical opposite of the "install" target.
+
+-->
+
+  <target name="remove"
+   description="Remove application on servlet container">
+
+    <undeploy url="${manager.url}"
+         username="${manager.username}"
+         password="${manager.password}"
+             path="${app.path}"/>
+
+  </target>
+
+
+</project>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/appdev/deployment.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/appdev/deployment.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/appdev/deployment.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,254 @@
+<?xml version="1.0"?>
+<!DOCTYPE document [
+  <!ENTITY project SYSTEM "project.xml">
+]>
+<document url="deployment.html">
+
+  &project;
+
+  <properties>
+    <author email="craigmcc at apache.org">Craig R. McClanahan</author>
+    <title>Deployment</title>
+  </properties>
+
+<body>
+
+
+<section name="Background">
+
+<p>Before describing how to organize your source code directories,
+it is useful to examine the runtime organization of a web application.
+Prior to the Servlet API Specification, version 2.2, there was little
+consistency between server platforms.  However, servers that conform
+to the 2.2 (or later) specification are required to accept a
+<em>Web Application Archive</em> in a standard format, which is discussed
+further below.</p>
+
+<p>A web application is defined as a hierarchy of directories and files
+in a standard layout.  Such a hierarchy can be accessed in its "unpacked"
+form, where each directory and file exists in the filesystem separately,
+or in a "packed" form known as a Web ARchive, or WAR file.  The former format
+is more useful during development, while the latter is used when you
+distribute your application to be installed.</p>
+
+<p>The top-level directory of your web application hierarchy is also the
+<em>document root</em> of your application.  Here, you will place the HTML
+files and JSP pages that comprise your application's user interface.  When the
+system administrator deploys your application into a particular server, he
+or she assigns a <em>context path</em> to your application (a later section
+of this manual describes deployment on Tomcat).  Thus, if the
+system administrator assigns your application to the context path
+<code>/catalog</code>, then a request URI referring to
+<code>/catalog/index.html</code> will retrieve the <code>index.html</code>
+file from your document root.</p>
+
+</section>
+
+
+<section name="Standard Directory Layout">
+
+<p>To facilitate creation of a Web Application Archive file in the required
+format, it is convenient to arrange the "executable" files of your web
+application (that is, the files that Tomcat actually uses when executing
+your app) in the same organization as required by the WAR format itself.
+To do this, you will end up with the following contents in your
+application's "document root" directory:</p>
+<ul>
+<li><strong>*.html, *.jsp, etc.</strong> - The HTML and JSP pages, along
+    with other files that must be visible to the client browser (such as
+    JavaScript, stylesheet files, and images) for your application.
+    In larger applications you may choose to divide these files into
+    a subdirectory hierarchy, but for smaller apps, it is generally
+    much simpler to maintain only a single directory for these files.
+    <br/><br/></li>
+<li><strong>/WEB-INF/web.xml</strong> - The <em>Web Application Deployment
+    Descriptor</em> for your application.  This is an XML file describing
+    the servlets and other components that make up your application,
+    along with any initialization parameters and container-managed
+    security constraints that you want the server to enforce for you.
+    This file is discussed in more detail in the following subsection.
+    <br/><br/></li>
+<li><strong>/WEB-INF/classes/</strong> - This directory contains any Java
+    class files (and associated resources) required for your application,
+    including both servlet and non-servlet classes, that are not combined
+    into JAR files.  If your classes are organized into Java packages,
+    you must reflect this in the directory hierarchy under
+    <code>/WEB-INF/classes/</code>.  For example, a Java class named
+    <code>com.mycompany.mypackage.MyServlet</code>
+    would need to be stored in a file named
+    <code>/WEB-INF/classes/com/mycompany/mypackage/MyServlet.class</code>.
+    <br/><br/></li>
+<li><strong>/WEB-INF/lib/</strong> - This directory contains JAR files that
+    contain Java class files (and associated resources) required for your
+    application, such as third party class libraries or JDBC drivers.</li>
+</ul>
+
+<p>When you install an application into Tomcat (or any other
+2.2/2.3-compatible server), the classes in the <code>WEB-INF/classes/</code>
+directory, as well as all classes in JAR files found in the
+<code>WEB-INF/lib/</code> directory, are made visible to other classes
+within your particular web application.  Thus, if
+you include all of the required library classes in one of these places (be
+sure to check licenses for redistribution rights for any third party libraries
+you utilize), you will simplify the installation of your web application --
+no adjustment to the system class path (or installation of global library
+files in your server) will be necessary.</p>
+
+<p>Much of this information was extracted from Chapter 9 of the Servlet
+API Specification, version 2.3, which you should consult for more details.</p>
+
+</section>
+
+
+<section name="Shared Library Files">
+
+<p>Like most servlet containers, Tomcat 5 also supports mechanisms to install
+library JAR files (or unpacked classes) once, and make them visible to all
+installed web applications (without having to be included inside the web
+application itself.  The details of how Tomcat locates and shares such
+classes are described in the
+<a href="../class-loader-howto.html">Class Loader HOW-TO</a> documentation.
+For the purposes of our discussion, there are two locations that are commonly
+used within a Tomcat 5 installation for shared code:</p>
+<ul>
+<li><strong>$CATALINA_HOME/common/lib</strong> - JAR files placed here are
+    visible both to web applications and internal Tomcat code.  This is a
+    good place to put JDBC drivers that are required for both your application
+    and internal Tomcat use (such as for a JDBCRealm).
+    <br/><br/></li>
+<li><strong>$CATALINA_BASE/shared/lib</strong> - JAR files placed here are
+    visible to all web applications, but not to internal Tomcat code.  This
+    is the right place for shared libraries that are specific to your
+    application.<br/><br/></li>
+</ul>
+
+<p>Out of the box, a standard Tomcat 5 installation includes a variety
+of pre-installed shared library files, including:</p>
+<ul>
+<li>The <em>Servlet 2.4</em> and <em>JSP 2.0</em> APIs that are fundamental
+    to writing servlets and JavaServer Pages.<br/><br/></li>
+<li>An <em>XML Parser</em> compliant with the JAXP (version 1.2) APIs, so
+    your application can perform DOM-based or SAX-based processing of
+    XML documents.<br/><br/></li>
+</ul>
+
+</section>
+
+
+<section name="Web Application Deployment Descriptor">
+
+    <blockquote><em>
+    <p>The description below uses the variable name $CATALINA_HOME
+    to refer to the directory into which you have installed Tomcat 5,
+    and is the base directory against which most relative paths are
+    resolved.  However, if you have configured Tomcat 5 for multiple
+    instances by setting a CATALINA_BASE directory, you should use
+    $CATALINA_BASE instead of $CATALINA_HOME for each of these
+    references.</p>
+    </em></blockquote>
+
+<p>As mentioned above, the <code>/WEB-INF/web.xml</code> file contains the
+Web Application Deployment Descriptor for your application.  As the filename
+extension implies, this file is an XML document, and defines everything about
+your application that a server needs to know (except the <em>context path</em>,
+which is assigned by the system administrator when the application is
+deployed).</p>
+
+<p>The complete syntax and semantics for the deployment descriptor is defined
+in Chapter 13 of the Servlet API Specification, version 2.3.  Over time, it
+is expected that development tools will be provided that create and edit the
+deployment descriptor for you.  In the meantime, to provide a starting point,
+a <a href="web.xml.txt" target="_new">basic web.xml file</a>
+is provided.  This file includes comments that describe the purpose of each
+included element.</p>
+
+<p><strong>NOTE</strong> - The Servlet Specification includes a Document
+Type Descriptor (DTD) for the web application deployment descriptor, and
+Tomcat 5 enforces the rules defined here when processing your application's
+<code>/WEB-INF/web.xml</code> file.  In particular, you <strong>must</strong>
+enter your descriptor elements (such as <code>&lt;filter&gt;</code>,
+<code>&lt;servlet&gt;</code>, and <code>&lt;servlet-mapping&gt;</code> in
+the order defined by the DTD (see Section 13.3).</p>
+
+</section>
+
+
+<section name="Tomcat Context Descriptor">
+
+    <blockquote><em>
+    <p>The description below uses the variable name $CATALINA_HOME
+    to refer to the directory into which you have installed Tomcat 5,
+    and is the base directory against which most relative paths are
+    resolved.  However, if you have configured Tomcat 5 for multiple
+    instances by setting a CATALINA_BASE directory, you should use
+    $CATALINA_BASE instead of $CATALINA_HOME for each of these
+    references.</p>
+    </em></blockquote>
+
+<p>A /META-INF/context.xml file can be used to define Tomcat specific
+configuration options, such as loggers, data sources, session manager
+configuration and more. This XML file must contain one Context element, which
+will be considered as if it was the child of the Host element corresponding
+to the Host to which the  The Tomcat configuration documentation contains
+information on the Context element.</p>
+
+</section>
+
+
+<section name="Deployment With Tomcat 5">
+
+<p>In order to be executed, a web application must be deployed on
+a servlet container.  This is true even during development.
+We will describe using Tomcat 5 to provide the execution environment.
+A web application can be deployed in Tomcat by one of the following
+approaches:</p>
+<ul>
+<li><em>Copy unpacked directory hierarchy into a subdirectory in directory
+    <code>$CATALINA_HOME/webapps/</code></em>.  Tomcat will assign a
+    context path to your application based on the subdirectory name you
+    choose.  We will use this technique in the <code>build.xml</code>
+    file that we construct, because it is the quickest and easiest approach
+    during development.  Be sure to restart Tomcat after installing or
+    updating your application.
+    <br/><br/></li>
+<li><em>Copy the web application archive file into directory
+    <code>$CATALINA_HOME/webapps/</code></em>.  When Tomcat is started, it will
+    automatically expand the web application archive file into its unpacked
+    form, and execute the application that way.  This approach would typically
+    be used to install an additional application, provided by a third party
+    vendor or by your internal development staff, into an existing
+    Tomcat installation.  <strong>NOTE</strong> - If you use this approach,
+    and wish to update your application later, you must both replace the
+    web application archive file <strong>AND</strong> delete the expanded
+    directory that Tomcat created, and then restart Tomcat, in order to reflect
+    your changes.
+    <br/><br/></li>
+<li><em>Use the Tomcat 5 "Manager" web application to deploy and undeploy
+    web applications</em>.  Tomcat 5 includes a web application, deployed
+    by default on context path <code>/manager</code>, that allows you to
+    deploy and undeploy applications on a running Tomcat server without
+    restarting it.  See the administrator documentation (TODO: hyperlink)
+    for more information on using the Manager web application.<br/><br/></li>
+<li><em>Use "Manager" Ant Tasks In Your Build Script</em>.  Tomcat 5
+    includes a set of custom task definitions for the <code>Ant</code>
+    build tool that allow you to automate the execution of commands to the
+    "Manager" web application.  These tasks are used in the Tomcat deployer.
+    <br/><br/></li>
+<li><em>Use the Tomcat Deployer</em>.  Tomcat 5 includes a packaged tool
+    bundling the Ant tasks, and can be used to automatically precompile JSPs
+    which are part of the web application before deployment to the server.
+    <br/><br/></li>
+</ul>
+
+<p>Deploying your app on other servlet containers will be specific to each
+container, but all containers compatible with the Servlet API Specification
+(version 2.2 or later) are required to accept a web application archive file.
+Note that other containers are <strong>NOT</strong> required to accept an
+unpacked directory structure (as Tomcat does), or to provide mechanisms for
+shared library files, but these features are commonly available.</p>
+
+</section>
+
+
+</body>
+</document>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/appdev/index.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/appdev/index.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/appdev/index.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,63 @@
+<?xml version="1.0"?>
+<!DOCTYPE document [
+  <!ENTITY project SYSTEM "project.xml">
+]>
+<document url="index.html">
+
+  &project;
+
+  <properties>
+    <author email="craigmcc at apache.org">Craig R. McClanahan</author>
+    <title>Table of Contents</title>
+  </properties>
+
+<body>
+
+
+<section name="Preface">
+
+<p>This manual includes contributions from many members of the Tomcat Project
+developer community.  The following authors have provided significant content:
+</p>
+<ul>
+<li>Craig R. McClanahan
+    (<a href="mailto:craigmcc at apache.org">craigmcc at apache.org</a>)</li>
+</ul>
+
+</section>
+
+
+<section name="Table of Contents">
+
+<p>The information presented is divided into the following sections:</p>
+<ul>
+<li><a href="introduction.html"><strong>Introduction</strong></a> -
+    Briefly describes the information covered here, with
+    links and references to other sources of information.</li>
+<li><a href="installation.html"><strong>Installation</strong></a> -
+    Covers acquiring and installing the required software
+    components to use Tomcat for web application development.</li>
+<li><a href="deployment.html"><strong>Deployment Organization</strong></a> -
+    Discusses the standard directory layout for a web application
+    (defined in the Servlet API Specification), the Web Application
+    Deployment Descriptor, and options for integration with Tomcat
+    in your development environment.</li>
+<li><a href="source.html"><strong>Source Organization</strong></a> -
+    Describes a useful approach to organizing the source code
+    directories for your project, and introduces the
+    <code>build.xml</code> used by Ant to manage compilation.</li>
+<li><a href="processes.html"><strong>Development Processes</strong></a> -
+    Provides brief descriptions of typical development processes
+    utilizing the recommended deployment and source organizations.</li>
+<li><a href="sample/" target="_new"><strong>Example Application</strong></a> -
+    This directory contains a very simple, but functionally complete,
+    "Hello, World" application built according to the principles
+    described in this manual.  You can use this application to
+    practice using the described techniques.</li>
+</ul>
+
+</section>
+
+
+</body>
+</document>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/appdev/installation.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/appdev/installation.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/appdev/installation.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,89 @@
+<?xml version="1.0"?>
+<!DOCTYPE document [
+  <!ENTITY project SYSTEM "project.xml">
+]>
+<document url="installation.html">
+
+  &project;
+
+  <properties>
+    <author email="craigmcc at apache.org">Craig R. McClanahan</author>
+    <author email="yoavs at apache.org">Yoav Shapira</author>
+    <title>Installation</title>
+  </properties>
+
+<body>
+
+
+<section name="Installation">
+
+<p>In order to use Tomcat 5 for developing web applications, you must first
+install it (and the software it depends on).  The required steps are outlined
+in the following subsections.</p>
+
+<subsection name="JDK">
+
+<p>Tomcat 5.5 was designed to run on J2SE 5.0, but it can run on JDK 1.4
+as well, using the compatability package as detailed in the Tomcat 
+installation instructions.
+</p>
+
+<p>Compatible JDKs for many platforms (or links to where they can be found)
+are available at
+<a href="http://java.sun.com/j2se/">http://java.sun.com/j2se/</a>.</p>
+
+</subsection>
+
+<subsection name="Tomcat">
+
+<p>Binary downloads of the <strong>Tomcat</strong> server are available from
+<a href="http://tomcat.apache.org/download-55.cgi">http://tomcat.apache.org/download-55.cgi</a>.
+This manual assumes you are using the most recent release
+of Tomcat 5.  Detailed instructions for downloading and installing
+Tomcat 5 are available <a href="../setup.html">here</a>.</p>
+
+<p>In the remainder of this manual, example shell scripts assume that you have
+set an environment variable <code>CATALINA_HOME</code> that contains the
+pathname to the directory in which Tomcat 5 has been installed.</p>
+
+</subsection>
+
+
+<subsection name="Ant">
+
+<p>Binary downloads of the <strong>Ant</strong> build tool are available from
+<a href="http://ant.apache.org/bindownload.cgi">http://ant.apache.org/bindownload.cgi</a>.
+This manual assumes you are using Ant 1.4 or later.  The instructions should
+also be compatible with later versions, but this has not been tested.</p>
+
+<p>Download and install Ant from the distribution directory mentioned above.
+Then, add the <code>bin</code> directory of the Ant distribution to your
+<code>PATH</code> environment variable, following the standard practices for
+your operating system platform.  Once you have done this, you will be able to
+execute the <code>ant</code> shell command directly.</p>
+
+</subsection>
+
+
+<subsection name="CVS">
+
+<p>Besides the required tools described above, you are strongly encouraged
+to download and install a <em>source code control</em> system, such as the
+<strong>Concurrent Version System</strong> (CVS), to maintain historical
+versions of the source files that make up your web application.  Besides
+the server, you will also need appropriate client
+tools to check out source code files, and check in modified versions.</p>
+
+<p>Detailed instructions for installing and using source code control
+applications is beyond the scope of this manual.  However, CVS server and
+client tools for many platforms (along with documentation) can be downloaded
+from <a href="http://www.cvshome.org">http://www.cvshome.org</a>.</p>
+
+</subsection>
+
+
+</section>
+
+
+</body>
+</document>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/appdev/introduction.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/appdev/introduction.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/appdev/introduction.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,84 @@
+<?xml version="1.0"?>
+<!DOCTYPE document [
+  <!ENTITY project SYSTEM "project.xml">
+]>
+<document url="introduction.html">
+
+  &project;
+
+  <properties>
+    <author email="craigmcc at apache.org">Craig R. McClanahan</author>
+    <title>Introduction</title>
+  </properties>
+
+<body>
+
+
+<section name="Overview">
+
+<p>Congratulations!  You've decided to (or been told to) learn how to
+build web applications using servlets and JSP pages, and picked the
+Tomcat server to use for your learning and development.  But now what
+do you do?</p>
+
+<p>This manual is a primer covering the basic steps of using Tomcat to
+set up a development environment, organize your source code, and then
+build and test your application.  It does not discuss architectures or
+recommended coding practices for web application development,
+or provide in depth instructions on operating the development
+tools that are discussed.  References to sources of additional information
+are included in the following subsections.</p>
+
+<p>The discussion in this manual is aimed at developers who will be using
+a text editor along with command line tools to develop and debug their
+applications.  As such, the recommendations are fairly generic -- but you
+should easily be able to apply them in either a Windows-based or Unix-based
+development environment.  If you are utilizing an Interactive Development
+Environment (IDE) tool, you will need to adapt the advice given here to
+the details of your particular environment.</p>
+
+</section>
+
+
+<section name="Links">
+
+<p>The following links provide access to selected sources of online
+information, documentation, and software that is useful in developing
+web applications with Tomcat.</p>
+<ul>
+<li><a href="http://java.sun.com/products/jsp/download.html">http://java.sun.com/products/jsp/download.html</a> -
+    <i>JavaServer Pages (JSP) Specfication, Version 2.0</i>.  Describes
+    the programming environment provided by standard implementations
+    of the JavaServer Pages (JSP) technology.  In conjunction with
+    the Servlet API Specification (see below), this document describes
+    what a portable API page is allowed to contain.  Specific
+    information on scripting (Chapter 6), tag extensions (Chapter 7),
+    and packaging JSP pages (Appendix A) is useful.  The Javadoc
+    API Documentation is included in the specification, and with the
+    Tomcat download.<br/><br/></li>
+<li><a href="http://java.sun.com/products/servlet/download.html">http://java.sun.com/products/servlet/download.html</a> -
+    <i>Servlet API Specification, Version 2.4</i>.  Describes the
+    programming environment that must be provided by all servlet
+    containers conforming to this specification.  In particular, you
+    will need this document to understand the web application
+    directory structure and deployment file (Chapter 9), methods of
+    mapping request URIs to servlets (Chapter 11), container managed
+    security (Chapter 12), and the syntax of the <code>web.xml</code>
+    Web Application Deployment Descriptor (Chapter 13).  The Javadoc
+    API Documentation is included in the specification, and with the
+    Tomcat download.<br/><br/></li>
+<li><a href="http://java.sun.com/j2ee/blueprints/">http://java.sun.com/j2ee/blueprints/</a> -
+    <i>Sun BluePrints (tm) Design Guidelines for J2EE</i>.  Comprehensive
+    advice and examples on application design for the Java2 Enterprise
+    Edition (J2EE) platform, which includes servlets and JSP pages.  The
+    chapters on servlet and JSP design are useful even when your application
+    does not require other J2EE platform components.
+    <br/><br/></li>
+<li><b>TODO</b> -- Add more entries here!</li>
+</ul>
+
+</section>
+
+
+</body>
+</document>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/appdev/processes.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/appdev/processes.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/appdev/processes.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,299 @@
+<?xml version="1.0"?>
+<!DOCTYPE document [
+  <!ENTITY project SYSTEM "project.xml">
+]>
+<document url="processes.html">
+
+  &project;
+
+  <properties>
+    <author email="craigmcc at apache.org">Craig R. McClanahan</author>
+    <title>Development Processes</title>
+  </properties>
+
+<body>
+
+
+<section name="Development Processes">
+
+<p>Although application development can take many forms, this manual proposes
+a fairly generic process for creating web applications using Tomcat.  The
+following sections highlight the commands and tasks that you, as the developer
+of the code, will perform.  The same basic approach works when you have
+multiple programmers involved, as long as you have an appropriate source code
+control system and internal team rules about who is working on what parts
+of the application at any given time.</p>
+
+<p>The task descriptions below assume that you will be using CVS for source
+code control, and that you have already configured access to the appropriate
+CVS repository.  Instructions for doing this are beyond the scope of this
+manual.  If you are using a different source code control environment, you
+will need to figure out the corresponding commands for your system.</p>
+
+
+<subsection name="One-Time Setup of Ant and Tomcat for Development">
+
+<p>In order to take advantage of the special Ant tasks that interact with the
+<em>Manager</em> web application, you need to perform the following tasks
+once (no matter how many web applications you plan to develop).</p>
+<ul>
+<li><em>Configure the Ant custom tasks</em>.  The implementation code for the
+    Ant custom tasks is in a JAR file named
+    <code>$CATALINA_HOME/server/lib/catalina-ant.jar</code>, which must be
+    copied in to the <code>lib</code> directory of your Ant installation.
+    <br/><br/></li>
+<li><em>Define one or more Tomcat users</em>.  The <em>Manager</em> web
+    application runs under a security constraint that requires a user to be
+    logged in, and have the security role <code>manager</code> assigned to
+    him or her.  How such users are defined depends on which Realm you have
+    configured in Tomcat's <code>conf/server.xml</code> file -- see the
+    <a href="../realm-howto.html">Realm Configuration HOW-TO</a> for more
+    information.  You may define any number of users (with any username
+    and password that you like) with the <code>manager</code> role.
+    <br/><br/></li>
+</ul>
+
+</subsection>
+
+
+<subsection name="Create Project Source Code Directory">
+
+<p>The first step is to create a new project source directory, and customize
+the <code>build.xml</code> and <code>build.properties</code> files you will
+be using.  The directory structure is described in <a href="source.html">the
+previous section</a>, or you can use the
+<a href="sample/">sample application</a> as a starting point.</p>
+
+<p>Create your project source directory, and define it within your CVS
+repository.  This might be done by a series of commands like this, where
+<code>{project}</code> is the name under which your project should be
+stored in the CVS repository, and {username} is your login username:</p>
+<source>
+cd {my home directory}
+mkdir myapp	&lt;-- Assumed "project source directory"
+cd myapp
+mkdir docs
+mkdir src
+mkdir web
+mkdir web/WEB-INF
+cvs import -m "Initial Project Creation" {project} \
+	{username} start
+</source>
+
+<p>Now, to verify that it was created correctly in CVS, we will perform a
+checkout of the new project:</p>
+<source>
+cd ..
+mv myapp myapp.bu
+cvs checkout {project}
+</source>
+
+<p>Next, you will need to create and check in an initial version of the
+<code>build.xml</code> script to be used for development.  For getting
+started quickly and easily, base your <code>build.xml</code> on the
+<a href="build.xml.txt">basic build.xml file</a>, included with this manual,
+or code it from scratch.</p>
+<source>
+cd {my home directory}
+cd myapp
+emacs build.xml		&lt;-- if you want a real editor :-)
+cvs add build.xml
+cvs commit
+</source>
+
+<p>Until you perform the CVS commit, your changes are local to your own
+development directory.  Committing makes those changes visible to other
+developers on your team that are sharing the same CVS repository.</p>
+
+<p>The next step is to customize the Ant <em>properties</em> that are
+named in the <code>build.xml</code> script.  This is done by creating a
+file named <code>build.properties</code> in your project's top-level
+directory.  The supported properties are listed in the comments inside
+the sample <code>build.xml</code> script.  At a minimum, you will generally
+need to define the <code>catalina.home</code> property defining where
+Tomcat 5 is installed, and the manager application username and password.
+You might end up with something like this:</p>
+<source>
+# Context path to install this application on
+app.path=/hello
+
+# Tomcat 5 installation directory
+catalina.home=/usr/local/apache-tomcat-5.5
+
+# Manager webapp username and password
+manager.username=myusername
+manager.password=mypassword
+</source>
+
+<p>In general, you will <strong>not</strong> want to check the
+<code>build.properties</code> file in to the CVS repository, because it
+is unique to each developer's environment.</p>
+
+<p>Now, create the initial version of the web application deployment
+descriptor.  You can base <code>web.xml</code> on the
+<a href="web.xml.txt">basic web.xml file</a>, or code it from scratch.</p>
+<source>
+cd {my home directory}
+cd myapp/web/WEB-INF
+emacs web.xml
+cvs add web.xml
+cvs commit
+</source>
+
+Note that this is only an example web.xml file.  The full definition
+of the deployment descriptor file is in the
+<a href="http://java.sun.com/products/servlet">Servlet Specification.</a>
+
+</subsection>
+
+
+<subsection name="Edit Source Code and Pages">
+
+<p>The edit/build/test tasks will generally be your most common activities
+during development and maintenance.  The following general principles apply.
+As described in <a href="source.html">Source Organization</a>, newly created
+source files should be located in the appropriate subdirectory, under your
+project source directory.</p>
+
+<p>Whenever you wish to refresh your development directory to reflect the
+work performed by other developers, you will ask CVS to do it for you:</p>
+<source>
+cd {my home directory}
+cd myapp
+cvs update -dP
+</source>
+
+<p>To create a new file, go to the appropriate directory, create the file,
+and register it with CVS.  When you are satisfied with it's contents (after
+building and testing is successful), commit the new file to the repository.
+For example, to create a new JSP page:</p>
+<source>
+cd {my home directory}
+cd myapp/web		&lt;-- Ultimate destination is document root
+emacs mypage.jsp
+cvs add mypage.jsp
+... build and test the application ...
+cvs commit
+</source>
+
+<p>Java source code that is defined in packages must be organized in a
+directory hierarchy (under the <strong>src/</strong> subdirectory) that
+matches the package names.  For example, a Java class named
+<code>com.mycompany.mypackage.MyClass.java</code> should be stored in file
+<code>src/com/mycompany/mypackage/MyClass.java</code>.
+Whenever you create a new subdirectory, don't forget to
+register it with CVS.</p>
+
+<p>To edit an existing source file, you will generally just start editing
+and testing, then commit the changed file when everything works.  Although
+CVS can be configured to required you to "check out" or "lock" a file you
+are going to be modifying, this is generally not used.</p>
+
+</subsection>
+
+
+<subsection name="Build the Web Application">
+
+<p>When you are ready to compile the application, issue the following
+commands (generally, you will want a shell window open that is set to
+the project source directory, so that only the last command is needed):</p>
+<source>
+cd {my home directory}
+cd myapp		&lt;-- Normally leave a window open here
+ant
+</source>
+
+<p>The Ant tool will be execute the default "compile" target in your
+<code>build.xml</code> file, which will compile any new or updated Java
+code.  If this is the first time you compile after a "build clean",
+it will cause everything to be recompiled.</p>
+
+<p>To force the recompilation of your entire application, do this instead:</p>
+<source>
+cd {my home directory}
+cd myapp
+ant all
+</source>
+
+<p>This is a very good habit immediately before checking in changes, to
+make sure that you have not introduced any subtle problems that Javac's
+conditional checking did not catch.</p>
+
+</subsection>
+
+
+<subsection name="Test Your Web Application">
+
+<p>To test your application, you will want to install it under Tomcat.  The
+quickest way to do that is to use the custom Ant tasks that are included in
+the sample <code>build.xml</code> script.  Using these commands might follow
+a pattern like this:</p>
+<ul>
+<li><em>Start Tomcat 5 if needed</em>.  If Tomcat 5 is not already running,
+    you will need to start it in the usual way.
+    <br/><br/></li>
+<li><em>Compile your application</em>.  Use the <code>ant compile</code>
+    command (or just <code>ant</code>, since this is the default).  Make
+    sure that there are no compilation errors.
+    <br/><br/></li>
+<li><em>Install the application</em>.  Use the <code>ant install</code>
+    command.  This tells Tomcat to immediately start running your app on
+    the context path defined in the <code>app.path</code> build property.
+    Tomcat does <strong>NOT</strong> have to be restarted for this to
+    take effect.<br/><br/></li>
+<li><em>Test the application</em>.  Using your browser or other testing
+    tools, test the functionality of your application.
+    <br/><br/></li>
+<li><em>Modify and rebuild as needed</em>.  As you discover that changes
+    are required, make those changes in the original <strong>source</strong>
+    files, not in the output build directory, and re-issue the
+    <code>ant compile</code> command.  This ensures that your changes will
+    be available to be saved (via <code>cvs commit</code>) later on --
+    the output build directory is deleted and recreated as necessary.
+    <br/><br/></li>
+<li><em>Reload the application</em>.  Tomcat will recognize changes in
+    JSP pages automatically, but it will continue to use the old versions
+    of any servlet or JavaBean classes until the application is reloaded.
+    You can trigger this by executing the <code>ant reload</code> command.
+    <br/><br/></li>
+<li><em>Remove the application when you re done</em>.  When you are through
+    working on this application, you can remove it from live execution by
+    running the <code>ant remove</code> command.</li>
+</ul>
+
+<p>Do not forget to commit your changes to the source code repository when
+you have completed your testing!</p>
+
+</subsection>
+
+
+<subsection name="Creating a Release">
+
+<p>When you are through adding new functionality, and you've tested everything
+(you DO test, don't you :-), it is time to create the distributable version
+of your web application that can be deployed on the production server.  The
+following general steps are required:</p>
+<ul>
+<li>Issue the command <code>ant all</code> from the project source
+    directory, to rebuild everything from scratch one last time.
+    <br/><br/></li>
+<li>Use the <code>cvs tag</code> command to create an identifier for
+    all of the source files utilized to create this release.  This allows
+    you to reliably reconstruct a release (from sources) at a later
+    time.</li>
+<li>Issue the command <code>ant dist</code> to create a distributable
+    web application archive (WAR) file, as well as a JAR file containing
+    the corresponding source code.
+    <br/><br/></li>
+<li>Package the contents of the <code>dist</code> directory using the
+    <strong>tar</strong> or <strong>zip</strong> utility, according to
+    the standard release procedures used by your organization.</li>
+</ul>
+
+</subsection>
+
+
+</section>
+
+</body>
+</document>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/appdev/project.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/appdev/project.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/appdev/project.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<project name="Application Developer's Guide"
+        href="http://apache.apache.org/">
+
+    <title>Application Developer's Guide</title>
+
+    <logo href="/images/tomcat.gif">
+      The Tomcat Servlet/JSP Container
+    </logo>
+
+    
+    <body>
+
+    <menu name="Links">
+        <item name="Docs Home"             href="../index.html"/>
+    </menu>
+
+    <menu name="Contents">
+        <item name="Contents"              href="index.html"/>
+        <item name="Introduction"          href="introduction.html"/>
+        <item name="Installation"          href="installation.html"/>
+        <item name="Deployment"            href="deployment.html"/>
+        <item name="Source Code"           href="source.html"/>
+        <item name="Processes"             href="processes.html"/>
+        <item name="Example App"           href="sample/"/>
+    </menu>
+
+    </body>
+</project>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/appdev/sample/docs/README.txt
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/appdev/sample/docs/README.txt	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/appdev/sample/docs/README.txt	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,2 @@
+This is a dummy README file for the sample
+web application.

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/appdev/sample/index.html
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/appdev/sample/index.html	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/appdev/sample/index.html	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,30 @@
+<html>
+<head>
+<meta name="author" content="Ben Souther" />
+<title>Sample Application</title>
+</head>
+<body>
+<h2>Sample Application</h2>
+      <p> 
+        The example app has been packaged as a war file and can be downloaded 
+        <a href="sample.war">here</a> (Note: make sure your browser doesn't 
+        change file extension or append a new one).
+      </p>
+      <p> 
+        The easiest way to run this application is simply to move the war file 
+        to your <b>CATALINA_HOME/webapps</b> directory. Tomcat will automatically 
+        expand and deploy the application for you. You can view it with the 
+        following URL (assuming that you're running tomcat on port 8080 
+        as is the default):
+        <br />
+        <a href="http://localhost:8080/sample">http://localhost:8080/sample</a>
+      </p>
+      <p>
+        If you just want to browse the code you can unpack the war file 
+        with the <b>jar</b> command.
+        <source>
+          jar -xvf sample.war
+        </source>
+      </p>
+</body>
+</html>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/appdev/sample/sample.war
===================================================================
(Binary files differ)


Property changes on: branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/appdev/sample/sample.war
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/appdev/sample/src/mypackage/Hello.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/appdev/sample/src/mypackage/Hello.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/appdev/sample/src/mypackage/Hello.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,95 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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 mypackage;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.Enumeration;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+
+/**
+ * Simple servlet to validate that the Hello, World example can
+ * execute servlets.  In the web application deployment descriptor,
+ * this servlet must be mapped to correspond to the link in the
+ * "index.html" file.
+ *
+ * @author Craig R. McClanahan <Craig.McClanahan at eng.sun.com>
+ */
+
+public final class Hello extends HttpServlet {
+
+
+    /**
+     * Respond to a GET request for the content produced by
+     * this servlet.
+     *
+     * @param request The servlet request we are processing
+     * @param response The servlet response we are producing
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception ServletException if a servlet error occurs
+     */
+    public void doGet(HttpServletRequest request,
+                      HttpServletResponse response)
+      throws IOException, ServletException {
+
+	response.setContentType("text/html");
+	PrintWriter writer = response.getWriter();
+
+	writer.println("<html>");
+	writer.println("<head>");
+	writer.println("<title>Sample Application Servlet Page</title>");
+	writer.println("</head>");
+	writer.println("<body bgcolor=white>");
+
+	writer.println("<table border=\"0\">");
+	writer.println("<tr>");
+	writer.println("<td>");
+	writer.println("<img src=\"images/tomcat.gif\">");
+	writer.println("</td>");
+	writer.println("<td>");
+	writer.println("<h1>Sample Application Servlet</h1>");
+	writer.println("This is the output of a servlet that is part of");
+	writer.println("the Hello, World application.  It displays the");
+	writer.println("request headers from the request we are currently");
+	writer.println("processing.");
+	writer.println("</td>");
+	writer.println("</tr>");
+	writer.println("</table>");
+
+	writer.println("<table border=\"0\" width=\"100%\">");
+	Enumeration names = request.getHeaderNames();
+	while (names.hasMoreElements()) {
+	    String name = (String) names.nextElement();
+	    writer.println("<tr>");
+	    writer.println("  <th align=\"right\">" + name + ":</th>");
+	    writer.println("  <td>" + request.getHeader(name) + "</td>");
+	    writer.println("</tr>");
+	}
+	writer.println("</table>");
+
+	writer.println("</body>");
+	writer.println("</html>");
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/appdev/sample/web/WEB-INF/web.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/appdev/sample/web/WEB-INF/web.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/appdev/sample/web/WEB-INF/web.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<web-app 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-app_2_4.xsd"
+    version="2.4">
+
+    <display-name>Hello, World Application</display-name>
+    <description>
+	This is a simple web application with a source code organization
+	based on the recommendations of the Application Developer's Guide.
+    </description>
+
+    <servlet>
+        <servlet-name>HelloServlet</servlet-name>
+        <servlet-class>mypackage.Hello</servlet-class>
+    </servlet>
+
+    <servlet-mapping>
+        <servlet-name>HelloServlet</servlet-name>
+        <url-pattern>/hello</url-pattern>
+    </servlet-mapping>
+
+</web-app>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/appdev/sample/web/hello.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/appdev/sample/web/hello.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/appdev/sample/web/hello.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,44 @@
+<html>
+<head>
+<title>Sample Application JSP Page</title>
+</head>
+<body bgcolor=white>
+
+<table border="0">
+<tr>
+<td align=center>
+<img src="images/tomcat.gif">
+</td>
+<td>
+<h1>Sample Application JSP Page</h1>
+This is the output of a JSP page that is part of the Hello, World
+application.  It displays several useful values from the request
+we are currently processing.
+</td>
+</tr>
+</table>
+
+<table border="0" border="100%">
+<tr>
+  <th align="right">Context Path:</th>
+  <td align="left"><%= request.getContextPath() %></td>
+</tr>
+<tr>
+  <th align="right">Path Information:</th>
+  <td align="left"><%= request.getPathInfo() %></td>
+</tr>
+<tr>
+  <th align="right">Query String:</th>
+  <td align="left"><%= request.getQueryString() %></td>
+</tr>
+<tr>
+  <th align="right">Request Method:</th>
+  <td align="left"><%= request.getMethod() %></td>
+</tr>
+<tr>
+  <th align="right">Servlet Path:</th>
+  <td align="left"><%= request.getServletPath() %></td>
+</tr>
+</table>
+</body>
+</html>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/appdev/sample/web/images/tomcat.gif
===================================================================
(Binary files differ)


Property changes on: branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/appdev/sample/web/images/tomcat.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/appdev/sample/web/index.html
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/appdev/sample/web/index.html	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/appdev/sample/web/index.html	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,28 @@
+<html>
+<head>
+<title>Sample "Hello, World" Application</title>
+</head>
+<body bgcolor=white>
+
+<table border="0">
+<tr>
+<td>
+<img src="images/tomcat.gif">
+</td>
+<td>
+<h1>Sample "Hello, World" Application</h1>
+<p>This is the home page for a sample application used to illustrate the
+source directory organization of a web application utilizing the principles
+outlined in the Application Developer's Guide.
+</td>
+</tr>
+</table>
+
+<p>To prove that they work, you can execute either of the following links:
+<ul>
+<li>To a <a href="hello.jsp">JSP page</a>.
+<li>To a <a href="hello">servlet</a>.
+</ul>
+
+</body>
+</html>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/appdev/source.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/appdev/source.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/appdev/source.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,306 @@
+<?xml version="1.0"?>
+<!DOCTYPE document [
+  <!ENTITY project SYSTEM "project.xml">
+]>
+<document url="source.html">
+
+  &project;
+
+  <properties>
+    <author email="craigmcc at apache.org">Craig R. McClanahan</author>
+    <title>Source Organization</title>
+  </properties>
+
+<body>
+
+
+<section name="Directory Structure">
+
+    <blockquote><em>
+    <p>The description below uses the variable name $CATALINA_HOME
+    to refer to the directory into which you have installed Tomcat 5,
+    and is the base directory against which most relative paths are
+    resolved.  However, if you have configured Tomcat 5 for multiple
+    instances by setting a CATALINA_BASE directory, you should use
+    $CATALINA_BASE instead of $CATALINA_HOME for each of these
+    references.</p>
+    </em></blockquote>
+
+<p>A key recommendation of this manual is to separate the directory
+hierarchy containing your source code (described in this section) from
+the directory hierarchy containing your deployable application
+(described in the preceding section).  Maintaining this separation has
+the following advantages:</p>
+<ul>
+<li>The contents of the source directories can be more easily administered,
+    moved, and backed up if the "executable" version of the application
+    is not intermixed.
+    <br/><br/></li>
+<li>Source code control is easier to manage on directories that contain
+    only source files.
+    <br/><br/></li>
+<li>The files that make up an installable distribution of your
+    application are much easier to select when the deployment
+    hierarchy is separate.</li>
+</ul>
+
+<p>As we will see, the <code>ant</code> development tool makes the creation
+and processing of such directory hierarchies nearly painless.</p>
+
+<p>The actual directory and file hierarchy used to contain the source code
+of an application can be pretty much anything you like.  However, the
+following organization has proven to be quite generally applicable, and is
+expected by the example <code>build.xml</code> configuration file that
+is discussed below.  All of these components exist under a top level
+<em>project source directory</em> for your application:</p>
+<ul>
+<li><strong>docs/</strong> - Documentation for your application, in whatever
+    format your development team is using.<br/><br/></li>
+<li><strong>src/</strong> - Java source files that generate the servlets,
+    beans, and other Java classes that are unique to your application.
+    If your source code is organized in packages (<strong>highly</strong>
+    recommended), the package hierarchy should be reflected as a directory
+    structure underneath this directory.<br/><br/></li>
+<li><strong>web/</strong> - The static content of your web site (HTML pages,
+    JSP pages, JavaScript files, CSS stylesheet files, and images) that will
+    be accessible to application clients.  This directory will be the
+    <em>document root</em> of your web application, and any subdirectory
+    structure found here will be reflected in the request URIs required to
+    access those files.<br/><br/></li>
+<li><strong>web/WEB-INF/</strong> - The special configuration files required
+    for your application, including the web application deployment descriptor
+    (<code>web.xml</code>, defined in the 
+    <a href="http://java.sun.com/products/servlet">Servlet Specification</a>), 
+    tag library descriptors for custom tag libraries
+    you have created, and other resource files you wish to include within
+    your web application.  Even though this directory appears to be a
+    subdirectory of your <em>document root</em>, the Servlet Specification
+    prohibits serving the contents of this directory (or any file it contains)
+    directly to a client request.  Therefore, this is a good place to store
+    configuration information that is sensitive (such as database connection
+    usernames and passwords), but is required for your application to
+    operate successfully.</li>
+</ul>
+
+<p>During the development process, two additional directories will be
+created on a temporary basis:</p>
+<ul>
+<li><strong>build/</strong> - When you execute a default build
+    (<code>ant</code>), this directory will contain an exact image
+    of the files in the web application archive for this application.
+    Tomcat 5 allows you to deploy an application in an unpacked
+    directory like this, either by copying it to the
+    <code>$CATALINA_HOME/webapps</code> directory, or by <em>installing</em>
+    it via the "Manager" web application.  The latter approach is very
+    useful during development, and will be illustrated below.
+    <br/><br/></li>
+<li><strong>dist/</strong> - When you execute the <code>ant dist</code>
+    target, this directory will be created.  It will create an exact image
+    of the binary distribution for your web application, including an license
+    information, documentation, and README files that you have prepared.</li>
+</ul>
+
+<p>Note that these two directories should <strong>NOT</strong> be archived in
+your source code control system, because they are deleted and recreated (from
+scratch) as needed during development.  For that reason, you should not edit
+any source files in these directories if you want to maintain a permanent
+record of the changes, because the changes will be lost the next time that a
+build is performed.</p>
+
+  <subsection name="External Dependencies">
+
+  <p>What do you do if your application requires JAR files (or other
+  resources) from external projects or packages?  A common example is that
+  you need to include a JDBC driver in your web application, in order to
+  operate.</p>
+
+  <p>Different developers take different approaches to this problem.
+  Some will encourage checking a copy of the JAR files you depend on into
+  the source code control archives for every application that requires those
+  JAR files.  However, this can cause significant management issues when you
+  use the same JAR in many applications - particular when faced with a need
+  to upgrade to a different version of that JAR file.</p>
+
+  <p>Therefore, this manual recommends that you <strong>NOT</strong> store
+  a copy of the packages you depend on inside the source control archives
+  of your applications.  Instead, the external dependencies should be
+  integrated as part of the process of <strong>building</strong> your
+  application.  In that way, you can always pick up the appropriate version
+  of the JAR files from wherever your development system administrator has
+  installed them, without having to worry about updating your application
+  every time the version of the dependent JAR file is changed.</p>
+
+  <p>In the example Ant <code>build.xml</code> file, we will demonstrate
+  how to define <em>build properties</em> that let you configure the locations
+  of the files to be copied, without having to modify <code>build.xml</code>
+  when these files change.  The build properties used by a particular
+  developer can be customized on a per-application basis, or defaulted to
+  "standard" build properties stored in the developer's home directory.</p>
+
+  <p>In many cases, your development system administrator will have already
+  installed the required JAR files into Tomcat 5's <code>common/lib</code>
+  or <code>shared/lib</code> directories.  If this has been done, you need
+  to take no actions at all - the example <code>build.xml</code> file
+  automatically constructs a compile classpath that includes these files.</p>
+
+  </subsection>
+
+</section>
+
+
+<section name="Source Code Control">
+
+<p>As mentioned earlier, it is highly recommended that you place all of the
+source files that comprise your application under the management of a
+source code control system like the Concurrent Version System (CVS).  If you
+elect to do this, every directory and file in the source hierarchy should be
+registered and saved -- but none of the generated files.  If you register
+binary format files (such as images or JAR libraries), be sure to indicate
+this to your source code control system.</p>
+
+<p>We recommended (in the previous section) that you should not store the
+contents of the <code>build/</code> and <code>dist/</code> directories
+created by your development process in the source code control system.  An
+easy way to tell CVS to ignore these directories is to create a file named
+<code>.cvsignore</code> (note the leading period) in your top-level source
+directory, with the following contents:</p>
+<source>
+build
+dist
+build.properties
+</source>
+
+<p>The reason for mentioning <code>build.properties</code> here will be
+explained in the <a href="processes.html">Processes</a> section.</p>
+
+<p>Detailed instructions for your source code control environment are beyond
+the scope of this manual.  However, the following steps are followed when
+using a command-line CVS client:</p>
+<ul>
+<li>To refresh the state of your source code to that stored in the
+    the source repository, go to your project source directory, and
+    execute <code>cvs update -dP</code>.
+    <br/><br/></li>
+<li>When you create a new subdirectory in the source code hierarchy, register
+    it in CVS with a command like <code>cvs add {subdirname}</code>.
+    <br/><br/></li>
+<li>When you first create a new source code file, navigate to the directory
+    that contains it, and register the new file with a command like
+    <code>cvs add {filename}</code>.
+    <br/><br/></li>
+<li>If you no longer need a particular source code file, navigate to the
+    containing directory and remove the file.  Then, deregister it in CVS
+    with a command like <code>cvs remove {filename}</code>.
+    <br/><br/></li>
+<li>While you are creating, modifying, and deleting source files, changes
+    are not yet reflected in the server repository.  To save your changes in
+    their current state, go to the project source directory
+    and execute <code>cvs commit</code>.  You will be asked to write a brief
+    description of the changes you have just completed, which will be stored
+    with the new version of any updated source file.</li>
+</ul>
+
+<p>CVS, like other source code control systems, has many additional features
+(such as the ability to tag the files that made up a particular release, and
+support for multiple development branches that can later be merged).  See the
+links and references in the <a href="introduction.html">Introduction</a> for
+more information.</p>
+
+</section>
+
+
+<section name="BUILD.XML Configuration File">
+
+<p>We will be using the <strong>ant</strong> tool to manage the compilation of
+our Java source code files, and creation of the deployment hierarchy.  Ant
+operates under the control of a build file, normally called
+<code>build.xml</code>, that defines the processing steps required.  This
+file is stored in the top-level directory of your source code hierarchy, and
+should be checked in to your source code control system.</p>
+
+<p>Like a Makefile, the <code>build.xml</code> file provides several
+"targets" that support optional development activities (such as creating
+the associated Javadoc documentation, erasing the deployment home directory
+so you can build your project from scratch, or creating the web application
+archive file so you can distribute your application.  A well-constructed
+<code>build.xml</code> file will contain internal documentation describing
+the targets that are designed for use by the developer, versus those targets
+used internally.  To ask Ant to display the project documentation, change to
+the directory containing the <code>build.xml</code> flie and type:</p>
+<source>
+ant -projecthelp
+</source>
+
+<p>To give you a head start, a <a href="build.xml.txt">basic build.xml file</a>
+is provided that you can customize and install in the project source directory
+for your application.  This file includes comments that describe the various
+targets that can be executed.  Briefly, the following targets are generally
+provided:</p>
+<ul>
+<li><strong>clean</strong> - This target deletes any existing
+    <code>build</code> and <code>dist</code> directories, so that they
+    can be reconstructed from scratch.  This allows you to guarantee that
+    you have not made source code modifications that will result in
+    problems at runtime due to not recompiling all affected classes.
+    <br/><br/></li>
+<li><strong>compile</strong> - This target is used to compile any source code
+    that has been changed since the last time compilation took place.  The
+    resulting class files are created in the <code>WEB-INF/classes</code>
+    subdirectory of your <code>build</code> directory, exactly where the
+    structure of a web application requires them to be.  Because
+    this command is executed so often during development, it is normally
+    made the "default" target so that a simple <code>ant</code> command will
+    execute it.
+    <br/><br/></li>
+<li><strong>all</strong> - This target is a short cut for running the
+    <code>clean</code> target, followed by the <code>compile</code> target.
+    Thus, it guarantees that you will recompile the entire application, to
+    ensure that you have not unknowingly introduced any incompatible changes.
+    <br/><br/></li>
+<li><strong>javadoc</strong> - This target creates Javadoc API documentation
+    for the Java classes in this web application.  The example
+    <code>build.xml</code> file assumes you want to include the API
+    documentation with your app distribution, so it generates the docs
+    in a subdirectory of the <code>dist</code> directory.  Because you normally
+    do not need to generate the Javadocs on every compilation, this target is
+    usually a dependency of the <code>dist</code> target, but not of the
+    <code>compile</code> target.
+    <br/><br/></li>
+<li><strong>dist</strong> - This target creates a distribution directory for
+    your application, including any required documentation, the Javadocs for
+    your Java classes, and a web application archive (WAR) file that will be
+    delivered to system administrators who wish to install your application.
+    Because this target also depends on the <code>deploy</code> target, the
+    web application archive will have also picked up any external dependencies
+    that were included at deployment time.</li>
+</ul>
+
+<p>For interactive development and testing of your web application using
+Tomcat 5, the following additional targets are defined:</p>
+<ul>
+<li><strong>install</strong> - Tell the currently running Tomcat 5 to make
+    the application you are developing immediately available for execution
+    and testing.  This action does not require Tomcat 5 to be restarted, but
+    it is also not remembered after Tomcat is restarted the next time.
+    <br/><br/></li>
+<li><strong>reload</strong> - Once the application is installed, you can
+    continue to make changes and recompile using the <code>compile</code>
+    target.  Tomcat 5 will automatically recognize changes made to JSP pages,
+    but not to servlet or JavaBean classes - this command will tell Tomcat
+    to restart the currently installed application so that such changes are
+    recognized.
+    <br/><br/></li>
+<li><strong>remove</strong> - When you have completed your development and
+    testing activities, you can optionally tell Tomcat 5 to remove this
+    application from service.
+    </li>
+</ul>
+
+<p>Using the development and testing targets requires some additional
+one-time setup that is described on the next page.</p>
+
+</section>
+
+
+</body>
+</document>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/appdev/web.xml.txt
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/appdev/web.xml.txt	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/appdev/web.xml.txt	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,150 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+
+<!DOCTYPE web-app 
+    PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" 
+    "http://java.sun.com/dtd/web-app_2_3.dtd">
+
+<web-app>
+
+
+    <!-- General description of your web application -->
+
+    <display-name>My Web Application</display-name>
+    <description>
+      This is version X.X of an application to perform
+      a wild and wonderful task, based on servlets and
+      JSP pages.  It was written by Dave Developer
+      (dave at mycompany.com), who should be contacted for
+      more information.
+    </description>
+
+
+    <!-- Context initialization parameters that define shared
+         String constants used within your application, which
+         can be customized by the system administrator who is
+         installing your application.  The values actually
+         assigned to these parameters can be retrieved in a
+         servlet or JSP page by calling:
+
+             String value =
+               getServletContext().getInitParameter("name");
+
+         where "name" matches the <param-name> element of
+         one of these initialization parameters.
+
+         You can define any number of context initialization
+         parameters, including zero.
+    -->
+
+    <context-param>
+      <param-name>webmaster</param-name>
+      <param-value>myaddress at mycompany.com</param-value>
+      <description>
+        The EMAIL address of the administrator to whom questions
+        and comments about this application should be addressed.
+      </description>
+    </context-param>
+
+
+    <!-- Servlet definitions for the servlets that make up
+         your web application, including initialization
+         parameters.  With Tomcat, you can also send requests
+         to servlets not listed here with a request like this:
+
+           http://localhost:8080/{context-path}/servlet/{classname}
+
+         but this usage is not guaranteed to be portable.  It also
+         makes relative references to images and other resources
+         required by your servlet more complicated, so defining
+         all of your servlets (and defining a mapping to them with
+         a servlet-mapping element) is recommended.
+
+         Servlet initialization parameters can be retrieved in a
+         servlet or JSP page by calling:
+
+             String value =
+               getServletConfig().getInitParameter("name");
+
+         where "name" matches the <param-name> element of
+         one of these initialization parameters.
+
+         You can define any number of servlets, including zero.
+    -->
+
+    <servlet>
+      <servlet-name>controller</servlet-name>
+      <description>
+        This servlet plays the "controller" role in the MVC architecture
+        used in this application.  It is generally mapped to the ".do"
+        filename extension with a servlet-mapping element, and all form
+        submits in the app will be submitted to a request URI like
+        "saveCustomer.do", which will therefore be mapped to this servlet.
+
+        The initialization parameter namess for this servlet are the
+        "servlet path" that will be received by this servlet (after the
+        filename extension is removed).  The corresponding value is the
+        name of the action class that will be used to process this request.
+      </description>
+      <servlet-class>com.mycompany.mypackage.ControllerServlet</servlet-class>
+      <init-param>
+        <param-name>listOrders</param-name>
+        <param-value>com.mycompany.myactions.ListOrdersAction</param-value>
+      </init-param>
+      <init-param>
+        <param-name>saveCustomer</param-name>
+        <param-value>com.mycompany.myactions.SaveCustomerAction</param-value>
+      </init-param>
+      <!-- Load this servlet at server startup time -->
+      <load-on-startup>5</load-on-startup>
+    </servlet>
+
+    <servlet>
+      <servlet-name>graph</servlet-name>
+      <description>
+        This servlet produces GIF images that are dynamically generated
+        graphs, based on the input parameters included on the request.
+        It is generally mapped to a specific request URI like "/graph".
+      </description>
+    </servlet>
+
+
+    <!-- Define mappings that are used by the servlet container to
+         translate a particular request URI (context-relative) to a
+         particular servlet.  The examples below correspond to the
+         servlet descriptions above.  Thus, a request URI like:
+
+           http://localhost:8080/{contextpath}/graph
+
+         will be mapped to the "graph" servlet, while a request like:
+
+           http://localhost:8080/{contextpath}/saveCustomer.do
+
+         will be mapped to the "controller" servlet.
+
+         You may define any number of servlet mappings, including zero.
+         It is also legal to define more than one mapping for the same
+         servlet, if you wish to.
+    -->
+
+    <servlet-mapping>
+      <servlet-name>controller</servlet-name>
+      <url-pattern>*.do</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+      <servlet-name>graph</servlet-name>
+      <url-pattern>/graph</url-pattern>
+    </servlet-mapping>
+
+
+    <!-- Define the default session timeout for your application,
+         in minutes.  From a servlet or JSP page, you can modify
+         the timeout for a particular session dynamically by using
+         HttpSession.getMaxInactiveInterval(). -->
+
+    <session-config>
+      <session-timeout>30</session-timeout>    <!-- 30 minutes -->
+    </session-config>
+
+
+</web-app>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/apr.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/apr.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/apr.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,331 @@
+<?xml version="1.0"?>
+<!DOCTYPE document [
+  <!ENTITY project SYSTEM "project.xml">
+]>
+<document url="apr.html">
+
+    &project;
+
+  <properties>
+    <title>Apache Portable Runtime and Tomcat</title>
+    <author>Remy Maucherat</author>
+  </properties>
+
+<body>
+
+  <section name="Introduction">
+
+  <p>
+      Tomcat can use the <a href="http://apr.apache.org/">Apache Portable Runtime</a> to 
+      provide superior scalability, performance, and better integration with native server 
+      technologies. The Apache Portable Runtime is a highly portable library that is at 
+      the heart of Apache HTTP Server 2.x. APR has many uses, including access to advanced IO
+      functionality (such as sendfile, epoll and OpenSSL), OS level functionality (random number
+      generation, system status, etc), and native process handling (shared memory, NT
+      pipes and Unix sockets).
+  </p>
+  
+  <p>
+      These features allows making Tomcat a general purpose webserver, will enable much better 
+      integration with other native web technologies, and overall make Java much more viable as
+      a full fledged webserver platform rather than simply a backend focused technology.
+  </p>
+
+  </section>
+
+  <section name="Installation">
+
+    <p>
+      APR support requires three main native components to be installed:
+      <ul>
+        <li>APR library</li>
+        <li>JNI wrappers for APR used by Tomcat (libtcnative)</li>
+        <li>OpenSSL libraries</li>
+      </ul>
+    </p>
+
+    <subsection name="Windows">
+    
+    <p>
+      Windows binaries are provided for tcnative-1, which is a statically compiled .dll which includes
+      OpenSSL and APR. It can be downloaded from <a href="http://tomcat.heanet.ie/native/">here</a>
+      as 32bit or AMD x86-64 binaries.
+      In security conscious production environments, it is recommended to use separate shared dlls
+      for OpenSSL, APR, and libtcnative-1, and update them as needed according to security bulletins.
+      Windows OpenSSL binaries are linked from the <a href="http://www.openssl.org">Official OpenSSL 
+      website</a> (see related/binaries).
+    </p>
+    
+    </subsection>
+    
+    <subsection name="Linux">
+    
+    <p>
+      Most Linux distributions will ship packages for APR and OpenSSL. The JNI wrapper (libtcnative) will 
+      then have to be compiled. It depends on APR, OpenSSL, and the Java headers.
+    </p>
+    
+    <p>
+      Requirements:
+      <ul>
+        <li>APR 1.2+ development headers (libapr1-dev package)</li>
+        <li>OpenSSL 0.9.7+ development headers (libssl-dev package)</li>
+        <li>JNI headers from Java compatible JDK 1.4+</li>
+        <li>GNU development environment (gcc, make)</li>
+      </ul>
+    </p>
+    
+    <p>
+      The wrapper library sources are located in the Tomcat binary bundle, in the 
+      <code>bin/tomcat-native.tar.gz</code> archive.
+      Once the build environment is installed and the source archive is extracted, the wrapper library 
+      can be compiled using (from the folder containing the configure script):
+      <source>./configure &amp;&amp; make &amp;&amp; make install</source>
+    </p>
+    
+    </subsection>
+	
+  </section>
+
+  <section name="APR Components">
+
+  <p>
+    Once the libraries are properly installed and available to Java (if loading fails, the library path
+    will be displayed), the Tomcat connectors will automatically use APR. Configuration of the connectors
+    is similar to the regular connectors, but have a few extra attributes which are used to configure
+    APR components. Note that the defaults should be well tuned for most use cases, and additional
+    tweaking shouldn't be required.
+  </p>
+
+  <p>
+    When APR is enabled, the following features are also enabled in Tomcat:
+    <ul>
+      <li>Secure session ID generation by default on all platforms (platforms other than Linux required
+          random number generation using a configured entropy)</li>
+      <li>OS level statistics on memory usage and CPU usage by the Tomcat process are displayed by
+          the status servlet</li>
+    </ul>
+  </p>
+
+  </section>
+
+  <section name="APR Connectors Configuration">
+
+    <subsection name="HTTP">
+    
+    <p>
+      When APR is enabled, the HTTP connector will use sendfile for hadling large static files (all such
+      files will be sent ansychronously using high performance kernel level calls), and will use 
+      a socket poller for keepalive, increasing scalability of the server.
+    </p>
+
+    <p>
+      The following attributes are supported in the HTTP APR connector in addition to the ones supported
+      in the regular HTTP connector:
+    </p>
+
+    <attributes>
+ 
+    <attribute name="firstReadTimeout" required="false">
+      <p>The first read of a request will be made using the specified timeout. If no data is available
+      after the specified time, the socket will be placed in the poller. The value of this attribute is
+      in ms. Setting this value to 0 or -1 will
+      increase scalability by always using a poller to handle keepalive, but will have a minor impact 
+      on latency (see the related pollTime attribute). The difference is that with 0, the first read of
+      a request will be made using a short timeout, while with -1, the first read will be made using the
+      regular socket timeout that is configured on the connector. Setting this to -2 will cause
+      the connector to not use the poller for keepalive in most situations, emulating the behavior of
+      the java.io HTTP connector.
+      The default value is -1. Note: on Windows, the actual value of firstReadTimeout will
+      be 500 + the specified value, if the specified value is strictly positive.</p>
+    </attribute>
+
+    <attribute name="pollTime" required="false">
+      <p>Duration of a poll call. Lowering this value will slightly decrease latency of connections 
+      being kept alive in some cases, but will use more CPU as more poll calls are being made. The
+      default value is 2000 (5ms).</p>
+    </attribute>
+
+    <attribute name="pollerSize" required="false">
+      <p>Amount of sockets that the poller responsible for polling kept alive connections can hold at a
+      given time. Extra connections will be closed right away. The default value is 8192, corresponding to
+      8192 keepalive connections.</p>
+    </attribute>
+
+    <attribute name="useSendfile" required="false">
+      <p>Use kernel level sendfile for certain static files. The default value is true.</p>
+    </attribute>
+
+    <attribute name="sendfileSize" required="false">
+      <p>Amount of sockets that the poller responsible for sending static files asynchronously can hold 
+      at a given time. Extra connections will be closed right away without any data being sent 
+      (resulting in a zero length file on the client side). Note that in most cases, sendfile is a call
+      that will return right away (being taken care of "synchonously" by the kernel), and the sendfile
+      poller will not be used, so the amount of static files which can be sent concurrently is much larger
+      than the specified amount. The default value is 1024.</p>
+    </attribute>
+
+    </attributes>
+    
+    </subsection>
+	
+    <subsection name="HTTPS">
+    
+    <p>
+      When APR is enabled, the HTTPS connector will use a socket poller for keepalive, increasing 
+      scalability of the server. It also uses OpenSSL, which may be more optimized than JSSE depending
+      on the processor being used, and can be complemented with many commercial accelerator components.
+      Unlike the HTTP connector, the HTTPS connector cannot use sendfile to optimize static file
+      processing.
+    </p>
+
+    <p>
+      The HTTPS APR connector has the same basic attributes than the HTTP APR connector, but adds 
+      OpenSSL specific ones. For the full details on using OpenSSL, please refer to OpenSSL documentations
+      and the many books available for it (see the <a href="http://www.openssl.org">Official OpenSSL 
+      website</a>). The SSL specific attributes for the connector are:
+    </p>
+    
+    <attributes>
+
+    <attribute name="SSLEngine" required="false">
+    <p>
+      Name of the SSLEngine to use. off: Do not use SSL, on: Use SSL but no specific ENGINE.
+      The default value is off.
+    </p>
+    </attribute>
+    <attribute name="SSLProtocol" required="false">
+    <p>
+      Protocol which may be used for communicating with clients. The default is "all", with
+      other acceptable values being "SSLv2", "SSLv3", "TLSv1", and "SSLv2+SSLv3".
+    </p>
+    </attribute>
+    <attribute name="SSLCipherSuite" required="false">
+    <p>
+      Ciphers which may be used for communicating with clients. The default is "ALL", with
+      other acceptable values being a list of ciphers, with ":" used as the delimiter
+      (see OpenSSL documentation for the list of ciphers supported).
+    </p>
+    </attribute>
+    <attribute name="SSLCertificateFile" required="true">
+    <p>
+      Name of the file that contains the server certificate. The format is PEM-encoded.
+    </p>
+    </attribute>
+    <attribute name="SSLCertificateKeyFile" required="false">
+    <p>
+      Name of the file that contains the server private key. The format is PEM-encoded.
+      The default value is the value of "SSLCertificateFile" and in this case both certificate
+      and private key have to be in this file (NOT RECOMMENDED).
+    </p>
+    </attribute>
+    <attribute name="SSLPassword" required="false">
+    <p>
+      Pass phrase for the encrypted private key. If "SSLPassword" is not provided, the callback fonction
+      should prompt for the pass phrase.
+    </p>
+    </attribute>
+    <attribute name="SSLVerifyClient" required="false">
+    <p>
+      Ask client for certificate. The default is "none", meaning the client will not have the opportunity
+      to submit a certificate. Other acceptable values include "optional", "require" and "optionalNoCA".
+    </p>
+    </attribute>
+    <attribute name="SSLVerifyDepth" required="false">
+    <p>
+      Maximum verification depth for client certificates. The default is "10".
+    </p>
+    </attribute>
+    <attribute name="SSLCACertificateFile" required="false">
+    <p>
+      See <a href="http://httpd.apache.org/docs/2.2/mod/mod_ssl.html#sslcacertificatefile">the mod_ssl documentation</a>.
+    </p>
+    </attribute>
+    <attribute name="SSLCACertificatePath" required="false">
+    <p>
+      See <a href="http://httpd.apache.org/docs/2.2/mod/mod_ssl.html#sslcacertificatepath">the mod_ssl documentation</a>.
+    </p>
+    </attribute>
+    <attribute name="SSLCertificateChainFile" required="false">
+    <p>
+      See <a href="http://httpd.apache.org/docs/2.2/mod/mod_ssl.html#sslcertificatechainfile">the mod_ssl documentation</a>.
+    </p>
+    </attribute>
+    <attribute name="SSLCARevocationFile" required="false">
+    <p>
+      See <a href="http://httpd.apache.org/docs/2.2/mod/mod_ssl.html#sslcarevocationfile">the mod_ssl documentation</a>.
+    </p>
+    </attribute>
+    <attribute name="SSLCARevocationPath" required="false">
+    <p>
+      See <a href="http://httpd.apache.org/docs/2.2/mod/mod_ssl.html#sslcarevocationpath">the mod_ssl documentation</a>.
+    </p>
+    </attribute>
+
+    </attributes>
+    
+    <p>
+    An example SSL Connector declaration can be:
+    <source>
+    &lt;Connector port="443" maxHttpHeaderSize="8192"
+               maxThreads="150" minSpareThreads="25" maxSpareThreads="75"
+               enableLookups="false" disableUploadTimeout="true"
+               acceptCount="100" scheme="https" secure="true"
+               SSLEngine="on" 
+               SSLCertificateFile="${catalina.base}/conf/localhost.crt"
+               SSLCertificateKeyFile="${catalina.base}/conf/localhost.key" /&gt;</source>
+    </p>
+    
+    </subsection>
+	
+    <subsection name="AJP">
+    
+    <p>
+      When APR is enabled, the AJP connector will use a socket poller for keepalive, increasing 
+      scalability of the server. As AJP is designed around a pool of persistent (or almost
+      persistent) connections, this will reduce significantly the amount of processing threads 
+      needed by Tomcat. Unlike the HTTP connector, the AJP connector cannot use sendfile to optimize
+      static file processing.
+    </p>
+
+    <p>
+      The following attributes are supported in the AJP APR connector in addition to the ones supported
+      in the regular AJP connector:
+    </p>
+
+    <attributes>
+ 
+    <attribute name="firstReadTimeout" required="false">
+      <p>The first read of a request will be made using the specified timeout. If no data is available
+      after the specified time, the socket will be placed in the poller. The value of this attribute is
+      in ms. Setting this value to 0 or -1 will
+      increase scalability by always using a poller to handle keepalive, but will have a minor impact 
+      on latency (see the related pollTime attribute). The difference is that with 0, the first read of
+      a request will be made using a short timeout, while with -1, the first read will be made using the
+      regular socket timeout that is configured on the connector. Setting this to -2 will cause
+      the connector to not use the poller for keepalive in most situations, emulating the behavior of
+      the java.io HTTP connector.
+      The default value is -1. Note: on Windows, the actual value of firstReadTimeout will
+      be 500 + the specified value, if the specified value is strictly positive.</p>
+    </attribute>
+
+    <attribute name="pollTime" required="false">
+      <p>Duration of a poll call. Lowering this value will slightly decrease latency of connections 
+      being kept alive in some cases, but will use more CPU as more poll calls are being made. The
+      default value is 2000 (5ms).</p>
+    </attribute>
+
+    <attribute name="pollerSize" required="false">
+      <p>Amount of sockets that the poller responsible for polling kept alive connections can hold at a
+      given time. Extra connections will be closed right away. The default value is 8192, corresponding to
+      8192 keepalive connections.</p>
+    </attribute>
+
+    </attributes>
+    
+    </subsection>
+	
+  </section>
+
+</body>
+</document>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/architecture/index.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/architecture/index.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/architecture/index.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,53 @@
+<?xml version="1.0"?>
+<!DOCTYPE document [
+  <!ENTITY project SYSTEM "project.xml">
+]>
+<document url="index.html">
+
+  &project;
+
+  <properties>
+    <author email="yoavs at apache.org">Yoav Shapira</author>
+    <title>Table of Contents</title>
+  </properties>
+
+<body>
+
+
+<section name="Preface">
+
+<p>This section of the Tomcat documentation attempts to explain
+the architecture and design of the Tomcat server.  It includes significant
+contributions from several tomcat developers:
+</p>
+<ul>
+<li>Yoav Shapira
+    (<a href="mailto:yoavs at apache.org">yoavs at apache.org</a>)</li>
+<li>Jeanfrancois Arcand
+    (<a href="mailto:jfarcand at apache.org">jfarcand at apache.org</a>)</li>
+<li>Filip Hanik
+    (<a href="mailto:fhanik at apache.org">fhanik at apache.org</a>)</li>
+</ul>
+
+</section>
+
+
+<section name="Table of Contents">
+
+<p>The information presented is divided into the following sections:</p>
+<ul>
+<li><a href="overview.html"><strong>Overview</strong></a> -
+    An overview of the Tomcat server architecture with key terms
+    and concepts.</li>
+<li><a href="startup.html"><strong>Server Startup</strong></a> -
+    A detailed description, with sequence diagrams, of how the Tomcat
+    server starts up.</li>
+<li><a href="requestProcess.html"><strong>Request Process Flow</strong></a> -
+    A detailed description of how Tomcat handles a request.</li>
+</ul>
+
+</section>
+
+
+</body>
+</document>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/architecture/overview.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/architecture/overview.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/architecture/overview.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,123 @@
+<?xml version="1.0"?>
+<!DOCTYPE document [
+  <!ENTITY project SYSTEM "project.xml">
+]>
+<document url="overview.html">
+
+  &project;
+
+  <properties>
+    <author email="yoavs at apache.org">Yoav Shapira</author>
+    <title>Architecture Overview</title>
+  </properties>
+
+<body>
+
+
+<section name="Overview">
+<p>
+This page provides an overview of the Tomcat server architecture.
+</p>
+</section>
+
+<section name="Terms">
+
+<subsection name="Server">
+<p>
+In the Tomcat world, a
+<a href="../config/server.html">Server</a> represents the whole container.
+Tomcat provides a default implementation of the 
+<a href="../catalina/docs/api/org/apache/catalina/Server.html">Server interface.</a>,
+and this is rarely customized by users.
+</p>
+</subsection>
+
+<subsection name="Service">
+<p>
+A <a href="../config/service.html">Service</a> is an intermediate component
+which lives inside a Server and ties one or more Connectors to exactly one
+Engine.  The Service element is rarely customized by users, as the default
+implementation is simple and sufficient:
+<a href="../catalina/docs/api/org/apache/catalina/Service.html">Service interface</a>.
+</p>
+</subsection>
+
+<subsection name="Engine">
+<p>
+An
+<a href="../config/engine.html">Engine</a> represents request processing
+pipeline for a specific Service.  As a Service may have multiple Connectors,
+the Engine received and processes all requests from these connectors, handing
+the response back to the appropriate connector for transmission to the client.
+The <a href="../catalina/docs/api/org/apache/catalina/Engine.html">Engine interface</a>
+may be implemented to supply custom Engines, though this is uncommon.
+</p>
+<p>
+Note that the Engine may be used for Tomcat server clustering via the
+jvmRoute parameter.  Read the Clustering documentation for more information.
+</p>
+</subsection>
+
+<subsection name="Host">
+<p>
+A <a href="../config/host.html">Host</a> is an association of a network name,
+e.g. www.yourcompany.com, to the Tomcat server.  An Engine may contain
+multiple hosts, and the Host element also supports network aliases such as
+yourcompany.com and abc.yourcompany.com.  Users rarely create custom
+<a href="../catalina/docs/api/org/apache/catalina/Host.html">Hosts</a>
+because the 
+<a href="../catalina/docs/api/org/apache/catalina/core/StandardHost.html">StandardHost
+implementation</a> provides significant additional functionality.
+</p>
+</subsection>
+
+<subsection name="Connector">
+<p>
+A Connector handles communications with the client.  There are multiple
+connectors available with Tomcat, all of which implement the 
+<a href="../catalina/docs/api/org/apache/catalina/Connector.html">Connector
+interface.</a>  These include the
+<a href="../config/coyote.html">Coyote connector</a> which is used for
+most HTTP traffic, especially when running Tomcat as a standalone server, 
+and the <a href="../config/jk2.html">JK2 connector</a> which implements
+the AJP procotol used when connecting Tomcat to an Apache HTTPD server.
+Creating a customized connector is a significant effort.
+</p>
+</subsection>
+
+<subsection name="Context">
+<p>
+A
+<a href="../config/context.html">Context</a>
+represents a web application.  A Host may contain multiple
+contexts, each with a unique path.  The
+<a href="../catalina/docs/api/org/apache/catalina/Context.html">Context
+interface</a> may be implemented to create custom Contexts, but
+this is rarely the case because the
+<a href="../catalina/docs/api/org/apache/catalina/core/StandardContext.html">
+StandardContext</a> provides significant additional functionality.
+</p>
+</subsection>
+</section>
+
+<section name="Comments">
+<p>
+Tomcat is designed to be a fast and efficient implementation of the
+Servlet Specification.  Tomcat came about as the reference implementation
+of this specification, and has remained rigorous in adhering to the
+specification.  At the same time, significant attention has been paid
+to Tomcat's performance and it is now on par with other servlet containers,
+including commercial ones.
+</p>
+<p>
+In recent releases of Tomcat, mostly starting with Tomcat 5,
+we have begun effots to make more aspects of Tomcat managable via
+JMX.  In addition, the Manager and Admin webapps have been greatly
+enhanced and improved.  Managability is a primary area of concern
+for us as the product matures and the specification becomes more
+stable.
+</p>
+</section>
+
+</body>
+</document>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/architecture/project.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/architecture/project.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/architecture/project.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<project name="Tomcat Architecture"
+        href="http://jakarta.apache.org/tomcat/">
+
+    <title>Tomcat Architecture</title>
+
+    <logo href="/images/tomcat.gif">
+      The Tomcat Servlet/JSP Container
+    </logo>
+
+    
+    <body>
+
+    <menu name="Links">
+        <item name="Docs Home"             href="../index.html" />
+    </menu>
+
+    <menu name="Contents">
+        <item name="Contents"              href="index.html" />
+        <item name="Overview"              href="overview.html" />
+        <item name="Server Startup"        href="startup.html" />
+        <item name="Request Process"       href="requestProcess.html" />
+    </menu>
+
+    </body>
+</project>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/architecture/requestProcess/requestProcess.pdf
===================================================================
(Binary files differ)


Property changes on: branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/architecture/requestProcess/requestProcess.pdf
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/architecture/requestProcess/roseModel.mdl
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/architecture/requestProcess/roseModel.mdl	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/architecture/requestProcess/roseModel.mdl	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,12921 @@
+
+(object Petal
+    version    	45
+    _written   	"Rose 7.6.0109.2314"
+    charSet    	0)
+
+(object Design "Logical View"
+    is_unit    	TRUE
+    is_loaded  	TRUE
+    quid       	"3DFDF6CE0337"
+    defaults   	(object defaults
+	rightMargin 	0.250000
+	leftMargin 	0.250000
+	topMargin  	0.250000
+	bottomMargin 	0.500000
+	pageOverlap 	0.250000
+	clipIconLabels 	TRUE
+	autoResize 	TRUE
+	snapToGrid 	TRUE
+	gridX      	16
+	gridY      	16
+	defaultFont 	(object Font
+	    size       	10
+	    face       	"Arial"
+	    bold       	FALSE
+	    italics    	FALSE
+	    underline  	FALSE
+	    strike     	FALSE
+	    color      	0
+	    default_color 	TRUE)
+	showMessageNum 	1
+	showClassOfObject 	TRUE
+	notation   	"Unified")
+    root_usecase_package 	(object Class_Category "Use Case View"
+	quid       	"3DFDF6CE0369"
+	exportControl 	"Public"
+	global     	TRUE
+	logical_models 	(list unit_reference_list)
+	logical_presentations 	(list unit_reference_list
+	    (object UseCaseDiagram "Main"
+		quid       	"3DFDF6D201FE"
+		title      	"Main"
+		zoom       	100
+		max_height 	28350
+		max_width  	21600
+		origin_x   	0
+		origin_y   	0
+		items      	(list diagram_item_list))))
+    root_category 	(object Class_Category "Logical View"
+	quid       	"3DFDF6CE0338"
+	exportControl 	"Public"
+	global     	TRUE
+	subsystem  	"Component View"
+	quidu      	"3DFDF6CE036A"
+	logical_models 	(list unit_reference_list
+	    (object Class_Category "org.apache.catalina"
+		quid       	"3E42DE8D0082"
+		visible_categories 	(list visibility_relationship_list
+		    (object Visibility_Relationship
+			quid       	"3E42DEF601EB"
+			supplier   	"Logical View::org.apache.tomcat.util"
+			quidu      	"3E42DEDF01F2")
+		    (object Visibility_Relationship
+			quid       	"3E42DF700060"
+			supplier   	"Logical View::org.apache.coyote"
+			quidu      	"3E42DE9F0132")
+		    (object Visibility_Relationship
+			quid       	"3E43D165039C"
+			supplier   	"Logical View::org.apache.naming"
+			quidu      	"3E43D1580339"))
+		exportControl 	"Public"
+		logical_models 	(list unit_reference_list
+		    (object Class_Category "ant"
+			quid       	"3E42DFBB037F"
+			visible_categories 	(list visibility_relationship_list
+			    (object Visibility_Relationship
+				quid       	"3E43CFF7020F"
+				supplier   	"Logical View::org.apache.catalina::util"
+				quidu      	"3E42E0260184"))
+			exportControl 	"Public"
+			logical_models 	(list unit_reference_list)
+			logical_presentations 	(list unit_reference_list))
+		    (object Class_Category "authenticator"
+			quid       	"3E42DFC702B4"
+			visible_categories 	(list visibility_relationship_list
+			    (object Visibility_Relationship
+				quid       	"3E43D03C0395"
+				supplier   	"Logical View::org.apache.catalina::deploy"
+				quidu      	"3E42DFDC0340")
+			    (object Visibility_Relationship
+				quid       	"3E43D03F01C2"
+				supplier   	"Logical View::org.apache.catalina::util"
+				quidu      	"3E42E0260184")
+			    (object Visibility_Relationship
+				quid       	"3E43D043024A"
+				supplier   	"Logical View::org.apache.catalina::valves"
+				quidu      	"3E42E02D035B"))
+			exportControl 	"Public"
+			logical_models 	(list unit_reference_list)
+			logical_presentations 	(list unit_reference_list))
+		    (object Class_Category "connector"
+			quid       	"3E42DFCF036A"
+			visible_categories 	(list visibility_relationship_list
+			    (object Visibility_Relationship
+				quid       	"3E43D07E017D"
+				supplier   	"Logical View::org.apache.catalina::session"
+				quidu      	"3E42E00C026D"))
+			exportControl 	"Public"
+			logical_models 	(list unit_reference_list)
+			logical_presentations 	(list unit_reference_list))
+		    (object Class_Category "core"
+			quid       	"3E42DFD603BA"
+			visible_categories 	(list visibility_relationship_list
+			    (object Visibility_Relationship
+				quid       	"3E43D19E01A9"
+				supplier   	"Logical View::org.apache.catalina::deploy"
+				quidu      	"3E42DFDC0340")
+			    (object Visibility_Relationship
+				quid       	"3E43D1A10185"
+				supplier   	"Logical View::org.apache.catalina::util"
+				quidu      	"3E42E0260184")
+			    (object Visibility_Relationship
+				quid       	"3E43D1CE007C"
+				supplier   	"Logical View::org.apache.catalina::connector"
+				quidu      	"3E42DFCF036A")
+			    (object Visibility_Relationship
+				quid       	"3E43D1D800D0"
+				supplier   	"Logical View::org.apache.catalina::security"
+				quidu      	"3E42E00100D7")
+			    (object Visibility_Relationship
+				quid       	"3E43D25C031F"
+				supplier   	"Logical View::org.apache.catalina::mbean"
+				quidu      	"3E42DFF10188")
+			    (object Visibility_Relationship
+				quid       	"3E43D260028E"
+				supplier   	"Logical View::org.apache.catalina::startup"
+				quidu      	"3E42E01E00EC")
+			    (object Visibility_Relationship
+				quid       	"3E43D26A015C"
+				supplier   	"Logical View::org.apache.catalina::session"
+				quidu      	"3E42E00C026D")
+			    (object Visibility_Relationship
+				quid       	"3E43D2830271"
+				supplier   	"Logical View::org.apache.catalina::valves"
+				quidu      	"3E42E02D035B")
+			    (object Visibility_Relationship
+				quid       	"3E43D2C80248"
+				supplier   	"Logical View::org.apache.catalina::net"
+				quidu      	"3E42DFF70227")
+			    (object Visibility_Relationship
+				quid       	"3E43D2D6002B"
+				supplier   	"Logical View::org.apache.catalina::loader"
+				quidu      	"3E43D2D002D6")
+			    (object Visibility_Relationship
+				quid       	"3E43D3D300F7"
+				supplier   	"Logical View::org.apache.naming"
+				quidu      	"3E43D1580339"))
+			exportControl 	"Public"
+			logical_models 	(list unit_reference_list)
+			logical_presentations 	(list unit_reference_list))
+		    (object Class_Category "deploy"
+			quid       	"3E42DFDC0340"
+			visible_categories 	(list visibility_relationship_list
+			    (object Visibility_Relationship
+				quid       	"3E43D32001B8"
+				supplier   	"Logical View::org.apache.catalina::util"
+				quidu      	"3E42E0260184"))
+			exportControl 	"Public"
+			logical_models 	(list unit_reference_list)
+			logical_presentations 	(list unit_reference_list))
+		    (object Class_Category "launcher"
+			quid       	"3E42DFE2033F"
+			exportControl 	"Public"
+			logical_models 	(list unit_reference_list)
+			logical_presentations 	(list unit_reference_list))
+		    (object Class_Category "logger"
+			quid       	"3E42DFEC0285"
+			exportControl 	"Public"
+			logical_models 	(list unit_reference_list)
+			logical_presentations 	(list unit_reference_list))
+		    (object Class_Category "mbean"
+			quid       	"3E42DFF10188"
+			visible_categories 	(list visibility_relationship_list
+			    (object Visibility_Relationship
+				quid       	"3E43D49101A5"
+				supplier   	"Logical View::org.apache.catalina::deploy"
+				quidu      	"3E42DFDC0340")
+			    (object Visibility_Relationship
+				quid       	"3E43D4C6027D"
+				supplier   	"Logical View::org.apache.catalina::core"
+				quidu      	"3E42DFD603BA")
+			    (object Visibility_Relationship
+				quid       	"3E43D4FB008F"
+				supplier   	"Logical View::org.apache.catalina::session"
+				quidu      	"3E42E00C026D")
+			    (object Visibility_Relationship
+				quid       	"3E43D50000BE"
+				supplier   	"Logical View::org.apache.catalina::valves"
+				quidu      	"3E42E02D035B")
+			    (object Visibility_Relationship
+				quid       	"3E43D5080278"
+				supplier   	"Logical View::org.apache.catalina::realm"
+				quidu      	"3E42DFFA00AE")
+			    (object Visibility_Relationship
+				quid       	"3E43D55A0258"
+				supplier   	"Logical View::org.apache.catalina::logger"
+				quidu      	"3E42DFEC0285")
+			    (object Visibility_Relationship
+				quid       	"3E43D56000D0"
+				supplier   	"Logical View::org.apache.catalina::authenticator"
+				quidu      	"3E42DFC702B4"))
+			exportControl 	"Public"
+			logical_models 	(list unit_reference_list)
+			logical_presentations 	(list unit_reference_list))
+		    (object Class_Category "net"
+			quid       	"3E42DFF70227"
+			visible_categories 	(list visibility_relationship_list
+			    (object Visibility_Relationship
+				quid       	"3E43D6390371"
+				supplier   	"Logical View::org.apache.catalina::util"
+				quidu      	"3E42E0260184"))
+			exportControl 	"Public"
+			logical_models 	(list unit_reference_list)
+			logical_presentations 	(list unit_reference_list))
+		    (object Class_Category "realm"
+			quid       	"3E42DFFA00AE"
+			visible_categories 	(list visibility_relationship_list
+			    (object Visibility_Relationship
+				quid       	"3E43D69F0133"
+				supplier   	"Logical View::org.apache.catalina::core"
+				quidu      	"3E42DFD603BA")
+			    (object Visibility_Relationship
+				quid       	"3E43D6A10353"
+				supplier   	"Logical View::org.apache.catalina::util"
+				quidu      	"3E42E0260184")
+			    (object Visibility_Relationship
+				quid       	"3E43D70E00E2"
+				supplier   	"Logical View::org.apache.naming"
+				quidu      	"3E43D1580339")
+			    (object Visibility_Relationship
+				quid       	"3E43D72302D7"
+				supplier   	"Logical View::org.apache.catalina::deploy"
+				quidu      	"3E42DFDC0340"))
+			exportControl 	"Public"
+			logical_models 	(list unit_reference_list)
+			logical_presentations 	(list unit_reference_list))
+		    (object Class_Category "security"
+			quid       	"3E42E00100D7"
+			visible_categories 	(list visibility_relationship_list
+			    (object Visibility_Relationship
+				quid       	"3E43D74D007F"
+				supplier   	"Logical View::org.apache.catalina::startup"
+				quidu      	"3E42E01E00EC")
+			    (object Visibility_Relationship
+				quid       	"3E43D76B0371"
+				supplier   	"Logical View::org.apache.catalina::util"
+				quidu      	"3E42E0260184"))
+			exportControl 	"Public"
+			logical_models 	(list unit_reference_list)
+			logical_presentations 	(list unit_reference_list))
+		    (object Class_Category "servlets"
+			quid       	"3E42E00502DB"
+			visible_categories 	(list visibility_relationship_list
+			    (object Visibility_Relationship
+				quid       	"3E43D82702E5"
+				supplier   	"Logical View::org.apache.tomcat.util"
+				quidu      	"3E42DEDF01F2")
+			    (object Visibility_Relationship
+				quid       	"3E43D82A02CC"
+				supplier   	"Logical View::org.apache.catalina::util"
+				quidu      	"3E42E0260184")
+			    (object Visibility_Relationship
+				quid       	"3E43D82D0244"
+				supplier   	"Logical View::org.apache.naming"
+				quidu      	"3E43D1580339"))
+			exportControl 	"Public"
+			logical_models 	(list unit_reference_list)
+			logical_presentations 	(list unit_reference_list))
+		    (object Class_Category "session"
+			quid       	"3E42E00C026D"
+			visible_categories 	(list visibility_relationship_list
+			    (object Visibility_Relationship
+				quid       	"3E43D8770344"
+				supplier   	"Logical View::org.apache.catalina::util"
+				quidu      	"3E42E0260184"))
+			exportControl 	"Public"
+			logical_models 	(list unit_reference_list)
+			logical_presentations 	(list unit_reference_list))
+		    (object Class_Category "ssi"
+			quid       	"3E42E01002C3"
+			visible_categories 	(list visibility_relationship_list
+			    (object Visibility_Relationship
+				quid       	"3E43D8F902B5"
+				supplier   	"Logical View::org.apache.catalina::util"
+				quidu      	"3E42E0260184"))
+			exportControl 	"Public"
+			logical_models 	(list unit_reference_list)
+			logical_presentations 	(list unit_reference_list))
+		    (object Class_Category "startup"
+			quid       	"3E42E01E00EC"
+			visible_categories 	(list visibility_relationship_list
+			    (object Visibility_Relationship
+				quid       	"3E43D9150251"
+				supplier   	"Logical View::org.apache.catalina::logger"
+				quidu      	"3E42DFEC0285")
+			    (object Visibility_Relationship
+				quid       	"3E43D919018F"
+				supplier   	"Logical View::org.apache.catalina::security"
+				quidu      	"3E42E00100D7")
+			    (object Visibility_Relationship
+				quid       	"3E43D946000D"
+				supplier   	"Logical View::org.apache.catalina::core"
+				quidu      	"3E42DFD603BA")
+			    (object Visibility_Relationship
+				quid       	"3E43D95E012A"
+				supplier   	"Logical View::org.apache.catalina::loader"
+				quidu      	"3E43D2D002D6")
+			    (object Visibility_Relationship
+				quid       	"3E43D9960315"
+				supplier   	"Logical View::org.apache.catalina::util"
+				quidu      	"3E42E0260184")
+			    (object Visibility_Relationship
+				quid       	"3E43D99902BF"
+				supplier   	"Logical View::org.apache.catalina::valves"
+				quidu      	"3E42E02D035B")
+			    (object Visibility_Relationship
+				quid       	"3E43D99C0147"
+				supplier   	"Logical View::org.apache.catalina::deploy"
+				quidu      	"3E42DFDC0340")
+			    (object Visibility_Relationship
+				quid       	"3E43D9DA0114"
+				supplier   	"Logical View::org.apache.catalina::net"
+				quidu      	"3E42DFF70227")
+			    (object Visibility_Relationship
+				quid       	"3E43D9F402F2"
+				supplier   	"Logical View::org.apache.catalina::realm"
+				quidu      	"3E42DFFA00AE"))
+			exportControl 	"Public"
+			logical_models 	(list unit_reference_list)
+			logical_presentations 	(list unit_reference_list))
+		    (object Class_Category "user"
+			quid       	"3E42E0220174"
+			visible_categories 	(list visibility_relationship_list
+			    (object Visibility_Relationship
+				quid       	"3E43DB240227"
+				supplier   	"Logical View::org.apache.catalina::util"
+				quidu      	"3E42E0260184")
+			    (object Visibility_Relationship
+				quid       	"3E43DB31009F"
+				supplier   	"Logical View::org.apache.naming"
+				quidu      	"3E43D1580339"))
+			exportControl 	"Public"
+			logical_models 	(list unit_reference_list)
+			logical_presentations 	(list unit_reference_list))
+		    (object Class_Category "util"
+			quid       	"3E42E0260184"
+			visible_categories 	(list visibility_relationship_list
+			    (object Visibility_Relationship
+				quid       	"3E43DB85017C"
+				supplier   	"Logical View::org.apache.catalina::core"
+				quidu      	"3E42DFD603BA")
+			    (object Visibility_Relationship
+				quid       	"3E43DB88016C"
+				supplier   	"Logical View::org.apache.naming"
+				quidu      	"3E43D1580339"))
+			exportControl 	"Public"
+			logical_models 	(list unit_reference_list)
+			logical_presentations 	(list unit_reference_list))
+		    (object Class_Category "valves"
+			quid       	"3E42E02D035B"
+			visible_categories 	(list visibility_relationship_list
+			    (object Visibility_Relationship
+				quid       	"3E43DC2B0257"
+				supplier   	"Logical View::org.apache.catalina::util"
+				quidu      	"3E42E0260184")
+			    (object Visibility_Relationship
+				quid       	"3E43DD3E0271"
+				supplier   	"Logical View::org.apache.catalina::deploy"
+				quidu      	"3E42DFDC0340")
+			    (object Visibility_Relationship
+				quid       	"3E43DD4102CF"
+				supplier   	"Logical View::org.apache.catalina::connector"
+				quidu      	"3E42DFCF036A")
+			    (object Visibility_Relationship
+				quid       	"3E43DDDE00B8"
+				supplier   	"Logical View::org.apache.catalina::core"
+				quidu      	"3E42DFD603BA"))
+			exportControl 	"Public"
+			logical_models 	(list unit_reference_list)
+			logical_presentations 	(list unit_reference_list))
+		    (object Class_Category "loader"
+			quid       	"3E43D2D002D6"
+			visible_categories 	(list visibility_relationship_list
+			    (object Visibility_Relationship
+				quid       	"3E43D3CF00F2"
+				supplier   	"Logical View::org.apache.naming"
+				quidu      	"3E43D1580339"))
+			exportControl 	"Public"
+			logical_models 	(list unit_reference_list)
+			logical_presentations 	(list unit_reference_list)))
+		logical_presentations 	(list unit_reference_list
+		    (object ClassDiagram "Main"
+			quid       	"3E42DFB6010B"
+			title      	"Main"
+			zoom       	100
+			max_height 	28350
+			max_width  	21600
+			origin_x   	0
+			origin_y   	0
+			items      	(list diagram_item_list
+			    (object CategoryView "Logical View::org.apache.catalina::ant" @1
+				location   	(2208, 1504)
+				font       	(object Font
+				    size       	10
+				    face       	"Arial"
+				    bold       	FALSE
+				    italics    	FALSE
+				    underline  	FALSE
+				    strike     	FALSE
+				    color      	0
+				    default_color 	TRUE)
+				label      	(object ItemLabel
+				    Parent_View 	@1
+				    location   	(2064, 1420)
+				    fill_color 	13434879
+				    nlines     	2
+				    max_width  	288
+				    justify    	0
+				    label      	"ant")
+				icon_style 	"Icon"
+				line_color 	3342489
+				fill_color 	13434879
+				quidu      	"3E42DFBB037F"
+				width      	300
+				height     	180)
+			    (object CategoryView "Logical View::org.apache.catalina::authenticator" @2
+				location   	(192, 2000)
+				font       	(object Font
+				    size       	10
+				    face       	"Arial"
+				    bold       	FALSE
+				    italics    	FALSE
+				    underline  	FALSE
+				    strike     	FALSE
+				    color      	0
+				    default_color 	TRUE)
+				label      	(object ItemLabel
+				    Parent_View 	@2
+				    location   	(48, 1916)
+				    fill_color 	13434879
+				    nlines     	2
+				    max_width  	288
+				    justify    	0
+				    label      	"authenticator")
+				icon_style 	"Icon"
+				line_color 	3342489
+				fill_color 	13434879
+				quidu      	"3E42DFC702B4"
+				width      	300
+				height     	180)
+			    (object CategoryView "Logical View::org.apache.catalina::connector" @3
+				location   	(464, 1328)
+				font       	(object Font
+				    size       	10
+				    face       	"Arial"
+				    bold       	FALSE
+				    italics    	FALSE
+				    underline  	FALSE
+				    strike     	FALSE
+				    color      	0
+				    default_color 	TRUE)
+				label      	(object ItemLabel
+				    Parent_View 	@3
+				    location   	(320, 1244)
+				    fill_color 	13434879
+				    nlines     	2
+				    max_width  	288
+				    justify    	0
+				    label      	"connector")
+				icon_style 	"Icon"
+				line_color 	3342489
+				fill_color 	13434879
+				quidu      	"3E42DFCF036A"
+				width      	300
+				height     	180)
+			    (object CategoryView "Logical View::org.apache.catalina::core" @4
+				location   	(2224, 800)
+				font       	(object Font
+				    size       	10
+				    face       	"Arial"
+				    bold       	FALSE
+				    italics    	FALSE
+				    underline  	FALSE
+				    strike     	FALSE
+				    color      	0
+				    default_color 	TRUE)
+				label      	(object ItemLabel
+				    Parent_View 	@4
+				    location   	(2080, 716)
+				    fill_color 	13434879
+				    nlines     	2
+				    max_width  	288
+				    justify    	0
+				    label      	"core")
+				icon_style 	"Icon"
+				line_color 	3342489
+				fill_color 	13434879
+				quidu      	"3E42DFD603BA"
+				width      	300
+				height     	180)
+			    (object CategoryView "Logical View::org.apache.catalina::deploy" @5
+				location   	(240, 160)
+				font       	(object Font
+				    size       	10
+				    face       	"Arial"
+				    bold       	FALSE
+				    italics    	FALSE
+				    underline  	FALSE
+				    strike     	FALSE
+				    color      	0
+				    default_color 	TRUE)
+				label      	(object ItemLabel
+				    Parent_View 	@5
+				    location   	(96, 76)
+				    fill_color 	13434879
+				    nlines     	2
+				    max_width  	288
+				    justify    	0
+				    label      	"deploy")
+				icon_style 	"Icon"
+				line_color 	3342489
+				fill_color 	13434879
+				quidu      	"3E42DFDC0340"
+				width      	300
+				height     	180)
+			    (object CategoryView "Logical View::org.apache.catalina::launcher" @6
+				location   	(1776, 2480)
+				font       	(object Font
+				    size       	10
+				    face       	"Arial"
+				    bold       	FALSE
+				    italics    	FALSE
+				    underline  	FALSE
+				    strike     	FALSE
+				    color      	0
+				    default_color 	TRUE)
+				label      	(object ItemLabel
+				    Parent_View 	@6
+				    location   	(1632, 2396)
+				    fill_color 	13434879
+				    nlines     	2
+				    max_width  	288
+				    justify    	0
+				    label      	"launcher")
+				icon_style 	"Icon"
+				line_color 	3342489
+				fill_color 	13434879
+				quidu      	"3E42DFE2033F"
+				width      	300
+				height     	180)
+			    (object CategoryView "Logical View::org.apache.catalina::logger" @7
+				location   	(752, 128)
+				font       	(object Font
+				    size       	10
+				    face       	"Arial"
+				    bold       	FALSE
+				    italics    	FALSE
+				    underline  	FALSE
+				    strike     	FALSE
+				    color      	0
+				    default_color 	TRUE)
+				label      	(object ItemLabel
+				    Parent_View 	@7
+				    location   	(608, 44)
+				    fill_color 	13434879
+				    nlines     	2
+				    max_width  	288
+				    justify    	0
+				    label      	"logger")
+				icon_style 	"Icon"
+				line_color 	3342489
+				fill_color 	13434879
+				quidu      	"3E42DFEC0285"
+				width      	300
+				height     	180)
+			    (object CategoryView "Logical View::org.apache.catalina::mbean" @8
+				location   	(2208, 1216)
+				font       	(object Font
+				    size       	10
+				    face       	"Arial"
+				    bold       	FALSE
+				    italics    	FALSE
+				    underline  	FALSE
+				    strike     	FALSE
+				    color      	0
+				    default_color 	TRUE)
+				label      	(object ItemLabel
+				    Parent_View 	@8
+				    location   	(2064, 1132)
+				    fill_color 	13434879
+				    nlines     	2
+				    max_width  	288
+				    justify    	0
+				    label      	"mbean")
+				icon_style 	"Icon"
+				line_color 	3342489
+				fill_color 	13434879
+				quidu      	"3E42DFF10188"
+				width      	300
+				height     	180)
+			    (object CategoryView "Logical View::org.apache.catalina::net" @9
+				location   	(1056, 2496)
+				font       	(object Font
+				    size       	10
+				    face       	"Arial"
+				    bold       	FALSE
+				    italics    	FALSE
+				    underline  	FALSE
+				    strike     	FALSE
+				    color      	0
+				    default_color 	TRUE)
+				label      	(object ItemLabel
+				    Parent_View 	@9
+				    location   	(912, 2412)
+				    fill_color 	13434879
+				    nlines     	2
+				    max_width  	288
+				    justify    	0
+				    label      	"net")
+				icon_style 	"Icon"
+				line_color 	3342489
+				fill_color 	13434879
+				quidu      	"3E42DFF70227"
+				width      	300
+				height     	180)
+			    (object CategoryView "Logical View::org.apache.catalina::realm" @10
+				location   	(1248, 112)
+				font       	(object Font
+				    size       	10
+				    face       	"Arial"
+				    bold       	FALSE
+				    italics    	FALSE
+				    underline  	FALSE
+				    strike     	FALSE
+				    color      	0
+				    default_color 	TRUE)
+				label      	(object ItemLabel
+				    Parent_View 	@10
+				    location   	(1104, 28)
+				    fill_color 	13434879
+				    nlines     	2
+				    max_width  	288
+				    justify    	0
+				    label      	"realm")
+				icon_style 	"Icon"
+				line_color 	3342489
+				fill_color 	13434879
+				quidu      	"3E42DFFA00AE"
+				width      	300
+				height     	180)
+			    (object CategoryView "Logical View::org.apache.catalina::security" @11
+				location   	(304, 2496)
+				font       	(object Font
+				    size       	10
+				    face       	"Arial"
+				    bold       	FALSE
+				    italics    	FALSE
+				    underline  	FALSE
+				    strike     	FALSE
+				    color      	0
+				    default_color 	TRUE)
+				label      	(object ItemLabel
+				    Parent_View 	@11
+				    location   	(160, 2412)
+				    fill_color 	13434879
+				    nlines     	2
+				    max_width  	288
+				    justify    	0
+				    label      	"security")
+				icon_style 	"Icon"
+				line_color 	3342489
+				fill_color 	13434879
+				quidu      	"3E42E00100D7"
+				width      	300
+				height     	180)
+			    (object CategoryView "Logical View::org.apache.catalina::servlets" @12
+				location   	(2096, 1888)
+				font       	(object Font
+				    size       	10
+				    face       	"Arial"
+				    bold       	FALSE
+				    italics    	FALSE
+				    underline  	FALSE
+				    strike     	FALSE
+				    color      	0
+				    default_color 	TRUE)
+				label      	(object ItemLabel
+				    Parent_View 	@12
+				    location   	(1952, 1804)
+				    fill_color 	13434879
+				    nlines     	2
+				    max_width  	288
+				    justify    	0
+				    label      	"servlets")
+				icon_style 	"Icon"
+				line_color 	3342489
+				fill_color 	13434879
+				quidu      	"3E42E00502DB"
+				width      	300
+				height     	180)
+			    (object CategoryView "Logical View::org.apache.catalina::session" @13
+				location   	(432, 1696)
+				font       	(object Font
+				    size       	10
+				    face       	"Arial"
+				    bold       	FALSE
+				    italics    	FALSE
+				    underline  	FALSE
+				    strike     	FALSE
+				    color      	0
+				    default_color 	TRUE)
+				label      	(object ItemLabel
+				    Parent_View 	@13
+				    location   	(288, 1612)
+				    fill_color 	13434879
+				    nlines     	2
+				    max_width  	288
+				    justify    	0
+				    label      	"session")
+				icon_style 	"Icon"
+				line_color 	3342489
+				fill_color 	13434879
+				quidu      	"3E42E00C026D"
+				width      	300
+				height     	180)
+			    (object CategoryView "Logical View::org.apache.catalina::ssi" @14
+				location   	(672, 2480)
+				font       	(object Font
+				    size       	10
+				    face       	"Arial"
+				    bold       	FALSE
+				    italics    	FALSE
+				    underline  	FALSE
+				    strike     	FALSE
+				    color      	0
+				    default_color 	TRUE)
+				label      	(object ItemLabel
+				    Parent_View 	@14
+				    location   	(528, 2393)
+				    fill_color 	13434879
+				    nlines     	2
+				    max_width  	288
+				    justify    	0
+				    label      	"ssi")
+				icon_style 	"Icon"
+				line_color 	3342489
+				fill_color 	13434879
+				quidu      	"3E42E01002C3"
+				width      	301
+				height     	187)
+			    (object CategoryView "Logical View::org.apache.catalina::startup" @15
+				location   	(1088, 832)
+				font       	(object Font
+				    size       	10
+				    face       	"Arial"
+				    bold       	FALSE
+				    italics    	FALSE
+				    underline  	FALSE
+				    strike     	FALSE
+				    color      	0
+				    default_color 	TRUE)
+				label      	(object ItemLabel
+				    Parent_View 	@15
+				    location   	(944, 748)
+				    fill_color 	13434879
+				    nlines     	2
+				    max_width  	288
+				    justify    	0
+				    label      	"startup")
+				icon_style 	"Icon"
+				line_color 	3342489
+				fill_color 	13434879
+				quidu      	"3E42E01E00EC"
+				width      	300
+				height     	180)
+			    (object CategoryView "Logical View::org.apache.catalina::user" @16
+				location   	(1424, 2496)
+				font       	(object Font
+				    size       	10
+				    face       	"Arial"
+				    bold       	FALSE
+				    italics    	FALSE
+				    underline  	FALSE
+				    strike     	FALSE
+				    color      	0
+				    default_color 	TRUE)
+				label      	(object ItemLabel
+				    Parent_View 	@16
+				    location   	(1280, 2412)
+				    fill_color 	13434879
+				    nlines     	2
+				    max_width  	288
+				    justify    	0
+				    label      	"user")
+				icon_style 	"Icon"
+				line_color 	3342489
+				fill_color 	13434879
+				quidu      	"3E42E0220174"
+				width      	300
+				height     	180)
+			    (object CategoryView "Logical View::org.apache.catalina::util" @17
+				location   	(1312, 1872)
+				font       	(object Font
+				    size       	10
+				    face       	"Arial"
+				    bold       	FALSE
+				    italics    	FALSE
+				    underline  	FALSE
+				    strike     	FALSE
+				    color      	0
+				    default_color 	TRUE)
+				label      	(object ItemLabel
+				    Parent_View 	@17
+				    location   	(1168, 1788)
+				    fill_color 	13434879
+				    nlines     	2
+				    max_width  	288
+				    justify    	0
+				    label      	"util")
+				icon_style 	"Icon"
+				line_color 	3342489
+				fill_color 	13434879
+				quidu      	"3E42E0260184"
+				width      	300
+				height     	180)
+			    (object CategoryView "Logical View::org.apache.catalina::valves" @18
+				location   	(304, 704)
+				font       	(object Font
+				    size       	10
+				    face       	"Arial"
+				    bold       	FALSE
+				    italics    	FALSE
+				    underline  	FALSE
+				    strike     	FALSE
+				    color      	0
+				    default_color 	TRUE)
+				label      	(object ItemLabel
+				    Parent_View 	@18
+				    location   	(160, 620)
+				    fill_color 	13434879
+				    nlines     	2
+				    max_width  	288
+				    justify    	0
+				    label      	"valves")
+				icon_style 	"Icon"
+				line_color 	3342489
+				fill_color 	13434879
+				quidu      	"3E42E02D035B"
+				width      	300
+				height     	180)
+			    (object ImportView "" @19
+				stereotype 	TRUE
+				line_color 	3342489
+				quidu      	"3E43CFF7020F"
+				client     	@1
+				supplier   	@17
+				line_style 	0)
+			    (object ImportView "" @20
+				stereotype 	TRUE
+				line_color 	3342489
+				quidu      	"3E43D07E017D"
+				client     	@3
+				supplier   	@13
+				line_style 	0)
+			    (object CategoryView "Logical View::org.apache.catalina::loader" @21
+				location   	(2240, 416)
+				font       	(object Font
+				    size       	10
+				    face       	"Arial"
+				    bold       	FALSE
+				    italics    	FALSE
+				    underline  	FALSE
+				    strike     	FALSE
+				    color      	0
+				    default_color 	TRUE)
+				label      	(object ItemLabel
+				    Parent_View 	@21
+				    location   	(2096, 332)
+				    fill_color 	13434879
+				    nlines     	2
+				    max_width  	288
+				    justify    	0
+				    label      	"loader")
+				icon_style 	"Icon"
+				line_color 	3342489
+				fill_color 	13434879
+				quidu      	"3E43D2D002D6"
+				width      	300
+				height     	180)
+			    (object ImportView "" @22
+				stereotype 	TRUE
+				line_color 	3342489
+				quidu      	"3E43D32001B8"
+				client     	@5
+				supplier   	@17
+				line_style 	0)
+			    (object CategoryView "Logical View::org.apache.naming" @23
+				location   	(1872, 96)
+				font       	(object Font
+				    size       	10
+				    face       	"Arial"
+				    bold       	FALSE
+				    italics    	FALSE
+				    underline  	FALSE
+				    strike     	FALSE
+				    color      	0
+				    default_color 	TRUE)
+				label      	(object ItemLabel
+				    Parent_View 	@23
+				    location   	(1699, 12)
+				    fill_color 	13434879
+				    nlines     	2
+				    max_width  	346
+				    justify    	0
+				    label      	"org.apache.naming")
+				icon_style 	"Icon"
+				line_color 	3342489
+				fill_color 	13434879
+				quidu      	"3E43D1580339"
+				width      	358
+				height     	180)
+			    (object ImportView "" @24
+				stereotype 	TRUE
+				line_color 	3342489
+				quidu      	"3E43D3CF00F2"
+				client     	@21
+				supplier   	@23
+				line_style 	0)
+			    (object ImportView "" @25
+				stereotype 	TRUE
+				line_color 	3342489
+				quidu      	"3E43D6390371"
+				client     	@9
+				supplier   	@17
+				line_style 	0)
+			    (object ImportView "" @26
+				stereotype 	TRUE
+				line_color 	3342489
+				quidu      	"3E43D69F0133"
+				client     	@10
+				supplier   	@4
+				line_style 	0)
+			    (object ImportView "" @27
+				stereotype 	TRUE
+				line_color 	3342489
+				quidu      	"3E43D6A10353"
+				client     	@10
+				supplier   	@17
+				line_style 	0)
+			    (object ImportView "" @28
+				stereotype 	TRUE
+				line_color 	3342489
+				quidu      	"3E43D70E00E2"
+				client     	@10
+				supplier   	@23
+				line_style 	0)
+			    (object ImportView "" @29
+				stereotype 	TRUE
+				line_color 	3342489
+				quidu      	"3E43D72302D7"
+				client     	@10
+				supplier   	@5
+				line_style 	0)
+			    (object ImportView "" @30
+				stereotype 	TRUE
+				line_color 	3342489
+				quidu      	"3E43D69F0133"
+				client     	@10
+				supplier   	@4
+				line_style 	0)
+			    (object ImportView "" @31
+				stereotype 	TRUE
+				line_color 	3342489
+				quidu      	"3E43D74D007F"
+				client     	@11
+				supplier   	@15
+				line_style 	0)
+			    (object ImportView "" @32
+				stereotype 	TRUE
+				line_color 	3342489
+				quidu      	"3E43D76B0371"
+				client     	@11
+				supplier   	@17
+				line_style 	0)
+			    (object CategoryView "Logical View::org.apache.tomcat.util" @33
+				location   	(2096, 2224)
+				font       	(object Font
+				    size       	10
+				    face       	"Arial"
+				    bold       	FALSE
+				    italics    	FALSE
+				    underline  	FALSE
+				    strike     	FALSE
+				    color      	0
+				    default_color 	TRUE)
+				label      	(object ItemLabel
+				    Parent_View 	@33
+				    location   	(1923, 2140)
+				    fill_color 	13434879
+				    nlines     	2
+				    max_width  	346
+				    justify    	0
+				    label      	"org.apache.tomcat.util")
+				icon_style 	"Icon"
+				line_color 	3342489
+				fill_color 	13434879
+				quidu      	"3E42DEDF01F2"
+				width      	358
+				height     	180)
+			    (object ImportView "" @34
+				stereotype 	TRUE
+				line_color 	3342489
+				quidu      	"3E43D8770344"
+				client     	@13
+				supplier   	@17
+				line_style 	0)
+			    (object ImportView "" @35
+				stereotype 	TRUE
+				line_color 	3342489
+				quidu      	"3E43D8F902B5"
+				client     	@14
+				supplier   	@17
+				line_style 	0)
+			    (object ImportView "" @36
+				stereotype 	TRUE
+				line_color 	3342489
+				quidu      	"3E43DB240227"
+				client     	@16
+				supplier   	@17
+				line_style 	0)
+			    (object ImportView "" @37
+				stereotype 	TRUE
+				line_color 	3342489
+				quidu      	"3E43DB31009F"
+				client     	@16
+				supplier   	@23
+				line_style 	0)
+			    (object ImportView "" @38
+				stereotype 	TRUE
+				line_color 	3342489
+				quidu      	"3E43DB85017C"
+				client     	@17
+				supplier   	@4
+				line_style 	0)
+			    (object ImportView "" @39
+				stereotype 	TRUE
+				line_color 	3342489
+				quidu      	"3E43DB88016C"
+				client     	@17
+				supplier   	@23
+				line_style 	0)
+			    (object ImportView "" @40
+				stereotype 	TRUE
+				line_color 	3342489
+				quidu      	"3E43D82702E5"
+				client     	@12
+				supplier   	@33
+				line_style 	0)
+			    (object ImportView "" @41
+				stereotype 	TRUE
+				line_color 	3342489
+				quidu      	"3E43D82A02CC"
+				client     	@12
+				supplier   	@17
+				line_style 	0)
+			    (object ImportView "" @42
+				stereotype 	TRUE
+				line_color 	3342489
+				quidu      	"3E43D82D0244"
+				client     	@12
+				supplier   	@23
+				vertices   	(list Points
+				    (2060, 1743)
+				    (1746, 447)
+				    (1838, 186))
+				line_style 	0)
+			    (object ImportView "" @43
+				stereotype 	TRUE
+				line_color 	3342489
+				quidu      	"3E43D919018F"
+				client     	@15
+				supplier   	@11
+				line_style 	0)
+			    (object ImportView "" @44
+				stereotype 	TRUE
+				line_color 	3342489
+				quidu      	"3E43D946000D"
+				client     	@15
+				supplier   	@4
+				line_style 	0)
+			    (object ImportView "" @45
+				stereotype 	TRUE
+				line_color 	3342489
+				quidu      	"3E43D95E012A"
+				client     	@15
+				supplier   	@21
+				line_style 	0)
+			    (object ImportView "" @46
+				stereotype 	TRUE
+				line_color 	3342489
+				quidu      	"3E43D95E012A"
+				client     	@15
+				supplier   	@21
+				line_style 	0)
+			    (object ImportView "" @47
+				stereotype 	TRUE
+				line_color 	3342489
+				quidu      	"3E43D9960315"
+				client     	@15
+				supplier   	@17
+				line_style 	0)
+			    (object ImportView "" @48
+				stereotype 	TRUE
+				line_color 	3342489
+				quidu      	"3E43D99902BF"
+				client     	@15
+				supplier   	@18
+				line_style 	0)
+			    (object ImportView "" @49
+				stereotype 	TRUE
+				line_color 	3342489
+				quidu      	"3E43D99C0147"
+				client     	@15
+				supplier   	@5
+				line_style 	0)
+			    (object ImportView "" @50
+				stereotype 	TRUE
+				line_color 	3342489
+				quidu      	"3E43D946000D"
+				client     	@15
+				supplier   	@4
+				line_style 	0)
+			    (object ImportView "" @51
+				stereotype 	TRUE
+				line_color 	3342489
+				quidu      	"3E43D9150251"
+				client     	@15
+				supplier   	@7
+				line_style 	0)
+			    (object ImportView "" @52
+				stereotype 	TRUE
+				line_color 	3342489
+				quidu      	"3E43D9DA0114"
+				client     	@15
+				supplier   	@9
+				line_style 	0)
+			    (object ImportView "" @53
+				stereotype 	TRUE
+				line_color 	3342489
+				quidu      	"3E43D9F402F2"
+				client     	@15
+				supplier   	@10
+				line_style 	0)
+			    (object ImportView "" @54
+				stereotype 	TRUE
+				line_color 	3342489
+				quidu      	"3E43D9960315"
+				client     	@15
+				supplier   	@17
+				line_style 	0)
+			    (object ImportView "" @55
+				stereotype 	TRUE
+				line_color 	3342489
+				quidu      	"3E43D946000D"
+				client     	@15
+				supplier   	@4
+				line_style 	0)
+			    (object ImportView "" @56
+				stereotype 	TRUE
+				line_color 	3342489
+				quidu      	"3E43D99C0147"
+				client     	@15
+				supplier   	@5
+				line_style 	0)
+			    (object ImportView "" @57
+				stereotype 	TRUE
+				line_color 	3342489
+				quidu      	"3E43D49101A5"
+				client     	@8
+				supplier   	@5
+				line_style 	0)
+			    (object ImportView "" @58
+				stereotype 	TRUE
+				line_color 	3342489
+				quidu      	"3E43D4C6027D"
+				client     	@8
+				supplier   	@4
+				line_style 	0)
+			    (object ImportView "" @59
+				stereotype 	TRUE
+				line_color 	3342489
+				quidu      	"3E43D4FB008F"
+				client     	@8
+				supplier   	@13
+				line_style 	0)
+			    (object ImportView "" @60
+				stereotype 	TRUE
+				line_color 	3342489
+				quidu      	"3E43D50000BE"
+				client     	@8
+				supplier   	@18
+				vertices   	(list Points
+				    (2057, 1216)
+				    (1278, 1216)
+				    (454, 783))
+				line_style 	0)
+			    (object ImportView "" @61
+				stereotype 	TRUE
+				line_color 	3342489
+				quidu      	"3E43D5080278"
+				client     	@8
+				supplier   	@10
+				line_style 	0)
+			    (object ImportView "" @62
+				stereotype 	TRUE
+				line_color 	3342489
+				quidu      	"3E43D55A0258"
+				client     	@8
+				supplier   	@7
+				line_style 	0)
+			    (object ImportView "" @63
+				stereotype 	TRUE
+				line_color 	3342489
+				quidu      	"3E43D56000D0"
+				client     	@8
+				supplier   	@2
+				line_style 	0)
+			    (object ImportView "" @64
+				stereotype 	TRUE
+				line_color 	3342489
+				quidu      	"3E43D19E01A9"
+				client     	@4
+				supplier   	@5
+				line_style 	0)
+			    (object ImportView "" @65
+				stereotype 	TRUE
+				line_color 	3342489
+				quidu      	"3E43D1A10185"
+				client     	@4
+				supplier   	@17
+				line_style 	0)
+			    (object ImportView "" @66
+				stereotype 	TRUE
+				line_color 	3342489
+				quidu      	"3E43D1CE007C"
+				client     	@4
+				supplier   	@3
+				line_style 	0)
+			    (object ImportView "" @67
+				stereotype 	TRUE
+				line_color 	3342489
+				quidu      	"3E43D1D800D0"
+				client     	@4
+				supplier   	@11
+				vertices   	(list Points
+				    (2081, 890)
+				    (959, 1616)
+				    (409, 2351))
+				line_style 	0)
+			    (object ImportView "" @68
+				stereotype 	TRUE
+				line_color 	3342489
+				quidu      	"3E43D25C031F"
+				client     	@4
+				supplier   	@8
+				line_style 	0)
+			    (object ImportView "" @69
+				stereotype 	TRUE
+				line_color 	3342489
+				quidu      	"3E43D260028E"
+				client     	@4
+				supplier   	@15
+				line_style 	0)
+			    (object ImportView "" @70
+				stereotype 	TRUE
+				line_color 	3342489
+				quidu      	"3E43D26A015C"
+				client     	@4
+				supplier   	@13
+				line_style 	0)
+			    (object ImportView "" @71
+				stereotype 	TRUE
+				line_color 	3342489
+				quidu      	"3E43D2830271"
+				client     	@4
+				supplier   	@18
+				line_style 	0)
+			    (object ImportView "" @72
+				stereotype 	TRUE
+				line_color 	3342489
+				quidu      	"3E43D2C80248"
+				client     	@4
+				supplier   	@9
+				line_style 	0)
+			    (object ImportView "" @73
+				stereotype 	TRUE
+				line_color 	3342489
+				quidu      	"3E43D2D6002B"
+				client     	@4
+				supplier   	@21
+				line_style 	0)
+			    (object ImportView "" @74
+				stereotype 	TRUE
+				line_color 	3342489
+				quidu      	"3E43D3D300F7"
+				client     	@4
+				supplier   	@23
+				line_style 	0)
+			    (object ImportView "" @75
+				stereotype 	TRUE
+				line_color 	3342489
+				quidu      	"3E43D03C0395"
+				client     	@2
+				supplier   	@5
+				vertices   	(list Points
+				    (171, 1855)
+				    (16, 766)
+				    (205, 250))
+				line_style 	0)
+			    (object ImportView "" @76
+				stereotype 	TRUE
+				line_color 	3342489
+				quidu      	"3E43D03F01C2"
+				client     	@2
+				supplier   	@17
+				line_style 	0)
+			    (object ImportView "" @77
+				stereotype 	TRUE
+				line_color 	3342489
+				quidu      	"3E43D043024A"
+				client     	@2
+				supplier   	@18
+				line_style 	0)
+			    (object ImportView "" @78
+				stereotype 	TRUE
+				line_color 	3342489
+				quidu      	"3E43DC2B0257"
+				client     	@18
+				supplier   	@17
+				line_style 	0)
+			    (object ImportView "" @79
+				stereotype 	TRUE
+				line_color 	3342489
+				quidu      	"3E43DD3E0271"
+				client     	@18
+				supplier   	@5
+				line_style 	0)
+			    (object ImportView "" @80
+				stereotype 	TRUE
+				line_color 	3342489
+				quidu      	"3E43DD4102CF"
+				client     	@18
+				supplier   	@3
+				line_style 	0)
+			    (object ImportView "" @81
+				stereotype 	TRUE
+				line_color 	3342489
+				quidu      	"3E43DDDE00B8"
+				client     	@18
+				supplier   	@4
+				vertices   	(list Points
+				    (454, 654)
+				    (1293, 381)
+				    (2073, 731))
+				line_style 	0)))))
+	    (object Class_Category "org.apache.coyote"
+		quid       	"3E42DE9F0132"
+		visible_categories 	(list visibility_relationship_list
+		    (object Visibility_Relationship
+			quid       	"3E42DEFC00B3"
+			supplier   	"Logical View::org.apache.tomcat.util"
+			quidu      	"3E42DEDF01F2"))
+		exportControl 	"Public"
+		logical_models 	(list unit_reference_list)
+		logical_presentations 	(list unit_reference_list))
+	    (object Class_Category "org.apache.tomcat.util"
+		quid       	"3E42DEDF01F2"
+		exportControl 	"Public"
+		logical_models 	(list unit_reference_list)
+		logical_presentations 	(list unit_reference_list))
+	    (object Class_Category "org.apache.jasper"
+		quid       	"3E42DEFF0270"
+		exportControl 	"Public"
+		logical_models 	(list unit_reference_list)
+		logical_presentations 	(list unit_reference_list))
+	    (object Class_Category "org.apache.naming"
+		quid       	"3E43D1580339"
+		exportControl 	"Public"
+		logical_models 	(list unit_reference_list)
+		logical_presentations 	(list unit_reference_list))
+	    (object Mechanism @82
+		logical_models 	(list unit_reference_list
+		    (object Object "Bootstrap"
+			quid       	"3DFDF8FD0345"
+			collaborators 	(list link_list
+			    (object Link
+				quid       	"3DFDF9210008"
+				supplier   	"Bootstrap"
+				quidu      	"3DFDF8FD0345"
+				messages   	(list Messages
+				    (object Message "initClassLoaders()"
+					quid       	"3DFDF9210009"
+					frequency  	"Aperiodic"
+					synchronization 	"Simple"
+					dir        	"FromClientToSupplier"
+					sequence   	"1"
+					ordinal    	0
+					quidu      	"000000000000"
+					creation   	FALSE)))
+			    (object Link
+				quid       	"3DFDF91A010C"
+				supplier   	"Catalina"
+				quidu      	"3DFDF90A0330"
+				messages   	(list Messages
+				    (object Message "newInstance()"
+					quid       	"3DFDF91A010D"
+					frequency  	"Aperiodic"
+					synchronization 	"Simple"
+					dir        	"FromClientToSupplier"
+					sequence   	"2"
+					ordinal    	1
+					quidu      	"000000000000"
+					creation   	FALSE)
+				    (object Message "setParentClassLoader()"
+					quid       	"3DFDF97900C2"
+					frequency  	"Aperiodic"
+					synchronization 	"Simple"
+					dir        	"FromClientToSupplier"
+					sequence   	"3"
+					ordinal    	2
+					quidu      	"000000000000"
+					creation   	FALSE)
+				    (object Message "load()"
+					quid       	"3DFDFA3402F2"
+					frequency  	"Aperiodic"
+					synchronization 	"Simple"
+					dir        	"FromClientToSupplier"
+					sequence   	"4"
+					ordinal    	3
+					quidu      	"000000000000"
+					creation   	FALSE))))
+			persistence 	"Transient"
+			creationObj 	FALSE
+			multi      	FALSE)
+		    (object Object "Digester"
+			quid       	"3DFDFAF201A1"
+			collaborators 	(list link_list
+			    (object Link
+				quid       	"3DFDFB8400A6"
+				supplier   	"ServerLifecycleListener"
+				quidu      	"3DFDFB4B0217"
+				messages   	(list Messages
+				    (object Message "newInstance()"
+					quid       	"3DFDFB8400A7"
+					frequency  	"Aperiodic"
+					synchronization 	"Simple"
+					dir        	"FromClientToSupplier"
+					sequence   	"9.1"
+					ordinal    	9
+					quidu      	"000000000000"
+					creation   	FALSE)))
+			    (object Link
+				quid       	"3DFDFB920147"
+				supplier   	"GlobalResourcesLifecycleListener"
+				quidu      	"3DFDFB7A02AB"
+				messages   	(list Messages
+				    (object Message "newInstance()"
+					quid       	"3DFDFB920148"
+					frequency  	"Aperiodic"
+					synchronization 	"Simple"
+					dir        	"FromClientToSupplier"
+					sequence   	"9.2"
+					ordinal    	10
+					quidu      	"000000000000"
+					creation   	FALSE))))
+			persistence 	"Transient"
+			creationObj 	FALSE
+			multi      	FALSE)
+		    (object Object "ServerLifecycleListener"
+			quid       	"3DFDFB4B0217"
+			persistence 	"Transient"
+			creationObj 	FALSE
+			multi      	FALSE)
+		    (object Object "GlobalResourcesLifecycleListener"
+			quid       	"3DFDFB7A02AB"
+			persistence 	"Transient"
+			creationObj 	FALSE
+			multi      	FALSE)
+		    (object Object "SecurityConfig"
+			quid       	"3DFDFBD802BA"
+			persistence 	"Transient"
+			creationObj 	FALSE
+			multi      	FALSE)
+		    (object Object "Catalina"
+			quid       	"3DFDF90A0330"
+			collaborators 	(list link_list
+			    (object Link
+				quid       	"3DFDFA8001D9"
+				supplier   	"Catalina"
+				quidu      	"3DFDF90A0330"
+				messages   	(list Messages
+				    (object Message "initDirs()"
+					quid       	"3DFDFA8001DA"
+					frequency  	"Aperiodic"
+					synchronization 	"Simple"
+					dir        	"FromClientToSupplier"
+					sequence   	"5"
+					ordinal    	4
+					quidu      	"000000000000"
+					creation   	FALSE)
+				    (object Message "initNaming()"
+					quid       	"3DFDFA8B0347"
+					frequency  	"Aperiodic"
+					synchronization 	"Simple"
+					dir        	"FromClientToSupplier"
+					sequence   	"6"
+					ordinal    	5
+					quidu      	"000000000000"
+					creation   	FALSE)
+				    (object Message "initialize()"
+					quid       	"3DFDFAAD01AC"
+					frequency  	"Aperiodic"
+					synchronization 	"Simple"
+					dir        	"FromClientToSupplier"
+					sequence   	"7"
+					ordinal    	6
+					quidu      	"000000000000"
+					creation   	FALSE)))
+			    (object Link
+				quid       	"3DFDFAF800C3"
+				supplier   	"Digester"
+				quidu      	"3DFDFAF201A1"
+				messages   	(list Messages
+				    (object Message "createDigester()"
+					quid       	"3DFDFAF800C4"
+					frequency  	"Aperiodic"
+					synchronization 	"Simple"
+					dir        	"FromClientToSupplier"
+					sequence   	"8"
+					ordinal    	7
+					quidu      	"000000000000"
+					creation   	FALSE)
+				    (object Message "parse()"
+					quid       	"3DFDFB0100B2"
+					frequency  	"Aperiodic"
+					synchronization 	"Simple"
+					dir        	"FromClientToSupplier"
+					sequence   	"9"
+					ordinal    	8
+					quidu      	"000000000000"
+					creation   	FALSE)))
+			    (object Link
+				quid       	"3DFDFBEA00C1"
+				supplier   	"SecurityConfig"
+				quidu      	"3DFDFBD802BA"
+				messages   	(list Messages
+				    (object Message "newInstance()"
+					quid       	"3DFDFBEA00C2"
+					frequency  	"Aperiodic"
+					synchronization 	"Simple"
+					dir        	"FromClientToSupplier"
+					sequence   	"10"
+					ordinal    	11
+					quidu      	"000000000000"
+					creation   	FALSE)
+				    (object Message "setPackageDefinition()"
+					quid       	"3DFDFBF401F2"
+					frequency  	"Aperiodic"
+					synchronization 	"Simple"
+					dir        	"FromClientToSupplier"
+					sequence   	"11"
+					ordinal    	12
+					Operation  	"setPackageDefinition"
+					quidu      	"000000000000"
+					creation   	FALSE)
+				    (object Message "setPackageAccess()"
+					quid       	"3DFDFC1203C2"
+					frequency  	"Aperiodic"
+					synchronization 	"Simple"
+					dir        	"FromClientToSupplier"
+					sequence   	"12"
+					ordinal    	13
+					Operation  	"setPackageAccess"
+					quidu      	"000000000000"
+					creation   	FALSE))))
+			persistence 	"Transient"
+			creationObj 	FALSE
+			multi      	FALSE)))
+	    (object Mechanism @83
+		logical_models 	(list unit_reference_list
+		    (object Object "Catalina"
+			quid       	"3DFDFC8F015F"
+			collaborators 	(list link_list
+			    (object Link
+				quid       	"3DFDFD1F0075"
+				supplier   	"StandardServer"
+				quidu      	"3DFDFCCB006B"
+				messages   	(list Messages
+				    (object Message "initialize()"
+					quid       	"3DFDFD1F0076"
+					frequency  	"Aperiodic"
+					synchronization 	"Simple"
+					dir        	"FromClientToSupplier"
+					sequence   	"1"
+					ordinal    	0
+					quidu      	"000000000000"
+					creation   	FALSE))))
+			persistence 	"Transient"
+			creationObj 	FALSE
+			multi      	FALSE)
+		    (object Object "StandardServer"
+			quid       	"3DFDFCCB006B"
+			collaborators 	(list link_list
+			    (object Link
+				quid       	"3DFDFD3D01C3"
+				supplier   	"StandardService"
+				quidu      	"3DFDFD370020"
+				messages   	(list Messages
+				    (object Message "initialize()"
+					quid       	"3DFDFD3D01C4"
+					frequency  	"Aperiodic"
+					synchronization 	"Simple"
+					dir        	"FromClientToSupplier"
+					sequence   	"2"
+					ordinal    	1
+					quidu      	"000000000000"
+					creation   	FALSE))))
+			persistence 	"Transient"
+			creationObj 	FALSE
+			multi      	FALSE)
+		    (object Object "StandardService"
+			quid       	"3DFDFD370020"
+			collaborators 	(list link_list
+			    (object Link
+				quid       	"3DFDFE990304"
+				supplier   	"CoyoteConnector"
+				quidu      	"3DFDFE810313"
+				messages   	(list Messages
+				    (object Message "initialize()"
+					quid       	"3DFDFE990305"
+					frequency  	"Aperiodic"
+					synchronization 	"Simple"
+					dir        	"FromClientToSupplier"
+					sequence   	"2.1"
+					ordinal    	2
+					quidu      	"000000000000"
+					creation   	FALSE))))
+			persistence 	"Transient"
+			creationObj 	FALSE
+			multi      	FALSE)
+		    (object Object "CoyoteConnector"
+			quid       	"3DFDFE810313"
+			collaborators 	(list link_list
+			    (object Link
+				quid       	"3DFE013D0216"
+				supplier   	"CoyoteAdapter"
+				quidu      	"3DFDFFA00226"
+				messages   	(list Messages
+				    (object Message "new()"
+					quid       	"3DFE013D0217"
+					frequency  	"Aperiodic"
+					synchronization 	"Simple"
+					dir        	"FromClientToSupplier"
+					sequence   	"2.1.1"
+					ordinal    	3
+					quidu      	"000000000000"
+					creation   	FALSE)))
+			    (object Link
+				quid       	"3DFE0183032F"
+				supplier   	"Http11Protocol"
+				quidu      	"3DFE016601A6"
+				messages   	(list Messages
+				    (object Message "new()"
+					quid       	"3DFE01830330"
+					frequency  	"Aperiodic"
+					synchronization 	"Simple"
+					dir        	"FromClientToSupplier"
+					sequence   	"2.1.2"
+					ordinal    	4
+					quidu      	"000000000000"
+					creation   	FALSE)
+				    (object Message "init()"
+					quid       	"3DFE0188032C"
+					frequency  	"Aperiodic"
+					synchronization 	"Simple"
+					dir        	"FromClientToSupplier"
+					sequence   	"2.1.3"
+					ordinal    	5
+					quidu      	"000000000000"
+					creation   	FALSE)))
+			    (object Link
+				quid       	"3DFE01BC038B"
+				supplier   	"JkCoyoteAdapter"
+				quidu      	"3DFE01AD01A8"
+				messages   	(list Messages
+				    (object Message "new()"
+					quid       	"3DFE01BC038C"
+					frequency  	"Aperiodic"
+					synchronization 	"Simple"
+					dir        	"FromClientToSupplier"
+					sequence   	"2.1.4"
+					ordinal    	6
+					quidu      	"000000000000"
+					creation   	FALSE)
+				    (object Message "init()"
+					quid       	"3DFE01C30164"
+					frequency  	"Aperiodic"
+					synchronization 	"Simple"
+					dir        	"FromClientToSupplier"
+					sequence   	"2.1.5"
+					ordinal    	7
+					quidu      	"000000000000"
+					creation   	FALSE))))
+			persistence 	"Transient"
+			creationObj 	FALSE
+			multi      	FALSE)
+		    (object Object "CoyoteAdapter"
+			quid       	"3DFDFFA00226"
+			persistence 	"Transient"
+			creationObj 	FALSE
+			multi      	FALSE)
+		    (object Object "Http11Protocol"
+			quid       	"3DFE016601A6"
+			persistence 	"Transient"
+			creationObj 	FALSE
+			multi      	FALSE)
+		    (object Object "JkCoyoteAdapter"
+			quid       	"3DFE01AD01A8"
+			persistence 	"Transient"
+			creationObj 	FALSE
+			multi      	FALSE)))
+	    (object Mechanism @84
+		logical_models 	(list unit_reference_list
+		    (object Object "Bootstrap"
+			quid       	"3DFE027700F5"
+			collaborators 	(list link_list
+			    (object Link
+				quid       	"3DFE02830373"
+				supplier   	"Catalina"
+				quidu      	"3DFE027D0067"
+				messages   	(list Messages
+				    (object Message "start()"
+					quid       	"3DFE02830374"
+					frequency  	"Aperiodic"
+					synchronization 	"Simple"
+					dir        	"FromClientToSupplier"
+					sequence   	"1"
+					ordinal    	0
+					quidu      	"000000000000"
+					creation   	FALSE))))
+			persistence 	"Transient"
+			creationObj 	FALSE
+			multi      	FALSE)
+		    (object Object "Catalina"
+			quid       	"3DFE027D0067"
+			collaborators 	(list link_list
+			    (object Link
+				quid       	"3DFE02BA0187"
+				supplier   	"StandardServer"
+				quidu      	"3DFE02B30015"
+				messages   	(list Messages
+				    (object Message "start()"
+					quid       	"3DFE02BA0188"
+					frequency  	"Aperiodic"
+					synchronization 	"Simple"
+					dir        	"FromClientToSupplier"
+					sequence   	"1.1"
+					ordinal    	1
+					quidu      	"000000000000"
+					creation   	FALSE))))
+			persistence 	"Transient"
+			creationObj 	FALSE
+			multi      	FALSE)
+		    (object Object "StandardServer"
+			quid       	"3DFE02B30015"
+			collaborators 	(list link_list
+			    (object Link
+				quid       	"3DFE02D3006B"
+				supplier   	"StandardServer"
+				quidu      	"3DFE02B30015"
+				messages   	(list Messages
+				    (object Message "fireLifecycleEvent(BEFORE_START_EVENT)"
+					quid       	"3DFE02D3006C"
+					frequency  	"Aperiodic"
+					synchronization 	"Simple"
+					dir        	"FromClientToSupplier"
+					sequence   	"1.1.1"
+					ordinal    	2
+					quidu      	"000000000000"
+					creation   	FALSE)
+				    (object Message "fireLifecycleEvent(START_EVENT)"
+					quid       	"3DFE02DF02DF"
+					frequency  	"Aperiodic"
+					synchronization 	"Simple"
+					dir        	"FromClientToSupplier"
+					sequence   	"1.1.2"
+					ordinal    	3
+					quidu      	"000000000000"
+					creation   	FALSE)))
+			    (object Link
+				quid       	"3DFE030C02B2"
+				supplier   	"StandardService"
+				quidu      	"3DFE030400E3"
+				messages   	(list Messages
+				    (object Message "start()"
+					quid       	"3DFE030C02B3"
+					frequency  	"Aperiodic"
+					synchronization 	"Simple"
+					dir        	"FromClientToSupplier"
+					sequence   	"1.1.3"
+					ordinal    	4
+					quidu      	"000000000000"
+					creation   	FALSE))))
+			persistence 	"Transient"
+			creationObj 	FALSE
+			multi      	FALSE)
+		    (object Object "StandardService"
+			quid       	"3DFE030400E3"
+			collaborators 	(list link_list
+			    (object Link
+				quid       	"3DFE031D0021"
+				supplier   	"StandardService"
+				quidu      	"3DFE030400E3"
+				messages   	(list Messages
+				    (object Message "fireLifecycleEvent(BEFORE_START_EVENT)"
+					quid       	"3DFE031D0022"
+					frequency  	"Aperiodic"
+					synchronization 	"Simple"
+					dir        	"FromClientToSupplier"
+					sequence   	"1.1.3.1"
+					ordinal    	5
+					quidu      	"000000000000"
+					creation   	FALSE)
+				    (object Message "fireLifecycleEvent(START_EVENT)"
+					quid       	"3DFE0330019B"
+					frequency  	"Aperiodic"
+					synchronization 	"Simple"
+					dir        	"FromClientToSupplier"
+					sequence   	"1.1.3.2"
+					ordinal    	6
+					quidu      	"000000000000"
+					creation   	FALSE)))
+			    (object Link
+				quid       	"3DFE03700189"
+				supplier   	"StandardEngine"
+				quidu      	"3DFE034700C2"
+				messages   	(list Messages
+				    (object Message "start()"
+					quid       	"3DFE0370018A"
+					frequency  	"Aperiodic"
+					synchronization 	"Simple"
+					dir        	"FromClientToSupplier"
+					sequence   	"1.1.3.3"
+					ordinal    	7
+					quidu      	"000000000000"
+					creation   	FALSE))))
+			persistence 	"Transient"
+			creationObj 	FALSE
+			multi      	FALSE)
+		    (object Object "StandardEngine"
+			quid       	"3DFE034700C2"
+			collaborators 	(list link_list
+			    (object Link
+				quid       	"3DFE03750050"
+				supplier   	"StandardEngine"
+				quidu      	"3DFE034700C2"
+				messages   	(list Messages
+				    (object Message "fireLifecycleEvent(BEFORE_START_EVENT)"
+					quid       	"3DFE03750051"
+					frequency  	"Aperiodic"
+					synchronization 	"Simple"
+					dir        	"FromClientToSupplier"
+					sequence   	"2"
+					ordinal    	8
+					quidu      	"000000000000"
+					creation   	FALSE)
+				    (object Message "addDefaultMapper()"
+					quid       	"3DFE0389001C"
+					frequency  	"Aperiodic"
+					synchronization 	"Simple"
+					dir        	"FromClientToSupplier"
+					sequence   	"3"
+					ordinal    	9
+					quidu      	"000000000000"
+					creation   	FALSE)
+				    (object Message "logger.start()"
+					quid       	"3DFE03980281"
+					frequency  	"Aperiodic"
+					synchronization 	"Simple"
+					dir        	"FromClientToSupplier"
+					sequence   	"4"
+					ordinal    	10
+					quidu      	"000000000000"
+					creation   	FALSE)
+				    (object Message "realm.start()"
+					quid       	"3DFE03A80107"
+					frequency  	"Aperiodic"
+					synchronization 	"Simple"
+					dir        	"FromClientToSupplier"
+					sequence   	"5"
+					ordinal    	11
+					quidu      	"000000000000"
+					creation   	FALSE)
+				    (object Message "findMappers()"
+					quid       	"3DFE03BD000D"
+					frequency  	"Aperiodic"
+					synchronization 	"Simple"
+					dir        	"FromClientToSupplier"
+					sequence   	"6"
+					ordinal    	12
+					quidu      	"000000000000"
+					creation   	FALSE)
+				    (object Message "findChildren()"
+					quid       	"3DFE03E000A4"
+					frequency  	"Aperiodic"
+					synchronization 	"Simple"
+					dir        	"FromClientToSupplier"
+					sequence   	"7"
+					ordinal    	13
+					quidu      	"000000000000"
+					creation   	FALSE)))
+			    (object Link
+				quid       	"3DFE03FB0279"
+				supplier   	"StandardHost"
+				quidu      	"3DFE03F2035D"
+				messages   	(list Messages
+				    (object Message "start()"
+					quid       	"3DFE03FB027A"
+					frequency  	"Aperiodic"
+					synchronization 	"Simple"
+					dir        	"FromClientToSupplier"
+					sequence   	"8"
+					ordinal    	14
+					quidu      	"000000000000"
+					creation   	FALSE))))
+			persistence 	"Transient"
+			creationObj 	FALSE
+			multi      	FALSE)
+		    (object Object "StandardHost"
+			quid       	"3DFE03F2035D"
+			collaborators 	(list link_list
+			    (object Link
+				quid       	"3DFE043B02AD"
+				supplier   	"StandardHost"
+				quidu      	"3DFE03F2035D"
+				messages   	(list Messages
+				    (object Message "fireLifecycleEvent(BEFORE_START_EVENT)"
+					quid       	"3DFE043B02AE"
+					frequency  	"Aperiodic"
+					synchronization 	"Simple"
+					dir        	"FromClientToSupplier"
+					sequence   	"8.1"
+					ordinal    	15
+					quidu      	"000000000000"
+					creation   	FALSE)
+				    (object Message "addDefaultMapper()"
+					quid       	"3DFE045C021F"
+					frequency  	"Aperiodic"
+					synchronization 	"Simple"
+					dir        	"FromClientToSupplier"
+					sequence   	"8.2"
+					ordinal    	16
+					quidu      	"000000000000"
+					creation   	FALSE)
+				    (object Message "logger.start()"
+					quid       	"3DFE049B000C"
+					frequency  	"Aperiodic"
+					synchronization 	"Simple"
+					dir        	"FromClientToSupplier"
+					sequence   	"8.3"
+					ordinal    	17
+					quidu      	"000000000000"
+					creation   	FALSE)
+				    (object Message "findMapper()"
+					quid       	"3DFE04A303BB"
+					frequency  	"Aperiodic"
+					synchronization 	"Simple"
+					dir        	"FromClientToSupplier"
+					sequence   	"8.4"
+					ordinal    	18
+					quidu      	"000000000000"
+					creation   	FALSE)
+				    (object Message "findChildren()"
+					quid       	"3DFE04A90342"
+					frequency  	"Aperiodic"
+					synchronization 	"Simple"
+					dir        	"FromClientToSupplier"
+					sequence   	"8.5"
+					ordinal    	19
+					Operation  	"findChildren"
+					quidu      	"000000000000"
+					creation   	FALSE)))
+			    (object Link
+				quid       	"3DFE048E00B8"
+				supplier   	"StandardPipeline"
+				quidu      	"3DFE047D006D"
+				messages   	(list Messages
+				    (object Message "start()"
+					quid       	"3DFE048E00B9"
+					frequency  	"Aperiodic"
+					synchronization 	"Simple"
+					dir        	"FromClientToSupplier"
+					sequence   	"8.6"
+					ordinal    	20
+					quidu      	"000000000000"
+					creation   	FALSE))))
+			persistence 	"Transient"
+			creationObj 	FALSE
+			multi      	FALSE)
+		    (object Object "StandardPipeline"
+			quid       	"3DFE047D006D"
+			collaborators 	(list link_list
+			    (object Link
+				quid       	"3DFE05780137"
+				supplier   	"StandardPipeline"
+				quidu      	"3DFE047D006D"
+				messages   	(list Messages
+				    (object Message "fireLifecycleEvent(BEFORE_START_EVENT)"
+					quid       	"3DFE05780138"
+					frequency  	"Aperiodic"
+					synchronization 	"Simple"
+					dir        	"FromClientToSupplier"
+					sequence   	"8.6.1"
+					ordinal    	21
+					Operation  	"fireLifecycleEvent(AFTER_START_EVENT)"
+					quidu      	"000000000000"
+					creation   	FALSE)
+				    (object Message "fireLifecycleEvent(START_EVENT)"
+					quid       	"3DFE05A80398"
+					frequency  	"Aperiodic"
+					synchronization 	"Simple"
+					dir        	"FromClientToSupplier"
+					sequence   	"8.6.2"
+					ordinal    	22
+					Operation  	"fireLifecycleEvent(BEFORE_START_EVENT)"
+					quidu      	"000000000000"
+					creation   	FALSE)
+				    (object Message "fireLifecycleEvent(AFTER_EVENT)"
+					quid       	"3DFE05BA0196"
+					frequency  	"Aperiodic"
+					synchronization 	"Simple"
+					dir        	"FromClientToSupplier"
+					sequence   	"8.6.3"
+					ordinal    	23
+					quidu      	"000000000000"
+					creation   	FALSE))))
+			persistence 	"Transient"
+			creationObj 	FALSE
+			multi      	FALSE)))
+	    (object Mechanism @85
+		logical_models 	(list unit_reference_list
+		    (object Object "StandardHost"
+			quid       	"3DFE0538017B"
+			collaborators 	(list link_list
+			    (object Link
+				quid       	"3DFE066C0340"
+				supplier   	"StandardHost"
+				quidu      	"3DFE0538017B"
+				messages   	(list Messages
+				    (object Message "fireLifecycleEvent(START_EVENT)"
+					quid       	"3DFE066C0341"
+					frequency  	"Aperiodic"
+					synchronization 	"Simple"
+					dir        	"FromClientToSupplier"
+					sequence   	"1"
+					ordinal    	0
+					quidu      	"000000000000"
+					creation   	FALSE)))
+			    (object Link
+				quid       	"3DFE06D20293"
+				supplier   	"HostConfig"
+				quidu      	"3DFE06A60131"
+				messages   	(list Messages
+				    (object Message "interested[i].lifecycleEvent()"
+					quid       	"3DFE06D20294"
+					frequency  	"Aperiodic"
+					synchronization 	"Simple"
+					dir        	"FromClientToSupplier"
+					sequence   	"2"
+					ordinal    	1
+					quidu      	"000000000000"
+					creation   	FALSE)
+				    (object Message "install()"
+					quid       	"3DFE078B03BB"
+					frequency  	"Aperiodic"
+					synchronization 	"Simple"
+					dir        	"ToClientFromSupplier"
+					sequence   	"2.6"
+					ordinal    	7
+					quidu      	"000000000000"
+					creation   	FALSE)
+				    (object Message "install()"
+					quid       	"3DFE132D0309"
+					frequency  	"Aperiodic"
+					synchronization 	"Simple"
+					dir        	"ToClientFromSupplier"
+					sequence   	"5"
+					ordinal    	13
+					quidu      	"000000000000"
+					creation   	FALSE)))
+			    (object Link
+				quid       	"3DFE07B100BD"
+				supplier   	"StandardHostDeployer"
+				quidu      	"3DFE079A0055"
+				messages   	(list Messages
+				    (object Message "install()"
+					quid       	"3DFE07B100BE"
+					frequency  	"Aperiodic"
+					synchronization 	"Simple"
+					dir        	"FromClientToSupplier"
+					sequence   	"3"
+					ordinal    	8
+					quidu      	"000000000000"
+					creation   	FALSE)
+				    (object Message "install() // same as above"
+					quid       	"3DFE133A036C"
+					frequency  	"Aperiodic"
+					synchronization 	"Simple"
+					dir        	"FromClientToSupplier"
+					sequence   	"6"
+					ordinal    	17
+					Operation  	"install()"
+					quidu      	"000000000000"
+					creation   	FALSE))))
+			persistence 	"Transient"
+			creationObj 	FALSE
+			multi      	FALSE)
+		    (object Object "HostConfig"
+			quid       	"3DFE06A60131"
+			collaborators 	(list link_list
+			    (object Link
+				quid       	"3DFE06E9028C"
+				supplier   	"HostConfig"
+				quidu      	"3DFE06A60131"
+				messages   	(list Messages
+				    (object Message "setDeployXML()"
+					quid       	"3DFE06E9028D"
+					frequency  	"Aperiodic"
+					synchronization 	"Simple"
+					dir        	"FromClientToSupplier"
+					sequence   	"2.1"
+					ordinal    	2
+					quidu      	"000000000000"
+					creation   	FALSE)
+				    (object Message "setLiveDeploy()"
+					quid       	"3DFE06F300FF"
+					frequency  	"Aperiodic"
+					synchronization 	"Simple"
+					dir        	"FromClientToSupplier"
+					sequence   	"2.2"
+					ordinal    	3
+					quidu      	"000000000000"
+					creation   	FALSE)
+				    (object Message "setUnpacksWar()"
+					quid       	"3DFE06FB00D9"
+					frequency  	"Aperiodic"
+					synchronization 	"Simple"
+					dir        	"FromClientToSupplier"
+					sequence   	"2.3"
+					ordinal    	4
+					quidu      	"000000000000"
+					creation   	FALSE)
+				    (object Message "setXMLValidation()"
+					quid       	"3DFE070C0015"
+					frequency  	"Aperiodic"
+					synchronization 	"Simple"
+					dir        	"FromClientToSupplier"
+					sequence   	"2.4"
+					ordinal    	5
+					quidu      	"000000000000"
+					creation   	FALSE)
+				    (object Message "deployDescriptors()"
+					quid       	"3DFE073B0031"
+					frequency  	"Aperiodic"
+					synchronization 	"Simple"
+					dir        	"FromClientToSupplier"
+					sequence   	"2.5"
+					ordinal    	6
+					quidu      	"000000000000"
+					creation   	FALSE)
+				    (object Message "deployApps()"
+					quid       	"3DFE131F0327"
+					frequency  	"Aperiodic"
+					synchronization 	"Simple"
+					dir        	"FromClientToSupplier"
+					sequence   	"4"
+					ordinal    	12
+					quidu      	"000000000000"
+					creation   	FALSE))))
+			persistence 	"Transient"
+			creationObj 	FALSE
+			multi      	FALSE)
+		    (object Object "StandardHostDeployer"
+			quid       	"3DFE079A0055"
+			collaborators 	(list link_list
+			    (object Link
+				quid       	"3DFE07D200EC"
+				supplier   	"Digester"
+				quidu      	"3DFE07C9034C"
+				messages   	(list Messages
+				    (object Message "create()"
+					quid       	"3DFE07D200ED"
+					frequency  	"Aperiodic"
+					synchronization 	"Simple"
+					dir        	"FromClientToSupplier"
+					sequence   	"3.1"
+					ordinal    	9
+					quidu      	"000000000000"
+					creation   	FALSE)
+				    (object Message "parse()"
+					quid       	"3DFE07D603D7"
+					frequency  	"Aperiodic"
+					synchronization 	"Simple"
+					dir        	"FromClientToSupplier"
+					sequence   	"3.6"
+					ordinal    	16
+					quidu      	"000000000000"
+					creation   	FALSE)
+				    (object Message "add(ContextRuleSet)"
+					quid       	"3DFE08FA003D"
+					frequency  	"Aperiodic"
+					synchronization 	"Simple"
+					dir        	"FromClientToSupplier"
+					sequence   	"3.3"
+					ordinal    	11
+					quidu      	"000000000000"
+					creation   	FALSE)))
+			    (object Link
+				quid       	"3DFE087D01E2"
+				supplier   	"StandardHostDeployer"
+				quidu      	"3DFE079A0055")
+			    (object Link
+				quid       	"3DFE08DA029A"
+				supplier   	"ContextRuleSet"
+				quidu      	"3DFE0834016F"
+				messages   	(list Messages
+				    (object Message "new()"
+					quid       	"3DFE08DA029B"
+					frequency  	"Aperiodic"
+					synchronization 	"Simple"
+					dir        	"FromClientToSupplier"
+					sequence   	"3.2"
+					ordinal    	10
+					quidu      	"000000000000"
+					creation   	FALSE)
+				    (object Message "add(NamingRuleSet())"
+					quid       	"3DFE0907015F"
+					frequency  	"Aperiodic"
+					synchronization 	"Simple"
+					dir        	"FromClientToSupplier"
+					sequence   	"3.5"
+					ordinal    	15
+					quidu      	"000000000000"
+					creation   	FALSE)))
+			    (object Link
+				quid       	"3DFE08E00090"
+				supplier   	"NamingRuleSet"
+				quidu      	"3DFE08D00173"
+				messages   	(list Messages
+				    (object Message "new()"
+					quid       	"3DFE08E00091"
+					frequency  	"Aperiodic"
+					synchronization 	"Simple"
+					dir        	"FromClientToSupplier"
+					sequence   	"3.4"
+					ordinal    	14
+					quidu      	"000000000000"
+					creation   	FALSE))))
+			persistence 	"Transient"
+			creationObj 	FALSE
+			multi      	FALSE)
+		    (object Object "Digester"
+			quid       	"3DFE07C9034C"
+			persistence 	"Transient"
+			creationObj 	FALSE
+			multi      	FALSE)
+		    (object Object "ContextRuleSet"
+			quid       	"3DFE0834016F"
+			persistence 	"Transient"
+			creationObj 	FALSE
+			multi      	FALSE)
+		    (object Object "NamingRuleSet"
+			quid       	"3DFE08D00173"
+			persistence 	"Transient"
+			creationObj 	FALSE
+			multi      	FALSE)))
+	    (object Mechanism @86
+		logical_models 	(list unit_reference_list
+		    (object Object "Digester"
+			quid       	"3DFE095A0371"
+			collaborators 	(list link_list
+			    (object Link
+				quid       	"3DFE0E7801DA"
+				supplier   	"Digester"
+				quidu      	"3DFE095A0371"
+				messages   	(list Messages
+				    (object Message "parse"
+					quid       	"3DFE0E7801DB"
+					frequency  	"Aperiodic"
+					synchronization 	"Simple"
+					dir        	"FromClientToSupplier"
+					sequence   	"1"
+					ordinal    	0
+					quidu      	"000000000000"
+					creation   	FALSE)
+				    (object Message "startElement()"
+					quid       	"3DFE0F2F03D2"
+					frequency  	"Aperiodic"
+					synchronization 	"Simple"
+					dir        	"FromClientToSupplier"
+					sequence   	"2"
+					ordinal    	1
+					quidu      	"000000000000"
+					creation   	FALSE)))
+			    (object Link
+				quid       	"3DFE0F400213"
+				supplier   	"Rule"
+				quidu      	"3DFE0E7400D0"
+				messages   	(list Messages
+				    (object Message "begin()"
+					quid       	"3DFE0F400214"
+					frequency  	"Aperiodic"
+					synchronization 	"Simple"
+					dir        	"FromClientToSupplier"
+					sequence   	"3"
+					ordinal    	2
+					quidu      	"000000000000"
+					creation   	FALSE))))
+			persistence 	"Transient"
+			creationObj 	FALSE
+			multi      	FALSE)
+		    (object Object "Rule"
+			quid       	"3DFE0E7400D0"
+			collaborators 	(list link_list
+			    (object Link
+				quid       	"3DFE0FD30265"
+				supplier   	"StandardContext"
+				quidu      	"3DFE0FC502A1"
+				messages   	(list Messages
+				    (object Message "newInstance()"
+					quid       	"3DFE0FD30266"
+					frequency  	"Aperiodic"
+					synchronization 	"Simple"
+					dir        	"FromClientToSupplier"
+					sequence   	"3.1"
+					ordinal    	3
+					quidu      	"000000000000"
+					creation   	FALSE)))
+			    (object Link
+				quid       	"3DFE102002E8"
+				supplier   	"SetPropertiesRule"
+				quidu      	"3DFE100303A4"
+				messages   	(list Messages
+				    (object Message "begin()"
+					quid       	"3DFE102002E9"
+					frequency  	"Aperiodic"
+					synchronization 	"Simple"
+					dir        	"FromClientToSupplier"
+					sequence   	"3.2"
+					ordinal    	6
+					quidu      	"000000000000"
+					creation   	FALSE)))
+			    (object Link
+				quid       	"3DFE127F0024"
+				supplier   	"Rule"
+				quidu      	"3DFE0E7400D0")
+			    (object Link
+				quid       	"3DFE128501C7"
+				supplier   	"SetNextRule"
+				quidu      	"3DFE12690267"
+				messages   	(list Messages
+				    (object Message "end()"
+					quid       	"3DFE128501C8"
+					frequency  	"Aperiodic"
+					synchronization 	"Simple"
+					dir        	"FromClientToSupplier"
+					sequence   	"3.3"
+					ordinal    	8
+					quidu      	"000000000000"
+					creation   	FALSE))))
+			persistence 	"Transient"
+			creationObj 	FALSE
+			multi      	FALSE)
+		    (object Object "StandardContext"
+			quid       	"3DFE0FC502A1"
+			collaborators 	(list link_list
+			    (object Link
+				quid       	"3DFE114A0192"
+				supplier   	"StandardPipeline"
+				quidu      	"3DFE112F003F"
+				messages   	(list Messages
+				    (object Message "setBasic(StandardContextValve)"
+					quid       	"3DFE114A0193"
+					frequency  	"Aperiodic"
+					synchronization 	"Simple"
+					dir        	"FromClientToSupplier"
+					sequence   	"3.1.2"
+					ordinal    	5
+					Operation  	"setBasic"
+					quidu      	"000000000000"
+					creation   	FALSE)))
+			    (object Link
+				quid       	"3DFE115E001E"
+				supplier   	"StandardContextValve"
+				quidu      	"3DFE110D0375"
+				messages   	(list Messages
+				    (object Message "new()"
+					quid       	"3DFE115E001F"
+					frequency  	"Aperiodic"
+					synchronization 	"Simple"
+					dir        	"FromClientToSupplier"
+					sequence   	"3.1.1"
+					ordinal    	4
+					quidu      	"000000000000"
+					creation   	FALSE))))
+			persistence 	"Transient"
+			creationObj 	FALSE
+			multi      	FALSE)
+		    (object Object "SetPropertiesRule"
+			quid       	"3DFE100303A4"
+			collaborators 	(list link_list
+			    (object Link
+				quid       	"3DFE11D50390"
+				supplier   	"StandardContext"
+				quidu      	"3DFE0FC502A1"
+				messages   	(list Messages
+				    (object Message "//Using BeanUtil, set the object properties (from ex: admin.xml)"
+					quid       	"3DFE11D50391"
+					frequency  	"Aperiodic"
+					synchronization 	"Simple"
+					dir        	"FromClientToSupplier"
+					sequence   	"3.2.1"
+					ordinal    	7
+					quidu      	"000000000000"
+					creation   	FALSE))))
+			persistence 	"Transient"
+			creationObj 	FALSE
+			multi      	FALSE)
+		    (object Object "StandardContextValve"
+			quid       	"3DFE110D0375"
+			persistence 	"Transient"
+			creationObj 	FALSE
+			multi      	FALSE)
+		    (object Object "StandardPipeline"
+			quid       	"3DFE112F003F"
+			persistence 	"Transient"
+			creationObj 	FALSE
+			multi      	FALSE)
+		    (object Object "SetNextRule"
+			quid       	"3DFE12690267"
+			persistence 	"Transient"
+			creationObj 	FALSE
+			multi      	FALSE)))
+	    (object Mechanism @87
+		logical_models 	(list unit_reference_list
+		    (object Object "StandardContext"
+			quid       	"3DFE196D00D9"
+			collaborators 	(list link_list
+			    (object Link
+				quid       	"3DFE200603BD"
+				supplier   	"WebappLoader"
+				quidu      	"3DFE1FFA0347"
+				messages   	(list Messages
+				    (object Message "new"
+					quid       	"3DFE200603BE"
+					frequency  	"Aperiodic"
+					synchronization 	"Simple"
+					dir        	"FromClientToSupplier"
+					sequence   	"3.1.1.1"
+					ordinal    	5
+					quidu      	"000000000000"
+					creation   	FALSE)))
+			    (object Link
+				quid       	"3DFE200C0299"
+				supplier   	"StandardContext"
+				quidu      	"3DFE196D00D9"
+				messages   	(list Messages
+				    (object Message "setLoader"
+					quid       	"3DFE200C029A"
+					frequency  	"Aperiodic"
+					synchronization 	"Simple"
+					dir        	"FromClientToSupplier"
+					sequence   	"3.1.1.2"
+					ordinal    	6
+					quidu      	"000000000000"
+					creation   	FALSE)
+				    (object Message "setManager"
+					quid       	"3DFE2032001C"
+					frequency  	"Aperiodic"
+					synchronization 	"Simple"
+					dir        	"FromClientToSupplier"
+					sequence   	"3.1.1.4"
+					ordinal    	8
+					quidu      	"000000000000"
+					creation   	FALSE)
+				    (object Message "fireLifecycleEvent(START_EVENT)"
+					quid       	"3DFE205B01A2"
+					frequency  	"Aperiodic"
+					synchronization 	"Simple"
+					dir        	"FromClientToSupplier"
+					sequence   	"3.1.1.5"
+					ordinal    	9
+					quidu      	"000000000000"
+					creation   	FALSE)))
+			    (object Link
+				quid       	"3DFE202C024F"
+				supplier   	"StandardManager"
+				quidu      	"3DFE201F0105"
+				messages   	(list Messages
+				    (object Message "new"
+					quid       	"3DFE202C0250"
+					frequency  	"Aperiodic"
+					synchronization 	"Simple"
+					dir        	"FromClientToSupplier"
+					sequence   	"3.1.1.3"
+					ordinal    	7
+					quidu      	"000000000000"
+					creation   	FALSE)
+				    (object Message "start()"
+					quid       	"3DFE20B600E5"
+					frequency  	"Aperiodic"
+					synchronization 	"Simple"
+					dir        	"FromClientToSupplier"
+					sequence   	"3.1.1.7"
+					ordinal    	12
+					quidu      	"000000000000"
+					creation   	FALSE)))
+			    (object Link
+				quid       	"3DFE20960002"
+				supplier   	"ContextConfig"
+				quidu      	"3DFE2087028C"
+				messages   	(list Messages
+				    (object Message " // Notify interested LifecycleListeners"
+					quid       	"3DFE20960003"
+					frequency  	"Aperiodic"
+					synchronization 	"Simple"
+					dir        	"FromClientToSupplier"
+					sequence   	"3.1.1.6"
+					ordinal    	10
+					quidu      	"000000000000"
+					creation   	FALSE))))
+			persistence 	"Transient"
+			creationObj 	FALSE
+			multi      	FALSE)
+		    (object Object "StandardHostDeployer"
+			quid       	"3DFE1D8A02DC"
+			collaborators 	(list link_list
+			    (object Link
+				quid       	"3DFE1FAF0014"
+				supplier   	"StandardHost"
+				quidu      	"3DFE1DF20141"
+				messages   	(list Messages
+				    (object Message "addChild"
+					quid       	"3DFE1FB60277"
+					frequency  	"Aperiodic"
+					synchronization 	"Simple"
+					dir        	"FromClientToSupplier"
+					sequence   	"3.1"
+					ordinal    	3
+					quidu      	"000000000000"
+					creation   	FALSE))))
+			persistence 	"Transient"
+			creationObj 	FALSE
+			multi      	FALSE)
+		    (object Object "StandardHost"
+			quid       	"3DFE1DF20141"
+			collaborators 	(list link_list
+			    (object Link
+				quid       	"3DFE1FC40227"
+				supplier   	"StandardContext"
+				quidu      	"3DFE196D00D9"
+				messages   	(list Messages
+				    (object Message "start()"
+					quid       	"3DFE1FC40228"
+					frequency  	"Aperiodic"
+					synchronization 	"Simple"
+					dir        	"FromClientToSupplier"
+					sequence   	"3.1.1"
+					ordinal    	4
+					quidu      	"000000000000"
+					creation   	FALSE))))
+			persistence 	"Transient"
+			creationObj 	FALSE
+			multi      	FALSE)
+		    (object Object "WebappLoader"
+			quid       	"3DFE1FFA0347"
+			persistence 	"Transient"
+			creationObj 	FALSE
+			multi      	FALSE)
+		    (object Object "StandardManager"
+			quid       	"3DFE201F0105"
+			persistence 	"Transient"
+			creationObj 	FALSE
+			multi      	FALSE)
+		    (object Object "ContextConfig"
+			quid       	"3DFE2087028C"
+			collaborators 	(list link_list
+			    (object Link
+				quid       	"3DFE20CF018B"
+				supplier   	"ContextConfig"
+				quidu      	"3DFE2087028C"
+				messages   	(list Messages
+				    (object Message "start()"
+					quid       	"3DFE20CF018C"
+					frequency  	"Aperiodic"
+					synchronization 	"Simple"
+					dir        	"FromClientToSupplier"
+					sequence   	"3.1.1.6.1"
+					ordinal    	11
+					quidu      	"000000000000"
+					creation   	FALSE)
+				    (object Message "defaultConfig()"
+					quid       	"3DFE20E303E2"
+					frequency  	"Aperiodic"
+					synchronization 	"Simple"
+					dir        	"FromClientToSupplier"
+					sequence   	"3.1.1.6.2"
+					ordinal    	13
+					quidu      	"000000000000"
+					creation   	FALSE)
+				    (object Message "applicationConfig()"
+					quid       	"3DFE211D01A1"
+					frequency  	"Aperiodic"
+					synchronization 	"Simple"
+					dir        	"FromClientToSupplier"
+					sequence   	"3.1.1.6.3"
+					ordinal    	14
+					Operation  	"applicationConfig"
+					quidu      	"000000000000"
+					creation   	FALSE)))
+			    (object Link
+				quid       	"3DFE21B60287"
+				supplier   	"Digester"
+				quidu      	"3DFE13960364"
+				messages   	(list Messages
+				    (object Message "create()"
+					quid       	"3DFE21B60288"
+					frequency  	"Aperiodic"
+					synchronization 	"Simple"
+					dir        	"FromClientToSupplier"
+					sequence   	"3.1.1.6.3.1"
+					ordinal    	15
+					quidu      	"000000000000"
+					creation   	FALSE)
+				    (object Message "createWarpper() // Invoked by a WebWrapperRule (not Directly by the Digester)"
+					quid       	"3DFE228B03BA"
+					frequency  	"Aperiodic"
+					synchronization 	"Simple"
+					dir        	"ToClientFromSupplier"
+					sequence   	"3.1.1.6.3.1.2"
+					ordinal    	17
+					Operation  	"createWarpper() // Invoked by a Rule (not Directly by the Digester)"
+					quidu      	"000000000000"
+					creation   	FALSE)))
+			    (object Link
+				quid       	"3DFE22560061"
+				supplier   	"StandardWrapper"
+				quidu      	"3DFE220C0122"
+				messages   	(list Messages
+				    (object Message "new"
+					quid       	"3DFE229A0004"
+					frequency  	"Aperiodic"
+					synchronization 	"Simple"
+					dir        	"FromClientToSupplier"
+					sequence   	"3.1.1.6.3.1.2.1"
+					ordinal    	18
+					quidu      	"000000000000"
+					creation   	FALSE)
+				    (object Message "addInstanceListener()"
+					quid       	"3DFE22A700C1"
+					frequency  	"Aperiodic"
+					synchronization 	"Simple"
+					dir        	"FromClientToSupplier"
+					sequence   	"3.1.1.6.3.2"
+					ordinal    	19
+					Operation  	"addInstanceListener"
+					quidu      	"000000000000"
+					creation   	FALSE)
+				    (object Message "addLifecycleListener()"
+					quid       	"3DFE22C701CC"
+					frequency  	"Aperiodic"
+					synchronization 	"Simple"
+					dir        	"FromClientToSupplier"
+					sequence   	"3.1.1.6.3.3"
+					ordinal    	20
+					quidu      	"000000000000"
+					creation   	FALSE)
+				    (object Message "addContainerListener()"
+					quid       	"3DFE22E80364"
+					frequency  	"Aperiodic"
+					synchronization 	"Simple"
+					dir        	"FromClientToSupplier"
+					sequence   	"3.1.1.6.3.4"
+					ordinal    	21
+					quidu      	"000000000000"
+					creation   	FALSE))))
+			persistence 	"Transient"
+			creationObj 	TRUE
+			multi      	FALSE)
+		    (object Object "Digester"
+			quid       	"3DFE13960364"
+			collaborators 	(list link_list
+			    (object Link
+				quid       	"3DFE19AE0064"
+				supplier   	"Digester"
+				quidu      	"3DFE13960364"
+				messages   	(list Messages
+				    (object Message "parse"
+					quid       	"3DFE19AE0065"
+					frequency  	"Aperiodic"
+					synchronization 	"Simple"
+					dir        	"FromClientToSupplier"
+					sequence   	"1"
+					ordinal    	0
+					quidu      	"000000000000"
+					creation   	FALSE)
+				    (object Message "startElement()"
+					quid       	"3DFE19B102E9"
+					frequency  	"Aperiodic"
+					synchronization 	"Simple"
+					dir        	"FromClientToSupplier"
+					sequence   	"2"
+					ordinal    	1
+					quidu      	"000000000000"
+					creation   	FALSE)
+				    (object Message "// Process web.xml * tld.xml"
+					quid       	"3DFE21BE021B"
+					frequency  	"Aperiodic"
+					synchronization 	"Simple"
+					dir        	"FromClientToSupplier"
+					sequence   	"3.1.1.6.3.1.1"
+					ordinal    	16
+					quidu      	"000000000000"
+					creation   	FALSE)))
+			    (object Link
+				quid       	"3DFE1DFB0021"
+				supplier   	"StandardHostDeployer"
+				quidu      	"3DFE1D8A02DC"
+				messages   	(list Messages
+				    (object Message "addChild"
+					quid       	"3DFE1DFB0022"
+					frequency  	"Aperiodic"
+					synchronization 	"Simple"
+					dir        	"FromClientToSupplier"
+					sequence   	"3"
+					ordinal    	2
+					quidu      	"000000000000"
+					creation   	FALSE)))
+			    (object Link
+				quid       	"3DFE22190225"
+				supplier   	"StandardWrapper"
+				quidu      	"3DFE220C0122"))
+			persistence 	"Transient"
+			creationObj 	FALSE
+			multi      	FALSE)
+		    (object Object "StandardWrapper"
+			quid       	"3DFE220C0122"
+			persistence 	"Transient"
+			creationObj 	FALSE
+			multi      	FALSE)))
+	    (object Mechanism @88
+		logical_models 	(list unit_reference_list
+		    (object Object "ThreadPool"
+			quid       	"3DFE402B02C5"
+			collaborators 	(list link_list
+			    (object Link
+				quid       	"3DFE40E701AD"
+				supplier   	"TcpWorkerThread"
+				quidu      	"3DFE403200F8"
+				messages   	(list Messages
+				    (object Message "runIt()"
+					quid       	"3DFE40E701AE"
+					frequency  	"Aperiodic"
+					synchronization 	"Simple"
+					dir        	"FromClientToSupplier"
+					sequence   	"1"
+					ordinal    	0
+					quidu      	"000000000000"
+					creation   	FALSE))))
+			persistence 	"Transient"
+			creationObj 	FALSE
+			multi      	FALSE)
+		    (object Object "TcpWorkerThread"
+			quid       	"3DFE403200F8"
+			collaborators 	(list link_list
+			    (object Link
+				quid       	"3DFE40FC010D"
+				supplier   	"Http11Protocol"
+				quidu      	"3DFE40750177"
+				messages   	(list Messages
+				    (object Message "processConnection"
+					quid       	"3DFE40FC010E"
+					frequency  	"Aperiodic"
+					synchronization 	"Simple"
+					dir        	"FromClientToSupplier"
+					sequence   	"1.1"
+					ordinal    	1
+					quidu      	"000000000000"
+					creation   	FALSE))))
+			persistence 	"Transient"
+			creationObj 	FALSE
+			multi      	FALSE)
+		    (object Object "Http11Protocol"
+			quid       	"3DFE40750177"
+			collaborators 	(list link_list
+			    (object Link
+				quid       	"3DFE4111029E"
+				supplier   	"Http11Protocol"
+				quidu      	"3DFE40750177"
+				messages   	(list Messages
+				    (object Message "process()"
+					quid       	"3DFE4111029F"
+					frequency  	"Aperiodic"
+					synchronization 	"Simple"
+					dir        	"FromClientToSupplier"
+					sequence   	"1.1.1"
+					ordinal    	2
+					quidu      	"000000000000"
+					creation   	FALSE)
+				    (object Message "parseHeaders()"
+					quid       	"3DFE415C0151"
+					frequency  	"Aperiodic"
+					synchronization 	"Simple"
+					dir        	"FromClientToSupplier"
+					sequence   	"2"
+					ordinal    	3
+					quidu      	"000000000000"
+					creation   	FALSE)
+				    (object Message "prepareRequest()"
+					quid       	"3DFE41A60161"
+					frequency  	"Aperiodic"
+					synchronization 	"Simple"
+					dir        	"FromClientToSupplier"
+					sequence   	"3"
+					ordinal    	4
+					quidu      	"000000000000"
+					creation   	FALSE)))
+			    (object Link
+				quid       	"3DFE41D60106"
+				supplier   	"CoyoteAdapter"
+				quidu      	"3DFE410600DF"
+				messages   	(list Messages
+				    (object Message "service()"
+					quid       	"3DFE41D60107"
+					frequency  	"Aperiodic"
+					synchronization 	"Simple"
+					dir        	"FromClientToSupplier"
+					sequence   	"4"
+					ordinal    	5
+					quidu      	"000000000000"
+					creation   	FALSE))))
+			persistence 	"Transient"
+			creationObj 	FALSE
+			multi      	FALSE)
+		    (object Object "CoyoteAdapter"
+			quid       	"3DFE410600DF"
+			collaborators 	(list link_list
+			    (object Link
+				quid       	"3DFE422C01F0"
+				supplier   	"CoyoteAdapter"
+				quidu      	"3DFE410600DF"
+				messages   	(list Messages
+				    (object Message "postParseRequest()"
+					quid       	"3DFE422C01F1"
+					frequency  	"Aperiodic"
+					synchronization 	"Simple"
+					dir        	"FromClientToSupplier"
+					sequence   	"5"
+					ordinal    	6
+					quidu      	"000000000000"
+					creation   	FALSE)))
+			    (object Link
+				quid       	"3DFE42800237"
+				supplier   	"StandardEngine"
+				quidu      	"3DFE424B0349"
+				messages   	(list Messages
+				    (object Message "invoke()"
+					quid       	"3DFE42800238"
+					frequency  	"Aperiodic"
+					synchronization 	"Simple"
+					dir        	"FromClientToSupplier"
+					sequence   	"6"
+					ordinal    	7
+					quidu      	"000000000000"
+					creation   	FALSE))))
+			persistence 	"Transient"
+			creationObj 	FALSE
+			multi      	FALSE)
+		    (object Object "StandardEngine"
+			quid       	"3DFE424B0349"
+			collaborators 	(list link_list
+			    (object Link
+				quid       	"3DFE429A002C"
+				supplier   	"StandardPipeline"
+				quidu      	"3DFE42900045"
+				messages   	(list Messages
+				    (object Message "invoke()"
+					quid       	"3DFE429A002D"
+					frequency  	"Aperiodic"
+					synchronization 	"Simple"
+					dir        	"FromClientToSupplier"
+					sequence   	"6.1"
+					ordinal    	8
+					Operation  	"invoke"
+					quidu      	"000000000000"
+					creation   	FALSE))))
+			persistence 	"Transient"
+			creationObj 	FALSE
+			multi      	FALSE)
+		    (object Object "StandardPipeline"
+			quid       	"3DFE42900045"
+			collaborators 	(list link_list
+			    (object Link
+				quid       	"3DFE42CE022F"
+				supplier   	"StandardValveContext"
+				quidu      	"3DFE42C002B1"
+				messages   	(list Messages
+				    (object Message "invoke()"
+					quid       	"3DFE42CE0230"
+					frequency  	"Aperiodic"
+					synchronization 	"Simple"
+					dir        	"FromClientToSupplier"
+					sequence   	"6.1.1"
+					ordinal    	9
+					quidu      	"000000000000"
+					creation   	FALSE))))
+			persistence 	"Transient"
+			creationObj 	FALSE
+			multi      	FALSE)
+		    (object Object "StandardValveContext"
+			quid       	"3DFE42C002B1"
+			persistence 	"Transient"
+			creationObj 	FALSE
+			multi      	FALSE)))
+	    (object Mechanism @89
+		logical_models 	(list unit_reference_list
+		    (object Object "StandardContextValve"
+			quid       	"3DFE4307001E"
+			collaborators 	(list link_list
+			    (object Link
+				quid       	"3DFE434C019A"
+				supplier   	"StandardEngineValve"
+				quidu      	"3DFE432801F3"
+				messages   	(list Messages
+				    (object Message "invoke()"
+					quid       	"3DFE434C019B"
+					frequency  	"Aperiodic"
+					synchronization 	"Simple"
+					dir        	"FromClientToSupplier"
+					sequence   	"1"
+					ordinal    	0
+					quidu      	"000000000000"
+					creation   	FALSE)))
+			    (object Link
+				quid       	"3DFE43C203A3"
+				supplier   	"ErrorReportValve"
+				quidu      	"3DFE438C028D"
+				messages   	(list Messages
+				    (object Message "invoke()"
+					quid       	"3DFE43C203A4"
+					frequency  	"Aperiodic"
+					synchronization 	"Simple"
+					dir        	"FromClientToSupplier"
+					sequence   	"3"
+					ordinal    	4
+					quidu      	"000000000000"
+					creation   	FALSE)
+				    (object Message "invokeNext()"
+					quid       	"3DFE46330293"
+					frequency  	"Aperiodic"
+					synchronization 	"Simple"
+					dir        	"ToClientFromSupplier"
+					sequence   	"3.2"
+					ordinal    	6
+					quidu      	"000000000000"
+					creation   	FALSE)))
+			    (object Link
+				quid       	"3DFE46E70025"
+				supplier   	"ErrorDispatcherValve"
+				quidu      	"3DFE451F01EC"
+				messages   	(list Messages
+				    (object Message "invoke()"
+					quid       	"3DFE46E70026"
+					frequency  	"Aperiodic"
+					synchronization 	"Simple"
+					dir        	"FromClientToSupplier"
+					sequence   	"4"
+					ordinal    	7
+					quidu      	"000000000000"
+					creation   	FALSE)
+				    (object Message "invokeNext"
+					quid       	"3DFE475D03A0"
+					frequency  	"Aperiodic"
+					synchronization 	"Simple"
+					dir        	"ToClientFromSupplier"
+					sequence   	"4.1"
+					ordinal    	8
+					quidu      	"000000000000"
+					creation   	FALSE)))
+			    (object Link
+				quid       	"3DFE476503C9"
+				supplier   	"StandardHostValve"
+				quidu      	"3DFE47310130"
+				messages   	(list Messages
+				    (object Message "invoke()"
+					quid       	"3DFE476503CA"
+					frequency  	"Aperiodic"
+					synchronization 	"Simple"
+					dir        	"FromClientToSupplier"
+					sequence   	"5"
+					ordinal    	9
+					quidu      	"000000000000"
+					creation   	FALSE))))
+			persistence 	"Transient"
+			creationObj 	FALSE
+			multi      	FALSE)
+		    (object Object "StandardEngineValve"
+			quid       	"3DFE432801F3"
+			collaborators 	(list link_list
+			    (object Link
+				quid       	"3DFE436C009C"
+				supplier   	"StandardHost"
+				quidu      	"3DFE436503BD"
+				messages   	(list Messages
+				    (object Message "map()"
+					quid       	"3DFE436C009D"
+					frequency  	"Aperiodic"
+					synchronization 	"Simple"
+					dir        	"FromClientToSupplier"
+					sequence   	"1.1"
+					ordinal    	1
+					quidu      	"000000000000"
+					creation   	FALSE)
+				    (object Message "invoke()"
+					quid       	"3DFE43830063"
+					frequency  	"Aperiodic"
+					synchronization 	"Simple"
+					dir        	"FromClientToSupplier"
+					sequence   	"1.2"
+					ordinal    	2
+					quidu      	"000000000000"
+					creation   	FALSE)))
+			    (object Link
+				quid       	"3DFE437F0143"
+				supplier   	"StandardEngineValve"
+				quidu      	"3DFE432801F3"))
+			persistence 	"Transient"
+			creationObj 	FALSE
+			multi      	FALSE)
+		    (object Object "StandardHost"
+			quid       	"3DFE436503BD"
+			collaborators 	(list link_list
+			    (object Link
+				quid       	"3DFE43B903BE"
+				supplier   	"StandardContextValve"
+				quidu      	"3DFE4307001E"
+				messages   	(list Messages
+				    (object Message "invoke()"
+					quid       	"3DFE43B903BF"
+					frequency  	"Aperiodic"
+					synchronization 	"Simple"
+					dir        	"FromClientToSupplier"
+					sequence   	"2"
+					ordinal    	3
+					quidu      	"000000000000"
+					creation   	FALSE))))
+			persistence 	"Transient"
+			creationObj 	FALSE
+			multi      	FALSE)
+		    (object Object "ErrorReportValve"
+			quid       	"3DFE438C028D"
+			collaborators 	(list link_list
+			    (object Link
+				quid       	"3DFE442501B0"
+				supplier   	"ErrorReportValve"
+				quidu      	"3DFE438C028D"
+				messages   	(list Messages
+				    (object Message "report()"
+					quid       	"3DFE442501B1"
+					frequency  	"Aperiodic"
+					synchronization 	"Simple"
+					dir        	"FromClientToSupplier"
+					sequence   	"3.1"
+					ordinal    	5
+					quidu      	"000000000000"
+					creation   	FALSE)))
+			    (object Link
+				quid       	"3DFE452A00F7"
+				supplier   	"ErrorDispatcherValve"
+				quidu      	"3DFE451F01EC"))
+			persistence 	"Transient"
+			creationObj 	FALSE
+			multi      	FALSE)
+		    (object Object "ErrorDispatcherValve"
+			quid       	"3DFE451F01EC"
+			collaborators 	(list link_list
+			    (object Link
+				quid       	"3DFE47500148"
+				supplier   	"StandardHostValve"
+				quidu      	"3DFE47310130")
+			    (object Link
+				quid       	"3DFE47580335"
+				supplier   	"ErrorDispatcherValve"
+				quidu      	"3DFE451F01EC"))
+			persistence 	"Transient"
+			creationObj 	FALSE
+			multi      	FALSE)
+		    (object Object "StandardHostValve"
+			quid       	"3DFE47310130"
+			collaborators 	(list link_list
+			    (object Link
+				quid       	"3DFE47CD0166"
+				supplier   	"StandardHostValve"
+				quidu      	"3DFE47310130"
+				messages   	(list Messages
+				    (object Message "map() //Context"
+					quid       	"3DFE47CD0167"
+					frequency  	"Aperiodic"
+					synchronization 	"Simple"
+					dir        	"FromClientToSupplier"
+					sequence   	"5.1"
+					ordinal    	10
+					quidu      	"000000000000"
+					creation   	FALSE)))
+			    (object Link
+				quid       	"3DFE47D500B3"
+				supplier   	"StandardContext"
+				quidu      	"3DFE47C100F1"
+				messages   	(list Messages
+				    (object Message "invoke()"
+					quid       	"3DFE47D500B4"
+					frequency  	"Aperiodic"
+					synchronization 	"Simple"
+					dir        	"FromClientToSupplier"
+					sequence   	"5.2"
+					ordinal    	11
+					quidu      	"000000000000"
+					creation   	FALSE))))
+			persistence 	"Transient"
+			creationObj 	FALSE
+			multi      	FALSE)
+		    (object Object "StandardContext"
+			quid       	"3DFE47C100F1"
+			persistence 	"Transient"
+			creationObj 	FALSE
+			multi      	FALSE)))
+	    (object Mechanism @90
+		logical_models 	(list unit_reference_list
+		    (object Object "StandardContext"
+			quid       	"3DFE48B001D1"
+			collaborators 	(list link_list
+			    (object Link
+				quid       	"3DFE48BE0267"
+				supplier   	"StandardPipeline"
+				quidu      	"3DFE48B80088"
+				messages   	(list Messages
+				    (object Message "invoke()"
+					quid       	"3DFE48BE0268"
+					frequency  	"Aperiodic"
+					synchronization 	"Simple"
+					dir        	"FromClientToSupplier"
+					sequence   	"1"
+					ordinal    	0
+					quidu      	"000000000000"
+					creation   	FALSE))))
+			persistence 	"Transient"
+			creationObj 	FALSE
+			multi      	FALSE)
+		    (object Object "StandardPipeline"
+			quid       	"3DFE48B80088"
+			collaborators 	(list link_list
+			    (object Link
+				quid       	"3DFE48EA0039"
+				supplier   	"StandardValveContext"
+				quidu      	"3DFE48D000DC"
+				messages   	(list Messages
+				    (object Message "invoke()"
+					quid       	"3DFE48EA003A"
+					frequency  	"Aperiodic"
+					synchronization 	"Simple"
+					dir        	"FromClientToSupplier"
+					sequence   	"1.1"
+					ordinal    	1
+					quidu      	"000000000000"
+					creation   	FALSE)
+				    (object Message "invoke()"
+					quid       	"3DFE4976015D"
+					frequency  	"Aperiodic"
+					synchronization 	"Simple"
+					dir        	"FromClientToSupplier"
+					sequence   	"1.2"
+					ordinal    	6
+					quidu      	"000000000000"
+					creation   	FALSE))))
+			persistence 	"Transient"
+			creationObj 	FALSE
+			multi      	FALSE)
+		    (object Object "StandardValveContext"
+			quid       	"3DFE48D000DC"
+			collaborators 	(list link_list
+			    (object Link
+				quid       	"3DFE491102D5"
+				supplier   	"StandardContextValve"
+				quidu      	"3DFE490303A7"
+				messages   	(list Messages
+				    (object Message "invoke()"
+					quid       	"3DFE491102D6"
+					frequency  	"Aperiodic"
+					synchronization 	"Simple"
+					dir        	"FromClientToSupplier"
+					sequence   	"1.1.1"
+					ordinal    	2
+					quidu      	"000000000000"
+					creation   	FALSE)))
+			    (object Link
+				quid       	"3DFE4993023B"
+				supplier   	"StandardWrapperValve"
+				quidu      	"3DFE49890056"
+				messages   	(list Messages
+				    (object Message "invoke()"
+					quid       	"3DFE4993023C"
+					frequency  	"Aperiodic"
+					synchronization 	"Simple"
+					dir        	"FromClientToSupplier"
+					sequence   	"1.2.1"
+					ordinal    	7
+					quidu      	"000000000000"
+					creation   	FALSE))))
+			persistence 	"Transient"
+			creationObj 	FALSE
+			multi      	FALSE)
+		    (object Object "StandardContextValve"
+			quid       	"3DFE490303A7"
+			collaborators 	(list link_list
+			    (object Link
+				quid       	"3DFE492F033C"
+				supplier   	"StandardContextValve"
+				quidu      	"3DFE490303A7"
+				messages   	(list Messages
+				    (object Message "map //return Wrapper"
+					quid       	"3DFE492F033D"
+					frequency  	"Aperiodic"
+					synchronization 	"Simple"
+					dir        	"FromClientToSupplier"
+					sequence   	"1.1.1.1"
+					ordinal    	3
+					quidu      	"000000000000"
+					creation   	FALSE)))
+			    (object Link
+				quid       	"3DFE494A0150"
+				supplier   	"StandardWrapper"
+				quidu      	"3DFE49370351"
+				messages   	(list Messages
+				    (object Message "invoke()"
+					quid       	"3DFE494A0151"
+					frequency  	"Aperiodic"
+					synchronization 	"Simple"
+					dir        	"FromClientToSupplier"
+					sequence   	"1.1.1.2"
+					ordinal    	4
+					Operation  	"invoke"
+					quidu      	"000000000000"
+					creation   	FALSE))))
+			persistence 	"Transient"
+			creationObj 	FALSE
+			multi      	FALSE)
+		    (object Object "StandardWrapper"
+			quid       	"3DFE49370351"
+			collaborators 	(list link_list
+			    (object Link
+				quid       	"3DFE495F0287"
+				supplier   	"StandardPipeline"
+				quidu      	"3DFE48B80088"
+				messages   	(list Messages
+				    (object Message "invoke()"
+					quid       	"3DFE495F0288"
+					frequency  	"Aperiodic"
+					synchronization 	"Simple"
+					dir        	"FromClientToSupplier"
+					sequence   	"1.1.1.2.1"
+					ordinal    	5
+					quidu      	"000000000000"
+					creation   	FALSE))))
+			persistence 	"Transient"
+			creationObj 	FALSE
+			multi      	FALSE)
+		    (object Object "StandardWrapperValve"
+			quid       	"3DFE49890056"
+			collaborators 	(list link_list
+			    (object Link
+				quid       	"3DFE49DB018A"
+				supplier   	"StandardWrapperValve"
+				quidu      	"3DFE49890056")
+			    (object Link
+				quid       	"3DFE49EC004E"
+				supplier   	"StandardWrapper"
+				quidu      	"3DFE49370351"
+				messages   	(list Messages
+				    (object Message "allocate()"
+					quid       	"3DFE49EC004F"
+					frequency  	"Aperiodic"
+					synchronization 	"Simple"
+					dir        	"FromClientToSupplier"
+					sequence   	"1.2.1.1"
+					ordinal    	8
+					quidu      	"000000000000"
+					creation   	FALSE)
+				    (object Message "return servlet"
+					quid       	"3DFE4A200067"
+					frequency  	"Aperiodic"
+					synchronization 	"Return"
+					dir        	"ToClientFromSupplier"
+					sequence   	"1.2.1.1.1"
+					ordinal    	9
+					quidu      	"000000000000"
+					creation   	FALSE)))
+			    (object Link
+				quid       	"3DFE4A29027D"
+				supplier   	"ApplicationFilterChain"
+				quidu      	"3DFE4A1500B2"
+				messages   	(list Messages
+				    (object Message "createFilterChain()"
+					quid       	"3DFE4A29027E"
+					frequency  	"Aperiodic"
+					synchronization 	"Simple"
+					dir        	"FromClientToSupplier"
+					sequence   	"1.2.1.1.1.1"
+					ordinal    	10
+					quidu      	"000000000000"
+					creation   	FALSE)
+				    (object Message "doFilter()"
+					quid       	"3DFE4A490283"
+					frequency  	"Aperiodic"
+					synchronization 	"Simple"
+					dir        	"FromClientToSupplier"
+					sequence   	"1.2.1.2"
+					ordinal    	11
+					Operation  	"doFilter"
+					quidu      	"000000000000"
+					creation   	FALSE)
+				    (object Message "return"
+					quid       	"3DFE4CB4025B"
+					frequency  	"Aperiodic"
+					synchronization 	"Return"
+					dir        	"ToClientFromSupplier"
+					sequence   	"1.2.1.2.3"
+					ordinal    	14
+					quidu      	"000000000000"
+					creation   	FALSE))))
+			persistence 	"Transient"
+			creationObj 	FALSE
+			multi      	FALSE)
+		    (object Object "ApplicationFilterChain"
+			quid       	"3DFE4A1500B2"
+			collaborators 	(list link_list
+			    (object Link
+				quid       	"3DFE4C2701C2"
+				supplier   	"ApplicationFilterChain"
+				quidu      	"3DFE4A1500B2"
+				messages   	(list Messages
+				    (object Message "internalDoFilter()"
+					quid       	"3DFE4C2701C3"
+					frequency  	"Aperiodic"
+					synchronization 	"Simple"
+					dir        	"FromClientToSupplier"
+					sequence   	"1.2.1.2.1"
+					ordinal    	12
+					quidu      	"000000000000"
+					creation   	FALSE)))
+			    (object Link
+				quid       	"3DFE4CA502BE"
+				supplier   	"$UNNAMED$0"
+				quidu      	"3DFE4BAE0056"
+				messages   	(list Messages
+				    (object Message "service()"
+					quid       	"3DFE4CA502BF"
+					frequency  	"Aperiodic"
+					synchronization 	"Simple"
+					dir        	"FromClientToSupplier"
+					sequence   	"1.2.1.2.2"
+					ordinal    	13
+					quidu      	"000000000000"
+					creation   	FALSE))))
+			persistence 	"Transient"
+			creationObj 	FALSE
+			multi      	FALSE)
+		    (object Object "$UNNAMED$0"
+			quid       	"3DFE4BAE0056"
+			stereotype 	"Servlet"
+			persistence 	"Transient"
+			creationObj 	TRUE
+			multi      	FALSE))))
+	logical_presentations 	(list unit_reference_list
+	    (object ClassDiagram "Main"
+		quid       	"3DFDF6D2021B"
+		title      	"Main"
+		zoom       	100
+		max_height 	28350
+		max_width  	21600
+		origin_x   	0
+		origin_y   	0
+		items      	(list diagram_item_list))
+	    (object ClassDiagram "high level packaging"
+		quid       	"3E42DE75004B"
+		title      	"high level packaging"
+		zoom       	100
+		max_height 	28350
+		max_width  	21600
+		origin_x   	0
+		origin_y   	0
+		items      	(list diagram_item_list
+		    (object CategoryView "Logical View::org.apache.catalina" @91
+			location   	(1024, 752)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	FALSE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object ItemLabel
+			    Parent_View 	@91
+			    location   	(780, 668)
+			    fill_color 	13434879
+			    nlines     	2
+			    max_width  	488
+			    justify    	0
+			    label      	"org.apache.catalina")
+			icon_style 	"Icon"
+			line_color 	3342489
+			fill_color 	13434879
+			quidu      	"3E42DE8D0082"
+			width      	500
+			height     	181)
+		    (object CategoryView "Logical View::org.apache.coyote" @92
+			location   	(512, 1184)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	FALSE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object ItemLabel
+			    Parent_View 	@92
+			    location   	(237, 1090)
+			    fill_color 	13434879
+			    nlines     	2
+			    max_width  	550
+			    justify    	0
+			    label      	"org.apache.coyote")
+			icon_style 	"Icon"
+			line_color 	3342489
+			fill_color 	13434879
+			quidu      	"3E42DE9F0132"
+			width      	563
+			height     	200)
+		    (object CategoryView "Logical View::org.apache.tomcat.util" @93
+			location   	(1920, 1104)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	FALSE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object ItemLabel
+			    Parent_View 	@93
+			    location   	(1670, 1020)
+			    fill_color 	13434879
+			    nlines     	2
+			    max_width  	500
+			    justify    	0
+			    label      	"org.apache.tomcat.util")
+			icon_style 	"Icon"
+			line_color 	3342489
+			fill_color 	13434879
+			quidu      	"3E42DEDF01F2"
+			width      	512
+			height     	181)
+		    (object ImportView "" @94
+			stereotype 	TRUE
+			line_color 	3342489
+			quidu      	"3E42DEF601EB"
+			client     	@91
+			supplier   	@93
+			line_style 	0)
+		    (object ImportView "" @95
+			stereotype 	TRUE
+			line_color 	3342489
+			quidu      	"3E42DEFC00B3"
+			client     	@92
+			supplier   	@93
+			line_style 	0)
+		    (object CategoryView "Logical View::org.apache.jasper" @96
+			location   	(1728, 624)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	FALSE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object ItemLabel
+			    Parent_View 	@96
+			    location   	(1437, 540)
+			    fill_color 	13434879
+			    nlines     	2
+			    max_width  	582
+			    justify    	0
+			    label      	"org.apache.jasper")
+			icon_style 	"Icon"
+			line_color 	3342489
+			fill_color 	13434879
+			quidu      	"3E42DEFF0270"
+			width      	594
+			height     	181)
+		    (object ImportView "" @97
+			stereotype 	TRUE
+			line_color 	3342489
+			quidu      	"3E42DF700060"
+			client     	@91
+			supplier   	@92
+			line_style 	0)
+		    (object NoteView @98
+			location   	(1200, 208)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	FALSE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object ItemLabel
+			    Parent_View 	@98
+			    location   	(847, 143)
+			    fill_color 	13434879
+			    nlines     	2
+			    max_width  	671
+			    label      	"High Level package dependencies")
+			line_color 	3342489
+			fill_color 	13434879
+			width      	731
+			height     	143)
+		    (object CategoryView "Logical View::org.apache.naming" @99
+			location   	(352, 304)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	FALSE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object ItemLabel
+			    Parent_View 	@99
+			    location   	(83, 220)
+			    fill_color 	13434879
+			    nlines     	2
+			    max_width  	538
+			    justify    	0
+			    label      	"org.apache.naming")
+			icon_style 	"Icon"
+			line_color 	3342489
+			fill_color 	13434879
+			quidu      	"3E43D1580339"
+			width      	550
+			height     	181)
+		    (object ImportView "" @100
+			stereotype 	TRUE
+			line_color 	3342489
+			quidu      	"3E43D165039C"
+			client     	@91
+			supplier   	@99
+			line_style 	0)))
+	    (object InteractionDiagram "1. catalina_load"
+		mechanism_ref 	@82
+		quid       	"3DFDF8EE0267"
+		title      	"1. catalina_load"
+		zoom       	100
+		max_height 	28350
+		max_width  	21600
+		origin_x   	0
+		origin_y   	519
+		items      	(list diagram_item_list
+		    (object InterObjView "Bootstrap" @101
+			location   	(224, 224)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	TRUE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object ItemLabel
+			    Parent_View 	@101
+			    location   	(224, 224)
+			    fill_color 	13434879
+			    anchor_loc 	1
+			    nlines     	2
+			    max_width  	282
+			    justify    	0
+			    label      	"Bootstrap")
+			icon_style 	"Icon"
+			line_color 	3342489
+			fill_color 	13434879
+			quidu      	"3DFDF8FD0345"
+			width      	300
+			height     	1972
+			icon_height 	0
+			icon_width 	0
+			icon_y_offset 	0
+			annotation 	1
+			Focus_Of_Control 	(object Focus_Of_Control "" @102
+			    location   	(224, 368)
+			    line_color 	3342489
+			    InterObjView 	@101
+			    height     	1738
+			    y_coord    	1678
+			    Nested     	FALSE)
+			Focus_Of_Control 	(object Focus_Of_Control "" @103
+			    location   	(224, 368)
+			    line_color 	3342489
+			    InterObjView 	@101
+			    height     	60
+			    y_coord    	0
+			    Nested     	TRUE))
+		    (object InterObjView "Digester" @104
+			location   	(896, 224)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	TRUE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object ItemLabel
+			    Parent_View 	@104
+			    location   	(896, 224)
+			    fill_color 	13434879
+			    anchor_loc 	1
+			    nlines     	2
+			    max_width  	282
+			    justify    	0
+			    label      	"Digester")
+			icon_style 	"Icon"
+			line_color 	3342489
+			fill_color 	13434879
+			quidu      	"3DFDFAF201A1"
+			width      	300
+			height     	1972
+			icon_height 	0
+			icon_width 	0
+			icon_y_offset 	0
+			annotation 	1
+			Focus_Of_Control 	(object Focus_Of_Control "" @105
+			    location   	(896, 1232)
+			    line_color 	3342489
+			    InterObjView 	@104
+			    height     	60
+			    y_coord    	0
+			    Nested     	FALSE)
+			Focus_Of_Control 	(object Focus_Of_Control "" @106
+			    location   	(896, 1312)
+			    line_color 	3342489
+			    InterObjView 	@104
+			    height     	264
+			    y_coord    	204
+			    Nested     	FALSE))
+		    (object InterObjView "ServerLifecycleListener" @107
+			location   	(1232, 224)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	TRUE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object ItemLabel
+			    Parent_View 	@107
+			    location   	(1232, 224)
+			    fill_color 	13434879
+			    anchor_loc 	1
+			    nlines     	2
+			    max_width  	282
+			    justify    	0
+			    label      	"ServerLifecycleListener")
+			icon_style 	"Icon"
+			line_color 	3342489
+			fill_color 	13434879
+			quidu      	"3DFDFB4B0217"
+			width      	300
+			height     	1972
+			icon_height 	0
+			icon_width 	0
+			icon_y_offset 	0
+			annotation 	1
+			Focus_Of_Control 	(object Focus_Of_Control "" @108
+			    location   	(1232, 1328)
+			    line_color 	3342489
+			    InterObjView 	@107
+			    height     	60
+			    y_coord    	0
+			    Nested     	FALSE))
+		    (object InterObjView "GlobalResourcesLifecycleListener" @109
+			location   	(1568, 224)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	TRUE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object ItemLabel
+			    Parent_View 	@109
+			    location   	(1568, 224)
+			    fill_color 	13434879
+			    anchor_loc 	1
+			    nlines     	2
+			    max_width  	322
+			    justify    	0
+			    label      	"GlobalResourcesLifecycleListener")
+			icon_style 	"Icon"
+			line_color 	3342489
+			fill_color 	13434879
+			quidu      	"3DFDFB7A02AB"
+			width      	340
+			height     	1972
+			icon_height 	0
+			icon_width 	0
+			icon_y_offset 	0
+			annotation 	1
+			Focus_Of_Control 	(object Focus_Of_Control "" @110
+			    location   	(1568, 1456)
+			    line_color 	3342489
+			    InterObjView 	@109
+			    height     	60
+			    y_coord    	0
+			    Nested     	FALSE))
+		    (object InterObjView "SecurityConfig" @111
+			location   	(1920, 224)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	TRUE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object ItemLabel
+			    Parent_View 	@111
+			    location   	(1920, 224)
+			    fill_color 	13434879
+			    anchor_loc 	1
+			    nlines     	2
+			    max_width  	282
+			    justify    	0
+			    label      	"SecurityConfig")
+			icon_style 	"Icon"
+			line_color 	3342489
+			fill_color 	13434879
+			quidu      	"3DFDFBD802BA"
+			width      	300
+			height     	1972
+			icon_height 	0
+			icon_width 	0
+			icon_y_offset 	0
+			annotation 	1
+			Focus_Of_Control 	(object Focus_Of_Control "" @112
+			    location   	(1920, 1600)
+			    line_color 	3342489
+			    InterObjView 	@111
+			    height     	60
+			    y_coord    	0
+			    Nested     	FALSE)
+			Focus_Of_Control 	(object Focus_Of_Control "" @113
+			    location   	(1920, 1680)
+			    line_color 	3342489
+			    InterObjView 	@111
+			    height     	146
+			    y_coord    	86
+			    Nested     	FALSE)
+			Focus_Of_Control 	(object Focus_Of_Control "" @114
+			    location   	(1920, 1760)
+			    line_color 	3342489
+			    InterObjView 	@111
+			    height     	60
+			    y_coord    	0
+			    Nested     	TRUE))
+		    (object SelfMessView "" @115
+			location   	(16, 368)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	FALSE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object SegLabel @116
+			    Parent_View 	@115
+			    location   	(315, 324)
+			    font       	(object Font
+				size       	10
+				face       	"Arial"
+				bold       	FALSE
+				italics    	FALSE
+				underline  	FALSE
+				strike     	FALSE
+				color      	0
+				default_color 	TRUE)
+			    quidu      	"3DFDF9210009"
+			    anchor_loc 	1
+			    nlines     	1
+			    max_width  	340
+			    justify    	0
+			    label      	"initClassLoaders()"
+			    pctDist    	0.500000
+			    height     	45
+			    orientation 	0)
+			line_color 	3342489
+			client     	@101
+			supplier   	@101
+			Focus_Src  	@102
+			Focus_Entry 	@103
+			origin     	(240, 368)
+			terminus   	(390, 368)
+			ordinal    	0)
+		    (object NoteView @117
+			location   	(1152, 1072)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	FALSE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object ItemLabel
+			    Parent_View 	@117
+			    location   	(1014, 1012)
+			    fill_color 	13434879
+			    nlines     	2
+			    max_width  	240
+			    label      	"parse server.xml")
+			line_color 	3342489
+			fill_color 	13434879
+			width      	300
+			height     	132)
+		    (object NoteView @118
+			location   	(1376, 80)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	FALSE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object ItemLabel
+			    Parent_View 	@118
+			    location   	(1238, 20)
+			    fill_color 	13434879
+			    nlines     	2
+			    max_width  	240
+			    label      	"MBeans")
+			line_color 	3342489
+			fill_color 	13434879
+			width      	300
+			height     	132)
+		    (object AttachView "" @119
+			stereotype 	TRUE
+			line_color 	3342489
+			client     	@118
+			supplier   	@107
+			line_style 	0)
+		    (object AttachView "" @120
+			stereotype 	TRUE
+			line_color 	3342489
+			client     	@109
+			supplier   	@118
+			line_style 	0)
+		    (object NoteView @121
+			location   	(2160, 2176)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	FALSE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object ItemLabel
+			    Parent_View 	@121
+			    location   	(1947, 2113)
+			    fill_color 	13434879
+			    nlines     	2
+			    max_width  	390
+			    label      	"#1Catalina.load()")
+			line_color 	3342489
+			fill_color 	13434879
+			width      	450
+			height     	138)
+		    (object InterObjView "Catalina" @122
+			location   	(560, 224)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	TRUE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object ItemLabel
+			    Parent_View 	@122
+			    location   	(560, 224)
+			    fill_color 	13434879
+			    anchor_loc 	1
+			    nlines     	2
+			    max_width  	282
+			    justify    	0
+			    label      	"Catalina")
+			icon_style 	"Icon"
+			line_color 	3342489
+			fill_color 	13434879
+			quidu      	"3DFDF90A0330"
+			width      	300
+			height     	1972
+			icon_height 	0
+			icon_width 	0
+			icon_y_offset 	0
+			annotation 	1
+			Focus_Of_Control 	(object Focus_Of_Control "" @123
+			    location   	(560, 464)
+			    line_color 	3342489
+			    InterObjView 	@122
+			    height     	60
+			    y_coord    	0
+			    Nested     	FALSE)
+			Focus_Of_Control 	(object Focus_Of_Control "" @124
+			    location   	(560, 608)
+			    line_color 	3342489
+			    InterObjView 	@122
+			    height     	60
+			    y_coord    	0
+			    Nested     	FALSE)
+			Focus_Of_Control 	(object Focus_Of_Control "" @125
+			    location   	(560, 720)
+			    line_color 	3342489
+			    InterObjView 	@122
+			    height     	1326
+			    y_coord    	1266
+			    Nested     	FALSE)
+			Focus_Of_Control 	(object Focus_Of_Control "" @126
+			    location   	(560, 896)
+			    line_color 	3342489
+			    InterObjView 	@122
+			    height     	194
+			    y_coord    	134
+			    Nested     	TRUE)
+			Focus_Of_Control 	(object Focus_Of_Control "" @127
+			    location   	(560, 896)
+			    InterObjView 	@122
+			    height     	60
+			    y_coord    	0
+			    Nested     	TRUE)
+			Focus_Of_Control 	(object Focus_Of_Control "" @128
+			    location   	(560, 1024)
+			    line_color 	3342489
+			    InterObjView 	@122
+			    height     	60
+			    y_coord    	0
+			    Nested     	TRUE)
+			Focus_Of_Control 	(object Focus_Of_Control "" @129
+			    location   	(560, 1024)
+			    InterObjView 	@122
+			    height     	60
+			    y_coord    	0
+			    Nested     	TRUE)
+			Focus_Of_Control 	(object Focus_Of_Control "" @130
+			    location   	(560, 1152)
+			    line_color 	3342489
+			    InterObjView 	@122
+			    height     	60
+			    y_coord    	0
+			    Nested     	TRUE)
+			Focus_Of_Control 	(object Focus_Of_Control "" @131
+			    location   	(560, 1152)
+			    InterObjView 	@122
+			    height     	60
+			    y_coord    	0
+			    Nested     	TRUE))
+		    (object SelfMessView "" @132
+			location   	(16, 896)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	FALSE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object SegLabel @133
+			    Parent_View 	@132
+			    location   	(651, 852)
+			    font       	(object Font
+				size       	10
+				face       	"Arial"
+				bold       	FALSE
+				italics    	FALSE
+				underline  	FALSE
+				strike     	FALSE
+				color      	0
+				default_color 	TRUE)
+			    quidu      	"3DFDFA8001DA"
+			    anchor_loc 	1
+			    nlines     	1
+			    max_width  	160
+			    justify    	0
+			    label      	"initDirs()"
+			    pctDist    	0.500000
+			    height     	45
+			    orientation 	0)
+			line_color 	3342489
+			client     	@122
+			supplier   	@122
+			Focus_Src  	@127
+			Focus_Entry 	@126
+			origin     	(576, 896)
+			terminus   	(726, 896)
+			ordinal    	4)
+		    (object SelfMessView "" @134
+			location   	(16, 1024)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	FALSE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object SegLabel @135
+			    Parent_View 	@134
+			    location   	(701, 981)
+			    font       	(object Font
+				size       	10
+				face       	"Arial"
+				bold       	FALSE
+				italics    	FALSE
+				underline  	FALSE
+				strike     	FALSE
+				color      	0
+				default_color 	TRUE)
+			    quidu      	"3DFDFA8B0347"
+			    anchor_loc 	1
+			    nlines     	1
+			    max_width  	228
+			    justify    	0
+			    label      	"initNaming()"
+			    pctDist    	0.840000
+			    height     	44
+			    orientation 	0)
+			line_color 	3342489
+			client     	@122
+			supplier   	@122
+			Focus_Src  	@129
+			Focus_Entry 	@128
+			origin     	(576, 1024)
+			terminus   	(726, 1024)
+			ordinal    	5)
+		    (object SelfMessView "" @136
+			location   	(16, 1152)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	FALSE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object SegLabel @137
+			    Parent_View 	@136
+			    location   	(686, 1109)
+			    font       	(object Font
+				size       	10
+				face       	"Arial"
+				bold       	FALSE
+				italics    	FALSE
+				underline  	FALSE
+				strike     	FALSE
+				color      	0
+				default_color 	TRUE)
+			    quidu      	"3DFDFAAD01AC"
+			    anchor_loc 	1
+			    nlines     	1
+			    max_width  	180
+			    justify    	0
+			    label      	"initialize()"
+			    pctDist    	0.733333
+			    height     	44
+			    orientation 	0)
+			line_color 	3342489
+			client     	@122
+			supplier   	@122
+			Focus_Src  	@131
+			Focus_Entry 	@130
+			origin     	(576, 1152)
+			terminus   	(726, 1152)
+			ordinal    	6)
+		    (object InterMessView "" @138
+			location   	(16, 464)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	FALSE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object SegLabel @139
+			    Parent_View 	@138
+			    location   	(389, 437)
+			    font       	(object Font
+				size       	10
+				face       	"Arial"
+				bold       	FALSE
+				italics    	FALSE
+				underline  	FALSE
+				strike     	FALSE
+				color      	0
+				default_color 	TRUE)
+			    quidu      	"3DFDF91A010D"
+			    anchor_loc 	1
+			    nlines     	1
+			    max_width  	265
+			    justify    	0
+			    label      	"newInstance()"
+			    pctDist    	0.495082
+			    height     	28
+			    orientation 	0)
+			line_color 	3342489
+			client     	@101
+			supplier   	@122
+			Focus_Src  	@102
+			Focus_Entry 	@123
+			origin     	(239, 464)
+			terminus   	(544, 464)
+			ordinal    	1)
+		    (object InterMessView "" @140
+			location   	(16, 608)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	FALSE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object SegLabel @141
+			    Parent_View 	@140
+			    location   	(456, 565)
+			    font       	(object Font
+				size       	10
+				face       	"Arial"
+				bold       	FALSE
+				italics    	FALSE
+				underline  	FALSE
+				strike     	FALSE
+				color      	0
+				default_color 	TRUE)
+			    quidu      	"3DFDF97900C2"
+			    anchor_loc 	1
+			    nlines     	1
+			    max_width  	445
+			    justify    	0
+			    label      	"setParentClassLoader()"
+			    pctDist    	0.711475
+			    height     	44
+			    orientation 	0)
+			line_color 	3342489
+			client     	@101
+			supplier   	@122
+			Focus_Src  	@102
+			Focus_Entry 	@124
+			origin     	(239, 608)
+			terminus   	(544, 608)
+			ordinal    	2)
+		    (object InterMessView "" @142
+			location   	(16, 720)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	FALSE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object SegLabel @143
+			    Parent_View 	@142
+			    location   	(391, 676)
+			    font       	(object Font
+				size       	10
+				face       	"Arial"
+				bold       	FALSE
+				italics    	FALSE
+				underline  	FALSE
+				strike     	FALSE
+				color      	0
+				default_color 	TRUE)
+			    quidu      	"3DFDFA3402F2"
+			    anchor_loc 	1
+			    nlines     	1
+			    max_width  	108
+			    justify    	0
+			    label      	"load()"
+			    pctDist    	0.500000
+			    height     	45
+			    orientation 	0)
+			line_color 	3342489
+			client     	@101
+			supplier   	@122
+			Focus_Src  	@102
+			Focus_Entry 	@125
+			origin     	(239, 720)
+			terminus   	(544, 720)
+			ordinal    	3)
+		    (object InterMessView "" @144
+			location   	(16, 1232)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	FALSE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object SegLabel @145
+			    Parent_View 	@144
+			    location   	(727, 1188)
+			    font       	(object Font
+				size       	10
+				face       	"Arial"
+				bold       	FALSE
+				italics    	FALSE
+				underline  	FALSE
+				strike     	FALSE
+				color      	0
+				default_color 	TRUE)
+			    quidu      	"3DFDFAF800C4"
+			    anchor_loc 	1
+			    nlines     	1
+			    max_width  	302
+			    justify    	0
+			    label      	"createDigester()"
+			    pctDist    	0.500000
+			    height     	45
+			    orientation 	0)
+			line_color 	3342489
+			client     	@122
+			supplier   	@104
+			Focus_Src  	@125
+			Focus_Entry 	@105
+			origin     	(575, 1232)
+			terminus   	(880, 1232)
+			ordinal    	7)
+		    (object InterMessView "" @146
+			location   	(16, 1312)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	FALSE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object SegLabel @147
+			    Parent_View 	@146
+			    location   	(727, 1268)
+			    font       	(object Font
+				size       	10
+				face       	"Arial"
+				bold       	FALSE
+				italics    	FALSE
+				underline  	FALSE
+				strike     	FALSE
+				color      	0
+				default_color 	TRUE)
+			    quidu      	"3DFDFB0100B2"
+			    anchor_loc 	1
+			    nlines     	1
+			    max_width  	136
+			    justify    	0
+			    label      	"parse()"
+			    pctDist    	0.500000
+			    height     	45
+			    orientation 	0)
+			line_color 	3342489
+			client     	@122
+			supplier   	@104
+			Focus_Src  	@125
+			Focus_Entry 	@106
+			origin     	(575, 1312)
+			terminus   	(880, 1312)
+			ordinal    	8)
+		    (object AttachView "" @148
+			stereotype 	TRUE
+			line_color 	3342489
+			client     	@147
+			supplier   	@117
+			line_style 	0)
+		    (object InterMessView "" @149
+			location   	(16, 1328)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	FALSE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object SegLabel @150
+			    Parent_View 	@149
+			    location   	(1063, 1284)
+			    font       	(object Font
+				size       	10
+				face       	"Arial"
+				bold       	FALSE
+				italics    	FALSE
+				underline  	FALSE
+				strike     	FALSE
+				color      	0
+				default_color 	TRUE)
+			    quidu      	"3DFDFB8400A7"
+			    anchor_loc 	1
+			    nlines     	1
+			    max_width  	265
+			    justify    	0
+			    label      	"newInstance()"
+			    pctDist    	0.500000
+			    height     	45
+			    orientation 	0)
+			line_color 	3342489
+			client     	@104
+			supplier   	@107
+			Focus_Src  	@106
+			Focus_Entry 	@108
+			origin     	(911, 1328)
+			terminus   	(1216, 1328)
+			ordinal    	9)
+		    (object InterMessView "" @151
+			location   	(16, 1456)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	FALSE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object SegLabel @152
+			    Parent_View 	@151
+			    location   	(1231, 1412)
+			    font       	(object Font
+				size       	10
+				face       	"Arial"
+				bold       	FALSE
+				italics    	FALSE
+				underline  	FALSE
+				strike     	FALSE
+				color      	0
+				default_color 	TRUE)
+			    quidu      	"3DFDFB920148"
+			    anchor_loc 	1
+			    nlines     	1
+			    max_width  	265
+			    justify    	0
+			    label      	"newInstance()"
+			    pctDist    	0.500000
+			    height     	45
+			    orientation 	0)
+			line_color 	3342489
+			client     	@104
+			supplier   	@109
+			Focus_Src  	@106
+			Focus_Entry 	@110
+			origin     	(911, 1456)
+			terminus   	(1552, 1456)
+			ordinal    	10)
+		    (object InterMessView "" @153
+			location   	(16, 1600)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	FALSE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object SegLabel @154
+			    Parent_View 	@153
+			    location   	(1239, 1556)
+			    font       	(object Font
+				size       	10
+				face       	"Arial"
+				bold       	FALSE
+				italics    	FALSE
+				underline  	FALSE
+				strike     	FALSE
+				color      	0
+				default_color 	TRUE)
+			    quidu      	"3DFDFBEA00C2"
+			    anchor_loc 	1
+			    nlines     	1
+			    max_width  	265
+			    justify    	0
+			    label      	"newInstance()"
+			    pctDist    	0.500000
+			    height     	45
+			    orientation 	0)
+			line_color 	3342489
+			client     	@122
+			supplier   	@111
+			Focus_Src  	@125
+			Focus_Entry 	@112
+			origin     	(575, 1600)
+			terminus   	(1904, 1600)
+			ordinal    	11)
+		    (object InterMessView "" @155
+			location   	(16, 1680)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	FALSE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object SegLabel @156
+			    Parent_View 	@155
+			    location   	(1239, 1636)
+			    font       	(object Font
+				size       	10
+				face       	"Arial"
+				bold       	FALSE
+				italics    	FALSE
+				underline  	FALSE
+				strike     	FALSE
+				color      	0
+				default_color 	TRUE)
+			    quidu      	"3DFDFBF401F2"
+			    anchor_loc 	1
+			    nlines     	1
+			    max_width  	425
+			    justify    	0
+			    label      	"setPackageDefinition()"
+			    pctDist    	0.500000
+			    height     	45
+			    orientation 	0)
+			line_color 	3342489
+			client     	@122
+			supplier   	@111
+			Focus_Src  	@125
+			Focus_Entry 	@113
+			origin     	(575, 1680)
+			terminus   	(1904, 1680)
+			ordinal    	12)
+		    (object InterMessView "" @157
+			location   	(16, 1760)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	FALSE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object SegLabel @158
+			    Parent_View 	@157
+			    location   	(1239, 1716)
+			    font       	(object Font
+				size       	10
+				face       	"Arial"
+				bold       	FALSE
+				italics    	FALSE
+				underline  	FALSE
+				strike     	FALSE
+				color      	0
+				default_color 	TRUE)
+			    quidu      	"3DFDFC1203C2"
+			    anchor_loc 	1
+			    nlines     	1
+			    max_width  	386
+			    justify    	0
+			    label      	"setPackageAccess()"
+			    pctDist    	0.500000
+			    height     	45
+			    orientation 	0)
+			line_color 	3342489
+			client     	@122
+			supplier   	@111
+			Focus_Src  	@125
+			Focus_Entry 	@114
+			origin     	(575, 1760)
+			terminus   	(1904, 1760)
+			ordinal    	13)))
+	    (object InteractionDiagram "2. catalina_initliaze"
+		mechanism_ref 	@83
+		quid       	"3DFDFC44002A"
+		title      	"2. catalina_initliaze"
+		zoom       	100
+		max_height 	28350
+		max_width  	21600
+		origin_x   	0
+		origin_y   	87
+		items      	(list diagram_item_list
+		    (object InterObjView "Catalina" @159
+			location   	(176, 224)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	TRUE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object ItemLabel
+			    Parent_View 	@159
+			    location   	(176, 224)
+			    fill_color 	13434879
+			    anchor_loc 	1
+			    nlines     	2
+			    max_width  	282
+			    justify    	0
+			    label      	"Catalina")
+			icon_style 	"Icon"
+			line_color 	3342489
+			fill_color 	13434879
+			quidu      	"3DFDFC8F015F"
+			width      	300
+			height     	1180
+			icon_height 	0
+			icon_width 	0
+			icon_y_offset 	0
+			annotation 	1
+			Focus_Of_Control 	(object Focus_Of_Control "" @160
+			    location   	(176, 400)
+			    line_color 	3342489
+			    InterObjView 	@159
+			    height     	914
+			    y_coord    	854
+			    Nested     	FALSE))
+		    (object InterObjView "StandardServer" @161
+			location   	(496, 224)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	TRUE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object ItemLabel
+			    Parent_View 	@161
+			    location   	(496, 224)
+			    fill_color 	13434879
+			    anchor_loc 	1
+			    nlines     	2
+			    max_width  	282
+			    justify    	0
+			    label      	"StandardServer")
+			icon_style 	"Icon"
+			line_color 	3342489
+			fill_color 	13434879
+			quidu      	"3DFDFCCB006B"
+			width      	300
+			height     	1180
+			icon_height 	0
+			icon_width 	0
+			icon_y_offset 	0
+			annotation 	1
+			Focus_Of_Control 	(object Focus_Of_Control "" @162
+			    location   	(496, 400)
+			    line_color 	3342489
+			    InterObjView 	@161
+			    height     	854
+			    y_coord    	794
+			    Nested     	FALSE)
+			Focus_Of_Control 	(object Focus_Of_Control "" @163
+			    location   	(496, 480)
+			    line_color 	3342489
+			    InterObjView 	@161
+			    height     	768
+			    y_coord    	708
+			    Nested     	TRUE))
+		    (object InterObjView "StandardService" @164
+			location   	(832, 224)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	TRUE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object ItemLabel
+			    Parent_View 	@164
+			    location   	(832, 224)
+			    fill_color 	13434879
+			    anchor_loc 	1
+			    nlines     	2
+			    max_width  	282
+			    justify    	0
+			    label      	"StandardService")
+			icon_style 	"Icon"
+			line_color 	3342489
+			fill_color 	13434879
+			quidu      	"3DFDFD370020"
+			width      	300
+			height     	1180
+			icon_height 	0
+			icon_width 	0
+			icon_y_offset 	0
+			annotation 	1
+			Focus_Of_Control 	(object Focus_Of_Control "" @165
+			    location   	(832, 480)
+			    line_color 	3342489
+			    InterObjView 	@164
+			    height     	708
+			    y_coord    	648
+			    Nested     	FALSE))
+		    (object InterObjView "CoyoteConnector" @166
+			location   	(1168, 224)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	TRUE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object ItemLabel
+			    Parent_View 	@166
+			    location   	(1168, 224)
+			    fill_color 	13434879
+			    anchor_loc 	1
+			    nlines     	2
+			    max_width  	282
+			    justify    	0
+			    label      	"CoyoteConnector")
+			icon_style 	"Icon"
+			line_color 	3342489
+			fill_color 	13434879
+			quidu      	"3DFDFE810313"
+			width      	300
+			height     	1180
+			icon_height 	0
+			icon_width 	0
+			icon_y_offset 	0
+			annotation 	1
+			Focus_Of_Control 	(object Focus_Of_Control "" @167
+			    location   	(1168, 528)
+			    line_color 	3342489
+			    InterObjView 	@166
+			    height     	600
+			    y_coord    	540
+			    Nested     	FALSE))
+		    (object InterObjView "CoyoteAdapter" @168
+			location   	(1504, 224)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	TRUE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object ItemLabel
+			    Parent_View 	@168
+			    location   	(1504, 224)
+			    fill_color 	13434879
+			    anchor_loc 	1
+			    nlines     	2
+			    max_width  	282
+			    justify    	0
+			    label      	"CoyoteAdapter")
+			icon_style 	"Icon"
+			line_color 	3342489
+			fill_color 	13434879
+			quidu      	"3DFDFFA00226"
+			width      	300
+			height     	1180
+			icon_height 	0
+			icon_width 	0
+			icon_y_offset 	0
+			annotation 	1
+			Focus_Of_Control 	(object Focus_Of_Control "" @169
+			    location   	(1504, 576)
+			    line_color 	3342489
+			    InterObjView 	@168
+			    height     	60
+			    y_coord    	0
+			    Nested     	FALSE))
+		    (object InterObjView "Http11Protocol" @170
+			location   	(1808, 224)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	TRUE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object ItemLabel
+			    Parent_View 	@170
+			    location   	(1808, 224)
+			    fill_color 	13434879
+			    anchor_loc 	1
+			    nlines     	2
+			    max_width  	282
+			    justify    	0
+			    label      	"Http11Protocol")
+			icon_style 	"Icon"
+			line_color 	3342489
+			fill_color 	13434879
+			quidu      	"3DFE016601A6"
+			width      	300
+			height     	1180
+			icon_height 	0
+			icon_width 	0
+			icon_y_offset 	0
+			annotation 	1
+			Focus_Of_Control 	(object Focus_Of_Control "" @171
+			    location   	(1808, 704)
+			    line_color 	3342489
+			    InterObjView 	@170
+			    height     	60
+			    y_coord    	0
+			    Nested     	FALSE)
+			Focus_Of_Control 	(object Focus_Of_Control "" @172
+			    location   	(1808, 832)
+			    line_color 	3342489
+			    InterObjView 	@170
+			    height     	60
+			    y_coord    	0
+			    Nested     	FALSE))
+		    (object InterObjView "JkCoyoteAdapter" @173
+			location   	(2144, 224)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	TRUE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object ItemLabel
+			    Parent_View 	@173
+			    location   	(2144, 224)
+			    fill_color 	13434879
+			    anchor_loc 	1
+			    nlines     	2
+			    max_width  	282
+			    justify    	0
+			    label      	"JkCoyoteAdapter")
+			icon_style 	"Icon"
+			line_color 	3342489
+			fill_color 	13434879
+			quidu      	"3DFE01AD01A8"
+			width      	300
+			height     	1180
+			icon_height 	0
+			icon_width 	0
+			icon_y_offset 	0
+			annotation 	1
+			Focus_Of_Control 	(object Focus_Of_Control "" @174
+			    location   	(2144, 928)
+			    line_color 	3342489
+			    InterObjView 	@173
+			    height     	60
+			    y_coord    	0
+			    Nested     	FALSE)
+			Focus_Of_Control 	(object Focus_Of_Control "" @175
+			    location   	(2144, 1008)
+			    line_color 	3342489
+			    InterObjView 	@173
+			    height     	60
+			    y_coord    	0
+			    Nested     	FALSE))
+		    (object InterMessView "" @176
+			location   	(16, 400)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	FALSE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object SegLabel @177
+			    Parent_View 	@176
+			    location   	(335, 356)
+			    font       	(object Font
+				size       	10
+				face       	"Arial"
+				bold       	FALSE
+				italics    	FALSE
+				underline  	FALSE
+				strike     	FALSE
+				color      	0
+				default_color 	TRUE)
+			    quidu      	"3DFDFD1F0076"
+			    anchor_loc 	1
+			    nlines     	1
+			    max_width  	180
+			    justify    	0
+			    label      	"initialize()"
+			    pctDist    	0.500000
+			    height     	45
+			    orientation 	0)
+			line_color 	3342489
+			client     	@159
+			supplier   	@161
+			Focus_Src  	@160
+			Focus_Entry 	@162
+			origin     	(191, 400)
+			terminus   	(480, 400)
+			ordinal    	0)
+		    (object InterMessView "" @178
+			location   	(16, 480)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	FALSE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object SegLabel @179
+			    Parent_View 	@178
+			    location   	(663, 436)
+			    font       	(object Font
+				size       	10
+				face       	"Arial"
+				bold       	FALSE
+				italics    	FALSE
+				underline  	FALSE
+				strike     	FALSE
+				color      	0
+				default_color 	TRUE)
+			    quidu      	"3DFDFD3D01C4"
+			    anchor_loc 	1
+			    nlines     	1
+			    max_width  	180
+			    justify    	0
+			    label      	"initialize()"
+			    pctDist    	0.500000
+			    height     	45
+			    orientation 	0)
+			line_color 	3342489
+			client     	@161
+			supplier   	@164
+			Focus_Src  	@163
+			Focus_Entry 	@165
+			origin     	(511, 480)
+			terminus   	(816, 480)
+			ordinal    	1)
+		    (object InterMessView "" @180
+			location   	(16, 528)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	FALSE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object SegLabel @181
+			    Parent_View 	@180
+			    location   	(999, 484)
+			    font       	(object Font
+				size       	10
+				face       	"Arial"
+				bold       	FALSE
+				italics    	FALSE
+				underline  	FALSE
+				strike     	FALSE
+				color      	0
+				default_color 	TRUE)
+			    quidu      	"3DFDFE990305"
+			    anchor_loc 	1
+			    nlines     	1
+			    max_width  	180
+			    justify    	0
+			    label      	"initialize()"
+			    pctDist    	0.500000
+			    height     	45
+			    orientation 	0)
+			line_color 	3342489
+			client     	@164
+			supplier   	@166
+			Focus_Src  	@165
+			Focus_Entry 	@167
+			origin     	(847, 528)
+			terminus   	(1152, 528)
+			ordinal    	2)
+		    (object InterMessView "" @182
+			location   	(16, 576)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	FALSE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object SegLabel @183
+			    Parent_View 	@182
+			    location   	(1335, 532)
+			    font       	(object Font
+				size       	10
+				face       	"Arial"
+				bold       	FALSE
+				italics    	FALSE
+				underline  	FALSE
+				strike     	FALSE
+				color      	0
+				default_color 	TRUE)
+			    quidu      	"3DFE013D0217"
+			    anchor_loc 	1
+			    nlines     	1
+			    max_width  	106
+			    justify    	0
+			    label      	"new()"
+			    pctDist    	0.500000
+			    height     	45
+			    orientation 	0)
+			line_color 	3342489
+			client     	@166
+			supplier   	@168
+			Focus_Src  	@167
+			Focus_Entry 	@169
+			origin     	(1183, 576)
+			terminus   	(1488, 576)
+			ordinal    	3)
+		    (object InterMessView "" @184
+			location   	(1504, 704)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	FALSE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object SegLabel @185
+			    Parent_View 	@184
+			    location   	(1487, 660)
+			    font       	(object Font
+				size       	10
+				face       	"Arial"
+				bold       	FALSE
+				italics    	FALSE
+				underline  	FALSE
+				strike     	FALSE
+				color      	0
+				default_color 	TRUE)
+			    quidu      	"3DFE01830330"
+			    anchor_loc 	1
+			    nlines     	1
+			    max_width  	106
+			    justify    	0
+			    label      	"new()"
+			    pctDist    	0.500000
+			    height     	45
+			    orientation 	0)
+			line_color 	3342489
+			client     	@166
+			supplier   	@170
+			Focus_Src  	@167
+			Focus_Entry 	@171
+			origin     	(1183, 704)
+			terminus   	(1792, 704)
+			ordinal    	4)
+		    (object InterMessView "" @186
+			location   	(1504, 832)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	FALSE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object SegLabel @187
+			    Parent_View 	@186
+			    location   	(1487, 788)
+			    font       	(object Font
+				size       	10
+				face       	"Arial"
+				bold       	FALSE
+				italics    	FALSE
+				underline  	FALSE
+				strike     	FALSE
+				color      	0
+				default_color 	TRUE)
+			    quidu      	"3DFE0188032C"
+			    anchor_loc 	1
+			    nlines     	1
+			    max_width  	80
+			    justify    	0
+			    label      	"init()"
+			    pctDist    	0.500000
+			    height     	45
+			    orientation 	0)
+			line_color 	3342489
+			client     	@166
+			supplier   	@170
+			Focus_Src  	@167
+			Focus_Entry 	@172
+			origin     	(1183, 832)
+			terminus   	(1792, 832)
+			ordinal    	5)
+		    (object InterMessView "" @188
+			location   	(16, 928)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	FALSE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object SegLabel @189
+			    Parent_View 	@188
+			    location   	(1655, 884)
+			    font       	(object Font
+				size       	10
+				face       	"Arial"
+				bold       	FALSE
+				italics    	FALSE
+				underline  	FALSE
+				strike     	FALSE
+				color      	0
+				default_color 	TRUE)
+			    quidu      	"3DFE01BC038C"
+			    anchor_loc 	1
+			    nlines     	1
+			    max_width  	106
+			    justify    	0
+			    label      	"new()"
+			    pctDist    	0.500000
+			    height     	45
+			    orientation 	0)
+			line_color 	3342489
+			client     	@166
+			supplier   	@173
+			Focus_Src  	@167
+			Focus_Entry 	@174
+			origin     	(1183, 928)
+			terminus   	(2128, 928)
+			ordinal    	6)
+		    (object InterMessView "" @190
+			location   	(16, 1008)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	FALSE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object SegLabel @191
+			    Parent_View 	@190
+			    location   	(1655, 964)
+			    font       	(object Font
+				size       	10
+				face       	"Arial"
+				bold       	FALSE
+				italics    	FALSE
+				underline  	FALSE
+				strike     	FALSE
+				color      	0
+				default_color 	TRUE)
+			    quidu      	"3DFE01C30164"
+			    anchor_loc 	1
+			    nlines     	1
+			    max_width  	80
+			    justify    	0
+			    label      	"init()"
+			    pctDist    	0.500000
+			    height     	45
+			    orientation 	0)
+			line_color 	3342489
+			client     	@166
+			supplier   	@173
+			Focus_Src  	@167
+			Focus_Entry 	@175
+			origin     	(1183, 1008)
+			terminus   	(2128, 1008)
+			ordinal    	7)
+		    (object NoteView @192
+			location   	(2144, 2016)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	FALSE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object ItemLabel
+			    Parent_View 	@192
+			    location   	(1947, 1957)
+			    fill_color 	13434879
+			    nlines     	2
+			    max_width  	359
+			    label      	"#2 Catalina.initialize()")
+			line_color 	3342489
+			fill_color 	13434879
+			width      	419
+			height     	131)))
+	    (object InteractionDiagram "3. catalina_start"
+		mechanism_ref 	@84
+		quid       	"3DFE026D02D1"
+		title      	"3. catalina_start"
+		zoom       	100
+		max_height 	28350
+		max_width  	21600
+		origin_x   	0
+		origin_y   	2481
+		items      	(list diagram_item_list
+		    (object InterObjView "Bootstrap" @193
+			location   	(192, 224)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	TRUE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object ItemLabel
+			    Parent_View 	@193
+			    location   	(192, 224)
+			    fill_color 	13434879
+			    anchor_loc 	1
+			    nlines     	2
+			    max_width  	282
+			    justify    	0
+			    label      	"Bootstrap")
+			icon_style 	"Icon"
+			line_color 	3342489
+			fill_color 	13434879
+			quidu      	"3DFE027700F5"
+			width      	300
+			height     	2912
+			icon_height 	0
+			icon_width 	0
+			icon_y_offset 	0
+			annotation 	1
+			Focus_Of_Control 	(object Focus_Of_Control "" @194
+			    location   	(192, 384)
+			    line_color 	3342489
+			    InterObjView 	@193
+			    height     	2662
+			    y_coord    	2602
+			    Nested     	FALSE))
+		    (object InterObjView "Catalina" @195
+			location   	(480, 224)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	TRUE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object ItemLabel
+			    Parent_View 	@195
+			    location   	(480, 224)
+			    fill_color 	13434879
+			    anchor_loc 	1
+			    nlines     	2
+			    max_width  	282
+			    justify    	0
+			    label      	"Catalina")
+			icon_style 	"Icon"
+			line_color 	3342489
+			fill_color 	13434879
+			quidu      	"3DFE027D0067"
+			width      	300
+			height     	2912
+			icon_height 	0
+			icon_width 	0
+			icon_y_offset 	0
+			annotation 	1
+			Focus_Of_Control 	(object Focus_Of_Control "" @196
+			    location   	(480, 384)
+			    line_color 	3342489
+			    InterObjView 	@195
+			    height     	2602
+			    y_coord    	2542
+			    Nested     	FALSE))
+		    (object InterObjView "StandardServer" @197
+			location   	(784, 224)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	TRUE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object ItemLabel
+			    Parent_View 	@197
+			    location   	(784, 224)
+			    fill_color 	13434879
+			    anchor_loc 	1
+			    nlines     	2
+			    max_width  	282
+			    justify    	0
+			    label      	"StandardServer")
+			icon_style 	"Icon"
+			line_color 	3342489
+			fill_color 	13434879
+			quidu      	"3DFE02B30015"
+			width      	300
+			height     	2912
+			icon_height 	0
+			icon_width 	0
+			icon_y_offset 	0
+			annotation 	1
+			Focus_Of_Control 	(object Focus_Of_Control "" @198
+			    location   	(784, 416)
+			    line_color 	3342489
+			    InterObjView 	@197
+			    height     	2510
+			    y_coord    	2450
+			    Nested     	FALSE)
+			Focus_Of_Control 	(object Focus_Of_Control "" @199
+			    location   	(784, 480)
+			    line_color 	3342489
+			    InterObjView 	@197
+			    height     	60
+			    y_coord    	0
+			    Nested     	TRUE)
+			Focus_Of_Control 	(object Focus_Of_Control "" @200
+			    location   	(784, 592)
+			    line_color 	3342489
+			    InterObjView 	@197
+			    height     	60
+			    y_coord    	0
+			    Nested     	TRUE))
+		    (object InterObjView "StandardService" @201
+			location   	(1088, 224)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	TRUE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object ItemLabel
+			    Parent_View 	@201
+			    location   	(1088, 224)
+			    fill_color 	13434879
+			    anchor_loc 	1
+			    nlines     	2
+			    max_width  	282
+			    justify    	0
+			    label      	"StandardService")
+			icon_style 	"Icon"
+			line_color 	3342489
+			fill_color 	13434879
+			quidu      	"3DFE030400E3"
+			width      	300
+			height     	2912
+			icon_height 	0
+			icon_width 	0
+			icon_y_offset 	0
+			annotation 	1
+			Focus_Of_Control 	(object Focus_Of_Control "" @202
+			    location   	(1088, 704)
+			    line_color 	3342489
+			    InterObjView 	@201
+			    height     	2162
+			    y_coord    	2102
+			    Nested     	FALSE)
+			Focus_Of_Control 	(object Focus_Of_Control "" @203
+			    location   	(1088, 752)
+			    line_color 	3342489
+			    InterObjView 	@201
+			    height     	60
+			    y_coord    	0
+			    Nested     	TRUE)
+			Focus_Of_Control 	(object Focus_Of_Control "" @204
+			    location   	(1088, 864)
+			    line_color 	3342489
+			    InterObjView 	@201
+			    height     	60
+			    y_coord    	0
+			    Nested     	TRUE))
+		    (object InterObjView "StandardEngine" @205
+			location   	(1424, 224)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	TRUE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object ItemLabel
+			    Parent_View 	@205
+			    location   	(1424, 224)
+			    fill_color 	13434879
+			    anchor_loc 	1
+			    nlines     	2
+			    max_width  	332
+			    justify    	0
+			    label      	"StandardEngine")
+			icon_style 	"Icon"
+			line_color 	3342489
+			fill_color 	13434879
+			quidu      	"3DFE034700C2"
+			width      	350
+			height     	2912
+			icon_height 	0
+			icon_width 	0
+			icon_y_offset 	0
+			annotation 	1
+			Focus_Of_Control 	(object Focus_Of_Control "" @206
+			    location   	(1424, 976)
+			    line_color 	3342489
+			    InterObjView 	@205
+			    height     	1830
+			    y_coord    	1770
+			    Nested     	FALSE)
+			Focus_Of_Control 	(object Focus_Of_Control "" @207
+			    location   	(1424, 1056)
+			    line_color 	3342489
+			    InterObjView 	@205
+			    height     	1744
+			    y_coord    	1684
+			    Nested     	TRUE)
+			Focus_Of_Control 	(object Focus_Of_Control "" @208
+			    location   	(1424, 1056)
+			    line_color 	3342489
+			    InterObjView 	@205
+			    height     	60
+			    y_coord    	0
+			    Nested     	TRUE)
+			Focus_Of_Control 	(object Focus_Of_Control "" @209
+			    location   	(1424, 1168)
+			    line_color 	3342489
+			    InterObjView 	@205
+			    height     	60
+			    y_coord    	0
+			    Nested     	TRUE)
+			Focus_Of_Control 	(object Focus_Of_Control "" @210
+			    location   	(1424, 1296)
+			    line_color 	3342489
+			    InterObjView 	@205
+			    height     	60
+			    y_coord    	0
+			    Nested     	TRUE)
+			Focus_Of_Control 	(object Focus_Of_Control "" @211
+			    location   	(1424, 1408)
+			    line_color 	3342489
+			    InterObjView 	@205
+			    height     	60
+			    y_coord    	0
+			    Nested     	TRUE)
+			Focus_Of_Control 	(object Focus_Of_Control "" @212
+			    location   	(1424, 1536)
+			    line_color 	3342489
+			    InterObjView 	@205
+			    height     	60
+			    y_coord    	0
+			    Nested     	TRUE)
+			Focus_Of_Control 	(object Focus_Of_Control "" @213
+			    location   	(1424, 1648)
+			    line_color 	3342489
+			    InterObjView 	@205
+			    height     	60
+			    y_coord    	0
+			    Nested     	TRUE))
+		    (object InterObjView "StandardHost" @214
+			location   	(1760, 224)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	TRUE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object ItemLabel
+			    Parent_View 	@214
+			    location   	(1760, 224)
+			    fill_color 	13434879
+			    anchor_loc 	1
+			    nlines     	2
+			    max_width  	282
+			    justify    	0
+			    label      	"StandardHost")
+			icon_style 	"Icon"
+			line_color 	3342489
+			fill_color 	13434879
+			quidu      	"3DFE03F2035D"
+			width      	300
+			height     	2912
+			icon_height 	0
+			icon_width 	0
+			icon_y_offset 	0
+			annotation 	1
+			Focus_Of_Control 	(object Focus_Of_Control "" @215
+			    location   	(1760, 1760)
+			    line_color 	3342489
+			    InterObjView 	@214
+			    height     	980
+			    y_coord    	920
+			    Nested     	FALSE)
+			Focus_Of_Control 	(object Focus_Of_Control "" @216
+			    location   	(1760, 1808)
+			    line_color 	3342489
+			    InterObjView 	@214
+			    height     	60
+			    y_coord    	0
+			    Nested     	TRUE)
+			Focus_Of_Control 	(object Focus_Of_Control "" @217
+			    location   	(1760, 1920)
+			    line_color 	3342489
+			    InterObjView 	@214
+			    height     	60
+			    y_coord    	0
+			    Nested     	TRUE)
+			Focus_Of_Control 	(object Focus_Of_Control "" @218
+			    location   	(1760, 2032)
+			    line_color 	3342489
+			    InterObjView 	@214
+			    height     	60
+			    y_coord    	0
+			    Nested     	TRUE)
+			Focus_Of_Control 	(object Focus_Of_Control "" @219
+			    location   	(1760, 2144)
+			    line_color 	3342489
+			    InterObjView 	@214
+			    height     	60
+			    y_coord    	0
+			    Nested     	TRUE)
+			Focus_Of_Control 	(object Focus_Of_Control "" @220
+			    location   	(1760, 2256)
+			    line_color 	3342489
+			    InterObjView 	@214
+			    height     	60
+			    y_coord    	0
+			    Nested     	TRUE))
+		    (object InterObjView "StandardPipeline" @221
+			location   	(2080, 224)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	TRUE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object ItemLabel
+			    Parent_View 	@221
+			    location   	(2080, 224)
+			    fill_color 	13434879
+			    anchor_loc 	1
+			    nlines     	2
+			    max_width  	326
+			    justify    	0
+			    label      	"StandardPipeline")
+			icon_style 	"Icon"
+			line_color 	3342489
+			fill_color 	13434879
+			quidu      	"3DFE047D006D"
+			width      	344
+			height     	2912
+			icon_height 	0
+			icon_width 	0
+			icon_y_offset 	0
+			annotation 	1
+			Focus_Of_Control 	(object Focus_Of_Control "" @222
+			    location   	(2080, 2368)
+			    line_color 	3342489
+			    InterObjView 	@221
+			    height     	312
+			    y_coord    	252
+			    Nested     	FALSE)
+			Focus_Of_Control 	(object Focus_Of_Control "" @223
+			    location   	(2080, 2416)
+			    line_color 	3342489
+			    InterObjView 	@221
+			    height     	60
+			    y_coord    	0
+			    Nested     	TRUE)
+			Focus_Of_Control 	(object Focus_Of_Control "" @224
+			    location   	(2080, 2480)
+			    line_color 	3342489
+			    InterObjView 	@221
+			    height     	60
+			    y_coord    	0
+			    Nested     	TRUE)
+			Focus_Of_Control 	(object Focus_Of_Control "" @225
+			    location   	(2080, 2560)
+			    line_color 	3342489
+			    InterObjView 	@221
+			    height     	60
+			    y_coord    	0
+			    Nested     	TRUE))
+		    (object InterMessView "" @226
+			location   	(16, 384)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	FALSE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object SegLabel @227
+			    Parent_View 	@226
+			    location   	(335, 340)
+			    font       	(object Font
+				size       	10
+				face       	"Arial"
+				bold       	FALSE
+				italics    	FALSE
+				underline  	FALSE
+				strike     	FALSE
+				color      	0
+				default_color 	TRUE)
+			    quidu      	"3DFE02830374"
+			    anchor_loc 	1
+			    nlines     	1
+			    max_width  	110
+			    justify    	0
+			    label      	"start()"
+			    pctDist    	0.500000
+			    height     	45
+			    orientation 	0)
+			line_color 	3342489
+			client     	@193
+			supplier   	@195
+			Focus_Src  	@194
+			Focus_Entry 	@196
+			origin     	(207, 384)
+			terminus   	(464, 384)
+			ordinal    	0)
+		    (object InterMessView "" @228
+			location   	(16, 416)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	FALSE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object SegLabel @229
+			    Parent_View 	@228
+			    location   	(631, 372)
+			    font       	(object Font
+				size       	10
+				face       	"Arial"
+				bold       	FALSE
+				italics    	FALSE
+				underline  	FALSE
+				strike     	FALSE
+				color      	0
+				default_color 	TRUE)
+			    quidu      	"3DFE02BA0188"
+			    anchor_loc 	1
+			    nlines     	1
+			    max_width  	110
+			    justify    	0
+			    label      	"start()"
+			    pctDist    	0.500000
+			    height     	45
+			    orientation 	0)
+			line_color 	3342489
+			client     	@195
+			supplier   	@197
+			Focus_Src  	@196
+			Focus_Entry 	@198
+			origin     	(495, 416)
+			terminus   	(768, 416)
+			ordinal    	1)
+		    (object SelfMessView "" @230
+			location   	(16, 480)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	FALSE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object SegLabel @231
+			    Parent_View 	@230
+			    location   	(1244, 437)
+			    font       	(object Font
+				size       	10
+				face       	"Arial"
+				bold       	FALSE
+				italics    	FALSE
+				underline  	FALSE
+				strike     	FALSE
+				color      	0
+				default_color 	TRUE)
+			    quidu      	"3DFE02D3006C"
+			    anchor_loc 	1
+			    nlines     	1
+			    max_width  	854
+			    justify    	0
+			    label      	"fireLifecycleEvent(BEFORE_START_EVENT)"
+			    pctDist    	2.960000
+			    height     	44
+			    orientation 	0)
+			line_color 	3342489
+			client     	@197
+			supplier   	@197
+			Focus_Src  	@198
+			Focus_Entry 	@199
+			origin     	(800, 480)
+			terminus   	(950, 480)
+			ordinal    	2)
+		    (object SelfMessView "" @232
+			location   	(16, 592)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	FALSE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object SegLabel @233
+			    Parent_View 	@232
+			    location   	(1146, 549)
+			    font       	(object Font
+				size       	10
+				face       	"Arial"
+				bold       	FALSE
+				italics    	FALSE
+				underline  	FALSE
+				strike     	FALSE
+				color      	0
+				default_color 	TRUE)
+			    quidu      	"3DFE02DF02DF"
+			    anchor_loc 	1
+			    nlines     	1
+			    max_width  	658
+			    justify    	0
+			    label      	"fireLifecycleEvent(START_EVENT)"
+			    pctDist    	2.313333
+			    height     	44
+			    orientation 	0)
+			line_color 	3342489
+			client     	@197
+			supplier   	@197
+			Focus_Src  	@198
+			Focus_Entry 	@200
+			origin     	(800, 592)
+			terminus   	(950, 592)
+			ordinal    	3)
+		    (object InterMessView "" @234
+			location   	(16, 704)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	FALSE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object SegLabel @235
+			    Parent_View 	@234
+			    location   	(935, 660)
+			    font       	(object Font
+				size       	10
+				face       	"Arial"
+				bold       	FALSE
+				italics    	FALSE
+				underline  	FALSE
+				strike     	FALSE
+				color      	0
+				default_color 	TRUE)
+			    quidu      	"3DFE030C02B3"
+			    anchor_loc 	1
+			    nlines     	1
+			    max_width  	110
+			    justify    	0
+			    label      	"start()"
+			    pctDist    	0.500000
+			    height     	45
+			    orientation 	0)
+			line_color 	3342489
+			client     	@197
+			supplier   	@201
+			Focus_Src  	@198
+			Focus_Entry 	@202
+			origin     	(799, 704)
+			terminus   	(1072, 704)
+			ordinal    	4)
+		    (object SelfMessView "" @236
+			location   	(16, 752)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	FALSE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object SegLabel @237
+			    Parent_View 	@236
+			    location   	(1531, 708)
+			    font       	(object Font
+				size       	10
+				face       	"Arial"
+				bold       	FALSE
+				italics    	FALSE
+				underline  	FALSE
+				strike     	FALSE
+				color      	0
+				default_color 	TRUE)
+			    quidu      	"3DFE031D0022"
+			    anchor_loc 	1
+			    nlines     	1
+			    max_width  	854
+			    justify    	0
+			    label      	"fireLifecycleEvent(BEFORE_START_EVENT)"
+			    pctDist    	2.853333
+			    height     	45
+			    orientation 	0)
+			line_color 	3342489
+			client     	@201
+			supplier   	@201
+			Focus_Src  	@202
+			Focus_Entry 	@203
+			origin     	(1104, 752)
+			terminus   	(1254, 752)
+			ordinal    	5)
+		    (object SelfMessView "" @238
+			location   	(16, 864)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	FALSE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object SegLabel @239
+			    Parent_View 	@238
+			    location   	(1449, 821)
+			    font       	(object Font
+				size       	10
+				face       	"Arial"
+				bold       	FALSE
+				italics    	FALSE
+				underline  	FALSE
+				strike     	FALSE
+				color      	0
+				default_color 	TRUE)
+			    quidu      	"3DFE0330019B"
+			    anchor_loc 	1
+			    nlines     	1
+			    max_width  	658
+			    justify    	0
+			    label      	"fireLifecycleEvent(START_EVENT)"
+			    pctDist    	2.306667
+			    height     	44
+			    orientation 	0)
+			line_color 	3342489
+			client     	@201
+			supplier   	@201
+			Focus_Src  	@202
+			Focus_Entry 	@204
+			origin     	(1104, 864)
+			terminus   	(1254, 864)
+			ordinal    	6)
+		    (object InterMessView "" @240
+			location   	(16, 976)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	FALSE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object SegLabel @241
+			    Parent_View 	@240
+			    location   	(1255, 932)
+			    font       	(object Font
+				size       	10
+				face       	"Arial"
+				bold       	FALSE
+				italics    	FALSE
+				underline  	FALSE
+				strike     	FALSE
+				color      	0
+				default_color 	TRUE)
+			    quidu      	"3DFE0370018A"
+			    anchor_loc 	1
+			    nlines     	1
+			    max_width  	110
+			    justify    	0
+			    label      	"start()"
+			    pctDist    	0.500000
+			    height     	45
+			    orientation 	0)
+			line_color 	3342489
+			client     	@201
+			supplier   	@205
+			Focus_Src  	@202
+			Focus_Entry 	@206
+			origin     	(1103, 976)
+			terminus   	(1408, 976)
+			ordinal    	7)
+		    (object SelfMessView "" @242
+			location   	(16, 1056)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	FALSE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object SegLabel @243
+			    Parent_View 	@242
+			    location   	(1865, 1014)
+			    font       	(object Font
+				size       	10
+				face       	"Arial"
+				bold       	FALSE
+				italics    	FALSE
+				underline  	FALSE
+				strike     	FALSE
+				color      	0
+				default_color 	TRUE)
+			    quidu      	"3DFE03750051"
+			    anchor_loc 	1
+			    nlines     	1
+			    max_width  	854
+			    justify    	0
+			    label      	"fireLifecycleEvent(BEFORE_START_EVENT)"
+			    pctDist    	2.840000
+			    height     	43
+			    orientation 	0)
+			line_color 	3342489
+			client     	@205
+			supplier   	@205
+			Focus_Src  	@207
+			Focus_Entry 	@208
+			origin     	(1440, 1056)
+			terminus   	(1590, 1056)
+			ordinal    	8)
+		    (object SelfMessView "" @244
+			location   	(16, 1168)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	FALSE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object SegLabel @245
+			    Parent_View 	@244
+			    location   	(1639, 1141)
+			    font       	(object Font
+				size       	10
+				face       	"Arial"
+				bold       	FALSE
+				italics    	FALSE
+				underline  	FALSE
+				strike     	FALSE
+				color      	0
+				default_color 	TRUE)
+			    quidu      	"3DFE0389001C"
+			    anchor_loc 	1
+			    nlines     	1
+			    max_width  	373
+			    justify    	0
+			    label      	"addDefaultMapper()"
+			    pctDist    	1.326667
+			    height     	28
+			    orientation 	0)
+			line_color 	3342489
+			client     	@205
+			supplier   	@205
+			Focus_Src  	@207
+			Focus_Entry 	@209
+			origin     	(1440, 1168)
+			terminus   	(1590, 1168)
+			ordinal    	9)
+		    (object SelfMessView "" @246
+			location   	(16, 1296)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	FALSE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object SegLabel @247
+			    Parent_View 	@246
+			    location   	(1592, 1268)
+			    font       	(object Font
+				size       	10
+				face       	"Arial"
+				bold       	FALSE
+				italics    	FALSE
+				underline  	FALSE
+				strike     	FALSE
+				color      	0
+				default_color 	TRUE)
+			    quidu      	"3DFE03980281"
+			    anchor_loc 	1
+			    nlines     	1
+			    max_width  	238
+			    justify    	0
+			    label      	"logger.start()"
+			    pctDist    	1.020000
+			    height     	29
+			    orientation 	0)
+			line_color 	3342489
+			client     	@205
+			supplier   	@205
+			Focus_Src  	@207
+			Focus_Entry 	@210
+			origin     	(1440, 1296)
+			terminus   	(1590, 1296)
+			ordinal    	10)
+		    (object SelfMessView "" @248
+			location   	(16, 1408)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	FALSE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object SegLabel @249
+			    Parent_View 	@248
+			    location   	(1593, 1380)
+			    font       	(object Font
+				size       	10
+				face       	"Arial"
+				bold       	FALSE
+				italics    	FALSE
+				underline  	FALSE
+				strike     	FALSE
+				color      	0
+				default_color 	TRUE)
+			    quidu      	"3DFE03A80107"
+			    anchor_loc 	1
+			    nlines     	1
+			    max_width  	226
+			    justify    	0
+			    label      	"realm.start()"
+			    pctDist    	1.026667
+			    height     	29
+			    orientation 	0)
+			line_color 	3342489
+			client     	@205
+			supplier   	@205
+			Focus_Src  	@207
+			Focus_Entry 	@211
+			origin     	(1440, 1408)
+			terminus   	(1590, 1408)
+			ordinal    	11)
+		    (object SelfMessView "" @250
+			location   	(16, 1536)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	FALSE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object SegLabel @251
+			    Parent_View 	@250
+			    location   	(1608, 1508)
+			    font       	(object Font
+				size       	10
+				face       	"Arial"
+				bold       	FALSE
+				italics    	FALSE
+				underline  	FALSE
+				strike     	FALSE
+				color      	0
+				default_color 	TRUE)
+			    quidu      	"3DFE03BD000D"
+			    anchor_loc 	1
+			    nlines     	1
+			    max_width  	259
+			    justify    	0
+			    label      	"findMappers()"
+			    pctDist    	1.120000
+			    height     	29
+			    orientation 	0)
+			line_color 	3342489
+			client     	@205
+			supplier   	@205
+			Focus_Src  	@207
+			Focus_Entry 	@212
+			origin     	(1440, 1536)
+			terminus   	(1590, 1536)
+			ordinal    	12)
+		    (object SelfMessView "" @252
+			location   	(16, 1648)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	FALSE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object SegLabel @253
+			    Parent_View 	@252
+			    location   	(1515, 1604)
+			    font       	(object Font
+				size       	10
+				face       	"Arial"
+				bold       	FALSE
+				italics    	FALSE
+				underline  	FALSE
+				strike     	FALSE
+				color      	0
+				default_color 	TRUE)
+			    quidu      	"3DFE03E000A4"
+			    anchor_loc 	1
+			    nlines     	1
+			    max_width  	251
+			    justify    	0
+			    label      	"findChildren()"
+			    pctDist    	0.500000
+			    height     	45
+			    orientation 	0)
+			line_color 	3342489
+			client     	@205
+			supplier   	@205
+			Focus_Src  	@207
+			Focus_Entry 	@213
+			origin     	(1440, 1648)
+			terminus   	(1590, 1648)
+			ordinal    	13)
+		    (object InterMessView "" @254
+			location   	(1664, 1760)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	FALSE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object SegLabel @255
+			    Parent_View 	@254
+			    location   	(1591, 1716)
+			    font       	(object Font
+				size       	10
+				face       	"Arial"
+				bold       	FALSE
+				italics    	FALSE
+				underline  	FALSE
+				strike     	FALSE
+				color      	0
+				default_color 	TRUE)
+			    quidu      	"3DFE03FB027A"
+			    anchor_loc 	1
+			    nlines     	1
+			    max_width  	110
+			    justify    	0
+			    label      	"start()"
+			    pctDist    	0.500000
+			    height     	45
+			    orientation 	0)
+			line_color 	3342489
+			client     	@205
+			supplier   	@214
+			Focus_Src  	@207
+			Focus_Entry 	@215
+			origin     	(1439, 1760)
+			terminus   	(1744, 1760)
+			ordinal    	14)
+		    (object SelfMessView "" @256
+			location   	(16, 1808)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	FALSE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object SegLabel @257
+			    Parent_View 	@256
+			    location   	(1606, 1784)
+			    font       	(object Font
+				size       	10
+				face       	"Arial"
+				bold       	FALSE
+				italics    	FALSE
+				underline  	FALSE
+				strike     	FALSE
+				color      	0
+				default_color 	TRUE)
+			    quidu      	"3DFE043B02AE"
+			    anchor_loc 	1
+			    nlines     	1
+			    max_width  	854
+			    justify    	0
+			    label      	"fireLifecycleEvent(BEFORE_START_EVENT)"
+			    pctDist    	-1.133333
+			    height     	24
+			    orientation 	0)
+			line_color 	3342489
+			client     	@214
+			supplier   	@214
+			Focus_Src  	@215
+			Focus_Entry 	@216
+			origin     	(1776, 1808)
+			terminus   	(1926, 1808)
+			ordinal    	15)
+		    (object SelfMessView "" @258
+			location   	(16, 1920)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	FALSE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object SegLabel @259
+			    Parent_View 	@258
+			    location   	(1963, 1877)
+			    font       	(object Font
+				size       	10
+				face       	"Arial"
+				bold       	FALSE
+				italics    	FALSE
+				underline  	FALSE
+				strike     	FALSE
+				color      	0
+				default_color 	TRUE)
+			    quidu      	"3DFE045C021F"
+			    anchor_loc 	1
+			    nlines     	1
+			    max_width  	373
+			    justify    	0
+			    label      	"addDefaultMapper()"
+			    pctDist    	1.253333
+			    height     	44
+			    orientation 	0)
+			line_color 	3342489
+			client     	@214
+			supplier   	@214
+			Focus_Src  	@215
+			Focus_Entry 	@217
+			origin     	(1776, 1920)
+			terminus   	(1926, 1920)
+			ordinal    	16)
+		    (object InterMessView "" @260
+			location   	(2000, 2368)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	FALSE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object SegLabel @261
+			    Parent_View 	@260
+			    location   	(1919, 2324)
+			    font       	(object Font
+				size       	10
+				face       	"Arial"
+				bold       	FALSE
+				italics    	FALSE
+				underline  	FALSE
+				strike     	FALSE
+				color      	0
+				default_color 	TRUE)
+			    quidu      	"3DFE048E00B9"
+			    anchor_loc 	1
+			    nlines     	1
+			    max_width  	110
+			    justify    	0
+			    label      	"start()"
+			    pctDist    	0.500000
+			    height     	45
+			    orientation 	0)
+			line_color 	3342489
+			client     	@214
+			supplier   	@221
+			Focus_Src  	@215
+			Focus_Entry 	@222
+			origin     	(1775, 2368)
+			terminus   	(2064, 2368)
+			ordinal    	20)
+		    (object SelfMessView "" @262
+			location   	(16, 2032)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	FALSE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object SegLabel @263
+			    Parent_View 	@262
+			    location   	(1916, 2004)
+			    font       	(object Font
+				size       	10
+				face       	"Arial"
+				bold       	FALSE
+				italics    	FALSE
+				underline  	FALSE
+				strike     	FALSE
+				color      	0
+				default_color 	TRUE)
+			    quidu      	"3DFE049B000C"
+			    anchor_loc 	1
+			    nlines     	1
+			    max_width  	238
+			    justify    	0
+			    label      	"logger.start()"
+			    pctDist    	0.933333
+			    height     	29
+			    orientation 	0)
+			line_color 	3342489
+			client     	@214
+			supplier   	@214
+			Focus_Src  	@215
+			Focus_Entry 	@218
+			origin     	(1776, 2032)
+			terminus   	(1926, 2032)
+			ordinal    	17)
+		    (object SelfMessView "" @264
+			location   	(16, 2144)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	FALSE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object SegLabel @265
+			    Parent_View 	@264
+			    location   	(1916, 2117)
+			    font       	(object Font
+				size       	10
+				face       	"Arial"
+				bold       	FALSE
+				italics    	FALSE
+				underline  	FALSE
+				strike     	FALSE
+				color      	0
+				default_color 	TRUE)
+			    quidu      	"3DFE04A303BB"
+			    anchor_loc 	1
+			    nlines     	1
+			    max_width  	238
+			    justify    	0
+			    label      	"findMapper()"
+			    pctDist    	0.933333
+			    height     	28
+			    orientation 	0)
+			line_color 	3342489
+			client     	@214
+			supplier   	@214
+			Focus_Src  	@215
+			Focus_Entry 	@219
+			origin     	(1776, 2144)
+			terminus   	(1926, 2144)
+			ordinal    	18)
+		    (object SelfMessView "" @266
+			location   	(16, 2256)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	FALSE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object SegLabel @267
+			    Parent_View 	@266
+			    location   	(1916, 2228)
+			    font       	(object Font
+				size       	10
+				face       	"Arial"
+				bold       	FALSE
+				italics    	FALSE
+				underline  	FALSE
+				strike     	FALSE
+				color      	0
+				default_color 	TRUE)
+			    quidu      	"3DFE04A90342"
+			    anchor_loc 	1
+			    nlines     	1
+			    max_width  	251
+			    justify    	0
+			    label      	"findChildren()"
+			    pctDist    	0.933333
+			    height     	29
+			    orientation 	0)
+			line_color 	3342489
+			client     	@214
+			supplier   	@214
+			Focus_Src  	@215
+			Focus_Entry 	@220
+			origin     	(1776, 2256)
+			terminus   	(1926, 2256)
+			ordinal    	19)
+		    (object NoteView @268
+			location   	(2128, 1488)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	FALSE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object ItemLabel
+			    Parent_View 	@268
+			    location   	(1915, 1422)
+			    fill_color 	13434879
+			    nlines     	2
+			    max_width  	390
+			    label      	"#1 Catalina.start()")
+			line_color 	3342489
+			fill_color 	13434879
+			width      	450
+			height     	144)
+		    (object SelfMessView "" @269
+			location   	(16, 2416)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	FALSE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object SegLabel @270
+			    Parent_View 	@269
+			    location   	(1644, 2498)
+			    font       	(object Font
+				size       	10
+				face       	"Arial"
+				bold       	FALSE
+				italics    	FALSE
+				underline  	FALSE
+				strike     	FALSE
+				color      	0
+				default_color 	TRUE)
+			    quidu      	"3DFE05780138"
+			    anchor_loc 	1
+			    nlines     	1
+			    max_width  	854
+			    justify    	0
+			    label      	"fireLifecycleEvent(BEFORE_START_EVENT)"
+			    pctDist    	-3.020000
+			    height     	45
+			    orientation 	0)
+			line_color 	3342489
+			client     	@221
+			supplier   	@221
+			Focus_Src  	@222
+			Focus_Entry 	@223
+			origin     	(2096, 2416)
+			terminus   	(2246, 2416)
+			ordinal    	21)
+		    (object SelfMessView "" @271
+			location   	(16, 2480)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	FALSE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object SegLabel @272
+			    Parent_View 	@271
+			    location   	(1705, 2582)
+			    font       	(object Font
+				size       	10
+				face       	"Arial"
+				bold       	FALSE
+				italics    	FALSE
+				underline  	FALSE
+				strike     	FALSE
+				color      	0
+				default_color 	TRUE)
+			    quidu      	"3DFE05A80398"
+			    anchor_loc 	1
+			    nlines     	1
+			    max_width  	658
+			    justify    	0
+			    label      	"fireLifecycleEvent(START_EVENT)"
+			    pctDist    	-2.613333
+			    height     	45
+			    orientation 	0)
+			line_color 	3342489
+			client     	@221
+			supplier   	@221
+			Focus_Src  	@222
+			Focus_Entry 	@224
+			origin     	(2096, 2480)
+			terminus   	(2246, 2480)
+			ordinal    	22)
+		    (object SelfMessView "" @273
+			location   	(16, 2560)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	FALSE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object SegLabel @274
+			    Parent_View 	@273
+			    location   	(1737, 2423)
+			    font       	(object Font
+				size       	10
+				face       	"Arial"
+				bold       	FALSE
+				italics    	FALSE
+				underline  	FALSE
+				strike     	FALSE
+				color      	0
+				default_color 	TRUE)
+			    quidu      	"3DFE05BA0196"
+			    anchor_loc 	1
+			    nlines     	1
+			    max_width  	658
+			    justify    	0
+			    label      	"fireLifecycleEvent(AFTER_EVENT)"
+			    pctDist    	-2.393333
+			    height     	138
+			    orientation 	0)
+			line_color 	3342489
+			client     	@221
+			supplier   	@221
+			Focus_Src  	@222
+			Focus_Entry 	@225
+			origin     	(2096, 2560)
+			terminus   	(2246, 2560)
+			ordinal    	23)
+		    (object NoteView @275
+			location   	(960, 1680)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	FALSE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object ItemLabel
+			    Parent_View 	@275
+			    location   	(635, 1571)
+			    fill_color 	13434879
+			    nlines     	4
+			    max_width  	615
+			    label      	"All StandardX will fire these events.")
+			line_color 	3342489
+			fill_color 	13434879
+			width      	675
+			height     	231)
+		    (object AttachView "" @276
+			stereotype 	TRUE
+			line_color 	3342489
+			client     	@275
+			supplier   	@272
+			line_style 	0)
+		    (object AttachView "" @277
+			stereotype 	TRUE
+			line_color 	3342489
+			client     	@275
+			supplier   	@270
+			line_style 	0)
+		    (object AttachView "" @278
+			stereotype 	TRUE
+			line_color 	3342489
+			client     	@275
+			supplier   	@274
+			line_style 	0)))
+	    (object InteractionDiagram "4. catalina_start_2"
+		mechanism_ref 	@85
+		quid       	"3DFE050900BF"
+		title      	"4. catalina_start_2"
+		zoom       	100
+		max_height 	28350
+		max_width  	21600
+		origin_x   	0
+		origin_y   	1087
+		items      	(list diagram_item_list
+		    (object InterObjView "StandardHost" @279
+			location   	(208, 224)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	TRUE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object ItemLabel
+			    Parent_View 	@279
+			    location   	(208, 224)
+			    fill_color 	13434879
+			    anchor_loc 	1
+			    nlines     	2
+			    max_width  	282
+			    justify    	0
+			    label      	"StandardHost")
+			icon_style 	"Icon"
+			line_color 	3342489
+			fill_color 	13434879
+			quidu      	"3DFE0538017B"
+			width      	300
+			height     	2114
+			icon_height 	0
+			icon_width 	0
+			icon_y_offset 	0
+			annotation 	1
+			Focus_Of_Control 	(object Focus_Of_Control "" @280
+			    location   	(208, 384)
+			    line_color 	3342489
+			    InterObjView 	@279
+			    height     	1864
+			    y_coord    	1804
+			    Nested     	FALSE)
+			Focus_Of_Control 	(object Focus_Of_Control "" @281
+			    location   	(208, 384)
+			    line_color 	3342489
+			    InterObjView 	@279
+			    height     	60
+			    y_coord    	0
+			    Nested     	TRUE)
+			Focus_Of_Control 	(object Focus_Of_Control "" @282
+			    location   	(208, 1088)
+			    line_color 	3342489
+			    InterObjView 	@279
+			    height     	60
+			    y_coord    	0
+			    Nested     	TRUE)
+			Focus_Of_Control 	(object Focus_Of_Control "" @283
+			    location   	(208, 1616)
+			    line_color 	3342489
+			    InterObjView 	@279
+			    height     	60
+			    y_coord    	0
+			    Nested     	TRUE))
+		    (object InterObjView "HostConfig" @284
+			location   	(544, 224)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	TRUE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object ItemLabel
+			    Parent_View 	@284
+			    location   	(544, 224)
+			    fill_color 	13434879
+			    anchor_loc 	1
+			    nlines     	2
+			    max_width  	282
+			    justify    	0
+			    label      	"HostConfig")
+			icon_style 	"Icon"
+			line_color 	3342489
+			fill_color 	13434879
+			quidu      	"3DFE06A60131"
+			width      	300
+			height     	2114
+			icon_height 	0
+			icon_width 	0
+			icon_y_offset 	0
+			annotation 	1
+			Focus_Of_Control 	(object Focus_Of_Control "" @285
+			    location   	(544, 512)
+			    line_color 	3342489
+			    InterObjView 	@284
+			    height     	696
+			    y_coord    	636
+			    Nested     	FALSE)
+			Focus_Of_Control 	(object Focus_Of_Control "" @286
+			    location   	(544, 576)
+			    line_color 	3342489
+			    InterObjView 	@284
+			    height     	60
+			    y_coord    	0
+			    Nested     	TRUE)
+			Focus_Of_Control 	(object Focus_Of_Control "" @287
+			    location   	(544, 688)
+			    line_color 	3342489
+			    InterObjView 	@284
+			    height     	60
+			    y_coord    	0
+			    Nested     	TRUE)
+			Focus_Of_Control 	(object Focus_Of_Control "" @288
+			    location   	(544, 784)
+			    line_color 	3342489
+			    InterObjView 	@284
+			    height     	60
+			    y_coord    	0
+			    Nested     	TRUE)
+			Focus_Of_Control 	(object Focus_Of_Control "" @289
+			    location   	(544, 896)
+			    line_color 	3342489
+			    InterObjView 	@284
+			    height     	60
+			    y_coord    	0
+			    Nested     	TRUE)
+			Focus_Of_Control 	(object Focus_Of_Control "" @290
+			    location   	(544, 1008)
+			    line_color 	3342489
+			    InterObjView 	@284
+			    height     	60
+			    y_coord    	0
+			    Nested     	TRUE)
+			Focus_Of_Control 	(object Focus_Of_Control "" @291
+			    location   	(544, 1536)
+			    line_color 	3342489
+			    InterObjView 	@284
+			    height     	200
+			    y_coord    	140
+			    Nested     	FALSE)
+			Focus_Of_Control 	(object Focus_Of_Control "" @292
+			    location   	(544, 1536)
+			    line_color 	3342489
+			    InterObjView 	@284
+			    height     	60
+			    y_coord    	0
+			    Nested     	TRUE))
+		    (object InterObjView "StandardHostDeployer" @293
+			location   	(944, 224)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	TRUE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object ItemLabel
+			    Parent_View 	@293
+			    location   	(944, 224)
+			    fill_color 	13434879
+			    anchor_loc 	1
+			    nlines     	2
+			    max_width  	426
+			    justify    	0
+			    label      	"StandardHostDeployer")
+			icon_style 	"Icon"
+			line_color 	3342489
+			fill_color 	13434879
+			quidu      	"3DFE079A0055"
+			width      	444
+			height     	2114
+			icon_height 	0
+			icon_width 	0
+			icon_y_offset 	0
+			annotation 	1
+			Focus_Of_Control 	(object Focus_Of_Control "" @294
+			    location   	(944, 1280)
+			    line_color 	3342489
+			    InterObjView 	@293
+			    height     	824
+			    y_coord    	764
+			    Nested     	FALSE)
+			Focus_Of_Control 	(object Focus_Of_Control "" @295
+			    location   	(944, 2128)
+			    line_color 	3342489
+			    InterObjView 	@293
+			    height     	60
+			    y_coord    	0
+			    Nested     	FALSE))
+		    (object InterObjView "Digester" @296
+			location   	(1328, 224)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	TRUE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object ItemLabel
+			    Parent_View 	@296
+			    location   	(1328, 224)
+			    fill_color 	13434879
+			    anchor_loc 	1
+			    nlines     	2
+			    max_width  	282
+			    justify    	0
+			    label      	"Digester")
+			icon_style 	"Icon"
+			line_color 	3342489
+			fill_color 	13434879
+			quidu      	"3DFE07C9034C"
+			width      	300
+			height     	2114
+			icon_height 	0
+			icon_width 	0
+			icon_y_offset 	0
+			annotation 	1
+			Focus_Of_Control 	(object Focus_Of_Control "" @297
+			    location   	(1328, 1280)
+			    line_color 	3342489
+			    InterObjView 	@296
+			    height     	60
+			    y_coord    	0
+			    Nested     	FALSE)
+			Focus_Of_Control 	(object Focus_Of_Control "" @298
+			    location   	(1328, 1488)
+			    line_color 	3342489
+			    InterObjView 	@296
+			    height     	60
+			    y_coord    	0
+			    Nested     	FALSE)
+			Focus_Of_Control 	(object Focus_Of_Control "" @299
+			    location   	(1328, 1984)
+			    line_color 	3342489
+			    InterObjView 	@296
+			    height     	60
+			    y_coord    	0
+			    Nested     	FALSE))
+		    (object InterObjView "ContextRuleSet" @300
+			location   	(1648, 224)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	TRUE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object ItemLabel
+			    Parent_View 	@300
+			    location   	(1648, 224)
+			    fill_color 	13434879
+			    anchor_loc 	1
+			    nlines     	2
+			    max_width  	282
+			    justify    	0
+			    label      	"ContextRuleSet")
+			icon_style 	"Icon"
+			line_color 	3342489
+			fill_color 	13434879
+			quidu      	"3DFE0834016F"
+			width      	300
+			height     	2114
+			icon_height 	0
+			icon_width 	0
+			icon_y_offset 	0
+			annotation 	1
+			Focus_Of_Control 	(object Focus_Of_Control "" @301
+			    location   	(1648, 1408)
+			    line_color 	3342489
+			    InterObjView 	@300
+			    height     	60
+			    y_coord    	0
+			    Nested     	FALSE)
+			Focus_Of_Control 	(object Focus_Of_Control "" @302
+			    location   	(1648, 1888)
+			    line_color 	3342489
+			    InterObjView 	@300
+			    height     	60
+			    y_coord    	0
+			    Nested     	FALSE))
+		    (object InterObjView "NamingRuleSet" @303
+			location   	(1968, 224)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	TRUE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object ItemLabel
+			    Parent_View 	@303
+			    location   	(1968, 224)
+			    fill_color 	13434879
+			    anchor_loc 	1
+			    nlines     	2
+			    max_width  	282
+			    justify    	0
+			    label      	"NamingRuleSet")
+			icon_style 	"Icon"
+			line_color 	3342489
+			fill_color 	13434879
+			quidu      	"3DFE08D00173"
+			width      	300
+			height     	2114
+			icon_height 	0
+			icon_width 	0
+			icon_y_offset 	0
+			annotation 	1
+			Focus_Of_Control 	(object Focus_Of_Control "" @304
+			    location   	(1968, 1792)
+			    line_color 	3342489
+			    InterObjView 	@303
+			    height     	60
+			    y_coord    	0
+			    Nested     	FALSE))
+		    (object SelfMessView "" @305
+			location   	(0, 384)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	FALSE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object SegLabel @306
+			    Parent_View 	@305
+			    location   	(555, 342)
+			    font       	(object Font
+				size       	10
+				face       	"Arial"
+				bold       	FALSE
+				italics    	FALSE
+				underline  	FALSE
+				strike     	FALSE
+				color      	0
+				default_color 	TRUE)
+			    quidu      	"3DFE066C0341"
+			    anchor_loc 	1
+			    nlines     	1
+			    max_width  	651
+			    justify    	0
+			    label      	"fireLifecycleEvent(START_EVENT)"
+			    pctDist    	2.206667
+			    height     	43
+			    orientation 	0)
+			line_color 	3342489
+			client     	@279
+			supplier   	@279
+			Focus_Src  	@280
+			Focus_Entry 	@281
+			origin     	(224, 384)
+			terminus   	(374, 384)
+			ordinal    	0)
+		    (object InterMessView "" @307
+			location   	(384, 512)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	FALSE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object SegLabel @308
+			    Parent_View 	@307
+			    location   	(486, 468)
+			    font       	(object Font
+				size       	10
+				face       	"Arial"
+				bold       	FALSE
+				italics    	FALSE
+				underline  	FALSE
+				strike     	FALSE
+				color      	0
+				default_color 	TRUE)
+			    quidu      	"3DFE06D20294"
+			    anchor_loc 	1
+			    nlines     	1
+			    max_width  	507
+			    justify    	0
+			    label      	"interested[i].lifecycleEvent()"
+			    pctDist    	0.865574
+			    height     	45
+			    orientation 	0)
+			line_color 	3342489
+			client     	@279
+			supplier   	@284
+			Focus_Src  	@280
+			Focus_Entry 	@285
+			origin     	(223, 512)
+			terminus   	(528, 512)
+			ordinal    	1)
+		    (object SelfMessView "" @309
+			location   	(16, 576)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	FALSE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object SegLabel @310
+			    Parent_View 	@309
+			    location   	(713, 537)
+			    font       	(object Font
+				size       	10
+				face       	"Arial"
+				bold       	FALSE
+				italics    	FALSE
+				underline  	FALSE
+				strike     	FALSE
+				color      	0
+				default_color 	TRUE)
+			    quidu      	"3DFE06E9028D"
+			    anchor_loc 	1
+			    nlines     	1
+			    max_width  	297
+			    justify    	0
+			    label      	"setDeployXML()"
+			    pctDist    	1.026667
+			    height     	40
+			    orientation 	0)
+			line_color 	3342489
+			client     	@284
+			supplier   	@284
+			Focus_Src  	@285
+			Focus_Entry 	@286
+			origin     	(560, 576)
+			terminus   	(710, 576)
+			ordinal    	2)
+		    (object SelfMessView "" @311
+			location   	(16, 688)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	FALSE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object SegLabel @312
+			    Parent_View 	@311
+			    location   	(714, 645)
+			    font       	(object Font
+				size       	10
+				face       	"Arial"
+				bold       	FALSE
+				italics    	FALSE
+				underline  	FALSE
+				strike     	FALSE
+				color      	0
+				default_color 	TRUE)
+			    quidu      	"3DFE06F300FF"
+			    anchor_loc 	1
+			    nlines     	1
+			    max_width  	288
+			    justify    	0
+			    label      	"setLiveDeploy()"
+			    pctDist    	1.033333
+			    height     	44
+			    orientation 	0)
+			line_color 	3342489
+			client     	@284
+			supplier   	@284
+			Focus_Src  	@285
+			Focus_Entry 	@287
+			origin     	(560, 688)
+			terminus   	(710, 688)
+			ordinal    	3)
+		    (object SelfMessView "" @313
+			location   	(16, 784)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	FALSE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object SegLabel @314
+			    Parent_View 	@313
+			    location   	(732, 756)
+			    font       	(object Font
+				size       	10
+				face       	"Arial"
+				bold       	FALSE
+				italics    	FALSE
+				underline  	FALSE
+				strike     	FALSE
+				color      	0
+				default_color 	TRUE)
+			    quidu      	"3DFE06FB00D9"
+			    anchor_loc 	1
+			    nlines     	1
+			    max_width  	326
+			    justify    	0
+			    label      	"setUnpacksWar()"
+			    pctDist    	1.153333
+			    height     	29
+			    orientation 	0)
+			line_color 	3342489
+			client     	@284
+			supplier   	@284
+			Focus_Src  	@285
+			Focus_Entry 	@288
+			origin     	(560, 784)
+			terminus   	(710, 784)
+			ordinal    	4)
+		    (object SelfMessView "" @315
+			location   	(16, 896)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	FALSE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object SegLabel @316
+			    Parent_View 	@315
+			    location   	(747, 868)
+			    font       	(object Font
+				size       	10
+				face       	"Arial"
+				bold       	FALSE
+				italics    	FALSE
+				underline  	FALSE
+				strike     	FALSE
+				color      	0
+				default_color 	TRUE)
+			    quidu      	"3DFE070C0015"
+			    anchor_loc 	1
+			    nlines     	1
+			    max_width  	350
+			    justify    	0
+			    label      	"setXMLValidation()"
+			    pctDist    	1.246667
+			    height     	29
+			    orientation 	0)
+			line_color 	3342489
+			client     	@284
+			supplier   	@284
+			Focus_Src  	@285
+			Focus_Entry 	@289
+			origin     	(560, 896)
+			terminus   	(710, 896)
+			ordinal    	5)
+		    (object SelfMessView "" @317
+			location   	(16, 1008)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	FALSE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object SegLabel @318
+			    Parent_View 	@317
+			    location   	(762, 980)
+			    font       	(object Font
+				size       	10
+				face       	"Arial"
+				bold       	FALSE
+				italics    	FALSE
+				underline  	FALSE
+				strike     	FALSE
+				color      	0
+				default_color 	TRUE)
+			    quidu      	"3DFE073B0031"
+			    anchor_loc 	1
+			    nlines     	1
+			    max_width  	359
+			    justify    	0
+			    label      	"deployDescriptors()"
+			    pctDist    	1.346667
+			    height     	29
+			    orientation 	0)
+			line_color 	3342489
+			client     	@284
+			supplier   	@284
+			Focus_Src  	@285
+			Focus_Entry 	@290
+			origin     	(560, 1008)
+			terminus   	(710, 1008)
+			ordinal    	6)
+		    (object InterMessView "" @319
+			location   	(16, 1088)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	FALSE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object SegLabel @320
+			    Parent_View 	@319
+			    location   	(376, 1044)
+			    font       	(object Font
+				size       	10
+				face       	"Arial"
+				bold       	FALSE
+				italics    	FALSE
+				underline  	FALSE
+				strike     	FALSE
+				color      	0
+				default_color 	TRUE)
+			    quidu      	"3DFE078B03BB"
+			    anchor_loc 	1
+			    nlines     	1
+			    max_width  	136
+			    justify    	0
+			    label      	"install()"
+			    pctDist    	0.500000
+			    height     	45
+			    orientation 	1)
+			line_color 	3342489
+			client     	@284
+			supplier   	@279
+			Focus_Src  	@285
+			Focus_Entry 	@282
+			origin     	(528, 1088)
+			terminus   	(224, 1088)
+			ordinal    	7)
+		    (object InterMessView "" @321
+			location   	(576, 1280)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	FALSE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object SegLabel @322
+			    Parent_View 	@321
+			    location   	(575, 1236)
+			    font       	(object Font
+				size       	10
+				face       	"Arial"
+				bold       	FALSE
+				italics    	FALSE
+				underline  	FALSE
+				strike     	FALSE
+				color      	0
+				default_color 	TRUE)
+			    quidu      	"3DFE07B100BE"
+			    anchor_loc 	1
+			    nlines     	1
+			    max_width  	136
+			    justify    	0
+			    label      	"install()"
+			    pctDist    	0.500000
+			    height     	45
+			    orientation 	0)
+			line_color 	3342489
+			client     	@279
+			supplier   	@293
+			Focus_Src  	@280
+			Focus_Entry 	@294
+			origin     	(223, 1280)
+			terminus   	(928, 1280)
+			ordinal    	8)
+		    (object InterMessView "" @323
+			location   	(1152, 1280)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	FALSE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object SegLabel @324
+			    Parent_View 	@323
+			    location   	(1135, 1236)
+			    font       	(object Font
+				size       	10
+				face       	"Arial"
+				bold       	FALSE
+				italics    	FALSE
+				underline  	FALSE
+				strike     	FALSE
+				color      	0
+				default_color 	TRUE)
+			    quidu      	"3DFE07D200ED"
+			    anchor_loc 	1
+			    nlines     	1
+			    max_width  	144
+			    justify    	0
+			    label      	"create()"
+			    pctDist    	0.500000
+			    height     	45
+			    orientation 	0)
+			line_color 	3342489
+			client     	@293
+			supplier   	@296
+			Focus_Src  	@294
+			Focus_Entry 	@297
+			origin     	(959, 1280)
+			terminus   	(1312, 1280)
+			ordinal    	9)
+		    (object InterMessView "" @325
+			location   	(1136, 1984)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	FALSE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object SegLabel @326
+			    Parent_View 	@325
+			    location   	(1135, 1940)
+			    font       	(object Font
+				size       	10
+				face       	"Arial"
+				bold       	FALSE
+				italics    	FALSE
+				underline  	FALSE
+				strike     	FALSE
+				color      	0
+				default_color 	TRUE)
+			    quidu      	"3DFE07D603D7"
+			    anchor_loc 	1
+			    nlines     	1
+			    max_width  	136
+			    justify    	0
+			    label      	"parse()"
+			    pctDist    	0.500000
+			    height     	45
+			    orientation 	0)
+			line_color 	3342489
+			client     	@293
+			supplier   	@296
+			Focus_Src  	@294
+			Focus_Entry 	@299
+			origin     	(959, 1984)
+			terminus   	(1312, 1984)
+			ordinal    	16)
+		    (object InterMessView "" @327
+			location   	(1296, 1408)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	FALSE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object SegLabel @328
+			    Parent_View 	@327
+			    location   	(1295, 1364)
+			    font       	(object Font
+				size       	10
+				face       	"Arial"
+				bold       	FALSE
+				italics    	FALSE
+				underline  	FALSE
+				strike     	FALSE
+				color      	0
+				default_color 	TRUE)
+			    quidu      	"3DFE08DA029B"
+			    anchor_loc 	1
+			    nlines     	1
+			    max_width  	106
+			    justify    	0
+			    label      	"new()"
+			    pctDist    	0.500000
+			    height     	45
+			    orientation 	0)
+			line_color 	3342489
+			client     	@293
+			supplier   	@300
+			Focus_Src  	@294
+			Focus_Entry 	@301
+			origin     	(959, 1408)
+			terminus   	(1632, 1408)
+			ordinal    	10)
+		    (object InterMessView "" @329
+			location   	(1456, 1792)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	FALSE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object SegLabel @330
+			    Parent_View 	@329
+			    location   	(1455, 1748)
+			    font       	(object Font
+				size       	10
+				face       	"Arial"
+				bold       	FALSE
+				italics    	FALSE
+				underline  	FALSE
+				strike     	FALSE
+				color      	0
+				default_color 	TRUE)
+			    quidu      	"3DFE08E00091"
+			    anchor_loc 	1
+			    nlines     	1
+			    max_width  	106
+			    justify    	0
+			    label      	"new()"
+			    pctDist    	0.500000
+			    height     	45
+			    orientation 	0)
+			line_color 	3342489
+			client     	@293
+			supplier   	@303
+			Focus_Src  	@294
+			Focus_Entry 	@304
+			origin     	(959, 1792)
+			terminus   	(1952, 1792)
+			ordinal    	14)
+		    (object InterMessView "" @331
+			location   	(16, 1488)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	FALSE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object SegLabel @332
+			    Parent_View 	@331
+			    location   	(1182, 1445)
+			    font       	(object Font
+				size       	10
+				face       	"Arial"
+				bold       	FALSE
+				italics    	FALSE
+				underline  	FALSE
+				strike     	FALSE
+				color      	0
+				default_color 	TRUE)
+			    quidu      	"3DFE08FA003D"
+			    anchor_loc 	1
+			    nlines     	1
+			    max_width  	387
+			    justify    	0
+			    label      	"add(ContextRuleSet)"
+			    pctDist    	0.631728
+			    height     	44
+			    orientation 	0)
+			line_color 	3342489
+			client     	@293
+			supplier   	@296
+			Focus_Src  	@294
+			Focus_Entry 	@298
+			origin     	(959, 1488)
+			terminus   	(1312, 1488)
+			ordinal    	11)
+		    (object InterMessView "" @333
+			location   	(1296, 1888)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	FALSE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object SegLabel @334
+			    Parent_View 	@333
+			    location   	(1295, 1844)
+			    font       	(object Font
+				size       	10
+				face       	"Arial"
+				bold       	FALSE
+				italics    	FALSE
+				underline  	FALSE
+				strike     	FALSE
+				color      	0
+				default_color 	TRUE)
+			    quidu      	"3DFE0907015F"
+			    anchor_loc 	1
+			    nlines     	1
+			    max_width  	416
+			    justify    	0
+			    label      	"add(NamingRuleSet())"
+			    pctDist    	0.500000
+			    height     	45
+			    orientation 	0)
+			line_color 	3342489
+			client     	@293
+			supplier   	@300
+			Focus_Src  	@294
+			Focus_Entry 	@302
+			origin     	(959, 1888)
+			terminus   	(1632, 1888)
+			ordinal    	15)
+		    (object NoteView @335
+			location   	(2096, 2384)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	FALSE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object ItemLabel
+			    Parent_View 	@335
+			    location   	(1893, 2315)
+			    fill_color 	13434879
+			    nlines     	2
+			    max_width  	371
+			    label      	"#2 Catalina.start()")
+			line_color 	3342489
+			fill_color 	13434879
+			width      	431
+			height     	150)
+		    (object SelfMessView "" @336
+			location   	(16, 1536)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	FALSE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object SegLabel @337
+			    Parent_View 	@336
+			    location   	(697, 1493)
+			    font       	(object Font
+				size       	10
+				face       	"Arial"
+				bold       	FALSE
+				italics    	FALSE
+				underline  	FALSE
+				strike     	FALSE
+				color      	0
+				default_color 	TRUE)
+			    quidu      	"3DFE131F0327"
+			    anchor_loc 	1
+			    nlines     	1
+			    max_width  	244
+			    justify    	0
+			    label      	"deployApps()"
+			    pctDist    	0.913333
+			    height     	43
+			    orientation 	0)
+			line_color 	3342489
+			client     	@284
+			supplier   	@284
+			Focus_Src  	@291
+			Focus_Entry 	@292
+			origin     	(560, 1536)
+			terminus   	(710, 1536)
+			ordinal    	12)
+		    (object InterMessView "" @338
+			location   	(16, 1616)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	FALSE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object SegLabel @339
+			    Parent_View 	@338
+			    location   	(376, 1572)
+			    font       	(object Font
+				size       	10
+				face       	"Arial"
+				bold       	FALSE
+				italics    	FALSE
+				underline  	FALSE
+				strike     	FALSE
+				color      	0
+				default_color 	TRUE)
+			    quidu      	"3DFE132D0309"
+			    anchor_loc 	1
+			    nlines     	1
+			    max_width  	136
+			    justify    	0
+			    label      	"install()"
+			    pctDist    	0.500000
+			    height     	45
+			    orientation 	1)
+			line_color 	3342489
+			client     	@284
+			supplier   	@279
+			Focus_Src  	@291
+			Focus_Entry 	@283
+			origin     	(528, 1616)
+			terminus   	(224, 1616)
+			ordinal    	13)
+		    (object InterMessView "" @340
+			location   	(576, 2128)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	FALSE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object SegLabel @341
+			    Parent_View 	@340
+			    location   	(575, 2084)
+			    font       	(object Font
+				size       	10
+				face       	"Arial"
+				bold       	FALSE
+				italics    	FALSE
+				underline  	FALSE
+				strike     	FALSE
+				color      	0
+				default_color 	TRUE)
+			    quidu      	"3DFE133A036C"
+			    anchor_loc 	1
+			    nlines     	1
+			    max_width  	463
+			    justify    	0
+			    label      	"install() // same as above"
+			    pctDist    	0.500000
+			    height     	45
+			    orientation 	0)
+			line_color 	3342489
+			client     	@279
+			supplier   	@293
+			Focus_Src  	@280
+			Focus_Entry 	@295
+			origin     	(223, 2128)
+			terminus   	(928, 2128)
+			ordinal    	17)))
+	    (object InteractionDiagram "5. catalina_start_3"
+		mechanism_ref 	@86
+		quid       	"3DFE094A0346"
+		title      	"5. catalina_start_3"
+		zoom       	100
+		max_height 	28350
+		max_width  	21600
+		origin_x   	0
+		origin_y   	0
+		items      	(list diagram_item_list
+		    (object InterObjView "Digester" @342
+			location   	(176, 224)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	TRUE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object ItemLabel
+			    Parent_View 	@342
+			    location   	(176, 224)
+			    fill_color 	13434879
+			    anchor_loc 	1
+			    nlines     	2
+			    max_width  	282
+			    justify    	0
+			    label      	"Digester")
+			icon_style 	"Icon"
+			line_color 	3342489
+			fill_color 	13434879
+			quidu      	"3DFE095A0371"
+			width      	300
+			height     	1214
+			icon_height 	0
+			icon_width 	0
+			icon_y_offset 	0
+			annotation 	1
+			Focus_Of_Control 	(object Focus_Of_Control "" @343
+			    location   	(176, 352)
+			    line_color 	3342489
+			    InterObjView 	@342
+			    height     	996
+			    y_coord    	936
+			    Nested     	FALSE)
+			Focus_Of_Control 	(object Focus_Of_Control "" @344
+			    location   	(176, 352)
+			    line_color 	3342489
+			    InterObjView 	@342
+			    height     	60
+			    y_coord    	0
+			    Nested     	TRUE)
+			Focus_Of_Control 	(object Focus_Of_Control "" @345
+			    location   	(176, 448)
+			    line_color 	3342489
+			    InterObjView 	@342
+			    height     	60
+			    y_coord    	0
+			    Nested     	TRUE))
+		    (object InterObjView "Rule" @346
+			location   	(480, 224)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	TRUE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object ItemLabel
+			    Parent_View 	@346
+			    location   	(480, 224)
+			    fill_color 	13434879
+			    anchor_loc 	1
+			    nlines     	2
+			    max_width  	282
+			    justify    	0
+			    label      	"Rule")
+			icon_style 	"Icon"
+			line_color 	3342489
+			fill_color 	13434879
+			quidu      	"3DFE0E7400D0"
+			width      	300
+			height     	1214
+			icon_height 	0
+			icon_width 	0
+			icon_y_offset 	0
+			annotation 	1
+			Focus_Of_Control 	(object Focus_Of_Control "" @347
+			    location   	(480, 560)
+			    line_color 	3342489
+			    InterObjView 	@346
+			    height     	728
+			    y_coord    	668
+			    Nested     	FALSE))
+		    (object InterObjView "StandardContext" @348
+			location   	(816, 224)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	TRUE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object ItemLabel
+			    Parent_View 	@348
+			    location   	(816, 224)
+			    fill_color 	13434879
+			    anchor_loc 	1
+			    nlines     	2
+			    max_width  	332
+			    justify    	0
+			    label      	"StandardContext")
+			icon_style 	"Icon"
+			line_color 	3342489
+			fill_color 	13434879
+			quidu      	"3DFE0FC502A1"
+			width      	350
+			height     	1214
+			icon_height 	0
+			icon_width 	0
+			icon_y_offset 	0
+			annotation 	1
+			Focus_Of_Control 	(object Focus_Of_Control "" @349
+			    location   	(816, 592)
+			    line_color 	3342489
+			    InterObjView 	@348
+			    height     	264
+			    y_coord    	204
+			    Nested     	FALSE)
+			Focus_Of_Control 	(object Focus_Of_Control "" @350
+			    location   	(816, 1008)
+			    line_color 	3342489
+			    InterObjView 	@348
+			    height     	60
+			    y_coord    	0
+			    Nested     	FALSE))
+		    (object InterObjView "StandardPipeline" @351
+			location   	(1184, 224)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	TRUE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object ItemLabel
+			    Parent_View 	@351
+			    location   	(1184, 224)
+			    fill_color 	13434879
+			    anchor_loc 	1
+			    nlines     	2
+			    max_width  	363
+			    justify    	0
+			    label      	"StandardPipeline")
+			icon_style 	"Icon"
+			line_color 	3342489
+			fill_color 	13434879
+			quidu      	"3DFE112F003F"
+			width      	381
+			height     	1214
+			icon_height 	0
+			icon_width 	0
+			icon_y_offset 	0
+			annotation 	1
+			Focus_Of_Control 	(object Focus_Of_Control "" @352
+			    location   	(1184, 736)
+			    line_color 	3342489
+			    InterObjView 	@351
+			    height     	60
+			    y_coord    	0
+			    Nested     	FALSE))
+		    (object InterObjView "StandardContextValve" @353
+			location   	(1552, 224)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	TRUE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object ItemLabel
+			    Parent_View 	@353
+			    location   	(1552, 224)
+			    fill_color 	13434879
+			    anchor_loc 	1
+			    nlines     	2
+			    max_width  	300
+			    justify    	0
+			    label      	"StandardContextValve")
+			icon_style 	"Icon"
+			line_color 	3342489
+			fill_color 	13434879
+			quidu      	"3DFE110D0375"
+			width      	318
+			height     	1214
+			icon_height 	0
+			icon_width 	0
+			icon_y_offset 	0
+			annotation 	1
+			Focus_Of_Control 	(object Focus_Of_Control "" @354
+			    location   	(1552, 624)
+			    line_color 	3342489
+			    InterObjView 	@353
+			    height     	60
+			    y_coord    	0
+			    Nested     	FALSE))
+		    (object InterObjView "SetPropertiesRule" @355
+			location   	(1920, 224)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	TRUE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object ItemLabel
+			    Parent_View 	@355
+			    location   	(1920, 224)
+			    fill_color 	13434879
+			    anchor_loc 	1
+			    nlines     	2
+			    max_width  	363
+			    justify    	0
+			    label      	"SetPropertiesRule")
+			icon_style 	"Icon"
+			line_color 	3342489
+			fill_color 	13434879
+			quidu      	"3DFE100303A4"
+			width      	381
+			height     	1214
+			icon_height 	0
+			icon_width 	0
+			icon_y_offset 	0
+			annotation 	1
+			Focus_Of_Control 	(object Focus_Of_Control "" @356
+			    location   	(1920, 928)
+			    line_color 	3342489
+			    InterObjView 	@355
+			    height     	200
+			    y_coord    	140
+			    Nested     	FALSE))
+		    (object InterObjView "SetNextRule" @357
+			location   	(2272, 224)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	TRUE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object ItemLabel
+			    Parent_View 	@357
+			    location   	(2272, 224)
+			    fill_color 	13434879
+			    anchor_loc 	1
+			    nlines     	2
+			    max_width  	282
+			    justify    	0
+			    label      	"SetNextRule")
+			icon_style 	"Icon"
+			line_color 	3342489
+			fill_color 	13434879
+			quidu      	"3DFE12690267"
+			width      	300
+			height     	1214
+			icon_height 	0
+			icon_width 	0
+			icon_y_offset 	0
+			annotation 	1
+			Focus_Of_Control 	(object Focus_Of_Control "" @358
+			    location   	(2272, 1168)
+			    line_color 	3342489
+			    InterObjView 	@357
+			    height     	60
+			    y_coord    	0
+			    Nested     	FALSE))
+		    (object SelfMessView "" @359
+			location   	(0, 352)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	FALSE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object SegLabel @360
+			    Parent_View 	@359
+			    location   	(267, 308)
+			    font       	(object Font
+				size       	10
+				face       	"Arial"
+				bold       	FALSE
+				italics    	FALSE
+				underline  	FALSE
+				strike     	FALSE
+				color      	0
+				default_color 	TRUE)
+			    quidu      	"3DFE0E7801DB"
+			    anchor_loc 	1
+			    nlines     	1
+			    max_width  	108
+			    justify    	0
+			    label      	"parse"
+			    pctDist    	0.500000
+			    height     	45
+			    orientation 	0)
+			line_color 	3342489
+			client     	@342
+			supplier   	@342
+			Focus_Src  	@343
+			Focus_Entry 	@344
+			origin     	(192, 352)
+			terminus   	(342, 352)
+			ordinal    	0)
+		    (object SelfMessView "" @361
+			location   	(16, 448)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	FALSE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object SegLabel @362
+			    Parent_View 	@361
+			    location   	(345, 420)
+			    font       	(object Font
+				size       	10
+				face       	"Arial"
+				bold       	FALSE
+				italics    	FALSE
+				underline  	FALSE
+				strike     	FALSE
+				color      	0
+				default_color 	TRUE)
+			    quidu      	"3DFE0F2F03D2"
+			    anchor_loc 	1
+			    nlines     	1
+			    max_width  	267
+			    justify    	0
+			    label      	"startElement()"
+			    pctDist    	1.020000
+			    height     	28
+			    orientation 	0)
+			line_color 	3342489
+			client     	@342
+			supplier   	@342
+			Focus_Src  	@343
+			Focus_Entry 	@345
+			origin     	(192, 448)
+			terminus   	(342, 448)
+			ordinal    	1)
+		    (object InterMessView "" @363
+			location   	(336, 560)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	FALSE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object SegLabel @364
+			    Parent_View 	@363
+			    location   	(327, 516)
+			    font       	(object Font
+				size       	10
+				face       	"Arial"
+				bold       	FALSE
+				italics    	FALSE
+				underline  	FALSE
+				strike     	FALSE
+				color      	0
+				default_color 	TRUE)
+			    quidu      	"3DFE0F400214"
+			    anchor_loc 	1
+			    nlines     	1
+			    max_width  	132
+			    justify    	0
+			    label      	"begin()"
+			    pctDist    	0.500000
+			    height     	45
+			    orientation 	0)
+			line_color 	3342489
+			client     	@342
+			supplier   	@346
+			Focus_Src  	@343
+			Focus_Entry 	@347
+			origin     	(191, 560)
+			terminus   	(464, 560)
+			ordinal    	2)
+		    (object InterMessView "" @365
+			location   	(16, 592)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	FALSE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object SegLabel @366
+			    Parent_View 	@365
+			    location   	(647, 548)
+			    font       	(object Font
+				size       	10
+				face       	"Arial"
+				bold       	FALSE
+				italics    	FALSE
+				underline  	FALSE
+				strike     	FALSE
+				color      	0
+				default_color 	TRUE)
+			    quidu      	"3DFE0FD30266"
+			    anchor_loc 	1
+			    nlines     	1
+			    max_width  	265
+			    justify    	0
+			    label      	"newInstance()"
+			    pctDist    	0.500000
+			    height     	45
+			    orientation 	0)
+			line_color 	3342489
+			client     	@346
+			supplier   	@348
+			Focus_Src  	@347
+			Focus_Entry 	@349
+			origin     	(495, 592)
+			terminus   	(800, 592)
+			ordinal    	3)
+		    (object InterMessView "" @367
+			location   	(864, 928)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	FALSE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object SegLabel @368
+			    Parent_View 	@367
+			    location   	(1199, 884)
+			    font       	(object Font
+				size       	10
+				face       	"Arial"
+				bold       	FALSE
+				italics    	FALSE
+				underline  	FALSE
+				strike     	FALSE
+				color      	0
+				default_color 	TRUE)
+			    quidu      	"3DFE102002E9"
+			    anchor_loc 	1
+			    nlines     	1
+			    max_width  	132
+			    justify    	0
+			    label      	"begin()"
+			    pctDist    	0.500000
+			    height     	45
+			    orientation 	0)
+			line_color 	3342489
+			client     	@346
+			supplier   	@355
+			Focus_Src  	@347
+			Focus_Entry 	@356
+			origin     	(495, 928)
+			terminus   	(1904, 928)
+			ordinal    	6)
+		    (object InterMessView "" @369
+			location   	(1008, 736)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	FALSE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object SegLabel @370
+			    Parent_View 	@369
+			    location   	(1139, 693)
+			    font       	(object Font
+				size       	10
+				face       	"Arial"
+				bold       	FALSE
+				italics    	FALSE
+				underline  	FALSE
+				strike     	FALSE
+				color      	0
+				default_color 	TRUE)
+			    quidu      	"3DFE114A0193"
+			    anchor_loc 	1
+			    nlines     	1
+			    max_width  	610
+			    justify    	0
+			    label      	"setBasic(StandardContextValve)"
+			    pctDist    	0.915014
+			    height     	44
+			    orientation 	0)
+			line_color 	3342489
+			client     	@348
+			supplier   	@351
+			Focus_Src  	@349
+			Focus_Entry 	@352
+			origin     	(831, 736)
+			terminus   	(1168, 736)
+			ordinal    	5)
+		    (object InterMessView "" @371
+			location   	(16, 624)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	FALSE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object SegLabel @372
+			    Parent_View 	@371
+			    location   	(1183, 580)
+			    font       	(object Font
+				size       	10
+				face       	"Arial"
+				bold       	FALSE
+				italics    	FALSE
+				underline  	FALSE
+				strike     	FALSE
+				color      	0
+				default_color 	TRUE)
+			    quidu      	"3DFE115E001F"
+			    anchor_loc 	1
+			    nlines     	1
+			    max_width  	106
+			    justify    	0
+			    label      	"new()"
+			    pctDist    	0.500000
+			    height     	45
+			    orientation 	0)
+			line_color 	3342489
+			client     	@348
+			supplier   	@353
+			Focus_Src  	@349
+			Focus_Entry 	@354
+			origin     	(831, 624)
+			terminus   	(1536, 624)
+			ordinal    	4)
+		    (object InterMessView "" @373
+			location   	(1440, 1008)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	FALSE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object SegLabel @374
+			    Parent_View 	@373
+			    location   	(1368, 964)
+			    font       	(object Font
+				size       	10
+				face       	"Arial"
+				bold       	FALSE
+				italics    	FALSE
+				underline  	FALSE
+				strike     	FALSE
+				color      	0
+				default_color 	TRUE)
+			    quidu      	"3DFE11D50391"
+			    anchor_loc 	1
+			    nlines     	1
+			    max_width  	1190
+			    justify    	0
+			    label      	"//Using BeanUtil, set the object properties (from ex: admin.xml)"
+			    pctDist    	0.500000
+			    height     	45
+			    orientation 	1)
+			line_color 	3342489
+			client     	@355
+			supplier   	@348
+			Focus_Src  	@356
+			Focus_Entry 	@350
+			origin     	(1904, 1008)
+			terminus   	(832, 1008)
+			ordinal    	7)
+		    (object InterMessView "" @375
+			location   	(1392, 1168)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	FALSE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object SegLabel @376
+			    Parent_View 	@375
+			    location   	(1375, 1124)
+			    font       	(object Font
+				size       	10
+				face       	"Arial"
+				bold       	FALSE
+				italics    	FALSE
+				underline  	FALSE
+				strike     	FALSE
+				color      	0
+				default_color 	TRUE)
+			    quidu      	"3DFE128501C8"
+			    anchor_loc 	1
+			    nlines     	1
+			    max_width  	99
+			    justify    	0
+			    label      	"end()"
+			    pctDist    	0.500000
+			    height     	45
+			    orientation 	0)
+			line_color 	3342489
+			client     	@346
+			supplier   	@357
+			Focus_Src  	@347
+			Focus_Entry 	@358
+			origin     	(495, 1168)
+			terminus   	(2256, 1168)
+			ordinal    	8)
+		    (object NoteView @377
+			location   	(1216, 80)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	FALSE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object ItemLabel
+			    Parent_View 	@377
+			    location   	(900, 15)
+			    fill_color 	13434879
+			    nlines     	2
+			    max_width  	596
+			    label      	"HostConfig.deployDescriptor()")
+			line_color 	3342489
+			fill_color 	13434879
+			width      	656
+			height     	143)
+		    (object NoteView @378
+			location   	(2128, 1888)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	FALSE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object ItemLabel
+			    Parent_View 	@378
+			    location   	(1947, 1822)
+			    fill_color 	13434879
+			    nlines     	2
+			    max_width  	327
+			    label      	"#3 Catalina.start()")
+			line_color 	3342489
+			fill_color 	13434879
+			width      	387
+			height     	144)))
+	    (object InteractionDiagram "6. catalina_start_4"
+		mechanism_ref 	@87
+		quid       	"3DFE13890008"
+		title      	"6. catalina_start_4"
+		zoom       	100
+		max_height 	28350
+		max_width  	21600
+		origin_x   	0
+		origin_y   	1818
+		items      	(list diagram_item_list
+		    (object InterObjView "Digester" @379
+			location   	(176, 224)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	TRUE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object ItemLabel
+			    Parent_View 	@379
+			    location   	(176, 224)
+			    fill_color 	13434879
+			    anchor_loc 	1
+			    nlines     	2
+			    max_width  	282
+			    justify    	0
+			    label      	"Digester")
+			icon_style 	"Icon"
+			line_color 	3342489
+			fill_color 	13434879
+			quidu      	"3DFE13960364"
+			width      	300
+			height     	2446
+			icon_height 	0
+			icon_width 	0
+			icon_y_offset 	0
+			annotation 	1
+			Focus_Of_Control 	(object Focus_Of_Control "" @380
+			    location   	(176, 336)
+			    line_color 	3342489
+			    InterObjView 	@379
+			    height     	1228
+			    y_coord    	1168
+			    Nested     	FALSE)
+			Focus_Of_Control 	(object Focus_Of_Control "" @381
+			    location   	(176, 336)
+			    line_color 	3342489
+			    InterObjView 	@379
+			    height     	60
+			    y_coord    	0
+			    Nested     	TRUE)
+			Focus_Of_Control 	(object Focus_Of_Control "" @382
+			    location   	(176, 480)
+			    line_color 	3342489
+			    InterObjView 	@379
+			    height     	60
+			    y_coord    	0
+			    Nested     	TRUE)
+			Focus_Of_Control 	(object Focus_Of_Control "" @383
+			    location   	(176, 1616)
+			    line_color 	3342489
+			    InterObjView 	@379
+			    height     	580
+			    y_coord    	520
+			    Nested     	FALSE)
+			Focus_Of_Control 	(object Focus_Of_Control "" @384
+			    location   	(176, 1728)
+			    line_color 	3342489
+			    InterObjView 	@379
+			    height     	60
+			    y_coord    	0
+			    Nested     	TRUE))
+		    (object InterObjView "StandardHostDeployer" @385
+			location   	(480, 224)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	TRUE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object ItemLabel
+			    Parent_View 	@385
+			    location   	(480, 224)
+			    fill_color 	13434879
+			    anchor_loc 	1
+			    nlines     	2
+			    max_width  	301
+			    justify    	0
+			    label      	"StandardHostDeployer")
+			icon_style 	"Icon"
+			line_color 	3342489
+			fill_color 	13434879
+			quidu      	"3DFE1D8A02DC"
+			width      	319
+			height     	2446
+			icon_height 	0
+			icon_width 	0
+			icon_y_offset 	0
+			annotation 	1
+			Focus_Of_Control 	(object Focus_Of_Control "" @386
+			    location   	(480, 576)
+			    line_color 	3342489
+			    InterObjView 	@385
+			    height     	928
+			    y_coord    	868
+			    Nested     	FALSE))
+		    (object InterObjView "StandardHost" @387
+			location   	(800, 224)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	TRUE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object ItemLabel
+			    Parent_View 	@387
+			    location   	(800, 224)
+			    fill_color 	13434879
+			    anchor_loc 	1
+			    nlines     	2
+			    max_width  	282
+			    justify    	0
+			    label      	"StandardHost")
+			icon_style 	"Icon"
+			line_color 	3342489
+			fill_color 	13434879
+			quidu      	"3DFE1DF20141"
+			width      	300
+			height     	2446
+			icon_height 	0
+			icon_width 	0
+			icon_y_offset 	0
+			annotation 	1
+			Focus_Of_Control 	(object Focus_Of_Control "" @388
+			    location   	(800, 592)
+			    line_color 	3342489
+			    InterObjView 	@387
+			    height     	852
+			    y_coord    	792
+			    Nested     	FALSE))
+		    (object InterObjView "StandardContext" @389
+			location   	(1120, 224)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	TRUE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object ItemLabel
+			    Parent_View 	@389
+			    location   	(1120, 224)
+			    fill_color 	13434879
+			    anchor_loc 	1
+			    nlines     	2
+			    max_width  	295
+			    justify    	0
+			    label      	"StandardContext")
+			icon_style 	"Icon"
+			line_color 	3342489
+			fill_color 	13434879
+			quidu      	"3DFE196D00D9"
+			width      	313
+			height     	2446
+			icon_height 	0
+			icon_width 	0
+			icon_y_offset 	0
+			annotation 	1
+			Focus_Of_Control 	(object Focus_Of_Control "" @390
+			    location   	(1120, 624)
+			    line_color 	3342489
+			    InterObjView 	@389
+			    height     	760
+			    y_coord    	700
+			    Nested     	FALSE)
+			Focus_Of_Control 	(object Focus_Of_Control "" @391
+			    location   	(1120, 800)
+			    line_color 	3342489
+			    InterObjView 	@389
+			    height     	60
+			    y_coord    	0
+			    Nested     	TRUE)
+			Focus_Of_Control 	(object Focus_Of_Control "" @392
+			    location   	(1120, 976)
+			    line_color 	3342489
+			    InterObjView 	@389
+			    height     	60
+			    y_coord    	0
+			    Nested     	TRUE)
+			Focus_Of_Control 	(object Focus_Of_Control "" @393
+			    location   	(1120, 1072)
+			    line_color 	3342489
+			    InterObjView 	@389
+			    height     	60
+			    y_coord    	0
+			    Nested     	TRUE))
+		    (object InterObjView "WebappLoader" @394
+			location   	(1440, 224)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	TRUE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object ItemLabel
+			    Parent_View 	@394
+			    location   	(1440, 224)
+			    fill_color 	13434879
+			    anchor_loc 	1
+			    nlines     	2
+			    max_width  	295
+			    justify    	0
+			    label      	"WebappLoader")
+			icon_style 	"Icon"
+			line_color 	3342489
+			fill_color 	13434879
+			quidu      	"3DFE1FFA0347"
+			width      	313
+			height     	2446
+			icon_height 	0
+			icon_width 	0
+			icon_y_offset 	0
+			annotation 	1
+			Focus_Of_Control 	(object Focus_Of_Control "" @395
+			    location   	(1440, 640)
+			    line_color 	3342489
+			    InterObjView 	@394
+			    height     	60
+			    y_coord    	0
+			    Nested     	FALSE))
+		    (object InterObjView "StandardManager" @396
+			location   	(1760, 224)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	TRUE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object ItemLabel
+			    Parent_View 	@396
+			    location   	(1760, 224)
+			    fill_color 	13434879
+			    anchor_loc 	1
+			    nlines     	2
+			    max_width  	301
+			    justify    	0
+			    label      	"StandardManager")
+			icon_style 	"Icon"
+			line_color 	3342489
+			fill_color 	13434879
+			quidu      	"3DFE201F0105"
+			width      	319
+			height     	2446
+			icon_height 	0
+			icon_width 	0
+			icon_y_offset 	0
+			annotation 	1
+			Focus_Of_Control 	(object Focus_Of_Control "" @397
+			    location   	(1760, 832)
+			    line_color 	3342489
+			    InterObjView 	@396
+			    height     	60
+			    y_coord    	0
+			    Nested     	FALSE)
+			Focus_Of_Control 	(object Focus_Of_Control "" @398
+			    location   	(1760, 1264)
+			    line_color 	3342489
+			    InterObjView 	@396
+			    height     	60
+			    y_coord    	0
+			    Nested     	FALSE))
+		    (object InterObjView "ContextConfig" @399
+			location   	(1952, 352)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	TRUE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object ItemLabel
+			    Parent_View 	@399
+			    location   	(1952, 352)
+			    fill_color 	13434879
+			    anchor_loc 	1
+			    nlines     	2
+			    max_width  	282
+			    justify    	0
+			    label      	"ContextConfig")
+			icon_style 	"Icon"
+			line_color 	3342489
+			fill_color 	13434879
+			quidu      	"3DFE2087028C"
+			width      	300
+			height     	2318
+			icon_height 	0
+			icon_width 	0
+			icon_y_offset 	0
+			annotation 	1
+			Focus_Of_Control 	(object Focus_Of_Control "" @400
+			    location   	(1952, 412)
+			    InterObjView 	@399
+			    height     	60
+			    y_coord    	0
+			    Nested     	FALSE)
+			Focus_Of_Control 	(object Focus_Of_Control "" @401
+			    location   	(1952, 1136)
+			    line_color 	3342489
+			    InterObjView 	@399
+			    height     	1444
+			    y_coord    	1384
+			    Nested     	FALSE)
+			Focus_Of_Control 	(object Focus_Of_Control "" @402
+			    location   	(1952, 1264)
+			    line_color 	3342489
+			    InterObjView 	@399
+			    height     	60
+			    y_coord    	0
+			    Nested     	TRUE)
+			Focus_Of_Control 	(object Focus_Of_Control "" @403
+			    location   	(1952, 1456)
+			    line_color 	3342489
+			    InterObjView 	@399
+			    height     	1070
+			    y_coord    	1010
+			    Nested     	TRUE)
+			Focus_Of_Control 	(object Focus_Of_Control "" @404
+			    location   	(1952, 1568)
+			    line_color 	3342489
+			    InterObjView 	@399
+			    height     	952
+			    y_coord    	892
+			    Nested     	TRUE)
+			Focus_Of_Control 	(object Focus_Of_Control "" @405
+			    location   	(1952, 1984)
+			    line_color 	3342489
+			    InterObjView 	@399
+			    height     	152
+			    y_coord    	92
+			    Nested     	TRUE))
+		    (object SelfMessView "" @406
+			location   	(16, 336)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	FALSE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object SegLabel @407
+			    Parent_View 	@406
+			    location   	(267, 292)
+			    font       	(object Font
+				size       	10
+				face       	"Arial"
+				bold       	FALSE
+				italics    	FALSE
+				underline  	FALSE
+				strike     	FALSE
+				color      	0
+				default_color 	TRUE)
+			    quidu      	"3DFE19AE0065"
+			    anchor_loc 	1
+			    nlines     	1
+			    max_width  	108
+			    justify    	0
+			    label      	"parse"
+			    pctDist    	0.500000
+			    height     	45
+			    orientation 	0)
+			line_color 	3342489
+			client     	@379
+			supplier   	@379
+			Focus_Src  	@380
+			Focus_Entry 	@381
+			origin     	(192, 336)
+			terminus   	(342, 336)
+			ordinal    	0)
+		    (object SelfMessView "" @408
+			location   	(16, 480)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	FALSE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object SegLabel @409
+			    Parent_View 	@408
+			    location   	(328, 437)
+			    font       	(object Font
+				size       	10
+				face       	"Arial"
+				bold       	FALSE
+				italics    	FALSE
+				underline  	FALSE
+				strike     	FALSE
+				color      	0
+				default_color 	TRUE)
+			    quidu      	"3DFE19B102E9"
+			    anchor_loc 	1
+			    nlines     	1
+			    max_width  	267
+			    justify    	0
+			    label      	"startElement()"
+			    pctDist    	0.906667
+			    height     	44
+			    orientation 	0)
+			line_color 	3342489
+			client     	@379
+			supplier   	@379
+			Focus_Src  	@380
+			Focus_Entry 	@382
+			origin     	(192, 480)
+			terminus   	(342, 480)
+			ordinal    	1)
+		    (object InterMessView "" @410
+			location   	(16, 576)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	FALSE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object SegLabel @411
+			    Parent_View 	@410
+			    location   	(327, 552)
+			    font       	(object Font
+				size       	10
+				face       	"Arial"
+				bold       	FALSE
+				italics    	FALSE
+				underline  	FALSE
+				strike     	FALSE
+				color      	0
+				default_color 	TRUE)
+			    quidu      	"3DFE1DFB0022"
+			    anchor_loc 	1
+			    nlines     	1
+			    max_width  	165
+			    justify    	0
+			    label      	"addChild"
+			    pctDist    	0.498645
+			    height     	25
+			    orientation 	0)
+			line_color 	3342489
+			client     	@379
+			supplier   	@385
+			Focus_Src  	@380
+			Focus_Entry 	@386
+			origin     	(191, 576)
+			terminus   	(464, 576)
+			ordinal    	2)
+		    (object InterMessView "" @412
+			location   	(16, 592)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	FALSE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object SegLabel @413
+			    Parent_View 	@412
+			    location   	(639, 548)
+			    font       	(object Font
+				size       	10
+				face       	"Arial"
+				bold       	FALSE
+				italics    	FALSE
+				underline  	FALSE
+				strike     	FALSE
+				color      	0
+				default_color 	TRUE)
+			    quidu      	"3DFE1FB60277"
+			    anchor_loc 	1
+			    nlines     	1
+			    max_width  	165
+			    justify    	0
+			    label      	"addChild"
+			    pctDist    	0.500000
+			    height     	45
+			    orientation 	0)
+			line_color 	3342489
+			client     	@385
+			supplier   	@387
+			Focus_Src  	@386
+			Focus_Entry 	@388
+			origin     	(495, 592)
+			terminus   	(784, 592)
+			ordinal    	3)
+		    (object InterMessView "" @414
+			location   	(16, 624)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	FALSE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object SegLabel @415
+			    Parent_View 	@414
+			    location   	(959, 580)
+			    font       	(object Font
+				size       	10
+				face       	"Arial"
+				bold       	FALSE
+				italics    	FALSE
+				underline  	FALSE
+				strike     	FALSE
+				color      	0
+				default_color 	TRUE)
+			    quidu      	"3DFE1FC40228"
+			    anchor_loc 	1
+			    nlines     	1
+			    max_width  	110
+			    justify    	0
+			    label      	"start()"
+			    pctDist    	0.500000
+			    height     	45
+			    orientation 	0)
+			line_color 	3342489
+			client     	@387
+			supplier   	@389
+			Focus_Src  	@388
+			Focus_Entry 	@390
+			origin     	(815, 624)
+			terminus   	(1104, 624)
+			ordinal    	4)
+		    (object InterMessView "" @416
+			location   	(16, 640)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	FALSE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object SegLabel @417
+			    Parent_View 	@416
+			    location   	(1279, 596)
+			    font       	(object Font
+				size       	10
+				face       	"Arial"
+				bold       	FALSE
+				italics    	FALSE
+				underline  	FALSE
+				strike     	FALSE
+				color      	0
+				default_color 	TRUE)
+			    quidu      	"3DFE200603BE"
+			    anchor_loc 	1
+			    nlines     	1
+			    max_width  	82
+			    justify    	0
+			    label      	"new"
+			    pctDist    	0.500000
+			    height     	45
+			    orientation 	0)
+			line_color 	3342489
+			client     	@389
+			supplier   	@394
+			Focus_Src  	@390
+			Focus_Entry 	@395
+			origin     	(1135, 640)
+			terminus   	(1424, 640)
+			ordinal    	5)
+		    (object SelfMessView "" @418
+			location   	(16, 800)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	FALSE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object SegLabel @419
+			    Parent_View 	@418
+			    location   	(1224, 756)
+			    font       	(object Font
+				size       	10
+				face       	"Arial"
+				bold       	FALSE
+				italics    	FALSE
+				underline  	FALSE
+				strike     	FALSE
+				color      	0
+				default_color 	TRUE)
+			    quidu      	"3DFE200C029A"
+			    anchor_loc 	1
+			    nlines     	1
+			    max_width  	186
+			    justify    	0
+			    label      	"setLoader"
+			    pctDist    	0.593333
+			    height     	45
+			    orientation 	0)
+			line_color 	3342489
+			client     	@389
+			supplier   	@389
+			Focus_Src  	@390
+			Focus_Entry 	@391
+			origin     	(1136, 800)
+			terminus   	(1286, 800)
+			ordinal    	6)
+		    (object InterMessView "" @420
+			location   	(16, 832)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	FALSE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object SegLabel @421
+			    Parent_View 	@420
+			    location   	(1439, 788)
+			    font       	(object Font
+				size       	10
+				face       	"Arial"
+				bold       	FALSE
+				italics    	FALSE
+				underline  	FALSE
+				strike     	FALSE
+				color      	0
+				default_color 	TRUE)
+			    quidu      	"3DFE202C0250"
+			    anchor_loc 	1
+			    nlines     	1
+			    max_width  	82
+			    justify    	0
+			    label      	"new"
+			    pctDist    	0.500000
+			    height     	45
+			    orientation 	0)
+			line_color 	3342489
+			client     	@389
+			supplier   	@396
+			Focus_Src  	@390
+			Focus_Entry 	@397
+			origin     	(1135, 832)
+			terminus   	(1744, 832)
+			ordinal    	7)
+		    (object SelfMessView "" @422
+			location   	(16, 976)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	FALSE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object SegLabel @423
+			    Parent_View 	@422
+			    location   	(1260, 933)
+			    font       	(object Font
+				size       	10
+				face       	"Arial"
+				bold       	FALSE
+				italics    	FALSE
+				underline  	FALSE
+				strike     	FALSE
+				color      	0
+				default_color 	TRUE)
+			    quidu      	"3DFE2032001C"
+			    anchor_loc 	1
+			    nlines     	1
+			    max_width  	221
+			    justify    	0
+			    label      	"setManager"
+			    pctDist    	0.833333
+			    height     	44
+			    orientation 	0)
+			line_color 	3342489
+			client     	@389
+			supplier   	@389
+			Focus_Src  	@390
+			Focus_Entry 	@392
+			origin     	(1136, 976)
+			terminus   	(1286, 976)
+			ordinal    	8)
+		    (object SelfMessView "" @424
+			location   	(16, 1072)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	FALSE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object SegLabel @425
+			    Parent_View 	@424
+			    location   	(1481, 1043)
+			    font       	(object Font
+				size       	10
+				face       	"Arial"
+				bold       	FALSE
+				italics    	FALSE
+				underline  	FALSE
+				strike     	FALSE
+				color      	0
+				default_color 	TRUE)
+			    quidu      	"3DFE205B01A2"
+			    anchor_loc 	1
+			    nlines     	1
+			    max_width  	658
+			    justify    	0
+			    label      	"fireLifecycleEvent(START_EVENT)"
+			    pctDist    	2.306667
+			    height     	30
+			    orientation 	0)
+			line_color 	3342489
+			client     	@389
+			supplier   	@389
+			Focus_Src  	@390
+			Focus_Entry 	@393
+			origin     	(1136, 1072)
+			terminus   	(1286, 1072)
+			ordinal    	9)
+		    (object InterMessView "" @426
+			location   	(16, 1136)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	FALSE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object SegLabel @427
+			    Parent_View 	@426
+			    location   	(1535, 1092)
+			    font       	(object Font
+				size       	10
+				face       	"Arial"
+				bold       	FALSE
+				italics    	FALSE
+				underline  	FALSE
+				strike     	FALSE
+				color      	0
+				default_color 	TRUE)
+			    quidu      	"3DFE20960003"
+			    anchor_loc 	1
+			    nlines     	1
+			    max_width  	745
+			    justify    	0
+			    label      	" // Notify interested LifecycleListeners"
+			    pctDist    	0.500000
+			    height     	45
+			    orientation 	0)
+			line_color 	3342489
+			client     	@389
+			supplier   	@399
+			Focus_Src  	@390
+			Focus_Entry 	@401
+			origin     	(1135, 1136)
+			terminus   	(1936, 1136)
+			ordinal    	10)
+		    (object SelfMessView "" @428
+			location   	(16, 1264)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	FALSE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object SegLabel @429
+			    Parent_View 	@428
+			    location   	(2043, 1220)
+			    font       	(object Font
+				size       	10
+				face       	"Arial"
+				bold       	FALSE
+				italics    	FALSE
+				underline  	FALSE
+				strike     	FALSE
+				color      	0
+				default_color 	TRUE)
+			    quidu      	"3DFE20CF018C"
+			    anchor_loc 	1
+			    nlines     	1
+			    max_width  	110
+			    justify    	0
+			    label      	"start()"
+			    pctDist    	0.500000
+			    height     	45
+			    orientation 	0)
+			line_color 	3342489
+			client     	@399
+			supplier   	@399
+			Focus_Src  	@401
+			Focus_Entry 	@402
+			origin     	(1968, 1264)
+			terminus   	(2118, 1264)
+			ordinal    	11)
+		    (object SelfMessView "" @430
+			location   	(16, 1456)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	FALSE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object SegLabel @431
+			    Parent_View 	@430
+			    location   	(2027, 1413)
+			    font       	(object Font
+				size       	10
+				face       	"Arial"
+				bold       	FALSE
+				italics    	FALSE
+				underline  	FALSE
+				strike     	FALSE
+				color      	0
+				default_color 	TRUE)
+			    quidu      	"3DFE20E303E2"
+			    anchor_loc 	1
+			    nlines     	1
+			    max_width  	275
+			    justify    	0
+			    label      	"defaultConfig()"
+			    pctDist    	0.393333
+			    height     	44
+			    orientation 	0)
+			line_color 	3342489
+			client     	@399
+			supplier   	@399
+			Focus_Src  	@401
+			Focus_Entry 	@403
+			origin     	(1968, 1456)
+			terminus   	(2118, 1456)
+			ordinal    	13)
+		    (object SelfMessView "" @432
+			location   	(16, 1568)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	FALSE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object SegLabel @433
+			    Parent_View 	@432
+			    location   	(2043, 1524)
+			    font       	(object Font
+				size       	10
+				face       	"Arial"
+				bold       	FALSE
+				italics    	FALSE
+				underline  	FALSE
+				strike     	FALSE
+				color      	0
+				default_color 	TRUE)
+			    quidu      	"3DFE211D01A1"
+			    anchor_loc 	1
+			    nlines     	1
+			    max_width  	349
+			    justify    	0
+			    label      	"applicationConfig()"
+			    pctDist    	0.500000
+			    height     	45
+			    orientation 	0)
+			line_color 	3342489
+			client     	@399
+			supplier   	@399
+			Focus_Src  	@401
+			Focus_Entry 	@404
+			origin     	(1968, 1568)
+			terminus   	(2118, 1568)
+			ordinal    	14)
+		    (object InterMessView "" @434
+			location   	(1664, 1264)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	FALSE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object SegLabel @435
+			    Parent_View 	@434
+			    location   	(1439, 1220)
+			    font       	(object Font
+				size       	10
+				face       	"Arial"
+				bold       	FALSE
+				italics    	FALSE
+				underline  	FALSE
+				strike     	FALSE
+				color      	0
+				default_color 	TRUE)
+			    quidu      	"3DFE20B600E5"
+			    anchor_loc 	1
+			    nlines     	1
+			    max_width  	110
+			    justify    	0
+			    label      	"start()"
+			    pctDist    	0.500000
+			    height     	45
+			    orientation 	0)
+			line_color 	3342489
+			client     	@389
+			supplier   	@396
+			Focus_Src  	@390
+			Focus_Entry 	@398
+			origin     	(1135, 1264)
+			terminus   	(1744, 1264)
+			ordinal    	12)
+		    (object InterMessView "" @436
+			location   	(16, 1616)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	FALSE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object SegLabel @437
+			    Parent_View 	@436
+			    location   	(1064, 1572)
+			    font       	(object Font
+				size       	10
+				face       	"Arial"
+				bold       	FALSE
+				italics    	FALSE
+				underline  	FALSE
+				strike     	FALSE
+				color      	0
+				default_color 	TRUE)
+			    quidu      	"3DFE21B60288"
+			    anchor_loc 	1
+			    nlines     	1
+			    max_width  	145
+			    justify    	0
+			    label      	"create()"
+			    pctDist    	0.500000
+			    height     	45
+			    orientation 	1)
+			line_color 	3342489
+			client     	@399
+			supplier   	@379
+			Focus_Src  	@404
+			Focus_Entry 	@383
+			origin     	(1936, 1616)
+			terminus   	(192, 1616)
+			ordinal    	15)
+		    (object SelfMessView "" @438
+			location   	(16, 1728)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	FALSE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object SegLabel @439
+			    Parent_View 	@438
+			    location   	(457, 1701)
+			    font       	(object Font
+				size       	10
+				face       	"Arial"
+				bold       	FALSE
+				italics    	FALSE
+				underline  	FALSE
+				strike     	FALSE
+				color      	0
+				default_color 	TRUE)
+			    quidu      	"3DFE21BE021B"
+			    anchor_loc 	1
+			    nlines     	1
+			    max_width  	530
+			    justify    	0
+			    label      	"// Process web.xml * tld.xml"
+			    pctDist    	1.773333
+			    height     	28
+			    orientation 	0)
+			line_color 	3342489
+			client     	@379
+			supplier   	@379
+			Focus_Src  	@383
+			Focus_Entry 	@384
+			origin     	(192, 1728)
+			terminus   	(342, 1728)
+			ordinal    	16)
+		    (object InterObjView "StandardWrapper" @440
+			location   	(2208, 224)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	TRUE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object ItemLabel
+			    Parent_View 	@440
+			    location   	(2208, 224)
+			    fill_color 	13434879
+			    anchor_loc 	1
+			    nlines     	2
+			    max_width  	282
+			    justify    	0
+			    label      	"StandardWrapper")
+			icon_style 	"Icon"
+			line_color 	3342489
+			fill_color 	13434879
+			quidu      	"3DFE220C0122"
+			width      	300
+			height     	2446
+			icon_height 	0
+			icon_width 	0
+			icon_y_offset 	0
+			annotation 	1
+			Focus_Of_Control 	(object Focus_Of_Control "" @441
+			    location   	(2208, 2016)
+			    line_color 	3342489
+			    InterObjView 	@440
+			    height     	60
+			    y_coord    	0
+			    Nested     	FALSE)
+			Focus_Of_Control 	(object Focus_Of_Control "" @442
+			    location   	(2208, 2176)
+			    line_color 	3342489
+			    InterObjView 	@440
+			    height     	60
+			    y_coord    	0
+			    Nested     	FALSE)
+			Focus_Of_Control 	(object Focus_Of_Control "" @443
+			    location   	(2208, 2288)
+			    line_color 	3342489
+			    InterObjView 	@440
+			    height     	60
+			    y_coord    	0
+			    Nested     	FALSE)
+			Focus_Of_Control 	(object Focus_Of_Control "" @444
+			    location   	(2208, 2400)
+			    line_color 	3342489
+			    InterObjView 	@440
+			    height     	60
+			    y_coord    	0
+			    Nested     	FALSE))
+		    (object InterMessView "" @445
+			location   	(16, 1984)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	FALSE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object SegLabel @446
+			    Parent_View 	@445
+			    location   	(1063, 1940)
+			    font       	(object Font
+				size       	10
+				face       	"Arial"
+				bold       	FALSE
+				italics    	FALSE
+				underline  	FALSE
+				strike     	FALSE
+				color      	0
+				default_color 	TRUE)
+			    quidu      	"3DFE228B03BA"
+			    anchor_loc 	1
+			    nlines     	1
+			    max_width  	1478
+			    justify    	0
+			    label      	"createWarpper() // Invoked by a WebWrapperRule (not Directly by the Digester)"
+			    pctDist    	0.500000
+			    height     	45
+			    orientation 	0)
+			line_color 	3342489
+			client     	@379
+			supplier   	@399
+			Focus_Src  	@383
+			Focus_Entry 	@405
+			origin     	(191, 1984)
+			terminus   	(1936, 1984)
+			ordinal    	17)
+		    (object InterMessView "" @447
+			location   	(16, 2016)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	FALSE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object SegLabel @448
+			    Parent_View 	@447
+			    location   	(2079, 1972)
+			    font       	(object Font
+				size       	10
+				face       	"Arial"
+				bold       	FALSE
+				italics    	FALSE
+				underline  	FALSE
+				strike     	FALSE
+				color      	0
+				default_color 	TRUE)
+			    quidu      	"3DFE229A0004"
+			    anchor_loc 	1
+			    nlines     	1
+			    max_width  	82
+			    justify    	0
+			    label      	"new"
+			    pctDist    	0.500000
+			    height     	45
+			    orientation 	0)
+			line_color 	3342489
+			client     	@399
+			supplier   	@440
+			Focus_Src  	@405
+			Focus_Entry 	@441
+			origin     	(1967, 2016)
+			terminus   	(2192, 2016)
+			ordinal    	18)
+		    (object InterMessView "" @449
+			location   	(16, 2176)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	FALSE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object SegLabel @450
+			    Parent_View 	@449
+			    location   	(2116, 2134)
+			    font       	(object Font
+				size       	10
+				face       	"Arial"
+				bold       	FALSE
+				italics    	FALSE
+				underline  	FALSE
+				strike     	FALSE
+				color      	0
+				default_color 	TRUE)
+			    quidu      	"3DFE22A700C1"
+			    anchor_loc 	1
+			    nlines     	1
+			    max_width  	405
+			    justify    	0
+			    label      	"addInstanceListener()"
+			    pctDist    	0.662295
+			    height     	43
+			    orientation 	0)
+			line_color 	3342489
+			client     	@399
+			supplier   	@440
+			Focus_Src  	@404
+			Focus_Entry 	@442
+			origin     	(1967, 2176)
+			terminus   	(2192, 2176)
+			ordinal    	19)
+		    (object InterMessView "" @451
+			location   	(2496, 2288)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	FALSE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object SegLabel @452
+			    Parent_View 	@451
+			    location   	(2116, 2245)
+			    font       	(object Font
+				size       	10
+				face       	"Arial"
+				bold       	FALSE
+				italics    	FALSE
+				underline  	FALSE
+				strike     	FALSE
+				color      	0
+				default_color 	TRUE)
+			    quidu      	"3DFE22C701CC"
+			    anchor_loc 	1
+			    nlines     	1
+			    max_width  	410
+			    justify    	0
+			    label      	"addLifecycleListener()"
+			    pctDist    	0.662295
+			    height     	44
+			    orientation 	0)
+			line_color 	3342489
+			client     	@399
+			supplier   	@440
+			Focus_Src  	@404
+			Focus_Entry 	@443
+			origin     	(1967, 2288)
+			terminus   	(2192, 2288)
+			ordinal    	20)
+		    (object InterMessView "" @453
+			location   	(16, 2400)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	FALSE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object SegLabel @454
+			    Parent_View 	@453
+			    location   	(2124, 2357)
+			    font       	(object Font
+				size       	10
+				face       	"Arial"
+				bold       	FALSE
+				italics    	FALSE
+				underline  	FALSE
+				strike     	FALSE
+				color      	0
+				default_color 	TRUE)
+			    quidu      	"3DFE22E80364"
+			    anchor_loc 	1
+			    nlines     	1
+			    max_width  	428
+			    justify    	0
+			    label      	"addContainerListener()"
+			    pctDist    	0.701639
+			    height     	44
+			    orientation 	0)
+			line_color 	3342489
+			client     	@399
+			supplier   	@440
+			Focus_Src  	@404
+			Focus_Entry 	@444
+			origin     	(1967, 2400)
+			terminus   	(2192, 2400)
+			ordinal    	21)
+		    (object NoteView @455
+			location   	(1216, 80)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	FALSE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object ItemLabel
+			    Parent_View 	@455
+			    location   	(825, 14)
+			    fill_color 	13434879
+			    nlines     	2
+			    max_width  	746
+			    label      	"Deploy App.")
+			line_color 	3342489
+			fill_color 	13434879
+			width      	806
+			height     	144)
+		    (object NoteView @456
+			location   	(2144, 2704)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	FALSE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object ItemLabel
+			    Parent_View 	@456
+			    location   	(1953, 2641)
+			    fill_color 	13434879
+			    nlines     	2
+			    max_width  	347
+			    label      	"#4 Catalina.start()")
+			line_color 	3342489
+			fill_color 	13434879
+			width      	407
+			height     	138)))
+	    (object InteractionDiagram "1. catalina_request"
+		mechanism_ref 	@88
+		quid       	"3DFE3B5001C3"
+		title      	"1. catalina_request"
+		zoom       	100
+		max_height 	28350
+		max_width  	21600
+		origin_x   	0
+		origin_y   	0
+		items      	(list diagram_item_list
+		    (object InterObjView "ThreadPool" @457
+			location   	(176, 224)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	TRUE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object ItemLabel
+			    Parent_View 	@457
+			    location   	(176, 224)
+			    fill_color 	13434879
+			    anchor_loc 	1
+			    nlines     	2
+			    max_width  	282
+			    justify    	0
+			    label      	"ThreadPool")
+			icon_style 	"Icon"
+			line_color 	3342489
+			fill_color 	13434879
+			quidu      	"3DFE402B02C5"
+			width      	300
+			height     	1276
+			icon_height 	0
+			icon_width 	0
+			icon_y_offset 	0
+			annotation 	1
+			Focus_Of_Control 	(object Focus_Of_Control "" @458
+			    location   	(176, 384)
+			    line_color 	3342489
+			    InterObjView 	@457
+			    height     	304
+			    y_coord    	244
+			    Nested     	FALSE))
+		    (object InterObjView "TcpWorkerThread" @459
+			location   	(512, 224)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	TRUE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object ItemLabel
+			    Parent_View 	@459
+			    location   	(512, 224)
+			    fill_color 	13434879
+			    anchor_loc 	1
+			    nlines     	2
+			    max_width  	332
+			    justify    	0
+			    label      	"TcpWorkerThread")
+			icon_style 	"Icon"
+			line_color 	3342489
+			fill_color 	13434879
+			quidu      	"3DFE403200F8"
+			width      	350
+			height     	1276
+			icon_height 	0
+			icon_width 	0
+			icon_y_offset 	0
+			annotation 	1
+			Focus_Of_Control 	(object Focus_Of_Control "" @460
+			    location   	(512, 384)
+			    line_color 	3342489
+			    InterObjView 	@459
+			    height     	244
+			    y_coord    	184
+			    Nested     	FALSE))
+		    (object InterObjView "Http11Protocol" @461
+			location   	(848, 224)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	TRUE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object ItemLabel
+			    Parent_View 	@461
+			    location   	(848, 224)
+			    fill_color 	13434879
+			    anchor_loc 	1
+			    nlines     	2
+			    max_width  	282
+			    justify    	0
+			    label      	"Http11Protocol")
+			icon_style 	"Icon"
+			line_color 	3342489
+			fill_color 	13434879
+			quidu      	"3DFE40750177"
+			width      	300
+			height     	1276
+			icon_height 	0
+			icon_width 	0
+			icon_y_offset 	0
+			annotation 	1
+			Focus_Of_Control 	(object Focus_Of_Control "" @462
+			    location   	(848, 400)
+			    line_color 	3342489
+			    InterObjView 	@461
+			    height     	168
+			    y_coord    	108
+			    Nested     	FALSE)
+			Focus_Of_Control 	(object Focus_Of_Control "" @463
+			    location   	(848, 448)
+			    line_color 	3342489
+			    InterObjView 	@461
+			    height     	60
+			    y_coord    	0
+			    Nested     	TRUE)
+			Focus_Of_Control 	(object Focus_Of_Control "" @464
+			    location   	(848, 592)
+			    line_color 	3342489
+			    InterObjView 	@461
+			    height     	120
+			    y_coord    	60
+			    Nested     	FALSE)
+			Focus_Of_Control 	(object Focus_Of_Control "" @465
+			    location   	(848, 592)
+			    line_color 	3342489
+			    InterObjView 	@461
+			    height     	60
+			    y_coord    	0
+			    Nested     	TRUE)
+			Focus_Of_Control 	(object Focus_Of_Control "" @466
+			    location   	(848, 736)
+			    line_color 	3342489
+			    InterObjView 	@461
+			    height     	674
+			    y_coord    	614
+			    Nested     	FALSE)
+			Focus_Of_Control 	(object Focus_Of_Control "" @467
+			    location   	(848, 736)
+			    line_color 	3342489
+			    InterObjView 	@461
+			    height     	60
+			    y_coord    	0
+			    Nested     	TRUE))
+		    (object InterObjView "CoyoteAdapter" @468
+			location   	(1168, 224)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	TRUE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object ItemLabel
+			    Parent_View 	@468
+			    location   	(1168, 224)
+			    fill_color 	13434879
+			    anchor_loc 	1
+			    nlines     	2
+			    max_width  	282
+			    justify    	0
+			    label      	"CoyoteAdapter")
+			icon_style 	"Icon"
+			line_color 	3342489
+			fill_color 	13434879
+			quidu      	"3DFE410600DF"
+			width      	300
+			height     	1276
+			icon_height 	0
+			icon_width 	0
+			icon_y_offset 	0
+			annotation 	1
+			Focus_Of_Control 	(object Focus_Of_Control "" @469
+			    location   	(1168, 848)
+			    line_color 	3342489
+			    InterObjView 	@468
+			    height     	502
+			    y_coord    	442
+			    Nested     	FALSE)
+			Focus_Of_Control 	(object Focus_Of_Control "" @470
+			    location   	(1168, 944)
+			    line_color 	3342489
+			    InterObjView 	@468
+			    height     	352
+			    y_coord    	292
+			    Nested     	TRUE)
+			Focus_Of_Control 	(object Focus_Of_Control "" @471
+			    location   	(1168, 944)
+			    line_color 	3342489
+			    InterObjView 	@468
+			    height     	60
+			    y_coord    	0
+			    Nested     	TRUE))
+		    (object InterObjView "StandardEngine" @472
+			location   	(1520, 224)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	TRUE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object ItemLabel
+			    Parent_View 	@472
+			    location   	(1520, 224)
+			    fill_color 	13434879
+			    anchor_loc 	1
+			    nlines     	2
+			    max_width  	363
+			    justify    	0
+			    label      	"StandardEngine")
+			icon_style 	"Icon"
+			line_color 	3342489
+			fill_color 	13434879
+			quidu      	"3DFE424B0349"
+			width      	381
+			height     	1276
+			icon_height 	0
+			icon_width 	0
+			icon_y_offset 	0
+			annotation 	1
+			Focus_Of_Control 	(object Focus_Of_Control "" @473
+			    location   	(1520, 1008)
+			    line_color 	3342489
+			    InterObjView 	@472
+			    height     	228
+			    y_coord    	168
+			    Nested     	FALSE))
+		    (object InterObjView "StandardPipeline" @474
+			location   	(1872, 224)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	TRUE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object ItemLabel
+			    Parent_View 	@474
+			    location   	(1872, 224)
+			    fill_color 	13434879
+			    anchor_loc 	1
+			    nlines     	2
+			    max_width  	282
+			    justify    	0
+			    label      	"StandardPipeline")
+			icon_style 	"Icon"
+			line_color 	3342489
+			fill_color 	13434879
+			quidu      	"3DFE42900045"
+			width      	300
+			height     	1276
+			icon_height 	0
+			icon_width 	0
+			icon_y_offset 	0
+			annotation 	1
+			Focus_Of_Control 	(object Focus_Of_Control "" @475
+			    location   	(1872, 1040)
+			    line_color 	3342489
+			    InterObjView 	@474
+			    height     	136
+			    y_coord    	76
+			    Nested     	FALSE))
+		    (object InterObjView "StandardValveContext" @476
+			location   	(2192, 224)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	TRUE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object ItemLabel
+			    Parent_View 	@476
+			    location   	(2192, 224)
+			    fill_color 	13434879
+			    anchor_loc 	1
+			    nlines     	2
+			    max_width  	282
+			    justify    	0
+			    label      	"StandardValveContext")
+			icon_style 	"Icon"
+			line_color 	3342489
+			fill_color 	13434879
+			quidu      	"3DFE42C002B1"
+			width      	300
+			height     	1276
+			icon_height 	0
+			icon_width 	0
+			icon_y_offset 	0
+			annotation 	1
+			Focus_Of_Control 	(object Focus_Of_Control "" @477
+			    location   	(2192, 1056)
+			    line_color 	3342489
+			    InterObjView 	@476
+			    height     	60
+			    y_coord    	0
+			    Nested     	FALSE))
+		    (object InterMessView "" @478
+			location   	(16, 384)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	FALSE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object SegLabel @479
+			    Parent_View 	@478
+			    location   	(343, 340)
+			    font       	(object Font
+				size       	10
+				face       	"Arial"
+				bold       	FALSE
+				italics    	FALSE
+				underline  	FALSE
+				strike     	FALSE
+				color      	0
+				default_color 	TRUE)
+			    quidu      	"3DFE40E701AE"
+			    anchor_loc 	1
+			    nlines     	1
+			    max_width  	112
+			    justify    	0
+			    label      	"runIt()"
+			    pctDist    	0.500000
+			    height     	45
+			    orientation 	0)
+			line_color 	3342489
+			client     	@457
+			supplier   	@459
+			Focus_Src  	@458
+			Focus_Entry 	@460
+			origin     	(191, 384)
+			terminus   	(496, 384)
+			ordinal    	0)
+		    (object InterMessView "" @480
+			location   	(16, 400)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	FALSE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object SegLabel @481
+			    Parent_View 	@480
+			    location   	(679, 356)
+			    font       	(object Font
+				size       	10
+				face       	"Arial"
+				bold       	FALSE
+				italics    	FALSE
+				underline  	FALSE
+				strike     	FALSE
+				color      	0
+				default_color 	TRUE)
+			    quidu      	"3DFE40FC010E"
+			    anchor_loc 	1
+			    nlines     	1
+			    max_width  	359
+			    justify    	0
+			    label      	"processConnection"
+			    pctDist    	0.500000
+			    height     	45
+			    orientation 	0)
+			line_color 	3342489
+			client     	@459
+			supplier   	@461
+			Focus_Src  	@460
+			Focus_Entry 	@462
+			origin     	(527, 400)
+			terminus   	(832, 400)
+			ordinal    	1)
+		    (object SelfMessView "" @482
+			location   	(16, 448)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	FALSE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object SegLabel @483
+			    Parent_View 	@482
+			    location   	(969, 405)
+			    font       	(object Font
+				size       	10
+				face       	"Arial"
+				bold       	FALSE
+				italics    	FALSE
+				underline  	FALSE
+				strike     	FALSE
+				color      	0
+				default_color 	TRUE)
+			    quidu      	"3DFE4111029F"
+			    anchor_loc 	1
+			    nlines     	1
+			    max_width  	175
+			    justify    	0
+			    label      	"process()"
+			    pctDist    	0.706667
+			    height     	44
+			    orientation 	0)
+			line_color 	3342489
+			client     	@461
+			supplier   	@461
+			Focus_Src  	@462
+			Focus_Entry 	@463
+			origin     	(864, 448)
+			terminus   	(1014, 448)
+			ordinal    	2)
+		    (object SelfMessView "" @484
+			location   	(16, 592)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	FALSE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object SegLabel @485
+			    Parent_View 	@484
+			    location   	(1048, 549)
+			    font       	(object Font
+				size       	10
+				face       	"Arial"
+				bold       	FALSE
+				italics    	FALSE
+				underline  	FALSE
+				strike     	FALSE
+				color      	0
+				default_color 	TRUE)
+			    quidu      	"3DFE415C0151"
+			    anchor_loc 	1
+			    nlines     	1
+			    max_width  	291
+			    justify    	0
+			    label      	"parseHeaders()"
+			    pctDist    	1.226667
+			    height     	44
+			    orientation 	0)
+			line_color 	3342489
+			client     	@461
+			supplier   	@461
+			Focus_Src  	@464
+			Focus_Entry 	@465
+			origin     	(864, 592)
+			terminus   	(1014, 592)
+			ordinal    	3)
+		    (object SelfMessView "" @486
+			location   	(16, 736)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	FALSE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object SegLabel @487
+			    Parent_View 	@486
+			    location   	(1052, 692)
+			    font       	(object Font
+				size       	10
+				face       	"Arial"
+				bold       	FALSE
+				italics    	FALSE
+				underline  	FALSE
+				strike     	FALSE
+				color      	0
+				default_color 	TRUE)
+			    quidu      	"3DFE41A60161"
+			    anchor_loc 	1
+			    nlines     	1
+			    max_width  	328
+			    justify    	0
+			    label      	"prepareRequest()"
+			    pctDist    	1.253333
+			    height     	44
+			    orientation 	0)
+			line_color 	3342489
+			client     	@461
+			supplier   	@461
+			Focus_Src  	@466
+			Focus_Entry 	@467
+			origin     	(864, 736)
+			terminus   	(1014, 736)
+			ordinal    	4)
+		    (object InterMessView "" @488
+			location   	(992, 848)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	FALSE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object SegLabel @489
+			    Parent_View 	@488
+			    location   	(1007, 804)
+			    font       	(object Font
+				size       	10
+				face       	"Arial"
+				bold       	FALSE
+				italics    	FALSE
+				underline  	FALSE
+				strike     	FALSE
+				color      	0
+				default_color 	TRUE)
+			    quidu      	"3DFE41D60107"
+			    anchor_loc 	1
+			    nlines     	1
+			    max_width  	162
+			    justify    	0
+			    label      	"service()"
+			    pctDist    	0.500000
+			    height     	45
+			    orientation 	0)
+			line_color 	3342489
+			client     	@461
+			supplier   	@468
+			Focus_Src  	@466
+			Focus_Entry 	@469
+			origin     	(863, 848)
+			terminus   	(1152, 848)
+			ordinal    	5)
+		    (object SelfMessView "" @490
+			location   	(16, 944)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	FALSE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object SegLabel @491
+			    Parent_View 	@490
+			    location   	(1372, 916)
+			    font       	(object Font
+				size       	10
+				face       	"Arial"
+				bold       	FALSE
+				italics    	FALSE
+				underline  	FALSE
+				strike     	FALSE
+				color      	0
+				default_color 	TRUE)
+			    quidu      	"3DFE422C01F1"
+			    anchor_loc 	1
+			    nlines     	1
+			    max_width  	373
+			    justify    	0
+			    label      	"postParseRequest()"
+			    pctDist    	1.253333
+			    height     	28
+			    orientation 	0)
+			line_color 	3342489
+			client     	@468
+			supplier   	@468
+			Focus_Src  	@470
+			Focus_Entry 	@471
+			origin     	(1184, 944)
+			terminus   	(1334, 944)
+			ordinal    	6)
+		    (object InterMessView "" @492
+			location   	(1344, 1008)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	FALSE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object SegLabel @493
+			    Parent_View 	@492
+			    location   	(1343, 964)
+			    font       	(object Font
+				size       	10
+				face       	"Arial"
+				bold       	FALSE
+				italics    	FALSE
+				underline  	FALSE
+				strike     	FALSE
+				color      	0
+				default_color 	TRUE)
+			    quidu      	"3DFE42800238"
+			    anchor_loc 	1
+			    nlines     	1
+			    max_width  	149
+			    justify    	0
+			    label      	"invoke()"
+			    pctDist    	0.500000
+			    height     	45
+			    orientation 	0)
+			line_color 	3342489
+			client     	@468
+			supplier   	@472
+			Focus_Src  	@470
+			Focus_Entry 	@473
+			origin     	(1183, 1008)
+			terminus   	(1504, 1008)
+			ordinal    	7)
+		    (object InterMessView "" @494
+			location   	(16, 1040)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	FALSE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object SegLabel @495
+			    Parent_View 	@494
+			    location   	(1695, 996)
+			    font       	(object Font
+				size       	10
+				face       	"Arial"
+				bold       	FALSE
+				italics    	FALSE
+				underline  	FALSE
+				strike     	FALSE
+				color      	0
+				default_color 	TRUE)
+			    quidu      	"3DFE429A002D"
+			    anchor_loc 	1
+			    nlines     	1
+			    max_width  	149
+			    justify    	0
+			    label      	"invoke()"
+			    pctDist    	0.500000
+			    height     	45
+			    orientation 	0)
+			line_color 	3342489
+			client     	@472
+			supplier   	@474
+			Focus_Src  	@473
+			Focus_Entry 	@475
+			origin     	(1535, 1040)
+			terminus   	(1856, 1040)
+			ordinal    	8)
+		    (object InterMessView "" @496
+			location   	(16, 1056)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	FALSE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object SegLabel @497
+			    Parent_View 	@496
+			    location   	(2031, 1012)
+			    font       	(object Font
+				size       	10
+				face       	"Arial"
+				bold       	FALSE
+				italics    	FALSE
+				underline  	FALSE
+				strike     	FALSE
+				color      	0
+				default_color 	TRUE)
+			    quidu      	"3DFE42CE0230"
+			    anchor_loc 	1
+			    nlines     	1
+			    max_width  	149
+			    justify    	0
+			    label      	"invoke()"
+			    pctDist    	0.500000
+			    height     	45
+			    orientation 	0)
+			line_color 	3342489
+			client     	@474
+			supplier   	@476
+			Focus_Src  	@475
+			Focus_Entry 	@477
+			origin     	(1887, 1056)
+			terminus   	(2176, 1056)
+			ordinal    	9)
+		    (object NoteView @498
+			location   	(2000, 2016)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	FALSE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object ItemLabel
+			    Parent_View 	@498
+			    location   	(1862, 1956)
+			    fill_color 	13434879
+			    nlines     	2
+			    max_width  	240
+			    label      	"See next diagram")
+			line_color 	3342489
+			fill_color 	13434879
+			width      	300
+			height     	132)
+		    (object AttachView "" @499
+			stereotype 	TRUE
+			line_color 	3342489
+			client     	@498
+			supplier   	@476
+			line_style 	0)))
+	    (object InteractionDiagram "2. catalina_request_2"
+		mechanism_ref 	@89
+		quid       	"3DFE42F7024C"
+		title      	"2. catalina_request_2"
+		zoom       	100
+		max_height 	28350
+		max_width  	21600
+		origin_x   	0
+		origin_y   	0
+		items      	(list diagram_item_list
+		    (object InterObjView "StandardContextValve" @500
+			location   	(224, 224)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	TRUE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object ItemLabel
+			    Parent_View 	@500
+			    location   	(224, 224)
+			    fill_color 	13434879
+			    anchor_loc 	1
+			    nlines     	2
+			    max_width  	401
+			    justify    	0
+			    label      	"StandardContextValve")
+			icon_style 	"Icon"
+			line_color 	3342489
+			fill_color 	13434879
+			quidu      	"3DFE4307001E"
+			width      	419
+			height     	1678
+			icon_height 	0
+			icon_width 	0
+			icon_y_offset 	0
+			annotation 	1
+			Focus_Of_Control 	(object Focus_Of_Control "" @501
+			    location   	(224, 384)
+			    line_color 	3342489
+			    InterObjView 	@500
+			    height     	386
+			    y_coord    	326
+			    Nested     	FALSE)
+			Focus_Of_Control 	(object Focus_Of_Control "" @502
+			    location   	(224, 704)
+			    line_color 	3342489
+			    InterObjView 	@500
+			    height     	60
+			    y_coord    	0
+			    Nested     	TRUE)
+			Focus_Of_Control 	(object Focus_Of_Control "" @503
+			    location   	(224, 896)
+			    line_color 	3342489
+			    InterObjView 	@500
+			    height     	916
+			    y_coord    	856
+			    Nested     	FALSE)
+			Focus_Of_Control 	(object Focus_Of_Control "" @504
+			    location   	(224, 1024)
+			    line_color 	3342489
+			    InterObjView 	@500
+			    height     	60
+			    y_coord    	0
+			    Nested     	TRUE)
+			Focus_Of_Control 	(object Focus_Of_Control "" @505
+			    location   	(224, 1280)
+			    line_color 	3342489
+			    InterObjView 	@500
+			    height     	60
+			    y_coord    	0
+			    Nested     	TRUE))
+		    (object InterObjView "StandardEngineValve" @506
+			location   	(592, 224)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	TRUE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object ItemLabel
+			    Parent_View 	@506
+			    location   	(592, 224)
+			    fill_color 	13434879
+			    anchor_loc 	1
+			    nlines     	2
+			    max_width  	282
+			    justify    	0
+			    label      	"StandardEngineValve")
+			icon_style 	"Icon"
+			line_color 	3342489
+			fill_color 	13434879
+			quidu      	"3DFE432801F3"
+			width      	300
+			height     	1678
+			icon_height 	0
+			icon_width 	0
+			icon_y_offset 	0
+			annotation 	1
+			Focus_Of_Control 	(object Focus_Of_Control "" @507
+			    location   	(592, 384)
+			    line_color 	3342489
+			    InterObjView 	@506
+			    height     	264
+			    y_coord    	204
+			    Nested     	FALSE))
+		    (object InterObjView "StandardHost" @508
+			location   	(912, 224)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	TRUE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object ItemLabel
+			    Parent_View 	@508
+			    location   	(912, 224)
+			    fill_color 	13434879
+			    anchor_loc 	1
+			    nlines     	2
+			    max_width  	282
+			    justify    	0
+			    label      	"StandardHost")
+			icon_style 	"Icon"
+			line_color 	3342489
+			fill_color 	13434879
+			quidu      	"3DFE436503BD"
+			width      	300
+			height     	1678
+			icon_height 	0
+			icon_width 	0
+			icon_y_offset 	0
+			annotation 	1
+			Focus_Of_Control 	(object Focus_Of_Control "" @509
+			    location   	(912, 416)
+			    line_color 	3342489
+			    InterObjView 	@508
+			    height     	431
+			    y_coord    	371
+			    Nested     	FALSE)
+			Focus_Of_Control 	(object Focus_Of_Control "" @510
+			    location   	(912, 528)
+			    line_color 	3342489
+			    InterObjView 	@508
+			    height     	60
+			    y_coord    	0
+			    Nested     	TRUE)
+			Focus_Of_Control 	(object Focus_Of_Control "" @511
+			    location   	(912, 704)
+			    line_color 	3342489
+			    InterObjView 	@508
+			    height     	120
+			    y_coord    	60
+			    Nested     	TRUE))
+		    (object InterObjView "ErrorReportValve" @512
+			location   	(1264, 224)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	TRUE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object ItemLabel
+			    Parent_View 	@512
+			    location   	(1264, 224)
+			    fill_color 	13434879
+			    anchor_loc 	1
+			    nlines     	2
+			    max_width  	294
+			    justify    	0
+			    label      	"ErrorReportValve")
+			icon_style 	"Icon"
+			line_color 	3342489
+			fill_color 	13434879
+			quidu      	"3DFE438C028D"
+			width      	312
+			height     	1678
+			icon_height 	0
+			icon_width 	0
+			icon_y_offset 	0
+			annotation 	1
+			Focus_Of_Control 	(object Focus_Of_Control "" @513
+			    location   	(1264, 896)
+			    line_color 	3342489
+			    InterObjView 	@512
+			    height     	248
+			    y_coord    	188
+			    Nested     	FALSE)
+			Focus_Of_Control 	(object Focus_Of_Control "" @514
+			    location   	(1264, 944)
+			    line_color 	3342489
+			    InterObjView 	@512
+			    height     	60
+			    y_coord    	0
+			    Nested     	TRUE))
+		    (object InterObjView "ErrorDispatcherValve" @515
+			location   	(1584, 224)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	TRUE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object ItemLabel
+			    Parent_View 	@515
+			    location   	(1584, 224)
+			    fill_color 	13434879
+			    anchor_loc 	1
+			    nlines     	2
+			    max_width  	295
+			    justify    	0
+			    label      	"ErrorDispatcherValve")
+			icon_style 	"Icon"
+			line_color 	3342489
+			fill_color 	13434879
+			quidu      	"3DFE451F01EC"
+			width      	313
+			height     	1678
+			icon_height 	0
+			icon_width 	0
+			icon_y_offset 	0
+			annotation 	1
+			Focus_Of_Control 	(object Focus_Of_Control "" @516
+			    location   	(1584, 1168)
+			    line_color 	3342489
+			    InterObjView 	@515
+			    height     	232
+			    y_coord    	172
+			    Nested     	FALSE))
+		    (object InterObjView "StandardHostValve" @517
+			location   	(1904, 224)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	TRUE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object ItemLabel
+			    Parent_View 	@517
+			    location   	(1904, 224)
+			    fill_color 	13434879
+			    anchor_loc 	1
+			    nlines     	2
+			    max_width  	295
+			    justify    	0
+			    label      	"StandardHostValve")
+			icon_style 	"Icon"
+			line_color 	3342489
+			fill_color 	13434879
+			quidu      	"3DFE47310130"
+			width      	313
+			height     	1678
+			icon_height 	0
+			icon_width 	0
+			icon_y_offset 	0
+			annotation 	1
+			Focus_Of_Control 	(object Focus_Of_Control "" @518
+			    location   	(1904, 1472)
+			    line_color 	3342489
+			    InterObjView 	@517
+			    height     	280
+			    y_coord    	220
+			    Nested     	FALSE)
+			Focus_Of_Control 	(object Focus_Of_Control "" @519
+			    location   	(1904, 1536)
+			    line_color 	3342489
+			    InterObjView 	@517
+			    height     	60
+			    y_coord    	0
+			    Nested     	TRUE))
+		    (object InterObjView "StandardContext" @520
+			location   	(2224, 224)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	TRUE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object ItemLabel
+			    Parent_View 	@520
+			    location   	(2224, 224)
+			    fill_color 	13434879
+			    anchor_loc 	1
+			    nlines     	2
+			    max_width  	282
+			    justify    	0
+			    label      	"StandardContext")
+			icon_style 	"Icon"
+			line_color 	3342489
+			fill_color 	13434879
+			quidu      	"3DFE47C100F1"
+			width      	300
+			height     	1678
+			icon_height 	0
+			icon_width 	0
+			icon_y_offset 	0
+			annotation 	1
+			Focus_Of_Control 	(object Focus_Of_Control "" @521
+			    location   	(2224, 1632)
+			    line_color 	3342489
+			    InterObjView 	@520
+			    height     	60
+			    y_coord    	0
+			    Nested     	FALSE))
+		    (object InterMessView "" @522
+			location   	(16, 384)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	FALSE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object SegLabel @523
+			    Parent_View 	@522
+			    location   	(407, 340)
+			    font       	(object Font
+				size       	10
+				face       	"Arial"
+				bold       	FALSE
+				italics    	FALSE
+				underline  	FALSE
+				strike     	FALSE
+				color      	0
+				default_color 	TRUE)
+			    quidu      	"3DFE434C019B"
+			    anchor_loc 	1
+			    nlines     	1
+			    max_width  	146
+			    justify    	0
+			    label      	"invoke()"
+			    pctDist    	0.500000
+			    height     	45
+			    orientation 	0)
+			line_color 	3342489
+			client     	@500
+			supplier   	@506
+			Focus_Src  	@501
+			Focus_Entry 	@507
+			origin     	(239, 384)
+			terminus   	(576, 384)
+			ordinal    	0)
+		    (object InterMessView "" @524
+			location   	(16, 416)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	FALSE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object SegLabel @525
+			    Parent_View 	@524
+			    location   	(751, 372)
+			    font       	(object Font
+				size       	10
+				face       	"Arial"
+				bold       	FALSE
+				italics    	FALSE
+				underline  	FALSE
+				strike     	FALSE
+				color      	0
+				default_color 	TRUE)
+			    quidu      	"3DFE436C009D"
+			    anchor_loc 	1
+			    nlines     	1
+			    max_width  	107
+			    justify    	0
+			    label      	"map()"
+			    pctDist    	0.500000
+			    height     	45
+			    orientation 	0)
+			line_color 	3342489
+			client     	@506
+			supplier   	@508
+			Focus_Src  	@507
+			Focus_Entry 	@509
+			origin     	(607, 416)
+			terminus   	(896, 416)
+			ordinal    	1)
+		    (object InterMessView "" @526
+			location   	(800, 528)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	FALSE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object SegLabel @527
+			    Parent_View 	@526
+			    location   	(751, 484)
+			    font       	(object Font
+				size       	10
+				face       	"Arial"
+				bold       	FALSE
+				italics    	FALSE
+				underline  	FALSE
+				strike     	FALSE
+				color      	0
+				default_color 	TRUE)
+			    quidu      	"3DFE43830063"
+			    anchor_loc 	1
+			    nlines     	1
+			    max_width  	146
+			    justify    	0
+			    label      	"invoke()"
+			    pctDist    	0.500000
+			    height     	45
+			    orientation 	0)
+			line_color 	3342489
+			client     	@506
+			supplier   	@508
+			Focus_Src  	@507
+			Focus_Entry 	@510
+			origin     	(607, 528)
+			terminus   	(896, 528)
+			ordinal    	2)
+		    (object InterMessView "" @528
+			location   	(608, 704)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	FALSE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object SegLabel @529
+			    Parent_View 	@528
+			    location   	(568, 660)
+			    font       	(object Font
+				size       	10
+				face       	"Arial"
+				bold       	FALSE
+				italics    	FALSE
+				underline  	FALSE
+				strike     	FALSE
+				color      	0
+				default_color 	TRUE)
+			    quidu      	"3DFE43B903BF"
+			    anchor_loc 	1
+			    nlines     	1
+			    max_width  	146
+			    justify    	0
+			    label      	"invoke()"
+			    pctDist    	0.500000
+			    height     	45
+			    orientation 	1)
+			line_color 	3342489
+			client     	@508
+			supplier   	@500
+			Focus_Src  	@511
+			Focus_Entry 	@502
+			origin     	(896, 704)
+			terminus   	(240, 704)
+			ordinal    	3)
+		    (object InterMessView "" @530
+			location   	(752, 896)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	FALSE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object SegLabel @531
+			    Parent_View 	@530
+			    location   	(743, 852)
+			    font       	(object Font
+				size       	10
+				face       	"Arial"
+				bold       	FALSE
+				italics    	FALSE
+				underline  	FALSE
+				strike     	FALSE
+				color      	0
+				default_color 	TRUE)
+			    quidu      	"3DFE43C203A4"
+			    anchor_loc 	1
+			    nlines     	1
+			    max_width  	146
+			    justify    	0
+			    label      	"invoke()"
+			    pctDist    	0.500000
+			    height     	45
+			    orientation 	0)
+			line_color 	3342489
+			client     	@500
+			supplier   	@512
+			Focus_Src  	@503
+			Focus_Entry 	@513
+			origin     	(239, 896)
+			terminus   	(1248, 896)
+			ordinal    	4)
+		    (object SelfMessView "" @532
+			location   	(16, 944)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	FALSE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object SegLabel @533
+			    Parent_View 	@532
+			    location   	(1355, 900)
+			    font       	(object Font
+				size       	10
+				face       	"Arial"
+				bold       	FALSE
+				italics    	FALSE
+				underline  	FALSE
+				strike     	FALSE
+				color      	0
+				default_color 	TRUE)
+			    quidu      	"3DFE442501B1"
+			    anchor_loc 	1
+			    nlines     	1
+			    max_width  	135
+			    justify    	0
+			    label      	"report()"
+			    pctDist    	0.500000
+			    height     	45
+			    orientation 	0)
+			line_color 	3342489
+			client     	@512
+			supplier   	@512
+			Focus_Src  	@513
+			Focus_Entry 	@514
+			origin     	(1280, 944)
+			terminus   	(1430, 944)
+			ordinal    	5)
+		    (object InterMessView "" @534
+			location   	(16, 1024)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	FALSE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object SegLabel @535
+			    Parent_View 	@534
+			    location   	(744, 980)
+			    font       	(object Font
+				size       	10
+				face       	"Arial"
+				bold       	FALSE
+				italics    	FALSE
+				underline  	FALSE
+				strike     	FALSE
+				color      	0
+				default_color 	TRUE)
+			    quidu      	"3DFE46330293"
+			    anchor_loc 	1
+			    nlines     	1
+			    max_width  	230
+			    justify    	0
+			    label      	"invokeNext()"
+			    pctDist    	0.500000
+			    height     	45
+			    orientation 	1)
+			line_color 	3342489
+			client     	@512
+			supplier   	@500
+			Focus_Src  	@513
+			Focus_Entry 	@504
+			origin     	(1248, 1024)
+			terminus   	(240, 1024)
+			ordinal    	6)
+		    (object InterMessView "" @536
+			location   	(944, 1168)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	FALSE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object SegLabel @537
+			    Parent_View 	@536
+			    location   	(903, 1124)
+			    font       	(object Font
+				size       	10
+				face       	"Arial"
+				bold       	FALSE
+				italics    	FALSE
+				underline  	FALSE
+				strike     	FALSE
+				color      	0
+				default_color 	TRUE)
+			    quidu      	"3DFE46E70026"
+			    anchor_loc 	1
+			    nlines     	1
+			    max_width  	146
+			    justify    	0
+			    label      	"invoke()"
+			    pctDist    	0.500000
+			    height     	45
+			    orientation 	0)
+			line_color 	3342489
+			client     	@500
+			supplier   	@515
+			Focus_Src  	@503
+			Focus_Entry 	@516
+			origin     	(239, 1168)
+			terminus   	(1568, 1168)
+			ordinal    	7)
+		    (object InterMessView "" @538
+			location   	(16, 1280)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	FALSE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object SegLabel @539
+			    Parent_View 	@538
+			    location   	(904, 1236)
+			    font       	(object Font
+				size       	10
+				face       	"Arial"
+				bold       	FALSE
+				italics    	FALSE
+				underline  	FALSE
+				strike     	FALSE
+				color      	0
+				default_color 	TRUE)
+			    quidu      	"3DFE475D03A0"
+			    anchor_loc 	1
+			    nlines     	1
+			    max_width  	206
+			    justify    	0
+			    label      	"invokeNext"
+			    pctDist    	0.500000
+			    height     	45
+			    orientation 	1)
+			line_color 	3342489
+			client     	@515
+			supplier   	@500
+			Focus_Src  	@516
+			Focus_Entry 	@505
+			origin     	(1568, 1280)
+			terminus   	(240, 1280)
+			ordinal    	8)
+		    (object InterMessView "" @540
+			location   	(1184, 1472)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	FALSE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object SegLabel @541
+			    Parent_View 	@540
+			    location   	(1063, 1428)
+			    font       	(object Font
+				size       	10
+				face       	"Arial"
+				bold       	FALSE
+				italics    	FALSE
+				underline  	FALSE
+				strike     	FALSE
+				color      	0
+				default_color 	TRUE)
+			    quidu      	"3DFE476503CA"
+			    anchor_loc 	1
+			    nlines     	1
+			    max_width  	146
+			    justify    	0
+			    label      	"invoke()"
+			    pctDist    	0.500000
+			    height     	45
+			    orientation 	0)
+			line_color 	3342489
+			client     	@500
+			supplier   	@517
+			Focus_Src  	@503
+			Focus_Entry 	@518
+			origin     	(239, 1472)
+			terminus   	(1888, 1472)
+			ordinal    	9)
+		    (object SelfMessView "" @542
+			location   	(16, 1536)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	FALSE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object SegLabel @543
+			    Parent_View 	@542
+			    location   	(1995, 1492)
+			    font       	(object Font
+				size       	10
+				face       	"Arial"
+				bold       	FALSE
+				italics    	FALSE
+				underline  	FALSE
+				strike     	FALSE
+				color      	0
+				default_color 	TRUE)
+			    quidu      	"3DFE47CD0167"
+			    anchor_loc 	1
+			    nlines     	1
+			    max_width  	295
+			    justify    	0
+			    label      	"map() //Context"
+			    pctDist    	0.500000
+			    height     	45
+			    orientation 	0)
+			line_color 	3342489
+			client     	@517
+			supplier   	@517
+			Focus_Src  	@518
+			Focus_Entry 	@519
+			origin     	(1920, 1536)
+			terminus   	(2070, 1536)
+			ordinal    	10)
+		    (object InterMessView "" @544
+			location   	(16, 1632)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	FALSE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object SegLabel @545
+			    Parent_View 	@544
+			    location   	(2063, 1588)
+			    font       	(object Font
+				size       	10
+				face       	"Arial"
+				bold       	FALSE
+				italics    	FALSE
+				underline  	FALSE
+				strike     	FALSE
+				color      	0
+				default_color 	TRUE)
+			    quidu      	"3DFE47D500B4"
+			    anchor_loc 	1
+			    nlines     	1
+			    max_width  	146
+			    justify    	0
+			    label      	"invoke()"
+			    pctDist    	0.500000
+			    height     	45
+			    orientation 	0)
+			line_color 	3342489
+			client     	@517
+			supplier   	@520
+			Focus_Src  	@518
+			Focus_Entry 	@521
+			origin     	(1919, 1632)
+			terminus   	(2208, 1632)
+			ordinal    	11)))
+	    (object InteractionDiagram "3. catalina_request_3"
+		mechanism_ref 	@90
+		quid       	"3DFE48A202AD"
+		title      	"3. catalina_request_3"
+		zoom       	100
+		max_height 	28350
+		max_width  	21600
+		origin_x   	612
+		origin_y   	938
+		items      	(list diagram_item_list
+		    (object InterObjView "StandardContext" @546
+			location   	(160, 224)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	TRUE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object ItemLabel
+			    Parent_View 	@546
+			    location   	(160, 224)
+			    fill_color 	13434879
+			    anchor_loc 	1
+			    nlines     	2
+			    max_width  	282
+			    justify    	0
+			    label      	"StandardContext")
+			icon_style 	"Icon"
+			line_color 	3342489
+			fill_color 	13434879
+			quidu      	"3DFE48B001D1"
+			width      	300
+			height     	2226
+			icon_height 	0
+			icon_width 	0
+			icon_y_offset 	0
+			annotation 	1
+			Focus_Of_Control 	(object Focus_Of_Control "" @547
+			    location   	(160, 400)
+			    line_color 	3342489
+			    InterObjView 	@546
+			    height     	1960
+			    y_coord    	1900
+			    Nested     	FALSE))
+		    (object InterObjView "StandardPipeline" @548
+			location   	(480, 224)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	TRUE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object ItemLabel
+			    Parent_View 	@548
+			    location   	(480, 224)
+			    fill_color 	13434879
+			    anchor_loc 	1
+			    nlines     	2
+			    max_width  	282
+			    justify    	0
+			    label      	"StandardPipeline")
+			icon_style 	"Icon"
+			line_color 	3342489
+			fill_color 	13434879
+			quidu      	"3DFE48B80088"
+			width      	300
+			height     	2226
+			icon_height 	0
+			icon_width 	0
+			icon_y_offset 	0
+			annotation 	1
+			Focus_Of_Control 	(object Focus_Of_Control "" @549
+			    location   	(480, 400)
+			    line_color 	3342489
+			    InterObjView 	@548
+			    height     	1900
+			    y_coord    	1840
+			    Nested     	FALSE)
+			Focus_Of_Control 	(object Focus_Of_Control "" @550
+			    location   	(480, 1088)
+			    line_color 	3342489
+			    InterObjView 	@548
+			    height     	60
+			    y_coord    	0
+			    Nested     	TRUE))
+		    (object InterObjView "StandardValveContext" @551
+			location   	(800, 224)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	TRUE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object ItemLabel
+			    Parent_View 	@551
+			    location   	(800, 224)
+			    fill_color 	13434879
+			    anchor_loc 	1
+			    nlines     	2
+			    max_width  	282
+			    justify    	0
+			    label      	"StandardValveContext")
+			icon_style 	"Icon"
+			line_color 	3342489
+			fill_color 	13434879
+			quidu      	"3DFE48D000DC"
+			width      	300
+			height     	2226
+			icon_height 	0
+			icon_width 	0
+			icon_y_offset 	0
+			annotation 	1
+			Focus_Of_Control 	(object Focus_Of_Control "" @552
+			    location   	(800, 736)
+			    line_color 	3342489
+			    InterObjView 	@551
+			    height     	1510
+			    y_coord    	1450
+			    Nested     	FALSE)
+			Focus_Of_Control 	(object Focus_Of_Control "" @553
+			    location   	(800, 1168)
+			    line_color 	3342489
+			    InterObjView 	@551
+			    height     	1072
+			    y_coord    	1012
+			    Nested     	TRUE))
+		    (object InterObjView "StandardContextValve" @554
+			location   	(1104, 224)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	TRUE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object ItemLabel
+			    Parent_View 	@554
+			    location   	(1104, 224)
+			    fill_color 	13434879
+			    anchor_loc 	1
+			    nlines     	2
+			    max_width  	282
+			    justify    	0
+			    label      	"StandardContextValve")
+			icon_style 	"Icon"
+			line_color 	3342489
+			fill_color 	13434879
+			quidu      	"3DFE490303A7"
+			width      	300
+			height     	2226
+			icon_height 	0
+			icon_width 	0
+			icon_y_offset 	0
+			annotation 	1
+			Focus_Of_Control 	(object Focus_Of_Control "" @555
+			    location   	(1104, 800)
+			    line_color 	3342489
+			    InterObjView 	@554
+			    height     	468
+			    y_coord    	408
+			    Nested     	FALSE)
+			Focus_Of_Control 	(object Focus_Of_Control "" @556
+			    location   	(1104, 848)
+			    line_color 	3342489
+			    InterObjView 	@554
+			    height     	60
+			    y_coord    	0
+			    Nested     	TRUE))
+		    (object InterObjView "StandardWrapper" @557
+			location   	(1424, 224)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	TRUE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object ItemLabel
+			    Parent_View 	@557
+			    location   	(1424, 224)
+			    fill_color 	13434879
+			    anchor_loc 	1
+			    nlines     	2
+			    max_width  	288
+			    justify    	0
+			    label      	"StandardWrapper")
+			icon_style 	"Icon"
+			line_color 	3342489
+			fill_color 	13434879
+			quidu      	"3DFE49370351"
+			width      	306
+			height     	2226
+			icon_height 	0
+			icon_width 	0
+			icon_y_offset 	0
+			annotation 	1
+			Focus_Of_Control 	(object Focus_Of_Control "" @558
+			    location   	(1424, 944)
+			    line_color 	3342489
+			    InterObjView 	@557
+			    height     	264
+			    y_coord    	204
+			    Nested     	FALSE)
+			Focus_Of_Control 	(object Focus_Of_Control "" @559
+			    location   	(1424, 1520)
+			    line_color 	3342489
+			    InterObjView 	@557
+			    height     	340
+			    y_coord    	280
+			    Nested     	FALSE))
+		    (object InterObjView "StandardWrapperValve" @560
+			location   	(1744, 224)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	TRUE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object ItemLabel
+			    Parent_View 	@560
+			    location   	(1744, 224)
+			    fill_color 	13434879
+			    anchor_loc 	1
+			    nlines     	2
+			    max_width  	282
+			    justify    	0
+			    label      	"StandardWrapperValve")
+			icon_style 	"Icon"
+			line_color 	3342489
+			fill_color 	13434879
+			quidu      	"3DFE49890056"
+			width      	300
+			height     	2226
+			icon_height 	0
+			icon_width 	0
+			icon_y_offset 	0
+			annotation 	1
+			Focus_Of_Control 	(object Focus_Of_Control "" @561
+			    location   	(1744, 1440)
+			    line_color 	3342489
+			    InterObjView 	@560
+			    height     	740
+			    y_coord    	680
+			    Nested     	FALSE)
+			Focus_Of_Control 	(object Focus_Of_Control "" @562
+			    location   	(1744, 1616)
+			    line_color 	3342489
+			    InterObjView 	@560
+			    height     	184
+			    y_coord    	124
+			    Nested     	FALSE)
+			Focus_Of_Control 	(object Focus_Of_Control "" @563
+			    location   	(1744, 2000)
+			    line_color 	3342489
+			    InterObjView 	@560
+			    height     	60
+			    y_coord    	0
+			    Nested     	TRUE))
+		    (object InterObjView "ApplicationFilterChain" @564
+			location   	(2064, 224)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	TRUE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object ItemLabel
+			    Parent_View 	@564
+			    location   	(2064, 224)
+			    fill_color 	13434879
+			    anchor_loc 	1
+			    nlines     	2
+			    max_width  	282
+			    justify    	0
+			    label      	"ApplicationFilterChain")
+			icon_style 	"Icon"
+			line_color 	3342489
+			fill_color 	13434879
+			quidu      	"3DFE4A1500B2"
+			width      	300
+			height     	2226
+			icon_height 	0
+			icon_width 	0
+			icon_y_offset 	0
+			annotation 	1
+			Focus_Of_Control 	(object Focus_Of_Control "" @565
+			    location   	(2064, 1680)
+			    line_color 	3342489
+			    InterObjView 	@564
+			    height     	60
+			    y_coord    	0
+			    Nested     	FALSE)
+			Focus_Of_Control 	(object Focus_Of_Control "" @566
+			    location   	(2064, 1808)
+			    line_color 	3342489
+			    InterObjView 	@564
+			    height     	312
+			    y_coord    	252
+			    Nested     	FALSE)
+			Focus_Of_Control 	(object Focus_Of_Control "" @567
+			    location   	(2064, 1872)
+			    line_color 	3342489
+			    InterObjView 	@564
+			    height     	60
+			    y_coord    	0
+			    Nested     	TRUE))
+		    (object InterMessView "" @568
+			location   	(336, 400)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	FALSE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object SegLabel @569
+			    Parent_View 	@568
+			    location   	(319, 356)
+			    font       	(object Font
+				size       	10
+				face       	"Arial"
+				bold       	FALSE
+				italics    	FALSE
+				underline  	FALSE
+				strike     	FALSE
+				color      	0
+				default_color 	TRUE)
+			    quidu      	"3DFE48BE0268"
+			    anchor_loc 	1
+			    nlines     	1
+			    max_width  	147
+			    justify    	0
+			    label      	"invoke()"
+			    pctDist    	0.500000
+			    height     	45
+			    orientation 	0)
+			line_color 	3342489
+			client     	@546
+			supplier   	@548
+			Focus_Src  	@547
+			Focus_Entry 	@549
+			origin     	(175, 400)
+			terminus   	(464, 400)
+			ordinal    	0)
+		    (object InterMessView "" @570
+			location   	(16, 736)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	FALSE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object SegLabel @571
+			    Parent_View 	@570
+			    location   	(639, 692)
+			    font       	(object Font
+				size       	10
+				face       	"Arial"
+				bold       	FALSE
+				italics    	FALSE
+				underline  	FALSE
+				strike     	FALSE
+				color      	0
+				default_color 	TRUE)
+			    quidu      	"3DFE48EA003A"
+			    anchor_loc 	1
+			    nlines     	1
+			    max_width  	147
+			    justify    	0
+			    label      	"invoke()"
+			    pctDist    	0.500000
+			    height     	45
+			    orientation 	0)
+			line_color 	3342489
+			client     	@548
+			supplier   	@551
+			Focus_Src  	@549
+			Focus_Entry 	@552
+			origin     	(495, 736)
+			terminus   	(784, 736)
+			ordinal    	1)
+		    (object InterMessView "" @572
+			location   	(16, 800)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	FALSE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object SegLabel @573
+			    Parent_View 	@572
+			    location   	(951, 756)
+			    font       	(object Font
+				size       	10
+				face       	"Arial"
+				bold       	FALSE
+				italics    	FALSE
+				underline  	FALSE
+				strike     	FALSE
+				color      	0
+				default_color 	TRUE)
+			    quidu      	"3DFE491102D6"
+			    anchor_loc 	1
+			    nlines     	1
+			    max_width  	147
+			    justify    	0
+			    label      	"invoke()"
+			    pctDist    	0.500000
+			    height     	45
+			    orientation 	0)
+			line_color 	3342489
+			client     	@551
+			supplier   	@554
+			Focus_Src  	@552
+			Focus_Entry 	@555
+			origin     	(815, 800)
+			terminus   	(1088, 800)
+			ordinal    	2)
+		    (object SelfMessView "" @574
+			location   	(16, 848)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	FALSE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object SegLabel @575
+			    Parent_View 	@574
+			    location   	(1322, 821)
+			    font       	(object Font
+				size       	10
+				face       	"Arial"
+				bold       	FALSE
+				italics    	FALSE
+				underline  	FALSE
+				strike     	FALSE
+				color      	0
+				default_color 	TRUE)
+			    quidu      	"3DFE492F033D"
+			    anchor_loc 	1
+			    nlines     	1
+			    max_width  	437
+			    justify    	0
+			    label      	"map //return Wrapper"
+			    pctDist    	1.346667
+			    height     	28
+			    orientation 	0)
+			line_color 	3342489
+			client     	@554
+			supplier   	@554
+			Focus_Src  	@555
+			Focus_Entry 	@556
+			origin     	(1120, 848)
+			terminus   	(1270, 848)
+			ordinal    	3)
+		    (object InterMessView "" @576
+			location   	(1264, 944)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	FALSE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object SegLabel @577
+			    Parent_View 	@576
+			    location   	(1262, 901)
+			    font       	(object Font
+				size       	10
+				face       	"Arial"
+				bold       	FALSE
+				italics    	FALSE
+				underline  	FALSE
+				strike     	FALSE
+				color      	0
+				default_color 	TRUE)
+			    quidu      	"3DFE494A0151"
+			    anchor_loc 	1
+			    nlines     	1
+			    max_width  	147
+			    justify    	0
+			    label      	"invoke()"
+			    pctDist    	0.498270
+			    height     	44
+			    orientation 	0)
+			line_color 	3342489
+			client     	@554
+			supplier   	@557
+			Focus_Src  	@555
+			Focus_Entry 	@558
+			origin     	(1119, 944)
+			terminus   	(1408, 944)
+			ordinal    	4)
+		    (object InterMessView "" @578
+			location   	(960, 1088)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	FALSE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object SegLabel @579
+			    Parent_View 	@578
+			    location   	(952, 1044)
+			    font       	(object Font
+				size       	10
+				face       	"Arial"
+				bold       	FALSE
+				italics    	FALSE
+				underline  	FALSE
+				strike     	FALSE
+				color      	0
+				default_color 	TRUE)
+			    quidu      	"3DFE495F0288"
+			    anchor_loc 	1
+			    nlines     	1
+			    max_width  	147
+			    justify    	0
+			    label      	"invoke()"
+			    pctDist    	0.500000
+			    height     	45
+			    orientation 	1)
+			line_color 	3342489
+			client     	@557
+			supplier   	@548
+			Focus_Src  	@558
+			Focus_Entry 	@550
+			origin     	(1408, 1088)
+			terminus   	(496, 1088)
+			ordinal    	5)
+		    (object InterMessView "" @580
+			location   	(16, 1168)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	FALSE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object SegLabel @581
+			    Parent_View 	@580
+			    location   	(639, 1124)
+			    font       	(object Font
+				size       	10
+				face       	"Arial"
+				bold       	FALSE
+				italics    	FALSE
+				underline  	FALSE
+				strike     	FALSE
+				color      	0
+				default_color 	TRUE)
+			    quidu      	"3DFE4976015D"
+			    anchor_loc 	1
+			    nlines     	1
+			    max_width  	147
+			    justify    	0
+			    label      	"invoke()"
+			    pctDist    	0.500000
+			    height     	45
+			    orientation 	0)
+			line_color 	3342489
+			client     	@548
+			supplier   	@551
+			Focus_Src  	@549
+			Focus_Entry 	@553
+			origin     	(495, 1168)
+			terminus   	(784, 1168)
+			ordinal    	6)
+		    (object InterMessView "" @582
+			location   	(1296, 1440)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	FALSE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object SegLabel @583
+			    Parent_View 	@582
+			    location   	(1271, 1396)
+			    font       	(object Font
+				size       	10
+				face       	"Arial"
+				bold       	FALSE
+				italics    	FALSE
+				underline  	FALSE
+				strike     	FALSE
+				color      	0
+				default_color 	TRUE)
+			    quidu      	"3DFE4993023C"
+			    anchor_loc 	1
+			    nlines     	1
+			    max_width  	147
+			    justify    	0
+			    label      	"invoke()"
+			    pctDist    	0.500000
+			    height     	45
+			    orientation 	0)
+			line_color 	3342489
+			client     	@551
+			supplier   	@560
+			Focus_Src  	@553
+			Focus_Entry 	@561
+			origin     	(815, 1440)
+			terminus   	(1728, 1440)
+			ordinal    	7)
+		    (object InterMessView "" @584
+			location   	(1616, 1520)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	FALSE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object SegLabel @585
+			    Parent_View 	@584
+			    location   	(1584, 1476)
+			    font       	(object Font
+				size       	10
+				face       	"Arial"
+				bold       	FALSE
+				italics    	FALSE
+				underline  	FALSE
+				strike     	FALSE
+				color      	0
+				default_color 	TRUE)
+			    quidu      	"3DFE49EC004F"
+			    anchor_loc 	1
+			    nlines     	1
+			    max_width  	175
+			    justify    	0
+			    label      	"allocate()"
+			    pctDist    	0.500000
+			    height     	45
+			    orientation 	1)
+			line_color 	3342489
+			client     	@560
+			supplier   	@557
+			Focus_Src  	@561
+			Focus_Entry 	@559
+			origin     	(1728, 1520)
+			terminus   	(1440, 1520)
+			ordinal    	8)
+		    (object InterMessView "" @586
+			location   	(1616, 1616)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	FALSE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object SegLabel @587
+			    Parent_View 	@586
+			    location   	(1583, 1572)
+			    font       	(object Font
+				size       	10
+				face       	"Arial"
+				bold       	FALSE
+				italics    	FALSE
+				underline  	FALSE
+				strike     	FALSE
+				color      	0
+				default_color 	TRUE)
+			    quidu      	"3DFE4A200067"
+			    anchor_loc 	1
+			    nlines     	1
+			    max_width  	242
+			    justify    	0
+			    label      	"return servlet"
+			    pctDist    	0.500000
+			    height     	45
+			    orientation 	0)
+			line_color 	3342489
+			client     	@557
+			supplier   	@560
+			Focus_Src  	@559
+			Focus_Entry 	@562
+			origin     	(1439, 1616)
+			terminus   	(1728, 1616)
+			ordinal    	9)
+		    (object InterMessView "" @588
+			location   	(1936, 1680)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	FALSE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object SegLabel @589
+			    Parent_View 	@588
+			    location   	(1937, 1636)
+			    font       	(object Font
+				size       	10
+				face       	"Arial"
+				bold       	FALSE
+				italics    	FALSE
+				underline  	FALSE
+				strike     	FALSE
+				color      	0
+				default_color 	TRUE)
+			    quidu      	"3DFE4A29027E"
+			    anchor_loc 	1
+			    nlines     	1
+			    max_width  	343
+			    justify    	0
+			    label      	"createFilterChain()"
+			    pctDist    	0.619377
+			    height     	45
+			    orientation 	0)
+			line_color 	3342489
+			client     	@560
+			supplier   	@564
+			Focus_Src  	@562
+			Focus_Entry 	@565
+			origin     	(1759, 1680)
+			terminus   	(2048, 1680)
+			ordinal    	10)
+		    (object InterMessView "" @590
+			location   	(16, 1808)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	FALSE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object SegLabel @591
+			    Parent_View 	@590
+			    location   	(1902, 1764)
+			    font       	(object Font
+				size       	10
+				face       	"Arial"
+				bold       	FALSE
+				italics    	FALSE
+				underline  	FALSE
+				strike     	FALSE
+				color      	0
+				default_color 	TRUE)
+			    quidu      	"3DFE4A490283"
+			    anchor_loc 	1
+			    nlines     	1
+			    max_width  	170
+			    justify    	0
+			    label      	"doFilter()"
+			    pctDist    	0.498270
+			    height     	45
+			    orientation 	0)
+			line_color 	3342489
+			client     	@560
+			supplier   	@564
+			Focus_Src  	@561
+			Focus_Entry 	@566
+			origin     	(1759, 1808)
+			terminus   	(2048, 1808)
+			ordinal    	11)
+		    (object InterObjView "$UNNAMED$0" @592
+			location   	(2240, 368)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	TRUE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object ItemLabel
+			    Parent_View 	@592
+			    location   	(2240, 368)
+			    fill_color 	13434879
+			    anchor_loc 	1
+			    nlines     	2
+			    max_width  	282
+			    justify    	0
+			    label      	"")
+			stereotype 	(object ItemLabel
+			    Parent_View 	@592
+			    location   	(2240, 368)
+			    fill_color 	13434879
+			    anchor     	10
+			    anchor_loc 	1
+			    nlines     	1
+			    max_width  	222
+			    justify    	0
+			    label      	"<<Servlet>>")
+			icon_style 	"Icon"
+			line_color 	3342489
+			fill_color 	13434879
+			quidu      	"3DFE4BAE0056"
+			width      	300
+			height     	2082
+			icon_height 	0
+			icon_width 	0
+			icon_y_offset 	0
+			annotation 	1
+			Focus_Of_Control 	(object Focus_Of_Control "" @593
+			    location   	(2240, 428)
+			    InterObjView 	@592
+			    height     	60
+			    y_coord    	0
+			    Nested     	FALSE)
+			Focus_Of_Control 	(object Focus_Of_Control "" @594
+			    location   	(2240, 1984)
+			    line_color 	3342489
+			    InterObjView 	@592
+			    height     	60
+			    y_coord    	0
+			    Nested     	FALSE))
+		    (object SelfMessView "" @595
+			location   	(16, 1872)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	FALSE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object SegLabel @596
+			    Parent_View 	@595
+			    location   	(2155, 1828)
+			    font       	(object Font
+				size       	10
+				face       	"Arial"
+				bold       	FALSE
+				italics    	FALSE
+				underline  	FALSE
+				strike     	FALSE
+				color      	0
+				default_color 	TRUE)
+			    quidu      	"3DFE4C2701C3"
+			    anchor_loc 	1
+			    nlines     	1
+			    max_width  	308
+			    justify    	0
+			    label      	"internalDoFilter()"
+			    pctDist    	0.500000
+			    height     	45
+			    orientation 	0)
+			line_color 	3342489
+			client     	@564
+			supplier   	@564
+			Focus_Src  	@566
+			Focus_Entry 	@567
+			origin     	(2080, 1872)
+			terminus   	(2230, 1872)
+			ordinal    	12)
+		    (object InterMessView "" @597
+			location   	(2144, 1984)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	FALSE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object SegLabel @598
+			    Parent_View 	@597
+			    location   	(2151, 1940)
+			    font       	(object Font
+				size       	10
+				face       	"Arial"
+				bold       	FALSE
+				italics    	FALSE
+				underline  	FALSE
+				strike     	FALSE
+				color      	0
+				default_color 	TRUE)
+			    quidu      	"3DFE4CA502BF"
+			    anchor_loc 	1
+			    nlines     	1
+			    max_width  	162
+			    justify    	0
+			    label      	"service()"
+			    pctDist    	0.500000
+			    height     	45
+			    orientation 	0)
+			line_color 	3342489
+			client     	@564
+			supplier   	@592
+			Focus_Src  	@566
+			Focus_Entry 	@594
+			origin     	(2079, 1984)
+			terminus   	(2224, 1984)
+			ordinal    	13)
+		    (object InterMessView "" @599
+			location   	(16, 2000)
+			font       	(object Font
+			    size       	10
+			    face       	"Arial"
+			    bold       	FALSE
+			    italics    	FALSE
+			    underline  	FALSE
+			    strike     	FALSE
+			    color      	0
+			    default_color 	TRUE)
+			label      	(object SegLabel @600
+			    Parent_View 	@599
+			    location   	(1904, 1956)
+			    font       	(object Font
+				size       	10
+				face       	"Arial"
+				bold       	FALSE
+				italics    	FALSE
+				underline  	FALSE
+				strike     	FALSE
+				color      	0
+				default_color 	TRUE)
+			    quidu      	"3DFE4CB4025B"
+			    anchor_loc 	1
+			    nlines     	1
+			    max_width  	113
+			    justify    	0
+			    label      	"return"
+			    pctDist    	0.500000
+			    height     	45
+			    orientation 	1)
+			line_color 	3342489
+			client     	@564
+			supplier   	@560
+			Focus_Src  	@566
+			Focus_Entry 	@563
+			origin     	(2048, 2000)
+			terminus   	(1760, 2000)
+			ordinal    	14)))))
+    root_subsystem 	(object SubSystem "Component View"
+	quid       	"3DFDF6CE036A"
+	physical_models 	(list unit_reference_list)
+	physical_presentations 	(list unit_reference_list
+	    (object Module_Diagram "Main"
+		quid       	"3DFDF6D201FD"
+		title      	"Main"
+		zoom       	100
+		max_height 	28350
+		max_width  	21600
+		origin_x   	0
+		origin_y   	0
+		items      	(list diagram_item_list))))
+    process_structure 	(object Processes
+	quid       	"3DFDF6CE0373"
+	ProcsNDevs 	(list
+	    (object Process_Diagram "Deployment View"
+		quid       	"3DFDF6CE0387"
+		title      	"Deployment View"
+		zoom       	100
+		max_height 	28350
+		max_width  	21600
+		origin_x   	0
+		origin_y   	0
+		items      	(list diagram_item_list))))
+    properties 	(object Properties
+	attributes 	(list Attribute_Set
+	    (object Attribute
+		tool       	"Data Modeler"
+		name       	"propertyId"
+		value      	"809135966")
+	    (object Attribute
+		tool       	"Data Modeler"
+		name       	"default__Project"
+		value      	(list Attribute_Set
+		    (object Attribute
+			tool       	"Data Modeler"
+			name       	"project"
+			value      	"")
+		    (object Attribute
+			tool       	"Data Modeler"
+			name       	"TableCounter"
+			value      	0)
+		    (object Attribute
+			tool       	"Data Modeler"
+			name       	"ViewCounter"
+			value      	0)
+		    (object Attribute
+			tool       	"Data Modeler"
+			name       	"DomainCounter"
+			value      	0)
+		    (object Attribute
+			tool       	"Data Modeler"
+			name       	"SPPackageCounter"
+			value      	0)
+		    (object Attribute
+			tool       	"Data Modeler"
+			name       	"TriggerCounter"
+			value      	0)
+		    (object Attribute
+			tool       	"Data Modeler"
+			name       	"IndexCounter"
+			value      	0)
+		    (object Attribute
+			tool       	"Data Modeler"
+			name       	"ConstraintCounter"
+			value      	0)
+		    (object Attribute
+			tool       	"Data Modeler"
+			name       	"StoreProcedureCounter"
+			value      	0)
+		    (object Attribute
+			tool       	"Data Modeler"
+			name       	"PrimaryKeyCounter"
+			value      	0)
+		    (object Attribute
+			tool       	"Data Modeler"
+			name       	"ForeignKeyCounter"
+			value      	0)
+		    (object Attribute
+			tool       	"Data Modeler"
+			name       	"JoinCounter"
+			value      	0)
+		    (object Attribute
+			tool       	"Data Modeler"
+			name       	"TableSpaceCounter"
+			value      	0)
+		    (object Attribute
+			tool       	"Data Modeler"
+			name       	"cONTAINERCounter"
+			value      	0)
+		    (object Attribute
+			tool       	"Data Modeler"
+			name       	"TablePrefix"
+			value      	"")
+		    (object Attribute
+			tool       	"Data Modeler"
+			name       	"ViewPrefix"
+			value      	"")
+		    (object Attribute
+			tool       	"Data Modeler"
+			name       	"DomainPrefix"
+			value      	"")
+		    (object Attribute
+			tool       	"Data Modeler"
+			name       	"TriggerPrefix"
+			value      	"")
+		    (object Attribute
+			tool       	"Data Modeler"
+			name       	"IndexPrefix"
+			value      	"")
+		    (object Attribute
+			tool       	"Data Modeler"
+			name       	"ConstraintPrefix"
+			value      	"")
+		    (object Attribute
+			tool       	"Data Modeler"
+			name       	"StoreProcedurePrefix"
+			value      	"")
+		    (object Attribute
+			tool       	"Data Modeler"
+			name       	"PrimaryKeyPrefix"
+			value      	"")
+		    (object Attribute
+			tool       	"Data Modeler"
+			name       	"ForeignKeyPrefix"
+			value      	"")
+		    (object Attribute
+			tool       	"Data Modeler"
+			name       	"TableSpacePrefix"
+			value      	"")))
+	    (object Attribute
+		tool       	"Data Modeler"
+		name       	"default__Module-Spec"
+		value      	(list Attribute_Set
+		    (object Attribute
+			tool       	"Data Modeler"
+			name       	"dmItem"
+			value      	FALSE)
+		    (object Attribute
+			tool       	"Data Modeler"
+			name       	"DMName"
+			value      	"")
+		    (object Attribute
+			tool       	"Data Modeler"
+			name       	"IsDatabase"
+			value      	FALSE)
+		    (object Attribute
+			tool       	"Data Modeler"
+			name       	"TargetDatabase"
+			value      	"")
+		    (object Attribute
+			tool       	"Data Modeler"
+			name       	"Location"
+			value      	"")
+		    (object Attribute
+			tool       	"Data Modeler"
+			name       	"IsTableSpace"
+			value      	FALSE)
+		    (object Attribute
+			tool       	"Data Modeler"
+			name       	"TableSpaceType"
+			value      	"")
+		    (object Attribute
+			tool       	"Data Modeler"
+			name       	"IsDeault"
+			value      	FALSE)
+		    (object Attribute
+			tool       	"Data Modeler"
+			name       	"BufferPool"
+			value      	"")
+		    (object Attribute
+			tool       	"Data Modeler"
+			name       	"ExtentSize"
+			value      	1)
+		    (object Attribute
+			tool       	"Data Modeler"
+			name       	"PrefetchSize"
+			value      	1)
+		    (object Attribute
+			tool       	"Data Modeler"
+			name       	"PageSize"
+			value      	4)
+		    (object Attribute
+			tool       	"Data Modeler"
+			name       	"ManagedBy"
+			value      	"")
+		    (object Attribute
+			tool       	"Data Modeler"
+			name       	"ContainerList"
+			value      	"")))
+	    (object Attribute
+		tool       	"Data Modeler"
+		name       	"default__Category"
+		value      	(list Attribute_Set
+		    (object Attribute
+			tool       	"Data Modeler"
+			name       	"dmItem"
+			value      	FALSE)
+		    (object Attribute
+			tool       	"Data Modeler"
+			name       	"DMName"
+			value      	"")
+		    (object Attribute
+			tool       	"Data Modeler"
+			name       	"dmSchema"
+			value      	"")
+		    (object Attribute
+			tool       	"Data Modeler"
+			name       	"dmDomainPackage"
+			value      	"")
+		    (object Attribute
+			tool       	"Data Modeler"
+			name       	"IsSchema"
+			value      	FALSE)
+		    (object Attribute
+			tool       	"Data Modeler"
+			name       	"IsDomainPackage"
+			value      	FALSE)
+		    (object Attribute
+			tool       	"Data Modeler"
+			name       	"IsRootSchema"
+			value      	FALSE)
+		    (object Attribute
+			tool       	"Data Modeler"
+			name       	"IsRootDomainPackage"
+			value      	FALSE)
+		    (object Attribute
+			tool       	"Data Modeler"
+			name       	"IsSchemaPackage"
+			value      	FALSE)
+		    (object Attribute
+			tool       	"Data Modeler"
+			name       	"DatabaseID"
+			value      	"")
+		    (object Attribute
+			tool       	"Data Modeler"
+			name       	"DBMS"
+			value      	"")))
+	    (object Attribute
+		tool       	"Data Modeler"
+		name       	"default__Class"
+		value      	(list Attribute_Set
+		    (object Attribute
+			tool       	"Data Modeler"
+			name       	"dmItem"
+			value      	FALSE)
+		    (object Attribute
+			tool       	"Data Modeler"
+			name       	"DMName"
+			value      	"")
+		    (object Attribute
+			tool       	"Data Modeler"
+			name       	"IsTable"
+			value      	FALSE)
+		    (object Attribute
+			tool       	"Data Modeler"
+			name       	"IsView"
+			value      	FALSE)
+		    (object Attribute
+			tool       	"Data Modeler"
+			name       	"IsDomain"
+			value      	FALSE)
+		    (object Attribute
+			tool       	"Data Modeler"
+			name       	"IsSPPackage"
+			value      	FALSE)
+		    (object Attribute
+			tool       	"Data Modeler"
+			name       	"Synonymns"
+			value      	"")
+		    (object Attribute
+			tool       	"Data Modeler"
+			name       	"TableSpaceID"
+			value      	"")
+		    (object Attribute
+			tool       	"Data Modeler"
+			name       	"SourceId"
+			value      	"")
+		    (object Attribute
+			tool       	"Data Modeler"
+			name       	"SourceType"
+			value      	"")
+		    (object Attribute
+			tool       	"Data Modeler"
+			name       	"CorrelationName"
+			value      	"")
+		    (object Attribute
+			tool       	"Data Modeler"
+			name       	"SelectClause"
+			value      	"")
+		    (object Attribute
+			tool       	"Data Modeler"
+			name       	"IsUpdateable"
+			value      	TRUE)
+		    (object Attribute
+			tool       	"Data Modeler"
+			name       	"CheckOption"
+			value      	"None")
+		    (object Attribute
+			tool       	"Data Modeler"
+			name       	"IsSnapShot"
+			value      	FALSE)
+		    (object Attribute
+			tool       	"Data Modeler"
+			name       	"IsDistinct"
+			value      	FALSE)
+		    (object Attribute
+			tool       	"Data Modeler"
+			name       	"PersistToServer"
+			value      	"")
+		    (object Attribute
+			tool       	"Data Modeler"
+			name       	"IsPackage"
+			value      	FALSE)))
+	    (object Attribute
+		tool       	"Data Modeler"
+		name       	"default__Attribute"
+		value      	(list Attribute_Set
+		    (object Attribute
+			tool       	"Data Modeler"
+			name       	"dmItem"
+			value      	FALSE)
+		    (object Attribute
+			tool       	"Data Modeler"
+			name       	"DMName"
+			value      	"")
+		    (object Attribute
+			tool       	"Data Modeler"
+			name       	"Ordinal"
+			value      	0)
+		    (object Attribute
+			tool       	"Data Modeler"
+			name       	"IsIdentity"
+			value      	FALSE)
+		    (object Attribute
+			tool       	"Data Modeler"
+			name       	"IsUnique"
+			value      	FALSE)
+		    (object Attribute
+			tool       	"Data Modeler"
+			name       	"NullsAllowed"
+			value      	FALSE)
+		    (object Attribute
+			tool       	"Data Modeler"
+			name       	"Length"
+			value      	0)
+		    (object Attribute
+			tool       	"Data Modeler"
+			name       	"Scale"
+			value      	0)
+		    (object Attribute
+			tool       	"Data Modeler"
+			name       	"ColumnType"
+			value      	"Native")
+		    (object Attribute
+			tool       	"Data Modeler"
+			name       	"ForBitData"
+			value      	FALSE)
+		    (object Attribute
+			tool       	"Data Modeler"
+			name       	"DefaultValueType"
+			value      	"")
+		    (object Attribute
+			tool       	"Data Modeler"
+			name       	"DefaultValue"
+			value      	"")
+		    (object Attribute
+			tool       	"Data Modeler"
+			name       	"SourceId"
+			value      	"")
+		    (object Attribute
+			tool       	"Data Modeler"
+			name       	"SourceType"
+			value      	"")
+		    (object Attribute
+			tool       	"Data Modeler"
+			name       	"OID"
+			value      	FALSE)))
+	    (object Attribute
+		tool       	"Data Modeler"
+		name       	"default__Association"
+		value      	(list Attribute_Set
+		    (object Attribute
+			tool       	"Data Modeler"
+			name       	"dmItem"
+			value      	FALSE)
+		    (object Attribute
+			tool       	"Data Modeler"
+			name       	"DMName"
+			value      	"")
+		    (object Attribute
+			tool       	"Data Modeler"
+			name       	"IsRelationship"
+			value      	FALSE)
+		    (object Attribute
+			tool       	"Data Modeler"
+			name       	"SourceId"
+			value      	"")
+		    (object Attribute
+			tool       	"Data Modeler"
+			name       	"SourceType"
+			value      	"")
+		    (object Attribute
+			tool       	"Data Modeler"
+			name       	"RIMethod"
+			value      	"")
+		    (object Attribute
+			tool       	"Data Modeler"
+			name       	"ParentUpdateRule"
+			value      	"")
+		    (object Attribute
+			tool       	"Data Modeler"
+			name       	"ParentUpdateRuleName"
+			value      	"")
+		    (object Attribute
+			tool       	"Data Modeler"
+			name       	"ParentDeleteRule"
+			value      	"")
+		    (object Attribute
+			tool       	"Data Modeler"
+			name       	"ParentDeleteRuleName"
+			value      	"")
+		    (object Attribute
+			tool       	"Data Modeler"
+			name       	"ChildInsertRestrict"
+			value      	FALSE)
+		    (object Attribute
+			tool       	"Data Modeler"
+			name       	"ChildInsertRestrictName"
+			value      	"")
+		    (object Attribute
+			tool       	"Data Modeler"
+			name       	"ChildMultiplicity"
+			value      	FALSE)
+		    (object Attribute
+			tool       	"Data Modeler"
+			name       	"ChildMultiplicityName"
+			value      	"")))
+	    (object Attribute
+		tool       	"Data Modeler"
+		name       	"default__Role"
+		value      	(list Attribute_Set
+		    (object Attribute
+			tool       	"Data Modeler"
+			name       	"dmItem"
+			value      	FALSE)
+		    (object Attribute
+			tool       	"Data Modeler"
+			name       	"DMName"
+			value      	"")
+		    (object Attribute
+			tool       	"Data Modeler"
+			name       	"ConstraintName"
+			value      	"")))
+	    (object Attribute
+		tool       	"Data Modeler"
+		name       	"default__Operation"
+		value      	(list Attribute_Set
+		    (object Attribute
+			tool       	"Data Modeler"
+			name       	"dmItem"
+			value      	FALSE)
+		    (object Attribute
+			tool       	"Data Modeler"
+			name       	"DMName"
+			value      	"")
+		    (object Attribute
+			tool       	"Data Modeler"
+			name       	"IsConstraint"
+			value      	FALSE)
+		    (object Attribute
+			tool       	"Data Modeler"
+			name       	"ConstraintType"
+			value      	"")
+		    (object Attribute
+			tool       	"Data Modeler"
+			name       	"IsIndex"
+			value      	FALSE)
+		    (object Attribute
+			tool       	"Data Modeler"
+			name       	"IsTrigger"
+			value      	FALSE)
+		    (object Attribute
+			tool       	"Data Modeler"
+			name       	"IsStoredProcedure"
+			value      	FALSE)
+		    (object Attribute
+			tool       	"Data Modeler"
+			name       	"IsCluster"
+			value      	FALSE)
+		    (object Attribute
+			tool       	"Data Modeler"
+			name       	"TableSpace"
+			value      	"")
+		    (object Attribute
+			tool       	"Data Modeler"
+			name       	"FillFactor"
+			value      	0)
+		    (object Attribute
+			tool       	"Data Modeler"
+			name       	"KeyList"
+			value      	"")
+		    (object Attribute
+			tool       	"Data Modeler"
+			name       	"CheckPredicate"
+			value      	"")
+		    (object Attribute
+			tool       	"Data Modeler"
+			name       	"IsUnique"
+			value      	FALSE)
+		    (object Attribute
+			tool       	"Data Modeler"
+			name       	"DeferalMode"
+			value      	"")
+		    (object Attribute
+			tool       	"Data Modeler"
+			name       	"InitialCheckTime"
+			value      	"")
+		    (object Attribute
+			tool       	"Data Modeler"
+			name       	"TriggerType"
+			value      	"")
+		    (object Attribute
+			tool       	"Data Modeler"
+			name       	"IsInsertEvent"
+			value      	FALSE)
+		    (object Attribute
+			tool       	"Data Modeler"
+			name       	"IsUpdateEvent"
+			value      	FALSE)
+		    (object Attribute
+			tool       	"Data Modeler"
+			name       	"IsDeleteEvent"
+			value      	FALSE)
+		    (object Attribute
+			tool       	"Data Modeler"
+			name       	"RefOldTable"
+			value      	"")
+		    (object Attribute
+			tool       	"Data Modeler"
+			name       	"RefNewTable"
+			value      	"")
+		    (object Attribute
+			tool       	"Data Modeler"
+			name       	"RefOldRow"
+			value      	"")
+		    (object Attribute
+			tool       	"Data Modeler"
+			name       	"RefNewRow"
+			value      	"")
+		    (object Attribute
+			tool       	"Data Modeler"
+			name       	"IsRow"
+			value      	FALSE)
+		    (object Attribute
+			tool       	"Data Modeler"
+			name       	"WhenClause"
+			value      	"")
+		    (object Attribute
+			tool       	"Data Modeler"
+			name       	"Language"
+			value      	"SQL")
+		    (object Attribute
+			tool       	"Data Modeler"
+			name       	"ProcType"
+			value      	"Procedure")
+		    (object Attribute
+			tool       	"Data Modeler"
+			name       	"IsDeterministic"
+			value      	FALSE)
+		    (object Attribute
+			tool       	"Data Modeler"
+			name       	"ParameterStyle"
+			value      	"")
+		    (object Attribute
+			tool       	"Data Modeler"
+			name       	"ReturnedNull"
+			value      	FALSE)
+		    (object Attribute
+			tool       	"Data Modeler"
+			name       	"ExternalName"
+			value      	"")
+		    (object Attribute
+			tool       	"Data Modeler"
+			name       	"Length"
+			value      	"")
+		    (object Attribute
+			tool       	"Data Modeler"
+			name       	"Scale"
+			value      	"")
+		    (object Attribute
+			tool       	"Data Modeler"
+			name       	"ForBitData"
+			value      	FALSE)
+		    (object Attribute
+			tool       	"Data Modeler"
+			name       	"DefaultValue"
+			value      	"")
+		    (object Attribute
+			tool       	"Data Modeler"
+			name       	"DefaultValueType"
+			value      	"")))
+	    (object Attribute
+		tool       	"Data Modeler"
+		name       	"default__Parameter"
+		value      	(list Attribute_Set
+		    (object Attribute
+			tool       	"Data Modeler"
+			name       	"dmItem"
+			value      	FALSE)
+		    (object Attribute
+			tool       	"Data Modeler"
+			name       	"DMName"
+			value      	"")
+		    (object Attribute
+			tool       	"Data Modeler"
+			name       	"IsInParameter"
+			value      	TRUE)
+		    (object Attribute
+			tool       	"Data Modeler"
+			name       	"IsOutParameter"
+			value      	FALSE)
+		    (object Attribute
+			tool       	"Data Modeler"
+			name       	"Ordinal"
+			value      	"")
+		    (object Attribute
+			tool       	"Data Modeler"
+			name       	"Length"
+			value      	"")
+		    (object Attribute
+			tool       	"Data Modeler"
+			name       	"Scale"
+			value      	"")
+		    (object Attribute
+			tool       	"Data Modeler"
+			name       	"ForBitData"
+			value      	FALSE)
+		    (object Attribute
+			tool       	"Data Modeler"
+			name       	"DefaultValueType"
+			value      	"")
+		    (object Attribute
+			tool       	"Data Modeler"
+			name       	"DefaultValue"
+			value      	"")
+		    (object Attribute
+			tool       	"Data Modeler"
+			name       	"OperationID"
+			value      	"")))
+	    (object Attribute
+		tool       	"Data Modeler"
+		name       	"HiddenTool"
+		value      	FALSE)
+	    (object Attribute
+		tool       	"Data Modeler Communicator"
+		name       	"HiddenTool"
+		value      	FALSE)
+	    (object Attribute
+		tool       	"Deploy"
+		name       	"HiddenTool"
+		value      	FALSE)
+	    (object Attribute
+		tool       	"Rose Model Integrator"
+		name       	"HiddenTool"
+		value      	FALSE)
+	    (object Attribute
+		tool       	"Rose Web Publisher"
+		name       	"HiddenTool"
+		value      	FALSE)
+	    (object Attribute
+		tool       	"Web Modeler"
+		name       	"HiddenTool"
+		value      	FALSE))
+	quid       	"3DFDF6CE0374"))

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/architecture/requestProcess.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/architecture/requestProcess.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/architecture/requestProcess.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,53 @@
+<?xml version="1.0"?>
+<!DOCTYPE document [
+  <!ENTITY project SYSTEM "project.xml">
+]>
+<document url="requestProcess.html">
+
+  &project;
+
+  <properties>
+    <author email="yoavs at apache.org">Yoav Shapira</author>
+    <title>Request Process Flow</title>
+  </properties>
+
+<body>
+
+
+<section name="Request Process Flow">
+
+<p>
+This page describes the process used by Tomcat to handle
+an incoming request.  This process is largely defined by
+the Servlet Specification, which outlines the order
+of events that must take place.
+</p>
+
+<subsection name="description">
+<p>
+TODO
+</p>
+</subsection>
+
+<subsection name="diagram">
+<p>
+A UML sequence diagram of the request process is available
+<a href="requestProcess/requestProcess.pdf">here.</a>
+</p>
+</subsection>
+
+<subsection name="comments">
+<p>
+The Servlet Specification provides many opportunities for
+listening in (using Listeners) or modiying (using Filters)
+the request handling process even before the request arrives
+at the servlet that will handle it.
+</p>
+
+</subsection>
+
+</section>
+
+
+</body>
+</document>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/architecture/startup/serverStartup.pdf
===================================================================
(Binary files differ)


Property changes on: branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/architecture/startup/serverStartup.pdf
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/architecture/startup/serverStartup.txt
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/architecture/startup/serverStartup.txt	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/architecture/startup/serverStartup.txt	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,136 @@
+Tomcat 5 Startup Sequence
+
+Sequence 1. Start from Command Line
+Class: org.apache.catalina.startup.Bootstrap
+What it does:
+	a) Set up classloaders 
+		commonLoader (common)-> System Loader
+		sharedLoader (shared)-> commonLoader -> System Loader
+		catalinaLoader(server) -> commonLoader -> System Loader
+	b) Load startup class (reflection)
+		org.apache.catalina.startup.Catalina
+		setParentClassloader -> sharedLoader
+		Thread.contextClassloader -> catalinaLoader
+	c) Bootstrap.daemon.init() complete
+	
+Sequence 2. Process command line argument (start, startd, stop, stopd)
+Class: org.apache.catalina.startup.Bootstrap (assume command->start)
+What it does: 
+	a) Catalina.setAwait(true);
+	b) Catalina.load()
+		b1) initDirs() -> set properties like 
+		                  catalina.home
+		                  catalina.base == catalina.home (most cases)
+		b2) initNaming
+			setProperty(javax.naming.Context.INITIAL_CONTEXT_FACTORY,
+				    org.apache.naming.java.javaURLContextFactory ->default)
+		b3) createStartDigester() 
+			Configures a digester for the main server.xml elements like
+			org.apache.catalina.core.StandardServer (can change of course :)
+			org.apache.catalina.deploy.NamingResources
+				Stores naming resources in the J2EE JNDI tree
+			org.apache.catalina.LifecycleListener
+				implements events for start/stop of major components
+			org.apache.catalina.core.StandardService
+				The single entry for a set of connectors,
+				so that a container can listen to multiple connectors
+				ie, single entry
+			org.apache.coyote.tomcat5.CoyoteConnector
+				Connectors to listen for incoming requests only
+			It also adds the following rulesets to the digester
+				NamingRuleSet
+				EngineRuleSet
+				HostRuleSet
+				ContextRuleSet
+		b4) Load the server.xml and parse it using the digester
+		    Parsing the server.xml using the digester is an automatic
+		    XML-object mapping tool, that will create the objects defined in server.xml
+		    Startup of the actual container has not started yet.
+		b5) Assigns System.out and System.err to the SystemLogHandler class
+		b6) Calls intialize on all components, this makes each object register itself with the 
+		    JMX agent.
+		    During the process call the Connectors also initialize the adapters.
+		    The adapters are the components that do the request pre-processing.
+		    Typical adapters are HTTP1.1 (default if no protocol is specified,
+		    org.apache.coyote.http11.Http11Protocol)
+		    AJP1.3 for mod_jk etc.
+
+	c) Catalina.start()
+		c1) Starts the NamingContext and binds all JNDI references into it
+		c2) Starts the services under <Server> which are:
+			StandardService -> starts Engine (ContainerBase ->Logger,Loader,Realm,Cluster etc)
+		c3) StandardHost (started by the service)
+				Configures a ErrorReportValvem to do proper HTML output for different HTTP 
+				errors codes
+				Starts the Valves in the pipeline (at least the ErrorReportValve)
+				Configures the StandardHostValve, 
+					this valves ties the Webapp Class loader to the thread context
+					it also finds the session for the request
+					and invokes the context pipeline
+				Starts the HostConfig component
+					This component deploys all the webapps
+						(webapps & conf/Catalina/localhost/*.xml)
+					Webapps are installed using the deployer (StandardHostDeployer)
+					The deployer will create a Digester for your context, this digester
+					will then invoke ContextConfig.start()
+						The ContextConfig.start() will process the default web.xml (conf/web.xml)
+						and then process the applications web.xml (WEB-INF/web.xml)
+						
+		c4) During the lifetime of the container (StandardEngine) there is a background thread that 
+		    keeps checking if the context has changed. If a context changes (timestamp of war file, 
+		    context xml file, web.xml) then a reload is issued (stop/remove/deploy/start)
+		    
+	d) Tomcat receives a request on an HTTP port
+	    d1) The request is received by a separate thread which is waiting in the PoolTcpEndPoint 
+	         class. It is waiting for a request in a regular ServerSocket.accept() method.
+	         When a request is received, this thread wakes up.
+	    d2) The PoolTcpEndPoint assigns the a TcpConnection to handle the request. 
+	        It also supplies a JMX object name to the catalina container (not used I believe)
+	    d3) The processor to handle the request in this case is Coyote Http11Processor, 
+	        and the process method is invoked.
+	        This same processor is also continuing to check the input stream of the socket
+	        until the keep alive point is reached or the connection is disconnected.
+	    d4) The HTTP request is parsed using an internal buffer class (Coyote Http11 Internal Buffer)
+	        The buffer class parses the request line, the headers, etc and store the result in a 
+	        Coyote request (not an HTTP request) This request contains all the HTTP info, such
+	        as servername, port, scheme, etc.
+	    d5) The processor contains a reference to an Adapter, in this case it is the 
+	        Coyote Tomcat 5 Adapter. Once the request has been parsed, the Http11 processor
+	        invokes service() on the adapter. In the service method, the Request contains a 
+	        CoyoteRequest and CoyoteRespons (null for the first time)
+	        The CoyoteRequest(Response) implements HttpRequest(Response) and HttpServletRequest(Response)
+	        The adapter parses and associates everything with the request, cookies, the context through a 
+	        Mapper, etc
+	    d6) When the parsing is finished, the CoyoteAdapter invokes its container (StandardEngine)
+	        and invokes the invoke(request,response) method.
+	        This initiates the HTTP request into the Catalina container starting at the engine level
+	    d7) The StandardEngine.invoke() simply invokes the container pipeline.invoke()
+	    d8) By default the engine only has one valve the StandardEngineValve, this valve simply
+	        invokes the invoke() method on the Host pipeline (StandardHost.getPipeLine())
+	    d9) the StandardHost has two valves by default, the StandardHostValve and the ErrorReportValve
+	    d10) The standard host valve associates the correct class loader with the current thread
+	         It also retrives the Manager and the session associated with the request (if there is one)
+	         If there is a session access() is called to keep the session alive
+	    d11) After that the StandardHostValve invokes the pipeline on the context associated
+	         with the request.
+	    d12) The first valve that gets invoked by the Context pipeline is the FormAuthenticator
+	         valve. Then the StandardContextValve gets invoke.
+	         The StandardContextValve invokes any context listeners associated with the context.
+	         Next it invokes the pipeline on the Wrapper component (StandardWrapperValve)
+	    d13) During the invokation of the StandardWrapperValve, the JSP wrapper (Jasper) gets invoked
+	         This results in the actual compilation of the JSP.
+	         And then invokes the actual servlet.
+	e) Invokation of the servlet class
+	         
+	         
+	         
+	    
+	        
+	        
+	        
+	    
+			
+			
+		
+		
+			

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/architecture/startup.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/architecture/startup.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/architecture/startup.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,57 @@
+<?xml version="1.0"?>
+<!DOCTYPE document [
+  <!ENTITY project SYSTEM "project.xml">
+]>
+<document url="startup.html">
+
+  &project;
+
+  <properties>
+    <author email="yoavs at apache.org">Yoav Shapira</author>
+    <title>Startup</title>
+  </properties>
+
+<body>
+
+
+<section name="Server Startup">
+
+<p>
+This page describes how the Tomcat server starts up.  There are several
+different ways to start tomcat, including:
+<ul>
+  <li>From the command line.</li>
+  <li>From a Java program as an embedded server.</li>
+  <li>Automatically as a Windows service.</li>
+</ul>
+</p>
+
+<subsection name="description">
+<p>
+A text description of the startup procedure is available
+<a href="startup/serverStartup.txt">here.</a>
+</p>
+</subsection>
+
+<subsection name="diagram">
+<p>
+A UML sequence diagram of the startup procedure is available
+<a href="startup/serverStartup.pdf">here.</a>
+</p>
+</subsection>
+
+<subsection name="comments">
+<p>
+The startup process can be customized in many ways, both
+by modifying Tomcat code and by implementing your own
+LifecycleListeners which are then registered in the server.xml
+configuration file.
+</p>
+
+</subsection>
+
+</section>
+
+
+</body>
+</document>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/balancer-howto.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/balancer-howto.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/balancer-howto.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,148 @@
+<?xml version="1.0"?>
+<!DOCTYPE document [
+  <!ENTITY project SYSTEM "project.xml">
+]>
+<document url="balancer-howto.html">
+
+    &project; 
+
+    <properties>
+        <author email="yoavs at apache.org">Yoav Shapira</author>
+        <author>Remy Maucherat</author>
+        <author>Andy Oliver</author>
+        <title>Load Balancer HOW-TO</title>
+    </properties>
+
+<body>
+
+<section name="Table of Contents">
+<p>
+<a href="#Using the JK 1.2.x native connector">
+Using the JK native connector</a><br />
+<a href="#Using Apache HTTP Server 2.x with mod_proxy">
+Using Apache HTTP Server 2.x and mod_proxy</a><br />
+<a href="#Using the balancer webapp">Using the balancer webapp</a><br />
+</p>
+</section>
+
+<section name="Using the JK 1.2.x native connector">
+
+Please refer to the JK 1.2.x documentation.
+
+</section>
+
+<section name="Using Apache HTTP Server 2.x with mod_proxy">
+
+Please refer to the mod_proxy documentation for Apache HTTP Server 2.2. This supports either
+HTTP or AJP load balancing. This new version of mod_proxy is also useable with
+Apache HTTP Server 2.0, but mod_proxy will have to be compiled separately using the code
+from Apache HTTP Server 2.2.
+
+</section>
+
+<section name="Using the balancer webapp">
+
+<subsection name="Overview">
+
+<p>
+Tomcat 5.0.15 and later ships with a webapp named balancer.  This is
+a simple implemention of a rules-based load balancer.  It was not designed
+as a replacement for other load-balancing mechanisms used for high traffic
+environments.  Rather, it is a simple, pure Java, easily extensible, and fast
+way to direct traffic among multiple servers.
+</p>
+<p>
+Although balancer ships with Tomcat, it is not Tomcat-specific and runs
+on other containers without any modification.  The balancer webapp 
+requires a Servlet Specification 2.3 or later container if you wish 
+to use a filter to redirect traffic.  If you wish to redirect traffic
+using a servlet, you may use any servlet container.
+</p>
+</subsection>
+
+<subsection name="Sample Configuration">
+<p>
+The default balancer installation uses a single filter, BalancerFilter,
+mapped to all requests (url-pattern /*).  The filter reads its rules
+from the location specified in the balancer deployment descriptor
+(web.xml file).  The default rules are:
+<ul>
+  <li>Redirect requests with News in the URL to www.cnn.com</li>
+  <li>Redirect requests with a parameter named paramName whose
+value is paramValue to www.yahoo.com.</li>
+  <li>Redirect all other requests to jakarta.apache.org.</li>
+</ul>
+
+Therefore, when you install tomcat, start it, and point your
+browser to http://localhost:8080/balancer, you will be redirected
+to http://jakarta.apache.org.  If you point your browser to
+http://localhost:8080/balancer/News you will be redirected to
+http://www.cnn.com.  The request for 
+http://localhost:8080/balancer/BlahBlah?paramName=paramValue will
+be redirected to http://www.yahoo.com.
+</p>
+</subsection>
+
+<subsection name="Balancer Rules">
+<p>
+A <i>Rule</i> in the balancer system is a combination of
+a request matching criterion and a redirection URL for
+matching requests.  Rules implement the
+org.apache.webapp.balancer.Rule interface.
+</p>
+
+<p>
+The balancer distribution contains a number of useful
+rules.  The framework is also designed for easy extensibility
+so that you can write your own rules quickly.  Rules
+should be JavaBeans (public no-args constructor, public
+setter method setXXX for property xxx), as they are
+instantiated by Jakarta Commons Digester.  Feel free
+to inquire on the tomcat-user mailing list regarding
+the availability of rules or the inclusion of your rules
+in the distribution.
+</p>
+
+<p>
+Rules are assembled into RuleChains.  Each BalancerFilter
+(or Servlet/JSP) refers to one RuleChain when making its
+redirection decisions.  Note that you are not restricted
+to having one filter mapped to /* as done in the sample
+configuration.  You can configure as many filters as
+desired, using the full filter mapping possibilities defined
+in the Servlet Specification.  Each filter will have
+its own RuleChain.
+</p>
+</subsection>
+
+<subsection name="How it Works">
+<p>
+<ol>
+  <li>You write a rules configuration file containing various
+rules and redirection locations.</li>
+  <li>You define the balancer filter in your web.xml, mapping
+it as desired (/* is a common use-case) and configuring it
+with your rules configuration file.</li>
+  <li>The server is started, initializing the filter.</li>
+  <li>A request comes into the server.  The filter consults
+its rule chain to determine where to redirect the request.  Rules
+are consulted in the order in which they are defined in the rules
+configuration file.  The first matching rule will stop the
+evaluation and cause the request to be redirected.</li>
+</ol>
+</p>
+
+</subsection>
+
+<subsection name="Comments">
+<p>
+Please direct questions, comments, suggestions, etc. to the
+tomcat-user mailing list.  Thank you.
+</p>
+</subsection>
+
+</section>
+
+</body>
+
+</document>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/build.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/build.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/build.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,240 @@
+<project name="tomcat-docs" default="build-main" basedir=".">
+
+
+  <!-- ===================== Initialize Property Values =================== -->
+
+  <!-- See "build.properties.sample" in the top level directory for all     -->
+  <!-- property values you must customize for successful building!!!        -->
+  <property file="build.properties"/>
+  <property file="../build.properties"/>
+  <property file="../../build.properties"/>
+  <property file="${user.home}/build.properties"/>
+
+  <property name="build.compiler"  value="modern"/>
+  <property name="webapps.build"   value="../build"/>
+  <property name="webapps.dist"    value="../dist"/>
+  <property name="webapp.name"     value="tomcat-docs"/>
+
+
+  <!-- =================== BUILD: Create Directories ====================== -->
+  <target name="build-prepare">
+    <mkdir dir="${webapps.build}"/>
+    <mkdir dir="${webapps.build}/${webapp.name}"/>
+  </target>
+
+
+  <!-- ================ BUILD: Copy Static Files ========================== -->
+  <target name="build-static" depends="build-prepare">
+
+    <!-- Top Level Static Files -->
+    <copy    todir="${webapps.build}/${webapp.name}">
+      <fileset dir="../..">
+        <include name="BUILDING.txt"/>
+        <include name="README.txt"/>
+        <include name="RUNNING.txt"/>
+      </fileset>
+    </copy>
+    <copy    todir="${webapps.build}/${webapp.name}">
+      <fileset dir="." includes="**/*.html"/>
+    </copy>
+
+    <!-- WEB-INF Static Files -->
+    <copy    todir="${webapps.build}/${webapp.name}/WEB-INF">
+      <fileset dir="WEB-INF"/>
+    </copy>
+
+    <!-- Application Developer's Guide Examples -->
+    <copy    todir="${webapps.build}/${webapp.name}/appdev">
+      <fileset dir="appdev" includes="*.txt"/>
+    </copy>
+
+    <!-- This copy includes a binary file (sample.war) so it should not have a filter token -->
+    <!-- See Bugzilla 36318: http://issues.apache.org/bugzilla/show_bug.cgi?id=36318 -->
+    <copy    todir="${webapps.build}/${webapp.name}/appdev/sample">
+      <fileset dir="appdev/sample"/>
+    </copy>
+
+    <copy   tofile="${webapps.build}/${webapp.name}/appdev/sample/build.xml"
+              file="appdev/build.xml.txt"/>
+
+    <!-- Catalina Functional Specifications -->
+    <mkdir     dir="${webapps.build}/${webapp.name}/catalina/funcspecs"/>
+
+    <!-- Architecture -->
+    <copy    todir="${webapps.build}/${webapp.name}/architecture">
+      <fileset dir="architecture" excludes="*.xml"/>
+    </copy>
+
+    <!-- Images Subdirectory -->
+    <mkdir     dir="${webapps.build}/${webapp.name}/images"/>
+    <copy    todir="${webapps.build}/${webapp.name}/images">
+      <fileset dir="images"/>
+    </copy>
+
+    <mkdir     dir="${webapps.build}/${webapp.name}/printer"/>
+    <!-- Top Level Static Files -->
+    <copy    todir="${webapps.build}/${webapp.name}/printer">
+      <fileset dir="../..">
+        <include name="BUILDING.txt"/>
+        <include name="README.txt"/>
+        <include name="RUNNING.txt"/>
+      </fileset>
+    </copy>
+    <style basedir="."
+           destdir="${webapps.build}/${webapp.name}/printer"
+         extension=".html"
+             style="tomcat-docs.xsl"
+          excludes="build.xml project.xml"
+          includes="*.xml">
+      <param name="relative-path" expression="./.."/>
+      <param name="project-menu" expression="nomenu"/>
+    </style>
+
+    <!-- WEB-INF Subdirectory -->
+    <mkdir     dir="${webapps.build}/${webapp.name}/WEB-INF"/>
+    <copy    todir="${webapps.build}/${webapp.name}/WEB-INF">
+      <fileset dir="WEB-INF"/>
+    </copy>
+
+  </target>
+
+
+  <!-- ================= BUILD: XML-HTML Generation ======================= -->
+  <target name="build-main" depends="build-static">
+
+    <!-- Top Level Directory -->
+    <style basedir="."
+           destdir="${webapps.build}/${webapp.name}"
+         extension=".html"
+             style="tomcat-docs.xsl"
+          excludes="build.xml project.xml"
+          includes="*.xml">
+      <param name="relative-path" expression="."/>
+    </style>
+
+    <!-- Application Developer's Guide -->
+    <style basedir="appdev"
+           destdir="${webapps.build}/${webapp.name}/appdev"
+         extension=".html"
+             style="tomcat-docs.xsl"
+          excludes="project.xml"
+          includes="*.xml">
+      <param name="relative-path" expression=".."/>
+    </style>
+    <mkdir     dir="${webapps.build}/${webapp.name}/appdev/printer"/>
+    <!-- Application Developer's Guide Examples -->
+    <copy    todir="${webapps.build}/${webapp.name}/appdev/printer">
+      <fileset dir="appdev" includes="*.txt"/>
+    </copy>
+    <style basedir="appdev"
+           destdir="${webapps.build}/${webapp.name}/appdev/printer"
+         extension=".html"
+             style="tomcat-docs.xsl"
+          excludes="project.xml"
+          includes="*.xml">
+      <param name="relative-path" expression="../.."/>
+      <param name="project-menu" expression="nomenu"/>
+    </style>
+
+    <!-- Catalina Functional Specifications -->
+    <mkdir     dir="${webapps.build}/${webapp.name}/catalina"/>
+    <mkdir     dir="${webapps.build}/${webapp.name}/catalina/funcspecs"/>
+    <style basedir="funcspecs"
+           destdir="${webapps.build}/${webapp.name}/catalina/funcspecs"
+         extension=".html"
+             style="tomcat-docs.xsl"
+          excludes="project.xml"
+          includes="*.xml">
+      <param name="relative-path" expression="../.."/>
+    </style>
+    <mkdir     dir="${webapps.build}/${webapp.name}/catalina/funcspecs/printer"/>
+    <style basedir="funcspecs"
+           destdir="${webapps.build}/${webapp.name}/catalina/funcspecs/printer"
+         extension=".html"
+             style="tomcat-docs.xsl"
+          excludes="project.xml"
+          includes="*.xml">
+      <param name="relative-path" expression="../../.."/>
+      <param name="project-menu" expression="nomenu"/>
+    </style>
+
+    <!-- Server Configuration Reference -->
+    <style basedir="config"
+           destdir="${webapps.build}/${webapp.name}/config"
+         extension=".html"
+             style="tomcat-docs.xsl"
+          excludes="project.xml"
+          includes="*.xml">
+      <param name="relative-path" expression=".."/>
+    </style>
+    <mkdir     dir="${webapps.build}/${webapp.name}/config/printer"/>
+    <style basedir="config"
+           destdir="${webapps.build}/${webapp.name}/config/printer"
+         extension=".html"
+             style="tomcat-docs.xsl"
+          excludes="project.xml"
+          includes="*.xml">
+      <param name="relative-path" expression="../.."/>
+      <param name="project-menu" expression="nomenu"/>
+    </style>
+
+    <!-- Server Architecture -->
+    <style basedir="architecture"
+           destdir="${webapps.build}/${webapp.name}/architecture"
+         extension=".html"
+             style="tomcat-docs.xsl"
+          excludes="project.xml"
+          includes="*.xml">
+      <param name="relative-path" expression=".."/>
+    </style>
+    <mkdir     dir="${webapps.build}/${webapp.name}/architecture/printer"/>
+    <style basedir="architecture"
+           destdir="${webapps.build}/${webapp.name}/architecture/printer"
+         extension=".html"
+             style="tomcat-docs.xsl"
+          excludes="project.xml"
+          includes="*.xml">
+      <param name="relative-path" expression="../.."/>
+      <param name="project-menu" expression="nomenu"/>
+    </style>
+
+  </target>
+
+
+  <!-- ==================== BUILD: Rebuild Everything ===================== -->
+  <target name="all" depends="build-clean,build-main"
+   description="Clean and build documentation webapp"/>
+
+
+  <!-- ======================= BUILD: Clean Directory ===================== -->
+  <target name="build-clean">
+    <delete dir="${webapps.build}/${webapp.name}"/>
+  </target>
+
+
+  <!-- ======================= DIST: Create Directories =================== -->
+  <target name="dist-prepare">
+    <mkdir dir="${webapps.dist}"/>
+  </target>
+
+
+  <!-- ======================= DIST: Create Distribution Files ============ -->
+  <target name="dist" depends="build-main,dist-prepare"
+   description="Create documentation webapp binary distribution">
+      <jar   jarfile="${webapps.dist}/${webapp.name}.war"
+             basedir="${webapps.build}/${webapp.name}" includes="**"/>
+  </target>
+
+
+  <!-- ======================= DIST: Clean Directory ====================== -->
+  <target name="dist-clean">
+    <delete dir="${webapps.dist}/${webapp.name}"/>
+  </target>
+
+
+  <!-- ====================== Convenient Synonyms ========================= -->
+  <target name="clean" depends="build-clean,dist-clean"
+   description="Clean build and dist directories"/>
+
+
+</project>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/building.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/building.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/building.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,231 @@
+<?xml version="1.0"?>
+<!DOCTYPE document [
+  <!ENTITY project SYSTEM "project.xml">
+]>
+<document>
+
+    &project;
+
+    <properties>
+      <author>Remy Maucherat</author>
+      <title>Building Tomcat</title>
+    </properties>
+
+<body>
+
+<section name="Introduction">
+
+<p>
+Building Tomcat from SVN is very easy, and is the first step to contributing to
+Tomcat. The following is a step by step TODO list.
+</p>
+
+</section>
+
+<section name="Download and install a Java Development Kit 1.4.x or later">
+
+<p>
+The default distribution of Tomcat 5.5.x requires a 5.0 or later JDK. Tomcat
+can be built using a 1.4.x JDK but you will need to copy the contents of the
+compat directory (created by the build process) to your build directory before
+Tomcat will start.
+</p>
+
+<p>
+The Sun JDK can be downloaded <a href="http://java.sun.com/j2se/">here</a>.
+</p>
+
+<p>
+<b>IMPORTANT</b>: Set an environment variable JAVA_HOME to the pathname of the 
+directory into which you installed the JDK release.
+</p>
+
+</section>
+
+<section name="Install Apache Ant 1.6.2 or later">
+
+<p>
+Download a binary distribution of Ant 1.6.2 or later from 
+<a href="http://ant.apache.org/bindownload.cgi">here</a>.
+</p>
+
+<p>
+Unpack the binary distribution into a convenient location so that the
+Ant release resides in its own directory (conventionally named
+"apache-ant-1.6.x").  For the purposes of the remainder of this document,
+the symbolic name "${ant.home}" is used to refer to the full pathname of
+ the release directory.
+</p>
+
+<p>
+Create an ANT_HOME environment variable to point the directory ${ant.home}, 
+and modify the PATH environment variable to include directory
+"${ant.home}/bin" in its list.  This makes the "ant" command line script
+available, which will be used to actually perform the build.
+</p>
+
+</section>
+
+<section name="Building Tomcat">
+
+<p>
+Download the main build.xml script from <a href="build.xml">here</a>.
+</p>
+
+<p>
+Create a new directory, and copy the newly download build.xml to it. This
+  directory will be referred to as the ${tomcat.source} directory in the rest
+  of this document.
+</p>
+
+<p>
+Go to that directory, and do:
+<code><br/>
+    cd ${tomcat.source}<br/>
+    ant<br/>
+</code>
+</p>
+
+<p>
+NOTE: Users accessing the Internet through a proxy must use a properties
+  file to indicate to Ant the proxy configuration. Read below.
+</p>
+
+<p>
+WARNING: Running this command will checkout the Tomcat 5 sources from SVN, as
+  well as download binaries to the <code>/usr/share/java</code> directory. 
+  Make sure this is appropriate to do so on your computer. On Windows, 
+  this usually corresponds to the <code>C:\usr\share\java</code> directory, 
+  unless Cygwin is used. Read below to customize the directory used 
+  to download the binaries.
+</p>
+
+<p>
+The build can be controlled by creating a ${tomcat.source}/build.properties
+  file, and adding the following content to it:
+<code><br/>
+    # ----- Proxy setup -----<br/>
+    # Uncomment if using a proxy server.<br/>
+    #proxy.host=proxy.domain<br/>
+    #proxy.port=8080<br/>
+    #proxy.use=on<br/>
+<br/>
+    # ----- Default Base Path for Dependent Packages -----<br/>
+    # Replace this path with the directory path where<br/>
+    # dependencies binaries should be downloaded.<br/>
+    base.path=/usr/share/java<br/>
+</code>
+</p>
+
+</section>
+
+<section name="Updating and rebuilding Tomcat sources">
+
+<p>
+It is recommended to regularly update the downloaded Tomcat 5 sources. 
+To do this, execute the following commands:
+
+<code><br/>
+    cd ${tomcat.source}<br/>
+    ant checkout<br/>
+</code>
+</p>
+
+<p>
+For a quick rebuild of only modified code you can use:
+<code><br/>
+    cd ${tomcat.source}<br/>
+    ant build<br/>
+</code>
+
+</p>
+
+</section>
+
+<section name="Building with Eclipse">
+
+<p>
+<b>Important:</b>
+This is not a supported means of building Tomcat; this information is
+provided without warranty :-).
+The only supported means of building Tomcat is with the "ant build"
+described above.
+However, some developers like to work on Java code with a Java IDE,
+and the following steps have been used by some developers.
+</p>
+
+<p>
+Note that you <b>must</b> complete all the above steps to fetch
+the repositories and build some JAR files the first time.
+After you have completed the above steps, you can set up a
+series of Eclipse 4 projects.
+<b>Note</b> that this will not let you build everything under Eclipse;
+the build process requires use of Ant for the many stages that aren't
+simple Java compilations.
+However, it will allow you to view and edit the Java code,
+get warnings, reformat code, perform refactorings, run Tomcat
+under the IDE, and so on.
+</p>
+
+<p>
+Use Windows-&gt;Preferences and then Java-&gt;Build Path-&gt;Classpath
+Variables to add two new Classpath variables:
+</p>
+
+<p>
+<table border="1">
+ <tr><td>TOMCAT_LIBS_BASE</td><td>the base path where the binary dependencies have been downloaded</td></tr>
+ <tr><td>ANT_HOME</td><td>the base path of Ant 1.6.2 or later</td></tr>
+</table>
+</p>
+
+<p>
+Use File-&gt;New Project to create a new Java project 
+for each of the binaries repository (e.g., /usr/share/java), 
+container, connectors, jasper, servletapi. 
+Unless you thought ahead to make the ${tomcat.source} directory be under
+your Workspace folder, tell Eclipse the external location using &quot;Import/Export...&quot;,
+General-&gt;Existing Project into Workspace.
+</p>
+
+<p>
+Eclipse .project and .classpath files are provided in each of these
+directories so Eclipse should find all source trees and jars, and
+hopefully compile without problems. <b>Note</b> that these
+files assume you are using Eclipse with a 5.0 or later JDK; also, the
+connectors module must be built with a compiler compliance level of 5.0.
+</p>
+
+<p>
+To run Tomcat without a special IDE plug-in, you can simply use Run-&gt;Run...
+enter "org.apache.catalina.startup.Catalina" as the main class,
+"start" as program arguments, and
+"-Dcatalina.home=..." (with the name of your build directory) 
+as VM arguments.
+</p>
+
+<p>
+Note also that due to the way the Tomcat source is assembled
+from several SVN projects, you may not be able to use the Eclipse
+SVN client to update (nor to commit, if you are a committer).
+Use the external SVN client of your choice, then use the
+Eclipse PackageExplorer or Navigator "Refresh" context menu item
+to tell Eclipse that you've updated the files.
+</p>
+
+</section>
+
+<section name="Building with other IDEs">
+<p>
+The same caveats apply as for Eclipse, above.
+</p>
+
+<p>
+The same general idea should work in most IDEs; it has been reported
+to work in Idea, for example.
+</p>
+
+</section>
+
+</body>
+</document>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/catalina/docs/api/index.html
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/catalina/docs/api/index.html	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/catalina/docs/api/index.html	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,17 @@
+<!doctype html public "-//w3c//dtd html 4.0 transitional//en" "http://www.w3.org/TR/REC-html40/strict.dtd">
+<html>
+    <head>
+    <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+    <title>Administration</title>
+</head>
+
+<body>
+
+Tomcat's internal javadoc is no longer installed by default. Download and install 
+the "fulldocs" package to get it.
+
+You can also access the javadoc online in the Tomcat 
+<a href="http://jakarta.apache.org/tomcat/tomcat-5.5-doc/">documentation bundle</a>.
+
+</body>
+</html>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/cgi-howto.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/cgi-howto.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/cgi-howto.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,76 @@
+<?xml version="1.0"?>
+<!DOCTYPE document [
+  <!ENTITY project SYSTEM "project.xml">
+]>
+<document url="cgi-howto.html">
+
+    &project;
+
+    <properties>
+        <author email="glenn at apache.org">Glenn L. Nielsen</author>
+        <title>CGI How To</title>
+    </properties>
+
+<body>
+
+<section name="Introduction">
+
+<p>The CGI (Common Gateway Interface) defines a way for a web server to
+interact with external content-generating programs, which are often
+referred to as CGI programs or CGI scripts.
+</p>
+
+<p>Within Tomcat, CGI support can be added when you are using Tomcat as your
+HTTP server and require CGI support.  Typically this is done
+during development when you don't want to run a web server like 
+Apache httpd.
+Tomcat's CGI support is largely compatible with Apache httpd's, 
+but there are some limitations (e.g., only one cgi-bin directory).
+</p>
+
+<p>CGI support is implemented using the servlet class
+<code>org.apache.catalina.servlets.CGIServlet</code>.  Traditionally,
+this servlet is mapped to the URL pattern "/cgi-bin/*".</p>
+
+<p>By default CGI support is disabled in Tomcat.</p>
+</section>
+
+<section name="Installation">
+
+<p><strong>CAUTION</strong> - CGI scripts are used to execute programs
+external to the Tomcat JVM. If you are using the Java SecurityManager this
+will bypass your security policy configuration in <code>catalina.policy.</code></p>
+
+<p>Rename <code>$CATALINA_BASE/server/lib/servlets-cgi.renametojar</code>
+to <code>$CATALINA_BASE/server/lib/servlets-cgi.jar</code>.</p>
+
+<p>Remove the XML comments from around the CGI servlet and servlet-mapping
+configuration in <code>$CATALINA_BASE/conf/web.xml</code>.</p>
+</section>
+
+<section name="Configuration">
+
+<p>There are several servlet init parameters which can be used to
+configure the behaviour of the CGI servlet.
+<ul>
+<li><strong>cgiPathPrefix</strong> - The CGI search path will start at
+the web application root directory + File.separator + this prefix.
+The default cgiPathPrefix is <code>WEB-INF/cgi</code></li>
+<li><strong>debug</strong> - Debugging detail level for messages logged
+by this servlet. Default 0.</li>
+<li><strong>executable</strong> - The of the executable to be used to
+run the script. Default is <code>perl</code>.</li>
+<li><strong>parameterEncoding</strong> - Name of the parameter encoding
+to be used with the GCI servlet. Default is
+<code>System.getProperty("file.encoding","UTF-8")</code>.</li>
+<li><strong>passShellEnvironment</strong> - Should the shell environment
+variables (if any) be passed to the CGI script? Default is
+<code>false</code>.</li>
+</ul>
+</p>
+
+</section>
+
+</body>
+
+</document>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/changelog.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/changelog.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/changelog.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,2987 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!DOCTYPE document [
+  <!ENTITY project SYSTEM "project.xml">
+]>
+<document url="changelog.html">
+
+  &project;
+
+  <properties>
+    <author email="remm at apache.org">Remy Maucherat</author>
+    <author email="yoavs at apache.org">Yoav Shapira</author>
+    <author email="fhanik at apache.org">Filip Hanik</author>
+    <title>Changelog</title>
+  </properties>
+
+<body>
+<section name="Tomcat 5.5.20 (fhanik)">
+  <subsection name="Catalina">
+    <changelog>
+      <fix>
+        Fix logic error in UserDatbaseRealm.getprincipal() that caused user
+        roles assigned via groups to be ignored. (markt)
+      </fix>
+    </changelog>
+  </subsection> 
+  <subsection name="Jasper">
+    <changelog>
+      <fix>
+        <bug>31804</bug>: Unnested tags within a tag file are now configured
+        with the Tag represented by the containing tag file as their parent
+        tag. (markt)
+      </fix>
+      <fix>
+        <bug>33356</bug>: Tag attributes that contained $ followed by 1 or
+        more non-special characters and then a { character caused an
+        exception. (markt)
+      </fix>
+      <fix>
+        <bug>33407</bug>: The string \$ in template text was reduced to $
+        when the isELIgnored page directive was set to true. (markt)
+      </fix>
+    </changelog>
+  </subsection>   
+</section>
+
+
+<section name="Tomcat 5.5.19 (fhanik)">
+  <subsection name="General">
+    <changelog>
+      <update>
+         Add multi attribute setting to jmx:set JMX remote ant task.
+         Patch contributed by Didier Donsez (pero)
+      </update>      
+    </changelog>
+  </subsection>
+  <subsection name="Catalina">
+    <changelog>
+      <fix>
+        <bug>30762</bug>: Re-fix this bug that was re-introduced by the fix
+        to <bug>37264</bug>. (markt)
+      </fix>
+      <fix>
+        <bug>37588</bug>: Fix JNDI realm creation through JMX. Patch contributed by TerryZhou  (fhanik)
+      </fix>
+      <fix>
+        <bug>39704</bug>: The use of custom classloaders failed when the context
+        was specified in server.xml. Correction of the fault will require setting
+        the new loader attribute useSystemClassLoaderAsParent to false. (markt)
+      </fix>
+    </changelog>
+  </subsection> 
+  <subsection name="Coyote">
+    <changelog>
+      <fix>
+        <bug>40418</bug>: APR Endpoint socket evaluation (remm)
+      </fix>
+  </changelog>
+  </subsection> 
+  <subsection name="Webapps">
+    <changelog>
+      <fix>
+        <bug>31339</bug>: Admin app threw exceptions if a name other than Catalina
+        was configured for the Engine. Patch based on a suggestion from Amila
+        Suriarachchi. (markt)
+      </fix>
+    </changelog>
+  </subsection> 
+</section>
+
+
+<section name="Tomcat 5.5.18 (yoavs)">
+  <subsection name="General">
+    <changelog>
+      <update>
+        Change MD5 release signature files to have md5 (lowercase) extension instead of MD5 (uppercase),
+        as suggested by Henk Penning and specified in the
+        <a href="http://www.apache.org/dev/release-publishing.html">ASF release publishing guidelines</a>. (yoavs)
+      </update>
+    </changelog>
+  </subsection>
+  <subsection name="Catalina">
+    <changelog>
+      <fix>
+        Fix that ManagerBase increment expireSessions counter at background task two times. (pero)
+      </fix>
+      <fix>
+        <bug>39406</bug>: Fix that StandardSession#getLastAccessedTime() uses correct exception message,
+        suggested by Takayoshi Kimura. (pero)
+      </fix>
+      <add>
+        <bug>39661</bug>: Add documentation on JULI FileHandler properties. (yoavs)
+      </add>
+      <add>
+        <bug>39657</bug>: Warn (and don't load jar) if JSP API is in webapp classloader repository, as suggested by
+          David Sanchez Crespillo. (yoavs)
+      </add>
+      <add>
+        <bug>39674</bug>: Support JRockit JVM in service.bat script, as suggested by lizongbo. (yoavs)
+      </add>
+      <fix>
+        <bug>39711</bug>: Update Loader configuration documentation, as suggested by Stephane Bailliez. (yoavs)
+      </fix>
+      <fix>
+        <bug>39865</bug>: Add Open Office mime types to conf/web.xml. (markt)
+      </fix>
+      <fix>
+        <bug>38814</bug>: Align CGI handling of indexed queries, parameters and
+        POST content with other CGI providers. The changes: only provide
+        parameters on the command line for indexed queries; always provide the
+        query string via the QUERY_STRING environment variable; provide POST
+        content unmodified to stdin; and never call getParameters(). (markt) 
+      </fix>
+      <fix>
+        <bug>34801</bug>: Partial fix that adds handling of IOExceptions during
+        long running CGI requests. Based on a patch by Chris Davey. (markt)
+      </fix>
+      <fix>
+        <bug>39689</bug>: Allow single quotes (') and backticks (`) as well as
+        double quotes (") to be used to delimit SSI attribute values. (markt)
+      </fix>
+      <fix>
+        <bug>40053</bug>: Correct application deployment documentation so it
+        agrees with the classloader documentation regarding shared lib and
+        CATALINA_BASE. (markt)
+      </fix>
+      <fix>
+        <bug>39592</bug>: Stop HEAD requests for resources handled by SSI
+        servlet or filter generating stack traces in the logs. (markt)
+      </fix>
+      <fix>
+        Improve handling of the ';' character in the URL so that it is now
+        allowed if properly %xx encoded. (remm)
+      </fix>
+  </changelog>
+  </subsection> 
+  <subsection name="Coyote">
+    <changelog>
+      <fix>
+        Fix APR endpoint so that the acceptor thread now only processes socket
+        accepts. (remm)
+      </fix>
+  </changelog>
+  </subsection> 
+  <subsection name="Webapps">
+    <changelog>
+      <fix>
+        <bug>39813</bug>: Correct handling of new line characters in JMX
+        attributes. Patch provided by R Bramley. (markt)
+      </fix>
+      <fix>
+        <bug>37781</bug>: Make sure that StoreConfig save external referenced war files at context.xml correct. (pero)
+      </fix>
+      <fix>
+        <bug>39791</bug>: Use correct default for useNaming within a Context. (markt)
+      </fix>
+      <fix>
+        Correctly generate re-direct for admin app index.jsp to prevent login page
+        being displayed twice when cookies are disabled. (markt)
+      </fix>
+    </changelog>
+  </subsection> 
+  <subsection name="Cluster">
+    <changelog>
+      <fix>
+        <bug>39473</bug>: Session timeout much shorter than setting
+         at web.xml at cluster environment, suggested by Jin Jiang. (pero)
+      </fix>
+    </changelog>
+  </subsection>   
+</section>
+
+<section name="Tomcat 5.5.17 (yoavs)">
+  <subsection name="General">
+    <changelog>
+      <update>
+        Update to Xerces 2.8.0 (remm)
+      </update>
+      <update>
+        Update to tcnative 1.1.3 (remm)
+      </update>
+    </changelog>
+  </subsection>
+  <subsection name="Catalina">
+    <changelog>
+      <fix>
+        Fix SingleSignOn Valve and add Session.getLastAccessTimeInternal() without session invalidation test. (pero)
+      </fix>
+      <fix>
+        <bug>38814</bug>: CGIServlet correctly handles Shift_JIS output. (markt) 
+      </fix>
+      <fix>
+        Add missing REQUEST_URI environment variable to CGI environment. (markt)
+      </fix>
+      <fix>
+        <bug>27617</bug>: Sync existing mime types with httpd. (keith)
+      </fix>
+      <fix>
+        <bug>38761</bug>: Handle relative symlinks to shell scripts as suggested by Adam Murray (keith)
+      </fix>
+      <fix>
+        <bug>38795</bug>: Associate more closely bind with a finally unbind in StandardContext start and
+        stop, based on a patch by Darryl Miles (remm)
+      </fix>
+      <fix>
+        Improve undeployment robustness (remm)
+      </fix>
+      <update>
+        Expand the semaphore valve (remm)
+      </update>
+      <fix>
+        <bug>39021</bug>: Add back support for authentication only, submitted by Scott Stark (remm)
+      </fix>
+      <fix>
+        Revert fix for <bug>38113</bug>, which does not seem a legitimate problem, and causes
+        regressions (remm)
+      </fix>
+      <fix>
+        Correctly reset listeners when reloading a webapp (remm)
+      </fix>
+      <fix>
+        <bug>38194</bug>: Don't fail silently if -force is used without CATALINA_PID, submitted by Matthew Buckett. (yoavs)
+      </fix>
+      <fix>
+        <bug>38154</bug>: Avoid NPE in FileDirContext after webapp undeploy, reported by Jamie Maher. (yoavs)
+      </fix>
+      <fix>
+        <bug>38217</bug>: Added cautionary note about keystore password to SSL HowTo, as suggested by Ralf Hauser. (yoavs)
+      </fix>
+      <fix>
+        <bug>38262</bug>: Cleared ambiguity in host documentation, as suggested by Jeffrey Bennett. (yoavs)
+      </fix>
+      <fix>
+        <bug>38476</bug>: Modified check for null TLD stream, as suggested by Fabrizio Giustina. (yoavs)
+      </fix>
+      <fix>
+        <bug>38052</bug>: Use <i>userName</i> as userField default. User is at many databases a 
+        reserved keyword, as suggested by rik. (pero)
+      </fix>
+      <fix>
+        Fix handling of non matching if-range header (remm)
+      </fix>
+      <fix>
+        <bug>37848</bug>: Only output catalina.sh diagnostic messages if we have a TTY, submitted by
+          David Shaw. (yoavs)
+      </fix>
+      <fix>
+        <bug>38596</bug>: Minor performance optimization in DataSourceRealm, suggested by Sandy
+          McArthur. (yoavs)
+      </fix>
+    </changelog>
+  </subsection>
+  <subsection name="Coyote">
+    <changelog>
+      <fix>
+        Make the default cipher suites available for SSL the same as the set of cipher
+        suites enabled by default rather than the set of all cipher suites. This prevents
+        ciphers suites that do not provide confidentiality protection and/or server
+        authentication being used by default. (markt)
+      </fix>
+      <fix>
+        Move AprEndpoint.getWorkerThread inside the try/catch for the main accept loop, to guard
+        about an OOM (which would most likely doom the server anyway) (remm)
+      </fix>
+      <fix>
+        As exhibited in the ASF's JIRA installation, it seems EINTR is a status code that should
+        be ignored as a result to a poll call (remm)
+      </fix>
+      <update>
+        New APR connectors defaults (remm)
+      </update>
+      <update>
+        Add multiple threads for APR pollers, to work around Windows limitations (performance degrades
+        very rapidly if poller sizes over 1024 are allowed when compiling APR) (remm)
+      </update>
+      <update>
+        New modes for firstReadTimeout (-1 being the new default) (remm)
+      </update>
+      <update>
+        Replace java.util.Stack usage with a simple array in the APR endpoint (remm)
+      </update>
+      <fix>
+        tcnative jnilib.c now report correct compile flags for runtime 
+        Library.java checks like sendfile support default true/false (pero)
+      </fix>
+    </changelog>
+  </subsection>
+  <subsection name="Jasper">
+    <changelog>
+      <fix>
+        <bug>38015</bug>: Remove misleading warnings logged in TagLibraryInfoImpl, as suggested by Andrew Houghton. (yoavs)
+      </fix>
+      <fix>
+        <bug>38376</bug>: Make sure body content stack is always properly aligned, as submitted by Tony Deigh. (yoavs)
+      </fix>
+      <fix>
+        Compatibility with JDT 3.2 (remm)
+      </fix>
+    </changelog>
+  </subsection>
+  <subsection name="Webapps">
+    <changelog>
+      <fix>
+        <bug>39292</bug>: Update catalina.policy at demo balancer app. Fix provided by Kerry Sainsbury (pero)
+      </fix>
+      <fix>
+        <bug>36847</bug>: Fixed the manager app copy function to not overwrite fileA with fileB when fileA==fileB.
+        Fix provided by Haroon Rafique (fhanik)
+      </fix>
+      <fix>
+        <bug>38508</bug>: Several enhancements to Host Manager application, including configurable
+          manager app support and dialog box enhancements.  Thanks to George Sexton for the patch. (yoavs)
+      </fix>
+      <fix>
+        <bug>37781</bug>: Make sure context config file is writeable, suggested by George Sexton. (yoavs,pero)
+      </fix>
+    </changelog>
+  </subsection>
+  <subsection name="Cluster">
+    <changelog>
+       <update>
+        Add at PooledSocketSender the jmx attributes inPoolSize and inUsePoolSize. (pero)
+       </update>
+       <fix>
+         DeltaManager set session creationTime at backup node. (pero)
+       </fix>
+       <update>
+        Add JvmRouteBinderValve documentation at cluster-howto.xml. (pero)
+       </update>
+       <add>
+        JvmRouteBinderValve now supports now sessionid's from request and cookies.
+        Thanks to Brian Stansberry for reporting it. (pero)
+       </add>
+       <fix>
+      	<bug>38779</bug> Fix wrong jmx message arg at SimpleTcpCluster
+          at o.a.c.cluster.tcp.mbeans-descriptors.xml, submitted by Pawel Tucholski (pero)
+      </fix>
+      <fix>
+        Fix that not after every "Keep Alive Socket close" a log warning is generated at TcpReplicationThread (pero)
+      </fix>
+      <fix>
+        <bug>39178</bug>: Now ROOT.war deployment with FarmWarDeployer is possible (pero)
+      </fix>
+      <fix>
+        ReplicationValve not set primarySession flag when all backup nodes gone (pero)
+      </fix>
+      <update>
+        Add DeltaSession.getLastAccessTimeInternal() without session invalidation test. (pero)
+      </update>
+    </changelog>
+  </subsection>
+ </section>
+
+<section name="Tomcat 5.5.16 (yoavs)">
+  <subsection name="General">
+    <changelog>
+      <update>
+        Updated / enhanced docs to remove old FIXME references. (yoavs)
+      </update>
+      <update>
+        Required tcnative library version upgraded to 1.1.2 (remm)
+      </update>
+      <update>
+        Update to Eclipse JDT 3.1.2 (remm)
+      </update>
+    </changelog>
+  </subsection>
+  <subsection name="Catalina">
+    <changelog>
+      <fix>
+        <bug>23950</bug>: Context.listBindings() should return objects not
+        references. (markt)
+      </fix>
+      <fix>
+        <bug>38124</bug>: Add support for Windows 20xx when reading environment
+        variables in CGIServlet. (markt)
+      </fix>
+      <fix>
+        <bug>29214</bug>: response.containsHeader() now returns the correct
+        value for Content-Type and Content-Length headers. (markt)
+      </fix>
+      <fix>
+        Allow using a custom ContextConfig when using JMX embedding of Tomcat, as
+        is done by the regular deployer. (remm)
+      </fix>
+      <add>
+        Add JMX serverInfo attribute to Server MBean, that we can identify
+        the tomcat release remotely. (pero)
+      </add>
+      <fix>
+        Fix the JMX MBeanFactory.createStandardHost signature at mbean-descriptors.xml (pero)
+      </fix>
+      <fix>
+        Fix some cases (for example with realm usage) where the container logger for a context
+        would be retrieved using the wrong classloader (remm)
+      </fix>
+      <fix>
+        HttpSession.getId will no longer throw an ISE when the session is invalid (remm)
+      </fix>
+      <fix>
+         ore detailed errors for naming issues (remm)
+      </fix>
+      <docs>
+        Add documentation for the Transaction element (remm)
+      </docs>
+      <update>
+        Add getContextPath to the internal servlet context implementation (remm)
+      </update>
+      <fix>
+        Only null instances loaded by the webapp CL, submitted by Matt Jensen (remm)
+      </fix>
+      <update>
+        Deploy folders which don't have a WEB-INF, and return an error when a context
+        file does not contain a Context element (remm)
+      </update>
+      <fix>
+        <bug>38653</bug>: Fix property name (remm)
+      </fix>
+      <fix>
+        Slightly modify the timing of the manager start, so that it is not started by a
+        listener (remm)
+      </fix>
+      <fix>
+        Refresh loggers used by the digester (remm)
+      </fix>
+      <fix>
+        Use sendError instead of setStatus to send the 401 code. (billbarker)
+      </fix>
+      <fix>
+        Don't append the port for an SSL redirect if it is the default port. (billbarker)
+      </fix>
+    </changelog>
+  </subsection>
+  <subsection name="Coyote">
+    <changelog>
+      <fix>
+        Log errors when setting socket options with debug priority rather than error. (remm)
+      </fix>
+      <fix>
+        <bug>38100</bug>: Make certain that a valid Host name is set, or none at all. (billbarker)
+      </fix>
+      <fix>
+        <bug>38485</bug>: Fix minor regression setting connection timeout (as well as linger and
+        no delay) where the default value was always used when using the regular 
+        HTTP connector (remm)
+      </fix>
+      <update>
+        Pass along more of the SSL related fields to OpenSSL (remm)
+      </update>
+      <update>
+        CharChunk now implements CharSequence (remm)
+      </update>
+      <fix>
+        Fix coding error which could cause a rare crash when a poller error occurred and sockets
+        where pending being added to the keepalive poller (remm)
+      </fix>
+      <fix>
+        Fix potential sync issues when restarting a poller (remm)
+      </fix>
+      <fix>
+        Update APR error reports, including the error codes (remm)
+      </fix>
+      <fix>
+        <bug>38726</bug>: Remove duplicate request group field causing blank statistics for the
+        HTTP connector (remm) 
+      </fix>
+      <fix>
+        Fix invalid length used by some AJP packets for the AJP APR connector, which could cause 
+        corruption, submitted by Rudiger Plum (jim)
+      </fix>
+      <fix>
+        <bug>38346</bug>: Fix problems with request.getReader().readLine(). 
+        Patch by Rainer Jung (billbarker)
+      </fix>
+      <update>
+        Local address reuse for APR Endpoints (via APR_SO_REUSEADDR) now enabled (jim)
+     </update>
+      <fix>
+        Don't write out the shutdown secret file if shutdown is disabled (the default) (billbarker)
+      </fix>
+      <fix>
+        Fix NPE when no sink is supplied. (billbarker)
+      </fix>
+      <update>
+        APR Endpoints now IPv6 aware (jim)
+     </update>
+      <update>
+        Downgrade "Response already committed" logging entry to DEBUG. (billbarker)
+     </update>
+     <fix>
+       <bug>38113</bug>: Return the empty String for an empty query-string instead of null. (billbarker)
+     </fix>
+    </changelog>
+  </subsection>
+  <subsection name="Jasper">
+    <changelog>
+      <fix>
+        <bug>38389</bug>: Set correct JDT Compiler option to java 1.5 compliance. 
+        Patch from Olivier Thomann and Paul Hamer (pero)
+      </fix>
+      <update>
+        Add some useful hints to jasper-howto. (pero).
+      </update>
+      <fix>
+        <bug>38776</bug>: Fix source file attribute, submitted by Olivier Thomann (remm)
+      </fix>
+    </changelog>
+  </subsection>
+  <subsection name="Cluster">
+    <changelog>
+      <fix>
+        Update DeltaManager session access stats  (pero)
+      </fix>
+      <fix>
+        DeltaSession getId will no longer throw an ISE when the session is invalid (pero)
+      </fix>
+      <update>
+          Resurrected the &quot;suspect&quot; property so that the logs don't fill
+          up with errors when member disappears or a connection is lost. Only useful for pooled mode (fhanik)
+      </update>
+      <add>
+       <bug>35710</bug>: Add session replication for cross context session changes.
+       The portlet api need this support, see refactored ReplicationValve. (pero)
+      </add>
+      <update>
+        ReplicationValve reset DeltaSession when cluster node has no backup node. (pero)
+      </update>
+      <update>
+        DataSender close connection and throw exception also even if waitForAck is false.  (pero)
+      </update>
+      <fix>
+        Active cluster junit test again. (pero)
+      </fix>
+    </changelog>
+  </subsection>
+  <subsection name="Webapps">
+    <changelog>
+      <fix>
+        Fix some XSS issues in the JSP examples. (markt)
+      </fix>
+      <fix>
+        Fix logos in the manager webapp (remm)
+      </fix>
+    </changelog>
+  </subsection>
+</section>
+
+<section name="Tomcat 5.5.15 (yoavs)">
+  <subsection name="General">
+    <changelog>
+      <fix>
+        <bug>32081</bug>: Remove the JDK requirement from the Win32 scripts. (keith)
+      </fix>
+    </changelog>
+  </subsection>
+  <subsection name="Catalina">
+    <changelog>
+      <fix>
+       <bug>37852</bug>: Fix regression where the magic role '*' was denying all access. Patch by xrcat (billbarker)
+      </fix>
+      <fix>
+       <bug>37934</bug>: Don't ask for authentication if deny-from-all is in effect. (billbarker)
+      </fix>
+      <fix>
+        <bug>15570</bug>: auth-constraint of * was interpretted as all
+        authenticated users rather than as all roles defined in web.xml. (markt)
+      </fix>
+      <fix>
+       Remove leftover static logger which was used to log application level messages in
+       ApplicationContextFacade (remm)
+      </fix>
+      <fix>
+        <bug>38012</bug>: Where a CGI script sets a response code, use it. (markt)
+      </fix>
+      <fix>
+        <bug>37854</bug>: Extension-List checking was too strict. (markt)
+      </fix>
+    </changelog>
+  </subsection>
+  <subsection name="Coyote">
+    <changelog>
+      <fix>
+       Report binding errors in the APR endpoint as strings rather than platform specific
+       status codes (remm)
+      </fix>
+      <fix>
+       <bug>37934</bug>: Don't ask for authentication if deny-from-all is in effect. (billbarker)
+      </fix>
+      <fix><bug>38047</bug>: Handle the case where the Servlet attempts to read
+              the Request body from the AJP/1.3 Connector, in the case that no
+              body was sent. (billbarker)
+      </fix>
+      <fix><bug>38030</bug>: Unconditionally return EOS for an attempt to read 
+              the body of any request that doesn't send CL or TE. 
+              (remm, billbarker).
+      </fix>
+    </changelog>
+  </subsection>
+  <subsection name="Jasper">
+    <changelog>
+      <fix>
+        <bug>35351</bug>: Fix problem using an inner class for a &lt;jsp:useBean /&gt;. (kinman).
+      </fix>
+      <fix>
+        <bug>37929</bug>: Don't stop on the generic attribute methods just because the session is invalid. Patch by Pierre Delisle. (billbarker)
+      </fix>
+      <update>
+        Add system properties org.apache.jasper.runtime.BodyContentImpl.LIMIT_BUFFER and
+        org.apache.jasper.runtime.JspFactoryImpl.USE_POOL to allow configuring Jasper
+        memory usage (remm)
+      </update>
+      <fix>
+        <bug>37933</bug>: Restrict &lt;jsp:getAttribute /&gt; to only look in PAGE_SCOPE. (billbarker)
+      </fix>
+    </changelog>
+  </subsection>
+  <subsection name="Cluster">
+    <changelog>
+      <fix>
+       <bug>37808</bug>: Fix ArrayIndexOutOfBoundsException inside XByteBuffer. Reported by Dietmar Mueller (pero)
+      </fix>
+      <update>
+        <bug>37896</bug>DataSender starts new Socket after IOException. (pero)
+      </update>
+      <update>
+        Reduce memory usage at membership service. (pero)
+      </update>
+    </changelog>
+  </subsection>
+</section>
+
+<section name="Tomcat 5.5.14 (yoavs)">
+  <subsection name="General">
+    <changelog>
+      <update>
+        Update optional native APR connector version to 1.1.1. (mturk)
+      </update>
+      <update>
+        Update build.properties.default to get native connector from new location. (yoavs)
+      </update>
+    </changelog>
+  </subsection>
+
+  <subsection name="Catalina">
+    <changelog>
+      <fix>
+        <bug>13040</bug>: Fix getContext() when used to obtain a context that is a sub-context
+        of the current context. Ported from TC4. (markt) 
+      </fix>
+    </changelog>
+  </subsection>
+
+  <subsection name="Jasper">
+    <changelog>
+      <fix>
+        <bug>37746</bug>: Remove extra space from StringTokenizer pattern in JspC, as suggested by
+        Eric Hedstrom. (yoavs)
+      </fix>
+    </changelog>
+  </subsection>
+  <subsection name="Coyote">
+    <changelog>
+      <fix>
+       <bug>36863</bug>: Strip quotes when parsing Cookie values, even for v0 Cookies. (billbarker)
+      </fix>
+      <fix>
+       <bug>37803</bug>: Don't claim that we have a string value in MessageBytes until we actually do. 
+           Patch by Doug Rand (billbarker)
+      </fix>
+    </changelog>
+  </subsection>
+</section>
+
+<section name="Tomcat 5.5.13 (yoavs)">
+  <subsection name="General">
+    <changelog>
+      <fix>
+        <bug>36711</bug>: Unused line of code. (yoavs)
+      </fix>
+      <update>
+        Removed unused SAXPath, Jaxen dependencies. (yoavs)
+      </update>
+      <update>
+        Update log4j dependency to version 1.2.12, Struts to 1.2.7. (yoavs)
+      </update>
+      <update>
+        Removed JDBC 2.0 StdExt dependency (only class from there is javax.sql.XADataSource, which is
+        present in JDK 1.4 and later. (yoavs)
+      </update>
+      <fix>
+        <bug>37039</bug>: typo on JK Quick configuration how-to. (yoavs)
+      </fix>
+      <add>
+        <bug>37035</bug>: Add a placeholder file in the temp directory for WinZip tar.gz handling. (yoavs)
+      </add>
+      <update>
+        Update JAF dependency to 1.0.2, JTA to 1.0.1b and JavaMail to 1.3.3_01. (markt)
+      </update>
+      <add>
+        Added Eclipse .project, .classpath, and associated files to make building Tomcat from
+        Eclipse significantly easier. (markt)
+      </add>
+      <add> 
+        <bug>37284</bug>: Guess JSE 5.0 location on Mac OS X, patch by Stepan Koltsov. (yoavs)
+      </add>
+      <fix>
+        <bug></bug>: Wrong class name in antlib.xml for JkStatusUpdateTask. (yoavs)
+      </fix>
+    </changelog>
+  </subsection>
+  <subsection name="Catalina">
+    <changelog>
+      <fix>
+        <bug>36802</bug>: Fix problem of double-init when JMX-deploying a 
+        Context into a started Host. (billbarker)
+      </fix>
+      <fix>
+        <bug>36840</bug>: Provide information as to which web.xml is being processed on startup to
+        help debug parsing errors. (yoavs)
+      </fix>
+      <add>
+        <bug>34724</bug>: Ability to set domain for Single-Sign-On cookie.  Patch by Oliver
+        Rossmueller. (yoavs)
+      </add>
+      <fix>
+        <bug>37044</bug>: RealmBase.hasResourcePermission needs to access the GenericPrincipal as
+        set by the realm unless hasRole is overriden, which was no longer being done properly for
+        the JAAS realm (remm)
+      </fix>
+      <fix>
+        <bug>37264</bug>: JNDI resources were no longer available when stopping listeners,
+        submitted by Bogdan Calmac (remm)
+      </fix>
+      <fix>
+        <bug>37150</bug>: Turn off directory listing by default and add a warning
+        regarding enabling listing of directories with many entries. (markt)
+      </fix>
+      <update>
+        Add configurability for the amount of time that the container will wait for requests
+        to complete when unloading servlets, using the unloadDelay property. (remm)
+      </update>
+      <update>
+        Add code to set to null fields in loaded classes when stopping a web application, as a
+        possible workaround for suspicious garbage collection behavior. (remm)
+      </update>
+      <update>
+        Update messages and stack traces for classloading errors which may occur when removing
+        a web application, and for stopped web applications. (remm)
+      </update>
+      <fix>
+        <bug>37319</bug>: Fix catalina.bat reference to CATALINA_BASE for logging.properties.  Thanks
+        to Pierre-Yves Benzaken. (yoavs)
+      </fix>
+      <fix>
+        <bug>36852</bug>: Custom classloaders don't honor Contet privileged attribute.  Thanks to
+        Matt Brinkley for the analysis and patch. (yoavs)
+      </fix>
+      <fix>Fix for a couple of (mostly silly) edge-cases in testing auth.
+           Thanks to Nam T. Nguyen for the report. (billbarker) 
+      </fix>
+      <fix>
+        <bug>37060</bug>: Actually copy the Request headers when replaying after Form auth. (billbarker)
+      </fix>
+      <fix>
+        <bug>37591</bug>: Typo in Engine configuration reference. (yoavs)
+      </fix>
+      <fix>
+        <bug>37668</bug>: Added note about JSP recompilation to Context configuration documentation. (yoavs)
+      </fix>
+      <fix>
+        <bug>37132</bug>: Have DigestAuthenticator Handle user names with commas.  Thanks to 
+          Robert Wille for the patch. (yoavs)
+      </fix>
+      <fix>
+        <bug>37212</bug>: Better error reporting in Connector.java.  Thanks to Ralf Hauser for
+        the patch. (yoavs)
+      </fix>
+    </changelog>
+  </subsection>
+  <subsection name="Coyote">
+    <changelog>
+      <fix>
+        Gracefully handle the case where some Socket options are disabled at 
+        the OS level for the AJP/1.3 Connector. (billbarker)
+      </fix>
+      <fix>
+        <bug>36366</bug>: Use rewritten deployer-howto page by Allistair Crossley. (remm)
+      </fix>
+      <add>
+        <bug>36630</bug>: Added extra log output for class instantiation failure. (yoavs)
+      </add>
+      <fix>
+        <bug>37121</bug>: Sendfile always needs to be given the length of data to write,
+        which fixes ranged requests. (remm)
+      </fix>
+      <fix>
+        Optimized direct byte buffers association with the socket for APR connectors. (mturk)
+      </fix>
+      <fix>
+        Fix hidden NPEs when using the APR connectors and there's no host header. (pero, remm)
+      </fix>
+      <fix>
+        Http11Protocol now register RequestProcessor at JMX and show current usage inside manager app. (pero)
+      </fix>
+      <add>
+        JkStatus Ant tasks for mod_jk 1.2.15. (pero)
+      </add>
+      <update>Connection Timeout is normal, so reduce logging to DEBUG (billbarker) 
+      </update>
+      <fix>
+        Fix crash which could occur with the HTTP APR connector when accessing request JMX objects
+        outside of the processing of the said request (remm)
+      </fix>
+      <fix>
+        <bug>37627</bug>: Fix buffering issue in the HTTP APR connector when a large buffer size was
+        used for servlets (remm)
+      </fix>
+      <fix>
+        <bug>37673</bug>: Fix implementation of getLocalPort and getLocalAddr in the HTTP APR connector
+        (remm)
+      </fix>
+    </changelog>
+  </subsection>
+  <subsection name="Jasper">
+    <changelog>
+      <fix>
+        <bug>35252</bug>: Jasper PageDataImpl outputs malformed XML.  Patch by Rahul Akolkar. (yoavs)
+      </fix>
+      <add>
+        <bug>37062</bug>: Helpful JSP exception message containing file, line numbers.  Patch by
+        Tim Fennell at http://www.tfenne.com/jasper/. (yoavs)
+      </add>
+      <fix>
+        <bug>37407</bug>: File descriptor leak in JspReader.  Thanks to Fred for the patch.  I also
+        did some minor cleanup in the class. (yoavs)
+      </fix>
+      <add>
+        <bug>37612</bug>: Add file location to JSP Validator error message.  Thanks to Renaud Bruyeron
+        for the patch. (yoavs)
+      </add>
+    </changelog>
+  </subsection>
+  <subsection name="Cluster">
+    <changelog>
+      <fix>
+        Fix that session replace messages are logged after node recovery get all session from master node. (pero)
+      </fix>
+      <fix>
+        <bug>37896</bug> Fix that sendMessage signature at all DataSender subclasses must be changed.
+        Now pooled and async modes working as expected. (pero)
+      </fix>
+      <fix>
+        Fix that socket at o.a.c.cluster.tcp.FastAsyncSocketSender can be disconnect/connect. (pero)
+      </fix>    
+      <fix>
+        Fix cluster module build.xml script for new svn repository structure (pero)
+      </fix>    
+      <fix>
+        Fix closed socket exceptions at normal server shutdown, reported by Olve Hansen (pero)
+      </fix>    
+      <fix>
+        Fix closed socket exceptions inside async message transfer modes (pero)
+      </fix>    
+      <fix>
+        <bug>34984</bug>: HttpSessionBindingEvent.getValue() get correct value (pero)
+      </fix>    
+      <fix>
+        <bug>35916</bug>: send sessionCreated to SessionListener after cluster node recovery (pero)
+      </fix>
+      <fix>
+        <bug>36541</bug>: Used also Hashtable at DeltaSession (pero)
+      </fix>
+      <fix>
+        Better support cluster at engine level. (pero)
+      </fix>
+      <fix>
+        <bug>36866</bug>: Correct attribute name in conf/server.xml documentation for Cluster element. (yoavs)
+      </fix>
+      <fix>
+        <bug>37261</bug>: Allow xerces to know where the web.xml file is so that relative entities can be resolved.
+      </fix>
+      <fix>
+        <bug>37529</bug>: Fixed race condition in ReplicationLister#stopListening.  Thanks to 
+        Chris Walker for the patch. (yoavs)
+      </fix>
+    </changelog>
+  </subsection>
+  <subsection name="Webapps">
+    <changelog>
+      <fix>Remove obsolete TagPlugin file from JSP examples (billbarker)</fix>
+      <fix>
+        <bug>36019</bug>: Made clear the Host-Manager HowTo is coming soon, not ready yet. (yoavs)
+      </fix>
+      <fix>
+        <bug>36336</bug>: Check WAR extension in both upper and lower case, as suggested by
+        A. Grasoff. (yoavs)
+      </fix>
+      <fix>
+        <bug>35982</bug>: Can't delete mail sessions in admin webapp. (yoavs)
+      </fix>
+      <fix>
+        <bug>36673</bug>: Similar to the one above, for data sources. (yoavs)
+      </fix>
+    </changelog>
+  </subsection>
+</section>
+
+<section name="Tomcat 5.5.12 (yoavs)">
+  <subsection name="General">
+    <changelog>
+      <fix>
+        Remove uneeded files in conf. (remm)
+      </fix>
+      <update>
+        Change distribution file names from jakarta-* to apache-*. (remm)
+      </update>
+    </changelog>
+  </subsection>
+  
+  <subsection name="Catalina">
+    <changelog>
+      <add>
+        Add JMX Remote create and unregister ant tasks (pero)
+      </add>
+      <fix>
+        <bug>36343</bug>: Only normalize out backslash on Windows platforms. (billbarker)
+      </fix>
+      <fix>
+        Allow configuring standard stream redirection. (remm)
+      </fix>
+      <add>
+        <bug>36088</bug>: Add RUNNING.txt and RELEASE-NOTES.txt to fulldocs distro. (yoavs)
+      </add>
+      <fix>
+        <bug>36534</bug>: fix equals for URLs returned by ServletContext.getResource() (luehe)
+      </fix>
+      <fix>
+        <bug>36558</bug>: Clear IntrospectionUtils cache when stopping a webapp, as it 
+        could leak to keeping a reference to the classloader (remm)
+      </fix>
+      <fix>
+        <bug>36113</bug>: Session persistence for objects with primitive types could fail in
+        some rare cases (remm)
+      </fix>
+      <fix>
+        <bug>36541</bug>: Full synchronization for session objects attributes collections (remm)
+      </fix>
+      <fix>
+        <bug>35609</bug>: service.bat echo command when wrong arguments given [patch by Robert
+        Longson] (yoavs)
+      </fix>
+      <fix>
+        <bug>34749</bug>: jsessionid dropped on trailing slash (/) redirect (remm)
+      </fix>
+    </changelog>
+  </subsection>
+  
+   <subsection name="Coyote">
+     <changelog>
+       <update>
+         Add support for secret for AJP APR (remm)
+       </update>
+     </changelog>
+  </subsection>
+
+  <subsection name="Jasper">
+    <changelog>
+      <fix>
+        Fix NPE with an error message when no Java compiler is available (remm)
+      </fix>
+      <fix>
+        Restrict System err stream capture to the Ant compiler, as the Eclipse compiler
+        does not need it (remm)
+      </fix>
+      <update>
+        JSP compilation speed improvement using tag library information caching, 
+        submitted by Xingbo Gao (remm)
+      </update>
+      <add>
+        Initial contribution of JSTL tag plugins supporting the core tag library of
+        JSTL, submitted by Jing Li (remm)
+      </add>
+    </changelog>
+  </subsection>
+  
+  <subsection name="Cluster">
+    <changelog>
+      <fix>
+        <bug>36541</bug>: Sync all session attribute access (read and write) at DeltaSession (pero)
+      </fix>
+      <fix>
+        <bug>36518</bug>: Classname typos for senders, submitted by Christoph Bachhuber-Haller (remm)
+      </fix>
+      <add>
+        <bug>35613</bug>: Added FAQ question and answer about tcpListenAddress="auto" and /etc/hosts (yoavs)
+      </add>
+      <update>
+        Moved FAQ section for Clustering from Clustering HowTo page to its own FAQ page. (yoavs)
+      </update>
+    </changelog>
+  </subsection>
+  
+  <subsection name="Webapps">
+    <changelog>
+      <docs>
+        <bug>36319</bug>: Fix broken link to DBCP docs, submitted by Xavier Poinsard (remm)
+      </docs>
+      <docs>
+        Brand new deployer specs, submitted by Allistair Crossley (remm)
+      </docs>
+    </changelog>
+  </subsection>
+ </section>
+
+<section name="Tomcat 5.5.11 (yoavs)">
+  <subsection name="General">
+    <changelog>
+      <update>
+        Update to Xerces 2.7.1 (remm)
+      </update>
+      <add>
+        Add ready to build bin/tomcat-native.tar.gz for the APR JNI wrapper library (remm)
+      </add>
+      <fix>
+        <bug>35930</bug>: Bad logging config used by the Tomcat Windows service (remm)
+      </fix>
+      <add>
+        <bug>33261</bug>: Windows installer now checks the user type and warns non-admins as needed. (yoavs)
+      </add>
+      <update>
+        The Windows installer will now optionally download a (32bit) Windows .dll for Tomcat native
+        from HEAnet (remm)
+      </update>
+      <fix>
+        Declaration of jspc Ant task to fix the deployer package (remm)
+      </fix>
+    </changelog>
+  </subsection>
+  
+  <subsection name="Catalina">
+    <changelog>
+      <add>
+        Add concurrency control valve (o.a.c.valves.SemaphoreValve). As the Tomcat distribution 
+        is not built for Java 5, the valve will have to be compiled from the sources 
+        using Java 5 (remm)
+      </add>
+      <fix>
+        <bug>35880</bug>: Ignore JSSE15SocketFactory when generating JavaDoc, as it breaks
+          the JDK 1.4 JavaDoc tool. (yoavs)
+      </fix>
+      <fix>
+        <bug>35865</bug>: setclasspath.sh cannot be excutive under cygwin. (funkman)
+      </fix>
+      <fix>
+        <bug>33267</bug>: Set working path in service installer, as suggested by Dominik
+          Drzewiecki. (yoavs)
+      </fix>
+      <update>
+        <bug>34794</bug>: Update connector documentation to include clientAuth attribute. (yoavs)
+      </update>
+      <fix>
+        <bug>35894</bug>, <bug>36228</bug>: Fix CNFE when starting in a sandbox. (billbarker, remm)
+      </fix>
+      <fix>
+        Add version check for Tomcat native so that incompatible API changes are detected early (remm)
+      </fix>
+      <fix>
+        <bug>36020</bug>: Allow MemoryUserDatabase to work better on write protected mediums,
+        submitted by Rainer Jung (remm)
+      </fix>
+      <fix>
+        <bug>35978</bug>: Bad handling of single range requests greater than 2GB in the DefaultServlet
+        (remm)
+      </fix>
+      <fix>
+        <bug>35984</bug>: Client abort exceptions will now use getCause (remm)
+      </fix>
+      <fix>
+        Fix handling of non-file based includes with SSI, submitted by David Becker (markt)
+      </fix>
+    </changelog>
+  </subsection>
+  
+   <subsection name="Coyote">
+     <changelog>
+      <fix>
+        Fix default ports for http and https which are set in the request when the parsed
+        hostname does not specify the port, and which were inverted (https was set as 80 
+        and http as 443). (remm)
+      </fix>
+      <fix>
+        Add missing tomcatAuthentication attribute to the AJP APR implementation. (remm)
+      </fix>
+      <fix>
+        Check filename sendfile attribute only if sendfile is enabled. (remm)
+      </fix>
+      <fix>
+        Fix output buffering for APR AJP implementation. (remm)
+      </fix>
+      <fix>
+        <bug>35941</bug>: Fix getRemoteAddr for APR AJP implementation. (remm)
+      </fix>
+      <fix>
+        <bug>35942</bug>: Fix NPE retriving cipher suite attribute when no certificate 
+        was submitted (for example with no SSL). (remm)
+      </fix>
+      <fix>
+        Internationalization and code cleanups for APR AJP implementation. (remm)
+      </fix>
+      <fix>
+        Security exception in APR AJP implementation when running with the security
+        manager enabled. (remm)
+      </fix>
+      <fix>
+        <bug>36173</bug>: Add missing sync in FastHttpDateFormat.formatDate, submitted 
+        by Alexei Krainiouk (remm)
+      </fix>
+      <fix>
+        Disable HTTP compression when sendfile is used for a resource (remm)
+      </fix>
+      <fix>
+        AJP secret attribute report only at trace level. (pero)
+      </fix>
+     </changelog>
+  </subsection>
+
+  <subsection name="Jasper">
+    <changelog>
+      <fix>
+        <bug>36127</bug>: Validation compatibility with Xerces 2.7.1, submitted 
+        by Florent Benoit (remm)
+      </fix>
+    </changelog>
+  </subsection>
+  
+  <subsection name="Cluster">
+    <changelog>        
+      <fix>
+        Fix NPE when cluster stops (pero)
+      </fix>
+      <fix>
+        <bug>36218</bug>: MemoryRealm now support also GenericPrincipal, but 
+        JAASRealm with cluster replication still has a problem, detected by Dirk Dekok (pero)
+      </fix>   
+     </changelog>
+  </subsection>
+  
+  <subsection name="Webapps">
+    <changelog>
+    </changelog>
+  </subsection>
+ </section>
+
+<section name="Tomcat 5.5.10 (yoavs)">
+  <subsection name="General">
+    <changelog>
+      <add>
+         Add JMX remote ant task to control tomcat MBeanserver via ant scripts.
+         Ant lib is included at "server/lib/catalina-ant-jmx.jar" and documentation
+         is added to <a href="monitoring.html">Monitoring and Managing Tomcat How-To</a> (pero)
+      </add>
+      <fix>
+        <bug>34361</bug>: Integrate better antlib and import support for 
+        catalina manager tasks [Modified patch from Daniel Santos]  (pero)
+      </fix>
+      <fix>
+        StoreConfig save now the Connector.sslProtocol attribute. (pero)
+      </fix>
+      <update>
+        Change log dir at service.bat to "$CATALINA_BASE/logs" for better multi instance support. (pero)
+      </update>
+      <update>
+        <bug>34237</bug>: Added note and links to context and host configuration
+          references in JNDI DataSources HowTo to aid the clueless. (yoavs)
+      </update>
+      <update>
+        <bug>34248</bug>: Update JavaMail download instructions to include JAF. (yoavs)
+      </update>
+      <update>
+        Update to JDT from Eclipse 3.1, with support for Java 5 (remm)
+      </update>
+      <update>
+        Refactoring, redesign and extend the cluster module
+          - Cluster can be configured as subelement from Engine and Host.
+          - Optimized performance and reduce memory usage
+          - Better JMX support
+          - add a lot of JMX stats attribute for better monitoring 
+          - add a single element default cluster configuration
+          - more config options
+             LifecycleListener
+             ClusterListener
+             more than one cluster valves
+          - better subclass support
+          - change a lot of existing cluster API's (pero)
+       </update>
+       <add>
+         Add Apache Portable Runtime JNI wrapper and helper API (mturk)
+       </add>
+       <update>
+         Update JULI to provide support for taking over java.util.logging bootstrap configuration,
+         and move the default properties file to ${catalina.base}/conf/logging.properties (remm)
+       </update>
+       <fix>
+         <bug>34746</bug>: Updated catalina.properties instructions per Bill Edwards' suggestion. (yoavs)
+       </fix>
+       <fix>
+         <bug>35090</bug>: Minor documentation typo fix. (yoavs)
+       </fix>
+       <fix>
+         <bug>34931</bug>: Rewrote ROOT/index.jsp to be XHTML strict compliant, per Richard
+           Beton's patch. (yoavs)
+       </fix>
+    </changelog>
+  </subsection>
+  
+  <subsection name="Catalina">
+    <changelog>
+      <fix>
+        <bug>20380</bug>: Access log timestamps now take account of Daylight Saving
+        Time (DST). (markt)
+      </fix>
+      <add>
+        <bug>34220</bug>: Provide better error message when server.xml can't be located.
+          [Modified patch from Ralf Hauser] (yoavs)
+      </add>
+      <add>
+          Add MessageListener and LifecylceListener cluster saving to storeconfig module
+          (&lt;Cluster ... &gt;&lt;ClusterListener className="org.apache.catalina.cluster.session.JvmRouteSessionIDBinderListener" &gt;) (pero)
+      </add>  
+      <fix>
+        <bug>33743</bug>: Add additional synchronization in webapp classloader to avoid
+        possible race condition when defining a class (remm)
+      </fix>
+      <fix>
+        <bug>33711</bug>: Add events on passivate and activate to cleanup SSO, and recycle
+        session objects when removing them from a manager (so that anyone keeping references
+        to it would leak a minimal amount of memory) (remm)
+      </fix>
+      <update>
+        Re-add patch causing Session.getId to throw an ISE, and make all internal components
+        use a safe getIdInternal method (remm)
+      </update>
+      <update>
+        Store principal to be exposed for Request.getUserPrincipal inside the GenericPrincipal,
+        to remove hacks from the JAAS realm (remm)
+      </update>
+      <fix>
+        <bug>10385</bug>: SSI Servlet now includes better support for files that use character
+        encodings other than the platform default.(markt)
+      </fix>
+      <fix>
+        Remove CopyParentClassLoader rule, which doesn't seem to be doing anything useful
+        anymore. (remm)
+      </fix>
+      <add>
+        Provide an ServletFilter implementation of Server Side Includes (SSI). This was
+        submitted by David Becker under <bug>33106</bug>. (markt)
+      </add>
+      <add>
+        Add sendfile support to default servlet, with a sendfileSize configuration attribute.
+        (remm)
+      </add>
+      <update>
+        If APR as well as Tomcat's JNI wrapper for APR are present, use APRized protocol handlers
+        instead of the regular ones (remm)
+      </update>
+      <fix>
+        <bug>22617</bug>: When used with an EJB container and a realm that supports the concept
+        of an unauthenticated user (J2EE.3.4.3) BASIC authentication was always authenticating
+        users as the unauthenticated user without giving them a chance to supply a username and
+        password. (markt)
+      </fix>
+      <fix>
+        Prevent facade objects cloning (remm)
+      </fix>
+      <update>
+        Add missing CGI variables to SSI servlet. Patch submitted by Fritz Schneider. (markt)
+      </update>
+      <fix>
+        <bug>34578</bug>: Updated JNDIRealm comment. (yoavs)
+      </fix>
+      <fix>
+        <bug>34273</bug>: Better Bootstrap warning message. [Path from Ralf Hauser] (yoavs)
+      </fix>
+      <update>
+        <bug>34675</bug>: Updated Proxy-HowTo page with Servlet API calls. (yoavs)
+      </update>
+      <fix>
+        <bug>34546</bug>: Fix problem where the "first" Valve couldn't be removed from a Pipeline. (billbarker)
+      </fix>
+      <fix>
+        Fix NPE when POST size exceeds limit defined by maxPostSize. (markt)
+      </fix>
+      <fix>
+        Fix FORM authentication so POSTed parameters are not assumed to be encoded with platform
+        default encoding. A side effect of this fix is that the bodies of POST requests that
+        require FORM authentication are now buffered and made available after a sucessful login. (markt)
+      </fix>
+      <fix>
+        <bug>34840</bug>: Better handling of external WARs redeployment, and ignore docBase specified
+        in context file if within the Host appBase (remm)
+      </fix>
+      <fix>
+        Fix handling of symbolic links when the DefaultServlet is generating directory
+        listings. (markt)
+      </fix>
+      <fix>
+        <bug>35769</bug>: Correct implementation of javax.naming.Context.composeName( Name, Name)
+        in multiple places. Patch provided by Laurent Simon. (markt)
+      </fix>
+      <add>
+        <bug>34805</bug>: Add warning for suspicious security patterns, as suggested by Ralf Hauser. (yoavs)
+      </add>
+      <fix>
+        <bug>35819</bug>: Use getWorkPath for deleting work directory on context destroy, as suggested
+          by Rob Steele. (yoavs)
+      </fix>
+    </changelog>
+  </subsection>
+  
+   <subsection name="Coyote">
+     <changelog>
+      <update>
+        Add support for using "Smart Cards" as trust/keyStore. (billbarker)
+      </update>
+      <update>
+        Add some Mbean attributes and operations to ChannelSocket (pero)
+      </update>    
+      <add>
+        Apache Portable Runtime based HTTP/1.1 protocol handler, with SSL support (remm)
+      </add>
+      <add>
+        Add support for simple file-based CRLs under JDK 1.5 (billbarker)
+      </add>
+      <add>
+        Add experimental NIO-Socket channel for the AJP/1.3 Connector (billbarker)
+      </add>
+      <add>
+        <bug>34648</bug>: Add configuration option to enable IP-based Virtual Hosts. (billbarker)
+      </add>
+      <update>
+        Refactor the AJP/1.3 Connector to be able to handle more advanced Actions. (billbarker)
+      </update>
+      <fix>
+        Fix connector initialisation so sslProtocol is not required for SSL. (markt)
+      </fix>
+      <add>
+        Add bufferSize option to the AJP/1.3 Java connector to control output buffering. (billbarker)
+      </add>
+      <add>
+        Apache Portable Runtime based AJP/1.3 protocol handler (remm)
+      </add>
+      <fix>
+        Delay reading the inital request body packet by default for the AJP/1.3 Java connector. (billbarker)
+      </fix>
+     </changelog>
+  </subsection>
+
+  <subsection name="Jasper">
+    <changelog>
+      <fix>
+        <bug>18477</bug>: Allow symbolic links when precompiling JSPs (markt)
+      </fix>
+      <add>
+        <bug>34272</bug>: Allow specifying the Option class used by the Jasper engine,
+        submitted by Scott Stark (remm)
+      </add>
+      <add>
+        Support for Java 5.0 in JSPs (remm)
+      </add>
+      <update>
+        Java 5 will be the source and target for JSPs when running on Java 5 (remm)
+      </update>
+      <update>
+        <bug>34652</bug>: Add the ability to get SMAPs when precompiling, submitted by
+        Daryl Robbins (remm)
+      </update>
+      <fix>
+        <bug>34465</bug>: Jspc failure if there is no web.xml (remm)
+      </fix>
+      <fix>
+        <bug>35696</bug>: Make certain that release is called for custom tags 
+         when tag-pooling is disabled. (billbarker)
+      </fix>
+      <fix>
+        <bug>35386</bug>: Make useBean resources use consistent spelling, from Kurt Huwig. (yoavs)
+      </fix>
+      <update>
+        <bug>33522</bug>: Update jasper-howto to reflect use of javac switch. (yoavs)
+      </update>
+      <add>
+        <bug>35114</bug>: Add failOnError flag to JspC, by ziweth. (yoavs)
+      </add>
+      <fix>
+        <bug>35410</bug>: Fixed NPE in JspWriterImpl. (yoavs)
+      </fix>
+      <add>
+        <bug>35571</bug>: JspC resolved uriRoot relative to Ant project basedir, if any, as suggested
+          by Jason Pettiss. (yoavs)
+      </add>
+    </changelog>
+  </subsection>
+  
+  <subsection name="Cluster">
+    <changelog>        
+      <add>
+        Add that cluster can configure as Engine and Host element. (pero)
+      </add>      
+      <add>
+        Add single cluster default configuration element - discussed at JAX 2005 conference Cluster Workshop. (pero)
+      </add>      
+      <fix>
+        Fix resend GET_ALL_SESSIONS when wait ACK failed at receiver side (pero)
+      </fix>  
+      <fix>
+        ClusterValve now remove from container element when cluster stops and added with next start again. (pero)
+      </fix>     
+      <add>
+        Set timestamp only at first time inside SessionMessageImpl (pero)
+      </add>    
+      <add>
+       Set timestamp from findsessions method call, when handling GET_ALL_SESSION
+       to all SEND_SESSION_DATA and TRANSFER complete messages. (pero>
+      </add>
+      <add> 
+       Drop all received message inside GET_ALL_SESSION message queue before state 
+       transfer message timestamp. (pero)
+      </add>      
+      <add>
+        Cluster ping now transfer cluster domain information and DeltaManager only
+        send and receive message from same domain members (pero)
+      </add>      
+      <add>
+        JMX Support for McastService (Membership) (pero)
+      </add>      
+      <add>
+        Redesign SimpleTcpCluster message receiving to ClusterReceiverBase (pero)
+      </add>      
+      <add>
+        Cluster transfer all attributes to the generate session manager at addManager. 
+        Remove some unused attributes at SimpleTcpCluster and ReplicationTransmitter (pero)
+      </add>    
+      <update>
+        Refactor DeltaManager:
+          - createSession call now ManagerBase super class method
+          - extract some long methods
+          - send GET_ALL_SESSION with session blocks
+          - don't sync sessions map when send all sessions (pero)  
+      </update>          
+      <update>
+        Add developer actions at to-do.txt (Proposal of changes) (pero)  
+      </update>          
+      <update>
+        Small refactorings at FastAsyncSocketSender (pero)  
+      </update>          
+      <update>
+        Redesign cluster message sending to lesser cpu and memory usage. 
+        Set at ReplicationTransmitter#compress=false as default. Change API from
+        ClusterSender, ReplicaitonTransmitter, DataSender, SimpleTcpCluster (pero)  
+      </update>          
+      <add>
+        DeltaManager has now JMX expireAllLocalSessions and processExipre operation 
+        for better cluster node shutdown handling (usefull for testing only) (pero)   
+      </add>  
+      <add>
+        DataSender doWaitAckStats for better understanding wait ack problems (pero)   
+      </add>  
+      <update>
+        Refactor DeltaManager and add counter for cluster message send/receive message (pero)  
+      </update>          
+      <fix>
+        <bug>34389</bug>:Porting Clustering fix pack to 5.5.10 code base.
+        Remove synchonized from DataSender.pushMessage(). Very offen the 
+        complete cluster blocking after replicated a bulk of new session messages under heavy load.
+        All cluster node standing for a lot of time and made nothing. 
+        Fix it for pooled, asynchronous and fastasyncqueue replication mode. Very bad thing, sorry! (pero)  
+      </fix>
+      <add>
+        Add notifySessionListenersOnReplication attribute to SimpleTcpCluster to stop notify 
+        event to SessionListener at backup nodes from create and destroy replicated session (pero)
+      </add>
+      <add>
+        Add compress attribute to ClusterSender and ClusterReceiver interface. Now compress config
+        transfer from sender to receiver at SimpleTcpCluster. (pero) 
+      </add>    
+      <add>
+        Add ClusterValve interface and implement it as ReplicationValve and JvmRouteBinderValve. Now both
+        Valves can be directly configured at server.xml Host/Cluster/Valve subelements.
+        Also this configuration are correctly handled with the StoreConfig module. (pero)  
+      </add>    
+      <update>
+        Deactivate DataSender keepAliveMaxRequestCount change default to -1. 
+        Cluster replication sockets are fast and very stable! (pero)  
+      </update>          
+      <update>
+        Setup JvmRouteBinderValve as host valve instead context valve. Refactor the API a little bit. (pero)
+      </update>
+      <fix>
+        Don't increment open socket counter before socket is really open. Add socket open failures counter (pero) 
+      </fix>  
+      <add>
+        Add MessageListener support to cluster server.xml element (ClusterListener) to 
+        register your own cluster message receiver (pero)
+      </add>  
+      <add>
+        Add LifecycleListener support to cluster server.xml element (Listener)
+        and notify those listener from start/stop cluster,
+        add/remove session manager, sending fault and start/stop member  (pero)
+      </add>  
+      <add>
+        Add active backgroundProcess keepAlive timeout and request count socket close check
+        at ReplicationTransmitter.  Check frequency can be change with attribute 
+        processSenderFrequency (default 2). (pero)
+      </add>
+      <add>
+        Remove useless Jdk13ReplicationListener,Jdk13ObjectReader. 
+        Add SocketReplicationListener and SocketObjectReader to have nativ socket ClusterReceiver. 
+        Also extract ClusterReceiverBase superclass for SocketReplicationListener and ReplicationListener (pero) 
+      </add>
+      <update>
+        Add and update some API and the <a href="cluster-howto.html">cluster howto documentation</a> (pero)
+      </update>
+      <update>
+        Refactor ReplicationValve for better understanding and small optimization (pero)
+      </update>
+      <add>
+        Starting a unit test suite for cluster module - very much todo (pero)
+      </add>
+      <fix>
+        Fix ant build.xml to direct compile at cluster module directory (pero)
+      </fix>
+      <fix>
+        Fix some I18N messages, but a lot of work is waiting for fix (pero)
+      </fix>
+      <add>
+        Add ReplicationValve Mbeans stats attribute getter and resetStatistics operation (pero)
+      </add>
+     </changelog>
+  </subsection>
+  
+  <subsection name="Webapps">
+    <changelog>
+      <fix>
+        <bug>35758</bug>: Admin webapp mishandling digest attribute of JDBCDataSourceRealm. (yoavs)
+      </fix>
+      <add>
+        <bug>34250</bug>: Admin webapp Commit Changes button now asks for confirmation. (yoavs)
+      </add>
+      <add>
+        <bug>34818</bug>: Alternating row for apps in HTML manager, as suggested by Jeff
+          Domeyer. (yoavs)
+      </add>
+      <add>
+        <bug>35379</bug>: Added commons-logging to build path of manager and host-manager apps,
+          to make them build with Jikes, as suggested by Aaron Isotton. (yoavs)
+      </add>
+    </changelog>
+  </subsection>
+ </section>
+
+<section name="Tomcat 5.5.9 (yoavs)">
+  <subsection name="General">
+    <changelog>
+      <add>
+        Add JULI, a java.util.logging implementation, used to provide sane defaults and
+        configurability equivalent to Tomcat 4.0 for Tomcat 5.5 logging (remm)
+      </add>
+      <docs>
+        Add JULI documentation to the logging page (remm)
+      </docs>
+      <add>
+        Add host manager webapp (remm)
+      </add>
+      <add>
+        Add ant JkStatusUpdateTask for remote status worker handling ( >=mod_jk 1.2.9) (pero)
+      </add>
+      <add>
+        <bug>33739</bug>: Add reference to RUNNING.txt in setup.html. (yoavs)
+      </add>
+      <fix>
+        <bug>33719</bug>: Update reference to Ant download page. (yoavs)
+      </fix>
+      <fix>
+        <bug>33883</bug>: Bad options in SSL-HowTo. (yoavs)
+      </fix>
+      <update>
+        Update to MX4J 3.0.1 (pero)
+      </update>
+      <update>
+        <bug>34139</bug>: Updated Realm-HowTo to specify JMX, Commons-Logging jars for RealmBase. (yoavs)
+      </update>
+      <add>
+        <bug>33325</bug>: Added top-level clean target to Netbuild build.xml file. (yoavs)
+      </add>
+      <update>
+        <bug>33755</bug>: Clarified Postgresql JNDI datasource example. [patch submitted by
+          Tom Witmer] (yoavs)
+      </update>
+    </changelog>
+   </subsection>
+
+  <subsection name="Catalina">
+    <changelog>
+      <fix>
+        Remove some instances of expanded folder removal (remm)
+      </fix>
+      <fix>
+        Don't call mkdirs if we're not going to save the configuration in StandardContext (remm)
+      </fix>
+      <fix>
+        Fix context classloader binding during loader initialization (it was set to null before) (remm)
+      </fix>
+      <fix>
+        The webapp logger should only be retrieved when the context classloader is set to the 
+        webapp's classloader (remm)
+      </fix>
+      <fix>
+        <bug>34170</bug>: Add back retry logic in JDBC realm in case of a connection failure (remm)
+      </fix>
+      <fix>
+        <bug>22041</bug>: Support dynamic proxies as session objects. (markt)
+      </fix>
+      <fix>
+        Fix logger names for wrappers (remm)
+      </fix>
+      <fix>
+        <bug>34006</bug>: If antiResourceLocking was used, HostConfig considered the path as external,
+        and web application resources were not correctly removed or tacked; also simplify the code a lot
+        (remm)
+      </fix>
+      <fix>
+        <bug>34016</bug>: Save and restore docBase when using antiResourceLocking, for compatibility with
+        the admin webapp (remm)
+      </fix>
+      <add>
+        <bug>33636</bug>: Set lastModified attribute when expanding WAR files. (yoavs)
+      </add>
+      <add>
+        <bug>32938</bug>: Allow Salted SHA (SSHA) passwords in JNDIRealm. (yoavs)
+      </add>
+      <add>
+        <bug>31288</bug>: Allow SMTP authentication for JNDI MailSessionFactory. (yoavs)
+      </add>
+      <update>
+        Harmonize processing of the context.xml defaults with the way web.xml is processed
+        (remm)
+      </update>
+      <fix>
+        Ignore ';' if it is in the query string (remm)
+      </fix>
+      <fix>
+        private to protected for the webapp classloader (remm)
+      </fix>
+      <fix>
+        Improve logging of filters and listeners startup errors (remm)
+      </fix>
+      <fix>
+        <bug>33774</bug>: Retry once in JNDI realm authenticate failure regardless of the 
+        exception message (remm)
+      </fix>
+      <fix>
+        <bug>33961</bug>: Don't encode '~' in context paths (remm)
+      </fix>
+      <fix>
+        <bug>32866</bug>: Propagate distributable property from context to manager (yoavs)
+      </fix>
+      <fix>
+        <bug>32867</bug>: Reset distributable attribute in context for clean reload handling (yoavs)
+      </fix>
+      <update>
+          Fix some RealmBase/JNDIRealm log.isXXXEnabled (pero)
+      </update>
+      <fix>
+          <bug>34161</bug>: Harmonize StandardContext.stop with ContainerBase.stop (remm)
+      </fix>
+    </changelog>
+   </subsection>
+   
+   <subsection name="Coyote">
+     <changelog>
+      <fix>
+        <bug>33971</bug>: Set remoteHost to null when Apache doesn't send one. (billbarker)
+      </fix>
+      <fix>
+        Fix calculation of threadRatio for the ms thread pool, and fix setting the updated
+        timeout value (remm)
+      </fix>
+      <update>
+        Update the ms thread pool so that we allocate a worker before accepting a new socket,
+        and wait a little if the pool is exhausted; this should make low maxThreads values work a 
+        lot better (remm)
+      </update>
+      <update>
+        <bug>33857</bug>: Update information on automatic mod_jk configuration in Apache-HowTo (yoavs)
+      </update>
+      <fix>
+        Fix sync block placement in Mapper.addContext (remm)
+      </fix>
+      <fix>
+        <bug>32741</bug>: Fix spelling of "committed" [patch from Ben Souther] (yoavs)
+      </fix>
+      <fix>
+        <bug>34133</bug>: Make setHeader clear multi-valued headers (billbarker)
+      </fix>
+     </changelog>
+   </subsection>
+
+  <subsection name="Jasper">
+    <changelog>
+      <fix>
+        <bug>34034</bug>: Jasper does not respect external entities (billbarker)
+      </fix>
+      <fix>
+        <bug>33810</bug>: Incorrect recycling of BodyContent if close is called (remm)
+      </fix>
+      <update>
+        Per instance loggers in Jasper (remm)
+      </update>
+    </changelog>
+  </subsection>
+   
+   <subsection name="Cluster">
+    <changelog>
+      <fix>
+        Fix JvmRouteBinderValve primary failover attribute to
+        org.apache.catalina.cluster.session.JvmRouteOrignalSessionID (pero)
+      </fix>
+      <fix>
+        Change attribute name waitForAck to sendAck at ReplicationListener (pero)
+      </fix>
+      <add>
+        Integrate new fastasyncqueue cluster sender mode.
+        Support queue size limitation,
+        get all queued objects and send it to the backup node,
+        no queue thread lock contention under high replication load,
+        submitted by Rainer Jung (pero)
+      </add>
+      <add>
+        Add compress attribute to Sender and Receiver to transfer data uncompressed. 
+        At high cluster load this option consume lesser cpu and memory.
+        Implement the compress handling to ReplicationTransmitter, ReplicationListener, 
+        XByteBuffer and Jdk13ReplicationListener (pero)
+      </add>
+      <add>
+        Add doProcessingStats to synchronous, asynchronous and fastqueueasync sender modes
+        to get min, avg, max processing times as IDataSender JMX MBeans (pero)
+      </add>
+      <fix>
+        TcpThreadPool use constant ACK byte array instead create 
+        new 3 byte buffer for every message ack (pero)
+      </fix>
+      <update>
+        Refactor ReplicationTransmitter and ReplicationListener (pero)
+      </update>
+      <update>
+        add getCatalinaCluster() to ClusterReceiver and SimpleTcpCluster (pero)
+      </update>    
+      <update>
+        Update the Api documentation (pero)
+      </update>
+    </changelog>
+   </subsection>
+   <subsection name="Webapps">
+     <changelog>
+       <update>
+         Use the standard struts taglib URIs in admin JSPs. (billbarker)
+       </update>
+      <add>
+        Add more host parameters to create new host with host-manager (pero)
+      </add>
+      <fix>
+        <bug>34033</bug>: Fix quoting related bugs (remm)
+      </fix>
+      <fix>
+        <bug>33713</bug>: Add Struts init code in frameset.jsp as well (remm)
+      </fix>
+     </changelog>
+   </subsection>
+</section>
+
+<section name="Tomcat 5.5.8 (yoavs)">
+  <subsection name="General">
+    <changelog>
+      <fix>
+        <bug>33204</bug>: Fixed SSL HowTo page. (yoavs)
+      </fix>
+      <fix>
+        <bug>33351</bug>: Fix silent uninstallation. (remm)
+      </fix>
+      <fix>
+        <bug>33489</bug>: Missing space in uninstaller message. (yoavs)
+      </fix>
+    </changelog>
+  </subsection>
+
+  <subsection name="Catalina">
+    <changelog>
+      <fix>
+        Unregister host mbean and all context mbeans at remove a host, s. StandardHost.destroy() and MBeanFactory.createStandardHost/removeHost(,) detected by Thorsten Kamann (pero)
+      </fix>
+      <fix>
+        make it possible to restart connector, now serversocket recreated after stop,start (pero)
+      </fix>
+      <fix>
+        change mbean names from Mapper and ProtocolHandler to connector naming style (pero)
+      </fix>
+      <update>
+        Add some log.isXXXEnabled (pero)
+      </update>
+      <fix>
+        Deregister MapperListener after remove connector (pero)
+      </fix>
+      <fix>
+        Remove host only at own domain with same name at all services, detected by Thorsten Kamann (pero)
+      </fix>
+      <fix>
+        <bug>33187</bug>: Remove any logging of the password in the JAAS realm,
+        submitted by Andrew Jaquith (remm)
+      </fix>
+      <fix>
+        <bug>33033</bug>: Don't do anything to the response in the ErrorReportValve
+        if data has already been written (remm)
+      </fix>
+      <update>
+        Add charset support for the URLs used by the tasks, to remove deprecation (remm)
+      </update>
+      <fix>
+        <bug>26135</bug>: Workaround for memory leak when reloading Struts
+        based web applications by clearing the bean instrospector cache of the JVM on
+        classloader stop, submitted by Tobias Lofstrand. (remm)
+      </fix>
+      <fix>
+         Ensure that if CLASSPATH is declared on startup - it is not used. (funkman)
+      </fix>
+      <fix>
+         Add back use of deployOnStartup in HostConfig (remm)
+      </fix>
+      <docs>
+         Ant tasks docs patches, submitted by Gabriele Garuglieri. (remm)
+      </docs>
+      <update>
+         Use NIO for the raw copying operation, as it is faster (a little under 30%), 
+         and decreases a little the impact of antiResourceLocking. (remm)
+      </update>
+      <fix>
+         <bug>33357</bug>: Fix connection leaks with the DataSourceRealm, as well 
+         as improve efficiency, submitted by Dominik Drzewiecki. (remm)
+      </fix>
+      <update>
+         Improve a little logging of servlet exceptions, which should all log the root cause. (remm)
+      </update>
+      <update>
+         Add new Manager.createSession(sessionId) method, allowing the client to "specify" the session id which should be used using a cookie
+         when using emptySessionPath="true". This fixes session tracking in this case. (remm)
+      </update>
+      <fix>
+         <bug>33368</bug>: Fix memory leak in swallowOutput feature which occurred when the thread pool size is
+         reduced, submitted by Rainer Jung. (remm)
+      </fix>
+	  <fix>
+          StoreConfig: can't save cluster Membership element (pero)
+       </fix>
+	  <add>
+          StoreConfig: suppress default jkHome attribute at connector  (pero)
+      </add>
+	  <add>
+          StoreConfig: Save new dymanic properties from ReplicationTransmitter  (pero)
+      </add>
+      <fix>
+         <bug>33463</bug>: Remove attributes after context destroy. (remm)
+      </fix>
+      <fix>
+         <bug>33572</bug>: context.xml should be a redeploy resource, and add prioritization for
+         redeploy resources. (remm)
+      </fix>
+    </changelog>
+  </subsection>
+  
+  <subsection name="Coyote">
+    <changelog>
+      <fix>
+         PoolTcpEndpoint recreate ServerSocket after start,stop,start connector (pero)
+      </fix>
+      <update>
+        Add some log.isXXXEnabled (pero)
+      </update>
+	  <add>
+	    JkMX: make log4j mbean configurable with attribute log4jEnabled (pero)
+	  </add>
+	  <fix>
+	    When Tomcat runs on Windows and IE is uploading data to the server, the first read 
+	    must be at least 8KB, otherwise upload speed is extremely low, submitted by Noel 
+	    Rocher (remm)
+	  </fix>
+    </changelog>
+  </subsection>
+ 
+  <subsection name="Jasper">
+    <changelog>
+      <fix>
+        <bug>33223</bug>: pageContext.forward and jsp:include result
+        in StringIndexOutOfBoundsException (luehe)
+      </fix>
+      <fix>
+        <bug>33373</bug>: Fix handling of context classloader in jspc (remm)
+      </fix>
+      <fix>
+        <bug>33538</bug>: Ignore example and tag-extension elements in TagLibraryInfoImpl. (yoavs)
+      </fix>
+      <fix>
+        <bug>33539</bug>: Better error message when an unknown element is encountered in the tag file. (yoavs)
+      </fix>
+      <fix>
+        <bug>33219</bug>: Minor JspServletWrapper code cleanup. (yoavs)
+      </fix>
+    </changelog>
+  </subsection>
+  
+  <subsection name="Cluster">
+    <changelog>
+       <fix>
+          Add instance based ReplicationValve statistics to Mbean descriptor (pero)
+       </fix>
+       <fix>
+          Better I18N support to cluster session and tcp classes (pero)
+       </fix>
+       <add>
+          Support optional primaryIndicator at ReplicationValve to mark that 
+          request processing to existing session is at primary cluster node. 
+          Easy failover detection, when mark is not at 
+          configurable primaryIndicator attribute, submitted by Rainer Jung (pero)
+       </add>
+       <update>
+          Refactor all implementation from interface IDataSenders (pero)
+       </update>
+      <add>
+          Add some usefull attributes and operations to the all sender MBeans. (pero)
+       </add>
+      <add>
+          Add keepAlive and waitForAck handling to AsyncSocketSender and factor out a DataSender base class.(pero)
+       </add>
+       <add>
+          ReplicationTransmitter: Enable and Disable autoreconnect sender and waitForAck. (pero)
+       </add>
+       <add>
+          ReplicationTransmitter: transfer all properties to socket sender from server.xml configuration. (pero)
+       </add>
+    </changelog>
+  </subsection>
+
+  <subsection name="Webapps">
+    <changelog>
+      <fix>
+        Fix create and remove Host for Admin app. (pero)
+      </fix>
+    </changelog>
+   </subsection>
+</section>
+
+<section name="Tomcat 5.5.7 (remm)">
+  <subsection name="General">
+    <changelog>
+      <add>
+        Add installer for mod_jk on IIS. (mturk)
+      </add>
+      <add>
+        New store config module for better server.xml saving support.<br/>
+        Add &lt;Listener className="org.apache.catalina.storeconfig.StoreConfigLifecycleListener" /&gt; to your server.xml (pero)
+      </add>
+      <update>
+        <bug>32081</bug>: Remove the JDK requirement from the Unix scripts, submitted
+        by Ben Souther (remm)
+      </update>
+      <fix>
+        <bug>32953</bug>: SERVLETAPI: XSS Issues, submitted by Mark Thomas (jfarcand)
+      </fix>
+      <update>
+        Update to commons-digester 1.6, JDT 3.0.1, MX4J 2.1.0, Struts 1.2.6 (remm)
+      </update>
+    </changelog>
+  </subsection>
+
+  <subsection name="Catalina">
+    <changelog>
+      <update>
+         First integration at StoreConfig to StandardServer (pero)
+      </update>
+      <fix>
+        <bug>32714 </bug>: Don't make the AccessLogValve final (funkman)
+      </fix>
+      <fix>
+        <bug>32694</bug>: Fix bad code to make docBase path aboslute in antiLocking
+        method. (remm)
+      </fix>
+      <fix>
+        <bug>32713</bug>: Fix resource-env-ref handling. (remm)
+      </fix>
+      <fix>
+        <bug>31201</bug>: Improve i18n support in DefaultServlet. This was causing
+        problems with JSP include actions and static files. (markt)
+      </fix>
+      <fix>
+        Add some log.isXXXEnabled to o.a.c.core.StandardHost StandardEngine, StandardService (pero)
+      </fix>
+      <add>
+        Feature addition to add Redirector and failOnError support for all Catalina Ant tasks,
+        submitted by Gabriele Garuglieri (remm)
+      </add>
+      <fix>
+        <bug>31198</bug>: Fix FORM and DIGEST authentication for non-ASCII
+        usernames and passwords. (markt)
+      </fix>
+      <fix>
+        Reimplement charset mapper (remm)
+      </fix>
+      <fix>
+        Add logging of exception which could occur when retrieving the password in JDBCRealm (remm)
+      </fix>
+      <fix>
+        <bug>25889</bug>: Don't execute queries twice, submitted by Tom Anderson (remm)
+      </fix>
+      <fix>
+        <bug>32832</bug>: request.getSession(false) fails to return null (luehe)
+      </fix>
+      <fix>
+        <bug>28222</bug>: request.getRequestURL() in forwarded jsp/servlet returns
+        original url rather than new url as per SRV8.4 (markt)
+      </fix>
+      <fix>
+        <bug>33157</bug>: Fix handling of the buffer length for basic authentication parsing (remm)
+      </fix>
+    </changelog>
+  </subsection>
+
+  <subsection name="Coyote">
+    <changelog>
+      <fix>
+        <bug>32708</bug>: Better handling of bad encoding with the string cache. (remm)
+      </fix>
+      <fix>
+        <bug>32781</bug>: Fix bad initialization of the "scheme" field of the request
+        object, which would cause getScheme to return "http" for the first request. (remm)
+      </fix>
+      <fix>
+        Content length should be ignored if there is chunking (remm)
+      </fix>
+      <fix>
+        Remove most deprecation problems for the AJP connector (remm)
+      </fix>
+    </changelog>
+  </subsection>
+
+  <subsection name="Jasper">
+    <changelog>
+      <fix>
+        <bug>32746</bug>: Avoid JAR locking when loading classes and improve loading
+        performance by taking advantage of caching, submitted by Dominik Drzewiecki. (remm)
+      </fix>
+    </changelog>
+  </subsection>
+
+  <subsection name="Cluster">
+    <changelog>
+       <fix>
+          correct JvmRouteSessionIDBinderListener MBean name to &lt;domain&gt;:type=Listener,name=JvmRouteSessionIDBinderListener,host=&lt;host&gt; (pero)
+       </fix>
+       <add>
+          JMX support to SimpleTcpCluster, ReplicationTransmitter and all senders (pero)
+       </add>
+    </changelog>
+  </subsection>
+
+  <subsection name="Webapps">
+    <changelog>
+      <fix>
+        Fix the webDAV servlet so it can be used via any arbitrary mapping
+        (eg /webdav/*) to edit the contents of a web application. (markt)
+      </fix>
+      <fix>
+        <bug>32729</bug>: Stop is optional and may fail, so it needs to be in a separate try/catch (remm)
+      </fix>
+      <update>
+        Remove the remove method of the manager servlet, and use the undeploy method instead (remm)
+      </update>
+      <fix>
+        <bug>32777</bug>: Fail if application isn't configured properly, submitted by Gabriele Garuglieri
+        (remm)
+      </fix>
+      <fix>
+        <bug>32771</bug>: Cannot undeploy/deploy misconfigured app after tomcat startup,
+        submitted by Gabriele Garuglieri (remm)
+      </fix>
+      <fix>
+        <bug>28867</bug>: Correct manager documentation to document correct way to
+        reference the ROOT context. Submitted by Stephane Bailliez. (markt)
+      </fix>
+      <fix>
+        <bug>33085</bug>: Add support for setting privileged attribute of context
+        to admin webapp. (markt)
+      </fix>
+      <fix>
+        <bug>33117</bug>: Fix Open bugs link broken on default homepage.
+        Patch supplied by Sander Temme. (markt)
+      </fix>
+      <fix>
+        Improve javadoc generation for Catalina. (remm)
+      </fix>
+    </changelog>
+  </subsection>
+</section>
+
+<section name="Tomcat 5.5.6 (yoavs)">
+  <subsection name="General">
+    <changelog>
+      <update>
+        <bug>32532</bug>: updated logging documentation. (yoavs)
+      </update>
+      <update>
+        <bug>32382</bug>: Index page and packaed WAR for sample webapp. (yoavs)
+      </update>
+      <fix>
+        <bug>32603</bug>: Updated host.xml to reflect appBase resolution. (yoavs)
+      </fix>
+    </changelog>
+  </subsection>
+
+  <subsection name="Catalina">
+    <changelog>
+      <fix>
+        Add child to the map of the parent before starting it. (remm)
+      </fix>
+      <fix>
+        Decouple usage of the scheme and secure attributes from enabling SSL. (remm)
+      </fix>
+      <fix>
+        <bug>32502</bug>: memory leak in DigestAuthenticator. (yoavs)
+      </fix>
+      <fix>
+        <bug>28709</bug>: javax.servlet.http.HttpServletRequest.isRequestedSessionIdValid() returns true for an invalidated session. (luehe)
+      </fix>
+      <fix>
+        <bug>32137</bug>: Possible thread-safety issue in RealmBase. (yoavs)
+      </fix>
+    </changelog>
+  </subsection>
+
+  <subsection name="Coyote">
+    <changelog>
+      <fix>
+        <bug>32585</bug>: Better handling for content length greater than Integer.MAX_VALUE in response. (markt)
+      </fix>
+      <update>
+        Allow ApacheConfig and friends to live under an Engine. (billbarker)
+      </update>
+      <update>
+        Syncronize access to the Jk Request registration count. (billbarker)
+      </update>
+      <update>
+        Speed the MsgContext on its way to GC. (billbarker)
+      </update>
+      <fix>
+        Keep correct thread counts in Thread pool when thread ends in an exception (billbarker)
+      </fix>
+    </changelog>
+  </subsection>
+
+  <subsection name="Jasper">
+    <changelog>
+      <update>
+        Updated Jasper-HowTo section on using Jikes, changed conf/web.xml JSPServlet to refer people to Jasper-HowTo so that we don't have these instructions in two places. (yoavs)
+      </update>
+    </changelog>
+  </subsection>
+
+  <subsection name="Webapps">
+    <changelog>
+      <fix>
+        <bug>32505</bug>: Fix handling of an empty context parameter (which occurred every time the HTML
+        manager was used to deploy a local war without specifying also a context file). (remm)
+      </fix>
+    </changelog>
+  </subsection>
+</section>
+
+<section name="Tomcat 5.5.5 (yoavs)">
+  <subsection name="General">
+    <changelog>
+      <update>
+        <bug>32235</bug>: Sync conf/web.xml MIME types with Apache httpd. (yoavs)
+      </update>
+      <fix>
+        <bug>31132</bug>: Better -x/-r support for OS/400 in startup scripts. (yoavs)
+      </fix>
+      <update>
+        <bug>22679</bug>: Added misc note on accessing session ID to SSL-HowTo. (yoavs)
+      </update>
+ <!-- ByteBufferAccessLogValve.java is not inside!!
+      <update>
+        Add an asynchrounous access log valve based on NIO (jfarcand)
+      </update>
+ -->
+       <update>
+        <bug>32249</bug>: Updated logging documentation. (yoavs)
+      </update>
+      <update>
+        <bug>32282</bug>: Modify Windows Uninstaller to only remove webapps/ROOT and webapps if user asks to remove everything. (yoavs)
+      </update>
+      <fix>
+        <bug>32371</bug>: outdated introduction.xml page. (yoavs)
+      </fix>
+      <fix>
+        <bug>32373</bug>: outdated installation.xml page. (yoavs)
+      </fix>
+      <update>
+        <bug>32454</bug>: amended JNDI documentation for JavaMail/JavaActivationFramework usage. (yoavs)
+      </update>
+    </changelog>
+  </subsection>
+
+  <subsection name="Catalina">
+    <changelog>
+      <fix>
+        <bug>32130</bug>: Add safety check to FileStore#keys method. (yoavs)
+      </fix>
+      <update>
+        <bug>32276</bug>: Add developer info to Realm How-To. (yoavs)
+      </update>
+      <fix>
+        <bug>32082</bug>: Added protected getPrincipals method to MemoryRealm for easier extension. (yoavs)
+      </fix>
+      <fix>
+        <bug>32023</bug>: CGIServlet fails to handle post message with multipart/form data. (yoavs)
+      </fix>
+      <fix>
+        <bug>32269</bug>: JNDIRealm fails with InvalidNameException to authenticate users if LDAP distinguished name (DN) contains slash or double quote character(s). (yoavs)
+      </fix>
+     <fix>
+        Move processExpiresFrequency check to ManagerBase and reflect change to all subclasses (StandardManager, PersientManagerBase, DeltaManager). (pero)
+      </fix>
+      <update>
+        Add DIGEST authentication support to the JDBC and DataSource realms. Supports both digested and cleartext passwords. (markt)
+      </update>
+      <fix>
+        <bug>32429</bug>: CGIServlet calculates number of lines received on stderr incorrectly. (markt)
+      </fix>
+      <fix>
+        <bug>32431</bug>: Fix typo in code that passes data to CGI script. (markt)
+      </fix>
+      <fix>
+        <bug>32430</bug>: Class cast exception in toString() method within CGI servlet. (markt)
+      </fix>
+      <fix>
+         Add some log.isXXXEnabled checks at StandardContext and HostConfig (pero)
+      </fix>
+      <fix>
+         Remove the last DefaultContext artifacts (pero)
+      </fix>
+      <fix>
+         <bug>32031</bug>: using createConnector with "http" protocol (remm)
+      </fix>
+      <fix>
+         Add configFile attribute in JMX descriptors (remm)
+      </fix>
+      <fix>
+         Fix autodeployer handling of a war which includes a /META-INF/context.xml, so that it is
+         correctly registered and can be reloaded correctly (remm)
+      </fix>
+      <fix>
+         <bug>32137</bug>: Use of MessageDigest should be synced in DIGEST (remm)
+      </fix>
+      <fix>
+         Add info log when the autodeployer reloads a context (remm)
+      </fix>
+    </changelog>
+  </subsection>
+
+  <subsection name="Coyote">
+    <changelog>
+      <update>
+        Small HTTP/1.1 optimizations: replace usage of Strings with constant byte arrays, and
+        simplify the code converting Strings to bytes (remm)
+      </update>
+      <update>
+        Greatly reduce the amount of recycle method calls on the buffers (remm)
+      </update>
+      <fix>Add null OName check for Request unregistration in Jk, to remove
+           exception under JDK 1.5. (billbarker)
+      </fix>
+      <fix><bug>32292</bug>: Don't send keep-alive header when the protocol
+           can't be parsed. (billbarker)
+      </fix>
+    </changelog>
+  </subsection>
+
+  <subsection name="Jasper">
+    <changelog>
+      <update>
+        Updated JspC usage messages to include recently added configurable parameters. (yoavs)
+      </update>
+      <fix>
+        <bug>32330</bug>: JspC changes context classloader. (yoavs)
+      </fix>
+    </changelog>
+  </subsection>
+
+  <subsection name="Cluster">
+    <changelog>
+       <add>
+          JvmRouteBinderValve/JvmRouteSessionIDBinderListener to bind cluster session after primary node failure at first calling backup node.
+          This was an option to have session stickyness after cluster node crashed. Work only with JESSIONID cookies. (pero)
+       </add>
+       <add>
+          Better log support to DeltaManager to see detail information at debug level. (pero)
+       </add>
+       <fix>
+          Fix FarmWarDeployer based on new HostConfig deployer. (pero)
+       </fix>
+       <fix>
+          FarmWarDeployer controlled WarWatcher with engine backgroundProcess call.
+          Added processDeployFrequency attribute to Deployer server.xml element. (pero)
+       </fix>
+    </changelog>
+  </subsection>
+
+  <subsection name="Webapps">
+    <changelog>
+      <update>
+        <bug>32019</bug>: Remove maxlength=64 restriction on env entry values in admin webapp. (yoavs)
+      </update>
+      <fix>
+        Fix various problems in realm docs, submitted by Phil Mocek. (remm)
+      </fix>
+      <update>
+        Add log4j docs submitted by Allistair Crossley. (remm)
+      </update>
+      <fix><bug>32381</bug>: Fix problem where EL expression is used as a
+        place holder in the admin webapp.
+        Submitted by Allistair Crossley. (billbarker)
+      </fix>
+    </changelog>
+  </subsection>
+</section>
+
+<section name="Tomcat 5.5.4 (yoavs)">
+  <subsection name="General">
+    <changelog>
+      <update>
+        <bug>31671</bug>: Update web.xml files to 2.4 schema where applicable. (yoavs)
+      </update>
+      <update>
+        <bug>31912</bug>: Add PNG and CSS file types to replication filter default. (yoavs)
+      </update>
+    </changelog>
+  </subsection>
+
+  <subsection name="Catalina">
+    <changelog>
+      <fix>
+        Add processExpiresFrequency to PersistentManagerBase and made some small JDBCStore optimizations (pero)
+      </fix>
+      <fix>
+        Register JSP monitoring mbean for each servlet that declares a jsp-file in web.xml. (luehe)
+      </fix>
+      <fix>
+        <bug>31578</bug>: Update Manager configuration documentation. (yoavs)
+      </fix>
+      <fix>
+        <bug>31273</bug>: Add support for derefaliases in JNDIRealm. (markt)
+      </fix>
+      <fix>
+        <bug>31623</bug>: Better OS400 support in setclasspath.sh. (yoavs)
+      </fix>
+      <add>
+        Extend background processing to most container components. (remm)
+      </add>
+      <fix>
+        Remove all MX4J related code. (remm)
+      </fix>
+      <fix>
+        Update JAR list in TldConfig. (remm)
+      </fix>
+      <add>
+        Register datasources with JMX. With DBCP, this is enough to provide JMX management and monitoring.
+        It might work well with many other data sources which might not register themselves in JMX
+        but do expose their stuff in a java bean fashion. (remm)
+      </add>
+      <update>
+        Add the ability to force session cookies to be set to the root path "/". This should not be used
+        on large servers, otherwise tons of cookies may be sent. (remm)
+      </update>
+      <fix>
+        Workaround for client socket exceptions occurring while running a CGI, which could cause
+        the external process to hang. (remm)
+      </fix>
+      <update>
+        Optimize session cookie IDs conversion to String, since this is an unavoidable and uncacheable
+        operation. (remm)
+      </update>
+      <fix>
+        Add explicit error message if temp dir does not exist, and remove useless calls to initDirs. (remm)
+      </fix>
+      <add>
+        Add an optimized access log valve, supporting hardcoded support for the common and combined patterns,
+        and doing a majority of its write-to-logfile operations asynchronously. (remm)
+      </add>
+      <update>
+        Register an MBean to monitor and manage the StringCache, and allow invoking the reset operation. (remm)
+      </update>
+      <fix>
+        <bug>31677</bug>: Log warning if work dir for context can't be determined. (yoavs)
+      </fix>
+      <fix>
+        <bug>31903</bug>: Fix condition which seems to not have been properly updated after adding
+        entry.binaryContent = null a little below, submitted by Joe Zhou. (remm)
+      </fix>
+      <fix>
+        Prevent silent NPEs during StandardContext.start dealing with JMX registration of realm, submitted
+        by Keith Wannamaker. (remm)
+      </fix>
+      <fix>
+        <bug>31592</bug>: Support other encodings for digests. (yoavs)
+      </fix>
+      <update>
+        <bug>31739</bug>: Minor realm-howto and AJP connector doc updates. (yoavs)
+      </update>
+      <fix>
+        <bug>31753</bug>: Minor inconsistency between JDBC and DataSourceRealm#authenticate. (yoavs)
+      </fix>
+      <update>
+        <bug>31683</bug>: Minor clarifications to realm documentation. (yoavs)
+      </update>
+    </changelog>
+  </subsection>
+
+  <subsection name="Coyote">
+    <changelog>
+      <fix>
+        Improve i18n in TCP endpoint, and add a better error message when an exception occurs
+        in setSocketOptions. (remm)
+      </fix>
+      <fix>
+        <bug>31663</bug>: Use interval field as the delay for monitor thread. (remm)
+      </fix>
+      <fix>
+        Remove bad shutdown logic for ms pool strategy. (remm)
+      </fix>
+      <fix>
+        Sync with Cookie, by adding ' ' as a special char. If a special char is present,
+        the string will be quoted. If the client doesn't support it, the String will no be quoted anyway
+        and no IAE will be thrown. (remm)
+      </fix>
+      <add>
+        Add an optional String cache for ByteChunk.toString and CharChunk.toString. The cache is
+        unsynchronized during most of its operation, and is static after a training period. An operation
+        is provided to allow resetting the cache. (remm)
+      </add>
+      <update>
+        String caching is enabled by default for ByteChunk. (remm)
+      </update>
+      <fix>
+        <bug>31090</bug>: Use a URL encoded path when setting session cookies. (remm)
+      </fix>
+       <add>
+          Add getAttributeName() to ProtocolHandler to get all attributes at runtime (pero)
+       </add>
+    </changelog>
+  </subsection>
+
+  <subsection name="Jasper">
+    <changelog>
+      <update>
+        Exposed compilerSourceVM and compilerTargetVM options to JspC. (yoavs)
+      </update>
+    </changelog>
+  </subsection>
+
+  <subsection name="Cluster">
+    <changelog>
+       <fix>
+          DeltaManager and SimpleTcpReplicationManager generate double jvmRoute (pero)
+       </fix>
+       <add>
+          Add some missing Getters and log.isXXXEnableds (pero)
+       </add>
+    </changelog>
+  </subsection>
+
+  <subsection name="Webapps">
+    <changelog>
+      <fix>
+        <bug>31707</bug>: Broken JavaScript confirmation in HTML manager. (yoavs)
+      </fix>
+      <fix>
+        Remove hard-coded admin context path from admin's banner.jsp. (yoavs)
+      </fix>
+      <update>
+        Major connector docs update. (remm)
+      </update>
+      <fix>
+        <bug>31732</bug>: Fix Japanese localization of Manager's list output. (yoavs)
+      </fix>
+    </changelog>
+  </subsection>
+
+</section>
+
+<section name="Tomcat 5.5.3 (yoavs)">
+
+  <subsection name="General">
+    <changelog>
+      <fix>
+        <bug>30568</bug>: Incomplete setup.html documentation for launching jsvc. (yoavs)
+      </fix>
+      <update>
+        Repackage naming features. (remm)
+      </update>
+      <fix>
+        Fix deployer packaging. (remm)
+      </fix>
+      <fix>
+        Fix embed packaging. (remm)
+      </fix>
+    </changelog>
+  </subsection>
+
+  <subsection name="Catalina">
+    <changelog>
+      <fix>
+        Fix memory leak when Security Manager is turned on. (jfarcand)
+      </fix>
+      <fix>
+        When checking status codes for error handling, only check if
+        Response.isError() is true. This way, users may use setStatus() to set their own
+        error status without having the error page invoked. (in which case, the user should've
+        use sendError()) (funkman)
+      </fix>
+      <update>
+        Remove Digester code for Xerces workaround. (jfarcand)
+      </update>
+      <fix>
+        Give proper permission to the balancer app when running under the security manager. (jfarcand)
+      </fix>
+      <fix>
+        <bug>30869</bug>: Make sure JAAS realm name is legal. (yoavs)
+      </fix>
+      <update>
+          md5Helper, md5Encoder, and normalize are used by WebdavServlet,
+          not DefaultServelt so move them into WebdavServlet.
+      </update>
+      <fix>
+        <bug>31277</bug>: Clarified automatic application deployment section of Host configuration page. (yoavs)
+      </fix>
+     <fix>
+       <bug>28631</bug>: JAASRealm enhancements to support custom user and role classes  use Commons-Logging. (yoavs)
+     </fix>
+     <fix>
+       <bug>31364</bug>: Missing resource in org.apache.catalina.core.LocalString.properties. (yoavs)
+     </fix>
+     <fix>
+       <bug>31362</bug>: Missing -Xdebug in catalina.bat when launching with JPDA and Security. (yoavs)
+     </fix>
+     <fix>
+       <bug>31356</bug>: Duplicates not counted in session generation. (yoavs)
+     </fix>
+     <fix>
+       <bug>30949</bug>: Make sure ApplicationDispatcher unwraps request/response even if include error occurs. (yoavs)
+     </fix>
+      <fix>
+        Fixed StandardContext.getStartTime() to return actual start time/date instead of time (startupTime) it took to start context. (luehe)
+      </fix>
+      <update>
+        getRequest/getResponse should return the most relevant interface, to avoid casts. (remm)
+      </update>
+      <update>
+        Add check for directory before considering something is a compressed WAR. (remm)
+      </update>
+      <docs>
+        Update the connector documentation. (remm)
+      </docs>
+      <fix>
+        When parsing a context file, ignore the "path" attribute:
+        the only place where it is acceptable is in server.xml. (remm)
+      </fix>
+      <fix>
+        Digester handling fixes: always call reset in a finally block after using a digester. (remm)
+      </fix>
+      <update>
+        Remove many fields from Connector, and tie the creation of the Connector to the
+        creation of the protocol handler. (remm)
+      </update>
+      <update>
+        Remove package triggers from the classloader, which seem useless when using Java 5. (remm)
+      </update>
+      <fix>
+        Realms will now use set attribute to set themselves in their container when using JMX. (remm)
+      </fix>
+      <fix>
+        Fix JMX related operations with the Connector. (remm)
+      </fix>
+      <fix>
+        Fix save-to-XML for naming resources. (remm)
+      </fix>
+      <fix>
+        Remove authenticator "debug" attributes from the descriptors. (remm)
+      </fix>
+      <update>
+        Refactor org.apache.catalina.deploy.ContextXXX to use new super class ResourceBase. (pero)
+      </update>
+      <fix>
+        Enable Connector.findLifecycleListener that we can listen start/stop Connector events and save the listener to xml. (pero)
+      </fix>
+      <update>
+        Remove Watchdog references, as it is no longer used. (yoavs)
+      </update>
+      <fix>
+        <bug>31511</bug>: Don't call setenv.bat if not found, in *using-launcher scripts. (yoavs)
+      </fix>
+      <fix>
+        <bug>31549</bug>: Add name to WebappClassLoader's stopped message. (yoavs)
+      </fix>
+    </changelog>
+  </subsection>
+
+  <subsection name="Coyote">
+    <changelog>
+      <update>
+        Allow customized server header for Standalone. (funkman)
+      </update>
+      <fix>
+        Digester.reset now removes the error handler, the root and calls clear, to prevent
+        any memory leak. (remm)
+      </fix>
+      <update>
+        Remove useless stuff in digester. (remm)
+      </update>
+      <update>
+        In HTTP, add a utility method to convert strings to byte arrays, and output the server header
+        directly as bytes. (remm)
+      </update>
+      <add>
+        Add a master slave thread pool based on the code from Tomcat 4.0. It is less exotic than the
+        default one, and might fare better on some picky systems, such as Redhat 9. The two threadpools
+        will likely be removed once we use the Java 5 API, although more investigation is needed. (remm)
+      </add>
+      <fix>
+        Fix issue with getProperty in IntrospectionUtils. (remm)
+      </fix>
+      <update>
+        Remove attribute translation for SSL in the HTTP protocol handler: it will now be done in the
+        Catalina Connector class. (remm)
+      </update>
+      <fix>
+        Fix handling of the "timeout" attribute of the HTTP protocol handler. (remm)
+      </fix>
+    </changelog>
+  </subsection>
+
+  <subsection name="Jasper">
+    <changelog>
+      <fix>
+        <bug>31171</bug>: Wrap to avoid ClassCastException in PageContextImpl. (yoavs)
+      </fix>
+      <fix>
+        <bug>31257</bug>: Added specification of endorsed dirs if forking.  Note that this is fairly useless for now in 5.5 since it uses JDT and not javac by default. (yoavs)
+      </fix>
+      <docs>
+        Document new Jasper defaults, and update the production configuration. (remm)
+      </docs>
+      <fix>
+        Copied XML encoding detection logic into JASPER, so we're no longer dependent on Xerces. (luehe)
+      </fix>
+      <fix>
+        Fix cosmetic issue where extra CRLF would be inserted during each precompilation in web.xml. (remm)
+      </fix>
+      <update>
+        Allow configuring the interval following a compilation during which a JSP will not be checked
+        for modifications. (remm)
+      </update>
+      <fix>
+        <bug>31465</bug>: Ensure that the compiler reads the .java file using the same encoding as that with which it was written. (markt)
+      </fix>
+      <fix>
+        <bug>31510</bug>: Null out response in JspWriterImpl#recycle to aid in JBoss memory leak. (yoavs)
+      </fix>
+    </changelog>
+  </subsection>
+
+  <subsection name="Cluster">
+    <changelog>
+      <update>
+        Added flag to the cluster (notifyListenersOnReplication) to enable/disable the
+        notifications of attribute/context listeners upon replication of a session delta
+        Works only with the DeltaManager (fhanik)
+      </update>
+      <update>
+        Added flag to the cluster (Cluster/Sender/ackTimeout) to set the timeout in milliseconds
+        for a synchronous request to go through, defaults to 15000ms (fhanik)
+      </update>
+    </changelog>
+  </subsection>
+
+  <subsection name="Webapps">
+    <changelog>
+      <fix>
+        <bug>29485</bug>: I broke the HTML manager when adding JavaScript confirmation, fixed now ;) (yoavs)
+      </fix>
+      <fix>
+        <bug>31058</bug>: Ensure StatusTransformer escapes query string for XML. (yoavs)
+      </fix>
+      <update>
+        Added contexts' start time (available from 'startTime' MBean attribute of StandardContext) to status page (luehe)
+      </update>
+      <fix>
+        <bug>31264</bug>: the deploy task should now behave correctly. (remm)
+      </fix>
+      <update>
+        Refactor the manager servlet to make calls to the deployer more robust. (remm)
+      </update>
+      <fix>
+        Use the more robust String.valueOf in the form edit action of the connector. (remm)
+      </fix>
+    </changelog>
+  </subsection>
+</section>
+
+
+<section name="Tomcat 5.5.2 (yoavs)">
+  <subsection name="General">
+    <changelog>
+      <fix>
+        The installer will now use the system's JRE. (remm)
+      </fix>
+    </changelog>
+  </subsection>
+
+  <subsection name="Catalina">
+    <changelog>
+      <fix>
+        Fix URL generation for classloaders on Windows, causing common/classes and shared/classes
+        to be unusable (remm)
+      </fix>
+      <fix>
+        <bug>31110</bug>: Fix resource packaging bug for servlets (remm)
+      </fix>
+      <fix>
+        Fix 5.5 regression where going through the authenticator would create a session each time. (remm)
+      </fix>
+      <fix>
+        Fix classname of the connector in Embedded, and remove the socket factory. (remm)
+      </fix>
+    </changelog>
+  </subsection>
+
+  <subsection name="Coyote">
+    <changelog>
+      <fix>
+        Redo server header handling again. (remm)
+      </fix>
+      <update>
+        Cleanup a little access to the headers using a local variable and
+        use setValue for Server and Date headers. (remm)
+      </update>
+    </changelog>
+  </subsection>
+
+  <subsection name="Jasper">
+    <changelog>
+      <fix>
+        Remove maxTagNesting and curTagNesting since they are unused. (funkman)
+      </fix>
+      <fix>
+        Fix tag files handling with JDT, which were ususable, and refactor the lifecycle handling of
+        the page loader. (remm)
+      </fix>
+    </changelog>
+  </subsection>
+
+  <subsection name="Cluster">
+    <changelog>
+    </changelog>
+  </subsection>
+
+  <subsection name="Webapps">
+    <changelog>
+    </changelog>
+  </subsection>
+</section>
+
+<section name="Tomcat 5.5.1 (yoavs)">
+  <subsection name="General">
+    <changelog>
+      <update>
+        Tomcat 5.5 can be built on JDK 5.0. (yoavs)
+      </update>
+      <fix>
+        Windows installer polish. (mladen, remm)
+      </fix>
+      <update>
+        Remove dependency on Jakarta regexp. (remm)
+      </update>
+    </changelog>
+  </subsection>
+
+  <subsection name="Catalina">
+    <changelog>
+      <fix>
+        Allow overriding the location of the default context file, similar to the default
+        web.xml. (remm)
+      </fix>
+      <update>
+        Backport if-else logic for SSI servlet from 4.1 (funkman)
+      </update>
+      <fix>
+        Remove DefaultContext elements from the digester rules. (remm)
+      </fix>
+      <fix>
+        Fix ResourceLink handling. (remm)
+      </fix>
+      <fix>
+        Modify the auto deployer to get along with contexts which are statically defined in server.xml. (remm)
+      </fix>
+      <fix>
+        Externalize constant strings defining the location of deployment related resources. (remm)
+      </fix>
+      <fix>
+        <bug>31052</bug>: BeanFactory swallows root cause of exception. (yoavs)
+      </fix>
+      <fix>
+        Allow using deploy Ant task with just config attribute, submitted by Michael Schuerig. (remm)
+      </fix>
+      <add>
+        Added longest time an expired session had been alive to set of monitorable session manager attributes. (luehe)
+      </add>
+      <add>
+        Added average time an expired session had been alive to set of monitorable session manager attributes. (luehe)
+      </add>
+      <fix>
+        Clear a reference in the digester where a context would be referenced for more time than it
+        needed, until the next context deployment operation. (remm)
+      </fix>
+    </changelog>
+  </subsection>
+
+  <subsection name="Coyote">
+    <changelog>
+      <fix>
+        <bug>31018</bug>: Race condition in SystemLogHandler. (yoavs)
+      </fix>
+    </changelog>
+  </subsection>
+
+  <subsection name="Jasper">
+    <changelog>
+      <fix>
+        Use the "compiler" parameter to allow specifying that Ant should be used. (remm)
+      </fix>
+      <fix>
+        Ignore JDT compiler warnings. (remm)
+      </fix>
+      <add>
+        Added compilerTargetVM option support, "1.4" default. (yoavs)
+      </add>
+    </changelog>
+  </subsection>
+
+  <subsection name="Cluster">
+    <changelog>
+      <fix>
+        Fix adding the clustering valve, so that session replication actually occurs. (fhanik)
+      </fix>
+    </changelog>
+  </subsection>
+
+  <subsection name="Webapps">
+    <changelog>
+      <update>
+        Major documentation update with current Tomcat 5.5 changes. (remm)
+      </update>
+      <update>
+        Added JavaScript confirmation dialog to "dangerous" Manager servler links. (yoavs)
+      </update>
+    </changelog>
+  </subsection>
+</section>
+
+<section name="Tomcat 5.5.0 (yoavs)">
+  <subsection name="General">
+    <changelog>
+      <update>
+        Many updated and fixed JavaDocs. (yoavs)
+      </update>
+      <update>
+        Designed and tested Tomcat on J2SE 5.0 (aka JDK 1.5). (everyone)
+      </update>
+      <update>
+        Bundled Eclipse JDT (new dependency) to allow Tomcat to run on a JRE only, i.e. no JDK required. (remm)
+      </update>
+      <update>
+        Repackage commons-dbcp and its dependencies as a sigle smaller WAR, with renamed packages. (remm)
+      </update>
+      <update>
+        Removed dependencies on commons-digester, commons-beanutils, and commons-collections.
+        The relevant digester functionality is now merged in tomcat-util. (remm)
+      </update>
+    </changelog>
+  </subsection>
+
+  <subsection name="Catalina">
+    <changelog>
+      <update>
+        Removed usage of org.apache.catalina.Logger, increased usage of commons-logging everywhere. (remm)
+      </update>
+      <update>
+        Refactored classloader code to better handle JAR and general resource locking. (remm)
+      </update>
+      <update>
+        Written JMX-related code to play nicely with J2SE 5.0 built-in JMX abilities. (remm, costin)
+      </update>
+      <update>
+        Extensively profiled and optimized the server startup performance as well as the request mapping and processing pipeline. (remm)
+      </update>
+      <update>
+        The container will now always process a /META-INF/context.xml resource, unless the webapp has a specified external context file. (remm)
+      </update>
+      <update>
+        New default configuration mechanism for web applications, replacing DefaultContext. This uses a
+        shared context file located in conf/context.xml. (remm)
+      </update>
+      <update>
+        Revamped deployer, alloying full hotdeploy (note: on Windows, this requires the anti file locking
+        features). (remm)
+      </update>
+      <update>
+        Remove verbosity from the JNDI resources configuration, by allowing arbitrary attributes on the Resource element. (remm)
+      </update>
+      <update>
+        Simpler Valve interface, to allow smaller stack traces and reducing the amount of method calls. (remm)
+      </update>
+    </changelog>
+  </subsection>
+
+  <subsection name="Coyote">
+  </subsection>
+
+  <subsection name="Jasper">
+    <changelog>
+      <update>
+        Eclipse JDT is now the default Java compiler in Jasper. Source dependencies are now loaded from
+        the container classloader, and compilation times are much faster. (remm)
+      </update>
+      <update>
+        Jasper development mode should now have acceptable performance for heavily accessed pages.
+        Precompiling JSPs is still significantly more efficient, however. (remm)
+      </update>
+    </changelog>
+  </subsection>
+
+  <subsection name="Cluster">
+  </subsection>
+
+  <subsection name="Webapps">
+    <changelog>
+    </changelog>
+  </subsection>
+</section>
+
+</body>
+</document>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/class-loader-howto.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/class-loader-howto.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/class-loader-howto.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,271 @@
+<?xml version="1.0"?>
+<!DOCTYPE document [
+  <!ENTITY project SYSTEM "project.xml">
+]>
+<document url="class-loader-howto.html">
+
+    &project;
+
+    <properties>
+        <author email="craigmcc at apache.org">Craig R. McClanahan</author>
+        <author email="yoavs at apache.org">Yoav Shapira</author>
+        <title>Class Loader HOW-TO</title>
+    </properties>
+
+<body>
+
+
+<section name="Quick Start">
+
+<p>The following rules cover about 95% of the decisions that application
+developers and deployers must make about where to place class and resource
+files to make them available to web applications:</p>
+<ul>
+<li>For classes and resources specific to a particular web application,
+    place unpacked classes and resources under <code>/WEB-INF/classes</code>
+    of your web application archive, or place JAR files containing those
+    classes and resources under <code>/WEB-INF/lib</code> of your web
+    application archive.</li>
+<li>For classes and resources that must be shared across all web applications,
+    place unpacked classes and resources under
+    <code>$CATALINA_BASE/shared/classes</code>, or place JAR files
+    containing those classes and resources under
+    <code>$CATALINA_BASE/shared/lib</code>.</li>
+</ul>
+
+</section>
+
+
+<section name="Overview">
+
+<p>Like many server applications, Tomcat 5 installs a variety of class loaders
+(that is, classes that implement <code>java.lang.ClassLoader</code>) to allow
+different portions of the container, and the web applications running on the
+container, to have access to different repositories of available classes and
+resources.  This mechanism is used to provide the functionality defined in the
+Servlet Specification, version 2.4 -- in particular, Sections 9.4 and 9.6.</p>
+
+<p>In a J2SE 2 (that is, J2SE 1.2 or later) environment, class loaders are
+arranged in a parent-child tree.  Normally, when a class loader is asked to
+load a particular class or resource, it delegates the request to a parent
+class loader first, and then looks in its own repositories only if the parent
+class loader(s) cannot find the requested class or resource.  The model for
+web application class loaders differs slightly from this, as discussed below,
+but the main principles are the same.</p>
+
+<p>When Tomcat 5 is started, it creates a set of class loaders that are
+organized into the following parent-child relationships, where the parent
+class loader is above the child class loader:</p>
+
+<source>
+      Bootstrap
+          |
+       System
+          |
+       Common
+      /      \
+ Catalina   Shared
+             /   \
+        Webapp1  Webapp2 ... 
+</source>
+
+<p>The characteristics of each of these class loaders, including the source
+of classes and resources that they make visible, are discussed in detail in
+the following section.</p>
+
+</section>
+
+<section name="Class Loader Definitions">
+
+<p>As indicated in the diagram above, Tomcat 5 creates the following class
+loaders as it is initialized:</p>
+<ul>
+<li><strong>Bootstrap</strong> - This class loader contains the basic runtime
+    classes provided by the Java Virtual Machine, plus any classes from JAR
+    files present in the System Extensions directory
+    (<code>$JAVA_HOME/jre/lib/ext</code>).  <em>NOTE</em> - Some JVMs may
+    implement this as more than one class loader, or it may not be visible
+    (as a class loader) at all.</li>
+<li><strong>System</strong> - This class loader is normally initialized from
+    the contents of the <code>CLASSPATH</code> environment variable.  All such
+    classes are visible to both Tomcat internal classes, and to web
+    applications.  However, the standard Tomcat 5 startup scripts
+    (<code>$CATALINA_HOME/bin/catalina.sh</code> or
+    <code>%CATALINA_HOME%\bin\catalina.bat</code>) totally ignore the contents
+    of the <code>CLASSPATH</code> environment variable itself, and instead
+    build the System class loader from the following repositories:
+    <ul>
+    <li><em>$CATALINA_HOME/bin/bootstrap.jar</em> - Contains the main() method
+        that is used to initialize the Tomcat 5 server, and the class loader
+        implementation classes it depends on.</li>
+    <li><em>$JAVA_HOME/lib/tools.jar</em> - Contains the "javac" compiler used
+        to convert JSP pages into servlet classes.</li>
+    <li><em>$CATALINA_HOME/bin/commons-logging-api.jar</em> - Jakarta commons 
+        logging API.</li>
+    <li><em>$CATALINA_HOME/bin/commons-daemon.jar</em> - Jakarta commons 
+        daemon API.</li>
+    <li><em>jmx.jar</em> - The JMX 1.2 implementation.</li>
+    </ul></li>
+<li><strong>Common</strong> - This class loader contains additional classes
+    that are made visible to both Tomcat internal classes and to all web
+    applications.  Normally, application classes should <strong>NOT</strong>
+    be placed here.  All unpacked classes and resources in
+    <code>$CATALINA_HOME/common/classes</code>, as well as classes and
+    resources in JAR files under the
+    <code>$CATALINA_HOME/commons/endorsed</code>,
+    <code>$CATALINA_HOME/commons/i18n</code> and
+    <code>$CATALINA_HOME/common/lib</code> directories,
+    are made visible through this
+    class loader.  By default, that includes the following:
+    <ul>
+    <li><em>commons-el.jar</em> - Jakarta commons el, implementing the 
+        expression language used by Jasper.</li>
+    <li><em>jasper-compiler.jar</em> - The JSP 2.0 compiler.</li>
+    <li><em>jasper-compiler-jdt.jar</em> - The Eclipse JDT Java compiler.</li>
+    <li><em>jasper-runtime.jar</em> - The JSP 2.0 runtime.</li>
+    <li><em>jsp-api.jar</em> - The JSP 2.0 API.</li>
+    <li><em>naming-common.jar</em> - The JNDI implementation used by Tomcat 5
+        to represent in-memory naming contexts.</li>
+    <li><em>naming-factory.jar</em> - The JNDI implementation used by Tomcat 5
+        to resolve references to enterprise resources (EJB, connection 
+        pools).</li>
+    <li><em>naming-factory-dbcp.jar</em> - Jakarta commons DBCP, providing a
+        JDBC connection pool to web applications. The classes have been moved
+        out of their default org.apache.commons package.</li>
+    <li><em>naming-java.jar</em> - Handler for the java: namespace.</li>
+    <li><em>naming-resources.jar</em> - The specialized JNDI naming context
+        implementation used to represent the static resources of a web
+        application. This is not related to the support of the J2EE ENC, and
+        cannot be removed.</li>
+    <li><em>servlet-api.jar</em> - The Servlet 2.4 API.</li>
+    <li><em>tomcat-i18n-**.jar</em> - Optional JARs containing resource bundles
+        for other languages. As default bundles are also included in each 
+        individual JAR, they can be safely removed if no internationalization
+        of messages is needed.</li>
+    </ul></li>
+<li><strong>Catalina</strong> - This class loader is initialized to include
+    all classes and resources required to implement Tomcat 5 itself.  These
+    classes and resources are <strong>TOTALLY</strong> invisible to web
+    applications.  All unpacked classes and resources in
+    <code>$CATALINA_HOME/server/classes</code>, as well as classes and
+    resources in JAR files under
+    <code>$CATALINA_HOME/server/lib</code>, are made visible through
+    this class loader.  By default, that includes the following:
+    <ul>
+    <li><em>catalina.jar</em> - Implementation of the Catalina servlet
+        container portion of Tomcat 5.</li>
+    <li><em>catalina-ant.jar</em> - Some Ant tasks which can be used to
+        manage Tomcat using the manager web application.</li>
+    <li><em>catalina-optional.jar</em> - Some optional components of
+        Catalina.</li>
+    <li><em>commons-modeler.jar</em> - A model MBeans implementation used
+        by Tomcat to expose its internal objects through JMX.</li>
+    <li><em>servlets-xxxxx.jar</em> - The classes associated with each
+        internal servlet that provides part of Tomcat's functionality.
+        These are separated so that they can be completely removed if the
+        corresponding service is not required, or they can be subject to
+        specialized security manager permissions.</li>
+    <li><em>tomcat-coyote.jar</em> - Coyote API.</li>
+    <li><em>tomcat-http.jar</em> - Standalone Java HTTP/1.1 
+        connector.</li>
+    <li><em>tomcat-ajp.jar</em> - Classes for the Java portion of the
+        <code>AJP</code> web server connector, which allows Tomcat to
+        run behind web servers such as Apache and iPlanet iAS and iWS.</li>
+    <li><em>tomcat-util.jar</em> - Utility classes required by some
+        Tomcat connectors.</li>
+    </ul></li>
+<li><strong>Shared</strong> - This class loader is the place to put classes
+    and resources that you wish to share across <strong>ALL</strong>
+    web applications (unless Tomcat internal classes also need access,
+    in which case you should put them in the <strong>Common</strong>
+    class loader instead).  All unpacked classes and resources in
+    <code>$CATALINA_BASE/shared/classes</code>, as well as classes and
+    resources in JAR files under <code>$CATALINA_BASE/shared/lib</code>, are
+    made visible through this class loader. If multiple Tomcat instances are
+    run from the same binary using the $CATALINA_BASE environment variable,
+    then this classloader repositories are relative to $CATALINA_BASE rather
+    than $CATALINA_HOME.</li>
+<li><strong>WebappX</strong> - A class loader is created for each web
+    application that is deployed in a single Tomcat 5 instance.  All unpacked
+    classes and resources in the <code>/WEB-INF/classes</code> directory of
+    your web application archive, plus classes and resources in JAR files
+    under the <code>/WEB-INF/lib</code> directory of your web application
+    archive, are made visible to the containing web application, but to
+    no others.</li>
+</ul>
+
+<p>As mentioned above, the web application class loader diverges from the
+default Java 2 delegation model (in accordance with the recommendations in the
+Servlet Specification, version 2.3, section 9.7.2 Web Application Classloader).  
+When a request to load a
+class from the web application's <em>WebappX</em> class loader is processed,
+this class loader will look in the local repositories <strong>first</strong>,
+instead of delegating before looking.  There are exceptions. Classes which are
+part of the JRE base classes cannot be overriden. For some classes (such as
+the XML parser components in J2SE 1.4+), the J2SE 1.4 endorsed feature can be 
+used  
+(see the common classloader definition above).
+Last, any JAR containing servlet API classes will be ignored by the 
+classloader.
+All other class loaders in Tomcat 5 follow the usual delegation pattern.</p>
+
+<p>Therefore, from the perspective of a web application, class or resource
+loading looks in the following repositories, in this order:</p>
+<ul>
+<li>Bootstrap classes of your JVM</li>
+<li>System class loader classses (described above)</li>
+<li><em>/WEB-INF/classes</em> of your web application</li>
+<li><em>/WEB-INF/lib/*.jar</em> of your web application</li>
+<li><em>$CATALINA_HOME/common/classes</em></li>
+<li><em>$CATALINA_HOME/common/endorsed/*.jar</em></li>
+<li><em>$CATALINA_HOME/common/i18n/*.jar</em></li>
+<li><em>$CATALINA_HOME/common/lib/*.jar</em></li>
+<li><em>$CATALINA_BASE/shared/classes</em></li>
+<li><em>$CATALINA_BASE/shared/lib/*.jar</em></li>
+</ul>
+
+</section>
+
+
+<section name="XML Parsers and J2SE 1.4">
+
+<p>Among many other changes, the J2SE 1.4 release packages the JAXP APIs, and
+a version of Xerces, inside the JRE.  This has impacts on applications that
+wish to use their own XML parser.</p>
+
+<p>In previous versions of Tomcat 5, you could simply replace the XML parser
+in the <code>$CATALINA_HOME/common/lib</code> directory to change the parser
+used by all web applications.  However, this technique will not be effective
+when you are running on J2SE 1.4, because the usual class loader delegation
+process will always choose the implementation inside the JDK in preference
+to this one.</p>
+
+<p>JDK 1.4 supports a mechanism called the "Endorsed Standards Override
+Mechanism" to allow replacement of APIs created outside of the JCP (i.e.
+DOM and SAX from W3C).  It can also be used to update the XML parser
+implementation.  For more information, see:
+<a href="http://java.sun.com/j2se/1.4/docs/guide/standards/index.html">
+http://java.sun.com/j2se/1.4/docs/guide/standards/index.html</a>.</p>
+
+<p>Tomcat utilizes this mechanism by including the system property setting
+<code>-Djava.endorsed.dirs=$CATALINA_HOME/common/endorsed</code> in the
+command line that starts the container.  Therefore, you can replace the
+parser that is installed in this directory, and it will get used even on a
+JDK 1.4 system.</p>
+
+</section>
+
+
+<section name="Running under a security manager">
+
+<p>When running under a security manager the locations from which classes
+are permitted to be loaded will also depend on the contents of your policy
+file. See <a href="security-manager-howto.html">Security Manager HOW-TO</a>
+for further information.</p>
+
+</section>
+
+
+</body>
+
+</document>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/cluster-howto.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/cluster-howto.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/cluster-howto.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,1129 @@
+<?xml version="1.0"?>
+<!DOCTYPE document [
+  <!ENTITY project SYSTEM "project.xml">
+]>
+<document url="cluster-howto.html">
+
+    &project;
+
+    <properties>
+        <author email="fhanik at apache.org">Filip Hanik</author>
+        <author email="pero at apache.org">Peter Rossbach</author>
+        <title>Clustering/Session Replication HOW-TO</title>
+    </properties>
+
+<body>
+
+
+<section name="Quick Start">
+
+<p>To run session replication in your Tomcat 5.5 container, the following steps
+should be completed:</p>
+<ul>
+<li>All your session attributes must implement <code>java.io.Serializable</code></li>
+<li>Uncomment the <code>Cluster</code> element in server.xml</li>
+<li>Uncomment the <code>Valve(ReplicationValve)</code> element in server.xml</li>
+<li>If your Tomcat instances are running on the same machine, make sure the <code>tcpListenPort</code>
+    attribute is unique for each instance.</li>
+<li>Make sure your <code>web.xml</code> has the <code>&lt;distributable/&gt;</code> element 
+    or set at your <code>&lt;Context distributable="true" /&gt;</code></li>
+<li>Make sure that jvmRoute attribute is set at your Engine <code>&lt;Engine name="Catalina" jvmRoute="node01" &gt;</code></li>
+<li>Make sure that all nodes have the same time and sync with NTP service!</li>
+<li>Make sure that your loadbalancer is configured for sticky session mode.</li>
+</ul>
+<p>Load balancing can be achieved through many techniques, as seen in the
+<a href="balancer-howto.html">Load Balancing</a> chapter.</p>
+<p>Note: Remember that your session state is tracked by a cookie, so your URL must look the same from the out
+   side otherwise, a new session will be created.</p>
+<p>Note: Clustering support currently requires the JDK version 1.4 or later.</p>
+</section>
+
+
+<section name="Overview">
+
+<p>To enable session replication in Tomcat, three different paths can be followed to achieve the exact same thing:</p>
+<ol>
+  <li>Using session persistence, and saving the session to a shared file system (PersistenceManager + FileStore)</li>
+  <li>Using session persistence, and saving the session to a shared database (PersistenceManager + JDBCStore)</li>
+  <li>Using in-memory-replication, using the SimpleTcpCluster that ships with Tomcat 5 (server/lib/catalina-cluster.jar)</li>
+</ol>
+
+<p>In this release of session replication, Tomcat performs an all-to-all replication of session state.
+
+   This is an algorithm that is only efficient when the clusters are small. For large clusters, the next
+   release will support a primary-secondary session replication where the session will only be stored at one
+   or maybe two backup servers. 
+   Currently you can use the domain worker attribute (mod_jk &gt; 1.2.8) to build cluster partitions
+   with the potential of very scaleable cluster solution.
+   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:
+   </p>
+
+<source>
+        DNS Round Robin
+               |
+         Load Balancer
+          /           \
+      Cluster1      Cluster2
+      /     \        /     \
+  Tomcat1 Tomcat2  Tomcat3 Tomcat4
+</source>
+
+<p>What is important to mention here, is that session replication is only the beginning of clustering.
+   Another popular concept used to implement clusters is farming, ie, you deploy your apps only to one
+   server, and the cluster will distribute the deployments across the entire cluster.
+   This is all capabilities that can go into with the FarmWarDeployer (s. cluster example at <code>server.xml</code>)</p>
+<p>In the next section will go deeper into how session replication works and how to configure it.</p>
+
+</section>
+
+<section name="How it Works">
+<p>To make it easy to understand how clustering works, We are gonna take you through a series of scenarios.
+   In the scenario we only plan to use two tomcat instances <code>TomcatA</code> and <code>TomcatB</code>.
+   We will cover the following sequence of events:</p>
+
+<ol>
+<li><code>TomcatA</code> starts up</li>
+<li><code>TomcatB</code> starts up (Wait that TomcatA start is complete)</li>
+<li><code>TomcatA</code> receives a request, a session <code>S1</code> is created.</li>
+<li><code>TomcatA</code> crashes</li>
+<li><code>TomcatB</code> receives a request for session <code>S1</code></li>
+<li><code>TomcatA</code> starts up</li>
+<li><code>TomcatA</code> receives a request, invalidate is called on the session (<code>S1</code>)</li>
+<li><code>TomcatB</code> receives a request, for a new session (<code>S2</code>)</li>
+<li><code>TomcatA</code> The session <code>S2</code> expires due to inactivity.</li>
+</ol>
+
+<p>Ok, now that we have a good sequence, we will take you through exactly what happens in the session repliction code</p>
+
+<ol>
+<li><b><code>TomcatA</code> starts up</b>
+    <p>
+        Tomcat starts up using the standard start up sequence. When the Host object is created, a cluster object is associated with it.
+        When the contexts are parsed, if the distributable element is in place in web.xml
+        Tomcat asks the Cluster class (in this case <code>SimpleTcpCluster</code>) to create a manager
+        for the replicated context. So with clustering enabled, distributable set in web.xml
+        Tomcat will create a <code>DeltaManager</code> for that context instead of a <code>StandardManager</code>.
+        The cluster class will start up a membership service (multicast) and a replication service (tcp unicast).
+        More on the architecture further down in this document.
+    </p><p></p>
+</li>
+<li><b><code>TomcatB</code> starts up</b>
+    <p>
+        When TomcatB starts up, it follows the same sequence as TomcatA did with one exception.
+        The cluster is started and will establish a membership (TomcatA,TomcatB).
+        TomcatB will now request the session state from a server that already exists in the cluster,
+        in this case TomcatA. TomcatA responds to the request, and before TomcatB starts listening
+        for HTTP requests, the state has been transferred from TomcatA to TomcatB.
+        In case TomcatA doesn't respond, TomcatB will time out after 60 seconds, and issue a log
+        entry. The session state gets transferred for each web application that has distributable in
+        its web.xml. Note: To use session replication efficiently, all your tomcat instances should be
+        configured the same.
+    </p><p></p>
+</li>
+<li><B><code>TomcatA</code> receives a request, a session <code>S1</code> is created.</B>
+    <p>
+        The request coming in to TomcatA is treated exactly the same way as without session replication.
+        The action happens when the request is completed, the <code>ReplicationValve</code> will intercept
+        the request before the response is returned to the user.
+        At this point it finds that the session has been modified, and it uses TCP to replicata the
+        session to TomcatB. Once the serialized data has been handed off to the operating systems TCP logic,
+        the request returns to the user, back through the valve pipeline.
+        For each request the entire session is replicated, this allows code that modifies attributes
+        in the session without calling setAttribute or removeAttribute to be replicated.
+        a useDirtyFlag configuration parameter can be used to optimize the number of times
+        a session is replicated.
+    </p><p></p>
+
+</li>
+<li><b><code>TomcatA</code> crashes</b>
+    <p>
+        When TomcatA crashes, TomcatB receives a notification that TomcatA has dropped out
+        of the cluster. TomcatB removes TomcatA from its membership list, and TomcatA will no longer
+        be notified of any changes that occurs in TomcatB.
+        The load balancer will redirect the requests from TomcatA to TomcatB and all the sessions
+        are current.
+    </p><p></p>
+</li>
+<li><b><code>TomcatB</code> receives a request for session <code>S1</code></b>
+    <p>Nothing exciting, TomcatB will process the request as any other request.
+    </p><p></p>
+</li>
+<li><b><code>TomcatA</code> starts up</b>
+    <p>Upon start up, before TomcatA starts taking new request and making itself
+    available to it will follow the start up sequence described above 1) 2).
+    It will join the cluster, contact TomcatB for the current state of all the sessions.
+    And once it receives the session state, it finishes loading and opens its HTTP/mod_jk ports.
+    So no requests will make it to TomcatA until it has received the session state from TomcatB.
+    </p><p></p>
+</li>
+<li><b><code>TomcatA</code> receives a request, invalidate is called on the session (<code>S1</code>)</b>
+    <p>The invalidate is call is intercepted, and the session is queued with invalidated sessions.
+        When the request is complete, instead of sending out the session that has changed, it sends out
+        an "expire" message to TomcatB and TomcatB will invalidate the session as well.
+    </p><p></p>
+
+</li>
+<li><b><code>TomcatB</code> receives a request, for a new session (<code>S2</code>)</b>
+    <p>Same scenario as in step 3)
+    </p><p></p>
+
+
+</li>
+<li><code>TomcatA</code> The session <code>S2</code> expires due to inactivity.
+    <p>The invalidate is call is intercepted the same was as when a session is invalidated by the user,
+       and the session is queued with invalidated sessions.
+       At this point, the invalidet session will not be replicated across until
+       another request comes through the system and checks the invalid queue.
+    </p><p></p>
+</li>
+</ol>
+
+<p>Phuuuhh! :)</p>
+
+<p><b>Membership</b>
+    Clustering membership is established using very simple multicast pings.
+    Each Tomcat instance will periodically send out a multicast ping,
+    in the ping message the instance will broad cast its IP and TCP listen port
+    for replication.
+    If an instance has not received such a ping within a given timeframe, the
+    member is considered dead. Very simple, and very effective!
+    Of course, you need to enable multicasting on your system.
+</p>
+
+<p><b>TCP Replication</b>
+    Once a multicast ping has been received, the member is added to the cluster
+    Upon the next replication request, the sending instance will use the host and
+    port info and establish a TCP socket. Using this socket it sends over the serialized data.
+    The reason I choose TCP sockets is because it has built in flow control and guaranteed delivery.
+    So I know, when I send some data, it will make it there :)
+</p>
+
+<p><b>Distributed locking and pages using frames</b>
+    Tomcat does not keep session instances in sync across the cluster.
+    The implementation of such logic would be to much overhead and cause all
+    kinds of problems. If your client accesses the same session
+    simultanously using multiple requests, then the last request
+    will override the other sessions in the cluster.
+</p>
+
+</section>
+
+<section name="Cluster Architecture">
+
+<p><b>Component Levels:</b>
+<source>
+         Server
+           |
+         Service
+           |
+         Engine
+           |  \ 
+           |  --- Cluster --*
+           |
+         Host
+           |
+         ------
+        /      \
+     Cluster    Context(1-N)                 
+        |             \
+        |             -- Manager
+        |                   \
+        |                   -- DeltaManager
+        |
+     -----------------------------
+     |          |         |       \
+   Receiver    Sender   Membership  \
+     \                               -- Valve
+     -- SocketReplicationListener    |      \
+     -- ReplicationListener          |       -- ReplicationValve
+                                     |       -- JvmRouteBinderValve 
+                                     |
+                                     -- LifecycleListener 
+                                     |
+                                     -- ClusterListener 
+                                     |      \
+                                     |       -- ClusterSessionListener
+                                     |       -- JvmRouteSessionIDBinderListener
+                                     |
+                                     -- Deployer 
+                                            \
+                                             -- FarmWarDeployer
+      
+      
+</source>
+<source>
+   Sender
+    \
+    -- ReplicationTransmitter 
+             |
+             ---------
+                      \
+                   IDataSender
+                          \
+                          |
+                          --- (sync)
+                          |  \
+                          |   -- PooledSocketSender   (pooled)
+                          |   -- SockerSender         (synchronous)
+                          |                                
+                          --- (async)
+                             \
+                              -- AsyncSocketSender     (asynchronous)
+                              -- FastAsyncSocketSender (fastasyncqueue)         
+</source>
+</p>
+
+</section>
+
+
+<section name="Cluster Configuration">
+<p>The cluster configuration is described in the sample server.xml file.
+What is worth to mention is that the attributes starting with mcastXXX
+are for the membership multicast ping, and the attributes starting with tcpXXX
+are for the actual TCP replication.
+</p>
+<p>
+    The membership is established by all the tomcat instances are sending broadcast messages
+    on the same multicast IP and port.
+    The TCP listen port, is the port where the session replication is received from other members.
+</p>
+<p>
+    The replication valve is used to find out when the request has been completed and initiate the
+    replication.
+</p>
+<p>
+    One of the most important performance considerations is the synchronous (pooled or not pooled) versus asynchronous replication
+    mode. In a synchronous replication mode the request doesn't return until the replicated session has been
+    sent over the wire and reinstantiated on all the other cluster nodes.
+    There are two settings for synchronous replication. Pooled or not pooled.
+    Not pooled (ie replicationMode=&quot;fastasnycqueue&quot; or &quot;synchronous&quot;) means that all the replication request are sent over a single
+    socket.
+    Using synchronous mode can potentially becomes a bottleneck when a lot of messages generated,
+    You can overcome this bottleneck by setting replicationMode=&quot;pooled&quot; but then you worker threads blocks with replication .
+    What is recommended here is to increase the number of threads that handle
+    incoming replication request. This is the tcpThreadCount property in the cluster
+    section of server.xml. The pooled setting means that we are using multiple sockets, hence increases the performance.
+    Asynchronous replication, should be used if you have sticky sessions until fail over, then
+    your replicated data is not time crucial, but the request time is, at this time leave the tcpThreadCount to
+    be number-of-nodes-1.
+    During async replication, the request is returned before the data has been replicated. async replication yields shorter
+    request times, and synchronous replication guarantees the session to be replicated before the request returns.
+</p>
+<p>
+    The parameter &quot;replicationMode&quot; has four different settings: &quot;pooled&quot;, &quot;synchronous&quot;, &quot;asynchronous&quot; and &quot;fastasyncqueue&quot;
+</p>
+
+<section name="Simple Cluster Configuration">
+<p>
+Simple one line configuration<br/>
+<source>
+   &lt;Server                 port="8011" 
+                       shutdown="SHUTDOWN" &gt;
+    &lt;GlobalNamingResources&gt;
+    &lt;Resource              name="UserDatabase" auth="Container"
+                           type="org.apache.catalina.UserDatabase"
+                    description="User database that can be updated and saved"
+                        factory="org.apache.catalina.users.MemoryUserDatabaseFactory"
+                        pathname="conf/tomcat-users.xml" /&gt;
+  &lt;/GlobalNamingResources&gt;
+    &lt;Service              name="Catalina"&gt;
+        &lt;Connector        port="9012" 
+                      protocol="AJP/1.3"
+        &lt;Connector         port="9013"
+                     maxThreads="100"
+                minSpareThreads="4"
+                maxSpareThreads="4"
+        /&gt;
+        &lt;Engine            name="Catalina" 
+                   defaultHost="localhost" 
+                        jvmRoute="node1"&gt;
+        &lt;Realm        className="org.apache.catalina.realm.UserDatabaseRealm"
+                   resourceName="UserDatabase" /&gt;
+            &lt;Host          name="localhost"
+                        appBase="webapps"&gt;
+             &lt;Cluster className="org.apache.catalina.cluster.tcp.SimpleTcpCluster"/&gt;
+            &lt;/Host&gt;
+        &lt;/Engine&gt;
+    &lt;/Service&gt;
+&lt;/Server&gt;
+</source>
+<br/>
+The default mode configuration setup a <em>fastasyncqueue</em> mode cluster configuration with following
+parameters:
+<ul>
+    <li>Open Membership receiver at <em>228.0.0.4</em> and send to multicast udp port <em>8012</em></li>
+    <li>Send membership every 1 sec and drop member after 30sec.</li>
+    <li>Open message receiver at default ip interface at first free port between <em>8015</em> and <em>8019</em>.</li>
+    <li>Receiver message with <em>SocketReplicationListener</em> </li>
+    <li>Configure a <em>ReplicationTransmitter</em> with <em>fastasyncqueue</em> sender mode.</li>
+    <li>Add <em>ClusterSessionListener</em> and <em>ReplicationValve</em>.</li>
+</ul> 
+</p>
+<p>
+<b>NOTE</b>: Use this configuration when you need very quick a test cluster with
+at your developer machine. You can change the default attributes from cluster sub elements.
+Use following cluster attribute prefixes <em>sender.</em>,
+<b>receiver.</b>, <b>service.</b>, <b>manager.</b>, <b>valve.</b> and <b>listener.</b>.
+<br/><b>Example</b> configure cluster at windows laptop with network connection and
+change receiver port range<br/>
+<source>
+&lt;Cluster                 className="org.apache.catalina.cluster.tcp.SimpleTcpCluster"
+          service.mcastBindAddress="127.0.0.1" 
+            receiver.tcpListenPort="9070" 
+         receiver.tcpListenMaxPort="9075" /&gt;
+</source>    
+<br/>       
+<b>WARNING</b>: When you add you sub elements, there overwrite the defaults complete.
+<br/><b>Example</b> configure cluster with cluster failover jsessionid support. In this
+case you need also the defaultmode Cluster listener <em>ClusterSessionListener</em> and <em>ReplicationValve</em>.<br/>
+<source>
+&lt;Cluster                 className="org.apache.catalina.cluster.tcp.SimpleTcpCluster"
+          service.mcastBindAddress="127.0.0.1" 
+            receiver.tcpListenPort="9070" 
+         receiver.tcpListenMaxPort="9075" &gt;
+       &lt;ClusterListener  className="org.apache.catalina.cluster.session.ClusterSessionListener" /&gt;
+       &lt;ClusterListener  className="org.apache.catalina.cluster.session.JvmRouteSessionIDBinderListener" /&gt;
+       &lt;Valve            className="org.apache.catalina.cluster.tcp.ReplicationValve"
+                            filter=".*\.gif;.*\.js;.*\.css;.*\.png;.*\.jpeg;.*\.jpg;.*\.htm;.*\.html;.*\.txt;"
+                  primaryIndicator="true" /&gt;
+	   &lt;Valve            className="org.apache.catalina.cluster.session.JvmRouteBinderValve"
+	                      enabled="true"  /&gt;
+&lt;Cluster/&gt;
+</source> 
+</p>
+</section>
+
+<section name="Simple Engine Cluster Configuration for all hosts">
+<p>
+Simple one line engine configuration<br/>
+<source>
+   &lt;Server                 port="8011" 
+                       shutdown="SHUTDOWN" &gt;
+    &lt;GlobalNamingResources&gt;
+    &lt;Resource              name="UserDatabase" auth="Container"
+                           type="org.apache.catalina.UserDatabase"
+                    description="User database that can be updated and saved"
+                        factory="org.apache.catalina.users.MemoryUserDatabaseFactory"
+                        pathname="conf/tomcat-users.xml" /&gt;
+  &lt;/GlobalNamingResources&gt;
+    &lt;Service              name="Catalina"&gt;
+        &lt;Connector        port="9012" 
+                      protocol="AJP/1.3"
+        &lt;Connector         port="9013"
+                     maxThreads="100"
+                minSpareThreads="4"
+                maxSpareThreads="4"
+        /&gt;
+        &lt;Engine            name="Catalina" 
+                   defaultHost="localhost" 
+                        jvmRoute="node01"&gt;
+        &lt;Realm        className="org.apache.catalina.realm.UserDatabaseRealm"
+                   resourceName="UserDatabase" /&gt;
+        &lt;Cluster      className="org.apache.catalina.cluster.tcp.SimpleTcpCluster"/&gt;
+            &lt;Host          name="localhost"
+                        appBase="webapps"/&gt;
+        &lt;/Engine&gt;
+    &lt;/Service&gt;
+&lt;/Server&gt;
+</source>
+<br/>
+See default mode configuration description as simple host cluster example before.
+</p>
+</section>
+
+<section name="Complex Cluster Configuration">
+<p>
+<br/><b>Example</b> Configure cluster with complete sub elements. Activate this node
+as master farm delopyer. Message receiver is NIO based <em>ReplicationListener</em> with six parallel
+worker threads.
+<br/>
+<source>
+       &lt;Server                 port="8011" 
+                       shutdown="SHUTDOWN" &gt;
+    &lt;GlobalNamingResources&gt;
+    &lt;Resource              name="UserDatabase" auth="Container"
+                           type="org.apache.catalina.UserDatabase"
+                    description="User database that can be updated and saved"
+                        factory="org.apache.catalina.users.MemoryUserDatabaseFactory"
+                        pathname="conf/tomcat-users.xml" /&gt;
+  &lt;/GlobalNamingResources&gt;
+    &lt;Service              name="Catalina"&gt;
+        &lt;Connector        port="9012" 
+                      protocol="AJP/1.3"
+        &lt;Connector         port="9013"
+                     maxThreads="100"
+                minSpareThreads="4"
+                maxSpareThreads="4"
+        /&gt;
+        &lt;Engine            name="Catalina" 
+                   defaultHost="localhost" 
+                        jvmRoute="node01"&gt;
+        &lt;Realm        className="org.apache.catalina.realm.UserDatabaseRealm"
+                   resourceName="UserDatabase" /&gt;
+            &lt;Host          name="localhost"
+                        appBase="webapps"&gt;
+                &lt;Cluster                  className="org.apache.catalina.cluster.tcp.SimpleTcpCluster"
+                                       doClusterLog="true"
+                                     clusterLogName="clusterlog"
+                                  manager.className="org.apache.catalina.cluster.session.DeltaManager"
+                   manager.expireSessionsOnShutdown="false"
+               manager.notifyListenersOnReplication="false"
+        manager.notifySessionListenersOnReplication="false"
+                            manager.sendAllSessions="false"
+                        manager.sendAllSessionsSize="500"
+                    manager.sendAllSessionsWaitTime="20"&gt;
+                  &lt;Membership 
+                                          className="org.apache.catalina.cluster.mcast.McastService"
+                                          mcastAddr="228.0.0.4"
+                                   mcastBindAddress="127.0.0.1" 
+                                 mcastClusterDomain="d10" 
+                                          mcastPort="45564"
+                                     mcastFrequency="1000"
+                                      mcastDropTime="30000"/&gt;
+                  &lt;Receiver 
+                                           className="org.apache.catalina.cluster.tcp.ReplicationListener"
+                                    tcpListenAddress="auto"
+                                       tcpListenPort="9015"
+                                  tcpSelectorTimeout="100"
+                                      tcpThreadCount="6"
+                  &lt;Sender
+                                           className="org.apache.catalina.cluster.tcp.ReplicationTransmitter"
+                                     replicationMode="fastasyncqueue"
+                        doTransmitterProcessingStats="true"
+                                   doProcessingStats="true"
+                                      doWaitAckStats="true"
+                                       queueTimeWait="true"
+                                        queueDoStats="true"
+                                      queueCheckLock="true"
+                                          ackTimeout="15000"
+                                          waitForAck="true"
+                                    keepAliveTimeout="80000"
+                            keepAliveMaxRequestCount="-1"/&gt;
+                  &lt;Valve                   className="org.apache.catalina.cluster.tcp.ReplicationValve"
+                                              filter=".*\.gif;.*\.js;.*\.css;.*\.png;.*\.jpeg;.*\.jpg;.*\.htm;.*\.html;.*\.txt;"
+                                    primaryIndicator="true" /&gt;
+                  &lt;Valve                    className="org.apache.catalina.cluster.session.JvmRouteBinderValve"
+                                             enabled="true" /&gt;	
+                  &lt;ClusterListener         className="org.apache.catalina.cluster.session.ClusterSessionListener" /&gt;
+                  &lt;ClusterListener         className="org.apache.catalina.cluster.session.JvmRouteSessionIDBinderListener" /&gt;
+                  &lt;Deployer                className="org.apache.catalina.cluster.deploy.FarmWarDeployer"
+                                            tempDir="${catalina.base}/war-temp"
+                                          deployDir="${catalina.base}/war-deploy/"
+                                           watchDir="${catalina.base}/war-listen/"
+                                       watchEnabled="true"/&gt;
+                  &lt;/Cluster&gt;
+            &lt;/Host&gt;
+        &lt;/Engine&gt;
+    &lt;/Service&gt;
+&lt;/Server&gt;
+</source>
+</p>
+</section>
+
+<section name="Cluster Configuration for ReplicationTransmitter">
+<p>
+List of Attributes<br/>
+<table border="1" cellpadding="5">
+
+  <tr>
+    <th align="center" bgcolor="aqua">Attribute</th>
+    <th align="center" bgcolor="aqua">Description</th>
+    <th align="center" bgcolor="aqua">Default value</th>
+  </tr>
+
+  <tr>
+    <td>replicationMode</td>
+    <td>replication mode (<em>synchronous</em>, <em>pooled</em>, <em>asynchronous</em> or <em>fastasyncqueue</em>)
+    </td>
+    <td><code>pooled</code></td>
+  </tr>
+
+  <tr>
+    <td>processSenderFrequency</td>
+    <td>Control the sender keepalive status and drop sender socket connection after timeout is reached.
+    Check every processSenderFrequency value engine background ticks.
+    </td>
+    <td><code>2</code></td>
+  </tr>
+
+  <tr>
+    <td>compress</td>
+    <td>compress bytes before sending (consume memory, but reduce network traffic - GZIP)</td>
+    <td><code>false</code></td>
+  </tr>
+
+  <tr>
+    <td>ackTimeout</td>
+    <td>acknowledge timeout and only usefull it waitForAck is true</td>
+    <td><code>15000</code></td>
+  </tr>
+  
+  <tr>
+    <td>waitForAck</td>
+    <td>Wait for ack after data send</td>
+    <td><code>false</code></td>
+  </tr>
+
+  <tr>
+    <td>autoConnect</td>
+    <td>is sender disabled, fork a new socket</td>
+    <td><code>false</code></td>
+  </tr>
+
+  <tr>
+    <td>doTransmitterProcessingStats</td>
+    <td>create processing time stats</td>
+    <td><code>false</code></td>
+  </tr>
+</table>
+</p>
+<p>
+Example to get statistic information, wait for ack at every message send and transfer at compressed mode<br/>
+<source>
+    &lt;Sender
+      className="org.apache.catalina.cluster.tcp.ReplicationTransmitter"
+      replicationMode="fastasyncqueue"
+      compress="true"
+      doTransmitterProcessingStats="true"
+      ackTimeout="15000"
+      waitForAck="true"
+      autoConnect="false"/&gt;
+</source>
+</p>  
+</section>
+     
+<section name="Cluster Configuration for ReplicationTransmitter (fastayncqueue - mode)">
+<p>
+List of Attributes<br/>
+<table border="1" cellpadding="5">
+
+  <tr>
+    <th align="center" bgcolor="aqua">Attribute</th>
+    <th align="center" bgcolor="aqua">Description</th>
+    <th align="center" bgcolor="aqua">Default value</th>
+  </tr>
+  
+  <tr>
+    <td>keepAliveTimeout</td>
+    <td>active socket keep alive timeout</td>
+    <td><code>60000</code></td>
+  </tr>  
+
+  <tr>
+    <td>keepAliveMaxRequestCount</td>
+    <td>max request over this socket</td>
+    <td><code>-1</code></td>
+  </tr>  
+
+  <tr>
+    <td>doProcessingStats</td>
+    <td>create Processing time stats</td>
+    <td><code>false</code></td>
+  </tr>
+
+  <tr>
+    <td>doWaitAckStats</td>
+    <td>create waitAck time stats</td>
+    <td><code>false</code></td>
+  </tr>
+
+  <tr>
+    <td>resend</td>
+    <td>resend message after failure, can overwrite at message</td>
+    <td><code>false</code></td>
+  </tr>
+
+  <tr>
+    <td>queueDoStats</td>
+    <td>activated queue stats</td>
+    <td><code>false</code></td>
+  </tr>
+
+  <tr>
+    <td>queueCheckLock</td>
+    <td>check to lost locks</td>
+    <td><code>false</code></td>
+  </tr>
+  <tr>
+    <td>queueAddWaitTimeout</td>
+    <td>queue add wait time (tomcat connector thread waits)</td>
+    <td><code>10000</code></td>
+  </tr>
+  <tr>
+    <td>queueRemoveWaitTimeout</td>
+    <td>queue remove wait time (queue thread waits)</td>
+    <td><code>30000</code></td>
+  </tr>
+  
+  <tr>
+    <td>maxQueueLength</td>
+    <td>max queue length (default without limit)</td>
+    <td><code>-1</code></td>
+  </tr>
+  
+  <tr>
+    <td>threadPriority</td>
+    <td>change queue thread priority (1-10 ; 5 is normal)</td>
+    <td><code>5</code></td>
+  </tr>
+</table>
+  
+</p>
+<p>
+Example to get a lot of statistic information and no wait for ACK<br/>
+<source>
+    &lt;Sender
+      className="org.apache.catalina.cluster.tcp.ReplicationTransmitter"
+      replicationMode="fastasyncqueue"
+      doTransmitterProcessingStats="true"
+      doProcessingStats="true"
+      queueTimeWait="true"
+      queueDoStats="true"
+      queueCheckLock="true"
+      waitForAck="false"
+      autoConnect="false"
+      keepAliveTimeout="320000"
+      keepAliveMaxRequestCount="-1"/&gt;
+</source>
+</p>  
+</section>
+
+<section name="Cluster Configuration for ReplicationTransmitter ( asynchronous - mode)">
+<p>
+List of Attributes<br/>
+<table border="1" cellpadding="5">
+
+  <tr>
+    <th align="center" bgcolor="aqua">Attribute</th>
+    <th align="center" bgcolor="aqua">Description</th>
+    <th align="center" bgcolor="aqua">Default value</th>
+  </tr>
+  
+  <tr>
+    <td>keepAliveTimeout</td>
+    <td>active socket keep alive timeout</td>
+    <td><code>60000</code></td>
+  </tr>  
+
+  <tr>
+    <td>keepAliveMaxRequestCount</td>
+    <td>max request over this socket</td>
+    <td><code>-1</code></td>
+  </tr>  
+
+  <tr>
+    <td>doProcessingStats</td>
+    <td>create Processing time stats</td>
+    <td><code>false</code></td>
+  </tr>
+
+  <tr>
+    <td>doWaitAckStats</td>
+    <td>create waitAck time stats</td>
+    <td><code>false</code></td>
+  </tr>
+  
+  <tr>
+    <td>resend</td>
+    <td>resend message after failure, can overwrite at message</td>
+    <td><code>false</code></td>
+  </tr>
+
+</table>
+</p>
+<p>
+Example to get a processing statistic information, resend after failure and wait for ACK<br/>
+<source>
+    &lt;Sender
+      className="org.apache.catalina.cluster.tcp.ReplicationTransmitter"
+      replicationMode="asynchronous"
+      doProcessingStats="true"
+      doWaitAckStats="true"
+      waitForAck="true"
+      ackTimeout="30000"
+      resend="true"
+      keepAliveTimeout="320000"
+      keepAliveMaxRequestCount="-1"/&gt;
+</source>
+</p>  
+</section>
+    
+<section name="Cluster Configuration for ReplicationTransmitter ( synchronous - mode)">
+<p>
+List of Attributes<br/>
+<table border="1" cellpadding="5">
+
+  <tr>
+    <th align="center" bgcolor="aqua">Attribute</th>
+    <th align="center" bgcolor="aqua">Description</th>
+    <th align="center" bgcolor="aqua">Default value</th>
+  </tr>
+  
+  <tr>
+    <td>keepAliveTimeout</td>
+    <td>active socket keep alive timeout</td>
+    <td><code>60000</code></td>
+  </tr>  
+
+  <tr>
+    <td>keepAliveMaxRequestCount</td>
+    <td>max request over this socket</td>
+    <td><code>-1</code></td>
+  </tr>  
+
+  <tr>
+    <td>doProcessingStats</td>
+    <td>create Processing time stats</td>
+    <td><code>false</code></td>
+  </tr>
+
+  <tr>
+    <td>doWaitAckStats</td>
+    <td>create waitAck time stats</td>
+    <td><code>true</code></td>
+  </tr>
+
+  <tr>
+    <td>resend</td>
+    <td>resend message after failure, can overwrite at message</td>
+    <td><code>false</code></td>
+  </tr>
+
+</table>
+  
+</p>
+<p>
+Example to get a no processing statistic information, no wait for ACK, after 10000 request renew socket and autoconnect before first request is send.<br/>
+<source>
+    &lt;Sender
+      className="org.apache.catalina.cluster.tcp.ReplicationTransmitter"
+      replicationMode="synchronous"
+      autoConnect="true"
+      keepAliveTimeout="-1"
+      keepAliveMaxRequestCount="100000"/&gt;
+</source>
+</p>  
+</section>
+
+<section name="Cluster Configuration for ReplicationTransmitter ( pooled - mode)">
+<p>
+List of Attributes<br/>
+<table border="1" cellpadding="5">
+
+  <tr>
+    <th align="center" bgcolor="aqua">Attribute</th>
+    <th align="center" bgcolor="aqua">Description</th>
+    <th align="center" bgcolor="aqua">Default value</th>
+  </tr>
+  
+  <tr>
+    <td>keepAliveTimeout</td>
+    <td>active socket keep alive timeout</td>
+    <td><code>60000</code></td>
+  </tr>  
+
+  <tr>
+    <td>keepAliveMaxRequestCount</td>
+    <td>max request over this socket</td>
+    <td><code>-1</code></td>
+  </tr>  
+
+  <tr>
+    <td>maxPoolSocketLimit</td>
+    <td>max pooled sockets (Sender Sockets)</td>
+    <td><code>25</code></td>
+  </tr>
+  
+  <tr>
+    <td>resend</td>
+    <td>resend message after failure, can overwrite at message</td>
+    <td><code>false</code></td>
+  </tr>
+  
+</table>
+  
+</p>
+<p>
+Example to get a no processing statistic information, wait for ACK, after 10000 request renew socket, only 10 SockerSender available and autoconnect before first request is send.<br/>
+<source>
+    &lt;Sender
+      className="org.apache.catalina.cluster.tcp.ReplicationTransmitter"
+      replicationMode="pooled"
+      autoConnect="true"
+      maxPoolSocketLimit="10"
+      keepAliveTimeout="-1"
+      keepAliveMaxRequestCount="10000"
+      waitForAck="true" /&gt;
+</source>
+</p>  
+</section>
+
+<section name="Cluster Configuration for ReplicationTransmitter ( DeltaManager Attribute)">
+<p>
+List of Attributes<br/>
+<table border="1" cellpadding="5">
+
+  <tr>
+    <th align="center" bgcolor="aqua">Attribute</th>
+    <th align="center" bgcolor="aqua">Description</th>
+    <th align="center" bgcolor="aqua">Default value</th>
+  </tr>
+  
+  <tr>
+    <td>expireSessionsOnShutdown</td>
+    <td>When server stopped, expire all sessions also at backup nodes (only for testing)</td>
+    <td><code>false</code></td>
+  </tr>
+
+  <tr>
+    <td>maxActiveSessions</td>
+    <td>Number of active sessions. (Default is no limit)</td>
+    <td><code>-1</code></td>
+  </tr>  
+
+  <tr>
+    <td>notifyListenersOnReplication</td>
+    <td>Notify application session listener to session creation 
+    and expiring events at backup nodes</td>
+    <td><code>true</code></td>
+  </tr>
+
+  <tr>
+    <td>notifySessionListenersOnReplication</td>
+    <td>Notify application session listener to attribute changes at backup nodes</td>
+    <td><code>true</code></td>
+  </tr>
+
+  <tr>
+    <td>stateTransferTimeout</td>
+    <td>Timeout that session state transfer is complete. Is attribute <code>stateTransferTimeout == -1</code> 
+        then application wait that other node send the complete session state</td>
+    <td><code>60</code></td>
+  </tr>
+  
+  <tr>
+    <td>sendAllSessions</td>
+    <td>Flag to send sessions as splited blocks</td>
+    <td><code>true</code></td>
+  </tr>
+
+  <tr>
+    <td>sendAllSessionsSize</td>
+    <td>Number of serialize sessions inside a send block session message. Only useful when <code>sendAllSessions==false</code></td>
+    <td><code>1000</code></td>
+  </tr>
+
+  <tr>
+    <td>sendAllSessionsWaitTime</td>
+    <td>wait time between two session send blocks.</td>
+    <td><code>2000</code></td>
+  </tr>
+
+  <tr>
+    <td>sendClusterDomainOnly</td>
+    <td>Send all session messages only to member inside same cluster domain 
+        (value od Membership attribute mcastClusterDomain). Also don't handle
+        session messages from other domains.</td>
+    <td><code>true</code></td>
+  </tr>  
+
+  <tr>
+    <td>stateTimestampDrop</td>
+    <td>DeltaManager queued Sessions messages when send GET_ALL_SESSION to other node.
+    with stateTimestampDrop all messages before state transfer message creation date (find session) are dropped.
+    Only other GET_ALL_SESSION events are handle with date before state transfer message.</td>
+    <td><code>true</code></td>
+  </tr>  
+  
+</table>
+  
+</p>
+<p>
+Example send all sessions at separate blocks. Serialize and send 100 session inside one block.
+Wait maximale two minutes before the complete backup sessions are loaded inside tomcat boot process.
+Between send blocks wait 5 secs to transfers the session block to other node. This save memory
+when you use the async modes with queues.<br/>
+<source>
+    &lt;Cluster className="org.apache.catalina.tcp.SimpleTcpCluster"
+      managerClassName="org.apache.catalina.cluster.session.DeltaManager"
+      manager.stateTransferTimeout="120"
+      manager.sendAllSessions="false"
+      manager.sendAllSessionsSize="100"
+      manager.sendAllSessionsWaitTime="5000"
+      "/&gt;
+</source>
+</p>
+<p>
+<b>Note:</b><br/>
+As <em>Cluster.defaultMode=true</em> you can configure the manager attributes with prefix <em>manager.</em>. 
+<br/>
+<b>Note:</b><br/>
+With <em>Cluster.setProperty(&lt;String&gt;,&lt;String&gt;)</em> you can modify 
+attributes for all register managers. The method exists as MBeans operation.
+</p>
+</section>
+
+<section name="Bind session after crash to failover node">
+<p>
+As you configure more then two nodes at same cluster for backup, most loadbalancer
+send don't all your requests after failover to the same node.
+</p>
+<p> 
+The JvmRouteBinderValve handle tomcat jvmRoute takeover using mod_jk module after node
+failure. After a node crashed the next request going to other cluster node. The JvmRouteBinderValve 
+now detect the takeover and rewrite the jsessionid
+information to the backup cluster node. After the next response all client
+request goes direct to the backup node. The change sessionid send also to all
+other cluster nodes. Well, now the session stickyness work directly to the
+backup node, but traffic don't go back too restarted cluster nodes!<br/>
+As jsessionid was created by cookie, the change JSESSIONID cookie resend with next response.
+</p>
+<p>
+You must add JvmRouteBinderValve and the corresponding cluster message listener JvmRouteSessionIDBinderListener.
+As you add the new listener you must also add the default ClusterSessionListener that receiver the normal cluster messages.
+
+<source>
+&lt;Cluster className="org.apache.catalina.tcp.SimpleTcpCluster" &gt;
+...
+     &lt;Valve className="org.apache.catalina.cluster.session.JvmRouteBinderValve"
+               enabled="true" sessionIdAttribute="takeoverSessionid"/&gt;	
+     &lt;ClusterListener className="org.apache.catalina.cluster.session.JvmRouteSessionIDBinderListener" /&gt;
+     &lt;ClusterListener className="org.apache.catalina.cluster.session.ClusterSessionListener" /&gt;
+...
+&lt;Cluster&gt;
+</source>
+</p>
+<p>
+<b>Hint:</b><br/>
+With attribute <i>sessionIdAttribute</i> you can change the request attribute name that included the old session id.
+Default attribuite name is <i>org.apache.catalina.cluster.session.JvmRouteOrignalSessionID</i>.
+</p>
+<p>
+<b>Trick:</b><br/>
+You can enable this mod_jk turnover mode via JMX before you drop a node to all backup nodes!
+Set enable true on all JvmRouteBinderValve backups, disable worker at mod_jk 
+and then drop node and restart it! Then enable mod_jk Worker and disable JvmRouteBinderValves again. 
+This use case means that only requested session are migrated.
+</p>
+
+</section>
+
+</section>
+
+
+<section name="Monitoring your Cluster with JMX">
+<p>Monitoring is a very important question when you use a cluster. Some of the cluster objects are JMX MBeans </p>
+<p>Add the following parameter to your startup script with Java 5:
+<source>
+set CATALINA_OPTS=\
+-Dcom.sun.management.jmxremote \
+-Dcom.sun.management.jmxremote.port=%my.jmx.port% \
+-Dcom.sun.management.jmxremote.ssl=false \
+-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>
+&lt;Connector port="${AJP.PORT}" 
+   handler.list="mx"
+   mx.enabled="true" 
+   mx.httpHost="${JMX.HOST}" 
+   mx.httpPort="${JMX.PORT}" 
+   protocol="AJP/1.3" /&gt;
+</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">
+
+  <tr>
+    <th align="center" bgcolor="aqua">Name</th>
+    <th align="center" bgcolor="aqua">Description</th>
+    <th align="center" bgcolor="aqua">MBean ObjectName - Engine</th>
+    <th align="center" bgcolor="aqua">MBean ObjectName - Host</th>
+  </tr>
+
+  <tr>
+    <td>Cluster</td>
+    <td>The complete cluster element</td>
+    <td><code>type=Cluster</code></td>
+    <td><code>type=Cluster,host=${HOST}</code></td>
+  </tr>
+ 
+  <tr>
+    <td>ClusterSender</td>
+    <td>Configuration and stats of the sender infrastructure</td>
+    <td><code>type=ClusterSender</code></td>
+    <td><code>type=ClusterSender,host=${HOST}</code></td>
+  </tr>
+ 
+  <tr>
+    <td>ClusterReceiver</td>
+    <td>Configuration and stats of the recevier infrastructure</td>
+    <td><code>type=ClusterReceiver</code></td>
+    <td><code>type=ClusterReceiver,host=${HOST}</code></td>
+  </tr>
+
+  <tr>
+    <td>ClusterMembership</td>
+    <td>Configuration and stats of the membership infrastructure</td>
+    <td><code>type=ClusterMembership</code></td>
+    <td><code>type=ClusterMembership,host=${HOST}</code></td>
+  </tr>
+
+  <tr>
+    <td>IDataSender</td>
+    <td>For every cluster member it exist a sender mbeans. 
+    It exists speziall MBeans to all replication modes</td>
+    <td><code>type=IDataSender,
+        senderAddress=${MEMBER.SENDER.IP},
+        senderPort=${MEMBER.SENDER.PORT}</code></td>
+    <td><code>type=IDataSender,host=${HOST},
+        senderAddress=${MEMBER.SENDER.IP},
+        senderPort=${MEMBER.SENDER.PORT}</code></td>
+  </tr>
+ 
+  <tr>
+    <td>DeltaManager</td>
+    <td>This manager control the sessions and handle session replication </td>
+    <td><code>type=Manager,path=${APP.CONTEXT.PATH}, host=${HOST}</code></td>
+    <td><code>type=Manager,path=${APP.CONTEXT.PATH}, host=${HOST}</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>
+    <td><code>type=Valve,name=ReplicationValve,host=${HOST}</code></td>
+  </tr>
+
+  <tr>
+    <td>JvmRouteBinderValve</td>
+    <td>This is a cluster fallback valve to change the Session ID to the current tomcat jvmroute.</td>
+    <td><code>type=Valve,name=JvmRouteBinderValve,
+              path=${APP.CONTEXT.PATH}</code></td>
+    <td><code>type=Valve,name=JvmRouteBinderValve,host=${HOST},
+              path=${APP.CONTEXT.PATH}</code></td>
+  </tr>
+
+</table>
+</p>
+</section>
+
+<section name="FAQ">
+<p>Please see <a href="http://tomcat.apache.org/faq/cluster.html">the clustering section of the FAQ</a>.</p>
+</section>
+
+</body>
+
+</document>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/config/ajp.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/config/ajp.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/config/ajp.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,297 @@
+<?xml version="1.0"?>
+<!DOCTYPE document [
+  <!ENTITY project SYSTEM "project.xml">
+]>
+<document url="ajp.html">
+
+  &project;
+
+  <properties>
+    <author email="remm at apache.org">Remy Maucherat</author>
+    <author email="yoavs at apache.org">Yoav Shapira</author>
+    <author email="arjaquith at mindspring.com">Andrew R. Jaquith</author>
+    <title>The AJP Connector</title>
+  </properties>
+
+<body>
+
+
+<section name="Introduction">
+
+  <p>The <strong>AJP Connector</strong> element represents a
+  <strong>Connector</strong> component that communicates with a web
+  connector via the <code>AJP</code> protocol.  This is used for cases
+  where you wish to invisibly integrate Tomcat 5 into an existing (or new)
+  Apache installation, and you want Apache to handle the static content
+  contained in the web application, and/or utilize Apache's SSL
+  processing.</p>
+
+  <p>This connector supports load balancing when used in conjunction with
+  the <code>jvmRoute</code> attribute of the 
+  <a href="engine.html">Engine</a>.</p>
+
+<p>The native connectors supported with this Tomcat release are:
+<ul>
+<li>JK 1.2.x with any of the supported servers</li>
+<li>mod_proxy on Apache httpd 2.x (included by default in Apache HTTP Server 2.2), 
+with AJP enabled</li>
+</ul>
+</p>
+
+<p><b>Other native connectors supporting AJP may work, but are no longer supported.</b></p>
+
+</section>
+
+
+<section name="Attributes">
+
+  <subsection name="Common Attributes">
+
+  <p>All implementations of <strong>Connector</strong>
+  support the following attributes:</p>
+
+  <attributes>
+
+    <attribute name="allowTrace" required="false">
+      <p>A boolean value which can be used to enable or disable the TRACE
+      HTTP method. If not specified, this attribute is set to false.</p>
+    </attribute>
+
+    <attribute name="emptySessionPath" required="false">
+      <p>If set to <code>true</code>, all paths for session cookies will be set
+      to <code>/</code>. This can be useful for portlet specification implementations,
+      but will greatly affect performance if many applications are accessed on a given
+      server by the client.
+      If not specified, this attribute is set to <code>false</code>.</p>
+    </attribute>
+
+    <attribute name="enableLookups" required="false">
+      <p>Set to <code>true</code> if you want calls to
+      <code>request.getRemoteHost()</code> to perform DNS lookups in
+      order to return the actual host name of the remote client.  Set
+      to <code>false</code> to skip the DNS lookup and return the IP
+      address in String form instead (thereby improving performance).
+      By default, DNS lookups are enabled.</p>
+    </attribute>
+
+    <attribute name="maxPostSize" required="false">
+      <p>The maximum size in bytes of the POST which will be handled by
+      the container FORM URL parameter parsing. The feature can be disabled by
+      setting this attribute to a value less than or equal to 0.
+      If not specified, this attribute is set to 2097152 (2 megabytes).</p>
+    </attribute>
+
+    <attribute name="maxSavePostSize" required="false">
+      <p>The maximum size in bytes of the POST which will be saved/buffered by
+      the container during FORM or CLIENT-CERT authentication. For both types
+      of authentication, the POST will be saved/buffered before the user is
+      authenticated. For CLIENT-CERT authentication, the POST is buffered for
+      the duration of the SSL handshake and the buffer emptied when the request
+      is processed. For FORM authentication the POST is saved whilst the user
+      is re-directed to the login form and is retained until the user
+      successfully authenticates or the session associated with the
+      authentication request expires. The limit can be disabled by setting this
+      attribute to -1. Setting the attribute to zero will disable the saving of
+      POST data during authentication. If not specified, this attribute is set
+      to 4096 (4 kilobytes).</p>
+    </attribute>
+
+    <attribute name="protocol" required="false">
+      <p>This attribute value must be <code>AJP/1.3</code> to use the AJP
+      handler.</p>
+    </attribute>
+
+    <attribute name="proxyName" required="false">
+      <p>If this <strong>Connector</strong> is being used in a proxy
+      configuration, configure this attribute to specify the server name
+      to be returned for calls to <code>request.getServerName()</code>.
+      See <a href="#Proxy Support">Proxy Support</a> for more
+      information.</p>
+    </attribute>
+
+    <attribute name="proxyPort" required="false">
+      <p>If this <strong>Connector</strong> is being used in a proxy
+      configuration, configure this attribute to specify the server port
+      to be returned for calls to <code>request.getServerPort()</code>.
+      See <a href="#Proxy Support">Proxy Support</a> for more
+      information.</p>
+    </attribute>
+
+    <attribute name="redirectPort" required="false">
+      <p>If this <strong>Connector</strong> is supporting non-SSL
+      requests, and a request is received for which a matching
+      <code>&lt;security-constraint&gt;</code> requires SSL transport,
+      Catalina will automatically redirect the request to the port
+      number specified here.</p>
+    </attribute>
+
+    <attribute name="request.registerRequests" required="false">
+      <p>This attribute controls request registration for JMX monitoring
+      of the Connector.  It is enabled by default, but may be turned
+      it off to save a bit of memory.</p>
+    </attribute>
+
+    <attribute name="scheme" required="false">
+      <p>Set this attribute to the name of the protocol you wish to have
+      returned by calls to <code>request.getScheme()</code>.  For
+      example, you would set this attribute to "<code>https</code>"
+      for an SSL Connector.  The default value is "<code>http</code>".
+      See <a href="#SSL Support">SSL Support</a> for more information.</p>
+    </attribute>
+
+    <attribute name="secure" required="false">
+      <p>Set this attribute to <code>true</code> if you wish to have
+      calls to <code>request.isSecure()</code> to return <code>true</code>
+      for requests received by this Connector (you would want this on an
+      SSL Connector).  The default value is <code>false</code>.</p>
+    </attribute>
+
+    <attribute name="URIEncoding" required="false">
+      <p>This specifies the character encoding used to decode the URI bytes,
+      after %xx decoding the URL. If not specified, ISO-8859-1 will be used.
+      </p>
+    </attribute>
+
+    <attribute name="useBodyEncodingForURI" required="false">
+      <p>This specifies if the encoding specified in contentType should be used
+      for URI query parameters, instead of using the URIEncoding. This
+      setting is present for compatibility with Tomcat 4.1.x, where the
+      encoding specified in the contentType, or explicitely set using
+      Request.setCharacterEncoding method was also used for the parameters from
+      the URL. The default value is <code>false</code>.
+      </p>
+    </attribute>
+
+    <attribute name="useIPVHosts" required="false">
+      <p>Set this attribute to <code>true</code> to cause Tomcat to use
+      the ServerName passed by the native web server to determine the Host
+      to send the request to.  The default value is <code>false</code>.</p>
+    </attribute>
+
+    <attribute name="xpoweredBy" required="false">
+      <p>Set this attribute to <code>true</code> to cause Tomcat to advertise
+      support for the Srevlet specification using the header recommended in the
+      specification.  The default value is <code>false</code>.</p>
+    </attribute>
+
+  </attributes>
+
+  </subsection>
+
+  <subsection name="Standard Implementation">
+
+  <p>To use AJP, you
+  must specify the protocol attribute (see above).</p>
+
+  <p><strong>This implementation supports the AJP 1.3 protocol.</strong></p>
+
+  <p>It supports the following additional attributes (in addition to the
+  common attributes listed above):</p>
+
+  <attributes>
+
+    <attribute name="address" required="false">
+      <p>For servers with more than one IP address, this attribute
+      specifies which address will be used for listening on the specified
+      port.  By default, this port will be used on all IP addresses
+      associated with the server. A value of <code>127.0.0.1</code>
+      indicates that the Connector will only listen on the loopback
+      interface.</p>
+    </attribute>
+
+    <attribute name="backlog" required="false">
+      <p>The maximum queue length for incoming connection requests when
+      all possible request processing threads are in use.  Any requests
+      received when the queue is full will be refused.  The default
+      value is 10.</p>
+    </attribute>
+
+    <attribute name="bufferSize" required="false">
+      <p>The size of the output buffer to use.  If less than or equal to zero,
+         then output buffering is disabled.  The default value is -1
+         (i.e. buffering disabled)</p>
+    </attribute>
+
+    <attribute name="connectionTimeout" required="false">
+      <p>The number of milliseconds this <strong>Connector</strong> will wait,
+      after accepting a connection, for the request URI line to be
+      presented.  The default value is infinite (i.e. no timeout).</p>
+    </attribute>
+
+    <attribute name="minProcessors" required="false">
+      <strong>deprecated</strong>
+      <p>The minimum number of processors to start at initialization time.
+      If not specified, this atttribute is set to 5.</p>
+    </attribute>
+
+    <attribute name="maxProcessors" required="false">
+      <strong>deprecated</strong>
+      <p>The maximum number of processors allowed. This should be
+      set to a value that is greater than or equal to the maximum number
+      of concurrent connections the remote web server can open to Tomcat 
+      simultaneously. For example, if the web server is Apache 1.x or 2.x
+      Tomcat's <code>maxProcessors</code> should be set to the 
+      value of Apache's <code>maxClients</code> directive.</p>
+      <p>A <code>maxProcessors</code> value of zero (0) signifies that 
+      the number of processors is unlimited. If not specified, this
+      atttribute defaults to 20.</p>
+     </attribute>
+
+    <attribute name="maxSpareThreads" required="false">
+      <p>The maximum number of unused request processing threads that
+      will be allowed to exist until the thread pool starts stopping the
+      unnecessary threads.  The default value is 50.</p>
+    </attribute>
+
+    <attribute name="maxThreads" required="false">
+      <p>The maximum number of request processing threads to be created
+      by this <strong>Connector</strong>, which therefore determines the
+      maximum number of simultaneous requests that can be handled.  If
+      not specified, this attribute is set to 200.</p>
+    </attribute>
+
+    <attribute name="minSpareThreads" required="false">
+      <p>The number of request processing threads that will be created
+      when this <strong>Connector</strong> is first started.  The connector
+      will also make sure it has the specified number of idle processing
+      threads available. This attribute should be set to a value smaller
+      than that set for <code>maxThreads</code>.  The default value is 4.</p>
+    </attribute>
+
+    <attribute name="port" required="true">
+      <p>The TCP port number on which this <strong>Connector</strong>
+      will create a server socket and await incoming connections.  Your
+      operating system will allow only one server application to listen
+      to a particular port number on a particular IP address.</p>
+    </attribute>
+
+    <attribute name="tcpNoDelay" required="false">
+      <p>If set to <code>true</code>, the TCP_NO_DELAY option will be
+      set on the server socket, which improves performance under most
+      circumstances.  This is set to <code>true</code> by default.</p>
+    </attribute>
+
+    <attribute name="tomcatAuthentication" required="false">
+      <p>If set to <code>true</code>, the authetication will be done in Tomcat. 
+      Otherwise, the authenticated principal will be propagated from the native
+      webaserver and used for authorization in Tomcat.  
+      The default value is <code>true</code>.</p>
+    </attribute>
+
+  </attributes>
+
+  </subsection>
+
+</section>
+
+
+<section name="Nested Components">
+
+  <p>None at this time.</p>
+
+</section>
+
+
+</body>
+
+</document>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/config/context.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/config/context.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/config/context.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,778 @@
+<?xml version="1.0"?>
+<!DOCTYPE document [
+  <!ENTITY project SYSTEM "project.xml">
+]>
+<document url="context.html">
+
+  &project;
+
+  <properties>
+    <author email="craigmcc at apache.org">Craig R. McClanahan</author>
+    <title>The Context Container</title>
+  </properties>
+
+<body>
+
+
+<section name="Introduction">
+
+  <p>The <strong>Context</strong> element represents a <em>web
+  application</em>, which is run within a particular virtual host.
+  Each web application is based on a <em>Web Application Archive</em>
+  (WAR) file, or a corresponding directory containing the corresponding
+  unpacked contents, as described in the Servlet Specification (version
+  2.2 or later).  For more information about web application archives,
+  you can download the
+  <a href="http://java.sun.com/products/servlet/download.html">Servlet
+  Specification</a>, and review the Tomcat
+  <a href="../appdev/index.html">Application Developer's Guide</a>.</p>
+
+  <p>The web application used to process each HTTP request is selected
+  by Catalina based on matching the longest possible prefix of the
+  Request URI against the <em>context path</em> of each defined Context.
+  Once selected, that Context will select an appropriate servlet to
+  process the incoming request, according to the servlet mappings defined
+  in the <em>web application deployment descriptor</em> file (which MUST
+  be located at <code>/WEB-INF/web.xml</code> within the web app's
+  directory hierarchy).</p>
+
+  <p>You may define as many <strong>Context</strong> elements as you
+  wish.  Each such Context MUST have a unique
+  context path, which is defined by the <code>path</code> attribute.
+  In addition, you MUST define a Context with a context path equal to
+  a zero-length string.  This Context becomes the <em>default</em>
+  web application for this virtual host, and is used to process all
+  requests that do not match any other Context's context path.</p>
+
+  <p>In addition to nesting <strong>Context</strong> elements inside a
+  <a href="host.html">Host</a> element, you can also store them:</p>
+  <ul>
+  <li>in the individual <code>$CATALINA_HOME/conf/context.xml</code> file: 
+  the Context element information will be loaded by all webapps</li>
+  <li>in the individual 
+  <code>$CATALINA_HOME/conf/[enginename]/[hostname]/context.xml.default</code>
+  file: the Context element information will be loaded by all webapps of that
+  host</li>
+  <li>in individual files (with a ".xml" extension) in the 
+  <code>$CATALINA_HOME/conf/[enginename]/[hostname]/</code> directory</li>
+  <li>if the previous file was not found for this application, in individual file
+  at <code>/META-INF/context.xml</code> inside the application files</li>
+  </ul>
+  <p>See
+  <a href="host.html#Automatic Application Deployment">Automatic
+  Application Deployment</a> for more information. This method allows dynamic
+  reconfiguration of the web application, since the main 
+  <code>conf/server.xml</code> file cannot be reloaded without restarting
+  Tomcat. <b>Please note that for tomcat 5, unlike tomcat 4.x, it is NOT
+  recommended to place &lt;Context&gt; elements directly in the server.xml file.</b>
+  Instead, put them in the META-INF/context.xml directory of your WAR file or
+  the conf directory as described above.
+  </p>
+
+  <p>In addition to explicitly specified Context elements, there are
+  several techniques by which Context elements can be created automatically
+  for you.  See <a href="host.html#Automatic Application Deployment">
+  Automatic Application Deployment</a> and
+  <a href="host.html#User Web Applications">User Web Applications</a>
+  for more information.</p>
+
+    <blockquote><em>
+    <p>The description below uses the variable name $CATALINA_HOME
+    to refer to the directory into which you have installed Tomcat 5,
+    and is the base directory against which most relative paths are
+    resolved.  However, if you have configured Tomcat 5 for multiple
+    instances by setting a CATALINA_BASE directory, you should use
+    $CATALINA_BASE instead of $CATALINA_HOME for each of these
+    references.</p>
+    </em></blockquote>
+
+</section>
+
+
+<section name="Attributes">
+
+  <subsection name="Common Attributes">
+
+    <p>All implementations of <strong>Context</strong>
+    support the following attributes:</p>
+
+    <attributes>
+
+      <attribute name="backgroundProcessorDelay" required="false">
+        <p>This value represents the delay in seconds between the 
+        invocation of the backgroundProcess method on this context and 
+        its child containers, including all wrappers. 
+        Child containers will not be invoked if their delay value is not 
+        negative (which would mean they are using their own processing 
+        thread). Setting this to a positive value will cause 
+        a thread to be spawn. After waiting the specified amount of time, 
+        the thread will invoke the backgroundProcess method on this host 
+        and all its child containers. A context will use background 
+        processing to perform session expiration and class monitoring for
+        reloading. If not specified, the default value for this attribute is 
+        -1, which means the context will rely on the background processing 
+        thread of its parent host.</p>
+      </attribute>
+
+      <attribute name="className" required="false">
+        <p>Java class name of the implementation to use.  This class must
+        implement the <code>org.apache.catalina.Context</code> interface.
+        If not specified, the standard value (defined below) will be used.</p>
+      </attribute>
+
+      <attribute name="cookies" required="false">
+        <p>Set to <code>true</code> if you want cookies to be used for
+        session identifier communication if supported by the client (this
+        is the default).  Set to <code>false</code> if you want to disable
+        the use of cookies for session identifier communication, and rely
+        only on URL rewriting by the application.</p>
+      </attribute>
+
+      <attribute name="crossContext" required="false">
+        <p>Set to <code>true</code> if you want calls within this application
+        to <code>ServletContext.getContext()</code> to successfully return a
+        request dispatcher for other web applications running on this virtual
+        host.  Set to <code>false</code> (the default) in security
+        conscious environments, to make <code>getContext()</code> always
+        return <code>null</code>.</p>
+      </attribute>
+
+      <attribute name="docBase" required="true">
+        <p>The <em>Document Base</em> (also known as the <em>Context
+        Root</em>) directory for this web application, or the pathname
+        to the web application archive file (if this web application is
+        being executed directly from the WAR file).    You may specify
+        an absolute pathname for this directory or WAR file, or a pathname
+        that is relative to the <code>appBase</code> directory of the
+        owning <a href="host.html">Host</a>.</p>
+      </attribute>
+
+      <attribute name="override" required="false">
+        <p>Set to <code>true</code> to have explicit settings in this
+        Context element override any corresponding settings in the
+        <a href="defaultcontext.html">DefaultContext</a> element associated
+        with our owning <a href="host.html">Host</a>.  By default, settings
+        in the DefaultContext element will be used.</p>
+      </attribute>
+
+      <attribute name="privileged" required="false">
+        <p>Set to <code>true</code> to allow this context to use container
+        servlets, like the manager servlet.</p>
+      </attribute>
+
+      <attribute name="path" required="false">
+        <p>The <em>context path</em> of this web application, which is
+        matched against the beginning of each request URI to select the
+        appropriate web application for processing.  All of the context paths
+        within a particular <a href="host.html">Host</a> must be unique.
+        If you specify a context path of an empty string (""), you are
+        defining the <em>default</em> web application for this Host, which
+        will process all requests not assigned to other Contexts. The value of
+        this field must not be set except when statically defining a Context in
+        server.xml, as it will be infered from the filenames used for either the 
+        .xml context file or the docBase.</p>
+      </attribute>
+
+      <attribute name="reloadable" required="false">
+        <p>Set to <code>true</code> if you want Catalina to monitor classes in
+        <code>/WEB-INF/classes/</code> and <code>/WEB-INF/lib</code> for
+        changes, and automatically reload the web application if a change
+        is detected.  This feature is very useful during application
+        development, but it requires significant runtime overhead and is
+        not recommended for use on deployed production applications.  That's
+        why the default setting for this attribute is <i>false</i>.  You
+        can use the <a href="../manager-howto.html">Manager</a> web
+        application, however, to trigger reloads of deployed applications
+        on demand.</p>
+      </attribute>
+
+      <attribute name="wrapperClass" required="false">
+        <p>Java class name of the <code>org.apache.catalina.Wrapper</code>
+        implementation class that will be used for servlets managed by this
+        Context.  If not specified, a standard default value will be used.</p>
+      </attribute>
+
+    </attributes>
+
+  </subsection>
+
+
+  <subsection name="Standard Implementation">
+
+    <p>The standard implementation of <strong>Context</strong> is
+    <strong>org.apache.catalina.core.StandardContext</strong>.
+    It supports the following additional attributes (in addition to the
+    common attributes listed above):</p>
+
+    <attributes>
+
+      <attribute name="allowLinking" required="false">
+        <p>If the value of this flag is <code>true</code>, symlinks will be
+        allowed inside the web application, pointing to resources outside the
+        web application base path. If not specified, the default value
+        of the flag is <code>false</code>.</p>
+        <p><b>NOTE: This flag MUST NOT be set to true on the Windows platform
+        (or any other OS which does not have a case sensitive filesystem),
+        as it will disable case sensitivity checks, allowing JSP source code
+        disclosure, among other security problems.</b></p>
+      </attribute>
+
+      <attribute name="antiJARLocking" required="false">
+        <p>If true, the Tomcat classloader will take extra measures to avoid
+        JAR file locking when resources are accessed inside JARs through URLs.
+        This will impact startup time of applications, but could prove to be useful
+        on platforms or configurations where file locking can occur.
+        If not specified, the default value is <code>false</code>.</p>
+      </attribute>
+
+      <attribute name="antiResourceLocking" required="false">
+        <p>If true, Tomcat will prevent any file locking.
+        This will significantly impact startup time of applications, 
+        but allows full webapp hot deploy and undeploy on platforms 
+        or configurations where file locking can occur.
+        If not specified, the default value is <code>false</code>.</p>
+   
+        <p>Please note that setting this to <code>true</code> has some side effects,
+        including the disabling of JSP reloading in a running server: see
+        <a href="http://issues.apache.org/bugzilla/show_bug.cgi?id=37668">Bugzilla 37668</a>.
+        </p>
+      </attribute>
+
+      <attribute name="cacheMaxSize" required="false">
+        <p>Maximum size of the static resource cache in kilobytes. 
+        If not specified, the default value is <code>10240</code>
+        (10 megabytes).</p>
+      </attribute>
+
+      <attribute name="cacheTTL" required="false">
+        <p>Amount of time in milliseconds between cache entries revalidation.
+        If not specified, the default value is <code>5000</code> 
+        (5 seconds).</p>
+      </attribute>
+
+      <attribute name="cachingAllowed" required="false">
+        <p>If the value of this flag is <code>true</code>, the cache for static
+        resources will be used. If not specified, the default value
+        of the flag is <code>true</code>.</p>
+      </attribute>
+
+      <attribute name="caseSensitive" required="false">
+        <p>If the value of this flag is <code>true</code>, all case sensitivity
+        checks will be disabled. If not 
+        specified, the default value of the flag is <code>true</code>.</p>
+        <p><b>NOTE: This flag MUST NOT be set to false on the Windows platform
+        (or any other OS which does not have a case sensitive filesystem),
+        as it will disable case sensitivity checks, allowing JSP source code
+        disclosure, among other security problems.</b></p>
+      </attribute>
+
+      <attribute name="processTlds" required="false">
+        <p>Whether the context should process TLDs on startup.  The default
+        is true.  The false setting is intended for special cases
+        that know in advance TLDs are not part of the webapp.</p>
+      </attribute>
+
+      <attribute name="swallowOutput" required="false">
+        <p>If the value of this flag is <code>true</code>, the bytes output to
+        System.out and System.err by the web application will be redirected to
+        the web application logger. If not specified, the default value
+        of the flag is <code>false</code>.</p>
+      </attribute>
+
+      <attribute name="tldNamespaceAware" required="false">
+        <p>If the value of this flag is <code>true</code>, the TLD files
+        XML validation will be namespace-aware.  If you turn this flag on,
+        you should probably also turn <code>tldValidation</code> on.  The
+        default value for this flag is <code>false</code>, and setting it
+        to true will incur a performance penalty.
+        </p>
+      </attribute>
+
+      <attribute name="tldValidation" required="false">
+        <p>If the value of this flag is <code>true</code>, the TLD files
+        will be XML validated on context startup.  The default value for
+        this flag is <code>false</code>, and setting it to true will incur
+        a performance penalty.</p>
+      </attribute>
+
+      <attribute name="unloadDelay" required="false">
+        <p>Amount of ms that the container will wait for servlets to unload.
+        If not specified, the default value of the flag is <code>2000</code> 
+        ms.</p>
+      </attribute>
+
+      <attribute name="unpackWAR" required="false">
+        <p>If true, Tomcat will unpack all compressed web applications before
+        running them.
+        If not specified, the default value is <code>true</code>.</p>
+      </attribute>
+
+      <attribute name="useNaming" required="false">
+        <p>Set to <code>true</code> (the default) to have Catalina enable a
+        JNDI <code>InitialContext</code> for this web application that is
+        compatible with Java2 Enterprise Edition (J2EE) platform
+        conventions.</p>
+      </attribute>
+
+      <attribute name="workDir" required="false">
+        <p>Pathname to a scratch directory to be provided by this Context
+        for temporary read-write use by servlets within the associated web
+        application.  This directory will be made visible to servlets in the
+        web application by a servlet context attribute (of type
+        <code>java.io.File</code>) named
+        <code>javax.servlet.context.tempdir</code> as described in the
+        Servlet Specification.  If not specified, a suitable directory
+        underneath <code>$CATALINA_HOME/work</code> will be provided.</p>
+      </attribute>
+
+    </attributes>
+
+  </subsection>
+
+
+</section>
+
+
+<section name="Nested Components">
+
+  <p>You can nest at most one instance of the following utility components
+  by nesting a corresponding element inside your <strong>Context</strong>
+  element:</p>
+  <ul>
+  <li><a href="loader.html"><strong>Loader</strong></a> -
+      Configure the web application class loader that will be used to load
+      servlet and bean classes for this web application.  Normally, the
+      default configuration of the class loader will be sufficient.</li>
+  <li><a href="manager.html"><strong>Manager</strong></a> -
+      Configure the session manager that will be used to create, destroy,
+      and persist HTTP sessions for this web application.  Normally, the
+      default configuration of the session manager will be sufficient.</li>
+  <li><a href="realm.html"><strong>Realm</strong></a> -
+      Configure a realm that will allow its
+      database of users, and their associated roles, to be utilized solely
+      for this particular web application.  If not specified, this web
+      application will utilize the Realm associated with the owning
+      <a href="host.html">Host</a> or <a href="engine.html">Engine</a>.</li>
+  <li><a href="resources.html"><strong>Resources</strong></a> -
+      Configure the resource manager that will be used to access the static
+      resources associated with this web application.  Normally, the
+      default configuration of the resource manager will be sufficient.</li>
+  <li><strong>WatchedResource</strong> - The auto deployer will monitor the 
+      specified static resource of the web application for updates, and will
+      reload the web application if is is updated. The content of this element
+      must be a string.</li>
+  </ul>
+
+</section>
+
+
+<section name="Special Features">
+
+
+  <subsection name="Logging">
+
+    <p>A context is associated with the 
+       <code>org.apache.catalina.core.ContainerBase.[enginename].[hostname].[path]</code>
+       log category.  Note that the brackets are actually part of the name, don't omit them.</p>
+
+  </subsection>
+
+
+  <subsection name="Access Logs">
+
+    <p>When you run a web server, one of the output files normally generated
+    is an <em>access log</em>, which generates one line of information for
+    each request processed by the server, in a standard format.  Catalina
+    includes an optional <a href="valve.html">Valve</a> implementation that
+    can create access logs in the same standard format created by web servers,
+    or in any number of custom formats.</p>
+
+    <p>You can ask Catalina to create an access log for all requests
+    processed by an <a href="engine.html">Engine</a>,
+    <a href="host.html">Host</a>, or <a href="context.html">Context</a>
+    by nesting a <a href="valve.html">Valve</a> element like this:</p>
+
+<source>
+&lt;Context path="/examples" ...&gt;
+  ...
+  &lt;Valve className="org.apache.catalina.valves.AccessLogValve"
+         prefix="localhost_access_log." suffix=".txt"
+         pattern="common"/&gt;
+  ...
+&lt;/Context&gt;
+</source>
+
+    <p>See <a href="valve.html#Access Log Valve">Access Log Valve</a>
+    for more information on the configuration attributes that are
+    supported.</p>
+
+  </subsection>
+
+
+  <subsection name="Automatic Context Configuration">
+
+    <p>If you use the standard <strong>Context</strong> implementation,
+    the following configuration steps occur automtically when Catalina
+    is started, or whenever this web application is reloaded.  No special
+    configuration is required to enable this feature.</p>
+    
+    <ul>
+    <li>If you have not declared your own <a href="loader.html">Loader</a>
+       element, a standard web application class loader will be configured.
+       </li>
+    <li>If you have not declared your own <a href="manager.html">Manager</a>
+        element, a standard session manager will be configured.</li>
+    <li>If you have not declared your own <a href="resources.html">Resources</a>
+        element, a standard resources manager will be configured.</li>
+    <li>The web application properties listed in <code>conf/web.xml</code>
+        will be processed as defaults for this web application.  This is used
+        to establish default mappings (such as mapping the <code>*.jsp</code>
+        extension to the corresponding JSP servlet), and other standard
+        features that apply to all web applications.</li>
+    <li>The web application properties listed in the
+        <code>/WEB-INF/web.xml</code> resource for this web application
+        will be processed (if this resource exists).</li>
+    <li>If your web application has specified security constraints that might
+        require user authentication, an appropriate Authenticator that
+        implements the login method you have selected will be configured.</li>
+    </ul>
+
+  </subsection>
+
+
+  <subsection name="Context Parameters">
+
+    <p>You can configure named values that will be made visible to the
+    web application as servlet context initialization parameters by nesting
+    <code>&lt;Parameter&gt;</code> elements inside this element.  For
+    example, you can create an initialization parameter like this:</p>
+<source>
+&lt;Context ...&gt;
+  ...
+  &lt;Parameter name="companyName" value="My Company, Incorporated"
+         override="false"/&gt;
+  ...
+&lt;/Context&gt;
+</source>
+
+    <p>This is equivalent to the inclusion of the following element in the
+    web application deployment descriptor (<code>/WEB-INF/web.xml</code>):
+    </p>
+<source>
+&lt;context-param&gt;
+  &lt;param-name&gt;companyName&lt;/param-name&gt;
+  &lt;param-value&gt;My Company, Incorporated&lt;/param-value&gt;
+&lt;/context-param&gt;
+</source>
+    <p>but does <em>not</em> require modification of the deployment descriptor
+    to customize this value.</p>
+
+    <p>The valid attributes for a <code>&lt;Parameter&gt;</code> element
+    are as follows:</p>
+
+    <attributes>
+
+      <attribute name="description" required="false">
+        <p>Optional, human-readable description of this context
+        initialization parameter.</p>
+      </attribute>
+
+      <attribute name="name" required="true">
+        <p>The name of the context initialization parameter to be created.</p>
+      </attribute>
+
+      <attribute name="override" required="false">
+        <p>Set this to <code>false</code> if you do <strong>not</strong> want
+        a <code>&lt;context-param&gt;</code> for the same parameter name,
+        found in the web application deployment descriptor, to override the
+        value specified here.  By default, overrides are allowed.</p>
+      </attribute>
+
+      <attribute name="value" required="true">
+        <p>The parameter value that will be presented to the application
+        when requested by calling
+        <code>ServletContext.getInitParameter()</code>.</p>
+      </attribute>
+
+    </attributes>
+
+  </subsection>
+
+
+  <subsection name="Environment Entries">
+
+    <p>You can configure named values that will be made visible to the
+    web application as environment entry resources, by nesting
+    <code>&lt;Environment&gt;</code> entries inside this element.  For
+    example, you can create an environment entry like this:</p>
+<source>
+&lt;Context ...&gt;
+  ...
+  &lt;Environment name="maxExemptions" value="10"
+         type="java.lang.Integer" override="false"/&gt;
+  ...
+&lt;/Context&gt;
+</source>
+
+    <p>This is equivalent to the inclusion of the following element in the
+    web application deployment descriptor (<code>/WEB-INF/web.xml</code>):
+    </p>
+<source>
+&lt;env-entry&gt;
+  &lt;env-entry-name&gt;maxExemptions&lt;/param-name&gt;
+  &lt;env-entry-value&gt;10&lt;/env-entry-value&gt;
+  &lt;env-entry-type&gt;java.lang.Integer&lt;/env-entry-type&gt;
+&lt;/env-entry&gt;
+</source>
+    <p>but does <em>not</em> require modification of the deployment descriptor
+    to customize this value.</p>
+
+    <p>The valid attributes for an <code>&lt;Environment&gt;</code> element
+    are as follows:</p>
+
+    <attributes>
+
+      <attribute name="description" required="false">
+        <p>Optional, human-readable description of this environment entry.</p>
+      </attribute>
+
+      <attribute name="name" required="true">
+        <p>The name of the environment entry to be created, relative to the
+        <code>java:comp/env</code> context.</p>
+      </attribute>
+
+      <attribute name="override" required="false">
+        <p>Set this to <code>false</code> if you do <strong>not</strong> want
+        an <code>&lt;env-entry&gt;</code> for the same environment entry name,
+        found in the web application deployment descriptor, to override the
+        value specified here.  By default, overrides are allowed.</p>
+      </attribute>
+
+      <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
+        <code>&lt;env-entry-type&gt;</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>
+      </attribute>
+
+      <attribute name="value" required="true">
+        <p>The parameter value that will be presented to the application
+        when requested from the JNDI context.  This value must be convertable
+        to the Java type defined by the <code>type</code> attribute.</p>
+      </attribute>
+
+    </attributes>
+
+  </subsection>
+
+
+  <subsection name="Lifecycle Listeners">
+
+    <p>If you have implemented a Java object that needs to know when this
+    <strong>Context</strong> is started or stopped, you can declare it by
+    nesting a <strong>Listener</strong> element inside this element.  The
+    class name you specify must implement the
+    <code>org.apache.catalina.LifecycleListener</code> interface, and
+    it will be notified about the occurrence of the coresponding
+    lifecycle events.  Configuration of such a listener looks like this:</p>
+
+<source>
+&lt;Context path="/examples" ...&gt;
+  ...
+  &lt;Listener className="com.mycompany.mypackage.MyListener" ... &gt;
+  ...
+&lt;/Context&gt;
+</source>
+
+    <p>Note that a Listener can have any number of additional properties
+    that may be configured from this element.  Attribute names are matched
+    to corresponding JavaBean property names using the standard property
+    method naming patterns.</p>
+
+  </subsection>
+
+
+  <subsection name="Request Filters">
+
+    <p>You can ask Catalina to check the IP address, or host name, on every
+    incoming request directed to the surrounding
+    <a href="engine.html">Engine</a>, <a href="host.html">Host</a>, or
+    <a href="context.html">Context</a> element.  The remote address or name
+    will be checked against a configured list of "accept" and/or "deny"
+    filters, which are defined using the Regular Expression syntax supported
+    by the <a href="http://jakarta.apache.org/regexp/">Jakarta Regexp</a>
+    regular expression library.  Requests that come from locations that are
+    not accepted will be rejected with an HTTP "Forbidden" error.
+    Example filter declarations:</p>
+
+<source>
+&lt;Context path="/examples" ...&gt;
+  ...
+  &lt;Valve className="org.apache.catalina.valves.RemoteHostValve"
+         allow="*.mycompany.com,www.yourcompany.com"/&gt;
+  &lt;Valve className="org.apache.catalina.valves.RemoteAddrValve"
+         deny="192.168.1.*"/&gt;
+  ...
+&lt;/Context&gt;
+</source>
+
+    <p>See <a href="valve.html#Remote Address Filter">Remote Address Filter</a>
+    and <a href="valve.html#Remote Host Filter">Remote Host Filter</a> for
+    more information about the configuration options that are supported.</p>
+
+  </subsection>
+
+
+  <subsection name="Resource Definitions">
+
+    <p>You can declare the characteristics of the resource
+    to be returned for JNDI lookups of <code>&lt;resource-ref&gt;</code> and
+    <code>&lt;resource-env-ref&gt;</code> elements in the web application
+    deployment descriptor.  You <strong>MUST</strong> also define
+    the needed resource parameters as attributes of the <code>Resource</code> 
+    element, to configure the object factory to be used (if not known to Tomcat 
+    already), and the properties used to configure that object factory.</p>
+
+    <p>For example, you can create a resource definition like this:</p>
+<source>
+&lt;Context ...&gt;
+  ...
+  &lt;Resource name="jdbc/EmployeeDB" auth="Container"
+            type="javax.sql.DataSource"
+     description="Employees Database for HR Applications"/&gt;
+  ...
+&lt;/Context&gt;
+</source>
+
+    <p>This is equivalent to the inclusion of the following element in the
+    web application deployment descriptor (<code>/WEB-INF/web.xml</code>):</p>
+<source>
+&lt;resource-ref&gt;
+  &lt;description&gt;Employees Database for HR Applications&lt;/description&gt;
+  &lt;res-ref-name&gt;jdbc/EmployeeDB&lt;/res-ref-name&gt;
+  &lt;res-ref-type&gt;javax.sql.DataSource&lt;/res-ref-type&gt;
+  &lt;res-auth&gt;Container&lt;/res-auth&gt;
+&lt;/resource-ref&gt;
+</source>
+
+    <p>but does <em>not</em> require modification of the deployment
+    descriptor to customize this value.</p>
+
+    <p>The valid attributes for a <code>&lt;Resource&gt;</code> element
+    are as follows:</p>
+
+    <attributes>
+
+      <attribute name="auth" required="false">
+        <p>Specify whether the web Application code signs on to the
+        corresponding resource manager programatically, or whether the
+        Container will sign on to the resource manager on behalf of the
+        application.  The value of this attribute must be
+        <code>Application</code> or <code>Container</code>.  This
+        attribute is <strong>required</strong> if the web application
+        will use a <code>&lt;resource-ref&gt;</code> element in the web
+        application deployment descriptor, but is optional if the
+        application uses a <code>&lt;resource-env-ref&gt;</code> instead.</p>
+      </attribute>
+
+      <attribute name="description" required="false">
+        <p>Optional, human-readable description of this resource.</p>
+      </attribute>
+
+      <attribute name="name" required="true">
+        <p>The name of the resource to be created, relative to the
+        <code>java:comp/env</code> context.</p>
+      </attribute>
+
+      <attribute name="scope" required="false">
+        <p>Specify whether connections obtained through this resource
+        manager can be shared.  The value of this attribute must be
+        <code>Shareable</code> or <code>Unshareable</code>.  By default,
+        connections are assumed to be shareable.</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>
+      </attribute>
+
+    </attributes>
+
+
+  </subsection>
+
+
+  <subsection name="Resource Links">
+
+     <p>This element is used to create a link to a global JNDI resource. Doing
+     a JNDI lookup on the link name will then return the linked global 
+     resource.</p>
+
+    <p>For example, you can create a resource link like this:</p>
+<source>
+&lt;Context ...&gt;
+  ...
+  &lt;ResourceLink name="linkToGlobalResource"
+            global="simpleValue"
+            type="java.lang.Integer"
+  ...
+&lt;/Context&gt;
+</source>
+
+    <p>The valid attributes for a <code>&lt;ResourceLink&gt;</code> element
+    are as follows:</p>
+
+    <attributes>
+
+      <attribute name="global" required="true">
+        <p>The name of the linked global resource in the 
+        global JNDI context.</p>
+      </attribute>
+
+      <attribute name="name" required="true">
+        <p>The name of the resource link to be created, relative to the
+        <code>java:comp/env</code> context.</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 link.</p>
+      </attribute>
+
+    </attributes>
+
+  </subsection>
+
+  <subsection name="Transaction">
+
+    <p>You can declare the characteristics of the UserTransaction
+    to be returned for JNDI lookup for <code>java:comp/UserTransaction</code>. 
+    You <strong>MUST</strong> define an object factory class to instantiate
+    this object as well as the needed resource parameters as attributes of the 
+    <code>Transaction</code> 
+    element, and the properties used to configure that object factory.</p>
+
+    <p>The valid attributes for the <code>&lt;Transaction&gt;</code> element
+    are as follows:</p>
+
+    <attributes>
+
+      <attribute name="factory" required="true">
+        <p>The class name for the JNDI object factory.</p>
+      </attribute>
+
+    </attributes>
+
+  </subsection>
+
+</section>
+
+
+</body>
+
+
+</document>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/config/engine.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/config/engine.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/config/engine.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,240 @@
+<?xml version="1.0"?>
+<!DOCTYPE document [
+  <!ENTITY project SYSTEM "project.xml">
+]>
+<document url="engine.html">
+
+  &project;
+
+  <properties>
+    <author email="craigmcc at apache.org">Craig R. McClanahan</author>
+    <title>The Engine Container</title>
+  </properties>
+
+<body>
+
+
+<section name="Introduction">
+
+  <p>The <strong>Engine</strong> element represents the entire request
+  processing machinery associated with a particular Catalina
+  <a href="service.html">Service</a>.  It receives and processes
+  <em>all</em> requests from one or more <strong>Connectors</strong>,
+  and returns the completed response to the Connector for ultimate
+  transmission back to the client.</p>
+
+  <p>Exactly one <strong>Engine</strong> element MUST be nested inside
+  a <a href="service.html">Service</a> element, following all of the
+  corresponding Connector elements associated with this Service.</p>
+
+</section>
+
+
+<section name="Attributes">
+
+  <subsection name="Common Attributes">
+
+    <p>All implementations of <strong>Engine</strong>
+    support the following attributes:</p>
+
+    <attributes>
+
+      <attribute name="backgroundProcessorDelay" required="false">
+        <p>This value represents the delay in seconds between the 
+        invocation of the backgroundProcess method on this engine and 
+        its child containers, including all hosts and contexts. 
+        Child containers will not be invoked if their delay value is not 
+        negative (which would mean they are using their own processing 
+        thread). Setting this to a positive value will cause 
+        a thread to be spawn. After waiting the specified amount of time, 
+        the thread will invoke the backgroundProcess method on this engine 
+        and all its child containers. If not specified, the default value for
+        this attribute is 10, which represent a 10 seconds delay.</p>
+      </attribute>
+
+      <attribute name="className" required="false">
+        <p>Java class name of the implementation to use.  This class must
+        implement the <code>org.apache.catalina.Engine</code> interface.
+        If not specified, the standard value (defined below) will be used.</p>
+      </attribute>
+
+      <attribute name="defaultHost" required="true">
+        <p>The default host name, which identifies the
+        <a href="host.html">Host</a> that will process requests directed
+        to host names on this server, but which are not configured in
+        this configuration file.  This name MUST match the <code>name</code>
+        attributes of one of the <a href="host.html">Host</a> elements
+        nested immediately inside.</p>
+      </attribute>
+
+      <attribute name="jvmRoute" required="false">
+        <p>Identifier which must be used in load balancing scenarios to enable
+        session affinity. The identifier, which must be unique across all
+        Tomcat 5 servers which participate in the cluster, will be appended to
+        the generated session identifier, therefore allowing the front end
+        proxy to always forward a particular session to the same Tomcat 5
+        instance.</p>
+      </attribute>
+
+      <attribute name="name" required="true">
+        <p>Logical name of this Engine, used in log and error messages.</p>
+      </attribute>
+
+    </attributes>
+
+  </subsection>
+
+
+  <subsection name="Standard Implementation">
+
+    <p>The standard implementation of <strong>Engine</strong> is
+    <strong>org.apache.catalina.core.StandardEngine</strong>.
+    It supports the following additional attributes (in addition to the
+    common attributes listed above):</p>
+
+    <attributes>
+
+    </attributes>
+
+  </subsection>
+
+
+</section>
+
+
+<section name="Nested Components">
+
+  <p>You can nest one or more <a href="host.html">Host</a> elements inside
+  this <strong>Engine</strong> element, each representing a different virtual
+  host associated with this server.  At least one <a href="host.html">Host</a>
+  is required, and one of the nested <a href="host.html">Hosts</a> MUST
+  have a name that matches the name specified for the
+  <code>defaultHost</code> attribute, listed above.</p>
+
+  <p>You can optional nest a <a href="defaultcontext.html">DefaultContext</a>
+  element inside this <strong>Engine</strong> element, to define the default
+  characteristics of web applications that are automatically deployed.</p>
+
+  <p>You can nest at most one instance of the following utility components
+  by nesting a corresponding element inside your <strong>Engine</strong>
+  element:</p>
+  <ul>
+  <li><a href="realm.html"><strong>Realm</strong></a> -
+      Configure a realm that will allow its
+      database of users, and their associated roles, to be shared across all
+      <a href="host.html">Hosts</a> and <a href="context.html">Contexts</a>
+      nested inside this Engine, unless overridden by a
+      <a href="realm.html">Realm</a> configuration at a lower level.</li>
+  </ul>
+
+</section>
+
+
+<section name="Special Features">
+
+
+  <subsection name="Logging">
+
+    <p>An engine is associated with the 
+       <code>org.apache.catalina.core.ContainerBase.[enginename]</code>
+       log category.  Note that the brackets are actually part of the name,
+       don't omit them.</p>
+
+  </subsection>
+
+
+  <subsection name="Access Logs">
+
+    <p>When you run a web server, one of the output files normally generated
+    is an <em>access log</em>, which generates one line of information for
+    each request processed by the server, in a standard format.  Catalina
+    includes an optional <a href="valve.html">Valve</a> implementation that
+    can create access logs in the same standard format created by web servers,
+    or in any number of custom formats.</p>
+
+    <p>You can ask Catalina to create an access log for all requests
+    processed by an <a href="engine.html">Engine</a>,
+    <a href="host.html">Host</a>, or <a href="context.html">Context</a>
+    by nesting a <a href="valve.html">Valve</a> element like this:</p>
+
+<source>
+&lt;Engine name="Standalone" ...&gt;
+  ...
+  &lt;Valve className="org.apache.catalina.valves.AccessLogValve"
+         prefix="catalina_access_log." suffix=".txt"
+         pattern="common"/&gt;
+  ...
+&lt;/Engine&gt;
+</source>
+
+    <p>See <a href="valve.html#Access Log Valve">Access Log Valve</a>
+    for more information on the configuration attributes that are
+    supported.</p>
+
+  </subsection>
+
+
+  <subsection name="Lifecycle Listeners">
+
+    <p>If you have implemented a Java object that needs to know when this
+    <strong>Engine</strong> is started or stopped, you can declare it by
+    nesting a <strong>Listener</strong> element inside this element.  The
+    class name you specify must implement the
+    <code>org.apache.catalina.LifecycleListener</code> interface, and
+    it will be notified about the occurrence of the coresponding
+    lifecycle events.  Configuration of such a listener looks like this:</p>
+
+<source>
+&lt;Engine name="Standalone" ...&gt;
+  ...
+  &lt;Listener className="com.mycompany.mypackage.MyListener" ... &gt;
+  ...
+&lt;/Engine&gt;
+</source>
+
+    <p>Note that a Listener can have any number of additional properties
+    that may be configured from this element.  Attribute names are matched
+    to corresponding JavaBean property names using the standard property
+    method naming patterns.</p>
+
+  </subsection>
+
+
+  <subsection name="Request Filters">
+
+    <p>You can ask Catalina to check the IP address, or host name, on every
+    incoming request directed to the surrounding
+    <a href="engine.html">Engine</a>, <a href="host.html">Host</a>, or
+    <a href="context.html">Context</a> element.  The remote address or name
+    will be checked against a configured list of "accept" and/or "deny"
+    filters, which are defined using the Regular Expression syntax supported
+    by the <a href="http://jakarta.apache.org/regexp/">Jakarta Regexp</a>
+    regular expression library.  Requests that come from locations that are
+    not accepted will be rejected with an HTTP "Forbidden" error.
+    Example filter declarations:</p>
+
+<source>
+&lt;Engine name="Standalone" ...&gt;
+  ...
+  &lt;Valve className="org.apache.catalina.valves.RemoteHostValve"
+         allow="*.mycompany.com,www.yourcompany.com"/&gt;
+  &lt;Valve className="org.apache.catalina.valves.RemoteAddrValve"
+         deny="192.168.1.*"/&gt;
+  ...
+&lt;/Engine&gt;
+</source>
+
+  <p>See <a href="valve.html#Remote Address Filter">Remote Address Filter</a>
+  and <a href="valve.html#Remote Host Filter">Remote Host Filter</a> for
+  more information about the configuration options that are supported.</p>
+
+  </subsection>
+
+
+</section>
+
+
+</body>
+
+
+</document>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/config/globalresources.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/config/globalresources.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/config/globalresources.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,254 @@
+<?xml version="1.0"?>
+<!DOCTYPE document [
+  <!ENTITY project SYSTEM "project.xml">
+]>
+<document url="globalresources.html">
+
+  &project;
+
+  <properties>
+    <author email="remm at apache.org">Remy Maucherat</author>
+    <author email="yoavs at apache.org">Yoav Shapira</author>
+    <title>The GlobalNamingResources Component</title>
+  </properties>
+
+<body>
+
+
+<section name="Introduction">
+
+  <p>The <strong>GlobalNamingResources</strong> element defines the global
+  JNDI resources for the <a href="server.html">Server</a>.</p>
+
+  <p>These resources are listed in the server's global JNDI resource context.
+   This context is distinct from the per-web-application JNDI contexts 
+  described in
+  the <a href="../jndi-resources-howto.html">JNDI Resources HOW-TO</a>.
+  The resources defined in this element are <strong>not</strong> visible in
+  the per-web-application contexts unless you explicitly link them with
+  <a href="context.html#Resource Links">&lt;ResourceLink&gt;</a> elements.
+  </p>
+
+</section>
+
+
+<section name="Attributes">
+
+</section>
+
+
+<section name="Nested Components">
+
+</section>
+
+
+<section name="Special Features">
+
+
+  <subsection name="Environment Entries">
+
+  <p>You can configure named values that will be made visible to all
+    web applications as environment entry resources by nesting
+    <code>&lt;Environment&gt;</code> entries inside this element. For
+    example, you can create an environment entry like this:</p>
+<source>
+&lt;GlobalNamingResources ...&gt;
+  ...
+  &lt;Environment name="maxExemptions" value="10"
+         type="java.lang.Integer" override="false"/&gt;
+  ...
+&lt;/GlobalNamingResources&gt;
+</source>
+
+    <p>This is equivalent to the inclusion of the following element in the
+    web application deployment descriptor (<code>/WEB-INF/web.xml</code>):
+    </p>
+<source>
+&lt;env-entry&gt;
+  &lt;env-entry-name&gt;maxExemptions&lt;/env-entry-name&gt;
+  &lt;env-entry-value&gt;10&lt;/env-entry-value&gt;
+  &lt;env-entry-type&gt;java.lang.Integer&lt;/env-entry-type&gt;
+&lt;/env-entry&gt;
+</source>
+    <p>but does <em>not</em> require modification of the deployment descriptor
+    to customize this value.</p>
+
+    <p>The valid attributes for an <code>&lt;Environment&gt;</code> element
+    are as follows:</p>
+
+    <attributes>
+
+      <attribute name="description" required="false">
+        <p>Optional, human-readable description of this environment entry.</p>
+      </attribute>
+
+      <attribute name="name" required="true">
+        <p>The name of the environment entry to be created, relative to the
+        <code>java:comp/env</code> context.</p>
+      </attribute>
+
+      <attribute name="override" required="false">
+        <p>Set this to <code>false</code> if you do <strong>not</strong> want
+        an <code>&lt;env-entry&gt;</code> for the same environment entry name,
+        found in the web application deployment descriptor, to override the
+        value specified here.  By default, overrides are allowed.</p>
+      </attribute>
+
+      <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
+        <code>&lt;env-entry-type&gt;</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>
+      </attribute>
+
+      <attribute name="value" required="true">
+        <p>The parameter value that will be presented to the application
+        when requested from the JNDI context.  This value must be convertable
+        to the Java type defined by the <code>type</code> attribute.</p>
+      </attribute>
+
+    </attributes>
+
+  </subsection>
+
+
+  <subsection name="Resource Definitions">
+
+    <p>You can declare the characteristics of resources
+    to be returned for JNDI lookups of <code>&lt;resource-ref&gt;</code> and
+    <code>&lt;resource-env-ref&gt;</code> elements in the web application
+    deployment descriptor by defining them in this element and then linking 
+    them with <a href="context.html#Resource Links">&lt;ResourceLink&gt;</a> 
+    elements
+    in the <code><strong>&lt;Context&gt;</strong></code> element.  
+
+    You <strong>MUST</strong> also define any other needed parameters using
+    attributes on the Resource element, to configure
+    the object factory to be used (if not known to Tomcat already), and
+    the properties used to configure that object factory.</p>
+
+    <p>For example, you can create a resource definition like this:</p>
+<source>
+&lt;GlobalNamingResources ...&gt;
+  ...
+  &lt;Resource name="jdbc/EmployeeDB" auth="Container"
+            type="javax.sql.DataSource"
+     description="Employees Database for HR Applications"/&gt;
+  ...
+&lt;/GlobalNamingResources&gt;
+</source>
+
+    <p>This is equivalent to the inclusion of the following element in the
+    web application deployment descriptor (<code>/WEB-INF/web.xml</code>):</p>
+<source>
+&lt;resource-ref&gt;
+  &lt;description&gt;Employees Database for HR Applications&lt;/description&gt;
+  &lt;res-ref-name&gt;jdbc/EmployeeDB&lt;/res-ref-name&gt;
+  &lt;res-ref-type&gt;javax.sql.DataSource&lt;/res-ref-type&gt;
+  &lt;res-auth&gt;Container&lt;/res-auth&gt;
+&lt;/resource-ref&gt;
+</source>
+
+    <p>but does <em>not</em> require modification of the deployment
+    descriptor to customize this value.</p>
+
+    <p>The valid attriutes for a <code>&lt;Resource&gt;</code> element
+    are as follows:</p>
+
+    <attributes>
+
+      <attribute name="auth" required="false">
+        <p>Specify whether the web Application code signs on to the
+        corresponding resource manager programatically, or whether the
+        Container will sign on to the resource manager on behalf of the
+        application.  The value of this attribute must be
+        <code>Application</code> or <code>Container</code>.  This
+        attribute is <strong>required</strong> if the web application
+        will use a <code>&lt;resource-ref&gt;</code> element in the web
+        application deployment descriptor, but is optional if the
+        application uses a <code>&lt;resource-env-ref&gt;</code> instead.</p>
+      </attribute>
+
+      <attribute name="description" required="false">
+        <p>Optional, human-readable description of this resource.</p>
+      </attribute>
+
+      <attribute name="name" required="true">
+        <p>The name of the resource to be created, relative to the
+        <code>java:comp/env</code> context.</p>
+      </attribute>
+
+      <attribute name="scope" required="false">
+        <p>Specify whether connections obtained through this resource
+        manager can be shared.  The value of this attribute must be
+        <code>Shareable</code> or <code>Unshareable</code>.  By default,
+        connections are assumed to be shareable.</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>
+      </attribute>
+
+    </attributes>
+
+
+  </subsection>
+
+  <subsection name="Resource Links">
+    <p>Use <a href="context.html#Resource Links">&lt;ResourceLink&gt;</a> 
+    elements to link resources from the global context into 
+    per-web-application contexts. Here is an example of making a custom 
+    factory available to all applications in the server, based on the example 
+    definition in the 
+    <a href="../jndi-resource-howto.html#Generic JavaBean Resources">
+    JNDI Resource HOW-TO</a>:
+    </p>
+
+    <source>
+      <![CDATA[
+        <DefaultContext>
+          <ResourceLink 
+            name="bean/MyBeanFactory"
+            global="bean/MyBeanFactory"
+            type="com.mycompany.MyBean"
+          />
+        </DefaultContext>
+      ]]>
+    </source>
+
+   </subsection>
+
+  <subsection name="Transaction">
+
+    <p>You can declare the characteristics of the UserTransaction
+    to be returned for JNDI lookup for <code>java:comp/UserTransaction</code>. 
+    You <strong>MUST</strong> define an object factory class to instantiate
+    this object as well as the needed resource parameters as attributes of the 
+    <code>Transaction</code> 
+    element, and the properties used to configure that object factory.</p>
+
+    <p>The valid attributes for the <code>&lt;Transaction&gt;</code> element
+    are as follows:</p>
+
+    <attributes>
+
+      <attribute name="factory" required="true">
+        <p>The class name for the JNDI object factory.</p>
+      </attribute>
+
+    </attributes>
+
+  </subsection>
+
+</section>
+
+
+</body>
+
+
+</document>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/config/host.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/config/host.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/config/host.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,542 @@
+<?xml version="1.0"?>
+<!DOCTYPE document [
+  <!ENTITY project SYSTEM "project.xml">
+]>
+<document url="host.html">
+
+  &project;
+
+  <properties>
+    <author email="craigmcc at apache.org">Craig R. McClanahan</author>
+    <author email="remm at apache.org">Remy Maucherat</author>
+    <author email="yoavs at apache.org">Yoav Shapira</author>
+    <title>The Host Container</title>
+  </properties>
+
+<body>
+
+
+<section name="Introduction">
+
+  <p>The <strong>Host</strong> element represents a <em>virtual host</em>,
+  which is an association of a network name for a server (such as
+  "www.mycompany.com" with the particular server on which Catalina is
+  running.  In order to be effective, this name must be registered in the
+  <em>Domain Name Service</em> (DNS) server that manages the Internet
+  domain you belong to - contact your Network Administrator for more
+  information.</p>
+
+  <p>In many cases, System Administrators wish to associate more than
+  one network name (such as <code>www.mycompany.com</code> and
+  <code>company.com</code>) with the same virtual host and applications.
+  This can be accomplished using the <a href="#Host Name Aliases">Host
+  Name Aliases</a> feature discussed below.</p>
+
+  <p>One or more <strong>Host</strong> elements are nested inside an
+  <a href="engine.html">Engine</a> element.  Inside the Host element, you
+  can nest <a href="context.html">Context</a> elements for the web
+  applications associated with this virtual host.  Exactly one of the Hosts
+  associated with each Engine MUST have a name matching the
+  <code>defaultHost</code> attribute of that Engine.</p>
+
+    <blockquote><em>
+    <p>The description below uses the variable name $CATALINA_HOME
+    to refer to the directory into which you have installed Tomcat 5,
+    and is the base directory against which most relative paths are
+    resolved.  However, if you have configured Tomcat 5 for multiple
+    instances by setting a CATALINA_BASE directory, you should use
+    $CATALINA_BASE instead of $CATALINA_HOME for each of these
+    references.</p>
+    </em></blockquote>
+
+</section>
+
+
+<section name="Attributes">
+
+  <subsection name="Common Attributes">
+
+    <p>All implementations of <strong>Host</strong>
+    support the following attributes:</p>
+
+    <attributes>
+
+      <attribute name="appBase" required="true">
+        <p>The <em>Application Base</em> directory for this virtual host.
+        This is the pathname of a directory that may contain web applications
+        to be deployed on this virtual host.  You may specify an
+        absolute pathname for this directory, or a pathname that is relative
+        to the <code>$CATALINA_BASE</code> directory.  See
+        <a href="#Automatic Application Deployment">Automatic Application
+        Deployment</a> for more information on automatic recognition and
+        deployment of web applications to be deployed automatically.</p>
+      </attribute>
+
+      <attribute name="autoDeploy" required="false">
+        <p>This flag value indicates if new web applications, dropped in to
+        the <code>appBase</code> directory while Tomcat is running, should
+        be automatically deployed.  The flag's value defaults to true.  See
+        <a href="#Automatic Application Deployment">Automatic Application
+        Deployment</a> for more information.</p>
+      </attribute>
+
+      <attribute name="backgroundProcessorDelay" required="false">
+        <p>This value represents the delay in seconds between the 
+        invocation of the backgroundProcess method on this host and 
+        its child containers, including all contexts. 
+        Child containers will not be invoked if their delay value is not 
+        negative (which would mean they are using their own processing 
+        thread). Setting this to a positive value will cause 
+        a thread to be spawn. After waiting the specified amount of time, 
+        the thread will invoke the backgroundProcess method on this host 
+        and all its child containers. A host will use background processing to
+        perform live web application deployment related tasks. If not 
+        specified, the default value for this attribute is -1, which means 
+        the host will rely on the background processing thread of its parent 
+        engine.</p>
+      </attribute>
+
+      <attribute name="className" required="false">
+        <p>Java class name of the implementation to use.  This class must
+        implement the <code>org.apache.catalina.Host</code> interface.
+        If not specified, the standard value (defined below) will be used.</p>
+      </attribute>
+
+      <attribute name="deployOnStartup" required="false">
+        <p>This flag value indicates if web applications from this host should
+        be automatically deployed by the host configurator.
+        The flag's value defaults to true.  See
+        <a href="#Automatic Application Deployment">Automatic Application
+        Deployment</a> for more information.</p>
+      </attribute>
+
+      <attribute name="name" required="true">
+        <p>Network name of this virtual host, as registered in your
+        <em>Domain Name Service</em> server.  One of the Hosts nested within
+        an <a href="engine.html">Engine</a> MUST have a name that matches the
+        <code>defaultHost</code> setting for that Engine.  See
+        <a href="#Host Name Aliases">Host Name Aliases</a> for information
+        on how to assign more than one network name to the same
+        virtual host.</p>
+      </attribute>
+
+    </attributes>
+
+  </subsection>
+
+
+  <subsection name="Standard Implementation">
+
+    <p>The standard implementation of <strong>Host</strong> is
+    <strong>org.apache.catalina.core.StandardHost</strong>.
+    It supports the following additional attributes (in addition to the
+    common attributes listed above):</p>
+
+    <attributes>
+
+      <attribute name="deployXML" required="false">
+        <p>Set to <code>false</code> if you want to disable parsing the context.xml
+        file embedded inside the application (located at <code>/META-INF/context.xml</code>). 
+        Security consious environments should set this to <code>false</code> to prevent
+        applications from interacting with the container's configuration. The 
+        administrator will then be responsible for providing an external context 
+        configuration file, and put it in 
+        <code>$CATALINA_HOME/conf/[enginename]/[hostname]/</code>.
+        The flag's value defaults to <code>true</code>.</p>
+      </attribute>
+
+      <attribute name="errorReportValveClass" required="false">
+        <p>Java class name of the error reporting valve which will be used
+        by this Host. The responsability of this valve is to output error
+        reports. Setting this property allows to customize the look of the
+        error pages which will be generated by Tomcat. This class must
+        implement the
+        <code>org.apache.catalina.Valve</code> interface. If none is specified,
+        the value <code>org.apache.catalina.valves.ErrorReportValve</code>
+        will be used by default.</p>
+      </attribute>
+
+      <attribute name="unpackWARs" required="false">
+        <p>Set to <code>true</code> if you want web applications that are
+        placed in the <code>appBase</code> directory as web application
+        archive (WAR) files to be unpacked into a corresponding disk directory
+        structure, <code>false</code> to run such web applications directly
+        from a WAR file.  See
+        <a href="#Automatic Application Deployment">Automatic Application
+        Deployment</a> for more information.</p>
+      </attribute>
+
+      <attribute name="workDir" required="false">
+        <p>Pathname to a scratch directory to be used by applications for
+        this Host. Each application will have its own sub directory with
+        temporary read-write use.  Configuring a Context workDir will override
+        use of the Host workDir configuration.  This directory will be made
+        visible to servlets in the web application by a servlet context
+        attribute (of type <code>java.io.File</code>) named
+        <code>javax.servlet.context.tempdir</code> as described in the
+        Servlet Specification.  If not specified, a suitable directory
+        underneath <code>$CATALINA_HOME/work</code> will be provided.</p>
+      </attribute>
+
+    </attributes>
+
+  </subsection>
+
+
+</section>
+
+
+<section name="Nested Components">
+
+  <p>You can nest one or more <a href="context.html">Context</a> elements
+  inside this <strong>Host</strong> element, each representing a different web
+  application associated with this virtual host.  In addition, you can nest a
+  single <a href="defaultcontext.html">DefaultContext</a> element that defines
+  default values for subsequently deployed web applications.</p>
+
+  <p>You can optional nest a <a href="defaultcontext.html">DefaultContext</a>
+  element inside this <strong>Host</strong> element, to define the default
+  characteristics of web applications that are automatically deployed.</p>
+
+  <p>You can nest at most one instance of the following utility components
+  by nesting a corresponding element inside your <strong>Host</strong>
+  element:</p>
+  <ul>
+  <li><a href="realm.html"><strong>Realm</strong></a> -
+      Configure a realm that will allow its
+      database of users, and their associated roles, to be shared across all
+      <a href="context.html">Contexts</a> nested inside this Host (unless
+      overridden by a <a href="realm.html">Realm</a> configuration
+      at a lower level).</li>
+  </ul>
+
+</section>
+
+
+<section name="Special Features">
+
+
+  <subsection name="Logging">
+
+    <p>A host is associated with the 
+       <code>org.apache.catalina.core.ContainerBase.[enginename].[hostname]</code>
+       log category.  Note that the brackets are actuall part of the name,
+       don't omit them.</p>
+
+  </subsection>
+
+
+  <subsection name="Access Logs">
+
+    <p>When you run a web server, one of the output files normally generated
+    is an <em>access log</em>, which generates one line of information for
+    each request processed by the server, in a standard format.  Catalina
+    includes an optional <a href="valve.html">Valve</a> implementation that
+    can create access logs in the same standard format created by web servers,
+    or in any number of custom formats.</p>
+
+    <p>You can ask Catalina to create an access log for all requests
+    processed by an <a href="engine.html">Engine</a>,
+    <a href="host.html">Host</a>, or <a href="context.html">Context</a>
+    by nesting a <a href="valve.html">Valve</a> element like this:</p>
+
+<source>
+&lt;Host name="localhost" ...&gt;
+  ...
+  &lt;Valve className="org.apache.catalina.valves.AccessLogValve"
+         prefix="localhost_access_log." suffix=".txt"
+         pattern="common"/&gt;
+  ...
+&lt;/Host&gt;
+</source>
+
+    <p>See <a href="valve.html#Access Log Valve">Access Log Valve</a>
+    for more information on the configuration attributes that are
+    supported.</p>
+
+  </subsection>
+
+
+  <subsection name="Automatic Application Deployment">
+
+    <p>If you are using the standard <strong>Host</strong> implementation,
+    the following actions take place automatically when Catalina is first
+    started, if the <code>deployOnStartup</code> property is set to
+    <code>true</code> (which is the default value):</p>
+    <ul>
+    <li>Any XML file in the 
+        <code>$CATALINA_HOME/conf/[engine_name]/[host_name]</code> directory is
+        assumed to contain a
+        <a href="context.html">Context</a> element (and its associated
+        subelements) for a single web application.  The <code>docBase</code>
+        attribute of this <code>&lt;Context&gt;</code> element will typically
+        be the absolute pathname to a web application directory, or the
+        absolute pathname of a web application archive (WAR) file (which
+        will not be expanded).</li>
+    <li>Any web application archive file within the application base (appBase)
+        directory that does not have a corresponding
+        directory of the same name (without the ".war" extension) will be
+        automatically expanded, unless the <code>unpackWARs</code> property
+        is set to <code>false</code>.  If you redeploy an updated WAR file,
+        be sure to delete the expanded directory when restarting Tomcat, so
+        that the updated WAR file will be re-expanded (note that the auto
+        deployer, if enabled, will automatically expand the updated WAR file
+        once the previously expanded directory is removed).</li>
+    <li>Any subdirectory within the <em>application base directory</em>
+        that appears to be an unpacked web application (that is, it contains
+        a <code>/WEB-INF/web.xml</code> file) will receive an automatically
+        generated <a href="context.html">Context</a> element, even if this
+        directory is not mentioned in the <code>conf/server.xml</code> file.
+        This generated Context entry will be configured according to the
+        properties set in any <a href="defaultcontext.html">DefaultContext</a>
+        element nested in this Host element.  The context path for this
+        deployed Context will be a slash character ("/") followed by the
+        directory name, unless the directory name is ROOT, in which case
+        the context path will be an empty string ("").</li>
+    </ul>
+
+    <p>In addition to the automatic deployment that occurs at startup time,
+    you can also request that new XML configuration files, WAR files, or
+    subdirectories (containing web applications) that are dropped in to the
+    <code>appBase</code> (or 
+    <code>$CATALINA_HOME/conf/[engine_name]/[host_name]</code> in the case of
+    an XML configuration file) directory while Tomcat is running will be
+    automatically deployed, according to the rules described above. The 
+    auto deployer will also track web applications for the following changes:
+    <ul>
+        <li>An update to the WEB-INF/web.xml file will trigger a reload of the
+        web application</li>
+        <li>An update to a WAR which has been expanded will trigger 
+        an undeploy (<strong>with a removal of the expanded webapp</strong>), 
+        followed by a deployment</li>
+        <li>An update to a XML configuration file will trigger an undeploy
+        (without the removal of any expanded directory), followed by 
+        a deployment of the associated web application</li>
+    </ul>
+    </p>
+
+    <p>When using automatic deployment, the <code>docBase</code> defined by
+    an XML <a href="context.html">Context</a> file should be outside of the
+    <code>appBase</code> directory. If this is not the case difficulties
+    may be experienced deploying the web application or the application may
+    be deployed twice.</p>
+
+    <p>Finally, note that if you are defining contexts explicitly, you should
+    probably turn off automatic application deployment.  Otherwise, your context
+    will be deployed twice each, and that may cause problems for your app.
+    </p>
+
+  </subsection>
+
+
+  <subsection name="Host Name Aliases">
+
+    <p>In many server environments, Network Administrators have configured
+    more than one network name (in the <em>Domain Name Service</em> (DNS)
+    server), that resolve to the IP address of the same server.  Normally,
+    each such network name would be configured as a separate
+    <strong>Host</strong> element in <code>conf/server.xml</code>, each
+    with its own set of web applications.</p>
+
+    <p>However, in some circumstances, it is desireable that two or more
+    network names should resolve to the <strong>same</strong> virtual host,
+    running the same set of applications.  A common use case for this
+    scenario is a corporate web site, where it is desireable that users
+    be able to utilize either <code>www.mycompany.com</code> or
+    <code>company.com</code> to access exactly the same content and
+    applications.</p>
+
+    <p>This is accomplished by utilizing one or more <strong>Alias</strong>
+    elements nested inside your <strong>Host</strong> element.  For
+    example:</p>
+<source>
+&lt;Host name="www.mycompany.com" ...&gt;
+  ...
+  &lt;Alias&gt;mycompany.com&lt;/Alias&gt;
+  ...
+&lt;/Host&gt;
+</source>
+
+    <p>In order for this strategy to be effective, all of the network names
+    involved must be registered in your DNS server to resolve to the
+    same computer that is running this instance of Catalina.</p>
+
+  </subsection>
+
+
+  <subsection name="Lifecycle Listeners">
+
+    <p>If you have implemented a Java object that needs to know when this
+    <strong>Host</strong> is started or stopped, you can declare it by
+    nesting a <strong>Listener</strong> element inside this element.  The
+    class name you specify must implement the
+    <code>org.apache.catalina.LifecycleListener</code> interface, and
+    it will be notified about the occurrence of the coresponding
+    lifecycle events.  Configuration of such a listener looks like this:</p>
+
+<source>
+&lt;Host name="localhost" ...&gt;
+  ...
+  &lt;Listener className="com.mycompany.mypackage.MyListener" ... &gt;
+  ...
+&lt;/Host&gt;
+</source>
+
+    <p>Note that a Listener can have any number of additional properties
+    that may be configured from this element.  Attribute names are matched
+    to corresponding JavaBean property names using the standard property
+    method naming patterns.</p>
+
+  </subsection>
+
+
+  <subsection name="Request Filters">
+
+    <p>You can ask Catalina to check the IP address, or host name, on every
+    incoming request directed to the surrounding
+    <a href="engine.html">Engine</a>, <a href="host.html">Host</a>, or
+    <a href="context.html">Context</a> element.  The remote address or name
+    will be checked against a configured list of "accept" and/or "deny"
+    filters, which are defined using the Regular Expression syntax supported
+    by the <a href="http://jakarta.apache.org/regexp/">Jakarta Regexp</a>
+    regular expression library.  Requests that come from locations that are
+    not accepted will be rejected with an HTTP "Forbidden" error.
+    Example filter declarations:</p>
+
+<source>
+&lt;Host name="localhost" ...&gt;
+  ...
+  &lt;Valve className="org.apache.catalina.valves.RemoteHostValve"
+         allow="*.mycompany.com,www.yourcompany.com"/&gt;
+  &lt;Valve className="org.apache.catalina.valves.RemoteAddrValve"
+         deny="192.168.1.*"/&gt;
+  ...
+&lt;/Host&gt;
+</source>
+
+  <p>See <a href="valve.html#Remote Address Filter">Remote Address Filter</a>
+  and <a href="valve.html#Remote Host Filter">Remote Host Filter</a> for
+  more information about the configuration options that are supported.</p>
+
+  </subsection>
+
+
+  <subsection name="Single Sign On">
+
+    <p>In many environments, but particularly in portal environments, it
+    is desireable to have a user challenged to authenticate themselves only
+    once over a set of web applications deployed on a particular virtual
+    host.  This can be accomplished by nesting an element like this inside
+    the Host element for this virtual host:</p>
+
+<source>
+&lt;Host name="localhost" ...&gt;
+  ...
+  &lt;Valve className="org.apache.catalina.authenticator.SingleSignOn"
+         debug="0"/&gt;
+  ...
+&lt;/Host&gt;
+</source>
+
+    <p>The Single Sign On facility operates according to the following rules:
+    </p>
+    <ul>
+    <li>All web applications configured for this virtual host must share the
+        same <a href="realm.html">Realm</a>.  In practice, that means you can
+        nest the Realm element inside this Host element (or the surrounding
+        <a href="engine.html">Engine</a> element), but not inside a
+        <a href="context.html">Context</a> element for one of the involved
+        web applications.</li>
+    <li>As long as the user accesses only unprotected resources in any of the
+        web applications on this virtual host, they will not be challenged
+        to authenticate themselves.</li>
+    <li>As soon as the user accesses a protected resource in
+        <strong>any</strong> web application associated with this virtual
+        host, the user will be challenged to authenticate himself or herself,
+        using the login method defined for the web application currently
+        being accessed.</li>
+    <li>Once authenticated, the roles associated with this user will be
+        utilized for access control decisions across <strong>all</strong>
+        of the associated web applications, without challenging the user
+        to authenticate themselves to each application individually.</li>
+    <li>As soon as the user logs out of one web application (for example,
+        by invalidating the corresponding session if form
+        based login is used), the user's sessions in <strong>all</strong>
+        web applications will be invalidated.  Any subsequent attempt to
+        access a protected resource in any application will require the
+        user to authenticate himself or herself again.</li>
+    <li>The Single Sign On feature utilizes HTTP cookies to transmit a token
+        that associates each request with the saved user identity, so it can
+        only be utilized in client environments that support cookies.</li>
+    </ul>
+
+  </subsection>
+
+
+  <subsection name="User Web Applications">
+
+    <p>Many web servers can automatically map a request URI starting with
+    a tilde character ("~") and a username to a directory (commonly named
+    <code>public_html</code>) in that user's home directory on the server.
+    You can accomplish the same thing in Catalina by using a special
+    <strong>Listener</strong> element like this (on a Unix system that
+    uses the <code>/etc/passwd</code> file to identify valid users):</p>
+
+<source>
+&lt;Host name="localhost" ...&gt;
+  ...
+  &lt;Listener className="org.apache.catalina.startup.UserConfig"
+            directoryName="public_html"
+            userClass="org.apache.catalina.startup.PasswdUserDatabase"/&gt;
+  ...
+&lt;/Host&gt;
+</source>
+
+    <p>On a server where <code>/etc/passwd</code> is not in use, you can
+    request Catalina to consider all directories found in a specified base
+    directory (such as <code>c:\Homes</code> in this example) to be
+    considered "user home" directories for the purposes of this directive:</p>
+
+<source>
+&lt;Host name="localhost" ...&gt;
+  ...
+  &lt;Listener className="org.apache.catalina.startup.UserConfig"
+            directoryName="public_html"
+            homeBase=c:\Homes"
+            userClass="org.apache.catalina.startup.HomesUserDatabase"/&gt;
+  ...
+&lt;/Host&gt;
+</source>
+
+    <p>If a user home directory has been set up for a user named
+    <code>craigmcc</code>, then its contents will be visible from a
+    client browser by making a request to a URL like:</p>
+
+<source>
+http://www.mycompany.com:8080/~craigmcc
+</source>
+
+    <p>Successful use of this feature requires recognition of the following
+    considerations:</p>
+    <ul>
+    <li>Each user web application will be deployed with characteristics
+        established by any <a href="defaultcontext.html">DefaultContext</a>
+        element you have configured for this Host.</li>
+    <li>It is legal to include more than one instance of this Listener
+        element.  This would only be useful, however, in circumstances
+        where you wanted to configure more than one "homeBase" directory.</li>
+    <li>The operating system username under which Catalina is executed
+        MUST have read access to each user's web application directory,
+        and all of its contents.</li>
+    </ul>
+
+  </subsection>
+
+
+</section>
+
+
+</body>
+
+
+</document>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/config/http.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/config/http.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/config/http.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,473 @@
+<?xml version="1.0"?>
+<!DOCTYPE document [
+  <!ENTITY project SYSTEM "project.xml">
+]>
+<document url="http.html">
+
+  &project;
+
+  <properties>
+    <author email="craigmcc at apache.org">Craig R. McClanahan</author>
+    <author email="yoavs at apache.org">Yoav Shapira</author>
+    <title>The HTTP Connector</title>
+  </properties>
+
+<body>
+
+
+<section name="Introduction">
+
+  <p>The <strong>HTTP Connector</strong> element represents a
+  <strong>Connector</strong> component that supports the HTTP/1.1 protocol.
+  It enables Catalina to function as a stand-alone web server, in addition
+  to its ability to execute servlets and JSP pages.  A particular instance
+  of this component listens for connections on a specific TCP port number
+  on the server.  One or more such <strong>Connectors</strong> can be
+  configured as part of a single <a href="service.html">Service</a>, each
+  forwarding to the associated <a href="engine.html">Engine</a> to perform
+  request processing and create the response.</p>
+
+  <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>
+
+  <p>At server startup time, this <strong>Connector</strong> will create a
+  number of request processing threads (based on the value configured for
+  the <code>minSpareThreads</code> attribute).  Each incoming request requires
+  a thread for the duration of that request.  If more simultaneous requests
+  are received than can be handled by the currently available request
+  processing threads, additional threads will be created up to the
+  configured maximum (the value of the <code>maxThreads</code> attribute).
+  If still more simultaneous requests are received, they are stacked up
+  inside the server socket created by the <strong>Connector</strong>, up to
+  the configured maximum (the value of the <code>acceptCount</code>
+  attribute.  Any further simultaneous requests will receive "connection
+  refused" errors, until resources are available to process them.</p>
+
+</section>
+
+
+<section name="Attributes">
+
+  <subsection name="Common Attributes">
+
+  <p>All implementations of <strong>Connector</strong>
+  support the following attributes:</p>
+
+  <attributes>
+ 
+    <attribute name="allowTrace" required="false">
+      <p>A boolean value which can be used to enable or disable the TRACE
+      HTTP method. If not specified, this attribute is set to false.</p>
+    </attribute>
+
+    <attribute name="emptySessionPath" required="false">
+      <p>If set to <code>true</code>, all paths for session cookies will be set
+      to <code>/</code>. This can be useful for portlet specification implementations,
+      but will greatly affect performance if many applications are accessed on a given
+      server by the client.
+      If not specified, this attribute is set to <code>false</code>.</p>
+    </attribute>
+
+    <attribute name="enableLookups" required="false">
+      <p>Set to <code>true</code> if you want calls to
+      <code>request.getRemoteHost()</code> to perform DNS lookups in
+      order to return the actual host name of the remote client.  Set
+      to <code>false</code> to skip the DNS lookup and return the IP
+      address in String form instead (thereby improving performance).
+      By default, DNS lookups are enabled.</p>
+    </attribute>
+
+    <attribute name="maxPostSize" required="false">
+      <p>The maximum size in bytes of the POST which will be handled by
+      the container FORM URL parameter parsing. The limit can be disabled by
+      setting this attribute to a value less than or equal to 0.
+      If not specified, this attribute is set to 2097152 (2 megabytes).</p>
+    </attribute>
+
+    <attribute name="maxSavePostSize" required="false">
+      <p>The maximum size in bytes of the POST which will be saved/buffered by
+      the container during FORM or CLIENT-CERT authentication. For both types
+      of authentication, the POST will be saved/buffered before the user is
+      authenticated. For CLIENT-CERT authentication, the POST is buffered for
+      the duration of
+ the SSL handshake and the buffer emptied when the request
+      is processed. For FORM authentication the POST is
+ saved whilst the user
+      is re-directed to the login form and is retained until the user
+      successfully authenticates or the session associated with the
+      authentication request expires. The limit can be disabled by setting this
+      attribute to -1. Setting the attribute to
+ zero will disable the saving of
+      POST data during authentication
+. If not
+ specified, this attribute is set
+      to
+ 4096 (4 kilobytes).</p>
+    </attribute>
+
+    <attribute name="protocol" required="false">
+      <p>This attribute value must be <code>HTTP/1.1</code> to use the HTTP
+      handler, which is the default.</p>
+    </attribute>
+
+    <attribute name="proxyName" required="false">
+      <p>If this <strong>Connector</strong> is being used in a proxy
+      configuration, configure this attribute to specify the server name
+      to be returned for calls to <code>request.getServerName()</code>.
+      See <a href="#Proxy Support">Proxy Support</a> for more
+      information.</p>
+    </attribute>
+
+    <attribute name="proxyPort" required="false">
+      <p>If this <strong>Connector</strong> is being used in a proxy
+      configuration, configure this attribute to specify the server port
+      to be returned for calls to <code>request.getServerPort()</code>.
+      See <a href="#Proxy Support">Proxy Support</a> for more
+      information.</p>
+    </attribute>
+
+    <attribute name="redirectPort" required="false">
+      <p>If this <strong>Connector</strong> is supporting non-SSL
+      requests, and a request is received for which a matching
+      <code>&lt;security-constraint&gt;</code> requires SSL transport,
+      Catalina will automatically redirect the request to the port
+      number specified here.</p>
+    </attribute>
+
+    <attribute name="scheme" required="false">
+      <p>Set this attribute to the name of the protocol you wish to have
+      returned by calls to <code>request.getScheme()</code>.  For
+      example, you would set this attribute to "<code>https</code>"
+      for an SSL Connector.  The default value is "<code>http</code>".
+      See <a href="#SSL Support">SSL Support</a> for more information.</p>
+    </attribute>
+
+    <attribute name="secure" required="false">
+      <p>Set this attribute to <code>true</code> if you wish to have
+      calls to <code>request.isSecure()</code> to return <code>true</code>
+      for requests received by this Connector (you would want this on an
+      SSL Connector).  The default value is <code>false</code>.</p>
+    </attribute>
+
+    <attribute name="URIEncoding" required="false">
+      <p>This specifies the character encoding used to decode the URI bytes,
+      after %xx decoding the URL. If not specified, ISO-8859-1 will be used.
+      </p>
+    </attribute>
+
+    <attribute name="useBodyEncodingForURI" required="false">
+      <p>This specifies if the encoding specified in contentType should be used
+      for URI query parameters, instead of using the URIEncoding. This
+      setting is present for compatibility with Tomcat 4.1.x, where the
+      encoding specified in the contentType, or explicitely set using
+      Request.setCharacterEncoding method was also used for the parameters from
+      the URL. The default value is <code>false</code>.
+      </p>
+    </attribute>
+
+    <attribute name="useIPVHosts" required="false">
+      <p>Set this attribute to <code>true</code> to cause Tomcat to use
+      the IP address that the request was recieved on to determine the Host
+      to send the request to.  The default value is <code>false</code>.</p>
+    </attribute>
+
+    <attribute name="xpoweredBy" required="false">
+      <p>Set this attribute to <code>true</code> to cause Tomcat to advertise
+      support for the Servlet specification using the header recommended in the
+      specification.  The default value is <code>false</code>.</p>
+    </attribute>
+
+
+  </attributes>
+
+  </subsection>
+
+  <subsection name="Standard Implementation">
+
+  <p>
+  HTTP supports the following additional attributes (in addition to the
+  common attributes listed above):</p>
+
+  <attributes>
+
+    <attribute name="acceptCount" required="false">
+      <p>The maximum queue length for incoming connection requests when
+      all possible request processing threads are in use.  Any requests
+      received when the queue is full will be refused.  The default
+      value is 10.</p>
+    </attribute>
+
+    <attribute name="address" required="false">
+      <p>For servers with more than one IP address, this attribute
+      specifies which address will be used for listening on the specified
+      port.  By default, this port will be used on all IP addresses
+      associated with the server.</p>
+    </attribute>
+
+    <attribute name="bufferSize" required="false">
+      <p>The size (in bytes) of the buffer to be provided for input
+      streams created by this connector.  By default, buffers of
+      2048 bytes will be provided.</p>
+    </attribute>
+
+    <attribute name="compressableMimeType" required="false">
+      <p>The value is a comma separated list of MIME types for which HTTP
+      compression may be used.
+      The default value is <code>text/html,text/xml,text/plain</code>.</p>
+    </attribute>
+
+    <attribute name="compression" required="false">
+      <p>The <strong>Connector</strong> may use HTTP/1.1 GZIP compression in
+      an attempt to save server bandwidth. The acceptable values for the
+      parameter is "off" (disable compression), "on" (allow compression, which
+      causes text data to be compressed), "force" (forces compression in all
+      cases), or a numerical integer value (which is equivalent to "on", but
+      specifies the minimum amount of data before the output is compressed). If
+      the content-length is not known and compression is set to "on" or more
+      aggressive, the output will also be compressed. If not specified, this
+      attribute is set to "off".</p>
+    </attribute>
+
+    <attribute name="connectionLinger" required="false">
+      <p>The number of milliseconds during which the sockets used by this
+      <strong>Connector</strong> will linger when they are closed.
+      The default value is -1 (socket linger is disabled).</p>
+    </attribute>
+
+    <attribute name="connectionTimeout" required="false">
+      <p>The number of milliseconds this <strong>Connector</strong> will wait,
+      after accepting a connection, for the request URI line to be
+      presented.  The default value is 60000 (i.e. 60 seconds).</p>
+    </attribute>
+
+    <attribute name="disableUploadTimeout" required="false">
+      <p>This flag allows the servlet container to use a different, longer
+      connection timeout while a servlet is being executed, which in the end
+      allows either the servlet a longer amount of time to complete its
+      execution, or a longer timeout during data upload. If not specified,
+      this attribute is set to "true".</p>
+    </attribute>
+
+    <attribute name="maxHttpHeaderSize" required="false">
+      <p>The maximum size of the request and response HTTP header, specified
+      in bytes.
+      If not specified, this attribute is set to 4096 (4 KB).</p>
+    </attribute>
+
+    <attribute name="maxKeepAliveRequests" required="false">
+      <p>The maximum number of HTTP requests which can be pipelined until
+      the connection is closed by the server. Setting this attribute to 1 will
+      disable HTTP/1.0 keep-alive, as well as HTTP/1.1 keep-alive and
+      pipelining. Setting this to -1 will allow an unlimited amount of
+      pipelined or keep-alive HTTP requests.
+      If not specified, this attribute is set to 100.</p>
+    </attribute>
+
+    <attribute name="maxSpareThreads" required="false">
+      <p>The maximum number of unused request processing threads that
+      will be allowed to exist until the thread pool starts stopping the
+      unnecessary threads.  The default value is 50.</p>
+    </attribute>
+
+    <attribute name="maxThreads" required="false">
+      <p>The maximum number of request processing threads to be created
+      by this <strong>Connector</strong>, which therefore determines the
+      maximum number of simultaneous requests that can be handled.  If
+      not specified, this attribute is set to 200.</p>
+    </attribute>
+
+    <attribute name="minSpareThreads" required="false">
+      <p>The number of request processing threads that will be created
+      when this <strong>Connector</strong> is first started.  The connector
+      will also make sure it has the specified number of idle processing
+      threads available. This attribute should be set to a value smaller
+      than that set for <code>maxThreads</code>.  The default value is 4.</p>
+    </attribute>
+
+    <attribute name="noCompressionUserAgents" required="false">
+      <p>The value is a comma separated list of regular expressions matching
+      user-agents of HTTP clients for which compression should not be used,
+      because these clients, although they do advertise support for the
+      feature, have a broken implementation.
+      The default value is an empty String (regexp matching disabled).</p>
+    </attribute>
+
+    <attribute name="port" required="true">
+      <p>The TCP port number on which this <strong>Connector</strong>
+      will create a server socket and await incoming connections.  Your
+      operating system will allow only one server application to listen
+      to a particular port number on a particular IP address.</p>
+    </attribute>
+
+    <attribute name="restrictedUserAgents" required="false">
+      <p>The value is a comma separated list of regular expressions matching
+      user-agents of HTTP clients for which HTTP/1.1 or HTTP/1.0 keep alive
+      should not be used, even if the clients advertise support for these
+      features.
+      The default value is an empty String (regexp matching disabled).</p>
+    </attribute>
+
+    <attribute name="server" required="false">
+      <p>The Server header for the http response.
+         Unless your paranoid, you won't need this feature.
+      </p>
+    </attribute>
+
+    <attribute name="socketBuffer" required="false">
+      <p>The size (in bytes) of the buffer to be provided for socket
+      output buffering. -1 can be specified to disable the use of a buffer.
+      By default, a buffers of 9000 bytes will be used.</p>
+    </attribute>
+
+    <attribute name="strategy" required="false">
+      <p>The thread pooling strategy which will be used. The default strategy does 
+      not use a master thread, but a more conventional strategy using a 
+      master listener thread can be used by setting "ms" as this attribute's value. 
+      The master strategy will work significantly better using the threadPriority 
+      attribute, which will apply only to the thread which listens on the server socket.
+      This is set to <code>lf</code> by default.
+      </p>
+    </attribute>
+
+    <attribute name="tcpNoDelay" required="false">
+      <p>If set to <code>true</code>, the TCP_NO_DELAY option will be
+      set on the server socket, which improves performance under most
+      circumstances.  This is set to <code>true</code> by default.</p>
+    </attribute>
+
+    <attribute name="threadPriority" required="false">
+      <p>The priority of the request processing threads within the JVM.
+      The default value is <code>java.lang.Thread#NORM_PRIORITY</code>.
+      See the JavaDoc for the java.lang.Thread class for more details on
+      what this priority means.
+      </p>
+    </attribute>
+
+  </attributes>
+
+  </subsection>
+
+</section>
+
+
+<section name="Nested Components">
+
+  <p>None at this time.</p>
+
+</section>
+
+
+<section name="Special Features">
+
+
+  <subsection name="HTTP/1.1 and HTTP/1.0 Support">
+
+  <p>This <strong>Connector</strong> supports all of the required features
+  of the HTTP/1.1 protocol, as described in RFC 2616, including persistent
+  connections, pipelining, expectations and chunked encoding.  If the client
+  (typically a browser) supports only HTTP/1.0, the
+  <strong>Connector</strong> will gracefully fall back to supporting this
+  protocol as well.  No special configuration is required to enable this
+  support. The <strong>Connector</strong> also supports HTTP/1.0
+  keep-alive.</p>
+
+  <p>RFC 2616 requires that HTTP servers always begin their responses with
+  the highest HTTP version that they claim to support.  Therefore, this
+  <strong>Connector</strong> will always return <code>HTTP/1.1</code> at
+  the beginning of its responses.</p>
+
+  </subsection>
+
+
+  <subsection name="Proxy Support">
+
+  <p>The <code>proxyName</code> and <code>proxyPort</code> attributes can
+  be used when Tomcat is run behind a proxy server.  These attributes
+  modify the values returned to web applications that call the
+  <code>request.getServerName()</code> and <code>request.getServerPort()</code>
+  methods, which are often used to construct absolute URLs for redirects.
+  Without configuring these attributes, the values returned would reflect
+  the server name and port on which the connection from the proxy server
+  was received, rather than the server name and port to whom the client
+  directed the original request.</p>
+
+  <p>For more information, see the
+  <a href="../proxy-howto.html">Proxy Support HOW-TO</a>.</p>
+
+  </subsection>
+
+
+  <subsection name="SSL Support">
+
+  <p>You can enable SSL support for a particular instance of this
+  <strong>Connector</strong> by setting the <code>secure</code> attribute to
+  <code>true</code>.  In addition, you may need to configure the following
+  attributes:</p>
+
+  <attributes>
+
+    <attribute name="algorithm" required="false">
+      <p>The certificate encoding algorithm to be used.  If not
+      specified, the default value is <code>SunX509</code>.</p>
+    </attribute>
+
+    <attribute name="clientAuth" required="false">
+      <p>Set to <code>true</code> if you want the SSL stack to require a
+      valid certificate chain from the client before
+ accepting a connection.
+      Set to <code>want</code> if you
+ want the SSL stack to request a client
+      Certificate, but
+ not fail if one isn't presented. A <code>false</code>
+      value (which is the default) will not require a certificate chain
+      unless
+ the client requests a resource protected by a security
+      constraint
+ that uses <code>CLIENT-CERT</code> authentication. See the
+      <a href="../ssl-howto.html">SSL HowTo</a> for an example.</p>
+    </attribute>
+
+    <attribute name="keystoreFile" required="false">
+      <p>The pathname of the keystore file where you have stored the
+      server certificate to be loaded.  By default, the pathname is
+      the file "<code>.keystore</code>" in the operating system home
+      directory of the user that is running Tomcat.</p>
+    </attribute>
+
+    <attribute name="keystorePass" required="false">
+      <p>The password used to access the server certificate from the
+      specified keystore file.  The default value is "<code>changeit</code>".
+      </p>
+    </attribute>
+
+    <attribute name="keystoreType" required="false">
+      <p>The type of keystore file to be used for the server certificate.
+      If not specified, the default value is "<code>JKS</code>".</p>
+    </attribute>
+
+    <attribute name="sslProtocol" required="false">
+      <p>The version of the SSL protocol to use.  If not specified,
+      the default is "<code>TLS</code>".</p>
+    </attribute>
+
+    <attribute name="ciphers" required="false">
+      <p>A comma seperated list of the encryption ciphers that may be used.
+      If not specified, then any available cipher may be used.</p>
+    </attribute>
+
+  </attributes>
+
+  <p>For more information, see the
+  <a href="../ssl-howto.html">SSL Configuration HOW-TO</a>.</p>
+
+  </subsection>
+
+
+</section>
+
+
+</body>
+
+</document>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/config/index.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/config/index.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/config/index.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,71 @@
+<?xml version="1.0"?>
+<!DOCTYPE document [
+  <!ENTITY project SYSTEM "project.xml">
+]>
+<document url="index.html">
+
+  &project;
+
+  <properties>
+    <author email="craigmcc at apache.org">Craig R. McClanahan</author>
+    <title>Overview</title>
+  </properties>
+
+<body>
+
+
+<section name="Overview">
+
+<p>This manual contains reference information about all of the configuration
+directives that can be included in a <code>conf/server.xml</code> file to
+configure the behavior of the Tomcat 5 Servlet/JSP container.  It does not
+attempt to describe which configuration directives should be used to perform
+specific tasks - for that, see the various <em>HOW-TO</em> documents on the
+main index page.</p>
+
+<p>The configuration element descriptions are organized into the following
+major categories:</p>
+<ul>
+<li><strong>Top Level Elements</strong> - <code>&lt;Server&gt;</code> is the
+    root element of the entire configuration file, while
+    <code>&lt;Service&gt;</code> represents a group of Connectors that is
+    associated with an Engine.</li>
+<li><strong>Connectors</strong> - Represent the interface between external
+    clients sending requests to (and receiving responses from) a particular
+    Service.</li>
+<li><strong>Containers</strong> - Represent components whose function is to
+    process incoming requests, and create the corresponding responses.
+    An Engine handles all requests for a Service, a Host handles all requests
+    for a particular virtual host, and a Context handles all requests for a
+    specific web application.</li>
+<li><strong>Nested Components</strong> - Represent elements that can be
+    nested inside the element for a Container.  Some elements can be nested
+    inside any Container, while others can only be nested inside a
+    Context.</li>
+</ul>
+
+<p>For each element, the corresponding documentation follows this general
+outline:</p>
+<ul>
+<li><strong>Introduction</strong> - Overall description of this particular
+    component.  There will be a corresponding Java <em>interface</em> (in
+    the <code>org.apache.catalina</code> pacakge) that is implemented by one
+    or more standard implementations.</li>
+<li><strong>Attributes</strong> - The set of attributes that are legal for
+    this element.  Generally, this will be subdivided into <em>Common</em>
+    attributes that are supported by all implementations of the corresponding
+    Java interface, and <em>Standard Implementation</em> attributes that are
+    specific to a particular Java class that implements this interface.
+    The names of required attributes are <strong>bolded</strong>.</li>
+<li><strong>Nested Components</strong> - Enumerates which of the <em>Nested
+    Components</em> can be legally nested within this element.</li>
+<li><strong>Special Features</strong> - Describes the configuration of a large
+    variety of special features (specific to each element type) that are
+    supported by the standard implementation of this interface.</li>
+</ul>
+
+</section>
+
+
+</body>
+</document>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/config/loader.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/config/loader.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/config/loader.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,162 @@
+<?xml version="1.0"?>
+<!DOCTYPE document [
+  <!ENTITY project SYSTEM "project.xml">
+]>
+<document url="loader.html">
+
+  &project;
+
+  <properties>
+    <author email="craigmcc at apache.org">Craig R. McClanahan</author>
+    <author>Yoav Shapira</author>
+    <title>The Loader Component</title>
+  </properties>
+
+<body>
+
+
+<section name="Introduction">
+
+  <p>The <strong>Loader</strong> element represents the <em>web
+  application class loader</em> that will be used to load Java
+  classes and resources for your web application.  Such
+  a class loader must follow the requirements of the Servlet
+  Specification, and load classes from the following locations:</p>
+  <ul>
+  <li>From the <code>/WEB-INF/classes</code> directory inside your
+      web application.</li>
+  <li>From JAR files in the <code>/WEB-INF/lib</code> directory
+      inside your web application.</li>
+  <li>From resources made available by Catalina to all web
+      applications globally.</li>
+  </ul>
+
+  <p>A Loader element MAY be nested inside a <a href="context.html">Context</a>
+  component.  If it is not included, a default Loader configuration will be
+  created automatically, which is sufficient for most requirements.</p>
+
+  <p>For a more in-depth description of the class loader hierarchy
+  that is implemented by Catalina, see <a href="../class-loader-howto.html">the ClassLoader HowTo</a>.</p>
+
+    <blockquote><em>
+    <p>The description below uses the variable name $CATALINA_HOME
+    to refer to the directory into which you have installed Tomcat 5,
+    and is the base directory against which most relative paths are
+    resolved.  However, if you have configured Tomcat 5 for multiple
+    instances by setting a CATALINA_BASE directory, you should use
+    $CATALINA_BASE instead of $CATALINA_HOME for each of these
+    references.</p>
+    </em></blockquote>
+
+</section>
+
+
+<section name="Attributes">
+
+  <subsection name="Common Attributes">
+
+    <p>All implementations of <strong>Loader</strong>
+    support the following attributes:</p>
+
+    <attributes>
+
+      <attribute name="className" required="false">
+        <p>Java class name of the implementation to use.  This class must
+        implement the <code>org.apache.catalina.Loader</code> interface.
+        If not specified, the standard value (defined below) will be used.</p>
+      </attribute>
+
+      <attribute name="delegate" required="false">
+        <p>Set to <code>true</code> if you want the class loader to follow
+        the standard Java2 delegation model, and attempt to load classes from
+        parent class loaders <strong>before</strong> looking inside the web
+        application.  Set to <code>false</code> (the default) to have the
+        class loader look inside the web application first, before asking
+        parent class loaders to find requested classes or resources.</p>
+      </attribute>
+
+      <attribute name="reloadable" required="false">
+        <p>Set to <code>true</code> if you want Catalina to monitor classes in
+        <code>/WEB-INF/classes/</code> and <code>/WEB-INF/lib</code> for
+        changes, and automatically reload the web application if a change
+        is detected.  This feature is very useful during application
+        development, but it requires significant runtime overhead and is
+        not recommended for use on deployed production applications.  You
+        can use the <a href="../manager-howto.html">Manager</a> web
+        application, however, to trigger reloads of deployed applications
+        on demand.</p>
+
+        <p><strong>NOTE</strong> - The value for this property will be
+        inherited from the <code>reloadable</code> attribute you set on
+        the surrounding <a href="context.html">Context</a> component,
+        and any value you explicitly set here will be replaced.</p>
+      </attribute>
+
+    </attributes>
+
+  </subsection>
+
+
+  <subsection name="Standard Implementation">
+
+    <p>The standard implementation of <strong>Loader</strong> is
+    <strong>org.apache.catalina.loader.WebappLoader</strong>.
+    It supports the following additional attributes (in addition to the
+    common attributes listed above):</p>
+
+    <attributes>
+
+      <attribute name="backgroundProcesssorDelay" required="false">
+        <p>The number of seconds between checks for modified classes and
+        resources, if <code>reloadable</code> has been set to
+        <code>true</code>.</p>
+        <p>See the general documentation for this parameter at <a href="../host.html">Host Container</a>.</p>
+      </attribute>
+
+      <attribute name="loaderClass" required="false">
+        <p>Java class name of the <code>java.lang.ClassLoader</code>
+        implementation class to use.  If not specified, the default value is
+        <code>org.apache.catalina.loader.WebappClassLoader</code>.</p>
+      </attribute>
+
+      <attribute name="useSystemClassLoaderAsParent" required="false">
+        <p>If no parent classloader is specified, should the system
+        classloader be used? The default of <code>true</code> mantains
+        backwards compatibility with previous releases however most
+        users will want to set this to <code>false</code> to obtain
+        the parent classloader from the associated container.</p>
+        <p>This attribute will not be present in Tomcat 6 where the
+        Loader API has changed and the parent class loader is always
+        obtained from the associated container.</p>
+      </attribute>
+
+    </attributes>
+
+  </subsection>
+
+
+</section>
+
+
+<section name="Nested Components">
+
+  <p>No components may be nested inside a <strong>Loader</strong> element.</p>
+
+</section>
+
+
+<section name="Special Features">
+
+  <subsection name="Logging">
+
+    <p>A loader is associated with the log category based on its classname.</p>
+
+  </subsection>
+
+</section>
+
+
+</body>
+
+
+</document>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/config/manager.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/config/manager.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/config/manager.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,459 @@
+<?xml version="1.0"?>
+<!DOCTYPE document [
+  <!ENTITY project SYSTEM "project.xml">
+]>
+<document url="manager.html">
+
+  &project;
+
+  <properties>
+    <author email="craigmcc at apache.org">Craig R. McClanahan</author>
+    <author email="yoavs at apache.org">Yoav Shapira</author>
+    <title>The Manager Component</title>
+  </properties>
+
+<body>
+
+
+<section name="Introduction">
+
+  <p>The <strong>Manager</strong> element represents the <em>session
+  manager</em> that will be used to create and maintain HTTP sessions
+  as requested by the associated web application.</p>
+
+  <p>A Manager element MAY be nested inside a
+  <a href="context.html">Context</a> component.  If it is not included,
+  a default Manager configuration will be created automatically, which
+  is sufficient for most requirements.</p>
+
+</section>
+
+
+<section name="Attributes">
+
+  <subsection name="Common Attributes">
+
+    <p>All implementations of <strong>Manager</strong>
+    support the following attributes:</p>
+
+    <attributes>
+
+      <attribute name="className" required="false">
+        <p>Java class name of the implementation to use.  This class must
+        implement the <code>org.apache.catalina.Manager</code> interface.
+        If not specified, the standard value (defined below) will be used.</p>
+      </attribute>
+
+      <attribute name="distributable" required="false">
+        <p>Set to <code>true</code> to ask the session manager to enforce
+        the restrictions described in the Servlet Specification on
+        distributable applications (primarily, this would mean that all
+        session attributes must implement <code>java.io.Serializable</code>).
+        Set to <code>false</code> (the default) to not enforce these
+        restrictions.</p>
+
+        <p><strong>NOTE</strong> - The value for this property is inherited
+        automatically based on the presence or absence of the
+        <code>&lt;distributable&gt;</code> element in the web application
+        deployment descriptor (<code>/WEB-INF/web.xml</code>).</p>
+      </attribute>
+
+    </attributes>
+
+  </subsection>
+
+
+  <subsection name="Standard Implementation">
+
+    <p>Tomcat provides two standard implementations of <strong>Manager</strong>
+    for use - the default one stores active sessions, while the optional one
+    stores active sessions that have been swapped out (in addition to saving
+    sessions across a restart of Tomcat) in a storage location that is selected
+    via the use of an appropriate <strong>Store</strong> nested element.</p>
+
+    <h3>Standard Manager Implementation</h3>
+
+    <p>The standard implementation of <strong>Manager</strong> is
+    <strong>org.apache.catalina.session.StandardManager</strong>.
+    It supports the following additional attributes (in addition to the
+    common attributes listed above):</p>
+
+    <attributes>
+
+      <attribute name="algorithm" required="false">
+        <p>Name of the <em>Message Digest</em> algorithm used to calculate
+        session identifiers produced by this Manager.  This value must
+        be supported by the <code>java.security.MessageDigest</code> class.
+        If not specified, the default value is "MD5".</p>
+      </attribute>
+
+      <attribute name="entropy" required="false">
+        <p>A String value that is utilized when seeding the random number
+        generator used to create session identifiers for this Manager.
+        If not specified, a semi-useful value is calculated, but a long
+        String value should be specified in security-conscious
+        environments.</p>
+      </attribute>
+
+      <attribute name="maxActiveSessions" required="false">
+        <p>The maximum number of active sessions that will be created by
+        this Manager, or -1 (the default) for no limit.</p>
+      </attribute>
+
+      <attribute name="maxInactiveInterval" required="false">
+        <p>The initial maximum time interval, in seconds, 
+        between client requests before a session is invalidated. A negative value
+        will result in sessions never timing out. If the attribute is not provided,
+        a default of 60 seconds is used.</p>
+        
+        <p>This attribute provides the initial value whenever a 
+        new session is created, but the interval may be dynamically 
+        varied by a servlet via the 
+        <code>setMaxInactiveInterval</code> method of the <code>HttpSession</code> object.</p>
+      </attribute>
+
+      <attribute name="pathname" required="false">
+        <p>Absolute or relative (to the work directory for this Context)
+        pathname of the file in which session state will be preserved
+        across application restarts, if possible.  The default is
+        "SESSIONS.ser".  See <a href="#Restart Persistence">Restart
+        Persistence</a> for more information. Restart persistence may be 
+        disabled by setting this attribute to an empty string.</p>
+      </attribute>
+
+      <attribute name="processExpiresFrequency" required="false">
+        <p>Frequency of the session expiration, and related manager operations.
+        Manager operations will be done once for the specified amount of
+        backgrondProcess calls (ie, the lower the amount, the more often the
+        checks will occur). The minimum value is 1, and the default value is 6.
+        </p>
+      </attribute>
+
+      <attribute name="randomClass" required="false">
+        <p>Java class name of the <code>java.util.Random</code>
+        implementation class to use.  If not specified, the default value is
+        <code>java.security.SecureRandom</code>.</p>
+      </attribute>
+
+      <attribute name="sessionIdLength" required="false">
+       <p>The length of session ids created by this Manager, excluding any
+        JVM route information used for load balancing. 
+        The default is 16.</p>
+      </attribute>
+
+    </attributes>
+
+    <h3>Persistent Manager Implementation</h3>
+
+    <p><em><strong>WARNING - Use of this Manager implementation
+    has not been thoroughly tested, and should be considered experimental!
+    </strong></em></p>
+
+    <p>The persistent implementation of <strong>Manager</strong> is
+    <strong>org.apache.catalina.session.PersistentManager</strong>.  In
+    addition to the usual operations of creating and deleting sessions, a
+    <code>PersistentManager</code> has the capability to swap active (but
+    idle) sessions out to a persistent storage mechanism, as well as to save
+    all sessions across a normal restart of Tomcat.  The actual persistent
+    storage mechanism used is selected by your choice of a
+    <strong>Store</strong> element nested inside the <strong>Manager</strong>
+    element - this is required for use of <code>PersistentManager</code>.</p>
+
+    <p>This implementation of Manager supports the following attributes in
+    addition to the <a href="#Common Attributes">Common Attributes</a>
+    described earlier.</p>
+
+    <attributes>
+
+      <attribute name="algorithm" required="false">
+        <p>Name of the <em>Message Digest</em> algorithm used to calculate
+        session identifiers produced by this Manager.  This value must
+        be supported by the <code>java.security.MessageDigest</code> class.
+        If not specified, the default value is "MD5".</p>
+      </attribute>
+
+      <attribute name="className" required="false">
+        <p>Java class name of the implementation to use.  This class must
+        implement the <code>org.apache.catalina.Manager</code> interface.
+        You <strong>must</strong> specify
+        <code>org.apache.catalina.session.PersistentManager</code> to use
+        this manager implementation.</p>
+      </attribute>
+
+      <attribute name="entropy" required="false">
+        <p>A String value that is utilized when seeding the random number
+        generator used to create session identifiers for this Manager.
+        If not specified, a semi-useful value is calculated, but a long
+        String value should be specified in security-conscious
+        environments.</p>
+      </attribute>
+
+      <attribute name="maxActiveSessions" required="false">
+        <p>The maximum number of active sessions that will be created by
+        this Manager, or -1 (the default) for no limit.</p>
+      </attribute>
+
+      <attribute name="maxIdleBackup" required="false">
+        <p>The time interval (in seconds) since the last access to a session
+        before it is eligible for being persisted to the session store, or
+        <code>-1</code> to disable this feature.  By default, this feature is
+        disabled.</p>
+      </attribute>
+
+      <attribute name="maxIdleSwap" required="false">
+        <p>The time interval (in seconds) since the last access to a session
+        before it should be persisted to the session store, and
+        passivated out of the server's memory, or <code>-1</code> to disable
+        this feature.  If this feature is enabled, the time interval specified
+        here should be equal to or longer than the value specified for
+        <code>maxIdleBackup</code>.  By default, this feature is disabled.</p>
+      </attribute>
+
+      <attribute name="minIdleSwap" required="false">
+        <p>The time interval (in seconds) since the last access to a session
+        before it will be eligible to be persisted to the session store, and
+        passivated out of the server's memory, or <code>-1</code> for this
+        swapping to be available at any time.  If specified, this value should
+        be less than that specified by <code>maxIdleSwap</code>.  By default,
+        this value is set to <code>-1</code>.</p>
+      </attribute>
+
+      <attribute name="maxInactiveInterval" required="false">
+        <p>The initial maximum time interval, in seconds, 
+        between client requests before a session is invalidated. A negative value
+        will result in sessions never timing out. If the attribute is not provided,
+        a default of 60 seconds is used.</p>
+        
+        <p>This attribute provides the initial value whenever a 
+        new session is created, but the interval may be dynamically 
+        varied by a servlet via the 
+        <code>setMaxInactiveInterval</code>method of the <code>HttpSession</code> object.</p>
+      </attribute>
+
+      <attribute name="randomClass" required="false">
+        <p>Java class name of the <code>java.util.Random</code>
+        implementation class to use.  If not specified, the default value is
+        <code>java.security.SecureRandom</code>.</p>
+      </attribute>
+
+      <attribute name="saveOnRestart" required="false">
+        <p>Should all sessions be persisted and reloaded when Tomcat is shut
+        down and restarted (or when this application is reloaded)?  By default,
+        this attribute is set to <code>true</code>.</p>
+      </attribute>
+
+      <attribute name="sessionIdLength" required="false">
+        <p>The length of session ids created by this Manager, excluding any
+        JVM route information used for load balancing. 
+        The default is 16.</p>
+      </attribute>
+
+    </attributes>
+
+    <p>In order to successfully use a PersistentManager, you must nest inside
+    it a <strong>&lt;Store&gt;</strong> element, as described below.</p>
+
+  </subsection>
+
+
+</section>
+
+
+<section name="Nested Components">
+
+  <h3>Standard Manager Implementation</h3>
+
+  <p>If you are using the <em>Standard Manager Implementation</em>
+  as described above, no elements may be nested inside your
+  <strong>&lt;Manager&gt;</strong> element.</p>
+
+  <h3>Persistent Manager Implementation</h3>
+
+  <p>If you are using the <em>Persistent Manager Implementation</em>
+  as described above, you <strong>MUST</strong> nest a
+  <strong>&lt;Store&gt;</strong> element inside, which defines the
+  characteristics of the persistent data storage.  Two implementations
+  of the <code>&lt;Store&gt;</code> element are currently available,
+  with different characteristics, as described belowl</p>
+
+  <h5>File Based Store</h5>
+
+  <p>The <em>File Based Store</em> implementation saves swapped out
+  sessions in individual files (named based on the session identifier)
+  in a configurable directory.  Therefore, you are likely to encounter
+  scalability problems as the number of active sessions increases, and
+  this should primarily be considered a means to easily experiment.</p>
+
+  <p>To configure this, add a <code>&lt;Store&gt;</code> nested inside
+  your <code>&lt;Manager&gt;</code> element with the following attributes:
+  </p>
+
+  <attributes>
+
+    <attribute name="checkInterval" required="false">
+      <p>The interval (in seconds) between checks for expired sessions
+      among those sessions that are currently swapped out.  By default,
+      this interval is set to 60 seconds (one minute).</p>
+    </attribute>
+
+    <attribute name="className" required="true">
+      <p>Java class name of the implementation to use.  This class must
+      implement the <code>org.apache.catalina.Store</code> interface.  You
+      <strong>must</strong> specify
+      <code>org.apache.catalina.session.FileStore</code>
+      to use this implementation.</p>
+    </attribute>
+
+    <attribute name="directory" required="false">
+      <p>Absolute or relative (to the temporary work directory for this web
+      application) pathname of the directory into which individual session
+      files are written.  If not specified, the temporary work directory
+      assigned by the container is utilized.</p>
+    </attribute>
+
+  </attributes>
+
+
+  <h5>JDBC Based Store</h5>
+
+  <p>The <em>JDBC Based Store</em> implementation saves swapped out
+  sessions in individual rows of a preconfigured table in a database
+  that is accessed via a JDBC driver.  With large numbers of swapped out
+  sessions, this implementation will exhibit improved performance over
+  the File Based Store described above.</p>
+
+  <p>To configure this, add a <code>&lt;Store&gt;</code> nested inside
+  your <code>&lt;Manager&gt;</code> element with the following attributes:
+  </p>
+
+  <attributes>
+
+    <attribute name="checkInterval" required="false">
+      <p>The interval (in seconds) between checks for expired sessions
+      among those sessions that are currently swapped out.  By default,
+      this interval is set to 60 seconds (one minute).</p>
+    </attribute>
+
+    <attribute name="className" required="true">
+      <p>Java class name of the implementation to use.  This class must
+      implement the <code>org.apache.catalina.Store</code> interface.  You
+      <strong>must</strong> specify
+      <code>org.apache.catalina.session.JDBCStore</code>
+      to use this implementation.</p>
+    </attribute>
+
+    <attribute name="connectionURL" required="true">
+      <p>The connection URL that will be handed to the configured JDBC
+      driver to establish a connection to the database containing our
+      session table.</p>
+    </attribute>
+
+    <attribute name="driverName" required="true">
+      <p>Java class name of the JDBC driver to be used.</p>
+    </attribute>
+
+    <attribute name="sessionAppCol" required="true">
+      <p>Name of the database column, contained in the specified session
+      table, that contains the Engine, Host, and Web Application Context
+      name in the format <code>/Engine/Host/Context</code>.</p>
+    </attribute>
+
+    <attribute name="sessionDataCol" required="true">
+      <p>Name of the database column, contained in the specified
+      session table, that contains the serialized form of all session
+      attributes for a swapped out session.  The column type must accept
+      a binary object (typically called a BLOB).</p>
+    </attribute>
+
+    <attribute name="sessionIdCol" required="true">
+      <p>Name of the database column, contained in the specified
+      session table, that contains the session identifier of the
+      swapped out session.  The column type must accept character
+      string data of at least as many characters as are contained
+      in session identifiers created by Tomcat (typically 32).</p>
+    </attribute>
+
+    <attribute name="sessionLastAccessedCol" required="true">
+      <p>Name of the database column, contained in the specified
+      session table, that contains the <code>lastAccessedTime</code>
+      property of this session.  The column type must accept a
+      Java <code>long</code> (64 bits).</p>
+    </attribute>
+
+    <attribute name="sessionMaxInactiveCol" required="true">
+      <p>Name of the database column, contained in the specified
+      session table, that contains the <code>maxInactiveInterval</code>
+      property of this session.  The column type must accept a
+      Java <code>integer</code> (32 bits).</p>
+    </attribute>
+
+    <attribute name="sessionTable" required="true">
+      <p>Name of the database table to be used for storing swapped out
+      sessions.  This table must contain (at least) the database columns
+      that are configured by the other attributes of this element.</p>
+    </attribute>
+
+    <attribute name="sessionValidCol" required="true">
+      <p>Name of the database column, contained in the specified
+      session table, that contains a flag indicating whether this
+      swapped out session is still valid or not.  The column type
+      must accept a single character.</p>
+    </attribute>
+
+  </attributes>
+
+  <p>Before attempting to use the JDBC Based Store for the first time,
+  you must create the table that will be used to store swapped out sessions.
+  Detailed SQL commands vary depending on the database you are using, but
+  a script like this will generally be required:</p>
+
+<source>
+create table tomcat_sessions (
+  session_id     varchar(100) not null primary key,
+  valid_session  char(1) not null,
+  max_inactive   int not null,
+  last_access    bigint not null,
+  app_name       varchar(255),
+  session_data   mediumblob,
+  KEY kapp_name(app_name)
+);
+</source>
+
+  <p>In order for the JDBC Based Store to successfully connect to your
+  database, the JDBC driver you configure must be visible to Tomcat's
+  internal class loader.  Generally, that means you must place the JAR
+  file containing this driver into the <code>$CATALINA_HOME/server/lib</code>
+  directory (if your applications do not also need it) or into the
+  <code>$CATALINA_HOME/common/lib</code> directory (if you wish to share
+  this driver with your web applications.</p>
+
+</section>
+
+
+<section name="Special Features">
+
+
+  <subsection name="Restart Persistence">
+
+    <p>Whenver Catalina is shut down normally and restarted, or when an
+    application reload is triggered, the standard Manager implementation
+    will attempt to serialize all currently active sessions to a disk
+    file located via the <code>pathname</code> attribute.  All such saved
+    sessions will then be deserialized and activated (assuming they have
+    not expired in the mean time) when the application reload is completed.</p>
+
+    <p>In order to successfully restore the state of session attributes,
+    all such attributes MUST implement the <code>java.io.Serializable</code>
+    interface.  You MAY cause the Manager to enforce this restriction by
+    including the <code>&lt;distributable&gt;</code> element in your web
+    application deployment descriptor (<code>/WEB-INF/web.xml</code>).</p>
+
+  </subsection>
+
+</section>
+
+
+</body>
+
+
+</document>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/config/project.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/config/project.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/config/project.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<project name="Apache Tomcat Configuration Reference"
+        href="http://tomcat.apache.org/">
+
+  <title>Apache Tomcat Configuration Reference</title>
+
+  <logo href="/images/tomcat.gif">
+    The Apache Tomcat Servlet/JSP Container
+  </logo>
+
+    
+  <body>
+
+    <menu name="Links">
+        <item name="Docs Home"             href="../index.html"/>
+        <item name="Config Ref. Home"      href="index.html"/>
+    </menu>
+
+    <menu name="Top Level Elements">
+        <item name="Server"                href="server.html"/>
+        <item name="Service"               href="service.html"/>
+    </menu>
+
+    <menu name="Connectors">
+        <item name="HTTP"                  href="http.html"/>
+        <item name="AJP"                   href="ajp.html"/>
+    </menu>
+
+    <menu name="Containers">
+        <item name="Context"               href="context.html"/>
+        <item name="Engine"                href="engine.html"/>
+        <item name="Host"                  href="host.html"/>
+    </menu>
+
+    <menu name="Nested Components">
+        <item name="Global Resources"      href="globalresources.html"/>
+        <item name="Loader"                href="loader.html"/>
+        <item name="Manager"               href="manager.html"/> 
+        <item name="Realm"                 href="realm.html"/>
+        <item name="Resources"             href="resources.html"/>
+        <item name="Valve"                 href="valve.html"/>
+    </menu>
+
+  </body>
+
+</project>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/config/realm.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/config/realm.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/config/realm.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,497 @@
+<?xml version="1.0"?>
+<!DOCTYPE document [
+  <!ENTITY project SYSTEM "project.xml">
+]>
+<document url="realm.html">
+
+  &project;
+
+  <properties>
+    <author email="craigmcc at apache.org">Craig R. McClanahan</author>
+    <title>The Realm Component</title>
+  </properties>
+
+<body>
+
+
+<section name="Introduction">
+
+  <p>A <strong>Realm</strong> element represents a "database" of usernames,
+  passwords, and <em>roles</em> (similar to Unix <em>groups</em>) assigned
+  to those users.  Different implementations of Realm allow Catalina to be
+  integrated into environments where such authentication information is already
+  being created and maintained, and then utilize that information to implement
+  <em>Container Managed Security</em> as described in the Servlet
+  Specification.</p>
+
+  <p>You may nest a Realm inside any Catalina container
+  <a href="engine.html">Engine</a>, <a href="host.html">Host</a>, or
+  <a href="context.html">Context</a>).  In addition, Realms associated with
+  an Engine or a Host are automatically inherited by lower-level
+  containers, unless explicitly overridden.</p>
+
+  <p>For more in-depth information about container managed security in web
+  applications, as well as more information on configuring and using the 
+  standard realm component implementations, please see the 
+  <a href="../realm-howto.html">Container-Managed Security Guide</a>.
+  </p>
+
+    <blockquote><em>
+    <p>The description below uses the variable name $CATALINA_HOME
+    to refer to the directory into which you have installed Tomcat 5,
+    and is the base directory against which most relative paths are
+    resolved.  However, if you have configured Tomcat 5 for multiple
+    instances by setting a CATALINA_BASE directory, you should use
+    $CATALINA_BASE instead of $CATALINA_HOME for each of these
+    references.</p>
+    </em></blockquote>
+
+</section>
+
+
+<section name="Attributes">
+
+  <subsection name="Common Attributes">
+
+    <p>All implementations of <strong>Realm</strong>
+    support the following attributes:</p>
+
+    <attributes>
+
+      <attribute name="className" required="true">
+        <p>Java class name of the implementation to use.  This class must
+        implement the <code>org.apache.catalina.Realm</code> interface.</p>
+      </attribute>
+
+    </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>
+
+    <p>The <strong>JDBC Database Realm</strong> connects Catalina 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,
+    changes to the database will be immediately reflected in the
+    information used to authenticate new logins.</p>
+
+    <p>A rich set of additional attributes lets you configure the required
+    connection to the underlying database, as well as the table and
+    column names used to retrieve the required information:</p>
+
+    <attributes>
+
+      <attribute name="connectionName" required="true">
+        <p>The database username to use when establishing the JDBC
+        connection.</p>
+      </attribute>
+
+      <attribute name="connectionPassword" required="true">
+        <p>The database password to use when establishing the JDBC
+        connection.</p>
+      </attribute>
+
+      <attribute name="connectionURL" required="true">
+        <p>The connection URL to be passed to the JDBC driver when
+        establishing a database connection.</p>
+      </attribute>
+
+      <attribute name="digest" required="false">
+        <p>The name of the <code>MessageDigest</code> algorithm used
+        to encode user passwords stored in the database.  If not specified,
+        user passwords are assumed to be stored in clear-text.</p>
+      </attribute>
+   
+      <attribute name="digestEncoding" required="false">
+        <p>The charset for encoding digests.  If not specified, the platform
+        default will be used.</p>
+      </attribute>
+
+      <attribute name="driverName" required="true">
+        <p>Fully qualified Java class name of the JDBC driver to be
+        used to connect to the authentication database.</p>
+      </attribute>
+
+      <attribute name="roleNameCol" required="true">
+        <p>Name of the column, in the "user roles" table, which contains
+        a role name assigned to the corresponding user.</p>
+      </attribute>
+
+      <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
+        <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
+        in clear text.</p>
+      </attribute>
+
+      <attribute name="userNameCol" required="true">
+        <p>Name of the column, in the "users" and "user roles" table,
+        that contains the user's username.</p>
+      </attribute>
+
+      <attribute name="userRoleTable" required="true">
+        <p>Name of the "user roles" table, which must contain columns
+        named by the <code>userNameCol</code> and <code>roleNameCol</code>
+        attributes.</p>
+      </attribute>
+
+      <attribute name="userTable" required="true">
+        <p>Name of the "users" table, which must contain columns named
+        by the <code>userNameCol</code> and <code>userCredCol</code>
+        attributes.</p>
+      </attribute>
+
+    </attributes>
+
+    <p>See the <a href="../realm-howto.html">Container-Managed Security Guide</a> for more
+    information on setting up container managed security using the
+    JDBC Database Realm component.</p>
+
+
+    <h3>
+      DataSource Database Realm (org.apache.catalina.realm.DataSourceRealm)
+    </h3>
+
+    <p>The <strong>DataSource Database Realm</strong> connects Catalina 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,
+    changes to the database will be immediately reflected in the
+    information used to authenticate new logins.</p>
+
+    <p>The JDBC Realm uses a single db connection. This requires that
+    realm based authentication be synchronized, i.e. only one authentication
+    can be done at a time. This could be a bottleneck for applications
+    with high volumes of realm based authentications.</p>
+
+    <p>The DataSource Database Realm supports simultaneous realm based
+    authentications and allows the underlying JDBC DataSource to
+    handle optimizations like database connection pooling.</p>
+
+    <p>A rich set of additional attributes lets you configure the name
+    of the JNDI JDBC DataSource, as well as the table and
+    column names used to retrieve the required information:</p>
+
+    <attributes>
+
+      <attribute name="dataSourceName" required="true">
+        <p>The name of the JNDI JDBC DataSource for this Realm.</p>
+      </attribute>
+
+      <attribute name="digest" required="false">
+        <p>The name of the <code>MessageDigest</code> algorithm used
+        to encode user passwords stored in the database.  If not specified,
+        user passwords are assumed to be stored in clear-text.</p>
+      </attribute>
+
+      <attribute name="roleNameCol" required="true">
+        <p>Name of the column, in the "user roles" table, which contains
+        a role name assigned to the corresponding user.</p>
+      </attribute>
+
+      <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
+        <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
+        in clear text.</p>
+      </attribute>
+
+      <attribute name="userNameCol" required="true">
+        <p>Name of the column, in the "users" and "user roles" table,
+        that contains the user's username.</p>
+      </attribute>
+
+      <attribute name="userRoleTable" required="true">
+        <p>Name of the "user roles" table, which must contain columns
+        named by the <code>userNameCol</code> and <code>roleNameCol</code>
+        attributes.</p>
+      </attribute>
+
+      <attribute name="userTable" required="true">
+        <p>Name of the "users" table, which must contain columns named
+        by the <code>userNameCol</code> and <code>userCredCol</code>
+        attributes.</p>
+      </attribute>
+
+    </attributes>
+
+    <p>See the <a href="../realm-howto.html#DataSourceRealm">
+    DataSource Realm HOW-TO</a> for more information on setting up container
+    managed security using the DataSource Database Realm component.</p>
+
+
+    <h3>JNDI Directory Realm (org.apache.catalina.realm.JNDIRealm)</h3>
+
+
+    <p>The <strong>JNDI Directory Realm</strong> connects Catalina 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
+    information used to authenticate new logins.</p>
+
+
+    <p>The directory realm supports a variety of approaches to using
+    LDAP for authentication:</p>
+
+    <ul>
+    <li>The realm can either use a pattern to determine the
+    distinguished name (DN) of the user's directory entry, or search
+    the directory to locate that entry.
+    </li>
+
+    <li>The realm can authenticate the user either by binding to the
+    directory with the DN of the user's entry and the password
+    presented by the user, or by retrieving the password from the
+    user's entry and performing a comparison locally.
+    </li>
+
+    <li>Roles may be represented in the directory as explicit entries
+    found by a directory search (e.g. group entries of which the user
+    is a member), as the values of an attribute in the user's entry,
+    or both.
+    </li>
+    </ul>
+
+    <p> A rich set of additional attributes lets you configure the
+    required behaviour as well as the connection to the underlying
+    directory and the element and attribute names used to retrieve
+    information from the directory:</p>
+
+    <attributes>
+       <attribute name="alternateURL" required="false">
+         <p>If a socket connection can not be made to the provider at
+         the <code>connectionURL</code> an attempt will be made to use the
+         <code>alternateURL</code>.</p>
+       </attribute>
+
+       <attribute name="authentication" required="false">
+         <p>A string specifying the type of authentication to use.
+         "none", "simple", "strong" or a provider specific definition
+         can be used. If no value is given the providers default is used.</p>
+       </attribute>
+
+      <attribute name="connectionName" required="false">
+        <p>The directory username to use when establishing a
+        connection to the directory for LDAP search operations. If not
+        specified an anonymous connection is made, which is often
+        sufficient unless you specify the <code>userPassword</code>
+        property.</p>
+      </attribute>
+
+      <attribute name="connectionPassword" required="false">
+        <p>The directory password to use when establishing a
+        connection to the directory for LDAP search operations. If not
+        specified an anonymous connection is made, which is often
+        sufficient unless you specify the <code>userPassword</code>
+        property.</p>
+      </attribute>
+
+      <attribute name="connectionURL" required="true">
+        <p>The connection URL to be passed to the JNDI driver when
+        establishing a connection to the directory.</p>
+      </attribute>
+
+      <attribute name="contextFactory" required="false">
+        <p>Fully qualified Java class name of the factory class used
+        to acquire our JNDI <code>InitialContext</code>.  By default,
+        assumes that the standard JNDI LDAP provider will be utilized.</p>
+      </attribute>
+      
+      <attribute name="derefAliases" required="false">
+        <p>A string specifying how aliases are to be dereferenced during
+        search operations. The allowed values are "always", "never",
+        "finding" and "searching". If not specified, "always" is used.</p>
+      </attribute>
+
+      <attribute name="protocol" required="false">
+         <p>A string specifying the security protocol to use. If not given
+         the providers default is used.</p>
+      </attribute>
+
+      <attribute name="roleBase" required="false">
+        <p>The base directory entry for performing role searches. If
+        not specified the top-level element in the directory context
+        will be used.</p>
+      </attribute>
+
+      <attribute name="roleName" required="false">
+        <p>The name of the attribute that contains role names in the
+        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
+        search does not take place, and roles are taken only from the
+        user's entry.</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>
+      </attribute>
+
+      <attribute name="roleSubtree" required="false">
+        <p>Set to <code>true</code> if you want to search the entire
+        subtree of the element specified by the <code>roleBase</code>
+        property for role entries associated with the user. The
+        default value of <code>false</code> causes only the top level
+        to be searched.</p>
+      </attribute>
+
+      <attribute name="userBase" required="false">
+        <p>The base element for user searches performed using the
+        <code>userSearch</code> expression.  Not used if you are using
+        the <code>userPattern</code> expression.</p>
+      </attribute>
+
+      <attribute name="userPassword" required="false">
+        <p>Name of the attribute in the user's entry containing the
+        user's password.  If you specify this value, JNDIRealm will
+        bind to the directory using the values specified by
+        <code>connectionName</code> and
+        <code>connectionPassword</code> properties, and retrieve the
+        corresponding attribute for comparison to the value specified
+        by the user being authenticated.  If you do
+        <strong>not</strong> specify this value, JNDIRealm will
+        attempt a simple bind to the directory using the DN of the
+        user's entry and the password presented by the user, with a
+        successful bind being interpreted as an authenticated
+        user.</p>
+      </attribute>
+
+      <attribute name="userPattern" required="false">
+        <p>Pattern for the distinguished name (DN) of the user's
+        directory entry, with <code>{0}</code> marking where the
+        actual username should be inserted. You can use this property
+        instead of <code>userSearch</code>, <code>userSubtree</code>
+        and <code>userBase</code> when the distinguished name contains
+        the username and is otherwise the same for all users.</p>
+      </attribute>
+
+      <attribute name="userRoleName" required="false">
+        <p>The name of an attribute in the user's directory entry
+        containing zero or more values for the names of roles assigned
+        to this user.  In addition you can use the
+        <code>roleName</code> property to specify the name of an
+        attribute to be retrieved from individual role entries found
+        by searching the directory. If <code>userRoleName</code> is
+        not specified all the roles for a user derive from the role
+        search.</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
+        the actual username should be inserted.  Use this property
+        (along with the <code>userBase</code> and
+        <code>userSubtree</code> properties) instead of
+        <code>userPattern</code> to search the directory for the
+        user's entry.</p>
+      </attribute>
+
+      <attribute name="userSubtree" required="false">
+        <p>Set to <code>true</code> if you want to search the entire
+        subtree of the element specified by the <code>userBase</code>
+        property for the user's entry. The default value of
+        <code>false</code> causes only the top level to be searched.
+        Not used if you are using the <code>userPattern</code>
+        expression.</p>
+      </attribute>
+
+    </attributes>
+
+    <p>See the <a href="../realm-howto.html">Container-Managed Security Guide</a> for more
+    information on setting up container managed security using the
+    JNDI Directory Realm component.</p>
+
+
+    <h3>Memory Based Realm (org.apache.catalina.realm.MemoryRealm)</h3>
+
+    <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
+    collection of Java objects in memory.  This implementation is intended
+    solely to get up and running with container managed security - it is NOT
+    intended for production use.  As such, there are no mechanisms for
+    updating the in-memory collection of users when the content of the
+    underlying data file is changed.</p>
+
+    <p>The Memory Based Realm implementation supports the following
+    additional attributes:</p>
+
+    <attributes>
+
+      <attribute name="pathname" required="false">
+        <p>Absolute or relative (to $CATALINA_HOME) pathname to the XML file
+        containing our user information.  See below for details on the
+        XML element format required.  If no pathname is specified, the
+        default value is <code>conf/tomcat-users.xml</code>.</p>
+      </attribute>
+
+    </attributes>
+
+    <p>The XML document referenced by the <code>pathname</code> attribute must
+    conform to the following requirements:</p>
+    <ul>
+    <li>The root (outer) element must be <code>&lt;tomcat-users&gt;</code>.
+        </li>
+    <li>Each authorized user must be represented by a single XML element
+        <code>&lt;user&gt;</code>, nested inside the root element.</li>
+    <li>Each <code>&lt;user&gt;</code> element must have the following
+        attributes:
+        <ul>
+        <li><strong>name</strong> - Username of this user (must be unique
+            within this file).</li>
+        <li><strong>password</strong> - Password of this user (in
+            clear text).</li>
+        <li><strong>roles</strong> - Comma-delimited list of the role names
+            assigned to this user.</li>
+        </ul></li>
+    </ul>
+
+    <p>See the <a href="../realm-howto.html">Container-Managed Security Guide</a> for more
+    information on setting up container managed security using the
+    Memory Based Realm component.</p>
+
+
+  </subsection>
+
+
+</section>
+
+
+<section name="Nested Components">
+
+  <p>No components may be nested inside a <strong>Realm</strong> element.</p>
+
+</section>
+
+
+<section name="Special Features">
+
+  <p>See <a href="host.html">Single Sign On</a> for information about
+  configuring Single Sign On support for a virtual host.</p>
+
+</section>
+
+
+</body>
+
+
+</document>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/config/resources.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/config/resources.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/config/resources.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,100 @@
+<?xml version="1.0"?>
+<!DOCTYPE document [
+  <!ENTITY project SYSTEM "project.xml">
+]>
+<document url="resources.html">
+
+  &project;
+
+  <properties>
+    <author email="remm at apache.org">Remy Maucherat</author>
+    <title>The Resources Component</title>
+  </properties>
+
+<body>
+
+
+<section name="Introduction">
+
+  <p>The <strong>Resources</strong> element represents the <em>web
+  application static resources</em>, from which classes will be loaded, 
+  HTML, JSP and the other static files will be served. This allows the webapp
+  to reside on various mediums other than the filesystem, like compressed
+  in a WAR file, in a JDBC database, or in a more advanced versioning
+  repository.</p>
+
+  <p>A unified caching engine is provided for all accesses to the webapp
+  resources made by the servlet container and web applications which use the
+  container provided mechanisms to access such resources, such as class laoder
+  access, access through the <code>ServletContext</code> interface, or native
+  access through the <code>DirectoryContext</code> interface.</p>
+
+  <p><strong>Note: Running a webapp with non-filesystem based 
+  Resources implementations is only possible when the webapp does not 
+  rely on direct filesystem access to its own resources, and uses the methods
+  in the ServletContext interface to access them.</strong></p>
+
+  <p>A Resources element MAY be nested inside a 
+  <a href="context.html">Context</a> component.  If it is not included, 
+  a default filesystem based Resources will be created automatically, 
+  which is sufficient for most requirements.</p>
+
+</section>
+
+
+<section name="Attributes">
+
+  <subsection name="Common Attributes">
+
+    <p>All implementations of <strong>Resources</strong>
+    support the following attributes:</p>
+
+    <attributes>
+
+      <attribute name="className" required="false">
+        <p>Java class name of the implementation to use.  This class must
+        implement the <code>javax.naming.directory.DirContext</code> interface.
+        It is recommended for optimal functionality and performance, 
+        but not mandatory, that the class extend 
+        <code>org.apache.naming.resources.BaseDirContext</code>, as well as
+        use the special object types provided in the 
+        <code>org.apache.naming.resources</code> for returned objects.
+        If not specified, the standard value (defined below) will be used.</p>
+      </attribute>
+
+    </attributes>
+
+  </subsection>
+
+
+  <subsection name="Standard Implementation">
+
+    <p>The standard implementation of <strong>Resources</strong> is
+    <strong>org.apache.naming.resources.FileDirContext</strong>, and 
+    is configured by its parent Context element.</p>
+
+  </subsection>
+
+
+</section>
+
+
+<section name="Nested Components">
+
+  <p>No components may be nested inside a <strong>Resources</strong> element.</p>
+
+</section>
+
+
+<section name="Special Features">
+
+  <p>No special features are associated with a <strong>Resources</strong>
+  element.</p>
+
+</section>
+
+
+</body>
+
+
+</document>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/config/server.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/config/server.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/config/server.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,97 @@
+<?xml version="1.0"?>
+<!DOCTYPE document [
+  <!ENTITY project SYSTEM "project.xml">
+]>
+<document url="server.html">
+
+  &project;
+
+  <properties>
+    <author email="craigmcc at apache.org">Craig R. McClanahan</author>
+    <title>The Server Component</title>
+  </properties>
+
+<body>
+
+
+<section name="Introduction">
+
+  <p>A <strong>Server</strong> element represents the entire Catalina
+  servlet container.  Therefore, it must be the single outermost element
+  in the <code>conf/server.xml</code> configuration file.  Its attributes
+  represent the characteristics of the servlet container as a whole.</p>
+
+</section>
+
+
+<section name="Attributes">
+
+  <subsection name="Common Attributes">
+
+  <p>All implementations of <strong>Server</strong>
+  support the following attributes:</p>
+
+  <attributes>
+
+    <attribute name="className" required="false">
+      <p>Java class name of the implementation to use.  This class must
+      implement the <code>org.apache.catalina.Server</code> interface.
+      If no class name is specified, the standard implementation will
+      be used.</p>
+    </attribute>
+
+    <attribute name="port" required="true">
+      <p>The TCP/IP port number on which this server waits for a shutdown
+      command.  This connection must be initiated from the same server
+      computer that is running this instance of Tomcat.</p>
+    </attribute>
+
+    <attribute name="shutdown" required="true">
+      <p>The command string that must be received via a TCP/IP connection
+      to the specified port number, in order to shut down Tomcat.</p>
+    </attribute>
+
+  </attributes>
+
+  </subsection>
+
+  <subsection name="Standard Implementation">
+
+  <p>The standard implementation of <strong>Server</strong> is
+  <strong>org.apache.catalina.core.StandardServer</strong>.
+  It supports the following additional attributes (in addition to the
+  common attributes listed above):</p>
+
+  <attributes>
+  </attributes>
+
+  </subsection>
+
+</section>
+
+
+<section name="Nested Components">
+
+  <p>The following components may be nested inside a <strong>Server</strong>
+  element:</p>
+  <ul>
+  <li><a href="service.html"><strong>Service</strong></a> - 
+      One or more service element.</li>
+  <li><a href="globalresources.html"><strong>GlobalNamingResources</strong></a> - 
+      Configure the JNDI global resources for the server.</li>
+  </ul>
+
+</section>
+
+
+<section name="Special Features">
+
+  <p>There are no special features associated with a <strong>Server</strong>.
+  </p>
+
+</section>
+
+
+</body>
+
+</document>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/config/service.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/config/service.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/config/service.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,91 @@
+<?xml version="1.0"?>
+<!DOCTYPE document [
+  <!ENTITY project SYSTEM "project.xml">
+]>
+<document url="service.html">
+
+  &project;
+
+  <properties>
+    <author email="craigmcc at apache.org">Craig R. McClanahan</author>
+    <title>The Service Component</title>
+  </properties>
+
+<body>
+
+
+<section name="Introduction">
+
+  <p>A <strong>Service</strong> element represents the combination of one or
+  more <strong>Connector</strong> components that share a single
+  <a href="engine.html">Engine</a> component for processing incoming
+  requests.  One or more <strong>Service</strong> elements may be nested
+  inside a <a href="server.html">Server</a> element.</p>
+
+</section>
+
+
+<section name="Attributes">
+
+  <subsection name="Common Attributes">
+
+  <p>All implementations of <strong>Service</strong>
+  support the following attributes:</p>
+
+  <attributes>
+
+    <attribute name="className" required="false">
+      <p>Java class name of the implementation to use.  This class must
+      implement the <code>org.apache.catalina.Service</code> interface.
+      If no class name is specified, the standard implementation will
+      be used.</p>
+    </attribute>
+
+    <attribute name="name" required="true">
+      <p>The display name of this <strong>Service</strong>, which will
+      be included in log messages if you utilize standard Catalina
+      components.  The name of each <strong>Service</strong> that is
+      associated with a particular <a href="server.html">Server</a>
+      must be unique.</p>
+    </attribute>
+
+  </attributes>
+
+  </subsection>
+
+  <subsection name="Standard Implementation">
+
+  <p>The standard implementation of <strong>Service</strong> is
+  <strong>org.apache.catalina.core.StandardService</strong>.
+  It supports the following additional attributes (in addition to the
+  common attributes listed above):</p>
+
+  <attributes>
+
+  </attributes>
+
+  </subsection>
+
+</section>
+
+
+<section name="Nested Components">
+
+  <p>The only components that may be nested inside a <strong>Service</strong>
+  element are one or more <strong>Connector</strong> elements,
+  followed by exactly one <a href="engine.html">Engine</a> element.</p>
+
+</section>
+
+
+<section name="Special Features">
+
+  <p>There are no special features associated with a <strong>Service</strong>.
+  </p>
+
+</section>
+
+
+</body>
+
+</document>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/config/valve.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/config/valve.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/config/valve.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,434 @@
+<?xml version="1.0"?>
+<!DOCTYPE document [
+  <!ENTITY project SYSTEM "project.xml">
+]>
+<document url="valve.html">
+
+  &project;
+
+  <properties>
+    <author email="craigmcc at apache.org">Craig R. McClanahan</author>
+    <title>The Valve Component</title>
+  </properties>
+
+<body>
+
+
+<section name="Introduction">
+
+  <p>A <strong>Valve</strong> element represents a component that will be
+  inserted into the request processing pipeline for the associated
+  Catalina container (<a href="engine.html">Engine</a>,
+  <a href="host.html">Host</a>, or <a href="context.html">Context</a>).
+  Individual Valves have distinct processing capabilities, and are
+  described individually below.</p>
+
+    <blockquote><em>
+    <p>The description below uses the variable name $CATALINA_HOME
+    to refer to the directory into which you have installed Tomcat 5,
+    and is the base directory against which most relative paths are
+    resolved.  However, if you have configured Tomcat 5 for multiple
+    instances by setting a CATALINA_BASE directory, you should use
+    $CATALINA_BASE instead of $CATALINA_HOME for each of these
+    references.</p>
+    </em></blockquote>
+
+</section>
+
+
+<section name="Access Log Valve">
+
+  <subsection name="Introduction">
+
+    <p>The <strong>Access Log Valve</strong> creates log files in the same
+    format as those created by standard web servers.  These logs can later
+    be analyzed by standard log analysis tools to track page hit counts,
+    user session activity, and so on.  The files produces by this <code>Valve</code>
+    are rolled over nightly at midnight.  This <code>Valve</code>
+    may be associated with any Catalina container (<code>Context</code>,
+    <code>Host</code>, or <code>Engine</code>), and
+    will record ALL requests processed by that container.</p>
+
+  </subsection>
+
+  <subsection name="Attributes">
+
+    <p>The <strong>Access Log Valve</strong> supports the following
+    configuration attributes:</p>
+
+    <attributes>
+
+      <attribute name="className" required="true">
+        <p>Java class name of the implementation to use.  This MUST be set to
+        <strong>org.apache.catalina.valves.AccessLogValve</strong> to use the
+        default access log valve. To use a more optimized access log valve
+        designed for production use, you MUST set this attribute to 
+        <strong>org.apache.catalina.valves.FastCommonAccessLogValve</strong>.
+        In this case, only the <code>common</code> and <code>combined</code>
+        patterns are supported.</p>
+      </attribute>
+
+      <attribute name="directory" required="false">
+        <p>Absolute or relative pathname of a directory in which log files
+        created by this valve will be placed.  If a relative path is
+        specified, it is interpreted as relative to $CATALINA_HOME.  If
+        no directory attribute is specified, the default value is "logs"
+        (relative to $CATALINA_HOME).</p>
+      </attribute>
+
+      <attribute name="pattern" required="false">
+        <p>A formatting layout identifying the various information fields
+        from the request and response to be logged, or the word
+        <code>common</code> or <code>combined</code> to select a
+        standard format.  See below for more information on configuring
+        this attribute. Note that the optimized access does only support
+        <code>common</code> and <code>combined</code> as the value for this
+        attribute.</p>
+      </attribute>
+
+      <attribute name="prefix" required="false">
+        <p>The prefix added to the start of each log file's name.  If not
+        specified, the default value is "access_log.".  To specify no prefix,
+        use a zero-length string.</p>
+      </attribute>
+
+      <attribute name="resolveHosts" required="false">
+        <p>Set to <code>true</code> to convert the IP address of the remote
+        host into the corresponding host name via a DNS lookup.  Set to
+        <code>false</code> to skip this lookup, and report the remote IP
+        address instead.</p>
+      </attribute>
+
+      <attribute name="suffix" required="false">
+        <p>The suffix added to the end of each log file's name.  If not
+        specified, the default value is "".  To specify no suffix,
+        use a zero-length string.</p>
+      </attribute>
+
+      <attribute name="rotatable" required="false">
+        <p>Deafult true. Flag to determine if log rotation should occur.
+           If set to false, then this file is never rotated and
+           <tt>fileDateFormat</tt> is ignored. Use with caution!
+        </p>
+      </attribute>
+
+      <attribute name="condition" required="false">
+        <p>Turns on conditional logging. If set, requests will be
+           logged only if <tt>ServletRequest.getAttribute()</tt> is
+           null. For example, if this value is set to
+           <tt>junk</tt>, then a particular request will only be logged
+           if <tt>ServletRequest.getAttribute("junk") == null</tt>.
+           The use of Filters is an easy way to set/unset the attribute
+           in the ServletRequest on many different requests.
+        </p>
+      </attribute>
+
+      <attribute name="fileDateFormat" required="false">
+        <p>Allows a customized date format in the access log file name.
+           The date format also decides how often the file is rotated.
+           If you wish to rotate every hour, then set this value
+           to: <tt>yyyy-MM-dd.HH</tt>
+        </p>
+      </attribute>
+
+    </attributes>
+
+    <p>Values for the <code>pattern</code> attribute are made up of literal
+    text strings, combined with pattern identifiers prefixed by the "%"
+    character to cause replacement by the corresponding variable value from
+    the current request and response.  The following pattern codes are
+    supported:</p>
+    <ul>
+    <li><b>%a</b> - Remote IP address</li>
+    <li><b>%A</b> - Local IP address</li>
+    <li><b>%b</b> - Bytes sent, excluding HTTP headers, or '-' if zero</li>
+    <li><b>%B</b> - Bytes sent, excluding HTTP headers</li>
+    <li><b>%h</b> - Remote host name (or IP address if
+        <code>resolveHosts</code> is false)</li>
+    <li><b>%H</b> - Request protocol</li>
+    <li><b>%l</b> - Remote logical username from identd (always returns
+        '-')</li>
+    <li><b>%m</b> - Request method (GET, POST, etc.)</li>
+    <li><b>%p</b> - Local port on which this request was received</li>
+    <li><b>%q</b> - Query string (prepended with a '?' if it exists)</li>
+    <li><b>%r</b> - First line of the request (method and request URI)</li>
+    <li><b>%s</b> - HTTP status code of the response</li>
+    <li><b>%S</b> - User session ID</li>
+    <li><b>%t</b> - Date and time, in Common Log Format</li>
+    <li><b>%u</b> - Remote user that was authenticated (if any), else '-'</li>
+    <li><b>%U</b> - Requested URL path</li>
+    <li><b>%v</b> - Local server name</li>
+    <li><b>%D</b> - Time taken to process the request, in millis</li>
+    <li><b>%T</b> - Time taken to process the request, in seconds</li>
+    </ul>
+
+    <p>
+    There is also support to write information from the cookie, incoming
+    header, the Session or something else in the ServletRequest.
+    It is modeled after the apache syntax:
+    <ul>
+    <li><b><code>%{xxx}i</code></b> for incoming headers</li>
+    <li><b><code>%{xxx}c</code></b> for a specific cookie</li>
+    <li><b><code>%{xxx}r</code></b> xxx is an attribute in the ServletRequest</li>
+    <li><b><code>%{xxx}s</code></b> xxx is an attribute in the HttpSession</li>
+    </ul>
+    </p>
+
+
+    <p>The shorthand pattern name <code>common</code> (which is also the
+    default) corresponds to <strong>%h %l %u %t "%r" %s %b"</strong>.</p>
+
+    <p>The shorthand pattern name <code>combined</code> appends the
+    values of the <code>Referer</code> and <code>User-Agent</code> headers,
+    each in double quotes, to the <code>common</code> pattern
+    described in the previous paragraph.</p>
+
+  </subsection>
+
+</section>
+
+
+<section name="Remote Address Filter">
+
+  <subsection name="Introduction">
+
+    <p>The <strong>Remote Address Filter</strong> allows you to compare the
+    IP address of the client that submitted this request against one or more
+    <em>regular expressions</em>, and either allow the request to continue
+    or refuse to process the request from this client.  A Remote Address
+    Filter can be associated with any Catalina container
+    (<a href="engine.html">Engine</a>, <a href="host.html">Host</a>, or
+    <a href="context.html">Context</a>), and must accept any request
+    presented to this container for processing before it will be passed on.</p>
+
+    <p>The syntax for <em>regular expressions</em> is different than that for
+    'standard' wildcard matching. Tomcat uses the
+    <a href="http://jakarta.apache.org/regexp/">Jakarta Regexp</a> library.
+    Please consult the Regexp documentation for details of the expressions
+    supported.</p>
+
+  </subsection>
+
+  <subsection name="Attributes">
+
+    <p>The <strong>Remote Address Filter</strong> supports the following
+    configuration attributes:</p>
+
+    <attributes>
+
+      <attribute name="className" required="true">
+        <p>Java class name of the implementation to use.  This MUST be set to
+        <strong>org.apache.catalina.valves.RemoteAddrValve</strong>.</p>
+      </attribute>
+
+      <attribute name="allow" required="false">
+        <p>A comma-separated list of <em>regular expression</em> patterns
+        that the remote client's IP address is compared to.  If this attribute
+        is specified, the remote address MUST match for this request to be
+        accepted.  If this attribute is not specified, all requests will be
+        accepted UNLESS the remote address matches a <code>deny</code>
+        pattern.</p>
+      </attribute>
+
+      <attribute name="deny" required="false">
+        <p>A comma-separated list of <em>regular expression</em> patterns
+        that the remote client's IP address is compared to.  If this attribute
+        is specified, the remote address MUST NOT match for this request to be
+        accepted.  If this attribute is not specified, request acceptance is
+        governed solely by the <code>accept</code> attribute.</p>
+      </attribute>
+
+    </attributes>
+
+  </subsection>
+
+</section>
+
+
+<section name="Remote Host Filter">
+
+  <subsection name="Introduction">
+
+    <p>The <strong>Remote Host Filter</strong> allows you to compare the
+    hostname of the client that submitted this request against one or more
+    <em>regular expressions</em>, and either allow the request to continue
+    or refuse to process the request from this client.  A Remote Host
+    Filter can be associated with any Catalina container
+    (<a href="engine.html">Engine</a>, <a href="host.html">Host</a>, or
+    <a href="context.html">Context</a>), and must accept any request
+    presented to this container for processing before it will be passed on.</p>
+
+    <p>The syntax for <em>regular expressions</em> is different than that for
+    'standard' wildcard matching. Tomcat uses the
+    <a href="http://jakarta.apache.org/regexp/">Jakarta Regexp</a> library.
+    Please consult the Regexp documentation for details of the expressions
+    supported.</p>
+
+  </subsection>
+
+  <subsection name="Attributes">
+
+    <p>The <strong>Remote Host Filter</strong> supports the following
+    configuration attributes:</p>
+
+    <attributes>
+
+      <attribute name="className" required="true">
+        <p>Java class name of the implementation to use.  This MUST be set to
+        <strong>org.apache.catalina.valves.RemoteHostValve</strong>.</p>
+      </attribute>
+
+      <attribute name="allow" required="false">
+        <p>A comma-separated list of <em>regular expression</em> patterns
+        that the remote client's hostname is compared to.  If this attribute
+        is specified, the remote hostname MUST match for this request to be
+        accepted.  If this attribute is not specified, all requests will be
+        accepted UNLESS the remote hostname matches a <code>deny</code>
+        pattern.</p>
+      </attribute>
+
+      <attribute name="deny" required="false">
+        <p>A comma-separated list of <em>regular expression</em> patterns
+        that the remote client's hostname is compared to.  If this attribute
+        is specified, the remote hostname MUST NOT match for this request to be
+        accepted.  If this attribute is not specified, request acceptance is
+        governed solely by the <code>accept</code> attribute.</p>
+      </attribute>
+
+    </attributes>
+
+  </subsection>
+
+</section>
+
+
+<section name="Request Dumper Valve">
+
+
+  <subsection name="Introduction">
+
+    <p>The <em>Request Dumper Valve</em> is a useful tool in debugging
+    interactions with a client application (or browser) that is sending
+    HTTP requests to your Tomcat-based server.  When configured, it causes
+    details about each request processed by its associated <code>Engine</code>, 
+    <code>Host</code>, or <code>Context</code> to be logged according to 
+    the logging configuration for that container.</p>
+
+    <p><strong>WARNING: Using this valve has side-effects.</strong>  The
+    output from this valve includes any parameters included with the request.
+    The parameters will be decoded using the default platform encoding. Any
+    subsequent calls to <code>request.setCharacterEncoding()</code> within
+    the web application will have no effect.</p>
+
+  </subsection>
+
+
+  <subsection name="Attributes">
+
+    <p>The <strong>Request Dumper Valve</strong> supports the following
+    configuration attributes:</p>
+
+    <attributes>
+
+      <attribute name="className" required="true">
+        <p>Java class name of the implementation to use.  This MUST be set to
+        <strong>org.apache.catalina.valves.RequestDumperValve</strong>.</p>
+      </attribute>
+
+    </attributes>
+
+  </subsection>
+
+
+</section>
+
+
+<section name="Single Sign On Valve">
+
+  <subsection name="Introduction">
+
+    <p>The <em>Single Sign On Vale</em> is utilized when you wish to give users
+    the ability to sign on to any one of the web applications associated with
+    your virtual host, and then have their identity recognized by all other
+    web applications on the same virtual host.</p>
+
+    <p>See the <a href="host.html#Single Sign On">Single Sign On</a> special
+    feature on the <strong>Host</strong> element for more information.</p>
+
+  </subsection>
+
+
+  <subsection name="Attributes">
+
+    <p>The <strong>Single Sign On</strong> Valve supports the following
+    configuration attributes:</p>
+
+    <attributes>
+
+      <attribute name="className" required="true">
+        <p>Java class name of the implementation to use.  This MUST be set to
+        <strong>org.apache.catalina.authenticator.SingleSignOn</strong>.</p>
+      </attribute>
+
+      <attribute name="requireReauthentication" required="false">
+        <p>Default false. Flag to determine whether each request needs to be 
+        reauthenticated to the security <strong>Realm</strong>. If "true", this
+        Valve uses cached security credentials (username and password) to
+        reauthenticate to the <strong>Realm</strong> each request associated 
+        with an SSO session.  If "false", the Valve can itself authenticate 
+        requests based on the presence of a valid SSO cookie, without 
+        rechecking with the <strong>Realm</strong>.</p>
+      </attribute>
+ 
+
+    </attributes>
+
+  </subsection>
+
+
+</section>
+
+
+<section name="Form Authenticator Valve">
+
+  <subsection name="Introduction">
+
+    <p>The <strong>Form Authenticator Valve</strong> is automatically added to
+    any <a href="context.html">Context</a> that is configured to use FORM
+    authentication.</p>
+
+    <p>If any non-default settings are required, the valve may be configured
+    within <a href="context.html">Context</a> element with the required
+    values.</p>
+
+  </subsection>
+
+  <subsection name="Attributes">
+
+    <p>The <strong>Form Authenticator Valve</strong> supports the following
+    configuration attributes:</p>
+
+    <attributes>
+
+      <attribute name="className" required="true">
+        <p>Java class name of the implementation to use.  This MUST be set to
+        <strong>org.apache.catalina.authenticator.FormAuthenticator</strong>.</p>
+      </attribute>
+
+      <attribute name="characterEncoding" required="false">
+        <p>Character encoding to use to read the username and password parameters
+        from the request. If not set, the encoding of the request body will be
+        used.</p>
+      </attribute>
+
+    </attributes>
+
+  </subsection>
+
+</section>
+
+
+</body>
+
+
+</document>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/connectors.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/connectors.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/connectors.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,61 @@
+<?xml version="1.0"?>
+<!DOCTYPE document [
+  <!ENTITY project SYSTEM "project.xml">
+]>
+<document url="connectors.html">
+
+    &project;
+
+    <properties>
+        <author email="remm at apache.org">Remy Maucherat</author>
+        <title>Connectors How To</title>
+    </properties>
+
+<body>
+
+<section name="Introduction">
+
+<p>Choosing a connector to use with Tomcat can be difficult. This page will
+list the connectors which are supported with this Tomcat release, and will
+hopefully help you make the right choice according to your needs.</p>
+
+</section>
+
+<section name="HTTP">
+
+<p>The HTTP connector is setup by default with Tomcat, and is ready to use. This
+connector features the lowest latency and best overall performance.</p>
+
+<p>For clustering, a HTTP load balancer <b>with support for web sessions stickiness</b>
+must be installed to direct the traffic to the Tomcat servers. Tomcat supports mod_proxy
+(on Apache HTTP Server 2.x, and included by default in Apache HTTP Server 2.2) as the load balancer. 
+It should be noted that the performance of HTTP proxying is usually lower than the 
+performance of AJP, so AJP clustering is often preferable.</p>
+
+</section>
+
+<section name="AJP">
+
+<p>When using a single server, the performance when using a native webserver in 
+front of the Tomcat instance is most of the time significantly worse than a
+standalone Tomcat with its default HTTP connector, even if a large part of the web
+application is made of static files. If integration with the native webserver is 
+needed for any reason, an AJP connector will provide faster performance than 
+proxied HTTP. AJP clustering is the most efficient from the Tomcat perspective. 
+It is otherwise functionally equivalent to HTTP clustering.</p>
+
+<p>The native connectors supported with this Tomcat release are:
+<ul>
+<li>JK 1.2.x with any of the supported servers</li>
+<li>mod_proxy on Apache HTTP Server 2.x (included by default in Apache HTTP Server 2.2), 
+with AJP enabled</li>
+</ul>
+</p>
+
+<p><b>Other native connectors supporting AJP may work, but are no longer supported.</b></p>
+
+</section>
+
+</body>
+
+</document>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/default-servlet.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/default-servlet.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/default-servlet.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,298 @@
+<?xml version="1.0"?>
+<!DOCTYPE document [
+  <!ENTITY project SYSTEM "project.xml">
+]>
+<document url="default-servlet.html">
+
+    &project;
+
+    <properties>
+        <author email="funkman at apache.org">Tim Funk</author>
+        <title>Default Servlet Reference</title>
+    </properties>
+
+<body>
+
+<section name="Introduction">
+
+This discusses different ways to manipulate the default servlet. Topics are
+<ul>
+  <li><a href="#what">What is the DefaultServlet?</a></li>
+  <li><a href="#where">Where is it declared?</a></li>
+  <li><a href="#change">What can I change?</a></li>
+  <li><a href="#dir">How do I customize directory listings?</a></li>
+  <li><a href="#secure">How do I secure directory listings?</a></li>
+
+</ul>
+
+</section>
+
+<section name="What is the DefaultServlet">
+<a name="what"></a>
+The default servlet is the servlet which serves static resources as well
+as serves the directory listings (if directory listings are enabled).
+
+</section>
+
+<section name="Where is it declared?">
+<a name="where"></a>
+It is declared globally in <i>$CATALINA_HOME/conf/web.xml</i>.
+By default here is it's declaration:
+<source>
+    &lt;servlet&gt;
+        &lt;servlet-name&gt;default&lt;/servlet-name&gt;
+        &lt;servlet-class&gt;
+          org.apache.catalina.servlets.DefaultServlet
+        &lt;/servlet-class&gt;
+        &lt;init-param&gt;
+            &lt;param-name&gt;debug&lt;/param-name&gt;
+            &lt;param-value&gt;0&lt;/param-value&gt;
+        &lt;/init-param&gt;
+        &lt;init-param&gt;
+            &lt;param-name&gt;listings&lt;/param-name&gt;
+            &lt;param-value&gt;true&lt;/param-value&gt;
+        &lt;/init-param&gt;
+        &lt;load-on-startup&gt;1&lt;/load-on-startup&gt;
+    &lt;/servlet&gt;
+
+...
+
+    &lt;servlet-mapping&gt;
+        &lt;servlet-name&gt;default&lt;/servlet-name&gt;
+        &lt;url-pattern&gt;/&lt;/url-pattern&gt;
+    &lt;/servlet-mapping&gt;
+
+</source>
+
+So by default, the default servlet is loaded at webapp startup and
+directory listings are enabled and debugging is turned off.
+</section>
+
+<section name="What can I change?">
+<a name="change"></a>
+The DefaultServlet allows the following initParamters:
+
+<table border="1">
+  <tr>
+    <th valign='top'>debug</th>
+    <td valign='top'>
+        Debugging level. It is not very useful unless you are a tomcat
+        developer. As
+        of this writing, useful values are 0, 1, 11, 1000.
+    </td>
+  </tr>
+  <tr>
+    <th valign='top'>listings</th>
+    <td valign='top'>
+        If no welcome file is present, can a directory listing be
+        shown?
+        value may be <b>true</b> or <b>false</b>
+        <br />
+        Welcome files are part of the servlet api.
+        <br />
+        <b>WARNING:</b> Listings of directories containing many entries are
+        expensive. Multiple requests for large directory listings can consume
+        significant proportions of server resources.
+    </td>
+  </tr>
+  <tr>
+    <th valign='top'>readmeFile</th>
+    <td valign='top'>
+        If a directory listing is presented, a readme file may also
+        be presented with the listing. This file is inserted as is
+        so it may contain HTML. default value is null
+    </td>
+  </tr>
+  <tr>
+    <th valign='top'>globalXsltFile</th>
+    <td valign='top'>
+        If you wish to customize your directory listing, you
+        can use an XSL transformation. This value is an absolute
+        file name which be used for all direcotory listings.
+        This can be disabled by per webapp by also declaring the
+        default servlet in your local webapp's web.xml. The format
+        of the xml is shown below.
+    </td>
+  </tr>
+  <tr>
+    <th valign='top'>localXsltFile</th>
+    <td valign='top'>
+        You may also customize your directory listing by directory by
+        configuring <code>localXsltFile</code>. This should be a relative
+        file name in the directory where the listing will take place.
+        This overrides <code>globalXsltFile</code>. If this value
+        is present but a file does not exist, then
+        <code>globalXsltFile</code> will be used. If
+        <code>globalXsltFile</code> does not exist, then the default
+        directory listing will be shown.
+    </td>
+  </tr>
+  <tr>
+    <th valign='top'>input</th>
+    <td valign='top'>
+        Input buffer size (in bytes) when reading
+        resources to be served.  [2048]
+    </td>
+  </tr>
+  <tr>
+    <th valign='top'>output</th>
+    <td valign='top'>
+        Output buffer size (in bytes) when writing
+        resources to be served.  [2048]
+    </td>
+  </tr>
+  <tr>
+    <th valign='top'>readonly</th>
+    <td valign='top'>
+        Is this context "read only", so HTTP commands like PUT and
+        DELETE are rejected?  [true]
+    </td>
+  </tr>
+  <tr>
+    <th valign='top'>fileEncoding</th>
+    <td valign='top'>
+        File encoding to be used when reading static resources.
+        [platform default]
+    </td>
+  </tr>
+  <tr>
+    <th valign='top'>sendfileSize</th>
+    <td valign='top'>
+        If the connector used supports sendfile, this represents the minimal 
+        file size in KB for which sendfile will be used. Use a negative value 
+        to always disable sendfile. [48]
+    </td>
+  </tr>
+
+</table>
+</section>
+
+<section name="How do I customize directory listings?">
+<a name="dir"></a>
+<p>You can override DefaultServlet with you own implementation and use that
+in your web.xml declaration. If you
+can undertand what was just said, we will assume yo can read the code
+to DefaultServlet servlet and make the appropriate adjustments. (If not,
+then that method isn't for you)
+</p>
+<p>
+You can use either  <code>localXsltFile</code> or
+<code>globalXsltFile</code> and DefaultServlet will create
+an xml document and run it through an xsl transformation based
+on the values provided in <code>localXsltFile</code> and
+<code>globalXsltFile</code>. <code>localXsltFile</code> is first
+checked, followed by <code>globalXsltFile</code>, then default
+behaviors takes place.
+</p>
+
+<p>
+Format:
+<source>
+    &lt;listing&gt;
+     &lt;entries&gt;
+      &lt;entry type='file|dir' urlPath='aPath' size='###' date='gmt date'&gt;
+        fileName1
+      &lt;/entry&gt;
+      &lt;entry type='file|dir' urlPath='aPath' size='###' date='gmt date'&gt;
+        fileName2
+      &lt;/entry&gt;
+      ...
+     &lt;/entries&gt;
+     &lt;readme&gt;&lt;/readme&gt;
+    &lt;/listing&gt;
+</source>
+<ul>
+  <li>size will be missing if <code>type='dir'</code></li>
+  <li>Readme is a CDATA entry</li>
+</ul>
+</p>
+The following is a sample xsl file which mimics the default tomcat behavior:
+<source>
+&lt;?xml version="1.0"?&gt;
+
+&lt;xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+  version="1.0"&gt;
+
+  &lt;xsl:output method="xhtml" encoding="iso-8859-1" indent="no"/&gt;
+
+  &lt;xsl:template match="listing"&gt;
+   &lt;html&gt;
+    &lt;head&gt;
+      &lt;title&gt;
+        Sample Directory Listing For
+        &lt;xsl:value-of select="@directory"/&gt;
+      &lt;/title&gt;
+      &lt;style&gt;
+        h1{color : white;background-color : #0086b2;}
+        h3{color : white;background-color : #0086b2;}
+        body{font-family : sans-serif,Arial,Tahoma;
+             color : black;background-color : white;}
+        b{color : white;background-color : #0086b2;}
+        a{color : black;} HR{color : #0086b2;}
+      &lt;/style&gt;
+    &lt;/head&gt;
+    &lt;body&gt;
+      &lt;h1&gt;Sample Directory Listing For
+            &lt;xsl:value-of select="@directory"/&gt;
+      &lt;/h1&gt;
+      &lt;hr size="1" /&gt;
+      &lt;table cellspacing="0"
+                  width="100%"
+            cellpadding="5"
+                  align="center"&gt;
+        &lt;tr&gt;
+          &lt;th align="left"&gt;Filename&lt;/th&gt;
+          &lt;th align="center"&gt;Size&lt;/th&gt;
+          &lt;th align="right"&gt;Last Modified&lt;/th&gt;
+        &lt;/tr&gt;
+        &lt;xsl:apply-templates select="entries"/&gt;
+        &lt;/table&gt;
+      &lt;xsl:apply-templates select="readme"/&gt;
+      &lt;hr size="1" /&gt;
+      &lt;h3&gt;Apache Tomcat/5.0&lt;/h3&gt;
+    &lt;/body&gt;
+   &lt;/html&gt;
+  &lt;/xsl:template&gt;
+
+
+  &lt;xsl:template match="entries"&gt;
+    &lt;xsl:apply-templates select="entry"/&gt;
+  &lt;/xsl:template&gt;
+
+  &lt;xsl:template match="readme"&gt;
+    &lt;hr size="1" /&gt;
+    &lt;pre&gt;&lt;xsl:apply-templates/&gt;&lt;/pre&gt;
+  &lt;/xsl:template&gt;
+
+  &lt;xsl:template match="entry"&gt;
+    &lt;tr&gt;
+      &lt;td align="left"&gt;
+        &lt;xsl:variable name="urlPath" select="@urlPath"/&gt;
+        &lt;a href="{$urlPath}"&gt;
+          &lt;tt&gt;&lt;xsl:apply-templates/&gt;&lt;/tt&gt;
+        &lt;/a&gt;
+      &lt;/td&gt;
+      &lt;td align="right"&gt;
+        &lt;tt&gt;&lt;xsl:value-of select="@size"/&gt;&lt;/tt&gt;
+      &lt;/td&gt;
+      &lt;td align="right"&gt;
+        &lt;tt&gt;&lt;xsl:value-of select="@date"/&gt;&lt;/tt&gt;
+      &lt;/td&gt;
+    &lt;/tr&gt;
+  &lt;/xsl:template&gt;
+
+&lt;/xsl:stylesheet&gt;
+</source>
+
+</section>
+
+<section name="How do I secure directory listings?">
+<a name="secure"></a>
+Use web.xml in each individual webapp. See the security section of the
+Servlet specification.
+
+</section>
+
+</body>
+
+</document>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/deployer-howto.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/deployer-howto.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/deployer-howto.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,330 @@
+<?xml version="1.0"?>
+<!DOCTYPE document [
+  <!ENTITY project SYSTEM "project.xml">
+]>
+<document url="deployer-howto.html">
+
+    &project;
+
+    <properties>
+        <author>Allistair Crossley</author>
+        <title>Tomcat Web Application Deployment</title>
+    </properties>
+
+<body>
+
+    <section name="Table of Contents">
+    <ul>
+        <li><a href="#Introduction">Introduction</a></li>
+        <li><a href="#Installation">Installation</a></li>
+        <li><a href="#A word on Contexts">A word on Contexts</a></li>
+        <li><a href="#Deployment on Tomcat startup">Deployment on Tomcat startup</a></li>
+        <li><a href="#Deploying on a running Tomcat server">Deploying on a running Tomcat server</a></li>
+        <li><a href="#Deploying using the Tomcat Manager">Deploying using the Tomcat Manager</a></li>
+        <li><a href="#Deploying using the Client Deployer Package">Deploying using
+            the Tomcat Client Deployer</a></li>
+    </ul>
+    
+    </section>
+    
+    <section name="Introduction">
+        <p>
+            Deployment is the term used for the process of installing a web
+            application (either a 3rd party WAR or your own custom web application) 
+            into the Tomcat server. 
+        </p>
+        <p>
+            Web application deployment may be accomplished in a number of ways
+            within the Tomcat server.
+            <ul>
+                <li>Statically; the web application is setup before Tomcat is started</li>
+                <li>
+                    Dynamically; in conjunction with the Tomcat Manager web application or 
+                    manipulating already deployed web applications
+                </li>
+            </ul>
+        </p>
+        <p>
+            The Tomcat Manager is a tool that allows URL-based web application
+            deployment features. There is also a tool called the Client Deployer,
+            which is a command shell based script that interacts with the Tomcat
+            Manager but provides additional functionality such as compiling and
+            validating web applications as well as packaging web application into
+            web application resource (WAR) files.
+        </p>
+    </section>
+    
+    <section name="Installation">
+        <p>
+            There is no installation required for static deployment of web
+            applications as this is provided out of the box by Tomcat. Nor is any
+            installation required for deployment functions with the Tomcat Manager, 
+            although some configuration is required as detailed in the 
+            Tomcat Manager manual. An installation is however required if you wish
+            to use the Tomcat Client Deployer (TCD). 
+        </p>   
+        <p>
+            The TCD is not packaged with the Tomcat core 
+            distribution, and must therefore be downloaded separately from 
+            the Downloads area. The download is usually labelled 
+            <i>jakarta-tomcat-5.5.x-deployer</i>.
+        </p>
+        <p>
+            TCD has prerequisites of Apache Ant 1.6.2+ and a Java installation.
+            Your environment should define an ANT_HOME environment value pointing to
+            the root of your Ant installation, and a JAVA_HOME value pointing to
+            your Java installation. Additionally, you should ensure Ant's ant
+            command, and the Java javac compiler command run from the command shell
+            that your operating system provides.
+        </p>
+        <ol>
+            <li>Download the TCD distribution</li>
+            <li>
+                The TCD package need not be extracted into any existing Tomcat
+                installation, it can be extracted to any location.
+            </li>
+            <li>Read Using the <a href="#Deploying using the Client Deployer Package">
+            Tomcat Client Deployer</a></li>
+        </ol>
+    </section>
+        
+    <section name="A word on Contexts">
+        <p>
+            In talking about deployment of web applications, the concept of a
+            <i>Context</i> is required to be understood. A Context is what Tomcat 
+            calls a web application.
+        </p>
+        <p>
+            In order to configure a Context within Tomcat a <i>Context Descriptor</i>
+            is required. A Context Descriptor is simply an XML file that contains
+            Tomcat related configuration for a Context, e.g naming resources or 
+            session manager configuration. In earlier versions of
+            Tomcat the content of a Context Descriptor configuration was often stored within
+            Tomcat's primary configuration file <i>server.xml</i> but this is now
+            discouraged (although it currently still works).
+        </p>
+        <p>        
+            Context Descriptors not only help Tomcat to know how to configure 
+            Contexts but other tools such as the Tomcat Manager and TDC often use 
+            these Context Descriptors to perform their roles properly.
+        </p>
+        <p>
+            The locations for Context Descriptors are;
+            <ol>
+                <li>$CATALINA_HOME/conf/[enginename]/[hostname]/context.xml</li>
+                <li>$CATALINA_HOME/webapps/[webappname]/META-INF/context.xml</li>
+            </ol>
+            If a Context Descriptor is not provided for a Context, Tomcat
+            automatically creates one and places it in (1) with a filename of
+            [webappname].xml although if manually created, the filename need not
+            match the web application name as Tomcat is concerned only with the
+            Context configuration contained within the Context Descriptor file(s).
+        </p>
+    </section>
+    
+    <section name="Deployment on Tomcat startup">
+        <p>
+            If you are not interested in using the Tomcat Manager, or TCD, 
+            then you'll need to deploy your web applications 
+            statically to Tomcat, followed by a Tomcat startup. The location you
+            deploy web applications to for this type of deployment is called the 
+            <code>appBase</code> which is specified per Host. You either copy a
+            so-called <i>exploded web application</i>, i.e non-compressed, to this
+            location, or a compressed web application resource .WAR file.
+        </p>
+        <p>
+            The web applications present in the location specified by the Host's
+            (default Host is "localhost") <code>appBase</code> attribute (default
+            appBase is "$CATALINA_HOME/webapps") will be deployed on Tomcat startup 
+            only if the Host's <code>deployOnStartup</code> attribute is "true".
+        </p>
+        <p>
+            The following deployment sequence will occur on Tomcat startup in that
+            case:
+        </p>
+        <ol>
+            <li>Any Context Descriptors will be deployed first.</li>
+            <li>
+                Exploded web applications not referenced by any Context
+                Descriptor will then be deployed. If they have an associated 
+                .WAR file in the appBase and it is newer than the exploded web application, 
+                the exploded directory will be removed and the webapp will be 
+                redeployed from the .WAR
+            </li>
+            <li>.WAR files will be deployed</li>
+        </ol>
+        <p>
+            Note again that for each deployed web application, a 
+            Context Descriptor will be created <i>unless one exists already</i>.
+        </p>
+    </section>
+    
+    <section name="Deploying on a running Tomcat server">
+        <p>
+            It is possible to deploy web applications to a running Tomcat server.
+        </p>
+        <p>
+            If the Host <code>autoDeploy</code> attribute is "true", the Host will 
+            attempt to deploy and update web applications dynamically, as needed,
+            for example if a new .WAR is dropped into the <code>appBase</code>. 
+            For this to work, the Host needs to have background processing 
+            enabled which is the default configuration.
+        </p>
+        
+        <p>
+            <code>autoDeploy</code> set to "true" and a running Tomcat allows for:
+        </p>
+        <ul>
+            <li>Deployment of .WAR files copied into the Host <code>appBase</code>.</li>
+            <li>
+                Deployment of exploded web applications which are
+                copied into the Host <code>appBase</code>.
+            </li>
+            <li>
+                Re-deployment of a web application which has already been deployed from
+                a .WAR when the new .WAR is provided. In this case the exploded 
+                web application is removed, and the .WAR is expanded again. 
+                Note that the explosion will not occur if the Host is configured 
+                so that .WARs are not exploded with a <code>unpackWARs</code>
+                attribute set to "false", in which case the web application 
+                will be simply redeployed as a compressed archive.
+            </li>
+            <li>
+                Re-deployment of a web application if the /WEB-INF/web.xml file (or any
+                other resource defined as a WatchedResource) is updated.
+            </li>
+            <li>
+                Re-deployment of a web application if the Context Descriptor file from which
+                the web application has been deployed is updated.
+            </li>
+            <li>
+                Re-deployment of a web application if a Context Descriptor file (with a
+                filename corresponding to the Context path of the previously deployed
+                web application) is added to the 
+                <code>$CATALINA_HOME/conf/[enginename]/[hostname]/</code>
+                directory.
+            </li>
+            <li>
+                Undeployment of a web application if its document base (docBase)
+                is deleted. Note that on Windows, this assumes that anti-locking 
+                features (see Context configuration) are enabled, otherwise it is not 
+                possible to delete the resources of a running web application.
+            </li>
+        </ul>
+        <p>
+            Note that web application reloading can also be configured in the loader, in which
+            case loaded classes will be tracked for changes.
+        </p>
+    </section>
+    
+    <section name="Deploying using the Tomcat Manager">
+        <p>
+            The Tomcat Manager is covered in its <a href="manager-howto.html">own manual page</a>. 
+        </p>
+    </section>
+        
+    <section name="Deploying using the Client Deployer Package">
+        <p>
+            Finally, deployment of web application may be achieved using the 
+            Tomcat Client Deployer. This is a package which can be used to 
+            validate, compile, compress to .WAR, and deploy web applications to 
+            production or development Tomcat servers. It should be noted that this feature 
+            uses the Tomcat Manager and as such the target Tomcat server should be
+            running.
+        </p>
+    
+        <p>
+            It is assumed the user will be familar with Apache Ant for using the TCD.
+            Apache Ant is a scripted build tool. The TCD comes pre-packaged with a
+            build script to use. Only a modest understanding of Apache Ant is
+            required (installation as listed earlier in this page, and familiarity
+            with using the operating system command shell and configuring
+            environment variables).
+        </p>
+        
+        <p>
+            The TCD includes Ant tasks, the Jasper page compiler for JSP compilation 
+            before deployment, as well as a task which
+            validates the web application Context Descriptor. The validator task (class
+            <code>org.apache.catalina.ant.ValidatorTask</code>) allows only one parameter:
+            the base path of an exploded web application.
+        </p>
+    
+        <p>
+            The TCD uses an exploded web application as input (see the list of the
+            properties used below). A web application that is programatically 
+            deployed with the deployer may include a Context Desciptor in 
+            <code>/META-INF/context.xml</code>.
+        </p>
+    
+        <p>
+            The TCD includes a ready-to-use Ant script, with the following targets:
+        </p>
+        <ul>
+            <li>
+                <code>compile</code> (default): Compile and validate the web 
+                application. This can be used standalone, and does not need a running
+                Tomcat server. The compiled application will only run on the associated
+                Tomcat 5.5.x server release, and is not guaranteed to work on another
+                Tomcat release, as the code generated by Jasper depends on its runtime
+                component. It should also be noted that this target will also compile
+                automatically any Java source file located in the 
+                <code>/WEB-INF/classes</code> folder of the web application.</li>
+            <li>
+                <code>deploy</code>: Deploy a web application (compiled or not) to 
+                a Tomcat server.
+            </li>
+            <li><code>undeploy</code>: Undeploy a web application</li>
+            <li><code>start</code>: Start web application</li>
+            <li><code>reload</code>: Reload web application</li>
+            <li><code>stop</code>: Stop web application</li>
+        </ul>
+        
+        <p>
+            In order for the deployment to be configured, create a file
+            called <code>deployer.properties</code> in the TCD installation
+            directory root. In this file, add the following name=value pairs per
+            line:
+        </p>
+        
+        <p>
+            Additionally, you will need to ensure that a user has been 
+            setup for the target Tomcat Manager (which TCD uses) otherwise the TCD
+            will not authenticate with the Tomcat Manager and the deployment will
+            fail. To do this, see the Tomcat Manager page.        
+        </p>
+        
+        <ul>
+            <li>
+                <code>build</code>: The build folder used will be, by default, 
+                <code>${build}/webapp/${path}</code>. After the end of the execution
+                of the <code>compile</code> target, the web application .WAR will be
+                located at <code>${build}/webapp/${path}.war</code>.
+            </li>
+            <li>
+                <code>webapp</code>: The directory containing the exploded web application 
+                which will be compiled and validated. By default, the folder is
+                <code>myapp</code>.
+            </li>
+            <li>
+                <code>path</code>: Deployed context path of the web application, 
+                by default <code>/myapp</code>.
+            </li>
+            <li>
+                <code>url</code>: Absolute URL to the Tomcat Manager web application of a 
+                running Tomcat server, which will be used to deploy and undeploy the
+                web application. By default, the deployer will attempt to access 
+                a Tomcat instance running on localhost, at 
+                <code>http://localhost:8080/manager</code>.
+            </li>
+            <li>
+                <code>username</code>: Tomcat Manager username (user should have a role of
+                manager)
+            </li>
+            <li><code>password</code>: Tomcat Manager password.</li>
+        </ul>
+    </section>
+
+</body>
+
+</document>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/developers.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/developers.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/developers.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,60 @@
+<?xml version="1.0"?>
+<!DOCTYPE document [
+  <!ENTITY project SYSTEM "project.xml">
+]>
+<document url="developers.html">
+
+  &project;
+
+  <properties>
+    <author email="remm at apache.org">Remy Maucherat</author>
+    <author email="yoavs at apache.org">Yoav Shapira</author>
+    <title>Tomcat Developers</title>
+  </properties>
+
+<body>
+
+  <section name="Active Developers">
+
+    <p>
+      The list indicates the developers' main areas of interest. Feel free to
+      add to the list :) The developers email addresses are 
+      <code>[login]@apache.org</code>. Please <strong>do not</strong> contact 
+      developers directly for any support issues (please post to the 
+      tomcat-users mailing list instead, or one of the other support 
+      resources; some organizations and individual consultants also offer 
+      for pay Tomcat support, as listed on the 
+      <a href="http://jakarta.apache.org/site/vendors.html">vendors page</a>
+      on the Jakarta website).
+    </p>
+
+    <ul>
+      <li>Amy Roh (amyroh): Catalina, Admin webapp</li>
+      <li>Bill Barker (billbarker): Connectors</li>
+      <li>Costin Manolache (costin): Catalina, Connectors</li>
+      <li>Filip Hanik (fhanik): Clustering, Release Manager</li>
+      <li>Glenn Nielsen (glenn): Catalina, Connectors</li>
+      <li>Henri Gomez (hgomez): Connectors</li>
+      <li>Jan Luehe (luehe): Jasper</li>
+      <li>Jean-Francois Arcand (jfarcand): Catalina</li>
+      <li>Jean-Frederic Clere (jfclere): Connectors</li>
+      <li>Kin-Man Chung (kinman): Jasper</li>
+      <li>Mark Thomas (markt): CGI, SSI, WebDAV, bug fixing</li>
+      <li>Mladen Turk (mturk): Connectors</li>
+      <li>Peter Rossbach (pero): Catalina, Clustering, JMX</li>
+      <li>Rainer Jung (rjung): Catalina, Clustering, Connectors</li>
+      <li>Remy Maucherat (remm): Catalina, Connectors, Docs</li>
+      <li>Tim Funk (funkman): Catalina, Docs</li>
+      <li>Yoav Shapira (yoavs): Docs, JMX, Catalina, balancer</li>
+    </ul>
+
+  </section>
+
+  <section name="Retired Developers">
+
+
+
+  </section>
+
+</body>
+</document>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/funcspecs/fs-admin-apps.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/funcspecs/fs-admin-apps.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/funcspecs/fs-admin-apps.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,278 @@
+<?xml version="1.0"?>
+<!DOCTYPE document [
+  <!ENTITY project SYSTEM "project.xml">
+]>
+<document url="fs-admin-apps.html">
+
+  &project;
+
+  <properties>
+    <author email="craigmcc at apache.org">Craig McClanahan</author>
+    <title>Administrative Apps - Overall Requirements</title>
+    <revision>$Id: fs-admin-apps.xml 301989 2003-06-25 01:38:16Z yoavs $</revision>
+  </properties>
+
+<body>
+
+
+<section name="Overview">
+
+
+  <subsection name="Introduction">
+
+    <p>The purpose of this specification is to define high level requirements
+    for administrative applications that can be used to manage the operation
+    of a running Tomcat 5 container.  A variety of <em>Access Methods</em>
+    to the supported administrative functionality shall be supported, to
+    meet varying requirements:</p>
+    <ul>
+    <li><em>As A Scriptable Web Application</em> - The existing
+        <code>Manager</code> web application provides a simple HTTP-based
+        interface for managing Tomcat through commands that are expressed
+        entirely through a request URI.  This is useful in environments
+        where you wish to script administrative commands with tools that
+        can generate HTTP transactions.</li>
+    <li><em>As An HTML-Based Web Application</em> - Use an HTML presentation
+        to provide a GUI-like user interface for humans to interact with the
+        administrative capabilities.</li>
+    <li><em>As SOAP-Based Web Services</em> - The operational commands to
+        administer Tomcat are made available as web services that utilize
+        SOAP message formats.</li>
+    <li><em>As Java Management Extensions (JMX) Commands</em> - The operational
+        commands to administer Tomcat are made available through JMX APIs,
+        for integration into management consoles that utilize them.</li>
+    <li><em>Other Remote Access APIs</em> - Other remote access APIs, such
+        as JINI, RMI, and CORBA can also be utilized to access administrative
+        capabilities.</li>
+    </ul>
+
+    <p>Underlying all of the access methods described above, it is assumed
+    that the actual operations are performed either directly on the
+    corresponding Catalina components (such as calling the
+    <code>Deployer.deploy()</code> method to deploy a new web application),
+    or through a "business logic" layer that can be shared across all of the
+    access methods.  This approach minimizes the cost of adding new
+    administrative capabilities later -- it is only necessary to add the
+    corresponding business logic function, and then write adapters to it for
+    all desired access methods.</p>
+
+    <p>The current status of this functional specification is
+    <strong>PROPOSED</strong>.  It has not yet been discussed and
+    agreed to on the TOMCAT-DEV mailing list.</p>
+
+  </subsection>
+
+
+  <subsection name="External Specifications">
+
+    <p>The implementation of this functionality depends on the following
+    external specifications:</p>
+    <ul>
+    <li><a href="http://java.sun.com/products/jdk/idl/index.html">Java
+        IDL</a> (for CORBA, included in the JDK)</li>
+    <li><a href="http://java.sun.com/products/JavaManagement/index.html">
+        Java Management Extensions</a></li>
+    <li><a href="http://java.sun.com/products/rmi/index.html">Remote
+        Method Invocation</a> (Included in the JDK)</li>
+    </ul>
+
+  </subsection>
+
+
+  <subsection name="Implementation Requirements">
+
+    <p>The implementation of this functionality shall conform to the
+    following requirements:</p>
+    <ul>
+    <li>To the maximum extent feasible, all administrative functions,
+        and the access methods that support them, shall run portably
+        on all platforms where Tomcat 5 itself runs.</li>
+    <li>In a default Tomcat distribution, all administrative capabilities
+        shall be disabled.  It shall be necessary for a system
+        administrator to specifically enable the desired access methods
+        (such as by adding a username/password with a specific role to
+        the Tomcat user's database.</li>
+    <li>Administrative functions shall be realized as direct calls to
+        corresponding Catalina APIs, or through a business logic layer
+        that is independent of the access method used to initiate it.</li>
+    <li>The common business logic components shall be implemented in
+        package <code>org.apache.catalina.admin</code>.</li>
+    <li>The common business logic components shall be built as part of the
+        standard Catalina build process, and made visible in the
+        Catalina class loader.</li>
+    <li>The Java components required for each access method shall be
+        implemented in subpackages of <code>org.apache.catalina.admin</code>.
+        </li>
+    <li>The build scripts should treat each access method as optional,
+        so that it will be built only if the corresponding required
+        APIs are present at build time.</li>
+    <li>It shall be possible to save the configured state of the running
+        Tomcat container such that this state can be reproduced when the
+        container is shut down and restarted.</li>
+    <li>Adminstrative commands to start up and shut down the overall
+        Tomcat container are <strong>out of scope</strong> for the
+        purposes of these applications.  It is assumed that other
+        (usually platform-specific) mechanisms will be used for container
+        startup and shutdown.</li>
+    </ul>
+
+  </subsection>
+
+
+</section>
+
+
+<section name="Dependencies">
+
+
+  <subsection name="Environmental Dependencies">
+
+    <p>The following environmental dependencies must be met in order for
+    administrative applications to operate correctly:</p>
+    <ul>
+    <li>For access methods that require creation of server sockets, the
+        appropriate ports must be configured and available.</li>
+    </ul>
+
+  </subsection>
+
+
+  <subsection name="Container Dependencies">
+
+    <p>Correct operation of administrative applications depends on the
+       following specific features of the surrounding container:</p>
+    <ul>
+    <li>To the maximum extent feasible, Catalina components that offer
+        direct administrative APIs and property setters shall support
+        "live" changes to their operation, without requiring a container
+        restart.</li>
+    </ul>
+
+  </subsection>
+
+
+  <subsection name="External Technologies">
+
+    <p>The availability of the following technologies can be assumed
+    for the implementation and operation of the various access methods
+    and the corresponding administrative business logic:</p>
+    <ul>
+    <li><a href="http://java.sun.com/j2se/">Java 2 Standard Edition</a>
+        (Version 1.2 or later)</li>
+    <li><a href="http://www.jcp.org/jsr/detail/154.jsp">Servlet 2.4</a>
+        (supported natively by Tomcat 5)</li>
+    <li><a href="http://www.jcp.org/jsr/detail/152.jsp">JavaServer Pages 2.0</a>
+        (supported natively by Tomcat 5)</li>
+    <li><a href="http://jakarta.apache.org/taglibs/doc/standard-doc/intro.html">JavaServer Pages Standard Tag Library 1.0 (Jakarta Taglibs-Standard 1.0.3)</a></li>
+    <li><a href="http://jakarta.apache.org/struts/">Struts Framework</a>
+        (Version 1.0) - MVC Framework for Web Applications</li>
+    <li><strong>TO BE DETERMINED</strong> - Application for hosting SOAP
+        based web services</li>
+    </ul>
+
+  </subsection>
+
+
+</section>
+
+
+<section name="Functionality">
+
+
+  <subsection name="Properties of Administered Objects">
+
+  <p>Functional requirements for administrative applications are specified
+  in terms of <em>Administered Objects</em>, whose definitions and detailed
+  properties are listed <a href="fs-admin-objects.html">here</a>.  In general,
+  Administered Objects correspond to components in the Catalina architecture,
+  but these objects are defined separately here for the following reasons:</p>
+  <ul>
+  <li>It is possible that the administrative applications do not expose
+      every possible configurable facet of the underlying components.</li>
+  <li>In some cases, an Administered Object (from the perspective of an
+      administrative operation) is realized by more than one Catalina
+      component, at a finer-grained level of detail.</li>
+  <li>It is necessary to represent the configuration information for a
+      component separately from the component itself (for instance, in
+      order to store that configuration information for later use).</li>
+  <li>It is necessary to represent configuration information (such as
+      a Default Context) when there is no corresponding component instance.
+      </li>
+  <li>Administered Objects, when realized as Java classes, will include
+      methods for administrative operations that have no correspondence
+      to operations performed by the corresponding actual components.</li>
+  </ul>
+
+  <p>It is assumed that the reader is familiar with the overall component
+  architecture of Catalina.  For further information, see the corresponding
+  Developer Documentation.  To distinguish names that are used as both
+  <em>Administered Objects</em> and <code>Components</code>, different
+  font presentations are utilized.  Default values for many properties
+  are listed in [square brackets].</p>
+
+  </subsection>
+
+
+  <subsection name="Supported Administrative Operations">
+
+  <p>The administrative operations that are available are described in terms
+  of the corresponding Administered Objects (as defined above), in a manner
+  that is independent of the access method by which these operations are
+  requested.  In general, such operations are relevant only in the context
+  of a particular Administered Object (and will most likely be realized as
+  method calls on the corresponding Administered Object classes), so they
+  are organized based on the currently "focused" administered object.
+  The available Supported Operations are documented
+  <a href="fs-admin-opers.html">here</a>.</p>
+
+  </subsection>
+
+
+  <subsection name="Access Method Specific Requirements">
+
+  <h5>Scriptable Web Application</h5>
+
+  <p>An appropriate subset of the administrative operations described above
+  shall be implemented as commands that can be performed by the "Manager"
+  web application.  <strong>FIXME</strong> - Enumerate them.</p>
+
+  <p>In addition, this web application shall conform to the following
+  requirements:</p>
+  <ul>
+  <li>All request URIs shall be protected by a security constraint that
+      requires security role <code>manager</code> for processing.</li>
+  <li>The default user database shall <strong>not</strong> contain any
+      user that has been assigned the role <code>manager</code>.</li>
+  </ul>
+
+  <h5>HTML-Based Web Application</h5>
+
+  <p>The entire suite of administrative operations described above shall be
+  made available through a web application designed for human interaction.
+  In addition, this web application shall conform to the following
+  requirements:</p>
+  <ul>
+  <li>Must be implemented using servlet, JSP, and MVC framework technologies
+      described under "External Technologies", above.</li>
+  <li>Prompts and error messages must be internationalizable to multiple
+      languages.</li>
+  <li>Rendered HTML must be compatible with Netscape Navigator (verson 4.7
+      or later) and Internet Explorer (version 5.0 or later).</li>
+  </ul>
+
+  </subsection>
+
+
+</section>
+
+
+<section name="Testable Assertions">
+
+  <p><strong>FIXME</strong> - Complete this section.</p>
+
+</section>
+
+
+</body>
+
+</document>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/funcspecs/fs-admin-objects.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/funcspecs/fs-admin-objects.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/funcspecs/fs-admin-objects.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,481 @@
+<?xml version="1.0"?>
+<!DOCTYPE document [
+  <!ENTITY project SYSTEM "project.xml">
+]>
+<document url="fs-admin-objects.html">
+
+  &project;
+
+  <properties>
+    <author email="craigmcc at apache.org">Craig McClanahan</author>
+    <title>Administrative Apps - Administered Objects</title>
+    <revision>$Id: fs-admin-objects.xml 303281 2004-09-27 16:00:31Z yoavs $</revision>
+  </properties>
+
+<body>
+
+
+<section name="Administered Objects Overview">
+
+<p>This document defines the <em>Administered Objects</em> that represent
+the internal architectural components of the Catalina servlet container.
+Associated with each is a set of <a href="fs-admin-opers.html">Supported
+Operations</a> that can be performed when the administrative application is
+"focused" on a particular configurable object.</p>
+
+<p>The following Administered Objects are defined:</p>
+<ul>
+<li><a href="#Access Logger">Access Logger</a></li>
+<li><a href="#Connector">Connector</a></li>
+<li><a href="#Context">Context</a></li>
+<li><a href="#Default Context">Default Context</a></li>
+<li><a href="#Default Deployment Descriptor">Default Deployment Descriptor</a></li>
+<li><a href="#Engine">Engine</a></li>
+<li><a href="#Environment Entry">Environment Entry</a></li>
+<li><a href="#Host">Host</a></li>
+<li><a href="#JDBC Resource">JDBC Resource</a></li>
+<li><a href="#Loader">Loader</a></li>
+<li><a href="#Manager">Manager</a></li>
+<li><a href="#Realm">Realm</a></li>
+<li><a href="#Request Filter">Request Filter</a></li>
+<li><a href="#Server">Server</a></li>
+<li><a href="#Service">Service</a></li>
+</ul>
+
+</section>
+
+
+<section name="Access Logger">
+
+  <p>An <em>Access Logger</em> is an optional <code>Valve</code> that can
+  create request access logs in the same formats as those provided by
+  web servers.  Such access logs are useful input to hit count and user
+  access tracking analysis programs.  An Access Logger can be attached to
+  an <em>Engine</em>, a <em>Host</em>, a <em>Context</em>, or a <em>Default
+  Context</em>.</p>
+
+  <p>The standard component implementing an <em>Access Logger</em> is
+  <code>org.apache.catalina.valves.AccessLogValve</code>.  It supports the
+  following configurable properties:</p>
+  <ul>
+  <li><code>debug</code> - Debugging detail level.  [0]</li>
+  <li><code>directory</code> - Absolute or relative (to $CATALINA_HOME) path
+      of the directory into which access log files are created.
+      [logs].</li>
+  <li><code>pattern</code> - Pattern string defining the fields to be
+      included in the access log output, or "common" for the standard
+      access log pattern.  See
+      <code>org.apache.catalina.valves.AccessLogValve</code> for more
+      information.  [common]</li>
+  <li><code>prefix</code> - Prefix added to the beginning of each log file
+      name created by this access logger.</li>
+  <li><code>resolveHosts</code> - Should IP addresses be resolved to host
+      names in the log?  [false]</li>
+  <li><code>suffix</code> - Suffix added to the end of each log file name
+      created by this access logger.</li>
+  </ul>
+
+</section>
+
+
+<section name="Connector">
+
+  <p>A <em>Connector</em> is the representation of a communications endpoint
+  by which requests are received from (and responses returned to) a Tomcat
+  client.  The administrative applications shall support those connectors
+  that are commonly utilized in Tomcat installations, as described in detail
+  below.</p>
+
+  <p>For standalone use, the standard connector supporting the HTTP/1.1
+  protocol is <code>org.apache.catalina.connectors.http.HttpConnector</code>.
+  It supports the following configurable properties:</p>
+  <ul>
+  <li><code>acceptCount</code> - The maximum queue length of incoming
+      connections that have not yet been accepted.  [10]</li>
+  <li><code>address</code> - For servers with more than one IP address, the
+      address upon which this connector should listen.  [All Addresses]</li>
+  <li><code>bufferSize</code> - Default input buffer size (in bytes) for
+      requests created by this Connector.  [2048]</li>
+  <li><code>debug</code> - Debugging detail level.  [0]</li>
+  <li><code>enableLookups</code> - Should we perform DNS lookups on remote
+      IP addresses when <code>request.getRemoteHost()</code> is called?
+      [true]</li>
+  <li><code>maxProcessors</code> - The maximum number of processor threads
+      supported by this connector.  [20]</li>
+  <li><code>minProcessors</code> - The minimum number of processor threads
+      to be created at container startup.  [5]</li>
+  <li><code>port</code> - TCP/IP port number on which this Connector should
+      listen for incoming requests. [8080]</li>
+  <li><code>proxyName</code> - Host name to be returned when an application
+      calls <code>request.getServerName()</code>.  [Value of Host: header]</li>
+  <li><code>proxyPort</code> - Port number to be returned when an application
+      calls <code>request.getServerPort()</code>.  [Same as <code>port</code>]
+      </li>
+  </ul>
+
+</section>
+
+
+<section name="Context">
+
+  <p>A <em>Context</em> is the representation of an individual web application,
+  which is associated with a corresponding <em>Host</em>.  Note that the
+  administrable properties of a <em>Context</em> do <strong>not</strong>
+  include any settings from inside the web application deployment descriptor
+  for that application.</p>
+
+  <p>The standard component implementing a <em>Context</em> is
+  <code>org.apache.catalina.core.StandardContext</code>.  It supports the
+  following configurable properties:</p>
+  <ul>
+  <li><code>cookies</code> - Should be use cookies for session identifier
+      communication?  [true]</li>
+  <li><code>crossContext</code> - Should calls to
+      <code>ServletContext.getServletContext()</code> return the actual
+      context responsible for the specified path?  [false]</li>
+  <li><code>debug</code> - Debugging detail level.  [0]</li>
+  <li><code>docBase</code> - The absolute or relative (to the
+      <code>appBase</code> of our owning <em>Host</em>) pathname of a
+      directory containing an unpacked web application, or of a web
+      application archive (WAR) file.</li>
+  <li><code>override</code> - Should settings in this <em>Context</em>
+      override corresponding settings in the <em>Default Context</em>?
+      [false]</li>
+  <li><code>path</code> - Context path for this web application, or an empty
+      string for the root application of a <em>Host</em>.  [Inferred from
+      directory or WAR file name]</li>
+  <li><code>reloadable</code> - Should Tomcat monitor classes in the
+      <code>/WEB-INF/classes</code> directory for changes, and reload the
+      application if they occur?  [false]</li>
+  <li><code>useNaming</code> - Should Tomcat provide a JNDI naming context,
+      containing preconfigured entries and resources, corresponding to the
+      requirements of the Java2 Enterprise Edition specification?  [true]</li>
+  <li><code>workDir</code> - Absolute pathname of a scratch directory that is
+      provided to this web application.  [Automatically assigned relative to
+      $CATALINA_HOME/work]</li>
+  </ul>
+
+  <p>Each <em>Context</em> is owned by a parent <em>Host</em>, and is
+  associated with:</p>
+  <ul>
+  <li>An optional <em>Access Logger</em> that logs all requests processed
+      by this web application.</li>
+  <li>Zero or more <em>Environment Entries</em> representing environment
+      entries for the JNDI naming context associated with a web
+      application.</li>
+  <li>Zero or more <em>JDBC Resources</em> representing database connection
+      pools associated with a web application.</li>
+  <li>A <em>Loader</em> representing the web application class loader used
+      by this web application.</li>
+  <li>A <em>Manager</em> representing the session manager used by this
+      web application.</li>
+  <li>An optional <em>Realm</em> used to provide authentication and access
+      control information for this web application.</li>
+  <li>Zero or more <em>Request Filters</em> used to limit access to this
+      web application based on remote host name or IP address.</li>
+  </ul>
+
+</section>
+
+
+<section name="Default Context">
+
+  <p>A <em>Default Context</em> represents a subset of the configurable
+  properties of a <em>Context</em>, and is used to set defaults for those
+  properties when web applications are automatically deployed.  A <em>Default
+  Context</em> object can be associated with an <em>Engine</em> or a
+  <em>Host</em>.  The following configurable properties are supported:</p>
+  <ul>
+  <li><code>cookies</code> - Should be use cookies for session identifier
+      communication?  [true]</li>
+  <li><code>crossContext</code> - Should calls to
+      <code>ServletContext.getServletContext()</code> return the actual
+      context responsible for the specified path?  [false]</li>
+  <li><code>reloadable</code> - Should Tomcat monitor classes in the
+      <code>/WEB-INF/classes</code> directory for changes, and reload the
+      application if they occur?  [false]</li>
+  <li><code>useNaming</code> - Should Tomcat provide a JNDI naming context,
+      containing preconfigured entries and resources, corresponding to the
+      requirements of the Java2 Enterprise Edition specification?  [true]</li>
+  </ul>
+
+  <p>Each <em>Default Context</em> is owned by a parent <em>Engine</em> or
+  <em>Host</em>, and is associated with:</p>
+  <ul>
+  <li>Zero or more <em>Environment Entries</em> representing environment
+      entries for the JNDI naming context associated with a web
+      application.</li>
+  <li>Zero or more <em>JDBC Resources</em> representing database connection
+      pools associated with a web application.</li>
+  <li>An optional <em>Loader</em> representing default configuration
+      properties for the Loader component of deployed web applications.</li>
+  <li>An optional <em>Manager</em> representing default configuration
+      properties for the Manager component fo deployed web applications.</li>
+  </ul>
+
+</section>
+
+
+<section name="Default Deployment Descriptor">
+
+  <p>Default web application characteristics are configured in a special
+  deployment descriptor named <code>$CATALINA_HOME/conf/web.xml</code>.  This
+  section describes the configurable components that may be stored there.</p>
+
+  <p><strong>FIXME</strong> - Complete the description of default servlets,
+  default mappings, default MIME types, and so on.</p>
+
+</section>
+
+
+<section name="Engine">
+
+  <p>An <em>Engine</em> is the representation of the entire Catalina
+  servlet container, and processes all requests for all of the associated
+  virtual hosts and web applications.</p>
+
+  <p>The standard component implementing an <em>Engine</em> is
+  <code>org.apache.catalina.core.StandardEngine</code>.  It supports the
+  following configurable properties:</p>
+  <ul>
+  <li><code>debug</code> - Debugging detail level.  [0]</li>
+  <li><code>defaultHost</code> - Name of the <em>Host</em> to which requests
+      will be directed if the requested host is unknown.  [localhost]</li>
+  <li><code>name</code> - Logical name of this engine. [Tomcat Stand-Alone]
+      </li>
+  </ul>
+
+  <p>Each <em>Engine</em> is owned by a parent <em>Service</em>, and is
+  associated with:</p>
+  <ul>
+  <li>An optional <em>Access Logger</em> that logs all requests processed
+      by the entire container.</li>
+  <li>A <em>Default Context</em>, representing default properties of a
+      <em>Context</em> for automatically deployed applications for all
+      associated <em>Hosts</em> (unless overridden by a subordinate
+      component).</li>
+  <li>One or more <em>Hosts</em> representing individual virtual hosts
+      supported by this container.</li>
+  <li>A <em>Realm</em> used to provide authentication and access control
+      information for all virtual hosts and web applications (unless
+      overridden by a subordinate component).</li>
+  <li>Zero or more <em>Request Filters</em> used to limit access to the
+      entire container based on remote host name or IP address.</li>
+  </ul>
+
+</section>
+
+
+<section name="Environment Entry">
+
+  <p>An <em>Environment Entry</em> is the representation of a
+  <code>&lt;env-entry&gt;</code> element from a web application deployment
+  descriptor.  It will cause the creation of a corresponding entry in the
+  JNDI naming context provided to the corresponding <em>Context</em>.  The
+  following configurable properties are supported:</p>
+  <ul>
+  <li><code>description</code> - Description of this environment entry.</li>
+  <li><code>name</code> - Environment entry name (relative to the
+      <code>java:comp/env</code> context)</li>
+  <li><code>type</code> - Environment entry type (must be one of the fully
+      qualified Java classes listed in the servlet spec).</li>
+  <li><code>value</code> - Environment entry value (must be convertible from
+      String to the specified <code>type</code>.</li>
+  </ul>
+
+</section>
+
+
+<section name="Host">
+
+  <p>A <em>Host</em> is the representation of an individual virtual host,
+  which has a unique set of associated web applications.</p>
+
+  <p>The standard component implementing a <em>Host</em> is
+  <code>org.apache.catalina.core.StandardHost</code>.  It supports the
+  following configurable properties:</p>
+  <ul>
+  <li><code>aliases</code> - Zero or more DNS names that are also associated
+      with this host (for example, a particular host might be named
+      <code>www.mycompany.com</code> with an alias <code>company.com</code>).
+      </li>
+  <li><code>appBase</code> - Absolute or relative (to $CATALINA_HOME) path
+      to a directory from which web applications will be automatically
+      deployed.</li>
+  <li><code>debug</code> - Debugging detail level.  [0]</li>
+  <li><code>name</code> - DNS Name of the virtual host represented by this
+      object.</li>
+  <li><code>unpackWARs</code> - Should web application archive files
+      deployed by this virtual host be unpacked first?  [true]</li>
+  </ul>
+
+  <p>Each <em>Host</em> is owned by a parent <em>Engine</em>, and is
+  associated with:</p>
+  <ul>
+  <li>An optional <em>Access Logger</em> that logs all requests processed
+      by this virtual host.</li>
+  <li>One or more <em>Contexts</em> representing the web applications
+      operating on this <em>Host</em>.</li>
+  <li>A <em>Default Context</em> representing default <em>Context</em>
+      properties for web applications that are automatically deployed
+      by this <em>Host</em>.</li>
+  <li>A optional <em>Realm</em> used to provide authentication and access
+      control information for all web applications associated with this
+      virtual host (unless overridden by a subordinate component).</li>
+  </ul>
+
+  <p><strong>FIXME</strong> - Should we support configuration of the
+  User Web Applications functionality?</p>
+
+</section>
+
+
+<section name="JDBC Resource">
+
+  <p>A <em>JDBC Resources</em> represents a database connection pool (i.e.
+  an implementation of <code>javax.sql.DataSource</code> that will be
+  configured and made available in the JNDI naming context associated with
+  a web application.</p>
+
+  <p><strong>FIXME</strong> - properties of this administered object</p>
+
+</section>
+
+
+<section name="Loader">
+
+  <p>A <em>Loader</em> represents a web application class loader that will
+  be utilized to provide class loading services for a particular
+  <em>Context</em>.</p>
+
+  <p>The standard component implementing a <em>Loader</em> is
+  <code>org.apache.catalina.loader.StandardLoader</code>.  It supports
+  the following configurable properties:</p>
+  <ul>
+  <li><code>checkInterval</code> - Number of seconds between checks for
+      modified classes, if automatic reloading is enabled.  [15]</li>
+  <li><code>debug</code> - Debugging detail level.  [0]</li>
+  <li><code>reloadable</code> - Should this class loader check for modified
+      classes and initiate automatic reloads?  [Set automatically from the
+      <code>reloadable</code> property of the corresponding <em>Context</em>]
+      </li>
+  </ul>
+
+  <p>Each <em>Loader</em> is owned by a parent <em>Context</em>.</p>
+
+</section>
+
+
+<section name="Manager">
+
+  <p>A <em>Manager</em> represents a session manager that will be associated
+  with a particular web application.  <strong>FIXME</strong> - Add support
+  for advanced session managers and their associated Stores.</p>
+
+  <p>The standard component implementing a <em>Manager</em> is
+  <code>org.apache.catalina.session.StandardManager</code>.  It supports
+  the following configurable properties:</p>
+  <ul>
+  <li><code>checkInterval</code> - Number of seconds between checks for
+      expired sessions.  [60]</li>
+  <li><code>debug</code> - Debugging detail level.  [0]</li>
+  <li><code>entropy</code> - String initialization parameter used to increase
+      the entropy (initial randomness) of the random number generator used to
+      create session identifiers.  [Inferred from engine, host, and context]
+      </li>
+  <li><code>maxActiveSessions</code> - The maximum number of active sessions
+      that are allowed, or -1 for no limit.  [-1]</li>
+  </ul>
+
+  <p>Each <em>Manager</em> is owned by a parent <em>Context</em>.</p>
+
+</section>
+
+
+<section name="Realm">
+
+  <p>A <em>Realm</em> represents a "database" of information about authorized
+  users, their passwords, and the security roles assigned to them.  This will
+  be used by the container in the implementation of container-managed security
+  in accordance with the Servlet Specification.  Several alternative
+  implementations are supported.</p>
+
+  <p><code>org.apache.catalina.realm.MemoryRealm</code> initializes its user
+  information from a simple XML file at startup time.  If changes are made
+  to the information in this file, the corresponding web applications using
+  it must be restarted for the changes to take effect.  It supports the
+  following configurable properties:</p>
+  <ul>
+  <li><code>debug</code> - Debugging detail level.  [0]</li>
+  <li><code>pathname</code> - Absolute or relative (to $CATALINA_HOME) path to
+      the XML file containing our user information.  [conf/tomcat-users.xml]
+      </li>
+  </ul>
+
+  <p><code>org.apache.catalina.realm.JDBCRealm</code> uses a relational
+  database (accessed via JDBC APIs) to contain the user information.  Changes
+  in the contents of this database take effect immediately; however, the roles
+  assigned to a particular user are calculated only when the user initially
+  logs on (and not per request).  The following configurable properties
+  are supported:</p>
+  <ul>
+  <li><code>connectionName</code> - Database username to use when establishing
+      a JDBC connection.</li>
+  <li><code>connectionPassword</code> - Database password to use when
+      establishing a JDBC connection.</li>
+  <li><code>connectionURL</code> - Connection URL to use when establishing
+      a JDBC connection.</li>
+  <li><code>debug</code> - Debugging detail level.  [0]</li>
+  <li><code>digest</code> - Name of the <code>MessageDigest</code> algorithm
+      used to encode passwords in the database, or a zero-length string for
+      no encoding.  [Zero-length String]</li>
+  <li><code>driverName</code> - Fully qualified Java class name of the JDBC
+      driver to be utilized.</li>
+  <li><code>roleNameCol</code> - Name of the column, in the User Roles table,
+      which contains the role name.</li>
+  <li><code>userCredCol</code> - Name of the column, in the Users table,
+      which contains the password (encrypted or unencrypted).</li>
+  <li><code>userNameCol</code> - Name of the column, in both the Users and
+      User Roles tables, that contains the username.</li>
+  <li><code>userRoleTable</code> - Name of the User Roles table, which contains
+      one row per security role assigned to a particular user.  This table must
+      contain the columns specified by the <code>userNameCol</code> and
+      <code>roleNameCol</code> properties.</li>
+  <li><code>userTable</code> - Name of the Users table, which contains one row
+      per authorized user.  This table must contain the columns specified by
+      the <code>userNameCol</code> and <code>userCredCol</code> properties.
+      </li>
+  </ul>
+
+  <p><strong>FIXME</strong> - Should we provide mechanisms to edit the contents
+  of a "tomcat-users.xml" file through the admin applications?</p>
+
+  <p>Each <em>Realm</em> is owned by a parent <em>Engine</em>, <em>Host</em>,
+  or <em>Context</em>.</p>
+
+</section>
+
+
+<section name="Request Filter">
+
+  <p><strong>FIXME</strong> - complete this entry</p>
+
+</section>
+
+
+<section name="Server">
+
+  <p><strong>FIXME</strong> - complete this entry</p>
+
+</section>
+
+
+<section name="Service">
+
+  <p><strong>FIXME</strong> - complete this entry</p>
+
+</section>
+
+</body>
+
+</document>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/funcspecs/fs-admin-opers.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/funcspecs/fs-admin-opers.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/funcspecs/fs-admin-opers.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,324 @@
+<?xml version="1.0"?>
+<!DOCTYPE document [
+  <!ENTITY project SYSTEM "project.xml">
+]>
+<document url="fs-admin-opers.html">
+
+  &project;
+
+  <properties>
+    <author email="craigmcc at apache.org">Craig McClanahan</author>
+    <title>Administrative Apps - Supported Operations</title>
+    <revision>$Id: fs-admin-opers.xml 303281 2004-09-27 16:00:31Z yoavs $</revision>
+  </properties>
+
+<body>
+
+
+<section name="Supported Operations Overview">
+
+<p>This document defines the <em>Supported Operations</em> that may
+be performed against the <a href="fs-admin-objects.html">Administered
+Objects</a> that are supported by Tomcat 5 administrative applications.
+Not all operations are required to be available through every administrative
+application that is implemented.  However, if a given operation is available,
+it should operate consistently with the descriptions found here.</p>
+
+<p>Supported Operations are described for the following Administered
+Objects:</p>
+<ul>
+<li><a href="#Access Logger">Access Logger</a></li>
+<li><a href="#Connector">Connector</a></li>
+<li><a href="#Context">Context</a></li>
+<li><a href="#Default Context">Default Context</a></li>
+<li><a href="#Engine">Engine</a></li>
+<li><a href="#Environment Entry">Environment Entry</a></li>
+<li><a href="#Host">Host</a></li>
+<li><a href="#JDBC Resource">JDBC Resource</a></li>
+<li><a href="#Loader">Loader</a></li>
+<li><a href="#Manager">Manager</a></li>
+<li><a href="#Realm">Realm</a></li>
+<li><a href="#Request Filter">Request Filter</a></li>
+<li><a href="#Server">Server</a></li>
+<li><a href="#Service">Service</a></li>
+</ul>
+
+</section>
+
+
+<section name="Access Logger">
+
+  <p>From the perspective of a particular <em>Access Logger</em>, it shall
+  be possible to perform the following administrative operations:</p>
+  <ul>
+  <li>Navigate to the owning <em>Engine</em>, <em>Host</em>, or
+      <em>Context</em>.</li>
+  <li>Edit the configurable properties of this object.</li>
+  </ul>
+
+</section>
+
+
+<section name="Connector">
+
+  <p>From the perspective of a particular <em>Connector</em>, it shall be
+  possible to perform the following administrative operations:</p>
+  <ul>
+  <li>Navigate to the owning <em>Service</em>.</li>
+  <li>Edit the configurable properties of this object.</li>
+  </ul>
+
+</section>
+
+
+<section name="Context">
+
+  <p>From the perspective of a particular <em>Context</em>, it shall be
+  possible to perform the following administrative operations:</p>
+  <ul>
+  <li>Navigate to the owning <em>Host</em>.</li>
+  <li>Edit the configurable properties of this object.</li>
+  <li>Create and configure a new <em>Access Logger</em> associated
+      with this object.</li>
+  <li>Edit the configurable properties of the associated <em>Access
+      Logger</em>.</li>
+  <li>Remove the associated <em>Access Logger</em>.</li>
+  <li>Create and configure a new <em>Environment Entry</em> associated
+      with this object.</li>
+  <li>Select and edit the configurable properties of an associated
+      <em>Environment Entry</em>.</li>
+  <li>Remove an associated <em>Environment Entry</em>.</li>
+  <li>Create and configure a new <em>JDBC Resource</em> associated
+      with this object.</li>
+  <li>Select and edit the configurable properties of an associated
+      <em>JDBC Resource</em>.</li>
+  <li>Remove an associated <em>JDBC Resource</em>.</li>
+  <li>Create and configure a new <em>Loader</em> associated with
+      this object.</li>
+  <li>Edit the configurable properties of the associated <em>Loader</em>.</li>
+  <li>Remove the associated <em>Loader</em>.</li>
+  <li>Create and configure a new <em>Manager</em> associated with
+      this object.</li>
+  <li>Edit the configurable properties of the associated <em>Manager</em>.</li>
+  <li>Remove the associated <em>Manager</em>.</li>
+  <li>Create and configure a new <em>Realm</em> associated with
+      this object.</li>
+  <li>Edit the configurable properties of the associated <em>Realm</em>.</li>
+  <li>Remove the associated <em>Realm</em>.</li>
+  <li>Create and configure a new <em>Request Filter</em> associated with
+      this object.</li>
+  <li>Select and edit the configurable properties of an
+      associated <em>Request Filter</em></li>
+  <li>Remove an associated <em>Request Filter</em>.</li>
+  </ul>
+
+</section>
+
+
+<section name="Default Context">
+
+  <p>From the perspective of a particular <em>Default Context</em>, it shall
+  be possible to perform the following administrative operations:</p>
+  <ul>
+  <li>Navigate to the owning <em>Engine</em> or <em>Host</em>.</li>
+  <li>Edit the configurable properties of this object.</li>
+  <li>Create and configure a new <em>Environment Entry</em> associated
+      with this object.</li>
+  <li>Select and edit the configurable properties of an associated
+      <em>Environment Entry</em>.</li>
+  <li>Remove an associated <em>Environment Entry</em>.</li>
+  <li>Create and configure a new <em>JDBC Resource</em> associated
+      with this object.</li>
+  <li>Select and edit the configurable properties of an associated
+      <em>JDBC Resource</em>.</li>
+  <li>Remove an associated <em>JDBC Resource</em>.</li>
+  </ul>
+
+</section>
+
+
+<section name="Engine">
+
+  <p>From the perspective of a particular <em>Engine</em>, it shall be
+  possible to perform the following administrative operations:</p>
+  <ul>
+  <li>Navigate to the owning <em>Service</em>.</li>
+  <li>Edit the configurable properties of this object.</li>
+  <li>Create and configure a new <em>Access Logger</em> associated
+      with this object.</li>
+  <li>Edit the configurable properties of the associated <em>Access
+      Logger</em>.</li>
+  <li>Remove the associated <em>Access Logger</em>.</li>
+  <li>Create and configure a new <em>Default Context</em> associated
+      with this object.</li>
+  <li>Edit the configurable properties of the associated <em>Default
+      Context</em>.</li>
+  <li>Remove the associated <em>Default Context</em>.</li>
+  <li>Create and configure a new <em>Host</em> associated with
+      this object.</li>
+  <li>Select and edit the configurable properties of an
+      associated <em>Host</em>.</li>
+  <li>Remove an associated <em>Host</em>.</li>
+  <li>Create and configure a new <em>Realm</em> associated with
+      this object.</li>
+  <li>Edit the configurable properties of the associated <em>Realm</em>.</li>
+  <li>Remove the associated <em>Realm</em>.</li>
+  <li>Create and configure a new <em>Request Filter</em> associated with
+      this object.</li>
+  <li>Select and edit the configurable properties of an
+      associated <em>Request Filter</em></li>
+  <li>Remove an associated <em>Request Filter</em>.</li>
+  </ul>
+
+</section>
+
+
+<section name="Environment Entry">
+
+  <p>From the perspective of a particular <em>Environment Entry</em>, it shall
+  be possible to perform the following administrative operations:</p>
+  <ul>
+  <li>Navigate to the owning <em>Context</em> or <em>Default Context</em>.</li>
+  <li>Edit the configurable properties of this object.</li>
+  </ul>
+
+</section>
+
+
+<section name="Host">
+
+  <p>From the perspective of a particular <em>Host</em>, it shall be
+  possible to perform the following administrative operations:</p>
+  <ul>
+  <li>Navigate to the owning <em>Engine</em>.</li>
+  <li>Edit the configurable properties of this object.</li>
+  <li>Create and configure a new <em>Access Logger</em> associated
+      with this object.</li>
+  <li>Edit the configurable properties of the associated <em>Access
+      Logger</em>.</li>
+  <li>Remove the associated <em>Access Logger</em>.</li>
+  <li>Create and configure a new <em>Context</em> associated with
+      this object.</li>
+  <li>Select and edit the configurable properties of an associated
+      <em>Context</em>.</li>
+  <li>Remove an associated <em>Context</em>.</li>
+  <li>Create and configure a new <em>Default Context</em> associated
+      with this object.</li>
+  <li>Edit the configurable properties of the associated <em>Default
+      Context</em>.</li>
+  <li>Remove the associated <em>Default Context</em>.</li>
+  <li>Create and configure a new <em>Realm</em> associated with
+      this object.</li>
+  <li>Edit the configurable properties of the associated <em>Realm</em>.</li>
+  <li>Remove the associated <em>Realm</em>.</li>
+  <li>Create and configure a new <em>Request Filter</em> associated with
+      this object.</li>
+  <li>Select and edit the configurable properties of an
+      associated <em>Request Filter</em></li>
+  <li>Remove an associated <em>Request Filter</em>.</li>
+  </ul>
+
+</section>
+
+
+<section name="JDBC Resource">
+
+  <p>From the perspective of a particular <em>JDBC Resource</em>, it shall
+  be possible to perform the following administrative operations:</p>
+  <ul>
+  <li>Navigate to the owning <em>Context</em> or <em>Default Context</em>.</li>
+  <li>Edit the configurable properties of this object.</li>
+  </ul>
+
+</section>
+
+
+<section name="Loader">
+
+  <p>From the perspective of a particular <em>Loader</em>, it shall
+  be possible to perform the following administrative operations:</p>
+  <ul>
+  <li>Navigate to the owning <em>Context</em>.</li>
+  <li>Edit the configurable properties of this object.</li>
+  </ul>
+
+</section>
+
+
+<section name="Manager">
+
+  <p>From the perspective of a particular <em>Manager</em>, it shall
+  be possible to perform the following administrative operations:</p>
+  <ul>
+  <li>Navigate to the owning <em>Context</em>.</li>
+  <li>Edit the configurable properties of this object.</li>
+  </ul>
+
+</section>
+
+
+<section name="Realm">
+
+  <p>From the perspective of a particular <em>Realm</em>, it shall
+  be possible to perform the following administrative operations:</p>
+  <ul>
+  <li>Navigate to the owning <em>Engine</em>, <em>Host</em>, or
+      <em>Context</em>.</li>
+  <li>Edit the configurable properties of this object.</li>
+  </ul>
+
+</section>
+
+
+<section name="Request Filter">
+
+  <p>From the perspective of a particular <em>Request Filter</em>, it shall
+  be possible to perform the following administrative operations:</p>
+  <ul>
+  <li>Navigate to the owning <em>Engine</em>, <em>Host</em>, or
+      <em>Context</em>.</li>
+  <li>Edit the configurable properties of this object.</li>
+  </ul>
+
+</section>
+
+
+<section name="Server">
+
+  <p>From the perspective of the overall <em>Server</em>, it shall be
+  possible to perform the following administrative operations:</p>
+  <ul>
+  <li>Edit the configurable properties of this object.</li>
+  <li>Create and configure a new <em>Service</em> associated with
+      this object.</li>
+  <li>Select and edit the configurable properties of an associated
+      <em>Service</em>.</li>
+  </ul>
+
+</section>
+
+
+<section name="Service">
+
+  <p>From the perspective of a particular <em>Service</em>, it shall be
+  possible to perform the following administrative operations:</p>
+  <ul>
+  <li>Navigate to the owning <em>Server</em>.</li>
+  <li>Edit the configurable properties of this object.</li>
+  <li>Create and configure a new <em>Connector</em> associated with
+      this object.</li>
+  <li>Select and edit the configurable properties of an associated
+      <em>Connector</em>.</li>
+  <li>Remove an associated <em>Connector</em>.</li>
+  <li>Create and configure a new <em>Engine</em> associated with
+      this object.</li>
+  <li>Edit the configurable properties of the associated <em>Engine</em>.</li>
+  <li>Remove the associated <em>Engine</em>.</li>
+  </ul>
+
+</section>
+
+
+</body>
+
+</document>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/funcspecs/fs-default.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/funcspecs/fs-default.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/funcspecs/fs-default.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,252 @@
+<?xml version="1.0"?>
+<!DOCTYPE document [
+  <!ENTITY project SYSTEM "project.xml">
+]>
+<document url="fs-default.html">
+
+  &project;
+
+  <properties>
+    <author email="craigmcc at apache.org">Craig McClanahan</author>
+    <title>Default Servlet</title>
+    <revision>$Id: fs-default.xml 301460 2003-01-15 03:40:45Z glenn $</revision>
+  </properties>
+
+<body>
+
+
+<section name="Overview">
+
+
+  <subsection name="Introduction">
+
+    <p>The purpose of the <strong>Default Servlet</strong> is to serve
+    static resources of a web application in response to client requests.
+    As the name implies, it is generally configured as the "default"
+    servlet for a web application, by being mapped to a URL pattern "/".</p>
+
+  </subsection>
+
+
+  <subsection name="External Specifications">
+
+    <p>The following external specifications have provisions which
+    partially define the correct behavior of the default servlet:</p>
+    <ul>
+    <li><a href="http://java.sun.com/products/servlet/download.html">
+        Servlet Specification</a> (Version 2.3 PFD2)</li>
+    <li><a href="http://www.rfc-editor.org/rfc/rfc2046.txt">Multipurpose
+        Internet Mail Extensions (MIME) Part Two: Media Types</a></li>
+    <li><a href="http://www.rfc-editor.org/rfc/rfc2616.txt">Hypertext
+        Transfer Protocol -- HTTP/1.1</a></li>
+    </ul>
+
+  </subsection>
+
+
+  <subsection name="Implementation Requirements">
+
+    <p>The implementation of this functionality shall conform to the
+    following requirements:</p>
+    <ul>
+    <li>Must be implemented as a servlet.</li>
+    <li>Must support configurable parameters for debugging detail level,
+        input buffer size, output buffer size, whether or not to produce
+        directory listings when no welcome file is present, and whether or not
+        modifications are supported via DELETE and PUT.</li>
+    <li>Log debugging and operational messages (suitably internationalized)
+        via the <code>getServletContext().log()</code> method.</li>
+    </ul>
+
+  </subsection>
+
+
+</section>
+
+
+<section name="Dependencies">
+
+
+  <subsection name="Environmental Dependencies">
+
+    <p>The following environmental dependencies must be met in order for
+    the default servlet to operate correctly:</p>
+    <ul>
+    <li>The default servlet must be registered in the application deployment
+        descriptor (or the default deployment descriptor in file
+        <code>$CATALINA_HOME/conf/web.xml</code>) using a "default servlet"
+        servlet mapping, signified by URL pattern "/".</li>
+    </ul>
+
+  </subsection>
+
+
+  <subsection name="Container Dependencies">
+
+    <p>Correct operation of the default servlet depends on the following
+    specific features of the surrounding container:</p>
+    <ul>
+    <li>The container shall provide a servlet context attribute that
+        lists the welcome file names that have been defined for this
+        web application.</li>
+    <li>The container shall provide a servlet context attribute that
+        contains a <code>javax.naming.directory.DirContext</code>
+        implementation representing the static resources of this
+        web application.</li>
+    </ul>
+
+  </subsection>
+
+
+</section>
+
+
+<section name="Functionality">
+
+
+  <subsection name="Initialization Functionality">
+
+    <p>The following processing must be performed when the <code>init()</code>
+    method of the invoker servlet is called:</p>
+    <ul>
+    <li>Process and sanity check configuration parameters.</li>
+    </ul>
+
+  </subsection>
+
+
+  <subsection name="Per-Request Functionality">
+
+
+    <p>For all HTTP request methods, the resource path is determined from
+    the path information provided to this request, either as request attribute
+    <code>javax.servlet.include.path_info</code> (for a request dispatcher
+    access to a static resource) or by calling
+    <code>request.getPathInfo()</code> directly.</p>
+
+    <p>On each HTTP DELETE request processed by this servlet, the following
+    processing shall be performed:</p>
+    <ul>
+    <li>If modifications to the static resources are not allowed (set by a
+        configuration parameter), return HTTP status 403 (forbidden).</li>
+    <li>If an attempt is made to delete a resource from <code>/META-INF</code>
+        or <code>/WEB-INF</code>, return HTTP status 403 (forbidden).</li>
+    <li>If the requested resource does not exist, return HTTP status 404
+        (not found)</li>
+    <li>Unbind the resource from the directory context containing the
+        static resources for this web application.  If successful, return
+        HTTP status 204 (no content).  Otherwise, return HTTP status 405
+        (method not allowed).</li>
+    </ul>
+
+
+    <p>On each HTTP GET request processed by this servlet, the following
+    processing shall be performed:</p>
+    <ul>
+    <li>If the request is for a resource under <code>/META-INF</code> or
+        <code>/WEB-INF</code>, return HTTP status 404 (not found).</li>
+    <li>If the requested resource does not exist, return HTTP status 404
+        (not found).</li>
+    <li>If the requested resource is not a directory, but the resource
+        path ends in "/" or "\", return HTTP status 404 (not found).</li>
+    <li>If the requested resource is a directory:
+        <ul>
+        <li>If the request path does not end with "/", redirect to a
+            corresponding path with "/" appended so that relative references
+            in welcome files are resolved correctly.</li>
+        <li>If one of the specified welcome files exists, redirect to the
+            path for that welcome file so that it will be served explicitly.
+            </li>
+        </ul></li>
+    <li>If the request being processed contains an <code>If-Range</code>
+        header, perform the processing described in the HTTP/1.1 specification
+        to determine whether the client's information is up to date.</li>
+    <li>Determine the content type of the response, by looking up the
+        corresponding MIME type in our servlet context.</li>
+    <li>If the requested resource is a directory:
+        <ul>
+        <li>If directory listings are suppressed, return HTTP status 404
+            (not found).</li>
+        <li>Set the content type to <code>text/html</code>.</li>
+        </ul></li>
+    <li>Determine the range(s) to be returned, based on the existence of
+        any <code>If-Range</code> and <code>Range</code> headers.</li>
+    <li>If the requested resource is a directory, include an <code>ETag</code>
+        header in the response, with the value calculated based on the content
+        of the directory.</li>
+    <li>Include a <code>Last-Modified</code> header in the response documenting
+        the date/time that the resource was last modified.</li>
+    <li>Unless we are processing a HEAD request, include the appropriate
+        content (or content ranges) in the response.</li>
+    </ul>
+
+    <p>On each HTTP HEAD request processed by this servlet, the following
+    processing shall be performed:</p>
+    <ul>
+    <li>Processed identically to an HTTP GET request, except that the data
+        content is not transmitted after the headers.</li>
+    </ul>
+
+    <p>On each HTTP POST request processed by this servlet, the following
+    processing shall be performed:</p>
+    <ul>
+    <li>Processed identically to an HTTP GET request.</li>
+    </ul>
+
+
+    <p>On each HTTP PUT request processed by this servlet, the following
+    processing shall be perfomred:</p>
+    <ul>
+    <li>If modifications to the static resources are not allowed (set by a
+        configuration parameter), return HTTP status 403 (forbidden).</li>
+    <li>If an attempt is made to delete a resource from <code>/META-INF</code>
+        or <code>/WEB-INF</code>, return HTTP status 403 (forbidden).</li>
+    <li>Create a new resource from the body of this request.</li>
+    <li>Bind or rebind the specified path to the new resource (depending on
+        whether it currently exists or not).  Return HTTP status as follows:
+        <ul>
+        <li>If binding was unsuccessful, return HTTP status 409 (conflict).
+            </li>
+        <li>If binding was successful and the resource did not previously
+            exist, return HTTP status 201 (created).</li>
+        <li>If binding was successful and the resource previously existed,
+            return HTTP status 204 (no content).</li>
+        </ul></li>
+    </ul>
+
+  </subsection>
+
+
+  <subsection name="Finalization Functionality">
+
+    <p>No specific processing is required when the <code>destroy()</code>
+    method is called:</p>
+
+  </subsection>
+
+
+</section>
+
+
+<section name="Testable Assertions">
+
+  <p>In addition the the assertions implied by the functionality requirements
+  listed above, the following additional assertions shall be tested to
+  validate the behavior of the invoker servlet:</p>
+  <ul>
+  <li>Requests for resources that do not exist in the web application must
+      return HTTP status 404 (not found).</li>
+  <li>The default servlet must operate identically for web applications that
+      are run out of a WAR file directly, or from an unpacked directory
+      structure.</li>
+  <li>If the web application is running out of an unpacked directory
+      structure, the default servlet must recognize cases where the resource
+      has been updated through external means.</li>
+  </ul>
+
+</section>
+
+
+</body>
+
+</document>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/funcspecs/fs-invoker.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/funcspecs/fs-invoker.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/funcspecs/fs-invoker.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,247 @@
+<?xml version="1.0"?>
+<!DOCTYPE document [
+  <!ENTITY project SYSTEM "project.xml">
+]>
+<document url="fs-invoker.html">
+
+  &project;
+
+  <properties>
+    <author email="craigmcc at apache.org">Craig McClanahan</author>
+    <title>Invoker Servlet</title>
+    <revision>$Id: fs-invoker.xml 301460 2003-01-15 03:40:45Z glenn $</revision>
+  </properties>
+
+<body>
+
+
+<section name="Overview">
+
+
+  <subsection name="Introduction">
+
+    <p>The purpose of the <strong>Invoker Servlet</strong> is to allow a
+    web application to dynamically register new <em>servlet definitions</em>
+    that correspond with a <code>&lt;servlet&gt;</code> element in the
+    <code>/WEB-INF/web.xml</code> deployment descriptor, and execute
+    requests utilizing the new servlet definitions.  From the perspective
+    of the newly registered servlets, all servlet lifecycle requirements
+    of the Servlet Specification (such as calling <code>init()</code> and
+    <code>destroy()</code> at the correct times) will be respected.</p>
+
+  </subsection>
+
+
+  <subsection name="External Specifications">
+
+    <p>I do not know of any formal specification of the behavior of an
+    invoker servlet that is publicly available.  Anyone know of one?</p>
+
+  </subsection>
+
+
+  <subsection name="Implementation Requirements">
+
+    <p>The implementation of this functionality shall conform to the
+    following requirements:</p>
+    <ul>
+    <li>Implemented as a servlet.</li>
+    <li>Exist in the <code>org.apache.catalina.servlets</code> package
+        so that it can be loaded by the Catalina class loader.</li>
+    <li>Implement the <code>org.apache.catalina.ContainerServlet</code>
+        interface, so that it gains knowledge of the <code>Wrapper</code>
+        that is responsible for itself and, therefore, access to other
+        internal Catalina components.</li>
+    <li>Support a configurable debugging detail level.</li>
+    <li>Log debugging and operational messages (suitably internationalized)
+        via the <code>getServletContext().log()</code> method.</li>
+    </ul>
+
+  </subsection>
+
+
+</section>
+
+
+<section name="Dependencies">
+
+
+  <subsection name="Environmental Dependencies">
+
+    <p>The following environmental dependencies must be met in order for
+    the Invoker servlet to operate correctly:</p>
+    <ul>
+    <li>The invoker servlet must be registered in the application deployment
+        descriptor (or the default deployment descriptor in file
+        <code>$CATALINA_HOME/conf/web.xml</code>) using a "path mapped"
+        servlet mapping.  The historical default mapping is to URL pattern
+        "<code>/servlet/*</code>", although the invoker servlet must operate
+        correctly with an arbitrary mapping.</li>
+    </ul>
+
+  </subsection>
+
+
+  <subsection name="Container Dependencies">
+
+    <p>Correct operation of the invoker servlet depends on the following
+    specific features of the surrounding container:</p>
+    <ul>
+    <li>Correct support for the <code>ContainerServlet</code> interface,
+        including calling <code>setWrapper()</code> <strong>before</strong>
+        the <code>init()</code> method of the invoker servlet is called.</li>
+    <li>The web application class loader must be stored as the context
+        class loader of the request processing thread.</li>
+    </ul>
+
+  </subsection>
+
+
+</section>
+
+
+<section name="Functionality">
+
+
+  <subsection name="Initialization Functionality">
+
+    <p>The following processing must be performed when the <code>init()</code>
+    method of the invoker servlet is called:</p>
+    <ul>
+    <li>Ensure that the container has called <code>setWrapper()</code>.  If
+        not, throw a permanent <code>UnavailableException</code>.</li>
+    <li>Look up and cache the <code>Context</code> that corresponds to our
+        <code>Wrapper</code>.  This is the component with which new servlet
+        definitions and mappings will be registered.</li>
+    </ul>
+
+  </subsection>
+
+
+  <subsection name="Per-Request Functionality">
+
+    <p>On each request, the following processing shall be performed:</p>
+    <ol>
+    <li>Calculate the <code>{ServletPath}</code> for this request, either from
+        request attribute <code>javax.servlet.include.servlet_path</code> or
+        by calling <code>request.getServletPath()</code>.</li>
+    <li>Calculate the <code>{PathInfo}</code> for this request, either from
+        request attribute <code>javax.servlet.include.path_info</code> or
+        by calling <code>request.getPathInfo()</code>.  If the calculated
+        <code>{PathInfo}</code> is null, return HTTP status 400
+        (bad request).</li>
+    <li>Parse the calculated <code>{PathInfo}</code> value as follows:
+        <ol>
+        <li>Ignore the leading slash character.</li>
+        <li>Accumulate characters up to the next '/' (if any) as the
+            <code>{ServletSelector}</code>.</li>
+        <li>If a '/' was encountered, accumulate all characters from that
+            slash (inclusive) to the end of the string as
+            <code>{PathRemainder}</code>.  If no slash was encountered,
+            set <code>{PathRemainder}</code> to a zero-length string.</li>
+        </ol></li>
+    <li>Determine whether <code>{ServletSelector}</code> is the name of an
+        existing servlet definition, and process it as follows:
+        <ol>
+        <li>Ask our associated <code>Context</code> to find and return a
+            child <code>Wrapper</code> named <code>{ServletSelector}</code>.
+            </li>
+        <li>If there is no such child, skip to the next major step.</li>
+        <li>Register a new servlet mapping for this <code>Wrapper</code>,
+            using a URL pattern calculated as follows:
+            <code>{ServletPath}</code> + "/" + <code>{ServletSelector}</code>
+            + "/*"</li>
+        <li>Create a request dispatcher using a path calculated as follows:
+            <code>{ServletPath}</code> + "/" + <code>{ServletSelector}</code>
+            + <code>{PathRemainder}</code></li>
+        <li>Forward this request to the created request dispatcher, and
+            exit from this request.</li>
+        </ol></li>
+    <li>Assume that <code>{ServletSelector}</code> is the fully qualified
+        name of a Java class that implements <code>javax.servlet.Servlet</code>
+        and process it as follows:
+        <ol>
+        <li>Synthesize a new <code>{ServletName}</code> for the servlet
+            definition that will be created.</li>
+        <li>If there is already a child <code>Wrapper</code> associated with
+            this name, return HTTP status 500 (internal server error), because
+            a mapping should have already been created for this servlet.</li>
+        <li>Attempt to load a class named <code>{ServletSelector}</code> from
+            the web application class loader (i.e. the context class loader
+            for our current thread).  If this fails, return HTTP status 404
+            (not found).</li>
+        <li>Instantiate an instance of this class.  If an error occurs,
+            return HTTP status 404 (not found).</li>
+        <li>If this class does not implement the
+            <code>javax.servlet.Servlet</code> interface, return HTTP status
+            404 (not found).</li>
+        <li>Create and register a new <code>Wrapper</code> child with our
+            <code>Context</code>, under name <code>{ServletName}</code>.</li>
+        <li>Register a new servlet mapping for this <code>Wrapper</code>,
+            using a URL pattern calculated as follows:
+            <code>{ServletPath}</code> + "/" + <code>{ServletSelector}</code>
+            + "/*"</li>
+        <li>Create a request dispatcher using a path calculated as follows:
+            <code>{ServletPath}</code> + "/" + <code>{ServletSelector}</code>
+            + <code>{PathRemainder}</code></li>
+        <li>Forward this request to the created request dispatcher, and
+            exit from this request.</li>
+        </ol></li>
+    </ol>
+
+  </subsection>
+
+
+  <subsection name="Finalization Functionality">
+
+    <p>No specific processing is required when the <code>destroy()</code>
+    method is called:</p>
+
+  </subsection>
+
+
+</section>
+
+
+<section name="Testable Assertions">
+
+  <p>In addition the the assertions implied by the functionality requirements
+  listed above, the following additional assertions shall be tested to
+  validate the behavior of the invoker servlet:</p>
+  <ul>
+  <li>It is possible to access an existing servlet definition by name
+      through the invoker.  The existing servlet definition can include
+      either a <code>&lt;servlet-class&gt;</code> or
+      <code>&lt;jsp-file&gt;</code> subelement.</li>
+  <li>When an existing servlet definition is accessed by name, the request
+      will be ultimately processed by the same servlet instance that would
+      have processed it had a mapping to that servlet definition been used
+      on the request directly.</li>
+  <li>It is possible to access an anonymous servlet by class name
+      through the invoker.</li>
+  <li>When an anonymous servlet is accessed, the servlet instance is processed
+      according to the lifecycle requirements of the Servlet Specification.
+      </li>
+  <li>When an anonymous servlet is accessed, the servlet instance receives
+      a <code>ServletConfig</code> instance with no servlet initialization
+      parameters.</li>
+  <li>It is possible to utilize the invoker servlet via a direct request.</li>
+  <li>It is possible to utilize the invoker servlet via a call to
+      <code>RequestDispatcher.forward()</code>, or the corresponding
+      <code>&lt;jsp:forward&gt;</code> tag in a JSP page.</li>
+  <li>It is possible to utilize the invoker servlet via a call to
+      <code>RequestDispatcher.include()</code>, or the corresponding
+      <code>&lt;jsp:include&gt;</code> tag in a JSP page.</li>
+  <li>It is possible to use any HTTP method (including GET and POST) that
+      is supported by the Servlet class that is ultimately executed.</li>
+  <li>The invoker servlet should never be asked to process a second or
+      subsequent request for the same <code>{ServletSelector}</code> (because
+      it will have registered an appropriate servlet mapping.</li>
+  </ul>
+
+</section>
+
+
+</body>
+
+</document>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/funcspecs/fs-jdbc-realm.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/funcspecs/fs-jdbc-realm.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/funcspecs/fs-jdbc-realm.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,248 @@
+<?xml version="1.0"?>
+<!DOCTYPE document [
+  <!ENTITY project SYSTEM "project.xml">
+]>
+<document url="fs-jdbc-realm.html">
+
+  &project;
+
+  <properties>
+    <author email="craigmcc at apache.org">Craig McClanahan</author>
+    <title>JDBCRealm</title>
+    <revision>$Id: fs-jdbc-realm.xml 301460 2003-01-15 03:40:45Z glenn $</revision>
+  </properties>
+
+<body>
+
+
+<section name="Overview">
+
+
+  <subsection name="Introduction">
+
+    <p>The purpose of the <strong>JDBCRealm</strong> implementation is to
+    provide a mechanism by which Tomcat 5 can acquire information needed
+    to authenticate web application users, and define their security roles,
+    from a relational database accessed via JDBC APIs.  For integration
+    with Catalina, the resulting class(es) must implement the
+    <code>org.apache.catalina.Realm</code> interface.</p>
+
+    <p>This specification reflects a combination of functionality that is
+    already present in the <code>org.apache.catalina.realm.JDBCRealm</code>
+    class, as well as requirements for enhancements that have been
+    discussed.  Where appropriate, requirements statements are marked
+    <em>[Current]</em> and <em>[Requested]</em> to distinguish them.</p>
+
+    <p>The current status of this functional specification is
+    <strong>PROPOSED</strong>.  It has not yet been discussed and
+    agreed to on the TOMCAT-DEV mailing list.</p>
+
+  </subsection>
+
+
+  <subsection name="External Specifications">
+
+    <p>The implementation of this functionality depends on the following
+    external specifications:</p>
+    <ul>
+    <li><a href="http://java.sun.com/products/jdbc/">Java Database
+        Connectivity</a> (version 2.0 or later)</li>
+    <li><a href="http://java.sun.com/products/jdbc/">Java Database
+        Connectivity Optional Package</a> (version 2.0 or later)</li>
+    </ul>
+
+  </subsection>
+
+
+  <subsection name="Implementation Requirements">
+
+    <p>The implementation of this functionality shall conform to the
+    following requirements:</p>
+    <ul>
+    <li>Be realized in one or more implementation classes.</li>
+    <li>Implement the <code>org.apache.catalina.Realm</code> interface.
+        [Current]</li>
+    <li>Implement the <code>org.apache.catalina.Lifecycle</code>
+        interface.  [Current]</li>
+    <li>Subclass the <code>org.apache.catalina.realm.RealmBase</code>
+        base class.</li>
+    <li>Live in the <code>org.apache.catalina.realm</code> package.
+        [Current]</li>
+    <li>Support a configurable debugging detail level. [Current]</li>
+    <li>Log debugging and operational messages (suitably internationalized)
+        via the <code>getContainer().log()</code> method. [Current]</li>
+    </ul>
+
+  </subsection>
+
+
+</section>
+
+
+<section name="Dependencies">
+
+
+  <subsection name="Environmental Dependencies">
+
+    <p>The following environmental dependencies must be met in order for
+    JDBCRealm to operate correctly:</p>
+    <ul>
+    <li>The desire to utilize JDBCRealm must be registered in
+        <code>$CATALINA_HOME/conf/server.xml</code>, in a
+        <code>&lt;Realm&gt;</code> element that is nested inside a
+        corresponding <code>&lt;Engine&gt;</code>, <code>&lt;Host&gt;</code>,
+        or <code>&lt;Context&gt;</code> element.</li>
+    </ul>
+
+  </subsection>
+
+
+  <subsection name="Container Dependencies">
+
+    <p>Correct operation of JDBCRealm depends on the following
+    specific features of the surrounding container:</p>
+    <ul>
+    <li>Interactions with <code>JDBCRealm</code> will be initiated by
+        the appropriate <code>Authenticator</code> implementation, based
+        on the login method that is selected.</li>
+    <li><code>JDBCRealm</code> must have the JDBC standard API classes
+        available to it.  For a JDK 1.2 or later container, these APIs
+        are included in the standard platform.</li>
+    <li>When connection pooling is implemented, <code>JDBCRealm</code>
+        must have the JDBC Optional Package (version 2.0 or later) APIs
+        available to it.  This library is available as a separate
+        download (and will be included in Tomcat binary distributions).</li>
+    </ul>
+
+  </subsection>
+
+
+</section>
+
+
+<section name="Functionality">
+
+
+  <subsection name="Overview of Operation">
+
+    <p>The main purpose of <code>JDBCRealm</code> is to allow Catalina to
+    authenticate users, and look up the corresponding security roles, from
+    the information found in a relational database accessed via JDBC APIs.
+    For maximum flexibility, the details of how this is done (for example,
+    the names of the required tables and columns) should be configurable.</p>
+
+    <p>Each time that Catalina needs to authenticate a user, it will call
+    the <code>authenticate()</code> method of this Realm implementation,
+    passing the username and password that were specified by the user.  If
+    we find the user in the database (and match on the password), we accumulate
+    all of the security roles that are defined for this user, and create a
+    new <code>GenericPrincipal</code> object to be returned.  If the user
+    is not authenticated, we return <code>null</code> instead.  The
+    <code>GenericUser</code> object caches the set of security roles that
+    were owned by this user at the time of authentication, so that calls to
+    <code>isUserInRole()</code> can be answered without going back to the
+    database every time.</p>
+
+  </subsection>
+
+
+  <subsection name="Detailed Functional Requirements">
+
+
+    <h3>Configurable Properties</h3>
+
+    <p>The implementation shall support the following properties
+    that can be configured with JavaBeans property setters:</p>
+    <ul>
+    <li>Configuration parameters defining the JDBC driver to use, the
+        database connection URL to be accessed, and the username/password
+        to use for logging in. [Current]</li>
+    <li>Configuration parameters describing the connection pool to be
+        created to support simultaneous authentications. [Requested]</li>
+    <li>Name of the tables to be searched for users and roles. [Current]</li>
+    <li>Name of the columns to be used for usernames, passwords, and
+        role names.  [Current]</li>
+    </ul>
+
+    <h3>Lifecycle Functionality</h3>
+
+    <p>The following processing must be performed when the <code>start()</code>
+    method is called:</p>
+    <ul>
+    <li>Establish a connection to the configured database, using the
+        configured username and password.  [Current]</li>
+    <li>Configure and establish a connection pool of connections to the
+        database.  [Requested]</li>
+    </ul>
+
+    <p>The following processing must be performed when the <code>stop()</code>
+    method is called:</p>
+    <ul>
+    <li>Close any opened connections to the database.</li>
+    </ul>
+
+
+    <h3>Method authenticate() Functionality</h3>
+
+    <p>When <code>authenticate()</code> is called, the following processing
+    is required:</p>
+    <ul>
+    <li>Acquire the one and only connection [Current] or acquire a connection
+        from the connection pool [Requested].</li>
+    <li>Select the one and only row from the user's table for this user,
+        and retrieve the corresponding password column.  If zero rows (or
+        more than one row) are found, return <code>null</code>.</li>
+    <li>Authenticate the user by comparing the (possibly encrypted) password
+        value that was received against the password presented by the user.
+        If there is no match, return <code>null</code>.</li>
+    <li>Acquire a <code>List</code> of the security roles assigned to the
+        authenticated user by selecting from the roles table.</li>
+    <li>Construct a new instance of class
+        <code>org.apache.catalina.realm.GenericPrincipal</code>, passing as
+        constructor arguments:  this realm instance, the authenticated
+        username, and a <code>List</code> of the security roles associated
+        with this user.</li>
+    <li><strong>WARNING</strong> - Do not attempt to cache and reuse previous
+        <code>GenericPrincipal</code> objects for a particular user, because
+        the information in the directory server might have changed since the
+        last time this user was authenticated.</li>
+    <li>Return the newly constructed <code>GenericPrincipal</code>.</li>
+    </ul>
+
+
+    <h3>Method hasRole() Functionality</h3>
+
+    <p>When <code>hasRole()</code> is called, the following processing
+    is required:</p>
+    <ul>
+    <li>The <code>principal</code> that is passed as an argument SHOULD
+        be one that we returned (instanceof class
+        <code>org.apache.catalina.realm.GenericPrincipal</code>, with a
+        <code>realm</code> property that is equal to our instance.</li>
+    <li>If the passed <code>principal</code> meets these criteria, check
+        the specified role against the list returned by
+        <code>getRoles()</code>, and return <code>true</code> if the
+        specified role is included; otherwise, return <code>false</code>.</li>
+    <li>If the passed <code>principal</code> does not meet these criteria,
+        return <code>false</code>.</li>
+    </ul>
+
+  </subsection>
+
+</section>
+
+
+<section name="Testable Assertions">
+
+  <p>In addition the the assertions implied by the functionality requirements
+  listed above, the following additional assertions shall be tested to
+  validate the behavior of <code>JDBCRealm</code>:</p>
+  <ul>
+  </ul>
+
+</section>
+
+
+</body>
+
+</document>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/funcspecs/fs-jndi-realm.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/funcspecs/fs-jndi-realm.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/funcspecs/fs-jndi-realm.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,403 @@
+<?xml version="1.0"?>
+<!DOCTYPE document [
+  <!ENTITY project SYSTEM "project.xml">
+]>
+<document url="fs-jndi-realm.html">
+
+  &project;
+
+  <properties>
+    <author email="craigmcc at apache.org">Craig McClanahan</author>
+    <title>JNDIRealm</title>
+    <revision>$Id: fs-jndi-realm.xml 301460 2003-01-15 03:40:45Z glenn $</revision>
+  </properties>
+
+<body>
+
+
+<section name="Overview">
+
+
+  <subsection name="Introduction">
+
+    <p>The purpose of the <strong>JNDIRealm</strong> implementation is to
+    provide a mechanism by which Tomcat 5 can acquire information needed
+    to authenticate web application users, and define their security roles,
+    from a directory server or other service accessed via JNDI APIs.  For
+    integration with Catalina, this class must implement the
+    <code>org.apache.catalina.Realm</code> interface.</p>
+
+    <p>This specification reflects a combination of functionality that is
+    already present in the <code>org.apache.catalina.realm.JNDIRealm</code>
+    class, as well as requirements for enhancements that have been
+    discussed.  Where appropriate, requirements statements are marked
+    <em>[Current]</em> and <em>[Requested]</em> to distinguish them.</p>
+
+    <p>The current status of this functional specification is
+    <strong>PROPOSED</strong>.  It has not yet been discussed and
+    agreed to on the TOMCAT-DEV mailing list.</p>
+
+    <p>The code in the current version of <code>JNDIRealm</code>, and the
+    ideas expressed in this functional specification, are the results of
+    contributions from many individuals, including (alphabetically):</p>
+    <ul>
+    <li>Holman, John &lt;j.g.holman at qmw.ac.uk&gt;</li>
+    <li>Lockhart, Ellen &lt;elockhart at home.com&gt;</li>
+    <li>McClanahan, Craig &lt;craigmcc at apache.org&gt;</li>
+    </ul>
+
+  </subsection>
+
+
+  <subsection name="External Specifications">
+
+    <p>The implementation of this functionality depends on the following
+    external specifications:</p>
+    <ul>
+    <li><a href="http://java.sun.com/products/jndi/">Java Naming and
+        Directory Interface</a> (version 1.2.1 or later)</li>
+    </ul>
+
+  </subsection>
+
+
+  <subsection name="Implementation Requirements">
+
+    <p>The implementation of this functionality shall conform to the
+    following requirements:</p>
+    <ul>
+    <li>Be realized in one or more implementation classes.</li>
+    <li>Implement the <code>org.apache.catalina.Realm</code> interface.
+        [Current]</li>
+    <li>Implement the <code>org.apache.catalina.Lifecycle</code>
+        interface.  [Current]</li>
+    <li>Subclass the <code>org.apache.catalina.realm.RealmBase</code>
+        base class.</li>
+    <li>Live in the <code>org.apache.catalina.realm</code> package.
+        [Current]</li>
+    <li>Support a configurable debugging detail level. [Current]</li>
+    <li>Log debugging and operational messages (suitably internationalized)
+        via the <code>getContainer().log()</code> method. [Current]</li>
+    </ul>
+
+  </subsection>
+
+
+</section>
+
+
+<section name="Dependencies">
+
+
+  <subsection name="Environmental Dependencies">
+
+    <p>The following environmental dependencies must be met in order for
+    JNDIRealm to operate correctly:</p>
+    <ul>
+    <li>The desire to utilize JNDIRealm must be registered in
+        <code>$CATALINA_HOME/conf/server.xml</code>, in a
+        <code>&lt;Realm&gt;</code> element that is nested inside a
+        corresponding <code>&lt;Engine&gt;</code>, <code>&lt;Host&gt;</code>,
+        or <code>&lt;Context&gt;</code> element.</li>
+    <li>If the <em>Administrator Login</em> operational mode is selected,
+        the configured administrator username and password must be configured
+        in the corresponding directory server.</li>
+    <li>If the <em>Username Login</em> operational mode is selected,
+        the corresponding directory server must be configured to accept
+        logins with the username and password that will be passed to
+        <code>JNDIRealm</code> by the appropriate <code>Authenticator</code>.
+        </li>
+    </ul>
+
+  </subsection>
+
+
+  <subsection name="Container Dependencies">
+
+    <p>Correct operation of JNDIRealm depends on the following
+    specific features of the surrounding container:</p>
+    <ul>
+    <li>Interactions with <code>JNDIRealm</code> will be initiated by
+        the appropriate <code>Authenticator</code> implementation, based
+        on the login method that is selected.</li>
+    <li><code>JNDIRealm</code> must have the JNDI API classes available
+        to it.  For a JDK 1.2 container, that means <code>jndi.jar</code>
+        and the appropriate implementation (such as <code>ldap.jar</code>)
+        must be placed in the <code>server/lib</code> directory.</li>
+    </ul>
+
+  </subsection>
+
+
+</section>
+
+
+<section name="Functionality">
+
+
+  <subsection name="Operational Modes">
+
+    <p>The completed <code>JNDIRealm</code> must support two major operational
+    modes in order to support all of the required use cases.  For the purposes
+    of this document, the modes are called <em>administrator login</em> and
+    <em>Username Login</em>.  They are described further in the following
+    paragraphs.</p>
+
+    <p>For <em>Administrator Login</em> mode, <code>JNDIRealm</code> will be
+    configured to establish one or more connections (using a connection pool)
+    to an appropriate directory server, using JNDI APIs, under a "system
+    administrator" username and password.  This is similar to the approach
+    normally used to configure <code>JDBCRealm</code> to access authentication
+    and access control information in a database.  It is assumed that the
+    system administrator username and password that are configured provide
+    sufficient privileges within the directory server to read (but not modify)
+    the username, password, and assigned roles for each valid user of the
+    web application associated with this <code>Realm</code>.  The password
+    can be stored in cleartext, or in one of the digested modes supported by
+    the <code>org.apache.catalina.realm.RealmBase</code> base class.</p>
+
+    <p>For <em>Username Login</em> mode, <code>JNDIRealm</code> does not
+    normally remain connected to the directory server.  Instead, whenever a
+    user is to be authenticated, a connection to the directory server
+    (using the username and password received from the authenticator) is
+    attempted.  If this connection is successful, the user is assumed to be
+    successfully authenticated.  This connection is then utilized to read
+    the corresponding security roles associated with this user, and the
+    connection is then broken.</p>
+
+    <p><strong>NOTE</strong> - <em>Username Login</em> mode cannot be used
+    if you have selected login method <code>DIGEST</code> in your web
+    application deployment descriptor (<code>web.xml</code>) file.  This
+    restriction exists because the cleartext password is never available
+    to the container, so it is not possible to bind to the directory server
+    using the user's username and password.</p>
+
+    <p>Because these operational modes work so differently, the functionality
+    for each mode will be described separately.  Whether or not both modes
+    are actually supported by a single class (versus a class per mode) is
+    an implementation detail left to the designer.</p>
+
+    <p><strong>NOTE</strong> - The current implementation only implements
+    part of the <em>Administrator Lookup</em> mode requirements.  It does
+    not support the <em>Username Lookup</em> mode at all, at this point.</p>
+
+  </subsection>
+
+
+  <subsection name="Administrator Login Mode Functionality">
+
+
+    <h3>Configurable Properties</h3>
+
+    <p>The implementation shall support the following properties
+    that can be configured with JavaBeans property setters:</p>
+    <ul>
+    <li><code>connectionURL</code> - URL of the directory server we will
+        be contacting.</li>
+    <li><code>contextFactory</code> - Fully qualified class name of the JNDI
+        context factory used to retrieve our InitialContext.
+        [com.sun.jndi.ldap.LdapCtxFactory]</li>
+    <li>Additional configuration properties required to establish the
+        appropriate connection.  [Requested]</li>
+    <li>Connection pool configuration properties.  [Requested]</li>
+    <li>Configuration properties defining how a particular user is
+        authenticated.  The following capabilities should be supported:
+        <ul>
+        <li>Substitute the specified username into a string.  [Requested]</li>
+        <li>Retrieve the distinguished name (DN) of an authorized user via an
+            LDAP search string with a replacement placeholder for the
+            username, and comparison of the password to a configurable
+            attribute retrieved from the search result.  [Current]</li>
+        </ul></li>
+    <li>Configuration properties defining how the roles associated with a
+        particular authenticated user can be retrieved.  The following
+        approaches should be supported:
+        <ul>
+        <li>Retrieve a specified attribute (possibly multi-valued)
+            from an LDAP search expression,
+            with a replacement placeholder for the DN of the user.
+            [Current]</li>
+        <li>Retrieve a set of role names that are defined implicitly (by
+            selecting principals that match a search pattern) rather than
+            explicitly (by finding a particular attribute value).
+            [Requested]</li>
+        </ul></li>
+    </ul>
+
+    <h3>Lifecycle Functionality</h3>
+
+    <p>The following processing must be performed when the <code>start()</code>
+    method is called:</p>
+    <ul>
+    <li>Establish a connection to the configured directory server, using the
+        configured system administrator username and password.  [Current]</li>
+    <li>Configure and establish a connection pool of connections to the
+        directory server.  [Requested]</li>
+    </ul>
+
+    <p>The following processing must be performed when the <code>stop()</code>
+    method is called:</p>
+    <ul>
+    <li>Close any opened connections to the directory server.</li>
+    </ul>
+
+
+    <h3>Method authenticate() Functionality</h3>
+
+    <p>When <code>authenticate()</code> is called, the following processing
+    is required:</p>
+    <ul>
+    <li>Acquire the one and only connection [Current] or acquire a connection
+        from the connection pool [Requested].</li>
+    <li>Authenticate the user by retrieving the user's Distinguished Name,
+        based on the specified username and password.</li>
+    <li>If the user was not authenticated, release the allocated connection
+        and return <code>null</code>.</li>
+    <li>Acquire a <code>List</code> of the security roles assigned to the
+        authenticated user.</li>
+    <li>Construct a new instance of class
+        <code>org.apache.catalina.realm.GenericPrincipal</code>, passing as
+        constructor arguments:  this realm instance, the authenticated
+        username, and a <code>List</code> of the security roles associated
+        with this user.</li>
+    <li><strong>WARNING</strong> - Do not attempt to cache and reuse previous
+        <code>GenericPrincipal</code> objects for a particular user, because
+        the information in the directory server might have changed since the
+        last time this user was authenticated.</li>
+    <li>Return the newly constructed <code>GenericPrincipal</code>.</li>
+    </ul>
+
+
+    <h3>Method hasRole() Functionality</h3>
+
+    <p>When <code>hasRole()</code> is called, the following processing
+    is required:</p>
+    <ul>
+    <li>The <code>principal</code> that is passed as an argument SHOULD
+        be one that we returned (instanceof class
+        <code>org.apache.catalina.realm.GenericPrincipal</code>, with a
+        <code>realm</code> property that is equal to our instance.</li>
+    <li>If the passed <code>principal</code> meets these criteria, check
+        the specified role against the list returned by
+        <code>getRoles()</code>, and return <code>true</code> if the
+        specified role is included; otherwise, return <code>false</code>.</li>
+    <li>If the passed <code>principal</code> does not meet these criteria,
+        return <code>false</code>.</li>
+    </ul>
+
+  </subsection>
+
+
+  <subsection name="Username Login Mode Functionality">
+
+    <h3>Configurable Properties</h3>
+
+    <p>The implementation shall support the following properties
+    that can be configured with JavaBeans property setters:</p>
+    <ul>
+    <li><code>connectionURL</code> - URL of the directory server we will
+        be contacting.</li>
+    <li><code>contextFactory</code> - Fully qualified class name of the JNDI
+        context factory used to retrieve our InitialContext.
+        [com.sun.jndi.ldap.LdapCtxFactory]</li>
+    <li>Additional configuration properties required to establish the
+        appropriate connection.  [Requested]</li>
+    <li>Connection pool configuration properties.  [Requested]</li>
+    <li>Configuration properties defining if and how a user might be looked
+        up before binding to the directory server.  The following approaches
+        should be supported:
+        <ul>
+        <li>No previous lookup is required - username specified by the user
+            is the same as that used to authenticate to the directory
+            server.</li>
+        <li>Substitute the specified username into a string.</li>
+        <li>Search the directory server based on configured criteria to
+            retrieve the distinguished name of the user, then attempt to
+            bind with that distinguished name.</li>
+        </ul></li>
+    <li>Configuration properties defining how the roles associated with a
+        particular authenticated user can be retrieved.  The following
+        approaches should be supported:
+        <ul>
+        <li>Retrieve a specified attribute (possibly multi-valued)
+            from an LDAP search expression,
+            with a replacement placeholder for the DN of the user.
+            [Current]</li>
+        </ul></li>
+    </ul>
+
+    <h3>Lifecycle Functionality</h3>
+
+    <p>The following processing must be performed when the <code>start()</code>
+    method is called:</p>
+    <ul>
+    <li>None required.</li>
+    </ul>
+
+    <p>The following processing must be performed when the <code>stop()</code>
+    method is called:</p>
+    <ul>
+    <li>None required.</li>
+    </ul>
+
+
+    <h3>Method authenticate() Functionality</h3>
+
+    <p>When <code>authenticate()</code> is called, the following processing
+    is required:</p>
+    <ul>
+    <li>Attempt to bind to the directory server, using the username and
+        password provided by the user.</li>
+    <li>If the user was not authenticated, release the allocated connection
+        and return <code>null</code>.</li>
+    <li>Acquire a <code>List</code> of the security roles assigned to the
+        authenticated user.</li>
+    <li>Construct a new instance of class
+        <code>org.apache.catalina.realm.GenericPrincipal</code>, passing as
+        constructor arguments:  this realm instance, the authenticated
+        username, and a <code>List</code> of the security roles associated
+        with this user.</li>
+    <li><strong>WARNING</strong> - Do not attempt to cache and reuse previous
+        <code>GenericPrincipal</code> objects for a particular user, because
+        the information in the directory server might have changed since the
+        last time this user was authenticated.</li>
+    <li>Return the newly constructed <code>GenericPrincipal</code>.</li>
+    </ul>
+
+
+    <h3>Method hasRole() Functionality</h3>
+
+    <p>When <code>hasRole()</code> is called, the following processing
+    is required:</p>
+    <ul>
+    <li>The <code>principal</code> that is passed as an argument SHOULD
+        be one that we returned (instanceof class
+        <code>org.apache.catalina.realm.GenericPrincipal</code>, with a
+        <code>realm</code> property that is equal to our instance.</li>
+    <li>If the passed <code>principal</code> meets these criteria, check
+        the specified role against the list returned by
+        <code>getRoles()</code>, and return <code>true</code> if the
+        specified role is included; otherwise, return <code>false</code>.</li>
+    <li>If the passed <code>principal</code> does not meet these criteria,
+        return <code>false</code>.</li>
+    </ul>
+
+  </subsection>
+
+</section>
+
+
+<section name="Testable Assertions">
+
+  <p>In addition the the assertions implied by the functionality requirements
+  listed above, the following additional assertions shall be tested to
+  validate the behavior of <code>JNDIRealm</code>:</p>
+  <ul>
+  </ul>
+
+</section>
+
+
+</body>
+
+</document>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/funcspecs/fs-memory-realm.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/funcspecs/fs-memory-realm.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/funcspecs/fs-memory-realm.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,239 @@
+<?xml version="1.0"?>
+<!DOCTYPE document [
+  <!ENTITY project SYSTEM "project.xml">
+]>
+<document url="fs-memory-realm.html">
+
+  &project;
+
+  <properties>
+    <author email="craigmcc at apache.org">Craig McClanahan</author>
+    <title>MemoryRealm</title>
+    <revision>$Id: fs-memory-realm.xml 301460 2003-01-15 03:40:45Z glenn $</revision>
+  </properties>
+
+<body>
+
+
+<section name="Overview">
+
+
+  <subsection name="Introduction">
+
+    <p>The purpose of the <strong>MemoryRealm</strong> implementation is to
+    provide a mechanism by which Tomcat 5 can acquire information needed
+    to authenticate web application users, and define their security roles,
+    from a simple text-based configuration file in XML format.  This is
+    intended to simplify the initial installation and operation of Tomcat 5,
+    without the complexity of configuring a database or directory server
+    based Realm.  It is not intended for production use.</p>
+
+    <p>This specification reflects a combination of functionality that is
+    already present in the <code>org.apache.catalina.realm.MemoryRealm</code>
+    class, as well as requirements for enhancements that have been
+    discussed.  Where appropriate, requirements statements are marked
+    <em>[Current]</em> and <em>[Requested]</em> to distinguish them.</p>
+
+    <p>The current status of this functional specification is
+    <strong>PROPOSED</strong>.  It has not yet been discussed and
+    agreed to on the TOMCAT-DEV mailing list.</p>
+
+  </subsection>
+
+
+  <subsection name="External Specifications">
+
+    <p>The implementation of this functionality depends on the following
+    external specifications:</p>
+    <ul>
+    <li>None</li>
+    </ul>
+
+  </subsection>
+
+
+  <subsection name="Implementation Requirements">
+
+    <p>The implementation of this functionality shall conform to the
+    following requirements:</p>
+    <ul>
+    <li>Be realized in one or more implementation classes.</li>
+    <li>Implement the <code>org.apache.catalina.Realm</code> interface.
+        [Current]</li>
+    <li>Implement the <code>org.apache.catalina.Lifecycle</code>
+        interface.  [Current]</li>
+    <li>Subclass the <code>org.apache.catalina.realm.RealmBase</code>
+        base class.</li>
+    <li>Live in the <code>org.apache.catalina.realm</code> package.
+        [Current]</li>
+    <li>Support a configurable debugging detail level. [Current]</li>
+    <li>Log debugging and operational messages (suitably internationalized)
+        via the <code>getContainer().log()</code> method. [Current]</li>
+    </ul>
+
+  </subsection>
+
+
+</section>
+
+
+<section name="Dependencies">
+
+
+  <subsection name="Environmental Dependencies">
+
+    <p>The following environmental dependencies must be met in order for
+    MemoryRealm to operate correctly:</p>
+    <ul>
+    <li>The desire to utilize MemoryRealm must be registered in
+        <code>$CATALINA_HOME/conf/server.xml</code>, in a
+        <code>&lt;Realm&gt;</code> element that is nested inside a
+        corresponding <code>&lt;Engine&gt;</code>, <code>&lt;Host&gt;</code>,
+        or <code>&lt;Context&gt;</code> element.  (This is already
+        included in the default <code>server.xml</code> file.)</li>
+    </ul>
+
+  </subsection>
+
+
+  <subsection name="Container Dependencies">
+
+    <p>Correct operation of MemoryRealm depends on the following
+    specific features of the surrounding container:</p>
+    <ul>
+    <li>Interactions with <code>MemoryRealm</code> will be initiated by
+        the appropriate <code>Authenticator</code> implementation, based
+        on the login method that is selected.</li>
+    <li><code>MemoryRealm</code> must have an XML parser compatible with
+        the JAXP/1.1 APIs available to it.  This is normally accomplished
+        by placing the corresponding JAR files in directory
+        <code>$CATALINA_HOME/server/lib</code> (to make them visible only
+        to internal Catalina classes) or in directory
+        <code>$CATALINA_HOME/common/lib</code> (to make them visible to
+        Catalina internal classes <strong>and</strong> installed web
+        applications).</li>
+    </ul>
+
+  </subsection>
+
+
+</section>
+
+
+<section name="Functionality">
+
+
+  <subsection name="Overview of Operation">
+
+    <p>The main purpose of <code>MemoryRealm</code> is to allow Catalina to
+    authenticate users, and look up the corresponding security roles, from
+    the information found in an XML-format configuration file.  The format
+    of this file is described below.  When a <code>MemoryRealm</code>
+    instance is started, it will read the contents of this XML file and create
+    an "in memory database" of all the valid users and their associated
+    security roles.</p>
+
+    <p>Each time that Catalina needs to authenticate a user, it will call
+    the <code>authenticate()</code> method of this Realm implementation,
+    passing the username and password that were specified by the user.  If
+    we find the user in the database (and match on the password), we accumulate
+    all of the security roles that are defined for this user, and create a
+    new <code>GenericPrincipal</code> object to be returned.  If the user
+    is not authenticated, we return <code>null</code> instead.  The
+    <code>GenericUser</code> object caches the set of security roles that
+    were owned by this user at the time of authentication, so that calls to
+    <code>isUserInRole()</code> can be answered without going back to the
+    database every time.</p>
+
+  </subsection>
+
+
+  <subsection name="Detailed Functional Requirements">
+
+
+    <h3>Configurable Properties</h3>
+
+    <p>The implementation shall support the following properties
+    that can be configured with JavaBeans property setters:</p>
+    <ul>
+    <li>Configurable debugging detail level.</li>
+    <li>Configurable file pathname (absolute or relative to
+        <code>$CATALINA_HOME</code> of the XML file containing our
+        defined users.  [<code>conf/tomcat-users.xml</code>].</li>
+    </ul>
+
+    <h3>Lifecycle Functionality</h3>
+
+    <p>The following processing must be performed when the <code>start()</code>
+    method is called:</p>
+    <ul>
+    <li>Open and parse the specified XML file.</li>
+    <li>Create an in-memory database representation of the XML file
+        contents.</li>
+    <li><strong>NOTE</strong> - There is no requirement to recognize
+        subsequent changes to the contents of the XML file.</li>
+    </ul>
+
+    <p>The following processing must be performed when the <code>stop()</code>
+    method is called:</p>
+    <ul>
+    <li>Release object references to the in-memory database representation.</li>
+    </ul>
+
+
+    <h3>Method authenticate() Functionality</h3>
+
+    <p>When <code>authenticate()</code> is called, the following processing
+    is required:</p>
+    <ul>
+    <li>Select the one and only "user" instance from the in-memory database,
+        based on matching the specified username.  If there is no such
+        instance, return <code>null</code>.</li>
+    <li>Authenticate the user by comparing the (possibly encrypted) password
+        value that was received against the password presented by the user.
+        If there is no match, return <code>null</code>.</li>
+    <li>Construct a new instance of class
+        <code>org.apache.catalina.realm.GenericPrincipal</code> (if not
+        already using this as the internal database representation) that
+        contains the authenticated username and a <code>List</code> of the
+        security roles associated with this user.</li>
+    <li>Return the newly constructed <code>GenericPrincipal</code>.</li>
+    </ul>
+
+
+    <h3>Method hasRole() Functionality</h3>
+
+    <p>When <code>hasRole()</code> is called, the following processing
+    is required:</p>
+    <ul>
+    <li>The <code>principal</code> that is passed as an argument SHOULD
+        be one that we returned (instanceof class
+        <code>org.apache.catalina.realm.GenericPrincipal</code>, with a
+        <code>realm</code> property that is equal to our instance.</li>
+    <li>If the passed <code>principal</code> meets these criteria, check
+        the specified role against the list returned by
+        <code>getRoles()</code>, and return <code>true</code> if the
+        specified role is included; otherwise, return <code>false</code>.</li>
+    <li>If the passed <code>principal</code> does not meet these criteria,
+        return <code>false</code>.</li>
+    </ul>
+
+  </subsection>
+
+</section>
+
+
+<section name="Testable Assertions">
+
+  <p>In addition the the assertions implied by the functionality requirements
+  listed above, the following additional assertions shall be tested to
+  validate the behavior of <code>MemoryRealm</code>:</p>
+  <ul>
+  </ul>
+
+</section>
+
+
+</body>
+
+</document>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/funcspecs/index.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/funcspecs/index.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/funcspecs/index.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,54 @@
+<?xml version="1.0"?>
+<!DOCTYPE document [
+  <!ENTITY project SYSTEM "project.xml">
+]>
+<document url="index.html">
+
+  &project;
+
+  <properties>
+    <author email="craigmcc at apache.org">Craig R. McClanahan</author>
+    <title>Table of Contents</title>
+  </properties>
+
+<body>
+
+
+<section name="Catalina Functional Specifications">
+
+<p>This documentation area includes <em>functional specifications</em> for
+many features supported by the <strong>Catalina</strong> servlet container
+portion of Tomcat 5.  In most cases, these features are not documented in the
+underlying Servlet or JSP specifications, so a definition of the expected
+correct behavior is important both to implementors of those features, and to
+test writers trying to decide what to test.</p>
+
+<p>The functional specifications are divided into the following categories
+in the menu (to the left):</p>
+<ul>
+<li><em>Administrative Apps</em> - Overall requirements for supporting an
+    ability to configure and operate a Tomcat 5 installation through tools,
+    as well as detailed requirements for the tools themselves.</li>
+<li><em>Internal Servlets</em> - Requirements for Catalina features that are
+    implemented as internal, container-managed, servlets.</li>
+<li><em>Realm Implementations</em> - Requirements for the implementations of
+    the <code>org.apache.catalina.Realm</code> interface (providing access to
+    collections of users, passwords and roles) that are included in the
+    standard Tomcat 5 distribution.</li>
+</ul>
+
+<p><em>NOTE</em> - In some cases, the contents of these functional specs has
+been "reverse engineered" from existing implementations.  This exercise is
+stil useful, because it provides an introduction to <strong>what</strong>
+Catalina does, without being as concerned with <strong>how</strong> this is
+accomplished.</p>
+
+<p><strong>TODO</strong> - Obviously, this area has a long ways to go before
+it is complete.  Contributions are welcome!</p>
+
+</section>
+
+
+</body>
+
+</document>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/funcspecs/mbean-names.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/funcspecs/mbean-names.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/funcspecs/mbean-names.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,870 @@
+<?xml version="1.0"?>
+<!DOCTYPE document [
+  <!ENTITY project SYSTEM "project.xml">
+]>
+<document url="mbean-names.html">
+
+  &project;
+
+  <properties>
+    <author email="craigmcc at apache.org">Craig McClanahan</author>
+    <author email="amyroh at apache.org">Amy Roh</author>
+    <title>Tomcat MBean Names</title>
+    <revision>$Id: mbean-names.xml 303281 2004-09-27 16:00:31Z yoavs $</revision>
+  </properties>
+
+<body>
+
+
+<section name="Background">
+
+    <p>We will be using <em>JMX MBeans</em> as the technology for
+    implementing manageability of Tomcat.</p>
+
+    <p>One of the key concepts of JMX (and JSR-77) is that each management
+    bean has a unique name in the MBeanServer's registry, and that
+    management applications can utilize these names to retrieve the MBean
+    of interest to them for a particular management operation.
+    This document proposes a naming convention for MBeans that allows easy
+    calculation of the name for a particular MBean.  For background
+    information on JMX MBean names, see the <em>Java Management Extensions
+    Instrumentation and Agent Specification</em>, version 1.0, section 6.
+    In particular, we will be discussing the String Representation of
+    <code>ObjectName</code> instances.</p>
+
+</section>
+
+<section name="Catalina Object Hierarchy">
+
+<p>Tomcat's servlet container implementation, called Catalina, can be
+represented as a hierarchy of objects that contain references to each other.
+The object hierarchy can be represented as a tree, or (isomorphically) based
+on the nesting of configuration elements in the <code>conf/server.xml</code>
+file that is traditionally used to configure Tomcat stand-alone.</p>
+
+<p>The valid component nestings for Catalina are depicted in the following
+table, with columns that contain the following values:</p>
+<ul>
+<li><em>Pattern</em> - Nesting pattern of XML elements (in the
+    <code>conf/server.xml</code> file) used to configure this component.</li>
+<li><em>Cardinality</em> - Minimum and maximum number of occurrences of
+    this element at this nesting position, which also corresponds to the
+    minimum and maximum number of Catalina components.</li>
+<li><em>Identifier</em> - Name of the JavaBeans property of this component
+    that represents the unique identifier (within the nested hierarchy),
+    if any.</li>
+<li><em>MBean ObjectName</em> - The portion of the MBean object name that
+    appears <strong>after</strong> the domain name.  For now, it should be
+    assumed that all of these MBeans appear in the default JMX domain.</li>
+</ul>
+
+<p>In the <em>MBean ObjectName</em> descriptions, several types of symbolic
+expressions are utilized to define variable text that is replaced by
+corresponding values:</p>
+<ul>
+<li><em>${GROUP}</em> - One of the standard MBean names of the specified
+    "group" category.  For example, the expression <code>${REALM}</code>
+    represents the values like <code>JDBCRealm</code> and <code>JAASRealm</code>
+    that identify the various MBeans for possible <code>Realm</code> components.</li>
+<li><em>${name}</em> - Replaced by the value of property <code>name</code>
+    from the current component.</li>
+<li><em>${parent.name}</em> - Replaced by the value of property
+    <code>name</code> from a parent of the current component, with the
+    parent's type identified by <em>parent</em>.</li>
+<li><em>${###}</em> - An arbitrary numeric identifier that preserves
+    order but has no other particular meaning.  In general, the server will
+    assign numeric values to existing instances with large gaps into which
+    new items can be configured if desired.</li>
+</ul>
+
+<table border="1" cellpadding="5">
+
+  <tr>
+    <th align="center" bgcolor="aqua">Pattern</th>
+    <th align="center" bgcolor="aqua">Cardinality</th>
+    <th align="center" bgcolor="aqua">Identifier</th>
+    <th align="center" bgcolor="aqua">MBean ObjectName</th>
+  </tr>
+
+  <tr>
+    <td>Server</td>
+    <td align="center">1..1</td>
+    <td align="center">(none)</td>
+    <td><code>type=${SERVER}</code></td>
+  </tr>
+
+  <tr>
+    <td>Server / Listener</td>
+    <td align="center">0..n</td>
+    <td align="center">(none)</td>
+    <td><code>type=${LISTENER}, sequence=${###}</code></td>
+  </tr>
+
+  <tr>
+    <td>Server / Service</td>
+    <td align="center">1..n</td>
+    <td align="center"><code>name</code></td>
+    <td><code>type=${SERVICE}, name=${name}</code></td>
+  </tr>
+
+  <tr>
+    <td>Server / Service / Connector</td>
+    <td align="center">1..n</td>
+    <td align="center"><code>address, port</code></td>
+    <td><code>type=${CONNECTOR}, service=${service}, port=${port},
+        address=${address}</code></td>
+  </tr>
+
+  <tr>
+    <td>Server / Service / Connector / Factory</td>
+    <td align="center">0..1</td>
+    <td align="center">(none)</td>
+    <td>(Only defined explicitly for an SSL connector, but can be treated
+        as part of the connector component)</td>
+  </tr>
+
+  <tr>
+    <td>Server / Service / Connector / Listener</td>
+    <td align="center">0..n</td>
+    <td align="center">(none)</td>
+    <td><code>type=${LISTENER}, sequence=${###}, service=${service},
+        port=${connector.port}, address=${connector.address}</code></td>
+  </tr>
+
+  <tr>
+    <td>Server / Service / Engine</td>
+    <td align="center">1..1</td>
+    <td align="center">(none)</td>
+    <td><code>type=${ENGINE}, service=${service.name}</code></td>
+  </tr>
+
+  <tr>
+    <td>Server / Service / Engine / DefaultContext</td>
+    <td align="center">0..1</td>
+    <td align="center">(none)</td>
+    <td><code>type=${DEFAULT-CONTEXT}, service=${service.name}</code></td>
+  </tr>
+
+<!--
+  <tr>
+    <td>Server / Service / Engine / DefaultContext / InstanceListener</td>
+    <td align="center">0..n</td>
+    <td align="center">(none)</td>
+    <td></td>
+  </tr>
+
+  <tr>
+    <td>Server / Service / Engine / DefaultContext / Listener</td>
+    <td align="center">0..n</td>
+    <td align="center">(none)</td>
+    <td><code>type=${LISTENER}, sequence=${###}</code></td>
+    <td></td>
+  </tr>
+
+  <tr>
+    <td>Server / Service / Engine / DefaultContext / Loader</td>
+    <td align="center">0..1</td>
+    <td align="center">(none)</td>
+    <td></td>
+  </tr>
+
+  <tr>
+    <td>Server / Service / Engine / DefaultContext / Manager</td>
+    <td align="center">0..1</td>
+    <td align="center">(none)</td>
+    <td></td>
+  </tr>
+
+  <tr>
+    <td>Server / Service / Engine / DefaultContext / Realm</td>
+    <td align="center">0..1</td>
+    <td align="center">(none)</td>
+    <td></td>
+  </tr>
+
+  <tr>
+    <td>Server / Service / Engine / DefaultContext / Resources</td>
+    <td align="center">0..1</td>
+    <td align="center">(none)</td>
+    <td></td>
+  </tr>
+
+  <tr>
+    <td>Server / Service / Engine / DefaultContext / Valve</td>
+    <td align="center">0..n</td>
+    <td align="center">(none)</td>
+    <td></td>
+  </tr>
+
+  <tr>
+    <td>Server / Service / Engine / DefaultContext / WrapperLifecycle</td>
+    <td align="center">0..n</td>
+    <td align="center">(none)</td>
+    <td></td>
+  </tr>
+
+  <tr>
+    <td>Server / Service / Engine / DefaultContext / WrapperListener</td>
+    <td align="center">0..n</td>
+    <td align="center">(none)</td>
+    <td></td>
+  </tr>
+-->
+
+  <tr>
+    <td>Server / Service / Engine / Host</td>
+    <td align="center">1..n</td>
+    <td align="center"><code>name</code></td>
+    <td><code>type=${HOST}, host=${name},
+        service=${service.name}</code></td>
+  </tr>
+
+  <tr>
+    <td>Server / Service / Engine / Host / Context</td>
+    <td align="center">1..n</td>
+    <td align="center"><code>path</code></td>
+    <td><code>type=${CONTEXT}, path=${path}, host=${host.name},
+        service=${service.name}</code></td>
+  </tr>
+
+  <tr>
+    <td>Server / Service / Engine / Host / Context / InstanceListener</td>
+    <td align="center">0..n</td>
+    <td align="center">(none)</td>
+    <td><code>type=${INSTANCE-LISTENER}, sequence=${###}, path=${context.path},
+        host=${host.name}, service=${service.name}</code></td>
+  </tr>
+
+  <tr>
+    <td>Server / Service / Engine / Host / Context / Listener</td>
+    <td align="center">0..n</td>
+    <td align="center">(none)</td>
+    <td><code>type=${LISTENER}, sequence=${###}, path=${context.path},
+        host=${host.name}, service=${service.name}</code></td>
+  </tr>
+
+  <tr>
+    <td>Server / Service / Engine / Host / Context / Loader</td>
+    <td align="center">0..1</td>
+    <td align="center">(none)</td>
+    <td><code>type=${LOADER}, path=${context.path}, host=${host.name},
+        service=${service.name}</code></td>
+  </tr>
+
+  <tr>
+    <td>Server / Service / Engine / Host / Context / Manager</td>
+    <td align="center">0..1</td>
+    <td align="center">(none)</td>
+    <td><code>type=${MANAGER}, path=${context.path}, host=${host.name},
+        service=${service.name}</code></td>
+  </tr>
+
+  <tr>
+    <td>Server / Service / Engine / Host / Context / Realm</td>
+    <td align="center">0..1</td>
+    <td align="center">(none)</td>
+    <td><code>type=${REALM}, path=${context.path}, host=${host.name},
+        service=${service.name}</code></td>
+  </tr>
+
+  <tr>
+    <td>Server / Service / Engine / Host / Context / Resources</td>
+    <td align="center">0..1</td>
+    <td align="center">(none)</td>
+    <td><code>type=${RESOURCES}, path=${context.path}, host=${host.name},
+        service=${service.name}</code></td>
+  </tr>
+
+  <tr>
+    <td>Server / Service / Engine / Host / Context / Valve</td>
+    <td align="center">0..n</td>
+    <td align="center">(none)</td>
+    <td><code>type=${VALVE}, sequence=${###}, path=${context.path},
+        host=${host.name}, service=${service.name}</code></td>
+  </tr>
+
+  <tr>
+    <td>Server / Service / Engine / Host / Context / WrapperLifecycle</td>
+    <td align="center">0..n</td>
+    <td align="center">(none)</td>
+    <td><code>type=${WRAPPER-LIFECYCLE}, sequence=${###}, path=${context.path},
+        host=${host.name}, service=${service.name}</code></td>
+  </tr>
+
+  <tr>
+    <td>Server / Service / Engine / Host / Context / WrapperListener</td>
+    <td align="center">0..n</td>
+    <td align="center">(none)</td>
+    <td><code>type=${WRAPPER-LISTENER}, sequence=${###}, path=${context.path},
+        host=${host.name}, service=${service.name}</code></td>
+  </tr>
+
+  <tr>
+    <td>Server / Service / Engine / Host / DefaultContext</td>
+    <td align="center">0..1</td>
+    <td align="center">(none)</td>
+    <td><code>type=DefaultContext, host=${host.name},
+        service=${service.name}</code></td>
+  </tr>
+
+<!--
+  <tr>
+    <td>Server / Service / Engine / Host / DefaultContext / InstanceListener</td>
+    <td align="center">0..n</td>
+    <td align="center">(none)</td>
+    <td></td>
+  </tr>
+
+  <tr>
+    <td>Server / Service / Engine / Host / DefaultContext / Listener</td>
+    <td align="center">0..n</td>
+    <td align="center">(none)</td>
+    <td></td>
+  </tr>
+
+  <tr>
+    <td>Server / Service / Engine / Host / DefaultContext / Loader</td>
+    <td align="center">0..1</td>
+    <td align="center">(none)</td>
+    <td></td>
+  </tr>
+
+  <tr>
+    <td>Server / Service / Engine / Host / DefaultContext / Manager</td>
+    <td align="center">0..1</td>
+    <td align="center">(none)</td>
+    <td></td>
+  </tr>
+
+  <tr>
+    <td>Server / Service / Engine / Host / DefaultContext / Realm</td>
+    <td align="center">0..1</td>
+    <td align="center">(none)</td>
+    <td></td>
+  </tr>
+
+  <tr>
+    <td>Server / Service / Engine / Host / DefaultContext / Resources</td>
+    <td align="center">0..1</td>
+    <td align="center">(none)</td>
+    <td></td>
+  </tr>
+
+  <tr>
+    <td>Server / Service / Engine / Host / DefaultContext / Valve</td>
+    <td align="center">0..n</td>
+    <td align="center">(none)</td>
+    <td></td>
+  </tr>
+
+  <tr>
+    <td>Server / Service / Engine / Host / DefaultContext / WrapperLifecycle</td>
+    <td align="center">0..n</td>
+    <td align="center">(none)</td>
+    <td></td>
+  </tr>
+
+  <tr>
+    <td>Server / Service / Engine / Host / DefaultContext / WrapperListener</td>
+    <td align="center">0..n</td>
+    <td align="center">(none)</td>
+    <td></td>
+  </tr>
+-->
+
+  <tr>
+    <td>Server / Service / Engine / Host / Listener</td>
+    <td align="center">0..n</td>
+    <td align="center">(none)</td>
+    <td><code>type=${LISTENER}, sequence=${###}, host=${host.name},
+        service=${service.name}</code></td>
+  </tr>
+
+  <tr>
+    <td>Server / Service / Engine / Host / Realm</td>
+    <td align="center">0..1</td>
+    <td align="center">(none)</td>
+    <td><code>type=${REALM}, host=${host.name},
+        service=${service.name}</code></td>
+  </tr>
+
+  <tr>
+    <td>Server / Service / Engine / Host / Valve</td>
+    <td align="center">0..n</td>
+    <td align="center">(none)</td>
+    <td><code>type=${VALVE}, sequence=${###},
+        host=${host.name}, service=${service.name}</code></td>
+  </tr>
+
+  <tr>
+    <td>Server / Service / Engine / Listener</td>
+    <td align="center">0..n</td>
+    <td align="center">(none)</td>
+    <td><code>type=${LISTENER}, sequence=${###}</code>
+        (<strong>FIXME</strong> - disambiguate from Server / Service /
+        Listener)</td>
+  </tr>
+
+  <tr>
+    <td>Server / Service / Engine / Realm</td>
+    <td align="center">0..1</td>
+    <td align="center">(none)</td>
+    <td><code>type=${REALM}, service=${service.name}</code></td>
+  </tr>
+
+  <tr>
+    <td>Server / Service / Engine / Valve</td>
+    <td align="center">0..n</td>
+    <td align="center">(none)</td>
+    <td><code>type=${VALVE}, sequence=${###},
+        service=${service.name}</code></td>
+  </tr>
+
+  <tr>
+    <td>Server / Service / Listener</td>
+    <td align="center">0..n</td>
+    <td align="center">(none)</td>
+    <td><code>type=${LISTENER}, sequence=${###}</code>
+        (<strong>FIXME</strong> - disambiguate from Server / Service /
+        Engine / Listener)</td>
+  </tr>
+
+</table>
+
+</section>
+
+<section name="MBean Groups and Names">
+
+<p>The following MBean names shall be defined in the resource file
+<code>/org/apache/catalina/mbeans/mbeans-descriptors.xml</code> (and
+therefore available for use within the Administration/Configuration
+web application for Tomcat):</p>
+
+<table border="1" cellpadding="5">
+
+  <tr>
+    <th align="center" bgcolor="aqua">MBean Name</th>
+    <th align="center" bgcolor="aqua">Group Name</th>
+    <th align="center" bgcolor="aqua">Catalina Interface</th>
+    <th align="center" bgcolor="aqua">Implementation Class</th>
+  </tr>
+
+  <tr>
+    <td><code>AccessLogValve</code></td>
+    <td align="center"><code>VALVE</code></td>
+    <td><code>org.apache.catalina.Valve</code></td>
+    <td><code>org.apache.catalina.valves.AccessLogValve</code></td>
+  </tr>
+
+  <tr>
+    <td><code>BasicAuthenticator</code></td>
+    <td align="center"><code>VALVE</code></td>
+    <td><code>org.apache.catalina.Valve</code></td>
+    <td><code>org.apache.catalina.authenticator.BasicAuthenticator</code></td>
+  </tr>
+
+  <tr>
+    <td><code>CertificatesValve</code></td>
+    <td align="center"><code>VALVE</code></td>
+    <td><code>org.apache.catalina.Valve</code></td>
+    <td><code>org.apache.catalina.valves.CertificatesValve</code></td>
+  </tr>
+
+  <tr>
+    <td><code>ContextConfig</code></td>
+    <td align="center"><code>LISTENER</code></td>
+    <td><code>org.apache.catalina.LifecycleListener</code></td>
+    <td><code>org.apache.catalina.startup.ContextConfig</code></td>
+  </tr>
+
+  <tr>
+    <td><code>ContextEnvironment</code></td>
+    <td align="center"><code>RESOURCES</code></td>
+    <td><code>org.apache.catalina.deploy.ContextEnvironment</code></td>
+    <td><code>org.apache.catalina.deploy.ContextEnvironment</code></td>
+  </tr>
+
+  <tr>
+    <td><code>ContextResource</code></td>
+    <td align="center"><code>RESOURCES</code></td>
+    <td><code>org.apache.catalina.deploy.ContextResource</code></td>
+    <td><code>org.apache.catalina.deploy.ContextResource</code></td>
+  </tr>
+
+  <tr>
+    <td><code>ContextResourceLink</code></td>
+    <td align="center"><code>RESOURCES</code></td>
+    <td><code>org.apache.catalina.deploy.ContextResourceLink</code></td>
+    <td><code>org.apache.catalina.deploy.ContextResourceLink</code></td>
+  </tr>
+
+  <tr>
+    <td><code>CoyoteConnector</code></td>
+    <td align="center"><code>CONNECTOR</code></td>
+    <td><code>org.apache.catalina.Connector</code></td>
+    <td><code>org.apache.coyote.tomcat4.CoyoteConnector</code></td>
+  </tr>
+
+  <tr>
+    <td><code>DefaultContext</code></td>
+    <td align="center"><code>DEFAULT-CONTEXT</code></td>
+    <td><code>org.apache.catalina.DefaultContext</code></td>
+    <td><code>org.apache.catalina.core.StandardDefaultContext</code></td>
+  </tr>
+
+  <tr>
+    <td><code>DigestAuthenticator</code></td>
+    <td align="center"><code>VALVE</code></td>
+    <td><code>org.apache.catalina.Valve</code></td>
+    <td><code>org.apache.catalina.authenticator.DigestAuthenticator</code></td>
+  </tr>
+
+  <tr>
+    <td><code>EngineConfig</code></td>
+    <td align="center"><code>LISTENER</code></td>
+    <td><code>org.apache.catalina.LifecycleListener</code></td>
+    <td><code>org.apache.catalina.startup.EngineConfig</code></td>
+  </tr>
+
+  <tr>
+    <td><code>ErrorReportValve</code></td>
+    <td align="center"><code>VALVE</code></td>
+    <td><code>org.apache.catalina.Valve</code></td>
+    <td><code>org.apache.catalina.valves.ErrorReportValve</code></td>
+  </tr>
+
+  <tr>
+    <td><code>ErrorDispatcherValve</code></td>
+    <td align="center"><code>VALVE</code></td>
+    <td><code>org.apache.catalina.Valve</code></td>
+    <td><code>org.apache.catalina.valves.ErrorDispatcherValve</code></td>
+  </tr>
+
+  <tr>
+    <td><code>FormAuthenticator</code></td>
+    <td align="center"><code>VALVE</code></td>
+    <td><code>org.apache.catalina.Valve</code></td>
+    <td><code>org.apache.catalina.authenticator.FormAuthenticator</code></td>
+  </tr>
+
+  <tr>
+    <td><code>Group</code></td>
+    <td align="center"><code>GROUP</code></td>
+    <td><code>org.apache.catalina.Group</code></td>
+    <td><code>org.apache.catalina.Group</code></td>
+  </tr>
+
+  <tr>
+    <td><code>HostConfig</code></td>
+    <td align="center"><code>LISTENER</code></td>
+    <td><code>org.apache.catalina.LifecycleListener</code></td>
+    <td><code>org.apache.catalina.startup.HostConfig</code></td>
+  </tr>
+
+  <tr>
+    <td><code>HttpConnector10</code></td>
+    <td align="center"><code>CONNECTOR</code></td>
+    <td><code>org.apache.catalina.Connector</code></td>
+    <td><code>org.apache.catalina.connector.http10.HttpConnector</code></td>
+  </tr>
+
+  <tr>
+    <td><code>HttpConnector11</code></td>
+    <td align="center"><code>CONNECTOR</code></td>
+    <td><code>org.apache.catalina.Connector</code></td>
+    <td><code>org.apache.catalina.connector.http.HttpConnector</code></td>
+  </tr>
+
+  <tr>
+    <td><code>JAASRealm</code></td>
+    <td align="center"><code>REALM</code></td>
+    <td><code>org.apache.catalina.Realm</code></td>
+    <td><code>org.apache.catalina.realm.JAASRealm</code></td>
+  </tr>
+
+  <tr>
+    <td><code>JDBCRealm</code></td>
+    <td align="center"><code>REALM</code></td>
+    <td><code>org.apache.catalina.Realm</code></td>
+    <td><code>org.apache.catalina.realm.JDBCRealm</code></td>
+  </tr>
+
+  <tr>
+    <td><code>JDBCUserDatabase</code></td>
+    <td align="center"><code>USERDATABASE</code></td>
+    <td><code>org.apache.catalina.users.JDBCUserDatabase</code></td>
+    <td><code>org.apache.catalina.users.JDBCUserDatabase</code></td>
+  </tr>
+
+  <tr>
+    <td><code>JNDIRealm</code></td>
+    <td align="center"><code>REALM</code></td>
+    <td><code>org.apache.catalina.Realm</code></td>
+    <td><code>org.apache.catalina.realm.JNDIRealm</code></td>
+  </tr>
+
+  <tr>
+    <td><code>MBeanFactory</code></td>
+    <td align="center"><code></code></td>
+    <td><code></code></td>
+    <td><code>org.apache.catalina.mbeans.MBeanFactory</code></td>
+  </tr>
+
+  <tr>
+    <td><code>MemoryRealm</code></td>
+    <td align="center"><code>REALM</code></td>
+    <td><code>org.apache.catalina.Realm</code></td>
+    <td><code>org.apache.catalina.realm.MemoryRealm</code></td>
+  </tr>
+
+  <tr>
+    <td><code>MemoryUserDatabase</code></td>
+    <td align="center"><code>USERDATABASE</code></td>
+    <td><code>org.apache.catalina.users.MemoryUserDatabase</code></td>
+    <td><code>org.apache.catalina.users.MemoryUserDatabase</code></td>
+  </tr>
+
+  <tr>
+    <td><code>NamingContextListener</code></td>
+    <td align="center"><code>LISTENER</code></td>
+    <td><code>org.apache.catalina.LifecycleListener</code></td>
+    <td><code>org.apache.catalina.core.NamingContextListener</code></td>
+  </tr>
+
+  <tr>
+    <td><code>NamingResources</code></td>
+    <td align="center"><code>RESOURCES</code></td>
+    <td><code>org.apache.catalina.deploy.NamingResources</code></td>
+    <td><code>org.apache.catalina.deploy.NamingResources</code></td>
+  </tr>
+
+  <tr>
+    <td><code>NonLoginAuthenticator</code></td>
+    <td align="center"><code>VALVE</code></td>
+    <td><code>org.apache.catalina.Valve</code></td>
+    <td><code>org.apache.catalina.authenticator.NonLoginAuthenticator</code></td>
+  </tr>
+
+  <tr>
+    <td><code>PersistentManager</code></td>
+    <td align="center"><code>MANAGER</code></td>
+    <td><code>org.apache.catalina.Manager</code></td>
+    <td><code>org.apache.catalina.session.PersistentManager</code></td>
+  </tr>
+
+  <tr>
+    <td><code>RemoteAddrValve</code></td>
+    <td align="center"><code>VALVE</code></td>
+    <td><code>org.apache.catalina.Valve</code></td>
+    <td><code>org.apache.catalina.valves.RemoteAddrValve</code></td>
+  </tr>
+
+  <tr>
+    <td><code>RemoteHostValve</code></td>
+    <td align="center"><code>VALVE</code></td>
+    <td><code>org.apache.catalina.Valve</code></td>
+    <td><code>org.apache.catalina.valves.RemoteHostValve</code></td>
+  </tr>
+
+  <tr>
+    <td><code>RequestDumperValve</code></td>
+    <td align="center"><code>VALVE</code></td>
+    <td><code>org.apache.catalina.Valve</code></td>
+    <td><code>org.apache.catalina.valves.RequestDumperValve</code></td>
+  </tr>
+
+  <tr>
+    <td><code>Role</code></td>
+    <td align="center"><code>ROLE</code></td>
+    <td><code>org.apache.catalina.Role</code></td>
+    <td><code>org.apache.catalina.Role</code></td>
+  </tr>
+
+  <tr>
+    <td><code>SingleSignOn</code></td>
+    <td align="center"><code>VALVE</code></td>
+    <td><code>org.apache.catalina.Valve</code></td>
+    <td><code>org.apache.catalina.valves.SingleSignOn</code></td>
+  </tr>
+
+  <tr>
+    <td><code>SSLAuthenticator</code></td>
+    <td align="center"><code>VALVE</code></td>
+    <td><code>org.apache.catalina.Valve</code></td>
+    <td><code>org.apache.catalina.authenticator.SSLAuthenticator</code></td>
+  </tr>
+
+  <tr>
+    <td><code>StandardContext</code></td>
+    <td align="center"><code>CONTEXT</code></td>
+    <td><code>org.apache.catalina.Context</code></td>
+    <td><code>org.apache.catalina.core.StandardContext</code></td>
+  </tr>
+
+  <tr>
+    <td><code>StandardContextValve</code></td>
+    <td align="center"><code>VALVE</code></td>
+    <td><code>org.apache.catalina.Valve</code></td>
+    <td><code>org.apache.catalina.core.StandardContextValve</code></td>
+  </tr>
+
+  <tr>
+    <td><code>StandardEngine</code></td>
+    <td align="center"><code>ENGINE</code></td>
+    <td><code>org.apache.catalina.Engine</code></td>
+    <td><code>org.apache.catalina.core.StandardEngine</code></td>
+  </tr>
+
+  <tr>
+    <td><code>StandardEngineValve</code></td>
+    <td align="center"><code>VALVE</code></td>
+    <td><code>org.apache.catalina.Valve</code></td>
+    <td><code>org.apache.catalina.core.StandardEngineValve</code></td>
+  </tr>
+
+  <tr>
+    <td><code>StandardHost</code></td>
+    <td align="center"><code>HOST</code></td>
+    <td><code>org.apache.catalina.Host</code></td>
+    <td><code>org.apache.catalina.core.StandardHost</code></td>
+  </tr>
+
+  <tr>
+    <td><code>StandardHostValve</code></td>
+    <td align="center"><code>VALVE</code></td>
+    <td><code>org.apache.catalina.Valve</code></td>
+    <td><code>org.apache.catalina.core.StandardHostValve</code></td>
+  </tr>
+
+  <tr>
+    <td><code>StandardManager</code></td>
+    <td align="center"><code>MANAGER</code></td>
+    <td><code>org.apache.catalina.Manager</code></td>
+    <td><code>org.apache.catalina.session.StandardManager</code></td>
+  </tr>
+
+  <tr>
+    <td><code>StandardServer</code></td>
+    <td align="center"><code>SERVER</code></td>
+    <td><code>org.apache.catalina.Server</code></td>
+    <td><code>org.apache.catalina.core.StandardServer</code></td>
+  </tr>
+
+  <tr>
+    <td><code>StandardService</code></td>
+    <td align="center"><code>SERVICE</code></td>
+    <td><code>org.apache.catalina.Service</code></td>
+    <td><code>org.apache.catalina.core.StandardService</code></td>
+  </tr>
+
+  <tr>
+    <td><code>StandardWrapperValve</code></td>
+    <td align="center"><code>VALVE</code></td>
+    <td><code>org.apache.catalina.Valve</code></td>
+    <td><code>org.apache.catalina.core.StandardWrapperValve</code></td>
+  </tr>
+
+  <tr>
+    <td><code>User</code></td>
+    <td align="center"><code>USER</code></td>
+    <td><code>org.apache.catalina.User</code></td>
+    <td><code>org.apache.catalina.User</code></td>
+  </tr>
+
+  <tr>
+    <td><code>UserDatabaseRealm</code></td>
+    <td align="center"><code>REALM</code></td>
+    <td><code>org.apache.catalina.Realm</code></td>
+    <td><code>org.apache.catalina.realm.UserDatabaseRealm</code></td>
+  </tr>
+
+  <tr>
+    <td><code>WebappLoader</code></td>
+    <td align="center"><code>LOADER</code></td>
+    <td><code>org.apache.catalina.Loader</code></td>
+    <td><code>org.apache.catalina.loader.WebappLoader</code></td>
+  </tr>
+
+</table>
+
+</section>
+
+<section name="JSR-77 Cross Reference">
+
+<p>The managed objects in the JSR-77 object hierarchy correspond
+to the specified MBean names or groups as follows:</p>
+
+<table border="1" cellpadding="5">
+
+  <tr>
+    <th align="center" bgcolor="aqua">JSR-77 Managed Object</th>
+    <th align="center" bgcolor="aqua">MBean Name or Group</th>
+    <th align="center" bgcolor="aqua">Comments</th>
+  </tr>
+
+  <tr>
+    <td><code>J2EEServer</code></td>
+    <td><code>${SERVICE}</code></td>
+    <td></td>
+  </tr>
+
+  <tr>
+    <td><code>Node</code></td>
+    <td><code>${SERVICE}</code></td>
+    <td>Tomcat supports a single node only.</td>
+  </tr>
+
+  <tr>
+    <td><code>Port</code></td>
+    <td><code>${CONNECTOR}</code></td>
+    <td></td>
+  </tr>
+
+  <tr>
+    <td><code>Servlet</code></td>
+    <td><code>${WRAPPER}</code></td>
+    <td><strong>FIXME</strong> - Not yet identified as an MBean</td>
+  </tr>
+
+  <tr>
+    <td><code>WebModule</code></td>
+    <td><code>${CONTEXT}</code></td>
+    <td></td>
+  </tr>
+
+</table>
+
+</section>
+
+<section name="JSR-88 Cross Reference">
+
+<p>The deployment objects in the JSR-88 API object hierarchy correspond
+to the specified MBean names or groups as follows:</p>
+
+<table border="1" cellpadding="5">
+
+  <tr>
+    <th align="center" bgcolor="aqua">JSR-88 API Object</th>
+    <th align="center" bgcolor="aqua">MBean Name or Group</th>
+    <th align="center" bgcolor="aqua">Comments</th>
+  </tr>
+
+  <tr>
+    <td><code>DeployableObject</code></td>
+    <td><code>${CONTEXT}</code></td>
+    <td>Context deployment info plus the corresponding WAR file</td>
+  </tr>
+
+  <tr>
+    <td><code>Target</code></td>
+    <td><code>${HOST}</code></td>
+    <td></td>
+  </tr>
+
+</table>
+
+</section>
+
+</body>
+
+</document>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/funcspecs/project.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/funcspecs/project.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/funcspecs/project.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<project name="Catalina Functional Specifications"
+        href="http://tomcat.apache.org/">
+
+    <title>Catalina Functional Specifications</title>
+
+    <logo href="/images/tomcat.gif">
+      Catalina Functional Specifications
+    </logo>
+
+    <body>
+
+    <menu name="Links">
+        <item name="Docs Home"             href="../../index.html"/>
+        <item name="Functional Specs"      href="index.html"/>
+    </menu>
+
+    <menu name="Administrative Apps">
+        <item name="Overall Requirements"  href="fs-admin-apps.html"/>
+	  <item name="Tomcat MBean Names"    href="mbean-names.html"/>
+        <item name="Administered Objects"  href="fs-admin-objects.html"/>
+        <item name="Supported Operations"  href="fs-admin-opers.html"/>
+    </menu>
+
+    <menu name="Internal Servlets">
+        <item name="Default Servlet"       href="fs-default.html"/>
+        <item name="Invoker Servlet"       href="fs-invoker.html"/>
+    </menu>
+
+    <menu name="Realm Implementations">
+        <item name="JDBC Realm"            href="fs-jdbc-realm.html"/>
+        <item name="JNDI Realm"            href="fs-jndi-realm.html"/>
+        <item name="Memory Realm"          href="fs-memory-realm.html"/>
+    </menu>
+
+
+    </body>
+
+</project>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/html-manager-howto.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/html-manager-howto.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/html-manager-howto.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,543 @@
+<?xml version="1.0"?>
+<!DOCTYPE document [
+  <!ENTITY project SYSTEM "project.xml">
+]>
+<document url="html-manager-howto.html">
+
+    &project;
+
+    <properties>
+        <author email="glenn at apache.org">Glenn L. Nielsen</author>
+        <title>Tomcat Web Application Manager How To</title>
+    </properties>
+
+<body>
+
+<section name="Introduction">
+
+<p>In many production environments it is very useful to have the capability
+to manage your web applications without having to shut down and restart
+Tomcat.  This document is for the HTML web interface to the web application
+<a href="manager-howto.html">manager</a>.</p>
+
+<p>The interface is divided into five sections:
+<ul>
+  <li><strong>Message</strong> - Displays success and failure messages.</li>
+  <li><strong>Manager</strong> - General manager operations like list and
+      help.</li>
+  <li><strong>Applications</strong> - List of web applications and
+      commands.</li>
+  <li><strong>Deploy</strong> - Deploying web applications.</li>
+  <li><strong>Server Information</strong> - Information about the Tomcat
+      server.</li>
+</ul>
+</p>
+
+</section>
+
+<section name="Message">
+
+<p>
+Displays information about the success or failure of the last web application
+manager command you performed. If it succeeded <strong>OK</strong> is displayed
+and may be followed by a success message. If it failed <strong>FAIL</strong>
+is displayed followed by an error message. Common failure messages are
+documented below for each command.  The complete list of failure messages for
+each command can be found in the <a href="manager-howto.html">manager</a> web
+application documentation.
+</p>
+
+</section>
+
+<section name="Manager">
+
+<p>The Manager section has three links:
+<ul>
+  <li><strong>List Applications</strong> - Redisplay a list of web
+      applications.</li>
+  <li><strong>HTML Manager Help</strong> - A link to this document.</li>
+  <li><strong>Manager Help</strong> - A link to the comprehensive Manager
+      App HOW TO.</li>
+</ul>
+</p>
+
+</section>
+
+<section name="Applications">
+
+<p>The Applications section lists information about all the installed web
+applications and provides links for managing them. For each web application
+the following is displayed:
+<ul>
+  <li><strong>Path</strong> - The web applicaton context path.</li>
+  <li><strong>Display Name</strong> - The display name for the web application
+      if it has one configured in its "web.xml" file.</li>
+  <li><strong>Running</strong> - Whether the web application is running and
+      available (true), or not running and unavailable (false).</li>
+  <li><strong>Sessions</strong> - The number of active sessions for remote
+      users of this web application.  The number of sessions is a link which
+      when submitted displays more details about session usage by the web
+      application in the Message box.</li>
+  <li><strong>Commands</strong> - Lists all commands which can be performed on
+      the web application. Only those commands which can be performed will be
+      listed as a link which can be submitted. No commands can be performed on
+      the manager web application itself. The following commands can be
+      performed:
+      <ul>
+        <li><strong>Start</strong> - Start a web application which had been
+            stopped.</li>
+        <li><strong>Stop</strong> - Stop a web application which is currently
+            running and make it unavailable.</li>
+        <li><strong>Reload</strong> - Reload the web application so that new
+            ".jar" files in <code>/WEB-INF/lib/</code> or new classes in
+            <code>/WEB-INF/classes/</code> can be used.</li>
+        <li><strong>Undeploy</strong> - Stop and then remove this web
+             application from the server.</li>
+      </ul>
+  </li>
+</ul>
+</p>
+
+<subsection name="Start">
+
+<p>Signal a stopped application to restart, and make itself available again.
+Stopping and starting is useful, for example, if the database required by
+your application becomes temporarily unavailable.  It is usually better to
+stop the web application that relies on this database rather than letting
+users continuously encounter database exceptions.</p>
+
+<p>If this command succeeds, you will see a Message like this:</p>
+<source>
+OK - Started application at context path /examples
+</source>
+
+<p>Otherwise, the Message will start with <code>FAIL</code> and include an
+error message.  Possible causes for problems include:
+<ul>
+<li><em>Encountered exception</em>
+    <blockquote>             
+    <p>An exception was encountered trying to start the web application.
+    Check the Tomcat 5 logs for the details.</p>
+    </blockquote></li>       
+<li><em>Invalid context path was specified</em>
+    <blockquote>             
+    <p>The context path must start with a slash character, unless you are
+    referencing the ROOT web application -- in which case the context path
+    must be a zero-length string.</p>
+    </blockquote></li>       
+<li><em>No context exists for path /foo</em>
+    <blockquote>             
+    <p>There is no deployed application on the context path
+    that you specified.</p>  
+    </blockquote></li>       
+<li><em>No context path was specified</em>
+    <blockquote>             
+    The <code>path</code> parameter is required.
+    </blockquote></li>       
+</ul>
+</p>
+
+</subsection>
+
+<subsection name="Stop">
+
+<p>Signal an existing application to make itself unavailable, but leave it
+deployed.  Any request that comes in while an application is
+stopped will see an HTTP error 404, and this application will show as
+"stopped" on a list applications command.</p>
+                             
+<p>If this command succeeds, you will see a Message like this:</p>
+<source>
+OK - Stopped application at context path /examples
+</source>
+                             
+<p>Otherwise, the Message will start with <code>FAIL</code> and include an
+error message.  Possible causes for problems include:
+<ul>                         
+<li><em>Encountered exception</em>
+    <blockquote>             
+    <p>An exception was encountered trying to stop the web application.
+    Check the Tomcat 5 logs for the details.</p>
+    </blockquote></li>       
+<li><em>Invalid context path was specified</em>
+    <blockquote>             
+    <p>The context path must start with a slash character, unless you are
+    referencing the ROOT web application -- in which case the context path
+    must be a zero-length string.</p>
+    </blockquote></li>       
+<li><em>No context exists for path /foo</em>
+    <blockquote>             
+    <p>There is no deployed application on the context path
+    that you specified.</p>  
+    </blockquote></li>       
+<li><em>No context path was specified</em>
+    <blockquote>             
+    The <code>path</code> parameter is required.
+    </blockquote></li>       
+</ul>
+</p>
+
+</subsection>
+
+<subsection name="Reload">
+
+<p>Signal an existing application to shut itself down and reload.  This can
+be useful when the web application context is not reloadable and you have
+updated classes or property files in the <code>/WEB-INF/classes</code>
+directory or when you have added or updated jar files in the
+<code>/WEB-INF/lib</code> directory.
+</p>
+<p><strong>NOTE:</strong> The <code>/WEB-INF/web.xml</code>
+web application configuration file is not checked on a reload;
+the previous web.xml configuration is used.
+If you have made changes to your web.xml file you must stop
+then start the web application.
+</p>
+
+<p>If this command succeeds, you will see a Message like this:</p>
+<source>
+OK - Reloaded application at context path /examples
+</source>
+
+<p>Otherwise, the Message will start with <code>FAIL</code> and include an
+error message.  Possible causes for problems include:
+<ul>
+<li><em>Encountered exception</em>
+    <blockquote>             
+    <p>An exception was encountered trying to restart the web application.
+    Check the Tomcat 5 logs for the details.</p>
+    </blockquote></li>       
+<li><em>Invalid context path was specified</em>
+    <blockquote>             
+    <p>The context path must start with a slash character, unless you are
+    referencing the ROOT web application -- in which case the context path
+    must be a zero-length string.</p>
+    </blockquote></li>       
+<li><em>No context exists for path /foo</em>
+    <blockquote>             
+    <p>There is no deployed application on the context path
+    that you specified.</p>  
+    </blockquote></li>       
+<li><em>No context path was specified</em>
+    <blockquote>             
+    The <code>path</code> parameter is required.
+    </blockquote></li>       
+<li><em>Reload not supported on WAR deployed at path /foo</em>
+    <blockquote>             
+    Currently, application reloading (to pick up changes to the classes or
+    <code>web.xml</code> file) is not supported when a web application is
+    installed directly from a WAR file, which happens when the host is 
+    configured to not unpack WAR files. As it only works when the web 
+    application is installed from an unpacked directory, if you are using 
+    a WAR file, you should <code>undeploy</code> and then <code>deploy</code> 
+    the application again to pick up your changes.
+    </blockquote></li>       
+</ul>
+</p>
+
+</subsection>
+
+<subsection name="Undeploy">
+
+<p><strong><font color="red">WARNING</font> - This command will delete the
+contents of the web application directory and/or ".war" file if it exists within
+the <code>appBase</code> directory (typically "webapps") for this virtual host
+</strong>.  The web application temporary work directory is also deleted.  If
+you simply want to take an application out of service, you should use the
+<code>/stop</code> command instead.</p>
+                             
+<p>Signal an existing application to gracefully shut itself down, and then
+remove it from Tomcat (which also makes this context path available for
+reuse later).  This command is the logical opposite of the
+<code>/deploy</code> Ant command, and the related deploy features available 
+in the HTML manager.</p>
+                             
+<p>If this command succeeds, you will see a Message like this:</p>
+<source>
+OK - Undeployed application at context path /examples
+</source>
+                             
+<p>Otherwise, the Message will start with <code>FAIL</code> and include an
+error message.  Possible causes for problems include:
+<ul>                         
+<li><em>Encountered exception</em>
+    <blockquote>             
+    <p>An exception was encountered trying to undeploy the web application.
+    Check the Tomcat logs for the details.</p>
+    </blockquote></li>       
+<li><em>Invalid context path was specified</em>
+    <blockquote>             
+    <p>The context path must start with a slash character, unless you are
+    referencing the ROOT web application -- in which case the context path
+    must be a zero-length string.</p>
+    </blockquote></li>       
+<li><em>No context exists for path /foo</em>
+    <blockquote>             
+    <p>There is no deployed application on the context path
+    that you specified.</p>  
+    </blockquote></li>       
+<li><em>No context path was specified</em>
+    <blockquote>             
+    The <code>path</code> parameter is required.
+    </blockquote></li>       
+</ul>
+</p>
+
+</subsection>
+
+</section>
+
+<section name="Deploy">
+
+<p>Web applications can be deployed using files or directories located
+on the Tomcat server or you can upload a web application archive (WAR)
+file to the server.</p>
+
+<p>To install an application, fill in the appropriate fields for the type
+of install you want to do and then submit it using the <i>Install</i>
+button.</p>
+
+<subsection name="Deploy directory or WAR file located on server">
+
+<p>Deploy and start a new web application, attached to the specified <i>Context
+Path:</i> (which must not be in use by any other web application).
+This command is the logical opposite of the <em>Undeploy</em> command.</p>
+
+<p>There are a number of different ways the deploy command can be used.</p>
+
+<h3>Deploy a Directory or WAR by URL</h3>
+
+<p>Install a web application directory or ".war" file located on the Tomcat
+server. If no <i>Context Path</i> is specified, the directory name or the
+war file name without the ".war" extension is used as the path. The
+<i>WAR or Directory URL</i> specifies a URL (including the <code>file:</code>
+scheme) for either a directory or a web application archive (WAR) file. The
+supported syntax for a URL referring to a WAR file is described on the Javadocs
+page for the <code>java.net.JarURLConnection</code> class.  Use only URLs that
+refer to the entire WAR file.</p>
+
+<p>In this example the web application located in the directory
+<code>C:\path\to\foo</code> on the Tomcat server (running on Windows)
+is deployed as the web application context named <code>/footoo</code>.
+<source>
+Context Path: /footoo
+WAR or Directory URL: file:C:/path/to/foo
+</source>
+</p>
+
+<p>In this example the ".war" file <code>/path/to/bar.war</code> on the
+Tomcat server (running on Unix) is deployed as the web application
+context named <code>/bar</code>. Notice that there is no <code>path</code>
+parameter so the context path defaults to the name of the web application
+archive file without the ".war" extension.
+<source>
+WAR or Directory URL: jar:file:/path/to/bar.war!/
+</source>
+</p>
+
+<h3>Deploy a Directory or War from the Host appBase</h3>
+
+<p>Install a web application directory or ".war" file located in your Host
+appBase directory. If no <i>Context Path</i> is specified the directory name
+or the war file name without the ".war" extension is used as the path.</p>
+
+<p>In this example the web application located in a subdirectory named
+<code>foo</code> in the Host appBase directory of the Tomcat server is
+deployed as the web application context named <code>/foo</code>. Notice
+that there is no <code>path</code> parameter so the context path defaults
+to the name of the web application directory.
+<source>
+WAR or Directory URL: foo
+</source>
+</p>
+
+<p>In this example the ".war" file <code>bar.war</code> located in your
+Host appBase directory on the Tomcat server is deployed as the web
+application context named <code>/bartoo</code>.
+<source>
+Context Path: /bartoo
+WAR or Directory URL: bar.war
+</source>
+</p>
+
+<h3>Deploy using a Context configuration ".xml" file</h3>
+
+<p>If the Host deployXML flag is set to true, you can install a web
+application using a Context configuration ".xml" file and an optional
+".war" file or web application directory. The <i>Context Path</i>
+is not used when installing a web application using a context ".xml"
+configuration file.</p>
+
+<p>A Context configuration ".xml" file can contain valid XML for a
+web application Context just as if it were configured in your
+Tomcat <code>server.xml</code> configuration file. Here is an
+example for Tomcat running on Windows:
+<source>
+&lt;Context path="/foobar" docBase="C:\path\to\application\foobar"
+         debug="0"&gt;
+
+  &lt;!-- Link to the user database we will get roles from --&gt;
+  &lt;ResourceLink name="users" global="UserDatabase"
+                type="org.apache.catalina.UserDatabase"/&gt;
+
+&lt;/Context&gt;
+</source>
+</p>
+
+<p>Use of the <i>WAR or Directory URL</i> is optional. When used
+to select a web application ".war" file or directory it overrides any
+docBase configured in the context configuration ".xml" file.</p>
+
+<p>Here is an example of installing an application using a Context
+configuration ".xml" file for Tomcat running on Windows.
+<source>
+XML Configuration file URL: file:C:/path/to/context.xml
+</source>
+</p>
+
+<p>Here is an example of installing an application using a Context
+configuration ".xml" file and a web application ".war" file located
+on the server (Tomcat running on Unix).
+<source>
+XML Configuration file URL: file:/path/to/context.xml
+WAR or Directory URL: jar:file:/path/to/bar.war!/
+</source>
+</p>
+
+</subsection>
+
+<subsection name="Upload a WAR file to install">
+
+<p>Upload a WAR file from your local system and install it into the
+appBase for your Host. The name of the WAR file without the ".war"
+extension is used as the context path name.</p>
+
+<p>Use the <i>Browse</i> button to select a WAR file to upload to the
+server from your local desktop system.</p>
+
+<p>The .WAR file may include Tomcat specific deployment configuration, by 
+including a Context configuration XML file in 
+<code>/META-INF/context.xml</code>.</p>
+
+<p>Upload of a WAR file could fail for the following reasons:</p>
+<ul>
+<li><em>File uploaded must be a .war</em>
+    <blockquote>
+    <p>The upload install will only accept files which have the filename
+    extension of ".war".</p>
+    </blockquote></li>
+<li><em>War file already exists on server</em>
+    <blockquote>
+    <p>If a war file of the same name already exists in your Host's
+    appBase the upload will fail. Either undeploy the existing war file
+    from your Host's appBase or upload the new war file using a different
+    name.</p>
+    </blockquote></li>
+<li><em>File upload failed, no file</em>
+    <blockquote>
+    <p>The file upload failed, no file was received by the server.</p>
+    </blockquote></li>
+<li><em>Install Upload Failed, Exception:</em>
+    <blockquote>
+    <p>The war file upload or install failed with a Java Exception.
+    The exception message will be listed.</p>
+    </blockquote></li>
+</ul>
+
+</subsection>
+
+<subsection name="Deployment Notes">
+
+<p>If the Host is configured with unpackWARs=true and you install a war
+file, the war will be unpacked into a directory in your Host appBase
+directory.</p>
+
+<p>If the application war or directory is deployed in your Host appBase
+directory and either the Host is configured with autoDeploy=true or
+liveDeploy=true, the Context path must match the directory name or
+war file name without the ".war" extension.</p>
+
+<p>For security when untrusted users can manage web applications, the
+Host deployXML flag can be set to false.  This prevents untrusted users
+from installing web applications using a configuration XML file and
+also prevents them from installing application directories or ".war"
+files located outside of their Host appBase.</p>
+
+</subsection>
+
+<subsection name="Deploy Message">
+
+<p>If deployment and startup is successful, you will receive a Message
+like this:</p>
+<source>
+OK - Deployed application at context path /foo
+</source>
+
+<p>Otherwise, the Message will start with <code>FAIL</code> and include an
+error message.  Possible causes for problems include:</p>
+<ul>
+<li><em>Application already exists at path /foo</em>
+    <blockquote>
+    <p>The context paths for all currently running web applications must be
+    unique.  Therefore, you must either undeploy the existing web
+    application using this context path, or choose a different context path
+    for the new one.</p>
+    </blockquote></li>
+<li><em>Document base does not exist or is not a readable directory</em>
+    <blockquote>
+    <p>The URL specified by the <i>WAR or Directory URL:</i> field must
+    identify a directory on this server that contains the "unpacked" version
+    of a web application, or the absolute URL of a web application archive
+    (WAR) file that contains this application.  Correct the value entered for
+    the <i>WAR or Directory URL:</i> field.</p>
+    </blockquote></li>
+<li><em>Encountered exception</em>
+    <blockquote>
+    <p>An exception was encountered trying to start the new web application.
+    Check the Tomcat 5 logs for the details, but likely explanations include
+    problems parsing your <code>/WEB-INF/web.xml</code> file, or missing
+    classes encountered when initializing application event listeners and
+    filters.</p>
+    </blockquote></li>
+<li><em>Invalid application URL was specified</em>
+    <blockquote>
+    <p>The URL for the <i>WAR or Directory URL:</i> field that you specified
+    was not valid.  Such URLs must start with <code>file:</code>, and URLs
+    for a WAR file must end in ".war".</p>
+    </blockquote></li>
+<li><em>Invalid context path was specified</em>
+    <blockquote>
+    <p>The context path must start with a slash character, unless you are
+    referencing the ROOT web application -- in which case the context path
+    must be a "/" string.</p>
+    </blockquote></li>
+<li><em>Context path must match the directory or WAR file name:</em>
+    <blockquote>
+    If the application war or directory is deployed in your Host appBase
+    directory and either the Host is configured with autoDeploy=true or
+    liveDeploy=true, the Context path must match the directory name or
+    war file name without the ".war" extension.
+    </blockquote></li>
+<li><em>Only web applications in the Host web application directory can
+     be deployed</em>
+     <blockquote>
+     If the Host deployXML flag is set to false this error will happen
+     if an attempt is made to install a web application directory or
+      ".war" file outside of the Host appBase directory.
+     </blockquote></li>
+</ul>
+
+</subsection>
+</section>
+
+<section name="Server Information">
+
+<p>This section displays information about Tomcat, the operating system of
+the server Tomcat is hosted on, and the Java Virtual Machine Tomcat is
+running in.</p>
+
+</section>
+
+</body>
+
+</document>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/images/add.gif
===================================================================
(Binary files differ)


Property changes on: branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/images/add.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/images/asf-logo.gif
===================================================================
(Binary files differ)


Property changes on: branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/images/asf-logo.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/images/code.gif
===================================================================
(Binary files differ)


Property changes on: branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/images/code.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/images/design.gif
===================================================================
(Binary files differ)


Property changes on: branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/images/design.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/images/docs.gif
===================================================================
(Binary files differ)


Property changes on: branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/images/docs.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/images/fix.gif
===================================================================
(Binary files differ)


Property changes on: branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/images/fix.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/images/printer.gif
===================================================================
(Binary files differ)


Property changes on: branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/images/printer.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/images/tomcat.gif
===================================================================
(Binary files differ)


Property changes on: branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/images/tomcat.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/images/update.gif
===================================================================
(Binary files differ)


Property changes on: branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/images/update.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/images/void.gif
===================================================================
(Binary files differ)


Property changes on: branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/images/void.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/index.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/index.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/index.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,173 @@
+<?xml version="1.0"?>
+<!DOCTYPE document [
+  <!ENTITY project SYSTEM "project.xml">
+]>
+<document url="index.html">
+
+  &project;
+
+  <properties>
+    <author email="craigmcc at apache.org">Craig R. McClanahan</author>
+    <author email="remm at apache.org">Remy Maucherat</author>
+    <author email="yoavs at apache.org">Yoav Shapira</author>
+    <title>Documentation Index</title>
+  </properties>
+
+<body>
+
+<section name="Introduction">
+
+<p>This is the top-level entry point of the documentation bundle for the
+<strong>Apache Tomcat</strong> Servlet/JSP container.  Apache Tomcat version 5.5 
+implements the
+Servlet 2.4 and JavaServer Pages 2.0 specifications from the
+<a href="http://www.jcp.org">Java Community Process</a>, and includes many
+additional features that make it a useful platform for developing and deploying
+web applications and web services.</p>
+
+<p>Select one of the links from the navigation menu (to the left) to drill
+down to the more detailed documentation that is available.  Each available
+manual is described in more detail below.</p>
+
+</section>
+
+
+<section name="Apache Tomcat User Guide">
+
+<p>The following documents will assist you in downloading, installing
+Apache Tomcat 5, and using many of the Apache Tomcat features.</p>
+
+<ol>
+<li><a href="introduction.html"><strong>Introduction</strong></a> - A
+    brief, high level, overview of Apache Tomcat.</li>
+<li><a href="setup.html"><strong>Setup</strong></a> - How to install and run
+    Apache Tomcat on a variety of platforms.</li>
+<li><a href="appdev/index.html"><strong>First web application</strong></a>
+    - An introduction to the concepts of a <em>web application</em> as defined
+    in the <a href="http://java.sun.com/products/servlet/download.html">Servlet
+    2.3 Specification</a>.  Covers basic organization of your web application
+    source tree, the structure of a web application archive, and an
+    introduction to the web application deployment descriptor
+    (<code>/WEB-INF/web.xml</code>).</li>
+<li><a href="deployer-howto.html"><strong>Deployer</strong></a> -
+    Operating the Apache Tomcat Deployer to deploy, precompile, and validate web
+    applications.</li>
+<li><a href="manager-howto.html"><strong>Manager</strong></a> -
+    Operating the <code>Manager</code> web app to deploy, undeploy, and
+    redeploy applications while Apache Tomcat is running.</li>
+<li><a href="realm-howto.html"><strong>Realms and Access Control</strong></a>
+    - Description of how to configure <em>Realms</em> (databases of users,
+    passwords, and their associated roles) for use in web applications that
+    utilize <em>Container Managed Security</em>.</li>
+<li><a href="security-manager-howto.html"><strong>Security Manager</strong></a>
+    - Configuring and using a Java Security Manager to
+    support fine-grained control over the behavior of your web applications.
+    </li>
+<li><a href="jndi-resources-howto.html"><strong>JNDI Resources</strong></a>
+    - Configuring standard and custom resources in the JNDI naming context
+    that is provided to each web application.</li>
+<li><a href="jndi-datasource-examples-howto.html">
+    <strong>JDBC DataSource</strong></a>
+    - Configuring a JNDI DataSoure with a DB connection pool.
+    Examples for many popular databases.</li>
+<li><a href="class-loader-howto.html"><strong>Classloading</strong></a>
+    - Information about class loading in Apache Tomcat 5, including where to place
+    your application classes so that they are visible.</li>
+<li><a href="jasper-howto.html"><strong>JSPs</strong></a>
+    - Information about Jasper configuration, as well as the JSP compiler
+    usage.</li>
+<li><a href="ssl-howto.html"><strong>SSL</strong></a> -
+    Installing and
+    configuring SSL support so that your Apache Tomcat will serve requests using
+    the <code>https</code> protocol.</li>
+<li><a href="ssi-howto.html"><strong>SSI</strong></a> -
+    Using Server Side Includes in Apache Tomcat.</li>
+<li><a href="cgi-howto.html"><strong>CGI</strong></a> -
+    Using CGIs with Apache Tomcat.</li>
+<li><a href="proxy-howto.html"><strong>Proxy Support</strong></a> -
+    Configuring Apache Tomcat 5 to run behind a proxy server (or a web server
+    functioning as a proxy server).</li>
+<li><a href="mbeans-descriptor-howto.html"><strong>MBean Descriptor</strong></a> -
+    Configuring MBean descriptors files for custom components.</li>
+<li><a href="default-servlet.html"><strong>Default Servlet</strong></a> -
+    Configuring the default servlet and customizing directory listings.</li>
+<li><a href="cluster-howto.html"><strong>Apache Tomcat Clustering</strong></a> -
+    Enable session replication in a Apache Tomcat environment.</li>
+<li><a href="balancer-howto.html"><strong>Balancer</strong></a> -
+    Configuring, using, and extending the load balancer application.</li>
+<li><a href="connectors.html"><strong>Connectors</strong></a> -
+    Connectors available in Apache Tomcat, and native web server integration.</li>
+<li><a href="monitoring.html"><strong>Monitoring and Management</strong></a> -
+    Enabling JMX Remote support, and using tools to monitor and manage Apache Tomcat.</li>
+<li><a href="logging.html"><strong>Logging</strong></a> -
+    Confuguring logging in Apache Tomcat.</li>
+
+</ol>
+
+</section>
+
+
+<section name="Reference">
+
+<p>The following documents are aimed at <em>System Administrators</em> who
+are responsible for installing, configuring, and operating a Apache Tomcat 5 server.
+</p>
+<ul>
+<li><a href="RELEASE-NOTES.txt"><strong>Release notes</strong></a>
+    - Known issues in this Apache Tomcat release.
+    </li>
+<li><a href="config/index.html"><strong>Apache Tomcat Server Configuration Reference</strong></a>
+    - Reference manual that documents all available elements and attributes
+      that may be placed into a Apache Tomcat 5 <code>conf/server.xml</code> file.
+    </li>
+<li><a href="http://tomcat.apache.org/connectors-doc/index.html"><strong>JK Documentation</strong></a>
+    - Complete documentation and HOWTOs on the JK native webserver connector,
+      used to interface Apache Tomcat with servers like Apache HTTPd, IIS
+      and others.</li>
+<li><a href="servletapi/index.html"><strong>Servlet API Javadocs</strong></a> -
+    The Servlet 2.4 API Javadocs.</li>
+<li><a href="jspapi/index.html"><strong>JSP API Javadocs</strong></a> -
+    The JSP 2.0 API Javadocs.</li>
+</ul>
+
+</section>
+
+
+<section name="Apache Tomcat Developers">
+
+<p>The following documents are for Java developers who wish to contribute to
+the development of the <em>Apache Tomcat</em> project.</p>
+<ul>
+<li><a href="building.html"><strong>Building from Source</strong></a> - 
+    Details the steps necessary to download Apache Tomcat 5 source code (and the 
+    other packages that it depends on), and build a binary distribution from 
+    those sources.
+    </li>
+<li><a href="changelog.html"><strong>Changelog</strong></a> - Details the
+    changes made to Apache Tomcat.
+    </li>
+<li><a href="status.html"><strong>Status</strong></a> - Apache Tomcat development 
+    status.
+    </li>
+<li><a href="developers.html"><strong>Developers</strong></a> - List of active
+    Apache Tomcat contributors.
+    </li>
+<li><a href="catalina/funcspecs/index.html"><strong>Functional Specifications</strong></a>
+    - Requirements specifications for features of the <em>Catalina</em> servlet
+    container portion of Apache Tomcat 5.</li>
+<li><a href="catalina/docs/api/index.html"><strong>Catalina Javadocs</strong></a>
+    - Javadoc API documentation for the <em>Catalina</em> servlet
+    container and its dependencies.</li>
+<li><a href="jasper/docs/api/index.html"><strong>Jasper Javadocs</strong></a>
+    - Javadoc API documentation for the <em>Jasper</em> JSP container
+    portion of Apache Tomcat 5.</li>
+<li><a href="architecture/index.html"><strong>Apache Tomcat Architecture</strong></a>
+    - Documentation of the Apache Tomcat Server Architecture.</li>
+    
+</ul>
+
+</section>
+
+
+</body>
+</document>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/introduction.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/introduction.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/introduction.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,130 @@
+<?xml version="1.0"?>
+<!DOCTYPE document [
+  <!ENTITY project SYSTEM "project.xml">
+]>
+<document url="introduction.html">
+
+    &project;
+
+    <properties>
+        <author email="rslifka at sfu.ca">Robert Slifka</author>
+        <title>Introduction</title>
+    </properties>
+
+<body>
+
+
+<section name="Introduction">
+
+<p>For administrators and web developers alike, there are some important bits
+of information you should familiarize yourself with before starting out. This
+document serves as a brief introduction to some of the concepts and
+terminology behind the Tomcat container. As well, where to go when you need
+help.</p>
+
+</section>
+
+
+<section name="Terminology">
+
+<p>In the course of reading these documents, you'll run across a number of
+terms; some specific to Tomcat, and others defined by the
+<a href="http://java.sun.com/products/servlet/">Servlet</a> or
+<a href="http://java.sun.com/products/jsp/">JSP</a> specifications.</p>
+
+<ul>
+<li><strong>Context</strong> - In a nutshell, a Context is a
+    web application.</li>
+<li><strong>Term2</strong> - This is it.</li>
+<li><strong>Term3</strong> - This is it!</li>
+</ul>
+
+</section>
+
+
+<section name="Directories and Files">
+
+<p>Throughout the docs, you'll notice there are numerous references to
+<strong>$CATALINA_HOME</strong>. This represents the root of your Tomcat
+installation. When we say, "This information can be found in your
+$CATALINA_HOME/README.txt file" we mean to look at the README.txt file at the
+root of your Tomcat install.</p>
+
+<p>These are some of the key tomcat directories, all relative
+to <strong>$CATALINA_HOME</strong>:</p>
+
+<ul>
+<li><strong>/bin</strong> - Startup, shutdown, and other scripts. The
+    <code>*.sh</code> files (for Unix systems) are functional duplicates of
+    the <code>*.bat</code> files (for Windows systems).  Since the Win32
+    command-line lacks certain functionality, there are some additional
+    files in here.</li>
+<li><strong>/conf</strong> - Configuration files and related DTDs.  The most
+    important file in here is server.xml.  It is the main configuration file
+    for the container.</li>
+<li><strong>/logs</strong> - Log files are here by default.</li>
+<li><strong>/webapps</strong> - This is where your webapps go.</li>
+</ul>
+
+</section>
+
+
+<section name="Configuring Tomcat">
+
+<p>This section will acquaint you with the basic information used during
+the configuration of the container.</p>
+
+<p>All of the information in the configuration files is read at startup,
+meaning that any change to the files necessitates a restart of the container.
+</p>
+
+</section>
+
+
+<section name="Where to Go for Help">
+
+<p>While we've done our best to ensure that these documents are clearly
+written and easy to understand, we may have missed something.  Provided
+below are various web sites and mailing lists in case you get stuck.</p>
+
+<p>As Tomcat 5 is a new release of Tomcat, keep in mind that some of the
+issues and solutions vary between the major versions of Tomcat (4.x versus
+5).  As you search around the web, there will be some documentation that
+is not relevant to Tomcat 5, but 3.x and 4.x.  Doing 3.x or 4.x things to 5
+will probably not work in most cases as the server.xml files are very
+different.</p>
+
+<ul>
+<li>Current document - most documents will list potential hangups. Be sure
+    to fully read the relevant documentation as it will save you much time
+    and effort. There's nothing like scouring the web only to find out that
+    the answer was right in front of you all along!</li>
+<li><a href="http://tomcat.apache.org/faq/">Tomcat FAQ</a> as maintained by the developers.</li>
+<li><a href="http://wiki.apache.org/tomcat/">Tomcat WIKI</a></li>
+<li>Tomcat FAQ at <a href="http://www.jguru.com/faq/home.jsp?topic=Tomcat">jGuru</a></li>
+<li>Tomcat mailing list archives - numerous sites archive the Tomcat mailing
+    lists. Since the links change over time, clicking here will search
+    <a href="http://www.google.com/search?q=tomcat+mailing+list+archives">Google</a>.
+    </li>
+<li>The TOMCAT-USER mailing list, which you can subscribe to
+    <a href="http://tomcat.apache.org/lists.html">here</a>. If you don't
+    get a reply, then there's a good chance that your question was probably
+    answered in the list archives or one of the FAQs.  Although questions
+    about web application development in general are sometimes asked and
+    answered, please focus your questions on Tomcat-specific issues.</li>
+<li>The TOMCAT-DEV mailing list, which you can subscribe to
+    <a href="http://tomcat.apache.org/lists.html">here</a>.  This list is
+    <strong>reserved</strong> for discussions about the development of Tomcat
+    itself.  Questions about Tomcat configuration, and the problems you run
+    into while developing and running applications, will normally be more
+    appropriate on the TOMCAT-USER list instead.</li>
+</ul>
+
+<p>And, if you think something should be in the docs, by all means let us know
+on the TOMCAT-DEV list, or send one of the doc authors email.</p>
+
+</section>
+
+</body>
+
+</document>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/jasper/docs/api/index.html
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/jasper/docs/api/index.html	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/jasper/docs/api/index.html	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,17 @@
+<!doctype html public "-//w3c//dtd html 4.0 transitional//en" "http://www.w3.org/TR/REC-html40/strict.dtd">
+<html>
+    <head>
+    <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+    <title>Administration</title>
+</head>
+
+<body>
+
+Tomcat's internal javadoc is no longer installed by default. Download and install 
+the "fulldocs" package to get it.
+
+You can also access the javadoc online in the Tomcat 
+<a href="http://jakarta.apache.org/tomcat/tomcat-5.5-doc/">documentation bundle</a>.
+
+</body>
+</html>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/jasper-howto.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/jasper-howto.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/jasper-howto.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,345 @@
+<?xml version="1.0"?>
+<!DOCTYPE document [
+  <!ENTITY project SYSTEM "project.xml">
+]>
+<document url="jasper-howto.html">
+
+    &project;
+
+    <properties>
+        <author email="glenn at apache.org">Glenn L. Nielsen</author>
+        <author email="pero at apache.org">Peter Rossbach</author>
+        <title>Jasper 2 JSP Engine How To</title>
+    </properties>
+
+<body>
+
+<section name="Table of Contents">
+<p>
+<a href="#Introduction">Introduction</a><br />
+<a href="#Configuration">Configuration</a><br />
+<a href="#Production Configuration">Production Configuration</a><br />
+<a href="#Web Application Compilation">Web Application Compilation</a><br />
+<a href="#Using Jikes">Using Jikes</a><br />
+</p>
+</section>
+
+<section name="Introduction">
+
+<p>Tomcat 5.5 uses the Jasper 2 JSP Engine to implement
+the <a href="http://java.sun.com/products/jsp/">JavaServer Pages 2.0</a>
+specification.</p>
+
+<p>Jasper 2 has been redesigned to significantly improve performance over
+the orignal Jasper.  In addition to general code improvements the following
+changes were made:
+<ul>
+<li><strong>JSP Custom Tag Pooling</strong> - The java objects instantiated
+for JSP Custom Tags can now be pooled and reused.  This significantly boosts
+the performance of JSP pages which use custom tags.</li>
+<li><strong>Background JSP compilation</strong> - If you make a change to
+a JSP page which had already been compiled Jasper 2 can recompile that
+page in the background.  The previously compiled JSP page will still be
+available to serve requests.  Once the new page has been compiled
+successfully it will replace the old page.  This helps improve availablity
+of your JSP pages on a production server.</li>
+<li><strong>Recompile JSP when included page changes</strong> - Jasper 2
+can now detect when a page included at compile time from a JSP has changed
+and then recompile the parent JSP.</li>
+<li><strong>JDT used to compile JSP pages</strong> - The
+Eclipse JDT Java compiler is now used to perform JSP java source code
+compilation. This compiler loads source dependencies from the container
+classloader. Ant and javac can still be used.</li>
+</ul>
+</p>
+
+<p>Jasper is implemented using the servlet class
+<code>org.apache.jasper.servlet.JspServlet</code>.</p>
+
+</section>
+
+<section name="Configuration">
+
+<p>By default Jasper is configured for use when doing web application
+development.  See the section <a href="#Production Configuration">
+Production Configuration</a> for information on configuring Jasper
+for use on a production Tomcat server.</p>
+
+<p>The servlet which implements Jasper is configured using init parameters
+in your global <code>$CATALINA_BASE/conf/web.xml</code>.
+
+<ul>
+<li><strong>checkInterval</strong> - If development is false and reloading is
+true, background compiles are enabled. checkInterval is the time in seconds
+between checks to see if a JSP page needs to be recompiled. Default
+<code>300</code> seconds.</li>
+
+<li><strong>compiler</strong> - Which compiler Ant should use to compile JSP
+pages.  See the Ant documentation for more information. If the value is not set,
+then the default Eclipse JDT Java compiler will be used instead of using Ant. 
+No default value.</li>
+
+<li><strong>classdebuginfo</strong> - Should the class file be compiled with
+debugging information?  <code>true</code> or <code>false</code>, default
+<code>true</code>.
+</li>
+
+<li><strong>classpath</strong> - What class path should I use while compiling
+generated servlets?  By default the classpath is created dynamically based on
+the current web application.</li>
+
+<li><strong>compilerSourceVM</strong> - What JDK version are the source files compatible with? (Default JDK 1.4)</li>
+
+<li><strong>compilerTargetVM</strong> - What JDK version are the generated files compatible with? (Default JDK 1.4)</li>
+
+<li><strong>development</strong> - Is Jasper used in development mode (will
+check for JSP modification on every access)? <code>true</code> or
+<code>false</code>, default <code>true</code>.</li>
+
+<li><strong>enablePooling</strong> - Determines whether tag handler pooling is
+enabled. <code>true</code> or <code>false</code>, default <code>true</code>.
+</li>
+
+<li><strong>engineOptionsClass</strong> - Allows specifying the Options class
+used to configure Jasper. If not present, the default EmbeddedServletOptions
+will be used.
+</li>
+
+<li><strong>ieClassId</strong> - The class-id value to be sent to Internet
+Explorer when using &lt;jsp:plugin&gt; tags.   Default
+<code>clsid:8AD9C840-044E-11D1-B3E9-00805F499D93</code>.</li>
+
+<li><strong>fork</strong> - Have Ant fork JSP page compiles so they are
+performed in a seperate JVM from Tomcat? <code>true</code> or
+<code>false</code>, default <code>true</code>.</li>
+
+<li><strong>javaEncoding</strong> - Java file encoding to use for generating
+java source files. Default <code>UTF8</code>.</li>
+
+<li><strong>genStringAsCharArray</strong> - Should text strings be generated as char
+arrays, to improve performance in some cases? Default <code>false</code>.</li>
+
+<li><strong>keepgenerated</strong> - Should we keep the generated Java source
+code for each page instead of deleting it? <code>true</code> or
+<code>false</code>, default <code>true</code>.</li>
+
+<li><strong>mappedfile</strong> - Should we generate static content with one 
+print statement per input line, to ease debugging?
+<code>true</code> or <code>false</code>, default <code>true</code>.</li>
+
+<li><strong>modificationTestInterval</strong> - Checks for modification for a given
+JSP file (and all its dependent files) will be performed only once every specified amount
+of seconds. Setting this to 0 will cause the JSP to be checked on every access.
+Default is <code>4</code> seconds.</li>
+
+<li><strong>reloading</strong> - Should Jasper check for modified JSPs?
+<code>true</code> or <code>false</code>, default <code>false</code>.</li>
+
+<li><strong>scratchdir</strong> - What scratch directory should we use when
+compiling JSP pages? Default is the work directory for the current web
+application.</li>
+
+<li><strong>trimSpaces</strong> - Should white spaces in template text between
+actions or directives be trimmed ?, default <code>false</code>.</li>
+</ul>
+</p>
+
+<p>The Java compiler from Eclipse JDT in included as the default compiler. It is an
+advanced Java compiler which will load all dependencies from the Tomcat class loader, 
+which will help tremendously when compiling on large installations with tens of JARs.
+On fast servers, this will allow sub-second recompilation cycles for even large JSP 
+pages. This new compiler will be updated to support the Java 5 syntax as soon as
+possible.</p>
+
+<p>Apache Ant, which was used in previous Tomcat releases, can be used instead instead of 
+the new compiler by simply removing the <code>common/lib/jasper-compiler-jdt.jar</code> file, 
+and placing the <code>ant.jar</code> file from the latest Ant distribution in the 
+<code>common/lib</code> folder.  If you do this, you also need to use the "javac"
+argument to catalina.sh.</p>
+
+</section>
+
+<section name="Production Configuration">
+
+<p>The main JSP optimization which can be done is precompilation of JSPs. However,
+this might not be possible (for example, when using the jsp-property-group feature)
+or practical, in which case the configuration of the Jasper servlet becomes critical.</p>
+
+<p>When using Jasper 2 in a production Tomcat server you should consider
+making the following changes from the default configuration.
+<ul>
+<li><strong>development</strong> - To disable on access checks for JSP
+pages compilation set this to <code>false</code>.</li>
+<li><strong>genStringAsCharArray</strong> - To generate slightly more efficient 
+char arrays, set this to <code>true</code>.</li>
+<li><strong>modificationTestInterval</strong> - If development has to be set to
+<code>true</code> for any reason (such as dynamic generation of JSPs), setting
+this to a high value will improve performance a lot.</li>
+<li><strong>trimSpaces</strong> - To remove useless bytes from the response,
+set this to <code>true</code>.</li>
+</ul>
+</p>
+
+</section>
+
+<section name="Web Application Compilation">
+
+<p>Using Ant is the preferred way to compile web applications using JSPC. 
+Use the script given below (a similar script is included in the "deployer" 
+download) to precompile a webapp:
+</p>
+
+<p>
+<source>
+&lt;project name="Webapp Precompilation" default="all" basedir="."&gt; 
+
+  &lt;target name="jspc"&gt; 
+
+    &lt;taskdef classname="org.apache.jasper.JspC" name="jasper2" &gt; 
+      &lt;classpath id="jspc.classpath"&gt; 
+        &lt;pathelement location="${java.home}/../lib/tools.jar"/&gt; 
+        &lt;fileset dir="${tomcat.home}/bin"&gt; 
+          &lt;include name="*.jar"/&gt; 
+        &lt;/fileset&gt; 
+        &lt;fileset dir="${tomcat.home}/server/lib"&gt; 
+          &lt;include name="*.jar"/&gt; 
+        &lt;/fileset&gt; 
+        &lt;fileset dir="${tomcat.home}/common/lib"&gt; 
+          &lt;include name="*.jar"/&gt; 
+        &lt;/fileset&gt; 
+      &lt;/classpath&gt; 
+    &lt;/taskdef&gt; 
+
+    &lt;jasper2 
+             validateXml="false" 
+             uriroot="${webapp.path}" 
+             webXmlFragment="${webapp.path}/WEB-INF/generated_web.xml" 
+             outputDir="${webapp.path}/WEB-INF/src" /&gt; 
+
+  &lt;/target&gt; 
+
+  &lt;target name="compile"&gt;
+
+    &lt;mkdir dir="${webapp.path}/WEB-INF/classes"/&gt;
+    &lt;mkdir dir="${webapp.path}/WEB-INF/lib"/&gt;
+
+    &lt;javac destdir="${webapp.path}/WEB-INF/classes"
+           optimize="off"
+           debug="on" failonerror="false"
+           srcdir="${webapp.path}/WEB-INF/src" 
+	   excludes="**/*.smap"&gt;
+      &lt;classpath&gt;
+        &lt;pathelement location="${webapp.path}/WEB-INF/classes"/&gt;
+        &lt;fileset dir="${webapp.path}/WEB-INF/lib"&gt;
+          &lt;include name="*.jar"/&gt;
+        &lt;/fileset&gt;
+        &lt;pathelement location="${tomcat.home}/common/classes"/&gt;
+        &lt;fileset dir="${tomcat.home}/common/lib"&gt;
+          &lt;include name="*.jar"/&gt;
+        &lt;/fileset&gt;
+        &lt;pathelement location="${tomcat.home}/shared/classes"/&gt;
+        &lt;fileset dir="${tomcat.home}/shared/lib"&gt;
+          &lt;include name="*.jar"/&gt;
+        &lt;/fileset&gt;
+        &lt;fileset dir="${tomcat.home}/bin"&gt; 
+          &lt;include name="*.jar"/&gt; 
+        &lt;/fileset&gt; 
+      &lt;/classpath&gt;
+      &lt;include name="**" /&gt;
+      &lt;exclude name="tags/**" /&gt;
+    &lt;/javac&gt;
+
+  &lt;/target&gt;
+
+  &lt;target name="all" depends="jspc,compile"&gt;
+  &lt;/target&gt;
+
+  &lt;target name="cleanup"&gt;
+  	&lt;delete&gt;
+        &lt;fileset dir="${webapp.path}/WEB-INF/src"/&gt;
+        &lt;fileset dir="${webapp.path}/WEB-INF/classes/org/apache/jsp"/&gt;
+  	&lt;/delete&gt;
+  &lt;/target&gt;
+
+&lt;/project&gt;
+</source>
+</p>
+
+<p>
+The following command line can be used to run the script
+(replacing the tokens with the Tomcat base path and the path to the webapp 
+which should be precompiled):<br/>
+<source>
+$ANT_HOME/bin/ant -Dtomcat.home=&lt;$TOMCAT_HOME&gt; -Dwebapp.path=&lt;$WEBAPP_PATH&gt;
+</source>
+</p>
+
+<p>
+Then, the declarations and mappings for the servlets which were generated 
+during the precompilation must be added to the web application deployment
+descriptor. Insert the <code>${webapp.path}/WEB-INF/generated_web.xml</code>
+at the right place inside the <code>${webapp.path}/WEB-INF/web.xml</code> file.
+Restart the web application (using the manager) and test it to verify it is 
+running fine with precompiled servlets. An appropriate token placed in the
+web application deployment descriptor may also be used to automatically
+insert the generated servlet declarations and mappings using Ant filtering 
+capabilities. This is actually how all the webapps distributed with Tomcat 
+are automatically compiled as part of the build process.
+</p>
+
+<p>
+At the jasper2 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 5 feature inside your jsp's, add the following javac compiler task
+attributes: <code>source=&quot;1.5&quot; target=&quot;1.5&quot;</code>. For live application
+you can also compile with <code>optimize=&quot;on&quot;</code> and without debug info
+<code>debug=&quot;off&quot;</code>.
+</p>
+
+<p>
+When you don't want to stop the jsp generation at first jsp syntax error, use   
+<code>failOnError=&quot;false&quot;</code>and with <code>showSuccess=&quot;true&quot;</code>
+all successfull <i>jsp to java</i> generation are printed out. Sometimes it is
+very helpfull, when you cleanup the generate java source files at <code>${webapp.path}/WEB-INF/src</code>
+and the compile jsp servlet classes at <code>${webapp.path}/WEB-INF/classes/org/apache/jsp</code>.
+</p>
+
+<p><strong>Hints:</strong>
+<ul>
+<li> When you switch to another tomcat release, then regenerate and recompile
+your jsp's with this version again!</li>
+<li>Use java system property at server runtime to disable tag pooling <code>org.apache.jasper.runtime.JspFactoryImpl.USE_POOL=false</code>.
+and limit the buffering with <code>org.apache.jasper.runtime.BodyContentImpl.LIMIT_BUFFER=true</code>. Note that changing
+from the defaults may affect performance, but depending on the application.</li>
+</ul>
+</p>
+</section>
+
+<section name="Using Jikes">
+
+<p>If you wish to use
+<a href="http://oss.software.ibm.com/developerworks/opensource/jikes/">
+Jikes</a> to compile JSP pages:
+<ul>
+<li>From your <a href="ant.apache.org">Ant</a> installation, copy ant.jar
+and (if it's available: Ant 1.5 and later) ant-launcher.jar to 
+<code>$CATALINA_BASE/common/lib</code>.</li>
+<li>Download and install jikes. jikes must support the -encoding option.
+Execute <code>jikes -help</code> to verify that it was built with support
+for <code>-encoding</code>.</li>
+<li>Set the init parameter <code>compiler</code> to <code>jikes</code>.</li>
+<li>Define the property <code>-Dbuild.compiler.emacs=true</code> when starting
+Tomcat by adding it to your <code>CATALINA_OPTS</code> environment variable.
+This changes how jikes outputs error messages so that it is compatible with
+Jasper.</li>
+<li>If you get an error reporting that jikes can't use UTF8 encoding, try
+setting the init parameter <code>javaEncoding</code> to
+<code>ISO-8859-1</code>.</li>
+</ul>
+</p>
+
+</section>
+</body>
+
+</document>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/jndi-datasource-examples-howto.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/jndi-datasource-examples-howto.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/jndi-datasource-examples-howto.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,655 @@
+<?xml version="1.0"?>
+<!DOCTYPE document [
+  <!ENTITY project SYSTEM "project.xml">
+]>
+<document url="jndi-datasource-examples-howto.html">
+
+    &project;
+
+    <properties>
+        <author email="leslie.hughes at rubus.com">Les Hughes</author>
+        <author email="david-tomcat at haraburda.com">David Haraburda</author>
+        <author>Glenn Nielsen</author>
+        <author email="yoavs at apache.org">Yoav Shapira</author>
+        <title>JNDI Datasource HOW-TO</title>
+    </properties>
+
+<body>
+
+<section name="Table of Contents">
+<p>
+<a href="#Introduction">Introduction</a><br />
+<a href="#Database Connection Pool (DBCP) Configurations">
+Database Connection Pool (DBCP) Configurations</a><br />
+<a href="#Non DBCP Solutions">Non DBCP Solutions</a><br />
+<a href="#Oracle 8i with OCI client">Oracle 8i with OCI client</a><br />
+<a href="#Common Problems">Common Problems</a><br />
+</p>
+</section>
+
+<section name="Introduction">
+
+<p>JNDI Datasource configuration is covered extensively in the
+JNDI-Resources-HOWTO.  However, feedback from <code>tomcat-user</code> has
+shown that specifics for individual configurations can be rather tricky.</p>
+
+<p>Here then are some example configurations that have been posted to
+tomcat-user for popular databases and some general tips for db useage.</p>
+
+<p>You should be aware that since these notes are derived from configuration
+and/or feedback posted to <code>tomcat-user</code> YMMV :-). Please let us
+know if you have any other tested configurations that you feel may be of use
+to the wider audience, or if you feel we can improve this section in anyway.</p>
+
+<p>
+<b>Please note that JNDI resource configuration has changed somewhat between
+Tomcat 5.0.x and Tomcat 5.5.x.</b>  You will most likely need to modify your JNDI
+resource configurations to match the syntax in the example below in order
+to make them work in Tomcat 5.5.x.
+</p>
+
+<p>
+Also, please note that JNDI DataSource configuration in general, and this 
+tutorial in particular, assumes that you have read and understood the 
+<a href="config/context.html">Context</a> and 
+<a href="config/host.html">Host</a> configuration references, including
+the section about Automatic Application Deployment in the latter reference.
+</p>
+</section>
+
+<section name="Database Connection Pool (DBCP) Configurations">
+
+<p>DBCP provides support for JDBC 2.0.  On systems using a 1.4 JVM DBCP
+will support JDBC 3.0. Please let us know if you have used DBCP and its
+JDBC 3.0 features with a 1.4 JVM.
+</p>
+
+<p>See the <a href="http://jakarta.apache.org/commons/dbcp/configuration.html">
+DBCP documentation</a> for a complete list of configuration parameters.
+</p>
+
+<subsection name="Installation">
+<p>DBCP uses the Jakarta-Commons Database Connection Pool. It relies on
+number of Jakarta-Commons components:
+<ul>
+<li>Jakarta-Commons DBCP</li>
+<li>Jakarta-Commons Collections</li>
+<li>Jakarta-Commons Pool</li>
+</ul>
+These libraries are located in a single JAR at 
+<code>$CATALINA_HOME/common/lib/naming-factory-dbcp.jar</code>. However,
+only the classes needed for connection pooling have been included, and the
+packages have been renamed to avoid interfering with applications.
+</p>
+
+</subsection>
+
+<subsection name="Preventing dB connection pool leaks">
+
+<p>
+A database connection pool creates and manages a pool of connections
+to a database. Recycling and reusing already existing connections
+to a dB is more efficient than opening a new connection.
+</p>
+
+<p>
+There is one problem with connection pooling.  A web application has
+to explicetely close ResultSet's, Statement's, and Connection's.
+Failure of a web application to close these resources can result in
+them never being available again for reuse, a db connection pool "leak".
+This can eventually result in your web application db connections failing
+if there are no more available connections.</p>
+
+<p>
+There is a solution to this problem.  The Jakarta-Commons DBCP can be
+configured to track and recover these abandoned dB connections.  Not
+only can it recover them, but also generate a stack trace for the code
+which opened these resources and never closed them.</p>
+
+<p>
+To configure a DBCP DataSource so that abandoned dB connections are
+removed and recycled add the following attribute to the
+<code>Resource</code> configuration for your DBCP DataSource:
+<source>
+            removeAbandoned="true"
+</source>
+When available db connections run low DBCP will recover and recyle
+any abandoned dB connections it finds. The default is <code>false</code>.
+</p>
+
+<p>
+Use the <code>removeAbandonedTimeout</code> attribute to set the number
+of seconds a dB connection has been idle before it is considered abandoned.
+<source>
+            removeAbandonedTimeout="60"
+</source>
+The default timeout for removing abandoned connections is 300 seconds.
+</p>
+
+<p>
+The <code>logAbandoned</code> attribute can be set to <code>true</code>
+if you want DBCP to log a stack trace of the code which abandoned the
+dB connection resources.
+<source>
+            logAbandoned="true"
+</source>
+The default is <code>false</code>.
+</p>
+
+</subsection>
+
+<subsection name="MySQL DBCP Example">
+
+<h3>0. Introduction</h3>
+<p>Versions of <a href="http://www.mysql.com/products/mysql/index.html">MySQL</a> and JDBC drivers that have been reported to work:
+<ul>
+<li>MySQL 3.23.47, MySQL 3.23.47 using InnoDB,, MySQL 3.23.58,  MySQL 4.0.1alpha</li>
+<li><a href="http://www.mysql.com/products/connector-j">Connector/J</a> 3.0.11-stable (the official JDBC Driver)</li>
+<li><a href="http://mmmysql.sourceforge.net">mm.mysql</a> 2.0.14 (an old 3rd party JDBC Driver)</li>
+</ul>
+</p>
+
+<p>Before you proceed, don't forget to copy the JDBC Driver's jar into <code>$CATALINA_HOME/common/lib</code>.</p>
+
+<h3>1. MySQL configuration</h3>
+<p>
+Ensure that you follow these instructions as variations can cause problems.
+</p>
+
+<p>Create a new test user, a new database and a single test table.
+Your MySQL user <strong>must</strong> have a password assigned. The driver
+will fail if you try to connect with an empty password.
+<source>
+mysql&gt; GRANT ALL PRIVILEGES ON *.* TO javauser at localhost 
+    -&gt;   IDENTIFIED BY 'javadude' WITH GRANT OPTION;
+mysql&gt; create database javatest;
+mysql&gt; use javatest;
+mysql&gt; create table testdata (
+    -&gt;   id int not null auto_increment primary key,
+    -&gt;   foo varchar(25), 
+    -&gt;   bar int);
+</source>
+<blockquote>
+<strong>Note:</strong> the above user should be removed once testing is
+complete!
+</blockquote>
+</p>
+
+<p>Next insert some test data into the testdata table.
+<source>
+mysql&gt; insert into testdata values(null, 'hello', 12345);
+Query OK, 1 row affected (0.00 sec)
+
+mysql> select * from testdata;
++----+-------+-------+
+| ID | FOO   | BAR   |
++----+-------+-------+
+|  1 | hello | 12345 |
++----+-------+-------+
+1 row in set (0.00 sec)
+
+mysql&gt;
+</source>
+</p>
+
+<h3>2. server.xml configuration</h3>
+<p>Configure the JNDI DataSource in Tomcat by adding a declaration for your
+resource to <code>$CATALINA_HOME/conf/server.xml</code>.</p>
+<p>Add this in between the <code>&lt;/Context&gt;</code> tag of the examples
+context and the <code>&lt;/Host&gt;</code> tag closing the localhost definition.
+If there is no such tag, you can add one as illustrated in the 
+<a href="config/context.html">Context</a> and
+<a href="config/host.html">Host</a> configuration references, and repeated below
+for your convenience.
+
+<source>
+&lt;Context path="/DBTest" docBase="DBTest"
+        debug="5" reloadable="true" crossContext="true"&gt;
+
+    &lt;!-- maxActive: Maximum number of dB connections in pool. Make sure you
+         configure your mysqld max_connections large enough to handle
+         all of your db connections. Set to 0 for no limit.
+         --&gt;
+
+    &lt;!-- maxIdle: Maximum number of idle dB connections to retain in pool.
+         Set to -1 for no limit.  See also the DBCP documentation on this
+         and the minEvictableIdleTimeMillis configuration parameter.
+         --&gt;
+
+    &lt;!-- maxWait: Maximum time to wait for a dB connection to become available
+         in ms, in this example 10 seconds. An Exception is thrown if
+         this timeout is exceeded.  Set to -1 to wait indefinitely.
+         --&gt;
+
+    &lt;!-- username and password: MySQL dB username and password for dB connections  --&gt;
+
+    &lt;!-- driverClassName: Class name for the old mm.mysql JDBC driver is
+         org.gjt.mm.mysql.Driver - we recommend using Connector/J though.
+         Class name for the official MySQL Connector/J driver is com.mysql.jdbc.Driver.
+         --&gt;
+    
+    &lt;!-- url: The JDBC connection url for connecting to your MySQL dB.
+         The autoReconnect=true argument to the url makes sure that the
+         mm.mysql JDBC Driver will automatically reconnect if mysqld closed the
+         connection.  mysqld by default closes idle connections after 8 hours.
+         --&gt;
+
+  &lt;Resource name="jdbc/TestDB" auth="Container" type="javax.sql.DataSource"
+               maxActive="100" maxIdle="30" maxWait="10000"
+               username="javauser" password="javadude" driverClassName="com.mysql.jdbc.Driver"
+               url="jdbc:mysql://localhost:3306/javatest?autoReconnect=true"/&gt;
+
+&lt;/Context&gt;
+</source>
+</p>
+
+<h3>3. web.xml configuration</h3>
+
+<p>Now create a <code>WEB-INF/web.xml</code> for this test application.
+<source>
+&lt;web-app 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-app_2_4.xsd"
+    version="2.4"&gt;
+  &lt;description&gt;MySQL Test App&lt;/description&gt;
+  &lt;resource-ref&gt;
+      &lt;description&gt;DB Connection&lt;/description&gt;
+      &lt;res-ref-name&gt;jdbc/TestDB&lt;/res-ref-name&gt;
+      &lt;res-type&gt;javax.sql.DataSource&lt;/res-type&gt;
+      &lt;res-auth&gt;Container&lt;/res-auth&gt;
+  &lt;/resource-ref&gt;
+&lt;/web-app&gt;
+</source>
+</p>
+
+<h3>4. Test code</h3>
+<p>Now create a simple <code>test.jsp</code> page for use later.
+<source>
+&lt;%@ taglib uri="http://java.sun.com/jsp/jstl/sql" prefix="sql" %&gt;
+&lt;%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %&gt;
+
+&lt;sql:query var="rs" dataSource="jdbc/TestDB"&gt;
+select id, foo, bar from testdata
+&lt;/sql:query&gt;
+
+&lt;html&gt;
+  &lt;head&gt;
+    &lt;title&gt;DB Test&lt;/title&gt;
+  &lt;/head&gt;
+  &lt;body&gt;
+
+  &lt;h2&gt;Results&lt;/h2&gt;
+  
+&lt;c:forEach var="row" items="${rs.rows}"&gt;
+    Foo ${row.foo}&lt;br/&gt;
+    Bar ${row.bar}&lt;br/&gt;
+&lt;/c:forEach&gt;
+
+  &lt;/body&gt;
+&lt;/html&gt;
+</source>
+</p>
+
+<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 Sun's <a href="http://java.sun.com/webservices/downloads/webservicespack.html">Java Web Services Developer Pack</a> or <a href="http://jakarta.apache.org/taglibs/doc/standard-doc/intro.html">Jakarta Taglib Standard 1.1</a> project - 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 <code>WEB-INF/lib</code> directory.
+
+</p>
+
+<p>Finally deploy your web app into <code>$CATALINA_HOME/webapps</code> either
+as a warfile called <code>DBTest.war</code> or into a sub-directory called
+<code>DBTest</code></p>
+<p>Once deployed, point a browser at
+<code>http://localhost:8080/DBTest/test.jsp</code> to view the fruits of
+your hard work.</p>
+
+</subsection>
+
+<subsection name="Oracle 8i, 9i &amp; 10g">
+<h3>0.    Introduction</h3>
+
+<p>Oracle requires minimal changes from the MySQL configuration except for the
+usual gotchas :-)</p>
+<p>Drivers for older Oracle versions may be distributed as *.zip files rather
+than *.jar files. Tomcat will only use <code>*.jar</code> files installed in
+<code>$CATALINA_HOME/common/lib</code>. Therefore <code>classes111.zip</code>
+or <code>classes12.zip</code> will need to be renamed with a <code>.jar</code>
+extension. Since jarfiles are zipfiles, there is no need to unzip and jar these
+files - a simple rename will suffice.</p>
+
+<p>Some early versions of Tomcat 4.0 when used with JDK 1.4 will not load
+classes12.zip unless you unzip the file, remove the <code>javax.sql.*</code>
+class heirarchy and rejar.</p>
+
+<p>For Oracle 9i onwards you should use <code>oracle.jdbc.OracleDriver</code>
+rather than <code>oracle.jdbc.driver.OracleDriver</code> as Oracle have stated
+that <code>oracle.jdbc.driver.OracleDriver</code> is deprecated and support
+for this driver class will be discontinued in the next major release.
+</p>
+
+<h3>1.    server.xml configuration</h3>
+<p>In a similar manner to the mysql config above, you will need to define your
+Datasource in your server.xml file. Here we define a Datasource called myoracle
+using the thin driver to connect as user scott, password tiger to the sid
+called mysid. (Note: with the thin driver this sid is not the same as the
+tnsname). The schema used will be the default schema for the user scott.</p>
+
+<p>Use of the OCI driver should simply involve a changing thin to oci in the URL string.
+<source>
+&lt;Resource name="jdbc/myoracle" auth="Container"
+              type="javax.sql.DataSource" driverClassName="oracle.jdbc.OracleDriver"
+              url="jdbc:oracle:thin:@127.0.0.1:1521:mysid"
+              username="scott" password="tiger" maxActive="20" maxIdle="10"
+              maxWait="-1"/&gt; 
+</source>
+</p>
+
+<h3>2.    web.xml configuration</h3>
+<p>You should ensure that you respect the elemeent ordering defined by the DTD when you
+create you applications web.xml file.</p>
+<source>
+&lt;resource-ref&gt;
+ &lt;description&gt;Oracle Datasource example&lt;/description&gt;
+ &lt;res-ref-name&gt;jdbc/myoracle&lt;/res-ref-name&gt;
+ &lt;res-type&gt;javax.sql.DataSource&lt;/res-type&gt;
+ &lt;res-auth&gt;Container&lt;/res-auth&gt;
+&lt;/resource-ref&gt;
+</source>
+<h3>3.   Code example</h3>
+<p>You can use the same example application as above (asuming you create the required DB
+instance, tables etc.) replacing the Datasource code with something like</p>
+<source>
+Context initContext = new InitialContext();
+Context envContext  = (Context)initContext.lookup("java:/comp/env");
+DataSource ds = (DataSource)envContext.lookup("jdbc/myoracle");
+Connection conn = ds.getConnection();
+//etc.
+</source>
+</subsection>
+
+
+<subsection name="PostgreSQL">
+<h3>0.    Introduction</h3>
+<p>PostgreSQL is configured in a similar manner to Oracle.</p>
+
+<h3>1. Required files </h3>
+<p>
+Copy the Postgres JDBC jar to $CATALINA_HOME/common/lib. As with Oracle, the
+jars need to be in this directory in order for DBCP's Classloader to find
+them. This has to be done regardless of which configuration step you take next.
+</p>
+
+<h3>2. Resource configuration</h3>
+
+<p>
+You have two choices here: define a datasource that is shared across all Tomcat
+applications, or define a datasource specifically for one application.
+</p>
+
+<h4>2a. Shared resource configuration</h4>
+<p>
+Use this option if you wish to define a datasource that is shared across
+multiple Tomcat applications, or if you just prefer defining your datasource
+in this file.
+</p>
+<p><i>This author has not had success here, although others have reported so.
+Clarification would be appreciated here.</i></p>
+
+<source>
+&lt;Resource name="jdbc/postgres" auth="Container"
+          type="javax.sql.DataSource" driverClassName="org.postgresql.Driver"
+          url="jdbc:postgresql://127.0.0.1:5432/mydb"
+          username="myuser" password="mypasswd" maxActive="20" maxIdle="10" maxWait="-1"/&gt;
+</source>
+<h4>2b. Application-specific resource configuration</h4>
+
+<p>
+Use this option if you wish to define a datasource specific to your application,
+not visible to other Tomcat applications. This method is less invasive to your
+Tomcat installation.
+</p>
+
+<p>
+Create a resource definition file for your application defining the
+datasource. This file must have the same name as your application, so if
+your application deploys as <code>someApp.war</code>, this filename must
+be <code>someApp.xml</code>. This file should look something like the following.
+</p>
+
+<source>
+&lt;Context path="/someApp" docBase="someApp"
+   crossContext="true" reloadable="true" debug="1"&gt;
+
+&lt;Resource name="jdbc/postgres" auth="Container"
+          type="javax.sql.DataSource" driverClassName="org.postgresql.Driver"
+          url="jdbc:postgresql://127.0.0.1:5432/mydb"
+          username="myuser" password="mypasswd" maxActive="20" maxIdle="10"
+maxWait="-1"/&gt;
+&lt;/Context&gt;
+</source>
+
+<h3>3. web.xml configuration</h3>
+<source>
+&lt;resource-ref&gt;
+ &lt;description&gt;postgreSQL Datasource example&lt;/description&gt;
+ &lt;res-ref-name&gt;jdbc/postgres&lt;/res-ref-name&gt;
+ &lt;res-type&gt;javax.sql.DataSource&lt;/res-type&gt;
+ &lt;res-auth&gt;Container&lt;/res-auth&gt;
+&lt;/resource-ref&gt;
+</source>
+
+<h4>4. Accessing the datasource</h4>
+<p>
+When accessing the datasource programmatically, remember to prepend
+<code>java:/comp/env</code> to your JNDI lookup, as in the following snippet of
+code. Note also that "jdbc/postgres" can be replaced with any value you prefer, provided
+you change it in the above resource definition file as well.
+</p>
+
+<source>
+InitialContext cxt = new InitialContext();
+if ( cxt == null ) {
+   throw new Exception("Uh oh -- no context!");
+}
+
+DataSource ds = (DataSource) cxt.lookup( "java:/comp/env/jdbc/postgres" );
+
+if ( ds == null ) {
+   throw new Exception("Data source not found!");
+}
+</source>
+
+</subsection>
+</section>
+
+<section name="Non-DBCP Solutions">
+<p>
+These solutions either utilise a single connection to the database (not recommended for anything other
+than testing!) or some other pooling technology.
+</p>
+</section>
+
+<section name="Oracle 8i with OCI client">
+<subsection name="Introduction">
+<p>Whilst not strictly addressing the creation of a JNDI DataSource using the OCI client, these notes can be combined with the
+Oracle and DBCP solution above.</p>
+<p>
+In order to use OCI driver, you should have an Oracle client installed. You should have installed
+Oracle8i(8.1.7) client from cd,  and download the suitable JDBC/OCI
+driver(Oracle8i 8.1.7.1 JDBC/OCI Driver) from <a href="http://otn.oracle.com/">otn.oracle.com</a>. 
+</p>
+<p>
+After renaming <code>classes12.zip</code> file to <code>classes12.jar</code>
+for Tomcat, copy it into <code>$CATALINA_HOME/common/lib</code>. 
+You may also have to remove the <code>javax.sql.*</code> classes
+from this file depending upon the version of Tomcat and JDK you are using.
+</p>
+</subsection>
+
+<subsection name="Putting it all together">
+<p>
+Ensure that you have the <code>ocijdbc8.dll</code> or <code>.so</code> in your <code>$PATH</code> or <code>LD_LIBRARY_PATH</code>
+ (possibly in <code>$ORAHOME\bin</code>) and also confirm that the native library can be loaded by a simple test program 
+using <code>System.loadLibrary("ocijdbc8");</code>
+</p>
+<p>
+You should next create a simple test servlet or jsp that has these
+<strong>critical lines</strong>:
+</p>
+<source>
+DriverManager.registerDriver(new
+oracle.jdbc.driver.OracleDriver());
+conn =
+DriverManager.getConnection("jdbc:oracle:oci8:@database","username","password");
+</source>
+<p>
+where database is of the form <code>host:port:SID</code> Now if you try to access the URL of your 
+test servlet/jsp and what you get is a 
+<code>ServletException</code> with a root cause of <code>java.lang.UnsatisfiedLinkError:get_env_handle</code>.
+</p>
+<p>
+First, the <code>UnsatisfiedLinkError</code> indicates that you have 
+<ul>
+<li>a mismatch between your JDBC classes file and
+your Oracle client version. The giveaway here is the message stating that a needed library file cannot be
+found. For example, you may be using a classes12.zip file from Oracle Version 8.1.6 with a Version 8.1.5
+Oracle client. The classeXXXs.zip file and Oracle client software versions must match.
+</li>
+<li>A <code>$PATH</code>, <code>LD_LIBRARY_PATH</code> problem.</li>
+<li>It has been reported that ignoring the driver you have downloded from otn and using 
+the classes12.zip file from the directory <code>$ORAHOME\jdbc\lib</code> will also work.
+</li>
+</ul>
+</p>
+<p>
+Next you may experience the error <code>ORA-06401 NETCMN: invalid driver designator</code>
+</p>
+<p>
+The Oracle documentation says : "Cause: The login (connect) string contains an invalid
+driver designator. Action: Correct the string and re-submit."
+
+Change the database connect string (of the form <code>host:port:SID</code>) with this one:
+<code>(description=(address=(host=myhost)(protocol=tcp)(port=1521))(connect_data=(sid=orcl)))</code>
+</p>
+<p>
+<i>Ed. Hmm, I don't think this is really needed if you sort out your TNSNames - but I'm not an Oracle DBA :-)</i>
+</p>
+</subsection>
+</section>
+
+<section name="Common Problems">
+<p>Here are some common problems encountered with a web application which
+uses a database and tips for how to solve them.</p>
+
+<subsection name="Intermittent dB Connection Failures">
+<p>
+Tomcat runs within a JVM.  The JVM periodically performs garbage collection
+(GC) to remove java objects which are no longer being used.  When the JVM
+performs GC execution of code within Tomcat freezes. If the maximum time
+configured for establishment of a dB connection is less than the amount
+of time garbage collection took you can get a db conneciton failure.
+</p>
+
+<p>To collect data on how long garbage collection is taking add the
+<code>-verbose:gc</code> argument to your <code>CATALINA_OPTS</code>
+environment variable when starting Tomcat.  When verbose gc is enabled
+your <code>$CATALINA_BASE/logs/catalina.out</code> log file will include
+data for every garbage collection including how long it took.</p>
+
+<p>When your JVM is tuned correctly 99% of the time a GC will take less
+than one second.  The remainder will only take a few seconds.  Rarely,
+if ever should a GC take more than 10 seconds.</p>
+
+<p>Make sure that the db connection timeout is set to 10-15 seconds.
+For the DBCP you set this using the parameter <code>maxWait</code>.</p>
+
+</subsection>
+
+<subsection name="Random Connection Closed Exceptions">
+<p>
+These can occur when one request gets a db connection from the connection
+pool and closes it twice.  When using a connection pool, closing the
+connection just returns it to the pool for reuse by another request,
+it doesn't close the connection.  And Tomcat uses multiple threads to
+handle concurrent requests. Here is an example of the sequence
+of events which could cause this error in Tomcat:
+<pre>
+  Request 1 running in Thread 1 gets a db connection.
+
+  Request 1 closes the db connection.
+
+  The JVM switches the running thread to Thread 2
+
+  Request 2 running in Thread 2 gets a db connection
+  (the same db connection just closed by Request 1).
+
+  The JVM switches the running thread back to Thread 1
+
+  Request 1 closes the db connection a second time in a finally block.
+
+  The JVM switches the running thread back to Thread 2
+
+  Request 2 Thread 2 tries to use the db connection but fails
+  because Request 1 closed it.
+</pre>
+Here is an example of properly written code to use a db connection
+obtained from a connection pool:
+<pre>
+  Connection conn = null;
+  Statement stmt = null;  // Or PreparedStatement if needed
+  ResultSet rs = null;
+  try {
+    conn = ... get connection from connection pool ...
+    stmt = conn.createStatement("select ...");
+    rs = stmt.executeQuery();
+    ... iterate through the result set ...
+    rs.close();
+    rs = null;
+    stmt.close();
+    stmt = null;
+    conn.close(); // Return to connection pool
+    conn = null;  // Make sure we don't close it twice
+  } catch (SQLException e) {
+    ... deal with errors ...
+  } finally {
+    // Always make sure result sets and statements are closed,
+    // and the connection is returned to the pool
+    if (rs != null) {
+      try { rs.close(); } catch (SQLException e) { ; }
+      rs = null;
+    }
+    if (stmt != null) {
+      try { stmt.close(); } catch (SQLException e) { ; }
+      stmt = null;
+    }
+    if (conn != null) {
+      try { conn.close(); } catch (SQLException e) { ; }
+      conn = null;
+    }
+  }
+</pre>
+</p>
+
+</subsection>
+
+<subsection name="Context versus GlobalNamingResources">
+<p>
+  Please note that although the above instructions place the JNDI declarations in a Context
+  element, it is possible and sometimes desirable to place these declarations in the 
+  <a href="config/globalresources.html">GlobalNamingResources</a> section of the server
+  configuration file.  A resource placed in the GlobalNamingResources section will be shared
+  among the Contexts of the server.
+</p>
+</subsection>
+
+<subsection name="JNDI Resource Naming and Realm Interaction">
+<p>
+  In order to get Realms to work, the realm must refer to the datasource as
+  defined in the &lt;GlobalNamingResources&gt; or &lt;Context&gt; section, not a datasource as renamed
+  using &lt;ResourceLink&gt;.
+</p>
+</subsection> 
+
+</section>
+
+</body>
+</document>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/jndi-resources-howto.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/jndi-resources-howto.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/jndi-resources-howto.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,765 @@
+<?xml version="1.0"?>
+<!DOCTYPE document [
+  <!ENTITY project SYSTEM "project.xml">
+]>
+<document url="jndi-resources-howto.html">
+
+    &project;
+
+    <properties>
+      <author email="craigmcc at apache.org">Craig R. McClanahan</author>
+      <author email="yoavs at apache.org">Yoav Shapira</author>
+      <title>JNDI Resources HOW-TO</title>
+    </properties>
+
+<body>
+
+
+<section name="Introduction">
+
+<p>Tomcat 5 provides a JNDI <strong>InitialContext</strong> implementation
+instance for each web application running under it, in a manner that is 
+compatible with those provided by a 
+<a href="http://java.sun.com/j2ee">Java2 Enterprise Edition</a> application 
+server. 
+
+The J2EE standard provides a standard set of elements in 
+the <code>/WEB-INF/web.xml</code> file to reference resources; resources 
+referenced in these elements must be defined in an application-server-specific configuration. 
+</p>
+
+<p>For Tomcat 5, these entries in per-web-application 
+<code>InitialContext</code> are configured in the 
+<code><strong>&lt;Context&gt;</strong></code> elements that can be specified 
+in either <code>$CATALINA_HOME/conf/server.xml</code> or, preferably, 
+the per-web-application context XML file (either <code>META-INF/context.xml</code>).
+</p>
+
+<p>Tomcat 5 maintains a separate namespace of global resources for the 
+entire server.  These are configured in the 
+<a href="config/globalresources.html">
+<code><strong>&lt;GlobalNameingResources&gt;</strong></code></a> element of 
+<code>$CATALINA_HOME/conf/server.xml</code>. You may expose these resources to 
+web applications by using 
+<code><strong>&lt;ResourceLink&gt;</strong></code> elements.
+</p>
+
+<p>The resources defined in these elements
+may be referenced by the following elements in the web application deployment
+descriptor (<code>/WEB-INF/web.xml</code>) of your web application:</p>
+<ul>
+<li><code><strong>&lt;env-entry&gt;</strong></code> - Environment entry, a
+    single-value parameter that can be used to configure how the application
+    will operate.</li>
+<li><code><strong>&lt;resource-ref&gt;</strong></code> - Resource reference,
+    which is typically to an object factory for resources such as a JDBC
+    <code>DataSource</code>, a JavaMail <code>Session</code>, or custom
+    object factories configured into Tomcat 5.</li>
+<li><code><strong>&lt;resource-env-ref&gt;</strong></code> - Resource
+    environment reference, a new variation of <code>resource-ref</code>
+    added in Servlet 2.4 that is simpler to configure for resources
+    that do not require authentication information.</li>
+</ul>
+
+<p>The <code>InitialContext</code> is configured as a web application is
+initially deployed, and is made available to web application components (for
+read-only access).  All configured entries and resources are placed in
+the <code>java:comp/env</code> portion of the JNDI namespace, so a typical
+access to a resource - in this case, to a JDBC <code>DataSource</code> -
+would look something like this:</p>
+
+<source>
+// Obtain our environment naming context
+Context initCtx = new InitialContext();
+Context envCtx = (Context) initCtx.lookup("java:comp/env");
+
+// Look up our data source
+DataSource ds = (DataSource)
+  envCtx.lookup("jdbc/EmployeeDB");
+
+// Allocate and use a connection from the pool
+Connection conn = ds.getConnection();
+... use this connection to access the database ...
+conn.close();
+</source>
+
+<p>See the following Specifications for more information about programming APIs
+for JNDI, and for the features supported by Java2 Enterprise Edition (J2EE)
+servers, which Tomcat emulates for the services that it provides:</p>
+<ul>
+<li><a href="http://java.sun.com/products/jndi/#download">Java Naming and
+    Directory Interface</a> (included in JDK 1.4, available separately for
+    prior JDK versions)</li>
+<li><a href="http://java.sun.com/j2ee/download.html">J2EE Platform
+    Specification</a> (in particular, see Chapter 5 on <em>Naming</em>)</li>
+</ul>
+
+</section>
+
+
+<section name="Configuring JNDI Resources">
+
+<p>Each available JNDI Resource is configured based on inclusion of the
+following elements in the <code><strong>&lt;Context&gt;</strong></code> or 
+<code><strong>&lt;DefaultContext&gt;</strong></code> elements:</p>
+
+<ul>
+<li><a href="config/context.html#Environment Entries">&lt;Environment&gt;</a> -
+    Configure names and values for scalar environment entries that will be
+    exposed to the web application through the JNDI
+    <code>InitialContext</code> (equivalent to the inclusion of an
+    <code>&lt;env-entry&gt;</code> element in the web application
+    deployment descriptor).</li>
+<li><a href="config/context.html#Resource Definitions">&lt;Resource&gt;</a> -
+    Configure the name and data type of a resource made available to the
+    application (equivalent to the inclusion of a
+    <code>&lt;resource-ref&gt;</code> element in the web application
+    deployment descriptor).</li>
+<li><a href="config/context.html#Resource Links">&lt;ResourceLink&gt;</a> -
+    Add a link to a resource defined in the global JNDI context. Use resource 
+    links to give a web application access to a resource defined in 
+    the<a href="config/globalresources.html">&lt;GlobalNamingResources&gt;</a>
+    child element of the <a href="config/server.html">&lt;Server&gt;</a>
+    element.</li>
+<li><a href="config/context.html#Transaction">&lt;Transaction&gt;</a> -
+    Add a resource factory for instantiating the UserTransaction object 
+    instance that is available at <code>java:comp/UserTransaction</code>.</li>
+
+</ul>
+
+<p>Any number of these elements may be nested inside a
+<a href="config/context.html">&lt;Context&gt;</a> element (to be associated
+only with that particular web application).</p>
+
+<p>In addition, the names and values of all <code>&lt;env-entry&gt;</code>
+elements included in the web application deployment descriptor
+(<code>/WEB-INF/web.xml</code>) are configured into the initial context as
+well, overriding corresponding values from <code>conf/server.xml</code>
+<strong>only</strong> if allowed by the corresponding
+<code>&lt;Environment&gt;</code> element (by setting the
+<code>override</code> attribute to "true").</p>
+
+<p>Global resources can be defined in the server-wide JNDI context, by adding
+the resource elements described above to the
+<a href="config/globalresources.html">&lt;GlobalNamingResources&gt;</a>
+child element of the <a href="config/server.html">&lt;Server&gt;</a>
+element and using a 
+<a href="config/context.html#Resource Links">&lt;ResourceLink&gt;</a> to
+include it in the per-web-application context.</p>
+
+</section>
+
+
+<section name="Tomcat Standard Resource Factories">
+
+  <p>Tomcat 5 includes a series of standard resource factories that can
+  provide services to your web applications, but give you configuration
+  flexibility (in <code>$CATALINA_HOME/conf/server.xml</code>) without
+  modifying the web application or the deployment descriptor.  Each
+  subsection below details the configuration and usage of the standard
+  resource factories.</p>
+
+  <p>See <a href="#Adding Custom Resource Factories">Adding Custom
+  Resource Factories</a> for information about how to create, install,
+  configure, and use your own custom resource factory classes with
+  Tomcat 5.</p>
+
+  <p><em>NOTE</em> - Of the standard resource factories, only the
+  "JDBC Data Source" and "User Transaction" factories are mandated to
+  be available on other platforms, and then they are required only if
+  the platform implements the Java2 Enterprise Edition (J2EE) specs.
+  All other standard resource factories, plus custom resource factories
+  that you write yourself, are specific to Tomcat and cannot be assumed
+  to be available on other containers.</p>
+
+  <subsection name="Generic JavaBean Resources">
+
+    <h3>0.  Introduction</h3>
+
+    <p>This resource factory can be used to create objects of <em>any</em>
+    Java class that conforms to standard JavaBeans naming conventions (i.e.
+    it has a zero-arguments constructor, and has property setters that
+    conform to the setFoo() naming pattern.  The resource factory will
+    create a new instance of the appropriate bean class every time a
+    <code>lookup()</code> for this entry is made.</p>
+
+    <p>The steps required to use this facility are described below.</p>
+
+    <h3>1.  Create Your JavaBean Class</h3>
+
+    <p>Create the JavaBean class which will be instantiated each time
+    that the resource factory is looked up.  For this example, assume
+    you create a class <code>com.mycompany.MyBean</code>, which looks
+    like this:</p>
+
+<source>
+package com.mycompany;
+
+public class MyBean {
+
+  private String foo = "Default Foo";
+
+  public String getFoo() {
+    return (this.foo);
+  }
+
+  public void setFoo(String foo) {
+    this.foo = foo;
+  }
+
+  private int bar = 0;
+
+  public int getBar() {
+    return (this.bar);
+  }
+
+  public void setBar(int bar) {
+    this.bar = bar;
+  }
+
+
+}
+</source>
+
+  <h3>2.  Declare Your Resource Requirements</h3>
+
+  <p>Next, modify your web application deployment descriptor
+  (<code>/WEB-INF/web.xml</code>) to declare the JNDI name under which
+  you will request new instances of this bean.  The simplest approach is
+  to use a <code>&lt;resource-env-ref&gt;</code> element, like this:</p>
+
+<source>
+&lt;resource-env-ref&gt;
+  &lt;description&gt;
+    Object factory for MyBean instances.
+  &lt;/description&gt;
+  &lt;resource-env-ref-name&gt;
+    bean/MyBeanFactory
+  &lt;/resource-env-ref-name&gt;
+  &lt;resource-env-ref-type&gt;
+    com.mycompany.MyBean
+  &lt;/resource-env-ref-type&gt;
+&lt;/resource-env-ref&gt;
+</source>
+
+    <p><strong>WARNING</strong> - Be sure you respect the element ordering
+    that is required by the DTD for web application deployment descriptors!
+    See the
+    <a href="http://java.sun.com/products/servlet/download.html">Servlet
+    Specification</a> for details.</p>
+
+  <h3>3.  Code Your Application's Use Of This Resource</h3>
+
+  <p>A typical use of this resource environment reference might look
+  like this:</p>
+
+<source>
+Context initCtx = new InitialContext();
+Context envCtx = (Context) initCtx.lookup("java:comp/env");
+MyBean bean = (MyBean) envCtx.lookup("bean/MyBeanFactory");
+
+writer.println("foo = " + bean.getFoo() + ", bar = " +
+               bean.getBar());
+</source>
+
+    <h3>4.  Configure Tomcat's Resource Factory</h3>
+
+    <p>To configure Tomcat's resource factory, add an elements like this to the
+    <code>$CATALINA_HOME/conf/server.xml</code> file, nested inside the
+    <code>Context</code> element for this web application.</p>
+<source>
+&lt;Context ...&gt;
+  ...
+  &lt;Resource name="bean/MyBeanFactory" auth="Container"
+            type="com.mycompany.MyBean"
+            factory="org.apache.naming.factory.BeanFactory"
+            bar="23"/&gt;
+  ...
+&lt;/Context&gt;
+</source>
+
+    <p>Note that the resource name (here, <code>bean/MyBeanFactory</code>
+    must match the value specified in the web application deployment
+    descriptor.  We are also initializing the value of the <code>bar</code>
+    property, which will cause <code>setBar(23)</code> to be called before
+    the new bean is returned.  Because we are not initializing the
+    <code>foo</code> property (although we could have), the bean will
+    contain whatever default value is set up by its constructor.</p>
+
+  </subsection>
+
+
+  <subsection name="JavaMail Sessions">
+
+    <h3>0.  Introduction</h3>
+
+    <p>In many web applications, sending electronic mail messages is a
+    required part of the system's functionality.  The
+    <a href="http://java.sun.com/products/javamail">Java Mail</a> API
+    makes this process relatively straightforward, but requires many
+    configuration details that the client application must be aware of
+    (including the name of the SMTP host to be used for message sending).</p>
+
+    <p>Tomcat 5 includes a standard resource factory that will create
+    <code>javax.mail.Session</code> session instances for you, already
+    connected to the SMTP server that is configured in <code>server.xml</code>.
+    In this way, the application is totally insulated from changes in the
+    email server configuration environment - it simply asks for, and receives,
+    a preconfigured session whenever needed.</p>
+
+    <p>The steps required for this are outlined below.</p>
+
+    <h3>1.  Declare Your Resource Requirements</h3>
+
+    <p>The first thing you should do is modify the web application deployment
+    descriptor (<code>/WEB-INF/web.xml</code>) to declare the JNDI name under
+    which you will look up preconfigured sessions.  By convention, all such
+    names should resolve to the <code>mail</code> subcontext (relative to the
+    standard <code>java:comp/env</code> naming context that is the root of
+    all provided resource factories.  A typical <code>web.xml</code> entry
+    might look like this:</p>
+<source>
+&lt;resource-ref&gt;
+  &lt;description&gt;
+    Resource reference to a factory for javax.mail.Session
+    instances that may be used for sending electronic mail
+    messages, preconfigured to connect to the appropriate
+    SMTP server.
+  &lt;/description&gt;
+  &lt;res-ref-name&gt;
+    mail/Session
+  &lt;/res-ref-name&gt;
+  &lt;res-type&gt;
+    javax.mail.Session
+  &lt;/res-type&gt;
+  &lt;res-auth&gt;
+    Container
+  &lt;/res-auth&gt;
+&lt;/resource-ref&gt;
+</source>
+
+    <p><strong>WARNING</strong> - Be sure you respect the element ordering
+    that is required by the DTD for web application deployment descriptors!
+    See the
+    <a href="http://java.sun.com/products/servlet/download.html">Servlet
+    Specification</a> for details.</p>
+
+    <h3>2.  Code Your Application's Use Of This Resource</h3>
+
+    <p>A typical use of this resource reference might look like this:</p>
+<source>
+Context initCtx = new InitialContext();
+Context envCtx = (Context) initCtx.lookup("java:comp/env");
+Session session = (Session) envCtx.lookup("mail/Session");
+
+Message message = new MimeMessage(session);
+message.setFrom(new InternetAddress(request.getParameter("from"));
+InternetAddress to[] = new InternetAddress[1];
+to[0] = new InternetAddress(request.getParameter("to"));
+message.setRecipients(Message.RecipientType.TO, to);
+message.setSubject(request.getParameter("subject"));
+message.setContent(request.getParameter("content"), "text/plain");
+Transport.send(message);
+</source>
+
+    <p>Note that the application uses the same resource reference name
+    that was declared in the web application deployment descriptor.  This
+    is matched up against the resource factory that is configured in
+    <code>$CATALINA_HOME/conf/server.xml</code>, as described below.</p>
+
+    <h3>3.  Configure Tomcat's Resource Factory</h3>
+
+    <p>To configure Tomcat's resource factory, add an elements like this to the
+    <code>$CATALINA_HOME/conf/server.xml</code> file, nested inside the
+    <code>Context</code> element for this web application.</p>
+<source>
+&lt;Context ...&gt;
+  ...
+  &lt;Resource name="mail/Session" auth="Container"
+            type="javax.mail.Session"
+            mail.smtp.host="localhost"/&gt;
+  ...
+&lt;/Context&gt;
+</source>
+
+    <p>Note that the resource name (here, <code>mail/Session</code>) must
+    match the value specified in the web application deployment descriptor.
+    Customize the value of the <code>mail.smtp.host</code> parameter to
+    point at the server that provides SMTP service for your network.</p>
+
+    <h3>4.  Install the JavaMail libraries</h3>
+
+    <p><a href="http://java.sun.com/products/javamail/downloads/index.html" target="_blank">
+    Download the JavaMail API</a>.  The JavaMail API requires the Java Activation
+    Framework (JAF) API as well.  The Java Activation Framework can be downloaded
+    from <a href="http://java.sun.com/products/javabeans/glasgow/jaf.html">Sun's site</a>.
+    </p>
+
+    <p>This download includes 2 vital libraries for the configuration; 
+    activation.jar and mail.jar. Unpackage both distributions and place 
+    them into $CATALINA_HOME/common/lib so that they are available to
+    Tomcat during the initialization of the mail Session Resource.
+    <strong>Note:</strong> placing these jars in both common/lib and a 
+    web application's lib folder will cause an error, so ensure you have
+    them in the $CATALINA_HOME/common/lib location only.
+    </p>
+
+    <h3>Example Application</h3>
+
+    <p>The <code>/examples</code> application included with Tomcat contains
+    an example of utilizing this resource factory.  It is accessed via the
+    "JSP Examples" link.  The source code for the servlet that actually
+    sends the mail message is in
+    <code>/WEB-INF/classes/SendMailServlet.java</code>.</p>
+
+    <p><strong>WARNING</strong> - The default configuration assumes that
+    there is an SMTP server listing on port 25 on <code>localhost</code>.
+    If this is not the case, edit the
+    <code>$CATALINA_HOME/conf/server.xml</code> file, and modify the
+    parameter value for the <code>mail.smtp.host</code> parameter to be
+    the host name of an SMTP server on your network.</p>
+
+  </subsection>
+
+  <subsection name="JDBC Data Sources">
+
+    <h3>0.  Introduction</h3>
+
+    <p>Many web applications need to access a database via a JDBC driver,
+    to support the functionality required by that application.  The J2EE
+    Platform Specification requires J2EE Application Servers to make
+    available a <em>DataSource</em> implementation (that is, a connection
+    pool for JDBC connections) for this purpose.  Tomcat 5 offers exactly
+    the same support, so that database-based applications you develop on
+    Tomcat using this service will run unchanged on any J2EE server.</p>
+
+    <p>For information about JDBC, you should consult the following:</p>
+    <ul>
+    <li><a href="http://java.sun.com/products/jdbc/">http://java.sun.com/products/jdbc/</a> -
+        Home page for information about Java Database Connectivity.</li>
+    <li><a href="http://java.sun.com/j2se/1.3/docs/guide/jdbc/spec2/jdbc2.1.frame.html">http://java.sun.com/j2se/1.3/docs/guide/jdbc/spec2/jdbc2.1.frame.html</a> -
+        The JDBC 2.1 API Specification.</li>
+    <li><a href="http://java.sun.com/products/jdbc/jdbc20.stdext.pdf">http://java.sun.com/products/jdbc/jdbc20.stdext.pdf</a> -
+        The JDBC 2.0 Standard Extension API (including the
+        <code>javax.sql.DataSource</code> API).  This package is now known
+        as the "JDBC Optional Package".</li>
+    <li><a href="http://java.sun.com/j2ee/download.html">http://java.sun.com/j2ee/download.html</a> -
+        The J2EE Platform Specification (covers the JDBC facilities that
+        all J2EE platforms must provide to applications).</li>
+    </ul>
+
+    <p><strong>NOTE</strong> - The default data source support in Tomcat
+    is based on the <strong>DBCP</strong> connection pool from the
+    <a href="http://jakarta.apache.org/commons">Jakarta Commons</a>
+    subproject.  However, it is possible to use any other connection pool
+    that implements <code>javax.sql.DataSource</code>, by writing your
+    own custom resource factory, as described
+    <a href="#Adding Custom Resource Factories">below</a>.</p>
+
+    <h3>1.  Install Your JDBC Driver</h3>
+
+    <p>Use of the <em>JDBC Data Sources</em> JNDI Resource Factory requires
+    that you make an appropriate JDBC driver available to both Tomcat internal
+    classes and to your web application.  This is most easily accomplished by
+    installing the driver's JAR file(s) into the
+    <code>$CATALINA_HOME/common/lib</code> directory, which makes the driver
+    available both to the resource factory and to your application.</p>
+
+    <h3>2.  Declare Your Resource Requirements</h3>
+
+    <p>Next, modify the web application deployment descriptor
+    (<code>/WEB-INF/web.xml</code>) to declare the JNDI name under
+    which you will look up preconfigured data source.  By convention, all such
+    names should resolve to the <code>jdbc</code> subcontext (relative to the
+    standard <code>java:comp/env</code> naming context that is the root of
+    all provided resource factories.  A typical <code>web.xml</code> entry
+    might look like this:</p>
+<source>
+&lt;resource-ref&gt;
+  &lt;description&gt;
+    Resource reference to a factory for java.sql.Connection
+    instances that may be used for talking to a particular
+    database that is configured in the server.xml file.
+  &lt;/description&gt;
+  &lt;res-ref-name&gt;
+    jdbc/EmployeeDB
+  &lt;/res-ref-name&gt;
+  &lt;res-type&gt;
+    javax.sql.DataSource
+  &lt;/res-type&gt;
+  &lt;res-auth&gt;
+    Container
+  &lt;/res-auth&gt;
+&lt;/resource-ref&gt;
+</source>
+
+    <p><strong>WARNING</strong> - Be sure you respect the element ordering
+    that is required by the DTD for web application deployment descriptors!
+    See the
+    <a href="http://java.sun.com/products/servlet/download.html">Servlet
+    Specification</a> for details.</p>
+
+    <h3>3.  Code Your Application's Use Of This Resource</h3>
+
+    <p>A typical use of this resource reference might look like this:</p>
+<source>
+Context initCtx = new InitialContext();
+Context envCtx = (Context) initCtx.lookup("java:comp/env");
+DataSource ds = (DataSource)
+  envCtx.lookup("jdbc/EmployeeDB");
+
+Connection conn = ds.getConnection();
+... use this connection to access the database ...
+conn.close();
+</source>
+
+    <p>Note that the application uses the same resource reference name
+    that was declared in the web application deployment descriptor.  This
+    is matched up against the resource factory that is configured in
+    <code>$CATALINA_HOME/conf/server.xml</code>, as described below.</p>
+
+    <h3>4.  Configure Tomcat's Resource Factory</h3>
+
+    <p>To configure Tomcat's resource factory, add an element like this to the
+    <code>/META-INF/context.xml</code> file in the web application.</p>
+<source>
+&lt;Context ...&gt;
+  ...
+  &lt;Resource name="jdbc/EmployeeDB" auth="Container"
+            type="javax.sql.DataSource" username="dbusername" password="dbpassword"
+            driverClassName="org.hsql.jdbcDriver" url="jdbc:HypersonicSQL:database"
+            maxActive="8" maxIdle="4"/&gt;
+  ...
+&lt;/Context&gt;
+</source>
+
+    <p>Note that the resource name (here, <code>jdbc/EmployeeDB</code>) must
+    match the value specified in the web application deployment descriptor.</p>
+
+    <p>This example assumes that you are using the HypersonicSQL database
+    JDBC driver.  Customize the <code>driverClassName</code> and
+    <code>driverName</code> parameters to match your actual database's
+    JDBC driver and connection URL.</p>
+
+    <p>The configuration properties for Tomcat's standard data source
+    resource factory
+    (<code>org.apache.tomcat.dbcp.dbcp.BasicDataSourceFactory</code>) are
+    as follows:</p>
+    <ul>
+    <li><strong>driverClassName</strong> - Fully qualified Java class name
+        of the JDBC driver to be used.</li>
+    <li><strong>maxActive</strong> - The maximum number of active instances
+        that can be allocated from this pool at the same time.</li>
+    <li><strong>maxIdle</strong> - The maximum number of connections that
+        can sit idle in this pool at the same time.</li>
+    <li><strong>maxWait</strong> - The maximum number of milliseconds that the
+        pool will wait (when there are no available connections) for a
+        connection to be returned before throwing an exception.</li>
+    <li><strong>password</strong> - Database password to be passed to our
+        JDBC driver.</li>
+    <li><strong>url</strong> - Connection URL to be passed to our JDBC driver.
+        (For backwards compatibility, the property <code>driverName</code>
+        is also recognized.)</li>
+    <li><strong>user</strong> - Database username to be passed to our
+        JDBC driver.</li>
+    <li><strong>validationQuery</strong> - SQL query that can be used by the
+        pool to validate connections before they are returned to the
+        application.  If specified, this query MUST be an SQL SELECT
+        statement that returns at least one row.</li>
+    </ul>
+    <p>For more details, please refer to the commons-dbcp documentation.</p>
+
+  </subsection>
+
+</section>
+
+
+<section name="Adding Custom Resource Factories">
+
+  <p>If none of the standard resource factories meet your needs, you can
+  write your own factory and integrate it into Tomcat 5, and then configure
+  the use of this factory in the <code>conf/server.xml</code> configuration
+  file.  In the example below, we will create a factory that only knows how
+  to create <code>com.mycompany.MyBean</code> beans, from the
+  <a href="#Generic JavaBean Resources">Generic JavaBean Resources</a>
+  example, above.</p>
+
+  <h3>1.  Write A Resource Factory Class</h3>
+
+  <p>You must write a class that implements the JNDI service provider
+  <code>javax.naming.spi.ObjectFactory</code> inteface.  Every time your
+  web application calls <code>lookup()</code> on a context entry that is
+  bound to this factory, the <code>getObjectInstance()</code> method is
+  called, with the following arguments:</p>
+  <ul>
+  <li><strong>Object obj</strong> - The (possibly null) object containing
+      location or reference information that can be used in creating an
+      object.  For Tomcat, this will always be an object of type
+      <code>javax.naming.Reference</code>, which contains the class name
+      of this factory class, as well as the configuration properties
+      (from <code>conf/server.xml</code>) to use in creating objects
+      to be returned.</li>
+  <li><strong>Name name</strong> - The name to which this factory is bound
+      relative to <code>nameCtx</code>, or <code>null</code> if no name
+      is specified.</li>
+  <li><strong>Context nameCtx</strong> - The context relative to which the
+      <code>name</code> parameter is specified, or <code>null</code> if
+      <code>name</code> is relative to the default initial context.</li>
+  <li><strong>Hashtable environment</strong> - The (possibly null)
+      environment that is used in creating this object.  This is generally
+      ignored in Tomcat object factories.</li>
+  </ul>
+
+  <p>To create a resource factory that knows how to produce <code>MyBean</code>
+  instances, you might create a class like this:</p>
+
+<source>
+package com.mycompany;
+
+import java.util.Enumeration;
+import java.util.Hashtable;
+import javax.naming.Context;
+import javax.naming.Name;
+import javax.naming.NamingException;
+import javax.naming.RefAddr;
+import javax.naming.Reference;
+import javax.naming.spi.ObjectFactory;
+
+public class MyBeanFactory implements ObjectFactory {
+
+  public Object getObjectInstance(Object obj,
+      Name name, Context nameCtx, Hashtable environment)
+      throws NamingException {
+
+      // Acquire an instance of our specified bean class
+      MyBean bean = new MyBean();
+
+      // Customize the bean properties from our attributes
+      Reference ref = (Reference) obj;
+      Enumeration addrs = ref.getAll();
+      while (addrs.hasMoreElements()) {
+          RefAddr addr = (RefAddr) addrs.nextElement();
+          String name = addr.getType();
+          String value = (String) addr.getContent();
+          if (name.equals("foo")) {
+              bean.setFoo(value);
+          } else if (name.equals("bar")) {
+              try {
+                  bean.setBar(Integer.parseInt(value));
+              } catch (NumberFormatException e) {
+                  throw new NamingException("Invalid 'bar' value " + value);
+              }
+          }
+      }
+
+      // Return the customized instance
+      return (bean);
+
+  }
+
+}
+</source>
+
+  <p>In this example, we are unconditionally creating a new instance of
+  the <code>com.mycompany.MyBean</code> class, and populating its properties
+  based on the parameters included in the <code>&lt;ResourceParams&gt;</code>
+  element that configures this factory (see below).  You should note that any
+  parameter named <code>factory</code> should be skipped - that parameter is
+  used to specify the name of the factory class itself (in this case,
+  <code>com.mycompany.MyBeanFactory</code>) rather than a property of the
+  bean being configured.</p>
+
+  <p>For more information about <code>ObjectFactory</code>, see the
+  <a href="http://java.sun.com/products/jndi/docs.html">JNDI 1.2 Service
+  Provider Interface (SPI) Specification</a>.</p>
+
+  <p>You will need to compile this class against a class path that includes
+  all of the JAR files in the <code>$CATALINA_HOME/common/lib</code> and
+  <code>$CATALINA_HOME/server/lib</code> directories.  When you are through,
+  place the factory class (and the corresponding bean class) unpacked under
+  <code>$CATALINA_HOME/common/classes</code>, or in a JAR file inside
+  <code>$CATALINA_HOME/common/lib</code>.  In this way, the required class
+  files are visible to both Catalina internal resources and your web
+  application.</p>
+
+  <h3>2.  Declare Your Resource Requirements</h3>
+
+  <p>Next, modify your web application deployment descriptor
+  (<code>/WEB-INF/web.xml</code>) to declare the JNDI name under which
+  you will request new instances of this bean.  The simplest approach is
+  to use a <code>&lt;resource-env-ref&gt;</code> element, like this:</p>
+
+<source>
+&lt;resource-env-ref&gt;
+  &lt;description&gt;
+    Object factory for MyBean instances.
+  &lt;/description&gt;
+  &lt;resource-env-ref-name&gt;
+    bean/MyBeanFactory
+  &lt;/resource-env-ref-name&gt;
+  &lt;resource-env-ref-type&gt;
+    com.mycompany.MyBean
+  &lt;/resource-env-ref-type&gt;
+&lt;resource-env-ref&gt;
+</source>
+
+    <p><strong>WARNING</strong> - Be sure you respect the element ordering
+    that is required by the DTD for web application deployment descriptors!
+    See the
+    <a href="http://java.sun.com/products/servlet/download.html">Servlet
+    Specification</a> for details.</p>
+
+  <h3>3.  Code Your Application's Use Of This Resource</h3>
+
+  <p>A typical use of this resource environment reference might look
+  like this:</p>
+
+<source>
+Context initCtx = new InitialContext();
+Context envCtx = (Context) initCtx.lookup("java:comp/env");
+MyBean bean = (MyBean) envCtx.lookup("bean/MyBeanFactory");
+
+writer.println("foo = " + bean.getFoo() + ", bar = " +
+               bean.getBar());
+</source>
+
+    <h3>4.  Configure Tomcat's Resource Factory</h3>
+
+    <p>To configure Tomcat's resource factory, add an elements like this to the
+    <code>$CATALINA_HOME/conf/server.xml</code> file, nested inside the
+    <code>Context</code> element for this web application.</p>
+<source>
+&lt;Context ...&gt;
+  ...
+  &lt;Resource name="bean/MyBeanFactory" auth="Container"
+            type="com.mycompany.MyBean"
+            factory="com.mycompany.MyBeanFactory"
+            bar="23"/&gt;
+  ...
+&lt;/Context&gt;
+</source>
+
+    <p>Note that the resource name (here, <code>bean/MyBeanFactory</code>
+    must match the value specified in the web application deployment
+    descriptor.  We are also initializing the value of the <code>bar</code>
+    property, which will cause <code>setBar(23)</code> to be called before
+    the new bean is returned.  Because we are not initializing the
+    <code>foo</code> property (although we could have), the bean will
+    contain whatever default value is set up by its constructor.</p>
+
+    <p>You will also note that, from the application developer's perspective,
+    the declaration of the resource environment reference, and the programming
+    used to request new instances, is identical to the approach used for the
+    <em>Generic JavaBean Resources</em> example.  This illustrates one of the
+    advantages of using JNDI resources to encapsulate functionality - you can
+    change the underlying implementation without necessarily having to
+    modify applications using the resources, as long as you maintain
+    compatible APIs.</p>
+
+</section>
+
+
+
+</body>
+
+</document>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/logging.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/logging.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/logging.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,336 @@
+<?xml version="1.0"?>
+<!DOCTYPE document [
+  <!ENTITY project SYSTEM "project.xml">
+]>
+<document url="logging.html">
+
+    &project;
+
+  <properties>
+    <title>Logging in Tomcat</title>
+    <author>Allistair Crossley</author>
+    <author email="yoavs at apache.org">Yoav Shapira</author>
+  </properties>
+
+<body>
+
+  <section name="Introduction">
+  <p>
+    Tomcat 5.5 uses 
+    <a href="http://jakarta.apache.org/commons/logging">Commons Logging</a>
+    throughout its internal code allowing the 
+    developer to choose a logging configuration that suits their needs, e.g
+    java.util.logging or 
+    <a href="http://logging.apache.org/log4j">Log4J</a>. 
+    Commons Logging provides Tomcat the ability to log
+    hierarchially across various log levels without needing to rely on a particular
+    logging implementation.
+  </p>
+  <p>
+    An important consequence for Tomcat 5.5 is that the &lt;Logger&gt; element found in 
+    previous versions to create a <code>localhost_log</code> is no longer a valid nested element 
+    of &lt;Context&gt;. Instead, the default Tomcat configuration will use java.util.logging. 
+    If the developer wishes to collect detailed internal Tomcat logging (i.e what is happening 
+    within the Tomcat engine), then they should configure a logging system such as java.util.logging 
+    or log4j as detailed next.
+  </p>
+
+  </section>
+
+  <section name="log4j">
+    <p>
+      Tomcat 5.5 has done away with <code>localhost_log</code> which you may be familiar with
+      as the runtime exception/stack trace log. These types of error are usually thrown
+      by uncaught exceptions, but are still valuable to the developer. They can now be
+      found in the <code>stdout</code> log.
+    </p>
+
+    <p>
+      If you need to setup cross-context detailed logging from within Tomcat's code, 
+      then you can use a simple log4j configuration. Note that this logging van be very 
+      verbose depending on the log level you chose to use.  Note also that a log4j logging 
+      configuration is not going to produce stack trace type logging: those stack traces
+      are output to <code>stdout</code> as discussed above.
+    </p>
+
+    <p>
+      Follow the following steps to setup a file named tomcat.log that has internal 
+      Tomcat logging output to it:
+    </p>
+
+    <p>
+      <ol>
+        <li>Create a file called log4j.properties with the following content 
+            and save it into common/classes.
+          <source>
+            log4j.rootLogger=debug, R <br />
+            log4j.appender.R=org.apache.log4j.RollingFileAppender <br />
+            log4j.appender.R.File=${catalina.home}/logs/tomcat.log <br />
+            log4j.appender.R.MaxFileSize=10MB <br />
+            log4j.appender.R.MaxBackupIndex=10 <br />
+            log4j.appender.R.layout=org.apache.log4j.PatternLayout <br />
+            log4j.appender.R.layout.ConversionPattern=%p %t %c - %m%n <br />
+            log4j.logger.org.apache.catalina=DEBUG, R
+          </source>
+	</li>
+
+	<li><a href="http://logging.apache.org/log4j">Download Log4J</a> 
+            (v1.2 or later) and place the log4j jar in $CATALINA_HOME/common/lib.</li>
+
+        <li><a href="http://jakarta.apache.org/site/downloads/downloads_commons-logging.cgi">
+            Download Commons Logging</a> and place the commons-logging.jar 
+            (not commons-logging-api.jar) in $CATALINA_HOME/common/lib with 
+            the log4j jar.</li>
+
+	<li>Start Tomcat</li>
+      </ol>
+    </p>
+
+    <p>
+      This log4j configuration sets up a file called tomcat.log in your 
+      Tomcat logs folder with a maximum file size of 10MB and
+      up to 10 backups.  DEBUG level is specified which will result in the 
+      most verbose output from Tomcat.
+    </p>
+	
+    <p>
+      You can (and should) be more picky about which packages to include 
+      in the logging. Tomcat 5.5 uses defines loggers by Engine and Host names.
+      For example, for a default Catalina localhost log, add this to the
+      end of the log4j.properties above. Note that there are known issues with 
+      using this naming convention (with square brackets) in log4j XML based
+      configuration files, so we recommend you use a properties file as described
+      until a future version of log4j allows this convention.
+      
+      <ul>
+        <li>log4j.logger.org.apache.catalina.core.ContainerBase.[Catalina].[localhost]=DEBUG, R</li>
+	<li>log4j.logger.org.apache.catalina.core=DEBUG, R</li>
+	<li>log4j.logger.org.apache.catalina.session=DEBUG, R</li>
+      </ul>
+
+      Be warned a level of DEBUG will produce megabytes of logging and slow startup
+      of Tomcat. This level should be used sparingly when debugging of internal Tomcat
+      operations is required.
+    </p>
+	
+    <p>
+      Your web applications should certainly use their own log4j configuration. 
+      This is valid <i>with</i> the above configuration.  You would place a similar log4j.properties 
+      file in your web application's WEB-INF/classes folder, and log4j1.2.8.jar into
+      WEB-INF/lib. Then specify your package level logging. This is a basic setup of log4j 
+      which does *not* require Commons-Logging, 
+      and you should consult the 
+      <a href="http://logging.apache.org/log4j/docs/documentation.html">log4j documentation</a> 
+      for more options.  This page is intended only as a bootstrapping guide.
+    </p>
+	
+  </section>
+
+  <section name="java.util.logging">
+
+  <p>
+    In order to configure JDK logging you should have JDK 1.4+. Tomcat 5.5 is intended for
+    JDK 5.0 or later, but can be run on JDK 1.4 using a compatibility package.
+  </p>
+  <p>
+    The default implemenatation of java.util.logging provided in the JDK is too limited to be 
+    useful. A limitation of JDK Logging appears to be the inability to have per-web application logging, 
+    as the configuration is per-VM. As a result, Tomcat will, in the default configuration,
+    replace the default LogManager implementation with a container friendly implementation
+    called JULI, which addresses these shortcomings. It supports the same configuration mechanisms 
+    as the standard JDK java.util.logging, using either a programmatic approach, or properties
+    files. The main difference is that per-classloader properties files can be set (which enables easy
+    redeployment friendly webapp configuration), and the properties files support slightly extended
+    constructs which allows more freedom for defining handlers and assigning them to loggers.
+  </p>
+  <p>
+    JULI is enabled by default in Tomcat 5.5, and supports per classloader configuration, in addition to 
+    the regular global java.util.logging configuration. This means that logging can be configured at 
+    the following layers:
+    <ul>
+      <li>In the JDK's logging.properties file. Check
+      your JAVA_HOME environment setting to see which JDK Tomcat is using (or maybe JRE 5.0 as Tomcat
+      can now run on a JRE from version 5.5). The file will be in <code>$JAVA_HOME/jre/lib</code>.
+      Alternately, it can also use a global configuration file located elsewhere by using the 
+      system property <code>java.util.logging.config.file</code>, or programmatic configuration using
+      <code>java.util.logging.config.class</code>.</li>
+      <li>In each classloader using a logging.properties file. This means that it is possible to have a
+      configuration for the Tomcat core, as well as separate configurations for each webapps which will 
+      have the same lifecycle as the webapps.</li>
+    </ul>
+  </p>
+  <p>
+    The default logging.properties specifies a ConsoleHandler for routing logging to stdout and
+    also a FileHandler. A handler's log level threshold can be set using SEVERE, CONFIG, INFO, 
+    WARN, FINE, FINEST or ALL. The logging.properties shipped with JDK is set to INFO. You
+    can also target specific packages to collect logging from and specify a level. Here is how
+    you would set debugging from Tomcat. You would need to ensure the ConsoleHandler's level is also
+    set to collect this threshold, so FINEST or ALL should be set. Please refer to Sun's java.util.logging
+    documentation for the complete details.
+  </p>
+  <p>
+    <source>org.apache.catalina.level=FINEST</source>
+  </p>
+  <p>
+    The configuration used by JULI is extremely similar, but uses a few extensions to allow better 
+    flexibility in assigning loggers. The main differences are:
+    <ul>
+      <li>A prefix may be added to handler names, so that multiple handlers of a single class may be 
+      instantiated. A prefix is a String which starts with a digit, and ends with '.'. For example, 
+      <code>22foobar.</code> is a valid prefix.</li>
+      <li>As in Java 5.0, loggers can define a list of handlers using the <code>loggerName.handlers</code>
+      property.</li>
+      <li>By default, loggers will not delegate to their parent if they have associated handlers. This
+      may be changed per logger using the <code>loggerName.useParentHandlers</code> property, which accepts 
+      a boolean value.</li>
+      <li>The root logger can define its set of handlers using a <code>.handlers</code> property.</li>
+      <li>System property replacement for property values which start with ${sytstemPropertyName}.</li>
+    </ul>
+  </p>
+  <p>
+    Example logging.properties file to be placed in common/classes:
+    <source>
+handlers = 1catalina.org.apache.juli.FileHandler, 2localhost.org.apache.juli.FileHandler, \
+           3manager.org.apache.juli.FileHandler, 4admin.org.apache.juli.FileHandler, \
+           java.util.logging.ConsoleHandler
+
+.handlers = 1catalina.org.apache.juli.FileHandler, java.util.logging.ConsoleHandler
+
+############################################################
+# Handler specific properties.
+# Describes specific configuration info for Handlers.
+############################################################
+
+1catalina.org.apache.juli.FileHandler.level = FINE
+1catalina.org.apache.juli.FileHandler.directory = ${catalina.base}/logs
+1catalina.org.apache.juli.FileHandler.prefix = catalina.
+
+2localhost.org.apache.juli.FileHandler.level = FINE
+2localhost.org.apache.juli.FileHandler.directory = ${catalina.base}/logs
+2localhost.org.apache.juli.FileHandler.prefix = localhost.
+
+3manager.org.apache.juli.FileHandler.level = FINE
+3manager.org.apache.juli.FileHandler.directory = ${catalina.base}/logs
+3manager.org.apache.juli.FileHandler.prefix = manager.
+
+4admin.org.apache.juli.FileHandler.level = FINE
+4admin.org.apache.juli.FileHandler.directory = ${catalina.base}/logs
+4admin.org.apache.juli.FileHandler.prefix = admin.
+
+java.util.logging.ConsoleHandler.level = FINE
+java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter
+
+
+############################################################
+# Facility specific properties.
+# Provides extra control for each logger.
+############################################################
+
+org.apache.catalina.core.ContainerBase.[Catalina].[localhost].level = INFO
+org.apache.catalina.core.ContainerBase.[Catalina].[localhost].handlers = \
+   2localhost.org.apache.juli.FileHandler
+
+org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/manager].level = INFO
+org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/manager].handlers = \
+   3manager.org.apache.juli.FileHandler
+
+org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/admin].level = INFO
+org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/admin].handlers = \
+   4admin.org.apache.juli.FileHandler
+
+# For example, set the com.xyz.foo logger to only log SEVERE
+# messages:
+#org.apache.catalina.startup.ContextConfig.level = FINE
+#org.apache.catalina.startup.HostConfig.level = FINE
+#org.apache.catalina.session.ManagerBase.level = FINE
+    </source>
+    </p>
+    
+    <p>
+      Example logging.properties for the servlet-examples web application to be placed
+      in WEB-INF/classes inside the web application:
+      <source>
+handlers = org.apache.juli.FileHandler, java.util.logging.ConsoleHandler
+
+############################################################
+# Handler specific properties.
+# Describes specific configuration info for Handlers.
+############################################################
+
+org.apache.juli.FileHandler.level = FINE
+org.apache.juli.FileHandler.directory = ${catalina.base}/logs
+org.apache.juli.FileHandler.prefix = servlet-examples.
+
+java.util.logging.ConsoleHandler.level = FINE
+java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter
+      </source>
+    </p>
+
+  </section>
+
+  <section name="Handler Properties">
+    <p>
+      Tomcat's JULI implementation is not intended to be a fully-featured logging libary, only
+      a simple bridge to those libraries.  However, JULI does provide several properties
+      for configuring the its handlers.  These are listed below.
+    </p>
+    
+    <subsection name="FileHandler">
+      <attributes>
+        <attribute name="directory" required="false">
+          <p>
+            The directory where the log file will be written.  The Tomcat server account
+            should have write permissions to this directory.  The default value of this
+            property is <em>logs</em>.
+          </p>
+        </attribute>
+
+        <attribute name="prefix" required="false">
+          <p>
+            The log file name prefix.  This is the portion of the log file name before the date.  
+            The default value of this property is <em>juli.</em>.
+          </p>
+        </attribute>
+
+        <attribute name="suffix" required="false">
+          <p>
+            The log file name suffix.  This is the portion of the log file name after the date.
+            The default value of this property is <em>.log</em>.
+          </p>
+        </attribute>
+
+        <attribute name="level" required="false">
+          <p>
+            The threshold level for this handler.  It must be one of the levels in the 
+            <a href="http://java.sun.com/j2se/1.4.2/docs/api/java/util/logging/Level.html">java.util.logging.Level</a> class.
+            The default value of this property is <em>ALL</em>.  Messages whose level is below
+            the specified level will not be written to the file.
+          </p>
+        </attribute>
+
+        <attribute name="filter" required="false">
+          <p>
+            The fully-qualified class name of a class that implements the 
+            <a href="http://java.sun.com/j2se/1.4.2/docs/api/java/util/logging/Filter.html">java.util.logging.Filter</a> 
+            interface.  JULI will load this class and associate it with this handler to filter its messages.
+            By default, there is no Filter associated with the handler.            
+          </p>
+        </attribute>
+
+        <attribute name="formatter" required="false">
+          <p>
+            The fully-qualified class name of a class that implements the
+            <a href="http://java.suncom/j2se/1.4.2/docs/api/java/util/logging/Formatter.html">java.util.logging.Formatter</a>
+            interface.  JULI will load this class and associate it with this handler to format its messages.
+            By default, there is no Formatter associated with the handler.
+          </p>
+        </attribute>
+
+      </attributes>
+
+    </subsection>    
+  
+  </section>
+
+</body>
+</document>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/manager-howto.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/manager-howto.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/manager-howto.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,1295 @@
+<?xml version="1.0"?>
+<!DOCTYPE document [
+  <!ENTITY project SYSTEM "project.xml">
+]>
+<document url="manager-howto.html">
+
+    &project;
+
+    <properties>
+        <author email="craigmcc at apache.org">Craig R. McClanahan</author>
+        <title>Manager App HOW-TO</title>
+    </properties>
+
+<body>
+
+<section name="Table of Contents">
+
+<p>
+<a href="#Introduction">Introduction</a><br />
+<a href="#Configuring Manager Application Access">
+Configuring Manager Application Access</a><br />
+<a href="#Supported Manager Commands">Supported Manager Commands</a><br />
+<blockquote>
+<a href="#Deploy A New Application Remotely">Deploy A New Application Remotely</a><br />
+<a href="#Deploy A New Application from a Local Path">Deploy A New Application from a Local Path</a><br />
+<a href="#List Currently Deployed Applications">
+List Currently Deployed Applications</a><br />
+<a href="#Reload An Existing Application">Reload An Existing Application</a><br />
+<a href="#List OS and JVM Properties">List OS and JVM Properties</a><br />
+<a href="#List Available Global JNDI Resources">
+List Available Global JNDI Resources</a><br />
+<a href="#List Available Security Roles">List Available Security Roles</a><br />
+<a href="#Session Statistics">Session Statistics</a><br />
+<a href="#Start an Existing Application">Start an Existing Application</a><br />
+<a href="#Stop an Existing Application">Stop an Existing Application</a><br />
+<a href="#Undeploy an Existing Application">
+Undeploy an Existing Application</a><br />
+</blockquote>
+<a href="#Executing Manager Commands With Ant">
+Executing Manager Commands With Ant</a><br />
+<a href="#Using the JMX Proxy Servlet">
+Using the JMX Proxy Servlet</a><br />
+<blockquote>
+<a href="#What is JMX Proxy Servlet">What is JMX Proxy Servlet?</a><br />
+<a href="#JMX Query command">Query command</a><br />
+<a href="#JMX Set command">Set command</a><br />
+</blockquote>
+</p>
+
+</section>
+
+<section name="Introduction">
+
+<p>In many production environments, it is very useful to have the capability
+to deploy a new web application, or undeploy an existing one, without having
+to shut down and restart the entire container.  In addition, you can request
+an existing application to reload itself, even if you have not declared it
+to be <code>reloadable</code> in the Tomcat 5 server
+configuration file.</p>
+
+<p>To support these capabilities, Tomcat 5 includes a web application
+(installed by default on context path <code>/manager</code>) that supports
+the following functions:</p>
+<ul>
+<li>Deploy a new web application, on a specified context path, from
+    the uploaded contents of a WAR file.</li>
+<li>Deploy a new web application, on a specified context path, from the
+    server file system.</li>
+<li>List the currently deployed web applications, as well as the
+    sessions that are currently active for those web apps.</li>
+<li>Reload an existing web application, to reflect changes in the
+    contents of <code>/WEB-INF/classes</code> or <code>/WEB-INF/lib</code>.
+    </li>
+<li>List the OS and JVM property values.</li>
+<li>List the available global JNDI resources, for use in deployment
+    tools that are preparing <code>&lt;ResourceLink&gt;</code> elements
+    nested in a <code>&lt;Context&gt;</code> deployment description.</li>
+<li>List the available security roles defined in the user database.</li>
+<li>Start a stopped application (thus making it available again).</li>
+<li>Stop an existing application (so that it becomes unavailable), but
+    do not undeploy it.</li>
+<li>Undeploy a deployed web application and delete its document base
+    directory (unless it was deployed from file system).</li>
+</ul>
+
+<p>There are two ways to configure the Manager web application
+<code>Context</code>:
+<ul>
+<li>Install the <code>manager.xml</code> context configuration file
+    in the <code>$CATALINA_HOME/conf/[enginename]/[hostname]</code> folder.
+</li>
+<li>Configure the Manager <code>Context</code> within the
+    <code>Host</code> configuration in your Tomcat <code>server.xml</code>
+    configuration. Here is an example:
+<pre>
+&lt;Context path="/manager" debug="0" privileged="true"
+         docBase="/usr/local/kinetic/tomcat5/server/webapps/manager"&gt;
+&lt;/Context&gt;
+</pre>
+</li>
+</ul>
+</p>
+
+<p>If you have Tomcat configured to support multiple virtual hosts
+(websites) you would need to configure a Manager for each.</p>
+
+<p>There are three ways to use the <code>Manager</code> web application.
+<ul>
+<li>As an application with a user interface you use in your browser.
+Here is an example URL where you can replace <code>localhost</code> with
+your website host name:  <code>http://localhost/manager/html/</code> .</li>
+<li>A minimal version using HTTP requests only which is suitable for use
+by scripts setup by system administrators.  Commands are given as part of the
+request URI, and responses are in the form of simple text that can be easily
+parsed and processed.  See <a href="#Supported Manager Commands">
+Supported Manager Commands</a> for more information.</li>
+<li>A convenient set of task definitions for the <em>Ant</em>
+(version 1.4 or later) build tool.  See
+<a href="#Executing Manager Commands With Ant">Executing Manager Commands
+With Ant</a> for more information.</li>
+</ul>
+</p>
+
+<p>Future versions of Tomcat 5 will include administrative functionality that
+is presented in (at least) the following forms:
+<ul>
+<li>As web services, so that Tomcat administration can be easily integrated
+    into remote and/or non-Java mnagement environments.</li>
+<li>As a web application with a nice user interface (built on top of the
+    web services processing layer) for easy Tomcat administration via a
+    web browser.</li>
+</ul>
+</p>
+
+</section>
+
+<section name="Configuring Manager Application Access">
+
+    <blockquote><em>
+    <p>The description below uses the variable name $CATALINA_HOME
+    to refer to the directory into which you have installed Tomcat 5,
+    and is the base directory against which most relative paths are
+    resolved.  However, if you have configured Tomcat 5 for multiple
+    instances by setting a CATALINA_BASE directory, you should use
+    $CATALINA_BASE instead of $CATALINA_HOME for each of these
+    references.</p>
+    </em></blockquote>
+
+<p>It would be quite unsafe to ship Tomcat with default settings that allowed
+anyone on the Internet to execute the Manager application on your server.
+Therefore, the Manager application is shipped with the requirement that anyone
+who attempts to use it must authenticate themselves, using a username and
+password that have the role <strong>manager</strong> associated with them.
+Further, there is no username in the default users file
+(<conf>$CATALINA_HOME/conf/tomcat-users.xml</conf>) that is assigned this
+role.  Therefore, access to the Manager application is completely disabled
+by default.</p>
+
+<p>To enable access to the Manager web application, you must either create
+a new username/password combination and associate the role name
+<strong>manager</strong> with it, or add the <strong>manager</strong> role
+to some existing username/password combination.  Exactly where this is done
+depends on which <code>Realm</code> implementation you are using:</p>
+<ul>
+<li><em>MemoryRealm</em> - If you have not customized your
+    <code>$CATALINA_HOME/conf/server.xml</code> to select a different one,
+    Tomcat 5 defaults to an XML-format file stored at
+    <code>$CATALINA_HOME/conf/tomcat-users.xml</code>, which can be
+    edited with any text editor.  This file contains an XML
+    <code>&lt;user&gt;</code> for each individual user, which might
+    look something like this:
+<source>
+&lt;user name="craigmcc" password="secret" roles="standard,manager" /&gt;
+</source>
+    which defines the username and password used by this individual to
+    log on, and the role names he or she is associated with.  You can
+    add the <strong>manager</strong> role to the comma-delimited
+    <code>roles</code> attribute for one or more existing users, and/or
+    create new users with that assigned role.</li>
+<li><em>JDBCRealm</em> - Your user and role information is stored in
+    a database accessed via JDBC.  Add the <strong>manager</strong> role
+    to one or more existing users, and/or create one or more new users
+    with this role assigned, following the standard procedures for your
+    environment.</li>
+<li><em>JNDIRealm</em> - Your user and role information is stored in
+    a directory server accessed via LDAP.  Add the <strong>manager</strong>
+    role to one or more existing users, and/or create one or more new users
+    with this role assigned, following the standard procedures for your
+    environment.</li>
+</ul>
+
+<p>The first time you attempt to issue one of the Manager commands
+described in the next section, you will be challenged to log on using
+BASIC authentication.  The username and password you enter do not matter,
+as long as they identify a valid user in the users database who possesses
+the role <strong>manager</strong>.</p>
+
+<p>In addition to the password restrictions the manager web application
+could be restricted by the remote IP address or host by adding a
+<code>RemoteAddrValve</code> or <code>RemoteHostValve</code>.  Here is
+an example of restricting access to the localhost by IP address:
+<pre>
+&lt;Context path="/manager" debug="0" privileged="true"
+         docBase="/usr/local/kinetic/tomcat5/server/webapps/manager"&gt;
+         &lt;Valve className="org.apache.catalina.valves.RemoteAddrValve"
+                allow="127.0.0.1"/&gt;
+&lt;/Context&gt;
+</pre>
+</p>
+</section>
+
+
+<section name="Supported Manager Commands">
+
+<p>All commands that the Manager application knows how to process are
+specified in a single request URI like this:</p>
+<source>
+http://{host}:{port}/manager/{command}?{parameters}
+</source>
+<p>where <code>{host}</code> and <code>{port}</code> represent the hostname
+and port number on which Tomcat is running, <code>{command}</code>
+represents the Manager command you wish to execute, and
+<code>{parameters}</code> represents the query parameters
+that are specific to that command.  In the illustrations below, customize
+the host and port appropriately for your installation.</p>
+
+<p>Most commands accept one or more of the following query parameters:</p>
+<ul>
+<li><strong>path</strong> - The context path (including the leading slash)
+    of the web application you are dealing with.  To select the ROOT web
+    application, specify "/".  <strong>NOTE</strong> -
+    It is not possible to perform administrative commands on the
+    Manager application itself.</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
+    following formats:
+    <ul>
+    <li><strong>file:/absolute/path/to/a/directory</strong> - The absolute
+        path of a directory that contains the unpacked version of a web
+        application.  This directory will be attached to the context path
+        you specify without any changes.</li>
+    <li><strong>file:/absolute/path/to/a/webapp.war</strong> - The absolute
+        path of a web application archive (WAR) file.  This is valid
+        <strong>only</strong> for the <code>/deploy</code> command, and is
+        the only acceptable format to that command.</li>
+    <li><strong>jar:file:/absolute/path/to/a/warfile.war!/</strong> - The
+        URL to a local web application archive (WAR) file.  You can use any
+        syntax that is valid for the <code>JarURLConnection</code> class
+        for reference to an entire JAR file.</li>
+    <li><strong>file:/absolute/path/to/a/context.xml</strong> - The
+        absolute path of a web application Context configuration ".xml"
+        file which contains the Context configuration element.</li>
+    <li><strong>directory</strong> - The directory name for the web
+        applciation context in the Host's application base directory.</li>
+    <li><strong>webapp.war</strong> - The name of a web application war file
+        located in the Host's application base directory.</li>
+    </ul></li>
+</ul>
+
+<p>Each command will return a response in <code>text/plain</code> format
+(i.e. plain ASCII with no HTML markup), making it easy for both humans and
+programs to read).  The first line of the response wil begin with either
+<code>OK</code> or <code>FAIL</code>, indicating whether the requested
+command was successful or not.  In the case of failure, the rest of the first
+line will contain a description of the problem that was encountered.  Some
+commands include additional lines of information as described below.</p>
+
+<p><em>Internationalization Note</em> - The Manager application looks up
+its message strings in resource bundles, so it is possible that the strings
+have been translated for your platform.  The examples below show the English
+version of the messages.</p>
+
+<blockquote><em>
+<p><strong>WARNING:</strong>  the legacy commands <code>/install</code> and 
+<code>/remove</code> are deprecated.
+They are presently equivalent to <code>/deploy</code> and <code>/undeploy</code>,
+but could be removed in a future release.</p>
+</em></blockquote>
+
+<subsection name="Deploy A New Application Remotely">
+
+<source>
+http://localhost:8080/manager/deploy?path=/foo
+</source>
+
+<p>Upload the web application archive (WAR) file that is specified as the
+request data in this HTTP PUT request, install it into the <code>appBase</code>
+directory of our corresponding virtual host, and start it on the context path
+specified by the <code>path</code> request parameter.  If no <code>path</code>
+is specified the directory name or the war file name without the .war extension
+is used as the path.  The application can
+later be undeployed (and the corresponding application directory removed)
+by use of the <code>/undeploy</code>.</p>
+
+<p>The .WAR file may include Tomcat specific deployment configuration, by 
+including a Context configuration XML file in 
+<code>/META-INF/context.xml</code>.</p>
+
+<p>URL parameters include:
+<ul>
+<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>
+</ul>
+</p>
+
+<p><strong>NOTE</strong> - This command is the logical
+opposite of the <code>/undeploy</code> command.</p>
+
+<p>If installation and startup is successful, you will receive a response
+like this:</p>
+<source>
+OK - Deployed application at context path /foo
+</source>
+
+<p>Otherwise, the response will start with <code>FAIL</code> and include an
+error message.  Possible causes for problems include:</p>
+<ul>
+<li><em>Application already exists at path /foo</em>
+    <blockquote>
+    <p>The context paths for all currently running web applications must be
+    unique.  Therefore, you must undeploy the existing web
+    application using this context path, or choose a different context path
+    for the new one. The <code>update</code> parameter may be specified as
+    a parameter on the URL, with a value of <code>true</code> to avoid this
+    error. In that case, an undeploy will be performed on an existing
+    application before performing the deployment.</p>
+    </blockquote></li>
+<li><em>Encountered exception</em>
+    <blockquote>
+    <p>An exception was encountered trying to start the new web application.
+    Check the Tomcat 5 logs for the details, but likely explanations include
+    problems parsing your <code>/WEB-INF/web.xml</code> file, or missing
+    classes encountered when initializing application event listeners and
+    filters.</p>
+    </blockquote></li>
+<li><em>Invalid context path was specified</em>
+    <blockquote>
+    <p>The context path must start with a slash character. To reference the
+    ROOT web application use "/".</p>
+    </blockquote></li>
+<li><em>No context path was specified</em>
+    <blockquote>
+    The <code>path</code> parameter is required.
+    </blockquote></li>
+</ul>
+
+</subsection>
+
+<subsection name="Deploy A New Application from a Local Path">
+
+<p>Deploy and start a new web application, attached to the specified context
+<code>path</code> (which must not be in use by any other web application).
+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>
+
+<p>This can be used to deploy a previous version of a 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.
+<source>
+http://localhost:8080/manager/deploy?path=/footoo&amp;tag=footag
+</source>
+</p>
+
+<h3>Deploy a Directory or WAR by URL</h3>
+
+<p>Deploy a web application directory or ".war" file located on the Tomcat
+server. If no <code>path</code> is specified, the directory name or the war file
+name without the ".war" extension is used as the path. The <code>war</code>
+parameter specifies a URL (including the <code>file:</code> scheme) for either
+a directory or a web application archive (WAR) file. The supported syntax for
+a URL referring to a WAR file is described on the Javadocs page for the
+<code>java.net.JarURLConnection</code> class.  Use only URLs that refer to
+the entire WAR file.</p>
+
+<p>In this example the web application located in the directory
+<code>/path/to/foo</code> on the Tomcat server is deployed as the
+web application context named <code>/footoo</code>.
+<source>
+http://localhost:8080/manager/deploy?path=/footoo&amp;war=file:/path/to/foo
+</source>
+</p>
+
+<p>In this example the ".war" file <code>/path/to/bar.war</code> on the
+Tomcat server is deployed as the web application context named
+<code>/bar</code>. Notice that there is no <code>path</code> parameter
+so the context path defaults to the name of the web application archive
+file without the ".war" extension.
+<source>
+http://localhost:8080/manager/deploy?war=jar:file:/path/to/bar.war!/
+</source>
+</p>
+
+<h3>Deploy a Directory or War from the Host appBase</h3>
+
+<p>Deploy a web application directory or ".war" file located in your Host
+appBase directory. If no <code>path</code> is specified the directory name
+or the war file name without the ".war" extension is used as the path.</p>
+
+<p>In this example the web application located in a sub directory named
+<code>foo</code> in the Host appBase directory of the Tomcat server is
+deployed as the web application context named <code>/foo</code>. Notice
+that there is no <code>path</code> parameter so the context path defaults
+to the name of the web application directory.
+<source>
+http://localhost:8080/manager/deploy?war=foo
+</source>
+</p>
+
+<p>In this example the ".war" file <code>bar.war</code> located in your
+Host appBase directory on the Tomcat server is deployed as the web
+application context named <code>/bartoo</code>.
+<source>
+http://localhost:8080/manager/deploy?path=/bartoo&amp;war=bar.war
+</source>
+</p>
+
+<h3>Deploy using a Context configuration ".xml" file</h3>
+
+<p>If the Host deployXML flag is set to true you can deploy a web
+application using a Context configuration ".xml" file and an optional
+".war" file or web application directory. The context <code>path</code>
+is not used when deploying a web application using a context ".xml"
+configuration file.</p>
+
+<p>A Context configuration ".xml" file can contain valid XML for a
+web application Context just as if it were configured in your
+Tomcat <code>server.xml</code> configuration file. Here is an
+example:
+<source>
+&lt;Context path="/foobar" docBase="/path/to/application/foobar"
+         debug="0"&gt;
+
+  &lt;!-- Link to the user database we will get roles from --&gt;
+  &lt;ResourceLink name="users" global="UserDatabase"
+                type="org.apache.catalina.UserDatabase"/&gt;
+
+&lt;/Context&gt;
+</source>
+</p>
+
+<p>When the optional <code>war</code> parameter is set to the URL
+for a web application ".war" file or directory it overrides any
+docBase configured in the context configuration ".xml" file.</p>
+
+<p>Here is an example of deploying an application using a Context
+configuration ".xml" file.
+<source>
+http://localhost:8080/manager/deploy?config=file:/path/context.xml
+</source>
+</p>
+
+<p>Here is an example of deploying an application using a Context
+configuration ".xml" file and a web application ".war" file located
+on the server.
+<source>
+http://localhost:8080/manager/deploy?config=file:/path/context.xml&amp;war=jar:file:/path/bar.war!/
+</source>
+</p>
+
+<h3>Deployment Notes</h3>
+
+<p>If the Host is configured with unpackWARs=true and you deploy a war
+file, the war will be unpacked into a directory in your Host appBase
+directory.</p>
+
+<p>If the application war or directory is installed in your Host appBase
+directory and either the Host is configured with autoDeploy=true or
+liveDeploy=true, the Context path must match the directory name or
+war file name without the ".war" extension.</p>
+
+<p>For security when untrusted users can manage web applications, the
+Host deployXML flag can be set to false.  This prevents untrusted users
+from deploying web applications using a configuration XML file and
+also prevents them from deploying application directories or ".war"
+files located outside of their Host appBase.</p>
+
+
+<h3>Deploy Response</h3>
+
+<p>If installation and startup is successful, you will receive a response
+like this:</p>
+<source>
+OK - Deployed application at context path /foo
+</source>
+
+<p>Otherwise, the response will start with <code>FAIL</code> and include an
+error message.  Possible causes for problems include:</p>
+<ul>
+<li><em>Application already exists at path /foo</em>
+    <blockquote>
+    <p>The context paths for all currently running web applications must be
+    unique.  Therefore, you must undeploy the existing web
+    application using this context path, or choose a different context path
+    for the new one. The <code>update</code> parameter may be specified as
+    a parameter on the URL, with a value of <code>true</code> to avoid this
+    error. In that case, an undeploy will be performed on an existing
+    application before performing the deployment.</p>
+    </blockquote></li>
+<li><em>Document base does not exist or is not a readable directory</em>
+    <blockquote>
+    <p>The URL specified by the <code>war</code> parameter must identify a
+    directory on this server that contains the "unpacked" version of a
+    web application, or the absolute URL of a web application archive (WAR)
+    file that contains this application.  Correct the value specified by
+    the <code>war</code> parameter.</p>
+    </blockquote></li>
+<li><em>Encountered exception</em>
+    <blockquote>
+    <p>An exception was encountered trying to start the new web application.
+    Check the Tomcat 5 logs for the details, but likely explanations include
+    problems parsing your <code>/WEB-INF/web.xml</code> file, or missing
+    classes encountered when initializing application event listeners and
+    filters.</p>
+    </blockquote></li>
+<li><em>Invalid application URL was specified</em>
+    <blockquote>
+    <p>The URL for the directory or web application that you specified
+    was not valid.  Such URLs must start with <code>file:</code>, and URLs
+    for a WAR file must end in ".war".</p>
+    </blockquote></li>
+<li><em>Invalid context path was specified</em>
+    <blockquote>
+    <p>The context path must start with a slash character. To reference the
+    ROOT web application use "/".</p>
+    </blockquote></li>
+<li><em>Context path must match the directory or WAR file name:</em>
+    <blockquote>
+    If the application war or directory is installed in your Host appBase
+    directory and either the Host is configured with autoDeploy=true or
+    liveDeploy=true, the Context path must match the directory name or
+    war file name without the ".war" extension.
+    </blockquote></li>
+<li><em>Only web applications in the Host web application directory can
+     be installed</em>
+     <blockquote>
+     If the Host deployXML flag is set to false this error will happen
+     if an attempt is made to deploy a web application directory or
+      ".war" file outside of the Host appBase directory.
+     </blockquote></li>
+</ul>
+
+</subsection>
+
+<subsection name="List Currently Deployed Applications">
+
+<source>
+http://localhost:8080/manager/list
+</source>
+
+<p>List the context paths, current status (<code>running</code> or
+<code>stopped</code>), and number of active sessions for all currently
+deployed web applications.  A typical response immediately
+after starting Tomcat might look like this:</p>
+<source>
+OK - Listed applications for virtual host localhost
+/webdav:running:0
+/examples:running:0
+/manager:running:0
+/:running:0
+</source>
+
+</subsection>
+
+<subsection name="Reload An Existing Application">
+
+<source>
+http://localhost:8080/manager/reload?path=/examples
+</source>
+
+<p>Signal an existing application to shut itself down and reload.  This can
+be useful when the web application context is not reloadable and you have
+updated classes or property files in the <code>/WEB-INF/classes</code>
+directory or when you have added or updated jar files in the
+<code>/WEB-INF/lib</code> directory.
+</p>
+<p><strong>NOTE:</strong> The <code>/WEB-INF/web.xml</code>
+web application configuration file is not reread on a reload.
+If you have made changes to your web.xml file you must stop
+then start the web application.
+</p>
+
+<p>If this command succeeds, you will see a response like this:</p>
+<source>
+OK - Reloaded application at context path /examples
+</source>
+
+<p>Otherwise, the response will start with <code>FAIL</code> and include an
+error message.  Possible causes for problems include:</p>
+<ul>
+<li><em>Encountered exception</em>
+    <blockquote>
+    <p>An exception was encountered trying to restart the web application.
+    Check the Tomcat 5 logs for the details.</p>
+    </blockquote></li>
+<li><em>Invalid context path was specified</em>
+    <blockquote>
+    <p>The context path must start with a slash character. To reference the
+    ROOT web application use "/".</p>
+    </blockquote></li>
+<li><em>No context exists for path /foo</em>
+    <blockquote>
+    <p>There is no deployed application on the context path
+    that you specified.</p>
+    </blockquote></li>
+<li><em>No context path was specified</em>
+    <blockquote>
+    The <code>path</code> parameter is required.
+    </blockquote></li>
+<li><em>Reload not supported on WAR deployed at path /foo</em>
+    <blockquote>
+    Currently, application reloading (to pick up changes to the classes or
+    <code>web.xml</code> file) is not supported when a web application is
+    deployed directly from a WAR file.  It only works when the web application
+    is deployed from an unpacked directory.  If you are using a WAR file,
+    you should <code>undeploy</code> and then <code>deploy</code> or
+    <code>deploy</code> with the <code>update</code> parameter the
+    application again to pick up your changes.
+    </blockquote></li>
+</ul>
+
+</subsection>
+
+<subsection name="List OS and JVM Properties">
+
+<source>
+http://localhost:8080/manager/serverinfo
+</source>
+
+<p>Lists information about the Tomcat version, OS, and JVM properties.</p>
+
+<p>If an error occurs, the response will start with <code>FAIL</code> and
+include an error message.  Possible causes for problems include:</p>
+<ul>
+<li><em>Encountered exception</em>
+    <blockquote>
+    <p>An exception was encountered trying to enumerate the system properties.
+    Check the Tomcat 5 logs for the details.</p>
+    </blockquote></li>
+</ul>
+
+</subsection>
+
+<subsection name="List Available Global JNDI Resources">
+
+<source>
+http://localhost:8080/manager/resources[?type=xxxxx]
+</source>
+
+<p>List the global JNDI resources that are available for use in resource
+links for context configuration files.  If you specify the <code>type</code>
+request parameter, the value must be the fully qualified Java class name of
+the resource type you are interested in (for example, you would specify
+<code>javax.sql.DataSource</code> to acquire the names of all available
+JDBC data sources).  If you do not specify the <code>type</code> request
+parameter, resources of all types will be returned.</p>
+
+<p>Depending on whether the <code>type</code> request parameter is specfied
+or not, the first line of a normal response will be:</p>
+<pre>
+  OK - Listed global resources of all types
+</pre>
+<p>or</p>
+<pre>
+  OK - Listed global resources of type xxxxx
+</pre>
+<p>followed by one line for each resource.  Each line is composed of fields
+delimited by colon characters (":"), as follows:</p>
+<ul>
+<li><em>Global Resource Name</em> - The name of this global JNDI resource,
+    which would be used in the <code>global</code> attribute of a
+    <code>&lt;ResourceLink&gt;</code> element.</li>
+<li><em>Global Resource Type</em> - The fully qualified Java class name of
+    this global JNDI resource.</li>
+</ul>
+
+<p>If an error occurs, the response will start with <code>FAIL</code> and
+include an error message.  Possible causes for problems include:</p>
+<ul>
+<li><em>Encountered exception</em>
+    <blockquote>
+    <p>An exception was encountered trying to enumerate the global JNDI
+    resources.  Check the Tomcat 5 logs for the details.</p>
+    </blockquote></li>
+<li><em>No global JNDI resources are available</em>
+    <blockquote>
+    <p>The Tomcat server you are running has been configured without
+    global JNDI resources.</p>
+    </blockquote></li>
+</ul>
+
+
+</subsection>
+
+
+<subsection name="List Available Security Roles">
+
+<source>
+http://localhost:8080/manager/roles
+</source>
+
+<p>List the security role names (and corresponding descriptions) that are
+available in the <code>org.apache.catalina.UserDatabase</code> resource that
+is linked to the <code>users</code> resource reference in the web.xml file
+for the Manager web application.  This would typically be used, for example,
+by a deployment tool that wanted to create
+<code>&lt;security-role-ref&gt;</code> elements to map security role names
+used in a web application to the role names actually defined within the
+container.</p>
+
+<p>By default, the <code>users</code> resource reference is pointed at the
+global <code>UserDatabase</code> resource.  If you choose to utilize a
+different user database per virtual host, you should modify the
+<code>&lt;ResourceLink&gt;</code> element in the default
+<code>manager.xml</code> context configuration file to point at the global
+user database resource for this virtual host.</p>
+
+<p>When this command is executed, the first line of the response will be:</p>
+<pre>
+  OK - Listed security roles
+</pre>
+<p>followed by one line for each security role.  Each line is composed of
+fields delimited by colon characters (":") as follows:</p>
+<ul>
+<li><em>Security Role Name</em> - A security role name that is known to Tomcat
+    in the user database.</li>
+<li><em>Description</em> - Description of this security role (useful in
+    creating user interfaces for selecting roles.</li>
+</ul>
+
+<p>If an error occurs, the response will start with <code>FAIL</code> and
+include an error message.  Possible causes for problems include:</p>
+<ul>
+<li><em>Cannot resolve user database reference</em> - A JNDI error prevented
+    the successful lookup of the <code>org.apache.catalina.UserDatabase</code>
+    resource.  Check the Tomcat log files for a stack trace associated with
+    this error.</li>
+<li><em>No user database is available</em> - You have not configured a resource
+    reference for the <code>users</code> resource that points at an
+    appropriate user database instance.  Check your <code>manager.xml</code>
+    file and ensure that you have created an appropriate
+    <code>&lt;ResourceLink&gt;</code> or
+    <code>&lt;ResourceParams&gt;</code> element for this resource.</li>
+</ul>
+
+</subsection>
+
+
+<subsection name="Session Statistics">
+
+<source>
+http://localhost:8080/manager/sessions?path=/examples
+</source>
+
+<p>Display the default session timeout for a web application, and the
+number of currently active sessions that fall within ten-minute ranges of
+their actual timeout times.  For example, after restarting Tomcat and then
+executing one of the JSP samples in the <code>/examples</code> web app,
+you might get something like this:</p>
+<source>
+OK - Session information for application at context path /examples
+Default maximum session inactive interval 30 minutes
+30 - &lt;40 minutes:1 sessions
+</source>
+
+</subsection>
+
+
+<subsection name="Start an Existing Application">
+
+<source>
+http://localhost:8080/manager/start?path=/examples
+</source>
+
+<p>Signal a stopped application to restart, and make itself available again.
+Stopping and starting is useful, for example, if the database required by
+your application becomes temporarily unavailable.  It is usually better to
+stop the web application that relies on this database rather than letting
+users continuously encounter database exceptions.</p>
+
+<p>If this command succeeds, you will see a response like this:</p>
+<source>
+OK - Started application at context path /examples
+</source>
+
+<p>Otherwise, the response will start with <code>FAIL</code> and include an
+error message.  Possible causes for problems include:</p>
+<ul>
+<li><em>Encountered exception</em>
+    <blockquote>
+    <p>An exception was encountered trying to start the web application.
+    Check the Tomcat 5 logs for the details.</p>
+    </blockquote></li>
+<li><em>Invalid context path was specified</em>
+    <blockquote>
+    <p>The context path must start with a slash character. To reference the
+    ROOT web application use "/".</p>
+    </blockquote></li>
+<li><em>No context exists for path /foo</em>
+    <blockquote>
+    <p>There is no deployed application on the context path
+    that you specified.</p>
+    </blockquote></li>
+<li><em>No context path was specified</em>
+    <blockquote>
+    The <code>path</code> parameter is required.
+    </blockquote></li>
+</ul>
+
+</subsection>
+
+<subsection name="Stop an Existing Application">
+
+<source>
+http://localhost:8080/manager/stop?path=/examples
+</source>
+
+<p>Signal an existing application to make itself unavailable, but leave it
+deployed.  Any request that comes in while an application is
+stopped will see an HTTP error 404, and this application will show as
+"stopped" on a list applications command.</p>
+
+<p>If this command succeeds, you will see a response like this:</p>
+<source>
+OK - Stopped application at context path /examples
+</source>
+
+<p>Otherwise, the response will start with <code>FAIL</code> and include an
+error message.  Possible causes for problems include:</p>
+<ul>
+<li><em>Encountered exception</em>
+    <blockquote>
+    <p>An exception was encountered trying to stop the web application.
+    Check the Tomcat 5 logs for the details.</p>
+    </blockquote></li>
+<li><em>Invalid context path was specified</em>
+    <blockquote>
+    <p>The context path must start with a slash character. To reference the
+    ROOT web application use "/".</p>
+    </blockquote></li>
+<li><em>No context exists for path /foo</em>
+    <blockquote>
+    <p>There is no deployed application on the context path
+    that you specified.</p>
+    </blockquote></li>
+<li><em>No context path was specified</em>
+    <blockquote>
+    The <code>path</code> parameter is required.
+    </blockquote></li>
+</ul>
+
+</subsection>
+
+
+<subsection name="Undeploy an Existing Application">
+
+<source>
+http://localhost:8080/manager/undeploy?path=/examples
+</source>
+
+<p><strong><font color="red">WARNING</font> - This command will delete any web 
+application artifacts that exist within <code>appBase</code> directory 
+(typically "webapps") for this virtual host</strong>.
+This will delete the the application .WAR, if present, 
+the application directory resulting either from a deploy in unpacked form 
+or from .WAR expansion as well as the XML Context definition from
+<code>$CATALINA_HOME/conf/[enginename]/[hostname]/</code> directory. 
+If you simply want to take an application
+out of service, you should use the <code>/stop</code> command instead.</p>
+
+<p>Signal an existing application to gracefully shut itself down, and
+remove it from Tomcat (which also makes this context path available for
+reuse later).  In addition, the document root directory is removed, if it
+exists in the <code>appBase</code> directory (typically "webapps") for
+this virtual host.  This command is the logical opposite of the
+<code>/deploy</code> command.</p>
+
+<p>If this command succeeds, you will see a response like this:</p>
+<source>
+OK - Undeployed application at context path /examples
+</source>
+
+<p>Otherwise, the response will start with <code>FAIL</code> and include an
+error message.  Possible causes for problems include:</p>
+<ul>
+<li><em>Encountered exception</em>
+    <blockquote>
+    <p>An exception was encountered trying to undeploy the web application.
+    Check the Tomcat 5 logs for the details.</p>
+    </blockquote></li>
+<li><em>Invalid context path was specified</em>
+    <blockquote>
+    <p>The context path must start with a slash character. To reference the
+    ROOT web application use "/".</p>
+    </blockquote></li>
+<li><em>No context exists for path /foo</em>
+    <blockquote>
+    <p>There is no deployed application on the context path
+    that you specified.</p>
+    </blockquote></li>
+<li><em>No context path was specified</em>
+    <blockquote>
+    The <code>path</code> parameter is required.
+    </blockquote></li>
+</ul>
+
+</subsection>
+
+</section>
+
+<section name="Executing Manager Commands With Ant">
+
+<p>In addition to the ability to execute Manager commands via HTTP requests,
+as documented above, Tomcat 5 includes a convenient set of Task definitions
+for the <em>Ant</em> (version 1.4 or later) build tool.  In order to use these
+commands, you must perform the following setup operations:</p>
+<ul>
+<li>Download the binary distribution of Ant from
+    <a href="http://ant.apache.org">http://ant.apache.org</a>.
+    You must use version <strong>1.4</strong> or later.</li>
+<li>Install the Ant distribution in a convenient directory (called
+    ANT_HOME in the remainder of these instructions).</li>
+<li>Copy the file <code>server/lib/catalina-ant.jar</code> from your Tomcat 5
+    installation into Ant's library directory (<code>$ANT_HOME/lib</code>).
+    </li>
+<li>Add the <code>$ANT_HOME/bin</code> directory to your <code>PATH</code>
+    environment variable.</li>
+<li>Configure at least one username/password combination in your Tomcat
+    user database that includes the <code>manager</code> role.</li>
+</ul>
+
+<p>To use custom tasks within Ant, you must declare them first with a
+<code>&lt;taskdef&gt;</code> element.  Therefore, your <code>build.xml</code>
+file might look something like this:</p>
+
+<table border="1">
+<tr><td><pre>
+&lt;project name="My Application" default="compile" basedir="."&gt;
+
+  &lt;!-- Configure the directory into which the web application is built --&gt;
+  &lt;property name="build"    value="${basedir}/build"/&gt;
+
+  &lt;!-- Configure the context path for this application --&gt;
+  &lt;property name="path"     value="/myapp"/&gt;
+
+  &lt;!-- Configure properties to access the Manager application --&gt;
+  &lt;property name="url"      value="http://localhost:8080/manager"/&gt;
+  &lt;property name="username" value="myusername"/&gt;
+  &lt;property name="password" value="mypassword"/&gt;
+
+  &lt;!-- Configure the custom Ant tasks for the Manager application --&gt;
+  &lt;taskdef name="deploy"    classname="org.apache.catalina.ant.DeployTask"/&gt;
+  &lt;taskdef name="list"      classname="org.apache.catalina.ant.ListTask"/&gt;
+  &lt;taskdef name="reload"    classname="org.apache.catalina.ant.ReloadTask"/&gt;
+  &lt;taskdef name="resources" classname="org.apache.catalina.ant.ResourcesTask"/&gt;
+  &lt;taskdef name="roles"     classname="org.apache.catalina.ant.RolesTask"/&gt;
+  &lt;taskdef name="start"     classname="org.apache.catalina.ant.StartTask"/&gt;
+  &lt;taskdef name="stop"      classname="org.apache.catalina.ant.StopTask"/&gt;
+  &lt;taskdef name="undeploy"  classname="org.apache.catalina.ant.UndeployTask"/&gt;
+
+  &lt;!-- Executable Targets --&gt;
+  &lt;target name="compile" description="Compile web application"&gt;
+    &lt;!-- ... construct web application in ${build} subdirectory, and
+            generated a ${path}.war ... --&gt;
+  &lt;/target&gt;
+
+  &lt;target name="deploy" description="Install web application"
+          depends="compile"&gt;
+    &lt;deploy url="${url}" username="${username}" password="${password}"
+            path="${path}" war="${build}${path}.war"/&gt;
+  &lt;/target&gt;
+
+  &lt;target name="reload" description="Reload web application"
+          depends="compile"&gt;
+    &lt;reload  url="${url}" username="${username}" password="${password}"
+            path="${path}"/&gt;
+  &lt;/target&gt;
+
+  &lt;target name="undeploy" description="Remove web application"&gt;
+    &lt;undeploy url="${url}" username="${username}" password="${password}"
+            path="${path}"/&gt;
+  &lt;/target&gt;
+
+&lt;/project&gt;
+</pre></td></tr>
+</table>
+
+<p>Now, you can execute commands like <code>ant deploy</code> to deploy the
+application to a running instance of Tomcat, or <code>ant reload</code> to
+tell Tomcat to reload it.  Note also that most of the interesting values in
+this <code>build.xml</code> file are defined as replaceable properties, so
+you can override their values from the command line.  For example, you might
+consider it a security risk to include the real manager password in your
+<code>build.xml</code> file's source code.  To avoid this, omit the password
+property, and specify it from the command line:</p>
+<pre>
+  ant -Dpassword=secret deploy
+</pre>
+
+<subsection name="Tasks output capture">
+
+<p>Using <em>Ant</em> version <strong>1.6.2</strong> or later,
+the Catalina tasks offer the option to capture their output in 
+properties or external files. They support directly the following subset of the 
+<code>&lt;redirector&gt;</code> type attributes:
+</p>
+
+<table border="1" cellpadding="2" cellspacing="0">
+<tbody>
+<tr>
+<td valign="top"><b>Attribute</b></td>
+<td valign="top"><b>Description</b></td>
+<td align="center" valign="top"><b>Required</b></td>
+</tr>
+<tr>
+<td valign="top">output</td>
+<td valign="top">Name of a file to which to write the output. If
+the error stream is not also redirected to a file or property, it will
+appear in this output.</td>
+<td align="center" valign="top">No</td>
+</tr>
+<tr>
+<td valign="top">error</td>
+<td valign="top">The file to which the standard error of the
+command should be redirected.</td>
+<td align="center" valign="top">No</td>
+</tr>
+<tr>
+<td valign="top">logError</td>
+<td valign="top">This attribute is used when you wish to see
+error output in Ant's log and you are redirecting output to a
+file/property. The error output will not be included in the output
+file/property. If you redirect error with the <i>error</i> or <i>errorProperty</i>
+attributes, this will have no effect.</td>
+<td align="center" valign="top">No</td>
+</tr>
+<tr>
+<td valign="top">append</td>
+<td valign="top">Whether output and error files should be
+appended to or overwritten. Defaults to <code>false</code>.</td>
+<td align="center" valign="top">No</td>
+</tr>
+<tr>
+<td valign="top">createemptyfiles</td>
+<td valign="top">Whether output and error files should be created
+even when empty. Defaults to <code>true</code>.</td>
+<td align="center" valign="top">No</td>
+</tr>
+<tr>
+<td valign="top">outputproperty</td>
+<td valign="top">The name of a property in which the output of
+the command should be stored. Unless the error stream is redirected to
+a separate file or stream, this property will include the error output.</td>
+<td align="center" valign="top">No</td>
+</tr>
+<tr>
+<td valign="top">errorproperty</td>
+<td valign="top">The name of a property in which the standard
+error of the command should be stored.</td>
+<td align="center" valign="top">No</td>
+</tr>
+</tbody>
+</table>
+
+<p>A couple of additional attributes can also be specified:
+</p>
+<table border="1" cellpadding="2" cellspacing="0">
+<tbody>
+<tr>
+<td valign="top"><b>Attribute</b></td>
+<td valign="top"><b>Description</b></td>
+<td align="center" valign="top"><b>Required</b></td>
+</tr>
+<tr>
+<td valign="top">alwaysLog</td>
+<td valign="top">This attribute is used when you wish to see the
+output you are capturing, appearing also in the Ant's log. It must not be
+used unless you are capturing task output.
+Defaults to <code>false</code>.
+<em>This attribute will be supported directly by <code>&lt;redirector&gt;</code>
+in Ant 1.6.3</em></td>
+<td align="center" valign="top">No</td>
+</tr>
+<tr>
+<td valign="top">failonerror</td>
+<td valign="top">This attribute is used when you wish to avoid that
+any manager command processing error terminates the ant execution. Defaults to <code>true</code>.
+It must be set to <code>false</code>, if you want to capture error output,
+otherwise execution will terminate before anything can be captured.
+<br></br>
+This attribute acts only on manager command execution,
+any wrong or missing command attribute will still cause Ant execution termination.
+</td>
+<td align="center" valign="top">No</td>
+</tr>
+</tbody>
+</table>
+
+<p>They also support the embedded <code>&lt;redirector&gt;</code> element
+in which you can specify
+its full set of attributes, but <code>input</code>, <code>inputstring</code> and 
+<code>inputencoding</code> that, even if accepted, are not used because they have
+no meaning in this context.
+Refer to <a href="http://ant.apache.org">ant manual</a> for details on 
+<code>&lt;redirector&gt;</code> element attributes.
+</p>
+
+<p>
+Here is a sample build file extract that shows how this output redirection support
+can be used:
+</p>
+
+<table border="1">
+<tr><td><pre>
+	&lt;target name="manager.deploy"
+		depends="context.status"
+		if="context.notInstalled"&gt;
+		&lt;deploy url="${mgr.url}"
+			username="${mgr.username}"
+			password="${mgr.password}"
+			path="${mgr.context.path}"
+			config="${mgr.context.descriptor}"/&gt;
+	&lt;/target&gt;
+
+	&lt;target name="manager.deploy.war"
+		depends="context.status"
+		if="context.deployable"&gt;
+		&lt;deploy url="${mgr.url}"
+			username="${mgr.username}"
+			password="${mgr.password}"
+			update="${mgr.update}"
+			path="${mgr.context.path}"
+			war="${mgr.war.file}"/&gt;
+	&lt;/target&gt;
+	
+	&lt;target name="context.status"&gt;
+		&lt;property name="running" value="${mgr.context.path}:running"/&gt;
+		&lt;property name="stopped" value="${mgr.context.path}:stopped"/&gt;
+	
+		&lt;list url="${mgr.url}"
+			outputproperty="ctx.status"
+			username="${mgr.username}"
+			password="${mgr.password}"&gt;
+		&lt;/list&gt;
+		
+		&lt;condition property="context.running"&gt;
+			&lt;contains string="${ctx.status}" substring="${running}"/&gt;
+		&lt;/condition&gt;
+		&lt;condition property="context.stopped"&gt;
+			&lt;contains string="${ctx.status}" substring="${stopped}"/&gt;
+		&lt;/condition&gt;
+		&lt;condition property="context.notInstalled"&gt;
+			&lt;and&gt;
+				&lt;isfalse value="${context.running}"/&gt;
+				&lt;isfalse value="${context.stopped}"/&gt;
+			&lt;/and&gt;
+		&lt;/condition&gt;
+		&lt;condition property="context.deployable"&gt;
+			&lt;or&gt;
+				&lt;istrue value="${context.notInstalled}"/&gt;
+				&lt;and&gt;
+					&lt;istrue value="${context.running}"/&gt;
+					&lt;istrue value="${mgr.update}"/&gt;
+				&lt;/and&gt;
+				&lt;and&gt;
+					&lt;istrue value="${context.stopped}"/&gt;
+					&lt;istrue value="${mgr.update}"/&gt;
+				&lt;/and&gt;
+			&lt;/or&gt;
+		&lt;/condition&gt;
+		&lt;condition property="context.undeployable"&gt;
+			&lt;or&gt;
+				&lt;istrue value="${context.running}"/&gt;
+				&lt;istrue value="${context.stopped}"/&gt;
+			&lt;/or&gt;
+		&lt;/condition&gt;
+	&lt;/target&gt;
+</pre></td></tr>
+</table>
+
+<p><strong>WARNING:</strong> even if it doesn't make many sense, and is always a bad idea,
+calling a Catalina task more than once,
+badly set Ant tasks depends chains may cause that a task be called
+more than once in the same Ant run, even if not intended to. A bit of caution should be exercised when you are
+capturing output from that task, because this could lead to something unexpected:
+<ul>
+<li>when capturing in a property you will find in it only the output from the <em>first</em> call, because
+Ant properties are immutable and once set they cannot be changed,
+</li>
+<li>when capturing in a file, each run will overwrite it and you will find in it only the <em>last</em> call
+output, unless you are using the <code>append="true"</code> attribute, in which case you will
+see the output of each task call appended to the file.
+</li>
+</ul>
+</p>
+
+</subsection>
+
+</section>
+
+<section name="Using the JMX Proxy Servlet">
+
+  <subsection name="What is JMX Proxy Servlet">
+    The JMX Proxy Servlet is a lightweight proxy to get and set the
+    tomcat internals. (Or any class that has been exposed via an MBean)
+    Its usage is not very user friendly but the UI is
+    extremely help for integrating command line scripts for monitoring
+    and changing the internals of tomcat. You can do two things with the proxy:
+    get information and set information. For you to really understand the
+    JMX Proxy Servlet, you should have a general understanding of JMX.
+    If you don't know what JMX is, then prepare to be confused.
+  </subsection>
+
+  <subsection name="JMX Query command">
+    This takes the form:
+<source>
+http://webserver/manager/jmxproxy/?qry=STUFF
+</source>
+    Where <code>STUFF</code> is the JMX query you wish to perform. For example,
+    here are some queries you might wish to run:
+    <ul>
+      <li>
+        <code>qry=*%3Atype%3DRequestProcessor%2C* -->
+         type=RequestProcessor</code> which will locate all
+         workers which can process requests and report
+         their state.
+      </li>
+      <li>
+        <code>qry=*%3Aj2eeType=Servlet%2c* -->
+            j2eeType=Servlet</code> which return all loaded servlets.
+      </li>
+      <li>
+        <code>qry=Catalina%3Atype%3DEnvironment%2Cresourcetype%3DGlobal%2Cname%3DsimpleValue -->
+            Catalina:type=Environment,resourcetype=Global,name=simpleValue</code>
+            which look for a specific MBean by the given name.
+      </li>
+    </ul>
+    You'll need to experiment with this to really understand its capabilites.
+    If you provide no <code>qry</code> parameter, then all of the MBeans will
+    be displayed. We really recommend looking at the tomcat source code and
+    understand the JMX spec to get a better understanding of all the queries
+    you may run.
+  </subsection>
+
+  <subsection name="JMX Set command">
+    Now that you can query an MBean, its time to muck with Tomcat's internals!
+    The general form of the set command is :
+<source>
+http://webserver/manager/jmxproxy/?set=BEANNAME&amp;att=MYATTRIBUTE&amp;val=NEWVALUE
+</source>
+    So you need to provide 3 request parameters:
+    <ol>
+      <li><code>set</code>: The full bean name</li>
+      <li><code>att</code>: The attribute you wish to alter</li>
+      <li><code>val</code>: The new value </li>
+    </ol>
+    If all goes ok, then it will say OK, otherwise an error message will be
+    shown. For example, lets say we wish to turn up debugging on the fly for the
+    <code>ErrorReportValve</code>. The following will set debugging to 10.
+<source>
+http://localhost:8080/manager/jmxproxy/
+?set=Catalina%3Atype%3DValve%2Cname%3DErrorReportValve%2Chost%3Dlocalhost&amp;att=debug&amp;val=10
+</source>
+    and my result is (YMMV):
+<source>
+Result: ok
+</source>
+
+    Here is what I see if I pass in a bad value. Here is the URL I used,
+    I try set debugging equal to 'cowbell':
+<source>
+http://localhost:8080/manager/jmxproxy/
+?set=Catalina%3Atype%3DValve%2Cname%3DErrorReportValve%2Chost%3Dlocalhost&amp;att=debug&amp;val=cowbell
+</source>
+    When I try that, my result is
+<source>
+Error: java.lang.NumberFormatException: For input string: "cowbell"
+</source>
+  </subsection>
+
+
+</section>
+
+
+
+</body>
+
+</document>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/mbeans-descriptor-howto.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/mbeans-descriptor-howto.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/mbeans-descriptor-howto.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,63 @@
+<?xml version="1.0"?>
+<!DOCTYPE document [
+  <!ENTITY project SYSTEM "project.xml">
+]>
+<document url="mbeans-descriptor-howto.html">
+
+    &project;
+
+    <properties>
+        <author email="amyroh at apache.org">Amy Roh</author>
+        <title>MBean Descriptor How To</title>
+    </properties>
+
+<body>
+
+<section name="Introduction">
+
+<p>Tomcat 5 uses JMX MBeans as the technology for implementing 
+manageability of Tomcat.</p>
+
+<p>The descriptions of JMX MBeans for Catalina are in the mbeans-descriptor.xml 
+file in each package.</p>
+
+<p>You will need to add MBean descriptions for your custom components 
+in order to avoid a "ManagedBean is not found" exception.</p>
+
+</section>
+
+<section name="Adding MBean descriptions">
+
+<p>You may also add MBean descriptions for custom components in 
+a mbeans-descriptor.xml file, located in the same package as the class files
+it describes.</p>
+
+<source>
+  &lt;mbean         name="LDAPRealm"
+            className="org.apache.catalina.mbeans.ClassNameMBean"
+          description="Custom LDAPRealm"
+               domain="Catalina"
+                group="Realm"
+                 type="com.myfirm.mypackage.LDAPRealm"&gt;
+
+    &lt;attribute   name="className"
+          description="Fully qualified class name of the managed object"
+                 type="java.lang.String"
+            writeable="false"/&gt;
+
+    &lt;attribute   name="debug"
+          description="The debugging detail level for this component"
+                 type="int"/&gt;
+    .
+    .
+    .
+
+  &lt;/mbean&gt;
+</source>
+
+
+</section>
+
+</body>
+
+</document>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/monitoring.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/monitoring.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/monitoring.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,1147 @@
+<?xml version="1.0"?>
+<!DOCTYPE document [
+  <!ENTITY project SYSTEM "project.xml">
+]>
+<document url="monitoring.html">
+
+  &project;
+
+  <properties>
+    <author email="pero at apache.org">Peter Rossbach</author>
+    <author email="remm at apache.org">Remy Maucherat</author>
+    <title>Monitoring and Managing Tomcat</title>
+  </properties>
+
+<body>
+
+  <section name="Introduction">
+
+  <p>Monitoring is a very important question today. Looking inside the running
+        server, grab some statistic data or reconfigure some aspects are 
+        daliy adminstration tasks.</p>  
+  
+  </section>
+
+  <section name="Enabling JMX Remote">
+
+    <p>The Sun website includes the list of options and how to configure JMX Remote on Java 5:
+        <a href="http://java.sun.com/j2se/1.5.0/docs/guide/management/agent.html">
+        http://java.sun.com/j2se/1.5.0/docs/guide/management/agent.html</a>.
+    </p>
+    <p>For quick installation you find here a short installation guide:</p>
+    <p>Add the following parameters to your tomcat startup script:
+    <source>
+    set CATALINA_OPTS="-Dcom.sun.management.jmxremote \
+    -Dcom.sun.management.jmxremote.port=%my.jmx.port% \
+    -Dcom.sun.management.jmxremote.ssl=false \
+    -Dcom.sun.management.jmxremote.authenticate=false"
+    </source>
+    </p>
+    <p>
+    <ol>
+    <li>When you think authorisation is a good, add and change this :
+    <source>
+    -Dcom.sun.management.jmxremote.authenticate=true \
+    -Dcom.sun.management.jmxremote.password.file=../conf/jmxremote.password \
+    -Dcom.sun.management.jmxremote.access.file=../conf/jmxremote.access \
+    </source>
+    </li>
+    <li>edit the access allow file <em>$CATALINA_BASE/conf/jmxremote.access</em> :
+    <source>
+monitorRole readonly
+controlRole readwrite
+    </source>
+    </li>
+    <li>edit the password file <em>$CATALINA_BASE/conf/jmxremote.password</em> :
+    <source>
+monitorRole tomcat
+controlRole tomcat
+    </source>
+    <b>Tipp</b>: Password File must be readonly and not accessable from every 
+    other user! Remove all other users under windows to access this file.
+    </li>
+    </ol>
+    <b>Note:</b>The JSR 160 JMX-Adaptor opens a second data protocol port. That is a problem
+    when you have installed a local firewall.<br/>
+    </p>
+    <p>Activate JMX MX4J Http Adaptor with Java 1.4:
+    <ol>
+      <li>Install the tomcat compat package</li>
+      <li>Install the mx4j-tools.jar at common/lib. Please, use the same MX4j 
+          version as your tomcat release</li>
+      <li>Configure a MX4J JMX HTTP Adaptor at your AJP Connector
+      <p>
+      <source>
+      &lt;Connector port="${AJP.PORT}" 
+            handler.list="mx" 
+            mx.enabled="true" 
+            mx.httpHost="${JMX.HOST}"
+            mx.httpPort="${JMX.PORT}"
+            protocol="AJP/1.3" /&gt;
+      </source>
+      </p>
+      <p><b>Tipp</b>: With <em>${AJP.PORT}=0</em> no ajp connection where started. 
+      </p>
+      <p><b>Note</b>: MX4J JSR 160 RMI Adaptor to support JDK 1.4 currently not integrated.
+      </p>
+      </li>
+      <li>Start your tomcat and look with a browser at http://${JMX.HOST}:${JMX.PORT}</li>
+      <li>With the mx connector parameter <code>mx.authMode="basic" mx.authUser="tomcat" mx.authPassword="strange"</code> 
+          you can control the access!</li>
+      <li>A complete list of all tomcat core MBeans can you find at <a href="http://tomcat.apache.org/tomcat-5.5-doc/catalina/funcspecs/mbean-names.html">
+        http://tomcat.apache.org/tomcat-5.5-doc/catalina/funcspecs/mbean-names.html</a>.</li>
+    </ol>
+    </p>
+
+  </section>
+
+  <section name="Manage Tomcat with JMX remote Ant Tasks">
+   <p>For simple tomcat ant task usage with ant 1.6.x we have integrate import and antlib support.</p>   
+   <p><b>antlib</b>Copy your catalina-ant.jar from $CATALINA_HOME/server/lib to $ANT_HOME/lib.</p>
+   <p>Following example show the JMX Accessor usage:</p>
+   <table border="1">
+   <tr><td><p><pre>
+&lt;project name="Catalina Ant JMX" 
+        xmlns:jmx="antlib:org.apache.catalina.ant.jmx" 
+        default="state"
+        basedir="."&gt;
+    &lt;property name="jmx.server.name" value="localhost" /&gt;
+    &lt;property name="jmx.server.port" value="9012" /&gt;
+    &lt;property name="cluster.server.address" value="192.168.1.75" /&gt;
+    &lt;property name="cluster.server.port" value="9025" /&gt;
+ 
+    &lt;target name="state" description="Show JMX Cluster state"&gt;
+        &lt;jmx:open
+            host="${jmx.server.name}"
+            port="${jmx.server.port}"
+            username="controlRole"
+            password="tomcat"/&gt;
+        &lt;jmx:get
+            name="Catalina:type=IDataSender,host=localhost,senderAddress=${cluster.server.address},senderPort=${cluster.server.port}" 
+            attribute="connected"
+            resultproperty="IDataSender.backup.connected"
+            echo="false"
+        /&gt;
+       &lt;jmx:get
+            name="Catalina:type=ClusterSender,host=localhost" 
+            attribute="senderObjectNames"
+            resultproperty="senderObjectNames"
+            echo="false"
+        /&gt;
+        &lt;!-- get current maxActiveSession from ClusterTest application
+             echo it to ant output and store at 
+             property &lt;em&gt;clustertest.maxActiveSessions.orginal&lt;/em&gt;
+        --&gt;
+       &lt;jmx:get
+            name="Catalina:type=Manager,path=/ClusterTest,host=localhost" 
+            attribute="maxActiveSessions"
+            resultproperty="clustertest.maxActiveSessions.orginal"
+            echo="true"
+        /&gt;
+        &lt;!-- set maxActiveSession to 100
+        --&gt;
+        &lt;jmx:set
+            name="Catalina:type=Manager,path=/ClusterTest,host=localhost" 
+            attribute="maxActiveSessions"
+            value="100"
+            type="int"
+        /&gt;
+        &lt;!-- get all sessions and split result as delimiter &lt;em&gt;SPACE&lt;/em&gt; for easy
+             access all session ids directly with ant property sessions.[0..n].
+        --&gt;
+        &lt;jmx:invoke
+            name="Catalina:type=Manager,path=/ClusterTest,host=localhost" 
+            operation="listSessionIds"
+            resultproperty="sessions"
+            echo="false"
+            delimiter=" "
+        /&gt;
+        &lt;!-- Access session attribute &lt;em&gt;Hello&lt;/em&gt; from first session.
+        --&gt;
+        &lt;jmx:invoke
+            name="Catalina:type=Manager,path=/ClusterTest,host=localhost" 
+            operation="getSessionAttribute"
+            resultproperty="Hello"
+            echo="false"
+        &gt;
+          &lt;arg value="${sessions.0}"/&gt;
+          &lt;arg value="Hello"/&gt;
+        &lt;/jmx:invoke&gt; 
+        &lt;!-- Query for all application manager.of the server from all hosts
+             and bind all attributes from all found manager mbeans.
+        --&gt;
+        &lt;jmx:query
+            name="Catalina:type=Manager,*" 
+            resultproperty="manager"
+            echo="true"
+            attributebinding="true"
+        /&gt;
+        &lt;!-- echo the create properties --&gt;
+        &lt;echo&gt;
+           senderObjectNames: ${senderObjectNames.0}
+           IDataSender.backup.connected: ${IDataSender.backup.connected}
+           session: ${sessions.0}
+           manager.length: ${manager.length}
+           manager.0.name: ${manager.0.name}
+           manager.1.name: ${manager.1.name}
+           hello: ${Hello}
+           manager.ClusterTest.0.name: ${manager.ClusterTest.0.name}
+           manager.ClusterTest.0.activeSessions: ${manager.ClusterTest.0.activeSessions}
+           manager.ClusterTest.0.counterSend_EVT_SESSION_EXPIRED: ${manager.ClusterTest.0.counterSend_EVT_SESSION_EXPIRED}
+           manager.ClusterTest.0.counterSend_EVT_GET_ALL_SESSIONS: ${manager.ClusterTest.0.counterSend_EVT_GET_ALL_SESSIONS}
+        &lt;/echo&gt;   
+
+    &lt;/target&gt;
+ 
+&lt;/project&gt;
+   </pre></p>
+   </td></tr>
+</table>
+   <p><b>import:</b> Import the JMX Accessor Projekt with 
+   <em>&lt;import file="${CATALINA.HOME}/bin/jmxaccessor-tasks.xml" /&gt;</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>
+
+  </section>
+
+<!-- Open ######################################################################### 
+-->
+
+<section name="JMXAccessorOpenTask - jmx open connection task">
+<p>
+List of Attributes<br/>
+<table border="1" cellpadding="5">
+
+  <tr>
+    <th align="center" bgcolor="aqua">Attribute</th>
+    <th align="center" bgcolor="aqua">Description</th>
+    <th align="center" bgcolor="aqua">Default value</th>
+  </tr>
+
+  <tr>
+    <td>url</td>
+    <td>Set jmx connection url - <em>service:jmx:rmi:///jndi/rmi://localhost:8050/jmxrmi</em>
+    </td>
+    <td></td>
+  </tr>
+
+  <tr>
+    <td>host</td>
+    <td>Set the host, shortcut the very long url syntax.
+    </td>
+    <td><code>localhost</code></td>
+  </tr>
+
+  <tr>
+    <td>port</td>
+    <td>Set the remote connection port 
+    </td>
+    <td><code>8050</code></td>
+  </tr>
+
+  <tr>
+    <td>username</td>
+    <td>remote jmx connection user name.
+    </td>
+    <td></td>
+  </tr>
+
+  <tr>
+    <td>password</td>
+    <td>remote jmx connection password.
+    </td>
+    <td></td>
+  </tr>
+
+  <tr>
+    <td>ref</td>
+    <td>Name of the internal connection referenz. With this attribute you can
+        configure more the one connection inside the same ant projekt.
+    </td>
+    <td><code>jmx.server</code></td>
+  </tr>
+
+  <tr>
+    <td>echo</td>
+    <td>Echo the command usage (for analyse access or debugging)
+    </td>
+    <td><code>false</code></td>
+  </tr>
+  
+  <tr>
+    <td>if</td>
+    <td>Only execute if a property of the given name <b>exists</b> in the current project.
+    </td>
+    <td></td>
+  </tr>
+
+  <tr>
+    <td>unless</td>
+    <td>Only execute if a property of the given name <b>not exists</b> in the current project.
+    </td>
+    <td></td>
+  </tr>
+
+</table>
+</p>
+<p>
+Example to open a new jmx connection<br/>
+<source>
+    &lt;jmx:open
+            host="${jmx.server.name}"
+            port="${jmx.server.port}"
+    /&gt;
+</source>
+</p>  
+<p>
+Example to open a jmx connection from url, with authorisation and 
+store at other reference <br/>
+<source>
+    &lt;jmx:open
+            url="service:jmx:rmi:///jndi/rmi://localhost:9024/jmxrmi"
+            ref="jmx.server.9024"
+            username="controlRole"
+            password="tomcat"    
+    /&gt;
+</source>
+</p>  
+
+<p>
+Example to open a jmx connection from url, with authorisation and 
+store at other reference, but only when property <em>jmx.if</em> exists and 
+<em>jmx.unless</em> not exists<br/>
+<source>
+    &lt;jmx:open
+            url="service:jmx:rmi:///jndi/rmi://localhost:9024/jmxrmi"
+            ref="jmx.server.9024"
+            username="controlRole"
+            password="tomcat"    
+            if="jmx.if"    
+            unless="jmx.unless"    
+    /&gt;
+</source>
+</p> 
+<p><b>Note</b>: All properties from <em>jmxOpen</em> task also exists at all 
+other tasks and conditions. 
+</p>
+
+</section>
+
+<!-- Get ######################################################################### 
+-->
+
+<section name="JMXAccessorGetTask:  get attribute value ant task">
+<p>
+List of Attributes<br/>
+<table border="1" cellpadding="5">
+
+  <tr>
+    <th align="center" bgcolor="aqua">Attribute</th>
+    <th align="center" bgcolor="aqua">Description</th>
+    <th align="center" bgcolor="aqua">Default value</th>
+  </tr>
+
+  <tr>
+    <td>name</td>
+    <td>Full qualified JMX ObjectName -- <em>Catalina:type=Server</em>
+    </td>
+    <td></td>
+  </tr>
+
+  <tr>
+    <td>attribute</td>
+    <td>Existing Mbean attribute (see Tomcat mbean description above)
+    </td>
+    <td></td>
+  </tr>
+
+  <tr>
+    <td>ref</td>
+    <td>JMX Connection reference
+    </td>
+    <td><code>jmx.server</code></td>
+  </tr>
+
+  <tr>
+    <td>echo</td>
+    <td>Echo command usage (access and result)
+    </td>
+    <td><code>false</code></td>
+  </tr>
+
+  <tr>
+    <td>resultproperty</td>
+    <td>Save result at this project property
+    </td>
+    <td></td>
+  </tr>
+
+  <tr>
+    <td>delimiter</td>
+    <td>Split result with delimiter (java.util.StringTokenizier) 
+        and use resultproperty as prefix to store tokens.
+    </td>
+    <td></td>
+  </tr>
+
+  <tr>
+    <td>separatearrayresults</td>
+    <td>When return value is an array, save result as property list 
+    (<em>$resultproperty.[0..N]</em> and <em>$resultproperty.lenght</em>) 
+    </td>
+    <td><code>true</code></td>
+  </tr>
+
+</table>
+</p>
+<p>
+Example to get remote mbean attribute from default jmx connection <br/>
+<source>
+    &lt;jmx:get
+        name="Catalina:type=Manager,path=/servlets-examples,host=localhost" 
+        attribute="maxActiveSessions"
+        resultproperty="servlets-examples.maxActiveSessions"
+    /&gt;
+</source>
+</p>  
+<p>
+Example to get and result array and split it at separate properties<br/>
+<source>
+    &lt;jmx:get
+        name="Catalina:type=ClusterSender,host=localhost" 
+        attribute="senderObjectNames"
+        resultproperty="senderObjectNames"
+    /&gt;
+</source>
+Access the senderObjectNames properties with:
+<source>
+    ${senderObjectNames.lenght} give the number of returned sender list.
+    ${senderObjectNames.[0..N]} found all sender object names
+</source>
+</p>  
+
+<p>
+Example to get IDataSender attribute connected only when cluster is configured.
+<source>
+&lt;jmx:query
+    failonerror="false"
+    name="Catalina:type=Cluster,host=${tomcat.application.host}"
+    resultproperty="cluster"
+/&gt;
+&lt;jmx:get
+    name="Catalina:type=IDataSender,host=${tomcat.application.host},senderAddress=${cluster.backup.address},senderPort=${cluster.backup.port}" 
+    attribute="connected"
+    resultproperty="datasender.connected"
+    if="cluster.0.name" /&gt;
+</source>
+</p>  
+
+</section>
+
+<!-- Set ######################################################################### 
+-->
+
+<section name="JMXAccessorSetTask:  set attribute value ant task">
+<p>
+List of Attributes<br/>
+<table border="1" cellpadding="5">
+
+  <tr>
+    <th align="center" bgcolor="aqua">Attribute</th>
+    <th align="center" bgcolor="aqua">Description</th>
+    <th align="center" bgcolor="aqua">Default value</th>
+  </tr>
+
+  <tr>
+    <td>name</td>
+    <td>Full qualified JMX ObjectName -- <em>Catalina:type=Server</em>
+    </td>
+    <td></td>
+  </tr>
+
+  <tr>
+    <td>attribute</td>
+    <td>Existing Mbean attribute (see Tomcat mbean description above)
+    </td>
+    <td></td>
+  </tr>
+
+  <tr>
+    <td>value</td>
+    <td>value that set to attribute 
+    </td>
+    <td></td>
+  </tr>
+
+  <tr>
+    <td>type</td>
+    <td>type of the attribute.
+    </td>
+    <td>java.lang.String</td>
+  </tr>
+
+  <tr>
+    <td>ref</td>
+    <td>JMX Connection reference
+    </td>
+    <td><code>jmx.server</code></td>
+  </tr>
+
+  <tr>
+    <td>echo</td>
+    <td>Echo command usage (access and result)
+    </td>
+    <td><code>false</code></td>
+  </tr>
+
+</table>
+</p>
+<p>
+Example to set remote mbean attribute value<br/>
+<source>
+    &lt;jmx:set
+        name="Catalina:type=Manager,path=/servlets-examples,host=localhost" 
+        attribute="maxActiveSessions"
+        value="500"
+        type="int"
+    /&gt;
+</source>
+</p>  
+<p>
+Examples to set multiple remote mbean attributes<br/>
+<source>
+    &lt;jmx:set
+        name="java.lang:type=Threading"&gt; 
+			 &lt;arg name="ThreadContentionMonitoringEnabled" value="true" type="boolean"/&gt;
+			 &lt;arg name="ThreadCpuTimeEnabled" value="false" type="boolean"/&gt;
+    &lt;/jmx:set&gt;
+</source>
+</p>  
+
+</section>
+
+<!-- Invoke ######################################################################### 
+-->
+
+<section name="JMXAccessorInvokeTask:  invoke Mbean operation ant task">
+<p>
+List of Attributes<br/>
+<table border="1" cellpadding="5">
+
+  <tr>
+    <th align="center" bgcolor="aqua">Attribute</th>
+    <th align="center" bgcolor="aqua">Description</th>
+    <th align="center" bgcolor="aqua">Default value</th>
+  </tr>
+
+  <tr>
+    <td>name</td>
+    <td>Full qualified JMX ObjectName -- <em>Catalina:type=Server</em>
+    </td>
+    <td></td>
+  </tr>
+
+  <tr>
+    <td>operation</td>
+    <td>Existing Mbean operation (see Tomcat 
+        <a href="http://tomcat.apache.org/tomcat-5.5-doc/catalina/funcspecs/fs-admin-opers.html">
+        http://tomcat.apache.org/tomcat-5.5-doc/catalina/funcspecs/fs-admin-opers.html</a>.
+    </td>
+    <td></td>
+  </tr>
+
+  <tr>
+    <td>ref</td>
+    <td>JMX Connection reference
+    </td>
+    <td><code>jmx.server</code></td>
+  </tr>
+
+  <tr>
+    <td>echo</td>
+    <td>Echo command usage (access and result)
+    </td>
+    <td><code>false</code></td>
+  </tr>
+
+  <tr>
+    <td>resultproperty</td>
+    <td>Save result at this project property
+    </td>
+    <td></td>
+  </tr>
+
+  <tr>
+    <td>delimiter</td>
+    <td>Split result with delimiter (java.util.StringTokenizier) 
+        and use resultproperty as prefix to store tokens.
+    </td>
+    <td></td>
+  </tr>
+
+  <tr>
+    <td>separatearrayresults</td>
+    <td>When return value is an array, save result as property list 
+    (<em>$resultproperty.[0..N]</em> and <em>$resultproperty.lenght</em>) 
+    </td>
+    <td><code>true</code></td>
+  </tr>
+
+</table>
+</p>
+<p>
+stop an application <br/>
+<source>
+    &lt;jmx:invoke
+        name="Catalina:type=Manager,path=/servlets-examples,host=localhost" 
+        operation="stop"/&gt;
+</source>
+Now you can find the sessionid at <em>${sessions.[0..N}</em> properties and access the count
+with ${sessions.lenght} property.
+</p>  
+<p>
+Example to get all sessionids <br/>
+<source>
+    &lt;jmx:invoke
+        name="Catalina:type=Manager,path=/servlets-examples,host=localhost" 
+        operation="listSessionIds"
+        resultproperty="sessions"
+        delimiter=" "        
+    /&gt;
+</source>
+Now you can find the sessionid at <em>${sessions.[0..N}</em> properties and access the count
+with ${sessions.lenght} property.
+</p>  
+<p>
+Example to get remote mbean session attribute from session ${sessionid.0}<br/>
+<source>
+    &lt;jmx:invoke
+        name="Catalina:type=Manager,path=/ClusterTest,host=localhost" 
+        operation="getSessionAttribute"
+        resultproperty="hello"&gt;
+         &lt;arg value="${sessionid.0}"/&gt;
+         &lt;arg value="Hello" /&gt;
+ &lt;/jmx:invoke&gt;
+</source>
+</p>
+<p>
+Example to create a new access logger valve at vhost <em>localhost</em>
+<source>
+ &lt;jmx:invoke
+         name="Catalina:type=MBeanFactory" 
+         operation="createAcccesLoggerValve"
+         resultproperty="acccesLoggerObjectName"
+ &gt;
+     &lt;arg value="Catalina:type=Host,host=localhost"/&gt;
+ &lt;/jmx:invoke&gt;
+</source>
+Now you can find new Mbean with name stored at <em>${acccesLoggerObjectName}</em>
+proeprty.
+</p>  
+
+</section>
+
+<!-- Query ######################################################################### 
+-->
+
+<section name="JMXAccessorQueryTask:  query Mbean ant task">
+<p>
+List of Attributes<br/>
+<table border="1" cellpadding="5">
+
+  <tr>
+    <th align="center" bgcolor="aqua">Attribute</th>
+    <th align="center" bgcolor="aqua">Description</th>
+    <th align="center" bgcolor="aqua">Default value</th>
+  </tr>
+
+  <tr>
+    <td>name</td>
+    <td>JMX  ObjectName query string -- <em>Catalina:type=Manager,*</em>
+    </td>
+    <td></td>
+  </tr>
+
+  <tr>
+    <td>ref</td>
+    <td>JMX Connection reference
+    </td>
+    <td><code>jmx.server</code></td>
+  </tr>
+
+  <tr>
+    <td>echo</td>
+    <td>Echo command usage (access and result)
+    </td>
+    <td><code>false</code></td>
+  </tr>
+
+  <tr>
+    <td>resultproperty</td>
+    <td>Prefix project property name to all founded Mbeans (<em>mbeans.[0..N].objectname</em>)
+    </td>
+    <td></td>
+  </tr>
+
+  <tr>
+    <td>attributebinduing</td>
+    <td>bind ALL MBean attributes in addition to <em>name</em>
+    </td>
+    <td><code>false</code></td>
+  </tr>
+
+  <tr>
+    <td>delimiter</td>
+    <td>Split result with delimiter (java.util.StringTokenizier) 
+        and use resultproperty as prefix to store tokens.
+    </td>
+    <td></td>
+  </tr>
+
+  <tr>
+    <td>separatearrayresults</td>
+    <td>When return value is an array, save result as property list 
+    (<em>$resultproperty.[0..N]</em> and <em>$resultproperty.lenght</em>) 
+    </td>
+    <td><code>true</code></td>
+  </tr>
+
+</table>
+</p>
+<p>
+Get all Manager ObjectNames from all services and Hosts <br/>
+<source>
+  &lt;jmx:query
+           name="Catalina:type=Manager,* 
+           resultproperty="manager" /&gt;
+</source>
+Now you can find the Session Manager at <em>${manager.[0..N].name}</em> 
+properties and access the result object counter with ${manager.length} property.
+</p>  
+<p>
+Example to get the Manager from <em>servlet-examples</em> application an bind all mbean properties<br/>
+<source>
+  &lt;jmx:query
+           name="Catalina:type=Manager,path=/servlet-examples,host=localhost*" 
+           attributebinding="true"
+           resultproperty="manager.servletExamples" /&gt;
+</source>
+Now you can find the manager at <em>${manager.servletExamples.0.name}</em> property
+and can access all properties from this manager with <em>${manager.servletExamples.0.[manager attribute names]</em>}.
+The result object counter from MBeans is stored ad ${manager.length} property.
+</p>  
+
+<p>
+Example to get all MBeans from a server and store inside an external xml property file<br/>
+<source>
+&lt;project name="jmx.query"         
+            xmlns:jmx="antlib:org.apache.catalina.ant.jmx"
+            default="query-all" basedir="."&gt;
+&lt;property name="jmx.host" value="localhost"/&gt;
+&lt;property name="jmx.port" value="8050"/&gt;
+&lt;property name="jmx.username" value="controlRole"/&gt;
+&lt;property name="jmx.password" value="tomcat"/&gt;
+
+&lt;target name="query-all" description="Query all MBeans of a server"&gt;
+&lt;!-- Configure connection --&gt;
+&lt;jmx:open 
+    host="${jmx.host}"
+    port="${jmx.port}"
+    ref="jmx.server"
+    username="${jmx.username}"
+    password="${jmx.password}"/&gt;
+&lt;!-- Query MBean list --&gt;
+&lt;jmx:query 
+    name="*:*"
+    resultproperty="mbeans"
+    attributebinding="false"/&gt;
+    
+&lt;echoproperties
+    destfile="mbeans.properties"
+    prefix="mbeans."
+    format="xml"/&gt;
+    
+&lt;!-- Print results --&gt;
+&lt;echo
+    message="Number of MBeans in server ${jmx.host}:${jmx.port} is ${mbeans.length}"/&gt;
+&lt;/target&gt;
+&lt;/project&gt;
+</source>
+Now you can find all MBeans inside the file <em>mbeans.properties</em>.
+</p>  
+
+</section>
+
+<!-- Create ######################################################################### 
+-->
+
+<section name="JMXAccessorCreateTask:  remote create mbean ant task">
+<p>
+List of Attributes<br/>
+<table border="1" cellpadding="5">
+
+  <tr>
+    <th align="center" bgcolor="aqua">Attribute</th>
+    <th align="center" bgcolor="aqua">Description</th>
+    <th align="center" bgcolor="aqua">Default value</th>
+  </tr>
+
+  <tr>
+    <td>name</td>
+    <td>Full qualified JMX ObjectName -- <em>Catalina:type=MBeanFactory</em>
+    </td>
+    <td></td>
+  </tr>
+
+  <tr>
+    <td>className</td>
+    <td>Existing MBean full qualified classname (see Tomcat mbean description above)
+    </td>
+    <td></td>
+  </tr>
+
+  <tr>
+    <td>classLoader</td>
+    <td>ObjectName of server or web application classloader <br/>
+    ( <em>Catalina:type=ServerClassLoader,name=[server,common,shared]</em> or<br/>
+     <em>Catalina:type=WebappClassLoader,path=/myapps,host=localhost</em>) 
+    </td>
+    <td></td>
+  </tr>
+
+  <tr>
+    <td>ref</td>
+    <td>JMX Connection reference
+    </td>
+    <td><code>jmx.server</code></td>
+  </tr>
+
+  <tr>
+    <td>echo</td>
+    <td>Echo command usage (access and result)
+    </td>
+    <td><code>false</code></td>
+  </tr>
+
+</table>
+</p>
+<p>
+Example to create remote mbean<br/>
+<source>
+    &lt;jmx:create
+             ref="${jmx.reference}"
+             name="Catalina:type=MBeanFactory"
+             className="org.apache.commons.modeler.BaseModelMBean"
+             classLoader="Catalina:type=ServerClassLoader,name=server"&gt;             
+             &lt;Arg value="org.apache.catalina.mbeans.MBeanFactory" /&gt;
+    &lt;/jmx:create&gt; 
+</source>
+</p>  
+<p>
+    <b>Warning</b>: A lot of tomcat mbeans can't be really create and connect with <br/>
+    the parent. The valve, cluster or realm Mbeans are not autconnect with there parent.<br/> 
+    Use <em>MBeanFacrory</em> create operation instead.
+</p>
+
+</section>
+
+<!-- Unregister ######################################################################### 
+-->
+
+<section name="JMXAccessorUnregisterTask:  remote unregister mbean ant task">
+<p>
+List of Attributes<br/>
+<table border="1" cellpadding="5">
+
+  <tr>
+    <th align="center" bgcolor="aqua">Attribute</th>
+    <th align="center" bgcolor="aqua">Description</th>
+    <th align="center" bgcolor="aqua">Default value</th>
+  </tr>
+
+  <tr>
+    <td>name</td>
+    <td>Full qualified JMX ObjectName -- <em>Catalina:type=MBeanFactory</em>
+    </td>
+    <td></td>
+  </tr>
+
+  <tr>
+    <td>ref</td>
+    <td>JMX Connection reference
+    </td>
+    <td><code>jmx.server</code></td>
+  </tr>
+
+  <tr>
+    <td>echo</td>
+    <td>Echo command usage (access and result)
+    </td>
+    <td><code>false</code></td>
+  </tr>
+
+</table>
+</p>
+<p>
+Example to unregister remote mbean<br/>
+<source>
+    &lt;jmx:unregister
+        name="Catalina:type=MBeanFactory" 
+    /&gt;
+</source>
+</p>  
+<p>
+    <b>Warning</b>: A lot of tomcat mbeans can't be really unregister. <br/>
+    The Mbeans are not deregister from parent. Use <em>MBeanFacrory</em> <br/>
+    remove operation instead.
+</p>
+
+</section>
+
+<!-- condition ######################################################################### 
+-->
+
+<section name="JMXAccessorCondition:  express condition">
+<p>
+List of Attributes<br/>
+<table border="1" cellpadding="5">
+
+  <tr>
+    <th align="center" bgcolor="aqua">Attribute</th>
+    <th align="center" bgcolor="aqua">Description</th>
+    <th align="center" bgcolor="aqua">Default value</th>
+  </tr>
+
+ <tr>
+    <td>url</td>
+    <td>Set jmx connection url - <em>service:jmx:rmi:///jndi/rmi://localhost:8050/jmxrmi</em>
+    </td>
+    <td></td>
+  </tr>
+
+  <tr>
+    <td>host</td>
+    <td>Set the host, shortcut the very long url syntax.
+    </td>
+    <td><code>localhost</code></td>
+  </tr>
+
+  <tr>
+    <td>port</td>
+    <td>Set the remote connection port 
+    </td>
+    <td><code>8050</code></td>
+  </tr>
+
+  <tr>
+    <td>username</td>
+    <td>remote jmx connection user name.
+    </td>
+    <td></td>
+  </tr>
+
+  <tr>
+    <td>password</td>
+    <td>remote jmx connection password.
+    </td>
+    <td></td>
+  </tr>
+
+  <tr>
+    <td>ref</td>
+    <td>Name of the internal connection reference. With this attribute you can
+        configure more the one connection inside the same ant projekt.
+    </td>
+    <td><code>jmx.server</code></td>
+  </tr>
+
+  <tr>
+    <td>name</td>
+    <td>Full qualified JMX ObjectName -- <em>Catalina:type=Server</em>
+    </td>
+    <td></td>
+  </tr>
+
+  <tr>
+    <td>echo</td>
+    <td>Echo condition usage (access and result)
+    </td>
+    <td><code>false</code></td>
+  </tr>
+
+  <tr>
+    <td>if</td>
+    <td>Only execute if a property of the given name <b>exists</b> in the current project.
+    </td>
+    <td></td>
+  </tr>
+
+  <tr>
+    <td>unless</td>
+    <td>Only execute if a property of the given name <b>not exists</b> in the current project.
+    </td>
+    <td></td>
+  </tr>
+
+  <tr>
+    <td>value (requiered)</td>
+    <td>Second arg for operation
+    </td>
+    <td></td>
+  </tr>
+
+  <tr>
+    <td>type</td>
+    <td>Value type to express operation (support <em>long</em> and <em>double</em>)
+    </td>
+    <td><code>long</code></td>
+  </tr>
+
+  <tr>
+    <td>operation</td>
+    <td> express one 
+    <ul>
+    <li>==  equals</li>
+    <li>!=  not equals</li>
+    <li>&gt; greater than (&amp;gt;)</li>
+    <li>&gt;= greater than or equals (&amp;gt;=)</li>
+    <li>&lt; lesser than (&amp;lt;)</li>
+    <li>&lt;= lesser than or equals (&amp;lt;=)</li>
+    </ul>         
+    </td>
+    <td><code>==</code></td>
+  </tr>
+
+</table>
+</p>
+<p>
+Wait for server connection and that cluster backup node is accessable<br/>
+<source>
+      &lt;target name="wait"&gt;
+         &lt;waitfor maxwait="${maxwait}" maxwaitunit="second" timeoutproperty="server.timeout" &gt;
+            &lt;and&gt;
+                &lt;socket server="${server.name}" port="${server.port}"/&gt;
+                &lt;http url="${url}"/&gt;
+                &lt;jmx:condition
+                    operation="==" 
+                    host="localhost" 
+                    port="9014"
+                    username="controlRole"
+                    password="tomcat"
+                    name="Catalina:type=IDataSender,host=localhost,senderAddress=192.168.111.1,senderPort=9025"
+                    attribute="connected"
+                    value="true"
+                /&gt;
+            &lt;/and&gt;
+        &lt;/waitfor&gt;
+        &lt;fail if="server.timeout" message="Server ${url} don't answer inside ${maxwait} sec" /&gt;
+        &lt;echo message="Server ${url} alive" /&gt;
+    &lt;/target&gt;
+</source>
+</p>  
+
+</section>
+
+<!-- Equals ######################################################################### 
+-->
+
+<section name="JMXAccessorEqualsCondition:  equals Mbean ant condition">
+<p>
+List of Attributes<br/>
+<table border="1" cellpadding="5">
+
+  <tr>
+    <th align="center" bgcolor="aqua">Attribute</th>
+    <th align="center" bgcolor="aqua">Description</th>
+    <th align="center" bgcolor="aqua">Default value</th>
+  </tr>
+
+ <tr>
+    <td>url</td>
+    <td>Set jmx connection url - <em>service:jmx:rmi:///jndi/rmi://localhost:8050/jmxrmi</em>
+    </td>
+    <td></td>
+  </tr>
+
+  <tr>
+    <td>host</td>
+    <td>Set the host, shortcut the very long url syntax.
+    </td>
+    <td><code>localhost</code></td>
+  </tr>
+
+  <tr>
+    <td>port</td>
+    <td>Set the remote connection port 
+    </td>
+    <td><code>8050</code></td>
+  </tr>
+
+  <tr>
+    <td>username</td>
+    <td>remote jmx connection user name.
+    </td>
+    <td></td>
+  </tr>
+
+  <tr>
+    <td>password</td>
+    <td>remote jmx connection password.
+    </td>
+    <td></td>
+  </tr>
+
+  <tr>
+    <td>ref</td>
+    <td>Name of the internal connection referenz. With this attribute you can
+        configure more the one connection inside the same ant projekt.
+    </td>
+    <td><code>jmx.server</code></td>
+  </tr>
+
+  <tr>
+    <td>name</td>
+    <td>Full qualified JMX ObjectName -- <em>Catalina:type=Server</em>
+    </td>
+    <td></td>
+  </tr>
+
+
+  <tr>
+    <td>echo</td>
+    <td>Echo condition usage (access and result)
+    </td>
+    <td><code>false</code></td>
+  </tr>
+
+</table>
+</p>
+<p>
+Wait for server connection and that cluster backup node is accessable<br/>
+<source>
+      &lt;target name="wait"&gt;
+         &lt;waitfor maxwait="${maxwait}" maxwaitunit="second" timeoutproperty="server.timeout" &gt;
+            &lt;and&gt;
+                &lt;socket server="${server.name}" port="${server.port}"/&gt;
+                &lt;http url="${url}"/&gt;
+                &lt;jmx:equals 
+                    host="localhost" 
+                    port="9014"
+                    username="controlRole"
+                    password="tomcat"
+                    name="Catalina:type=IDataSender,host=localhost,senderAddress=192.168.111.1,senderPort=9025"
+                    attribute="connected"
+                    value="true"
+                /&gt;
+            &lt;/and&gt;
+        &lt;/waitfor&gt;
+        &lt;fail if="server.timeout" message="Server ${url} don't answer inside ${maxwait} sec" /&gt;
+        &lt;echo message="Server ${url} alive" /&gt;
+    &lt;/target&gt;
+</source>
+</p>  
+
+</section>
+
+</body>
+</document>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/project.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/project.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/project.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,71 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<project name="Apache Tomcat Documentation - Top Level Directory"
+        href="http://tomcat.apache.org/">
+
+    <title>The Apache Tomcat 5.5 Servlet/JSP Container</title>
+
+    <logo href="/images/tomcat.gif">
+      The Apache Tomcat Servlet/JSP Container
+    </logo>
+
+
+    <body>
+
+    <menu name="Links">
+        <item name="Docs Home"             href="index.html"/>
+        <item name="FAQ"                   href="http://tomcat.apache.org/faq" />
+    </menu>
+
+    <menu name="User Guide">
+        <item name="1) Introduction"        href="introduction.html"/>
+        <item name="2) Setup"               href="setup.html"/>
+        <item name="3) First webapp"        href="appdev/index.html"/>
+        <item name="4) Deployer"            href="deployer-howto.html"/>
+        <item name="5) Manager"             href="manager-howto.html"/>
+        <item name="6) Realms and AAA"      href="realm-howto.html"/>
+        <item name="7) Security Manager"
+              href="security-manager-howto.html"/>
+        <item name="8) JNDI Resources"      href="jndi-resources-howto.html"/>
+        <item name="9) JDBC DataSources"
+              href="jndi-datasource-examples-howto.html"/>
+        <item name="10) Classloading"       href="class-loader-howto.html"/>
+        <item name="11) JSPs"               href="jasper-howto.html"/>
+        <item name="12) SSL"                href="ssl-howto.html"/>
+        <item name="13) SSI"                href="ssi-howto.html"/>
+        <item name="14) CGI"                href="cgi-howto.html"/>
+        <item name="15) Proxy Support"      href="proxy-howto.html"/>
+        <item name="16) MBean Descriptor"
+              href="mbeans-descriptor-howto.html"/>
+        <item name="17) Default Servlet"    href="default-servlet.html"/>
+        <item name="18) Clustering"         href="cluster-howto.html"/>
+        <item name="19) Load Balancer"      href="balancer-howto.html"/>
+        <item name="20) Connectors"         href="connectors.html"/>
+        <item name="21) Monitoring and Management"         
+              href="monitoring.html"/>
+        <item name="22) Logging"            href="logging.html"/>
+        <item name="23) APR"                href="apr.html"/>
+    </menu>
+
+    <menu name="Reference">
+        <item name="Release Notes"         href="RELEASE-NOTES.txt"/>
+        <item name="Apache Tomcat Configuration"  href="config/index.html"/>
+        <item name="JK 1.2 Documentation"      
+              href="http://tomcat.apache.org/connectors-doc/"/>
+        <item name="Servlet API Javadocs"  href="servletapi/index.html"/>
+        <item name="JSP API Javadocs"      href="jspapi/index.html"/>
+    </menu>
+
+    <menu name="Apache Tomcat Development">
+        <item name="Building"              href="building.html"/>
+        <item name="Changelog"             href="changelog.html"/>
+        <item name="Status"                href="status.html"/>
+        <item name="Developers"            href="developers.html"/>
+        <item name="Functional Specs."     href="catalina/funcspecs/index.html"/>
+        <item name="Apache Tomcat Javadocs"       href="catalina/docs/api/index.html"/>
+        <item name="Apache Jasper Javadocs"       href="jasper/docs/api/index.html"/>
+        <item name="Architecture"          href="architecture/index.html" />
+    </menu>
+
+    </body>
+
+</project>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/proxy-howto.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/proxy-howto.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/proxy-howto.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,136 @@
+<?xml version="1.0"?>
+<!DOCTYPE document [
+  <!ENTITY project SYSTEM "project.xml">
+]>
+<document url="proxy-howto.html">
+
+    &project;
+
+    <properties>
+        <author email="craigmcc at apache.org">Craig R. McClanahan</author>
+        <title>Proxy Support HOW-TO</title>
+    </properties>
+
+<body>
+
+
+<section name="Introduction">
+
+<p>Using standard configurations of Tomcat, web applications can ask for
+the server name and port number to which the request was directed for
+processing.  When Tomcat is running standalone with the
+<a href="config/coyote.html">Coyote HTTP/1.1 Connector</a>, it will generally
+report the server name specified in the request, and the port number on
+which the <strong>Connector</strong> is listening.  The servlet API
+calls of interest, for this purpose, are:</p>
+<ul>
+<li><code>ServletRequest.getServerName()</code>: Returns the host name of the server to which the request was sent.</li>
+<li><code>ServletRequest.getServerPort()</code>: Returns the host name of the server to which the request was sent.</li>
+<li><code>ServletRequest.getLocalName()</code>: Returns the host name of the Internet Protocol (IP) interface on which the request was received.</li>
+<li><code>ServletRequest.getLocalPort()</code>:  Returns the Internet Protocol (IP) port number of the interface on which the request was received.</li>
+</ul>
+
+<p>When you are running behind a proxy server (or a web server that is
+configured to behave like a proxy server), you will sometimes prefer to
+manage the values returned by these calls.  In particular, you will
+generally want the port number to reflect that specified in the original
+request, not the one on which the <strong>Connector</strong> itself is
+listening.  You can use the <code>proxyName</code> and <code>proxyPort</code>
+attributes on the <code>&lt;Connector&gt;</code> element to configure
+these values.</p>
+
+<p>Proxy support can take many forms.  The following sections describe
+proxy configurations for several common cases.</p>
+
+</section>
+
+<section name="Apache 1.3 Proxy Support">
+
+<p>Apache 1.3 supports an optional module (<code>mod_proxy</code>) that
+configures the web server to act as a proxy server.  This can be used to
+forward requests for a particular web application to a Tomcat 5 instance,
+without having to configure a web connector such as <code>mod_jk</code>.
+To accomplish this, you need to perform the following tasks:</p>
+<ol>
+<li>Configure your copy of Apache so that it includes the
+    <code>mod_proxy</code> module.  If you are building from source,
+    the easiest way to do this is to include the
+    <code>--enable-module=proxy</code> directive on the
+    <code>./configure</code> command line.</li>
+<li>If not already added for you, make sure that you are loading the
+    <code>mod_proxy</code> module at Apache startup time, by using the
+    following directives in your <code>httpd.conf</code> file:
+<source>
+LoadModule proxy_module  {path-to-modules}/mod_proxy.so
+AddModule  mod_proxy.c
+</source></li>
+<li>Include two directives in your <code>httpd.conf</code> file for
+    each web application that you wish to forward to Tomcat 5.  For
+    example, to forward an application at context path <code>/myapp</code>:
+<source>
+ProxyPass         /myapp  http://localhost:8081/myapp
+ProxyPassReverse  /myapp  http://localhost:8081/myapp
+</source>
+    which tells Apache to forward URLs of the form
+    <code>http://localhost/myapp/*</code> to the Tomcat 5 connector
+    listening on port 8081.</li>
+<li>Configure your copy of Tomcat 5 to include a special
+    <code>&lt;Connector&gt;</code> element, with appropriate
+    proxy settings, for example:
+<source>
+&lt;Connector port="8081" ...
+              proxyName="www.mycompany.com"
+              proxyPort="80"/&gt;
+</source>
+    which will cause servlets inside this web application to think that
+    all proxied requests were directed to <code>www.mycompany.com</code>
+    on port 80.</li>
+<li>It is legal to omit the <code>proxyName</code> attribute from the
+    <code>&lt;Connector&gt;</code> element.  If you do so, the value
+    returned by <code>request.getServerName()</code> will by the host
+    name on which Tomcat is running.  In the example above, it would be
+    <code>localhost</code>.</li>
+<li>If you also have a <code>&lt;Connector&gt;</code> listening on port
+    8080 (nested within the same <a href="config/service.html">Service</a>
+    element), the requests to either port will share the same set of
+    virtual hosts and web applications.</li>
+<li>You might wish to use the IP filtering features of your operating
+    system to restrict connections to port 8081 (in this example) to
+    be allowed <strong>only</strong> from the server that is running
+    Apache.</li>
+<li>Alternatively, you can set up a series of web applications that are
+    only available via proxying, as follows:
+    <ul>
+    <li>Configure another <code>&lt;Service&gt;</code> that contains
+        only a <code>&lt;Connector&gt;</code> for the proxy port.</li>
+    <li>Configure appropriate <a href="config/engine.html">Engine</a>,
+        <a href="config/host.html">Host</a>, and
+        <a href="config/context.html">Context</a> elements for the virtual hosts
+        and web applications accessible via proxying.</li>
+    <li>Optionally, protect port 8081 with IP filters as described
+        earlier.</li>
+    </ul></li>
+<li>When requests are proxied by Apache, the web server will be recording
+    these requests in its access log.  Therefore, you will generally want to
+    disable any access logging performed by Tomcat itself.</li>
+</ol>
+
+<p>When requests are proxied in this manner, <strong>all</strong> requests
+for the configured web applications will be processed by Tomcat (including
+requests for static content).  You can improve performance by using the
+<code>mod_jk</code> web connector instead of <code>mod_proxy</code>. 
+<code>mod_jk</code> can be configured so that the web server serves static
+content that is not processed by filters or security constraints defined
+within the web application's deployment descriptor
+(<code>/WEB-INF/web.xml</code>).</p>
+
+</section>
+
+<section name="Apache 2.0 Proxy Support">
+The same instructions hold true as for 1.3. (Except in Apache 2.0,
+you may omit <code>AddModule  mod_proxy.c</code>)
+</section>
+
+</body>
+
+</document>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/realm-howto.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/realm-howto.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/realm-howto.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,1422 @@
+<?xml version="1.0"?>
+<!DOCTYPE document [
+  <!ENTITY project SYSTEM "project.xml">
+]>
+<document url="realm-howto.html">
+
+    &project;
+
+    <properties>
+        <author email="craigmcc at apache.org">Craig R. McClanahan</author>
+        <author email="yoavs at apache.org">Yoav Shapira</author>
+        <author email="arjaquith at mindspring.com">Andrew R. Jaquith</author>
+        <title>Realm Configuration HOW-TO</title>
+    </properties>
+
+<body>
+
+
+<section name="Table of Contents">
+
+<p>
+<a href="#Quick Start">Quick Start</a><br />
+<blockquote>
+<a href="#What is a Realm?">What is a Realm?</a><br />
+<a href="#Configuring a Realm">Configuring a Realm</a><br />
+</blockquote>
+<a href="#Common Features">Common Features</a><br />
+<blockquote>
+<a href="#Digested Passwords">Digested Passwords</a><br />
+<a href="#Example Application">Example Application</a><br />
+<a href="#Manager Application">Manager Application</a><br />
+<a href="#Realm Logging">Logging Within Realms</a><br />
+</blockquote>
+<a href="#Standard Realm Implementations">
+Standard Realm Implementations</a><br />
+<blockquote>
+<a href="#JDBCRealm">JDBCRealm</a><br />
+<a href="#DataSourceRealm">DataSourceRealm</a><br />
+<a href="#JNDIRealm">JNDIRealm</a><br />
+<a href="#MemoryRealm">MemoryRealm</a><br />
+<a href="#JAASRealm">JAASRealm</a><br />
+</blockquote>
+</p>
+
+</section>
+
+<section name="Quick Start">
+
+<p>This document describes how to configure Tomcat to support <em>container
+managed security</em>, by connecting to an existing "database" of usernames,
+passwords, and user roles.  You only need to care about this if you are using
+a web application that includes one or more
+<code>&lt;security-constraint&gt;</code> elements, and a
+<code>&lt;login-config&gt;</code> element defining how users are required
+to authenticate themselves.  If you are not utilizing these features, you can
+safely skip this document.</p>
+
+<p>For fundamental background information about container managed security,
+see the <a href="http://java.sun.com/products/servlet/download.html">Servlet
+Specification (Version 2.4)</a>, Section 12.</p>
+
+<p>For information about utilizing the <em>Single Sign On</em> feature of
+Tomcat 5 (allowing a user to authenticate themselves once across the entire
+set of web applications associated with a virtual host), see
+<a href="config/host.html#Single Sign On">here</a>.</p>
+
+</section>
+
+
+<section name="Overview">
+
+
+<subsection name="What is a Realm?">
+
+<p>A <strong>Realm</strong> is a "database" of usernames and passwords that
+identify valid users of a web application (or set of web applications), plus
+an enumeration of the list of <em>roles</em> associated with each valid user.
+You can think of roles as similar to <em>groups</em> in Unix-like operating
+systems, because access to specific web application resources is granted to
+all users possessing a particular role (rather than enumerating the list of
+associated usernames).  A particular user can have any number of roles
+associated with their username.</p>
+
+<p>Although the Servlet Specification describes a portable mechanism for
+applications to <em>declare</em> their security requirements (in the
+<code>web.xml</code> deployment descriptor), there is no portable API
+defining the interface between a servlet container and the associated user
+and role information.  In many cases, however, it is desireable to "connect"
+a servlet container to some existing authentication database or mechanism
+that already exists in the production environment.  Therefore, Tomcat 5
+defines a Java interface (<code>org.apache.catalina.Realm</code>) that
+can be implemented by "plug in" components to establish this connection.
+Five standard plug-ins are provided, supporting connections to various
+sources of authentication information:</p>
+<ul>
+<li><a href="#JDBCRealm">JDBCRealm</a> - Accesses authentication information
+    stored in a relational database, accessed via a JDBC driver.</li>
+<li><a href="#DataSourceRealm">DataSourceRealm</a> - Accesses authentication
+    information stored in a relational database, accessed via a named JNDI
+    JDBC DataSource.</li>
+<li><a href="#JNDIRealm">JNDIRealm</a> - Accesses authentication information
+    stored in an LDAP based directory server, accessed via a JNDI provider.
+    </li>
+<li><a href="#MemoryRealm">MemoryRealm</a> - Accesses authentication
+    information stored in an in-memory object collection, which is initialized
+    from an XML document (<code>conf/tomcat-users.xml</code>).</li>
+<li><a href="#JAASRealm">JAASRealm</a> - Accesses authentication information
+    through the Java Authentication &amp; Authorization Service (JAAS)
+    framework.</li>
+</ul>
+
+<p>It is also possible to write your own <code>Realm</code> implementation,
+and integrate it with Tomcat 5.  To do so, you need to:
+<ul>
+  <li>Implement <code>org.apache.catalina.Realm</code>,</li>
+  <li>Place your compiled realm in $CATALINA_HOME/server/lib,</li>
+  <li>Declare your realm as described in the "Configuring a Realm" section below,</li>
+  <li>Declare your realm to the <a href="mbeans-descriptor-howto.html">MBeans Descriptor</a>.</li>
+</ul>
+</p>
+
+</subsection>
+
+
+<subsection name="Configuring a Realm">
+
+<p>Before getting into the details of the standard Realm implementations, it is
+important to understand, in general terms, how a Realm is configured.  In
+general, you will be adding an XML element to your <code>conf/server.xml</code>
+configuration file, that looks something like this:</p>
+
+<source>
+&lt;Realm className="... class name for this implementation"
+       ... other attributes for this implementation .../&gt;
+</source>
+
+<p>The <code>&lt;Realm&gt;</code> element can be nested inside any one of 
+of the following <code>Container</code> elements.  The location of the
+Realm element has a direct impact on the "scope" of that Realm
+(i.e. which web applications will share the same authentication information):
+</p>
+<ul>
+<li><em>Inside an &lt;Engine&gt; element</em> - This Realm will be shared
+    across ALL web applications on ALL virtual hosts, UNLESS it is overridden
+    by a Realm element nested inside a subordinate <code>&lt;Host&gt;</code>
+    or <code>&lt;Context&gt;</code> element.</li>
+<li><em>Inside a &lt;Host&gt; element</em> - This Realm will be shared across
+    ALL web applications for THIS virtual host, UNLESS it is overridden
+    by a Realm element nested inside a subordinate <code>&lt;Context&gt;</code>
+    element.</li>
+<li><em>Inside a &lt;Context&gt; element</em> - This Realm will be used ONLY
+    for THIS web application.</li>
+</ul>
+
+
+</subsection>
+
+
+</section>
+
+
+<section name="Common Features">
+
+
+<subsection name="Digested Passwords">
+
+<p>For each of the standard <code>Realm</code> implementations, the
+user's password (by default) is stored in clear text.  In many
+environments, this is undesireable because casual observers of the
+authentication data can collect enough information to log on
+successfully, and impersonate other users.  To avoid this problem, the
+standard implementations support the concept of <em>digesting</em>
+user passwords.  This allows the stored version of the passwords to be
+encoded (in a form that is not easily reversible), but that the
+<code>Realm</code> implementation can still utilize for
+authentication.</p>
+
+<p>When a standard realm authenticates by retrieving the stored
+password and comparing it with the value presented by the user, you
+can select digested passwords by specifying the <code>digest</code>
+attribute on your <code>&lt;Realm&gt;</code> element.  The value for
+this attribute must be one of the digest algorithms supported by the
+<code>java.security.MessageDigest</code> class (SHA, MD2, or MD5).
+When you select this option, the contents of the password that is
+stored in the <code>Realm</code> must be the cleartext version of the
+password, as digested by the specified algorithm.</p>
+
+<p>When the <code>authenticate()</code> method of the Realm is called, the
+(cleartext) password specified by the user is itself digested by the same
+algorithm, and the result is compared with the value returned by the
+<code>Realm</code>.  An equal match implies that the cleartext version of the
+original password is the same as the one presented by the user, so that this
+user should be authorized.</p>
+
+<p>To calculate the digested value of a cleartext password, two convenience
+techniques are supported:</p>
+<ul>
+<li>If you are writing an application that needs to calculate digested
+    passwords dynamically, call the static <code>Digest()</code> method of the
+    <code>org.apache.catalina.realm.RealmBase</code> class, passing the
+    cleartext password and the digest algorithm name as arguments.  This
+    method will return the digested password.</li>
+<li>If you want to execute a command line utility to calculate the digested
+    password, simply execute
+<source>
+java org.apache.catalina.realm.RealmBase \
+    -a {algorithm} {cleartext-password}
+</source>
+    and the digested version of this cleartext password will be returned to
+    standard output.</li>
+</ul>
+
+<p>If using digested passwords with DIGEST authentication, the cleartext used
+   to generate the digest is different. In the examples above
+   <code>{cleartext-password}</code> must be replaced with 
+   <code>{username}:{realm}:{cleartext-password}</code>. For example, in a
+   development environment this might take the form
+   <code>testUser:localhost:8080:testPassword</code>.</p>
+
+<p>To use either of the above techniques, the
+<code>$CATALINA_HOME/server/lib/catalina.jar</code> file will need to be
+on your class path to make the <code>RealmBase</code> class available.  In 
+addition, you will need the JMX jar and the commons-logging jar (either 
+commons-logging-api.jar or commons-logging.jar).  Both of these are included
+with the Tomcat distribution.
+</p>
+
+<p>Non-ASCII usernames and/or passwords are supported using
+<source>java org.apache.catalina.realm.RealmBase \
+    -a {algorithm} -e {encoding} {input}
+</source>
+but care is required to ensure that the non-ASCII input is
+correctly passed to the digester.
+The digester returns <code>{input}:{digest}</code>. If the input appears
+corrupted in the return, the digest will be invalid.</p>
+
+</subsection>
+
+
+
+<subsection name="Example Application">
+
+<p>The example application shipped with Tomcat 5 includes an area that is
+protected by a security constraint, utilizing form-based login.  To access it,
+point your browser at
+<a href="http://localhost:8080/jsp-examples/security/protected/">http://localhost:8080/jsp-examples/security/protected/</a>
+and log on with one of the usernames and passwords described for the default
+<a href="#MemoryRealm">MemoryRealm</a>.</p>
+
+</subsection>
+
+
+<subsection name="Manager Application">
+
+<p>If you wish to use the <a href="manager-howto.html">Manager Application</a>
+to deploy and undeploy applications in a running Tomcat 5 installation, you
+MUST add the "manager" role to at least one username in your selected Realm
+implementation.  This is because the manager web application itself uses a
+security constraint that requires role "manager" to access ANY request URI
+within that application.</p>
+
+<p>For security reasons, no username in the default Realm (i.e. using
+<code>conf/tomcat-users.xml</code> is assigned the "manager" role.  Therfore,
+no one will be able to utilize the features of this application until the
+Tomcat administrator specifically assigns this role to one or more users.</p>
+
+</subsection>
+
+<subsection name="Realm Logging">
+
+<p>Debugging and exception messages logged by a <code>Realm</code> will
+   be recorded by the logging configuration associated with the container
+   for the realm: its surrounding <a href="config/context.html">Context</a>,
+   <a href="config/host.html">Host</a>, or
+   <a href="config/engine.html">Engine</a>.</p>
+
+</subsection>
+
+</section>
+
+
+<section name="Standard Realm Implementations">
+
+<subsection name="JDBCRealm">
+
+<h3>Introduction</h3>
+
+<p><strong>JDBCRealm</strong> is an implementation of the Tomcat 5
+<code>Realm</code> interface that looks up users in a relational database
+accessed via a JDBC driver.  There is substantial configuration flexibility
+that lets you adapt to existing table and column names, as long as your
+database structure conforms to the following requirements:</p>
+<ul>
+<li>There must be a table, referenced below as the <em>users</em> table,
+    that contains one row for every valid user that this <code>Realm</code>
+    should recognize.</li>
+<li>The <em>users</em> table must contain at least two columns (it may
+    contain more if your existing applications required it):
+    <ul>
+    <li>Username to be recognized by Tomcat when the user logs in.</li>
+    <li>Password to be recognized by Tomcat when the user logs in.
+        This value may in cleartext or digested - see below for more
+        information.</li>
+    </ul></li>
+<li>There must be a table, referenced below as the <em>user roles</em> table,
+    that contains one row for every valid role that is assigned to a
+    particular user.  It is legal for a user to have zero, one, or more than
+    one valid role.</li>
+<li>The <em>user roles</em> table must contain at least two columns (it may
+    contain more if your existing applications required it):
+    <ul>
+    <li>Username to be recognized by Tomcat (same value as is specified
+        in the <em>users</em> table).</li>
+    <li>Role name of a valid role associated with this user.</li>
+    </ul></li>
+</ul>
+
+<h3>Quick Start</h3>
+
+<p>To set up Tomcat to use JDBCRealm, you will need to follow these steps:</p>
+<ol>
+<li>If you have not yet done so, create tables and columns in your database
+    that conform to the requirements described above.</li>
+<li>Configure a database username and password for use by Tomcat, that has
+    at least read only access to the tables described above.  (Tomcat will
+    never attempt to write to these tables.)</li>
+<li>Place a copy of the JDBC driver you will be using inside the
+    <code>$CATALINA_HOME/server/lib</code> directory (if you do not need it
+    visible to web applications) or <code>$CATALINA_HOME/common/lib</code>
+    (if it will be used both by Tomcat 5 <em>and</em> by your apps).
+    Note that <strong>only</strong> JAR files are recognized!</li>
+<li>Set up a <code>&lt;Realm&gt;</code> element, as described below, in your
+    <code>$CATALINA_HOME/conf/server.xml</code> file.</li>
+<li>Restart Tomcat 5 if it is already running.</li>
+</ol>
+
+<h3>Realm Element Attributes</h3>
+
+<p>To configure JDBCRealm, you will create a <code>&lt;Realm&gt;</code>
+element and nest it in your <code>$CATALINA_HOME/conf/server.xml</code> file,
+as described <a href="#Configuring a Realm">above</a>.  The following
+attributes are supported by this implementation:</p>
+
+<attributes>
+
+  <attribute name="className" required="true">
+    <p>The fully qualified Java class name of this Realm implementation.
+    You <strong>MUST</strong> specify the value
+    "<code>org.apache.catalina.realm.JDBCRealm</code>" here.</p>
+  </attribute>
+
+  <attribute name="connectionName" required="true">
+    <p>The database username used to establish a JDBC connection.</p>
+  </attribute>
+
+  <attribute name="connectionPassword" required="true">
+    <p>The database password used to establish a JDBC connection.</p>
+  </attribute>
+
+  <attribute name="connectionURL" required="true">
+    <p>The database URL used to establish a JDBC connection.</p>
+  </attribute>
+
+  <attribute name="digest" required="false">
+    <p>The digest algorithm used to store passwords in non-plaintext formats.
+    Valid values are those accepted for the algorithm name by the
+    <code>java.security.MessageDigest</code> class.  See
+    <a href="#Digested Passwords">Digested Passwords</a> for more
+    information.  If not specified, passwords are stored in clear text.</p>
+  </attribute>
+
+  <attribute name="driverName" required="true">
+    <p>The fully qualified Java class name of the JDBC driver to be used.
+    Consult the documentation for your JDBC driver for the appropriate
+    value.</p>
+  </attribute>
+
+  <attribute name="roleNameCol" required="true">
+    <p>The name of the column, in the <em>user roles</em> table, that
+    contains the name of a role assigned to this user.</p>
+  </attribute>
+
+  <attribute name="userCredCol" required="true">
+    <p>The name of the column, in the <em>users</em> table, that contains
+    the password for this user (either in clear text, or digested if the
+    <code>digest</code> attribute is set).</p>
+  </attribute>
+
+  <attribute name="userNameCol" required="true">
+    <p>The name of the column, in the <em>users</em> and <em>user roles</em>
+    tables, that contains the username of this user.</p>
+  </attribute>
+
+  <attribute name="userRoleTable" required="true">
+    <p>The name of the table that contains one row for each <em>role</em>
+    assigned to a particular <em>username</em>.  This table must include at
+    least the columns named by the <code>userNameCol</code> and
+    <code>roleNameCol</code> attributes.</p>
+  </attribute>
+
+  <attribute name="userTable" required="true">
+    <p>The name of the table that contains one row for each <em>username</em>
+    to be recognized by Tomcat.  This table must include at least the columns
+    named by the <code>userNameCol</code> and <code>userCredCol</code>
+    attributes.</p>
+  </attribute>
+
+</attributes>
+
+<h3>Example</h3>
+
+<p>An example SQL script to create the needed tables might look something
+like this (adapt the syntax as required for your particular database):</p>
+<source>
+create table users (
+  user_name         varchar(15) not null primary key,
+  user_pass         varchar(15) not null
+);
+
+create table user_roles (
+  user_name         varchar(15) not null,
+  role_name         varchar(15) not null,
+  primary key (user_name, role_name)
+);
+</source>
+
+<p>Example <code>Realm</code> elements are included (commented out) in the
+default <code>$CATALINA_HOME/conf/server.xml</code> file.  Here's an example
+for using a MySQL database called "authority", configured with the tables
+described above, and accessed with username "dbuser" and password "dbpass":</p>
+<source>
+&lt;Realm className="org.apache.catalina.realm.JDBCRealm" debug="99"
+      driverName="org.gjt.mm.mysql.Driver"
+   connectionURL="jdbc:mysql://localhost/authority?user=dbuser&amp;amp;password=dbpass"
+       userTable="users" userNameCol="user_name" userCredCol="user_pass"
+   userRoleTable="user_roles" roleNameCol="role_name"/&gt;
+</source>
+
+<h3>Additional Notes</h3>
+
+<p>JDBCRealm operates according to the following rules:</p>
+<ul>
+<li>When a user attempts to access a protected resource for the first time,
+    Tomcat 5 will call the <code>authenticate()</code> method of this
+    <code>Realm</code>.  Thus, any changes you have made to the database
+    directly (new users, changed passwords or roles, etc.) will be immediately
+    reflected.</li>
+<li>Once a user has been authenticated, the user (and his or her associated
+    roles) are cached within Tomcat for the duration of the user's login.
+    (For FORM-based authentication, that means until the session times out or
+    is invalidated; for BASIC authentication, that means until the user
+    closes their browser).  The cached user is <strong>not</strong> saved and
+    restored across sessions serialisations. Any changes to the database
+    information for an already authenticated user will <strong>not</strong> be
+    reflected until the next time that user logs on again.</li>
+<li>Administering the information in the <em>users</em> and <em>user roles</em>
+    table is the responsibility of your own applications.  Tomcat does not
+    provide any built-in capabilities to maintain users and roles.</li>
+</ul>
+
+</subsection>
+
+
+<subsection name="DataSourceRealm">
+
+<h3>Introduction</h3>
+
+<p><strong>DataSourceRealm</strong> is an implementation of the Tomcat 5
+<code>Realm</code> interface that looks up users in a relational database
+accessed via a JNDI named JDBC DataSource.  There is substantial configuration
+flexibility that lets you adapt to existing table and column names, as long
+as your database structure conforms to the following requirements:</p>
+<ul>
+<li>There must be a table, referenced below as the <em>users</em> table,
+    that contains one row for every valid user that this <code>Realm</code>
+    should recognize.</li>
+<li>The <em>users</em> table must contain at least two columns (it may
+    contain more if your existing applications required it):
+    <ul>
+    <li>Username to be recognized by Tomcat when the user logs in.</li>
+    <li>Password to be recognized by Tomcat when the user logs in.
+        This value may in cleartext or digested - see below for more
+        information.</li>
+    </ul></li>    
+<li>There must be a table, referenced below as the <em>user roles</em> table,
+    that contains one row for every valid role that is assigned to a
+    particular user.  It is legal for a user to have zero, one, or more than
+    one valid role.</li>
+<li>The <em>user roles</em> table must contain at least two columns (it may
+    contain more if your existing applications required it):
+    <ul>
+    <li>Username to be recognized by Tomcat (same value as is specified
+        in the <em>users</em> table).</li>
+    <li>Role name of a valid role associated with this user.</li>
+    </ul></li>
+</ul>
+
+<h3>Quick Start</h3>
+                  
+<p>To set up Tomcat to use DataSourceRealm, you will need to follow these steps:</p>
+<ol>              
+<li>If you have not yet done so, create tables and columns in your database
+    that conform to the requirements described above.</li>
+<li>Configure a database username and password for use by Tomcat, that has
+    at least read only access to the tables described above.  (Tomcat will
+    never attempt to write to these tables.)</li>
+<li>Configure a JNDI named JDBC DataSource for your database.  Refer to the
+    <a href="jndi-datasource-examples-howto.html">JNDI DataSource Example HOW-TO</a>
+    for information on how to configure a JNDI named JDBC DataSource.</li>
+<li>Set up a <code>&lt;Realm&gt;</code> element, as described below, in your
+    <code>$CATALINA_HOME/conf/server.xml</code> file.</li>
+<li>Restart Tomcat 5 if it is already running.</li>
+</ol>
+
+<h3>Realm Element Attributes</h3>
+
+<p>To configure DataSourceRealm, you will create a <code>&lt;Realm&gt;</code>
+element and nest it in your <code>$CATALINA_HOME/conf/server.xml</code> file,
+as described <a href="#Configuring a Realm">above</a>.  The following
+attributes are supported by this implementation:</p>
+
+<attributes>
+
+  <attribute name="className" required="true">
+    <p>The fully qualified Java class name of this Realm implementation.
+    You <strong>MUST</strong> specify the value
+    "<code>org.apache.catalina.realm.DataSourceRealm</code>" here.</p>
+  </attribute>
+
+  <attribute name="dataSourceName" required="true">
+    <p>The JNDI named JDBC DataSource for your database. If the DataSource is
+    local to the context, the name is relative to <code>java:/comp/env</code>,
+    and otherwise the name should match the name used to define the global
+    DataSource.</p>
+  </attribute>
+
+  <attribute name="digest" required="false">
+    <p>The digest algorithm used to store passwords in non-plaintext formats.
+    Valid values are those accepted for the algorithm name by the
+    <code>java.security.MessageDigest</code> class.  See
+    <a href="#Digested Passwords">Digested Passwords</a> for more
+    information.  If not specified, passwords are stored in clear text.</p>
+  </attribute>
+    
+  <attribute name="localDataSource" required="false">
+    <p>When the realm is nested inside a Context element, this allows the 
+    realm to use a DataSource defined for the Context rather than a global
+    DataSource.  If not specified, the default is <code>false</code>: use a 
+    global DataSource.</p>
+  </attribute>
+    
+  <attribute name="roleNameCol" required="true">
+    <p>The name of the column, in the <em>user roles</em> table, that
+    contains the name of a role assigned to this user.</p>
+  </attribute>
+    
+  <attribute name="userCredCol" required="true">
+    <p>The name of the column, in the <em>users</em> table, that contains
+    the password for this user (either in clear text, or digested if the
+    <code>digest</code> attribute is set).</p>
+  </attribute>
+    
+  <attribute name="userNameCol" required="true">
+    <p>The name of the column, in the <em>users</em> and <em>user roles</em>
+    tables, that contains the username of this user.</p>
+  </attribute>
+
+  <attribute name="userRoleTable" required="true">
+    <p>The name of the table that contains one row for each <em>role</em>
+    assigned to a particular <em>username</em>.  This table must include at
+    least the columns named by the <code>userNameCol</code> and
+    <code>roleNameCol</code> attributes.</p>
+  </attribute>
+
+  <attribute name="userTable" required="true">
+    <p>The name of the table that contains one row for each <em>username</em>
+    to be recognized by Tomcat.  This table must include at least the columns
+    named by the <code>userNameCol</code> and <code>userCredCol</code>
+    attributes.</p>
+  </attribute>
+
+</attributes>
+
+<h3>Example</h3>
+
+<p>An example SQL script to create the needed tables might look something
+like this (adapt the syntax as required for your particular database):</p>
+<source>
+create table users (
+  user_name         varchar(15) not null primary key,
+  user_pass         varchar(15) not null
+);
+
+create table user_roles (
+  user_name         varchar(15) not null,
+  role_name         varchar(15) not null,
+  primary key (user_name, role_name)
+);
+</source>
+
+<p>Here is an example for using a MySQL database called "authority", configured
+with the tables described above, and accessed with the JNDI JDBC DataSource with
+name "java:/comp/env/jdbc/authority".</p>
+<source>
+&lt;Realm className="org.apache.catalina.realm.DataSourceRealm" debug="99"
+   dataSourceName="jdbc/authority"
+   userTable="users" userNameCol="user_name" userCredCol="user_pass"
+   userRoleTable="user_roles" roleNameCol="role_name"/&gt;
+</source>
+
+<h3>Additional Notes</h3>
+
+<p>DataSourceRealm operates according to the following rules:</p>
+<ul>
+<li>When a user attempts to access a protected resource for the first time,
+    Tomcat 5 will call the <code>authenticate()</code> method of this
+    <code>Realm</code>.  Thus, any changes you have made to the database
+    directly (new users, changed passwords or roles, etc.) will be immediately
+    reflected.</li>
+<li>Once a user has been authenticated, the user (and his or her associated
+    roles) are cached within Tomcat for the duration of the user's login.
+    (For FORM-based authentication, that means until the session times out or
+    is invalidated; for BASIC authentication, that means until the user
+    closes their browser).  The cached user is <strong>not</strong> saved and
+    restored across sessions serialisations. Any changes to the database
+    information for an already authenticated user will <strong>not</strong> be
+    reflected until the next time that user logs on again.</li>
+<li>Administering the information in the <em>users</em> and <em>user roles</em>
+    table is the responsibility of your own applications.  Tomcat does not
+    provide any built-in capabilities to maintain users and roles.</li>
+</ul>
+
+</subsection>
+
+
+<subsection name="JNDIRealm">
+
+<h3>Introduction</h3>
+
+<p><strong>JNDIRealm</strong> is an implementation of the Tomcat 5
+<code>Realm</code> interface that looks up users in an LDAP directory
+server accessed by a JNDI provider (typically, the standard LDAP
+provider that is available with the JNDI API classes). The realm
+supports a variety of approaches to using a directory for
+authentication.</p>
+
+<h4>Connecting to the directory</h4>
+
+<p>The realm's connection to the directory is defined by the
+<strong>connectionURL</strong> configuration attribute. This is a URL
+whose format is defined by the JNDI provider. It is usually an LDAP
+URL that specifies the domain name of the directory server to connect
+to, and optionally the port number and distinguished name (DN) of the
+required root naming context.</p>
+
+<p>If you have more than one provider you can configure an
+<strong>alternateURL</strong>.  If a socket connection can not be
+made to the provider at the <strong>connectionURL</strong> an
+attempt will be made to use the <strong>alternateURL</strong>.</p>
+
+<p>When making a connection in order to search the directory and
+retrieve user and role information, the realm authenticates itself to
+the directory with the username and password specified by the
+<strong>connectionName</strong> and
+<strong>connectionPassword</strong> properties. If these properties
+are not specified the connection is anonymous. This is sufficient in
+many cases.
+</p>
+
+
+<h4>Selecting the user's directory entry</h4>
+
+<p>Each user that can be authenticated must be represented in the
+directory by an individual entry that corresponds to an element in the
+initial <code>DirContext</code> defined by the
+<strong>connectionURL</strong> attribute. This user entry must have an
+attribute containing the username that is presented for
+authentication.</p>
+
+<p>Often the distinguished name of the user's entry contains the
+username presented for authentication but is otherwise the same for
+all users. In this case the <strong>userPattern</strong> attribute may
+be used to specify the DN, with "{0}" marking where
+the username should be substituted.</p>
+
+<p>Otherwise the realm must search the directory to find a unique entry
+containing the username. The following attributes configure this
+search:
+
+     <ul>
+     <li><strong>userBase</strong> - the entry that is the base of
+         the subtree containing users.  If not specified, the search
+         base is the top-level context.</li>
+
+     <li><strong>userSubtree</strong> - the search scope. Set to
+         <code>true</code> if you wish to search the entire subtree
+         rooted at the <strong>userBase</strong> entry. The default value
+         of <code>false</code> requests a single-level search
+         including only the top level.</li>
+
+     <li><strong>userSearch</strong> - pattern specifying the LDAP
+         search filter to use after substitution of the username.</li>
+
+    </ul>
+</p>
+
+
+<h4>Authenticating the user</h4>
+
+<ul>
+<li>
+<p><b>Bind mode</b></p>
+
+<p>By default the realm authenticates a user by binding to
+the directory with the DN of the entry for that user and the password
+presented by the user. If this simple bind succeeds the user is considered to
+be authenticated.</p>
+
+<p>For security reasons a directory may store a digest of the user's
+password rather than the clear text version (see <a href="#Digested
+Passwords">Digested Passwords</a> for more information). In that case,
+as part of the simple bind operation the directory automatically
+computes the correct digest of the plaintext password presented by the
+user before validating it against the stored value. In bind mode,
+therefore, the realm is not involved in digest processing. The
+<strong>digest</strong> attribute is not used, and will be ignored if
+set.</p>
+</li>
+
+<li>
+<p><b>Comparison mode</b></p>
+<p>Alternatively, the realm may retrieve the stored
+password from the directory and compare it explicitly with the value
+presented by the user. This mode is configured by setting the
+<strong>userPassword</strong> attribute to the name of a directory
+attribute in the user's entry that contains the password.</p>
+
+<p>Comparison mode has some disadvantages. First, the
+<strong>connectionName</strong> and
+<strong>connectionPassword</strong> attributes must be configured to
+allow the realm to read users' passwords in the directory. For
+security reasons this is generally undesirable; indeed many directory
+implementations will not allow even the directory manager to read
+these passwords. In addition, the realm must handle password digests
+itself, including variations in the algorithms used and ways of
+representing password hashes in the directory. However, the realm may
+sometimes need access to the stored password, for example to support
+HTTP Digest Access Authentication (RFC 2069). (Note that HTTP digest
+authentication is different from the storage of password digests in
+the repository for user information as discussed above).
+</p>
+</li>
+</ul>
+
+<h4>Assigning roles to the user</h4>
+
+<p>The directory realm supports two approaches to the representation
+of roles in the directory:</p>
+
+<ul>
+<li>
+<p><b>Roles as explicit directory entries</b></p>
+
+<p>Roles may be represented by explicit directory entries. A role
+entry is usually an LDAP group entry with one attribute
+containing the name of the role and another whose values are the
+distinguished names or usernames of the users in that role.  The
+following attributes configure a directory search to
+find the names of roles associated with the authenticated user:</p>
+
+<ul>
+<li><strong>roleBase</strong> - the base entry for the role search.
+    If not specified, the search base is the top-level directory
+    context.</li>
+
+<li><strong>roleSubtree</strong> - the search
+    scope. Set to <code>true</code> if you wish to search the entire
+    subtree rooted at the <code>roleBase</code> entry. The default
+    value of <code>false</code> requests a single-level search
+    including the top level only.</li>
+
+<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>
+
+<li><strong>roleName</strong> - the attribute in a role entry
+     containing the name of that role.</li>
+
+</ul>
+
+</li>
+</ul>
+
+<ul>
+<li>
+<p><b>Roles as an attribute of the user entry</b></p>
+
+<p>Role names may also be held as the values of an attribute in the
+user's directory entry. Use <strong>userRoleName</strong> to specify
+the name of this attribute.</p>
+
+</li>
+</ul>
+<p>A combination of both approaches to role representation may be used.</p>
+
+<h3>Quick Start</h3>
+
+<p>To set up Tomcat to use JNDIRealm, you will need to follow these steps:</p>
+<ol>
+<li>Make sure your directory server is configured with a schema that matches
+    the requirements listed above.</li>
+<li>If required, configure a username and password for use by Tomcat, that has
+    read only access to the information described above.  (Tomcat will
+    never attempt to modify this information.)</li>
+<li>Place a copy of the JNDI driver you will be using (typically
+    <code>ldap.jar</code> available with JNDI) inside the
+    <code>$CATALINA_HOME/server/lib</code> directory (if you do not need it
+    visible to web applications) or <code>$CATALINA_HOME/common/lib</code>
+    (if it will be used both by Tomcat 5 <em>and</em> by your apps).</li>
+<li>Set up a <code>&lt;Realm&gt;</code> element, as described below, in your
+    <code>$CATALINA_HOME/conf/server.xml</code> file.</li>
+<li>Restart Tomcat 5 if it is already running.</li>
+</ol>
+
+<h3>Realm Element Attributes</h3>
+
+<p>To configure JNDIRealm, you will create a <code>&lt;Realm&gt;</code>
+element and nest it in your <code>$CATALINA_HOME/conf/server.xml</code> file,
+as described <a href="#Configuring a Realm">above</a>.  The following
+attributes are supported by this implementation:</p>
+
+<attributes>
+  <attribute name="className" required="true">
+    <p>The fully qualified Java class name of this Realm implementation.
+    You <strong>MUST</strong> specify the value
+    "<code>org.apache.catalina.realm.JNDIRealm</code>" here.</p>
+  </attribute>
+
+
+      <attribute name="connectionName" required="false">
+        <p>The directory username to use when establishing a
+        connection to the directory for LDAP search operations. If not
+        specified an anonymous connection is made, which is often
+        sufficient unless you specify the <code>userPassword</code>
+        property.</p>
+      </attribute>
+
+      <attribute name="connectionPassword" required="false">
+        <p>The directory password to use when establishing a
+        connection to the directory for LDAP search operations. If not
+        specified an anonymous connection is made, which is often
+        sufficient unless you specify the <code>userPassword</code>
+        property.</p>
+      </attribute>
+
+      <attribute name="connectionURL" required="true">
+        <p>The connection URL to be passed to the JNDI driver when
+        establishing a connection to the directory.</p>
+      </attribute>
+
+      <attribute name="contextFactory" required="false">
+        <p>The fully qualified Java class name of the JNDI context
+        factory to be used for this connection.  By default, the standard
+        JNDI LDAP provider is used
+        (<code>com.sun.jndi.ldap.LdapCtxFactory</code>).</p>
+      </attribute>
+
+      <attribute name="digest" required="false">
+        <p>The digest algorithm to apply to the plaintext password offered
+        by the user before comparing it with the value retrieved from the
+        directory.  Valid values are those accepted for the algorithm name
+        by the <code>java.security.MessageDigest</code> class.  See <a
+        href="#Digested Passwords">Digested Passwords</a> for more
+        information. If not specified the plaintext password is assumed to
+        be retrieved. Not required unless <code>userPassword</code> is
+        specified</p>
+      </attribute>
+
+      <attribute name="roleBase" required="false">
+        <p>The base directory entry for performing role searches. If
+        not specified, the top level element in the directory context
+        will be used.</p>
+      </attribute>
+
+      <attribute name="roleName" required="false">
+        <p>The name of the attribute that contains role names in the
+        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
+        search does not take place, and roles are taken only from the
+        user's entry.</p>
+      </attribute>
+
+      <attribute name="roleSearch" required="false">
+        <p>The LDAP filter expression used for performing role
+        searches, following the syntax supported by the
+        <code>java.text.MessageFormat</code> class.  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>
+      </attribute>
+
+      <attribute name="roleSubtree" required="false">
+        <p>Set to <code>true</code> if you want to search the entire
+        subtree of the element specified by the <code>roleBase</code>
+        property for role entries associated with the user. The
+        default value of <code>false</code> causes only the top level
+        to be searched.</p>
+      </attribute>
+
+      <attribute name="userBase" required="false">
+        <p>The base element for user searches performed using the
+        <code>userSearch</code> expression.  If not specified, the top
+        level element in the directory context will be used. Not used
+        if you are using the <code>userPattern</code> expression.</p>
+      </attribute>
+
+      <attribute name="userPassword" required="false">
+        <p>Name of the attribute in the user's entry containing the
+        user's password.  If you specify this value, JNDIRealm will
+        bind to the directory using the values specified by
+        <code>connectionName</code> and
+        <code>connectionPassword</code> properties, and retrieve the
+        corresponding attribute for comparison to the value specified
+        by the user being authenticated.  If the <code>digest</code>
+        attribute is set, the specified digest algorithm is applied to
+        the password offered by the user before comparing it with the
+        value retrieved from the directory.  If you do
+        <strong>not</strong> specify this value, JNDIRealm will
+        attempt a simple bind to the directory using the DN of the
+        user's entry and password specified by the user, with a
+        successful bind being interpreted as an authenticated
+        user.</p>
+      </attribute>
+
+      <attribute name="userPattern" required="false">
+        <p>A pattern for the distinguished name (DN) of the user's
+        directory entry, following the syntax supported by the
+        <code>java.text.MessageFormat</code> class with
+        <code>{0}</code> marking where the actual username should be
+        inserted. You can use this property instead of
+        <code>userSearch</code>, <code>userSubtree</code> and
+        <code>userBase</code> when the distinguished name contains the
+        username and is otherwise the same for all users.</p>
+      </attribute>
+
+      <attribute name="userRoleName" required="false">
+        <p>The name of an attribute in the user's directory entry
+        containing zero or more values for the names of roles assigned
+        to this user.  In addition you can use the
+        <code>roleName</code> property to specify the name of an
+        attribute to be retrieved from individual role entries found
+        by searching the directory. If <code>userRoleName</code> is
+        not specified all the roles for a user derive from the role
+        search.</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
+        the actual username should be inserted.  Use this property
+        (along with the <code>userBase</code> and
+        <code>userSubtree</code> properties) instead of
+        <code>userPattern</code> to search the directory for the
+        user's entry.</p>
+      </attribute>
+
+      <attribute name="userSubtree" required="false">
+        <p>Set to <code>true</code> if you want to search the entire
+        subtree of the element specified by the <code>userBase</code>
+        property for the user's entry. The default value of
+        <code>false</code> causes only the top level to be searched.
+        Not used if you are using the <code>userPattern</code>
+        expression.</p>
+      </attribute>
+
+</attributes>
+
+<h3>Example</h3>
+
+<p>Creation of the appropriate schema in your directory server is beyond the
+scope of this document, because it is unique to each directory server
+implementation.  In the examples below, we will assume that you are using a
+distribution of the OpenLDAP directory server (version 2.0.11 or later), which
+can be downloaded from
+<a href="http://www.openldap.org">http://www.openldap.org</a>.  Assume that
+your <code>slapd.conf</code> file contains the following settings
+(among others):</p>
+<source>
+database ldbm
+suffix dc="mycompany",dc="com"
+rootdn "cn=Manager,dc=mycompany,dc=com"
+rootpw secret
+</source>
+
+<p>We will assume for <code>connectionURL</code> that the directory
+server runs on the same machine as Tomcat.  See <a
+href="http://java.sun.com/products/jndi/docs.html">http://java.sun.com/products/jndi/docs.html</a>
+for more information about configuring and using the JNDI LDAP
+provider.</p>
+
+<p>Next, assume that this directory server has been populated with elements
+as shown below (in LDIF format):</p>
+
+<source>
+
+# Define top-level entry
+dn: dc=mycompany,dc=com
+objectClass: dcObject
+dc:mycompany
+
+# Define an entry to contain people
+# searches for users are based on this entry
+dn: ou=people,dc=mycompany,dc=com
+objectClass: organizationalUnit
+ou: people
+
+# Define a user entry for Janet Jones
+dn: uid=jjones,ou=people,dc=mycompany,dc=com
+objectClass: inetOrgPerson
+uid: jjones
+sn: jones
+cn: janet jones
+mail: j.jones at mycompany.com
+userPassword: janet
+
+# Define a user entry for Fred Bloggs
+dn: uid=fbloggs,ou=people,dc=mycompany,dc=com
+objectClass: inetOrgPerson
+uid: fbloggs
+sn: bloggs
+cn: fred bloggs
+mail: f.bloggs at mycompany.com
+userPassword: fred
+
+# Define an entry to contain LDAP groups
+# searches for roles are based on this entry
+dn: ou=groups,dc=mycompany,dc=com
+objectClass: organizationalUnit
+ou: groups
+
+# Define an entry for the "tomcat" role
+dn: cn=tomcat,ou=groups,dc=mycompany,dc=com
+objectClass: groupOfUniqueNames
+cn: tomcat
+uniqueMember: uid=jjones,ou=people,dc=mycompany,dc=com
+uniqueMember: uid=fbloggs,ou=people,dc=mycompany,dc=com
+
+# Define an entry for the "role1" role
+dn: cn=role1,ou=groups,dc=mycompany,dc=com
+objectClass: groupOfUniqueNames
+cn: role1
+uniqueMember: uid=fbloggs,ou=people,dc=mycompany,dc=com
+</source>
+
+<p>An example <code>Realm</code> element for the OpenLDAP directory
+server configured as described above might look like this, assuming
+that users use their uid (e.g. jjones) to login to the
+application and that an anonymous connection is sufficient to search
+the directory and retrieve role information:</p>
+
+<source>
+&lt;Realm   className="org.apache.catalina.realm.JNDIRealm" debug="99"
+     connectionURL="ldap://localhost:389"
+       userPattern="uid={0},ou=people,dc=mycompany,dc=com"
+          roleBase="ou=groups,dc=mycompany,dc=com"
+          roleName="cn"
+        roleSearch="(uniqueMember={0})"
+/&gt;
+</source>
+
+<p>With this configuration, the realm will determine the user's
+distinguished name by substituting the username into the
+<code>userPattern</code>, authenticate by binding to the directory
+with this DN and the password received from the user, and search the
+directory to find the user's roles.</p>
+
+<p>Now suppose that users are expected to enter their email address
+rather than their userid when logging in. In this case the realm must
+search the directory for the user's entry. (A search is also necessary
+when user entries are held in multiple subtrees corresponding perhaps
+to different organizational units or company locations).</p>
+
+<p>Further, suppose that in addition to the group entries you want to
+use an attribute of the user's entry to hold roles. Now the entry for
+Janet Jones might read as follows:</p>
+
+<source>
+dn: uid=jjones,ou=people,dc=mycompany,dc=com
+objectClass: inetOrgPerson
+uid: jjones
+sn: jones
+cn: janet jones
+mail: j.jones at mycompany.com
+memberOf: role2
+memberOf: role3
+userPassword: janet
+</source>
+
+<p> This realm configuration would satisfy the new requirements:</p>
+
+<source>
+&lt;Realm   className="org.apache.catalina.realm.JNDIRealm" debug="99"
+     connectionURL="ldap://localhost:389"
+          userBase="ou=people,dc=mycompany,dc=com"
+        userSearch="(mail={0})"
+      userRoleName="memberOf"
+          roleBase="ou=groups,dc=mycompany,dc=com"
+          roleName="cn"
+        roleSearch="(uniqueMember={0})"
+/&gt;
+</source>
+
+<p>Now when Janet Jones logs in as "j.jones at mycompany.com", the realm
+searches the directory for a unique entry with that value as its mail
+attribute and attempts to bind to the directory as
+<code>uid=jjones,ou=people,dc=mycompany,dc=com</code> with the given
+password. If authentication succeeds, she is assigned three roles:
+"role2" and "role3", the values of the "memberOf" attribute in her
+directory entry, and "tomcat", the value of the "cn" attribute in the
+only group entry of which she is a member.</p>
+
+<p>Finally, to authenticate the user by retrieving
+the password from the directory and making a local comparison in the
+realm, you might use a realm configuration like this:</p>
+
+<source>
+&lt;Realm   className="org.apache.catalina.realm.JNDIRealm" debug="99"
+    connectionName="cn=Manager,dc=mycompany,dc=com"
+connectionPassword="secret"
+     connectionURL="ldap://localhost:389"
+      userPassword="userPassword"
+       userPattern="uid={0},ou=people,dc=mycompany,dc=com"
+          roleBase="ou=groups,dc=mycompany,dc=com"
+          roleName="cn"
+        roleSearch="(uniqueMember={0})"
+/&gt;
+</source>
+
+<p>However, as discussed above, the default bind mode for
+authentication is usually to be preferred.</p>
+
+<h3>Additional Notes</h3>
+
+<p>JNDIRealm operates according to the following rules:</p>
+<ul>
+<li>When a user attempts to access a protected resource for the first time,
+    Tomcat 5 will call the <code>authenticate()</code> method of this
+    <code>Realm</code>.  Thus, any changes you have made to the directory
+    (new users, changed passwords or roles, etc.) will be immediately
+    reflected.</li>
+<li>Once a user has been authenticated, the user (and his or her associated
+    roles) are cached within Tomcat for the duration of the user's login.
+    (For FORM-based authentication, that means until the session times out or
+    is invalidated; for BASIC authentication, that means until the user
+    closes their browser).  The cached user is <strong>not</strong> saved and
+    restored across sessions serialisations. Any changes to the directory
+    information for an already authenticated user will <strong>not</strong> be
+    reflected until the next time that user logs on again.</li>
+<li>Administering the information in the directory server
+    is the responsibility of your own applications.  Tomcat does not
+    provide any built-in capabilities to maintain users and roles.</li>
+</ul>
+
+</subsection>
+
+
+<subsection name="MemoryRealm">
+
+<h3>Introduction</h3>
+
+<p><strong>MemoryRealm</strong> is a simple demonstration implementation of the
+Tomcat 5 <code>Realm</code> interface.  It is not designed for production use.
+At startup time, MemoryRealm loads information about all users, and their
+corresponding roles, from an XML document (by default, this document is loaded from <code>$CATALINA_HOME/conf/tomcat-users.xml</code>).  Changes to the data
+in this file are not recognized until Tomcat is restarted.</p>
+
+<h3>Realm Element Attributes</h3>
+
+<p>To configure MemoryRealm, you will create a <code>&lt;Realm&gt;</code>
+element and nest it in your <code>$CATALINA_HOME/conf/server.xml</code> file,
+as described <a href="#Configuring a Realm">above</a>.  The following
+attributes are supported by this implementation:</p>
+
+<attributes>
+
+  <attribute name="className" required="true">
+    <p>The fully qualified Java class name of this Realm implementation.
+    You <strong>MUST</strong> specify the value
+    "<code>org.apache.catalina.realm.MemoryRealm</code>" here.</p>
+  </attribute>
+
+  <attribute name="digest" required="false">
+    <p>The digest algorithm used to store passwords in non-plaintext formats.
+    Valid values are those accepted for the algorithm name by the
+    <code>java.security.MessageDigest</code> class.  See
+    <a href="#Digested Passwords">Digested Passwords</a> for more
+    information.  If not specified, passwords are stored in clear text.</p>
+  </attribute>
+
+  <attribute name="pathname" required="false">
+    <p>Absolute or relative (to $CATALINA_HOME) pathname of the XML document
+    containing our valid usernames, passwords, and roles.  See below for more
+    information on the format of this file.  If not specified, the value
+    <code>conf/tomcat-users.xml</code> is used.</p>
+  </attribute>
+
+</attributes>
+
+<h3>User File Format</h3>
+
+<p>The users file (by default, <code>conf/tomcat-users.xml</code> must be an
+XML document, with a root element <code>&lt;tomcat-users&gt;</code>.  Nested
+inside the root element will be a <code>&lt;user&gt;</code> element for each
+valid user, consisting of the following attributes:</p>
+<ul>
+<li><strong>name</strong> - Username this user must log on with.</li>
+<li><strong>password</strong> - Password this user must log on with (in
+    clear text if the <code>digest</code> attribute was not set on the
+    <code>&lt;Realm&gt;</code> element, or digested appropriately as
+    described <a href="#Digested Passwords">here</a> otherwise).</li>
+<li><strong>roles</strong> - Comma-delimited list of the role names
+    associated with this user.</li>
+</ul>
+
+<h3>Example</h3>
+
+<p>The default installation of Tomcat 5 is configured with a MemoryRealm
+nested inside the <code>&lt;Engine&gt;</code> element, so that it applies
+to all virtual hosts and web applications.  The default contents of the
+<code>conf/tomcat-users.xml</code> file is:</p>
+<source>
+&lt;tomcat-users&gt;
+  &lt;user name="tomcat" password="tomcat" roles="tomcat" /&gt;
+  &lt;user name="role1"  password="tomcat" roles="role1"  /&gt;
+  &lt;user name="both"   password="tomcat" roles="tomcat,role1" /&gt;
+&lt;/tomcat-users&gt;
+</source>
+
+<h3>Additional Notes</h3>
+
+<p>MemoryRealm operates according to the following rules:</p>
+<ul>
+<li>When Tomcat first starts up, it loads all defined users and their
+    associated information from the users file.  Changes to the data in
+    this file will <strong>not</strong> be recognized until Tomcat is
+    restarted.</li>
+<li>When a user attempts to access a protected resource for the first time,
+    Tomcat 5 will call the <code>authenticate()</code> method of this
+    <code>Realm</code>.</li>
+<li>Once a user has been authenticated, the user (and his or her associated
+    roles) are cached within Tomcat for the duration of the user's login.
+    (For FORM-based authentication, that means until the session times out or
+    is invalidated; for BASIC authentication, that means until the user
+    closes their browser).  The cached user is <strong>not</strong> saved and
+    restored across sessions serialisations.</li>
+<li>Administering the information in the users file is the responsibility
+    of your application.  Tomcat does not
+    provide any built-in capabilities to maintain users and roles.</li>
+</ul>
+
+
+</subsection>
+
+
+<subsection name="JAASRealm">
+
+<h3>Introduction</h3>
+
+        <p><strong>JAASRealm</strong> is an implementation of the Tomcat
+4 <code>Realm</code> interface that authenticates users through the Java
+Authentication &amp; Authorization Service (JAAS) framework, a Java
+package that is available as an optional package in Java 2 SDK 1.3 and
+is fully integrated as of SDK 1.4 .</p>
+        <p>Using JAASRealm gives the developer the ability to combine
+practically any conceivable security realm with Tomcat's CMA. </p>
+        <p>JAASRealm is prototype for Tomcat of the proposed JAAS-based
+J2EE authentication framework for J2EE v1.4, based on the <a
+ href="http://www.jcp.org/en/jsr/detail?id=196">JCP Specification
+Request 196</a> to enhance container-managed security and promote
+'pluggable' authentication mechanisms whose implementations would be
+container-independent.
+        </p>
+        <p>Based on the JAAS login module and principal (see <code>javax.security.auth.spi.LoginModule</code>
+and <code>javax.security.Principal</code>), you can develop your own
+security mechanism or wrap another third-party mechanism for
+integration with the CMA as implemented by Tomcat.
+        </p>
+
+        <h3>Quick Start</h3>
+        <p>To set up Tomcat to use JAASRealm with your own JAAS login module,
+ you will need to follow these steps:</p>
+        <ol>
+          <li>Write your own LoginModule, User and Role classes based
+on JAAS (see 
+<a href="http://java.sun.com/j2se/1.4.1/docs/guide/security/jaas/tutorials/GeneralAcnOnly.html">the
+JAAS Authentication Tutorial</a> and 
+<a href="http://java.sun.com/j2se/1.4.1/docs/guide/security/jaas/JAASLMDevGuide.html">the JAAS Login Module 
+Developer's Guide</a>) to be managed by the JAAS Login
+Context (<code>javax.security.auth.login.LoginContext</code>)
+When developing your LoginModule, note that JAASRealm's built-in <code>CallbackHandler</code>
++only recognizes the <code>NameCallback</code> and <code>PasswordCallback</code> at present.
+          </li>
+          <li>Although not specified in JAAS, you should create
+seperate classes to distinguish between users and roles, extending <code>javax.security.Principal</code>,
+so that Tomcat can tell which Principals returned from your login
+module are users and which are roles (see <code>org.apache.catalina.realm.JAASRealm</code>).
+Regardless, the first Principal returned is <em>always</em> treated as the user Principal.
+          </li>
+          <li>Place the compiled classes on Tomcat's classpath
+          </li>
+          <li>Set up a login.config file for Java (see <a
+ href="http://java.sun.com/j2se/1.4.1/docs/guide/security/jaas/tutorials/LoginConfigFile.html">JAAS
+LoginConfig file</a>) and tell Tomcat where to find it by specifying
+its location to the JVM, for instance by setting the environment
+variable: <code>JAVA_OPTS=-DJAVA_OPTS=-Djava.security.auth.login.config==$CATALINA_HOME/conf/jaas.config</code></li>
+
+          <li>Configure your security-constraints in your web.xml for
+the resources you want to protect</li>
+          <li>Configure the JAASRealm module in your server.xml </li>
+          <li>Restart Tomcat 5 if it is already running.</li>
+        </ol>
+        <h3>Realm Element Attributes</h3>
+        <p>To configure JAASRealm as for step 6 above, you create
+a <code>&lt;Realm&gt;</code> element and nest it in your 
+<code>$CATALINA_HOME/conf/server.xml</code>
+file within your <code>&lt;Engine&gt;</code> node. The following attributes 
+are supported by this implementation:</p>
+
+<attributes>
+
+  <attribute name="className" required="true">
+    <p>The fully qualified Java class name of this Realm implementation.
+    You <strong>MUST</strong> specify the value
+    "<code>org.apache.catalina.realm.JAASRealm</code>" here.</p>
+  </attribute>
+
+  <attribute name="appName" required="true">
+    <p>The name of the application as configured in your login configuration file 
+    (<a href="http://java.sun.com/j2se/1.4.1/docs/guide/security/jaas/tutorials/LoginConfigFile.html">JAAS LoginConfig</a>).</p>
+  </attribute>
+
+  <attribute name="userClassNames" required="true">
+    <p>A comma-seperated list of the names of the classes that you have made 
+    for your user <code>Principals</code>.</p>
+  </attribute>
+
+  <attribute name="roleClassNames" required="false">
+    <p>A comma-seperated list of the names of the classes that you have made 
+    for your role <code>Principals</code>.</p>
+  </attribute>
+
+  <attribute name="useContextClassLoader" required="false">
+    <p>Instructs JAASRealm to use the context class loader for loading the user-specified
+    <code>LoginModule</code> class and associated <code>Principal</code> classes. The
+    default value is <code>true</code>, which is backwards-compatible with the way 
+    Tomcat 4 works. To load classes using the container's classloader, specify
+    <code>false</code>.</p>
+  </attribute>
+
+</attributes>
+
+<h3>Example</h3>
+
+<p>Here is an example of how your server.xml snippet should look.</p>
+
+<source>
+&lt;Realm className="org.apache.catalina.realm.JAASRealm"                 
+                appName="MyFooRealm"       
+    userClassNames="org.foobar.realm.FooUser"       
+     roleClassNames="org.foobar.realm.FooRole" 
+                      debug="99"/&gt;
+</source>
+
+<p>It is the responsibility of your login module to create and save User and 
+Role objects representing Principals for the user 
+(<code>javax.security.auth.Subject</code>). If your login module doesn't 
+create a user object but also doesn't throw a login exception, then the 
+Tomcat CMA will break and you will be left at the 
+http://localhost:8080/myapp/j_security_check URI or at some other 
+unspecified location.</p>
+
+        <p>The flexibility of the JAAS approach is two-fold: </p>
+        <ul>
+          <li>you can carry out whatever processing you require behind
+the scenes in your own login module.</li>
+          <li>you can plug in a completely different LoginModule by changing the configuration 
+and restarting the server, without any code changes to your application.</li>
+        </ul>
+
+        <h3>Additional Notes</h3>
+        <ul>
+          <li>When a user attempts to access a protected resource for
+              the first time, Tomcat 5 will call the <code>authenticate()</code>
+              method of this <code>Realm</code>.  Thus, any changes you have made in
+              the security mechanism directly (new users, changed passwords or
+              roles, etc.) will be immediately reflected.</li>
+          <li>Once a user has been authenticated, the user (and his or
+              her associated roles) are cached within Tomcat for the duration of
+              the user's login.  For FORM-based authentication, that means until
+              the session times out or is invalidated; for BASIC authentication,
+              that means until the user closes their browser.  Any changes to the
+              security information for an already authenticated user will <strong>not</strong>
+              be reflected until the next time that user logs on again.</li>
+          <li>As with other <code>Realm</code> implementations, digested passwords
+              are supported if the <code>&lt;Realm&gt;</code> element in <code>server.xml</code>
+              contains a <code>digest</code> attribute; JAASRealm's <code>CallbackHandler</code>
+              will digest the password prior to passing it back to the <code>LoginModule</code></li>  
+        </ul>
+
+</subsection>
+
+
+</section>
+
+</body>
+
+</document>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/security-manager-howto.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/security-manager-howto.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/security-manager-howto.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,383 @@
+<?xml version="1.0"?>
+<!DOCTYPE document [
+  <!ENTITY project SYSTEM "project.xml">
+]>
+<document url="security-manager-howto.html">
+
+    &project;
+
+    <properties>
+        <author email="glenn at voyager.apg.more.net">Glenn Nielsen</author>
+        <author email="jeanfrancois.arcand at sun.com">Jean-Francois Arcand</author>
+        <title>Security Manager HOW-TO</title>
+    </properties>
+
+<body>
+
+
+<section name="Background">
+
+  <p>The Java <strong>SecurityManager</strong> is what allows a web browser
+  to run an applet in its own sandbox to prevent untrusted code from
+  accessing files on the local file system, connecting to a host other
+  than the one the applet was loaded from, and so on.  In the same way
+  the SecurityManager protects you from an untrusted applet running in
+  your browser, use of a SecurityManager while running Tomcat can protect
+  your server from trojan servlets, JSPs, JSP beans, and tag libraries.
+  Or even inadvertent mistakes.</p>
+
+  <p>Imagine if someone who is authorized to publish JSPs on your site
+  inadvertently included the following in their JSP:</p>
+<source>
+&lt;% System.exit(1); %&gt;
+</source>
+
+  <p>Every time this JSP was executed by Tomcat, Tomcat would exit.
+  Using the Java SecurityManager is just one more line of defense a
+  system administrator can use to keep the server secure and reliable.</p>
+
+  <p><strong>WARNING</strong> - A security audit
+  have been conducted using the Tomcat 5 codebase. Most of the critical
+  package have been protected and a new security package protection mechanism 
+  has been implemented. Still, make sure that you are satisfied with your SecurityManager 
+  configuration before allowing untrusted users to publish web applications, 
+  JSPs, servlets, beans, or tag libraries.  <strong>However, running with a 
+  SecurityManager is definitely better than running without one.</strong></p>
+
+</section>
+
+
+<section name="Permissions">
+
+  <p>Permission classes are used to define what Permissions a class loaded
+  by Tomcat will have.  There are a number of Permission classes that are
+  a standard part of the JDK, and you can create your own Permission class
+  for use in your own web applications.  Both techniques are used in
+  Tomcat 5.</p>
+
+
+  <subsection name="Standard Permissions">
+
+    <p>This is just a short summary of the standard system SecurityManager
+    Permission classes applicable to Tomcat.  See
+    <a href="http://java.sun.com/security/">http://java.sun.com/security/</a>
+    for more information.</p>
+
+    <ul>
+    <li><strong>java.util.PropertyPermission</strong> - Controls read/write
+        access to JVM properties such as <code>java.home</code>.</li>
+    <li><strong>java.lang.RuntimePermission</strong> - Controls use of
+        some System/Runtime functions like <code>exit()</code> and
+        <code>exec()</code>. Also control the package access/definition.</li>
+    <li><strong>java.io.FilePermission</strong> - Controls read/write/execute
+        access to files and directories.</li>
+    <li><strong>java.net.SocketPermission</strong> - Controls use of
+        network sockets.</li>
+    <li><strong>java.net.NetPermission</strong> - Controls use of
+        multicast network connections.</li>
+    <li><strong>java.lang.reflect.ReflectPermission</strong> - Controls
+        use of reflection to do class introspection.</li>
+    <li><strong>java.security.SecurityPermission</strong> - Controls access
+        to Security methods.</li>
+    <li><strong>java.security.AllPermission</strong> - Allows access to all
+        permissions, just as if you were running Tomcat without a
+        SecurityManager.</li>
+    </ul>
+
+  </subsection>
+
+
+  <subsection name="Tomcat Custom Permissions">
+
+    <p>Tomcat utilizes a custom permission class called
+    <strong>org.apache.naming.JndiPermission</strong>.  This permission
+    controls read access to JNDI named file based resources.  The permission
+    name is the JNDI name and there are no actions.  A trailing "*" can be
+    used to do wild card matching for a JNDI named file resource when
+    granting permission.  For example, you might include the following
+    in your policy file:</p>
+<source>
+permission  org.apache.naming.JndiPermission  "jndi://localhost/examples/*";
+</source>
+
+    <p>A Permission entry like this is generated dynamically for each web
+    application that is deployed, to allow it to read its own static resources
+    but disallow it from using file access to read any other files (unless
+    permissions for those files are explicitly granted).</p>
+
+    <p>Also, Tomcat always dynamically creates the following file permission:</p>
+<source>  
+permission java.io.FilePermission "** your application context**", "read";
+</source>  
+    <p>Where **your application context** equals the folder(or WAR file) under which 
+    your application has been deployed. </p>  
+
+  </subsection>
+
+
+</section>
+
+
+<section name="Configuring Tomcat With A SecurityManager">
+
+  <h3>Policy File Format</h3>
+
+  <p>The security policies implemented by the Java SecurityManager are
+  configured in the <code>$CATALINA_HOME/conf/catalina.policy</code> file.
+  This file completely replaces the <code>java.policy</code> file present
+  in your JDK system directories.  The <code>catalina.policy</code> file
+  can be edited by hand, or you can use the
+  <a href="http://java.sun.com/products/jdk/1.2/docs/tooldocs/solaris/policytool.html">policytool</a>
+  application that comes with Java 1.2 or later.</p>
+
+  <p>Entries in the <code>catalina.policy</code> file use the standard
+  <code>java.policy</code> file format, as follows:</p>
+<source>
+// Example policy file entry
+
+grant [signedBy &lt;signer&gt;,] [codeBase &lt;code source&gt;] {
+  permission  &lt;class&gt;  [&lt;name&gt; [, &lt;action list&gt;]];
+};
+</source>
+
+  <p>The <strong>signedBy</strong> and <strong>codeBase</strong> entries are
+  optional when granting permissions.  Comment lines begin with "//" and
+  end at the end of the current line.  The <code>codeBase</code> is in the
+  form of a URL, and for a file URL can use the <code>${java.home}</code>
+  and <code>${catalina.home}</code> properties (which are expanded out to
+  the directory paths defined for them by the <code>JAVA_HOME</code> and
+  <code>CATALINA_HOME</code> environment variables).</p>
+
+  <h3>The Default Policy File</h3>
+
+  <p>The default <code>$CATALINA_HOME/conf/catalina.policy</code> file
+  looks like this:</p>
+<source>
+// ============================================================================
+// catalina.corepolicy - Security Policy Permissions for Tomcat 5
+//
+// This file contains a default set of security policies to be enforced (by the
+// JVM) when Catalina is executed with the "-security" option.  In addition
+// to the permissions granted here, the following additional permissions are
+// granted to the codebase specific to each web application:
+//
+// * Read access to the document root directory
+//
+// $Id: security-manager-howto.xml 301460 2003-01-15 03:40:45Z glenn $
+// ============================================================================
+
+
+// ========== SYSTEM CODE PERMISSIONS =========================================
+
+
+// These permissions apply to javac
+grant codeBase "file:${java.home}/lib/-" {
+        permission java.security.AllPermission;
+};
+
+// These permissions apply to all shared system extensions
+grant codeBase "file:${java.home}/jre/lib/ext/-" {
+        permission java.security.AllPermission;
+};
+
+// These permissions apply to javac when ${java.home] points at $JAVA_HOME/jre
+grant codeBase "file:${java.home}/../lib/-" {
+        permission java.security.AllPermission;
+};
+
+// These permissions apply to all shared system extensions when
+// ${java.home} points at $JAVA_HOME/jre
+grant codeBase "file:${java.home}/lib/ext/-" {
+        permission java.security.AllPermission;
+};
+
+
+// ========== CATALINA CODE PERMISSIONS =======================================
+
+
+// These permissions apply to the launcher code
+grant codeBase "file:${catalina.home}/bin/commons-launcher.jar" {
+        permission java.security.AllPermission;
+};
+
+// These permissions apply to the server startup code
+grant codeBase "file:${catalina.home}/bin/bootstrap.jar" {
+        permission java.security.AllPermission;
+};
+
+// These permissions apply to the servlet API classes
+// and those that are shared across all class loaders
+// located in the "common" directory
+grant codeBase "file:${catalina.home}/common/-" {
+        permission java.security.AllPermission;
+};
+
+// These permissions apply to the container's core code, plus any additional
+// libraries installed in the "server" directory
+grant codeBase "file:${catalina.home}/server/-" {
+        permission java.security.AllPermission;
+};
+
+// ========== WEB APPLICATION PERMISSIONS =====================================
+
+
+// These permissions are granted by default to all web applications
+// In addition, a web application will be given a read FilePermission
+// and JndiPermission for all files and directories in its document root.
+grant { 
+        // Required for JNDI lookup of named JDBC DataSource's and
+        // javamail named MimePart DataSource used to send mail
+        permission java.util.PropertyPermission "java.home", "read";
+        permission java.util.PropertyPermission "java.naming.*", "read";
+        permission java.util.PropertyPermission "javax.sql.*", "read";
+
+        // OS Specific properties to allow read access
+	permission java.util.PropertyPermission "os.name", "read";
+	permission java.util.PropertyPermission "os.version", "read";
+	permission java.util.PropertyPermission "os.arch", "read";
+	permission java.util.PropertyPermission "file.separator", "read";
+	permission java.util.PropertyPermission "path.separator", "read";
+	permission java.util.PropertyPermission "line.separator", "read";
+
+        // JVM properties to allow read access
+        permission java.util.PropertyPermission "java.version", "read";
+        permission java.util.PropertyPermission "java.vendor", "read";
+        permission java.util.PropertyPermission "java.vendor.url", "read";
+        permission java.util.PropertyPermission "java.class.version", "read";
+	permission java.util.PropertyPermission "java.specification.version", "read";
+	permission java.util.PropertyPermission "java.specification.vendor", "read";
+	permission java.util.PropertyPermission "java.specification.name", "read";
+
+	permission java.util.PropertyPermission "java.vm.specification.version", "read";
+	permission java.util.PropertyPermission "java.vm.specification.vendor", "read";
+	permission java.util.PropertyPermission "java.vm.specification.name", "read";
+	permission java.util.PropertyPermission "java.vm.version", "read";
+	permission java.util.PropertyPermission "java.vm.vendor", "read";
+	permission java.util.PropertyPermission "java.vm.name", "read";
+
+        // Required for getting BeanInfo
+        permission java.lang.RuntimePermission "accessClassInPackage.sun.beans.*";
+
+        // Required for OpenJMX
+        permission java.lang.RuntimePermission "getAttribute";
+
+	// Allow read of JAXP compliant XML parser debug
+	permission java.util.PropertyPermission "jaxp.debug", "read";
+};
+
+
+// You can assign additional permissions to particular web applications by
+// adding additional "grant" entries here, based on the code base for that
+// application, /WEB-INF/classes/, or /WEB-INF/lib/ jar files.
+//
+// Different permissions can be granted to JSP pages, classes loaded from
+// the /WEB-INF/classes/ directory, all jar files in the /WEB-INF/lib/
+// directory, or even to individual jar files in the /WEB-INF/lib/ directory.
+//
+// For instance, assume that the standard "examples" application
+// included a JDBC driver that needed to establish a network connection to the
+// corresponding database and used the scrape taglib to get the weather from
+// the NOAA web server.  You might create a "grant" entries like this:
+//
+// The permissions granted to the context root directory apply to JSP pages.
+// grant codeBase "file:${catalina.home}/webapps/examples/-" {
+//      permission java.net.SocketPermission "dbhost.mycompany.com:5432", "connect";
+//      permission java.net.SocketPermission "*.noaa.gov:80", "connect";
+// };
+//
+// The permissions granted to the context WEB-INF/classes directory
+// grant codeBase "file:${catalina.home}/webapps/examples/WEB-INF/classes/-" {
+// };
+//
+// The permission granted to your JDBC driver
+// grant codeBase "jar:file:${catalina.home}/webapps/examples/WEB-INF/lib/driver.jar!/-" {
+//      permission java.net.SocketPermission "dbhost.mycompany.com:5432", "connect";
+// };
+// The permission granted to the scrape taglib
+// grant codeBase "jar:file:${catalina.home}/webapps/examples/WEB-INF/lib/scrape.jar!/-" {
+//      permission java.net.SocketPermission "*.noaa.gov:80", "connect";
+// };
+</source>
+
+  <h3>Starting Tomcat With A SecurityManager</h3>
+
+  <p>Once you have configured the <code>catalina.policy</code> file for use
+  with a SecurityManager, Tomcat can be started with a SecurityManager in
+  place by using the "-security" option:</p>
+<source>
+$CATALINA_HOME/bin/catalina.sh start -security    (Unix)
+%CATALINA_HOME%\bin\catalina start -security      (Windows)
+</source>
+
+</section>
+<section name="Configuring Package Protection in Tomcat">
+  <p>Starting with Tomcat 5, it is now possible to configure which Tomcat
+  internal package are protected againts package definition and access. See
+  <a href="http://java.sun.com/security/seccodeguide.html">
+    http://java.sun.com/security/seccodeguide.html</a>
+    for more information.</p>    
+
+  
+  <p><strong>WARNING</strong>: Be aware that removing the default package protection 
+  could possibly open a security hole</p>
+
+  <h3>The Default Properties File</h3>
+
+  <p>The default <code>$CATALINA_HOME/conf/catalina.properties</code> file
+  looks like this:</p>
+<source>  
+#
+# List of comma-separated packages that start with or equal this string
+# will cause a security exception to be thrown when
+# passed to checkPackageAccess unless the
+# corresponding RuntimePermission ("accessClassInPackage."+package) has
+# been granted.
+package.access=sun.,org.apache.catalina.,org.apache.coyote.,org.apache.tomcat.,
+org.apache.jasper.
+#
+# List of comma-separated packages that start with or equal this string
+# will cause a security exception to be thrown when
+# passed to checkPackageDefinition unless the
+# corresponding RuntimePermission ("defineClassInPackage."+package) has
+# been granted.
+#
+# by default, no packages are restricted for definition, and none of
+# the class loaders supplied with the JDK call checkPackageDefinition.
+#
+package.definition=sun.,java.,org.apache.catalina.,org.apache.coyote.,
+org.apache.tomcat.,org.apache.jasper.
+</source>
+  <p>Once you have configured the <code>catalina.properties</code> file for use
+  with a SecurityManager, remember to re-start Tomcat.</p>
+</section>
+
+<section name="Troubleshooting">
+
+  <p>If your web application attempts to execute an operation that is
+  prohibited by lack of a required Permission, it will throw an
+  <code>AccessControLException</code> or a <code>SecurityException</code>
+  when the SecurityManager detects the violation.  Debugging the permission
+  that is missing can be challenging, and one option is to turn on debug
+  output of all security decisions that are made during execution.  This
+  is done by setting a system property before starting Tomcat.  The easiest
+  way to do this is via the <code>CATALINA_OPTS</code> environment variable.
+  Execute this command:</p>
+<source>
+export CATALINA_OPTS=-Djava.security.debug=all    (Unix)
+set CATALINA_OPTS=-Djava.security.debug=all       (Windows)
+</source>
+
+  <p>before starting Tomcat.</p>
+
+  <p><strong>WARNING</strong> - This will generate <em>many megabytes</em>
+  of output!  However, it can help you track down problems by searching
+  for the word "FAILED" and determining which permission was being checked
+  for.  See the Java security documentation for more options that you can
+  specify here as well.</p>
+
+</section>
+
+
+</body>
+
+</document>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/setup.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/setup.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/setup.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,135 @@
+<?xml version="1.0"?>
+<!DOCTYPE document [
+  <!ENTITY project SYSTEM "project.xml">
+]>
+<document url="setup.html">
+
+  &project;
+
+  <properties>
+    <author email="remm at apache.org">Remy Maucherat</author>
+    <title>Tomcat Setup</title>
+  </properties>
+
+<body>
+
+  <section name="Introduction">
+    <p>
+      This document introduces several ways to set up Tomcat for running
+      on different platforms.  Please note that some advanced setup issues
+      are not covered here: the full distribution (ZIP file or tarball) 
+      includes a file called
+      RUNNING.txt which discusses these issues.  We encourage you to refer
+      to it if the information below does not answer some of your questions.
+    </p>
+  </section>
+
+  <section name="Windows">
+
+    <p>
+      Installing Tomcat on Windows can be done easily using the Windows 
+      installer. Its interface and functionality is similar to other wizard
+      based installers, with only a few items of interest.
+    </p>
+
+    <p>
+      <ul>
+        <li><strong>Installation as a service</strong>: Tomcat will be 
+            installed as a Windows
+            NT/2k/XP service no matter what setting is selected. Using the
+            checkbox on the component page sets the service as "auto"
+            startup, so that Tomcat is automatically started when Windows
+            starts. For optimal security, the service should be run as a
+            separate user, with reduced permissions (see the Windows Services
+            administration tool and its documentation).</li>
+        <li><strong>Java location</strong>: The installer will use the registry
+            or the JAVA_HOME environment variable to determine the base path
+            of a J2SE 5 JRE.
+            </li>
+        <li><strong>Tray icon</strong>: When Tomcat is run as a service, there
+            will not be any tray icon present when Tomcat is running. Note that
+            when choosing to run Tomcat at the end of installation, the tray
+            icon will be used even if Tomcat was installed as a service.</li>
+        <li>Refer to the
+            <a href="windows-service-howto.html">Windows Service HOW-TO</a>
+            for information on how to manage Tomcat as Windows NT service.
+            </li>            
+      </ul>
+    </p>
+
+    <p>The installer will create shortcuts allowing starting and configuring 
+       Tomcat. It is important to note that the Tomcat administration web 
+       application can only be used when Tomcat is running.</p>
+
+    <p>If using a J2SE 1.4 JRE, the compatibility package must be downloaded and
+       expanded inside the folder where Tomcat was installed.</p>
+
+  </section>
+
+  <section name="Unix daemon">
+
+    <p>Tomcat can be run as a daemon using the jsvc tool from the 
+       commons-daemon project. Source tarballs for jsvc are included with the
+       Tomcat binaries, and need to be compiled. Building jsvc requires
+       a C ANSI compiler (such as GCC), GNU Autoconf, and a JDK.</p>
+
+    <p>Before running the script, the <code>JAVA_HOME</code> environment
+       variable should be set to the base path of the JDK. Alternately, when
+       calling the <code>./configure</code> script, the path of the JDK may
+       be specified using the <code>--with-java</code> parameter, such as
+       <code>./configure --with-java=/usr/java</code>.</p>
+
+    <p>Using the following commands should result in a compiled jsvc binary,
+       located in the <code>$CATALINA_HOME/bin</code> folder. This assumes
+       that GNU TAR is used, and that <code>CATALINA_HOME</code> is an 
+       environment variable pointing to the base path of the Tomcat 
+       installation.</p>
+  
+    <p>Please note that you should use the GNU make (gmake) instead of
+       the native BSD make on FreeBSD systems.</p>
+
+
+<source>
+    cd $CATALINA_HOME/bin
+    tar xvfz jsvc.tar.gz
+    cd jsvc-src
+    autoconf
+    ./configure
+    make
+    cp jsvc ..
+    cd ..
+</source>
+
+    <p>Tomcat can then be run as a daemon using the following commands.</p>
+
+<source>
+    cd $CATALINA_HOME
+    ./bin/jsvc -Djava.endorsed.dirs=./common/endorsed -cp ./bin/bootstrap.jar \
+        -outfile ./logs/catalina.out -errfile ./logs/catalina.err \
+        org.apache.catalina.startup.Bootstrap
+</source>
+
+    <p>jsvc has other useful parameters, such as <code>-user</code> which 
+       causes it to switch to another user after the daemon initialization is
+       complete. This allows, for example, running Tomcat as a non privileged
+       user while still being able to use privileged ports. 
+       <code>jsvc --help</code> will return the full jsvc usage 
+       information. In particular, the <code>-debug</code> option is useful
+       to debug issues running jsvc.</p>
+
+    <p>The file <code>$CATALINA_HOME/bin/jsvc/native/tomcat.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 4.1.x, so it is necessary to edit it and change the classname 
+       from <code>BootstrapService</code> to <code>Bootstrap</code>.</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 Class-Path 
+       entry of the bootstrap.jar manifest, but if you get a ClassNotFoundException 
+       or a NoClassDefFoundError for a Commons-Daemon class, add the Commons-Daemon 
+       JAR to the -cp argument when launching jsvc.</p> 
+
+  </section>
+
+</body>
+</document>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/ssi-howto.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/ssi-howto.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/ssi-howto.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,373 @@
+<?xml version="1.0"?>
+<!DOCTYPE document [
+  <!ENTITY project SYSTEM "project.xml">
+]>
+<document url="ssi-howto.html">
+
+&project;
+
+<properties>
+<author email="glenn at apache.org">Glenn L. Nielsen</author>
+<title>SSI How To</title>
+</properties>
+
+<body>
+
+<section name="Introduction">
+
+<p>SSI (Server Side Includes) are directives that are placed in HTML pages,
+and evaluated on the server while the pages are being served. They let you
+add dynamically generated content to an existing HTML page, without having
+to serve the entire page via a CGI program, or other dynamic technology.
+</p>
+
+<p>Within Tomcat SSI support can be added when using Tomcat as your
+HTTP server and you require SSI support.  Typically this is done
+during development when you don't want to run a web server like Apache.</p>
+
+<p>Tomcat SSI support implements the same SSI directives as Apache.  See the
+<a href="http://httpd.apache.org/docs/howto/ssi.html#basicssidirectives">
+Apache Introduction to SSI</a> for information on using SSI directives.</p>
+
+<p>SSI support is available as a servlet and as a filter. You should use one
+or the other to provide SSI support but not both.</p>
+
+<p>Servlet based SSI support is implemented using the class
+<code>org.apache.catalina.ssi.SSIServlet</code>.  Traditionally, this servlet
+is mapped to the URL pattern "*.shtml".</p>
+
+<p>Filter based SSI support is implemented using the class
+<code>org.apache.catalina.ssi.SSIFilter</code>.  Traditionally, this filter
+is mapped to the URL pattern "*.shtml", though it can be mapped to "*" as
+it will selectively enable/disable SSI processing based on mime types.  The
+contentType init param allows you to apply SSI processing to JSP pages,
+javascript, or any other content you wish.</p>
+<p>By default SSI support is disabled in Tomcat.</p>
+</section>
+
+<section name="Installation">
+
+<p><strong>CAUTION</strong> - SSI directives can be used to execute programs
+external to the Tomcat JVM. If you are using the Java SecurityManager this
+will bypass your security policy configuration in <code>catalina.policy.</code>
+</p>
+
+<p>Rename <code>$CATALINA_BASE/server/lib/servlets-ssi.renametojar</code>
+to <code>$CATALINA_BASE/server/lib/servlets-ssi.jar</code>.</p>
+
+<p>To use the SSI servlet, remove the XML comments from around the SSI servlet
+and servlet-mapping configuration in
+<code>$CATALINA_BASE/conf/web.xml</code>.</p>
+
+<p>To use the SSI filter, remove the XML comments from around the SSI filter
+and filter-mapping configuration in
+<code>$CATALINA_BASE/conf/web.xml</code>.</p>
+
+</section>
+
+<section name="Servlet Configuration">
+
+<p>There are several servlet init parameters which can be used to
+configure the behaviour of the SSI servlet.
+<ul>
+<li><strong>buffered</strong> - Should output from this servlet be buffered?
+(0=false, 1=true) Default 0 (false).</li>
+<li><strong>debug</strong> - Debugging detail level for messages logged
+by this servlet. Default 0.</li>
+<li><strong>expires</strong> - The number of seconds before a page with SSI
+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>
+<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>
+<li><strong>outputEncoding</strong> - The encoding to be used for the result
+of the SSI processing. Default is UTF-8.</li>
+</ul>
+</p>
+
+</section>
+
+<section name="Filter Configuration">
+
+<p>There are several filter init parameters which can be used to
+configure the behaviour of the SSI filter.
+<ul>
+<li><strong>contentType</strong> - A regex pattern that must be matched before
+SSI processing is applied. When crafting your own pattern, don't forget that a
+mime content type may be followed by an optional character set in the form
+"mime/type; charset=set" that you must take into account.  Default is
+"text/x-server-parsed-html(;.*)?".</li>
+<li><strong>debug</strong> - Debugging detail level for messages logged
+by this servlet. Default 0.</li>
+<li><strong>expires</strong> - The number of seconds before a page with SSI
+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>
+</ul>
+</p>
+
+</section>
+
+<section name="Directives">
+<p>Server Side Includes are invoked by embedding SSI directives in an HTML document
+ whose type will be processed by the SSI servlet. The directives take the form of an HTML
+ comment. The directive is replaced by the results of interpreting it before sending the
+ page to the client. The general form of a directive is: </p>
+<p> <code>&lt;!--#directive [parm=value] --&gt;</code></p>
+<p>The directives are:
+<ul>
+<li>
+<strong>config</strong> - <code>&lt;!--#config timefmt=&quot;%B %Y&quot; --&gt;</code>
+Used to set the format of dates and other items processed by SSI
+</li>
+<li>
+<strong>echo</strong> -   <code>&lt;!--#echo var=&quot;VARIABLE_NAME&quot; --&gt;</code>
+will be replaced bt the value of the variable.
+</li>
+<li>
+<strong>exec</strong> -  Used to run commands on the host system.
+</li>
+<li>
+<strong>include</strong> -  <code>&lt;!--#include virtual=&quot;file-name&quot; --&gt;</code>
+inserts the contents
+</li>
+<li>
+<strong>flastmod</strong> - <code>&lt;!--#flastmod file=&quot;filename.shtml&quot; --&gt;</code>
+Returns the time that a file was lost modified.
+</li>
+<li>
+<strong>fsize</strong> - <code>&lt;!--#fsize file=&quot;filename.shtml&quot; --&gt;</code>
+Returns the size of a file.
+</li>
+<li>
+<strong>printenv</strong> - <code>&lt;!--#printenv --&gt;</code>
+Returns the list of all the defined variables.
+</li>
+<li>
+<strong>set</strong> - <code>&lt;!--#set var="foo" value="Bar" --&gt;</code>
+is used to assign a value to a user-defind variable.
+</li>
+<li>
+<strong>if elif endif else</strong> - Used to create conditional sections. For example:</li>
+<code>&lt;!--#config timefmt="%A" --&gt;<br />
+  &lt;!--#if expr="$DATE_LOCAL = /Monday/" --&gt;<br />
+  &lt;p&gt;Meeting at 10:00 on Mondays&lt;/p&gt;<br />
+  &lt;!--#elif expr="$DATE_LOCAL = /Friday/" --&gt;<br />
+  &lt;p&gt;Turn in your time card&lt;/p&gt;<br />
+  &lt;!--#else --&gt;<br />
+  &lt;p&gt;Yoga class at noon.&lt;/p&gt;<br />
+  &lt;!--#endif --&gt;</code>
+ </ul>
+</p>
+See the
+<p> <a href="http://httpd.apache.org/docs/howto/ssi.html#basicssidirectives">
+Apache Introduction to SSI</a> for more information on using SSI directives.</p>
+</section>
+
+<section name="Variables">
+<p>The SSI servlet currently implements the following variables:
+</p>
+<table border="1">
+<tr>
+<th>Variable Name</th>
+<th>Description</th>
+</tr>
+
+<tr>
+<td>AUTH_TYPE</td>
+<td>
+  The type of authentication used for this user: BASIC, FORM, etc.</td>
+</tr>
+
+<tr>
+<td>CONTENT_LENGTH</td>
+<td>
+  The length of the data (in bytes or the number of 
+  characters) passed from a form.</td>
+</tr>
+
+<tr>
+<td>CONTENT_TYPE</td>
+<td>
+  The MIME type of the query data, such as &quot;text/html&quot;.</td>
+</tr>
+
+<tr>
+<td>DATE_GMT</td>
+<td>
+Current date and time in GMT</td>
+</tr>
+
+<tr>
+<td>DATE_LOCAL</td>
+<td>
+Current date and time in the local time zone</td>
+</tr>
+<tr>
+<td>DOCUMENT_NAME</td>
+<td>
+The current file</td>
+</tr>
+<tr>
+<td>DOCUMENT_URI</td>
+<td>
+Virtual path to the file</td>
+</tr>
+
+<tr>
+<td>GATEWAY_INTERFACE</td>
+<td>
+  The revision of the Common Gateway Interface that the 
+  server uses if enabled: &quot;CGI/1.1&quot;.</td>
+</tr>
+
+<tr>
+<td>HTTP_ACCEPT</td>
+<td>
+  A list of the MIME types that the client can accept.</td>
+</tr>
+
+<tr>
+<td>HTTP_ACCEPT_ENCODING</td>
+<td>
+  A list of the compression types that the client can accept.</td>
+</tr>
+
+<tr>
+<td>HTTP_ACCEPT_LANGUAGE</td>
+<td>
+  A list of the laguages that the client can accept.</td>
+</tr>
+<tr>
+<td>HTTP_CONNECTION</td>
+<td>
+  The way that the connection from the client is being managed:
+  &quot;Close&quot; or &quot;Keep-Alive&quot;.</td>
+</tr>
+<tr>
+<td>HTTP_HOST</td>
+<td>
+  The web site that the client requested.</td>
+</tr>
+<tr>
+<td>HTTP_REFERER</td>
+<td>
+  The URL of the document that the client linked from.</td>
+</tr>
+<tr>
+<td>HTTP_USER_AGENT</td>
+<td>
+  The browser the client is using to issue the request.</td>
+</tr>
+<tr>
+<td>LAST_MODIFIED</td>
+<td>
+Last modification date and time for current file</td>
+</tr>
+<tr>
+<td>PATH_INFO</td>
+<td>
+  Extra path information passed to a servlet.</td>
+</tr>
+<tr>
+<td>PATH_TRANSLATED</td>
+<td>
+  The translated version of the path given by the
+  variable PATH_INFO.</td>
+</tr>
+<tr>
+<td>QUERY_STRING</td>
+<td>
+The query string that follows the &quot;?&quot; in the URL.
+</td>
+</tr>
+<tr>
+<td>QUERY_STRING_UNESCAPED</td>
+<td>
+Undecoded query string with all shell metacharacters escaped 
+with &quot;\&quot;</td>
+</tr>
+<tr>
+<td>REMOTE_ADDR</td>
+<td>
+  The remote IP address of the user making the request.</td>
+</tr>
+<tr>
+<td>REMOTE_HOST</td>
+<td>
+  The remote hostname of the user making the request.</td>
+</tr>
+<tr>
+<td>REMOTE_PORT</td>
+<td>
+  The port number at remote IP address of the user making the request.</td>
+</tr>
+<tr>
+<td>REMOTE_USER</td>
+<td>
+  The authenticated name of the user.</td>
+</tr>
+<tr>
+<td>REQUEST_METHOD</td>
+<td>
+  The method with which the information request was
+  issued: &quot;GET&quot;, &quot;POST&quot; etc.</td>
+</tr>
+<tr>
+<td>REQUEST_URI</td>
+<td>
+  The web page originally requested by the client.</td>
+</tr>
+<tr>
+<td>SCRIPT_FILENAME</td>
+<td>
+  The location of the current web page on the server.</td>
+</tr>
+<tr>
+<td>SCRIPT_NAME</td>
+<td>
+  The name of the web page.</td>
+</tr>
+<tr>
+<td>SERVER_ADDR</td>
+<td>
+  The server's IP address.</td>
+</tr>
+<tr>
+<td>SERVER_NAME</td>
+<td>
+  The server's hostname or IP address.</td>
+</tr>
+<tr>
+<td>SERVER_PORT</td>
+<td>
+  The port on which the server received the request.</td>
+</tr>
+<tr>
+<td>SERVER_PROTOCOL</td>
+<td>
+  The protocol used by the server. E.g. &quot;HTTP/1.1&quot;.</td>
+</tr>
+<tr>
+<td>SERVER_SOFTWARE</td>
+<td>
+  The name and version of the server software that is 
+  answering the client request.</td>
+</tr>
+<tr>
+<td>UNIQUE_ID</td>
+<td>
+  A token used to identify the current session if one
+  has been established.</td>
+</tr>
+</table>
+</section>
+
+</body>
+
+</document>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/ssl-howto.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/ssl-howto.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/ssl-howto.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,545 @@
+<?xml version="1.0"?>
+<!DOCTYPE document [
+  <!ENTITY project SYSTEM "project.xml">
+]>
+<document url="ssl-howto.html">
+
+    &project;
+
+    <properties>
+        <author email="ccain at apache.org">Christopher Cain</author>
+        <author email="yoavs at apache.org">Yoav Shapira</author>
+        <title>SSL Configuration HOW-TO</title>
+    </properties>
+
+<body>
+
+
+<section name="Quick Start">
+
+   <p><b>IMPORTANT NOTE: This Howto refers to usage of JSSE. When using APR, Tomcat will
+   use OpenSSL, which uses a different configuration.</b></p>
+
+    <blockquote><em>
+    <p>The description below uses the variable name $CATALINA_HOME
+    to refer to the directory into which you have installed Tomcat 5,
+    and is the base directory against which most relative paths are
+    resolved.  However, if you have configured Tomcat 5 for multiple
+    instances by setting a CATALINA_BASE directory, you should use
+    $CATALINA_BASE instead of $CATALINA_HOME for each of these
+    references.</p>
+    </em></blockquote>
+
+<p>To install and configure SSL support on Tomcat 5, you need to follow
+these simple steps.  For more information, read the rest of this HOW-TO.</p>
+<ol>
+<li>If you are running a 1.3 JVM, download JSSE 1.0.3 (or later) from
+   <a href="http://java.sun.com/products/jsse/">http://java.sun.com/products/jsse/</a>
+   and either make it an <em>installed extension</em> on the system, or else
+   set an environment variable <code>JSSE_HOME</code> that points at the
+   directory into which you installed JSSE.  </li><br/><br/>
+<li>Create a certificate keystore by executing the following command:
+<p>Windows:</p>
+<source>
+%JAVA_HOME%\bin\keytool -genkey -alias tomcat -keyalg RSA
+</source>
+<p>Unix:</p>
+<source>
+$JAVA_HOME/bin/keytool -genkey -alias tomcat -keyalg RSA
+</source>
+<p></p>
+    and specify a password value of "changeit".</li><br/><br/>
+<li>Uncomment the "SSL HTTP/1.1 Connector" entry in
+    <code>$CATALINA_HOME/conf/server.xml</code> and tweak as necessary.</li>
+    <br/><br/>
+</ol>
+
+
+</section>
+
+
+<section name="Introduction to SSL">
+
+<p>SSL, or Secure Socket Layer, is a technology which allows web browsers and
+web servers to communicate over a secured connection.  This means that the data
+being sent is encrypted by one side, transmitted, then decrypted by the other
+side before processing.  This is a two-way process, meaning that both the
+server AND the browser encrypt all traffic before sending out data.</p>
+
+<p>Another important aspect of the SSL protocol is Authentication.  This means
+that during your initial attempt to communicate with a web server over a secure
+connection, that server will present your web browser with a set of
+credentials, in the form of a "Certificate", as proof the site is who and what
+it claims to be.  In certain cases, the server may also request a Certificate
+from your web browser, asking for proof that <em>you</em> are who you claim
+to be.  This is known as "Client Authentication," although in practice this is
+used more for business-to-business (B2B) transactions than with individual
+users.  Most SSL-enabled web servers do not request Client Authentication.</p>
+
+</section>
+
+<section name="SSL and Tomcat">
+
+<p>It is important to note that configuring Tomcat to take advantage of
+secure sockets is usually only necessary when running it as a stand-alone
+web server.  When running Tomcat primarily as a Servlet/JSP container behind
+another web server, such as Apache or Microsoft IIS, it is usually necessary
+to configure the primary web server to handle the SSL connections from users.
+Typically, this server will negotiate all SSL-related functionality, then
+pass on any requests destined for the Tomcat container only after decrypting
+those requests.  Likewise, Tomcat will return cleartext responses, that will
+be encrypted before being returned to the user's browser.  In this environment,
+Tomcat knows that communications between the primary web server and the
+client are taking place over a secure connection (because your application
+needs to be able to ask about this), but it does not participate in the
+encryption or decryption itself.</p>
+
+</section>
+
+<section name="Certificates">
+
+<p>In order to implement SSL, a web server must have an associated Certificate
+for each external interface (IP address) that accepts secure connections.
+The theory behind this design is that a server should provide some kind of
+reasonable assurance that its owner is who you think it is, particularly
+before receiving any sensitive information.  While a broader explanation of
+Certificates is beyond the scope of this document, think of a Certificate
+as a "digital driver's license" for an Internet address.  It states what
+company the site is associated with, along with some basic contact
+information about the site owner or administrator.</p>
+
+<p>This "driver's license" is cryptographically signed by its owner, and is
+therefore extremely difficult for anyone else to forge.  For sites involved
+in e-commerce, or any other business transaction in which authentication of
+identity is important, a Certificate is typically purchased from a well-known
+<em>Certificate Authority</em> (CA) such as VeriSign or Thawte.  Such
+certificates can be electronically verified -- in effect, the Certificate
+Authority will vouch for the authenticity of the certificates that it grants,
+so you can believe that that Certificate is valid if you trust the Certificate
+Authority that granted it.</p>
+
+<p>In many cases, however, authentication is not really a concern.  An
+administrator may simply want to ensure that the data being transmitted and
+received by the server is private and cannot be snooped by anyone who may be
+eavesdropping on the connection.  Fortunately, Java provides a relatively
+simple command-line tool, called <code>keytool</code>, which can easily create
+a "self-signed" Certificate.  Self-signed Certificates are simply user
+generated Certificates which have not been officially registered with any
+well-known CA, and are therefore not really guaranteed to be authentic at all.
+Again, this may or may not even be important, depending on your needs.</p>
+
+</section>
+
+<section name="General Tips on Running SSL">
+
+<p>The first time a user attempts to access a secured page on your site,
+he or she is typically presented with a dialog containing the details of
+the certificate (such as the company and contact name), and asked if he or she
+wishes to accept the Certificate as valid and continue with the transaction.
+Some browsers will provide an option for permanently accepting a given
+Certificate as valid, in which case the user will not be bothered with a
+prompt each time they visit your site.  Other browsers do not provide this
+option.  Once approved by the user, a Certificate will be considered valid
+for at least the entire browser session.</p>
+
+<p>Also, while the SSL protocol was designed to be as efficient as securely
+possible, encryption/decryption is a computationally expensive process from
+a performance standpoint.  It is not strictly necessary to run an entire
+web application over SSL, and indeed a developer can pick and choose which
+pages require a secure connection and which do not.  For a reasonably busy
+site, it is customary to only run certain pages under SSL, namely those
+pages where sensitive information could possibly be exchanged.  This would
+include things like login pages, personal information pages, and shopping
+cart checkouts, where credit card information could possibly be transmitted.
+Any page within an application can be requested over a secure socket by
+simply prefixing the address with <code>https:</code> instead of
+<code>http:</code>.  Any pages which absolutely <strong>require</strong>
+a secure connection should check the protocol type associated with the
+page request and take the appropriate action if <code>https</code> is not
+specified.</p>
+
+<p>Finally, using name-based virtual hosts on a secured connection can be
+problematic.  This is a design limitation of the SSL protocol itself.  The SSL
+handshake, where the client browser accepts the server certificate, must occur
+before the HTTP request is accessed.  As a result, the request information
+containing the virtual host name cannot be determined prior to authentication,
+and it is therefore not possible to assign multiple certificates to a single
+IP address.  If all virtual hosts on a single IP address need to authenticate
+against the same certificate, the addition of multiple virtual hosts should not
+interfere with normal SSL operations on the server.  Be aware, however, that
+most client browsers will compare the server's domain name against the domain
+name listed in the certificate, if any (applicable primarily to official,
+CA-signed certificates).  If the domain names do not match, these browsers will
+display a warning to the client user.  In general, only address-based virtual
+hosts are commonly used with SSL in a production environment.</p>
+
+</section>
+
+<section name="Configuration">
+
+<subsection name="Download and Install JSSE (if needed)">
+<p>Note that JSSE is bundled with Sun's JDK 1.4 and later, so if you're using
+JDK 1.4 and later, you can skip this step.</p>
+
+
+<p>Download the <em>Java Secure Socket Extensions</em> (JSSE) package,
+version 1.0.3 or later, from
+<a href="http://java.sun.com/products/jsse/">http://java.sun.com/products/jsse/</a>.
+If you built Tomcat from source, you have probably already downloaded this
+package.</p>
+
+<p>After expanding the package, there are two ways to make it available to
+Tomcat (choose one or the other):</p>
+<ul>
+<li>Make JSSE an <em>installed extension</em> by copying all three JAR files
+    (<code>jcert.jar</code>, <code>jnet.jar</code>, and <code>jsse.jar</code>)
+    into your <code>$JAVA_HOME/jre/lib/ext</code> directory.</li>
+<li>Create a new environment variable <code>JSSE_HOME</code> that contains
+    the absolute path to the directory into which you unpacked the
+    JSSE binary distribution.</li>
+</ul>
+
+</subsection>
+
+<subsection name="Prepare the Certificate Keystore">
+
+<p>Tomcat currently operates only on <code>JKS</code> or <code>PKCS12</code>
+format keystores.  The <code>JKS</code> format
+is Java's standard "Java KeyStore" format, and is the format created by the
+<code>keytool</code> command-line utility.  This tool is included in the JDK.
+The <code>PKCS12</code> format is an internet standard, and can be manipulated
+via (among other things) OpenSSL and Microsoft's Key-Manager.
+</p>
+
+<p>To import an existing certificate into a JKS keystore, please read the
+documentation (in your JDK documentation package) about <code>keytool</code>.
+Note that openssl often adds a readable comments before the key, <code>keytool</code>does not support that, so remove the openssl comments if they exist before importing the key using <code>keytool</code>.
+</p>
+<p>To import an existing certificate signed by your own CA into a PKCS12 
+keystore using OpenSSL you would execute a command like:
+<source>openssl pkcs12 -export -in mycert.crt -inkey mykey.key \
+                        -out mycert.p12 -name tomcat -CAfile myCA.crt \
+                        -caname root -chain
+</source>
+For more advanced cases, consult the <a href="http://www.openssl.org/">OpenSSL
+documententation</a>.
+</p>
+<p>To create a new keystore from scratch, containing a single self-signed
+Certificate, execute the following from a terminal command line:</p>
+<p>Windows:</p>
+<source>
+%JAVA_HOME%\bin\keytool -genkey -alias tomcat -keyalg RSA
+</source>
+<p>Unix:</p>
+<source>
+$JAVA_HOME/bin/keytool -genkey -alias tomcat -keyalg RSA
+</source>
+
+<p>(The RSA algorithm should be preferred as a secure algorithm, and this
+also ensures general compatibility with other servers and components.)</p>
+
+<p>This command will create a new file, in the home directory of the user
+under which you run it, named "<code>.keystore</code>".  To specify a
+different location or filename, add the <code>-keystore</code> parameter,
+followed by the complete pathname to your keystore file,
+to the <code>keytool</code> command shown above.  You will also need to
+reflect this new location in the <code>server.xml</code> configuration file,
+as described later.  For example:</p>
+<p>Windows:</p>
+<source>
+%JAVA_HOME%\bin\keytool -genkey -alias tomcat -keyalg RSA \
+  -keystore \path\to\my\keystore
+</source>
+<p>Unix:</p>
+<source>
+$JAVA_HOME/bin/keytool -genkey -alias tomcat -keyalg RSA \
+  -keystore /path/to/my/keystore
+</source>
+
+<p>After executing this command, you will first be prompted for the keystore
+password.  The default password used by Tomcat is "<code>changeit</code>"
+(all lower case), although you can specify a custom password if you like.
+You will also need to specify the custom password in the
+<code>server.xml</code> configuration file, as described later.</p>
+
+<p>Next, you will be prompted for general information about this Certificate,
+such as company, contact name, and so on.  This information will be displayed
+to users who attempt to access a secure page in your application, so make
+sure that the information provided here matches what they will expect.</p>
+
+<p>Finally, you will be prompted for the <em>key password</em>, which is the
+password specifically for this Certificate (as opposed to any other
+Certificates stored in the same keystore file).  You <strong>MUST</strong>
+use the same password here as was used for the keystore password itself.
+(Currently, the <code>keytool</code> prompt will tell you that pressing the
+ENTER key does this for you automatically.)</p>
+
+<p>If everything was successful, you now have a keystore file with a
+Certificate that can be used by your server.</p>
+
+<p><strong>Note:</strong> your private key password and keystore password
+should be the same.  If they differ, you will get an error along the lines
+of <code>java.io.IOException: Cannot recover key</code>, as documented in 
+<a href="http://issues.apache.org/bugzilla/show_bug.cgi?id=38217">Bugzilla issue 38217</a>, 
+which contains further references for this issue.</p>
+
+</subsection>
+
+<subsection name="Edit the Tomcat Configuration File">
+
+<p>The final step is to configure your secure socket in the
+<code>$CATALINA_HOME/conf/server.xml</code> file, where
+<code>$CATALINA_HOME</code> represents the directory into which you
+installed Tomcat 5.  An example <code>&lt;Connector&gt;</code> element
+for an SSL connector is included in the default <code>server.xml</code>
+file installed with Tomcat.  It will look something like this:</p>
+<source>
+&lt;-- Define a SSL Coyote HTTP/1.1 Connector on port 8443 --&gt;
+&lt;!--
+&lt;Connector 
+           port="8443" minProcessors="5" maxProcessors="75"
+           enableLookups="true" disableUploadTimeout="true"
+           acceptCount="100" debug="0" scheme="https" secure="true";
+           clientAuth="false" sslProtocol="TLS"/&gt;
+--&gt;
+</source>
+
+<p>You will note that the Connector element itself is commented out by default,
+so you will need to remove the comment tags around it.  Then, you can
+customize the specified attributes as necessary.  For detailed information
+about the various options, consult the
+<a href="config/index.html">Server Configuration Reference</a>.  The
+following discussion covers only those attributes of most interest when
+setting up SSL communication.</p>
+
+<p>The <code>port</code> attribute (default value is 8443) is the TCP/IP
+port number on which Tomcat will listen for secure connections.  You can
+change this to any port number you wish (such as to the default port for
+<code>https</code> communications, which is 443).  However, special setup
+(outside the scope of this document) is necessary to run Tomcat on port
+numbers lower than 1024 on many operating systems.</p>
+
+  <blockquote><em>
+  <p>If you change the port number here, you should also change the
+  value specified for the <code>redirectPort</code> attribute on the
+  non-SSL connector.  This allows Tomcat to automatically redirect
+  users who attempt to access a page with a security constraint specifying
+  that SSL is required, as required by the Servlet 2.4 Specification.</p>
+  </em></blockquote>
+
+<p>There are addional option used to configure the SSL protocol.
+  You may need to add or change the following attribute
+values, depending on how you configured your keystore earlier:</p>
+
+<table border="1">
+  <tr>
+    <th>Attribute</th>
+    <th>Description</th>
+  </tr>
+  <tr>
+    <td><code>clientAuth</code></td>
+    <td>Set this value to <code>true</code> if you want Tomcat to require
+        all SSL clients to present a client Certificate in order to use
+        this socket.  Set this value to <code>want</code> if you want Tomcat
+        to request a client Certificate, but not fail if one isn't presented.
+    </td>
+  </tr>
+  <tr>
+    <td><code>keystoreFile</code></td>
+    <td>Add this attribute if the keystore file you created is not in
+        the default place that Tomcat expects (a file named
+        <code>.keystore</code> in the user home directory under
+        which Tomcat is running).  You can specify an absolute pathname,
+        or a relative pathname that is resolved against the
+        <code>$CATALINA_BASE</code> environment variable.</td>
+  </tr>
+  <tr>
+    <td><code>keystorePass</code></td>
+    <td>Add this element if you used a different keystore (and Certificate)
+        password than the one Tomcat expects (<code>changeit</code>).</td>
+  </tr>
+  <tr>
+    <td><code>keystoreType</code></td>
+    <td>Add this element if using a PKCS12 keystore.  The valid values are
+        <code>JKS</code> and <code>PKCS12</code>.</td>
+  </tr>
+  <tr>
+    <td><code>sslProtocol</code></td>
+    <td>The encryption/decryption protocol to be used on this socket.
+        It is not recommended to change this value if you are using Sun's
+        JVM.  It is reported that IBM's 1.4.1 implementation
+        of the TLS protocol is not compatible with some popular browsers.
+        In this case, use the value <code>SSL</code>.</td>
+  </tr>
+  <tr>
+    <td><code>ciphers</code></td>
+    <td>The comma separated list of encryption ciphers that this socket is 
+        allowed to use.  By default, any available cipher is allowed.</td>
+  </tr>
+  <tr>
+    <td><code>algorithm</code></td>
+    <td>The <code>X509</code> algorithm to use.  This defaults to the Sun 
+        implementation (<code>SunX509</code>).  For IBM JVMs you should use
+        the value <code>IbmX509</code>.  For other vendors, consult the JVM
+        documentation for the correct value.
+    </td>
+  </tr>
+  <tr>
+   <td><code>truststoreFile</code></td>
+   <td>The TrustStore file to use to validate client certificates.</td>
+  </tr>
+  <tr>
+   <td><code>truststorePass</code></td>
+   <td>The password to access the TrustStore.  This defaults to the value
+       of <code>keystorePass</code>.</td>
+  </tr>
+  <tr>
+   <td><code>truststoreType</code></td>
+    <td>Add this element if your are using a different format for the 
+        TrustStore then you are using for the KeyStore.  The valid values are
+        <code>JKS</code> and <code>PKCS12</code>.</td>
+  </tr>
+  <tr>
+   <td><code>keyAlias</code></td>
+    <td>Add this element if your have more than one key in the KeyStore.
+        If the element is not present the first key read in the KeyStore
+        will be used.</td>
+  </tr>
+</table>
+
+<p>After completing these configuration changes, you must restart Tomcat as
+you normally do, and you should be in business.  You should be able to access
+any web application supported by Tomcat via SSL.  For example, try:</p>
+<source>
+https://localhost:8443
+</source>
+
+<p>and you should see the usual Tomcat splash page (unless you have modified
+the ROOT web application).  If this does not work, the following section
+contains some troubleshooting tips.</p>
+
+</subsection>
+
+</section>
+
+<section name="Installing a Certificate from a Certificate Authority">
+<p>To obstain and install a Certificate from a Certificate Authority (like verisign.com, thawte.com 
+or trustcenter.de) you should have read the previous section and then follow these instructions:</p>
+
+<subsection name="Create a local Certificate Signing Request (CSR)">
+<p>In order to obtain a Certificate from the Certificate Authority of your choice 
+you have to create a so called Certificate Signing Request (CSR). That CSR will be used 
+by the Certificate Authority to create a Certificate that will identify your website 
+as "secure". To create a CSR follow these steps:</p>
+<ul>
+<li>Create a local Certificate (as described in the previous section):
+	<source>keytool -genkey -alias tomcat -keyalg RSA \
+	-keystore &lt;your_keystore_filename&gt;</source>
+	Note: In some cases you will have to enter the domain of your website (i.e. <code>www.myside.org</code>)
+	in the field "first- and lastname" in order to create a working Certificate. 
+</li>
+<li>The CSR is then created with:
+	<source>keytool -certreq -keyalg RSA -alias tomcat -file certreq.csr \
+	-keystore &lt;your_keystore_filename&gt;</source>
+</li>
+</ul>
+<p>Now you have a file called <code>certreq.csr</code> that you can submit to the Certificate Authority (look at the
+documentation of the Certificate Authority website on how to do this). In return you get a Certificate.</p>
+</subsection>
+
+<subsection name="Importing the Certificate">
+<p>Now that you have your Certificate you can import it into you local keystore. 
+First of all you have to import a so called Chain Certificate or Root Certificate into your keystore. 
+After that you can procede with importing your Certificate.</p>
+
+<ul>
+<li>Download a Chain Certificate from the Certificate Authority you obtained the Certificate from.<br/>
+	For Verisign.com commercial certificates go to:
+            http://www.verisign.com/support/install/intermediate.html<br/>
+        For Verisign.com trial certificates go to:
+            http://www.verisign.com/support/verisign-intermediate-ca/Trial_Secure_Server_Root/index.html
+	For Trustcenter.de go to:
+            http://www.trustcenter.de/certservices/cacerts/en/en.htm#server<br/>
+	For Thawte.com go to:
+            http://www.thawte.com/certs/trustmap.html<br/>
+</li>
+<li>Import the Chain Certificate into you keystore
+    <source>keytool -import -alias root -keystore &lt;your_keystore_filename&gt; \
+	-trustcacerts -file &lt;filename_of_the_chain_certificate&gt;</source>
+</li>
+<li>And finally import your new Certificate
+	<source>keytool -import -alias tomcat -keystore &lt;your_keystore_filename&gt; \
+	-trustcacerts -file &lt;your_certificate_filename&gt;</source>
+</li>
+</ul>
+</subsection>
+</section>
+
+<section name="Troubleshooting">
+
+<p>Here is a list of common problems that you may encounter when setting up
+SSL communications, and what to do about them.</p>
+
+<ul>
+
+<li>I get "java.security.NoSuchAlgorithmException" errors in my
+    log files.
+    <blockquote>
+    <p>The JVM cannot find the JSSE JAR files.  Follow all of the directions to
+    <a href="#Download and Install JSSE">download and install JSSE</a>.</p>
+    </blockquote></li>
+
+<li>When Tomcat starts up, I get an exception like
+    "java.io.FileNotFoundException: {some-directory}/{some-file} not found".
+    <blockquote>
+    <p>A likely explanation is that Tomcat cannot find the keystore file
+    where it is looking.  By default, Tomcat expects the keystore file to
+    be named <code>.keystore</code> in the user home directory under which
+    Tomcat is running (which may or may not be the same as yours :-).  If
+    the keystore file is anywhere else, you will need to add a
+    <code>keystoreFile</code> attribute to the <code>&lt;Factory&gt;</code>
+    element in the <a href="#Edit the Tomcat Configuration File">Tomcat
+    configuration file</a>.</p>
+    </blockquote></li>
+
+<li>When Tomcat starts up, I get an exception like
+    "java.io.FileNotFoundException:  Keystore was tampered with, or
+    password was incorrect".
+    <blockquote>
+    <p>Assuming that someone has not <em>actually</em> tampered with
+    your keystore file, the most likely cause is that Tomcat is using
+    a different password than the one you used when you created the
+    keystore file.  To fix this, you can either go back and
+    <a href="#Prepare the Certificate Keystore">recreate the keystore
+    file</a>, or you can add or update the <code>keystorePass</code>
+    attribute on the <code>&lt;Connector&gt;</code> element in the
+    <a href="#Edit the Tomcat Configuration File">Tomcat configuration
+    file</a>.  <strong>REMINDER</strong> - Passwords are case sensitive!</p>
+    </blockquote></li>
+
+</ul>
+
+<p>If you are still having problems, a good source of information is the
+<strong>TOMCAT-USER</strong> mailing list.  You can find pointers to archives
+of previous messages on this list, as well as subscription and unsubscription
+information, at
+<a href="http://tomcat.apache.org/lists.html">http://tomcat.apache.org/lists.html</a>.</p>
+
+</section>
+
+<section name="Miscellaneous Tips and Bits">
+
+<p>To access the SSL session ID from the request, use:<br />
+
+  <code>
+    String sslID = (String)request.getAttribute("javax.servlet.request.ssl_session");
+  </code>
+<br />
+For additional discussion on this area, please see
+<a href="http://issues.apache.org/bugzilla/show_bug.cgi?id=22679">Bugzilla</a>.
+</p>
+</section>
+
+</body>
+
+</document>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/status.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/status.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/status.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,123 @@
+<?xml version="1.0"?>
+<!DOCTYPE document [
+  <!ENTITY project SYSTEM "project.xml">
+]>
+<document url="status.html">
+
+  &project;
+
+  <properties>
+    <author email="remm at apache.org">Remy Maucherat</author>
+    <author email="yoavs at apache.org">Yoav Shapira</author>
+    <title>Project Status</title>
+  </properties>
+
+<body>
+  <section name="Preface">
+    <p>
+      This document attempts to convey the current status of Tomcat development
+      in "big picture" terms.  This is not the place to check if an individual
+      bug report has been addressed or when an individual feature will be available.
+    </p>
+    <p>
+      This page is updated roughly once per every couple of Tomcat minor releases,
+      so for day-to-day status you should check the tomcat-user and tomcat-dev mailing
+      lists.  You can always inquire there as to the availability or status of a
+      specific feature or component.
+    </p>
+  </section>
+
+  <section name="Current Status Summary">
+    <p>
+      <b>Tomcat 5.0.27</b> was released on June 17th, 2004.  At that time, the TOMCAT_5_0
+      branch was tagged in CVS, and work on Tomcat 5.5 began.  We have now had several
+      Tomcat 5.5 releases, including a couple of stable ones.  Accordingly, Tomcat 5.5
+      is now the focus on work.  Tomcat 5.0 is in maintenance mode and its releases
+      will become less and less frequent.
+    </p>
+    <p>
+      <b>Tomcat 5.5</b> has several major goals.  They are discussed in the tomcat-dev
+      mailing list's "5.next" thread: 
+      <a href="http://marc.theaimsgroup.com/?l=tomcat-dev&amp;w=2&amp;r=1&amp;s=5.next&amp;q=b">MARC</a>.
+      The status of some of these items is detailed below.  Once 5.5 releases are
+      available, please refer to the Changelog accompanying each release for detailed
+      changes, enhancements, and fixes.
+    </p>
+    <p>
+      <b>Tomcat 4.1.x</b> is no longer actively developed.  It is maintained to address
+      only showstopper, security, and Servlet Specification compliance issues.  Maintenance
+      for Tomcat 4.1.x will likely cease once a stable release or two of Tomcat 5.5 are out.
+      Users of Tomcat 4.1.x are strongly encouraged to upgrade to the latest stable Tomcat
+      5.0 release.
+    </p>
+    <p>
+      <b>Tomcat 4.0.x</b> is relatively old, and not actively maintained or supported.
+      It is strongly recommended that users of these releases upgrade to the latest
+      stable Tomcat 5.0 release or at least the latest stable Tomcat 4.1 release.
+    </p>
+    <p>
+      <b>Tomcat 3.3.x</b> is in roughly the same maintenance mode as Tomcat 4.1.x.
+    </p>
+    <p>
+      <b>Tomcat 3.2</b> and earlier are in roughly the same support state as Tomcat 4.0.x.
+      Users should upgrade to Tomcat 3.3.x or the latest stable Tomcat 5.0.x.
+    </p>
+  </section>
+
+  <section name="How to read the report">
+    
+    <p>
+      The columns in this report contain the following information:
+    <ul>
+      <li><b>Priority</b> - A sense of how important it is to address this 
+        issue in the short term.</li>
+      <li><b>Action Item</b> - Concise description of the action item
+        to be completed.  Where relevant, Java package names of the
+        primary classes involved are listed in [square brackets]</li>
+      <li><b>Volunteers</b> - Login of those developers who
+        have volunteered to assist in the design, implementation, testing, and
+        documentation of this action item's changes to Tomcat.</li>
+    </ul>
+      Developers can nominate
+      themselves to work on particular action items by asking a Committer to 
+      add their name address to those items.  The developers 
+      working on each item should discuss and agree upon the approach to be 
+      used for implementing the item's changes to the project source code 
+      and documentation, prior to completing those changes.  Such discussions 
+      should take place on the tomcat-dev mailing list so that everyone can 
+      stay apprised of what is going on, or chime in if they want to 
+      contribute ideas and suggestions.
+    </p>
+    
+  </section>
+
+  <section name="TODO List">
+
+    <status>
+      <item priority="High" owner="costin">
+        Refactor ClassLoaders for Tomcat 5.5 to allow container plugins.
+      </item>
+      <item priority="Medium" owner="fhanik">
+        Enhance Cluster functionality for Tomcat 5.5.
+      </item>
+      <item priority="Medium" owner="everyone">
+        Continue fixing bugs and updating docs.
+      </item>
+    </status>
+
+  </section>
+
+  <section name="Open bugs">
+    
+    <p>
+      The list of the bugs which are in an unresolved state for Tomcat 5 can be
+      seen 
+      <a href="http://issues.apache.org/bugzilla/buglist.cgi?bug_status=UNCONFIRMED&amp;bug_status=NEW&amp;bug_status=ASSIGNED&amp;bug_status=REOPENED&amp;bug_status=RESOLVED&amp;resolution=LATER&amp;resolution=REMIND&amp;resolution=---&amp;bugidtype=include&amp;product=Tomcat+5&amp;cmdtype=doit&amp;order=Importance">here</a>.
+      Aspiring volunteers and others are strongly encouraged to attempt 
+      to comment and help resolve these issues.
+    </p>
+    
+  </section>
+
+</body>
+</document>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/tomcat-docs.xsl
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/tomcat-docs.xsl	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/tomcat-docs.xsl	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,436 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!-- Content Stylesheet for "tomcat-docs" Documentation -->
+
+<!-- $Id: tomcat-docs.xsl 377243 2006-02-12 21:26:03Z markt $ -->
+
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+  version="1.0">
+
+
+  <!-- Output method -->
+  <xsl:output method="html"
+            encoding="iso-8859-1"
+              indent="no"/>
+
+
+  <!-- Defined parameters (overrideable) -->
+  <xsl:param    name="home-name"        select="'The Tomcat Project'"/>
+  <xsl:param    name="home-href"        select="'http://tomcat.apache.org/'"/>
+  <xsl:param    name="home-logo"        select="'/images/tomcat.gif'"/>
+  <xsl:param    name="printer-logo"     select="'/images/printer.gif'"/>
+  <xsl:param    name="apache-logo"      select="'/images/asf-logo.gif'"/>
+  <xsl:param    name="relative-path"    select="'.'"/>
+  <xsl:param    name="void-image"       select="'/images/void.gif'"/>
+  <xsl:param    name="project-menu"     select="'menu'"/>
+  <xsl:param    name="standalone"       select="''"/>
+  <xsl:param    name="buglink"          select="'http://issues.apache.org/bugzilla/show_bug.cgi?id='"/>
+
+  <!-- Defined variables (non-overrideable) -->
+  <xsl:variable name="body-bg"          select="'#ffffff'"/>
+  <xsl:variable name="body-fg"          select="'#000000'"/>
+  <xsl:variable name="body-link"        select="'#525D76'"/>
+  <xsl:variable name="banner-bg"        select="'#525D76'"/>
+  <xsl:variable name="banner-fg"        select="'#ffffff'"/>
+  <xsl:variable name="sub-banner-bg"    select="'#828DA6'"/>
+  <xsl:variable name="sub-banner-fg"    select="'#ffffff'"/>
+  <xsl:variable name="source-color"     select="'#023264'"/>
+  <xsl:variable name="attributes-color" select="'#023264'"/>
+  <xsl:variable name="table-th-bg"      select="'#039acc'"/>
+  <xsl:variable name="table-td-bg"      select="'#a0ddf0'"/>
+
+  <!-- Process an entire document into an HTML page -->
+  <xsl:template match="document">
+  <xsl:variable name="project"
+              select="document('project.xml')/project"/>
+    <html>
+    <head>
+    <title><xsl:value-of select="project/title"/> - <xsl:value-of select="properties/title"/></title>
+    <xsl:for-each select="properties/author">
+      <xsl:variable name="name">
+        <xsl:value-of select="."/>
+      </xsl:variable>
+      <xsl:variable name="email">
+        <xsl:value-of select="@email"/>
+      </xsl:variable>
+      <meta name="author" value="{$name}"/>
+      <meta name="email" value="{$email}"/>
+    </xsl:for-each>
+    </head>
+
+    <body bgcolor="{$body-bg}" text="{$body-fg}" link="{$body-link}"
+          alink="{$body-link}" vlink="{$body-link}">
+
+    <table border="0" width="100%" cellspacing="0">
+
+      <xsl:comment>PAGE HEADER</xsl:comment>
+      <tr>
+        <td>
+        <xsl:if test="project/logo">
+          <xsl:variable name="alt">
+            <xsl:value-of select="project/logo"/>
+          </xsl:variable>
+          <xsl:variable name="home">
+            <xsl:value-of select="project/@href"/>
+          </xsl:variable>
+          <xsl:variable name="src">
+            <xsl:value-of select="$relative-path"/><xsl:value-of select="project/logo/@href"/>
+          </xsl:variable>
+
+          <xsl:comment>PROJECT LOGO</xsl:comment>
+          <a href="{$home}">
+            <img src="{$src}" align="right" alt="{$alt}" border="0"/>
+          </a>
+        </xsl:if>
+        </td>
+        <td>
+          <font face="arial,helvetica,sanserif">
+            <h1><xsl:value-of select="$project/title"/></h1>
+          </font>
+        </td>
+        <td>
+          <xsl:comment>APACHE LOGO</xsl:comment>
+          <xsl:variable name="src">
+            <xsl:value-of select="$relative-path"/><xsl:value-of select="$apache-logo"/>
+          </xsl:variable>
+          <a href="http://www.apache.org/">
+            <img src="{$src}" align="right" alt="Apache Logo" border="0"/>
+          </a>
+        </td>
+      </tr>
+    </table>
+
+    <table border="0" width="100%" cellspacing="4">
+
+      <xsl:comment>HEADER SEPARATOR</xsl:comment>
+      <tr>
+        <td colspan="2">
+          <hr noshade="noshade" size="1"/>
+        </td>
+      </tr>
+
+      <tr>
+
+        <!-- Don't generate a menu if styling printer friendly docs -->
+        <xsl:if test="$project-menu = 'menu'">
+          <xsl:comment>LEFT SIDE NAVIGATION</xsl:comment>
+          <td width="20%" valign="top" nowrap="true">
+            <xsl:apply-templates select="project/body/menu"/>
+          </td>
+        </xsl:if>
+
+        <xsl:comment>RIGHT SIDE MAIN BODY</xsl:comment>
+        <td width="80%" valign="top" align="left">
+          <table border="0" width="100%" cellspacing="4">
+            <tr>
+              <td align="left" valign="top">
+                <h1><xsl:value-of select="project/title"/></h1>
+                <h2><xsl:value-of select="properties/title"/></h2>
+              </td>
+              <td align="right" valign="top" nowrap="true">
+                <!-- Add the printer friendly link for docs with a menu -->
+                <xsl:if test="$project-menu = 'menu'">
+                  <xsl:variable name="src">
+                    <xsl:value-of select="$relative-path"/><xsl:value-of select="$printer-logo"/>
+                  </xsl:variable>
+                  <xsl:variable name="url">
+                    <xsl:value-of select="/document/@url"/>
+                  </xsl:variable>
+                  <small>
+                    <a href="printer/{$url}">
+                      <img src="{$src}" border="0" alt="Printer Friendly Version"/>
+                      <br />print-friendly<br />version
+                    </a>
+                  </small>
+                </xsl:if>
+                <xsl:if test="$project-menu != 'menu'">
+                  <xsl:variable name="void">
+                    <xsl:value-of select="$relative-path"/><xsl:value-of select="$void-image"/>
+                    </xsl:variable>
+                  <img src="{$void}" width="1" height="1" vspace="0" hspace="0" border="0"/>
+                </xsl:if>
+              </td>
+            </tr>
+          </table>
+          <xsl:apply-templates select="body/section"/>
+        </td>
+
+      </tr>
+
+      <xsl:comment>FOOTER SEPARATOR</xsl:comment>
+      <tr>
+        <td colspan="2">
+          <hr noshade="noshade" size="1"/>
+        </td>
+      </tr>
+
+      <xsl:comment>PAGE FOOTER</xsl:comment>
+      <tr><td colspan="2">
+        <div align="center"><font color="{$body-link}" size="-1"><em>
+        Copyright &#169; 1999-2006, Apache Software Foundation
+        </em></font></div>
+      </td></tr>
+
+    </table>
+    </body>
+    </html>
+
+  </xsl:template>
+
+
+  <!-- Process a menu for the navigation bar -->
+  <xsl:template match="menu">
+    <p><strong><xsl:value-of select="@name"/></strong></p>
+    <ul>
+      <xsl:apply-templates select="item"/>
+    </ul>
+  </xsl:template>
+
+
+  <!-- Process a menu item for the navigation bar -->
+  <xsl:template match="item">
+    <xsl:variable name="href">
+      <xsl:value-of select="@href"/>
+    </xsl:variable>
+    <li><a href="{$href}"><xsl:value-of select="@name"/></a></li>
+  </xsl:template>
+
+
+  <!-- Process a documentation section -->
+  <xsl:template match="section">
+    <xsl:variable name="name">
+      <xsl:value-of select="@name"/>
+    </xsl:variable>
+    <table border="0" cellspacing="0" cellpadding="2">
+      <!-- Section heading -->
+      <tr><td bgcolor="{$banner-bg}">
+          <font color="{$banner-fg}" face="arial,helvetica.sanserif">
+          <a name="{$name}">
+          <strong><xsl:value-of select="@name"/></strong></a></font>
+      </td></tr>
+      <!-- Section body -->
+      <tr><td><blockquote>
+        <xsl:apply-templates/>
+      </blockquote></td></tr>
+    </table>
+  </xsl:template>
+
+
+  <!-- Process a documentation subsection -->
+  <xsl:template match="subsection">
+    <xsl:variable name="name">
+      <xsl:value-of select="@name"/>
+    </xsl:variable>
+    <table border="0" cellspacing="0" cellpadding="2">
+      <!-- Subsection heading -->
+      <tr><td bgcolor="{$sub-banner-bg}">
+          <font color="{$sub-banner-fg}" face="arial,helvetica.sanserif">
+          <a name="{$name}">
+          <strong><xsl:value-of select="@name"/></strong></a></font>
+      </td></tr>
+      <!-- Subsection body -->
+      <tr><td><blockquote>
+        <xsl:apply-templates/>
+      </blockquote></td></tr>
+    </table>
+  </xsl:template>
+
+
+  <!-- Process a source code example -->
+  <xsl:template match="source">
+    <xsl:variable name="void">
+      <xsl:value-of select="$relative-path"/><xsl:value-of select="$void-image"/>
+    </xsl:variable>
+    <div align="left">
+      <table cellspacing="4" cellpadding="0" border="0">
+        <tr>
+          <td bgcolor="{$source-color}" width="1" height="1">
+            <img src="{$void}" width="1" height="1" vspace="0" hspace="0" border="0"/>
+          </td>
+          <td bgcolor="{$source-color}" height="1">
+            <img src="{$void}" width="1" height="1" vspace="0" hspace="0" border="0"/>
+          </td>
+          <td bgcolor="{$source-color}" width="1" height="1">
+            <img src="{$void}" width="1" height="1" vspace="0" hspace="0" border="0"/>
+          </td>
+        </tr>
+        <tr>
+          <td bgcolor="{$source-color}" width="1">
+            <img src="{$void}" width="1" height="1" vspace="0" hspace="0" border="0"/>
+          </td>
+          <td bgcolor="#ffffff" height="1"><pre>
+            <xsl:value-of select="."/>
+          </pre></td>
+          <td bgcolor="{$source-color}" width="1">
+            <img src="{$void}" width="1" height="1" vspace="0" hspace="0" border="0"/>
+          </td>
+        </tr>
+        <tr>
+          <td bgcolor="{$source-color}" width="1" height="1">
+            <img src="{$void}" width="1" height="1" vspace="0" hspace="0" border="0"/>
+          </td>
+          <td bgcolor="{$source-color}" height="1">
+            <img src="{$void}" width="1" height="1" vspace="0" hspace="0" border="0"/>
+          </td>
+          <td bgcolor="{$source-color}" width="1" height="1">
+            <img src="{$void}" width="1" height="1" vspace="0" hspace="0" border="0"/>
+          </td>
+        </tr>
+      </table>
+    </div>
+  </xsl:template>
+
+
+  <!-- Process an attributes list with nested attribute elements -->
+  <xsl:template match="attributes">
+    <table border="1" cellpadding="5">
+      <tr>
+        <th width="15%" bgcolor="{$attributes-color}">
+          <font color="#ffffff">Attribute</font>
+        </th>
+        <th width="85%" bgcolor="{$attributes-color}">
+          <font color="#ffffff">Description</font>
+        </th>
+      </tr>
+      <xsl:for-each select="attribute">
+        <tr>
+          <td align="left" valign="center">
+            <xsl:if test="@required = 'true'">
+              <strong><code><xsl:value-of select="@name"/></code></strong>
+            </xsl:if>
+            <xsl:if test="@required != 'true'">
+              <code><xsl:value-of select="@name"/></code>
+            </xsl:if>
+          </td>
+          <td align="left" valign="center">
+            <xsl:apply-templates/>
+          </td>
+        </tr>
+      </xsl:for-each>
+    </table>
+  </xsl:template>
+
+  <!-- Fix relative links in printer friendly versions of the docs -->
+  <xsl:template match="a">
+    <xsl:variable name="href" select="@href"/>
+    <xsl:choose>
+      <xsl:when test="$standalone = 'standalone'">
+        <xsl:apply-templates/>
+      </xsl:when>
+      <xsl:when test="$project-menu != 'menu' and starts-with(@href,'../')">
+        <a href="../{$href}"><xsl:apply-templates/></a>
+      </xsl:when>
+      <xsl:when test="$project-menu != 'menu' and starts-with(@href,'./') and contains(substring(@href,3),'/')">
+        <a href=".{$href}"><xsl:apply-templates/></a>
+      </xsl:when>
+      <xsl:when test="$project-menu != 'menu' and not(contains(@href,'//')) and not(starts-with(@href,'/')) and not(starts-with(@href,'#')) and contains(@href,'/')">
+        <a href="../{$href}"><xsl:apply-templates/></a>
+      </xsl:when>
+      <xsl:when test="$href != ''">
+        <a href="{$href}"><xsl:apply-templates/></a>
+      </xsl:when>
+      <xsl:otherwise>
+        <xsl:variable name="name" select="@name"/>
+        <a name="{$name}"><xsl:apply-templates/></a>
+      </xsl:otherwise>
+    </xsl:choose>
+  </xsl:template>
+
+  <!-- Changelog related tags -->
+  <xsl:template match="changelog">
+    <table border="0" cellpadding="2" cellspacing="2">
+      <xsl:apply-templates/>
+    </table>
+  </xsl:template>
+
+  <xsl:template match="changelog/add">
+    <tr>
+      <xsl:variable name="src"><xsl:value-of select="$relative-path"/>/images/add.gif</xsl:variable>
+      <td><img alt="add" class="icon" src="{$src}"/></td>
+      <td><xsl:apply-templates/></td>
+    </tr>
+  </xsl:template>
+
+  <xsl:template match="changelog/update">
+    <tr>
+      <xsl:variable name="src"><xsl:value-of select="$relative-path"/>/images/update.gif</xsl:variable>
+      <td><img alt="update" class="icon" src="{$src}"/></td>
+      <td><xsl:apply-templates/></td>
+    </tr>
+  </xsl:template>
+
+  <xsl:template match="changelog/design">
+    <tr>
+      <xsl:variable name="src"><xsl:value-of select="$relative-path"/>/images/design.gif</xsl:variable>
+      <td><img alt="design" class="icon" src="{$src}"/></td>
+      <td><xsl:apply-templates/></td>
+    </tr>
+  </xsl:template>
+
+  <xsl:template match="changelog/docs">
+    <tr>
+      <xsl:variable name="src"><xsl:value-of select="$relative-path"/>/images/docs.gif</xsl:variable>
+      <td><img alt="docs" class="icon" src="{$src}"/></td>
+      <td><xsl:apply-templates/></td>
+    </tr>
+  </xsl:template>
+
+  <xsl:template match="changelog/fix">
+    <tr>
+      <xsl:variable name="src"><xsl:value-of select="$relative-path"/>/images/fix.gif</xsl:variable>
+      <td><img alt="fix" class="icon" src="{$src}"/></td>
+      <td><xsl:apply-templates/></td>
+    </tr>
+  </xsl:template>
+
+  <xsl:template match="changelog/scode">
+    <tr>
+      <xsl:variable name="src"><xsl:value-of select="$relative-path"/>/images/code.gif</xsl:variable>
+      <td><img alt="code" class="icon" src="{$src}"/></td>
+      <td><xsl:apply-templates/></td>
+    </tr>
+  </xsl:template>
+
+  <!-- Process an attributes list with nested attribute elements -->
+  <xsl:template match="status">
+    <table border="1" cellpadding="5">
+      <tr>
+        <th width="15%" bgcolor="{$attributes-color}">
+          <font color="#ffffff">Priority</font>
+        </th>
+        <th width="50%" bgcolor="{$attributes-color}">
+          <font color="#ffffff">Action Item</font>
+        </th>
+        <th width="25%" bgcolor="{$attributes-color}">
+          <font color="#ffffff">Volunteers</font>
+        </th>
+        <xsl:for-each select="item">
+        <tr>
+          <td align="left" valign="center">
+            <xsl:value-of select="@priority"/>
+          </td>
+          <td align="left" valign="center">
+            <xsl:apply-templates/>
+          </td>
+          <td align="left" valign="center">
+            <xsl:value-of select="@owner"/>
+          </td>
+        </tr>
+        </xsl:for-each>
+      </tr>
+    </table>
+  </xsl:template>
+
+  <!-- Link to a bug report -->
+  <xsl:template match="bug">
+      <xsl:variable name="link"><xsl:value-of select="$buglink"/><xsl:value-of select="text()"/></xsl:variable>
+      <a href="{$link}"><xsl:apply-templates/></a>
+  </xsl:template>
+
+  <!-- Process everything else by just passing it through -->
+  <xsl:template match="*|@*">
+    <xsl:copy>
+      <xsl:apply-templates select="@*|*|text()"/>
+    </xsl:copy>
+  </xsl:template>
+
+</xsl:stylesheet>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/windows-service-howto.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/windows-service-howto.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/docs/windows-service-howto.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,352 @@
+<?xml version="1.0"?>
+<!DOCTYPE document [
+  <!ENTITY project SYSTEM "project.xml">
+]>
+<document url="windows-service-howto.html">
+
+    &project;
+
+    <properties>
+      <author email="mturk at apache.org">Mladen Turk</author>
+      <title>Windows service HOW-TO</title>
+    </properties>
+
+<body>
+ 
+<section name="NOTICE">
+<p>
+    <b>This section of the documentation applies to procrun 1.0, and is now obsolete.</b>
+</p>
+</section>
+<section name="Tomcat5 service application">
+<p>
+    <b>Tomcat5</b> is a service application for running Tomcat5 as NT service.
+</p>
+</section>
+<section name="Tomcat5w monitor application">
+<p>
+    <b>Tomcat5w</b> is a GUI application for monitoring and configuring Tomcat
+    services.
+</p>    
+    <p>The available command line options are:</p>
+<p> 
+    <table>
+    <tr><th>//ES//</th>
+        <td>Edit service configuration</td>
+        <td>This is the default operation. It is called if the no option is
+            provided but the executable is renamed to <b>servicenameW.exe</b></td>
+    </tr>
+    <tr><th>//MS//</th>
+        <td>Monitor service</td>
+        <td>Put the icon in the system try</td>
+    </tr>
+    </table>
+</p>
+</section>
+<section name="Command line arguments">
+<p>
+    Each command line directive is in the form of <b>//XX//ServiceName</b>
+</p>
+    <p>The available command line options are:</p>
+<p> 
+    <table>
+    <tr><th>//TS//</th>
+        <td>Run the service as console application</td>
+        <td>This is the default operation. It is called if the no option is
+            provided. The ServiceName is the name of the executable without
+            exe sufix, meaning Tomcat5</td>
+    </tr>
+    <tr><th>//RS//</th>
+        <td>Run the service</td>
+        <td>Called only from ServiceManager</td>
+    </tr>
+    <tr><th>//SS//</th>
+        <td>Stop the service</td>
+        <td></td>
+    </tr>
+    <tr><th>//US//</th>
+        <td>Update service parameters</td>
+        <td></td>
+    </tr>
+    <tr><th>//IS//</th>
+        <td>Install service</td>
+        <td></td>
+    </tr>
+    <tr><th>//DS//</th>
+        <td>Delete service</td>
+        <td>Stops the service if running</td>
+    </tr>        
+    </table>
+</p> 
+</section>
+<section name="Command line parameters">
+<p>
+    Each command parameter is prefixed with <b>--</b>.
+    If the command line is prefixed with <b>++</b> then it's value will
+    be appended to the existing option.
+    If the environment variable with the same name as command line parameter but
+    prefixed with <code>PR_</code> exists it will take precedence.
+    For example:
+<source>set PR_CLASSPATH=xx.jar</source>
+</p>    
+<p>is equivalent to providing
+<source>--Classpath=xx.jar</source>
+</p>
+<p> as command line parameter.</p>
+<p> 
+    <table>
+    <tr>
+    <th>ParameterName</th>
+	<th>Default</th>
+	<th>Description</th>
+	</tr> 
+    <tr>
+    <td>--Description</td>
+    <td></td>
+    <td>Service name description (maximum 1024 characters)</td>
+    </tr>
+    <tr>
+    <td>--DisplayName</td>
+    <td>ServiceName</td>
+    <td>Service display name</td>
+    </tr>
+    <tr>
+    <td>--Install</td>
+    <td>procrun.exe //RS//ServiceName</td>
+    <td>Install image</td>
+    </tr>
+    <tr>
+    <td>--Startup</td>
+    <td>manual</td>
+    <td>Service startup mode can be either <b>auto</b> or <b>manual</b></td>
+    </tr>
+    <tr>
+    <td>--DependsOn</td>
+    <td></td>
+    <td>List of services that this service depend on. Dependent services
+        are separated using either <b>#</b> or <b>;</b> characters</td>
+    </tr>
+    <tr>
+    <td>--Environment</td>
+    <td></td>
+    <td>List of environment variables that will be provided to the service
+        in the form <b>key=value</b>. They are separated using either
+        <b>#</b> or <b>;</b> characters</td>
+    </tr>
+    <tr>
+    <td>--User</td>
+    <td></td>
+    <td>User account used for running executable. It is used only for
+    	StartMode <b>java</b> or <b>exe</b> and enables running applications
+    	as service under account without LogonAsService privilege.</td>
+    </tr>
+    <tr>
+    <td>--Password</td>
+    <td></td>
+    <td>Password for user account set by --User parameter</td>
+    </tr>
+    <tr>
+    <td>--JavaHome</td>
+    <td>JAVA_HOME</td>
+    <td>Set a different JAVA_HOME then defined by JAVA_HOME environment
+        variable</td>
+    </tr>
+    <tr>
+    <td>--Jvm</td>
+    <td>auto</td>
+    <td>Use either <b>auto</b> or specify the full path to the <b>jvm.dll</b>.
+        You can use the environment variable expansion here.</td>
+    </tr>
+    <tr>
+    <td>--JvmOptions</td>
+    <td>-Xrs</td>
+    <td>List of options in the form of <b>-D</b> or <b>-X</b> that will be
+        passed to the JVM. The options are separated using either
+        <b>#</b> or <b>;</b> characters.</td>
+    </tr>
+    <tr>
+    <td>--Classpath</td>
+    <td></td>
+    <td>Set the Java classpath</td>
+    </tr>
+    <tr>
+    <td>--JvmMs</td>
+    <td></td>
+    <td>Initial memory pool size in MB</td>
+    </tr>
+    <tr>
+    <td>--JvmMx</td>
+    <td></td>
+    <td>Maximum memory pool size in MB</td>
+    </tr>
+    <tr>
+    <td>--JvmSs</td>
+    <td></td>
+    <td>Thread stack size in KB</td>
+    </tr>
+    <tr>
+    <tr>
+    <td>--StartImage</td>
+    <td></td>
+    <td>Executable that will be run.</td>
+    </tr>
+    <tr>
+    <td>--StartPath</td>
+    <td></td>
+    <td>Working path for the start image executable.</td>
+    </tr>
+    <tr>
+    <td>--StartClass</td>
+    <td></td>
+    <td>Class that will be used for startup.</td>
+    </tr>
+    <tr>
+    <td>--StartParams</td>
+    <td></td>
+    <td>List of parameters that will be passed to either StartImage or
+        StartClass. Parameters are separated using either <b>#</b> or
+        <b>;</b> character.</td>
+    </tr>
+    <tr>
+    <td>--StartMethod</td>
+    <td>Main</td>
+    <td>Method name if differs then main</td>
+    </tr>
+    <tr>
+    <td>--StartMode</td>
+    <td>executable</td>
+    <td>Can one of <b>jvm</b> <b>java</b> or <b>exe</b></td>
+    </tr>
+    <td>--StopImage</td>
+    <td></td>
+    <td>Executable that will be run on Stop service signal.</td>
+    </tr>
+    <tr>
+    <td>--StopPath</td>
+    <td></td>
+    <td>Working path for the stop image executable.</td>
+    </tr>
+    <tr>
+    <td>--StopClass</td>
+    <td></td>
+    <td>Class that will be used on Stop service signal.</td>
+    </tr>
+    <tr>
+    <td>--StopParams</td>
+    <td></td>
+    <td>List of parameters that will be passed to either StopImage or
+        StopClass. Parameters are separated using either <b>#</b> or
+        <b>;</b> character.</td>
+    </tr>
+    <tr>
+    <td>--StopMethod</td>
+    <td>Main</td>
+    <td>Method name if differs then main</td>
+    </tr>
+    <tr>
+    <td>--StopMode</td>
+    <td>executable</td>
+    <td>Can one of <b>jvm</b> <b>java</b> or <b>exe</b></td>
+    </tr>
+    <tr>
+    <td>--StopTimeout</td>
+    <td>No Timeout</td>
+    <td>Defines the timeout in seconds that procrun waits for service to
+        exit gracefully.</td>
+    </tr>
+    <tr>
+    <td>--LogPath</td>
+    <td>working path</td>
+    <td>Defines the path for logging</td>
+    </tr>
+    <tr>
+    <td>--LogPrefix</td>
+    <td>jakarta_service</td>
+    <td>Defines the service log filename</td>
+    </tr>
+    <tr>
+    <td>--LogLevel</td>
+    <td>INFO</td>
+    <td>Defines the logging level and can be either <b>error</b>,
+        <b>info</b>, <b>warn</b> or <b>debug</b></td>
+    </tr>
+    <tr>
+    <td>--StdOutput</td>
+    <td></td>
+    <td>Redirected stdout filename</td>
+    </tr>
+    <tr>
+    <td>--StdError</td>
+    <td></td>
+    <td>Redirected stderr filename</td>
+    </tr>    
+    </table>
+</p> 
+</section>
+<section name="Installing services">
+<p>
+The safest way to manually install the service is to use the provided <b>service.bat</b> script.
+</p>
+<p>
+<source>
+Install the service named 'Tomcat5'
+C:\> service.bat install
+</source>
+</p>
+<p>
+If using tomcat5.exe, you need to use the <b>//IS//</b> parameter.
+</p>
+<p>
+<source>
+Install the service named 'Tomcat5'
+C:\> tomcat5 //IS//Tomcat5 --DisplayName="Apache Tomcat 5" \
+C:\> --Install="C:\Program Files\Tomcat\bin\tomcat5.exe" --Jvm=auto \
+C:\> --StartMode=jvm --StopMode=jvm \
+C:\> --StartClass=org.apache.catalina.startup.Bootstrap --StartParams=start \
+C:\> --StopClass=org.apache.catalina.startup.Bootstrap --StopParams=stop
+</source>
+</p>
+</section>
+<section name="Updating services">
+<p>
+To update the service parameters, you need to use the <b>//US//</b> parameter.
+</p>
+<p>
+<source>
+Update the service named 'Tomcat5
+C:\> tomcat5 //US//Tomcat5 --Description="Apache Tomcat Server - http://tomcat.apache.org/ " \
+C:\> --Startup=auto --Classpath=%JAVA_HOME%\lib\tools.jar;%CATALINA_HOME%\bin\bootstrap.jar
+</source>
+</p>
+</section>
+<section name="Removing services">
+<p>
+To remove the service, you need to use the <b>//DS//</b> parameter.<br/>
+If the service is running it will be stopped and then deleted.
+</p>
+<p>
+<source>
+Remove the service named 'Tomcat5'
+C:\> tomcat5 //DS//Tomcat5
+</source>
+</p>
+</section>
+<section name="Debugging services">
+<p>
+To run the service in console mode, you need to use the <b>//TS//</b> parameter.
+The service shutdown can be initiated by pressing <b>CTRL+C</b> or
+<b>CTRL+BREAK</b>.
+If you rename the tomcat5.exe to testservice.exe then you can just execute the
+testservice.exe and this command mode will be executed by default.
+</p>
+<p>
+<source>
+Run the service named 'Tomcat5' in console mode
+C:\> tomcat5 //TS//Tomcat5 [additional arguments]
+Or simply execute:
+C:\> tomcat5
+</source>
+</p>
+</section>
+</body>
+</document> 

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/host-manager/WEB-INF/classes/org/apache/catalina/hostmanager/Constants.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/host-manager/WEB-INF/classes/org/apache/catalina/hostmanager/Constants.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/host-manager/WEB-INF/classes/org/apache/catalina/hostmanager/Constants.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,203 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.hostmanager;
+
+
+public class Constants {
+
+    public static final String Package = "org.apache.catalina.hostmanager";
+
+    public static final String HTML_HEADER_SECTION =
+        "<html>\n" +
+        "<head>\n" +
+        "<style>\n" +
+        org.apache.catalina.util.TomcatCSS.TOMCAT_CSS +
+        "  table {\n" +
+        "    width: 100%;\n" +
+        "  }\n" +
+        "  td.page-title {\n" +
+        "    text-align: center;\n" +
+        "    vertical-align: top;\n" +
+        "    font-family:sans-serif,Tahoma,Arial;\n" +
+        "    font-weight: bold;\n" +
+        "    background: white;\n" +
+        "    color: black;\n" +
+        "  }\n" +
+        "  td.title {\n" +
+        "    text-align: left;\n" +
+        "    vertical-align: top;\n" +
+        "    font-family:sans-serif,Tahoma,Arial;\n" +
+        "    font-style:italic;\n" +
+        "    font-weight: bold;\n" +
+        "    background: #D2A41C;\n" +
+        "  }\n" +
+        "  td.header-left {\n" +
+        "    text-align: left;\n" +
+        "    vertical-align: top;\n" +
+        "    font-family:sans-serif,Tahoma,Arial;\n" +
+        "    font-weight: bold;\n" +
+        "    background: #FFDC75;\n" +
+        "  }\n" +
+        "  td.header-center {\n" +
+        "    text-align: center;\n" +
+        "    vertical-align: top;\n" +
+        "    font-family:sans-serif,Tahoma,Arial;\n" +
+        "    font-weight: bold;\n" +
+        "    background: #FFDC75;\n" +
+        "  }\n" +
+        "  td.row-left {\n" +
+        "    text-align: left;\n" +
+        "    vertical-align: middle;\n" +
+        "    font-family:sans-serif,Tahoma,Arial;\n" +
+        "    color: black;\n" +
+        "    background: white;\n" +
+        "  }\n" +
+        "  td.row-center {\n" +
+        "    text-align: center;\n" +
+        "    vertical-align: middle;\n" +
+        "    font-family:sans-serif,Tahoma,Arial;\n" +
+        "    color: black;\n" +
+        "    background: white;\n" +
+        "  }\n" +
+        "  td.row-right {\n" +
+        "    text-align: right;\n" +
+        "    vertical-align: middle;\n" +
+        "    font-family:sans-serif,Tahoma,Arial;\n" +
+        "    color: black;\n" +
+        "    background: white;\n" +
+        "  }\n" +
+        "  TH {\n" +
+        "    text-align: center;\n" +
+        "    vertical-align: top;\n" +
+        "    font-family:sans-serif,Tahoma,Arial;\n" +
+        "    font-weight: bold;\n" +
+        "    background: #FFDC75;\n" +
+        "  }\n" +
+        "  TD {\n" +
+        "    text-align: center;\n" +
+        "    vertical-align: middle;\n" +
+        "    font-family:sans-serif,Tahoma,Arial;\n" +
+        "    color: black;\n" +
+        "    background: white;\n" +
+        "  }\n" +
+        "</style>\n";
+
+    public static final String BODY_HEADER_SECTION =
+        "<title>{0}</title>\n" +
+        "</head>\n" +
+        "\n" +
+        "<body bgcolor=\"#FFFFFF\">\n" +
+        "\n" +
+        "<table cellspacing=\"4\" width=\"100%\" border=\"0\">\n" +
+        " <tr>\n" +
+        "  <td colspan=\"2\">\n" +
+        "   <a href=\"http://www.apache.org/\">\n" +
+        "    <img border=\"0\" alt=\"The Apache Software Foundation\" align=\"left\"\n" +
+        "         src=\"{0}/images/asf-logo.gif\">\n" +
+        "   </a>\n" +
+        "   <a href=\"http://tomcat.apache.org/\">\n" +
+        "    <img border=\"0\" alt=\"The Tomcat Servlet/JSP Container\"\n" +
+        "         align=\"right\" src=\"{0}/images/tomcat.gif\">\n" +
+        "   </a>\n" +
+        "  </td>\n" +
+        " </tr>\n" +
+        "</table>\n" +
+        "<hr size=\"1\" noshade=\"noshade\">\n" +
+        "<table cellspacing=\"4\" width=\"100%\" border=\"0\">\n" +
+        " <tr>\n" +
+        "  <td class=\"page-title\" bordercolor=\"#000000\" " +
+        "align=\"left\" nowrap>\n" +
+        "   <font size=\"+2\">{1}</font>\n" +
+        "  </td>\n" +
+        " </tr>\n" +
+        "</table>\n" +
+        "<br>\n" +
+        "\n";
+
+    public static final String MESSAGE_SECTION =
+        "<table border=\"1\" cellspacing=\"0\" cellpadding=\"3\">\n" +
+        " <tr>\n" +
+        "  <td class=\"row-left\" width=\"10%\">" +
+        "<small><strong>{0}</strong></small>&nbsp;</td>\n" +
+        "  <td class=\"row-left\"><pre>{1}</pre></td>\n" +
+        " </tr>\n" +
+        "</table>\n" +
+        "<br>\n" +
+        "\n";
+
+    public static final String MANAGER_SECTION =
+        "<table border=\"1\" cellspacing=\"0\" cellpadding=\"3\">\n" +
+        "<tr>\n" +
+        " <td colspan=\"4\" class=\"title\">{0}</td>\n" +
+        "</tr>\n" +
+        " <tr>\n" +
+        "  <td class=\"row-left\"><a href=\"{1}\">{2}</a></td>\n" +
+        "  <td class=\"row-center\"><a href=\"{3}\">{4}</a></td>\n" +
+        "  <td class=\"row-center\"><a href=\"{5}\">{6}</a></td>\n" +
+        "  <td class=\"row-right\"><a href=\"{7}\">{8}</a></td>\n" +
+        " </tr>\n" +
+        "</table>\n" +
+        "<br>\n" +
+        "\n";
+
+    public static final String SERVER_HEADER_SECTION =
+        "<table border=\"1\" cellspacing=\"0\" cellpadding=\"3\">\n" +
+        "<tr>\n" +
+        " <td colspan=\"6\" class=\"title\">{0}</td>\n" +
+        "</tr>\n" +
+        "<tr>\n" +
+        " <td class=\"header-center\"><small>{1}</small></td>\n" +
+        " <td class=\"header-center\"><small>{2}</small></td>\n" +
+        " <td class=\"header-center\"><small>{3}</small></td>\n" +
+        " <td class=\"header-center\"><small>{4}</small></td>\n" +
+        " <td class=\"header-center\"><small>{5}</small></td>\n" +
+        " <td class=\"header-center\"><small>{6}</small></td>\n" +
+        "</tr>\n";
+
+    public static final String SERVER_ROW_SECTION =
+        "<tr>\n" +
+        " <td class=\"row-center\"><small>{0}</small></td>\n" +
+        " <td class=\"row-center\"><small>{1}</small></td>\n" +
+        " <td class=\"row-center\"><small>{2}</small></td>\n" +
+        " <td class=\"row-center\"><small>{3}</small></td>\n" +
+        " <td class=\"row-center\"><small>{4}</small></td>\n" +
+        " <td class=\"row-center\"><small>{5}</small></td>\n" +
+        "</tr>\n" +
+        "</table>\n" +
+        "<br>\n" +
+        "\n";
+
+    public static final String HTML_TAIL_SECTION =
+        "<hr size=\"1\" noshade=\"noshade\">\n" +
+        "<center><font size=\"-1\" color=\"#525D76\">\n" +
+        " <em>Copyright &copy; 1999-2005, Apache Software Foundation</em>" +
+        "</font></center>\n" +
+        "\n" +
+        "</body>\n" +
+        "</html>";
+    public static final String CHARSET="utf-8";
+
+    // FIXME need we this?
+    public static final String XML_DECLARATION =
+        "<?xml version=\"1.0\" encoding=\""+CHARSET+"\"?>";
+		
+    public static final String XML_STYLE =
+        "<?xml-stylesheet type=\"text/xsl\" href=\"/manager/xform.xsl\" ?>";
+
+}
+

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/host-manager/WEB-INF/classes/org/apache/catalina/hostmanager/HTMLHostManagerServlet.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/host-manager/WEB-INF/classes/org/apache/catalina/hostmanager/HTMLHostManagerServlet.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/host-manager/WEB-INF/classes/org/apache/catalina/hostmanager/HTMLHostManagerServlet.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,478 @@
+/*
+ * Copyright 1999,2004-2006 The Apache Software Foundation.
+ * 
+ * Licensed 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.hostmanager;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.text.MessageFormat;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.TreeMap;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.catalina.Container;
+import org.apache.catalina.Host;
+import org.apache.catalina.util.ServerInfo;
+
+/**
+* Servlet that enables remote management of the virtual hosts deployed
+* on the server.  Normally, this functionality will be protected by a security
+* constraint in the web application deployment descriptor.  However, 
+* this requirement can be relaxed during testing.
+* <p>
+* The difference between the <code>HostManagerServlet</code> and this
+* Servlet is that this Servlet prints out a HTML interface which
+* makes it easier to administrate.
+* <p>
+* However if you use a software that parses the output of
+* <code>HostManagerServlet</code> you won't be able to upgrade
+* to this Servlet since the output are not in the
+* same format as from <code>HostManagerServlet</code>
+*
+* @author Bip Thelin
+* @author Malcolm Edgar
+* @author Glenn L. Nielsen
+* @author Peter Rossbach
+* @version $Revision: 384293 $, $Date: 2006-03-08 12:09:36 -0600 (Wed, 08 Mar 2006) $
+* @see ManagerServlet
+*/
+
+public final class HTMLHostManagerServlet extends HostManagerServlet {
+
+    // --------------------------------------------------------- Public Methods
+
+    /**
+     * Process a GET request for the specified resource.
+     *
+     * @param request The servlet request we are processing
+     * @param response The servlet response we are creating
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception ServletException if a servlet-specified error occurs
+     */
+    public void doGet(HttpServletRequest request,
+                      HttpServletResponse response)
+        throws IOException, ServletException {
+
+        // Identify the request parameters that we need
+        String command = request.getPathInfo();
+
+        String name = request.getParameter("name");
+ 
+        // Prepare our output writer to generate the response message
+        response.setContentType("text/html; charset=" + Constants.CHARSET);
+
+        String message = "";
+        // Process the requested command
+        if (command == null) {
+        } else if (command.equals("/add")) {
+            message = add(request, name);
+        } else if (command.equals("/remove")) {
+            message = remove(name);
+        } else if (command.equals("/list")) {
+        } else if (command.equals("/start")) {
+            message = start(name);
+        } else if (command.equals("/stop")) {
+            message = stop(name);
+        } else {
+            message =
+                sm.getString("hostManagerServlet.unknownCommand", command);
+        }
+
+        list(request, response, message);
+    }
+
+    
+    /**
+     * Add a host using the specified parameters.
+     *
+     * @param name host name
+     */
+    protected String add(HttpServletRequest request,String name) {
+
+        StringWriter stringWriter = new StringWriter();
+        PrintWriter printWriter = new PrintWriter(stringWriter);
+
+        super.add(request,printWriter,name,true);
+
+        return stringWriter.toString();
+    }
+
+
+    /**
+     * Remove the specified host.
+     *
+     * @param writer Writer to render results to
+     * @param name host name
+     */
+    protected String remove(String name) {
+
+        StringWriter stringWriter = new StringWriter();
+        PrintWriter printWriter = new PrintWriter(stringWriter);
+
+        super.remove(printWriter, name);
+
+        return stringWriter.toString();
+    }
+
+    
+    /**
+     * Start the host with the specified name.
+     *
+     * @param name Host name
+     */
+    protected String start(String name) {
+
+        StringWriter stringWriter = new StringWriter();
+        PrintWriter printWriter = new PrintWriter(stringWriter);
+
+        super.start(printWriter, name);
+
+        return stringWriter.toString();
+    }
+
+    
+    /**
+     * Stop the host with the specified name.
+     *
+     * @param name Host name
+     */
+    protected String stop(String name) {
+
+        StringWriter stringWriter = new StringWriter();
+        PrintWriter printWriter = new PrintWriter(stringWriter);
+
+        super.stop(printWriter, name);
+
+        return stringWriter.toString();
+    }
+
+    
+    /**
+     * Render a HTML list of the currently active Contexts in our virtual host,
+     * and memory and server status information.
+     *
+     * @param request The request
+     * @param response The response
+     * @param message a message to display
+     */
+    public void list(HttpServletRequest request,
+                     HttpServletResponse response,
+                     String message) throws IOException {
+
+        PrintWriter writer = response.getWriter();
+
+        // HTML Header Section
+        writer.print(Constants.HTML_HEADER_SECTION);
+
+        // Body Header Section
+        Object[] args = new Object[2];
+        args[0] = request.getContextPath();
+        args[1] = sm.getString("htmlHostManagerServlet.title");
+        writer.print(MessageFormat.format
+                     (Constants.BODY_HEADER_SECTION, args));
+
+        // Message Section
+        args = new Object[3];
+        args[0] = sm.getString("htmlHostManagerServlet.messageLabel");
+        args[1] = (message == null || message.length() == 0) ? "OK" : message;
+        writer.print(MessageFormat.format(Constants.MESSAGE_SECTION, args));
+
+        // Manager Section
+        args = new Object[9];
+        args[0] = sm.getString("htmlHostManagerServlet.manager");
+        args[1] = response.encodeURL(request.getContextPath() + "/html/list");
+        args[2] = sm.getString("htmlHostManagerServlet.list");
+        args[3] = response.encodeURL
+            (request.getContextPath() + "/" +
+             sm.getString("htmlHostManagerServlet.helpHtmlManagerFile"));
+        args[4] = sm.getString("htmlHostManagerServlet.helpHtmlManager");
+        args[5] = response.encodeURL
+            (request.getContextPath() + "/" +
+             sm.getString("htmlHostManagerServlet.helpManagerFile"));
+        args[6] = sm.getString("htmlHostManagerServlet.helpManager");
+        args[7] = response.encodeURL("/manager/status");
+        args[8] = sm.getString("statusServlet.title");
+        writer.print(MessageFormat.format(Constants.MANAGER_SECTION, args));
+
+         // Hosts Header Section
+        args = new Object[3];
+        args[0] = sm.getString("htmlHostManagerServlet.hostName");
+        args[1] = sm.getString("htmlHostManagerServlet.hostAliases");
+        args[2] = sm.getString("htmlHostManagerServlet.hostTasks");
+        writer.print(MessageFormat.format(HOSTS_HEADER_SECTION, args));
+
+        // Hosts Row Section
+        // Create sorted map of host names.
+        Container[] children = engine.findChildren();
+        String hostNames[] = new String[children.length];
+        for (int i = 0; i < children.length; i++)
+            hostNames[i] = children[i].getName();
+
+        TreeMap sortedHostNamesMap = new TreeMap();
+
+        for (int i = 0; i < hostNames.length; i++) {
+            String displayPath = hostNames[i];
+            sortedHostNamesMap.put(displayPath, hostNames[i]);
+        }
+
+        String hostsStart = sm.getString("htmlHostManagerServlet.hostsStart");
+        String hostsStop = sm.getString("htmlHostManagerServlet.hostsStop");
+        String hostsRemove = sm.getString("htmlHostManagerServlet.hostsRemove");
+
+        Iterator iterator = sortedHostNamesMap.entrySet().iterator();
+        while (iterator.hasNext()) {
+            Map.Entry entry = (Map.Entry) iterator.next();
+            String hostName = (String) entry.getKey();
+            Host host = (Host) engine.findChild(hostName);
+
+            if (host != null ) {
+                args = new Object[2];
+                args[0] = hostName;
+                String[] aliases = host.findAliases();
+                StringBuffer buf = new StringBuffer();
+                if (aliases.length > 0) {
+                    buf.append(aliases[0]);
+                    for (int j = 1; j < aliases.length; j++) {
+                        buf.append(", ").append(aliases[j]);
+                    }
+                }
+
+                if (buf.length() == 0) {
+                    buf.append("&nbsp;");
+                }
+
+                args[1] = buf.toString();
+                writer.print
+                    (MessageFormat.format(HOSTS_ROW_DETAILS_SECTION, args));
+
+                args = new Object[7];
+                args[0] = response.encodeURL
+                    (request.getContextPath() +
+                     "/html/start?name=" + hostName);
+                args[1] = hostsStart;
+                args[2] = response.encodeURL
+                    (request.getContextPath() +
+                     "/html/stop?name=" + hostName);
+                args[3] = hostsStop;
+                args[4] = response.encodeURL
+                    (request.getContextPath() +
+                     "/html/remove?name=" + hostName);
+                args[5] = hostsRemove;
+                args[6] = hostName;
+                if (host == this.host) {
+                    writer.print(MessageFormat.format(
+                        MANAGER_HOST_ROW_BUTTON_SECTION, args));
+                } else {
+                    writer.print(MessageFormat.format(
+                        HOSTS_ROW_BUTTON_SECTION, args));
+                }
+
+            }
+        }
+
+        // Add Section
+        args = new Object[6];
+        args[0] = sm.getString("htmlHostManagerServlet.addTitle");
+        args[1] = sm.getString("htmlHostManagerServlet.addHost");
+        args[2] = response.encodeURL(request.getContextPath() + "/html/add");
+        args[3] = sm.getString("htmlHostManagerServlet.addName");
+        args[4] = sm.getString("htmlHostManagerServlet.addAliases");
+        args[5] = sm.getString("htmlHostManagerServlet.addAppBase");
+        writer.print(MessageFormat.format(ADD_SECTION_START, args));
+ 
+        args = new Object[3];
+        args[0] = sm.getString("htmlHostManagerServlet.addAutoDeploy");
+        args[1] = "autoDeploy";
+        args[2] = "checked";
+        writer.print(MessageFormat.format(ADD_SECTION_BOOLEAN, args));
+        args[0] = sm.getString("htmlHostManagerServlet.addDeployOnStartup");
+        args[1] = "deployOnStartup";
+        args[2] = "checked";
+        writer.print(MessageFormat.format(ADD_SECTION_BOOLEAN, args));
+        args[0] = sm.getString("htmlHostManagerServlet.addDeployXML");
+        args[1] = "deployXML";
+        args[2] = "checked";
+        writer.print(MessageFormat.format(ADD_SECTION_BOOLEAN, args));
+        args[0] = sm.getString("htmlHostManagerServlet.addUnpackWARs");
+        args[1] = "unpackWARs";
+        args[2] = "checked";
+        writer.print(MessageFormat.format(ADD_SECTION_BOOLEAN, args));
+        args[0] = sm.getString("htmlHostManagerServlet.addXmlNamespaceAware");
+        args[1] = "xmlNamespaceAware";
+        args[2] = "";
+        writer.print(MessageFormat.format(ADD_SECTION_BOOLEAN, args));
+        args[0] = sm.getString("htmlHostManagerServlet.addXmlValidation");
+        args[1] = "xmlValidation";
+        args[2] = "";
+        writer.print(MessageFormat.format(ADD_SECTION_BOOLEAN, args));
+
+        args[0] = sm.getString("htmlHostManagerServlet.addManager");
+        args[1] = "manager";
+        args[2] = "checked";
+        writer.print(MessageFormat.format(ADD_SECTION_BOOLEAN, args));
+        
+        args = new Object[1];
+        args[0] = sm.getString("htmlHostManagerServlet.addButton");
+        writer.print(MessageFormat.format(ADD_SECTION_END, args));
+
+        // Server Header Section
+        args = new Object[7];
+        args[0] = sm.getString("htmlHostManagerServlet.serverTitle");
+        args[1] = sm.getString("htmlHostManagerServlet.serverVersion");
+        args[2] = sm.getString("htmlHostManagerServlet.serverJVMVersion");
+        args[3] = sm.getString("htmlHostManagerServlet.serverJVMVendor");
+        args[4] = sm.getString("htmlHostManagerServlet.serverOSName");
+        args[5] = sm.getString("htmlHostManagerServlet.serverOSVersion");
+        args[6] = sm.getString("htmlHostManagerServlet.serverOSArch");
+        writer.print(MessageFormat.format
+                     (Constants.SERVER_HEADER_SECTION, args));
+
+        // Server Row Section
+        args = new Object[6];
+        args[0] = ServerInfo.getServerInfo();
+        args[1] = System.getProperty("java.runtime.version");
+        args[2] = System.getProperty("java.vm.vendor");
+        args[3] = System.getProperty("os.name");
+        args[4] = System.getProperty("os.version");
+        args[5] = System.getProperty("os.arch");
+        writer.print(MessageFormat.format(Constants.SERVER_ROW_SECTION, args));
+
+        // HTML Tail Section
+        writer.print(Constants.HTML_TAIL_SECTION);
+
+        // Finish up the response
+        writer.flush();
+        writer.close();
+    }
+
+    
+    // ------------------------------------------------------ Private Constants
+
+    // These HTML sections are broken in relatively small sections, because of
+    // limited number of subsitutions MessageFormat can process
+    // (maximium of 10).
+
+    private static final String HOSTS_HEADER_SECTION =
+        "<table border=\"1\" cellspacing=\"0\" cellpadding=\"3\">\n" +
+        "<tr>\n" +
+        " <td colspan=\"5\" class=\"title\">{0}</td>\n" +
+        "</tr>\n" +
+        "<tr>\n" +
+        " <td class=\"header-left\"><small>{0}</small></td>\n" +
+        " <td class=\"header-center\"><small>{1}</small></td>\n" +
+        " <td class=\"header-center\"><small>{2}</small></td>\n" +
+        "</tr>\n";
+
+    private static final String HOSTS_ROW_DETAILS_SECTION =
+        "<tr>\n" +
+        " <td class=\"row-left\"><small><a href=\"http://{0}\">{0}</a>" +
+        "</small></td>\n" +
+        " <td class=\"row-center\"><small>{1}</small></td>\n";
+
+    private static final String MANAGER_HOST_ROW_BUTTON_SECTION =
+        " <td class=\"row-left\">\n" +
+        "  <small>\n" +
+        "  &nbsp;{1}&nbsp;\n" +
+        "  &nbsp;{3}&nbsp;\n" +
+        "  &nbsp;{5}&nbsp;\n" +
+        "  </small>\n" +
+        " </td>\n" +
+        "</tr>\n";
+
+    private static final String HOSTS_ROW_BUTTON_SECTION =
+        " <td class=\"row-left\" NOWRAP>\n" +
+        "  <small>\n" +
+        "  &nbsp;<a href=\"{0}\" onclick=\"return(confirm(''{1} {6}\\n\\nAre you sure?''))\">{1}</a>&nbsp;\n" +
+        "  &nbsp;<a href=\"{2}\" onclick=\"return(confirm(''{3} {6}\\n\\nAre you sure?''))\">{3}</a>&nbsp;\n" +
+        "  &nbsp;<a href=\"{4}\" onclick=\"return(confirm(''{5} {6}\\n\\nAre you sure?''))\">{5}</a>&nbsp;\n" +
+        "  </small>\n" +
+        " </td>\n" +
+        "</tr>\n";
+
+    private static final String ADD_SECTION_START =
+        "</table>\n" +
+        "<br>\n" +
+        "<table border=\"1\" cellspacing=\"0\" cellpadding=\"3\">\n" +
+        "<tr>\n" +
+        " <td colspan=\"2\" class=\"title\">{0}</td>\n" +
+        "</tr>\n" +
+        "<tr>\n" +
+        " <td colspan=\"2\" class=\"header-left\"><small>{1}</small></td>\n" +
+        "</tr>\n" +
+        "<tr>\n" +
+        " <td colspan=\"2\">\n" +
+        "<form method=\"get\" action=\"{2}\">\n" +
+        "<table cellspacing=\"0\" cellpadding=\"3\">\n" +
+        "<tr>\n" +
+        " <td class=\"row-right\">\n" +
+        "  <small>{3}</small>\n" +
+        " </td>\n" +
+        " <td class=\"row-left\">\n" +
+        "  <input type=\"text\" name=\"name\" size=\"20\">\n" +
+        " </td>\n" +
+        "</tr>\n" +
+        "<tr>\n" +
+        " <td class=\"row-right\">\n" +
+        "  <small>{4}</small>\n" +
+        " </td>\n" +
+        " <td class=\"row-left\">\n" +
+        "  <input type=\"text\" name=\"aliases\" size=\"64\">\n" +
+        " </td>\n" +
+        "</tr>\n" +
+        "<tr>\n" +
+        " <td class=\"row-right\">\n" +
+        "  <small>{5}</small>\n" +
+        " </td>\n" +
+        " <td class=\"row-left\">\n" +
+        "  <input type=\"text\" name=\"appBase\" size=\"64\">\n" +
+        " </td>\n" +
+        "</tr>\n" ;
+    
+        private static final String ADD_SECTION_BOOLEAN =
+        "<tr>\n" +
+        " <td class=\"row-right\">\n" +
+        "  <small>{0}</small>\n" +
+        " </td>\n" +
+        " <td class=\"row-left\">\n" +
+        "  <input type=\"checkbox\" name=\"{1}\" {2}>\n" +
+        " </td>\n" +
+        "</tr>\n" ;
+        
+        private static final String ADD_SECTION_END =
+        "<tr>\n" +
+        " <td class=\"row-right\">\n" +
+        "  &nbsp;\n" +
+        " </td>\n" +
+        " <td class=\"row-left\">\n" +
+        "  <input type=\"submit\" value=\"{0}\">\n" +
+        " </td>\n" +
+        "</tr>\n" +
+         "</table>\n" +
+        "</form>\n" +
+        "</td>\n" +
+        "</tr>\n" +
+        "</table>\n" +
+        "<br>\n" +
+        "\n";
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/host-manager/WEB-INF/classes/org/apache/catalina/hostmanager/HostManagerServlet.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/host-manager/WEB-INF/classes/org/apache/catalina/hostmanager/HostManagerServlet.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/host-manager/WEB-INF/classes/org/apache/catalina/hostmanager/HostManagerServlet.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,684 @@
+/*
+ * Copyright 1999,2004-2006 The Apache Software Foundation.
+ * 
+ * Licensed 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.hostmanager;
+
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.PrintWriter;
+import java.util.StringTokenizer;
+
+import javax.management.MBeanServer;
+import javax.servlet.ServletException;
+import javax.servlet.UnavailableException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.catalina.Container;
+import org.apache.catalina.ContainerServlet;
+import org.apache.catalina.Context;
+import org.apache.catalina.Engine;
+import org.apache.catalina.Globals;
+import org.apache.catalina.Host;
+import org.apache.catalina.Lifecycle;
+import org.apache.catalina.Wrapper;
+import org.apache.catalina.core.StandardHost;
+import org.apache.catalina.startup.HostConfig;
+import org.apache.catalina.util.StringManager;
+import org.apache.commons.modeler.Registry;
+
+
+/**
+ * Servlet that enables remote management of the virtual hosts installed
+ * on the server.  Normally, this functionality will be protected by 
+ * a security constraint in the web application deployment descriptor.  
+ * However, this requirement can be relaxed during testing.
+ * <p>
+ * This servlet examines the value returned by <code>getPathInfo()</code>
+ * and related query parameters to determine what action is being requested.
+ * The following actions and parameters (starting after the servlet path)
+ * are supported:
+ * <ul>
+ * <li><b>/add?name={host-name}&aliases={host-aliases}&manager={manager}</b> -
+ *     Create and add a new virtual host. The <code>host-name</code> attribute
+ *     indicates the name of the new host. The <code>host-aliases</code> 
+ *     attribute is a comma separated list of the host alias names. 
+ *     The <code>manager</code> attribute is a boolean value indicating if the
+ *     webapp manager will be installed in the newly created host (optional, 
+ *     false by default).</li>
+ * <li><b>/remove?name={host-name}</b> - Remove a virtual host. 
+ *     The <code>host-name</code> attribute indicates the name of the host.
+ *     </li>
+ * <li><b>/list</b> - List the virtual hosts installed on the server.
+ *     Each host will be listed with the following format 
+ *     <code>host-name#host-aliases</code>.</li>
+ * <li><b>/start?name={host-name}</b> - Start the virtual host.</li>
+ * <li><b>/stop?name={host-name}</b> - Stop the virtual host.</li>
+ * </ul>
+ * <p>
+ * <b>NOTE</b> - Attempting to stop or remove the host containing
+ * this servlet itself will not succeed.  Therefore, this servlet should
+ * generally be deployed in a separate virtual host.
+ * <p>
+ * <b>NOTE</b> - For security reasons, this application will not operate
+ * when accessed via the invoker servlet.  You must explicitly map this servlet
+ * with a servlet mapping, and you will always want to protect it with
+ * appropriate security constraints as well.
+ * <p>
+ * The following servlet initialization parameters are recognized:
+ * <ul>
+ * <li><b>debug</b> - The debugging detail level that controls the amount
+ *     of information that is logged by this servlet.  Default is zero.
+ * </ul>
+ *
+ * @author Craig R. McClanahan
+ * @author Remy Maucherat
+ * @version $Revision: 384293 $ $Date: 2006-03-08 12:09:36 -0600 (Wed, 08 Mar 2006) $
+ */
+
+public class HostManagerServlet
+    extends HttpServlet implements ContainerServlet {
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * Path where context descriptors should be deployed.
+     */
+    protected File configBase = null;
+
+
+    /**
+     * The Context container associated with our web application.
+     */
+    protected Context context = null;
+
+
+    /**
+     * The debugging detail level for this servlet.
+     */
+    protected int debug = 1;
+
+
+    /**
+     * The associated host.
+     */
+    protected Host host = null;
+
+    
+    /**
+     * The associated engine.
+     */
+    protected Engine engine = null;
+
+    
+    /**
+     * MBean server.
+     */
+    protected MBeanServer mBeanServer = null;
+
+
+    /**
+     * The string manager for this package.
+     */
+    protected static StringManager sm =
+        StringManager.getManager(Constants.Package);
+
+
+    /**
+     * The Wrapper container associated with this servlet.
+     */
+    protected Wrapper wrapper = null;
+
+
+    // ----------------------------------------------- ContainerServlet Methods
+
+
+    /**
+     * Return the Wrapper with which we are associated.
+     */
+    public Wrapper getWrapper() {
+
+        return (this.wrapper);
+
+    }
+
+
+    /**
+     * Set the Wrapper with which we are associated.
+     *
+     * @param wrapper The new wrapper
+     */
+    public void setWrapper(Wrapper wrapper) {
+
+        this.wrapper = wrapper;
+        if (wrapper == null) {
+            context = null;
+            host = null;
+            engine = null;
+        } else {
+            context = (Context) wrapper.getParent();
+            host = (Host) context.getParent();
+            engine = (Engine) host.getParent();
+        }
+
+        // Retrieve the MBean server
+        mBeanServer = Registry.getRegistry(null, null).getMBeanServer();
+        
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Finalize this servlet.
+     */
+    public void destroy() {
+
+        ;       // No actions necessary
+
+    }
+
+
+    /**
+     * Process a GET request for the specified resource.
+     *
+     * @param request The servlet request we are processing
+     * @param response The servlet response we are creating
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception ServletException if a servlet-specified error occurs
+     */
+    public void doGet(HttpServletRequest request,
+                      HttpServletResponse response)
+        throws IOException, ServletException {
+
+        // Verify that we were not accessed using the invoker servlet
+        if (request.getAttribute(Globals.INVOKED_ATTR) != null)
+            throw new UnavailableException
+                (sm.getString("hostManagerServlet.cannotInvoke"));
+
+        // Identify the request parameters that we need
+        String command = request.getPathInfo();
+        if (command == null)
+            command = request.getServletPath();
+        String name = request.getParameter("name");
+  
+        // Prepare our output writer to generate the response message
+        response.setContentType("text/plain; charset=" + Constants.CHARSET);
+        PrintWriter writer = response.getWriter();
+
+        // Process the requested command
+        if (command == null) {
+            writer.println(sm.getString("hostManagerServlet.noCommand"));
+        } else if (command.equals("/add")) {
+            add(request, writer, name, false);
+        } else if (command.equals("/remove")) {
+            remove(writer, name);
+        } else if (command.equals("/list")) {
+            list(writer);
+        } else if (command.equals("/start")) {
+            start(writer, name);
+        } else if (command.equals("/stop")) {
+            stop(writer, name);
+        } else {
+            writer.println(sm.getString("hostManagerServlet.unknownCommand",
+                                        command));
+        }
+
+        // Finish up the response
+        writer.flush();
+        writer.close();
+
+    }
+
+
+    /**
+     * Add host with the given parameters.
+     *
+     * @param request The request
+     * @param writer The output writer
+     * @param name The host name
+     * @param htmlMode Flag value
+     */
+    protected void add(HttpServletRequest request, PrintWriter writer, String name, boolean htmlMode ) {
+        String aliases = request.getParameter("aliases");
+        String appBase = request.getParameter("appBase");
+        boolean manager = booleanParameter(request, "manager", false, htmlMode);
+        boolean autoDeploy = booleanParameter(request, "autoDeploy", true, htmlMode);
+        boolean deployOnStartup = booleanParameter(request, "deployOnStartup", true, htmlMode);
+        boolean deployXML = booleanParameter(request, "deployXML", true, htmlMode);
+        boolean unpackWARs = booleanParameter(request, "unpackWARs", true, htmlMode);
+        boolean xmlNamespaceAware = booleanParameter(request, "xmlNamespaceAware", false, htmlMode);
+        boolean xmlValidation = booleanParameter(request, "xmlValidation", false, htmlMode);
+        add(writer, name, aliases, appBase, manager,
+            autoDeploy,
+            deployOnStartup,
+            deployXML,                                       
+            unpackWARs,
+            xmlNamespaceAware,
+            xmlValidation);
+    }
+
+
+    /**
+     * extract boolean value from checkbox with default
+     * @param request
+     * @param parameter
+     * @param theDefault
+     * @param htmlMode
+     * @return
+     */
+    protected boolean booleanParameter(HttpServletRequest request,
+            String parameter, boolean theDefault, boolean htmlMode) {
+        String value = request.getParameter(parameter);
+        boolean booleanValue = theDefault;
+        if (value != null) {
+            if (htmlMode) {
+                if (value.equals("on")) {
+                    booleanValue = true;
+                }
+            } else if (theDefault) {
+                if (value.equals("false")) {
+                    booleanValue = false;
+                }
+            } else if (value.equals("true")) {
+                booleanValue = true;
+            }
+        } else if (htmlMode)
+            booleanValue = false;
+        return booleanValue;
+    }
+
+
+    /**
+     * Initialize this servlet.
+     */
+    public void init() throws ServletException {
+
+        // Ensure that our ContainerServlet properties have been set
+        if ((wrapper == null) || (context == null))
+            throw new UnavailableException
+                (sm.getString("hostManagerServlet.noWrapper"));
+
+        // Verify that we were not accessed using the invoker servlet
+        String servletName = getServletConfig().getServletName();
+        if (servletName == null)
+            servletName = "";
+        if (servletName.startsWith("org.apache.catalina.INVOKER."))
+            throw new UnavailableException
+                (sm.getString("hostManagerServlet.cannotInvoke"));
+
+        // Set our properties from the initialization parameters
+        String value = null;
+        try {
+            value = getServletConfig().getInitParameter("debug");
+            debug = Integer.parseInt(value);
+        } catch (Throwable t) {
+            ;
+        }
+
+    }
+
+
+
+    // -------------------------------------------------------- Private Methods
+
+
+    /**
+     * Add a host using the specified parameters.
+     *
+     * @param writer Writer to render results to
+     * @param name host name
+     * @param aliases comma separated alias list
+     * @param appBase application base for the host
+     * @param manager should the manager webapp be deployed to the new host ?
+     */
+    protected synchronized void add
+        (PrintWriter writer, String name, String aliases, String appBase, 
+         boolean manager,
+         boolean autoDeploy,
+         boolean deployOnStartup,
+         boolean deployXML,                                       
+         boolean unpackWARs,
+         boolean xmlNamespaceAware,
+         boolean xmlValidation) {
+        if (debug >= 1) {
+            log("add: Adding host '" + name + "'");
+        }
+
+        // Validate the requested host name
+        if ((name == null) || name.length() == 0) {
+            writer.println(sm.getString("hostManagerServlet.invalidHostName", name));
+            return;
+        }
+
+        // Check if host already exists
+        if (engine.findChild(name) != null) {
+            writer.println
+                (sm.getString("hostManagerServlet.alreadyHost", name));
+            return;
+        }
+
+        // Validate and create appBase
+        File appBaseFile = null;
+        if (appBase == null || appBase.length() == 0) {
+            appBase = name;
+        }
+        File file = new File(appBase);
+        if (!file.isAbsolute())
+            file = new File(System.getProperty("catalina.base"), appBase);
+        try {
+            appBaseFile = file.getCanonicalFile();
+        } catch (IOException e) {
+            appBaseFile = file;
+        }
+        if (!appBaseFile.exists()) {
+            appBaseFile.mkdirs();
+        }
+        
+        // Create base for config files
+        File configBaseFile = getConfigBase(name);
+        
+        // Copy manager.xml if requested
+        if (manager) {
+            InputStream is = null;
+            OutputStream os = null;
+            try {
+                is = getServletContext().getResourceAsStream("/manager.xml");
+                os = new FileOutputStream(new File(configBaseFile, "manager.xml"));
+                byte buffer[] = new byte[512];
+                int len = buffer.length;
+                while (true) {
+                    len = is.read(buffer);
+                    if (len == -1)
+                        break;
+                    os.write(buffer, 0, len);
+                }
+            } catch (IOException e) {
+                writer.println
+                    (sm.getString("hostManagerServlet.managerXml"));
+                return;
+            } finally {
+                if (is != null) {
+                    try {
+                        is.close();
+                    } catch (IOException e) {
+                    }
+                }
+                if (os != null) {
+                    try {
+                        os.close();
+                    } catch (IOException e) {
+                    }
+                }
+            }
+        }
+        
+        StandardHost host = new StandardHost();
+        host.setAppBase(appBase);
+        host.setName(name);
+
+        host.addLifecycleListener(new HostConfig());
+
+        // Add host aliases
+        if ((aliases != null) && !("".equals(aliases))) {
+            StringTokenizer tok = new StringTokenizer(aliases, ",");
+            while (tok.hasMoreTokens()) {
+                host.addAlias(tok.nextToken());
+            }
+        }
+        host.setAutoDeploy(autoDeploy);
+        host.setDeployOnStartup(deployOnStartup);
+        host.setDeployXML(deployXML);
+        host.setUnpackWARs(unpackWARs);
+        host.setXmlNamespaceAware(xmlNamespaceAware);
+        host.setXmlValidation(xmlValidation);
+        
+        // Add new host
+        try {
+            engine.addChild(host);
+        } catch (Exception e) {
+            writer.println(sm.getString("hostManagerServlet.exception",
+                                        e.toString()));
+            return;
+        }
+        
+        host = (StandardHost) engine.findChild(name);
+        if (host != null) {
+            writer.println(sm.getString("hostManagerServlet.add", name));
+        } else {
+            // Something failed
+            writer.println(sm.getString("hostManagerServlet.addFailed", name));
+        }
+        
+    }
+
+
+    /**
+     * Remove the specified host.
+     *
+     * @param writer Writer to render results to
+     * @param name host name
+     */
+    protected synchronized void remove(PrintWriter writer, String name) {
+
+        if (debug >= 1) {
+            log("remove: Removing host '" + name + "'");
+        }
+
+        // Validate the requested host name
+        if ((name == null) || name.length() == 0) {
+            writer.println(sm.getString("hostManagerServlet.invalidHostName", name));
+            return;
+        }
+
+        // Check if host exists
+        if (engine.findChild(name) == null) {
+            writer.println
+                (sm.getString("hostManagerServlet.noHost", name));
+            return;
+        }
+
+        // Prevent removing our own host
+        if (engine.findChild(name) == host) {
+            writer.println
+                (sm.getString("hostManagerServlet.cannotRemoveOwnHost", name));
+            return;
+        }
+
+        // Remove host
+        // Note that the host will not get physically removed
+        try {
+            engine.removeChild(engine.findChild(name));
+        } catch (Exception e) {
+            writer.println(sm.getString("hostManagerServlet.exception",
+                                        e.toString()));
+            return;
+        }
+        
+        Host host = (StandardHost) engine.findChild(name);
+        if (host == null) {
+            writer.println(sm.getString("hostManagerServlet.remove", name));
+        } else {
+            // Something failed
+            writer.println(sm.getString("hostManagerServlet.removeFailed", name));
+        }
+        
+    }
+
+
+    /**
+     * Render a list of the currently active Contexts in our virtual host.
+     *
+     * @param writer Writer to render to
+     */
+    protected void list(PrintWriter writer) {
+
+        if (debug >= 1)
+            log("list: Listing hosts for engine '" 
+                + engine.getName() + "'");
+
+        writer.println(sm.getString("hostManagerServlet.listed",
+                                    engine.getName()));
+        Container[] hosts = engine.findChildren();
+        for (int i = 0; i < hosts.length; i++) {
+            Host host = (Host) hosts[i];
+            String name = host.getName();
+            String[] aliases = host.findAliases();
+            StringBuffer buf = new StringBuffer();
+            if (aliases.length > 0) {
+                buf.append(aliases[0]);
+                for (int j = 1; j < aliases.length; j++) {
+                    buf.append(',').append(aliases[j]);
+                }
+            }
+            writer.println(sm.getString("hostManagerServlet.listitem",
+                                        name, buf.toString()));
+        }
+    }
+
+
+    /**
+     * Start the host with the specified name.
+     *
+     * @param writer Writer to render to
+     * @param name Host name
+     */
+    protected void start(PrintWriter writer, String name) {
+
+        if (debug >= 1)
+            log("start: Starting host with name '" + name + "'");
+
+        // Validate the requested host name
+        if ((name == null) || name.length() == 0) {
+            writer.println(sm.getString("hostManagerServlet.invalidHostName", name));
+            return;
+        }
+
+        // Check if host exists
+        if (engine.findChild(name) == null) {
+            writer.println
+                (sm.getString("hostManagerServlet.noHost", name));
+            return;
+        }
+
+        // Prevent starting our own host
+        if (engine.findChild(name) == host) {
+            writer.println
+                (sm.getString("hostManagerServlet.cannotStartOwnHost", name));
+            return;
+        }
+
+        // Start host
+        try {
+            ((Lifecycle) engine.findChild(name)).start();
+            writer.println
+                (sm.getString("hostManagerServlet.started", name));
+        } catch (Throwable t) {
+            getServletContext().log
+                (sm.getString("hostManagerServlet.startFailed", name), t);
+            writer.println
+                (sm.getString("hostManagerServlet.startFailed", name));
+            writer.println(sm.getString("hostManagerServlet.exception",
+                                        t.toString()));
+            return;
+        }
+        
+    }
+
+
+    /**
+     * Start the host with the specified name.
+     *
+     * @param writer Writer to render to
+     * @param name Host name
+     */
+    protected void stop(PrintWriter writer, String name) {
+
+        if (debug >= 1)
+            log("stop: Stopping host with name '" + name + "'");
+
+        // Validate the requested host name
+        if ((name == null) || name.length() == 0) {
+            writer.println(sm.getString("hostManagerServlet.invalidHostName", name));
+            return;
+        }
+
+        // Check if host exists
+        if (engine.findChild(name) == null) {
+            writer.println
+                (sm.getString("hostManagerServlet.noHost", name));
+            return;
+        }
+
+        // Prevent starting our own host
+        if (engine.findChild(name) == host) {
+            writer.println
+                (sm.getString("hostManagerServlet.cannotStopOwnHost", name));
+            return;
+        }
+
+        // Start host
+        try {
+            ((Lifecycle) engine.findChild(name)).stop();
+            writer.println
+                (sm.getString("hostManagerServlet.stopped", name));
+        } catch (Throwable t) {
+            getServletContext().log
+                (sm.getString("hostManagerServlet.stopFailed", name), t);
+            writer.println
+                (sm.getString("hostManagerServlet.stopFailed", name));
+            writer.println(sm.getString("hostManagerServlet.exception",
+                                        t.toString()));
+            return;
+        }
+        
+    }
+
+
+    // -------------------------------------------------------- Support Methods
+
+
+    /**
+     * Get config base.
+     */
+    protected File getConfigBase(String hostName) {
+        File configBase = 
+            new File(System.getProperty("catalina.base"), "conf");
+        if (!configBase.exists()) {
+            return null;
+        }
+        if (engine != null) {
+            configBase = new File(configBase, engine.getName());
+        }
+        if (host != null) {
+            configBase = new File(configBase, hostName);
+        }
+        configBase.mkdirs();
+        return configBase;
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/host-manager/WEB-INF/classes/org/apache/catalina/hostmanager/LocalStrings.properties
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/host-manager/WEB-INF/classes/org/apache/catalina/hostmanager/LocalStrings.properties	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/host-manager/WEB-INF/classes/org/apache/catalina/hostmanager/LocalStrings.properties	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,59 @@
+hostManagerServlet.cannotInvoke=Cannot invoke host manager servlet through invoker
+hostManagerServlet.noCommand=FAIL - No command was specified
+hostManagerServlet.unknownCommand=FAIL - Unknown command {0}
+hostManagerServlet.noWrapper=Container has not called setWrapper() for this servlet
+hostManagerServlet.invalidHostName=FAIL - Invalid host name {0} was specified
+hostManagerServlet.alreadyHost=FAIL - Host already exists with host name {0}
+hostManagerServlet.managerXml=FAIL - Couldn't install manager.xml
+hostManagerServlet.exception=FAIL - Encountered exception {0}
+hostManagerServlet.add=OK - Host {0} added
+hostManagerServlet.addFailed=FAIL - Failed to add host {0}
+hostManagerServlet.cannotRemoveOwnHost=FAIL - Cannot remove own host {0}
+hostManagerServlet.remove=OK - Removed host {0}
+hostManagerServlet.removeFailed=FAIL - Failed to remove host {0}
+hostManagerServlet.listed=OK - Listed hosts
+hostManagerServlet.listitem={0}:{1}
+hostManagerServlet.cannotStartOwnHost=FAIL - Cannot start own host {0}
+hostManagerServlet.started=OK - Host {0} started
+hostManagerServlet.startFailed=FAIL - Failed to start host {0}
+hostManagerServlet.cannotStopOwnHost=FAIL - Cannot stop own host {0}
+hostManagerServlet.stopped=OK - Host {0} stopped
+hostManagerServlet.stopFailed=FAIL - Failed to stop host {0}
+
+htmlHostManagerServlet.title=Tomcat Virtual Host Manager
+htmlHostManagerServlet.messageLabel=Message:
+htmlHostManagerServlet.manager=Host Manager
+htmlHostManagerServlet.list=List Virtual Hosts
+htmlHostManagerServlet.helpHtmlManagerFile=html-host-manager-howto.html
+htmlHostManagerServlet.helpHtmlManager=HTML Host Manager Help (Coming Soon!)
+htmlHostManagerServlet.helpManagerFile=host-manager-howto.html
+htmlHostManagerServlet.helpManager=Host Manager Help
+htmlHostManagerServlet.hostName=Host name
+htmlHostManagerServlet.hostAliases=Host aliases
+htmlHostManagerServlet.hostTasks=Commands
+htmlHostManagerServlet.hostsStart=Start
+htmlHostManagerServlet.hostsStop=Stop
+htmlHostManagerServlet.hostsRemove=Remove
+htmlHostManagerServlet.addTitle=Add Virtual Host
+htmlHostManagerServlet.addHost=Host
+htmlHostManagerServlet.addName=Name:
+htmlHostManagerServlet.addAliases=Aliases:
+htmlHostManagerServlet.addAppBase=App base:
+htmlHostManagerServlet.addManager=Manager App
+htmlHostManagerServlet.addAutoDeploy=AutoDeploy
+htmlHostManagerServlet.addDeployOnStartup=DeployOnStartup
+htmlHostManagerServlet.addDeployXML=DeployXML
+htmlHostManagerServlet.addUnpackWARs=UnpackWARs
+htmlHostManagerServlet.addXmlNamespaceAware=XmlNamespaceAware
+htmlHostManagerServlet.addXmlValidation=XmlValidation
+htmlHostManagerServlet.addButton=Add
+htmlHostManagerServlet.serverTitle=Server Information
+htmlHostManagerServlet.serverVersion=Tomcat Version
+htmlHostManagerServlet.serverJVMVersion=JVM Version
+htmlHostManagerServlet.serverJVMVendor=JVM Vendor
+htmlHostManagerServlet.serverOSName=OS Name
+htmlHostManagerServlet.serverOSVersion=OS Version
+htmlHostManagerServlet.serverOSArch=OS Architecture
+
+statusServlet.title=Server Status
+statusServlet.complete=Complete Server Status

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/host-manager/WEB-INF/web.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/host-manager/WEB-INF/web.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/host-manager/WEB-INF/web.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,95 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+
+<!DOCTYPE web-app
+    PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
+    "http://java.sun.com/dtd/web-app_2_3.dtd">
+
+<web-app>
+
+  <display-name>Tomcat Manager Application</display-name>
+  <description>
+    A scriptable management web application for the Tomcat Web Server;
+	Manager lets you view, load/unload/etc particular web applications.
+  </description>
+
+  <!-- Define the Manager Servlet
+       Change servlet-class to: org.apache.catalina.servlets.HTMLManagerServlet
+       to get a Servlet with a more intuitive HTML interface, don't change if you
+       have software that is expected to parse the output from ManagerServlet
+       since they're not compatible.
+   -->
+  <servlet>
+    <servlet-name>HostManager</servlet-name>
+    <servlet-class>org.apache.catalina.hostmanager.HostManagerServlet</servlet-class>
+    <init-param>
+      <param-name>debug</param-name>
+      <param-value>2</param-value>
+    </init-param>
+  </servlet>
+  <servlet>
+    <servlet-name>HTMLHostManager</servlet-name>
+    <servlet-class>org.apache.catalina.hostmanager.HTMLHostManagerServlet</servlet-class>
+    <init-param>
+      <param-name>debug</param-name>
+      <param-value>2</param-value>
+    </init-param>
+  </servlet>
+
+  <!-- Define the Manager Servlet Mapping -->
+  <servlet-mapping>
+    <servlet-name>HostManager</servlet-name>
+    <url-pattern>/list</url-pattern>
+  </servlet-mapping>
+  <servlet-mapping>
+    <servlet-name>HostManager</servlet-name>
+    <url-pattern>/add</url-pattern>
+  </servlet-mapping>
+  <servlet-mapping>
+    <servlet-name>HostManager</servlet-name>
+    <url-pattern>/remove</url-pattern>
+  </servlet-mapping>
+  <servlet-mapping>
+    <servlet-name>HostManager</servlet-name>
+    <url-pattern>/start</url-pattern>
+  </servlet-mapping>
+  <servlet-mapping>
+    <servlet-name>HostManager</servlet-name>
+    <url-pattern>/stop</url-pattern>
+  </servlet-mapping>
+  <servlet-mapping>
+    <servlet-name>HTMLHostManager</servlet-name>
+    <url-pattern>/html/*</url-pattern>
+  </servlet-mapping>
+
+  <!-- Define a Security Constraint on this Application -->
+  <security-constraint>
+    <web-resource-collection>
+      <web-resource-name>HTMLHostManager and HostManager commands</web-resource-name>
+      <url-pattern>/html/*</url-pattern>
+      <url-pattern>/list</url-pattern>
+      <url-pattern>/add</url-pattern>
+      <url-pattern>/remove</url-pattern>
+      <url-pattern>/start</url-pattern>
+      <url-pattern>/stop</url-pattern>
+    </web-resource-collection>
+    <auth-constraint>
+       <!-- NOTE:  This role is not present in the default users file -->
+       <role-name>admin</role-name>
+    </auth-constraint>
+  </security-constraint>
+
+  <!-- Define the Login Configuration for this Application -->
+  <login-config>
+    <auth-method>BASIC</auth-method>
+    <realm-name>Tomcat Host Manager Application</realm-name>
+  </login-config>
+
+  <!-- Security roles referenced by this web application -->
+  <security-role>
+    <description>
+      The role that is required to log in to the Manager Application
+    </description>
+    <role-name>admin</role-name>
+  </security-role>
+
+</web-app>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/host-manager/build.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/host-manager/build.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/host-manager/build.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,126 @@
+<project name="host-manager" default="build-main" basedir=".">
+
+
+  <!-- ===================== Initialize Property Values =================== -->
+
+  <!-- See "build.properties.sample" in the top level directory for all     -->
+  <!-- property values you must customize for successful building!!!        -->
+  <property file="build.properties"/>
+  <property file="../build.properties"/>
+  <property file="../../build.properties"/>
+  <property file="${user.home}/build.properties"/>
+
+  <property name="build.compiler"  value="modern"/>
+  <property name="webapps.build"   value="../build"/>
+  <property name="webapps.dist"    value="../dist"/>
+  <property name="webapp.name"     value="host-manager"/>
+
+  <!-- Dependent JARs and files -->
+  <property name="servlet-api.jar" value="${api.home}/jsr154/dist/lib/servlet-api.jar"/>
+  <property name="jsp-api.jar"     value="${api.home}/jsr152/dist/lib/jsp-api.jar"/>
+
+  <!-- Construct Admin classpath -->
+  <path id="host-manager.classpath">
+    <pathelement location="${catalina.deploy}/classes"/>
+    <pathelement location="${commons-fileupload.jar}"/>
+    <pathelement location="${commons-logging.jar}"/>   
+    <pathelement location="${commons-modeler.jar}"/>
+    <pathelement location="${jmx.jar}"/>
+    <pathelement location="${servlet-api.jar}"/>
+    <pathelement location="${jsp-api.jar}"/>
+  </path>
+
+
+	  <!-- ======================== BUILD: Copy JARs ========================== -->
+
+
+  <!-- =================== BUILD: Create Directories ====================== -->
+  <target name="build-prepare">
+    <mkdir dir="${webapps.build}"/>
+    <mkdir dir="${webapps.build}/${webapp.name}"/>
+    <mkdir dir="${webapps.build}/${webapp.name}/images"/>
+    <mkdir dir="${webapps.build}/${webapp.name}/WEB-INF"/>
+    <mkdir dir="${webapps.build}/${webapp.name}/WEB-INF/classes"/>
+  </target>
+
+
+  <!-- ================ BUILD: Copy Static Files ========================== -->
+  <target name="build-static" depends="build-prepare">
+    <copy todir="${webapps.build}/${webapp.name}">
+      <fileset dir=".">
+        <exclude name="build.*"/>
+      </fileset>
+    </copy>
+  </target>
+
+
+  <!-- ================= BUILD: Compile Server Components ================= -->
+  <target name="build-main" depends="build-static">
+
+    <!-- Top Level Directory -->
+    <style basedir="../docs"
+           destdir="${webapps.build}/${webapp.name}"
+           extension=".html"
+           style="tomcat-docs.xsl"
+           excludes="build.xml project.xml"
+           includes="host-manager-howto.xml,host-html-manager-howto.xml">
+      <param name="relative-path" expression="."/>
+      <param name="project-menu" expression="nomenu"/>
+      <param name="standalone" expression="standalone"/>
+    </style>
+
+    <!-- Images Subdirectory -->
+    <copy todir="${webapps.build}/${webapp.name}/images">
+      <fileset dir="../docs/images">
+        <exclude name="printer.gif"/>
+      </fileset>
+    </copy>
+
+    <javac   srcdir="WEB-INF/classes" 
+             destdir="${webapps.build}/${webapp.name}/WEB-INF/classes"
+             debug="${compile.debug}" deprecation="${compile.deprecation}"
+             optimize="${compile.optimize}"
+             excludes="**/CVS/**">
+      <classpath refid="host-manager.classpath" />
+    </javac>
+
+  </target>
+
+
+  <!-- ==================== BUILD: Rebuild Everything ===================== -->
+  <target name="all" depends="build-clean,build-main"
+   description="Clean and build host manager webapp"/>
+
+
+  <!-- ======================= BUILD: Clean Directory ===================== -->
+  <target name="build-clean">
+    <delete dir="${webapps.build}/${webapp.name}"/>
+  </target>
+
+
+  <!-- ======================= DIST: Create Directories =================== -->
+  <target name="dist-prepare">
+    <mkdir dir="${webapps.dist}"/>
+  </target>
+
+
+  <!-- ======================= DIST: Create Distribution Files ============ -->
+  <target name="dist" depends="build-main,dist-prepare"
+   description="Create host manager webapp binary distribution">
+      <jar   jarfile="${webapps.dist}/${webapp.name}.war"
+             basedir="${webapps.build}/${webapp.name}" includes="**"/>
+  </target>
+
+
+  <!-- ======================= DIST: Clean Directory ====================== -->
+  <target name="dist-clean">
+    <deltree dir="${dist.dir}/${webapp.name}"/>
+  </target>
+
+
+  <!-- ====================== Convenient Synonyms ========================= -->
+  <target name="clean" depends="build-clean,dist-clean"
+   description="Clean build and dist directories"/>
+
+
+</project>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/host-manager/host-manager.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/host-manager/host-manager.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/host-manager/host-manager.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,13 @@
+<!--
+
+    Context configuration file for the Tomcat Host Manager Web App
+
+    $Id: host-manager.xml 303743 2005-03-11 22:39:26Z remm $
+
+-->
+
+
+<Context docBase="${catalina.home}/server/webapps/host-manager"
+         privileged="true" antiResourceLocking="false" antiJARLocking="false">
+
+</Context>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/host-manager/manager.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/host-manager/manager.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/host-manager/manager.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,13 @@
+<!--
+
+    Context configuration file for the Tomcat Manager Web App
+
+    $Id: manager.xml 303743 2005-03-11 22:39:26Z remm $
+
+-->
+
+
+<Context docBase="${catalina.home}/server/webapps/manager"
+         privileged="true" antiResourceLocking="false" antiJARLocking="false">
+
+</Context>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/jmxremote/README
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/jmxremote/README	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/jmxremote/README	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,12 @@
+Simple webapp that loads the Jmx remote connector. 
+
+You need to add mx4j-remote.jar to your common loader or use JDK1.5. Any other JMX implementation
+that supports javax.remote should work as well. 
+
+The directory structure is a bit different from manager and the other webapps in catalina. I'm
+using eclipse, set up to use separate output dirs and autocompile. The output dir is set to WEB-INF/classes,
+and I have a symlink to the jmxremote dir in the sources - so basically there is no need to run ant/manually compile, 
+just save the file and reload the app. 
+
+MISSING: user/password, SSL, custom RMI server address - can be easily added using servlet params ( and should be 
+added if this ever gets included in the distro )

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/jmxremote/WEB-INF/src/org/apache/tomcat/servlets/jmxremote/JmxRemoteServlet.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/jmxremote/WEB-INF/src/org/apache/tomcat/servlets/jmxremote/JmxRemoteServlet.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/jmxremote/WEB-INF/src/org/apache/tomcat/servlets/jmxremote/JmxRemoteServlet.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,110 @@
+/*
+ * Created on Jul 14, 2004
+ *
+ * TODO To change the template for this generated file go to
+ * Window - Preferences - Java - Code Style - Code Templates
+ */
+package org.apache.tomcat.servlets.jmxremote;
+
+import java.io.IOException;
+import java.rmi.registry.LocateRegistry;
+import java.rmi.registry.Registry;
+
+import javax.management.MBeanServer;
+import javax.management.MBeanServerFactory;
+import javax.management.remote.JMXConnectorServer;
+import javax.management.remote.JMXConnectorServerFactory;
+import javax.management.remote.JMXServiceURL;
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+// Using o.a.tomcat.servlets because o.a.catalina won't be loaded unless trusted app 
+
+/**
+ * Experimental servlet allowing connectors to be deployed and managed using the 
+ * webapp infrastructure.
+ * 
+ * Connectors can be packaged in a WAR file, deployed and managed using the 
+ * normal tools. Configuration is done using web.xml init-params - while this is 
+ * not as simple as <connector> tags in server.xml, it may be easier to support
+ * in tools and explain to webapp developers.
+ * 
+ * Since webapp class loader is used - start/stop as well as reloading can be 
+ * controlled from the /manager.
+ * 
+ * Issues:
+ *  - may polute the webapps namespace - solution would be to reserve a prefix
+ * or use some invalid/special name.    
+ *
+ * @author Costin Manolache
+ */
+public class JmxRemoteServlet extends HttpServlet {
+    JMXConnectorServer cntorServer = null; 
+    
+    public void init(ServletConfig conf) throws ServletException {
+        // otherwise log doesn't work
+        super.init(conf);
+        
+        MBeanServer mBeanServer = null;
+
+        Registry reg=null;
+        
+        // TODO: use config to get the registry port, url, pass, user
+
+        
+        try {
+            if( reg==null )
+                reg=LocateRegistry.createRegistry(1099);
+        } catch( Throwable t ) {
+            log("Can't start registry - it may be already started: " + t);
+        }
+        
+        try {
+            mBeanServer = null;
+            if (MBeanServerFactory.findMBeanServer(null).size() > 0) {
+                mBeanServer =
+                    (MBeanServer) MBeanServerFactory.findMBeanServer(null).get(0);
+            } else {
+                mBeanServer = MBeanServerFactory.createMBeanServer();
+            }
+        } catch( Throwable t ) {
+            log("Can't get the mbean server " + t);
+            return;
+        }
+        
+        try {
+            JMXServiceURL address = new JMXServiceURL("service:jmx:rmi://rmiHost/jndi/rmi://localhost:1099/jndiPath");
+            cntorServer = 
+                JMXConnectorServerFactory.newJMXConnectorServer(address, null, mBeanServer);
+            cntorServer.start();
+        } catch (Throwable e) {
+            log("Can't register jmx connector ", e);
+        }
+    }
+
+    /** Stop the connector
+     * 
+     */
+    public void destroy() {
+        try {
+            if( cntorServer != null ) cntorServer.stop();
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+
+    public void service(HttpServletRequest req, HttpServletResponse resp)
+        throws ServletException, IOException
+    {
+        resp.sendError(404);
+    }
+
+    // I don't know why super.log is broken in init 
+//    public void log(String s) {
+//        System.err.println("JMX rem:" + s);
+//    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/jmxremote/WEB-INF/web.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/jmxremote/WEB-INF/web.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/jmxremote/WEB-INF/web.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!--
+  Copyright 2004 The Apache Software Foundation
+
+  Licensed 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.
+-->
+
+<web-app 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-app_2_4.xsd"
+    version="2.4">
+
+  <display-name>JMX Remote Connector Loader</display-name>
+  <description>
+	Will start Jmx RMI connector if JMX is available.
+  </description>
+
+  <servlet>
+    <servlet-name>JmxRemote</servlet-name>
+    <servlet-class>org.apache.tomcat.servlets.jmxremote.JmxRemoteServlet</servlet-class>
+    <init-param>
+      <param-name>debug</param-name>
+      <param-value>0</param-value>
+    </init-param>
+    <load-on-startup>1</load-on-startup>
+  </servlet>
+
+</web-app>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/jmxremote/build.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/jmxremote/build.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/jmxremote/build.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,105 @@
+<project name="manager" default="build-main" basedir=".">
+
+
+  <!-- ===================== Initialize Property Values =================== -->
+
+  <!-- See "build.properties.sample" in the top level directory for all     -->
+  <!-- property values you must customize for successful building!!!        -->
+  <property file="${user.home}/build.properties"/>
+  <property file="build.properties"/>
+  <property file="../build.properties"/>
+  <property file="../../build.properties"/>
+  <property file="../../../jakarta-tomcat-5/build.properties"/>
+  <property file="../../../jakarta-tomcat-5/build.properties.default"/>
+
+  <property name="build.compiler"  value="modern"/>
+  <property name="webapps.build"   value="../build"/>
+  <property name="webapps.dist"    value="../dist"/>
+  <property name="webapp.name"     value="jmxremote"/>
+
+  <!-- Dependent JARs and files -->
+  <property name="servlet-api.jar" value="${api.home}/jsr154/dist/lib/servlet-api.jar"/>
+  <property name="jsp-api.jar"     value="${api.home}/jsr152/dist/lib/jsp-api.jar"/>
+
+  <path id="build.classpath">
+    <pathelement location="${catalina.deploy}/classes"/>
+    <pathelement location="${commons-fileupload.jar}"/>
+    <pathelement location="${commons-modeler.jar}"/>
+    <pathelement location="${jmx.jar}"/>
+    <pathelement location="${jmx-remote.jar}"/>
+    <pathelement location="${servlet-api.jar}"/>
+    <pathelement location="${jsp-api.jar}"/>
+  </path>
+
+
+  <!-- =================== BUILD: Create Directories ====================== -->
+  <target name="build-prepare">
+    <mkdir dir="${webapps.build}"/>
+    <mkdir dir="${webapps.build}/${webapp.name}"/>
+    <mkdir dir="${webapps.build}/${webapp.name}/images"/>
+    <mkdir dir="${webapps.build}/${webapp.name}/WEB-INF"/>
+    <mkdir dir="${webapps.build}/${webapp.name}/WEB-INF/classes"/>
+  </target>
+
+
+  <!-- ================ BUILD: Copy Static Files ========================== -->
+  <target name="build-static" depends="build-prepare">
+    <copy todir="${webapps.build}/${webapp.name}">
+      <fileset dir=".">
+        <exclude name="build.*"/>
+      </fileset>
+    </copy>
+  </target>
+
+
+  <!-- ================= BUILD: Compile Server Components ================= -->
+  <target name="build-main" depends="build-static">
+
+    <javac   srcdir="WEB-INF/src" 
+             destdir="${webapps.build}/${webapp.name}/WEB-INF/classes"
+             debug="${compile.debug}" deprecation="${compile.deprecation}"
+             optimize="${compile.optimize}"
+             excludes="**/CVS/**">
+      <classpath refid="build.classpath" />
+    </javac>
+
+  </target>
+
+
+  <!-- ==================== BUILD: Rebuild Everything ===================== -->
+  <target name="all" depends="build-clean,build-main"
+   description="Clean and build manager webapp"/>
+
+
+  <!-- ======================= BUILD: Clean Directory ===================== -->
+  <target name="build-clean">
+    <delete dir="${webapps.build}/${webapp.name}"/>
+  </target>
+
+
+  <!-- ======================= DIST: Create Directories =================== -->
+  <target name="dist-prepare">
+    <mkdir dir="${webapps.dist}"/>
+  </target>
+
+
+  <!-- ======================= DIST: Create Distribution Files ============ -->
+  <target name="dist" depends="build-main,dist-prepare"
+   description="Create manager webapp binary distribution">
+      <jar   jarfile="${webapps.dist}/${webapp.name}.war"
+             basedir="${webapps.build}/${webapp.name}" includes="**"/>
+  </target>
+
+
+  <!-- ======================= DIST: Clean Directory ====================== -->
+  <target name="dist-clean">
+    <deltree dir="${dist.dir}/${webapp.name}"/>
+  </target>
+
+
+  <!-- ====================== Convenient Synonyms ========================= -->
+  <target name="clean" depends="build-clean,dist-clean"
+   description="Clean build and dist directories"/>
+
+
+</project>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/manager/WEB-INF/classes/org/apache/catalina/manager/Constants.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/manager/WEB-INF/classes/org/apache/catalina/manager/Constants.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/manager/WEB-INF/classes/org/apache/catalina/manager/Constants.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,198 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.manager;
+
+
+public class Constants {
+
+    public static final String Package = "org.apache.catalina.manager";
+
+    public static final String HTML_HEADER_SECTION =
+        "<html>\n" +
+        "<head>\n" +
+        "<style>\n" +
+        org.apache.catalina.util.TomcatCSS.TOMCAT_CSS +
+        "  table {\n" +
+        "    width: 100%;\n" +
+        "  }\n" +
+        "  td.page-title {\n" +
+        "    text-align: center;\n" +
+        "    vertical-align: top;\n" +
+        "    font-family:sans-serif,Tahoma,Arial;\n" +
+        "    font-weight: bold;\n" +
+        "    background: white;\n" +
+        "    color: black;\n" +
+        "  }\n" +
+        "  td.title {\n" +
+        "    text-align: left;\n" +
+        "    vertical-align: top;\n" +
+        "    font-family:sans-serif,Tahoma,Arial;\n" +
+        "    font-style:italic;\n" +
+        "    font-weight: bold;\n" +
+        "    background: #D2A41C;\n" +
+        "  }\n" +
+        "  td.header-left {\n" +
+        "    text-align: left;\n" +
+        "    vertical-align: top;\n" +
+        "    font-family:sans-serif,Tahoma,Arial;\n" +
+        "    font-weight: bold;\n" +
+        "    background: #FFDC75;\n" +
+        "  }\n" +
+        "  td.header-center {\n" +
+        "    text-align: center;\n" +
+        "    vertical-align: top;\n" +
+        "    font-family:sans-serif,Tahoma,Arial;\n" +
+        "    font-weight: bold;\n" +
+        "    background: #FFDC75;\n" +
+        "  }\n" +
+        "  td.row-left {\n" +
+        "    text-align: left;\n" +
+        "    vertical-align: middle;\n" +
+        "    font-family:sans-serif,Tahoma,Arial;\n" +
+        "    color: black;\n" +
+        "  }\n" +
+        "  td.row-center {\n" +
+        "    text-align: center;\n" +
+        "    vertical-align: middle;\n" +
+        "    font-family:sans-serif,Tahoma,Arial;\n" +
+        "    color: black;\n" +
+        "  }\n" +
+        "  td.row-right {\n" +
+        "    text-align: right;\n" +
+        "    vertical-align: middle;\n" +
+        "    font-family:sans-serif,Tahoma,Arial;\n" +
+        "    color: black;\n" +
+        "  }\n" +
+        "  TH {\n" +
+        "    text-align: center;\n" +
+        "    vertical-align: top;\n" +
+        "    font-family:sans-serif,Tahoma,Arial;\n" +
+        "    font-weight: bold;\n" +
+        "    background: #FFDC75;\n" +
+        "  }\n" +
+        "  TD {\n" +
+        "    text-align: center;\n" +
+        "    vertical-align: middle;\n" +
+        "    font-family:sans-serif,Tahoma,Arial;\n" +
+        "    color: black;\n" +
+        "  }\n" +
+        "</style>\n";
+
+    public static final String BODY_HEADER_SECTION =
+        "<title>{0}</title>\n" +
+        "</head>\n" +
+        "\n" +
+        "<body bgcolor=\"#FFFFFF\">\n" +
+        "\n" +
+        "<table cellspacing=\"4\" width=\"100%\" border=\"0\">\n" +
+        " <tr>\n" +
+        "  <td colspan=\"2\">\n" +
+        "   <a href=\"http://www.apache.org/\">\n" +
+        "    <img border=\"0\" alt=\"The Apache Software Foundation\" align=\"left\"\n" +
+        "         src=\"{0}/images/asf-logo.gif\">\n" +
+        "   </a>\n" +
+        "   <a href=\"http://tomcat.apache.org/\">\n" +
+        "    <img border=\"0\" alt=\"The Tomcat Servlet/JSP Container\"\n" +
+        "         align=\"right\" src=\"{0}/images/tomcat.gif\">\n" +
+        "   </a>\n" +
+        "  </td>\n" +
+        " </tr>\n" +
+        "</table>\n" +
+        "<hr size=\"1\" noshade=\"noshade\">\n" +
+        "<table cellspacing=\"4\" width=\"100%\" border=\"0\">\n" +
+        " <tr>\n" +
+        "  <td class=\"page-title\" bordercolor=\"#000000\" " +
+        "align=\"left\" nowrap>\n" +
+        "   <font size=\"+2\">{1}</font>\n" +
+        "  </td>\n" +
+        " </tr>\n" +
+        "</table>\n" +
+        "<br>\n" +
+        "\n";
+
+    public static final String MESSAGE_SECTION =
+        "<table border=\"1\" cellspacing=\"0\" cellpadding=\"3\">\n" +
+        " <tr>\n" +
+        "  <td class=\"row-left\" width=\"10%\">" +
+        "<small><strong>{0}</strong></small>&nbsp;</td>\n" +
+        "  <td class=\"row-left\"><pre>{1}</pre></td>\n" +
+        " </tr>\n" +
+        "</table>\n" +
+        "<br>\n" +
+        "\n";
+
+    public static final String MANAGER_SECTION =
+        "<table border=\"1\" cellspacing=\"0\" cellpadding=\"3\">\n" +
+        "<tr>\n" +
+        " <td colspan=\"4\" class=\"title\">{0}</td>\n" +
+        "</tr>\n" +
+        " <tr>\n" +
+        "  <td class=\"row-left\"><a href=\"{1}\">{2}</a></td>\n" +
+        "  <td class=\"row-center\"><a href=\"{3}\">{4}</a></td>\n" +
+        "  <td class=\"row-center\"><a href=\"{5}\">{6}</a></td>\n" +
+        "  <td class=\"row-right\"><a href=\"{7}\">{8}</a></td>\n" +
+        " </tr>\n" +
+        "</table>\n" +
+        "<br>\n" +
+        "\n";
+
+    public static final String SERVER_HEADER_SECTION =
+        "<table border=\"1\" cellspacing=\"0\" cellpadding=\"3\">\n" +
+        "<tr>\n" +
+        " <td colspan=\"6\" class=\"title\">{0}</td>\n" +
+        "</tr>\n" +
+        "<tr>\n" +
+        " <td class=\"header-center\"><small>{1}</small></td>\n" +
+        " <td class=\"header-center\"><small>{2}</small></td>\n" +
+        " <td class=\"header-center\"><small>{3}</small></td>\n" +
+        " <td class=\"header-center\"><small>{4}</small></td>\n" +
+        " <td class=\"header-center\"><small>{5}</small></td>\n" +
+        " <td class=\"header-center\"><small>{6}</small></td>\n" +
+        "</tr>\n";
+
+    public static final String SERVER_ROW_SECTION =
+        "<tr>\n" +
+        " <td class=\"row-center\"><small>{0}</small></td>\n" +
+        " <td class=\"row-center\"><small>{1}</small></td>\n" +
+        " <td class=\"row-center\"><small>{2}</small></td>\n" +
+        " <td class=\"row-center\"><small>{3}</small></td>\n" +
+        " <td class=\"row-center\"><small>{4}</small></td>\n" +
+        " <td class=\"row-center\"><small>{5}</small></td>\n" +
+        "</tr>\n" +
+        "</table>\n" +
+        "<br>\n" +
+        "\n";
+
+    public static final String HTML_TAIL_SECTION =
+        "<hr size=\"1\" noshade=\"noshade\">\n" +
+        "<center><font size=\"-1\" color=\"#525D76\">\n" +
+        " <em>Copyright &copy; 1999-2005, Apache Software Foundation</em>" +
+        "</font></center>\n" +
+        "\n" +
+        "</body>\n" +
+        "</html>";
+    public static final String CHARSET="utf-8";
+
+    public static final String XML_DECLARATION =
+        "<?xml version=\"1.0\" encoding=\""+CHARSET+"\"?>";
+		
+    public static final String XML_STYLE =
+        "<?xml-stylesheet type=\"text/xsl\" href=\"/manager/xform.xsl\" ?>";
+
+}
+

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/manager/WEB-INF/classes/org/apache/catalina/manager/HTMLManagerServlet.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/manager/WEB-INF/classes/org/apache/catalina/manager/HTMLManagerServlet.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/manager/WEB-INF/classes/org/apache/catalina/manager/HTMLManagerServlet.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,691 @@
+/*
+ * Copyright 1999,2004-2005 The Apache Software Foundation.
+ * 
+ * Licensed 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.manager;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.text.MessageFormat;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.catalina.Container;
+import org.apache.catalina.Context;
+import org.apache.catalina.util.RequestUtil;
+import org.apache.catalina.util.ServerInfo;
+import org.apache.commons.fileupload.FileItem;
+import org.apache.commons.fileupload.DiskFileUpload;
+
+/**
+* Servlet that enables remote management of the web applications deployed
+* within the same virtual host as this web application is.  Normally, this
+* functionality will be protected by a security constraint in the web
+* application deployment descriptor.  However, this requirement can be
+* relaxed during testing.
+* <p>
+* The difference between the <code>ManagerServlet</code> and this
+* Servlet is that this Servlet prints out a HTML interface which
+* makes it easier to administrate.
+* <p>
+* However if you use a software that parses the output of
+* <code>ManagerServlet</code you won't be able to upgrade
+* to this Servlet since the output are not in the
+* same format ar from <code>ManagerServlet</code>
+*
+* @author Bip Thelin
+* @author Malcolm Edgar
+* @author Glenn L. Nielsen
+* @version $Revision: 326772 $, $Date: 2005-10-19 20:37:02 -0500 (Wed, 19 Oct 2005) $
+* @see ManagerServlet
+*/
+
+public final class HTMLManagerServlet extends ManagerServlet {
+
+    // --------------------------------------------------------- Public Methods
+
+    /**
+     * Process a GET request for the specified resource.
+     *
+     * @param request The servlet request we are processing
+     * @param response The servlet response we are creating
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception ServletException if a servlet-specified error occurs
+     */
+    public void doGet(HttpServletRequest request,
+                      HttpServletResponse response)
+        throws IOException, ServletException {
+
+        // Identify the request parameters that we need
+        String command = request.getPathInfo();
+
+        String path = request.getParameter("path");
+        String deployPath = request.getParameter("deployPath");
+        String deployConfig = request.getParameter("deployConfig");
+        String deployWar = request.getParameter("deployWar");
+
+        // Prepare our output writer to generate the response message
+        response.setContentType("text/html; charset=" + Constants.CHARSET);
+
+        String message = "";
+        // Process the requested command
+        if (command == null || command.equals("/")) {
+        } else if (command.equals("/deploy")) {
+            message = deployInternal(deployConfig, deployPath, deployWar);
+        } else if (command.equals("/list")) {
+        } else if (command.equals("/reload")) {
+            message = reload(path);
+        } else if (command.equals("/undeploy")) {
+            message = undeploy(path);
+        } else if (command.equals("/sessions")) {
+            message = sessions(path);
+        } else if (command.equals("/start")) {
+            message = start(path);
+        } else if (command.equals("/stop")) {
+            message = stop(path);
+        } else {
+            message =
+                sm.getString("managerServlet.unknownCommand",
+                             RequestUtil.filter(command));
+        }
+
+        list(request, response, message);
+    }
+
+    /**
+     * Process a POST request for the specified resource.
+     *
+     * @param request The servlet request we are processing
+     * @param response The servlet response we are creating
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception ServletException if a servlet-specified error occurs
+     */
+    public void doPost(HttpServletRequest request,
+                      HttpServletResponse response)
+        throws IOException, ServletException {
+
+        // Identify the request parameters that we need
+        String command = request.getPathInfo();
+
+        if (command == null || !command.equals("/upload")) {
+            doGet(request,response);
+            return;
+        }
+
+        // Prepare our output writer to generate the response message
+        response.setContentType("text/html; charset=" + Constants.CHARSET);
+
+        String message = "";
+
+        // Create a new file upload handler
+        DiskFileUpload upload = new DiskFileUpload();
+
+        // Get the tempdir
+        File tempdir = (File) getServletContext().getAttribute
+            ("javax.servlet.context.tempdir");
+        // Set upload parameters
+        upload.setSizeMax(-1);
+        upload.setRepositoryPath(tempdir.getCanonicalPath());
+    
+        // Parse the request
+        String basename = null;
+        String war = null;
+        FileItem warUpload = null;
+        try {
+            List items = upload.parseRequest(request);
+        
+            // Process the uploaded fields
+            Iterator iter = items.iterator();
+            while (iter.hasNext()) {
+                FileItem item = (FileItem) iter.next();
+        
+                if (!item.isFormField()) {
+                    if (item.getFieldName().equals("deployWar") &&
+                        warUpload == null) {
+                        warUpload = item;
+                    } else {
+                        item.delete();
+                    }
+                }
+            }
+            while (true) {
+                if (warUpload == null) {
+                    message = sm.getString
+                        ("htmlManagerServlet.deployUploadNoFile");
+                    break;
+                }
+                war = warUpload.getName();
+                if (!war.toLowerCase().endsWith(".war")) {
+                    message = sm.getString
+                        ("htmlManagerServlet.deployUploadNotWar",war);
+                    break;
+                }
+                // Get the filename if uploaded name includes a path
+                if (war.lastIndexOf('\\') >= 0) {
+                    war = war.substring(war.lastIndexOf('\\') + 1);
+                }
+                if (war.lastIndexOf('/') >= 0) {
+                    war = war.substring(war.lastIndexOf('/') + 1);
+                }
+                // Identify the appBase of the owning Host of this Context
+                // (if any)
+                basename = war.substring(0, war.toLowerCase().indexOf(".war"));
+                File file = new File(getAppBase(), war);
+                if (file.exists()) {
+                    message = sm.getString
+                        ("htmlManagerServlet.deployUploadWarExists",war);
+                    break;
+                }
+                String path = null;
+                if (basename.equals("ROOT")) {
+                    path = "";
+                } else {
+                    path = "/" + basename;
+                }
+
+                if (!isServiced(path)) {
+                    addServiced(path);
+                    try {
+                        warUpload.write(file);
+                        // Perform new deployment
+                        check(path);
+                    } finally {
+                        removeServiced(path);
+                    }
+                }
+                break;
+            }
+        } catch(Exception e) {
+            message = sm.getString
+                ("htmlManagerServlet.deployUploadFail", e.getMessage());
+            log(message, e);
+        } finally {
+            if (warUpload != null) {
+                warUpload.delete();
+            }
+            warUpload = null;
+        }
+
+        list(request, response, message);
+    }
+
+    /**
+     * Deploy an application for the specified path from the specified
+     * web application archive.
+     *
+     * @param config URL of the context configuration file to be deployed
+     * @param path Context path of the application to be deployed
+     * @param war URL of the web application archive to be deployed
+     * @return message String
+     */
+    protected String deployInternal(String config, String path, String war) {
+
+        StringWriter stringWriter = new StringWriter();
+        PrintWriter printWriter = new PrintWriter(stringWriter);
+
+        super.deploy(printWriter, config, path, war, false);
+
+        return stringWriter.toString();
+    }
+
+    /**
+     * Render a HTML list of the currently active Contexts in our virtual host,
+     * and memory and server status information.
+     *
+     * @param request The request
+     * @param response The response
+     * @param message a message to display
+     */
+    public void list(HttpServletRequest request,
+                     HttpServletResponse response,
+                     String message) throws IOException {
+
+        if (debug >= 1)
+            log("list: Listing contexts for virtual host '" +
+                host.getName() + "'");
+
+        PrintWriter writer = response.getWriter();
+
+        // HTML Header Section
+        writer.print(Constants.HTML_HEADER_SECTION);
+
+        // Body Header Section
+        Object[] args = new Object[2];
+        args[0] = request.getContextPath();
+        args[1] = sm.getString("htmlManagerServlet.title");
+        writer.print(MessageFormat.format
+                     (Constants.BODY_HEADER_SECTION, args));
+
+        // Message Section
+        args = new Object[3];
+        args[0] = sm.getString("htmlManagerServlet.messageLabel");
+        args[1] = (message == null || message.length() == 0) ? "OK" : message;
+        writer.print(MessageFormat.format(Constants.MESSAGE_SECTION, args));
+
+        // Manager Section
+        args = new Object[9];
+        args[0] = sm.getString("htmlManagerServlet.manager");
+        args[1] = response.encodeURL(request.getContextPath() + "/html/list");
+        args[2] = sm.getString("htmlManagerServlet.list");
+        args[3] = response.encodeURL
+            (request.getContextPath() + "/" +
+             sm.getString("htmlManagerServlet.helpHtmlManagerFile"));
+        args[4] = sm.getString("htmlManagerServlet.helpHtmlManager");
+        args[5] = response.encodeURL
+            (request.getContextPath() + "/" +
+             sm.getString("htmlManagerServlet.helpManagerFile"));
+        args[6] = sm.getString("htmlManagerServlet.helpManager");
+        args[7] = response.encodeURL
+            (request.getContextPath() + "/status");
+        args[8] = sm.getString("statusServlet.title");
+        writer.print(MessageFormat.format(Constants.MANAGER_SECTION, args));
+
+        // Apps Header Section
+        args = new Object[6];
+        args[0] = sm.getString("htmlManagerServlet.appsTitle");
+        args[1] = sm.getString("htmlManagerServlet.appsPath");
+        args[2] = sm.getString("htmlManagerServlet.appsName");
+        args[3] = sm.getString("htmlManagerServlet.appsAvailable");
+        args[4] = sm.getString("htmlManagerServlet.appsSessions");
+        args[5] = sm.getString("htmlManagerServlet.appsTasks");
+        writer.print(MessageFormat.format(APPS_HEADER_SECTION, args));
+
+        // Apps Row Section
+        // Create sorted map of deployed applications context paths.
+        Container children[] = host.findChildren();
+        String contextPaths[] = new String[children.length];
+        for (int i = 0; i < children.length; i++)
+            contextPaths[i] = children[i].getName();
+
+        TreeMap sortedContextPathsMap = new TreeMap();
+
+        for (int i = 0; i < contextPaths.length; i++) {
+            String displayPath = contextPaths[i];
+            sortedContextPathsMap.put(displayPath, contextPaths[i]);
+        }
+
+        String appsStart = sm.getString("htmlManagerServlet.appsStart");
+        String appsStop = sm.getString("htmlManagerServlet.appsStop");
+        String appsReload = sm.getString("htmlManagerServlet.appsReload");
+        String appsUndeploy = sm.getString("htmlManagerServlet.appsUndeploy");
+
+        Iterator iterator = sortedContextPathsMap.entrySet().iterator();
+        boolean isHighlighted = true;
+        String highlightColor = null;
+
+        while (iterator.hasNext()) {
+            // Bugzilla 34818, alternating row colors
+            isHighlighted = !isHighlighted;
+            if(isHighlighted) {
+                highlightColor = "#C3F3C3";
+            } else {
+                highlightColor = "#FFFFFF";
+            }
+
+            Map.Entry entry = (Map.Entry) iterator.next();
+            String displayPath = (String) entry.getKey();
+            String contextPath = (String) entry.getKey();
+            Context context = (Context) host.findChild(contextPath);
+            if (displayPath.equals("")) {
+                displayPath = "/";
+            }
+
+            if (context != null ) {
+                args = new Object[6];
+                args[0] = displayPath;
+                args[1] = context.getDisplayName();
+                if (args[1] == null) {
+                    args[1] = "&nbsp;";
+                }
+                args[2] = new Boolean(context.getAvailable());
+                args[3] = response.encodeURL
+                    (request.getContextPath() +
+                     "/html/sessions?path=" + displayPath);
+                if (context.getManager() != null) {
+                    args[4] = new Integer
+                        (context.getManager().getActiveSessions());
+                } else {
+                    args[4] = new Integer(0);
+                }
+
+                args[5] = highlightColor;
+
+                writer.print
+                    (MessageFormat.format(APPS_ROW_DETAILS_SECTION, args));
+
+                args = new Object[9];
+                args[0] = response.encodeURL
+                    (request.getContextPath() +
+                     "/html/start?path=" + displayPath);
+                args[1] = appsStart;
+                args[2] = response.encodeURL
+                    (request.getContextPath() +
+                     "/html/stop?path=" + displayPath);
+                args[3] = appsStop;
+                args[4] = response.encodeURL
+                    (request.getContextPath() +
+                     "/html/reload?path=" + displayPath);
+                args[5] = appsReload;
+                args[6] = response.encodeURL
+                    (request.getContextPath() +
+                     "/html/undeploy?path=" + displayPath);
+                args[7] = appsUndeploy;
+                
+                args[8] = highlightColor;
+
+                if (context.getPath().equals(this.context.getPath())) {
+                    writer.print(MessageFormat.format(
+                        MANAGER_APP_ROW_BUTTON_SECTION, args));
+                } else if (context.getAvailable()) {
+                    writer.print(MessageFormat.format(
+                        STARTED_APPS_ROW_BUTTON_SECTION, args));
+                } else {
+                    writer.print(MessageFormat.format(
+                        STOPPED_APPS_ROW_BUTTON_SECTION, args));
+                }
+
+            }
+        }
+
+        // Deploy Section
+        args = new Object[7];
+        args[0] = sm.getString("htmlManagerServlet.deployTitle");
+        args[1] = sm.getString("htmlManagerServlet.deployServer");
+        args[2] = response.encodeURL(request.getContextPath() + "/html/deploy");
+        args[3] = sm.getString("htmlManagerServlet.deployPath");
+        args[4] = sm.getString("htmlManagerServlet.deployConfig");
+        args[5] = sm.getString("htmlManagerServlet.deployWar");
+        args[6] = sm.getString("htmlManagerServlet.deployButton");
+        writer.print(MessageFormat.format(DEPLOY_SECTION, args));
+
+        args = new Object[4];
+        args[0] = sm.getString("htmlManagerServlet.deployUpload");
+        args[1] = response.encodeURL(request.getContextPath() + "/html/upload");
+        args[2] = sm.getString("htmlManagerServlet.deployUploadFile");
+        args[3] = sm.getString("htmlManagerServlet.deployButton");
+        writer.print(MessageFormat.format(UPLOAD_SECTION, args));
+
+        // Server Header Section
+        args = new Object[7];
+        args[0] = sm.getString("htmlManagerServlet.serverTitle");
+        args[1] = sm.getString("htmlManagerServlet.serverVersion");
+        args[2] = sm.getString("htmlManagerServlet.serverJVMVersion");
+        args[3] = sm.getString("htmlManagerServlet.serverJVMVendor");
+        args[4] = sm.getString("htmlManagerServlet.serverOSName");
+        args[5] = sm.getString("htmlManagerServlet.serverOSVersion");
+        args[6] = sm.getString("htmlManagerServlet.serverOSArch");
+        writer.print(MessageFormat.format
+                     (Constants.SERVER_HEADER_SECTION, args));
+
+        // Server Row Section
+        args = new Object[6];
+        args[0] = ServerInfo.getServerInfo();
+        args[1] = System.getProperty("java.runtime.version");
+        args[2] = System.getProperty("java.vm.vendor");
+        args[3] = System.getProperty("os.name");
+        args[4] = System.getProperty("os.version");
+        args[5] = System.getProperty("os.arch");
+        writer.print(MessageFormat.format(Constants.SERVER_ROW_SECTION, args));
+
+        // HTML Tail Section
+        writer.print(Constants.HTML_TAIL_SECTION);
+
+        // Finish up the response
+        writer.flush();
+        writer.close();
+    }
+
+    /**
+     * Reload the web application at the specified context path.
+     *
+     * @see ManagerServlet#reload(PrintWriter, String)
+     *
+     * @param path Context path of the application to be restarted
+     * @return message String
+     */
+    protected String reload(String path) {
+
+        StringWriter stringWriter = new StringWriter();
+        PrintWriter printWriter = new PrintWriter(stringWriter);
+
+        super.reload(printWriter, path);
+
+        return stringWriter.toString();
+    }
+
+    /**
+     * Undeploy the web application at the specified context path.
+     *
+     * @see ManagerServlet#undeploy(PrintWriter, String)
+     *
+     * @param path Context path of the application to be undeployd
+     * @return message String
+     */
+    protected String undeploy(String path) {
+
+        StringWriter stringWriter = new StringWriter();
+        PrintWriter printWriter = new PrintWriter(stringWriter);
+
+        super.undeploy(printWriter, path);
+
+        return stringWriter.toString();
+    }
+
+    /**
+     * Display session information and invoke list.
+     *
+     * @see ManagerServlet#sessions(PrintWriter, String)
+     *
+     * @param path Context path of the application to list session information
+     * @return message String
+     */
+    public String sessions(String path) {
+
+        StringWriter stringWriter = new StringWriter();
+        PrintWriter printWriter = new PrintWriter(stringWriter);
+
+        super.sessions(printWriter, path);
+
+        return stringWriter.toString();
+    }
+
+    /**
+     * Start the web application at the specified context path.
+     *
+     * @see ManagerServlet#start(PrintWriter, String)
+     *
+     * @param path Context path of the application to be started
+     * @return message String
+     */
+    public String start(String path) {
+
+        StringWriter stringWriter = new StringWriter();
+        PrintWriter printWriter = new PrintWriter(stringWriter);
+
+        super.start(printWriter, path);
+
+        return stringWriter.toString();
+    }
+
+    /**
+     * Stop the web application at the specified context path.
+     *
+     * @see ManagerServlet#stop(PrintWriter, String)
+     *
+     * @param path Context path of the application to be stopped
+     * @return message String
+     */
+    protected String stop(String path) {
+
+        StringWriter stringWriter = new StringWriter();
+        PrintWriter printWriter = new PrintWriter(stringWriter);
+
+        super.stop(printWriter, path);
+
+        return stringWriter.toString();
+    }
+
+    // ------------------------------------------------------ Private Constants
+
+    // These HTML sections are broken in relatively small sections, because of
+    // limited number of subsitutions MessageFormat can process
+    // (maximium of 10).
+
+    private static final String APPS_HEADER_SECTION =
+        "<table border=\"1\" cellspacing=\"0\" cellpadding=\"3\">\n" +
+        "<tr>\n" +
+        " <td colspan=\"5\" class=\"title\">{0}</td>\n" +
+        "</tr>\n" +
+        "<tr>\n" +
+        " <td class=\"header-left\"><small>{1}</small></td>\n" +
+        " <td class=\"header-left\"><small>{2}</small></td>\n" +
+        " <td class=\"header-center\"><small>{3}</small></td>\n" +
+        " <td class=\"header-center\"><small>{4}</small></td>\n" +
+        " <td class=\"header-center\"><small>{5}</small></td>\n" +
+        "</tr>\n";
+
+    private static final String APPS_ROW_DETAILS_SECTION =
+        "<tr>\n" +
+        " <td class=\"row-left\" bgcolor=\"{5}\"><small><a href=\"{0}\">{0}</a></small></td>\n" +
+        " <td class=\"row-left\" bgcolor=\"{5}\"><small>{1}</small></td>\n" +
+        " <td class=\"row-center\" bgcolor=\"{5}\"><small>{2}</small></td>\n" +
+        " <td class=\"row-center\" bgcolor=\"{5}\"><small><a href=\"{3}\">{4}</a></small></td>\n";
+
+    private static final String MANAGER_APP_ROW_BUTTON_SECTION =
+        " <td class=\"row-left\" bgcolor=\"{8}\">\n" +
+        "  <small>\n" +
+        "  &nbsp;{1}&nbsp;\n" +
+        "  &nbsp;{3}&nbsp;\n" +
+        "  &nbsp;{5}&nbsp;\n" +
+        "  &nbsp;{7}&nbsp;\n" +
+        "  </small>\n" +
+        " </td>\n" +
+        "</tr>\n";
+
+    private static final String STARTED_APPS_ROW_BUTTON_SECTION =
+        " <td class=\"row-left\" bgcolor=\"{8}\">\n" +
+        "  <small>\n" +
+        "  &nbsp;{1}&nbsp;\n" +
+        "  &nbsp;<a href=\"{2}\" onclick=\"return(confirm('''Are you sure?'''))\">{3}</a>&nbsp;\n" +
+        "  &nbsp;<a href=\"{4}\" onclick=\"return(confirm('''Are you sure?'''))\">{5}</a>&nbsp;\n" +
+        "  &nbsp;<a href=\"{6}\" onclick=\"return(confirm('''Are you sure?'''))\">{7}</a>&nbsp;\n" +
+        "  </small>\n" +
+        " </td>\n" +
+        "</tr>\n";
+
+    private static final String STOPPED_APPS_ROW_BUTTON_SECTION =
+        " <td class=\"row-left\" bgcolor=\"{8}\">\n" +
+        "  <small>\n" +
+        "  &nbsp;<a href=\"{0}\" onclick=\"return(confirm('''Are you sure?'''))\">{1}</a>&nbsp;\n" +
+        "  &nbsp;{3}&nbsp;\n" +
+        "  &nbsp;{5}&nbsp;\n" +
+        "  &nbsp;<a href=\"{6}\" onclick=\"return(confirm('''Are you sure?  This will delete the application.'''))\">{7}</a>&nbsp;\n" +
+        "  </small>\n" +
+        " </td>\n" +
+        "</tr>\n";
+
+    private static final String DEPLOY_SECTION =
+        "</table>\n" +
+        "<br>\n" +
+        "<table border=\"1\" cellspacing=\"0\" cellpadding=\"3\">\n" +
+        "<tr>\n" +
+        " <td colspan=\"2\" class=\"title\">{0}</td>\n" +
+        "</tr>\n" +
+        "<tr>\n" +
+        " <td colspan=\"2\" class=\"header-left\"><small>{1}</small></td>\n" +
+        "</tr>\n" +
+        "<tr>\n" +
+        " <td colspan=\"2\">\n" +
+        "<form method=\"get\" action=\"{2}\">\n" +
+        "<table cellspacing=\"0\" cellpadding=\"3\">\n" +
+        "<tr>\n" +
+        " <td class=\"row-right\">\n" +
+        "  <small>{3}</small>\n" +
+        " </td>\n" +
+        " <td class=\"row-left\">\n" +
+        "  <input type=\"text\" name=\"deployPath\" size=\"20\">\n" +
+        " </td>\n" +
+        "</tr>\n" +
+        "<tr>\n" +
+        " <td class=\"row-right\">\n" +
+        "  <small>{4}</small>\n" +
+        " </td>\n" +
+        " <td class=\"row-left\">\n" +
+        "  <input type=\"text\" name=\"deployConfig\" size=\"20\">\n" +
+        " </td>\n" +
+        "</tr>\n" +
+        "<tr>\n" +
+        " <td class=\"row-right\">\n" +
+        "  <small>{5}</small>\n" +
+        " </td>\n" +
+        " <td class=\"row-left\">\n" +
+        "  <input type=\"text\" name=\"deployWar\" size=\"40\">\n" +
+        " </td>\n" +
+        "</tr>\n" +
+        "<tr>\n" +
+        " <td class=\"row-right\">\n" +
+        "  &nbsp;\n" +
+        " </td>\n" +
+        " <td class=\"row-left\">\n" +
+        "  <input type=\"submit\" value=\"{6}\">\n" +
+        " </td>\n" +
+        "</tr>\n" +
+        "</table>\n" +
+        "</form>\n" +
+        "</td>\n" +
+        "</tr>\n";
+
+    private static final String UPLOAD_SECTION =
+        "<tr>\n" +
+        " <td colspan=\"2\" class=\"header-left\"><small>{0}</small></td>\n" +
+        "</tr>\n" +
+        "<tr>\n" +
+        " <td colspan=\"2\">\n" +
+        "<form action=\"{1}\" method=\"post\" " +
+        "enctype=\"multipart/form-data\">\n" +
+        "<table cellspacing=\"0\" cellpadding=\"3\">\n" +
+        "<tr>\n" +
+        " <td class=\"row-right\">\n" +
+        "  <small>{2}</small>\n" +
+        " </td>\n" +
+        " <td class=\"row-left\">\n" +
+        "  <input type=\"file\" name=\"deployWar\" size=\"40\">\n" +
+        " </td>\n" +
+        "</tr>\n" +
+        "<tr>\n" +
+        " <td class=\"row-right\">\n" +
+        "  &nbsp;\n" +
+        " </td>\n" +
+        " <td class=\"row-left\">\n" +
+        "  <input type=\"submit\" value=\"{3}\">\n" +
+        " </td>\n" +
+        "</tr>\n" +
+        "</table>\n" +
+        "</form>\n" +
+        "</table>\n" +
+        "<br>\n" +
+        "\n";
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/manager/WEB-INF/classes/org/apache/catalina/manager/JMXProxyServlet.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/manager/WEB-INF/classes/org/apache/catalina/manager/JMXProxyServlet.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/manager/WEB-INF/classes/org/apache/catalina/manager/JMXProxyServlet.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,231 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.manager;
+
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.Iterator;
+import java.util.Set;
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+import javax.management.MBeanInfo;
+import javax.management.MBeanAttributeInfo;
+import javax.management.Attribute;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import org.apache.commons.modeler.Registry;
+
+/**
+ * This servlet will dump JMX attributes in a simple format
+ * and implement proxy services for modeler.
+ *
+ * @author Costin Manolache
+ */
+public class JMXProxyServlet extends HttpServlet  {
+    // ----------------------------------------------------- Instance Variables
+
+    /**
+     * MBean server.
+     */
+    protected MBeanServer mBeanServer = null;
+    protected Registry registry;
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Initialize this servlet.
+     */
+    public void init() throws ServletException {
+        // Retrieve the MBean server
+        registry = Registry.getRegistry(null, null);
+        mBeanServer = Registry.getRegistry(null, null).getMBeanServer();
+    }
+
+
+    /**
+     * Process a GET request for the specified resource.
+     *
+     * @param request The servlet request we are processing
+     * @param response The servlet response we are creating
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception ServletException if a servlet-specified error occurs
+     */
+    public void doGet(HttpServletRequest request,
+                      HttpServletResponse response)
+        throws IOException, ServletException
+    {
+
+        response.setContentType("text/plain");
+
+        PrintWriter writer = response.getWriter();
+
+        if( mBeanServer==null ) {
+            writer.println("Error - No mbean server");
+            return;
+        }
+
+        String qry=request.getParameter("set");
+        if( qry!= null ) {
+            String name=request.getParameter("att");
+            String val=request.getParameter("val");
+
+            setAttribute( writer, qry, name, val );
+            return;
+        }
+        qry=request.getParameter("get");
+        if( qry!= null ) {
+            String name=request.getParameter("att");
+            getAttribute( writer, qry, name );
+            return;
+        }        
+        qry=request.getParameter("qry");
+        if( qry == null ) {
+            qry = "*:*";
+        }
+
+        listBeans( writer, qry );
+
+    }
+
+    public void getAttribute(PrintWriter writer, String onameStr, String att) {
+        try {
+            ObjectName oname = new ObjectName(onameStr);
+            Object value = mBeanServer.getAttribute(oname, att);
+            writer.println("OK - Attribute get '" + onameStr + "' - " + att
+                    + "= " + escape(value.toString()));
+        } catch (Exception ex) {
+            writer.println("Error - " + ex.toString());
+        }
+    }
+
+    public void setAttribute( PrintWriter writer,
+                              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));
+            writer.println("OK - Attribute set");
+        } catch( Exception ex ) {
+            writer.println("Error - " + ex.toString());
+        }
+    }
+
+    public void listBeans( PrintWriter writer, String qry )
+    {
+
+        Set names = null;
+        try {
+            names=mBeanServer.queryNames(new ObjectName(qry), null);
+            writer.println("OK - Number of results: " + names.size());
+            writer.println();
+        } catch (Exception e) {
+            writer.println("Error - " + e.toString());
+            return;
+        }
+
+        Iterator it=names.iterator();
+        while( it.hasNext()) {
+            ObjectName oname=(ObjectName)it.next();
+            writer.println( "Name: " + oname.toString());
+
+            try {
+                MBeanInfo minfo=mBeanServer.getMBeanInfo(oname);
+                // can't be null - I thinl
+                String code=minfo.getClassName();
+                if ("org.apache.commons.modeler.BaseModelMBean".equals(code)) {
+                    code=(String)mBeanServer.getAttribute(oname, "modelerType");
+                }
+                writer.println("modelerType: " + code);
+
+                MBeanAttributeInfo attrs[]=minfo.getAttributes();
+                Object value=null;
+
+                for( int i=0; i< attrs.length; i++ ) {
+                    if( ! attrs[i].isReadable() ) continue;
+                    if( ! isSupported( attrs[i].getType() )) continue;
+                    String attName=attrs[i].getName();
+                    if( attName.indexOf( "=") >=0 ||
+                            attName.indexOf( ":") >=0 ||
+                            attName.indexOf( " ") >=0 ) {
+                        continue;
+                    }
+            
+                    try {
+                        value=mBeanServer.getAttribute(oname, attName);
+                    } catch( Throwable t) {
+                        System.out.println("Error getting attribute " + oname +
+                                " " + attName + " " + t.toString());
+                        continue;
+                    }
+                    if( value==null ) continue;
+                    if( "modelerType".equals( attName)) continue;
+                    String valueString=value.toString();
+                    writer.println( attName + ": " + escape(valueString));
+                }
+            } catch (Exception e) {
+                // Ignore
+            }
+            writer.println();
+        }
+
+    }
+
+    public String escape(String value) {
+        // The only invalid char is \n
+        // We also need to keep the string short and split it with \nSPACE
+        // XXX TODO
+        int idx=value.indexOf( "\n" );
+        if( idx < 0 ) return value;
+
+        int prev=0;
+        StringBuffer sb=new StringBuffer();
+        while( idx >= 0 ) {
+            appendHead(sb, value, prev, idx);
+
+            sb.append( "\\n\n ");
+            prev=idx+1;
+            if( idx==value.length() -1 ) break;
+            idx=value.indexOf('\n', idx+1);
+        }
+        if( prev < value.length() )
+            appendHead( sb, value, prev, value.length());
+        return sb.toString();
+    }
+
+    private void appendHead( StringBuffer sb, String value, int start, int end) {
+        if (end < 1) return;
+        
+        int pos=start;
+        while( end-pos > 78 ) {
+            sb.append( value.substring(pos, pos+78));
+            sb.append( "\n ");
+            pos=pos+78;
+        }
+        sb.append( value.substring(pos,end));
+    }
+
+    public boolean isSupported( String type ) {
+        return true;
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/manager/WEB-INF/classes/org/apache/catalina/manager/LocalStrings.properties
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/manager/WEB-INF/classes/org/apache/catalina/manager/LocalStrings.properties	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/manager/WEB-INF/classes/org/apache/catalina/manager/LocalStrings.properties	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,81 @@
+htmlManagerServlet.appsAvailable=Running
+htmlManagerServlet.appsName=Display Name
+htmlManagerServlet.appsPath=Path
+htmlManagerServlet.appsReload=Reload
+htmlManagerServlet.appsUndeploy=Undeploy
+htmlManagerServlet.appsSessions=Sessions
+htmlManagerServlet.appsStart=Start
+htmlManagerServlet.appsStop=Stop
+htmlManagerServlet.appsTasks=Commands
+htmlManagerServlet.appsTitle=Applications
+htmlManagerServlet.helpHtmlManager=HTML Manager Help
+htmlManagerServlet.helpHtmlManagerFile=html-manager-howto.html
+htmlManagerServlet.helpManager=Manager Help
+htmlManagerServlet.helpManagerFile=manager-howto.html
+htmlManagerServlet.deployButton=Deploy
+htmlManagerServlet.deployConfig=XML Configuration file URL:
+htmlManagerServlet.deployPath=Context Path (optional):
+htmlManagerServlet.deployServer=Deploy directory or WAR file located on server
+htmlManagerServlet.deployTitle=Deploy
+htmlManagerServlet.deployUpload=WAR file to deploy
+htmlManagerServlet.deployUploadFail=FAIL - Deploy Upload Failed, Exception: {0}
+htmlManagerServlet.deployUploadFile=Select WAR file to upload
+htmlManagerServlet.deployUploadNotWar=FAIL - File uploaded \"{0}\" must be a .war
+htmlManagerServlet.deployUploadNoFile=FAIL - File upload failed, no file
+htmlManagerServlet.deployUploadWarExists=FAIL - War file \"{0}\" already exists on server
+htmlManagerServlet.deployWar=WAR or Directory URL:
+htmlManagerServlet.list=List Applications
+htmlManagerServlet.manager=Manager
+htmlManagerServlet.messageLabel=Message:
+htmlManagerServlet.serverJVMVendor=JVM Vendor
+htmlManagerServlet.serverJVMVersion=JVM Version
+htmlManagerServlet.serverOSArch=OS Architecture
+htmlManagerServlet.serverOSName=OS Name
+htmlManagerServlet.serverOSVersion=OS Version
+htmlManagerServlet.serverTitle=Server Information
+htmlManagerServlet.serverVersion=Tomcat Version
+htmlManagerServlet.title=Tomcat Web Application Manager
+managerServlet.alreadyContext=FAIL - Application already exists at path {0}
+managerServlet.alreadyDocBase=FAIL - Directory {0} is already in use
+managerServlet.cannotInvoke=Cannot invoke manager servlet through invoker
+managerServlet.configured=OK - Deployed application from context file {0}
+managerServlet.deployed=OK - Deployed application at context path {0}
+managerServlet.deployFailed=FAIL - Failed to deploy application at context path {0}
+managerServlet.exception=FAIL - Encountered exception {0}
+managerServlet.deployed=OK - Deployed application at context path {0}
+managerServlet.invalidPath=FAIL - Invalid context path {0} was specified
+managerServlet.invalidWar=FAIL - Invalid application URL {0} was specified
+managerServlet.listed=OK - Listed applications for virtual host {0}
+managerServlet.listitem={0}:{1}:{2}:{3}
+managerServlet.noAppBase=FAIL - Cannot identify application base for context path {0}
+managerServlet.noCommand=FAIL - No command was specified
+managerServlet.noContext=FAIL - No context exists for path {0}
+managerServlet.noDirectory=FAIL - Non-directory document base for path {0}
+managerServlet.noDocBase=FAIL - Cannot undeploy document base for path {0}
+managerServlet.noGlobal=FAIL - No global JNDI resources are available
+managerServlet.noReload=FAIL - Reload not supported on WAR deployed at path {0}
+managerServlet.noRename=FAIL - Cannot deploy uploaded WAR for path {0}
+managerServlet.noRole=FAIL - User does not possess role {0}
+managerServlet.noSelf=FAIL - The manager can not reload, undeploy, stop, or undeploy itself
+managerServlet.noWrapper=Container has not called setWrapper() for this servlet
+managerServlet.reloaded=OK - Reloaded application at context path {0}
+managerServlet.undeployd=OK - Undeployed application at context path {0}
+managerServlet.resourcesAll=OK - Listed global resources of all types
+managerServlet.resourcesType=OK - Listed global resources of type {0}
+managerServlet.rolesList=OK - Listed security roles
+managerServlet.saveFail=FAIL - Configuration save failed: {0}
+managerServlet.saved=OK - Server configuration saved
+managerServlet.savedContext=OK - Context {0} configuration saved
+managerServlet.sessiondefaultmax=Default maximum session inactive interval {0} minutes
+managerServlet.sessiontimeout={0} minutes:{1} sessions
+managerServlet.sessions=OK - Session information for application at context path {0}
+managerServlet.started=OK - Started application at context path {0}
+managerServlet.startFailed=FAIL - Application at context path {0} could not be started
+managerServlet.stopped=OK - Stopped application at context path {0}
+managerServlet.undeployed=OK - Undeployed application at context path {0}
+managerServlet.unknownCommand=FAIL - Unknown command {0}
+managerServlet.userDatabaseError=FAIL - Cannot resolve user database reference
+managerServlet.userDatabaseMissing=FAIL - No user database is available
+
+statusServlet.title=Server Status
+statusServlet.complete=Complete Server Status

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/manager/WEB-INF/classes/org/apache/catalina/manager/LocalStrings_de.properties
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/manager/WEB-INF/classes/org/apache/catalina/manager/LocalStrings_de.properties	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/manager/WEB-INF/classes/org/apache/catalina/manager/LocalStrings_de.properties	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,78 @@
+htmlManagerServlet.appsAvailable=Verfügbar
+htmlManagerServlet.appsName=Anzeigename
+htmlManagerServlet.appsPath=Kontext Pfad
+htmlManagerServlet.appsReload=Neu laden
+htmlManagerServlet.appsUndeploy=Entfernen
+htmlManagerServlet.appsSessions=Sitzungen
+htmlManagerServlet.appsStart=Start
+htmlManagerServlet.appsStop=Stop
+htmlManagerServlet.appsTasks=Kommandos
+htmlManagerServlet.appsTitle=Anwendungen
+htmlManagerServlet.helpHtmlManager=Hilfeseite HTML Manager (englisch)
+htmlManagerServlet.helpHtmlManagerFile=html-manager-howto.html
+htmlManagerServlet.helpManager=Hilfeseite Manager (englisch)
+htmlManagerServlet.helpManagerFile=manager-howto.html
+htmlManagerServlet.deployButton=Installieren
+htmlManagerServlet.deployConfig=XML Konfigurationsdatei URL:
+htmlManagerServlet.deployPath=Kontext Pfad (optional):
+htmlManagerServlet.deployServer=Verzeichnis oder WAR Datei auf Server installieren
+htmlManagerServlet.deployTitle=Installieren
+htmlManagerServlet.deployUpload=Lokale WAR Datei zur Installation hochladen
+htmlManagerServlet.deployUploadFail=FEHLER - Hochladen zur Installation fehlgeschlagen, Ausnahme: {0}
+htmlManagerServlet.deployUploadFile=WAR Datei auswählen
+htmlManagerServlet.deployUploadNotWar=FEHLER - Hochgeladene Datei \"{0}\" muss ein .war sein
+htmlManagerServlet.deployUploadNoFile=FEHLER - Hochladen fehlgeschlagen, keine Datei vorhanden
+htmlManagerServlet.deployUploadWarExists=FEHLER - WAR Datei \"{0}\" existiert bereits auf Server
+htmlManagerServlet.deployWar=WAR oder Verzeichnis URL:
+htmlManagerServlet.list=Anwendungen auflisten
+htmlManagerServlet.manager=Manager
+htmlManagerServlet.messageLabel=Nachricht:
+htmlManagerServlet.serverJVMVendor=JVM Hersteller
+htmlManagerServlet.serverJVMVersion=JVM Version
+htmlManagerServlet.serverOSArch=OS Architektur
+htmlManagerServlet.serverOSName=OS Name
+htmlManagerServlet.serverOSVersion=OS Version
+htmlManagerServlet.serverTitle=Server Informationen
+htmlManagerServlet.serverVersion=Tomcat Version
+htmlManagerServlet.title=Tomcat Webanwendungs-Manager
+managerServlet.alreadyContext=FEHLER - Anwendung existiert bereits für Kontext Pfad {0}
+managerServlet.alreadyDocBase=FEHLER - Verzeichnis {0} bereits in Benutzung
+managerServlet.cannotInvoke=Kann Manager-Servlet nicht durch Invoker aufrufen
+managerServlet.configured=OK - Anwendung von Kontext-Datei {0} installiert
+managerServlet.deployed=OK - Anwendung mit Kontext Pfad {0} installiert
+managerServlet.exception=FEHLER - Ausnahme aufgetreten {0}
+managerServlet.deployed=OK - Anwendung mit Kontext Pfad {0} installiert
+managerServlet.invalidPath=FEHLER - Ungültiger Kontext Pfad {0} angegeben
+managerServlet.invalidWar=FEHLER - Ungültige URL {0} für Anwendung angegeben
+managerServlet.listed=OK - Auflistung der Webanwendungen für virtuellen Server {0}
+managerServlet.listitem={0}:{1}:{2}:{3}
+managerServlet.noAppBase=FEHLER - Kann Verzeichnis für Kontext Pfad {0} nicht finden
+managerServlet.noCommand=FEHLER - Es wurde kein Kommando angegeben
+managerServlet.noContext=FEHLER - Es existiert kein Kontext für Pfad {0}
+managerServlet.noDirectory=FEHLER - Pfad {0} ist kein Verzeichnis
+managerServlet.noDocBase=FEHLER - Kann Webanwendungs-Verzeichnis nicht entfernen für Kontext Pfad {0}
+managerServlet.noGlobal=FEHLER - Keine globalen JNDI Ressourcen verfügbar
+managerServlet.noReload=FEHLER - Neu laden nicht unterstützt für WAR mit Pfad {0}
+managerServlet.noRename=FEHLER - Kann hochgeladenes WAR mit Pfad {0} nicht installieren
+managerServlet.noRole=FEHLER - Benutzer nicht in Rolle {0}
+managerServlet.noSelf=FEHLER - Manager-Kommandos können nicht auf die Manager-Anwendung selbst angewendet werden
+managerServlet.noWrapper=Container hat setWrapper() für dieses Servlet nicht aufgerufen
+managerServlet.reloaded=OK - Anwendung mit Kontext Pfad {0} neu geladen
+managerServlet.undeployd=OK - Anwendung mit Kontext Pfad {0} entfernt
+managerServlet.resourcesAll=OK - Auflistung globaler Ressourcen (alle Typen)
+managerServlet.resourcesType=OK - Auflistung globaler Ressourcen von Typ {0}
+managerServlet.rolesList=OK - Auflistung der Sicherheits-Rollen
+managerServlet.saveFail=FEHLER - Speichern der Konfiguration fehlgeschlagen: {0}
+managerServlet.sessiondefaultmax=Voreingestellter Sitzungsablauf nach maximal {0} Minuten Inaktivität
+managerServlet.sessiontimeout={0} Minuten: {1} Sitzungen
+managerServlet.sessions=OK - Sitzungs-Informationen für Anwendung mit Kontext Pfad {0}
+managerServlet.started=OK - Anwendung mit Kontext Pfad {0} gestartet
+managerServlet.startFailed=FEHLER - Anwendung mit Kontext Pfad {0} konnte nicht gestartet werden
+managerServlet.stopped=OK - Anwendung mit Kontext Pfad {0} gestoppt
+managerServlet.undeployed=OK - Anwendung mit Kontext Pfad {0} entfernt
+managerServlet.unknownCommand=FEHLER - Unbekanntes Kommando {0}
+managerServlet.userDatabaseError=FEHLER - Kann Referenz auf Benutzerdatendank nicht auflösen
+managerServlet.userDatabaseMissing=FEHLER - Keine Benutzerdatenbank vorhanden
+
+statusServlet.title=Server Status
+statusServlet.complete=Ausführlicher Server Status

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/manager/WEB-INF/classes/org/apache/catalina/manager/LocalStrings_es.properties
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/manager/WEB-INF/classes/org/apache/catalina/manager/LocalStrings_es.properties	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/manager/WEB-INF/classes/org/apache/catalina/manager/LocalStrings_es.properties	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,80 @@
+htmlManagerServlet.appsAvailable=Ejecutándose
+htmlManagerServlet.appsName=Nombre a Mostrar
+htmlManagerServlet.appsPath=Trayectoria
+htmlManagerServlet.appsReload=Recargar
+htmlManagerServlet.appsUndeploy=Replegar
+htmlManagerServlet.appsSessions=Sesiones
+htmlManagerServlet.appsStart=Arrancar
+htmlManagerServlet.appsStop=Parar
+htmlManagerServlet.appsTasks=Comandos
+htmlManagerServlet.appsTitle=Aplicaciones
+htmlManagerServlet.helpHtmlManager=Ayuda HTML de Gestor
+htmlManagerServlet.helpHtmlManagerFile=html-manager-howto.html
+htmlManagerServlet.helpManager=Ayuda de Gestor
+htmlManagerServlet.helpManagerFile=manager-howto.html
+htmlManagerServlet.deployButton=Desplegar
+htmlManagerServlet.deployConfig=URL de archivo de Configuración XML:
+htmlManagerServlet.deployPath=Trayectoria de Contexto (opcional):
+htmlManagerServlet.deployServer=Desplegar directorio o archivo WAR localizado en servidor
+htmlManagerServlet.deployTitle=Desplegar
+htmlManagerServlet.deployUpload=Archivo WAR a desplegar
+htmlManagerServlet.deployUploadFail=FALLO - Falló Carga de Despliegue, Excepción: {0}
+htmlManagerServlet.deployUploadFile=Seleccione archivo WAR a cargar
+htmlManagerServlet.deployUploadNotWar=FALLO - El archivo cargado \"{0}\" debe de ser un .war
+htmlManagerServlet.deployUploadNoFile=FALLO - Falló la carga de archivo, no hay archivo
+htmlManagerServlet.deployUploadWarExists=FALLO - El archivo war \"{0}\" ya existe en el servidor
+htmlManagerServlet.deployWar=URL de WAR o Directorio:
+htmlManagerServlet.list=Listar Aplicaciones
+htmlManagerServlet.manager=Gestor
+htmlManagerServlet.messageLabel=Mensaje:
+htmlManagerServlet.serverJVMVendor=Vendedor JVM
+htmlManagerServlet.serverJVMVersion=Versión JVM
+htmlManagerServlet.serverOSArch=Arquitectura de SO
+htmlManagerServlet.serverOSName=Nombre de SO
+htmlManagerServlet.serverOSVersion=Versión de SO
+htmlManagerServlet.serverTitle=Información de Servidor
+htmlManagerServlet.serverVersion=Versión de Tomcat
+htmlManagerServlet.title=Gestor de Aplicaciones Web de Tomcat
+managerServlet.alreadyContext=FALLO - Ya existe la aplicación en la trayectoria {0}
+managerServlet.alreadyDocBase=FALLO - Directorio {0} ya está siendo usado
+managerServlet.cannotInvoke=No puedo invocar servlet de gestor a través de invocador
+managerServlet.configured=OK - Desplegada aplicación desde archivo de contexto {0}
+managerServlet.deployed=OK - Desplegada aplicación en trayectoria de contexto {0}
+managerServlet.exception=FALLO - Encontrada excepción {0}
+managerServlet.deployed=OK - Desplegada aplicación en trayectoria de contexto {0}
+managerServlet.invalidPath=FALLO - Se ha especificado una trayectoria inválida de contexto {0}
+managerServlet.invalidWar=FALLO - Se ha especificado una URL de aplicación inválida {0}
+managerServlet.listed=OK - Aplicaciones listadas para máquinda virutal {0}
+managerServlet.listitem={0}:{1}:{2}:{3}
+managerServlet.noAppBase=FALLO - No puedo identificar aplicación base para trayectoria de contexto {0}
+managerServlet.noCommand=FALLO - No se ha especificado comando
+managerServlet.noContext=FALLO - No existe contexto para trayectoria {0}
+managerServlet.noDirectory=FALLO - Documento base No-directorio para trayectoria {0}
+managerServlet.noDocBase=FALLO - No puedo replegar documento base para trayectoria {0}
+managerServlet.noGlobal=FALLO - No hay disponibles recursos globales JNDI 
+managerServlet.noReload=FALLO - Recarga no soportada en WAR desplegado en trayectoria {0}
+managerServlet.noRename=FALLO - No pudeo desplegar WAR cargado para trayectoria {0}
+managerServlet.noRole=FALLO - El usuario no desempeña el papel de {0}
+managerServlet.noSelf=FALLO - El gestor no puede recargarse, replegarse, pararse o replegarse a sí mismo
+managerServlet.noWrapper=El Contenedor no ha llamado a setWrapper() para este servlet
+managerServlet.reloaded=OK - Recargada aplicación en trayectoria de contexto {0}
+managerServlet.undeployd=OK - Replegada aplicación en trayectoria de contexto {0}
+managerServlet.resourcesAll=OK - Listados recursos globales de todos los tipos
+managerServlet.resourcesType=OK - Listados recursos globales de tipo {0}
+managerServlet.rolesList=OK - Listados papeles de seguridad
+managerServlet.saveFail=FAIL - Fallo al guardar la configuración: {0}
+managerServlet.saved=OK - Configuración de Servidor guardada
+managerServlet.savedContext=OK - Configuración de Contexto {0} guardada
+managerServlet.sessiondefaultmax=Intervalo máximo por defecto de sesión inactiva {0} minutos
+managerServlet.sessiontimeout={0} minutos: {1} sesiones
+managerServlet.sessions=OK - Información de sesión para aplicación en trayectoria de contexto {0}
+managerServlet.started=OK - Arrancada aplicación en trayectoria de contexto {0}
+managerServlet.startFailed=FALLO - No se pudo arrancar la aplicación en trayectoria de contexto {0}
+managerServlet.stopped=OK - Parada aplicación en trayectoria de contexto {0}
+managerServlet.undeployed=OK - Replegada aplicacación en trayectoria de contexto {0}
+managerServlet.unknownCommand=FALLO - Comando desconocido {0}
+managerServlet.userDatabaseError=FALLO - No puedo resolver referencia de base de datos de usuario
+managerServlet.userDatabaseMissing=FALLO - No se encuentra disponible base de datos de usuario
+
+statusServlet.title=Estado de Servidor
+statusServlet.complete=Estado Completo de Servidor

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/manager/WEB-INF/classes/org/apache/catalina/manager/LocalStrings_fr.properties
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/manager/WEB-INF/classes/org/apache/catalina/manager/LocalStrings_fr.properties	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/manager/WEB-INF/classes/org/apache/catalina/manager/LocalStrings_fr.properties	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,64 @@
+htmlManagerServlet.appsAvailable=Fonctionnant
+htmlManagerServlet.appsName=Nom d''affichage
+htmlManagerServlet.appsPath=Chemin
+htmlManagerServlet.appsReload=Recharger
+htmlManagerServlet.appsRemove=Retirer
+htmlManagerServlet.appsSessions=Sessions
+htmlManagerServlet.appsStart=Démarrer
+htmlManagerServlet.appsStop=Arréter
+htmlManagerServlet.appsTitle=Applications
+htmlManagerServlet.installButton=Installation
+htmlManagerServlet.installConfig=URL de configuration:
+htmlManagerServlet.installPath=Chemin:
+htmlManagerServlet.installTitle=Installation
+htmlManagerServlet.installWar=URL du WAR:
+htmlManagerServlet.messageLabel=Message:
+htmlManagerServlet.serverJVMVendor=Fournisseur de la JVM
+htmlManagerServlet.serverJVMVersion=Version de la JVM
+htmlManagerServlet.serverOSArch=Architecture d''OS
+htmlManagerServlet.serverOSName=Nom d''OS
+htmlManagerServlet.serverOSVersion=Version d''OS
+htmlManagerServlet.serverTitle=Serveur
+htmlManagerServlet.serverVersion=Version de serveur
+htmlManagerServlet.title=Gestionnaire d''applications WEB Tomcat
+managerServlet.alreadyContext=ECHEC - l''application existe déjà dans le chemin {0}
+managerServlet.alreadyDocBase=ECHEC - Le répertoire {0} est déjà utilisé
+managerServlet.cannotInvoke=Impossible d''utiliser le gestionnaire de servlet au travers du délégué (invoker)
+managerServlet.configured=OK - Application configurée depuis le fichier contexte {0}
+managerServlet.deployed=OK - Application déployée pour le chemin de contexte {0}
+managerServlet.exception=ECHEC - L''exception {0} a été rencontrée
+managerServlet.installed=OK - Application installée pour le chemin de contexte {0}
+managerServlet.invalidPath=ECHEC - Un chemin de contexte invalide {0} a été spécifié
+managerServlet.invalidWar=ECHEC - Une URL d''application invalide {0} a été spécifiée
+managerServlet.listed=OK - Applications listées pour l''hôte virtuel (virtual host) {0}
+managerServlet.listitem={0}:{1}:{2}:{3}
+managerServlet.noAppBase=ECHEC - Impossible d''identifier la base de l''application base pour le chemin de context {0}
+managerServlet.noCommand=ECHEC - Aucune commande n''a été spécifiée
+managerServlet.noContext=ECHEC - Aucune contexte n''existe pour le chemin {0}
+managerServlet.noDirectory=ECHEC - La base de document n''est pas un répertoire pour le chemin {0}
+managerServlet.noDocBase=ECHEC - Impossible de retirer la base de document pour le chemin {0}
+managerServlet.noGlobal=ECHEC - Aucune ressource JNDI globale n''est disponible
+managerServlet.noReload=ECHEC - Rechargement non supporté par le WAR déployé au chemin {0}
+managerServlet.noRename=ECHEC - Impossible de déployer un WAR téléchargé pour le chemin {0}
+managerServlet.noRole=ECHEC - L''utilisateur ne possède pas le rôle {0}
+managerServlet.noSelf=ECHEC - Le gestionnaire ne peut recharger, retirer, arrêter, ou se déployer lui-même
+managerServlet.noWrapper=Le conteneur n''a pas appelé "setWrapper()" pour cette servlet
+managerServlet.reloaded=OK - Application rechargée au chemin de contexte {0}
+managerServlet.removed=OK - Application retirée au chemin de contexte {0}
+managerServlet.resourcesAll=OK - Liste des ressources globales de tout type
+managerServlet.resourcesType=OK - Liste des ressources globales de type {0}
+managerServlet.rolesList=OK - Liste de rôles de securité
+managerServlet.saveFail=ECHEC - La sauvegarde de la configuration a échoué: {0}
+managerServlet.sessiondefaultmax=Interval par défaut de maximum de session inactive {0} minutes
+managerServlet.sessiontimeout={0} minutes:{1} sessions
+managerServlet.sessions=OK - Information de session pour l''application au chemin de contexte {0}
+managerServlet.started=OK - Application démarrée pour le chemin de contexte {0}
+managerServlet.startFailed=ECHEC - L''application pour le chemin de contexte {0} n''a pas puêtredémarrée
+managerServlet.stopped=OK - Application arrétée pour le chemin de contexte {0}
+managerServlet.undeployed=OK - Application non-déployée pour le chemin de contexte {0}
+managerServlet.unknownCommand=ECHEC - Commande inconnue {0}
+managerServlet.userDatabaseError=ECHEC - Impossible de résoudre la base de données utilisateurs deréférence
+managerServlet.userDatabaseMissing=ECHEC - Aucune base de données utilisateurs n''est disponible
+
+statusServlet.title=Etat du serveur
+statusServlet.complete=Etat complet du serveur

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/manager/WEB-INF/classes/org/apache/catalina/manager/LocalStrings_ja.properties
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/manager/WEB-INF/classes/org/apache/catalina/manager/LocalStrings_ja.properties	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/manager/WEB-INF/classes/org/apache/catalina/manager/LocalStrings_ja.properties	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,79 @@
+htmlManagerServlet.appsAvailable=\u5b9f\u884c\u4e2d
+htmlManagerServlet.appsName=\u8868\u793a\u540d
+htmlManagerServlet.appsPath=\u30d1\u30b9
+htmlManagerServlet.appsReload=\u518d\u30ed\u30fc\u30c9
+htmlManagerServlet.appsUndeploy=\u914d\u5099\u89e3\u9664
+htmlManagerServlet.appsSessions=\u30bb\u30c3\u30b7\u30e7\u30f3
+htmlManagerServlet.appsStart=\u8d77\u52d5
+htmlManagerServlet.appsStop=\u505c\u6b62
+htmlManagerServlet.appsTasks=\u30b3\u30de\u30f3\u30c9
+htmlManagerServlet.appsTitle=\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3
+htmlManagerServlet.helpHtmlManager=HTML\u30de\u30cd\u30fc\u30b8\u30e3\u30d8\u30eb\u30d7
+htmlManagerServlet.helpHtmlManagerFile=html-manager-howto.html
+htmlManagerServlet.helpManager=\u30de\u30cd\u30fc\u30b8\u30e3\u30d8\u30eb\u30d7
+htmlManagerServlet.helpManagerFile=manager-howto.html
+htmlManagerServlet.deployButton=\u914d\u5099
+htmlManagerServlet.deployConfig=XML\u8a2d\u5b9a\u30d5\u30a1\u30a4\u30eb\u306eURL:
+htmlManagerServlet.deployPath=\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u30d1\u30b9 (\u7701\u7565\u53ef):
+htmlManagerServlet.deployServer=\u30b5\u30fc\u30d0\u4e0a\u306eWAR\u30d5\u30a1\u30a4\u30eb\u53c8\u306f\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u306e\u914d\u5099
+htmlManagerServlet.deployTitle=\u914d\u5099
+htmlManagerServlet.deployUpload=WAR\u30d5\u30a1\u30a4\u30eb\u306e\u914d\u5099
+htmlManagerServlet.deployUploadFail=FAIL - \u914d\u5099\u306e\u30a2\u30c3\u30d7\u30ed\u30fc\u30c9\u304c\u5931\u6557\u3057\u307e\u3057\u305f\u3001\u4f8b\u5916: {0}
+htmlManagerServlet.deployUploadFile=\u30a2\u30c3\u30d7\u30ed\u30fc\u30c9\u3059\u308bWAR\u30d5\u30a1\u30a4\u30eb\u306e\u9078\u629e
+htmlManagerServlet.deployUploadNotWar=FAIL - \u30a2\u30c3\u30d7\u30ed\u30fc\u30c9\u3059\u308b\u30d5\u30a1\u30a4\u30eb \"{0}\" \u306fWAR\u30d5\u30a1\u30a4\u30eb\u3067\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093
+htmlManagerServlet.deployUploadNoFile=FAIL - \u30d5\u30a1\u30a4\u30eb\u306e\u30a2\u30c3\u30d7\u30ed\u30fc\u30c9\u304c\u5931\u6557\u3057\u307e\u3057\u305f\u3001\u30d5\u30a1\u30a4\u30eb\u304c\u5b58\u5728\u3057\u307e\u305b\u3093
+htmlManagerServlet.deployUploadWarExists=FAIL - WAR\u30d5\u30a1\u30a4\u30eb \"{0}\" \u306f\u65e2\u306b\u30b5\u30fc\u30d0\u4e0a\u306b\u5b58\u5728\u3057\u307e\u3059
+htmlManagerServlet.deployWar=WAR\u30d5\u30a1\u30a4\u30eb\u53c8\u306f\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u306eURL:
+htmlManagerServlet.list=\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u306e\u4e00\u89a7
+htmlManagerServlet.manager=\u30de\u30cd\u30fc\u30b8\u30e3
+htmlManagerServlet.messageLabel=\u30e1\u30c3\u30bb\u30fc\u30b8
+htmlManagerServlet.serverJVMVendor=JVM\u30d9\u30f3\u30c0
+htmlManagerServlet.serverJVMVersion=JVM\u30d0\u30fc\u30b8\u30e7\u30f3
+htmlManagerServlet.serverOSArch=OS\u30a2\u30fc\u30ad\u30c6\u30af\u30c1\u30e3
+htmlManagerServlet.serverOSName=OS\u540d
+htmlManagerServlet.serverOSVersion=OS\u30d0\u30fc\u30b8\u30e7\u30f3
+htmlManagerServlet.serverTitle=\u30b5\u30fc\u30d0\u60c5\u5831
+htmlManagerServlet.serverVersion=Tomcat\u30d0\u30fc\u30b8\u30e7\u30f3
+htmlManagerServlet.title=Tomcat Web\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u30de\u30cd\u30fc\u30b8\u30e3
+managerServlet.alreadyContext=FAIL - \u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u306f\u3001\u65e2\u306b\u30d1\u30b9 {0} \u306b\u5b58\u5728\u3057\u307e\u3059
+managerServlet.alreadyDocBase=FAIL - \u30c7\u30a3\u30ec\u30af\u30c8\u30ea {0} \u306f\u65e2\u306b\u4f7f\u7528\u3055\u308c\u3066\u3044\u307e\u3059
+managerServlet.cannotInvoke=\u30a4\u30f3\u30dc\u30fc\u30ab\u3067\u30de\u30cd\u30fc\u30b8\u30e3\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8\u3092\u8d77\u52d5\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f
+managerServlet.configured=OK - \u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u30d5\u30a1\u30a4\u30eb {0} \u304b\u3089\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u3092\u30a4\u30f3\u30b9\u30c8\u30fc\u30eb\u3057\u307e\u3057\u305f
+managerServlet.deployed=OK - \u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u30d1\u30b9 {0} \u3067\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u3092\u914d\u5099\u3057\u307e\u3057\u305f
+managerServlet.exception=FAIL - \u4f8b\u5916 {0} \u304c\u767a\u751f\u3057\u307e\u3057\u305f
+managerServlet.deployed=OK - \u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u30d1\u30b9 {0} \u306b\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u3092\u30a4\u30f3\u30b9\u30c8\u30fc\u30eb\u3057\u307e\u3057\u305f
+managerServlet.invalidPath=FAIL - \u7121\u52b9\u306a\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u30d1\u30b9 {0} \u304c\u6307\u5b9a\u3055\u308c\u307e\u3057\u305f
+managerServlet.invalidWar=FAIL - \u7121\u52b9\u306a\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u306eURL {0} \u304c\u6307\u5b9a\u3055\u308c\u307e\u3057\u305f
+managerServlet.listed=OK - \u30d0\u30fc\u30c1\u30e3\u30eb\u30db\u30b9\u30c8 {0} \u306e\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u4e00\u89a7\u3067\u3059
+managerServlet.listitem={0}:{1}:{2}:{3}
+managerServlet.noAppBase=FAIL - \u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u30d1\u30b9 {0} \u306b\u5bfe\u3057\u3066\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u30d9\u30fc\u30b9\u3092\u78ba\u8a8d\u3067\u304d\u307e\u305b\u3093
+managerServlet.noCommand=FAIL - \u30b3\u30de\u30f3\u30c9\u304c\u6307\u5b9a\u3055\u308c\u3066\u3044\u307e\u305b\u3093
+managerServlet.noContext=FAIL - \u30d1\u30b9 {0} \u306e\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u304c\u5b58\u5728\u3057\u307e\u305b\u3093
+managerServlet.noDirectory=FAIL - \u30d1\u30b9 {0} \u306b\u5bfe\u3059\u308b\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u30c9\u30ad\u30e5\u30e1\u30f3\u30c8\u30d9\u30fc\u30b9\u304c\u3042\u308a\u307e\u305b\u3093
+managerServlet.noDocBase=FAIL - \u30d1\u30b9 {0} \u306b\u5bfe\u3059\u308b\u30c9\u30ad\u30e5\u30e1\u30f3\u30c8\u30d9\u30fc\u30b9\u3092\u524a\u9664\u3067\u304d\u307e\u305b\u3093
+managerServlet.noGlobal=FAIL - \u30b0\u30ed\u30fc\u30d0\u30eb\u306aJNDI\u30ea\u30bd\u30fc\u30b9\u304c\u5229\u7528\u3067\u304d\u307e\u305b\u3093
+managerServlet.noReload=FAIL - \u30d1\u30b9 {0} \u306b\u914d\u5099\u3055\u308c\u305fWAR\u30d5\u30a1\u30a4\u30eb\u3067\u306f\u518d\u30ed\u30fc\u30c9\u304c\u30b5\u30dd\u30fc\u30c8\u3055\u308c\u3066\u3044\u307e\u305b\u3093
+managerServlet.noRename=FAIL - \u30a2\u30c3\u30d7\u30ed\u30fc\u30c9\u3055\u308c\u305fWAR\u30d5\u30a1\u30a4\u30eb\u3092\u30d1\u30b9 {0} \u306b\u914d\u5099\u3067\u304d\u307e\u305b\u3093
+managerServlet.noRole=FAIL - \u30e6\u30fc\u30b6\u306f\u30ed\u30fc\u30eb {0} \u3092\u6301\u3063\u3066\u3044\u307e\u305b\u3093
+managerServlet.noSelf=FAIL - \u30de\u30cd\u30fc\u30b8\u30e3\u81ea\u8eab\u3092\u518d\u30ed\u30fc\u30c9\u3001\u524a\u9664\u3001\u505c\u6b62\u3001\u53c8\u306f\u914d\u5099\u89e3\u9664\u3067\u304d\u307e\u305b\u3093
+managerServlet.noWrapper=\u30b3\u30f3\u30c6\u30ca\u306f\u3053\u306e\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8\u306b\u5bfe\u3057\u3066\u547c\u3073\u51fa\u3055\u308c\u305fsetWrapper()\u3092\u6301\u3063\u3066\u3044\u307e\u305b\u3093
+managerServlet.reloaded=OK - \u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u30d1\u30b9 {0} \u306e\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u3092\u518d\u30ed\u30fc\u30c9\u3057\u307e\u3057\u305f
+managerServlet.undeployd=OK - \u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u30d1\u30b9 {0} \u304b\u3089\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u3092\u914d\u5099\u89e3\u9664\u3057\u307e\u3057\u305f
+managerServlet.resourcesAll=OK - \u3059\u3079\u3066\u306e\u30bf\u30a4\u30d7\u306e\u30b0\u30ed\u30fc\u30d0\u30eb\u30ea\u30bd\u30fc\u30b9\u3092\u5217\u6319\u3057\u307e\u3057\u305f
+managerServlet.resourcesType=OK - \u30bf\u30a4\u30d7 {0} \u306e\u30b0\u30ed\u30fc\u30d0\u30eb\u30ea\u30bd\u30fc\u30b9\u3092\u5217\u6319\u3057\u307e\u3057\u305f
+managerServlet.rolesList=OK - \u30bb\u30ad\u30e5\u30ea\u30c6\u30a3\u30ed\u30fc\u30eb\u3092\u5217\u6319\u3057\u307e\u3057\u305f
+managerServlet.saveFail=FAIL - \u8a2d\u5b9a\u306e\u4fdd\u5b58\u306b\u5931\u6557\u3057\u307e\u3057\u305f: {0}
+managerServlet.saved=OK - \u30b5\u30fc\u30d0\u306e\u8a2d\u5b9a\u3092\u4fdd\u5b58\u3057\u307e\u3057\u305f
+managerServlet.savedContext=OK - \u30b3\u30f3\u30c6\u30ad\u30b9\u30c8 {0} \u306e\u8a2d\u5b9a\u3092\u4fdd\u5b58\u3057\u307e\u3057\u305f
+managerServlet.sessiondefaultmax=\u30c7\u30d5\u30a9\u30eb\u30c8\u306e\u6700\u5927\u30bb\u30c3\u30b7\u30e7\u30f3\u505c\u6b62\u9593\u9694\u306f{0}\u5206\u3067\u3059
+managerServlet.sessiontimeout={0}\u5206: {1}\u30bb\u30c3\u30b7\u30e7\u30f3
+managerServlet.sessions=OK - \u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u30d1\u30b9 {0} \u306e\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u306e\u30bb\u30c3\u30b7\u30e7\u30f3\u60c5\u5831\u3067\u3059
+managerServlet.started=OK - \u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u30d1\u30b9 {0} \u3067\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u3092\u8d77\u52d5\u3057\u307e\u3057\u305f
+managerServlet.startFailed=FAIL - \u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u30d1\u30b9 {0} \u306e\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u304c\u8d77\u52d5\u3067\u304d\u307e\u305b\u3093
+managerServlet.stopped=OK - \u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u30d1\u30b9 {0} \u3067\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u3092\u505c\u6b62\u3057\u307e\u3057\u305f
+managerServlet.undeployed=OK - \u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u30d1\u30b9 {0} \u306e\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u3092\u914d\u5099\u89e3\u9664\u3057\u307e\u3057\u305f
+managerServlet.unknownCommand=FAIL - \u672a\u77e5\u306e\u30b3\u30de\u30f3\u30c9 {0} \u3067\u3059
+managerServlet.userDatabaseError=FAIL - \u30e6\u30fc\u30b6\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u53c2\u7167\u3092\u89e3\u6c7a\u3067\u304d\u307e\u305b\u3093
+managerServlet.userDatabaseMissing=FAIL - \u30e6\u30fc\u30b6\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u304c\u5229\u7528\u3067\u304d\u307e\u305b\u3093
+statusServlet.title=\u30b5\u30fc\u30d0\u306e\u72b6\u614b
+statusServlet.complete=\u30b5\u30fc\u30d0\u306e\u5168\u72b6\u614b

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/manager/WEB-INF/classes/org/apache/catalina/manager/ManagerServlet.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/manager/WEB-INF/classes/org/apache/catalina/manager/ManagerServlet.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/manager/WEB-INF/classes/org/apache/catalina/manager/ManagerServlet.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,1581 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.manager;
+
+
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.Iterator;
+
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+import javax.naming.Binding;
+import javax.naming.InitialContext;
+import javax.naming.NamingEnumeration;
+import javax.naming.NamingException;
+import javax.servlet.ServletException;
+import javax.servlet.ServletInputStream;
+import javax.servlet.UnavailableException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import org.apache.catalina.Container;
+import org.apache.catalina.ContainerServlet;
+import org.apache.catalina.Context;
+import org.apache.catalina.Engine;
+import org.apache.catalina.Globals;
+import org.apache.catalina.Host;
+import org.apache.catalina.Lifecycle;
+import org.apache.catalina.Role;
+import org.apache.catalina.Server;
+import org.apache.catalina.ServerFactory;
+import org.apache.catalina.Session;
+import org.apache.catalina.UserDatabase;
+import org.apache.catalina.Wrapper;
+import org.apache.catalina.core.StandardServer;
+import org.apache.catalina.util.RequestUtil;
+import org.apache.catalina.util.ServerInfo;
+import org.apache.catalina.util.StringManager;
+import org.apache.commons.modeler.Registry;
+
+
+/**
+ * Servlet that enables remote management of the web applications installed
+ * within the same virtual host as this web application is.  Normally, this
+ * functionality will be protected by a security constraint in the web
+ * application deployment descriptor.  However, this requirement can be
+ * relaxed during testing.
+ * <p>
+ * This servlet examines the value returned by <code>getPathInfo()</code>
+ * and related query parameters to determine what action is being requested.
+ * The following actions and parameters (starting after the servlet path)
+ * are supported:
+ * <ul>
+ * <li><b>/deploy?config={config-url}</b> - Install and start a new
+ *     web application, based on the contents of the context configuration
+ *     file found at the specified URL.  The <code>docBase</code> attribute
+ *     of the context configuration file is used to locate the actual
+ *     WAR or directory containing the application.</li>
+ * <li><b>/deploy?config={config-url}&war={war-url}/</b> - Install and start
+ *     a new web application, based on the contents of the context
+ *     configuration file found at <code>{config-url}</code>, overriding the
+ *     <code>docBase</code> attribute with the contents of the web
+ *     application archive found at <code>{war-url}</code>.</li>
+ * <li><b>/deploy?path=/xxx&war={war-url}</b> - Install and start a new
+ *     web application attached to context path <code>/xxx</code>, based
+ *     on the contents of the web application archive found at the
+ *     specified URL.</li>
+ * <li><b>/list</b> - List the context paths of all currently installed web
+ *     applications for this virtual host.  Each context will be listed with
+ *     the following format <code>path:status:sessions</code>.
+ *     Where path is the context path.  Status is either running or stopped.
+ *     Sessions is the number of active Sessions.</li>
+ * <li><b>/reload?path=/xxx</b> - Reload the Java classes and resources for
+ *     the application at the specified path.</li>
+ * <li><b>/resources?type=xxxx</b> - Enumerate the available global JNDI
+ *     resources, optionally limited to those of the specified type
+ *     (fully qualified Java class name), if available.</li>
+ * <li><b>/roles</b> - Enumerate the available security role names and
+ *     descriptions from the user database connected to the <code>users</code>
+ *     resource reference.
+ * <li><b>/serverinfo</b> - Display system OS and JVM properties.
+ * <li><b>/sessions?path=/xxx</b> - List session information about the web
+ *     application attached to context path <code>/xxx</code> for this
+ *     virtual host.</li>
+ * <li><b>/start?path=/xxx</b> - Start the web application attached to
+ *     context path <code>/xxx</code> for this virtual host.</li>
+ * <li><b>/stop?path=/xxx</b> - Stop the web application attached to
+ *     context path <code>/xxx</code> for this virtual host.</li>
+ * <li><b>/undeploy?path=/xxx</b> - Shutdown and remove the web application
+ *     attached to context path <code>/xxx</code> for this virtual host,
+ *     and remove the underlying WAR file or document base directory.
+ *     (<em>NOTE</em> - This is only allowed if the WAR file or document
+ *     base is stored in the <code>appBase</code> directory of this host,
+ *     typically as a result of being placed there via the <code>/deploy</code>
+ *     command.</li>
+ * </ul>
+ * <p>Use <code>path=/</code> for the ROOT context.</p>
+ * <p>The syntax of the URL for a web application archive must conform to one
+ * of the following patterns to be successfully deployed:</p>
+ * <ul>
+ * <li><b>file:/absolute/path/to/a/directory</b> - You can specify the absolute
+ *     path of a directory that contains the unpacked version of a web
+ *     application.  This directory will be attached to the context path you
+ *     specify without any changes.</li>
+ * <li><b>jar:file:/absolute/path/to/a/warfile.war!/</b> - You can specify a
+ *     URL to a local web application archive file.  The syntax must conform to
+ *     the rules specified by the <code>JarURLConnection</code> class for a
+ *     reference to an entire JAR file.</li>
+ * <li><b>jar:http://hostname:port/path/to/a/warfile.war!/</b> - You can specify
+ *     a URL to a remote (HTTP-accessible) web application archive file.  The
+ *     syntax must conform to the rules specified by the
+ *     <code>JarURLConnection</code> class for a reference to an entire
+ *     JAR file.</li>
+ * </ul>
+ * <p>
+ * <b>NOTE</b> - Attempting to reload or remove the application containing
+ * this servlet itself will not succeed.  Therefore, this servlet should
+ * generally be deployed as a separate web application within the virtual host
+ * to be managed.
+ * <p>
+ * <b>NOTE</b> - For security reasons, this application will not operate
+ * when accessed via the invoker servlet.  You must explicitly map this servlet
+ * with a servlet mapping, and you will always want to protect it with
+ * appropriate security constraints as well.
+ * <p>
+ * The following servlet initialization parameters are recognized:
+ * <ul>
+ * <li><b>debug</b> - The debugging detail level that controls the amount
+ *     of information that is logged by this servlet.  Default is zero.
+ * </ul>
+ *
+ * @author Craig R. McClanahan
+ * @author Remy Maucherat
+ * @version $Revision: 393613 $ $Date: 2006-04-12 16:08:01 -0500 (Wed, 12 Apr 2006) $
+ */
+
+public class ManagerServlet
+    extends HttpServlet implements ContainerServlet {
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * Path where context descriptors should be deployed.
+     */
+    protected File configBase = null;
+
+
+    /**
+     * The Context container associated with our web application.
+     */
+    protected Context context = null;
+
+
+    /**
+     * The debugging detail level for this servlet.
+     */
+    protected int debug = 1;
+
+
+    /**
+     * File object representing the directory into which the deploy() command
+     * will store the WAR and context configuration files that have been
+     * uploaded.
+     */
+    protected File deployed = null;
+
+
+    /**
+     * Path used to store revisions of webapps.
+     */
+    protected File versioned = null;
+
+
+    /**
+     * Path used to store context descriptors.
+     */
+    protected File contextDescriptors = null;
+
+
+    /**
+     * The associated host.
+     */
+    protected Host host = null;
+
+    
+    /**
+     * The host appBase.
+     */
+    protected File appBase = null;
+    
+    
+    /**
+     * MBean server.
+     */
+    protected MBeanServer mBeanServer = null;
+
+
+    /**
+     * The associated deployer ObjectName.
+     */
+    protected ObjectName oname = null;
+    
+
+    /**
+     * The global JNDI <code>NamingContext</code> for this server,
+     * if available.
+     */
+    protected javax.naming.Context global = null;
+
+
+    /**
+     * The string manager for this package.
+     */
+    protected static StringManager sm =
+        StringManager.getManager(Constants.Package);
+
+
+    /**
+     * The Wrapper container associated with this servlet.
+     */
+    protected Wrapper wrapper = null;
+
+
+    // ----------------------------------------------- ContainerServlet Methods
+
+
+    /**
+     * Return the Wrapper with which we are associated.
+     */
+    public Wrapper getWrapper() {
+
+        return (this.wrapper);
+
+    }
+
+
+    /**
+     * Set the Wrapper with which we are associated.
+     *
+     * @param wrapper The new wrapper
+     */
+    public void setWrapper(Wrapper wrapper) {
+
+        this.wrapper = wrapper;
+        if (wrapper == null) {
+            context = null;
+            host = null;
+            oname = null;
+        } else {
+            context = (Context) wrapper.getParent();
+            host = (Host) context.getParent();
+            Engine engine = (Engine) host.getParent();
+            try {
+                oname = new ObjectName(engine.getName() 
+                        + ":type=Deployer,host=" + host.getName());
+            } catch (Exception e) {
+                // ?
+            }
+        }
+
+        // Retrieve the MBean server
+        mBeanServer = Registry.getRegistry(null, null).getMBeanServer();
+        
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Finalize this servlet.
+     */
+    public void destroy() {
+
+        ;       // No actions necessary
+
+    }
+
+
+    /**
+     * Process a GET request for the specified resource.
+     *
+     * @param request The servlet request we are processing
+     * @param response The servlet response we are creating
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception ServletException if a servlet-specified error occurs
+     */
+    public void doGet(HttpServletRequest request,
+                      HttpServletResponse response)
+        throws IOException, ServletException {
+
+        // Verify that we were not accessed using the invoker servlet
+        if (request.getAttribute(Globals.INVOKED_ATTR) != null)
+            throw new UnavailableException
+                (sm.getString("managerServlet.cannotInvoke"));
+
+        // Identify the request parameters that we need
+        String command = request.getPathInfo();
+        if (command == null)
+            command = request.getServletPath();
+        String config = request.getParameter("config");
+        String path = request.getParameter("path");
+        String type = request.getParameter("type");
+        String war = request.getParameter("war");
+        String tag = request.getParameter("tag");
+        boolean update = false;
+        if ((request.getParameter("update") != null) 
+            && (request.getParameter("update").equals("true"))) {
+            update = true;
+        }
+
+        // Prepare our output writer to generate the response message
+        response.setContentType("text/plain; charset=" + Constants.CHARSET);
+        PrintWriter writer = response.getWriter();
+
+        // Process the requested command (note - "/deploy" is not listed here)
+        if (command == null) {
+            writer.println(sm.getString("managerServlet.noCommand"));
+        } else if (command.equals("/deploy")) {
+            if (war != null || config != null) {
+                deploy(writer, config, path, war, update);
+            } else {
+                deploy(writer, path, tag);
+            }
+        } else if (command.equals("/install")) {
+            // Deprecated
+            deploy(writer, config, path, war, false);
+        } else if (command.equals("/list")) {
+            list(writer);
+        } else if (command.equals("/reload")) {
+            reload(writer, path);
+        } else if (command.equals("/remove")) {
+            // Deprecated
+            undeploy(writer, path);
+        } else if (command.equals("/resources")) {
+            resources(writer, type);
+        } else if (command.equals("/roles")) {
+            roles(writer);
+        } else if (command.equals("/save")) {
+            save(writer, path);
+        } else if (command.equals("/serverinfo")) {
+            serverinfo(writer);
+        } else if (command.equals("/sessions")) {
+            sessions(writer, path);
+        } else if (command.equals("/start")) {
+            start(writer, path);
+        } else if (command.equals("/stop")) {
+            stop(writer, path);
+        } else if (command.equals("/undeploy")) {
+            undeploy(writer, path);
+        } else {
+            writer.println(sm.getString("managerServlet.unknownCommand",
+                                        command));
+        }
+
+        // Finish up the response
+        writer.flush();
+        writer.close();
+
+    }
+
+
+    /**
+     * Process a PUT request for the specified resource.
+     *
+     * @param request The servlet request we are processing
+     * @param response The servlet response we are creating
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception ServletException if a servlet-specified error occurs
+     */
+    public void doPut(HttpServletRequest request,
+                      HttpServletResponse response)
+        throws IOException, ServletException {
+
+        // Verify that we were not accessed using the invoker servlet
+        if (request.getAttribute(Globals.INVOKED_ATTR) != null)
+            throw new UnavailableException
+                (sm.getString("managerServlet.cannotInvoke"));
+
+        // Identify the request parameters that we need
+        String command = request.getPathInfo();
+        if (command == null)
+            command = request.getServletPath();
+        String path = request.getParameter("path");
+        String tag = request.getParameter("tag");
+        boolean update = false;
+        if ((request.getParameter("update") != null) 
+            && (request.getParameter("update").equals("true"))) {
+            update = true;
+        }
+
+        // Prepare our output writer to generate the response message
+        response.setContentType("text/plain;charset="+Constants.CHARSET);
+        PrintWriter writer = response.getWriter();
+
+        // Process the requested command
+        if (command == null) {
+            writer.println(sm.getString("managerServlet.noCommand"));
+        } else if (command.equals("/deploy")) {
+            deploy(writer, path, tag, update, request);
+        } else {
+            writer.println(sm.getString("managerServlet.unknownCommand",
+                                        command));
+        }
+
+        // Finish up the response
+        writer.flush();
+        writer.close();
+
+    }
+
+
+    /**
+     * Initialize this servlet.
+     */
+    public void init() throws ServletException {
+
+        // Ensure that our ContainerServlet properties have been set
+        if ((wrapper == null) || (context == null))
+            throw new UnavailableException
+                (sm.getString("managerServlet.noWrapper"));
+
+        // Verify that we were not accessed using the invoker servlet
+        String servletName = getServletConfig().getServletName();
+        if (servletName == null)
+            servletName = "";
+        if (servletName.startsWith("org.apache.catalina.INVOKER."))
+            throw new UnavailableException
+                (sm.getString("managerServlet.cannotInvoke"));
+
+        // Set our properties from the initialization parameters
+        String value = null;
+        try {
+            value = getServletConfig().getInitParameter("debug");
+            debug = Integer.parseInt(value);
+        } catch (Throwable t) {
+            ;
+        }
+
+        // Acquire global JNDI resources if available
+        Server server = ServerFactory.getServer();
+        if ((server != null) && (server instanceof StandardServer)) {
+            global = ((StandardServer) server).getGlobalNamingContext();
+        }
+
+        // Calculate the directory into which we will be deploying applications
+        versioned = (File) getServletContext().getAttribute
+            ("javax.servlet.context.tempdir");
+
+        // Identify the appBase of the owning Host of this Context
+        // (if any)
+        String appBase = ((Host) context.getParent()).getAppBase();
+        deployed = new File(appBase);
+        if (!deployed.isAbsolute()) {
+            deployed = new File(System.getProperty("catalina.base"),
+                                appBase);
+        }
+        configBase = new File(System.getProperty("catalina.base"), "conf");
+        Container container = context;
+        Container host = null;
+        Container engine = null;
+        while (container != null) {
+            if (container instanceof Host)
+                host = container;
+            if (container instanceof Engine)
+                engine = container;
+            container = container.getParent();
+        }
+        if (engine != null) {
+            configBase = new File(configBase, engine.getName());
+        }
+        if (host != null) {
+            configBase = new File(configBase, host.getName());
+        }
+        // Note: The directory must exist for this to work.
+
+        // Log debugging messages as necessary
+        if (debug >= 1) {
+            log("init: Associated with Deployer '" +
+                oname + "'");
+            if (global != null) {
+                log("init: Global resources are available");
+            }
+        }
+
+    }
+
+
+
+    // -------------------------------------------------------- Private Methods
+
+
+    /**
+     * Store server configuration.
+     * 
+     * @param path Optional context path to save
+     */
+    protected synchronized void save(PrintWriter writer, String path) {
+
+        Server server = ServerFactory.getServer();
+
+        if (!(server instanceof StandardServer)) {
+            writer.println(sm.getString("managerServlet.saveFail", server));
+            return;
+        }
+
+        if ((path == null) || path.length() == 0 || !path.startsWith("/")) {
+            try {
+                ((StandardServer) server).storeConfig();
+                writer.println(sm.getString("managerServlet.saved"));
+            } catch (Exception e) {
+                log("managerServlet.storeConfig", e);
+                writer.println(sm.getString("managerServlet.exception",
+                                            e.toString()));
+                return;
+            }
+        } else {
+            String contextPath = path;
+            if (path.equals("/")) {
+                contextPath = "";
+            }
+            Context context = (Context) host.findChild(contextPath);
+            if (context == null) {
+                writer.println(sm.getString("managerServlet.noContext", path));
+                return;
+            }
+            try {
+                ((StandardServer) server).storeContext(context);
+                writer.println(sm.getString("managerServlet.savedContext", 
+                               path));
+            } catch (Exception e) {
+                log("managerServlet.save[" + path + "]", e);
+                writer.println(sm.getString("managerServlet.exception",
+                                            e.toString()));
+                return;
+            }
+        }
+
+    }
+
+
+    /**
+     * Deploy a web application archive (included in the current request)
+     * at the specified context path.
+     *
+     * @param writer Writer to render results to
+     * @param path Context path of the application to be installed
+     * @param tag Tag to be associated with the webapp
+     * @param request Servlet request we are processing
+     */
+    protected synchronized void deploy
+        (PrintWriter writer, String path,
+         String tag, boolean update, HttpServletRequest request) {
+
+        if (debug >= 1) {
+            log("deploy: Deploying web application at '" + path + "'");
+        }
+
+        // Validate the requested context path
+        if ((path == null) || path.length() == 0 || !path.startsWith("/")) {
+            writer.println(sm.getString("managerServlet.invalidPath", path));
+            return;
+        }
+        String displayPath = path;
+        if( path.equals("/") )
+            path = "";
+        String basename = getDocBase(path);
+
+        // Check if app already exists, or undeploy it if updating
+        Context context = (Context) host.findChild(path);
+        if (update) {
+            if (context != null) {
+                undeploy(writer, displayPath);
+            }
+            context = (Context) host.findChild(path);
+        }
+        if (context != null) {
+            writer.println
+                (sm.getString("managerServlet.alreadyContext",
+                              displayPath));
+            return;
+        }
+
+        // Calculate the base path
+        File deployedPath = deployed;
+        if (tag != null) {
+            deployedPath = new File(versioned, tag);
+            deployedPath.mkdirs();
+        }
+
+        // Upload the web application archive to a local WAR file
+        File localWar = new File(deployedPath, basename + ".war");
+        if (debug >= 2) {
+            log("Uploading WAR file to " + localWar);
+        }
+
+        // Copy WAR to appBase
+        try {
+            if (!isServiced(path)) {
+                addServiced(path);
+                try {
+                    // Upload WAR
+                    uploadWar(request, localWar);
+                    // Copy WAR and XML to the host app base if needed
+                    if (tag != null) {
+                        deployedPath = deployed;
+                        File localWarCopy = new File(deployedPath, basename + ".war");
+                        copy(localWar, localWarCopy);
+                        localWar = localWarCopy;
+                        copy(localWar, new File(getAppBase(), basename + ".war"));
+                    }
+                    // Perform new deployment
+                    check(path);
+                } finally {
+                    removeServiced(path);
+                }
+            }
+        } catch (Exception e) {
+            log("managerServlet.check[" + displayPath + "]", e);
+            writer.println(sm.getString("managerServlet.exception",
+                                        e.toString()));
+            return;
+        }
+        
+        context = (Context) host.findChild(path);
+        if (context != null && context.getConfigured()) {
+            writer.println(sm.getString("managerServlet.deployed", displayPath));
+        } else {
+            // Something failed
+            writer.println(sm.getString("managerServlet.deployFailed", displayPath));
+        }
+        
+    }
+
+
+    /**
+     * Install an application for the specified path from the specified
+     * web application archive.
+     *
+     * @param writer Writer to render results to
+     * @param tag Revision tag to deploy from
+     * @param path Context path of the application to be installed
+     */
+    protected void deploy(PrintWriter writer, String path, String tag) {
+
+        // Validate the requested context path
+        if ((path == null) || path.length() == 0 || !path.startsWith("/")) {
+            writer.println(sm.getString("managerServlet.invalidPath", path));
+            return;
+        }
+        String displayPath = path;
+        if( path.equals("/") )
+            path = "";
+
+        // Calculate the base path
+        File deployedPath = versioned;
+        if (tag != null) {
+            deployedPath = new File(deployedPath, tag);
+        }
+
+        // Find the local WAR file
+        File localWar = new File(deployedPath, getDocBase(path) + ".war");
+        // Find the local context deployment file (if any)
+        File localXml = new File(configBase, getConfigFile(path) + ".xml");
+
+        // Check if app already exists, or undeploy it if updating
+        Context context = (Context) host.findChild(path);
+        if (context != null) {
+            undeploy(writer, displayPath);
+        }
+
+        // Copy WAR to appBase
+        try {
+            if (!isServiced(path)) {
+                addServiced(path);
+                try {
+                    copy(localWar, new File(getAppBase(), getDocBase(path) + ".war"));
+                    // Perform new deployment
+                    check(path);
+                } finally {
+                    removeServiced(path);
+                }
+            }
+        } catch (Exception e) {
+            log("managerServlet.check[" + displayPath + "]", e);
+            writer.println(sm.getString("managerServlet.exception",
+                                        e.toString()));
+            return;
+        }
+        
+        context = (Context) host.findChild(path);
+        if (context != null && context.getConfigured()) {
+            writer.println(sm.getString("managerServlet.deployed", displayPath));
+        } else {
+            // Something failed
+            writer.println(sm.getString("managerServlet.deployFailed", displayPath));
+        }
+        
+    }
+
+
+    /**
+     * Install an application for the specified path from the specified
+     * web application archive.
+     *
+     * @param writer Writer to render results to
+     * @param config URL of the context configuration file to be installed
+     * @param path Context path of the application to be installed
+     * @param war URL of the web application archive to be installed
+     * @param update true to override any existing webapp on the path
+     */
+    protected void deploy(PrintWriter writer, String config,
+            String path, String war, boolean update) {
+        
+        if (config != null && config.length() == 0) {
+            config = null;
+        }
+        if (war != null && war.length() == 0) {
+            war = null;
+        }
+        
+        if (debug >= 1) {
+            if (config != null && config.length() > 0) {
+                if (war != null) {
+                    log("install: Installing context configuration at '" +
+                            config + "' from '" + war + "'");
+                } else {
+                    log("install: Installing context configuration at '" +
+                            config + "'");
+                }
+            } else {
+                if (path != null && path.length() > 0) {
+                    log("install: Installing web application at '" + path +
+                            "' from '" + war + "'");
+                } else {
+                    log("install: Installing web application from '" + war + "'");
+                }
+            }
+        }
+        
+        if (path == null || path.length() == 0 || !path.startsWith("/")) {
+            writer.println(sm.getString("managerServlet.invalidPath",
+                                        RequestUtil.filter(path)));
+            return;
+        }
+        String displayPath = path;
+        if("/".equals(path)) {
+            path = "";
+        }
+        
+        // Check if app already exists, or undeploy it if updating
+        Context context = (Context) host.findChild(path);
+        if (update) {
+            if (context != null) {
+                undeploy(writer, displayPath);
+            }
+            context = (Context) host.findChild(path);
+        }
+        if (context != null) {
+            writer.println
+            (sm.getString("managerServlet.alreadyContext",
+                    displayPath));
+            return;
+        }
+        
+        if (config != null && (config.startsWith("file:"))) {
+            config = config.substring("file:".length());
+        }
+        if (war != null && (war.startsWith("file:"))) {
+            war = war.substring("file:".length());
+        }
+        
+        try {
+            if (!isServiced(path)) {
+                addServiced(path);
+                try {
+                    if (config != null) {
+                        copy(new File(config), 
+                                new File(configBase, getConfigFile(path) + ".xml"));
+                    }
+                    if (war != null) {
+                        if (war.endsWith(".war")) {
+                            copy(new File(war), 
+                                    new File(getAppBase(), getDocBase(path) + ".war"));
+                        } else {
+                            copy(new File(war), 
+                                    new File(getAppBase(), getDocBase(path)));
+                        }
+                    }
+                    // Perform new deployment
+                    check(path);
+                } finally {
+                    removeServiced(path);
+                }
+            }
+            context = (Context) host.findChild(path);
+            if (context != null && context.getConfigured()) {
+                writer.println(sm.getString("managerServlet.deployed", displayPath));
+            } else {
+                // Something failed
+                writer.println(sm.getString("managerServlet.deployFailed", displayPath));
+            }
+        } catch (Throwable t) {
+            log("ManagerServlet.install[" + displayPath + "]", t);
+            writer.println(sm.getString("managerServlet.exception",
+                    t.toString()));
+        }
+        
+    }
+
+
+    /**
+     * Render a list of the currently active Contexts in our virtual host.
+     *
+     * @param writer Writer to render to
+     */
+    protected void list(PrintWriter writer) {
+
+        if (debug >= 1)
+            log("list: Listing contexts for virtual host '" +
+                host.getName() + "'");
+
+        writer.println(sm.getString("managerServlet.listed",
+                                    host.getName()));
+        Container[] contexts = host.findChildren();
+        for (int i = 0; i < contexts.length; i++) {
+            Context context = (Context) contexts[i];
+            String displayPath = context.getPath();
+            if( displayPath.equals("") )
+                displayPath = "/";
+            if (context != null ) {
+                if (context.getAvailable()) {
+                    writer.println(sm.getString("managerServlet.listitem",
+                                                displayPath,
+                                                "running",
+                                      "" + context.getManager().findSessions().length,
+                                                context.getDocBase()));
+                } else {
+                    writer.println(sm.getString("managerServlet.listitem",
+                                                displayPath,
+                                                "stopped",
+                                                "0",
+                                                context.getDocBase()));
+                }
+            }
+        }
+    }
+
+
+    /**
+     * Reload the web application at the specified context path.
+     *
+     * @param writer Writer to render to
+     * @param path Context path of the application to be restarted
+     */
+    protected void reload(PrintWriter writer, String path) {
+
+        if (debug >= 1)
+            log("restart: Reloading web application at '" + path + "'");
+
+        if ((path == null) || (!path.startsWith("/") && path.equals(""))) {
+            writer.println(sm.getString("managerServlet.invalidPath",
+                                        RequestUtil.filter(path)));
+            return;
+        }
+        String displayPath = path;
+        if( path.equals("/") )
+            path = "";
+
+        try {
+            Context context = (Context) host.findChild(path);
+            if (context == null) {
+                writer.println(sm.getString
+                               ("managerServlet.noContext",
+                                   RequestUtil.filter(displayPath)));
+                return;
+            }
+            // It isn't possible for the manager to reload itself
+            if (context.getPath().equals(this.context.getPath())) {
+                writer.println(sm.getString("managerServlet.noSelf"));
+                return;
+            }
+            context.reload();
+            writer.println
+                (sm.getString("managerServlet.reloaded", displayPath));
+        } catch (Throwable t) {
+            log("ManagerServlet.reload[" + displayPath + "]", t);
+            writer.println(sm.getString("managerServlet.exception",
+                                        t.toString()));
+        }
+
+    }
+
+
+    /**
+     * Render a list of available global JNDI resources.
+     *
+     * @param type Fully qualified class name of the resource type of interest,
+     *  or <code>null</code> to list resources of all types
+     */
+    protected void resources(PrintWriter writer, String type) {
+
+        if (debug >= 1) {
+            if (type != null) {
+                log("resources:  Listing resources of type " + type);
+            } else {
+                log("resources:  Listing resources of all types");
+            }
+        }
+
+        // Is the global JNDI resources context available?
+        if (global == null) {
+            writer.println(sm.getString("managerServlet.noGlobal"));
+            return;
+        }
+
+        // Enumerate the global JNDI resources of the requested type
+        if (type != null) {
+            writer.println(sm.getString("managerServlet.resourcesType",
+                                        type));
+        } else {
+            writer.println(sm.getString("managerServlet.resourcesAll"));
+        }
+
+        Class clazz = null;
+        try {
+            if (type != null) {
+                clazz = Class.forName(type);
+            }
+        } catch (Throwable t) {
+            log("ManagerServlet.resources[" + type + "]", t);
+            writer.println(sm.getString("managerServlet.exception",
+                                        t.toString()));
+            return;
+        }
+
+        printResources(writer, "", global, type, clazz);
+
+    }
+
+
+    /**
+     * List the resources of the given context.
+     */
+    protected void printResources(PrintWriter writer, String prefix,
+                                  javax.naming.Context namingContext,
+                                  String type, Class clazz) {
+
+        try {
+            NamingEnumeration items = namingContext.listBindings("");
+            while (items.hasMore()) {
+                Binding item = (Binding) items.next();
+                if (item.getObject() instanceof javax.naming.Context) {
+                    printResources
+                        (writer, prefix + item.getName() + "/",
+                         (javax.naming.Context) item.getObject(), type, clazz);
+                } else {
+                    if ((clazz != null) &&
+                        (!(clazz.isInstance(item.getObject())))) {
+                        continue;
+                    }
+                    writer.print(prefix + item.getName());
+                    writer.print(':');
+                    writer.print(item.getClassName());
+                    // Do we want a description if available?
+                    writer.println();
+                }
+            }
+        } catch (Throwable t) {
+            log("ManagerServlet.resources[" + type + "]", t);
+            writer.println(sm.getString("managerServlet.exception",
+                                        t.toString()));
+        }
+
+    }
+
+
+    /**
+     * Render a list of security role names (and corresponding descriptions)
+     * from the <code>org.apache.catalina.UserDatabase</code> resource that is
+     * connected to the <code>users</code> resource reference.  Typically, this
+     * will be the global user database, but can be adjusted if you have
+     * different user databases for different virtual hosts.
+     *
+     * @param writer Writer to render to
+     */
+    protected void roles(PrintWriter writer) {
+
+        if (debug >= 1) {
+            log("roles:  List security roles from user database");
+        }
+
+        // Look up the UserDatabase instance we should use
+        UserDatabase database = null;
+        try {
+            InitialContext ic = new InitialContext();
+            database = (UserDatabase) ic.lookup("java:comp/env/users");
+        } catch (NamingException e) {
+            writer.println(sm.getString("managerServlet.userDatabaseError"));
+            log("java:comp/env/users", e);
+            return;
+        }
+        if (database == null) {
+            writer.println(sm.getString("managerServlet.userDatabaseMissing"));
+            return;
+        }
+
+        // Enumerate the available roles
+        writer.println(sm.getString("managerServlet.rolesList"));
+        Iterator roles = database.getRoles();
+        if (roles != null) {
+            while (roles.hasNext()) {
+                Role role = (Role) roles.next();
+                writer.print(role.getRolename());
+                writer.print(':');
+                if (role.getDescription() != null) {
+                    writer.print(role.getDescription());
+                }
+                writer.println();
+            }
+        }
+
+
+    }
+
+
+    /**
+     * Writes System OS and JVM properties.
+     * @param writer Writer to render to
+     */
+    protected void serverinfo(PrintWriter writer) {
+        if (debug >= 1)
+            log("serverinfo");
+        try {
+            StringBuffer props = new StringBuffer();
+            props.append("OK - Server info");
+            props.append("\nTomcat Version: ");
+            props.append(ServerInfo.getServerInfo());
+            props.append("\nOS Name: ");
+            props.append(System.getProperty("os.name"));
+            props.append("\nOS Version: ");
+            props.append(System.getProperty("os.version"));
+            props.append("\nOS Architecture: ");
+            props.append(System.getProperty("os.arch"));
+            props.append("\nJVM Version: ");
+            props.append(System.getProperty("java.runtime.version"));
+            props.append("\nJVM Vendor: ");
+            props.append(System.getProperty("java.vm.vendor"));
+            writer.println(props.toString());
+        } catch (Throwable t) {
+            getServletContext().log("ManagerServlet.serverinfo",t);
+            writer.println(sm.getString("managerServlet.exception",
+                                        t.toString()));
+        }
+    }
+
+    /**
+     * Session information for the web application at the specified context path.
+     * Displays a profile of session MaxInactiveInterval timeouts listing number
+     * of sessions for each 10 minute timeout interval up to 10 hours.
+     *
+     * @param writer Writer to render to
+     * @param path Context path of the application to list session information for
+     */
+    protected void sessions(PrintWriter writer, String path) {
+
+        if (debug >= 1)
+            log("sessions: Session information for web application at '" + path + "'");
+
+        if ((path == null) || (!path.startsWith("/") && path.equals(""))) {
+            writer.println(sm.getString("managerServlet.invalidPath",
+                                        RequestUtil.filter(path)));
+            return;
+        }
+        String displayPath = path;
+        if( path.equals("/") )
+            path = "";
+        try {
+            Context context = (Context) host.findChild(path);
+            if (context == null) {
+                writer.println(sm.getString("managerServlet.noContext",
+                                            RequestUtil.filter(displayPath)));
+                return;
+            }
+            writer.println(sm.getString("managerServlet.sessions", displayPath));
+            writer.println(sm.getString("managerServlet.sessiondefaultmax",
+                                "" + context.getManager().getMaxInactiveInterval()/60));
+            Session [] sessions = context.getManager().findSessions();
+            int [] timeout = new int[60];
+            int notimeout = 0;
+            for (int i = 0; i < sessions.length; i++) {
+                int time = sessions[i].getMaxInactiveInterval()/(10*60);
+                if (time < 0)
+                    notimeout++;
+                else if (time >= timeout.length)
+                    timeout[timeout.length-1]++;
+                else
+                    timeout[time]++;
+            }
+            if (timeout[0] > 0)
+                writer.println(sm.getString("managerServlet.sessiontimeout",
+                                            "<10", "" + timeout[0]));
+            for (int i = 1; i < timeout.length-1; i++) {
+                if (timeout[i] > 0)
+                    writer.println(sm.getString("managerServlet.sessiontimeout",
+                                     "" + (i)*10 + " - <" + (i+1)*10,
+                                                "" + timeout[i]));
+            }
+            if (timeout[timeout.length-1] > 0)
+                writer.println(sm.getString("managerServlet.sessiontimeout",
+                                            ">=" + timeout.length*10,
+                                            "" + timeout[timeout.length-1]));
+            if (notimeout > 0)
+                writer.println(sm.getString("managerServlet.sessiontimeout",
+                                            "unlimited","" + notimeout));
+        } catch (Throwable t) {
+            log("ManagerServlet.sessions[" + displayPath + "]", t);
+            writer.println(sm.getString("managerServlet.exception",
+                                        t.toString()));
+        }
+
+    }
+
+
+    /**
+     * Start the web application at the specified context path.
+     *
+     * @param writer Writer to render to
+     * @param path Context path of the application to be started
+     */
+    protected void start(PrintWriter writer, String path) {
+
+        if (debug >= 1)
+            log("start: Starting web application at '" + path + "'");
+
+        if ((path == null) || (!path.startsWith("/") && path.equals(""))) {
+            writer.println(sm.getString("managerServlet.invalidPath",
+                                        RequestUtil.filter(path)));
+            return;
+        }
+        String displayPath = path;
+        if( path.equals("/") )
+            path = "";
+
+        try {
+            Context context = (Context) host.findChild(path);
+            if (context == null) {
+                writer.println(sm.getString("managerServlet.noContext", 
+                                            RequestUtil.filter(displayPath)));
+                return;
+            }
+            ((Lifecycle) context).start();
+            if (context.getAvailable())
+                writer.println
+                    (sm.getString("managerServlet.started", displayPath));
+            else
+                writer.println
+                    (sm.getString("managerServlet.startFailed", displayPath));
+        } catch (Throwable t) {
+            getServletContext().log
+                (sm.getString("managerServlet.startFailed", displayPath), t);
+            writer.println
+                (sm.getString("managerServlet.startFailed", displayPath));
+            writer.println(sm.getString("managerServlet.exception",
+                                        t.toString()));
+        }
+
+    }
+
+
+    /**
+     * Stop the web application at the specified context path.
+     *
+     * @param writer Writer to render to
+     * @param path Context path of the application to be stopped
+     */
+    protected void stop(PrintWriter writer, String path) {
+
+        if (debug >= 1)
+            log("stop: Stopping web application at '" + path + "'");
+
+        if ((path == null) || (!path.startsWith("/") && path.equals(""))) {
+            writer.println(sm.getString("managerServlet.invalidPath",
+                                        RequestUtil.filter(path)));
+            return;
+        }
+        String displayPath = path;
+        if( path.equals("/") )
+            path = "";
+
+        try {
+            Context context = (Context) host.findChild(path);
+            if (context == null) {
+                writer.println(sm.getString("managerServlet.noContext", 
+                                            RequestUtil.filter(displayPath)));
+                return;
+            }
+            // It isn't possible for the manager to stop itself
+            if (context.getPath().equals(this.context.getPath())) {
+                writer.println(sm.getString("managerServlet.noSelf"));
+                return;
+            }
+            ((Lifecycle) context).stop();
+            writer.println(sm.getString("managerServlet.stopped", displayPath));
+        } catch (Throwable t) {
+            log("ManagerServlet.stop[" + displayPath + "]", t);
+            writer.println(sm.getString("managerServlet.exception",
+                                        t.toString()));
+        }
+
+    }
+
+
+    /**
+     * Undeploy the web application at the specified context path.
+     *
+     * @param writer Writer to render to
+     * @param path Context path of the application to be removed
+     */
+    protected void undeploy(PrintWriter writer, String path) {
+
+        if (debug >= 1)
+            log("undeploy: Undeploying web application at '" + path + "'");
+
+        if ((path == null) || (!path.startsWith("/") && path.equals(""))) {
+            writer.println(sm.getString("managerServlet.invalidPath",
+                                        RequestUtil.filter(path)));
+            return;
+        }
+        String displayPath = path;
+        if( path.equals("/") )
+            path = "";
+
+        try {
+
+            // Validate the Context of the specified application
+            Context context = (Context) host.findChild(path);
+            if (context == null) {
+                writer.println(sm.getString("managerServlet.noContext",
+                                            RequestUtil.filter(displayPath)));
+                return;
+            }
+
+            // Identify the appBase of the owning Host of this Context (if any)
+            String appBase = null;
+            File appBaseDir = null;
+            if (context.getParent() instanceof Host) {
+                appBase = ((Host) context.getParent()).getAppBase();
+                appBaseDir = new File(appBase);
+                if (!appBaseDir.isAbsolute()) {
+                    appBaseDir = new File(System.getProperty("catalina.base"),
+                                          appBase);
+                }
+            }
+
+            if (!isServiced(path)) {
+                addServiced(path);
+                try {
+                    // Try to stop the context first to be nicer
+                    ((Lifecycle) context).stop();
+                } catch (Throwable t) {
+                    // Ignore
+                }
+                try {
+                    File war = new File(getAppBase(), getDocBase(path) + ".war");
+                    File dir = new File(getAppBase(), getDocBase(path));
+                    File xml = new File(configBase, getConfigFile(path) + ".xml");
+                    if (war.exists()) {
+                        war.delete();
+                    } else if (dir.exists()) {
+                        undeployDir(dir);
+                    } else {
+                        xml.delete();
+                    }
+                    // Perform new deployment
+                    check(path);
+                } finally {
+                    removeServiced(path);
+                }
+            }
+            writer.println(sm.getString("managerServlet.undeployed",
+                                        displayPath));
+        } catch (Throwable t) {
+            log("ManagerServlet.undeploy[" + displayPath + "]", t);
+            writer.println(sm.getString("managerServlet.exception",
+                                        t.toString()));
+        }
+
+    }
+
+
+    // -------------------------------------------------------- Support Methods
+
+
+    /**
+     * Given a context path, get the config file name.
+     */
+    protected String getConfigFile(String path) {
+        String basename = null;
+        if (path.equals("")) {
+            basename = "ROOT";
+        } else {
+            basename = path.substring(1).replace('/', '#');
+        }
+        return (basename);
+    }
+
+
+    /**
+     * Given a context path, get the config file name.
+     */
+    protected String getDocBase(String path) {
+        String basename = null;
+        if (path.equals("")) {
+            basename = "ROOT";
+        } else {
+            basename = path.substring(1);
+        }
+        return (basename);
+    }
+
+    
+    /**
+     * Return a File object representing the "application root" directory
+     * for our associated Host.
+     */
+    protected File getAppBase() {
+
+        if (appBase != null) {
+            return appBase;
+        }
+
+        File file = new File(host.getAppBase());
+        if (!file.isAbsolute())
+            file = new File(System.getProperty("catalina.base"),
+                            host.getAppBase());
+        try {
+            appBase = file.getCanonicalFile();
+        } catch (IOException e) {
+            appBase = file;
+        }
+        return (appBase);
+
+    }
+
+
+    /**
+     * Invoke the check method on the deployer.
+     */
+    protected void check(String name) 
+        throws Exception {
+        String[] params = { name };
+        String[] signature = { "java.lang.String" };
+        mBeanServer.invoke(oname, "check", params, signature);
+    }
+    
+
+    /**
+     * Invoke the check method on the deployer.
+     */
+    protected boolean isServiced(String name) 
+        throws Exception {
+        String[] params = { name };
+        String[] signature = { "java.lang.String" };
+        Boolean result = 
+            (Boolean) mBeanServer.invoke(oname, "isServiced", params, signature);
+        return result.booleanValue();
+    }
+    
+
+    /**
+     * Invoke the check method on the deployer.
+     */
+    protected void addServiced(String name) 
+        throws Exception {
+        String[] params = { name };
+        String[] signature = { "java.lang.String" };
+        mBeanServer.invoke(oname, "addServiced", params, signature);
+    }
+    
+
+    /**
+     * Invoke the check method on the deployer.
+     */
+    protected void removeServiced(String name) 
+        throws Exception {
+        String[] params = { name };
+        String[] signature = { "java.lang.String" };
+        mBeanServer.invoke(oname, "removeServiced", params, signature);
+    }
+    
+
+    /**
+     * Delete the specified directory, including all of its contents and
+     * subdirectories recursively.
+     *
+     * @param dir File object representing the directory to be deleted
+     */
+    protected void undeployDir(File dir) {
+
+        String files[] = dir.list();
+        if (files == null) {
+            files = new String[0];
+        }
+        for (int i = 0; i < files.length; i++) {
+            File file = new File(dir, files[i]);
+            if (file.isDirectory()) {
+                undeployDir(file);
+            } else {
+                file.delete();
+            }
+        }
+        dir.delete();
+
+    }
+
+
+    /**
+     * Upload the WAR file included in this request, and store it at the
+     * specified file location.
+     *
+     * @param request The servlet request we are processing
+     * @param war The file into which we should store the uploaded WAR
+     *
+     * @exception IOException if an I/O error occurs during processing
+     */
+    protected void uploadWar(HttpServletRequest request, File war)
+        throws IOException {
+
+        war.delete();
+        ServletInputStream istream = null;
+        BufferedOutputStream ostream = null;
+        try {
+            istream = request.getInputStream();
+            ostream =
+                new BufferedOutputStream(new FileOutputStream(war), 1024);
+            byte buffer[] = new byte[1024];
+            while (true) {
+                int n = istream.read(buffer);
+                if (n < 0) {
+                    break;
+                }
+                ostream.write(buffer, 0, n);
+            }
+            ostream.flush();
+            ostream.close();
+            ostream = null;
+            istream.close();
+            istream = null;
+        } catch (IOException e) {
+            war.delete();
+            throw e;
+        } finally {
+            if (ostream != null) {
+                try {
+                    ostream.close();
+                } catch (Throwable t) {
+                    ;
+                }
+                ostream = null;
+            }
+            if (istream != null) {
+                try {
+                    istream.close();
+                } catch (Throwable t) {
+                    ;
+                }
+                istream = null;
+            }
+        }
+
+    }
+
+
+    /**
+     * Copy the specified file or directory to the destination.
+     *
+     * @param src File object representing the source
+     * @param dest File object representing the destination
+     */
+    public static boolean copy(File src, File dest) {
+        boolean result = false;
+        try {
+            if( src != null &&
+                    !src.getCanonicalPath().equals(dest.getCanonicalPath()) ) {
+                result = copyInternal(src, dest, new byte[4096]);
+            }
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+        return result;
+    }
+
+    
+    /**
+     * Copy the specified file or directory to the destination.
+     *
+     * @param src File object representing the source
+     * @param dest File object representing the destination
+     */
+    public static boolean copyInternal(File src, File dest, byte[] buf) {
+        
+        boolean result = true;
+        
+        String files[] = null;
+        if (src.isDirectory()) {
+            files = src.list();
+            result = dest.mkdir();
+        } else {
+            files = new String[1];
+            files[0] = "";
+        }
+        if (files == null) {
+            files = new String[0];
+        }
+        for (int i = 0; (i < files.length) && result; i++) {
+            File fileSrc = new File(src, files[i]);
+            File fileDest = new File(dest, files[i]);
+            if (fileSrc.isDirectory()) {
+                result = copyInternal(fileSrc, fileDest, buf);
+            } else {
+                FileInputStream is = null;
+                FileOutputStream os = null;
+                try {
+                    is = new FileInputStream(fileSrc);
+                    os = new FileOutputStream(fileDest);
+                    int len = 0;
+                    while (true) {
+                        len = is.read(buf);
+                        if (len == -1)
+                            break;
+                        os.write(buf, 0, len);
+                    }
+                } catch (IOException e) {
+                    e.printStackTrace();
+                    result = false;
+                } finally {
+                    if (is != null) {
+                        try {
+                            is.close();
+                        } catch (IOException e) {
+                        }
+                    }
+                    if (os != null) {
+                        try {
+                            os.close();
+                        } catch (IOException e) {
+                        }
+                    }
+                }
+            }
+        }
+        return result;
+        
+    }
+    
+    
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/manager/WEB-INF/classes/org/apache/catalina/manager/ManagerServlet.java.orig
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/manager/WEB-INF/classes/org/apache/catalina/manager/ManagerServlet.java.orig	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/manager/WEB-INF/classes/org/apache/catalina/manager/ManagerServlet.java.orig	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,1572 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.manager;
+
+
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.Iterator;
+
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+import javax.naming.Binding;
+import javax.naming.InitialContext;
+import javax.naming.NamingEnumeration;
+import javax.naming.NamingException;
+import javax.servlet.ServletException;
+import javax.servlet.ServletInputStream;
+import javax.servlet.UnavailableException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import org.apache.catalina.Container;
+import org.apache.catalina.ContainerServlet;
+import org.apache.catalina.Context;
+import org.apache.catalina.Engine;
+import org.apache.catalina.Globals;
+import org.apache.catalina.Host;
+import org.apache.catalina.Lifecycle;
+import org.apache.catalina.Role;
+import org.apache.catalina.Server;
+import org.apache.catalina.ServerFactory;
+import org.apache.catalina.Session;
+import org.apache.catalina.UserDatabase;
+import org.apache.catalina.Wrapper;
+import org.apache.catalina.core.StandardServer;
+import org.apache.catalina.util.RequestUtil;
+import org.apache.catalina.util.ServerInfo;
+import org.apache.catalina.util.StringManager;
+import org.apache.commons.modeler.Registry;
+
+
+/**
+ * Servlet that enables remote management of the web applications installed
+ * within the same virtual host as this web application is.  Normally, this
+ * functionality will be protected by a security constraint in the web
+ * application deployment descriptor.  However, this requirement can be
+ * relaxed during testing.
+ * <p>
+ * This servlet examines the value returned by <code>getPathInfo()</code>
+ * and related query parameters to determine what action is being requested.
+ * The following actions and parameters (starting after the servlet path)
+ * are supported:
+ * <ul>
+ * <li><b>/deploy?config={config-url}</b> - Install and start a new
+ *     web application, based on the contents of the context configuration
+ *     file found at the specified URL.  The <code>docBase</code> attribute
+ *     of the context configuration file is used to locate the actual
+ *     WAR or directory containing the application.</li>
+ * <li><b>/deploy?config={config-url}&war={war-url}/</b> - Install and start
+ *     a new web application, based on the contents of the context
+ *     configuration file found at <code>{config-url}</code>, overriding the
+ *     <code>docBase</code> attribute with the contents of the web
+ *     application archive found at <code>{war-url}</code>.</li>
+ * <li><b>/deploy?path=/xxx&war={war-url}</b> - Install and start a new
+ *     web application attached to context path <code>/xxx</code>, based
+ *     on the contents of the web application archive found at the
+ *     specified URL.</li>
+ * <li><b>/list</b> - List the context paths of all currently installed web
+ *     applications for this virtual host.  Each context will be listed with
+ *     the following format <code>path:status:sessions</code>.
+ *     Where path is the context path.  Status is either running or stopped.
+ *     Sessions is the number of active Sessions.</li>
+ * <li><b>/reload?path=/xxx</b> - Reload the Java classes and resources for
+ *     the application at the specified path.</li>
+ * <li><b>/resources?type=xxxx</b> - Enumerate the available global JNDI
+ *     resources, optionally limited to those of the specified type
+ *     (fully qualified Java class name), if available.</li>
+ * <li><b>/roles</b> - Enumerate the available security role names and
+ *     descriptions from the user database connected to the <code>users</code>
+ *     resource reference.
+ * <li><b>/serverinfo</b> - Display system OS and JVM properties.
+ * <li><b>/sessions?path=/xxx</b> - List session information about the web
+ *     application attached to context path <code>/xxx</code> for this
+ *     virtual host.</li>
+ * <li><b>/start?path=/xxx</b> - Start the web application attached to
+ *     context path <code>/xxx</code> for this virtual host.</li>
+ * <li><b>/stop?path=/xxx</b> - Stop the web application attached to
+ *     context path <code>/xxx</code> for this virtual host.</li>
+ * <li><b>/undeploy?path=/xxx</b> - Shutdown and remove the web application
+ *     attached to context path <code>/xxx</code> for this virtual host,
+ *     and remove the underlying WAR file or document base directory.
+ *     (<em>NOTE</em> - This is only allowed if the WAR file or document
+ *     base is stored in the <code>appBase</code> directory of this host,
+ *     typically as a result of being placed there via the <code>/deploy</code>
+ *     command.</li>
+ * </ul>
+ * <p>Use <code>path=/</code> for the ROOT context.</p>
+ * <p>The syntax of the URL for a web application archive must conform to one
+ * of the following patterns to be successfully deployed:</p>
+ * <ul>
+ * <li><b>file:/absolute/path/to/a/directory</b> - You can specify the absolute
+ *     path of a directory that contains the unpacked version of a web
+ *     application.  This directory will be attached to the context path you
+ *     specify without any changes.</li>
+ * <li><b>jar:file:/absolute/path/to/a/warfile.war!/</b> - You can specify a
+ *     URL to a local web application archive file.  The syntax must conform to
+ *     the rules specified by the <code>JarURLConnection</code> class for a
+ *     reference to an entire JAR file.</li>
+ * <li><b>jar:http://hostname:port/path/to/a/warfile.war!/</b> - You can specify
+ *     a URL to a remote (HTTP-accessible) web application archive file.  The
+ *     syntax must conform to the rules specified by the
+ *     <code>JarURLConnection</code> class for a reference to an entire
+ *     JAR file.</li>
+ * </ul>
+ * <p>
+ * <b>NOTE</b> - Attempting to reload or remove the application containing
+ * this servlet itself will not succeed.  Therefore, this servlet should
+ * generally be deployed as a separate web application within the virtual host
+ * to be managed.
+ * <p>
+ * <b>NOTE</b> - For security reasons, this application will not operate
+ * when accessed via the invoker servlet.  You must explicitly map this servlet
+ * with a servlet mapping, and you will always want to protect it with
+ * appropriate security constraints as well.
+ * <p>
+ * The following servlet initialization parameters are recognized:
+ * <ul>
+ * <li><b>debug</b> - The debugging detail level that controls the amount
+ *     of information that is logged by this servlet.  Default is zero.
+ * </ul>
+ *
+ * @author Craig R. McClanahan
+ * @author Remy Maucherat
+ * @version $Revision: 303614 $ $Date: 2005-01-04 19:03:22 -0600 (Tue, 04 Jan 2005) $
+ */
+
+public class ManagerServlet
+    extends HttpServlet implements ContainerServlet {
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * Path where context descriptors should be deployed.
+     */
+    protected File configBase = null;
+
+
+    /**
+     * The Context container associated with our web application.
+     */
+    protected Context context = null;
+
+
+    /**
+     * The debugging detail level for this servlet.
+     */
+    protected int debug = 1;
+
+
+    /**
+     * File object representing the directory into which the deploy() command
+     * will store the WAR and context configuration files that have been
+     * uploaded.
+     */
+    protected File deployed = null;
+
+
+    /**
+     * Path used to store revisions of webapps.
+     */
+    protected File versioned = null;
+
+
+    /**
+     * Path used to store context descriptors.
+     */
+    protected File contextDescriptors = null;
+
+
+    /**
+     * The associated host.
+     */
+    protected Host host = null;
+
+    
+    /**
+     * The host appBase.
+     */
+    protected File appBase = null;
+    
+    
+    /**
+     * MBean server.
+     */
+    protected MBeanServer mBeanServer = null;
+
+
+    /**
+     * The associated deployer ObjectName.
+     */
+    protected ObjectName oname = null;
+    
+
+    /**
+     * The global JNDI <code>NamingContext</code> for this server,
+     * if available.
+     */
+    protected javax.naming.Context global = null;
+
+
+    /**
+     * The string manager for this package.
+     */
+    protected static StringManager sm =
+        StringManager.getManager(Constants.Package);
+
+
+    /**
+     * The Wrapper container associated with this servlet.
+     */
+    protected Wrapper wrapper = null;
+
+
+    // ----------------------------------------------- ContainerServlet Methods
+
+
+    /**
+     * Return the Wrapper with which we are associated.
+     */
+    public Wrapper getWrapper() {
+
+        return (this.wrapper);
+
+    }
+
+
+    /**
+     * Set the Wrapper with which we are associated.
+     *
+     * @param wrapper The new wrapper
+     */
+    public void setWrapper(Wrapper wrapper) {
+
+        this.wrapper = wrapper;
+        if (wrapper == null) {
+            context = null;
+            host = null;
+            oname = null;
+        } else {
+            context = (Context) wrapper.getParent();
+            host = (Host) context.getParent();
+            Engine engine = (Engine) host.getParent();
+            try {
+                oname = new ObjectName(engine.getName() 
+                        + ":type=Deployer,host=" + host.getName());
+            } catch (Exception e) {
+                // ?
+            }
+        }
+
+        // Retrieve the MBean server
+        mBeanServer = Registry.getRegistry(null, null).getMBeanServer();
+        
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Finalize this servlet.
+     */
+    public void destroy() {
+
+        ;       // No actions necessary
+
+    }
+
+
+    /**
+     * Process a GET request for the specified resource.
+     *
+     * @param request The servlet request we are processing
+     * @param response The servlet response we are creating
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception ServletException if a servlet-specified error occurs
+     */
+    public void doGet(HttpServletRequest request,
+                      HttpServletResponse response)
+        throws IOException, ServletException {
+
+        // Verify that we were not accessed using the invoker servlet
+        if (request.getAttribute(Globals.INVOKED_ATTR) != null)
+            throw new UnavailableException
+                (sm.getString("managerServlet.cannotInvoke"));
+
+        // Identify the request parameters that we need
+        String command = request.getPathInfo();
+        if (command == null)
+            command = request.getServletPath();
+        String config = request.getParameter("config");
+        String path = request.getParameter("path");
+        String type = request.getParameter("type");
+        String war = request.getParameter("war");
+        String tag = request.getParameter("tag");
+        boolean update = false;
+        if ((request.getParameter("update") != null) 
+            && (request.getParameter("update").equals("true"))) {
+            update = true;
+        }
+
+        // Prepare our output writer to generate the response message
+        response.setContentType("text/plain; charset=" + Constants.CHARSET);
+        PrintWriter writer = response.getWriter();
+
+        // Process the requested command (note - "/deploy" is not listed here)
+        if (command == null) {
+            writer.println(sm.getString("managerServlet.noCommand"));
+        } else if (command.equals("/deploy")) {
+            if (war != null || config != null) {
+                deploy(writer, config, path, war, update);
+            } else {
+                deploy(writer, path, tag);
+            }
+        } else if (command.equals("/install")) {
+            // Deprecated
+            deploy(writer, config, path, war, false);
+        } else if (command.equals("/list")) {
+            list(writer);
+        } else if (command.equals("/reload")) {
+            reload(writer, path);
+        } else if (command.equals("/remove")) {
+            // Deprecated
+            undeploy(writer, path);
+        } else if (command.equals("/resources")) {
+            resources(writer, type);
+        } else if (command.equals("/roles")) {
+            roles(writer);
+        } else if (command.equals("/save")) {
+            save(writer, path);
+        } else if (command.equals("/serverinfo")) {
+            serverinfo(writer);
+        } else if (command.equals("/sessions")) {
+            sessions(writer, path);
+        } else if (command.equals("/start")) {
+            start(writer, path);
+        } else if (command.equals("/stop")) {
+            stop(writer, path);
+        } else if (command.equals("/undeploy")) {
+            undeploy(writer, path);
+        } else {
+            writer.println(sm.getString("managerServlet.unknownCommand",
+                                        command));
+        }
+
+        // Finish up the response
+        writer.flush();
+        writer.close();
+
+    }
+
+
+    /**
+     * Process a PUT request for the specified resource.
+     *
+     * @param request The servlet request we are processing
+     * @param response The servlet response we are creating
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception ServletException if a servlet-specified error occurs
+     */
+    public void doPut(HttpServletRequest request,
+                      HttpServletResponse response)
+        throws IOException, ServletException {
+
+        // Verify that we were not accessed using the invoker servlet
+        if (request.getAttribute(Globals.INVOKED_ATTR) != null)
+            throw new UnavailableException
+                (sm.getString("managerServlet.cannotInvoke"));
+
+        // Identify the request parameters that we need
+        String command = request.getPathInfo();
+        if (command == null)
+            command = request.getServletPath();
+        String path = request.getParameter("path");
+        String tag = request.getParameter("tag");
+        boolean update = false;
+        if ((request.getParameter("update") != null) 
+            && (request.getParameter("update").equals("true"))) {
+            update = true;
+        }
+
+        // Prepare our output writer to generate the response message
+        response.setContentType("text/plain;charset="+Constants.CHARSET);
+        PrintWriter writer = response.getWriter();
+
+        // Process the requested command
+        if (command == null) {
+            writer.println(sm.getString("managerServlet.noCommand"));
+        } else if (command.equals("/deploy")) {
+            deploy(writer, path, tag, update, request);
+        } else {
+            writer.println(sm.getString("managerServlet.unknownCommand",
+                                        command));
+        }
+
+        // Finish up the response
+        writer.flush();
+        writer.close();
+
+    }
+
+
+    /**
+     * Initialize this servlet.
+     */
+    public void init() throws ServletException {
+
+        // Ensure that our ContainerServlet properties have been set
+        if ((wrapper == null) || (context == null))
+            throw new UnavailableException
+                (sm.getString("managerServlet.noWrapper"));
+
+        // Verify that we were not accessed using the invoker servlet
+        String servletName = getServletConfig().getServletName();
+        if (servletName == null)
+            servletName = "";
+        if (servletName.startsWith("org.apache.catalina.INVOKER."))
+            throw new UnavailableException
+                (sm.getString("managerServlet.cannotInvoke"));
+
+        // Set our properties from the initialization parameters
+        String value = null;
+        try {
+            value = getServletConfig().getInitParameter("debug");
+            debug = Integer.parseInt(value);
+        } catch (Throwable t) {
+            ;
+        }
+
+        // Acquire global JNDI resources if available
+        Server server = ServerFactory.getServer();
+        if ((server != null) && (server instanceof StandardServer)) {
+            global = ((StandardServer) server).getGlobalNamingContext();
+        }
+
+        // Calculate the directory into which we will be deploying applications
+        versioned = (File) getServletContext().getAttribute
+            ("javax.servlet.context.tempdir");
+
+        // Identify the appBase of the owning Host of this Context
+        // (if any)
+        String appBase = ((Host) context.getParent()).getAppBase();
+        deployed = new File(appBase);
+        if (!deployed.isAbsolute()) {
+            deployed = new File(System.getProperty("catalina.base"),
+                                appBase);
+        }
+        configBase = new File(System.getProperty("catalina.base"), "conf");
+        Container container = context;
+        Container host = null;
+        Container engine = null;
+        while (container != null) {
+            if (container instanceof Host)
+                host = container;
+            if (container instanceof Engine)
+                engine = container;
+            container = container.getParent();
+        }
+        if (engine != null) {
+            configBase = new File(configBase, engine.getName());
+        }
+        if (host != null) {
+            configBase = new File(configBase, host.getName());
+        }
+        // Note: The directory must exist for this to work.
+
+        // Log debugging messages as necessary
+        if (debug >= 1) {
+            log("init: Associated with Deployer '" +
+                oname + "'");
+            if (global != null) {
+                log("init: Global resources are available");
+            }
+        }
+
+    }
+
+
+
+    // -------------------------------------------------------- Private Methods
+
+
+    /**
+     * Store server configuration.
+     * 
+     * @param path Optional context path to save
+     */
+    protected synchronized void save(PrintWriter writer, String path) {
+
+        Server server = ServerFactory.getServer();
+
+        if (!(server instanceof StandardServer)) {
+            writer.println(sm.getString("managerServlet.saveFail", server));
+            return;
+        }
+
+        if ((path == null) || path.length() == 0 || !path.startsWith("/")) {
+            try {
+                ((StandardServer) server).storeConfig();
+                writer.println(sm.getString("managerServlet.saved"));
+            } catch (Exception e) {
+                log("managerServlet.storeConfig", e);
+                writer.println(sm.getString("managerServlet.exception",
+                                            e.toString()));
+                return;
+            }
+        } else {
+            String contextPath = path;
+            if (path.equals("/")) {
+                contextPath = "";
+            }
+            Context context = (Context) host.findChild(contextPath);
+            if (context == null) {
+                writer.println(sm.getString("managerServlet.noContext", path));
+                return;
+            }
+            try {
+                ((StandardServer) server).storeContext(context);
+                writer.println(sm.getString("managerServlet.savedContext", 
+                               path));
+            } catch (Exception e) {
+                log("managerServlet.save[" + path + "]", e);
+                writer.println(sm.getString("managerServlet.exception",
+                                            e.toString()));
+                return;
+            }
+        }
+
+    }
+
+
+    /**
+     * Deploy a web application archive (included in the current request)
+     * at the specified context path.
+     *
+     * @param writer Writer to render results to
+     * @param path Context path of the application to be installed
+     * @param tag Tag to be associated with the webapp
+     * @param request Servlet request we are processing
+     */
+    protected synchronized void deploy
+        (PrintWriter writer, String path,
+         String tag, boolean update, HttpServletRequest request) {
+
+        if (debug >= 1) {
+            log("deploy: Deploying web application at '" + path + "'");
+        }
+
+        // Validate the requested context path
+        if ((path == null) || path.length() == 0 || !path.startsWith("/")) {
+            writer.println(sm.getString("managerServlet.invalidPath", path));
+            return;
+        }
+        String displayPath = path;
+        if( path.equals("/") )
+            path = "";
+        String basename = getDocBase(path);
+
+        // Check if app already exists, or undeploy it if updating
+        Context context = (Context) host.findChild(path);
+        if (update) {
+            if (context != null) {
+                undeploy(writer, displayPath);
+            }
+            context = (Context) host.findChild(path);
+        }
+        if (context != null) {
+            writer.println
+                (sm.getString("managerServlet.alreadyContext",
+                              displayPath));
+            return;
+        }
+
+        // Calculate the base path
+        File deployedPath = deployed;
+        if (tag != null) {
+            deployedPath = new File(versioned, tag);
+            deployedPath.mkdirs();
+        }
+
+        // Upload the web application archive to a local WAR file
+        File localWar = new File(deployedPath, basename + ".war");
+        if (debug >= 2) {
+            log("Uploading WAR file to " + localWar);
+        }
+
+        // Copy WAR to appBase
+        try {
+            if (!isServiced(path)) {
+                addServiced(path);
+                try {
+                    // Upload WAR
+                    uploadWar(request, localWar);
+                    // Copy WAR and XML to the host app base if needed
+                    if (tag != null) {
+                        deployedPath = deployed;
+                        File localWarCopy = new File(deployedPath, basename + ".war");
+                        copy(localWar, localWarCopy);
+                        localWar = localWarCopy;
+                        copy(localWar, new File(getAppBase(), basename + ".war"));
+                    }
+                    // Perform new deployment
+                    check(path);
+                } finally {
+                    removeServiced(path);
+                }
+            }
+        } catch (Exception e) {
+            log("managerServlet.check[" + displayPath + "]", e);
+            writer.println(sm.getString("managerServlet.exception",
+                                        e.toString()));
+            return;
+        }
+        
+        context = (Context) host.findChild(path);
+        if (context != null && context.getConfigured()) {
+            writer.println(sm.getString("managerServlet.deployed", displayPath));
+        } else {
+            // Something failed
+            writer.println(sm.getString("managerServlet.deployFailed", displayPath));
+        }
+        
+    }
+
+
+    /**
+     * Install an application for the specified path from the specified
+     * web application archive.
+     *
+     * @param writer Writer to render results to
+     * @param tag Revision tag to deploy from
+     * @param path Context path of the application to be installed
+     */
+    protected void deploy(PrintWriter writer, String path, String tag) {
+
+        // Validate the requested context path
+        if ((path == null) || path.length() == 0 || !path.startsWith("/")) {
+            writer.println(sm.getString("managerServlet.invalidPath", path));
+            return;
+        }
+        String displayPath = path;
+        if( path.equals("/") )
+            path = "";
+
+        // Calculate the base path
+        File deployedPath = versioned;
+        if (tag != null) {
+            deployedPath = new File(deployedPath, tag);
+        }
+
+        // Find the local WAR file
+        File localWar = new File(deployedPath, getDocBase(path) + ".war");
+        // Find the local context deployment file (if any)
+        File localXml = new File(configBase, getConfigFile(path) + ".xml");
+
+        // Check if app already exists, or undeploy it if updating
+        Context context = (Context) host.findChild(path);
+        if (context != null) {
+            undeploy(writer, displayPath);
+        }
+
+        // Copy WAR to appBase
+        try {
+            if (!isServiced(path)) {
+                addServiced(path);
+                try {
+                    copy(localWar, new File(getAppBase(), getDocBase(path) + ".war"));
+                    // Perform new deployment
+                    check(path);
+                } finally {
+                    removeServiced(path);
+                }
+            }
+        } catch (Exception e) {
+            log("managerServlet.check[" + displayPath + "]", e);
+            writer.println(sm.getString("managerServlet.exception",
+                                        e.toString()));
+            return;
+        }
+        
+        context = (Context) host.findChild(path);
+        if (context != null && context.getConfigured()) {
+            writer.println(sm.getString("managerServlet.deployed", displayPath));
+        } else {
+            // Something failed
+            writer.println(sm.getString("managerServlet.deployFailed", displayPath));
+        }
+        
+    }
+
+
+    /**
+     * Install an application for the specified path from the specified
+     * web application archive.
+     *
+     * @param writer Writer to render results to
+     * @param config URL of the context configuration file to be installed
+     * @param path Context path of the application to be installed
+     * @param war URL of the web application archive to be installed
+     * @param update true to override any existing webapp on the path
+     */
+    protected void deploy(PrintWriter writer, String config,
+            String path, String war, boolean update) {
+        
+        if (config != null && config.length() == 0) {
+            config = null;
+        }
+        if (war != null && war.length() == 0) {
+            war = null;
+        }
+        
+        if (debug >= 1) {
+            if (config != null && config.length() > 0) {
+                if (war != null) {
+                    log("install: Installing context configuration at '" +
+                            config + "' from '" + war + "'");
+                } else {
+                    log("install: Installing context configuration at '" +
+                            config + "'");
+                }
+            } else {
+                if (path != null && path.length() > 0) {
+                    log("install: Installing web application at '" + path +
+                            "' from '" + war + "'");
+                } else {
+                    log("install: Installing web application from '" + war + "'");
+                }
+            }
+        }
+        
+        if (path == null || path.length() == 0 || !path.startsWith("/")) {
+            writer.println(sm.getString("managerServlet.invalidPath",
+                                        RequestUtil.filter(path)));
+            return;
+        }
+        String displayPath = path;
+        if("/".equals(path)) {
+            path = "";
+        }
+        
+        // Check if app already exists, or undeploy it if updating
+        Context context = (Context) host.findChild(path);
+        if (update) {
+            if (context != null) {
+                undeploy(writer, displayPath);
+            }
+            context = (Context) host.findChild(path);
+        }
+        if (context != null) {
+            writer.println
+            (sm.getString("managerServlet.alreadyContext",
+                    displayPath));
+            return;
+        }
+        
+        if (config != null && (config.startsWith("file:"))) {
+            config = config.substring("file:".length());
+        }
+        if (war != null && (war.startsWith("file:"))) {
+            war = war.substring("file:".length());
+        }
+        
+        try {
+            if (!isServiced(path)) {
+                addServiced(path);
+                try {
+                    if (config != null) {
+                        copy(new File(config), 
+                                new File(configBase, getConfigFile(path) + ".xml"));
+                    }
+                    if (war != null) {
+                        if (war.endsWith(".war")) {
+                            copy(new File(war), 
+                                    new File(getAppBase(), getDocBase(path) + ".war"));
+                        } else {
+                            copy(new File(war), 
+                                    new File(getAppBase(), getDocBase(path)));
+                        }
+                    }
+                    // Perform new deployment
+                    check(path);
+                } finally {
+                    removeServiced(path);
+                }
+            }
+            context = (Context) host.findChild(path);
+            if (context != null && context.getConfigured()) {
+                writer.println(sm.getString("managerServlet.deployed", displayPath));
+            } else {
+                // Something failed
+                writer.println(sm.getString("managerServlet.deployFailed", displayPath));
+            }
+        } catch (Throwable t) {
+            log("ManagerServlet.install[" + displayPath + "]", t);
+            writer.println(sm.getString("managerServlet.exception",
+                    t.toString()));
+        }
+        
+    }
+
+
+    /**
+     * Render a list of the currently active Contexts in our virtual host.
+     *
+     * @param writer Writer to render to
+     */
+    protected void list(PrintWriter writer) {
+
+        if (debug >= 1)
+            log("list: Listing contexts for virtual host '" +
+                host.getName() + "'");
+
+        writer.println(sm.getString("managerServlet.listed",
+                                    host.getName()));
+        Container[] contexts = host.findChildren();
+        for (int i = 0; i < contexts.length; i++) {
+            Context context = (Context) contexts[i];
+            String displayPath = context.getPath();
+            if( displayPath.equals("") )
+                displayPath = "/";
+            if (context != null ) {
+                if (context.getAvailable()) {
+                    writer.println(sm.getString("managerServlet.listitem",
+                                                displayPath,
+                                                "running",
+                                      "" + context.getManager().findSessions().length,
+                                                context.getDocBase()));
+                } else {
+                    writer.println(sm.getString("managerServlet.listitem",
+                                                displayPath,
+                                                "stopped",
+                                                "0",
+                                                context.getDocBase()));
+                }
+            }
+        }
+    }
+
+
+    /**
+     * Reload the web application at the specified context path.
+     *
+     * @param writer Writer to render to
+     * @param path Context path of the application to be restarted
+     */
+    protected void reload(PrintWriter writer, String path) {
+
+        if (debug >= 1)
+            log("restart: Reloading web application at '" + path + "'");
+
+        if ((path == null) || (!path.startsWith("/") && path.equals(""))) {
+            writer.println(sm.getString("managerServlet.invalidPath",
+                                        RequestUtil.filter(path)));
+            return;
+        }
+        String displayPath = path;
+        if( path.equals("/") )
+            path = "";
+
+        try {
+            Context context = (Context) host.findChild(path);
+            if (context == null) {
+                writer.println(sm.getString
+                               ("managerServlet.noContext",
+                                   RequestUtil.filter(displayPath)));
+                return;
+            }
+            // It isn't possible for the manager to reload itself
+            if (context.getPath().equals(this.context.getPath())) {
+                writer.println(sm.getString("managerServlet.noSelf"));
+                return;
+            }
+            context.reload();
+            writer.println
+                (sm.getString("managerServlet.reloaded", displayPath));
+        } catch (Throwable t) {
+            log("ManagerServlet.reload[" + displayPath + "]", t);
+            writer.println(sm.getString("managerServlet.exception",
+                                        t.toString()));
+        }
+
+    }
+
+
+    /**
+     * Render a list of available global JNDI resources.
+     *
+     * @param type Fully qualified class name of the resource type of interest,
+     *  or <code>null</code> to list resources of all types
+     */
+    protected void resources(PrintWriter writer, String type) {
+
+        if (debug >= 1) {
+            if (type != null) {
+                log("resources:  Listing resources of type " + type);
+            } else {
+                log("resources:  Listing resources of all types");
+            }
+        }
+
+        // Is the global JNDI resources context available?
+        if (global == null) {
+            writer.println(sm.getString("managerServlet.noGlobal"));
+            return;
+        }
+
+        // Enumerate the global JNDI resources of the requested type
+        if (type != null) {
+            writer.println(sm.getString("managerServlet.resourcesType",
+                                        type));
+        } else {
+            writer.println(sm.getString("managerServlet.resourcesAll"));
+        }
+
+        Class clazz = null;
+        try {
+            if (type != null) {
+                clazz = Class.forName(type);
+            }
+        } catch (Throwable t) {
+            log("ManagerServlet.resources[" + type + "]", t);
+            writer.println(sm.getString("managerServlet.exception",
+                                        t.toString()));
+            return;
+        }
+
+        printResources(writer, "", global, type, clazz);
+
+    }
+
+
+    /**
+     * List the resources of the given context.
+     */
+    protected void printResources(PrintWriter writer, String prefix,
+                                  javax.naming.Context namingContext,
+                                  String type, Class clazz) {
+
+        try {
+            NamingEnumeration items = namingContext.listBindings("");
+            while (items.hasMore()) {
+                Binding item = (Binding) items.next();
+                if (item.getObject() instanceof javax.naming.Context) {
+                    printResources
+                        (writer, prefix + item.getName() + "/",
+                         (javax.naming.Context) item.getObject(), type, clazz);
+                } else {
+                    if ((clazz != null) &&
+                        (!(clazz.isInstance(item.getObject())))) {
+                        continue;
+                    }
+                    writer.print(prefix + item.getName());
+                    writer.print(':');
+                    writer.print(item.getClassName());
+                    // Do we want a description if available?
+                    writer.println();
+                }
+            }
+        } catch (Throwable t) {
+            log("ManagerServlet.resources[" + type + "]", t);
+            writer.println(sm.getString("managerServlet.exception",
+                                        t.toString()));
+        }
+
+    }
+
+
+    /**
+     * Render a list of security role names (and corresponding descriptions)
+     * from the <code>org.apache.catalina.UserDatabase</code> resource that is
+     * connected to the <code>users</code> resource reference.  Typically, this
+     * will be the global user database, but can be adjusted if you have
+     * different user databases for different virtual hosts.
+     *
+     * @param writer Writer to render to
+     */
+    protected void roles(PrintWriter writer) {
+
+        if (debug >= 1) {
+            log("roles:  List security roles from user database");
+        }
+
+        // Look up the UserDatabase instance we should use
+        UserDatabase database = null;
+        try {
+            InitialContext ic = new InitialContext();
+            database = (UserDatabase) ic.lookup("java:comp/env/users");
+        } catch (NamingException e) {
+            writer.println(sm.getString("managerServlet.userDatabaseError"));
+            log("java:comp/env/users", e);
+            return;
+        }
+        if (database == null) {
+            writer.println(sm.getString("managerServlet.userDatabaseMissing"));
+            return;
+        }
+
+        // Enumerate the available roles
+        writer.println(sm.getString("managerServlet.rolesList"));
+        Iterator roles = database.getRoles();
+        if (roles != null) {
+            while (roles.hasNext()) {
+                Role role = (Role) roles.next();
+                writer.print(role.getRolename());
+                writer.print(':');
+                if (role.getDescription() != null) {
+                    writer.print(role.getDescription());
+                }
+                writer.println();
+            }
+        }
+
+
+    }
+
+
+    /**
+     * Writes System OS and JVM properties.
+     * @param writer Writer to render to
+     */
+    protected void serverinfo(PrintWriter writer) {
+        if (debug >= 1)
+            log("serverinfo");
+        try {
+            StringBuffer props = new StringBuffer();
+            props.append("OK - Server info");
+            props.append("\nTomcat Version: ");
+            props.append(ServerInfo.getServerInfo());
+            props.append("\nOS Name: ");
+            props.append(System.getProperty("os.name"));
+            props.append("\nOS Version: ");
+            props.append(System.getProperty("os.version"));
+            props.append("\nOS Architecture: ");
+            props.append(System.getProperty("os.arch"));
+            props.append("\nJVM Version: ");
+            props.append(System.getProperty("java.runtime.version"));
+            props.append("\nJVM Vendor: ");
+            props.append(System.getProperty("java.vm.vendor"));
+            writer.println(props.toString());
+        } catch (Throwable t) {
+            getServletContext().log("ManagerServlet.serverinfo",t);
+            writer.println(sm.getString("managerServlet.exception",
+                                        t.toString()));
+        }
+    }
+
+    /**
+     * Session information for the web application at the specified context path.
+     * Displays a profile of session MaxInactiveInterval timeouts listing number
+     * of sessions for each 10 minute timeout interval up to 10 hours.
+     *
+     * @param writer Writer to render to
+     * @param path Context path of the application to list session information for
+     */
+    protected void sessions(PrintWriter writer, String path) {
+
+        if (debug >= 1)
+            log("sessions: Session information for web application at '" + path + "'");
+
+        if ((path == null) || (!path.startsWith("/") && path.equals(""))) {
+            writer.println(sm.getString("managerServlet.invalidPath",
+                                        RequestUtil.filter(path)));
+            return;
+        }
+        String displayPath = path;
+        if( path.equals("/") )
+            path = "";
+        try {
+            Context context = (Context) host.findChild(path);
+            if (context == null) {
+                writer.println(sm.getString("managerServlet.noContext",
+                                            RequestUtil.filter(displayPath)));
+                return;
+            }
+            writer.println(sm.getString("managerServlet.sessions", displayPath));
+            writer.println(sm.getString("managerServlet.sessiondefaultmax",
+                                "" + context.getManager().getMaxInactiveInterval()/60));
+            Session [] sessions = context.getManager().findSessions();
+            int [] timeout = new int[60];
+            int notimeout = 0;
+            for (int i = 0; i < sessions.length; i++) {
+                int time = sessions[i].getMaxInactiveInterval()/(10*60);
+                if (time < 0)
+                    notimeout++;
+                else if (time >= timeout.length)
+                    timeout[timeout.length-1]++;
+                else
+                    timeout[time]++;
+            }
+            if (timeout[0] > 0)
+                writer.println(sm.getString("managerServlet.sessiontimeout",
+                                            "<10", "" + timeout[0]));
+            for (int i = 1; i < timeout.length-1; i++) {
+                if (timeout[i] > 0)
+                    writer.println(sm.getString("managerServlet.sessiontimeout",
+                                     "" + (i)*10 + " - <" + (i+1)*10,
+                                                "" + timeout[i]));
+            }
+            if (timeout[timeout.length-1] > 0)
+                writer.println(sm.getString("managerServlet.sessiontimeout",
+                                            ">=" + timeout.length*10,
+                                            "" + timeout[timeout.length-1]));
+            if (notimeout > 0)
+                writer.println(sm.getString("managerServlet.sessiontimeout",
+                                            "unlimited","" + notimeout));
+        } catch (Throwable t) {
+            log("ManagerServlet.sessions[" + displayPath + "]", t);
+            writer.println(sm.getString("managerServlet.exception",
+                                        t.toString()));
+        }
+
+    }
+
+
+    /**
+     * Start the web application at the specified context path.
+     *
+     * @param writer Writer to render to
+     * @param path Context path of the application to be started
+     */
+    protected void start(PrintWriter writer, String path) {
+
+        if (debug >= 1)
+            log("start: Starting web application at '" + path + "'");
+
+        if ((path == null) || (!path.startsWith("/") && path.equals(""))) {
+            writer.println(sm.getString("managerServlet.invalidPath",
+                                        RequestUtil.filter(path)));
+            return;
+        }
+        String displayPath = path;
+        if( path.equals("/") )
+            path = "";
+
+        try {
+            Context context = (Context) host.findChild(path);
+            if (context == null) {
+                writer.println(sm.getString("managerServlet.noContext", 
+                                            RequestUtil.filter(displayPath)));
+                return;
+            }
+            ((Lifecycle) context).start();
+            if (context.getAvailable())
+                writer.println
+                    (sm.getString("managerServlet.started", displayPath));
+            else
+                writer.println
+                    (sm.getString("managerServlet.startFailed", displayPath));
+        } catch (Throwable t) {
+            getServletContext().log
+                (sm.getString("managerServlet.startFailed", displayPath), t);
+            writer.println
+                (sm.getString("managerServlet.startFailed", displayPath));
+            writer.println(sm.getString("managerServlet.exception",
+                                        t.toString()));
+        }
+
+    }
+
+
+    /**
+     * Stop the web application at the specified context path.
+     *
+     * @param writer Writer to render to
+     * @param path Context path of the application to be stopped
+     */
+    protected void stop(PrintWriter writer, String path) {
+
+        if (debug >= 1)
+            log("stop: Stopping web application at '" + path + "'");
+
+        if ((path == null) || (!path.startsWith("/") && path.equals(""))) {
+            writer.println(sm.getString("managerServlet.invalidPath",
+                                        RequestUtil.filter(path)));
+            return;
+        }
+        String displayPath = path;
+        if( path.equals("/") )
+            path = "";
+
+        try {
+            Context context = (Context) host.findChild(path);
+            if (context == null) {
+                writer.println(sm.getString("managerServlet.noContext", 
+                                            RequestUtil.filter(displayPath)));
+                return;
+            }
+            // It isn't possible for the manager to stop itself
+            if (context.getPath().equals(this.context.getPath())) {
+                writer.println(sm.getString("managerServlet.noSelf"));
+                return;
+            }
+            ((Lifecycle) context).stop();
+            writer.println(sm.getString("managerServlet.stopped", displayPath));
+        } catch (Throwable t) {
+            log("ManagerServlet.stop[" + displayPath + "]", t);
+            writer.println(sm.getString("managerServlet.exception",
+                                        t.toString()));
+        }
+
+    }
+
+
+    /**
+     * Undeploy the web application at the specified context path.
+     *
+     * @param writer Writer to render to
+     * @param path Context path of the application to be removed
+     */
+    protected void undeploy(PrintWriter writer, String path) {
+
+        if (debug >= 1)
+            log("undeploy: Undeploying web application at '" + path + "'");
+
+        if ((path == null) || (!path.startsWith("/") && path.equals(""))) {
+            writer.println(sm.getString("managerServlet.invalidPath",
+                                        RequestUtil.filter(path)));
+            return;
+        }
+        String displayPath = path;
+        if( path.equals("/") )
+            path = "";
+
+        try {
+
+            // Validate the Context of the specified application
+            Context context = (Context) host.findChild(path);
+            if (context == null) {
+                writer.println(sm.getString("managerServlet.noContext",
+                                            RequestUtil.filter(displayPath)));
+                return;
+            }
+
+            // Identify the appBase of the owning Host of this Context (if any)
+            String appBase = null;
+            File appBaseDir = null;
+            if (context.getParent() instanceof Host) {
+                appBase = ((Host) context.getParent()).getAppBase();
+                appBaseDir = new File(appBase);
+                if (!appBaseDir.isAbsolute()) {
+                    appBaseDir = new File(System.getProperty("catalina.base"),
+                                          appBase);
+                }
+            }
+
+            if (!isServiced(path)) {
+                addServiced(path);
+                try {
+                    // Try to stop the context first to be nicer
+                    ((Lifecycle) context).stop();
+                } catch (Throwable t) {
+                    // Ignore
+                }
+                try {
+                    File war = new File(getAppBase(), getDocBase(path) + ".war");
+                    File dir = new File(getAppBase(), getDocBase(path));
+                    File xml = new File(configBase, getConfigFile(path) + ".xml");
+                    if (war.exists()) {
+                        war.delete();
+                    } else if (dir.exists()) {
+                        undeployDir(dir);
+                    } else {
+                        xml.delete();
+                    }
+                    // Perform new deployment
+                    check(path);
+                } finally {
+                    removeServiced(path);
+                }
+            }
+            writer.println(sm.getString("managerServlet.undeployed",
+                                        displayPath));
+        } catch (Throwable t) {
+            log("ManagerServlet.undeploy[" + displayPath + "]", t);
+            writer.println(sm.getString("managerServlet.exception",
+                                        t.toString()));
+        }
+
+    }
+
+
+    // -------------------------------------------------------- Support Methods
+
+
+    /**
+     * Given a context path, get the config file name.
+     */
+    protected String getConfigFile(String path) {
+        String basename = null;
+        if (path.equals("")) {
+            basename = "ROOT";
+        } else {
+            basename = path.substring(1).replace('/', '#');
+        }
+        return (basename);
+    }
+
+
+    /**
+     * Given a context path, get the config file name.
+     */
+    protected String getDocBase(String path) {
+        String basename = null;
+        if (path.equals("")) {
+            basename = "ROOT";
+        } else {
+            basename = path.substring(1);
+        }
+        return (basename);
+    }
+
+    
+    /**
+     * Return a File object representing the "application root" directory
+     * for our associated Host.
+     */
+    protected File getAppBase() {
+
+        if (appBase != null) {
+            return appBase;
+        }
+
+        File file = new File(host.getAppBase());
+        if (!file.isAbsolute())
+            file = new File(System.getProperty("catalina.base"),
+                            host.getAppBase());
+        try {
+            appBase = file.getCanonicalFile();
+        } catch (IOException e) {
+            appBase = file;
+        }
+        return (appBase);
+
+    }
+
+
+    /**
+     * Invoke the check method on the deployer.
+     */
+    protected void check(String name) 
+        throws Exception {
+        String[] params = { name };
+        String[] signature = { "java.lang.String" };
+        mBeanServer.invoke(oname, "check", params, signature);
+    }
+    
+
+    /**
+     * Invoke the check method on the deployer.
+     */
+    protected boolean isServiced(String name) 
+        throws Exception {
+        String[] params = { name };
+        String[] signature = { "java.lang.String" };
+        Boolean result = 
+            (Boolean) mBeanServer.invoke(oname, "isServiced", params, signature);
+        return result.booleanValue();
+    }
+    
+
+    /**
+     * Invoke the check method on the deployer.
+     */
+    protected void addServiced(String name) 
+        throws Exception {
+        String[] params = { name };
+        String[] signature = { "java.lang.String" };
+        mBeanServer.invoke(oname, "addServiced", params, signature);
+    }
+    
+
+    /**
+     * Invoke the check method on the deployer.
+     */
+    protected void removeServiced(String name) 
+        throws Exception {
+        String[] params = { name };
+        String[] signature = { "java.lang.String" };
+        mBeanServer.invoke(oname, "removeServiced", params, signature);
+    }
+    
+
+    /**
+     * Delete the specified directory, including all of its contents and
+     * subdirectories recursively.
+     *
+     * @param dir File object representing the directory to be deleted
+     */
+    protected void undeployDir(File dir) {
+
+        String files[] = dir.list();
+        if (files == null) {
+            files = new String[0];
+        }
+        for (int i = 0; i < files.length; i++) {
+            File file = new File(dir, files[i]);
+            if (file.isDirectory()) {
+                undeployDir(file);
+            } else {
+                file.delete();
+            }
+        }
+        dir.delete();
+
+    }
+
+
+    /**
+     * Upload the WAR file included in this request, and store it at the
+     * specified file location.
+     *
+     * @param request The servlet request we are processing
+     * @param war The file into which we should store the uploaded WAR
+     *
+     * @exception IOException if an I/O error occurs during processing
+     */
+    protected void uploadWar(HttpServletRequest request, File war)
+        throws IOException {
+
+        war.delete();
+        ServletInputStream istream = null;
+        BufferedOutputStream ostream = null;
+        try {
+            istream = request.getInputStream();
+            ostream =
+                new BufferedOutputStream(new FileOutputStream(war), 1024);
+            byte buffer[] = new byte[1024];
+            while (true) {
+                int n = istream.read(buffer);
+                if (n < 0) {
+                    break;
+                }
+                ostream.write(buffer, 0, n);
+            }
+            ostream.flush();
+            ostream.close();
+            ostream = null;
+            istream.close();
+            istream = null;
+        } catch (IOException e) {
+            war.delete();
+            throw e;
+        } finally {
+            if (ostream != null) {
+                try {
+                    ostream.close();
+                } catch (Throwable t) {
+                    ;
+                }
+                ostream = null;
+            }
+            if (istream != null) {
+                try {
+                    istream.close();
+                } catch (Throwable t) {
+                    ;
+                }
+                istream = null;
+            }
+        }
+
+    }
+
+
+    /**
+     * Copy the specified file or directory to the destination.
+     *
+     * @param src File object representing the source
+     * @param dest File object representing the destination
+     */
+    public static boolean copy(File src, File dest) {
+        return copyInternal(src, dest, new byte[4096]);
+    }
+
+    
+    /**
+     * Copy the specified file or directory to the destination.
+     *
+     * @param src File object representing the source
+     * @param dest File object representing the destination
+     */
+    public static boolean copyInternal(File src, File dest, byte[] buf) {
+        
+        boolean result = true;
+        
+        String files[] = null;
+        if (src.isDirectory()) {
+            files = src.list();
+            result = dest.mkdir();
+        } else {
+            files = new String[1];
+            files[0] = "";
+        }
+        if (files == null) {
+            files = new String[0];
+        }
+        for (int i = 0; (i < files.length) && result; i++) {
+            File fileSrc = new File(src, files[i]);
+            File fileDest = new File(dest, files[i]);
+            if (fileSrc.isDirectory()) {
+                result = copyInternal(fileSrc, fileDest, buf);
+            } else {
+                FileInputStream is = null;
+                FileOutputStream os = null;
+                try {
+                    is = new FileInputStream(fileSrc);
+                    os = new FileOutputStream(fileDest);
+                    int len = 0;
+                    while (true) {
+                        len = is.read(buf);
+                        if (len == -1)
+                            break;
+                        os.write(buf, 0, len);
+                    }
+                } catch (IOException e) {
+                    e.printStackTrace();
+                    result = false;
+                } finally {
+                    if (is != null) {
+                        try {
+                            is.close();
+                        } catch (IOException e) {
+                        }
+                    }
+                    if (os != null) {
+                        try {
+                            os.close();
+                        } catch (IOException e) {
+                        }
+                    }
+                }
+            }
+        }
+        return result;
+        
+    }
+    
+    
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/manager/WEB-INF/classes/org/apache/catalina/manager/StatusManagerServlet.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/manager/WEB-INF/classes/org/apache/catalina/manager/StatusManagerServlet.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/manager/WEB-INF/classes/org/apache/catalina/manager/StatusManagerServlet.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,360 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.manager;
+
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.Enumeration;
+import java.util.Iterator;
+import java.util.Set;
+import java.util.Vector;
+
+import javax.management.MBeanServer;
+import javax.management.MBeanServerNotification;
+import javax.management.Notification;
+import javax.management.NotificationListener;
+import javax.management.ObjectInstance;
+import javax.management.ObjectName;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.commons.modeler.Registry;
+
+import org.apache.catalina.util.ServerInfo;
+import org.apache.catalina.util.StringManager;
+
+/**
+ * This servlet will display a complete status of the HTTP/1.1 connector.
+ *
+ * @author Remy Maucherat
+ * @version $Revision: 303870 $ $Date: 2005-04-18 17:50:24 -0500 (Mon, 18 Apr 2005) $
+ */
+
+public class StatusManagerServlet
+    extends HttpServlet implements NotificationListener {
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The debugging detail level for this servlet.
+     */
+    private int debug = 0;
+
+
+    /**
+     * MBean server.
+     */
+    protected MBeanServer mBeanServer = null;
+
+
+    /**
+     * Vector of protocol handlers object names.
+     */
+    protected Vector protocolHandlers = new Vector();
+
+
+    /**
+     * Vector of thread pools object names.
+     */
+    protected Vector threadPools = new Vector();
+
+
+    /**
+     * Vector of request processors object names.
+     */
+    protected Vector requestProcessors = new Vector();
+
+
+    /**
+     * Vector of global request processors object names.
+     */
+    protected Vector globalRequestProcessors = new Vector();
+
+
+    /**
+     * The string manager for this package.
+     */
+    protected static StringManager sm =
+        StringManager.getManager(Constants.Package);
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Initialize this servlet.
+     */
+    public void init() throws ServletException {
+
+        // Retrieve the MBean server
+        mBeanServer = Registry.getRegistry(null, null).getMBeanServer();
+
+        // Set our properties from the initialization parameters
+        String value = null;
+        try {
+            value = getServletConfig().getInitParameter("debug");
+            debug = Integer.parseInt(value);
+        } catch (Throwable t) {
+            ;
+        }
+
+        try {
+
+            // Query protocol handlers
+            String onStr = "*:type=ProtocolHandler,*";
+            ObjectName objectName = new ObjectName(onStr);
+            Set set = mBeanServer.queryMBeans(objectName, null);
+            Iterator iterator = set.iterator();
+            while (iterator.hasNext()) {
+                ObjectInstance oi = (ObjectInstance) iterator.next();
+                protocolHandlers.addElement(oi.getObjectName());
+            }
+
+            // Query Thread Pools
+            onStr = "*:type=ThreadPool,*";
+            objectName = new ObjectName(onStr);
+            set = mBeanServer.queryMBeans(objectName, null);
+            iterator = set.iterator();
+            while (iterator.hasNext()) {
+                ObjectInstance oi = (ObjectInstance) iterator.next();
+                threadPools.addElement(oi.getObjectName());
+            }
+
+            // Query Global Request Processors
+            onStr = "*:type=GlobalRequestProcessor,*";
+            objectName = new ObjectName(onStr);
+            set = mBeanServer.queryMBeans(objectName, null);
+            iterator = set.iterator();
+            while (iterator.hasNext()) {
+                ObjectInstance oi = (ObjectInstance) iterator.next();
+                globalRequestProcessors.addElement(oi.getObjectName());
+            }
+
+            // Query Request Processors
+            onStr = "*:type=RequestProcessor,*";
+            objectName = new ObjectName(onStr);
+            set = mBeanServer.queryMBeans(objectName, null);
+            iterator = set.iterator();
+            while (iterator.hasNext()) {
+                ObjectInstance oi = (ObjectInstance) iterator.next();
+                requestProcessors.addElement(oi.getObjectName());
+            }
+
+            // Register with MBean server
+            onStr = "JMImplementation:type=MBeanServerDelegate";
+            objectName = new ObjectName(onStr);
+            mBeanServer.addNotificationListener(objectName, this, null, null);
+
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+
+    }
+
+
+    /**
+     * Finalize this servlet.
+     */
+    public void destroy() {
+
+        ;       // No actions necessary
+
+    }
+
+
+    /**
+     * Process a GET request for the specified resource.
+     *
+     * @param request The servlet request we are processing
+     * @param response The servlet response we are creating
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception ServletException if a servlet-specified error occurs
+     */
+    public void doGet(HttpServletRequest request,
+                      HttpServletResponse response)
+        throws IOException, ServletException {
+
+        // mode is flag for HTML or XML output
+        int mode = 0;
+        // if ?XML=true, set the mode to XML
+        if (request.getParameter("XML") != null 
+            && request.getParameter("XML").equals("true")) {
+            mode = 1;
+        }
+        StatusTransformer.setContentType(response, mode);
+
+        PrintWriter writer = response.getWriter();
+
+        boolean completeStatus = false;
+        if ((request.getPathInfo() != null) 
+            && (request.getPathInfo().equals("/all"))) {
+            completeStatus = true;
+        }
+        // use StatusTransformer to output status
+        StatusTransformer.writeHeader(writer,mode);
+
+        // Body Header Section
+        Object[] args = new Object[2];
+        args[0] = request.getContextPath();
+        if (completeStatus) {
+            args[1] = sm.getString("statusServlet.complete");
+        } else {
+            args[1] = sm.getString("statusServlet.title");
+        }
+        // use StatusTransformer to output status
+        StatusTransformer.writeBody(writer,args,mode);
+
+        // Manager Section
+        args = new Object[9];
+        args[0] = sm.getString("htmlManagerServlet.manager");
+        args[1] = response.encodeURL(request.getContextPath() + "/html/list");
+        args[2] = sm.getString("htmlManagerServlet.list");
+        args[3] = response.encodeURL
+            (request.getContextPath() + "/" +
+             sm.getString("htmlManagerServlet.helpHtmlManagerFile"));
+        args[4] = sm.getString("htmlManagerServlet.helpHtmlManager");
+        args[5] = response.encodeURL
+            (request.getContextPath() + "/" +
+             sm.getString("htmlManagerServlet.helpManagerFile"));
+        args[6] = sm.getString("htmlManagerServlet.helpManager");
+        if (completeStatus) {
+            args[7] = response.encodeURL
+                (request.getContextPath() + "/status");
+            args[8] = sm.getString("statusServlet.title");
+        } else {
+            args[7] = response.encodeURL
+                (request.getContextPath() + "/status/all");
+            args[8] = sm.getString("statusServlet.complete");
+        }
+        // use StatusTransformer to output status
+        StatusTransformer.writeManager(writer,args,mode);
+
+        // Server Header Section
+        args = new Object[7];
+        args[0] = sm.getString("htmlManagerServlet.serverTitle");
+        args[1] = sm.getString("htmlManagerServlet.serverVersion");
+        args[2] = sm.getString("htmlManagerServlet.serverJVMVersion");
+        args[3] = sm.getString("htmlManagerServlet.serverJVMVendor");
+        args[4] = sm.getString("htmlManagerServlet.serverOSName");
+        args[5] = sm.getString("htmlManagerServlet.serverOSVersion");
+        args[6] = sm.getString("htmlManagerServlet.serverOSArch");
+        // use StatusTransformer to output status
+        StatusTransformer.writePageHeading(writer,args,mode);
+
+        // Server Row Section
+        args = new Object[6];
+        args[0] = ServerInfo.getServerInfo();
+        args[1] = System.getProperty("java.runtime.version");
+        args[2] = System.getProperty("java.vm.vendor");
+        args[3] = System.getProperty("os.name");
+        args[4] = System.getProperty("os.version");
+        args[5] = System.getProperty("os.arch");
+        // use StatusTransformer to output status
+        StatusTransformer.writeServerInfo(writer, args, mode);
+
+        try {
+
+            // Display operating system statistics using APR if available
+            StatusTransformer.writeOSState(writer,mode);
+
+            // Display virtual machine statistics
+            StatusTransformer.writeVMState(writer,mode);
+
+            Enumeration enumeration = threadPools.elements();
+            while (enumeration.hasMoreElements()) {
+                ObjectName objectName = (ObjectName) enumeration.nextElement();
+                String name = objectName.getKeyProperty("name");
+                // use StatusTransformer to output status
+                StatusTransformer.writeConnectorState
+                    (writer, objectName,
+                     name, mBeanServer, globalRequestProcessors,
+                     requestProcessors, mode);
+            }
+
+            if ((request.getPathInfo() != null) 
+                && (request.getPathInfo().equals("/all"))) {
+                // Note: Retrieving the full status is much slower
+                // use StatusTransformer to output status
+                StatusTransformer.writeDetailedState
+                    (writer, mBeanServer, mode);
+            }
+
+        } catch (Exception e) {
+            throw new ServletException(e);
+        }
+
+        // use StatusTransformer to output status
+        StatusTransformer.writeFooter(writer, mode);
+
+    }
+
+    // ------------------------------------------- NotificationListener Methods
+
+
+    public void handleNotification(Notification notification,
+                                   java.lang.Object handback) {
+
+        if (notification instanceof MBeanServerNotification) {
+            ObjectName objectName = 
+                ((MBeanServerNotification) notification).getMBeanName();
+            if (notification.getType().equals
+                (MBeanServerNotification.REGISTRATION_NOTIFICATION)) {
+                String type = objectName.getKeyProperty("type");
+                if (type != null) {
+                    if (type.equals("ProtocolHandler")) {
+                        protocolHandlers.addElement(objectName);
+                    } else if (type.equals("ThreadPool")) {
+                        threadPools.addElement(objectName);
+                    } else if (type.equals("GlobalRequestProcessor")) {
+                        globalRequestProcessors.addElement(objectName);
+                    } else if (type.equals("RequestProcessor")) {
+                        requestProcessors.addElement(objectName);
+                    }
+                }
+            } else if (notification.getType().equals
+                       (MBeanServerNotification.UNREGISTRATION_NOTIFICATION)) {
+                String type = objectName.getKeyProperty("type");
+                if (type != null) {
+                    if (type.equals("ProtocolHandler")) {
+                        protocolHandlers.removeElement(objectName);
+                    } else if (type.equals("ThreadPool")) {
+                        threadPools.removeElement(objectName);
+                    } else if (type.equals("GlobalRequestProcessor")) {
+                        globalRequestProcessors.removeElement(objectName);
+                    } else if (type.equals("RequestProcessor")) {
+                        requestProcessors.removeElement(objectName);
+                    }
+                }
+                String j2eeType = objectName.getKeyProperty("j2eeType");
+                if (j2eeType != null) {
+                    
+                }
+            }
+        }
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/manager/WEB-INF/classes/org/apache/catalina/manager/StatusTransformer.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/manager/WEB-INF/classes/org/apache/catalina/manager/StatusTransformer.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/manager/WEB-INF/classes/org/apache/catalina/manager/StatusTransformer.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,933 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.manager;
+
+import java.io.PrintWriter;
+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.Vector;
+
+import javax.servlet.http.HttpServletResponse;
+import org.apache.catalina.util.RequestUtil;
+import org.apache.tomcat.util.compat.JdkCompat;
+
+import javax.management.MBeanServer;
+import javax.management.ObjectInstance;
+import javax.management.ObjectName;
+
+/**
+ * This is a refactoring of the servlet to externalize
+ * the output into a simple class. Although we could
+ * use XSLT, that is unnecessarily complex.
+ *
+ * @author Peter Lin
+ * @version $Revision: 303967 $ $Date: 2005-06-29 12:31:56 -0500 (Wed, 29 Jun 2005) $
+ */
+
+public class StatusTransformer {
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    public static void setContentType(HttpServletResponse response, 
+                                      int mode) {
+        if (mode == 0){
+            response.setContentType("text/html;charset="+Constants.CHARSET);
+        } else if (mode == 1){
+            response.setContentType("text/xml;charset="+Constants.CHARSET);
+        }
+    }
+
+
+    /**
+     * Process a GET request for the specified resource.
+     *
+     * @param request The servlet request we are processing
+     * @param response The servlet response we are creating
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception ServletException if a servlet-specified error occurs
+     */
+    public static void writeHeader(PrintWriter writer, int mode) {
+        if (mode == 0){
+            // HTML Header Section
+            writer.print(Constants.HTML_HEADER_SECTION);
+        } else if (mode == 1){
+            writer.write(Constants.XML_DECLARATION);
+            writer.write
+                (Constants.XML_STYLE);
+            writer.write("<status>");
+        }
+    }
+
+
+    /**
+     * Write the header body. XML output doesn't bother
+     * to output this stuff, since it's just title.
+     * 
+     * @param writer The output writer
+     * @param args What to write
+     * @param mode 0 means write 
+     */
+    public static void writeBody(PrintWriter writer, Object[] args, int mode) {
+        if (mode == 0){
+            writer.print(MessageFormat.format
+                         (Constants.BODY_HEADER_SECTION, args));
+        }
+    }
+
+
+    /**
+     * Write the manager webapp information.
+     * 
+     * @param writer The output writer
+     * @param args What to write
+     * @param mode 0 means write
+     */
+    public static void writeManager(PrintWriter writer, Object[] args, 
+                                    int mode) {
+        if (mode == 0){
+            writer.print(MessageFormat.format(Constants.MANAGER_SECTION, args));
+        }
+    }
+
+
+    public static void writePageHeading(PrintWriter writer, Object[] args, 
+                                        int mode) {
+        if (mode == 0){
+            writer.print(MessageFormat.format
+                         (Constants.SERVER_HEADER_SECTION, args));
+        }
+    }
+
+
+    public static void writeServerInfo(PrintWriter writer, Object[] args, 
+                                       int mode){
+        if (mode == 0){
+            writer.print(MessageFormat.format(Constants.SERVER_ROW_SECTION, args));
+        }
+    }
+
+
+    /**
+     * 
+     */
+    public static void writeFooter(PrintWriter writer, int mode) {
+        if (mode == 0){
+            // HTML Tail Section
+            writer.print(Constants.HTML_TAIL_SECTION);
+        } else if (mode == 1){
+            writer.write("</status>");
+        }
+    }
+
+
+    /**
+     * Write the OS state. Mode 0 will generate HTML.
+     * Mode 1 will generate XML.
+     */
+    public static void writeOSState(PrintWriter writer, int mode) {
+        long[] result = new long[16];
+        boolean ok = false;
+        try {
+            String methodName = "info";
+            Class paramTypes[] = new Class[1];
+            paramTypes[0] = result.getClass();
+            Object paramValues[] = new Object[1];
+            paramValues[0] = result;
+            Method method = Class.forName("org.apache.tomcat.jni.OS")
+                .getMethod(methodName, paramTypes);
+            method.invoke(null, paramValues);
+            ok = true;
+        } catch (Throwable t) {
+            // Ignore
+        }
+        
+        if (ok) {
+            if (mode == 0){
+                writer.print("<h1>OS</h1>");
+
+                writer.print("<p>");
+                writer.print(" Physical memory: ");
+                writer.print(formatSize(new Long(result[0]), true));
+                writer.print(" Available memory: ");
+                writer.print(formatSize(new Long(result[1]), true));
+                writer.print(" Total page file: ");
+                writer.print(formatSize(new Long(result[2]), true));
+                writer.print(" Free page file: ");
+                writer.print(formatSize(new Long(result[3]), true));
+                writer.print(" Memory load: ");
+                writer.print(new Long(result[6]));
+                writer.print("<br>");
+                writer.print(" Process kernel time: ");
+                writer.print(formatTime(new Long(result[11] / 1000), true));
+                writer.print(" Process user time: ");
+                writer.print(formatTime(new Long(result[12] / 1000), true));
+                writer.print("</p>");
+            } else if (mode == 1){
+            }
+        }
+        
+    }
+    
+    
+    /**
+     * Write the VM state. Mode 0 will generate HTML.
+     * Mode 1 will generate XML.
+     */
+    public static void writeVMState(PrintWriter writer, int mode)
+        throws Exception {
+
+        if (mode == 0){
+            writer.print("<h1>JVM</h1>");
+
+            writer.print("<p>");
+            writer.print(" Free memory: ");
+            writer.print(formatSize
+                         (new Long(Runtime.getRuntime().freeMemory()), true));
+            writer.print(" Total memory: ");
+            writer.print(formatSize
+                         (new Long(Runtime.getRuntime().totalMemory()), true));
+            writer.print(" Max memory: ");
+            writer.print(formatSize
+                         (new Long(JdkCompat.getJdkCompat().getMaxMemory()), 
+                          true));
+            writer.print("</p>");
+        } else if (mode == 1){
+            writer.write("<jvm>");
+
+            writer.write("<memory");
+            writer.write(" free='" + Runtime.getRuntime().freeMemory() + "'");
+            writer.write(" total='" + Runtime.getRuntime().totalMemory() + "'");
+            writer.write(" max='" + JdkCompat.getJdkCompat().getMaxMemory() + "'/>");
+
+            writer.write("</jvm>");
+        }
+
+    }
+
+
+    /**
+     * Write connector state.
+     */
+    public static void writeConnectorState(PrintWriter writer, 
+                                           ObjectName tpName, String name,
+                                           MBeanServer mBeanServer,
+                                           Vector globalRequestProcessors,
+                                           Vector requestProcessors,
+                                           int mode)
+        throws Exception {
+
+        if (mode == 0) {
+            writer.print("<h1>");
+            writer.print(name);
+            writer.print("</h1>");
+
+            writer.print("<p>");
+            writer.print(" Max threads: ");
+            writer.print(mBeanServer.getAttribute(tpName, "maxThreads"));
+            writer.print(" Min spare threads: ");
+            writer.print(mBeanServer.getAttribute(tpName, "minSpareThreads"));
+            writer.print(" Max spare threads: ");
+            writer.print(mBeanServer.getAttribute(tpName, "maxSpareThreads"));
+            writer.print(" Current thread count: ");
+            writer.print(mBeanServer.getAttribute(tpName, "currentThreadCount"));
+            writer.print(" Current thread busy: ");
+            writer.print(mBeanServer.getAttribute(tpName, "currentThreadsBusy"));
+            try {
+                Object value = mBeanServer.getAttribute(tpName, "keepAliveCount");
+                writer.print(" Keeped alive sockets count: ");
+                writer.print(value);
+            } catch (Exception e) {
+                // Ignore
+            }
+            
+            writer.print("<br>");
+
+            ObjectName grpName = null;
+
+            Enumeration enumeration = globalRequestProcessors.elements();
+            while (enumeration.hasMoreElements()) {
+                ObjectName objectName = (ObjectName) enumeration.nextElement();
+                if (name.equals(objectName.getKeyProperty("name"))) {
+                    grpName = objectName;
+                }
+            }
+
+            if (grpName == null) {
+                return;
+            }
+
+            writer.print(" Max processing time: ");
+            writer.print(formatTime(mBeanServer.getAttribute
+                                    (grpName, "maxTime"), false));
+            writer.print(" Processing time: ");
+            writer.print(formatTime(mBeanServer.getAttribute
+                                    (grpName, "processingTime"), true));
+            writer.print(" Request count: ");
+            writer.print(mBeanServer.getAttribute(grpName, "requestCount"));
+            writer.print(" Error count: ");
+            writer.print(mBeanServer.getAttribute(grpName, "errorCount"));
+            writer.print(" Bytes received: ");
+            writer.print(formatSize(mBeanServer.getAttribute
+                                    (grpName, "bytesReceived"), true));
+            writer.print(" Bytes sent: ");
+            writer.print(formatSize(mBeanServer.getAttribute
+                                    (grpName, "bytesSent"), true));
+            writer.print("</p>");
+
+            writer.print("<table border=\"0\"><tr><th>Stage</th><th>Time</th><th>B Sent</th><th>B Recv</th><th>Client</th><th>VHost</th><th>Request</th></tr>");
+
+            enumeration = requestProcessors.elements();
+            while (enumeration.hasMoreElements()) {
+                ObjectName objectName = (ObjectName) enumeration.nextElement();
+                if (name.equals(objectName.getKeyProperty("worker"))) {
+                    writer.print("<tr>");
+                    writeProcessorState(writer, objectName, mBeanServer, mode);
+                    writer.print("</tr>");
+                }
+            }
+
+            writer.print("</table>");
+
+            writer.print("<p>");
+            writer.print("P: Parse and prepare request S: Service F: Finishing R: Ready K: Keepalive");
+            writer.print("</p>");
+        } else if (mode == 1){
+            writer.write("<connector name='" + name + "'>");
+
+            writer.write("<threadInfo ");
+            writer.write(" maxThreads=\"" + mBeanServer.getAttribute(tpName, "maxThreads") + "\"");
+            writer.write(" minSpareThreads=\"" + mBeanServer.getAttribute(tpName, "minSpareThreads") + "\"");
+            writer.write(" maxSpareThreads=\"" + mBeanServer.getAttribute(tpName, "maxSpareThreads") + "\"");
+            writer.write(" currentThreadCount=\"" + mBeanServer.getAttribute(tpName, "currentThreadCount") + "\"");
+            writer.write(" currentThreadsBusy=\"" + mBeanServer.getAttribute(tpName, "currentThreadsBusy") + "\"");
+            writer.write(" />");
+
+            ObjectName grpName = null;
+
+            Enumeration enumeration = globalRequestProcessors.elements();
+            while (enumeration.hasMoreElements()) {
+                ObjectName objectName = (ObjectName) enumeration.nextElement();
+                if (name.equals(objectName.getKeyProperty("name"))) {
+                    grpName = objectName;
+                }
+            }
+
+            if (grpName != null) {
+
+                writer.write("<requestInfo ");
+                writer.write(" maxTime=\"" + mBeanServer.getAttribute(grpName, "maxTime") + "\"");
+                writer.write(" processingTime=\"" + mBeanServer.getAttribute(grpName, "processingTime") + "\"");
+                writer.write(" requestCount=\"" + mBeanServer.getAttribute(grpName, "requestCount") + "\"");
+                writer.write(" errorCount=\"" + mBeanServer.getAttribute(grpName, "errorCount") + "\"");
+                writer.write(" bytesReceived=\"" + mBeanServer.getAttribute(grpName, "bytesReceived") + "\"");
+                writer.write(" bytesSent=\"" + mBeanServer.getAttribute(grpName, "bytesSent") + "\"");
+                writer.write(" />");
+
+                writer.write("<workers>");
+                enumeration = requestProcessors.elements();
+                while (enumeration.hasMoreElements()) {
+                    ObjectName objectName = (ObjectName) enumeration.nextElement();
+                    if (name.equals(objectName.getKeyProperty("worker"))) {
+                        writeProcessorState(writer, objectName, mBeanServer, mode);
+                    }
+                }
+                writer.write("</workers>");
+            }
+
+            writer.write("</connector>");
+        }
+
+    }
+
+
+    /**
+     * Write processor state.
+     */
+    protected static void writeProcessorState(PrintWriter writer, 
+                                              ObjectName pName,
+                                              MBeanServer mBeanServer, 
+                                              int mode)
+        throws Exception {
+
+        Integer stageValue = 
+            (Integer) mBeanServer.getAttribute(pName, "stage");
+        int stage = stageValue.intValue();
+        boolean fullStatus = true;
+        boolean showRequest = true;
+        String stageStr = null;
+
+        switch (stage) {
+
+        case (1/*org.apache.coyote.Constants.STAGE_PARSE*/):
+            stageStr = "P";
+            fullStatus = false;
+            break;
+        case (2/*org.apache.coyote.Constants.STAGE_PREPARE*/):
+            stageStr = "P";
+            fullStatus = false;
+            break;
+        case (3/*org.apache.coyote.Constants.STAGE_SERVICE*/):
+            stageStr = "S";
+            break;
+        case (4/*org.apache.coyote.Constants.STAGE_ENDINPUT*/):
+            stageStr = "F";
+            break;
+        case (5/*org.apache.coyote.Constants.STAGE_ENDOUTPUT*/):
+            stageStr = "F";
+            break;
+        case (7/*org.apache.coyote.Constants.STAGE_ENDED*/):
+            stageStr = "R";
+            fullStatus = false;
+            break;
+        case (6/*org.apache.coyote.Constants.STAGE_KEEPALIVE*/):
+            stageStr = "K";
+            fullStatus = true;
+            showRequest = false;
+            break;
+        case (0/*org.apache.coyote.Constants.STAGE_NEW*/):
+            stageStr = "R";
+            fullStatus = false;
+            break;
+        default:
+            // Unknown stage
+            stageStr = "?";
+            fullStatus = false;
+
+        }
+
+        if (mode == 0) {
+            writer.write("<td><strong>");
+            writer.write(stageStr);
+            writer.write("</strong></td>");
+
+            if (fullStatus) {
+                writer.write("<td>");
+                writer.print(formatTime(mBeanServer.getAttribute
+                                        (pName, "requestProcessingTime"), false));
+                writer.write("</td>");
+                writer.write("<td>");
+                if (showRequest) {
+                    writer.print(formatSize(mBeanServer.getAttribute
+                                            (pName, "requestBytesSent"), false));
+                } else {
+                    writer.write("?");
+                }
+                writer.write("</td>");
+                writer.write("<td>");
+                if (showRequest) {
+                    writer.print(formatSize(mBeanServer.getAttribute
+                                            (pName, "requestBytesReceived"), 
+                                            false));
+                } else {
+                    writer.write("?");
+                }
+                writer.write("</td>");
+                writer.write("<td>");
+                writer.print(filter(mBeanServer.getAttribute
+                                    (pName, "remoteAddr")));
+                writer.write("</td>");
+                writer.write("<td nowrap>");
+                writer.write(filter(mBeanServer.getAttribute
+                                    (pName, "virtualHost")));
+                writer.write("</td>");
+                writer.write("<td nowrap>");
+                if (showRequest) {
+                    writer.write(filter(mBeanServer.getAttribute
+                                        (pName, "method")));
+                    writer.write(" ");
+                    writer.write(filter(mBeanServer.getAttribute
+                                        (pName, "currentUri")));
+                    String queryString = (String) mBeanServer.getAttribute
+                        (pName, "currentQueryString");
+                    if ((queryString != null) && (!queryString.equals(""))) {
+                        writer.write("?");
+                        writer.print(RequestUtil.filter(queryString));
+                    }
+                    writer.write(" ");
+                    writer.write(filter(mBeanServer.getAttribute
+                                        (pName, "protocol")));
+                } else {
+                    writer.write("?");
+                }
+                writer.write("</td>");
+            } else {
+                writer.write("<td>?</td><td>?</td><td>?</td><td>?</td><td>?</td><td>?</td>");
+            }
+        } else if (mode == 1){
+            writer.write("<worker ");
+            writer.write(" stage=\"" + stageStr + "\"");
+
+            if (fullStatus) {
+                writer.write(" requestProcessingTime=\"" 
+                             + mBeanServer.getAttribute
+                             (pName, "requestProcessingTime") + "\"");
+                writer.write(" requestBytesSent=\"");
+                if (showRequest) {
+                    writer.write("" + mBeanServer.getAttribute
+                                 (pName, "requestBytesSent"));
+                } else {
+                    writer.write("0");
+                }
+                writer.write("\"");
+                writer.write(" requestBytesReceived=\"");
+                if (showRequest) {
+                    writer.write("" + mBeanServer.getAttribute
+                                 (pName, "requestBytesReceived"));
+                } else {
+                    writer.write("0");
+                }
+                writer.write("\"");
+                writer.write(" remoteAddr=\"" 
+                             + filter(mBeanServer.getAttribute
+                                      (pName, "remoteAddr")) + "\"");
+                writer.write(" virtualHost=\"" 
+                             + filter(mBeanServer.getAttribute
+                                      (pName, "virtualHost")) + "\"");
+
+                if (showRequest) {
+                    writer.write(" method=\"" 
+                                 + filter(mBeanServer.getAttribute
+                                          (pName, "method")) + "\"");
+                    writer.write(" currentUri=\"" 
+                                 + filter(mBeanServer.getAttribute
+                                          (pName, "currentUri")) + "\"");
+
+                    String queryString = (String) mBeanServer.getAttribute
+                        (pName, "currentQueryString");
+                    if ((queryString != null) && (!queryString.equals(""))) {
+                        writer.write(" currentQueryString=\"" 
+                                     + RequestUtil.filter(queryString) + "\"");
+                    } else {
+                        writer.write(" currentQueryString=\"&#63;\"");
+                    }
+                    writer.write(" protocol=\"" 
+                                 + filter(mBeanServer.getAttribute
+                                          (pName, "protocol")) + "\"");
+                } else {
+                    writer.write(" method=\"&#63;\"");
+                    writer.write(" currentUri=\"&#63;\"");
+                    writer.write(" currentQueryString=\"&#63;\"");
+                    writer.write(" protocol=\"&#63;\"");
+                }
+            } else {
+                writer.write(" requestProcessingTime=\"0\"");
+                writer.write(" requestBytesSent=\"0\"");
+                writer.write(" requestBytesRecieved=\"0\"");
+                writer.write(" remoteAddr=\"&#63;\"");
+                writer.write(" virtualHost=\"&#63;\"");
+                writer.write(" method=\"&#63;\"");
+                writer.write(" currentUri=\"&#63;\"");
+                writer.write(" currentQueryString=\"&#63;\"");
+                writer.write(" protocol=\"&#63;\"");
+            }
+            writer.write(" />");
+        }
+
+    }
+
+
+    /**
+     * Write applications state.
+     */
+    public static void writeDetailedState(PrintWriter writer,
+                                          MBeanServer mBeanServer, int mode)
+        throws Exception {
+
+        if (mode == 0){
+            ObjectName queryHosts = new ObjectName("*:j2eeType=WebModule,*");
+            Set hostsON = mBeanServer.queryNames(queryHosts, null);
+
+            // Navigation menu
+            writer.print("<h1>");
+            writer.print("Application list");
+            writer.print("</h1>");
+
+            writer.print("<p>");
+            int count = 0;
+            Iterator iterator = hostsON.iterator();
+            while (iterator.hasNext()) {
+                ObjectName contextON = (ObjectName) iterator.next();
+                String webModuleName = contextON.getKeyProperty("name");
+                if (webModuleName.startsWith("//")) {
+                    webModuleName = webModuleName.substring(2);
+                }
+                int slash = webModuleName.indexOf("/");
+                if (slash == -1) {
+                    count++;
+                    continue;
+                }
+
+                writer.print("<a href=\"#" + (count++) + ".0\">");
+                writer.print(webModuleName);
+                writer.print("</a>");
+                if (iterator.hasNext()) {
+                    writer.print("<br>");
+                }
+
+            }
+            writer.print("</p>");
+
+            // Webapp list
+            count = 0;
+            iterator = hostsON.iterator();
+            while (iterator.hasNext()) {
+                ObjectName contextON = (ObjectName) iterator.next();
+                writer.print("<a class=\"A.name\" name=\"" 
+                             + (count++) + ".0\">");
+                writeContext(writer, contextON, mBeanServer, mode);
+            }
+
+        } else if (mode == 1){
+            // for now we don't write out the Detailed state in XML
+        }
+
+    }
+
+
+    /**
+     * Write context state.
+     */
+    protected static void writeContext(PrintWriter writer, 
+                                       ObjectName objectName,
+                                       MBeanServer mBeanServer, int mode)
+        throws Exception {
+
+        if (mode == 0){
+            String webModuleName = objectName.getKeyProperty("name");
+            String name = webModuleName;
+            if (name == null) {
+                return;
+            }
+            
+            String hostName = null;
+            String contextName = null;
+            if (name.startsWith("//")) {
+                name = name.substring(2);
+            }
+            int slash = name.indexOf("/");
+            if (slash != -1) {
+                hostName = name.substring(0, slash);
+                contextName = name.substring(slash);
+            } else {
+                return;
+            }
+
+            ObjectName queryManager = new ObjectName
+                (objectName.getDomain() + ":type=Manager,path=" + contextName 
+                 + ",host=" + hostName + ",*");
+            Set managersON = mBeanServer.queryNames(queryManager, null);
+            ObjectName managerON = null;
+            Iterator iterator2 = managersON.iterator();
+            while (iterator2.hasNext()) {
+                managerON = (ObjectName) iterator2.next();
+            }
+
+            ObjectName queryJspMonitor = new ObjectName
+                (objectName.getDomain() + ":type=JspMonitor,WebModule=" +
+                 webModuleName + ",*");
+            Set jspMonitorONs = mBeanServer.queryNames(queryJspMonitor, null);
+
+            // Special case for the root context
+            if (contextName.equals("/")) {
+                contextName = "";
+            }
+
+            writer.print("<h1>");
+            writer.print(name);
+            writer.print("</h1>");
+            writer.print("</a>");
+
+            writer.print("<p>");
+            Object startTime = mBeanServer.getAttribute(objectName,
+                                                        "startTime");
+            writer.print(" Start time: " +
+                         new Date(((Long) startTime).longValue()));
+            writer.print(" Startup time: ");
+            writer.print(formatTime(mBeanServer.getAttribute
+                                    (objectName, "startupTime"), false));
+            writer.print(" TLD scan time: ");
+            writer.print(formatTime(mBeanServer.getAttribute
+                                    (objectName, "tldScanTime"), false));
+            if (managerON != null) {
+                writeManager(writer, managerON, mBeanServer, mode);
+            }
+            if (jspMonitorONs != null) {
+                writeJspMonitor(writer, jspMonitorONs, mBeanServer, mode);
+            }
+            writer.print("</p>");
+
+            String onStr = objectName.getDomain() 
+                + ":j2eeType=Servlet,WebModule=" + webModuleName + ",*";
+            ObjectName servletObjectName = new ObjectName(onStr);
+            Set set = mBeanServer.queryMBeans(servletObjectName, null);
+            Iterator iterator = set.iterator();
+            while (iterator.hasNext()) {
+                ObjectInstance oi = (ObjectInstance) iterator.next();
+                writeWrapper(writer, oi.getObjectName(), mBeanServer, mode);
+            }
+
+        } else if (mode == 1){
+            // for now we don't write out the context in XML
+        }
+
+    }
+
+
+    /**
+     * Write detailed information about a manager.
+     */
+    public static void writeManager(PrintWriter writer, ObjectName objectName,
+                                    MBeanServer mBeanServer, int mode)
+        throws Exception {
+
+        if (mode == 0) {
+            writer.print("<br>");
+            writer.print(" Active sessions: ");
+            writer.print(mBeanServer.getAttribute
+                         (objectName, "activeSessions"));
+            writer.print(" Session count: ");
+            writer.print(mBeanServer.getAttribute
+                         (objectName, "sessionCounter"));
+            writer.print(" Max active sessions: ");
+            writer.print(mBeanServer.getAttribute(objectName, "maxActive"));
+            writer.print(" Rejected session creations: ");
+            writer.print(mBeanServer.getAttribute
+                         (objectName, "rejectedSessions"));
+            writer.print(" Expired sessions: ");
+            writer.print(mBeanServer.getAttribute
+                         (objectName, "expiredSessions"));
+            writer.print(" Longest session alive time: ");
+            writer.print(formatSeconds(mBeanServer.getAttribute(
+                                                    objectName,
+                                                    "sessionMaxAliveTime")));
+            writer.print(" Average session alive time: ");
+            writer.print(formatSeconds(mBeanServer.getAttribute(
+                                                    objectName,
+                                                    "sessionAverageAliveTime")));
+            writer.print(" Processing time: ");
+            writer.print(formatTime(mBeanServer.getAttribute
+                                    (objectName, "processingTime"), false));
+        } else if (mode == 1) {
+            // for now we don't write out the wrapper details
+        }
+
+    }
+
+
+    /**
+     * Write JSP monitoring information.
+     */
+    public static void writeJspMonitor(PrintWriter writer,
+                                       Set jspMonitorONs,
+                                       MBeanServer mBeanServer,
+                                       int mode)
+            throws Exception {
+
+        int jspCount = 0;
+        int jspReloadCount = 0;
+
+        Iterator iter = jspMonitorONs.iterator();
+        while (iter.hasNext()) {
+            ObjectName jspMonitorON = (ObjectName) iter.next();
+            Object obj = mBeanServer.getAttribute(jspMonitorON, "jspCount");
+            jspCount += ((Integer) obj).intValue();
+            obj = mBeanServer.getAttribute(jspMonitorON, "jspReloadCount");
+            jspReloadCount += ((Integer) obj).intValue();
+        }
+
+        if (mode == 0) {
+            writer.print("<br>");
+            writer.print(" JSPs loaded: ");
+            writer.print(jspCount);
+            writer.print(" JSPs reloaded: ");
+            writer.print(jspReloadCount);
+        } else if (mode == 1) {
+            // for now we don't write out anything
+        }
+    }
+
+
+    /**
+     * Write detailed information about a wrapper.
+     */
+    public static void writeWrapper(PrintWriter writer, ObjectName objectName,
+                                    MBeanServer mBeanServer, int mode)
+        throws Exception {
+
+        if (mode == 0) {
+            String servletName = objectName.getKeyProperty("name");
+            
+            String[] mappings = (String[]) 
+                mBeanServer.invoke(objectName, "findMappings", null, null);
+            
+            writer.print("<h2>");
+            writer.print(servletName);
+            if ((mappings != null) && (mappings.length > 0)) {
+                writer.print(" [ ");
+                for (int i = 0; i < mappings.length; i++) {
+                    writer.print(mappings[i]);
+                    if (i < mappings.length - 1) {
+                        writer.print(" , ");
+                    }
+                }
+                writer.print(" ] ");
+            }
+            writer.print("</h2>");
+            
+            writer.print("<p>");
+            writer.print(" Processing time: ");
+            writer.print(formatTime(mBeanServer.getAttribute
+                                    (objectName, "processingTime"), true));
+            writer.print(" Max time: ");
+            writer.print(formatTime(mBeanServer.getAttribute
+                                    (objectName, "maxTime"), false));
+            writer.print(" Request count: ");
+            writer.print(mBeanServer.getAttribute(objectName, "requestCount"));
+            writer.print(" Error count: ");
+            writer.print(mBeanServer.getAttribute(objectName, "errorCount"));
+            writer.print(" Load time: ");
+            writer.print(formatTime(mBeanServer.getAttribute
+                                    (objectName, "loadTime"), false));
+            writer.print(" Classloading time: ");
+            writer.print(formatTime(mBeanServer.getAttribute
+                                    (objectName, "classLoadTime"), false));
+            writer.print("</p>");
+        } else if (mode == 1){
+            // for now we don't write out the wrapper details
+        }
+
+    }
+
+
+    /**
+     * Filter the specified message string for characters that are sensitive
+     * in HTML.  This avoids potential attacks caused by including JavaScript
+     * codes in the request URL that is often reported in error messages.
+     *
+     * @param obj The message string to be filtered
+     */
+    public static String filter(Object obj) {
+
+        if (obj == null)
+            return ("?");
+        String message = obj.toString();
+
+        char content[] = new char[message.length()];
+        message.getChars(0, message.length(), content, 0);
+        StringBuffer result = new StringBuffer(content.length + 50);
+        for (int i = 0; i < content.length; i++) {
+            switch (content[i]) {
+            case '<':
+                result.append("&lt;");
+                break;
+            case '>':
+                result.append("&gt;");
+                break;
+            case '&':
+                result.append("&amp;");
+                break;
+            case '"':
+                result.append("&quot;");
+                break;
+            default:
+                result.append(content[i]);
+            }
+        }
+        return (result.toString());
+
+    }
+
+
+    /**
+     * Display the given size in bytes, either as KB or MB.
+     *
+     * @param mb true to display megabytes, false for kilobytes
+     */
+    public static String formatSize(Object obj, boolean mb) {
+
+        long bytes = -1L;
+
+        if (obj instanceof Long) {
+            bytes = ((Long) obj).longValue();
+        } else if (obj instanceof Integer) {
+            bytes = ((Integer) obj).intValue();
+        }
+
+        if (mb) {
+            long mbytes = bytes / (1024 * 1024);
+            long rest = 
+                ((bytes - (mbytes * (1024 * 1024))) * 100) / (1024 * 1024);
+            return (mbytes + "." + ((rest < 10) ? "0" : "") + rest + " MB");
+        } else {
+            return ((bytes / 1024) + " KB");
+        }
+
+    }
+
+
+    /**
+     * Display the given time in ms, either as ms or s.
+     *
+     * @param seconds true to display seconds, false for milliseconds
+     */
+    public static String formatTime(Object obj, boolean seconds) {
+
+        long time = -1L;
+
+        if (obj instanceof Long) {
+            time = ((Long) obj).longValue();
+        } else if (obj instanceof Integer) {
+            time = ((Integer) obj).intValue();
+        }
+
+        if (seconds) {
+            return ((((float) time ) / 1000) + " s");
+        } else {
+            return (time + " ms");
+        }
+    }
+
+
+    /**
+     * Formats the given time (given in seconds) as a string.
+     *
+     * @param obj Time object to be formatted as string
+     *
+     * @return String formatted time
+     */
+    public static String formatSeconds(Object obj) {
+
+        long time = -1L;
+
+        if (obj instanceof Long) {
+            time = ((Long) obj).longValue();
+        } else if (obj instanceof Integer) {
+            time = ((Integer) obj).intValue();
+        }
+
+        return (time + " s");
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/manager/WEB-INF/web.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/manager/WEB-INF/web.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/manager/WEB-INF/web.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,186 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!--
+  Copyright 2004 The Apache Software Foundation
+
+  Licensed 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.
+-->
+
+<web-app 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-app_2_4.xsd"
+    version="2.4">
+
+  <display-name>Tomcat Manager Application</display-name>
+  <description>
+    A scriptable management web application for the Tomcat Web Server;
+	Manager lets you view, load/unload/etc particular web applications.
+  </description>
+
+  <!-- Define the Manager Servlet
+       Change servlet-class to: org.apache.catalina.servlets.HTMLManagerServlet
+       to get a Servlet with a more intuitive HTML interface, don't change if you
+       have software that is expected to parse the output from ManagerServlet
+       since they're not compatible.
+   -->
+  <servlet>
+    <servlet-name>Manager</servlet-name>
+    <servlet-class>org.apache.catalina.manager.ManagerServlet</servlet-class>
+    <init-param>
+      <param-name>debug</param-name>
+      <param-value>2</param-value>
+    </init-param>
+  </servlet>
+  <servlet>
+    <servlet-name>HTMLManager</servlet-name>
+    <servlet-class>org.apache.catalina.manager.HTMLManagerServlet</servlet-class>
+    <init-param>
+      <param-name>debug</param-name>
+      <param-value>2</param-value>
+    </init-param>
+  </servlet>
+  <servlet>
+    <servlet-name>Status</servlet-name>
+    <servlet-class>org.apache.catalina.manager.StatusManagerServlet</servlet-class>
+    <init-param>
+      <param-name>debug</param-name>
+      <param-value>0</param-value>
+    </init-param>
+  </servlet>
+
+  <servlet>
+    <servlet-name>JMXProxy</servlet-name>
+    <servlet-class>org.apache.catalina.manager.JMXProxyServlet</servlet-class>
+  </servlet>
+
+  <!-- Define the Manager Servlet Mapping -->
+  <servlet-mapping>
+    <servlet-name>Manager</servlet-name>
+      <url-pattern>/list</url-pattern>
+  </servlet-mapping>
+  <servlet-mapping>
+    <servlet-name>Manager</servlet-name>
+      <url-pattern>/sessions</url-pattern>
+  </servlet-mapping>
+  <servlet-mapping>
+    <servlet-name>Manager</servlet-name>
+      <url-pattern>/start</url-pattern>
+  </servlet-mapping>
+  <servlet-mapping>
+    <servlet-name>Manager</servlet-name>
+      <url-pattern>/stop</url-pattern>
+  </servlet-mapping>
+  <servlet-mapping>
+    <servlet-name>Manager</servlet-name>
+      <url-pattern>/install</url-pattern>
+  </servlet-mapping>
+  <servlet-mapping>
+    <servlet-name>Manager</servlet-name>
+      <url-pattern>/remove</url-pattern>
+  </servlet-mapping>
+  <servlet-mapping>
+    <servlet-name>Manager</servlet-name>
+      <url-pattern>/deploy</url-pattern>
+  </servlet-mapping>
+  <servlet-mapping>
+    <servlet-name>Manager</servlet-name>
+      <url-pattern>/undeploy</url-pattern>
+  </servlet-mapping>
+  <servlet-mapping>
+    <servlet-name>Manager</servlet-name>
+      <url-pattern>/reload</url-pattern>
+  </servlet-mapping>
+  <servlet-mapping>
+    <servlet-name>Manager</servlet-name>
+      <url-pattern>/save</url-pattern>
+  </servlet-mapping>
+  <servlet-mapping>
+    <servlet-name>Manager</servlet-name>
+      <url-pattern>/serverinfo</url-pattern>
+  </servlet-mapping>
+  <servlet-mapping>
+    <servlet-name>Manager</servlet-name>
+      <url-pattern>/roles</url-pattern>
+  </servlet-mapping>
+  <servlet-mapping>
+    <servlet-name>Manager</servlet-name>
+      <url-pattern>/resources</url-pattern>
+  </servlet-mapping>
+  <servlet-mapping>
+    <servlet-name>Status</servlet-name>
+    <url-pattern>/status/*</url-pattern>
+  </servlet-mapping>
+  <servlet-mapping>
+    <servlet-name>JMXProxy</servlet-name>
+      <url-pattern>/jmxproxy/*</url-pattern>
+  </servlet-mapping>
+  <servlet-mapping>
+    <servlet-name>HTMLManager</servlet-name>
+    <url-pattern>/html/*</url-pattern>
+  </servlet-mapping>
+
+  <!-- Define reference to the user database for looking up roles -->
+  <resource-env-ref>
+    <description>
+      Link to the UserDatabase instance from which we request lists of
+      defined role names.  Typically, this will be connected to the global
+      user database with a ResourceLink element in server.xml or the context
+      configuration file for the Manager web application.
+    </description>
+    <resource-env-ref-name>users</resource-env-ref-name>
+    <resource-env-ref-type>
+      org.apache.catalina.UserDatabase
+    </resource-env-ref-type>
+  </resource-env-ref>
+
+  <!-- Define a Security Constraint on this Application -->
+  <security-constraint>
+    <web-resource-collection>
+      <web-resource-name>HTMLManger and Manager command</web-resource-name>
+      <url-pattern>/jmxproxy/*</url-pattern>
+      <url-pattern>/html/*</url-pattern>
+      <url-pattern>/list</url-pattern>
+      <url-pattern>/sessions</url-pattern>
+      <url-pattern>/start</url-pattern>
+      <url-pattern>/stop</url-pattern>
+      <url-pattern>/install</url-pattern>
+      <url-pattern>/remove</url-pattern>
+      <url-pattern>/deploy</url-pattern>
+      <url-pattern>/undeploy</url-pattern>
+      <url-pattern>/reload</url-pattern>
+      <url-pattern>/save</url-pattern>
+      <url-pattern>/serverinfo</url-pattern>
+      <url-pattern>/status/*</url-pattern>
+      <url-pattern>/roles</url-pattern>
+      <url-pattern>/resources</url-pattern>
+    </web-resource-collection>
+    <auth-constraint>
+       <!-- NOTE:  This role is not present in the default users file -->
+       <role-name>manager</role-name>
+    </auth-constraint>
+  </security-constraint>
+
+  <!-- Define the Login Configuration for this Application -->
+  <login-config>
+    <auth-method>BASIC</auth-method>
+    <realm-name>Tomcat Manager Application</realm-name>
+  </login-config>
+
+  <!-- Security roles referenced by this web application -->
+  <security-role>
+    <description>
+      The role that is required to log in to the Manager Application
+    </description>
+    <role-name>manager</role-name>
+  </security-role>
+
+</web-app>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/manager/build.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/manager/build.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/manager/build.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,129 @@
+<project name="manager" default="build-main" basedir=".">
+
+
+  <!-- ===================== Initialize Property Values =================== -->
+
+  <!-- See "build.properties.sample" in the top level directory for all     -->
+  <!-- property values you must customize for successful building!!!        -->
+  <property file="build.properties"/>
+  <property file="../build.properties"/>
+  <property file="../../build.properties"/>
+  <property file="${user.home}/build.properties"/>
+
+  <property name="build.compiler"  value="modern"/>
+  <property name="webapps.build"   value="../build"/>
+  <property name="webapps.dist"    value="../dist"/>
+  <property name="webapp.name"     value="manager"/>
+
+  <!-- Dependent JARs and files -->
+  <property name="servlet-api.jar" value="${api.home}/jsr154/dist/lib/servlet-api.jar"/>
+  <property name="jsp-api.jar"     value="${api.home}/jsr152/dist/lib/jsp-api.jar"/>
+
+  <!-- Construct Admin classpath -->
+  <path id="manager.classpath">
+    <pathelement location="${catalina.deploy}/classes"/>
+    <pathelement location="${commons-fileupload.jar}"/>
+    <pathelement location="${commons-logging.jar}"/>   
+    <pathelement location="${commons-modeler.jar}"/>
+    <pathelement location="${jmx.jar}"/>
+    <pathelement location="${servlet-api.jar}"/>
+    <pathelement location="${jsp-api.jar}"/>
+  </path>
+
+
+	  <!-- ======================== BUILD: Copy JARs ========================== -->
+	  <target name="copy-fileupload.jar">
+	    <copy todir="${webapps.build}/${webapp.name}/WEB-INF/lib" file="${commons-fileupload.jar}"/>
+	  </target>
+
+
+  <!-- =================== BUILD: Create Directories ====================== -->
+  <target name="build-prepare">
+    <mkdir dir="${webapps.build}"/>
+    <mkdir dir="${webapps.build}/${webapp.name}"/>
+    <mkdir dir="${webapps.build}/${webapp.name}/images"/>
+    <mkdir dir="${webapps.build}/${webapp.name}/WEB-INF"/>
+    <mkdir dir="${webapps.build}/${webapp.name}/WEB-INF/classes"/>
+  </target>
+
+
+  <!-- ================ BUILD: Copy Static Files ========================== -->
+  <target name="build-static" depends="build-prepare,copy-fileupload.jar">
+    <copy todir="${webapps.build}/${webapp.name}">
+      <fileset dir=".">
+        <exclude name="build.*"/>
+      </fileset>
+    </copy>
+  </target>
+
+
+  <!-- ================= BUILD: Compile Server Components ================= -->
+  <target name="build-main" depends="build-static">
+
+    <!-- Top Level Directory -->
+    <style basedir="../docs"
+           destdir="${webapps.build}/${webapp.name}"
+           extension=".html"
+           style="tomcat-docs.xsl"
+           excludes="build.xml project.xml"
+           includes="manager-howto.xml,html-manager-howto.xml">
+      <param name="relative-path" expression="."/>
+      <param name="project-menu" expression="nomenu"/>
+      <param name="standalone" expression="standalone"/>
+    </style>
+
+    <!-- Images Subdirectory -->
+    <copy todir="${webapps.build}/${webapp.name}/images">
+      <fileset dir="../docs/images">
+        <exclude name="printer.gif"/>
+      </fileset>
+    </copy>
+
+    <javac   srcdir="WEB-INF/classes" 
+             destdir="${webapps.build}/${webapp.name}/WEB-INF/classes"
+             debug="${compile.debug}" deprecation="${compile.deprecation}"
+             optimize="${compile.optimize}"
+             excludes="**/CVS/**">
+      <classpath refid="manager.classpath" />
+    </javac>
+
+  </target>
+
+
+  <!-- ==================== BUILD: Rebuild Everything ===================== -->
+  <target name="all" depends="build-clean,build-main"
+   description="Clean and build manager webapp"/>
+
+
+  <!-- ======================= BUILD: Clean Directory ===================== -->
+  <target name="build-clean">
+    <delete dir="${webapps.build}/${webapp.name}"/>
+  </target>
+
+
+  <!-- ======================= DIST: Create Directories =================== -->
+  <target name="dist-prepare">
+    <mkdir dir="${webapps.dist}"/>
+  </target>
+
+
+  <!-- ======================= DIST: Create Distribution Files ============ -->
+  <target name="dist" depends="build-main,dist-prepare"
+   description="Create manager webapp binary distribution">
+      <jar   jarfile="${webapps.dist}/${webapp.name}.war"
+             basedir="${webapps.build}/${webapp.name}" includes="**"/>
+  </target>
+
+
+  <!-- ======================= DIST: Clean Directory ====================== -->
+  <target name="dist-clean">
+    <deltree dir="${dist.dir}/${webapp.name}"/>
+  </target>
+
+
+  <!-- ====================== Convenient Synonyms ========================= -->
+  <target name="clean" depends="build-clean,dist-clean"
+   description="Clean build and dist directories"/>
+
+
+</project>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/manager/manager.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/manager/manager.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/manager/manager.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,17 @@
+<!--
+
+    Context configuration file for the Tomcat Manager Web App
+
+    $Id: manager.xml 303123 2004-08-26 17:03:35Z remm $
+
+-->
+
+
+<Context docBase="${catalina.home}/server/webapps/manager"
+         privileged="true" antiResourceLocking="false" antiJARLocking="false">
+
+  <!-- Link to the user database we will get roles from -->
+  <ResourceLink name="users" global="UserDatabase"
+                type="org.apache.catalina.UserDatabase"/>
+
+</Context>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/manager/status.xsd
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/manager/status.xsd	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/manager/status.xsd	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- edited with XMLSPY v5 rel. 4 U (http://www.xmlspy.com) by peter lin (consultant) -->
+<!--W3C Schema generated by XMLSPY v5 rel. 4 U (http://www.xmlspy.com)-->
+<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
+	<xs:complexType name="connector">
+		<xs:sequence>
+			<xs:element name="threadInfo" type="threadInfo"/>
+			<xs:element name="requestInfo" type="requestInfo"/>
+			<xs:element name="workers" type="workers"/>
+		</xs:sequence>
+		<xs:attribute name="name" type="xs:string" use="required"/>
+	</xs:complexType>
+	<xs:complexType name="jvm">
+		<xs:sequence>
+			<xs:element name="memory" type="memory"/>
+		</xs:sequence>
+	</xs:complexType>
+	<xs:complexType name="memory">
+		<xs:attribute name="free" type="xs:long" use="required"/>
+		<xs:attribute name="total" type="xs:long" use="required"/>
+		<xs:attribute name="max" type="xs:long" use="required"/>
+	</xs:complexType>
+	<xs:complexType name="requestInfo">
+		<xs:attribute name="maxTime" type="xs:long" use="required"/>
+		<xs:attribute name="processingTime" type="xs:int" use="required"/>
+		<xs:attribute name="requestCount" type="xs:long" use="required"/>
+		<xs:attribute name="errorCount" type="xs:long" use="required"/>
+		<xs:attribute name="bytesReceived" type="xs:long" use="required"/>
+		<xs:attribute name="bytesSent" type="xs:long" use="required"/>
+	</xs:complexType>
+	<xs:element name="status">
+		<xs:complexType>
+			<xs:sequence>
+				<xs:element name="jvm" type="jvm"/>
+				<xs:element name="connector" type="connector"/>
+			</xs:sequence>
+		</xs:complexType>
+	</xs:element>
+	<xs:complexType name="threadInfo">
+		<xs:attribute name="maxThreads" type="xs:int" use="required"/>
+		<xs:attribute name="minSpareThreads" type="xs:int" use="required"/>
+		<xs:attribute name="maxSpareThreads" type="xs:int" use="required"/>
+		<xs:attribute name="currentThreadCount" type="xs:int" use="required"/>
+		<xs:attribute name="currentThreadsBusy" type="xs:int" use="required"/>
+	</xs:complexType>
+	<xs:complexType name="worker">
+		<xs:attribute name="stage" type="xs:string" use="required"/>
+		<xs:attribute name="requestProcessingTime" type="xs:int" use="required"/>
+		<xs:attribute name="requestBytesSent" type="xs:long" use="required"/>
+		<xs:attribute name="requestBytesRecieved" type="xs:long" use="required"/>
+		<xs:attribute name="remoteAddr" type="xs:string" use="required"/>
+		<xs:attribute name="virtualHost" type="xs:string" use="required"/>
+		<xs:attribute name="method" type="xs:string" use="required"/>
+		<xs:attribute name="currentUri" type="xs:string" use="required"/>
+		<xs:attribute name="currentQueryString" type="xs:string" use="required"/>
+		<xs:attribute name="protocol" type="xs:string" use="required"/>
+	</xs:complexType>
+	<xs:complexType name="workers">
+		<xs:sequence>
+			<xs:element name="worker" type="worker"/>
+		</xs:sequence>
+	</xs:complexType>
+</xs:schema>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/manager/xform.xsl
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/manager/xform.xsl	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/manager/xform.xsl	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,96 @@
+<?xml version="1.0"?>
+
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+  version="1.0">
+
+  <!-- Output method -->
+  <xsl:output encoding="iso-8859-1"
+              indent="no"/>
+
+  <xsl:template match="status">
+    <html>
+    <head>
+    	<TITLE>Tomcat Status</TITLE>
+		<STYLE type="text/css">
+			body, table, tr, td, a, div, span {
+				vertical-align : top;
+			}
+		</STYLE>
+    </head>
+    <body>
+      <div style='font-size:20px;'>Tomcat Status</div>
+
+      <xsl:apply-templates select="jvm"/>
+      <xsl:apply-templates select="connector"/>
+     </body>
+    </html>
+  </xsl:template>
+
+  <xsl:template match="jvm">
+   <xsl:apply-templates select="memory"/>
+  </xsl:template>
+
+  <xsl:template match="memory">
+    <table><tr>
+    		 <td><b>JVM:</b></td>
+    		 <td><b>free:</b> <xsl:value-of select="@free"/></td>
+    		 <td><b>total:</b> <xsl:value-of select="@total"/></td>
+    		 <td><b>max:</b> <xsl:value-of select="@max"/></td>
+    	   </tr>
+    </table><hr />
+  </xsl:template>
+
+  <xsl:template match="connector">
+	 <b>Connector -- </b> <xsl:value-of select="@name"/><br />
+
+  	<xsl:apply-templates select="threadInfo"/>
+  	<xsl:apply-templates select="requestInfo"/>
+  	<xsl:apply-templates select="workers"/>
+  </xsl:template>
+
+  <xsl:template match="threadInfo">
+    <table><tr>
+    		 <td><b>threadInfo </b></td>
+    		 <td><b>maxThreads:</b> <xsl:value-of select="@maxThreads"/></td>
+    		 <td><b>minSpareThreads:</b> <xsl:value-of select="@minSpareThreads"/></td>
+    		 <td><b>maxSpareThreads:</b> <xsl:value-of select="@maxSpareThreads"/></td>
+    		 <td><b>currentThreadCount:</b> <xsl:value-of select="@currentThreadCount"/></td>
+    		 <td><b>currentThreadsBusy:</b> <xsl:value-of select="@currentThreadsBusy"/></td>
+    	   </tr>
+    </table><hr />
+  </xsl:template>
+
+  <xsl:template match="requestInfo">
+    <table><tr>
+    		 <td><b>requestInfo </b></td>
+    		 <td><b>maxTime:</b> <xsl:value-of select="@maxTime"/></td>
+    		 <td><b>processingTime:</b> <xsl:value-of select="@processingTime"/></td>
+    		 <td><b>requestCount:</b> <xsl:value-of select="@requestCount"/></td>
+    		 <td><b>errorCount:</b> <xsl:value-of select="@errorCount"/></td>
+    		 <td><b>bytesReceived:</b> <xsl:value-of select="@bytesReceived"/></td>
+    		 <td><b>bytesSent:</b> <xsl:value-of select="@bytesSent"/></td>
+    	   </tr>
+    </table><hr />
+  </xsl:template>
+
+  <xsl:template match="workers">
+   <table>
+    <tr><th>Stage</th><th>Time</th><th>B Sent</th><th>B Recv</th><th>Client</th><th>VHost</th><th>Request</th></tr>
+  	<xsl:apply-templates select="worker"/>
+
+   </table><hr />
+  </xsl:template>
+
+  <xsl:template match="worker">
+   <tr>
+    <td><xsl:value-of select="@stage"/></td>
+    <td><xsl:value-of select="@requestProcessingTime"/></td>
+    <td><xsl:value-of select="@requestBytesSent"/></td>
+    <td><xsl:value-of select="@requestBytesReceived"/></td>
+    <td><xsl:value-of select="@remoteAddr"/></td>
+    <td><xsl:value-of select="@virtualHost"/></td>
+    <td><xsl:value-of select="@method"/> <xsl:value-of select="@currentUri"/>?<xsl:value-of select="@currentQueryString"/> <xsl:value-of select="@protocol"/></td>
+   </tr>
+  </xsl:template>
+
+</xsl:stylesheet>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/webdav/WEB-INF/web.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/webdav/WEB-INF/web.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/webdav/WEB-INF/web.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,91 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!--
+  Copyright 2004 The Apache Software Foundation
+
+  Licensed 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.
+-->
+
+<web-app 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-app_2_4.xsd"
+    version="2.4">
+
+  <display-name>Webdav Content Management</display-name>
+  <description>
+     Webdav Content Management
+  </description>
+
+  <servlet>
+    <servlet-name>webdav</servlet-name>
+    <servlet-class>org.apache.catalina.servlets.WebdavServlet</servlet-class>
+    <init-param>
+      <param-name>debug</param-name>
+      <param-value>0</param-value>
+    </init-param>
+    <init-param>
+      <param-name>listings</param-name>
+      <param-value>true</param-value>
+    </init-param>
+    <!-- Uncomment this to enable read and write access -->
+<!--
+    <init-param>
+      <param-name>readonly</param-name>
+      <param-value>false</param-value>
+    </init-param>
+-->
+    <!--load-on-startup>1</load-on-startup-->
+  </servlet>
+
+  <!-- The mapping for the webdav servlet -->
+  <!-- Using /* as the mapping ensures that jasper, welcome files etc are
+       over-ridden and all requests are processed by the webdav servlet.
+       This also overcomes a number of issues with some webdav clients
+       (including MS Webfolders) that do not respond correctly
+ to the
+       redirects (302) that result from using a mapping of / -->
+  <servlet-mapping>
+    <servlet-name>webdav</servlet-name>
+    <url-pattern>/*</url-pattern>
+  </servlet-mapping>
+
+  <!-- ================ Security Constraints for Testing =============== -->
+
+<!--
+  <security-constraint>
+    <web-resource-collection>
+      <web-resource-name>The Entire Web Application</web-resource-name>
+      <url-pattern>/*</url-pattern>
+    </web-resource-collection>
+    <auth-constraint>
+      <role-name>tomcat</role-name>
+    </auth-constraint>
+  </security-constraint>
+
+  <login-config>
+    <auth-method>BASIC</auth-method>
+    <realm-name>Tomcat Supported Realm</realm-name>
+  </login-config>
+
+  <security-role>
+    <description>
+      An example role defined in "conf/tomcat-users.xml"
+    </description>
+    <role-name>tomcat</role-name>
+  </security-role>
+-->
+
+  <welcome-file-list>
+    <welcome-file/>
+  </welcome-file-list>  
+
+</web-app>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/webdav/build.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/webdav/build.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/webdav/build.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,77 @@
+<project name="webdav" default="build-main" basedir=".">
+
+
+  <!-- ===================== Initialize Property Values =================== -->
+
+  <!-- See "build.properties.sample" in the top level directory for all     -->
+  <!-- property values you must customize for successful building!!!        -->
+  <property file="build.properties"/>
+  <property file="../build.properties"/>
+  <property file="../../build.properties"/>
+  <property file="${user.home}/build.properties"/>
+
+  <property name="build.compiler"  value="modern"/>
+  <property name="webapps.build"   value="../build"/>
+  <property name="webapps.dist"    value="../dist"/>
+  <property name="webapp.name"     value="webdav"/>
+
+
+  <!-- =================== BUILD: Create Directories ====================== -->
+  <target name="build-prepare">
+    <mkdir dir="${webapps.build}"/>
+    <mkdir dir="${webapps.build}/${webapp.name}"/>
+    <mkdir dir="${webapps.build}/${webapp.name}/WEB-INF"/>
+  </target>
+
+
+  <!-- ================ BUILD: Copy Static Files ========================== -->
+  <target name="build-static" depends="build-prepare">
+    <copy todir="${webapps.build}/${webapp.name}">
+      <fileset dir=".">
+        <exclude name="build.*"/>
+      </fileset>
+    </copy>
+  </target>
+
+
+  <!-- ================= BUILD: Compile Server Components ================= -->
+  <target name="build-main" depends="build-static"/>
+
+
+  <!-- ==================== BUILD: Rebuild Everything ===================== -->
+  <target name="all" depends="build-clean,build-main"
+   description="Clean and build webdav webapp"/>
+
+
+  <!-- ======================= BUILD: Clean Directory ===================== -->
+  <target name="build-clean">
+    <delete dir="${webapps.build}/${webapp.name}"/>
+  </target>
+
+
+  <!-- ======================= DIST: Create Directories =================== -->
+  <target name="dist-prepare">
+    <mkdir dir="${webapps.dist}"/>
+  </target>
+
+
+  <!-- ======================= DIST: Create Distribution Files ============ -->
+  <target name="dist" depends="build-main,dist-prepare"
+   description="Create webdav webapp binary distribution">
+      <jar   jarfile="${webapps.dist}/${webapp.name}.war"
+             basedir="${webapps.build}/${webapp.name}" includes="**"/>
+  </target>
+
+
+  <!-- ======================= DIST: Clean Directory ====================== -->
+  <target name="dist-clean">
+    <delete dir="${dist.dir}/${webapp.name}"/>
+  </target>
+
+
+  <!-- ====================== Convenient Synonyms ========================= -->
+  <target name="clean" depends="build-clean,dist-clean"
+   description="Clean build and dist directories"/>
+
+
+</project>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/webdav/index.html
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/container/webapps/webdav/index.html	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/container/webapps/webdav/index.html	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,76 @@
+<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+<meta name="GENERATOR" content="Mozilla/4.72 [en] (WinNT; U) [Netscape]">
+<meta name="Author" content="Anil K. Vijendran">
+<title>Tomcat WebDAV support</title>
+</head>
+<body bgcolor="#FFFFFF">
+<img SRC="tomcat.gif" height=92 width=130 align=LEFT><b><font face="Arial, Helvetica, sans-serif"><font size=+3>Tomcat</font></font></b> 
+<br>
+<b><font face="Arial, Helvetica, sans-serif"><font size=-1>WebDAV support</font></font></b>
+<p>This is the home page for the webdav context. This page is located at:
+<ul>
+<li>
+<font face="Courier New, Courier,mono">$TOMCAT_HOME/webapps/webdav/index.html</font></li>
+</ul>
+
+<p>Tomcat includes built-in support for WebDAV level 2, which enables 
+remote authoring of the website. You can test these capabilities using a WebDAV
+client like MS WebFolders (included with IE 4.0 and up), MS Office 2000, DAV
+Explorer (others are listed on the webpages linked below), and point to the
+<b>/webdav</b> path of the server.
+
+<p>This test context is DAV enabled, but has been set up in read-only mode for
+safety reasons. It can be put in read-write mode by editing the web 
+application descriptor file (WEB-INF/web.xml).
+
+<p>To add remote authoring to your web application, you need to make the following
+changes:
+<ul>
+<li>Add the webDAV servlet to your web application. See the web application
+deployment descriptor for an example. Don't forget to make it read/write.
+<li>Add a servlet mapping for the webDAV servlet with a url pattern of "/webdav/*"
+to your web.xml.
+<li>Add an appropriate security constraint to prevent unauthorised changes to your
+web application.
+<li>You can then edit your web application using a webDAV client using a url
+like <font face="Courier New, Courier,mono">http://host:port/webapp/webdav</font></li>
+</ul>
+
+<p>Working WebDAV clients include :
+<ul>
+<li>Adobe GoLive 5.0 (and other WebDAV-enabled Adobe products, like
+  Photoshop)</li>
+<li>Cadaver 0.15</li>
+<li>DAV Explorer 0.60 and 0.70</li>
+<li>Internet Explorer 5 (Windows 2000)</li>
+<li>Internet Explorer 5.5 (Windows 2000)</li>
+<li>Jakarta Slide 1.0 WebDAV client library</li>
+<li>Office 2000 (Windows 2000)</li>
+<li>SkunkDAV 1.0</li>
+<li>Xythos Drive</li>
+</ul>
+
+<p>WebDAV links:</p>
+<ul>
+<li><b><a href="http://www.webdav.org">General info on WebDAV</a></b></li>
+<li><b><a href="http://www.ics.uci.edu/pub/ietf/webdav/">WebDAV working 
+group</a></b></li>
+<li><b><a href="http://www.webdav.org/projects/">WebDAV clients</a></b></li>
+<li><b>
+<a href="http://jakarta.apache.org/slide/">The Jakarta Slide Project</a>
+</b></li>
+</ul>
+
+
+<hr>
+<p align="right"><font size=-1><img src="tomcat-power.gif" width="77" height="80"></font><br>
+&nbsp;
+<font size=-1>Copyright &copy; 1999-2001 Apache Software Foundation</font><br>
+<font size=-1>All Rights Reserved</font> <br>
+&nbsp;</p>
+<p align="right">&nbsp;</p>
+</body>
+</html>

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/webdav/tomcat-power.gif
===================================================================
(Binary files differ)


Property changes on: branches/tomcat5.5/upstream/5.5.20/container/webapps/webdav/tomcat-power.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: branches/tomcat5.5/upstream/5.5.20/container/webapps/webdav/tomcat.gif
===================================================================
(Binary files differ)


Property changes on: branches/tomcat5.5/upstream/5.5.20/container/webapps/webdav/tomcat.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: branches/tomcat5.5/upstream/5.5.20/jasper/.classpath
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/jasper/.classpath	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/jasper/.classpath	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+	<classpathentry kind="src" path="src/share"/>
+	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
+	<classpathentry kind="var" path="TOMCAT_LIBS_BASE/commons-logging-1.0.4/commons-logging-api.jar"/>
+	<classpathentry kind="var" path="ANT_HOME/lib/ant.jar"/>
+	<classpathentry kind="var" path="TOMCAT_LIBS_BASE/commons-el-1.0/commons-el.jar"/>
+	<classpathentry kind="var" path="TOMCAT_LIBS_BASE/eclipse/plugins/org.eclipse.jdt.core_3.1.1.jar"/>
+	<classpathentry kind="var" path="TOMCAT_LIBS_BASE/jsp-api-2.0/lib/jsp-api.jar"/>
+	<classpathentry kind="var" path="TOMCAT_LIBS_BASE/servlet-api-2.4/lib/servlet-api.jar"/>
+	<classpathentry kind="output" path="bin"/>
+</classpath>

Added: branches/tomcat5.5/upstream/5.5.20/jasper/.project
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/jasper/.project	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/jasper/.project	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>jasper</name>
+	<comment></comment>
+	<projects>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>org.eclipse.jdt.core.javabuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>org.eclipse.jdt.core.javanature</nature>
+	</natures>
+</projectDescription>

Added: branches/tomcat5.5/upstream/5.5.20/jasper/BUILDING.txt
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/jasper/BUILDING.txt	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/jasper/BUILDING.txt	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,73 @@
+$Id: BUILDING.txt 373928 2006-01-31 22:19:27Z markt $
+
+         Building The Tomcat 4.0 Servlet/JSP Container With Jasper2
+         ==========================================================
+
+Jasper2 is a reimplementation of the JSP Container for Tomcat 4.0 that is
+cleaner and easier to extend.  It also forms the basis of the JSP 2.0 
+implementation.  Jasper2 will eventually replace the Jasper module
+built into the Tomcat distribution.  In the meanwhile, you can build Jasper2
+alongside Tomcat 4.0 and replace Jasper.
+
+To build Jasper2, first make sure you have a working build environment for
+Tomcat 4.0.  You can do so by following the instructions in the BUILDING.txt
+file in the Tomcat 4.0 workspace.
+
+Once you have a working build environment for Tomcat 4.0, do the following:
+
+(0) Modify your build.properties file in Tomcat 4.0
+
+* Add a line to your build.properties file for Tomcat 4.0 that
+  points the build script to Jasper2 instead of Jasper, as follows:
+
+      # ----- Jakarta Tomcat Jasper source path -----
+      jasper.home=${base.path}/jakarta-tomcat-jasper/jasper2
+
+  This directory is relative to the location of build.xml for Tomcat.
+
+(1) Use anonymous CVS (as described on the Jakarta web site at
+    <http://jakarta.apache.org/site/cvsindex.html>, or download a source
+    distribution of the "jakarta-taglibs" repository (7/15/2002 or later).
+
+    http://jakarta.apache.org/builds/jakarta-taglibs/nightly/projects/standard/
+
+* Unpack the package into a convenient location so that
+  it resides in its own subdirectory.
+
+* Follow the instructions in BUILDING.txt to set up the correct 
+  build environment.  Make sure you have a valid build.properties file.
+
+* Change directory to "standard" and build the special JSP 2.0 build target
+  for producing the JSP 2.0 Expression Language Evaluator.  The ant target
+  is called jsp20el.dist.
+
+        cd standard
+        ant jsp20el.dist
+
+(2) Customize Build Properties for this subproject
+
+Most Jakarta subprojects allow you to customize Ant properties (with default
+values defined in the "build.xml" file.  This is done by creating a text file
+named "build.properties" in the source distribution directory (for property
+definitions local to this subproject) and/or your user home directory (for
+property definitions shared across subprojects).  You can use the included
+"build.properties.sample" file as a starting point for this.
+
+Jasper2 has external dependencies that are satisfied by configuring
+appropriate values in your build.properties file.  The easiest
+way to satisfy these dependencies is to copy the "build.properties.sample"
+file (in the top-level Tomcat source directory) to "build.properties", and
+then edit it to suit your environment.  On Unix, this would be done as:
+
+  cd ${jasper2.source}
+  cp build.properties.sample build.properties
+  emacs build.properties
+
+NOTE:  Be *sure* that you do not check "build.properties" in to the CVS
+repository.  This file is local to your own development environment, and
+each developer will have their own version.
+
+(3) Build A Binary Distribution
+
+Jasper2 is built as part of Tomcat.  Follow the instructions in 
+BUILDING.txt in the Tomcat project to build Tomcat with Jasper2.

Added: branches/tomcat5.5/upstream/5.5.20/jasper/LICENSE
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/jasper/LICENSE	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/jasper/LICENSE	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,202 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed 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.

Added: branches/tomcat5.5/upstream/5.5.20/jasper/README.txt
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/jasper/README.txt	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/jasper/README.txt	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,24 @@
+This project is a rewrite of Jasper for tomcat 4.x.
+
+1. Main goals:
+
+   * Cleanup of the current Jasper.
+   * Use for RI work for JSP 1.3
+   * Use for optimization work for generated servlet codes.
+
+2. Status
+
+   * Main jasper engine (parser, attribute validates, code generator)
+     basically complete.
+
+3. Todo
+
+   * Rewrite attribute parser for better spec comformance.
+   * More cleanup, especially jspc parts.
+   * Added large file option.
+   * Error messages.
+   * JSR045 support
+   * Expression language support (JSP1.3)
+   * Optimizations, optimizations, and optimizations
+
+

Added: branches/tomcat5.5/upstream/5.5.20/jasper/build.properties.sample
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/jasper/build.properties.sample	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/jasper/build.properties.sample	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,17 @@
+# -----------------------------------------------------------------------------
+# build.properties.sample
+#
+# This is an example "build.properties" file, used to customize building 
+# Jasper2 for your local environment.  It defines the location of all external
+# modules that Jasper2 depends on.  Copy this file to "build.properties"
+# in the top-level source directory, and customize it as needed.
+#
+# $Id: build.properties.sample 373928 2006-01-31 22:19:27Z markt $
+# -----------------------------------------------------------------------------
+
+# ----- Pointer to Catalina -----
+catalina.home=../../jakarta-tomcat-5/build
+
+# ----- Pointer to JSP Standard Tag Library distribution -----
+#standard.home=${base.path}/jakarta-taglibs/standard
+#jsp20el.jar=${standard.home}/../dist/jsp20el/jsp20el.jar

Added: branches/tomcat5.5/upstream/5.5.20/jasper/build.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/jasper/build.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/jasper/build.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,306 @@
+<project name="Jasper2" default="deploy" basedir=".">
+
+
+  <!-- ===================== Initialize Property Values =================== -->
+
+  <!-- See "build.properties.sample" in the top level directory for all     -->
+  <!-- property values you must customize for successful building!!!        -->
+  <property file="${user.home}/build.properties"/>
+  <property file="build.properties"/>
+  <property file="build.properties.sample"/>
+  <property file="${catalina.home}/build.properties"/>
+
+  <!-- Build Defaults -->
+  <property name="jasper.build"      value="${basedir}/build"/>
+  <property name="catalina.home"     value="../../jakarta-tomcat-4.1/build"/>
+  <property name="jasper.deploy"     value="${catalina.home}"/>
+  <property name="jasper.dist"       value="${basedir}/dist"/>
+  <property name="test.failonerror"  value="true"/>
+  <property name="test.runner"       value="junit.textui.TestRunner"/>
+  <property name="tools.jar"         value="${java.home}/lib/tools.jar"/>
+  <property name="ant.jar"           value="${ant.home}/lib/ant.jar"/>
+  <property name="servlet-api.jar" value="${api.home}/jsr154/dist/lib/servlet-api.jar"/>
+  <property name="jsp-api.jar" value="${api.home}/jsr152/dist/lib/jsp-api.jar"/>
+
+
+  <!-- Construct Jasper classpath -->
+  <path id="jasper.classpath">
+    <pathelement location="${ant.jar}"/>
+    <pathelement location="${servlet-api.jar}"/>
+    <pathelement location="${jsp-api.jar}"/>
+    <pathelement location="${tools.jar}"/>
+    <pathelement location="${jasper-compiler-jdt.jar}"/>
+    <pathelement location="${xerces.jar}"/>
+    <pathelement location="${xercesImpl.jar}"/>
+    <pathelement location="${xml-apis.jar}"/>
+    <pathelement location="${commons-el.jar}"/>
+    <pathelement location="${commons-collections.jar}"/>
+    <pathelement location="${commons-logging.jar}"/>
+    <pathelement location="${commons-daemon-launcher.jar}"/>
+    <pathelement location="${jasper.build}/shared/classes"/>
+  </path>
+
+  <!-- Construct unit tests classpath -->
+  <path id="test.classpath">
+    <pathelement location="${ant.jar}"/>
+    <pathelement location="${junit.jar}"/>
+    <pathelement location="${servlet-api.jar}"/>
+    <pathelement location="${jsp-api.jar}"/>
+    <pathelement location="${tools.jar}"/>
+    <pathelement location="${xerces.jar}"/>
+    <pathelement location="${xercesImpl.jar}"/>
+    <pathelement location="${xml-apis.jar}"/>
+    <pathelement location="${commons-collections.jar}"/>
+    <pathelement location="${commons-launcher.jar}"/>
+    <pathelement location="${jasper.build}/shared/classes"/>
+    <pathelement location="${jasper.build}/tests"/>
+  </path>
+
+
+  <!-- =================== BUILD: Create Directories ====================== -->
+  <target name="build-prepare">
+
+    <available classname="junit.framework.TestCase" property="junit.present" />
+    <available property="launcher.present"
+     classname="org.apache.commons.launcher.Launcher"
+     classpath="${commons-daemon-launcher.jar}"/>
+    <available property="launcher.bootstrap.present"
+     file="${commons-daemon-launcher-bootstrap.class}"/>
+
+    <condition property="copy.launcher.jars">
+      <and>
+        <equals arg1="${launcher.present}" arg2="true" />
+        <equals arg1="${launcher.bootstrap.present}" arg2="true" />
+      </and>
+    </condition>
+
+    <mkdir dir="${jasper.build}"/>
+    <mkdir dir="${jasper.build}/bin"/>
+    <mkdir dir="${jasper.build}/common/classes"/>
+    <mkdir dir="${jasper.build}/common/lib"/>
+    <mkdir dir="${jasper.build}/shared/classes"/>
+    <mkdir dir="${jasper.build}/shared/lib"/>
+
+  </target>
+
+
+  <!-- =================== BUILD: Copy Launcher Files ===================== -->
+  <target name="copy-launcher.jars" if="copy.launcher.jars">
+    <!-- <copy todir="${jasper.build}/common/lib" file="${ant.jar}"/> -->
+    <copy todir="${jasper.build}/bin" file="${commons-daemon-launcher.jar}"/>
+    <copy todir="${jasper.build}/bin" file="${commons-daemon-launcher-bootstrap.class}"/>
+    <copy todir="${jasper.build}/bin">
+      <fileset dir="src/bin" includes="*-using-launcher.*,launcher.properties,jasper.xml" />
+    </copy>
+  </target>
+
+
+  <!-- =================== BUILD: Copy Static Files ======================= -->
+  <target name="build-static" depends="build-prepare,copy-launcher.jars">
+
+    <!-- Executable Commands -->
+    <copy todir="${jasper.build}/bin">
+      <fileset dir="src/bin" excludes="*-using-launcher.*,launcher.properties,jasper.xml" />
+    </copy>
+    <fixcrlf srcdir="${jasper.build}/bin" includes="*.sh" eol="lf"/>
+    <fixcrlf srcdir="${jasper.build}/bin" includes="*.bat" eol="crlf"/>
+    <chmod perm="+x" dir="${jasper.build}/bin" includes="*.sh"/>
+
+  </target>
+
+
+  <!-- ================= BUILD: Compile Server Components ================= -->
+  <target name="build-main" depends="build-static,build-only">
+    <!-- Extra operations: Supporting JAR Files -->
+    <copy todir="${jasper.build}/shared/lib" file="${commons-el.jar}"/>
+  </target>
+
+  <!-- Just build jasper -->
+  <target name="build-only">
+    <property name="jasper.classes" value="${jasper.build}/shared/classes"/>
+    <property name="jasper-compiler.jar" value="${jasper.build}/shared/lib/jasper-compiler.jar"/>
+    <property name="jasper-runtime.jar" value="${jasper.build}/shared/lib/jasper-runtime.jar"/>
+
+    <!-- Compile internal server components -->
+    <javac srcdir="src/share" destdir="${jasper.classes}"
+           debug="${compile.debug}"
+           deprecation="${compile.deprecation}"
+           source="${compile.source}"
+           optimize="${compile.optimize}"
+           excludes="**/CVS/**">
+      <classpath refid="jasper.classpath" />
+    </javac>
+
+    <!-- Copy static resource files -->
+    <copy todir="${jasper.classes}">
+      <fileset dir="src/share">
+        <include name="**/*.properties"/>
+        <include name="**/*.dtd"/>
+      </fileset>
+    </copy>
+
+   <!-- Jasper Compiler JAR File -->
+   <jar  jarfile="${jasper-compiler.jar}">
+      <fileset dir="${jasper.classes}">
+        <include name="org/apache/jasper/compiler/**" />
+        <include name="org/apache/jasper/xmlparser/**" />
+        <include name="org/apache/jasper/servlet/**" />
+        <include name="org/apache/jasper/tagplugins/**" />
+        <exclude name="org/apache/jasper/Constants.class" />
+        <exclude name="org/apache/jasper/JasperException.class" />
+        <include name="org/apache/jasper/*.class" />
+        <!-- Javadoc and i18n exclusions -->
+        <exclude name="**/package.html" />
+        <exclude name="**/LocalStrings_*" />
+      </fileset>
+    </jar>
+
+    <!-- Jasper Runtime JAR File -->
+    <jar  jarfile="${jasper-runtime.jar}">
+      <fileset dir="${jasper.classes}">
+        <include name="org/apache/jasper/Constants.class" />
+        <include name="org/apache/jasper/JasperException.class" />
+        <include name="org/apache/jasper/compiler/Localizer.class" />
+        <include name="org/apache/jasper/resources/**" />
+        <include name="org/apache/jasper/runtime/**" />
+        <include name="org/apache/jasper/security/**" />
+        <include name="org/apache/jasper/util/**" />
+        <!-- Javadoc and i18n exclusions -->
+        <exclude name="**/package.html" />
+        <exclude name="**/LocalStrings_*" />
+      </fileset>
+    </jar>
+
+  </target>
+
+
+  <!-- ================ BUILD: Create Jasper Javadocs ===================== -->
+  <target name="javadoc">
+    <delete dir="${jasper.build}/javadoc"/>
+    <mkdir dir="${jasper.build}/javadoc"/>
+    <javadoc packagenames="org.apache.jasper.*"
+     classpathref="jasper.classpath"
+     sourcepath="src/share"
+     destdir="${jasper.build}/javadoc"
+     author="true"
+     version="true"
+     windowtitle="Jasper Internal API Documentation"
+     doctitle="Jasper API"
+     bottom="Copyright &#169; 2000-2004 Apache Software Foundation.  All Rights Reserved."
+     additionalparam="-breakiterator"
+    />
+  </target>
+
+
+  <!-- ======================= BUILD: Clean Directory ===================== -->
+  <target name="build-clean">
+    <delete dir="${jasper.build}"/>
+  </target>
+
+
+  <!-- ==================== BUILD: Rebuild Everything ===================== -->
+  <target name="all" depends="build-clean,build-main"
+   description="Clean, build, and deploy Jasper component"/>
+
+
+  <!-- =============== BUILD: Compile Unit Tests ========================== -->
+  <target name="build-tests" depends="build-main" if="junit.present">
+    <mkdir      dir="${jasper.build}/tests"/>
+    <!-- Compile unit test classes -->
+<!--
+    <javac   srcdir="src/test" destdir="${jasper.build}/tests"
+             deprecation="${compile.deprecation}"
+             debug="${compile.debug}"
+             source="${compile.source}"
+             optimize="off"
+             excludes="**/CVS/**">
+      <classpath refid="test.classpath"/>
+    </javac>
+-->
+  </target>
+
+
+  <!-- ==================== BUILD: Execute Unit Tests ===================== -->
+  <target name="test" if="junit.present"
+   description="Run all unit test cases"
+   depends="build-tests">
+  </target>
+
+
+  <!-- ====================== DEPLOY: Create Directories ================== -->
+  <target name="deploy-prepare">
+    <mkdir dir="${jasper.deploy}"/>
+    <mkdir dir="${jasper.deploy}/bin"/>
+    <mkdir dir="${jasper.deploy}/common/lib"/>
+  </target>
+
+
+  <!-- ====================== DEPLOY: Copy Static Files =================== -->
+  <target name="deploy-static" depends="build-main,deploy-prepare">
+
+    <!-- Executable Commands -->
+    <copy todir="${jasper.deploy}/bin">
+      <fileset dir="${jasper.build}/bin" />
+    </copy>
+    <fixcrlf srcdir="${jasper.deploy}/bin" includes="*.sh" eol="lf"/>
+    <fixcrlf srcdir="${jasper.deploy}/bin" includes="*.bat" eol="crlf"/>
+    <chmod perm="+x" file="${jasper.deploy}/bin/jspc.sh"/>
+
+  </target>
+
+
+  <!-- ====================== DEPLOY: Create Jasper JARs ================== -->
+  <target name="deploy" depends="deploy-static,build-main"
+   description="Build and deploy Jasper component">
+    <echo message="Deploy to ${jasper.deploy}/common/lib" /> 
+    <!-- Jasper Compiler JAR File -->
+    <copy file="${jasper.build}/shared/lib/jasper-compiler.jar"
+          tofile="${jasper.deploy}/common/lib/jasper-compiler.jar" />
+
+    <copy file="${jasper.build}/shared/lib/jasper-runtime.jar"
+          tofile="${jasper.deploy}/common/lib/jasper-runtime.jar" />
+
+    <!-- Copy JARs -->
+    <copy todir="${jasper.deploy}/common/lib" file="${jasper-compiler-jdt.jar}"/>
+    <copy todir="${jasper.deploy}/common/lib" file="${jsp-api.jar}"/>
+    <copy todir="${jasper.deploy}/common/lib" file="${commons-el.jar}"/>
+
+  </target>
+
+
+  <!-- ================ DIST: Create Distribution ========================= -->
+  <target name="dist" depends="build-main"
+   description="Create binary distribution">
+
+    <!-- Executable commands -->
+    <mkdir dir="${jasper.dist}/bin"/>
+    <copy todir="${jasper.dist}/bin">
+      <fileset dir="${jasper.build}/bin" />
+    </copy>
+    <fixcrlf srcdir="${jasper.dist}/bin" includes="*.sh" eol="lf"/>
+    <fixcrlf srcdir="${jasper.dist}/bin" includes="*.bat" eol="crlf"/>
+    <chmod perm="+x" file="${jasper.dist}/bin/jspc.sh"/>
+
+    <!-- Jasper Compiler and Runtime JAR Files -->
+    <mkdir dir="${jasper.dist}/shared/lib"/>
+    <copy todir="${jasper.dist}/shared/lib">
+      <fileset dir="${jasper.build}/shared/lib"/>
+    </copy>
+
+
+  </target>
+
+
+  <!-- ======================== DIST: Clean Directory ===================== -->
+  <target name="dist-clean">
+    <delete dir="${jasper.dist}"/>
+  </target>
+
+
+  <!-- ====================== Convenient Synonyms ========================= -->
+  <target name="clean" depends="build-clean, dist-clean"
+   description="Clean build and dist directories"/>
+
+
+</project>
+

Added: branches/tomcat5.5/upstream/5.5.20/jasper/doc/jspc.html
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/jasper/doc/jspc.html	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/jasper/doc/jspc.html	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,137 @@
+<html>
+<head>
+<title>&lt;jspc&gt;</title>
+</head>
+<body>
+<H1> JspC -- A Command Line JSP Compilation Tool </H1>
+<H3>$Id: jspc.html 373928 2006-01-31 22:19:27Z markt $</H3>
+
+<H2>OVERVIEW </H2>
+
+Even thought the primary focus of JSP is as a container run environment,
+sometimes it is useful to create a pure servlet out of the JSP page.
+JspC encapsulates the core JSP to servlet translation into a program
+that has no dependencies on a containing servlet engine and allows you
+to translate JSP pages into an equivalent Java servlet.
+
+<H2>GENERAL USE </H2>
+
+The most basic use of JspC is to compile a JSP page in place with the
+jsp page(s) as the arguments.  This will compile the page with the
+resulting java files placed in the directory JspC was called from.  The
+package will be determined from the directories that the JSP page lives
+in.  This will be relative to the web-app it live in (if it exists or is
+specified) or the default package.  The class name will be the name of
+the JSP page without the extension.
+
+<P>To override these default values you can use the <tt>-c</tt> and 
+<tt>-p</tt> options.  <tt>-c &lt;class name&gt;</tt> changes the name of 
+the class of the first compiled JSP page to the class specified.
+Subsequent JSP pages will not be affected by this option.  The 
+<tt>-p &lt;package name&gt;</tt> option sets the package name of all JSP 
+pages compiled by that invocation.  Web-Apps specified for translation 
+will not be affected by either of these options.</P>
+
+<P>The directory that the resulting java files will go into is specified by
+the <TT>-d &lt;dir&gt;</TT> and <tt>-dd &lt;dir&gt;</tt> options.  Both
+of these specify a directory that files will be written into.  When
+using <tt>-d</tt> the java files will be placed in package appropriate
+sub directories while with <tt>-dd</tt> all of the java files will be
+placed literally into the specified directory (without any subdirectory
+structure).</P>
+
+<P>The amount of command line output can be throttled by the <tt>-q</tt> and 
+the <tt>-v&lt;#&gt;</tt> options.  <tt>-q</tt> has the same effect as
+<tt>-v0</tt>, which is to turn off all but fatal error messages.  
+<tt>-v1</tt> builds on <tt>-v0</tt> and it will print out error messages, 
+<tt>-v2</tt> adds warnings, <tt>-v3</tt> adds informational messages
+that have no operational impact, and <tt>-v4</tt> adds various messages
+used in debugging JspC itself.</P>
+
+<P><tt>-ieplugin</tt> is used by the <tt>&lt;jsp:plugin&gt;</tt> tags.
+If the Java Plug-in COM Class-ID you want to use changes then it can be
+specified here.  This should not need to be altered.</P>
+
+<P>As an aid to makefiles, the <tt>-die[#]</tt> option will cause the
+JVM to exit with an error code if a fatal error occurs during the
+translation.   This can be caused by such things as an invalid JSP 
+or an unwritable destination.  There is an optional number that can be 
+specified to specify the specific exit code, but it defaults to 
+<tt>1</tt> if it is not specified or cannot be deciphered.</P>
+
+<P>The <tt>-mapped</tt> option will split the JSP text content into a
+one line per call format.  There are comments above and below the mapped
+write calls to localize where in the JSP file each line of text comes
+from.  This can lead to a minor performance degradation (but it is bound 
+by a linear complexity).  Without this options all adjacent writes are
+concatenated into a single write.</P>
+
+<H2>WEB-APP INTEGRATION</H2>
+<P>JspC is web-app aware.  The package names and all relative uri
+references in JSP elements are rooted to a web-app base that is either
+heuristically determined or specified by the user.<P>
+
+<P><tt>-uriroot &lt;dir&gt;</tt> specifies the root of the web 
+application.  This is where all absolute uris will be resolved from.  
+If it is not specified then the first JSP page will be used to derive 
+it.  To derive it each parent directory of the first JSP page is 
+searched for a <tt>WEB-INF</tt> directory, and the directory closest to 
+the JSP page that has one will be used.  If none can be found then the 
+directory JspC was called from will be used.  This only affects pages 
+translated from an explicitly declared JSP file.</P>
+
+<P><tt>-uribase &lt;uri&gt;</tt> is used to establish the uri context of
+relative URI references in the JSP pages.  If it does not exist then it
+is derived from the location of the file relative to the declared or 
+derived value of <tt>-uriroot</tt>.    This only affects pages 
+translated from an explicitly declared JSP file.</P>
+
+<P> The jsp files option of <tt>-webapp &lt;dir&gt;</tt> is used to
+specify that an entire web-app's JSP files are to be translated.  The
+value of <tt>-uriroot</tt> for that directory becomes the specified
+directory, and all relative uris are resolved against their position in
+the web app.  Currently specifying a war, jar, or zip file is not
+supported.  Each directory is recursively searched and any file with a 
+<tt>.jsp</tt> extension is parsed as though it is a JSP page.  These
+pages obey the <tt>-d</tt>, <tt>-dd</tt>, and <tt>-p</tt> options.
+
+<P>Appropriate entries for the <tt>web.xml</tt> file can be created via
+the <tt>-webinc &lt;file&gt;</tt> and <tt>-webxml &lt;file&gt;</tt>
+options.  All JSP files and web-apps parsed by the single invocation
+will have appropriate <tt>servlet</tt> and <tt>servlet-mapping</tt> 
+elements created for them.  The <tt>webinc</tt> creates only an XML
+fragment suitable for inclusion into an existing <tt>web.xml</tt> file,
+while the <tt>webxml</tt> option creates an entire file with the 
+appropriate headers and root elements suitable for use as a 
+<tt>web.xml</tt> file.</P>
+
+<H2>COMMAND LINE SUMMARY</H2>
+<pre>
+Usage: jspc &lt;options&gt; [--] &lt;jsp files&gt;
+where jsp files is any number of:
+    &lt;file&gt;         A file to be parsed as a jsp page
+    -webapp &lt;dir&gt;  A directory containing a web-app, all jsp pages
+                   will recursively be parsed
+where options include:
+    -q          Quite mode (same as -v0)
+    -v[#]       Verbose mode (optional number is level, default is 2)
+    -d &lt;dir&gt;    Output Directory
+    -dd &lt;dir&gt;   Literal Output Directory.  (package dirs will not be made)
+    -p &lt;name&gt;         Name of target package
+    -c &lt;name&gt;         Name of target class name
+                (only applies to first JSP page)
+    -mapped     Generate separate write() calls for each HTML line in the JSP
+    -die[#]     Generate an error return code (#) on fatal errors.
+                If the number is absent or unparsable it defaults to 1.
+    -uribase &lt;dir&gt;  The uri directory compilations should be relative to
+                    (Default is "/")
+    -uriroot &lt;dir&gt;  The root directory that uri files should be resolved
+                    against, (Default is the directory jspc is invoked from)
+    -webinc &lt;file&gt;  Creates partial servlet mappings for the -webapp option
+    -webxml &lt;file&gt;  Creates a complete web.xml when using the -webapp option.
+    -ieplugin &lt;clsid&gt;  Java Plugin classid for Internet Explorer
+    -sax2 &lt;driverclassname&gt; Driver class name for the SAX 2.0 parser to be used
+</pre>
+
+</body>
+</html>

Added: branches/tomcat5.5/upstream/5.5.20/jasper/src/bin/jasper.bat
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/jasper/src/bin/jasper.bat	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/jasper/src/bin/jasper.bat	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,71 @@
+ at echo off
+if "%OS%" == "Windows_NT" setlocal
+rem ---------------------------------------------------------------------------
+rem Script for Jasper compiler
+rem
+rem Environment Variable Prequisites
+rem
+rem   JASPER_HOME   May point at your Catalina "build" directory.
+rem
+rem   JASPER_OPTS   (Optional) Java runtime options used when the "start",
+rem                 "stop", or "run" command is executed.
+rem
+rem   JAVA_HOME     Must point at your Java Development Kit installation.
+rem
+rem   JAVA_OPTS     (Optional) Java runtime options used when the "start",
+rem                 "stop", or "run" command is executed.
+rem
+rem $Id: jasper.bat 305074 2002-08-04 18:21:08Z patrickl $
+rem ---------------------------------------------------------------------------
+
+rem Guess JASPER_HOME if not defined
+if not "%JASPER_HOME%" == "" goto gotHome
+set JASPER_HOME=.
+if exist "%JASPER_HOME%\bin\jasper.bat" goto okHome
+set JASPER_HOME=..
+:gotHome
+if exist "%JASPER_HOME%\bin\jasper.bat" goto okHome
+echo The JASPER_HOME environment variable is not defined correctly
+echo This environment variable is needed to run this program
+goto end
+:okHome
+
+rem Get standard environment variables
+if exist "%JASPER_HOME%\bin\setenv.bat" call "%JASPER_HOME%\bin\setenv.bat"
+
+rem Get standard Java environment variables
+if exist "%JASPER_HOME%\bin\setclasspath.bat" goto okSetclasspath
+echo Cannot find %JASPER_HOME%\bin\setclasspath.bat
+echo This file is needed to run this program
+goto end
+:okSetclasspath
+set BASEDIR=%JASPER_HOME%
+call "%JASPER_HOME%\bin\setclasspath.bat"
+
+rem Add on extra jar files to CLASSPATH
+for %%i in ("%JASPER_HOME%\common\endorsed\*.jar") do call "%JASPER_HOME%\bin\cpappend.bat" %%i
+for %%i in ("%JASPER_HOME%\common\lib\*.jar") do call "%JASPER_HOME%\bin\cpappend.bat" %%i
+for %%i in ("%JASPER_HOME%\shared\lib\*.jar") do call "%JASPER_HOME%\bin\cpappend.bat" %%i
+set CLASSPATH=%CLASSPATH%;%JASPER_HOME%\shared\classes
+
+rem Parse arguments
+if ""%1"" == ""jspc"" goto doJspc
+echo Usage: jasper ( jspc )
+echo Commands:
+echo   jspc - Run the offline JSP compiler
+goto end
+:doJspc
+shift
+
+rem Get remaining unshifted command line arguments and save them in the
+set CMD_LINE_ARGS=
+:setArgs
+if ""%1""=="""" goto doneSetArgs
+set CMD_LINE_ARGS=%CMD_LINE_ARGS% %1
+shift
+goto setArgs
+:doneSetArgs
+
+%_RUNJAVA% %JAVA_OPTS% %JASPER_OPTS% -Djava.endorsed.dirs="%JAVA_ENDORSED_DIRS%" -classpath "%CLASSPATH%" -Djasper.home="%JASPER_HOME%" org.apache.jasper.JspC %CMD_LINE_ARGS%
+
+:end

Added: branches/tomcat5.5/upstream/5.5.20/jasper/src/bin/jasper.sh
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/jasper/src/bin/jasper.sh	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/jasper/src/bin/jasper.sh	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,111 @@
+#!/bin/sh
+# -----------------------------------------------------------------------------
+# Script for Jasper compiler
+#
+# Environment Variable Prequisites
+#
+#   JASPER_HOME   May point at your Catalina "build" directory.
+#
+#   JASPER_OPTS   (Optional) Java runtime options used when the "start",
+#                 "stop", or "run" command is executed.
+#
+#   JAVA_HOME     Must point at your Java Development Kit installation.
+#
+#   JAVA_OPTS     (Optional) Java runtime options used when the "start",
+#                 "stop", or "run" command is executed.
+#
+# $Id: jasper.sh 305839 2003-10-01 18:39:08Z kinman $
+# -----------------------------------------------------------------------------
+
+# OS specific support.  $var _must_ be set to either true or false.
+cygwin=false
+os400=false
+case "`uname`" in
+CYGWIN*) cygwin=true;;
+OS400*) os400=true;;
+esac
+
+# resolve links - $0 may be a softlink
+PRG="$0"
+
+while [ -h "$PRG" ]; do
+  ls=`ls -ld "$PRG"`
+  link=`expr "$ls" : '.*-> \(.*\)$'`
+  if expr "$link" : '.*/.*' > /dev/null; then
+    PRG="$link"
+  else
+    PRG=`dirname "$PRG"`/"$link"
+  fi
+done
+
+# Get standard environment variables
+PRGDIR=`dirname "$PRG"`
+JASPER_HOME=`cd "$PRGDIR/.." ; pwd`
+if [ -r "$JASPER_HOME"/bin/setenv.sh ]; then
+  . "$JASPER_HOME"/bin/setenv.sh
+fi
+
+# For Cygwin, ensure paths are in UNIX format before anything is touched
+if $cygwin; then
+  [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
+  [ -n "$JASPER_HOME" ] && JASPER_HOME=`cygpath --unix "$JASPER_HOME"`
+  [ -n "$CLASSPATH" ] && CLASSPATH=`cygpath --path --unix "$CLASSPATH"`
+fi
+
+# Get standard Java environment variables
+if [ -r "$JASPER_HOME"/bin/setclasspath.sh ]; then
+  BASEDIR="$JASPER_HOME"
+  . "$JASPER_HOME"/bin/setclasspath.sh
+else
+  echo "Cannot find $JASPER_HOME/bin/setclasspath.sh"
+  echo "This file is needed to run this program"
+  exit 1
+fi
+
+# Add on extra jar files to CLASSPATH
+for i in "$JASPER_HOME"/common/endorsed/*.jar; do
+  CLASSPATH="$CLASSPATH":"$i"
+done
+for i in "$JASPER_HOME"/common/lib/*.jar; do
+  CLASSPATH="$CLASSPATH":"$i"
+done
+for i in "$JASPER_HOME"/shared/lib/*.jar; do
+  CLASSPATH="$CLASSPATH":"$i"
+done
+CLASSPATH="$CLASSPATH":"$JASPER_HOME"/shared/classes
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin; then
+  JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"`
+  JASPER_HOME=`cygpath --path --windows "$JASPER_HOME"`
+  CLASSPATH=`cygpath --path --windows "$CLASSPATH"`
+fi
+
+# ----- Execute The Requested Command -----------------------------------------
+
+if [ "$1" = "jspc" ] ; then
+
+  shift
+  exec "$_RUNJAVA" $JAVA_OPTS $JASPER_OPTS \
+    -Djava.endorsed.dirs="$JAVA_ENDORSED_DIRS" -classpath "$CLASSPATH" \
+    -Djasper.home="$JASPER_HOME" \
+    -Dcatalina.home="$JASPER_HOME" \
+    org.apache.jasper.JspC "$@"
+
+elif [ "$1" = "debug" ] ; then
+
+  shift
+  exec "$_RUNJDB" $JAVA_OPTS $JASPER_OPTS \
+    -Djava.endorsed.dirs="$JAVA_ENDORSED_DIRS" -classpath "$CLASSPATH" \
+    -Djasper.home="$JASPER_HOME" \
+    -Dcatalina.home="$JASPER_HOME" \
+    org.apache.jasper.JspC "$@"
+
+else
+
+  echo "Usage: jasper.sh ( jspc )"
+  echo "Commands:"
+  echo "  jspc - Run the offline JSP compiler"
+  exit 1
+
+fi

Added: branches/tomcat5.5/upstream/5.5.20/jasper/src/bin/jasper.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/jasper/src/bin/jasper.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/jasper/src/bin/jasper.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,97 @@
+<!--
+
+  XML file for launching Jasper applications using the Launcher.
+
+  To run any of the applications in the JDB debugger, execute the Launcher with
+  a "-Ddebug=true" argument.
+
+  To run any of the applications in JPDA mode, execute the Launcher with a
+  "-Djpda=true" argument.
+
+-->
+
+<project name="Jasper Launcher" default="jspc" basedir=".">
+
+  <!-- Set the application home to the parent directory of this directory -->
+  <property name="jasper.home" location="${basedir}/.."/>
+
+  <!-- Import the user's custom properties -->
+  <property file="${jasper.home}/bin/jasper.properties"/>
+
+  <!-- Set user configurable properties -->
+  <property name="jasper.jvm.args" value=""/>
+  <property name="jasper.source.path" value="${jasper.home}/../../jakarta-servletapi-5/src/share:${jasper.home}/../../jakarta-tomcat-jasper/jasper2/src/share"/>
+
+  <!-- Build the classpath relative to the application home -->
+  <path id="base.class.path">
+    <fileset dir="${jasper.home}/common/lib" includes="*.jar"/>
+    <fileset dir="${jasper.home}/common/endorsed" includes="*.jar"/>
+    <fileset dir="${jasper.home}/shared/lib" includes="*.jar"/>
+    <pathelement location="${jasper.home}/shared/classes"/>
+  </path>
+
+  <!-- Build the sysproperties relative to the application home -->
+  <syspropertyset id="base.sys.properties">
+    <sysproperty key="java.endorsed.dirs" file="${jasper.home}/common/endorsed"/>
+    <sysproperty key="jasper.home" file="${jasper.home}"/>
+  </syspropertyset>
+
+  <!-- Build the standard jvmargs -->
+  <jvmargset id="base.jvm.args">
+    <jvmarg line="${jasper.jvm.args}"/>
+    <jvmarg value="-Xdebug" if="jpda.settings"/>
+    <jvmarg value="-Xrunjdwp:${jpda.settings}" if="jpda.settings"/>
+    <jvmarg value="-sourcepath" if="jdb"/>
+    <jvmarg path="${jasper.source.path}" if="jdb"/>
+  </jvmargset>
+
+  <!-- Target that sets JDB properties when the "debug" property is set -->
+  <target name="setjdb" description="Set JDB properties" if="debug">
+
+    <property name="jdb" value="true"/>
+
+  </target>
+
+  <!-- Target that sets JPDA properties when the "jpda" property is set -->
+  <target name="setjpda" description="Set JPDA properties" if="jpda">
+
+    <condition property="jpda.transport" value="dt_shmem">
+      <os family="windows"/>
+    </condition>
+    <condition property="jpda.transport" value="dt_socket">
+      <not>
+        <os family="windows"/>
+      </not>
+    </condition>
+    <condition property="jpda.address" value="jdbconn">
+      <equals arg1="${jpda.transport}" arg2="dt_shmem"/>
+    </condition>
+    <condition property="jpda.address" value="8000">
+      <not>
+        <equals arg1="${jpda.transport}" arg2="dt_shmem"/>
+      </not>
+    </condition>
+    <property name="jpda.suspend" value="y"/>
+    <property name="jpda.settings" value="transport=${jpda.transport},address=${jpda.address},server=y,suspend=${jpda.suspend}"/>
+
+  </target>
+
+  <!-- Target that executes the JSPC compiler-->
+  <target name="jspc" description="Execute JSPC compiler"
+    depends="setjdb,setjpda">
+
+    <!-- Launch JSPC compiler -->
+    <launch classname="org.apache.jasper.JspC"
+      debug="${jdb}"
+      print="${print}"
+      usesystemin="false"
+      requiretools="true">
+        <jvmargset refid="base.jvm.args"/>
+        <arg value="jspc"/>
+        <syspropertyset refid="base.sys.properties"/>
+        <classpath refid="base.class.path"/>
+    </launch>
+
+  </target>
+
+</project>

Added: branches/tomcat5.5/upstream/5.5.20/jasper/src/bin/jspc-using-launcher.bat
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/jasper/src/bin/jspc-using-launcher.bat	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/jasper/src/bin/jspc-using-launcher.bat	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,40 @@
+ at echo off
+if "%OS%" == "Windows_NT" setlocal
+
+rem ---------------------------------------------------------------------------
+rem
+rem Script for running JSPC compiler using the Launcher
+rem
+rem ---------------------------------------------------------------------------
+
+rem Get standard environment variables
+set PRG=%0
+if exist %PRG%\..\setenv.bat goto gotCmdPath
+rem %0 must have been found by DOS using the %PATH% so we assume that
+rem setenv.bat will also be found in the %PATH%
+call setenv.bat
+goto doneSetenv
+:gotCmdPath
+call %PRG%\..\setenv.bat
+:doneSetenv
+
+rem Make sure prerequisite environment variables are set
+if not "%JAVA_HOME%" == "" goto gotJavaHome
+echo The JAVA_HOME environment variable is not defined
+echo This environment variable is needed to run this program
+goto end
+:gotJavaHome
+
+rem Get command line arguments and save them with the proper quoting
+set CMD_LINE_ARGS=
+:setArgs
+if ""%1""=="""" goto doneSetArgs
+set CMD_LINE_ARGS=%CMD_LINE_ARGS% %1
+shift
+goto setArgs
+:doneSetArgs
+
+rem Execute the Launcher using the "jspc" target
+"%JAVA_HOME%\bin\java.exe" -classpath %PRG%\..;"%PATH%";. LauncherBootstrap -launchfile jasper.xml -verbose jspc %CMD_LINE_ARGS%
+
+:end

Added: branches/tomcat5.5/upstream/5.5.20/jasper/src/bin/jspc-using-launcher.sh
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/jasper/src/bin/jspc-using-launcher.sh	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/jasper/src/bin/jspc-using-launcher.sh	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,29 @@
+#!/bin/sh
+
+# -----------------------------------------------------------------------------
+#
+# Script for running JSPC compiler using the Launcher
+#
+# -----------------------------------------------------------------------------
+
+# Resolve links - $0 may be a softlink
+PRG="$0"
+
+while [ -h "$PRG" ]; do
+  ls=`ls -ld "$PRG"`
+  link=`expr "$ls" : '.*-> \(.*\)$'`
+  if expr "$link" : '.*/.*' > /dev/null; then
+    PRG="$link"
+  else
+    PRG=`dirname "$PRG"`/"$link"
+  fi
+done
+
+# Get standard environment variables
+PRGDIR=`dirname "$PRG"`
+if [ -r "$PRGDIR"/setenv.sh ]; then
+  . "$PRGDIR"/setenv.sh
+fi
+
+# Execute the Launcher using the "jspc" target
+exec "$JAVA_HOME"/bin/java -classpath "$PRGDIR" LauncherBootstrap -launchfile jasper.xml -verbose jspc "$@"

Added: branches/tomcat5.5/upstream/5.5.20/jasper/src/bin/jspc.bat
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/jasper/src/bin/jspc.bat	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/jasper/src/bin/jspc.bat	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,41 @@
+ at echo off
+if "%OS%" == "Windows_NT" setlocal
+rem ---------------------------------------------------------------------------
+rem Script to run the Jasper "offline JSP compiler"
+rem
+rem $Id: jspc.bat 305074 2002-08-04 18:21:08Z patrickl $
+rem ---------------------------------------------------------------------------
+
+rem Guess JASPER_HOME if not defined
+if not "%JASPER_HOME%" == "" goto gotHome
+set JASPER_HOME=.
+if exist "%JASPER_HOME%\bin\jspc.bat" goto okHome
+set JASPER_HOME=..
+:gotHome
+if exist "%JASPER_HOME%\bin\jspc.bat" goto okHome
+echo The JASPER_HOME environment variable is not defined correctly
+echo This environment variable is needed to run this program
+goto end
+:okHome
+
+set EXECUTABLE=%JASPER_HOME%\bin\jasper.bat
+
+rem Check that target executable exists
+if exist "%EXECUTABLE%" goto okExec
+echo Cannot find %EXECUTABLE%
+echo This file is needed to run this program
+goto end
+:okExec
+
+rem Get remaining unshifted command line arguments and save them in the
+set CMD_LINE_ARGS=
+:setArgs
+if ""%1""=="""" goto doneSetArgs
+set CMD_LINE_ARGS=%CMD_LINE_ARGS% %1
+shift
+goto setArgs
+:doneSetArgs
+
+call "%EXECUTABLE%" jspc %CMD_LINE_ARGS%
+
+:end

Added: branches/tomcat5.5/upstream/5.5.20/jasper/src/bin/jspc.sh
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/jasper/src/bin/jspc.sh	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/jasper/src/bin/jspc.sh	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,36 @@
+#!/bin/sh
+# -----------------------------------------------------------------------------
+# Script to run the Jasper "offline JSP compiler"
+#
+# $Id: jspc.sh 305555 2003-02-21 18:23:14Z kinman $
+# -----------------------------------------------------------------------------
+
+# resolve links - $0 may be a softlink
+PRG="$0"
+
+while [ -h "$PRG" ] ; do
+  ls=`ls -ld "$PRG"`
+  link=`expr "$ls" : '.*-> \(.*\)$'`
+  if expr "$link" : '.*/.*' > /dev/null; then
+    PRG="$link"
+  else
+    PRG=`dirname "$PRG"`/"$link"
+  fi
+done
+ 
+PRGDIR=`dirname "$PRG"`
+EXECUTABLE=jasper.sh
+
+# Check that target executable exists
+if [ ! -x "$PRGDIR"/"$EXECUTABLE" ]; then
+  echo "Cannot find $PRGDIR/$EXECUTABLE"
+  echo "This file is needed to run this program"
+  exit 1
+fi
+
+if [ "$1" = "debug" ]; then
+  shift
+  exec "$PRGDIR"/"$EXECUTABLE" debug "$@"
+else
+  exec "$PRGDIR"/"$EXECUTABLE" jspc "$@"
+fi

Added: branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/Constants.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/Constants.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/Constants.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,194 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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;
+
+
+/**
+ * Some constants and other global data that are used by the compiler and the runtime.
+ *
+ * @author Anil K. Vijendran
+ * @author Harish Prabandham
+ * @author Shawn Bayern
+ * @author Mark Roth
+ */
+public class Constants {
+    /**
+     * The base class of the generated servlets. 
+     */
+    public static final String JSP_SERVLET_BASE = "org.apache.jasper.runtime.HttpJspBase";
+
+    /**
+     * _jspService is the name of the method that is called by 
+     * HttpJspBase.service(). This is where most of the code generated
+     * from JSPs go.
+     */
+    public static final String SERVICE_METHOD_NAME = "_jspService";
+
+    /**
+     * Default servlet content type.
+     */
+    public static final String SERVLET_CONTENT_TYPE = "text/html";
+
+    /**
+     * These classes/packages are automatically imported by the
+     * generated code. 
+     */
+    public static final String[] STANDARD_IMPORTS = { 
+	"javax.servlet.*", 
+	"javax.servlet.http.*", 
+	"javax.servlet.jsp.*"
+    };
+
+    /**
+     * FIXME
+     * ServletContext attribute for classpath. This is tomcat specific. 
+     * Other servlet engines may choose to support this attribute if they 
+     * want to have this JSP engine running on them. 
+     */
+    public static final String SERVLET_CLASSPATH = "org.apache.catalina.jsp_classpath";
+
+    /**
+     * FIXME
+     * Request attribute for <code>&lt;jsp-file&gt;</code> element of a
+     * servlet definition.  If present on a request, this overrides the
+     * value returned by <code>request.getServletPath()</code> to select
+     * the JSP page to be executed.
+     */
+    public static final String JSP_FILE = "org.apache.catalina.jsp_file";
+
+
+    /**
+     * FIXME
+     * ServletContext attribute for class loader. This is tomcat specific. 
+     * Other servlet engines can choose to have this attribute if they 
+     * want to have this JSP engine running on them. 
+     */
+    //public static final String SERVLET_CLASS_LOADER = "org.apache.tomcat.classloader";
+    public static final String SERVLET_CLASS_LOADER = "org.apache.catalina.classloader";
+
+    /**
+     * Default size of the JSP buffer.
+     */
+    public static final int K = 1024;
+    public static final int DEFAULT_BUFFER_SIZE = 8*K;
+
+    /**
+     * Default size for the tag buffers.
+     */
+    public static final int DEFAULT_TAG_BUFFER_SIZE = 512;
+
+    /**
+     * Default tag handler pool size.
+     */
+    public static final int MAX_POOL_SIZE = 5;
+
+    /**
+     * The query parameter that causes the JSP engine to just
+     * pregenerated the servlet but not invoke it. 
+     */
+    public static final String PRECOMPILE = "jsp_precompile";
+
+    /**
+     * The default package name for compiled jsp pages.
+     */
+    public static final String JSP_PACKAGE_NAME = "org.apache.jsp";
+
+    /**
+     * The default package name for tag handlers generated from tag files
+     */
+    public static final String TAG_FILE_PACKAGE_NAME = "org.apache.jsp.tag";
+
+    /**
+     * Servlet context and request attributes that the JSP engine
+     * uses. 
+     */
+    public static final String INC_REQUEST_URI = "javax.servlet.include.request_uri";
+    public static final String INC_SERVLET_PATH = "javax.servlet.include.servlet_path";
+    public static final String TMP_DIR = "javax.servlet.context.tempdir";
+    public static final String FORWARD_SEEN = "javax.servlet.forward.seen";
+
+    // Must be kept in sync with org/apache/catalina/Globals.java
+    public static final String ALT_DD_ATTR = "org.apache.catalina.deploy.alt_dd";
+
+    /**
+     * Public Id and the Resource path (of the cached copy) 
+     * of the DTDs for tag library descriptors. 
+     */
+    public static final String TAGLIB_DTD_PUBLIC_ID_11 = 
+	"-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.1//EN";
+    public static final String TAGLIB_DTD_RESOURCE_PATH_11 = 
+	"/javax/servlet/jsp/resources/web-jsptaglibrary_1_1.dtd";
+    public static final String TAGLIB_DTD_PUBLIC_ID_12 = 
+	"-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN";
+    public static final String TAGLIB_DTD_RESOURCE_PATH_12 = 
+	"/javax/servlet/jsp/resources/web-jsptaglibrary_1_2.dtd";
+
+    /**
+     * Public Id and the Resource path (of the cached copy) 
+     * of the DTDs for web application deployment descriptors
+     */
+    public static final String WEBAPP_DTD_PUBLIC_ID_22 = 
+	"-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN";
+    public static final String WEBAPP_DTD_RESOURCE_PATH_22 = 
+	"/javax/servlet/resources/web-app_2_2.dtd";
+    public static final String WEBAPP_DTD_PUBLIC_ID_23 = 
+	"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN";
+    public static final String WEBAPP_DTD_RESOURCE_PATH_23 = 
+	"/javax/servlet/resources/web-app_2_3.dtd";
+
+    /**
+     * List of the Public IDs that we cache, and their
+     * associated location. This is used by 
+     * an EntityResolver to return the location of the
+     * cached copy of a DTD.
+     */
+    public static final String[] CACHED_DTD_PUBLIC_IDS = {
+	TAGLIB_DTD_PUBLIC_ID_11,
+	TAGLIB_DTD_PUBLIC_ID_12,
+	WEBAPP_DTD_PUBLIC_ID_22,
+	WEBAPP_DTD_PUBLIC_ID_23,
+    };
+    public static final String[] CACHED_DTD_RESOURCE_PATHS = {
+	TAGLIB_DTD_RESOURCE_PATH_11,
+	TAGLIB_DTD_RESOURCE_PATH_12,
+	WEBAPP_DTD_RESOURCE_PATH_22,
+	WEBAPP_DTD_RESOURCE_PATH_23,
+    };
+    
+    /**
+     * Default URLs to download the pluging for Netscape and IE.
+     */
+    public static final String NS_PLUGIN_URL = 
+        "http://java.sun.com/products/plugin/";
+
+    public static final String IE_PLUGIN_URL = 
+        "http://java.sun.com/products/plugin/1.2.2/jinstall-1_2_2-win.cab#Version=1,2,2,0";
+
+    /**
+     * Prefix to use for generated temporary variable names
+     */
+    public static final String TEMP_VARIABLE_NAME_PREFIX =
+        "_jspx_temp";
+
+    /**
+     * A replacement char for "\$".
+     * XXX This is a hack to avoid changing EL interpreter to recognize "\$"
+     */
+    public static final char ESC='\u001b';
+    public static final String ESCStr="'\\u001b'";
+}
+

Added: branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/EmbeddedServletOptions.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/EmbeddedServletOptions.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/EmbeddedServletOptions.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,651 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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;
+
+import java.io.File;
+import java.util.*;
+
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletContext;
+
+import org.apache.jasper.compiler.TldLocationsCache;
+import org.apache.jasper.compiler.JspConfig;
+import org.apache.jasper.compiler.TagPluginManager;
+import org.apache.jasper.compiler.Localizer;
+import org.apache.jasper.xmlparser.ParserUtils;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * A class to hold all init parameters specific to the JSP engine. 
+ *
+ * @author Anil K. Vijendran
+ * @author Hans Bergsten
+ * @author Pierre Delisle
+ */
+public final class EmbeddedServletOptions implements Options {
+    
+    // Logger
+    private Log log = LogFactory.getLog(EmbeddedServletOptions.class);
+    
+    private Properties settings = new Properties();
+    
+    /**
+     * Is Jasper being used in development mode?
+     */
+    private boolean development = true;
+    
+    /**
+     * Should Ant fork its java compiles of JSP pages.
+     */
+    public boolean fork = true;
+    
+    /**
+     * Do you want to keep the generated Java files around?
+     */
+    private boolean keepGenerated = true;
+    
+    /**
+     * Should white spaces between directives or actions be trimmed?
+     */
+    private boolean trimSpaces = false;
+    
+    /**
+     * Determines whether tag handler pooling is enabled.
+     */
+    private boolean isPoolingEnabled = true;
+    
+    /**
+     * Do you want support for "mapped" files? This will generate
+     * servlet that has a print statement per line of the JSP file.
+     * This seems like a really nice feature to have for debugging.
+     */
+    private boolean mappedFile = true;
+    
+    /**
+     * Do you want stack traces and such displayed in the client's
+     * browser? If this is false, such messages go to the standard
+     * error or a log file if the standard error is redirected. 
+     */
+    private boolean sendErrorToClient = false;
+    
+    /**
+     * Do we want to include debugging information in the class file?
+     */
+    private boolean classDebugInfo = true;
+    
+    /**
+     * Background compile thread check interval in seconds.
+     */
+    private int checkInterval = 0;
+    
+    /**
+     * Is the generation of SMAP info for JSR45 debuggin suppressed?
+     */
+    private boolean isSmapSuppressed = false;
+    
+    /**
+     * Should SMAP info for JSR45 debugging be dumped to a file?
+     */
+    private boolean isSmapDumped = false;
+    
+    /**
+     * Are Text strings to be generated as char arrays?
+     */
+    private boolean genStringAsCharArray = false;
+    
+    private boolean errorOnUseBeanInvalidClassAttribute = true;
+    
+    /**
+     * I want to see my generated servlets. Which directory are they
+     * in?
+     */
+    private File scratchDir;
+    
+    /**
+     * Need to have this as is for versions 4 and 5 of IE. Can be set from
+     * the initParams so if it changes in the future all that is needed is
+     * to have a jsp initParam of type ieClassId="<value>"
+     */
+    private String ieClassId = "clsid:8AD9C840-044E-11D1-B3E9-00805F499D93";
+    
+    /**
+     * What classpath should I use while compiling generated servlets?
+     */
+    private String classpath = null;
+    
+    /**
+     * Compiler to use.
+     */
+    private String compiler = null;
+    
+    /**
+     * Compiler target VM.
+     */
+    private String compilerTargetVM = "1.5";
+    
+    /**
+     * The compiler source VM.
+     */
+    private String compilerSourceVM = "1.5";
+    
+    /**
+     * Cache for the TLD locations
+     */
+    private TldLocationsCache tldLocationsCache = null;
+    
+    /**
+     * Jsp config information
+     */
+    private JspConfig jspConfig = null;
+    
+    /**
+     * TagPluginManager
+     */
+    private TagPluginManager tagPluginManager = null;
+    
+    /**
+     * Java platform encoding to generate the JSP
+     * page servlet.
+     */
+    private String javaEncoding = "UTF8";
+    
+    /**
+     * Modification test interval.
+     */
+    private int modificationTestInterval = 4;
+    
+    /**
+     * Is generation of X-Powered-By response header enabled/disabled?
+     */
+    private boolean xpoweredBy;
+    
+    public String getProperty(String name ) {
+        return settings.getProperty( name );
+    }
+    
+    public void setProperty(String name, String value ) {
+        if (name != null && value != null){ 
+            settings.setProperty( name, value );
+        }
+    }
+    
+    /**
+     * Are we keeping generated code around?
+     */
+    public boolean getKeepGenerated() {
+        return keepGenerated;
+    }
+    
+    /**
+     * Should white spaces between directives or actions be trimmed?
+     */
+    public boolean getTrimSpaces() {
+        return trimSpaces;
+    }
+    
+    public boolean isPoolingEnabled() {
+        return isPoolingEnabled;
+    }
+    
+    /**
+     * Are we supporting HTML mapped servlets?
+     */
+    public boolean getMappedFile() {
+        return mappedFile;
+    }
+    
+    /**
+     * Should errors be sent to client or thrown into stderr?
+     */
+    public boolean getSendErrorToClient() {
+        return sendErrorToClient;
+    }
+    
+    /**
+     * Should class files be compiled with debug information?
+     */
+    public boolean getClassDebugInfo() {
+        return classDebugInfo;
+    }
+    
+    /**
+     * Background JSP compile thread check intervall
+     */
+    public int getCheckInterval() {
+        return checkInterval;
+    }
+    
+    /**
+     * Modification test interval.
+     */
+    public int getModificationTestInterval() {
+        return modificationTestInterval;
+    }
+    
+    /**
+     * Is Jasper being used in development mode?
+     */
+    public boolean getDevelopment() {
+        return development;
+    }
+    
+    /**
+     * Is the generation of SMAP info for JSR45 debuggin suppressed?
+     */
+    public boolean isSmapSuppressed() {
+        return isSmapSuppressed;
+    }
+    
+    /**
+     * Should SMAP info for JSR45 debugging be dumped to a file?
+     */
+    public boolean isSmapDumped() {
+        return isSmapDumped;
+    }
+    
+    /**
+     * Are Text strings to be generated as char arrays?
+     */
+    public boolean genStringAsCharArray() {
+        return this.genStringAsCharArray;
+    }
+    
+    /**
+     * Class ID for use in the plugin tag when the browser is IE. 
+     */
+    public String getIeClassId() {
+        return ieClassId;
+    }
+    
+    /**
+     * What is my scratch dir?
+     */
+    public File getScratchDir() {
+        return scratchDir;
+    }
+    
+    /**
+     * What classpath should I use while compiling the servlets
+     * generated from JSP files?
+     */
+    public String getClassPath() {
+        return classpath;
+    }
+    
+    /**
+     * Is generation of X-Powered-By response header enabled/disabled?
+     */
+    public boolean isXpoweredBy() {
+        return xpoweredBy;
+    }
+    
+    /**
+     * Compiler to use.
+     */
+    public String getCompiler() {
+        return compiler;
+    }
+    
+    /**
+     * @see Options#getCompilerTargetVM
+     */
+    public String getCompilerTargetVM() {
+        return compilerTargetVM;
+    }
+    
+    /**
+     * @see Options#getCompilerSourceVM
+     */
+    public String getCompilerSourceVM() {
+        return compilerSourceVM;
+    }
+    
+    public boolean getErrorOnUseBeanInvalidClassAttribute() {
+        return errorOnUseBeanInvalidClassAttribute;
+    }
+    
+    public void setErrorOnUseBeanInvalidClassAttribute(boolean b) {
+        errorOnUseBeanInvalidClassAttribute = b;
+    }
+    
+    public TldLocationsCache getTldLocationsCache() {
+        return tldLocationsCache;
+    }
+    
+    public void setTldLocationsCache( TldLocationsCache tldC ) {
+        tldLocationsCache = tldC;
+    }
+    
+    public String getJavaEncoding() {
+        return javaEncoding;
+    }
+    
+    public boolean getFork() {
+        return fork;
+    }
+    
+    public JspConfig getJspConfig() {
+        return jspConfig;
+    }
+    
+    public TagPluginManager getTagPluginManager() {
+        return tagPluginManager;
+    }
+    
+    public boolean isCaching() {
+        return false;
+    }
+    
+    public Map getCache() {
+        return null;
+    }
+
+    /**
+     * Create an EmbeddedServletOptions object using data available from
+     * ServletConfig and ServletContext. 
+     */
+    public EmbeddedServletOptions(ServletConfig config,
+            ServletContext context) {
+        
+        // JVM version numbers
+        try {
+            if (Float.parseFloat(System.getProperty("java.specification.version")) > 1.4) {
+                compilerSourceVM = compilerTargetVM = "1.5";
+            } else {
+                compilerSourceVM = compilerTargetVM = "1.4";
+            }
+        } catch (NumberFormatException e) {
+            // Ignore
+        }
+        
+        Enumeration enumeration=config.getInitParameterNames();
+        while( enumeration.hasMoreElements() ) {
+            String k=(String)enumeration.nextElement();
+            String v=config.getInitParameter( k );
+            setProperty( k, v);
+        }
+        
+        // quick hack
+        String validating=config.getInitParameter( "validating");
+        if( "false".equals( validating )) ParserUtils.validating=false;
+        
+        String keepgen = config.getInitParameter("keepgenerated");
+        if (keepgen != null) {
+            if (keepgen.equalsIgnoreCase("true")) {
+                this.keepGenerated = true;
+            } else if (keepgen.equalsIgnoreCase("false")) {
+                this.keepGenerated = false;
+            } else {
+                if (log.isWarnEnabled()) {
+                    log.warn(Localizer.getMessage("jsp.warning.keepgen"));
+                }
+            }
+        }
+        
+        
+        String trimsp = config.getInitParameter("trimSpaces"); 
+        if (trimsp != null) {
+            if (trimsp.equalsIgnoreCase("true")) {
+                trimSpaces = true;
+            } else if (trimsp.equalsIgnoreCase("false")) {
+                trimSpaces = false;
+            } else {
+                if (log.isWarnEnabled()) {
+                    log.warn(Localizer.getMessage("jsp.warning.trimspaces"));
+                }
+            }
+        }
+        
+        this.isPoolingEnabled = true;
+        String poolingEnabledParam
+        = config.getInitParameter("enablePooling"); 
+        if (poolingEnabledParam != null
+                && !poolingEnabledParam.equalsIgnoreCase("true")) {
+            if (poolingEnabledParam.equalsIgnoreCase("false")) {
+                this.isPoolingEnabled = false;
+            } else {
+                if (log.isWarnEnabled()) {
+                    log.warn(Localizer.getMessage("jsp.warning.enablePooling"));
+                }		       	   
+            }
+        }
+        
+        String mapFile = config.getInitParameter("mappedfile"); 
+        if (mapFile != null) {
+            if (mapFile.equalsIgnoreCase("true")) {
+                this.mappedFile = true;
+            } else if (mapFile.equalsIgnoreCase("false")) {
+                this.mappedFile = false;
+            } else {
+                if (log.isWarnEnabled()) {
+                    log.warn(Localizer.getMessage("jsp.warning.mappedFile"));
+                }
+            }
+        }
+        
+        String senderr = config.getInitParameter("sendErrToClient");
+        if (senderr != null) {
+            if (senderr.equalsIgnoreCase("true")) {
+                this.sendErrorToClient = true;
+            } else if (senderr.equalsIgnoreCase("false")) {
+                this.sendErrorToClient = false;
+            } else {
+                if (log.isWarnEnabled()) {
+                    log.warn(Localizer.getMessage("jsp.warning.sendErrToClient"));
+                }
+            }
+        }
+        
+        String debugInfo = config.getInitParameter("classdebuginfo");
+        if (debugInfo != null) {
+            if (debugInfo.equalsIgnoreCase("true")) {
+                this.classDebugInfo  = true;
+            } else if (debugInfo.equalsIgnoreCase("false")) {
+                this.classDebugInfo  = false;
+            } else {
+                if (log.isWarnEnabled()) {
+                    log.warn(Localizer.getMessage("jsp.warning.classDebugInfo"));
+                }
+            }
+        }
+        
+        String checkInterval = config.getInitParameter("checkInterval");
+        if (checkInterval != null) {
+            try {
+                this.checkInterval = Integer.parseInt(checkInterval);
+                if (this.checkInterval == 0) {
+                    this.checkInterval = 300;
+                    if (log.isWarnEnabled()) {
+                        log.warn(Localizer.getMessage("jsp.warning.checkInterval"));
+                    }
+                }
+            } catch(NumberFormatException ex) {
+                if (log.isWarnEnabled()) {
+                    log.warn(Localizer.getMessage("jsp.warning.checkInterval"));
+                }
+            }
+        }
+        
+        String modificationTestInterval = config.getInitParameter("modificationTestInterval");
+        if (modificationTestInterval != null) {
+            try {
+                this.modificationTestInterval = Integer.parseInt(modificationTestInterval);
+            } catch(NumberFormatException ex) {
+                if (log.isWarnEnabled()) {
+                    log.warn(Localizer.getMessage("jsp.warning.modificationTestInterval"));
+                }
+            }
+        }
+        
+        String development = config.getInitParameter("development");
+        if (development != null) {
+            if (development.equalsIgnoreCase("true")) {
+                this.development = true;
+            } else if (development.equalsIgnoreCase("false")) {
+                this.development = false;
+            } else {
+                if (log.isWarnEnabled()) {
+                    log.warn(Localizer.getMessage("jsp.warning.development"));
+                }
+            }
+        }
+        
+        String suppressSmap = config.getInitParameter("suppressSmap");
+        if (suppressSmap != null) {
+            if (suppressSmap.equalsIgnoreCase("true")) {
+                isSmapSuppressed = true;
+            } else if (suppressSmap.equalsIgnoreCase("false")) {
+                isSmapSuppressed = false;
+            } else {
+                if (log.isWarnEnabled()) {
+                    log.warn(Localizer.getMessage("jsp.warning.suppressSmap"));
+                }
+            }
+        }
+        
+        String dumpSmap = config.getInitParameter("dumpSmap");
+        if (dumpSmap != null) {
+            if (dumpSmap.equalsIgnoreCase("true")) {
+                isSmapDumped = true;
+            } else if (dumpSmap.equalsIgnoreCase("false")) {
+                isSmapDumped = false;
+            } else {
+                if (log.isWarnEnabled()) {
+                    log.warn(Localizer.getMessage("jsp.warning.dumpSmap"));
+                }
+            }
+        }
+        
+        String genCharArray = config.getInitParameter("genStrAsCharArray");
+        if (genCharArray != null) {
+            if (genCharArray.equalsIgnoreCase("true")) {
+                genStringAsCharArray = true;
+            } else if (genCharArray.equalsIgnoreCase("false")) {
+                genStringAsCharArray = false;
+            } else {
+                if (log.isWarnEnabled()) {
+                    log.warn(Localizer.getMessage("jsp.warning.genchararray"));
+                }
+            }
+        }
+        
+        String errBeanClass =
+            config.getInitParameter("errorOnUseBeanInvalidClassAttribute");
+        if (errBeanClass != null) {
+            if (errBeanClass.equalsIgnoreCase("true")) {
+                errorOnUseBeanInvalidClassAttribute = true;
+            } else if (errBeanClass.equalsIgnoreCase("false")) {
+                errorOnUseBeanInvalidClassAttribute = false;
+            } else {
+                if (log.isWarnEnabled()) {
+                    log.warn(Localizer.getMessage("jsp.warning.errBean"));
+                }
+            }
+        }
+        
+        String ieClassId = config.getInitParameter("ieClassId");
+        if (ieClassId != null)
+            this.ieClassId = ieClassId;
+        
+        String classpath = config.getInitParameter("classpath");
+        if (classpath != null)
+            this.classpath = classpath;
+        
+        /*
+         * scratchdir
+         */
+        String dir = config.getInitParameter("scratchdir"); 
+        if (dir != null) {
+            scratchDir = new File(dir);
+        } else {
+            // First try the Servlet 2.2 javax.servlet.context.tempdir property
+            scratchDir = (File) context.getAttribute(Constants.TMP_DIR);
+            if (scratchDir == null) {
+                // Not running in a Servlet 2.2 container.
+                // Try to get the JDK 1.2 java.io.tmpdir property
+                dir = System.getProperty("java.io.tmpdir");
+                if (dir != null)
+                    scratchDir = new File(dir);
+            }
+        }      
+        if (this.scratchDir == null) {
+            log.fatal(Localizer.getMessage("jsp.error.no.scratch.dir"));
+            return;
+        }
+        
+        if (!(scratchDir.exists() && scratchDir.canRead() &&
+                scratchDir.canWrite() && scratchDir.isDirectory()))
+            log.fatal(Localizer.getMessage("jsp.error.bad.scratch.dir",
+                    scratchDir.getAbsolutePath()));
+        
+        this.compiler = config.getInitParameter("compiler");
+        
+        String compilerTargetVM = config.getInitParameter("compilerTargetVM");
+        if(compilerTargetVM != null) {
+            this.compilerTargetVM = compilerTargetVM;
+        }
+        
+        String compilerSourceVM = config.getInitParameter("compilerSourceVM");
+        if(compilerSourceVM != null) {
+            this.compilerSourceVM = compilerSourceVM;
+        }
+        
+        String javaEncoding = config.getInitParameter("javaEncoding");
+        if (javaEncoding != null) {
+            this.javaEncoding = javaEncoding;
+        }
+        
+        String fork = config.getInitParameter("fork");
+        if (fork != null) {
+            if (fork.equalsIgnoreCase("true")) {
+                this.fork = true;
+            } else if (fork.equalsIgnoreCase("false")) {
+                this.fork = false;
+            } else {
+                if (log.isWarnEnabled()) {
+                    log.warn(Localizer.getMessage("jsp.warning.fork"));
+                }
+            }
+        }
+        
+        String xpoweredBy = config.getInitParameter("xpoweredBy"); 
+        if (xpoweredBy != null) {
+            if (xpoweredBy.equalsIgnoreCase("true")) {
+                this.xpoweredBy = true;
+            } else if (xpoweredBy.equalsIgnoreCase("false")) {
+                this.xpoweredBy = false;
+            } else {
+                if (log.isWarnEnabled()) {
+                    log.warn(Localizer.getMessage("jsp.warning.xpoweredBy"));
+                }
+            }
+        }
+        
+        // Setup the global Tag Libraries location cache for this
+        // web-application.
+        tldLocationsCache = new TldLocationsCache(context);
+        
+        // Setup the jsp config info for this web app.
+        jspConfig = new JspConfig(context);
+        
+        // Create a Tag plugin instance
+        tagPluginManager = new TagPluginManager(context);
+    }
+    
+}
+

Added: branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/JasperException.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/JasperException.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/JasperException.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,45 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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;
+
+/**
+ * Base class for all exceptions generated by the JSP engine. Makes it
+ * convienient to catch just this at the top-level. 
+ *
+ * @author Anil K. Vijendran
+ */
+public class JasperException extends javax.servlet.ServletException {
+    
+    public JasperException(String reason) {
+	super(reason);
+    }
+
+    /**
+     * Creates a JasperException with the embedded exception and the reason for
+     * throwing a JasperException
+     */
+    public JasperException (String reason, Throwable exception) {
+   	super(reason, exception);
+    }
+
+    /**
+     * Creates a JasperException with the embedded exception
+     */
+    public JasperException (Throwable exception) {
+   	super(exception);
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/JspC.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/JspC.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/JspC.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,1400 @@
+/*
+ * Copyright 1999,2004-2005 The Apache Software Foundation.
+ *
+ * Licensed 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;
+
+import java.io.BufferedReader;
+import java.io.CharArrayWriter;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.Writer;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.HashMap;
+import java.util.Stack;
+import java.util.StringTokenizer;
+import java.util.Vector;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.jasper.compiler.Compiler;
+import org.apache.jasper.compiler.JspConfig;
+import org.apache.jasper.compiler.JspRuntimeContext;
+import org.apache.jasper.compiler.Localizer;
+import org.apache.jasper.compiler.TagPluginManager;
+import org.apache.jasper.compiler.TldLocationsCache;
+import org.apache.jasper.servlet.JspCServletContext;
+
+import org.apache.tools.ant.AntClassLoader;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.util.FileUtils;
+
+/**
+ * Shell for the jspc compiler.  Handles all options associated with the
+ * command line and creates compilation contexts which it then compiles
+ * according to the specified options.
+ *
+ * This version can process files from a _single_ webapp at once, i.e.
+ * a single docbase can be specified.
+ *
+ * It can be used as an Ant task using:
+ * <pre>
+ *   &lt;taskdef classname="org.apache.jasper.JspC" name="jasper2" &gt;
+ *      &lt;classpath&gt;
+ *          &lt;pathelement location="${java.home}/../lib/tools.jar"/&gt;
+ *          &lt;fileset dir="${ENV.CATALINA_HOME}/server/lib"&gt;
+ *              &lt;include name="*.jar"/&gt;
+ *          &lt;/fileset&gt;
+ *          &lt;fileset dir="${ENV.CATALINA_HOME}/common/lib"&gt;
+ *              &lt;include name="*.jar"/&gt;
+ *          &lt;/fileset&gt;
+ *          &lt;path refid="myjars"/&gt;
+ *       &lt;/classpath&gt;
+ *  &lt;/taskdef&gt;
+ *
+ *  &lt;jasper2 verbose="0"
+ *           package="my.package"
+ *           uriroot="${webapps.dir}/${webapp.name}"
+ *           webXmlFragment="${build.dir}/generated_web.xml"
+ *           outputDir="${webapp.dir}/${webapp.name}/WEB-INF/src/my/package" /&gt;
+ * </pre>
+ *
+ * @author Danno Ferrin
+ * @author Pierre Delisle
+ * @author Costin Manolache
+ * @author Yoav Shapira
+ */
+public class JspC implements Options {
+
+    public static final String DEFAULT_IE_CLASS_ID =
+            "clsid:8AD9C840-044E-11D1-B3E9-00805F499D93";
+
+    // Logger
+    private static Log log = LogFactory.getLog(JspC.class);
+
+    private static final String SWITCH_VERBOSE = "-v";
+    private static final String SWITCH_HELP = "-help";
+    private static final String SWITCH_QUIET = "-q";
+    private static final String SWITCH_OUTPUT_DIR = "-d";
+    private static final String SWITCH_IE_CLASS_ID = "-ieplugin";
+    private static final String SWITCH_PACKAGE_NAME = "-p";
+    private static final String SWITCH_CACHE = "-cache";
+    private static final String SWITCH_CLASS_NAME = "-c";
+    private static final String SWITCH_FULL_STOP = "--";
+    private static final String SWITCH_COMPILE = "-compile";
+    private static final String SWITCH_SOURCE = "-source";
+    private static final String SWITCH_TARGET = "-target";
+    private static final String SWITCH_URI_BASE = "-uribase";
+    private static final String SWITCH_URI_ROOT = "-uriroot";
+    private static final String SWITCH_FILE_WEBAPP = "-webapp";
+    private static final String SWITCH_WEBAPP_INC = "-webinc";
+    private static final String SWITCH_WEBAPP_XML = "-webxml";
+    private static final String SWITCH_MAPPED = "-mapped";
+    private static final String SWITCH_XPOWERED_BY = "-xpoweredBy";
+    private static final String SWITCH_TRIM_SPACES = "-trimSpaces";
+    private static final String SWITCH_CLASSPATH = "-classpath";
+    private static final String SWITCH_DIE = "-die";
+    private static final String SWITCH_POOLING = "-poolingEnabled";
+    private static final String SWITCH_ENCODING = "-javaEncoding";
+    private static final String SWITCH_SMAP = "-smap";
+    private static final String SWITCH_DUMP_SMAP = "-dumpsmap";
+
+    private static final String SHOW_SUCCESS ="-s";
+    private static final String LIST_ERRORS = "-l";
+    private static final int NO_WEBXML = 0;
+    private static final int INC_WEBXML = 10;
+    private static final int ALL_WEBXML = 20;
+    private static final int DEFAULT_DIE_LEVEL = 1;
+    private static final int NO_DIE_LEVEL = 0;
+
+    private static final String[] insertBefore =
+    { "</web-app>", "<servlet-mapping>", "<session-config>",
+      "<mime-mapping>", "<welcome-file-list>", "<error-page>", "<taglib>",
+      "<resource-env-ref>", "<resource-ref>", "<security-constraint>",
+      "<login-config>", "<security-role>", "<env-entry>", "<ejb-ref>",
+      "<ejb-local-ref>" };
+
+    private static int die;
+    private String classPath = null;
+    private URLClassLoader loader = null;
+    private boolean trimSpaces = false;
+    private boolean genStringAsCharArray = false;
+    private boolean xpoweredBy;
+    private boolean mappedFile = false;
+    private boolean poolingEnabled = true;
+    private File scratchDir;
+    private String ieClassId = DEFAULT_IE_CLASS_ID;
+    private String targetPackage;
+    private String targetClassName;
+    private String uriBase;
+    private String uriRoot;
+    private Project project;
+    private int dieLevel;
+    private boolean helpNeeded = false;
+    private boolean compile = false;
+    private boolean smapSuppressed = true;
+    private boolean smapDumped = false;
+    private boolean caching = true;
+    private Map cache = new HashMap();
+
+    private String compiler = null;
+
+    private String compilerTargetVM = "1.4";
+    private String compilerSourceVM = "1.4";
+
+    private boolean classDebugInfo = true;
+
+    /**
+     * Throw an exception if there's a compilation error, or swallow it.
+     * Default is true to preserve old behavior.
+     */
+    private boolean failOnError = true;
+
+    /**
+     * The file extensions to be handled as JSP files.
+     * Default list is .jsp and .jspx.
+     */
+    private List extensions;
+
+    /**
+     * The pages.
+     */
+    private List pages = new Vector();
+
+    /**
+     * Needs better documentation, this data member does.
+     * True by default.
+     */
+    private boolean errorOnUseBeanInvalidClassAttribute = true;
+
+    /**
+     * The java file encoding.  Default
+     * is UTF-8.  Added per bugzilla 19622.
+     */
+    private String javaEncoding = "UTF-8";
+
+    // Generation of web.xml fragments
+    private String webxmlFile;
+    private int webxmlLevel;
+    private boolean addWebXmlMappings = false;
+
+    private Writer mapout;
+    private CharArrayWriter servletout;
+    private CharArrayWriter mappingout;
+
+    /**
+     * The servlet context.
+     */
+    private JspCServletContext context;
+
+    /**
+     * The runtime context.
+     * Maintain a dummy JspRuntimeContext for compiling tag files.
+     */
+    private JspRuntimeContext rctxt;
+
+    /**
+     * Cache for the TLD locations
+     */
+    private TldLocationsCache tldLocationsCache = null;
+
+    private JspConfig jspConfig = null;
+    private TagPluginManager tagPluginManager = null;
+
+    private boolean verbose = false;
+    private boolean listErrors = false;
+    private boolean showSuccess = false;
+    private int argPos;
+    private boolean fullstop = false;
+    private String args[];
+
+    public static void main(String arg[]) {
+        if (arg.length == 0) {
+            System.out.println(Localizer.getMessage("jspc.usage"));
+        } else {
+            try {
+                JspC jspc = new JspC();
+                jspc.setArgs(arg);
+                if (jspc.helpNeeded) {
+                    System.out.println(Localizer.getMessage("jspc.usage"));
+                } else {
+                    jspc.execute();
+                }
+            } catch (JasperException je) {
+                System.err.println(je);
+                //System.err.println(je.getMessage());
+                if (die != NO_DIE_LEVEL) {
+                    System.exit(die);
+                }
+            }
+        }
+    }
+
+    public void setArgs(String[] arg) throws JasperException {
+        args = arg;
+        String tok;
+
+        dieLevel = NO_DIE_LEVEL;
+        die = dieLevel;
+
+        while ((tok = nextArg()) != null) {
+            if (tok.equals(SWITCH_VERBOSE)) {
+                verbose = true;
+                showSuccess = true;
+                listErrors = true;
+            } else if (tok.equals(SWITCH_OUTPUT_DIR)) {
+                tok = nextArg();
+                setOutputDir( tok );
+            } else if (tok.equals(SWITCH_PACKAGE_NAME)) {
+                targetPackage = nextArg();
+            } else if (tok.equals(SWITCH_COMPILE)) {
+                compile=true;
+            } else if (tok.equals(SWITCH_CLASS_NAME)) {
+                targetClassName = nextArg();
+            } else if (tok.equals(SWITCH_URI_BASE)) {
+                uriBase=nextArg();
+            } else if (tok.equals(SWITCH_URI_ROOT)) {
+                setUriroot( nextArg());
+            } else if (tok.equals(SWITCH_FILE_WEBAPP)) {
+                setUriroot( nextArg());
+            } else if ( tok.equals( SHOW_SUCCESS ) ) {
+                showSuccess = true;
+            } else if ( tok.equals( LIST_ERRORS ) ) {
+                listErrors = true;
+            } else if (tok.equals(SWITCH_WEBAPP_INC)) {
+                webxmlFile = nextArg();
+                if (webxmlFile != null) {
+                    webxmlLevel = INC_WEBXML;
+                }
+            } else if (tok.equals(SWITCH_WEBAPP_XML)) {
+                webxmlFile = nextArg();
+                if (webxmlFile != null) {
+                    webxmlLevel = ALL_WEBXML;
+                }
+            } else if (tok.equals(SWITCH_MAPPED)) {
+                mappedFile = true;
+            } else if (tok.equals(SWITCH_XPOWERED_BY)) {
+                xpoweredBy = true;
+            } else if (tok.equals(SWITCH_TRIM_SPACES)) {
+                setTrimSpaces(true);
+            } else if (tok.equals(SWITCH_CACHE)) {
+                tok = nextArg();
+                if ("false".equals(tok)) {
+                    caching = false;
+                } else {
+                    caching = true;
+                }            
+            } else if (tok.equals(SWITCH_CLASSPATH)) {
+                setClassPath(nextArg());
+            } else if (tok.startsWith(SWITCH_DIE)) {
+                try {
+                    dieLevel = Integer.parseInt(
+                        tok.substring(SWITCH_DIE.length()));
+                } catch (NumberFormatException nfe) {
+                    dieLevel = DEFAULT_DIE_LEVEL;
+                }
+                die = dieLevel;
+            } else if (tok.equals(SWITCH_HELP)) {
+                helpNeeded = true;
+            } else if (tok.equals(SWITCH_POOLING)) {
+                tok = nextArg();
+                if ("false".equals(tok)) {
+                    poolingEnabled = false;
+                } else {
+                    poolingEnabled = true;
+                }
+            } else if (tok.equals(SWITCH_ENCODING)) {
+                setJavaEncoding(nextArg());
+            } else if (tok.equals(SWITCH_SOURCE)) {
+                setCompilerSourceVM(nextArg());
+            } else if (tok.equals(SWITCH_TARGET)) {
+                setCompilerTargetVM(nextArg());
+            } else if (tok.equals(SWITCH_SMAP)) {
+                smapSuppressed = false;
+            } else if (tok.equals(SWITCH_DUMP_SMAP)) {
+                smapDumped = true;
+            } else {
+                if (tok.startsWith("-")) {
+                    throw new JasperException("Unrecognized option: " + tok +
+                        ".  Use -help for help.");
+                }
+                if (!fullstop) {
+                    argPos--;
+                }
+                // Start treating the rest as JSP Pages
+                break;
+            }
+        }
+
+        // Add all extra arguments to the list of files
+        while( true ) {
+            String file = nextFile();
+            if( file==null ) {
+                break;
+            }
+            pages.add( file );
+        }
+    }
+
+    public boolean getKeepGenerated() {
+        // isn't this why we are running jspc?
+        return true;
+    }
+
+    public boolean getTrimSpaces() {
+        return trimSpaces;
+    }
+
+    public void setTrimSpaces(boolean ts) {
+        this.trimSpaces = ts;
+    }
+
+    public boolean isPoolingEnabled() {
+        return poolingEnabled;
+    }
+
+    public void setPoolingEnabled(boolean poolingEnabled) {
+        this.poolingEnabled = poolingEnabled;
+    }
+
+    public boolean isXpoweredBy() {
+        return xpoweredBy;
+    }
+
+    public void setXpoweredBy(boolean xpoweredBy) {
+        this.xpoweredBy = xpoweredBy;
+    }
+
+    public boolean getErrorOnUseBeanInvalidClassAttribute() {
+        return errorOnUseBeanInvalidClassAttribute;
+    }
+
+    public void setErrorOnUseBeanInvalidClassAttribute(boolean b) {
+        errorOnUseBeanInvalidClassAttribute = b;
+    }
+
+    public int getTagPoolSize() {
+        return Constants.MAX_POOL_SIZE;
+    }
+
+    /**
+     * Are we supporting HTML mapped servlets?
+     */
+    public boolean getMappedFile() {
+        return mappedFile;
+    }
+
+    // Off-line compiler, no need for security manager
+    public Object getProtectionDomain() {
+        return null;
+    }
+
+    public boolean getSendErrorToClient() {
+        // implied send to System.err
+        return true;
+    }
+
+    public void setClassDebugInfo( boolean b ) {
+        classDebugInfo=b;
+    }
+
+    public boolean getClassDebugInfo() {
+        // compile with debug info
+        return classDebugInfo;
+    }
+
+     /**
+      * @see Options#isCaching()
+     */
+    public boolean isCaching() {
+        return caching;
+    }
+
+    /**
+     * @see Options#isCaching()
+     */
+    public void setCaching(boolean caching) {
+        this.caching = caching;
+    }
+
+    /**
+     * @see Options#getCache()
+     */
+    public Map getCache() {
+        return cache;
+    }
+
+    /**
+     * Background compilation check intervals in seconds
+     */
+    public int getCheckInterval() {
+        return 0;
+    }
+
+    /**
+     * Modification test interval.
+     */
+    public int getModificationTestInterval() {
+        return 0;
+    }
+
+    /**
+     * Is Jasper being used in development mode?
+     */
+    public boolean getDevelopment() {
+        return false;
+    }
+
+    /**
+     * Is the generation of SMAP info for JSR45 debuggin suppressed?
+     */
+    public boolean isSmapSuppressed() {
+        return smapSuppressed;
+    }
+
+    /**
+     * Set smapSuppressed flag.
+     */
+    public void setSmapSuppressed(boolean smapSuppressed) {
+        this.smapSuppressed = smapSuppressed;
+    }
+
+    
+    /**
+     * Should SMAP info for JSR45 debugging be dumped to a file?
+     */
+    public boolean isSmapDumped() {
+        return smapDumped;
+    }
+
+    /**
+     * Set smapSuppressed flag.
+     */
+    public void setSmapDumped(boolean smapDumped) {
+        this.smapDumped = smapDumped;
+    }
+
+    
+    /**
+     * Determines whether text strings are to be generated as char arrays,
+     * which improves performance in some cases.
+     *
+     * @param genStringAsCharArray true if text strings are to be generated as
+     * char arrays, false otherwise
+     */
+    public void setGenStringAsCharArray(boolean genStringAsCharArray) {
+        this.genStringAsCharArray = genStringAsCharArray;
+    }
+
+    /**
+     * Indicates whether text strings are to be generated as char arrays.
+     *
+     * @return true if text strings are to be generated as char arrays, false
+     * otherwise
+     */
+    public boolean genStringAsCharArray() {
+        return genStringAsCharArray;
+    }
+
+    /**
+     * Sets the class-id value to be sent to Internet Explorer when using
+     * <jsp:plugin> tags.
+     *
+     * @param ieClassId Class-id value
+     */
+    public void setIeClassId(String ieClassId) {
+        this.ieClassId = ieClassId;
+    }
+
+    /**
+     * Gets the class-id value that is sent to Internet Explorer when using
+     * <jsp:plugin> tags.
+     *
+     * @return Class-id value
+     */
+    public String getIeClassId() {
+        return ieClassId;
+    }
+
+    public File getScratchDir() {
+        return scratchDir;
+    }
+
+    public Class getJspCompilerPlugin() {
+       // we don't compile, so this is meanlingless
+        return null;
+    }
+
+    public String getJspCompilerPath() {
+       // we don't compile, so this is meanlingless
+        return null;
+    }
+
+    /**
+     * Compiler to use.
+     */
+    public String getCompiler() {
+        return compiler;
+    }
+
+    public void setCompiler(String c) {
+        compiler=c;
+    }
+
+    /**
+     * @see Options#getCompilerTargetVM
+     */
+    public String getCompilerTargetVM() {
+        return compilerTargetVM;
+    }
+
+    public void setCompilerTargetVM(String vm) {
+        compilerTargetVM = vm;
+    }
+
+    /**
+     * @see Options#getCompilerSourceVM()
+     */
+     public String getCompilerSourceVM() {
+         return compilerSourceVM;
+     }
+        
+    /**
+     * @see Options#getCompilerSourceVM()
+     */
+    public void setCompilerSourceVM(String vm) {
+        compilerSourceVM = vm;
+    }
+
+    public TldLocationsCache getTldLocationsCache() {
+        return tldLocationsCache;
+    }
+
+    /**
+     * Returns the encoding to use for
+     * java files.  The default is UTF-8.
+     *
+     * @return String The encoding
+     */
+    public String getJavaEncoding() {
+        return javaEncoding;
+    }
+
+    /**
+     * Sets the encoding to use for
+     * java files.
+     *
+     * @param encodingName The name, e.g. "UTF-8"
+     */
+    public void setJavaEncoding(String encodingName) {
+        javaEncoding = encodingName;
+    }
+
+    public boolean getFork() {
+        return false;
+    }
+
+    public String getClassPath() {
+        if( classPath != null )
+            return classPath;
+        return System.getProperty("java.class.path");
+    }
+
+    public void setClassPath(String s) {
+        classPath=s;
+    }
+
+    /**
+     * Returns the list of file extensions
+     * that are treated as JSP files.
+     *
+     * @return The list of extensions
+     */
+    public List getExtensions() {
+        return extensions;
+    }
+
+    /**
+     * Adds the given file extension to the
+     * list of extensions handled as JSP files.
+     *
+     * @param extension The extension to add, e.g. "myjsp"
+     */
+    protected void addExtension(final String extension) {
+        if(extension != null) {
+            if(extensions == null) {
+                extensions = new Vector();
+            }
+
+            extensions.add(extension);
+        }
+    }
+
+    /**
+     * Sets the project.
+     *
+     * @param theProject The project
+     */
+    public void setProject(final Project theProject) {
+        project = theProject;
+    }
+
+    /**
+     * Returns the project: may be null if not running
+     * inside an Ant project.
+     *
+     * @return The project
+     */
+    public Project getProject() {
+        return project;
+    }
+
+    /**
+     * Base dir for the webapp. Used to generate class names and resolve
+     * includes
+     */
+    public void setUriroot( String s ) {
+        if( s==null ) {
+            uriRoot = s;
+            return;
+        }
+        try {
+            uriRoot = resolveFile(s).getCanonicalPath();
+        } catch( Exception ex ) {
+            uriRoot = s;
+        }
+    }
+
+    /**
+     * Parses comma-separated list of JSP files to be processed.  If the argument
+     * is null, nothing is done.
+     *
+     * <p>Each file is interpreted relative to uriroot, unless it is absolute,
+     * in which case it must start with uriroot.</p>
+     *
+     * @param jspFiles Comma-separated list of JSP files to be processed
+     */
+    public void setJspFiles(final String jspFiles) {
+        if(jspFiles == null) {
+            return;
+        }
+
+        StringTokenizer tok = new StringTokenizer(jspFiles, ",");
+        while (tok.hasMoreTokens()) {
+            pages.add(tok.nextToken());
+        }
+    }
+
+    /**
+     * Sets the compile flag.
+     *
+     * @param b Flag value
+     */
+    public void setCompile( final boolean b ) {
+        compile = b;
+    }
+
+    /**
+     * Sets the verbosity level.  The actual number doesn't
+     * matter: if it's greater than zero, the verbose flag will
+     * be true.
+     *
+     * @param level Positive means verbose
+     */
+    public void setVerbose( final int level ) {
+        if (level > 0) {
+            verbose = true;
+            showSuccess = true;
+            listErrors = true;
+        }
+    }
+
+    public void setValidateXml( boolean b ) {
+        org.apache.jasper.xmlparser.ParserUtils.validating=b;
+    }
+
+    public void setListErrors( boolean b ) {
+        listErrors = b;
+    }
+
+    public void setOutputDir( String s ) {
+        if( s!= null ) {
+            scratchDir = resolveFile(s).getAbsoluteFile();
+        } else {
+            scratchDir=null;
+        }
+    }
+
+    public void setPackage( String p ) {
+        targetPackage=p;
+    }
+
+    /**
+     * Class name of the generated file ( without package ).
+     * Can only be used if a single file is converted.
+     * XXX Do we need this feature ?
+     */
+    public void setClassName( String p ) {
+        targetClassName=p;
+    }
+
+    /**
+     * File where we generate a web.xml fragment with the class definitions.
+     */
+    public void setWebXmlFragment( String s ) {
+        webxmlFile=resolveFile(s).getAbsolutePath();
+        webxmlLevel=INC_WEBXML;
+    }
+
+    /**
+     * File where we generate a complete web.xml with the class definitions.
+     */
+    public void setWebXml( String s ) {
+        webxmlFile=resolveFile(s).getAbsolutePath();
+        webxmlLevel=ALL_WEBXML;
+    }
+
+    public void setAddWebXmlMappings(boolean b) {
+        addWebXmlMappings = b;
+    }
+
+    /**
+     * Set the option that throws an exception in case of a compilation error.
+     */
+    public void setFailOnError(final boolean b) {
+        failOnError = b;
+    }
+
+    public boolean getFailOnError() {
+        return failOnError;
+    }
+
+    /**
+     * Obtain JSP configuration informantion specified in web.xml.
+     */
+    public JspConfig getJspConfig() {
+        return jspConfig;
+    }
+
+    public TagPluginManager getTagPluginManager() {
+        return tagPluginManager;
+    }
+
+    public void generateWebMapping( String file, JspCompilationContext clctxt )
+        throws IOException
+    {
+        String className = clctxt.getServletClassName();
+        String packageName = clctxt.getServletPackageName();
+
+        String thisServletName;
+        if  ("".equals(packageName)) {
+            thisServletName = className;
+        } else {
+            thisServletName = packageName + '.' + className;
+        }
+
+        if (servletout != null) {
+            servletout.write("\n    <servlet>\n        <servlet-name>");
+            servletout.write(thisServletName);
+            servletout.write("</servlet-name>\n        <servlet-class>");
+            servletout.write(thisServletName);
+            servletout.write("</servlet-class>\n    </servlet>\n");
+        }
+        if (mappingout != null) {
+            mappingout.write("\n    <servlet-mapping>\n        <servlet-name>");
+            mappingout.write(thisServletName);
+            mappingout.write("</servlet-name>\n        <url-pattern>");
+            mappingout.write(file.replace('\\', '/'));
+            mappingout.write("</url-pattern>\n    </servlet-mapping>\n");
+
+        }
+    }
+
+    /**
+     * Include the generated web.xml inside the webapp's web.xml.
+     */
+    protected void mergeIntoWebXml() throws IOException {
+
+        File webappBase = new File(uriRoot);
+        File webXml = new File(webappBase, "WEB-INF/web.xml");
+        File webXml2 = new File(webappBase, "WEB-INF/web2.xml");
+        String insertStartMarker =
+            Localizer.getMessage("jspc.webinc.insertStart");
+        String insertEndMarker =
+            Localizer.getMessage("jspc.webinc.insertEnd");
+
+        BufferedReader reader = new BufferedReader(new FileReader(webXml));
+        BufferedReader fragmentReader =
+            new BufferedReader(new FileReader(webxmlFile));
+        PrintWriter writer = new PrintWriter(new FileWriter(webXml2));
+
+        // Insert the <servlet> and <servlet-mapping> declarations
+        int pos = -1;
+        String line = null;
+        while (true) {
+            line = reader.readLine();
+            if (line == null) {
+                break;
+            }
+            // Skip anything previously generated by JSPC
+            if (line.indexOf(insertStartMarker) >= 0) {
+                while (true) {
+                    line = reader.readLine();
+                    if (line == null) {
+                        return;
+                    }
+                    if (line.indexOf(insertEndMarker) >= 0) {
+                        line = reader.readLine();
+                        line = reader.readLine();
+                        if (line == null) {
+                            return;
+                        }
+                        break;
+                    }
+                }
+            }
+            for (int i = 0; i < insertBefore.length; i++) {
+                pos = line.indexOf(insertBefore[i]);
+                if (pos >= 0)
+                    break;
+            }
+            if (pos >= 0) {
+                writer.print(line.substring(0, pos));
+                break;
+            } else {
+                writer.println(line);
+            }
+        }
+
+        writer.println(insertStartMarker);
+        while (true) {
+            String line2 = fragmentReader.readLine();
+            if (line2 == null) {
+                writer.println();
+                break;
+            }
+            writer.println(line2);
+        }
+        writer.println(insertEndMarker);
+        writer.println();
+
+        for (int i = 0; i < pos; i++) {
+            writer.print(" ");
+        }
+        writer.println(line.substring(pos));
+
+        while (true) {
+            line = reader.readLine();
+            if (line == null) {
+                break;
+            }
+            writer.println(line);
+        }
+        writer.close();
+
+        reader.close();
+        fragmentReader.close();
+
+        FileInputStream fis = new FileInputStream(webXml2);
+        FileOutputStream fos = new FileOutputStream(webXml);
+
+        byte buf[] = new byte[512];
+        while (true) {
+            int n = fis.read(buf);
+            if (n < 0) {
+                break;
+            }
+            fos.write(buf, 0, n);
+        }
+
+        fis.close();
+        fos.close();
+
+        webXml2.delete();
+        (new File(webxmlFile)).delete();
+
+    }
+
+    private void processFile(String file)
+        throws JasperException
+    {
+        ClassLoader originalClassLoader = null;
+
+        try {
+            // set up a scratch/output dir if none is provided
+            if (scratchDir == null) {
+                String temp = System.getProperty("java.io.tmpdir");
+                if (temp == null) {
+                    temp = "";
+                }
+                scratchDir = new File(new File(temp).getAbsolutePath());
+            }
+
+            String jspUri=file.replace('\\','/');
+            JspCompilationContext clctxt = new JspCompilationContext
+                ( jspUri, false,  this, context, null, rctxt );
+
+            /* Override the defaults */
+            if ((targetClassName != null) && (targetClassName.length() > 0)) {
+                clctxt.setServletClassName(targetClassName);
+                targetClassName = null;
+            }
+            if (targetPackage != null) {
+                clctxt.setServletPackageName(targetPackage);
+            }
+
+            originalClassLoader = Thread.currentThread().getContextClassLoader();
+            if( loader==null ) {
+                initClassLoader( clctxt );
+            }
+            Thread.currentThread().setContextClassLoader(loader);
+
+            clctxt.setClassLoader(loader);
+            clctxt.setClassPath(classPath);
+
+            Compiler clc = clctxt.createCompiler();
+
+            // If compile is set, generate both .java and .class, if
+            // .jsp file is newer than .class file;
+            // Otherwise only generate .java, if .jsp file is newer than
+            // the .java file
+            if( clc.isOutDated(compile) ) {
+                clc.compile(compile, true);
+            }
+
+            // Generate mapping
+            generateWebMapping( file, clctxt );
+            if ( showSuccess ) {
+                log.info( "Built File: " + file );
+            }
+
+        } catch (JasperException je) {
+            Throwable rootCause = je;
+            while (rootCause instanceof JasperException
+                    && ((JasperException) rootCause).getRootCause() != null) {
+                rootCause = ((JasperException) rootCause).getRootCause();
+            }
+            if (rootCause != je) {
+                log.error(Localizer.getMessage("jspc.error.generalException",
+                                               file),
+                          rootCause);
+            }
+
+            // Bugzilla 35114.
+            if(getFailOnError()) {
+                throw je;
+            } else {
+                log.error(je.getMessage());
+            }
+
+        } catch (Exception e) {
+            if ((e instanceof FileNotFoundException) && log.isWarnEnabled()) {
+                log.warn(Localizer.getMessage("jspc.error.fileDoesNotExist",
+                                              e.getMessage()));
+            }
+            throw new JasperException(e);
+        } finally {
+            if(originalClassLoader != null) {
+                Thread.currentThread().setContextClassLoader(originalClassLoader);
+            }
+        }
+    }
+
+    /**
+     * Locate all jsp files in the webapp. Used if no explicit
+     * jsps are specified.
+     */
+    public void scanFiles( File base ) throws JasperException {
+        Stack dirs = new Stack();
+        dirs.push(base);
+
+        // Make sure default extensions are always included
+        if ((getExtensions() == null) || (getExtensions().size() < 2)) {
+            addExtension("jsp");
+            addExtension("jspx");
+        }
+
+        while (!dirs.isEmpty()) {
+            String s = dirs.pop().toString();
+            File f = new File(s);
+            if (f.exists() && f.isDirectory()) {
+                String[] files = f.list();
+                String ext;
+                for (int i = 0; (files != null) && i < files.length; i++) {
+                    File f2 = new File(s, files[i]);
+                    if (f2.isDirectory()) {
+                        dirs.push(f2.getPath());
+                    } else {
+                        String path = f2.getPath();
+                        String uri = path.substring(uriRoot.length());
+                        ext = files[i].substring(files[i].lastIndexOf('.') +1);
+                        if (getExtensions().contains(ext) ||
+                            jspConfig.isJspPage(uri)) {
+                            pages.add(path);
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Executes the compilation.
+     *
+     * @throws JasperException If an error occurs
+     */
+    public void execute() throws JasperException {
+        if(log.isDebugEnabled()) {
+            log.debug("execute() starting for " + pages.size() + " pages.");
+        }
+
+        try {
+            if (uriRoot == null) {
+                if( pages.size() == 0 ) {
+                    throw new JasperException(
+                        Localizer.getMessage("jsp.error.jspc.missingTarget"));
+                }
+                String firstJsp = (String) pages.get( 0 );
+                File firstJspF = new File( firstJsp );
+                if (!firstJspF.exists()) {
+                    throw new JasperException(
+                        Localizer.getMessage("jspc.error.fileDoesNotExist",
+                                             firstJsp));
+                }
+                locateUriRoot( firstJspF );
+            }
+
+            if (uriRoot == null) {
+                throw new JasperException(
+                    Localizer.getMessage("jsp.error.jspc.no_uriroot"));
+            }
+
+            if( context==null ) {
+                initServletContext();
+            }
+
+            // No explicit pages, we'll process all .jsp in the webapp
+            if (pages.size() == 0) {
+                scanFiles( new File( uriRoot ));
+            }
+
+            File uriRootF = new File(uriRoot);
+            if (!uriRootF.exists() || !uriRootF.isDirectory()) {
+                throw new JasperException(
+                    Localizer.getMessage("jsp.error.jspc.uriroot_not_dir"));
+            }
+
+            initWebXml();
+
+            Iterator iter = pages.iterator();
+            while (iter.hasNext()) {
+                String nextjsp = iter.next().toString();
+                File fjsp = new File(nextjsp);
+                if (!fjsp.isAbsolute()) {
+                    fjsp = new File(uriRootF, nextjsp);
+                }
+                if (!fjsp.exists()) {
+                    if (log.isWarnEnabled()) {
+                        log.warn
+                            (Localizer.getMessage
+                             ("jspc.error.fileDoesNotExist", fjsp.toString()));
+                    }
+                    continue;
+                }
+                String s = fjsp.getAbsolutePath();
+                if (s.startsWith(uriRoot)) {
+                    nextjsp = s.substring(uriRoot.length());
+                }
+                if (nextjsp.startsWith("." + File.separatorChar)) {
+                    nextjsp = nextjsp.substring(2);
+                }
+                processFile(nextjsp);
+            }
+
+            completeWebXml();
+
+            if (addWebXmlMappings) {
+                mergeIntoWebXml();
+            }
+
+        } catch (IOException ioe) {
+            throw new JasperException(ioe);
+
+        } catch (JasperException je) {
+            Throwable rootCause = je;
+            while (rootCause instanceof JasperException
+                    && ((JasperException) rootCause).getRootCause() != null) {
+                rootCause = ((JasperException) rootCause).getRootCause();
+            }
+            if (rootCause != je) {
+                rootCause.printStackTrace();
+            }
+            throw je;
+        } finally {
+            if (loader != null) {
+                LogFactory.release(loader);
+            }
+        }
+    }
+
+    // ==================== Private utility methods ====================
+
+    private String nextArg() {
+        if ((argPos >= args.length)
+            || (fullstop = SWITCH_FULL_STOP.equals(args[argPos]))) {
+            return null;
+        } else {
+            return args[argPos++];
+        }
+    }
+
+    private String nextFile() {
+        if (fullstop) argPos++;
+        if (argPos >= args.length) {
+            return null;
+        } else {
+            return args[argPos++];
+        }
+    }
+
+    private void initWebXml() {
+        try {
+            if (webxmlLevel >= INC_WEBXML) {
+                File fmapings = new File(webxmlFile);
+                mapout = new FileWriter(fmapings);
+                servletout = new CharArrayWriter();
+                mappingout = new CharArrayWriter();
+            } else {
+                mapout = null;
+                servletout = null;
+                mappingout = null;
+            }
+            if (webxmlLevel >= ALL_WEBXML) {
+                mapout.write(Localizer.getMessage("jspc.webxml.header"));
+                mapout.flush();
+            } else if ((webxmlLevel>= INC_WEBXML) && !addWebXmlMappings) {
+                mapout.write(Localizer.getMessage("jspc.webinc.header"));
+                mapout.flush();
+            }
+        } catch (IOException ioe) {
+            mapout = null;
+            servletout = null;
+            mappingout = null;
+        }
+    }
+
+    private void completeWebXml() {
+        if (mapout != null) {
+            try {
+                servletout.writeTo(mapout);
+                mappingout.writeTo(mapout);
+                if (webxmlLevel >= ALL_WEBXML) {
+                    mapout.write(Localizer.getMessage("jspc.webxml.footer"));
+                } else if ((webxmlLevel >= INC_WEBXML) && !addWebXmlMappings) {
+                    mapout.write(Localizer.getMessage("jspc.webinc.footer"));
+                }
+                mapout.close();
+            } catch (IOException ioe) {
+                // noting to do if it fails since we are done with it
+            }
+        }
+    }
+
+    private void initServletContext() {
+        try {
+            context =new JspCServletContext
+                (new PrintWriter(System.out),
+                 new URL("file:" + uriRoot.replace('\\','/') + '/'));
+            tldLocationsCache = new TldLocationsCache(context, true);
+        } catch (MalformedURLException me) {
+            System.out.println("**" + me);
+        }
+        rctxt = new JspRuntimeContext(context, this);
+        jspConfig = new JspConfig(context);
+        tagPluginManager = new TagPluginManager(context);
+    }
+
+    /**
+     * Initializes the classloader as/if needed for the given
+     * compilation context.
+     *
+     * @param clctxt The compilation context
+     * @throws IOException If an error occurs
+     */
+    private void initClassLoader(JspCompilationContext clctxt)
+        throws IOException {
+
+        classPath = getClassPath();
+
+        ClassLoader jspcLoader = getClass().getClassLoader();
+        if (jspcLoader instanceof AntClassLoader) {
+            classPath += File.pathSeparator
+                + ((AntClassLoader) jspcLoader).getClasspath();
+        }
+
+        // Turn the classPath into URLs
+        ArrayList urls = new ArrayList();
+        StringTokenizer tokenizer = new StringTokenizer(classPath,
+                                                        File.pathSeparator);
+        while (tokenizer.hasMoreTokens()) {
+            String path = tokenizer.nextToken();
+            try {
+                File libFile = new File(path);
+                urls.add(libFile.toURL());
+            } catch (IOException ioe) {
+                // Failing a toCanonicalPath on a file that
+                // exists() should be a JVM regression test,
+                // therefore we have permission to freak uot
+                throw new RuntimeException(ioe.toString());
+            }
+        }
+
+        File webappBase = new File(uriRoot);
+        if (webappBase.exists()) {
+            File classes = new File(webappBase, "/WEB-INF/classes");
+            try {
+                if (classes.exists()) {
+                    classPath = classPath + File.pathSeparator
+                        + classes.getCanonicalPath();
+                    urls.add(classes.getCanonicalFile().toURL());
+                }
+            } catch (IOException ioe) {
+                // failing a toCanonicalPath on a file that
+                // exists() should be a JVM regression test,
+                // therefore we have permission to freak out
+                throw new RuntimeException(ioe.toString());
+            }
+            File lib = new File(webappBase, "/WEB-INF/lib");
+            if (lib.exists() && lib.isDirectory()) {
+                String[] libs = lib.list();
+                for (int i = 0; i < libs.length; i++) {
+                    if( libs[i].length() <5 ) continue;
+                    String ext=libs[i].substring( libs[i].length() - 4 );
+                    if (! ".jar".equalsIgnoreCase(ext)) {
+                        if (".tld".equalsIgnoreCase(ext)) {
+                            log.warn("TLD files should not be placed in "
+                                     + "/WEB-INF/lib");
+                        }
+                        continue;
+                    }
+                    try {
+                        File libFile = new File(lib, libs[i]);
+                        classPath = classPath + File.pathSeparator
+                            + libFile.getAbsolutePath();
+                        urls.add(libFile.getAbsoluteFile().toURL());
+                    } catch (IOException ioe) {
+                        // failing a toCanonicalPath on a file that
+                        // exists() should be a JVM regression test,
+                        // therefore we have permission to freak out
+                        throw new RuntimeException(ioe.toString());
+                    }
+                }
+            }
+        }
+
+        // What is this ??
+        urls.add(new File(clctxt.getRealPath("/")).getCanonicalFile().toURL());
+
+        URL urlsA[]=new URL[urls.size()];
+        urls.toArray(urlsA);
+        loader = new URLClassLoader(urlsA, this.getClass().getClassLoader());
+
+    }
+
+    /**
+     * Find the WEB-INF dir by looking up in the directory tree.
+     * This is used if no explicit docbase is set, but only files.
+     * XXX Maybe we should require the docbase.
+     */
+    private void locateUriRoot( File f ) {
+        String tUriBase = uriBase;
+        if (tUriBase == null) {
+            tUriBase = "/";
+        }
+        try {
+            if (f.exists()) {
+                f = new File(f.getAbsolutePath());
+                while (f != null) {
+                    File g = new File(f, "WEB-INF");
+                    if (g.exists() && g.isDirectory()) {
+                        uriRoot = f.getCanonicalPath();
+                        uriBase = tUriBase;
+                        if (log.isInfoEnabled()) {
+                            log.info(Localizer.getMessage(
+                                        "jspc.implicit.uriRoot",
+                                        uriRoot));
+                        }
+                        break;
+                    }
+                    if (f.exists() && f.isDirectory()) {
+                        tUriBase = "/" + f.getName() + "/" + tUriBase;
+                    }
+
+                    String fParent = f.getParent();
+                    if (fParent == null) {
+                        break;
+                    } else {
+                        f = new File(fParent);
+                    }
+
+                    // If there is no acceptible candidate, uriRoot will
+                    // remain null to indicate to the CompilerContext to
+                    // use the current working/user dir.
+                }
+
+                if (uriRoot != null) {
+                    File froot = new File(uriRoot);
+                    uriRoot = froot.getCanonicalPath();
+                }
+            }
+        } catch (IOException ioe) {
+            // since this is an optional default and a null value
+            // for uriRoot has a non-error meaning, we can just
+            // pass straight through
+        }
+    }
+
+    /**
+     * Resolves the relative or absolute pathname correctly
+     * in both Ant and command-line situations.  If Ant launched
+     * us, we should use the basedir of the current project
+     * to resolve relative paths.
+     *
+     * See Bugzilla 35571.
+     *
+     * @param s The file
+     * @return The file resolved
+     */
+     protected File resolveFile(final String s) {
+         if(getProject() == null) {
+             // Note FileUtils.getFileUtils replaces FileUtils.newFileUtils in Ant 1.6.3
+             return FileUtils.newFileUtils().resolveFile(null, s);
+         } else {
+             return FileUtils.newFileUtils().resolveFile(getProject().getBaseDir(), s);
+         }
+     }
+}

Added: branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/JspCompilationContext.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/JspCompilationContext.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/JspCompilationContext.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,705 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.Hashtable;
+import java.util.Set;
+
+import javax.servlet.ServletContext;
+import javax.servlet.jsp.tagext.TagInfo;
+
+import org.apache.jasper.compiler.Compiler;
+import org.apache.jasper.compiler.JspRuntimeContext;
+import org.apache.jasper.compiler.JspUtil;
+import org.apache.jasper.compiler.Localizer;
+import org.apache.jasper.compiler.ServletWriter;
+import org.apache.jasper.servlet.JasperLoader;
+import org.apache.jasper.servlet.JspServletWrapper;
+
+/**
+ * A place holder for various things that are used through out the JSP
+ * engine. This is a per-request/per-context data structure. Some of
+ * the instance variables are set at different points.
+ *
+ * Most of the path-related stuff is here - mangling names, versions, dirs,
+ * loading resources and dealing with uris. 
+ *
+ * @author Anil K. Vijendran
+ * @author Harish Prabandham
+ * @author Pierre Delisle
+ * @author Costin Manolache
+ * @author Kin-man Chung
+ */
+public class JspCompilationContext {
+
+    protected org.apache.commons.logging.Log log =
+        org.apache.commons.logging.LogFactory.getLog(JspCompilationContext.class);
+
+    private Hashtable tagFileJarUrls;
+    private boolean isPackagedTagFile;
+
+    private String className;
+    private String jspUri;
+    private boolean isErrPage;
+    private String basePackageName;
+    private String derivedPackageName;
+    private String servletJavaFileName;
+    private String javaPath;
+    private String classFileName;
+    private String contentType;
+    private ServletWriter writer;
+    private Options options;
+    private JspServletWrapper jsw;
+    private Compiler jspCompiler;
+    private String classPath;
+
+    private String baseURI;
+    private String baseOutputDir;
+    private String outputDir;
+    private ServletContext context;
+    private URLClassLoader loader;
+
+    private JspRuntimeContext rctxt;
+
+    private int removed = 0;
+
+    private URLClassLoader jspLoader;
+    private URL baseUrl;
+    private Class servletClass;
+
+    private boolean isTagFile;
+    private boolean protoTypeMode;
+    private TagInfo tagInfo;
+    private URL tagFileJarUrl;
+
+    // jspURI _must_ be relative to the context
+    public JspCompilationContext(String jspUri,
+                                 boolean isErrPage,
+                                 Options options,
+                                 ServletContext context,
+                                 JspServletWrapper jsw,
+                                 JspRuntimeContext rctxt) {
+
+        this.jspUri = canonicalURI(jspUri);
+        this.isErrPage = isErrPage;
+        this.options = options;
+        this.jsw = jsw;
+        this.context = context;
+
+        this.baseURI = jspUri.substring(0, jspUri.lastIndexOf('/') + 1);
+        // hack fix for resolveRelativeURI
+        if (baseURI == null) {
+            baseURI = "/";
+        } else if (baseURI.charAt(0) != '/') {
+            // strip the basde slash since it will be combined with the
+            // uriBase to generate a file
+            baseURI = "/" + baseURI;
+        }
+        if (baseURI.charAt(baseURI.length() - 1) != '/') {
+            baseURI += '/';
+        }
+
+        this.rctxt = rctxt;
+        this.tagFileJarUrls = new Hashtable();
+        this.basePackageName = Constants.JSP_PACKAGE_NAME;
+    }
+
+    public JspCompilationContext(String tagfile,
+                                 TagInfo tagInfo, 
+                                 Options options,
+                                 ServletContext context,
+                                 JspServletWrapper jsw,
+                                 JspRuntimeContext rctxt,
+                                 URL tagFileJarUrl) {
+        this(tagfile, false, options, context, jsw, rctxt);
+        this.isTagFile = true;
+        this.tagInfo = tagInfo;
+        this.tagFileJarUrl = tagFileJarUrl;
+        if (tagFileJarUrl != null) {
+            isPackagedTagFile = true;
+        }
+    }
+
+    /* ==================== Methods to override ==================== */
+    
+    /** ---------- Class path and loader ---------- */
+
+    /**
+     * The classpath that is passed off to the Java compiler. 
+     */
+    public String getClassPath() {
+        if( classPath != null )
+            return classPath;
+        return rctxt.getClassPath();
+    }
+
+    /**
+     * The classpath that is passed off to the Java compiler. 
+     */
+    public void setClassPath(String classPath) {
+        this.classPath = classPath;
+    }
+
+    /**
+     * What class loader to use for loading classes while compiling
+     * this JSP?
+     */
+    public ClassLoader getClassLoader() {
+        if( loader != null )
+            return loader;
+        return rctxt.getParentClassLoader();
+    }
+
+    public void setClassLoader(URLClassLoader loader) {
+        this.loader = loader;
+    }
+
+    public ClassLoader getJspLoader() {
+        if( jspLoader == null ) {
+            jspLoader = new JasperLoader
+            (new URL[] {baseUrl},
+                    getClassLoader(),
+                    rctxt.getPermissionCollection(),
+                    rctxt.getCodeSource());
+        }
+        return jspLoader;
+    }
+
+    /** ---------- Input/Output  ---------- */
+    
+    /**
+     * The output directory to generate code into.  The output directory
+     * is make up of the scratch directory, which is provide in Options,
+     * plus the directory derived from the package name.
+     */
+    public String getOutputDir() {
+	if (outputDir == null) {
+	    createOutputDir();
+	}
+
+        return outputDir;
+    }
+
+    /**
+     * Create a "Compiler" object based on some init param data. This
+     * is not done yet. Right now we're just hardcoding the actual
+     * compilers that are created. 
+     */
+    public Compiler createCompiler() throws JasperException {
+        if (jspCompiler != null ) {
+            return jspCompiler;
+        }
+        jspCompiler = null;
+        if (options.getCompiler() == null) {
+            jspCompiler = createCompiler("org.apache.jasper.compiler.JDTCompiler");
+            if (jspCompiler == null) {
+                jspCompiler = createCompiler("org.apache.jasper.compiler.AntCompiler");
+            }
+        } else {
+            jspCompiler = createCompiler("org.apache.jasper.compiler.AntCompiler");
+            if (jspCompiler == null) {
+                jspCompiler = createCompiler("org.apache.jasper.compiler.JDTCompiler");
+            }
+        }
+        if (jspCompiler == null) {
+            throw new IllegalStateException(Localizer.getMessage("jsp.error.compiler"));
+        }
+        jspCompiler.init(this, jsw);
+        return jspCompiler;
+    }
+
+    private Compiler createCompiler(String className) {
+        Compiler compiler = null; 
+        try {
+            compiler = (Compiler) Class.forName(className).newInstance();
+        } catch (Throwable t) {
+            if (log.isDebugEnabled()) {
+                log.debug(Localizer.getMessage("jsp.error.compiler"), t);
+            }
+        }
+        return compiler;
+    }
+    
+    public Compiler getCompiler() {
+        return jspCompiler;
+    }
+
+    /** ---------- Access resources in the webapp ---------- */
+
+    /** 
+     * Get the full value of a URI relative to this compilations context
+     * uses current file as the base.
+     */
+    public String resolveRelativeUri(String uri) {
+        // sometimes we get uri's massaged from File(String), so check for
+        // a root directory deperator char
+        if (uri.startsWith("/") || uri.startsWith(File.separator)) {
+            return uri;
+        } else {
+            return baseURI + uri;
+        }
+    }
+
+    /**
+     * Gets a resource as a stream, relative to the meanings of this
+     * context's implementation.
+     * @return a null if the resource cannot be found or represented 
+     *         as an InputStream.
+     */
+    public java.io.InputStream getResourceAsStream(String res) {
+        return context.getResourceAsStream(canonicalURI(res));
+    }
+
+
+    public URL getResource(String res) throws MalformedURLException {
+        return context.getResource(canonicalURI(res));
+    }
+
+    public Set getResourcePaths(String path) {
+        return context.getResourcePaths(canonicalURI(path));
+    }
+
+    /** 
+     * Gets the actual path of a URI relative to the context of
+     * the compilation.
+     */
+    public String getRealPath(String path) {
+        if (context != null) {
+            return context.getRealPath(path);
+        }
+        return path;
+    }
+
+    /**
+     * Returns the tag-file-name-to-JAR-file map of this compilation unit,
+     * which maps tag file names to the JAR files in which the tag files are
+     * packaged.
+     *
+     * The map is populated when parsing the tag-file elements of the TLDs
+     * of any imported taglibs. 
+     */
+    public Hashtable getTagFileJarUrls() {
+        return this.tagFileJarUrls;
+    }
+
+    /**
+     * Returns the JAR file in which the tag file for which this
+     * JspCompilationContext was created is packaged, or null if this
+     * JspCompilationContext does not correspond to a tag file, or if the
+     * corresponding tag file is not packaged in a JAR.
+     */
+    public URL getTagFileJarUrl() {
+        return this.tagFileJarUrl;
+    }
+
+    /* ==================== Common implementation ==================== */
+
+    /**
+     * Just the class name (does not include package name) of the
+     * generated class. 
+     */
+    public String getServletClassName() {
+
+        if (className != null) {
+            return className;
+        }
+
+        if (isTagFile) {
+            className = tagInfo.getTagClassName();
+            int lastIndex = className.lastIndexOf('.');
+            if (lastIndex != -1) {
+                className = className.substring(lastIndex + 1);
+            }
+        } else {
+            int iSep = jspUri.lastIndexOf('/') + 1;
+            className = JspUtil.makeJavaIdentifier(jspUri.substring(iSep));
+        }
+        return className;
+    }
+
+    public void setServletClassName(String className) {
+        this.className = className;
+    }
+    
+    /**
+     * Path of the JSP URI. Note that this is not a file name. This is
+     * the context rooted URI of the JSP file. 
+     */
+    public String getJspFile() {
+        return jspUri;
+    }
+
+    /**
+     * Are we processing something that has been declared as an
+     * errorpage? 
+     */
+    public boolean isErrorPage() {
+        return isErrPage;
+    }
+
+    public void setErrorPage(boolean isErrPage) {
+        this.isErrPage = isErrPage;
+    }
+
+    public boolean isTagFile() {
+        return isTagFile;
+    }
+
+    public TagInfo getTagInfo() {
+        return tagInfo;
+    }
+
+    public void setTagInfo(TagInfo tagi) {
+        tagInfo = tagi;
+    }
+
+    /**
+     * True if we are compiling a tag file in prototype mode.
+     * ie we only generate codes with class for the tag handler with empty
+     * method bodies.
+     */
+    public boolean isPrototypeMode() {
+        return protoTypeMode;
+    }
+
+    public void setPrototypeMode(boolean pm) {
+        protoTypeMode = pm;
+    }
+
+    /**
+     * Package name for the generated class is make up of the base package
+     * name, which is user settable, and the derived package name.  The
+     * derived package name directly mirrors the file heirachy of the JSP page.
+     */
+    public String getServletPackageName() {
+        if (isTagFile()) {
+            String className = tagInfo.getTagClassName();
+            int lastIndex = className.lastIndexOf('.');
+            String pkgName = "";
+            if (lastIndex != -1) {
+                pkgName = className.substring(0, lastIndex);
+            }
+            return pkgName;
+        } else {
+            String dPackageName = getDerivedPackageName();
+            if (dPackageName.length() == 0) {
+                return basePackageName;
+            }
+            return basePackageName + '.' + getDerivedPackageName();
+        }
+    }
+
+    private String getDerivedPackageName() {
+        if (derivedPackageName == null) {
+            int iSep = jspUri.lastIndexOf('/');
+            derivedPackageName = (iSep > 0) ?
+                    JspUtil.makeJavaPackage(jspUri.substring(1,iSep)) : "";
+        }
+        return derivedPackageName;
+    }
+	    
+    /**
+     * The package name into which the servlet class is generated.
+     */
+    public void setServletPackageName(String servletPackageName) {
+        this.basePackageName = servletPackageName;
+    }
+
+    /**
+     * Full path name of the Java file into which the servlet is being
+     * generated. 
+     */
+    public String getServletJavaFileName() {
+
+        if (servletJavaFileName == null) {
+            servletJavaFileName =
+		getOutputDir() + getServletClassName() + ".java";
+        } else {
+            // Make sure output dir exists
+            makeOutputDir();
+        }
+        return servletJavaFileName;
+    }
+
+    public void setServletJavaFileName(String servletJavaFileName) {
+        this.servletJavaFileName = servletJavaFileName;
+    }
+
+    /**
+     * Get hold of the Options object for this context. 
+     */
+    public Options getOptions() {
+        return options;
+    }
+
+    public ServletContext getServletContext() {
+        return context;
+    }
+
+    public JspRuntimeContext getRuntimeContext() {
+        return rctxt;
+    }
+
+    /**
+     * Path of the Java file relative to the work directory.
+     */
+    public String getJavaPath() {
+
+        if (javaPath != null) {
+            return javaPath;
+        }
+
+        if (isTagFile()) {
+	    String tagName = tagInfo.getTagClassName();
+            javaPath = tagName.replace('.', '/') + ".java";
+        } else {
+            javaPath = getServletPackageName().replace('.', '/') + '/' +
+                       getServletClassName() + ".java";
+	}
+        return javaPath;
+    }
+
+    public String getClassFileName() {
+
+        if (classFileName == null) {
+            classFileName = getOutputDir() + getServletClassName() + ".class";
+        } else {
+            // Make sure output dir exists
+            makeOutputDir();
+        }
+        return classFileName;
+    }
+
+    /**
+     * Get the content type of this JSP.
+     *
+     * Content type includes content type and encoding.
+     */
+    public String getContentType() {
+        return contentType;
+    }
+
+    public void setContentType(String contentType) {
+        this.contentType = contentType;
+    }
+
+    /**
+     * Where is the servlet being generated?
+     */
+    public ServletWriter getWriter() {
+        return writer;
+    }
+
+    public void setWriter(ServletWriter writer) {
+        this.writer = writer;
+    }
+
+    /**
+     * Gets the 'location' of the TLD associated with the given taglib 'uri'.
+     * 
+     * @return An array of two Strings: The first element denotes the real
+     * path to the TLD. If the path to the TLD points to a jar file, then the
+     * second element denotes the name of the TLD entry in the jar file.
+     * Returns null if the given uri is not associated with any tag library
+     * 'exposed' in the web application.
+     */
+    public String[] getTldLocation(String uri) throws JasperException {
+        String[] location = 
+            getOptions().getTldLocationsCache().getLocation(uri);
+        return location;
+    }
+
+    /**
+     * Are we keeping generated code around?
+     */
+    public boolean keepGenerated() {
+        return getOptions().getKeepGenerated();
+    }
+
+    // ==================== Removal ==================== 
+
+    public void incrementRemoved() {
+        if (removed > 1) {
+            jspCompiler.removeGeneratedFiles();
+            if( rctxt != null )
+                rctxt.removeWrapper(jspUri);
+        }
+        removed++;
+    }
+
+    public boolean isRemoved() {
+        if (removed > 1 ) {
+            return true;
+        }
+        return false;
+    }
+
+    // ==================== Compile and reload ====================
+    
+    public void compile() throws JasperException, FileNotFoundException {
+        createCompiler();
+        if (isPackagedTagFile || jspCompiler.isOutDated()) {
+            try {
+                jspLoader = null;
+                jspCompiler.compile();
+                jsw.setReload(true);
+                jsw.setCompilationException(null);
+            } catch (JasperException ex) {
+                // Cache compilation exception
+                jsw.setCompilationException(ex);
+                throw ex;
+            } catch (Exception ex) {
+                ex.printStackTrace();
+                JasperException je = new JasperException(
+                            Localizer.getMessage("jsp.error.unable.compile"),
+                            ex);
+                // Cache compilation exception
+                jsw.setCompilationException(je);
+                throw je;
+            }
+        }
+    }
+
+    // ==================== Manipulating the class ====================
+
+    public Class load() 
+        throws JasperException, FileNotFoundException
+    {
+        try {
+            getJspLoader();
+            
+            String name;
+            if (isTagFile()) {
+                name = tagInfo.getTagClassName();
+            } else {
+                name = getServletPackageName() + "." + getServletClassName();
+            }
+            servletClass = jspLoader.loadClass(name);
+        } catch (ClassNotFoundException cex) {
+            throw new JasperException(Localizer.getMessage("jsp.error.unable.load"),
+                                      cex);
+        } catch (Exception ex) {
+            throw new JasperException(Localizer.getMessage("jsp.error.unable.compile"),
+                                      ex);
+        }
+        removed = 0;
+        return servletClass;
+    }
+
+    // ==================== Private methods ==================== 
+
+    static Object outputDirLock = new Object();
+
+    private void makeOutputDir() {
+        synchronized(outputDirLock) {
+            File outDirFile = new File(outputDir);
+            outDirFile.mkdirs();
+        }
+    }
+
+    private void createOutputDir() {
+        String path = null;
+        if (isTagFile()) {
+	    String tagName = tagInfo.getTagClassName();
+            path = tagName.replace('.', '/');
+	    path = path.substring(0, path.lastIndexOf('/'));
+        } else {
+            path = getServletPackageName().replace('.', '/');
+	}
+
+        try {
+            // Append servlet or tag handler path to scratch dir
+            baseUrl = options.getScratchDir().toURL();
+            String outUrlString = baseUrl.toString() + '/' + path;
+            URL outUrl = new URL(outUrlString);
+            outputDir = outUrl.getFile() + File.separator;
+            makeOutputDir();
+        } catch (Exception e) {
+            throw new IllegalStateException("No output directory: " +
+                                            e.getMessage());
+        }
+    }
+    
+    private static final boolean isPathSeparator(char c) {
+       return (c == '/' || c == '\\');
+    }
+
+    private static final String canonicalURI(String s) {
+       if (s == null) return null;
+       StringBuffer result = new StringBuffer();
+       final int len = s.length();
+       int pos = 0;
+       while (pos < len) {
+           char c = s.charAt(pos);
+           if ( isPathSeparator(c) ) {
+               /*
+                * multiple path separators.
+                * 'foo///bar' -> 'foo/bar'
+                */
+               while (pos+1 < len && isPathSeparator(s.charAt(pos+1))) {
+                   ++pos;
+               }
+
+               if (pos+1 < len && s.charAt(pos+1) == '.') {
+                   /*
+                    * a single dot at the end of the path - we are done.
+                    */
+                   if (pos+2 >= len) break;
+
+                   switch (s.charAt(pos+2)) {
+                       /*
+                        * self directory in path
+                        * foo/./bar -> foo/bar
+                        */
+                   case '/':
+                   case '\\':
+                       pos += 2;
+                       continue;
+
+                       /*
+                        * two dots in a path: go back one hierarchy.
+                        * foo/bar/../baz -> foo/baz
+                        */
+                   case '.':
+                       // only if we have exactly _two_ dots.
+                       if (pos+3 < len && isPathSeparator(s.charAt(pos+3))) {
+                           pos += 3;
+                           int separatorPos = result.length()-1;
+                           while (separatorPos >= 0 && 
+                                  ! isPathSeparator(result
+                                                    .charAt(separatorPos))) {
+                               --separatorPos;
+                           }
+                           if (separatorPos >= 0)
+                               result.setLength(separatorPos);
+                           continue;
+                       }
+                   }
+               }
+           }
+           result.append(c);
+           ++pos;
+       }
+       return result.toString();
+    }
+}
+

Added: branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/Options.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/Options.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/Options.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,188 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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;
+
+import java.io.File;
+import java.util.Map;
+
+import org.apache.jasper.compiler.JspConfig;
+import org.apache.jasper.compiler.TagPluginManager;
+import org.apache.jasper.compiler.TldLocationsCache;
+
+/**
+ * A class to hold all init parameters specific to the JSP engine. 
+ *
+ * @author Anil K. Vijendran
+ * @author Hans Bergsten
+ * @author Pierre Delisle
+ */
+public interface Options {
+
+    /**
+     * Returns true if Jasper issues a compilation error instead of a runtime
+     * Instantiation error if the class attribute specified in useBean action
+     * is invalid.
+     */
+    public boolean getErrorOnUseBeanInvalidClassAttribute();
+
+    /**
+     * Are we keeping generated code around?
+     */
+    public boolean getKeepGenerated();
+
+    /**
+     * Returns true if tag handler pooling is enabled, false otherwise.
+     */
+    public boolean isPoolingEnabled();
+
+    /**
+     * Are we supporting HTML mapped servlets?
+     */
+    public boolean getMappedFile();
+
+    /**
+     * Should errors be sent to client or thrown into stderr?
+     */
+    public boolean getSendErrorToClient();
+ 
+    /**
+     * Should we include debug information in compiled class?
+     */
+    public boolean getClassDebugInfo();
+
+    /**
+     * Background compile thread check interval in seconds
+     */
+    public int getCheckInterval();
+
+    /**
+     * Is Jasper being used in development mode?
+     */
+    public boolean getDevelopment();
+
+    /**
+     * Is the generation of SMAP info for JSR45 debugging suppressed?
+     */
+    public boolean isSmapSuppressed();
+
+    /**
+     * Indicates whether SMAP info for JSR45 debugging should be dumped to a
+     * file.
+     * Ignored is suppressSmap() is true
+     */
+    public boolean isSmapDumped();
+
+    /**
+     * Should white spaces between directives or actions be trimmed?
+     */
+    public boolean getTrimSpaces();
+
+    /**
+     * Class ID for use in the plugin tag when the browser is IE. 
+     */
+    public String getIeClassId();
+
+    /**
+     * What is my scratch dir?
+     */
+    public File getScratchDir();
+
+    /**
+     * What classpath should I use while compiling the servlets
+     * generated from JSP files?
+     */
+    public String getClassPath();
+
+    /**
+     * Compiler to use.
+     */
+    public String getCompiler();
+
+    /**
+     * The compiler target VM, e.g. 1.1, 1.2, 1.3, 1.4, or 1.5.
+     */
+    public String getCompilerTargetVM();
+
+    /**
+     * Compiler source VM, e.g. 1.3, 1.4, or 1.5.
+     */
+    public String getCompilerSourceVM();   
+
+    /**
+     * The cache for the location of the TLD's
+     * for the various tag libraries 'exposed'
+     * by the web application.
+     * A tag library is 'exposed' either explicitely in 
+     * web.xml or implicitely via the uri tag in the TLD 
+     * of a taglib deployed in a jar file (WEB-INF/lib).
+     *
+     * @return the instance of the TldLocationsCache
+     * for the web-application.
+     */
+    public TldLocationsCache getTldLocationsCache();
+
+    /**
+     * Java platform encoding to generate the JSP
+     * page servlet.
+     */
+    public String getJavaEncoding();
+
+    /**
+     * boolean flag to tell Ant whether to fork JSP page compilations.
+     */
+    public boolean getFork();
+
+    /**
+     * Obtain JSP configuration informantion specified in web.xml.  
+     */
+    public JspConfig getJspConfig();
+
+    /**
+     * Is generation of X-Powered-By response header enabled/disabled?
+     */
+    public boolean isXpoweredBy();
+
+    /**
+     * Obtain a Tag Plugin Manager
+     */
+    public TagPluginManager getTagPluginManager();
+
+    /**
+     * Are Text strings to be generated as char arrays?
+     */
+    public boolean genStringAsCharArray();
+    
+    /**
+     * Modification test interval.
+     */
+    public int getModificationTestInterval();
+    
+    /**
+     * Is caching enabled (used for precompilation).
+     */
+    public boolean isCaching();
+    
+    /**
+     * The web-application wide cache for the returned TreeNode
+     * by parseXMLDocument in TagLibraryInfoImpl.parseTLD,
+     * if isCaching returns true.
+     * 
+     * @return the Map(String uri, TreeNode tld) instance.
+     */
+    public Map getCache();
+    
+}

Added: branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/AntCompiler.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/AntCompiler.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/AntCompiler.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,275 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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 java.io.FileNotFoundException;
+import java.io.PrintStream;
+import java.util.StringTokenizer;
+
+import org.apache.jasper.JasperException;
+import org.apache.jasper.util.SystemLogHandler;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.DefaultLogger;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.taskdefs.Javac;
+import org.apache.tools.ant.types.Path;
+import org.apache.tools.ant.types.PatternSet;
+
+/**
+ * Main JSP compiler class. This class uses Ant for compiling.
+ *
+ * @author Anil K. Vijendran
+ * @author Mandar Raje
+ * @author Pierre Delisle
+ * @author Kin-man Chung
+ * @author Remy Maucherat
+ * @author Mark Roth
+ */
+public class AntCompiler extends Compiler {
+
+    static {
+        System.setErr(new SystemLogHandler(System.err));
+    }
+
+    // ----------------------------------------------------- Instance Variables
+
+    protected Project project=null;
+    protected JasperAntLogger logger;
+
+    // ------------------------------------------------------------ Constructor
+
+    // Lazy eval - if we don't need to compile we probably don't need the project
+    protected Project getProject() {
+        
+        if( project!=null ) return project;
+        
+        // Initializing project
+        project = new Project();
+        logger = new JasperAntLogger();
+        logger.setOutputPrintStream(System.out);
+        logger.setErrorPrintStream(System.err);
+        logger.setMessageOutputLevel(Project.MSG_INFO);
+        project.addBuildListener( logger);
+        if (System.getProperty("catalina.home") != null) {
+            project.setBasedir( System.getProperty("catalina.home"));
+        }
+        
+        if( options.getCompiler() != null ) {
+            if( log.isDebugEnabled() )
+                log.debug("Compiler " + options.getCompiler() );
+            project.setProperty("build.compiler", options.getCompiler() );
+        }
+        project.init();
+        return project;
+    }
+    
+    class JasperAntLogger extends DefaultLogger {
+        
+        protected StringBuffer reportBuf = new StringBuffer();
+        
+        protected void printMessage(final String message,
+                final PrintStream stream,
+                final int priority) {
+        }
+        
+        protected void log(String message) {
+            reportBuf.append(message);
+            reportBuf.append(System.getProperty("line.separator"));
+        }
+        
+        protected String getReport() {
+            String report = reportBuf.toString();
+            reportBuf.setLength(0);
+            return report;
+        }
+    }
+    
+    // --------------------------------------------------------- Public Methods
+
+
+    /** 
+     * Compile the servlet from .java file to .class file
+     */
+    protected void generateClass(String[] smap)
+        throws FileNotFoundException, JasperException, Exception {
+        
+        long t1 = 0;
+        if (log.isDebugEnabled()) {
+            t1 = System.currentTimeMillis();
+        }
+
+        String javaEncoding = ctxt.getOptions().getJavaEncoding();
+        String javaFileName = ctxt.getServletJavaFileName();
+        String classpath = ctxt.getClassPath(); 
+        
+        String sep = System.getProperty("path.separator");
+        
+        StringBuffer errorReport = new StringBuffer();
+        
+        StringBuffer info=new StringBuffer();
+        info.append("Compile: javaFileName=" + javaFileName + "\n" );
+        info.append("    classpath=" + classpath + "\n" );
+        
+        // Start capturing the System.err output for this thread
+        SystemLogHandler.setThread();
+        
+        // Initializing javac task
+        getProject();
+        Javac javac = (Javac) project.createTask("javac");
+        
+        // Initializing classpath
+        Path path = new Path(project);
+        path.setPath(System.getProperty("java.class.path"));
+        info.append("    cp=" + System.getProperty("java.class.path") + "\n");
+        StringTokenizer tokenizer = new StringTokenizer(classpath, sep);
+        while (tokenizer.hasMoreElements()) {
+            String pathElement = tokenizer.nextToken();
+            File repository = new File(pathElement);
+            path.setLocation(repository);
+            info.append("    cp=" + repository + "\n");
+        }
+        
+        if( log.isDebugEnabled() )
+            log.debug( "Using classpath: " + System.getProperty("java.class.path") + sep
+                    + classpath);
+        
+        // Initializing sourcepath
+        Path srcPath = new Path(project);
+        srcPath.setLocation(options.getScratchDir());
+        
+        info.append("    work dir=" + options.getScratchDir() + "\n");
+        
+        // Initialize and set java extensions
+        String exts = System.getProperty("java.ext.dirs");
+        if (exts != null) {
+            Path extdirs = new Path(project);
+            extdirs.setPath(exts);
+            javac.setExtdirs(extdirs);
+            info.append("    extension dir=" + exts + "\n");
+        }
+
+        // Add endorsed directories if any are specified and we're forking
+        // See Bugzilla 31257
+        if(ctxt.getOptions().getFork()) {
+            String endorsed = System.getProperty("java.endorsed.dirs");
+            if(endorsed != null) {
+                Javac.ImplementationSpecificArgument endorsedArg = 
+                    javac.createCompilerArg();
+                endorsedArg.setLine("-J-Djava.endorsed.dirs="+endorsed);
+                info.append("    endorsed dir=" + endorsed + "\n");
+            } else {
+                info.append("    no endorsed dirs specified\n");
+            }
+        }
+        
+        // Configure the compiler object
+        javac.setEncoding(javaEncoding);
+        javac.setClasspath(path);
+        javac.setDebug(ctxt.getOptions().getClassDebugInfo());
+        javac.setSrcdir(srcPath);
+        javac.setTempdir(options.getScratchDir());
+        javac.setOptimize(! ctxt.getOptions().getClassDebugInfo() );
+        javac.setFork(ctxt.getOptions().getFork());
+        info.append("    srcDir=" + srcPath + "\n" );
+        
+        // Set the Java compiler to use
+        if (options.getCompiler() != null) {
+            javac.setCompiler(options.getCompiler());
+            info.append("    compiler=" + options.getCompiler() + "\n");
+        }
+
+        if (options.getCompilerTargetVM() != null) {
+            javac.setTarget(options.getCompilerTargetVM());
+            info.append("   compilerTargetVM=" + options.getCompilerTargetVM() + "\n");
+        }
+
+        if (options.getCompilerSourceVM() != null) {
+            javac.setSource(options.getCompilerSourceVM());
+            info.append("   compilerSourceVM=" + options.getCompilerSourceVM() + "\n");
+        }
+        
+        // Build includes path
+        PatternSet.NameEntry includes = javac.createInclude();
+        
+        includes.setName(ctxt.getJavaPath());
+        info.append("    include="+ ctxt.getJavaPath() + "\n" );
+        
+        BuildException be = null;
+        
+        try {
+            if (ctxt.getOptions().getFork()) {
+                javac.execute();
+            } else {
+                synchronized(javacLock) {
+                    javac.execute();
+                }
+            }
+        } catch (BuildException e) {
+            be = e;
+            log.error( "Javac exception ", e);
+            log.error( "Env: " + info.toString());
+        }
+        
+        errorReport.append(logger.getReport());
+
+        // Stop capturing the System.err output for this thread
+        String errorCapture = SystemLogHandler.unsetThread();
+        if (errorCapture != null) {
+            errorReport.append(System.getProperty("line.separator"));
+            errorReport.append(errorCapture);
+        }
+
+        if (!ctxt.keepGenerated()) {
+            File javaFile = new File(javaFileName);
+            javaFile.delete();
+        }
+        
+        if (be != null) {
+            String errorReportString = errorReport.toString();
+            log.error("Error compiling file: " + javaFileName + " "
+                    + errorReportString);
+            JavacErrorDetail[] javacErrors = ErrorDispatcher.parseJavacErrors(
+                    errorReportString, javaFileName, pageNodes);
+            if (javacErrors != null) {
+                errDispatcher.javacError(javacErrors);
+            } else {
+                errDispatcher.javacError(errorReportString, be);
+            }
+        }
+        
+        if( log.isDebugEnabled() ) {
+            long t2=System.currentTimeMillis();
+            log.debug("Compiled " + ctxt.getServletJavaFileName() + " "
+                      + (t2-t1) + "ms");
+        }
+        
+        logger = null;
+        project = null;
+        
+        if (ctxt.isPrototypeMode()) {
+            return;
+        }
+        
+        // JSR45 Support
+        if (! options.isSmapSuppressed()) {
+            SmapUtil.installSmap(smap);
+        }
+    }
+
+    
+}

Added: branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/BeanRepository.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/BeanRepository.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/BeanRepository.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,114 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.util.Vector;
+import java.util.Hashtable;
+
+import org.apache.jasper.JasperException;
+
+/**
+ * Repository of {page, request, session, application}-scoped beans 
+ *
+ * @author Mandar Raje
+ */
+class BeanRepository {
+
+    private Vector sessionBeans;
+    private Vector pageBeans;
+    private Vector appBeans;
+    private Vector requestBeans;
+    private Hashtable beanTypes;
+    private ClassLoader loader;
+    private ErrorDispatcher errDispatcher;
+
+    /*
+     * Constructor.
+     */    
+    public BeanRepository(ClassLoader loader, ErrorDispatcher err) {
+
+        this.loader = loader;
+	this.errDispatcher = err;
+
+	sessionBeans = new Vector(11);
+	pageBeans = new Vector(11);
+	appBeans = new Vector(11);
+	requestBeans = new Vector(11);
+	beanTypes = new Hashtable();
+    }
+        
+    public void addBean(Node.UseBean n, String s, String type, String scope)
+	    throws JasperException {
+
+	if (scope == null || scope.equals("page")) {
+	    pageBeans.addElement(s);	
+	} else if (scope.equals("request")) {
+	    requestBeans.addElement(s);
+	} else if (scope.equals("session")) {
+	    sessionBeans.addElement(s);
+	} else if (scope.equals("application")) {
+	    appBeans.addElement(s);
+	} else {
+	    errDispatcher.jspError(n, "jsp.error.usebean.badScope");
+	}
+	
+	putBeanType(s, type);
+    }
+            
+    public Class getBeanType(String bean) throws JasperException {
+	Class clazz = null;
+	try {
+	    clazz = loader.loadClass ((String)beanTypes.get(bean));
+	} catch (ClassNotFoundException ex) {
+	    throw new JasperException (ex);
+	}
+	return clazz;
+    }
+      
+    public boolean checkVariable (String bean) {
+	// XXX Not sure if this is the correct way.
+	// After pageContext is finalised this will change.
+	return (checkPageBean(bean) || checkSessionBean(bean) ||
+		checkRequestBean(bean) || checkApplicationBean(bean));
+    }
+
+
+    private void putBeanType(String bean, String type) {
+	beanTypes.put (bean, type);
+    }
+
+    private boolean checkPageBean (String s) {
+	return pageBeans.contains (s);
+    }
+
+    private boolean checkRequestBean (String s) {
+	return requestBeans.contains (s);
+    }
+
+    private boolean checkSessionBean (String s) {
+	return sessionBeans.contains (s);
+    }
+
+    private boolean checkApplicationBean (String s) {
+	return appBeans.contains (s);
+    }
+
+}
+
+
+
+

Added: branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/Collector.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/Collector.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/Collector.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,203 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ *
+ * Licensed 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 org.apache.jasper.JasperException;
+
+/**
+ * Collect info about the page and nodes, and make them availabe through
+ * the PageInfo object.
+ *
+ * @author Kin-man Chung
+ * @author Mark Roth
+ */
+
+class Collector {
+
+    /**
+     * A visitor for collecting information on the page and the body of
+     * the custom tags.
+     */
+    static class CollectVisitor extends Node.Visitor {
+
+        private boolean scriptingElementSeen = false;
+        private boolean usebeanSeen = false;
+        private boolean includeActionSeen = false;
+        private boolean paramActionSeen = false;
+        private boolean setPropertySeen = false;
+        private boolean hasScriptingVars = false;
+
+        public void visit(Node.ParamAction n) throws JasperException {
+            if (n.getValue().isExpression()) {
+                scriptingElementSeen = true;
+            }
+            paramActionSeen = true;
+        }
+
+        public void visit(Node.IncludeAction n) throws JasperException {
+            if (n.getPage().isExpression()) {
+                scriptingElementSeen = true;
+            }
+            includeActionSeen = true;
+            visitBody(n);
+        }
+
+        public void visit(Node.ForwardAction n) throws JasperException {
+            if (n.getPage().isExpression()) {
+                scriptingElementSeen = true;
+            }
+            visitBody(n);
+        }
+
+        public void visit(Node.SetProperty n) throws JasperException {
+            if (n.getValue() != null && n.getValue().isExpression()) {
+                scriptingElementSeen = true;
+            }
+            setPropertySeen = true;
+        }
+
+        public void visit(Node.UseBean n) throws JasperException {
+            if (n.getBeanName() != null && n.getBeanName().isExpression()) {
+                scriptingElementSeen = true;
+            }
+            usebeanSeen = true;
+                visitBody(n);
+        }
+
+        public void visit(Node.PlugIn n) throws JasperException {
+            if (n.getHeight() != null && n.getHeight().isExpression()) {
+                scriptingElementSeen = true;
+            }
+            if (n.getWidth() != null && n.getWidth().isExpression()) {
+                scriptingElementSeen = true;
+            }
+            visitBody(n);
+        }
+
+        public void visit(Node.CustomTag n) throws JasperException {
+            // Check to see what kinds of element we see as child elements
+            checkSeen( n.getChildInfo(), n );
+        }
+
+        /**
+         * Check all child nodes for various elements and update the given
+         * ChildInfo object accordingly.  Visits body in the process.
+         */
+        private void checkSeen( Node.ChildInfo ci, Node n )
+            throws JasperException
+        {
+            // save values collected so far
+            boolean scriptingElementSeenSave = scriptingElementSeen;
+            scriptingElementSeen = false;
+            boolean usebeanSeenSave = usebeanSeen;
+            usebeanSeen = false;
+            boolean includeActionSeenSave = includeActionSeen;
+            includeActionSeen = false;
+            boolean paramActionSeenSave = paramActionSeen;
+            paramActionSeen = false;
+            boolean setPropertySeenSave = setPropertySeen;
+            setPropertySeen = false;
+            boolean hasScriptingVarsSave = hasScriptingVars;
+            hasScriptingVars = false;
+
+            // Scan attribute list for expressions
+            if( n instanceof Node.CustomTag ) {
+                Node.CustomTag ct = (Node.CustomTag)n;
+                Node.JspAttribute[] attrs = ct.getJspAttributes();
+                for (int i = 0; attrs != null && i < attrs.length; i++) {
+                    if (attrs[i].isExpression()) {
+                        scriptingElementSeen = true;
+                        break;
+                    }
+                }
+            }
+
+            visitBody(n);
+
+            if( (n instanceof Node.CustomTag) && !hasScriptingVars) {
+                Node.CustomTag ct = (Node.CustomTag)n;
+                hasScriptingVars = ct.getVariableInfos().length > 0 ||
+                    ct.getTagVariableInfos().length > 0;
+            }
+
+            // Record if the tag element and its body contains any scriptlet.
+            ci.setScriptless(! scriptingElementSeen);
+            ci.setHasUseBean(usebeanSeen);
+            ci.setHasIncludeAction(includeActionSeen);
+            ci.setHasParamAction(paramActionSeen);
+            ci.setHasSetProperty(setPropertySeen);
+            ci.setHasScriptingVars(hasScriptingVars);
+
+            // Propagate value of scriptingElementSeen up.
+            scriptingElementSeen = scriptingElementSeen || scriptingElementSeenSave;
+            usebeanSeen = usebeanSeen || usebeanSeenSave;
+            setPropertySeen = setPropertySeen || setPropertySeenSave;
+            includeActionSeen = includeActionSeen || includeActionSeenSave;
+            paramActionSeen = paramActionSeen || paramActionSeenSave;
+            hasScriptingVars = hasScriptingVars || hasScriptingVarsSave;
+        }
+
+        public void visit(Node.JspElement n) throws JasperException {
+            if (n.getNameAttribute().isExpression())
+                scriptingElementSeen = true;
+
+            Node.JspAttribute[] attrs = n.getJspAttributes();
+            for (int i = 0; i < attrs.length; i++) {
+                if (attrs[i].isExpression()) {
+                    scriptingElementSeen = true;
+                    break;
+                }
+            }
+            visitBody(n);
+        }
+
+        public void visit(Node.JspBody n) throws JasperException {
+            checkSeen( n.getChildInfo(), n );
+        }
+
+        public void visit(Node.NamedAttribute n) throws JasperException {
+            checkSeen( n.getChildInfo(), n );
+        }
+
+        public void visit(Node.Declaration n) throws JasperException {
+            scriptingElementSeen = true;
+        }
+
+        public void visit(Node.Expression n) throws JasperException {
+            scriptingElementSeen = true;
+        }
+
+        public void visit(Node.Scriptlet n) throws JasperException {
+            scriptingElementSeen = true;
+        }
+
+        public void updatePageInfo(PageInfo pageInfo) {
+            pageInfo.setScriptless(! scriptingElementSeen);
+        }
+    }
+
+
+    public static void collect(Compiler compiler, Node.Nodes page)
+        throws JasperException {
+
+    CollectVisitor collectVisitor = new CollectVisitor();
+        page.visit(collectVisitor);
+        collectVisitor.updatePageInfo(compiler.getPageInfo());
+
+    }
+}
+

Added: branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/Compiler.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/Compiler.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/Compiler.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,500 @@
+/*
+ * Copyright 1999,2004-2005 The Apache Software Foundation.
+ * 
+ * Licensed 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 java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+import java.io.UnsupportedEncodingException;
+import java.net.URL;
+import java.net.URLConnection;
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.jasper.JasperException;
+import org.apache.jasper.JspCompilationContext;
+import org.apache.jasper.Options;
+import org.apache.jasper.servlet.JspServletWrapper;
+
+/**
+ * Main JSP compiler class. This class uses Ant for compiling.
+ *
+ * @author Anil K. Vijendran
+ * @author Mandar Raje
+ * @author Pierre Delisle
+ * @author Kin-man Chung
+ * @author Remy Maucherat
+ * @author Mark Roth
+ */
+public abstract class Compiler {
+    protected org.apache.commons.logging.Log log=
+        org.apache.commons.logging.LogFactory.getLog( Compiler.class );
+
+    // ----------------------------------------------------------------- Static
+
+
+    // Some javac are not thread safe; use a lock to serialize compilation, 
+    static Object javacLock = new Object();
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    protected JspCompilationContext ctxt;
+
+    protected ErrorDispatcher errDispatcher;
+    protected PageInfo pageInfo;
+    protected JspServletWrapper jsw;
+    protected TagFileProcessor tfp;
+
+    protected Options options;
+
+    protected Node.Nodes pageNodes;
+    // ------------------------------------------------------------ Constructor
+
+    public void init(JspCompilationContext ctxt, JspServletWrapper jsw) {
+        this.jsw = jsw;
+        this.ctxt = ctxt;
+        this.options = ctxt.getOptions();
+    }
+
+    // --------------------------------------------------------- Public Methods
+
+    /**
+     * <p>Retrieves the parsed nodes of the JSP page, if they are available.
+     * May return null.  Used in development mode for generating detailed
+     * error messages.  http://issues.apache.org/bugzilla/show_bug.cgi?id=37062.
+     * </p>
+     */
+    public Node.Nodes getPageNodes() {
+        return this.pageNodes;
+    }
+
+    /** 
+     * Compile the jsp file into equivalent servlet in .java file
+     * @return a smap for the current JSP page, if one is generated,
+     *         null otherwise
+     */
+    protected String[] generateJava() throws Exception {
+
+        String[] smapStr = null;
+
+        long t1, t2, t3, t4;
+
+        t1 = t2 = t3 = t4 = 0;
+      
+        if (log.isDebugEnabled()) {
+            t1 = System.currentTimeMillis();
+        }
+
+        // Setup page info area
+        pageInfo = new PageInfo(new BeanRepository(ctxt.getClassLoader(),
+                                                   errDispatcher),
+                                                   ctxt.getJspFile());
+
+        JspConfig jspConfig = options.getJspConfig();
+        JspConfig.JspProperty jspProperty =
+            jspConfig.findJspProperty(ctxt.getJspFile());
+
+        /*
+         * If the current uri is matched by a pattern specified in
+         * a jsp-property-group in web.xml, initialize pageInfo with
+         * those properties.
+         */
+        pageInfo.setELIgnored(JspUtil.booleanValue(
+                                            jspProperty.isELIgnored()));
+        pageInfo.setScriptingInvalid(JspUtil.booleanValue(
+                                            jspProperty.isScriptingInvalid()));
+        if (jspProperty.getIncludePrelude() != null) {
+            pageInfo.setIncludePrelude(jspProperty.getIncludePrelude());
+        }
+        if (jspProperty.getIncludeCoda() != null) {
+            pageInfo.setIncludeCoda(jspProperty.getIncludeCoda());
+        }
+
+        String javaFileName = ctxt.getServletJavaFileName();
+        ServletWriter writer = null;
+
+        try {
+            // Setup the ServletWriter
+            String javaEncoding = ctxt.getOptions().getJavaEncoding();
+            OutputStreamWriter osw = null; 
+
+            try {
+                osw = new OutputStreamWriter(
+                            new FileOutputStream(javaFileName), javaEncoding);
+            } catch (UnsupportedEncodingException ex) {
+                errDispatcher.jspError("jsp.error.needAlternateJavaEncoding",
+                                       javaEncoding);
+            }
+
+            writer = new ServletWriter(new PrintWriter(osw));
+            ctxt.setWriter(writer);
+
+            // Reset the temporary variable counter for the generator.
+            JspUtil.resetTemporaryVariableName();
+
+            // Parse the file
+            ParserController parserCtl = new ParserController(ctxt, this);
+            pageNodes = parserCtl.parse(ctxt.getJspFile());
+
+            if (ctxt.isPrototypeMode()) {
+                // generate prototype .java file for the tag file
+                Generator.generate(writer, this, pageNodes);
+                writer.close();
+                writer = null;
+                return null;
+            }
+
+            // Validate and process attributes
+            Validator.validate(this, pageNodes);
+
+            if (log.isDebugEnabled()) {
+                t2 = System.currentTimeMillis();
+            }
+
+            // Collect page info
+            Collector.collect(this, pageNodes);
+
+            // Compile (if necessary) and load the tag files referenced in
+            // this compilation unit.
+            tfp = new TagFileProcessor();
+            tfp.loadTagFiles(this, pageNodes);
+
+            if (log.isDebugEnabled()) {
+                t3 = System.currentTimeMillis();
+            }
+        
+            // Determine which custom tag needs to declare which scripting vars
+            ScriptingVariabler.set(pageNodes, errDispatcher);
+
+            // Optimizations by Tag Plugins
+            TagPluginManager tagPluginManager = options.getTagPluginManager();
+            tagPluginManager.apply(pageNodes, errDispatcher, pageInfo);
+
+            // Optimization: concatenate contiguous template texts.
+            TextOptimizer.concatenate(this, pageNodes);
+
+            // Generate static function mapper codes.
+            ELFunctionMapper.map(this, pageNodes);
+
+            // generate servlet .java file
+            Generator.generate(writer, this, pageNodes);
+            writer.close();
+            writer = null;
+
+            // The writer is only used during the compile, dereference
+            // it in the JspCompilationContext when done to allow it
+            // to be GC'd and save memory.
+            ctxt.setWriter(null);
+
+            if (log.isDebugEnabled()) {
+                t4 = System.currentTimeMillis();
+                log.debug("Generated "+ javaFileName + " total="
+                          + (t4-t1) + " generate=" + (t4-t3)
+                          + " validate=" + (t2-t1));
+            }
+
+        } catch (Exception e) {
+            if (writer != null) {
+                try {
+                    writer.close();
+                    writer = null;
+                } catch (Exception e1) {
+                    // do nothing
+                }
+            }
+            // Remove the generated .java file
+            new File(javaFileName).delete();
+            throw e;
+        } finally {
+            if (writer != null) {
+                try {
+                    writer.close();
+                } catch (Exception e2) {
+                    // do nothing
+                }
+            }
+        }
+        
+        // JSR45 Support
+        if (! options.isSmapSuppressed()) {
+            smapStr = SmapUtil.generateSmap(ctxt, pageNodes);
+        }
+
+        // If any proto type .java and .class files was generated,
+        // the prototype .java may have been replaced by the current
+        // compilation (if the tag file is self referencing), but the
+        // .class file need to be removed, to make sure that javac would
+        // generate .class again from the new .java file just generated.
+        tfp.removeProtoTypeFiles(ctxt.getClassFileName());
+
+        return smapStr;
+    }
+
+    /** 
+     * Compile the servlet from .java file to .class file
+     */
+    protected abstract void generateClass(String[] smap)
+        throws FileNotFoundException, JasperException, Exception;
+    
+    
+    /** 
+     * Compile the jsp file from the current engine context
+     */
+    public void compile()
+        throws FileNotFoundException, JasperException, Exception
+    {
+        compile(true);
+    }
+
+    /**
+     * Compile the jsp file from the current engine context.  As an side-
+     * effect, tag files that are referenced by this page are also compiled.
+     * @param compileClass If true, generate both .java and .class file
+     *                     If false, generate only .java file
+     */
+    public void compile(boolean compileClass)
+        throws FileNotFoundException, JasperException, Exception
+    {
+        compile(compileClass, false);
+    }
+
+    /**
+     * Compile the jsp file from the current engine context.  As an side-
+     * effect, tag files that are referenced by this page are also compiled.
+     *
+     * @param compileClass If true, generate both .java and .class file
+     *                     If false, generate only .java file
+     * @param jspcMode true if invoked from JspC, false otherwise
+     */
+    public void compile(boolean compileClass, boolean jspcMode)
+        throws FileNotFoundException, JasperException, Exception
+    {
+        if (errDispatcher == null) {
+            this.errDispatcher = new ErrorDispatcher(jspcMode);
+        }
+
+        try {
+            String[] smap = generateJava();
+            if (compileClass) {
+                generateClass(smap);
+            }
+        } finally {
+            if (tfp != null) {
+                tfp.removeProtoTypeFiles(null);
+            }
+            // Make sure these object which are only used during the
+            // generation and compilation of the JSP page get
+            // dereferenced so that they can be GC'd and reduce the
+            // memory footprint.
+            tfp = null;
+            errDispatcher = null;
+            pageInfo = null;
+
+            // Only get rid of the pageNodes if in production.
+            // In development mode, they are used for detailed
+            // error messages.
+            // http://issues.apache.org/bugzilla/show_bug.cgi?id=37062
+            if(!this.options.getDevelopment()) {
+                pageNodes = null;
+            }
+
+            if (ctxt.getWriter() != null) {
+                ctxt.getWriter().close();
+                ctxt.setWriter(null);
+            }
+        }
+    }
+
+    /**
+     * This is a protected method intended to be overridden by 
+     * subclasses of Compiler. This is used by the compile method
+     * to do all the compilation. 
+     */
+    public boolean isOutDated() {
+        return isOutDated( true );
+    }
+
+    /**
+     * Determine if a compilation is necessary by checking the time stamp
+     * of the JSP page with that of the corresponding .class or .java file.
+     * If the page has dependencies, the check is also extended to its
+     * dependeants, and so on.
+     * This method can by overidden by a subclasses of Compiler.
+     * @param checkClass If true, check against .class file,
+     *                   if false, check against .java file.
+     */
+    public boolean isOutDated(boolean checkClass) {
+
+        String jsp = ctxt.getJspFile();
+
+        if (jsw != null
+                && (ctxt.getOptions().getModificationTestInterval() > 0)) {
+ 
+            if (jsw.getLastModificationTest()
+                    + (ctxt.getOptions().getModificationTestInterval() * 1000) 
+                    > System.currentTimeMillis()) {
+                return false;
+            } else {
+                jsw.setLastModificationTest(System.currentTimeMillis());
+            }
+        }
+        
+        long jspRealLastModified = 0;
+        try {
+            URL jspUrl = ctxt.getResource(jsp);
+            if (jspUrl == null) {
+                ctxt.incrementRemoved();
+                return false;
+            }
+            URLConnection uc = jspUrl.openConnection();
+            jspRealLastModified = uc.getLastModified();
+            uc.getInputStream().close();
+        } catch (Exception e) {
+            e.printStackTrace();
+            return true;
+        }
+
+        long targetLastModified = 0;
+        File targetFile;
+        
+        if( checkClass ) {
+            targetFile = new File(ctxt.getClassFileName());
+        } else {
+            targetFile = new File(ctxt.getServletJavaFileName());
+        }
+        
+        if (!targetFile.exists()) {
+            return true;
+        }
+
+        targetLastModified = targetFile.lastModified();
+        if (checkClass && jsw != null) {
+            jsw.setServletClassLastModifiedTime(targetLastModified);
+        }   
+        if (targetLastModified < jspRealLastModified) {
+            if( log.isDebugEnabled() ) {
+                log.debug("Compiler: outdated: " + targetFile + " " +
+                    targetLastModified );
+            }
+            return true;
+        }
+
+        // determine if source dependent files (e.g. includes using include
+        // directives) have been changed.
+        if( jsw==null ) {
+            return false;
+        }
+        
+        List depends = jsw.getDependants();
+        if (depends == null) {
+            return false;
+        }
+
+        Iterator it = depends.iterator();
+        while (it.hasNext()) {
+            String include = (String)it.next();
+            try {
+                URL includeUrl = ctxt.getResource(include);
+                if (includeUrl == null) {
+                    return true;
+                }
+
+                URLConnection includeUconn = includeUrl.openConnection();
+                long includeLastModified = includeUconn.getLastModified();
+                includeUconn.getInputStream().close();
+
+                if (includeLastModified > targetLastModified) {
+                    return true;
+                }
+            } catch (Exception e) {
+                e.printStackTrace();
+                return true;
+            }
+        }
+
+        return false;
+
+    }
+
+    
+    /**
+     * Gets the error dispatcher.
+     */
+    public ErrorDispatcher getErrorDispatcher() {
+        return errDispatcher;
+    }
+
+
+    /**
+     * Gets the info about the page under compilation
+     */
+    public PageInfo getPageInfo() {
+        return pageInfo;
+    }
+
+
+    public JspCompilationContext getCompilationContext() {
+        return ctxt;
+    }
+
+
+    /**
+     * Remove generated files
+     */
+    public void removeGeneratedFiles() {
+        try {
+            String classFileName = ctxt.getClassFileName();
+            if (classFileName != null) {
+                File classFile = new File(classFileName);
+                if( log.isDebugEnabled() )
+                    log.debug( "Deleting " + classFile );
+                classFile.delete();
+            }
+        } catch (Exception e) {
+            // Remove as much as possible, ignore possible exceptions
+        }
+        try {
+            String javaFileName = ctxt.getServletJavaFileName();
+            if (javaFileName != null) {
+                File javaFile = new File(javaFileName);
+                if( log.isDebugEnabled() )
+                    log.debug( "Deleting " + javaFile );
+                javaFile.delete();
+            }
+        } catch (Exception e) {
+            // Remove as much as possible, ignore possible exceptions
+        }
+    }
+
+    public void removeGeneratedClassFiles() {
+        try {
+            String classFileName = ctxt.getClassFileName();
+            if (classFileName != null) {
+                File classFile = new File(classFileName);
+                if( log.isDebugEnabled() )
+                    log.debug( "Deleting " + classFile );
+                classFile.delete();
+            }
+        } catch (Exception e) {
+            // Remove as much as possible, ignore possible exceptions
+        }
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/DefaultErrorHandler.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/DefaultErrorHandler.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/DefaultErrorHandler.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,100 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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 org.apache.jasper.JasperException;
+
+/**
+ * Default implementation of ErrorHandler interface.
+ *
+ * @author Jan Luehe
+ */
+class DefaultErrorHandler implements ErrorHandler {
+    
+    /*
+     * Processes the given JSP parse error.
+     *
+     * @param fname Name of the JSP file in which the parse error occurred
+     * @param line Parse error line number
+     * @param column Parse error column number
+     * @param errMsg Parse error message
+     * @param exception Parse exception
+     */
+    public void jspError(String fname, int line, int column, String errMsg,
+            Exception ex) throws JasperException {
+        throw new JasperException(fname + "(" + line + "," + column + ")"
+                + " " + errMsg, ex);
+    }
+    
+    /*
+     * Processes the given JSP parse error.
+     *
+     * @param errMsg Parse error message
+     * @param exception Parse exception
+     */
+    public void jspError(String errMsg, Exception ex) throws JasperException {
+        throw new JasperException(errMsg, ex);
+    }
+    
+    /*
+     * Processes the given javac compilation errors.
+     *
+     * @param details Array of JavacErrorDetail instances corresponding to the
+     * compilation errors
+     */
+    public void javacError(JavacErrorDetail[] details) throws JasperException {
+        
+        if (details == null) {
+            return;
+        }
+        
+        Object[] args = null;
+        StringBuffer buf = new StringBuffer();
+        
+        for (int i=0; i < details.length; i++) {
+            if (details[i].getJspBeginLineNumber() >= 0) {
+                args = new Object[] {
+                        new Integer(details[i].getJspBeginLineNumber()), 
+                        details[i].getJspFileName() };
+                buf.append(Localizer.getMessage("jsp.error.single.line.number",
+                        args));
+                buf.append("\n"); 
+            }
+            
+            buf.append(
+                    Localizer.getMessage("jsp.error.corresponding.servlet"));
+            buf.append(details[i].getErrorMessage());
+            buf.append("\n\n");
+        }
+        
+        throw new JasperException(Localizer.getMessage("jsp.error.unable.compile") + "\n\n" + buf);
+    }
+    
+    /**
+     * Processes the given javac error report and exception.
+     *
+     * @param errorReport Compilation error report
+     * @param exception Compilation exception
+     */
+    public void javacError(String errorReport, Exception exception)
+    throws JasperException {
+        
+        throw new JasperException(
+                Localizer.getMessage("jsp.error.unable.compile"), exception);
+    }
+    
+}

Added: branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/Dumper.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/Dumper.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/Dumper.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,206 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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 org.xml.sax.Attributes;
+import org.apache.jasper.JasperException;
+
+class Dumper {
+
+    static class DumpVisitor extends Node.Visitor {
+	private int indent = 0;
+
+	private String getAttributes(Attributes attrs) {
+	    if (attrs == null)
+		return "";
+
+	    StringBuffer buf = new StringBuffer();
+	    for (int i=0; i < attrs.getLength(); i++) {
+		buf.append(" " + attrs.getQName(i) + "=\""
+			   + attrs.getValue(i) + "\"");
+	    }
+	    return buf.toString();
+	}
+
+	private void printString(String str) {
+	    printIndent();
+	    System.out.print(str);
+	}
+
+	private void printString(String prefix, char[] chars, String suffix) {
+	    String str = null;
+	    if (chars != null) {
+		str = new String(chars);
+	    }
+	    printString(prefix, str, suffix);
+	}
+	     
+	private void printString(String prefix, String str, String suffix) {
+	    printIndent();
+	    if (str != null) {
+		System.out.print(prefix + str + suffix);
+	    } else {
+		System.out.print(prefix + suffix);
+	    }
+	}
+
+	private void printAttributes(String prefix, Attributes attrs,
+				     String suffix) {
+	    printString(prefix, getAttributes(attrs), suffix);
+	}
+
+	private void dumpBody(Node n) throws JasperException {
+	    Node.Nodes page = n.getBody();
+	    if (page != null) {
+//		indent++;
+		page.visit(this);
+//		indent--;
+	    }
+        }
+
+        public void visit(Node.PageDirective n) throws JasperException {
+	    printAttributes("<%@ page", n.getAttributes(), "%>");
+        }
+
+        public void visit(Node.TaglibDirective n) throws JasperException {
+	    printAttributes("<%@ taglib", n.getAttributes(), "%>");
+        }
+
+        public void visit(Node.IncludeDirective n) throws JasperException {
+	    printAttributes("<%@ include", n.getAttributes(), "%>");
+	    dumpBody(n);
+        }
+
+        public void visit(Node.Comment n) throws JasperException {
+	    printString("<%--", n.getText(), "--%>");
+        }
+
+        public void visit(Node.Declaration n) throws JasperException {
+	    printString("<%!", n.getText(), "%>");
+        }
+
+        public void visit(Node.Expression n) throws JasperException {
+	    printString("<%=", n.getText(), "%>");
+        }
+
+        public void visit(Node.Scriptlet n) throws JasperException {
+	    printString("<%", n.getText(), "%>");
+        }
+
+        public void visit(Node.IncludeAction n) throws JasperException {
+	    printAttributes("<jsp:include", n.getAttributes(), ">");
+	    dumpBody(n);
+            printString("</jsp:include>");
+        }
+
+        public void visit(Node.ForwardAction n) throws JasperException {
+	    printAttributes("<jsp:forward", n.getAttributes(), ">");
+	    dumpBody(n);
+	    printString("</jsp:forward>");
+        }
+
+        public void visit(Node.GetProperty n) throws JasperException {
+	    printAttributes("<jsp:getProperty", n.getAttributes(), "/>");
+        }
+
+        public void visit(Node.SetProperty n) throws JasperException {
+	    printAttributes("<jsp:setProperty", n.getAttributes(), ">");
+            dumpBody(n);
+            printString("</jsp:setProperty>");
+        }
+
+        public void visit(Node.UseBean n) throws JasperException {
+	    printAttributes("<jsp:useBean", n.getAttributes(), ">");
+	    dumpBody(n);
+	    printString("</jsp:useBean>");
+        }
+	
+        public void visit(Node.PlugIn n) throws JasperException {
+	    printAttributes("<jsp:plugin", n.getAttributes(), ">");
+	    dumpBody(n);
+	    printString("</jsp:plugin>");
+	}
+        
+        public void visit(Node.ParamsAction n) throws JasperException {
+	    printAttributes("<jsp:params", n.getAttributes(), ">");
+	    dumpBody(n);
+	    printString("</jsp:params>");
+        }
+        
+        public void visit(Node.ParamAction n) throws JasperException {
+	    printAttributes("<jsp:param", n.getAttributes(), ">");
+	    dumpBody(n);
+	    printString("</jsp:param>");
+        }
+        
+        public void visit(Node.NamedAttribute n) throws JasperException {
+	    printAttributes("<jsp:attribute", n.getAttributes(), ">");
+	    dumpBody(n);
+	    printString("</jsp:attribute>");
+        }
+
+        public void visit(Node.JspBody n) throws JasperException {
+	    printAttributes("<jsp:body", n.getAttributes(), ">");
+	    dumpBody(n);
+	    printString("</jsp:body>");
+        }
+        
+        public void visit(Node.ELExpression n) throws JasperException {
+	    printString( "${" + new String( n.getText() ) + "}" );
+        }
+
+        public void visit(Node.CustomTag n) throws JasperException {
+	    printAttributes("<" + n.getQName(), n.getAttributes(), ">");
+	    dumpBody(n);
+	    printString("</" + n.getQName() + ">");
+        }
+
+	public void visit(Node.UninterpretedTag n) throws JasperException {
+	    String tag = n.getQName();
+	    printAttributes("<"+tag, n.getAttributes(), ">");
+	    dumpBody(n);
+	    printString("</" + tag + ">");
+        }
+
+	public void visit(Node.TemplateText n) throws JasperException {
+	    printString(new String(n.getText()));
+	}
+
+	private void printIndent() {
+	    for (int i=0; i < indent; i++) {
+		System.out.print("  ");
+	    }
+	}
+    }
+
+    public static void dump(Node n) {
+	try {
+	    n.accept(new DumpVisitor());	
+	} catch (JasperException e) {
+	    e.printStackTrace();
+	}
+    }
+
+    public static void dump(Node.Nodes page) {
+	try {
+	    page.visit(new DumpVisitor());
+	} catch (JasperException e) {
+	    e.printStackTrace();
+	}
+    }
+}
+

Added: branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/ELFunctionMapper.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/ELFunctionMapper.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/ELFunctionMapper.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,282 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.util.*;
+import javax.servlet.jsp.tagext.FunctionInfo;
+import org.apache.jasper.JasperException;
+
+/**
+ * This class generates functions mappers for the EL expressions in the page.
+ * Instead of a global mapper, a mapper is used for ecah call to EL
+ * evaluator, thus avoiding the prefix overlapping and redefinition
+ * issues.
+ *
+ * @author Kin-man Chung
+ */
+
+public class ELFunctionMapper {
+    static private int currFunc = 0;
+    private ErrorDispatcher err;
+    StringBuffer ds;  // Contains codes to initialize the functions mappers.
+    StringBuffer ss;  // Contains declarations of the functions mappers.
+
+    /**
+     * Creates the functions mappers for all EL expressions in the JSP page.
+     *
+     * @param compiler Current compiler, mainly for accessing error dispatcher.
+     * @param page The current compilation unit.
+     */
+    public static void map(Compiler compiler, Node.Nodes page) 
+		throws JasperException {
+
+	currFunc = 0;
+	ELFunctionMapper map = new ELFunctionMapper();
+	map.err = compiler.getErrorDispatcher();
+	map.ds = new StringBuffer();
+	map.ss = new StringBuffer();
+
+	page.visit(map.new ELFunctionVisitor());
+
+	// Append the declarations to the root node
+	String ds = map.ds.toString();
+	if (ds.length() > 0) {
+	    Node root = page.getRoot();
+	    new Node.Declaration(map.ss.toString(), null, root);
+	    new Node.Declaration("static {\n" + ds + "}\n", null, root);
+	}
+    }
+
+    /**
+     * A visitor for the page.  The places where EL is allowed are scanned
+     * for functions, and if found functions mappers are created.
+     */
+    class ELFunctionVisitor extends Node.Visitor {
+	
+	/**
+	 * Use a global name map to facilitate reuse of function maps.
+	 * The key used is prefix:function:uri.
+	 */
+	private HashMap gMap = new HashMap();
+
+	public void visit(Node.ParamAction n) throws JasperException {
+	    doMap(n.getValue());
+	    visitBody(n);
+	}
+
+	public void visit(Node.IncludeAction n) throws JasperException {
+	    doMap(n.getPage());
+	    visitBody(n);
+	}
+
+	public void visit(Node.ForwardAction n) throws JasperException {
+	    doMap(n.getPage());
+	    visitBody(n);
+	}
+
+        public void visit(Node.SetProperty n) throws JasperException {
+	    doMap(n.getValue());
+	    visitBody(n);
+	}
+
+        public void visit(Node.UseBean n) throws JasperException {
+	    doMap(n.getBeanName());
+	    visitBody(n);
+	}
+
+        public void visit(Node.PlugIn n) throws JasperException {
+	    doMap(n.getHeight());
+	    doMap(n.getWidth());
+	    visitBody(n);
+	}
+
+        public void visit(Node.JspElement n) throws JasperException {
+
+	    Node.JspAttribute[] attrs = n.getJspAttributes();
+	    for (int i = 0; attrs != null && i < attrs.length; i++) {
+		doMap(attrs[i]);
+	    }
+	    doMap(n.getNameAttribute());
+	    visitBody(n);
+	}
+
+        public void visit(Node.UninterpretedTag n) throws JasperException {
+
+	    Node.JspAttribute[] attrs = n.getJspAttributes();
+	    for (int i = 0; attrs != null && i < attrs.length; i++) {
+		doMap(attrs[i]);
+	    }
+	    visitBody(n);
+	}
+
+        public void visit(Node.CustomTag n) throws JasperException {
+	    Node.JspAttribute[] attrs = n.getJspAttributes();
+	    for (int i = 0; attrs != null && i < attrs.length; i++) {
+		doMap(attrs[i]);
+	    }
+	    visitBody(n);
+	}
+
+        public void visit(Node.ELExpression n) throws JasperException {
+	    doMap(n.getEL());
+	}
+
+	private void doMap(Node.JspAttribute attr) 
+		throws JasperException {
+	    if (attr != null) {
+		doMap(attr.getEL());
+	    }
+	}
+
+        /**
+         * Creates function mappers, if needed, from ELNodes
+         */
+	private void doMap(ELNode.Nodes el) 
+		throws JasperException {
+
+            // Only care about functions in ELNode's
+	    class Fvisitor extends ELNode.Visitor {
+		ArrayList funcs = new ArrayList();
+		HashMap keyMap = new HashMap();
+		public void visit(ELNode.Function n) throws JasperException {
+		    String key = n.getPrefix() + ":" + n.getName();
+		    if (! keyMap.containsKey(key)) {
+			keyMap.put(key,"");
+			funcs.add(n);
+		    }
+		}
+	    }
+
+	    if (el == null) {
+		return;
+	    }
+
+	    // First locate all unique functions in this EL
+	    Fvisitor fv = new Fvisitor();
+	    el.visit(fv);
+	    ArrayList functions = fv.funcs;
+
+	    if (functions.size() == 0) {
+		return;
+	    }
+
+	    // Reuse a previous map if possible
+	    String decName = matchMap(functions);
+	    if (decName != null) {
+		el.setMapName(decName);
+		return;
+	    }
+	
+	    // Generate declaration for the map statically
+	    decName = getMapName();
+	    ss.append("static private org.apache.jasper.runtime.ProtectedFunctionMapper " + decName + ";\n");
+
+	    ds.append("  " + decName + "= ");
+	    ds.append("org.apache.jasper.runtime.ProtectedFunctionMapper");
+
+	    // Special case if there is only one function in the map
+	    String funcMethod = null;
+	    if (functions.size() == 1) {
+		funcMethod = ".getMapForFunction";
+	    } else {
+		ds.append(".getInstance();\n");
+		funcMethod = "  " + decName + ".mapFunction";
+	    }
+
+            // Setup arguments for either getMapForFunction or mapFunction
+	    for (int i = 0; i < functions.size(); i++) {
+		ELNode.Function f = (ELNode.Function)functions.get(i);
+		FunctionInfo funcInfo = f.getFunctionInfo();
+		String key = f.getPrefix()+ ":" + f.getName();
+		ds.append(funcMethod + "(\"" + key + "\", " +
+			funcInfo.getFunctionClass() + ".class, " +
+			'\"' + f.getMethodName() + "\", " +
+			"new Class[] {");
+		String params[] = f.getParameters();
+		for (int k = 0; k < params.length; k++) {
+		    if (k != 0) {
+			ds.append(", ");
+		    }
+		    int iArray = params[k].indexOf('[');
+		    if (iArray < 0) {
+			ds.append(params[k] + ".class");
+		    }
+		    else {
+			String baseType = params[k].substring(0, iArray);
+			ds.append("java.lang.reflect.Array.newInstance(");
+			ds.append(baseType);
+			ds.append(".class,");
+
+			// Count the number of array dimension
+			int aCount = 0;
+			for (int jj = iArray; jj < params[k].length(); jj++ ) {
+			    if (params[k].charAt(jj) == '[') {
+				aCount++;
+			    }
+			}
+			if (aCount == 1) {
+			    ds.append("0).getClass()");
+			} else {
+			    ds.append("new int[" + aCount + "]).getClass()");
+			}
+		    }
+		}
+		ds.append("});\n");
+		// Put the current name in the global function map
+		gMap.put(f.getPrefix() + ':' + f.getName() + ':' + f.getUri(),
+			 decName);
+	    }
+	    el.setMapName(decName);
+	}
+
+        /**
+         * Find the name of the function mapper for an EL.  Reuse a
+         * previously generated one if possible.
+         * @param functions An ArrayList of ELNode.Function instances that
+         *                  represents the functions in an EL
+         * @return A previous generated function mapper name that can be used
+         *         by this EL; null if none found.
+         */
+	private String matchMap(ArrayList functions) {
+
+	    String mapName = null;
+	    for (int i = 0; i < functions.size(); i++) {
+		ELNode.Function f = (ELNode.Function)functions.get(i);
+		String temName = (String) gMap.get(f.getPrefix() + ':' +
+					f.getName() + ':' + f.getUri());
+		if (temName == null) {
+		    return null;
+		}
+		if (mapName == null) {
+		    mapName = temName;
+		} else if (!temName.equals(mapName)) {
+		    // If not all in the previous match, then no match.
+		    return null;
+		}
+	    }
+	    return mapName;
+	}
+
+        /*
+         * @return An unique name for a function mapper.
+         */
+	private String getMapName() {
+	    return "_jspx_fnmap_" + currFunc++;
+	}
+    }
+}
+

Added: branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/ELNode.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/ELNode.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/ELNode.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,247 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.util.*;
+import javax.servlet.jsp.tagext.FunctionInfo;
+import org.apache.jasper.JasperException;
+
+/**
+ * This class defines internal representation for an EL Expression
+ *
+ * It currently only defines functions.  It can be expanded to define
+ * all the components of an EL expression, if need to.
+ *
+ * @author Kin-man Chung
+ */
+
+abstract class ELNode {
+
+    abstract public void accept(Visitor v) throws JasperException;
+
+    /**
+     * Child classes
+     */
+
+
+    /**
+     * Represents an EL expression: anything in ${ and }.
+     */
+    public static class Root extends ELNode {
+
+	private ELNode.Nodes expr;
+
+	Root(ELNode.Nodes expr) {
+	    this.expr = expr;
+	}
+
+	public void accept(Visitor v) throws JasperException {
+	    v.visit(this);
+	}
+
+	public ELNode.Nodes getExpression() {
+	    return expr;
+	}
+    }
+
+    /**
+     * Represents text outside of EL expression.
+     */
+    public static class Text extends ELNode {
+
+	private String text;
+
+	Text(String text) {
+	    this.text = text;
+	}
+
+	public void accept(Visitor v) throws JasperException {
+	    v.visit(this);
+	}
+
+	public String getText() {
+	    return text;
+	}
+    }
+
+    /**
+     * Represents anything in EL expression, other than functions, including
+     * function arguments etc
+     */
+    public static class ELText extends ELNode {
+
+	private String text;
+
+	ELText(String text) {
+	    this.text = text;
+	}
+
+	public void accept(Visitor v) throws JasperException {
+	    v.visit(this);
+	}
+
+	public String getText() {
+	    return text;
+	}
+    }
+
+    /**
+     * Represents a function
+     * Currently only include the prefix and function name, but not its
+     * arguments.
+     */
+    public static class Function extends ELNode {
+
+	private String prefix;
+	private String name;
+	private String uri;
+	private FunctionInfo functionInfo;
+	private String methodName;
+	private String[] parameters;
+
+	Function(String prefix, String name) {
+	    this.prefix = prefix;
+	    this.name = name;
+	}
+
+	public void accept(Visitor v) throws JasperException {
+	    v.visit(this);
+	}
+
+	public String getPrefix() {
+	    return prefix;
+	}
+
+	public String getName() {
+	    return name;
+	}
+
+	public void setUri(String uri) {
+	    this.uri = uri;
+	}
+
+	public String getUri() {
+	    return uri;
+	}
+
+	public void setFunctionInfo(FunctionInfo f) {
+	    this.functionInfo = f;
+	}
+
+	public FunctionInfo getFunctionInfo() {
+	    return functionInfo;
+	}
+
+	public void setMethodName(String methodName) {
+	    this.methodName = methodName;
+	}
+
+	public String getMethodName() {
+	    return methodName;
+	}
+
+	public void setParameters(String[] parameters) {
+	    this.parameters = parameters;
+	}
+
+	public String[] getParameters() {
+	    return parameters;
+	}
+    }
+
+    /**
+     * An ordered list of ELNode.
+     */
+    public static class Nodes {
+
+	/* Name used for creating a map for the functions in this
+	   EL expression, for communication to Generator.
+	 */
+	String mapName = null;	// The function map associated this EL
+	private List list;
+
+	public Nodes() {
+	    list = new ArrayList();
+	}
+
+	public void add(ELNode en) {
+	    list.add(en);
+	}
+
+	/**
+	 * Visit the nodes in the list with the supplied visitor
+	 * @param v The visitor used
+	 */
+	public void visit(Visitor v) throws JasperException {
+	    Iterator iter = list.iterator();
+	    while (iter.hasNext()) {
+		ELNode n = (ELNode) iter.next();
+		n.accept(v);
+	    }
+	}
+
+	public Iterator iterator() {
+	    return list.iterator();
+	}
+
+	public boolean isEmpty() {
+	    return list.size() == 0;
+	}
+
+	/**
+	 * @return true if the expression contains a ${...}
+	 */
+	public boolean containsEL() {
+	    Iterator iter = list.iterator();
+	    while (iter.hasNext()) {
+		ELNode n = (ELNode) iter.next();
+		if (n instanceof Root) {
+		    return true;
+		}
+	    }
+	    return false;
+	}
+
+	public void setMapName(String name) {
+	    this.mapName = name;
+	}
+
+	public String getMapName() {
+	    return mapName;
+	}
+    }
+
+    /*
+     * A visitor class for traversing ELNodes
+     */
+    public static class Visitor {
+
+	public void visit(Root n) throws JasperException {
+	    n.getExpression().visit(this);
+	}
+
+	public void visit(Function n) throws JasperException {
+	}
+
+	public void visit(Text n) throws JasperException {
+	}
+
+	public void visit(ELText n) throws JasperException {
+	}
+    }
+}
+

Added: branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/ELParser.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/ELParser.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/ELParser.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,368 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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;
+
+/**
+ * This class implements a parser for EL expressions.
+ *
+ * It takes strings of the form xxx${..}yyy${..}zzz etc, and turn it into
+ * a ELNode.Nodes.
+ *
+ * Currently, it only handles text outside ${..} and functions in ${ ..}.
+ *
+ * @author Kin-man Chung
+ */
+
+public class ELParser {
+
+    private Token curToken;        // current token
+    private ELNode.Nodes expr;
+    private ELNode.Nodes ELexpr;
+    private int index;                // Current index of the expression
+    private String expression;        // The EL expression
+    private boolean escapeBS;        // is '\' an escape char in text outside EL?
+
+    private static final String reservedWords[] = {
+        "and", "div", "empty", "eq", "false",
+        "ge", "gt", "instanceof", "le", "lt", "mod",
+        "ne", "not", "null", "or", "true"};
+
+    public ELParser(String expression) {
+        index = 0;
+        this.expression = expression;
+        expr = new ELNode.Nodes();
+    }
+
+    /**
+     * Parse an EL expression
+     * @param expression The input expression string of the form
+     *                   Char* ('${' Char* '}')* Char*
+     * @return Parsed EL expression in ELNode.Nodes
+     */
+    public static ELNode.Nodes parse(String expression) {
+        ELParser parser = new ELParser(expression);
+        while (parser.hasNextChar()) {
+            String text = parser.skipUntilEL();
+            if (text.length() > 0) {
+                parser.expr.add(new ELNode.Text(text));
+            }
+            ELNode.Nodes elexpr = parser.parseEL();
+            if (! elexpr.isEmpty()) {
+                parser.expr.add(new ELNode.Root(elexpr));
+            }
+        }
+        return parser.expr;
+    }
+
+    /**
+     * Parse an EL expression string '${...}'
+     *@return An ELNode.Nodes representing the EL expression
+     * TODO: Currently only parsed into functions and text strings.  This
+     *       should be rewritten for a full parser.
+     */
+    private ELNode.Nodes parseEL() {
+
+        StringBuffer buf = new StringBuffer();
+        ELexpr = new ELNode.Nodes();
+        while (hasNext()) {
+            curToken = nextToken();
+            if (curToken instanceof Char) {
+                if (curToken.toChar() == '}') {
+                    break;
+                }
+                buf.append(curToken.toChar());
+            } else {
+                // Output whatever is in buffer
+                if (buf.length() > 0) {
+                    ELexpr.add(new ELNode.ELText(buf.toString()));
+                }
+                if (!parseFunction()) {
+                    ELexpr.add(new ELNode.ELText(curToken.toString()));
+                }
+            }
+        }
+        if (buf.length() > 0) {
+            ELexpr.add(new ELNode.ELText(buf.toString()));
+        }
+
+        return ELexpr;
+    }
+
+    /**
+     * Parse for a function
+     * FunctionInvokation ::= (identifier ':')? identifier '('
+     *                              (Expression (,Expression)*)? ')'
+     * Note: currently we don't parse arguments
+     */
+    private boolean parseFunction() {
+        if (! (curToken instanceof Id) || isELReserved(curToken.toString())) {
+            return false;
+        }
+        String s1 = null;                 // Function prefix
+        String s2 = curToken.toString();  // Function name
+        int mark = getIndex();
+        if (hasNext()) {
+            Token t = nextToken();
+            if (t.toChar() == ':') {
+                if (hasNext()) {
+                    Token t2 = nextToken();
+                    if (t2 instanceof Id) {
+                        s1 = s2;
+                        s2 = t2.toString();
+                        if (hasNext()) {
+                            t = nextToken();
+                        }
+                    }
+                }
+            }
+            if (t.toChar() == '(') {
+                ELexpr.add(new ELNode.Function(s1, s2));
+                return true;
+            }
+        }
+        setIndex(mark);
+        return false;
+    }
+
+    /**
+     * Test if an id is a reserved word in EL
+     */
+    private boolean isELReserved(String id) {
+        int i = 0;
+        int j = reservedWords.length;
+        while (i < j) {
+            int k = (i+j)/2;
+            int result = reservedWords[k].compareTo(id);
+            if (result == 0) {
+                return true;
+            }
+            if (result < 0) {
+                i = k+1;
+            } else {
+                j = k;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Skip until an EL expression ('${') is reached, allowing escape sequences
+     * '\\' and '\$'.
+     * @return The text string up to the EL expression
+     */
+    private String skipUntilEL() {
+        char prev = 0;
+        StringBuffer buf = new StringBuffer();
+        while (hasNextChar()) {
+            char ch = nextChar();
+            if (prev == '\\') {
+                prev = 0;
+                if (ch == '\\') {
+                    buf.append('\\');
+                    if (!escapeBS)
+                        prev = '\\';
+                } else if (ch == '$') {
+                    buf.append('$');
+                }
+                // else error!
+            } else if (prev == '$') {
+                if (ch == '{') {
+                    prev = 0;
+                    break;
+                } 
+                buf.append('$');
+                buf.append(ch);
+                prev = 0;
+            } else if (ch == '\\' || ch == '$') {
+                prev = ch;
+            } else {
+                buf.append(ch);
+            }
+        }
+        if (prev != 0) {
+            buf.append(prev);
+        }
+        return buf.toString();
+    }
+
+    /*
+     * @return true if there is something left in EL expression buffer other
+     *         than white spaces.
+     */
+    private boolean hasNext() {
+        skipSpaces();
+        return hasNextChar();
+    }
+
+    /*
+     * @return The next token in the EL expression buffer.
+     */
+    private Token nextToken() {
+        skipSpaces();
+        if (hasNextChar()) {
+            char ch = nextChar();
+            if (Character.isJavaIdentifierStart(ch)) {
+                StringBuffer buf = new StringBuffer();
+                buf.append(ch);
+                while ((ch = peekChar()) != -1 &&
+                                Character.isJavaIdentifierPart(ch)) {
+                    buf.append(ch);
+                    nextChar();
+                }
+                return new Id(buf.toString());
+            }
+
+            if (ch == '\'' || ch == '"') {
+                return parseQuotedChars(ch);
+            } else {
+                // For now...
+                return new Char(ch);
+            }
+        }
+        return null;
+    }
+
+    /*
+     * Parse a string in single or double quotes, allowing for escape sequences
+     * '\\', and ('\"', or "\'")
+     */
+    private Token parseQuotedChars(char quote) {
+        StringBuffer buf = new StringBuffer();
+        buf.append(quote);
+        while (hasNextChar()) {
+            char ch = nextChar();
+            if (ch == '\\') {
+                ch = nextChar();
+                if (ch == '\\' || ch == quote) {
+                    buf.append(ch);
+                }
+                // else error!
+            } else if (ch == quote) {
+                buf.append(ch);
+                break;
+            } else {
+                buf.append(ch);
+            }
+        }
+        return new QuotedString(buf.toString());
+    }
+
+    /*
+     * A collection of low level parse methods dealing with character in
+     * the EL expression buffer.
+     */
+
+    private void skipSpaces() {
+        while (hasNextChar()) {
+            if (expression.charAt(index) > ' ')
+                break;
+            index++;
+        }
+    }
+
+    private boolean hasNextChar() {
+        return index < expression.length();
+    }
+
+    private char nextChar() {
+        if (index >= expression.length()) {
+            return (char)-1;
+        }
+        return expression.charAt(index++);
+    }
+
+    private char peekChar() {
+        if (index >= expression.length()) {
+            return (char)-1;
+        }
+        return expression.charAt(index);
+    }
+
+    private int getIndex() {
+        return index;
+    }
+
+    private void setIndex(int i) {
+        index = i;
+    }
+
+    /*
+     * Represents a token in EL expression string
+     */
+    private static class Token {
+
+        char toChar() {
+            return 0;
+        }
+
+        public String toString() {
+            return "";
+        }
+    }
+
+    /*
+     * Represents an ID token in EL
+     */
+    private static class Id extends Token {
+        String id;
+
+        Id(String id) {
+            this.id = id;
+        }
+
+        public String toString() {
+            return id;
+        }
+    }
+
+    /*
+     * Represents a character token in EL
+     */
+    private static class Char extends Token {
+
+        private char ch;
+
+        Char(char ch) {
+            this.ch = ch;
+        }
+
+        char toChar() {
+            return ch;
+        }
+
+        public String toString() {
+            return (new Character(ch)).toString();
+        }
+    }
+
+    /*
+     * Represents a quoted (single or double) string token in EL
+     */
+    private static class QuotedString extends Token {
+
+        private String value;
+
+        QuotedString(String v) {
+            this.value = v;
+        }
+
+        public String toString() {
+            return value;
+        }
+    }
+}
+

Added: branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/ErrorDispatcher.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/ErrorDispatcher.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/ErrorDispatcher.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,582 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.BufferedReader;
+import java.io.IOException;
+import java.io.StringReader;
+import java.util.Vector;
+import java.net.MalformedURLException;
+
+import org.apache.jasper.JasperException;
+import org.xml.sax.SAXException;
+
+/**
+ * Class responsible for dispatching JSP parse and javac compilation errors
+ * to the configured error handler.
+ *
+ * This class is also responsible for localizing any error codes before they
+ * are passed on to the configured error handler.
+ * 
+ * In the case of a Java compilation error, the compiler error message is
+ * parsed into an array of JavacErrorDetail instances, which is passed on to 
+ * the configured error handler.
+ *
+ * @author Jan Luehe
+ * @author Kin-man Chung
+ */
+public class ErrorDispatcher {
+
+    // Custom error handler
+    private ErrorHandler errHandler;
+
+    // Indicates whether the compilation was initiated by JspServlet or JspC
+    private boolean jspcMode = false;
+
+
+    /*
+     * Constructor.
+     *
+     * @param jspcMode true if compilation has been initiated by JspC, false
+     * otherwise
+     */
+    public ErrorDispatcher(boolean jspcMode) {
+	// XXX check web.xml for custom error handler
+	errHandler = new DefaultErrorHandler();
+        this.jspcMode = jspcMode;
+    }
+
+    /*
+     * Dispatches the given JSP parse error to the configured error handler.
+     *
+     * The given error code is localized. If it is not found in the
+     * resource bundle for localized error messages, it is used as the error
+     * message.
+     *
+     * @param errCode Error code
+     */
+    public void jspError(String errCode) throws JasperException {
+	dispatch(null, errCode, null, null);
+    }
+
+    /*
+     * Dispatches the given JSP parse error to the configured error handler.
+     *
+     * The given error code is localized. If it is not found in the
+     * resource bundle for localized error messages, it is used as the error
+     * message.
+     *
+     * @param where Error location
+     * @param errCode Error code
+     */
+    public void jspError(Mark where, String errCode) throws JasperException {
+	dispatch(where, errCode, null, null);
+    }
+
+    /*
+     * Dispatches the given JSP parse error to the configured error handler.
+     *
+     * The given error code is localized. If it is not found in the
+     * resource bundle for localized error messages, it is used as the error
+     * message.
+     *
+     * @param n Node that caused the error
+     * @param errCode Error code
+     */
+    public void jspError(Node n, String errCode) throws JasperException {
+	dispatch(n.getStart(), errCode, null, null);
+    }
+
+    /*
+     * Dispatches the given JSP parse error to the configured error handler.
+     *
+     * The given error code is localized. If it is not found in the
+     * resource bundle for localized error messages, it is used as the error
+     * message.
+     *
+     * @param errCode Error code
+     * @param arg Argument for parametric replacement
+     */
+    public void jspError(String errCode, String arg) throws JasperException {
+	dispatch(null, errCode, new Object[] {arg}, null);
+    }
+
+    /*
+     * Dispatches the given JSP parse error to the configured error handler.
+     *
+     * The given error code is localized. If it is not found in the
+     * resource bundle for localized error messages, it is used as the error
+     * message.
+     *
+     * @param where Error location
+     * @param errCode Error code
+     * @param arg Argument for parametric replacement
+     */
+    public void jspError(Mark where, String errCode, String arg)
+	        throws JasperException {
+	dispatch(where, errCode, new Object[] {arg}, null);
+    }
+
+    /*
+     * Dispatches the given JSP parse error to the configured error handler.
+     *
+     * The given error code is localized. If it is not found in the
+     * resource bundle for localized error messages, it is used as the error
+     * message.
+     *
+     * @param n Node that caused the error
+     * @param errCode Error code
+     * @param arg Argument for parametric replacement
+     */
+    public void jspError(Node n, String errCode, String arg)
+	        throws JasperException {
+	dispatch(n.getStart(), errCode, new Object[] {arg}, null);
+    }
+
+    /*
+     * Dispatches the given JSP parse error to the configured error handler.
+     *
+     * The given error code is localized. If it is not found in the
+     * resource bundle for localized error messages, it is used as the error
+     * message.
+     *
+     * @param errCode Error code
+     * @param arg1 First argument for parametric replacement
+     * @param arg2 Second argument for parametric replacement
+     */
+    public void jspError(String errCode, String arg1, String arg2)
+	        throws JasperException {
+	dispatch(null, errCode, new Object[] {arg1, arg2}, null);
+    }
+
+    /*
+     * Dispatches the given JSP parse error to the configured error handler.
+     *
+     * The given error code is localized. If it is not found in the
+     * resource bundle for localized error messages, it is used as the error
+     * message.
+     *
+     * @param errCode Error code
+     * @param arg1 First argument for parametric replacement
+     * @param arg2 Second argument for parametric replacement
+     * @param arg3 Third argument for parametric replacement
+     */
+    public void jspError(String errCode, String arg1, String arg2, String arg3)
+	        throws JasperException {
+	dispatch(null, errCode, new Object[] {arg1, arg2, arg3}, null);
+    }
+
+    /*
+     * Dispatches the given JSP parse error to the configured error handler.
+     *
+     * The given error code is localized. If it is not found in the
+     * resource bundle for localized error messages, it is used as the error
+     * message.
+     *
+     * @param where Error location
+     * @param errCode Error code
+     * @param arg1 First argument for parametric replacement
+     * @param arg2 Second argument for parametric replacement
+     */
+    public void jspError(Mark where, String errCode, String arg1, String arg2)
+	        throws JasperException {
+	dispatch(where, errCode, new Object[] {arg1, arg2}, null);
+    }
+
+    /*
+     * Dispatches the given JSP parse error to the configured error handler.
+     *
+     * The given error code is localized. If it is not found in the
+     * resource bundle for localized error messages, it is used as the error
+     * message.
+     *
+     * @param where Error location
+     * @param errCode Error code
+     * @param arg1 First argument for parametric replacement
+     * @param arg2 Second argument for parametric replacement
+     * @param arg3 Third argument for parametric replacement
+     */
+
+    public void jspError(Mark where, String errCode, String arg1, String arg2,
+                         String arg3)
+                throws JasperException {
+        dispatch(where, errCode, new Object[] {arg1, arg2, arg3}, null);
+    }
+
+    /*
+     * Dispatches the given JSP parse error to the configured error handler.
+     *
+     * The given error code is localized. If it is not found in the
+     * resource bundle for localized error messages, it is used as the error
+     * message.
+     *
+     * @param n Node that caused the error
+     * @param errCode Error code
+     * @param arg1 First argument for parametric replacement
+     * @param arg2 Second argument for parametric replacement
+     */
+
+    public void jspError(Node n, String errCode, String arg1, String arg2)
+	        throws JasperException {
+	dispatch(n.getStart(), errCode, new Object[] {arg1, arg2}, null);
+    }
+
+    /*
+     * Dispatches the given JSP parse error to the configured error handler.
+     *
+     * The given error code is localized. If it is not found in the
+     * resource bundle for localized error messages, it is used as the error
+     * message.
+     *
+     * @param n Node that caused the error
+     * @param errCode Error code
+     * @param arg1 First argument for parametric replacement
+     * @param arg2 Second argument for parametric replacement
+     * @param arg3 Third argument for parametric replacement
+     */
+
+    public void jspError(Node n, String errCode, String arg1, String arg2,
+                         String arg3)
+	        throws JasperException {
+	dispatch(n.getStart(), errCode, new Object[] {arg1, arg2, arg3}, null);
+    }
+
+    /*
+     * Dispatches the given parsing exception to the configured error handler.
+     *
+     * @param e Parsing exception
+     */
+    public void jspError(Exception e) throws JasperException {
+	dispatch(null, null, null, e);
+    }
+
+    /*
+     * Dispatches the given JSP parse error to the configured error handler.
+     *
+     * The given error code is localized. If it is not found in the
+     * resource bundle for localized error messages, it is used as the error
+     * message.
+     *
+     * @param errCode Error code
+     * @param arg Argument for parametric replacement
+     * @param e Parsing exception
+     */
+    public void jspError(String errCode, String arg, Exception e)
+	        throws JasperException {
+	dispatch(null, errCode, new Object[] {arg}, e);
+    }
+
+    /*
+     * Dispatches the given JSP parse error to the configured error handler.
+     *
+     * The given error code is localized. If it is not found in the
+     * resource bundle for localized error messages, it is used as the error
+     * message.
+     *
+     * @param n Node that caused the error
+     * @param errCode Error code
+     * @param arg Argument for parametric replacement
+     * @param e Parsing exception
+     */
+    public void jspError(Node n, String errCode, String arg, Exception e)
+	        throws JasperException {
+	dispatch(n.getStart(), errCode, new Object[] {arg}, e);
+    }
+
+    /**
+     * Parses the given error message into an array of javac compilation error
+     * messages (one per javac compilation error line number).
+     *
+     * @param errMsg Error message
+     * @param fname Name of Java source file whose compilation failed
+     * @param page Node representation of JSP page from which the Java source
+     * file was generated
+     *
+     * @return Array of javac compilation errors, or null if the given error
+     * message does not contain any compilation error line numbers
+     */
+    public static JavacErrorDetail[] parseJavacErrors(String errMsg,
+                                                      String fname,
+                                                      Node.Nodes page)
+            throws JasperException, IOException {
+
+	return parseJavacMessage(errMsg, fname, page);
+    }
+
+    /*
+     * Dispatches the given javac compilation errors to the configured error
+     * handler.
+     *
+     * @param javacErrors Array of javac compilation errors
+     */
+    public void javacError(JavacErrorDetail[] javacErrors)
+            throws JasperException {
+
+        errHandler.javacError(javacErrors);
+    }
+
+
+    /*
+     * Dispatches the given compilation error report and exception to the
+     * configured error handler.
+     *
+     * @param errorReport Compilation error report
+     * @param e Compilation exception
+     */
+    public void javacError(String errorReport, Exception e)
+                throws JasperException {
+
+        errHandler.javacError(errorReport, e);
+    }
+
+
+    //*********************************************************************
+    // Private utility methods
+
+    /*
+     * Dispatches the given JSP parse error to the configured error handler.
+     *
+     * The given error code is localized. If it is not found in the
+     * resource bundle for localized error messages, it is used as the error
+     * message.
+     *
+     * @param where Error location
+     * @param errCode Error code
+     * @param args Arguments for parametric replacement
+     * @param e Parsing exception
+     */
+    private void dispatch(Mark where, String errCode, Object[] args,
+			  Exception e) throws JasperException {
+	String file = null;
+	String errMsg = null;
+	int line = -1;
+	int column = -1;
+	boolean hasLocation = false;
+
+	// Localize
+	if (errCode != null) {
+	    errMsg = Localizer.getMessage(errCode, args);
+	} else if (e != null) {
+	    // give a hint about what's wrong
+	    errMsg = e.getMessage();
+	}
+
+	// Get error location
+	if (where != null) {
+            if (jspcMode) {
+                // Get the full URL of the resource that caused the error
+                try {
+                    file = where.getURL().toString();
+                } catch (MalformedURLException me) {
+                    // Fallback to using context-relative path
+                    file = where.getFile();
+                }
+            } else {
+                // Get the context-relative resource path, so as to not
+                // disclose any local filesystem details
+                file = where.getFile();
+            }
+	    line = where.getLineNumber();
+	    column = where.getColumnNumber();
+	    hasLocation = true;
+	}
+
+	// Get nested exception
+	Exception nestedEx = e;
+	if ((e instanceof SAXException)
+	        && (((SAXException) e).getException() != null)) {
+	    nestedEx = ((SAXException) e).getException();
+	}
+
+	if (hasLocation) {
+	    errHandler.jspError(file, line, column, errMsg, nestedEx);
+	} else {
+	    errHandler.jspError(errMsg, nestedEx);
+	}
+    }
+
+    /*
+     * Parses the given Java compilation error message, which may contain one
+     * or more compilation errors, into an array of JavacErrorDetail instances.
+     *
+     * Each JavacErrorDetail instance contains the information about a single
+     * compilation error.
+     *
+     * @param errMsg Compilation error message that was generated by the
+     * javac compiler
+     * @param fname Name of Java source file whose compilation failed
+     * @param page Node representation of JSP page from which the Java source
+     * file was generated
+     *
+     * @return Array of JavacErrorDetail instances corresponding to the
+     * compilation errors
+     */
+    private static JavacErrorDetail[] parseJavacMessage(
+                                String errMsg, String fname, Node.Nodes page)
+	        throws IOException, JasperException {
+
+        Vector errVec = new Vector();
+        StringBuffer errMsgBuf = null;
+        int lineNum = -1;
+        JavacErrorDetail javacError = null;
+        
+        BufferedReader reader = new BufferedReader(new StringReader(errMsg));
+        
+        /*
+         * Parse compilation errors. Each compilation error consists of a file
+         * path and error line number, followed by a number of lines describing
+         * the error.
+         */
+        String line = null;
+        while ((line = reader.readLine()) != null) {
+            
+            /*
+             * Error line number is delimited by set of colons.
+             * Ignore colon following drive letter on Windows (fromIndex = 2).
+             * XXX Handle deprecation warnings that don't have line info
+             */
+            int beginColon = line.indexOf(':', 2); 
+            int endColon = line.indexOf(':', beginColon + 1);
+            if ((beginColon >= 0) && (endColon >= 0)) {
+                if (javacError != null) {
+                    // add previous error to error vector
+                    errVec.add(javacError);
+                }
+                
+                String lineNumStr = line.substring(beginColon + 1, endColon);
+                try {
+                    lineNum = Integer.parseInt(lineNumStr);
+                } catch (NumberFormatException e) {
+                    // XXX
+                }
+                
+                errMsgBuf = new StringBuffer();
+                
+                javacError = createJavacError(fname, page, errMsgBuf, lineNum);
+            }
+            
+            // Ignore messages preceding first error
+            if (errMsgBuf != null) {
+                errMsgBuf.append(line);
+                errMsgBuf.append("\n");
+            }
+        }
+        
+        // Add last error to error vector
+        if (javacError != null) {
+            errVec.add(javacError);
+        } 
+        
+        reader.close();
+        
+        JavacErrorDetail[] errDetails = null;
+        if (errVec.size() > 0) {
+            errDetails = new JavacErrorDetail[errVec.size()];
+            errVec.copyInto(errDetails);
+        }
+        
+        return errDetails;
+    }
+
+
+    /**
+     * @param fname
+     * @param page
+     * @param errMsgBuf
+     * @param lineNum
+     * @return JavacErrorDetail The error details
+     * @throws JasperException
+     */
+    public static JavacErrorDetail createJavacError(String fname, Node.Nodes page, 
+            StringBuffer errMsgBuf, int lineNum) throws JasperException {
+        JavacErrorDetail javacError;
+        // Attempt to map javac error line number to line in JSP page
+        ErrorVisitor errVisitor = new ErrorVisitor(lineNum);
+        page.visit(errVisitor);
+        Node errNode = errVisitor.getJspSourceNode();
+        if ((errNode != null) && (errNode.getStart() != null)) {
+            javacError = new JavacErrorDetail(
+                    fname,
+                    lineNum,
+                    errNode.getStart().getFile(),
+                    errNode.getStart().getLineNumber(),
+                    errMsgBuf);
+        } else {
+            /*
+             * javac error line number cannot be mapped to JSP page
+             * line number. For example, this is the case if a 
+             * scriptlet is missing a closing brace, which causes
+             * havoc with the try-catch-finally block that the code
+             * generator places around all generated code: As a result
+             * of this, the javac error line numbers will be outside
+             * the range of begin and end java line numbers that were
+             * generated for the scriptlet, and therefore cannot be
+             * mapped to the start line number of the scriptlet in the
+             * JSP page.
+             * Include just the javac error info in the error detail.
+             */
+            javacError = new JavacErrorDetail(
+                    fname,
+                    lineNum,
+                    errMsgBuf);
+        }
+        return javacError;
+    }
+
+
+    /*
+     * Visitor responsible for mapping a line number in the generated servlet
+     * source code to the corresponding JSP node.
+     */
+    static class ErrorVisitor extends Node.Visitor {
+
+	// Java source line number to be mapped
+	private int lineNum;
+
+	/*
+	 * JSP node whose Java source code range in the generated servlet
+	 * contains the Java source line number to be mapped
+	 */
+	Node found;
+
+	/*
+	 * Constructor.
+	 *
+	 * @param lineNum Source line number in the generated servlet code
+	 */
+	public ErrorVisitor(int lineNum) {
+	    this.lineNum = lineNum;
+	}
+
+	public void doVisit(Node n) throws JasperException {
+	    if ((lineNum >= n.getBeginJavaLine())
+		    && (lineNum < n.getEndJavaLine())) {
+		found = n;
+	    }
+        }
+
+	/*
+	 * Gets the JSP node to which the source line number in the generated
+	 * servlet code was mapped.
+	 *
+	 * @return JSP node to which the source line number in the generated
+	 * servlet code was mapped
+	 */
+	public Node getJspSourceNode() {
+	    return found;
+	}
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/ErrorHandler.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/ErrorHandler.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/ErrorHandler.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,72 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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 org.apache.jasper.JasperException;
+
+/**
+ * Interface for handling JSP parse and javac compilation errors.
+ * 
+ * An implementation of this interface may be registered with the
+ * ErrorDispatcher by setting the XXX initialization parameter in the JSP
+ * page compiler and execution servlet in Catalina's web.xml file to the
+ * implementation's fully qualified class name.
+ *
+ * @author Jan Luehe
+ * @author Kin-man Chung
+ */
+public interface ErrorHandler {
+
+    /**
+     * Processes the given JSP parse error.
+     *
+     * @param fname Name of the JSP file in which the parse error occurred
+     * @param line Parse error line number
+     * @param column Parse error column number
+     * @param msg Parse error message
+     * @param exception Parse exception
+     */
+    public void jspError(String fname, int line, int column, String msg,
+			 Exception exception) throws JasperException;
+
+    /**
+     * Processes the given JSP parse error.
+     *
+     * @param msg Parse error message
+     * @param exception Parse exception
+     */
+    public void jspError(String msg, Exception exception)
+	throws JasperException;
+
+    /**
+     * Processes the given javac compilation errors.
+     *
+     * @param details Array of JavacErrorDetail instances corresponding to the
+     * compilation errors
+     */
+    public void javacError(JavacErrorDetail[] details)
+	throws JasperException;
+
+    /**
+     * Processes the given javac error report and exception.
+     *
+     * @param errorReport Compilation error report
+     * @param exception Compilation exception
+     */
+    public void javacError(String errorReport, Exception exception)
+        throws JasperException;
+}

Added: branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/Generator.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/Generator.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/Generator.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,4059 @@
+/*
+ * Copyright 1999,2004-2006 The Apache Software Foundation.
+ *
+ * Licensed 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.beans.BeanInfo;
+import java.beans.IntrospectionException;
+import java.beans.Introspector;
+import java.beans.PropertyDescriptor;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Vector;
+
+import javax.servlet.jsp.tagext.TagAttributeInfo;
+import javax.servlet.jsp.tagext.TagInfo;
+import javax.servlet.jsp.tagext.TagVariableInfo;
+import javax.servlet.jsp.tagext.VariableInfo;
+
+import org.apache.jasper.Constants;
+import org.apache.jasper.JasperException;
+import org.apache.jasper.JspCompilationContext;
+import org.apache.jasper.runtime.JspRuntimeLibrary;
+import org.xml.sax.Attributes;
+
+/**
+ * Generate Java source from Nodes
+ *
+ * @author Anil K. Vijendran
+ * @author Danno Ferrin
+ * @author Mandar Raje
+ * @author Rajiv Mordani
+ * @author Pierre Delisle
+ *
+ * Tomcat 4.1.x and Tomcat 5:
+ * @author Kin-man Chung
+ * @author Jan Luehe
+ * @author Shawn Bayern
+ * @author Mark Roth
+ * @author Denis Benoit
+ */
+
+class Generator {
+
+    private static final Class[] OBJECT_CLASS = { Object.class };
+    private ServletWriter out;
+    private ArrayList methodsBuffered;
+    private FragmentHelperClass fragmentHelperClass;
+    private ErrorDispatcher err;
+    private BeanRepository beanInfo;
+    private JspCompilationContext ctxt;
+    private boolean isPoolingEnabled;
+    private boolean breakAtLF;
+    private PageInfo pageInfo;
+    private Vector tagHandlerPoolNames;
+    private GenBuffer charArrayBuffer;
+
+    /**
+     * @param s the input string
+     * @return quoted and escaped string, per Java rule
+     */
+    static String quote(String s) {
+
+        if (s == null)
+            return "null";
+
+        return '"' + escape(s) + '"';
+    }
+
+    /**
+     * @param s the input string
+     * @return escaped string, per Java rule
+     */
+    static String escape(String s) {
+
+        if (s == null)
+            return "";
+
+        StringBuffer b = new StringBuffer();
+        for (int i = 0; i < s.length(); i++) {
+            char c = s.charAt(i);
+            if (c == '"')
+                b.append('\\').append('"');
+            else if (c == '\\')
+                b.append('\\').append('\\');
+            else if (c == '\n')
+                b.append('\\').append('n');
+            else if (c == '\r')
+                b.append('\\').append('r');
+            else
+                b.append(c);
+        }
+        return b.toString();
+    }
+
+    /**
+     * Single quote and escape a character
+     */
+    static String quote(char c) {
+
+        StringBuffer b = new StringBuffer();
+        b.append('\'');
+        if (c == '\'')
+            b.append('\\').append('\'');
+        else if (c == '\\')
+            b.append('\\').append('\\');
+        else if (c == '\n')
+            b.append('\\').append('n');
+        else if (c == '\r')
+            b.append('\\').append('r');
+        else
+            b.append(c);
+        b.append('\'');
+        return b.toString();
+    }
+
+    /**
+     * Generates declarations.  This includes "info" of the page directive,
+     * and scriptlet declarations.
+     */
+    private void generateDeclarations(Node.Nodes page) throws JasperException {
+
+        class DeclarationVisitor extends Node.Visitor {
+
+            private boolean getServletInfoGenerated = false;
+
+            /*
+             * Generates getServletInfo() method that returns the value of the
+             * page directive's 'info' attribute, if present.
+             *
+             * The Validator has already ensured that if the translation unit
+             * contains more than one page directive with an 'info' attribute,
+             * their values match.
+             */
+            public void visit(Node.PageDirective n) throws JasperException {
+
+                if (getServletInfoGenerated) {
+                    return;
+                }
+
+                String info = n.getAttributeValue("info");
+                if (info == null)
+                    return;
+
+                getServletInfoGenerated = true;
+                out.printil("public String getServletInfo() {");
+                out.pushIndent();
+                out.printin("return ");
+                out.print(quote(info));
+                out.println(";");
+                out.popIndent();
+                out.printil("}");
+                out.println();
+            }
+
+            public void visit(Node.Declaration n) throws JasperException {
+                n.setBeginJavaLine(out.getJavaLine());
+                out.printMultiLn(new String(n.getText()));
+                out.println();
+                n.setEndJavaLine(out.getJavaLine());
+            }
+
+            // Custom Tags may contain declarations from tag plugins.
+            public void visit(Node.CustomTag n) throws JasperException {
+                if (n.useTagPlugin()) {
+                    if (n.getAtSTag() != null) {
+                        n.getAtSTag().visit(this);
+                    }
+                    visitBody(n);
+                    if (n.getAtETag() != null) {
+                        n.getAtETag().visit(this);
+                    }
+                } else {
+                    visitBody(n);
+                }
+            }
+        }
+
+        out.println();
+        page.visit(new DeclarationVisitor());
+    }
+
+    /**
+     * Compiles list of tag handler pool names.
+     */
+    private void compileTagHandlerPoolList(Node.Nodes page)
+        throws JasperException {
+
+        class TagHandlerPoolVisitor extends Node.Visitor {
+
+            private Vector names;
+
+            /*
+             * Constructor
+             *
+             * @param v Vector of tag handler pool names to populate
+             */
+            TagHandlerPoolVisitor(Vector v) {
+                names = v;
+            }
+
+            /*
+             * Gets the name of the tag handler pool for the given custom tag
+             * and adds it to the list of tag handler pool names unless it is
+             * already contained in it.
+             */
+            public void visit(Node.CustomTag n) throws JasperException {
+
+                if (!n.implementsSimpleTag()) {
+                    String name =
+                        createTagHandlerPoolName(
+                            n.getPrefix(),
+                            n.getLocalName(),
+                            n.getAttributes(),
+                            n.hasEmptyBody());
+                    n.setTagHandlerPoolName(name);
+                    if (!names.contains(name)) {
+                        names.add(name);
+                    }
+                }
+                visitBody(n);
+            }
+
+            /*
+             * Creates the name of the tag handler pool whose tag handlers may
+             * be (re)used to service this action.
+             *
+             * @return The name of the tag handler pool
+             */
+            private String createTagHandlerPoolName(
+                String prefix,
+                String shortName,
+                Attributes attrs,
+                boolean hasEmptyBody) {
+                String poolName = null;
+
+                poolName = "_jspx_tagPool_" + prefix + "_" + shortName;
+                if (attrs != null) {
+                    String[] attrNames = new String[attrs.getLength()];
+                    for (int i = 0; i < attrNames.length; i++) {
+                        attrNames[i] = attrs.getQName(i);
+                    }
+                    Arrays.sort(attrNames, Collections.reverseOrder());
+                    for (int i = 0; i < attrNames.length; i++) {
+                        poolName = poolName + "_" + attrNames[i];
+                    }
+                }
+                if (hasEmptyBody) {
+                    poolName = poolName + "_nobody";
+                }
+                return JspUtil.makeXmlJavaIdentifier(poolName);
+            }
+        }
+
+        page.visit(new TagHandlerPoolVisitor(tagHandlerPoolNames));
+    }
+
+    private void declareTemporaryScriptingVars(Node.Nodes page)
+        throws JasperException {
+
+        class ScriptingVarVisitor extends Node.Visitor {
+
+            private Vector vars;
+
+            ScriptingVarVisitor() {
+                vars = new Vector();
+            }
+
+            public void visit(Node.CustomTag n) throws JasperException {
+
+                if (n.getCustomNestingLevel() > 0) {
+                    TagVariableInfo[] tagVarInfos = n.getTagVariableInfos();
+                    VariableInfo[] varInfos = n.getVariableInfos();
+
+                    if (varInfos.length > 0) {
+                        for (int i = 0; i < varInfos.length; i++) {
+                            String varName = varInfos[i].getVarName();
+                            String tmpVarName =
+                                "_jspx_"
+                                    + varName
+                                    + "_"
+                                    + n.getCustomNestingLevel();
+                            if (!vars.contains(tmpVarName)) {
+                                vars.add(tmpVarName);
+                                out.printin(varInfos[i].getClassName());
+                                out.print(" ");
+                                out.print(tmpVarName);
+                                out.print(" = ");
+                                out.print(null);
+                                out.println(";");
+                            }
+                        }
+                    } else {
+                        for (int i = 0; i < tagVarInfos.length; i++) {
+                            String varName = tagVarInfos[i].getNameGiven();
+                            if (varName == null) {
+                                varName =
+                                    n.getTagData().getAttributeString(
+                                        tagVarInfos[i].getNameFromAttribute());
+                            } else if (
+                                tagVarInfos[i].getNameFromAttribute()
+                                    != null) {
+                                // alias
+                                continue;
+                            }
+                            String tmpVarName =
+                                "_jspx_"
+                                    + varName
+                                    + "_"
+                                    + n.getCustomNestingLevel();
+                            if (!vars.contains(tmpVarName)) {
+                                vars.add(tmpVarName);
+                                out.printin(tagVarInfos[i].getClassName());
+                                out.print(" ");
+                                out.print(tmpVarName);
+                                out.print(" = ");
+                                out.print(null);
+                                out.println(";");
+                            }
+                        }
+                    }
+                }
+
+                visitBody(n);
+            }
+        }
+
+        page.visit(new ScriptingVarVisitor());
+    }
+
+    /**
+     * Generates the _jspInit() method for instantiating the tag handler pools.
+     * For tag file, _jspInit has to be invoked manually, and the ServletConfig
+     * object explicitly passed.
+     */
+    private void generateInit() {
+
+        if (ctxt.isTagFile()) {
+            out.printil("private void _jspInit(ServletConfig config) {");
+        } else {
+            out.printil("public void _jspInit() {");
+        }
+
+        out.pushIndent();
+        for (int i = 0; i < tagHandlerPoolNames.size(); i++) {
+            out.printin((String)tagHandlerPoolNames.elementAt(i));
+            out.print(
+                " = org.apache.jasper.runtime.TagHandlerPool.getTagHandlerPool(");
+            if (ctxt.isTagFile()) {
+                out.print("config");
+            } else {
+                out.print("getServletConfig()");
+            }
+            out.println(");");
+        }
+        out.popIndent();
+        out.printil("}");
+        out.println();
+    }
+
+    /**
+     * Generates the _jspDestroy() method which is responsible for calling the
+     * release() method on every tag handler in any of the tag handler pools.
+     */
+    private void generateDestroy() {
+
+        out.printil("public void _jspDestroy() {");
+        out.pushIndent();
+        for (int i = 0; i < tagHandlerPoolNames.size(); i++) {
+            out.printin((String)tagHandlerPoolNames.elementAt(i));
+            out.println(".release();");
+        }
+        out.popIndent();
+        out.printil("}");
+        out.println();
+    }
+
+    /**
+     * Generate preamble package name
+     * (shared by servlet and tag handler preamble generation)
+     */
+    private void genPreamblePackage(String packageName)
+        throws JasperException {
+        if (!"".equals(packageName) && packageName != null) {
+            out.printil("package " + packageName + ";");
+            out.println();
+        }
+    }
+
+    /**
+     * Generate preamble imports
+     * (shared by servlet and tag handler preamble generation)
+     */
+    private void genPreambleImports() throws JasperException {
+        Iterator iter = pageInfo.getImports().iterator();
+        while (iter.hasNext()) {
+            out.printin("import ");
+            out.print((String)iter.next());
+            out.println(";");
+        }
+        out.println();
+    }
+
+    /**
+     * Generation of static initializers in preamble.
+     * For example, dependant list, el function map, prefix map.
+     * (shared by servlet and tag handler preamble generation)
+     */
+    private void genPreambleStaticInitializers() throws JasperException {
+        // Static data for getDependants()
+        out.printil("private static java.util.List _jspx_dependants;");
+        out.println();
+        List dependants = pageInfo.getDependants();
+        Iterator iter = dependants.iterator();
+        if (!dependants.isEmpty()) {
+            out.printil("static {");
+            out.pushIndent();
+            out.printin("_jspx_dependants = new java.util.ArrayList(");
+            out.print("" + dependants.size());
+            out.println(");");
+            while (iter.hasNext()) {
+                out.printin("_jspx_dependants.add(\"");
+                out.print((String)iter.next());
+                out.println("\");");
+            }
+            out.popIndent();
+            out.printil("}");
+            out.println();
+        }
+    }
+
+    /**
+     * Declare tag handler pools (tags of the same type and with the same
+     * attribute set share the same tag handler pool)
+     * (shared by servlet and tag handler preamble generation)
+     */
+    private void genPreambleClassVariableDeclarations(String className)
+        throws JasperException {
+        if (isPoolingEnabled && !tagHandlerPoolNames.isEmpty()) {
+            for (int i = 0; i < tagHandlerPoolNames.size(); i++) {
+                out.printil(
+                    "private org.apache.jasper.runtime.TagHandlerPool "
+                        + tagHandlerPoolNames.elementAt(i)
+                        + ";");
+            }
+            out.println();
+        }
+    }
+
+    /**
+     * Declare general-purpose methods
+     * (shared by servlet and tag handler preamble generation)
+     */
+    private void genPreambleMethods() throws JasperException {
+        // Method used to get compile time file dependencies
+        out.printil("public Object getDependants() {");
+        out.pushIndent();
+        out.printil("return _jspx_dependants;");
+        out.popIndent();
+        out.printil("}");
+        out.println();
+
+        if (isPoolingEnabled && !tagHandlerPoolNames.isEmpty()) {
+            generateInit();
+            generateDestroy();
+        }
+    }
+
+    /**
+     * Generates the beginning of the static portion of the servlet.
+     */
+    private void generatePreamble(Node.Nodes page) throws JasperException {
+
+        String servletPackageName = ctxt.getServletPackageName();
+        String servletClassName = ctxt.getServletClassName();
+        String serviceMethodName = Constants.SERVICE_METHOD_NAME;
+
+        // First the package name:
+        genPreamblePackage(servletPackageName);
+
+        // Generate imports
+        genPreambleImports();
+
+        // Generate class declaration
+        out.printin("public final class ");
+        out.print(servletClassName);
+        out.print(" extends ");
+        out.println(pageInfo.getExtends());
+        out.printin(
+            "    implements org.apache.jasper.runtime.JspSourceDependent");
+        if (!pageInfo.isThreadSafe()) {
+            out.println(",");
+            out.printin("                 SingleThreadModel");
+        }
+        out.println(" {");
+        out.pushIndent();
+
+        // Class body begins here
+        generateDeclarations(page);
+
+        // Static initializations here
+        genPreambleStaticInitializers();
+
+        // Class variable declarations
+        genPreambleClassVariableDeclarations(servletClassName);
+
+        // Constructor
+        //  generateConstructor(className);
+
+        // Methods here
+        genPreambleMethods();
+
+        // Now the service method
+        out.printin("public void ");
+        out.print(serviceMethodName);
+        out.println(
+            "(HttpServletRequest request, HttpServletResponse response)");
+        out.println("        throws java.io.IOException, ServletException {");
+
+        out.pushIndent();
+        out.println();
+
+        // Local variable declarations
+        out.printil("JspFactory _jspxFactory = null;");
+        out.printil("PageContext pageContext = null;");
+        if (pageInfo.isSession())
+            out.printil("HttpSession session = null;");
+
+        if (pageInfo.isErrorPage()) {
+            out.printil(
+                "Throwable exception = org.apache.jasper.runtime.JspRuntimeLibrary.getThrowable(request);");
+            out.printil("if (exception != null) {");
+            out.pushIndent();
+            out.printil(
+                "response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);");
+            out.popIndent();
+            out.printil("}");
+        }
+
+        out.printil("ServletContext application = null;");
+        out.printil("ServletConfig config = null;");
+        out.printil("JspWriter out = null;");
+        out.printil("Object page = this;");
+
+        out.printil("JspWriter _jspx_out = null;");
+        out.printil("PageContext _jspx_page_context = null;");
+        out.println();
+
+        declareTemporaryScriptingVars(page);
+        out.println();
+
+        out.printil("try {");
+        out.pushIndent();
+
+        out.printil("_jspxFactory = JspFactory.getDefaultFactory();");
+
+        out.printin("response.setContentType(");
+        out.print(quote(pageInfo.getContentType()));
+        out.println(");");
+
+        if (ctxt.getOptions().isXpoweredBy()) {
+            out.printil("response.addHeader(\"X-Powered-By\", \"JSP/2.0\");");
+        }
+
+        out.printil(
+            "pageContext = _jspxFactory.getPageContext(this, request, response,");
+        out.printin("\t\t\t");
+        out.print(quote(pageInfo.getErrorPage()));
+        out.print(", " + pageInfo.isSession());
+        out.print(", " + pageInfo.getBuffer());
+        out.print(", " + pageInfo.isAutoFlush());
+        out.println(");");
+        out.printil("_jspx_page_context = pageContext;");
+
+        out.printil("application = pageContext.getServletContext();");
+        out.printil("config = pageContext.getServletConfig();");
+
+        if (pageInfo.isSession())
+            out.printil("session = pageContext.getSession();");
+        out.printil("out = pageContext.getOut();");
+        out.printil("_jspx_out = out;");
+        out.println();
+    }
+
+    /**
+     * Generates an XML Prolog, which includes an XML declaration and
+     * an XML doctype declaration.
+     */
+    private void generateXmlProlog(Node.Nodes page) {
+
+        /*
+         * An XML declaration is generated under the following conditions:
+         *
+         * - 'omit-xml-declaration' attribute of <jsp:output> action is set to
+         *   "no" or "false"
+         * - JSP document without a <jsp:root>
+         */
+        String omitXmlDecl = pageInfo.getOmitXmlDecl();
+        if ((omitXmlDecl != null && !JspUtil.booleanValue(omitXmlDecl))
+            || (omitXmlDecl == null
+                && page.getRoot().isXmlSyntax()
+                && !pageInfo.hasJspRoot()
+                && !ctxt.isTagFile())) {
+            String cType = pageInfo.getContentType();
+            String charSet = cType.substring(cType.indexOf("charset=") + 8);
+            out.printil(
+                "out.write(\"<?xml version=\\\"1.0\\\" encoding=\\\""
+                    + charSet
+                    + "\\\"?>\\n\");");
+        }
+
+        /*
+         * Output a DOCTYPE declaration if the doctype-root-element appears.
+         * If doctype-public appears:
+         *     <!DOCTYPE name PUBLIC "doctypePublic" "doctypeSystem">
+         * else
+         *     <!DOCTYPE name SYSTEM "doctypeSystem" >
+         */
+
+        String doctypeName = pageInfo.getDoctypeName();
+        if (doctypeName != null) {
+            String doctypePublic = pageInfo.getDoctypePublic();
+            String doctypeSystem = pageInfo.getDoctypeSystem();
+            out.printin("out.write(\"<!DOCTYPE ");
+            out.print(doctypeName);
+            if (doctypePublic == null) {
+                out.print(" SYSTEM \\\"");
+            } else {
+                out.print(" PUBLIC \\\"");
+                out.print(doctypePublic);
+                out.print("\\\" \\\"");
+            }
+            out.print(doctypeSystem);
+            out.println("\\\">\\n\");");
+        }
+    }
+
+    /*
+     * Generates the constructor.
+     * (shared by servlet and tag handler preamble generation)
+     */
+    private void generateConstructor(String className) {
+        out.printil("public " + className + "() {");
+        out.printil("}");
+        out.println();
+    }
+
+    /**
+     * A visitor that generates codes for the elements in the page.
+     */
+    class GenerateVisitor extends Node.Visitor {
+
+        /*
+         * Hashtable containing introspection information on tag handlers:
+         *   <key>: tag prefix
+         *   <value>: hashtable containing introspection on tag handlers:
+         *              <key>: tag short name
+         *              <value>: introspection info of tag handler for
+         *                       <prefix:shortName> tag
+         */
+        private Hashtable handlerInfos;
+
+        private Hashtable tagVarNumbers;
+        private String parent;
+        private boolean isSimpleTagParent; // Is parent a SimpleTag?
+        private String pushBodyCountVar;
+        private String simpleTagHandlerVar;
+        private boolean isSimpleTagHandler;
+        private boolean isFragment;
+        private boolean isTagFile;
+        private ServletWriter out;
+        private ArrayList methodsBuffered;
+        private FragmentHelperClass fragmentHelperClass;
+        private int methodNesting;
+        private TagInfo tagInfo;
+        private ClassLoader loader;
+        private int charArrayCount;
+        private HashMap textMap;
+
+        /**
+         * Constructor.
+         */
+        public GenerateVisitor(
+            boolean isTagFile,
+            ServletWriter out,
+            ArrayList methodsBuffered,
+            FragmentHelperClass fragmentHelperClass,
+            ClassLoader loader,
+            TagInfo tagInfo) {
+
+            this.isTagFile = isTagFile;
+            this.out = out;
+            this.methodsBuffered = methodsBuffered;
+            this.fragmentHelperClass = fragmentHelperClass;
+            this.loader = loader;
+            this.tagInfo = tagInfo;
+            methodNesting = 0;
+            handlerInfos = new Hashtable();
+            tagVarNumbers = new Hashtable();
+            textMap = new HashMap();
+        }
+
+        /**
+         * Returns an attribute value, optionally URL encoded.  If
+         * the value is a runtime expression, the result is the expression
+         * itself, as a string.  If the result is an EL expression, we insert
+         * a call to the interpreter.  If the result is a Named Attribute
+         * we insert the generated variable name.  Otherwise the result is a
+         * string literal, quoted and escaped.
+         *
+         * @param attr An JspAttribute object
+         * @param encode true if to be URL encoded
+         * @param expectedType the expected type for an EL evaluation
+         *        (ignored for attributes that aren't EL expressions)
+         */
+        private String attributeValue(
+            Node.JspAttribute attr,
+            boolean encode,
+            Class expectedType) {
+            String v = attr.getValue();
+            if (!attr.isNamedAttribute() && (v == null))
+                return "";
+
+            if (attr.isExpression()) {
+                if (encode) {
+                    return "org.apache.jasper.runtime.JspRuntimeLibrary.URLEncode(String.valueOf("
+                        + v
+                        + "), request.getCharacterEncoding())";
+                }
+                return v;
+            } else if (attr.isELInterpreterInput()) {
+                boolean replaceESC = v.indexOf(Constants.ESC) > 0;
+                v =
+                    JspUtil.interpreterCall(
+                        this.isTagFile,
+                        v,
+                        expectedType,
+                        attr.getEL().getMapName(),
+                        false);
+                // XXX ESC replacement hack
+                if (replaceESC) {
+                    v = "(" + v + ").replace(" + Constants.ESCStr + ", '$')";
+                }
+                if (encode) {
+                    return "org.apache.jasper.runtime.JspRuntimeLibrary.URLEncode("
+                        + v
+                        + ", request.getCharacterEncoding())";
+                }
+                return v;
+            } else if (attr.isNamedAttribute()) {
+                return attr.getNamedAttributeNode().getTemporaryVariableName();
+            } else {
+                if (encode) {
+                    return "org.apache.jasper.runtime.JspRuntimeLibrary.URLEncode("
+                        + quote(v)
+                        + ", request.getCharacterEncoding())";
+                }
+                return quote(v);
+            }
+        }
+
+        /**
+         * Prints the attribute value specified in the param action, in the
+         * form of name=value string.
+         *
+         * @param n the parent node for the param action nodes.
+         */
+        private void printParams(Node n, String pageParam, boolean literal)
+            throws JasperException {
+
+            class ParamVisitor extends Node.Visitor {
+                String separator;
+
+                ParamVisitor(String separator) {
+                    this.separator = separator;
+                }
+
+                public void visit(Node.ParamAction n) throws JasperException {
+
+                    out.print(" + ");
+                    out.print(separator);
+                    out.print(" + ");
+                    out.print(
+                        "org.apache.jasper.runtime.JspRuntimeLibrary."
+                            + "URLEncode("
+                            + quote(n.getTextAttribute("name"))
+                            + ", request.getCharacterEncoding())");
+                    out.print("+ \"=\" + ");
+                    out.print(attributeValue(n.getValue(), true, String.class));
+
+                    // The separator is '&' after the second use
+                    separator = "\"&\"";
+                }
+            }
+
+            String sep;
+            if (literal) {
+                sep = pageParam.indexOf('?') > 0 ? "\"&\"" : "\"?\"";
+            } else {
+                sep = "((" + pageParam + ").indexOf('?')>0? '&': '?')";
+            }
+            if (n.getBody() != null) {
+                n.getBody().visit(new ParamVisitor(sep));
+            }
+        }
+
+        public void visit(Node.Expression n) throws JasperException {
+            n.setBeginJavaLine(out.getJavaLine());
+            out.printin("out.print(");
+            out.printMultiLn(n.getText());
+            out.println(");");
+            n.setEndJavaLine(out.getJavaLine());
+        }
+
+        public void visit(Node.Scriptlet n) throws JasperException {
+            n.setBeginJavaLine(out.getJavaLine());
+            out.printMultiLn(n.getText());
+            out.println();
+            n.setEndJavaLine(out.getJavaLine());
+        }
+
+        public void visit(Node.ELExpression n) throws JasperException {
+            n.setBeginJavaLine(out.getJavaLine());
+            if (!pageInfo.isELIgnored()) {
+                out.printil(
+                    "out.write("
+                        + JspUtil.interpreterCall(
+                            this.isTagFile,
+                            "${" + new String(n.getText()) + "}",
+                            String.class,
+                            n.getEL().getMapName(),
+                            false)
+                        + ");");
+            } else {
+                out.printil(
+                    "out.write("
+                        + quote("${" + new String(n.getText()) + "}")
+                        + ");");
+            }
+            n.setEndJavaLine(out.getJavaLine());
+        }
+
+        public void visit(Node.IncludeAction n) throws JasperException {
+
+            String flush = n.getTextAttribute("flush");
+            Node.JspAttribute page = n.getPage();
+
+            boolean isFlush = false; // default to false;
+            if ("true".equals(flush))
+                isFlush = true;
+
+            n.setBeginJavaLine(out.getJavaLine());
+
+            String pageParam;
+            if (page.isNamedAttribute()) {
+                // If the page for jsp:include was specified via
+                // jsp:attribute, first generate code to evaluate
+                // that body.
+                pageParam =
+                    generateNamedAttributeValue(page.getNamedAttributeNode());
+            } else {
+                pageParam = attributeValue(page, false, String.class);
+            }
+
+            // If any of the params have their values specified by
+            // jsp:attribute, prepare those values first.
+            Node jspBody = findJspBody(n);
+            if (jspBody != null) {
+                prepareParams(jspBody);
+            } else {
+                prepareParams(n);
+            }
+
+            out.printin(
+                "org.apache.jasper.runtime.JspRuntimeLibrary.include(request, response, "
+                    + pageParam);
+            printParams(n, pageParam, page.isLiteral());
+            out.println(", out, " + isFlush + ");");
+
+            n.setEndJavaLine(out.getJavaLine());
+        }
+
+        /**
+         * Scans through all child nodes of the given parent for
+         * <param> subelements.  For each <param> element, if its value
+         * is specified via a Named Attribute (<jsp:attribute>),
+         * generate the code to evaluate those bodies first.
+         * <p>
+         * If parent is null, simply returns.
+         */
+        private void prepareParams(Node parent) throws JasperException {
+            if (parent == null)
+                return;
+
+            Node.Nodes subelements = parent.getBody();
+            if (subelements != null) {
+                for (int i = 0; i < subelements.size(); i++) {
+                    Node n = subelements.getNode(i);
+                    if (n instanceof Node.ParamAction) {
+                        Node.Nodes paramSubElements = n.getBody();
+                        for (int j = 0;
+                            (paramSubElements != null)
+                                && (j < paramSubElements.size());
+                            j++) {
+                            Node m = paramSubElements.getNode(j);
+                            if (m instanceof Node.NamedAttribute) {
+                                generateNamedAttributeValue(
+                                    (Node.NamedAttribute)m);
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+        /**
+         * Finds the <jsp:body> subelement of the given parent node.
+         * If not found, null is returned.
+         */
+        private Node.JspBody findJspBody(Node parent) throws JasperException {
+            Node.JspBody result = null;
+
+            Node.Nodes subelements = parent.getBody();
+            for (int i = 0;
+                (subelements != null) && (i < subelements.size());
+                i++) {
+                Node n = subelements.getNode(i);
+                if (n instanceof Node.JspBody) {
+                    result = (Node.JspBody)n;
+                    break;
+                }
+            }
+
+            return result;
+        }
+
+        public void visit(Node.ForwardAction n) throws JasperException {
+            Node.JspAttribute page = n.getPage();
+
+            n.setBeginJavaLine(out.getJavaLine());
+
+            out.printil("if (true) {"); // So that javac won't complain about
+            out.pushIndent(); // codes after "return"
+
+            String pageParam;
+            if (page.isNamedAttribute()) {
+                // If the page for jsp:forward was specified via
+                // jsp:attribute, first generate code to evaluate
+                // that body.
+                pageParam =
+                    generateNamedAttributeValue(page.getNamedAttributeNode());
+            } else {
+                pageParam = attributeValue(page, false, String.class);
+            }
+
+            // If any of the params have their values specified by
+            // jsp:attribute, prepare those values first.
+            Node jspBody = findJspBody(n);
+            if (jspBody != null) {
+                prepareParams(jspBody);
+            } else {
+                prepareParams(n);
+            }
+
+            out.printin("_jspx_page_context.forward(");
+            out.print(pageParam);
+            printParams(n, pageParam, page.isLiteral());
+            out.println(");");
+            if (isTagFile || isFragment) {
+                out.printil("throw new SkipPageException();");
+            } else {
+                out.printil((methodNesting > 0) ? "return true;" : "return;");
+            }
+            out.popIndent();
+            out.printil("}");
+
+            n.setEndJavaLine(out.getJavaLine());
+            // XXX Not sure if we can eliminate dead codes after this.
+        }
+
+        public void visit(Node.GetProperty n) throws JasperException {
+            String name = n.getTextAttribute("name");
+            String property = n.getTextAttribute("property");
+
+            n.setBeginJavaLine(out.getJavaLine());
+
+            if (beanInfo.checkVariable(name)) {
+                // Bean is defined using useBean, introspect at compile time
+                Class bean = beanInfo.getBeanType(name);
+                String beanName = JspUtil.getCanonicalName(bean);
+                java.lang.reflect.Method meth =
+                    JspRuntimeLibrary.getReadMethod(bean, property);
+                String methodName = meth.getName();
+                out.printil(
+                    "out.write(org.apache.jasper.runtime.JspRuntimeLibrary.toString("
+                        + "((("
+                        + beanName
+                        + ")_jspx_page_context.findAttribute("
+                        + "\""
+                        + name
+                        + "\"))."
+                        + methodName
+                        + "())));");
+            } else {
+                // The object could be a custom action with an associated
+                // VariableInfo entry for this name.
+                // Get the class name and then introspect at runtime.
+                out.printil(
+                    "out.write(org.apache.jasper.runtime.JspRuntimeLibrary.toString"
+                        + "(org.apache.jasper.runtime.JspRuntimeLibrary.handleGetProperty"
+                        + "(_jspx_page_context.getAttribute(\""
+                        + name
+                        + "\", PageContext.PAGE_SCOPE), \""
+                        + property
+                        + "\")));");
+            }
+
+            n.setEndJavaLine(out.getJavaLine());
+        }
+
+        public void visit(Node.SetProperty n) throws JasperException {
+            String name = n.getTextAttribute("name");
+            String property = n.getTextAttribute("property");
+            String param = n.getTextAttribute("param");
+            Node.JspAttribute value = n.getValue();
+
+            n.setBeginJavaLine(out.getJavaLine());
+
+            if ("*".equals(property)) {
+                out.printil(
+                    "org.apache.jasper.runtime.JspRuntimeLibrary.introspect("
+                        + "_jspx_page_context.findAttribute("
+                        + "\""
+                        + name
+                        + "\"), request);");
+            } else if (value == null) {
+                if (param == null)
+                    param = property; // default to same as property
+                out.printil(
+                    "org.apache.jasper.runtime.JspRuntimeLibrary.introspecthelper("
+                        + "_jspx_page_context.findAttribute(\""
+                        + name
+                        + "\"), \""
+                        + property
+                        + "\", request.getParameter(\""
+                        + param
+                        + "\"), "
+                        + "request, \""
+                        + param
+                        + "\", false);");
+            } else if (value.isExpression()) {
+                out.printil(
+                    "org.apache.jasper.runtime.JspRuntimeLibrary.handleSetProperty("
+                        + "_jspx_page_context.findAttribute(\""
+                        + name
+                        + "\"), \""
+                        + property
+                        + "\",");
+                out.print(attributeValue(value, false, null));
+                out.println(");");
+            } else if (value.isELInterpreterInput()) {
+                // We've got to resolve the very call to the interpreter
+                // at runtime since we don't know what type to expect
+                // in the general case; we thus can't hard-wire the call
+                // into the generated code.  (XXX We could, however,
+                // optimize the case where the bean is exposed with
+                // <jsp:useBean>, much as the code here does for
+                // getProperty.)
+
+                // The following holds true for the arguments passed to
+                // JspRuntimeLibrary.handleSetPropertyExpression():
+                // - 'pageContext' is a VariableResolver.
+                // - 'this' (either the generated Servlet or the generated tag
+                //   handler for Tag files) is a FunctionMapper.
+                out.printil(
+                    "org.apache.jasper.runtime.JspRuntimeLibrary.handleSetPropertyExpression("
+                        + "_jspx_page_context.findAttribute(\""
+                        + name
+                        + "\"), \""
+                        + property
+                        + "\", "
+                        + quote(value.getValue())
+                        + ", "
+                        + "_jspx_page_context, "
+                        + value.getEL().getMapName()
+                        + ");");
+            } else if (value.isNamedAttribute()) {
+                // If the value for setProperty was specified via
+                // jsp:attribute, first generate code to evaluate
+                // that body.
+                String valueVarName =
+                    generateNamedAttributeValue(value.getNamedAttributeNode());
+                out.printil(
+                    "org.apache.jasper.runtime.JspRuntimeLibrary.introspecthelper("
+                        + "_jspx_page_context.findAttribute(\""
+                        + name
+                        + "\"), \""
+                        + property
+                        + "\", "
+                        + valueVarName
+                        + ", null, null, false);");
+            } else {
+                out.printin(
+                    "org.apache.jasper.runtime.JspRuntimeLibrary.introspecthelper("
+                        + "_jspx_page_context.findAttribute(\""
+                        + name
+                        + "\"), \""
+                        + property
+                        + "\", ");
+                out.print(attributeValue(value, false, null));
+                out.println(", null, null, false);");
+            }
+
+            n.setEndJavaLine(out.getJavaLine());
+        }
+
+        public void visit(Node.UseBean n) throws JasperException {
+
+            String name = n.getTextAttribute("id");
+            String scope = n.getTextAttribute("scope");
+            String klass = n.getTextAttribute("class");
+            String type = n.getTextAttribute("type");
+            Node.JspAttribute beanName = n.getBeanName();
+
+            // If "class" is specified, try an instantiation at compile time
+            boolean generateNew = false;
+            String canonicalName = null;    // Canonical name for klass
+            if (klass != null) {
+                try {
+                    Class bean = ctxt.getClassLoader().loadClass(klass);
+                    if (klass.indexOf('$') >= 0)  {
+                        // Obtain the canonical type name
+                        canonicalName = JspUtil.getCanonicalName(bean);
+                    } else {
+                        canonicalName = klass;
+                    }
+                    int modifiers = bean.getModifiers();
+                    if (!Modifier.isPublic(modifiers) ||
+                        Modifier.isInterface(modifiers) ||
+                        Modifier.isAbstract(modifiers)) {
+                        throw new Exception("Invalid bean class modifier");
+                    }
+                    // Check that there is a 0 arg constructor
+                    bean.getConstructor(new Class[] {});
+                    // At compile time, we have determined that the bean class
+                    // exists, with a public zero constructor, new() can be
+                    // used for bean instantiation.
+                    generateNew = true;
+                } catch (Exception e) {
+                    // Cannot instantiate the specified class, either a
+                    // compilation error or a runtime error will be raised,
+                    // depending on a compiler flag.
+                    if(ctxt.getOptions().getErrorOnUseBeanInvalidClassAttribute()) {
+                        err.jspError(n, "jsp.error.invalid.bean", klass);
+                    }
+                    if (canonicalName == null) {
+                        // Doing our best here to get a canonical name
+                        // from the binary name, should work 99.99% of time.
+                        canonicalName = klass.replace('$','.');
+                    }
+                }
+                if (type == null) {
+                    // if type is unspecified, use "class" as type of bean
+                    type = canonicalName;
+                }
+            }
+
+            String scopename = "PageContext.PAGE_SCOPE"; // Default to page
+            String lock = "_jspx_page_context";
+
+            if ("request".equals(scope)) {
+                scopename = "PageContext.REQUEST_SCOPE";
+                lock = "request";
+            } else if ("session".equals(scope)) {
+                scopename = "PageContext.SESSION_SCOPE";
+                lock = "session";
+            } else if ("application".equals(scope)) {
+                scopename = "PageContext.APPLICATION_SCOPE";
+                lock = "application";
+            }
+
+            n.setBeginJavaLine(out.getJavaLine());
+
+            // Declare bean
+            out.printin(type);
+            out.print(' ');
+            out.print(name);
+            out.println(" = null;");
+
+            // Lock while getting or creating bean
+            out.printin("synchronized (");
+            out.print(lock);
+            out.println(") {");
+            out.pushIndent();
+
+            // Locate bean from context
+            out.printin(name);
+            out.print(" = (");
+            out.print(type);
+            out.print(") _jspx_page_context.getAttribute(");
+            out.print(quote(name));
+            out.print(", ");
+            out.print(scopename);
+            out.println(");");
+
+            // Create bean
+            /*
+             * Check if bean is alredy there
+             */
+            out.printin("if (");
+            out.print(name);
+            out.println(" == null){");
+            out.pushIndent();
+            if (klass == null && beanName == null) {
+                /*
+                 * If both class name and beanName is not specified, the bean
+                 * must be found locally, otherwise it's an error
+                 */
+                out.printin(
+                    "throw new java.lang.InstantiationException(\"bean ");
+                out.print(name);
+                out.println(" not found within scope\");");
+            } else {
+                /*
+                 * Instantiate the bean if it is not in the specified scope.
+                 */
+                if (!generateNew) {
+                    String binaryName;
+                    if (beanName != null) {
+                        if (beanName.isNamedAttribute()) {
+                            // If the value for beanName was specified via
+                            // jsp:attribute, first generate code to evaluate
+                            // that body.
+                            binaryName =
+                                generateNamedAttributeValue(
+                                    beanName.getNamedAttributeNode());
+                        } else {
+                            binaryName =
+                                attributeValue(beanName, false, String.class);
+                        }
+                    } else {
+                        // Implies klass is not null
+                        binaryName = quote(klass);
+                    }
+                    out.printil("try {");
+                    out.pushIndent();
+                    out.printin(name);
+                    out.print(" = (");
+                    out.print(type);
+                    out.print(") java.beans.Beans.instantiate(");
+                    out.print("this.getClass().getClassLoader(), ");
+                    out.print(binaryName);
+                    out.println(");");
+                    out.popIndent();
+                    /*
+                     * Note: Beans.instantiate throws ClassNotFoundException
+                     * if the bean class is abstract.
+                     */
+                    out.printil("} catch (ClassNotFoundException exc) {");
+                    out.pushIndent();
+                    out.printil(
+                        "throw new InstantiationException(exc.getMessage());");
+                    out.popIndent();
+                    out.printil("} catch (Exception exc) {");
+                    out.pushIndent();
+                    out.printin("throw new ServletException(");
+                    out.print("\"Cannot create bean of class \" + ");
+                    out.print(binaryName);
+                    out.println(", exc);");
+                    out.popIndent();
+                    out.printil("}"); // close of try
+                } else {
+                    // Implies klass is not null
+                    // Generate codes to instantiate the bean class
+                    out.printin(name);
+                    out.print(" = new ");
+                    out.print(canonicalName);
+                    out.println("();");
+                }
+                /*
+                 * Set attribute for bean in the specified scope
+                 */
+                out.printin("_jspx_page_context.setAttribute(");
+                out.print(quote(name));
+                out.print(", ");
+                out.print(name);
+                out.print(", ");
+                out.print(scopename);
+                out.println(");");
+
+                // Only visit the body when bean is instantiated
+                visitBody(n);
+            }
+            out.popIndent();
+            out.printil("}");
+
+            // End of lock block
+            out.popIndent();
+            out.printil("}");
+
+            n.setEndJavaLine(out.getJavaLine());
+        }
+
+        /**
+         * @return a string for the form 'attr = "value"'
+         */
+        private String makeAttr(String attr, String value) {
+            if (value == null)
+                return "";
+
+            return " " + attr + "=\"" + value + '\"';
+        }
+
+        public void visit(Node.PlugIn n) throws JasperException {
+
+            /**
+             * A visitor to handle <jsp:param> in a plugin
+             */
+            class ParamVisitor extends Node.Visitor {
+
+                private boolean ie;
+
+                ParamVisitor(boolean ie) {
+                    this.ie = ie;
+                }
+
+                public void visit(Node.ParamAction n) throws JasperException {
+
+                    String name = n.getTextAttribute("name");
+                    if (name.equalsIgnoreCase("object"))
+                        name = "java_object";
+                    else if (name.equalsIgnoreCase("type"))
+                        name = "java_type";
+
+                    n.setBeginJavaLine(out.getJavaLine());
+                    // XXX - Fixed a bug here - value used to be output
+                    // inline, which is only okay if value is not an EL
+                    // expression.  Also, key/value pairs for the
+                    // embed tag were not being generated correctly.
+                    // Double check that this is now the correct behavior.
+                    if (ie) {
+                        // We want something of the form
+                        // out.println( "<PARAM name=\"blah\"
+                        //     value=\"" + ... + "\">" );
+                        out.printil(
+                            "out.write( \"<PARAM name=\\\""
+                                + escape(name)
+                                + "\\\" value=\\\"\" + "
+                                + attributeValue(
+                                    n.getValue(),
+                                    false,
+                                    String.class)
+                                + " + \"\\\">\" );");
+                        out.printil("out.write(\"\\n\");");
+                    } else {
+                        // We want something of the form
+                        // out.print( " blah=\"" + ... + "\"" );
+                        out.printil(
+                            "out.write( \" "
+                                + escape(name)
+                                + "=\\\"\" + "
+                                + attributeValue(
+                                    n.getValue(),
+                                    false,
+                                    String.class)
+                                + " + \"\\\"\" );");
+                    }
+
+                    n.setEndJavaLine(out.getJavaLine());
+                }
+            }
+
+            String type = n.getTextAttribute("type");
+            String code = n.getTextAttribute("code");
+            String name = n.getTextAttribute("name");
+            Node.JspAttribute height = n.getHeight();
+            Node.JspAttribute width = n.getWidth();
+            String hspace = n.getTextAttribute("hspace");
+            String vspace = n.getTextAttribute("vspace");
+            String align = n.getTextAttribute("align");
+            String iepluginurl = n.getTextAttribute("iepluginurl");
+            String nspluginurl = n.getTextAttribute("nspluginurl");
+            String codebase = n.getTextAttribute("codebase");
+            String archive = n.getTextAttribute("archive");
+            String jreversion = n.getTextAttribute("jreversion");
+
+            String widthStr = null;
+            if (width != null) {
+                if (width.isNamedAttribute()) {
+                    widthStr =
+                        generateNamedAttributeValue(
+                            width.getNamedAttributeNode());
+                } else {
+                    widthStr = attributeValue(width, false, String.class);
+                }
+            }
+
+            String heightStr = null;
+            if (height != null) {
+                if (height.isNamedAttribute()) {
+                    heightStr =
+                        generateNamedAttributeValue(
+                            height.getNamedAttributeNode());
+                } else {
+                    heightStr = attributeValue(height, false, String.class);
+                }
+            }
+
+            if (iepluginurl == null)
+                iepluginurl = Constants.IE_PLUGIN_URL;
+            if (nspluginurl == null)
+                nspluginurl = Constants.NS_PLUGIN_URL;
+
+            n.setBeginJavaLine(out.getJavaLine());
+
+            // If any of the params have their values specified by
+            // jsp:attribute, prepare those values first.
+            // Look for a params node and prepare its param subelements:
+            Node.JspBody jspBody = findJspBody(n);
+            if (jspBody != null) {
+                Node.Nodes subelements = jspBody.getBody();
+                if (subelements != null) {
+                    for (int i = 0; i < subelements.size(); i++) {
+                        Node m = subelements.getNode(i);
+                        if (m instanceof Node.ParamsAction) {
+                            prepareParams(m);
+                            break;
+                        }
+                    }
+                }
+            }
+
+            // XXX - Fixed a bug here - width and height can be set
+            // dynamically.  Double-check if this generation is correct.
+
+            // IE style plugin
+            // <OBJECT ...>
+            // First compose the runtime output string
+            String s0 = "<OBJECT"
+                    + makeAttr("classid", ctxt.getOptions().getIeClassId())
+                    + makeAttr("name", name);
+
+            String s1 = "";
+            if (width != null) {
+                s1 = " + \" width=\\\"\" + " + widthStr + " + \"\\\"\"";
+            }
+
+            String s2 = "";
+            if (height != null) {
+                s2 = " + \" height=\\\"\" + " + heightStr + " + \"\\\"\"";
+            }
+
+            String s3 = makeAttr("hspace", hspace)
+                    + makeAttr("vspace", vspace)
+                    + makeAttr("align", align)
+                    + makeAttr("codebase", iepluginurl)
+                    + '>';
+
+            // Then print the output string to the java file
+            out.printil(
+                "out.write(" + quote(s0) + s1 + s2 + " + " + quote(s3) + ");");
+            out.printil("out.write(\"\\n\");");
+
+            // <PARAM > for java_code
+            s0 = "<PARAM name=\"java_code\"" + makeAttr("value", code) + '>';
+            out.printil("out.write(" + quote(s0) + ");");
+            out.printil("out.write(\"\\n\");");
+
+            // <PARAM > for java_codebase
+            if (codebase != null) {
+                s0 = "<PARAM name=\"java_codebase\""
+                        + makeAttr("value", codebase)
+                        + '>';
+                out.printil("out.write(" + quote(s0) + ");");
+                out.printil("out.write(\"\\n\");");
+            }
+
+            // <PARAM > for java_archive
+            if (archive != null) {
+                s0 = "<PARAM name=\"java_archive\""
+                        + makeAttr("value", archive)
+                        + '>';
+                out.printil("out.write(" + quote(s0) + ");");
+                out.printil("out.write(\"\\n\");");
+            }
+
+            // <PARAM > for type
+            s0 = "<PARAM name=\"type\""
+                    + makeAttr(
+                        "value",
+                        "application/x-java-"
+                            + type
+                            + ";"
+                            + ((jreversion == null)
+                                ? ""
+                                : "version=" + jreversion))
+                    + '>';
+            out.printil("out.write(" + quote(s0) + ");");
+            out.printil("out.write(\"\\n\");");
+
+            /*
+             * generate a <PARAM> for each <jsp:param> in the plugin body
+             */
+            if (n.getBody() != null)
+                n.getBody().visit(new ParamVisitor(true));
+
+            /*
+             * Netscape style plugin part
+             */
+            out.printil("out.write(" + quote("<COMMENT>") + ");");
+            out.printil("out.write(\"\\n\");");
+            s0 = "<EMBED"
+                    + makeAttr(
+                        "type",
+                        "application/x-java-"
+                            + type
+                            + ";"
+                            + ((jreversion == null)
+                                ? ""
+                                : "version=" + jreversion))
+                    + makeAttr("name", name);
+
+            // s1 and s2 are the same as before.
+
+            s3 = makeAttr("hspace", hspace)
+                    + makeAttr("vspace", vspace)
+                    + makeAttr("align", align)
+                    + makeAttr("pluginspage", nspluginurl)
+                    + makeAttr("java_code", code)
+                    + makeAttr("java_codebase", codebase)
+                    + makeAttr("java_archive", archive);
+            out.printil(
+                "out.write(" + quote(s0) + s1 + s2 + " + " + quote(s3) + ");");
+
+            /*
+             * Generate a 'attr = "value"' for each <jsp:param> in plugin body
+             */
+            if (n.getBody() != null)
+                n.getBody().visit(new ParamVisitor(false));
+
+            out.printil("out.write(" + quote("/>") + ");");
+            out.printil("out.write(\"\\n\");");
+
+            out.printil("out.write(" + quote("<NOEMBED>") + ");");
+            out.printil("out.write(\"\\n\");");
+
+            /*
+             * Fallback
+             */
+            if (n.getBody() != null) {
+                visitBody(n);
+                out.printil("out.write(\"\\n\");");
+            }
+
+            out.printil("out.write(" + quote("</NOEMBED>") + ");");
+            out.printil("out.write(\"\\n\");");
+
+            out.printil("out.write(" + quote("</COMMENT>") + ");");
+            out.printil("out.write(\"\\n\");");
+
+            out.printil("out.write(" + quote("</OBJECT>") + ");");
+            out.printil("out.write(\"\\n\");");
+
+            n.setEndJavaLine(out.getJavaLine());
+        }
+
+        public void visit(Node.NamedAttribute n) throws JasperException {
+            // Don't visit body of this tag - we already did earlier.
+        }
+
+        public void visit(Node.CustomTag n) throws JasperException {
+
+            // Use plugin to generate more efficient code if there is one.
+            if (n.useTagPlugin()) {
+                generateTagPlugin(n);
+                return;
+            }
+
+            TagHandlerInfo handlerInfo = getTagHandlerInfo(n);
+
+            // Create variable names
+            String baseVar =
+                createTagVarName(n.getQName(), n.getPrefix(), n.getLocalName());
+            String tagEvalVar = "_jspx_eval_" + baseVar;
+            String tagHandlerVar = "_jspx_th_" + baseVar;
+            String tagPushBodyCountVar = "_jspx_push_body_count_" + baseVar;
+
+            // If the tag contains no scripting element, generate its codes
+            // to a method.
+            ServletWriter outSave = null;
+            Node.ChildInfo ci = n.getChildInfo();
+            if (ci.isScriptless() && !ci.hasScriptingVars()) {
+                // The tag handler and its body code can reside in a separate
+                // method if it is scriptless and does not have any scripting
+                // variable defined.
+
+                String tagMethod = "_jspx_meth_" + baseVar;
+
+                // Generate a call to this method
+                out.printin("if (");
+                out.print(tagMethod);
+                out.print("(");
+                if (parent != null) {
+                    out.print(parent);
+                    out.print(", ");
+                }
+                out.print("_jspx_page_context");
+                if (pushBodyCountVar != null) {
+                    out.print(", ");
+                    out.print(pushBodyCountVar);
+                }
+                out.println("))");
+                out.pushIndent();
+                out.printil((methodNesting > 0) ? "return true;" : "return;");
+                out.popIndent();
+
+                // Set up new buffer for the method
+                outSave = out;
+                /* For fragments, their bodies will be generated in fragment
+                   helper classes, and the Java line adjustments will be done
+                   there, hence they are set to null here to avoid double
+                   adjustments.
+                */
+                GenBuffer genBuffer =
+                    new GenBuffer(n, n.implementsSimpleTag()? null: n.getBody());
+                methodsBuffered.add(genBuffer);
+                out = genBuffer.getOut();
+
+                methodNesting++;
+                // Generate code for method declaration
+                out.println();
+                out.pushIndent();
+                out.printin("private boolean ");
+                out.print(tagMethod);
+                out.print("(");
+                if (parent != null) {
+                    out.print("javax.servlet.jsp.tagext.JspTag ");
+                    out.print(parent);
+                    out.print(", ");
+                }
+                out.print("PageContext _jspx_page_context");
+                if (pushBodyCountVar != null) {
+                    out.print(", int[] ");
+                    out.print(pushBodyCountVar);
+                }
+                out.println(")");
+                out.printil("        throws Throwable {");
+                out.pushIndent();
+
+                // Initilaize local variables used in this method.
+                if (! isTagFile) {
+                    out.printil("PageContext pageContext = _jspx_page_context;");
+                }
+                out.printil("JspWriter out = _jspx_page_context.getOut();");
+                generateLocalVariables(out, n);
+            }
+
+            if (n.implementsSimpleTag()) {
+                generateCustomDoTag(n, handlerInfo, tagHandlerVar);
+            } else {
+                /*
+                 * Classic tag handler: Generate code for start element, body,
+                 * and end element
+                 */
+                generateCustomStart(
+                    n,
+                    handlerInfo,
+                    tagHandlerVar,
+                    tagEvalVar,
+                    tagPushBodyCountVar);
+
+                // visit body
+                String tmpParent = parent;
+                parent = tagHandlerVar;
+                boolean isSimpleTagParentSave = isSimpleTagParent;
+                isSimpleTagParent = false;
+                String tmpPushBodyCountVar = null;
+                if (n.implementsTryCatchFinally()) {
+                    tmpPushBodyCountVar = pushBodyCountVar;
+                    pushBodyCountVar = tagPushBodyCountVar;
+                }
+                boolean tmpIsSimpleTagHandler = isSimpleTagHandler;
+                isSimpleTagHandler = false;
+
+                visitBody(n);
+
+                parent = tmpParent;
+                isSimpleTagParent = isSimpleTagParentSave;
+                if (n.implementsTryCatchFinally()) {
+                    pushBodyCountVar = tmpPushBodyCountVar;
+                }
+                isSimpleTagHandler = tmpIsSimpleTagHandler;
+
+                generateCustomEnd(
+                    n,
+                    tagHandlerVar,
+                    tagEvalVar,
+                    tagPushBodyCountVar);
+            }
+
+            if (ci.isScriptless() && !ci.hasScriptingVars()) {
+                // Generate end of method
+                if (methodNesting > 0) {
+                    out.printil("return false;");
+                }
+                out.popIndent();
+                out.printil("}");
+                out.popIndent();
+
+                methodNesting--;
+
+                // restore previous writer
+                out = outSave;
+            }
+        }
+
+        private static final String SINGLE_QUOTE = "'";
+        private static final String DOUBLE_QUOTE = "\\\"";
+
+        public void visit(Node.UninterpretedTag n) throws JasperException {
+
+            n.setBeginJavaLine(out.getJavaLine());
+
+            /*
+             * Write begin tag
+             */
+            out.printin("out.write(\"<");
+            out.print(n.getQName());
+
+            Attributes attrs = n.getNonTaglibXmlnsAttributes();
+            int attrsLen = (attrs == null) ? 0 : attrs.getLength();
+            for (int i = 0; i < attrsLen; i++) {
+                out.print(" ");
+                out.print(attrs.getQName(i));
+                out.print("=");
+                String quote = DOUBLE_QUOTE;
+                String value = attrs.getValue(i);
+                if (value.indexOf('"') != -1) {
+                    quote = SINGLE_QUOTE;
+                }
+                out.print(quote);
+                out.print(value);
+                out.print(quote);
+            }
+
+            attrs = n.getAttributes();
+            attrsLen = (attrs == null) ? 0 : attrs.getLength();
+            Node.JspAttribute[] jspAttrs = n.getJspAttributes();
+            for (int i = 0; i < attrsLen; i++) {
+                out.print(" ");
+                out.print(attrs.getQName(i));
+                out.print("=");
+                if (jspAttrs[i].isELInterpreterInput()) {
+                    out.print("\\\"\" + ");
+                    out.print(attributeValue(jspAttrs[i], false, String.class));
+                    out.print(" + \"\\\"");
+                } else {
+                    String quote = DOUBLE_QUOTE;
+                    String value = attrs.getValue(i);
+                    if (value.indexOf('"') != -1) {
+                        quote = SINGLE_QUOTE;
+                    }
+                    out.print(quote);
+                    out.print(value);
+                    out.print(quote);
+                }
+            }
+
+            if (n.getBody() != null) {
+                out.println(">\");");
+
+                // Visit tag body
+                visitBody(n);
+
+                /*
+                 * Write end tag
+                 */
+                out.printin("out.write(\"</");
+                out.print(n.getQName());
+                out.println(">\");");
+            } else {
+                out.println("/>\");");
+            }
+
+            n.setEndJavaLine(out.getJavaLine());
+        }
+
+        public void visit(Node.JspElement n) throws JasperException {
+
+            n.setBeginJavaLine(out.getJavaLine());
+
+            // Compute attribute value string for XML-style and named
+            // attributes
+            Hashtable map = new Hashtable();
+            Node.JspAttribute[] attrs = n.getJspAttributes();
+            for (int i = 0; attrs != null && i < attrs.length; i++) {
+                String attrStr = null;
+                if (attrs[i].isNamedAttribute()) {
+                    attrStr =
+                        generateNamedAttributeValue(
+                            attrs[i].getNamedAttributeNode());
+                } else {
+                    attrStr = attributeValue(attrs[i], false, Object.class);
+                }
+                String s =
+                    " + \" "
+                        + attrs[i].getName()
+                        + "=\\\"\" + "
+                        + attrStr
+                        + " + \"\\\"\"";
+                map.put(attrs[i].getName(), s);
+            }
+
+            // Write begin tag, using XML-style 'name' attribute as the
+            // element name
+            String elemName =
+                attributeValue(n.getNameAttribute(), false, String.class);
+            out.printin("out.write(\"<\"");
+            out.print(" + " + elemName);
+
+            // Write remaining attributes
+            Enumeration enumeration = map.keys();
+            while (enumeration.hasMoreElements()) {
+                String attrName = (String)enumeration.nextElement();
+                out.print((String)map.get(attrName));
+            }
+
+            // Does the <jsp:element> have nested tags other than
+            // <jsp:attribute>
+            boolean hasBody = false;
+            Node.Nodes subelements = n.getBody();
+            if (subelements != null) {
+                for (int i = 0; i < subelements.size(); i++) {
+                    Node subelem = subelements.getNode(i);
+                    if (!(subelem instanceof Node.NamedAttribute)) {
+                        hasBody = true;
+                        break;
+                    }
+                }
+            }
+            if (hasBody) {
+                out.println(" + \">\");");
+
+                // Smap should not include the body
+                n.setEndJavaLine(out.getJavaLine());
+
+                // Visit tag body
+                visitBody(n);
+
+                // Write end tag
+                out.printin("out.write(\"</\"");
+                out.print(" + " + elemName);
+                out.println(" + \">\");");
+            } else {
+                out.println(" + \"/>\");");
+                n.setEndJavaLine(out.getJavaLine());
+            }
+        }
+
+        public void visit(Node.TemplateText n) throws JasperException {
+
+            String text = n.getText();
+
+            int textSize = text.length();
+            if (textSize == 0) {
+                return;
+            }
+
+            // Replace marker for \$ sequence with correct sequence
+            if (text.indexOf(Constants.ESC) > 0) {
+                if (pageInfo.isELIgnored()) {
+                    text = text.replaceAll(String.valueOf(Constants.ESC), "\\\\\\$");
+                    textSize++;
+                } else {
+                    text = text.replace(Constants.ESC, '$');
+                }
+            }
+
+            if (textSize <= 3) {
+               // Special case small text strings
+               n.setBeginJavaLine(out.getJavaLine());
+               int lineInc = 0;
+               for (int i = 0; i < textSize; i++) {
+                   char ch = text.charAt(i);
+                   out.printil("out.write(" + quote(ch) + ");");
+                   if (i > 0) {
+                       n.addSmap(lineInc);
+                   }
+                   if (ch == '\n') {
+                       lineInc++;
+                   }
+               }
+               n.setEndJavaLine(out.getJavaLine());
+               return;
+           }
+
+            if (ctxt.getOptions().genStringAsCharArray()) {
+               // Generate Strings as char arrays, for performance
+                ServletWriter caOut;
+                if (charArrayBuffer == null) {
+                    charArrayBuffer = new GenBuffer();
+                    caOut = charArrayBuffer.getOut();
+                    caOut.pushIndent();
+                    textMap = new HashMap();
+                } else {
+                    caOut = charArrayBuffer.getOut();
+                }
+                String charArrayName = (String) textMap.get(text);
+                if (charArrayName == null) {
+                    charArrayName = "_jspx_char_array_" + charArrayCount++;
+                    textMap.put(text, charArrayName);
+                    caOut.printin("static char[] ");
+                    caOut.print(charArrayName);
+                    caOut.print(" = ");
+                    caOut.print(quote(text));
+                    caOut.println(".toCharArray();");
+                }
+
+                n.setBeginJavaLine(out.getJavaLine());
+                out.printil("out.write(" + charArrayName + ");");
+                n.setEndJavaLine(out.getJavaLine());
+                return;
+            }
+
+            n.setBeginJavaLine(out.getJavaLine());
+
+            out.printin();
+            StringBuffer sb = new StringBuffer("out.write(\"");
+            int initLength = sb.length();
+            int count = JspUtil.CHUNKSIZE;
+            int srcLine = 0;    // relative to starting srouce line
+            for (int i = 0; i < text.length(); i++) {
+                char ch = text.charAt(i);
+                --count;
+                switch (ch) {
+                    case '"' :
+                        sb.append('\\').append('\"');
+                        break;
+                    case '\\' :
+                        sb.append('\\').append('\\');
+                        break;
+                    case '\r' :
+                        sb.append('\\').append('r');
+                        break;
+                    case '\n' :
+                        sb.append('\\').append('n');
+                        srcLine++;
+
+                        if (breakAtLF || count < 0) {
+                            // Generate an out.write() when see a '\n' in template
+                            sb.append("\");");
+                            out.println(sb.toString());
+                            if (i < text.length() - 1) {
+                                out.printin();
+                            }
+                            sb.setLength(initLength);
+                            count = JspUtil.CHUNKSIZE;
+                        }
+                        // add a Smap for this line
+                        n.addSmap(srcLine);
+                        break;
+                    case '\t' : // Not sure we need this
+                        sb.append('\\').append('t');
+                        break;
+                    default :
+                        sb.append(ch);
+                }
+            }
+
+            if (sb.length() > initLength) {
+                sb.append("\");");
+                out.println(sb.toString());
+            }
+
+            n.setEndJavaLine(out.getJavaLine());
+        }
+
+        public void visit(Node.JspBody n) throws JasperException {
+            if (n.getBody() != null) {
+                if (isSimpleTagHandler) {
+                    out.printin(simpleTagHandlerVar);
+                    out.print(".setJspBody(");
+                    generateJspFragment(n, simpleTagHandlerVar);
+                    out.println(");");
+                } else {
+                    visitBody(n);
+                }
+            }
+        }
+
+        public void visit(Node.InvokeAction n) throws JasperException {
+
+            n.setBeginJavaLine(out.getJavaLine());
+
+            // Copy virtual page scope of tag file to page scope of invoking
+            // page
+            out.printil(
+                "((org.apache.jasper.runtime.JspContextWrapper) this.jspContext).syncBeforeInvoke();");
+            String varReaderAttr = n.getTextAttribute("varReader");
+            String varAttr = n.getTextAttribute("var");
+            if (varReaderAttr != null || varAttr != null) {
+                out.printil("_jspx_sout = new java.io.StringWriter();");
+            } else {
+                out.printil("_jspx_sout = null;");
+            }
+
+            // Invoke fragment, unless fragment is null
+            out.printin("if (");
+            out.print(toGetterMethod(n.getTextAttribute("fragment")));
+            out.println(" != null) {");
+            out.pushIndent();
+            out.printin(toGetterMethod(n.getTextAttribute("fragment")));
+            out.println(".invoke(_jspx_sout);");
+            out.popIndent();
+            out.printil("}");
+
+            // Store varReader in appropriate scope
+            if (varReaderAttr != null || varAttr != null) {
+                String scopeName = n.getTextAttribute("scope");
+                out.printin("_jspx_page_context.setAttribute(");
+                if (varReaderAttr != null) {
+                    out.print(quote(varReaderAttr));
+                    out.print(
+                        ", new java.io.StringReader(_jspx_sout.toString())");
+                } else {
+                    out.print(quote(varAttr));
+                    out.print(", _jspx_sout.toString()");
+                }
+                if (scopeName != null) {
+                    out.print(", ");
+                    out.print(getScopeConstant(scopeName));
+                }
+                out.println(");");
+            }
+
+            n.setEndJavaLine(out.getJavaLine());
+        }
+
+        public void visit(Node.DoBodyAction n) throws JasperException {
+
+            n.setBeginJavaLine(out.getJavaLine());
+
+            // Copy virtual page scope of tag file to page scope of invoking
+            // page
+            out.printil(
+                "((org.apache.jasper.runtime.JspContextWrapper) this.jspContext).syncBeforeInvoke();");
+
+            // Invoke body
+            String varReaderAttr = n.getTextAttribute("varReader");
+            String varAttr = n.getTextAttribute("var");
+            if (varReaderAttr != null || varAttr != null) {
+                out.printil("_jspx_sout = new java.io.StringWriter();");
+            } else {
+                out.printil("_jspx_sout = null;");
+            }
+            out.printil("if (getJspBody() != null)");
+            out.pushIndent();
+            out.printil("getJspBody().invoke(_jspx_sout);");
+            out.popIndent();
+
+            // Store varReader in appropriate scope
+            if (varReaderAttr != null || varAttr != null) {
+                String scopeName = n.getTextAttribute("scope");
+                out.printin("_jspx_page_context.setAttribute(");
+                if (varReaderAttr != null) {
+                    out.print(quote(varReaderAttr));
+                    out.print(
+                        ", new java.io.StringReader(_jspx_sout.toString())");
+                } else {
+                    out.print(quote(varAttr));
+                    out.print(", _jspx_sout.toString()");
+                }
+                if (scopeName != null) {
+                    out.print(", ");
+                    out.print(getScopeConstant(scopeName));
+                }
+                out.println(");");
+            }
+
+            n.setEndJavaLine(out.getJavaLine());
+        }
+
+        public void visit(Node.AttributeGenerator n) throws JasperException {
+            Node.CustomTag tag = n.getTag();
+            Node.JspAttribute[] attrs = tag.getJspAttributes();
+            for (int i = 0; attrs != null && i < attrs.length; i++) {
+                if (attrs[i].getName().equals(n.getName())) {
+                    out.print(
+                        evaluateAttribute(
+                            getTagHandlerInfo(tag),
+                            attrs[i],
+                            tag,
+                            null));
+                    break;
+                }
+            }
+        }
+
+        private TagHandlerInfo getTagHandlerInfo(Node.CustomTag n)
+            throws JasperException {
+            Hashtable handlerInfosByShortName =
+                (Hashtable)handlerInfos.get(n.getPrefix());
+            if (handlerInfosByShortName == null) {
+                handlerInfosByShortName = new Hashtable();
+                handlerInfos.put(n.getPrefix(), handlerInfosByShortName);
+            }
+            TagHandlerInfo handlerInfo =
+                (TagHandlerInfo)handlerInfosByShortName.get(n.getLocalName());
+            if (handlerInfo == null) {
+                handlerInfo =
+                    new TagHandlerInfo(n, n.getTagHandlerClass(), err);
+                handlerInfosByShortName.put(n.getLocalName(), handlerInfo);
+            }
+            return handlerInfo;
+        }
+
+        private void generateTagPlugin(Node.CustomTag n)
+            throws JasperException {
+            if (n.getAtSTag() != null) {
+                n.getAtSTag().visit(this);
+            }
+            visitBody(n);
+            if (n.getAtETag() != null) {
+                n.getAtETag().visit(this);
+            }
+        }
+
+        private void generateCustomStart(
+            Node.CustomTag n,
+            TagHandlerInfo handlerInfo,
+            String tagHandlerVar,
+            String tagEvalVar,
+            String tagPushBodyCountVar)
+            throws JasperException {
+
+            Class tagHandlerClass = handlerInfo.getTagHandlerClass();
+
+            out.printin("//  ");
+            out.println(n.getQName());
+            n.setBeginJavaLine(out.getJavaLine());
+
+            // Declare AT_BEGIN scripting variables
+            declareScriptingVars(n, VariableInfo.AT_BEGIN);
+            saveScriptingVars(n, VariableInfo.AT_BEGIN);
+
+            String tagHandlerClassName =
+                JspUtil.getCanonicalName(tagHandlerClass);
+            out.printin(tagHandlerClassName);
+            out.print(" ");
+            out.print(tagHandlerVar);
+            out.print(" = ");
+            if (isPoolingEnabled) {
+                out.print("(");
+                out.print(tagHandlerClassName);
+                out.print(") ");
+                out.print(n.getTagHandlerPoolName());
+                out.print(".get(");
+                out.print(tagHandlerClassName);
+                out.println(".class);");
+            } else {
+                out.print("new ");
+                out.print(tagHandlerClassName);
+                out.println("();");
+            }
+
+            generateSetters(n, tagHandlerVar, handlerInfo, false);
+
+            if (n.implementsTryCatchFinally()) {
+                out.printin("int[] ");
+                out.print(tagPushBodyCountVar);
+                out.println(" = new int[] { 0 };");
+                out.printil("try {");
+                out.pushIndent();
+            }
+            out.printin("int ");
+            out.print(tagEvalVar);
+            out.print(" = ");
+            out.print(tagHandlerVar);
+            out.println(".doStartTag();");
+
+            if (!n.implementsBodyTag()) {
+                // Synchronize AT_BEGIN scripting variables
+                syncScriptingVars(n, VariableInfo.AT_BEGIN);
+            }
+
+            if (!n.hasEmptyBody()) {
+                out.printin("if (");
+                out.print(tagEvalVar);
+                out.println(" != javax.servlet.jsp.tagext.Tag.SKIP_BODY) {");
+                out.pushIndent();
+
+                // Declare NESTED scripting variables
+                declareScriptingVars(n, VariableInfo.NESTED);
+                saveScriptingVars(n, VariableInfo.NESTED);
+
+                if (n.implementsBodyTag()) {
+                    out.printin("if (");
+                    out.print(tagEvalVar);
+                    out.println(
+                        " != javax.servlet.jsp.tagext.Tag.EVAL_BODY_INCLUDE) {");
+                    // Assume EVAL_BODY_BUFFERED
+                    out.pushIndent();
+                    out.printil("out = _jspx_page_context.pushBody();");
+                    if (n.implementsTryCatchFinally()) {
+                        out.printin(tagPushBodyCountVar);
+                        out.println("[0]++;");
+                    } else if (pushBodyCountVar != null) {
+                        out.printin(pushBodyCountVar);
+                        out.println("[0]++;");
+                    }
+                    out.printin(tagHandlerVar);
+                    out.println(
+                        ".setBodyContent((javax.servlet.jsp.tagext.BodyContent) out);");
+                    out.printin(tagHandlerVar);
+                    out.println(".doInitBody();");
+
+                    out.popIndent();
+                    out.printil("}");
+
+                    // Synchronize AT_BEGIN and NESTED scripting variables
+                    syncScriptingVars(n, VariableInfo.AT_BEGIN);
+                    syncScriptingVars(n, VariableInfo.NESTED);
+
+                } else {
+                    // Synchronize NESTED scripting variables
+                    syncScriptingVars(n, VariableInfo.NESTED);
+                }
+
+                if (n.implementsIterationTag()) {
+                    out.printil("do {");
+                    out.pushIndent();
+                }
+            }
+            // Map the Java lines that handles start of custom tags to the
+            // JSP line for this tag
+            n.setEndJavaLine(out.getJavaLine());
+        }
+
+        private void generateCustomEnd(
+            Node.CustomTag n,
+            String tagHandlerVar,
+            String tagEvalVar,
+            String tagPushBodyCountVar) {
+
+            if (!n.hasEmptyBody()) {
+                if (n.implementsIterationTag()) {
+                    out.printin("int evalDoAfterBody = ");
+                    out.print(tagHandlerVar);
+                    out.println(".doAfterBody();");
+
+                    // Synchronize AT_BEGIN and NESTED scripting variables
+                    syncScriptingVars(n, VariableInfo.AT_BEGIN);
+                    syncScriptingVars(n, VariableInfo.NESTED);
+
+                    out.printil(
+                        "if (evalDoAfterBody != javax.servlet.jsp.tagext.BodyTag.EVAL_BODY_AGAIN)");
+                    out.pushIndent();
+                    out.printil("break;");
+                    out.popIndent();
+
+                    out.popIndent();
+                    out.printil("} while (true);");
+                }
+
+                restoreScriptingVars(n, VariableInfo.NESTED);
+
+                if (n.implementsBodyTag()) {
+                    out.printin("if (");
+                    out.print(tagEvalVar);
+                    out.println(
+                        " != javax.servlet.jsp.tagext.Tag.EVAL_BODY_INCLUDE) {");
+                    out.pushIndent();
+                    out.printil("out = _jspx_page_context.popBody();");
+                    if (n.implementsTryCatchFinally()) {
+                        out.printin(tagPushBodyCountVar);
+                        out.println("[0]--;");
+                    } else if (pushBodyCountVar != null) {
+                        out.printin(pushBodyCountVar);
+                        out.println("[0]--;");
+                    }
+                    out.popIndent();
+                    out.printil("}");
+                }
+
+                out.popIndent(); // EVAL_BODY
+                out.printil("}");
+            }
+
+            out.printin("if (");
+            out.print(tagHandlerVar);
+            out.println(
+                ".doEndTag() == javax.servlet.jsp.tagext.Tag.SKIP_PAGE) {");
+            out.pushIndent();
+            if(!n.implementsTryCatchFinally()) {
+                if(isPoolingEnabled) {
+                    out.printin(n.getTagHandlerPoolName());
+                    out.print(".reuse(");
+                    out.print(tagHandlerVar);
+                    out.println(");");
+                } else {
+                    out.printin(tagHandlerVar);
+                    out.println(".release();");
+                }
+            }
+            if (isTagFile || isFragment) {
+                out.printil("throw new SkipPageException();");
+            } else {
+                out.printil((methodNesting > 0) ? "return true;" : "return;");
+            }
+            out.popIndent();
+            out.printil("}");
+            // Synchronize AT_BEGIN scripting variables
+            syncScriptingVars(n, VariableInfo.AT_BEGIN);
+
+            // TryCatchFinally
+            if (n.implementsTryCatchFinally()) {
+                out.popIndent(); // try
+                out.printil("} catch (Throwable _jspx_exception) {");
+                out.pushIndent();
+
+                out.printin("while (");
+                out.print(tagPushBodyCountVar);
+                out.println("[0]-- > 0)");
+                out.pushIndent();
+                out.printil("out = _jspx_page_context.popBody();");
+                out.popIndent();
+
+                out.printin(tagHandlerVar);
+                out.println(".doCatch(_jspx_exception);");
+                out.popIndent();
+                out.printil("} finally {");
+                out.pushIndent();
+                out.printin(tagHandlerVar);
+                out.println(".doFinally();");
+            }
+
+            if (isPoolingEnabled) {
+                out.printin(n.getTagHandlerPoolName());
+                out.print(".reuse(");
+                out.print(tagHandlerVar);
+                out.println(");");
+            } else {
+                out.printin(tagHandlerVar);
+                out.println(".release();");
+            }
+
+            if (n.implementsTryCatchFinally()) {
+                out.popIndent();
+                out.printil("}");
+            }
+
+            // Declare and synchronize AT_END scripting variables (must do this
+            // outside the try/catch/finally block)
+            declareScriptingVars(n, VariableInfo.AT_END);
+            syncScriptingVars(n, VariableInfo.AT_END);
+
+            restoreScriptingVars(n, VariableInfo.AT_BEGIN);
+        }
+
+        private void generateCustomDoTag(
+            Node.CustomTag n,
+            TagHandlerInfo handlerInfo,
+            String tagHandlerVar)
+            throws JasperException {
+
+            Class tagHandlerClass = handlerInfo.getTagHandlerClass();
+
+            n.setBeginJavaLine(out.getJavaLine());
+            out.printin("//  ");
+            out.println(n.getQName());
+
+            // Declare AT_BEGIN scripting variables
+            declareScriptingVars(n, VariableInfo.AT_BEGIN);
+            saveScriptingVars(n, VariableInfo.AT_BEGIN);
+
+            String tagHandlerClassName =
+                JspUtil.getCanonicalName(tagHandlerClass);
+            out.printin(tagHandlerClassName);
+            out.print(" ");
+            out.print(tagHandlerVar);
+            out.print(" = ");
+            out.print("new ");
+            out.print(tagHandlerClassName);
+            out.println("();");
+
+            generateSetters(n, tagHandlerVar, handlerInfo, true);
+
+            // Set the body
+            if (findJspBody(n) == null) {
+                /*
+                 * Encapsulate body of custom tag invocation in JspFragment
+                 * and pass it to tag handler's setJspBody(), unless tag body
+                 * is empty
+                 */
+                if (!n.hasEmptyBody()) {
+                    out.printin(tagHandlerVar);
+                    out.print(".setJspBody(");
+                    generateJspFragment(n, tagHandlerVar);
+                    out.println(");");
+                }
+            } else {
+                /*
+                 * Body of tag is the body of the <jsp:body> element.
+                 * The visit method for that element is going to encapsulate
+                 * that element's body in a JspFragment and pass it to
+                 * the tag handler's setJspBody()
+                 */
+                String tmpTagHandlerVar = simpleTagHandlerVar;
+                simpleTagHandlerVar = tagHandlerVar;
+                boolean tmpIsSimpleTagHandler = isSimpleTagHandler;
+                isSimpleTagHandler = true;
+                visitBody(n);
+                simpleTagHandlerVar = tmpTagHandlerVar;
+                isSimpleTagHandler = tmpIsSimpleTagHandler;
+            }
+
+            out.printin(tagHandlerVar);
+            out.println(".doTag();");
+
+            restoreScriptingVars(n, VariableInfo.AT_BEGIN);
+
+            // Synchronize AT_BEGIN scripting variables
+            syncScriptingVars(n, VariableInfo.AT_BEGIN);
+
+            // Declare and synchronize AT_END scripting variables
+            declareScriptingVars(n, VariableInfo.AT_END);
+            syncScriptingVars(n, VariableInfo.AT_END);
+
+            n.setEndJavaLine(out.getJavaLine());
+        }
+
+        private void declareScriptingVars(Node.CustomTag n, int scope) {
+
+            Vector vec = n.getScriptingVars(scope);
+            if (vec != null) {
+                for (int i = 0; i < vec.size(); i++) {
+                    Object elem = vec.elementAt(i);
+                    if (elem instanceof VariableInfo) {
+                        VariableInfo varInfo = (VariableInfo)elem;
+                        if (varInfo.getDeclare()) {
+                            out.printin(varInfo.getClassName());
+                            out.print(" ");
+                            out.print(varInfo.getVarName());
+                            out.println(" = null;");
+                        }
+                    } else {
+                        TagVariableInfo tagVarInfo = (TagVariableInfo)elem;
+                        if (tagVarInfo.getDeclare()) {
+                            String varName = tagVarInfo.getNameGiven();
+                            if (varName == null) {
+                                varName =
+                                    n.getTagData().getAttributeString(
+                                        tagVarInfo.getNameFromAttribute());
+                            } else if (
+                                tagVarInfo.getNameFromAttribute() != null) {
+                                // alias
+                                continue;
+                            }
+                            out.printin(tagVarInfo.getClassName());
+                            out.print(" ");
+                            out.print(varName);
+                            out.println(" = null;");
+                        }
+                    }
+                }
+            }
+        }
+
+        /*
+         * This method is called as part of the custom tag's start element.
+         *
+         * If the given custom tag has a custom nesting level greater than 0,
+         * save the current values of its scripting variables to
+         * temporary variables, so those values may be restored in the tag's
+         * end element. This way, the scripting variables may be synchronized
+         * by the given tag without affecting their original values.
+         */
+        private void saveScriptingVars(Node.CustomTag n, int scope) {
+            if (n.getCustomNestingLevel() == 0) {
+                return;
+            }
+
+            TagVariableInfo[] tagVarInfos = n.getTagVariableInfos();
+            VariableInfo[] varInfos = n.getVariableInfos();
+            if ((varInfos.length == 0) && (tagVarInfos.length == 0)) {
+                return;
+            }
+
+            if (varInfos.length > 0) {
+                for (int i = 0; i < varInfos.length; i++) {
+                    if (varInfos[i].getScope() != scope)
+                        continue;
+                    // If the scripting variable has been declared, skip codes
+                    // for saving and restoring it.
+                    if (n.getScriptingVars(scope).contains(varInfos[i]))
+                        continue;
+                    String varName = varInfos[i].getVarName();
+                    String tmpVarName =
+                        "_jspx_" + varName + "_" + n.getCustomNestingLevel();
+                    out.printin(tmpVarName);
+                    out.print(" = ");
+                    out.print(varName);
+                    out.println(";");
+                }
+            } else {
+                for (int i = 0; i < tagVarInfos.length; i++) {
+                    if (tagVarInfos[i].getScope() != scope)
+                        continue;
+                    // If the scripting variable has been declared, skip codes
+                    // for saving and restoring it.
+                    if (n.getScriptingVars(scope).contains(tagVarInfos[i]))
+                        continue;
+                    String varName = tagVarInfos[i].getNameGiven();
+                    if (varName == null) {
+                        varName =
+                            n.getTagData().getAttributeString(
+                                tagVarInfos[i].getNameFromAttribute());
+                    } else if (tagVarInfos[i].getNameFromAttribute() != null) {
+                        // alias
+                        continue;
+                    }
+                    String tmpVarName =
+                        "_jspx_" + varName + "_" + n.getCustomNestingLevel();
+                    out.printin(tmpVarName);
+                    out.print(" = ");
+                    out.print(varName);
+                    out.println(";");
+                }
+            }
+        }
+
+        /*
+         * This method is called as part of the custom tag's end element.
+         *
+         * If the given custom tag has a custom nesting level greater than 0,
+         * restore its scripting variables to their original values that were
+         * saved in the tag's start element.
+         */
+        private void restoreScriptingVars(Node.CustomTag n, int scope) {
+            if (n.getCustomNestingLevel() == 0) {
+                return;
+            }
+
+            TagVariableInfo[] tagVarInfos = n.getTagVariableInfos();
+            VariableInfo[] varInfos = n.getVariableInfos();
+            if ((varInfos.length == 0) && (tagVarInfos.length == 0)) {
+                return;
+            }
+
+            if (varInfos.length > 0) {
+                for (int i = 0; i < varInfos.length; i++) {
+                    if (varInfos[i].getScope() != scope)
+                        continue;
+                    // If the scripting variable has been declared, skip codes
+                    // for saving and restoring it.
+                    if (n.getScriptingVars(scope).contains(varInfos[i]))
+                        continue;
+                    String varName = varInfos[i].getVarName();
+                    String tmpVarName =
+                        "_jspx_" + varName + "_" + n.getCustomNestingLevel();
+                    out.printin(varName);
+                    out.print(" = ");
+                    out.print(tmpVarName);
+                    out.println(";");
+                }
+            } else {
+                for (int i = 0; i < tagVarInfos.length; i++) {
+                    if (tagVarInfos[i].getScope() != scope)
+                        continue;
+                    // If the scripting variable has been declared, skip codes
+                    // for saving and restoring it.
+                    if (n.getScriptingVars(scope).contains(tagVarInfos[i]))
+                        continue;
+                    String varName = tagVarInfos[i].getNameGiven();
+                    if (varName == null) {
+                        varName =
+                            n.getTagData().getAttributeString(
+                                tagVarInfos[i].getNameFromAttribute());
+                    } else if (tagVarInfos[i].getNameFromAttribute() != null) {
+                        // alias
+                        continue;
+                    }
+                    String tmpVarName =
+                        "_jspx_" + varName + "_" + n.getCustomNestingLevel();
+                    out.printin(varName);
+                    out.print(" = ");
+                    out.print(tmpVarName);
+                    out.println(";");
+                }
+            }
+        }
+
+        /*
+         * Synchronizes the scripting variables of the given custom tag for
+         * the given scope.
+         */
+        private void syncScriptingVars(Node.CustomTag n, int scope) {
+            TagVariableInfo[] tagVarInfos = n.getTagVariableInfos();
+            VariableInfo[] varInfos = n.getVariableInfos();
+
+            if ((varInfos.length == 0) && (tagVarInfos.length == 0)) {
+                return;
+            }
+
+            if (varInfos.length > 0) {
+                for (int i = 0; i < varInfos.length; i++) {
+                    if (varInfos[i].getScope() == scope) {
+                        out.printin(varInfos[i].getVarName());
+                        out.print(" = (");
+                        out.print(varInfos[i].getClassName());
+                        out.print(") _jspx_page_context.findAttribute(");
+                        out.print(quote(varInfos[i].getVarName()));
+                        out.println(");");
+                    }
+                }
+            } else {
+                for (int i = 0; i < tagVarInfos.length; i++) {
+                    if (tagVarInfos[i].getScope() == scope) {
+                        String name = tagVarInfos[i].getNameGiven();
+                        if (name == null) {
+                            name =
+                                n.getTagData().getAttributeString(
+                                    tagVarInfos[i].getNameFromAttribute());
+                        } else if (
+                            tagVarInfos[i].getNameFromAttribute() != null) {
+                            // alias
+                            continue;
+                        }
+                        out.printin(name);
+                        out.print(" = (");
+                        out.print(tagVarInfos[i].getClassName());
+                        out.print(") _jspx_page_context.findAttribute(");
+                        out.print(quote(name));
+                        out.println(");");
+                    }
+                }
+            }
+        }
+
+        /*
+         * Creates a tag variable name by concatenating the given prefix and
+         * shortName and endcoded to make the resultant string a valid Java
+         * Identifier.
+         */
+        private String createTagVarName(
+            String fullName,
+            String prefix,
+            String shortName) {
+
+            String varName;
+            synchronized (tagVarNumbers) {
+                varName = prefix + "_" + shortName + "_";
+                if (tagVarNumbers.get(fullName) != null) {
+                    Integer i = (Integer)tagVarNumbers.get(fullName);
+                    varName = varName + i.intValue();
+                    tagVarNumbers.put(fullName, new Integer(i.intValue() + 1));
+                } else {
+                    tagVarNumbers.put(fullName, new Integer(1));
+                    varName = varName + "0";
+                }
+            }
+            return JspUtil.makeXmlJavaIdentifier(varName);
+        }
+
+        private String evaluateAttribute(
+            TagHandlerInfo handlerInfo,
+            Node.JspAttribute attr,
+            Node.CustomTag n,
+            String tagHandlerVar)
+            throws JasperException {
+
+            String attrValue = attr.getValue();
+            if (attrValue == null) {
+                if (attr.isNamedAttribute()) {
+                    if (n.checkIfAttributeIsJspFragment(attr.getName())) {
+                        // XXX - no need to generate temporary variable here
+                        attrValue =
+                            generateNamedAttributeJspFragment(
+                                attr.getNamedAttributeNode(),
+                                tagHandlerVar);
+                    } else {
+                        attrValue =
+                            generateNamedAttributeValue(
+                                attr.getNamedAttributeNode());
+                    }
+                } else {
+                    return null;
+                }
+            }
+
+            String localName = attr.getLocalName();
+
+            Method m = null;
+            Class[] c = null;
+            if (attr.isDynamic()) {
+                c = OBJECT_CLASS;
+            } else {
+                m = handlerInfo.getSetterMethod(localName);
+                if (m == null) {
+                    err.jspError(
+                        n,
+                        "jsp.error.unable.to_find_method",
+                        attr.getName());
+                }
+                c = m.getParameterTypes();
+                // XXX assert(c.length > 0)
+            }
+
+            if (attr.isExpression()) {
+                // Do nothing
+            } else if (attr.isNamedAttribute()) {
+                if (!n.checkIfAttributeIsJspFragment(attr.getName())
+                    && !attr.isDynamic()) {
+                    attrValue =
+                        convertString(
+                            c[0],
+                            attrValue,
+                            localName,
+                            handlerInfo.getPropertyEditorClass(localName),
+                            true);
+                }
+            } else if (attr.isELInterpreterInput()) {
+                // run attrValue through the expression interpreter
+                boolean replaceESC = attrValue.indexOf(Constants.ESC) > 0;
+                attrValue =
+                    JspUtil.interpreterCall(
+                        this.isTagFile,
+                        attrValue,
+                        c[0],
+                        attr.getEL().getMapName(),
+                        false);
+                // XXX hack: Replace ESC with '$'
+                if (replaceESC) {
+                    attrValue =
+                        "("
+                            + attrValue
+                            + ").replace("
+                            + Constants.ESCStr
+                            + ", '$')";
+                }
+            } else {
+                attrValue =
+                    convertString(
+                        c[0],
+                        attrValue,
+                        localName,
+                        handlerInfo.getPropertyEditorClass(localName),
+                        false);
+            }
+            return attrValue;
+        }
+
+        /**
+         * Generate code to create a map for the alias variables
+         * @return the name of the map
+         */
+        private String generateAliasMap(Node.CustomTag n, String tagHandlerVar)
+            throws JasperException {
+
+            TagVariableInfo[] tagVars = n.getTagVariableInfos();
+            String aliasMapVar = null;
+
+            boolean aliasSeen = false;
+            for (int i = 0; i < tagVars.length; i++) {
+
+                String nameFrom = tagVars[i].getNameFromAttribute();
+                if (nameFrom != null) {
+                    String aliasedName = n.getAttributeValue(nameFrom);
+                    if (aliasedName == null)
+                        continue;
+
+                    if (!aliasSeen) {
+                        out.printin("java.util.HashMap ");
+                        aliasMapVar = tagHandlerVar + "_aliasMap";
+                        out.print(aliasMapVar);
+                        out.println(" = new java.util.HashMap();");
+                        aliasSeen = true;
+                    }
+                    out.printin(aliasMapVar);
+                    out.print(".put(");
+                    out.print(quote(tagVars[i].getNameGiven()));
+                    out.print(", ");
+                    out.print(quote(aliasedName));
+                    out.println(");");
+                }
+            }
+            return aliasMapVar;
+        }
+
+        private void generateSetters(
+            Node.CustomTag n,
+            String tagHandlerVar,
+            TagHandlerInfo handlerInfo,
+            boolean simpleTag)
+            throws JasperException {
+
+            // Set context
+            if (simpleTag) {
+                // Generate alias map
+                String aliasMapVar = null;
+                if (n.isTagFile()) {
+                    aliasMapVar = generateAliasMap(n, tagHandlerVar);
+                }
+                out.printin(tagHandlerVar);
+                if (aliasMapVar == null) {
+                    out.println(".setJspContext(_jspx_page_context);");
+                } else {
+                    out.print(".setJspContext(_jspx_page_context, ");
+                    out.print(aliasMapVar);
+                    out.println(");");
+                }
+            } else {
+                out.printin(tagHandlerVar);
+                out.println(".setPageContext(_jspx_page_context);");
+            }
+
+            // Set parent
+            if (isTagFile && parent == null) {
+                out.printin(tagHandlerVar);
+                out.print(".setParent(");
+                out.print("new javax.servlet.jsp.tagext.TagAdapter(");
+                out.print("(javax.servlet.jsp.tagext.SimpleTag) this ));");
+            } else if (!simpleTag) {
+                out.printin(tagHandlerVar);
+                out.print(".setParent(");
+                if (parent != null) {
+                    if (isSimpleTagParent) {
+                        out.print("new javax.servlet.jsp.tagext.TagAdapter(");
+                        out.print("(javax.servlet.jsp.tagext.SimpleTag) ");
+                        out.print(parent);
+                        out.println("));");
+                    } else {
+                        out.print("(javax.servlet.jsp.tagext.Tag) ");
+                        out.print(parent);
+                        out.println(");");
+                    }
+                } else {
+                    out.println("null);");
+                }
+            } else {
+                // The setParent() method need not be called if the value being
+                // passed is null, since SimpleTag instances are not reused
+                if (parent != null) {
+                    out.printin(tagHandlerVar);
+                    out.print(".setParent(");
+                    out.print(parent);
+                    out.println(");");
+                }
+            }
+
+            Node.JspAttribute[] attrs = n.getJspAttributes();
+            for (int i = 0; attrs != null && i < attrs.length; i++) {
+                String attrValue =
+                    evaluateAttribute(handlerInfo, attrs[i], n, tagHandlerVar);
+
+                if (attrs[i].isDynamic()) {
+                    out.printin(tagHandlerVar);
+                    out.print(".");
+                    out.print("setDynamicAttribute(");
+                    String uri = attrs[i].getURI();
+                    if ("".equals(uri) || (uri == null)) {
+                        out.print("null");
+                    } else {
+                        out.print("\"" + attrs[i].getURI() + "\"");
+                    }
+                    out.print(", \"");
+                    out.print(attrs[i].getLocalName());
+                    out.print("\", ");
+                    out.print(attrValue);
+                    out.println(");");
+                } else {
+                    out.printin(tagHandlerVar);
+                    out.print(".");
+                    out.print(
+                        handlerInfo
+                            .getSetterMethod(attrs[i].getLocalName())
+                            .getName());
+                    out.print("(");
+                    out.print(attrValue);
+                    out.println(");");
+                }
+            }
+        }
+
+        /*
+         * @param c The target class to which to coerce the given string
+         * @param s The string value
+         * @param attrName The name of the attribute whose value is being
+         * supplied
+         * @param propEditorClass The property editor for the given attribute
+         * @param isNamedAttribute true if the given attribute is a named
+         * attribute (that is, specified using the jsp:attribute standard
+         * action), and false otherwise
+         */
+        private String convertString(
+            Class c,
+            String s,
+            String attrName,
+            Class propEditorClass,
+            boolean isNamedAttribute)
+            throws JasperException {
+
+            String quoted = s;
+            if (!isNamedAttribute) {
+                quoted = quote(s);
+            }
+
+            if (propEditorClass != null) {
+                String className = JspUtil.getCanonicalName(c);
+                return "("
+                    + className
+                    + ")org.apache.jasper.runtime.JspRuntimeLibrary.getValueFromBeanInfoPropertyEditor("
+                    + className
+                    + ".class, \""
+                    + attrName
+                    + "\", "
+                    + quoted
+                    + ", "
+                    + JspUtil.getCanonicalName(propEditorClass)
+                    + ".class)";
+            } else if (c == String.class) {
+                return quoted;
+            } else if (c == boolean.class) {
+                return JspUtil.coerceToPrimitiveBoolean(s, isNamedAttribute);
+            } else if (c == Boolean.class) {
+                return JspUtil.coerceToBoolean(s, isNamedAttribute);
+            } else if (c == byte.class) {
+                return JspUtil.coerceToPrimitiveByte(s, isNamedAttribute);
+            } else if (c == Byte.class) {
+                return JspUtil.coerceToByte(s, isNamedAttribute);
+            } else if (c == char.class) {
+                return JspUtil.coerceToChar(s, isNamedAttribute);
+            } else if (c == Character.class) {
+                return JspUtil.coerceToCharacter(s, isNamedAttribute);
+            } else if (c == double.class) {
+                return JspUtil.coerceToPrimitiveDouble(s, isNamedAttribute);
+            } else if (c == Double.class) {
+                return JspUtil.coerceToDouble(s, isNamedAttribute);
+            } else if (c == float.class) {
+                return JspUtil.coerceToPrimitiveFloat(s, isNamedAttribute);
+            } else if (c == Float.class) {
+                return JspUtil.coerceToFloat(s, isNamedAttribute);
+            } else if (c == int.class) {
+                return JspUtil.coerceToInt(s, isNamedAttribute);
+            } else if (c == Integer.class) {
+                return JspUtil.coerceToInteger(s, isNamedAttribute);
+            } else if (c == short.class) {
+                return JspUtil.coerceToPrimitiveShort(s, isNamedAttribute);
+            } else if (c == Short.class) {
+                return JspUtil.coerceToShort(s, isNamedAttribute);
+            } else if (c == long.class) {
+                return JspUtil.coerceToPrimitiveLong(s, isNamedAttribute);
+            } else if (c == Long.class) {
+                return JspUtil.coerceToLong(s, isNamedAttribute);
+            } else if (c == Object.class) {
+                return "new String(" + quoted + ")";
+            } else {
+                String className = JspUtil.getCanonicalName(c);
+                return "("
+                    + className
+                    + ")org.apache.jasper.runtime.JspRuntimeLibrary.getValueFromPropertyEditorManager("
+                    + className
+                    + ".class, \""
+                    + attrName
+                    + "\", "
+                    + quoted
+                    + ")";
+            }
+        }
+
+        /*
+         * Converts the scope string representation, whose possible values
+         * are "page", "request", "session", and "application", to the
+         * corresponding scope constant.
+         */
+        private String getScopeConstant(String scope) {
+            String scopeName = "PageContext.PAGE_SCOPE"; // Default to page
+
+            if ("request".equals(scope)) {
+                scopeName = "PageContext.REQUEST_SCOPE";
+            } else if ("session".equals(scope)) {
+                scopeName = "PageContext.SESSION_SCOPE";
+            } else if ("application".equals(scope)) {
+                scopeName = "PageContext.APPLICATION_SCOPE";
+            }
+
+            return scopeName;
+        }
+
+        /**
+         * Generates anonymous JspFragment inner class which is passed as an
+         * argument to SimpleTag.setJspBody().
+         */
+        private void generateJspFragment(Node n, String tagHandlerVar)
+            throws JasperException {
+            // XXX - A possible optimization here would be to check to see
+            // if the only child of the parent node is TemplateText.  If so,
+            // we know there won't be any parameters, etc, so we can
+            // generate a low-overhead JspFragment that just echoes its
+            // body.  The implementation of this fragment can come from
+            // the org.apache.jasper.runtime package as a support class.
+            FragmentHelperClass.Fragment fragment =
+                fragmentHelperClass.openFragment(
+                    n,
+                    tagHandlerVar,
+                    methodNesting);
+            ServletWriter outSave = out;
+            out = fragment.getGenBuffer().getOut();
+            String tmpParent = parent;
+            parent = "_jspx_parent";
+            boolean isSimpleTagParentSave = isSimpleTagParent;
+            isSimpleTagParent = true;
+            boolean tmpIsFragment = isFragment;
+            isFragment = true;
+            String pushBodyCountVarSave = pushBodyCountVar;
+            if (pushBodyCountVar != null) {
+                // Use a fixed name for push body count, to simplify code gen
+                pushBodyCountVar = "_jspx_push_body_count";
+            }
+            visitBody(n);
+            out = outSave;
+            parent = tmpParent;
+            isSimpleTagParent = isSimpleTagParentSave;
+            isFragment = tmpIsFragment;
+            pushBodyCountVar = pushBodyCountVarSave;
+            fragmentHelperClass.closeFragment(fragment, methodNesting);
+            // XXX - Need to change pageContext to jspContext if
+            // we're not in a place where pageContext is defined (e.g.
+            // in a fragment or in a tag file.
+            out.print(
+                "new "
+                    + fragmentHelperClass.getClassName()
+                    + "( "
+                    + fragment.getId()
+                    + ", _jspx_page_context, "
+                    + tagHandlerVar
+                    + ", "
+                    + pushBodyCountVar
+                    + ")");
+        }
+
+        /**
+         * Generate the code required to obtain the runtime value of the
+         * given named attribute.
+         *
+         * @return The name of the temporary variable the result is stored in.
+         */
+        public String generateNamedAttributeValue(Node.NamedAttribute n)
+            throws JasperException {
+
+            String varName = n.getTemporaryVariableName();
+
+            // If the only body element for this named attribute node is
+            // template text, we need not generate an extra call to
+            // pushBody and popBody.  Maybe we can further optimize
+            // here by getting rid of the temporary variable, but in
+            // reality it looks like javac does this for us.
+            Node.Nodes body = n.getBody();
+            if (body != null) {
+                boolean templateTextOptimization = false;
+                if (body.size() == 1) {
+                    Node bodyElement = body.getNode(0);
+                    if (bodyElement instanceof Node.TemplateText) {
+                        templateTextOptimization = true;
+                        out.printil(
+                            "String "
+                                + varName
+                                + " = "
+                                + quote(
+                                    new String(
+                                        ((Node.TemplateText)bodyElement)
+                                            .getText()))
+                                + ";");
+                    }
+                }
+
+                // XXX - Another possible optimization would be for
+                // lone EL expressions (no need to pushBody here either).
+
+                if (!templateTextOptimization) {
+                    out.printil("out = _jspx_page_context.pushBody();");
+                    visitBody(n);
+                    out.printil(
+                        "String "
+                            + varName
+                            + " = "
+                            + "((javax.servlet.jsp.tagext.BodyContent)"
+                            + "out).getString();");
+                    out.printil("out = _jspx_page_context.popBody();");
+                }
+            } else {
+                // Empty body must be treated as ""
+                out.printil("String " + varName + " = \"\";");
+            }
+
+            return varName;
+        }
+
+        /**
+         * Similar to generateNamedAttributeValue, but create a JspFragment
+         * instead.
+         *
+         * @param n The parent node of the named attribute
+         * @param tagHandlerVar The variable the tag handler is stored in,
+         *     so the fragment knows its parent tag.
+         * @return The name of the temporary variable the fragment
+         *     is stored in.
+         */
+        public String generateNamedAttributeJspFragment(
+            Node.NamedAttribute n,
+            String tagHandlerVar)
+            throws JasperException {
+            String varName = n.getTemporaryVariableName();
+
+            out.printin(
+                "javax.servlet.jsp.tagext.JspFragment " + varName + " = ");
+            generateJspFragment(n, tagHandlerVar);
+            out.println(";");
+
+            return varName;
+        }
+    }
+
+    private static void generateLocalVariables(ServletWriter out, Node n)
+        throws JasperException {
+        Node.ChildInfo ci;
+        if (n instanceof Node.CustomTag) {
+            ci = ((Node.CustomTag)n).getChildInfo();
+        } else if (n instanceof Node.JspBody) {
+            ci = ((Node.JspBody)n).getChildInfo();
+        } else if (n instanceof Node.NamedAttribute) {
+            ci = ((Node.NamedAttribute)n).getChildInfo();
+        } else {
+            // Cannot access err since this method is static, but at
+            // least flag an error.
+            throw new JasperException("Unexpected Node Type");
+            //err.getString(
+            //    "jsp.error.internal.unexpected_node_type" ) );
+        }
+
+        if (ci.hasUseBean()) {
+            out.printil("HttpSession session = _jspx_page_context.getSession();");
+            out.printil(
+                "ServletContext application = _jspx_page_context.getServletContext();");
+        }
+        if (ci.hasUseBean()
+            || ci.hasIncludeAction()
+            || ci.hasSetProperty()
+            || ci.hasParamAction()) {
+            out.printil(
+                "HttpServletRequest request = (HttpServletRequest)_jspx_page_context.getRequest();");
+        }
+        if (ci.hasIncludeAction()) {
+            out.printil(
+                "HttpServletResponse response = (HttpServletResponse)_jspx_page_context.getResponse();");
+        }
+    }
+
+    /**
+     * Common part of postamble, shared by both servlets and tag files.
+     */
+    private void genCommonPostamble() {
+        // Append any methods that were generated in the buffer.
+        for (int i = 0; i < methodsBuffered.size(); i++) {
+            GenBuffer methodBuffer = (GenBuffer)methodsBuffered.get(i);
+            methodBuffer.adjustJavaLines(out.getJavaLine() - 1);
+            out.printMultiLn(methodBuffer.toString());
+        }
+
+        // Append the helper class
+        if (fragmentHelperClass.isUsed()) {
+            fragmentHelperClass.generatePostamble();
+            fragmentHelperClass.adjustJavaLines(out.getJavaLine() - 1);
+            out.printMultiLn(fragmentHelperClass.toString());
+        }
+
+        // Append char array declarations
+        if (charArrayBuffer != null) {
+            out.printMultiLn(charArrayBuffer.toString());
+        }
+
+        // Close the class definition
+        out.popIndent();
+        out.printil("}");
+    }
+
+    /**
+     * Generates the ending part of the static portion of the servlet.
+     */
+    private void generatePostamble(Node.Nodes page) {
+        out.popIndent();
+        out.printil("} catch (Throwable t) {");
+        out.pushIndent();
+        out.printil(
+            "if (!(t instanceof SkipPageException)){");
+        out.pushIndent();
+        out.printil("out = _jspx_out;");
+        out.printil("if (out != null && out.getBufferSize() != 0)");
+        out.pushIndent();
+        out.printil("out.clearBuffer();");
+        out.popIndent();
+
+        out.printil(
+            "if (_jspx_page_context != null) _jspx_page_context.handlePageException(t);");
+        out.popIndent();
+        out.printil("}");
+        out.popIndent();
+        out.printil("} finally {");
+        out.pushIndent();
+
+        out.printil(
+            "if (_jspxFactory != null) _jspxFactory.releasePageContext(_jspx_page_context);");
+
+        out.popIndent();
+        out.printil("}");
+
+        // Close the service method
+        out.popIndent();
+        out.printil("}");
+
+        // Generated methods, helper classes, etc.
+        genCommonPostamble();
+    }
+
+    /**
+     * Constructor.
+     */
+    Generator(ServletWriter out, Compiler compiler) {
+        this.out = out;
+        methodsBuffered = new ArrayList();
+        charArrayBuffer = null;
+        err = compiler.getErrorDispatcher();
+        ctxt = compiler.getCompilationContext();
+        fragmentHelperClass =
+            new FragmentHelperClass(ctxt.getServletClassName() + "Helper");
+        pageInfo = compiler.getPageInfo();
+
+        /*
+         * Temporary hack. If a JSP page uses the "extends" attribute of the
+         * page directive, the _jspInit() method of the generated servlet class
+         * will not be called (it is only called for those generated servlets
+         * that extend HttpJspBase, the default), causing the tag handler pools
+         * not to be initialized and resulting in a NPE.
+         * The JSP spec needs to clarify whether containers can override
+         * init() and destroy(). For now, we just disable tag pooling for pages
+         * that use "extends".
+         */
+        if (pageInfo.getExtends(false) == null) {
+            isPoolingEnabled = ctxt.getOptions().isPoolingEnabled();
+        } else {
+            isPoolingEnabled = false;
+        }
+        beanInfo = pageInfo.getBeanRepository();
+        breakAtLF = ctxt.getOptions().getMappedFile();
+        if (isPoolingEnabled) {
+            tagHandlerPoolNames = new Vector();
+        }
+    }
+
+    /**
+     * The main entry for Generator.
+     * @param out The servlet output writer
+     * @param compiler The compiler
+     * @param page The input page
+     */
+    public static void generate(
+        ServletWriter out,
+        Compiler compiler,
+        Node.Nodes page)
+        throws JasperException {
+
+        Generator gen = new Generator(out, compiler);
+
+        if (gen.isPoolingEnabled) {
+            gen.compileTagHandlerPoolList(page);
+        }
+        if (gen.ctxt.isTagFile()) {
+            JasperTagInfo tagInfo = (JasperTagInfo)gen.ctxt.getTagInfo();
+            gen.generateTagHandlerPreamble(tagInfo, page);
+
+            if (gen.ctxt.isPrototypeMode()) {
+                return;
+            }
+
+            gen.generateXmlProlog(page);
+            gen.fragmentHelperClass.generatePreamble();
+            page.visit(
+                gen.new GenerateVisitor(
+                    gen.ctxt.isTagFile(),
+                    out,
+                    gen.methodsBuffered,
+                    gen.fragmentHelperClass,
+                    gen.ctxt.getClassLoader(),
+                    tagInfo));
+            gen.generateTagHandlerPostamble(tagInfo);
+        } else {
+            gen.generatePreamble(page);
+            gen.generateXmlProlog(page);
+            gen.fragmentHelperClass.generatePreamble();
+            page.visit(
+                gen.new GenerateVisitor(
+                    gen.ctxt.isTagFile(),
+                    out,
+                    gen.methodsBuffered,
+                    gen.fragmentHelperClass,
+                    gen.ctxt.getClassLoader(),
+                    null));
+            gen.generatePostamble(page);
+        }
+    }
+
+    /*
+     * Generates tag handler preamble.
+     */
+    private void generateTagHandlerPreamble(
+        JasperTagInfo tagInfo,
+        Node.Nodes tag)
+        throws JasperException {
+
+        // Generate package declaration
+        String className = tagInfo.getTagClassName();
+        int lastIndex = className.lastIndexOf('.');
+        if (lastIndex != -1) {
+            String pkgName = className.substring(0, lastIndex);
+            genPreamblePackage(pkgName);
+            className = className.substring(lastIndex + 1);
+        }
+
+        // Generate imports
+        genPreambleImports();
+
+        // Generate class declaration
+        out.printin("public final class ");
+        out.println(className);
+        out.printil("    extends javax.servlet.jsp.tagext.SimpleTagSupport");
+        out.printin(
+            "    implements org.apache.jasper.runtime.JspSourceDependent");
+        if (tagInfo.hasDynamicAttributes()) {
+            out.println(",");
+            out.printin(
+                "               javax.servlet.jsp.tagext.DynamicAttributes");
+        }
+        out.println(" {");
+        out.println();
+        out.pushIndent();
+
+        /*
+         * Class body begins here
+         */
+
+        generateDeclarations(tag);
+
+        // Static initializations here
+        genPreambleStaticInitializers();
+
+        out.printil("private JspContext jspContext;");
+
+        // Declare writer used for storing result of fragment/body invocation
+        // if 'varReader' or 'var' attribute is specified
+        out.printil("private java.io.Writer _jspx_sout;");
+
+        // Class variable declarations
+        genPreambleClassVariableDeclarations(tagInfo.getTagName());
+
+        generateSetJspContext(tagInfo);
+
+        // Tag-handler specific declarations
+        generateTagHandlerAttributes(tagInfo);
+        if (tagInfo.hasDynamicAttributes())
+            generateSetDynamicAttribute();
+
+        // Methods here
+        genPreambleMethods();
+
+        // Now the doTag() method
+        out.printil(
+            "public void doTag() throws JspException, java.io.IOException {");
+
+        if (ctxt.isPrototypeMode()) {
+            out.printil("}");
+            out.popIndent();
+            out.printil("}");
+            return;
+        }
+
+        out.pushIndent();
+
+        /*
+         * According to the spec, 'pageContext' must not be made available as
+         * an implicit object in tag files.
+         * Declare _jspx_page_context, so we can share the code generator with
+         * JSPs.
+         */
+        out.printil("PageContext _jspx_page_context = (PageContext)jspContext;");
+
+        // Declare implicit objects.
+        out.printil(
+            "HttpServletRequest request = "
+                + "(HttpServletRequest) _jspx_page_context.getRequest();");
+        out.printil(
+            "HttpServletResponse response = "
+                + "(HttpServletResponse) _jspx_page_context.getResponse();");
+        out.printil("HttpSession session = _jspx_page_context.getSession();");
+        out.printil(
+            "ServletContext application = _jspx_page_context.getServletContext();");
+        out.printil("ServletConfig config = _jspx_page_context.getServletConfig();");
+        out.printil("JspWriter out = jspContext.getOut();");
+        if (isPoolingEnabled && !tagHandlerPoolNames.isEmpty()) {
+            out.printil("_jspInit(config);");
+        }
+        generatePageScopedVariables(tagInfo);
+
+        declareTemporaryScriptingVars(tag);
+        out.println();
+
+        out.printil("try {");
+        out.pushIndent();
+    }
+
+    private void generateTagHandlerPostamble(TagInfo tagInfo) {
+        out.popIndent();
+
+        // Have to catch Throwable because a classic tag handler
+        // helper method is declared to throw Throwable.
+        out.printil("} catch( Throwable t ) {");
+        out.pushIndent();
+        out.printil("if( t instanceof SkipPageException )");
+        out.printil("    throw (SkipPageException) t;");
+        out.printil("if( t instanceof java.io.IOException )");
+        out.printil("    throw (java.io.IOException) t;");
+        out.printil("if( t instanceof IllegalStateException )");
+        out.printil("    throw (IllegalStateException) t;");
+        out.printil("if( t instanceof JspException )");
+        out.printil("    throw (JspException) t;");
+        out.printil("throw new JspException(t);");
+        out.popIndent();
+        out.printil("} finally {");
+        out.pushIndent();
+        out.printil(
+            "((org.apache.jasper.runtime.JspContextWrapper) jspContext).syncEndTagFile();");
+        if (isPoolingEnabled && !tagHandlerPoolNames.isEmpty()) {
+            out.printil("_jspDestroy();");
+        }
+        out.popIndent();
+        out.printil("}");
+
+        // Close the doTag method
+        out.popIndent();
+        out.printil("}");
+
+        // Generated methods, helper classes, etc.
+        genCommonPostamble();
+    }
+
+    /**
+     * Generates declarations for tag handler attributes, and defines the
+     * getter and setter methods for each.
+     */
+    private void generateTagHandlerAttributes(TagInfo tagInfo)
+        throws JasperException {
+
+        if (tagInfo.hasDynamicAttributes()) {
+            out.printil(
+                "private java.util.HashMap _jspx_dynamic_attrs = new java.util.HashMap();");
+        }
+
+        // Declare attributes
+        TagAttributeInfo[] attrInfos = tagInfo.getAttributes();
+        for (int i = 0; i < attrInfos.length; i++) {
+            out.printin("private ");
+            if (attrInfos[i].isFragment()) {
+                out.print("javax.servlet.jsp.tagext.JspFragment ");
+            } else {
+                out.print(JspUtil.toJavaSourceType(attrInfos[i].getTypeName()));
+                out.print(" ");
+            }
+            out.print(attrInfos[i].getName());
+            out.println(";");
+        }
+        out.println();
+
+        // Define attribute getter and setter methods
+        if (attrInfos != null) {
+            for (int i = 0; i < attrInfos.length; i++) {
+                // getter method
+                out.printin("public ");
+                if (attrInfos[i].isFragment()) {
+                    out.print("javax.servlet.jsp.tagext.JspFragment ");
+                } else {
+                    out.print(JspUtil.toJavaSourceType(attrInfos[i].getTypeName()));
+                    out.print(" ");
+                }
+                out.print(toGetterMethod(attrInfos[i].getName()));
+                out.println(" {");
+                out.pushIndent();
+                out.printin("return this.");
+                out.print(attrInfos[i].getName());
+                out.println(";");
+                out.popIndent();
+                out.printil("}");
+                out.println();
+
+                // setter method
+                out.printin("public void ");
+                out.print(toSetterMethodName(attrInfos[i].getName()));
+                if (attrInfos[i].isFragment()) {
+                    out.print("(javax.servlet.jsp.tagext.JspFragment ");
+                } else {
+                    out.print("(");
+                    out.print(JspUtil.toJavaSourceType(attrInfos[i].getTypeName()));
+                    out.print(" ");
+                }
+                out.print(attrInfos[i].getName());
+                out.println(") {");
+                out.pushIndent();
+                out.printin("this.");
+                out.print(attrInfos[i].getName());
+                out.print(" = ");
+                out.print(attrInfos[i].getName());
+                out.println(";");
+                out.popIndent();
+                out.printil("}");
+                out.println();
+            }
+        }
+    }
+
+    /*
+     * Generate setter for JspContext so we can create a wrapper and
+     * store both the original and the wrapper.  We need the wrapper
+     * to mask the page context from the tag file and simulate a
+     * fresh page context.  We need the original to do things like
+     * sync AT_BEGIN and AT_END scripting variables.
+     */
+    private void generateSetJspContext(TagInfo tagInfo) {
+
+        boolean nestedSeen = false;
+        boolean atBeginSeen = false;
+        boolean atEndSeen = false;
+
+        // Determine if there are any aliases
+        boolean aliasSeen = false;
+        TagVariableInfo[] tagVars = tagInfo.getTagVariableInfos();
+        for (int i = 0; i < tagVars.length; i++) {
+            if (tagVars[i].getNameFromAttribute() != null
+                && tagVars[i].getNameGiven() != null) {
+                aliasSeen = true;
+                break;
+            }
+        }
+
+        if (aliasSeen) {
+            out.printil(
+                "public void setJspContext(JspContext ctx, java.util.Map aliasMap) {");
+        } else {
+            out.printil("public void setJspContext(JspContext ctx) {");
+        }
+        out.pushIndent();
+        out.printil("super.setJspContext(ctx);");
+        out.printil("java.util.ArrayList _jspx_nested = null;");
+        out.printil("java.util.ArrayList _jspx_at_begin = null;");
+        out.printil("java.util.ArrayList _jspx_at_end = null;");
+
+        for (int i = 0; i < tagVars.length; i++) {
+
+            switch (tagVars[i].getScope()) {
+                case VariableInfo.NESTED :
+                    if (!nestedSeen) {
+                        out.printil(
+                            "_jspx_nested = new java.util.ArrayList();");
+                        nestedSeen = true;
+                    }
+                    out.printin("_jspx_nested.add(");
+                    break;
+
+                case VariableInfo.AT_BEGIN :
+                    if (!atBeginSeen) {
+                        out.printil(
+                            "_jspx_at_begin = new java.util.ArrayList();");
+                        atBeginSeen = true;
+                    }
+                    out.printin("_jspx_at_begin.add(");
+                    break;
+
+                case VariableInfo.AT_END :
+                    if (!atEndSeen) {
+                        out.printil(
+                            "_jspx_at_end = new java.util.ArrayList();");
+                        atEndSeen = true;
+                    }
+                    out.printin("_jspx_at_end.add(");
+                    break;
+            } // switch
+
+            out.print(quote(tagVars[i].getNameGiven()));
+            out.println(");");
+        }
+        if (aliasSeen) {
+            out.printil(
+                "this.jspContext = new org.apache.jasper.runtime.JspContextWrapper(ctx, _jspx_nested, _jspx_at_begin, _jspx_at_end, aliasMap);");
+        } else {
+            out.printil(
+                "this.jspContext = new org.apache.jasper.runtime.JspContextWrapper(ctx, _jspx_nested, _jspx_at_begin, _jspx_at_end, null);");
+        }
+        out.popIndent();
+        out.printil("}");
+        out.println();
+        out.printil("public JspContext getJspContext() {");
+        out.pushIndent();
+        out.printil("return this.jspContext;");
+        out.popIndent();
+        out.printil("}");
+    }
+
+    /*
+     * Generates implementation of
+     * javax.servlet.jsp.tagext.DynamicAttributes.setDynamicAttribute() method,
+     * which saves each dynamic attribute that is passed in so that a scoped
+     * variable can later be created for it.
+     */
+    public void generateSetDynamicAttribute() {
+        out.printil(
+            "public void setDynamicAttribute(String uri, String localName, Object value) throws JspException {");
+        out.pushIndent();
+        /*
+         * According to the spec, only dynamic attributes with no uri are to
+         * be present in the Map; all other dynamic attributes are ignored.
+         */
+        out.printil("if (uri == null)");
+        out.pushIndent();
+        out.printil("_jspx_dynamic_attrs.put(localName, value);");
+        out.popIndent();
+        out.popIndent();
+        out.printil("}");
+    }
+
+    /*
+     * Creates a page-scoped variable for each declared tag attribute.
+     * Also, if the tag accepts dynamic attributes, a page-scoped variable
+     * is made available for each dynamic attribute that was passed in.
+     */
+    private void generatePageScopedVariables(JasperTagInfo tagInfo) {
+
+        // "normal" attributes
+        TagAttributeInfo[] attrInfos = tagInfo.getAttributes();
+        for (int i = 0; i < attrInfos.length; i++) {
+            String attrName = attrInfos[i].getName();
+            out.printil("if( " + toGetterMethod(attrName) + " != null ) ");
+            out.pushIndent();
+            out.printin("_jspx_page_context.setAttribute(");
+            out.print(quote(attrName));
+            out.print(", ");
+            out.print(toGetterMethod(attrName));
+            out.println(");");
+            out.popIndent();
+        }
+
+        // Expose the Map containing dynamic attributes as a page-scoped var
+        if (tagInfo.hasDynamicAttributes()) {
+            out.printin("_jspx_page_context.setAttribute(\"");
+            out.print(tagInfo.getDynamicAttributesMapName());
+            out.print("\", _jspx_dynamic_attrs);");
+        }
+    }
+
+    /*
+     * Generates the getter method for the given attribute name.
+     */
+    private String toGetterMethod(String attrName) {
+        char[] attrChars = attrName.toCharArray();
+        attrChars[0] = Character.toUpperCase(attrChars[0]);
+        return "get" + new String(attrChars) + "()";
+    }
+
+    /*
+     * Generates the setter method name for the given attribute name.
+     */
+    private String toSetterMethodName(String attrName) {
+        char[] attrChars = attrName.toCharArray();
+        attrChars[0] = Character.toUpperCase(attrChars[0]);
+        return "set" + new String(attrChars);
+    }
+
+    /**
+     * Class storing the result of introspecting a custom tag handler.
+     */
+    private static class TagHandlerInfo {
+
+        private Hashtable methodMaps;
+        private Hashtable propertyEditorMaps;
+        private Class tagHandlerClass;
+
+        /**
+         * Constructor.
+         *
+         * @param n The custom tag whose tag handler class is to be
+         * introspected
+         * @param tagHandlerClass Tag handler class
+         * @param err Error dispatcher
+         */
+        TagHandlerInfo(Node n, Class tagHandlerClass, ErrorDispatcher err)
+            throws JasperException {
+            this.tagHandlerClass = tagHandlerClass;
+            this.methodMaps = new Hashtable();
+            this.propertyEditorMaps = new Hashtable();
+
+            try {
+                BeanInfo tagClassInfo =
+                    Introspector.getBeanInfo(tagHandlerClass);
+                PropertyDescriptor[] pd = tagClassInfo.getPropertyDescriptors();
+                for (int i = 0; i < pd.length; i++) {
+                    /*
+                     * FIXME: should probably be checking for things like
+                     *        pageContext, bodyContent, and parent here -akv
+                     */
+                    if (pd[i].getWriteMethod() != null) {
+                        methodMaps.put(pd[i].getName(), pd[i].getWriteMethod());
+                    }
+                    if (pd[i].getPropertyEditorClass() != null)
+                        propertyEditorMaps.put(
+                            pd[i].getName(),
+                            pd[i].getPropertyEditorClass());
+                }
+            } catch (IntrospectionException ie) {
+                err.jspError(
+                    n,
+                    "jsp.error.introspect.taghandler",
+                    tagHandlerClass.getName(),
+                    ie);
+            }
+        }
+
+        /**
+         * XXX
+         */
+        public Method getSetterMethod(String attrName) {
+            return (Method)methodMaps.get(attrName);
+        }
+
+        /**
+         * XXX
+         */
+        public Class getPropertyEditorClass(String attrName) {
+            return (Class)propertyEditorMaps.get(attrName);
+        }
+
+        /**
+         * XXX
+         */
+        public Class getTagHandlerClass() {
+            return tagHandlerClass;
+        }
+    }
+
+    /**
+     * A class for generating codes to a buffer.  Included here are some
+     * support for tracking source to Java lines mapping.
+     */
+    private static class GenBuffer {
+
+        /*
+         * For a CustomTag, the codes that are generated at the beginning of
+         * the tag may not be in the same buffer as those for the body of the
+         * tag.  Two fields are used here to keep this straight.  For codes
+         * that do not corresponds to any JSP lines, they should be null.
+         */
+        private Node node;
+        private Node.Nodes body;
+        private java.io.CharArrayWriter charWriter;
+        protected ServletWriter out;
+
+        GenBuffer() {
+            this(null, null);
+        }
+
+        GenBuffer(Node n, Node.Nodes b) {
+            node = n;
+            body = b;
+            if (body != null) {
+                body.setGeneratedInBuffer(true);
+            }
+            charWriter = new java.io.CharArrayWriter();
+            out = new ServletWriter(new java.io.PrintWriter(charWriter));
+        }
+
+        public ServletWriter getOut() {
+            return out;
+        }
+
+        public String toString() {
+            return charWriter.toString();
+        }
+
+        /**
+         * Adjust the Java Lines.  This is necessary because the Java lines
+         * stored with the nodes are relative the beginning of this buffer
+         * and need to be adjusted when this buffer is inserted into the
+         * source.
+         */
+        public void adjustJavaLines(final int offset) {
+
+            if (node != null) {
+                adjustJavaLine(node, offset);
+            }
+
+            if (body != null) {
+                try {
+                    body.visit(new Node.Visitor() {
+
+                        public void doVisit(Node n) {
+                            adjustJavaLine(n, offset);
+                        }
+
+                        public void visit(Node.CustomTag n)
+                            throws JasperException {
+                            Node.Nodes b = n.getBody();
+                            if (b != null && !b.isGeneratedInBuffer()) {
+                                // Don't adjust lines for the nested tags that
+                                // are also generated in buffers, because the
+                                // adjustments will be done elsewhere.
+                                b.visit(this);
+                            }
+                        }
+                    });
+                } catch (JasperException ex) {
+                }
+            }
+        }
+
+        private static void adjustJavaLine(Node n, int offset) {
+            if (n.getBeginJavaLine() > 0) {
+                n.setBeginJavaLine(n.getBeginJavaLine() + offset);
+                n.setEndJavaLine(n.getEndJavaLine() + offset);
+            }
+        }
+    }
+
+    /**
+     * Keeps track of the generated Fragment Helper Class
+     */
+    private static class FragmentHelperClass {
+
+        private static class Fragment {
+            private GenBuffer genBuffer;
+            private int id;
+
+            public Fragment(int id, Node node) {
+                this.id = id;
+                genBuffer = new GenBuffer(null, node.getBody());
+            }
+
+            public GenBuffer getGenBuffer() {
+                return this.genBuffer;
+            }
+
+            public int getId() {
+                return this.id;
+            }
+        }
+
+        // True if the helper class should be generated.
+        private boolean used = false;
+
+        private ArrayList fragments = new ArrayList();
+
+        private String className;
+
+        // Buffer for entire helper class
+        private GenBuffer classBuffer = new GenBuffer();
+
+        public FragmentHelperClass(String className) {
+            this.className = className;
+        }
+
+        public String getClassName() {
+            return this.className;
+        }
+
+        public boolean isUsed() {
+            return this.used;
+        }
+
+        public void generatePreamble() {
+            ServletWriter out = this.classBuffer.getOut();
+            out.println();
+            out.pushIndent();
+            // Note: cannot be static, as we need to reference things like
+            // _jspx_meth_*
+            out.printil("private class " + className);
+            out.printil(
+                "    extends " + "org.apache.jasper.runtime.JspFragmentHelper");
+            out.printil("{");
+            out.pushIndent();
+            out.printil(
+                "private javax.servlet.jsp.tagext.JspTag _jspx_parent;");
+            out.printil("private int[] _jspx_push_body_count;");
+            out.println();
+            out.printil(
+                "public "
+                    + className
+                    + "( int discriminator, JspContext jspContext, "
+                    + "javax.servlet.jsp.tagext.JspTag _jspx_parent, "
+                    + "int[] _jspx_push_body_count ) {");
+            out.pushIndent();
+            out.printil("super( discriminator, jspContext, _jspx_parent );");
+            out.printil("this._jspx_parent = _jspx_parent;");
+            out.printil("this._jspx_push_body_count = _jspx_push_body_count;");
+            out.popIndent();
+            out.printil("}");
+        }
+
+        public Fragment openFragment(
+            Node parent,
+            String tagHandlerVar,
+            int methodNesting)
+            throws JasperException {
+            Fragment result = new Fragment(fragments.size(), parent);
+            fragments.add(result);
+            this.used = true;
+            parent.setInnerClassName(className);
+
+            ServletWriter out = result.getGenBuffer().getOut();
+            out.pushIndent();
+            out.pushIndent();
+            // XXX - Returns boolean because if a tag is invoked from
+            // within this fragment, the Generator sometimes might
+            // generate code like "return true".  This is ignored for now,
+            // meaning only the fragment is skipped.  The JSR-152
+            // expert group is currently discussing what to do in this case.
+            // See comment in closeFragment()
+            if (methodNesting > 0) {
+                out.printin("public boolean invoke");
+            } else {
+                out.printin("public void invoke");
+            }
+            out.println(result.getId() + "( " + "JspWriter out ) ");
+            out.pushIndent();
+            // Note: Throwable required because methods like _jspx_meth_*
+            // throw Throwable.
+            out.printil("throws Throwable");
+            out.popIndent();
+            out.printil("{");
+            out.pushIndent();
+            generateLocalVariables(out, parent);
+
+            return result;
+        }
+
+        public void closeFragment(Fragment fragment, int methodNesting) {
+            ServletWriter out = fragment.getGenBuffer().getOut();
+            // XXX - See comment in openFragment()
+            if (methodNesting > 0) {
+                out.printil("return false;");
+            } else {
+                out.printil("return;");
+            }
+            out.popIndent();
+            out.printil("}");
+        }
+
+        public void generatePostamble() {
+            ServletWriter out = this.classBuffer.getOut();
+            // Generate all fragment methods:
+            for (int i = 0; i < fragments.size(); i++) {
+                Fragment fragment = (Fragment)fragments.get(i);
+                fragment.getGenBuffer().adjustJavaLines(out.getJavaLine() - 1);
+                out.printMultiLn(fragment.getGenBuffer().toString());
+            }
+
+            // Generate postamble:
+            out.printil("public void invoke( java.io.Writer writer )");
+            out.pushIndent();
+            out.printil("throws JspException");
+            out.popIndent();
+            out.printil("{");
+            out.pushIndent();
+            out.printil("JspWriter out = null;");
+            out.printil("if( writer != null ) {");
+            out.pushIndent();
+            out.printil("out = this.jspContext.pushBody(writer);");
+            out.popIndent();
+            out.printil("} else {");
+            out.pushIndent();
+            out.printil("out = this.jspContext.getOut();");
+            out.popIndent();
+            out.printil("}");
+            out.printil("try {");
+            out.pushIndent();
+            out.printil("switch( this.discriminator ) {");
+            out.pushIndent();
+            for (int i = 0; i < fragments.size(); i++) {
+                out.printil("case " + i + ":");
+                out.pushIndent();
+                out.printil("invoke" + i + "( out );");
+                out.printil("break;");
+                out.popIndent();
+            }
+            out.popIndent();
+            out.printil("}"); // switch
+            out.popIndent();
+            out.printil("}"); // try
+            out.printil("catch( Throwable e ) {");
+            out.pushIndent();
+            out.printil(
+                "if (e instanceof SkipPageException)");
+            out.printil("    throw (SkipPageException) e;");
+            out.printil("throw new JspException( e );");
+            out.popIndent();
+            out.printil("}"); // catch
+            out.printil("finally {");
+            out.pushIndent();
+
+            out.printil("if( writer != null ) {");
+            out.pushIndent();
+            out.printil("this.jspContext.popBody();");
+            out.popIndent();
+            out.printil("}");
+
+            out.popIndent();
+            out.printil("}"); // finally
+            out.popIndent();
+            out.printil("}"); // invoke method
+            out.popIndent();
+            out.printil("}"); // helper class
+            out.popIndent();
+        }
+
+        public String toString() {
+            return classBuffer.toString();
+        }
+
+        public void adjustJavaLines(int offset) {
+            for (int i = 0; i < fragments.size(); i++) {
+                Fragment fragment = (Fragment)fragments.get(i);
+                fragment.getGenBuffer().adjustJavaLines(offset);
+            }
+        }
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/ImplicitTagLibraryInfo.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/ImplicitTagLibraryInfo.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/ImplicitTagLibraryInfo.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,141 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.util.*;
+import javax.servlet.jsp.tagext.FunctionInfo;
+import javax.servlet.jsp.tagext.TagLibraryInfo;
+import javax.servlet.jsp.tagext.TagInfo;
+import javax.servlet.jsp.tagext.TagFileInfo;
+import org.apache.jasper.JspCompilationContext;
+import org.apache.jasper.JasperException;
+
+/**
+ * Class responsible for generating an implicit tag library containing tag
+ * handlers corresponding to the tag files in "/WEB-INF/tags/" or a 
+ * subdirectory of it.
+ *
+ * @author Jan Luehe
+ */
+class ImplicitTagLibraryInfo extends TagLibraryInfo {
+
+    private static final String WEB_INF_TAGS = "/WEB-INF/tags";
+    private static final String TAG_FILE_SUFFIX = ".tag";
+    private static final String TAGX_FILE_SUFFIX = ".tagx";
+    private static final String TAGS_SHORTNAME = "tags";
+    private static final String TLIB_VERSION = "1.0";
+    private static final String JSP_VERSION = "2.0";
+
+    // Maps tag names to tag file paths
+    private Hashtable tagFileMap;
+
+    private ParserController pc;
+    private Vector vec;
+
+    /**
+     * Constructor.
+     */
+    public ImplicitTagLibraryInfo(JspCompilationContext ctxt,
+				  ParserController pc,
+				  String prefix,
+				  String tagdir,
+				  ErrorDispatcher err) throws JasperException {
+        super(prefix, null);
+	this.pc = pc;
+	this.tagFileMap = new Hashtable();
+	this.vec = new Vector();
+
+        // Implicit tag libraries have no functions:
+        this.functions = new FunctionInfo[0];
+
+	tlibversion = TLIB_VERSION;
+	jspversion = JSP_VERSION;
+
+	if (!tagdir.startsWith(WEB_INF_TAGS)) {
+	    err.jspError("jsp.error.invalid.tagdir", tagdir);
+	}
+	
+	// Determine the value of the <short-name> subelement of the
+	// "imaginary" <taglib> element
+	if (tagdir.equals(WEB_INF_TAGS)
+	        || tagdir.equals( WEB_INF_TAGS + "/")) {
+	    shortname = TAGS_SHORTNAME;
+	} else {
+	    shortname = tagdir.substring(WEB_INF_TAGS.length());
+	    shortname = shortname.replace('/', '-');
+	}
+
+	// Populate mapping of tag names to tag file paths
+	Set dirList = ctxt.getResourcePaths(tagdir);
+	if (dirList != null) {
+	    Iterator it = dirList.iterator();
+	    while (it.hasNext()) {
+		String path = (String) it.next();
+		if (path.endsWith(TAG_FILE_SUFFIX)
+		        || path.endsWith(TAGX_FILE_SUFFIX)) {
+		    /*
+		     * Use the filename of the tag file, without the .tag or
+		     * .tagx extension, respectively, as the <name> subelement
+		     * of the "imaginary" <tag-file> element
+		     */
+		    String suffix = path.endsWith(TAG_FILE_SUFFIX) ?
+			TAG_FILE_SUFFIX : TAGX_FILE_SUFFIX; 
+		    String tagName = path.substring(path.lastIndexOf("/") + 1);
+		    tagName = tagName.substring(0,
+						tagName.lastIndexOf(suffix));
+		    tagFileMap.put(tagName, path);
+		}
+	    }
+	}
+    }
+
+    /**
+     * Checks to see if the given tag name maps to a tag file path,
+     * and if so, parses the corresponding tag file.
+     *
+     * @return The TagFileInfo corresponding to the given tag name, or null if
+     * the given tag name is not implemented as a tag file
+     */
+    public TagFileInfo getTagFile(String shortName) {
+
+	TagFileInfo tagFile = super.getTagFile(shortName);
+	if (tagFile == null) {
+	    String path = (String) tagFileMap.get(shortName);
+	    if (path == null) {
+		return null;
+	    }
+
+	    TagInfo tagInfo = null;
+	    try {
+		tagInfo = TagFileProcessor.parseTagFileDirectives(pc,
+								  shortName,
+								  path,
+								  this);
+	    } catch (JasperException je) {
+		throw new RuntimeException(je.toString());
+	    }
+
+	    tagFile = new TagFileInfo(shortName, path, tagInfo);
+	    vec.addElement(tagFile);
+
+	    this.tagFiles = new TagFileInfo[vec.size()];
+	    vec.copyInto(this.tagFiles);
+	}
+
+	return tagFile;
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/JDTCompiler.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/JDTCompiler.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/JDTCompiler.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,435 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.BufferedOutputStream;
+import java.io.BufferedReader;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+import java.util.StringTokenizer;
+
+import org.apache.jasper.JasperException;
+import org.eclipse.jdt.core.compiler.IProblem;
+import org.eclipse.jdt.internal.compiler.ClassFile;
+import org.eclipse.jdt.internal.compiler.CompilationResult;
+import org.eclipse.jdt.internal.compiler.Compiler;
+import org.eclipse.jdt.internal.compiler.DefaultErrorHandlingPolicies;
+import org.eclipse.jdt.internal.compiler.ICompilerRequestor;
+import org.eclipse.jdt.internal.compiler.IErrorHandlingPolicy;
+import org.eclipse.jdt.internal.compiler.IProblemFactory;
+import org.eclipse.jdt.internal.compiler.classfmt.ClassFileReader;
+import org.eclipse.jdt.internal.compiler.env.ICompilationUnit;
+import org.eclipse.jdt.internal.compiler.env.INameEnvironment;
+import org.eclipse.jdt.internal.compiler.env.NameEnvironmentAnswer;
+import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
+import org.eclipse.jdt.internal.compiler.problem.DefaultProblemFactory;
+
+/**
+ * JDT class compiler. This compiler will load source dependencies from the
+ * context classloader, reducing dramatically disk access during 
+ * the compilation process.
+ *
+ * @author Cocoon2
+ * @author Remy Maucherat
+ */
+public class JDTCompiler extends org.apache.jasper.compiler.Compiler {
+
+    
+    /** 
+     * Compile the servlet from .java file to .class file
+     */
+    protected void generateClass(String[] smap)
+        throws FileNotFoundException, JasperException, Exception {
+
+        long t1 = 0;
+        if (log.isDebugEnabled()) {
+            t1 = System.currentTimeMillis();
+        }
+        
+        final String sourceFile = ctxt.getServletJavaFileName();
+        final String outputDir = ctxt.getOptions().getScratchDir().getAbsolutePath();
+        String packageName = ctxt.getServletPackageName();
+        final String targetClassName = 
+            ((packageName.length() != 0) ? (packageName + ".") : "") 
+                    + ctxt.getServletClassName();
+        final ClassLoader classLoader = ctxt.getJspLoader();
+        String[] fileNames = new String[] {sourceFile};
+        String[] classNames = new String[] {targetClassName};
+        final ArrayList problemList = new ArrayList();
+        
+        class CompilationUnit implements ICompilationUnit {
+
+            String className;
+            String sourceFile;
+
+            CompilationUnit(String sourceFile, String className) {
+                this.className = className;
+                this.sourceFile = sourceFile;
+            }
+
+            public char[] getFileName() {
+                return sourceFile.toCharArray();
+            }
+            
+            public char[] getContents() {
+                char[] result = null;
+                try {
+                    InputStreamReader isReader =
+                        new InputStreamReader(new FileInputStream(sourceFile),
+                                ctxt.getOptions().getJavaEncoding());
+                    Reader reader = new BufferedReader(isReader);
+                    if (reader != null) {
+                        char[] chars = new char[8192];
+                        StringBuffer buf = new StringBuffer();
+                        int count;
+                        while ((count = reader.read(chars, 0, 
+                                                    chars.length)) > 0) {
+                            buf.append(chars, 0, count);
+                        }
+                        result = new char[buf.length()];
+                        buf.getChars(0, result.length, result, 0);
+                    }
+                } catch (IOException e) {
+                    log.error("Compilation error", e);
+                }
+                return result;
+            }
+            
+            public char[] getMainTypeName() {
+                int dot = className.lastIndexOf('.');
+                if (dot > 0) {
+                    return className.substring(dot + 1).toCharArray();
+                }
+                return className.toCharArray();
+            }
+            
+            public char[][] getPackageName() {
+                StringTokenizer izer = 
+                    new StringTokenizer(className, ".");
+                char[][] result = new char[izer.countTokens()-1][];
+                for (int i = 0; i < result.length; i++) {
+                    String tok = izer.nextToken();
+                    result[i] = tok.toCharArray();
+                }
+                return result;
+            }
+        }
+
+        final INameEnvironment env = new INameEnvironment() {
+
+                public NameEnvironmentAnswer 
+                    findType(char[][] compoundTypeName) {
+                    String result = "";
+                    String sep = "";
+                    for (int i = 0; i < compoundTypeName.length; i++) {
+                        result += sep;
+                        result += new String(compoundTypeName[i]);
+                        sep = ".";
+                    }
+                    return findType(result);
+                }
+
+                public NameEnvironmentAnswer 
+                    findType(char[] typeName, 
+                             char[][] packageName) {
+                        String result = "";
+                        String sep = "";
+                        for (int i = 0; i < packageName.length; i++) {
+                            result += sep;
+                            result += new String(packageName[i]);
+                            sep = ".";
+                        }
+                        result += sep;
+                        result += new String(typeName);
+                        return findType(result);
+                }
+                
+                private NameEnvironmentAnswer findType(String className) {
+
+                    InputStream is = null;
+                    try {
+                        if (className.equals(targetClassName)) {
+                            ICompilationUnit compilationUnit = 
+                                new CompilationUnit(sourceFile, className);
+                            return 
+                                new NameEnvironmentAnswer(compilationUnit, null);
+                        }
+                        String resourceName = 
+                            className.replace('.', '/') + ".class";
+                        is = classLoader.getResourceAsStream(resourceName);
+                        if (is != null) {
+                            byte[] classBytes;
+                            byte[] buf = new byte[8192];
+                            ByteArrayOutputStream baos = 
+                                new ByteArrayOutputStream(buf.length);
+                            int count;
+                            while ((count = is.read(buf, 0, buf.length)) > 0) {
+                                baos.write(buf, 0, count);
+                            }
+                            baos.flush();
+                            classBytes = baos.toByteArray();
+                            char[] fileName = className.toCharArray();
+                            ClassFileReader classFileReader = 
+                                new ClassFileReader(classBytes, fileName, 
+                                                    true);
+                            return 
+                                new NameEnvironmentAnswer(classFileReader, null);
+                        }
+                    } catch (IOException exc) {
+                        log.error("Compilation error", exc);
+                    } catch (org.eclipse.jdt.internal.compiler.classfmt.ClassFormatException exc) {
+                        log.error("Compilation error", exc);
+                    } finally {
+                        if (is != null) {
+                            try {
+                                is.close();
+                            } catch (IOException exc) {
+                                // Ignore
+                            }
+                        }
+                    }
+                    return null;
+                }
+
+                private boolean isPackage(String result) {
+                    if (result.equals(targetClassName)) {
+                        return false;
+                    }
+                    String resourceName = result.replace('.', '/') + ".class";
+                    InputStream is = 
+                        classLoader.getResourceAsStream(resourceName);
+                    return is == null;
+                }
+
+                public boolean isPackage(char[][] parentPackageName, 
+                                         char[] packageName) {
+                    String result = "";
+                    String sep = "";
+                    if (parentPackageName != null) {
+                        for (int i = 0; i < parentPackageName.length; i++) {
+                            result += sep;
+                            String str = new String(parentPackageName[i]);
+                            result += str;
+                            sep = ".";
+                        }
+                    }
+                    String str = new String(packageName);
+                    if (Character.isUpperCase(str.charAt(0))) {
+                        if (!isPackage(result)) {
+                            return false;
+                        }
+                    }
+                    result += sep;
+                    result += str;
+                    return isPackage(result);
+                }
+
+                public void cleanup() {
+                }
+
+            };
+
+        final IErrorHandlingPolicy policy = 
+            DefaultErrorHandlingPolicies.proceedWithAllProblems();
+
+        final Map settings = new HashMap();
+        settings.put(CompilerOptions.OPTION_LineNumberAttribute,
+                     CompilerOptions.GENERATE);
+        settings.put(CompilerOptions.OPTION_SourceFileAttribute,
+                     CompilerOptions.GENERATE);
+        settings.put(CompilerOptions.OPTION_ReportDeprecation,
+                     CompilerOptions.IGNORE);
+        if (ctxt.getOptions().getJavaEncoding() != null) {
+            settings.put(CompilerOptions.OPTION_Encoding,
+                    ctxt.getOptions().getJavaEncoding());
+        }
+        if (ctxt.getOptions().getClassDebugInfo()) {
+            settings.put(CompilerOptions.OPTION_LocalVariableAttribute,
+                         CompilerOptions.GENERATE);
+        }
+
+        // Source JVM
+        if(ctxt.getOptions().getCompilerSourceVM() != null) {
+            String opt = ctxt.getOptions().getCompilerSourceVM();
+            if(opt.equals("1.1")) {
+                settings.put(CompilerOptions.OPTION_Source,
+                             CompilerOptions.VERSION_1_1);
+            } else if(opt.equals("1.2")) {
+                settings.put(CompilerOptions.OPTION_Source,
+                             CompilerOptions.VERSION_1_2);
+            } else if(opt.equals("1.3")) { 
+                settings.put(CompilerOptions.OPTION_Source,
+                             CompilerOptions.VERSION_1_3);
+            } else if(opt.equals("1.4")) {
+                settings.put(CompilerOptions.OPTION_Source,
+                             CompilerOptions.VERSION_1_4);
+            } else if(opt.equals("1.5")) {
+                settings.put(CompilerOptions.OPTION_Source,
+                             CompilerOptions.VERSION_1_5);
+            } else {
+                log.warn("Unknown source VM " + opt + " ignored.");
+                settings.put(CompilerOptions.OPTION_Source,
+                        CompilerOptions.VERSION_1_5);
+            }
+        } else {
+            // Default to 1.5
+            settings.put(CompilerOptions.OPTION_Source,
+                    CompilerOptions.VERSION_1_5);
+        }
+        
+        // Target JVM
+        if(ctxt.getOptions().getCompilerTargetVM() != null) {
+            String opt = ctxt.getOptions().getCompilerTargetVM();
+            if(opt.equals("1.1")) {
+                settings.put(CompilerOptions.OPTION_TargetPlatform,
+                             CompilerOptions.VERSION_1_1);
+            } else if(opt.equals("1.2")) {
+                settings.put(CompilerOptions.OPTION_TargetPlatform,
+                             CompilerOptions.VERSION_1_2);
+            } else if(opt.equals("1.3")) { 
+                settings.put(CompilerOptions.OPTION_TargetPlatform,
+                             CompilerOptions.VERSION_1_3);
+            } else if(opt.equals("1.4")) {
+                settings.put(CompilerOptions.OPTION_TargetPlatform,
+                             CompilerOptions.VERSION_1_4);
+            } else if(opt.equals("1.5")) {
+                settings.put(CompilerOptions.OPTION_TargetPlatform,
+                             CompilerOptions.VERSION_1_5);
+                settings.put(CompilerOptions.OPTION_Compliance,
+                        CompilerOptions.VERSION_1_5);
+            } else {
+                log.warn("Unknown target VM " + opt + " ignored.");
+                settings.put(CompilerOptions.OPTION_TargetPlatform,
+                        CompilerOptions.VERSION_1_5);
+            }
+        } else {
+            // Default to 1.5
+            settings.put(CompilerOptions.OPTION_TargetPlatform,
+                    CompilerOptions.VERSION_1_5);
+            settings.put(CompilerOptions.OPTION_Compliance,
+                    CompilerOptions.VERSION_1_5);
+        }
+
+        final IProblemFactory problemFactory = 
+            new DefaultProblemFactory(Locale.getDefault());
+        
+        final ICompilerRequestor requestor = new ICompilerRequestor() {
+                public void acceptResult(CompilationResult result) {
+                    try {
+                        if (result.hasProblems()) {
+                            IProblem[] problems = result.getProblems();
+                            for (int i = 0; i < problems.length; i++) {
+                                IProblem problem = problems[i];
+                                if (problem.isError()) {
+                                    String name = 
+                                        new String(problems[i].getOriginatingFileName());
+                                    try {
+                                        problemList.add(ErrorDispatcher.createJavacError
+                                                (name, pageNodes, new StringBuffer(problem.getMessage()), 
+                                                        problem.getSourceLineNumber()));
+                                    } catch (JasperException e) {
+                                        log.error("Error visiting node", e);
+                                    }
+                                }
+                            }
+                        }
+                        if (problemList.isEmpty()) {
+                            ClassFile[] classFiles = result.getClassFiles();
+                            for (int i = 0; i < classFiles.length; i++) {
+                                ClassFile classFile = classFiles[i];
+                                char[][] compoundName = 
+                                    classFile.getCompoundName();
+                                String className = "";
+                                String sep = "";
+                                for (int j = 0; 
+                                     j < compoundName.length; j++) {
+                                    className += sep;
+                                    className += new String(compoundName[j]);
+                                    sep = ".";
+                                }
+                                byte[] bytes = classFile.getBytes();
+                                String outFile = outputDir + "/" + 
+                                    className.replace('.', '/') + ".class";
+                                FileOutputStream fout = 
+                                    new FileOutputStream(outFile);
+                                BufferedOutputStream bos = 
+                                    new BufferedOutputStream(fout);
+                                bos.write(bytes);
+                                bos.close();
+                            }
+                        }
+                    } catch (IOException exc) {
+                        log.error("Compilation error", exc);
+                    }
+                }
+            };
+
+        ICompilationUnit[] compilationUnits = 
+            new ICompilationUnit[classNames.length];
+        for (int i = 0; i < compilationUnits.length; i++) {
+            String className = classNames[i];
+            compilationUnits[i] = new CompilationUnit(fileNames[i], className);
+        }
+        Compiler compiler = new Compiler(env,
+                                         policy,
+                                         settings,
+                                         requestor,
+                                         problemFactory,
+                                         true);
+        compiler.compile(compilationUnits);
+
+        if (!ctxt.keepGenerated()) {
+            File javaFile = new File(ctxt.getServletJavaFileName());
+            javaFile.delete();
+        }
+    
+        if (!problemList.isEmpty()) {
+            JavacErrorDetail[] jeds = 
+                (JavacErrorDetail[]) problemList.toArray(new JavacErrorDetail[0]);
+            errDispatcher.javacError(jeds);
+        }
+        
+        if( log.isDebugEnabled() ) {
+            long t2=System.currentTimeMillis();
+            log.debug("Compiled " + ctxt.getServletJavaFileName() + " "
+                      + (t2-t1) + "ms");
+        }
+
+        if (ctxt.isPrototypeMode()) {
+            return;
+        }
+
+        // JSR45 Support
+        if (! options.isSmapSuppressed()) {
+            SmapUtil.installSmap(smap);
+        }
+        
+    }
+    
+    
+}

Added: branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/JasperTagInfo.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/JasperTagInfo.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/JasperTagInfo.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,57 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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 javax.servlet.jsp.tagext.*;
+
+/**
+ * TagInfo extension used by tag handlers that are implemented via tag files.
+ * This class provides access to the name of the Map used to store the
+ * dynamic attribute names and values passed to the custom action invocation.
+ * This information is used by the code generator.
+ */
+class JasperTagInfo extends TagInfo {
+
+    private String dynamicAttrsMapName;
+
+    public JasperTagInfo(String tagName,
+			 String tagClassName,
+			 String bodyContent,
+			 String infoString,
+			 TagLibraryInfo taglib,
+			 TagExtraInfo tagExtraInfo,
+			 TagAttributeInfo[] attributeInfo,
+			 String displayName,
+			 String smallIcon,
+			 String largeIcon,
+			 TagVariableInfo[] tvi,
+			 String mapName) {
+
+	super(tagName, tagClassName, bodyContent, infoString, taglib,
+	      tagExtraInfo, attributeInfo, displayName, smallIcon, largeIcon,
+	      tvi);
+	this.dynamicAttrsMapName = mapName;
+    }
+
+    public String getDynamicAttributesMapName() {
+	return dynamicAttrsMapName;
+    }
+
+    public boolean hasDynamicAttributes() {
+        return dynamicAttrsMapName != null;
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/JavacErrorDetail.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/JavacErrorDetail.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/JavacErrorDetail.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,122 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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;
+
+/**
+ * Class providing details about a javac compilation error.
+ *
+ * @author Jan Luehe
+ * @author Kin-man Chung
+ */
+public class JavacErrorDetail {
+
+    private String javaFileName;
+    private int javaLineNum;
+    private String jspFileName;
+    private int jspBeginLineNum;
+    private StringBuffer errMsg;
+
+    /**
+     * Constructor.
+     *
+     * @param javaFileName The name of the Java file in which the 
+     * compilation error occurred
+     * @param javaLineNum The compilation error line number
+     * @param errMsg The compilation error message
+     */
+    public JavacErrorDetail(String javaFileName,
+			    int javaLineNum,
+			    StringBuffer errMsg) {
+
+	this.javaFileName = javaFileName;
+	this.javaLineNum = javaLineNum;
+	this.errMsg = errMsg;
+        this.jspBeginLineNum = -1;
+    }
+
+    /**
+     * Constructor.
+     *
+     * @param javaFileName The name of the Java file in which the 
+     * compilation error occurred
+     * @param javaLineNum The compilation error line number
+     * @param jspFileName The name of the JSP file from which the Java source
+     * file was generated
+     * @param jspBeginLineNum The start line number of the JSP element
+     * responsible for the compilation error
+     * @param errMsg The compilation error message
+     */
+    public JavacErrorDetail(String javaFileName,
+			    int javaLineNum,
+			    String jspFileName,
+			    int jspBeginLineNum,
+			    StringBuffer errMsg) {
+
+        this(javaFileName, javaLineNum, errMsg);
+	this.jspFileName = jspFileName;
+	this.jspBeginLineNum = jspBeginLineNum;
+    }
+
+    /**
+     * Gets the name of the Java source file in which the compilation error
+     * occurred.
+     *
+     * @return Java source file name
+     */
+    public String getJavaFileName() {
+	return this.javaFileName;
+    }
+
+    /**
+     * Gets the compilation error line number.
+     * 
+     * @return Compilation error line number
+     */
+    public int getJavaLineNumber() {
+	return this.javaLineNum;
+    }
+
+    /**
+     * Gets the name of the JSP file from which the Java source file was
+     * generated.
+     *
+     * @return JSP file from which the Java source file was generated.
+     */
+    public String getJspFileName() {
+	return this.jspFileName;
+    }
+
+    /**
+     * Gets the start line number (in the JSP file) of the JSP element
+     * responsible for the compilation error.
+     *
+     * @return Start line number of the JSP element responsible for the
+     * compilation error
+     */
+    public int getJspBeginLineNumber() {
+	return this.jspBeginLineNum;
+    }
+
+    /**
+     * Gets the compilation error message.
+     *
+     * @return Compilation error message
+     */
+    public String getErrorMessage() {
+	return this.errMsg.toString();
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/JspConfig.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/JspConfig.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/JspConfig.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,472 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.InputStream;
+import java.util.Iterator;
+import java.util.Vector;
+import java.net.URL;
+
+import javax.servlet.ServletContext;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.jasper.JasperException;
+import org.apache.jasper.xmlparser.ParserUtils;
+import org.apache.jasper.xmlparser.TreeNode;
+import org.xml.sax.InputSource;
+
+/**
+ * Handles the jsp-config element in WEB_INF/web.xml.  This is used
+ * for specifying the JSP configuration information on a JSP page
+ *
+ * @author Kin-man Chung
+ */
+
+public class JspConfig {
+
+    private static final String WEB_XML = "/WEB-INF/web.xml";
+
+    // Logger
+    private Log log = LogFactory.getLog(JspConfig.class);
+
+    private Vector jspProperties = null;
+    private ServletContext ctxt;
+    private boolean initialized = false;
+
+    private String defaultIsXml = null;		// unspecified
+    private String defaultIsELIgnored = null;	// unspecified
+    private String defaultIsScriptingInvalid = "false";
+    private JspProperty defaultJspProperty;
+
+    public JspConfig(ServletContext ctxt) {
+	this.ctxt = ctxt;
+    }
+
+    private void processWebDotXml(ServletContext ctxt) throws JasperException {
+
+        InputStream is = null;
+
+        try {
+            URL uri = ctxt.getResource(WEB_XML);
+            if (uri == null) {
+	        // no web.xml
+                return;
+	    }
+
+            is = uri.openStream();
+            InputSource ip = new InputSource(is);
+            ip.setSystemId(uri.toExternalForm()); 
+
+            ParserUtils pu = new ParserUtils();
+	    TreeNode webApp = pu.parseXMLDocument(WEB_XML, ip);
+
+	    if (webApp == null
+                    || !"2.4".equals(webApp.findAttribute("version"))) {
+	        defaultIsELIgnored = "true";
+	        return;
+	    }
+	    TreeNode jspConfig = webApp.findChild("jsp-config");
+	    if (jspConfig == null) {
+	        return;
+	    }
+
+            jspProperties = new Vector();
+            Iterator jspPropertyList = jspConfig.findChildren("jsp-property-group");
+            while (jspPropertyList.hasNext()) {
+
+                TreeNode element = (TreeNode) jspPropertyList.next();
+                Iterator list = element.findChildren();
+
+                Vector urlPatterns = new Vector();
+                String pageEncoding = null;
+                String scriptingInvalid = null;
+                String elIgnored = null;
+                String isXml = null;
+                Vector includePrelude = new Vector();
+                Vector includeCoda = new Vector();
+
+                while (list.hasNext()) {
+
+                    element = (TreeNode) list.next();
+                    String tname = element.getName();
+
+                    if ("url-pattern".equals(tname))
+                        urlPatterns.addElement( element.getBody() );
+                    else if ("page-encoding".equals(tname))
+                        pageEncoding = element.getBody();
+                    else if ("is-xml".equals(tname))
+                        isXml = element.getBody();
+                    else if ("el-ignored".equals(tname))
+                        elIgnored = element.getBody();
+                    else if ("scripting-invalid".equals(tname))
+                        scriptingInvalid = element.getBody();
+                    else if ("include-prelude".equals(tname))
+                        includePrelude.addElement(element.getBody());
+                    else if ("include-coda".equals(tname))
+                        includeCoda.addElement(element.getBody());
+                }
+
+                if (urlPatterns.size() == 0) {
+                    continue;
+                }
+ 
+                // Add one JspPropertyGroup for each URL Pattern.  This makes
+                // the matching logic easier.
+                for( int p = 0; p < urlPatterns.size(); p++ ) {
+                    String urlPattern = (String)urlPatterns.elementAt( p );
+                    String path = null;
+                    String extension = null;
+ 
+                    if (urlPattern.indexOf('*') < 0) {
+                        // Exact match
+                        path = urlPattern;
+                    } else {
+                        int i = urlPattern.lastIndexOf('/');
+                        String file;
+                        if (i >= 0) {
+                            path = urlPattern.substring(0,i+1);
+                            file = urlPattern.substring(i+1);
+                        } else {
+                            file = urlPattern;
+                        }
+ 
+                        // pattern must be "*", or of the form "*.jsp"
+                        if (file.equals("*")) {
+                            extension = "*";
+                        } else if (file.startsWith("*.")) {
+                            extension = file.substring(file.indexOf('.')+1);
+                        }
+
+                        // The url patterns are reconstructed as the follwoing:
+                        // path != null, extension == null:  / or /foo/bar.ext
+                        // path == null, extension != null:  *.ext
+                        // path != null, extension == "*":   /foo/*
+                        boolean isStar = "*".equals(extension);
+                        if ((path == null && (extension == null || isStar))
+                                || (path != null && !isStar)) {
+                            if (log.isWarnEnabled()) {
+			        log.warn(Localizer.getMessage(
+                                    "jsp.warning.bad.urlpattern.propertygroup",
+                                    urlPattern));
+                            }
+                            continue;
+                        }
+                    }
+
+                    JspProperty property = new JspProperty(isXml,
+                                                           elIgnored,
+                                                           scriptingInvalid,
+                                                           pageEncoding,
+                                                           includePrelude,
+                                                           includeCoda);
+                    JspPropertyGroup propertyGroup =
+                        new JspPropertyGroup(path, extension, property);
+
+                    jspProperties.addElement(propertyGroup);
+                }
+            }
+        } catch (Exception ex) {
+            throw new JasperException(ex);
+        } finally {
+            if (is != null) {
+                try {
+                    is.close();
+                } catch (Throwable t) {}
+            }
+        }
+    }
+
+    private void init() throws JasperException {
+
+	if (!initialized) {
+	    processWebDotXml(ctxt);
+	    defaultJspProperty = new JspProperty(defaultIsXml,
+						 defaultIsELIgnored,
+						 defaultIsScriptingInvalid,
+						 null, null, null);
+	    initialized = true;
+	}
+    }
+
+    /**
+     * Select the property group that has more restrictive url-pattern.
+     * In case of tie, select the first.
+     */
+    private JspPropertyGroup selectProperty(JspPropertyGroup prev,
+                                            JspPropertyGroup curr) {
+        if (prev == null) {
+            return curr;
+        }
+        if (prev.getExtension() == null) {
+            // exact match
+            return prev;
+        }
+        if (curr.getExtension() == null) {
+            // exact match
+            return curr;
+        }
+        String prevPath = prev.getPath();
+        String currPath = curr.getPath();
+        if (prevPath == null && currPath == null) {
+            // Both specifies a *.ext, keep the first one
+            return prev;
+        }
+        if (prevPath == null && currPath != null) {
+            return curr;
+        }
+        if (prevPath != null && currPath == null) {
+            return prev;
+        }
+        if (prevPath.length() >= currPath.length()) {
+            return prev;
+        }
+        return curr;
+    }
+            
+
+    /**
+     * Find a property that best matches the supplied resource.
+     * @param uri the resource supplied.
+     * @return a JspProperty indicating the best match, or some default.
+     */
+    public JspProperty findJspProperty(String uri) throws JasperException {
+
+	init();
+
+	// JSP Configuration settings do not apply to tag files	    
+	if (jspProperties == null || uri.endsWith(".tag")
+	        || uri.endsWith(".tagx")) {
+	    return defaultJspProperty;
+	}
+
+	String uriPath = null;
+	int index = uri.lastIndexOf('/');
+	if (index >=0 ) {
+	    uriPath = uri.substring(0, index+1);
+	}
+	String uriExtension = null;
+	index = uri.lastIndexOf('.');
+	if (index >=0) {
+	    uriExtension = uri.substring(index+1);
+	}
+
+	Vector includePreludes = new Vector();
+	Vector includeCodas = new Vector();
+
+	JspPropertyGroup isXmlMatch = null;
+	JspPropertyGroup elIgnoredMatch = null;
+	JspPropertyGroup scriptingInvalidMatch = null;
+	JspPropertyGroup pageEncodingMatch = null;
+
+	Iterator iter = jspProperties.iterator();
+	while (iter.hasNext()) {
+
+	    JspPropertyGroup jpg = (JspPropertyGroup) iter.next();
+	    JspProperty jp = jpg.getJspProperty();
+
+             // (arrays will be the same length)
+             String extension = jpg.getExtension();
+             String path = jpg.getPath();
+ 
+             if (extension == null) {
+                 // exact match pattern: /a/foo.jsp
+                 if (!uri.equals(path)) {
+                     // not matched;
+                     continue;
+                 }
+             } else {
+                 // Matching patterns *.ext or /p/*
+                 if (path != null && uriPath != null &&
+                         ! uriPath.startsWith(path)) {
+                     // not matched
+                     continue;
+                 }
+                 if (!extension.equals("*") &&
+                                 !extension.equals(uriExtension)) {
+                     // not matched
+                     continue;
+                 }
+             }
+             // We have a match
+             // Add include-preludes and include-codas
+             if (jp.getIncludePrelude() != null) {
+                 includePreludes.addAll(jp.getIncludePrelude());
+             }
+             if (jp.getIncludeCoda() != null) {
+                 includeCodas.addAll(jp.getIncludeCoda());
+             }
+
+             // If there is a previous match for the same property, remember
+             // the one that is more restrictive.
+             if (jp.isXml() != null) {
+                 isXmlMatch = selectProperty(isXmlMatch, jpg);
+             }
+             if (jp.isELIgnored() != null) {
+                 elIgnoredMatch = selectProperty(elIgnoredMatch, jpg);
+             }
+             if (jp.isScriptingInvalid() != null) {
+                 scriptingInvalidMatch =
+                     selectProperty(scriptingInvalidMatch, jpg);
+             }
+             if (jp.getPageEncoding() != null) {
+                 pageEncodingMatch = selectProperty(pageEncodingMatch, jpg);
+             }
+	}
+
+
+	String isXml = defaultIsXml;
+	String isELIgnored = defaultIsELIgnored;
+	String isScriptingInvalid = defaultIsScriptingInvalid;
+	String pageEncoding = null;
+
+	if (isXmlMatch != null) {
+	    isXml = isXmlMatch.getJspProperty().isXml();
+	}
+	if (elIgnoredMatch != null) {
+	    isELIgnored = elIgnoredMatch.getJspProperty().isELIgnored();
+	}
+	if (scriptingInvalidMatch != null) {
+	    isScriptingInvalid =
+		scriptingInvalidMatch.getJspProperty().isScriptingInvalid();
+	}
+	if (pageEncodingMatch != null) {
+	    pageEncoding = pageEncodingMatch.getJspProperty().getPageEncoding();
+	}
+
+	return new JspProperty(isXml, isELIgnored, isScriptingInvalid,
+			       pageEncoding, includePreludes, includeCodas);
+    }
+
+    /**
+     * To find out if an uri matches an url pattern in jsp config.  If so,
+     * then the uri is a JSP page.  This is used primarily for jspc.
+     */
+    public boolean isJspPage(String uri) throws JasperException {
+
+        init();
+        if (jspProperties == null) {
+            return false;
+        }
+
+        String uriPath = null;
+        int index = uri.lastIndexOf('/');
+        if (index >=0 ) {
+            uriPath = uri.substring(0, index+1);
+        }
+        String uriExtension = null;
+        index = uri.lastIndexOf('.');
+        if (index >=0) {
+            uriExtension = uri.substring(index+1);
+        }
+
+        Iterator iter = jspProperties.iterator();
+        while (iter.hasNext()) {
+
+            JspPropertyGroup jpg = (JspPropertyGroup) iter.next();
+            JspProperty jp = jpg.getJspProperty();
+
+            String extension = jpg.getExtension();
+            String path = jpg.getPath();
+
+            if (extension == null) {
+                if (uri.equals(path)) {
+                    // There is an exact match
+                    return true;
+                }
+            } else {
+                if ((path == null || path.equals(uriPath)) &&
+                    (extension.equals("*") || extension.equals(uriExtension))) {
+                    // Matches *, *.ext, /p/*, or /p/*.ext
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    static class JspPropertyGroup {
+	private String path;
+	private String extension;
+	private JspProperty jspProperty;
+
+	JspPropertyGroup(String path, String extension,
+			 JspProperty jspProperty) {
+	    this.path = path;
+	    this.extension = extension;
+	    this.jspProperty = jspProperty;
+	}
+
+	public String getPath() {
+	    return path;
+	}
+
+	public String getExtension() {
+	    return extension;
+	}
+
+	public JspProperty getJspProperty() {
+	    return jspProperty;
+	}
+    }
+
+    static public class JspProperty {
+
+	private String isXml;
+	private String elIgnored;
+	private String scriptingInvalid;
+	private String pageEncoding;
+	private Vector includePrelude;
+	private Vector includeCoda;
+
+	public JspProperty(String isXml, String elIgnored,
+		    String scriptingInvalid, String pageEncoding,
+		    Vector includePrelude, Vector includeCoda) {
+
+	    this.isXml = isXml;
+	    this.elIgnored = elIgnored;
+	    this.scriptingInvalid = scriptingInvalid;
+	    this.pageEncoding = pageEncoding;
+	    this.includePrelude = includePrelude;
+	    this.includeCoda = includeCoda;
+	}
+
+	public String isXml() {
+	    return isXml;
+	}
+
+	public String isELIgnored() {
+	    return elIgnored;
+	}
+
+	public String isScriptingInvalid() {
+	    return scriptingInvalid;
+	}
+
+	public String getPageEncoding() {
+	    return pageEncoding;
+	}
+
+	public Vector getIncludePrelude() {
+	    return includePrelude;
+	}
+
+	public Vector getIncludeCoda() {
+	    return includeCoda;
+	}
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/JspDocumentParser.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/JspDocumentParser.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/JspDocumentParser.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,1438 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.CharArrayWriter;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+
+import java.util.Iterator;
+import java.util.List;
+import java.util.jar.JarFile;
+
+import javax.servlet.jsp.tagext.TagFileInfo;
+import javax.servlet.jsp.tagext.TagInfo;
+import javax.servlet.jsp.tagext.TagLibraryInfo;
+import javax.xml.parsers.SAXParser;
+import javax.xml.parsers.SAXParserFactory;
+
+import org.apache.jasper.JasperException;
+import org.apache.jasper.JspCompilationContext;
+import org.xml.sax.Attributes;
+import org.xml.sax.InputSource;
+import org.xml.sax.Locator;
+import org.xml.sax.SAXException;
+import org.xml.sax.SAXParseException;
+import org.xml.sax.XMLReader;
+import org.xml.sax.ext.LexicalHandler;
+import org.xml.sax.helpers.AttributesImpl;
+import org.xml.sax.helpers.DefaultHandler;
+
+/**
+ * Class implementing a parser for a JSP document, that is, a JSP page in XML
+ * syntax.
+ *
+ * @author Jan Luehe
+ * @author Kin-man Chung
+ */
+
+class JspDocumentParser
+    extends DefaultHandler
+    implements LexicalHandler, TagConstants {
+
+    private static final String JSP_VERSION = "version";
+    private static final String LEXICAL_HANDLER_PROPERTY =
+        "http://xml.org/sax/properties/lexical-handler";
+    private static final String JSP_URI = "http://java.sun.com/JSP/Page";
+
+    private static final EnableDTDValidationException ENABLE_DTD_VALIDATION_EXCEPTION =
+        new EnableDTDValidationException(
+            "jsp.error.enable_dtd_validation",
+            null);
+
+    private ParserController parserController;
+    private JspCompilationContext ctxt;
+    private PageInfo pageInfo;
+    private String path;
+    private StringBuffer charBuffer;
+
+    // Node representing the XML element currently being parsed
+    private Node current;
+
+    /*
+     * Outermost (in the nesting hierarchy) node whose body is declared to be
+     * scriptless. If a node's body is declared to be scriptless, all its
+     * nested nodes must be scriptless, too.
+     */ 
+    private Node scriptlessBodyNode;
+
+    private Locator locator;
+
+    //Mark representing the start of the current element.  Note
+    //that locator.getLineNumber() and locator.getColumnNumber()
+    //return the line and column numbers for the character
+    //immediately _following_ the current element.  The underlying
+    //XMl parser eats white space that is not part of character
+    //data, so for Nodes that are not created from character data,
+    //this is the best we can do.  But when we parse character data,
+    //we get an accurate starting location by starting with startMark
+    //as set by the previous element, and updating it as we advance
+    //through the characters.
+    private Mark startMark;
+
+    // Flag indicating whether we are inside DTD declarations
+    private boolean inDTD;
+
+    private boolean isValidating;
+
+    private ErrorDispatcher err;
+    private boolean isTagFile;
+    private boolean directivesOnly;
+    private boolean isTop;
+
+    // Nesting level of Tag dependent bodies
+    private int tagDependentNesting = 0;
+    // Flag set to delay incrmenting tagDependentNesting until jsp:body
+    // is first encountered
+    private boolean tagDependentPending = false;
+
+    /*
+     * Constructor
+     */
+    public JspDocumentParser(
+        ParserController pc,
+        String path,
+        boolean isTagFile,
+        boolean directivesOnly) {
+        this.parserController = pc;
+        this.ctxt = pc.getJspCompilationContext();
+        this.pageInfo = pc.getCompiler().getPageInfo();
+        this.err = pc.getCompiler().getErrorDispatcher();
+        this.path = path;
+        this.isTagFile = isTagFile;
+        this.directivesOnly = directivesOnly;
+        this.isTop = true;
+    }
+
+    /*
+     * Parses a JSP document by responding to SAX events.
+     *
+     * @throws JasperException
+     */
+    public static Node.Nodes parse(
+        ParserController pc,
+        String path,
+        JarFile jarFile,
+        Node parent,
+        boolean isTagFile,
+        boolean directivesOnly,
+        String pageEnc,
+        String jspConfigPageEnc,
+        boolean isEncodingSpecifiedInProlog)
+        throws JasperException {
+
+        JspDocumentParser jspDocParser =
+            new JspDocumentParser(pc, path, isTagFile, directivesOnly);
+        Node.Nodes pageNodes = null;
+
+        try {
+
+            // Create dummy root and initialize it with given page encodings
+            Node.Root dummyRoot = new Node.Root(null, parent, true);
+            dummyRoot.setPageEncoding(pageEnc);
+            dummyRoot.setJspConfigPageEncoding(jspConfigPageEnc);
+            dummyRoot.setIsEncodingSpecifiedInProlog(
+                isEncodingSpecifiedInProlog);
+            jspDocParser.current = dummyRoot;
+            if (parent == null) {
+                jspDocParser.addInclude(
+                    dummyRoot,
+                    jspDocParser.pageInfo.getIncludePrelude());
+            } else {
+                jspDocParser.isTop = false;
+            }
+
+            // Parse the input
+            SAXParser saxParser = getSAXParser(false, jspDocParser);
+            InputStream inStream = null;
+            try {
+                inStream = JspUtil.getInputStream(path, jarFile,
+                                                  jspDocParser.ctxt,
+                                                  jspDocParser.err);
+                saxParser.parse(new InputSource(inStream), jspDocParser);
+            } catch (EnableDTDValidationException e) {
+                saxParser = getSAXParser(true, jspDocParser);
+                jspDocParser.isValidating = true;
+                if (inStream != null) {
+                    try {
+                        inStream.close();
+                    } catch (Exception any) {
+                    }
+                }
+                inStream = JspUtil.getInputStream(path, jarFile,
+                                                  jspDocParser.ctxt,
+                                                  jspDocParser.err);
+                saxParser.parse(new InputSource(inStream), jspDocParser);
+            } finally {
+                if (inStream != null) {
+                    try {
+                        inStream.close();
+                    } catch (Exception any) {
+                    }
+                }
+            }
+
+            if (parent == null) {
+                jspDocParser.addInclude(
+                    dummyRoot,
+                    jspDocParser.pageInfo.getIncludeCoda());
+            }
+
+            // Create Node.Nodes from dummy root
+            pageNodes = new Node.Nodes(dummyRoot);
+
+        } catch (IOException ioe) {
+            jspDocParser.err.jspError("jsp.error.data.file.read", path, ioe);
+        } catch (SAXParseException e) {
+            jspDocParser.err.jspError
+                (new Mark(jspDocParser.ctxt, path, e.getLineNumber(),
+                          e.getColumnNumber()),
+                 e.getMessage());
+        } catch (Exception e) {
+            jspDocParser.err.jspError(e);
+        }
+
+        return pageNodes;
+    }
+
+    /*
+     * Processes the given list of included files.
+     *
+     * This is used to implement the include-prelude and include-coda
+     * subelements of the jsp-config element in web.xml
+     */
+    private void addInclude(Node parent, List files) throws SAXException {
+        if (files != null) {
+            Iterator iter = files.iterator();
+            while (iter.hasNext()) {
+                String file = (String)iter.next();
+                AttributesImpl attrs = new AttributesImpl();
+                attrs.addAttribute("", "file", "file", "CDATA", file);
+
+                // Create a dummy Include directive node
+                    Node includeDir =
+                        new Node.IncludeDirective(attrs, null, // XXX
+    parent);
+                processIncludeDirective(file, includeDir);
+            }
+        }
+    }
+
+    /*
+     * Receives notification of the start of an element.
+     *
+     * This method assigns the given tag attributes to one of 3 buckets:
+     * 
+     * - "xmlns" attributes that represent (standard or custom) tag libraries.
+     * - "xmlns" attributes that do not represent tag libraries.
+     * - all remaining attributes.
+     *
+     * For each "xmlns" attribute that represents a custom tag library, the
+     * corresponding TagLibraryInfo object is added to the set of custom
+     * tag libraries.
+     */
+    public void startElement(
+        String uri,
+        String localName,
+        String qName,
+        Attributes attrs)
+        throws SAXException {
+
+        AttributesImpl taglibAttrs = null;
+        AttributesImpl nonTaglibAttrs = null;
+        AttributesImpl nonTaglibXmlnsAttrs = null;
+
+        processChars();
+
+        checkPrefixes(uri, qName, attrs);
+
+        if (directivesOnly &&
+            !(JSP_URI.equals(uri) && localName.startsWith(DIRECTIVE_ACTION))) {
+            return;
+        }
+
+        // jsp:text must not have any subelements
+        if (JSP_URI.equals(uri) && TEXT_ACTION.equals(current.getLocalName())) {
+            throw new SAXParseException(
+                Localizer.getMessage("jsp.error.text.has_subelement"),
+                locator);
+        }
+
+        startMark = new Mark(ctxt, path, locator.getLineNumber(),
+                             locator.getColumnNumber());
+
+        if (attrs != null) {
+            /*
+             * Notice that due to a bug in the underlying SAX parser, the
+             * attributes must be enumerated in descending order. 
+             */
+            boolean isTaglib = false;
+            for (int i = attrs.getLength() - 1; i >= 0; i--) {
+                isTaglib = false;
+                String attrQName = attrs.getQName(i);
+                if (!attrQName.startsWith("xmlns")) {
+                    if (nonTaglibAttrs == null) {
+                        nonTaglibAttrs = new AttributesImpl();
+                    }
+                    nonTaglibAttrs.addAttribute(
+                        attrs.getURI(i),
+                        attrs.getLocalName(i),
+                        attrs.getQName(i),
+                        attrs.getType(i),
+                        attrs.getValue(i));
+                } else {
+                    if (attrQName.startsWith("xmlns:jsp")) {
+                        isTaglib = true;
+                    } else {
+                        String attrUri = attrs.getValue(i);
+                        // TaglibInfo for this uri already established in
+                        // startPrefixMapping
+                        isTaglib = pageInfo.hasTaglib(attrUri);
+                    }
+                    if (isTaglib) {
+                        if (taglibAttrs == null) {
+                            taglibAttrs = new AttributesImpl();
+                        }
+                        taglibAttrs.addAttribute(
+                            attrs.getURI(i),
+                            attrs.getLocalName(i),
+                            attrs.getQName(i),
+                            attrs.getType(i),
+                            attrs.getValue(i));
+                    } else {
+                        if (nonTaglibXmlnsAttrs == null) {
+                            nonTaglibXmlnsAttrs = new AttributesImpl();
+                        }
+                        nonTaglibXmlnsAttrs.addAttribute(
+                            attrs.getURI(i),
+                            attrs.getLocalName(i),
+                            attrs.getQName(i),
+                            attrs.getType(i),
+                            attrs.getValue(i));
+                    }
+                }
+            }
+        }
+
+        Node node = null;
+
+        if (tagDependentPending && JSP_URI.equals(uri) &&
+                     localName.equals(BODY_ACTION)) {
+            tagDependentPending = false;
+            tagDependentNesting++;
+            current =
+                parseStandardAction(
+                    qName,
+                    localName,
+                    nonTaglibAttrs,
+                    nonTaglibXmlnsAttrs,
+                    taglibAttrs,
+                    startMark,
+                    current);
+            return;
+        }
+
+        if (tagDependentPending && JSP_URI.equals(uri) &&
+                     localName.equals(ATTRIBUTE_ACTION)) {
+            current =
+                parseStandardAction(
+                    qName,
+                    localName,
+                    nonTaglibAttrs,
+                    nonTaglibXmlnsAttrs,
+                    taglibAttrs,
+                    startMark,
+                    current);
+            return;
+        }
+
+        if (tagDependentPending) {
+            tagDependentPending = false;
+            tagDependentNesting++;
+        }
+
+        if (tagDependentNesting > 0) {
+            node =
+                new Node.UninterpretedTag(
+                    qName,
+                    localName,
+                    nonTaglibAttrs,
+                    nonTaglibXmlnsAttrs,
+                    taglibAttrs,
+                    startMark,
+                    current);
+        } else if (JSP_URI.equals(uri)) {
+            node =
+                parseStandardAction(
+                    qName,
+                    localName,
+                    nonTaglibAttrs,
+                    nonTaglibXmlnsAttrs,
+                    taglibAttrs,
+                    startMark,
+                    current);
+        } else {
+            node =
+                parseCustomAction(
+                    qName,
+                    localName,
+                    uri,
+                    nonTaglibAttrs,
+                    nonTaglibXmlnsAttrs,
+                    taglibAttrs,
+                    startMark,
+                    current);
+            if (node == null) {
+                node =
+                    new Node.UninterpretedTag(
+                        qName,
+                        localName,
+                        nonTaglibAttrs,
+                        nonTaglibXmlnsAttrs,
+                        taglibAttrs,
+                        startMark,
+                        current);
+            } else {
+                // custom action
+                String bodyType = getBodyType((Node.CustomTag) node);
+
+                if (scriptlessBodyNode == null
+                        && bodyType.equalsIgnoreCase(TagInfo.BODY_CONTENT_SCRIPTLESS)) {
+                    scriptlessBodyNode = node;
+                }
+                else if (TagInfo.BODY_CONTENT_TAG_DEPENDENT.equalsIgnoreCase(bodyType)) {
+                    tagDependentPending = true;
+                }
+            }
+        }
+
+        current = node;
+    }
+
+    /*
+     * Receives notification of character data inside an element.
+     *
+     * The SAX does not call this method with all of the template text, but may
+     * invoke this method with chunks of it.  This is a problem when we try
+     * to determine if the text contains only whitespaces, or when we are
+     * looking for an EL expression string.  Therefore it is necessary to
+     * buffer and concatenate the chunks and process the concatenated text 
+     * later (at beginTag and endTag)
+     *
+     * @param buf The characters
+     * @param offset The start position in the character array
+     * @param len The number of characters to use from the character array
+     *
+     * @throws SAXException
+     */
+    public void characters(char[] buf, int offset, int len) {
+
+        if (charBuffer == null) {
+            charBuffer = new StringBuffer();
+        }
+        charBuffer.append(buf, offset, len);
+    }
+
+    private void processChars() throws SAXException {
+
+        if (charBuffer == null || directivesOnly) {
+            return;
+        }
+
+        /*
+         * JSP.6.1.1: All textual nodes that have only white space are to be
+         * dropped from the document, except for nodes in a jsp:text element,
+         * and any leading and trailing white-space-only textual nodes in a
+         * jsp:attribute whose 'trim' attribute is set to FALSE, which are to
+         * be kept verbatim.
+         * JSP.6.2.3 defines white space characters.
+         */
+        boolean isAllSpace = true;
+        if (!(current instanceof Node.JspText)
+            && !(current instanceof Node.NamedAttribute)) {
+            for (int i = 0; i < charBuffer.length(); i++) {
+                if (!(charBuffer.charAt(i) == ' '
+                    || charBuffer.charAt(i) == '\n'
+                    || charBuffer.charAt(i) == '\r'
+                    || charBuffer.charAt(i) == '\t')) {
+                    isAllSpace = false;
+                    break;
+                }
+            }
+        }
+
+        if (!isAllSpace && tagDependentPending) {
+            tagDependentPending = false;
+            tagDependentNesting++;
+        }
+
+        if (tagDependentNesting > 0) {
+            if (charBuffer.length() > 0) {
+                new Node.TemplateText(charBuffer.toString(), startMark, current);
+            }
+            startMark = new Mark(ctxt, path, locator.getLineNumber(),
+                                 locator.getColumnNumber());
+            charBuffer = null;
+            return;
+        }
+
+        if ((current instanceof Node.JspText)
+            || (current instanceof Node.NamedAttribute)
+            || !isAllSpace) {
+
+            int line = startMark.getLineNumber();
+            int column = startMark.getColumnNumber();
+
+            CharArrayWriter ttext = new CharArrayWriter();
+            int lastCh = 0;
+            for (int i = 0; i < charBuffer.length(); i++) {
+
+                int ch = charBuffer.charAt(i);
+                if (ch == '\n') {
+                    column = 1;
+                    line++;
+                } else {
+                    column++;
+                }
+                if (lastCh == '$' && ch == '{') {
+                    if (ttext.size() > 0) {
+                        new Node.TemplateText(
+                            ttext.toString(),
+                            startMark,
+                            current);
+                        ttext = new CharArrayWriter();
+                        //We subtract two from the column number to
+                        //account for the '${' that we've already parsed
+                        startMark = new Mark(ctxt, path, line, column - 2);
+                    }
+                    // following "${" to first unquoted "}"
+                    i++;
+                    boolean singleQ = false;
+                    boolean doubleQ = false;
+                    lastCh = 0;
+                    for (;; i++) {
+                        if (i >= charBuffer.length()) {
+                            throw new SAXParseException(
+                                Localizer.getMessage(
+                                    "jsp.error.unterminated",
+                                    "${"),
+                                locator);
+
+                        }
+                        ch = charBuffer.charAt(i);
+                        if (ch == '\n') {
+                            column = 1;
+                            line++;
+                        } else {
+                            column++;
+                        }
+                        if (lastCh == '\\' && (singleQ || doubleQ)) {
+                            ttext.write(ch);
+                            lastCh = 0;
+                            continue;
+                        }
+                        if (ch == '}') {
+                            new Node.ELExpression(
+                                ttext.toString(),
+                                startMark,
+                                current);
+                            ttext = new CharArrayWriter();
+                            startMark = new Mark(ctxt, path, line, column);
+                            break;
+                        }
+                        if (ch == '"')
+                            doubleQ = !doubleQ;
+                        else if (ch == '\'')
+                            singleQ = !singleQ;
+
+                        ttext.write(ch);
+                        lastCh = ch;
+                    }
+                } else if (lastCh == '\\' && ch == '$') {
+                    ttext.write('$');
+                    ch = 0;  // Not start of EL anymore
+                } else {
+                    if (lastCh == '$' || lastCh == '\\') {
+                        ttext.write(lastCh);
+                    }
+                    if (ch != '$' && ch != '\\') {
+                        ttext.write(ch);
+                    }
+                }
+                lastCh = ch;
+            }
+            if (lastCh == '$' || lastCh == '\\') {
+                ttext.write(lastCh);
+            }
+            if (ttext.size() > 0) {
+                new Node.TemplateText(ttext.toString(), startMark, current);
+            }
+        }
+        startMark = new Mark(ctxt, path, locator.getLineNumber(),
+                             locator.getColumnNumber());
+
+        charBuffer = null;
+    }
+
+    /*
+     * Receives notification of the end of an element.
+     */
+    public void endElement(String uri, String localName, String qName)
+        throws SAXException {
+
+        processChars();
+
+        if (directivesOnly &&
+            !(JSP_URI.equals(uri) && localName.startsWith(DIRECTIVE_ACTION))) {
+            return;
+        }
+
+        if (current instanceof Node.NamedAttribute) {
+            boolean isTrim = ((Node.NamedAttribute)current).isTrim();
+            Node.Nodes subElems = ((Node.NamedAttribute)current).getBody();
+            for (int i = 0; subElems != null && i < subElems.size(); i++) {
+                Node subElem = subElems.getNode(i);
+                if (!(subElem instanceof Node.TemplateText)) {
+                    continue;
+                }
+                // Ignore any whitespace (including spaces, carriage returns,
+                // line feeds, and tabs, that appear at the beginning and at
+                // the end of the body of the <jsp:attribute> action, if the
+                // action's 'trim' attribute is set to TRUE (default).
+                // In addition, any textual nodes in the <jsp:attribute> that
+                // have only white space are dropped from the document, with
+                // the exception of leading and trailing white-space-only
+                // textual nodes in a <jsp:attribute> whose 'trim' attribute
+                // is set to FALSE, which must be kept verbatim.
+                if (i == 0) {
+                    if (isTrim) {
+                        ((Node.TemplateText)subElem).ltrim();
+                    }
+                } else if (i == subElems.size() - 1) {
+                    if (isTrim) {
+                        ((Node.TemplateText)subElem).rtrim();
+                    }
+                } else {
+                    if (((Node.TemplateText)subElem).isAllSpace()) {
+                        subElems.remove(subElem);
+                    }
+                }
+            }
+        } else if (current instanceof Node.ScriptingElement) {
+            checkScriptingBody((Node.ScriptingElement)current);
+        }
+
+        if ( isTagDependent(current)) {
+            tagDependentNesting--;
+        }
+
+        if (scriptlessBodyNode != null
+                && current.equals(scriptlessBodyNode)) {
+            scriptlessBodyNode = null;
+        }
+
+        if (current.getParent() != null) {
+            current = current.getParent();
+        }
+    }
+
+    /*
+     * Receives the document locator.
+     *
+     * @param locator the document locator
+     */
+    public void setDocumentLocator(Locator locator) {
+        this.locator = locator;
+    }
+
+    /*
+     * See org.xml.sax.ext.LexicalHandler.
+     */
+    public void comment(char[] buf, int offset, int len) throws SAXException {
+
+        processChars();  // Flush char buffer and remove white spaces
+
+        // ignore comments in the DTD
+        if (!inDTD) {
+            startMark =
+                new Mark(
+                    ctxt,
+                    path,
+                    locator.getLineNumber(),
+                    locator.getColumnNumber());
+            new Node.Comment(new String(buf, offset, len), startMark, current);
+        }
+    }
+
+    /*
+     * See org.xml.sax.ext.LexicalHandler.
+     */
+    public void startCDATA() throws SAXException {
+
+        processChars();  // Flush char buffer and remove white spaces
+        startMark = new Mark(ctxt, path, locator.getLineNumber(),
+                             locator.getColumnNumber());
+    }
+
+    /*
+     * See org.xml.sax.ext.LexicalHandler.
+     */
+    public void endCDATA() throws SAXException {
+        processChars();  // Flush char buffer and remove white spaces
+    }
+
+    /*
+     * See org.xml.sax.ext.LexicalHandler.
+     */
+    public void startEntity(String name) throws SAXException {
+        // do nothing
+    }
+
+    /*
+     * See org.xml.sax.ext.LexicalHandler.
+     */
+    public void endEntity(String name) throws SAXException {
+        // do nothing
+    }
+
+    /*
+     * See org.xml.sax.ext.LexicalHandler.
+     */
+    public void startDTD(String name, String publicId, String systemId)
+        throws SAXException {
+        if (!isValidating) {
+            fatalError(ENABLE_DTD_VALIDATION_EXCEPTION);
+        }
+
+        inDTD = true;
+    }
+
+    /*
+     * See org.xml.sax.ext.LexicalHandler.
+     */
+    public void endDTD() throws SAXException {
+        inDTD = false;
+    }
+
+    /*
+     * Receives notification of a non-recoverable error.
+     */
+    public void fatalError(SAXParseException e) throws SAXException {
+        throw e;
+    }
+
+    /*
+     * Receives notification of a recoverable error.
+     */
+    public void error(SAXParseException e) throws SAXException {
+        throw e;
+    }
+
+    /*
+     * Receives notification of the start of a Namespace mapping. 
+     */
+    public void startPrefixMapping(String prefix, String uri)
+        throws SAXException {
+        TagLibraryInfo taglibInfo;
+
+        if (directivesOnly && !(JSP_URI.equals(uri))) {
+            return;
+        }
+        
+        try {
+            taglibInfo = getTaglibInfo(prefix, uri);
+        } catch (JasperException je) {
+            throw new SAXParseException(
+                Localizer.getMessage("jsp.error.could.not.add.taglibraries"),
+                locator,
+                je);
+        }
+
+        if (taglibInfo != null) {
+            if (pageInfo.getTaglib(uri) == null) {
+                pageInfo.addTaglib(uri, taglibInfo);
+            }
+            pageInfo.pushPrefixMapping(prefix, uri);
+        } else {
+            pageInfo.pushPrefixMapping(prefix, null);
+        }
+    }
+
+    /*
+     * Receives notification of the end of a Namespace mapping. 
+     */
+    public void endPrefixMapping(String prefix) throws SAXException {
+
+        if (directivesOnly) {
+            String uri = pageInfo.getURI(prefix);
+            if (!JSP_URI.equals(uri)) {
+                return;
+            }
+        }
+
+        pageInfo.popPrefixMapping(prefix);
+    }
+
+    //*********************************************************************
+    // Private utility methods
+
+    private Node parseStandardAction(
+        String qName,
+        String localName,
+        Attributes nonTaglibAttrs,
+        Attributes nonTaglibXmlnsAttrs,
+        Attributes taglibAttrs,
+        Mark start,
+        Node parent)
+        throws SAXException {
+
+        Node node = null;
+
+        if (localName.equals(ROOT_ACTION)) {
+            if (!(current instanceof Node.Root)) {
+                throw new SAXParseException(
+                    Localizer.getMessage("jsp.error.nested_jsproot"),
+                    locator);
+            }
+            node =
+                new Node.JspRoot(
+                    qName,
+                    nonTaglibAttrs,
+                    nonTaglibXmlnsAttrs,
+                    taglibAttrs,
+                    start,
+                    current);
+            if (isTop) {
+                pageInfo.setHasJspRoot(true);
+            }
+        } else if (localName.equals(PAGE_DIRECTIVE_ACTION)) {
+            if (isTagFile) {
+                throw new SAXParseException(
+                    Localizer.getMessage(
+                        "jsp.error.action.istagfile",
+                        localName),
+                    locator);
+            }
+            node =
+                new Node.PageDirective(
+                    qName,
+                    nonTaglibAttrs,
+                    nonTaglibXmlnsAttrs,
+                    taglibAttrs,
+                    start,
+                    current);
+            String imports = nonTaglibAttrs.getValue("import");
+            // There can only be one 'import' attribute per page directive
+            if (imports != null) {
+                ((Node.PageDirective)node).addImport(imports);
+            }
+        } else if (localName.equals(INCLUDE_DIRECTIVE_ACTION)) {
+            node =
+                new Node.IncludeDirective(
+                    qName,
+                    nonTaglibAttrs,
+                    nonTaglibXmlnsAttrs,
+                    taglibAttrs,
+                    start,
+                    current);
+            processIncludeDirective(nonTaglibAttrs.getValue("file"), node);
+        } else if (localName.equals(DECLARATION_ACTION)) {
+            if (scriptlessBodyNode != null) {
+                // We're nested inside a node whose body is
+                // declared to be scriptless
+                throw new SAXParseException(
+                    Localizer.getMessage(
+                        "jsp.error.no.scriptlets",
+                        localName),
+                    locator);
+            }
+            node =
+                new Node.Declaration(
+                    qName,
+                    nonTaglibXmlnsAttrs,
+                    taglibAttrs,
+                    start,
+                    current);
+        } else if (localName.equals(SCRIPTLET_ACTION)) {
+            if (scriptlessBodyNode != null) {
+                // We're nested inside a node whose body is
+                // declared to be scriptless
+                throw new SAXParseException(
+                    Localizer.getMessage(
+                        "jsp.error.no.scriptlets",
+                        localName),
+                    locator);
+            }
+            node =
+                new Node.Scriptlet(
+                    qName,
+                    nonTaglibXmlnsAttrs,
+                    taglibAttrs,
+                    start,
+                    current);
+        } else if (localName.equals(EXPRESSION_ACTION)) {
+            if (scriptlessBodyNode != null) {
+                // We're nested inside a node whose body is
+                // declared to be scriptless
+                throw new SAXParseException(
+                    Localizer.getMessage(
+                        "jsp.error.no.scriptlets",
+                        localName),
+                    locator);
+            }
+            node =
+                new Node.Expression(
+                    qName,
+                    nonTaglibXmlnsAttrs,
+                    taglibAttrs,
+                    start,
+                    current);
+        } else if (localName.equals(USE_BEAN_ACTION)) {
+            node =
+                new Node.UseBean(
+                    qName,
+                    nonTaglibAttrs,
+                    nonTaglibXmlnsAttrs,
+                    taglibAttrs,
+                    start,
+                    current);
+        } else if (localName.equals(SET_PROPERTY_ACTION)) {
+            node =
+                new Node.SetProperty(
+                    qName,
+                    nonTaglibAttrs,
+                    nonTaglibXmlnsAttrs,
+                    taglibAttrs,
+                    start,
+                    current);
+        } else if (localName.equals(GET_PROPERTY_ACTION)) {
+            node =
+                new Node.GetProperty(
+                    qName,
+                    nonTaglibAttrs,
+                    nonTaglibXmlnsAttrs,
+                    taglibAttrs,
+                    start,
+                    current);
+        } else if (localName.equals(INCLUDE_ACTION)) {
+            node =
+                new Node.IncludeAction(
+                    qName,
+                    nonTaglibAttrs,
+                    nonTaglibXmlnsAttrs,
+                    taglibAttrs,
+                    start,
+                    current);
+        } else if (localName.equals(FORWARD_ACTION)) {
+            node =
+                new Node.ForwardAction(
+                    qName,
+                    nonTaglibAttrs,
+                    nonTaglibXmlnsAttrs,
+                    taglibAttrs,
+                    start,
+                    current);
+        } else if (localName.equals(PARAM_ACTION)) {
+            node =
+                new Node.ParamAction(
+                    qName,
+                    nonTaglibAttrs,
+                    nonTaglibXmlnsAttrs,
+                    taglibAttrs,
+                    start,
+                    current);
+        } else if (localName.equals(PARAMS_ACTION)) {
+            node =
+                new Node.ParamsAction(
+                    qName,
+                    nonTaglibXmlnsAttrs,
+                    taglibAttrs,
+                    start,
+                    current);
+        } else if (localName.equals(PLUGIN_ACTION)) {
+            node =
+                new Node.PlugIn(
+                    qName,
+                    nonTaglibAttrs,
+                    nonTaglibXmlnsAttrs,
+                    taglibAttrs,
+                    start,
+                    current);
+        } else if (localName.equals(TEXT_ACTION)) {
+            node =
+                new Node.JspText(
+                    qName,
+                    nonTaglibXmlnsAttrs,
+                    taglibAttrs,
+                    start,
+                    current);
+        } else if (localName.equals(BODY_ACTION)) {
+            node =
+                new Node.JspBody(
+                    qName,
+                    nonTaglibXmlnsAttrs,
+                    taglibAttrs,
+                    start,
+                    current);
+        } else if (localName.equals(ATTRIBUTE_ACTION)) {
+            node =
+                new Node.NamedAttribute(
+                    qName,
+                    nonTaglibAttrs,
+                    nonTaglibXmlnsAttrs,
+                    taglibAttrs,
+                    start,
+                    current);
+        } else if (localName.equals(OUTPUT_ACTION)) {
+            node =
+                new Node.JspOutput(
+                    qName,
+                    nonTaglibAttrs,
+                    nonTaglibXmlnsAttrs,
+                    taglibAttrs,
+                    start,
+                    current);
+        } else if (localName.equals(TAG_DIRECTIVE_ACTION)) {
+            if (!isTagFile) {
+                throw new SAXParseException(
+                    Localizer.getMessage(
+                        "jsp.error.action.isnottagfile",
+                        localName),
+                    locator);
+            }
+            node =
+                new Node.TagDirective(
+                    qName,
+                    nonTaglibAttrs,
+                    nonTaglibXmlnsAttrs,
+                    taglibAttrs,
+                    start,
+                    current);
+            String imports = nonTaglibAttrs.getValue("import");
+            // There can only be one 'import' attribute per tag directive
+            if (imports != null) {
+                ((Node.TagDirective)node).addImport(imports);
+            }
+        } else if (localName.equals(ATTRIBUTE_DIRECTIVE_ACTION)) {
+            if (!isTagFile) {
+                throw new SAXParseException(
+                    Localizer.getMessage(
+                        "jsp.error.action.isnottagfile",
+                        localName),
+                    locator);
+            }
+            node =
+                new Node.AttributeDirective(
+                    qName,
+                    nonTaglibAttrs,
+                    nonTaglibXmlnsAttrs,
+                    taglibAttrs,
+                    start,
+                    current);
+        } else if (localName.equals(VARIABLE_DIRECTIVE_ACTION)) {
+            if (!isTagFile) {
+                throw new SAXParseException(
+                    Localizer.getMessage(
+                        "jsp.error.action.isnottagfile",
+                        localName),
+                    locator);
+            }
+            node =
+                new Node.VariableDirective(
+                    qName,
+                    nonTaglibAttrs,
+                    nonTaglibXmlnsAttrs,
+                    taglibAttrs,
+                    start,
+                    current);
+        } else if (localName.equals(INVOKE_ACTION)) {
+            if (!isTagFile) {
+                throw new SAXParseException(
+                    Localizer.getMessage(
+                        "jsp.error.action.isnottagfile",
+                        localName),
+                    locator);
+            }
+            node =
+                new Node.InvokeAction(
+                    qName,
+                    nonTaglibAttrs,
+                    nonTaglibXmlnsAttrs,
+                    taglibAttrs,
+                    start,
+                    current);
+        } else if (localName.equals(DOBODY_ACTION)) {
+            if (!isTagFile) {
+                throw new SAXParseException(
+                    Localizer.getMessage(
+                        "jsp.error.action.isnottagfile",
+                        localName),
+                    locator);
+            }
+            node =
+                new Node.DoBodyAction(
+                    qName,
+                    nonTaglibAttrs,
+                    nonTaglibXmlnsAttrs,
+                    taglibAttrs,
+                    start,
+                    current);
+        } else if (localName.equals(ELEMENT_ACTION)) {
+            node =
+                new Node.JspElement(
+                    qName,
+                    nonTaglibAttrs,
+                    nonTaglibXmlnsAttrs,
+                    taglibAttrs,
+                    start,
+                    current);
+        } else if (localName.equals(FALLBACK_ACTION)) {
+            node =
+                new Node.FallBackAction(
+                    qName,
+                    nonTaglibXmlnsAttrs,
+                    taglibAttrs,
+                    start,
+                    current);
+        } else {
+            throw new SAXParseException(
+                Localizer.getMessage(
+                    "jsp.error.xml.badStandardAction",
+                    localName),
+                locator);
+        }
+
+        return node;
+    }
+
+    /*
+     * Checks if the XML element with the given tag name is a custom action,
+     * and returns the corresponding Node object.
+     */
+    private Node parseCustomAction(
+        String qName,
+        String localName,
+        String uri,
+        Attributes nonTaglibAttrs,
+        Attributes nonTaglibXmlnsAttrs,
+        Attributes taglibAttrs,
+        Mark start,
+        Node parent)
+        throws SAXException {
+
+        // Check if this is a user-defined (custom) tag
+        TagLibraryInfo tagLibInfo = pageInfo.getTaglib(uri);
+        if (tagLibInfo == null) {
+            return null;
+        }
+
+        TagInfo tagInfo = tagLibInfo.getTag(localName);
+        TagFileInfo tagFileInfo = tagLibInfo.getTagFile(localName);
+        if (tagInfo == null && tagFileInfo == null) {
+            throw new SAXException(
+                Localizer.getMessage("jsp.error.xml.bad_tag", localName, uri));
+        }
+        Class tagHandlerClass = null;
+        if (tagInfo != null) {
+            String handlerClassName = tagInfo.getTagClassName();
+            try {
+                tagHandlerClass =
+                    ctxt.getClassLoader().loadClass(handlerClassName);
+            } catch (Exception e) {
+                throw new SAXException(
+                    Localizer.getMessage("jsp.error.loadclass.taghandler",
+                                         handlerClassName,
+                                         qName),
+                    e);
+            }
+        }
+
+        String prefix = "";
+        int colon = qName.indexOf(':');
+        if (colon != -1) {
+            prefix = qName.substring(0, colon);
+        }
+
+        Node.CustomTag ret = null;
+        if (tagInfo != null) {
+            ret =
+                new Node.CustomTag(
+                    qName,
+                    prefix,
+                    localName,
+                    uri,
+                    nonTaglibAttrs,
+                    nonTaglibXmlnsAttrs,
+                    taglibAttrs,
+                    start,
+                    parent,
+                    tagInfo,
+                    tagHandlerClass);
+        } else {
+            ret =
+                new Node.CustomTag(
+                    qName,
+                    prefix,
+                    localName,
+                    uri,
+                    nonTaglibAttrs,
+                    nonTaglibXmlnsAttrs,
+                    taglibAttrs,
+                    start,
+                    parent,
+                    tagFileInfo);
+        }
+
+        return ret;
+    }
+
+    /*
+     * Creates the tag library associated with the given uri namespace, and
+     * returns it.
+     *
+     * @param prefix The prefix of the xmlns attribute
+     * @param uri The uri namespace (value of the xmlns attribute)
+     *
+     * @return The tag library associated with the given uri namespace
+     */
+    private TagLibraryInfo getTaglibInfo(String prefix, String uri)
+        throws JasperException {
+
+        TagLibraryInfo result = null;
+
+        if (uri.startsWith(URN_JSPTAGDIR)) {
+            // uri (of the form "urn:jsptagdir:path") references tag file dir
+            String tagdir = uri.substring(URN_JSPTAGDIR.length());
+            result =
+                new ImplicitTagLibraryInfo(
+                    ctxt,
+                    parserController,
+                    prefix,
+                    tagdir,
+                    err);
+        } else {
+            // uri references TLD file
+            boolean isPlainUri = false;
+            if (uri.startsWith(URN_JSPTLD)) {
+                // uri is of the form "urn:jsptld:path"
+                uri = uri.substring(URN_JSPTLD.length());
+            } else {
+                isPlainUri = true;
+            }
+
+            String[] location = ctxt.getTldLocation(uri);
+            if (location != null || !isPlainUri) {
+                if (ctxt.getOptions().isCaching()) {
+                    result = (TagLibraryInfoImpl) ctxt.getOptions().getCache().get(uri);
+                }
+                if (result == null) {
+                    /*
+                     * If the uri value is a plain uri, a translation error must
+                     * not be generated if the uri is not found in the taglib map.
+                     * Instead, any actions in the namespace defined by the uri
+                     * value must be treated as uninterpreted.
+                     */
+                    result =
+                        new TagLibraryInfoImpl(
+                            ctxt,
+                            parserController,
+                            prefix,
+                            uri,
+                            location,
+                            err);
+                    if (ctxt.getOptions().isCaching()) {
+                        ctxt.getOptions().getCache().put(uri, result);
+                    }
+                }
+            }
+        }
+
+        return result;
+    }
+
+    /*
+     * Ensures that the given body only contains nodes that are instances of
+     * TemplateText.
+     *
+     * This check is performed only for the body of a scripting (that is:
+     * declaration, scriptlet, or expression) element, after the end tag of a
+     * scripting element has been reached.
+     */
+    private void checkScriptingBody(Node.ScriptingElement scriptingElem)
+        throws SAXException {
+        Node.Nodes body = scriptingElem.getBody();
+        if (body != null) {
+            int size = body.size();
+            for (int i = 0; i < size; i++) {
+                Node n = body.getNode(i);
+                if (!(n instanceof Node.TemplateText)) {
+                    String elemType = SCRIPTLET_ACTION;
+                    if (scriptingElem instanceof Node.Declaration)
+                        elemType = DECLARATION_ACTION;
+                    if (scriptingElem instanceof Node.Expression)
+                        elemType = EXPRESSION_ACTION;
+                    String msg =
+                        Localizer.getMessage(
+                            "jsp.error.parse.xml.scripting.invalid.body",
+                            elemType);
+                    throw new SAXException(msg);
+                }
+            }
+        }
+    }
+
+    /*
+     * Parses the given file included via an include directive.
+     *
+     * @param fname The path to the included resource, as specified by the
+     * 'file' attribute of the include directive
+     * @param parent The Node representing the include directive
+     */
+    private void processIncludeDirective(String fname, Node parent)
+        throws SAXException {
+
+        if (fname == null) {
+            return;
+        }
+
+        try {
+            parserController.parse(fname, parent, null);
+        } catch (FileNotFoundException fnfe) {
+            throw new SAXParseException(
+                Localizer.getMessage("jsp.error.file.not.found", fname),
+                locator,
+                fnfe);
+        } catch (Exception e) {
+            throw new SAXException(e);
+        }
+    }
+
+    /*
+     * Checks an element's given URI, qname, and attributes to see if any
+     * of them hijack the 'jsp' prefix, that is, bind it to a namespace other
+     * than http://java.sun.com/JSP/Page.
+     *
+     * @param uri The element's URI
+     * @param qName The element's qname
+     * @param attrs The element's attributes
+     */
+    private void checkPrefixes(String uri, String qName, Attributes attrs) {
+
+        checkPrefix(uri, qName);
+
+        int len = attrs.getLength();
+        for (int i = 0; i < len; i++) {
+            checkPrefix(attrs.getURI(i), attrs.getQName(i));
+        }
+    }
+
+    /*
+     * Checks the given URI and qname to see if they hijack the 'jsp' prefix,
+     * which would be the case if qName contained the 'jsp' prefix and
+     * uri was different from http://java.sun.com/JSP/Page.
+     *
+     * @param uri The URI to check
+     * @param qName The qname to check
+     */
+    private void checkPrefix(String uri, String qName) {
+
+        int index = qName.indexOf(':');
+        if (index != -1) {
+            String prefix = qName.substring(0, index);
+            pageInfo.addPrefix(prefix);
+            if ("jsp".equals(prefix) && !JSP_URI.equals(uri)) {
+                pageInfo.setIsJspPrefixHijacked(true);
+            }
+        }
+    }
+
+    /*
+     * Gets SAXParser.
+     *
+     * @param validating Indicates whether the requested SAXParser should
+     * be validating
+     * @param jspDocParser The JSP document parser
+     *
+     * @return The SAXParser
+     */
+    private static SAXParser getSAXParser(
+        boolean validating,
+        JspDocumentParser jspDocParser)
+        throws Exception {
+
+        SAXParserFactory factory = SAXParserFactory.newInstance();
+        factory.setNamespaceAware(true);
+
+        // Preserve xmlns attributes
+        factory.setFeature(
+            "http://xml.org/sax/features/namespace-prefixes",
+            true);
+        factory.setValidating(validating);
+        //factory.setFeature(
+        //    "http://xml.org/sax/features/validation",
+        //    validating);
+        
+        // Configure the parser
+        SAXParser saxParser = factory.newSAXParser();
+        XMLReader xmlReader = saxParser.getXMLReader();
+        xmlReader.setProperty(LEXICAL_HANDLER_PROPERTY, jspDocParser);
+        xmlReader.setErrorHandler(jspDocParser);
+
+        return saxParser;
+    }
+
+    /*
+     * Exception indicating that a DOCTYPE declaration is present, but
+     * validation is turned off.
+     */
+    private static class EnableDTDValidationException
+        extends SAXParseException {
+
+        EnableDTDValidationException(String message, Locator loc) {
+            super(message, loc);
+        }
+    }
+
+    private static String getBodyType(Node.CustomTag custom) {
+
+        if (custom.getTagInfo() != null) {
+            return custom.getTagInfo().getBodyContent();
+        }
+
+        return custom.getTagFileInfo().getTagInfo().getBodyContent();
+    }
+
+    private boolean isTagDependent(Node n) {
+
+        if (n instanceof Node.CustomTag) {
+            String bodyType = getBodyType((Node.CustomTag) n);
+            return
+                TagInfo.BODY_CONTENT_TAG_DEPENDENT.equalsIgnoreCase(bodyType);
+        }
+        return false;
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/JspReader.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/JspReader.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/JspReader.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,656 @@
+/*
+ * Copyright 1999,2004-2005 The Apache Software Foundation.
+ * 
+ * Licensed 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.CharArrayWriter;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.util.List;
+import java.util.Vector;
+import java.util.jar.JarFile;
+import java.net.URL;
+import java.net.MalformedURLException;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.jasper.JasperException;
+import org.apache.jasper.JspCompilationContext;
+
+/**
+ * JspReader is an input buffer for the JSP parser. It should allow
+ * unlimited lookahead and pushback. It also has a bunch of parsing
+ * utility methods for understanding htmlesque thingies.
+ *
+ * @author Anil K. Vijendran
+ * @author Anselm Baird-Smith
+ * @author Harish Prabandham
+ * @author Rajiv Mordani
+ * @author Mandar Raje
+ * @author Danno Ferrin
+ * @author Kin-man Chung
+ * @author Shawn Bayern
+ * @author Mark Roth
+ */
+
+class JspReader {
+
+    /**
+     * Logger.
+     */
+    private Log log = LogFactory.getLog(JspReader.class);
+
+    /**
+     * The current spot in the file.
+     */
+    private Mark current;
+
+    /**
+     * What is this?
+     */
+    private String master;
+
+    /**
+     * The list of source files.
+     */
+    private List sourceFiles;
+
+    /**
+     * The current file ID (-1 indicates an error or no file).
+     */
+    private int currFileId;
+
+    /**
+     * Seems redundant.
+     */
+    private int size;
+
+    /**
+     * The compilation context.
+     */
+    private JspCompilationContext context;
+
+    /**
+     * The Jasper error dispatcher.
+     */
+    private ErrorDispatcher err;
+
+    /**
+     * Set to true when using the JspReader on a single file where we read up
+     * to the end and reset to the beginning many times.
+     * (as in ParserController.figureOutJspDocument()).
+     */
+    private boolean singleFile;
+
+    /**
+     * Constructor.
+     *
+     * @param ctxt The compilation context
+     * @param fname The file name
+     * @param encoding The file encoding
+     * @param jarFile ?
+     * @param err The error dispatcher
+     * @throws JasperException If a Jasper-internal error occurs
+     * @throws FileNotFoundException If the JSP file is not found (or is unreadable)
+     * @throws IOException If an IO-level error occurs, e.g. reading the file
+     */
+    public JspReader(JspCompilationContext ctxt,
+                     String fname,
+                     String encoding,
+                     JarFile jarFile,
+                     ErrorDispatcher err)
+            throws JasperException, FileNotFoundException, IOException {
+
+        this(ctxt, fname, encoding,
+             JspUtil.getReader(fname, encoding, jarFile, ctxt, err),
+             err);
+    }
+
+    /**
+     * Constructor: same as above constructor but with initialized reader
+     * to the file given.
+     */
+    public JspReader(JspCompilationContext ctxt,
+                     String fname,
+                     String encoding,
+                     InputStreamReader reader,
+                     ErrorDispatcher err)
+            throws JasperException, FileNotFoundException {
+
+        this.context = ctxt;
+        this.err = err;
+        sourceFiles = new Vector();
+        currFileId = 0;
+        size = 0;
+        singleFile = false;
+        pushFile(fname, encoding, reader);
+    }
+
+    /**
+     * @return JSP compilation context with which this JspReader is 
+     * associated
+     */
+    JspCompilationContext getJspCompilationContext() {
+        return context;
+    }
+    
+    /**
+     * Returns the file at the given position in the list.
+     *
+     * @param fileid The file position in the list
+     * @return The file at that position, if found, null otherwise
+     */
+    String getFile(final int fileid) {
+        return (String) sourceFiles.get(fileid);
+    }
+       
+    /**
+     * Checks if the current file has more input.
+     *
+     * @return True if more reading is possible
+     * @throws JasperException if an error occurs
+     */ 
+    boolean hasMoreInput() throws JasperException {
+        if (current.cursor >= current.stream.length) {
+            if (singleFile) return false; 
+            while (popFile()) {
+                if (current.cursor < current.stream.length) return true;
+            }
+            return false;
+        }
+        return true;
+    }
+    
+    int nextChar() throws JasperException {
+        if (!hasMoreInput())
+            return -1;
+        
+        int ch = current.stream[current.cursor];
+
+        current.cursor++;
+        
+        if (ch == '\n') {
+            current.line++;
+            current.col = 0;
+        } else {
+            current.col++;
+        }
+        return ch;
+    }
+
+    /**
+     * Back up the current cursor by one char, assumes current.cursor > 0,
+     * and that the char to be pushed back is not '\n'.
+     */
+    void pushChar() {
+        current.cursor--;
+        current.col--;
+    }
+
+    String getText(Mark start, Mark stop) throws JasperException {
+        Mark oldstart = mark();
+        reset(start);
+        CharArrayWriter caw = new CharArrayWriter();
+        while (!stop.equals(mark()))
+            caw.write(nextChar());
+        caw.close();
+        reset(oldstart);
+        return caw.toString();
+    }
+
+    int peekChar() throws JasperException {
+        if (!hasMoreInput())
+            return -1;
+        return current.stream[current.cursor];
+    }
+
+    Mark mark() {
+        return new Mark(current);
+    }
+
+    void reset(Mark mark) {
+        current = new Mark(mark);
+    }
+
+    boolean matchesIgnoreCase(String string) throws JasperException {
+        Mark mark = mark();
+        int ch = 0;
+        int i = 0;
+        do {
+            ch = nextChar();
+            if (Character.toLowerCase((char) ch) != string.charAt(i++)) {
+                reset(mark);
+                return false;
+            }
+        } while (i < string.length());
+        reset(mark);
+        return true;
+    }
+
+    /**
+     * 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
+     *         in stream is positioned after the search string, <strong>
+     *               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;
+    }
+
+    boolean matchesETag(String tagName) throws JasperException {
+        Mark mark = mark();
+
+        if (!matches("</" + tagName))
+            return false;
+        skipSpaces();
+        if (nextChar() == '>')
+            return true;
+
+        reset(mark);
+        return false;
+    }
+
+    boolean matchesETagWithoutLessThan(String tagName)
+        throws JasperException
+    {
+       Mark mark = mark();
+
+       if (!matches("/" + tagName))
+           return false;
+       skipSpaces();
+       if (nextChar() == '>')
+           return true;
+
+       reset(mark);
+       return false;
+    }
+
+
+    /**
+     * Looks ahead to see if there are optional spaces followed by
+     * the given String.  If so, true is returned and those spaces and
+     * characters are skipped.  If not, false is returned and the
+     * position is restored to where we were before.
+     */
+    boolean matchesOptionalSpacesFollowedBy( String s )
+        throws JasperException
+    {
+        Mark mark = mark();
+
+        skipSpaces();
+        boolean result = matches( s );
+        if( !result ) {
+            reset( mark );
+        }
+
+        return result;
+    }
+
+    int skipSpaces() throws JasperException {
+        int i = 0;
+        while (hasMoreInput() && isSpace()) {
+            i++;
+            nextChar();
+        }
+        return i;
+    }
+
+    /**
+     * Skip until the given string is matched in the stream.
+     * When returned, the context is positioned past the end of the match.
+     *
+     * @param s The String to match.
+     * @return A non-null <code>Mark</code> instance (positioned immediately
+     *         before the search string) if found, <strong>null</strong>
+     *         otherwise.
+     */
+    Mark skipUntil(String limit) throws JasperException {
+        Mark ret = null;
+        int limlen = limit.length();
+        int ch;
+
+    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;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Skip until the given string is matched in the stream, but ignoring
+     * chars initially escaped by a '\'.
+     * When returned, the context is positioned past the end of the match.
+     *
+     * @param s The String to match.
+     * @return A non-null <code>Mark</code> instance (positioned immediately
+     *         before the search string) if found, <strong>null</strong>
+     *         otherwise.
+     */
+    Mark skipUntilIgnoreEsc(String limit) throws JasperException {
+        Mark ret = null;
+        int limlen = limit.length();
+        int ch;
+        int prev = 'x';        // Doesn't matter
+        
+    skip:
+        for (ret = mark(), ch = nextChar() ; ch != -1 ;
+                 ret = mark(), prev = ch, ch = nextChar()) {            
+            if (ch == '\\' && prev == '\\') {
+                ch = 0;                // Double \ is not an escape char anymore
+            }
+            else if (ch == limit.charAt(0) && prev != '\\') {
+                for (int i = 1 ; i < limlen ; i++) {
+                    if (peekChar() == limit.charAt(i))
+                        nextChar();
+                    else
+                        continue skip;
+                }
+                return ret;
+            }
+        }
+        return null;
+    }
+    
+    /**
+     * Skip until the given end tag is matched in the stream.
+     * When returned, the context is positioned past the end of the tag.
+     *
+     * @param tag The name of the tag whose ETag (</tag>) to match.
+     * @return A non-null <code>Mark</code> instance (positioned immediately
+     *               before the ETag) if found, <strong>null</strong> otherwise.
+     */
+    Mark skipUntilETag(String tag) throws JasperException {
+        Mark ret = skipUntil("</" + tag);
+        if (ret != null) {
+            skipSpaces();
+            if (nextChar() != '>')
+                ret = null;
+        }
+        return ret;
+    }
+
+    final boolean isSpace() throws JasperException {
+        // Note: If this logic changes, also update Node.TemplateText.rtrim()
+        return peekChar() <= ' ';
+    }
+
+    /**
+     * Parse a space delimited token.
+     * If quoted the token will consume all characters up to a matching quote,
+     * otherwise, it consumes up to the first delimiter character.
+     *
+     * @param quoted If <strong>true</strong> accept quoted strings.
+     */
+    String parseToken(boolean quoted) throws JasperException {
+        StringBuffer stringBuffer = new StringBuffer();
+        skipSpaces();
+        stringBuffer.setLength(0);
+        
+        if (!hasMoreInput()) {
+            return "";
+        }
+
+        int ch = peekChar();
+        
+        if (quoted) {
+            if (ch == '"' || ch == '\'') {
+
+                char endQuote = ch == '"' ? '"' : '\'';
+                // Consume the open quote: 
+                ch = nextChar();
+                for (ch = nextChar(); ch != -1 && ch != endQuote;
+                         ch = nextChar()) {
+                    if (ch == '\\') 
+                        ch = nextChar();
+                    stringBuffer.append((char) ch);
+                }
+                // Check end of quote, skip closing quote:
+                if (ch == -1) {
+                    err.jspError(mark(), "jsp.error.quotes.unterminated");
+                }
+            } else {
+                err.jspError(mark(), "jsp.error.attr.quoted");
+            }
+        } else {
+            if (!isDelimiter()) {
+                // Read value until delimiter is found:
+                do {
+                    ch = nextChar();
+                    // Take care of the quoting here.
+                    if (ch == '\\') {
+                        if (peekChar() == '"' || peekChar() == '\'' ||
+                               peekChar() == '>' || peekChar() == '%')
+                            ch = nextChar();
+                    }
+                    stringBuffer.append((char) ch);
+                } while (!isDelimiter());
+            }
+        }
+
+        return stringBuffer.toString();
+    }
+
+    void setSingleFile(boolean val) {
+        singleFile = val;
+    }
+
+
+    /**
+     * Gets the URL for the given path name.
+     *
+     * @param path Path name
+     *
+     * @return URL for the given path name.
+     *
+     * @exception MalformedURLException if the path name is not given in 
+     * the correct form
+     */
+    URL getResource(String path) throws MalformedURLException {
+        return context.getResource(path);
+    }
+
+
+    /**
+     * Parse utils - Is current character a token delimiter ?
+     * Delimiters are currently defined to be =, &gt;, &lt;, ", and ' or any
+     * any space character as defined by <code>isSpace</code>.
+     *
+     * @return A boolean.
+     */
+    private boolean isDelimiter() throws JasperException {
+        if (! isSpace()) {
+            int ch = peekChar();
+            // Look for a single-char work delimiter:
+            if (ch == '=' || ch == '>' || ch == '"' || ch == '\''
+                    || ch == '/') {
+                return true;
+            }
+            // Look for an end-of-comment or end-of-tag:                
+            if (ch == '-') {
+                Mark mark = mark();
+                if (((ch = nextChar()) == '>')
+                        || ((ch == '-') && (nextChar() == '>'))) {
+                    reset(mark);
+                    return true;
+                } else {
+                    reset(mark);
+                    return false;
+                }
+            }
+            return false;
+        } else {
+            return true;
+        }
+    }
+
+    /**
+     * Register a new source file.
+     * This method is used to implement file inclusion. Each included file
+     * gets a unique identifier (which is the index in the array of source
+     * files).
+     *
+     * @return The index of the now registered file.
+     */
+    private int registerSourceFile(final String file) {
+        if (sourceFiles.contains(file)) {
+            return -1;
+        }
+
+        sourceFiles.add(file);
+        this.size++;
+
+        return sourceFiles.size() - 1;
+    }
+    
+
+    /**
+     * Unregister the source file.
+     * This method is used to implement file inclusion. Each included file
+     * gets a uniq identifier (which is the index in the array of source
+     * files).
+     *
+     * @return The index of the now registered file.
+     */
+    private int unregisterSourceFile(final String file) {
+        if (!sourceFiles.contains(file)) {
+            return -1;
+        }
+
+        sourceFiles.remove(file);
+        this.size--;
+        return sourceFiles.size() - 1;
+    }
+
+    /**
+     * Push a file (and its associated Stream) on the file stack.  THe
+     * current position in the current file is remembered.
+     */
+    private void pushFile(String file, String encoding, 
+                           InputStreamReader reader) 
+                throws JasperException, FileNotFoundException {
+
+        // Register the file
+        String longName = file;
+
+        int fileid = registerSourceFile(longName);
+
+        if (fileid == -1) {
+            // Bugzilla 37407: http://issues.apache.org/bugzilla/show_bug.cgi?id=37407
+            if(reader != null) {
+                try {
+                    reader.close();
+                } catch (Exception any) {
+                    if(log.isDebugEnabled()) {
+                        log.debug("Exception closing reader: ", any);
+                    }
+                }
+            }
+
+            err.jspError("jsp.error.file.already.registered", file);
+        }
+
+        currFileId = fileid;
+
+        try {
+            CharArrayWriter caw = new CharArrayWriter();
+            char buf[] = new char[1024];
+            for (int i = 0 ; (i = reader.read(buf)) != -1 ;)
+                caw.write(buf, 0, i);
+            caw.close();
+            if (current == null) {
+                current = new Mark(this, caw.toCharArray(), fileid, 
+                                   getFile(fileid), master, encoding);
+            } else {
+                current.pushStream(caw.toCharArray(), fileid, getFile(fileid),
+                                   longName, encoding);
+            }
+        } catch (Throwable ex) {
+            log.error("Exception parsing file ", ex);
+            // Pop state being constructed:
+            popFile();
+            err.jspError("jsp.error.file.cannot.read", file);
+        } finally {
+            if (reader != null) {
+                try {
+                    reader.close();
+                } catch (Exception any) {
+                    if(log.isDebugEnabled()) {
+                        log.debug("Exception closing reader: ", any);
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Pop a file from the file stack.  The field "current" is retored
+     * to the value to point to the previous files, if any, and is set
+     * to null otherwise.
+     * @return true is there is a previous file on the stack.
+     *         false otherwise.
+     */
+    private boolean popFile() throws JasperException {
+
+        // Is stack created ? (will happen if the Jsp file we're looking at is
+        // missing.
+        if (current == null || currFileId < 0) {
+            return false;
+        }
+
+        // Restore parser state:
+        String fName = getFile(currFileId);
+        currFileId = unregisterSourceFile(fName);
+        if (currFileId < -1) {
+            err.jspError("jsp.error.file.not.registered", fName);
+        }
+
+        Mark previous = current.popStream();
+        if (previous != null) {
+            master = current.baseDir;
+            current = previous;
+            return true;
+        }
+        // Note that although the current file is undefined here, "current"
+        // is not set to null just for convience, for it maybe used to
+        // set the current (undefined) position.
+        return false;
+    }
+}
+

Added: branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/JspRuntimeContext.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/JspRuntimeContext.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/JspRuntimeContext.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,524 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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 java.io.FileNotFoundException;
+import java.io.FilePermission;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.security.CodeSource;
+import java.security.PermissionCollection;
+import java.security.Policy;
+import java.security.cert.Certificate;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import javax.servlet.ServletContext;
+import javax.servlet.jsp.JspFactory;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.jasper.Constants;
+import org.apache.jasper.JspCompilationContext;
+import org.apache.jasper.Options;
+import org.apache.jasper.runtime.JspFactoryImpl;
+import org.apache.jasper.security.SecurityClassLoad;
+import org.apache.jasper.servlet.JspServletWrapper;
+
+/**
+ * Class for tracking JSP compile time file dependencies when the
+ * &060;%@include file="..."%&062; directive is used.
+ *
+ * A background thread periodically checks the files a JSP page
+ * is dependent upon.  If a dpendent file changes the JSP page
+ * which included it is recompiled.
+ *
+ * Only used if a web application context is a directory.
+ *
+ * @author Glenn L. Nielsen
+ * @version $Revision: 306189 $
+ */
+public final class JspRuntimeContext implements Runnable {
+
+    // Logger
+    private Log log = LogFactory.getLog(JspRuntimeContext.class);
+
+    /*
+     * Counts how many times the webapp's JSPs have been reloaded.
+     */
+    private int jspReloadCount;
+
+    /**
+     * Preload classes required at runtime by a JSP servlet so that
+     * we don't get a defineClassInPackage security exception.
+     */
+    static {
+        JspFactoryImpl factory = new JspFactoryImpl();
+        SecurityClassLoad.securityClassLoad(factory.getClass().getClassLoader());
+        JspFactory.setDefaultFactory(factory);
+    }
+
+    // ----------------------------------------------------------- Constructors
+
+    /**
+     * Create a JspRuntimeContext for a web application context.
+     *
+     * Loads in any previously generated dependencies from file.
+     *
+     * @param context ServletContext for web application
+     */
+    public JspRuntimeContext(ServletContext context, Options options) {
+
+        this.context = context;
+        this.options = options;
+
+        // Get the parent class loader
+        parentClassLoader =
+            (URLClassLoader) Thread.currentThread().getContextClassLoader();
+        if (parentClassLoader == null) {
+            parentClassLoader =
+                (URLClassLoader)this.getClass().getClassLoader();
+        }
+
+	if (log.isDebugEnabled()) {
+	    if (parentClassLoader != null) {
+		log.debug(Localizer.getMessage("jsp.message.parent_class_loader_is",
+					       parentClassLoader.toString()));
+	    } else {
+		log.debug(Localizer.getMessage("jsp.message.parent_class_loader_is",
+					       "<none>"));
+	    }
+        }
+
+        initClassPath();
+
+	if (context instanceof org.apache.jasper.servlet.JspCServletContext) {
+	    return;
+	}
+
+        if (System.getSecurityManager() != null) {
+            initSecurity();
+        }
+
+        // If this web application context is running from a
+        // directory, start the background compilation thread
+        String appBase = context.getRealPath("/");         
+        if (!options.getDevelopment()
+                && appBase != null
+                && options.getCheckInterval() > 0) {
+            if (appBase.endsWith(File.separator) ) {
+                appBase = appBase.substring(0,appBase.length()-1);
+            }
+            String directory =
+                appBase.substring(appBase.lastIndexOf(File.separator));
+            threadName = threadName + "[" + directory + "]";
+            threadStart();
+        }                                            
+    }
+
+    // ----------------------------------------------------- Instance Variables
+
+    /**
+     * This web applications ServletContext
+     */
+    private ServletContext context;
+    private Options options;
+    private URLClassLoader parentClassLoader;
+    private PermissionCollection permissionCollection;
+    private CodeSource codeSource;                    
+    private String classpath;
+
+    /**
+     * Maps JSP pages to their JspServletWrapper's
+     */
+    private Map jsps = Collections.synchronizedMap( new HashMap());
+ 
+
+    /**
+     * The background thread.
+     */
+    private Thread thread = null;
+
+
+    /**
+     * The background thread completion semaphore.
+     */
+    private boolean threadDone = false;
+
+
+    /**
+     * Name to register for the background thread.
+     */
+    private String threadName = "JspRuntimeContext";
+
+    // ------------------------------------------------------ Public Methods
+
+    /**
+     * Add a new JspServletWrapper.
+     *
+     * @param jspUri JSP URI
+     * @param jsw Servlet wrapper for JSP
+     */
+    public void addWrapper(String jspUri, JspServletWrapper jsw) {
+        jsps.remove(jspUri);
+        jsps.put(jspUri,jsw);
+    }
+
+    /**
+     * Get an already existing JspServletWrapper.
+     *
+     * @param jspUri JSP URI
+     * @return JspServletWrapper for JSP
+     */
+    public JspServletWrapper getWrapper(String jspUri) {
+        return (JspServletWrapper) jsps.get(jspUri);
+    }
+
+    /**
+     * Remove a  JspServletWrapper.
+     *
+     * @param jspUri JSP URI of JspServletWrapper to remove
+     */
+    public void removeWrapper(String jspUri) {
+        jsps.remove(jspUri);
+    }
+
+    /**
+     * Returns the number of JSPs for which JspServletWrappers exist, i.e.,
+     * the number of JSPs that have been loaded into the webapp.
+     *
+     * @return The number of JSPs that have been loaded into the webapp
+     */
+    public int getJspCount() {
+        return jsps.size();
+    }
+
+    /**
+     * Get the SecurityManager Policy CodeSource for this web
+     * applicaiton context.
+     *
+     * @return CodeSource for JSP
+     */
+    public CodeSource getCodeSource() {
+        return codeSource;
+    }
+
+    /**
+     * Get the parent URLClassLoader.
+     *
+     * @return URLClassLoader parent
+     */
+    public URLClassLoader getParentClassLoader() {
+        return parentClassLoader;
+    }
+
+    /**
+     * Get the SecurityManager PermissionCollection for this
+     * web application context.
+     *
+     * @return PermissionCollection permissions
+     */
+    public PermissionCollection getPermissionCollection() {
+        return permissionCollection;
+    }
+
+    /**
+     * Process a "destory" event for this web application context.
+     */                                                        
+    public void destroy() {
+        threadStop();
+
+        Iterator servlets = jsps.values().iterator();
+        while (servlets.hasNext()) {
+            ((JspServletWrapper) servlets.next()).destroy();
+        }
+    }
+
+    /**
+     * Increments the JSP reload counter.
+     */
+    public synchronized void incrementJspReloadCount() {
+        jspReloadCount++;
+    }
+
+    /**
+     * Resets the JSP reload counter.
+     *
+     * @param count Value to which to reset the JSP reload counter
+     */
+    public synchronized void setJspReloadCount(int count) {
+        this.jspReloadCount = count;
+    }
+
+    /**
+     * Gets the current value of the JSP reload counter.
+     *
+     * @return The current value of the JSP reload counter
+     */
+    public int getJspReloadCount() {
+        return jspReloadCount;
+    }
+
+
+    // -------------------------------------------------------- Private Methods
+
+    /**
+     * Method used by background thread to check the JSP dependencies
+     * registered with this class for JSP's.
+     */
+    private void checkCompile() {
+        Object [] wrappers = jsps.values().toArray();
+        for (int i = 0; i < wrappers.length; i++ ) {
+            JspServletWrapper jsw = (JspServletWrapper)wrappers[i];
+            JspCompilationContext ctxt = jsw.getJspEngineContext();
+            // JspServletWrapper also synchronizes on this when
+            // it detects it has to do a reload
+            synchronized(jsw) {
+                try {
+                    ctxt.compile();
+                } catch (FileNotFoundException ex) {
+                    ctxt.incrementRemoved();
+                } catch (Throwable t) {
+                    jsw.getServletContext().log("Background compile failed",
+						t);
+                }
+            }
+        }
+    }
+
+    /**
+     * The classpath that is passed off to the Java compiler.
+     */
+    public String getClassPath() {
+        return classpath;
+    }
+
+    /**
+     * Method used to initialize classpath for compiles.
+     */
+    private void initClassPath() {
+
+        URL [] urls = parentClassLoader.getURLs();
+        StringBuffer cpath = new StringBuffer();
+        String sep = System.getProperty("path.separator");
+
+        for(int i = 0; i < urls.length; i++) {
+            // Tomcat 4 can use URL's other than file URL's,
+            // a protocol other than file: will generate a
+            // bad file system path, so only add file:
+            // protocol URL's to the classpath.
+            
+            if( urls[i].getProtocol().equals("file") ) {
+                cpath.append((String)urls[i].getFile()+sep);
+            }
+        }    
+
+	cpath.append(options.getScratchDir() + sep);
+
+        String cp = (String) context.getAttribute(Constants.SERVLET_CLASSPATH);
+        if (cp == null || cp.equals("")) {
+            cp = options.getClassPath();
+        }
+
+        classpath = cpath.toString() + cp;
+
+        if(log.isDebugEnabled()) {
+            log.debug("Compilation classpath initialized: " + getClassPath());
+        }
+    }
+
+    /**
+     * Method used to initialize SecurityManager data.
+     */
+    private void initSecurity() {
+
+        // Setup the PermissionCollection for this web app context
+        // based on the permissions configured for the root of the
+        // web app context directory, then add a file read permission
+        // for that directory.
+        Policy policy = Policy.getPolicy();
+        if( policy != null ) {
+            try {          
+                // Get the permissions for the web app context
+                String docBase = context.getRealPath("/");
+                if( docBase == null ) {
+                    docBase = options.getScratchDir().toString();
+                }
+                String codeBase = docBase;
+                if (!codeBase.endsWith(File.separator)){
+                    codeBase = codeBase + File.separator;
+                }
+                File contextDir = new File(codeBase);
+                URL url = contextDir.getCanonicalFile().toURL();
+                codeSource = new CodeSource(url,(Certificate[])null);
+                permissionCollection = policy.getPermissions(codeSource);
+
+                // Create a file read permission for web app context directory
+                if (!docBase.endsWith(File.separator)){
+                    permissionCollection.add
+                        (new FilePermission(docBase,"read"));
+                    docBase = docBase + File.separator;
+                } else {
+                    permissionCollection.add
+                        (new FilePermission
+                            (docBase.substring(0,docBase.length() - 1),"read"));
+                }
+                docBase = docBase + "-";
+                permissionCollection.add(new FilePermission(docBase,"read"));
+
+                // Create a file read permission for web app tempdir (work)
+                // directory
+                String workDir = options.getScratchDir().toString();
+                if (!workDir.endsWith(File.separator)){
+                    permissionCollection.add
+                        (new FilePermission(workDir,"read"));
+                    workDir = workDir + File.separator;
+                }
+                workDir = workDir + "-";
+                permissionCollection.add(new FilePermission(workDir,"read"));
+
+                // Allow the JSP to access org.apache.jasper.runtime.HttpJspBase
+                permissionCollection.add( new RuntimePermission(
+                    "accessClassInPackage.org.apache.jasper.runtime") );
+
+                if (parentClassLoader instanceof URLClassLoader) {
+                    URL [] urls = parentClassLoader.getURLs();
+                    String jarUrl = null;
+                    String jndiUrl = null;
+                    for (int i=0; i<urls.length; i++) {
+                        if (jndiUrl == null
+                                && urls[i].toString().startsWith("jndi:") ) {
+                            jndiUrl = urls[i].toString() + "-";
+                        }
+                        if (jarUrl == null
+                                && urls[i].toString().startsWith("jar:jndi:")
+                                ) {
+                            jarUrl = urls[i].toString();
+                            jarUrl = jarUrl.substring(0,jarUrl.length() - 2);
+                            jarUrl = jarUrl.substring(0,
+                                     jarUrl.lastIndexOf('/')) + "/-";
+                        }
+                    }
+                    if (jarUrl != null) {
+                        permissionCollection.add(
+                                new FilePermission(jarUrl,"read"));
+                        permissionCollection.add(
+                                new FilePermission(jarUrl.substring(4),"read"));
+                    }
+                    if (jndiUrl != null)
+                        permissionCollection.add(
+                                new FilePermission(jndiUrl,"read") );
+                }
+            } catch(Exception e) {
+                context.log("Security Init for context failed",e);
+            }
+        }
+    }
+
+
+    // -------------------------------------------------------- Thread Support
+
+    /**
+     * Start the background thread that will periodically check for
+     * changes to compile time included files in a JSP.
+     *
+     * @exception IllegalStateException if we should not be starting
+     *  a background thread now
+     */
+    protected void threadStart() {
+
+        // Has the background thread already been started?
+        if (thread != null) {
+            return;
+        }
+
+        // Start the background thread
+        threadDone = false;
+        thread = new Thread(this, threadName);
+        thread.setDaemon(true);
+        thread.start();
+
+    }
+
+
+    /**
+     * Stop the background thread that is periodically checking for
+     * changes to compile time included files in a JSP.
+     */ 
+    protected void threadStop() {
+
+        if (thread == null) {
+            return;
+        }
+
+        threadDone = true;
+        thread.interrupt();
+        try {
+            thread.join();
+        } catch (InterruptedException e) {
+            ;
+        }
+        
+        thread = null;
+        
+    }
+
+    /**
+     * Sleep for the duration specified by the <code>checkInterval</code>
+     * property.
+     */ 
+    protected void threadSleep() {
+        
+        try {
+            Thread.sleep(options.getCheckInterval() * 1000L);
+        } catch (InterruptedException e) {
+            ;
+        }
+        
+    }   
+    
+    
+    // ------------------------------------------------------ Background Thread
+        
+        
+    /**
+     * The background thread that checks for changes to files
+     * included by a JSP and flags that a recompile is required.
+     */ 
+    public void run() {
+        
+        // Loop until the termination semaphore is set
+        while (!threadDone) {
+
+            // Wait for our check interval
+            threadSleep();
+
+            // Check for included files which are newer than the
+            // JSP which uses them.
+            try {
+                checkCompile();
+            } catch (Throwable t) {
+                log.error("Exception checking if recompile needed: ", t);
+            }
+        }
+        
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/JspUtil.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/JspUtil.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/JspUtil.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,1108 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.CharArrayWriter;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.UnsupportedEncodingException;
+import java.util.Vector;
+import java.util.jar.JarFile;
+import java.util.zip.ZipEntry;
+
+import javax.servlet.jsp.el.ELException;
+import javax.servlet.jsp.el.ELParseException;
+import javax.servlet.jsp.el.FunctionMapper;
+
+import org.apache.commons.el.ExpressionEvaluatorImpl;
+import org.apache.jasper.Constants;
+import org.apache.jasper.JasperException;
+import org.apache.jasper.JspCompilationContext;
+import org.xml.sax.Attributes;
+
+/** 
+ * This class has all the utility method(s).
+ * Ideally should move all the bean containers here.
+ *
+ * @author Mandar Raje.
+ * @author Rajiv Mordani.
+ * @author Danno Ferrin
+ * @author Pierre Delisle
+ * @author Shawn Bayern
+ * @author Mark Roth
+ */
+public class JspUtil {
+
+    private static final String WEB_INF_TAGS = "/WEB-INF/tags/";
+    private static final String META_INF_TAGS = "/META-INF/tags/";
+
+    // Delimiters for request-time expressions (JSP and XML syntax)
+    private static final String OPEN_EXPR  = "<%=";
+    private static final String CLOSE_EXPR = "%>";
+    private static final String OPEN_EXPR_XML  = "%=";
+    private static final String CLOSE_EXPR_XML = "%";
+
+    private static int tempSequenceNumber = 0;
+    private static ExpressionEvaluatorImpl expressionEvaluator
+	= new ExpressionEvaluatorImpl();
+
+    private static final String javaKeywords[] = {
+        "abstract", "assert", "boolean", "break", "byte", "case",
+        "catch", "char", "class", "const", "continue",
+        "default", "do", "double", "else", "enum", "extends",
+        "final", "finally", "float", "for", "goto",
+        "if", "implements", "import", "instanceof", "int",
+        "interface", "long", "native", "new", "package",
+        "private", "protected", "public", "return", "short",
+        "static", "strictfp", "super", "switch", "synchronized",
+        "this", "throws", "transient", "try", "void",
+        "volatile", "while" };
+
+    public static final int CHUNKSIZE = 1024;
+        
+    public static char[] removeQuotes(char []chars) {
+        CharArrayWriter caw = new CharArrayWriter();
+        for (int i = 0; i < chars.length; i++) {
+            if (chars[i] == '%' && chars[i+1] == '\\' &&
+                chars[i+2] == '>') {
+                caw.write('%');
+                caw.write('>');
+                i = i + 2;
+            } else {
+                caw.write(chars[i]);
+            }
+        }
+        return caw.toCharArray();
+    }
+
+    public static char[] escapeQuotes (char []chars) {
+        // Prescan to convert %\> to %>
+        String s = new String(chars);
+        while (true) {
+            int n = s.indexOf("%\\>");
+            if (n < 0)
+                break;
+            StringBuffer sb = new StringBuffer(s.substring(0, n));
+            sb.append("%>");
+            sb.append(s.substring(n + 3));
+            s = sb.toString();
+        }
+        chars = s.toCharArray();
+        return (chars);
+
+
+        // Escape all backslashes not inside a Java string literal
+        /*
+        CharArrayWriter caw = new CharArrayWriter();
+        boolean inJavaString = false;
+        for (int i = 0; i < chars.length; i++) {
+            if (chars[i] == '"') inJavaString = !inJavaString;
+            // escape out the escape character
+            if (!inJavaString && (chars[i] == '\\')) caw.write('\\');
+            caw.write(chars[i]);
+        }
+        return caw.toCharArray();
+        */
+    }
+
+    /**
+     * Checks if the token is a runtime expression.
+     * In standard JSP syntax, a runtime expression starts with '<%' and
+     * ends with '%>'. When the JSP document is in XML syntax, a runtime
+     * expression starts with '%=' and ends with '%'.
+     *
+     * @param token The token to be checked
+     * return whether the token is a runtime expression or not.
+     */
+    public static boolean isExpression(String token, boolean isXml) {
+	String openExpr;
+	String closeExpr;
+	if (isXml) {
+	    openExpr = OPEN_EXPR_XML;
+	    closeExpr = CLOSE_EXPR_XML;
+	} else {
+	    openExpr = OPEN_EXPR;
+	    closeExpr = CLOSE_EXPR;
+	}
+	if (token.startsWith(openExpr) && token.endsWith(closeExpr)) {
+	    return true;
+	} else {
+	    return false;
+	}
+    }
+
+    /**
+     * @return the "expression" part of a runtime expression, 
+     * taking the delimiters out.
+     */
+    public static String getExpr (String expression, boolean isXml) {
+	String returnString;
+	String openExpr;
+	String closeExpr;
+	if (isXml) {
+	    openExpr = OPEN_EXPR_XML;
+	    closeExpr = CLOSE_EXPR_XML;
+	} else {
+	    openExpr = OPEN_EXPR;
+	    closeExpr = CLOSE_EXPR;
+	}
+	int length = expression.length();
+	if (expression.startsWith(openExpr) && 
+                expression.endsWith(closeExpr)) {
+	    returnString = expression.substring(
+                               openExpr.length(), length - closeExpr.length());
+	} else {
+	    returnString = "";
+	}
+	return returnString;
+    }
+
+    /**
+     * Takes a potential expression and converts it into XML form
+     */
+    public static String getExprInXml(String expression) {
+        String returnString;
+        int length = expression.length();
+
+        if (expression.startsWith(OPEN_EXPR) 
+                && expression.endsWith(CLOSE_EXPR)) {
+            returnString = expression.substring (1, length - 1);
+        } else {
+            returnString = expression;
+        }
+
+        return escapeXml(returnString.replace(Constants.ESC, '$'));
+    }
+
+    /**
+     * Checks to see if the given scope is valid.
+     *
+     * @param scope The scope to be checked
+     * @param n The Node containing the 'scope' attribute whose value is to be
+     * checked
+     * @param err error dispatcher
+     *
+     * @throws JasperException if scope is not null and different from
+     * &quot;page&quot;, &quot;request&quot;, &quot;session&quot;, and
+     * &quot;application&quot;
+     */
+    public static void checkScope(String scope, Node n, ErrorDispatcher err)
+            throws JasperException {
+	if (scope != null && !scope.equals("page") && !scope.equals("request")
+		&& !scope.equals("session") && !scope.equals("application")) {
+	    err.jspError(n, "jsp.error.invalid.scope", scope);
+	}
+    }
+
+    /**
+     * Checks if all mandatory attributes are present and if all attributes
+     * present have valid names.  Checks attributes specified as XML-style
+     * attributes as well as attributes specified using the jsp:attribute
+     * standard action. 
+     */
+    public static void checkAttributes(String typeOfTag,
+				       Node n,
+				       ValidAttribute[] validAttributes,
+				       ErrorDispatcher err)
+				throws JasperException {
+        Attributes attrs = n.getAttributes();
+        Mark start = n.getStart();
+	boolean valid = true;
+
+        // AttributesImpl.removeAttribute is broken, so we do this...
+        int tempLength = (attrs == null) ? 0 : attrs.getLength();
+	Vector temp = new Vector(tempLength, 1);
+        for (int i = 0; i < tempLength; i++) {
+            String qName = attrs.getQName(i);
+            if ((!qName.equals("xmlns")) && (!qName.startsWith("xmlns:")))
+                temp.addElement(qName);
+        }
+
+        // Add names of attributes specified using jsp:attribute
+        Node.Nodes tagBody = n.getBody();
+        if( tagBody != null ) {
+            int numSubElements = tagBody.size();
+            for( int i = 0; i < numSubElements; i++ ) {
+                Node node = tagBody.getNode( i );
+                if( node instanceof Node.NamedAttribute ) {
+                    String attrName = node.getAttributeValue( "name" );
+                    temp.addElement( attrName );
+		    // Check if this value appear in the attribute of the node
+		    if (n.getAttributeValue(attrName) != null) {
+			err.jspError(n, "jsp.error.duplicate.name.jspattribute",
+					attrName);
+		    }
+                }
+                else {
+                    // Nothing can come before jsp:attribute, and only
+                    // jsp:body can come after it.
+                    break;
+                }
+            }
+        }
+
+	/*
+	 * First check to see if all the mandatory attributes are present.
+	 * If so only then proceed to see if the other attributes are valid
+	 * for the particular tag.
+	 */
+	String missingAttribute = null;
+
+	for (int i = 0; i < validAttributes.length; i++) {
+	    int attrPos;    
+	    if (validAttributes[i].mandatory) {
+                attrPos = temp.indexOf(validAttributes[i].name);
+		if (attrPos != -1) {
+		    temp.remove(attrPos);
+		    valid = true;
+		} else {
+		    valid = false;
+		    missingAttribute = validAttributes[i].name;
+		    break;
+		}
+	    }
+	}
+
+	// If mandatory attribute is missing then the exception is thrown
+	if (!valid)
+	    err.jspError(start, "jsp.error.mandatory.attribute", typeOfTag,
+			 missingAttribute);
+
+	// Check to see if there are any more attributes for the specified tag.
+        int attrLeftLength = temp.size();
+	if (attrLeftLength == 0)
+	    return;
+
+	// Now check to see if the rest of the attributes are valid too.
+	String attribute = null;
+
+	for (int j = 0; j < attrLeftLength; j++) {
+	    valid = false;
+	    attribute = (String) temp.elementAt(j);
+	    for (int i = 0; i < validAttributes.length; i++) {
+		if (attribute.equals(validAttributes[i].name)) {
+		    valid = true;
+		    break;
+		}
+	    }
+	    if (!valid)
+		err.jspError(start, "jsp.error.invalid.attribute", typeOfTag,
+			     attribute);
+	}
+	// XXX *could* move EL-syntax validation here... (sb)
+    }
+    
+    public static String escapeQueryString(String unescString) {
+	if ( unescString == null )
+	    return null;
+	
+	String escString    = "";
+	String shellSpChars = "\\\"";
+	
+	for(int index=0; index<unescString.length(); index++) {
+	    char nextChar = unescString.charAt(index);
+	    
+	    if( shellSpChars.indexOf(nextChar) != -1 )
+		escString += "\\";
+	    
+	    escString += nextChar;
+	}
+	return escString;
+    }
+ 
+    /**
+     *  Escape the 5 entities defined by XML.
+     */
+    public static String escapeXml(String s) {
+        if (s == null) return null;
+        StringBuffer sb = new StringBuffer();
+        for(int i=0; i<s.length(); i++) {
+            char c = s.charAt(i);
+            if (c == '<') {
+                sb.append("&lt;");
+            } else if (c == '>') {
+                sb.append("&gt;");
+            } else if (c == '\'') {
+                sb.append("&apos;");
+            } else if (c == '&') {
+                sb.append("&amp;");
+            } else if (c == '"') {
+                sb.append("&quot;");
+            } else {
+                sb.append(c);
+            }
+        }
+        return sb.toString();
+    }
+
+    /**
+     * Replaces any occurrences of the character <tt>replace</tt> with the
+     * string <tt>with</tt>.
+     */
+    public static String replace(String name, char replace, String with) {
+	StringBuffer buf = new StringBuffer();
+	int begin = 0;
+	int end;
+	int last = name.length();
+
+	while (true) {
+	    end = name.indexOf(replace, begin);
+	    if (end < 0) {
+		end = last;
+	    }
+	    buf.append(name.substring(begin, end));
+	    if (end == last) {
+		break;
+	    }
+	    buf.append(with);
+	    begin = end + 1;
+	}
+	
+	return buf.toString();
+    }
+
+    public static class ValidAttribute {
+	String name;
+	boolean mandatory;
+	boolean rtexprvalue;	// not used now
+
+	public ValidAttribute (String name, boolean mandatory,
+            boolean rtexprvalue )
+        {
+	    this.name = name;
+	    this.mandatory = mandatory;
+            this.rtexprvalue = rtexprvalue;
+        }
+
+       public ValidAttribute (String name, boolean mandatory) {
+            this( name, mandatory, false );
+	}
+
+	public ValidAttribute (String name) {
+	    this (name, false);
+	}
+    }
+    
+    /**
+     * Convert a String value to 'boolean'.
+     * Besides the standard conversions done by
+     * Boolean.valueOf(s).booleanValue(), the value "yes"
+     * (ignore case) is also converted to 'true'. 
+     * If 's' is null, then 'false' is returned.
+     *
+     * @param s the string to be converted
+     * @return the boolean value associated with the string s
+     */
+    public static boolean booleanValue(String s) {
+	boolean b = false;
+	if (s != null) {
+	    if (s.equalsIgnoreCase("yes")) {
+		b = true;
+	    } else {
+		b = Boolean.valueOf(s).booleanValue();
+	    }
+	}
+	return b;
+    }
+
+    /**
+     * Returns the <tt>Class</tt> object associated with the class or
+     * interface with the given string name.
+     *
+     * <p> The <tt>Class</tt> object is determined by passing the given string
+     * name to the <tt>Class.forName()</tt> method, unless the given string
+     * name represents a primitive type, in which case it is converted to a
+     * <tt>Class</tt> object by appending ".class" to it (e.g., "int.class").
+     */
+    public static Class toClass(String type, ClassLoader loader)
+	    throws ClassNotFoundException {
+
+	Class c = null;
+	int i0 = type.indexOf('[');
+	int dims = 0;
+	if (i0 > 0) {
+	    // This is an array.  Count the dimensions
+	    for (int i = 0; i < type.length(); i++) {
+		if (type.charAt(i) == '[')
+		    dims++;
+	    }
+	    type = type.substring(0, i0);
+	}
+
+	if ("boolean".equals(type))
+	    c = boolean.class;
+	else if ("char".equals(type))
+	    c = char.class;
+	else if ("byte".equals(type))
+	    c =  byte.class;
+	else if ("short".equals(type))
+	    c = short.class;
+	else if ("int".equals(type))
+	    c = int.class;
+	else if ("long".equals(type))
+	    c = long.class;
+	else if ("float".equals(type))
+	    c = float.class;
+	else if ("double".equals(type))
+	    c = double.class;
+	else if (type.indexOf('[') < 0)
+	    c = loader.loadClass(type);
+
+	if (dims == 0)
+	    return c;
+
+	if (dims == 1)
+	    return java.lang.reflect.Array.newInstance(c, 1).getClass();
+
+	// Array of more than i dimension
+	return java.lang.reflect.Array.newInstance(c, new int[dims]).getClass();
+    }
+
+    /**
+     * Produces a String representing a call to the EL interpreter.
+     * @param expression a String containing zero or more "${}" expressions
+     * @param expectedType the expected type of the interpreted result
+     * @param fnmapvar Variable pointing to a function map.
+     * @param XmlEscape True if the result should do XML escaping
+     * @return a String representing a call to the EL interpreter.
+     */
+    public static String interpreterCall(boolean isTagFile,
+					 String expression,
+                                         Class expectedType,
+                                         String fnmapvar,
+                                         boolean XmlEscape ) 
+    {
+        /*
+         * Determine which context object to use.
+         */
+	String jspCtxt = null;
+	if (isTagFile)
+	    jspCtxt = "this.getJspContext()";
+	else
+	    jspCtxt = "_jspx_page_context";
+
+	/*
+         * Determine whether to use the expected type's textual name
+	 * or, if it's a primitive, the name of its correspondent boxed
+	 * type.
+         */
+	String targetType = expectedType.getName();
+	String primitiveConverterMethod = null;
+	if (expectedType.isPrimitive()) {
+	    if (expectedType.equals(Boolean.TYPE)) {
+		targetType = Boolean.class.getName();
+		primitiveConverterMethod = "booleanValue";
+	    } else if (expectedType.equals(Byte.TYPE)) {
+		targetType = Byte.class.getName();
+		primitiveConverterMethod = "byteValue";
+	    } else if (expectedType.equals(Character.TYPE)) {
+		targetType = Character.class.getName();
+		primitiveConverterMethod = "charValue";
+	    } else if (expectedType.equals(Short.TYPE)) {
+		targetType = Short.class.getName();
+		primitiveConverterMethod = "shortValue";
+	    } else if (expectedType.equals(Integer.TYPE)) {
+		targetType = Integer.class.getName();
+		primitiveConverterMethod = "intValue";
+	    } else if (expectedType.equals(Long.TYPE)) {
+		targetType = Long.class.getName();
+		primitiveConverterMethod = "longValue";
+	    } else if (expectedType.equals(Float.TYPE)) {
+		targetType = Float.class.getName();
+		primitiveConverterMethod = "floatValue";
+	    } else if (expectedType.equals(Double.TYPE)) { 
+		targetType = Double.class.getName();
+		primitiveConverterMethod = "doubleValue";
+	    }
+	}
+ 
+	if (primitiveConverterMethod != null) {
+	    XmlEscape = false;
+	}
+
+	/*
+         * Build up the base call to the interpreter.
+         */
+        // XXX - We use a proprietary call to the interpreter for now
+        // as the current standard machinery is inefficient and requires
+        // lots of wrappers and adapters.  This should all clear up once
+        // the EL interpreter moves out of JSTL and into its own project.
+        // In the future, this should be replaced by code that calls
+        // ExpressionEvaluator.parseExpression() and then cache the resulting
+        // expression objects.  The interpreterCall would simply select
+        // one of the pre-cached expressions and evaluate it.
+        // Note that PageContextImpl implements VariableResolver and
+        // the generated Servlet/SimpleTag implements FunctionMapper, so
+        // that machinery is already in place (mroth).
+	targetType = toJavaSourceType(targetType);
+	StringBuffer call = new StringBuffer(
+             "(" + targetType + ") "
+               + "org.apache.jasper.runtime.PageContextImpl.proprietaryEvaluate"
+               + "(" + Generator.quote(expression) + ", "
+               +       targetType + ".class, "
+	       +       "(PageContext)" + jspCtxt 
+               +       ", " + fnmapvar
+	       + ", " + XmlEscape
+               + ")");
+ 
+	/*
+         * Add the primitive converter method if we need to.
+         */
+	if (primitiveConverterMethod != null) {
+	    call.insert(0, "(");
+	    call.append(")." + primitiveConverterMethod + "()");
+	}
+ 
+	return call.toString();
+    }
+
+    /**
+     * Validates the syntax of all ${} expressions within the given string.
+     * @param where the approximate location of the expressions in the JSP page
+     * @param expressions a string containing zero or more "${}" expressions
+     * @param err an error dispatcher to use
+     */
+    public static void validateExpressions(Mark where,
+                                           String expressions,
+                                           Class expectedType,
+                                           FunctionMapper functionMapper,
+                                           ErrorDispatcher err)
+            throws JasperException {
+
+        try {
+            JspUtil.expressionEvaluator.parseExpression( expressions, 
+                expectedType, null );
+        }
+        catch( ELParseException e ) {
+            err.jspError(where, "jsp.error.invalid.expression", expressions,
+                e.toString() );
+        }
+        catch( ELException e ) {
+            err.jspError(where, "jsp.error.invalid.expression", expressions,
+                e.toString() );
+        }
+    }
+
+    /**
+     * Resets the temporary variable name.
+     * (not thread-safe)
+     */
+    public static void resetTemporaryVariableName() {
+        tempSequenceNumber = 0;
+    }
+
+    /**
+     * Generates a new temporary variable name.
+     * (not thread-safe)
+     */
+    public static String nextTemporaryVariableName() {
+        return Constants.TEMP_VARIABLE_NAME_PREFIX + (tempSequenceNumber++);
+    }
+
+    public static String coerceToPrimitiveBoolean(String s,
+						  boolean isNamedAttribute) {
+	if (isNamedAttribute) {
+	    return "org.apache.jasper.runtime.JspRuntimeLibrary.coerceToBoolean(" + s + ")";
+	} else {
+	    if (s == null || s.length() == 0)
+		return "false";
+	    else
+		return Boolean.valueOf(s).toString();
+	}
+    }
+
+    public static String coerceToBoolean(String s, boolean isNamedAttribute) {
+	if (isNamedAttribute) {
+	    return "(Boolean) org.apache.jasper.runtime.JspRuntimeLibrary.coerce(" + s + ", Boolean.class)";
+	} else {
+	    if (s == null || s.length() == 0) {
+		return "new Boolean(false)";
+	    } else {
+		// Detect format error at translation time
+		return "new Boolean(" + Boolean.valueOf(s).toString() + ")";
+	    }
+	}
+    }
+
+    public static String coerceToPrimitiveByte(String s,
+					       boolean isNamedAttribute) {
+	if (isNamedAttribute) {
+	    return "org.apache.jasper.runtime.JspRuntimeLibrary.coerceToByte(" + s + ")";
+	} else {
+	    if (s == null || s.length() == 0)
+		return "(byte) 0";
+	    else
+		return "((byte)" + Byte.valueOf(s).toString() + ")";
+	}
+    }
+
+    public static String coerceToByte(String s, boolean isNamedAttribute) {
+	if (isNamedAttribute) {
+	    return "(Byte) org.apache.jasper.runtime.JspRuntimeLibrary.coerce(" + s + ", Byte.class)";
+	} else {
+	    if (s == null || s.length() == 0) {
+		return "new Byte((byte) 0)";
+	    } else {
+		// Detect format error at translation time
+		return "new Byte((byte)" + Byte.valueOf(s).toString() + ")";
+	    }
+	}
+    }
+
+    public static String coerceToChar(String s, boolean isNamedAttribute) {
+	if (isNamedAttribute) {
+	    return "org.apache.jasper.runtime.JspRuntimeLibrary.coerceToChar(" + s + ")";
+	} else {
+	    if (s == null || s.length() == 0) {
+		return "(char) 0";
+	    } else {
+		char ch = s.charAt(0);
+		// this trick avoids escaping issues
+		return "((char) " + (int) ch + ")";
+	    }
+	}
+    }
+
+    public static String coerceToCharacter(String s, boolean isNamedAttribute) {
+	if (isNamedAttribute) {
+	    return "(Character) org.apache.jasper.runtime.JspRuntimeLibrary.coerce(" + s + ", Character.class)";
+	} else {
+	    if (s == null || s.length() == 0) {
+		return "new Character((char) 0)";
+	    } else {
+		char ch = s.charAt(0);
+		// this trick avoids escaping issues
+		return "new Character((char) " + (int) ch + ")";
+	    }
+	}
+    }
+
+    public static String coerceToPrimitiveDouble(String s,
+						 boolean isNamedAttribute) {
+	if (isNamedAttribute) {
+	    return "org.apache.jasper.runtime.JspRuntimeLibrary.coerceToDouble(" + s + ")";
+	} else {
+	    if (s == null || s.length() == 0)
+		return "(double) 0";
+	    else
+		return Double.valueOf(s).toString();
+	}
+    }
+
+    public static String coerceToDouble(String s, boolean isNamedAttribute) {
+	if (isNamedAttribute) {
+	    return "(Double) org.apache.jasper.runtime.JspRuntimeLibrary.coerce(" + s + ", Double.class)";
+	} else {
+	    if (s == null || s.length() == 0) {
+		return "new Double(0)";
+	    } else {
+		// Detect format error at translation time
+		return "new Double(" + Double.valueOf(s).toString() + ")";
+	    }
+	}
+    }
+
+    public static String coerceToPrimitiveFloat(String s,
+						boolean isNamedAttribute) {
+	if (isNamedAttribute) {
+	    return "org.apache.jasper.runtime.JspRuntimeLibrary.coerceToFloat(" + s + ")";
+	} else {
+	    if (s == null || s.length() == 0)
+		return "(float) 0";
+	    else
+		return Float.valueOf(s).toString() + "f";
+	}
+    }
+
+    public static String coerceToFloat(String s, boolean isNamedAttribute) {
+	if (isNamedAttribute) {
+	    return "(Float) org.apache.jasper.runtime.JspRuntimeLibrary.coerce(" + s + ", Float.class)";
+	} else {
+	    if (s == null || s.length() == 0) {
+		return "new Float(0)";
+	    } else {
+		// Detect format error at translation time
+		return "new Float(" + Float.valueOf(s).toString() + "f)";
+	    }
+	}
+    }
+
+    public static String coerceToInt(String s, boolean isNamedAttribute) {
+	if (isNamedAttribute) {
+	    return "org.apache.jasper.runtime.JspRuntimeLibrary.coerceToInt(" + s + ")";
+	} else {
+	    if (s == null || s.length() == 0)
+		return "0";
+	    else
+		return Integer.valueOf(s).toString();
+	}
+    }
+
+    public static String coerceToInteger(String s, boolean isNamedAttribute) {
+	if (isNamedAttribute) {
+	    return "(Integer) org.apache.jasper.runtime.JspRuntimeLibrary.coerce(" + s + ", Integer.class)";
+	} else {
+	    if (s == null || s.length() == 0) {
+		return "new Integer(0)";
+	    } else {
+		// Detect format error at translation time
+		return "new Integer(" + Integer.valueOf(s).toString() + ")";
+	    }
+	}
+    }
+
+    public static String coerceToPrimitiveShort(String s,
+						boolean isNamedAttribute) {
+	if (isNamedAttribute) {
+	    return "org.apache.jasper.runtime.JspRuntimeLibrary.coerceToShort(" + s + ")";
+	} else {
+	    if (s == null || s.length() == 0)
+		return "(short) 0";
+	    else
+		return "((short) " + Short.valueOf(s).toString() + ")";
+	}
+    }
+    
+    public static String coerceToShort(String s, boolean isNamedAttribute) {
+	if (isNamedAttribute) {
+	    return "(Short) org.apache.jasper.runtime.JspRuntimeLibrary.coerce(" + s + ", Short.class)";
+	} else {
+	    if (s == null || s.length() == 0) {
+		return "new Short((short) 0)";
+	    } else {
+		// Detect format error at translation time
+		return "new Short(\"" + Short.valueOf(s).toString() + "\")";
+	    }
+	}
+    }
+    
+    public static String coerceToPrimitiveLong(String s,
+					       boolean isNamedAttribute) {
+	if (isNamedAttribute) {
+	    return "org.apache.jasper.runtime.JspRuntimeLibrary.coerceToLong(" + s + ")";
+	} else {
+	    if (s == null || s.length() == 0)
+		return "(long) 0";
+	    else
+		return Long.valueOf(s).toString() + "l";
+	}
+    }
+
+    public static String coerceToLong(String s, boolean isNamedAttribute) {
+	if (isNamedAttribute) {
+	    return "(Long) org.apache.jasper.runtime.JspRuntimeLibrary.coerce(" + s + ", Long.class)";
+	} else {
+	    if (s == null || s.length() == 0) {
+		return "new Long(0)";
+	    } else {
+		// Detect format error at translation time
+		return "new Long(" + Long.valueOf(s).toString() + "l)";
+	    }
+	}
+    }
+
+    public static InputStream getInputStream(String fname, JarFile jarFile,
+					     JspCompilationContext ctxt,
+					     ErrorDispatcher err)
+		throws JasperException, IOException {
+
+        InputStream in = null;
+
+	if (jarFile != null) {
+	    String jarEntryName = fname.substring(1, fname.length());
+	    ZipEntry jarEntry = jarFile.getEntry(jarEntryName);
+	    if (jarEntry == null) {
+		err.jspError("jsp.error.file.not.found", fname);
+	    }
+	    in = jarFile.getInputStream(jarEntry);
+	} else {
+	    in = ctxt.getResourceAsStream(fname);
+	}
+
+	if (in == null) {
+	    err.jspError("jsp.error.file.not.found", fname);
+	}
+
+	return in;
+    }
+
+    /**
+     * Gets the fully-qualified class name of the tag handler corresponding to
+     * the given tag file path.
+     *
+     * @param path Tag file path
+     * @param err Error dispatcher
+     *
+     * @return Fully-qualified class name of the tag handler corresponding to 
+     * the given tag file path
+     */
+    public static String getTagHandlerClassName(String path,
+						ErrorDispatcher err)
+                throws JasperException {
+
+        String className = null;
+        int begin = 0;
+        int index;
+        
+        index = path.lastIndexOf(".tag");
+        if (index == -1) {
+            err.jspError("jsp.error.tagfile.badSuffix", path);
+        }
+
+        //It's tempting to remove the ".tag" suffix here, but we can't.
+        //If we remove it, the fully-qualified class name of this tag
+        //could conflict with the package name of other tags.
+        //For instance, the tag file
+        //    /WEB-INF/tags/foo.tag
+        //would have fully-qualified class name
+        //    org.apache.jsp.tag.web.foo
+        //which would conflict with the package name of the tag file
+        //    /WEB-INF/tags/foo/bar.tag
+
+        index = path.indexOf(WEB_INF_TAGS);
+        if (index != -1) {
+            className = "org.apache.jsp.tag.web.";
+            begin = index + WEB_INF_TAGS.length();
+        } else {
+	    index = path.indexOf(META_INF_TAGS);
+	    if (index != -1) {
+		className = "org.apache.jsp.tag.meta.";
+		begin = index + META_INF_TAGS.length();
+	    } else {
+		err.jspError("jsp.error.tagfile.illegalPath", path);
+	    }
+	}
+
+        className += makeJavaPackage(path.substring(begin));
+  
+       return className;
+    }
+
+    /**
+     * Converts the given path to a Java package or fully-qualified class name
+     *
+     * @param path Path to convert
+     *
+     * @return Java package corresponding to the given path
+     */
+    public static final String makeJavaPackage(String path) {
+        String classNameComponents[] = split(path,"/");
+        StringBuffer legalClassNames = new StringBuffer();
+        for (int i = 0; i < classNameComponents.length; i++) {
+            legalClassNames.append(makeJavaIdentifier(classNameComponents[i]));
+            if (i < classNameComponents.length - 1) {
+                legalClassNames.append('.');
+            }
+        }
+        return legalClassNames.toString();
+    }
+
+    /**
+     * Splits a string into it's components.
+     * @param path String to split
+     * @param pat Pattern to split at
+     * @return the components of the path
+     */
+    private static final String [] split(String path, String pat) {
+        Vector comps = new Vector();
+        int pos = path.indexOf(pat);
+        int start = 0;
+        while( pos >= 0 ) {
+            if(pos > start ) {
+                String comp = path.substring(start,pos);
+                comps.add(comp);
+            }
+            start = pos + pat.length();
+            pos = path.indexOf(pat,start);
+        }
+        if( start < path.length()) {
+            comps.add(path.substring(start));
+        }
+        String [] result = new String[comps.size()];
+        for(int i=0; i < comps.size(); i++) {
+            result[i] = (String)comps.elementAt(i);
+        }
+        return result;
+    }
+            
+    /**
+     * Converts the given identifier to a legal Java identifier
+     *
+     * @param identifier Identifier to convert
+     *
+     * @return Legal Java identifier corresponding to the given identifier
+     */
+    public static final String makeJavaIdentifier(String identifier) {
+        StringBuffer modifiedIdentifier = 
+            new StringBuffer(identifier.length());
+        if (!Character.isJavaIdentifierStart(identifier.charAt(0))) {
+            modifiedIdentifier.append('_');
+        }
+        for (int i = 0; i < identifier.length(); i++) {
+            char ch = identifier.charAt(i);
+            if (Character.isJavaIdentifierPart(ch) && ch != '_') {
+                modifiedIdentifier.append(ch);
+            } else if (ch == '.') {
+                modifiedIdentifier.append('_');
+            } else {
+                modifiedIdentifier.append(mangleChar(ch));
+            }
+        }
+        if (isJavaKeyword(modifiedIdentifier.toString())) {
+            modifiedIdentifier.append('_');
+        }
+        return modifiedIdentifier.toString();
+    }
+    
+    /**
+     * Mangle the specified character to create a legal Java class name.
+     */
+    public static final String mangleChar(char ch) {
+        char[] result = new char[5];
+        result[0] = '_';
+        result[1] = Character.forDigit((ch >> 12) & 0xf, 16);
+        result[2] = Character.forDigit((ch >> 8) & 0xf, 16);
+        result[3] = Character.forDigit((ch >> 4) & 0xf, 16);
+        result[4] = Character.forDigit(ch & 0xf, 16);
+        return new String(result);
+    }
+
+    /**
+     * Test whether the argument is a Java keyword
+     */
+    public static boolean isJavaKeyword(String key) {
+        int i = 0;
+        int j = javaKeywords.length;
+        while (i < j) {
+            int k = (i+j)/2;
+            int result = javaKeywords[k].compareTo(key);
+            if (result == 0) {
+                return true;
+            }
+            if (result < 0) {
+                i = k+1;
+            } else {
+                j = k;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Converts the given Xml name to a legal Java identifier.  This is
+     * slightly more efficient than makeJavaIdentifier in that we only need
+     * to worry about '.', '-', and ':' in the string.  We also assume that
+     * the resultant string is further concatenated with some prefix string
+     * so that we don't have to worry about it being a Java key word.
+     *
+     * @param name Identifier to convert
+     *
+     * @return Legal Java identifier corresponding to the given identifier
+     */
+    public static final String makeXmlJavaIdentifier(String name) {
+        if (name.indexOf('-') >= 0)
+            name = replace(name, '-', "$1");
+        if (name.indexOf('.') >= 0)
+            name = replace(name, '.', "$2");
+        if (name.indexOf(':') >= 0)
+            name = replace(name, ':', "$3");
+        return name;
+    }
+
+    static InputStreamReader getReader(String fname, String encoding,
+				       JarFile jarFile,
+				       JspCompilationContext ctxt,
+				       ErrorDispatcher err)
+		throws JasperException, IOException {
+
+        InputStreamReader reader = null;
+	InputStream in = getInputStream(fname, jarFile, ctxt, err);
+
+	try {
+            reader = new InputStreamReader(in, encoding);
+	} catch (UnsupportedEncodingException ex) {
+	    err.jspError("jsp.error.unsupported.encoding", encoding);
+	}
+
+	return reader;
+    }
+
+    /**
+     * Class.getName() return arrays in the form "[[[<et>", where et,
+     * the element type can be one of ZBCDFIJS or L<classname>;
+     * It is converted into forms that can be understood by javac.
+     */
+    public static String toJavaSourceType(String type) {
+
+	if (type.charAt(0) != '[') {
+	    return type;
+ 	}
+
+	int dims = 1;
+	String t = null;
+	for (int i = 1; i < type.length(); i++) {
+	    if (type.charAt(i) == '[') {
+		dims++;
+	    } else {
+		switch (type.charAt(i)) {
+		case 'Z': t = "boolean"; break;
+		case 'B': t = "byte"; break;
+		case 'C': t = "char"; break;
+		case 'D': t = "double"; break;
+		case 'F': t = "float"; break;
+		case 'I': t = "int"; break;
+		case 'J': t = "long"; break;
+		case 'S': t = "short"; break;
+		case 'L': t = type.substring(i+1, type.indexOf(';')); break;
+		}
+		break;
+	    }
+	}
+	StringBuffer resultType = new StringBuffer(t);
+	for (; dims > 0; dims--) {
+	    resultType.append("[]");
+	}
+	return resultType.toString();
+    }
+
+    /**
+     * Compute the canonical name from a Class instance.  Note that a
+     * simple replacment of '$' with '.' of a binary name would not work,
+     * as '$' is a legal Java Identifier character.
+     * @param c A instance of java.lang.Class
+     * @return  The canonical name of c.
+     */
+    public static String getCanonicalName(Class c) {
+
+        String binaryName = c.getName();
+        c = c.getDeclaringClass();
+
+        if (c == null) {
+            return binaryName;
+        }
+
+        StringBuffer buf = new StringBuffer(binaryName);
+        do {
+            buf.setCharAt(c.getName().length(), '.');
+            c = c.getDeclaringClass();
+        } while ( c != null);
+
+        return buf.toString();
+    }
+}
+

Added: branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/Localizer.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/Localizer.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/Localizer.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,159 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.text.MessageFormat;
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+
+/**
+ * Class responsible for converting error codes to corresponding localized
+ * error messages.
+ *
+ * @author Jan Luehe
+ */
+public class Localizer {
+
+    private static ResourceBundle bundle = null;
+    
+    static {
+        try {
+        bundle = ResourceBundle.getBundle(
+            "org.apache.jasper.resources.LocalStrings");
+        } catch (Throwable t) {
+            t.printStackTrace();
+        }
+    }
+
+    /*
+     * Returns the localized error message corresponding to the given error
+     * code.
+     *
+     * If the given error code is not defined in the resource bundle for
+     * localized error messages, it is used as the error message.
+     *
+     * @param errCode Error code to localize
+     * 
+     * @return Localized error message
+     */
+    public static String getMessage(String errCode) {
+	String errMsg = errCode;
+	try {
+	    errMsg = bundle.getString(errCode);
+	} catch (MissingResourceException e) {
+	}
+	return errMsg;
+    }
+
+    /* 
+     * Returns the localized error message corresponding to the given error
+     * code.
+     *
+     * If the given error code is not defined in the resource bundle for
+     * localized error messages, it is used as the error message.
+     *
+     * @param errCode Error code to localize
+     * @param arg Argument for parametric replacement
+     *
+     * @return Localized error message
+     */
+    public static String getMessage(String errCode, String arg) {
+	return getMessage(errCode, new Object[] {arg});
+    }
+
+    /* 
+     * Returns the localized error message corresponding to the given error
+     * code.
+     *
+     * If the given error code is not defined in the resource bundle for
+     * localized error messages, it is used as the error message.
+     *
+     * @param errCode Error code to localize
+     * @param arg1 First argument for parametric replacement
+     * @param arg2 Second argument for parametric replacement
+     *
+     * @return Localized error message
+     */
+    public static String getMessage(String errCode, String arg1, String arg2) {
+	return getMessage(errCode, new Object[] {arg1, arg2});
+    }
+    
+    /* 
+     * Returns the localized error message corresponding to the given error
+     * code.
+     *
+     * If the given error code is not defined in the resource bundle for
+     * localized error messages, it is used as the error message.
+     *
+     * @param errCode Error code to localize
+     * @param arg1 First argument for parametric replacement
+     * @param arg2 Second argument for parametric replacement
+     * @param arg3 Third argument for parametric replacement
+     *
+     * @return Localized error message
+     */
+    public static String getMessage(String errCode, String arg1, String arg2,
+				    String arg3) {
+	return getMessage(errCode, new Object[] {arg1, arg2, arg3});
+    }
+
+    /* 
+     * Returns the localized error message corresponding to the given error
+     * code.
+     *
+     * If the given error code is not defined in the resource bundle for
+     * localized error messages, it is used as the error message.
+     *
+     * @param errCode Error code to localize
+     * @param arg1 First argument for parametric replacement
+     * @param arg2 Second argument for parametric replacement
+     * @param arg3 Third argument for parametric replacement
+     * @param arg4 Fourth argument for parametric replacement
+     *
+     * @return Localized error message
+     */
+    public static String getMessage(String errCode, String arg1, String arg2,
+				    String arg3, String arg4) {
+	return getMessage(errCode, new Object[] {arg1, arg2, arg3, arg4});
+    }
+
+    /*
+     * Returns the localized error message corresponding to the given error
+     * code.
+     *
+     * If the given error code is not defined in the resource bundle for
+     * localized error messages, it is used as the error message.
+     *
+     * @param errCode Error code to localize
+     * @param args Arguments for parametric replacement
+     *
+     * @return Localized error message
+     */
+    public static String getMessage(String errCode, Object[] args) {
+	String errMsg = errCode;
+	try {
+	    errMsg = bundle.getString(errCode);
+	    if (args != null) {
+		MessageFormat formatter = new MessageFormat(errMsg);
+		errMsg = formatter.format(args);
+	    }
+	} catch (MissingResourceException e) {
+	}
+	
+	return errMsg;
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/Mark.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/Mark.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/Mark.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,281 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.util.Stack;
+import java.net.URL;
+import java.net.MalformedURLException;
+import org.apache.jasper.JspCompilationContext;
+
+/**
+ * Mark represents a point in the JSP input. 
+ *
+ * @author Anil K. Vijendran
+ */
+final class Mark {
+
+    // position within current stream
+    int cursor, line, col;
+
+    // directory of file for current stream
+    String baseDir;
+
+    // current stream
+    char[] stream = null;
+
+    // fileid of current stream
+    private int fileId;
+
+    // name of the current file
+    private String fileName;
+
+    /*
+     * stack of stream and stream state of streams that have included
+     * current stream
+     */
+    private Stack includeStack = null;
+
+    // encoding of current file
+    private String encoding = null;
+
+    // reader that owns this mark (so we can look up fileid's)
+    private JspReader reader;
+
+    private JspCompilationContext ctxt;
+
+    /**
+     * Constructor
+     *
+     * @param reader JspReader this mark belongs to
+     * @param inStream current stream for this mark
+     * @param fileId id of requested jsp file
+     * @param name JSP file name
+     * @param inBaseDir base directory of requested jsp file
+     * @param inEncoding encoding of current file
+     */
+    Mark(JspReader reader, char[] inStream, int fileId, String name,
+         String inBaseDir, String inEncoding) {
+
+        this.reader = reader;
+        this.ctxt = reader.getJspCompilationContext();
+        this.stream = inStream;
+        this.cursor = 0;
+        this.line = 1;
+        this.col = 1;
+        this.fileId = fileId;
+        this.fileName = name;
+        this.baseDir = inBaseDir;
+        this.encoding = inEncoding;
+        this.includeStack = new Stack();
+    }
+
+
+    /**
+     * Constructor
+     */
+    Mark(Mark other) {
+
+        this.reader = other.reader;
+        this.ctxt = other.reader.getJspCompilationContext();
+        this.stream = other.stream;
+        this.fileId = other.fileId;
+        this.fileName = other.fileName;
+        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();
+        for ( int i=0; i < other.includeStack.size(); i++ ) {
+            includeStack.addElement( other.includeStack.elementAt(i) );
+        }
+    }
+
+
+    /**
+     * Constructor
+     */    
+    Mark(JspCompilationContext ctxt, String filename, int line, int col) {
+
+        this.reader = null;
+        this.ctxt = ctxt;
+        this.stream = null;
+        this.cursor = 0;
+        this.line = line;
+        this.col = col;
+        this.fileId = -1;
+        this.fileName = filename;
+        this.baseDir = "le-basedir";
+        this.encoding = "le-endocing";
+        this.includeStack = null;
+    }
+
+
+    /**
+     * Sets this mark's state to a new stream.
+     * It will store the current stream in it's includeStack.
+     *
+     * @param inStream new stream for mark
+     * @param inFileId id of new file from which stream comes from
+     * @param inBaseDir directory of file
+     * @param inEncoding encoding of new file
+     */
+    public void pushStream(char[] inStream, int inFileId, String name,
+                           String inBaseDir, String inEncoding) 
+    {
+        // store current state in stack
+        includeStack.push(new IncludeState(cursor, line, col, fileId,
+                                           fileName, baseDir, 
+					   encoding, stream) );
+
+        // set new variables
+        cursor = 0;
+        line = 1;
+        col = 1;
+        fileId = inFileId;
+        fileName = name;
+        baseDir = inBaseDir;
+        encoding = inEncoding;
+        stream = inStream;
+    }
+
+
+    /**
+     * Restores this mark's state to a previously stored stream.
+     * @return The previous Mark instance when the stream was pushed, or null
+     * if there is no previous stream
+     */
+    public Mark popStream() {
+        // make sure we have something to pop
+        if ( includeStack.size() <= 0 ) {
+            return null;
+        }
+
+        // get previous state in stack
+        IncludeState state = (IncludeState) includeStack.pop( );
+
+        // set new variables
+        cursor = state.cursor;
+        line = state.line;
+        col = state.col;
+        fileId = state.fileId;
+        fileName = state.fileName;
+        baseDir = state.baseDir;
+        stream = state.stream;
+        return this;
+    }
+
+
+    // -------------------- Locator interface --------------------
+
+    public int getLineNumber() {
+        return line;
+    }
+
+    public int getColumnNumber() {
+        return col;
+    }
+
+    public String getSystemId() {
+        return getFile();
+    }
+
+    public String getPublicId() {
+        return null;
+    }
+
+    public String toString() {
+	return getFile()+"("+line+","+col+")";
+    }
+
+    public String getFile() {
+        return this.fileName;
+    }
+
+    /**
+     * Gets the URL of the resource with which this Mark is associated
+     *
+     * @return URL of the resource with which this Mark is associated
+     *
+     * @exception MalformedURLException if the resource pathname is incorrect
+     */
+    public URL getURL() throws MalformedURLException {
+        return ctxt.getResource(getFile());
+    }
+
+    public String toShortString() {
+        return "("+line+","+col+")";
+    }
+
+    public boolean equals(Object other) {
+	if (other instanceof Mark) {
+	    Mark m = (Mark) other;
+	    return this.reader == m.reader && this.fileId == m.fileId 
+		&& this.cursor == m.cursor && this.line == m.line 
+		&& this.col == m.col;
+	} 
+	return false;
+    }
+
+    /**
+     * @return true if this Mark is greather than the <code>other</code>
+     * Mark, false otherwise.
+     */
+    public boolean isGreater(Mark other) {
+
+        boolean greater = false;
+
+        if (this.line > other.line) {
+            greater = true;
+        } else if (this.line == other.line && this.col > other.col) {
+            greater = true;
+        }
+
+        return greater;
+    }
+
+    /**
+     * Keep track of parser before parsing an included file.
+     * This class keeps track of the parser before we switch to parsing an
+     * included file. In other words, it's the parser's continuation to be
+     * reinstalled after the included file parsing is done.
+     */
+    class IncludeState {
+        int cursor, line, col;
+        int fileId;
+        String fileName;
+        String baseDir;
+        String encoding;
+        char[] stream = null;
+
+        IncludeState(int inCursor, int inLine, int inCol, int inFileId, 
+                     String name, String inBaseDir, String inEncoding,
+                     char[] inStream) {
+            cursor = inCursor;
+            line = inLine;
+            col = inCol;
+            fileId = inFileId;
+            fileName = name;
+            baseDir = inBaseDir;
+            encoding = inEncoding;
+            stream = inStream;
+        }
+    }
+
+}
+

Added: branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/Node.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/Node.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/Node.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,2369 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.util.Iterator;
+import java.util.List;
+import java.util.Vector;
+import java.util.ArrayList;
+
+import javax.servlet.jsp.tagext.BodyTag;
+import javax.servlet.jsp.tagext.DynamicAttributes;
+import javax.servlet.jsp.tagext.IterationTag;
+import javax.servlet.jsp.tagext.SimpleTag;
+import javax.servlet.jsp.tagext.TagAttributeInfo;
+import javax.servlet.jsp.tagext.TagData;
+import javax.servlet.jsp.tagext.TagFileInfo;
+import javax.servlet.jsp.tagext.TagInfo;
+import javax.servlet.jsp.tagext.TagVariableInfo;
+import javax.servlet.jsp.tagext.TryCatchFinally;
+import javax.servlet.jsp.tagext.VariableInfo;
+
+import org.apache.jasper.JasperException;
+import org.apache.jasper.compiler.tagplugin.TagPluginContext;
+import org.xml.sax.Attributes;
+
+
+/**
+ * An internal data representation of a JSP page or a JSP docuement (XML).
+ * Also included here is a visitor class for tranversing nodes.
+ *
+ * @author Kin-man Chung
+ * @author Jan Luehe
+ * @author Shawn Bayern
+ * @author Mark Roth
+ */
+
+abstract class Node implements TagConstants {
+
+    private static final VariableInfo[] ZERO_VARIABLE_INFO = { };
+    
+    protected Attributes attrs;
+
+    // xmlns attributes that represent tag libraries (only in XML syntax)
+    protected Attributes taglibAttrs;
+
+    /*
+     * xmlns attributes that do not represent tag libraries
+     * (only in XML syntax)
+     */
+    protected Attributes nonTaglibXmlnsAttrs;
+
+    protected Nodes body;
+    protected String text;
+    protected Mark startMark;
+    protected int beginJavaLine;
+    protected int endJavaLine;
+    protected Node parent;
+    protected Nodes namedAttributeNodes; // cached for performance
+    protected String qName;
+    protected String localName;
+    /*
+     * The name of the inner class to which the codes for this node and
+     * its body are generated.  For instance, for <jsp:body> in foo.jsp,
+     * this is "foo_jspHelper".  This is primarily used for communicating
+     * such info from Generator to Smap generator.
+     */
+    protected String innerClassName;
+
+    private boolean isDummy;
+
+    /**
+     * Zero-arg Constructor.
+     */
+    public Node() {
+	this.isDummy = true;
+    }
+
+    /**
+     * Constructor.
+     *
+     * @param start The location of the jsp page
+     * @param parent The enclosing node
+     */
+    public Node(Mark start, Node parent) {
+	this.startMark = start;
+	this.isDummy = (start == null);
+	addToParent(parent);
+    }
+
+    /**
+     * Constructor.
+     *
+     * @param qName The action's qualified name
+     * @param localName The action's local name
+     * @param start The location of the jsp page
+     * @param parent The enclosing node
+     */
+    public Node(String qName, String localName, Mark start, Node parent) {
+	this.qName = qName;
+	this.localName = localName;
+	this.startMark = start;
+	this.isDummy = (start == null);
+	addToParent(parent);
+    }
+
+    /**
+     * Constructor for Nodes parsed from standard syntax.
+     *
+     * @param qName The action's qualified name
+     * @param localName The action's local name
+     * @param attrs The attributes for this node
+     * @param start The location of the jsp page
+     * @param parent The enclosing node
+     */
+    public Node(String qName, String localName, Attributes attrs, Mark start,
+		Node parent) {
+	this.qName = qName;
+	this.localName = localName;
+	this.attrs = attrs;
+	this.startMark = start;
+	this.isDummy = (start == null);
+	addToParent(parent);
+    }
+
+    /**
+     * Constructor for Nodes parsed from XML syntax.
+     *
+     * @param qName The action's qualified name
+     * @param localName The action's local name
+     * @param attrs The action's attributes whose name does not start with
+     * xmlns
+     * @param nonTaglibXmlnsAttrs The action's xmlns attributes that do not
+     * represent tag libraries
+     * @param taglibAttrs The action's xmlns attributes that represent tag
+     * libraries
+     * @param start The location of the jsp page
+     * @param parent The enclosing node
+     */
+    public Node(String qName, String localName, Attributes attrs,
+		Attributes nonTaglibXmlnsAttrs, Attributes taglibAttrs,
+		Mark start, Node parent) {
+	this.qName = qName;
+	this.localName = localName;
+	this.attrs = attrs;
+	this.nonTaglibXmlnsAttrs = nonTaglibXmlnsAttrs;
+	this.taglibAttrs = taglibAttrs;
+	this.startMark = start;
+	this.isDummy = (start == null);
+	addToParent(parent);
+    }
+
+    /*
+     * Constructor.
+     *
+     * @param qName The action's qualified name
+     * @param localName The action's local name
+     * @param text The text associated with this node
+     * @param start The location of the jsp page
+     * @param parent The enclosing node
+     */
+    public Node(String qName, String localName, String text, Mark start,
+		Node parent) {
+	this.qName = qName;
+	this.localName = localName;
+	this.text = text;
+	this.startMark = start;
+	this.isDummy = (start == null);
+	addToParent(parent);
+    }
+
+    public String getQName() {
+	return this.qName;
+    }
+
+    public String getLocalName() {
+	return this.localName;
+    }
+
+    /*
+     * Gets this Node's attributes.
+     *
+     * In the case of a Node parsed from standard syntax, this method returns
+     * all the Node's attributes.
+     *
+     * In the case of a Node parsed from XML syntax, this method returns only
+     * those attributes whose name does not start with xmlns.
+     */
+    public Attributes getAttributes() {
+	return this.attrs;
+    }
+
+    /*
+     * Gets this Node's xmlns attributes that represent tag libraries
+     * (only meaningful for Nodes parsed from XML syntax)
+     */
+    public Attributes getTaglibAttributes() {
+	return this.taglibAttrs;
+    }
+
+    /*
+     * Gets this Node's xmlns attributes that do not represent tag libraries
+     * (only meaningful for Nodes parsed from XML syntax)
+     */
+    public Attributes getNonTaglibXmlnsAttributes() {
+	return this.nonTaglibXmlnsAttrs;
+    }
+
+    public void setAttributes(Attributes attrs) {
+	this.attrs = attrs;
+    }
+
+    public String getAttributeValue(String name) {
+	return (attrs == null) ? null : attrs.getValue(name);
+    }
+
+    /**
+     * Get the attribute that is non request time expression, either
+     * from the attribute of the node, or from a jsp:attrbute 
+     */
+    public String getTextAttribute(String name) {
+
+	String attr = getAttributeValue(name);
+	if (attr != null) {
+	    return attr;
+	}
+
+	NamedAttribute namedAttribute = getNamedAttributeNode(name);
+	if (namedAttribute == null) {
+	    return null;
+	}
+
+	return namedAttribute.getText();
+    }
+
+    /**
+     * Searches all subnodes of this node for jsp:attribute standard
+     * actions with the given name, and returns the NamedAttribute node
+     * of the matching named attribute, nor null if no such node is found.
+     * <p>
+     * This should always be called and only be called for nodes that
+     * accept dynamic runtime attribute expressions.
+     */
+    public NamedAttribute getNamedAttributeNode( String name ) {
+        NamedAttribute result = null;
+        
+        // Look for the attribute in NamedAttribute children
+        Nodes nodes = getNamedAttributeNodes();
+        int numChildNodes = nodes.size();
+        for( int i = 0; i < numChildNodes; i++ ) {
+            NamedAttribute na = (NamedAttribute)nodes.getNode( i );
+	    boolean found = false;
+	    int index = name.indexOf(':');
+	    if (index != -1) {
+		// qualified name
+		found = na.getName().equals(name);
+	    } else {
+		found = na.getLocalName().equals(name);
+	    }
+	    if (found) {
+                result = na;
+                break;
+            }
+        }
+        
+        return result;
+    }
+
+    /**
+     * Searches all subnodes of this node for jsp:attribute standard
+     * actions, and returns that set of nodes as a Node.Nodes object.
+     *
+     * @return Possibly empty Node.Nodes object containing any jsp:attribute
+     * subnodes of this Node
+     */
+    public Node.Nodes getNamedAttributeNodes() {
+
+	if (namedAttributeNodes != null) {
+	    return namedAttributeNodes;
+	}
+
+        Node.Nodes result = new Node.Nodes();
+        
+        // Look for the attribute in NamedAttribute children
+        Nodes nodes = getBody();
+        if( nodes != null ) {
+            int numChildNodes = nodes.size();
+            for( int i = 0; i < numChildNodes; i++ ) {
+                Node n = nodes.getNode( i );
+                if( n instanceof NamedAttribute ) {
+                    result.add( n );
+                }
+                else if (! (n instanceof Comment)) {
+                    // Nothing can come before jsp:attribute, and only
+                    // jsp:body can come after it.
+                    break;
+                }
+            }
+        }
+
+	namedAttributeNodes = result;
+        return result;
+    }
+    
+    public Nodes getBody() {
+	return body;
+    }
+
+    public void setBody(Nodes body) {
+	this.body = body;
+    }
+
+    public String getText() {
+	return text;
+    }
+
+    public Mark getStart() {
+	return startMark;
+    }
+
+    public Node getParent() {
+	return parent;
+    }
+
+    public int getBeginJavaLine() {
+	return beginJavaLine;
+    }
+
+    public void setBeginJavaLine(int begin) {
+	beginJavaLine = begin;
+    }
+
+    public int getEndJavaLine() {
+	return endJavaLine;
+    }
+
+    public void setEndJavaLine(int end) {
+	endJavaLine = end;
+    }
+
+    public boolean isDummy() {
+	return isDummy;
+    }
+
+    public Node.Root getRoot() {
+	Node n = this;
+	while (!(n instanceof Node.Root)) {
+	    n = n.getParent();
+	}
+	return (Node.Root) n;
+    }
+
+    public String getInnerClassName() {
+        return innerClassName;
+    }
+
+    public void setInnerClassName(String icn) {
+        innerClassName = icn;
+    }
+
+    /**
+     * Selects and invokes a method in the visitor class based on the node
+     * type.  This is abstract and should be overrode by the extending classes.
+     * @param v The visitor class
+     */
+    abstract void accept(Visitor v) throws JasperException;
+
+
+    //*********************************************************************
+    // Private utility methods
+
+    /*
+     * Adds this Node to the body of the given parent.
+     */
+    private void addToParent(Node parent) {
+	if (parent != null) {
+	    this.parent = parent;
+	    Nodes parentBody = parent.getBody();
+	    if (parentBody == null) {
+		parentBody = new Nodes();
+		parent.setBody(parentBody);
+	    }
+	    parentBody.add(this);
+	}
+    }
+
+
+    /*********************************************************************
+     * Child classes
+     */
+    
+    /**
+     * Represents the root of a Jsp page or Jsp document
+     */
+    public static class Root extends Node {
+
+	private Root parentRoot;
+	private boolean isXmlSyntax;
+
+	// Source encoding of the page containing this Root
+	private String pageEnc;
+	
+	// Page encoding specified in JSP config element
+	private String jspConfigPageEnc;
+
+	/*
+	 * Flag indicating if the default page encoding is being used (only
+	 * applicable with standard syntax).
+	 *
+	 * True if the page does not provide a page directive with a
+	 * 'contentType' attribute (or the 'contentType' attribute doesn't
+	 * have a CHARSET value), the page does not provide a page directive
+	 * with a 'pageEncoding' attribute, and there is no JSP configuration
+	 * element page-encoding whose URL pattern matches the page.
+	 */
+	private boolean isDefaultPageEncoding;
+
+	/*
+	 * Indicates whether an encoding has been explicitly specified in the
+	 * page's XML prolog (only used for pages in XML syntax).
+	 * This information is used to decide whether a translation error must
+	 * be reported for encoding conflicts.
+	 */
+	private boolean isEncodingSpecifiedInProlog;
+
+	/*
+	 * Constructor.
+	 */
+	Root(Mark start, Node parent, boolean isXmlSyntax) {
+	    super(start, parent);
+	    this.isXmlSyntax = isXmlSyntax;
+	    this.qName = JSP_ROOT_ACTION;
+	    this.localName = ROOT_ACTION;
+
+	    // Figure out and set the parent root
+	    Node r = parent;
+	    while ((r != null) && !(r instanceof Node.Root))
+		r = r.getParent();
+	    parentRoot = (Node.Root) r;
+	}
+
+	public void accept(Visitor v) throws JasperException {
+	    v.visit(this);
+	}
+
+	public boolean isXmlSyntax() {
+	    return isXmlSyntax;
+	}
+
+	/*
+	 * Sets the encoding specified in the JSP config element whose URL
+	 * pattern matches the page containing this Root.
+	 */
+	public void setJspConfigPageEncoding(String enc) {
+	    jspConfigPageEnc = enc;
+	}
+
+	/*
+	 * Gets the encoding specified in the JSP config element whose URL
+	 * pattern matches the page containing this Root.
+	 */
+	public String getJspConfigPageEncoding() {
+	    return jspConfigPageEnc;
+	}
+
+	public void setPageEncoding(String enc) {
+	    pageEnc = enc;
+	}
+
+	public String getPageEncoding() {
+	    return pageEnc;
+	}
+
+	public void setIsDefaultPageEncoding(boolean isDefault) {
+	    isDefaultPageEncoding = isDefault;
+	}
+
+	public boolean isDefaultPageEncoding() {
+	    return isDefaultPageEncoding;
+	}
+	
+	public void setIsEncodingSpecifiedInProlog(boolean isSpecified) {
+	    isEncodingSpecifiedInProlog = isSpecified;
+	}
+
+	public boolean isEncodingSpecifiedInProlog() {
+	    return isEncodingSpecifiedInProlog;
+	}
+
+	/**
+	 * @return The enclosing root to this Root. Usually represents the
+	 * page that includes this one.
+	 */
+	public Root getParentRoot() {
+	    return parentRoot;
+	}
+    }
+    
+    /**
+     * Represents the root of a Jsp document (XML syntax)
+     */
+    public static class JspRoot extends Node {
+
+	public JspRoot(String qName, Attributes attrs,
+		       Attributes nonTaglibXmlnsAttrs, Attributes taglibAttrs,
+		       Mark start, Node parent) {
+	    super(qName, ROOT_ACTION, attrs, nonTaglibXmlnsAttrs, taglibAttrs,
+		  start, parent);
+	}
+
+	public void accept(Visitor v) throws JasperException {
+	    v.visit(this);
+	}
+    }
+
+    /**
+     * Represents a page directive
+     */
+    public static class PageDirective extends Node {
+
+	private Vector imports;
+
+	public PageDirective(Attributes attrs, Mark start, Node parent) {
+	    this(JSP_PAGE_DIRECTIVE_ACTION, attrs, null, null, start, parent);
+	}
+
+	public PageDirective(String qName, Attributes attrs,
+			     Attributes nonTaglibXmlnsAttrs,
+			     Attributes taglibAttrs, Mark start, Node parent) {
+	    super(qName, PAGE_DIRECTIVE_ACTION, attrs, nonTaglibXmlnsAttrs,
+		  taglibAttrs, start, parent);
+	    imports = new Vector();
+	}
+
+	public void accept(Visitor v) throws JasperException {
+	    v.visit(this);
+	}
+
+	/**
+	 * Parses the comma-separated list of class or package names in the
+	 * given attribute value and adds each component to this
+	 * PageDirective's vector of imported classes and packages.
+	 * @param value A comma-separated string of imports.
+	 */
+	public void addImport(String value) {
+	    int start = 0;
+	    int index;
+	    while ((index = value.indexOf(',', start)) != -1) {
+		imports.add(value.substring(start, index).trim());
+		start = index + 1;
+	    }
+	    if (start == 0) {
+		// No comma found
+		imports.add(value.trim());
+	    } else {
+		imports.add(value.substring(start).trim());
+	    }
+	}
+
+	public List getImports() {
+	    return imports;
+	}
+    }
+
+    /**
+     * Represents an include directive
+     */
+    public static class IncludeDirective extends Node {
+
+	public IncludeDirective(Attributes attrs, Mark start, Node parent) {
+	    this(JSP_INCLUDE_DIRECTIVE_ACTION, attrs, null, null, start,
+		 parent);
+	}
+
+	public IncludeDirective(String qName, Attributes attrs,
+				Attributes nonTaglibXmlnsAttrs,
+				Attributes taglibAttrs, Mark start,
+				Node parent) {
+	    super(qName, INCLUDE_DIRECTIVE_ACTION, attrs, nonTaglibXmlnsAttrs,
+		  taglibAttrs, start, parent);
+	}
+
+	public void accept(Visitor v) throws JasperException {
+	    v.visit(this);
+	}
+    }
+
+    /**
+     * Represents a custom taglib directive
+     */
+    public static class TaglibDirective extends Node {
+
+	public TaglibDirective(Attributes attrs, Mark start, Node parent) {
+	    super(JSP_TAGLIB_DIRECTIVE_ACTION, TAGLIB_DIRECTIVE_ACTION, attrs,
+		  start, parent);
+	}
+
+	public void accept(Visitor v) throws JasperException {
+	    v.visit(this);
+	}
+    }
+
+    /**
+     * Represents a tag directive
+     */
+    public static class TagDirective extends Node {
+        private Vector imports;
+
+	public TagDirective(Attributes attrs, Mark start, Node parent) {
+	    this(JSP_TAG_DIRECTIVE_ACTION, attrs, null, null, start, parent);
+	}
+
+	public TagDirective(String qName, Attributes attrs,
+			    Attributes nonTaglibXmlnsAttrs,
+			    Attributes taglibAttrs, Mark start, Node parent) {
+	    super(qName, TAG_DIRECTIVE_ACTION, attrs, nonTaglibXmlnsAttrs,
+		  taglibAttrs, start, parent);
+            imports = new Vector();
+	}
+
+	public void accept(Visitor v) throws JasperException {
+	    v.visit(this);
+        }
+ 
+        /**
+         * Parses the comma-separated list of class or package names in the
+         * given attribute value and adds each component to this
+         * PageDirective's vector of imported classes and packages.
+         * @param value A comma-separated string of imports.
+         */
+        public void addImport(String value) {
+            int start = 0;
+            int index;
+            while ((index = value.indexOf(',', start)) != -1) {
+                imports.add(value.substring(start, index).trim());
+                start = index + 1;
+            }
+            if (start == 0) {
+                // No comma found
+                imports.add(value.trim());
+            } else {
+                imports.add(value.substring(start).trim());
+            }
+        }
+ 
+        public List getImports() {
+            return imports;
+	}
+    }
+
+    /**
+     * Represents an attribute directive
+     */
+    public static class AttributeDirective extends Node {
+
+	public AttributeDirective(Attributes attrs, Mark start, Node parent) {
+	    this(JSP_ATTRIBUTE_DIRECTIVE_ACTION, attrs, null, null, start,
+		 parent);
+	}
+
+	public AttributeDirective(String qName, Attributes attrs,
+				  Attributes nonTaglibXmlnsAttrs,
+				  Attributes taglibAttrs, Mark start,
+				  Node parent) {
+	    super(qName, ATTRIBUTE_DIRECTIVE_ACTION, attrs,
+		  nonTaglibXmlnsAttrs, taglibAttrs, start, parent);
+	}
+
+	public void accept(Visitor v) throws JasperException {
+	    v.visit(this);
+	}
+    }
+
+    /**
+     * Represents a variable directive
+     */
+    public static class VariableDirective extends Node {
+
+	public VariableDirective(Attributes attrs, Mark start, Node parent) {
+	    this(JSP_VARIABLE_DIRECTIVE_ACTION, attrs, null, null, start,
+		 parent);
+	}
+
+	public VariableDirective(String qName, Attributes attrs,
+				 Attributes nonTaglibXmlnsAttrs,
+				 Attributes taglibAttrs,
+				 Mark start, Node parent) {
+	    super(qName, VARIABLE_DIRECTIVE_ACTION, attrs, nonTaglibXmlnsAttrs,
+		  taglibAttrs, start, parent);
+	}
+
+	public void accept(Visitor v) throws JasperException {
+	    v.visit(this);
+	}
+    }
+
+    /**
+     * Represents a <jsp:invoke> tag file action
+     */
+    public static class InvokeAction extends Node {
+
+	public InvokeAction(Attributes attrs, Mark start, Node parent) {
+	    this(JSP_INVOKE_ACTION, attrs, null, null, start, parent);
+	}
+
+	public InvokeAction(String qName, Attributes attrs,
+			    Attributes nonTaglibXmlnsAttrs,
+			    Attributes taglibAttrs, Mark start, Node parent) {
+	    super(qName, INVOKE_ACTION, attrs, nonTaglibXmlnsAttrs,
+		  taglibAttrs, start, parent);
+	}
+
+	public void accept(Visitor v) throws JasperException {
+	    v.visit(this);
+	}
+    }
+
+    /**
+     * Represents a <jsp:doBody> tag file action
+     */
+    public static class DoBodyAction extends Node {
+
+	public DoBodyAction(Attributes attrs, Mark start, Node parent) {
+	    this(JSP_DOBODY_ACTION, attrs, null, null, start, parent);
+	}
+
+	public DoBodyAction(String qName, Attributes attrs,
+			    Attributes nonTaglibXmlnsAttrs,
+			    Attributes taglibAttrs, Mark start, Node parent) {
+	    super(qName, DOBODY_ACTION, attrs, nonTaglibXmlnsAttrs,
+		  taglibAttrs, start, parent);
+	}
+
+	public void accept(Visitor v) throws JasperException {
+	    v.visit(this);
+	}
+    }
+
+    /**
+     * Represents a Jsp comment
+     * Comments are kept for completeness.
+     */
+    public static class Comment extends Node {
+
+	public Comment(String text, Mark start, Node parent) {
+	    super(null, null, text, start, parent);
+	}
+
+	public void accept(Visitor v) throws JasperException {
+	    v.visit(this);
+	}
+    }
+
+    /**
+     * Represents an expression, declaration, or scriptlet
+     */
+    public static abstract class ScriptingElement extends Node {
+
+	public ScriptingElement(String qName, String localName, String text,
+				Mark start, Node parent) {
+	    super(qName, localName, text, start, parent);
+	}
+
+	public ScriptingElement(String qName, String localName,
+				Attributes nonTaglibXmlnsAttrs,
+				Attributes taglibAttrs, Mark start,
+				Node parent) {
+	    super(qName, localName, null, nonTaglibXmlnsAttrs, taglibAttrs,
+		  start, parent);
+	}
+
+	/**
+	 * When this node was created from a JSP page in JSP syntax, its text
+	 * was stored as a String in the "text" field, whereas when this node
+	 * was created from a JSP document, its text was stored as one or more
+	 * TemplateText nodes in its body. This method handles either case.
+	 * @return The text string
+	 */
+	public String getText() {
+	    String ret = text;
+	    if ((ret == null) && (body != null)) {
+		StringBuffer buf = new StringBuffer();
+		for (int i=0; i<body.size(); i++) {
+		    buf.append(body.getNode(i).getText());
+		}
+		ret = buf.toString();
+	    }
+	    return ret;
+	}
+
+        /**
+         * For the same reason as above, the source line information in the
+         * contained TemplateText node should be used.
+         */
+        public Mark getStart() {
+            if (text == null && body != null && body.size() > 0) {
+                return body.getNode(0).getStart();
+            } else {
+                return super.getStart();
+            }
+        }
+    }
+
+    /**
+     * Represents a declaration
+     */
+    public static class Declaration extends ScriptingElement {
+
+	public Declaration(String text, Mark start, Node parent) {
+	    super(JSP_DECLARATION_ACTION, DECLARATION_ACTION, text, start,
+		  parent);
+	}
+
+	public Declaration(String qName, Attributes nonTaglibXmlnsAttrs,
+			   Attributes taglibAttrs, Mark start,
+			   Node parent) {
+	    super(qName, DECLARATION_ACTION, nonTaglibXmlnsAttrs,
+		  taglibAttrs, start, parent);
+	}
+
+	public void accept(Visitor v) throws JasperException {
+	    v.visit(this);
+	}
+    }
+
+    /**
+     * Represents an expression.  Expressions in attributes are embedded
+     * in the attribute string and not here.
+     */
+    public static class Expression extends ScriptingElement {
+
+	public Expression(String text, Mark start, Node parent) {
+	    super(JSP_EXPRESSION_ACTION, EXPRESSION_ACTION, text, start,
+		  parent);
+	}
+
+	public Expression(String qName, Attributes nonTaglibXmlnsAttrs,
+			  Attributes taglibAttrs, Mark start,
+			  Node parent) {
+	    super(qName, EXPRESSION_ACTION, nonTaglibXmlnsAttrs, taglibAttrs,
+		  start, parent);
+	}
+
+	public void accept(Visitor v) throws JasperException {
+	    v.visit(this);
+	}
+    }
+
+    /**
+     * Represents a scriptlet
+     */
+    public static class Scriptlet extends ScriptingElement {
+
+	public Scriptlet(String text, Mark start, Node parent) {
+	    super(JSP_SCRIPTLET_ACTION, SCRIPTLET_ACTION, text, start, parent);
+	}
+
+	public Scriptlet(String qName, Attributes nonTaglibXmlnsAttrs,
+			 Attributes taglibAttrs, Mark start,
+			 Node parent) {
+	    super(qName, SCRIPTLET_ACTION, nonTaglibXmlnsAttrs, taglibAttrs,
+		  start, parent);
+	}
+
+	public void accept(Visitor v) throws JasperException {
+	    v.visit(this);
+	}
+    }
+
+    /**
+     * Represents an EL expression.  Expressions in attributes are embedded
+     * in the attribute string and not here.
+     */
+    public static class ELExpression extends Node {
+
+	private ELNode.Nodes el;
+
+        public ELExpression(String text, Mark start, Node parent) {
+            super(null, null, text, start, parent);
+        }
+
+        public void accept(Visitor v) throws JasperException {
+            v.visit(this);
+        }
+
+	public void setEL(ELNode.Nodes el) {
+	    this.el = el;
+	}
+
+	public ELNode.Nodes getEL() {
+	    return el;
+	}
+    }
+
+    /**
+     * Represents a param action
+     */
+    public static class ParamAction extends Node {
+
+	JspAttribute value;
+
+	public ParamAction(Attributes attrs, Mark start, Node parent) {
+	    this(JSP_PARAM_ACTION, attrs, null, null, start, parent);
+	}
+
+	public ParamAction(String qName, Attributes attrs,
+			   Attributes nonTaglibXmlnsAttrs,
+			   Attributes taglibAttrs, Mark start, Node parent) {
+	    super(qName, PARAM_ACTION, attrs, nonTaglibXmlnsAttrs,
+		  taglibAttrs, start, parent);
+	}
+
+	public void accept(Visitor v) throws JasperException {
+	    v.visit(this);
+	}
+
+	public void setValue(JspAttribute value) {
+	    this.value = value;
+	}
+
+	public JspAttribute getValue() {
+	    return value;
+	}
+    }
+
+    /**
+     * Represents a params action
+     */
+    public static class ParamsAction extends Node {
+
+	public ParamsAction(Mark start, Node parent) {
+	    this(JSP_PARAMS_ACTION, null, null, start, parent);
+	}
+
+	public ParamsAction(String qName,
+			    Attributes nonTaglibXmlnsAttrs,
+			    Attributes taglibAttrs,
+			    Mark start, Node parent) {
+	    super(qName, PARAMS_ACTION, null, nonTaglibXmlnsAttrs, taglibAttrs,
+		  start, parent);
+	}
+
+	public void accept(Visitor v) throws JasperException {
+	    v.visit(this);
+	}
+    }
+
+    /**
+     * Represents a fallback action
+     */
+    public static class FallBackAction extends Node {
+
+	public FallBackAction(Mark start, Node parent) {
+	    this(JSP_FALLBACK_ACTION, null, null, start, parent);
+	}
+
+	public FallBackAction(String qName,
+			      Attributes nonTaglibXmlnsAttrs,
+			      Attributes taglibAttrs, Mark start,
+			      Node parent) {
+	    super(qName, FALLBACK_ACTION, null, nonTaglibXmlnsAttrs,
+		  taglibAttrs, start, parent);
+	}
+
+	public void accept(Visitor v) throws JasperException {
+	    v.visit(this);
+	}
+    }
+
+    /**
+     * Represents an include action
+     */
+    public static class IncludeAction extends Node {
+
+	private JspAttribute page;
+
+	public IncludeAction(Attributes attrs, Mark start, Node parent) {
+	    this(JSP_INCLUDE_ACTION, attrs, null, null, start, parent);
+	}
+
+	public IncludeAction(String qName, Attributes attrs,
+			     Attributes nonTaglibXmlnsAttrs,
+			     Attributes taglibAttrs, Mark start, Node parent) {
+	    super(qName, INCLUDE_ACTION, attrs, nonTaglibXmlnsAttrs,
+		  taglibAttrs, start, parent);
+	}
+
+	public void accept(Visitor v) throws JasperException {
+	    v.visit(this);
+	}
+
+	public void setPage(JspAttribute page) {
+	    this.page = page;
+	}
+
+	public JspAttribute getPage() {
+	    return page;
+	}
+    }
+
+    /**
+     * Represents a forward action
+     */
+    public static class ForwardAction extends Node {
+
+	private JspAttribute page;
+
+	public ForwardAction(Attributes attrs, Mark start, Node parent) {
+	    this(JSP_FORWARD_ACTION, attrs, null, null, start, parent);
+	}
+
+	public ForwardAction(String qName, Attributes attrs,
+			     Attributes nonTaglibXmlnsAttrs,
+			     Attributes taglibAttrs, Mark start, Node parent) {
+	    super(qName, FORWARD_ACTION, attrs, nonTaglibXmlnsAttrs,
+		  taglibAttrs, start, parent);
+	}
+
+	public void accept(Visitor v) throws JasperException {
+	    v.visit(this);
+	}
+
+	public void setPage(JspAttribute page) {
+	    this.page = page;
+	}
+
+	public JspAttribute getPage() {
+	    return page;
+	}
+    }
+
+    /**
+     * Represents a getProperty action
+     */
+    public static class GetProperty extends Node {
+
+	public GetProperty(Attributes attrs, Mark start, Node parent) {
+	    this(JSP_GET_PROPERTY_ACTION, attrs, null, null, start, parent);
+	}
+
+	public GetProperty(String qName, Attributes attrs,
+			   Attributes nonTaglibXmlnsAttrs,
+			   Attributes taglibAttrs, Mark start, Node parent) {
+	    super(qName, GET_PROPERTY_ACTION, attrs, nonTaglibXmlnsAttrs,
+		  taglibAttrs, start,  parent);
+	}
+
+	public void accept(Visitor v) throws JasperException {
+	    v.visit(this);
+	}
+    }
+
+    /**
+     * Represents a setProperty action
+     */
+    public static class SetProperty extends Node {
+
+	private JspAttribute value;
+
+	public SetProperty(Attributes attrs, Mark start, Node parent) {
+	    this(JSP_SET_PROPERTY_ACTION, attrs, null, null, start, parent);
+	}
+
+	public SetProperty(String qName, Attributes attrs,
+			   Attributes nonTaglibXmlnsAttrs,
+			   Attributes taglibAttrs, Mark start, Node parent) {
+	    super(qName, SET_PROPERTY_ACTION, attrs, nonTaglibXmlnsAttrs,
+		  taglibAttrs, start, parent);
+	}
+
+	public void accept(Visitor v) throws JasperException {
+	    v.visit(this);
+	}
+
+	public void setValue(JspAttribute value) {
+	    this.value = value;
+	}
+
+	public JspAttribute getValue() {
+	    return value;
+	}
+    }
+
+    /**
+     * Represents a useBean action
+     */
+    public static class UseBean extends Node {
+
+	JspAttribute beanName;
+
+	public UseBean(Attributes attrs, Mark start, Node parent) {
+	    this(JSP_USE_BEAN_ACTION, attrs, null, null, start, parent);
+	}
+
+	public UseBean(String qName, Attributes attrs,
+		       Attributes nonTaglibXmlnsAttrs, Attributes taglibAttrs,
+		       Mark start, Node parent) {
+	    super(qName, USE_BEAN_ACTION, attrs, nonTaglibXmlnsAttrs,
+		  taglibAttrs, start, parent);
+	}
+
+	public void accept(Visitor v) throws JasperException {
+	    v.visit(this);
+	}
+
+	public void setBeanName(JspAttribute beanName) {
+	    this.beanName = beanName;
+	}
+
+	public JspAttribute getBeanName() {
+	    return beanName;
+	}
+    }
+
+    /**
+     * Represents a plugin action
+     */
+    public static class PlugIn extends Node {
+
+        private JspAttribute width;
+        private JspAttribute height;
+        
+	public PlugIn(Attributes attrs, Mark start, Node parent) {
+	    this(JSP_PLUGIN_ACTION, attrs, null, null, start, parent);
+	}
+
+	public PlugIn(String qName, Attributes attrs,
+		      Attributes nonTaglibXmlnsAttrs, Attributes taglibAttrs,
+		      Mark start, Node parent) {
+	    super(qName, PLUGIN_ACTION, attrs, nonTaglibXmlnsAttrs,
+		  taglibAttrs, start, parent);
+	}
+
+	public void accept(Visitor v) throws JasperException {
+	    v.visit(this);
+	}
+
+	public void setHeight(JspAttribute height) {
+	    this.height = height;
+	}
+
+	public void setWidth(JspAttribute width) {
+	    this.width = width;
+	}
+
+	public JspAttribute getHeight() {
+	    return height;
+	}
+
+	public JspAttribute getWidth() {
+	    return width;
+	}
+    }
+
+    /**
+     * Represents an uninterpreted tag, from a Jsp document
+     */
+    public static class UninterpretedTag extends Node {
+
+	private JspAttribute[] jspAttrs;
+
+	public UninterpretedTag(String qName, String localName,
+				Attributes attrs,
+				Attributes nonTaglibXmlnsAttrs,
+				Attributes taglibAttrs,
+				Mark start, Node parent) {
+	    super(qName, localName, attrs, nonTaglibXmlnsAttrs, taglibAttrs,
+		  start, parent);
+	}
+
+	public void accept(Visitor v) throws JasperException {
+	    v.visit(this);
+	}
+
+	public void setJspAttributes(JspAttribute[] jspAttrs) {
+	    this.jspAttrs = jspAttrs;
+	}
+
+	public JspAttribute[] getJspAttributes() {
+	    return jspAttrs;
+	}
+    }
+    
+    /**
+     * Represents a <jsp:element>.
+     */
+    public static class JspElement extends Node {
+
+	private JspAttribute[] jspAttrs;
+	private JspAttribute nameAttr;
+
+	public JspElement(Attributes attrs, Mark start, Node parent) {
+	    this(JSP_ELEMENT_ACTION, attrs, null, null, start, parent);
+	}
+
+	public JspElement(String qName, Attributes attrs,
+			  Attributes nonTaglibXmlnsAttrs,
+			  Attributes taglibAttrs, Mark start, Node parent) {
+	    super(qName, ELEMENT_ACTION, attrs, nonTaglibXmlnsAttrs,
+		  taglibAttrs, start, parent);
+	}
+
+	public void accept(Visitor v) throws JasperException {
+	    v.visit(this);
+	}
+
+	public void setJspAttributes(JspAttribute[] jspAttrs) {
+	    this.jspAttrs = jspAttrs;
+	}
+
+	public JspAttribute[] getJspAttributes() {
+	    return jspAttrs;
+	}
+
+	/*
+	 * Sets the XML-style 'name' attribute
+	 */
+	public void setNameAttribute(JspAttribute nameAttr) {
+	    this.nameAttr = nameAttr;
+	}
+
+	/*
+	 * Gets the XML-style 'name' attribute
+	 */
+	public JspAttribute getNameAttribute() {
+	    return this.nameAttr;
+	}
+    }
+
+    /**
+     * Represents a <jsp:output>.
+     */
+    public static class JspOutput extends Node {
+
+	public JspOutput(String qName, Attributes attrs,
+			 Attributes nonTaglibXmlnsAttrs,
+			 Attributes taglibAttrs,
+			 Mark start, Node parent) {
+	    super(qName, OUTPUT_ACTION, attrs, nonTaglibXmlnsAttrs,
+		  taglibAttrs, start, parent);
+	}
+
+	public void accept(Visitor v) throws JasperException {
+	    v.visit(this);
+	}
+    }
+
+    /**
+     * Collected information about child elements.  Used by nodes like
+     * CustomTag, JspBody, and NamedAttribute.  The information is 
+     * set in the Collector.
+     */
+    public static class ChildInfo {
+	private boolean scriptless;	// true if the tag and its body
+					// contain no scripting elements.
+	private boolean hasUseBean;
+	private boolean hasIncludeAction;
+	private boolean hasParamAction;
+	private boolean hasSetProperty;
+	private boolean hasScriptingVars;
+
+	public void setScriptless(boolean s) {
+	    scriptless = s;
+	}
+
+	public boolean isScriptless() {
+	    return scriptless;
+	}
+
+	public void setHasUseBean(boolean u) {
+	    hasUseBean = u;
+	}
+
+	public boolean hasUseBean() {
+	    return hasUseBean;
+	}
+
+	public void setHasIncludeAction(boolean i) {
+	    hasIncludeAction = i;
+	}
+
+	public boolean hasIncludeAction() {
+	    return hasIncludeAction;
+	}
+
+	public void setHasParamAction(boolean i) {
+	    hasParamAction = i;
+	}
+
+	public boolean hasParamAction() {
+	    return hasParamAction;
+	}
+
+	public void setHasSetProperty(boolean s) {
+	    hasSetProperty = s;
+	}
+
+	public boolean hasSetProperty() {
+	    return hasSetProperty;
+	}
+        
+	public void setHasScriptingVars(boolean s) {
+	    hasScriptingVars = s;
+	}
+
+	public boolean hasScriptingVars() {
+	    return hasScriptingVars;
+	}
+    }
+
+    /**
+     * Represents a custom tag
+     */
+    public static class CustomTag extends Node {
+
+	private String uri;
+	private String prefix;
+	private JspAttribute[] jspAttrs;
+	private TagData tagData;
+	private String tagHandlerPoolName;
+	private TagInfo tagInfo;
+	private TagFileInfo tagFileInfo;
+	private Class tagHandlerClass;
+	private VariableInfo[] varInfos;
+	private int customNestingLevel;
+        private ChildInfo childInfo;
+	private boolean implementsIterationTag;
+	private boolean implementsBodyTag;
+	private boolean implementsTryCatchFinally;
+	private boolean implementsSimpleTag;
+	private boolean implementsDynamicAttributes;
+	private Vector atBeginScriptingVars;
+	private Vector atEndScriptingVars;
+	private Vector nestedScriptingVars;
+	private Node.CustomTag customTagParent;
+	private Integer numCount;
+	private boolean useTagPlugin;
+	private TagPluginContext tagPluginContext;
+
+	/**
+	 * The following two fields are used for holding the Java
+	 * scriptlets that the tag plugins may generate.  Meaningful
+	 * only if useTagPlugin is true;
+	 * Could move them into TagPluginContextImpl, but we'll need
+	 * to cast tagPluginContext to TagPluginContextImpl all the time...
+	 */
+	private Nodes atSTag;
+	private Nodes atETag;
+
+	/*
+	 * Constructor for custom action implemented by tag handler.
+	 */
+	public CustomTag(String qName, String prefix, String localName,
+			 String uri, Attributes attrs, Mark start, Node parent,
+			 TagInfo tagInfo, Class tagHandlerClass) {
+	    this(qName, prefix, localName, uri, attrs, null, null, start,
+		 parent, tagInfo, tagHandlerClass);
+	}
+
+	/*
+	 * Constructor for custom action implemented by tag handler.
+	 */
+	public CustomTag(String qName, String prefix, String localName,
+			 String uri, Attributes attrs,
+			 Attributes nonTaglibXmlnsAttrs,
+			 Attributes taglibAttrs,
+			 Mark start, Node parent, TagInfo tagInfo,
+			 Class tagHandlerClass) {
+	    super(qName, localName, attrs, nonTaglibXmlnsAttrs, taglibAttrs,
+		  start, parent);
+
+	    this.uri = uri;
+	    this.prefix = prefix;
+	    this.tagInfo = tagInfo;
+	    this.tagHandlerClass = tagHandlerClass;
+	    this.customNestingLevel = makeCustomNestingLevel();
+            this.childInfo = new ChildInfo();
+
+	    this.implementsIterationTag = 
+		IterationTag.class.isAssignableFrom(tagHandlerClass);
+	    this.implementsBodyTag =
+		BodyTag.class.isAssignableFrom(tagHandlerClass);
+	    this.implementsTryCatchFinally = 
+		TryCatchFinally.class.isAssignableFrom(tagHandlerClass);
+	    this.implementsSimpleTag = 
+		SimpleTag.class.isAssignableFrom(tagHandlerClass);
+	    this.implementsDynamicAttributes = 
+		DynamicAttributes.class.isAssignableFrom(tagHandlerClass);
+	}
+
+	/*
+	 * Constructor for custom action implemented by tag file.
+	 */
+	public CustomTag(String qName, String prefix, String localName,
+			 String uri, Attributes attrs, Mark start, Node parent,
+			 TagFileInfo tagFileInfo) {
+	    this(qName, prefix, localName, uri, attrs, null, null, start,
+		 parent, tagFileInfo);
+	}
+
+	/*
+	 * Constructor for custom action implemented by tag file.
+	 */
+	public CustomTag(String qName, String prefix, String localName,
+			 String uri, Attributes attrs,
+			 Attributes nonTaglibXmlnsAttrs,
+			 Attributes taglibAttrs,
+			 Mark start, Node parent, TagFileInfo tagFileInfo) {
+
+	    super(qName, localName, attrs, nonTaglibXmlnsAttrs, taglibAttrs,
+		  start, parent);
+
+	    this.uri = uri;
+	    this.prefix = prefix;
+	    this.tagFileInfo = tagFileInfo;
+	    this.tagInfo = tagFileInfo.getTagInfo();
+	    this.customNestingLevel = makeCustomNestingLevel();
+            this.childInfo = new ChildInfo();
+
+	    this.implementsIterationTag = false;
+	    this.implementsBodyTag = false;
+	    this.implementsTryCatchFinally = false;
+	    this.implementsSimpleTag = true;
+	    this.implementsDynamicAttributes = tagInfo.hasDynamicAttributes();
+	}
+
+	public void accept(Visitor v) throws JasperException {
+	    v.visit(this);
+	}
+
+	/**
+	 * @return The URI namespace that this custom action belongs to
+	 */
+	public String getURI() {
+	    return this.uri;
+	}
+
+	/**
+	 * @return The tag prefix
+	 */
+	public String getPrefix() {
+	    return prefix;
+	}
+
+	public void setJspAttributes(JspAttribute[] jspAttrs) {
+	    this.jspAttrs = jspAttrs;
+	}
+
+	public JspAttribute[] getJspAttributes() {
+	    return jspAttrs;
+	}
+        
+        public ChildInfo getChildInfo() {
+            return childInfo;
+        }
+	
+	public void setTagData(TagData tagData) {
+	    this.tagData = tagData;
+	    this.varInfos = tagInfo.getVariableInfo(tagData);
+	    if (this.varInfos == null) {
+		this.varInfos = ZERO_VARIABLE_INFO;
+	    }
+	}
+
+	public TagData getTagData() {
+	    return tagData;
+	}
+
+	public void setTagHandlerPoolName(String s) {
+	    tagHandlerPoolName = s;
+	}
+
+	public String getTagHandlerPoolName() {
+	    return tagHandlerPoolName;
+	}
+
+	public TagInfo getTagInfo() {
+	    return tagInfo;
+	}
+
+	public TagFileInfo getTagFileInfo() {
+	    return tagFileInfo;
+	}
+
+	/*
+	 * @return true if this custom action is supported by a tag file,
+	 * false otherwise
+	 */
+	public boolean isTagFile() {
+	    return tagFileInfo != null;
+	}
+
+	public Class getTagHandlerClass() {
+	    return tagHandlerClass;
+	}
+
+	public void setTagHandlerClass(Class hc) {
+	    tagHandlerClass = hc;
+	}
+
+	public boolean implementsIterationTag() {
+	    return implementsIterationTag;
+	}
+
+	public boolean implementsBodyTag() {
+	    return implementsBodyTag;
+	}
+
+	public boolean implementsTryCatchFinally() {
+	    return implementsTryCatchFinally;
+	}
+
+	public boolean implementsSimpleTag() {
+	    return implementsSimpleTag;
+	}
+
+	public boolean implementsDynamicAttributes() {
+	    return implementsDynamicAttributes;
+	}
+
+	public TagVariableInfo[] getTagVariableInfos() {
+	    return tagInfo.getTagVariableInfos();
+ 	}
+ 
+	public VariableInfo[] getVariableInfos() {
+	    return varInfos;
+	}
+
+	public void setCustomTagParent(Node.CustomTag n) {
+	    this.customTagParent = n;
+	}
+
+	public Node.CustomTag getCustomTagParent() {
+	    return this.customTagParent;
+	}
+
+	public void setNumCount(Integer count) {
+	    this.numCount = count;
+	}
+
+	public Integer getNumCount() {
+	    return this.numCount;
+	}
+
+	public void setScriptingVars(Vector vec, int scope) {
+	    switch (scope) {
+	    case VariableInfo.AT_BEGIN:
+		this.atBeginScriptingVars = vec;
+		break;
+	    case VariableInfo.AT_END:
+		this.atEndScriptingVars = vec;
+		break;
+	    case VariableInfo.NESTED:
+		this.nestedScriptingVars = vec;
+		break;
+	    }
+	}
+
+	/*
+	 * Gets the scripting variables for the given scope that need to be
+	 * declared.
+	 */
+	public Vector getScriptingVars(int scope) {
+	    Vector vec = null;
+
+	    switch (scope) {
+	    case VariableInfo.AT_BEGIN:
+		vec = this.atBeginScriptingVars;
+		break;
+	    case VariableInfo.AT_END:
+		vec = this.atEndScriptingVars;
+		break;
+	    case VariableInfo.NESTED:
+		vec = this.nestedScriptingVars;
+		break;
+	    }
+
+	    return vec;
+	}
+
+	/*
+	 * Gets this custom tag's custom nesting level, which is given as
+	 * the number of times this custom tag is nested inside itself.
+	 */
+	public int getCustomNestingLevel() {
+	    return customNestingLevel;
+	}
+
+        /**
+         * Checks to see if the attribute of the given name is of type
+	 * JspFragment.
+         */
+        public boolean checkIfAttributeIsJspFragment( String name ) {
+            boolean result = false;
+
+	    TagAttributeInfo[] attributes = tagInfo.getAttributes();
+	    for (int i = 0; i < attributes.length; i++) {
+		if (attributes[i].getName().equals(name) &&
+		            attributes[i].isFragment()) {
+		    result = true;
+		    break;
+		}
+	    }
+            
+            return result;
+        }
+
+	public void setUseTagPlugin(boolean use) {
+	    useTagPlugin = use;
+	}
+
+	public boolean useTagPlugin() {
+	    return useTagPlugin;
+	}
+
+	public void setTagPluginContext(TagPluginContext tagPluginContext) {
+	    this.tagPluginContext = tagPluginContext;
+	}
+
+	public TagPluginContext getTagPluginContext() {
+	    return tagPluginContext;
+	}
+
+	public void setAtSTag(Nodes sTag) {
+	    atSTag = sTag;
+	}
+
+	public Nodes getAtSTag() {
+	    return atSTag;
+	}
+        
+	public void setAtETag(Nodes eTag) {
+	    atETag = eTag;
+	}
+
+	public Nodes getAtETag() {
+	    return atETag;
+	}
+        
+	/*
+	 * Computes this custom tag's custom nesting level, which corresponds
+	 * to the number of times this custom tag is nested inside itself.
+	 *
+	 * Example:
+	 * 
+	 *  <g:h>
+	 *    <a:b> -- nesting level 0
+	 *      <c:d>
+	 *        <e:f>
+	 *          <a:b> -- nesting level 1
+	 *            <a:b> -- nesting level 2
+	 *            </a:b>
+	 *          </a:b>
+	 *          <a:b> -- nesting level 1
+	 *          </a:b>
+	 *        </e:f>
+	 *      </c:d>
+	 *    </a:b>
+	 *  </g:h>
+	 * 
+	 * @return Custom tag's nesting level
+	 */
+	private int makeCustomNestingLevel() {
+	    int n = 0;
+	    Node p = parent;
+	    while (p != null) {
+		if ((p instanceof Node.CustomTag)
+		        && qName.equals(((Node.CustomTag) p).qName)) {
+		    n++;
+		}
+		p = p.parent;
+	    }
+	    return n;
+	}
+
+	/**
+	 * Returns true if this custom action has an empty body, and false
+	 * otherwise.
+	 *
+	 * A custom action is considered to have an empty body if the 
+	 * following holds true:
+	 * - getBody() returns null, or
+	 * - all immediate children are jsp:attribute actions, or
+	 * - the action's jsp:body is empty.
+	 */
+	 public boolean hasEmptyBody() {
+	     boolean hasEmptyBody = true;
+	     Nodes nodes = getBody();
+	     if (nodes != null) {
+		 int numChildNodes = nodes.size();
+		 for (int i=0; i<numChildNodes; i++) {
+		     Node n = nodes.getNode(i);
+		     if (!(n instanceof NamedAttribute)) {
+			 if (n instanceof JspBody) {
+			     hasEmptyBody = (n.getBody() == null);
+			 } else {
+			     hasEmptyBody = false;
+			 }
+			 break;
+		     }
+		 }
+	     }
+
+	     return hasEmptyBody;
+	 }
+    }
+
+    /**
+     * Used as a placeholder for the evaluation code of a custom action
+     * attribute (used by the tag plugin machinery only).
+     */
+    public static class AttributeGenerator extends Node {
+	String name;	// name of the attribute
+	CustomTag tag;	// The tag this attribute belongs to
+
+	public AttributeGenerator(Mark start, String name, CustomTag tag) {
+	    super(start, null);
+	    this.name = name;
+	    this.tag = tag;
+	}
+
+	public void accept(Visitor v) throws JasperException {
+	    v.visit(this);
+	}
+
+	public String getName() {
+	    return name;
+	}
+
+	public CustomTag getTag() {
+	    return tag;
+	}
+    }
+
+    /**
+     * Represents the body of a &lt;jsp:text&gt; element
+     */
+    public static class JspText extends Node {
+
+	public JspText(String qName, Attributes nonTaglibXmlnsAttrs,
+		       Attributes taglibAttrs, Mark start, Node parent) {
+	    super(qName, TEXT_ACTION, null, nonTaglibXmlnsAttrs, taglibAttrs,
+		  start, parent);
+	}
+
+	public void accept(Visitor v) throws JasperException {
+	    v.visit(this);
+	}
+    }
+
+    /**
+     * Represents a Named Attribute (&lt;jsp:attribute&gt;)
+     */
+    public static class NamedAttribute extends Node {
+
+        // A unique temporary variable name suitable for code generation
+        private String temporaryVariableName;
+
+        // True if this node is to be trimmed, or false otherwise
+        private boolean trim = true;
+        
+        private ChildInfo childInfo;
+	private String name;
+	private String localName;
+	private String prefix;
+
+        public NamedAttribute(Attributes attrs, Mark start, Node parent) {
+	    this(JSP_ATTRIBUTE_ACTION, attrs, null, null, start, parent);
+	}
+
+        public NamedAttribute(String qName, Attributes attrs,
+			      Attributes nonTaglibXmlnsAttrs,
+			      Attributes taglibAttrs,
+			      Mark start, Node parent) {
+
+            super(qName, ATTRIBUTE_ACTION, attrs, nonTaglibXmlnsAttrs,
+		  taglibAttrs, start, parent);
+            temporaryVariableName = JspUtil.nextTemporaryVariableName();
+            if( "false".equals( this.getAttributeValue( "trim" ) ) ) {
+                // (if null or true, leave default of true)
+                trim = false;
+            }
+            childInfo = new ChildInfo();
+	    name = this.getAttributeValue("name");
+            if (name != null) {
+                // Mandatary attribute "name" will be checked in Validator
+	        localName = name;
+	        int index = name.indexOf(':');
+	        if (index != -1) {
+		    prefix = name.substring(0, index);
+		    localName = name.substring(index+1);
+                }
+	    }
+        }
+
+        public void accept(Visitor v) throws JasperException {
+            v.visit(this);
+        }
+
+        public String getName() {
+            return this.name;
+        }
+
+        public String getLocalName() {
+            return this.localName;
+        }
+
+        public String getPrefix() {
+            return this.prefix;
+        }
+        
+        public ChildInfo getChildInfo() {
+            return this.childInfo;
+        }
+
+        public boolean isTrim() {
+            return trim;
+        }
+
+        /**
+         * @return A unique temporary variable name to store the result in.
+         *      (this probably could go elsewhere, but it's convenient here)
+         */
+        public String getTemporaryVariableName() {
+            return temporaryVariableName;
+        }
+
+	/*
+	 * Get the attribute value from this named attribute (<jsp:attribute>).
+	 * Since this method is only for attributes that are not rtexpr,
+	 * we can assume the body of the jsp:attribute is a template text.
+	 */
+	public String getText() {
+
+	    class AttributeVisitor extends Visitor {
+		String attrValue = null;
+		public void visit(TemplateText txt) {
+		    attrValue = new String(txt.getText());
+		}
+		
+		public String getAttrValue() {
+		    return attrValue;
+		}
+	    }
+
+	    // According to JSP 2.0, if the body of the <jsp:attribute>
+	    // action is empty, it is equivalent of specifying "" as the value
+	    // of the attribute.
+	    String text = "";
+	    if (getBody() != null) {
+		AttributeVisitor attributeVisitor = new AttributeVisitor();
+		try {
+		    getBody().visit(attributeVisitor);
+		} catch (JasperException e) {
+		}
+		text = attributeVisitor.getAttrValue();
+	    }
+	    
+	    return text;
+	}
+    }
+
+    /**
+     * Represents a JspBody node (&lt;jsp:body&gt;)
+     */
+    public static class JspBody extends Node {
+
+        private ChildInfo childInfo;
+
+        public JspBody(Mark start, Node parent) {
+            this(JSP_BODY_ACTION, null, null, start, parent);
+        }
+
+        public JspBody(String qName, Attributes nonTaglibXmlnsAttrs,
+		       Attributes taglibAttrs, Mark start, Node parent) {
+            super(qName, BODY_ACTION, null, nonTaglibXmlnsAttrs, taglibAttrs,
+		  start, parent);
+            this.childInfo = new ChildInfo();
+        }
+
+        public void accept(Visitor v) throws JasperException {
+            v.visit(this);
+        }
+
+        public ChildInfo getChildInfo() {
+            return childInfo;
+        }
+    }
+
+    /**
+     * Represents a template text string
+     */
+    public static class TemplateText extends Node {
+
+        private ArrayList extraSmap = null;
+
+	public TemplateText(String text, Mark start, Node parent) {
+	    super(null, null, text, start, parent);
+	}
+
+	public void accept(Visitor v) throws JasperException {
+	    v.visit(this);
+	}
+
+        /**
+         * Trim all whitespace from the left of the template text
+         */
+        public void ltrim() {
+	    int index = 0;
+            while ((index < text.length()) && (text.charAt(index) <= ' ')) {
+		index++;
+            }
+            text = text.substring(index);
+        }
+
+        public void setText(String text) {
+            this.text = text;
+        }
+
+        /**
+         * Trim all whitespace from the right of the template text
+         */
+        public void rtrim() {
+            int index = text.length();
+            while( (index > 0) && (text.charAt(index-1) <= ' ') ) {
+                index--;
+            }
+            text = text.substring(0, index);
+        }
+
+	/**
+	 * Returns true if this template text contains whitespace only.
+	 */
+	public boolean isAllSpace() {
+	    boolean isAllSpace = true;
+	    for (int i=0; i<text.length(); i++) {
+		if (!Character.isWhitespace(text.charAt(i))) {
+		    isAllSpace = false;
+		    break;
+		}
+	    }
+	    return isAllSpace;
+	}
+
+        /**
+         * Add a source to Java line mapping
+         * @param srcLine The postion of the source line, relative to the line
+         *        at the start of this node.  The corresponding java line is
+         *        assumed to be consecutive, i.e. one more than the last.
+         */
+        public void addSmap(int srcLine) {
+            if (extraSmap == null) {
+                extraSmap = new ArrayList();
+            }
+            extraSmap.add(new Integer(srcLine));
+        }
+
+        public ArrayList getExtraSmap() {
+            return extraSmap;
+        }
+    }
+
+    /*********************************************************************
+     * Auxillary classes used in Node
+     */
+
+    /**
+     * Represents attributes that can be request time expressions.
+     *
+     * Can either be a plain attribute, an attribute that represents a
+     * request time expression value, or a named attribute (specified using
+     * the jsp:attribute standard action).
+     */
+
+    public static class JspAttribute {
+
+	private String qName;
+	private String uri;
+	private String localName;
+	private String value;
+	private boolean expression;
+	private boolean dynamic;
+        private ELNode.Nodes el;
+
+        // If true, this JspAttribute represents a <jsp:attribute>
+        private boolean namedAttribute;
+        // The node in the parse tree for the NamedAttribute
+        private NamedAttribute namedAttributeNode;
+
+        JspAttribute(String qName, String uri, String localName, String value,
+		     boolean expr, ELNode.Nodes el, boolean dyn ) {
+	    this.qName = qName;
+	    this.uri = uri;
+	    this.localName = localName;
+	    this.value = value;
+            this.namedAttributeNode = null;
+	    this.expression = expr;
+            this.el = el;
+	    this.dynamic = dyn;
+            this.namedAttribute = false;
+	}
+
+        /**
+         * Use this constructor if the JspAttribute represents a
+         * named attribute.  In this case, we have to store the nodes of
+         * the body of the attribute.
+         */
+        JspAttribute(NamedAttribute na, boolean dyn) {
+            this.qName = na.getName();
+	    this.localName = na.getLocalName();
+            this.value = null;
+            this.namedAttributeNode = na;
+            this.expression = false;
+            this.el = null;
+	    this.dynamic = dyn;
+            this.namedAttribute = true;
+        }
+
+	/**
+ 	 * @return The name of the attribute
+	 */
+	public String getName() {
+	    return qName;
+	}
+
+	/**
+ 	 * @return The local name of the attribute
+	 */
+	public String getLocalName() {
+	    return localName;
+	}
+
+	/**
+ 	 * @return The namespace of the attribute, or null if in the default
+	 * namespace
+	 */
+	public String getURI() {
+	    return uri;
+	}
+
+	/**
+         * Only makes sense if namedAttribute is false.
+         *
+         * @return the value for the attribute, or the expression string
+         *         (stripped of "<%=", "%>", "%=", or "%"
+         *          but containing "${" and "}" for EL expressions)
+	 */
+	public String getValue() {
+	    return value;
+	}
+
+        /**
+         * Only makes sense if namedAttribute is true.
+         *
+         * @return the nodes that evaluate to the body of this attribute.
+         */
+        public NamedAttribute getNamedAttributeNode() {
+            return namedAttributeNode;
+        }
+
+	/**
+         * @return true if the value represents a traditional rtexprvalue
+	 */
+	public boolean isExpression() {
+	    return expression;
+	}
+
+        /**
+         * @return true if the value represents a NamedAttribute value.
+         */
+        public boolean isNamedAttribute() {
+            return namedAttribute;
+        }
+
+        /**
+         * @return true if the value represents an expression that should
+         * be fed to the expression interpreter
+         * @return false for string literals or rtexprvalues that should
+         * not be interpreted or reevaluated
+         */
+        public boolean isELInterpreterInput() {
+            return el != null;
+        }
+
+	/**
+	 * @return true if the value is a string literal known at translation
+	 * time.
+	 */
+	public boolean isLiteral() {
+	    return !expression && (el != null) && !namedAttribute;
+	}
+
+	/**
+	 * XXX
+	 */
+	public boolean isDynamic() {
+	    return dynamic;
+	}
+
+	public ELNode.Nodes getEL() {
+	    return el;
+	}
+    }
+
+    /**
+     * An ordered list of Node, used to represent the body of an element, or
+     * a jsp page of jsp document.
+     */
+    public static class Nodes {
+
+	private List list;
+	private Node.Root root;		// null if this is not a page
+	private boolean generatedInBuffer;
+
+	public Nodes() {
+	    list = new Vector();
+	}
+
+	public Nodes(Node.Root root) {
+	    this.root = root;
+	    list = new Vector();
+	    list.add(root);
+	}
+
+	/**
+	 * Appends a node to the list
+	 * @param n The node to add
+	 */
+	public void add(Node n) {
+	    list.add(n);
+	    root = null;
+	}
+
+	/**
+	 * Removes the given node from the list.
+	 * @param n The node to be removed
+	 */
+	public void remove(Node n) {
+	    list.remove(n);
+	}
+
+	/**
+	 * Visit the nodes in the list with the supplied visitor
+	 * @param v The visitor used
+	 */
+	public void visit(Visitor v) throws JasperException {
+	    Iterator iter = list.iterator();
+	    while (iter.hasNext()) {
+		Node n = (Node) iter.next();
+		n.accept(v);
+	    }
+	}
+
+	public int size() {
+	    return list.size();
+	}
+
+	public Node getNode(int index) {
+	    Node n = null;
+	    try {
+		n = (Node) list.get(index);
+	    } catch (ArrayIndexOutOfBoundsException e) {
+	    }
+	    return n;
+	}
+	
+	public Node.Root getRoot() {
+	    return root;
+	}
+
+	public boolean isGeneratedInBuffer() {
+	    return generatedInBuffer;
+	}
+
+	public void setGeneratedInBuffer(boolean g) {
+	    generatedInBuffer = g;
+	}
+    }
+
+    /**
+     * A visitor class for visiting the node.  This class also provides the
+     * default action (i.e. nop) for each of the child class of the Node.
+     * An actual visitor should extend this class and supply the visit
+     * method for the nodes that it cares.
+     */
+    public static class Visitor {
+
+	/**
+	 * This method provides a place to put actions that are common to
+	 * all nodes. Override this in the child visitor class if need to.
+	 */
+	protected void doVisit(Node n) throws JasperException {
+	}
+
+	/**
+	 * Visit the body of a node, using the current visitor
+	 */
+	protected void visitBody(Node n) throws JasperException {
+	    if (n.getBody() != null) {
+		n.getBody().visit(this);
+	    }
+	}
+
+	public void visit(Root n) throws JasperException {
+	    doVisit(n);
+	    visitBody(n);
+	}
+
+	public void visit(JspRoot n) throws JasperException {
+	    doVisit(n);
+	    visitBody(n);
+	}
+
+	public void visit(PageDirective n) throws JasperException {
+	    doVisit(n);
+	}
+
+	public void visit(TagDirective n) throws JasperException {
+	    doVisit(n);
+	}
+
+	public void visit(IncludeDirective n) throws JasperException {
+	    doVisit(n);
+	    visitBody(n);
+	}
+
+	public void visit(TaglibDirective n) throws JasperException {
+	    doVisit(n);
+	}
+
+	public void visit(AttributeDirective n) throws JasperException {
+	    doVisit(n);
+	}
+
+	public void visit(VariableDirective n) throws JasperException {
+	    doVisit(n);
+	}
+
+	public void visit(Comment n) throws JasperException {
+	    doVisit(n);
+	}
+
+	public void visit(Declaration n) throws JasperException {
+	    doVisit(n);
+	}
+
+	public void visit(Expression n) throws JasperException {
+	    doVisit(n);
+	}
+
+	public void visit(Scriptlet n) throws JasperException {
+	    doVisit(n);
+	}
+
+        public void visit(ELExpression n) throws JasperException {
+            doVisit(n);
+        }
+
+	public void visit(IncludeAction n) throws JasperException {
+	    doVisit(n);
+	    visitBody(n);
+	}
+
+	public void visit(ForwardAction n) throws JasperException {
+	    doVisit(n);
+	    visitBody(n);
+	}
+
+	public void visit(GetProperty n) throws JasperException {
+	    doVisit(n);
+	    visitBody(n);
+	}
+
+	public void visit(SetProperty n) throws JasperException {
+	    doVisit(n);
+	    visitBody(n);
+	}
+
+	public void visit(ParamAction n) throws JasperException {
+	    doVisit(n);
+	    visitBody(n);
+	}
+
+	public void visit(ParamsAction n) throws JasperException {
+	    doVisit(n);
+	    visitBody(n);
+	}
+
+	public void visit(FallBackAction n) throws JasperException {
+	    doVisit(n);
+	    visitBody(n);
+	}
+
+	public void visit(UseBean n) throws JasperException {
+	    doVisit(n);
+	    visitBody(n);
+	}
+
+	public void visit(PlugIn n) throws JasperException {
+	    doVisit(n);
+	    visitBody(n);
+	}
+
+	public void visit(CustomTag n) throws JasperException {
+	    doVisit(n);
+	    visitBody(n);
+	}
+
+	public void visit(UninterpretedTag n) throws JasperException {
+	    doVisit(n);
+	    visitBody(n);
+	}
+
+	public void visit(JspElement n) throws JasperException {
+	    doVisit(n);
+	    visitBody(n);
+	}
+
+	public void visit(JspText n) throws JasperException {
+	    doVisit(n);
+	    visitBody(n);
+	}
+
+        public void visit(NamedAttribute n) throws JasperException {
+            doVisit(n);
+            visitBody(n);
+        }
+
+        public void visit(JspBody n) throws JasperException {
+            doVisit(n);
+            visitBody(n);
+        }
+
+        public void visit(InvokeAction n) throws JasperException {
+            doVisit(n);
+            visitBody(n);
+        }
+
+        public void visit(DoBodyAction n) throws JasperException {
+            doVisit(n);
+            visitBody(n);
+        }
+
+	public void visit(TemplateText n) throws JasperException {
+	    doVisit(n);
+	}
+
+	public void visit(JspOutput n) throws JasperException {
+	    doVisit(n);
+	}
+
+	public void visit(AttributeGenerator n) throws JasperException {
+	    doVisit(n);
+	}
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/PageDataImpl.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/PageDataImpl.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/PageDataImpl.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,710 @@
+/*
+ * Copyright 1999,2004-2005 The Apache Software Foundation.
+ * 
+ * Licensed 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.InputStream;
+import java.io.ByteArrayInputStream;
+import java.io.CharArrayWriter;
+import java.io.UnsupportedEncodingException;
+import java.util.ListIterator;
+import javax.servlet.jsp.tagext.PageData;
+import org.xml.sax.Attributes;
+import org.xml.sax.helpers.AttributesImpl;
+import org.apache.jasper.JasperException;
+
+/**
+ * An implementation of <tt>javax.servlet.jsp.tagext.PageData</tt> which
+ * builds the XML view of a given page.
+ *
+ * The XML view is built in two passes:
+ *
+ * During the first pass, the FirstPassVisitor collects the attributes of the
+ * top-level jsp:root and those of the jsp:root elements of any included
+ * pages, and adds them to the jsp:root element of the XML view.
+ * In addition, any taglib directives are converted into xmlns: attributes and
+ * added to the jsp:root element of the XML view.
+ * This pass ignores any nodes other than JspRoot and TaglibDirective.
+ *
+ * During the second pass, the SecondPassVisitor produces the XML view, using
+ * the combined jsp:root attributes determined in the first pass and any
+ * remaining pages nodes (this pass ignores any JspRoot and TaglibDirective
+ * nodes).
+ *
+ * @author Jan Luehe
+ */
+class PageDataImpl extends PageData implements TagConstants {
+
+    private static final String JSP_VERSION = "2.0";
+    private static final String CDATA_START_SECTION = "<![CDATA[\n";
+    private static final String CDATA_END_SECTION = "]]>\n";
+
+    // string buffer used to build XML view
+    private StringBuffer buf;
+
+    /**
+     * Constructor.
+     *
+     * @param page the page nodes from which to generate the XML view
+     */
+    public PageDataImpl(Node.Nodes page, Compiler compiler)
+	        throws JasperException {
+
+	// First pass
+	FirstPassVisitor firstPass = new FirstPassVisitor(page.getRoot(),
+							  compiler.getPageInfo());
+	page.visit(firstPass);
+
+	// Second pass
+	buf = new StringBuffer();
+	SecondPassVisitor secondPass
+	    = new SecondPassVisitor(page.getRoot(), buf, compiler,
+				    firstPass.getJspIdPrefix());
+	page.visit(secondPass);
+    }
+
+    /**
+     * Returns the input stream of the XML view.
+     *
+     * @return the input stream of the XML view
+     */
+    public InputStream getInputStream() {
+	// Turn StringBuffer into InputStream
+        try {
+            return new ByteArrayInputStream(buf.toString().getBytes("UTF-8"));
+        } catch (UnsupportedEncodingException uee) {
+	    // should never happen
+            throw new RuntimeException(uee.toString());
+        }
+    }
+
+    /*
+     * First-pass Visitor for JspRoot nodes (representing jsp:root elements)
+     * and TablibDirective nodes, ignoring any other nodes.
+     *
+     * The purpose of this Visitor is to collect the attributes of the
+     * top-level jsp:root and those of the jsp:root elements of any included
+     * pages, and add them to the jsp:root element of the XML view.
+     * In addition, this Visitor converts any taglib directives into xmlns:
+     * attributes and adds them to the jsp:root element of the XML view.
+     */
+    static class FirstPassVisitor
+	        extends Node.Visitor implements TagConstants {
+
+	private Node.Root root;
+	private AttributesImpl rootAttrs;
+	private PageInfo pageInfo;
+
+	// Prefix for the 'id' attribute
+	private String jspIdPrefix;
+
+	/*
+	 * Constructor
+	 */
+	public FirstPassVisitor(Node.Root root, PageInfo pageInfo) {
+	    this.root = root;
+	    this.pageInfo = pageInfo;
+	    this.rootAttrs = new AttributesImpl();
+	    this.rootAttrs.addAttribute("", "", "version", "CDATA",
+					JSP_VERSION);
+	    this.jspIdPrefix = "jsp";
+	}
+
+	public void visit(Node.Root n) throws JasperException {
+	    visitBody(n);
+	    if (n == root) {
+		/*
+		 * Top-level page.
+		 *
+		 * Add
+		 *   xmlns:jsp="http://java.sun.com/JSP/Page"
+		 * attribute only if not already present.
+		 */
+		if (!JSP_URI.equals(rootAttrs.getValue("xmlns:jsp"))) {
+		    rootAttrs.addAttribute("", "", "xmlns:jsp", "CDATA",
+					   JSP_URI);
+		}
+
+		if (pageInfo.isJspPrefixHijacked()) {
+		    /*
+		     * 'jsp' prefix has been hijacked, that is, bound to a
+		     * namespace other than the JSP namespace. This means that
+		     * when adding an 'id' attribute to each element, we can't
+		     * use the 'jsp' prefix. Therefore, create a new prefix 
+		     * (one that is unique across the translation unit) for use
+		     * by the 'id' attribute, and bind it to the JSP namespace
+		     */
+		    jspIdPrefix += "jsp";
+		    while (pageInfo.containsPrefix(jspIdPrefix)) {
+			jspIdPrefix += "jsp";
+		    }
+		    rootAttrs.addAttribute("", "", "xmlns:" + jspIdPrefix,
+					   "CDATA", JSP_URI);
+		}
+
+		root.setAttributes(rootAttrs);
+	    }
+	}
+
+	public void visit(Node.JspRoot n) throws JasperException {
+	    addAttributes(n.getTaglibAttributes());
+            addAttributes(n.getNonTaglibXmlnsAttributes());
+	    addAttributes(n.getAttributes());
+
+	    visitBody(n);
+	}
+
+	/*
+	 * Converts taglib directive into "xmlns:..." attribute of jsp:root
+	 * element.
+	 */
+	public void visit(Node.TaglibDirective n) throws JasperException {
+	    Attributes attrs = n.getAttributes();
+	    if (attrs != null) {
+		String qName = "xmlns:" + attrs.getValue("prefix");
+		/*
+		 * According to javadocs of org.xml.sax.helpers.AttributesImpl,
+		 * the addAttribute method does not check to see if the
+		 * specified attribute is already contained in the list: This
+		 * is the application's responsibility!
+		 */
+		if (rootAttrs.getIndex(qName) == -1) {
+		    String location = attrs.getValue("uri");
+		    if (location != null) {
+                        if (location.startsWith("/")) {
+                            location = URN_JSPTLD + location;
+                        }
+			rootAttrs.addAttribute("", "", qName, "CDATA",
+					       location);
+		    } else {
+			location = attrs.getValue("tagdir");
+			rootAttrs.addAttribute("", "", qName, "CDATA",
+					       URN_JSPTAGDIR + location);
+		    }
+		}
+	    }
+	}
+
+	public String getJspIdPrefix() {
+	    return jspIdPrefix;
+	}
+
+	private void addAttributes(Attributes attrs) {
+	    if (attrs != null) {
+		int len = attrs.getLength();
+
+		for (int i=0; i<len; i++) {
+                    String qName = attrs.getQName(i);
+		    if ("version".equals(qName)) {
+			continue;
+		    }
+
+                    // Bugzilla 35252: http://issues.apache.org/bugzilla/show_bug.cgi?id=35252
+                    if(rootAttrs.getIndex(qName) == -1) {
+                        rootAttrs.addAttribute(attrs.getURI(i),
+                                               attrs.getLocalName(i),
+                                               qName,
+                                               attrs.getType(i),
+                                               attrs.getValue(i));
+                    }
+		}
+	    }
+	}
+    }
+
+
+    /*
+     * Second-pass Visitor responsible for producing XML view and assigning
+     * each element a unique jsp:id attribute.
+     */
+    static class SecondPassVisitor extends Node.Visitor
+        	implements TagConstants {
+
+	private Node.Root root;
+	private StringBuffer buf;
+	private Compiler compiler;
+	private String jspIdPrefix;
+	private boolean resetDefaultNS = false;
+
+	// Current value of jsp:id attribute
+	private int jspId;
+
+	/*
+	 * Constructor
+	 */
+	public SecondPassVisitor(Node.Root root, StringBuffer buf,
+				 Compiler compiler, String jspIdPrefix) {
+	    this.root = root;
+	    this.buf = buf;
+	    this.compiler = compiler;
+	    this.jspIdPrefix = jspIdPrefix;
+	}
+
+	/*
+	 * Visits root node.
+	 */
+	public void visit(Node.Root n) throws JasperException {
+	    if (n == this.root) {
+		// top-level page
+		appendXmlProlog();
+		appendTag(n);
+	    } else {
+		boolean resetDefaultNSSave = resetDefaultNS;
+		if (n.isXmlSyntax()) {
+		    resetDefaultNS = true;
+		}
+		visitBody(n);
+		resetDefaultNS = resetDefaultNSSave;
+	    }
+	}
+
+	/*
+	 * Visits jsp:root element of JSP page in XML syntax.
+	 *
+	 * Any nested jsp:root elements (from pages included via an
+	 * include directive) are ignored.
+	 */
+	public void visit(Node.JspRoot n) throws JasperException {
+	    visitBody(n);
+	}
+
+	public void visit(Node.PageDirective n) throws JasperException {
+	    appendPageDirective(n);
+	}
+
+	public void visit(Node.IncludeDirective n) throws JasperException {
+	    // expand in place
+	    visitBody(n);
+	}
+
+	public void visit(Node.Comment n) throws JasperException {
+	    // Comments are ignored in XML view
+	}
+
+	public void visit(Node.Declaration n) throws JasperException {
+	    appendTag(n);
+	}
+
+	public void visit(Node.Expression n) throws JasperException {
+	    appendTag(n);
+	}
+
+	public void visit(Node.Scriptlet n) throws JasperException {
+	    appendTag(n);
+	}
+
+	public void visit(Node.JspElement n) throws JasperException {
+	    appendTag(n);
+	}
+
+	public void visit(Node.ELExpression n) throws JasperException {
+	    if (!n.getRoot().isXmlSyntax()) {
+		buf.append("<").append(JSP_TEXT_ACTION);
+		buf.append(" ");
+	        buf.append(jspIdPrefix);
+		buf.append(":id=\"");
+		buf.append(jspId++).append("\">");
+	    }
+	    buf.append("${");
+            buf.append(JspUtil.escapeXml(n.getText()));
+	    buf.append("}");
+	    if (!n.getRoot().isXmlSyntax()) {
+		buf.append(JSP_TEXT_ACTION_END);
+	    }
+	    buf.append("\n");
+	}
+
+	public void visit(Node.IncludeAction n) throws JasperException {
+	    appendTag(n);
+	}
+    
+	public void visit(Node.ForwardAction n) throws JasperException {
+	    appendTag(n);
+	}
+
+	public void visit(Node.GetProperty n) throws JasperException {
+	    appendTag(n);
+	}
+
+	public void visit(Node.SetProperty n) throws JasperException {
+	    appendTag(n);
+	}
+
+	public void visit(Node.ParamAction n) throws JasperException {
+	    appendTag(n);
+	}
+
+	public void visit(Node.ParamsAction n) throws JasperException {
+	    appendTag(n);
+	}
+
+	public void visit(Node.FallBackAction n) throws JasperException {
+	    appendTag(n);
+	}
+
+	public void visit(Node.UseBean n) throws JasperException {
+	    appendTag(n);
+	}
+	
+	public void visit(Node.PlugIn n) throws JasperException {
+	    appendTag(n);
+	}
+
+        public void visit(Node.NamedAttribute n) throws JasperException {
+            appendTag(n);
+        }
+        
+        public void visit(Node.JspBody n) throws JasperException {
+            appendTag(n);
+        }
+
+	public void visit(Node.CustomTag n) throws JasperException {
+	    boolean resetDefaultNSSave = resetDefaultNS;
+	    appendTag(n, resetDefaultNS);
+	    resetDefaultNS = resetDefaultNSSave;
+	}
+
+	public void visit(Node.UninterpretedTag n) throws JasperException {
+	    boolean resetDefaultNSSave = resetDefaultNS;
+	    appendTag(n, resetDefaultNS);
+	    resetDefaultNS = resetDefaultNSSave;
+	}
+
+	public void visit(Node.JspText n) throws JasperException {
+	    appendTag(n);
+	}
+
+	public void visit(Node.DoBodyAction n) throws JasperException {
+	    appendTag(n);
+	}
+
+        public void visit(Node.InvokeAction n) throws JasperException {
+	    appendTag(n);
+	}
+
+	public void visit(Node.TagDirective n) throws JasperException {
+	    appendTagDirective(n);
+	}
+
+	public void visit(Node.AttributeDirective n) throws JasperException {
+	    appendTag(n);
+	}
+
+	public void visit(Node.VariableDirective n) throws JasperException {
+	    appendTag(n);
+	}
+        
+	public void visit(Node.TemplateText n) throws JasperException {
+	    /*
+	     * If the template text came from a JSP page written in JSP syntax,
+	     * create a jsp:text element for it (JSP 5.3.2).
+	     */
+	    appendText(n.getText(), !n.getRoot().isXmlSyntax());
+	}
+
+	/*
+	 * Appends the given tag, including its body, to the XML view.
+	 */
+	private void appendTag(Node n) throws JasperException {
+	    appendTag(n, false);
+	}
+
+	/*
+	 * Appends the given tag, including its body, to the XML view,
+	 * and optionally reset default namespace to "", if none specified.
+	 */
+	private void appendTag(Node n, boolean addDefaultNS)
+		throws JasperException {
+
+	    Node.Nodes body = n.getBody();
+	    String text = n.getText();
+
+	    buf.append("<").append(n.getQName());
+	    buf.append("\n");
+
+	    printAttributes(n, addDefaultNS);
+	    buf.append("  ").append(jspIdPrefix).append(":id").append("=\"");
+	    buf.append(jspId++).append("\"\n");
+
+	    if (ROOT_ACTION.equals(n.getLocalName()) || body != null
+		        || text != null) {
+		buf.append(">\n");
+		if (ROOT_ACTION.equals(n.getLocalName())) {
+		    if (compiler.getCompilationContext().isTagFile()) {
+			appendTagDirective();
+		    } else {
+			appendPageDirective();
+		    }
+		}
+		if (body != null) {
+		    body.visit(this);
+		} else {
+		    appendText(text, false);
+		}
+		buf.append("</" + n.getQName() + ">\n");
+	    } else {
+		buf.append("/>\n");
+	    }
+	}
+
+	/*
+	 * Appends the page directive with the given attributes to the XML
+	 * view.
+	 *
+	 * Since the import attribute of the page directive is the only page
+	 * attribute that is allowed to appear multiple times within the same
+	 * document, and since XML allows only single-value attributes,
+	 * the values of multiple import attributes must be combined into one,
+	 * separated by comma.
+	 *
+	 * If the given page directive contains just 'contentType' and/or
+	 * 'pageEncoding' attributes, we ignore it, as we've already appended
+	 * a page directive containing just these two attributes.
+	 */
+	private void appendPageDirective(Node.PageDirective n) {
+	    boolean append = false;
+	    Attributes attrs = n.getAttributes();
+	    int len = (attrs == null) ? 0 : attrs.getLength();
+	    for (int i=0; i<len; i++) {
+		String attrName = attrs.getQName(i);
+		if (!"pageEncoding".equals(attrName)
+		        && !"contentType".equals(attrName)) {
+		    append = true;
+		    break;
+		}
+	    }
+	    if (!append) {
+		return;
+	    }
+
+	    buf.append("<").append(n.getQName());
+	    buf.append("\n");
+
+	    // append jsp:id
+	    buf.append("  ").append(jspIdPrefix).append(":id").append("=\"");
+	    buf.append(jspId++).append("\"\n");
+
+	    // append remaining attributes
+	    for (int i=0; i<len; i++) {
+		String attrName = attrs.getQName(i);
+		if ("import".equals(attrName) || "contentType".equals(attrName)
+		        || "pageEncoding".equals(attrName)) {
+		    /*
+		     * Page directive's 'import' attribute is considered
+		     * further down, and its 'pageEncoding' and 'contentType'
+		     * attributes are ignored, since we've already appended
+		     * a new page directive containing just these two
+		     * attributes
+		     */
+		    continue;
+		}
+		String value = attrs.getValue(i);
+		buf.append("  ").append(attrName).append("=\"");
+		buf.append(JspUtil.getExprInXml(value)).append("\"\n");
+	    }
+	    if (n.getImports().size() > 0) {
+		// Concatenate names of imported classes/packages
+		boolean first = true;
+		ListIterator iter = n.getImports().listIterator();
+		while (iter.hasNext()) {
+		    if (first) {
+			first = false;
+			buf.append("  import=\"");
+		    } else {
+			buf.append(",");
+		    }
+		    buf.append(JspUtil.getExprInXml((String) iter.next()));
+		}
+		buf.append("\"\n");
+	    }
+	    buf.append("/>\n");
+	}
+
+	/*
+	 * Appends a page directive with 'pageEncoding' and 'contentType'
+	 * attributes.
+	 *
+	 * The value of the 'pageEncoding' attribute is hard-coded
+	 * to UTF-8, whereas the value of the 'contentType' attribute, which
+	 * is identical to what the container will pass to
+	 * ServletResponse.setContentType(), is derived from the pageInfo.
+	 */
+	private void appendPageDirective() {
+	    buf.append("<").append(JSP_PAGE_DIRECTIVE_ACTION);
+	    buf.append("\n");
+
+	    // append jsp:id
+	    buf.append("  ").append(jspIdPrefix).append(":id").append("=\"");
+	    buf.append(jspId++).append("\"\n");
+	    buf.append("  ").append("pageEncoding").append("=\"UTF-8\"\n");
+	    buf.append("  ").append("contentType").append("=\"");
+	    buf.append(compiler.getPageInfo().getContentType()).append("\"\n");
+	    buf.append("/>\n");	    
+	}
+
+	/*
+	 * Appends the tag directive with the given attributes to the XML
+	 * view.
+	 *
+	 * If the given tag directive contains just a 'pageEncoding'
+	 * attributes, we ignore it, as we've already appended
+	 * a tag directive containing just this attributes.
+	 */
+	private void appendTagDirective(Node.TagDirective n)
+	        throws JasperException {
+
+	    boolean append = false;
+	    Attributes attrs = n.getAttributes();
+	    int len = (attrs == null) ? 0 : attrs.getLength();
+	    for (int i=0; i<len; i++) {
+		String attrName = attrs.getQName(i);
+		if (!"pageEncoding".equals(attrName)) {
+		    append = true;
+		    break;
+		}
+	    }
+	    if (!append) {
+		return;
+	    }
+
+	    appendTag(n);
+	}
+
+	/*
+	 * Appends a tag directive containing a single 'pageEncoding'
+	 * attribute whose value is hard-coded to UTF-8.
+	 */
+	private void appendTagDirective() {
+	    buf.append("<").append(JSP_TAG_DIRECTIVE_ACTION);
+	    buf.append("\n");
+
+	    // append jsp:id
+	    buf.append("  ").append(jspIdPrefix).append(":id").append("=\"");
+	    buf.append(jspId++).append("\"\n");
+	    buf.append("  ").append("pageEncoding").append("=\"UTF-8\"\n");
+	    buf.append("/>\n");	    
+	}
+
+	private void appendText(String text, boolean createJspTextElement) {
+	    if (createJspTextElement) {
+		buf.append("<").append(JSP_TEXT_ACTION);
+		buf.append("\n");
+
+		// append jsp:id
+		buf.append("  ").append(jspIdPrefix).append(":id").append("=\"");
+		buf.append(jspId++).append("\"\n");
+		buf.append(">\n");
+
+		appendCDATA(text);
+		buf.append(JSP_TEXT_ACTION_END);
+		buf.append("\n");
+	    } else {
+		appendCDATA(text);
+	    }
+	}
+	
+	/*
+	 * Appends the given text as a CDATA section to the XML view, unless
+	 * the text has already been marked as CDATA.
+	 */
+	private void appendCDATA(String text) {
+	    buf.append(CDATA_START_SECTION);
+	    buf.append(escapeCDATA(text));
+	    buf.append(CDATA_END_SECTION);
+	}
+
+	/*
+	 * Escapes any occurrences of "]]>" (by replacing them with "]]&gt;")
+	 * within the given text, so it can be included in a CDATA section.
+	 */
+	private String escapeCDATA(String text) {
+            if( text==null ) return "";
+	    int len = text.length();
+	    CharArrayWriter result = new CharArrayWriter(len);
+	    for (int i=0; i<len; i++) {
+		if (((i+2) < len)
+		        && (text.charAt(i) == ']')
+		        && (text.charAt(i+1) == ']')
+		        && (text.charAt(i+2) == '>')) {
+		    // match found
+		    result.write(']');
+		    result.write(']');
+		    result.write('&');
+		    result.write('g');
+		    result.write('t');
+		    result.write(';');
+		    i += 2;
+		} else {
+		    result.write(text.charAt(i));
+		}
+	    }
+	    return result.toString();
+	}
+
+	/*
+	 * Appends the attributes of the given Node to the XML view.
+	 */
+	private void printAttributes(Node n, boolean addDefaultNS) {
+
+	    /*
+	     * Append "xmlns" attributes that represent tag libraries
+	     */
+	    Attributes attrs = n.getTaglibAttributes();
+	    int len = (attrs == null) ? 0 : attrs.getLength();
+	    for (int i=0; i<len; i++) {
+		String name = attrs.getQName(i);
+		String value = attrs.getValue(i);
+		buf.append("  ").append(name).append("=\"").append(value).append("\"\n");
+	    }
+
+	    /*
+	     * Append "xmlns" attributes that do not represent tag libraries
+	     */
+	    attrs = n.getNonTaglibXmlnsAttributes();
+	    len = (attrs == null) ? 0 : attrs.getLength();
+	    boolean defaultNSSeen = false;
+	    for (int i=0; i<len; i++) {
+		String name = attrs.getQName(i);
+		String value = attrs.getValue(i);
+		buf.append("  ").append(name).append("=\"").append(value).append("\"\n");
+		defaultNSSeen |= "xmlns".equals(name);
+	    }
+	    if (addDefaultNS && !defaultNSSeen) {
+		buf.append("  xmlns=\"\"\n");
+	    }
+	    resetDefaultNS = false;
+
+	    /*
+	     * Append all other attributes
+	     */
+	    attrs = n.getAttributes();
+	    len = (attrs == null) ? 0 : attrs.getLength();
+	    for (int i=0; i<len; i++) {
+		String name = attrs.getQName(i);
+		String value = attrs.getValue(i);
+		buf.append("  ").append(name).append("=\"");
+		buf.append(JspUtil.getExprInXml(value)).append("\"\n");
+	    }
+	}
+
+	/*
+	 * Appends XML prolog with encoding declaration.
+	 */
+	private void appendXmlProlog() {
+	    buf.append("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n");
+	}
+    }
+}
+

Added: branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/PageInfo.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/PageInfo.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/PageInfo.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,628 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ *
+ * Licensed 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.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Vector;
+
+import org.apache.jasper.Constants;
+import org.apache.jasper.JasperException;
+import javax.servlet.jsp.tagext.TagLibraryInfo;
+
+/**
+ * A repository for various info about the translation unit under compilation.
+ *
+ * @author Kin-man Chung
+ */
+
+class PageInfo {
+
+    private Vector imports;
+    private Vector dependants;
+
+    private BeanRepository beanRepository;
+    private HashMap taglibsMap;
+    private HashMap jspPrefixMapper;
+    private HashMap xmlPrefixMapper;
+    private HashMap nonCustomTagPrefixMap;
+    private String jspFile;
+    private String defaultLanguage = "java";
+    private String language;
+    private String defaultExtends = Constants.JSP_SERVLET_BASE;
+    private String xtends;
+    private String contentType = null;
+    private String session;
+    private boolean isSession = true;
+    private String bufferValue;
+    private int buffer = 8*1024;    // XXX confirm
+    private String autoFlush;
+    private boolean isAutoFlush = true;
+    private String isThreadSafeValue;
+    private boolean isThreadSafe = true;
+    private String isErrorPageValue;
+    private boolean isErrorPage = false;
+    private String errorPage = null;
+    private String info;
+
+    private boolean scriptless = false;
+    private boolean scriptingInvalid = false;
+    private String isELIgnoredValue;
+    private boolean isELIgnored = false;
+    private String omitXmlDecl = null;
+    private String doctypeName = null;
+    private String doctypePublic = null;
+    private String doctypeSystem = null;
+
+    private boolean isJspPrefixHijacked;
+
+    // Set of all element and attribute prefixes used in this translation unit
+    private HashSet prefixes;
+
+    private boolean hasJspRoot = false;
+    private Vector includePrelude;
+    private Vector includeCoda;
+    private Vector pluginDcls;      // Id's for tagplugin declarations
+
+
+    PageInfo(BeanRepository beanRepository, String jspFile) {
+
+        this.jspFile = jspFile;
+        this.beanRepository = beanRepository;
+        this.taglibsMap = new HashMap();
+        this.jspPrefixMapper = new HashMap();
+        this.xmlPrefixMapper = new HashMap();
+        this.nonCustomTagPrefixMap = new HashMap();
+        this.imports = new Vector();
+        this.dependants = new Vector();
+        this.includePrelude = new Vector();
+        this.includeCoda = new Vector();
+        this.pluginDcls = new Vector();
+        this.prefixes = new HashSet();
+
+        // Enter standard imports
+        for(int i = 0; i < Constants.STANDARD_IMPORTS.length; i++)
+            imports.add(Constants.STANDARD_IMPORTS[i]);
+    }
+
+    /**
+     * Check if the plugin ID has been previously declared.  Make a not
+     * that this Id is now declared.
+     * @return true if Id has been declared.
+     */
+    public boolean isPluginDeclared(String id) {
+        if (pluginDcls.contains(id))
+            return true;
+        pluginDcls.add(id);
+        return false;
+    }
+
+    public void addImports(List imports) {
+        this.imports.addAll(imports);
+    }
+
+    public void addImport(String imp) {
+        this.imports.add(imp);
+    }
+
+    public List getImports() {
+        return imports;
+    }
+
+    public String getJspFile() {
+        return jspFile;
+    }
+
+    public void addDependant(String d) {
+        if (!dependants.contains(d) && !jspFile.equals(d))
+                dependants.add(d);
+    }
+
+    public List getDependants() {
+        return dependants;
+    }
+
+    public BeanRepository getBeanRepository() {
+        return beanRepository;
+    }
+
+    public void setScriptless(boolean s) {
+        scriptless = s;
+    }
+
+    public boolean isScriptless() {
+        return scriptless;
+    }
+
+    public void setScriptingInvalid(boolean s) {
+        scriptingInvalid = s;
+    }
+
+    public boolean isScriptingInvalid() {
+        return scriptingInvalid;
+    }
+
+    public List getIncludePrelude() {
+        return includePrelude;
+    }
+
+    public void setIncludePrelude(Vector prelude) {
+        includePrelude = prelude;
+    }
+
+    public List getIncludeCoda() {
+        return includeCoda;
+    }
+
+    public void setIncludeCoda(Vector coda) {
+        includeCoda = coda;
+    }
+
+    public void setHasJspRoot(boolean s) {
+        hasJspRoot = s;
+    }
+
+    public boolean hasJspRoot() {
+        return hasJspRoot;
+    }
+
+    public String getOmitXmlDecl() {
+        return omitXmlDecl;
+    }
+
+    public void setOmitXmlDecl(String omit) {
+        omitXmlDecl = omit;
+    }
+
+    public String getDoctypeName() {
+        return doctypeName;
+    }
+
+    public void setDoctypeName(String doctypeName) {
+        this.doctypeName = doctypeName;
+    }
+
+    public String getDoctypeSystem() {
+        return doctypeSystem;
+    }
+
+    public void setDoctypeSystem(String doctypeSystem) {
+        this.doctypeSystem = doctypeSystem;
+    }
+
+    public String getDoctypePublic() {
+        return doctypePublic;
+    }
+
+    public void setDoctypePublic(String doctypePublic) {
+        this.doctypePublic = doctypePublic;
+    }
+
+    /* Tag library and XML namespace management methods */
+
+    public void setIsJspPrefixHijacked(boolean isHijacked) {
+        isJspPrefixHijacked = isHijacked;
+    }
+
+    public boolean isJspPrefixHijacked() {
+        return isJspPrefixHijacked;
+    }
+
+    /*
+     * Adds the given prefix to the set of prefixes of this translation unit.
+     *
+     * @param prefix The prefix to add
+     */
+    public void addPrefix(String prefix) {
+        prefixes.add(prefix);
+    }
+
+    /*
+     * Checks to see if this translation unit contains the given prefix.
+     *
+     * @param prefix The prefix to check
+     *
+     * @return true if this translation unit contains the given prefix, false
+     * otherwise
+     */
+    public boolean containsPrefix(String prefix) {
+        return prefixes.contains(prefix);
+    }
+
+    /*
+     * Maps the given URI to the given tag library.
+     *
+     * @param uri The URI to map
+     * @param info The tag library to be associated with the given URI
+     */
+    public void addTaglib(String uri, TagLibraryInfo info) {
+        taglibsMap.put(uri, info);
+    }
+
+    /*
+     * Gets the tag library corresponding to the given URI.
+     *
+     * @return Tag library corresponding to the given URI
+     */
+    public TagLibraryInfo getTaglib(String uri) {
+        return (TagLibraryInfo) taglibsMap.get(uri);
+    }
+
+    /*
+     * Gets the collection of tag libraries that are associated with a URI
+     *
+     * @return Collection of tag libraries that are associated with a URI
+     */
+    public Collection getTaglibs() {
+        return taglibsMap.values();
+    }
+
+    /*
+     * Checks to see if the given URI is mapped to a tag library.
+     *
+     * @param uri The URI to map
+     *
+     * @return true if the given URI is mapped to a tag library, false
+     * otherwise
+     */
+    public boolean hasTaglib(String uri) {
+        return taglibsMap.containsKey(uri);
+    }
+
+    /*
+     * Maps the given prefix to the given URI.
+     *
+     * @param prefix The prefix to map
+     * @param uri The URI to be associated with the given prefix
+     */
+    public void addPrefixMapping(String prefix, String uri) {
+        jspPrefixMapper.put(prefix, uri);
+    }
+
+    /*
+     * Pushes the given URI onto the stack of URIs to which the given prefix
+     * is mapped.
+     *
+     * @param prefix The prefix whose stack of URIs is to be pushed
+     * @param uri The URI to be pushed onto the stack
+     */
+    public void pushPrefixMapping(String prefix, String uri) {
+        LinkedList stack = (LinkedList) xmlPrefixMapper.get(prefix);
+        if (stack == null) {
+            stack = new LinkedList();
+            xmlPrefixMapper.put(prefix, stack);
+        }
+        stack.addFirst(uri);
+    }
+
+    /*
+     * Removes the URI at the top of the stack of URIs to which the given
+     * prefix is mapped.
+     *
+     * @param prefix The prefix whose stack of URIs is to be popped
+     */
+    public void popPrefixMapping(String prefix) {
+        LinkedList stack = (LinkedList) xmlPrefixMapper.get(prefix);
+        if (stack == null || stack.size() == 0) {
+            // XXX throw new Exception("XXX");
+        }
+        stack.removeFirst();
+    }
+
+    /*
+     * Returns the URI to which the given prefix maps.
+     *
+     * @param prefix The prefix whose URI is sought
+     *
+     * @return The URI to which the given prefix maps
+     */
+    public String getURI(String prefix) {
+
+        String uri = null;
+
+        LinkedList stack = (LinkedList) xmlPrefixMapper.get(prefix);
+        if (stack == null || stack.size() == 0) {
+            uri = (String) jspPrefixMapper.get(prefix);
+        } else {
+            uri = (String) stack.getFirst();
+        }
+
+        return uri;
+    }
+
+
+    /* Page/Tag directive attributes */
+
+    /*
+     * language
+     */
+    public void setLanguage(String value, Node n, ErrorDispatcher err,
+                boolean pagedir)
+        throws JasperException {
+
+        if (!"java".equalsIgnoreCase(value)) {
+            if (pagedir)
+                err.jspError(n, "jsp.error.page.language.nonjava");
+            else
+                err.jspError(n, "jsp.error.tag.language.nonjava");
+        }
+
+        language = value;
+    }
+
+    public String getLanguage(boolean useDefault) {
+        return (language == null && useDefault ? defaultLanguage : language);
+    }
+
+    public String getLanguage() {
+        return getLanguage(true);
+    }
+
+
+    /*
+     * extends
+     */
+    public void setExtends(String value, Node.PageDirective n) {
+
+        xtends = value;
+
+        /*
+         * If page superclass is top level class (i.e. not in a package)
+         * explicitly import it. If this is not done, the compiler will assume
+         * the extended class is in the same pkg as the generated servlet.
+         */
+        if (value.indexOf('.') < 0)
+            n.addImport(value);
+    }
+
+    /**
+     * Gets the value of the 'extends' page directive attribute.
+     *
+     * @param useDefault TRUE if the default
+     * (org.apache.jasper.runtime.HttpJspBase) should be returned if this
+     * attribute has not been set, FALSE otherwise
+     *
+     * @return The value of the 'extends' page directive attribute, or the
+     * default (org.apache.jasper.runtime.HttpJspBase) if this attribute has
+     * not been set and useDefault is TRUE
+     */
+    public String getExtends(boolean useDefault) {
+        return (xtends == null && useDefault ? defaultExtends : xtends);
+    }
+
+    /**
+     * Gets the value of the 'extends' page directive attribute.
+     *
+     * @return The value of the 'extends' page directive attribute, or the
+     * default (org.apache.jasper.runtime.HttpJspBase) if this attribute has
+     * not been set
+     */
+    public String getExtends() {
+        return getExtends(true);
+    }
+
+
+    /*
+     * contentType
+     */
+    public void setContentType(String value) {
+        contentType = value;
+    }
+
+    public String getContentType() {
+        return contentType;
+    }
+
+
+    /*
+     * buffer
+     */
+    public void setBufferValue(String value, Node n, ErrorDispatcher err)
+        throws JasperException {
+
+        if ("none".equalsIgnoreCase(value))
+            buffer = 0;
+        else {
+            if (value == null || !value.endsWith("kb"))
+                err.jspError(n, "jsp.error.page.invalid.buffer");
+            try {
+                Integer k = new Integer(value.substring(0, value.length()-2));
+                buffer = k.intValue() * 1024;
+            } catch (NumberFormatException e) {
+                err.jspError(n, "jsp.error.page.invalid.buffer");
+            }
+        }
+
+        bufferValue = value;
+    }
+
+    public String getBufferValue() {
+        return bufferValue;
+    }
+
+    public int getBuffer() {
+        return buffer;
+    }
+
+
+    /*
+     * session
+     */
+    public void setSession(String value, Node n, ErrorDispatcher err)
+        throws JasperException {
+
+        if ("true".equalsIgnoreCase(value))
+            isSession = true;
+        else if ("false".equalsIgnoreCase(value))
+            isSession = false;
+        else
+            err.jspError(n, "jsp.error.page.invalid.session");
+
+        session = value;
+    }
+
+    public String getSession() {
+        return session;
+    }
+
+    public boolean isSession() {
+        return isSession;
+    }
+
+
+    /*
+     * autoFlush
+     */
+    public void setAutoFlush(String value, Node n, ErrorDispatcher err)
+        throws JasperException {
+
+        if ("true".equalsIgnoreCase(value))
+            isAutoFlush = true;
+        else if ("false".equalsIgnoreCase(value))
+            isAutoFlush = false;
+        else
+            err.jspError(n, "jsp.error.autoFlush.invalid");
+
+        autoFlush = value;
+    }
+
+    public String getAutoFlush() {
+        return autoFlush;
+    }
+
+    public boolean isAutoFlush() {
+        return isAutoFlush;
+    }
+
+
+    /*
+     * isThreadSafe
+     */
+    public void setIsThreadSafe(String value, Node n, ErrorDispatcher err)
+        throws JasperException {
+
+        if ("true".equalsIgnoreCase(value))
+            isThreadSafe = true;
+        else if ("false".equalsIgnoreCase(value))
+            isThreadSafe = false;
+        else
+            err.jspError(n, "jsp.error.page.invalid.isthreadsafe");
+
+        isThreadSafeValue = value;
+    }
+
+    public String getIsThreadSafe() {
+        return isThreadSafeValue;
+    }
+
+    public boolean isThreadSafe() {
+        return isThreadSafe;
+    }
+
+
+    /*
+     * info
+     */
+    public void setInfo(String value) {
+        info = value;
+    }
+
+    public String getInfo() {
+        return info;
+    }
+
+
+    /*
+     * errorPage
+     */
+    public void setErrorPage(String value) {
+        errorPage = value;
+    }
+
+    public String getErrorPage() {
+        return errorPage;
+    }
+
+
+    /*
+     * isErrorPage
+     */
+    public void setIsErrorPage(String value, Node n, ErrorDispatcher err)
+        throws JasperException {
+
+        if ("true".equalsIgnoreCase(value))
+            isErrorPage = true;
+        else if ("false".equalsIgnoreCase(value))
+            isErrorPage = false;
+        else
+            err.jspError(n, "jsp.error.page.invalid.iserrorpage");
+
+        isErrorPageValue = value;
+    }
+
+    public String getIsErrorPage() {
+        return isErrorPageValue;
+    }
+
+    public boolean isErrorPage() {
+        return isErrorPage;
+    }
+
+
+    /*
+     * isELIgnored
+     */
+    public void setIsELIgnored(String value, Node n, ErrorDispatcher err,
+                   boolean pagedir)
+        throws JasperException {
+
+        if ("true".equalsIgnoreCase(value))
+            isELIgnored = true;
+        else if ("false".equalsIgnoreCase(value))
+            isELIgnored = false;
+        else {
+            if (pagedir)
+                err.jspError(n, "jsp.error.page.invalid.iselignored");
+            else
+                err.jspError(n, "jsp.error.tag.invalid.iselignored");
+        }
+
+        isELIgnoredValue = value;
+    }
+
+    public void setELIgnored(boolean s) {
+        isELIgnored = s;
+    }
+
+    public String getIsELIgnored() {
+        return isELIgnoredValue;
+    }
+
+    public boolean isELIgnored() {
+        return isELIgnored;
+    }
+
+    public void putNonCustomTagPrefix(String prefix, Mark where) {
+        nonCustomTagPrefixMap.put(prefix, where);
+    }
+
+    public Mark getNonCustomTagPrefix(String prefix) {
+        return (Mark) nonCustomTagPrefixMap.get(prefix);
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/Parser.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/Parser.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/Parser.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,1936 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.CharArrayWriter;
+import java.io.FileNotFoundException;
+import java.net.URL;
+import java.util.Iterator;
+import java.util.List;
+
+import javax.servlet.jsp.tagext.TagAttributeInfo;
+import javax.servlet.jsp.tagext.TagFileInfo;
+import javax.servlet.jsp.tagext.TagInfo;
+import javax.servlet.jsp.tagext.TagLibraryInfo;
+
+import org.apache.jasper.Constants;
+import org.apache.jasper.JasperException;
+import org.apache.jasper.JspCompilationContext;
+import org.xml.sax.Attributes;
+import org.xml.sax.helpers.AttributesImpl;
+
+/**
+ * This class implements a parser for a JSP page (non-xml view).
+ * JSP page grammar is included here for reference.  The token '#'
+ * that appears in the production indicates the current input token
+ * location in the production.
+ * 
+ * @author Kin-man Chung
+ * @author Shawn Bayern
+ * @author Mark Roth
+ */
+
+class Parser implements TagConstants {
+
+    private ParserController parserController;
+    private JspCompilationContext ctxt;
+    private JspReader reader;
+    private String currentFile;
+    private Mark start;
+    private ErrorDispatcher err;
+    private int scriptlessCount;
+    private boolean isTagFile;
+    private boolean directivesOnly;
+    private URL jarFileUrl;
+    private PageInfo pageInfo;
+
+    // Virtual body content types, to make parsing a little easier.
+    // These are not accessible from outside the parser.
+    private static final String JAVAX_BODY_CONTENT_PARAM = 
+        "JAVAX_BODY_CONTENT_PARAM";
+    private static final String JAVAX_BODY_CONTENT_PLUGIN = 
+        "JAVAX_BODY_CONTENT_PLUGIN";
+    private static final String JAVAX_BODY_CONTENT_TEMPLATE_TEXT = 
+        "JAVAX_BODY_CONTENT_TEMPLATE_TEXT";
+
+    /**
+     * The constructor
+     */
+    private Parser(ParserController pc, JspReader reader, boolean isTagFile,
+                   boolean directivesOnly, URL jarFileUrl) {
+        this.parserController = pc;
+        this.ctxt = pc.getJspCompilationContext();
+        this.pageInfo = pc.getCompiler().getPageInfo();
+        this.err = pc.getCompiler().getErrorDispatcher();
+        this.reader = reader;
+        this.currentFile = reader.mark().getFile();
+        this.scriptlessCount = 0;
+        this.isTagFile = isTagFile;
+        this.directivesOnly = directivesOnly;
+        this.jarFileUrl = jarFileUrl;
+        start = reader.mark();
+    }
+
+    /**
+     * The main entry for Parser
+     * 
+     * @param pc The ParseController, use for getting other objects in compiler
+     *                 and for parsing included pages
+     * @param reader To read the page
+     * @param parent The parent node to this page, null for top level page
+     * @return list of nodes representing the parsed page
+     */
+    public static Node.Nodes parse(ParserController pc,
+                                   JspReader reader,
+                                   Node parent,
+                                   boolean isTagFile,
+                                   boolean directivesOnly,
+                                   URL jarFileUrl,
+                                   String pageEnc,
+                                   String jspConfigPageEnc,
+                                   boolean isDefaultPageEncoding)
+                throws JasperException {
+
+        Parser parser = new Parser(pc, reader, isTagFile, directivesOnly,
+                                   jarFileUrl);
+
+        Node.Root root = new Node.Root(reader.mark(), parent, false);
+        root.setPageEncoding(pageEnc);
+        root.setJspConfigPageEncoding(jspConfigPageEnc);
+        root.setIsDefaultPageEncoding(isDefaultPageEncoding);
+
+        if (directivesOnly) {
+            parser.parseTagFileDirectives(root);
+            return new Node.Nodes(root);
+        }
+
+        // For the Top level page, add inlcude-prelude and include-coda
+        PageInfo pageInfo = pc.getCompiler().getPageInfo();
+        if (parent == null) {
+            parser.addInclude(root, pageInfo.getIncludePrelude());
+        }
+        while (reader.hasMoreInput()) {
+            parser.parseElements(root);
+        }
+        if (parent == null) {
+            parser.addInclude(root, pageInfo.getIncludeCoda());
+        }
+
+        Node.Nodes page = new Node.Nodes(root);
+        return page;
+    }
+
+    /**
+     * Attributes ::= (S Attribute)* S?
+     */
+    Attributes parseAttributes() throws JasperException {
+        AttributesImpl attrs = new AttributesImpl();
+
+        reader.skipSpaces();
+        while (parseAttribute(attrs))
+            reader.skipSpaces();
+
+        return attrs;
+    }
+
+    /**
+     * Parse Attributes for a reader, provided for external use
+     */
+    public static Attributes parseAttributes(ParserController pc,
+                                             JspReader reader)
+                throws JasperException {
+        Parser tmpParser = new Parser(pc, reader, false, false, null);
+        return tmpParser.parseAttributes();
+    }
+
+    /**
+     * Attribute ::= Name S? Eq S?
+     *               (   '"<%=' RTAttributeValueDouble
+     *                 | '"' AttributeValueDouble
+     *                 | "'<%=" RTAttributeValueSingle
+     *                 | "'" AttributeValueSingle
+     *               }
+     * Note: JSP and XML spec does not allow while spaces around Eq.  It is
+     * added to be backward compatible with Tomcat, and with other xml parsers.
+     */
+    private boolean parseAttribute(AttributesImpl attrs)
+                throws JasperException {
+
+        // Get the qualified name
+        String qName = parseName();
+        if (qName == null)
+            return false;
+
+        // Determine prefix and local name components
+        String localName = qName;
+        String uri = "";
+        int index = qName.indexOf(':');
+        if (index != -1) {
+            String prefix = qName.substring(0, index);
+            uri = pageInfo.getURI(prefix);
+            if (uri == null) {
+                err.jspError(reader.mark(),
+                             "jsp.error.attribute.invalidPrefix", prefix);
+            }
+            localName = qName.substring(index+1);
+        }
+
+         reader.skipSpaces();
+        if (!reader.matches("="))
+            err.jspError(reader.mark(), "jsp.error.attribute.noequal");
+
+         reader.skipSpaces();
+        char quote = (char) reader.nextChar();
+        if (quote != '\'' && quote != '"')
+            err.jspError(reader.mark(), "jsp.error.attribute.noquote");
+
+         String watchString = "";
+        if (reader.matches("<%="))
+            watchString = "%>";
+        watchString = watchString + quote;
+        
+        String attrValue = parseAttributeValue(watchString);
+        attrs.addAttribute(uri, localName, qName, "CDATA", attrValue);
+        return true;
+    }
+
+    /**
+     * Name ::= (Letter | '_' | ':') (Letter | Digit | '.' | '_' | '-' | ':')*
+     */
+    private String parseName() throws JasperException {
+        char ch = (char)reader.peekChar();
+        if (Character.isLetter(ch) || ch == '_' || ch == ':') {
+            StringBuffer buf = new StringBuffer();
+            buf.append(ch);
+            reader.nextChar();
+            ch = (char)reader.peekChar();
+            while (Character.isLetter(ch) || Character.isDigit(ch) ||
+                        ch == '.' || ch == '_' || ch == '-' || ch == ':') {
+                buf.append(ch);
+                reader.nextChar();
+                ch = (char) reader.peekChar();
+            }
+            return buf.toString();
+        }
+        return null;
+    }
+
+    /**
+     * AttributeValueDouble ::= (QuotedChar - '"')*
+     *                                ('"' | <TRANSLATION_ERROR>)
+     * RTAttributeValueDouble ::= ((QuotedChar - '"')* - ((QuotedChar-'"')'%>"')
+     *                                  ('%>"' | TRANSLATION_ERROR)
+     */
+    private String parseAttributeValue(String watch) throws JasperException {
+        Mark start = reader.mark();
+        Mark stop = reader.skipUntilIgnoreEsc(watch);
+        if (stop == null) {
+            err.jspError(start, "jsp.error.attribute.unterminated", watch);
+        }
+
+        String ret = parseQuoted(reader.getText(start, stop));
+        if (watch.length() == 1)        // quote
+            return ret;
+
+        // putback delimiter '<%=' and '%>', since they are needed if the
+        // attribute does not allow RTexpression.
+        return "<%=" + ret + "%>";
+    }
+
+    /**
+     * QuotedChar ::=   '&apos;'
+     *                      | '&quot;'
+     *                | '\\'
+     *                | '\"'
+     *                | "\'"
+     *                | '\>'
+     *                | '\$'
+     *                | Char
+     */
+    private String parseQuoted(String tx) {
+        StringBuffer buf = new StringBuffer();
+        int size = tx.length();
+        int i = 0;
+        while (i < size) {
+            char ch = tx.charAt(i);
+            if (ch == '&') {
+                if (i+5 < size && tx.charAt(i+1) == 'a'
+                        && tx.charAt(i+2) == 'p' && tx.charAt(i+3) == 'o'
+                        && tx.charAt(i+4) == 's' && tx.charAt(i+5) == ';') {
+                    buf.append('\'');
+                    i += 6;
+                } else if (i+5 < size && tx.charAt(i+1) == 'q'
+                           && tx.charAt(i+2) == 'u' && tx.charAt(i+3) == 'o'
+                           && tx.charAt(i+4) == 't' && tx.charAt(i+5) == ';') {
+                    buf.append('"');
+                    i += 6;
+                } else {
+                    buf.append(ch);
+                    ++i;
+                }
+            } else if (ch == '\\' && i+1 < size) {
+                ch = tx.charAt(i+1);
+                if (ch == '\\' || ch == '\"' || ch == '\'' || ch == '>') {
+                    buf.append(ch);
+                    i += 2;
+                } else if (ch == '$') {
+                    // Replace "\$" with some special char.  XXX hack!
+                    buf.append(Constants.ESC);
+                    i += 2;
+                } else {
+                    buf.append('\\');
+                    ++i;
+                }
+            } else {
+                buf.append(ch);
+                ++i;
+            }
+        }
+        return buf.toString();
+    }
+
+    private String parseScriptText(String tx) {
+        CharArrayWriter cw = new CharArrayWriter();
+        int size = tx.length();
+        int i = 0;
+        while (i < size) {
+            char ch = tx.charAt(i);
+            if (i+2 < size && ch == '%' && tx.charAt(i+1) == '\\'
+                    && tx.charAt(i+2) == '>') {
+                cw.write('%');
+                cw.write('>');
+                i += 3;
+            } else {
+                cw.write(ch);
+                ++i;
+            }
+        }
+        cw.close();
+        return cw.toString();
+    }
+
+    /*
+     * Invokes parserController to parse the included page
+     */
+    private void processIncludeDirective(String file, Node parent) 
+                throws JasperException {
+        if (file == null) {
+            return;
+        }
+
+        try {
+            parserController.parse(file, parent, jarFileUrl);
+        } catch (FileNotFoundException ex) {
+            err.jspError(start, "jsp.error.file.not.found", file);
+        } catch (Exception ex) {
+            err.jspError(start, ex.getMessage());
+        }
+    }
+
+    /*
+     * Parses a page directive with the following syntax:
+     *   PageDirective ::= ( S Attribute)*
+     */
+    private void parsePageDirective(Node parent) throws JasperException {
+        Attributes attrs = parseAttributes();
+        Node.PageDirective n = new Node.PageDirective(attrs, start, parent);
+
+        /*
+         * A page directive may contain multiple 'import' attributes, each of
+         * which consists of a comma-separated list of package names.
+         * Store each list with the node, where it is parsed.
+         */
+        for (int i = 0; i < attrs.getLength(); i++) {
+            if ("import".equals(attrs.getQName(i))) {
+                n.addImport(attrs.getValue(i));
+            }
+        }
+    }
+
+    /*
+     * Parses an include directive with the following syntax:
+     *   IncludeDirective ::= ( S Attribute)*
+     */
+    private void parseIncludeDirective(Node parent) throws JasperException {
+        Attributes attrs = parseAttributes();
+
+        // Included file expanded here
+        Node includeNode = new Node.IncludeDirective(attrs, start, parent);
+        processIncludeDirective(attrs.getValue("file"), includeNode);
+    }
+
+    /**
+     * Add a list of files.  This is used for implementing include-prelude
+     * and include-coda of jsp-config element in web.xml
+     */
+    private void addInclude(Node parent, List files) throws JasperException {
+        if( files != null ) {
+            Iterator iter = files.iterator();
+            while (iter.hasNext()) {
+                String file = (String) iter.next();
+                AttributesImpl attrs = new AttributesImpl();
+                attrs.addAttribute("", "file", "file", "CDATA", file);
+
+                // Create a dummy Include directive node
+                Node includeNode = new Node.IncludeDirective(attrs, 
+                    reader.mark(), parent);
+                processIncludeDirective(file, includeNode);
+            }
+        }
+    }
+
+    /*
+     * Parses a taglib directive with the following syntax:
+     *   Directive ::= ( S Attribute)*
+     */
+    private void parseTaglibDirective(Node parent) throws JasperException {
+
+        Attributes attrs = parseAttributes();
+        String uri = attrs.getValue("uri");
+        String prefix = attrs.getValue("prefix");
+        if (prefix != null) {
+            Mark prevMark = pageInfo.getNonCustomTagPrefix(prefix);
+            if (prevMark != null) {
+                err.jspError(reader.mark(), "jsp.error.prefix.use_before_dcl",
+                    prefix, prevMark.getFile(), "" + prevMark.getLineNumber());
+            }
+            if (uri != null) {
+                String uriPrev = pageInfo.getURI(prefix);
+                if (uriPrev != null && !uriPrev.equals(uri)) {
+                    err.jspError(reader.mark(), "jsp.error.prefix.refined",
+                        prefix, uri, uriPrev);
+                }
+                if (pageInfo.getTaglib(uri) == null) {
+            TagLibraryInfoImpl impl = null;
+            if (ctxt.getOptions().isCaching()) {
+                impl = (TagLibraryInfoImpl) ctxt.getOptions().getCache().get(uri);
+            }
+            if (impl == null) {
+                String[] location = ctxt.getTldLocation(uri);
+                impl = new TagLibraryInfoImpl(ctxt,
+                        parserController,
+                        prefix,
+                        uri,
+                        location,
+                        err);
+                if (ctxt.getOptions().isCaching()) {
+                    ctxt.getOptions().getCache().put(uri, impl);
+                }
+            }
+                    pageInfo.addTaglib(uri, impl);
+                }
+                pageInfo.addPrefixMapping(prefix, uri);
+            } else {
+                String tagdir = attrs.getValue("tagdir");
+                if (tagdir != null) {
+                    String urnTagdir = URN_JSPTAGDIR + tagdir;
+                    if (pageInfo.getTaglib(urnTagdir) == null) {
+                        pageInfo.addTaglib(urnTagdir,
+                                           new ImplicitTagLibraryInfo(
+                                                   ctxt,
+                                                   parserController,
+                                                   prefix, 
+                                                   tagdir,
+                                                   err));
+                    }
+                    pageInfo.addPrefixMapping(prefix, urnTagdir);
+                }
+            }
+        }
+
+        new Node.TaglibDirective(attrs, start, parent);
+    }
+
+    /*
+     * Parses a directive with the following syntax:
+     *   Directive ::= S? (   'page' PageDirective
+     *                            | 'include' IncludeDirective
+     *                            | 'taglib' TagLibDirective)
+     *                       S? '%>'
+     *
+     *   TagDirective ::= S? ('tag' PageDirective
+     *                            | 'include' IncludeDirective
+     *                            | 'taglib' TagLibDirective)
+     *                      | 'attribute AttributeDirective
+     *                      | 'variable VariableDirective
+     *                       S? '%>'
+     */
+    private void parseDirective(Node parent) throws JasperException {
+        reader.skipSpaces();
+
+        String directive = null;
+        if (reader.matches("page")) {
+            directive = "&lt;%@ page";
+            if (isTagFile) {
+                err.jspError(reader.mark(), "jsp.error.directive.istagfile",
+                                            directive);
+            }
+            parsePageDirective(parent);
+        } else if (reader.matches("include")) {
+            directive = "&lt;%@ include";
+            parseIncludeDirective(parent);
+        } else if (reader.matches("taglib")) {
+            if (directivesOnly) {
+                // No need to get the tagLibInfo objects.  This alos suppresses
+                // parsing of any tag files used in this tag file.
+                return;
+            }
+            directive = "&lt;%@ taglib";
+            parseTaglibDirective(parent);
+        } else if (reader.matches("tag")) {
+            directive = "&lt;%@ tag";
+            if (!isTagFile) {
+                err.jspError(reader.mark(), "jsp.error.directive.isnottagfile",
+                                            directive);
+            }
+            parseTagDirective(parent);
+        } else if (reader.matches("attribute")) {
+            directive = "&lt;%@ attribute";
+            if (!isTagFile) {
+                err.jspError(reader.mark(), "jsp.error.directive.isnottagfile",
+                                            directive);
+            }
+            parseAttributeDirective(parent);
+        } else if (reader.matches("variable")) {
+            directive = "&lt;%@ variable";
+            if (!isTagFile) {
+                err.jspError(reader.mark(), "jsp.error.directive.isnottagfile",
+                                            directive);
+            }
+            parseVariableDirective(parent);
+        } else {
+            err.jspError(reader.mark(), "jsp.error.invalid.directive");
+        }
+
+        reader.skipSpaces();
+        if (!reader.matches("%>")) {
+            err.jspError(start, "jsp.error.unterminated", directive);
+        }
+    }
+        
+    /*
+     * Parses a directive with the following syntax:
+     *
+     *   XMLJSPDirectiveBody ::= S? (   ( 'page' PageDirectiveAttrList
+     *                                    S? ( '/>' | ( '>' S? ETag ) )
+     *                               | ( 'include' IncludeDirectiveAttrList
+     *                                    S? ( '/>' | ( '>' S? ETag ) )
+     *                           | <TRANSLATION_ERROR>
+     *
+     *   XMLTagDefDirectiveBody ::= (   ( 'tag' TagDirectiveAttrList
+     *                                    S? ( '/>' | ( '>' S? ETag ) )
+     *                                | ( 'include' IncludeDirectiveAttrList
+     *                                    S? ( '/>' | ( '>' S? ETag ) )
+     *                                | ( 'attribute' AttributeDirectiveAttrList
+     *                                    S? ( '/>' | ( '>' S? ETag ) )
+     *                                | ( 'variable' VariableDirectiveAttrList
+     *                                    S? ( '/>' | ( '>' S? ETag ) )
+     *                              )
+     *                            | <TRANSLATION_ERROR>
+     */
+    private void parseXMLDirective(Node parent) throws JasperException {
+       reader.skipSpaces();
+
+        String eTag = null;
+       if (reader.matches("page")) {
+            eTag = "jsp:directive.page";
+           if (isTagFile) {
+               err.jspError(reader.mark(), "jsp.error.directive.istagfile",
+                                           "&lt;" + eTag);
+           }
+           parsePageDirective(parent);
+       } else if (reader.matches("include")) {
+            eTag = "jsp:directive.include";
+           parseIncludeDirective(parent);
+       } else if (reader.matches("tag")) {
+            eTag = "jsp:directive.tag";
+           if (!isTagFile) {
+               err.jspError(reader.mark(), "jsp.error.directive.isnottagfile",
+                                           "&lt;" + eTag);
+           }
+           parseTagDirective(parent);
+       } else if (reader.matches("attribute")) {
+            eTag = "jsp:directive.attribute";
+           if (!isTagFile) {
+               err.jspError(reader.mark(), "jsp.error.directive.isnottagfile",
+                                           "&lt;" + eTag);
+           }
+           parseAttributeDirective(parent);
+       } else if (reader.matches("variable")) {
+            eTag = "jsp:directive.variable";
+           if (!isTagFile) {
+               err.jspError(reader.mark(), "jsp.error.directive.isnottagfile",
+                                           "&lt;" + eTag);
+           }
+           parseVariableDirective(parent);
+       } else {
+           err.jspError(reader.mark(), "jsp.error.invalid.directive");
+       }
+
+       reader.skipSpaces();
+        if( reader.matches( ">" ) ) {
+            reader.skipSpaces();
+            if( !reader.matchesETag( eTag ) ) {
+                err.jspError(start, "jsp.error.unterminated", "&lt;" + eTag );
+            }
+        }
+        else if( !reader.matches( "/>" ) ) {
+            err.jspError(start, "jsp.error.unterminated", "&lt;" + eTag );
+        }
+    }
+
+    /*
+     * Parses a tag directive with the following syntax:
+     *   PageDirective ::= ( S Attribute)*
+     */
+    private void parseTagDirective(Node parent) throws JasperException {
+        Attributes attrs = parseAttributes();
+        Node.TagDirective n = new Node.TagDirective(attrs, start, parent);
+
+        /*
+         * A page directive may contain multiple 'import' attributes, each of
+         * which consists of a comma-separated list of package names.
+         * Store each list with the node, where it is parsed.
+         */
+        for (int i = 0; i < attrs.getLength(); i++) {
+            if ("import".equals(attrs.getQName(i))) {
+                n.addImport(attrs.getValue(i));
+            }
+        }
+    }
+
+    /*
+     * Parses a attribute directive with the following syntax:
+     *   AttributeDirective ::= ( S Attribute)*
+     */
+    private void parseAttributeDirective(Node parent) throws JasperException {
+        Attributes attrs = parseAttributes();
+        Node.AttributeDirective n =
+                new Node.AttributeDirective(attrs, start, parent);
+    }
+
+    /*
+     * Parses a variable directive with the following syntax:
+     *   PageDirective ::= ( S Attribute)*
+     */
+    private void parseVariableDirective(Node parent) throws JasperException {
+        Attributes attrs = parseAttributes();
+        Node.VariableDirective n =
+                new Node.VariableDirective(attrs, start, parent);
+    }
+
+    /*
+     * JSPCommentBody ::= (Char* - (Char* '--%>')) '--%>'
+     */
+    private void parseComment(Node parent) throws JasperException {        
+        start = reader.mark();
+        Mark stop = reader.skipUntil("--%>");
+        if (stop == null) {
+            err.jspError(start, "jsp.error.unterminated", "&lt;%--");
+        }
+
+        new Node.Comment(reader.getText(start, stop), start, parent);
+    }
+
+    /*
+     * DeclarationBody ::= (Char* - (char* '%>')) '%>'
+     */
+    private void parseDeclaration(Node parent) throws JasperException {
+        start = reader.mark();
+        Mark stop = reader.skipUntil("%>");
+        if (stop == null) {
+            err.jspError(start, "jsp.error.unterminated", "&lt;%!");
+        }
+
+        new Node.Declaration(parseScriptText(reader.getText(start, stop)),
+                             start, parent);
+    }
+
+    /*
+     * XMLDeclarationBody ::=   ( S? '/>' )
+     *                        | ( S? '>' (Char* - (char* '<')) CDSect?)* ETag
+     *                        | <TRANSLATION_ERROR>
+     * CDSect ::= CDStart CData CDEnd
+     * CDStart ::= '<![CDATA['
+     * CData ::= (Char* - (Char* ']]>' Char*))
+     * CDEnd ::= ']]>'
+     */
+    private void parseXMLDeclaration(Node parent) throws JasperException {
+        reader.skipSpaces();
+        if( !reader.matches( "/>" ) ) {
+            if( !reader.matches( ">" ) ) {
+                err.jspError(start, "jsp.error.unterminated",
+                        "&lt;jsp:declaration&gt;");
+            }
+            Mark stop;
+            String text;
+            while (true) {
+                start = reader.mark();
+                stop = reader.skipUntil("<");
+                if (stop == null) {
+                    err.jspError(start, "jsp.error.unterminated",
+                        "&lt;jsp:declaration&gt;");
+                }
+                text = parseScriptText(reader.getText(start, stop));
+                new Node.Declaration(text, start, parent);
+                if (reader.matches("![CDATA[")) {
+                    start = reader.mark();
+                    stop = reader.skipUntil("]]>");
+                    if (stop == null) {
+                        err.jspError(start, "jsp.error.unterminated", "CDATA");
+                    }
+                    text = parseScriptText(reader.getText(start, stop));
+                    new Node.Declaration(text, start, parent);
+                }
+                else {
+                    break;
+                }
+            }
+                
+            if (!reader.matchesETagWithoutLessThan( "jsp:declaration" ) ) {
+                err.jspError(start, "jsp.error.unterminated",
+                        "&lt;jsp:declaration&gt;");
+            }
+        }
+    }
+
+    /*
+     * ExpressionBody ::= (Char* - (char* '%>')) '%>'
+     */
+    private void parseExpression(Node parent) throws JasperException {
+        start = reader.mark();
+        Mark stop = reader.skipUntil("%>");
+        if (stop == null) {
+            err.jspError(start, "jsp.error.unterminated", "&lt;%=");
+        }
+
+        new Node.Expression(parseScriptText(reader.getText(start, stop)),
+                            start, parent);
+    }
+
+    /*
+     * XMLExpressionBody ::=   ( S? '/>' )
+     *                       | ( S? '>' (Char* - (char* '<')) CDSect?)* ETag )
+     *                       | <TRANSLATION_ERROR>
+     */
+    private void parseXMLExpression(Node parent) throws JasperException {
+        reader.skipSpaces();
+        if( !reader.matches( "/>" ) ) {
+            if( !reader.matches( ">" ) ) {
+                err.jspError(start, "jsp.error.unterminated",
+                    "&lt;jsp:expression&gt;");
+            }
+            Mark stop;
+            String text;
+            while (true) {
+                start = reader.mark();
+                stop = reader.skipUntil("<");
+                if (stop == null) {
+                    err.jspError(start, "jsp.error.unterminated",
+                        "&lt;jsp:expression&gt;");
+                }
+                text = parseScriptText(reader.getText(start, stop));
+                new Node.Expression(text, start, parent);
+                if (reader.matches("![CDATA[")) {
+                    start = reader.mark();
+                    stop = reader.skipUntil("]]>");
+                    if (stop == null) {
+                        err.jspError(start, "jsp.error.unterminated", "CDATA");
+                    }
+                    text = parseScriptText(reader.getText(start, stop));
+                    new Node.Expression(text, start, parent);
+                }
+                else {
+                    break;
+                }
+            }
+            if (!reader.matchesETagWithoutLessThan( "jsp:expression" )) {
+                err.jspError(start, "jsp.error.unterminated",
+                    "&lt;jsp:expression&gt;");
+            }
+        }
+    }
+
+    /*
+     * ELExpressionBody
+     * (following "${" to first unquoted "}")
+     * // XXX add formal production and confirm implementation against it,
+     * //     once it's decided
+     */
+    private void parseELExpression(Node parent) throws JasperException {
+        start = reader.mark();
+        Mark last = null;
+        boolean singleQuoted = false, doubleQuoted = false;
+        int currentChar;
+        do {
+            // XXX could move this logic to JspReader
+            last = reader.mark();               // XXX somewhat wasteful
+            currentChar = reader.nextChar();
+            if (currentChar == '\\' && (singleQuoted || doubleQuoted)) {
+                // skip character following '\' within quotes
+                reader.nextChar();
+                currentChar = reader.nextChar();
+            }
+            if (currentChar == -1)
+                err.jspError(start, "jsp.error.unterminated", "${");
+            if (currentChar == '"')
+                doubleQuoted = !doubleQuoted;
+            if (currentChar == '\'')
+                singleQuoted = !singleQuoted;
+        } while (currentChar != '}' || (singleQuoted || doubleQuoted));
+
+        new Node.ELExpression(reader.getText(start, last), start, parent);
+    }
+
+    /*
+     * ScriptletBody ::= (Char* - (char* '%>')) '%>'
+     */
+    private void parseScriptlet(Node parent) throws JasperException {
+        start = reader.mark();
+        Mark stop = reader.skipUntil("%>");
+        if (stop == null) {
+            err.jspError(start, "jsp.error.unterminated", "&lt;%");
+        }
+
+        new Node.Scriptlet(parseScriptText(reader.getText(start, stop)),
+                           start, parent);
+    }
+
+    /*
+     * XMLScriptletBody ::=   ( S? '/>' )
+     *                      | ( S? '>' (Char* - (char* '<')) CDSect?)* ETag )
+     *                      | <TRANSLATION_ERROR>
+     */
+    private void parseXMLScriptlet(Node parent) throws JasperException {
+        reader.skipSpaces();
+        if( !reader.matches( "/>" ) ) {
+            if( !reader.matches( ">" ) ) {
+                err.jspError(start, "jsp.error.unterminated",
+                    "&lt;jsp:scriptlet&gt;");
+            }
+            Mark stop;
+            String text;
+            while (true) {
+                start = reader.mark();
+                stop = reader.skipUntil("<");
+                if (stop == null) {
+                    err.jspError(start, "jsp.error.unterminated",
+                        "&lt;jsp:scriptlet&gt;");
+                }
+                text = parseScriptText(reader.getText(start, stop));
+                new Node.Scriptlet(text, start, parent);
+                if (reader.matches("![CDATA[")) {
+                    start = reader.mark();
+                    stop = reader.skipUntil("]]>");
+                    if (stop == null) {
+                        err.jspError(start, "jsp.error.unterminated", "CDATA");
+                    }
+                    text = parseScriptText(reader.getText(start, stop));
+                    new Node.Scriptlet(text, start, parent);
+                }
+                else {
+                    break;
+                }
+            }
+
+            if (!reader.matchesETagWithoutLessThan( "jsp:scriptlet" )) {
+                err.jspError(start, "jsp.error.unterminated",
+                    "&lt;jsp:scriptlet&gt;");
+            }
+        }
+    }
+        
+    /**
+     * Param ::= '<jsp:param' S Attributes S? EmptyBody S?
+     */
+    private void parseParam(Node parent) throws JasperException {
+        if (!reader.matches("<jsp:param")) {
+            err.jspError(reader.mark(), "jsp.error.paramexpected");
+        }
+        Attributes attrs = parseAttributes();
+        reader.skipSpaces();
+        
+        Node paramActionNode = new Node.ParamAction( attrs, start, parent );
+        
+        parseEmptyBody( paramActionNode, "jsp:param" );
+        
+        reader.skipSpaces();
+    }
+
+    /*
+     * For Include:
+     * StdActionContent ::= Attributes ParamBody
+     *
+     * ParamBody ::=   EmptyBody
+     *               | ( '>' S? ( '<jsp:attribute' NamedAttributes )?
+     *                   '<jsp:body'
+     *                   (JspBodyParam | <TRANSLATION_ERROR> )
+     *                   S? ETag
+     *                 )
+     *               | ( '>' S? Param* ETag )
+     *
+     * EmptyBody ::=   '/>'
+     *               | ( '>' ETag )
+     *               | ( '>' S? '<jsp:attribute' NamedAttributes ETag )
+     *
+     * JspBodyParam ::= S? '>' Param* '</jsp:body>'
+     */
+    private void parseInclude(Node parent) throws JasperException {
+        Attributes attrs = parseAttributes();
+        reader.skipSpaces();
+
+        Node includeNode = new Node.IncludeAction( attrs, start, parent );
+        
+        parseOptionalBody(includeNode, "jsp:include", 
+                          JAVAX_BODY_CONTENT_PARAM);
+    }
+
+    /*
+     * For Forward:
+     * StdActionContent ::= Attributes ParamBody
+     */
+    private void parseForward(Node parent) throws JasperException {
+        Attributes attrs = parseAttributes();
+        reader.skipSpaces();
+
+        Node forwardNode = new Node.ForwardAction( attrs, start, parent );
+        
+        parseOptionalBody(forwardNode, "jsp:forward",
+                          JAVAX_BODY_CONTENT_PARAM);
+    }
+
+    private void parseInvoke(Node parent) throws JasperException {
+        Attributes attrs = parseAttributes();
+        reader.skipSpaces();
+
+        Node invokeNode = new Node.InvokeAction(attrs, start, parent);
+        
+        parseEmptyBody(invokeNode, "jsp:invoke");
+    }
+
+    private void parseDoBody(Node parent) throws JasperException {
+        Attributes attrs = parseAttributes();
+        reader.skipSpaces();
+
+        Node doBodyNode = new Node.DoBodyAction(attrs, start, parent);
+        
+        parseEmptyBody(doBodyNode, "jsp:doBody");
+    }
+
+    private void parseElement(Node parent) throws JasperException {
+        Attributes attrs = parseAttributes();
+        reader.skipSpaces();
+
+        Node elementNode = new Node.JspElement(attrs, start, parent);
+        
+        parseOptionalBody( elementNode, "jsp:element", 
+            TagInfo.BODY_CONTENT_JSP );
+    }
+
+    /*
+     * For GetProperty:
+     * StdActionContent ::= Attributes EmptyBody
+     */
+    private void parseGetProperty(Node parent) throws JasperException {
+        Attributes attrs = parseAttributes();
+        reader.skipSpaces();
+
+        Node getPropertyNode = new Node.GetProperty( attrs, start, parent );
+        
+        parseOptionalBody(getPropertyNode, "jsp:getProperty",
+                          TagInfo.BODY_CONTENT_EMPTY);
+    }
+
+    /*
+     * For SetProperty:
+     * StdActionContent ::= Attributes EmptyBody
+     */
+    private void parseSetProperty(Node parent) throws JasperException {
+        Attributes attrs = parseAttributes();
+        reader.skipSpaces();
+
+        Node setPropertyNode = new Node.SetProperty( attrs, start, parent );
+        
+        parseOptionalBody(setPropertyNode, "jsp:setProperty",
+                          TagInfo.BODY_CONTENT_EMPTY);
+    }
+
+    /*
+     * EmptyBody ::=   '/>'
+     *               | ( '>' ETag )
+     *               | ( '>' S? '<jsp:attribute' NamedAttributes ETag )
+     */
+    private void parseEmptyBody( Node parent, String tag ) 
+        throws JasperException
+    {
+        if( reader.matches("/>") ) {
+            // Done
+        }
+        else if( reader.matches( ">" ) ) {
+            if( reader.matchesETag( tag ) ) {
+                // Done
+            }
+            else if( reader.matchesOptionalSpacesFollowedBy(
+                "<jsp:attribute" ) )
+            {
+                // Parse the one or more named attribute nodes
+                parseNamedAttributes( parent );
+                if( !reader.matchesETag( tag ) ) {
+                    // Body not allowed
+                    err.jspError(reader.mark(),
+                        "jsp.error.jspbody.emptybody.only",
+                        "&lt;" + tag );
+                }
+            }
+            else {
+                err.jspError(reader.mark(), "jsp.error.jspbody.emptybody.only",
+                    "&lt;" + tag );
+            }
+        }
+        else {
+            err.jspError(reader.mark(), "jsp.error.unterminated",
+                "&lt;" + tag );
+        }
+    }
+
+    /*
+     * For UseBean:
+     * StdActionContent ::= Attributes OptionalBody
+     */
+    private void parseUseBean(Node parent) throws JasperException {
+        Attributes attrs = parseAttributes();
+        reader.skipSpaces();
+        
+        Node useBeanNode = new Node.UseBean( attrs, start, parent );
+        
+        parseOptionalBody( useBeanNode, "jsp:useBean", 
+            TagInfo.BODY_CONTENT_JSP );
+    }
+
+    /*
+     * Parses OptionalBody, but also reused to parse bodies for plugin
+     * and param since the syntax is identical (the only thing that
+     * differs substantially is how to process the body, and thus
+     * we accept the body type as a parameter).
+     *
+     * OptionalBody ::= EmptyBody | ActionBody
+     *
+     * ScriptlessOptionalBody ::= EmptyBody | ScriptlessActionBody
+     *
+     * TagDependentOptionalBody ::= EmptyBody | TagDependentActionBody
+     *
+     * EmptyBody ::=   '/>'
+     *               | ( '>' ETag )
+     *               | ( '>' S? '<jsp:attribute' NamedAttributes ETag )
+     *
+     * ActionBody ::=   JspAttributeAndBody
+     *                | ( '>' Body ETag )
+     *
+     * ScriptlessActionBody ::=   JspAttributeAndBody 
+     *                          | ( '>' ScriptlessBody ETag )
+     * 
+     * TagDependentActionBody ::=   JspAttributeAndBody
+     *                            | ( '>' TagDependentBody ETag )
+     *
+     */
+    private void parseOptionalBody( Node parent, String tag, String bodyType ) 
+        throws JasperException 
+    {
+        if (reader.matches("/>")) {
+            // EmptyBody
+            return;
+        }
+
+        if (!reader.matches(">")) {
+            err.jspError(reader.mark(), "jsp.error.unterminated",
+                         "&lt;" + tag );
+        }
+        
+        if( reader.matchesETag( tag ) ) {
+            // EmptyBody
+            return;
+        }
+        
+        if( !parseJspAttributeAndBody( parent, tag, bodyType ) ) {
+            // Must be ( '>' # Body ETag )
+            parseBody(parent, tag, bodyType );
+        }
+    }
+    
+    /**
+     * Attempts to parse 'JspAttributeAndBody' production.  Returns true if
+     * it matched, or false if not.  Assumes EmptyBody is okay as well.
+     *
+     * JspAttributeAndBody ::=
+     *                  ( '>' # S? ( '<jsp:attribute' NamedAttributes )?
+     *                    '<jsp:body'
+     *                    ( JspBodyBody | <TRANSLATION_ERROR> )
+     *                    S? ETag
+     *                  )
+     */
+    private boolean parseJspAttributeAndBody( Node parent, String tag, 
+        String bodyType ) 
+        throws JasperException
+    {
+        boolean result = false;
+        
+        if( reader.matchesOptionalSpacesFollowedBy( "<jsp:attribute" ) ) {
+            // May be an EmptyBody, depending on whether
+            // There's a "<jsp:body" before the ETag
+            
+            // First, parse <jsp:attribute> elements:
+            parseNamedAttributes( parent );
+            
+            result = true;
+        }
+        
+        if( reader.matchesOptionalSpacesFollowedBy( "<jsp:body" ) ) {
+            // ActionBody
+            parseJspBody( parent, bodyType );
+            reader.skipSpaces();
+            if( !reader.matchesETag( tag ) ) {
+                err.jspError(reader.mark(), "jsp.error.unterminated", 
+                    "&lt;" + tag );
+            }
+            
+            result = true;
+        }
+        else if( result && !reader.matchesETag( tag ) ) {
+            // If we have <jsp:attribute> but something other than
+            // <jsp:body> or the end tag, translation error.
+            err.jspError(reader.mark(), "jsp.error.jspbody.required", 
+                "&lt;" + tag );
+        }
+        
+        return result;
+    }
+
+    /*
+     * Params ::=  `>' S?
+     *              (   ( `<jsp:body>'
+     *                    ( ( S? Param+ S? `</jsp:body>' )
+     *                      | <TRANSLATION_ERROR>
+     *                    )
+     *                  )
+     *                | Param+
+     *              )
+     *              '</jsp:params>'
+     */
+    private void parseJspParams(Node parent) throws JasperException {
+        Node jspParamsNode = new Node.ParamsAction(start, parent);
+        parseOptionalBody(jspParamsNode, "jsp:params",
+                          JAVAX_BODY_CONTENT_PARAM );
+    }
+
+    /*
+     * Fallback ::=   '/>'
+     *               | ( `>' S? `<jsp:body>'
+     *                   (   ( S?
+     *                         ( Char* - ( Char* `</jsp:body>' ) )
+     *                         `</jsp:body>' S?
+     *                       )
+     *                     | <TRANSLATION_ERROR>
+     *                   )
+     *                   `</jsp:fallback>'
+     *                 )
+     *               | ( '>'
+     *                   ( Char* - ( Char* '</jsp:fallback>' ) )
+     *                   '</jsp:fallback>'
+     *                 )
+     */
+    private void parseFallBack(Node parent) throws JasperException {
+        Node fallBackNode = new Node.FallBackAction(start, parent);
+        parseOptionalBody(fallBackNode, "jsp:fallback", 
+                          JAVAX_BODY_CONTENT_TEMPLATE_TEXT);
+    }
+
+    /*
+     * For Plugin:
+     * StdActionContent ::= Attributes PluginBody
+     *
+     * PluginBody ::=   EmptyBody 
+     *                | ( '>' S? ( '<jsp:attribute' NamedAttributes )?
+     *                    '<jsp:body'
+     *                    ( JspBodyPluginTags | <TRANSLATION_ERROR> )
+     *                    S? ETag
+     *                  )
+     *                | ( '>' S? PluginTags ETag )
+     *
+     * EmptyBody ::=   '/>'
+     *               | ( '>' ETag )
+     *               | ( '>' S? '<jsp:attribute' NamedAttributes ETag )
+     *
+     */
+    private void parsePlugin(Node parent) throws JasperException {
+        Attributes attrs = parseAttributes();
+        reader.skipSpaces();
+        
+        Node pluginNode = new Node.PlugIn(attrs, start, parent);
+        
+        parseOptionalBody( pluginNode, "jsp:plugin", 
+            JAVAX_BODY_CONTENT_PLUGIN );
+    }
+
+    /*
+     * PluginTags ::= ( '<jsp:params' Params S? )?
+     *                ( '<jsp:fallback' Fallback? S? )?
+     */
+    private void parsePluginTags( Node parent ) throws JasperException {
+        reader.skipSpaces();
+        
+        if( reader.matches( "<jsp:params" ) ) {
+            parseJspParams( parent );
+            reader.skipSpaces();
+        }
+        
+        if( reader.matches( "<jsp:fallback" ) ) {
+            parseFallBack( parent );
+            reader.skipSpaces();
+        }
+    }
+        
+    /*
+     * StandardAction ::=   'include'       StdActionContent
+     *                    | 'forward'       StdActionContent
+     *                    | 'invoke'        StdActionContent
+     *                    | 'doBody'        StdActionContent
+     *                    | 'getProperty'   StdActionContent
+     *                    | 'setProperty'   StdActionContent
+     *                    | 'useBean'       StdActionContent
+     *                    | 'plugin'        StdActionContent
+     *                    | 'element'       StdActionContent
+     */
+    private void parseStandardAction(Node parent) throws JasperException {
+        Mark start = reader.mark();
+
+        if (reader.matches(INCLUDE_ACTION)) {
+            parseInclude(parent);
+        } else if (reader.matches(FORWARD_ACTION)) {
+            parseForward(parent);
+        } else if (reader.matches(INVOKE_ACTION)) {
+            if (!isTagFile) {
+                err.jspError(reader.mark(), "jsp.error.action.isnottagfile",
+                             "&lt;jsp:invoke");
+            }
+            parseInvoke(parent);
+        } else if (reader.matches(DOBODY_ACTION)) {
+            if (!isTagFile) {
+                err.jspError(reader.mark(), "jsp.error.action.isnottagfile",
+                             "&lt;jsp:doBody");
+            }
+            parseDoBody(parent);
+        } else if (reader.matches(GET_PROPERTY_ACTION)) {
+            parseGetProperty(parent);
+        } else if (reader.matches(SET_PROPERTY_ACTION)) {
+            parseSetProperty(parent);
+        } else if (reader.matches(USE_BEAN_ACTION)) {
+            parseUseBean(parent);
+        } else if (reader.matches(PLUGIN_ACTION)) {
+            parsePlugin(parent);
+        } else if (reader.matches(ELEMENT_ACTION)) {
+            parseElement(parent);
+        } else if (reader.matches(ATTRIBUTE_ACTION)) {
+            err.jspError(start, "jsp.error.namedAttribute.invalidUse");
+        } else if (reader.matches(BODY_ACTION)) {
+            err.jspError(start, "jsp.error.jspbody.invalidUse");
+        } else if (reader.matches(FALLBACK_ACTION)) {
+            err.jspError(start, "jsp.error.fallback.invalidUse");
+        } else if (reader.matches(PARAMS_ACTION)) {
+            err.jspError(start, "jsp.error.params.invalidUse");
+        } else if (reader.matches(PARAM_ACTION)) {
+            err.jspError(start, "jsp.error.param.invalidUse");
+        } else if (reader.matches(OUTPUT_ACTION)) {
+            err.jspError(start, "jsp.error.jspoutput.invalidUse");
+        } else {
+            err.jspError(start, "jsp.error.badStandardAction");
+        }
+    }
+
+    /*
+     * # '<' CustomAction CustomActionBody
+     *
+     * CustomAction ::= TagPrefix ':' CustomActionName
+     *
+     * TagPrefix ::= Name
+     *
+     * CustomActionName ::= Name
+     *
+     * CustomActionBody ::=   ( Attributes CustomActionEnd )
+     *                      | <TRANSLATION_ERROR>
+     *
+     * Attributes ::= ( S Attribute )* S?
+     *
+     * CustomActionEnd ::=   CustomActionTagDependent
+     *                     | CustomActionJSPContent
+     *                     | CustomActionScriptlessContent
+     *
+     * CustomActionTagDependent ::= TagDependentOptionalBody
+     *
+     * CustomActionJSPContent ::= OptionalBody
+     *
+     * CustomActionScriptlessContent ::= ScriptlessOptionalBody
+     */
+    private boolean parseCustomTag(Node parent) throws JasperException {
+
+        if (reader.peekChar() != '<') {
+            return false;
+        }
+
+        // Parse 'CustomAction' production (tag prefix and custom action name)
+        reader.nextChar();        // skip '<'
+        String tagName = reader.parseToken(false);
+        int i = tagName.indexOf(':');
+        if (i == -1) {
+            reader.reset(start);
+            return false;
+        }
+
+        String prefix = tagName.substring(0, i);
+        String shortTagName = tagName.substring(i+1);
+
+        // Check if this is a user-defined tag.
+        String uri = pageInfo.getURI(prefix);
+        if (uri == null) {
+            reader.reset(start);
+            // Remember the prefix for later error checking
+            pageInfo.putNonCustomTagPrefix(prefix, reader.mark());
+            return false;
+        }
+
+        TagLibraryInfo tagLibInfo = pageInfo.getTaglib(uri);
+        TagInfo tagInfo = tagLibInfo.getTag(shortTagName);
+        TagFileInfo tagFileInfo = tagLibInfo.getTagFile(shortTagName);
+        if (tagInfo == null && tagFileInfo == null) {
+            err.jspError(start, "jsp.error.bad_tag", shortTagName, prefix);
+        }
+        Class tagHandlerClass = null;
+        if (tagInfo != null) {
+            // Must be a classic tag, load it here.
+            // tag files will be loaded later, in TagFileProcessor
+            String handlerClassName = tagInfo.getTagClassName();
+            try {
+                tagHandlerClass =
+                    ctxt.getClassLoader().loadClass(handlerClassName);
+            } catch (Exception e) {
+                err.jspError(start, "jsp.error.loadclass.taghandler",
+                             handlerClassName, tagName);
+            }
+        }
+
+        // Parse 'CustomActionBody' production:
+        // At this point we are committed - if anything fails, we produce
+        // a translation error.
+
+        // Parse 'Attributes' production:
+        Attributes attrs = parseAttributes();
+        reader.skipSpaces();
+        
+        // Parse 'CustomActionEnd' production:
+        if (reader.matches("/>")) {
+            if (tagInfo != null) {
+                new Node.CustomTag(tagName, prefix, shortTagName, uri, attrs,
+                                   start, parent, tagInfo, tagHandlerClass);
+            } else {
+                new Node.CustomTag(tagName, prefix, shortTagName, uri, attrs,
+                                   start, parent, tagFileInfo);
+            }
+            return true;
+        }
+        
+        // Now we parse one of 'CustomActionTagDependent', 
+        // 'CustomActionJSPContent', or 'CustomActionScriptlessContent'.
+        // depending on body-content in TLD.
+
+        // Looking for a body, it still can be empty; but if there is a
+        // a tag body, its syntax would be dependent on the type of
+        // body content declared in the TLD.
+        String bc;
+        if (tagInfo != null) {
+            bc = tagInfo.getBodyContent();
+        } else {
+            bc = tagFileInfo.getTagInfo().getBodyContent();
+        }
+
+        Node tagNode = null;
+        if (tagInfo != null) {
+            tagNode = new Node.CustomTag(tagName, prefix, shortTagName, uri,
+                                         attrs, start, parent, tagInfo,
+                                         tagHandlerClass);
+        } else {
+            tagNode = new Node.CustomTag(tagName, prefix, shortTagName, uri,
+                                         attrs, start, parent, tagFileInfo);
+        }
+
+        parseOptionalBody( tagNode, tagName, bc );
+
+        return true;
+    }
+
+    /*
+     * Parse for a template text string until '<' or "${" is encountered, 
+     * recognizing escape sequences "\%" and "\$".
+     */
+    private void parseTemplateText(Node parent) throws JasperException {
+
+        if (!reader.hasMoreInput())
+            return;
+
+        CharArrayWriter ttext = new CharArrayWriter();
+        // Output the first character
+        int ch = reader.nextChar();
+        if (ch == '\\') {
+            reader.pushChar();
+        } else {
+            ttext.write(ch);
+        }
+
+        while (reader.hasMoreInput()) {
+            ch = reader.nextChar();
+            if (ch == '<') {
+                reader.pushChar();
+                break;
+            }
+            else if( ch == '$' ) {
+                if (!reader.hasMoreInput()) {
+                    ttext.write('$');
+                    break;
+                }
+                ch = reader.nextChar();
+                if (ch == '{') {
+                    reader.pushChar();
+                    reader.pushChar();
+                    break;
+                }
+                ttext.write('$');
+                reader.pushChar();
+                continue;
+            }
+            else if (ch == '\\') {
+                if (!reader.hasMoreInput()) {
+                    ttext.write('\\');
+                    break;
+                }
+                // Look for \% or \$
+                // Only recognize \$ if isELIgnored is false, but since it can
+                // be set in a page directive, it cannot be determined yet.
+                char next = (char)reader.peekChar();
+                if (next == '%') {
+                    ch = reader.nextChar();
+                } else if(next == '$') {
+                    // Skip the $ and use a hack to flag this sequence
+                    reader.nextChar();
+                    ch = Constants.ESC;
+                }
+            }
+            ttext.write(ch);
+        }
+        new Node.TemplateText(ttext.toString(), start, parent);
+    }
+    
+    /*
+     * XMLTemplateText ::=   ( S? '/>' )
+     *                     | ( S? '>'
+     *                         ( ( Char* - ( Char* ( '<' | '${' ) ) )
+     *                           ( '${' ELExpressionBody )?
+     *                           CDSect?
+     *                         )* ETag
+     *                       )
+     *                     | <TRANSLATION_ERROR>
+     */
+    private void parseXMLTemplateText(Node parent) throws JasperException {
+        reader.skipSpaces();
+        if( !reader.matches( "/>" ) ) {
+            if( !reader.matches( ">" ) ) {
+                err.jspError(start, "jsp.error.unterminated",
+                    "&lt;jsp:text&gt;" );
+            }
+            CharArrayWriter ttext = new CharArrayWriter();
+            while (reader.hasMoreInput()) {
+                int ch = reader.nextChar();
+                if( ch == '<' ) {
+                    // Check for <![CDATA[
+                    if (!reader.matches("![CDATA[")) {
+                        break;
+                    }
+                    start = reader.mark();
+                    Mark stop = reader.skipUntil("]]>");
+                    if (stop == null) {
+                        err.jspError(start, "jsp.error.unterminated", "CDATA");
+                    }
+                    String text = reader.getText(start, stop);
+                    ttext.write(text, 0, text.length());
+                }
+                else if( ch == '\\') {
+                    if (!reader.hasMoreInput()) {
+                        ttext.write('\\');
+                        break;
+                    }
+                    ch = reader.nextChar();
+                    if (ch != '$' ) {
+                        ttext.write('\\');
+                    }
+                    ttext.write(ch);
+                }
+                else if( ch == '$' ) {
+                    if (!reader.hasMoreInput()) {
+                        ttext.write('$');
+                        break;
+                    }
+                    ch = reader.nextChar();
+                    if (ch != '{') {
+                        ttext.write('$');
+                        reader.pushChar();
+                        continue;
+                    }
+                    // Create a template text node
+                    new Node.TemplateText( ttext.toString(), start, parent);
+
+                    // Mark and parse the EL expression and create its node:
+                    start = reader.mark();
+                    parseELExpression(parent);
+
+                    start = reader.mark();
+                    ttext = new CharArrayWriter();
+                }
+                else {
+                    ttext.write( ch );
+                }
+            }
+
+            new Node.TemplateText( ttext.toString(), start, parent );
+
+            if (! reader.hasMoreInput()) {
+                err.jspError( start, "jsp.error.unterminated",
+                    "&lt;jsp:text&gt;" );
+            } else if( !reader.matchesETagWithoutLessThan( "jsp:text" ) ) {
+                err.jspError( start, "jsp.error.jsptext.badcontent");
+            }
+        }
+    }
+
+    /*
+     * AllBody ::=       ( '<%--'              JSPCommentBody     )
+     *                 | ( '<%@'               DirectiveBody      )
+     *                 | ( '<jsp:directive.'   XMLDirectiveBody   )
+     *                 | ( '<%!'               DeclarationBody    )
+     *                 | ( '<jsp:declaration'  XMLDeclarationBody )
+     *                 | ( '<%='               ExpressionBody     )
+     *                 | ( '<jsp:expression'   XMLExpressionBody  )
+     *                 | ( '${'                ELExpressionBody   )
+     *                 | ( '<%'                ScriptletBody      )
+     *                 | ( '<jsp:scriptlet'    XMLScriptletBody   )
+     *                 | ( '<jsp:text'         XMLTemplateText    )
+     *                 | ( '<jsp:'             StandardAction     )
+     *                 | ( '<'                 CustomAction
+     *                                         CustomActionBody   )
+     *                       | TemplateText
+     */
+    private void parseElements(Node parent) 
+        throws JasperException 
+    {
+        if( scriptlessCount > 0 ) {
+            // vc: ScriptlessBody
+            // We must follow the ScriptlessBody production if one of
+            // our parents is ScriptlessBody.
+            parseElementsScriptless( parent );
+            return;
+        }
+        
+        start = reader.mark();
+        if (reader.matches("<%--")) {
+            parseComment(parent);
+        } else if (reader.matches("<%@")) {
+            parseDirective(parent);
+        } else if (reader.matches("<jsp:directive.")) {
+            parseXMLDirective(parent);
+        } else if (reader.matches("<%!")) {
+            parseDeclaration(parent);
+        } else if (reader.matches("<jsp:declaration")) {
+            parseXMLDeclaration(parent);
+        } else if (reader.matches("<%=")) {
+            parseExpression(parent);
+        } else if (reader.matches("<jsp:expression")) {
+            parseXMLExpression(parent);
+        } else if (reader.matches("<%")) {
+            parseScriptlet(parent);
+        } else if (reader.matches("<jsp:scriptlet")) {
+            parseXMLScriptlet(parent);
+        } else if (reader.matches("<jsp:text")) {
+            parseXMLTemplateText(parent);
+        } else if (reader.matches("${")) {
+            parseELExpression(parent);
+        } else if (reader.matches("<jsp:")) {
+            parseStandardAction(parent);
+        } else if (!parseCustomTag(parent)) {
+            checkUnbalancedEndTag();
+            parseTemplateText(parent);
+        }
+    }
+
+    /*
+     * ScriptlessBody ::=  ( '<%--'              JSPCommentBody      )
+     *                   | ( '<%@'               DirectiveBody       )
+     *                   | ( '<jsp:directive.'   XMLDirectiveBody    )
+     *                   | ( '<%!'               <TRANSLATION_ERROR> )
+     *                   | ( '<jsp:declaration'  <TRANSLATION_ERROR> )
+     *                   | ( '<%='               <TRANSLATION_ERROR> )
+     *                   | ( '<jsp:expression'   <TRANSLATION_ERROR> )
+     *                   | ( '<%'                <TRANSLATION_ERROR> )
+     *                   | ( '<jsp:scriptlet'    <TRANSLATION_ERROR> )
+     *                   | ( '<jsp:text'         XMLTemplateText     )
+     *                   | ( '${'                ELExpressionBody    )
+     *                   | ( '<jsp:'             StandardAction      )
+     *                   | ( '<'                 CustomAction
+     *                                           CustomActionBody    )
+     *                   | TemplateText
+     */
+    private void parseElementsScriptless(Node parent) 
+        throws JasperException 
+    {
+        // Keep track of how many scriptless nodes we've encountered
+        // so we know whether our child nodes are forced scriptless
+        scriptlessCount++;
+        
+        start = reader.mark();
+        if (reader.matches("<%--")) {
+            parseComment(parent);
+        } else if (reader.matches("<%@")) {
+            parseDirective(parent);
+        } else if (reader.matches("<jsp:directive.")) {
+            parseXMLDirective(parent);
+        } else if (reader.matches("<%!")) {
+            err.jspError( reader.mark(), "jsp.error.no.scriptlets" );
+        } else if (reader.matches("<jsp:declaration")) {
+            err.jspError( reader.mark(), "jsp.error.no.scriptlets" );
+        } else if (reader.matches("<%=")) {
+            err.jspError( reader.mark(), "jsp.error.no.scriptlets" );
+        } else if (reader.matches("<jsp:expression")) {
+            err.jspError( reader.mark(), "jsp.error.no.scriptlets" );
+        } else if (reader.matches("<%")) {
+            err.jspError( reader.mark(), "jsp.error.no.scriptlets" );
+        } else if (reader.matches("<jsp:scriptlet")) {
+            err.jspError( reader.mark(), "jsp.error.no.scriptlets" );
+        } else if (reader.matches("<jsp:text")) {
+            parseXMLTemplateText(parent);
+        } else if (reader.matches("${")) {
+            parseELExpression(parent);
+        } else if (reader.matches("<jsp:")) {
+            parseStandardAction(parent);
+        } else if (!parseCustomTag(parent)) {
+            checkUnbalancedEndTag();
+            parseTemplateText(parent);
+        }
+        
+        scriptlessCount--;
+    }
+    
+    /*
+     * TemplateTextBody ::=   ( '<%--'              JSPCommentBody      )
+     *                      | ( '<%@'               DirectiveBody       )
+     *                      | ( '<jsp:directive.'   XMLDirectiveBody    )
+     *                      | ( '<%!'               <TRANSLATION_ERROR> )
+     *                      | ( '<jsp:declaration'  <TRANSLATION_ERROR> )
+     *                      | ( '<%='               <TRANSLATION_ERROR> )
+     *                      | ( '<jsp:expression'   <TRANSLATION_ERROR> )
+     *                      | ( '<%'                <TRANSLATION_ERROR> )
+     *                      | ( '<jsp:scriptlet'    <TRANSLATION_ERROR> )
+     *                      | ( '<jsp:text'         <TRANSLATION_ERROR> )
+     *                      | ( '${'                <TRANSLATION_ERROR> )
+     *                      | ( '<jsp:'             <TRANSLATION_ERROR> )
+     *                      | TemplateText
+     */
+    private void parseElementsTemplateText(Node parent)
+        throws JasperException
+    {
+        start = reader.mark();
+        if (reader.matches("<%--")) {
+            parseComment(parent);
+        } else if (reader.matches("<%@")) {
+            parseDirective(parent);
+        } else if (reader.matches("<jsp:directive.")) {
+            parseXMLDirective(parent);
+        } else if (reader.matches("<%!")) {
+            err.jspError( reader.mark(), "jsp.error.not.in.template",
+                "Declarations" );
+        } else if (reader.matches("<jsp:declaration")) {
+            err.jspError( reader.mark(), "jsp.error.not.in.template",
+                "Declarations" );
+        } else if (reader.matches("<%=")) {
+            err.jspError( reader.mark(), "jsp.error.not.in.template",
+                "Expressions" );
+        } else if (reader.matches("<jsp:expression")) {
+            err.jspError( reader.mark(), "jsp.error.not.in.template",
+                "Expressions" );
+        } else if (reader.matches("<%")) {
+            err.jspError( reader.mark(), "jsp.error.not.in.template",
+                "Scriptlets" );
+        } else if (reader.matches("<jsp:scriptlet")) {
+            err.jspError( reader.mark(), "jsp.error.not.in.template",
+                "Scriptlets" );
+        } else if (reader.matches("<jsp:text")) {
+            err.jspError( reader.mark(), "jsp.error.not.in.template",
+                "&lt;jsp:text" );
+        } else if (reader.matches("${")) {
+            err.jspError( reader.mark(), "jsp.error.not.in.template",
+                "Expression language" );
+        } else if (reader.matches("<jsp:")) {
+            err.jspError( reader.mark(), "jsp.error.not.in.template",
+                "Standard actions" );
+        } else if (parseCustomTag(parent)) {
+            err.jspError( reader.mark(), "jsp.error.not.in.template",
+                "Custom actions" );
+        } else {
+            checkUnbalancedEndTag();
+            parseTemplateText(parent);
+        }
+    }
+
+    /*
+     * Flag as error if an unbalanced end tag appears by itself.
+     */
+    private void checkUnbalancedEndTag() throws JasperException {
+
+        if (!reader.matches("</")) {
+            return;
+        }
+
+        // Check for unbalanced standard actions
+        if (reader.matches("jsp:")) {
+            err.jspError(start, "jsp.error.unbalanced.endtag", "jsp:");
+        }
+
+        // Check for unbalanced custom actions
+        String tagName = reader.parseToken(false);
+        int i = tagName.indexOf(':');
+        if (i == -1 || pageInfo.getURI(tagName.substring(0, i)) == null) {
+            reader.reset(start);
+            return;
+        }
+
+        err.jspError(start, "jsp.error.unbalanced.endtag", tagName);
+    }
+
+    /**
+     * TagDependentBody := 
+     */
+    private void parseTagDependentBody(Node parent, String tag)
+                throws JasperException{
+        Mark bodyStart = reader.mark();
+        Mark bodyEnd = reader.skipUntilETag(tag);
+        if (bodyEnd == null) {
+            err.jspError(start, "jsp.error.unterminated", "&lt;"+tag );
+        }
+        new Node.TemplateText(reader.getText(bodyStart, bodyEnd), bodyStart,
+                              parent);
+    }
+
+    /*
+     * Parses jsp:body action.
+     */
+    private void parseJspBody(Node parent, String bodyType) 
+        throws JasperException 
+    {
+        Mark start = reader.mark();
+        Node bodyNode = new Node.JspBody(start, parent);
+
+        reader.skipSpaces();
+        if (!reader.matches("/>")) {
+            if (!reader.matches(">")) {
+                err.jspError(start, "jsp.error.unterminated",
+                             "&lt;jsp:body");
+            }
+            parseBody( bodyNode, "jsp:body", bodyType );
+        }
+    }
+
+    /*
+     * Parse the body as JSP content.
+     * @param tag The name of the tag whose end tag would terminate the body
+     * @param bodyType One of the TagInfo body types
+     */
+    private void parseBody(Node parent, String tag, String bodyType) 
+        throws JasperException 
+    {
+        if( bodyType.equalsIgnoreCase( TagInfo.BODY_CONTENT_TAG_DEPENDENT ) ) {
+            parseTagDependentBody( parent, tag );
+        }
+        else if( bodyType.equalsIgnoreCase( TagInfo.BODY_CONTENT_EMPTY ) ) {
+            if( !reader.matchesETag( tag ) ) {
+                err.jspError(start, "jasper.error.emptybodycontent.nonempty",
+                             tag);
+            }
+        }
+        else if( bodyType == JAVAX_BODY_CONTENT_PLUGIN ) {
+            // (note the == since we won't recognize JAVAX_* 
+            // from outside this module).
+            parsePluginTags(parent);
+            if( !reader.matchesETag( tag ) ) {
+                err.jspError( reader.mark(), "jsp.error.unterminated",
+                    "&lt;" + tag  );
+            }
+        }
+        else if( bodyType.equalsIgnoreCase( TagInfo.BODY_CONTENT_JSP ) ||
+            bodyType.equalsIgnoreCase( TagInfo.BODY_CONTENT_SCRIPTLESS ) ||
+            (bodyType == JAVAX_BODY_CONTENT_PARAM) ||
+            (bodyType == JAVAX_BODY_CONTENT_TEMPLATE_TEXT) )
+        {
+            while (reader.hasMoreInput()) {
+                if (reader.matchesETag(tag)) {
+                    return;
+                }
+                
+                // Check for nested jsp:body or jsp:attribute
+                if (tag.equals("jsp:body") || tag.equals("jsp:attribute")) {
+                    if (reader.matches("<jsp:attribute")) {
+                        err.jspError(reader.mark(), "jsp.error.nested.jspattribute");
+                    }
+                    else if (reader.matches("<jsp:body")) {
+                        err.jspError(reader.mark(), "jsp.error.nested.jspbody");
+                    }
+                }
+
+                if( bodyType.equalsIgnoreCase( TagInfo.BODY_CONTENT_JSP ) ) {
+                    parseElements( parent );
+                }
+                else if( bodyType.equalsIgnoreCase( 
+                    TagInfo.BODY_CONTENT_SCRIPTLESS ) ) 
+                {
+                    parseElementsScriptless( parent );
+                }
+                else if( bodyType == JAVAX_BODY_CONTENT_PARAM ) {
+                    // (note the == since we won't recognize JAVAX_* 
+                    // from outside this module).
+                    reader.skipSpaces();
+                    parseParam( parent );
+                }
+                else if (bodyType == JAVAX_BODY_CONTENT_TEMPLATE_TEXT) {
+                    parseElementsTemplateText(parent);
+                }
+            }
+            err.jspError(start, "jsp.error.unterminated", "&lt;"+tag );
+        }
+        else {
+            err.jspError(start, "jasper.error.bad.bodycontent.type");
+        }
+    }
+
+    /*
+     * Parses named attributes.
+     */
+    private void parseNamedAttributes(Node parent) throws JasperException {
+        do {
+            Mark start = reader.mark();
+            Attributes attrs = parseAttributes();
+            Node.NamedAttribute namedAttributeNode =
+                new Node.NamedAttribute( attrs, start, parent );
+
+            reader.skipSpaces();
+            if (!reader.matches("/>")) {
+                if (!reader.matches(">")) {
+                    err.jspError(start, "jsp.error.unterminated",
+                                 "&lt;jsp:attribute");
+                }
+                if (namedAttributeNode.isTrim()) {
+                    reader.skipSpaces();
+                }
+                parseBody(namedAttributeNode, "jsp:attribute", 
+                          getAttributeBodyType(parent,
+                                               attrs.getValue("name")));
+                if (namedAttributeNode.isTrim()) {
+                    Node.Nodes subElems = namedAttributeNode.getBody();
+                    if (subElems != null) {
+                        Node lastNode = subElems.getNode(subElems.size() - 1);
+                        if (lastNode instanceof Node.TemplateText) {
+                            ((Node.TemplateText)lastNode).rtrim();
+                        }
+                    }
+                }
+            }
+            reader.skipSpaces();
+        } while( reader.matches( "<jsp:attribute" ) );
+    }
+
+    /**
+     * Determine the body type of <jsp:attribute> from the enclosing node
+     */
+    private String getAttributeBodyType(Node n, String name) {
+
+        if (n instanceof Node.CustomTag) {
+            TagInfo tagInfo = ((Node.CustomTag)n).getTagInfo();
+            TagAttributeInfo[] tldAttrs = tagInfo.getAttributes();
+            for (int i=0; i<tldAttrs.length; i++) {
+                if (name.equals(tldAttrs[i].getName())) {
+                    if (tldAttrs[i].isFragment()) {
+                        return TagInfo.BODY_CONTENT_SCRIPTLESS;
+                    }
+                    if (tldAttrs[i].canBeRequestTime()) {
+                        return TagInfo.BODY_CONTENT_JSP;
+                    }
+                }
+            }
+            if (tagInfo.hasDynamicAttributes()) {
+                return TagInfo.BODY_CONTENT_JSP;
+            }
+        } else if (n instanceof Node.IncludeAction) {
+            if ("page".equals(name)) {
+                return TagInfo.BODY_CONTENT_JSP;
+            }
+        } else if (n instanceof Node.ForwardAction) {
+            if ("page".equals(name)) {
+                return TagInfo.BODY_CONTENT_JSP;
+            }
+        } else if (n instanceof Node.SetProperty) {
+            if ("value".equals(name)) {
+                return TagInfo.BODY_CONTENT_JSP;
+            }
+        } else if (n instanceof Node.UseBean) {
+            if ("beanName".equals(name)) {
+                return TagInfo.BODY_CONTENT_JSP;
+            }
+        } else if (n instanceof Node.PlugIn) {
+            if ("width".equals(name) || "height".equals(name)) {
+                return TagInfo.BODY_CONTENT_JSP;
+            }
+        } else if (n instanceof Node.ParamAction) {
+            if ("value".equals(name)) {
+                return TagInfo.BODY_CONTENT_JSP;
+            }
+        } else if (n instanceof Node.JspElement) {
+            return TagInfo.BODY_CONTENT_JSP;
+        }
+
+        return JAVAX_BODY_CONTENT_TEMPLATE_TEXT;
+    }
+
+    private void parseTagFileDirectives(Node parent)
+        throws JasperException
+    {
+        reader.setSingleFile(true);
+        reader.skipUntil("<");
+        while (reader.hasMoreInput()) {
+            start = reader.mark();
+            if (reader.matches("%--")) {
+                parseComment(parent);
+            } else if (reader.matches("%@")) {
+                parseDirective(parent);
+            } else if (reader.matches("jsp:directive.")) {
+                parseXMLDirective(parent);
+            }
+            reader.skipUntil("<");
+        }
+    }
+}
+

Added: branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/ParserController.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/ParserController.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/ParserController.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,582 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.net.JarURLConnection;
+import java.net.URL;
+import java.util.Stack;
+import java.util.jar.JarFile;
+
+import org.apache.jasper.JasperException;
+import org.apache.jasper.JspCompilationContext;
+import org.apache.jasper.xmlparser.XMLEncodingDetector;
+import org.xml.sax.Attributes;
+
+/**
+ * Controller for the parsing of a JSP page.
+ * <p>
+ * The same ParserController instance is used for a JSP page and any JSP
+ * segments included by it (via an include directive), where each segment may
+ * be provided in standard or XML syntax. This class selects and invokes the
+ * appropriate parser for the JSP page and its included segments.
+ *
+ * @author Pierre Delisle
+ * @author Jan Luehe
+ */
+class ParserController implements TagConstants {
+
+    private static final String CHARSET = "charset=";
+
+    private JspCompilationContext ctxt;
+    private Compiler compiler;
+    private ErrorDispatcher err;
+
+    /*
+     * Indicates the syntax (XML or standard) of the file being processed
+     */
+    private boolean isXml;
+
+    /*
+     * A stack to keep track of the 'current base directory'
+     * for include directives that refer to relative paths.
+     */
+    private Stack baseDirStack = new Stack();
+    
+    private boolean isEncodingSpecifiedInProlog;
+
+    private String sourceEnc;
+
+    private boolean isDefaultPageEncoding;
+    private boolean isTagFile;
+    private boolean directiveOnly;
+
+    /*
+     * Constructor
+     */
+    public ParserController(JspCompilationContext ctxt, Compiler compiler) {
+        this.ctxt = ctxt; 
+	this.compiler = compiler;
+	this.err = compiler.getErrorDispatcher();
+    }
+
+    public JspCompilationContext getJspCompilationContext () {
+	return ctxt;
+    }
+
+    public Compiler getCompiler () {
+	return compiler;
+    }
+
+    /**
+     * Parses a JSP page or tag file. This is invoked by the compiler.
+     *
+     * @param inFileName The path to the JSP page or tag file to be parsed.
+     */
+    public Node.Nodes parse(String inFileName)
+	        throws FileNotFoundException, JasperException, IOException {
+	// If we're parsing a packaged tag file or a resource included by it
+	// (using an include directive), ctxt.getTagFileJar() returns the 
+	// JAR file from which to read the tag file or included resource,
+	// respectively.
+        isTagFile = ctxt.isTagFile();
+        directiveOnly = false;
+        return doParse(inFileName, null, ctxt.getTagFileJarUrl());
+    }
+
+    /**
+     * Processes an include directive with the given path.
+     *
+     * @param inFileName The path to the resource to be included.
+     * @param parent The parent node of the include directive.
+     * @param jarFile The JAR file from which to read the included resource,
+     * or null of the included resource is to be read from the filesystem
+     */
+    public Node.Nodes parse(String inFileName, Node parent,
+			    URL jarFileUrl)
+	        throws FileNotFoundException, JasperException, IOException {
+        // For files that are statically included, isTagfile and directiveOnly
+        // remain unchanged.
+        return doParse(inFileName, parent, jarFileUrl);
+    }
+
+    /**
+     * Extracts tag file directive information from the tag file with the
+     * given name.
+     *
+     * This is invoked by the compiler 
+     *
+     * @param inFileName The name of the tag file to be parsed.
+     */
+    public Node.Nodes parseTagFileDirectives(String inFileName)
+	        throws FileNotFoundException, JasperException, IOException {
+        boolean isTagFileSave = isTagFile;
+        boolean directiveOnlySave = directiveOnly;
+        isTagFile = true;
+        directiveOnly = true;
+        Node.Nodes page = doParse(inFileName, null,
+                             (URL) ctxt.getTagFileJarUrls().get(inFileName));
+        directiveOnly = directiveOnlySave;
+        isTagFile = isTagFileSave;
+        return page;
+    }
+
+    /**
+     * Parses the JSP page or tag file with the given path name.
+     *
+     * @param inFileName The name of the JSP page or tag file to be parsed.
+     * @param parent The parent node (non-null when processing an include
+     * directive)
+     * @param isTagFile true if file to be parsed is tag file, and false if it
+     * is a regular JSP page
+     * @param directivesOnly true if the file to be parsed is a tag file and
+     * we are only interested in the directives needed for constructing a
+     * TagFileInfo.
+     * @param jarFile The JAR file from which to read the JSP page or tag file,
+     * or null if the JSP page or tag file is to be read from the filesystem
+     */
+    private Node.Nodes doParse(String inFileName,
+                               Node parent,
+                               URL jarFileUrl)
+	        throws FileNotFoundException, JasperException, IOException {
+
+	Node.Nodes parsedPage = null;
+	isEncodingSpecifiedInProlog = false;
+	isDefaultPageEncoding = false;
+
+	JarFile jarFile = getJarFile(jarFileUrl);
+	String absFileName = resolveFileName(inFileName);
+	String jspConfigPageEnc = getJspConfigPageEncoding(absFileName);
+
+	// Figure out what type of JSP document and encoding type we are
+	// dealing with
+	determineSyntaxAndEncoding(absFileName, jarFile, jspConfigPageEnc);
+
+	if (parent != null) {
+	    // Included resource, add to dependent list
+	    compiler.getPageInfo().addDependant(absFileName);
+	}
+
+	if (isXml && isEncodingSpecifiedInProlog) {
+	    /*
+	     * Make sure the encoding explicitly specified in the XML
+	     * prolog (if any) matches that in the JSP config element
+	     * (if any), treating "UTF-16", "UTF-16BE", and "UTF-16LE" as
+	     * identical.
+	     */
+	    if (jspConfigPageEnc != null && !jspConfigPageEnc.equals(sourceEnc)
+		        && (!jspConfigPageEnc.startsWith("UTF-16")
+			    || !sourceEnc.startsWith("UTF-16"))) {
+		err.jspError("jsp.error.prolog_config_encoding_mismatch",
+			     sourceEnc, jspConfigPageEnc);
+	    }
+	}
+
+	// Dispatch to the appropriate parser
+	if (isXml) {
+	    // JSP document (XML syntax)
+            // InputStream for jspx page is created and properly closed in
+            // JspDocumentParser.
+            parsedPage = JspDocumentParser.parse(this, absFileName,
+                                                 jarFile, parent,
+                                                 isTagFile, directiveOnly,
+                                                 sourceEnc,
+                                                 jspConfigPageEnc,
+                                                 isEncodingSpecifiedInProlog);
+	} else {
+	    // Standard syntax
+	    InputStreamReader inStreamReader = null;
+	    try {
+		inStreamReader = JspUtil.getReader(absFileName, sourceEnc,
+						   jarFile, ctxt, err);
+		JspReader jspReader = new JspReader(ctxt, absFileName,
+						    sourceEnc, inStreamReader,
+						    err);
+                parsedPage = Parser.parse(this, jspReader, parent, isTagFile,
+					  directiveOnly, jarFileUrl,
+					  sourceEnc, jspConfigPageEnc,
+					  isDefaultPageEncoding);
+            } finally {
+		if (inStreamReader != null) {
+		    try {
+			inStreamReader.close();
+		    } catch (Exception any) {
+		    }
+		}
+	    }
+	}
+
+	if (jarFile != null) {
+	    try {
+		jarFile.close();
+	    } catch (Throwable t) {}
+	}
+
+	baseDirStack.pop();
+
+	return parsedPage;
+    }
+
+    /*
+     * Checks to see if the given URI is matched by a URL pattern specified in
+     * a jsp-property-group in web.xml, and if so, returns the value of the
+     * <page-encoding> element.
+     *
+     * @param absFileName The URI to match
+     *
+     * @return The value of the <page-encoding> attribute of the 
+     * jsp-property-group with matching URL pattern
+     */
+    private String getJspConfigPageEncoding(String absFileName)
+            throws JasperException {
+
+	JspConfig jspConfig = ctxt.getOptions().getJspConfig();
+	JspConfig.JspProperty jspProperty
+	    = jspConfig.findJspProperty(absFileName);
+	return jspProperty.getPageEncoding();
+    }
+
+    /**
+     * Determines the syntax (standard or XML) and page encoding properties
+     * for the given file, and stores them in the 'isXml' and 'sourceEnc'
+     * instance variables, respectively.
+     */
+    private void determineSyntaxAndEncoding(String absFileName,
+					    JarFile jarFile,
+					    String jspConfigPageEnc)
+	        throws JasperException, IOException {
+
+	isXml = false;
+
+	/*
+	 * 'true' if the syntax (XML or standard) of the file is given
+	 * from external information: either via a JSP configuration element,
+	 * the ".jspx" suffix, or the enclosing file (for included resources)
+	 */
+	boolean isExternal = false;
+
+	/*
+	 * Indicates whether we need to revert from temporary usage of
+	 * "ISO-8859-1" back to "UTF-8"
+	 */
+	boolean revert = false;
+
+        JspConfig jspConfig = ctxt.getOptions().getJspConfig();
+        JspConfig.JspProperty jspProperty = jspConfig.findJspProperty(
+                                                                absFileName);
+        if (jspProperty.isXml() != null) {
+            // If <is-xml> is specified in a <jsp-property-group>, it is used.
+            isXml = JspUtil.booleanValue(jspProperty.isXml());
+	    isExternal = true;
+	} else if (absFileName.endsWith(".jspx")
+		   || absFileName.endsWith(".tagx")) {
+	    isXml = true;
+	    isExternal = true;
+	}
+	
+	if (isExternal && !isXml) {
+	    // JSP (standard) syntax. Use encoding specified in jsp-config
+	    // if provided.
+	    sourceEnc = jspConfigPageEnc;
+	    if (sourceEnc != null) {
+		return;
+	    }
+	    // We don't know the encoding
+	    sourceEnc = "ISO-8859-1";
+	} else {
+	    // XML syntax or unknown, (auto)detect encoding ...
+	    Object[] ret = XMLEncodingDetector.getEncoding(absFileName,
+							   jarFile, ctxt, err);
+	    sourceEnc = (String) ret[0];
+	    if (((Boolean) ret[1]).booleanValue()) {
+		isEncodingSpecifiedInProlog = true;
+	    }
+
+	    if (!isXml && sourceEnc.equals("UTF-8")) {
+		/*
+		 * We don't know if we're dealing with XML or standard syntax.
+		 * Therefore, we need to check to see if the page contains
+		 * a <jsp:root> element.
+		 *
+		 * We need to be careful, because the page may be encoded in
+		 * ISO-8859-1 (or something entirely different), and may
+		 * contain byte sequences that will cause a UTF-8 converter to
+		 * throw exceptions. 
+		 *
+		 * It is safe to use a source encoding of ISO-8859-1 in this
+		 * case, as there are no invalid byte sequences in ISO-8859-1,
+		 * and the byte/character sequences we're looking for (i.e.,
+		 * <jsp:root>) are identical in either encoding (both UTF-8
+		 * and ISO-8859-1 are extensions of ASCII).
+		 */
+		sourceEnc = "ISO-8859-1";
+		revert = true;
+	    }
+	}
+
+	if (isXml) {
+	    // (This implies 'isExternal' is TRUE.)
+	    // We know we're dealing with a JSP document (via JSP config or
+	    // ".jspx" suffix), so we're done.
+	    return;
+	}
+
+	/*
+	 * At this point, 'isExternal' or 'isXml' is FALSE.
+	 * Search for jsp:root action, in order to determine if we're dealing 
+	 * with XML or standard syntax (unless we already know what we're 
+	 * dealing with, i.e., when 'isExternal' is TRUE and 'isXml' is FALSE).
+	 * No check for XML prolog, since nothing prevents a page from
+	 * outputting XML and still using JSP syntax (in this case, the 
+	 * XML prolog is treated as template text).
+	 */
+	JspReader jspReader = null;
+	try {
+	    jspReader = new JspReader(ctxt, absFileName, sourceEnc, jarFile,
+				      err);
+	} catch (FileNotFoundException ex) {
+	    throw new JasperException(ex);
+	}
+        jspReader.setSingleFile(true);
+        Mark startMark = jspReader.mark();
+	if (!isExternal) {
+	    jspReader.reset(startMark);
+	    if (hasJspRoot(jspReader)) {
+	        isXml = true;
+		if (revert) sourceEnc = "UTF-8";
+		return;
+	    } else {
+	        isXml = false;
+	    }
+	}
+
+	/*
+	 * At this point, we know we're dealing with JSP syntax.
+	 * If an XML prolog is provided, it's treated as template text.
+	 * Determine the page encoding from the page directive, unless it's
+	 * specified via JSP config.
+	 */
+	sourceEnc = jspConfigPageEnc;
+	if (sourceEnc == null) {
+	    sourceEnc = getPageEncodingForJspSyntax(jspReader, startMark);
+	    if (sourceEnc == null) {
+		// Default to "ISO-8859-1" per JSP spec
+		sourceEnc = "ISO-8859-1";
+		isDefaultPageEncoding = true;
+	    }
+	}
+    }
+    
+    /*
+     * Determines page source encoding for page or tag file in JSP syntax,
+     * by reading (in this order) the value of the 'pageEncoding' page
+     * directive attribute, or the charset value of the 'contentType' page
+     * directive attribute.
+     *
+     * @return The page encoding, or null if not found
+     */
+    private String getPageEncodingForJspSyntax(JspReader jspReader,
+					       Mark startMark)
+	        throws JasperException {
+
+	String encoding = null;
+        String saveEncoding = null;
+
+        jspReader.reset(startMark);
+
+	/*
+	 * Determine page encoding from directive of the form <%@ page %>,
+	 * <%@ tag %>, <jsp:directive.page > or <jsp:directive.tag >.
+	 */
+        while (true) {
+            if (jspReader.skipUntil("<") == null) {
+                break;
+            }
+            // If this is a comment, skip until its end
+            if (jspReader.matches("%--")) {
+                if (jspReader.skipUntil("--%>") == null) {
+                    // error will be caught in Parser
+                    break;
+                }
+                continue;
+            }
+            boolean isDirective = jspReader.matches("%@");
+            if (isDirective) {
+	        jspReader.skipSpaces();
+            }
+            else {
+                isDirective = jspReader.matches("jsp:directive.");
+            }
+            if (!isDirective) {
+                continue;
+            }
+
+	    // compare for "tag ", so we don't match "taglib"
+	    if (jspReader.matches("tag ") || jspReader.matches("page")) {
+
+		jspReader.skipSpaces();
+                Attributes attrs = Parser.parseAttributes(this, jspReader);
+		encoding = getPageEncodingFromDirective(attrs, "pageEncoding");
+                if (encoding != null) {
+                    break;
+                }
+		encoding = getPageEncodingFromDirective(attrs, "contentType");
+                if (encoding != null) {
+                    saveEncoding = encoding;
+                }
+	    }
+	}
+
+        if (encoding == null) {
+            encoding = saveEncoding;
+        }
+
+	return encoding;
+    }
+
+    /*
+     * Scans the given attributes for the attribute with the given name,
+     * which is either 'pageEncoding' or 'contentType', and returns the
+     * specified page encoding.
+     *
+     * In the case of 'contentType', the page encoding is taken from the
+     * content type's 'charset' component.
+     *
+     * @param attrs The page directive attributes
+     * @param attrName The name of the attribute to search for (either
+     * 'pageEncoding' or 'contentType')
+     *
+     * @return The page encoding, or null
+     */
+    private String getPageEncodingFromDirective(Attributes attrs,
+                                                String attrName) {
+	String value = attrs.getValue(attrName);
+        if (attrName.equals("pageEncoding")) {
+            return value;
+        }
+
+        // attrName = contentType
+        String contentType = value;
+        String encoding = null;
+        if (contentType != null) {
+	    int loc = contentType.indexOf(CHARSET);
+	    if (loc != -1) {
+		encoding = contentType.substring(loc + CHARSET.length());
+	    }
+	}
+
+	return encoding;
+    }
+
+    /*
+     * Resolve the name of the file and update baseDirStack() to keep track of
+     * the current base directory for each included file.
+     * The 'root' file is always an 'absolute' path, so no need to put an
+     * initial value in the baseDirStack.
+     */
+    private String resolveFileName(String inFileName) {
+        String fileName = inFileName.replace('\\', '/');
+        boolean isAbsolute = fileName.startsWith("/");
+	fileName = isAbsolute ? fileName 
+            : (String) baseDirStack.peek() + fileName;
+	String baseDir = 
+	    fileName.substring(0, fileName.lastIndexOf("/") + 1);
+	baseDirStack.push(baseDir);
+	return fileName;
+    }
+
+    /*
+     * Checks to see if the given page contains, as its first element, a <root>
+     * element whose prefix is bound to the JSP namespace, as in:
+     *
+     * <wombat:root xmlns:wombat="http://java.sun.com/JSP/Page" version="1.2">
+     *   ...
+     * </wombat:root>
+     *
+     * @param reader The reader for this page
+     *
+     * @return true if this page contains a root element whose prefix is bound
+     * to the JSP namespace, and false otherwise
+     */
+    private boolean hasJspRoot(JspReader reader) throws JasperException {
+
+	// <prefix>:root must be the first element
+	Mark start = null;
+	while ((start = reader.skipUntil("<")) != null) {
+	    int c = reader.nextChar();
+	    if (c != '!' && c != '?') break;
+	}
+	if (start == null) {
+	    return false;
+	}
+	Mark stop = reader.skipUntil(":root");
+	if (stop == null) {
+	    return false;
+	}
+	// call substring to get rid of leading '<'
+	String prefix = reader.getText(start, stop).substring(1);
+
+	start = stop;
+	stop = reader.skipUntil(">");
+	if (stop == null) {
+	    return false;
+	}
+
+	// Determine namespace associated with <root> element's prefix
+	String root = reader.getText(start, stop);
+	String xmlnsDecl = "xmlns:" + prefix;
+	int index = root.indexOf(xmlnsDecl);
+	if (index == -1) {
+	    return false;
+	}
+	index += xmlnsDecl.length();
+	while (index < root.length()
+	           && Character.isWhitespace(root.charAt(index))) {
+	    index++;
+	}
+	if (index < root.length() && root.charAt(index) == '=') {
+	    index++;
+	    while (index < root.length()
+		       && Character.isWhitespace(root.charAt(index))) {
+		index++;
+	    }
+	    if (index < root.length() && root.charAt(index++) == '"'
+		    && root.regionMatches(index, JSP_URI, 0,
+					  JSP_URI.length())) {
+		return true;
+	    }
+	}
+
+	return false;
+    }
+
+    private JarFile getJarFile(URL jarFileUrl) throws IOException {
+	JarFile jarFile = null;
+
+	if (jarFileUrl != null) {
+	    JarURLConnection conn = (JarURLConnection) jarFileUrl.openConnection();
+	    conn.setUseCaches(false);
+	    conn.connect();
+	    jarFile = conn.getJarFile();
+	}
+
+	return jarFile;
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/ScriptingVariabler.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/ScriptingVariabler.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/ScriptingVariabler.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,147 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.util.*;
+import javax.servlet.jsp.tagext.*;
+import org.apache.jasper.JasperException;
+
+/**
+ * Class responsible for determining the scripting variables that every
+ * custom action needs to declare.
+ *
+ * @author Jan Luehe
+ */
+class ScriptingVariabler {
+
+    private static final Integer MAX_SCOPE = new Integer(Integer.MAX_VALUE);
+
+    /*
+     * Assigns an identifier (of type integer) to every custom tag, in order
+     * to help identify, for every custom tag, the scripting variables that it
+     * needs to declare.
+     */
+    static class CustomTagCounter extends Node.Visitor {
+
+	private int count;
+	private Node.CustomTag parent;
+
+	public void visit(Node.CustomTag n) throws JasperException {
+	    n.setCustomTagParent(parent);
+	    Node.CustomTag tmpParent = parent;
+	    parent = n;
+	    visitBody(n);
+	    parent = tmpParent;
+	    n.setNumCount(new Integer(count++));
+	}
+    }
+
+    /*
+     * For every custom tag, determines the scripting variables it needs to
+     * declare. 
+     */
+    static class ScriptingVariableVisitor extends Node.Visitor {
+
+	private ErrorDispatcher err;
+	private Hashtable scriptVars;
+	
+	public ScriptingVariableVisitor(ErrorDispatcher err) {
+	    this.err = err;
+	    scriptVars = new Hashtable();
+	}
+
+	public void visit(Node.CustomTag n) throws JasperException {
+	    setScriptingVars(n, VariableInfo.AT_BEGIN);
+	    setScriptingVars(n, VariableInfo.NESTED);
+	    visitBody(n);
+	    setScriptingVars(n, VariableInfo.AT_END);
+	}
+
+	private void setScriptingVars(Node.CustomTag n, int scope)
+	        throws JasperException {
+
+	    TagVariableInfo[] tagVarInfos = n.getTagVariableInfos();
+	    VariableInfo[] varInfos = n.getVariableInfos();
+	    if (tagVarInfos.length == 0 && varInfos.length == 0) {
+		return;
+	    }
+
+	    Vector vec = new Vector();
+
+	    Integer ownRange = null;
+	    if (scope == VariableInfo.AT_BEGIN
+		    || scope == VariableInfo.AT_END) {
+		Node.CustomTag parent = n.getCustomTagParent();
+		if (parent == null)
+		    ownRange = MAX_SCOPE;
+		else
+		    ownRange = parent.getNumCount();
+	    } else {
+		// NESTED
+		ownRange = n.getNumCount();
+	    }
+
+	    if (varInfos.length > 0) {
+		for (int i=0; i<varInfos.length; i++) {
+		    if (varInfos[i].getScope() != scope
+			    || !varInfos[i].getDeclare()) {
+			continue;
+		    }
+		    String varName = varInfos[i].getVarName();
+		    
+		    Integer currentRange = (Integer) scriptVars.get(varName);
+		    if (currentRange == null
+			    || ownRange.compareTo(currentRange) > 0) {
+			scriptVars.put(varName, ownRange);
+			vec.add(varInfos[i]);
+		    }
+		}
+	    } else {
+		for (int i=0; i<tagVarInfos.length; i++) {
+		    if (tagVarInfos[i].getScope() != scope
+			    || !tagVarInfos[i].getDeclare()) {
+			continue;
+		    }
+		    String varName = tagVarInfos[i].getNameGiven();
+		    if (varName == null) {
+			varName = n.getTagData().getAttributeString(
+		                        tagVarInfos[i].getNameFromAttribute());
+			if (varName == null) {
+			    err.jspError(n, "jsp.error.scripting.variable.missing_name",
+					 tagVarInfos[i].getNameFromAttribute());
+			}
+		    }
+
+		    Integer currentRange = (Integer) scriptVars.get(varName);
+		    if (currentRange == null
+			    || ownRange.compareTo(currentRange) > 0) {
+			scriptVars.put(varName, ownRange);
+			vec.add(tagVarInfos[i]);
+		    }
+		}
+	    }
+
+	    n.setScriptingVars(vec, scope);
+	}
+    }
+
+    public static void set(Node.Nodes page, ErrorDispatcher err)
+	    throws JasperException {
+	page.visit(new CustomTagCounter());
+	page.visit(new ScriptingVariableVisitor(err));
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/ServletWriter.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/ServletWriter.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/ServletWriter.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,175 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.IOException;
+import java.io.PrintWriter;
+
+/**
+ * This is what is used to generate servlets. 
+ *
+ * @author Anil K. Vijendran
+ * @author Kin-man Chung
+ */
+public class ServletWriter {
+    public static int TAB_WIDTH = 2;
+    public static String SPACES = "                              ";
+
+    // Current indent level:
+    private int indent = 0;
+    private int virtual_indent = 0;
+
+    // The sink writer:
+    PrintWriter writer;
+    
+    // servlet line numbers start from 1
+    private int javaLine = 1;
+
+
+    public ServletWriter(PrintWriter writer) {
+	this.writer = writer;
+    }
+
+    public void close() throws IOException {
+	writer.close();
+    }
+
+    
+    // -------------------- Access informations --------------------
+
+    public int getJavaLine() {
+        return javaLine;
+    }
+
+
+    // -------------------- Formatting --------------------
+
+    public void pushIndent() {
+	virtual_indent += TAB_WIDTH;
+	if (virtual_indent >= 0 && virtual_indent <= SPACES.length())
+	    indent = virtual_indent;
+    }
+
+    public void popIndent() {
+	virtual_indent -= TAB_WIDTH;
+	if (virtual_indent >= 0 && virtual_indent <= SPACES.length())
+	    indent = virtual_indent;
+    }
+
+    /**
+     * Print a standard comment for echo outputed chunk.
+     * @param start The starting position of the JSP chunk being processed. 
+     * @param stop  The ending position of the JSP chunk being processed. 
+     */
+    public void printComment(Mark start, Mark stop, char[] chars) {
+        if (start != null && stop != null) {
+            println("// from="+start);
+            println("//   to="+stop);
+        }
+        
+        if (chars != null)
+            for(int i = 0; i < chars.length;) {
+                printin();
+                print("// ");
+                while (chars[i] != '\n' && i < chars.length)
+                    writer.print(chars[i++]);
+            }
+    }
+
+    /**
+     * Prints the given string followed by '\n'
+     */
+    public void println(String s) {
+        javaLine++;
+	writer.println(s);
+    }
+
+    /**
+     * Prints a '\n'
+     */
+    public void println() {
+        javaLine++;
+	writer.println("");
+    }
+
+    /**
+     * Prints the current indention
+     */
+    public void printin() {
+	writer.print(SPACES.substring(0, indent));
+    }
+
+    /**
+     * Prints the current indention, followed by the given string
+     */
+    public void printin(String s) {
+	writer.print(SPACES.substring(0, indent));
+	writer.print(s);
+    }
+
+    /**
+     * Prints the current indention, and then the string, and a '\n'.
+     */
+    public void printil(String s) {
+        javaLine++;
+	writer.print(SPACES.substring(0, indent));
+	writer.println(s);
+    }
+
+    /**
+     * Prints the given char.
+     *
+     * Use println() to print a '\n'.
+     */
+    public void print(char c) {
+	writer.print(c);
+    }
+
+    /**
+     * Prints the given int.
+     */
+    public void print(int i) {
+	writer.print(i);
+    }
+
+    /**
+     * Prints the given string.
+     *
+     * The string must not contain any '\n', otherwise the line count will be
+     * off.
+     */
+    public void print(String s) {
+	writer.print(s);
+    }
+
+    /**
+     * Prints the given string.
+     *
+     * If the string spans multiple lines, the line count will be adjusted
+     * accordingly.
+     */
+    public void printMultiLn(String s) {
+        int index = 0;
+
+        // look for hidden newlines inside strings
+        while ((index=s.indexOf('\n',index)) > -1 ) {
+            javaLine++;
+            index++;
+        }
+
+	writer.print(s);
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/SmapGenerator.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/SmapGenerator.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/SmapGenerator.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,170 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.util.List;
+import java.util.ArrayList;
+
+/**
+ * Represents a source map (SMAP), which serves to associate lines
+ * of the input JSP file(s) to lines in the generated servlet in the
+ * final .class file, according to the JSR-045 spec.
+ * 
+ * @author Shawn Bayern
+ */
+public class SmapGenerator {
+
+    //*********************************************************************
+    // Overview
+
+    /*
+     * The SMAP syntax is reasonably straightforward.  The purpose of this
+     * class is currently twofold:
+     *  - to provide a simple but low-level Java interface to build
+     *    a logical SMAP
+     *  - to serialize this logical SMAP for eventual inclusion directly
+     *    into a .class file.
+     */
+
+
+    //*********************************************************************
+    // Private state
+
+    private String outputFileName;
+    private String defaultStratum = "Java";
+    private List strata = new ArrayList();
+    private List embedded = new ArrayList();
+    private boolean doEmbedded = true;
+
+    //*********************************************************************
+    // Methods for adding mapping data
+
+    /**
+     * Sets the filename (without path information) for the generated
+     * source file.  E.g., "foo$jsp.java".
+     */
+    public synchronized void setOutputFileName(String x) {
+	outputFileName = x;
+    }
+
+    /**
+     * Adds the given SmapStratum object, representing a Stratum with
+     * logically associated FileSection and LineSection blocks, to
+     * the current SmapGenerator.  If <tt>default</tt> is true, this
+     * stratum is made the default stratum, overriding any previously
+     * set default.
+     *
+     * @param stratum the SmapStratum object to add
+     * @param defaultStratum if <tt>true</tt>, this SmapStratum is considered
+     *                to represent the default SMAP stratum unless
+     *                overwritten
+     */
+    public synchronized void addStratum(SmapStratum stratum,
+					boolean defaultStratum) {
+	strata.add(stratum);
+	if (defaultStratum)
+	    this.defaultStratum = stratum.getStratumName();
+    }
+
+    /**
+     * Adds the given string as an embedded SMAP with the given stratum name.
+     *
+     * @param smap the SMAP to embed
+     * @param stratumName the name of the stratum output by the compilation
+     *                    that produced the <tt>smap</tt> to be embedded
+     */
+    public synchronized void addSmap(String smap, String stratumName) {
+	embedded.add("*O " + stratumName + "\n"
+		   + smap
+		   + "*C " + stratumName + "\n");
+    }
+
+    /**
+     * Instructs the SmapGenerator whether to actually print any embedded
+     * SMAPs or not.  Intended for situations without an SMAP resolver.
+     *
+     * @param status If <tt>false</tt>, ignore any embedded SMAPs.
+     */
+    public void setDoEmbedded(boolean status) {
+	doEmbedded = status;
+    }
+
+    //*********************************************************************
+    // Methods for serializing the logical SMAP
+
+    public synchronized String getString() {
+	// check state and initialize buffer
+	if (outputFileName == null)
+	    throw new IllegalStateException();
+        StringBuffer out = new StringBuffer();
+
+	// start the SMAP
+	out.append("SMAP\n");
+	out.append(outputFileName + '\n');
+	out.append(defaultStratum + '\n');
+
+	// include embedded SMAPs
+	if (doEmbedded) {
+	    int nEmbedded = embedded.size();
+	    for (int i = 0; i < nEmbedded; i++) {
+	        out.append(embedded.get(i));
+	    }
+	}
+
+	// print our StratumSections, FileSections, and LineSections
+	int nStrata = strata.size();
+	for (int i = 0; i < nStrata; i++) {
+	    SmapStratum s = (SmapStratum) strata.get(i);
+	    out.append(s.getString());
+	}
+
+	// end the SMAP
+	out.append("*E\n");
+
+	return out.toString();
+    }
+
+    public String toString() { return getString(); }
+
+    //*********************************************************************
+    // For testing (and as an example of use)...
+
+    public static void main(String args[]) {
+	SmapGenerator g = new SmapGenerator();
+	g.setOutputFileName("foo.java");
+	SmapStratum s = new SmapStratum("JSP");
+	s.addFile("foo.jsp");
+	s.addFile("bar.jsp", "/foo/foo/bar.jsp");
+	s.addLineData(1, "foo.jsp", 1, 1, 1);
+	s.addLineData(2, "foo.jsp", 1, 6, 1);
+	s.addLineData(3, "foo.jsp", 2, 10, 5);
+	s.addLineData(20, "bar.jsp", 1, 30, 1);
+	g.addStratum(s, true);
+	System.out.print(g);
+
+	System.out.println("---");
+
+	SmapGenerator embedded = new SmapGenerator();
+	embedded.setOutputFileName("blargh.tier2");
+	s = new SmapStratum("Tier2");
+	s.addFile("1.tier2");
+	s.addLineData(1, "1.tier2", 1, 1, 1);
+	embedded.addStratum(s, true);
+	g.addSmap(embedded.toString(), "JSP");
+	System.out.println(g);
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/SmapStratum.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/SmapStratum.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/SmapStratum.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,335 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.util.List;
+import java.util.ArrayList;
+
+/**
+ * Represents the line and file mappings associated with a JSR-045
+ * "stratum".
+ *
+ * @author Jayson Falkner
+ * @author Shawn Bayern
+ */
+public class SmapStratum {
+
+    //*********************************************************************
+    // Class for storing LineInfo data
+
+    /**
+     * Represents a single LineSection in an SMAP, associated with
+     * a particular stratum.
+     */
+    public static class LineInfo {
+        private int inputStartLine = -1;
+        private int outputStartLine = -1;
+        private int lineFileID = 0;
+        private int inputLineCount = 1;
+        private int outputLineIncrement = 1;
+        private boolean lineFileIDSet = false;
+
+        /** Sets InputStartLine. */
+        public void setInputStartLine(int inputStartLine) {
+            if (inputStartLine < 0)
+                throw new IllegalArgumentException("" + inputStartLine);
+            this.inputStartLine = inputStartLine;
+        }
+
+        /** Sets OutputStartLine. */
+        public void setOutputStartLine(int outputStartLine) {
+            if (outputStartLine < 0)
+                throw new IllegalArgumentException("" + outputStartLine);
+            this.outputStartLine = outputStartLine;
+        }
+
+        /**
+             * Sets lineFileID.  Should be called only when different from
+             * that of prior LineInfo object (in any given context) or 0
+             * if the current LineInfo has no (logical) predecessor.
+             * <tt>LineInfo</tt> will print this file number no matter what.
+             */
+        public void setLineFileID(int lineFileID) {
+            if (lineFileID < 0)
+                throw new IllegalArgumentException("" + lineFileID);
+            this.lineFileID = lineFileID;
+            this.lineFileIDSet = true;
+        }
+
+        /** Sets InputLineCount. */
+        public void setInputLineCount(int inputLineCount) {
+            if (inputLineCount < 0)
+                throw new IllegalArgumentException("" + inputLineCount);
+            this.inputLineCount = inputLineCount;
+        }
+
+        /** Sets OutputLineIncrement. */
+        public void setOutputLineIncrement(int outputLineIncrement) {
+            if (outputLineIncrement < 0)
+                throw new IllegalArgumentException("" + outputLineIncrement);
+            this.outputLineIncrement = outputLineIncrement;
+        }
+
+        /**
+         * Retrieves the current LineInfo as a String, print all values
+         * only when appropriate (but LineInfoID if and only if it's been
+         * specified, as its necessity is sensitive to context).
+         */
+        public String getString() {
+            if (inputStartLine == -1 || outputStartLine == -1)
+                throw new IllegalStateException();
+            StringBuffer out = new StringBuffer();
+            out.append(inputStartLine);
+            if (lineFileIDSet)
+                out.append("#" + lineFileID);
+            if (inputLineCount != 1)
+                out.append("," + inputLineCount);
+            out.append(":" + outputStartLine);
+            if (outputLineIncrement != 1)
+                out.append("," + outputLineIncrement);
+            out.append('\n');
+            return out.toString();
+        }
+
+        public String toString() {
+            return getString();
+        }
+    }
+
+    //*********************************************************************
+    // Private state
+
+    private String stratumName;
+    private List fileNameList;
+    private List filePathList;
+    private List lineData;
+    private int lastFileID;
+
+    //*********************************************************************
+    // Constructor
+
+    /**
+     * Constructs a new SmapStratum object for the given stratum name
+     * (e.g., JSP).
+     *
+     * @param stratumName the name of the stratum (e.g., JSP)
+     */
+    public SmapStratum(String stratumName) {
+        this.stratumName = stratumName;
+        fileNameList = new ArrayList();
+        filePathList = new ArrayList();
+        lineData = new ArrayList();
+        lastFileID = 0;
+    }
+
+    //*********************************************************************
+    // Methods to add mapping information
+
+    /**
+     * Adds record of a new file, by filename.
+     *
+     * @param filename the filename to add, unqualified by path.
+     */
+    public void addFile(String filename) {
+        addFile(filename, filename);
+    }
+
+    /**
+     * Adds record of a new file, by filename and path.  The path
+     * may be relative to a source compilation path.
+     *
+     * @param filename the filename to add, unqualified by path
+     * @param filePath the path for the filename, potentially relative
+     *                 to a source compilation path
+     */
+    public void addFile(String filename, String filePath) {
+        int pathIndex = filePathList.indexOf(filePath);
+        if (pathIndex == -1) {
+            fileNameList.add(filename);
+            filePathList.add(filePath);
+        }
+    }
+
+    /**
+     * Combines consecutive LineInfos wherever possible
+     */
+    public void optimizeLineSection() {
+
+/* Some debugging code
+        for (int i = 0; i < lineData.size(); i++) {
+            LineInfo li = (LineInfo)lineData.get(i);
+            System.out.print(li.toString());
+        }
+*/
+        //Incorporate each LineInfo into the previous LineInfo's 
+        //outputLineIncrement, if possible
+        int i = 0;
+        while (i < lineData.size() - 1) {
+            LineInfo li = (LineInfo)lineData.get(i);
+            LineInfo liNext = (LineInfo)lineData.get(i + 1);
+            if (!liNext.lineFileIDSet
+                && liNext.inputStartLine == li.inputStartLine
+                && liNext.inputLineCount == 1
+                && li.inputLineCount == 1
+                && liNext.outputStartLine
+                    == li.outputStartLine
+                        + li.inputLineCount * li.outputLineIncrement) {
+                li.setOutputLineIncrement(
+                    liNext.outputStartLine
+                        - li.outputStartLine
+                        + liNext.outputLineIncrement);
+                lineData.remove(i + 1);
+            } else {
+                i++;
+            }
+        }
+
+        //Incorporate each LineInfo into the previous LineInfo's
+        //inputLineCount, if possible
+        i = 0;
+        while (i < lineData.size() - 1) {
+            LineInfo li = (LineInfo)lineData.get(i);
+            LineInfo liNext = (LineInfo)lineData.get(i + 1);
+            if (!liNext.lineFileIDSet
+                && liNext.inputStartLine == li.inputStartLine + li.inputLineCount
+                && liNext.outputLineIncrement == li.outputLineIncrement
+                && liNext.outputStartLine
+                    == li.outputStartLine
+                        + li.inputLineCount * li.outputLineIncrement) {
+                li.setInputLineCount(li.inputLineCount + liNext.inputLineCount);
+                lineData.remove(i + 1);
+            } else {
+                i++;
+            }
+        }
+    }
+
+    /**
+     * Adds complete information about a simple line mapping.  Specify
+     * all the fields in this method; the back-end machinery takes care
+     * of printing only those that are necessary in the final SMAP.
+     * (My view is that fields are optional primarily for spatial efficiency,
+     * not for programmer convenience.  Could always add utility methods
+     * later.)
+     *
+     * @param inputStartLine starting line in the source file
+     *        (SMAP <tt>InputStartLine</tt>)
+     * @param inputFileName the filepath (or name) from which the input comes
+     *        (yields SMAP <tt>LineFileID</tt>)  Use unqualified names
+     *        carefully, and only when they uniquely identify a file.
+     * @param inputLineCount the number of lines in the input to map
+     *        (SMAP <tt>LineFileCount</tt>)
+     * @param outputStartLine starting line in the output file 
+     *        (SMAP <tt>OutputStartLine</tt>)
+     * @param outputLineIncrement number of output lines to map to each
+     *        input line (SMAP <tt>OutputLineIncrement</tt>).  <i>Given the
+     *        fact that the name starts with "output", I continuously have
+     *        the subconscious urge to call this field
+     *        <tt>OutputLineExcrement</tt>.</i>
+     */
+    public void addLineData(
+        int inputStartLine,
+        String inputFileName,
+        int inputLineCount,
+        int outputStartLine,
+        int outputLineIncrement) {
+        // check the input - what are you doing here??
+        int fileIndex = filePathList.indexOf(inputFileName);
+        if (fileIndex == -1) // still
+            throw new IllegalArgumentException(
+                "inputFileName: " + inputFileName);
+
+        //Jasper incorrectly SMAPs certain Nodes, giving them an 
+        //outputStartLine of 0.  This can cause a fatal error in
+        //optimizeLineSection, making it impossible for Jasper to
+        //compile the JSP.  Until we can fix the underlying
+        //SMAPping problem, we simply ignore the flawed SMAP entries.
+        if (outputStartLine == 0)
+            return;
+
+        // build the LineInfo
+        LineInfo li = new LineInfo();
+        li.setInputStartLine(inputStartLine);
+        li.setInputLineCount(inputLineCount);
+        li.setOutputStartLine(outputStartLine);
+        li.setOutputLineIncrement(outputLineIncrement);
+        if (fileIndex != lastFileID)
+            li.setLineFileID(fileIndex);
+        lastFileID = fileIndex;
+
+        // save it
+        lineData.add(li);
+    }
+
+    //*********************************************************************
+    // Methods to retrieve information
+
+    /**
+     * Returns the name of the stratum.
+     */
+    public String getStratumName() {
+        return stratumName;
+    }
+
+    /**
+     * Returns the given stratum as a String:  a StratumSection,
+     * followed by at least one FileSection and at least one LineSection.
+     */
+    public String getString() {
+        // check state and initialize buffer
+        if (fileNameList.size() == 0 || lineData.size() == 0)
+            return null;
+
+        StringBuffer out = new StringBuffer();
+
+        // print StratumSection
+        out.append("*S " + stratumName + "\n");
+
+        // print FileSection
+        out.append("*F\n");
+        int bound = fileNameList.size();
+        for (int i = 0; i < bound; i++) {
+            if (filePathList.get(i) != null) {
+                out.append("+ " + i + " " + fileNameList.get(i) + "\n");
+                // Source paths must be relative, not absolute, so we
+                // remove the leading "/", if one exists.
+                String filePath = (String)filePathList.get(i);
+                if (filePath.startsWith("/")) {
+                    filePath = filePath.substring(1);
+                }
+                out.append(filePath + "\n");
+            } else {
+                out.append(i + " " + fileNameList.get(i) + "\n");
+            }
+        }
+
+        // print LineSection
+        out.append("*L\n");
+        bound = lineData.size();
+        for (int i = 0; i < bound; i++) {
+            LineInfo li = (LineInfo)lineData.get(i);
+            out.append(li.getString());
+        }
+
+        return out.toString();
+    }
+
+    public String toString() {
+        return getString();
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/SmapUtil.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/SmapUtil.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/SmapUtil.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,728 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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 java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+import java.io.UnsupportedEncodingException;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import org.apache.jasper.JasperException;
+import org.apache.jasper.JspCompilationContext;
+
+/**
+ * Contains static utilities for generating SMAP data based on the
+ * current version of Jasper.
+ * 
+ * @author Jayson Falkner
+ * @author Shawn Bayern
+ * @author Robert Field (inner SDEInstaller class)
+ * @author Mark Roth
+ * @author Kin-man Chung
+ */
+public class SmapUtil {
+
+    private org.apache.commons.logging.Log log=
+        org.apache.commons.logging.LogFactory.getLog( SmapUtil.class );
+
+    //*********************************************************************
+    // Constants
+
+    public static final String SMAP_ENCODING = "UTF-8";
+
+    //*********************************************************************
+    // Public entry points
+
+    /**
+     * Generates an appropriate SMAP representing the current compilation
+     * context.  (JSR-045.)
+     *
+     * @param ctxt Current compilation context
+     * @param pageNodes The current JSP page
+     * @return a SMAP for the page
+     */
+    public static String[] generateSmap(
+        JspCompilationContext ctxt,
+        Node.Nodes pageNodes)
+        throws IOException {
+
+        // Scan the nodes for presence of Jasper generated inner classes
+        PreScanVisitor psVisitor = new PreScanVisitor();
+        try {
+            pageNodes.visit(psVisitor);
+        } catch (JasperException ex) {
+        }
+        HashMap map = psVisitor.getMap();
+
+        // set up our SMAP generator
+        SmapGenerator g = new SmapGenerator();
+        
+        /** Disable reading of input SMAP because:
+            1. There is a bug here: getRealPath() is null if .jsp is in a jar
+        	Bugzilla 14660.
+            2. Mappings from other sources into .jsp files are not supported.
+            TODO: fix 1. if 2. is not true.
+        // determine if we have an input SMAP
+        String smapPath = inputSmapPath(ctxt.getRealPath(ctxt.getJspFile()));
+            File inputSmap = new File(smapPath);
+            if (inputSmap.exists()) {
+                byte[] embeddedSmap = null;
+            byte[] subSmap = SDEInstaller.readWhole(inputSmap);
+            String subSmapString = new String(subSmap, SMAP_ENCODING);
+            g.addSmap(subSmapString, "JSP");
+        }
+        **/
+
+        // now, assemble info about our own stratum (JSP) using JspLineMap
+        SmapStratum s = new SmapStratum("JSP");
+
+        g.setOutputFileName(unqualify(ctxt.getServletJavaFileName()));
+
+        // Map out Node.Nodes
+        evaluateNodes(pageNodes, s, map, ctxt.getOptions().getMappedFile());
+        s.optimizeLineSection();
+        g.addStratum(s, true);
+
+        if (ctxt.getOptions().isSmapDumped()) {
+            File outSmap = new File(ctxt.getClassFileName() + ".smap");
+            PrintWriter so =
+                new PrintWriter(
+                    new OutputStreamWriter(
+                        new FileOutputStream(outSmap),
+                        SMAP_ENCODING));
+            so.print(g.getString());
+            so.close();
+        }
+
+        String classFileName = ctxt.getClassFileName();
+        int innerClassCount = map.size();
+        String [] smapInfo = new String[2 + innerClassCount*2];
+        smapInfo[0] = classFileName;
+        smapInfo[1] = g.getString();
+
+        int count = 2;
+        Iterator iter = map.entrySet().iterator();
+        while (iter.hasNext()) {
+            Map.Entry entry = (Map.Entry) iter.next();
+            String innerClass = (String) entry.getKey();
+            s = (SmapStratum) entry.getValue();
+            s.optimizeLineSection();
+            g = new SmapGenerator();
+            g.setOutputFileName(unqualify(ctxt.getServletJavaFileName()));
+            g.addStratum(s, true);
+
+            String innerClassFileName =
+                classFileName.substring(0, classFileName.indexOf(".class")) +
+                '$' + innerClass + ".class";
+            if (ctxt.getOptions().isSmapDumped()) {
+                File outSmap = new File(innerClassFileName + ".smap");
+                PrintWriter so =
+                    new PrintWriter(
+                        new OutputStreamWriter(
+                            new FileOutputStream(outSmap),
+                            SMAP_ENCODING));
+                so.print(g.getString());
+                so.close();
+            }
+            smapInfo[count] = innerClassFileName;
+            smapInfo[count+1] = g.getString();
+            count += 2;
+        }
+
+        return smapInfo;
+    }
+
+    public static void installSmap(String[] smap)
+        throws IOException {
+        if (smap == null) {
+            return;
+        }
+
+        for (int i = 0; i < smap.length; i += 2) {
+            File outServlet = new File(smap[i]);
+            SDEInstaller.install(outServlet, smap[i+1].getBytes());
+        }
+    }
+
+    //*********************************************************************
+    // Private utilities
+
+    /**
+     * Returns an unqualified version of the given file path.
+     */
+    private static String unqualify(String path) {
+        path = path.replace('\\', '/');
+        return path.substring(path.lastIndexOf('/') + 1);
+    }
+
+    /**
+     * Returns a file path corresponding to a potential SMAP input
+     * for the given compilation input (JSP file).
+     */
+    private static String inputSmapPath(String path) {
+        return path.substring(0, path.lastIndexOf('.') + 1) + "smap";
+    }
+
+    //*********************************************************************
+    // Installation logic (from Robert Field, JSR-045 spec lead)
+    private static class SDEInstaller {
+
+        private org.apache.commons.logging.Log log=
+            org.apache.commons.logging.LogFactory.getLog( SDEInstaller.class );
+
+        static final String nameSDE = "SourceDebugExtension";
+
+        byte[] orig;
+        byte[] sdeAttr;
+        byte[] gen;
+
+        int origPos = 0;
+        int genPos = 0;
+
+        int sdeIndex;
+
+        public static void main(String[] args) throws IOException {
+            if (args.length == 2) {
+                install(new File(args[0]), new File(args[1]));
+            } else if (args.length == 3) {
+                install(
+                    new File(args[0]),
+                    new File(args[1]),
+                    new File(args[2]));
+            } else {
+                System.err.println(
+                    "Usage: <command> <input class file> "
+                        + "<attribute file> <output class file name>\n"
+                        + "<command> <input/output class file> <attribute file>");
+            }
+        }
+
+        static void install(File inClassFile, File attrFile, File outClassFile)
+            throws IOException {
+            new SDEInstaller(inClassFile, attrFile, outClassFile);
+        }
+
+        static void install(File inOutClassFile, File attrFile)
+            throws IOException {
+            File tmpFile = new File(inOutClassFile.getPath() + "tmp");
+            new SDEInstaller(inOutClassFile, attrFile, tmpFile);
+            if (!inOutClassFile.delete()) {
+                throw new IOException("inOutClassFile.delete() failed");
+            }
+            if (!tmpFile.renameTo(inOutClassFile)) {
+                throw new IOException("tmpFile.renameTo(inOutClassFile) failed");
+            }
+        }
+
+        static void install(File classFile, byte[] smap) throws IOException {
+            File tmpFile = new File(classFile.getPath() + "tmp");
+            new SDEInstaller(classFile, smap, tmpFile);
+            if (!classFile.delete()) {
+                throw new IOException("classFile.delete() failed");
+            }
+            if (!tmpFile.renameTo(classFile)) {
+                throw new IOException("tmpFile.renameTo(classFile) failed");
+            }
+        }
+
+        SDEInstaller(File inClassFile, byte[] sdeAttr, File outClassFile)
+            throws IOException {
+            if (!inClassFile.exists()) {
+                throw new FileNotFoundException("no such file: " + inClassFile);
+            }
+
+            this.sdeAttr = sdeAttr;
+            // get the bytes
+            orig = readWhole(inClassFile);
+            gen = new byte[orig.length + sdeAttr.length + 100];
+
+            // do it
+            addSDE();
+
+            // write result
+            FileOutputStream outStream = new FileOutputStream(outClassFile);
+            outStream.write(gen, 0, genPos);
+            outStream.close();
+        }
+
+        SDEInstaller(File inClassFile, File attrFile, File outClassFile)
+            throws IOException {
+            this(inClassFile, readWhole(attrFile), outClassFile);
+        }
+
+        static byte[] readWhole(File input) throws IOException {
+            FileInputStream inStream = new FileInputStream(input);
+            int len = (int)input.length();
+            byte[] bytes = new byte[len];
+            if (inStream.read(bytes, 0, len) != len) {
+                throw new IOException("expected size: " + len);
+            }
+            inStream.close();
+            return bytes;
+        }
+
+        void addSDE() throws UnsupportedEncodingException, IOException {
+            int i;
+            copy(4 + 2 + 2); // magic min/maj version
+            int constantPoolCountPos = genPos;
+            int constantPoolCount = readU2();
+            if (log.isDebugEnabled())
+                log.debug("constant pool count: " + constantPoolCount);
+            writeU2(constantPoolCount);
+
+            // copy old constant pool return index of SDE symbol, if found
+            sdeIndex = copyConstantPool(constantPoolCount);
+            if (sdeIndex < 0) {
+                // if "SourceDebugExtension" symbol not there add it
+                writeUtf8ForSDE();
+
+                // increment the countantPoolCount
+                sdeIndex = constantPoolCount;
+                ++constantPoolCount;
+                randomAccessWriteU2(constantPoolCountPos, constantPoolCount);
+
+                if (log.isDebugEnabled())
+                    log.debug("SourceDebugExtension not found, installed at: " + sdeIndex);
+            } else {
+                if (log.isDebugEnabled())
+                    log.debug("SourceDebugExtension found at: " + sdeIndex);
+            }
+            copy(2 + 2 + 2); // access, this, super
+            int interfaceCount = readU2();
+            writeU2(interfaceCount);
+            if (log.isDebugEnabled())
+                log.debug("interfaceCount: " + interfaceCount);
+            copy(interfaceCount * 2);
+            copyMembers(); // fields
+            copyMembers(); // methods
+            int attrCountPos = genPos;
+            int attrCount = readU2();
+            writeU2(attrCount);
+            if (log.isDebugEnabled())
+                log.debug("class attrCount: " + attrCount);
+            // copy the class attributes, return true if SDE attr found (not copied)
+            if (!copyAttrs(attrCount)) {
+                // we will be adding SDE and it isn't already counted
+                ++attrCount;
+                randomAccessWriteU2(attrCountPos, attrCount);
+                if (log.isDebugEnabled())
+                    log.debug("class attrCount incremented");
+            }
+            writeAttrForSDE(sdeIndex);
+        }
+
+        void copyMembers() {
+            int count = readU2();
+            writeU2(count);
+            if (log.isDebugEnabled())
+                log.debug("members count: " + count);
+            for (int i = 0; i < count; ++i) {
+                copy(6); // access, name, descriptor
+                int attrCount = readU2();
+                writeU2(attrCount);
+                if (log.isDebugEnabled())
+                    log.debug("member attr count: " + attrCount);
+                copyAttrs(attrCount);
+            }
+        }
+
+        boolean copyAttrs(int attrCount) {
+            boolean sdeFound = false;
+            for (int i = 0; i < attrCount; ++i) {
+                int nameIndex = readU2();
+                // don't write old SDE
+                if (nameIndex == sdeIndex) {
+                    sdeFound = true;
+                    if (log.isDebugEnabled())
+                        log.debug("SDE attr found");
+                } else {
+                    writeU2(nameIndex); // name
+                    int len = readU4();
+                    writeU4(len);
+                    copy(len);
+                    if (log.isDebugEnabled())
+                        log.debug("attr len: " + len);
+                }
+            }
+            return sdeFound;
+        }
+
+        void writeAttrForSDE(int index) {
+            writeU2(index);
+            writeU4(sdeAttr.length);
+            for (int i = 0; i < sdeAttr.length; ++i) {
+                writeU1(sdeAttr[i]);
+            }
+        }
+
+        void randomAccessWriteU2(int pos, int val) {
+            int savePos = genPos;
+            genPos = pos;
+            writeU2(val);
+            genPos = savePos;
+        }
+
+        int readU1() {
+            return ((int)orig[origPos++]) & 0xFF;
+        }
+
+        int readU2() {
+            int res = readU1();
+            return (res << 8) + readU1();
+        }
+
+        int readU4() {
+            int res = readU2();
+            return (res << 16) + readU2();
+        }
+
+        void writeU1(int val) {
+            gen[genPos++] = (byte)val;
+        }
+
+        void writeU2(int val) {
+            writeU1(val >> 8);
+            writeU1(val & 0xFF);
+        }
+
+        void writeU4(int val) {
+            writeU2(val >> 16);
+            writeU2(val & 0xFFFF);
+        }
+
+        void copy(int count) {
+            for (int i = 0; i < count; ++i) {
+                gen[genPos++] = orig[origPos++];
+            }
+        }
+
+        byte[] readBytes(int count) {
+            byte[] bytes = new byte[count];
+            for (int i = 0; i < count; ++i) {
+                bytes[i] = orig[origPos++];
+            }
+            return bytes;
+        }
+
+        void writeBytes(byte[] bytes) {
+            for (int i = 0; i < bytes.length; ++i) {
+                gen[genPos++] = bytes[i];
+            }
+        }
+
+        int copyConstantPool(int constantPoolCount)
+            throws UnsupportedEncodingException, IOException {
+            int sdeIndex = -1;
+            // copy const pool index zero not in class file
+            for (int i = 1; i < constantPoolCount; ++i) {
+                int tag = readU1();
+                writeU1(tag);
+                switch (tag) {
+                    case 7 : // Class
+                    case 8 : // String
+                        if (log.isDebugEnabled())
+                            log.debug(i + " copying 2 bytes");
+                        copy(2);
+                        break;
+                    case 9 : // Field
+                    case 10 : // Method
+                    case 11 : // InterfaceMethod
+                    case 3 : // Integer
+                    case 4 : // Float
+                    case 12 : // NameAndType
+                        if (log.isDebugEnabled())
+                            log.debug(i + " copying 4 bytes");
+                        copy(4);
+                        break;
+                    case 5 : // Long
+                    case 6 : // Double
+                        if (log.isDebugEnabled())
+                            log.debug(i + " copying 8 bytes");
+                        copy(8);
+                        i++;
+                        break;
+                    case 1 : // Utf8
+                        int len = readU2();
+                        writeU2(len);
+                        byte[] utf8 = readBytes(len);
+                        String str = new String(utf8, "UTF-8");
+                        if (log.isDebugEnabled())
+                            log.debug(i + " read class attr -- '" + str + "'");
+                        if (str.equals(nameSDE)) {
+                            sdeIndex = i;
+                        }
+                        writeBytes(utf8);
+                        break;
+                    default :
+                        throw new IOException("unexpected tag: " + tag);
+                }
+            }
+            return sdeIndex;
+        }
+
+        void writeUtf8ForSDE() {
+            int len = nameSDE.length();
+            writeU1(1); // Utf8 tag
+            writeU2(len);
+            for (int i = 0; i < len; ++i) {
+                writeU1(nameSDE.charAt(i));
+            }
+        }
+    }
+
+    public static void evaluateNodes(
+        Node.Nodes nodes,
+        SmapStratum s,
+        HashMap innerClassMap,
+        boolean breakAtLF) {
+        try {
+            nodes.visit(new SmapGenVisitor(s, breakAtLF, innerClassMap));
+        } catch (JasperException ex) {
+        }
+    }
+
+    static class SmapGenVisitor extends Node.Visitor {
+
+        private SmapStratum smap;
+        private boolean breakAtLF;
+        private HashMap innerClassMap;
+
+        SmapGenVisitor(SmapStratum s, boolean breakAtLF, HashMap map) {
+            this.smap = s;
+            this.breakAtLF = breakAtLF;
+            this.innerClassMap = map;
+        }
+
+        public void visitBody(Node n) throws JasperException {
+            SmapStratum smapSave = smap;
+            String innerClass = n.getInnerClassName();
+            if (innerClass != null) {
+                this.smap = (SmapStratum) innerClassMap.get(innerClass);
+            }
+            super.visitBody(n);
+            smap = smapSave;
+        }
+
+        public void visit(Node.Declaration n) throws JasperException {
+            doSmapText(n);
+        }
+
+        public void visit(Node.Expression n) throws JasperException {
+            doSmapText(n);
+        }
+
+        public void visit(Node.Scriptlet n) throws JasperException {
+            doSmapText(n);
+        }
+
+        public void visit(Node.IncludeAction n) throws JasperException {
+            doSmap(n);
+            visitBody(n);
+        }
+
+        public void visit(Node.ForwardAction n) throws JasperException {
+            doSmap(n);
+            visitBody(n);
+        }
+
+        public void visit(Node.GetProperty n) throws JasperException {
+            doSmap(n);
+            visitBody(n);
+        }
+
+        public void visit(Node.SetProperty n) throws JasperException {
+            doSmap(n);
+            visitBody(n);
+        }
+
+        public void visit(Node.UseBean n) throws JasperException {
+            doSmap(n);
+            visitBody(n);
+        }
+
+        public void visit(Node.PlugIn n) throws JasperException {
+            doSmap(n);
+            visitBody(n);
+        }
+
+        public void visit(Node.CustomTag n) throws JasperException {
+            doSmap(n);
+            visitBody(n);
+        }
+
+        public void visit(Node.UninterpretedTag n) throws JasperException {
+            doSmap(n);
+            visitBody(n);
+        }
+
+        public void visit(Node.JspElement n) throws JasperException {
+            doSmap(n);
+            visitBody(n);
+        }
+
+        public void visit(Node.JspText n) throws JasperException {
+            doSmap(n);
+            visitBody(n);
+        }
+
+        public void visit(Node.NamedAttribute n) throws JasperException {
+            visitBody(n);
+        }
+
+        public void visit(Node.JspBody n) throws JasperException {
+            doSmap(n);
+            visitBody(n);
+        }
+
+        public void visit(Node.InvokeAction n) throws JasperException {
+            doSmap(n);
+            visitBody(n);
+        }
+
+        public void visit(Node.DoBodyAction n) throws JasperException {
+            doSmap(n);
+            visitBody(n);
+        }
+
+        public void visit(Node.ELExpression n) throws JasperException {
+            doSmap(n);
+        }
+
+        public void visit(Node.TemplateText n) throws JasperException {
+            Mark mark = n.getStart();
+            if (mark == null) {
+                return;
+            }
+
+            //Add the file information
+            String fileName = mark.getFile();
+            smap.addFile(unqualify(fileName), fileName);
+
+            //Add a LineInfo that corresponds to the beginning of this node
+            int iInputStartLine = mark.getLineNumber();
+            int iOutputStartLine = n.getBeginJavaLine();
+            int iOutputLineIncrement = breakAtLF? 1: 0;
+            smap.addLineData(iInputStartLine, fileName, 1, iOutputStartLine, 
+                             iOutputLineIncrement);
+
+            // Output additional mappings in the text
+            java.util.ArrayList extraSmap = n.getExtraSmap();
+
+            if (extraSmap != null) {
+                for (int i = 0; i < extraSmap.size(); i++) {
+                    iOutputStartLine += iOutputLineIncrement;
+                    smap.addLineData(
+                        iInputStartLine+((Integer)extraSmap.get(i)).intValue(),
+                        fileName,
+                        1,
+                        iOutputStartLine,
+                        iOutputLineIncrement);
+                }
+            }
+        }
+
+        private void doSmap(
+            Node n,
+            int inLineCount,
+            int outIncrement,
+            int skippedLines) {
+            Mark mark = n.getStart();
+            if (mark == null) {
+                return;
+            }
+
+            String unqualifiedName = unqualify(mark.getFile());
+            smap.addFile(unqualifiedName, mark.getFile());
+            smap.addLineData(
+                mark.getLineNumber() + skippedLines,
+                mark.getFile(),
+                inLineCount - skippedLines,
+                n.getBeginJavaLine() + skippedLines,
+                outIncrement);
+        }
+
+        private void doSmap(Node n) {
+            doSmap(n, 1, n.getEndJavaLine() - n.getBeginJavaLine(), 0);
+        }
+
+        private void doSmapText(Node n) {
+            String text = n.getText();
+            int index = 0;
+            int next = 0;
+            int lineCount = 1;
+            int skippedLines = 0;
+            boolean slashStarSeen = false;
+            boolean beginning = true;
+
+            // Count lines inside text, but skipping comment lines at the
+            // beginning of the text.
+            while ((next = text.indexOf('\n', index)) > -1) {
+                if (beginning) {
+                    String line = text.substring(index, next).trim();
+                    if (!slashStarSeen && line.startsWith("/*")) {
+                        slashStarSeen = true;
+                    }
+                    if (slashStarSeen) {
+                        skippedLines++;
+                        int endIndex = line.indexOf("*/");
+                        if (endIndex >= 0) {
+                            // End of /* */ comment
+                            slashStarSeen = false;
+                            if (endIndex < line.length() - 2) {
+                                // Some executable code after comment
+                                skippedLines--;
+                                beginning = false;
+                            }
+                        }
+                    } else if (line.length() == 0 || line.startsWith("//")) {
+                        skippedLines++;
+                    } else {
+                        beginning = false;
+                    }
+                }
+                lineCount++;
+                index = next + 1;
+            }
+
+            doSmap(n, lineCount, 1, skippedLines);
+        }
+    }
+
+    private static class PreScanVisitor extends Node.Visitor {
+
+        HashMap map = new HashMap();
+
+        public void doVisit(Node n) {
+            String inner = n.getInnerClassName();
+            if (inner != null && !map.containsKey(inner)) {
+                map.put(inner, new SmapStratum("JSP"));
+            }
+        }
+
+        HashMap getMap() {
+            return map;
+        }
+    }
+    
+}

Added: branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/TagConstants.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/TagConstants.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/TagConstants.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,115 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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;
+
+public interface TagConstants {
+
+    public static final String JSP_URI = "http://java.sun.com/JSP/Page";
+
+    public static final String DIRECTIVE_ACTION = "directive.";
+
+    public static final String ROOT_ACTION = "root";
+    public static final String JSP_ROOT_ACTION = "jsp:root";
+
+    public static final String PAGE_DIRECTIVE_ACTION = "directive.page";
+    public static final String JSP_PAGE_DIRECTIVE_ACTION = "jsp:directive.page";
+
+    public static final String INCLUDE_DIRECTIVE_ACTION = "directive.include";
+    public static final String JSP_INCLUDE_DIRECTIVE_ACTION = "jsp:directive.include";
+
+    public static final String DECLARATION_ACTION = "declaration";
+    public static final String JSP_DECLARATION_ACTION = "jsp:declaration";
+
+    public static final String SCRIPTLET_ACTION = "scriptlet";
+    public static final String JSP_SCRIPTLET_ACTION = "jsp:scriptlet";
+
+    public static final String EXPRESSION_ACTION = "expression";
+    public static final String JSP_EXPRESSION_ACTION = "jsp:expression";
+
+    public static final String USE_BEAN_ACTION = "useBean";
+    public static final String JSP_USE_BEAN_ACTION = "jsp:useBean";
+
+    public static final String SET_PROPERTY_ACTION = "setProperty";
+    public static final String JSP_SET_PROPERTY_ACTION = "jsp:setProperty";
+
+    public static final String GET_PROPERTY_ACTION = "getProperty";
+    public static final String JSP_GET_PROPERTY_ACTION = "jsp:getProperty";
+
+    public static final String INCLUDE_ACTION = "include";
+    public static final String JSP_INCLUDE_ACTION = "jsp:include";
+
+    public static final String FORWARD_ACTION = "forward";
+    public static final String JSP_FORWARD_ACTION = "jsp:forward";
+
+    public static final String PARAM_ACTION = "param";
+    public static final String JSP_PARAM_ACTION = "jsp:param";
+
+    public static final String PARAMS_ACTION = "params";
+    public static final String JSP_PARAMS_ACTION = "jsp:params";
+
+    public static final String PLUGIN_ACTION = "plugin";
+    public static final String JSP_PLUGIN_ACTION = "jsp:plugin";
+
+    public static final String FALLBACK_ACTION = "fallback";
+    public static final String JSP_FALLBACK_ACTION = "jsp:fallback";
+
+    public static final String TEXT_ACTION = "text";
+    public static final String JSP_TEXT_ACTION = "jsp:text";
+    public static final String JSP_TEXT_ACTION_END = "</jsp:text>";
+
+    public static final String ATTRIBUTE_ACTION = "attribute";
+    public static final String JSP_ATTRIBUTE_ACTION = "jsp:attribute";
+
+    public static final String BODY_ACTION = "body";
+    public static final String JSP_BODY_ACTION = "jsp:body";
+
+    public static final String ELEMENT_ACTION = "element";
+    public static final String JSP_ELEMENT_ACTION = "jsp:element";
+
+    public static final String OUTPUT_ACTION = "output";
+    public static final String JSP_OUTPUT_ACTION = "jsp:output";
+
+    public static final String TAGLIB_DIRECTIVE_ACTION = "taglib";
+    public static final String JSP_TAGLIB_DIRECTIVE_ACTION = "jsp:taglib";
+
+    /*
+     * Tag Files
+     */
+    public static final String INVOKE_ACTION = "invoke";
+    public static final String JSP_INVOKE_ACTION = "jsp:invoke";
+
+    public static final String DOBODY_ACTION = "doBody";
+    public static final String JSP_DOBODY_ACTION = "jsp:doBody";
+
+    /*
+     * Tag File Directives
+     */
+    public static final String TAG_DIRECTIVE_ACTION = "directive.tag";
+    public static final String JSP_TAG_DIRECTIVE_ACTION = "jsp:directive.tag";
+
+    public static final String ATTRIBUTE_DIRECTIVE_ACTION = "directive.attribute";
+    public static final String JSP_ATTRIBUTE_DIRECTIVE_ACTION = "jsp:directive.attribute";
+
+    public static final String VARIABLE_DIRECTIVE_ACTION = "directive.variable";
+    public static final String JSP_VARIABLE_DIRECTIVE_ACTION = "jsp:directive.variable";
+
+    /*
+     * Directive attributes
+     */
+    public static final String URN_JSPTAGDIR = "urn:jsptagdir:";
+    public static final String URN_JSPTLD = "urn:jsptld:";
+}

Added: branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/TagFileProcessor.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/TagFileProcessor.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/TagFileProcessor.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,608 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.FileNotFoundException;
+import java.io.IOException;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Vector;
+import java.util.HashMap;
+
+import javax.servlet.jsp.tagext.TagAttributeInfo;
+import javax.servlet.jsp.tagext.TagExtraInfo;
+import javax.servlet.jsp.tagext.TagFileInfo;
+import javax.servlet.jsp.tagext.TagInfo;
+import javax.servlet.jsp.tagext.TagLibraryInfo;
+import javax.servlet.jsp.tagext.TagVariableInfo;
+import javax.servlet.jsp.tagext.VariableInfo;
+
+import org.apache.jasper.JasperException;
+import org.apache.jasper.JspCompilationContext;
+import org.apache.jasper.servlet.JspServletWrapper;
+import org.apache.jasper.runtime.JspSourceDependent;
+
+/**
+ * 1. Processes and extracts the directive info in a tag file.
+ * 2. Compiles and loads tag files used in a JSP file.
+ *
+ * @author Kin-man Chung
+ */
+
+class TagFileProcessor {
+
+    private Vector tempVector;
+
+    /**
+     * A visitor the tag file
+     */
+    private static class TagFileDirectiveVisitor extends Node.Visitor {
+
+        private static final JspUtil.ValidAttribute[] tagDirectiveAttrs = {
+            new JspUtil.ValidAttribute("display-name"),
+            new JspUtil.ValidAttribute("body-content"),
+            new JspUtil.ValidAttribute("dynamic-attributes"),
+            new JspUtil.ValidAttribute("small-icon"),
+            new JspUtil.ValidAttribute("large-icon"),
+            new JspUtil.ValidAttribute("description"),
+            new JspUtil.ValidAttribute("example"),
+            new JspUtil.ValidAttribute("pageEncoding"),
+            new JspUtil.ValidAttribute("language"),
+            new JspUtil.ValidAttribute("import"),
+            new JspUtil.ValidAttribute("isELIgnored") };
+
+        private static final JspUtil.ValidAttribute[] attributeDirectiveAttrs = {
+            new JspUtil.ValidAttribute("name", true),
+            new JspUtil.ValidAttribute("required"),
+            new JspUtil.ValidAttribute("fragment"),
+            new JspUtil.ValidAttribute("rtexprvalue"),
+            new JspUtil.ValidAttribute("type"),
+            new JspUtil.ValidAttribute("description")
+        };
+
+        private static final JspUtil.ValidAttribute[] variableDirectiveAttrs = {
+            new JspUtil.ValidAttribute("name-given"),
+            new JspUtil.ValidAttribute("name-from-attribute"),
+            new JspUtil.ValidAttribute("alias"),
+            new JspUtil.ValidAttribute("variable-class"),
+            new JspUtil.ValidAttribute("scope"),
+            new JspUtil.ValidAttribute("declare"),
+            new JspUtil.ValidAttribute("description")
+        };
+
+        private ErrorDispatcher err;
+        private TagLibraryInfo tagLibInfo;
+
+        private String name = null;
+        private String path = null;
+        private TagExtraInfo tei = null;
+        private String bodycontent = null;
+        private String description = null;
+        private String displayName = null;
+        private String smallIcon = null;
+        private String largeIcon = null;
+        private String dynamicAttrsMapName;
+        private String example = null;
+        
+        private Vector attributeVector;
+        private Vector variableVector;
+
+        private static final String ATTR_NAME =
+            "the name attribute of the attribute directive";
+        private static final String VAR_NAME_GIVEN =
+            "the name-given attribute of the variable directive";
+        private static final String VAR_NAME_FROM =
+            "the name-from-attribute attribute of the variable directive";
+        private static final String VAR_ALIAS =
+            "the alias attribute of the variable directive";
+        private static final String TAG_DYNAMIC =
+            "the dynamic-attributes attribute of the tag directive";
+        private HashMap nameTable = new HashMap();
+        private HashMap nameFromTable = new HashMap();
+
+        public TagFileDirectiveVisitor(Compiler compiler,
+                                       TagLibraryInfo tagLibInfo,
+                                       String name,
+                                       String path) {
+            err = compiler.getErrorDispatcher();
+            this.tagLibInfo = tagLibInfo;
+            this.name = name;
+            this.path = path;
+            attributeVector = new Vector();
+            variableVector = new Vector();
+        }
+
+        public void visit(Node.TagDirective n) throws JasperException {
+
+            JspUtil.checkAttributes("Tag directive", n, tagDirectiveAttrs,
+                                    err);
+
+            bodycontent = checkConflict(n, bodycontent, "body-content");
+            if (bodycontent != null &&
+                    !bodycontent.equalsIgnoreCase(TagInfo.BODY_CONTENT_EMPTY) &&
+                    !bodycontent.equalsIgnoreCase(TagInfo.BODY_CONTENT_TAG_DEPENDENT) &&
+                    !bodycontent.equalsIgnoreCase(TagInfo.BODY_CONTENT_SCRIPTLESS)) {
+                err.jspError(n, "jsp.error.tagdirective.badbodycontent",
+                             bodycontent);
+            }
+            dynamicAttrsMapName = checkConflict(n, dynamicAttrsMapName,
+                                                "dynamic-attributes");
+            if (dynamicAttrsMapName != null) {
+                checkUniqueName(dynamicAttrsMapName, TAG_DYNAMIC, n);
+            }
+            smallIcon = checkConflict(n, smallIcon, "small-icon");
+            largeIcon = checkConflict(n, largeIcon, "large-icon");
+            description = checkConflict(n, description, "description");
+            displayName = checkConflict(n, displayName, "display-name");
+            example = checkConflict(n, example, "example");
+        }
+
+        private String checkConflict(Node n, String oldAttrValue, String attr)
+                throws JasperException {
+
+            String result = oldAttrValue;
+            String attrValue = n.getAttributeValue(attr);
+            if (attrValue != null) {
+                if (oldAttrValue != null && !oldAttrValue.equals(attrValue)) {
+                    err.jspError(n, "jsp.error.tag.conflict.attr", attr,
+                                 oldAttrValue, attrValue);
+                }
+                result = attrValue;
+            }
+            return result;
+        }
+            
+
+        public void visit(Node.AttributeDirective n) throws JasperException {
+
+            JspUtil.checkAttributes("Attribute directive", n,
+                                    attributeDirectiveAttrs, err);
+
+            String attrName = n.getAttributeValue("name");
+            boolean required = JspUtil.booleanValue(
+                                        n.getAttributeValue("required"));
+            boolean rtexprvalue = true;
+            String rtexprvalueString = n.getAttributeValue("rtexprvalue");
+            if (rtexprvalueString != null) {
+                rtexprvalue = JspUtil.booleanValue( rtexprvalueString );
+            }
+            boolean fragment = JspUtil.booleanValue(
+                                        n.getAttributeValue("fragment"));
+            String type = n.getAttributeValue("type");
+            if (fragment) {
+                // type is fixed to "JspFragment" and a translation error
+                // must occur if specified.
+                if (type != null) {
+                    err.jspError(n, "jsp.error.fragmentwithtype");
+                }
+                // rtexprvalue is fixed to "true" and a translation error
+                // must occur if specified.
+                rtexprvalue = true;
+                if( rtexprvalueString != null ) {
+                    err.jspError(n, "jsp.error.frgmentwithrtexprvalue" );
+                }
+            } else {
+                if (type == null)
+                    type = "java.lang.String";
+            }
+
+            TagAttributeInfo tagAttributeInfo =
+                    new TagAttributeInfo(attrName, required, type, rtexprvalue,
+                                         fragment);
+            attributeVector.addElement(tagAttributeInfo);
+            checkUniqueName(attrName, ATTR_NAME, n, tagAttributeInfo);
+        }
+
+        public void visit(Node.VariableDirective n) throws JasperException {
+
+            JspUtil.checkAttributes("Variable directive", n,
+                                    variableDirectiveAttrs, err);
+
+            String nameGiven = n.getAttributeValue("name-given");
+            String nameFromAttribute = n.getAttributeValue("name-from-attribute");
+            if (nameGiven == null && nameFromAttribute == null) {
+                err.jspError("jsp.error.variable.either.name");
+            }
+
+            if (nameGiven != null && nameFromAttribute != null) {
+                err.jspError("jsp.error.variable.both.name");
+            }
+
+            String alias = n.getAttributeValue("alias");
+            if (nameFromAttribute != null && alias == null ||
+                nameFromAttribute == null && alias != null) {
+                err.jspError("jsp.error.variable.alias");
+            }
+
+            String className = n.getAttributeValue("variable-class");
+            if (className == null)
+                className = "java.lang.String";
+
+            String declareStr = n.getAttributeValue("declare");
+            boolean declare = true;
+            if (declareStr != null)
+                declare = JspUtil.booleanValue(declareStr);
+
+            int scope = VariableInfo.NESTED;
+            String scopeStr = n.getAttributeValue("scope");
+            if (scopeStr != null) {
+                if ("NESTED".equals(scopeStr)) {
+                    // Already the default
+                } else if ("AT_BEGIN".equals(scopeStr)) {
+                    scope = VariableInfo.AT_BEGIN;
+                } else if ("AT_END".equals(scopeStr)) {
+                    scope = VariableInfo.AT_END;
+                }
+            }
+
+            if (nameFromAttribute != null) {
+                /*
+		 * An alias has been specified. We use 'nameGiven' to hold the
+		 * value of the alias, and 'nameFromAttribute' to hold the 
+		 * name of the attribute whose value (at invocation-time)
+		 * denotes the name of the variable that is being aliased
+		 */
+                nameGiven = alias;
+                checkUniqueName(nameFromAttribute, VAR_NAME_FROM, n);
+                checkUniqueName(alias, VAR_ALIAS, n);
+            }
+            else {
+                // name-given specified
+                checkUniqueName(nameGiven, VAR_NAME_GIVEN, n);
+            }
+                
+            variableVector.addElement(new TagVariableInfo(
+                                                nameGiven,
+                                                nameFromAttribute,
+                                                className,
+                                                declare,
+                                                scope));
+        }
+
+        /*
+         * Returns the vector of attributes corresponding to attribute
+         * directives.
+         */
+        public Vector getAttributesVector() {
+            return attributeVector;
+        }
+
+        /*
+         * Returns the vector of variables corresponding to variable
+         * directives.
+         */        
+        public Vector getVariablesVector() {
+            return variableVector;
+        }
+
+	/*
+	 * Returns the value of the dynamic-attributes tag directive
+	 * attribute.
+	 */
+	public String getDynamicAttributesMapName() {
+	    return dynamicAttrsMapName;
+	}
+
+        public TagInfo getTagInfo() throws JasperException {
+
+            if (name == null) {
+                // XXX Get it from tag file name
+            }
+
+            if (bodycontent == null) {
+                bodycontent = TagInfo.BODY_CONTENT_SCRIPTLESS;
+            }
+
+            String tagClassName = JspUtil.getTagHandlerClassName(path, err);
+
+            TagVariableInfo[] tagVariableInfos
+                = new TagVariableInfo[variableVector.size()];
+            variableVector.copyInto(tagVariableInfos);
+
+            TagAttributeInfo[] tagAttributeInfo
+                = new TagAttributeInfo[attributeVector.size()];
+            attributeVector.copyInto(tagAttributeInfo);
+
+            return new JasperTagInfo(name,
+			       tagClassName,
+			       bodycontent,
+			       description,
+			       tagLibInfo,
+			       tei,
+			       tagAttributeInfo,
+			       displayName,
+			       smallIcon,
+			       largeIcon,
+			       tagVariableInfos,
+			       dynamicAttrsMapName);
+        }
+
+        static class NameEntry {
+            private String type;
+            private Node node;
+            private TagAttributeInfo attr;
+
+            NameEntry(String type, Node node, TagAttributeInfo attr) {
+                this.type = type;
+                this.node = node;
+                this.attr = attr;
+            }
+
+            String getType() { return type;}
+            Node getNode() { return node; }
+            TagAttributeInfo getTagAttributeInfo() { return attr; }
+        }
+
+        /**
+         * Reports a translation error if names specified in attributes of
+         * directives are not unique in this translation unit.
+         *
+         * The value of the following attributes must be unique.
+         *   1. 'name' attribute of an attribute directive
+         *   2. 'name-given' attribute of a variable directive
+         *   3. 'alias' attribute of variable directive
+         *   4. 'dynamic-attributes' of a tag directive
+         * except that 'dynamic-attributes' can (and must) have the same
+         * value when it appears in multiple tag directives.
+         *
+         * Also, 'name-from' attribute of a variable directive cannot have
+         * the same value as that from another variable directive.
+         */
+        private void checkUniqueName(String name, String type, Node n)
+                throws JasperException {
+            checkUniqueName(name, type, n, null);
+        }
+
+        private void checkUniqueName(String name, String type, Node n,
+                                     TagAttributeInfo attr)
+                throws JasperException {
+
+            HashMap table = (type == VAR_NAME_FROM)? nameFromTable: nameTable;
+            NameEntry nameEntry = (NameEntry) table.get(name);
+            if (nameEntry != null) {
+                if (type != TAG_DYNAMIC || nameEntry.getType() != TAG_DYNAMIC) {
+                    int line = nameEntry.getNode().getStart().getLineNumber();
+                    err.jspError(n, "jsp.error.tagfile.nameNotUnique",
+                         type, nameEntry.getType(), Integer.toString(line));
+                }
+            } else {
+                table.put(name, new NameEntry(type, n, attr));
+            }
+        }
+
+        /**
+         * Perform miscellean checks after the nodes are visited.
+         */
+        void postCheck() throws JasperException {
+            // Check that var.name-from-attributes has valid values.
+	    Iterator iter = nameFromTable.keySet().iterator();
+            while (iter.hasNext()) {
+                String nameFrom = (String) iter.next();
+                NameEntry nameEntry = (NameEntry) nameTable.get(nameFrom);
+                NameEntry nameFromEntry =
+                    (NameEntry) nameFromTable.get(nameFrom);
+                Node nameFromNode = nameFromEntry.getNode();
+                if (nameEntry == null) {
+                    err.jspError(nameFromNode,
+                                 "jsp.error.tagfile.nameFrom.noAttribute",
+                                 nameFrom);
+                } else {
+                    Node node = nameEntry.getNode();
+                    TagAttributeInfo tagAttr = nameEntry.getTagAttributeInfo();
+                    if (! "java.lang.String".equals(tagAttr.getTypeName())
+                            || ! tagAttr.isRequired()
+                            || tagAttr.canBeRequestTime()){
+                        err.jspError(nameFromNode,
+                            "jsp.error.tagfile.nameFrom.badAttribute",
+                            nameFrom,
+                            Integer.toString(node.getStart().getLineNumber()));
+                     }
+                }
+            }
+        }
+    }
+
+    /**
+     * Parses the tag file, and collects information on the directives included
+     * in it.  The method is used to obtain the info on the tag file, when the 
+     * handler that it represents is referenced.  The tag file is not compiled
+     * here.
+     *
+     * @param pc the current ParserController used in this compilation
+     * @param name the tag name as specified in the TLD
+     * @param tagfile the path for the tagfile
+     * @param tagLibInfo the TagLibraryInfo object associated with this TagInfo
+     * @return a TagInfo object assembled from the directives in the tag file.
+     */
+    public static TagInfo parseTagFileDirectives(ParserController pc,
+						 String name,
+						 String path,
+						 TagLibraryInfo tagLibInfo)
+                        throws JasperException {
+
+        ErrorDispatcher err = pc.getCompiler().getErrorDispatcher();
+
+        Node.Nodes page = null;
+        try {
+            page = pc.parseTagFileDirectives(path);
+        } catch (FileNotFoundException e) {
+            err.jspError("jsp.error.file.not.found", path);
+        } catch (IOException e) {
+            err.jspError("jsp.error.file.not.found", path);
+        }
+
+        TagFileDirectiveVisitor tagFileVisitor
+            = new TagFileDirectiveVisitor(pc.getCompiler(), tagLibInfo, name,
+                                          path);
+        page.visit(tagFileVisitor);
+        tagFileVisitor.postCheck();
+
+        return tagFileVisitor.getTagInfo();
+    }
+
+    /**
+     * Compiles and loads a tagfile.
+     */
+    private Class loadTagFile(Compiler compiler,
+                              String tagFilePath, TagInfo tagInfo,
+                              PageInfo parentPageInfo)
+        throws JasperException {
+
+        JspCompilationContext ctxt = compiler.getCompilationContext();
+        JspRuntimeContext rctxt = ctxt.getRuntimeContext();
+        JspServletWrapper wrapper =
+                (JspServletWrapper) rctxt.getWrapper(tagFilePath);
+
+        synchronized(rctxt) {
+            if (wrapper == null) {
+                wrapper = new JspServletWrapper(ctxt.getServletContext(),
+                                                ctxt.getOptions(),
+                                                tagFilePath,
+                                                tagInfo,
+                                                ctxt.getRuntimeContext(),
+                                                (URL) ctxt.getTagFileJarUrls().get(tagFilePath));
+                    rctxt.addWrapper(tagFilePath,wrapper);
+
+		// Use same classloader and classpath for compiling tag files
+		wrapper.getJspEngineContext().setClassLoader(
+				(URLClassLoader) ctxt.getClassLoader());
+		wrapper.getJspEngineContext().setClassPath(ctxt.getClassPath());
+            }
+            else {
+                // Make sure that JspCompilationContext gets the latest TagInfo
+                // for the tag file.  TagInfo instance was created the last
+                // time the tag file was scanned for directives, and the tag
+                // file may have been modified since then.
+                wrapper.getJspEngineContext().setTagInfo(tagInfo);
+            }
+
+            Class tagClazz;
+            int tripCount = wrapper.incTripCount();
+            try {
+                if (tripCount > 0) {
+                    // When tripCount is greater than zero, a circular
+                    // dependency exists.  The circularily dependant tag
+                    // file is compiled in prototype mode, to avoid infinite
+                    // recursion.
+
+                    JspServletWrapper tempWrapper
+                        = new JspServletWrapper(ctxt.getServletContext(),
+                                                ctxt.getOptions(),
+                                                tagFilePath,
+                                                tagInfo,
+                                                ctxt.getRuntimeContext(),
+                                                (URL) ctxt.getTagFileJarUrls().get(tagFilePath));
+                    tagClazz = tempWrapper.loadTagFilePrototype();
+                    tempVector.add(
+                               tempWrapper.getJspEngineContext().getCompiler());
+                } else {
+                    tagClazz = wrapper.loadTagFile();
+                }
+            } finally {
+                wrapper.decTripCount();
+            }
+        
+            // Add the dependants for this tag file to its parent's
+            // dependant list.  The only reliable dependency information
+            // can only be obtained from the tag instance.
+            try {
+                Object tagIns = tagClazz.newInstance();
+                if (tagIns instanceof JspSourceDependent) {
+                    Iterator iter = 
+                        ((List) ((JspSourceDependent) tagIns).getDependants()).iterator();
+                    while (iter.hasNext()) {
+                        parentPageInfo.addDependant((String)iter.next());
+                    }
+                }
+            } catch (Exception e) {
+                // ignore errors
+            }
+        
+            return tagClazz;
+        }
+    }
+
+
+    /*
+     * Visitor which scans the page and looks for tag handlers that are tag
+     * files, compiling (if necessary) and loading them.
+     */ 
+    private class TagFileLoaderVisitor extends Node.Visitor {
+
+        private Compiler compiler;
+        private PageInfo pageInfo;
+
+        TagFileLoaderVisitor(Compiler compiler) {
+            
+            this.compiler = compiler;
+            this.pageInfo = compiler.getPageInfo();
+        }
+
+        public void visit(Node.CustomTag n) throws JasperException {
+            TagFileInfo tagFileInfo = n.getTagFileInfo();
+            if (tagFileInfo != null) {
+                String tagFilePath = tagFileInfo.getPath();
+		JspCompilationContext ctxt = compiler.getCompilationContext();
+		if (ctxt.getTagFileJarUrls().get(tagFilePath) == null) {
+		    // Omit tag file dependency info on jar files for now.
+                    pageInfo.addDependant(tagFilePath);
+		}
+                Class c = loadTagFile(compiler, tagFilePath, n.getTagInfo(),
+                                      pageInfo);
+                n.setTagHandlerClass(c);
+            }
+            visitBody(n);
+        }
+    }
+
+    /**
+     * Implements a phase of the translation that compiles (if necessary)
+     * the tag files used in a JSP files.  The directives in the tag files
+     * are assumed to have been proccessed and encapsulated as TagFileInfo
+     * in the CustomTag nodes.
+     */
+    public void loadTagFiles(Compiler compiler, Node.Nodes page)
+                throws JasperException {
+
+        tempVector = new Vector();
+        page.visit(new TagFileLoaderVisitor(compiler));
+    }
+
+    /**
+     * Removed the java and class files for the tag prototype 
+     * generated from the current compilation.
+     * @param classFileName If non-null, remove only the class file with
+     *        with this name.
+     */
+    public void removeProtoTypeFiles(String classFileName) {
+        Iterator iter = tempVector.iterator();
+        while (iter.hasNext()) {
+            Compiler c = (Compiler) iter.next();
+            if (classFileName == null) {
+                c.removeGeneratedClassFiles();
+            } else if (classFileName.equals(
+                        c.getCompilationContext().getClassFileName())) {
+                c.removeGeneratedClassFiles();
+                tempVector.remove(c);
+                return;
+            }
+        }
+    }
+}
+

Added: branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/TagLibraryInfoImpl.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/TagLibraryInfoImpl.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/TagLibraryInfoImpl.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,758 @@
+/*
+ * Copyright 1999,2004-2006 The Apache Software Foundation.
+ * 
+ * Licensed 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.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.InputStream;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.net.JarURLConnection;
+import java.net.URL;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Vector;
+import java.util.jar.JarFile;
+import java.util.zip.ZipEntry;
+
+import javax.servlet.jsp.tagext.FunctionInfo;
+import javax.servlet.jsp.tagext.PageData;
+import javax.servlet.jsp.tagext.TagAttributeInfo;
+import javax.servlet.jsp.tagext.TagExtraInfo;
+import javax.servlet.jsp.tagext.TagFileInfo;
+import javax.servlet.jsp.tagext.TagInfo;
+import javax.servlet.jsp.tagext.TagLibraryInfo;
+import javax.servlet.jsp.tagext.TagLibraryValidator;
+import javax.servlet.jsp.tagext.TagVariableInfo;
+import javax.servlet.jsp.tagext.ValidationMessage;
+import javax.servlet.jsp.tagext.VariableInfo;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.jasper.JasperException;
+import org.apache.jasper.JspCompilationContext;
+import org.apache.jasper.xmlparser.ParserUtils;
+import org.apache.jasper.xmlparser.TreeNode;
+
+/**
+ * Implementation of the TagLibraryInfo class from the JSP spec. 
+ *
+ * @author Anil K. Vijendran
+ * @author Mandar Raje
+ * @author Pierre Delisle
+ * @author Kin-man Chung
+ * @author Jan Luehe
+ */
+class TagLibraryInfoImpl extends TagLibraryInfo implements TagConstants {
+
+    // Logger
+    private Log log = LogFactory.getLog(TagLibraryInfoImpl.class);
+
+    private Hashtable jarEntries;
+    private JspCompilationContext ctxt;
+    private ErrorDispatcher err;
+    private ParserController parserController;
+
+    private final void print(String name, String value, PrintWriter w) {
+        if (value != null) {
+            w.print(name+" = {\n\t");
+            w.print(value);
+            w.print("\n}\n");
+        }
+    }
+
+    public String toString() {
+        StringWriter sw = new StringWriter();
+        PrintWriter out = new PrintWriter(sw);
+        print("tlibversion", tlibversion, out);
+        print("jspversion", jspversion, out);
+        print("shortname", shortname, out);
+        print("urn", urn, out);
+        print("info", info, out);
+        print("uri", uri, out);
+        print("tagLibraryValidator", "" + tagLibraryValidator, out);
+
+        for(int i = 0; i < tags.length; i++)
+            out.println(tags[i].toString());
+        
+        for(int i = 0; i < tagFiles.length; i++)
+            out.println(tagFiles[i].toString());
+        
+        for(int i = 0; i < functions.length; i++)
+            out.println(functions[i].toString());
+        
+        return sw.toString();
+    }
+    
+    // XXX FIXME
+    // resolveRelativeUri and/or getResourceAsStream don't seem to properly
+    // handle relative paths when dealing when home and getDocBase are set
+    // the following is a workaround until these problems are resolved.
+    private InputStream getResourceAsStream(String uri) 
+        throws FileNotFoundException 
+    {
+        try {
+            // see if file exists on the filesystem first
+            String real = ctxt.getRealPath(uri);
+            if (real == null) {
+                return ctxt.getResourceAsStream(uri);
+            } else {
+                return new FileInputStream(real);
+            }
+        }
+        catch (FileNotFoundException ex) {
+            // if file not found on filesystem, get the resource through
+            // the context
+            return ctxt.getResourceAsStream(uri);
+        }
+       
+    }
+
+    /**
+     * Constructor.
+     */
+    public TagLibraryInfoImpl(JspCompilationContext ctxt,
+                              ParserController pc,
+                              String prefix, 
+                              String uriIn,
+                              String[] location,
+                              ErrorDispatcher err) throws JasperException {
+        super(prefix, uriIn);
+
+        this.ctxt = ctxt;
+        this.parserController = pc;
+        this.err = err;
+        InputStream in = null;
+        JarFile jarFile = null;
+
+        if (location == null) {
+            // The URI points to the TLD itself or to a JAR file in which the
+            // TLD is stored
+            location = generateTLDLocation(uri, ctxt);
+        }
+
+        try {
+            if (!location[0].endsWith("jar")) {
+                // Location points to TLD file
+                try {
+                    in = getResourceAsStream(location[0]);
+                    if (in == null) {
+                        throw new FileNotFoundException(location[0]);
+                    }
+                } catch (FileNotFoundException ex) {
+                    err.jspError("jsp.error.file.not.found", location[0]);
+                }
+
+                parseTLD(ctxt, location[0], in, null);
+                // Add TLD to dependency list
+                PageInfo pageInfo = ctxt.createCompiler().getPageInfo();
+                if (pageInfo != null) {
+                    pageInfo.addDependant(location[0]);
+                }
+            } else {
+                // Tag library is packaged in JAR file
+                try {
+                    URL jarFileUrl = new URL("jar:" + location[0] + "!/");
+                    JarURLConnection conn =
+                        (JarURLConnection) jarFileUrl.openConnection();
+                    conn.setUseCaches(false);
+                    conn.connect();
+                    jarFile = conn.getJarFile();
+                    ZipEntry jarEntry = jarFile.getEntry(location[1]);
+                    in = jarFile.getInputStream(jarEntry);
+                    parseTLD(ctxt, location[0], in, jarFileUrl);
+                } catch (Exception ex) {
+                    err.jspError("jsp.error.tld.unable_to_read", location[0],
+                                 location[1], ex.toString());
+                }
+            }
+        } finally {
+            if (in != null) {
+                try {
+                    in.close();
+                } catch (Throwable t) {}
+            }
+            if (jarFile != null) {
+                try {
+                    jarFile.close();
+                } catch (Throwable t) {}
+            }
+        }
+
+    }
+    
+    /*
+     * @param ctxt The JSP compilation context
+     * @param uri The TLD's uri
+     * @param in The TLD's input stream
+     * @param jarFileUrl The JAR file containing the TLD, or null if the tag
+     * library is not packaged in a JAR
+     */
+    private void parseTLD(JspCompilationContext ctxt,
+                          String uri, InputStream in, URL jarFileUrl) 
+        throws JasperException
+    {
+        Vector tagVector = new Vector();
+        Vector tagFileVector = new Vector();
+        Hashtable functionTable = new Hashtable();
+
+        // Create an iterator over the child elements of our <taglib> element
+        ParserUtils pu = new ParserUtils();
+        TreeNode tld = pu.parseXMLDocument(uri, in);
+
+        // Check to see if the <taglib> root element contains a 'version'
+        // attribute, which was added in JSP 2.0 to replace the <jsp-version>
+        // subelement
+        this.jspversion = tld.findAttribute("version");
+
+        // Process each child element of our <taglib> element
+        Iterator list = tld.findChildren();
+
+        while (list.hasNext()) {
+            TreeNode element = (TreeNode) list.next();
+            String tname = element.getName();
+
+            if ("tlibversion".equals(tname)                    // JSP 1.1
+                        || "tlib-version".equals(tname)) {     // JSP 1.2
+                this.tlibversion = element.getBody();
+            } else if ("jspversion".equals(tname)
+                        || "jsp-version".equals(tname)) {
+                this.jspversion = element.getBody();
+            } else if ("shortname".equals(tname) ||
+                     "short-name".equals(tname))
+                this.shortname = element.getBody();
+            else if ("uri".equals(tname))
+                this.urn = element.getBody();
+            else if ("info".equals(tname) ||
+                     "description".equals(tname))
+                this.info = element.getBody();
+            else if ("validator".equals(tname))
+                this.tagLibraryValidator = createValidator(element);
+            else if ("tag".equals(tname))
+                tagVector.addElement(createTagInfo(element, jspversion));
+            else if ("tag-file".equals(tname)) {
+                TagFileInfo tagFileInfo = createTagFileInfo(element, uri,
+                                                            jarFileUrl);
+                tagFileVector.addElement(tagFileInfo);
+            } else if ("function".equals(tname)) {         // JSP2.0
+                FunctionInfo funcInfo = createFunctionInfo(element);
+                String funcName = funcInfo.getName();
+                if (functionTable.containsKey(funcName)) {
+                    err.jspError("jsp.error.tld.fn.duplicate.name",
+                                 funcName, uri);
+
+                }
+                functionTable.put(funcName, funcInfo);
+            } else if ("display-name".equals(tname) ||    // Ignored elements
+                     "small-icon".equals(tname) ||
+                     "large-icon".equals(tname) ||
+                     "listener".equals(tname)) {
+                ;
+            } else if ("taglib-extension".equals(tname)) {
+                // Recognized but ignored
+            } else {
+                if (log.isWarnEnabled()) {
+                    log.warn(Localizer.getMessage(
+                            "jsp.warning.unknown.element.in.taglib", tname));
+                }
+            }
+
+        }
+
+        if (tlibversion == null) {
+            err.jspError("jsp.error.tld.mandatory.element.missing", 
+                         "tlib-version");
+        }
+        if (jspversion == null) {
+            err.jspError("jsp.error.tld.mandatory.element.missing",
+                         "jsp-version");
+        }
+
+        this.tags = new TagInfo[tagVector.size()];
+        tagVector.copyInto (this.tags);
+
+        this.tagFiles = new TagFileInfo[tagFileVector.size()];
+        tagFileVector.copyInto (this.tagFiles);
+
+        this.functions = new FunctionInfo[functionTable.size()];
+        int i=0;
+        Enumeration enumeration = functionTable.elements();
+        while (enumeration.hasMoreElements()) {
+            this.functions[i++] = (FunctionInfo) enumeration.nextElement();
+        }
+    }
+    
+    /*
+     * @param uri The uri of the TLD
+     * @param ctxt The compilation context
+     *
+     * @return String array whose first element denotes the path to the TLD.
+     * If the path to the TLD points to a jar file, then the second element
+     * denotes the name of the TLD entry in the jar file, which is hardcoded
+     * to META-INF/taglib.tld.
+     */
+    private String[] generateTLDLocation(String uri,
+                                         JspCompilationContext ctxt)
+                throws JasperException {
+
+        int uriType = TldLocationsCache.uriType(uri);
+        if (uriType == TldLocationsCache.ABS_URI) {
+            err.jspError("jsp.error.taglibDirective.absUriCannotBeResolved",
+                         uri);
+        } else if (uriType == TldLocationsCache.NOROOT_REL_URI) {
+            uri = ctxt.resolveRelativeUri(uri);
+        }
+
+        String[] location = new String[2];
+        location[0] = uri;
+        if (location[0].endsWith("jar")) {
+            URL url = null;
+            try {
+                url = ctxt.getResource(location[0]);
+            } catch (Exception ex) {
+                err.jspError("jsp.error.tld.unable_to_get_jar", location[0],
+                             ex.toString());
+            }
+            if (url == null) {
+                err.jspError("jsp.error.tld.missing_jar", location[0]);
+            }
+            location[0] = url.toString();
+            location[1] = "META-INF/taglib.tld";
+        }
+
+        return location;
+    }
+
+    private TagInfo createTagInfo(TreeNode elem, String jspVersion)
+            throws JasperException {
+
+        String tagName = null;
+        String tagClassName = null;
+        String teiClassName = null;
+
+        /*
+         * Default body content for JSP 1.2 tag handlers (<body-content> has
+         * become mandatory in JSP 2.0, because the default would be invalid
+         * for simple tag handlers)
+         */
+        String bodycontent = "JSP";
+
+        String info = null;
+        String displayName = null;
+        String smallIcon = null;
+        String largeIcon = null;
+        boolean dynamicAttributes = false;
+        
+        Vector attributeVector = new Vector();
+        Vector variableVector = new Vector();
+        Iterator list = elem.findChildren();
+        while (list.hasNext()) {
+            TreeNode element = (TreeNode) list.next();
+            String tname = element.getName();
+
+            if ("name".equals(tname)) {
+                tagName = element.getBody();
+            } else if ("tagclass".equals(tname) ||
+                     "tag-class".equals(tname)) {
+                tagClassName = element.getBody();
+            } else if ("teiclass".equals(tname) ||
+                     "tei-class".equals(tname)) {
+                teiClassName = element.getBody();
+            } else if ("bodycontent".equals(tname) ||
+                     "body-content".equals(tname)) {
+                bodycontent = element.getBody();
+            } else if ("display-name".equals(tname)) {
+                displayName = element.getBody();
+            } else if ("small-icon".equals(tname)) {
+                smallIcon = element.getBody();
+            } else if ("large-icon".equals(tname)) {
+                largeIcon = element.getBody();
+            } else if ("icon".equals(tname)) {
+                TreeNode icon = element.findChild("small-icon");
+                if (icon != null) {
+                    smallIcon = icon.getBody();
+                }
+                icon = element.findChild("large-icon");
+                if (icon != null) {
+                    largeIcon = icon.getBody();
+                }
+            } else if ("info".equals(tname) ||
+                     "description".equals(tname)) {
+                info = element.getBody();
+            } else if ("variable".equals(tname)) {
+                variableVector.addElement(createVariable(element));
+            } else if ("attribute".equals(tname)) {
+                attributeVector.addElement(createAttribute(element, jspVersion));
+            } else if ("dynamic-attributes".equals(tname)) {
+                dynamicAttributes = JspUtil.booleanValue(element.getBody());
+            } else if ("example".equals(tname)) {
+                // Ignored elements
+            } else if ("tag-extension".equals(tname)) {
+                // Ignored
+            } else {
+                if (log.isWarnEnabled()) {
+                    log.warn(Localizer.getMessage(
+                            "jsp.warning.unknown.element.in.tag", tname));
+                }
+            }
+        }
+
+        TagExtraInfo tei = null;
+        if (teiClassName != null && !teiClassName.equals("")) {
+            try {
+                Class teiClass = ctxt.getClassLoader().loadClass(teiClassName);
+                tei = (TagExtraInfo) teiClass.newInstance();
+            } catch (Exception e) {
+                err.jspError("jsp.error.teiclass.instantiation", teiClassName,
+                             e);
+            }
+        }
+
+        TagAttributeInfo[] tagAttributeInfo
+            = new TagAttributeInfo[attributeVector.size()];
+        attributeVector.copyInto(tagAttributeInfo);
+
+        TagVariableInfo[] tagVariableInfos
+            = new TagVariableInfo[variableVector.size()];
+        variableVector.copyInto(tagVariableInfos);
+
+        TagInfo taginfo = new TagInfo(tagName,
+                                      tagClassName,
+                                      bodycontent,
+                                      info,
+                                      this, 
+                                      tei,
+                                      tagAttributeInfo,
+                                      displayName,
+                                      smallIcon,
+                                      largeIcon,
+                                      tagVariableInfos,
+                                      dynamicAttributes);
+        return taginfo;
+    }
+
+    /*
+     * Parses the tag file directives of the given TagFile and turns them into
+     * a TagInfo.
+     *
+     * @param elem The <tag-file> element in the TLD
+     * @param uri The location of the TLD, in case the tag file is specified
+     * relative to it
+     * @param jarFile The JAR file, in case the tag file is packaged in a JAR
+     *
+     * @return TagInfo correspoding to tag file directives
+     */
+    private TagFileInfo createTagFileInfo(TreeNode elem, String uri,
+                                          URL jarFileUrl)
+                throws JasperException {
+
+        String name = null;
+        String path = null;
+
+        Iterator list = elem.findChildren();
+        while (list.hasNext()) {
+            TreeNode child = (TreeNode) list.next();
+            String tname = child.getName();
+            if ("name".equals(tname)) {
+                name = child.getBody();
+            } else if ("path".equals(tname)) {
+                path = child.getBody();
+            } else if ("example".equals(tname)) {
+                // Ignore <example> element: Bugzilla 33538
+            } else if ("tag-extension".equals(tname)) {
+                // Ignore <tag-extension> element: Bugzilla 33538
+            } else if ("icon".equals(tname) ||
+                        "display-name".equals(tname) ||
+                       "description".equals(tname)) {
+                // Ignore these elements: Bugzilla 38015
+            } else {
+                if (log.isWarnEnabled()) {
+                    log.warn(Localizer.getMessage(
+                            "jsp.warning.unknown.element.in.tagfile", tname));
+                }
+            }
+        }
+
+        if (path.startsWith("/META-INF/tags")) {
+            // Tag file packaged in JAR
+            ctxt.getTagFileJarUrls().put(path, jarFileUrl);
+        } else if (!path.startsWith("/WEB-INF/tags")) {
+            err.jspError("jsp.error.tagfile.illegalPath", path);
+        }
+
+        TagInfo tagInfo
+            = TagFileProcessor.parseTagFileDirectives(parserController, name,
+                                                      path, this);
+        return new TagFileInfo(name, path, tagInfo);
+    }
+
+    TagAttributeInfo createAttribute(TreeNode elem, String jspVersion) {
+        String name = null;
+        String type = null;
+        boolean required = false, rtexprvalue = false, reqTime = false,
+            isFragment = false;
+        
+        Iterator list = elem.findChildren();
+        while (list.hasNext()) {
+            TreeNode element = (TreeNode) list.next();
+            String tname = element.getName();
+
+            if ("name".equals(tname)) {
+                name = element.getBody();
+            } else if ("required".equals(tname)) {
+                String s = element.getBody();
+                if (s != null)
+                    required = JspUtil.booleanValue(s);
+            } else if ("rtexprvalue".equals(tname)) {
+                String s = element.getBody();
+                if (s != null)
+                    rtexprvalue = JspUtil.booleanValue(s);
+            } else if ("type".equals(tname)) {
+                type = element.getBody();
+                if ("1.2".equals(jspVersion)
+                        && (type.equals("Boolean")
+                            || type.equals("Byte")
+                            || type.equals("Character")
+                            || type.equals("Double")
+                            || type.equals("Float")
+                            || type.equals("Integer")
+                            || type.equals("Long")
+                            || type.equals("Object")
+                            || type.equals("Short")
+                            || type.equals("String"))) {
+                    type = "java.lang." + type;
+                }
+            } else if ("fragment".equals(tname)) {
+                String s = element.getBody();
+                if (s != null) {
+                    isFragment = JspUtil.booleanValue(s);
+                }
+            } else if ("description".equals(tname) ||    // Ignored elements
+                       false) {
+                ;
+            } else {
+                if (log.isWarnEnabled()) {
+                    log.warn(Localizer.getMessage(
+                            "jsp.warning.unknown.element.in.attribute", tname));
+                }
+            }
+        }
+
+        if (isFragment) {
+            /*
+             * According to JSP.C-3 ("TLD Schema Element Structure - tag"), 
+             * 'type' and 'rtexprvalue' must not be specified if 'fragment'
+             * has been specified (this will be enforced by validating parser).
+             * Also, if 'fragment' is TRUE, 'type' is fixed at
+             * javax.servlet.jsp.tagext.JspFragment, and 'rtexprvalue' is
+             * fixed at true. See also JSP.8.5.2.
+             */
+            type = "javax.servlet.jsp.tagext.JspFragment";
+            rtexprvalue = true;            
+        }
+        
+        if (!rtexprvalue) {
+            // According to JSP spec, for static values (those determined at
+            // translation time) the type is fixed at java.lang.String.
+            type = "java.lang.String";
+        }
+
+        return new TagAttributeInfo(name, required, type, rtexprvalue,
+                                    isFragment);
+    }
+
+    TagVariableInfo createVariable(TreeNode elem) {
+        String nameGiven = null;
+        String nameFromAttribute = null;
+        String className = "java.lang.String";
+        boolean declare = true;
+        int scope = VariableInfo.NESTED;
+
+        Iterator list = elem.findChildren();
+        while (list.hasNext()) {
+            TreeNode element = (TreeNode) list.next();
+            String tname = element.getName();
+            if ("name-given".equals(tname))
+                nameGiven = element.getBody();
+            else if ("name-from-attribute".equals(tname))
+                nameFromAttribute = element.getBody();
+            else if ("variable-class".equals(tname))
+                className = element.getBody();
+            else if ("declare".equals(tname)) {
+                String s = element.getBody();
+                if (s != null)
+                    declare = JspUtil.booleanValue(s);
+            } else if ("scope".equals(tname)) {
+                String s = element.getBody();
+                if (s != null) {
+                    if ("NESTED".equals(s)) {
+                        scope = VariableInfo.NESTED;
+                    } else if ("AT_BEGIN".equals(s)) {
+                        scope = VariableInfo.AT_BEGIN;
+                    } else if ("AT_END".equals(s)) {
+                        scope = VariableInfo.AT_END;
+                    }
+                }
+            } else if ("description".equals(tname) ||    // Ignored elements
+                     false ) {
+            } else {
+                if (log.isWarnEnabled()) {
+                    log.warn(Localizer.getMessage(
+                            "jsp.warning.unknown.element.in.variable", tname));
+                }
+            }
+        }
+        return new TagVariableInfo(nameGiven, nameFromAttribute,
+                                   className, declare, scope);
+    }
+
+    private TagLibraryValidator createValidator(TreeNode elem)
+            throws JasperException {
+
+        String validatorClass = null;
+        Map initParams = new Hashtable();
+
+        Iterator list = elem.findChildren();
+        while (list.hasNext()) {
+            TreeNode element = (TreeNode) list.next();
+            String tname = element.getName();
+            if ("validator-class".equals(tname))
+                validatorClass = element.getBody();
+            else if ("init-param".equals(tname)) {
+                String[] initParam = createInitParam(element);
+                initParams.put(initParam[0], initParam[1]);
+            } else if ("description".equals(tname) ||    // Ignored elements
+                     false ) {
+            } else {
+                if (log.isWarnEnabled()) {
+                    log.warn(Localizer.getMessage(
+                            "jsp.warning.unknown.element.in.validator", tname));
+                }
+            }
+        }
+
+        TagLibraryValidator tlv = null;
+        if (validatorClass != null && !validatorClass.equals("")) {
+            try {
+                Class tlvClass = 
+                    ctxt.getClassLoader().loadClass(validatorClass);
+                tlv = (TagLibraryValidator)tlvClass.newInstance();
+            } catch (Exception e) {
+                err.jspError("jsp.error.tlvclass.instantiation",
+                             validatorClass, e);
+            }
+        }
+        if (tlv != null) {
+            tlv.setInitParameters(initParams);
+        }
+        return tlv;
+    }
+
+    String[] createInitParam(TreeNode elem) {
+        String[] initParam = new String[2];
+        
+        Iterator list = elem.findChildren();
+        while (list.hasNext()) {
+            TreeNode element = (TreeNode) list.next();
+            String tname = element.getName();
+            if ("param-name".equals(tname)) {
+                initParam[0] = element.getBody();
+            } else if ("param-value".equals(tname)) {
+                initParam[1] = element.getBody();
+            } else if ("description".equals(tname)) {
+                ; // Do nothing
+            } else {
+                if (log.isWarnEnabled()) {
+                    log.warn(Localizer.getMessage(
+                            "jsp.warning.unknown.element.in.initParam", tname));
+                }
+            }
+        }
+        return initParam;
+    }
+
+    FunctionInfo createFunctionInfo(TreeNode elem) {
+
+        String name = null;
+        String klass = null;
+        String signature = null;
+
+        Iterator list = elem.findChildren();
+        while (list.hasNext()) {
+            TreeNode element = (TreeNode) list.next();
+            String tname = element.getName();
+
+            if ("name".equals(tname)) {
+                name = element.getBody();
+            } else if ("function-class".equals(tname)) {
+                klass = element.getBody();
+            } else if ("function-signature".equals(tname)) {
+                signature = element.getBody();
+            } else if ("display-name".equals(tname) ||    // Ignored elements
+                     "small-icon".equals(tname) ||
+                     "large-icon".equals(tname) ||
+                     "description".equals(tname) || 
+                     "example".equals(tname)) {
+            } else {
+                if (log.isWarnEnabled()) {
+                    log.warn(Localizer.getMessage(
+                        "jsp.warning.unknown.element.in.function", tname));
+                }
+            }
+        }
+
+        return new FunctionInfo(name, klass, signature);
+    }
+
+
+    //*********************************************************************
+    // Until javax.servlet.jsp.tagext.TagLibraryInfo is fixed
+
+    /**
+     * The instance (if any) for the TagLibraryValidator class.
+     * 
+     * @return The TagLibraryValidator instance, if any.
+     */
+    public TagLibraryValidator getTagLibraryValidator() {
+        return tagLibraryValidator;
+    }
+
+    /**
+     * Translation-time validation of the XML document
+     * associated with the JSP page.
+     * This is a convenience method on the associated 
+     * TagLibraryValidator class.
+     *
+     * @param thePage The JSP page object
+     * @return A string indicating whether the page is valid or not.
+     */
+    public ValidationMessage[] validate(PageData thePage) {
+        TagLibraryValidator tlv = getTagLibraryValidator();
+        if (tlv == null) return null;
+
+        String uri = getURI();
+        if (uri.startsWith("/")) {
+            uri = URN_JSPTLD + uri;
+        }
+
+        return tlv.validate(getPrefixString(), uri, thePage);
+    }
+
+    protected TagLibraryValidator tagLibraryValidator; 
+}

Added: branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/TagPluginManager.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/TagPluginManager.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/TagPluginManager.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,239 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.util.*;
+import java.io.*;
+import javax.servlet.ServletContext;
+
+import org.apache.jasper.JasperException;
+import org.apache.jasper.xmlparser.ParserUtils;
+import org.apache.jasper.xmlparser.TreeNode;
+import org.apache.jasper.compiler.tagplugin.TagPlugin;
+import org.apache.jasper.compiler.tagplugin.TagPluginContext;
+
+/**
+ * Manages tag plugin optimizations.
+ * @author Kin-man Chung
+ */
+
+public class TagPluginManager {
+
+    private static final String TAG_PLUGINS_XML = "/WEB-INF/tagPlugins.xml";
+    private static final String TAG_PLUGINS_ROOT_ELEM = "tag-plugins";
+
+    private boolean initialized = false;
+    private HashMap tagPlugins = null;
+    private ServletContext ctxt;
+    private PageInfo pageInfo;
+
+    public TagPluginManager(ServletContext ctxt) {
+	this.ctxt = ctxt;
+    }
+
+    public void apply(Node.Nodes page, ErrorDispatcher err, PageInfo pageInfo)
+	    throws JasperException {
+
+	init(err);
+	if (tagPlugins == null || tagPlugins.size() == 0) {
+	    return;
+	}
+
+	this.pageInfo = pageInfo;
+
+        page.visit(new Node.Visitor() {
+            public void visit(Node.CustomTag n)
+                    throws JasperException {
+                invokePlugin(n);
+                visitBody(n);
+            }
+        });
+
+    }
+ 
+    private void init(ErrorDispatcher err) throws JasperException {
+	if (initialized)
+	    return;
+
+	InputStream is = ctxt.getResourceAsStream(TAG_PLUGINS_XML);
+	if (is == null)
+	    return;
+
+	TreeNode root = (new ParserUtils()).parseXMLDocument(TAG_PLUGINS_XML,
+							     is);
+	if (root == null) {
+	    return;
+	}
+
+	if (!TAG_PLUGINS_ROOT_ELEM.equals(root.getName())) {
+	    err.jspError("jsp.error.plugin.wrongRootElement", TAG_PLUGINS_XML,
+			 TAG_PLUGINS_ROOT_ELEM);
+	}
+
+	tagPlugins = new HashMap();
+	Iterator pluginList = root.findChildren("tag-plugin");
+	while (pluginList.hasNext()) {
+	    TreeNode pluginNode = (TreeNode) pluginList.next();
+            TreeNode tagClassNode = pluginNode.findChild("tag-class");
+	    if (tagClassNode == null) {
+		// Error
+		return;
+	    }
+	    String tagClass = tagClassNode.getBody().trim();
+	    TreeNode pluginClassNode = pluginNode.findChild("plugin-class");
+	    if (pluginClassNode == null) {
+		// Error
+		return;
+	    }
+
+	    String pluginClassStr = pluginClassNode.getBody();
+	    TagPlugin tagPlugin = null;
+	    try {
+		Class pluginClass = Class.forName(pluginClassStr);
+		tagPlugin = (TagPlugin) pluginClass.newInstance();
+	    } catch (Exception e) {
+		throw new JasperException(e);
+	    }
+	    if (tagPlugin == null) {
+		return;
+	    }
+	    tagPlugins.put(tagClass, tagPlugin);
+	}
+	initialized = true;
+    }
+
+    /**
+     * Invoke tag plugin for the given custom tag, if a plugin exists for 
+     * the custom tag's tag handler.
+     *
+     * The given custom tag node will be manipulated by the plugin.
+     */
+    private void invokePlugin(Node.CustomTag n) {
+	TagPlugin tagPlugin = (TagPlugin)
+		tagPlugins.get(n.getTagHandlerClass().getName());
+	if (tagPlugin == null) {
+	    return;
+	}
+
+	TagPluginContext tagPluginContext = new TagPluginContextImpl(n, pageInfo);
+	n.setTagPluginContext(tagPluginContext);
+	tagPlugin.doTag(tagPluginContext);
+    }
+
+    static class TagPluginContextImpl implements TagPluginContext {
+	private Node.CustomTag node;
+	private Node.Nodes curNodes;
+	private PageInfo pageInfo;
+	private HashMap pluginAttributes;
+
+	TagPluginContextImpl(Node.CustomTag n, PageInfo pageInfo) {
+	    this.node = n;
+	    this.pageInfo = pageInfo;
+	    curNodes = new Node.Nodes();
+	    n.setAtETag(curNodes);
+	    curNodes = new Node.Nodes();
+	    n.setAtSTag(curNodes);
+	    n.setUseTagPlugin(true);
+	    pluginAttributes = new HashMap();
+	}
+
+	public TagPluginContext getParentContext() {
+	    Node parent = node.getParent();
+	    if (! (parent instanceof Node.CustomTag)) {
+		return null;
+	    }
+	    return ((Node.CustomTag) parent).getTagPluginContext();
+	}
+
+	public void setPluginAttribute(String key, Object value) {
+	    pluginAttributes.put(key, value);
+	}
+
+	public Object getPluginAttribute(String key) {
+	    return pluginAttributes.get(key);
+	}
+
+	public boolean isScriptless() {
+	    return node.getChildInfo().isScriptless();
+	}
+
+	public boolean isConstantAttribute(String attribute) {
+	    Node.JspAttribute attr = getNodeAttribute(attribute);
+	    if (attr == null)
+		return false;
+	    return attr.isLiteral();
+	}
+
+	public String getConstantAttribute(String attribute) {
+	    Node.JspAttribute attr = getNodeAttribute(attribute);
+            if (attr == null)
+		return null;
+	    return attr.getValue();
+	}
+
+	public boolean isAttributeSpecified(String attribute) {
+	    return getNodeAttribute(attribute) != null;
+	}
+
+	public String getTemporaryVariableName() {
+	    return JspUtil.nextTemporaryVariableName();
+	}
+
+	public void generateImport(String imp) {
+	    pageInfo.addImport(imp);
+	}
+
+	public void generateDeclaration(String id, String text) {
+	    if (pageInfo.isPluginDeclared(id)) {
+		return;
+	    }
+	    curNodes.add(new Node.Declaration(text, node.getStart(), null));
+	}
+
+	public void generateJavaSource(String sourceCode) {
+	    curNodes.add(new Node.Scriptlet(sourceCode, node.getStart(),
+					    null));
+	}
+
+	public void generateAttribute(String attributeName) {
+	    curNodes.add(new Node.AttributeGenerator(node.getStart(),
+						     attributeName,
+						     node));
+	}
+
+	public void dontUseTagPlugin() {
+	    node.setUseTagPlugin(false);
+	}
+
+	public void generateBody() {
+	    // Since we'll generate the body anyway, this is really a nop, 
+	    // except for the fact that it lets us put the Java sources the
+	    // plugins produce in the correct order (w.r.t the body).
+	    curNodes = node.getAtETag();
+	}
+
+	private Node.JspAttribute getNodeAttribute(String attribute) {
+	    Node.JspAttribute[] attrs = node.getJspAttributes();
+	    for (int i=0; attrs != null && i < attrs.length; i++) {
+		if (attrs[i].getName().equals(attribute)) {
+		    return attrs[i];
+		}
+	    }
+	    return null;
+	}
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/TextOptimizer.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/TextOptimizer.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/TextOptimizer.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,112 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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 org.apache.jasper.JasperException;
+import org.apache.jasper.Options;
+
+/**
+ */
+public class TextOptimizer {
+
+    /**
+     * A visitor to concatenate contiguous template texts.
+     */
+    static class TextCatVisitor extends Node.Visitor {
+
+        private Options options;
+        private int textNodeCount = 0;
+        private Node.TemplateText firstTextNode = null;
+        private StringBuffer textBuffer;
+        private final String emptyText = new String("");
+
+        public TextCatVisitor(Compiler compiler) {
+            options = compiler.getCompilationContext().getOptions();
+        }
+
+        public void doVisit(Node n) throws JasperException {
+            collectText();
+        }
+
+	/*
+         * The following directis are ignored in text concatenation
+         */
+
+        public void visit(Node.PageDirective n) throws JasperException {
+        }
+
+        public void visit(Node.TagDirective n) throws JasperException {
+        }
+
+        public void visit(Node.TaglibDirective n) throws JasperException {
+        }
+
+        public void visit(Node.AttributeDirective n) throws JasperException {
+        }
+
+        public void visit(Node.VariableDirective n) throws JasperException {
+        }
+
+        /*
+         * Don't concatenate text across body boundaries
+         */
+        public void visitBody(Node n) throws JasperException {
+            super.visitBody(n);
+            collectText();
+        }
+
+        public void visit(Node.TemplateText n) throws JasperException {
+
+            if (options.getTrimSpaces() && n.isAllSpace()) {
+                n.setText(emptyText);
+                return;
+            }
+
+            if (textNodeCount++ == 0) {
+                firstTextNode = n;
+                textBuffer = new StringBuffer(n.getText());
+            } else {
+                // Append text to text buffer
+                textBuffer.append(n.getText());
+                n.setText(emptyText);
+            }
+        }
+
+        /**
+         * This method breaks concatenation mode.  As a side effect it copies
+         * the concatenated string to the first text node 
+         */
+        private void collectText() {
+
+            if (textNodeCount > 1) {
+                // Copy the text in buffer into the first template text node.
+                firstTextNode.setText(textBuffer.toString());
+            }
+            textNodeCount = 0;
+        }
+
+    }
+
+    public static void concatenate(Compiler compiler, Node.Nodes page)
+            throws JasperException {
+
+        TextCatVisitor v = new TextCatVisitor(compiler);
+        page.visit(v);
+
+	// Cleanup, in case the page ends with a template text
+        v.collectText();
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/TldLocationsCache.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/TldLocationsCache.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/TldLocationsCache.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,554 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.InputStream;
+import java.io.IOException;
+import java.net.JarURLConnection;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.net.URLConnection;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+import java.util.StringTokenizer;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+import org.xml.sax.InputSource;
+
+import javax.servlet.ServletContext;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.jasper.Constants;
+import org.apache.jasper.JasperException;
+import org.apache.jasper.xmlparser.ParserUtils;
+import org.apache.jasper.xmlparser.TreeNode;
+
+/**
+ * A container for all tag libraries that are defined "globally"
+ * for the web application.
+ * 
+ * Tag Libraries can be defined globally in one of two ways:
+ *   1. Via <taglib> elements in web.xml:
+ *      the uri and location of the tag-library are specified in
+ *      the <taglib> element.
+ *   2. Via packaged jar files that contain .tld files
+ *      within the META-INF directory, or some subdirectory
+ *      of it. The taglib is 'global' if it has the <uri>
+ *      element defined.
+ *
+ * A mapping between the taglib URI and its associated TaglibraryInfoImpl
+ * is maintained in this container.
+ * Actually, that's what we'd like to do. However, because of the
+ * way the classes TagLibraryInfo and TagInfo have been defined,
+ * it is not currently possible to share an instance of TagLibraryInfo
+ * across page invocations. A bug has been submitted to the spec lead.
+ * In the mean time, all we do is save the 'location' where the
+ * TLD associated with a taglib URI can be found.
+ *
+ * When a JSP page has a taglib directive, the mappings in this container
+ * are first searched (see method getLocation()).
+ * If a mapping is found, then the location of the TLD is returned.
+ * If no mapping is found, then the uri specified
+ * in the taglib directive is to be interpreted as the location for
+ * the TLD of this tag library.
+ *
+ * @author Pierre Delisle
+ * @author Jan Luehe
+ */
+
+public class TldLocationsCache {
+
+    // Logger
+    private Log log = LogFactory.getLog(TldLocationsCache.class);
+
+    /**
+     * The types of URI one may specify for a tag library
+     */
+    public static final int ABS_URI = 0;
+    public static final int ROOT_REL_URI = 1;
+    public static final int NOROOT_REL_URI = 2;
+
+    private static final String WEB_XML = "/WEB-INF/web.xml";
+    private static final String FILE_PROTOCOL = "file:";
+    private static final String JAR_FILE_SUFFIX = ".jar";
+
+    // Names of JARs that are known not to contain any TLDs
+    private static HashSet noTldJars;
+
+    /**
+     * 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 mappings;
+
+    private boolean initialized;
+    private ServletContext ctxt;
+    private boolean redeployMode;
+
+    //*********************************************************************
+    // Constructor and Initilizations
+
+    /*
+     * Initializes the set of JARs that are known not to contain any TLDs
+     */
+    static {
+        noTldJars = new HashSet();
+        noTldJars.add("ant.jar");
+        noTldJars.add("catalina.jar");
+        noTldJars.add("catalina-ant.jar");
+        noTldJars.add("catalina-cluster.jar");
+        noTldJars.add("catalina-optional.jar");
+        noTldJars.add("catalina-i18n-fr.jar");
+        noTldJars.add("catalina-i18n-ja.jar");
+        noTldJars.add("catalina-i18n-es.jar");
+        noTldJars.add("commons-dbcp.jar");
+        noTldJars.add("commons-modeler.jar");
+        noTldJars.add("commons-logging-api.jar");
+        noTldJars.add("commons-beanutils.jar");
+        noTldJars.add("commons-fileupload-1.0.jar");
+        noTldJars.add("commons-pool.jar");
+        noTldJars.add("commons-digester.jar");
+        noTldJars.add("commons-logging.jar");
+        noTldJars.add("commons-collections.jar");
+        noTldJars.add("commons-el.jar");
+        noTldJars.add("jakarta-regexp-1.2.jar");
+        noTldJars.add("jasper-compiler.jar");
+        noTldJars.add("jasper-runtime.jar");
+        noTldJars.add("jmx.jar");
+        noTldJars.add("jmx-tools.jar");
+        noTldJars.add("jsp-api.jar");
+        noTldJars.add("jkshm.jar");
+        noTldJars.add("jkconfig.jar");
+        noTldJars.add("naming-common.jar");
+        noTldJars.add("naming-resources.jar");
+        noTldJars.add("naming-factory.jar");
+        noTldJars.add("naming-java.jar");
+        noTldJars.add("servlet-api.jar");
+        noTldJars.add("servlets-default.jar");
+        noTldJars.add("servlets-invoker.jar");
+        noTldJars.add("servlets-common.jar");
+        noTldJars.add("servlets-webdav.jar");
+        noTldJars.add("tomcat-util.jar");
+        noTldJars.add("tomcat-http11.jar");
+        noTldJars.add("tomcat-jni.jar");
+        noTldJars.add("tomcat-jk.jar");
+        noTldJars.add("tomcat-jk2.jar");
+        noTldJars.add("tomcat-coyote.jar");
+        noTldJars.add("xercesImpl.jar");
+        noTldJars.add("xmlParserAPIs.jar");
+        noTldJars.add("xml-apis.jar");
+        // JARs from J2SE runtime
+        noTldJars.add("sunjce_provider.jar");
+        noTldJars.add("ldapsec.jar");
+        noTldJars.add("localedata.jar");
+        noTldJars.add("dnsns.jar");
+    }
+    
+    public TldLocationsCache(ServletContext ctxt) {
+        this(ctxt, true);
+    }
+
+    /** Constructor. 
+     *
+     * @param ctxt the servlet context of the web application in which Jasper 
+     * is running
+     * @param redeployMode if true, then the compiler will allow redeploying 
+     * a tag library from the same jar, at the expense of slowing down the
+     * server a bit. Note that this may only work on JDK 1.3.1_01a and later,
+     * because of JDK bug 4211817 fixed in this release.
+     * If redeployMode is false, a faster but less capable mode will be used.
+     */
+    public TldLocationsCache(ServletContext ctxt, boolean redeployMode) {
+        this.ctxt = ctxt;
+        this.redeployMode = redeployMode;
+        mappings = new Hashtable();
+        initialized = false;
+    }
+
+    /**
+     * 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) {
+        if (jarNames != null) {
+            noTldJars.clear();
+            StringTokenizer tokenizer = new StringTokenizer(jarNames, ",");
+            while (tokenizer.hasMoreElements()) {
+                noTldJars.add(tokenizer.nextToken());
+            }
+        }
+    }
+
+    /**
+     * Gets the 'location' of the TLD associated with the given taglib 'uri'.
+     *
+     * Returns null if the uri is not associated with any tag library 'exposed'
+     * in the web application. A tag library is 'exposed' either explicitly in
+     * web.xml or implicitly via the uri tag in the TLD of a taglib deployed
+     * in a jar file (WEB-INF/lib).
+     * 
+     * @param uri The taglib uri
+     *
+     * @return An array of two Strings: The first element denotes the real
+     * path to the TLD. If the path to the TLD points to a jar file, then the
+     * second element denotes the name of the TLD entry in the jar file.
+     * Returns null if the uri is not associated with any tag library 'exposed'
+     * in the web application.
+     */
+    public String[] getLocation(String uri) throws JasperException {
+        if (!initialized) {
+            init();
+        }
+        return (String[]) mappings.get(uri);
+    }
+
+    /** 
+     * Returns the type of a URI:
+     *     ABS_URI
+     *     ROOT_REL_URI
+     *     NOROOT_REL_URI
+     */
+    public static int uriType(String uri) {
+        if (uri.indexOf(':') != -1) {
+            return ABS_URI;
+        } else if (uri.startsWith("/")) {
+            return ROOT_REL_URI;
+        } else {
+            return NOROOT_REL_URI;
+        }
+    }
+
+    private void init() throws JasperException {
+        if (initialized) return;
+        try {
+            processWebDotXml();
+            scanJars();
+            processTldsInFileSystem("/WEB-INF/");
+            initialized = true;
+        } catch (Exception ex) {
+            throw new JasperException(Localizer.getMessage(
+                    "jsp.error.internal.tldinit", ex.getMessage()));
+        }
+    }
+
+    /*
+     * Populates taglib map described in web.xml.
+     */    
+    private void processWebDotXml() throws Exception {
+
+        InputStream is = null;
+
+        try {
+            // Acquire input stream to web application deployment descriptor
+            String altDDName = (String)ctxt.getAttribute(
+                                                    Constants.ALT_DD_ATTR);
+            URL uri = null;
+            if (altDDName != null) {
+                try {
+                    uri = new URL(FILE_PROTOCOL+altDDName.replace('\\', '/'));
+                } catch (MalformedURLException e) {
+                    if (log.isWarnEnabled()) {
+                        log.warn(Localizer.getMessage(
+                                            "jsp.error.internal.filenotfound",
+                                            altDDName));
+                    }
+                }
+            } else {
+                uri = ctxt.getResource(WEB_XML);
+                if (uri == null && log.isWarnEnabled()) {
+                    log.warn(Localizer.getMessage(
+                                            "jsp.error.internal.filenotfound",
+                                            WEB_XML));
+                }
+            }
+
+            if (uri == null) {
+                return;
+            }
+            is = uri.openStream();
+            InputSource ip = new InputSource(is);
+            ip.setSystemId(uri.toExternalForm()); 
+
+            // Parse the web application deployment descriptor
+            TreeNode webtld = null;
+            // altDDName is the absolute path of the DD
+            if (altDDName != null) {
+                webtld = new ParserUtils().parseXMLDocument(altDDName, ip);
+            } else {
+                webtld = new ParserUtils().parseXMLDocument(WEB_XML, ip);
+            }
+
+            // Allow taglib to be an element of the root or jsp-config (JSP2.0)
+            TreeNode jspConfig = webtld.findChild("jsp-config");
+            if (jspConfig != null) {
+                webtld = jspConfig;
+            }
+            Iterator taglibs = webtld.findChildren("taglib");
+            while (taglibs.hasNext()) {
+
+                // Parse the next <taglib> element
+                TreeNode taglib = (TreeNode) taglibs.next();
+                String tagUri = null;
+                String tagLoc = null;
+                TreeNode child = taglib.findChild("taglib-uri");
+                if (child != null)
+                    tagUri = child.getBody();
+                child = taglib.findChild("taglib-location");
+                if (child != null)
+                    tagLoc = child.getBody();
+
+                // Save this location if appropriate
+                if (tagLoc == null)
+                    continue;
+                if (uriType(tagLoc) == NOROOT_REL_URI)
+                    tagLoc = "/WEB-INF/" + tagLoc;
+                String tagLoc2 = null;
+                if (tagLoc.endsWith(JAR_FILE_SUFFIX)) {
+                    tagLoc = ctxt.getResource(tagLoc).toString();
+                    tagLoc2 = "META-INF/taglib.tld";
+                }
+                mappings.put(tagUri, new String[] { tagLoc, tagLoc2 });
+            }
+        } finally {
+            if (is != null) {
+                try {
+                    is.close();
+                } catch (Throwable t) {}
+            }
+        }
+    }
+
+    /**
+     * Scans the given JarURLConnection for TLD files located in META-INF
+     * (or a subdirectory of it), adding an implicit map entry to the taglib
+     * map for any TLD that has a <uri> element.
+     *
+     * @param conn The JarURLConnection to the JAR file to scan
+     * @param ignore true if any exceptions raised when processing the given
+     * JAR should be ignored, false otherwise
+     */
+    private void scanJar(JarURLConnection conn, boolean ignore)
+                throws JasperException {
+
+        JarFile jarFile = null;
+        String resourcePath = conn.getJarFileURL().toString();
+        try {
+            if (redeployMode) {
+                conn.setUseCaches(false);
+            }
+            jarFile = conn.getJarFile();
+            Enumeration entries = jarFile.entries();
+            while (entries.hasMoreElements()) {
+                JarEntry entry = (JarEntry) entries.nextElement();
+                String name = entry.getName();
+                if (!name.startsWith("META-INF/")) continue;
+                if (!name.endsWith(".tld")) continue;
+                InputStream stream = jarFile.getInputStream(entry);
+                try {
+                    String uri = getUriFromTld(resourcePath, stream);
+                    // Add implicit map entry only if its uri is not already
+                    // present in the map
+                    if (uri != null && mappings.get(uri) == null) {
+                        mappings.put(uri, new String[]{ resourcePath, name });
+                    }
+                } finally {
+                    if (stream != null) {
+                        try {
+                            stream.close();
+                        } catch (Throwable t) {
+                            // do nothing
+                        }
+                    }
+                }
+            }
+        } catch (Exception ex) {
+            if (!redeployMode) {
+                // if not in redeploy mode, close the jar in case of an error
+                if (jarFile != null) {
+                    try {
+                        jarFile.close();
+                    } catch (Throwable t) {
+                        // ignore
+                    }
+                }
+            }
+            if (!ignore) {
+                throw new JasperException(ex);
+            }
+        } finally {
+            if (redeployMode) {
+                // if in redeploy mode, always close the jar
+                if (jarFile != null) {
+                    try {
+                        jarFile.close();
+                    } catch (Throwable t) {
+                        // ignore
+                    }
+                }
+            }
+        }
+    }
+
+    /*
+     * Searches the filesystem under /WEB-INF for any TLD files, and adds
+     * an implicit map entry to the taglib map for any TLD that has a <uri>
+     * element.
+     */
+    private void processTldsInFileSystem(String startPath)
+            throws Exception {
+
+        Set dirList = ctxt.getResourcePaths(startPath);
+        if (dirList != null) {
+            Iterator it = dirList.iterator();
+            while (it.hasNext()) {
+                String path = (String) it.next();
+                if (path.endsWith("/")) {
+                    processTldsInFileSystem(path);
+                }
+                if (!path.endsWith(".tld")) {
+                    continue;
+                }
+                InputStream stream = ctxt.getResourceAsStream(path);
+                String uri = null;
+                try {
+                    uri = getUriFromTld(path, stream);
+                } finally {
+                    if (stream != null) {
+                        try {
+                            stream.close();
+                        } catch (Throwable t) {
+                            // do nothing
+                        }
+                    }
+                }
+                // Add implicit map entry only if its uri is not already
+                // present in the map
+                if (uri != null && mappings.get(uri) == null) {
+                    mappings.put(uri, new String[] { path, null });
+                }
+            }
+        }
+    }
+
+    /*
+     * Returns the value of the uri element of the given TLD, or null if the
+     * given TLD does not contain any such element.
+     */
+    private String getUriFromTld(String resourcePath, InputStream in) 
+        throws JasperException
+    {
+        // Parse the tag library descriptor at the specified resource path
+        TreeNode tld = new ParserUtils().parseXMLDocument(resourcePath, in);
+        TreeNode uri = tld.findChild("uri");
+        if (uri != null) {
+            String body = uri.getBody();
+            if (body != null)
+                return body;
+        }
+
+        return null;
+    }
+
+    /*
+     * Scans all JARs accessible to the webapp's classloader and its
+     * parent classloaders for TLDs.
+     * 
+     * The list of JARs always includes the JARs under WEB-INF/lib, as well as
+     * all shared JARs in the classloader delegation chain of the webapp's
+     * classloader.
+     *
+     * Considering JARs in the classloader delegation chain constitutes a
+     * Tomcat-specific extension to the TLD search
+     * order defined in the JSP spec. It allows tag libraries packaged as JAR
+     * files to be shared by web applications by simply dropping them in a 
+     * location that all web applications have access to (e.g.,
+     * <CATALINA_HOME>/common/lib).
+     *
+     * The set of shared JARs to be scanned for TLDs is narrowed down by
+     * the <tt>noTldJars</tt> class variable, which contains the names of JARs
+     * that are known not to contain any TLDs.
+     */
+    private void scanJars() throws Exception {
+
+        ClassLoader webappLoader
+            = Thread.currentThread().getContextClassLoader();
+        ClassLoader loader = webappLoader;
+
+        while (loader != null) {
+            if (loader instanceof URLClassLoader) {
+                URL[] urls = ((URLClassLoader) loader).getURLs();
+                for (int i=0; i<urls.length; i++) {
+                    URLConnection conn = urls[i].openConnection();
+                    if (conn instanceof JarURLConnection) {
+                        if (needScanJar(loader, webappLoader,
+                                        ((JarURLConnection) conn).getJarFile().getName())) {
+                            scanJar((JarURLConnection) conn, true);
+                        }
+                    } else {
+                        String urlStr = urls[i].toString();
+                        if (urlStr.startsWith(FILE_PROTOCOL)
+                                && urlStr.endsWith(JAR_FILE_SUFFIX)
+                                && needScanJar(loader, webappLoader, urlStr)) {
+                            URL jarURL = new URL("jar:" + urlStr + "!/");
+                            scanJar((JarURLConnection) jarURL.openConnection(),
+                                    true);
+                        }
+                    }
+                }
+            }
+
+            loader = loader.getParent();
+        }
+    }
+
+    /*
+     * Determines if the JAR file with the given <tt>jarPath</tt> needs to be
+     * scanned for TLDs.
+     *
+     * @param loader The current classloader in the parent chain
+     * @param webappLoader The webapp classloader
+     * @param jarPath The JAR file path
+     *
+     * @return TRUE if the JAR file identified by <tt>jarPath</tt> needs to be
+     * scanned for TLDs, FALSE otherwise
+     */
+    private boolean needScanJar(ClassLoader loader, ClassLoader webappLoader,
+                                String jarPath) {
+        if (loader == webappLoader) {
+            // JARs under WEB-INF/lib must be scanned unconditionally according
+            // to the spec.
+            return true;
+        } else {
+            String jarName = jarPath;
+            int slash = jarPath.lastIndexOf('/');
+            if (slash >= 0) {
+                jarName = jarPath.substring(slash + 1);
+            }
+            return (!noTldJars.contains(jarName));
+        }
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/Validator.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/Validator.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/Validator.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,1553 @@
+/*
+ * Copyright 1999,2004-2005 The Apache Software Foundation.
+ * 
+ * Licensed 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.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.Iterator;
+
+import javax.servlet.jsp.el.FunctionMapper;
+import javax.servlet.jsp.tagext.FunctionInfo;
+import javax.servlet.jsp.tagext.JspFragment;
+import javax.servlet.jsp.tagext.PageData;
+import javax.servlet.jsp.tagext.TagAttributeInfo;
+import javax.servlet.jsp.tagext.TagData;
+import javax.servlet.jsp.tagext.TagExtraInfo;
+import javax.servlet.jsp.tagext.TagInfo;
+import javax.servlet.jsp.tagext.TagLibraryInfo;
+import javax.servlet.jsp.tagext.ValidationMessage;
+
+import org.apache.jasper.Constants;
+import org.apache.jasper.JasperException;
+import org.apache.jasper.JspCompilationContext;
+import org.xml.sax.Attributes;
+
+/**
+ * Performs validation on the page elements.  Attributes are checked for
+ * mandatory presence, entry value validity, and consistency.  As a
+ * side effect, some page global value (such as those from page direcitves)
+ * are stored, for later use.
+ *
+ * @author Kin-man Chung
+ * @author Jan Luehe
+ * @author Shawn Bayern
+ * @author Mark Roth
+ */
+class Validator {
+
+    /**
+     * A visitor to validate and extract page directive info
+     */
+    static class DirectiveVisitor extends Node.Visitor {
+
+	private PageInfo pageInfo;
+	private ErrorDispatcher err;
+
+	private static final JspUtil.ValidAttribute[] pageDirectiveAttrs = {
+	    new JspUtil.ValidAttribute("language"),
+	    new JspUtil.ValidAttribute("extends"),
+	    new JspUtil.ValidAttribute("import"),
+	    new JspUtil.ValidAttribute("session"),
+	    new JspUtil.ValidAttribute("buffer"),
+	    new JspUtil.ValidAttribute("autoFlush"),
+	    new JspUtil.ValidAttribute("isThreadSafe"),
+	    new JspUtil.ValidAttribute("info"),
+	    new JspUtil.ValidAttribute("errorPage"),
+	    new JspUtil.ValidAttribute("isErrorPage"),
+	    new JspUtil.ValidAttribute("contentType"),
+	    new JspUtil.ValidAttribute("pageEncoding"),
+	    new JspUtil.ValidAttribute("isELIgnored")
+	};
+
+	private boolean pageEncodingSeen = false;
+
+	/*
+	 * Constructor
+	 */
+	DirectiveVisitor(Compiler compiler) throws JasperException {
+	    this.pageInfo = compiler.getPageInfo();
+	    this.err = compiler.getErrorDispatcher();
+	    JspCompilationContext ctxt = compiler.getCompilationContext();
+	}
+
+	public void visit(Node.IncludeDirective n) throws JasperException {
+            // Since pageDirectiveSeen flag only applies to the Current page
+            // save it here and restore it after the file is included.
+            boolean pageEncodingSeenSave = pageEncodingSeen;
+            pageEncodingSeen = false;
+            visitBody(n);
+            pageEncodingSeen = pageEncodingSeenSave;
+        }
+
+	public void visit(Node.PageDirective n) throws JasperException {    
+
+            JspUtil.checkAttributes("Page directive", n,
+                                    pageDirectiveAttrs, err);
+
+	    // JSP.2.10.1
+	    Attributes attrs = n.getAttributes();
+	    for (int i = 0; attrs != null && i < attrs.getLength(); i++) {
+		String attr = attrs.getQName(i);
+		String value = attrs.getValue(i);
+
+		if ("language".equals(attr)) {
+		    if (pageInfo.getLanguage(false) == null) {
+			pageInfo.setLanguage(value, n, err, true);
+		    } else if (!pageInfo.getLanguage(false).equals(value)) {
+			err.jspError(n, "jsp.error.page.conflict.language",
+				     pageInfo.getLanguage(false), value);
+		    }
+		} else if ("extends".equals(attr)) {
+		    if (pageInfo.getExtends(false) == null) {
+			pageInfo.setExtends(value, n);
+		    } else if (!pageInfo.getExtends(false).equals(value)) {
+			err.jspError(n, "jsp.error.page.conflict.extends",
+				     pageInfo.getExtends(false), value);
+		    }
+		} else if ("contentType".equals(attr)) {
+		    if (pageInfo.getContentType() == null) {
+			pageInfo.setContentType(value);
+		    } else if (!pageInfo.getContentType().equals(value)) {
+			err.jspError(n, "jsp.error.page.conflict.contenttype",
+				     pageInfo.getContentType(), value);
+		    }
+		} else if ("session".equals(attr)) {
+		    if (pageInfo.getSession() == null) {
+			pageInfo.setSession(value, n, err);
+		    } else if (!pageInfo.getSession().equals(value)) {
+			err.jspError(n, "jsp.error.page.conflict.session",
+				     pageInfo.getSession(), value);
+		    }
+		} else if ("buffer".equals(attr)) {
+		    if (pageInfo.getBufferValue() == null) {
+			pageInfo.setBufferValue(value, n, err);
+		    } else if (!pageInfo.getBufferValue().equals(value)) {
+			err.jspError(n, "jsp.error.page.conflict.buffer",
+				     pageInfo.getBufferValue(), value);
+		    }
+		} else if ("autoFlush".equals(attr)) {
+		    if (pageInfo.getAutoFlush() == null) {
+			pageInfo.setAutoFlush(value, n, err);
+		    } else if (!pageInfo.getAutoFlush().equals(value)) {
+			err.jspError(n, "jsp.error.page.conflict.autoflush",
+				     pageInfo.getAutoFlush(), value);
+		    }
+		} else if ("isThreadSafe".equals(attr)) {
+		    if (pageInfo.getIsThreadSafe() == null) {
+			pageInfo.setIsThreadSafe(value, n, err);
+		    } else if (!pageInfo.getIsThreadSafe().equals(value)) {
+			err.jspError(n, "jsp.error.page.conflict.isthreadsafe",
+				     pageInfo.getIsThreadSafe(), value);
+		    }
+		} else if ("isELIgnored".equals(attr)) {
+		    if (pageInfo.getIsELIgnored() == null) {
+                        pageInfo.setIsELIgnored(value, n, err, true);
+		    } else if (!pageInfo.getIsELIgnored().equals(value)) {
+			err.jspError(n, "jsp.error.page.conflict.iselignored",
+				     pageInfo.getIsELIgnored(), value);
+		    }
+		} else if ("isErrorPage".equals(attr)) {
+		    if (pageInfo.getIsErrorPage() == null) {
+			pageInfo.setIsErrorPage(value, n, err);
+		    } else if (!pageInfo.getIsErrorPage().equals(value)) {
+			err.jspError(n, "jsp.error.page.conflict.iserrorpage",
+				     pageInfo.getIsErrorPage(), value);
+		    }
+		} else if ("errorPage".equals(attr)) {
+		    if (pageInfo.getErrorPage() == null) {
+			pageInfo.setErrorPage(value);
+		    } else if (!pageInfo.getErrorPage().equals(value)) {
+			err.jspError(n, "jsp.error.page.conflict.errorpage",
+				     pageInfo.getErrorPage(), value);
+		    }
+		} else if ("info".equals(attr)) {
+		    if (pageInfo.getInfo() == null) {
+			pageInfo.setInfo(value);
+		    } else if (!pageInfo.getInfo().equals(value)) {
+			err.jspError(n, "jsp.error.page.conflict.info",
+				     pageInfo.getInfo(), value);
+		    }
+		} else if ("pageEncoding".equals(attr)) {
+		    if (pageEncodingSeen) 
+			err.jspError(n, "jsp.error.page.multi.pageencoding");
+		    // 'pageEncoding' can occur at most once per file
+		    pageEncodingSeen = true;
+		    comparePageEncodings(value, n);
+		}
+	    }
+
+	    // Check for bad combinations
+	    if (pageInfo.getBuffer() == 0 && !pageInfo.isAutoFlush())
+		err.jspError(n, "jsp.error.page.badCombo");
+
+	    // Attributes for imports for this node have been processed by
+	    // the parsers, just add them to pageInfo.
+	    pageInfo.addImports(n.getImports());
+	}
+
+	public void visit(Node.TagDirective n) throws JasperException {
+            // Note: Most of the validation is done in TagFileProcessor
+            // when it created a TagInfo object from the
+            // tag file in which the directive appeared.
+        
+            // This method does additional processing to collect page info
+            
+	    Attributes attrs = n.getAttributes();
+	    for (int i = 0; attrs != null && i < attrs.getLength(); i++) {
+		String attr = attrs.getQName(i);
+		String value = attrs.getValue(i);
+
+		if ("language".equals(attr)) {
+		    if (pageInfo.getLanguage(false) == null) {
+			pageInfo.setLanguage(value, n, err, false);
+		    } else if (!pageInfo.getLanguage(false).equals(value)) {
+			err.jspError(n, "jsp.error.tag.conflict.language",
+				     pageInfo.getLanguage(false), value);
+		    }
+		} else if ("isELIgnored".equals(attr)) {
+		    if (pageInfo.getIsELIgnored() == null) {
+                        pageInfo.setIsELIgnored(value, n, err, false);
+		    } else if (!pageInfo.getIsELIgnored().equals(value)) {
+			err.jspError(n, "jsp.error.tag.conflict.iselignored",
+				     pageInfo.getIsELIgnored(), value);
+		    }
+		} else if ("pageEncoding".equals(attr)) {
+		    if (pageEncodingSeen) 
+			err.jspError(n, "jsp.error.tag.multi.pageencoding");
+		    pageEncodingSeen = true;
+		    n.getRoot().setPageEncoding(value);
+		}
+	    }
+
+	    // Attributes for imports for this node have been processed by
+	    // the parsers, just add them to pageInfo.
+	    pageInfo.addImports(n.getImports());
+	}
+
+	public void visit(Node.AttributeDirective n) throws JasperException {
+	    // Do nothing, since this attribute directive has already been
+	    // validated by TagFileProcessor when it created a TagInfo object
+	    // from the tag file in which the directive appeared
+	}
+
+	public void visit(Node.VariableDirective n) throws JasperException {
+	    // Do nothing, since this variable directive has already been
+	    // validated by TagFileProcessor when it created a TagInfo object
+	    // from the tag file in which the directive appeared
+	}
+
+        /*
+         * Compares page encodings specified in various places, and throws
+         * exception in case of page encoding mismatch.
+         *
+         * @param pageDirEnc The value of the pageEncoding attribute of the
+         * page directive
+         * @param pageDir The page directive node
+         *
+         * @throws JasperException in case of page encoding mismatch
+         */
+        private void comparePageEncodings(String pageDirEnc,
+                                          Node.PageDirective pageDir)
+                throws JasperException {
+
+            Node.Root root = pageDir.getRoot();
+            String configEnc = root.getJspConfigPageEncoding();
+
+            /*
+             * Compare the 'pageEncoding' attribute of the page directive with
+             * the encoding specified in the JSP config element whose URL
+             * pattern matches this page.
+             * Treat "UTF-16", "UTF-16BE", and "UTF-16LE" as identical.
+             */
+            if (configEnc != null && !pageDirEnc.equals(configEnc) 
+                    && (!pageDirEnc.startsWith("UTF-16")
+                        || !configEnc.startsWith("UTF-16"))) {
+                err.jspError(pageDir,
+                             "jsp.error.config_pagedir_encoding_mismatch",
+                             configEnc, pageDirEnc);
+            }
+
+            /*
+             * Compare the 'pageEncoding' attribute of the page directive with
+             * the encoding specified in the XML prolog (only for XML syntax,
+             * and only if JSP document contains XML prolog with encoding
+             * declaration).
+             * Treat "UTF-16", "UTF-16BE", and "UTF-16LE" as identical.
+             */
+	    if (root.isXmlSyntax() && root.isEncodingSpecifiedInProlog()) {
+		String pageEnc = root.getPageEncoding();
+                if (!pageDirEnc.equals(pageEnc) 
+                        && (!pageDirEnc.startsWith("UTF-16")
+                            || !pageEnc.startsWith("UTF-16"))) {
+                    err.jspError(pageDir,
+                                 "jsp.error.prolog_pagedir_encoding_mismatch",
+                                 pageEnc, pageDirEnc);
+                }
+            }
+        }
+    }
+
+    /**
+     * A visitor for validating nodes other than page directives
+     */
+    static class ValidateVisitor extends Node.Visitor {
+
+	private PageInfo pageInfo;
+	private ErrorDispatcher err;
+	private TagInfo tagInfo;
+        private ClassLoader loader;
+
+	private static final JspUtil.ValidAttribute[] jspRootAttrs = {
+            new JspUtil.ValidAttribute("xsi:schemaLocation"),
+	    new JspUtil.ValidAttribute("version", true) };
+
+	private static final JspUtil.ValidAttribute[] includeDirectiveAttrs = {
+	    new JspUtil.ValidAttribute("file", true) };
+
+	private static final JspUtil.ValidAttribute[] taglibDirectiveAttrs = {
+	    new JspUtil.ValidAttribute("uri"),
+	    new JspUtil.ValidAttribute("tagdir"),
+	    new JspUtil.ValidAttribute("prefix", true) };
+
+	private static final JspUtil.ValidAttribute[] includeActionAttrs = {
+	    new JspUtil.ValidAttribute("page", true, true),
+	    new JspUtil.ValidAttribute("flush") };
+
+	private static final JspUtil.ValidAttribute[] paramActionAttrs = {
+	    new JspUtil.ValidAttribute("name", true),
+	    new JspUtil.ValidAttribute("value", true, true) };
+
+	private static final JspUtil.ValidAttribute[] forwardActionAttrs = {
+	    new JspUtil.ValidAttribute("page", true, true) };
+
+	private static final JspUtil.ValidAttribute[] getPropertyAttrs = {
+	    new JspUtil.ValidAttribute("name", true),
+	    new JspUtil.ValidAttribute("property", true) };
+
+	private static final JspUtil.ValidAttribute[] setPropertyAttrs = {
+	    new JspUtil.ValidAttribute("name", true),
+	    new JspUtil.ValidAttribute("property", true),
+	    new JspUtil.ValidAttribute("value", false, true),
+	    new JspUtil.ValidAttribute("param") };
+
+	private static final JspUtil.ValidAttribute[] useBeanAttrs = {
+	    new JspUtil.ValidAttribute("id", true),
+	    new JspUtil.ValidAttribute("scope"),
+	    new JspUtil.ValidAttribute("class"),
+	    new JspUtil.ValidAttribute("type"),
+	    new JspUtil.ValidAttribute("beanName", false, true) };
+
+	private static final JspUtil.ValidAttribute[] plugInAttrs = {
+	    new JspUtil.ValidAttribute("type",true),
+	    new JspUtil.ValidAttribute("code", true),
+	    new JspUtil.ValidAttribute("codebase"),
+	    new JspUtil.ValidAttribute("align"),
+	    new JspUtil.ValidAttribute("archive"),
+	    new JspUtil.ValidAttribute("height", false, true),
+	    new JspUtil.ValidAttribute("hspace"),
+	    new JspUtil.ValidAttribute("jreversion"),
+	    new JspUtil.ValidAttribute("name"),
+	    new JspUtil.ValidAttribute("vspace"),
+	    new JspUtil.ValidAttribute("width", false, true),
+	    new JspUtil.ValidAttribute("nspluginurl"),
+	    new JspUtil.ValidAttribute("iepluginurl") };
+            
+        private static final JspUtil.ValidAttribute[] attributeAttrs = {
+            new JspUtil.ValidAttribute("name", true),
+            new JspUtil.ValidAttribute("trim") };
+            
+        private static final JspUtil.ValidAttribute[] invokeAttrs = {
+            new JspUtil.ValidAttribute("fragment", true),
+	    new JspUtil.ValidAttribute("var"),
+	    new JspUtil.ValidAttribute("varReader"),
+	    new JspUtil.ValidAttribute("scope") };
+
+        private static final JspUtil.ValidAttribute[] doBodyAttrs = {
+            new JspUtil.ValidAttribute("var"),
+	    new JspUtil.ValidAttribute("varReader"),
+	    new JspUtil.ValidAttribute("scope") };
+
+	private static final JspUtil.ValidAttribute[] jspOutputAttrs = {
+	    new JspUtil.ValidAttribute("omit-xml-declaration"),
+	    new JspUtil.ValidAttribute("doctype-root-element"),
+	    new JspUtil.ValidAttribute("doctype-public"),
+	    new JspUtil.ValidAttribute("doctype-system") };
+
+	/*
+	 * Constructor
+	 */
+	ValidateVisitor(Compiler compiler) {
+	    this.pageInfo = compiler.getPageInfo();
+	    this.err = compiler.getErrorDispatcher();
+	    this.tagInfo = compiler.getCompilationContext().getTagInfo();
+	    this.loader = compiler.getCompilationContext().getClassLoader();
+	}
+
+	public void visit(Node.JspRoot n) throws JasperException {
+	    JspUtil.checkAttributes("Jsp:root", n,
+				    jspRootAttrs, err);
+	    String version = n.getTextAttribute("version");
+	    if (!version.equals("1.2") && !version.equals("2.0")) {
+		err.jspError(n, "jsp.error.jsproot.version.invalid", version);
+	    }
+	    visitBody(n);
+	}
+
+	public void visit(Node.IncludeDirective n) throws JasperException {
+            JspUtil.checkAttributes("Include directive", n,
+                                    includeDirectiveAttrs, err);
+	    visitBody(n);
+	}
+
+	public void visit(Node.TaglibDirective n) throws JasperException {
+            JspUtil.checkAttributes("Taglib directive", n,
+                                    taglibDirectiveAttrs, err);
+	    // Either 'uri' or 'tagdir' attribute must be specified
+	    String uri = n.getAttributeValue("uri");
+	    String tagdir = n.getAttributeValue("tagdir");
+	    if (uri == null && tagdir == null) {
+		err.jspError(n, "jsp.error.taglibDirective.missing.location");
+	    }
+	    if (uri != null && tagdir != null) {
+		err.jspError(n, "jsp.error.taglibDirective.both_uri_and_tagdir");
+	    }
+	}
+
+	public void visit(Node.ParamAction n) throws JasperException {
+            JspUtil.checkAttributes("Param action", n,
+                                    paramActionAttrs, err);
+	    // make sure the value of the 'name' attribute is not a
+	    // request-time expression
+	    throwErrorIfExpression(n, "name", "jsp:param");
+	    n.setValue(getJspAttribute("value", null, null,
+				       n.getAttributeValue("value"),
+                                       java.lang.String.class,
+				       n, false));
+            visitBody(n);
+	}
+
+	public void visit(Node.ParamsAction n) throws JasperException {
+	    // Make sure we've got at least one nested jsp:param
+            Node.Nodes subElems = n.getBody();
+            if (subElems == null) {
+		err.jspError(n, "jsp.error.params.emptyBody");
+	    }
+            visitBody(n);
+	}
+
+	public void visit(Node.IncludeAction n) throws JasperException {
+            JspUtil.checkAttributes("Include action", n,
+                                    includeActionAttrs, err);
+	    n.setPage(getJspAttribute("page", null, null,
+				      n.getAttributeValue("page"), 
+                                      java.lang.String.class, n, false));
+	    visitBody(n);
+        };
+
+	public void visit(Node.ForwardAction n) throws JasperException {
+            JspUtil.checkAttributes("Forward", n,
+                                    forwardActionAttrs, err);
+	    n.setPage(getJspAttribute("page", null, null,
+				      n.getAttributeValue("page"), 
+                                      java.lang.String.class, n, false));
+	    visitBody(n);
+	}
+
+	public void visit(Node.GetProperty n) throws JasperException {
+            JspUtil.checkAttributes("GetProperty", n,
+                                    getPropertyAttrs, err);
+	}
+
+	public void visit(Node.SetProperty n) throws JasperException {
+            JspUtil.checkAttributes("SetProperty", n,
+                                    setPropertyAttrs, err);
+	    String name = n.getTextAttribute("name");
+	    String property = n.getTextAttribute("property");
+	    String param = n.getTextAttribute("param");
+	    String value = n.getAttributeValue("value");
+
+            n.setValue(getJspAttribute("value", null, null, value, 
+                java.lang.Object.class, n, false));
+
+            boolean valueSpecified = n.getValue() != null;
+
+	    if ("*".equals(property)) { 
+                if (param != null || valueSpecified)
+		    err.jspError(n, "jsp.error.setProperty.invalid");
+		
+            } else if (param != null && valueSpecified) {
+		err.jspError(n, "jsp.error.setProperty.invalid");
+	    }
+            
+            visitBody(n);
+	}
+
+	public void visit(Node.UseBean n) throws JasperException {
+            JspUtil.checkAttributes("UseBean", n,
+                                    useBeanAttrs, err);
+
+	    String name = n.getTextAttribute ("id");
+	    String scope = n.getTextAttribute ("scope");
+	    JspUtil.checkScope(scope, n, err);
+	    String className = n.getTextAttribute ("class");
+	    String type = n.getTextAttribute ("type");
+	    BeanRepository beanInfo = pageInfo.getBeanRepository();
+
+	    if (className == null && type == null)
+		err.jspError(n, "jsp.error.usebean.missingType");
+
+	    if (beanInfo.checkVariable(name))
+		err.jspError(n, "jsp.error.usebean.duplicate");
+
+	    if ("session".equals(scope) && !pageInfo.isSession())
+		err.jspError(n, "jsp.error.usebean.noSession");
+
+	    Node.JspAttribute jattr
+		= getJspAttribute("beanName", null, null,
+				  n.getAttributeValue("beanName"),
+				  java.lang.String.class, n, false);
+	    n.setBeanName(jattr);
+	    if (className != null && jattr != null)
+		err.jspError(n, "jsp.error.usebean.notBoth");
+
+	    if (className == null)
+		className = type;
+
+	    beanInfo.addBean(n, name, className, scope);
+
+	    visitBody(n);
+	}
+
+	public void visit(Node.PlugIn n) throws JasperException {
+            JspUtil.checkAttributes("Plugin", n, plugInAttrs, err);
+
+	    throwErrorIfExpression(n, "type", "jsp:plugin");
+	    throwErrorIfExpression(n, "code", "jsp:plugin");
+	    throwErrorIfExpression(n, "codebase", "jsp:plugin");
+	    throwErrorIfExpression(n, "align", "jsp:plugin");
+	    throwErrorIfExpression(n, "archive", "jsp:plugin");
+	    throwErrorIfExpression(n, "hspace", "jsp:plugin");
+	    throwErrorIfExpression(n, "jreversion", "jsp:plugin");
+	    throwErrorIfExpression(n, "name", "jsp:plugin");
+	    throwErrorIfExpression(n, "vspace", "jsp:plugin");
+	    throwErrorIfExpression(n, "nspluginurl", "jsp:plugin");
+	    throwErrorIfExpression(n, "iepluginurl", "jsp:plugin");
+
+	    String type = n.getTextAttribute("type");
+	    if (type == null)
+		err.jspError(n, "jsp.error.plugin.notype");
+	    if (!type.equals("bean") && !type.equals("applet"))
+		err.jspError(n, "jsp.error.plugin.badtype");
+	    if (n.getTextAttribute("code") == null)
+		err.jspError(n, "jsp.error.plugin.nocode");
+            
+	    Node.JspAttribute width
+		= getJspAttribute("width", null, null,
+				  n.getAttributeValue("width"), 
+                                  java.lang.String.class, n, false);
+	    n.setWidth( width );
+            
+	    Node.JspAttribute height
+		= getJspAttribute("height", null, null,
+				  n.getAttributeValue("height"), 
+                                  java.lang.String.class, n, false);
+	    n.setHeight( height );
+
+	    visitBody(n);
+	}
+
+	public void visit(Node.NamedAttribute n) throws JasperException {
+	    JspUtil.checkAttributes("Attribute", n,
+				    attributeAttrs, err);
+            visitBody(n);
+	}
+        
+	public void visit(Node.JspBody n) throws JasperException {
+            visitBody(n);
+	}
+        
+	public void visit(Node.Declaration n) throws JasperException {
+	    if (pageInfo.isScriptingInvalid()) {
+		err.jspError(n.getStart(), "jsp.error.no.scriptlets");
+	    }
+	}
+
+        public void visit(Node.Expression n) throws JasperException {
+	    if (pageInfo.isScriptingInvalid()) {
+		err.jspError(n.getStart(), "jsp.error.no.scriptlets");
+	    }
+	}
+
+        public void visit(Node.Scriptlet n) throws JasperException {
+	    if (pageInfo.isScriptingInvalid()) {
+		err.jspError(n.getStart(), "jsp.error.no.scriptlets");
+	    }
+	}
+
+	public void visit(Node.ELExpression n) throws JasperException {
+            if ( !pageInfo.isELIgnored() ) {
+		String expressions = "${" + new String(n.getText()) + "}";
+		ELNode.Nodes el = ELParser.parse(expressions);
+		validateFunctions(el, n);
+                JspUtil.validateExpressions(
+                    n.getStart(),
+		    expressions,
+                    java.lang.String.class, // XXX - Should template text 
+                                            // always evaluate to String?
+                    getFunctionMapper(el),
+                    err);
+		n.setEL(el);
+            }
+        }
+
+	public void visit(Node.UninterpretedTag n) throws JasperException {
+            if (n.getNamedAttributeNodes().size() != 0) {
+		err.jspError(n, "jsp.error.namedAttribute.invalidUse");
+            }
+
+	    Attributes attrs = n.getAttributes();
+	    if (attrs != null) {
+		int attrSize = attrs.getLength();
+		Node.JspAttribute[] jspAttrs = new Node.JspAttribute[attrSize];
+		for (int i=0; i < attrSize; i++) {
+		    jspAttrs[i] = getJspAttribute(attrs.getQName(i),
+						  attrs.getURI(i),
+						  attrs.getLocalName(i),
+						  attrs.getValue(i),
+						  java.lang.Object.class,
+						  n,
+						  false);
+		}
+		n.setJspAttributes(jspAttrs);
+	    }
+
+	    visitBody(n);
+        }
+
+	public void visit(Node.CustomTag n) throws JasperException {
+
+	    TagInfo tagInfo = n.getTagInfo();
+	    if (tagInfo == null) {
+		err.jspError(n, "jsp.error.missing.tagInfo", n.getQName());
+	    }
+
+	    /*
+	     * The bodyconet of a SimpleTag cannot be JSP.
+	     */
+	    if (n.implementsSimpleTag() &&
+                tagInfo.getBodyContent().equalsIgnoreCase(TagInfo.BODY_CONTENT_JSP)) {
+                err.jspError(n, "jsp.error.simpletag.badbodycontent",
+                        tagInfo.getTagClassName());
+	    }
+
+	    /*
+	     * If the tag handler declares in the TLD that it supports dynamic
+	     * attributes, it also must implement the DynamicAttributes
+	     * interface.
+	     */
+	    if (tagInfo.hasDynamicAttributes()
+		    && !n.implementsDynamicAttributes()) {
+		err.jspError(n, "jsp.error.dynamic.attributes.not.implemented",
+			     n.getQName());
+	    }
+
+	    /*
+	     * Make sure all required attributes are present, either as
+             * attributes or named attributes (<jsp:attribute>).
+ 	     * Also make sure that the same attribute is not specified in
+	     * both attributes or named attributes.
+	     */
+	    TagAttributeInfo[] tldAttrs = tagInfo.getAttributes();
+	    String customActionUri = n.getURI();
+	    Attributes attrs = n.getAttributes();
+	    int attrsSize = (attrs == null) ? 0 : attrs.getLength();
+	    for (int i=0; i<tldAttrs.length; i++) {
+		String attr = null;
+		if (attrs != null) {
+		    attr = attrs.getValue(tldAttrs[i].getName());
+		    if (attr == null) {
+			attr = attrs.getValue(customActionUri,
+					      tldAttrs[i].getName());
+		    }
+		}
+		Node.NamedAttribute na =
+			n.getNamedAttributeNode(tldAttrs[i].getName());
+		
+		if (tldAttrs[i].isRequired() && attr == null && na == null) {
+		    err.jspError(n, "jsp.error.missing_attribute",
+				 tldAttrs[i].getName(), n.getLocalName());
+		}
+		if (attr != null && na != null) {
+		    err.jspError(n, "jsp.error.duplicate.name.jspattribute",
+			tldAttrs[i].getName());
+		}
+	    }
+
+            Node.Nodes naNodes = n.getNamedAttributeNodes();
+	    int jspAttrsSize = naNodes.size() + attrsSize;
+	    Node.JspAttribute[] jspAttrs = null;
+	    if (jspAttrsSize > 0) {
+		jspAttrs = new Node.JspAttribute[jspAttrsSize];
+	    }
+	    Hashtable tagDataAttrs = new Hashtable(attrsSize);
+
+	    checkXmlAttributes(n, jspAttrs, tagDataAttrs);
+            checkNamedAttributes(n, jspAttrs, attrsSize, tagDataAttrs);
+
+	    TagData tagData = new TagData(tagDataAttrs);
+
+	    // JSP.C1: It is a (translation time) error for an action that
+	    // has one or more variable subelements to have a TagExtraInfo
+	    // class that returns a non-null object.
+	    TagExtraInfo tei = tagInfo.getTagExtraInfo();
+	    if (tei != null
+		    && tei.getVariableInfo(tagData) != null
+		    && tei.getVariableInfo(tagData).length > 0
+		    && tagInfo.getTagVariableInfos().length > 0) {
+		err.jspError("jsp.error.non_null_tei_and_var_subelems",
+			     n.getQName());
+	    }
+
+	    n.setTagData(tagData);
+	    n.setJspAttributes(jspAttrs);
+
+	    visitBody(n);
+	}
+
+	public void visit(Node.JspElement n) throws JasperException {
+
+	    Attributes attrs = n.getAttributes();
+	    if (attrs == null) {
+		err.jspError(n, "jsp.error.jspelement.missing.name");
+	    }
+	    int xmlAttrLen = attrs.getLength();
+
+            Node.Nodes namedAttrs = n.getNamedAttributeNodes();
+
+	    // XML-style 'name' attribute, which is mandatory, must not be
+	    // included in JspAttribute array
+	    int jspAttrSize = xmlAttrLen-1 + namedAttrs.size();
+
+	    Node.JspAttribute[] jspAttrs = new Node.JspAttribute[jspAttrSize];
+	    int jspAttrIndex = 0;
+
+	    // Process XML-style attributes
+	    for (int i=0; i<xmlAttrLen; i++) {
+		if ("name".equals(attrs.getLocalName(i))) {
+		    n.setNameAttribute(getJspAttribute(attrs.getQName(i),
+						       attrs.getURI(i),
+						       attrs.getLocalName(i),
+						       attrs.getValue(i),
+						       java.lang.String.class,
+						       n,
+						       false));
+		} else {
+		    if (jspAttrIndex<jspAttrSize) {
+			jspAttrs[jspAttrIndex++]
+			    = getJspAttribute(attrs.getQName(i),
+					      attrs.getURI(i),
+					      attrs.getLocalName(i),
+					      attrs.getValue(i),
+					      java.lang.Object.class,
+					      n,
+					      false);
+		    }
+		}
+	    }
+	    if (n.getNameAttribute() == null) {
+		err.jspError(n, "jsp.error.jspelement.missing.name");
+	    }
+
+	    // Process named attributes
+	    for (int i=0; i<namedAttrs.size(); i++) {
+                Node.NamedAttribute na = (Node.NamedAttribute) namedAttrs.getNode(i);
+		jspAttrs[jspAttrIndex++] = new Node.JspAttribute(na, false);
+	    }
+
+	    n.setJspAttributes(jspAttrs);
+
+	    visitBody(n);
+	}
+
+	public void visit(Node.JspOutput n) throws JasperException {
+            JspUtil.checkAttributes("jsp:output", n, jspOutputAttrs, err);
+
+	    if (n.getBody() != null) {
+                err.jspError(n, "jsp.error.jspoutput.nonemptybody");
+	    }
+
+	    String omitXmlDecl = n.getAttributeValue("omit-xml-declaration");
+	    String doctypeName = n.getAttributeValue("doctype-root-element");
+	    String doctypePublic = n.getAttributeValue("doctype-public");
+	    String doctypeSystem = n.getAttributeValue("doctype-system");
+
+	    String omitXmlDeclOld = pageInfo.getOmitXmlDecl();
+	    String doctypeNameOld = pageInfo.getDoctypeName();
+	    String doctypePublicOld = pageInfo.getDoctypePublic();
+	    String doctypeSystemOld = pageInfo.getDoctypeSystem();
+
+	    if (omitXmlDecl != null && omitXmlDeclOld != null &&
+			!omitXmlDecl.equals(omitXmlDeclOld) ) {
+                err.jspError(n, "jsp.error.jspoutput.conflict",
+			"omit-xml-declaration", omitXmlDeclOld, omitXmlDecl);
+	    }
+
+	    if (doctypeName != null && doctypeNameOld != null &&
+			!doctypeName.equals(doctypeNameOld) ) {
+                err.jspError(n, "jsp.error.jspoutput.conflict",
+			"doctype-root-element", doctypeNameOld, doctypeName);
+	    }
+
+	    if (doctypePublic != null && doctypePublicOld != null &&
+			!doctypePublic.equals(doctypePublicOld) ) {
+                err.jspError(n, "jsp.error.jspoutput.conflict",
+			"doctype-public", doctypePublicOld, doctypePublic);
+	    }
+
+	    if (doctypeSystem != null && doctypeSystemOld != null &&
+			!doctypeSystem.equals(doctypeSystemOld) ) {
+                err.jspError(n, "jsp.error.jspoutput.conflict",
+			"doctype-system", doctypeSystemOld, doctypeSystem);
+	    }
+
+	    if (doctypeName == null && doctypeSystem != null ||
+		doctypeName != null && doctypeSystem == null) {
+		err.jspError(n, "jsp.error.jspoutput.doctypenamesystem");
+	    }
+
+	    if (doctypePublic != null && doctypeSystem == null) {
+		err.jspError(n, "jsp.error.jspoutput.doctypepulicsystem");
+	    }
+
+	    if (omitXmlDecl != null) {
+		pageInfo.setOmitXmlDecl(omitXmlDecl);
+	    }
+	    if (doctypeName != null) {
+		pageInfo.setDoctypeName(doctypeName);
+	    }
+	    if (doctypeSystem != null) {
+		pageInfo.setDoctypeSystem(doctypeSystem);
+	    }
+	    if (doctypePublic != null) {
+		pageInfo.setDoctypePublic(doctypePublic);
+	    }
+	}
+
+	public void visit(Node.InvokeAction n) throws JasperException {
+
+            JspUtil.checkAttributes("Invoke", n, invokeAttrs, err);
+
+	    String scope = n.getTextAttribute ("scope");
+	    JspUtil.checkScope(scope, n, err);
+
+	    String var = n.getTextAttribute("var");
+	    String varReader = n.getTextAttribute("varReader");
+	    if (scope != null && var == null && varReader == null) {
+		err.jspError(n, "jsp.error.missing_var_or_varReader");
+	    }
+	    if (var != null && varReader != null) {
+		err.jspError(n, "jsp.error.var_and_varReader");
+	    }
+	}
+
+	public void visit(Node.DoBodyAction n) throws JasperException {
+
+            JspUtil.checkAttributes("DoBody", n, doBodyAttrs, err);
+
+	    String scope = n.getTextAttribute ("scope");
+	    JspUtil.checkScope(scope, n, err);
+
+	    String var = n.getTextAttribute("var");
+	    String varReader = n.getTextAttribute("varReader");
+	    if (scope != null && var == null && varReader == null) {
+		err.jspError(n, "jsp.error.missing_var_or_varReader");
+	    }
+	    if (var != null && varReader != null) {
+		err.jspError(n, "jsp.error.var_and_varReader");
+	    }
+	}
+
+	/*
+	 * Make sure the given custom action does not have any invalid
+	 * attributes.
+	 *
+	 * A custom action and its declared attributes always belong to the
+	 * same namespace, which is identified by the prefix name of the
+	 * custom tag invocation. For example, in this invocation:
+	 *
+	 *     <my:test a="1" b="2" c="3"/>, the action
+	 *
+	 * "test" and its attributes "a", "b", and "c" all belong to the
+	 * namespace identified by the prefix "my". The above invocation would
+	 * be equivalent to:
+	 *
+	 *     <my:test my:a="1" my:b="2" my:c="3"/>
+	 *
+	 * An action attribute may have a prefix different from that of the
+	 * action invocation only if the underlying tag handler supports
+	 * dynamic attributes, in which case the attribute with the different
+	 * prefix is considered a dynamic attribute.
+	 */
+	private void checkXmlAttributes(Node.CustomTag n,
+					Node.JspAttribute[] jspAttrs,
+					Hashtable tagDataAttrs)
+	        throws JasperException {
+
+	    TagInfo tagInfo = n.getTagInfo();
+	    if (tagInfo == null) {
+		err.jspError(n, "jsp.error.missing.tagInfo", n.getQName());
+	    }
+	    TagAttributeInfo[] tldAttrs = tagInfo.getAttributes();
+	    Attributes attrs = n.getAttributes();
+
+	    for (int i=0; attrs != null && i<attrs.getLength(); i++) {
+		boolean found = false;
+		for (int j=0; tldAttrs != null && j<tldAttrs.length; j++) {
+		    if (attrs.getLocalName(i).equals(tldAttrs[j].getName())
+			    && (attrs.getURI(i) == null
+				|| attrs.getURI(i).length() == 0
+				|| attrs.getURI(i).equals(n.getURI()))) {
+			if (tldAttrs[j].canBeRequestTime()) {
+                            Class expectedType = String.class;
+                            try {
+                                String typeStr = tldAttrs[j].getTypeName();
+                                if( tldAttrs[j].isFragment() ) {
+                                    expectedType = JspFragment.class;
+                                }
+                                else if( typeStr != null ) {
+                                    expectedType = JspUtil.toClass(typeStr,
+								   loader);
+                                }
+                                jspAttrs[i]
+                                    = getJspAttribute(attrs.getQName(i),
+                                                      attrs.getURI(i),
+                                                      attrs.getLocalName(i),
+                                                      attrs.getValue(i),
+                                                      expectedType,
+                                                      n,
+                                                      false);
+                            } catch (ClassNotFoundException e) {
+                                err.jspError(n, 
+                                    "jsp.error.unknown_attribute_type",
+                                    tldAttrs[j].getName(), 
+                                    tldAttrs[j].getTypeName() );
+                            }
+			} else {
+			    // Attribute does not accept any expressions.
+			    // Make sure its value does not contain any.
+			    if (isExpression(n, attrs.getValue(i))) {
+                                err.jspError(n,
+				        "jsp.error.attribute.custom.non_rt_with_expr",
+					     tldAttrs[j].getName());
+			    }
+			    jspAttrs[i]
+				= new Node.JspAttribute(attrs.getQName(i),
+							attrs.getURI(i),
+							attrs.getLocalName(i),
+							attrs.getValue(i),
+							false,
+							null,
+							false);
+			}
+			if (jspAttrs[i].isExpression()) {
+			    tagDataAttrs.put(attrs.getQName(i),
+					     TagData.REQUEST_TIME_VALUE);
+			} else {
+			    tagDataAttrs.put(attrs.getQName(i),
+					     attrs.getValue(i));
+			}
+			found = true;
+			break;
+		    }
+		}
+		if (!found) {
+		    if (tagInfo.hasDynamicAttributes()) {
+			jspAttrs[i] = getJspAttribute(attrs.getQName(i),
+						      attrs.getURI(i),
+						      attrs.getLocalName(i),
+						      attrs.getValue(i),
+						      java.lang.Object.class,
+                                                      n,
+						      true);
+		    } else {
+			err.jspError(n, "jsp.error.bad_attribute",
+				     attrs.getQName(i), n.getLocalName());
+		    }
+		}
+	    }
+	}
+
+	/*
+	 * Make sure the given custom action does not have any invalid named
+	 * attributes
+	 */
+	private void checkNamedAttributes(Node.CustomTag n,
+					  Node.JspAttribute[] jspAttrs,
+					  int start,
+					  Hashtable tagDataAttrs)
+	        throws JasperException {
+
+	    TagInfo tagInfo = n.getTagInfo();
+	    if (tagInfo == null) {
+		err.jspError(n, "jsp.error.missing.tagInfo", n.getQName());
+	    }
+	    TagAttributeInfo[] tldAttrs = tagInfo.getAttributes();
+            Node.Nodes naNodes = n.getNamedAttributeNodes();
+
+	    for (int i=0; i<naNodes.size(); i++) {
+                Node.NamedAttribute na = (Node.NamedAttribute)
+		    naNodes.getNode(i);
+		boolean found = false;
+		for (int j=0; j<tldAttrs.length; j++) {
+		    /*
+		     * See above comment about namespace matches. For named
+		     * attributes, we use the prefix instead of URI as the
+		     * match criterion, because in the case of a JSP document,
+		     * we'd have to keep track of which namespaces are in scope
+		     * when parsing a named attribute, in order to determine
+		     * the URI that the prefix of the named attribute's name
+		     * matches to.
+		     */
+		    String attrPrefix = na.getPrefix();
+		    if (na.getLocalName().equals(tldAttrs[j].getName())
+			    && (attrPrefix == null || attrPrefix.length() == 0
+				|| attrPrefix.equals(n.getPrefix()))) {
+			jspAttrs[start + i] = new Node.JspAttribute(na, false);
+			NamedAttributeVisitor nav = null;
+			if (na.getBody() != null) {
+			    nav = new NamedAttributeVisitor();
+			    na.getBody().visit(nav);
+			}
+			if (nav != null && nav.hasDynamicContent()) {
+			    tagDataAttrs.put(na.getName(),
+					     TagData.REQUEST_TIME_VALUE);
+			} else {
+			    tagDataAttrs.put(na.getName(), na.getText());    
+			}
+			found = true;
+			break;
+		    }
+		}
+		if (!found) {
+		    if (tagInfo.hasDynamicAttributes()) {
+			jspAttrs[start + i] = new Node.JspAttribute(na, true);
+		    } else {
+			err.jspError(n, "jsp.error.bad_attribute",
+				     na.getName(), n.getLocalName());
+		    }
+		}
+	    }
+	}
+
+	/**
+	 * Preprocess attributes that can be expressions.  Expression
+	 * delimiters are stripped.
+         * <p>
+         * If value is null, checks if there are any
+         * NamedAttribute subelements in the tree node, and if so,
+         * constructs a JspAttribute out of a child NamedAttribute node.
+	 */
+	private Node.JspAttribute getJspAttribute(String qName,
+						  String uri,
+						  String localName,
+						  String value,
+                                                  Class expectedType,
+                                                  Node n,
+						  boolean dynamic)
+                throws JasperException {
+
+            Node.JspAttribute result = null;
+
+	    // XXX Is it an error to see "%=foo%" in non-Xml page?
+	    // (We won't see "<%=foo%> in xml page because '<' is not a
+	    // valid attribute value in xml).
+
+            if (value != null) {
+                if (n.getRoot().isXmlSyntax() && value.startsWith("%=")) {
+                    result = new Node.JspAttribute(
+                                        qName,
+					uri,
+					localName,
+					value.substring(2, value.length()-1),
+					true,
+					null,
+					dynamic);
+                }
+                else if(!n.getRoot().isXmlSyntax() && value.startsWith("<%=")) {
+                    result = new Node.JspAttribute(
+                                        qName,
+					uri,
+					localName,
+					value.substring(3, value.length()-2),
+					true,
+					null,
+					dynamic);
+                }
+                else {
+                    // The attribute can contain expressions but is not a
+                    // scriptlet expression; thus, we want to run it through 
+                    // the expression interpreter
+
+                    // validate expression syntax if string contains
+                    // expression(s)
+                    ELNode.Nodes el = ELParser.parse(value);
+                    if (el.containsEL() && !pageInfo.isELIgnored()) {
+	                validateFunctions(el, n);
+                        JspUtil.validateExpressions(
+                            n.getStart(),
+                            value, 
+                            expectedType, 
+                            getFunctionMapper(el),
+                            this.err);
+
+                        
+                        result = new Node.JspAttribute(qName, uri, localName,
+						       value, false, el,
+						       dynamic);
+                    } else {
+			value = value.replace(Constants.ESC, '$');
+                        result = new Node.JspAttribute(qName, uri, localName,
+						       value, false, null,
+						       dynamic);
+                    }
+                }
+            }
+            else {
+                // Value is null.  Check for any NamedAttribute subnodes
+                // that might contain the value for this attribute.
+                // Otherwise, the attribute wasn't found so we return null.
+
+                Node.NamedAttribute namedAttributeNode =
+                    n.getNamedAttributeNode( qName );
+                if( namedAttributeNode != null ) {
+                    result = new Node.JspAttribute(namedAttributeNode,
+						   dynamic);
+                }
+            }
+
+            return result;
+        }
+
+	/*
+	 * Checks to see if the given attribute value represents a runtime or
+	 * EL expression.
+	 */
+	private boolean isExpression(Node n, String value) {
+	    if ((n.getRoot().isXmlSyntax() && value.startsWith("%="))
+		    || (!n.getRoot().isXmlSyntax() && value.startsWith("<%="))
+   		    || (value.indexOf("${") != -1 && !pageInfo.isELIgnored()))
+		return true;
+	    else
+		return false;
+	}
+
+	/*
+	 * Throws exception if the value of the attribute with the given
+	 * name in the given node is given as an RT or EL expression, but the
+	 * spec requires a static value.
+	 */
+	private void throwErrorIfExpression(Node n, String attrName,
+					    String actionName)
+	            throws JasperException {
+	    if (n.getAttributes() != null
+		    && n.getAttributes().getValue(attrName) != null
+		    && isExpression(n, n.getAttributes().getValue(attrName))) {
+		err.jspError(n,
+			     "jsp.error.attribute.standard.non_rt_with_expr",
+			     attrName, actionName);
+	    }
+	}
+
+	private static class NamedAttributeVisitor extends Node.Visitor {
+	    private boolean hasDynamicContent;
+
+	    public void doVisit(Node n) throws JasperException {
+		if (!(n instanceof Node.JspText)
+		        && !(n instanceof Node.TemplateText)) {
+		    hasDynamicContent = true;
+		}
+		visitBody(n);
+	    }
+	    
+	    public boolean hasDynamicContent() {
+		return hasDynamicContent;
+	    }
+	}
+
+	private String findUri(String prefix, Node n) {
+
+	    for (Node p = n; p != null; p = p.getParent()) {
+		Attributes attrs = p.getTaglibAttributes();
+		if (attrs == null) {
+		    continue;
+		}
+		for (int i = 0; i < attrs.getLength(); i++) {
+		    String name = attrs.getQName(i);
+		    int k = name.indexOf(':');
+		    if (prefix == null && k < 0) {
+			// prefix not specified and a default ns found
+			return attrs.getValue(i);
+		    }   
+		    if (prefix != null && k >= 0 &&
+				prefix.equals(name.substring(k+1))) {
+			return attrs.getValue(i);
+		    }
+		}
+	    }
+	    return null;
+	}
+
+	/**
+	 * Validate functions in EL expressions
+	 */
+	private void validateFunctions(ELNode.Nodes el, Node n) 
+		throws JasperException {
+
+	    class FVVisitor extends ELNode.Visitor {
+
+		Node n;
+
+		FVVisitor(Node n) {
+		    this.n = n;
+		}
+
+		public void visit(ELNode.Function func) throws JasperException {
+		    String prefix = func.getPrefix();
+		    String function = func.getName();
+		    String uri = null;
+
+		    if (n.getRoot().isXmlSyntax()) {
+		        uri = findUri(prefix, n);
+		    } else if (prefix != null) {
+			uri = pageInfo.getURI(prefix);
+		    }
+
+		    if (uri == null) {
+			if (prefix == null) {
+			    err.jspError(n, "jsp.error.noFunctionPrefix",
+				function);
+			}
+			else {
+			    err.jspError(n,
+				"jsp.error.attribute.invalidPrefix", prefix);
+			}
+		    }
+		    TagLibraryInfo taglib = pageInfo.getTaglib(uri);
+		    FunctionInfo funcInfo = null;
+		    if (taglib != null) {
+			funcInfo = taglib.getFunction(function);
+		    }
+		    if (funcInfo == null) {
+			err.jspError(n, "jsp.error.noFunction", function);
+		    }
+		    // Skip TLD function uniqueness check.  Done by Schema ?
+		    func.setUri(uri);
+		    func.setFunctionInfo(funcInfo);
+		    processSignature(func);
+		}
+	    }
+
+	    el.visit(new FVVisitor(n));
+	}
+
+	private void processSignature(ELNode.Function func)
+		throws JasperException {
+	    func.setMethodName(getMethod(func));
+	    func.setParameters(getParameters(func));
+	}
+
+	/**
+	 * Get the method name from the signature.
+	 */
+	private String getMethod(ELNode.Function func)
+		throws JasperException {
+	    FunctionInfo funcInfo = func.getFunctionInfo();
+	    String signature = funcInfo.getFunctionSignature();
+	    
+	    int start = signature.indexOf(' ');
+	    if (start < 0) {
+		err.jspError("jsp.error.tld.fn.invalid.signature",
+			     func.getPrefix(), func.getName());
+	    }
+	    int end = signature.indexOf('(');
+	    if (end < 0) {
+		err.jspError("jsp.error.tld.fn.invalid.signature.parenexpected",
+			     func.getPrefix(), func.getName());
+	    }
+	    return signature.substring(start+1, end).trim();
+	}
+
+	/**
+	 * Get the parameters types from the function signature.
+	 * @return An array of parameter class names
+	 */
+	private String[] getParameters(ELNode.Function func) 
+		throws JasperException {
+	    FunctionInfo funcInfo = func.getFunctionInfo();
+	    String signature = funcInfo.getFunctionSignature();
+	    ArrayList params = new ArrayList();
+	    // Signature is of the form
+	    // <return-type> S <method-name S? '('
+	    // < <arg-type> ( ',' <arg-type> )* )? ')'
+	    int start = signature.indexOf('(') + 1;
+	    boolean lastArg = false;
+	    while (true) {
+		int p = signature.indexOf(',', start);
+		if (p < 0) {
+		    p = signature.indexOf(')', start);
+		    if (p < 0) {
+			err.jspError("jsp.error.tld.fn.invalid.signature",
+				     func.getPrefix(), func.getName());
+		    }
+		    lastArg = true;
+		}
+                String arg = signature.substring(start, p).trim();
+                if (!"".equals(arg)) {
+                    params.add(arg);
+                }
+		if (lastArg) {
+		    break;
+		}
+		start = p+1;
+	    }
+	    return (String[]) params.toArray(new String[params.size()]);
+	}
+
+	private FunctionMapper getFunctionMapper(ELNode.Nodes el)
+		throws JasperException {
+
+	    class ValidateFunctionMapper implements FunctionMapper {
+
+		private HashMap fnmap = new java.util.HashMap();
+		public void mapFunction(String fnQName, Method method) {
+		    fnmap.put(fnQName, method);
+		}
+
+		public Method resolveFunction(String prefix,
+					      String localName) {
+		    return (Method) this.fnmap.get(prefix + ":" + localName);
+		}
+	    }
+
+	    class MapperELVisitor extends ELNode.Visitor {
+		ValidateFunctionMapper fmapper;
+
+		MapperELVisitor(ValidateFunctionMapper fmapper) {
+		    this.fmapper = fmapper;
+		}
+
+		public void visit(ELNode.Function n) throws JasperException {
+
+		    Class c = null;
+		    Method method = null;
+		    try {
+			c = loader.loadClass(
+				n.getFunctionInfo().getFunctionClass());
+		    } catch (ClassNotFoundException e) {
+			err.jspError("jsp.error.function.classnotfound",
+				     n.getFunctionInfo().getFunctionClass(),
+				     n.getPrefix() + ':' + n.getName(),
+				     e.getMessage());
+		    }
+		    String paramTypes[] = n.getParameters();
+		    int size = paramTypes.length;
+		    Class params[] = new Class[size];
+		    int i = 0;
+		    try {
+			for (i = 0; i < size; i++) {
+			    params[i] = JspUtil.toClass(paramTypes[i], loader);
+			}
+			method = c.getDeclaredMethod(n.getMethodName(),
+						     params);
+		    } catch (ClassNotFoundException e) {
+			err.jspError("jsp.error.signature.classnotfound",
+				     paramTypes[i],
+				     n.getPrefix() + ':' + n.getName(),
+				     e.getMessage());
+		    } catch (NoSuchMethodException e ) {
+			err.jspError("jsp.error.noFunctionMethod",
+				     n.getMethodName(), n.getName(),
+				     c.getName());
+		    }
+		    fmapper.mapFunction(n.getPrefix() + ':' + n.getName(),
+					method);
+		}
+	    }
+
+	    ValidateFunctionMapper fmapper = new ValidateFunctionMapper();
+	    el.visit(new MapperELVisitor(fmapper));
+	    return fmapper;
+	}
+    } // End of ValidateVisitor
+
+    /**
+     * A visitor for validating TagExtraInfo classes of all tags
+     */
+    static class TagExtraInfoVisitor extends Node.Visitor {
+
+	private PageInfo pageInfo;
+	private ErrorDispatcher err;
+
+	/*
+	 * Constructor
+	 */
+	TagExtraInfoVisitor(Compiler compiler) {
+	    this.pageInfo = compiler.getPageInfo();
+	    this.err = compiler.getErrorDispatcher();
+	}
+
+	public void visit(Node.CustomTag n) throws JasperException {
+	    TagInfo tagInfo = n.getTagInfo();
+	    if (tagInfo == null) {
+		err.jspError(n, "jsp.error.missing.tagInfo", n.getQName());
+	    }
+
+	    ValidationMessage[] errors = tagInfo.validate(n.getTagData());
+            if (errors != null && errors.length != 0) {
+		StringBuffer errMsg = new StringBuffer();
+                errMsg.append("<h3>");
+                errMsg.append(Localizer.getMessage("jsp.error.tei.invalid.attributes",
+						   n.getQName()));
+                errMsg.append("</h3>");
+                for (int i=0; i<errors.length; i++) {
+                    errMsg.append("<p>");
+		    if (errors[i].getId() != null) {
+			errMsg.append(errors[i].getId());
+			errMsg.append(": ");
+		    }
+                    errMsg.append(errors[i].getMessage());
+                    errMsg.append("</p>");
+                }
+
+		err.jspError(n, errMsg.toString());
+            }
+
+	    visitBody(n);
+	}
+    }
+
+    public static void validate(Compiler compiler,
+				Node.Nodes page) throws JasperException {
+
+	/*
+	 * Visit the page/tag directives first, as they are global to the page
+	 * and are position independent.
+	 */
+	page.visit(new DirectiveVisitor(compiler));
+
+	// Determine the default output content type
+	PageInfo pageInfo = compiler.getPageInfo();
+	String contentType = pageInfo.getContentType();
+
+	if (contentType == null || contentType.indexOf("charset=") < 0) {
+	    boolean isXml = page.getRoot().isXmlSyntax();
+	    String defaultType;
+	    if (contentType == null) {
+		defaultType = isXml? "text/xml": "text/html";
+	    } else {
+		defaultType = contentType;
+	    }
+
+	    String charset = null;
+	    if (isXml) {
+		charset = "UTF-8";
+	    } else {
+		if (!page.getRoot().isDefaultPageEncoding()) {
+		    charset = page.getRoot().getPageEncoding();
+		}
+	    }
+
+	    if (charset != null) {
+		pageInfo.setContentType(defaultType + ";charset=" + charset);
+	    } else {
+		pageInfo.setContentType(defaultType);
+	    }
+	}
+
+	/*
+	 * Validate all other nodes.
+	 * This validation step includes checking a custom tag's mandatory and
+	 * optional attributes against information in the TLD (first validation
+	 * step for custom tags according to JSP.10.5).
+	 */
+	page.visit(new ValidateVisitor(compiler));
+
+	/*
+	 * Invoke TagLibraryValidator classes of all imported tags
+	 * (second validation step for custom tags according to JSP.10.5).
+	 */
+	validateXmlView(new PageDataImpl(page, compiler), compiler);
+
+	/*
+	 * Invoke TagExtraInfo method isValid() for all imported tags 
+	 * (third validation step for custom tags according to JSP.10.5).
+	 */
+	page.visit(new TagExtraInfoVisitor(compiler));
+
+    }
+
+
+    //*********************************************************************
+    // Private (utility) methods
+
+    /**
+     * Validate XML view against the TagLibraryValidator classes of all
+     * imported tag libraries.
+     */
+    private static void validateXmlView(PageData xmlView, Compiler compiler)
+	        throws JasperException {
+
+	StringBuffer errMsg = null;
+	ErrorDispatcher errDisp = compiler.getErrorDispatcher();
+
+	for (Iterator iter=compiler.getPageInfo().getTaglibs().iterator();
+	         iter.hasNext(); ) {
+
+	    Object o = iter.next();
+	    if (!(o instanceof TagLibraryInfoImpl))
+		continue;
+	    TagLibraryInfoImpl tli = (TagLibraryInfoImpl) o;
+
+	    ValidationMessage[] errors = tli.validate(xmlView);
+            if ((errors != null) && (errors.length != 0)) {
+                if (errMsg == null) {
+		    errMsg = new StringBuffer();
+		}
+                errMsg.append("<h3>");
+                errMsg.append(Localizer.getMessage("jsp.error.tlv.invalid.page",
+						   tli.getShortName(), compiler.getPageInfo().getJspFile()));
+                errMsg.append("</h3>");
+                for (int i=0; i<errors.length; i++) {
+		    if (errors[i] != null) {
+			errMsg.append("<p>");
+			errMsg.append(errors[i].getId());
+			errMsg.append(": ");
+			errMsg.append(errors[i].getMessage());
+			errMsg.append("</p>");
+		    }
+                }
+            }
+        }
+
+	if (errMsg != null) {
+            errDisp.jspError(errMsg.toString());
+	}
+    }
+}
+

Added: branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/tagplugin/TagPlugin.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/tagplugin/TagPlugin.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/tagplugin/TagPlugin.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,36 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tagplugin;
+
+/**
+ * This interface is to be implemented by the plugin author, to supply
+ * an alternate implementation of the tag handlers.  It can be used to
+ * specify the Java codes to be generated when a tag is invoked.
+ *
+ * An implementation of this interface must be registered in a file
+ * named "tagPlugins.xml" under WEB-INF.
+ */
+
+public interface TagPlugin {
+
+    /**
+     * Generate codes for a custom tag.
+     * @param ctxt a TagPluginContext for accessing Jasper functions
+     */
+    void doTag(TagPluginContext ctxt);
+}
+

Added: branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/tagplugin/TagPluginContext.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/tagplugin/TagPluginContext.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/compiler/tagplugin/TagPluginContext.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,123 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.tagplugin;
+
+
+/**
+ * This interface allows the plugin author to make inqueries about the
+ * properties of the current tag, and to use Jasper resources to generate
+ * direct Java codes in place of tag handler invocations.
+ */
+
+public interface TagPluginContext {
+    /**
+     * @return true if the body of the tag is scriptless.
+     */
+    boolean isScriptless();
+
+    /**
+     * @param attribute Name of the attribute
+     * @return true if the attribute is specified in the tag
+     */
+    boolean isAttributeSpecified(String attribute);
+
+    /**
+     * @return An unique temporary variable name that the plugin can use.
+     */
+    String getTemporaryVariableName();
+
+    /**
+     * Generate an import statement
+     * @param s Name of the import class, '*' allowed.
+     */
+    void generateImport(String s);
+
+    /**
+     * Generate a declaration in the of the generated class.  This can be
+     * used to declare an innter class, a method, or a class variable.
+     * @param id An unique ID identifying the declaration.  It is not
+     *           part of the declaration, and is used to ensure that the
+     *           declaration will only appear once.  If this method is
+     *           invoked with the same id more than once in the translation
+     *           unit, only the first declaration will be taken.
+     * @param text The text of the declaration.
+     **/
+    void generateDeclaration(String id, String text);
+
+    /**
+     * Generate Java source codes
+     */
+    void generateJavaSource(String s);
+
+    /**
+     * @return true if the attribute is specified and its value is a
+     *         translation-time constant.
+     */
+    boolean isConstantAttribute(String attribute);
+
+    /**
+     * @return A string that is the value of a constant attribute.  Undefined
+     *         if the attribute is not a (translation-time) constant.
+     *         null if the attribute is not specified.
+     */
+    String getConstantAttribute(String attribute);
+
+    /**
+     * Generate codesto evaluate value of a attribute in the custom tag
+     * The codes is a Java expression.
+     * NOTE: Currently cannot handle attributes that are fragments.
+     * @param attribute The specified attribute
+     */
+    void generateAttribute(String attribute);
+
+    /**
+     * Generate codes for the body of the custom tag
+     */
+    void generateBody();
+
+    /**
+     * Abandon optimization for this tag handler, and instruct
+     * Jasper to generate the tag handler calls, as usual.
+     * Should be invoked if errors are detected, or when the tag body
+     * is deemed too compilicated for optimization.
+     */
+    void dontUseTagPlugin();
+
+    /**
+     * Get the PluginContext for the parent of this custom tag.  NOTE:
+     * The operations available for PluginContext so obtained is limited
+     * to getPluginAttribute and setPluginAttribute, and queries (e.g.
+     * isScriptless().  There should be no calls to generate*().
+     * @return The pluginContext for the parent node.
+     *         null if the parent is not a custom tag, or if the pluginConxt
+     *         if not available (because useTagPlugin is false, e.g).
+     */
+    TagPluginContext getParentContext();
+
+    /**
+     * Associate the attribute with a value in the current tagplugin context.
+     * The plugin attributes can be used for communication among tags that
+     * must work together as a group.  See <c:when> for an example.
+     */
+    void setPluginAttribute(String attr, Object value);
+
+    /**
+     * Get the value of an attribute in the current tagplugin context.
+     */
+    Object getPluginAttribute(String attr);
+}
+

Added: branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/resources/LocalStrings.properties
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/resources/LocalStrings.properties	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/resources/LocalStrings.properties	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,410 @@
+# $Id: LocalStrings.properties 349479 2005-11-28 19:44:47Z yoavs $
+#
+# Default localized string information
+# Localized this the Default Locale as is en_US
+
+jsp.error.compiler=No Java compiler available
+jsp.error.bad.servlet.engine=Incorrect servlet engine version!
+jsp.error.no.scratch.dir=The JSP engine is not configured with a scratch dir.\
+\n Please add \"jsp.initparams=scratchdir=<dir-name>\" \
+\n in the servlets.properties file for this context.
+jsp.error.bad.scratch.dir=The scratchDir you specified: {0} is unusable.
+jsp.message.scratch.dir.is=Scratch dir for the JSP engine is: {0}
+jsp.message.parent_class_loader_is=Parent class loader is: {0}
+jsp.message.dont.modify.servlets=IMPORTANT: Do not modify the generated servlets
+jsp.error.not.impl.comments=Internal error: Comments not implemented
+jsp.error.not.impl.directives=Internal error: Directives not implemented
+jsp.error.not.impl.declarations=Internal error: Declarations not implemented
+jsp.error.not.impl.expressions=Internal error: Expressions not implemented
+jsp.error.not.impl.scriptlets=Internal error: Scriptlets not implemented
+jsp.error.not.impl.usebean=Internal error: useBean not implemented
+jsp.error.not.impl.getp=Internal error: getProperty not implemented
+jsp.error.not.impl.setp=Internal error: setProperty not implemented
+jsp.error.not.impl.plugin=Internal error: plugin not implemented
+jsp.error.not.impl.forward=Internal error: forward not implemented
+jsp.error.not.impl.include=Internal error: include not implemented
+jsp.error.unavailable=JSP has been marked unavailable
+jsp.error.usebean.missing.attribute=useBean: id attribute missing or misspelled
+jsp.error.usebean.missing.type=useBean ({0}): Either class or type attribute must be \
+specified: 
+jsp.error.usebean.duplicate=useBean: Duplicate bean name: {0}
+jsp.error.usebean.prohibited.as.session=Can't use as session bean {0} since it is prohibited \
+by jsp directive defined earlier: 
+jsp.error.usebean.not.both=useBean: Can't specify both class and beanName attribute: 
+jsp.error.usebean.bad.type.cast=useBean ({0}): Type ({1}) is not assignable from class ({2}) 
+jsp.error.invalid.scope=Illegal value of \'scope\' attribute: {0} (must be one of \"page\", \"request\", \"session\", or \"application\")
+jsp.error.classname=Can't determine classname from .class file
+jsp.warning.bad.type=Warning: bad type in .class file
+jsp.error.data.file.write=Error while writing data file
+jsp.error.page.invalid.buffer=Page directive: invalid buffer size
+jsp.error.page.conflict.contenttype=Page directive: illegal to have multiple occurrences of 'contentType' with different values (old: {0}, new: {1})
+jsp.error.page.invalid.contenttype=Page directive: invalid value for contentType
+jsp.error.page.conflict.session=Page directive: illegal to have multiple occurrences of 'session' with different values (old: {0}, new: {1})
+jsp.error.page.invalid.session=Page directive: invalid value for session
+jsp.error.page.conflict.buffer=Page directive: illegal to have multiple occurrences of 'buffer' with different values (old: {0}, new: {1})
+jsp.error.page.invalid.buffer=Page directive: invalid value for buffer
+jsp.error.page.conflict.autoflush=Page directive: illegal to have multiple occurrences of 'autoFlush' with different values (old: {0}, new: {1})
+jsp.error.page.invalid.autoflush=Page directive: invalid value for autoFlush
+jsp.error.page.conflict.isthreadsafe=Page directive: illegal to have multiple occurrences of 'isThreadSafe' with different values (old: {0}, new: {1})
+jsp.error.page.invalid.isthreadsafe=Page directive: invalid value for isThreadSafe
+jsp.error.page.conflict.info=Page directive: illegal to have multiple occurrences of 'info' with different values (old: {0}, new: {1})
+jsp.error.page.invalid.info=Page directive: invalid value for info
+jsp.error.page.conflict.iserrorpage=Page directive: illegal to have multiple occurrences of 'isErrorPage' with different values (old: {0}, new: {1})
+jsp.error.page.invalid.iserrorpage=Page directive: invalid value for isErrorPage
+jsp.error.page.conflict.errorpage=Page directive: illegal to have multiple occurrences of 'errorPage' with different values (old: {0}, new: {1})
+jsp.error.page.conflict.language=Page directive: illegal to have multiple occurrences of 'language' with different values (old: {0}, new: {1})
+jsp.error.tag.conflict.language=Tag directive: illegal to have multiple occurrences of 'language' with different values (old: {0}, new: {1})
+jsp.error.page.language.nonjava=Page directive: invalid language attribute
+jsp.error.tag.language.nonjava=Tag directive: invalid language attribute
+jsp.error.page.defafteruse.language=Page directive: can't define language after a scriptlet 
+jsp.error.page.nomapping.language=Page directive: No mapping for language: 
+jsp.error.page.conflict.extends=Page directive: illegal to have multiple occurrences of 'extends' with different values (old: {0}, new: {1})
+jsp.error.page.conflict.iselignored=Page directive: illegal to have multiple occurrences of 'isELIgnored' with different values (old: {0}, new: {1})
+jsp.error.tag.conflict.iselignored=Tag directive: illegal to have multiple occurrences of 'isELIgnored' with different values (old: {0}, new: {1})
+jsp.error.page.invalid.iselignored=Page directive: invalid value for isELIgnored
+jsp.error.tag.invalid.iselignored=Tag directive: invalid value for isELIgnored
+jsp.error.page.multi.pageencoding=Page directive must not have multiple occurrences of pageencoding
+jsp.error.tag.conflict.attr=Tag directive: illegal to have multiple occurrences of the attribute \"{0}\" with different values (old: {1}, new: {2})
+jsp.error.tag.multi.pageencoding=Tag directive must not have multiple occurrences of pageencoding
+jsp.error.page.bad_b_and_a_combo=Page directive: Illegal combination of buffer=\"none\" && autoFlush=\"false\"
+jsp.error.not.impl.taglib=Internal error: Tag extensions not implemented
+jsp.error.include.missing.file=Missing file argument to include
+jsp.error.include.bad.file=Bad file argument to include 
+jsp.error.include.exception=Unable to include {0}
+jsp.error.stream.closed=Stream closed
+jsp.error.invalid.forward=Invalid forward tag
+jsp.error.unknownException=Unhandled error! You might want to consider having an error page \
+to report such errors more gracefully
+jsp.error.invalid.directive=Invalid directive
+jsp.error.directive.istagfile={0} directive cannot be used in a tag file
+jsp.error.directive.isnottagfile={0} directive can only be used in a tag file
+jsp.error.tagfile.tld.name=The \"name\" attribute of the tag directive has a value {0} while the \"name\" tag of the \"tag-file\" element in the TLD is {1}
+jsp.error.action.istagfile={0} action cannot be used in a tag file
+jsp.error.action.isnottagfile={0} action can be used in tag files only
+jsp.error.unterminated=Unterminated {0} tag
+jsp.error.usebean.notinsamefile=useBean tag must begin and end in the same physical file
+jsp.error.loadclass.taghandler=Unable to load tag handler class \"{0}\" for tag \"{1}\"
+jsp.error.unable.compile=Unable to compile class for JSP
+jsp.error.unable.load=Unable to load class for JSP
+jsp.error.unable.rename=Unable to rename class file {0} to {1}
+jsp.error.mandatory.attribute={0}: Mandatory attribute {1} missing
+jsp.engine.info=Jasper JSP 2.0 Engine
+jsp.error.invalid.expression="{0}" contains invalid expression(s): {1}
+jsp.error.invalid.attribute={0} has invalid attribute: {1}
+jsp.error.usebean.class.notfound=Class: {0} not found
+jsp.error.file.cannot.read=Cannot read file: {0}
+jsp.error.file.already.registered=Recursive include of file {0}
+jsp.error.file.not.registered=file {0} not seen in include
+jsp.error.quotes.unterminated=Unterminated quotes
+jsp.error.attr.quoted=Attribute value should be quoted
+jsp.error.attr.novalue=Attribute {0} has no value
+jsp.error.tag.attr.unterminated=Unterminated tag attribute list
+jsp.error.param.noname=No name in PARAM tag
+jsp.error.param.novalue=No value in PARAM tag
+jsp.error.beans.nullbean=Attempted a bean operation on a null object.
+jsp.error.beans.nobeaninfo=No BeanInfo for the bean of type ''{0}'' could be found, the class likely does not exist.
+jsp.error.beans.introspection=An exception occurred while introspecting the read method of property ''{0}'' in a bean of type ''{1}'':\n{2}
+jsp.error.beans.nomethod=Cannot find a method to read property ''{0}'' in a bean of type ''{1}''
+jsp.error.beans.nomethod.setproperty=Can''t find a method to write property ''{0}'' of type ''{1}'' in a bean of type ''{2}''
+jsp.error.beans.noproperty=Cannot find any information on property ''{0}'' in a bean of type ''{1}''
+jsp.error.beans.setproperty.noindexset=Cannot set indexed property
+jsp.error.include.tag=Invalid jsp:include tag
+jsp.error.include.noflush=jsp:include needs to have \"flush=true\"
+jsp.error.include.badflush=jsp:include page=\"...\" flush=\"true\" is the only valid combination in JSP 1.0
+jsp.error.attempt_to_clear_flushed_buffer=Error: Attempt to clear a buffer that's already been flushed
+jsp.error.overflow=Error: JSP Buffer overflow
+jsp.error.paramexpected=Expecting \"jsp:param\" standard action with \"name\" and \"value\" attributes
+jsp.error.param.invalidUse=The jsp:param action must not be used outside the jsp:include, jsp:forward, or jsp:params elements
+jsp.error.params.invalidUse=jsp:params must be a direct child of jsp:plugin
+jsp.error.fallback.invalidUse=jsp:fallback must be a direct child of jsp:plugin
+jsp.error.namedAttribute.invalidUse=jsp:attribute must be the subelement of a standard or custom action
+jsp.error.jspbody.invalidUse=jsp:body must be the subelement of a standard or custom action
+jsp.error.closeindividualparam=param tag needs to be closed with \"/>\"
+jsp.error.closeparams=param tag needs to be closed with /params
+jsp.error.params.emptyBody=jsp:params must contain at least one nested jsp:param
+jsp.error.params.illegalChild=jsp:params must not have any nested elements other than jsp:param
+jsp.error.plugin.notype=type not declared in jsp:plugin
+jsp.error.plugin.badtype=Illegal value for 'type' attribute in jsp:plugin: must be 'bean' or 'applet'
+jsp.error.plugin.nocode=code not declared in jsp:plugin
+jsp.error.ise_on_clear=Illegal to clear() when buffer size == 0
+jsp.error.setproperty.beanNotFound=setProperty: Bean {0} not found
+jsp.error.getproperty.beanNotFound=getProperty: Bean {0} not found
+jsp.error.setproperty.ClassNotFound=setProperty: Class {0} not found
+# typo ?
+#jsp.error.setproperty.invalidSayntax=setProperty: can't have non-null value when property=*
+jsp.error.setproperty.invalidSyntax=setProperty: can't have non-null value when property=*
+jsp.error.setproperty.beanInfoNotFound=setproperty: beanInfo for bean {0} not found
+jsp.error.setproperty.paramOrValue=setProperty: either param or value can be present
+jsp.error.setproperty.arrayVal=setProperty: can't set array property {0} through a string constant value
+jsp.warning.keepgen=Warning: Invalid value for the initParam keepgenerated. Will use the default value of \"false\"
+jsp.warning.xpoweredBy=Warning: Invalid value for the initParam xpoweredBy. Will use the default value of \"false\"
+jsp.warning.enablePooling=Warning: Invalid value for the initParam enablePooling. Will use the default value of \"true\"
+jsp.warning.invalidTagPoolSize=Warning: Invalid value for the init parameter named tagPoolSize. Will use default size of {0}
+jsp.warning.mappedFile=Warning: Invalid value for the initParam mappedFile. Will use the default value of \"false\"
+jsp.warning.sendErrToClient=Warning: Invalid value for the initParam sendErrToClient. Will use the default value of \"false\"
+jsp.warning.classDebugInfo=Warning: Invalid value for the initParam classdebuginfo. Will use the default value of \"false\"
+jsp.warning.checkInterval=Warning: Invalid value for the initParam checkInterval. Will use the default value of \"300\" seconds
+jsp.warning.modificationTestInterval=Warning: Invalid value for the initParam modificationTestInterval. Will use the default value of \"4\" seconds
+jsp.warning.development=Warning: Invalid value for the initParam development. Will use the default value of \"true\"
+jsp.warning.fork=Warning: Invalid value for the initParam fork. Will use the default value of \"true\"
+jsp.warning.reloading=Warning: Invalid value for the initParam reloading. Will use the default value of \"true\"
+jsp.warning.dumpSmap=Warning: Invalid value for the initParam dumpSmap. Will use the default value of \"false\"
+jsp.warning.genchararray=Warning: Invalid value for the initParam genStrAsCharArray. Will use the default value of \"false\"
+jsp.warning.suppressSmap=Warning: Invalid value for the initParam suppressSmap. Will use the default value of \"false\"
+jsp.error.badtaglib=Unable to open taglibrary {0} : {1}
+jsp.error.badGetReader=Cannot create a reader when the stream is not buffered
+jsp.warning.unknown.element.in.taglib=Unknown element ({0}) in taglib
+jsp.warning.unknown.element.in.tag=Unknown element ({0}) in tag
+jsp.warning.unknown.element.in.tagfile=Unknown element ({0}) in tag-file
+jsp.warning.unknown.element.in.attribute=Unknown element ({0}) in attribute
+jsp.warning.unknown.element.in.variable=Unknown element ({0}) in variable
+jsp.warning.unknown.element.in.validator=Unknown element ({0}) in validator
+jsp.warning.unknown.element.in.initParam=Unknown element ({0}) in validator's init-param
+jsp.warning.unknown.element.in.function=Unknown element ({0}) in function
+jsp.error.more.than.one.taglib=More than one taglib in the TLD: {0}
+jsp.error.teiclass.instantiation=Failed to load or instantiate TagExtraInfo class: {0}
+jsp.error.non_null_tei_and_var_subelems=Tag {0} has one or more variable subelements and a TagExtraInfo class that returns one or more VariableInfo
+jsp.error.parse.error.in.TLD=Parse Error in the tag library descriptor: {0}
+jsp.error.unable.to.open.TLD=Unable to open the tag library descriptor: {0}
+jsp.buffer.size.zero=Buffer size <= 0
+jsp.error.file.not.found=File \"{0}\" not found
+jsp.message.copyinguri=Copying {0} into {1}
+jsp.message.htmlcomment=\nStripping Comment: \t{0}
+jsp.message.handling_directive=\nHandling Directive: {0}\t{1}
+jsp.message.handling_plugin=\nPlugin: {0}
+jsp.message.package_name_is=Package name is: {0}
+jsp.message.class_name_is=Class name is: {0}
+jsp.message.java_file_name_is=Java file name is: {0}
+jsp.message.class_file_name_is=Class file name is: {0}
+jsp.message.accepted=Accepted {0} at {1}
+jsp.message.adding_jar=Adding jar {0} to my classpath
+jsp.message.compiling_with=Compiling with: {0}
+jsp.message.template_text=template text
+jsp.error.missing_attribute=According to the TLD or the tag file, attribute {0} is mandatory for tag {1}
+jsp.error.bad_attribute=Attribute {0} invalid for tag {1} according to TLD
+jsp.error.tld.unable_to_read=Unable to read TLD \"{1}\" from JAR file \"{0}\": {2}
+jsp.error.tld.unable_to_get_jar=Unable to get JAR resource \"{0}\" containing TLD: {1}
+jsp.error.tld.missing_jar=Missing JAR resource \"{0}\" containing TLD
+jsp.error.webxml_not_found=Could not locate web.xml
+jsp.cmd_line.usage=Usage: jsptoservlet [-dd <path/to/outputDirectory>] [-keepgenerated] \
+<.jsp files>
+jsp.message.cp_is=Classpath {0} is: {1}
+jsp.error.unable.to_load_taghandler_class=Unable to load tag handler class {0} because of {1}
+jsp.error.unable.to_find_method=Unable to find setter method for attribute: {0}
+jsp.error.unable.to_convert_string=Unable to convert a String to {0} for attribute {1}
+jsp.error.unable.to_introspect=Unable to introspect on tag handler class: {0} because of {1}
+jsp.error.bad_tag=No tag \"{0}\" defined in tag library imported with prefix \"{1}\"
+jsp.error.xml.bad_tag=No tag \"{0}\" defined in tag library associated with uri \"{1}\"
+jsp.error.bad_string_Character=Cannot extract a Character from a zero length array
+jsp.error.bad_string_char=Cannot extract a char from a zero length array
+jsp.warning.compiler.class.cantcreate=Can't create an instance of specified compiler plugin class {0} due to {1}. Will default to Sun Java Compiler.
+jsp.warning.compiler.class.notfound=Specified compiler plugin class {0} not found. Will default to Sun Java Compiler.
+jsp.warning.compiler.path.notfound=Specified compiler path {0} not found. Will default to system PATH.
+jsp.error.jspc.uriroot_not_dir=The -uriroot option must specify a pre-existing directory
+jsp.error.jspc.missingTarget=Missing target: Must specify -webapp or -uriroot, or one or more JSP pages
+jsp.error.jspc.no_uriroot=The uriroot is not specified and cannot be located with the specified JSP file(s)
+jspc.implicit.uriRoot=uriRoot implicitly set to "{0}"
+jspc.usage=Usage: jspc <options> [--] <jsp files>\n\
+where jsp files is\n\
+\    -webapp <dir>      A directory containing a web-app, whose JSP pages\n\
+\                       will be processed recursively\n\
+or any number of\n\
+\    <file>             A file to be parsed as a JSP page\n\
+where options include:\n\
+\    -help              Print this help message\n\
+\    -v                 Verbose mode\n\
+\    -d <dir>           Output Directory (default -Djava.io.tmpdir)\n\
+\    -l                 Outputs the name of the JSP page upon failure\n\
+\    -s                 Outputs the name of the JSP page upon success\n\
+\    -p <name>          Name of target package (default org.apache.jsp)\n\
+\    -c <name>          Name of target class name (only applies to first JSP page)\n\
+\    -mapped            Generates separate write() calls for each HTML line in the JSP\n\
+\    -die[#]            Generates an error return code (#) on fatal errors (default 1)\n\
+\    -uribase <dir>     The uri directory compilations should be relative to\n\
+\                       (default "/")\n\
+\    -uriroot <dir>     Same as -webapp\n\
+\    -compile           Compiles generated servlets\n\
+\    -webinc <file>     Creates a partial servlet mappings in the file\n\
+\    -webxml <file>     Creates a complete web.xml in the file\n\
+\    -ieplugin <clsid>  Java Plugin classid for Internet Explorer\n\
+\    -classpath <path>  Overrides java.class.path system property\n\
+\    -xpoweredBy        Add X-Powered-By response header\n\
+\    -trimSpaces        Trim spaces in template text between actions, directives\n\
+\    -javaEncoding <enc> Set the encoding charset for Java classes (default UTF-8)\n\
+\    -source <version>   Set the -source argument to the compiler (default 1.4)\n\
+\    -target <version>   Set the -target argument to the compiler (default 1.4)\n\
+
+jspc.webxml.header=<?xml version="1.0" encoding="ISO-8859-1"?>\n\
+\n\
+<!DOCTYPE web-app\n\
+\    PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"\n\
+\    "http://java.sun.com/dtd/web-app_2_3.dtd">\n\
+<!--\n\
+Automatically created by Apache Jakarta Tomcat JspC.\n\
+-->\n\
+<web-app>\n\
+\n
+jspc.webxml.footer=\n\
+</web-app>\n\
+\n
+jspc.webinc.header=\n\
+<!--\n\
+Automatically created by Apache Jakarta Tomcat JspC.\n\
+Place this fragment in the web.xml before all icon, display-name,\n\
+description, distributable, and context-param elements.\n\
+-->\n
+jspc.webinc.footer=\n\
+<!--\n\
+All session-config, mime-mapping, welcome-file-list, error-page, taglib,\n\
+resource-ref, security-constraint, login-config, security-role,\n\
+env-entry, and ejb-ref elements should follow this fragment.\n\
+-->\n
+jspc.webinc.insertEnd=<!-- JSPC servlet mappings end -->
+jspc.webinc.insertStart=<!-- JSPC servlet mappings start -->
+jspc.error.jasperException=error-the file ''{0}'' generated the following parse exception: {1}
+jspc.error.generalException=ERROR-the file ''{0}'' generated the following general exception:
+jspc.error.fileDoesNotExist=The file argument ''{0}'' does not exist
+jspc.error.emptyWebApp=-webapp requires a trailing file argument
+jsp.error.library.invalid=JSP page is invalid according to library {0}: {1}
+jsp.error.tlvclass.instantiation=Failed to load or instantiate TagLibraryValidator class: {0}
+jsp.error.tlv.invalid.page=Validation error messages from TagLibraryValidator for {0} in {1}
+jsp.error.tei.invalid.attributes=Validation error messages from TagExtraInfo for {0}
+jsp.parser.sax.propertynotsupported=SAX property not supported: {0}
+jsp.parser.sax.propertynotrecognized=SAX property not recognized: {0}
+jsp.parser.sax.featurenotsupported=SAX feature not supported: {0}
+jsp.parser.sax.featurenotrecognized=SAX feature not recognized: {0}
+jsp.error.no.more.content=End of content reached while more parsing required: tag nesting error?
+jsp.error.parse.xml=XML parsing error on file {0}
+jsp.error.parse.xml.line=XML parsing error on file {0}: (line {1}, col {2})
+jsp.error.parse.xml.scripting.invalid.body=Body of {0} element must not contain any XML elements
+jsp.error.internal.tldinit=Unable to initialize TldLocationsCache: {0}
+jsp.error.internal.filenotfound=Internal Error: File {0} not found
+jsp.error.internal.evaluator_not_found=Internal error: unable to load expression evaluator
+jsp.error.parse.xml.invalidPublicId=Invalid PUBLIC ID: {0}
+jsp.error.include.flush.invalid.value=Invalid value for the flush attribute: {0}
+jsp.error.unsupported.encoding=Unsupported encoding: {0}
+tld.error.variableNotAllowed=It is an error for a tag that has one or more variable subelements to have a TagExtraInfo class that returns a non-null object.
+jsp.error.tldInWebDotXmlNotFound=Could not locate TLD {1} for URI {0} specified in web.xml
+jsp.error.taglibDirective.absUriCannotBeResolved=The absolute uri: {0} cannot be resolved in either web.xml or the jar files deployed with this application
+jsp.error.taglibDirective.missing.location=Neither \'uri\' nor \'tagdir\' attribute specified
+jsp.error.taglibDirective.both_uri_and_tagdir=Both \'uri\' and \'tagdir\' attributes specified
+jsp.error.invalid.tagdir=Tag file directory {0} does not start with \"/WEB-INF/tags\"
+jsp.error.unterminated.user.tag=Unterminated user-defined tag: ending tag {0} not found or incorrectly nested
+#jspx.error.templateDataNotInJspCdata=Validation Error: Element &lt;{0}&gt; cannot have template data. Template data must be encapsulated within a &lt;jsp:cdata&gt; element. [JSP1.2 PFD section 5.1.9]\nTemplate data in error: {1}
+jspx.error.templateDataNotInJspCdata=Validation Error: Element &lt;{0}&gt; cannot have template data. Template data must be encapsulated within a &lt;jsp:text&gt; element. [JSP1.2 PFD section 5.1.9]\nTemplate data in error: {1}
+#Error while processing taglib jar file {0}: {1}
+jsp.error.taglib.reserved.prefix=The taglib prefix {0} is reserved
+jsp.error.invalid.javaEncoding=Invalid java encodings. Tried {0} and then {1}. Both failed.
+jsp.error.needAlternateJavaEncoding=Default java encoding {0} is invalid on your java platform. An alternate can be specified via the 'javaEncoding' parameter of JspServlet.
+#Error when compiling, used for jsp line number error messages
+jsp.error.single.line.number=An error occurred at line: {0} in the jsp file: {1}
+jsp.error.multiple.line.number=\n\nAn error occurred between lines: {0} and {1} in the jsp file: {2}\n\n
+jsp.error.corresponding.servlet=Generated servlet error:\n
+jsp.error.empty.body.not.allowed=Empty body not allowed for {0}
+jsp.error.jspbody.required=Must use jsp:body to specify tag body for {0} if jsp:attribute is used.
+jsp.error.jspbody.emptybody.only=The {0} tag can only have jsp:attribute in its body.
+jsp.error.no.scriptlets=Scripting elements ( &lt;%!, &lt;jsp:declaration, &lt;%=, &lt;jsp:expression, &lt;%, &lt;jsp:scriptlet ) are disallowed here.
+jsp.error.internal.unexpected_node_type=Internal Error: Unexpected node type encountered
+jsp.error.tld.fn.invalid.signature=Invalid syntax for function signature in TLD.  Tag Library: {0}, Function: {1}
+jsp.error.tld.fn.duplicate.name=Duplicate function name {0} in tag library {1}
+jsp.error.tld.fn.invalid.signature.commaexpected=Invalid syntax for function signature in TLD.  Comma ',' expected.  Tag Library: {0}, Function: {1}.
+jsp.error.tld.fn.invalid.signature.parenexpected=Invalid syntax for function signature in TLD.  Parenthesis '(' expected.  Tag Library: {0}, Function: {1}.
+jsp.error.tld.mandatory.element.missing=Mandatory TLD element missing or empty: {0}
+jsp.error.dynamic.attributes.not.implemented=The {0} tag declares that it accepts dynamic attributes but does not implement the required interface
+jsp.error.nomatching.fragment=Cannot find an attribute directive (with name={0} and fragment=true) prior to the fragment directive.
+jsp.error.attribute.noequal=equal symbol expected
+jsp.error.attribute.noquote=quote symbol expected
+jsp.error.attribute.unterminated=attribute for {0} is not properly terminated
+jsp.error.missing.tagInfo=TagInfo object for {0} is missing from TLD
+jsp.error.fragmentwithtype=Cannot specify both 'fragment' and 'type' attributes.  If 'fragment' is present, 'type' is fixed as 'javax.servlet.jsp.tagext.JspFragment'
+jsp.error.fragmentwithrtexprvalue=Cannot specify both 'fragment' and 'rtexprvalue' attributes.  If 'fragment' is present, 'rtexprvalue' is fixed as 'true'
+jsp.error.fragmentWithDeclareOrScope=Both 'fragment' and 'declare' or 'scope' attributes specified in variable directive
+jsp.error.var_and_varReader=Only one of \'var\' or \'varReader\' may be specified
+jsp.error.missing_var_or_varReader=Missing \'var\' or \'varReader\' attribute
+jsp.warning.bad.urlpattern.propertygroup=Bad value {0} in the url-pattern subelement in web.xml
+jsp.error.unknown_attribute_type=Unknown attribute type ({1}) for attribute {0}.
+jsp.error.jspelement.missing.name=Mandatory XML-style \'name\' attribute missing
+jsp.error.xmlns.redefinition.notimplemented=Internal error: Attempt to redefine xmlns:{0}.  Redefinition of namespaces is not implemented.
+jsp.error.could.not.add.taglibraries=Could not add one or more tag libraries.
+jsp.error.duplicate.name.jspattribute=The attribute {0} specified in the standard or custom action also appears as the value of the name attribute in the enclosed jsp:attribute
+jsp.error.not.in.template={0} not allowed in a template text body.
+jsp.error.badStandardAction=Invalid standard action
+jsp.error.xml.badStandardAction=Invalid standard action: {0}
+jsp.error.tagdirective.badbodycontent=Invalid body-content ({0}) in tag directive
+jsp.error.simpletag.badbodycontent=The TLD for the class {0} specifies an invalid body-content (JSP) for a SimpleTag.
+jsp.error.config_pagedir_encoding_mismatch=Page-encoding specified in jsp-property-group ({0}) is different from that specified in page directive ({1})
+jsp.error.prolog_pagedir_encoding_mismatch=Page-encoding specified in XML prolog ({0}) is different from that specified in page directive ({1})
+jsp.error.prolog_config_encoding_mismatch=Page-encoding specified in XML prolog ({0}) is different from that specified in jsp-property-group ({1})
+jsp.error.attribute.custom.non_rt_with_expr=According to TLD or attribute directive in tag file, attribute {0} does not accept any expressions
+jsp.error.attribute.standard.non_rt_with_expr=The {0} attribute of the {1} standard action does not accept any expressions
+jsp.error.scripting.variable.missing_name=Unable to determine scripting variable name from attribute {0}
+jasper.error.emptybodycontent.nonempty=According to TLD, tag {0} must be empty, but is not
+jsp.error.tagfile.nameNotUnique=The value of {0} and the value of {1} in line {2} are the same.
+jsp.error.tagfile.nameFrom.noAttribute=Cannot find an attribute directive with a name attribute with a value \"{0}\", the value of this name-from-attribute attribute.
+jsp.error.tagfile.nameFrom.badAttribute=The attribute directive (declared in line {1} and whose name attribute is \"{0}\", the value of this name-from-attribute attribute) must be of type java.lang.String, is \"required\" and not a \"rtexprvalue\".
+jsp.error.page.noSession=Cannot access session scope in page that does not participate in any session
+jsp.error.usebean.noSession=Illegal for useBean to use session scope when JSP page declares (via page directive) that it does not participate in sessions
+jsp.error.xml.encodingByteOrderUnsupported = Given byte order for encoding \"{0}\" is not supported.
+jsp.error.xml.encodingDeclInvalid = Invalid encoding name \"{0}\".
+jsp.error.xml.encodingDeclRequired = The encoding declaration is required in the text declaration.
+jsp.error.xml.morePseudoAttributes = more pseudo attributes is expected.
+jsp.error.xml.noMorePseudoAttributes = no more pseudo attributes is allowed.
+jsp.error.xml.versionInfoRequired = The version is required in the XML declaration.
+jsp.error.xml.xmlDeclUnterminated = The XML declaration must end with \"?>\".
+jsp.error.xml.reservedPITarget = The processing instruction target matching \"[xX][mM][lL]\" is not allowed.
+jsp.error.xml.spaceRequiredInPI = White space is required between the processing instruction target and data.
+jsp.error.xml.invalidCharInContent = An invalid XML character (Unicode: 0x{0}) was found in the element content of the document.
+jsp.error.xml.spaceRequiredBeforeStandalone = White space is required before the encoding pseudo attribute in the XML declaration.
+jsp.error.xml.sdDeclInvalid = The standalone document declaration value must be \"yes\" or \"no\", not \"{0}\".
+jsp.error.xml.invalidCharInPI = An invalid XML character (Unicode: 0x{0}) was found in the processing instruction.
+jsp.error.xml.versionNotSupported = XML version \"{0}\" is not supported, only XML 1.0 is supported.
+jsp.error.xml.pseudoAttrNameExpected = a pseudo attribute name is expected.
+jsp.error.xml.expectedByte = Expected byte {0} of {1}-byte UTF-8 sequence.
+jsp.error.xml.invalidByte = Invalid byte {0} of {1}-byte UTF-8 sequence.
+jsp.error.xml.operationNotSupported = Operation \"{0}\" not supported by {1} reader.
+jsp.error.xml.invalidHighSurrogate = High surrogate bits in UTF-8 sequence must not exceed 0x10 but found 0x{0}.
+jsp.error.xml.invalidASCII = Byte \"{0}\" not 7-bit ASCII.
+jsp.error.xml.spaceRequiredBeforeEncodingInXMLDecl = White space is required before the encoding pseudo attribute in the XML declaration.
+jsp.error.xml.spaceRequiredBeforeEncodingInTextDecl = White space is required before the encoding pseudo attribute in the text declaration.
+jsp.error.xml.spaceRequiredBeforeVersionInTextDecl = White space is required before the version pseudo attribute in the text declaration.
+jsp.error.xml.spaceRequiredBeforeVersionInXMLDecl = White space is required before the version pseudo attribute in the XML declaration.
+jsp.error.xml.eqRequiredInXMLDecl = The '' = '' character must follow \"{0}\" in the XML declaration.
+jsp.error.xml.eqRequiredInTextDecl = The '' = '' character must follow \"{0}\" in the text declaration.
+jsp.error.xml.quoteRequiredInTextDecl = The value following \"{0}\" in the text declaration must be a quoted string.
+jsp.error.xml.quoteRequiredInXMLDecl = The value following \"{0}\" in the XML declaration must be a quoted string.
+jsp.error.xml.invalidCharInTextDecl = An invalid XML character (Unicode: 0x{0}) was found in the text declaration.
+jsp.error.xml.invalidCharInXMLDecl = An invalid XML character (Unicode: 0x{0}) was found in the XML declaration.
+jsp.error.xml.closeQuoteMissingInTextDecl = closing quote in the value following \"{0}\" in the text declaration is missing.
+jsp.error.xml.closeQuoteMissingInXMLDecl = closing quote in the value following \"{0}\" in the XML declaration is missing.
+jsp.error.xml.invalidHighSurrogate = High surrogate bits in UTF-8 sequence must not exceed 0x10 but found 0x{0}.
+jsp.error.multiple.jsp = Cannot have multiple specifications of 
+jsp.error.jspoutput.conflict=&lt;jsp:output&gt;: illegal to have multiple occurrences of \"{0}\" with different values (old: {1}, new: {2})
+jsp.error.jspoutput.doctypenamesystem=&lt;jsp:output&gt;: 'doctype-root-element' and 'doctype-system' attributes must appear together
+jsp.error.jspoutput.doctypepulicsystem=&lt;jsp:output&gt;: 'doctype-system' attribute must appear if 'doctype-public' attribute appears
+jsp.error.jspoutput.nonemptybody=&lt;jsp:output&gt; must not have a body
+jsp.error.jspoutput.invalidUse=&lt;jsp:output&gt; must not be used in standard syntax
+jsp.error.attributes.not.allowed = {0} must not have any attributes
+jsp.error.tagfile.badSuffix=Missing \".tag\" suffix in tag file path {0}
+jsp.error.tagfile.illegalPath=Illegal tag file path: {0}, must start with \"/WEB-INF/tags\" or \"/META-INF/tags\"
+jsp.error.plugin.wrongRootElement=Name of root element in {0} different from {1}
+jsp.error.attribute.invalidPrefix=The attribute prefix {0} does not correspond to any imported tag library
+jsp.error.nested.jspattribute=A jsp:attribute standard action cannot be nested within another jsp:attribute standard action
+jsp.error.nested.jspbody=A jsp:body standard action cannot be nested within another jsp:body or jsp:attribute standard action
+jsp.error.variable.either.name=Either name-given or name-from-attribute attribute must be specified in a variable directive
+jsp.error.variable.both.name=Cannot specify both name-given or name-from-attribute attributes in a variable directive
+jsp.error.variable.alias=Both or none of the name-from-attribute and alias attributes must be specified in a variable directive
+jsp.error.attribute.null_name=Null attribute name
+jsp.error.jsptext.badcontent=\'&lt;\', when appears in the body of &lt;jsp:text&gt;, must be encapsulated within a CDATA
+jsp.error.jsproot.version.invalid=Invalid version number: \"{0}\", must be \"1.2\" or \"2.0\"
+jsp.error.noFunctionPrefix=The function {0} must be used with a prefix when a default namespace is not specified
+jsp.error.noFunction=The function {0} cannot be located with the specified prefix
+jsp.error.noFunctionMethod=Method \"{0}\" for function \"{1}\" not found in class \"{2}\"
+jsp.error.function.classnotfound=The class {0} specified in TLD for the function {1} cannot be found: {2}
+jsp.error.signature.classnotfound=The class {0} specified in the method signature in TLD for the function {1} cannot be found. {2}
+jsp.error.text.has_subelement=&lt;jsp:text&gt; must not have any subelements
+jsp.error.data.file.read=Error reading file \"{0}\"
+jsp.error.prefix.refined=Attempt to redefine the prefix {0} to {1}, when it was already defined as {2} in the current scope.
+jsp.error.nested_jsproot=Nested &lt;jsp:root&gt;
+jsp.error.unbalanced.endtag=The end tag \"&lt;/{0}\" is unbalanced
+jsp.error.invalid.bean=The value for the useBean class attribute {0} is invalid.
+jsp.error.prefix.use_before_dcl=The prefix {0} specified in this tag directive has been previously used by an action in file {1} line {2}.

Added: branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/resources/LocalStrings_es.properties
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/resources/LocalStrings_es.properties	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/resources/LocalStrings_es.properties	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,408 @@
+# $Id: LocalStrings_es.properties 349479 2005-11-28 19:44:47Z yoavs $
+#
+# Default localized string information
+# Localized para Locale es_ES
+
+jsp.error.bad.servlet.engine=¡Versión incorrecta del motor servlet!
+jsp.error.no.scratch.dir=El motor JSP no tiene configurado un directorio de trabajo.\
+\n Añada \"jsp.initparams=scratchdir=<dir-name>\" \
+\n en el fichero servlets.properties para este contexto.
+jsp.error.bad.scratch.dir=El directorio de trabajo especificado: {0} no es utilizable.
+jsp.message.scratch.dir.is=El directorio de trabajo para el motor JSP es: {0}
+jsp.message.parent_class_loader_is=El cargador de clases es: {0}
+jsp.message.dont.modify.servlets=IMPORTANTE: No modifique los servlets generados
+jsp.error.not.impl.comments=Error Interno: Comments no implementado
+jsp.error.not.impl.directives=Error Interno: Directives no implementado
+jsp.error.not.impl.declarations=Error Interno: Declarations no implementado
+jsp.error.not.impl.expressions=Error Interno: Expressions no implementado
+jsp.error.not.impl.scriptlets=Error Interno: Scriptlets no implementado
+jsp.error.not.impl.useBean=Error Interno: useBean no implementado
+jsp.error.not.impl.getp=Error Interno: getProperty no implementado
+jsp.error.not.impl.setp=Error Interno: setProperty no implementado
+jsp.error.not.impl.plugin=Error Interno: plugin no implementado
+jsp.error.not.impl.forward=Error Interno: forward no implementado
+jsp.error.not.impl.include=Error Interno: include no implementado
+jsp.error.unavailable=JSP ha sido marcado como no disponible
+jsp.error.usebean.missing.attribute=useBean: falta atributo id o está mal digitado
+jsp.error.usebean.missing.type=useBean ({0}): Se debe de especificar atributo class o type:
+jsp.error.usebean.duplicate=useBean: Nombre de bean duplicado: {0}
+jsp.error.usebean.prohibited.as.session=No puedo usar como bean de sesión {0} ya que está prohibido \
+por directiva jsp definida previamente: 
+jsp.error.usebean.not.both=useBean: No puede especificar ambos atributos class y beanName: 
+jsp.error.usebean.bad.type.cast=useBean ({0}): Tipo ({1}) no es asignable desde clase ({2}) 
+jsp.error.invalid.scope=Valor ilegal de atributo \'scope\': {0} (debe de ser uno de \"page\", \"request\", \"session\", o \"application\")
+jsp.error.classname=No pude determinar el nombre de clase desde el fichero .class
+jsp.warning.bad.type=Aviso: tipo incorrecto en archivo .class
+jsp.error.data.file.write=Error mientras escribía el archivo de datos
+jsp.error.page.invalid.buffer=Directiva Page: medida de buffer inválida
+jsp.error.page.conflict.contenttype=Directiva Page: es ilegal tener múltiples ocurrencias de 'contentType' con valores distintos (viejo: {0}, nuevo: {1})
+jsp.error.page.invalid.contenttype=Directiva Page: valor incorrecto para contentType
+jsp.error.page.conflict.session=Directiva Page: es ilegal tener múltiples ocurrencias de 'session' con valores distintos (viejo: {0}, nuevo: {1})
+jsp.error.page.invalid.session=Directiva Page: valor incorrecto para session
+jsp.error.page.conflict.buffer=Directiva Page: es ilegal tener múltiples ocurrencias de 'buffer'con valores distintos (viejo: {0}, nuevo: {1})
+jsp.error.page.invalid.buffer=Directiva Page: valor incorrecto para buffer
+jsp.error.page.conflict.autoflush=Directiva Page: es ilegal tener múltiples ocurrencias de 'autoFlush' con valores distintos (viejo: {0}, nuevo: {1})
+jsp.error.page.invalid.autoflush==Directiva Page: valor incorrecto para autoFlush
+jsp.error.page.conflict.isthreadsafe=Directiva Page: es ilegal tener múltiples ocurrencias de 'isThreadSafe' con valores distintos (viejo: {0}, nuevo: {1})
+jsp.error.page.invalid.isthreadsafe==Directiva Page: valor incorrecto para isThreadSafe
+jsp.error.page.conflict.info=Directiva Page: es ilegal tener múltiples ocurrencias de 'info' con valores distintos (viejo: {0}, nuevo: {1})
+jsp.error.page.invalid.info==Directiva Page: valor incorrecto para info
+jsp.error.page.conflict.iserrorpage=Directiva Page: es ilegal tener múltiples ocurrencias de 'isErrorPage' con valores distintos (viejo: {0}, nuevo: {1})
+jsp.error.page.invalid.iserrorpage==Directiva Page: valor incorrecto para isErrorPage
+jsp.error.page.conflict.errorpage=Directiva Page: es ilegal tener múltiples ocurrencias de 'errorPage' con valores distintos (viejo: {0}, nuevo: {1})
+jsp.error.page.conflict.language=Directiva Page: es ilegal tener múltiples ocurrencias de 'language' con valores distintos (viejo: {0}, nuevo: {1})
+jsp.error.tag.conflict.language=Directiva Tag: es ilegal tener múltiples ocurrencias de 'language' con valores distintos (viejo: {0}, nuevo: {1})
+jsp.error.page.language.nonjava=Directiva Page: atributo language incorrecto
+jsp.error.tag.language.nonjava=Directiva Tag: atributo language incorrecto
+jsp.error.page.defafterusar.language=Directiva Page: No puede definir language tras un scriptlet 
+jsp.error.page.nomapping.language=Directiva Page: No hay mapeado para language: 
+jsp.error.page.conflict.extends=Directiva Page: es ilegal tener múltiples ocurrencias de 'extends' con valores distintos (viejo: {0}, nuevo: {1})
+jsp.error.page.conflict.iselignored=Directiva Page: es ilegal tener múltiples ocurrencias de 'isELIgnored' con valores distintos (viejo: {0}, nuevo: {1})
+jsp.error.tag.conflict.iselignored=Directiva Tag: es ilegal tener múltiples ocurrencias de 'isELIgnored' con valores distintos (viejo: {0}, nuevo: {1})
+jsp.error.page.invalid.iselignored=Directiva Page: valor inválido para isELIgnored
+jsp.error.tag.invalid.iselignored=Directiva Tag: valor incorrecto para isELIgnored
+jsp.error.page.multi.pageencoding=La directiva Page no debe de tener múltiples ocurrencias de pageencoding
+jsp.error.tag.conflict.attr=Directiva Tag: es ilegal tener múltiples ocurrencias del atributo \"{0}\" con valores distintos (viejo: {1}, nuevo: {2})
+jsp.error.tag.multi.pageencoding=La directiva Tag no debe de tener múltiples ocurrencias de pageencoding
+jsp.error.page.bad_b_and_a_combo=Directiva Page: Combinación ilegal de buffer=\"none\" y autoFlush=\"false\"
+jsp.error.not.impl.taglib=Error Interno: Tag extensions no implementado
+jsp.error.include.missing.file=No tiene argumento de nombre de fichero 
+jsp.error.include.bad.file=Argumento de nombre de fichero no válido
+jsp.error.include.exception=No se puede incluir {0}
+jsp.error.stream.closed=Stream cerrado
+jsp.error.invalid.forward=Tag forward no válido
+jsp.error.unknownException=¡Error no caturado!. Deberías de considerar el poner una página de error para avisar de los errores más elegantemente
+jsp.error.invalid.directive=Directiva no válida
+jsp.error.directive.istagfile=La Directiva {0} no puede usarse en archivo de tag
+jsp.error.directive.isnottagfile=La Directiva {0} sólo se puede usar en un archivo de tag
+jsp.error.tagfile.tld.name=El atributo \"name\" de la directiva tag tiene un valor {0} mientras que el tag \"name\" del elemento \"tag-file\" en el TLD es {1}
+jsp.error.action.istagfile=La acción {0} no se puede usar en un archivo tag
+jsp.error.action.isnottagfile=La acción {0} sólo se puede usar en archivos tag
+jsp.error.unterminated=Tag {0} no terminado
+jsp.error.usebean.notinsamefile=El Tag useBean debe de empezar y terminar en el mismo archivo físico
+jsp.error.loadclass.taghandler=No se puede cargar la clase {0}
+jsp.error.unable.compile=No se puede compilar la clase para JSP
+jsp.error.unable.load=No se puede cargar la clase para JSP
+jsp.error.unable.rename=No se puede renombrar el archivo de clase {0} a {1}
+jsp.error.mandatory.atributo={0}: atributo obligatorio {1} perdido
+jsp.engine.info=Motor Jasper JSP 2.0
+jsp.error.invalid.expression="{0}" contiene expresiones incorrectas: {1}
+jsp.error.invalid.attribute={0}: Atributo incorrecto, {1}
+jsp.error.usebean.class.notfound=Clase: {0} no hallada
+jsp.error.file.cannot.read=No se puede leer el archivo: {0}
+jsp.error.file.already.registered=El archivo {0} ya se ha visto, ¿podría ser un include recursivo?
+jsp.error.file.not.registered=Archivo {0} not visto en include
+jsp.error.quotes.unterminated=Comillas no terminadas
+jsp.error.attr.quoted=El valor del atributo debería ir entre comillas
+jsp.error.attr.novalue=Atributo {0} no tiene valor
+jsp.error.tag.attr.unterminated=Lista de atributos del tag no terminada
+jsp.error.param.noname=No hay nombre en el tag PARAM
+jsp.error.param.novalue=No hay valor en el tag PARAM
+jsp.error.beans.nullbean=Se ha intentado una operación de bean en un objeto nulo
+jsp.error.beans.nobeaninfo=No se puede encontrar BeanInfo para el bean  ''{0}'' seguramente la clase no existe
+jsp.error.beans.introspection=Una excepción ha tenido lugar mientras se leía el método de lectura de la propiedad ''{0}'' en un bean del tipo ''{1}'':\n{2}
+jsp.error.beans.nomethod=No puedo encontrar un método para leer la propiedad ''{0}'' en un bean del tipo ''{1}''
+jsp.error.beans.nomethod.setproperty=No puedo encontrar un método para escribir la propiedad ''{0}'' en un bean del tipo ''{2}''
+jsp.error.beans.noproperty=No puedo encontrar información de la propiedad ''{0}'' en un bean del tipo ''{1}''
+jsp.error.beans.setproperty.noindexset=No puedo poner la propiedad indexada
+jsp.error.include.tag=Tag jsp:include no válido
+jsp.error.include.noflush=jsp:include necesita tener \"flush=true\"
+jsp.error.include.badflush=jsp:include page=\"...\" flush=\"true\" es la única combinación válida en JSP 1.0
+jsp.error.attempt_to_clear_flushed_buffer=Error: Se ha intentado limpiar un buffer que ya había sido escrito
+jsp.error.overflow=Error:Buffer de JSP desbordado
+jsp.error.paramexpected=El tag \"param\" era esperado con los atributos \"name\" y \"value\" después del tag \"params\".
+jsp.error.param.invalidUse=La acción jsp:param no debe de ser usada fuera de los elementos jsp:include, jsp:forward o jsp:params
+jsp.error.params.invalidUse=jsp:params debe de ser un hijo directo de jsp:plugin
+jsp.error.fallback.invalidUse=jsp:fallback debe de ser un hijo directo de jsp:plugin
+jsp.error.namedAttribute.invalidUse=jsp:attribute debe de ser el subelemento de una acción estándar o de cliente
+jsp.error.jspbody.invalidUse=jsp:body debe de ser el subelemento de una acción estándar o de cliente
+jsp.error.closeindividualparam=El tag param necesita ser cerrado con \"/>\"
+jsp.error.closeparams=El tag param necesita ser cerrado con /params
+jsp.error.params.emptyBody=jsp:params debe de contener al menos un jsp:param anidado
+jsp.error.params.illegalChild=jsp:params no debe de contener elementos anidados que no sean jsp:param
+jsp.error.plugin.notype=Tipo no declarado en jsp:plugin
+jsp.error.plugin.badtype=Valor ilegal para atributo 'type' en jsp:plugin: debe de ser 'bean' o 'applet'
+jsp.error.plugin.nocode=Código no declarado en jsp:plugin
+jsp.error.ise_on_clear=Es ilegal usar clear() cuando el tamaño del buffer es cero
+jsp.error.setproperty.beanNotFound=setProperty: Bean {0} no encontrado
+jsp.error.getproperty.beanNotFound=getProperty: Bean {0} no encontrado
+jsp.error.setproperty.ClassNotFound=setProperty: clase {0} no encontrada
+# typo ?
+#jsp.error.setproperty.invalidSayntax=setProperty: can't have non-null value when property=*
+jsp.error.setproperty.invalidSyantax=setProperty: No puede haber un valor no nulo cuando se ha especificado property=*
+jsp.error.setproperty.beanInfoNotFound=setproperty: beanInfo para bean {0} no encontrado
+jsp.error.setproperty.paramOrValue=setProperty: O param o value pueden estar presentes
+jsp.error.setproperty.arrayVal=setProperty: No puede escribir en la propiedad de array {0} a través de una valor de cadena literal
+jsp.warning.keepgen=Aviso: valor incorrecto para el initParam keepgen. Se usará el valor por defecto de \"false\"
+jsp.warning.xpoweredBy=Aviso: valor incorrecto para el initParam xpoweredBy. Se usará el valor por defecto de \"false\"
+jsp.warning.enablePooling=Aviso: valor incorrecto para el initParam enablePooling. Se usará el valor por defecto de \"true\"
+jsp.warning.invalidTagPoolSize=Aviso: valor incorrecto para el parámetro init llamado tagPoolSize. Se usará la medida por defecto de {0}
+jsp.warning.mappedFile=Aviso: valor incorrecto para el initParam mappedFile. Se usará el valor por defecto de \"false\"
+jsp.warning.sendErrToClient=Aviso: valor incorrecto para el initParam sendErrToClient. Se usará el valor por defecto de \"false\"
+jsp.warning.classDebugInfo=Aviso: valor incorrecto para el initParam classdebuginfo. Se usará el valor por defecto de \"false\"
+jsp.warning.checkInterval=Aviso: valor incorrecto para el initParam checkInterval. Se usará el valor por defecto de \"300\" segundos
+jsp.warning.development=Aviso: valor incorrecto para el initParam development. Se usará el valor por defecto de \"true\"
+jsp.warning.fork=Aviso: valor incorrecto para el initParam fork. Se usará el valor por defecto de \"true\"
+jsp.warning.reloading=Aviso: valor incorrecto para el initParam reloading. Se usará el valor por defecto de \"true\"
+jsp.warning.dumpSmap=Aviso: valor incorrecto para el initParam dumpSmap. Se usará el valor por defecto de \"false\"
+jsp.warning.genchararray=Aviso: valor incorrecto para el initParam genStrAsCharArray. Se usará el valor por defecto de \"false\"
+jsp.warning.suppressSmap=Aviso: valor incorrecto para el initParam suppressSmap. Se usará el valor por defecto de \"false\"
+jsp.error.badtaglib=No se puede abrir la biblioteca de tags {0}: {1}
+jsp.error.badGetReader=No se puede crear un reader cuando el stream no tiene buffer
+jsp.warning.unknown.element.in.taglib=Elemento desconocido ({0}) en taglib
+jsp.warning.unknown.element.in.tag=Elemento desconocido ({0}) en tag
+jsp.warning.unknown.element.in.tagfile=Elemento desconocido ({0}) en tag-file
+jsp.warning.unknown.element.in.attribute=Elemento desconocido ({0}) en attribute
+jsp.warning.unknown.element.in.variable=Elemento desconocido ({0}) en variable
+jsp.warning.unknown.element.in.validator=Elemento desconocido ({0}) en validator
+jsp.warning.unknown.element.in.initParam=Elemento desconocido ({0}) en init-param de validator
+jsp.warning.unknown.element.in.function=Elemento desconocido ({0}) en function
+jsp.error.more.than.one.taglib=Más de una biblioteca de tags en el TLD: {0}
+jsp.error.teiclass.instantiation=No se puede cargar la clase TagExtraInfo llamada: {0}
+jsp.error.non_null_tei_and_var_subelems=Tag {0} tiene uno o más subelementos variable y una clase TagExtraInfo que devuelve una o más VariableInfo
+jsp.error.parse.error.in.TLD=Error de análisis en el descriptor de biblioteca de tags: {0}
+jsp.error.unable.to.open.TLD=No se puede abrir el descriptor de biblioteca de tags: {0}
+jsp.buffer.size.zero=Tamaño de buffer <= 0
+jsp.error.file.not.found=Archivo JSP \"{0}\" no encontrado
+jsp.message.copyinguri=Copiando {0} en {1}
+jsp.message.htmlcomment=\nQuitando comentario: \t{0}
+jsp.message.handling_directive=\nResolviendo directiva: {0}\t{1}
+jsp.message.handling_plugin=\nPlugin: {0}
+jsp.message.package_name_is=El Nombre del Package es: {0}
+jsp.message.class_name_is=El Nombre de la clase es: {0}
+jsp.message.java_file_name_is=El Nombre del Archivo Java es: {0}
+jsp.message.class_file_name_is=El Nombre del Archivo de clase es: {0}
+jsp.message.accepted=Aceptó {0} en {1}
+jsp.message.adding_jar=Añadiendo jar {0} a mi classpath
+jsp.message.compiling_with=Compilado con: {0}
+jsp.message.template_text=texto plantilla
+jsp.error.missing_attribute=De acuerdo con el TLD el atributo {0} es obligatorio para el tag {1}
+jsp.error.bad_attribute=El atributo {0} no es válido según el TLD especificado
+jsp.error.tld.unable_to_read=Imposible de leer TLD \"{1}\" desde archivo JAR \"{0}\": {2}
+jsp.error.tld.unable_to_get_jar=Imposible obtener recurso JAR \"{0}\" conteniendo TLD: {1}
+jsp.error.tld.missing_jar=Falta recurso JAR \"{0}\" conteniendo TLD
+jsp.error.webxml_not_found=No puedo localizar web.xml
+jsp.cmd_line.usage=Uso: jsptoservlet [-dd <ruta/a/DirectorioSalida>] [-keepgenerated] <Archivos .jsp>
+jsp.message.cp_is=Classpath {0} es: {1}
+jsp.error.unable.to_load_taghandler_class=No se puede cargar clase manejadora {0} del tag a causa de {1}
+jsp.error.unable.to_find_method=No se puede encontrar el método de escritura para el atributo: {0}
+jsp.error.unable.to_convert_string=No pude convertir un String a {0} para atributo {1}
+jsp.error.unable.to_introspect=No se puede hacer introspección en manejador de tag clase: {0} a causa de {1}
+jsp.error.bad_tag=No existe el tag {0} en la biblioteca importada con prefijo {1}
+jsp.error.xml.bad_tag=No se ha definido el tag \"{0}\" en la biblioteca tag asociada con uri \"{1}\"
+jsp.error.bad_string_Character=No puede extraer un Character desde un array de tamaño cero
+jsp.error.bad_string_char=No puede extraer un char desde un array de tamaño cero
+jsp.warning.compiler.class.cantcreate=No puedo crear una instancia de la clase especificada {0} de plugin del compilador debido a {1}. Se usará el compilador Java de Sun.
+jsp.warning.compiler.class.notfound=No puedo encontrar una instancia de la clase {0} de plugin de compilador. Se usará el compilador del Java de Sun.
+jsp.warning.compiler.path.notfound=Trayectoria del compilador especificado {0} no encontrada. Se usará el PATH del sistema.
+jsp.error.jspc.uriroot_not_dir=La opción -uriroot debe de especificar un directorio ya existente
+jsp.error.jspc.missingTarget=Falta target: Debe de especificar -webapp o -uriroot o una o más páginas JSP
+jsp.error.jspc.no_uriroot=No se ha especificado uriroot y no puede ser localizado en los archivos JSP especificados
+jspc.implicit.uriRoot=uriRoot implicitamente puesto a "{0}"
+jspc.usage=Uso: jspc <opciones> [--] <Archivos JSP>\n\
+donde <Archivos JSP> son:\n\
+\    -webapp <dir>      Un directorio conteniendo una web-app. Todas las\n\
+\                       páginas jsp serán compiladas recursivamente\n\
+o cualquier número de\n\
+\    <Archivo>          Un Archivo para ser interpretado como una página jsp\n\
+y donde <opciones> incluyen:\n\
+\    -help              Muestra este mensaje de ayuda\n\
+\    -v                 Modo detallado\n\
+\    -d <dir>           Directorio de salida\n\
+\    -l                 Muestra el nombre de la página JSP al ocurrir un fallo\n\
+\    -s                 Muestra el nombre de la página JSP al tener éxito\n\
+\    -p <name>          Nombre del package objetivo\n\
+\                       (por defecto org.apache.jsp)\n\
+\    -c <name>          Nombre de la clase objetivo\n\
+\                       (sólo se aplica a la primera página JSP)\n\
+\    -mapped            Genera llamadas separadas a write() para cada línea de\n\
+\                       HTML en el JSP\n\
+\    -die[#]            Genera un código de retorno de error (#) en errores\n\
+\                       fatales. (por defecto 1).\n\
+\    -uribase <dir>     El directorio uri de donde deben de partir las\n\
+\                       compilaciones. (por defecto "/")\n\
+\    -uriroot <dir>     Igual que -webapp\n\
+\    -compile           Compila los servlets generados\n\
+\    -webinc <file>     Crea unos mapeos parciales de servlet en el archivo\n\
+\    -webxml <file>     Crea un web.xml completo en el archivo.\n\
+\    -ieplugin <clsid>  Java Plugin classid para Internet Explorer\n\
+\    -classpath <path>  Pasa por alto la propiedad de sistema java.class.path\n\
+\    -xpoweredBy        Añade cabecera de respuesta  X-Powered-By\n\
+\    -trimSpaces        Trim spaces in template text between actions, directives\n\
+\    -javaEncoding <enc> Set the encoding charset for Java classes (default UTF-8)\n\
+\    -source <version>   Set the -source argument to the compiler (default 1.4)\n\
+\    -target <version>   Set the -target argument to the compiler (default 1.4)\n\
+
+jspc.webxml.header=<?xml version="1.0" encoding="ISO-8859-1"?>\n\
+\n\
+<!DOCTYPE web-app\n\
+\    PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"\n\
+\    "http://java.sun.com/dtd/web-app_2_3.dtd">\n\
+<!--\n\
+Creado automaticamente mediante Apache Jakarta Tomcat JspC.\n\
+-->\n\
+<web-app>\n\
+\n
+jspc.webxml.footer=\n\
+</web-app>\n\
+\n
+jspc.webinc.header=\n\
+<!--\n\
+Creado automaticamente mediante Apache Jakarta Tomcat JspC.\n\
+Coloque este fragmento en el fichero web.xml antes de \n\
+todos los elementos: icon, display-name, description, \n\
+distributable y context-param .\n\
+-->\n
+jspc.webinc.footer=\n\
+<!--\n\
+Los Elementos: session-config, mime-mapping, welcome-file-list, error-page, taglib,\n\
+resource-ref, security-constraint, login-config, security-role,\n\
+env-entry y ejb-ref deberán de ir después de este fragmento .\n\
+-->\n
+jspc.webinc.insertEnd=<!-- Fin de mapeos de servlet JSPC -->
+jspc.webinc.insertStart=<!-- Inicio de mapeos de servlet JSPC -->
+jspc.error.jasperException=error-el archivo ''{0}'' ha generado la excepción de sintáxis siguiente: {1}
+jspc.error.generalException=ERROR-el archivo ''{0}'' ha generado la excepción general siguiente:
+jspc.error.fileDoesNotExist=El archivo ''{0}'' utilizado como argumento no existe.
+jspc.error.emptyWebApp=-webapp necesita un argumento de archivo
+jsp.error.library.invalid=La página JSP es incorrecta de acuerdo a la biblioteca {0}: {1}
+jsp.error.tlvclass.instantiation=No pude cargar o instanciar clase TagLibraryValidator: {0}
+jsp.error.tlv.invalid.page=Mensajes de error de validación desde TagLibraryValidator para {0} in {1}
+jsp.error.tei.invalid.attributes=Mensajes de error de validación desde TagExtraInfo para {0}
+jsp.parser.sax.propertynotsupported=Propiedad SAX no soportada: {0}
+jsp.parser.sax.propertynotrecognized=Propiedad SAX no reconocida: {0}
+jsp.parser.sax.featurenotsupported=Característica SAX no soportada: {0}
+jsp.parser.sax.featurenotrecognized=Característica SAX no reconocida: {0}
+jsp.error.no.more.content=Alcanzado fin de contenido mietras se requería más análisis: ¿error de anidamiento de tag?
+jsp.error.parse.xml=Error de análisis XML en archivo {0}
+jsp.error.parse.xml.line=Error de análisis XML en archivo {0}: (línea {1}, col {2})
+jsp.error.parse.xml.scripting.invalid.body=El cuerpo de elemento {0} no debe de contener elementos XML
+jsp.error.internal.tldinit=No pude inicializar TldLocationsCache: {0}
+jsp.error.internal.filenotfound=Error Interno: Archivo {0} no hallado
+jsp.error.internal.evaluator_not_found=Error interno: no pude cargar evaluador de expresiones
+jsp.error.parse.xml.invalidPublicId=PUBLIC ID incorrecta: {0}
+jsp.error.include.flush.invalid.value=Valor incorrecto para atributo flush: {0}
+jsp.error.unsupported.encoding=Codificación no soportada: {0}
+tld.error.variableNotAllowed=Es un error para un tag, que tiene uno o más subelementos variables, el tener una clase TagExtraInfo que devuelve un objeto no nulo.
+jsp.error.tldInWebDotXmlNotFound=No pude localizar TLD {1} para URI {0} especificado en web.xml
+jsp.error.taglibDirective.absUriCannotBeResolved=La uri absoluta: {0} no puede resolverse o en web.xml o el los archivos jar desplegados con esta aplicación
+jsp.error.taglibDirective.missing.location=No se ha especificado ni el atributo \'uri\' ni el \'tagdir\'
+jsp.error.taglibDirective.both_uri_and_tagdir=Se han especificado ambos atributos \'uri\' y \'tagdir\'
+jsp.error.invalid.tagdir=El directorio de archivo Tag {0} no comienza con \"/WEB-INF/tags\"
+jsp.error.unterminated.user.tag=Tag definido por usuario no terminado: tag final {0} no hallado o anidado incorrectamente
+#jspx.error.templateDataNotInJspCdata=Validation Error: Element &lt;{0}&gt; cannot have template data. Template data must be encapsulated within a &lt;jsp:cdata&gt; element. [JSP1.2 PFD section 5.1.9]\nTemplate data in error: {1}
+jspx.error.templateDataNotInJspCdata=Error de Validación: El Elemento &lt;{0}&gt; no puede tener datos plantilla. Los datos plantilla deben de estar encapsulados dentro de un elemento &lt;jsp:text&gt;. [JSP1.2 PFD sección 5.1.9]\nDatos de Plantilla en error: {1}
+#Error while processing taglib jar file {0}: {1}
+jsp.error.taglib.reserved.prefix=El prefijo taglib {0} está reservado
+jsp.error.invalid.javaEncoding=Codificaciones java incorrectas. Intenté {0} y luego {1}. Ambas fallaron.
+jsp.error.needAlternateJavaEncoding=La codificación java por defecto {0} es incorrecta en tu plataforma java. Se puede especificar una alternativa vía parámetro 'javaEncoding' de JspServlet.
+#Error when compiling, used for jsp line number error messages
+jsp.error.single.line.number=Ha tenido lugar un error en la línea: {0} en el archivo jsp: {1}
+jsp.error.multiple.line.number=\n\nHa tenido lugar un error entre las líneas: {0} y {1} en el archivo jsp: {2}\n\n
+jsp.error.corresponding.servlet=Error de servlet generado:\n
+jsp.error.empty.body.not.allowed=Cuerpo vacío no permitido para {0}
+jsp.error.jspbody.required=Se debe de usar jsp:body para especificar cuerpo tag para {0} si se usa jsp:attribute.
+jsp.error.jspbody.emptybody.only=El tag {0} sólo puede tener jsp:attribute en su cuerpo.
+jsp.error.no.scriptlets=Los elementos de Scripting (&lt;%!, &lt;jsp:declaration, &lt;%=, &lt;jsp:expression, &lt;%, &lt;jsp:scriptlet ) no están permitidos aquí.
+jsp.error.internal.unexpected_node_type=Error Interno: Encontrado tipo de nodo inesperado
+jsp.error.tld.fn.invalid.signature=Sintáxis incorrecta para firma de función en TLD. Biblioteca de Tag: {0}, Función: {1}
+jsp.error.tld.fn.duplicate.name=Nombre duplicado de función {0} en biblioteca de tag {1}
+jsp.error.tld.fn.invalid.signature.commaexpected=Sintáxis incorrecta para firma de función en TLD. Se esperaba Coma ','. Biblioteca de Tag: {0}, Función: {1}.
+jsp.error.tld.fn.invalid.signature.parenexpected=Sintáxis incorrecta para firma de función en TLD. Se esperaba Paréntesis '('. Biblioteca de Tag: {0}, Función: {1}.
+jsp.error.tld.mandatory.element.missing=Falta o está vacío elemento TLD obligatorio: {0}
+jsp.error.dynamic.attributes.not.implemented=El tag {0} declara que acepta atributos dinámicos pero no implementa la interfaz requerida
+jsp.error.nomatching.fragment=No puedo hallar una directiva de atributo (con name={0} y fragment=true) antes de la directiva de fragment.
+jsp.error.attribute.noequal=se esperaba símbolo igual
+jsp.error.attribute.noquote=se esperaba símbolo comillas
+jsp.error.attribute.unterminated=el atributo para {0} no está terminado correctamente
+jsp.error.missing.tagInfo=El objeto TagInfo para {0} falta del TLD
+jsp.error.fragmentwithtype=No puede especificar ambos atributos 'fragment' y 'type'. Si está presente 'fragment', 'type' se pone como 'javax.servlet.jsp.tagext.JspFragment'
+jsp.error.fragmentwithrtexprvalue=No puede especificar ambos atributos 'fragment' y 'rtexprvalue'.  Si está presente 'fragment', 'rtexprvalue' se pone como 'true'
+jsp.error.fragmentWithDeclareOrScope=Ambos atributos 'fragment' y 'declare' o 'scope' se han especificado en la directiva variable
+jsp.error.var_and_varReader=Sólo se puede especificar uno de \'var\' o \'varReader\'
+jsp.error.missing_var_or_varReader=Falta atributo \'var\' o \'varReader\'
+jsp.warning.bad.urlpattern.propertygroup=Valor malo {0} en el subelemento url-pattern en web.xml
+jsp.error.unknown_attribute_type=Tipo de atributo desconocido ({1}) para atributo {0}.
+jsp.error.jspelement.missing.name=Falta atributo obligatorio XML-style \'name\'
+jsp.error.xmlns.redefinition.notimplemented=Error interno: Intento de redefinir xmlns:{0}. La redefinición de espacios de nombre no está implementada.
+jsp.error.could.not.add.taglibraries=No pude añadir una o más bibliotecas.
+jsp.error.duplicate.name.jspattribute=El atributo {0} especificado en la acción standard o custom también aparece como el valor del atributo name en jsp:attribute
+jsp.error.not.in.template={0} no permitido en una plantilla cuerpo de texto.
+jsp.error.badStandardAction=Acción estándar incorrecta
+jsp.error.xml.badStandardAction=Acción estándar incorrecta: {0}
+jsp.error.tagdirective.badbodycontent=body-content incorrecto ({0}) en directiva tag
+jsp.error.simpletag.badbodycontent=El TLD para la clase {0} especifica un body-content es incorrecto (JSP) para un SimpleTag.
+jsp.error.config_pagedir_encoding_mismatch=El Page-encoding especificado en jsp-property-group ({0}) es diferente del especificado en la diectiva page ({1})
+jsp.error.prolog_pagedir_encoding_mismatch=El Page-encoding especificado en XML prolog ({0}) difiere del especificado en la directiva page ({1})
+jsp.error.prolog_config_encoding_mismatch=El Page-encoding especificado en XML prolog ({0}) difiere del especificado en jsp-property-group ({1})
+jsp.error.attribute.custom.non_rt_with_expr=Según el TLD o la directiva attribute del archivo tag, el atributo {0} no acepta expresiones
+jsp.error.attribute.standard.non_rt_with_expr=El atributo {0} de la acción estándar {1} no acepta expresiones
+jsp.error.scripting.variable.missing_name=Imposible determinar nombre de variable de scripting desde atributo {0}
+jasper.error.emptybodycontent.nonempty=Según el TLD, el tag {0} debe de estar vacío, pero no lo está
+jsp.error.tagfile.nameNotUnique=El valor de {0} y el valor de {1} en la línea {2} son el mismo.
+jsp.error.tagfile.nameFrom.noAttribute=No puedo hallar una directiva attribute con un atributo name con un valor \"{0}\", el valor de este atributo name-from-attribute.
+jsp.error.tagfile.nameFrom.badAttribute=La directiva attribute (declarada en la línea {1} y cuyo atributo name es \"{0}\", el valor de este atributo name-from-attribute attribute) debe de ser del tipo java.lang.String, es \"required\" y no un \"rtexprvalue\".
+jsp.error.page.noSession=No puedo acceder al ámbito de sesión en una página que no participa en una sesión
+jsp.error.useBean.noSession=Es ilegal para useBean usar un ámbito de sesión cuando la página JSP declara (vía directiva page) que no participa en sesiones
+jsp.error.xml.encodingByteOrderUnsupported=El orden de byte dado para encoding \"{0}\" no está soportado
+jsp.error.xml.encodingDeclInvalid=Nombre de codificación \"{0}\" incorrecto.
+jsp.error.xml.encodingDeclRequired=Se necesita la declaración encoding en la declaración de texto
+jsp.error.xml.morePseudoAttributes=se esperan más pseudo-atributos
+jsp.error.xml.noMorePseudoAttributes=no se permiten más pseudo-atributos.
+jsp.error.xml.versionInfoRequired=Se requiere la versión en la declaración XML.
+jsp.error.xml.xmlDeclUnterminated=La declaración XML debe de terminar con \"?>\".
+jsp.error.xml.reservedPITarget=La instrucción de procesamiento que coincide con \"[xX][mM][lL]\" no está permitida.
+jsp.error.xml.spaceRequiredInPI=Se necesita un espacio en blanco entre la instrucción de procesamiento y los datos.
+jsp.error.xml.invalidCharInContent=Un carácter XML incorrecto (Unicode: 0x{0}) se halló en el contenido del elemento del documento.
+jsp.error.xml.spaceRequiredBeforeStandalone=Se necesita un espacio en blanco antes del pseudo-atributo encoding en la declaración XML.
+jsp.error.xml.sdDeclInvalid=El valor de declaración de documento standalone debe de ser \"yes\" o \"no\", no \"{0}\".
+jsp.error.xml.invalidCharInPI=Se halló un carácter XML incorrecto (Unicode: 0x{0}) en la instrucción de procesamiento
+jsp.error.xml.versionNotSupported=No se soporta la versión XML \"{0}\", sólo se soporta XML 1.0
+jsp.error.xml.pseudoAttrNameExpected=se esperaba un pseudo-atributo name.
+jsp.error.xml.expectedByte=Se esperaba byte {0} de {1}-byte de secuencia UTF-8.
+jsp.error.xml.invalidByte=Incorrecto byte {0} de {1}-byte de secuencia UTF-8.
+jsp.error.xml.operationNotSupported=La operación \"{0}\" no está soportada por lector {1}.
+jsp.error.xml.invalidHighSurrogate=Surrogación Alta de bits en secuencia UTF-8 no debe de exceder 0x10, pero se halló 0x{0}.
+jsp.error.xml.invalidASCII=El Byte \"{0}\" no es ASCII de 7-bit.
+jsp.error.xml.spaceRequiredBeforeEncodingInXMLDecl=Se necesita espacio en blanco antes del pseudo-atributo encoding en la declaración XML.
+jsp.error.xml.spaceRequiredBeforeEncodingInTextDecl=Se necesita espacio en blanco antes del pseudo-atributo encoding en la declaración text.
+jsp.error.xml.spaceRequiredBeforeVersionInTextDecl=Se necesita espacio en blanco antes del pseudo-atributo version en la declaración text.
+jsp.error.xml.spaceRequiredBeforeVersionInXMLDecl=Se necesita espacio en blanco antes del pseudo-atributo version en la declaración XML.
+jsp.error.xml.eqRequiredInXMLDecl=El carácter '' = '' debe de serguir a \"{0}\" en la declaración XML.
+jsp.error.xml.eqRequiredInTextDecl=El carácter '' = '' debe de serguir a \"{0}\" en la declaración text.
+jsp.error.xml.quoteRequiredInTextDecl=El valor que sigue a \"{0}\" en la declaración text debe de ser una cadena entre comillas.
+jsp.error.xml.quoteRequiredInXMLDecl=El valor que sigue a \"{0}\" en la declaración XML debe de ser un cadena entre comillas.
+jsp.error.xml.invalidCharInTextDecl=Un carácter XML incorrecto (Unicode: 0x{0}) se halló en la declaración text
+jsp.error.xml.invalidCharInXMLDecl=Un carácter XML incorrecto (Unicode: 0x{0}) se halló en la declaración XML
+jsp.error.xml.closeQuoteMissingInTextDecl=Faltan las comillas de cierre en el valor que sigue a \"{0}\" en la declaración text.
+jsp.error.xml.closeQuoteMissingInXMLDecl=Faltan las comillas de cierre en el valor que sigue a  \"{0}\" en la declaración XML.
+jsp.error.multiple.jsp=No puedo tener múltiples especificaciones de
+jsp.error.jspoutput.conflict=&lt;jsp:output&gt;: ilegal tener ocurrencias múltiples de \"{0}\" con diferentes valores (viejo: {1}, nuevo: {2})
+jsp.error.jspoutput.doctypenamesystem=&lt;jsp:output&gt;: atributos 'doctype-root-element' y 'doctype-system' deben de aparecer juntos
+jsp.error.jspoutput.doctypepulicsystem=&lt;jsp:output&gt;: atributo 'doctype-system' debe de aparecer si aparece atributo 'doctype-public'
+jsp.error.jspoutput.nonemptybody=&lt;jsp:output&gt; no debe de tener un cuerpo
+jsp.error.jspoutput.invalidUse=&lt;jsp:output&gt; no se debe de usar en sintáxis estándar
+jsp.error.attributes.not.allowed = {0} no debe de tener atributos
+jsp.error.tagfile.badSuffix=Falta sufijo \".tag\" en trayectoria de archivo de tag {0}
+jsp.error.tagfile.illegalPath=Trayectoria de archivo de tag: {0}, debe de comenzar con \"/WEB-INF/tags\" o \"/META-INF/tags\"
+jsp.error.plugin.wrongRootElement=El nombre del elemento raíz en {0} difiere de {1}
+jsp.error.attribute.invalidPrefix=El prefijo de atributo {0} no se correponde con ninguna biblioteca importada
+jsp.error.nested.jspattribute=Una acción estándar jsp:attribute no puede estar anidada dentro de otra acción estándar jsp:attribute
+jsp.error.nested.jspbody=Una acción estándar jsp:body no puede estar anidada dentro de otra acción estándar jsp:body o jsp:attribute
+jsp.error.variable.either.name=O el atributo name-given o name-from-attribute deben de ser especificados en una directiva variable
+jsp.error.variable.both.name=No se puede especificar ambos atributos name-given o name-from-attribute en una directiva variable
+jsp.error.variable.alias=Ambos atributos o ninguno de name-from-attribute y alias pueden ser especificados en una directiva variable
+jsp.error.attribute.null_name=Nombre de atributo nulo
+jsp.error.jsptext.badcontent=\'&lt;\', cuando aparece en el cuerpo de &lt;jsp:text&gt;, debe de estar encapsulado dentro de un CDATA
+jsp.error.jsproot.version.invalid=Número incorrecto de versión: \"{0}\", debe de ser \"1.2\" o \"2.0\"
+jsp.error.noFunctionPrefix=La función {0} debe de usarse con un prefijo cuando no se especifica un espacio de nombres por defecto
+jsp.error.noFunction=La función {0} no puede ser localizada mediante el prefijo especificado
+jsp.error.noFunctionMethod=El método \"{0}\" para la función \"{1}\" no se pudo hallar en la clase \"{2}\"
+jsp.error.function.classnotfound=La clase {0} especificada en el TLD para la función {1} no se puede hallar: {2}
+jsp.error.signature.classnotfound=La clase {0} especificada en la firma del método en el TLD para la función {1} no se puede hallar. {2}
+jsp.error.text.has_subelement=&lt;jsp:text&gt; no debe de tener subelementos
+jsp.error.data.file.read=Error leyendo archivo \"{0}\"
+jsp.error.prefix.refined=Intento de redefinir el prefijo {0} por {1}, cuando ya estaba definido como {2} en el ámbito en curso.
+jsp.error.nested_jsproot=&lt;jsp:root&gt; anidado
+jsp.error.unbalanced.endtag=El tgag final \"&lt;/{0}\" está desequilibrado
+jsp.error.invalid.bean=

Added: branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/resources/LocalStrings_fr.properties
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/resources/LocalStrings_fr.properties	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/resources/LocalStrings_fr.properties	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,305 @@
+# $Id: LocalStrings_fr.properties 349479 2005-11-28 19:44:47Z yoavs $
+#
+# Default localized string information
+# Localized this the Default Locale as is fr_FR
+
+jsp.error.bad.servlet.engine=Version de moteur de servlet incorrecte!
+jsp.error.no.scratch.dir=Le moteur de JSP engine n''est pas configuré avec un répertoire de travail.\
+\n Merci d''ajouter \"jsp.initparams=scratchdir=<dir-name>\" \
+\n dans le fichier "servlets.properties" de ce contexte.
+jsp.error.bad.scratch.dir=Le paramêtre "scratchDir" que vous avez spécifié: {0} est inutilisable.
+jsp.message.scratch.dir.is=Le répertoire de travail (scratch dir) pour le moteur de JSP est: {0}
+jsp.message.parent_class_loader_is=Le chargeur de classe parent (class loader) est: {0}
+jsp.message.dont.modify.servlets=IMPORTANT: Ne pas modifier les servlets générées
+jsp.error.not.impl.comments=Erreur interne: Commentaires non implémentés
+jsp.error.not.impl.directives=Erreur interne: Directives non implémentées
+jsp.error.not.impl.declarations=Erreur interne: Declarations non implémentées
+jsp.error.not.impl.expressions=Erreur interne: Expressions non implémentées
+jsp.error.not.impl.scriptlets=Erreur interne: Scriptlets non implémentés
+jsp.error.not.impl.usebean=Erreur interne: useBean non implémenté
+jsp.error.not.impl.getp=Erreur interne: getProperty non implémenté
+jsp.error.not.impl.setp=Erreur interne: setProperty non implémenté
+jsp.error.not.impl.plugin=Erreur interne: plugin non implémenté
+jsp.error.not.impl.forward=Erreur interne: forward non implémenté
+jsp.error.not.impl.include=Erreur interne: include non implémenté
+jsp.error.unavailable=La JSP a été marquée comme non disponible
+jsp.error.usebean.missing.attribute=useBean: l''identificateur d''attribut (id attribute) est manquant ou mal orthographié
+jsp.error.usebean.missing.type=useBean ({0}): La classe ou le type d''attribut doit être\
+spécifié: 
+jsp.error.usebean.duplicate=useBean: Nom de bean dupliqué: {0}
+jsp.error.usebean.prohibited.as.session=Impossible d''utiliser comme bean de session {0} car c''est interdit\
+par la directive jsp définie précédemment: 
+jsp.error.usebean.not.both=useBean: Impossible de spécifier à la fois la classe et l''attribut beanName: 
+jsp.error.usebean.bad.type.cast=useBean ({0}): Le type ({1}) n''est pas assignable depuis la classe ({2}) 
+jsp.error.classname=Impossible de déterminer le nom de classe d''après le fichier .class
+jsp.warning.bad.type=Attention: mauvais type dans le fichier .class
+jsp.error.data.file.write=Erreur lors de l''écriture du fichier de données
+#Directive de Page: valeur incorrecte pour pageEncoding
+jsp.error.page.invalid.contenttype=Directive de Page: valeur incorrecte pour contentType
+jsp.error.page.invalid.session=Directive de Page: valeur incorrecte pour session
+jsp.error.page.invalid.buffer=Directive de Page: valeur incorrecte pour "buffer"
+jsp.error.page.invalid.autoflush=Directive de Page: valeur incorrecte pour autoFlush
+jsp.error.page.invalid.isthreadsafe=Directive de Page: valeur incorrecte pour isThreadSafe
+jsp.error.page.invalid.info=Directive de Page: valeur incorrecte pour info
+jsp.error.page.invalid.iserrorpage=Directive de Page: valeur incorrecte pour isErrorPage
+jsp.error.page.defafteruse.language=Directive de Page: on ne peut définir language après un scriptlet 
+jsp.error.page.nomapping.language=Directive de Page: Pas de correspondance pour language: 
+jsp.error.page.bad_b_and_a_combo=Directive de Page: combinaison illégale de buffer=\"none\" && autoFlush=\"false\"
+jsp.error.not.impl.taglib=Internal error: Tag extensions non implémentés
+jsp.error.include.missing.file=l''argument fichier (file) pour l''inclusion (include) est absent
+jsp.error.include.bad.file=Mauvais argument fichier (file) pour l''inclusion (include)
+jsp.error.include.exception=Impossible d''inclure (include) {0}
+jsp.error.stream.closed=Flux fermé
+jsp.error.invalid.forward=Tag forward incorrect
+jsp.error.unknownException=Erreur non traitée! Vous devriez penser à utiliser une page d''erreur \
+pour rapporter ce type d''erreur plus élégamment
+jsp.error.invalid.directive=Directive incorrecte
+jsp.error.directive.istagfile=La directive {0} ne peut être utilisée dans un fichier tag
+jsp.error.directive.isnottagfile=La directive {0} ne peut être utilisée que dans un fichier tag
+jsp.error.tagfile.tld.name=L''attribut \"name\" de la directive tag contient la valeur {0} alors que le tag \"name\" de l''élément \"tag-file\" dans le TLD est {1}
+jsp.error.action.istagfile=L''action {0} ne peut être utilisée dans un fichier tag
+jsp.error.action.isnottagfile=L''action {0} ne peut être utilisée que dans un fichier tag
+jsp.error.unterminated=Tag {0} non terminé
+jsp.error.usebean.notinsamefile=le tag useBean doit commencé et finir dans le même fichier physique
+jsp.error.loadclass.taghandler=Impossible de charger la classe {0}
+jsp.error.unable.compile=Impossible de compiler la classe pour la JSP
+jsp.error.unable.load=Impossible de charger la classe pour la JSP
+jsp.error.unable.rename=Impossible de renommer le fichier classe de {0} vers {1}
+jsp.error.mandatory.attribute={0}: L''attribut obligatoire {1} est manquant
+jsp.engine.info=Moteur Jasper JSP 2.0
+jsp.error.invalid.expression="{0}" contient d''incorrecte(s) expression(s): {1}
+jsp.error.invalid.attribute={0}: Attribut incorrect: {1}
+jsp.error.usebean.class.notfound=Classe: {0} non trouvée
+jsp.error.file.cannot.read=Impossible de lire le fichier: {0}
+jsp.error.file.already.registered=Inclusion récursive du fichier {0}
+jsp.error.file.not.registered=Le fichier {0} n''apparaît pas dans l''inclusion (include)
+jsp.error.quotes.unterminated=guillemets non terminés
+jsp.error.attr.quoted=La valeur de l''attribute doit être entre guillemets 
+jsp.error.attr.novalue=L''attribute {0} n''a pas de valeur
+jsp.error.tag.attr.unterminated=Liste de tag d''attribut non terminée
+jsp.error.param.noname=Pas de nom dans le tag PARAM
+jsp.error.param.novalue=Pas de valeur dans le tag PARAM
+jsp.error.beans.nullbean=Tentative d''opération bean sur un objet nul.
+jsp.error.beans.nobeaninfo=Pas d''information bean (BeanInfo) pour le bean de type ''{0}'' n''a pu être trouvée, la classe n''existe probablement pas.
+jsp.error.beans.introspection=Une exception s''est produite lors de l''introspection de la méthode read de la propriété ''{0}'' dans le bean de type ''{1}'':\n{2}
+jsp.error.beans.nomethod=Impossible de trouver une méthode pour lire la propriété ''{0}'' dans le bean de type ''{1}''
+jsp.error.beans.nomethod.setproperty=Impossible de trouver une méthode pour mettre à jour la propriété ''{0}'' de type ''{1}''dans le bean de type ''{2}''
+jsp.error.beans.noproperty==Impossible de trouver de l''information sur la propriété ''{0}'' dans le bean de type ''{1}''
+jsp.error.beans.setproperty.noindexset=Impossible de renseigner la propriété indéxée
+jsp.error.include.tag=Tag jsp:include incorrect
+jsp.error.include.noflush=jsp:include doit avoir \"flush=true\"
+jsp.error.include.badflush=jsp:include page=\"...\" flush=\"true\" est la seule combinaison valide dans JSP 1.0
+jsp.error.attempt_to_clear_flushed_buffer=Erreur: Tentative d''effacement d''un tampon qui a déjà été vidangé (flush)
+jsp.error.overflow=Erreur: Dépassement de capacité du tampon JSP
+jsp.error.paramexpected=Le tag \"param\" est attendu avec les attributs \"name\" et \"value\" après le tag \"params\".
+jsp.error.closeindividualparam=Le tag param doit être fermé avec \"/>\"
+jsp.error.closeparams=Le tag param tag doit être fermé avec  /params
+jsp.error.plugin.notype=type non déclaré dans jsp:plugin
+jsp.error.plugin.nocode=code non déclaré dans jsp:plugin
+jsp.error.ise_on_clear=Il est interdit d''utiliser clear() quand la taille de tampon== 0
+jsp.error.setproperty.beanNotFound=setProperty: le Bean {0} est introuvable
+jsp.error.getproperty.beanNotFound=getProperty: le Bean {0} est introuvable
+jsp.error.setproperty.ClassNotFound=setProperty: la Classe {0} est introuvable
+jsp.error.setproperty.invalidSyntax=setProperty: On ne peut avoir de valeur non nulle quand property=*
+jsp.error.setproperty.beanInfoNotFound=setproperty: beanInfo pour le bean {0} est introuvable
+jsp.error.setproperty.paramOrValue=setProperty: param ou value doit être présent
+jsp.error.setproperty.arrayVal=setProperty: on ne peut renseigner les array property {0} au travers d''une valeur chaîne constante (string constant value)
+jsp.warning.keepgen=Attention: Valeur incorrecte pour le initParam keepgenerated. Utilisation de la valeur par défaut \"false\"
+jsp.warning.enablePooling=Attention: Valeur incorrecte pour le initParam enablePooling. Utilisation de la valeur par défaut \"true\"
+jsp.warning.mappedFile=Attention: Valeur incorrecte pour le initParam mappedFile. Utilisation de la valeur par défaut \"false\"
+jsp.warning.sendErrToClient=Attention: Valeur incorrecte pour le  initParam sendErrToClient. Utilisation de la valeur par défaut \"false\"
+jsp.warning.classDebugInfo=Attention: Valeur incorrecte pour le initParam classdebuginfo. Utilisation de la valeur par défaut \"false\"
+jsp.warning.checkInterval=Attention: Valeur incorrecte pour le initParam checkInterval. Utilisation de la valeur par défaut \"300\" secondes
+jsp.warning.development=Attention: Valeur incorrecte pour le initParam development. Utilisation de la valeur par défaut \"true\"
+jsp.warning.reloading=Attention: Valeur incorrecte pour le initParam reloading. Utilisation de la valeur par défaut \"true\"
+jsp.warning.reloading=
+jsp.error.badtaglib=Impossible d''ouvrir le taglibrary {0} : {1}
+jsp.error.badGetReader=Impossible de créer un lecteur (reader) quand le flux n''utilse pas des tampons (not buffered)
+jsp.warning.unknown.element.in.TLD=Attention: Elément inconnu {0} dans le TLD
+jsp.warning.unknown.element.in.tag=Attention: Elément inconnu {0} dans le tag
+jsp.warning.unknown.element.in.tagfile=Attention: El?ment inconnu {0} dans le tag-file
+jsp.warning.unknown.element.in.attribute=Attention: Elément inconnu {0} dans l''attribute
+jsp.error.more.than.one.taglib=plus d''un taglib dans le TLD: {0}
+jsp.error.teiclass.instantiation=Impossible de charger ou d''instancier la classe TagExtraInfo: {0}
+jsp.error.non_null_tei_and_var_subelems=Le tag {0} possède une ou plusieurs variables subelements et une classe TagExtraInfo qui retourne une ou plusieurs VariableInfo
+jsp.error.parse.error.in.TLD=Erreur d''évaluation (parse) dans le descripteur de librairie de tag (TLD): {0}
+jsp.error.unable.to.open.TLD=Impossible d''ouvrir le descripteur de librairie de tag (TLD): {0}
+jsp.buffer.size.zero=Taille du tampon <= 0
+jsp.error.file.not.found=Le fichier \"{0}\" n''a pas été trouvé
+jsp.message.copyinguri=Copie de {0} dans {1}
+jsp.message.htmlcomment=\nEffacement des commentaires: \t{0}
+jsp.message.handling_directive=\nDirective de gestion (handling): {0}\t{1}
+jsp.message.handling_plugin=\nPlugin: {0}
+jsp.message.package_name_is=Le nom de package est: {0}
+jsp.message.class_name_is=Le nom de classe est: {0}
+jsp.message.java_file_name_is=Le nom de fichier Java est: {0}
+jsp.message.class_file_name_is=Le nom de fichier Class est: {0}
+jsp.message.accepted=Accepté {0} à {1}
+jsp.message.adding_jar=Ajout du jar {0} à mon classpath
+jsp.message.compiling_with=Compilation avec: {0}
+jsp.message.template_text=texte template
+jsp.error.missing_attribute=D''après le TLD l''attribut {0} est obligatoire pour le tag {1}
+jsp.error.bad_attribute=L''attribut {0} est incorrect pour le tag {1} d''après la TLD indiquée
+jsp.error.webxml_not_found=Impossible de localiser le fichier web.xml
+jsp.cmd_line.usage=Usage: jsptoservlet [-dd <path/to/outputDirectory>] [-keepgenerated] \
+<.jsp files>
+jsp.message.cp_is=Le Classpath {0} est: {1}
+jsp.error.unable.to_load_taghandler_class=Impossible de charger la classe gestionnaire de tag {0} car {1}
+jsp.error.unable.to_find_method=Impossible de trouver une méthode de mise à jour pour l''attribut: {0}
+jsp.error.unable.to_convert_string=Impossible de convertir une chaîne vers {0} pour l''attribut {1}
+jsp.error.unable.to_introspect=Impossible d''introspecter la classe gestionnaire de tag : {0} car {1}
+jsp.error.bad_tag=Aucun tag {0} dans la librairie de tag importée avec le préfixe {1}
+jsp.error.bad_string_Character=Impossible d''extraire un caractère depuis un tableau vide
+jsp.error.bad_string_char=Impossible d''extraire un caractère depuis un tableau vide
+jsp.warning.compiler.class.cantcreate=Impossible de créer une instance de classe plugin pour le compilateur indiqué {0} due to {1}. Utilisation par défaut du Compilateur Java Sun.
+jsp.warning.compiler.class.notfound=La classe plugin de compilateur {0} est introuvable. Utilisation par défaut du Compilateur Java Sun.
+jsp.warning.compiler.path.notfound=le chemin de compilateur indiqué {0} est introuvable. Utilisation par défaut du chemin système (system PATH).
+jsp.error.jspc.uriroot_not_dir=L''option -uriroot doit indiqué un répertoire déjà existant
+jspc.implicit.uriRoot=uriRoot réglé implicitement à "{0}"
+jspc.usage=Usage: jspc <options> [--] <fichiers jsp>\n\
+où les fichiers jsp sont n''importe quel nombre de:\n\
+\    <file>         Un fichier à évaluer (parser) comme page jsp\n\
+\    -webapp <dir>  Un répertoire contenant une application web, toutes les pages jsp\n\
+\                   seront récursivement évaluées\n\
+où les options comprennet:\n\
+\    -q          Mode silencieux (identique à -v0)\n\
+\    -v[#]       Mode bavard (Le nombre optionnel indique le niveau, 2 par défaut)\n\
+\    -d <dir>    Dossier de sortie\n\
+\    -dd <dir>   Dossier de sortie literal.  (Les dossiers de paquets ne seront pas construits)\n\
+\    -l          Sortie du nom la page JSP en cas d''échec\n\
+\    -s          Sortie du nom la page JSP en cas de succès\n\
+\    -p <name>   Nom du paquet cible\n\
+\    -c <name>   Nom d'un nom de classe cible\n\
+\                (s''applique seulement à la première page JSP)\n\
+\    -mapped     Génère des appels à write() séparés pour chaque ligne HTML dans la JSP\n\
+\    -die[#]     Génère un code d''erreur de retour (#) en cas d''erreurs fatales.\n\
+\                Si le nombre est absent ou non numérique, le défaut est 1.\n\
+\    -uribase <dir>  Le répertoire uri de compilations relatif\n\
+\                    (Par défaut "/")\n\
+\    -uriroot <dir>  The répertoire racine contre lequel les fichiers seront résolus\n\
+\                    , (Par défaut le répertoire depuis lequel jspc est appelé)\n\
+\    -webinc <file>  Création d''association partielle de servlet pour l''option -webapp.\n\
+\    -webxml <file>  Création d''un fichier web.xml complet pour l''option -webapp.\n\
+\    -ieplugin <clsid>  Le classid du Plugin Java Plugin pour Internet Explorer\n\
+\    -sax2 <driverclassname>  Le nom de classe du Driver SAX 2.0 à utiliser\n\
+\    -trimSpaces        Trim spaces in template text between actions, directives\n\
+\    -javaEncoding <enc> Set the encoding charset for Java classes (default UTF-8)\n\
+\    -source <version>   Set the -source argument to the compiler (default 1.4)\n\
+\    -target <version>   Set the -target argument to the compiler (default 1.4)\n\
+
+jspc.webxml.header=<?xml version="1.0" encoding="ISO-8859-1"?>\n\
+\n\
+<!DOCTYPE web-app\n\
+\    PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"\n\
+\    "http://java.sun.com/dtd/web-app_2_3.dtd">\n\
+<!--\n\
+Créer automatiquement par le JspC Apache Jakarta Tomcat.\n\
+-->\n\
+<web-app>\n\
+\n
+jspc.webxml.footer=\n\
+</web-app>\n\
+\n
+jspc.webinc.header=\n\
+<!--\n\
+Créer automatiquement par le JspC Apache Jakarta Tomcat.\n\
+Placez ce fragment dans le fichier web.xml avant all icon, display-name,\n\
+description, distributable, and context-param elements.\n\
+-->\n
+jspc.webinc.footer=\n\
+<!--\n\
+All session-config, mime-mapping, welcome-file-list, error-page, taglib,\n\
+resource-ref, security-constraint, login-config, security-role,\n\
+env-entry, and ejb-ref elements should follow this fragment.\n\
+-->\n
+jspc.error.jasperException=erreur-le fichier ''{0}'' a généré l''exception d''évaluation suivante: {1}
+jspc.error.generalException=ERREUR-le fichier ''{0}'' a généré l''exception générale suivante:
+jspc.error.fileDoesNotExist=L''argument fichier ''{0}'' n''existe pas
+jspc.error.emptyWebApp=-webapp nécessite à sa suite un argument fichier
+jsp.error.library.invalid=La page JSP page est incorrecte d''après la librairie {0}: {1}
+jsp.error.tlvclass.instantiation=Impossible de charger ou d''instancier la classe TagLibraryValidator: {0}
+jsp.error.tlv.invalid.page=Message d''erreurs de validation provenant du TagLibraryValidator pour {0} en {1}
+jsp.error.tei.invalid.attributes=Message d''erreurs de validation provenant du TagExtraInfo pour {0}
+jsp.parser.sax.propertynotsupported=Propriété SAX non supportée: {0}
+jsp.parser.sax.propertynotrecognized=Propriété SAX non reconnue: {0}
+jsp.parser.sax.featurenotsupported=Fonctionnalité SAX non supportée: {0}
+jsp.parser.sax.featurenotrecognized=Fonctionnalité SAX non reconnue: {0}
+jsp.error.no.more.content=Fin de contenu alors que l''évalution n''était pas terminée: erreur de tags imbriqués?
+jsp.error.parse.xml=Erreur d''évaluation XML sur le fichier {0}
+jsp.error.parse.xml.line=Erreur d''évaluation XML sur le fichier  {0}: (ligne {1}, col {2})
+jsp.error.parse.xml.scripting.invalid.body=Le corps de l''élément {0} ne doit contenir aucun éléments XML
+jsp.error.internal.tldinit=Exception lors de l'initialisation de TldLocationsCache: {0}
+jsp.error.internal.filenotfound=Erreur interne: Fichier {0} introuvable
+jsp.error.internal.evaluator_not_found=Erreur interne: Impossible de charger l''évaluateur d''expression
+jsp.error.parse.xml.invalidPublicId=PUBLIC ID invalide: {0}
+jsp.error.include.flush.invalid.value=Valeur incorrecte pour l''attribut flush: {0}
+jsp.error.unsupported.encoding=Encodage non supporté: {0}
+jsp.warning.unknown.element.in.variable=Attention: Element inconnu {0} dans la variable
+tld.error.variableNotAllowed=Ceci est une erreur pour le tag qui possède une ou plusieurs variables subelements pour avoir une classe TagExtraInfo qui retourne un objet non-nul.
+jsp.error.tldInWebDotXmlNotFound=Ne peut trouver le TLD {1} pour l''URI {0} indiquée dans le fichier web.xml
+jsp.error.taglibDirective.absUriCannotBeResolved=L''uri absolue: {0} ne peut être résolu dans le fichier web.xml ou dans les fichiers jar déployés avec cette application
+jsp.error.taglibDirective.missing.location=Ni l''uri' ni l''attribut 'tagdir' n''ont été indiqués dans la directive taglib
+jsp.error.invalid.tagdir=Le répertoire du fichier Tag {0} ne commence pas par \"/WEB-INF/tags\"
+jsp.error.unterminated.user.tag=Tag user-defined non terminé: Le tag de fermeture {0} est introuvable found ou incorrectement imbriqué
+#jspx.error.templateDataNotInJspCdata=Erreur de validation: l''élément &lt;{0}&gt; ne peut avoir de données template. Les données Template doivent être encapsulées à l''intérieur d''un élément &lt;jsp:cdata&gt;. [JSP1.2 PFD section 5.1.9]\nDonnée Template en erreur: {1}
+jspx.error.templateDataNotInJspCdata=Erreur de validation: l''élément &lt;{0}&gt; ne peut avoir de données template. Les données Template doivent être encapsulées à l''intérieur d''un élément &lt;jsp:text&gt;. [JSP1.2 PFD section 5.1.9]\nDonnée Template en erreur: {1}
+#Erreur lors du traitement du fichier jar de la taglib {0}: {1}
+jsp.error.taglib.reserved.prefix=Le préfixe taglib {0} est réservé
+jsp.error.invalid.javaEncoding=Encodage java incorrect. Essai de {0} puis de {1}. Les deux ont échoué.
+jsp.error.needAlternateJavaEncoding=L''encodage java par défaut {0} est incorrect sur votre environnement java. Une alternative peut être indiquée via le paramêtre 'javaEncoding' de la JspServlet.
+#Erreur lors de la compilation, utilisé pour la ligne jsp des messages d''erreur
+jsp.error.single.line.number=Une erreur s''est produite à la ligne: {0} dans le fichier jsp: {1}
+jsp.error.multiple.line.number=\n\nUne erreur s''est produite entre les lignes: {0} et {1} dans le fichier jsp: {2}\n\n
+jsp.error.corresponding.servlet=Erreur de servlet générée:\n
+jsp.error.empty.body.not.allowed=Un corps vide n'est pas autorisé pour {0}
+jsp.error.jspbody.required=Doit utiliser jsp:body pour indiqué le corps de tag body de {0} si jsp:attribute est utilisé.
+jsp.error.jspbody.emptybody.only=Le tag {0} ne peut avoir que jsp:attribute dans son corps.
+jsp.error.no.scriptlets=Les éléments de Scripting ( <%!, <jsp:declaration, <%=, <jsp:expression, <%, <jsp:scriptlet ) ne sont pas autorisés ici.
+jsp.error.internal.unexpected_node_type=Erreur Interne: Type de node inattendu rencontré
+jsp.error.tld.fn.invalid.signature=Synthaxe invalide pour la signature de fonction dans la TLD.  Librairie de Tag : {0}, Fonction: {1}
+jsp.error.tld.fn.invalid.signature.classnotfound=Synthaxe invalide pour la signature de fonction dans la TLD.  Classe introuvable: ${0}.  Librairie de Tag: {1}, Fonction: {2}.
+jsp.error.tld.fn.invalid.signature.commaexpected=Synthaxe invalide pour la signature de fonction dans la TLD.  Virgule ',' attendue.  Librairie de Tag: {0}, Fonction: {1}.
+jsp.error.tld.fn.invalid.signature.parenexpected=Synthaxe invalide pour la signature de fonction dans la TLD.  Parenthèse '(' attendue.  Librairie de Tag: {0}, Fonction: {1}.
+jsp.error.dynamic.attributes.not.implemented=Le tag {0} indique qu''il accepte des attributs dynamics mais n''implémente pas l''interface requise
+jsp.error.nomatching.fragment=Ne peut trouver une directive attribut (avec pour nom={0} et fragment=true) avant la directive fragment.
+jsp.error.attribute.noequal=Symbole égal (equal) attendu
+jsp.error.attribute.noquote=Symbole guillemet (quote) attendu
+jsp.error.attribute.unterminated=L''attribut pour {0} n''est pas correctement terminé
+jsp.error.missing.tagInfo=L''objet TagInfo de {0} est absent de la TLD
+jsp.error.fragmentwithtype=On ne peut indiquer à la fois les attributs 'fragment' et 'type'.  Si 'fragment' est présent, 'type' est fixé comme 'javax.servlet.jsp.tagext.JspFragment'
+jsp.error.fragmentwithrtexprvalue=On ne peut indiquer à la fois les attributs 'fragment' et 'rtexprvalue'.  Si 'fragment' est présent, 'rtexprvalue' est fixé à 'true'
+jsp.error.fragmentWithDeclareOrScope=Les attributs 'fragment' et 'declare' ou 'scope' sont indiqués dans la directive variable
+jsp.error.var_and_varReader=A la fois 'var' et 'varReader' sont indiqués
+jsp.warning.bad.urlpattern.propertygroup=Mauvaise valeur {0} dans le sous-élément (subelement) url-pattern du fichier web.xml
+jsp.error.unknown_attribute_type=Type d''attribut inconnu ({1}) pour l''attribut {0}.
+jsp.error.jspelement.missing.name=L''attribut obligatoire 'name' est absent de jsp:element
+jsp.error.xmlns.redefinition.notimplemented=Erreur Interne: Tentative de redéfinition de xmlns:{0}.  La redéfinition des domaines de noms (namespaces) n''est pas implémentée.
+jsp.error.could.not.add.taglibraries=Impossible d''ajouter une ou plusieurs librairies de tag.
+jsp.error.duplicate.name.jspattribute=L''attribut {0} indiqué dans l''action standard ou spécifique (custom) apparait aussi comme valeur de l''attribut de nom dans le jsp:attribute inclus
+jsp.error.not.in.template={0} n''est pas autorisé dans le corps de texte de template.
+jsp.error.badStandardAction=L''action n''est pas reconnue comme une action standard.
+jsp.error.tagdirective.badbodycontent=Contenu de corps (body-content) ({0}) invalide dans la directive tag
+jsp.error.config_pagedir_encoding_mismatch=L''encode de page (Page-encoding) indiqué dans le jsp-property-group ({0}) est différent de celui indiqué dans la directive de page ({1})
+jsp.error.prolog_pagedir_encoding_mismatch=
+jsp.error.prolog_config_encoding_mismatch=
+jsp.error.attribute.custom.non_rt_with_expr=D''après la TLD, l''attribut {0} n''accepte aucune expression
+jsp.error.scripting.variable.missing_name=Incapable de déterminer le nom de variable scripting d''après l''attribut {0}
+jasper.error.emptybodycontent.nonempty=D''après la TLD, le tag {0} doit être vide, mais ne l''est pas
+jsp.error.tagfile.nameNotUnique=
+jsp.error.tagfile.nameFrom.noAttribute=
+jsp.error.tagfile.nameFrom.badAttribute=
+jsp.error.useBean.noSession=Il est illégal pour useBean d''utiliser une portée de session (session scope) quand la page JSP indique (via la directive de page) qu''elle ne participe pas aux sessions
+jsp.error.attributes.not.allowed = {0} ne doit avoir aucun attribut
+jsp.error.nested.jspattribute=
+jsp.error.nested.jspbody=
+jsp.error.variable.either.name=
+jsp.error.variable.both.name=
+jsp.error.variable.alias=
+jsp.error.jsptext.badcontent=
+jsp.error.prefix.refined=
+jsp.error.jspoutput.conflict=
+jsp.error.jspoutput.doctypenamesystem=
+jsp.error.jspoutput.doctypepulicsystem=
+jsp.error.jspoutput.nonemptybody=
+jsp.error.jspoutput.invalidUse=
+jsp.error.invalid.bean=

Added: branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/resources/LocalStrings_ja.properties
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/resources/LocalStrings_ja.properties	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/resources/LocalStrings_ja.properties	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,407 @@
+# $Id: LocalStrings_ja.properties 349479 2005-11-28 19:44:47Z yoavs $
+#
+# Default localized string information
+# Localized this the Default Locale as is ja_JP
+
+jsp.error.bad.servlet.engine=\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8\u30a8\u30f3\u30b8\u30f3\u306e\u30d0\u30fc\u30b8\u30e7\u30f3\u304c\u6b63\u3057\u304f\u3042\u308a\u307e\u305b\u3093
+jsp.error.no.scratch.dir=JSP\u30a8\u30f3\u30b8\u30f3\u306b\u30c7\u30d5\u30a9\u30eb\u30c8\u306escratchDir\u304c\u8a2d\u5b9a\u3055\u308c\u3066\u3044\u307e\u305b\u3093\u3002\
+\n \u3053\u306e\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u306eservlets.properties\u30d5\u30a1\u30a4\u30eb\u306b\u3001\
+\n \"jsp.initparams=scratchdir=<dir-name>\" \u3092\u8ffd\u52a0\u3057\u3066\u304f\u3060\u3055\u3044\u3002
+jsp.error.bad.scratch.dir=\u3042\u306a\u305f\u304c\u6307\u5b9a\u3057\u305fscratchDir\u306f\u4f7f\u7528\u3067\u304d\u307e\u305b\u3093
+jsp.message.scratch.dir.is=JSP\u30a8\u30f3\u30b8\u30f3\u306eScratchdir: {0}
+jsp.message.parent_class_loader_is=\u89aa\u30af\u30e9\u30b9\u30ed\u30fc\u30c0: {0}
+jsp.message.dont.modify.servlets=\u91cd\u8981: \u751f\u6210\u3055\u308c\u305f\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8\u3092\u5909\u66f4\u3057\u3066\u306f\u3044\u3051\u307e\u305b\u3093
+jsp.error.not.impl.comments=\u5185\u90e8\u30a8\u30e9\u30fc: Comments\u306f\u5b9f\u88c5\u3055\u308c\u3066\u3044\u307e\u305b\u3093
+jsp.error.not.impl.directives=\u5185\u90e8\u30a8\u30e9\u30fc: Directives\u306f\u5b9f\u88c5\u3055\u308c\u3066\u3044\u307e\u305b\u3093
+jsp.error.not.impl.declarations=\u5185\u90e8\u30a8\u30e9\u30fc: Declarations\u306f\u5b9f\u88c5\u3055\u308c\u3066\u3044\u307e\u305b\u3093
+jsp.error.not.impl.expressions=\u5185\u90e8\u30a8\u30e9\u30fc: Expressions\u306f\u5b9f\u88c5\u3055\u308c\u3066\u3044\u307e\u305b\u3093
+jsp.error.not.impl.scriptlets=\u5185\u90e8\u30a8\u30e9\u30fc: Scriptlets\u306f\u5b9f\u88c5\u3055\u308c\u3066\u3044\u307e\u305b\u3093
+jsp.error.not.impl.usebean=\u5185\u90e8\u30a8\u30e9\u30fc: useBean\u306f\u5b9f\u88c5\u3055\u308c\u3066\u3044\u307e\u305b\u3093
+jsp.error.not.impl.getp=\u5185\u90e8\u30a8\u30e9\u30fc: getProperty\u306f\u5b9f\u88c5\u3055\u308c\u3066\u3044\u307e\u305b\u3093
+jsp.error.not.impl.setp=\u5185\u90e8\u30a8\u30e9\u30fc: setProperty\u306f\u5b9f\u88c5\u3055\u308c\u3066\u3044\u307e\u305b\u3093
+jsp.error.not.impl.plugin=\u5185\u90e8\u30a8\u30e9\u30fc: plugin\u306f\u5b9f\u88c5\u3055\u308c\u3066\u3044\u307e\u305b\u3093
+jsp.error.not.impl.forward=\u5185\u90e8\u30a8\u30e9\u30fc: forward\u306f\u5b9f\u88c5\u3055\u308c\u3066\u3044\u307e\u305b\u3093
+jsp.error.not.impl.include=\u5185\u90e8\u30a8\u30e9\u30fc: include\u306f\u5b9f\u88c5\u3055\u308c\u3066\u3044\u307e\u305b\u3093
+jsp.error.unavailable=JSP\u306f\u5229\u7528\u4e0d\u53ef\u3068\u30de\u30fc\u30af\u3055\u308c\u3066\u3044\u307e\u3059
+jsp.error.usebean.missing.attribute=useBean: id\u5c5e\u6027\u304c\u5b58\u5728\u3057\u306a\u3044\u304b\u3001\u30b9\u30da\u30eb\u30df\u30b9\u3067\u3059
+jsp.error.usebean.missing.type=useBean ({0}): class\u5c5e\u6027\u304btype\u5c5e\u6027\u3092\u6307\u5b9a\u3057\u3066\u304f\u3060\u3055\u3044:
+jsp.error.usebean.duplicate=useBean: beanName\u5c5e\u6027\u304c\u91cd\u8907\u3057\u3066\u3044\u307e\u3059: {0}
+jsp.error.usebean.prohibited.as.session=\u4ee5\u524d\u306b\u5b9a\u7fa9\u3057\u305fJSP\u6307\u793a\u5b50\u306b\u3088\u3063\u3066\u7981\u6b62\u3055\u308c\u3066\u3044\u308b\u305f\u3081\u306b\u3001session bean {0} \u3068\u3057\u3066\u4f7f\u7528\u3067\u304d\u307e\u305b\u3093:
+jsp.error.usebean.not.both=useBean: class\u5c5e\u6027\u3068beanName\u5c5e\u6027\u306e\u4e21\u65b9\u3092\u540c\u6642\u306b\u6307\u5b9a\u3067\u304d\u307e\u305b\u3093:
+jsp.error.usebean.bad.type.cast=useBean ({0}): type ({1}) \u306fclass ({2}) \u304b\u3089\u5272\u308a\u5f53\u3066\u3089\u308c\u307e\u305b\u3093
+jsp.error.invalid.scope='scope'\u5c5e\u6027\u306e\u5024\u304c\u7121\u52b9\u3067\u3059: {0} (\"page\"\u3001\"request\"\u3001\"session\"\u53c8\u306f\"application\"\u306e\u3069\u308c\u304b\u3067\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093)
+jsp.error.classname=.class\u30d5\u30a1\u30a4\u30eb\u304b\u3089\u30af\u30e9\u30b9\u540d\u3092\u6c7a\u5b9a\u3067\u304d\u307e\u305b\u3093
+jsp.warning.bad.type=\u8b66\u544a: .class\u30d5\u30a1\u30a4\u30eb\u4e2d\u306e\u578b\u304c\u9055\u3044\u307e\u3059
+jsp.error.data.file.write=\u30c7\u30fc\u30bf\u30d5\u30a1\u30a4\u30eb\u3092\u66f8\u304d\u8fbc\u307f\u4e2d\u306e\u30a8\u30e9\u30fc\u3067\u3059
+jsp.error.page.invalid.buffer=page\u6307\u793a\u5b50: \u7121\u52b9\u306a\u30d0\u30c3\u30d5\u30a1\u30b5\u30a4\u30ba\u3067\u3059
+jsp.error.page.conflict.contenttype=page\u6307\u793a\u5b50: 'contentType'\u3092\u7570\u306a\u308b\u5024\u3067\u8907\u6570\u56de\u6307\u5b9a\u3059\u308b\u306e\u306f\u7121\u52b9\u3067\u3059 (\u65e7: {0}, \u65b0: {1})
+jsp.error.page.invalid.contenttype=page\u6307\u793a\u5b50: contentType\u5c5e\u6027\u306e\u5024\u304c\u7121\u52b9\u3067\u3059
+jsp.error.page.conflict.session=page\u6307\u793a\u5b50: 'session'\u3092\u7570\u306a\u308b\u5024\u3067\u8907\u6570\u56de\u6307\u5b9a\u3059\u308b\u306e\u306f\u7121\u52b9\u3067\u3059 (\u65e7: {0}, \u65b0: {1})
+jsp.error.page.invalid.session=page\u6307\u793a\u5b50: session\u5c5e\u6027\u306e\u5024\u304c\u7121\u52b9\u3067\u3059
+jsp.error.page.conflict.buffer=page\u6307\u793a\u5b50: 'buffer'\u3092\u7570\u306a\u308b\u5024\u3067\u8907\u6570\u56de\u6307\u5b9a\u3059\u308b\u306e\u306f\u7121\u52b9\u3067\u3059 (\u65e7: {0}, \u65b0: {1})
+jsp.error.page.invalid.buffer=page\u6307\u793a\u5b50: buffer\u5c5e\u6027\u306e\u5024\u304c\u7121\u52b9\u3067\u3059
+jsp.error.page.conflict.autoflush=page\u6307\u793a\u5b50: 'autoFlush'\u3092\u7570\u306a\u308b\u5024\u3067\u8907\u6570\u56de\u6307\u5b9a\u3059\u308b\u306e\u306f\u7121\u52b9\u3067\u3059 (\u65e7: {0}, \u65b0: {1})
+jsp.error.page.invalid.autoflush=page\u6307\u793a\u5b50: autoFlush\u5c5e\u6027\u306e\u5024\u304c\u7121\u52b9\u3067\u3059
+jsp.error.page.conflict.isthreadsafe=page\u6307\u793a\u5b50: 'isThreadSafe'\u3092\u7570\u306a\u308b\u5024\u3067\u8907\u6570\u56de\u6307\u5b9a\u3059\u308b\u306e\u306f\u7121\u52b9\u3067\u3059 (\u65e7: {0}, \u65b0: {1})
+jsp.error.page.invalid.isthreadsafe=page\u6307\u793a\u5b50: isThreadSafe\u306e\u5024\u304c\u7121\u52b9\u3067\u3059
+jsp.error.page.conflict.info=page\u6307\u793a\u5b50: 'info'\u3092\u7570\u306a\u308b\u5024\u3067\u8907\u6570\u56de\u6307\u5b9a\u3059\u308b\u306e\u306f\u7121\u52b9\u3067\u3059 (\u65e7: {0}, \u65b0: {1})
+jsp.error.page.invalid.info=page\u6307\u793a\u5b50: info\u5c5e\u6027\u306e\u5024\u304c\u7121\u52b9\u3067\u3059
+jsp.error.page.conflict.iserrorpage=page\u6307\u793a\u5b50: 'isErrorPage'\u3092\u7570\u306a\u308b\u5024\u3067\u8907\u6570\u56de\u6307\u5b9a\u3059\u308b\u306e\u306f\u7121\u52b9\u3067\u3059 (\u65e7: {0}, \u65b0: {1})
+jsp.error.page.invalid.iserrorpage=page\u6307\u793a\u5b50: isErrorPage\u5c5e\u6027\u306e\u5024\u304c\u7121\u52b9\u3067\u3059
+jsp.error.page.conflict.errorpage=page\u6307\u793a\u5b50: 'errorPage'\u3092\u7570\u306a\u308b\u5024\u3067\u8907\u6570\u56de\u6307\u5b9a\u3059\u308b\u306e\u306f\u7121\u52b9\u3067\u3059 (\u65e7: {0}, \u65b0: {1})
+jsp.error.page.conflict.language=page\u6307\u793a\u5b50: 'language'\u3092\u7570\u306a\u308b\u5024\u3067\u8907\u6570\u56de\u6307\u5b9a\u3059\u308b\u306e\u306f\u7121\u52b9\u3067\u3059 (\u65e7: {0}, \u65b0: {1})
+jsp.error.tag.conflict.language=tag\u6307\u793a\u5b50: 'language'\u3092\u7570\u306a\u308b\u5024\u3067\u8907\u6570\u56de\u6307\u5b9a\u3059\u308b\u306e\u306f\u7121\u52b9\u3067\u3059 (\u65e7: {0}, \u65b0: {1})
+jsp.error.page.language.nonjava=page\u6307\u793a\u5b50: \u7121\u52b9\u306alanguage\u5c5e\u6027\u3067\u3059
+jsp.error.tag.language.nonjava=tag\u6307\u793a\u5b50: \u7121\u52b9\u306alanguage\u5c5e\u6027\u3067\u3059
+jsp.error.page.defafteruse.language=page\u6307\u793a\u5b50: scriptlet\u306e\u5f8c\u3067language\u5c5e\u6027\u3092\u6307\u5b9a\u3067\u304d\u307e\u305b\u3093
+jsp.error.page.nomapping.language=page\u6307\u793a\u5b50 language\u5c5e\u6027\u306e\u30de\u30c3\u30d4\u30f3\u30b0\u304c\u5b58\u5728\u3057\u307e\u305b\u3093:
+jsp.error.page.conflict.extends=page\u6307\u793a\u5b50: 'extends'\u3092\u7570\u306a\u308b\u5024\u3067\u8907\u6570\u56de\u6307\u5b9a\u3059\u308b\u306e\u306f\u7121\u52b9\u3067\u3059 (\u65e7: {0}, \u65b0: {1})
+jsp.error.page.conflict.iselignored=page\u6307\u793a\u5b50: 'isELIgnored'\u3092\u7570\u306a\u308b\u5024\u3067\u8907\u6570\u56de\u6307\u5b9a\u3059\u308b\u306e\u306f\u7121\u52b9\u3067\u3059 (\u65e7: {0}, \u65b0: {1})
+jsp.error.tag.conflict.iselignored=tag\u6307\u793a\u5b50: 'isELIgnored'\u3092\u7570\u306a\u308b\u5024\u3067\u8907\u6570\u56de\u6307\u5b9a\u3059\u308b\u306e\u306f\u7121\u52b9\u3067\u3059 (\u65e7: {0}, \u65b0: {1})
+jsp.error.page.invalid.iselignored=page\u6307\u793a\u5b50: isELIgnored\u306b\u7121\u52b9\u306a\u5024\u304c\u6307\u5b9a\u3055\u308c\u3066\u3044\u307e\u3059
+jsp.error.tag.invalid.iselignored=tag\u6307\u793a\u5b50: isELIgnored\u306b\u7121\u52b9\u306a\u5024\u304c\u6307\u5b9a\u3055\u308c\u3066\u3044\u307e\u3059
+jsp.error.page.multi.pageencoding=page\u6307\u793a\u5b50\u306f\u8907\u6570\u306epageencoding\u3092\u6301\u3064\u3053\u3068\u306f\u3067\u304d\u307e\u305b\u3093
+jsp.error.tag.conflict.attr=Tag\u6307\u793a\u5b50: \u5c5e\u6027\"{0}\"\u3092\u7570\u306a\u308b\u5024\u3067\u8907\u6570\u56de\u6307\u5b9a\u3059\u308b\u306e\u306f\u4e0d\u6b63\u3067\u3059 (\u65e7: {1}, \u65b0: {2})
+jsp.error.tag.multi.pageencoding=tag\u6307\u793a\u5b50\u306f\u8907\u6570\u306epageencoding\u3092\u6301\u3064\u3053\u3068\u306f\u3067\u304d\u307e\u305b\u3093
+jsp.error.page.bad_b_and_a_combo=page\u6307\u793a\u5b50: buffer=\"none\"\u3068autoFlush=\"false\"\u3092\u540c\u6642\u306b\u4f7f\u7528\u3067\u304d\u307e\u305b\u3093
+jsp.error.not.impl.taglib=\u5185\u90e8\u30a8\u30e9\u30fc: \u30bf\u30b0\u62e1\u5f35\u5b50\u306f\u5b9f\u88c5\u3055\u308c\u3066\u3044\u307e\u305b\u3093
+jsp.error.include.missing.file=\u53d6\u308a\u8fbc\u3080\u30d5\u30a1\u30a4\u30eb\u5f15\u6570\u304c\u3042\u308a\u307e\u305b\u3093
+jsp.error.include.bad.file=include\u5c5e\u6027\u306e\u30d5\u30a1\u30a4\u30eb\u5f15\u6570\u304c\u9593\u9055\u3063\u3066\u3044\u307e\u3059
+jsp.error.include.exception={0} \u3092\u53d6\u308a\u8fbc\u3081\u307e\u305b\u3093
+jsp.error.stream.closed=\u30b9\u30c8\u30ea\u30fc\u30e0\u304c\u30af\u30ed\u30fc\u30ba\u3055\u308c\u3066\u3044\u307e\u3059
+jsp.error.invalid.forward=\u7121\u52b9\u306aforward\u30bf\u30b0\u3067\u3059
+jsp.error.unknownException=\u51e6\u7406\u4e0d\u53ef\u80fd\u306a\u30a8\u30e9\u30fc\u3067\u3059! \u3053\u306e\u3088\u3046\u306a\u30a8\u30e9\u30fc\u3092\u3088\u308a\u8a73\u7d30\u306b\u5831\u544a\u3059\u308b\u30a8\u30e9\u30fc\u30da\u30fc\u30b8\u3092\u6301\u3063\u305f\u65b9\u304c\u3088\u3044\u304b\u3082\u3057\u308c\u307e\u305b\u3093
+jsp.error.invalid.directive=\u7121\u52b9\u306a\u6307\u793a\u5b50\u3067\u3059
+jsp.error.directive.istagfile={0} \u6307\u793a\u5b50\u306f\u30bf\u30b0\u30d5\u30a1\u30a4\u30eb\u4e2d\u3067\u306f\u4f7f\u7528\u3067\u304d\u307e\u305b\u3093
+jsp.error.directive.isnottagfile={0} \u6307\u793a\u5b50\u306f\u30bf\u30b0\u30d5\u30a1\u30a4\u30eb\u4e2d\u3067\u3057\u304b\u4f7f\u7528\u3067\u304d\u307e\u305b\u3093
+jsp.error.tagfile.tld.name=TLD\u4e2d\u306e\u30bf\u30b0\u6307\u793a\u5b50\u306e\"tag-file\"\u8981\u7d20\u306e\"name\"\u30bf\u30b0\u306f {1} \u3067\u3059\u304c\uff0c\"name\"\u5c5e\u6027\u306f\u5024 {0} \u3092\u6301\u3063\u3066\u3044\u307e\u3059
+jsp.error.action.istagfile={0} \u30a2\u30af\u30b7\u30e7\u30f3\u306f\u30bf\u30b0\u30d5\u30a1\u30a4\u30eb\u4e2d\u3067\u4f7f\u7528\u3067\u304d\u307e\u305b\u3093
+jsp.error.action.isnottagfile={0} \u30a2\u30af\u30b7\u30e7\u30f3\u306f\u30bf\u30b0\u30d5\u30a1\u30a4\u30eb\u4e2d\u3067\u306e\u307f\u4f7f\u7528\u3067\u304d\u307e\u305b\u3093
+jsp.error.unterminated={0} \u30bf\u30b0\u304c\u7d42\u4e86\u3057\u3066\u3044\u307e\u305b\u3093
+jsp.error.usebean.notinsamefile=useBean\u30bf\u30b0\u306f\u3001\u540c\u4e00\u30d5\u30a1\u30a4\u30eb\u4e2d\u3067\u958b\u59cb\u3057\u3001\u7d42\u4e86\u3057\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093
+jsp.error.loadclass.taghandler=\u30bf\u30b0 \"{1}\" \u306b\u30bf\u30b0\u30cf\u30f3\u30c9\u30e9\u30af\u30e9\u30b9 \"{0}\" \u3092\u30ed\u30fc\u30c9\u3067\u304d\u307e\u305b\u3093
+jsp.error.unable.compile=JSP\u306e\u30af\u30e9\u30b9\u3092\u30b3\u30f3\u30d1\u30a4\u30eb\u3067\u304d\u307e\u305b\u3093
+jsp.error.unable.load=JSP\u306e\u30af\u30e9\u30b9\u3092\u30ed\u30fc\u30c9\u3067\u304d\u307e\u305b\u3093
+jsp.error.unable.rename=\u30af\u30e9\u30b9\u30d5\u30a1\u30a4\u30eb {0} \u3092 {1} \u306b\u30d5\u30a1\u30a4\u30eb\u540d\u3092\u5909\u66f4\u3067\u304d\u307e\u305b\u3093
+jsp.error.mandatory.attribute={0}: \u5fc5\u9808\u5c5e\u6027 {1} \u304c\u3042\u308a\u307e\u305b\u3093
+jsp.engine.info=Jasper JSP 2.0\u30a8\u30f3\u30b8\u30f3
+jsp.error.invalid.expression="{0}" \u306f\u7121\u52b9\u306a\u5f0f\u3092\u542b\u3093\u3067\u3044\u307e\u3059: {1}
+jsp.error.invalid.attribute={0}\u306f\u7121\u52b9\u306a\u5c5e\u6027\u3092\u6301\u3063\u3066\u3044\u307e\u3059: {1}
+jsp.error.usebean.class.notfound=\u30af\u30e9\u30b9: {0} \u304c\u898b\u3064\u304b\u308a\u307e\u305b\u3093
+jsp.error.file.cannot.read=\u30d5\u30a1\u30a4\u30eb\u304c\u8aad\u3081\u307e\u305b\u3093: {0}
+jsp.error.file.already.registered=\u30d5\u30a1\u30a4\u30eb {0} \u306e\u518d\u5e30\u7684\u306a\u53d6\u308a\u8fbc\u307f\u3067\u3059
+jsp.error.file.not.registered=include\u5c5e\u6027\u4e2d\u306e\u30d5\u30a1\u30a4\u30eb {0} \u304c\u5b58\u5728\u3057\u307e\u305b\u3093
+jsp.error.quotes.unterminated=\u5f15\u7528\u7b26\u304c\u7d42\u4e86\u3057\u3066\u3044\u307e\u305b\u3093
+jsp.error.attr.quoted=\u5c5e\u6027\u5024\u306f\u5f15\u7528\u7b26\u3067\u56f2\u308f\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093
+jsp.error.attr.novalue=\u5c5e\u6027 {0} \u306b\u306f\u5024\u304c\u6307\u5b9a\u3055\u308c\u3066\u3044\u307e\u305b\u3093
+jsp.error.tag.attr.unterminated=\u30bf\u30b0\u306e\u5c5e\u6027\u30ea\u30b9\u30c8\u304c\u7d42\u4e86\u3057\u3066\u3044\u307e\u305b\u3093
+jsp.error.param.noname=PARAM\u30bf\u30b0\u306bname\u5c5e\u6027\u304c\u3042\u308a\u307e\u305b\u3093
+jsp.error.param.novalue=PARAM\u30bf\u30b0\u306bvalue\u5c5e\u6027\u304c\u3042\u308a\u307e\u305b\u3093
+jsp.error.beans.nullbean=null\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u306bBean\u64cd\u4f5c\u3092\u304a\u3053\u306a\u304a\u3046\u3068\u3057\u307e\u3057\u305f
+jsp.error.beans.nobeaninfo=\u30bf\u30a4\u30d7 ''{0}'' \u306eBean\u306bBeanInfo\u304c\u306a\u3044\u306e\u3092\u691c\u51fa\u3057\u307e\u3057\u305f, \u30af\u30e9\u30b9\u304c\u5b58\u5728\u3057\u306a\u3044\u304b\u3082\u3057\u308c\u307e\u305b\u3093
+jsp.error.beans.introspection=\u30bf\u30a4\u30d7 ''{1}'' \u306eBean\u4e2d\u306e\u5c5e\u6027 ''{0}'' \u306eread\u30e1\u30bd\u30c3\u30c9\u3092\u5185\u7701\u4e2d\u306b\u4f8b\u5916\u304c\u767a\u751f\u3057\u307e\u3057\u305f:\n{2}
+jsp.error.beans.nomethod=\u30bf\u30a4\u30d7 ''{1}'' \u306eBean\u4e2d\u306e\u5c5e\u6027 ''{0}'' \u3092\u8aad\u307f\u8fbc\u3080\u30e1\u30bd\u30c3\u30c9\u3092\u767a\u898b\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f
+jsp.error.beans.nomethod.setproperty=\u30bf\u30a4\u30d7''{2}''\u306eBean\u306e\u30bf\u30a4\u30d7 ''{1}'' \u306e\u5c5e\u6027 ''{0}'' \u3092\u66f8\u304d\u8fbc\u3080\u30e1\u30bd\u30c3\u30c9\u3092\u767a\u898b\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f
+jsp.error.beans.noproperty=\u30bf\u30a4\u30d7 ''{1}'' \u306ebean\u4e2d\u306e\u5c5e\u6027 ''{0}'' \u306e\u60c5\u5831\u3092\u767a\u898b\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f
+jsp.error.beans.setproperty.noindexset=\u30a4\u30f3\u30c7\u30c3\u30af\u30b9\u4ed8\u304d\u306e\u5c5e\u6027\u3092\u6307\u5b9a\u3067\u304d\u307e\u305b\u3093
+jsp.error.include.tag=\u7121\u52b9\u306ajsp:include\u30bf\u30b0\u3067\u3059
+jsp.error.include.noflush=jsp:include\u30bf\u30b0\u306b \"flush=true\" \u3092\u5b9a\u7fa9\u3057\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093
+jsp.error.include.badflush=jsp:include page=\"...\" flush=\"true\" \u306f\u3001JSP 1.0\u3067\u306e\u307f\u6709\u52b9\u306a\u7d44\u307f\u5408\u308f\u305b\u3067\u3059
+jsp.error.attempt_to_clear_flushed_buffer=\u30a8\u30e9\u30fc: \u65e2\u306b\u30d5\u30e9\u30c3\u30b7\u30e5\u3055\u308c\u3066\u3044\u308b\u30d0\u30c3\u30d5\u30a1\u3092\u30af\u30ea\u30a2\u3057\u3088\u3046\u3068\u3057\u307e\u3057\u305f
+jsp.error.overflow=\u30a8\u30e9\u30fc: JSP\u30d0\u30c3\u30d5\u30a1\u304c\u30aa\u30fc\u30d0\u30fc\u30d5\u30ed\u30fc\u3057\u307e\u3057\u305f
+jsp.error.paramexpected=\"name\"\u5c5e\u6027 \u3068 \"value\" \u5c5e\u6027\u3092\u6301\u3064 \"jsp:param\" \u6a19\u6e96\u30a2\u30af\u30b7\u30e7\u30f3\u304c\u5fc5\u8981\u3067\u3059
+jsp.error.param.invalidUse=jsp:include\u3001jsp:forward\u3001\u53c8\u306fjsp:params\u8981\u7d20\u306e\u5916\u3067jsp:param\u30a2\u30af\u30b7\u30e7\u30f3\u3092\u4f7f\u7528\u3057\u3066\u306f\u3044\u3051\u307e\u305b\u3093
+jsp.error.params.invalidUse=jsp:params\u306fjsp:plugin\u306e\u76f4\u63a5\u306e\u5b50\u4f9b\u3067\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093
+jsp.error.fallback.invalidUse=jsp:fallback\u306fjsp:plugin\u306e\u76f4\u63a5\u306e\u5b50\u4f9b\u3067\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093
+jsp.error.namedAttribute.invalidUse=jsp:attribute\u306f\u6a19\u6e96\u53c8\u306f\u30ab\u30b9\u30bf\u30e0\u30a2\u30af\u30b7\u30e7\u30f3\u306e\u526f\u8981\u7d20\u3067\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093
+jsp.error.jspbody.invalidUse=jsp:body\u306f\u6a19\u6e96\u53c8\u306f\u30ab\u30b9\u30bf\u30e0\u30a2\u30af\u30b7\u30e7\u30f3\u306e\u526f\u8981\u7d20\u3067\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093
+jsp.error.closeindividualparam=param\u30bf\u30b0\u306f \"/>\" \u3067\u9589\u3058\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093
+jsp.error.closeparams=param\u30bf\u30b0\u306f/params\u3067\u9589\u3058\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093
+jsp.error.params.emptyBody=jsp:params\u306f\u5c11\u306a\u304f\u3068\u3082\u4e00\u3064\u306e\u30cd\u30b9\u30c8\u3057\u305fjsp:param\u3092\u542b\u307e\u306d\u3070\u3044\u3051\u307e\u305b\u3093
+jsp.error.params.illegalChild=jsp:params\u306fjsp:param\u4ee5\u5916\u306e\u30cd\u30b9\u30c8\u3057\u305f\u8981\u7d20\u3092\u542b\u3093\u3067\u306f\u3044\u3051\u307e\u305b\u3093
+jsp.error.plugin.notype=jsp:plugin\u3067type\u5c5e\u6027\u304c\u5ba3\u8a00\u3055\u308c\u3066\u3044\u307e\u305b\u3093
+jsp.error.plugin.badtype=jsp:plugin\u306e 'type'\u5c5e\u6027\u306e\u5024\u304c\u7121\u52b9\u3067\u3059: 'bean'\u53c8\u306f'applet'\u3067\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093
+jsp.error.plugin.nocode=jsp:plugin\u3067code\u5c5e\u6027\u304c\u5ba3\u8a00\u3055\u308c\u3066\u3044\u307e\u305b\u3093
+jsp.error.ise_on_clear=\u30d0\u30c3\u30d5\u30a1\u30b5\u30a4\u30ba\u304c0\u306e\u6642\u306bclear()\u3092\u5b9f\u884c\u3057\u3066\u3082\u7121\u52b9\u3067\u3059
+jsp.error.setproperty.beanNotFound=setProperty: Bean {0} \u304c\u898b\u3064\u304b\u308a\u307e\u305b\u3093
+jsp.error.getproperty.beanNotFound=getProperty: Bean {0} \u304c\u898b\u3064\u304b\u308a\u307e\u305b\u3093
+jsp.error.setproperty.ClassNotFound=setProperty: \u30af\u30e9\u30b9 {0} \u304c\u898b\u3064\u304b\u308a\u307e\u305b\u3093
+# typo ?
+#jsp.error.setproperty.invalidSayntax=setProperty: property=*\u306e\u5834\u5408\u306fnull\u3067\u306a\u3044\u5024\u3092\u6307\u5b9a\u3067\u304d\u307e\u305b\u3093
+jsp.error.setproperty.invalidSyntax=setProperty: property=*\u306e\u5834\u5408\u306fnull\u3067\u306a\u3044\u5024\u3092\u6307\u5b9a\u3067\u304d\u307e\u305b\u3093
+jsp.error.setproperty.beanInfoNotFound=setproperty: Bean {0} \u306ebeanInfo\u304c\u898b\u3064\u304b\u308a\u307e\u305b\u3093
+jsp.error.setproperty.paramOrValue=setProperty: param\u5c5e\u6027\u304bvalue\u5c5e\u6027\u306e\u3069\u3061\u3089\u304b\u4e00\u3064\u3060\u3051\u3092\u6307\u5b9a\u3067\u304d\u307e\u3059
+jsp.error.setproperty.arrayVal=setProperty: \u5c5e\u6027\u914d\u5217 {0} \u3092\u6587\u5b57\u5217\u5b9a\u6570\u5024\u3067\u6307\u5b9a\u3067\u304d\u307e\u305b\u3093
+jsp.warning.keepgen=\u8b66\u544a: initParam keepgenerated\u306e\u5024\u304c\u7121\u52b9\u3067\u3059\u3002 \u30c7\u30d5\u30a9\u30eb\u30c8\u5024 \"false\" \u3092\u4f7f\u7528\u3057\u307e\u3059
+jsp.warning.xpoweredBy=\u8b66\u544a: Invalid value for the initParam xpoweredBy\u306e\u5024\u304c\u7121\u52b9\u3067\u3059\u3002\u30c7\u30d5\u30a9\u30eb\u30c8\u5024 \"false\" \u3092\u4f7f\u7528\u3057\u307e\u3059
+jsp.warning.enablePooling=\u8b66\u544a: initParam enablePooling\u304c\u7121\u52b9\u306a\u5024\u3067\u3059\u3002\"true\"\u306e\u30c7\u30d5\u30a9\u30eb\u30c8\u5024\u3092\u4f7f\u7528\u3057\u307e\u3059
+jsp.warning.invalidTagPoolSize=\u8b66\u544a: tagPoolSize\u306e\u521d\u671f\u30d1\u30e9\u30e1\u30fc\u30bf\u304c\u7121\u52b9\u306a\u5024\u3067\u3059\u3002{0}\u306e\u30c7\u30d5\u30a9\u30eb\u30c8\u30b5\u30a4\u30ba\u3092\u4f7f\u7528\u3057\u307e\u3059
+jsp.warning.mappedFile=\u8b66\u544a: initParam mappedFile\u306e\u5024\u304c\u7121\u52b9\u3067\u3059\u3002\u30c7\u30d5\u30a9\u30eb\u30c8\u5024 \"false\" \u3092\u4f7f\u7528\u3057\u307e\u3059
+jsp.warning.sendErrToClient=\u8b66\u544a: initParam sendErrToClient\u306e\u5024\u304c\u7121\u52b9\u3067\u3059\u3002\u30c7\u30d5\u30a9\u30eb\u30c8\u5024 \"false\" \u3092\u4f7f\u7528\u3057\u307e\u3059
+jsp.warning.classDebugInfo=\u8b66\u544a: initParam classDebugInfo\u306e\u5024\u304c\u7121\u52b9\u3067\u3059\u3002\u30c7\u30d5\u30a9\u30eb\u30c8\u5024 \"false\"\u3092\u4f7f\u7528\u3057\u307e\u3059
+jsp.warning.checkInterval=\u8b66\u544a: initParam checkInterval\u306e\u5024\u304c\u7121\u52b9\u3067\u3059\u3002\"300\"\u79d2\u306e\u30c7\u30d5\u30a9\u30eb\u30c8\u5024\u3092\u4f7f\u7528\u3057\u307e\u3059
+jsp.warning.development=\u8b66\u544a: initParam development\u306e\u5024\u304c\u7121\u52b9\u3067\u3059\u3002\"true\"\u306e\u30c7\u30d5\u30a9\u30eb\u30c8\u5024\u3092\u4f7f\u7528\u3057\u307e\u3059
+jsp.warning.fork=\u8b66\u544a: initParam fork\u306e\u5024\u304c\u7121\u52b9\u3067\u3059\u3002\"true\"\u306e\u30c7\u30d5\u30a9\u30eb\u30c8\u5024\u3092\u4f7f\u7528\u3057\u307e\u3059
+jsp.warning.reloading=\u8b66\u544a: initParam reloading\u306e\u5024\u304c\u7121\u52b9\u3067\u3059\u3002\"true\"\u306e\u30c7\u30d5\u30a9\u30eb\u30c8\u5024\u3092\u4f7f\u7528\u3057\u307e\u3059
+jsp.warning.dumpSmap=\u8b66\u544a: initParam dumpSmap\u306e\u5024\u304c\u7121\u52b9\u3067\u3059\u3002\"false\"\u306e\u30c7\u30d5\u30a9\u30eb\u30c8\u5024\u3092\u4f7f\u7528\u3057\u307e\u3059
+jsp.warning.genchararray=\u8b66\u544a: initParam genStrAsCharArray\u306e\u5024\u304c\u7121\u52b9\u3067\u3059\u3002\"false\"\u306e\u30c7\u30d5\u30a9\u30eb\u30c8\u5024\u3092\u4f7f\u7528\u3057\u307e\u3059
+jsp.warning.suppressSmap=\u8b66\u544a: initParam suppressSmap\u306e\u5024\u304c\u7121\u52b9\u3067\u3059\u3002\u30c7\u30d5\u30a9\u30eb\u30c8\u5024 \"false\" \u3092\u4f7f\u7528\u3057\u307e\u3059
+jsp.error.badtaglib=\u30bf\u30b0\u30e9\u30a4\u30d6\u30e9\u30ea {0} \u3092\u30aa\u30fc\u30d7\u30f3\u3067\u304d\u307e\u305b\u3093: {1}
+jsp.error.badGetReader=\u30b9\u30c8\u30ea\u30fc\u30e0\u304c\u30d0\u30c3\u30d5\u30a1\u30ea\u30f3\u30b0\u3055\u308c\u3066\u3044\u306a\u3044\u5834\u5408\u306b\u306f\u3001Reader\u3092\u4f5c\u6210\u3067\u304d\u307e\u305b\u3093
+jsp.warning.unknown.element.in.taglib=taglib\u4e2d\u306b\u672a\u77e5\u306e\u8981\u7d20 ({0}) \u304c\u3042\u308a\u307e\u3059
+jsp.warning.unknown.element.in.tag=tag\u4e2d\u306b\u672a\u77e5\u306e\u8981\u7d20 ({0}) \u304c\u3042\u308a\u307e\u3059
+jsp.warning.unknown.element.in.tagfile=tag-file\u4e2d\u306b\u672a\u77e5\u306e\u8981\u7d20 ({0}) \u304c\u3042\u308a\u307e\u3059
+jsp.warning.unknown.element.in.attribute=attribute\u4e2d\u306b\u672a\u77e5\u306e\u8981\u7d20 ({0}) \u304c\u3042\u308a\u307e\u3059
+jsp.warning.unknown.element.in.variable=variable\u4e2d\u306b\u672a\u77e5\u306e\u8981\u7d20 ({0}) \u304c\u3042\u308a\u307e\u3059
+jsp.warning.unknown.element.in.validator=validator\u4e2d\u306b\u672a\u77e5\u306e\u8981\u7d20 ({0}) \u304c\u3042\u308a\u307e\u3059
+jsp.warning.unknown.element.in.initParam=validator\u306einit-param\u4e2d\u306b\u672a\u77e5\u306e\u8981\u7d20 ({0}) \u304c\u3042\u308a\u307e\u3059
+jsp.warning.unknown.element.in.function=function\u4e2d\u306b\u672a\u77e5\u306e\u8981\u7d20 ({0}) \u304c\u3042\u308a\u307e\u3059
+jsp.error.more.than.one.taglib=TLD\u306e\u4e2d\u306b\u8907\u6570\u306etaglib\u304c\u5b58\u5728\u3057\u307e\u3059: {0}
+jsp.error.teiclass.instantiation=TagExtraInfo class\u306e\u30ed\u30fc\u30c9\u53c8\u306f\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u5316\u306b\u5931\u6557\u3057\u307e\u3057\u305f: {0}
+jsp.error.non_null_tei_and_var_subelems=\u30bf\u30b0 {0} \u306f\u4e00\u3064\u4ee5\u4e0a\u306evariable\u526f\u8981\u7d20\u3068\u4e00\u3064\u4ee5\u4e0a\u306eVariableInfo\u3092\u8fd4\u3059TagExtraInfo\u30af\u30e9\u30b9\u3092\u6301\u3063\u3066\u3044\u307e\u3059
+jsp.error.parse.error.in.TLD=\u30bf\u30b0\u30e9\u30a4\u30d6\u30e9\u30ea\u8a18\u8ff0\u5b50 {0} \u4e2d\u306e\u89e3\u6790\u30a8\u30e9\u30fc\u3067\u3059
+jsp.error.unable.to.open.TLD=\u30bf\u30b0\u30e9\u30a4\u30d6\u30e9\u30ea\u8a18\u8ff0\u5b50 {0} \u3092\u30aa\u30fc\u30d7\u30f3\u3067\u304d\u307e\u305b\u3093
+jsp.buffer.size.zero=\u30d0\u30c3\u30d5\u30a1\u30b5\u30a4\u30ba\u304c0\u4ee5\u4e0b\u3067\u3059
+jsp.error.file.not.found=JSP \u30d5\u30a1\u30a4\u30eb \"{0}\" \u304c\u898b\u3064\u304b\u308a\u307e\u305b\u3093
+jsp.message.copyinguri={0} \u3092 {1} \u306b\u30b3\u30d4\u30fc\u3057\u307e\u3059
+jsp.message.htmlcomment=\n\u524a\u9664\u3059\u308b\u30b3\u30e1\u30f3\u30c8: \t{0}
+jsp.message.handling_directive=\n\u51e6\u7406\u3059\u308b\u6307\u793a\u5b50: {0}\t{1}
+jsp.message.handling_plugin=\nPlugin: {0}
+jsp.message.package_name_is=\u30d1\u30c3\u30b1\u30fc\u30b8\u540d: {0}
+jsp.message.class_name_is=\u30af\u30e9\u30b9\u540d: {0}
+jsp.message.java_file_name_is=Java\u30d5\u30a1\u30a4\u30eb\u540d: {0}
+jsp.message.class_file_name_is=\u30af\u30e9\u30b9\u30d5\u30a1\u30a4\u30eb\u540d: {0}
+jsp.message.accepted={1} \u3067 {0} \u3092\u53d7\u3051\u5165\u308c\u307e\u3059
+jsp.message.adding_jar=jar {0} \u3092\u30af\u30e9\u30b9\u30d1\u30b9\u306b\u8ffd\u52a0\u3057\u307e\u3059
+jsp.message.compiling_with={0} \u3092\u30b3\u30f3\u30d1\u30a4\u30eb\u4e2d\u3067\u3059
+jsp.message.template_text=\u30c6\u30f3\u30d7\u30ec\u30fc\u30c8\u30c6\u30ad\u30b9\u30c8
+jsp.error.missing_attribute=TLD\u53c8\u306f\u30bf\u30b0\u30d5\u30a1\u30a4\u30eb\u306b\u3088\u308b\u3068\u3001\u5c5e\u6027 {0} \u306f\u30bf\u30b0 {1} \u306b\u306f\u5fc5\u9808\u3067\u3059
+jsp.error.bad_attribute=TLD\u306b\u3088\u308b\u3068\u3001\u30bf\u30b0 {1} \u306e\u5c5e\u6027 {0} \u306f\u7121\u52b9\u3067\u3059
+jsp.error.tld.unable_to_read=JAR\u30d5\u30a1\u30a4\u30eb \"{0}\" \u304b\u3089TLD \"{1}\" \u3092\u8aad\u307f\u8fbc\u3081\u307e\u305b\u3093: {2}
+jsp.error.tld.unable_to_get_jar=TLD\u3092\u542b\u3080JAR\u30ea\u30bd\u30fc\u30b9 \"{0}\" \u3092\u53d6\u5f97\u3067\u304d\u307e\u305b\u3093 : {1}
+jsp.error.tld.missing_jar=TLD\u3092\u542b\u3080JAR\u30ea\u30bd\u30fc\u30b9 \"{0}\" \u304c\u3042\u308a\u307e\u305b\u3093
+jsp.error.webxml_not_found=web.xml\u304c\u898b\u3064\u304b\u308a\u307e\u305b\u3093
+jsp.cmd_line.usage=\u4f7f\u7528\u6cd5:  [-dd <\u51fa\u529b\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u306e\u30d1\u30b9>] [-keepgenerated] \
+<.jsp\u30d5\u30a1\u30a4\u30eb\u7fa4>
+jsp.message.cp_is=\u30af\u30e9\u30b9\u30d1\u30b9 {0} \u306f {1} \u3067\u3059
+jsp.error.unable.to_load_taghandler_class=\u30bf\u30b0\u30cf\u30f3\u30c9\u30e9\u30af\u30e9\u30b9 {0} \u3092 {1} \u306e\u305f\u3081\u306b\u30ed\u30fc\u30c9\u3067\u304d\u307e\u305b\u3093
+jsp.error.unable.to_find_method=\u5c5e\u6027 {0} \u306esetter\u30e1\u30bd\u30c3\u30c9\u304c\u898b\u3064\u304b\u308a\u307e\u305b\u3093
+jsp.error.unable.to_convert_string=\u5c5e\u6027 {1}\u306e\u6587\u5b57\u5217\u3092 {0}\u306b\u5909\u63db\u3067\u304d\u307e\u305b\u3093
+jsp.error.unable.to_introspect=\u30bf\u30b0\u30cf\u30f3\u30c9\u30e9\u30af\u30e9\u30b9 {0} \u3092 {1} \u306e\u305f\u3081\u306b\u5185\u7701\u3067\u304d\u307e\u305b\u3093
+jsp.error.bad_tag=\u30d7\u30ec\u30d5\u30a3\u30c3\u30af\u30b9 {1}\u3067\u30a4\u30f3\u30dd\u30fc\u30c8\u3055\u308c\u305f\u30bf\u30b0\u30e9\u30a4\u30d6\u30e9\u30ea\u306b\u306f\u3001\u30bf\u30b0 {0} \u306f\u5b58\u5728\u3057\u307e\u305b\u3093
+jsp.error.xml.bad_tag=URI \"{1}\" \u306b\u95a2\u9023\u3065\u3051\u3089\u308c\u305f\u30bf\u30b0\u30e9\u30a4\u30d6\u30e9\u30ea\u306e\u4e2d\u306b\u306f\u30bf\u30b0 \"{0}\" \u306f\u5b9a\u7fa9\u3055\u308c\u3066\u3044\u307e\u305b\u3093
+jsp.error.bad_string_Character=\u9577\u30550\u306e\u914d\u5217\u304b\u3089\u306f\u6587\u5b57\u3092\u53d6\u5f97\u3067\u304d\u307e\u305b\u3093
+jsp.error.bad_string_char=\u9577\u30550\u306e\u914d\u5217\u304b\u3089\u306f\u6587\u5b57\u3092\u53d6\u5f97\u3067\u304d\u307e\u305b\u3093
+jsp.warning.compiler.class.cantcreate=\u6307\u5b9a\u3055\u308c\u305f\u30b3\u30f3\u30d1\u30a4\u30e9\u30d7\u30e9\u30b0\u30a4\u30f3\u30af\u30e9\u30b9 {0} \u306e\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u3092 {1} \u306e\u305f\u3081\u306b\u4f5c\u6210\u3067\u304d\u307e\u305b\u3093\u3002\u30c7\u30d5\u30a9\u30eb\u30c8\u3092Sun\u306eJava\u30b3\u30f3\u30d1\u30a4\u30e9\u306b\u3057\u307e\u3059\u3002
+jsp.warning.compiler.class.notfound=\u6307\u5b9a\u3055\u308c\u305f\u30b3\u30f3\u30d1\u30a4\u30e9\u30d7\u30e9\u30b0\u30a4\u30f3\u30af\u30e9\u30b9 {0} \u304c\u898b\u3064\u304b\u308a\u307e\u305b\u3093\u3002not found. \u30c7\u30d5\u30a9\u30eb\u30c8\u3092Sun\u306eJava\u30b3\u30f3\u30d1\u30a4\u30e9\u306b\u3057\u307e\u3059\u3002
+jsp.warning.compiler.path.notfound=\u6307\u5b9a\u3055\u308c\u305f\u30b3\u30f3\u30d1\u30a4\u30e9\u30d1\u30b9 {0} \u304c\u898b\u3064\u304b\u308a\u307e\u305b\u3093\u3002\u30b7\u30b9\u30c6\u30e0\u306ePATH\u3092\u30c7\u30d5\u30a9\u30eb\u30c8\u306b\u3057\u307e\u3059\u3002
+jsp.error.jspc.uriroot_not_dir=-uriroot \u30aa\u30d7\u30b7\u30e7\u30f3\u306f\u3001\u65e2\u306b\u5b58\u5728\u3059\u308b\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u3092\u6307\u5b9a\u3057\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093
+jsp.error.jspc.missingTarget=\u30bf\u30fc\u30b2\u30c3\u30c8\u304c\u3042\u308a\u307e\u305b\u3093: -webapp\u53c8\u306f-uriroot\uff0c\u53c8\u306f\u4e00\u3064\u4ee5\u4e0a\u306eJSP\u30da\u30fc\u30b8\u3092\u6307\u5b9a\u3057\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093
+jsp.error.jspc.no_uriroot=uriroot\u304c\u6307\u5b9a\u3055\u308c\u3066\u3044\u306a\u3044\u306e\u3067\u3001\u6307\u5b9a\u3055\u308c\u305fJSP\u30d5\u30a1\u30a4\u30eb(\u7fa4)\u3092\u914d\u7f6e\u3067\u304d\u307e\u305b\u3093
+jspc.implicit.uriRoot=uriRoot\u306f\u30c7\u30d5\u30a9\u30eb\u30c8"{0}"\u306b\u8a2d\u5b9a\u3055\u308c\u307e\u3059
+jspc.usage=\u4f7f\u7528\u6cd5: jspc <options> [--] <jsp files>\n\
+JSP\u30d5\u30a1\u30a4\u30eb\u306e\u5834\u6240\u306f\u6b21\u306e\u30aa\u30d7\u30b7\u30e7\u30f3\u3067\u6307\u5b9a\u3059\u308b\u304b\u3001\n\
+\    -webapp <dir>   web-app\u3092\u542b\u3080\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u3002\u3059\u3079\u3066\u306eJSP\u30d5\u30a1\u30a4\u30eb\u306f\n\
+\                    \u518d\u5e30\u7684\u306b\u89e3\u6790\u3055\u308c\u308b\n\
+\u53c8\u306f\u6b21\u306e\u4efb\u610f\u306e\u6570\u306e\u30d5\u30a1\u30a4\u30eb\u3067\u6307\u5b9a\u3057\u307e\u3059\u3002\n\
+\    <file>          JSP\u3068\u3057\u3066\u89e3\u6790\u3055\u308c\u308b\u30d5\u30a1\u30a4\u30eb\n\
+\u30aa\u30d7\u30b7\u30e7\u30f3\u306f\u4ee5\u4e0b\u306e\u901a\u308a\u3067\u3059\n\
+\    -help           \u3053\u306e\u30d8\u30eb\u30d7\u30e1\u30c3\u30bb\u30fc\u30b8\u306e\u8868\u793a\n\
+\    -v              Verbose\u30e2\u30fc\u30c9\n\
+\    -d <dir>        \u51fa\u529b\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\n\
+\    -l              \u5931\u6557\u3057\u305fJSP\u30da\u30fc\u30b8\u306e\u540d\u524d\u306e\u51fa\u529b\n\
+\    -s              \u6210\u529f\u3057\u305fJSP\u30da\u30fc\u30b8\u306e\u540d\u524d\u306e\u51fa\u529b\n\
+\    -p <name>       \u30bf\u30fc\u30b2\u30c3\u30c8\u30d1\u30c3\u30b1\u30fc\u30b8\u306e\u540d\u524d  (\u30c7\u30d5\u30a9\u30eb\u30c8\u306forg.apache.jsp)\n\
+\    -c <name>       \u30bf\u30fc\u30b2\u30c3\u30c8\u30af\u30e9\u30b9\u306e\u540d\u524d (\u6700\u521d\u306eJSP\u30da\u30fc\u30b8\u3060\u3051\u306b\u9069\u7528\u3055\u308c\u308b)\n\
+\    -mapped         JSP\u306e\u5404HTML\u884c\u3054\u3068\u306bwrite()\u30b3\u30fc\u30eb\u3092\u751f\u6210\n\
+\    -die[#]         \u81f4\u547d\u7684\u30a8\u30e9\u30fc\u306b\u30a8\u30e9\u30fc\u30ea\u30bf\u30fc\u30f3\u30b3\u30fc\u30c9(#)\u3092\u751f\u6210 (\u30c7\u30d5\u30a9\u30eb\u30c8\u306f1)\n\
+\    -uribase <dir>  \u30b3\u30f3\u30d1\u30a4\u30eb\u304c\u76f8\u5bfe\u7684\u306b\u304a\u3053\u306a\u308f\u308c\u308buri\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\n\
+\                    (\u30c7\u30d5\u30a9\u30eb\u30c8\u306f"/")\n\
+\    -uriroot <dir>  -webapp\u3068\u540c\u3058\n\
+\    -compile        \u751f\u6210\u3057\u305f\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8\u306e\u30b3\u30f3\u30d1\u30a4\u30eb\n\
+\    -webinc <file>  \u30d5\u30a1\u30a4\u30eb\u306b\u90e8\u5206\u7684\u306a\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8\u30de\u30c3\u30d4\u30f3\u30b0\u3092\u4f5c\u6210\n\
+\    -webxml <file>  \u30d5\u30a1\u30a4\u30eb\u306b\u5b8c\u5168\u306aweb.xml\u3092\u4f5c\u6210\n\
+\    -ieplugin <clsid>  Internet Explorer\u306eJava Plugin\u306eclassid\n\
+\    -classpath <path>  java.class.path\u30b7\u30b9\u30c6\u30e0\u30d7\u30ed\u30d1\u30c6\u30a3\u306e\u4e0a\u66f8\u304d\n\
+\    -xpoweredBy        X-Powered-By\u30ec\u30b9\u30dd\u30f3\u30b9\u30d8\u30c3\u30c0\u306e\u8ffd\u52a0\n\
+\    -trimSpaces        \u30a2\u30af\u30b7\u30e7\u30f3\u3084\u6307\u793a\u5b50\u306e\u9593\u306e\u30c6\u30f3\u30d7\u30ec\u30fc\u30c8\u30c6\u30ad\u30b9\u30c8\u4e2d\u306e\u30b9\u30da\u30fc\u30b9\u3092\u524a\u9664\n\
+\    -trimSpaces        Trim spaces in template text between actions, directives\n\
+\    -javaEncoding <enc> Set the encoding charset for Java classes (default UTF-8)\n\
+\    -source <version>   Set the -source argument to the compiler (default 1.4)\n\
+\    -target <version>   Set the -target argument to the compiler (default 1.4)\n\
+
+jspc.webxml.header=<?xml version="1.0" encoding="ISO-8859-1"?>\n\
+\n\
+<!DOCTYPE web-app\n\
+\    PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"\n\
+\    "http://java.sun.com/dtd/web-app_2_3.dtd">\n\
+<!--\n\
+Automatically created by Apache Jakarta Tomcat JspC.\n\
+-->\n\
+<web-app>\n\
+\n
+jspc.webxml.footer=\n\
+</web-app>\n\
+\n
+jspc.webinc.header=\n\
+<!--\n\
+Automatically created by Apache Jakarta Tomcat JspC.\n\
+Place this fragment in the web.xml before all icon, display-name,\n\
+description, distributable, and context-param elements.\n\
+-->\n
+jspc.webinc.footer=\n\
+<!--\n\
+All session-config, mime-mapping, welcome-file-list, error-page, taglib,\n\
+resource-ref, security-constraint, login-config, security-role,\n\
+env-entry, and ejb-ref elements should follow this fragment.\n\
+-->\n
+jspc.webinc.insertEnd=<!-- JSPC servlet mappings end -->
+jspc.webinc.insertStart=<!-- JSPC servlet mappings start -->
+jspc.error.jasperException=\u30a8\u30e9\u30fc: \u30d5\u30a1\u30a4\u30eb ''{0}'' \u306f\u6b21\u306e\u4f8b\u5916\u3092\u767a\u751f\u3057\u307e\u3057\u305f: {1}
+jspc.error.generalException=\u30a8\u30e9\u30fc: \u30d5\u30a1\u30a4\u30eb ''{0}'' \u306f\u6b21\u306e\u4f8b\u5916\u3092\u767a\u751f\u3057\u307e\u3057\u305f:
+jspc.error.fileDoesNotExist=\u30d5\u30a1\u30a4\u30eb\u5f15\u6570 ''{0}'' \u306f\u5b58\u5728\u3057\u307e\u305b\u3093\u3002
+jspc.error.emptyWebApp=-webapp\u30aa\u30d7\u30b7\u30e7\u30f3\u306b\u306f\u3001\u30d5\u30a1\u30a4\u30eb\u5f15\u6570\u304c\u5fc5\u8981\u3067\u3059
+jsp.error.library.invalid=\u30e9\u30a4\u30d6\u30e9\u30ea{0}\u306b\u5f93\u3046\u3068JSP\u30da\u30fc\u30b8\u306f\u7121\u52b9\u3067\u3059: {1}
+jsp.error.tlvclass.instantiation=TagLibraryValidator\u30af\u30e9\u30b9\u306e\u30ed\u30fc\u30c9\u53c8\u306f\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u5316\u306b\u5931\u6557\u3057\u307e\u3057\u305f: {0}
+jsp.error.tlv.invalid.page={0} \u306b\u5bfe\u3059\u308bTagLibraryValidator\u306e\u691c\u8a3c\u30a8\u30e9\u30fc\u30e1\u30c3\u30bb\u30fc\u30b8\u3067\u3059 ({1})
+jsp.error.tei.invalid.attributes={0} \u306b\u5bfe\u3059\u308bTagExtraInfo\u304b\u3089\u306e\u691c\u8a3c\u30a8\u30e9\u30fc\u30e1\u30c3\u30bb\u30fc\u30b8\u3067\u3059
+jsp.parser.sax.propertynotsupported=SAX\u30d7\u30ed\u30d1\u30c6\u30a3\u304c\u30b5\u30dd\u30fc\u30c8\u3055\u308c\u307e\u305b\u3093: {0}
+jsp.parser.sax.propertynotrecognized=SAX\u30d7\u30ed\u30d1\u30c6\u30a3\u304c\u8a8d\u8b58\u3055\u308c\u307e\u305b\u3093: {0}
+jsp.parser.sax.featurenotsupported=SAX\u30d5\u30a3\u30fc\u30c1\u30e3\u304c\u30b5\u30dd\u30fc\u30c8\u3055\u308c\u307e\u305b\u3093: {0}
+jsp.parser.sax.featurenotrecognized=SAX\u30d5\u30a3\u30fc\u30c1\u30e3\u304c\u8a8d\u8b58\u3055\u308c\u307e\u305b\u3093: {0}
+jsp.error.no.more.content=\u5fc5\u8981\u306a\u89e3\u6790\u4e2d\u306b\u5185\u5bb9\u306e\u6700\u5f8c\u307e\u3067\u9054\u3057\u307e\u3057\u305f: \u30bf\u30b0\u306e\u30cd\u30b9\u30c8\u306e\u30a8\u30e9\u30fc\u304b\u3082\u3057\u308c\u307e\u305b\u3093
+jsp.error.parse.xml=\u30d5\u30a1\u30a4\u30eb{0}\u306eXML\u89e3\u6790\u30a8\u30e9\u30fc
+jsp.error.parse.xml.line=\u30d5\u30a1\u30a4\u30eb{0}\u306eXML\u89e3\u6790\u30a8\u30e9\u30fc: (\u884c {1}, \u5217 {2})
+jsp.error.parse.xml.scripting.invalid.body={0} \u8981\u7d20\u306e\u30dc\u30c7\u30a3\u306fXML\u8981\u7d20\u3092\u542b\u3093\u3067\u306f\u3044\u3051\u307e\u305b\u3093
+jsp.error.internal.tldinit=TldLocationsCache\u3092\u521d\u671f\u5316\u4e2d\u306e\u4f8b\u5916\u3067\u3059: {0}
+jsp.error.internal.filenotfound=\u5185\u90e8\u30a8\u30e9\u30fc: \u30d5\u30a1\u30a4\u30eb {0} \u304c\u898b\u3064\u304b\u308a\u307e\u305b\u3093
+jsp.error.internal.evaluator_not_found=\u5185\u90e8\u30a8\u30e9\u30fc: \u5f0f\u691c\u8a3c\u5668\u3092\u30ed\u30fc\u30c9\u3067\u304d\u307e\u305b\u3093
+jsp.error.parse.xml.invalidPublicId=\u7121\u52b9\u306aPUBLIC ID: {0}
+jsp.error.include.flush.invalid.value=flush\u5c5e\u6027\u306b\u7121\u52b9\u306a\u5024\u304c\u6307\u5b9a\u3055\u308c\u3066\u3044\u307e\u3059: {0}
+jsp.error.unsupported.encoding=\u30b5\u30dd\u30fc\u30c8\u3055\u308c\u3066\u3044\u306a\u3044\u30a8\u30f3\u30b3\u30fc\u30c7\u30a3\u30f3\u30b0\u3067\u3059: {0}
+tld.error.variableNotAllowed=null\u3067\u306a\u3044\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u3092\u8fd4\u3059TagExtraInfo\u3092\u6301\u3064\u4e00\u3064\u4ee5\u4e0a\u306e\u5909\u6570\u526f\u8981\u7d20\u3092\u6301\u3064\u30bf\u30b0\u306f\u30a8\u30e9\u30fc\u3067\u3059\u3002
+jsp.error.tldInWebDotXmlNotFound=web.xml\u3067\u6307\u5b9a\u3055\u308c\u305fURI {0} \u306bTLD\u3092\u914d\u7f6e\u3067\u304d\u307e\u305b\u3093
+jsp.error.taglibDirective.absUriCannotBeResolved=\u7d76\u5bfeURI:  {0} \u306fweb.xml\u3068\u3053\u306e\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u3092\u914d\u5099\u3057\u305fJAR\u30d5\u30a1\u30a4\u30eb\u306e\u3069\u3061\u3089\u304b\u3067\u3082\u89e3\u6c7a\u3067\u304d\u307e\u305b\u3093
+jsp.error.taglibDirective.missing.location=taglib\u6307\u793a\u5b50\u306e\u4e2d\u306b'uri'\u5c5e\u6027\u3068'tagdir'\u5c5e\u6027\u306e\u3069\u3061\u3089\u3082\u6307\u5b9a\u3055\u308c\u3066\u3044\u307e\u305b\u3093
+jsp.error.taglibDirective.both_uri_and_tagdir=\'uri\'\u5c5e\u6027 \u3068 \'tagdir\'\u5c5e\u6027\u306e\u4e21\u65b9\u304c\u6307\u5b9a\u3055\u308c\u3066\u3044\u307e\u3059
+jsp.error.invalid.tagdir=\u30bf\u30b0\u30d5\u30a1\u30a4\u30eb\u30c7\u30a3\u30ec\u30af\u30c8\u30ea {0} \u304c\"/WEB-INF/tags\"\u3067\u59cb\u307e\u308a\u307e\u305b\u3093
+jsp.error.unterminated.user.tag=\u672a\u7d42\u4e86\u306e\u30e6\u30fc\u30b6\u5b9a\u7fa9\u30bf\u30b0: \u7d42\u4e86\u30bf\u30b0 {0} \u304c\u898b\u3064\u304b\u3089\u306a\u3044\u304b\u3001\u30cd\u30b9\u30c8\u304c\u9593\u9055\u3063\u3066\u3044\u307e\u3059
+#jspx.error.templateDataNotInJspCdata=Validation Error: Element &lt;{0}&gt; cannot have template data. Template data must be encapsulated within a &lt;jsp:cdata&gt; element. [JSP1.2 PFD section 5.1.9]\nTemplate data in error: {1}
+jspx.error.templateDataNotInJspCdata=\u8a3c\u660e\u30a8\u30e9\u30fc: \u8981\u7d20&lt;{0}&gt;\u306f\u30c6\u30f3\u30d7\u30ec\u30fc\u30c8\u30c7\u30fc\u30bf\u3092\u6301\u3064\u3053\u3068\u306f\u3067\u304d\u307e\u305b\u3093\u3002\u30c6\u30f3\u30d7\u30ec\u30fc\u30c8\u30c7\u30fc\u30bf\u306f\u3001&lt;jsp:text&gt;\u8981\u7d20\u306e\u4e2d\u3067\u96a0\u853d\u3055\u308c\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093\u3002[JSP1.2 PFD 5.1.9]\n\u30c6\u30f3\u30d7\u30ec\u30fc\u30c8\u30c7\u30fc\u30bf\u306e\u30a8\u30e9\u30fc\u3067\u3059: {1}
+#Error while processing taglib jar file {0}: {1}
+jsp.error.taglib.reserved.prefix=taglib\u30d7\u30ea\u30d5\u30a3\u30af\u30b9 {0} \u306f\u4e88\u7d04\u3055\u308c\u3066\u3044\u307e\u3059
+jsp.error.invalid.javaEncoding=\u7121\u52b9\u306aJava\u30a8\u30f3\u30b3\u30fc\u30c7\u30a3\u30f3\u30b0\u3067\u3059\u3002{0}\u3092\u8a66\u3057\u3066\u3001\u305d\u308c\u304b\u3089{1}\u3092\u8a66\u3057\u307e\u3057\u305f\u304c\u3001\u4e21\u65b9\u304c\u5931\u6557\u3057\u307e\u3057\u305f
+jsp.error.needAlternateJavaEncoding=\u30c7\u30d5\u30a9\u30eb\u30c8\u306eJava\u30a8\u30f3\u30b3\u30fc\u30c7\u30a3\u30f3\u30b0 {0} \u306f\u3042\u306a\u305f\u306e\u30d7\u30e9\u30c3\u30c8\u30d5\u30a9\u30fc\u30e0\u3067\u306f\u7121\u52b9\u3067\u3059\u3002JspServlet\u306e 'javaEncoding' \u30d1\u30e9\u30e1\u30bf\u3067\u3001\u5225\u306e\u5024\u3092\u6307\u5b9a\u3059\u308b\u3053\u3068\u304c\u3067\u304d\u307e\u3059\u3002
+#Error when compiling, used for jsp line number error messages
+jsp.error.single.line.number=JSP\u30d5\u30a1\u30a4\u30eb: {1} \u306e\u4e2d\u306e{0}\u884c\u76ee\u3067\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f
+jsp.error.multiple.line.number=\n\nJPS\u30d5\u30a1\u30a4\u30eb: {2}\u306e\u4e2d\u306e{0}\u884c\u76ee\u3068{1}\u884c\u76ee\u306e\u9593\u3067\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f\n\n
+jsp.error.corresponding.servlet=\u751f\u6210\u3055\u308c\u305f\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8\u306e\u30a8\u30e9\u30fc\u3067\u3059:\n
+jsp.error.empty.body.not.allowed={0} \u306b\u5bfe\u3057\u3066\u7a7a\u306e\u30dc\u30c7\u30a3\u306f\u8a31\u3055\u308c\u307e\u305b\u3093
+jsp.error.jspbody.required=jsp:attribute\u304c\u4f7f\u7528\u3055\u308c\u305f\u5834\u5408\u306b\u306f\u3001{0}\u306b\u30bf\u30b0\u30dc\u30c7\u30a3\u3092\u6307\u5b9a\u3059\u308b\u305f\u3081\u306bjsp:body\u3092\u4f7f\u7528\u3057\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093
+jsp.error.jspbody.emptybody.only={0} \u30bf\u30b0\u306f\u3001\u305d\u306e\u30dc\u30c7\u30a3\u4e2d\u306bjsp:attribute\u3060\u3051\u3092\u6301\u3064\u3053\u3068\u304c\u3067\u304d\u307e\u3059
+jsp.error.no.scriptlets=\u30b9\u30af\u30ea\u30d7\u30c6\u30a3\u30f3\u30b0\u8981\u7d20 ( &lt;%!\u3001&lt;jsp:declaration\u3001&lt;%=\u3001&lt;jsp:expression\u3001&lt;%\u3001&lt;jsp:scriptlet ) \u306f\u3053\u3053\u3067\u306f\u8a31\u3055\u308c\u307e\u305b\u3093
+jsp.error.internal.unexpected_node_type=\u5185\u90e8\u30a8\u30e9\u30fc: \u672a\u77e5\u306e\u30ce\u30fc\u30c9\u30bf\u30a4\u30d7\u304c\u8868\u308c\u307e\u3057\u305f
+jsp.error.tld.fn.invalid.signature=TLD\u306e\u4e2d\u306e\u95a2\u6570\u30b7\u30b0\u30cd\u30c1\u30e3\u306b\u5bfe\u3059\u308b\u7121\u52b9\u306a\u69cb\u6587\u3067\u3059\u3002\u30bf\u30b0\u30e9\u30a4\u30d6\u30e9\u30ea: {0}\u3001\u95a2\u6570: {1}
+jsp.error.tld.fn.duplicate.name=\u30bf\u30b0\u30e9\u30a4\u30d6\u30e9\u30ea {1} \u306e\u4e2d\u306e\u95a2\u6570\u540d {0} \u304c\u91cd\u8907\u3057\u3066\u3044\u307e\u3059
+jsp.error.tld.fn.invalid.signature.commaexpected=TLD\u306e\u4e2d\u306e\u95a2\u6570\u30b7\u30b0\u30cd\u30c1\u30e3\u306b\u5bfe\u3059\u308b\u7121\u52b9\u306a\u69cb\u6587\u3067\u3059\u3002\u30b3\u30f3\u30de ',' \u304c\u3042\u308a\u307e\u305b\u3093\u3002\u30bf\u30b0\u30e9\u30a4\u30d6\u30e9\u30ea: {0}\u3001\u95a2\u6570: {1}\u3002
+jsp.error.tld.fn.invalid.signature.parenexpected=TLD\u306e\u4e2d\u306e\u95a2\u6570\u30b7\u30b0\u30cd\u30c1\u30e3\u306b\u5bfe\u3059\u308b\u7121\u52b9\u306a\u69cb\u6587\u3067\u3059\u3002\u62ec\u5f27 '(' \u304c\u3042\u308a\u307e\u305b\u3093\u3002\u30bf\u30b0\u30e9\u30a4\u30d6\u30e9\u30ea: {0}\u3001\u95a2\u6570: {1}\u3002
+jsp.error.tld.mandatory.element.missing=\u5fc5\u9808TLD\u8981\u7d20\u304c\u306a\u3044\u3001\u53c8\u306f\u7a7a\u3067\u3059: {0}
+jsp.error.dynamic.attributes.not.implemented={0} \u30bf\u30b0\u306f\u305d\u308c\u304cdynamic\u5c5e\u6027\u3092\u53d7\u3051\u4ed8\u3051\u308b\u3068\u5ba3\u8a00\u3057\u3066\u3044\u307e\u3059\u304c\u3001\u305d\u308c\u306b\u5fc5\u8981\u306a\u30a4\u30f3\u30bf\u30d5\u30a7\u30fc\u30b9\u3092\u5b9f\u88c5\u3057\u3066\u3044\u307e\u305b\u3093
+jsp.error.nomatching.fragment=attribute\u6307\u793a\u5b50 (name={0}\u304a\u3088\u3073fragment=true\u3092\u6301\u3064) \u304cfragment\u6307\u793a\u5b50\u3088\u308a\u524d\u306b\u898b\u3064\u304b\u308a\u307e\u305b\u3093
+jsp.error.attribute.noequal=\u7b49\u53f7\u8a18\u53f7\u304c\u5fc5\u8981\u3067\u3059
+jsp.error.attribute.noquote=\u5f15\u7528\u7b26\u304c\u5fc5\u8981\u3067\u3059
+jsp.error.attribute.unterminated={0} \u306e\u5c5e\u6027\u304c\u6b63\u3057\u304f\u7d42\u4e86\u3057\u3066\u3044\u307e\u305b\u3093
+jsp.error.missing.tagInfo={0} \u306b\u5bfe\u3059\u308bTagInfo\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u304cTLD\u304b\u3089\u5931\u308f\u308c\u307e\u3057\u305f
+jsp.error.fragmentwithtype='fragment'\u5c5e\u6027\u3068'type'\u5c5e\u6027\u3092\u4e21\u65b9\u6307\u5b9a\u3067\u304d\u307e\u305b\u3093\u3002'fragment'\u304c\u5b58\u5728\u3059\u308b\u5834\u5408\u306b\u306f'type'\u306f'javax.servlet.jsp.tagext.JspFragment'\u306b\u56fa\u5b9a\u3055\u308c\u307e\u3059
+jsp.error.fragmentwithrtexprvalue='fragment'\u5c5e\u6027\u3068'rtexprvalue'\u5c5e\u6027\u3092\u4e21\u65b9\u6307\u5b9a\u3067\u304d\u307e\u305b\u3093\u3002'fragment'\u304c\u5b58\u5728\u3059\u308b\u5834\u5408\u306b\u306f'rtexprvalue'\u306f'true'\u306b\u56fa\u5b9a\u3055\u308c\u307e\u3059
+jsp.error.fragmentWithDeclareOrScope='fragment'\u5c5e\u6027\u3068'declare'\u5c5e\u6027\u306e\u4e21\u65b9\u53c8\u306f'scope'\u5c5e\u6027\u304cvariable\u6307\u793a\u5b50\u4e2d\u3067\u6307\u5b9a\u3055\u308c\u3066\u3044\u307e\u3059
+jsp.error.var_and_varReader=\'var\'\u53c8\u306f\'varReader\'\u306e\u3069\u3061\u3089\u304b\u4e00\u3064\u3092\u6307\u5b9a\u3059\u308b\u3053\u3068\u304c\u3067\u304d\u307e\u3059
+jsp.error.missing_var_or_varReader=\'var\'\u53c8\u306f\'varReader\'\u5c5e\u6027\u304c\u3042\u308a\u307e\u305b\u3093
+jsp.warning.bad.urlpattern.propertygroup=web.xml\u4e2d\u306eurl-pattern\u526f\u8981\u7d20\u4e2d\u306b\u8aa4\u3063\u305f\u5024 {0} \u304c\u3042\u308a\u307e\u3059
+jsp.error.unknown_attribute_type=\u5c5e\u6027 {0} \u306b\u5bfe\u3059\u308b\u672a\u77e5\u306e\u5c5e\u6027\u30bf\u30a4\u30d7\u3067\u3059
+jsp.error.jspelement.missing.name=\u5fc5\u9808\u306eXML\u30b9\u30bf\u30a4\u30eb\u306e'name'\u5c5e\u6027\u304cjsp:element\u4e2d\u306b\u3042\u308a\u307e\u305b\u3093
+jsp.error.xmlns.redefinition.notimplemented=\u5185\u90e8\u30a8\u30e9\u30fc: xmlns:{0}\u3092\u518d\u5b9a\u7fa9\u3057\u3088\u3046\u3068\u3057\u307e\u3057\u305f\u3002\u540d\u524d\u7a7a\u9593\u306e\u518d\u5b9a\u7fa9\u306f\u5b9f\u88c5\u3055\u308c\u3066\u3044\u307e\u305b\u3093\u3002
+jsp.error.could.not.add.taglibraries=1\u3064\u4ee5\u4e0a\u306e\u30bf\u30b0\u30e9\u30a4\u30d6\u30e9\u30ea\u3092\u8ffd\u52a0\u3067\u304d\u307e\u305b\u3093
+jsp.error.duplicate.name.jspattribute=\u6a19\u6e96\u53c8\u306f\u30ab\u30b9\u30bf\u30e0\u30a2\u30af\u30b7\u30e7\u30f3\u4e2d\u3067\u6307\u5b9a\u3055\u308c\u3066\u3044\u308b\u5c5e\u6027 {0} \u306f\u305d\u308c\u306b\u56f2\u307e\u308c\u305fjsp:attribute\u4e2d\u306ename\u5c5e\u6027\u306e\u5024\u3068\u3057\u3066\u3082\u8868\u308c\u307e\u3059
+jsp.error.not.in.template=\u30c6\u30f3\u30d7\u30ec\u30fc\u30c8\u30c6\u30ad\u30b9\u30c8\u30dc\u30c7\u30a3\u4e2d\u3067\u306f {0} \u306f\u8a31\u3055\u308c\u307e\u305b\u3093
+jsp.error.badStandardAction=\u7121\u52b9\u306a\u6a19\u6e96\u30a2\u30af\u30b7\u30e7\u30f3\u3067\u3059
+jsp.error.xml.badStandardAction=\u7121\u52b9\u306a\u6a19\u6e96\u30a2\u30af\u30b7\u30e7\u30f3\u3067\u3059: {0}
+jsp.error.tagdirective.badbodycontent=tag\u6307\u793a\u5b50\u4e2d\u306e\u7121\u52b9\u306abody-content ({0})\u3067\u3059
+jsp.error.simpletag.badbodycontent=\u30af\u30e9\u30b9 {0} \u306eTLD\u306fSimpleTag\u306b\u7121\u52b9\u306abody-content (JSP)\u3092\u6307\u5b9a\u3057\u3066\u3044\u307e\u3059
+jsp.error.config_pagedir_encoding_mismatch=jsp-property-group\u4e2d\u306b\u6307\u5b9a\u3055\u308c\u3066\u3044\u308bPage-encoding ({0}) \u304cpage\u6307\u793a\u5b50\u4e2d\u306e\u6307\u5b9a ({1}) \u3068\u9055\u3044\u307e\u3059
+jsp.error.prolog_pagedir_encoding_mismatch=XML\u5c0e\u5165\u90e8\u3067\u6307\u5b9a\u3055\u308c\u305fpage-encoding ({0}) \u304cpage\u6307\u793a\u5b50\u4e2d\u306e\u6307\u5b9a ({1}) \u3068\u9055\u3044\u307e\u3059
+jsp.error.prolog_config_encoding_mismatch=XML\u5c0e\u5165\u90e8\u3067\u6307\u5b9a\u3055\u308c\u305fpage-encoding ({0}) \u304cjsp-property-group\u4e2d\u306e\u6307\u5b9a\u3068\u9055\u3044\u307e\u3059 ({1})
+jsp.error.attribute.custom.non_rt_with_expr=TLD\u53c8\u306f\u30bf\u30b0\u30d5\u30a1\u30a4\u30eb\u4e2d\u306eattribute\u6307\u793a\u5b50\u306b\u5f93\u3063\u3066\u5c5e\u6027{0}\u306f\u3069\u3093\u306a\u5f0f\u3082\u53d7\u3051\u4ed8\u3051\u307e\u305b\u3093
+jsp.error.attribute.standard.non_rt_with_expr={1} \u6a19\u6e96\u30a2\u30af\u30b7\u30e7\u30f3\u306e {0} \u5c5e\u6027\u306f\u3069\u3093\u306a\u5f0f\u3082\u53d7\u3051\u4ed8\u3051\u307e\u305b\u3093
+jsp.error.scripting.variable.missing_name=\u5c5e\u6027 {0} \u304b\u3089\u30b9\u30af\u30ea\u30d7\u30c8\u5909\u6570\u540d\u3092\u6c7a\u5b9a\u3067\u304d\u307e\u305b\u3093
+jasper.error.emptybodycontent.nonempty=TLD\u306b\u5f93\u3063\u3066\u30bf\u30b0 {0} \u306f\u7a7a\u3067\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093\u304c\u3001\u305d\u3046\u3067\u306f\u3042\u308a\u307e\u305b\u3093
+jsp.error.tagfile.nameNotUnique={2}\u884c\u76ee\u306e {0} \u306e\u5024\u3068 {1} \u306e\u5024\u306f\u540c\u3058\u3067\u3059
+jsp.error.tagfile.nameFrom.noAttribute=\u3053\u306ename-from-attribute\u5c5e\u6027\u306e\u5024\u3067\u3042\u308b\u5024 \"{0}\" \u306ename\u5c5e\u6027\u3092\u6301\u3064attribute\u6307\u793a\u5b50\u304c\u898b\u3064\u304b\u308a\u307e\u305b\u3093
+jsp.error.tagfile.nameFrom.badAttribute=attribute\u6307\u793a\u5b50 ({1}\u884c\u76ee\u3067\u5ba3\u8a00\u3055\u308c\u3001\u305d\u306ename\u5c5e\u6027\u304c\"{0}\"\u3001\u3053\u306ename-from-attribute\u5c5e\u6027\u306e\u5024) \u306fjava.lang.String\u578b\u306e\"required\" \u3067 \"rtexprvalue\".\u3067\u3042\u3063\u3066\u306f\u3044\u3051\u307e\u305b\u3093
+jsp.error.page.noSession=\u30bb\u30c3\u30b7\u30e7\u30f3\u306b\u52a0\u308f\u3063\u3066\u3044\u306a\u3044\u30da\u30fc\u30b8\u306e\u4e2d\u3067\u306f\u30bb\u30c3\u30b7\u30e7\u30f3\u30b9\u30b3\u30fc\u30d7\u306b\u30a2\u30af\u30bb\u30b9\u3067\u304d\u307e\u305b\u3093
+jsp.error.useBean.noSession=JSP\u30da\u30fc\u30b8\u304c(page\u6307\u793a\u5b50\u306b\u3088\u308a)\u30bb\u30c3\u30b7\u30e7\u30f3\u4e2d\u3067\u5354\u8abf\u3057\u306a\u3044\u3053\u3068\u3092\u5ba3\u8a00\u3057\u3066\u3044\u308b\u6642\u3001\u30bb\u30c3\u30b7\u30e7\u30f3\u30b9\u30b3\u30fc\u30d7\u3092\u4f7f\u7528\u3059\u308b\u305f\u3081\u306euseBean\u304c\u4e0d\u6b63\u3067\u3059
+jsp.error.xml.encodingByteOrderUnsupported = \u30a8\u30f3\u30b3\u30fc\u30c7\u30a3\u30f3\u30b0 \"{0}\" \u306b\u6307\u5b9a\u3055\u308c\u305f\u30d0\u30a4\u30c8\u30aa\u30fc\u30c0\u306f\u30b5\u30dd\u30fc\u30c8\u3055\u308c\u3066\u3044\u307e\u305b\u3093
+jsp.error.xml.encodingDeclInvalid = \u7121\u52b9\u306a\u30a8\u30f3\u30b3\u30fc\u30c7\u30a3\u30f3\u30b0\u540d \"{0}\" \u3067\u3059
+jsp.error.xml.encodingDeclRequired = \u30c6\u30ad\u30b9\u30c8\u5ba3\u8a00\u4e2d\u306b\u30a8\u30f3\u30b3\u30fc\u30c7\u30a3\u30f3\u30b0\u5ba3\u8a00\u304c\u5fc5\u8981\u3067\u3059
+jsp.error.xml.morePseudoAttributes = \u3088\u308a\u591a\u304f\u306e\u7591\u4f3c\u5c5e\u6027\u304c\u5fc5\u8981\u3067\u3059
+jsp.error.xml.noMorePseudoAttributes = \u3053\u308c\u4ee5\u4e0a\u306e\u7591\u4f3c\u5c5e\u6027\u306f\u8a31\u3055\u308c\u307e\u305b\u3093
+jsp.error.xml.versionInfoRequired = XML\u5ba3\u8a00\u306e\u4e2d\u306b\u30d0\u30fc\u30b8\u30e7\u30f3\u304c\u5fc5\u8981\u3067\u3059
+jsp.error.xml.xmlDeclUnterminated = XML\u5ba3\u8a00\u306f\"?>\"\u3067\u7d42\u3089\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093
+jsp.error.xml.reservedPITarget = \"[xX][mM][lL]\"\u306b\u4e00\u81f4\u3059\u308b\u51e6\u7406\u547d\u4ee4\u30bf\u30fc\u30b2\u30c3\u30c8\u306f\u8a31\u3055\u308c\u3066\u3044\u307e\u305b\u3093
+jsp.error.xml.spaceRequiredInPI = \u7a7a\u767d\u304c\u51e6\u7406\u547d\u4ee4\u30bf\u30fc\u30b2\u30c3\u30c8\u3068\u30c7\u30fc\u30bf\u306e\u9593\u306b\u5fc5\u8981\u3067\u3059
+jsp.error.xml.invalidCharInContent = \u30c9\u30ad\u30e5\u30e1\u30f3\u30c8\u306e\u7121\u52b9\u306aXML\u6587\u5b57 (Unicode: 0x{0}) \u304c\u30c9\u30ad\u30e5\u30e1\u30f3\u30c8\u306e\u8981\u7d20\u5185\u5bb9\u306e\u4e2d\u306b\u898b\u3064\u304b\u308a\u307e\u3057\u305f
+jsp.error.xml.spaceRequiredBeforeStandalone = XML\u5ba3\u8a00\u306eencoding\u7591\u4f3c\u5c5e\u6027\u306e\u524d\u306b\u7a7a\u767d\u304c\u5fc5\u8981\u3067\u3059
+jsp.error.xml.sdDeclInvalid = \u30b9\u30bf\u30f3\u30c9\u30a2\u30ed\u30f3\u6587\u66f8\u5ba3\u8a00\u5024\u306f\"yes\"\u53c8\u306f\"no\"\u306e\u3069\u3061\u3089\u304b\u3067\u3042\u308a\u3001\"{0}\"\u3067\u306f\u3044\u3051\u307e\u305b\u3093
+jsp.error.xml.invalidCharInPI = \u7121\u52b9\u306aXML\u6587\u5b57 (Unicode: 0x{0}) \u304c\u547d\u4ee4\u51e6\u7406\u4e2d\u306b\u898b\u3064\u304b\u308a\u307e\u3057\u305f
+jsp.error.xml.versionNotSupported = XML\u30d0\u30fc\u30b8\u30e7\u30f3 \"{0}\" \u306f\u30b5\u30dd\u30fc\u30c8\u3055\u308c\u3066\u3044\u307e\u305b\u3093\u3001XML 1.0\u3060\u3051\u3092\u30b5\u30dd\u30fc\u30c8\u3057\u3066\u3044\u307e\u3059
+jsp.error.xml.pseudoAttrNameExpected = \u7591\u4f3c\u5c5e\u6027\u540d\u304c\u5fc5\u8981\u3067\u3059
+jsp.error.xml.expectedByte ={1}\u30d0\u30a4\u30c8UTF-8\u30b7\u30fc\u30b1\u30f3\u30b9\u306e\u30d0\u30a4\u30c8 {0} \u304c\u5fc5\u8981\u3067\u3059
+jsp.error.xml.invalidByte = {1}\u30d0\u30a4\u30c8UTF-8\u30b7\u30fc\u30b1\u30f3\u30b9\u306e\u7121\u52b9\u306a\u30d0\u30a4\u30c8 {0} \u3067\u3059
+jsp.error.xml.operationNotSupported = {1} reader\u306f\u64cd\u4f5c \"{0}\" \u3092\u30b5\u30dd\u30fc\u30c8\u3057\u3066\u3044\u307e\u305b\u3093
+jsp.error.xml.invalidHighSurrogate = UTF-8\u30b7\u30fc\u30b1\u30f3\u30b9\u306e\u30cf\u30a4\u30b5\u30ed\u30b2\u30fc\u30c8\u30d3\u30c3\u30c8\u306f0x10\u3092\u8d8a\u3048\u3066\u306f\u3044\u3051\u307e\u305b\u3093\u304c\u30010x{0}\u304c\u898b\u3064\u304b\u308a\u307e\u3057\u305f
+jsp.error.xml.invalidASCII = \u30d0\u30a4\u30c8 \"{0}\" \u306f7\u30d3\u30c3\u30c8ASCII\u3067\u306f\u3042\u308a\u307e\u305b\u3093
+jsp.error.xml.spaceRequiredBeforeEncodingInXMLDecl = XML\u5ba3\u8a00\u306eencoding\u7591\u4f3c\u5c5e\u6027\u306e\u524d\u306b\u7a7a\u767d\u304c\u5fc5\u8981\u3067\u3059
+jsp.error.xml.spaceRequiredBeforeEncodingInTextDecl = \u30c6\u30ad\u30b9\u30c8\u5ba3\u8a00\u306eencoding\u7591\u4f3c\u5c5e\u6027\u306e\u524d\u306b\u7a7a\u767d\u304c\u5fc5\u8981\u3067\u3059
+jsp.error.xml.spaceRequiredBeforeVersionInTextDecl = \u30c6\u30ad\u30b9\u30c8\u5ba3\u8a00\u306eversion\u7591\u4f3c\u5c5e\u6027\u306e\u524d\u306b\u7a7a\u767d\u304c\u5fc5\u8981\u3067\u3059
+jsp.error.xml.spaceRequiredBeforeVersionInXMLDecl = XML\u5ba3\u8a00\u306eversion\u7591\u4f3c\u5c5e\u6027\u306e\u524d\u306b\u7a7a\u767d\u304c\u5fc5\u8981\u3067\u3059
+jsp.error.xml.eqRequiredInXMLDecl = XML\u5ba3\u8a00\u4e2d\u3067\"{0}\"\u306e\u6b21\u306b'' = '' \u6587\u5b57\u304c\u7d9a\u304b\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093
+jsp.error.xml.eqRequiredInTextDecl = \u30c6\u30ad\u30b9\u30c8\u5ba3\u8a00\u4e2d\u3067\"{0}\"\u306e\u6b21\u306b'' = ''\u6587\u5b57\u304c\u7d9a\u304b\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093
+jsp.error.xml.quoteRequiredInTextDecl = \u30c6\u30ad\u30b9\u30c8\u5ba3\u8a00\u4e2d\u306e\"{0}\"\u306b\u7d9a\u304f\u5024\u306f\u30af\u30aa\u30fc\u30c8\u3067\u56f2\u307e\u308c\u305f\u6587\u5b57\u5217\u3067\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093
+jsp.error.xml.quoteRequiredInXMLDecl = XML\u5ba3\u8a00\u4e2d\u306e\"{0}\"\u306b\u7d9a\u304f\u5024\u306f\u30af\u30aa\u30fc\u30c8\u3067\u56f2\u307e\u308c\u305f\u6587\u5b57\u5217\u3067\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093
+jsp.error.xml.invalidCharInTextDecl = \u30c6\u30ad\u30b9\u30c8\u5ba3\u8a00\u306e\u4e2d\u306b\u7121\u52b9\u306aXML\u6587\u5b57 (Unicode: 0x{0}) \u304c\u898b\u3064\u304b\u308a\u307e\u3057\u305f
+jsp.error.xml.invalidCharInXMLDecl = XML\u5ba3\u8a00\u306e\u4e2d\u306b\u7121\u52b9\u306aXML\u6587\u5b57 (Unicode: 0x{0}) \u304c\u898b\u3064\u304b\u308a\u307e\u3057\u305f
+jsp.error.xml.closeQuoteMissingInTextDecl = \u30c6\u30ad\u30b9\u30c8\u5ba3\u8a00\u4e2d\u306e\"{0}\"\u306b\u7d9a\u304f\u5024\u306e\u4e2d\u306e\u6700\u5f8c\u306e\u30af\u30aa\u30fc\u30c8\u304c\u3042\u308a\u307e\u305b\u3093
+jsp.error.xml.closeQuoteMissingInXMLDecl = XML\u5ba3\u8a00\u4e2d\u306e\"{0}\"\u306b\u7d9a\u304f\u5024\u306e\u4e2d\u306e\u6700\u5f8c\u306e\u30af\u30aa\u30fc\u30c8\u304c\u3042\u308a\u307e\u305b\u3093
+jsp.error.xml.invalidHighSurrogate = UTF-8\u30b7\u30fc\u30b1\u30f3\u30b9\u306e\u30cf\u30a4\u30b5\u30ed\u30b2\u30fc\u30c8\u30d3\u30c3\u30c8\u306f0x10\u3092\u8d8a\u3048\u3066\u306f\u3044\u3051\u307e\u305b\u3093\u304c\u30010x{0}\u304c\u898b\u3064\u304b\u308a\u307e\u3057\u305f
+jsp.error.multiple.jsp = \u8907\u6570\u306e\u4ed5\u69d8\u3092\u6e80\u305f\u3059\u3053\u3068\u306f\u3067\u304d\u307e\u305b\u3093
+jsp.error.jspoutput.conflict=&lt;jsp:output&gt;: \"{0}\"\u306b\u7570\u306a\u308b\u5024\u3092\u8907\u6570\u56de\u6307\u5b9a\u3059\u308b\u306e\u306f\u7121\u52b9\u3067\u3059 (\u65e7: {1}, \u65b0: {2})
+jsp.error.jspoutput.doctypenamesystem=&lt;jsp:output&gt;: 'doctype-root-element' \u53ca\u3073 'doctype-system' \u5c5e\u6027\u306f\u540c\u6642\u306b\u6307\u5b9a\u3057\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093
+jsp.error.jspoutput.doctypepulicsystem=&lt;jsp:output&gt;: 'doctype-public'\u5c5e\u6027\u3092\u6307\u5b9a\u3059\u308b\u5834\u5408\u306f\u3001'doctype-system' \u5c5e\u6027\u3082\u6307\u5b9a\u3057\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093
+jsp.error.jspoutput.nonemptybody=&lt;jsp:output&gt; \u30dc\u30c7\u30a3\u3092\u6301\u3063\u3066\u306f\u3044\u3051\u307e\u305b\u3093
+jsp.error.jspoutput.invalidUse=&lt;jsp:output&gt; \u6a19\u6e96\u69cb\u6587\u306e\u4e2d\u3067\u4f7f\u7528\u3057\u3066\u306f\u3044\u3051\u307e\u305b\u3093
+jsp.error.attributes.not.allowed = {0} \u306f\u5c5e\u6027\u3092\u6301\u3064\u3053\u3068\u306f\u3067\u304d\u307e\u305b\u3093
+jsp.error.tagfile.badSuffix=\u30bf\u30b0\u30d5\u30a1\u30a4\u30eb\u30d1\u30b9 {0} \u306e\u4e2d\u306b\".tag\" \u62e1\u5f35\u5b50\u304c\u3042\u308a\u307e\u305b\u3093
+jsp.error.tagfile.illegalPath=\u4e0d\u6b63\u306a\u30bf\u30b0\u30d5\u30a1\u30a4\u30eb\u30d1\u30b9\u3067\u3059: {0}\u3001\u3053\u308c\u306f\"/WEB-INF/tags\"\u53c8\u306f\"/META-INF/tags\"\u3067\u59cb\u307e\u3089\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093
+jsp.error.plugin.wrongRootElement={0} \u306e\u4e2d\u306e\u30eb\u30fc\u30c8\u8981\u7d20\u306e\u540d\u524d\u306f {1} \u3067\u306f\u3042\u308a\u307e\u305b\u3093
+jsp.error.attribute.invalidPrefix=\u5c5e\u6027\u306e\u30d7\u30ec\u30d5\u30a3\u30c3\u30af\u30b9 {0} \u306f\u3069\u306e\u53d6\u308a\u8fbc\u307e\u308c\u305f\u30bf\u30b0\u30e9\u30a4\u30d6\u30e9\u30ea\u306b\u3082\u5bfe\u5fdc\u3057\u307e\u305b\u3093
+jsp.error.nested.jspattribute=jsp:attribute\u6a19\u6e96\u30a2\u30af\u30b7\u30e7\u30f3\u306f\u5225\u306ejsp:attribute\u6a19\u6e96\u30a2\u30af\u30b7\u30e7\u30f3\u306e\u7bc4\u56f2\u5185\u3067\u30cd\u30b9\u30c8\u3059\u308b\u3053\u3068\u306f\u3067\u304d\u307e\u305b\u3093
+jsp.error.nested.jspbody=jsp:body\u6a19\u6e96\u30a2\u30af\u30b7\u30e7\u30f3\u306f\u5225\u306ejsp:body\u53c8\u306fjsp:attribute\u6a19\u6e96\u30a2\u30af\u30b7\u30e7\u30f3\u306e\u7bc4\u56f2\u5185\u3067\u30cd\u30b9\u30c8\u3059\u308b\u3053\u3068\u306f\u3067\u304d\u307e\u305b\u3093
+jsp.error.variable.either.name=name-given\u53c8\u306fname-from-attribute\u5c5e\u6027\u306e\u3069\u3061\u3089\u304b\u3092variable\u6307\u793a\u5b50\u306e\u4e2d\u3067\u6307\u5b9a\u3055\u308c\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093
+jsp.error.variable.both.name=variable\u6307\u793a\u5b50\u4e2d\u3067name-given\u3068name-from-attribute\u5c5e\u6027\u306e\u4e21\u65b9\u3092\u6307\u5b9a\u3059\u308b\u3053\u3068\u306f\u3067\u304d\u307e\u305b\u3093
+jsp.error.variable.alias=name-from-attribute\u304a\u3088\u3073alias\u5c5e\u6027\u306e\u4e21\u65b9\u3092variable\u6307\u793a\u5b50\u4e2d\u306b\u6307\u5b9a\u3059\u308b\u3001\u53c8\u306f\u3069\u3061\u3089\u3082\u6307\u5b9a\u3057\u306a\u3044\u3053\u3068\u304c\u3067\u304d\u307e\u3059
+jsp.error.attribute.null_name=\u7a7a\u306e\u5c5e\u6027\u540d\u3067\u3059
+jsp.error.jsptext.badcontent=\'&lt;\'\u304c&lt;jsp:text&gt;\u306e\u30dc\u30c7\u30a3\u306e\u4e2d\u306b\u73fe\u308c\u308b\u6642\u306f\u3001CDATA\u306e\u4e2d\u306b\u96a0\u853d\u3057\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093
+jsp.error.jsproot.version.invalid=\u7121\u52b9\u306a\u30d0\u30fc\u30b8\u30e7\u30f3\u756a\u53f7\u3067\u3059: \"{0}\"\u3001\"1.2\" \u53c8\u306f \"2.0\"\u3000\u3067\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093
+jsp.error.noFunctionPrefix=\u30c7\u30d5\u30a9\u30eb\u30c8\u306e\u540d\u524d\u7a7a\u9593\u304c\u6307\u5b9a\u3055\u308c\u3066\u3044\u306a\u3044\u6642\u306b\u306f\u3001\u95a2\u6570 {0} \u306f\u30d7\u30ea\u30d5\u30a3\u30af\u30b9\u4ed8\u304d\u3067\u4f7f\u7528\u3057\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093
+jsp.error.noFunction=\u95a2\u6570 {0} \u3092\u6307\u5b9a\u3055\u308c\u305f\u30d7\u30ea\u30d5\u30a3\u30af\u30b9\u3067\u914d\u7f6e\u3067\u304d\u307e\u305b\u3093
+jsp.error.noFunctionMethod=\u95a2\u6570 \"{1}\" \u306e\u30e1\u30bd\u30c3\u30c9 \"{0}\" \u304c \"{2}\" \u4e2d\u3067\u898b\u3064\u304b\u308a\u307e\u305b\u3093
+jsp.error.function.classnotfound=TLD\u306e\u4e2d\u3067\u95a2\u6570 {1} \u306b\u6307\u5b9a\u3055\u308c\u3066\u3044\u308b\u30af\u30e9\u30b9 {0} \u304c\u898b\u3064\u304b\u308a\u307e\u305b\u3093: {2}
+jsp.error.signature.classnotfound=TLD\u306e\u4e2d\u306e\u30e1\u30bd\u30c3\u30c9\u30b7\u30b0\u30cd\u30c1\u30e3\u3067\u95a2\u6570 {1} \u306b\u6307\u5b9a\u3055\u308c\u3066\u3044\u308b\u30af\u30e9\u30b9 {0} \u304c\u898b\u3064\u304b\u308a\u307e\u305b\u3093\u3002 {2}
+jsp.error.text.has_subelement=&lt;jsp:text&gt; \u306f\u526f\u8981\u7d20\u3092\u6301\u3063\u3066\u306f\u3044\u3051\u307e\u305b\u3093
+jsp.error.data.file.read=\u30d5\u30a1\u30a4\u30eb \"{0}\" \u3092\u8aad\u307f\u8fbc\u307f\u4e2d\u306b\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f
+jsp.error.prefix.refined=\u30d7\u30ea\u30d5\u30a3\u30c3\u30af\u30b9 {0} \u304c\u73fe\u5728\u306e\u30b9\u30b3\u30fc\u30d7\u4e2d\u3067\u65e2\u306b {2} \u3068\u5b9a\u7fa9\u3055\u308c\u3066\u3044\u308b\u306e\u3067 {1} \u306b\u518d\u5b9a\u7fa9\u3057\u307e\u3057\u305f
+jsp.error.nested_jsproot=\u5165\u308c\u5b50\u306b\u306a\u3063\u305f &lt;jsp:root&gt; \u3067\u3059
+jsp.error.unbalanced.endtag=\u7d42\u4e86\u30bf\u30b0 \"&lt;/{0}\" \u306e\u5bfe\u5fdc\u304c\u53d6\u308c\u3066\u3044\u307e\u305b\u3093
+jsp.error.invalid.bean=useBean\u306e\u30af\u30e9\u30b9\u5c5e\u6027 {0} \u306e\u5024\u304c\u7121\u52b9\u3067\u3059
+jsp.error.prefix.use_before_dcl=\u3053\u306e\u30bf\u30b0\u6307\u793a\u5b50\u3067\u6307\u5b9a\u3055\u308c\u3066\u3044\u308b\u30d7\u30ea\u30d5\u30a3\u30c3\u30af\u30b9 {0} \u306f\u3001\u3059\u3067\u306b\u30d5\u30a1\u30a4\u30eb {1} \u306e {2} \u884c\u76ee\u306e\u30a2\u30af\u30b7\u30e7\u30f3\u3067\u4f7f\u7528\u3055\u308c\u3066\u3044\u307e\u3059
+

Added: branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/runtime/BodyContentImpl.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/runtime/BodyContentImpl.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/runtime/BodyContentImpl.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,608 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.CharArrayReader;
+import java.io.IOException;
+import java.io.Reader;
+import java.io.Writer;
+
+import javax.servlet.jsp.JspWriter;
+import javax.servlet.jsp.tagext.BodyContent;
+
+import org.apache.jasper.Constants;
+
+/**
+ * Write text to a character-output stream, buffering characters so as
+ * to provide for the efficient writing of single characters, arrays,
+ * and strings. 
+ *
+ * Provide support for discarding for the output that has been buffered. 
+ *
+ * @author Rajiv Mordani
+ * @author Jan Luehe
+ */
+public class BodyContentImpl extends BodyContent {
+    
+    private static final String LINE_SEPARATOR = 
+        System.getProperty("line.separator");
+    private static final boolean LIMIT_BUFFER = 
+        Boolean.valueOf(System.getProperty("org.apache.jasper.runtime.BodyContentImpl.LIMIT_BUFFER", "false")).booleanValue();
+    
+    private char[] cb;
+    private int nextChar;
+    private boolean closed;
+    
+    // Enclosed writer to which any output is written
+    private Writer writer;
+    
+    // See comment in setWriter()
+    private int bufferSizeSave;
+    
+    /**
+     * Constructor.
+     */
+    public BodyContentImpl(JspWriter enclosingWriter) {
+        super(enclosingWriter);
+        bufferSize = Constants.DEFAULT_TAG_BUFFER_SIZE;
+        cb = new char[bufferSize];
+        nextChar = 0;
+        closed = false;
+    }
+    
+    /**
+     * Write a single character.
+     */
+    public void write(int c) throws IOException {
+        if (writer != null) {
+            writer.write(c);
+        } else {
+            ensureOpen();
+            if (nextChar >= bufferSize) {
+                reAllocBuff (1);
+            }
+            cb[nextChar++] = (char) c;
+        }
+    }
+    
+    /**
+     * Write a portion of an array of characters.
+     *
+     * <p> Ordinarily this method stores characters from the given array into
+     * this stream's buffer, flushing the buffer to the underlying stream as
+     * needed.  If the requested length is at least as large as the buffer,
+     * however, then this method will flush the buffer and write the characters
+     * directly to the underlying stream.  Thus redundant
+     * <code>DiscardableBufferedWriter</code>s will not copy data
+     * unnecessarily.
+     *
+     * @param cbuf A character array
+     * @param off Offset from which to start reading characters
+     * @param len Number of characters to write
+     */
+    public void write(char[] cbuf, int off, int len) throws IOException {
+        if (writer != null) {
+            writer.write(cbuf, off, len);
+        } else {
+            ensureOpen();
+            
+            if ((off < 0) || (off > cbuf.length) || (len < 0) ||
+                    ((off + len) > cbuf.length) || ((off + len) < 0)) {
+                throw new IndexOutOfBoundsException();
+            } else if (len == 0) {
+                return;
+            } 
+            
+            if (len >= bufferSize - nextChar)
+                reAllocBuff (len);
+            
+            System.arraycopy(cbuf, off, cb, nextChar, len);
+            nextChar+=len;
+        }
+    }
+    
+    /**
+     * Write an array of characters.  This method cannot be inherited from the
+     * Writer class because it must suppress I/O exceptions.
+     */
+    public void write(char[] buf) throws IOException {
+        if (writer != null) {
+            writer.write(buf);
+        } else {
+            write(buf, 0, buf.length);
+        }
+    }
+    
+    /**
+     * Write a portion of a String.
+     *
+     * @param s String to be written
+     * @param off Offset from which to start reading characters
+     * @param len Number of characters to be written
+     */
+    public void write(String s, int off, int len) throws IOException {
+        if (writer != null) {
+            writer.write(s, off, len);
+        } else {
+            ensureOpen();
+            if (len >= bufferSize - nextChar)
+                reAllocBuff(len);
+            
+            s.getChars(off, off + len, cb, nextChar);
+            nextChar += len;
+        }
+    }
+    
+    /**
+     * Write a string.  This method cannot be inherited from the Writer class
+     * because it must suppress I/O exceptions.
+     */
+    public void write(String s) throws IOException {
+        if (writer != null) {
+            writer.write(s);
+        } else {
+            write(s, 0, s.length());
+        }
+    }
+    
+    /**
+     * Write a line separator.  The line separator string is defined by the
+     * system property <tt>line.separator</tt>, and is not necessarily a single
+     * newline ('\n') character.
+     *
+     * @throws IOException If an I/O error occurs
+     */
+    public void newLine() throws IOException {
+        if (writer != null) {
+            writer.write(LINE_SEPARATOR);
+        } else {
+            write(LINE_SEPARATOR);
+        }
+    }
+    
+    /**
+     * Print a boolean value.  The string produced by <code>{@link
+     * java.lang.String#valueOf(boolean)}</code> is translated into bytes
+     * according to the platform's default character encoding, and these bytes
+     * are written in exactly the manner of the <code>{@link
+     * #write(int)}</code> method.
+     *
+     * @param b The <code>boolean</code> to be printed
+     * @throws IOException
+     */
+    public void print(boolean b) throws IOException {
+        if (writer != null) {
+            writer.write(b ? "true" : "false");
+        } else {
+            write(b ? "true" : "false");
+        }
+    }
+    
+    /**
+     * Print a character.  The character is translated into one or more bytes
+     * according to the platform's default character encoding, and these bytes
+     * are written in exactly the manner of the <code>{@link
+     * #write(int)}</code> method.
+     *
+     * @param c The <code>char</code> to be printed
+     * @throws IOException
+     */
+    public void print(char c) throws IOException {
+        if (writer != null) {
+            writer.write(String.valueOf(c));
+        } else {
+            write(String.valueOf(c));
+        }
+    }
+    
+    /**
+     * Print an integer.  The string produced by <code>{@link
+     * java.lang.String#valueOf(int)}</code> is translated into bytes according
+     * to the platform's default character encoding, and these bytes are
+     * written in exactly the manner of the <code>{@link #write(int)}</code>
+     * method.
+     *
+     * @param i The <code>int</code> to be printed
+     * @throws IOException
+     */
+    public void print(int i) throws IOException {
+        if (writer != null) {
+            writer.write(String.valueOf(i));
+        } else {
+            write(String.valueOf(i));
+        }
+    }
+    
+    /**
+     * Print a long integer.  The string produced by <code>{@link
+     * java.lang.String#valueOf(long)}</code> is translated into bytes
+     * according to the platform's default character encoding, and these bytes
+     * are written in exactly the manner of the
+     * <code>{@link #write(int)}</code> method.
+     *
+     * @param l The <code>long</code> to be printed
+     * @throws IOException
+     */
+    public void print(long l) throws IOException {
+        if (writer != null) {
+            writer.write(String.valueOf(l));
+        } else {
+            write(String.valueOf(l));
+        }
+    }
+    
+    /**
+     * Print a floating-point number.  The string produced by <code>{@link
+     * java.lang.String#valueOf(float)}</code> is translated into bytes
+     * according to the platform's default character encoding, and these bytes
+     * are written in exactly the manner of the
+     * <code>{@link #write(int)}</code> method.
+     *
+     * @param f The <code>float</code> to be printed
+     * @throws IOException
+     */
+    public void print(float f) throws IOException {
+        if (writer != null) {
+            writer.write(String.valueOf(f));
+        } else {
+            write(String.valueOf(f));
+        }
+    }
+    
+    /**
+     * Print a double-precision floating-point number.  The string produced by
+     * <code>{@link java.lang.String#valueOf(double)}</code> is translated into
+     * bytes according to the platform's default character encoding, and these
+     * bytes are written in exactly the manner of the <code>{@link
+     * #write(int)}</code> method.
+     *
+     * @param d The <code>double</code> to be printed
+     * @throws IOException
+     */
+    public void print(double d) throws IOException {
+        if (writer != null) {
+            writer.write(String.valueOf(d));
+        } else {
+            write(String.valueOf(d));
+        }
+    }
+    
+    /**
+     * Print an array of characters.  The characters are converted into bytes
+     * according to the platform's default character encoding, and these bytes
+     * are written in exactly the manner of the
+     * <code>{@link #write(int)}</code> method.
+     *
+     * @param s The array of chars to be printed
+     *
+     * @throws NullPointerException If <code>s</code> is <code>null</code>
+     * @throws IOException
+     */
+    public void print(char[] s) throws IOException {
+        if (writer != null) {
+            writer.write(s);
+        } else {
+            write(s);
+        }
+    }
+    
+    /**
+     * Print a string.  If the argument is <code>null</code> then the string
+     * <code>"null"</code> is printed.  Otherwise, the string's characters are
+     * converted into bytes according to the platform's default character
+     * encoding, and these bytes are written in exactly the manner of the
+     * <code>{@link #write(int)}</code> method.
+     *
+     * @param s The <code>String</code> to be printed
+     * @throws IOException
+     */
+    public void print(String s) throws IOException {
+        if (s == null) s = "null";
+        if (writer != null) {
+            writer.write(s);
+        } else {
+            write(s);
+        }
+    }
+    
+    /**
+     * Print an object.  The string produced by the <code>{@link
+     * java.lang.String#valueOf(Object)}</code> method is translated into bytes
+     * according to the platform's default character encoding, and these bytes
+     * are written in exactly the manner of the
+     * <code>{@link #write(int)}</code> method.
+     *
+     * @param obj The <code>Object</code> to be printed
+     * @throws IOException
+     */
+    public void print(Object obj) throws IOException {
+        if (writer != null) {
+            writer.write(String.valueOf(obj));
+        } else {
+            write(String.valueOf(obj));
+        }
+    }
+    
+    /**
+     * Terminate the current line by writing the line separator string.  The
+     * line separator string is defined by the system property
+     * <code>line.separator</code>, and is not necessarily a single newline
+     * character (<code>'\n'</code>).
+     *
+     * @throws IOException
+     */
+    public void println() throws IOException {
+        newLine();
+    }
+    
+    /**
+     * Print a boolean value and then terminate the line.  This method behaves
+     * as though it invokes <code>{@link #print(boolean)}</code> and then
+     * <code>{@link #println()}</code>.
+     *
+     * @throws IOException
+     */
+    public void println(boolean x) throws IOException {
+        print(x);
+        println();
+    }
+    
+    /**
+     * Print a character and then terminate the line.  This method behaves as
+     * though it invokes <code>{@link #print(char)}</code> and then
+     * <code>{@link #println()}</code>.
+     *
+     * @throws IOException
+     */
+    public void println(char x) throws IOException {
+        print(x);
+        println();
+    }
+    
+    /**
+     * Print an integer and then terminate the line.  This method behaves as
+     * though it invokes <code>{@link #print(int)}</code> and then
+     * <code>{@link #println()}</code>.
+     *
+     * @throws IOException
+     */
+    public void println(int x) throws IOException {
+        print(x);
+        println();
+    }
+    
+    /**
+     * Print a long integer and then terminate the line.  This method behaves
+     * as though it invokes <code>{@link #print(long)}</code> and then
+     * <code>{@link #println()}</code>.
+     *
+     * @throws IOException
+     */
+    public void println(long x) throws IOException {
+        print(x);
+        println();
+    }
+    
+    /**
+     * Print a floating-point number and then terminate the line.  This method
+     * behaves as though it invokes <code>{@link #print(float)}</code> and then
+     * <code>{@link #println()}</code>.
+     *
+     * @throws IOException
+     */
+    public void println(float x) throws IOException {
+        print(x);
+        println();
+    }
+    
+    /**
+     * Print a double-precision floating-point number and then terminate the
+     * line.  This method behaves as though it invokes <code>{@link
+     * #print(double)}</code> and then <code>{@link #println()}</code>.
+     *
+     * @throws IOException
+     */
+    public void println(double x) throws IOException{
+        print(x);
+        println();
+    }
+    
+    /**
+     * Print an array of characters and then terminate the line.  This method
+     * behaves as though it invokes <code>{@link #print(char[])}</code> and
+     * then <code>{@link #println()}</code>.
+     *
+     * @throws IOException
+     */
+    public void println(char x[]) throws IOException {
+        print(x);
+        println();
+    }
+    
+    /**
+     * Print a String and then terminate the line.  This method behaves as
+     * though it invokes <code>{@link #print(String)}</code> and then
+     * <code>{@link #println()}</code>.
+     *
+     * @throws IOException
+     */
+    public void println(String x) throws IOException {
+        print(x);
+        println();
+    }
+    
+    /**
+     * Print an Object and then terminate the line.  This method behaves as
+     * though it invokes <code>{@link #print(Object)}</code> and then
+     * <code>{@link #println()}</code>.
+     *
+     * @throws IOException
+     */
+    public void println(Object x) throws IOException {
+        print(x);
+        println();
+    }
+    
+    /**
+     * Clear the contents of the buffer. If the buffer has been already
+     * been flushed then the clear operation shall throw an IOException
+     * to signal the fact that some data has already been irrevocably 
+     * written to the client response stream.
+     *
+     * @throws IOException If an I/O error occurs
+     */
+    public void clear() throws IOException {
+        if (writer != null) {
+            throw new IOException();
+        } else {
+            nextChar = 0;
+            if (LIMIT_BUFFER && (cb.length > Constants.DEFAULT_TAG_BUFFER_SIZE)) {
+                bufferSize = Constants.DEFAULT_TAG_BUFFER_SIZE;
+                cb = new char[bufferSize];
+            }
+        }
+    }
+    
+    /**
+     * Clears the current contents of the buffer. Unlike clear(), this
+     * mehtod will not throw an IOException if the buffer has already been
+     * flushed. It merely clears the current content of the buffer and
+     * returns.
+     *
+     * @throws IOException If an I/O error occurs
+     */
+    public void clearBuffer() throws IOException {
+        if (writer == null) {
+            this.clear();
+        }
+    }
+    
+    /**
+     * Close the stream, flushing it first.  Once a stream has been closed,
+     * further write() or flush() invocations will cause an IOException to be
+     * thrown.  Closing a previously-closed stream, however, has no effect.
+     *
+     * @throws IOException If an I/O error occurs
+     */
+    public void close() throws IOException {
+        if (writer != null) {
+            writer.close();
+        } else {
+            closed = true;
+        }
+    }
+    
+    /**
+     * @return the number of bytes unused in the buffer
+     */
+    public int getRemaining() {
+        return (writer == null) ? bufferSize-nextChar : 0;
+    }
+    
+    /**
+     * Return the value of this BodyJspWriter as a Reader.
+     * Note: this is after evaluation!!  There are no scriptlets,
+     * etc in this stream.
+     *
+     * @return the value of this BodyJspWriter as a Reader
+     */
+    public Reader getReader() {
+        return (writer == null) ? new CharArrayReader (cb, 0, nextChar) : null;
+    }
+    
+    /**
+     * Return the value of the BodyJspWriter as a String.
+     * Note: this is after evaluation!!  There are no scriptlets,
+     * etc in this stream.
+     *
+     * @return the value of the BodyJspWriter as a String
+     */
+    public String getString() {
+        return (writer == null) ? new String(cb, 0, nextChar) : null;
+    }
+    
+    /**
+     * Write the contents of this BodyJspWriter into a Writer.
+     * Subclasses are likely to do interesting things with the
+     * implementation so some things are extra efficient.
+     *
+     * @param out The writer into which to place the contents of this body
+     * evaluation
+     */
+    public void writeOut(Writer out) throws IOException {
+        if (writer == null) {
+            out.write(cb, 0, nextChar);
+            // Flush not called as the writer passed could be a BodyContent and
+            // it doesn't allow to flush.
+        }
+    }
+    
+    /**
+     * Sets the writer to which all output is written.
+     */
+    void setWriter(Writer writer) {
+        this.writer = writer;
+        closed = false;
+        if (writer != null) {
+            // According to the spec, the JspWriter returned by 
+            // JspContext.pushBody(java.io.Writer writer) must behave as
+            // though it were unbuffered. This means that its getBufferSize()
+            // must always return 0. The implementation of
+            // JspWriter.getBufferSize() returns the value of JspWriter's
+            // 'bufferSize' field, which is inherited by this class. 
+            // Therefore, we simply save the current 'bufferSize' (so we can 
+            // later restore it should this BodyContentImpl ever be reused by
+            // a call to PageContext.pushBody()) before setting it to 0.
+            if (bufferSize != 0) {
+                bufferSizeSave = bufferSize;
+                bufferSize = 0;
+            }
+        } else {
+            bufferSize = bufferSizeSave;
+            clearBody();
+        }
+    }
+    
+    private void ensureOpen() throws IOException {
+        if (closed) throw new IOException("Stream closed");
+    }
+    
+    /**
+     * Reallocates buffer since the spec requires it to be unbounded.
+     */
+    private void reAllocBuff(int len) {
+        
+        if (bufferSize + len <= cb.length) {
+            bufferSize = cb.length;
+            return;
+        }
+        
+        if (len < cb.length) {
+            len = cb.length;
+        }
+        
+        bufferSize = cb.length + len;
+        char[] tmp = new char[bufferSize];
+        
+        System.arraycopy(cb, 0, tmp, 0, cb.length);
+        cb = tmp;
+        tmp = null;
+        
+    }
+    
+    
+}

Added: branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/runtime/HttpJspBase.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/runtime/HttpJspBase.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/runtime/HttpJspBase.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,115 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.IOException;
+
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.jsp.HttpJspPage;
+import javax.servlet.jsp.JspFactory;
+
+import org.apache.jasper.compiler.Localizer;
+
+/**
+ * This is the super class of all JSP-generated servlets.
+ *
+ * @author Anil K. Vijendran
+ */
+public abstract class HttpJspBase 
+    extends HttpServlet 
+    implements HttpJspPage 
+        
+    
+{
+    
+    static {
+        if( JspFactory.getDefaultFactory() == null ) {
+            JspFactoryImpl factory = new JspFactoryImpl();
+            if( System.getSecurityManager() != null ) {
+                String basePackage = "org.apache.jasper.";
+                try {
+                    factory.getClass().getClassLoader().loadClass( basePackage +
+                                                                   "runtime.JspFactoryImpl$PrivilegedGetPageContext");
+                    factory.getClass().getClassLoader().loadClass( basePackage +
+                                                                   "runtime.JspFactoryImpl$PrivilegedReleasePageContext");
+                    factory.getClass().getClassLoader().loadClass( basePackage +
+                                                                   "runtime.JspRuntimeLibrary");
+                    factory.getClass().getClassLoader().loadClass( basePackage +
+                                                                   "runtime.JspRuntimeLibrary$PrivilegedIntrospectHelper");
+                    factory.getClass().getClassLoader().loadClass( basePackage +
+                                                                   "runtime.ServletResponseWrapperInclude");
+                    factory.getClass().getClassLoader().loadClass( basePackage +
+                                                                   "servlet.JspServletWrapper");
+                } catch (ClassNotFoundException ex) {
+                    org.apache.commons.logging.LogFactory.getLog( HttpJspBase.class )
+                        .error("Jasper JspRuntimeContext preload of class failed: " +
+                                       ex.getMessage(), ex);
+                }
+            }
+            JspFactory.setDefaultFactory(factory);
+        }
+    }
+
+    protected HttpJspBase() {
+    }
+
+    public final void init(ServletConfig config) 
+	throws ServletException 
+    {
+        super.init(config);
+	jspInit();
+        _jspInit();
+    }
+    
+    public String getServletInfo() {
+	return Localizer.getMessage("jsp.engine.info");
+    }
+
+    public final void destroy() {
+	jspDestroy();
+	_jspDestroy();
+    }
+
+    /**
+     * Entry point into service.
+     */
+    public final void service(HttpServletRequest request, HttpServletResponse response) 
+	throws ServletException, IOException 
+    {
+        _jspService(request, response);
+    }
+    
+    public void jspInit() {
+    }
+
+    public void _jspInit() {
+    }
+
+    public void jspDestroy() {
+    }
+
+    protected void _jspDestroy() {
+    }
+
+    public abstract void _jspService(HttpServletRequest request, 
+				     HttpServletResponse response) 
+	throws ServletException, IOException;
+}

Added: branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/runtime/JspContextWrapper.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/runtime/JspContextWrapper.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/runtime/JspContextWrapper.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,454 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.IOException;
+import java.io.Writer;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.Map;
+
+import javax.servlet.Servlet;
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpSession;
+import javax.servlet.jsp.JspContext;
+import javax.servlet.jsp.JspWriter;
+import javax.servlet.jsp.PageContext;
+import javax.servlet.jsp.el.ELException;
+import javax.servlet.jsp.el.ExpressionEvaluator;
+import javax.servlet.jsp.el.VariableResolver;
+import javax.servlet.jsp.tagext.BodyContent;
+import javax.servlet.jsp.tagext.VariableInfo;
+
+import org.apache.commons.el.VariableResolverImpl;
+import org.apache.jasper.compiler.Localizer;
+
+/**
+ * Implementation of a JSP Context Wrapper.
+ *
+ * The JSP Context Wrapper is a JspContext created and maintained by a tag
+ * handler implementation. It wraps the Invoking JSP Context, that is, the
+ * JspContext instance passed to the tag handler by the invoking page via
+ * setJspContext().
+ *
+ * @author Kin-man Chung
+ * @author Jan Luehe
+ */
+public class JspContextWrapper
+            extends PageContext implements VariableResolver {
+
+    // Invoking JSP context
+    private PageContext invokingJspCtxt;
+
+    private transient Hashtable	pageAttributes;
+
+    // ArrayList of NESTED scripting variables
+    private ArrayList nestedVars;
+
+    // ArrayList of AT_BEGIN scripting variables
+    private ArrayList atBeginVars;
+
+    // ArrayList of AT_END scripting variables
+    private ArrayList atEndVars;
+
+    private Map aliases;
+
+    private Hashtable originalNestedVars;
+
+    /**
+     * The variable resolver, for evaluating EL expressions.
+     */
+    private VariableResolverImpl variableResolver
+        = new VariableResolverImpl(this);
+
+    public JspContextWrapper(JspContext jspContext, ArrayList nestedVars,
+			     ArrayList atBeginVars, ArrayList atEndVars,
+			     Map aliases) {
+        this.invokingJspCtxt = (PageContext) jspContext;
+	this.nestedVars = nestedVars;
+	this.atBeginVars = atBeginVars;
+	this.atEndVars = atEndVars;
+	this.pageAttributes = new Hashtable(16);
+	this.aliases = aliases;
+
+	if (nestedVars != null) {
+	    this.originalNestedVars = new Hashtable(nestedVars.size());
+	}
+	syncBeginTagFile();
+    }
+
+    public void initialize(Servlet servlet, ServletRequest request,
+                           ServletResponse response, String errorPageURL,
+                           boolean needsSession, int bufferSize,
+                           boolean autoFlush)
+        throws IOException, IllegalStateException, IllegalArgumentException
+    {
+    }
+    
+    public Object getAttribute(String name) {
+
+	if (name == null) {
+	    throw new NullPointerException(
+	            Localizer.getMessage("jsp.error.attribute.null_name"));
+	}
+
+	return pageAttributes.get(name);
+    }
+
+    public Object getAttribute(String name, int scope) {
+
+	if (name == null) {
+	    throw new NullPointerException(
+	            Localizer.getMessage("jsp.error.attribute.null_name"));
+	}
+
+	if (scope == PAGE_SCOPE) {
+	    return pageAttributes.get(name);
+	}
+
+	return invokingJspCtxt.getAttribute(name, scope);
+    }
+
+    public void setAttribute(String name, Object value) {
+
+	if (name == null) {
+	    throw new NullPointerException(
+	            Localizer.getMessage("jsp.error.attribute.null_name"));
+	}
+
+	if (value != null) {
+	    pageAttributes.put(name, value);
+	} else {
+	    removeAttribute(name, PAGE_SCOPE);
+	}
+    }
+
+    public void setAttribute(String name, Object value, int scope) {
+
+	if (name == null) {
+	    throw new NullPointerException(
+	            Localizer.getMessage("jsp.error.attribute.null_name"));
+	}
+
+	if (scope == PAGE_SCOPE) {
+	    if (value != null) {
+		pageAttributes.put(name, value);
+	    } else {
+		removeAttribute(name, PAGE_SCOPE);
+	    }
+	} else {
+	    invokingJspCtxt.setAttribute(name, value, scope);
+	}
+    }
+
+    public Object findAttribute(String name) {
+
+	if (name == null) {
+	    throw new NullPointerException(
+	            Localizer.getMessage("jsp.error.attribute.null_name"));
+	}
+
+        Object o = pageAttributes.get(name);
+        if (o == null) {
+	    o = invokingJspCtxt.getAttribute(name, REQUEST_SCOPE);
+	    if (o == null) {
+		if (getSession() != null) {
+		    o = invokingJspCtxt.getAttribute(name, SESSION_SCOPE);
+		}
+		if (o == null) {
+		    o = invokingJspCtxt.getAttribute(name, APPLICATION_SCOPE);
+		} 
+	    }
+	}
+
+	return o;
+    }
+
+    public void removeAttribute(String name) {
+
+	if (name == null) {
+	    throw new NullPointerException(
+	            Localizer.getMessage("jsp.error.attribute.null_name"));
+	}
+
+	pageAttributes.remove(name);
+	invokingJspCtxt.removeAttribute(name, REQUEST_SCOPE);
+	if (getSession() != null) {
+	    invokingJspCtxt.removeAttribute(name, SESSION_SCOPE);
+	}
+	invokingJspCtxt.removeAttribute(name, APPLICATION_SCOPE);
+    }
+
+    public void removeAttribute(String name, int scope) {
+
+	if (name == null) {
+	    throw new NullPointerException(
+	            Localizer.getMessage("jsp.error.attribute.null_name"));
+	}
+
+	if (scope == PAGE_SCOPE){
+	    pageAttributes.remove(name);
+	} else {
+	    invokingJspCtxt.removeAttribute(name, scope);
+	}
+    }
+
+    public int getAttributesScope(String name) {
+
+	if (name == null) {
+	    throw new NullPointerException(
+	            Localizer.getMessage("jsp.error.attribute.null_name"));
+	}
+
+	if (pageAttributes.get(name) != null) {
+	    return PAGE_SCOPE;
+	} else {
+	    return invokingJspCtxt.getAttributesScope(name);
+	}
+    }
+
+    public Enumeration getAttributeNamesInScope(int scope) {
+        if (scope == PAGE_SCOPE) {
+            return pageAttributes.keys();
+	}
+
+	return invokingJspCtxt.getAttributeNamesInScope(scope);
+    }
+
+    public void release() {
+	invokingJspCtxt.release();
+    }
+
+    public JspWriter getOut() {
+	return invokingJspCtxt.getOut();
+    }
+
+    public HttpSession getSession() {
+	return invokingJspCtxt.getSession();
+    }
+
+    public Object getPage() {
+	return invokingJspCtxt.getPage();
+    }
+
+    public ServletRequest getRequest() {
+	return invokingJspCtxt.getRequest();
+    }
+
+    public ServletResponse getResponse() {
+	return invokingJspCtxt.getResponse();
+    }
+
+    public Exception getException() {
+	return invokingJspCtxt.getException();
+    }
+
+    public ServletConfig getServletConfig() {
+	return invokingJspCtxt.getServletConfig();
+    }
+
+    public ServletContext getServletContext() {
+	return invokingJspCtxt.getServletContext();
+    }
+
+    public void forward(String relativeUrlPath)
+        throws ServletException, IOException
+    {
+	invokingJspCtxt.forward(relativeUrlPath);
+    }
+
+    public void include(String relativeUrlPath)
+	throws ServletException, IOException
+    {
+	invokingJspCtxt.include(relativeUrlPath);
+    }
+
+    public void include(String relativeUrlPath, boolean flush) 
+	    throws ServletException, IOException {
+	include(relativeUrlPath, false); // XXX
+    }
+
+    public VariableResolver getVariableResolver() {
+	return this;
+    }
+
+    public BodyContent pushBody() {
+	return invokingJspCtxt.pushBody();
+    }
+
+    public JspWriter pushBody(Writer writer) {
+	return invokingJspCtxt.pushBody(writer);
+    }
+
+    public JspWriter popBody() {
+        return invokingJspCtxt.popBody();
+    }
+
+    public ExpressionEvaluator getExpressionEvaluator() {
+	return invokingJspCtxt.getExpressionEvaluator();
+    }
+
+    public void handlePageException(Exception ex)
+        throws IOException, ServletException 
+    {
+	// Should never be called since handleException() called with a
+	// Throwable in the generated servlet.
+	handlePageException((Throwable) ex);
+    }
+
+    public void handlePageException(Throwable t)
+        throws IOException, ServletException 
+    {
+	invokingJspCtxt.handlePageException(t);
+    }
+
+    /**
+     * VariableResolver interface
+     */
+    public Object resolveVariable( String pName ) throws ELException
+    {
+        return variableResolver.resolveVariable(pName);
+    }
+
+    /**
+     * Synchronize variables at begin of tag file
+     */
+    public void syncBeginTagFile() {
+	saveNestedVariables();
+    }
+
+    /**
+     * Synchronize variables before fragment invokation
+     */
+    public void syncBeforeInvoke() {
+	copyTagToPageScope(VariableInfo.NESTED);
+	copyTagToPageScope(VariableInfo.AT_BEGIN);
+    }
+
+    /**
+     * Synchronize variables at end of tag file
+     */
+    public void syncEndTagFile() {
+	copyTagToPageScope(VariableInfo.AT_BEGIN);
+	copyTagToPageScope(VariableInfo.AT_END);
+	restoreNestedVariables();
+    }
+
+    /**
+     * Copies the variables of the given scope from the virtual page scope of
+     * this JSP context wrapper to the page scope of the invoking JSP context.
+     *
+     * @param scope variable scope (one of NESTED, AT_BEGIN, or AT_END)
+     */
+    private void copyTagToPageScope(int scope) {
+	Iterator iter = null;
+
+	switch (scope) {
+	case VariableInfo.NESTED:
+	    if (nestedVars != null) {
+		iter = nestedVars.iterator();
+	    }
+	    break;
+	case VariableInfo.AT_BEGIN:
+	    if (atBeginVars != null) {
+		iter = atBeginVars.iterator();
+	    }
+	    break;
+	case VariableInfo.AT_END:
+	    if (atEndVars != null) {
+		iter = atEndVars.iterator();
+	    }
+	    break;
+	}
+
+	while ((iter != null) && iter.hasNext()) {
+	    String varName = (String) iter.next();
+	    Object obj = getAttribute(varName);
+	    varName = findAlias(varName);
+	    if (obj != null) {
+		invokingJspCtxt.setAttribute(varName, obj);
+	    } else {
+		invokingJspCtxt.removeAttribute(varName, PAGE_SCOPE);
+	    }
+	}
+    }
+
+    /**
+     * Saves the values of any NESTED variables that are present in
+     * the invoking JSP context, so they can later be restored.
+     */
+    private void saveNestedVariables() {
+	if (nestedVars != null) {
+	    Iterator iter = nestedVars.iterator();
+	    while (iter.hasNext()) {
+		String varName = (String) iter.next();
+		varName = findAlias(varName);
+		Object obj = invokingJspCtxt.getAttribute(varName);
+		if (obj != null) {
+		    originalNestedVars.put(varName, obj);
+		}
+	    }
+	}
+    }
+
+    /**
+     * Restores the values of any NESTED variables in the invoking JSP
+     * context.
+     */
+    private void restoreNestedVariables() {
+	if (nestedVars != null) {
+	    Iterator iter = nestedVars.iterator();
+	    while (iter.hasNext()) {
+		String varName = (String) iter.next();
+		varName = findAlias(varName);
+		Object obj = originalNestedVars.get(varName);
+		if (obj != null) {
+		    invokingJspCtxt.setAttribute(varName, obj);
+		} else {
+		    invokingJspCtxt.removeAttribute(varName, PAGE_SCOPE);
+		}
+	    }
+	}
+    }
+
+    /**
+     * Checks to see if the given variable name is used as an alias, and if so,
+     * returns the variable name for which it is used as an alias.
+     *
+     * @param varName The variable name to check
+     * @return The variable name for which varName is used as an alias, or
+     * varName if it is not being used as an alias
+     */
+    private String findAlias(String varName) {
+
+	if (aliases == null)
+	    return varName;
+
+	String alias = (String) aliases.get(varName);
+	if (alias == null) {
+	    return varName;
+	}
+	return alias;
+    }
+}
+

Added: branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/runtime/JspFactoryImpl.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/runtime/JspFactoryImpl.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/runtime/JspFactoryImpl.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,177 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.security.AccessController;
+import java.security.PrivilegedAction;
+
+import javax.servlet.Servlet;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.jsp.JspFactory;
+import javax.servlet.jsp.JspEngineInfo;
+import javax.servlet.jsp.PageContext;
+
+import org.apache.jasper.util.SimplePool;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * Implementation of JspFactory.
+ *
+ * @author Anil K. Vijendran
+ */
+public class JspFactoryImpl extends JspFactory {
+
+    // Logger
+    private Log log = LogFactory.getLog(JspFactoryImpl.class);
+
+    private static final String SPEC_VERSION = "2.0";
+    private static final boolean USE_POOL = 
+        Boolean.valueOf(System.getProperty("org.apache.jasper.runtime.JspFactoryImpl.USE_POOL", "true")).booleanValue();
+
+    private SimplePool pool = new SimplePool(100);
+    
+    public PageContext getPageContext(Servlet servlet,
+				      ServletRequest request,
+                                      ServletResponse response,
+                                      String errorPageURL,                    
+                                      boolean needsSession,
+				      int bufferSize,
+                                      boolean autoflush) {
+	if( System.getSecurityManager() != null ) {
+	    PrivilegedGetPageContext dp = new PrivilegedGetPageContext(
+		(JspFactoryImpl)this, servlet, request, response, errorPageURL,
+                needsSession, bufferSize, autoflush);
+	    return (PageContext)AccessController.doPrivileged(dp);
+	} else {
+	    return internalGetPageContext(servlet, request, response,
+					  errorPageURL, needsSession,
+					  bufferSize, autoflush);
+	}
+    }
+
+    public void releasePageContext(PageContext pc) {
+	if( pc == null )
+	    return;
+        if( System.getSecurityManager() != null ) {
+            PrivilegedReleasePageContext dp = new PrivilegedReleasePageContext(
+                (JspFactoryImpl)this,pc);
+            AccessController.doPrivileged(dp);
+        } else {
+            internalReleasePageContext(pc);
+	}
+    }
+
+    public JspEngineInfo getEngineInfo() {
+        return new JspEngineInfo() {
+		public String getSpecificationVersion() {
+		    return SPEC_VERSION;
+		}
+	    };
+    }
+
+    private PageContext internalGetPageContext(Servlet servlet,
+					       ServletRequest request,
+					       ServletResponse response, 
+					       String errorPageURL, 
+					       boolean needsSession,
+					       int bufferSize, 
+					       boolean autoflush) {
+        try {
+	    PageContext pc;
+	    if( USE_POOL ) {
+                pc = (PageContext) pool.get();
+		if( pc == null ) {
+		    pc= new PageContextImpl(this);
+		}
+	    } else {
+		pc = new PageContextImpl(this);
+	    }
+	    pc.initialize(servlet, request, response, errorPageURL, 
+                          needsSession, bufferSize, autoflush);
+            return pc;
+        } catch (Throwable ex) {
+            /* FIXME: need to do something reasonable here!! */
+            log.fatal("Exception initializing page context", ex);
+            return null;
+        }
+    }
+
+    private void internalReleasePageContext(PageContext pc) {
+        pc.release();
+	if (USE_POOL && (pc instanceof PageContextImpl)) {
+	    pool.put( pc );
+	}
+    }
+
+    private class PrivilegedGetPageContext implements PrivilegedAction {
+
+	private JspFactoryImpl factory;
+	private Servlet servlet;
+	private ServletRequest request;
+	private ServletResponse response;
+	private String errorPageURL;
+	private boolean needsSession;
+	private int bufferSize;
+	private boolean autoflush;
+
+	PrivilegedGetPageContext(JspFactoryImpl factory,
+				 Servlet servlet,
+				 ServletRequest request,
+				 ServletResponse response,
+				 String errorPageURL,
+				 boolean needsSession,
+				 int bufferSize,
+				 boolean autoflush) {
+	    this.factory = factory;
+	    this.servlet = servlet;
+	    this.request = request;
+	    this.response = response;
+	    this.errorPageURL = errorPageURL;
+	    this.needsSession = needsSession;
+	    this.bufferSize = bufferSize;
+	    this.autoflush = autoflush;
+	}
+ 
+	public Object run() {
+	    return factory.internalGetPageContext(servlet,
+						  request,
+						  response,
+						  errorPageURL,
+						  needsSession,
+						  bufferSize,
+						  autoflush);
+	}
+    }
+
+    private class PrivilegedReleasePageContext implements PrivilegedAction {
+
+        private JspFactoryImpl factory;
+	private PageContext pageContext;
+
+        PrivilegedReleasePageContext(JspFactoryImpl factory,
+				     PageContext pageContext) {
+            this.factory = factory;
+            this.pageContext = pageContext;
+        }
+
+        public Object run() {
+            factory.internalReleasePageContext(pageContext);
+	    return null;
+        }
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/runtime/JspFragmentHelper.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/runtime/JspFragmentHelper.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/runtime/JspFragmentHelper.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,64 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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 javax.servlet.jsp.JspContext;
+import javax.servlet.jsp.PageContext;
+import javax.servlet.jsp.tagext.JspFragment;
+import javax.servlet.jsp.tagext.JspTag;
+
+/**
+ * Helper class from which all Jsp Fragment helper classes extend.
+ * This class allows for the emulation of numerous fragments within
+ * a single class, which in turn reduces the load on the class loader
+ * since there are potentially many JspFragments in a single page.
+ * <p>
+ * The class also provides various utility methods for JspFragment
+ * implementations.
+ *
+ * @author Mark Roth
+ */
+public abstract class JspFragmentHelper 
+    extends JspFragment 
+{
+    
+    protected int discriminator;
+    protected JspContext jspContext;
+    protected PageContext _jspx_page_context;
+    protected JspTag parentTag;
+
+    public JspFragmentHelper( int discriminator, JspContext jspContext, 
+        JspTag parentTag ) 
+    {
+        this.discriminator = discriminator;
+        this.jspContext = jspContext;
+        this._jspx_page_context = null;
+        if( jspContext instanceof PageContext ) {
+            _jspx_page_context = (PageContext)jspContext;
+        }
+        this.parentTag = parentTag;
+    }
+    
+    public JspContext getJspContext() {
+        return this.jspContext;
+    }
+    
+    public JspTag getParentTag() {
+        return this.parentTag;
+    }
+    
+}

Added: branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/runtime/JspRuntimeLibrary.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/runtime/JspRuntimeLibrary.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/runtime/JspRuntimeLibrary.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,1045 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.beans.PropertyEditor;
+import java.beans.PropertyEditorManager;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.lang.reflect.Method;
+import java.security.AccessController;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
+import java.util.Enumeration;
+
+import javax.servlet.RequestDispatcher;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.jsp.JspWriter;
+import javax.servlet.jsp.PageContext;
+import javax.servlet.jsp.tagext.BodyContent;
+
+import org.apache.jasper.JasperException;
+import org.apache.jasper.compiler.Localizer;
+
+/**
+ * Bunch of util methods that are used by code generated for useBean,
+ * getProperty and setProperty.  
+ *
+ * The __begin, __end stuff is there so that the JSP engine can
+ * actually parse this file and inline them if people don't want
+ * runtime dependencies on this class. However, I'm not sure if that
+ * works so well right now. It got forgotten at some point. -akv
+ *
+ * @author Mandar Raje
+ * @author Shawn Bayern
+ */
+public class JspRuntimeLibrary {
+    
+    private static final String SERVLET_EXCEPTION
+	= "javax.servlet.error.exception";
+    private static final String JSP_EXCEPTION
+	= "javax.servlet.jsp.jspException";
+
+    protected static class PrivilegedIntrospectHelper
+	implements PrivilegedExceptionAction {
+
+	private Object bean;
+	private String prop;
+	private String value;
+	private ServletRequest request;
+	private String param;
+	private boolean ignoreMethodNF;
+
+        PrivilegedIntrospectHelper(Object bean, String prop,
+                                   String value, ServletRequest request,
+                                   String param, boolean ignoreMethodNF)
+        {
+	    this.bean = bean;
+	    this.prop = prop;
+	    this.value = value;
+            this.request = request;
+	    this.param = param;
+	    this.ignoreMethodNF = ignoreMethodNF;
+        }
+         
+        public Object run() throws JasperException {
+	    internalIntrospecthelper(
+                bean,prop,value,request,param,ignoreMethodNF);
+            return null;
+        }
+    }
+
+    /**
+     * Returns the value of the javax.servlet.error.exception request
+     * attribute value, if present, otherwise the value of the
+     * javax.servlet.jsp.jspException request attribute value.
+     *
+     * This method is called at the beginning of the generated servlet code
+     * for a JSP error page, when the "exception" implicit scripting language
+     * variable is initialized.
+     */
+    public static Throwable getThrowable(ServletRequest request) {
+	Throwable error = (Throwable) request.getAttribute(SERVLET_EXCEPTION);
+	if (error == null) {
+	    error = (Throwable) request.getAttribute(JSP_EXCEPTION);
+	    if (error != null) {
+		/*
+		 * The only place that sets JSP_EXCEPTION is
+		 * PageContextImpl.handlePageException(). It really should set
+		 * SERVLET_EXCEPTION, but that would interfere with the 
+		 * ErrorReportValve. Therefore, if JSP_EXCEPTION is set, we
+		 * need to set SERVLET_EXCEPTION.
+		 */
+		request.setAttribute(SERVLET_EXCEPTION, error);
+	    }
+	}
+
+	return error;
+    }
+
+    public static boolean coerceToBoolean(String s) {
+	if (s == null || s.length() == 0)
+	    return false;
+	else
+	    return Boolean.valueOf(s).booleanValue();
+    }
+
+    public static byte coerceToByte(String s) {
+	if (s == null || s.length() == 0)
+	    return (byte) 0;
+	else
+	    return Byte.valueOf(s).byteValue();
+    }
+
+    public static char coerceToChar(String s) {
+	if (s == null || s.length() == 0) {
+	    return (char) 0;
+	} else {
+	    // this trick avoids escaping issues
+	    return (char)(int) s.charAt(0);
+	}
+    }
+
+    public static double coerceToDouble(String s) {
+	if (s == null || s.length() == 0)
+	    return (double) 0;
+	else
+	    return Double.valueOf(s).doubleValue();
+    }
+
+    public static float coerceToFloat(String s) {
+	if (s == null || s.length() == 0)
+	    return (float) 0;
+	else
+	    return Float.valueOf(s).floatValue();
+    }
+
+    public static int coerceToInt(String s) {
+	if (s == null || s.length() == 0)
+	    return 0;
+	else
+	    return Integer.valueOf(s).intValue();
+    }
+
+    public static short coerceToShort(String s) {
+	if (s == null || s.length() == 0)
+	    return (short) 0;
+	else
+	    return Short.valueOf(s).shortValue();
+    }
+
+    public static long coerceToLong(String s) {
+	if (s == null || s.length() == 0)
+	    return (long) 0;
+	else
+	    return Long.valueOf(s).longValue();
+    }
+
+    public static Object coerce(String s, Class target) {
+
+	boolean isNullOrEmpty = (s == null || s.length() == 0);
+
+	if (target == Boolean.class) {
+	    if (isNullOrEmpty) {
+		s = "false";
+	    }
+	    return new Boolean(s);
+	} else if (target == Byte.class) {
+	    if (isNullOrEmpty)
+		return new Byte((byte) 0);
+	    else
+		return new Byte(s);
+	} else if (target == Character.class) {
+	    if (isNullOrEmpty)
+		return new Character((char) 0);
+	    else 
+		return new Character(s.charAt(0));
+	} else if (target == Double.class) {
+	    if (isNullOrEmpty)
+		return new Double(0);
+	    else
+		return new Double(s);
+	} else if (target == Float.class) {
+	    if (isNullOrEmpty)
+		return new Float(0);
+	    else
+		return new Float(s);
+	} else if (target == Integer.class) {
+	    if (isNullOrEmpty)
+		return new Integer(0);
+	    else
+		return new Integer(s);
+	} else if (target == Short.class) {
+	    if (isNullOrEmpty)
+		return new Short((short) 0);
+	    else
+		return new Short(s);
+	} else if (target == Long.class) {
+	    if (isNullOrEmpty)
+		return new Long(0);
+	    else
+		return new Long(s);
+	} else {
+	    return null;
+	}
+    }
+
+   // __begin convertMethod
+    public static Object convert(String propertyName, String s, Class t,
+				 Class propertyEditorClass) 
+       throws JasperException 
+    {
+        try {
+            if (s == null) {
+                if (t.equals(Boolean.class) || t.equals(Boolean.TYPE))
+                    s = "false";
+                else
+                    return null;
+            }
+	    if (propertyEditorClass != null) {
+		return getValueFromBeanInfoPropertyEditor(
+				    t, propertyName, s, propertyEditorClass);
+	    } else if ( t.equals(Boolean.class) || t.equals(Boolean.TYPE) ) {
+                if (s.equalsIgnoreCase("on") || s.equalsIgnoreCase("true"))
+                    s = "true";
+                else
+                    s = "false";
+                return new Boolean(s);
+            } else if ( t.equals(Byte.class) || t.equals(Byte.TYPE) ) {
+                return new Byte(s);
+            } else if (t.equals(Character.class) || t.equals(Character.TYPE)) {
+                return s.length() > 0 ? new Character(s.charAt(0)) : null;
+            } else if ( t.equals(Short.class) || t.equals(Short.TYPE) ) {
+                return new Short(s);
+            } else if ( t.equals(Integer.class) || t.equals(Integer.TYPE) ) {
+                return new Integer(s);
+            } else if ( t.equals(Float.class) || t.equals(Float.TYPE) ) {
+                return new Float(s);
+            } else if ( t.equals(Long.class) || t.equals(Long.TYPE) ) {
+                return new Long(s);
+            } else if ( t.equals(Double.class) || t.equals(Double.TYPE) ) {
+                return new Double(s);
+            } else if ( t.equals(String.class) ) {
+                return s;
+            } else if ( t.equals(java.io.File.class) ) {
+                return new java.io.File(s);
+            } else if (t.getName().equals("java.lang.Object")) {
+                return new Object[] {s};
+	    } else {
+		return getValueFromPropertyEditorManager(
+                                            t, propertyName, s);
+            }
+        } catch (Exception ex) {
+            throw new JasperException(ex);
+        }
+    }
+    // __end convertMethod
+
+    // __begin introspectMethod
+    public static void introspect(Object bean, ServletRequest request)
+                                  throws JasperException
+    {
+	Enumeration e = request.getParameterNames();
+	while ( e.hasMoreElements() ) {
+	    String name  = (String) e.nextElement();
+	    String value = request.getParameter(name);
+	    introspecthelper(bean, name, value, request, name, true);
+	}
+    }
+    // __end introspectMethod
+    
+    // __begin introspecthelperMethod
+    public static void introspecthelper(Object bean, String prop,
+                                        String value, ServletRequest request,
+                                        String param, boolean ignoreMethodNF)
+                                        throws JasperException
+    {
+        if( System.getSecurityManager() != null ) {
+            try {
+                PrivilegedIntrospectHelper dp =
+		    new PrivilegedIntrospectHelper(
+			bean,prop,value,request,param,ignoreMethodNF);
+                AccessController.doPrivileged(dp);
+            } catch( PrivilegedActionException pe) {
+                Exception e = pe.getException();
+                throw (JasperException)e;
+            }
+        } else {
+            internalIntrospecthelper(
+		bean,prop,value,request,param,ignoreMethodNF);
+        }
+    }
+
+    private static void internalIntrospecthelper(Object bean, String prop,
+					String value, ServletRequest request,
+					String param, boolean ignoreMethodNF) 
+					throws JasperException
+    {
+        Method method = null;
+        Class type = null;
+        Class propertyEditorClass = null;
+	try {
+	    java.beans.BeanInfo info
+		= java.beans.Introspector.getBeanInfo(bean.getClass());
+	    if ( info != null ) {
+		java.beans.PropertyDescriptor pd[]
+		    = info.getPropertyDescriptors();
+		for (int i = 0 ; i < pd.length ; i++) {
+		    if ( pd[i].getName().equals(prop) ) {
+			method = pd[i].getWriteMethod();
+			type   = pd[i].getPropertyType();
+			propertyEditorClass = pd[i].getPropertyEditorClass();
+			break;
+		    }
+		}
+	    }
+	    if ( method != null ) {
+		if (type.isArray()) {
+                    if (request == null) {
+			throw new JasperException(
+		            Localizer.getMessage("jsp.error.beans.setproperty.noindexset"));
+                    }
+		    Class t = type.getComponentType();
+		    String[] values = request.getParameterValues(param);
+		    //XXX Please check.
+		    if(values == null) return;
+		    if(t.equals(String.class)) {
+			method.invoke(bean, new Object[] { values });
+		    } else {
+			Object tmpval = null;
+			createTypedArray (prop, bean, method, values, t,
+					  propertyEditorClass); 
+		    }
+		} else {
+		    if(value == null || (param != null && value.equals(""))) return;
+		    Object oval = convert(prop, value, type, propertyEditorClass);
+		    if ( oval != null )
+			method.invoke(bean, new Object[] { oval });
+		}
+	    }
+	} catch (Exception ex) {
+	    throw new JasperException(ex);
+	}
+        if (!ignoreMethodNF && (method == null)) {
+            if (type == null) {
+		throw new JasperException(
+                    Localizer.getMessage("jsp.error.beans.noproperty",
+					 prop,
+					 bean.getClass().getName()));
+            } else {
+		throw new JasperException(
+	            Localizer.getMessage("jsp.error.beans.nomethod.setproperty",
+					 prop,
+					 type.getName(),
+					 bean.getClass().getName()));
+            }
+        }
+    }
+    // __end introspecthelperMethod
+    
+    //-------------------------------------------------------------------
+    // functions to convert builtin Java data types to string.
+    //-------------------------------------------------------------------
+    // __begin toStringMethod
+    public static String toString(Object o) {
+        return String.valueOf(o);
+    }
+
+    public static String toString(byte b) {
+        return new Byte(b).toString();
+    }
+
+    public static String toString(boolean b) {
+        return new Boolean(b).toString();
+    }
+
+    public static String toString(short s) {
+        return new Short(s).toString();
+    }
+
+    public static String toString(int i) {
+        return new Integer(i).toString();
+    }
+
+    public static String toString(float f) {
+        return new Float(f).toString();
+    }
+
+    public static String toString(long l) {
+        return new Long(l).toString();
+    }
+
+    public static String toString(double d) {
+        return new Double(d).toString();
+    }
+
+    public static String toString(char c) {
+        return new Character(c).toString();
+    }
+    // __end toStringMethod
+
+
+    /**
+     * Create a typed array.
+     * This is a special case where params are passed through
+     * the request and the property is indexed.
+     */
+    public static void createTypedArray(String propertyName,
+					Object bean,
+					Method method,
+					String[] values,
+					Class t,
+					Class propertyEditorClass)
+	        throws JasperException {
+
+	try {
+	    if (propertyEditorClass != null) {
+		Object[] tmpval = new Integer[values.length];
+		for (int i=0; i<values.length; i++) {
+		    tmpval[i] = getValueFromBeanInfoPropertyEditor(
+                            t, propertyName, values[i], propertyEditorClass);
+		}
+		method.invoke (bean, new Object[] {tmpval});
+	    } else if (t.equals(Integer.class)) {
+		Integer []tmpval = new Integer[values.length];
+		for (int i = 0 ; i < values.length; i++)
+		    tmpval[i] =  new Integer (values[i]);
+		method.invoke (bean, new Object[] {tmpval});
+	    } else if (t.equals(Byte.class)) {
+		Byte[] tmpval = new Byte[values.length];
+		for (int i = 0 ; i < values.length; i++)
+		    tmpval[i] = new Byte (values[i]);
+		method.invoke (bean, new Object[] {tmpval});
+	    } else if (t.equals(Boolean.class)) {
+		Boolean[] tmpval = new Boolean[values.length];
+		for (int i = 0 ; i < values.length; i++)
+		    tmpval[i] = new Boolean (values[i]);
+		method.invoke (bean, new Object[] {tmpval});
+	    } else if (t.equals(Short.class)) {
+		Short[] tmpval = new Short[values.length];
+		for (int i = 0 ; i < values.length; i++)
+		    tmpval[i] = new Short (values[i]);
+		method.invoke (bean, new Object[] {tmpval});
+	    } else if (t.equals(Long.class)) {
+		Long[] tmpval = new Long[values.length];
+		for (int i = 0 ; i < values.length; i++)
+		    tmpval[i] = new Long (values[i]);
+		method.invoke (bean, new Object[] {tmpval});
+	    } else if (t.equals(Double.class)) {
+		Double[] tmpval = new Double[values.length];
+		for (int i = 0 ; i < values.length; i++)
+		    tmpval[i] = new Double (values[i]);
+		method.invoke (bean, new Object[] {tmpval});
+	    } else if (t.equals(Float.class)) {
+		Float[] tmpval = new Float[values.length];
+		for (int i = 0 ; i < values.length; i++)
+		    tmpval[i] = new Float (values[i]);
+		method.invoke (bean, new Object[] {tmpval});
+	    } else if (t.equals(Character.class)) {
+		Character[] tmpval = new Character[values.length];
+		for (int i = 0 ; i < values.length; i++)
+		    tmpval[i] = new Character(values[i].charAt(0));
+		method.invoke (bean, new Object[] {tmpval});
+	    } else if (t.equals(int.class)) {
+		int []tmpval = new int[values.length];
+		for (int i = 0 ; i < values.length; i++)
+		    tmpval[i] = Integer.parseInt (values[i]);
+		method.invoke (bean, new Object[] {tmpval});
+	    } else if (t.equals(byte.class)) {
+		byte[] tmpval = new byte[values.length];
+		for (int i = 0 ; i < values.length; i++)
+		    tmpval[i] = Byte.parseByte (values[i]);
+		method.invoke (bean, new Object[] {tmpval});
+	    } else if (t.equals(boolean.class)) {
+		boolean[] tmpval = new boolean[values.length];
+		for (int i = 0 ; i < values.length; i++)
+		    tmpval[i] = (Boolean.valueOf(values[i])).booleanValue();
+		method.invoke (bean, new Object[] {tmpval});
+	    } else if (t.equals(short.class)) {
+		short[] tmpval = new short[values.length];
+		for (int i = 0 ; i < values.length; i++)
+		    tmpval[i] = Short.parseShort (values[i]);
+		method.invoke (bean, new Object[] {tmpval});
+	    } else if (t.equals(long.class)) {
+		long[] tmpval = new long[values.length];
+		for (int i = 0 ; i < values.length; i++)
+		    tmpval[i] = Long.parseLong (values[i]);
+		method.invoke (bean, new Object[] {tmpval});
+	    } else if (t.equals(double.class)) {
+		double[] tmpval = new double[values.length];
+		for (int i = 0 ; i < values.length; i++)
+		    tmpval[i] = Double.valueOf(values[i]).doubleValue();
+		method.invoke (bean, new Object[] {tmpval});
+	    } else if (t.equals(float.class)) {
+		float[] tmpval = new float[values.length];
+		for (int i = 0 ; i < values.length; i++)
+		    tmpval[i] = Float.valueOf(values[i]).floatValue();
+		method.invoke (bean, new Object[] {tmpval});
+	    } else if (t.equals(char.class)) {
+		char[] tmpval = new char[values.length];
+		for (int i = 0 ; i < values.length; i++)
+		    tmpval[i] = values[i].charAt(0);
+		method.invoke (bean, new Object[] {tmpval});
+	    } else {
+		Object[] tmpval = new Integer[values.length];
+		for (int i=0; i<values.length; i++) {
+		    tmpval[i] =  
+			getValueFromPropertyEditorManager(
+                                            t, propertyName, values[i]);
+		}
+		method.invoke (bean, new Object[] {tmpval});
+	    }
+	} catch (Exception ex) {
+            throw new JasperException ("error in invoking method", ex);
+	}
+    }
+
+    /**
+     * Escape special shell characters.
+     * @param unescString The string to shell-escape
+     * @return The escaped shell string.
+     */
+
+    public static String escapeQueryString(String unescString) {
+    if ( unescString == null )
+        return null;
+   
+    String escString    = "";
+    String shellSpChars = "&;`'\"|*?~<>^()[]{}$\\\n";
+   
+    for(int index=0; index<unescString.length(); index++) {
+        char nextChar = unescString.charAt(index);
+
+        if( shellSpChars.indexOf(nextChar) != -1 )
+        escString += "\\";
+
+        escString += nextChar;
+    }
+    return escString;
+    }
+
+    /**
+     * Decode an URL formatted string.
+     * @param encoded The string to decode.
+     * @return The decoded string.
+     */
+
+    public static String decode(String encoded) {
+        // speedily leave if we're not needed
+    if (encoded == null) return null;
+        if (encoded.indexOf('%') == -1 && encoded.indexOf('+') == -1)
+        return encoded;
+
+    //allocate the buffer - use byte[] to avoid calls to new.
+        byte holdbuffer[] = new byte[encoded.length()];
+
+        char holdchar;
+        int bufcount = 0;
+
+        for (int count = 0; count < encoded.length(); count++) {
+        char cur = encoded.charAt(count);
+            if (cur == '%') {
+            holdbuffer[bufcount++] =
+          (byte)Integer.parseInt(encoded.substring(count+1,count+3),16);
+                if (count + 2 >= encoded.length())
+                    count = encoded.length();
+                else
+                    count += 2;
+            } else if (cur == '+') {
+        holdbuffer[bufcount++] = (byte) ' ';
+        } else {
+            holdbuffer[bufcount++] = (byte) cur;
+            }
+        }
+	// REVISIT -- remedy for Deprecated warning.
+    //return new String(holdbuffer,0,0,bufcount);
+    return new String(holdbuffer,0,bufcount);
+    }
+
+    // __begin lookupReadMethodMethod
+    public static Object handleGetProperty(Object o, String prop)
+    throws JasperException {
+        if (o == null) {
+	    throw new JasperException(
+	            Localizer.getMessage("jsp.error.beans.nullbean"));
+        }
+	Object value = null;
+        try {
+            Method method = getReadMethod(o.getClass(), prop);
+	    value = method.invoke(o, null);
+        } catch (Exception ex) {
+	    throw new JasperException (ex);
+        }
+        return value;
+    }
+    // __end lookupReadMethodMethod
+
+    // handles <jsp:setProperty> with EL expression for 'value' attribute
+/** Use proprietaryEvaluate
+    public static void handleSetPropertyExpression(Object bean,
+        String prop, String expression, PageContext pageContext,
+        VariableResolver variableResolver, FunctionMapper functionMapper )
+	throws JasperException
+    {
+	try {
+            Method method = getWriteMethod(bean.getClass(), prop);
+	    method.invoke(bean, new Object[] { 
+		pageContext.getExpressionEvaluator().evaluate(
+		    expression,
+		    method.getParameterTypes()[0],
+                    variableResolver,
+                    functionMapper,
+                    null )
+	    });
+	} catch (Exception ex) {
+	    throw new JasperException(ex);
+	}
+    }
+**/
+    public static void handleSetPropertyExpression(Object bean,
+        String prop, String expression, PageContext pageContext,
+	ProtectedFunctionMapper functionMapper )
+        throws JasperException
+    {
+        try {
+            Method method = getWriteMethod(bean.getClass(), prop);
+            method.invoke(bean, new Object[] {
+                PageContextImpl.proprietaryEvaluate(
+                    expression,
+                    method.getParameterTypes()[0],
+		    pageContext,
+                    functionMapper,
+                    false )
+            });
+        } catch (Exception ex) {
+            throw new JasperException(ex);
+        }
+    }
+
+    public static void handleSetProperty(Object bean, String prop,
+					 Object value)
+	throws JasperException
+    {
+	try {
+            Method method = getWriteMethod(bean.getClass(), prop);
+	    method.invoke(bean, new Object[] { value });
+	} catch (Exception ex) {
+	    throw new JasperException(ex);
+	}
+    }
+    
+    public static void handleSetProperty(Object bean, String prop,
+					 int value)
+	throws JasperException
+    {
+	try {
+            Method method = getWriteMethod(bean.getClass(), prop);
+	    method.invoke(bean, new Object[] { new Integer(value) });
+	} catch (Exception ex) {
+	    throw new JasperException(ex);
+	}	
+    }
+    
+    public static void handleSetProperty(Object bean, String prop,
+					 short value)
+	throws JasperException
+    {
+	try {
+            Method method = getWriteMethod(bean.getClass(), prop);
+	    method.invoke(bean, new Object[] { new Short(value) });
+	} catch (Exception ex) {
+	    throw new JasperException(ex);
+	}	
+    }
+    
+    public static void handleSetProperty(Object bean, String prop,
+					 long value)
+	throws JasperException
+    {
+	try {
+            Method method = getWriteMethod(bean.getClass(), prop);
+	    method.invoke(bean, new Object[] { new Long(value) });
+	} catch (Exception ex) {
+	    throw new JasperException(ex);
+	}	
+    } 
+    
+    public static void handleSetProperty(Object bean, String prop,
+					 double value)
+	throws JasperException
+    {
+	try {
+            Method method = getWriteMethod(bean.getClass(), prop);
+	    method.invoke(bean, new Object[] { new Double(value) });
+	} catch (Exception ex) {
+	    throw new JasperException(ex);
+	}	
+    }
+    
+    public static void handleSetProperty(Object bean, String prop,
+					 float value)
+	throws JasperException
+    {
+	try {
+            Method method = getWriteMethod(bean.getClass(), prop);
+	    method.invoke(bean, new Object[] { new Float(value) });
+	} catch (Exception ex) {
+	    throw new JasperException(ex);
+	}	
+    }
+    
+    public static void handleSetProperty(Object bean, String prop,
+					 char value)
+	throws JasperException
+    {
+	try {
+            Method method = getWriteMethod(bean.getClass(), prop);
+	    method.invoke(bean, new Object[] { new Character(value) });
+	} catch (Exception ex) {
+	    throw new JasperException(ex);
+	}	
+    }
+
+    public static void handleSetProperty(Object bean, String prop,
+					 byte value)
+	throws JasperException
+    {
+	try {
+            Method method = getWriteMethod(bean.getClass(), prop);
+	    method.invoke(bean, new Object[] { new Byte(value) });
+	} catch (Exception ex) {
+	    throw new JasperException(ex);
+	}	
+    }
+    
+    public static void handleSetProperty(Object bean, String prop,
+					 boolean value)
+	throws JasperException
+    {
+	try {
+            Method method = getWriteMethod(bean.getClass(), prop);
+	    method.invoke(bean, new Object[] { new Boolean(value) });
+	} catch (Exception ex) {
+	    throw new JasperException(ex);
+	}	
+    }
+    
+    public static Method getWriteMethod(Class beanClass, String prop)
+    throws JasperException {
+	Method method = null;	
+        Class type = null;
+	try {
+	    java.beans.BeanInfo info
+                = java.beans.Introspector.getBeanInfo(beanClass);
+	    if ( info != null ) {
+		java.beans.PropertyDescriptor pd[]
+		    = info.getPropertyDescriptors();
+		for (int i = 0 ; i < pd.length ; i++) {
+		    if ( pd[i].getName().equals(prop) ) {
+			method = pd[i].getWriteMethod();
+			type   = pd[i].getPropertyType();
+			break;
+		    }
+		}
+            } else {        
+                // just in case introspection silently fails.
+                throw new JasperException(
+                    Localizer.getMessage("jsp.error.beans.nobeaninfo",
+					 beanClass.getName()));
+            }
+        } catch (Exception ex) {
+            throw new JasperException (ex);
+        }
+        if (method == null) {
+            if (type == null) {
+		throw new JasperException(
+                        Localizer.getMessage("jsp.error.beans.noproperty",
+					     prop,
+					     beanClass.getName()));
+            } else {
+		throw new JasperException(
+		    Localizer.getMessage("jsp.error.beans.nomethod.setproperty",
+					 prop,
+					 type.getName(),
+					 beanClass.getName()));
+            }
+        }
+        return method;
+    }
+
+    public static Method getReadMethod(Class beanClass, String prop)
+	    throws JasperException {
+
+        Method method = null;        
+        Class type = null;
+        try {
+            java.beans.BeanInfo info
+                = java.beans.Introspector.getBeanInfo(beanClass);
+            if ( info != null ) {
+                java.beans.PropertyDescriptor pd[]
+                    = info.getPropertyDescriptors();
+                for (int i = 0 ; i < pd.length ; i++) {
+                    if ( pd[i].getName().equals(prop) ) {
+                        method = pd[i].getReadMethod();
+                        type   = pd[i].getPropertyType();
+                        break;
+                    }
+                }
+            } else {        
+                // just in case introspection silently fails.
+		throw new JasperException(
+                    Localizer.getMessage("jsp.error.beans.nobeaninfo",
+					 beanClass.getName()));
+	    }
+	} catch (Exception ex) {
+	    throw new JasperException (ex);
+	}
+        if (method == null) {
+            if (type == null) {
+		throw new JasperException(
+                    Localizer.getMessage("jsp.error.beans.noproperty", prop,
+					 beanClass.getName()));
+            } else {
+		throw new JasperException(
+                    Localizer.getMessage("jsp.error.beans.nomethod", prop,
+					 beanClass.getName()));
+            }
+        }
+
+	return method;
+    }
+
+    //*********************************************************************
+    // PropertyEditor Support
+
+    public static Object getValueFromBeanInfoPropertyEditor(
+		           Class attrClass, String attrName, String attrValue,
+			   Class propertyEditorClass) 
+	throws JasperException 
+    {
+	try {
+	    PropertyEditor pe = (PropertyEditor)propertyEditorClass.newInstance();
+	    pe.setAsText(attrValue);
+	    return pe.getValue();
+	} catch (Exception ex) {
+	    throw new JasperException(
+                Localizer.getMessage("jsp.error.beans.property.conversion",
+				     attrValue, attrClass.getName(), attrName,
+				     ex.getMessage()));
+	}
+    }
+
+    public static Object getValueFromPropertyEditorManager(
+	             Class attrClass, String attrName, String attrValue) 
+	throws JasperException 
+    {
+	try {
+	    PropertyEditor propEditor = 
+		PropertyEditorManager.findEditor(attrClass);
+	    if (propEditor != null) {
+		propEditor.setAsText(attrValue);
+		return propEditor.getValue();
+	    } else {
+		throw new IllegalArgumentException(
+                    Localizer.getMessage("jsp.error.beans.propertyeditor.notregistered"));
+	    }
+	} catch (IllegalArgumentException ex) {
+	    throw new JasperException(
+                Localizer.getMessage("jsp.error.beans.property.conversion",
+				     attrValue, attrClass.getName(), attrName,
+				     ex.getMessage()));
+	}
+    }
+
+
+    // ************************************************************************
+    // General Purpose Runtime Methods
+    // ************************************************************************
+
+
+    /**
+     * Convert a possibly relative resource path into a context-relative
+     * resource path that starts with a '/'.
+     *
+     * @param request The servlet request we are processing
+     * @param relativePath The possibly relative resource path
+     */
+    public static String getContextRelativePath(ServletRequest request,
+                                                String relativePath) {
+
+        if (relativePath.startsWith("/"))
+            return (relativePath);
+        if (!(request instanceof HttpServletRequest))
+            return (relativePath);
+        HttpServletRequest hrequest = (HttpServletRequest) request;
+        String uri = (String)
+            request.getAttribute("javax.servlet.include.servlet_path");
+        if (uri != null) {
+            String pathInfo = (String)
+                request.getAttribute("javax.servlet.include.path_info");
+            if (pathInfo == null) {
+                if (uri.lastIndexOf('/') >= 0) 
+                    uri = uri.substring(0, uri.lastIndexOf('/'));
+            }
+        }
+        else {
+            uri = hrequest.getServletPath();
+            if (uri.lastIndexOf('/') >= 0) 
+                uri = uri.substring(0, uri.lastIndexOf('/'));
+        }
+        return uri + '/' + relativePath;
+
+    }
+
+
+    /**
+     * Perform a RequestDispatcher.include() operation, with optional flushing
+     * of the response beforehand.
+     *
+     * @param request The servlet request we are processing
+     * @param response The servlet response we are processing
+     * @param relativePath The relative path of the resource to be included
+     * @param out The Writer to whom we are currently writing
+     * @param flush Should we flush before the include is processed?
+     *
+     * @exception IOException if thrown by the included servlet
+     * @exception ServletException if thrown by the included servlet
+     */
+    public static void include(ServletRequest request,
+                               ServletResponse response,
+                               String relativePath,
+                               JspWriter out,
+                               boolean flush)
+        throws IOException, ServletException {
+
+        if (flush && !(out instanceof BodyContent))
+            out.flush();
+
+        // FIXME - It is tempting to use request.getRequestDispatcher() to
+        // resolve a relative path directly, but Catalina currently does not
+        // take into account whether the caller is inside a RequestDispatcher
+        // include or not.  Whether Catalina *should* take that into account
+        // is a spec issue currently under review.  In the mean time,
+        // replicate Jasper's previous behavior
+
+        String resourcePath = getContextRelativePath(request, relativePath);
+        RequestDispatcher rd = request.getRequestDispatcher(resourcePath);
+
+        rd.include(request,
+                   new ServletResponseWrapperInclude(response, out));
+
+    }
+
+    /**
+     * URL encodes a string, based on the supplied character encoding.
+     * This performs the same function as java.next.URLEncode.encode
+     * in J2SDK1.4, and should be removed if the only platform supported
+     * is 1.4 or higher.
+     * @param s The String to be URL encoded.
+     * @param enc The character encoding 
+     * @return The URL encoded String
+     */
+    public static String URLEncode(String s, String enc) {
+
+	if (s == null) {
+	    return "null";
+	}
+
+	if (enc == null) {
+	    enc = "ISO-8859-1";	// The default request encoding 
+	}
+
+	StringBuffer out = new StringBuffer(s.length());
+	ByteArrayOutputStream buf = new ByteArrayOutputStream();
+	OutputStreamWriter writer = null;
+	try {
+	    writer = new OutputStreamWriter(buf, enc);
+	} catch (java.io.UnsupportedEncodingException ex) {
+	    // Use the default encoding?
+	    writer = new OutputStreamWriter(buf);
+	}
+	
+	for (int i = 0; i < s.length(); i++) {
+	    int c = s.charAt(i);
+	    if (c == ' ') {
+		out.append('+');
+	    } else if (isSafeChar(c)) {
+		out.append((char)c);
+	    } else {
+		// convert to external encoding before hex conversion
+		try {
+		    writer.write(c);
+		    writer.flush();
+		} catch(IOException e) {
+		    buf.reset();
+		    continue;
+		}
+		byte[] ba = buf.toByteArray();
+		for (int j = 0; j < ba.length; j++) {
+		    out.append('%');
+		    // Converting each byte in the buffer
+		    out.append(Character.forDigit((ba[j]>>4) & 0xf, 16));
+		    out.append(Character.forDigit(ba[j] & 0xf, 16));
+		}
+		buf.reset();
+	    }
+	}
+	return out.toString();
+    }
+
+    private static boolean isSafeChar(int c) {
+	if (c >= 'a' && c <= 'z') {
+	    return true;
+	}
+	if (c >= 'A' && c <= 'Z') {
+	    return true;
+	}
+	if (c >= '0' && c <= '9') {
+	    return true;
+	}
+	if (c == '-' || c == '_' || c == '.' || c == '!' ||
+	    c == '~' || c == '*' || c == '\'' || c == '(' || c == ')') {
+	    return true;
+	}
+	return false;
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/runtime/JspSourceDependent.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/runtime/JspSourceDependent.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/runtime/JspSourceDependent.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,38 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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;
+
+/**
+ * Interface for tracking the source files dependencies, for the purpose
+ * of compiling out of date pages.  This is used for
+ * 1) files that are included by page directives
+ * 2) files that are included by include-prelude and include-coda in jsp:config
+ * 3) files that are tag files and referenced
+ * 4) TLDs referenced
+ */
+
+public interface JspSourceDependent {
+
+   /**
+    * Returns a list of files names that the current page has a source
+    * dependency on.
+    */
+    // FIXME: Type used is Object due to very weird behavior 
+    // with Eclipse JDT 3.1 in Java 5 mode
+    public Object getDependants();
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/runtime/JspWriterImpl.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/runtime/JspWriterImpl.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/runtime/JspWriterImpl.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,589 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.IOException;
+import java.io.Writer;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+
+import javax.servlet.ServletResponse;
+import javax.servlet.jsp.JspWriter;
+
+import org.apache.jasper.Constants;
+import org.apache.jasper.compiler.Localizer;
+import org.apache.jasper.security.SecurityUtil;
+
+/**
+ * Write text to a character-output stream, buffering characters so as
+ * to provide for the efficient writing of single characters, arrays,
+ * and strings. 
+ *
+ * Provide support for discarding for the output that has been 
+ * buffered. 
+ * 
+ * This needs revisiting when the buffering problems in the JSP spec
+ * are fixed -akv 
+ *
+ * @author Anil K. Vijendran
+ */
+public class JspWriterImpl extends JspWriter {
+    
+    private Writer out;
+    private ServletResponse response;    
+    private char cb[];
+    private int nextChar;
+    private boolean flushed = false;
+    private boolean closed = false;
+    
+    public JspWriterImpl() {
+        super( Constants.DEFAULT_BUFFER_SIZE, true );
+    }
+    
+    /**
+     * Create a buffered character-output stream that uses a default-sized
+     * output buffer.
+     *
+     * @param  response  A Servlet Response
+     */
+    public JspWriterImpl(ServletResponse response) {
+        this(response, Constants.DEFAULT_BUFFER_SIZE, true);
+    }
+    
+    /**
+     * Create a new buffered character-output stream that uses an output
+     * buffer of the given size.
+     *
+     * @param  response A Servlet Response
+     * @param  sz   	Output-buffer size, a positive integer
+     *
+     * @exception  IllegalArgumentException  If sz is <= 0
+     */
+    public JspWriterImpl(ServletResponse response, int sz, 
+            boolean autoFlush) {
+        super(sz, autoFlush);
+        if (sz < 0)
+            throw new IllegalArgumentException("Buffer size <= 0");
+        this.response = response;
+        cb = sz == 0 ? null : new char[sz];
+        nextChar = 0;
+    }
+    
+    void init( ServletResponse response, int sz, boolean autoFlush ) {
+        this.response= response;
+        if( sz > 0 && ( cb == null || sz > cb.length ) )
+            cb=new char[sz];
+        nextChar = 0;
+        this.autoFlush=autoFlush;
+        this.bufferSize=sz;
+    }
+    
+    /** Package-level access
+     */
+    void recycle() {
+        flushed = false;
+        closed = false;
+        out = null;
+        nextChar = 0;
+        response = null;
+    }
+    
+    /**
+     * Flush the output buffer to the underlying character stream, without
+     * flushing the stream itself.  This method is non-private only so that it
+     * may be invoked by PrintStream.
+     */
+    protected final void flushBuffer() throws IOException {
+        if (bufferSize == 0)
+            return;
+        flushed = true;
+        ensureOpen();
+        if (nextChar == 0)
+            return;
+        initOut();
+        out.write(cb, 0, nextChar);
+        nextChar = 0;
+    }
+    
+    private void initOut() throws IOException {
+        if (out == null) {
+            out = response.getWriter();
+        }
+    }
+    
+    private String getLocalizeMessage(final String message){
+        if (SecurityUtil.isPackageProtectionEnabled()){
+            return (String)AccessController.doPrivileged(new PrivilegedAction(){
+                public Object run(){
+                    return Localizer.getMessage(message); 
+                }
+            });
+        } else {
+            return Localizer.getMessage(message);
+        }
+    }
+    
+    /**
+     * Discard the output buffer.
+     */
+    public final void clear() throws IOException {
+        if ((bufferSize == 0) && (out != null))
+            // clear() is illegal after any unbuffered output (JSP.5.5)
+            throw new IllegalStateException(
+                    getLocalizeMessage("jsp.error.ise_on_clear"));
+        if (flushed)
+            throw new IOException(
+                    getLocalizeMessage("jsp.error.attempt_to_clear_flushed_buffer"));
+        ensureOpen();
+        nextChar = 0;
+    }
+    
+    public void clearBuffer() throws IOException {
+        if (bufferSize == 0)
+            throw new IllegalStateException(
+                    getLocalizeMessage("jsp.error.ise_on_clear"));
+        ensureOpen();
+        nextChar = 0;
+    }
+    
+    private final void bufferOverflow() throws IOException {
+        throw new IOException(getLocalizeMessage("jsp.error.overflow"));
+    }
+    
+    /**
+     * Flush the stream.
+     *
+     */
+    public void flush()  throws IOException {
+        flushBuffer();
+        if (out != null) {
+            out.flush();
+        }
+    }
+    
+    /**
+     * Close the stream.
+     *
+     */
+    public void close() throws IOException {
+        if (response == null || closed)
+            // multiple calls to close is OK
+            return;
+        flush();
+        if (out != null)
+            out.close();
+        out = null;
+        closed = true;
+    }
+    
+    /**
+     * @return the number of bytes unused in the buffer
+     */
+    public int getRemaining() {
+        return bufferSize - nextChar;
+    }
+    
+    /** check to make sure that the stream has not been closed */
+    private void ensureOpen() throws IOException {
+        if (response == null || closed)
+            throw new IOException("Stream closed");
+    }
+    
+    
+    /**
+     * Write a single character.
+     */
+    public void write(int c) throws IOException {
+        ensureOpen();
+        if (bufferSize == 0) {
+            initOut();
+            out.write(c);
+        }
+        else {
+            if (nextChar >= bufferSize)
+                if (autoFlush)
+                    flushBuffer();
+                else
+                    bufferOverflow();
+            cb[nextChar++] = (char) c;
+        }
+    }
+    
+    /**
+     * Our own little min method, to avoid loading java.lang.Math if we've run
+     * out of file descriptors and we're trying to print a stack trace.
+     */
+    private int min(int a, int b) {
+        if (a < b) return a;
+        return b;
+    }
+    
+    /**
+     * Write a portion of an array of characters.
+     *
+     * <p> Ordinarily this method stores characters from the given array into
+     * this stream's buffer, flushing the buffer to the underlying stream as
+     * needed.  If the requested length is at least as large as the buffer,
+     * however, then this method will flush the buffer and write the characters
+     * directly to the underlying stream.  Thus redundant
+     * <code>DiscardableBufferedWriter</code>s will not copy data unnecessarily.
+     *
+     * @param  cbuf  A character array
+     * @param  off   Offset from which to start reading characters
+     * @param  len   Number of characters to write
+     */
+    public void write(char cbuf[], int off, int len) 
+    throws IOException 
+    {
+        ensureOpen();
+        
+        if (bufferSize == 0) {
+            initOut();
+            out.write(cbuf, off, len);
+            return;
+        }
+        
+        if ((off < 0) || (off > cbuf.length) || (len < 0) ||
+                ((off + len) > cbuf.length) || ((off + len) < 0)) {
+            throw new IndexOutOfBoundsException();
+        } else if (len == 0) {
+            return;
+        } 
+        
+        if (len >= bufferSize) {
+            /* If the request length exceeds the size of the output buffer,
+             flush the buffer and then write the data directly.  In this
+             way buffered streams will cascade harmlessly. */
+            if (autoFlush)
+                flushBuffer();
+            else
+                bufferOverflow();
+            initOut();
+            out.write(cbuf, off, len);
+            return;
+        }
+        
+        int b = off, t = off + len;
+        while (b < t) {
+            int d = min(bufferSize - nextChar, t - b);
+            System.arraycopy(cbuf, b, cb, nextChar, d);
+            b += d;
+            nextChar += d;
+            if (nextChar >= bufferSize) 
+                if (autoFlush)
+                    flushBuffer();
+                else
+                    bufferOverflow();
+        }
+        
+    }
+    
+    /**
+     * Write an array of characters.  This method cannot be inherited from the
+     * Writer class because it must suppress I/O exceptions.
+     */
+    public void write(char buf[]) throws IOException {
+        write(buf, 0, buf.length);
+    }
+    
+    /**
+     * Write a portion of a String.
+     *
+     * @param  s     String to be written
+     * @param  off   Offset from which to start reading characters
+     * @param  len   Number of characters to be written
+     */
+    public void write(String s, int off, int len) throws IOException {
+        ensureOpen();
+        if (bufferSize == 0) {
+            initOut();
+            out.write(s, off, len);
+            return;
+        }
+        int b = off, t = off + len;
+        while (b < t) {
+            int d = min(bufferSize - nextChar, t - b);
+            s.getChars(b, b + d, cb, nextChar);
+            b += d;
+            nextChar += d;
+            if (nextChar >= bufferSize) 
+                if (autoFlush)
+                    flushBuffer();
+                else
+                    bufferOverflow();
+        }
+    }
+    
+    /**
+     * Write a string.  This method cannot be inherited from the Writer class
+     * because it must suppress I/O exceptions.
+     */
+    public void write(String s) throws IOException {
+        // Simple fix for Bugzilla 35410
+        // Calling the other write function so as to init the buffer anyways
+        if(s == null) {
+            write(s, 0, 0);
+        } else {
+            write(s, 0, s.length());
+        }
+    }
+    
+    
+    static String lineSeparator = System.getProperty("line.separator");
+    
+    /**
+     * Write a line separator.  The line separator string is defined by the
+     * system property <tt>line.separator</tt>, and is not necessarily a single
+     * newline ('\n') character.
+     *
+     * @exception  IOException  If an I/O error occurs
+     */
+    
+    public void newLine() throws IOException {
+        write(lineSeparator);
+    }
+    
+    
+    /* Methods that do not terminate lines */
+    
+    /**
+     * Print a boolean value.  The string produced by <code>{@link
+     * java.lang.String#valueOf(boolean)}</code> is translated into bytes
+     * according to the platform's default character encoding, and these bytes
+     * are written in exactly the manner of the <code>{@link
+     * #write(int)}</code> method.
+     *
+     * @param      b   The <code>boolean</code> to be printed
+     */
+    public void print(boolean b) throws IOException {
+        write(b ? "true" : "false");
+    }
+    
+    /**
+     * Print a character.  The character is translated into one or more bytes
+     * according to the platform's default character encoding, and these bytes
+     * are written in exactly the manner of the <code>{@link
+     * #write(int)}</code> method.
+     *
+     * @param      c   The <code>char</code> to be printed
+     */
+    public void print(char c) throws IOException {
+        write(String.valueOf(c));
+    }
+    
+    /**
+     * Print an integer.  The string produced by <code>{@link
+     * java.lang.String#valueOf(int)}</code> is translated into bytes according
+     * to the platform's default character encoding, and these bytes are
+     * written in exactly the manner of the <code>{@link #write(int)}</code>
+     * method.
+     *
+     * @param      i   The <code>int</code> to be printed
+     */
+    public void print(int i) throws IOException {
+        write(String.valueOf(i));
+    }
+    
+    /**
+     * Print a long integer.  The string produced by <code>{@link
+     * java.lang.String#valueOf(long)}</code> is translated into bytes
+     * according to the platform's default character encoding, and these bytes
+     * are written in exactly the manner of the <code>{@link #write(int)}</code>
+     * method.
+     *
+     * @param      l   The <code>long</code> to be printed
+     */
+    public void print(long l) throws IOException {
+        write(String.valueOf(l));
+    }
+    
+    /**
+     * Print a floating-point number.  The string produced by <code>{@link
+     * java.lang.String#valueOf(float)}</code> is translated into bytes
+     * according to the platform's default character encoding, and these bytes
+     * are written in exactly the manner of the <code>{@link #write(int)}</code>
+     * method.
+     *
+     * @param      f   The <code>float</code> to be printed
+     */
+    public void print(float f) throws IOException {
+        write(String.valueOf(f));
+    }
+    
+    /**
+     * Print a double-precision floating-point number.  The string produced by
+     * <code>{@link java.lang.String#valueOf(double)}</code> is translated into
+     * bytes according to the platform's default character encoding, and these
+     * bytes are written in exactly the manner of the <code>{@link
+     * #write(int)}</code> method.
+     *
+     * @param      d   The <code>double</code> to be printed
+     */
+    public void print(double d) throws IOException {
+        write(String.valueOf(d));
+    }
+    
+    /**
+     * Print an array of characters.  The characters are converted into bytes
+     * according to the platform's default character encoding, and these bytes
+     * are written in exactly the manner of the <code>{@link #write(int)}</code>
+     * method.
+     *
+     * @param      s   The array of chars to be printed
+     *
+     * @throws  NullPointerException  If <code>s</code> is <code>null</code>
+     */
+    public void print(char s[]) throws IOException {
+        write(s);
+    }
+    
+    /**
+     * Print a string.  If the argument is <code>null</code> then the string
+     * <code>"null"</code> is printed.  Otherwise, the string's characters are
+     * converted into bytes according to the platform's default character
+     * encoding, and these bytes are written in exactly the manner of the
+     * <code>{@link #write(int)}</code> method.
+     *
+     * @param      s   The <code>String</code> to be printed
+     */
+    public void print(String s) throws IOException {
+        if (s == null) {
+            s = "null";
+        }
+        write(s);
+    }
+    
+    /**
+     * Print an object.  The string produced by the <code>{@link
+     * java.lang.String#valueOf(Object)}</code> method is translated into bytes
+     * according to the platform's default character encoding, and these bytes
+     * are written in exactly the manner of the <code>{@link #write(int)}</code>
+     * method.
+     *
+     * @param      obj   The <code>Object</code> to be printed
+     */
+    public void print(Object obj) throws IOException {
+        write(String.valueOf(obj));
+    }
+    
+    /* Methods that do terminate lines */
+    
+    /**
+     * Terminate the current line by writing the line separator string.  The
+     * line separator string is defined by the system property
+     * <code>line.separator</code>, and is not necessarily a single newline
+     * character (<code>'\n'</code>).
+     *
+     * Need to change this from PrintWriter because the default
+     * println() writes  to the sink directly instead of through the
+     * write method...  
+     */
+    public void println() throws IOException {
+        newLine();
+    }
+    
+    /**
+     * Print a boolean value and then terminate the line.  This method behaves
+     * as though it invokes <code>{@link #print(boolean)}</code> and then
+     * <code>{@link #println()}</code>.
+     */
+    public void println(boolean x) throws IOException {
+        print(x);
+        println();
+    }
+    
+    /**
+     * Print a character and then terminate the line.  This method behaves as
+     * though it invokes <code>{@link #print(char)}</code> and then <code>{@link
+     * #println()}</code>.
+     */
+    public void println(char x) throws IOException {
+        print(x);
+        println();
+    }
+    
+    /**
+     * Print an integer and then terminate the line.  This method behaves as
+     * though it invokes <code>{@link #print(int)}</code> and then <code>{@link
+     * #println()}</code>.
+     */
+    public void println(int x) throws IOException {
+        print(x);
+        println();
+    }
+    
+    /**
+     * Print a long integer and then terminate the line.  This method behaves
+     * as though it invokes <code>{@link #print(long)}</code> and then
+     * <code>{@link #println()}</code>.
+     */
+    public void println(long x) throws IOException {
+        print(x);
+        println();
+    }
+    
+    /**
+     * Print a floating-point number and then terminate the line.  This method
+     * behaves as though it invokes <code>{@link #print(float)}</code> and then
+     * <code>{@link #println()}</code>.
+     */
+    public void println(float x) throws IOException {
+        print(x);
+        println();
+    }
+    
+    /**
+     * Print a double-precision floating-point number and then terminate the
+     * line.  This method behaves as though it invokes <code>{@link
+     * #print(double)}</code> and then <code>{@link #println()}</code>.
+     */
+    public void println(double x) throws IOException {
+        print(x);
+        println();
+    }
+    
+    /**
+     * Print an array of characters and then terminate the line.  This method
+     * behaves as though it invokes <code>{@link #print(char[])}</code> and then
+     * <code>{@link #println()}</code>.
+     */
+    public void println(char x[]) throws IOException {
+        print(x);
+        println();
+    }
+    
+    /**
+     * Print a String and then terminate the line.  This method behaves as
+     * though it invokes <code>{@link #print(String)}</code> and then
+     * <code>{@link #println()}</code>.
+     */
+    public void println(String x) throws IOException {
+        print(x);
+        println();
+    }
+    
+    /**
+     * Print an Object and then terminate the line.  This method behaves as
+     * though it invokes <code>{@link #print(Object)}</code> and then
+     * <code>{@link #println()}</code>.
+     */
+    public void println(Object x) throws IOException {
+        print(x);
+        println();
+    }
+    
+}

Added: branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/runtime/PageContextImpl.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/runtime/PageContextImpl.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/runtime/PageContextImpl.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,929 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.IOException;
+import java.io.Writer;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
+import java.util.Enumeration;
+import java.util.Hashtable;
+
+import javax.servlet.Servlet;
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+import javax.servlet.jsp.JspException;
+import javax.servlet.jsp.JspFactory;
+import javax.servlet.jsp.JspWriter;
+import javax.servlet.jsp.PageContext;
+import javax.servlet.jsp.el.ELException;
+import javax.servlet.jsp.el.ExpressionEvaluator;
+import javax.servlet.jsp.el.VariableResolver;
+import javax.servlet.jsp.tagext.BodyContent;
+
+import org.apache.commons.el.ExpressionEvaluatorImpl;
+import org.apache.commons.el.VariableResolverImpl;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.jasper.Constants;
+import org.apache.jasper.compiler.Localizer;
+import org.apache.jasper.security.SecurityUtil;
+
+/**
+ * Implementation of the PageContext class from the JSP spec.
+ * Also doubles as a VariableResolver for the EL.
+ *
+ * @author Anil K. Vijendran
+ * @author Larry Cable
+ * @author Hans Bergsten
+ * @author Pierre Delisle
+ * @author Mark Roth
+ * @author Jan Luehe
+ */
+public class PageContextImpl extends PageContext implements VariableResolver {
+
+    // Logger
+    private static Log log = LogFactory.getLog(PageContextImpl.class);
+
+    // The expression evaluator, for evaluating EL expressions.
+    private static ExpressionEvaluatorImpl elExprEval
+        = new ExpressionEvaluatorImpl(false);
+
+    // The variable resolver, for evaluating EL expressions.
+    private VariableResolverImpl variableResolver;
+
+    private BodyContentImpl[] outs;
+    private int depth;
+
+    // per-servlet state
+    private Servlet servlet;
+    private ServletConfig config;
+    private ServletContext context;
+    private String errorPageURL;
+
+    // page-scope attributes
+    private transient Hashtable        attributes;
+
+    // per-request state
+    private transient ServletRequest request;
+    private transient ServletResponse response;
+    private transient HttpSession session;
+    private boolean isIncluded;
+
+    // initial output stream
+    private transient JspWriter out;
+    private transient JspWriterImpl baseOut;
+
+    /*
+     * Constructor.
+     */
+    PageContextImpl(JspFactory factory) {
+        this.variableResolver = new VariableResolverImpl(this);
+        this.outs = new BodyContentImpl[0];
+        this.attributes = new Hashtable(16);
+        this.depth = -1;
+    }
+
+    public void initialize(Servlet servlet,
+                           ServletRequest request,
+                           ServletResponse response,
+                           String errorPageURL,
+                           boolean needsSession,
+                           int bufferSize,
+                           boolean autoFlush) throws IOException {
+
+        _initialize(servlet, request, response, errorPageURL, needsSession,
+                    bufferSize, autoFlush);
+    }
+
+    private void _initialize(Servlet servlet,
+                             ServletRequest request,
+                             ServletResponse response,
+                             String errorPageURL,
+                             boolean needsSession,
+                             int bufferSize,
+                             boolean autoFlush) throws IOException {
+
+        // initialize state
+        this.servlet = servlet;
+        this.config = servlet.getServletConfig();
+        this.context = config.getServletContext();
+        this.errorPageURL = errorPageURL;
+        this.request = request;
+         this.response = response;
+
+        // Setup session (if required)
+        if (request instanceof HttpServletRequest && needsSession)
+            this.session = ((HttpServletRequest)request).getSession();
+        if (needsSession && session == null)
+            throw new IllegalStateException
+                ("Page needs a session and none is available");
+
+        // initialize the initial out ...
+        depth = -1;
+        if (this.baseOut == null) {
+            this.baseOut = new JspWriterImpl(response, bufferSize, autoFlush);
+        } else {
+            this.baseOut.init(response, bufferSize, autoFlush);
+        }
+        this.out = baseOut;
+
+        // register names/values as per spec
+        setAttribute(OUT, this.out);
+        setAttribute(REQUEST, request);
+        setAttribute(RESPONSE, response);
+
+        if (session != null)
+            setAttribute(SESSION, session);
+
+        setAttribute(PAGE, servlet);
+        setAttribute(CONFIG, config);
+        setAttribute(PAGECONTEXT, this);
+        setAttribute(APPLICATION, context);
+
+        isIncluded = request.getAttribute(
+            "javax.servlet.include.servlet_path") != null;
+    }
+
+    public void release() {
+        out = baseOut;
+        try {
+            if (isIncluded) {
+                ((JspWriterImpl)out).flushBuffer();
+                // push it into the including jspWriter
+            } else {
+                // Old code:
+                //out.flush();
+                // Do not flush the buffer even if we're not included (i.e.
+                // we are the main page. The servlet will flush it and close
+                // the stream.
+                ((JspWriterImpl)out).flushBuffer();
+            }
+        } catch (IOException ex) {
+            log.warn("Internal error flushing the buffer in release()");
+        }
+
+        servlet = null;
+        config = null;
+        context = null;
+        errorPageURL = null;
+        request = null;
+        response = null;
+        depth = -1;
+        baseOut.recycle();
+        session = null;
+
+        attributes.clear();
+    }
+
+    public Object getAttribute(final String name) {
+
+        if (name == null) {
+            throw new NullPointerException(
+                    Localizer.getMessage("jsp.error.attribute.null_name"));
+        }
+
+        if (SecurityUtil.isPackageProtectionEnabled()){
+            return AccessController.doPrivileged(new PrivilegedAction(){
+                public Object run(){
+                    return doGetAttribute(name);
+                }
+            });
+        } else {
+            return doGetAttribute(name);
+        }
+
+    }
+
+    private Object doGetAttribute(String name){
+        return attributes.get(name);
+    }
+
+    public Object getAttribute(final String name, final int scope) {
+
+        if (name == null) {
+            throw new NullPointerException(
+                    Localizer.getMessage("jsp.error.attribute.null_name"));
+        }
+
+        if (SecurityUtil.isPackageProtectionEnabled()){
+            return AccessController.doPrivileged(new PrivilegedAction(){
+                public Object run(){
+                    return doGetAttribute(name, scope);
+                }
+            });
+        } else {
+            return doGetAttribute(name, scope);
+        }
+
+    }
+
+    private Object doGetAttribute(String name, int scope){
+        switch (scope) {
+            case PAGE_SCOPE:
+            return attributes.get(name);
+
+            case REQUEST_SCOPE:
+            return request.getAttribute(name);
+
+            case SESSION_SCOPE:
+            if (session == null) {
+                throw new IllegalStateException(
+                        Localizer.getMessage("jsp.error.page.noSession"));
+            }
+            return session.getAttribute(name);
+
+            case APPLICATION_SCOPE:
+            return context.getAttribute(name);
+
+            default:
+            throw new IllegalArgumentException("Invalid scope");
+        }
+    }
+
+    public void setAttribute(final String name, final Object attribute) {
+
+        if (name == null) {
+            throw new NullPointerException(
+                    Localizer.getMessage("jsp.error.attribute.null_name"));
+        }
+
+        if (SecurityUtil.isPackageProtectionEnabled()){
+            AccessController.doPrivileged(new PrivilegedAction(){
+                public Object run(){
+                    doSetAttribute(name, attribute);
+                    return null;
+                }
+            });
+        } else {
+            doSetAttribute(name, attribute);
+        }
+    }
+
+    private void doSetAttribute(String name, Object attribute){
+        if (attribute != null) {
+            attributes.put(name, attribute);
+        } else {
+            removeAttribute(name, PAGE_SCOPE);
+        }
+    }
+
+    public void setAttribute(final String name, final Object o, final int scope) {
+
+        if (name == null) {
+            throw new NullPointerException(
+                    Localizer.getMessage("jsp.error.attribute.null_name"));
+        }
+
+        if (SecurityUtil.isPackageProtectionEnabled()){
+            AccessController.doPrivileged(new PrivilegedAction(){
+                public Object run(){
+                    doSetAttribute(name, o, scope);
+                    return null;
+                }
+            });
+        } else {
+            doSetAttribute(name, o, scope);
+        }
+
+    }
+
+    private void doSetAttribute(String name, Object o, int scope ){
+        if (o != null) {
+            switch (scope) {
+            case PAGE_SCOPE:
+            attributes.put(name, o);
+            break;
+
+            case REQUEST_SCOPE:
+            request.setAttribute(name, o);
+            break;
+
+            case SESSION_SCOPE:
+            if (session == null) {
+                throw new IllegalStateException(
+                        Localizer.getMessage("jsp.error.page.noSession"));
+            }
+            session.setAttribute(name, o);
+            break;
+
+            case APPLICATION_SCOPE:
+            context.setAttribute(name, o);
+            break;
+
+            default:
+            throw new IllegalArgumentException("Invalid scope");
+            }
+        } else {
+            removeAttribute(name, scope);
+        }
+    }
+
+    public void removeAttribute(final String name, final int scope) {
+
+        if (name == null) {
+            throw new NullPointerException(
+                    Localizer.getMessage("jsp.error.attribute.null_name"));
+        }
+        if (SecurityUtil.isPackageProtectionEnabled()){
+            AccessController.doPrivileged(new PrivilegedAction(){
+                public Object run(){
+                    doRemoveAttribute(name, scope);
+                    return null;
+                }
+            });
+        } else {
+            doRemoveAttribute(name, scope);
+        }
+    }
+
+    private void doRemoveAttribute(String name, int scope){
+        switch (scope) {
+        case PAGE_SCOPE:
+            attributes.remove(name);
+            break;
+
+        case REQUEST_SCOPE:
+            request.removeAttribute(name);
+            break;
+
+        case SESSION_SCOPE:
+            if (session == null) {
+            throw new IllegalStateException(
+                        Localizer.getMessage("jsp.error.page.noSession"));
+            }
+            session.removeAttribute(name);
+            break;
+
+        case APPLICATION_SCOPE:
+            context.removeAttribute(name);
+            break;
+            
+        default:
+            throw new IllegalArgumentException("Invalid scope");
+        }
+    }
+
+    public int getAttributesScope(final String name) {
+
+        if (name == null) {
+            throw new NullPointerException(
+                    Localizer.getMessage("jsp.error.attribute.null_name"));
+        }
+
+        if (SecurityUtil.isPackageProtectionEnabled()){
+            return ((Integer)AccessController.doPrivileged(new PrivilegedAction(){
+                public Object run(){
+                    return new Integer(doGetAttributeScope(name));
+                }
+            })).intValue();
+        } else {
+            return doGetAttributeScope(name);
+        }
+    }
+
+    private int doGetAttributeScope(String name){
+        if (attributes.get(name) != null)
+            return PAGE_SCOPE;
+
+        if (request.getAttribute(name) != null)
+            return REQUEST_SCOPE;
+
+        if (session != null) {
+            try {
+                if (session.getAttribute(name) != null)
+                    return SESSION_SCOPE;
+            } catch(IllegalStateException ise) {
+                // Session has been invalidated.
+                // Ignore and fall through to application scope.
+            }
+        }
+
+        if (context.getAttribute(name) != null)
+            return APPLICATION_SCOPE;
+
+        return 0;
+    }
+
+    public Object findAttribute(final String name) {
+        if (SecurityUtil.isPackageProtectionEnabled()){
+            return AccessController.doPrivileged(new PrivilegedAction(){
+                public Object run(){
+                    if (name == null) {
+                        throw new NullPointerException(
+                                Localizer.getMessage("jsp.error.attribute.null_name"));
+                    }
+
+                    return doFindAttribute(name);
+                }
+            });
+        } else {
+            if (name == null) {
+                throw new NullPointerException(
+                        Localizer.getMessage("jsp.error.attribute.null_name"));
+            }
+
+            return doFindAttribute(name);
+        }
+    }
+
+    private Object doFindAttribute(String name){
+
+        Object o = attributes.get(name);
+        if (o != null)
+            return o;
+
+        o = request.getAttribute(name);
+        if (o != null)
+            return o;
+
+        if (session != null) {
+            try {
+                o = session.getAttribute(name);
+            } catch(IllegalStateException ise) {
+                // Session has been invalidated.
+                // Ignore and fall through to application scope.
+            }
+            if (o != null)
+                return o;
+        }
+
+        return context.getAttribute(name);
+    }
+
+
+    public Enumeration getAttributeNamesInScope(final int scope) {
+        if (SecurityUtil.isPackageProtectionEnabled()){
+            return (Enumeration)
+                    AccessController.doPrivileged(new PrivilegedAction(){
+                public Object run(){
+                    return doGetAttributeNamesInScope(scope);
+                }
+            });
+        } else {
+            return doGetAttributeNamesInScope(scope);
+        }
+    }
+
+    private Enumeration doGetAttributeNamesInScope(int scope){
+        switch (scope) {
+        case PAGE_SCOPE:
+            return attributes.keys();
+            
+        case REQUEST_SCOPE:
+            return request.getAttributeNames();
+
+        case SESSION_SCOPE:
+            if (session == null) {
+            throw new IllegalStateException(
+                        Localizer.getMessage("jsp.error.page.noSession"));
+            }
+            return session.getAttributeNames();
+
+        case APPLICATION_SCOPE:
+            return context.getAttributeNames();
+
+        default:
+            throw new IllegalArgumentException("Invalid scope");
+        }
+    }
+
+    public void removeAttribute(final String name) {
+
+        if (name == null) {
+            throw new NullPointerException(
+                    Localizer.getMessage("jsp.error.attribute.null_name"));
+        }
+
+        if (SecurityUtil.isPackageProtectionEnabled()){
+            AccessController.doPrivileged(new PrivilegedAction(){
+                public Object run(){
+                    doRemoveAttribute(name);
+                    return null;
+                }
+            });
+        } else {
+            doRemoveAttribute(name);
+        }
+        }
+
+
+    private void doRemoveAttribute(String name){
+        removeAttribute(name, PAGE_SCOPE);
+        removeAttribute(name, REQUEST_SCOPE);
+        if( session != null ) {
+            try {
+                removeAttribute(name, SESSION_SCOPE);
+            } catch(IllegalStateException ise) {
+                // Session has been invalidated.
+                // Ignore and fall throw to application scope.
+            }
+        }
+        removeAttribute(name, APPLICATION_SCOPE);
+    }
+
+    public JspWriter getOut() {
+        return out;
+    }
+
+    public HttpSession getSession() { return session; }
+    public Servlet getServlet() { return servlet; }
+    public ServletConfig getServletConfig() { return config; }
+    public ServletContext getServletContext() {
+        return config.getServletContext();
+    }
+    public ServletRequest getRequest() { return request; }
+    public ServletResponse getResponse() { return response; }
+
+
+    /**
+     * Returns the exception associated with this page
+     * context, if any.
+     * <p/>
+     * Added wrapping for Throwables to avoid ClassCastException:
+     * see Bugzilla 31171 for details.
+     *
+     * @return The Exception associated with this page context, if any.
+     */
+    public Exception getException() {
+        Throwable t = JspRuntimeLibrary.getThrowable(request);
+
+        // Only wrap if needed
+        if((t != null) && (! (t instanceof Exception))) {
+            t = new JspException(t);
+        }
+
+        return (Exception) t;
+    }
+
+
+    public Object getPage() { return servlet; }
+
+
+    private final String getAbsolutePathRelativeToContext(String relativeUrlPath) {
+        String path = relativeUrlPath;
+
+        if (!path.startsWith("/")) {
+            String uri = (String)
+                request.getAttribute("javax.servlet.include.servlet_path");
+            if (uri == null)
+                uri = ((HttpServletRequest) request).getServletPath();
+            String baseURI = uri.substring(0, uri.lastIndexOf('/'));
+            path = baseURI+'/'+path;
+        }
+
+        return path;
+    }
+
+    public void include(String relativeUrlPath)
+                throws ServletException, IOException {
+        JspRuntimeLibrary.include(request, response, relativeUrlPath, out,
+                                  true);
+    }
+
+    public void include(final String relativeUrlPath, final boolean flush)
+                throws ServletException, IOException {
+        if (SecurityUtil.isPackageProtectionEnabled()){
+            try{
+                AccessController.doPrivileged(new PrivilegedExceptionAction(){
+                    public Object run() throws Exception{
+                        doInclude(relativeUrlPath, flush);
+                        return null;
+                    }
+                });
+            } catch (PrivilegedActionException e){
+                Exception ex =  e.getException();
+                if (ex instanceof IOException){
+                    throw (IOException)ex;
+                } else {
+                    throw (ServletException)ex;
+                }
+            }
+        } else {
+            doInclude(relativeUrlPath, flush);
+        }
+    }
+
+    private void doInclude(String relativeUrlPath, boolean flush)
+                throws ServletException, IOException {
+        JspRuntimeLibrary.include(request, response, relativeUrlPath, out,
+                                  flush);
+    }
+
+    public VariableResolver getVariableResolver() {
+        return this;
+    }
+
+    public void forward(final String relativeUrlPath)
+        throws ServletException, IOException {
+        if (SecurityUtil.isPackageProtectionEnabled()){
+            try{
+                AccessController.doPrivileged(new PrivilegedExceptionAction(){
+                    public Object run() throws Exception{
+                        doForward(relativeUrlPath);
+                        return null;
+                    }
+                });
+            } catch (PrivilegedActionException e){
+                Exception ex =  e.getException();
+                if (ex instanceof IOException){
+                    throw (IOException)ex;
+                } else {
+                    throw (ServletException)ex;
+                }
+            }
+        } else {
+            doForward(relativeUrlPath);
+        }
+    }
+
+    private void doForward(String relativeUrlPath)
+        throws ServletException, IOException{
+
+        // JSP.4.5 If the buffer was flushed, throw IllegalStateException
+        try {
+            out.clear();
+        } catch (IOException ex) {
+            IllegalStateException ise =
+                new IllegalStateException(Localizer.getMessage(
+                            "jsp.error.attempt_to_clear_flushed_buffer"));
+            ise.initCause(ex);
+            throw ise;
+        }
+
+        // Make sure that the response object is not the wrapper for include
+        while (response instanceof ServletResponseWrapperInclude) {
+            response = ((ServletResponseWrapperInclude)response).getResponse();
+        }
+
+        final String path = getAbsolutePathRelativeToContext(relativeUrlPath);
+        String includeUri
+            = (String) request.getAttribute(Constants.INC_SERVLET_PATH);
+            
+        if (includeUri != null)
+            request.removeAttribute(Constants.INC_SERVLET_PATH);
+        try {
+            context.getRequestDispatcher(path).forward(request, response);
+        } finally {
+            if (includeUri != null)
+                request.setAttribute(Constants.INC_SERVLET_PATH, includeUri);
+            request.setAttribute(Constants.FORWARD_SEEN, "true");
+        }
+    }
+
+    public BodyContent pushBody() {
+        return (BodyContent) pushBody(null);
+    }
+
+    public JspWriter pushBody(Writer writer) {
+        depth++;
+        if (depth >= outs.length) {
+            BodyContentImpl[] newOuts = new BodyContentImpl[depth + 1];
+            for (int i=0; i<outs.length; i++) {
+                newOuts[i] = outs[i];
+            }
+            newOuts[depth] = new BodyContentImpl(out);
+            outs = newOuts;
+        }
+
+        outs[depth].setWriter(writer);
+        out = outs[depth];
+
+        // Update the value of the "out" attribute in the page scope
+        // attribute namespace of this PageContext
+        setAttribute(OUT, out);
+
+        return outs[depth];
+    }
+
+    public JspWriter popBody() {
+        depth--;
+        if (depth >= 0) {
+            out = outs[depth];
+        } else {
+            out = baseOut;
+        }
+
+        // Update the value of the "out" attribute in the page scope
+        // attribute namespace of this PageContext
+        setAttribute(OUT, out);
+
+        return out;
+    }
+
+    /**
+     * Provides programmatic access to the ExpressionEvaluator.
+     * The JSP Container must return a valid instance of an
+     * ExpressionEvaluator that can parse EL expressions.
+     */
+    public ExpressionEvaluator getExpressionEvaluator() {
+        return elExprEval;
+    }
+
+    public void handlePageException(Exception ex)
+        throws IOException, ServletException
+    {
+        // Should never be called since handleException() called with a
+        // Throwable in the generated servlet.
+        handlePageException((Throwable) ex);
+    }
+
+    public void handlePageException(final Throwable t)
+        throws IOException, ServletException
+    {
+        if (t == null)
+            throw new NullPointerException("null Throwable");
+
+        if (SecurityUtil.isPackageProtectionEnabled()){
+            try{
+                AccessController.doPrivileged(new PrivilegedExceptionAction(){
+                    public Object run() throws Exception{
+                        doHandlePageException(t);
+                        return null;
+                    }
+                });
+            } catch (PrivilegedActionException e){
+                Exception ex =  e.getException();
+                if (ex instanceof IOException){
+                    throw (IOException)ex;
+                } else {
+                    throw (ServletException)ex;
+                }
+            }
+        } else {
+            doHandlePageException(t);
+        }
+
+    }
+
+    private void doHandlePageException(Throwable t)
+        throws IOException, ServletException {
+
+        if (errorPageURL != null && !errorPageURL.equals("")) {
+
+            /*
+             * Set request attributes.
+             * Do not set the javax.servlet.error.exception attribute here
+             * (instead, set in the generated servlet code for the error page)
+             * in order to prevent the ErrorReportValve, which is invoked as
+             * part of forwarding the request to the error page, from
+             * throwing it if the response has not been committed (the response
+             * will have been committed if the error page is a JSP page).
+             */
+            request.setAttribute("javax.servlet.jsp.jspException", t);
+            request.setAttribute("javax.servlet.error.status_code",
+                new Integer(HttpServletResponse.SC_INTERNAL_SERVER_ERROR));
+            request.setAttribute("javax.servlet.error.request_uri",
+            ((HttpServletRequest) request).getRequestURI());
+            request.setAttribute("javax.servlet.error.servlet_name",
+                     config.getServletName());
+            try {
+                forward(errorPageURL);
+            } catch (IllegalStateException ise) {
+                include(errorPageURL);
+            }
+
+            // The error page could be inside an include.
+
+            Object newException = request.getAttribute("javax.servlet.error.exception");
+
+            // t==null means the attribute was not set.
+            if( (newException!= null) && (newException==t) ) {
+                request.removeAttribute("javax.servlet.error.exception");
+            }
+
+            // now clear the error code - to prevent double handling.
+            request.removeAttribute("javax.servlet.error.status_code");
+            request.removeAttribute("javax.servlet.error.request_uri");
+            request.removeAttribute("javax.servlet.error.status_code");
+            request.removeAttribute("javax.servlet.jsp.jspException");
+
+        } else {
+            // Otherwise throw the exception wrapped inside a ServletException.
+            // Set the exception as the root cause in the ServletException
+            // to get a stack trace for the real problem
+            if (t instanceof IOException) throw (IOException)t;
+            if (t instanceof ServletException) throw (ServletException)t;
+            if (t instanceof RuntimeException) throw (RuntimeException)t;
+
+            Throwable rootCause = null;
+            if (t instanceof JspException) {
+                rootCause = ((JspException) t).getRootCause();
+            } else if (t instanceof ELException) {
+                rootCause = ((ELException) t).getRootCause();
+            }
+
+            if (rootCause != null) {
+                throw new ServletException(t.getClass().getName() + ": " + 
+                                           t.getMessage(), rootCause);
+            }
+                 
+            throw new ServletException(t);
+        }
+    }
+
+    /**
+     * VariableResolver interface
+     */
+    public Object resolveVariable(String pName) throws ELException {
+        return variableResolver.resolveVariable(pName);
+    }
+
+    private static String XmlEscape(String s) {
+        if (s == null) return null;
+        StringBuffer sb = new StringBuffer();
+        for(int i = 0; i < s.length(); i++) {
+            char c = s.charAt(i);
+            if (c == '<') {
+                sb.append("&lt;");
+            } else if (c == '>') {
+                sb.append("&gt;");
+            } else if (c == '\'') {
+                sb.append("&#039;");        // &apos;
+            } else if (c == '&') {
+                sb.append("&amp;");
+            } else if (c == '"') {
+                sb.append("&#034;");        // &quot;
+            } else {
+                sb.append(c);
+            }
+        }
+        return sb.toString();
+    }
+
+    /**
+     * Proprietary method to evaluate EL expressions.
+     * XXX - This method should go away once the EL interpreter moves
+     * out of JSTL and into its own project.  For now, this is necessary
+     * because the standard machinery is too slow.
+     *
+     * @param expression The expression to be evaluated
+     * @param expectedType The expected resulting type
+     * @param pageContext The page context
+     * @param functionMap Maps prefix and name to Method
+     * @return The result of the evaluation
+     */
+    public static Object proprietaryEvaluate(final String expression, 
+                                             final Class expectedType,
+                                             final PageContext pageContext,
+                                             final ProtectedFunctionMapper functionMap,
+                                             final boolean escape)
+        throws ELException
+    {
+        Object retValue;
+        if (SecurityUtil.isPackageProtectionEnabled()){
+            try {
+                retValue = AccessController.doPrivileged(
+                        new PrivilegedExceptionAction(){
+
+                    public Object run() throws Exception{
+                        return elExprEval.evaluate(expression,
+                                                   expectedType,
+                                                   pageContext.getVariableResolver(),
+                                                   functionMap);
+                    }
+                });
+            } catch (PrivilegedActionException ex) {
+                Exception realEx = ex.getException();
+                if (realEx instanceof ELException) {
+                    throw (ELException) realEx;
+                } else {
+                    throw new ELException(realEx);
+                }
+            }
+        } else {
+            retValue = elExprEval.evaluate(expression,
+                                           expectedType,
+                                           pageContext.getVariableResolver(),
+                                           functionMap);
+        }
+        if (escape) {
+            retValue = XmlEscape(retValue.toString());
+        }
+
+        return retValue;
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/runtime/PerThreadTagHandlerPool.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/runtime/PerThreadTagHandlerPool.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/runtime/PerThreadTagHandlerPool.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,133 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.util.Enumeration;
+import java.util.Vector;
+
+import javax.servlet.ServletConfig;
+import javax.servlet.jsp.JspException;
+import javax.servlet.jsp.tagext.Tag;
+
+import org.apache.jasper.Constants;
+
+/**
+ * Thread-local based pool of tag handlers that can be reused.
+ *
+ * @author Jan Luehe
+ * @author Costin Manolache
+ */
+public class PerThreadTagHandlerPool extends TagHandlerPool {
+
+    private int maxSize;
+
+    // For cleanup
+    private Vector perThreadDataVector;
+
+    private ThreadLocal perThread;
+
+    private static class PerThreadData {
+        Tag handlers[];
+        int current;
+    }
+
+    /**
+     * Constructs a tag handler pool with the default capacity.
+     */
+    public PerThreadTagHandlerPool() {
+        super();
+        perThreadDataVector = new Vector();
+    }
+
+    protected void init(ServletConfig config) {
+        maxSize = Constants.MAX_POOL_SIZE;
+        String maxSizeS = getOption(config, OPTION_MAXSIZE, null);
+        if (maxSizeS != null) {
+            maxSize = Integer.parseInt(maxSizeS);
+            if (maxSize < 0) {
+                maxSize = Constants.MAX_POOL_SIZE;
+            }
+        }
+
+        perThread = new ThreadLocal() {
+            protected Object initialValue() {
+                PerThreadData ptd = new PerThreadData();
+                ptd.handlers = new Tag[maxSize];
+                ptd.current = -1;
+                perThreadDataVector.addElement(ptd);
+                return ptd;
+            }
+        };
+    }
+
+    /**
+     * Gets the next available tag handler from this tag handler pool,
+     * instantiating one if this tag handler pool is empty.
+     *
+     * @param handlerClass Tag handler class
+     *
+     * @return Reused or newly instantiated tag handler
+     *
+     * @throws JspException if a tag handler cannot be instantiated
+     */
+    public Tag get(Class handlerClass) throws JspException {
+        PerThreadData ptd = (PerThreadData)perThread.get();
+        if(ptd.current >=0 ) {
+            return ptd.handlers[ptd.current--];
+        } else {
+	    try {
+		return (Tag) handlerClass.newInstance();
+	    } catch (Exception e) {
+		throw new JspException(e.getMessage(), e);
+	    }
+	}
+    }
+
+    /**
+     * Adds the given tag handler to this tag handler pool, unless this tag
+     * handler pool has already reached its capacity, in which case the tag
+     * handler's release() method is called.
+     *
+     * @param handler Tag handler to add to this tag handler pool
+     */
+    public void reuse(Tag handler) {
+        PerThreadData ptd=(PerThreadData)perThread.get();
+	if (ptd.current < (ptd.handlers.length - 1)) {
+	    ptd.handlers[++ptd.current] = handler;
+        } else {
+            handler.release();
+        }
+    }
+
+    /**
+     * Calls the release() method of all tag handlers in this tag handler pool.
+     */
+    public void release() {        
+        Enumeration enumeration = perThreadDataVector.elements();
+        while (enumeration.hasMoreElements()) {
+	    PerThreadData ptd = (PerThreadData)enumeration.nextElement();
+            if (ptd.handlers != null) {
+                for (int i=ptd.current; i>=0; i--) {
+                    if (ptd.handlers[i] != null) {
+                        ptd.handlers[i].release();
+		    }
+                }
+            }
+        }
+    }
+}
+

Added: branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/runtime/ProtectedFunctionMapper.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/runtime/ProtectedFunctionMapper.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/runtime/ProtectedFunctionMapper.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,188 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.util.HashMap;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.security.PrivilegedExceptionAction;
+import java.security.PrivilegedActionException;
+import java.lang.reflect.Method;
+import javax.servlet.jsp.el.FunctionMapper;
+
+import org.apache.jasper.security.SecurityUtil;
+
+/**
+ * Maps EL functions to their Java method counterparts.  Keeps the
+ * actual Method objects protected so that JSP pages can't indirectly
+ * do reflection.
+ *
+ * @author Mark Roth
+ * @author Kin-man Chung
+ */
+public final class ProtectedFunctionMapper implements FunctionMapper {
+
+    /** 
+     * Maps "prefix:name" to java.lang.Method objects.
+     */
+    private HashMap fnmap = null;
+
+    /**
+     * If there is only one function in the map, this is the Method for it.
+     */
+    private Method theMethod = null;
+
+    /**
+     * Constructor has protected access.
+     */
+    private ProtectedFunctionMapper() {
+    }
+
+    /**
+     * Generated Servlet and Tag Handler implementations call this
+     * method to retrieve an instance of the ProtectedFunctionMapper.
+     * This is necessary since generated code does not have access to
+     * create instances of classes in this package.
+     *
+     * @return A new protected function mapper.
+     */
+    public static ProtectedFunctionMapper getInstance() {
+        ProtectedFunctionMapper funcMapper;
+	if (SecurityUtil.isPackageProtectionEnabled()) {
+	    funcMapper = (ProtectedFunctionMapper)AccessController.doPrivileged(
+		new PrivilegedAction() {
+		public Object run() {
+		    return new ProtectedFunctionMapper();
+		}
+	    } );
+	} else {
+	    funcMapper = new ProtectedFunctionMapper();
+	}
+	funcMapper.fnmap = new java.util.HashMap();
+	return funcMapper;
+    }
+
+    /**
+     * Stores a mapping from the given EL function prefix and name to 
+     * the given Java method.
+     *
+     * @param fnQName The EL function qualified name (including prefix)
+     * @param c The class containing the Java method
+     * @param methodName The name of the Java method
+     * @param args The arguments of the Java method
+     * @throws RuntimeException if no method with the given signature
+     *     could be found.
+     */
+    public void mapFunction(String fnQName, final Class c,
+			    final String methodName, final Class[] args ) 
+    {
+	java.lang.reflect.Method method;
+        if (SecurityUtil.isPackageProtectionEnabled()){
+            try{
+                method = (java.lang.reflect.Method)AccessController.doPrivileged(new PrivilegedExceptionAction(){
+
+                    public Object run() throws Exception{
+                        return c.getDeclaredMethod(methodName, args);
+                    }                
+                });      
+            } catch (PrivilegedActionException ex){
+                throw new RuntimeException(
+                    "Invalid function mapping - no such method: "
+		    + ex.getException().getMessage());               
+            }
+        } else {
+             try {
+                method = c.getDeclaredMethod(methodName, args);
+            } catch( NoSuchMethodException e ) {
+                throw new RuntimeException(
+                    "Invalid function mapping - no such method: "
+		    + e.getMessage());
+            }
+        }
+
+	this.fnmap.put(fnQName, method );
+    }
+
+    /**
+     * Creates an instance for this class, and stores the Method for
+     * the given EL function prefix and name. This method is used for
+     * the case when there is only one function in the EL expression.
+     *
+     * @param fnQName The EL function qualified name (including prefix)
+     * @param c The class containing the Java method
+     * @param methodName The name of the Java method
+     * @param args The arguments of the Java method
+     * @throws RuntimeException if no method with the given signature
+     *     could be found.
+     */
+    public static ProtectedFunctionMapper getMapForFunction(
+		String fnQName, final Class c,
+                final String methodName, final Class[] args )
+    {
+        java.lang.reflect.Method method;
+        ProtectedFunctionMapper funcMapper;
+        if (SecurityUtil.isPackageProtectionEnabled()){
+            funcMapper = (ProtectedFunctionMapper)AccessController.doPrivileged(
+                new PrivilegedAction(){
+                public Object run() {
+                    return new ProtectedFunctionMapper();
+                }
+            });
+
+            try{
+                method = (java.lang.reflect.Method)AccessController.doPrivileged
+(new PrivilegedExceptionAction(){
+
+                    public Object run() throws Exception{
+                        return c.getDeclaredMethod(methodName, args);
+                    }
+                });
+            } catch (PrivilegedActionException ex){
+                throw new RuntimeException(
+                    "Invalid function mapping - no such method: "
+                    + ex.getException().getMessage());
+            }
+        } else {
+	    funcMapper = new ProtectedFunctionMapper();
+             try {
+                method = c.getDeclaredMethod(methodName, args);
+            } catch( NoSuchMethodException e ) {
+                throw new RuntimeException(
+                    "Invalid function mapping - no such method: "
+                    + e.getMessage());
+            }
+        }
+        funcMapper.theMethod = method;
+	return funcMapper;
+    }
+
+    /**
+     * Resolves the specified local name and prefix into a Java.lang.Method.
+     * Returns null if the prefix and local name are not found.
+     * 
+     * @param prefix the prefix of the function
+     * @param localName the short name of the function
+     * @return the result of the method mapping.  Null means no entry found.
+     **/
+    public Method resolveFunction(String prefix, String localName) {
+        if (this.fnmap != null) {
+            return (Method) this.fnmap.get(prefix + ":" + localName);
+        }
+	return theMethod;
+    }
+}
+

Added: branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/runtime/ServletResponseWrapperInclude.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/runtime/ServletResponseWrapperInclude.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/runtime/ServletResponseWrapperInclude.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,75 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.IOException;
+import java.io.PrintWriter;
+
+import javax.servlet.ServletOutputStream;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpServletResponseWrapper;
+import javax.servlet.jsp.JspWriter;
+
+/**
+ * ServletResponseWrapper used by the JSP 'include' action.
+ *
+ * This wrapper response object is passed to RequestDispatcher.include(), so
+ * that the output of the included resource is appended to that of the
+ * including page.
+ *
+ * @author Pierre Delisle
+ */
+
+public class ServletResponseWrapperInclude extends HttpServletResponseWrapper {
+
+    /**
+     * PrintWriter which appends to the JspWriter of the including page.
+     */
+    private PrintWriter printWriter;
+
+    private JspWriter jspWriter;
+
+    public ServletResponseWrapperInclude(ServletResponse response, 
+					 JspWriter jspWriter) {
+	super((HttpServletResponse)response);
+	this.printWriter = new PrintWriter(jspWriter);
+	this.jspWriter = jspWriter;
+    }
+
+    /**
+     * Returns a wrapper around the JspWriter of the including page.
+     */
+    public PrintWriter getWriter() throws IOException {
+	return printWriter;
+    }
+
+    public ServletOutputStream getOutputStream() throws IOException {
+	throw new IllegalStateException();
+    }
+
+    /**
+     * Clears the output buffer of the JspWriter associated with the including
+     * page.
+     */
+    public void resetBuffer() {
+	try {
+	    jspWriter.clearBuffer();
+	} catch (IOException ioe) {
+	}
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/runtime/TagHandlerPool.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/runtime/TagHandlerPool.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/runtime/TagHandlerPool.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,163 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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 javax.servlet.jsp.JspException;
+import javax.servlet.jsp.tagext.Tag;
+import javax.servlet.ServletConfig;
+import org.apache.jasper.Constants;
+
+/**
+ * Pool of tag handlers that can be reused.
+ *
+ * @author Jan Luehe
+ */
+public class TagHandlerPool {
+
+    private Tag[] handlers;
+
+    public static String OPTION_TAGPOOL="tagpoolClassName";
+    public static String OPTION_MAXSIZE="tagpoolMaxSize";
+
+    // index of next available tag handler
+    private int current;
+
+    public static TagHandlerPool getTagHandlerPool( ServletConfig config) {
+        TagHandlerPool result=null;
+
+        String tpClassName=getOption( config, OPTION_TAGPOOL, null);
+        if( tpClassName != null ) {
+            try {
+                Class c=Class.forName( tpClassName );
+                result=(TagHandlerPool)c.newInstance();
+            } catch (Exception e) {
+                e.printStackTrace();
+                result=null;
+            }
+        }
+        if( result==null ) result=new TagHandlerPool();
+        result.init(config);
+
+        return result;
+    }
+
+    protected void init( ServletConfig config ) {
+        int maxSize=-1;
+        String maxSizeS=getOption(config, OPTION_MAXSIZE, null);
+        if( maxSizeS != null ) {
+            try {
+                maxSize=Integer.parseInt(maxSizeS);
+            } catch( Exception ex) {
+                maxSize=-1;
+            }
+        }
+        if( maxSize <0  ) {
+            maxSize=Constants.MAX_POOL_SIZE;
+        }
+        this.handlers = new Tag[maxSize];
+        this.current = -1;
+    }
+
+    /**
+     * Constructs a tag handler pool with the default capacity.
+     */
+    public TagHandlerPool() {
+	// Nothing - jasper generated servlets call the other constructor,
+        // this should be used in future + init .
+    }
+
+    /**
+     * Constructs a tag handler pool with the given capacity.
+     *
+     * @param capacity Tag handler pool capacity
+     * @deprecated Use static getTagHandlerPool
+     */
+    public TagHandlerPool(int capacity) {
+	this.handlers = new Tag[capacity];
+	this.current = -1;
+    }
+
+    /**
+     * Gets the next available tag handler from this tag handler pool,
+     * instantiating one if this tag handler pool is empty.
+     *
+     * @param handlerClass Tag handler class
+     *
+     * @return Reused or newly instantiated tag handler
+     *
+     * @throws JspException if a tag handler cannot be instantiated
+     */
+    public Tag get(Class handlerClass) throws JspException {
+	Tag handler = null;
+        synchronized( this ) {
+            if (current >= 0) {
+                handler = handlers[current--];
+                return handler;
+            }
+        }
+
+        // Out of sync block - there is no need for other threads to
+        // wait for us to construct a tag for this thread.
+        try {
+            return (Tag) handlerClass.newInstance();
+        } catch (Exception e) {
+            throw new JspException(e.getMessage(), e);
+        }
+    }
+
+    /**
+     * Adds the given tag handler to this tag handler pool, unless this tag
+     * handler pool has already reached its capacity, in which case the tag
+     * handler's release() method is called.
+     *
+     * @param handler Tag handler to add to this tag handler pool
+     */
+    public void reuse(Tag handler) {
+        synchronized( this ) {
+            if (current < (handlers.length - 1)) {
+                handlers[++current] = handler;
+                return;
+            }
+        }
+        // There is no need for other threads to wait for us to release
+        handler.release();
+    }
+
+    /**
+     * Calls the release() method of all available tag handlers in this tag
+     * handler pool.
+     */
+    public synchronized void release() {
+	for (int i=current; i>=0; i--) {
+	    handlers[i].release();
+	}
+    }
+
+    protected static String getOption( ServletConfig config, String name, String defaultV) {
+        if( config == null ) return defaultV;
+
+        String value=config.getInitParameter(name);
+        if( value != null ) return value;
+        if( config.getServletContext() ==null )
+            return defaultV;
+        value=config.getServletContext().getInitParameter(name);
+        if( value!=null ) return value;
+        return defaultV;
+    }
+
+}
+

Added: branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/security/SecurityClassLoad.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/security/SecurityClassLoad.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/security/SecurityClassLoad.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,110 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.security;
+
+/**
+ * Static class used to preload java classes when using the
+ * Java SecurityManager so that the defineClassInPackage
+ * RuntimePermission does not trigger an AccessControlException.
+ *
+ * @author Jean-Francois Arcand
+ */
+
+public final class SecurityClassLoad {
+
+    private static org.apache.commons.logging.Log log=
+        org.apache.commons.logging.LogFactory.getLog( SecurityClassLoad.class );
+
+    public static void securityClassLoad(ClassLoader loader){
+
+        if( System.getSecurityManager() == null ){
+            return;
+        }
+
+        String basePackage = "org.apache.jasper.";
+        try {
+            loader.loadClass( basePackage +
+                "runtime.JspFactoryImpl$PrivilegedGetPageContext");
+            loader.loadClass( basePackage +
+                "runtime.JspFactoryImpl$PrivilegedReleasePageContext");
+
+            loader.loadClass( basePackage +
+                "runtime.JspRuntimeLibrary");
+            loader.loadClass( basePackage +
+                "runtime.JspRuntimeLibrary$PrivilegedIntrospectHelper");
+            
+            loader.loadClass( basePackage +
+                "runtime.ServletResponseWrapperInclude");
+            loader.loadClass( basePackage +
+                "runtime.TagHandlerPool");
+            loader.loadClass( basePackage +
+                "runtime.JspFragmentHelper");
+
+            loader.loadClass( basePackage +
+                "runtime.ProtectedFunctionMapper");
+            loader.loadClass( basePackage +
+                "runtime.ProtectedFunctionMapper$1");
+            loader.loadClass( basePackage +
+                "runtime.ProtectedFunctionMapper$2"); 
+            loader.loadClass( basePackage +
+                "runtime.ProtectedFunctionMapper$3");
+            loader.loadClass( basePackage +
+                "runtime.ProtectedFunctionMapper$4"); 
+
+            loader.loadClass( basePackage +
+                "runtime.PageContextImpl");      
+            loader.loadClass( basePackage +
+                "runtime.PageContextImpl$1");      
+            loader.loadClass( basePackage +
+                "runtime.PageContextImpl$2");      
+            loader.loadClass( basePackage +
+                "runtime.PageContextImpl$3");      
+            loader.loadClass( basePackage +
+                "runtime.PageContextImpl$4");      
+            loader.loadClass( basePackage +
+                "runtime.PageContextImpl$5");      
+            loader.loadClass( basePackage +
+                "runtime.PageContextImpl$6");      
+            loader.loadClass( basePackage +
+                "runtime.PageContextImpl$7");      
+            loader.loadClass( basePackage +
+                "runtime.PageContextImpl$8");      
+            loader.loadClass( basePackage +
+                "runtime.PageContextImpl$9");      
+            loader.loadClass( basePackage +
+                "runtime.PageContextImpl$10");      
+            loader.loadClass( basePackage +
+                "runtime.PageContextImpl$11");      
+            loader.loadClass( basePackage +
+                "runtime.PageContextImpl$12");      
+            loader.loadClass( basePackage +
+                "runtime.PageContextImpl$13");      
+
+            loader.loadClass( basePackage +
+                "runtime.JspContextWrapper");   
+
+            loader.loadClass( basePackage +
+                "servlet.JspServletWrapper");
+
+            loader.loadClass( basePackage +
+                "runtime.JspWriterImpl$1");
+        } catch (ClassNotFoundException ex) {
+            log.error("SecurityClassLoad", ex);
+        }
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/security/SecurityUtil.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/security/SecurityUtil.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/security/SecurityUtil.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,41 @@
+/*
+ * Copyright 1999-2002,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.security;
+
+/**
+ * Util class for Security related operations.
+ *
+ * @author Jean-Francois Arcand
+ */
+
+public final class SecurityUtil{
+    
+    private static boolean packageDefinitionEnabled =  
+         System.getProperty("package.definition") == null ? false : true;
+    
+    /**
+     * Return the <code>SecurityManager</code> only if Security is enabled AND
+     * package protection mechanism is enabled.
+     */
+    public static boolean isPackageProtectionEnabled(){
+        if (packageDefinitionEnabled && System.getSecurityManager() !=  null){
+            return true;
+        }
+        return false;
+    }
+    
+    
+}

Added: branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/servlet/JasperLoader.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/servlet/JasperLoader.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/servlet/JasperLoader.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,171 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.servlet;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.security.CodeSource;
+import java.security.PermissionCollection;
+
+import org.apache.jasper.Constants;
+
+/**
+ * Class loader for loading servlet class files (corresponding to JSP files) 
+ * and tag handler class files (corresponding to tag files).
+ *
+ * @author Anil K. Vijendran
+ * @author Harish Prabandham
+ * @author Jean-Francois Arcand
+ */
+public class JasperLoader extends URLClassLoader {
+
+    private PermissionCollection permissionCollection;
+    private CodeSource codeSource;
+    private String className;
+    private ClassLoader parent;
+    private SecurityManager securityManager;
+
+    public JasperLoader(URL[] urls, ClassLoader parent,
+			PermissionCollection permissionCollection,
+			CodeSource codeSource) {
+	super(urls, parent);
+	this.permissionCollection = permissionCollection;
+	this.codeSource = codeSource;
+	this.parent = parent;
+	this.securityManager = System.getSecurityManager();
+    }
+
+    /**
+     * Load the class with the specified name.  This method searches for
+     * classes in the same manner as <code>loadClass(String, boolean)</code>
+     * with <code>false</code> as the second argument.
+     *
+     * @param name Name of the class to be loaded
+     *
+     * @exception ClassNotFoundException if the class was not found
+     */
+    public Class loadClass(String name) throws ClassNotFoundException {
+
+        return (loadClass(name, false));
+    }
+
+    /**
+     * Load the class with the specified name, searching using the following
+     * algorithm until it finds and returns the class.  If the class cannot
+     * be found, returns <code>ClassNotFoundException</code>.
+     * <ul>
+     * <li>Call <code>findLoadedClass(String)</code> to check if the
+     *     class has already been loaded.  If it has, the same
+     *     <code>Class</code> object is returned.</li>
+     * <li>If the <code>delegate</code> property is set to <code>true</code>,
+     *     call the <code>loadClass()</code> method of the parent class
+     *     loader, if any.</li>            
+     * <li>Call <code>findClass()</code> to find this class in our locally
+     *     defined repositories.</li>      
+     * <li>Call the <code>loadClass()</code> method of our parent
+     *     class loader, if any.</li>      
+     * </ul>
+     * If the class was found using the above steps, and the
+     * <code>resolve</code> flag is <code>true</code>, this method will then
+     * call <code>resolveClass(Class)</code> on the resulting Class object.
+     *                                     
+     * @param name Name of the class to be loaded
+     * @param resolve If <code>true</code> then resolve the class
+     *                                     
+     * @exception ClassNotFoundException if the class was not found
+     */                                    
+    public Class loadClass(final String name, boolean resolve)
+        throws ClassNotFoundException {
+
+        Class clazz = null;                
+                                           
+        // (0) Check our previously loaded class cache
+        clazz = findLoadedClass(name);     
+        if (clazz != null) {               
+            if (resolve)                   
+                resolveClass(clazz);       
+            return (clazz);        
+        }                          
+                          
+        // (.5) Permission to access this class when using a SecurityManager
+        if (securityManager != null) {     
+            int dot = name.lastIndexOf('.');
+            if (dot >= 0) {                
+                try {        
+                    // Do not call the security manager since by default, we grant that package.
+                    if (!"org.apache.jasper.runtime".equalsIgnoreCase(name.substring(0,dot))){
+                        securityManager.checkPackageAccess(name.substring(0,dot));
+                    }
+                } catch (SecurityException se) {
+                    String error = "Security Violation, attempt to use " +
+                        "Restricted Class: " + name;
+                    se.printStackTrace();
+                    throw new ClassNotFoundException(error);
+                }                          
+            }                              
+        }
+
+	if( !name.startsWith(Constants.JSP_PACKAGE_NAME) ) {
+            // Class is not in org.apache.jsp, therefore, have our
+            // parent load it
+            clazz = parent.loadClass(name);            
+	    if( resolve )
+		resolveClass(clazz);
+	    return clazz;
+	}
+
+	return findClass(name);
+    }
+
+    
+    /**
+     * Delegate to parent
+     * 
+     * @see java.lang.ClassLoader#getResourceAsStream(java.lang.String)
+     */
+    public InputStream getResourceAsStream(String name) {
+        InputStream is = parent.getResourceAsStream(name);
+        if (is == null) {
+            URL url = findResource(name);
+            if (url != null) {
+                try {
+                    is = url.openStream();
+                } catch (IOException e) {
+                    is = null;
+                }
+            }
+        }
+        return is;
+    }
+    
+    
+    /**
+     * Get the Permissions for a CodeSource.
+     *
+     * Since this ClassLoader is only used for a JSP page in
+     * a web application context, we just return our preset
+     * PermissionCollection for the web app context.
+     *
+     * @param codeSource Code source where the code was loaded from
+     * @return PermissionCollection for CodeSource
+     */
+    public final PermissionCollection getPermissions(CodeSource codeSource) {
+        return permissionCollection;
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/servlet/JspCServletContext.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/servlet/JspCServletContext.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/servlet/JspCServletContext.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,430 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.servlet;
+
+
+import java.io.File;
+import java.io.InputStream;
+import java.io.PrintWriter;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.Set;
+import java.util.Vector;
+
+import javax.servlet.RequestDispatcher;
+import javax.servlet.Servlet;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+
+
+/**
+ * Simple <code>ServletContext</code> implementation without
+ * HTTP-specific methods.
+ *
+ * @author Peter Rossbach (pr at webapp.de)
+ */
+
+public class JspCServletContext implements ServletContext {
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * Servlet context attributes.
+     */
+    protected Hashtable myAttributes;
+
+
+    /**
+     * The log writer we will write log messages to.
+     */
+    protected PrintWriter myLogWriter;
+
+
+    /**
+     * The base URL (document root) for this context.
+     */
+    protected URL myResourceBaseURL;
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Create a new instance of this ServletContext implementation.
+     *
+     * @param aLogWriter PrintWriter which is used for <code>log()</code> calls
+     * @param aResourceBaseURL Resource base URL
+     */
+    public JspCServletContext(PrintWriter aLogWriter, URL aResourceBaseURL) {
+
+        myAttributes = new Hashtable();
+        myLogWriter = aLogWriter;
+        myResourceBaseURL = aResourceBaseURL;
+
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Return the specified context attribute, if any.
+     *
+     * @param name Name of the requested attribute
+     */
+    public Object getAttribute(String name) {
+
+        return (myAttributes.get(name));
+
+    }
+
+
+    /**
+     * Return an enumeration of context attribute names.
+     */
+    public Enumeration getAttributeNames() {
+
+        return (myAttributes.keys());
+
+    }
+
+
+    /**
+     * Return the servlet context for the specified path.
+     *
+     * @param uripath Server-relative path starting with '/'
+     */
+    public ServletContext getContext(String uripath) {
+
+        return (null);
+
+    }
+
+
+    /**
+     * Return the specified context initialization parameter.
+     *
+     * @param name Name of the requested parameter
+     */
+    public String getInitParameter(String name) {
+
+        return (null);
+
+    }
+
+
+    /**
+     * Return an enumeration of the names of context initialization
+     * parameters.
+     */
+    public Enumeration getInitParameterNames() {
+
+        return (new Vector().elements());
+
+    }
+
+
+    /**
+     * Return the Servlet API major version number.
+     */
+    public int getMajorVersion() {
+
+        return (2);
+
+    }
+
+
+    /**
+     * Return the MIME type for the specified filename.
+     *
+     * @param file Filename whose MIME type is requested
+     */
+    public String getMimeType(String file) {
+
+        return (null);
+
+    }
+
+
+    /**
+     * Return the Servlet API minor version number.
+     */
+    public int getMinorVersion() {
+
+        return (3);
+
+    }
+
+
+    /**
+     * Return a request dispatcher for the specified servlet name.
+     *
+     * @param name Name of the requested servlet
+     */
+    public RequestDispatcher getNamedDispatcher(String name) {
+
+        return (null);
+
+    }
+
+
+    /**
+     * Return the real path for the specified context-relative
+     * virtual path.
+     *
+     * @param path The context-relative virtual path to resolve
+     */
+    public String getRealPath(String path) {
+
+        if (!myResourceBaseURL.getProtocol().equals("file"))
+            return (null);
+        if (!path.startsWith("/"))
+            return (null);
+        try {
+            return
+                (getResource(path).getFile().replace('/', File.separatorChar));
+        } catch (Throwable t) {
+            return (null);
+        }
+
+    }
+            
+            
+    /**
+     * Return a request dispatcher for the specified context-relative path.
+     *
+     * @param path Context-relative path for which to acquire a dispatcher
+     */
+    public RequestDispatcher getRequestDispatcher(String path) {
+
+        return (null);
+
+    }
+
+
+    /**
+     * Return a URL object of a resource that is mapped to the
+     * specified context-relative path.
+     *
+     * @param path Context-relative path of the desired resource
+     *
+     * @exception MalformedURLException if the resource path is
+     *  not properly formed
+     */
+    public URL getResource(String path) throws MalformedURLException {
+
+        if (!path.startsWith("/"))
+            throw new MalformedURLException("Path '" + path +
+                                            "' does not start with '/'");
+        URL url = new URL(myResourceBaseURL, path.substring(1));
+        InputStream is = null;
+        try {
+            is = url.openStream();
+        } catch (Throwable t) {
+            url = null;
+        } finally {
+            if (is != null) {
+                try {
+                    is.close();
+                } catch (Throwable t2) {
+                    // Ignore
+                }
+            }
+        }
+        return url;
+
+    }
+
+
+    /**
+     * Return an InputStream allowing access to the resource at the
+     * specified context-relative path.
+     *
+     * @param path Context-relative path of the desired resource
+     */
+    public InputStream getResourceAsStream(String path) {
+
+        try {
+            return (getResource(path).openStream());
+        } catch (Throwable t) {
+            return (null);
+        }
+
+    }
+
+
+    /**
+     * Return the set of resource paths for the "directory" at the
+     * specified context path.
+     *
+     * @param path Context-relative base path
+     */
+    public Set getResourcePaths(String path) {
+
+        Set thePaths = new HashSet();
+        if (!path.endsWith("/"))
+            path += "/";
+        String basePath = getRealPath(path);
+        if (basePath == null)
+            return (thePaths);
+        File theBaseDir = new File(basePath);
+        if (!theBaseDir.exists() || !theBaseDir.isDirectory())
+            return (thePaths);
+        String theFiles[] = theBaseDir.list();
+        for (int i = 0; i < theFiles.length; i++) {
+            File testFile = new File(basePath + File.separator + theFiles[i]);
+            if (testFile.isFile())
+                thePaths.add(path + theFiles[i]);
+            else if (testFile.isDirectory())
+                thePaths.add(path + theFiles[i] + "/");
+        }
+        return (thePaths);
+
+    }
+
+
+    /**
+     * Return descriptive information about this server.
+     */
+    public String getServerInfo() {
+
+        return ("JspCServletContext/1.0");
+
+    }
+
+
+    /**
+     * Return a null reference for the specified servlet name.
+     *
+     * @param name Name of the requested servlet
+     *
+     * @deprecated This method has been deprecated with no replacement
+     */
+    public Servlet getServlet(String name) throws ServletException {
+
+        return (null);
+
+    }
+
+
+    /**
+     * Return the name of this servlet context.
+     */
+    public String getServletContextName() {
+
+        return (getServerInfo());
+
+    }
+
+
+    /**
+     * Return an empty enumeration of servlet names.
+     *
+     * @deprecated This method has been deprecated with no replacement
+     */
+    public Enumeration getServletNames() {
+
+        return (new Vector().elements());
+
+    }
+
+
+    /**
+     * Return an empty enumeration of servlets.
+     *
+     * @deprecated This method has been deprecated with no replacement
+     */
+    public Enumeration getServlets() {
+
+        return (new Vector().elements());
+
+    }
+
+
+    /**
+     * Log the specified message.
+     *
+     * @param message The message to be logged
+     */
+    public void log(String message) {
+
+        myLogWriter.println(message);
+
+    }
+
+
+    /**
+     * Log the specified message and exception.
+     *
+     * @param exception The exception to be logged
+     * @param message The message to be logged
+     *
+     * @deprecated Use log(String,Throwable) instead
+     */
+    public void log(Exception exception, String message) {
+
+        log(message, exception);
+
+    }
+
+
+    /**
+     * Log the specified message and exception.
+     *
+     * @param message The message to be logged
+     * @param exception The exception to be logged
+     */
+    public void log(String message, Throwable exception) {
+
+        myLogWriter.println(message);
+        exception.printStackTrace(myLogWriter);
+
+    }
+
+
+    /**
+     * Remove the specified context attribute.
+     *
+     * @param name Name of the attribute to remove
+     */
+    public void removeAttribute(String name) {
+
+        myAttributes.remove(name);
+
+    }
+
+
+    /**
+     * Set or replace the specified context attribute.
+     *
+     * @param name Name of the context attribute to set
+     * @param value Corresponding attribute value
+     */
+    public void setAttribute(String name, Object value) {
+
+        myAttributes.put(name, value);
+
+    }
+
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/servlet/JspServlet.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/servlet/JspServlet.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/servlet/JspServlet.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,318 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.servlet;
+
+import java.io.IOException;
+import java.lang.reflect.Constructor;
+import java.util.Enumeration;
+
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.apache.jasper.Constants;
+import org.apache.jasper.EmbeddedServletOptions;
+import org.apache.jasper.Options;
+import org.apache.jasper.compiler.JspRuntimeContext;
+import org.apache.jasper.compiler.Localizer;
+
+/**
+ * The JSP engine (a.k.a Jasper).
+ *
+ * The servlet container is responsible for providing a
+ * URLClassLoader for the web application context Jasper
+ * is being used in. Jasper will try get the Tomcat
+ * ServletContext attribute for its ServletContext class
+ * loader, if that fails, it uses the parent class loader.
+ * In either case, it must be a URLClassLoader.
+ *
+ * @author Anil K. Vijendran
+ * @author Harish Prabandham
+ * @author Remy Maucherat
+ * @author Kin-man Chung
+ * @author Glenn Nielsen
+ */
+public class JspServlet extends HttpServlet {
+
+    // Logger
+    private Log log = LogFactory.getLog(JspServlet.class);
+
+    private ServletContext context;
+    private ServletConfig config;
+    private Options options;
+    private JspRuntimeContext rctxt;
+
+
+    /*
+     * Initializes this JspServlet.
+     */
+    public void init(ServletConfig config) throws ServletException {
+        
+        super.init(config);
+        this.config = config;
+        this.context = config.getServletContext();
+        
+        // Initialize the JSP Runtime Context
+        // Check for a custom Options implementation
+        String engineOptionsName = 
+            config.getInitParameter("engineOptionsClass");
+        if (engineOptionsName != null) {
+            // Instantiate the indicated Options implementation
+            try {
+                ClassLoader loader = Thread.currentThread()
+                        .getContextClassLoader();
+                Class engineOptionsClass = loader.loadClass(engineOptionsName);
+                Class[] ctorSig = { ServletConfig.class, ServletContext.class };
+                Constructor ctor = engineOptionsClass.getConstructor(ctorSig);
+                Object[] args = { config, context };
+                options = (Options) ctor.newInstance(args);
+            } catch (Throwable e) {
+                // Need to localize this.
+                log.warn("Failed to load engineOptionsClass", e);
+                // Use the default Options implementation
+                options = new EmbeddedServletOptions(config, context);
+            }
+        } else {
+            // Use the default Options implementation
+            options = new EmbeddedServletOptions(config, context);
+        }
+        rctxt = new JspRuntimeContext(context, options);
+        
+        if (log.isDebugEnabled()) {
+            log.debug(Localizer.getMessage("jsp.message.scratch.dir.is",
+                    options.getScratchDir().toString()));
+            log.debug(Localizer.getMessage("jsp.message.dont.modify.servlets"));
+        }
+    }
+
+
+    /**
+     * Returns the number of JSPs for which JspServletWrappers exist, i.e.,
+     * the number of JSPs that have been loaded into the webapp with which
+     * this JspServlet is associated.
+     *
+     * <p>This info may be used for monitoring purposes.
+     *
+     * @return The number of JSPs that have been loaded into the webapp with
+     * which this JspServlet is associated
+     */
+    public int getJspCount() {
+        return this.rctxt.getJspCount();
+    }
+
+
+    /**
+     * Resets the JSP reload counter.
+     *
+     * @param count Value to which to reset the JSP reload counter
+     */
+    public void setJspReloadCount(int count) {
+        this.rctxt.setJspReloadCount(count);
+    }
+
+
+    /**
+     * Gets the number of JSPs that have been reloaded.
+     *
+     * <p>This info may be used for monitoring purposes.
+     *
+     * @return The number of JSPs (in the webapp with which this JspServlet is
+     * associated) that have been reloaded
+     */
+    public int getJspReloadCount() {
+        return this.rctxt.getJspReloadCount();
+    }
+
+
+    /**
+     * <p>Look for a <em>precompilation request</em> as described in
+     * Section 8.4.2 of the JSP 1.2 Specification.  <strong>WARNING</strong> -
+     * we cannot use <code>request.getParameter()</code> for this, because
+     * that will trigger parsing all of the request parameters, and not give
+     * a servlet the opportunity to call
+     * <code>request.setCharacterEncoding()</code> first.</p>
+     *
+     * @param request The servlet requset we are processing
+     *
+     * @exception ServletException if an invalid parameter value for the
+     *  <code>jsp_precompile</code> parameter name is specified
+     */
+    boolean preCompile(HttpServletRequest request) throws ServletException {
+
+        String queryString = request.getQueryString();
+        if (queryString == null) {
+            return (false);
+        }
+        int start = queryString.indexOf(Constants.PRECOMPILE);
+        if (start < 0) {
+            return (false);
+        }
+        queryString =
+            queryString.substring(start + Constants.PRECOMPILE.length());
+        if (queryString.length() == 0) {
+            return (true);             // ?jsp_precompile
+        }
+        if (queryString.startsWith("&")) {
+            return (true);             // ?jsp_precompile&foo=bar...
+        }
+        if (!queryString.startsWith("=")) {
+            return (false);            // part of some other name or value
+        }
+        int limit = queryString.length();
+        int ampersand = queryString.indexOf("&");
+        if (ampersand > 0) {
+            limit = ampersand;
+        }
+        String value = queryString.substring(1, limit);
+        if (value.equals("true")) {
+            return (true);             // ?jsp_precompile=true
+        } else if (value.equals("false")) {
+	    // Spec says if jsp_precompile=false, the request should not
+	    // be delivered to the JSP page; the easiest way to implement
+	    // this is to set the flag to true, and precompile the page anyway.
+	    // This still conforms to the spec, since it says the
+	    // precompilation request can be ignored.
+            return (true);             // ?jsp_precompile=false
+        } else {
+            throw new ServletException("Cannot have request parameter " +
+                                       Constants.PRECOMPILE + " set to " +
+                                       value);
+        }
+
+    }
+    
+
+    public void service (HttpServletRequest request, 
+    			 HttpServletResponse response)
+                throws ServletException, IOException {
+
+        String jspUri = null;
+
+        String jspFile = (String) request.getAttribute(Constants.JSP_FILE);
+        if (jspFile != null) {
+            // JSP is specified via <jsp-file> in <servlet> declaration
+            jspUri = jspFile;
+        } else {
+            /*
+             * Check to see if the requested JSP has been the target of a
+             * RequestDispatcher.include()
+             */
+            jspUri = (String) request.getAttribute(Constants.INC_SERVLET_PATH);
+            if (jspUri != null) {
+                /*
+		 * Requested JSP has been target of
+                 * RequestDispatcher.include(). Its path is assembled from the
+                 * relevant javax.servlet.include.* request attributes
+                 */
+                String pathInfo = (String) request.getAttribute(
+                                    "javax.servlet.include.path_info");
+                if (pathInfo != null) {
+                    jspUri += pathInfo;
+                }
+            } else {
+                /*
+                 * Requested JSP has not been the target of a 
+                 * RequestDispatcher.include(). Reconstruct its path from the
+                 * request's getServletPath() and getPathInfo()
+                 */
+                jspUri = request.getServletPath();
+                String pathInfo = request.getPathInfo();
+                if (pathInfo != null) {
+                    jspUri += pathInfo;
+                }
+            }
+        }
+
+        if (log.isDebugEnabled()) {	    
+            log.debug("JspEngine --> " + jspUri);
+            log.debug("\t     ServletPath: " + request.getServletPath());
+            log.debug("\t        PathInfo: " + request.getPathInfo());
+            log.debug("\t        RealPath: " + context.getRealPath(jspUri));
+            log.debug("\t      RequestURI: " + request.getRequestURI());
+            log.debug("\t     QueryString: " + request.getQueryString());
+            log.debug("\t  Request Params: ");
+            Enumeration e = request.getParameterNames();
+            while (e.hasMoreElements()) {
+                String name = (String) e.nextElement();
+                log.debug("\t\t " + name + " = " 
+                          + request.getParameter(name));
+            }
+        }
+
+        try {
+            boolean precompile = preCompile(request);
+            serviceJspFile(request, response, jspUri, null, precompile);
+        } catch (RuntimeException e) {
+            throw e;
+        } catch (ServletException e) {
+            throw e;
+        } catch (IOException e) {
+            throw e;
+        } catch (Throwable e) {
+            throw new ServletException(e);
+        }
+
+    }
+
+    public void destroy() {
+        if (log.isDebugEnabled()) {
+            log.debug("JspServlet.destroy()");
+        }
+
+        rctxt.destroy();
+    }
+
+
+    // -------------------------------------------------------- Private Methods
+
+    private void serviceJspFile(HttpServletRequest request,
+                                HttpServletResponse response, String jspUri,
+                                Throwable exception, boolean precompile)
+        throws ServletException, IOException {
+
+        JspServletWrapper wrapper =
+            (JspServletWrapper) rctxt.getWrapper(jspUri);
+        if (wrapper == null) {
+            synchronized(this) {
+                wrapper = (JspServletWrapper) rctxt.getWrapper(jspUri);
+                if (wrapper == null) {
+                    // Check if the requested JSP page exists, to avoid
+                    // creating unnecessary directories and files.
+                    if (null == context.getResource(jspUri)) {
+                        response.sendError(HttpServletResponse.SC_NOT_FOUND,
+                                           jspUri);
+                        return;
+                    }
+                    boolean isErrorPage = exception != null;
+                    wrapper = new JspServletWrapper(config, options, jspUri,
+                                                    isErrorPage, rctxt);
+                    rctxt.addWrapper(jspUri,wrapper);
+                }
+            }
+        }
+
+        wrapper.service(request, response, precompile);
+
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/servlet/JspServletWrapper.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/servlet/JspServletWrapper.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/servlet/JspServletWrapper.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,532 @@
+/*
+ * Copyright 1999,2004-2005 The Apache Software Foundation.
+ * 
+ * Licensed 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.servlet;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.IOException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.servlet.Servlet;
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+import javax.servlet.SingleThreadModel;
+import javax.servlet.UnavailableException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.jsp.tagext.TagInfo;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.jasper.JasperException;
+import org.apache.jasper.JspCompilationContext;
+import org.apache.jasper.Options;
+import org.apache.jasper.compiler.ErrorDispatcher;
+import org.apache.jasper.compiler.JavacErrorDetail;
+import org.apache.jasper.compiler.JspRuntimeContext;
+import org.apache.jasper.compiler.Localizer;
+import org.apache.jasper.runtime.JspSourceDependent;
+
+/**
+ * The JSP engine (a.k.a Jasper).
+ *
+ * The servlet container is responsible for providing a
+ * URLClassLoader for the web application context Jasper
+ * is being used in. Jasper will try get the Tomcat
+ * ServletContext attribute for its ServletContext class
+ * loader, if that fails, it uses the parent class loader.
+ * In either case, it must be a URLClassLoader.
+ *
+ * @author Anil K. Vijendran
+ * @author Harish Prabandham
+ * @author Remy Maucherat
+ * @author Kin-man Chung
+ * @author Glenn Nielsen
+ * @author Tim Fennell
+ */
+
+public class JspServletWrapper {
+
+    // Logger
+    private Log log = LogFactory.getLog(JspServletWrapper.class);
+
+    private Servlet theServlet;
+    private String jspUri;
+    private Class servletClass;
+    private Class tagHandlerClass;
+    private JspCompilationContext ctxt;
+    private long available = 0L;
+    private ServletConfig config;
+    private Options options;
+    private boolean firstTime = true;
+    private boolean reload = true;
+    private boolean isTagFile;
+    private int tripCount;
+    private JasperException compileException;
+    private long servletClassLastModifiedTime;
+    private long lastModificationTest = 0L;
+
+    /*
+     * JspServletWrapper for JSP pages.
+     */
+    JspServletWrapper(ServletConfig config, Options options, String jspUri,
+                      boolean isErrorPage, JspRuntimeContext rctxt)
+            throws JasperException {
+
+	this.isTagFile = false;
+        this.config = config;
+        this.options = options;
+        this.jspUri = jspUri;
+        ctxt = new JspCompilationContext(jspUri, isErrorPage, options,
+					 config.getServletContext(),
+					 this, rctxt);
+    }
+
+    /*
+     * JspServletWrapper for tag files.
+     */
+    public JspServletWrapper(ServletContext servletContext,
+			     Options options,
+			     String tagFilePath,
+			     TagInfo tagInfo,
+			     JspRuntimeContext rctxt,
+			     URL tagFileJarUrl)
+	    throws JasperException {
+
+	this.isTagFile = true;
+        this.config = null;	// not used
+        this.options = options;
+	this.jspUri = tagFilePath;
+	this.tripCount = 0;
+        ctxt = new JspCompilationContext(jspUri, tagInfo, options,
+					 servletContext, this, rctxt,
+					 tagFileJarUrl);
+    }
+
+    public JspCompilationContext getJspEngineContext() {
+        return ctxt;
+    }
+
+    public void setReload(boolean reload) {
+        this.reload = reload;
+    }
+
+    public Servlet getServlet()
+        throws ServletException, IOException, FileNotFoundException
+    {
+        if (reload) {
+            synchronized (this) {
+                // Synchronizing on jsw enables simultaneous loading
+                // of different pages, but not the same page.
+                if (reload) {
+                    // This is to maintain the original protocol.
+                    destroy();
+                    
+                    try {
+                        servletClass = ctxt.load();
+                        theServlet = (Servlet) servletClass.newInstance();
+                    } catch( IllegalAccessException ex1 ) {
+                        throw new JasperException( ex1 );
+                    } catch( InstantiationException ex ) {
+                        throw new JasperException( ex );
+                    }
+                    
+                    theServlet.init(config);
+
+                    if (!firstTime) {
+                        ctxt.getRuntimeContext().incrementJspReloadCount();
+                    }
+
+                    reload = false;
+                }
+            }    
+        }
+        return theServlet;
+    }
+
+    public ServletContext getServletContext() {
+        return config.getServletContext();
+    }
+
+    /**
+     * Sets the compilation exception for this JspServletWrapper.
+     *
+     * @param je The compilation exception
+     */
+    public void setCompilationException(JasperException je) {
+        this.compileException = je;
+    }
+
+    /**
+     * Sets the last-modified time of the servlet class file associated with
+     * this JspServletWrapper.
+     *
+     * @param lastModified Last-modified time of servlet class
+     */
+    public void setServletClassLastModifiedTime(long lastModified) {
+        if (this.servletClassLastModifiedTime < lastModified) {
+            synchronized (this) {
+                if (this.servletClassLastModifiedTime < lastModified) {
+                    this.servletClassLastModifiedTime = lastModified;
+                    reload = true;
+                }
+            }
+        }
+    }
+
+    /**
+     * Compile (if needed) and load a tag file
+     */
+    public Class loadTagFile() throws JasperException {
+
+        try {
+            if (ctxt.isRemoved()) {
+                throw new FileNotFoundException(jspUri);
+            }
+            if (options.getDevelopment() || firstTime ) {
+                synchronized (this) {
+                    firstTime = false;
+                    ctxt.compile();
+                }
+            } else {
+                if (compileException != null) {
+                    throw compileException;
+                }
+            }
+
+            if (reload) {
+                tagHandlerClass = ctxt.load();
+                reload = false;
+            }
+        } catch (FileNotFoundException ex) {
+            throw new JasperException(ex);
+	}
+
+	return tagHandlerClass;
+    }
+
+    /**
+     * Compile and load a prototype for the Tag file.  This is needed
+     * when compiling tag files with circular dependencies.  A prototpe
+     * (skeleton) with no dependencies on other other tag files is
+     * generated and compiled.
+     */
+    public Class loadTagFilePrototype() throws JasperException {
+
+	ctxt.setPrototypeMode(true);
+	try {
+	    return loadTagFile();
+	} finally {
+	    ctxt.setPrototypeMode(false);
+	}
+    }
+
+    /**
+     * Get a list of files that the current page has source dependency on.
+     */
+    public java.util.List getDependants() {
+	try {
+	    Object target;
+	    if (isTagFile) {
+                if (reload) {
+                    tagHandlerClass = ctxt.load();
+                    reload = false;
+                }
+		target = tagHandlerClass.newInstance();
+	    } else {
+		target = getServlet();
+	    }
+	    if (target != null && target instanceof JspSourceDependent) {
+            return ((java.util.List) ((JspSourceDependent) target).getDependants());
+	    }
+	} catch (Throwable ex) {
+	}
+	return null;
+    }
+
+    public boolean isTagFile() {
+	return this.isTagFile;
+    }
+
+    public int incTripCount() {
+	return tripCount++;
+    }
+
+    public int decTripCount() {
+	return tripCount--;
+    }
+
+    public void service(HttpServletRequest request, 
+                        HttpServletResponse response,
+                        boolean precompile)
+	    throws ServletException, IOException, FileNotFoundException {
+        try {
+
+            if (ctxt.isRemoved()) {
+                throw new FileNotFoundException(jspUri);
+            }
+
+            if ((available > 0L) && (available < Long.MAX_VALUE)) {
+                response.setDateHeader("Retry-After", available);
+                response.sendError
+                    (HttpServletResponse.SC_SERVICE_UNAVAILABLE,
+                     Localizer.getMessage("jsp.error.unavailable"));
+            }
+
+            /*
+             * (1) Compile
+             */
+            if (options.getDevelopment() || firstTime ) {
+                synchronized (this) {
+                    firstTime = false;
+
+                    // The following sets reload to true, if necessary
+                    ctxt.compile();
+                }
+            } else {
+                if (compileException != null) {
+                    // Throw cached compilation exception
+                    throw compileException;
+                }
+            }
+
+            /*
+             * (2) (Re)load servlet class file
+             */
+            getServlet();
+
+            // If a page is to be precompiled only, return.
+            if (precompile) {
+                return;
+            }
+
+            /*
+             * (3) Service request
+             */
+            if (theServlet instanceof SingleThreadModel) {
+               // sync on the wrapper so that the freshness
+               // of the page is determined right before servicing
+               synchronized (this) {
+                   theServlet.service(request, response);
+                }
+            } else {
+                theServlet.service(request, response);
+            }
+
+        } catch (UnavailableException ex) {
+            String includeRequestUri = (String)
+                request.getAttribute("javax.servlet.include.request_uri");
+            if (includeRequestUri != null) {
+                // This file was included. Throw an exception as
+                // a response.sendError() will be ignored by the
+                // servlet engine.
+                throw ex;
+            } else {
+                int unavailableSeconds = ex.getUnavailableSeconds();
+                if (unavailableSeconds <= 0) {
+                    unavailableSeconds = 60;        // Arbitrary default
+                }
+                available = System.currentTimeMillis() +
+                    (unavailableSeconds * 1000L);
+                response.sendError
+                    (HttpServletResponse.SC_SERVICE_UNAVAILABLE, 
+                     ex.getMessage());
+            }
+        } catch (FileNotFoundException ex) {
+            ctxt.incrementRemoved();
+            String includeRequestUri = (String)
+                request.getAttribute("javax.servlet.include.request_uri");
+            if (includeRequestUri != null) {
+                // This file was included. Throw an exception as
+                // a response.sendError() will be ignored by the
+                // servlet engine.
+                throw new ServletException(ex);
+            } else {
+                try {
+                    response.sendError(HttpServletResponse.SC_NOT_FOUND, 
+                                      ex.getMessage());
+                } catch (IllegalStateException ise) {
+                    log.error(Localizer.getMessage("jsp.error.file.not.found",
+						   ex.getMessage()),
+			      ex);
+                }
+            }
+        } catch (ServletException ex) {
+            if(options.getDevelopment()) {
+                throw handleJspException(ex);
+            } else {
+                throw ex;
+            }
+        } catch (IOException ex) {
+            if(options.getDevelopment()) {
+                throw handleJspException(ex);
+            } else {
+                throw ex;
+            }
+        } catch (IllegalStateException ex) {
+            if(options.getDevelopment()) {
+                throw handleJspException(ex);
+            } else {
+                throw ex;
+            }
+        } catch (Exception ex) {
+            if(options.getDevelopment()) {
+                throw handleJspException(ex);
+            } else {
+                throw new JasperException(ex);
+            }
+        }
+    }
+
+    public void destroy() {
+        if (theServlet != null) {
+            theServlet.destroy();
+        }
+    }
+
+    /**
+     * @return Returns the lastModificationTest.
+     */
+    public long getLastModificationTest() {
+        return lastModificationTest;
+    }
+    /**
+     * @param lastModificationTest The lastModificationTest to set.
+     */
+    public void setLastModificationTest(long lastModificationTest) {
+        this.lastModificationTest = lastModificationTest;
+    }
+
+    /**
+     * <p>Attempts to construct a JasperException that contains helpful information
+     * about what went wrong. Uses the JSP compiler system to translate the line
+     * number in the generated servlet that originated the exception to a line
+     * number in the JSP.  Then constructs an exception containing that
+     * information, and a snippet of the JSP to help debugging.
+     * Please see http://issues.apache.org/bugzilla/show_bug.cgi?id=37062 and
+     * http://www.tfenne.com/jasper/ for more details.
+     *</p>
+     *
+     * @param ex the exception that was the cause of the problem.
+     * @return a JasperException with more detailed information
+     */
+    protected JasperException handleJspException(Exception ex) {
+        try {
+            Throwable realException = ex;
+            if (ex instanceof ServletException) {
+                realException = ((ServletException) ex).getRootCause();
+            }
+
+            // First identify the stack frame in the trace that represents the JSP
+            StackTraceElement[] frames = realException.getStackTrace();
+            StackTraceElement jspFrame = null;
+
+            for (int i=0; i<frames.length; ++i) {
+                if ( frames[i].getClassName().equals(this.getServlet().getClass().getName()) ) {
+                    jspFrame = frames[i];
+                    break;
+                }
+            }
+
+            if (jspFrame == null) {
+                // If we couldn't find a frame in the stack trace corresponding
+                // to the generated servlet class, we can't really add anything
+                return new JasperException(ex);
+            }
+            else {
+                int javaLineNumber = jspFrame.getLineNumber();
+                JavacErrorDetail detail = ErrorDispatcher.createJavacError(
+                                                                           jspFrame.getMethodName(),
+                                                                           this.ctxt.getCompiler().getPageNodes(),
+                                                                           null,
+                                                                           javaLineNumber);
+
+                // If the line number is less than one we couldn't find out
+                // where in the JSP things went wrong
+                int jspLineNumber = detail.getJspBeginLineNumber();
+                if (jspLineNumber < 1) {
+                    throw new JasperException(ex);
+                }
+
+                // Read both files in, so we can inspect them
+                String[] jspLines = readFile
+                    (this.ctxt.getResourceAsStream(this.ctxt.getJspFile()));
+
+                String[] javaLines = readFile
+                    (new FileInputStream(this.ctxt.getServletJavaFileName()));
+
+                // If the line contains the opening of a multi-line scriptlet
+                // block, then the JSP line number we got back is probably
+                // faulty.  Scan forward to match the java line...
+                if (jspLines[jspLineNumber-1].lastIndexOf("<%") >
+                    jspLines[jspLineNumber-1].lastIndexOf("%>")) {
+                    String javaLine = javaLines[javaLineNumber-1].trim();
+
+                    for (int i=jspLineNumber-1; i<jspLines.length; i++) {
+                        if (jspLines[i].indexOf(javaLine) != -1) {
+                            jspLineNumber = i+1;
+                            break;
+                        }
+                    }
+                }
+
+                // copy out a fragment of JSP to display to the user
+                StringBuffer buffer = new StringBuffer(1024);
+                int startIndex = Math.max(0, jspLineNumber-1-3);
+                int endIndex = Math.min(jspLines.length-1, jspLineNumber-1+3);
+
+                for (int i=startIndex;i<=endIndex; ++i) {
+                    buffer.append(i+1);
+                    buffer.append(": ");
+                    buffer.append(jspLines[i]);
+                    buffer.append("\n");
+                }
+
+                return new JasperException(
+                                           "Exception in JSP: " + detail.getJspFileName() + ":" +
+                                           jspLineNumber + "\n\n" + buffer + "\n\nStacktrace:", ex);
+            }
+        } catch (Exception je) {
+            // If anything goes wrong, just revert to the original behaviour
+            return new JasperException(ex);
+        }
+    }
+
+    /**
+     * Reads a text file from an input stream into a String[]. Used to read in
+     * the JSP and generated Java file when generating error messages.
+     */
+    private String[] readFile(InputStream s) throws IOException {
+        BufferedReader reader = new BufferedReader(new InputStreamReader(s));
+        List lines = new ArrayList();
+        String line;
+
+        while ( (line = reader.readLine()) != null ) {
+            lines.add(line);
+        }
+
+        return (String[]) lines.toArray( new String[lines.size()] );
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/servlet/mbeans-descriptors.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/servlet/mbeans-descriptors.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/servlet/mbeans-descriptors.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,20 @@
+<?xml version="1.0"?>
+<mbeans-descriptors>
+
+  <mbean         name="JspMonitor"
+          description="JSP Monitoring"
+               domain="Catalina"
+                group="Monitoring"
+                 type="org.apache.jasper.servlet.JspServlet">
+
+    <attribute   name="jspCount"
+          description="The number of JSPs that have been loaded into a webapp"
+                 type="int"/>
+
+    <attribute   name="jspReloadCount"
+          description="The number of JSPs that have been reloaded"
+                 type="int"/>
+
+  </mbean>
+
+</mbeans-descriptors>

Added: branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/tagplugins/jstl/Util.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/tagplugins/jstl/Util.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/tagplugins/jstl/Util.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,325 @@
+/*
+ * Copyright 1999,2005 The Apache Software Foundation.
+ * 
+ * Licensed 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.tagplugins.jstl;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.io.UnsupportedEncodingException;
+import java.util.Locale;
+
+import javax.servlet.ServletOutputStream;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpServletResponseWrapper;
+import javax.servlet.jsp.JspException;
+import javax.servlet.jsp.JspTagException;
+import javax.servlet.jsp.PageContext;
+
+/**
+ * Util contains some often used consts, static methods and embedded class
+ * to support the JSTL tag plugin.
+ */
+
+public class Util {
+    
+    public static final String VALID_SCHEME_CHAR = 
+        "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+.-";
+    
+    public static final String DEFAULT_ENCODING = 
+        "ISO-8859-1";
+    
+    public static final int HIGHEST_SPECIAL = '>';
+    
+    public static char[][] specialCharactersRepresentation = new char[HIGHEST_SPECIAL + 1][];
+    
+    static {
+        specialCharactersRepresentation['&'] = "&amp;".toCharArray();
+        specialCharactersRepresentation['<'] = "&lt;".toCharArray();
+        specialCharactersRepresentation['>'] = "&gt;".toCharArray();
+        specialCharactersRepresentation['"'] = "&#034;".toCharArray();
+        specialCharactersRepresentation['\''] = "&#039;".toCharArray();
+    }
+    
+    /**
+     * Converts the given string description of a scope to the corresponding
+     * PageContext constant.
+     *
+     * The validity of the given scope has already been checked by the
+     * appropriate TLV.
+     *
+     * @param scope String description of scope
+     *
+     * @return PageContext constant corresponding to given scope description
+     * 
+     * taken from org.apache.taglibs.standard.tag.common.core.Util  
+     */
+    public static int getScope(String scope){
+        int ret = PageContext.PAGE_SCOPE;
+        
+        if("request".equalsIgnoreCase(scope)){
+            ret = PageContext.REQUEST_SCOPE;
+        }else if("session".equalsIgnoreCase(scope)){
+            ret = PageContext.SESSION_SCOPE;
+        }else if("application".equalsIgnoreCase(scope)){
+            ret = PageContext.APPLICATION_SCOPE;
+        }
+        
+        return ret;
+    }
+    
+    /**
+     * Returns <tt>true</tt> if our current URL is absolute,
+     * <tt>false</tt> otherwise.
+     * taken from org.apache.taglibs.standard.tag.common.core.ImportSupport
+     */
+    public static boolean isAbsoluteUrl(String url){
+        if(url == null){
+            return false;
+        }
+        
+        int colonPos = url.indexOf(":");
+        if(colonPos == -1){
+            return false;
+        }
+        
+        for(int i=0;i<colonPos;i++){
+            if(VALID_SCHEME_CHAR.indexOf(url.charAt(i)) == -1){
+                return false;
+            }
+        }
+        
+        return true;
+    }
+    
+    /**
+     * Get the value associated with a content-type attribute.
+     * Syntax defined in RFC 2045, section 5.1.
+     * taken from org.apache.taglibs.standard.tag.common.core.Util
+     */
+    public static String getContentTypeAttribute(String input, String name) {
+        int begin;
+        int end;
+        int index = input.toUpperCase().indexOf(name.toUpperCase());
+        if (index == -1) return null;
+        index = index + name.length(); // positioned after the attribute name
+        index = input.indexOf('=', index); // positioned at the '='
+        if (index == -1) return null;
+        index += 1; // positioned after the '='
+        input = input.substring(index).trim();
+        
+        if (input.charAt(0) == '"') {
+            // attribute value is a quoted string
+            begin = 1;
+            end = input.indexOf('"', begin);
+            if (end == -1) return null;
+        } else {
+            begin = 0;
+            end = input.indexOf(';');
+            if (end == -1) end = input.indexOf(' ');
+            if (end == -1) end = input.length();
+        }
+        return input.substring(begin, end).trim();
+    }
+    
+    /**
+     * Strips a servlet session ID from <tt>url</tt>.  The session ID
+     * is encoded as a URL "path parameter" beginning with "jsessionid=".
+     * We thus remove anything we find between ";jsessionid=" (inclusive)
+     * and either EOS or a subsequent ';' (exclusive).
+     * 
+     * taken from org.apache.taglibs.standard.tag.common.core.ImportSupport
+     */
+    public static String stripSession(String url) {
+        StringBuffer u = new StringBuffer(url);
+        int sessionStart;
+        while ((sessionStart = u.toString().indexOf(";jsessionid=")) != -1) {
+            int sessionEnd = u.toString().indexOf(";", sessionStart + 1);
+            if (sessionEnd == -1)
+                sessionEnd = u.toString().indexOf("?", sessionStart + 1);
+            if (sessionEnd == -1) 				// still
+                sessionEnd = u.length();
+            u.delete(sessionStart, sessionEnd);
+        }
+        return u.toString();
+    }
+    
+    
+    /**
+     * Performs the following substring replacements
+     * (to facilitate output to XML/HTML pages):
+     *
+     *    & -> &amp;
+     *    < -> &lt;
+     *    > -> &gt;
+     *    " -> &#034;
+     *    ' -> &#039;
+     *
+     * See also OutSupport.writeEscapedXml().
+     * 
+     * taken from org.apache.taglibs.standard.tag.common.core.Util
+     */
+    public static String escapeXml(String buffer) {
+        int start = 0;
+        int length = buffer.length();
+        char[] arrayBuffer = buffer.toCharArray();
+        StringBuffer escapedBuffer = null;
+        
+        for (int i = 0; i < length; i++) {
+            char c = arrayBuffer[i];
+            if (c <= HIGHEST_SPECIAL) {
+                char[] escaped = specialCharactersRepresentation[c];
+                if (escaped != null) {
+                    // create StringBuffer to hold escaped xml string
+                    if (start == 0) {
+                        escapedBuffer = new StringBuffer(length + 5);
+                    }
+                    // add unescaped portion
+                    if (start < i) {
+                        escapedBuffer.append(arrayBuffer,start,i-start);
+                    }
+                    start = i + 1;
+                    // add escaped xml
+                    escapedBuffer.append(escaped);
+                }
+            }
+        }
+        // no xml escaping was necessary
+        if (start == 0) {
+            return buffer;
+        }
+        // add rest of unescaped portion
+        if (start < length) {
+            escapedBuffer.append(arrayBuffer,start,length-start);
+        }
+        return escapedBuffer.toString();
+    }
+    
+    /** Utility methods
+     * taken from org.apache.taglibs.standard.tag.common.core.UrlSupport
+     */
+    public static String resolveUrl(
+            String url, String context, PageContext pageContext)
+    throws JspException {
+        // don't touch absolute URLs
+        if (isAbsoluteUrl(url))
+            return url;
+        
+        // normalize relative URLs against a context root
+        HttpServletRequest request =
+            (HttpServletRequest) pageContext.getRequest();
+        if (context == null) {
+            if (url.startsWith("/"))
+                return (request.getContextPath() + url);
+            else
+                return url;
+        } else {
+            if (!context.startsWith("/") || !url.startsWith("/")) {
+                throw new JspTagException(
+                "In URL tags, when the \"context\" attribute is specified, values of both \"context\" and \"url\" must start with \"/\".");
+            }
+            if (context.equals("/")) {
+                // Don't produce string starting with '//', many
+                // browsers interpret this as host name, not as
+                // path on same host.
+                return url;
+            } else {
+                return (context + url);
+            }
+        }
+    }
+    
+    /** Wraps responses to allow us to retrieve results as Strings. 
+     * mainly taken from org.apache.taglibs.standard.tag.common.core.importSupport 
+     */
+    public static class ImportResponseWrapper extends HttpServletResponseWrapper{
+        
+        private StringWriter sw = new StringWriter();
+        private ByteArrayOutputStream bos = new ByteArrayOutputStream();
+        private ServletOutputStream sos = new ServletOutputStream() {
+            public void write(int b) throws IOException {
+                bos.write(b);
+            }
+        };
+        private boolean isWriterUsed;
+        private boolean isStreamUsed;
+        private int status = 200;
+        private String charEncoding;
+        
+        public ImportResponseWrapper(HttpServletResponse arg0) {
+            super(arg0);
+            // TODO Auto-generated constructor stub
+        }
+        
+        public PrintWriter getWriter() {
+            if (isStreamUsed)
+                throw new IllegalStateException("Unexpected internal error during &lt;import&gt: " +
+                "Target servlet called getWriter(), then getOutputStream()");
+            isWriterUsed = true;
+            return new PrintWriter(sw);
+        }
+        
+        public ServletOutputStream getOutputStream() {
+            if (isWriterUsed)
+                throw new IllegalStateException("Unexpected internal error during &lt;import&gt: " +
+                "Target servlet called getOutputStream(), then getWriter()");
+            isStreamUsed = true;
+            return sos;
+        }
+        
+        /** Has no effect. */
+        public void setContentType(String x) {
+            // ignore
+        }
+        
+        /** Has no effect. */
+        public void setLocale(Locale x) {
+            // ignore
+        }
+        
+        public void setStatus(int status) {
+            this.status = status;
+        }
+        
+        public int getStatus() {
+            return status;
+        }
+        
+        public String getCharEncoding(){
+            return this.charEncoding;
+        }
+        
+        public void setCharEncoding(String ce){
+            this.charEncoding = ce;
+        }
+        
+        public String getString() throws UnsupportedEncodingException {
+            if (isWriterUsed)
+                return sw.toString();
+            else if (isStreamUsed) {
+                if (this.charEncoding != null && !this.charEncoding.equals(""))
+                    return bos.toString(charEncoding);
+                else
+                    return bos.toString("ISO-8859-1");
+            } else
+                return "";		// target didn't write anything
+        }
+    }
+    
+}

Added: branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/tagplugins/jstl/core/Catch.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/tagplugins/jstl/core/Catch.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/tagplugins/jstl/core/Catch.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,71 @@
+/*
+ * Copyright 1999,2005 The Apache Software Foundation.
+ * 
+ * Licensed 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.tagplugins.jstl.core;
+
+import org.apache.jasper.compiler.tagplugin.TagPlugin;
+import org.apache.jasper.compiler.tagplugin.TagPluginContext;
+
+public class Catch implements TagPlugin {
+    
+    public void doTag(TagPluginContext ctxt) {
+        
+        //flag for the existence of the var attribute
+        boolean hasVar = ctxt.isAttributeSpecified("var");
+        
+        //temp name for exception and caught
+        String exceptionName = ctxt.getTemporaryVariableName();
+        String caughtName = ctxt.getTemporaryVariableName();
+        
+        //main part to generate code
+        ctxt.generateJavaSource("boolean " + caughtName + " = false;");
+        ctxt.generateJavaSource("try{");
+        ctxt.generateBody();
+        ctxt.generateJavaSource("}");
+        
+        //do catch
+        ctxt.generateJavaSource("catch(Throwable " + exceptionName + "){");
+        
+        //if the var specified, the exception object should 
+        //be set to the attribute "var" defines in page scope 
+        if(hasVar){
+            String strVar = ctxt.getConstantAttribute("var");
+            ctxt.generateJavaSource("    pageContext.setAttribute(\"" + strVar + "\", " 
+                    + exceptionName + ", PageContext.PAGE_SCOPE);");
+        }
+        
+        //whenever there's exception caught, 
+        //the flag caught should be set true;
+        ctxt.generateJavaSource("    " + caughtName + " = true;");
+        ctxt.generateJavaSource("}");
+        
+        //do finally
+        ctxt.generateJavaSource("finally{");
+        
+        //if var specified, the attribute it defines 
+        //in page scope should be removed
+        if(hasVar){
+            String strVar = ctxt.getConstantAttribute("var");
+            ctxt.generateJavaSource("    if(!" + caughtName + "){");
+            ctxt.generateJavaSource("        pageContext.removeAttribute(\"" + strVar + "\", PageContext.PAGE_SCOPE);");
+            ctxt.generateJavaSource("    }");
+        }
+        
+        ctxt.generateJavaSource("}");
+    }
+    
+}

Added: branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/tagplugins/jstl/core/Choose.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/tagplugins/jstl/core/Choose.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/tagplugins/jstl/core/Choose.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,33 @@
+/*
+ * Copyright 1999,2005 The Apache Software Foundation.
+ * 
+ * Licensed 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.tagplugins.jstl.core;
+
+import org.apache.jasper.compiler.tagplugin.*;
+
+public final class Choose implements TagPlugin {
+    
+    public void doTag(TagPluginContext ctxt) {
+        
+        // Not much to do here, much of the work will be done in the
+        // containing tags, <c:when> and <c:otherwise>.
+        
+        ctxt.generateBody();
+        // See comments in When.java for the reason "}" is generated here.
+        ctxt.generateJavaSource("}");
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/tagplugins/jstl/core/ForEach.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/tagplugins/jstl/core/ForEach.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/tagplugins/jstl/core/ForEach.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,343 @@
+/*
+ * Copyright 1999,2005 The Apache Software Foundation.
+ * 
+ * Licensed 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.tagplugins.jstl.core;
+
+import org.apache.jasper.compiler.tagplugin.*;
+
+public final class ForEach implements TagPlugin {
+    
+    private boolean hasVar, hasBegin, hasEnd, hasStep;
+    
+    public void doTag(TagPluginContext ctxt) {
+        
+        String index = null;
+        
+        boolean hasVarStatus = ctxt.isAttributeSpecified("varStatus");
+        if (hasVarStatus) {
+            ctxt.dontUseTagPlugin();
+            return;
+        }
+        
+        hasVar = ctxt.isAttributeSpecified("var");
+        hasBegin = ctxt.isAttributeSpecified("begin");
+        hasEnd = ctxt.isAttributeSpecified("end");
+        hasStep = ctxt.isAttributeSpecified("step");
+        
+        boolean hasItems = ctxt.isAttributeSpecified("items");
+        if (hasItems) {
+            doCollection(ctxt);
+            return;
+        }
+        
+        // We must have a begin and end attributes
+        index = ctxt.getTemporaryVariableName();
+        ctxt.generateJavaSource("for (int " + index + " = ");
+        ctxt.generateAttribute("begin");
+        ctxt.generateJavaSource("; " + index + " <= ");
+        ctxt.generateAttribute("end");
+        if (hasStep) {
+            ctxt.generateJavaSource("; " + index + "+=");
+            ctxt.generateAttribute("step");
+            ctxt.generateJavaSource(") {");
+        }
+        else {
+            ctxt.generateJavaSource("; " + index + "++) {");
+        }
+        
+        // If var is specified and the body contains an EL, then sycn
+        // the var attribute
+        if (hasVar /* && ctxt.hasEL() */) {
+            ctxt.generateJavaSource("_jspx_page_context.setAttribute(");
+            ctxt.generateAttribute("var");
+            ctxt.generateJavaSource(", String.valueOf(" + index + "));");
+        }
+        ctxt.generateBody();
+        ctxt.generateJavaSource("}");
+    }
+    
+    /**
+     * Generate codes for Collections
+     * The pseudo code is:
+     */
+    private void doCollection(TagPluginContext ctxt) {
+        
+        ctxt.generateImport("java.util.*");
+        generateIterators(ctxt);
+        
+        String itemsV = ctxt.getTemporaryVariableName();
+        ctxt.generateJavaSource("Object " + itemsV + "= ");
+        ctxt.generateAttribute("items");
+        ctxt.generateJavaSource(";");
+        
+        String indexV=null, beginV=null, endV=null, stepV=null;
+        if (hasBegin) {
+            beginV = ctxt.getTemporaryVariableName();
+            ctxt.generateJavaSource("int " + beginV + " = ");
+            ctxt.generateAttribute("begin");
+            ctxt.generateJavaSource(";");
+        }
+        if (hasEnd) {
+            indexV = ctxt.getTemporaryVariableName();
+            ctxt.generateJavaSource("int " + indexV + " = 0;");
+            endV = ctxt.getTemporaryVariableName();
+            ctxt.generateJavaSource("int " + endV + " = ");
+            ctxt.generateAttribute("end");
+            ctxt.generateJavaSource(";");
+        }
+        if (hasStep) {
+            stepV = ctxt.getTemporaryVariableName();
+            ctxt.generateJavaSource("int " + stepV + " = ");
+            ctxt.generateAttribute("step");
+            ctxt.generateJavaSource(";");
+        }
+        
+        String iterV = ctxt.getTemporaryVariableName();
+        ctxt.generateJavaSource("Iterator " + iterV + " = null;");
+        // Object[]
+        ctxt.generateJavaSource("if (" + itemsV + " instanceof Object[])");
+        ctxt.generateJavaSource(iterV + "=toIterator((Object[])" + itemsV + ");");
+        // boolean[]
+        ctxt.generateJavaSource("else if (" + itemsV + " instanceof boolean[])");
+        ctxt.generateJavaSource(iterV + "=toIterator((boolean[])" + itemsV + ");");
+        // byte[]
+        ctxt.generateJavaSource("else if (" + itemsV + " instanceof byte[])");
+        ctxt.generateJavaSource(iterV + "=toIterator((byte[])" + itemsV + ");");
+        // char[]
+        ctxt.generateJavaSource("else if (" + itemsV + " instanceof char[])");
+        ctxt.generateJavaSource(iterV + "=toIterator((char[])" + itemsV + ");");
+        // short[]
+        ctxt.generateJavaSource("else if (" + itemsV + " instanceof short[])");
+        ctxt.generateJavaSource(iterV + "=toIterator((short[])" + itemsV + ");");
+        // int[]
+        ctxt.generateJavaSource("else if (" + itemsV + " instanceof int[])");
+        ctxt.generateJavaSource(iterV + "=toIterator((int[])" + itemsV + ");");
+        // long[]
+        ctxt.generateJavaSource("else if (" + itemsV + " instanceof long[])");
+        ctxt.generateJavaSource(iterV + "=toIterator((long[])" + itemsV + ");");
+        // float[]
+        ctxt.generateJavaSource("else if (" + itemsV + " instanceof float[])");
+        ctxt.generateJavaSource(iterV + "=toIterator((float[])" + itemsV + ");");
+        // double[]
+        ctxt.generateJavaSource("else if (" + itemsV + " instanceof double[])");
+        ctxt.generateJavaSource(iterV + "=toIterator((double[])" + itemsV + ");");
+        
+        // Collection
+        ctxt.generateJavaSource("else if (" + itemsV + " instanceof Collection)");
+        ctxt.generateJavaSource(iterV + "=((Collection)" + itemsV + ").iterator();");
+        
+        // Iterator
+        ctxt.generateJavaSource("else if (" + itemsV + " instanceof Iterator)");
+        ctxt.generateJavaSource(iterV + "=(Iterator)" + itemsV + ";");
+        
+        // Enumeration
+        ctxt.generateJavaSource("else if (" + itemsV + " instanceof Enumeration)");
+        ctxt.generateJavaSource(iterV + "=toIterator((Enumeration)" + itemsV + ");");
+        
+        // Map
+        ctxt.generateJavaSource("else if (" + itemsV + " instanceof Map)");
+        ctxt.generateJavaSource(iterV + "=((Map)" + itemsV + ").entrySet().iterator();");
+        
+        if (hasBegin) {
+            String tV = ctxt.getTemporaryVariableName();
+            ctxt.generateJavaSource("for (int " + tV + "=" + beginV + ";" +
+                    tV + ">0 && " + iterV + ".hasNext(); " +
+                    tV + "--)");
+            ctxt.generateJavaSource(iterV + ".next();");
+        }
+        
+        ctxt.generateJavaSource("while (" + iterV + ".hasNext()){");
+        if (hasVar) {
+            ctxt.generateJavaSource("_jspx_page_context.setAttribute(");
+            ctxt.generateAttribute("var");
+            ctxt.generateJavaSource(", " + iterV + ".next());");
+        }
+        
+        ctxt.generateBody();
+        
+        if (hasStep) {
+            String tV = ctxt.getTemporaryVariableName();
+            ctxt.generateJavaSource("for (int " + tV + "=" + stepV + "-1;" +
+                    tV + ">0 && " + iterV + ".hasNext(); " +
+                    tV + "--)");
+            ctxt.generateJavaSource(iterV + ".next();");
+        }
+        if (hasEnd) {
+            if (hasStep) {
+                ctxt.generateJavaSource(indexV + "+=" + stepV + ";");
+            }
+            else {
+                ctxt.generateJavaSource(indexV + "++;");
+            }
+            if (hasBegin) {
+                ctxt.generateJavaSource("if(" + beginV + "+" + indexV +
+                        ">"+ endV + ")");
+            }
+            else {
+                ctxt.generateJavaSource("if(" + indexV + ">" + endV + ")");
+            }
+            ctxt.generateJavaSource("break;");
+        }
+        ctxt.generateJavaSource("}");	// while
+    }
+    
+    /**
+     * Generate iterators for data types supported in items
+     */
+    private void generateIterators(TagPluginContext ctxt) {
+        
+        // Object[]
+        ctxt.generateDeclaration("ObjectArrayIterator", 
+                "private Iterator toIterator(final Object[] a){\n" +
+                "  return (new Iterator() {\n" +
+                "    int index=0;\n" +
+                "    public boolean hasNext() {\n" +
+                "      return index < a.length;}\n" +
+                "    public Object next() {\n" +
+                "      return a[index++];}\n" +
+                "    public void remove() {}\n" +
+                "  });\n" +
+                "}"
+        );
+        
+        // boolean[]
+        ctxt.generateDeclaration("booleanArrayIterator", 
+                "private Iterator toIterator(final boolean[] a){\n" +
+                "  return (new Iterator() {\n" +
+                "    int index=0;\n" +
+                "    public boolean hasNext() {\n" +
+                "      return index < a.length;}\n" +
+                "    public Object next() {\n" +
+                "      return new Boolean(a[index++]);}\n" +
+                "    public void remove() {}\n" +
+                "  });\n" +
+                "}"
+        );
+        
+        // byte[]
+        ctxt.generateDeclaration("byteArrayIterator", 
+                "private Iterator toIterator(final byte[] a){\n" +
+                "  return (new Iterator() {\n" +
+                "    int index=0;\n" +
+                "    public boolean hasNext() {\n" +
+                "      return index < a.length;}\n" +
+                "    public Object next() {\n" +
+                "      return new Byte(a[index++]);}\n" +
+                "    public void remove() {}\n" +
+                "  });\n" +
+                "}"
+        );
+        
+        // char[]
+        ctxt.generateDeclaration("charArrayIterator", 
+                "private Iterator toIterator(final char[] a){\n" +
+                "  return (new Iterator() {\n" +
+                "    int index=0;\n" +
+                "    public boolean hasNext() {\n" +
+                "      return index < a.length;}\n" +
+                "    public Object next() {\n" +
+                "      return new Character(a[index++]);}\n" +
+                "    public void remove() {}\n" +
+                "  });\n" +
+                "}"
+        );
+        
+        // short[]
+        ctxt.generateDeclaration("shortArrayIterator", 
+                "private Iterator toIterator(final short[] a){\n" +
+                "  return (new Iterator() {\n" +
+                "    int index=0;\n" +
+                "    public boolean hasNext() {\n" +
+                "      return index < a.length;}\n" +
+                "    public Object next() {\n" +
+                "      return new Short(a[index++]);}\n" +
+                "    public void remove() {}\n" +
+                "  });\n" +
+                "}"
+        );
+        
+        // int[]
+        ctxt.generateDeclaration("intArrayIterator", 
+                "private Iterator toIterator(final int[] a){\n" +
+                "  return (new Iterator() {\n" +
+                "    int index=0;\n" +
+                "    public boolean hasNext() {\n" +
+                "      return index < a.length;}\n" +
+                "    public Object next() {\n" +
+                "      return new Integer(a[index++]);}\n" +
+                "    public void remove() {}\n" +
+                "  });\n" +
+                "}"
+        );
+        
+        // long[]
+        ctxt.generateDeclaration("longArrayIterator", 
+                "private Iterator toIterator(final long[] a){\n" +
+                "  return (new Iterator() {\n" +
+                "    int index=0;\n" +
+                "    public boolean hasNext() {\n" +
+                "      return index < a.length;}\n" +
+                "    public Object next() {\n" +
+                "      return new Long(a[index++]);}\n" +
+                "    public void remove() {}\n" +
+                "  });\n" +
+                "}"
+        );
+        
+        // float[]
+        ctxt.generateDeclaration("floatArrayIterator",
+                "private Iterator toIterator(final float[] a){\n" +
+                "  return (new Iterator() {\n" +
+                "    int index=0;\n" +
+                "    public boolean hasNext() {\n" +
+                "      return index < a.length;}\n" +
+                "    public Object next() {\n" +
+                "      return new Float(a[index++]);}\n" +
+                "    public void remove() {}\n" +
+                "  });\n" +
+                "}"
+        );
+        
+        // double[]
+        ctxt.generateDeclaration("doubleArrayIterator",
+                "private Iterator toIterator(final double[] a){\n" +
+                "  return (new Iterator() {\n" +
+                "    int index=0;\n" +
+                "    public boolean hasNext() {\n" +
+                "      return index < a.length;}\n" +
+                "    public Object next() {\n" +
+                "      return new Double(a[index++]);}\n" +
+                "    public void remove() {}\n" +
+                "  });\n" +
+                "}"
+        );
+        
+        // Enumeration
+        ctxt.generateDeclaration("enumIterator",
+                "private Iterator toIterator(final Enumeration e){\n" +
+                "  return (new Iterator() {\n" +
+                "    public boolean hasNext() {\n" +
+                "      return e.hasMoreElements();}\n" +
+                "    public Object next() {\n" +
+                "      return e.nextElement();}\n" +
+                "    public void remove() {}\n" +
+                "  });\n" +
+                "}"
+        );
+        
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/tagplugins/jstl/core/ForTokens.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/tagplugins/jstl/core/ForTokens.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/tagplugins/jstl/core/ForTokens.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,118 @@
+/*
+ * Copyright 1999,2005 The Apache Software Foundation.
+ * 
+ * Licensed 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.tagplugins.jstl.core;
+
+import org.apache.jasper.compiler.tagplugin.TagPlugin;
+import org.apache.jasper.compiler.tagplugin.TagPluginContext;
+
+public class ForTokens implements TagPlugin {
+    
+    public void doTag(TagPluginContext ctxt) {
+        boolean hasVar, hasVarStatus, hasBegin, hasEnd, hasStep;
+        
+        //init the flags
+        hasVar = ctxt.isAttributeSpecified("var");
+        hasVarStatus = ctxt.isAttributeSpecified("varStatus");
+        hasBegin = ctxt.isAttributeSpecified("begin");
+        hasEnd = ctxt.isAttributeSpecified("end");
+        hasStep = ctxt.isAttributeSpecified("step");
+        
+        if(hasVarStatus){
+            ctxt.dontUseTagPlugin();
+            return;
+        }
+        
+        //define all the temp variables' names
+        String itemsName = ctxt.getTemporaryVariableName();
+        String delimsName = ctxt.getTemporaryVariableName();
+        String stName = ctxt.getTemporaryVariableName();
+        String beginName = ctxt.getTemporaryVariableName();
+        String endName  = ctxt.getTemporaryVariableName();
+        String stepName = ctxt.getTemporaryVariableName();
+        String index = ctxt.getTemporaryVariableName();
+        String temp  = ctxt.getTemporaryVariableName();
+        String tokensCountName = ctxt.getTemporaryVariableName();
+        
+        //get the value of the "items" attribute 
+        ctxt.generateJavaSource("String " + itemsName + " = (String)");
+        ctxt.generateAttribute("items");
+        ctxt.generateJavaSource(";");
+        
+        //get the value of the "delim" attribute
+        ctxt.generateJavaSource("String " + delimsName + " = (String)");
+        ctxt.generateAttribute("delims");
+        ctxt.generateJavaSource(";");
+        
+        //new a StringTokenizer Object according to the "items" and the "delim"
+        ctxt.generateJavaSource("java.util.StringTokenizer " + stName + " = " +
+                "new java.util.StringTokenizer(" + itemsName + ", " + delimsName + ");");
+        
+        //if "begin" specified, move the token to the "begin" place
+        //and record the begin index. default begin place is 0.
+        ctxt.generateJavaSource("int " + tokensCountName + " = " + stName + ".countTokens();");
+        if(hasBegin){
+            ctxt.generateJavaSource("int " + beginName + " = "  );
+            ctxt.generateAttribute("begin");
+            ctxt.generateJavaSource(";");
+            ctxt.generateJavaSource("for(int " + index + " = 0; " + index + " < " + beginName + " && " + stName + ".hasMoreTokens(); " + index + "++, " + stName + ".nextToken()){}");
+        }else{
+            ctxt.generateJavaSource("int " + beginName + " = 0;");
+        }
+        
+        //when "end" is specified, if the "end" is more than the last index,
+        //record the end place as the last index, otherwise, record it as "end";
+        //default end place is the last index 
+        if(hasEnd){
+            ctxt.generateJavaSource("int " + endName + " = 0;"  );
+            ctxt.generateJavaSource("if((" + tokensCountName + " - 1) < ");
+            ctxt.generateAttribute("end");
+            ctxt.generateJavaSource("){");
+            ctxt.generateJavaSource("    " + endName + " = " + tokensCountName + " - 1;");
+            ctxt.generateJavaSource("}else{");
+            ctxt.generateJavaSource("    " + endName + " = ");
+            ctxt.generateAttribute("end");
+            ctxt.generateJavaSource(";}");
+        }else{
+            ctxt.generateJavaSource("int " + endName + " = " + tokensCountName + " - 1;");
+        }
+        
+        //get the step value from "step" if specified.
+        //default step value is 1.
+        if(hasStep){
+            ctxt.generateJavaSource("int " + stepName + " = "  );
+            ctxt.generateAttribute("step");
+            ctxt.generateJavaSource(";");
+        }else{
+            ctxt.generateJavaSource("int " + stepName + " = 1;");
+        }
+        
+        //the loop
+        ctxt.generateJavaSource("for(int " + index + " = " + beginName + "; " + index + " <= " + endName + "; " + index + "++){");
+        ctxt.generateJavaSource("    String " + temp + " = " + stName + ".nextToken();");
+        ctxt.generateJavaSource("    if(((" + index + " - " + beginName + ") % " + stepName + ") == 0){");
+        //if var specified, put the current token into the attribute "var" defines.
+        if(hasVar){
+            String strVar = ctxt.getConstantAttribute("var");
+            ctxt.generateJavaSource("        pageContext.setAttribute(\"" + strVar + "\", " + temp + ");");
+        }
+        ctxt.generateBody();
+        ctxt.generateJavaSource("    }");
+        ctxt.generateJavaSource("}");
+    }
+    
+}

Added: branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/tagplugins/jstl/core/If.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/tagplugins/jstl/core/If.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/tagplugins/jstl/core/If.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,49 @@
+/*
+ * Copyright 1999,2005 The Apache Software Foundation.
+ * 
+ * Licensed 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.tagplugins.jstl.core;
+
+import org.apache.jasper.compiler.tagplugin.*;
+
+public final class If implements TagPlugin {
+    
+    public void doTag(TagPluginContext ctxt) {
+        String condV = ctxt.getTemporaryVariableName();
+        ctxt.generateJavaSource("boolean " + condV + "=");
+        ctxt.generateAttribute("test");
+        ctxt.generateJavaSource(";");
+        if (ctxt.isAttributeSpecified("var")) {
+            String scope = "PageContext.PAGE_SCOPE";
+            if (ctxt.isAttributeSpecified("scope")) {
+                String scopeStr = ctxt.getConstantAttribute("scope");
+                if ("request".equals(scopeStr)) {
+                    scope = "PageContext.REQUEST_SCOPE";
+                } else if ("session".equals(scopeStr)) {
+                    scope = "PageContext.SESSION_SCOPE";
+                } else if ("application".equals(scopeStr)) {
+                    scope = "PageContext.APPLICATION_SCOPE";
+                }
+            }
+            ctxt.generateJavaSource("_jspx_page_context.setAttribute(");
+            ctxt.generateAttribute("var");
+            ctxt.generateJavaSource(", new Boolean(" + condV + ")," + scope + ");");
+        }
+        ctxt.generateJavaSource("if (" + condV + "){");
+        ctxt.generateBody();
+        ctxt.generateJavaSource("}");
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/tagplugins/jstl/core/Import.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/tagplugins/jstl/core/Import.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/tagplugins/jstl/core/Import.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,381 @@
+/*
+ * Copyright 1999,2005 The Apache Software Foundation.
+ * 
+ * Licensed 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.tagplugins.jstl.core;
+
+import org.apache.jasper.compiler.tagplugin.TagPlugin;
+import org.apache.jasper.compiler.tagplugin.TagPluginContext;
+import org.apache.jasper.tagplugins.jstl.Util;
+
+public class Import implements TagPlugin {
+    
+    public void doTag(TagPluginContext ctxt) {
+        boolean hasContext, hasVar, hasScope, hasVarReader, hasCharEncoding;
+        
+        //flags
+        hasContext  = ctxt.isAttributeSpecified("context");
+        hasVar = ctxt.isAttributeSpecified("var");
+        hasScope = ctxt.isAttributeSpecified("scope");
+        hasVarReader = ctxt.isAttributeSpecified("varReader");
+        hasCharEncoding = ctxt.isAttributeSpecified("charEncoding");
+        
+        //variables' names
+        String urlName = ctxt.getTemporaryVariableName();           
+        String contextName = ctxt.getTemporaryVariableName();       
+        String iauName = ctxt.getTemporaryVariableName();           // is absolute url
+        String urlObjName = ctxt.getTemporaryVariableName();        //URL object
+        String ucName = ctxt.getTemporaryVariableName();            //URLConnection
+        String inputStreamName = ctxt.getTemporaryVariableName();   
+        String tempReaderName = ctxt.getTemporaryVariableName();
+        String tempReaderName2 = ctxt.getTemporaryVariableName();
+        String charSetName = ctxt.getTemporaryVariableName();
+        String charEncodingName = ctxt.getTemporaryVariableName();
+        String contentTypeName = ctxt.getTemporaryVariableName();
+        String varReaderName = ctxt.getTemporaryVariableName();
+        String servletContextName = ctxt.getTemporaryVariableName();
+        String servletPathName = ctxt.getTemporaryVariableName();
+        String requestDispatcherName = ctxt.getTemporaryVariableName();
+        String irwName = ctxt.getTemporaryVariableName();           //ImportResponseWrapper name
+        String brName = ctxt.getTemporaryVariableName();            //BufferedReader name
+        String sbName = ctxt.getTemporaryVariableName();            //StringBuffer name
+        String tempStringName = ctxt.getTemporaryVariableName();
+        
+        //is absolute url
+        ctxt.generateJavaSource("boolean " + iauName + ";");
+        
+        //get the url value
+        ctxt.generateJavaSource("String " + urlName + " = ");
+        ctxt.generateAttribute("url");
+        ctxt.generateJavaSource(";");
+        
+        //validate the url
+        ctxt.generateJavaSource("if(" + urlName + " == null || " + urlName + ".equals(\"\")){");
+        ctxt.generateJavaSource("    throw new JspTagException(\"The \\\"url\\\" attribute " +
+        "illegally evaluated to \\\"null\\\" or \\\"\\\" in &lt;import&gt;\");");
+        ctxt.generateJavaSource("}");
+        
+        //initialize the is_absolute_url
+        ctxt.generateJavaSource(iauName + " = " +
+                "org.apache.jasper.tagplugins.jstl.Util.isAbsoluteUrl(" + urlName + ");");
+        
+        //validate the context
+        if(hasContext){
+            
+            ctxt.generateJavaSource("String " + contextName + " = ");
+            ctxt.generateAttribute("context");
+            ctxt.generateJavaSource(";");
+            
+            ctxt.generateJavaSource("if((!" + contextName + ".startsWith(\"/\")) " +
+                    "|| (!" + urlName + ".startsWith(\"/\"))){");
+            ctxt.generateJavaSource("    throw new JspTagException" +
+                    "(\"In URL tags, when the \\\"context\\\" attribute is specified, " +
+            "values of both \\\"context\\\" and \\\"url\\\" must start with \\\"/\\\".\");");
+            ctxt.generateJavaSource("}");
+            
+        }
+        
+        //define charset
+        ctxt.generateJavaSource("String " + charSetName + " = null;");
+        
+        //if the charEncoding attribute is specified
+        if(hasCharEncoding){
+            
+            //initialize the charEncoding
+            ctxt.generateJavaSource("String " + charEncodingName + " = ");
+            ctxt.generateAttribute("charEncoding");
+            ctxt.generateJavaSource(";");
+            
+            //assign appropriate value tp the charset
+            ctxt.generateJavaSource("if(null != " + charEncodingName + " " +
+                    "&& !" + charEncodingName + ".equals(\"\")){");
+            ctxt.generateJavaSource("    " + charSetName + " = " 
+                    + charEncodingName + ";");
+            ctxt.generateJavaSource("}");
+        }
+        
+        //reshape the url string
+        ctxt.generateJavaSource("if(!"+iauName+"){");
+        ctxt.generateJavaSource("    if(!" + urlName + ".startsWith(\"/\")){");
+        ctxt.generateJavaSource("        String " + servletPathName + " = " +
+        "((HttpServletRequest)pageContext.getRequest()).getServletPath();");
+        ctxt.generateJavaSource("        " + urlName + " = " 
+                + servletPathName + ".substring(0," + servletPathName + ".lastIndexOf('/')) + '/' + " + urlName + ";");
+        ctxt.generateJavaSource("    }");
+        ctxt.generateJavaSource("}");
+        
+        //if the varReader attribute specified
+        if(hasVarReader){
+            
+            //get the String value of varReader
+            ctxt.generateJavaSource("String " + varReaderName + " = ");
+            ctxt.generateAttribute("varReader");
+            ctxt.generateJavaSource(";");
+            
+            //if the url is absolute url
+            ctxt.generateJavaSource("if(" + iauName + "){");
+            
+            //get the content of the target
+            ctxt.generateJavaSource("    java.net.URL " + urlObjName + " = new java.net.URL(" + urlName + ");");
+            ctxt.generateJavaSource("    java.net.URLConnection " + ucName + " = " 
+                    + urlObjName + ".openConnection();");
+            ctxt.generateJavaSource("    java.io.InputStream " + inputStreamName + " = " 
+                    + ucName + ".getInputStream();");
+            
+            ctxt.generateJavaSource("    if(" + charSetName + " == null){");
+            ctxt.generateJavaSource("        String " + contentTypeName + " = " 
+                    + ucName + ".getContentType();");
+            ctxt.generateJavaSource("        if(null != " + contentTypeName + "){");
+            ctxt.generateJavaSource("            " + charSetName + " = " +
+                    "org.apache.jasper.tagplugins.jstl.Util.getContentTypeAttribute(" + contentTypeName + ", \"charset\");");
+            ctxt.generateJavaSource("            if(" + charSetName + " == null) " 
+                    + charSetName + " = org.apache.jasper.tagplugins.jstl.Util.DEFAULT_ENCODING;");
+            ctxt.generateJavaSource("        }else{");
+            ctxt.generateJavaSource("            " + charSetName + " = org.apache.jasper.tagplugins.jstl.Util.DEFAULT_ENCODING;");
+            ctxt.generateJavaSource("        }");
+            ctxt.generateJavaSource("    }");
+            
+            if(!hasCharEncoding){
+                ctxt.generateJavaSource("    String " + contentTypeName + " = " + ucName + ".getContentType();");
+            }
+            
+            //define the Reader
+            ctxt.generateJavaSource("    java.io.Reader " + tempReaderName + " = null;");
+            
+            //initialize the Reader object
+            ctxt.generateJavaSource("    try{");
+            ctxt.generateJavaSource("        " + tempReaderName + " = new java.io.InputStreamReader(" + inputStreamName + ", " + charSetName + ");");
+            ctxt.generateJavaSource("    }catch(Exception ex){");
+            ctxt.generateJavaSource("        " + tempReaderName + " = new java.io.InputStreamReader(" + inputStreamName + ", org.apache.jasper.tagplugins.jstl.Util.DEFAULT_ENCODING);");
+            ctxt.generateJavaSource("    }");
+            
+            //validate the response
+            ctxt.generateJavaSource("    if(" + ucName + " instanceof java.net.HttpURLConnection){");
+            ctxt.generateJavaSource("        int status = ((java.net.HttpURLConnection) " + ucName + ").getResponseCode();");
+            ctxt.generateJavaSource("        if(status < 200 || status > 299){");
+            ctxt.generateJavaSource("            throw new JspTagException(status + \" \" + " + urlName + ");");
+            ctxt.generateJavaSource("        }");
+            ctxt.generateJavaSource("    }");
+            
+            //set attribute in the page context scope
+            ctxt.generateJavaSource("    pageContext.setAttribute(" + varReaderName + ", " + tempReaderName + ");");
+            
+            //if the url is relative
+            ctxt.generateJavaSource("}else{");
+            
+            //if the url is relative, http request is needed
+            ctxt.generateJavaSource("    if (!(pageContext.getRequest() instanceof HttpServletRequest  " +
+            "&& pageContext.getResponse() instanceof HttpServletResponse)){");
+            ctxt.generateJavaSource("        throw new JspTagException(\"Relative &lt;import&gt; from non-HTTP request not allowed\");");
+            ctxt.generateJavaSource("    }");
+            
+            //get the servlet context of the context defined in the context attribute
+            ctxt.generateJavaSource("    ServletContext " + servletContextName + " = null;");
+            if(hasContext){
+                ctxt.generateJavaSource("    if(null != " + contextName + "){");
+                ctxt.generateJavaSource("        " + servletContextName + " = pageContext.getServletContext().getContext(" + contextName + ");" );
+                ctxt.generateJavaSource("    }else{");
+                ctxt.generateJavaSource("        " + servletContextName + " = pageContext.getServletContext();");
+                ctxt.generateJavaSource("    }");
+            }else{
+                ctxt.generateJavaSource("    " + servletContextName + " = pageContext.getServletContext();");
+            }
+            
+            //
+            ctxt.generateJavaSource("    if(" + servletContextName + " == null){");
+            if(hasContext){
+                ctxt.generateJavaSource("        throw new JspTagException(\"Unable to get RequestDispatcher for Context: \\\" \"+" + contextName + "+\" \\\" and URL: \\\" \" +" + urlName + "+ \" \\\". Verify values and/or enable cross context access.\");");
+            }else{
+                ctxt.generateJavaSource("        throw new JspTagException(\"Unable to get RequestDispatcher for  URL: \\\" \" +" + urlName + "+ \" \\\". Verify values and/or enable cross context access.\");");
+            }
+            ctxt.generateJavaSource("    }");
+            
+            //get the request dispatcher
+            ctxt.generateJavaSource("    RequestDispatcher " + requestDispatcherName + " = " + servletContextName + ".getRequestDispatcher(org.apache.jasper.tagplugins.jstl.Util.stripSession("+urlName+"));");
+            ctxt.generateJavaSource("    if(" + requestDispatcherName + " == null) throw new JspTagException(org.apache.jasper.tagplugins.jstl.Util.stripSession("+urlName+"));");
+            
+            //initialize a ImportResponseWrapper to include the resource
+            ctxt.generateJavaSource("    org.apache.jasper.tagplugins.jstl.Util.ImportResponseWrapper " + irwName + " = new org.apache.jasper.tagplugins.jstl.Util.ImportResponseWrapper((HttpServletResponse) pageContext.getResponse());");
+            ctxt.generateJavaSource("    if(" + charSetName + " == null){");
+            ctxt.generateJavaSource("        " + charSetName + " = org.apache.jasper.tagplugins.jstl.Util.DEFAULT_ENCODING;");
+            ctxt.generateJavaSource("    }");
+            ctxt.generateJavaSource("    " + irwName + ".setCharEncoding(" + charSetName + ");");
+            ctxt.generateJavaSource("    try{");
+            ctxt.generateJavaSource("        " + requestDispatcherName + ".include(pageContext.getRequest(), " + irwName + ");");
+            ctxt.generateJavaSource("    }catch(java.io.IOException ex){");
+            ctxt.generateJavaSource("        throw new JspException(ex);");
+            ctxt.generateJavaSource("    }catch(RuntimeException ex){");
+            ctxt.generateJavaSource("        throw new JspException(ex);");
+            ctxt.generateJavaSource("    }catch(ServletException ex){");
+            ctxt.generateJavaSource("        Throwable rc = ex.getRootCause();");
+            ctxt.generateJavaSource("        if (rc == null)");
+            ctxt.generateJavaSource("            throw new JspException(ex);");
+            ctxt.generateJavaSource("        else");
+            ctxt.generateJavaSource("            throw new JspException(rc);");
+            ctxt.generateJavaSource("    }");
+            
+            //validate the response status
+            ctxt.generateJavaSource("    if(" + irwName + ".getStatus() < 200 || " + irwName + ".getStatus() > 299){");
+            ctxt.generateJavaSource("        throw new JspTagException(" + irwName + ".getStatus()+\" \" + org.apache.jasper.tagplugins.jstl.Util.stripSession(" + urlName + "));");
+            ctxt.generateJavaSource("    }");
+            
+            //push in the page context
+            ctxt.generateJavaSource("    java.io.Reader " + tempReaderName + " = new java.io.StringReader(" + irwName + ".getString());");
+            ctxt.generateJavaSource("    pageContext.setAttribute(" + varReaderName + ", " + tempReaderName + ");");
+            
+            ctxt.generateJavaSource("}");
+            
+            //execute the body action
+            ctxt.generateBody();
+            
+            //close the reader
+            ctxt.generateJavaSource("java.io.Reader " + tempReaderName2 + " = (java.io.Reader)pageContext.getAttribute(" + varReaderName + ");");
+            ctxt.generateJavaSource("if(" + tempReaderName2 + " != null) " + tempReaderName2 + ".close();");
+            ctxt.generateJavaSource("pageContext.removeAttribute(" + varReaderName + ",1);");
+        }
+        
+        //if the varReader is not specified 
+        else{
+            
+            ctxt.generateJavaSource("pageContext.setAttribute(\"url_without_param\"," + urlName + ");");
+            ctxt.generateBody();
+            ctxt.generateJavaSource(urlName + " = (String)pageContext.getAttribute(\"url_without_param\");");
+            ctxt.generateJavaSource("pageContext.removeAttribute(\"url_without_param\");");
+            String strScope = "page";
+            if(hasScope){
+                strScope = ctxt.getConstantAttribute("scope");
+            }
+            int iScope = Util.getScope(strScope);
+            
+            ctxt.generateJavaSource("String " + tempStringName + " = null;");
+            
+            ctxt.generateJavaSource("if(" + iauName + "){");
+            
+            //get the content of the target
+            ctxt.generateJavaSource("    java.net.URL " + urlObjName + " = new java.net.URL(" + urlName + ");");
+            ctxt.generateJavaSource("    java.net.URLConnection " + ucName + " = " + urlObjName + ".openConnection();");
+            ctxt.generateJavaSource("    java.io.InputStream " + inputStreamName + " = " + ucName + ".getInputStream();");
+            ctxt.generateJavaSource("    java.io.Reader " + tempReaderName + " = null;");
+            
+            ctxt.generateJavaSource("    if(" + charSetName + " == null){");
+            ctxt.generateJavaSource("        String " + contentTypeName + " = " 
+                    + ucName + ".getContentType();");
+            ctxt.generateJavaSource("        if(null != " + contentTypeName + "){");
+            ctxt.generateJavaSource("            " + charSetName + " = " +
+                    "org.apache.jasper.tagplugins.jstl.Util.getContentTypeAttribute(" + contentTypeName + ", \"charset\");");
+            ctxt.generateJavaSource("            if(" + charSetName + " == null) " 
+                    + charSetName + " = org.apache.jasper.tagplugins.jstl.Util.DEFAULT_ENCODING;");
+            ctxt.generateJavaSource("        }else{");
+            ctxt.generateJavaSource("            " + charSetName + " = org.apache.jasper.tagplugins.jstl.Util.DEFAULT_ENCODING;");
+            ctxt.generateJavaSource("        }");
+            ctxt.generateJavaSource("    }");
+            
+            ctxt.generateJavaSource("    try{");
+            ctxt.generateJavaSource("        " + tempReaderName + " = new java.io.InputStreamReader(" + inputStreamName + "," + charSetName + ");");
+            ctxt.generateJavaSource("    }catch(Exception ex){");
+            //ctxt.generateJavaSource("        throw new JspTagException(ex.toString());");
+            ctxt.generateJavaSource("        " + tempReaderName + " = new java.io.InputStreamReader(" + inputStreamName + ",org.apache.jasper.tagplugins.jstl.Util.DEFAULT_ENCODING);");
+            ctxt.generateJavaSource("    }");
+            
+            //validate the response
+            ctxt.generateJavaSource("    if(" + ucName + " instanceof java.net.HttpURLConnection){");
+            ctxt.generateJavaSource("        int status = ((java.net.HttpURLConnection) " + ucName + ").getResponseCode();");
+            ctxt.generateJavaSource("        if(status < 200 || status > 299){");
+            ctxt.generateJavaSource("            throw new JspTagException(status + \" \" + " + urlName + ");");
+            ctxt.generateJavaSource("        }");
+            ctxt.generateJavaSource("    }");
+            
+            ctxt.generateJavaSource("    java.io.BufferedReader " + brName + " =  new java.io.BufferedReader(" + tempReaderName + ");");
+            ctxt.generateJavaSource("    StringBuffer " + sbName + " = new StringBuffer();");
+            String index = ctxt.getTemporaryVariableName();
+            ctxt.generateJavaSource("    int " + index + ";");
+            ctxt.generateJavaSource("    while(("+index+" = "+brName+".read()) != -1) "+sbName+".append((char)"+index+");");
+            ctxt.generateJavaSource("    " + tempStringName + " = " +sbName + ".toString();");
+            
+            ctxt.generateJavaSource("}else{");
+            
+            //if the url is relative, http request is needed.
+            ctxt.generateJavaSource("    if (!(pageContext.getRequest() instanceof HttpServletRequest  " +
+            "&& pageContext.getResponse() instanceof HttpServletResponse)){");
+            ctxt.generateJavaSource("        throw new JspTagException(\"Relative &lt;import&gt; from non-HTTP request not allowed\");");
+            ctxt.generateJavaSource("    }");
+            
+            //get the servlet context of the context defined in the context attribute
+            ctxt.generateJavaSource("    ServletContext " + servletContextName + " = null;");
+            if(hasContext){
+                ctxt.generateJavaSource("    if(null != " + contextName + "){");
+                ctxt.generateJavaSource("        " + servletContextName + " = pageContext.getServletContext().getContext(" + contextName + ");" );
+                ctxt.generateJavaSource("    }else{");
+                ctxt.generateJavaSource("        " + servletContextName + " = pageContext.getServletContext();");
+                ctxt.generateJavaSource("    }");
+            }else{
+                ctxt.generateJavaSource("    " + servletContextName + " = pageContext.getServletContext();");
+            }
+            
+            //
+            ctxt.generateJavaSource("    if(" + servletContextName + " == null){");
+            if(hasContext){
+                ctxt.generateJavaSource("        throw new JspTagException(\"Unable to get RequestDispatcher for Context: \\\" \" +" + contextName + "+ \" \\\" and URL: \\\" \" +" + urlName + "+ \" \\\". Verify values and/or enable cross context access.\");");
+            }else{
+                ctxt.generateJavaSource("        throw new JspTagException(\"Unable to get RequestDispatcher for URL: \\\" \" +" + urlName + "+ \" \\\". Verify values and/or enable cross context access.\");");
+            }
+            ctxt.generateJavaSource("    }");
+            
+            //get the request dispatcher
+            ctxt.generateJavaSource("    RequestDispatcher " + requestDispatcherName + " = " + servletContextName + ".getRequestDispatcher(org.apache.jasper.tagplugins.jstl.Util.stripSession("+urlName+"));");
+            ctxt.generateJavaSource("    if(" + requestDispatcherName + " == null) throw new JspTagException(org.apache.jasper.tagplugins.jstl.Util.stripSession("+urlName+"));");
+            
+            //initialize a ImportResponseWrapper to include the resource
+            ctxt.generateJavaSource("    org.apache.jasper.tagplugins.jstl.Util.ImportResponseWrapper " + irwName + " = new org.apache.jasper.tagplugins.jstl.Util.ImportResponseWrapper((HttpServletResponse) pageContext.getResponse());");
+            ctxt.generateJavaSource("    if(" + charSetName + " == null){");
+            ctxt.generateJavaSource("        " + charSetName + " = org.apache.jasper.tagplugins.jstl.Util.DEFAULT_ENCODING;");
+            ctxt.generateJavaSource("    }");
+            ctxt.generateJavaSource("    " + irwName + ".setCharEncoding(" + charSetName + ");");
+            ctxt.generateJavaSource("    try{");
+            ctxt.generateJavaSource("        " + requestDispatcherName + ".include(pageContext.getRequest(), " + irwName + ");");
+            ctxt.generateJavaSource("    }catch(java.io.IOException ex){");
+            ctxt.generateJavaSource("        throw new JspException(ex);");
+            ctxt.generateJavaSource("    }catch(RuntimeException ex){");
+            ctxt.generateJavaSource("        throw new JspException(ex);");
+            ctxt.generateJavaSource("    }catch(ServletException ex){");
+            ctxt.generateJavaSource("        Throwable rc = ex.getRootCause();");
+            ctxt.generateJavaSource("        if (rc == null)");
+            ctxt.generateJavaSource("            throw new JspException(ex);");
+            ctxt.generateJavaSource("        else");
+            ctxt.generateJavaSource("            throw new JspException(rc);");
+            ctxt.generateJavaSource("    }");
+            
+            //validate the response status
+            ctxt.generateJavaSource("    if(" + irwName + ".getStatus() < 200 || " + irwName + ".getStatus() > 299){");
+            ctxt.generateJavaSource("        throw new JspTagException(" + irwName + ".getStatus()+\" \" + org.apache.jasper.tagplugins.jstl.Util.stripSession(" + urlName + "));");
+            ctxt.generateJavaSource("    }");
+            
+            ctxt.generateJavaSource("    " + tempStringName + " = " + irwName + ".getString();");
+            
+            ctxt.generateJavaSource("}");
+            
+            if(hasVar){
+                String strVar = ctxt.getConstantAttribute("var");
+                ctxt.generateJavaSource("pageContext.setAttribute(\""+strVar+"\"," + tempStringName + "," + iScope + ");");
+            }else{
+                ctxt.generateJavaSource("pageContext.getOut().print(" + tempStringName + ");");
+            }
+        }
+    }
+    
+    
+    
+}

Added: branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/tagplugins/jstl/core/Otherwise.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/tagplugins/jstl/core/Otherwise.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/tagplugins/jstl/core/Otherwise.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,31 @@
+/*
+ * Copyright 1999,2005 The Apache Software Foundation.
+ * 
+ * Licensed 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.tagplugins.jstl.core;
+
+import org.apache.jasper.compiler.tagplugin.*;
+
+public final class Otherwise implements TagPlugin {
+    
+    public void doTag(TagPluginContext ctxt) {
+        
+        // See When.java for the reason whey "}" is need at the beginng and
+        // not at the end.
+        ctxt.generateJavaSource("} else {");
+        ctxt.generateBody();
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/tagplugins/jstl/core/Out.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/tagplugins/jstl/core/Out.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/tagplugins/jstl/core/Out.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,89 @@
+/*
+ * Copyright 1999,2005 The Apache Software Foundation.
+ * 
+ * Licensed 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.tagplugins.jstl.core;
+
+import org.apache.jasper.compiler.tagplugin.TagPlugin;
+import org.apache.jasper.compiler.tagplugin.TagPluginContext;
+
+
+public final class Out implements TagPlugin {
+    
+    public void doTag(TagPluginContext ctxt) {
+        
+        //these two data member are to indicate 
+        //whether the corresponding attribute is specified
+        boolean hasDefault=false, hasEscapeXml=false;
+        hasDefault = ctxt.isAttributeSpecified("default");
+        hasEscapeXml = ctxt.isAttributeSpecified("escapeXml");
+        
+        //strValName, strEscapeXmlName & strDefName are two variables' name 
+        //standing for value, escapeXml and default attribute
+        String strValName = ctxt.getTemporaryVariableName();
+        String strDefName = ctxt.getTemporaryVariableName();
+        String strEscapeXmlName = 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.generateAttribute("value");
+        ctxt.generateJavaSource(").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");
+        if(hasDefault){
+            ctxt.generateJavaSource("if(");
+            ctxt.generateAttribute("default");
+            ctxt.generateJavaSource(" != null){");
+            ctxt.generateJavaSource(strDefName + " = (");
+            ctxt.generateAttribute("default");
+            ctxt.generateJavaSource(").toString();");
+            ctxt.generateJavaSource("}");
+        }
+        
+        //initiate the strEscapeXmlName with true;
+        //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());");
+        }
+        
+        //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.generateBody();
+        ctxt.generateJavaSource("    }");
+        ctxt.generateJavaSource("}");   
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/tagplugins/jstl/core/Param.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/tagplugins/jstl/core/Param.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/tagplugins/jstl/core/Param.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,76 @@
+/*
+ * Copyright 1999,2005 The Apache Software Foundation.
+ * 
+ * Licensed 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.tagplugins.jstl.core;
+
+import org.apache.jasper.compiler.tagplugin.TagPlugin;
+import org.apache.jasper.compiler.tagplugin.TagPluginContext;
+
+public class Param implements TagPlugin {
+    
+    public void doTag(TagPluginContext ctxt) {
+        
+        //don't support the body content
+        
+        //define names of all the temp variables
+        String nameName = ctxt.getTemporaryVariableName();
+        String valueName = ctxt.getTemporaryVariableName();
+        String urlName = ctxt.getTemporaryVariableName();
+        String encName = ctxt.getTemporaryVariableName();
+        String index = ctxt.getTemporaryVariableName();
+        
+        //if the param tag has no parents, throw a exception
+        TagPluginContext parent = ctxt.getParentContext();
+        if(parent == null){
+            ctxt.generateJavaSource(" throw new JspTagExcption" +
+            "(\"&lt;param&gt; outside &lt;import&gt; or &lt;urlEncode&gt;\");");
+            return;
+        }
+        
+        //get the url string before adding this param
+        ctxt.generateJavaSource("String " + urlName + " = " +
+        "(String)pageContext.getAttribute(\"url_without_param\");");
+        
+        //get the value of "name"
+        ctxt.generateJavaSource("String " + nameName + " = ");
+        ctxt.generateAttribute("name");
+        ctxt.generateJavaSource(";");
+        
+        //if the "name" is null then do nothing.
+        //else add such string "name=value" to the url.
+        //and the url should be encoded
+        ctxt.generateJavaSource("if(" + nameName + " != null && !" + nameName + ".equals(\"\")){");
+        ctxt.generateJavaSource("    String " + valueName + " = ");
+        ctxt.generateAttribute("value");
+        ctxt.generateJavaSource(";");
+        ctxt.generateJavaSource("    if(" + valueName + " == null) " + valueName + " = \"\";");
+        ctxt.generateJavaSource("    String " + encName + " = pageContext.getResponse().getCharacterEncoding();");
+        ctxt.generateJavaSource("    " + nameName + " = java.net.URLEncoder.encode(" + nameName + ", " + encName + ");");
+        ctxt.generateJavaSource("    " + valueName + " = java.net.URLEncoder.encode(" + valueName + ", " + encName + ");");
+        ctxt.generateJavaSource("    int " + index + ";");
+        ctxt.generateJavaSource("    " + index + " = " + urlName + ".indexOf(\'?\');");
+        //if the current param is the first one, add a "?" ahead of it
+        //else add a "&" ahead of it
+        ctxt.generateJavaSource("    if(" + index + " == -1){");
+        ctxt.generateJavaSource("        " + urlName + " = " + urlName + " + \"?\" + " + nameName + " + \"=\" + " + valueName + ";");
+        ctxt.generateJavaSource("    }else{");
+        ctxt.generateJavaSource("        " + urlName + " = " + urlName + " + \"&\" + " + nameName + " + \"=\" + " + valueName + ";");
+        ctxt.generateJavaSource("    }");
+        ctxt.generateJavaSource("    pageContext.setAttribute(\"url_without_param\"," + urlName + ");");
+        ctxt.generateJavaSource("}");	
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/tagplugins/jstl/core/Redirect.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/tagplugins/jstl/core/Redirect.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/tagplugins/jstl/core/Redirect.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,82 @@
+/*
+ * Copyright 1999,2005 The Apache Software Foundation.
+ * 
+ * Licensed 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.tagplugins.jstl.core;
+
+import org.apache.jasper.compiler.tagplugin.TagPlugin;
+import org.apache.jasper.compiler.tagplugin.TagPluginContext;
+
+public class Redirect implements TagPlugin {
+    
+    public void doTag(TagPluginContext ctxt) {
+        
+        //flag for the existence of the "context"
+        boolean hasContext = ctxt.isAttributeSpecified("context");
+        
+        //names of the temp variables
+        String urlName = ctxt.getTemporaryVariableName();
+        String contextName = ctxt.getTemporaryVariableName();
+        String baseUrlName = ctxt.getTemporaryVariableName();
+        String resultName = ctxt.getTemporaryVariableName();
+        String responseName = ctxt.getTemporaryVariableName();
+        
+        //get context
+        ctxt.generateJavaSource("String " + contextName + " = null;");
+        if(hasContext){
+            ctxt.generateJavaSource(contextName + " = ");
+            ctxt.generateAttribute("context");
+            ctxt.generateJavaSource(";");
+        }
+        
+        //get the url
+        ctxt.generateJavaSource("String " + urlName + " = ");
+        ctxt.generateAttribute("url");
+        ctxt.generateJavaSource(";");
+        
+        //get the raw url according to "url" and "context"
+        ctxt.generateJavaSource("String " + baseUrlName + " = " +
+                "org.apache.jasper.tagplugins.jstl.Util.resolveUrl(" + urlName + ", " + contextName + ", pageContext);");
+        ctxt.generateJavaSource("pageContext.setAttribute" +
+                "(\"url_without_param\", " + baseUrlName + ");");
+        
+        //add params
+        ctxt.generateBody();
+        
+        ctxt.generateJavaSource("String " + resultName + " = " +
+        "(String)pageContext.getAttribute(\"url_without_param\");");
+        ctxt.generateJavaSource("pageContext.removeAttribute" +
+        "(\"url_without_param\");");
+        
+        //get the response object
+        ctxt.generateJavaSource("HttpServletResponse " + responseName + " = " +
+        "((HttpServletResponse) pageContext.getResponse());");
+        
+        //if the url is relative, encode it
+        ctxt.generateJavaSource("if(!org.apache.jasper.tagplugins.jstl.Util.isAbsoluteUrl(" + resultName + ")){");
+        ctxt.generateJavaSource("    " + resultName + " = "
+                + responseName + ".encodeRedirectURL(" + resultName + ");");
+        ctxt.generateJavaSource("}");
+        
+        //do redirect
+        ctxt.generateJavaSource("try{");
+        ctxt.generateJavaSource("    " + responseName + ".sendRedirect(" + resultName + ");");
+        ctxt.generateJavaSource("}catch(java.io.IOException ex){");
+        ctxt.generateJavaSource("    throw new JspTagException(ex.toString(), ex);");
+        ctxt.generateJavaSource("}");
+    }
+    
+}

Added: branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/tagplugins/jstl/core/Remove.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/tagplugins/jstl/core/Remove.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/tagplugins/jstl/core/Remove.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,44 @@
+/*
+ * Copyright 1999,2005 The Apache Software Foundation.
+ * 
+ * Licensed 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.tagplugins.jstl.core;
+
+import org.apache.jasper.compiler.tagplugin.TagPlugin;
+import org.apache.jasper.compiler.tagplugin.TagPluginContext;
+import org.apache.jasper.tagplugins.jstl.Util;
+
+public class Remove implements TagPlugin {
+    
+    public void doTag(TagPluginContext ctxt) {
+        
+        //scope flag
+        boolean hasScope = ctxt.isAttributeSpecified("scope");
+        
+        //the value of the "var"
+        String strVar = ctxt.getConstantAttribute("var");
+        
+        //remove attribute from certain scope.
+        //default scope is "page".
+        if(hasScope){
+            int iScope = Util.getScope(ctxt.getConstantAttribute("scope"));
+            ctxt.generateJavaSource("pageContext.removeAttribute(\"" + strVar + "\"," + iScope + ");");
+        }else{
+            ctxt.generateJavaSource("pageContext.removeAttribute(\"" + strVar + "\");");
+        }
+    }
+    
+}

Added: branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/tagplugins/jstl/core/Set.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/tagplugins/jstl/core/Set.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/tagplugins/jstl/core/Set.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,166 @@
+/*
+ * Copyright 1999,2005 The Apache Software Foundation.
+ * 
+ * Licensed 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.tagplugins.jstl.core;
+
+import org.apache.jasper.compiler.tagplugin.TagPlugin;
+import org.apache.jasper.compiler.tagplugin.TagPluginContext;
+import org.apache.jasper.tagplugins.jstl.Util;
+
+public class Set implements TagPlugin {
+    
+    public void doTag(TagPluginContext ctxt) {
+        
+        //the flags to indicate whether the attributes have been specified
+        boolean hasValue = false, hasVar = false, hasScope = false, 
+        hasTarget = false;
+        
+        //the scope name
+        String strScope;
+        //the id of the scope
+        int iScope;
+        
+        //initialize the flags
+        hasValue = ctxt.isAttributeSpecified("value");
+        hasVar = ctxt.isAttributeSpecified("var");
+        hasScope = ctxt.isAttributeSpecified("scope");
+        hasTarget = ctxt.isAttributeSpecified("target");
+        
+        //the temp variables name
+        String resultName = ctxt.getTemporaryVariableName();
+        String targetName = ctxt.getTemporaryVariableName();
+        String propertyName = ctxt.getTemporaryVariableName();
+        
+        //initialize the "result" which will be assigned to the var or target.property
+        ctxt.generateJavaSource("Object " + resultName + " = null;");
+        if(hasValue){
+            ctxt.generateJavaSource(resultName + " = ");
+            ctxt.generateAttribute("value");
+            ctxt.generateJavaSource(";");
+        }else{
+            ctxt.dontUseTagPlugin();
+            return;
+        }
+        
+        //initialize the strScope
+        if(hasScope){
+            strScope = ctxt.getConstantAttribute("scope");
+        }else{
+            strScope = "page";
+        }
+        
+        //get the iScope according to the strScope
+        iScope = Util.getScope(strScope);
+        
+        //if the attribute var has been specified then assign the result to the var;
+        if(hasVar){
+            String strVar = ctxt.getConstantAttribute("var");
+            ctxt.generateJavaSource("if(null != " + resultName + "){");
+            ctxt.generateJavaSource("    pageContext.setAttribute(\"" + strVar + "\"," + resultName + "," + iScope + ");");
+            ctxt.generateJavaSource("} else {");
+            if(hasScope){
+                ctxt.generateJavaSource("    pageContext.removeAttribute(\"" + strVar + "\"," + iScope + ");");
+            }else{
+                ctxt.generateJavaSource("    pageContext.removeAttribute(\"" + strVar + "\");");
+            }
+            ctxt.generateJavaSource("}");
+            
+            //else assign the result to the target.property
+        }else if(hasTarget){
+            
+            //generate the temp variable name
+            String pdName = ctxt.getTemporaryVariableName();
+            String successFlagName = ctxt.getTemporaryVariableName();
+            String index = ctxt.getTemporaryVariableName();
+            String methodName = ctxt.getTemporaryVariableName();
+            
+            //initialize the property
+            ctxt.generateJavaSource("String " + propertyName + " = null;");
+            ctxt.generateJavaSource("if(");
+            ctxt.generateAttribute("property");
+            ctxt.generateJavaSource(" != null){");
+            ctxt.generateJavaSource("    " + propertyName + " = (");
+            ctxt.generateAttribute("property");
+            ctxt.generateJavaSource(").toString();");
+            ctxt.generateJavaSource("}");
+            
+            //initialize the target
+            ctxt.generateJavaSource("Object " + targetName + " = ");
+            ctxt.generateAttribute("target");
+            ctxt.generateJavaSource(";");
+            
+            //the target is ok
+            ctxt.generateJavaSource("if(" + targetName + " != null){");
+            
+            //if the target is a map, then put the result into the map with the key property
+            ctxt.generateJavaSource("    if(" + targetName + " instanceof java.util.Map){");
+            ctxt.generateJavaSource("        if(null != " + resultName + "){");
+            ctxt.generateJavaSource("            ((java.util.Map) " + targetName + ").put(" + propertyName + "," + resultName + ");");
+            ctxt.generateJavaSource("        }else{");
+            ctxt.generateJavaSource("            ((java.util.Map) " + targetName + ").remove(" + propertyName + ");");
+            ctxt.generateJavaSource("        }");
+            
+            //else assign the result to the target.property
+            ctxt.generateJavaSource("    }else{");
+            ctxt.generateJavaSource("        try{");
+            
+            //get all the property of the target
+            ctxt.generateJavaSource("            java.beans.PropertyDescriptor " + pdName + "[] = java.beans.Introspector.getBeanInfo(" + targetName + ".getClass()).getPropertyDescriptors();");
+            
+            //the success flag is to imply whether the assign is successful
+            ctxt.generateJavaSource("            boolean " + successFlagName + " = false;");
+            
+            //find the right property
+            ctxt.generateJavaSource("            for(int " + index + "=0;" + index + "<" + pdName + ".length;" + index + "++){");
+            ctxt.generateJavaSource("                if(" + pdName + "[" + index + "].getName().equals(" + propertyName + ")){");
+            
+            //get the "set" method;
+            ctxt.generateJavaSource("                    java.lang.reflect.Method " + methodName + " = " + pdName + "[" + index + "].getWriteMethod();");
+            ctxt.generateJavaSource("                    if(null == " + methodName + "){");
+            ctxt.generateJavaSource("                        throw new JspException(\"No setter method in &lt;set&gt; for property \"+" + propertyName + ");");
+            ctxt.generateJavaSource("                    }");
+            
+            //invoke the method through the reflection
+            ctxt.generateJavaSource("                    if(" + resultName + " != null){");
+            ctxt.generateJavaSource("                        " + methodName + ".invoke(" + targetName + ", new Object[]{(" + methodName + ".getParameterTypes()[0]).cast(" + resultName + ")});");
+            ctxt.generateJavaSource("                    }else{");
+            ctxt.generateJavaSource("                        " + methodName + ".invoke(" + targetName + ", new Object[]{null});");
+            ctxt.generateJavaSource("                    }");
+            ctxt.generateJavaSource("                    " + successFlagName + " = true;");
+            ctxt.generateJavaSource("                }");
+            ctxt.generateJavaSource("            }");
+            ctxt.generateJavaSource("            if(!" + successFlagName + "){");
+            ctxt.generateJavaSource("                throw new JspException(\"Invalid property in &lt;set&gt;:\"+" + propertyName + ");");
+            ctxt.generateJavaSource("            }");
+            ctxt.generateJavaSource("        }");
+            
+            //catch the el exception and throw it as a JspException
+            ctxt.generateJavaSource("        catch (IllegalAccessException ex) {");
+            ctxt.generateJavaSource("            throw new JspException(ex);");
+            ctxt.generateJavaSource("        } catch (java.beans.IntrospectionException ex) {");
+            ctxt.generateJavaSource("            throw new JspException(ex);");
+            ctxt.generateJavaSource("        } catch (java.lang.reflect.InvocationTargetException ex) {");
+            ctxt.generateJavaSource("            throw new JspException(ex);");
+            ctxt.generateJavaSource("        }");
+            ctxt.generateJavaSource("    }");
+            ctxt.generateJavaSource("}else{");
+            ctxt.generateJavaSource("    throw new JspException();");
+            ctxt.generateJavaSource("}");
+        }
+    }
+    
+}

Added: branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/tagplugins/jstl/core/Url.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/tagplugins/jstl/core/Url.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/tagplugins/jstl/core/Url.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,100 @@
+/*
+ * Copyright 1999,2005 The Apache Software Foundation.
+ * 
+ * Licensed 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.tagplugins.jstl.core;
+
+import org.apache.jasper.compiler.tagplugin.TagPlugin;
+import org.apache.jasper.compiler.tagplugin.TagPluginContext;
+import org.apache.jasper.tagplugins.jstl.Util;
+
+public class Url implements TagPlugin {
+    
+    public void doTag(TagPluginContext ctxt) {
+        
+        //flags
+        boolean hasVar, hasContext, hasScope;
+        
+        //init flags
+        hasVar = ctxt.isAttributeSpecified("var");
+        hasContext = ctxt.isAttributeSpecified("context");
+        hasScope = ctxt.isAttributeSpecified("scope");
+        
+        //define name of the temp variables
+        String valueName = ctxt.getTemporaryVariableName();
+        String contextName = ctxt.getTemporaryVariableName();
+        String baseUrlName = ctxt.getTemporaryVariableName();
+        String resultName = ctxt.getTemporaryVariableName();
+        String responseName = ctxt.getTemporaryVariableName();
+        
+        //get the scope
+        String strScope = "page";
+        if(hasScope){
+            strScope = ctxt.getConstantAttribute("scope");
+        }
+        int iScope = Util.getScope(strScope);
+        
+        //get the value
+        ctxt.generateJavaSource("String " + valueName + " = ");
+        ctxt.generateAttribute("value");
+        ctxt.generateJavaSource(";");
+        
+        //get the context
+        ctxt.generateJavaSource("String " + contextName + " = null;");
+        if(hasContext){
+            ctxt.generateJavaSource(contextName + " = ");
+            ctxt.generateAttribute("context");
+            ctxt.generateJavaSource(";");
+        }
+        
+        //get the raw url
+        ctxt.generateJavaSource("String " + baseUrlName + " = " +
+                "org.apache.jasper.tagplugins.jstl.Util.resolveUrl(" + valueName + ", " + contextName + ", pageContext);");
+        ctxt.generateJavaSource("pageContext.setAttribute" +
+                "(\"url_without_param\", " + baseUrlName + ");");
+        
+        //add params
+        ctxt.generateBody();
+        
+        ctxt.generateJavaSource("String " + resultName + " = " +
+        "(String)pageContext.getAttribute(\"url_without_param\");");
+        ctxt.generateJavaSource("pageContext.removeAttribute(\"url_without_param\");");
+        
+        //if the url is relative, encode it
+        ctxt.generateJavaSource("if(!org.apache.jasper.tagplugins.jstl.Util.isAbsoluteUrl(" + resultName + ")){");
+        ctxt.generateJavaSource("    HttpServletResponse " + responseName + " = " +
+        "((HttpServletResponse) pageContext.getResponse());");
+        ctxt.generateJavaSource("    " + resultName + " = "
+                + responseName + ".encodeURL(" + resultName + ");");
+        ctxt.generateJavaSource("}");
+        
+        //if "var" is specified, the url string store in the attribute var defines
+        if(hasVar){
+            String strVar = ctxt.getConstantAttribute("var");
+            ctxt.generateJavaSource("pageContext.setAttribute" +
+                    "(\"" + strVar + "\", " + resultName + ", " + iScope + ");");
+            
+            //if var is not specified, just print out the url string
+        }else{
+            ctxt.generateJavaSource("try{");
+            ctxt.generateJavaSource("    pageContext.getOut().print(" + resultName + ");");
+            ctxt.generateJavaSource("}catch(java.io.IOException ex){");
+            ctxt.generateJavaSource("    throw new JspTagException(ex.toString(), ex);");
+            ctxt.generateJavaSource("}");
+        }
+    }
+    
+}

Added: branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/tagplugins/jstl/core/When.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/tagplugins/jstl/core/When.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/tagplugins/jstl/core/When.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,49 @@
+/*
+ * Copyright 1999,2005 The Apache Software Foundation.
+ * 
+ * Licensed 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.tagplugins.jstl.core;
+
+import org.apache.jasper.compiler.tagplugin.*;
+
+public final class When implements TagPlugin {
+    
+    public void doTag(TagPluginContext ctxt) {
+        // Get the parent context to determine if this is the first <c:when>
+        TagPluginContext parentContext = ctxt.getParentContext();
+        if (parentContext == null) {
+            ctxt.dontUseTagPlugin();
+            return;
+        }
+        
+        if ("true".equals(parentContext.getPluginAttribute("hasBeenHere"))) {
+            ctxt.generateJavaSource("} else if(");
+            // See comment below for the reason we generate the extra "}" here.
+        }
+        else {
+            ctxt.generateJavaSource("if(");
+            parentContext.setPluginAttribute("hasBeenHere", "true");
+        }
+        ctxt.generateAttribute("test");
+        ctxt.generateJavaSource("){");
+        ctxt.generateBody();
+        
+        // We don't generate the closing "}" for the "if" here because there
+        // may be whitespaces in between <c:when>'s.  Instead we delay
+        // generating it until the next <c:when> or <c:otherwise> or
+        // <c:choose>
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/tagplugins/jstl/tagPlugins.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/tagplugins/jstl/tagPlugins.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/tagplugins/jstl/tagPlugins.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,46 @@
+<tag-plugins>
+  <tag-plugin>
+    <tag-class>org.apache.taglibs.standard.tag.rt.core.IfTag</tag-class>
+    <plugin-class>org.apache.jasper.tagplugins.jstl.core.If</plugin-class>
+  </tag-plugin>
+  <tag-plugin>
+    <tag-class>org.apache.taglibs.standard.tag.common.core.ChooseTag</tag-class>
+    <plugin-class>org.apache.jasper.tagplugins.jstl.core.Choose</plugin-class>
+  </tag-plugin>
+  <tag-plugin>
+    <tag-class>org.apache.taglibs.standard.tag.rt.core.WhenTag</tag-class>
+    <plugin-class>org.apache.jasper.tagplugins.jstl.core.When</plugin-class>
+  </tag-plugin>
+  <tag-plugin>
+    <tag-class>org.apache.taglibs.standard.tag.common.core.OtherwiseTag</tag-class>
+    <plugin-class>org.apache.jasper.tagplugins.jstl.core.Otherwise</plugin-class>
+  </tag-plugin>
+  <tag-plugin>
+    <tag-class>org.apache.taglibs.standard.tag.rt.core.ForEachTag</tag-class>
+    <plugin-class>org.apache.jasper.tagplugins.jstl.core.ForEach</plugin-class>
+  </tag-plugin>
+  <tag-plugin>
+  	<tag-class>org.apache.taglibs.standard.tag.rt.core.OutTag</tag-class>
+  	<plugin-class>org.apache.jasper.tagplugins.jstl.core.Out</plugin-class>
+  </tag-plugin>
+  <tag-plugin>
+    <tag-class>org.apache.taglibs.standard.tag.rt.core.SetTag</tag-class>
+    <plugin-class>org.apache.jasper.tagplugins.jstl.core.Set</plugin-class>
+  </tag-plugin>
+  <tag-plugin>
+    <tag-class>org.apache.taglibs.standard.tag.common.core.RemoveTag</tag-class>
+    <plugin-class>org.apache.jasper.tagplugins.jstl.core.Remove</plugin-class>
+  </tag-plugin>
+  <tag-plugin>
+    <tag-class>org.apache.taglibs.standard.tag.common.core.CatchTag</tag-class>
+    <plugin-class>org.apache.jasper.tagplugins.jstl.core.Catch</plugin-class>
+  </tag-plugin>
+  <tag-plugin>
+    <tag-class>org.apache.taglibs.standard.tag.rt.core.ForTokensTag</tag-class>
+    <plugin-class>org.apache.jasper.tagplugins.jstl.core.ForTokens</plugin-class>
+  </tag-plugin>
+  <tag-plugin>
+    <tag-class>org.apache.taglibs.standard.tag.rt.core.ImportTag</tag-class>
+    <plugin-class>org.apache.jasper.tagplugins.jstl.core.Import</plugin-class>
+  </tag-plugin>
+</tag-plugins>

Added: branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/util/FastDateFormat.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/util/FastDateFormat.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/util/FastDateFormat.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,133 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.util;
+
+import java.util.Date;
+
+import java.text.DateFormat;
+import java.text.FieldPosition;
+import java.text.ParsePosition;
+import java.text.SimpleDateFormat;
+
+/**
+ * Fast date formatter that caches recently formatted date information
+ * and uses it to avoid too-frequent calls to the underlying
+ * formatter.  Note: breaks fieldPosition param of format(Date,
+ * StringBuffer, FieldPosition).  If you care about the field
+ * position, call the underlying DateFormat directly.
+ *
+ * @author Stan Bailes
+ * @author Alex Chaffee
+ */
+public class FastDateFormat extends DateFormat {
+
+    private DateFormat df;
+    private long lastSec = -1;
+    private StringBuffer sb = new StringBuffer();
+    private FieldPosition fp = new FieldPosition(DateFormat.MILLISECOND_FIELD);
+    
+    public FastDateFormat(DateFormat df) {
+        this.df = df;
+    }
+
+    public Date parse(String text, ParsePosition pos) {
+	return df.parse(text, pos);
+    }
+
+    /**
+     * Note: breaks functionality of fieldPosition param. Also:
+     * there's a bug in SimpleDateFormat with "S" and "SS", use "SSS"
+     * instead if you want a msec field.
+     */
+    public StringBuffer format(Date date, StringBuffer toAppendTo,
+			       FieldPosition fieldPosition) {
+        long dt = date.getTime();
+        long ds = dt / 1000;
+        if (ds != lastSec) {
+            sb.setLength(0);
+            df.format(date, sb, fp);
+            lastSec = ds;
+        } else {
+	    // munge current msec into existing string
+            int ms = (int)(dt % 1000);
+            int pos = fp.getEndIndex();
+	    int begin = fp.getBeginIndex();
+	    if (pos > 0) {
+		if (pos > begin)
+		    sb.setCharAt(--pos, Character.forDigit(ms % 10, 10));
+		ms /= 10;
+		if (pos > begin)
+		    sb.setCharAt(--pos, Character.forDigit(ms % 10, 10));
+		ms /= 10;
+		if (pos > begin)
+		    sb.setCharAt(--pos, Character.forDigit(ms % 10, 10));
+	    }
+        }
+	toAppendTo.append(sb.toString());
+	return toAppendTo;
+    }
+
+    public static void main(String[] args) {
+	String format = "yyyy-MM-dd HH:mm:ss.SSS";
+	if (args.length > 0)
+	    format = args[0];
+        SimpleDateFormat sdf = new SimpleDateFormat(format);
+        FastDateFormat fdf = new FastDateFormat(sdf);
+        Date d = new Date();
+
+	d.setTime(1);
+	System.out.println(fdf.format(d) + "\t" + sdf.format(d));
+	d.setTime(20);
+	System.out.println(fdf.format(d) + "\t" + sdf.format(d));
+	d.setTime(500);
+	System.out.println(fdf.format(d) + "\t" + sdf.format(d));
+	d.setTime(543);
+	System.out.println(fdf.format(d) + "\t" + sdf.format(d));
+	d.setTime(999);
+	System.out.println(fdf.format(d) + "\t" + sdf.format(d));
+	d.setTime(1050);
+	System.out.println(fdf.format(d) + "\t" + sdf.format(d));
+	d.setTime(2543);
+	System.out.println(fdf.format(d) + "\t" + sdf.format(d));
+	d.setTime(12345);
+	System.out.println(fdf.format(d) + "\t" + sdf.format(d));
+	d.setTime(12340);
+	System.out.println(fdf.format(d) + "\t" + sdf.format(d));
+	
+        final int reps = 100000;
+        {
+            long start = System.currentTimeMillis();
+            for (int i = 0; i < reps; i++) {
+                d.setTime(System.currentTimeMillis());
+                fdf.format(d);
+            }
+            long elap = System.currentTimeMillis() - start;
+            System.out.println("fast: " + elap + " elapsed");
+	    System.out.println(fdf.format(d));
+        }
+        {
+            long start = System.currentTimeMillis();
+            for (int i = 0; i < reps; i++) {
+                d.setTime(System.currentTimeMillis());
+                sdf.format(d);
+            }
+            long elap = System.currentTimeMillis() - start;	    
+            System.out.println("slow: " + elap + " elapsed");
+	    System.out.println(sdf.format(d));
+        }
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/util/Queue.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/util/Queue.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/util/Queue.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,88 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.util;
+
+import java.util.Vector;
+
+/**
+ * A simple FIFO queue class which causes the calling thread to wait
+ * if the queue is empty and notifies threads that are waiting when it
+ * is not empty.
+ *
+ * @author Anil V (akv at eng.sun.com)
+ */
+public class Queue {
+    private Vector vector = new Vector();
+
+    /** 
+     * Put the object into the queue.
+     * 
+     * @param	object		the object to be appended to the
+     * 				queue. 
+     */
+    public synchronized void put(Object object) {
+	vector.addElement(object);
+	notify();
+    }
+    
+    /**
+     * Pull the first object out of the queue. Wait if the queue is
+     * empty.
+     */
+    public synchronized Object pull() {
+	while (isEmpty())
+	    try {
+		wait();
+	    } catch (InterruptedException ex) {
+	    }
+	return get();
+    }
+
+    /**
+     * Get the first object out of the queue. Return null if the queue
+     * is empty. 
+     */
+    public synchronized Object get() {
+	Object object = peek();
+	if (object != null)
+	    vector.removeElementAt(0);
+	return object;
+    }
+
+    /**
+     * Peek to see if something is available.
+     */
+    public Object peek() {
+	if (isEmpty())
+	    return null;
+	return vector.elementAt(0);
+    }
+    
+    /**
+     * Is the queue empty?
+     */
+    public boolean isEmpty() {
+	return vector.isEmpty();
+    }
+
+    /**
+     * How many elements are there in this queue?
+     */
+    public int size() {
+	return vector.size();
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/util/SimplePool.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/util/SimplePool.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/util/SimplePool.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,85 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.util;
+
+/**
+ * Simple object pool. Based on ThreadPool and few other classes
+ *
+ * The pool will ignore overflow and return null if empty.
+ *
+ * @author Gal Shachor
+ * @author Costin
+ */
+public final class SimplePool  {
+
+    private static final int DEFAULT_SIZE=16;
+
+    /*
+     * Where the threads are held.
+     */
+    private Object pool[];
+
+    private int max;
+    private int current=-1;
+
+    private Object lock;
+    
+    public SimplePool() {
+	this.max=DEFAULT_SIZE;
+	this.pool=new Object[max];
+	this.lock=new Object();
+    }
+    
+    public SimplePool(int max) {
+	this.max=max;
+	this.pool=new Object[max];
+	this.lock=new Object();
+    }
+
+    /**
+     * Adds the given object to the pool, and does nothing if the pool is full
+     */
+    public void put(Object o) {
+	synchronized( lock ) {
+	    if( current < (max-1) ) {
+		current += 1;
+		pool[current] = o;
+            }
+	}
+    }
+
+    /**
+     * Get an object from the pool, null if the pool is empty.
+     */
+    public Object get() {
+	Object item = null;
+	synchronized( lock ) {
+	    if( current >= 0 ) {
+		item = pool[current];
+		current -= 1;
+	    }
+	}
+	return item;
+    }
+
+    /**
+     * Return the size of the pool
+     */
+    public int getMax() {
+	return max;
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/util/SystemLogHandler.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/util/SystemLogHandler.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/util/SystemLogHandler.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,221 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.util;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.PrintStream;
+
+
+/**
+ * This helper class may be used to do sophisticated redirection of 
+ * System.out and System.err.
+ * 
+ * @author Remy Maucherat
+ */
+public class SystemLogHandler extends PrintStream {
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Construct the handler to capture the output of the given steam.
+     */
+    public SystemLogHandler(PrintStream wrapped) {
+        super(wrapped);
+        this.wrapped = wrapped;
+    }
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * Wrapped PrintStream.
+     */
+    protected PrintStream wrapped = null;
+
+
+    /**
+     * Thread <-> PrintStream associations.
+     */
+    protected static ThreadLocal streams = new ThreadLocal();
+
+
+    /**
+     * Thread <-> ByteArrayOutputStream associations.
+     */
+    protected static ThreadLocal data = new ThreadLocal();
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    public PrintStream getWrapped() {
+      return wrapped;
+    }
+
+    /**
+     * Start capturing thread's output.
+     */
+    public static void setThread() {
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        data.set(baos);
+        streams.set(new PrintStream(baos));
+    }
+
+
+    /**
+     * Stop capturing thread's output and return captured data as a String.
+     */
+    public static String unsetThread() {
+        ByteArrayOutputStream baos = 
+            (ByteArrayOutputStream) data.get();
+        if (baos == null) {
+            return null;
+        }
+        streams.set(null);
+        data.set(null);
+        return baos.toString();
+    }
+
+
+    // ------------------------------------------------------ Protected Methods
+
+
+    /**
+     * Find PrintStream to which the output must be written to.
+     */
+    protected PrintStream findStream() {
+        PrintStream ps = (PrintStream) streams.get();
+        if (ps == null) {
+            ps = wrapped;
+        }
+        return ps;
+    }
+
+
+    // ---------------------------------------------------- PrintStream Methods
+
+
+    public void flush() {
+        findStream().flush();
+    }
+
+    public void close() {
+        findStream().close();
+    }
+
+    public boolean checkError() {
+        return findStream().checkError();
+    }
+
+    protected void setError() {
+        //findStream().setError();
+    }
+
+    public void write(int b) {
+        findStream().write(b);
+    }
+
+    public void write(byte[] b)
+        throws IOException {
+        findStream().write(b);
+    }
+
+    public void write(byte[] buf, int off, int len) {
+        findStream().write(buf, off, len);
+    }
+
+    public void print(boolean b) {
+        findStream().print(b);
+    }
+
+    public void print(char c) {
+        findStream().print(c);
+    }
+
+    public void print(int i) {
+        findStream().print(i);
+    }
+
+    public void print(long l) {
+        findStream().print(l);
+    }
+
+    public void print(float f) {
+        findStream().print(f);
+    }
+
+    public void print(double d) {
+        findStream().print(d);
+    }
+
+    public void print(char[] s) {
+        findStream().print(s);
+    }
+
+    public void print(String s) {
+        findStream().print(s);
+    }
+
+    public void print(Object obj) {
+        findStream().print(obj);
+    }
+
+    public void println() {
+        findStream().println();
+    }
+
+    public void println(boolean x) {
+        findStream().println(x);
+    }
+
+    public void println(char x) {
+        findStream().println(x);
+    }
+
+    public void println(int x) {
+        findStream().println(x);
+    }
+
+    public void println(long x) {
+        findStream().println(x);
+    }
+
+    public void println(float x) {
+        findStream().println(x);
+    }
+
+    public void println(double x) {
+        findStream().println(x);
+    }
+
+    public void println(char[] x) {
+        findStream().println(x);
+    }
+
+    public void println(String x) {
+        findStream().println(x);
+    }
+
+    public void println(Object x) {
+        findStream().println(x);
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/xmlparser/ASCIIReader.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/xmlparser/ASCIIReader.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/xmlparser/ASCIIReader.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,203 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.xmlparser;
+
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.Reader;
+import org.apache.jasper.compiler.Localizer;
+
+/**
+ * A simple ASCII byte reader. This is an optimized reader for reading
+ * byte streams that only contain 7-bit ASCII characters.
+ *
+ * @author Andy Clark, IBM
+ *
+ * @version $Id: ASCIIReader.java 305933 2004-03-17 19:23:05Z luehe $
+ */
+public class ASCIIReader
+    extends Reader {
+
+    //
+    // Constants
+    //
+
+    /** Default byte buffer size (2048). */
+    public static final int DEFAULT_BUFFER_SIZE = 2048;
+
+    //
+    // Data
+    //
+
+    /** Input stream. */
+    protected InputStream fInputStream;
+
+    /** Byte buffer. */
+    protected byte[] fBuffer;
+
+    //
+    // Constructors
+    //
+
+    /** 
+     * Constructs an ASCII reader from the specified input stream 
+     * and buffer size.
+     *
+     * @param inputStream The input stream.
+     * @param size        The initial buffer size.
+     */
+    public ASCIIReader(InputStream inputStream, int size) {
+        fInputStream = inputStream;
+        fBuffer = new byte[size];
+    }
+
+    //
+    // Reader methods
+    //
+
+    /**
+     * Read a single character.  This method will block until a character is
+     * available, an I/O error occurs, or the end of the stream is reached.
+     *
+     * <p> Subclasses that intend to support efficient single-character input
+     * should override this method.
+     *
+     * @return     The character read, as an integer in the range 0 to 127
+     *             (<tt>0x00-0x7f</tt>), or -1 if the end of the stream has
+     *             been reached
+     *
+     * @exception  IOException  If an I/O error occurs
+     */
+    public int read() throws IOException {
+        int b0 = fInputStream.read();
+        if (b0 > 0x80) {
+            throw new IOException(Localizer.getMessage("jsp.error.xml.invalidASCII",
+						       Integer.toString(b0)));
+        }
+        return b0;
+    } // read():int
+
+    /**
+     * Read characters into a portion of an array.  This method will block
+     * until some input is available, an I/O error occurs, or the end of the
+     * stream is reached.
+     *
+     * @param      ch     Destination buffer
+     * @param      offset Offset at which to start storing characters
+     * @param      length Maximum number of characters to read
+     *
+     * @return     The number of characters read, or -1 if the end of the
+     *             stream has been reached
+     *
+     * @exception  IOException  If an I/O error occurs
+     */
+    public int read(char ch[], int offset, int length) throws IOException {
+        if (length > fBuffer.length) {
+            length = fBuffer.length;
+        }
+        int count = fInputStream.read(fBuffer, 0, length);
+        for (int i = 0; i < count; i++) {
+            int b0 = fBuffer[i];
+            if (b0 > 0x80) {
+                throw new IOException(Localizer.getMessage("jsp.error.xml.invalidASCII",
+							   Integer.toString(b0)));
+            }
+            ch[offset + i] = (char)b0;
+        }
+        return count;
+    } // read(char[],int,int)
+
+    /**
+     * Skip characters.  This method will block until some characters are
+     * available, an I/O error occurs, or the end of the stream is reached.
+     *
+     * @param  n  The number of characters to skip
+     *
+     * @return    The number of characters actually skipped
+     *
+     * @exception  IOException  If an I/O error occurs
+     */
+    public long skip(long n) throws IOException {
+        return fInputStream.skip(n);
+    } // skip(long):long
+
+    /**
+     * Tell whether this stream is ready to be read.
+     *
+     * @return True if the next read() is guaranteed not to block for input,
+     * false otherwise.  Note that returning false does not guarantee that the
+     * next read will block.
+     *
+     * @exception  IOException  If an I/O error occurs
+     */
+    public boolean ready() throws IOException {
+	return false;
+    } // ready()
+
+    /**
+     * Tell whether this stream supports the mark() operation.
+     */
+    public boolean markSupported() {
+	return fInputStream.markSupported();
+    } // markSupported()
+
+    /**
+     * Mark the present position in the stream.  Subsequent calls to reset()
+     * will attempt to reposition the stream to this point.  Not all
+     * character-input streams support the mark() operation.
+     *
+     * @param  readAheadLimit  Limit on the number of characters that may be
+     *                         read while still preserving the mark.  After
+     *                         reading this many characters, attempting to
+     *                         reset the stream may fail.
+     *
+     * @exception  IOException  If the stream does not support mark(),
+     *                          or if some other I/O error occurs
+     */
+    public void mark(int readAheadLimit) throws IOException {
+	fInputStream.mark(readAheadLimit);
+    } // mark(int)
+
+    /**
+     * Reset the stream.  If the stream has been marked, then attempt to
+     * reposition it at the mark.  If the stream has not been marked, then
+     * attempt to reset it in some way appropriate to the particular stream,
+     * for example by repositioning it to its starting point.  Not all
+     * character-input streams support the reset() operation, and some support
+     * reset() without supporting mark().
+     *
+     * @exception  IOException  If the stream has not been marked,
+     *                          or if the mark has been invalidated,
+     *                          or if the stream does not support reset(),
+     *                          or if some other I/O error occurs
+     */
+    public void reset() throws IOException {
+        fInputStream.reset();
+    } // reset()
+
+    /**
+     * Close the stream.  Once a stream has been closed, further read(),
+     * ready(), mark(), or reset() invocations will throw an IOException.
+     * Closing a previously-closed stream, however, has no effect.
+     *
+     * @exception  IOException  If an I/O error occurs
+     */
+     public void close() throws IOException {
+         fInputStream.close();
+     } // close()
+
+} // class ASCIIReader

Added: branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/xmlparser/EncodingMap.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/xmlparser/EncodingMap.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/xmlparser/EncodingMap.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,1019 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation and was
+ * originally based on software copyright (c) 1999, International
+ * Business Machines, Inc., http://www.apache.org.  For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ */
+
+package org.apache.jasper.xmlparser;
+
+import java.util.Hashtable;
+
+/**
+ * EncodingMap is a convenience class which handles conversions between 
+ * IANA encoding names and Java encoding names, and vice versa. The
+ * encoding names used in XML instance documents <strong>must</strong>
+ * be the IANA encoding names specified or one of the aliases for those names
+ * which IANA defines.
+ * <p>
+ * <TABLE BORDER="0" WIDTH="100%">
+ *  <TR>
+ *      <TD WIDTH="33%">
+ *          <P ALIGN="CENTER"><B>Common Name</B>
+ *      </TD>
+ *      <TD WIDTH="15%">
+ *          <P ALIGN="CENTER"><B>Use this name in XML files</B>
+ *      </TD>
+ *      <TD WIDTH="12%">
+ *          <P ALIGN="CENTER"><B>Name Type</B>
+ *      </TD>
+ *      <TD WIDTH="31%">
+ *          <P ALIGN="CENTER"><B>Xerces converts to this Java Encoder Name</B>
+ *      </TD>
+ *  </TR>
+ *  <TR>
+ *      <TD WIDTH="33%">8 bit Unicode</TD>
+ *      <TD WIDTH="15%">
+ *          <P ALIGN="CENTER">UTF-8
+ *      </TD>
+ *      <TD WIDTH="12%">
+ *          <P ALIGN="CENTER">IANA
+ *      </TD>
+ *      <TD WIDTH="31%">
+ *          <P ALIGN="CENTER">UTF8
+ *      </TD>
+ *  </TR>
+ *  <TR>
+ *      <TD WIDTH="33%">ISO Latin 1</TD>
+ *      <TD WIDTH="15%">
+ *          <P ALIGN="CENTER">ISO-8859-1
+ *      </TD>
+ *      <TD WIDTH="12%">
+ *          <P ALIGN="CENTER">MIME
+ *      </TD>
+ *      <TD WIDTH="31%">
+ *          <P ALIGN="CENTER">ISO-8859-1
+ *      </TD>
+ *  </TR>
+ *  <TR>
+ *      <TD WIDTH="33%">ISO Latin 2</TD>
+ *      <TD WIDTH="15%">
+ *          <P ALIGN="CENTER">ISO-8859-2
+ *      </TD>
+ *      <TD WIDTH="12%">
+ *          <P ALIGN="CENTER">MIME
+ *      </TD>
+ *      <TD WIDTH="31%">
+ *          <P ALIGN="CENTER">ISO-8859-2
+ *      </TD>
+ *  </TR>
+ *  <TR>
+ *      <TD WIDTH="33%">ISO Latin 3</TD>
+ *      <TD WIDTH="15%">
+ *          <P ALIGN="CENTER">ISO-8859-3
+ *      </TD>
+ *      <TD WIDTH="12%">
+ *          <P ALIGN="CENTER">MIME
+ *      </TD>
+ *      <TD WIDTH="31%">
+ *          <P ALIGN="CENTER">ISO-8859-3
+ *      </TD>
+ *  </TR>
+ *  <TR>
+ *      <TD WIDTH="33%">ISO Latin 4</TD>
+ *      <TD WIDTH="15%">
+ *          <P ALIGN="CENTER">ISO-8859-4
+ *      </TD>
+ *      <TD WIDTH="12%">
+ *          <P ALIGN="CENTER">MIME
+ *      </TD>
+ *      <TD WIDTH="31%">
+ *          <P ALIGN="CENTER">ISO-8859-4
+ *      </TD>
+ *  </TR>
+ *  <TR>
+ *      <TD WIDTH="33%">ISO Latin Cyrillic</TD>
+ *      <TD WIDTH="15%">
+ *          <P ALIGN="CENTER">ISO-8859-5
+ *      </TD>
+ *      <TD WIDTH="12%">
+ *          <P ALIGN="CENTER">MIME
+ *      </TD>
+ *      <TD WIDTH="31%">
+ *          <P ALIGN="CENTER">ISO-8859-5
+ *      </TD>
+ *  </TR>
+ *  <TR>
+ *      <TD WIDTH="33%">ISO Latin Arabic</TD>
+ *      <TD WIDTH="15%">
+ *          <P ALIGN="CENTER">ISO-8859-6
+ *      </TD>
+ *      <TD WIDTH="12%">
+ *          <P ALIGN="CENTER">MIME
+ *      </TD>
+ *      <TD WIDTH="31%">
+ *          <P ALIGN="CENTER">ISO-8859-6
+ *      </TD>
+ *  </TR>
+ *  <TR>
+ *      <TD WIDTH="33%">ISO Latin Greek</TD>
+ *      <TD WIDTH="15%">
+ *          <P ALIGN="CENTER">ISO-8859-7
+ *      </TD>
+ *      <TD WIDTH="12%">
+ *          <P ALIGN="CENTER">MIME
+ *      </TD>
+ *      <TD WIDTH="31%">
+ *          <P ALIGN="CENTER">ISO-8859-7
+ *      </TD>
+ *  </TR>
+ *  <TR>
+ *      <TD WIDTH="33%">ISO Latin Hebrew</TD>
+ *      <TD WIDTH="15%">
+ *          <P ALIGN="CENTER">ISO-8859-8
+ *      </TD>
+ *      <TD WIDTH="12%">
+ *          <P ALIGN="CENTER">MIME
+ *      </TD>
+ *      <TD WIDTH="31%">
+ *          <P ALIGN="CENTER">ISO-8859-8
+ *      </TD>
+ *  </TR>
+ *  <TR>
+ *      <TD WIDTH="33%">ISO Latin 5</TD>
+ *      <TD WIDTH="15%">
+ *          <P ALIGN="CENTER">ISO-8859-9
+ *      </TD>
+ *      <TD WIDTH="12%">
+ *          <P ALIGN="CENTER">MIME
+ *      </TD>
+ *      <TD WIDTH="31%">
+ *          <P ALIGN="CENTER">ISO-8859-9
+ *      </TD>
+ *  </TR>
+ *  <TR>
+ *      <TD WIDTH="33%">EBCDIC: US</TD>
+ *      <TD WIDTH="15%">
+ *          <P ALIGN="CENTER">ebcdic-cp-us
+ *      </TD>
+ *      <TD WIDTH="12%">
+ *          <P ALIGN="CENTER">IANA
+ *      </TD>
+ *      <TD WIDTH="31%">
+ *          <P ALIGN="CENTER">cp037
+ *      </TD>
+ *  </TR>
+ *  <TR>
+ *      <TD WIDTH="33%">EBCDIC: Canada</TD>
+ *      <TD WIDTH="15%">
+ *          <P ALIGN="CENTER">ebcdic-cp-ca
+ *      </TD>
+ *      <TD WIDTH="12%">
+ *          <P ALIGN="CENTER">IANA
+ *      </TD>
+ *      <TD WIDTH="31%">
+ *          <P ALIGN="CENTER">cp037
+ *      </TD>
+ *  </TR>
+ *  <TR>
+ *      <TD WIDTH="33%">EBCDIC: Netherlands</TD>
+ *      <TD WIDTH="15%">
+ *          <P ALIGN="CENTER">ebcdic-cp-nl
+ *      </TD>
+ *      <TD WIDTH="12%">
+ *          <P ALIGN="CENTER">IANA
+ *      </TD>
+ *      <TD WIDTH="31%">
+ *          <P ALIGN="CENTER">cp037
+ *      </TD>
+ *  </TR>
+ *  <TR>
+ *      <TD WIDTH="33%">EBCDIC: Denmark</TD>
+ *      <TD WIDTH="15%">
+ *          <P ALIGN="CENTER">ebcdic-cp-dk
+ *      </TD>
+ *      <TD WIDTH="12%">
+ *          <P ALIGN="CENTER">IANA
+ *      </TD>
+ *      <TD WIDTH="31%">
+ *          <P ALIGN="CENTER">cp277
+ *      </TD>
+ *  </TR>
+ *  <TR>
+ *      <TD WIDTH="33%">EBCDIC: Norway</TD>
+ *      <TD WIDTH="15%">
+ *          <P ALIGN="CENTER">ebcdic-cp-no
+ *      </TD>
+ *      <TD WIDTH="12%">
+ *          <P ALIGN="CENTER">IANA
+ *      </TD>
+ *      <TD WIDTH="31%">
+ *          <P ALIGN="CENTER">cp277
+ *      </TD>
+ *  </TR>
+ *  <TR>
+ *      <TD WIDTH="33%">EBCDIC: Finland</TD>
+ *      <TD WIDTH="15%">
+ *          <P ALIGN="CENTER">ebcdic-cp-fi
+ *      </TD>
+ *      <TD WIDTH="12%">
+ *          <P ALIGN="CENTER">IANA
+ *      </TD>
+ *      <TD WIDTH="31%">
+ *          <P ALIGN="CENTER">cp278
+ *      </TD>
+ *  </TR>
+ *  <TR>
+ *      <TD WIDTH="33%">EBCDIC: Sweden</TD>
+ *      <TD WIDTH="15%">
+ *          <P ALIGN="CENTER">ebcdic-cp-se
+ *      </TD>
+ *      <TD WIDTH="12%">
+ *          <P ALIGN="CENTER">IANA
+ *      </TD>
+ *      <TD WIDTH="31%">
+ *          <P ALIGN="CENTER">cp278
+ *      </TD>
+ *  </TR>
+ *  <TR>
+ *      <TD WIDTH="33%">EBCDIC: Italy</TD>
+ *      <TD WIDTH="15%">
+ *          <P ALIGN="CENTER">ebcdic-cp-it
+ *      </TD>
+ *      <TD WIDTH="12%">
+ *          <P ALIGN="CENTER">IANA
+ *      </TD>
+ *      <TD WIDTH="31%">
+ *          <P ALIGN="CENTER">cp280
+ *      </TD>
+ *  </TR>
+ *  <TR>
+ *      <TD WIDTH="33%">EBCDIC: Spain, Latin America</TD>
+ *      <TD WIDTH="15%">
+ *          <P ALIGN="CENTER">ebcdic-cp-es
+ *      </TD>
+ *      <TD WIDTH="12%">
+ *          <P ALIGN="CENTER">IANA
+ *      </TD>
+ *      <TD WIDTH="31%">
+ *          <P ALIGN="CENTER">cp284
+ *      </TD>
+ *  </TR>
+ *  <TR>
+ *      <TD WIDTH="33%">EBCDIC: Great Britain</TD>
+ *      <TD WIDTH="15%">
+ *          <P ALIGN="CENTER">ebcdic-cp-gb
+ *      </TD>
+ *      <TD WIDTH="12%">
+ *          <P ALIGN="CENTER">IANA
+ *      </TD>
+ *      <TD WIDTH="31%">
+ *          <P ALIGN="CENTER">cp285
+ *      </TD>
+ *  </TR>
+ *  <TR>
+ *      <TD WIDTH="33%">EBCDIC: France</TD>
+ *      <TD WIDTH="15%">
+ *          <P ALIGN="CENTER">ebcdic-cp-fr
+ *      </TD>
+ *      <TD WIDTH="12%">
+ *          <P ALIGN="CENTER">IANA
+ *      </TD>
+ *      <TD WIDTH="31%">
+ *          <P ALIGN="CENTER">cp297
+ *      </TD>
+ *  </TR>
+ *  <TR>
+ *      <TD WIDTH="33%">EBCDIC: Arabic</TD>
+ *      <TD WIDTH="15%">
+ *          <P ALIGN="CENTER">ebcdic-cp-ar1
+ *      </TD>
+ *      <TD WIDTH="12%">
+ *          <P ALIGN="CENTER">IANA
+ *      </TD>
+ *      <TD WIDTH="31%">
+ *          <P ALIGN="CENTER">cp420
+ *      </TD>
+ *  </TR>
+ *  <TR>
+ *      <TD WIDTH="33%">EBCDIC: Hebrew</TD>
+ *      <TD WIDTH="15%">
+ *          <P ALIGN="CENTER">ebcdic-cp-he
+ *      </TD>
+ *      <TD WIDTH="12%">
+ *          <P ALIGN="CENTER">IANA
+ *      </TD>
+ *      <TD WIDTH="31%">
+ *          <P ALIGN="CENTER">cp424
+ *      </TD>
+ *  </TR>
+ *  <TR>
+ *      <TD WIDTH="33%">EBCDIC: Switzerland</TD>
+ *      <TD WIDTH="15%">
+ *          <P ALIGN="CENTER">ebcdic-cp-ch
+ *      </TD>
+ *      <TD WIDTH="12%">
+ *          <P ALIGN="CENTER">IANA
+ *      </TD>
+ *      <TD WIDTH="31%">
+ *          <P ALIGN="CENTER">cp500
+ *      </TD>
+ *  </TR>
+ *  <TR>
+ *      <TD WIDTH="33%">EBCDIC: Roece</TD>
+ *      <TD WIDTH="15%">
+ *          <P ALIGN="CENTER">ebcdic-cp-roece
+ *      </TD>
+ *      <TD WIDTH="12%">
+ *          <P ALIGN="CENTER">IANA
+ *      </TD>
+ *      <TD WIDTH="31%">
+ *          <P ALIGN="CENTER">cp870
+ *      </TD>
+ *  </TR>
+ *  <TR>
+ *      <TD WIDTH="33%">EBCDIC: Yugoslavia</TD>
+ *      <TD WIDTH="15%">
+ *          <P ALIGN="CENTER">ebcdic-cp-yu
+ *      </TD>
+ *      <TD WIDTH="12%">
+ *          <P ALIGN="CENTER">IANA
+ *      </TD>
+ *      <TD WIDTH="31%">
+ *          <P ALIGN="CENTER">cp870
+ *      </TD>
+ *  </TR>
+ *  <TR>
+ *      <TD WIDTH="33%">EBCDIC: Iceland</TD>
+ *      <TD WIDTH="15%">
+ *          <P ALIGN="CENTER">ebcdic-cp-is
+ *      </TD>
+ *      <TD WIDTH="12%">
+ *          <P ALIGN="CENTER">IANA
+ *      </TD>
+ *      <TD WIDTH="31%">
+ *          <P ALIGN="CENTER">cp871
+ *      </TD>
+ *  </TR>
+ *  <TR>
+ *      <TD WIDTH="33%">EBCDIC: Urdu</TD>
+ *      <TD WIDTH="15%">
+ *          <P ALIGN="CENTER">ebcdic-cp-ar2
+ *      </TD>
+ *      <TD WIDTH="12%">
+ *          <P ALIGN="CENTER">IANA
+ *      </TD>
+ *      <TD WIDTH="31%">
+ *          <P ALIGN="CENTER">cp918
+ *      </TD>
+ *  </TR>
+ *  <TR>
+ *      <TD WIDTH="33%">Chinese for PRC, mixed 1/2 byte</TD>
+ *      <TD WIDTH="15%">
+ *          <P ALIGN="CENTER">gb2312
+ *      </TD>
+ *      <TD WIDTH="12%">
+ *          <P ALIGN="CENTER">MIME
+ *      </TD>
+ *      <TD WIDTH="31%">
+ *          <P ALIGN="CENTER">GB2312
+ *      </TD>
+ *  </TR>
+ *  <TR>
+ *      <TD WIDTH="33%">Extended Unix Code, packed for Japanese</TD>
+ *      <TD WIDTH="15%">
+ *          <P ALIGN="CENTER">euc-jp
+ *      </TD>
+ *      <TD WIDTH="12%">
+ *          <P ALIGN="CENTER">MIME
+ *      </TD>
+ *      <TD WIDTH="31%">
+ *          <P ALIGN="CENTER">eucjis
+ *      </TD>
+ *  </TR>
+ *  <TR>
+ *      <TD WIDTH="33%">Japanese: iso-2022-jp</TD>
+ *      <TD WIDTH="15%">
+ *          <P ALIGN="CENTER">iso-2020-jp
+ *      </TD>
+ *      <TD WIDTH="12%">
+ *          <P ALIGN="CENTER">MIME
+ *      </TD>
+ *      <TD WIDTH="31%">
+ *          <P ALIGN="CENTER">JIS
+ *      </TD>
+ *  </TR>
+ *  <TR>
+ *      <TD WIDTH="33%">Japanese: Shift JIS</TD>
+ *      <TD WIDTH="15%">
+ *          <P ALIGN="CENTER">Shift_JIS
+ *      </TD>
+ *      <TD WIDTH="12%">
+ *          <P ALIGN="CENTER">MIME
+ *      </TD>
+ *      <TD WIDTH="31%">
+ *          <P ALIGN="CENTER">SJIS
+ *      </TD>
+ *  </TR>
+ *  <TR>
+ *      <TD WIDTH="33%">Chinese: Big5</TD>
+ *      <TD WIDTH="15%">
+ *          <P ALIGN="CENTER">Big5
+ *      </TD>
+ *      <TD WIDTH="12%">
+ *          <P ALIGN="CENTER">MIME
+ *      </TD>
+ *      <TD WIDTH="31%">
+ *          <P ALIGN="CENTER">Big5
+ *      </TD>
+ *  </TR>
+ *  <TR>
+ *      <TD WIDTH="33%">Extended Unix Code, packed for Korean</TD>
+ *      <TD WIDTH="15%">
+ *          <P ALIGN="CENTER">euc-kr
+ *      </TD>
+ *      <TD WIDTH="12%">
+ *          <P ALIGN="CENTER">MIME
+ *      </TD>
+ *      <TD WIDTH="31%">
+ *          <P ALIGN="CENTER">iso2022kr
+ *      </TD>
+ *  </TR>
+ *  <TR>
+ *      <TD WIDTH="33%">Cyrillic</TD>
+ *      <TD WIDTH="15%">
+ *          <P ALIGN="CENTER">koi8-r
+ *      </TD>
+ *      <TD WIDTH="12%">
+ *          <P ALIGN="CENTER">MIME
+ *      </TD>
+ *      <TD WIDTH="31%">
+ *          <P ALIGN="CENTER">koi8-r
+ *      </TD>
+ *  </TR>
+ * </TABLE>
+ * 
+ * @author TAMURA Kent, IBM
+ * @author Andy Clark, IBM
+ *
+ * @version $Id: EncodingMap.java 306086 2004-10-01 19:24:35Z luehe $
+ */
+public class EncodingMap {
+
+    //
+    // Data
+    //
+
+    /** fIANA2JavaMap */
+    protected final static Hashtable fIANA2JavaMap = new Hashtable();
+
+    /** fJava2IANAMap */
+    protected final static Hashtable fJava2IANAMap = new Hashtable();
+
+    //
+    // Static initialization
+    //
+
+    static {
+
+        // add IANA to Java encoding mappings.
+        fIANA2JavaMap.put("BIG5",            "Big5");
+        fIANA2JavaMap.put("CSBIG5",            "Big5");
+        fIANA2JavaMap.put("CP037",    "CP037");
+        fIANA2JavaMap.put("IBM037",    "CP037");
+        fIANA2JavaMap.put("CSIBM037",    "CP037");
+        fIANA2JavaMap.put("EBCDIC-CP-US",    "CP037");
+        fIANA2JavaMap.put("EBCDIC-CP-CA",    "CP037");
+        fIANA2JavaMap.put("EBCDIC-CP-NL",    "CP037");
+        fIANA2JavaMap.put("EBCDIC-CP-WT",    "CP037");
+        fIANA2JavaMap.put("IBM273",    "CP273");
+        fIANA2JavaMap.put("CP273",    "CP273");
+        fIANA2JavaMap.put("CSIBM273",    "CP273");
+        fIANA2JavaMap.put("IBM277",    "CP277");
+        fIANA2JavaMap.put("CP277",    "CP277");
+        fIANA2JavaMap.put("CSIBM277",    "CP277");
+        fIANA2JavaMap.put("EBCDIC-CP-DK",    "CP277");
+        fIANA2JavaMap.put("EBCDIC-CP-NO",    "CP277");
+        fIANA2JavaMap.put("IBM278",    "CP278");
+        fIANA2JavaMap.put("CP278",    "CP278");
+        fIANA2JavaMap.put("CSIBM278",    "CP278");
+        fIANA2JavaMap.put("EBCDIC-CP-FI",    "CP278");
+        fIANA2JavaMap.put("EBCDIC-CP-SE",    "CP278");
+        fIANA2JavaMap.put("IBM280",    "CP280");
+        fIANA2JavaMap.put("CP280",    "CP280");
+        fIANA2JavaMap.put("CSIBM280",    "CP280");
+        fIANA2JavaMap.put("EBCDIC-CP-IT",    "CP280");
+        fIANA2JavaMap.put("IBM284",    "CP284");
+        fIANA2JavaMap.put("CP284",    "CP284");
+        fIANA2JavaMap.put("CSIBM284",    "CP284");
+        fIANA2JavaMap.put("EBCDIC-CP-ES",    "CP284");
+        fIANA2JavaMap.put("EBCDIC-CP-GB",    "CP285");
+        fIANA2JavaMap.put("IBM285",    "CP285");
+        fIANA2JavaMap.put("CP285",    "CP285");
+        fIANA2JavaMap.put("CSIBM285",    "CP285");
+        fIANA2JavaMap.put("EBCDIC-JP-KANA",    "CP290");
+        fIANA2JavaMap.put("IBM290",    "CP290");
+        fIANA2JavaMap.put("CP290",    "CP290");
+        fIANA2JavaMap.put("CSIBM290",    "CP290");
+        fIANA2JavaMap.put("EBCDIC-CP-FR",    "CP297");
+        fIANA2JavaMap.put("IBM297",    "CP297");
+        fIANA2JavaMap.put("CP297",    "CP297");
+        fIANA2JavaMap.put("CSIBM297",    "CP297");
+        fIANA2JavaMap.put("EBCDIC-CP-AR1",   "CP420");
+        fIANA2JavaMap.put("IBM420",    "CP420");
+        fIANA2JavaMap.put("CP420",    "CP420");
+        fIANA2JavaMap.put("CSIBM420",    "CP420");
+        fIANA2JavaMap.put("EBCDIC-CP-HE",    "CP424");
+        fIANA2JavaMap.put("IBM424",    "CP424");
+        fIANA2JavaMap.put("CP424",    "CP424");
+        fIANA2JavaMap.put("CSIBM424",    "CP424");
+        fIANA2JavaMap.put("IBM437",    "CP437");
+        fIANA2JavaMap.put("437",    "CP437");
+        fIANA2JavaMap.put("CP437",    "CP437");
+        fIANA2JavaMap.put("CSPC8CODEPAGE437",    "CP437");
+        fIANA2JavaMap.put("EBCDIC-CP-CH",    "CP500");
+        fIANA2JavaMap.put("IBM500",    "CP500");
+        fIANA2JavaMap.put("CP500",    "CP500");
+        fIANA2JavaMap.put("CSIBM500",    "CP500");
+        fIANA2JavaMap.put("EBCDIC-CP-CH",    "CP500");
+        fIANA2JavaMap.put("EBCDIC-CP-BE",    "CP500"); 
+        fIANA2JavaMap.put("IBM775",    "CP775");
+        fIANA2JavaMap.put("CP775",    "CP775");
+        fIANA2JavaMap.put("CSPC775BALTIC",    "CP775");
+        fIANA2JavaMap.put("IBM850",    "CP850");
+        fIANA2JavaMap.put("850",    "CP850");
+        fIANA2JavaMap.put("CP850",    "CP850");
+        fIANA2JavaMap.put("CSPC850MULTILINGUAL",    "CP850");
+        fIANA2JavaMap.put("IBM852",    "CP852");
+        fIANA2JavaMap.put("852",    "CP852");
+        fIANA2JavaMap.put("CP852",    "CP852");
+        fIANA2JavaMap.put("CSPCP852",    "CP852");
+        fIANA2JavaMap.put("IBM855",    "CP855");
+        fIANA2JavaMap.put("855",    "CP855");
+        fIANA2JavaMap.put("CP855",    "CP855");
+        fIANA2JavaMap.put("CSIBM855",    "CP855");
+        fIANA2JavaMap.put("IBM857",    "CP857");
+        fIANA2JavaMap.put("857",    "CP857");
+        fIANA2JavaMap.put("CP857",    "CP857");
+        fIANA2JavaMap.put("CSIBM857",    "CP857");
+        fIANA2JavaMap.put("IBM00858",    "CP858");
+        fIANA2JavaMap.put("CP00858",    "CP858");
+        fIANA2JavaMap.put("CCSID00858",    "CP858");
+        fIANA2JavaMap.put("IBM860",    "CP860");
+        fIANA2JavaMap.put("860",    "CP860");
+        fIANA2JavaMap.put("CP860",    "CP860");
+        fIANA2JavaMap.put("CSIBM860",    "CP860");
+        fIANA2JavaMap.put("IBM861",    "CP861");
+        fIANA2JavaMap.put("861",    "CP861");
+        fIANA2JavaMap.put("CP861",    "CP861");
+        fIANA2JavaMap.put("CP-IS",    "CP861");
+        fIANA2JavaMap.put("CSIBM861",    "CP861");
+        fIANA2JavaMap.put("IBM862",    "CP862");
+        fIANA2JavaMap.put("862",    "CP862");
+        fIANA2JavaMap.put("CP862",    "CP862");
+        fIANA2JavaMap.put("CSPC862LATINHEBREW",    "CP862");
+        fIANA2JavaMap.put("IBM863",    "CP863");
+        fIANA2JavaMap.put("863",    "CP863");
+        fIANA2JavaMap.put("CP863",    "CP863");
+        fIANA2JavaMap.put("CSIBM863",    "CP863");
+        fIANA2JavaMap.put("IBM864",    "CP864");
+        fIANA2JavaMap.put("CP864",    "CP864");
+        fIANA2JavaMap.put("CSIBM864",    "CP864");
+        fIANA2JavaMap.put("IBM865",    "CP865");
+        fIANA2JavaMap.put("865",    "CP865");
+        fIANA2JavaMap.put("CP865",    "CP865");
+        fIANA2JavaMap.put("CSIBM865",    "CP865");
+        fIANA2JavaMap.put("IBM866",    "CP866");
+        fIANA2JavaMap.put("866",    "CP866");
+        fIANA2JavaMap.put("CP866",    "CP866");
+        fIANA2JavaMap.put("CSIBM866",    "CP866");
+        fIANA2JavaMap.put("IBM868",    "CP868");
+        fIANA2JavaMap.put("CP868",    "CP868");
+        fIANA2JavaMap.put("CSIBM868",    "CP868");
+        fIANA2JavaMap.put("CP-AR",        "CP868");
+        fIANA2JavaMap.put("IBM869",    "CP869");
+        fIANA2JavaMap.put("CP869",    "CP869");
+        fIANA2JavaMap.put("CSIBM869",    "CP869");
+        fIANA2JavaMap.put("CP-GR",        "CP869");
+        fIANA2JavaMap.put("IBM870",    "CP870");
+        fIANA2JavaMap.put("CP870",    "CP870");
+        fIANA2JavaMap.put("CSIBM870",    "CP870");
+        fIANA2JavaMap.put("EBCDIC-CP-ROECE", "CP870");
+        fIANA2JavaMap.put("EBCDIC-CP-YU",    "CP870");
+        fIANA2JavaMap.put("IBM871",    "CP871");
+        fIANA2JavaMap.put("CP871",    "CP871");
+        fIANA2JavaMap.put("CSIBM871",    "CP871");
+        fIANA2JavaMap.put("EBCDIC-CP-IS",    "CP871");
+        fIANA2JavaMap.put("IBM918",    "CP918");
+        fIANA2JavaMap.put("CP918",    "CP918");
+        fIANA2JavaMap.put("CSIBM918",    "CP918");
+        fIANA2JavaMap.put("EBCDIC-CP-AR2",   "CP918");
+        fIANA2JavaMap.put("IBM00924",    "CP924");
+        fIANA2JavaMap.put("CP00924",    "CP924");
+        fIANA2JavaMap.put("CCSID00924",    "CP924");
+        // is this an error???
+        fIANA2JavaMap.put("EBCDIC-LATIN9--EURO",    "CP924");
+        fIANA2JavaMap.put("IBM1026",    "CP1026");
+        fIANA2JavaMap.put("CP1026",    "CP1026");
+        fIANA2JavaMap.put("CSIBM1026",    "CP1026");
+        fIANA2JavaMap.put("IBM01140",    "Cp1140");
+        fIANA2JavaMap.put("CP01140",    "Cp1140");
+        fIANA2JavaMap.put("CCSID01140",    "Cp1140");
+        fIANA2JavaMap.put("IBM01141",    "Cp1141");
+        fIANA2JavaMap.put("CP01141",    "Cp1141");
+        fIANA2JavaMap.put("CCSID01141",    "Cp1141");
+        fIANA2JavaMap.put("IBM01142",    "Cp1142");
+        fIANA2JavaMap.put("CP01142",    "Cp1142");
+        fIANA2JavaMap.put("CCSID01142",    "Cp1142");
+        fIANA2JavaMap.put("IBM01143",    "Cp1143");
+        fIANA2JavaMap.put("CP01143",    "Cp1143");
+        fIANA2JavaMap.put("CCSID01143",    "Cp1143");
+        fIANA2JavaMap.put("IBM01144",    "Cp1144");
+        fIANA2JavaMap.put("CP01144",    "Cp1144");
+        fIANA2JavaMap.put("CCSID01144",    "Cp1144");
+        fIANA2JavaMap.put("IBM01145",    "Cp1145");
+        fIANA2JavaMap.put("CP01145",    "Cp1145");
+        fIANA2JavaMap.put("CCSID01145",    "Cp1145");
+        fIANA2JavaMap.put("IBM01146",    "Cp1146");
+        fIANA2JavaMap.put("CP01146",    "Cp1146");
+        fIANA2JavaMap.put("CCSID01146",    "Cp1146");
+        fIANA2JavaMap.put("IBM01147",    "Cp1147");
+        fIANA2JavaMap.put("CP01147",    "Cp1147");
+        fIANA2JavaMap.put("CCSID01147",    "Cp1147");
+        fIANA2JavaMap.put("IBM01148",    "Cp1148");
+        fIANA2JavaMap.put("CP01148",    "Cp1148");
+        fIANA2JavaMap.put("CCSID01148",    "Cp1148");
+        fIANA2JavaMap.put("IBM01149",    "Cp1149");
+        fIANA2JavaMap.put("CP01149",    "Cp1149");
+        fIANA2JavaMap.put("CCSID01149",    "Cp1149");
+        fIANA2JavaMap.put("EUC-JP",          "EUCJIS");
+        fIANA2JavaMap.put("CSEUCPKDFMTJAPANESE",          "EUCJIS");
+        fIANA2JavaMap.put("EXTENDED_UNIX_CODE_PACKED_FORMAT_FOR_JAPANESE",          "EUCJIS");
+        fIANA2JavaMap.put("EUC-KR",          "KSC5601");
+        fIANA2JavaMap.put("CSEUCKR",          "KSC5601");
+        fIANA2JavaMap.put("KS_C_5601-1987",          "KS_C_5601-1987");
+        fIANA2JavaMap.put("ISO-IR-149",          "KS_C_5601-1987");
+        fIANA2JavaMap.put("KS_C_5601-1989",          "KS_C_5601-1987");
+        fIANA2JavaMap.put("KSC_5601",          "KS_C_5601-1987");
+        fIANA2JavaMap.put("KOREAN",          "KS_C_5601-1987");
+        fIANA2JavaMap.put("CSKSC56011987",          "KS_C_5601-1987");
+        fIANA2JavaMap.put("GB2312",          "GB2312");
+        fIANA2JavaMap.put("CSGB2312",          "GB2312");
+        fIANA2JavaMap.put("ISO-2022-JP",     "JIS");
+        fIANA2JavaMap.put("CSISO2022JP",     "JIS");
+        fIANA2JavaMap.put("ISO-2022-KR",     "ISO2022KR");
+        fIANA2JavaMap.put("CSISO2022KR",     "ISO2022KR");
+        fIANA2JavaMap.put("ISO-2022-CN",     "ISO2022CN");
+
+        fIANA2JavaMap.put("X0201",  "JIS0201");
+        fIANA2JavaMap.put("CSISO13JISC6220JP", "JIS0201");
+        fIANA2JavaMap.put("X0208",  "JIS0208");
+        fIANA2JavaMap.put("ISO-IR-87",  "JIS0208");
+        fIANA2JavaMap.put("X0208dbiJIS_X0208-1983",  "JIS0208");
+        fIANA2JavaMap.put("CSISO87JISX0208",  "JIS0208");
+        fIANA2JavaMap.put("X0212",  "JIS0212");
+        fIANA2JavaMap.put("ISO-IR-159",  "JIS0212");
+        fIANA2JavaMap.put("CSISO159JISX02121990",  "JIS0212");
+        fIANA2JavaMap.put("GB18030",       "GB18030");
+        fIANA2JavaMap.put("GBK",       "GBK");
+        fIANA2JavaMap.put("CP936",       "GBK");
+        fIANA2JavaMap.put("MS936",       "GBK");
+        fIANA2JavaMap.put("WINDOWS-936",       "GBK");
+        fIANA2JavaMap.put("SHIFT_JIS",       "SJIS");
+        fIANA2JavaMap.put("CSSHIFTJIS",       "SJIS");
+        fIANA2JavaMap.put("MS_KANJI",       "SJIS");
+        fIANA2JavaMap.put("WINDOWS-31J",       "MS932");
+        fIANA2JavaMap.put("CSWINDOWS31J",       "MS932");
+
+	    // Add support for Cp1252 and its friends
+        fIANA2JavaMap.put("WINDOWS-1250",   "Cp1250");
+        fIANA2JavaMap.put("WINDOWS-1251",   "Cp1251");
+        fIANA2JavaMap.put("WINDOWS-1252",   "Cp1252");
+        fIANA2JavaMap.put("WINDOWS-1253",   "Cp1253");
+        fIANA2JavaMap.put("WINDOWS-1254",   "Cp1254");
+        fIANA2JavaMap.put("WINDOWS-1255",   "Cp1255");
+        fIANA2JavaMap.put("WINDOWS-1256",   "Cp1256");
+        fIANA2JavaMap.put("WINDOWS-1257",   "Cp1257");
+        fIANA2JavaMap.put("WINDOWS-1258",   "Cp1258");
+        fIANA2JavaMap.put("TIS-620",   "TIS620");
+
+        fIANA2JavaMap.put("ISO-8859-1",      "ISO8859_1"); 
+        fIANA2JavaMap.put("ISO-IR-100",      "ISO8859_1");
+        fIANA2JavaMap.put("ISO_8859-1",      "ISO8859_1");
+        fIANA2JavaMap.put("LATIN1",      "ISO8859_1");
+        fIANA2JavaMap.put("CSISOLATIN1",      "ISO8859_1");
+        fIANA2JavaMap.put("L1",      "ISO8859_1");
+        fIANA2JavaMap.put("IBM819",      "ISO8859_1");
+        fIANA2JavaMap.put("CP819",      "ISO8859_1");
+
+        fIANA2JavaMap.put("ISO-8859-2",      "ISO8859_2"); 
+        fIANA2JavaMap.put("ISO-IR-101",      "ISO8859_2");
+        fIANA2JavaMap.put("ISO_8859-2",      "ISO8859_2");
+        fIANA2JavaMap.put("LATIN2",      "ISO8859_2");
+        fIANA2JavaMap.put("CSISOLATIN2",      "ISO8859_2");
+        fIANA2JavaMap.put("L2",      "ISO8859_2");
+
+        fIANA2JavaMap.put("ISO-8859-3",      "ISO8859_3"); 
+        fIANA2JavaMap.put("ISO-IR-109",      "ISO8859_3");
+        fIANA2JavaMap.put("ISO_8859-3",      "ISO8859_3");
+        fIANA2JavaMap.put("LATIN3",      "ISO8859_3");
+        fIANA2JavaMap.put("CSISOLATIN3",      "ISO8859_3");
+        fIANA2JavaMap.put("L3",      "ISO8859_3");
+
+        fIANA2JavaMap.put("ISO-8859-4",      "ISO8859_4"); 
+        fIANA2JavaMap.put("ISO-IR-110",      "ISO8859_4");
+        fIANA2JavaMap.put("ISO_8859-4",      "ISO8859_4");
+        fIANA2JavaMap.put("LATIN4",      "ISO8859_4");
+        fIANA2JavaMap.put("CSISOLATIN4",      "ISO8859_4");
+        fIANA2JavaMap.put("L4",      "ISO8859_4");
+
+        fIANA2JavaMap.put("ISO-8859-5",      "ISO8859_5"); 
+        fIANA2JavaMap.put("ISO-IR-144",      "ISO8859_5");
+        fIANA2JavaMap.put("ISO_8859-5",      "ISO8859_5");
+        fIANA2JavaMap.put("CYRILLIC",      "ISO8859_5");
+        fIANA2JavaMap.put("CSISOLATINCYRILLIC",      "ISO8859_5");
+
+        fIANA2JavaMap.put("ISO-8859-6",      "ISO8859_6"); 
+        fIANA2JavaMap.put("ISO-IR-127",      "ISO8859_6");
+        fIANA2JavaMap.put("ISO_8859-6",      "ISO8859_6");
+        fIANA2JavaMap.put("ECMA-114",      "ISO8859_6");
+        fIANA2JavaMap.put("ASMO-708",      "ISO8859_6");
+        fIANA2JavaMap.put("ARABIC",      "ISO8859_6");
+        fIANA2JavaMap.put("CSISOLATINARABIC",      "ISO8859_6");
+
+        fIANA2JavaMap.put("ISO-8859-7",      "ISO8859_7"); 
+        fIANA2JavaMap.put("ISO-IR-126",      "ISO8859_7");
+        fIANA2JavaMap.put("ISO_8859-7",      "ISO8859_7");
+        fIANA2JavaMap.put("ELOT_928",      "ISO8859_7");
+        fIANA2JavaMap.put("ECMA-118",      "ISO8859_7");
+        fIANA2JavaMap.put("GREEK",      "ISO8859_7");
+        fIANA2JavaMap.put("CSISOLATINGREEK",      "ISO8859_7");
+        fIANA2JavaMap.put("GREEK8",      "ISO8859_7");
+
+        fIANA2JavaMap.put("ISO-8859-8",      "ISO8859_8"); 
+        fIANA2JavaMap.put("ISO-8859-8-I",      "ISO8859_8"); // added since this encoding only differs w.r.t. presentation 
+        fIANA2JavaMap.put("ISO-IR-138",      "ISO8859_8");
+        fIANA2JavaMap.put("ISO_8859-8",      "ISO8859_8");
+        fIANA2JavaMap.put("HEBREW",      "ISO8859_8");
+        fIANA2JavaMap.put("CSISOLATINHEBREW",      "ISO8859_8");
+
+        fIANA2JavaMap.put("ISO-8859-9",      "ISO8859_9"); 
+        fIANA2JavaMap.put("ISO-IR-148",      "ISO8859_9");
+        fIANA2JavaMap.put("ISO_8859-9",      "ISO8859_9");
+        fIANA2JavaMap.put("LATIN5",      "ISO8859_9");
+        fIANA2JavaMap.put("CSISOLATIN5",      "ISO8859_9");
+        fIANA2JavaMap.put("L5",      "ISO8859_9");
+
+        fIANA2JavaMap.put("ISO-8859-13",      "ISO8859_13"); 
+        
+        fIANA2JavaMap.put("ISO-8859-15",      "ISO8859_15_FDIS"); 
+        fIANA2JavaMap.put("ISO_8859-15",      "ISO8859_15_FDIS");
+        fIANA2JavaMap.put("LATIN-9",          "ISO8859_15_FDIS"); 
+
+        fIANA2JavaMap.put("KOI8-R",          "KOI8_R");
+        fIANA2JavaMap.put("CSKOI8R",          "KOI8_R");
+        fIANA2JavaMap.put("US-ASCII",        "ASCII"); 
+        fIANA2JavaMap.put("ISO-IR-6",        "ASCII");
+        fIANA2JavaMap.put("ANSI_X3.4-1968",        "ASCII");
+        fIANA2JavaMap.put("ANSI_X3.4-1986",        "ASCII");
+        fIANA2JavaMap.put("ISO_646.IRV:1991",        "ASCII");
+        fIANA2JavaMap.put("ASCII",        "ASCII");
+        fIANA2JavaMap.put("CSASCII",        "ASCII");
+        fIANA2JavaMap.put("ISO646-US",        "ASCII");
+        fIANA2JavaMap.put("US",        "ASCII");
+        fIANA2JavaMap.put("IBM367",        "ASCII");
+        fIANA2JavaMap.put("CP367",        "ASCII");
+        fIANA2JavaMap.put("UTF-8",           "UTF8");
+        fIANA2JavaMap.put("UTF-16",           "UTF-16");
+        fIANA2JavaMap.put("UTF-16BE",           "UnicodeBig");
+        fIANA2JavaMap.put("UTF-16LE",           "UnicodeLittle");
+
+        // support for 1047, as proposed to be added to the 
+        // IANA registry in 
+        // http://lists.w3.org/Archives/Public/ietf-charset/2002JulSep/0049.html
+        fIANA2JavaMap.put("IBM-1047",    "Cp1047");
+        fIANA2JavaMap.put("IBM1047",    "Cp1047");
+        fIANA2JavaMap.put("CP1047",    "Cp1047");
+
+        // Adding new aliases as proposed in
+        // http://lists.w3.org/Archives/Public/ietf-charset/2002JulSep/0058.html
+        fIANA2JavaMap.put("IBM-37",    "CP037");
+        fIANA2JavaMap.put("IBM-273",    "CP273");
+        fIANA2JavaMap.put("IBM-277",    "CP277");
+        fIANA2JavaMap.put("IBM-278",    "CP278");
+        fIANA2JavaMap.put("IBM-280",    "CP280");
+        fIANA2JavaMap.put("IBM-284",    "CP284");
+        fIANA2JavaMap.put("IBM-285",    "CP285");
+        fIANA2JavaMap.put("IBM-290",    "CP290");
+        fIANA2JavaMap.put("IBM-297",    "CP297");
+        fIANA2JavaMap.put("IBM-420",    "CP420");
+        fIANA2JavaMap.put("IBM-424",    "CP424");
+        fIANA2JavaMap.put("IBM-437",    "CP437");
+        fIANA2JavaMap.put("IBM-500",    "CP500");
+        fIANA2JavaMap.put("IBM-775",    "CP775");
+        fIANA2JavaMap.put("IBM-850",    "CP850");
+        fIANA2JavaMap.put("IBM-852",    "CP852");
+        fIANA2JavaMap.put("IBM-855",    "CP855");
+        fIANA2JavaMap.put("IBM-857",    "CP857");
+        fIANA2JavaMap.put("IBM-858",    "CP858");
+        fIANA2JavaMap.put("IBM-860",    "CP860");
+        fIANA2JavaMap.put("IBM-861",    "CP861");
+        fIANA2JavaMap.put("IBM-862",    "CP862");
+        fIANA2JavaMap.put("IBM-863",    "CP863");
+        fIANA2JavaMap.put("IBM-864",    "CP864");
+        fIANA2JavaMap.put("IBM-865",    "CP865");
+        fIANA2JavaMap.put("IBM-866",    "CP866");
+        fIANA2JavaMap.put("IBM-868",    "CP868");
+        fIANA2JavaMap.put("IBM-869",    "CP869");
+        fIANA2JavaMap.put("IBM-870",    "CP870");
+        fIANA2JavaMap.put("IBM-871",    "CP871");
+        fIANA2JavaMap.put("IBM-918",    "CP918");
+        fIANA2JavaMap.put("IBM-924",    "CP924");
+        fIANA2JavaMap.put("IBM-1026",    "CP1026");
+        fIANA2JavaMap.put("IBM-1140",    "Cp1140");
+        fIANA2JavaMap.put("IBM-1141",    "Cp1141");
+        fIANA2JavaMap.put("IBM-1142",    "Cp1142");
+        fIANA2JavaMap.put("IBM-1143",    "Cp1143");
+        fIANA2JavaMap.put("IBM-1144",    "Cp1144");
+        fIANA2JavaMap.put("IBM-1145",    "Cp1145");
+        fIANA2JavaMap.put("IBM-1146",    "Cp1146");
+        fIANA2JavaMap.put("IBM-1147",    "Cp1147");
+        fIANA2JavaMap.put("IBM-1148",    "Cp1148");
+        fIANA2JavaMap.put("IBM-1149",    "Cp1149");
+        fIANA2JavaMap.put("IBM-819",      "ISO8859_1");
+        fIANA2JavaMap.put("IBM-367",        "ASCII");
+
+        // REVISIT:
+        //   j:CNS11643 -> EUC-TW?
+        //   ISO-2022-CN? ISO-2022-CN-EXT?
+                                                
+        // add Java to IANA encoding mappings
+        //fJava2IANAMap.put("8859_1",    "US-ASCII"); // ?
+        fJava2IANAMap.put("ISO8859_1",    "ISO-8859-1");
+        fJava2IANAMap.put("ISO8859_2",    "ISO-8859-2");
+        fJava2IANAMap.put("ISO8859_3",    "ISO-8859-3");
+        fJava2IANAMap.put("ISO8859_4",    "ISO-8859-4");
+        fJava2IANAMap.put("ISO8859_5",    "ISO-8859-5");
+        fJava2IANAMap.put("ISO8859_6",    "ISO-8859-6");
+        fJava2IANAMap.put("ISO8859_7",    "ISO-8859-7");
+        fJava2IANAMap.put("ISO8859_8",    "ISO-8859-8");
+        fJava2IANAMap.put("ISO8859_9",    "ISO-8859-9");
+        fJava2IANAMap.put("ISO8859_13",    "ISO-8859-13");
+        fJava2IANAMap.put("ISO8859_15",    "ISO-8859-15");
+        fJava2IANAMap.put("ISO8859_15_FDIS",    "ISO-8859-15");
+        fJava2IANAMap.put("Big5",      "BIG5");
+        fJava2IANAMap.put("CP037",     "EBCDIC-CP-US");
+        fJava2IANAMap.put("CP273",     "IBM273");
+        fJava2IANAMap.put("CP277",     "EBCDIC-CP-DK");
+        fJava2IANAMap.put("CP278",     "EBCDIC-CP-FI");
+        fJava2IANAMap.put("CP280",     "EBCDIC-CP-IT");
+        fJava2IANAMap.put("CP284",     "EBCDIC-CP-ES");
+        fJava2IANAMap.put("CP285",     "EBCDIC-CP-GB");
+        fJava2IANAMap.put("CP290",     "EBCDIC-JP-KANA");
+        fJava2IANAMap.put("CP297",     "EBCDIC-CP-FR");
+        fJava2IANAMap.put("CP420",     "EBCDIC-CP-AR1");
+        fJava2IANAMap.put("CP424",     "EBCDIC-CP-HE");
+        fJava2IANAMap.put("CP437",     "IBM437");
+        fJava2IANAMap.put("CP500",     "EBCDIC-CP-CH");
+        fJava2IANAMap.put("CP775",     "IBM775");
+        fJava2IANAMap.put("CP850",     "IBM850");
+        fJava2IANAMap.put("CP852",     "IBM852");
+        fJava2IANAMap.put("CP855",     "IBM855");
+        fJava2IANAMap.put("CP857",     "IBM857");
+        fJava2IANAMap.put("CP858",     "IBM00858");
+        fJava2IANAMap.put("CP860",     "IBM860");
+        fJava2IANAMap.put("CP861",     "IBM861");
+        fJava2IANAMap.put("CP862",     "IBM862");
+        fJava2IANAMap.put("CP863",     "IBM863");
+        fJava2IANAMap.put("CP864",     "IBM864");
+        fJava2IANAMap.put("CP865",     "IBM865");
+        fJava2IANAMap.put("CP866",     "IBM866");
+        fJava2IANAMap.put("CP868",     "IBM868");
+        fJava2IANAMap.put("CP869",     "IBM869");
+        fJava2IANAMap.put("CP870",     "EBCDIC-CP-ROECE");
+        fJava2IANAMap.put("CP871",     "EBCDIC-CP-IS");
+        fJava2IANAMap.put("CP918",     "EBCDIC-CP-AR2");
+        fJava2IANAMap.put("CP924",     "IBM00924");
+        fJava2IANAMap.put("CP1026",     "IBM1026");
+        fJava2IANAMap.put("Cp01140",     "IBM01140");
+        fJava2IANAMap.put("Cp01141",     "IBM01141");
+        fJava2IANAMap.put("Cp01142",     "IBM01142");
+        fJava2IANAMap.put("Cp01143",     "IBM01143");
+        fJava2IANAMap.put("Cp01144",     "IBM01144");
+        fJava2IANAMap.put("Cp01145",     "IBM01145");
+        fJava2IANAMap.put("Cp01146",     "IBM01146");
+        fJava2IANAMap.put("Cp01147",     "IBM01147");
+        fJava2IANAMap.put("Cp01148",     "IBM01148");
+        fJava2IANAMap.put("Cp01149",     "IBM01149");
+        fJava2IANAMap.put("EUCJIS",    "EUC-JP");
+        fJava2IANAMap.put("KS_C_5601-1987",          "KS_C_5601-1987");
+        fJava2IANAMap.put("GB2312",    "GB2312");
+        fJava2IANAMap.put("ISO2022KR", "ISO-2022-KR");
+        fJava2IANAMap.put("ISO2022CN", "ISO-2022-CN");
+        fJava2IANAMap.put("JIS",       "ISO-2022-JP");
+        fJava2IANAMap.put("KOI8_R",    "KOI8-R");
+        fJava2IANAMap.put("KSC5601",   "EUC-KR");
+        fJava2IANAMap.put("GB18030",      "GB18030");
+        fJava2IANAMap.put("GBK",       "GBK");
+        fJava2IANAMap.put("SJIS",      "SHIFT_JIS");
+        fJava2IANAMap.put("MS932",      "WINDOWS-31J");
+        fJava2IANAMap.put("UTF8",      "UTF-8");
+        fJava2IANAMap.put("Unicode",   "UTF-16");
+        fJava2IANAMap.put("UnicodeBig",   "UTF-16BE");
+        fJava2IANAMap.put("UnicodeLittle",   "UTF-16LE");
+        fJava2IANAMap.put("JIS0201",  "X0201");
+        fJava2IANAMap.put("JIS0208",  "X0208");
+        fJava2IANAMap.put("JIS0212",  "ISO-IR-159");
+
+        // proposed addition (see above for details):
+        fJava2IANAMap.put("CP1047",    "IBM1047");
+
+    } // <clinit>()
+
+    //
+    // Constructors
+    //
+
+    /** Default constructor. */
+    public EncodingMap() {}
+
+    //
+    // Public static methods
+    //
+
+    /**
+     * Adds an IANA to Java encoding name mapping.
+     * 
+     * @param ianaEncoding The IANA encoding name.
+     * @param javaEncoding The Java encoding name.
+     */
+    public static void putIANA2JavaMapping(String ianaEncoding, 
+                                           String javaEncoding) {
+        fIANA2JavaMap.put(ianaEncoding, javaEncoding);
+    } // putIANA2JavaMapping(String,String)
+
+    /**
+     * Returns the Java encoding name for the specified IANA encoding name.
+     * 
+     * @param ianaEncoding The IANA encoding name.
+     */
+    public static String getIANA2JavaMapping(String ianaEncoding) {
+        return (String)fIANA2JavaMap.get(ianaEncoding);
+    } // getIANA2JavaMapping(String):String
+
+    /**
+     * Removes an IANA to Java encoding name mapping.
+     * 
+     * @param ianaEncoding The IANA encoding name.
+     */
+    public static String removeIANA2JavaMapping(String ianaEncoding) {
+        return (String)fIANA2JavaMap.remove(ianaEncoding);
+    } // removeIANA2JavaMapping(String):String
+
+    /**
+     * Adds a Java to IANA encoding name mapping.
+     * 
+     * @param javaEncoding The Java encoding name.
+     * @param ianaEncoding The IANA encoding name.
+     */
+    public static void putJava2IANAMapping(String javaEncoding, 
+                                           String ianaEncoding) {
+        fJava2IANAMap.put(javaEncoding, ianaEncoding);
+    } // putJava2IANAMapping(String,String)
+
+    /**
+     * Returns the IANA encoding name for the specified Java encoding name.
+     * 
+     * @param javaEncoding The Java encoding name.
+     */
+    public static String getJava2IANAMapping(String javaEncoding) {
+        return (String)fJava2IANAMap.get(javaEncoding);
+    } // getJava2IANAMapping(String):String
+
+    /**
+     * Removes a Java to IANA encoding name mapping.
+     * 
+     * @param javaEncoding The Java encoding name.
+     */
+    public static String removeJava2IANAMapping(String javaEncoding) {
+        return (String)fJava2IANAMap.remove(javaEncoding);
+    } // removeJava2IANAMapping
+
+} // class EncodingMap

Added: branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/xmlparser/ParserUtils.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/xmlparser/ParserUtils.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/xmlparser/ParserUtils.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,238 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.xmlparser;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.jasper.Constants;
+import org.apache.jasper.JasperException;
+import org.apache.jasper.compiler.Localizer;
+import org.w3c.dom.Comment;
+import org.w3c.dom.Document;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.w3c.dom.Text;
+import org.xml.sax.EntityResolver;
+import org.xml.sax.ErrorHandler;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+import org.xml.sax.SAXParseException;
+
+
+/**
+ * XML parsing utilities for processing web application deployment
+ * descriptor and tag library descriptor files.  FIXME - make these
+ * use a separate class loader for the parser to be used.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 306152 $ $Date: 2005-03-23 22:08:01 -0600 (Wed, 23 Mar 2005) $
+ */
+
+public class ParserUtils {
+
+    /**
+     * An error handler for use when parsing XML documents.
+     */
+    static ErrorHandler errorHandler = new MyErrorHandler();
+
+    /**
+     * An entity resolver for use when parsing XML documents.
+     */
+    static EntityResolver entityResolver = new MyEntityResolver();
+
+    // Turn off for JSP 2.0 until switch over to using xschema.
+    public static boolean validating = false;
+
+
+    // --------------------------------------------------------- Public Methods
+
+    /**
+     * Parse the specified XML document, and return a <code>TreeNode</code>
+     * that corresponds to the root node of the document tree.
+     *
+     * @param uri URI of the XML document being parsed
+     * @param is Input source containing the deployment descriptor
+     *
+     * @exception JasperException if an input/output error occurs
+     * @exception JasperException if a parsing error occurs
+     */
+    public TreeNode parseXMLDocument(String uri, InputSource is)
+        throws JasperException {
+
+        Document document = null;
+
+        // Perform an XML parse of this document, via JAXP
+        try {
+            DocumentBuilderFactory factory =
+                DocumentBuilderFactory.newInstance();
+            factory.setNamespaceAware(true);
+            factory.setValidating(validating);
+            DocumentBuilder builder = factory.newDocumentBuilder();
+            builder.setEntityResolver(entityResolver);
+            builder.setErrorHandler(errorHandler);
+            document = builder.parse(is);
+	} catch (ParserConfigurationException ex) {
+            throw new JasperException
+                (Localizer.getMessage("jsp.error.parse.xml", uri), ex);
+	} catch (SAXParseException ex) {
+            throw new JasperException
+                (Localizer.getMessage("jsp.error.parse.xml.line",
+				      uri,
+				      Integer.toString(ex.getLineNumber()),
+				      Integer.toString(ex.getColumnNumber())),
+		 ex);
+	} catch (SAXException sx) {
+            throw new JasperException
+                (Localizer.getMessage("jsp.error.parse.xml", uri), sx);
+        } catch (IOException io) {
+            throw new JasperException
+                (Localizer.getMessage("jsp.error.parse.xml", uri), io);
+	}
+
+        // Convert the resulting document to a graph of TreeNodes
+        return (convert(null, document.getDocumentElement()));
+    }
+
+
+    /**
+     * Parse the specified XML document, and return a <code>TreeNode</code>
+     * that corresponds to the root node of the document tree.
+     *
+     * @param uri URI of the XML document being parsed
+     * @param is Input stream containing the deployment descriptor
+     *
+     * @exception JasperException if an input/output error occurs
+     * @exception JasperException if a parsing error occurs
+     */
+    public TreeNode parseXMLDocument(String uri, InputStream is)
+            throws JasperException {
+
+        return (parseXMLDocument(uri, new InputSource(is)));
+    }
+
+
+    // ------------------------------------------------------ Protected Methods
+
+
+    /**
+     * Create and return a TreeNode that corresponds to the specified Node,
+     * including processing all of the attributes and children nodes.
+     *
+     * @param parent The parent TreeNode (if any) for the new TreeNode
+     * @param node The XML document Node to be converted
+     */
+    protected TreeNode convert(TreeNode parent, Node node) {
+
+        // Construct a new TreeNode for this node
+        TreeNode treeNode = new TreeNode(node.getNodeName(), parent);
+
+        // Convert all attributes of this node
+        NamedNodeMap attributes = node.getAttributes();
+        if (attributes != null) {
+            int n = attributes.getLength();
+            for (int i = 0; i < n; i++) {
+                Node attribute = attributes.item(i);
+                treeNode.addAttribute(attribute.getNodeName(),
+                                      attribute.getNodeValue());
+            }
+        }
+
+        // Create and attach all children of this node
+        NodeList children = node.getChildNodes();
+        if (children != null) {
+            int n = children.getLength();
+            for (int i = 0; i < n; i++) {
+                Node child = children.item(i);
+                if (child instanceof Comment)
+                    continue;
+                if (child instanceof Text) {
+                    String body = ((Text) child).getData();
+                    if (body != null) {
+                        body = body.trim();
+                        if (body.length() > 0)
+                            treeNode.setBody(body);
+                    }
+                } else {
+                    TreeNode treeChild = convert(treeNode, child);
+                }
+            }
+        }
+        
+        // Return the completed TreeNode graph
+        return (treeNode);
+    }
+}
+
+
+// ------------------------------------------------------------ Private Classes
+
+class MyEntityResolver implements EntityResolver {
+
+    // Logger
+    private Log log = LogFactory.getLog(MyEntityResolver.class);
+
+    public InputSource resolveEntity(String publicId, String systemId)
+            throws SAXException {
+        for (int i = 0; i < Constants.CACHED_DTD_PUBLIC_IDS.length; i++) {
+            String cachedDtdPublicId = Constants.CACHED_DTD_PUBLIC_IDS[i];
+            if (cachedDtdPublicId.equals(publicId)) {
+                String resourcePath = Constants.CACHED_DTD_RESOURCE_PATHS[i];
+                InputStream input = this.getClass().getResourceAsStream(
+                        resourcePath);
+                if (input == null) {
+                    throw new SAXException(Localizer.getMessage(
+                            "jsp.error.internal.filenotfound", resourcePath));
+                }
+                InputSource isrc = new InputSource(input);
+                return isrc;
+            }
+        }
+        if (log.isDebugEnabled())
+            log.debug("Resolve entity failed" + publicId + " " + systemId);
+        log.error(Localizer.getMessage("jsp.error.parse.xml.invalidPublicId",
+                publicId));
+        return null;
+    }
+}
+
+class MyErrorHandler implements ErrorHandler {
+
+    // Logger
+    private Log log = LogFactory.getLog(MyErrorHandler.class);
+
+    public void warning(SAXParseException ex) throws SAXException {
+        if (log.isDebugEnabled())
+            log.debug("ParserUtils: warning ", ex);
+        // We ignore warnings
+    }
+
+    public void error(SAXParseException ex) throws SAXException {
+        throw ex;
+    }
+
+    public void fatalError(SAXParseException ex) throws SAXException {
+        throw ex;
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/xmlparser/SymbolTable.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/xmlparser/SymbolTable.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/xmlparser/SymbolTable.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,301 @@
+/*
+ * Copyright 1999,2004-2005 The Apache Software Foundation.
+ * 
+ * Licensed 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.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation and was
+ * originally based on software copyright (c) 1999, International
+ * Business Machines, Inc., http://www.apache.org.  For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ */
+
+package org.apache.jasper.xmlparser;
+
+/**
+ * This class is a symbol table implementation that guarantees that
+ * strings used as identifiers are unique references. Multiple calls
+ * to <code>addSymbol</code> will always return the same string
+ * reference.
+ * <p>
+ * The symbol table performs the same task as <code>String.intern()</code>
+ * with the following differences:
+ * <ul>
+ *  <li>
+ *   A new string object does not need to be created in order to
+ *   retrieve a unique reference. Symbols can be added by using
+ *   a series of characters in a character array.
+ *  </li>
+ *  <li>
+ *   Users of the symbol table can provide their own symbol hashing
+ *   implementation. For example, a simple string hashing algorithm
+ *   may fail to produce a balanced set of hashcodes for symbols
+ *   that are <em>mostly</em> unique. Strings with similar leading
+ *   characters are especially prone to this poor hashing behavior.
+ *  </li>
+ * </ul>
+ *
+ * @author Andy Clark
+ * @version $Id: SymbolTable.java 306179 2005-07-27 15:12:04Z yoavs $
+ */
+public class SymbolTable {
+
+    //
+    // Constants
+    //
+
+    /** Default table size. */
+    protected static final int TABLE_SIZE = 101;
+
+    //
+    // Data
+    //
+
+    /** Buckets. */
+    protected Entry[] fBuckets = null;
+
+    // actual table size
+    protected int fTableSize;
+
+    //
+    // Constructors
+    //
+
+    /** Constructs a symbol table with a default number of buckets. */
+    public SymbolTable() {
+        this(TABLE_SIZE);
+    }
+
+    /** Constructs a symbol table with a specified number of buckets. */
+    public SymbolTable(int tableSize) {
+        fTableSize = tableSize;
+        fBuckets = new Entry[fTableSize];
+    }
+
+    //
+    // Public methods
+    //
+
+    /**
+     * Adds the specified symbol to the symbol table and returns a
+     * reference to the unique symbol. If the symbol already exists,
+     * the previous symbol reference is returned instead, in order
+     * guarantee that symbol references remain unique.
+     *
+     * @param symbol The new symbol.
+     */
+    public String addSymbol(String symbol) {
+
+        // search for identical symbol
+        int bucket = hash(symbol) % fTableSize;
+        int length = symbol.length();
+        OUTER: for (Entry entry = fBuckets[bucket]; entry != null; entry = entry.next) {
+            if (length == entry.characters.length) {
+                for (int i = 0; i < length; i++) {
+                    if (symbol.charAt(i) != entry.characters[i]) {
+                        continue OUTER;
+                    }
+                }
+                return entry.symbol;
+            }
+        }
+
+        // create new entry
+        Entry entry = new Entry(symbol, fBuckets[bucket]);
+        fBuckets[bucket] = entry;
+        return entry.symbol;
+
+    } // addSymbol(String):String
+
+    /**
+     * Adds the specified symbol to the symbol table and returns a
+     * reference to the unique symbol. If the symbol already exists,
+     * the previous symbol reference is returned instead, in order
+     * guarantee that symbol references remain unique.
+     *
+     * @param buffer The buffer containing the new symbol.
+     * @param offset The offset into the buffer of the new symbol.
+     * @param length The length of the new symbol in the buffer.
+     */
+    public String addSymbol(char[] buffer, int offset, int length) {
+
+        // search for identical symbol
+        int bucket = hash(buffer, offset, length) % fTableSize;
+        OUTER: for (Entry entry = fBuckets[bucket]; entry != null; entry = entry.next) {
+            if (length == entry.characters.length) {
+                for (int i = 0; i < length; i++) {
+                    if (buffer[offset + i] != entry.characters[i]) {
+                        continue OUTER;
+                    }
+                }
+                return entry.symbol;
+            }
+        }
+
+        // add new entry
+        Entry entry = new Entry(buffer, offset, length, fBuckets[bucket]);
+        fBuckets[bucket] = entry;
+        return entry.symbol;
+
+    } // addSymbol(char[],int,int):String
+
+    /**
+     * Returns a hashcode value for the specified symbol. The value
+     * returned by this method must be identical to the value returned
+     * by the <code>hash(char[],int,int)</code> method when called
+     * with the character array that comprises the symbol string.
+     *
+     * @param symbol The symbol to hash.
+     */
+    public int hash(String symbol) {
+
+        int code = 0;
+        int length = symbol.length();
+        for (int i = 0; i < length; i++) {
+            code = code * 37 + symbol.charAt(i);
+        }
+        return code & 0x7FFFFFF;
+
+    } // hash(String):int
+
+    /**
+     * Returns a hashcode value for the specified symbol information.
+     * The value returned by this method must be identical to the value
+     * returned by the <code>hash(String)</code> method when called
+     * with the string object created from the symbol information.
+     *
+     * @param buffer The character buffer containing the symbol.
+     * @param offset The offset into the character buffer of the start
+     *               of the symbol.
+     * @param length The length of the symbol.
+     */
+    public int hash(char[] buffer, int offset, int length) {
+
+        int code = 0;
+        for (int i = 0; i < length; i++) {
+            code = code * 37 + buffer[offset + i];
+        }
+        return code & 0x7FFFFFF;
+
+    } // hash(char[],int,int):int
+
+    /**
+     * Returns true if the symbol table already contains the specified
+     * symbol.
+     *
+     * @param symbol The symbol to look for.
+     */
+    public boolean containsSymbol(String symbol) {
+
+        // search for identical symbol
+        int bucket = hash(symbol) % fTableSize;
+        int length = symbol.length();
+        OUTER: for (Entry entry = fBuckets[bucket]; entry != null; entry = entry.next) {
+            if (length == entry.characters.length) {
+                for (int i = 0; i < length; i++) {
+                    if (symbol.charAt(i) != entry.characters[i]) {
+                        continue OUTER;
+                    }
+                }
+                return true;
+            }
+        }
+
+        return false;
+
+    } // containsSymbol(String):boolean
+
+    /**
+     * Returns true if the symbol table already contains the specified
+     * symbol.
+     *
+     * @param buffer The buffer containing the symbol to look for.
+     * @param offset The offset into the buffer.
+     * @param length The length of the symbol in the buffer.
+     */
+    public boolean containsSymbol(char[] buffer, int offset, int length) {
+
+        // search for identical symbol
+        int bucket = hash(buffer, offset, length) % fTableSize;
+        OUTER: for (Entry entry = fBuckets[bucket]; entry != null; entry = entry.next) {
+            if (length == entry.characters.length) {
+                for (int i = 0; i < length; i++) {
+                    if (buffer[offset + i] != entry.characters[i]) {
+                        continue OUTER;
+                    }
+                }
+                return true;
+            }
+        }
+
+        return false;
+
+    } // containsSymbol(char[],int,int):boolean
+
+    //
+    // Classes
+    //
+
+    /**
+     * This class is a symbol table entry. Each entry acts as a node
+     * in a linked list.
+     */
+    protected static final class Entry {
+
+        //
+        // Data
+        //
+
+        /** Symbol. */
+        public String symbol;
+
+        /**
+         * Symbol characters. This information is duplicated here for
+         * comparison performance.
+         */
+        public char[] characters;
+
+        /** The next entry. */
+        public Entry next;
+
+        //
+        // Constructors
+        //
+
+        /**
+         * Constructs a new entry from the specified symbol and next entry
+         * reference.
+         */
+        public Entry(String symbol, Entry next) {
+            this.symbol = symbol.intern();
+            characters = new char[symbol.length()];
+            symbol.getChars(0, characters.length, characters, 0);
+            this.next = next;
+        }
+
+        /**
+         * Constructs a new entry from the specified symbol information and
+         * next entry reference.
+         */
+        public Entry(char[] ch, int offset, int length, Entry next) {
+            characters = new char[length];
+            System.arraycopy(ch, offset, characters, 0, length);
+            symbol = new String(characters).intern();
+            this.next = next;
+        }
+
+    } // class Entry
+
+} // class SymbolTable

Added: branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/xmlparser/TreeNode.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/xmlparser/TreeNode.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/xmlparser/TreeNode.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,359 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.xmlparser;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+
+
+/**
+ * Simplified implementation of a Node from a Document Object Model (DOM)
+ * parse of an XML document.  This class is used to represent a DOM tree
+ * so that the XML parser's implementation of <code>org.w3c.dom</code> need
+ * not be visible to the remainder of Jasper.
+ * <p>
+ * <strong>WARNING</strong> - Construction of a new tree, or modifications
+ * to an existing one, are not thread-safe and such accesses must be
+ * synchronized.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 305933 $ $Date: 2004-03-17 13:23:05 -0600 (Wed, 17 Mar 2004) $
+ */
+
+public class TreeNode {
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Construct a new node with no parent.
+     *
+     * @param name The name of this node
+     */
+    public TreeNode(String name) {
+
+        this(name, null);
+
+    }
+
+
+    /**
+     * Construct a new node with the specified parent.
+     *
+     * @param name The name of this node
+     * @param parent The node that is the parent of this node
+     */
+    public TreeNode(String name, TreeNode parent) {
+
+        super();
+        this.name = name;
+        this.parent = parent;
+        if (this.parent != null)
+            this.parent.addChild(this);
+
+    }
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The attributes of this node, keyed by attribute name,
+     * Instantiated only if required.
+     */
+    protected HashMap attributes = null;
+
+
+    /**
+     * The body text associated with this node (if any).
+     */
+    protected String body = null;
+
+
+    /**
+     * The children of this node, instantiated only if required.
+     */
+    protected ArrayList children = null;
+
+
+    /**
+     * The name of this node.
+     */
+    protected String name = null;
+
+
+    /**
+     * The parent node of this node.
+     */
+    protected TreeNode parent = null;
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Add an attribute to this node, replacing any existing attribute
+     * with the same name.
+     *
+     * @param name The attribute name to add
+     * @param value The new attribute value
+     */
+    public void addAttribute(String name, String value) {
+
+        if (attributes == null)
+            attributes = new HashMap();
+        attributes.put(name, value);
+
+    }
+
+
+    /**
+     * Add a new child node to this node.
+     *
+     * @param node The new child node
+     */
+    public void addChild(TreeNode node) {
+
+        if (children == null)
+            children = new ArrayList();
+        children.add(node);
+
+    }
+
+
+    /**
+     * Return the value of the specified node attribute if it exists, or
+     * <code>null</code> otherwise.
+     *
+     * @param name Name of the requested attribute
+     */
+    public String findAttribute(String name) {
+
+        if (attributes == null)
+            return (null);
+        else
+            return ((String) attributes.get(name));
+
+    }
+
+
+    /**
+     * Return an Iterator of the attribute names of this node.  If there are
+     * no attributes, an empty Iterator is returned.
+     */
+    public Iterator findAttributes() {
+
+        if (attributes == null)
+            return (Collections.EMPTY_LIST.iterator());
+        else
+            return (attributes.keySet().iterator());
+
+    }
+
+
+    /**
+     * Return the first child node of this node with the specified name,
+     * if there is one; otherwise, return <code>null</code>.
+     *
+     * @param name Name of the desired child element
+     */
+    public TreeNode findChild(String name) {
+
+        if (children == null)
+            return (null);
+        Iterator items = children.iterator();
+        while (items.hasNext()) {
+            TreeNode item = (TreeNode) items.next();
+            if (name.equals(item.getName()))
+                return (item);
+        }
+        return (null);
+
+    }
+
+
+    /**
+     * Return an Iterator of all children of this node.  If there are no
+     * children, an empty Iterator is returned.
+     */
+    public Iterator findChildren() {
+
+        if (children == null)
+            return (Collections.EMPTY_LIST.iterator());
+        else
+            return (children.iterator());
+
+    }
+
+
+    /**
+     * Return an Iterator over all children of this node that have the
+     * specified name.  If there are no such children, an empty Iterator
+     * is returned.
+     *
+     * @param name Name used to select children
+     */
+    public Iterator findChildren(String name) {
+
+        if (children == null)
+            return (Collections.EMPTY_LIST.iterator());
+
+        ArrayList results = new ArrayList();
+        Iterator items = children.iterator();
+        while (items.hasNext()) {
+            TreeNode item = (TreeNode) items.next();
+            if (name.equals(item.getName()))
+                results.add(item);
+        }
+        return (results.iterator());
+
+    }
+
+
+    /**
+     * Return the body text associated with this node (if any).
+     */
+    public String getBody() {
+
+        return (this.body);
+
+    }
+
+
+    /**
+     * Return the name of this node.
+     */
+    public String getName() {
+
+        return (this.name);
+
+    }
+
+
+    /**
+     * Remove any existing value for the specified attribute name.
+     *
+     * @param name The attribute name to remove
+     */
+    public void removeAttribute(String name) {
+
+        if (attributes != null)
+            attributes.remove(name);
+
+    }
+
+
+    /**
+     * Remove a child node from this node, if it is one.
+     *
+     * @param node The child node to remove
+     */
+    public void removeNode(TreeNode node) {
+
+        if (children != null)
+            children.remove(node);
+
+    }
+
+
+    /**
+     * Set the body text associated with this node (if any).
+     *
+     * @param body The body text (if any)
+     */
+    public void setBody(String body) {
+
+        this.body = body;
+
+    }
+
+
+    /**
+     * Return a String representation of this TreeNode.
+     */
+    public String toString() {
+
+        StringBuffer sb = new StringBuffer();
+        toString(sb, 0, this);
+        return (sb.toString());
+
+    }
+
+
+    // ------------------------------------------------------ Protected Methods
+
+
+    /**
+     * Append to the specified StringBuffer a character representation of
+     * this node, with the specified amount of indentation.
+     *
+     * @param sb The StringBuffer to append to
+     * @param indent Number of characters of indentation
+     * @param node The TreeNode to be printed
+     */
+    protected void toString(StringBuffer sb, int indent,
+                            TreeNode node) {
+
+        int indent2 = indent + 2;
+
+        // Reconstruct an opening node
+        for (int i = 0; i < indent; i++)
+            sb.append(' ');
+        sb.append('<');
+        sb.append(node.getName());
+        Iterator names = node.findAttributes();
+        while (names.hasNext()) {
+            sb.append(' ');
+            String name = (String) names.next();
+            sb.append(name);
+            sb.append("=\"");
+            String value = node.findAttribute(name);
+            sb.append(value);
+            sb.append("\"");
+        }
+        sb.append(">\n");
+
+        // Reconstruct the body text of this node (if any)
+        String body = node.getBody();
+        if ((body != null) && (body.length() > 0)) {
+            for (int i = 0; i < indent2; i++)
+                sb.append(' ');
+            sb.append(body);
+            sb.append("\n");
+        }
+
+        // Reconstruct child nodes with extra indentation
+        Iterator children = node.findChildren();
+        while (children.hasNext()) {
+            TreeNode child = (TreeNode) children.next();
+            toString(sb, indent2, child);
+        }
+
+        // Reconstruct a closing node marker
+        for (int i = 0; i < indent; i++)
+            sb.append(' ');
+        sb.append("</");
+        sb.append(node.getName());
+        sb.append(">\n");
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/xmlparser/UCSReader.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/xmlparser/UCSReader.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/xmlparser/UCSReader.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,300 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.xmlparser;
+
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.Reader;
+
+/** 
+ * Reader for UCS-2 and UCS-4 encodings.
+ * (i.e., encodings from ISO-10646-UCS-(2|4)).
+ *
+ * @author Neil Graham, IBM
+ *
+ * @version $Id: UCSReader.java 306148 2005-03-21 15:38:13Z remm $
+ */
+public class UCSReader extends Reader {
+
+    private org.apache.commons.logging.Log log=
+        org.apache.commons.logging.LogFactory.getLog( UCSReader.class );
+    
+    //
+    // Constants
+    //
+
+    /** Default byte buffer size (8192, larger than that of ASCIIReader
+     * since it's reasonable to surmise that the average UCS-4-encoded
+     * file should be 4 times as large as the average ASCII-encoded file). 
+     */
+    public static final int DEFAULT_BUFFER_SIZE = 8192;
+
+    public static final short UCS2LE = 1;
+    public static final short UCS2BE = 2;
+    public static final short UCS4LE = 4;
+    public static final short UCS4BE = 8;
+
+    //
+    // Data
+    //
+
+    /** Input stream. */
+    protected InputStream fInputStream;
+
+    /** Byte buffer. */
+    protected byte[] fBuffer;
+
+    // what kind of data we're dealing with
+    protected short fEncoding;
+
+    //
+    // Constructors
+    //
+
+    /** 
+     * Constructs an ASCII reader from the specified input stream 
+     * using the default buffer size.  The Endian-ness and whether this is
+     * UCS-2 or UCS-4 needs also to be known in advance.
+     *
+     * @param inputStream The input stream.
+     * @param encoding One of UCS2LE, UCS2BE, UCS4LE or UCS4BE.
+     */
+    public UCSReader(InputStream inputStream, short encoding) {
+        this(inputStream, DEFAULT_BUFFER_SIZE, encoding);
+    } // <init>(InputStream, short)
+
+    /** 
+     * Constructs an ASCII reader from the specified input stream 
+     * and buffer size.  The Endian-ness and whether this is
+     * UCS-2 or UCS-4 needs also to be known in advance.
+     *
+     * @param inputStream The input stream.
+     * @param size        The initial buffer size.
+     * @param encoding One of UCS2LE, UCS2BE, UCS4LE or UCS4BE.
+     */
+    public UCSReader(InputStream inputStream, int size, short encoding) {
+        fInputStream = inputStream;
+        fBuffer = new byte[size];
+        fEncoding = encoding;
+    } // <init>(InputStream,int,short)
+
+    //
+    // Reader methods
+    //
+
+    /**
+     * Read a single character.  This method will block until a character is
+     * available, an I/O error occurs, or the end of the stream is reached.
+     *
+     * <p> Subclasses that intend to support efficient single-character input
+     * should override this method.
+     *
+     * @return     The character read, as an integer in the range 0 to 127
+     *             (<tt>0x00-0x7f</tt>), or -1 if the end of the stream has
+     *             been reached
+     *
+     * @exception  IOException  If an I/O error occurs
+     */
+    public int read() throws IOException { 
+        int b0 = fInputStream.read() & 0xff;
+        if (b0 == 0xff)
+            return -1;
+        int b1 = fInputStream.read() & 0xff;
+        if (b1 == 0xff)
+            return -1;
+        if(fEncoding >=4) {
+            int b2 = fInputStream.read() & 0xff;
+            if (b2 == 0xff)
+                return -1;
+            int b3 = fInputStream.read() & 0xff;
+            if (b3 == 0xff)
+                return -1;
+            if (log.isDebugEnabled())
+                log.debug("b0 is " + (b0 & 0xff) + " b1 " + (b1 & 0xff) + " b2 " + (b2 & 0xff) + " b3 " + (b3 & 0xff));
+            if (fEncoding == UCS4BE)
+                return (b0<<24)+(b1<<16)+(b2<<8)+b3;
+            else
+                return (b3<<24)+(b2<<16)+(b1<<8)+b0;
+        } else { // UCS-2
+            if (fEncoding == UCS2BE)
+                return (b0<<8)+b1;
+            else
+                return (b1<<8)+b0;
+        }
+    } // read():int
+
+    /**
+     * Read characters into a portion of an array.  This method will block
+     * until some input is available, an I/O error occurs, or the end of the
+     * stream is reached.
+     *
+     * @param      ch     Destination buffer
+     * @param      offset Offset at which to start storing characters
+     * @param      length Maximum number of characters to read
+     *
+     * @return     The number of characters read, or -1 if the end of the
+     *             stream has been reached
+     *
+     * @exception  IOException  If an I/O error occurs
+     */
+    public int read(char ch[], int offset, int length) throws IOException {
+        int byteLength = length << ((fEncoding >= 4)?2:1);
+        if (byteLength > fBuffer.length) {
+            byteLength = fBuffer.length;
+        }
+        int count = fInputStream.read(fBuffer, 0, byteLength);
+        if(count == -1) return -1;
+        // try and make count be a multiple of the number of bytes we're looking for
+        if(fEncoding >= 4) { // BigEndian
+            // this looks ugly, but it avoids an if at any rate...
+            int numToRead = (4 - (count & 3) & 3);
+            for(int i=0; i<numToRead; i++) {
+                int charRead = fInputStream.read();
+                if(charRead == -1) { // end of input; something likely went wrong!A  Pad buffer with nulls.
+                    for (int j = i;j<numToRead; j++)
+                        fBuffer[count+j] = 0;
+                    break;
+                } else {
+                    fBuffer[count+i] = (byte)charRead; 
+                }
+            }
+            count += numToRead;
+        } else {
+            int numToRead = count & 1;
+            if(numToRead != 0) {
+                count++;
+                int charRead = fInputStream.read();
+                if(charRead == -1) { // end of input; something likely went wrong!A  Pad buffer with nulls.
+                    fBuffer[count] = 0;
+                } else {
+                    fBuffer[count] = (byte)charRead;
+                }
+            }
+        }
+
+        // now count is a multiple of the right number of bytes
+        int numChars = count >> ((fEncoding >= 4)?2:1);
+        int curPos = 0;
+        for (int i = 0; i < numChars; i++) {
+            int b0 = fBuffer[curPos++] & 0xff;
+            int b1 = fBuffer[curPos++] & 0xff;
+            if(fEncoding >=4) {
+                int b2 = fBuffer[curPos++] & 0xff;
+                int b3 = fBuffer[curPos++] & 0xff;
+                if (fEncoding == UCS4BE)
+                    ch[offset+i] = (char)((b0<<24)+(b1<<16)+(b2<<8)+b3);
+                else
+                    ch[offset+i] = (char)((b3<<24)+(b2<<16)+(b1<<8)+b0);
+            } else { // UCS-2
+                if (fEncoding == UCS2BE)
+                    ch[offset+i] = (char)((b0<<8)+b1);
+                else
+                    ch[offset+i] = (char)((b1<<8)+b0);
+            }
+        }
+        return numChars;
+    } // read(char[],int,int)
+
+    /**
+     * Skip characters.  This method will block until some characters are
+     * available, an I/O error occurs, or the end of the stream is reached.
+     *
+     * @param  n  The number of characters to skip
+     *
+     * @return    The number of characters actually skipped
+     *
+     * @exception  IOException  If an I/O error occurs
+     */
+    public long skip(long n) throws IOException {
+        // charWidth will represent the number of bits to move
+        // n leftward to get num of bytes to skip, and then move the result rightward
+        // to get num of chars effectively skipped.
+        // The trick with &'ing, as with elsewhere in this dcode, is
+        // intended to avoid an expensive use of / that might not be optimized
+        // away.
+        int charWidth = (fEncoding >=4)?2:1;
+        long bytesSkipped = fInputStream.skip(n<<charWidth);
+        if((bytesSkipped & (charWidth | 1)) == 0) return bytesSkipped >> charWidth;
+        return (bytesSkipped >> charWidth) + 1;
+    } // skip(long):long
+
+    /**
+     * Tell whether this stream is ready to be read.
+     *
+     * @return True if the next read() is guaranteed not to block for input,
+     * false otherwise.  Note that returning false does not guarantee that the
+     * next read will block.
+     *
+     * @exception  IOException  If an I/O error occurs
+     */
+    public boolean ready() throws IOException {
+	return false;
+    } // ready()
+
+    /**
+     * Tell whether this stream supports the mark() operation.
+     */
+    public boolean markSupported() {
+	return fInputStream.markSupported();
+    } // markSupported()
+
+    /**
+     * Mark the present position in the stream.  Subsequent calls to reset()
+     * will attempt to reposition the stream to this point.  Not all
+     * character-input streams support the mark() operation.
+     *
+     * @param  readAheadLimit  Limit on the number of characters that may be
+     *                         read while still preserving the mark.  After
+     *                         reading this many characters, attempting to
+     *                         reset the stream may fail.
+     *
+     * @exception  IOException  If the stream does not support mark(),
+     *                          or if some other I/O error occurs
+     */
+    public void mark(int readAheadLimit) throws IOException {
+	fInputStream.mark(readAheadLimit);
+    } // mark(int)
+
+    /**
+     * Reset the stream.  If the stream has been marked, then attempt to
+     * reposition it at the mark.  If the stream has not been marked, then
+     * attempt to reset it in some way appropriate to the particular stream,
+     * for example by repositioning it to its starting point.  Not all
+     * character-input streams support the reset() operation, and some support
+     * reset() without supporting mark().
+     *
+     * @exception  IOException  If the stream has not been marked,
+     *                          or if the mark has been invalidated,
+     *                          or if the stream does not support reset(),
+     *                          or if some other I/O error occurs
+     */
+    public void reset() throws IOException {
+        fInputStream.reset();
+    } // reset()
+
+    /**
+     * Close the stream.  Once a stream has been closed, further read(),
+     * ready(), mark(), or reset() invocations will throw an IOException.
+     * Closing a previously-closed stream, however, has no effect.
+     *
+     * @exception  IOException  If an I/O error occurs
+     */
+     public void close() throws IOException {
+         fInputStream.close();
+     } // close()
+
+} // class UCSReader

Added: branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/xmlparser/UTF8Reader.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/xmlparser/UTF8Reader.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/xmlparser/UTF8Reader.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,634 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.xmlparser;
+
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.Reader;
+import java.io.UTFDataFormatException;
+import org.apache.jasper.compiler.Localizer;
+
+/**
+ * @author Andy Clark, IBM
+ *
+ * @version $Id: UTF8Reader.java 306148 2005-03-21 15:38:13Z remm $
+ */
+public class UTF8Reader
+    extends Reader {
+
+    private org.apache.commons.logging.Log log=
+        org.apache.commons.logging.LogFactory.getLog( UTF8Reader.class );
+    
+    //
+    // Constants
+    //
+
+    /** Default byte buffer size (2048). */
+    public static final int DEFAULT_BUFFER_SIZE = 2048;
+
+    // debugging
+
+    /** Debug read. */
+    private static final boolean DEBUG_READ = false;
+
+    //
+    // Data
+    //
+
+    /** Input stream. */
+    protected InputStream fInputStream;
+
+    /** Byte buffer. */
+    protected byte[] fBuffer;
+
+    /** Offset into buffer. */
+    protected int fOffset;
+
+    /** Surrogate character. */
+    private int fSurrogate = -1;
+
+    //
+    // Constructors
+    //
+
+    /** 
+     * Constructs a UTF-8 reader from the specified input stream, 
+     * buffer size and MessageFormatter.
+     *
+     * @param inputStream The input stream.
+     * @param size        The initial buffer size.
+     */
+    public UTF8Reader(InputStream inputStream, int size) {
+        fInputStream = inputStream;
+        fBuffer = new byte[size];
+    }
+
+    //
+    // Reader methods
+    //
+
+    /**
+     * Read a single character.  This method will block until a character is
+     * available, an I/O error occurs, or the end of the stream is reached.
+     *
+     * <p> Subclasses that intend to support efficient single-character input
+     * should override this method.
+     *
+     * @return     The character read, as an integer in the range 0 to 16383
+     *             (<tt>0x00-0xffff</tt>), or -1 if the end of the stream has
+     *             been reached
+     *
+     * @exception  IOException  If an I/O error occurs
+     */
+    public int read() throws IOException {
+
+        // decode character
+        int c = fSurrogate;
+        if (fSurrogate == -1) {
+            // NOTE: We use the index into the buffer if there are remaining
+            //       bytes from the last block read. -Ac
+            int index = 0;
+
+            // get first byte
+            int b0 = index == fOffset 
+                   ? fInputStream.read() : fBuffer[index++] & 0x00FF;
+            if (b0 == -1) {
+                return -1;
+            }
+
+            // UTF-8:   [0xxx xxxx]
+            // Unicode: [0000 0000] [0xxx xxxx]
+            if (b0 < 0x80) {
+                c = (char)b0;
+            }
+
+            // UTF-8:   [110y yyyy] [10xx xxxx]
+            // Unicode: [0000 0yyy] [yyxx xxxx]
+            else if ((b0 & 0xE0) == 0xC0) {
+                int b1 = index == fOffset 
+                       ? fInputStream.read() : fBuffer[index++] & 0x00FF;
+                if (b1 == -1) {
+                    expectedByte(2, 2);
+                }
+                if ((b1 & 0xC0) != 0x80) {
+                    invalidByte(2, 2, b1);
+                }
+                c = ((b0 << 6) & 0x07C0) | (b1 & 0x003F);
+            }
+
+            // UTF-8:   [1110 zzzz] [10yy yyyy] [10xx xxxx]
+            // Unicode: [zzzz yyyy] [yyxx xxxx]
+            else if ((b0 & 0xF0) == 0xE0) {
+                int b1 = index == fOffset
+                       ? fInputStream.read() : fBuffer[index++] & 0x00FF;
+                if (b1 == -1) {
+                    expectedByte(2, 3);
+                }
+                if ((b1 & 0xC0) != 0x80) {
+                    invalidByte(2, 3, b1);
+                }
+                int b2 = index == fOffset 
+                       ? fInputStream.read() : fBuffer[index++] & 0x00FF;
+                if (b2 == -1) {
+                    expectedByte(3, 3);
+                }
+                if ((b2 & 0xC0) != 0x80) {
+                    invalidByte(3, 3, b2);
+                }
+                c = ((b0 << 12) & 0xF000) | ((b1 << 6) & 0x0FC0) |
+                    (b2 & 0x003F);
+            }
+
+            // UTF-8:   [1111 0uuu] [10uu zzzz] [10yy yyyy] [10xx xxxx]*
+            // Unicode: [1101 10ww] [wwzz zzyy] (high surrogate)
+            //          [1101 11yy] [yyxx xxxx] (low surrogate)
+            //          * uuuuu = wwww + 1
+            else if ((b0 & 0xF8) == 0xF0) {
+                int b1 = index == fOffset 
+                       ? fInputStream.read() : fBuffer[index++] & 0x00FF;
+                if (b1 == -1) {
+                    expectedByte(2, 4);
+                }
+                if ((b1 & 0xC0) != 0x80) {
+                    invalidByte(2, 3, b1);
+                }
+                int b2 = index == fOffset 
+                       ? fInputStream.read() : fBuffer[index++] & 0x00FF;
+                if (b2 == -1) {
+                    expectedByte(3, 4);
+                }
+                if ((b2 & 0xC0) != 0x80) {
+                    invalidByte(3, 3, b2);
+                }
+                int b3 = index == fOffset 
+                       ? fInputStream.read() : fBuffer[index++] & 0x00FF;
+                if (b3 == -1) {
+                    expectedByte(4, 4);
+                }
+                if ((b3 & 0xC0) != 0x80) {
+                    invalidByte(4, 4, b3);
+                }
+                int uuuuu = ((b0 << 2) & 0x001C) | ((b1 >> 4) & 0x0003);
+                if (uuuuu > 0x10) {
+                    invalidSurrogate(uuuuu);
+                }
+                int wwww = uuuuu - 1;
+                int hs = 0xD800 | 
+                         ((wwww << 6) & 0x03C0) | ((b1 << 2) & 0x003C) | 
+                         ((b2 >> 4) & 0x0003);
+                int ls = 0xDC00 | ((b2 << 6) & 0x03C0) | (b3 & 0x003F);
+                c = hs;
+                fSurrogate = ls;
+            }
+
+            // error
+            else {
+                invalidByte(1, 1, b0);
+            }
+        }
+
+        // use surrogate
+        else {
+            fSurrogate = -1;
+        }
+
+        // return character
+        if (DEBUG_READ) {
+            if (log.isDebugEnabled())
+                log.debug("read(): 0x"+Integer.toHexString(c));
+        }
+        return c;
+
+    } // read():int
+
+    /**
+     * Read characters into a portion of an array.  This method will block
+     * until some input is available, an I/O error occurs, or the end of the
+     * stream is reached.
+     *
+     * @param      ch     Destination buffer
+     * @param      offset Offset at which to start storing characters
+     * @param      length Maximum number of characters to read
+     *
+     * @return     The number of characters read, or -1 if the end of the
+     *             stream has been reached
+     *
+     * @exception  IOException  If an I/O error occurs
+     */
+    public int read(char ch[], int offset, int length) throws IOException {
+
+        // handle surrogate
+        int out = offset;
+        if (fSurrogate != -1) {
+            ch[offset + 1] = (char)fSurrogate;
+            fSurrogate = -1;
+            length--;
+            out++;
+        }
+
+        // read bytes
+        int count = 0;
+        if (fOffset == 0) {
+            // adjust length to read
+            if (length > fBuffer.length) {
+                length = fBuffer.length;
+            }
+
+            // perform read operation
+            count = fInputStream.read(fBuffer, 0, length);
+            if (count == -1) {
+                return -1;
+            }
+            count += out - offset;
+        }
+
+        // skip read; last character was in error
+        // NOTE: Having an offset value other than zero means that there was
+        //       an error in the last character read. In this case, we have
+        //       skipped the read so we don't consume any bytes past the 
+        //       error. By signalling the error on the next block read we
+        //       allow the method to return the most valid characters that
+        //       it can on the previous block read. -Ac
+        else {
+            count = fOffset;
+            fOffset = 0;
+        }
+
+        // convert bytes to characters
+        final int total = count;
+        for (int in = 0; in < total; in++) {
+            int b0 = fBuffer[in] & 0x00FF;
+
+            // UTF-8:   [0xxx xxxx]
+            // Unicode: [0000 0000] [0xxx xxxx]
+            if (b0 < 0x80) {
+                ch[out++] = (char)b0;
+                continue;
+            }
+
+            // UTF-8:   [110y yyyy] [10xx xxxx]
+            // Unicode: [0000 0yyy] [yyxx xxxx]
+            if ((b0 & 0xE0) == 0xC0) {
+                int b1 = -1;
+                if (++in < total) { 
+                    b1 = fBuffer[in] & 0x00FF; 
+                }
+                else {
+                    b1 = fInputStream.read();
+                    if (b1 == -1) {
+                        if (out > offset) {
+                            fBuffer[0] = (byte)b0;
+                            fOffset = 1;
+                            return out - offset;
+                        }
+                        expectedByte(2, 2);
+                    }
+                    count++;
+                }
+                if ((b1 & 0xC0) != 0x80) {
+                    if (out > offset) {
+                        fBuffer[0] = (byte)b0;
+                        fBuffer[1] = (byte)b1;
+                        fOffset = 2;
+                        return out - offset;
+                    }
+                    invalidByte(2, 2, b1);
+                }
+                int c = ((b0 << 6) & 0x07C0) | (b1 & 0x003F);
+                ch[out++] = (char)c;
+                count -= 1;
+                continue;
+            }
+
+            // UTF-8:   [1110 zzzz] [10yy yyyy] [10xx xxxx]
+            // Unicode: [zzzz yyyy] [yyxx xxxx]
+            if ((b0 & 0xF0) == 0xE0) {
+                int b1 = -1;
+                if (++in < total) { 
+                    b1 = fBuffer[in] & 0x00FF; 
+                }
+                else {
+                    b1 = fInputStream.read();
+                    if (b1 == -1) {
+                        if (out > offset) {
+                            fBuffer[0] = (byte)b0;
+                            fOffset = 1;
+                            return out - offset;
+                        }
+                        expectedByte(2, 3);
+                    }
+                    count++;
+                }
+                if ((b1 & 0xC0) != 0x80) {
+                    if (out > offset) {
+                        fBuffer[0] = (byte)b0;
+                        fBuffer[1] = (byte)b1;
+                        fOffset = 2;
+                        return out - offset;
+                    }
+                    invalidByte(2, 3, b1);
+                }
+                int b2 = -1;
+                if (++in < total) { 
+                    b2 = fBuffer[in] & 0x00FF; 
+                }
+                else {
+                    b2 = fInputStream.read();
+                    if (b2 == -1) {
+                        if (out > offset) {
+                            fBuffer[0] = (byte)b0;
+                            fBuffer[1] = (byte)b1;
+                            fOffset = 2;
+                            return out - offset;
+                        }
+                        expectedByte(3, 3);
+                    }
+                    count++;
+                }
+                if ((b2 & 0xC0) != 0x80) {
+                    if (out > offset) {
+                        fBuffer[0] = (byte)b0;
+                        fBuffer[1] = (byte)b1;
+                        fBuffer[2] = (byte)b2;
+                        fOffset = 3;
+                        return out - offset;
+                    }
+                    invalidByte(3, 3, b2);
+                }
+                int c = ((b0 << 12) & 0xF000) | ((b1 << 6) & 0x0FC0) |
+                        (b2 & 0x003F);
+                ch[out++] = (char)c;
+                count -= 2;
+                continue;
+            }
+
+            // UTF-8:   [1111 0uuu] [10uu zzzz] [10yy yyyy] [10xx xxxx]*
+            // Unicode: [1101 10ww] [wwzz zzyy] (high surrogate)
+            //          [1101 11yy] [yyxx xxxx] (low surrogate)
+            //          * uuuuu = wwww + 1
+            if ((b0 & 0xF8) == 0xF0) {
+                int b1 = -1;
+                if (++in < total) { 
+                    b1 = fBuffer[in] & 0x00FF; 
+                }
+                else {
+                    b1 = fInputStream.read();
+                    if (b1 == -1) {
+                        if (out > offset) {
+                            fBuffer[0] = (byte)b0;
+                            fOffset = 1;
+                            return out - offset;
+                        }
+                        expectedByte(2, 4);
+                    }
+                    count++;
+                }
+                if ((b1 & 0xC0) != 0x80) {
+                    if (out > offset) {
+                        fBuffer[0] = (byte)b0;
+                        fBuffer[1] = (byte)b1;
+                        fOffset = 2;
+                        return out - offset;
+                    }
+                    invalidByte(2, 4, b1);
+                }
+                int b2 = -1;
+                if (++in < total) { 
+                    b2 = fBuffer[in] & 0x00FF; 
+                }
+                else {
+                    b2 = fInputStream.read();
+                    if (b2 == -1) {
+                        if (out > offset) {
+                            fBuffer[0] = (byte)b0;
+                            fBuffer[1] = (byte)b1;
+                            fOffset = 2;
+                            return out - offset;
+                        }
+                        expectedByte(3, 4);
+                    }
+                    count++;
+                }
+                if ((b2 & 0xC0) != 0x80) {
+                    if (out > offset) {
+                        fBuffer[0] = (byte)b0;
+                        fBuffer[1] = (byte)b1;
+                        fBuffer[2] = (byte)b2;
+                        fOffset = 3;
+                        return out - offset;
+                    }
+                    invalidByte(3, 4, b2);
+                }
+                int b3 = -1;
+                if (++in < total) { 
+                    b3 = fBuffer[in] & 0x00FF; 
+                }
+                else {
+                    b3 = fInputStream.read();
+                    if (b3 == -1) {
+                        if (out > offset) {
+                            fBuffer[0] = (byte)b0;
+                            fBuffer[1] = (byte)b1;
+                            fBuffer[2] = (byte)b2;
+                            fOffset = 3;
+                            return out - offset;
+                        }
+                        expectedByte(4, 4);
+                    }
+                    count++;
+                }
+                if ((b3 & 0xC0) != 0x80) {
+                    if (out > offset) {
+                        fBuffer[0] = (byte)b0;
+                        fBuffer[1] = (byte)b1;
+                        fBuffer[2] = (byte)b2;
+                        fBuffer[3] = (byte)b3;
+                        fOffset = 4;
+                        return out - offset;
+                    }
+                    invalidByte(4, 4, b2);
+                }
+
+                // decode bytes into surrogate characters
+                int uuuuu = ((b0 << 2) & 0x001C) | ((b1 >> 4) & 0x0003);
+                if (uuuuu > 0x10) {
+                    invalidSurrogate(uuuuu);
+                }
+                int wwww = uuuuu - 1;
+                int zzzz = b1 & 0x000F;
+                int yyyyyy = b2 & 0x003F;
+                int xxxxxx = b3 & 0x003F;
+                int hs = 0xD800 | ((wwww << 6) & 0x03C0) | (zzzz << 2) | (yyyyyy >> 4);
+                int ls = 0xDC00 | ((yyyyyy << 6) & 0x03C0) | xxxxxx;
+
+                // set characters
+                ch[out++] = (char)hs;
+                ch[out++] = (char)ls;
+                count -= 2;
+                continue;
+            }
+
+            // error
+            if (out > offset) {
+                fBuffer[0] = (byte)b0;
+                fOffset = 1;
+                return out - offset;
+            }
+            invalidByte(1, 1, b0);
+        }
+
+        // return number of characters converted
+        if (DEBUG_READ) {
+            if (log.isDebugEnabled())
+                log.debug("read(char[],"+offset+','+length+"): count="+count);
+        }
+        return count;
+
+    } // read(char[],int,int)
+
+    /**
+     * Skip characters.  This method will block until some characters are
+     * available, an I/O error occurs, or the end of the stream is reached.
+     *
+     * @param  n  The number of characters to skip
+     *
+     * @return    The number of characters actually skipped
+     *
+     * @exception  IOException  If an I/O error occurs
+     */
+    public long skip(long n) throws IOException {
+
+        long remaining = n;
+        final char[] ch = new char[fBuffer.length];
+        do {
+            int length = ch.length < remaining ? ch.length : (int)remaining;
+            int count = read(ch, 0, length);
+            if (count > 0) {
+                remaining -= count;
+            }
+            else {
+                break;
+            }
+        } while (remaining > 0);
+
+        long skipped = n - remaining;
+        return skipped;
+
+    } // skip(long):long
+
+    /**
+     * Tell whether this stream is ready to be read.
+     *
+     * @return True if the next read() is guaranteed not to block for input,
+     * false otherwise.  Note that returning false does not guarantee that the
+     * next read will block.
+     *
+     * @exception  IOException  If an I/O error occurs
+     */
+    public boolean ready() throws IOException {
+	    return false;
+    } // ready()
+
+    /**
+     * Tell whether this stream supports the mark() operation.
+     */
+    public boolean markSupported() {
+	    return false;
+    } // markSupported()
+
+    /**
+     * Mark the present position in the stream.  Subsequent calls to reset()
+     * will attempt to reposition the stream to this point.  Not all
+     * character-input streams support the mark() operation.
+     *
+     * @param  readAheadLimit  Limit on the number of characters that may be
+     *                         read while still preserving the mark.  After
+     *                         reading this many characters, attempting to
+     *                         reset the stream may fail.
+     *
+     * @exception  IOException  If the stream does not support mark(),
+     *                          or if some other I/O error occurs
+     */
+    public void mark(int readAheadLimit) throws IOException {
+	throw new IOException(
+                Localizer.getMessage("jsp.error.xml.operationNotSupported",
+				     "mark()", "UTF-8"));
+    }
+
+    /**
+     * Reset the stream.  If the stream has been marked, then attempt to
+     * reposition it at the mark.  If the stream has not been marked, then
+     * attempt to reset it in some way appropriate to the particular stream,
+     * for example by repositioning it to its starting point.  Not all
+     * character-input streams support the reset() operation, and some support
+     * reset() without supporting mark().
+     *
+     * @exception  IOException  If the stream has not been marked,
+     *                          or if the mark has been invalidated,
+     *                          or if the stream does not support reset(),
+     *                          or if some other I/O error occurs
+     */
+    public void reset() throws IOException {
+        fOffset = 0;
+        fSurrogate = -1;
+    } // reset()
+
+    /**
+     * Close the stream.  Once a stream has been closed, further read(),
+     * ready(), mark(), or reset() invocations will throw an IOException.
+     * Closing a previously-closed stream, however, has no effect.
+     *
+     * @exception  IOException  If an I/O error occurs
+     */
+    public void close() throws IOException {
+        fInputStream.close();
+    } // close()
+
+    //
+    // Private methods
+    //
+
+    /** Throws an exception for expected byte. */
+    private void expectedByte(int position, int count)
+        throws UTFDataFormatException {
+
+        throw new UTFDataFormatException(
+                Localizer.getMessage("jsp.error.xml.expectedByte",
+				     Integer.toString(position),
+				     Integer.toString(count)));
+
+    } // expectedByte(int,int,int)
+
+    /** Throws an exception for invalid byte. */
+    private void invalidByte(int position, int count, int c) 
+        throws UTFDataFormatException {
+
+        throw new UTFDataFormatException(
+                Localizer.getMessage("jsp.error.xml.invalidByte",
+				     Integer.toString(position),
+				     Integer.toString(count)));
+    } // invalidByte(int,int,int,int)
+
+    /** Throws an exception for invalid surrogate bits. */
+    private void invalidSurrogate(int uuuuu) throws UTFDataFormatException {
+        
+        throw new UTFDataFormatException(
+                Localizer.getMessage("jsp.error.xml.invalidHighSurrogate",
+				     Integer.toHexString(uuuuu)));
+    } // invalidSurrogate(int)
+
+} // class UTF8Reader

Added: branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/xmlparser/XMLChar.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/xmlparser/XMLChar.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/xmlparser/XMLChar.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,1030 @@
+/*
+ * Copyright 1999,2004-2005 The Apache Software Foundation.
+ * 
+ * Licensed 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.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation and was
+ * originally based on software copyright (c) 1999, International
+ * Business Machines, Inc., http://www.apache.org.  For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ */
+
+package org.apache.jasper.xmlparser;
+
+import java.util.Arrays;
+
+/**
+ * This class defines the basic XML character properties. The data
+ * in this class can be used to verify that a character is a valid
+ * XML character or if the character is a space, name start, or name
+ * character.
+ * <p>
+ * A series of convenience methods are supplied to ease the burden
+ * of the developer. Because inlining the checks can improve per
+ * character performance, the tables of character properties are
+ * public. Using the character as an index into the <code>CHARS</code>
+ * array and applying the appropriate mask flag (e.g.
+ * <code>MASK_VALID</code>), yields the same results as calling the
+ * convenience methods. There is one exception: check the comments
+ * for the <code>isValid</code> method for details.
+ *
+ * @author Glenn Marcy, IBM
+ * @author Andy Clark, IBM
+ * @author Eric Ye, IBM
+ * @author Arnaud  Le Hors, IBM
+ * @author Michael Glavassevich, IBM
+ * @author Rahul Srivastava, Sun Microsystems Inc.
+ *
+ * @version $Id: XMLChar.java 306179 2005-07-27 15:12:04Z yoavs $
+ */
+public class XMLChar {
+
+    //
+    // Constants
+    //
+
+    /** Character flags. */
+    private static final byte[] CHARS = new byte[1 << 16];
+
+    /** Valid character mask. */
+    public static final int MASK_VALID = 0x01;
+
+    /** Space character mask. */
+    public static final int MASK_SPACE = 0x02;
+
+    /** Name start character mask. */
+    public static final int MASK_NAME_START = 0x04;
+
+    /** Name character mask. */
+    public static final int MASK_NAME = 0x08;
+
+    /** Pubid character mask. */
+    public static final int MASK_PUBID = 0x10;
+    
+    /** 
+     * Content character mask. Special characters are those that can
+     * be considered the start of markup, such as '&lt;' and '&amp;'. 
+     * The various newline characters are considered special as well.
+     * All other valid XML characters can be considered content.
+     * <p>
+     * This is an optimization for the inner loop of character scanning.
+     */
+    public static final int MASK_CONTENT = 0x20;
+
+    /** NCName start character mask. */
+    public static final int MASK_NCNAME_START = 0x40;
+
+    /** NCName character mask. */
+    public static final int MASK_NCNAME = 0x80;
+
+    //
+    // Static initialization
+    //
+
+    static {
+        
+        // Initializing the Character Flag Array
+        // Code generated by: XMLCharGenerator.
+        
+        CHARS[9] = 35;
+        CHARS[10] = 19;
+        CHARS[13] = 19;
+        CHARS[32] = 51;
+        CHARS[33] = 49;
+        CHARS[34] = 33;
+        Arrays.fill(CHARS, 35, 38, (byte) 49 ); // Fill 3 of value (byte) 49
+        CHARS[38] = 1;
+        Arrays.fill(CHARS, 39, 45, (byte) 49 ); // Fill 6 of value (byte) 49
+        Arrays.fill(CHARS, 45, 47, (byte) -71 ); // Fill 2 of value (byte) -71
+        CHARS[47] = 49;
+        Arrays.fill(CHARS, 48, 58, (byte) -71 ); // Fill 10 of value (byte) -71
+        CHARS[58] = 61;
+        CHARS[59] = 49;
+        CHARS[60] = 1;
+        CHARS[61] = 49;
+        CHARS[62] = 33;
+        Arrays.fill(CHARS, 63, 65, (byte) 49 ); // Fill 2 of value (byte) 49
+        Arrays.fill(CHARS, 65, 91, (byte) -3 ); // Fill 26 of value (byte) -3
+        Arrays.fill(CHARS, 91, 93, (byte) 33 ); // Fill 2 of value (byte) 33
+        CHARS[93] = 1;
+        CHARS[94] = 33;
+        CHARS[95] = -3;
+        CHARS[96] = 33;
+        Arrays.fill(CHARS, 97, 123, (byte) -3 ); // Fill 26 of value (byte) -3
+        Arrays.fill(CHARS, 123, 183, (byte) 33 ); // Fill 60 of value (byte) 33
+        CHARS[183] = -87;
+        Arrays.fill(CHARS, 184, 192, (byte) 33 ); // Fill 8 of value (byte) 33
+        Arrays.fill(CHARS, 192, 215, (byte) -19 ); // Fill 23 of value (byte) -19
+        CHARS[215] = 33;
+        Arrays.fill(CHARS, 216, 247, (byte) -19 ); // Fill 31 of value (byte) -19
+        CHARS[247] = 33;
+        Arrays.fill(CHARS, 248, 306, (byte) -19 ); // Fill 58 of value (byte) -19
+        Arrays.fill(CHARS, 306, 308, (byte) 33 ); // Fill 2 of value (byte) 33
+        Arrays.fill(CHARS, 308, 319, (byte) -19 ); // Fill 11 of value (byte) -19
+        Arrays.fill(CHARS, 319, 321, (byte) 33 ); // Fill 2 of value (byte) 33
+        Arrays.fill(CHARS, 321, 329, (byte) -19 ); // Fill 8 of value (byte) -19
+        CHARS[329] = 33;
+        Arrays.fill(CHARS, 330, 383, (byte) -19 ); // Fill 53 of value (byte) -19
+        CHARS[383] = 33;
+        Arrays.fill(CHARS, 384, 452, (byte) -19 ); // Fill 68 of value (byte) -19
+        Arrays.fill(CHARS, 452, 461, (byte) 33 ); // Fill 9 of value (byte) 33
+        Arrays.fill(CHARS, 461, 497, (byte) -19 ); // Fill 36 of value (byte) -19
+        Arrays.fill(CHARS, 497, 500, (byte) 33 ); // Fill 3 of value (byte) 33
+        Arrays.fill(CHARS, 500, 502, (byte) -19 ); // Fill 2 of value (byte) -19
+        Arrays.fill(CHARS, 502, 506, (byte) 33 ); // Fill 4 of value (byte) 33
+        Arrays.fill(CHARS, 506, 536, (byte) -19 ); // Fill 30 of value (byte) -19
+        Arrays.fill(CHARS, 536, 592, (byte) 33 ); // Fill 56 of value (byte) 33
+        Arrays.fill(CHARS, 592, 681, (byte) -19 ); // Fill 89 of value (byte) -19
+        Arrays.fill(CHARS, 681, 699, (byte) 33 ); // Fill 18 of value (byte) 33
+        Arrays.fill(CHARS, 699, 706, (byte) -19 ); // Fill 7 of value (byte) -19
+        Arrays.fill(CHARS, 706, 720, (byte) 33 ); // Fill 14 of value (byte) 33
+        Arrays.fill(CHARS, 720, 722, (byte) -87 ); // Fill 2 of value (byte) -87
+        Arrays.fill(CHARS, 722, 768, (byte) 33 ); // Fill 46 of value (byte) 33
+        Arrays.fill(CHARS, 768, 838, (byte) -87 ); // Fill 70 of value (byte) -87
+        Arrays.fill(CHARS, 838, 864, (byte) 33 ); // Fill 26 of value (byte) 33
+        Arrays.fill(CHARS, 864, 866, (byte) -87 ); // Fill 2 of value (byte) -87
+        Arrays.fill(CHARS, 866, 902, (byte) 33 ); // Fill 36 of value (byte) 33
+        CHARS[902] = -19;
+        CHARS[903] = -87;
+        Arrays.fill(CHARS, 904, 907, (byte) -19 ); // Fill 3 of value (byte) -19
+        CHARS[907] = 33;
+        CHARS[908] = -19;
+        CHARS[909] = 33;
+        Arrays.fill(CHARS, 910, 930, (byte) -19 ); // Fill 20 of value (byte) -19
+        CHARS[930] = 33;
+        Arrays.fill(CHARS, 931, 975, (byte) -19 ); // Fill 44 of value (byte) -19
+        CHARS[975] = 33;
+        Arrays.fill(CHARS, 976, 983, (byte) -19 ); // Fill 7 of value (byte) -19
+        Arrays.fill(CHARS, 983, 986, (byte) 33 ); // Fill 3 of value (byte) 33
+        CHARS[986] = -19;
+        CHARS[987] = 33;
+        CHARS[988] = -19;
+        CHARS[989] = 33;
+        CHARS[990] = -19;
+        CHARS[991] = 33;
+        CHARS[992] = -19;
+        CHARS[993] = 33;
+        Arrays.fill(CHARS, 994, 1012, (byte) -19 ); // Fill 18 of value (byte) -19
+        Arrays.fill(CHARS, 1012, 1025, (byte) 33 ); // Fill 13 of value (byte) 33
+        Arrays.fill(CHARS, 1025, 1037, (byte) -19 ); // Fill 12 of value (byte) -19
+        CHARS[1037] = 33;
+        Arrays.fill(CHARS, 1038, 1104, (byte) -19 ); // Fill 66 of value (byte) -19
+        CHARS[1104] = 33;
+        Arrays.fill(CHARS, 1105, 1117, (byte) -19 ); // Fill 12 of value (byte) -19
+        CHARS[1117] = 33;
+        Arrays.fill(CHARS, 1118, 1154, (byte) -19 ); // Fill 36 of value (byte) -19
+        CHARS[1154] = 33;
+        Arrays.fill(CHARS, 1155, 1159, (byte) -87 ); // Fill 4 of value (byte) -87
+        Arrays.fill(CHARS, 1159, 1168, (byte) 33 ); // Fill 9 of value (byte) 33
+        Arrays.fill(CHARS, 1168, 1221, (byte) -19 ); // Fill 53 of value (byte) -19
+        Arrays.fill(CHARS, 1221, 1223, (byte) 33 ); // Fill 2 of value (byte) 33
+        Arrays.fill(CHARS, 1223, 1225, (byte) -19 ); // Fill 2 of value (byte) -19
+        Arrays.fill(CHARS, 1225, 1227, (byte) 33 ); // Fill 2 of value (byte) 33
+        Arrays.fill(CHARS, 1227, 1229, (byte) -19 ); // Fill 2 of value (byte) -19
+        Arrays.fill(CHARS, 1229, 1232, (byte) 33 ); // Fill 3 of value (byte) 33
+        Arrays.fill(CHARS, 1232, 1260, (byte) -19 ); // Fill 28 of value (byte) -19
+        Arrays.fill(CHARS, 1260, 1262, (byte) 33 ); // Fill 2 of value (byte) 33
+        Arrays.fill(CHARS, 1262, 1270, (byte) -19 ); // Fill 8 of value (byte) -19
+        Arrays.fill(CHARS, 1270, 1272, (byte) 33 ); // Fill 2 of value (byte) 33
+        Arrays.fill(CHARS, 1272, 1274, (byte) -19 ); // Fill 2 of value (byte) -19
+        Arrays.fill(CHARS, 1274, 1329, (byte) 33 ); // Fill 55 of value (byte) 33
+        Arrays.fill(CHARS, 1329, 1367, (byte) -19 ); // Fill 38 of value (byte) -19
+        Arrays.fill(CHARS, 1367, 1369, (byte) 33 ); // Fill 2 of value (byte) 33
+        CHARS[1369] = -19;
+        Arrays.fill(CHARS, 1370, 1377, (byte) 33 ); // Fill 7 of value (byte) 33
+        Arrays.fill(CHARS, 1377, 1415, (byte) -19 ); // Fill 38 of value (byte) -19
+        Arrays.fill(CHARS, 1415, 1425, (byte) 33 ); // Fill 10 of value (byte) 33
+        Arrays.fill(CHARS, 1425, 1442, (byte) -87 ); // Fill 17 of value (byte) -87
+        CHARS[1442] = 33;
+        Arrays.fill(CHARS, 1443, 1466, (byte) -87 ); // Fill 23 of value (byte) -87
+        CHARS[1466] = 33;
+        Arrays.fill(CHARS, 1467, 1470, (byte) -87 ); // Fill 3 of value (byte) -87
+        CHARS[1470] = 33;
+        CHARS[1471] = -87;
+        CHARS[1472] = 33;
+        Arrays.fill(CHARS, 1473, 1475, (byte) -87 ); // Fill 2 of value (byte) -87
+        CHARS[1475] = 33;
+        CHARS[1476] = -87;
+        Arrays.fill(CHARS, 1477, 1488, (byte) 33 ); // Fill 11 of value (byte) 33
+        Arrays.fill(CHARS, 1488, 1515, (byte) -19 ); // Fill 27 of value (byte) -19
+        Arrays.fill(CHARS, 1515, 1520, (byte) 33 ); // Fill 5 of value (byte) 33
+        Arrays.fill(CHARS, 1520, 1523, (byte) -19 ); // Fill 3 of value (byte) -19
+        Arrays.fill(CHARS, 1523, 1569, (byte) 33 ); // Fill 46 of value (byte) 33
+        Arrays.fill(CHARS, 1569, 1595, (byte) -19 ); // Fill 26 of value (byte) -19
+        Arrays.fill(CHARS, 1595, 1600, (byte) 33 ); // Fill 5 of value (byte) 33
+        CHARS[1600] = -87;
+        Arrays.fill(CHARS, 1601, 1611, (byte) -19 ); // Fill 10 of value (byte) -19
+        Arrays.fill(CHARS, 1611, 1619, (byte) -87 ); // Fill 8 of value (byte) -87
+        Arrays.fill(CHARS, 1619, 1632, (byte) 33 ); // Fill 13 of value (byte) 33
+        Arrays.fill(CHARS, 1632, 1642, (byte) -87 ); // Fill 10 of value (byte) -87
+        Arrays.fill(CHARS, 1642, 1648, (byte) 33 ); // Fill 6 of value (byte) 33
+        CHARS[1648] = -87;
+        Arrays.fill(CHARS, 1649, 1720, (byte) -19 ); // Fill 71 of value (byte) -19
+        Arrays.fill(CHARS, 1720, 1722, (byte) 33 ); // Fill 2 of value (byte) 33
+        Arrays.fill(CHARS, 1722, 1727, (byte) -19 ); // Fill 5 of value (byte) -19
+        CHARS[1727] = 33;
+        Arrays.fill(CHARS, 1728, 1743, (byte) -19 ); // Fill 15 of value (byte) -19
+        CHARS[1743] = 33;
+        Arrays.fill(CHARS, 1744, 1748, (byte) -19 ); // Fill 4 of value (byte) -19
+        CHARS[1748] = 33;
+        CHARS[1749] = -19;
+        Arrays.fill(CHARS, 1750, 1765, (byte) -87 ); // Fill 15 of value (byte) -87
+        Arrays.fill(CHARS, 1765, 1767, (byte) -19 ); // Fill 2 of value (byte) -19
+        Arrays.fill(CHARS, 1767, 1769, (byte) -87 ); // Fill 2 of value (byte) -87
+        CHARS[1769] = 33;
+        Arrays.fill(CHARS, 1770, 1774, (byte) -87 ); // Fill 4 of value (byte) -87
+        Arrays.fill(CHARS, 1774, 1776, (byte) 33 ); // Fill 2 of value (byte) 33
+        Arrays.fill(CHARS, 1776, 1786, (byte) -87 ); // Fill 10 of value (byte) -87
+        Arrays.fill(CHARS, 1786, 2305, (byte) 33 ); // Fill 519 of value (byte) 33
+        Arrays.fill(CHARS, 2305, 2308, (byte) -87 ); // Fill 3 of value (byte) -87
+        CHARS[2308] = 33;
+        Arrays.fill(CHARS, 2309, 2362, (byte) -19 ); // Fill 53 of value (byte) -19
+        Arrays.fill(CHARS, 2362, 2364, (byte) 33 ); // Fill 2 of value (byte) 33
+        CHARS[2364] = -87;
+        CHARS[2365] = -19;
+        Arrays.fill(CHARS, 2366, 2382, (byte) -87 ); // Fill 16 of value (byte) -87
+        Arrays.fill(CHARS, 2382, 2385, (byte) 33 ); // Fill 3 of value (byte) 33
+        Arrays.fill(CHARS, 2385, 2389, (byte) -87 ); // Fill 4 of value (byte) -87
+        Arrays.fill(CHARS, 2389, 2392, (byte) 33 ); // Fill 3 of value (byte) 33
+        Arrays.fill(CHARS, 2392, 2402, (byte) -19 ); // Fill 10 of value (byte) -19
+        Arrays.fill(CHARS, 2402, 2404, (byte) -87 ); // Fill 2 of value (byte) -87
+        Arrays.fill(CHARS, 2404, 2406, (byte) 33 ); // Fill 2 of value (byte) 33
+        Arrays.fill(CHARS, 2406, 2416, (byte) -87 ); // Fill 10 of value (byte) -87
+        Arrays.fill(CHARS, 2416, 2433, (byte) 33 ); // Fill 17 of value (byte) 33
+        Arrays.fill(CHARS, 2433, 2436, (byte) -87 ); // Fill 3 of value (byte) -87
+        CHARS[2436] = 33;
+        Arrays.fill(CHARS, 2437, 2445, (byte) -19 ); // Fill 8 of value (byte) -19
+        Arrays.fill(CHARS, 2445, 2447, (byte) 33 ); // Fill 2 of value (byte) 33
+        Arrays.fill(CHARS, 2447, 2449, (byte) -19 ); // Fill 2 of value (byte) -19
+        Arrays.fill(CHARS, 2449, 2451, (byte) 33 ); // Fill 2 of value (byte) 33
+        Arrays.fill(CHARS, 2451, 2473, (byte) -19 ); // Fill 22 of value (byte) -19
+        CHARS[2473] = 33;
+        Arrays.fill(CHARS, 2474, 2481, (byte) -19 ); // Fill 7 of value (byte) -19
+        CHARS[2481] = 33;
+        CHARS[2482] = -19;
+        Arrays.fill(CHARS, 2483, 2486, (byte) 33 ); // Fill 3 of value (byte) 33
+        Arrays.fill(CHARS, 2486, 2490, (byte) -19 ); // Fill 4 of value (byte) -19
+        Arrays.fill(CHARS, 2490, 2492, (byte) 33 ); // Fill 2 of value (byte) 33
+        CHARS[2492] = -87;
+        CHARS[2493] = 33;
+        Arrays.fill(CHARS, 2494, 2501, (byte) -87 ); // Fill 7 of value (byte) -87
+        Arrays.fill(CHARS, 2501, 2503, (byte) 33 ); // Fill 2 of value (byte) 33
+        Arrays.fill(CHARS, 2503, 2505, (byte) -87 ); // Fill 2 of value (byte) -87
+        Arrays.fill(CHARS, 2505, 2507, (byte) 33 ); // Fill 2 of value (byte) 33
+        Arrays.fill(CHARS, 2507, 2510, (byte) -87 ); // Fill 3 of value (byte) -87
+        Arrays.fill(CHARS, 2510, 2519, (byte) 33 ); // Fill 9 of value (byte) 33
+        CHARS[2519] = -87;
+        Arrays.fill(CHARS, 2520, 2524, (byte) 33 ); // Fill 4 of value (byte) 33
+        Arrays.fill(CHARS, 2524, 2526, (byte) -19 ); // Fill 2 of value (byte) -19
+        CHARS[2526] = 33;
+        Arrays.fill(CHARS, 2527, 2530, (byte) -19 ); // Fill 3 of value (byte) -19
+        Arrays.fill(CHARS, 2530, 2532, (byte) -87 ); // Fill 2 of value (byte) -87
+        Arrays.fill(CHARS, 2532, 2534, (byte) 33 ); // Fill 2 of value (byte) 33
+        Arrays.fill(CHARS, 2534, 2544, (byte) -87 ); // Fill 10 of value (byte) -87
+        Arrays.fill(CHARS, 2544, 2546, (byte) -19 ); // Fill 2 of value (byte) -19
+        Arrays.fill(CHARS, 2546, 2562, (byte) 33 ); // Fill 16 of value (byte) 33
+        CHARS[2562] = -87;
+        Arrays.fill(CHARS, 2563, 2565, (byte) 33 ); // Fill 2 of value (byte) 33
+        Arrays.fill(CHARS, 2565, 2571, (byte) -19 ); // Fill 6 of value (byte) -19
+        Arrays.fill(CHARS, 2571, 2575, (byte) 33 ); // Fill 4 of value (byte) 33
+        Arrays.fill(CHARS, 2575, 2577, (byte) -19 ); // Fill 2 of value (byte) -19
+        Arrays.fill(CHARS, 2577, 2579, (byte) 33 ); // Fill 2 of value (byte) 33
+        Arrays.fill(CHARS, 2579, 2601, (byte) -19 ); // Fill 22 of value (byte) -19
+        CHARS[2601] = 33;
+        Arrays.fill(CHARS, 2602, 2609, (byte) -19 ); // Fill 7 of value (byte) -19
+        CHARS[2609] = 33;
+        Arrays.fill(CHARS, 2610, 2612, (byte) -19 ); // Fill 2 of value (byte) -19
+        CHARS[2612] = 33;
+        Arrays.fill(CHARS, 2613, 2615, (byte) -19 ); // Fill 2 of value (byte) -19
+        CHARS[2615] = 33;
+        Arrays.fill(CHARS, 2616, 2618, (byte) -19 ); // Fill 2 of value (byte) -19
+        Arrays.fill(CHARS, 2618, 2620, (byte) 33 ); // Fill 2 of value (byte) 33
+        CHARS[2620] = -87;
+        CHARS[2621] = 33;
+        Arrays.fill(CHARS, 2622, 2627, (byte) -87 ); // Fill 5 of value (byte) -87
+        Arrays.fill(CHARS, 2627, 2631, (byte) 33 ); // Fill 4 of value (byte) 33
+        Arrays.fill(CHARS, 2631, 2633, (byte) -87 ); // Fill 2 of value (byte) -87
+        Arrays.fill(CHARS, 2633, 2635, (byte) 33 ); // Fill 2 of value (byte) 33
+        Arrays.fill(CHARS, 2635, 2638, (byte) -87 ); // Fill 3 of value (byte) -87
+        Arrays.fill(CHARS, 2638, 2649, (byte) 33 ); // Fill 11 of value (byte) 33
+        Arrays.fill(CHARS, 2649, 2653, (byte) -19 ); // Fill 4 of value (byte) -19
+        CHARS[2653] = 33;
+        CHARS[2654] = -19;
+        Arrays.fill(CHARS, 2655, 2662, (byte) 33 ); // Fill 7 of value (byte) 33
+        Arrays.fill(CHARS, 2662, 2674, (byte) -87 ); // Fill 12 of value (byte) -87
+        Arrays.fill(CHARS, 2674, 2677, (byte) -19 ); // Fill 3 of value (byte) -19
+        Arrays.fill(CHARS, 2677, 2689, (byte) 33 ); // Fill 12 of value (byte) 33
+        Arrays.fill(CHARS, 2689, 2692, (byte) -87 ); // Fill 3 of value (byte) -87
+        CHARS[2692] = 33;
+        Arrays.fill(CHARS, 2693, 2700, (byte) -19 ); // Fill 7 of value (byte) -19
+        CHARS[2700] = 33;
+        CHARS[2701] = -19;
+        CHARS[2702] = 33;
+        Arrays.fill(CHARS, 2703, 2706, (byte) -19 ); // Fill 3 of value (byte) -19
+        CHARS[2706] = 33;
+        Arrays.fill(CHARS, 2707, 2729, (byte) -19 ); // Fill 22 of value (byte) -19
+        CHARS[2729] = 33;
+        Arrays.fill(CHARS, 2730, 2737, (byte) -19 ); // Fill 7 of value (byte) -19
+        CHARS[2737] = 33;
+        Arrays.fill(CHARS, 2738, 2740, (byte) -19 ); // Fill 2 of value (byte) -19
+        CHARS[2740] = 33;
+        Arrays.fill(CHARS, 2741, 2746, (byte) -19 ); // Fill 5 of value (byte) -19
+        Arrays.fill(CHARS, 2746, 2748, (byte) 33 ); // Fill 2 of value (byte) 33
+        CHARS[2748] = -87;
+        CHARS[2749] = -19;
+        Arrays.fill(CHARS, 2750, 2758, (byte) -87 ); // Fill 8 of value (byte) -87
+        CHARS[2758] = 33;
+        Arrays.fill(CHARS, 2759, 2762, (byte) -87 ); // Fill 3 of value (byte) -87
+        CHARS[2762] = 33;
+        Arrays.fill(CHARS, 2763, 2766, (byte) -87 ); // Fill 3 of value (byte) -87
+        Arrays.fill(CHARS, 2766, 2784, (byte) 33 ); // Fill 18 of value (byte) 33
+        CHARS[2784] = -19;
+        Arrays.fill(CHARS, 2785, 2790, (byte) 33 ); // Fill 5 of value (byte) 33
+        Arrays.fill(CHARS, 2790, 2800, (byte) -87 ); // Fill 10 of value (byte) -87
+        Arrays.fill(CHARS, 2800, 2817, (byte) 33 ); // Fill 17 of value (byte) 33
+        Arrays.fill(CHARS, 2817, 2820, (byte) -87 ); // Fill 3 of value (byte) -87
+        CHARS[2820] = 33;
+        Arrays.fill(CHARS, 2821, 2829, (byte) -19 ); // Fill 8 of value (byte) -19
+        Arrays.fill(CHARS, 2829, 2831, (byte) 33 ); // Fill 2 of value (byte) 33
+        Arrays.fill(CHARS, 2831, 2833, (byte) -19 ); // Fill 2 of value (byte) -19
+        Arrays.fill(CHARS, 2833, 2835, (byte) 33 ); // Fill 2 of value (byte) 33
+        Arrays.fill(CHARS, 2835, 2857, (byte) -19 ); // Fill 22 of value (byte) -19
+        CHARS[2857] = 33;
+        Arrays.fill(CHARS, 2858, 2865, (byte) -19 ); // Fill 7 of value (byte) -19
+        CHARS[2865] = 33;
+        Arrays.fill(CHARS, 2866, 2868, (byte) -19 ); // Fill 2 of value (byte) -19
+        Arrays.fill(CHARS, 2868, 2870, (byte) 33 ); // Fill 2 of value (byte) 33
+        Arrays.fill(CHARS, 2870, 2874, (byte) -19 ); // Fill 4 of value (byte) -19
+        Arrays.fill(CHARS, 2874, 2876, (byte) 33 ); // Fill 2 of value (byte) 33
+        CHARS[2876] = -87;
+        CHARS[2877] = -19;
+        Arrays.fill(CHARS, 2878, 2884, (byte) -87 ); // Fill 6 of value (byte) -87
+        Arrays.fill(CHARS, 2884, 2887, (byte) 33 ); // Fill 3 of value (byte) 33
+        Arrays.fill(CHARS, 2887, 2889, (byte) -87 ); // Fill 2 of value (byte) -87
+        Arrays.fill(CHARS, 2889, 2891, (byte) 33 ); // Fill 2 of value (byte) 33
+        Arrays.fill(CHARS, 2891, 2894, (byte) -87 ); // Fill 3 of value (byte) -87
+        Arrays.fill(CHARS, 2894, 2902, (byte) 33 ); // Fill 8 of value (byte) 33
+        Arrays.fill(CHARS, 2902, 2904, (byte) -87 ); // Fill 2 of value (byte) -87
+        Arrays.fill(CHARS, 2904, 2908, (byte) 33 ); // Fill 4 of value (byte) 33
+        Arrays.fill(CHARS, 2908, 2910, (byte) -19 ); // Fill 2 of value (byte) -19
+        CHARS[2910] = 33;
+        Arrays.fill(CHARS, 2911, 2914, (byte) -19 ); // Fill 3 of value (byte) -19
+        Arrays.fill(CHARS, 2914, 2918, (byte) 33 ); // Fill 4 of value (byte) 33
+        Arrays.fill(CHARS, 2918, 2928, (byte) -87 ); // Fill 10 of value (byte) -87
+        Arrays.fill(CHARS, 2928, 2946, (byte) 33 ); // Fill 18 of value (byte) 33
+        Arrays.fill(CHARS, 2946, 2948, (byte) -87 ); // Fill 2 of value (byte) -87
+        CHARS[2948] = 33;
+        Arrays.fill(CHARS, 2949, 2955, (byte) -19 ); // Fill 6 of value (byte) -19
+        Arrays.fill(CHARS, 2955, 2958, (byte) 33 ); // Fill 3 of value (byte) 33
+        Arrays.fill(CHARS, 2958, 2961, (byte) -19 ); // Fill 3 of value (byte) -19
+        CHARS[2961] = 33;
+        Arrays.fill(CHARS, 2962, 2966, (byte) -19 ); // Fill 4 of value (byte) -19
+        Arrays.fill(CHARS, 2966, 2969, (byte) 33 ); // Fill 3 of value (byte) 33
+        Arrays.fill(CHARS, 2969, 2971, (byte) -19 ); // Fill 2 of value (byte) -19
+        CHARS[2971] = 33;
+        CHARS[2972] = -19;
+        CHARS[2973] = 33;
+        Arrays.fill(CHARS, 2974, 2976, (byte) -19 ); // Fill 2 of value (byte) -19
+        Arrays.fill(CHARS, 2976, 2979, (byte) 33 ); // Fill 3 of value (byte) 33
+        Arrays.fill(CHARS, 2979, 2981, (byte) -19 ); // Fill 2 of value (byte) -19
+        Arrays.fill(CHARS, 2981, 2984, (byte) 33 ); // Fill 3 of value (byte) 33
+        Arrays.fill(CHARS, 2984, 2987, (byte) -19 ); // Fill 3 of value (byte) -19
+        Arrays.fill(CHARS, 2987, 2990, (byte) 33 ); // Fill 3 of value (byte) 33
+        Arrays.fill(CHARS, 2990, 2998, (byte) -19 ); // Fill 8 of value (byte) -19
+        CHARS[2998] = 33;
+        Arrays.fill(CHARS, 2999, 3002, (byte) -19 ); // Fill 3 of value (byte) -19
+        Arrays.fill(CHARS, 3002, 3006, (byte) 33 ); // Fill 4 of value (byte) 33
+        Arrays.fill(CHARS, 3006, 3011, (byte) -87 ); // Fill 5 of value (byte) -87
+        Arrays.fill(CHARS, 3011, 3014, (byte) 33 ); // Fill 3 of value (byte) 33
+        Arrays.fill(CHARS, 3014, 3017, (byte) -87 ); // Fill 3 of value (byte) -87
+        CHARS[3017] = 33;
+        Arrays.fill(CHARS, 3018, 3022, (byte) -87 ); // Fill 4 of value (byte) -87
+        Arrays.fill(CHARS, 3022, 3031, (byte) 33 ); // Fill 9 of value (byte) 33
+        CHARS[3031] = -87;
+        Arrays.fill(CHARS, 3032, 3047, (byte) 33 ); // Fill 15 of value (byte) 33
+        Arrays.fill(CHARS, 3047, 3056, (byte) -87 ); // Fill 9 of value (byte) -87
+        Arrays.fill(CHARS, 3056, 3073, (byte) 33 ); // Fill 17 of value (byte) 33
+        Arrays.fill(CHARS, 3073, 3076, (byte) -87 ); // Fill 3 of value (byte) -87
+        CHARS[3076] = 33;
+        Arrays.fill(CHARS, 3077, 3085, (byte) -19 ); // Fill 8 of value (byte) -19
+        CHARS[3085] = 33;
+        Arrays.fill(CHARS, 3086, 3089, (byte) -19 ); // Fill 3 of value (byte) -19
+        CHARS[3089] = 33;
+        Arrays.fill(CHARS, 3090, 3113, (byte) -19 ); // Fill 23 of value (byte) -19
+        CHARS[3113] = 33;
+        Arrays.fill(CHARS, 3114, 3124, (byte) -19 ); // Fill 10 of value (byte) -19
+        CHARS[3124] = 33;
+        Arrays.fill(CHARS, 3125, 3130, (byte) -19 ); // Fill 5 of value (byte) -19
+        Arrays.fill(CHARS, 3130, 3134, (byte) 33 ); // Fill 4 of value (byte) 33
+        Arrays.fill(CHARS, 3134, 3141, (byte) -87 ); // Fill 7 of value (byte) -87
+        CHARS[3141] = 33;
+        Arrays.fill(CHARS, 3142, 3145, (byte) -87 ); // Fill 3 of value (byte) -87
+        CHARS[3145] = 33;
+        Arrays.fill(CHARS, 3146, 3150, (byte) -87 ); // Fill 4 of value (byte) -87
+        Arrays.fill(CHARS, 3150, 3157, (byte) 33 ); // Fill 7 of value (byte) 33
+        Arrays.fill(CHARS, 3157, 3159, (byte) -87 ); // Fill 2 of value (byte) -87
+        Arrays.fill(CHARS, 3159, 3168, (byte) 33 ); // Fill 9 of value (byte) 33
+        Arrays.fill(CHARS, 3168, 3170, (byte) -19 ); // Fill 2 of value (byte) -19
+        Arrays.fill(CHARS, 3170, 3174, (byte) 33 ); // Fill 4 of value (byte) 33
+        Arrays.fill(CHARS, 3174, 3184, (byte) -87 ); // Fill 10 of value (byte) -87
+        Arrays.fill(CHARS, 3184, 3202, (byte) 33 ); // Fill 18 of value (byte) 33
+        Arrays.fill(CHARS, 3202, 3204, (byte) -87 ); // Fill 2 of value (byte) -87
+        CHARS[3204] = 33;
+        Arrays.fill(CHARS, 3205, 3213, (byte) -19 ); // Fill 8 of value (byte) -19
+        CHARS[3213] = 33;
+        Arrays.fill(CHARS, 3214, 3217, (byte) -19 ); // Fill 3 of value (byte) -19
+        CHARS[3217] = 33;
+        Arrays.fill(CHARS, 3218, 3241, (byte) -19 ); // Fill 23 of value (byte) -19
+        CHARS[3241] = 33;
+        Arrays.fill(CHARS, 3242, 3252, (byte) -19 ); // Fill 10 of value (byte) -19
+        CHARS[3252] = 33;
+        Arrays.fill(CHARS, 3253, 3258, (byte) -19 ); // Fill 5 of value (byte) -19
+        Arrays.fill(CHARS, 3258, 3262, (byte) 33 ); // Fill 4 of value (byte) 33
+        Arrays.fill(CHARS, 3262, 3269, (byte) -87 ); // Fill 7 of value (byte) -87
+        CHARS[3269] = 33;
+        Arrays.fill(CHARS, 3270, 3273, (byte) -87 ); // Fill 3 of value (byte) -87
+        CHARS[3273] = 33;
+        Arrays.fill(CHARS, 3274, 3278, (byte) -87 ); // Fill 4 of value (byte) -87
+        Arrays.fill(CHARS, 3278, 3285, (byte) 33 ); // Fill 7 of value (byte) 33
+        Arrays.fill(CHARS, 3285, 3287, (byte) -87 ); // Fill 2 of value (byte) -87
+        Arrays.fill(CHARS, 3287, 3294, (byte) 33 ); // Fill 7 of value (byte) 33
+        CHARS[3294] = -19;
+        CHARS[3295] = 33;
+        Arrays.fill(CHARS, 3296, 3298, (byte) -19 ); // Fill 2 of value (byte) -19
+        Arrays.fill(CHARS, 3298, 3302, (byte) 33 ); // Fill 4 of value (byte) 33
+        Arrays.fill(CHARS, 3302, 3312, (byte) -87 ); // Fill 10 of value (byte) -87
+        Arrays.fill(CHARS, 3312, 3330, (byte) 33 ); // Fill 18 of value (byte) 33
+        Arrays.fill(CHARS, 3330, 3332, (byte) -87 ); // Fill 2 of value (byte) -87
+        CHARS[3332] = 33;
+        Arrays.fill(CHARS, 3333, 3341, (byte) -19 ); // Fill 8 of value (byte) -19
+        CHARS[3341] = 33;
+        Arrays.fill(CHARS, 3342, 3345, (byte) -19 ); // Fill 3 of value (byte) -19
+        CHARS[3345] = 33;
+        Arrays.fill(CHARS, 3346, 3369, (byte) -19 ); // Fill 23 of value (byte) -19
+        CHARS[3369] = 33;
+        Arrays.fill(CHARS, 3370, 3386, (byte) -19 ); // Fill 16 of value (byte) -19
+        Arrays.fill(CHARS, 3386, 3390, (byte) 33 ); // Fill 4 of value (byte) 33
+        Arrays.fill(CHARS, 3390, 3396, (byte) -87 ); // Fill 6 of value (byte) -87
+        Arrays.fill(CHARS, 3396, 3398, (byte) 33 ); // Fill 2 of value (byte) 33
+        Arrays.fill(CHARS, 3398, 3401, (byte) -87 ); // Fill 3 of value (byte) -87
+        CHARS[3401] = 33;
+        Arrays.fill(CHARS, 3402, 3406, (byte) -87 ); // Fill 4 of value (byte) -87
+        Arrays.fill(CHARS, 3406, 3415, (byte) 33 ); // Fill 9 of value (byte) 33
+        CHARS[3415] = -87;
+        Arrays.fill(CHARS, 3416, 3424, (byte) 33 ); // Fill 8 of value (byte) 33
+        Arrays.fill(CHARS, 3424, 3426, (byte) -19 ); // Fill 2 of value (byte) -19
+        Arrays.fill(CHARS, 3426, 3430, (byte) 33 ); // Fill 4 of value (byte) 33
+        Arrays.fill(CHARS, 3430, 3440, (byte) -87 ); // Fill 10 of value (byte) -87
+        Arrays.fill(CHARS, 3440, 3585, (byte) 33 ); // Fill 145 of value (byte) 33
+        Arrays.fill(CHARS, 3585, 3631, (byte) -19 ); // Fill 46 of value (byte) -19
+        CHARS[3631] = 33;
+        CHARS[3632] = -19;
+        CHARS[3633] = -87;
+        Arrays.fill(CHARS, 3634, 3636, (byte) -19 ); // Fill 2 of value (byte) -19
+        Arrays.fill(CHARS, 3636, 3643, (byte) -87 ); // Fill 7 of value (byte) -87
+        Arrays.fill(CHARS, 3643, 3648, (byte) 33 ); // Fill 5 of value (byte) 33
+        Arrays.fill(CHARS, 3648, 3654, (byte) -19 ); // Fill 6 of value (byte) -19
+        Arrays.fill(CHARS, 3654, 3663, (byte) -87 ); // Fill 9 of value (byte) -87
+        CHARS[3663] = 33;
+        Arrays.fill(CHARS, 3664, 3674, (byte) -87 ); // Fill 10 of value (byte) -87
+        Arrays.fill(CHARS, 3674, 3713, (byte) 33 ); // Fill 39 of value (byte) 33
+        Arrays.fill(CHARS, 3713, 3715, (byte) -19 ); // Fill 2 of value (byte) -19
+        CHARS[3715] = 33;
+        CHARS[3716] = -19;
+        Arrays.fill(CHARS, 3717, 3719, (byte) 33 ); // Fill 2 of value (byte) 33
+        Arrays.fill(CHARS, 3719, 3721, (byte) -19 ); // Fill 2 of value (byte) -19
+        CHARS[3721] = 33;
+        CHARS[3722] = -19;
+        Arrays.fill(CHARS, 3723, 3725, (byte) 33 ); // Fill 2 of value (byte) 33
+        CHARS[3725] = -19;
+        Arrays.fill(CHARS, 3726, 3732, (byte) 33 ); // Fill 6 of value (byte) 33
+        Arrays.fill(CHARS, 3732, 3736, (byte) -19 ); // Fill 4 of value (byte) -19
+        CHARS[3736] = 33;
+        Arrays.fill(CHARS, 3737, 3744, (byte) -19 ); // Fill 7 of value (byte) -19
+        CHARS[3744] = 33;
+        Arrays.fill(CHARS, 3745, 3748, (byte) -19 ); // Fill 3 of value (byte) -19
+        CHARS[3748] = 33;
+        CHARS[3749] = -19;
+        CHARS[3750] = 33;
+        CHARS[3751] = -19;
+        Arrays.fill(CHARS, 3752, 3754, (byte) 33 ); // Fill 2 of value (byte) 33
+        Arrays.fill(CHARS, 3754, 3756, (byte) -19 ); // Fill 2 of value (byte) -19
+        CHARS[3756] = 33;
+        Arrays.fill(CHARS, 3757, 3759, (byte) -19 ); // Fill 2 of value (byte) -19
+        CHARS[3759] = 33;
+        CHARS[3760] = -19;
+        CHARS[3761] = -87;
+        Arrays.fill(CHARS, 3762, 3764, (byte) -19 ); // Fill 2 of value (byte) -19
+        Arrays.fill(CHARS, 3764, 3770, (byte) -87 ); // Fill 6 of value (byte) -87
+        CHARS[3770] = 33;
+        Arrays.fill(CHARS, 3771, 3773, (byte) -87 ); // Fill 2 of value (byte) -87
+        CHARS[3773] = -19;
+        Arrays.fill(CHARS, 3774, 3776, (byte) 33 ); // Fill 2 of value (byte) 33
+        Arrays.fill(CHARS, 3776, 3781, (byte) -19 ); // Fill 5 of value (byte) -19
+        CHARS[3781] = 33;
+        CHARS[3782] = -87;
+        CHARS[3783] = 33;
+        Arrays.fill(CHARS, 3784, 3790, (byte) -87 ); // Fill 6 of value (byte) -87
+        Arrays.fill(CHARS, 3790, 3792, (byte) 33 ); // Fill 2 of value (byte) 33
+        Arrays.fill(CHARS, 3792, 3802, (byte) -87 ); // Fill 10 of value (byte) -87
+        Arrays.fill(CHARS, 3802, 3864, (byte) 33 ); // Fill 62 of value (byte) 33
+        Arrays.fill(CHARS, 3864, 3866, (byte) -87 ); // Fill 2 of value (byte) -87
+        Arrays.fill(CHARS, 3866, 3872, (byte) 33 ); // Fill 6 of value (byte) 33
+        Arrays.fill(CHARS, 3872, 3882, (byte) -87 ); // Fill 10 of value (byte) -87
+        Arrays.fill(CHARS, 3882, 3893, (byte) 33 ); // Fill 11 of value (byte) 33
+        CHARS[3893] = -87;
+        CHARS[3894] = 33;
+        CHARS[3895] = -87;
+        CHARS[3896] = 33;
+        CHARS[3897] = -87;
+        Arrays.fill(CHARS, 3898, 3902, (byte) 33 ); // Fill 4 of value (byte) 33
+        Arrays.fill(CHARS, 3902, 3904, (byte) -87 ); // Fill 2 of value (byte) -87
+        Arrays.fill(CHARS, 3904, 3912, (byte) -19 ); // Fill 8 of value (byte) -19
+        CHARS[3912] = 33;
+        Arrays.fill(CHARS, 3913, 3946, (byte) -19 ); // Fill 33 of value (byte) -19
+        Arrays.fill(CHARS, 3946, 3953, (byte) 33 ); // Fill 7 of value (byte) 33
+        Arrays.fill(CHARS, 3953, 3973, (byte) -87 ); // Fill 20 of value (byte) -87
+        CHARS[3973] = 33;
+        Arrays.fill(CHARS, 3974, 3980, (byte) -87 ); // Fill 6 of value (byte) -87
+        Arrays.fill(CHARS, 3980, 3984, (byte) 33 ); // Fill 4 of value (byte) 33
+        Arrays.fill(CHARS, 3984, 3990, (byte) -87 ); // Fill 6 of value (byte) -87
+        CHARS[3990] = 33;
+        CHARS[3991] = -87;
+        CHARS[3992] = 33;
+        Arrays.fill(CHARS, 3993, 4014, (byte) -87 ); // Fill 21 of value (byte) -87
+        Arrays.fill(CHARS, 4014, 4017, (byte) 33 ); // Fill 3 of value (byte) 33
+        Arrays.fill(CHARS, 4017, 4024, (byte) -87 ); // Fill 7 of value (byte) -87
+        CHARS[4024] = 33;
+        CHARS[4025] = -87;
+        Arrays.fill(CHARS, 4026, 4256, (byte) 33 ); // Fill 230 of value (byte) 33
+        Arrays.fill(CHARS, 4256, 4294, (byte) -19 ); // Fill 38 of value (byte) -19
+        Arrays.fill(CHARS, 4294, 4304, (byte) 33 ); // Fill 10 of value (byte) 33
+        Arrays.fill(CHARS, 4304, 4343, (byte) -19 ); // Fill 39 of value (byte) -19
+        Arrays.fill(CHARS, 4343, 4352, (byte) 33 ); // Fill 9 of value (byte) 33
+        CHARS[4352] = -19;
+        CHARS[4353] = 33;
+        Arrays.fill(CHARS, 4354, 4356, (byte) -19 ); // Fill 2 of value (byte) -19
+        CHARS[4356] = 33;
+        Arrays.fill(CHARS, 4357, 4360, (byte) -19 ); // Fill 3 of value (byte) -19
+        CHARS[4360] = 33;
+        CHARS[4361] = -19;
+        CHARS[4362] = 33;
+        Arrays.fill(CHARS, 4363, 4365, (byte) -19 ); // Fill 2 of value (byte) -19
+        CHARS[4365] = 33;
+        Arrays.fill(CHARS, 4366, 4371, (byte) -19 ); // Fill 5 of value (byte) -19
+        Arrays.fill(CHARS, 4371, 4412, (byte) 33 ); // Fill 41 of value (byte) 33
+        CHARS[4412] = -19;
+        CHARS[4413] = 33;
+        CHARS[4414] = -19;
+        CHARS[4415] = 33;
+        CHARS[4416] = -19;
+        Arrays.fill(CHARS, 4417, 4428, (byte) 33 ); // Fill 11 of value (byte) 33
+        CHARS[4428] = -19;
+        CHARS[4429] = 33;
+        CHARS[4430] = -19;
+        CHARS[4431] = 33;
+        CHARS[4432] = -19;
+        Arrays.fill(CHARS, 4433, 4436, (byte) 33 ); // Fill 3 of value (byte) 33
+        Arrays.fill(CHARS, 4436, 4438, (byte) -19 ); // Fill 2 of value (byte) -19
+        Arrays.fill(CHARS, 4438, 4441, (byte) 33 ); // Fill 3 of value (byte) 33
+        CHARS[4441] = -19;
+        Arrays.fill(CHARS, 4442, 4447, (byte) 33 ); // Fill 5 of value (byte) 33
+        Arrays.fill(CHARS, 4447, 4450, (byte) -19 ); // Fill 3 of value (byte) -19
+        CHARS[4450] = 33;
+        CHARS[4451] = -19;
+        CHARS[4452] = 33;
+        CHARS[4453] = -19;
+        CHARS[4454] = 33;
+        CHARS[4455] = -19;
+        CHARS[4456] = 33;
+        CHARS[4457] = -19;
+        Arrays.fill(CHARS, 4458, 4461, (byte) 33 ); // Fill 3 of value (byte) 33
+        Arrays.fill(CHARS, 4461, 4463, (byte) -19 ); // Fill 2 of value (byte) -19
+        Arrays.fill(CHARS, 4463, 4466, (byte) 33 ); // Fill 3 of value (byte) 33
+        Arrays.fill(CHARS, 4466, 4468, (byte) -19 ); // Fill 2 of value (byte) -19
+        CHARS[4468] = 33;
+        CHARS[4469] = -19;
+        Arrays.fill(CHARS, 4470, 4510, (byte) 33 ); // Fill 40 of value (byte) 33
+        CHARS[4510] = -19;
+        Arrays.fill(CHARS, 4511, 4520, (byte) 33 ); // Fill 9 of value (byte) 33
+        CHARS[4520] = -19;
+        Arrays.fill(CHARS, 4521, 4523, (byte) 33 ); // Fill 2 of value (byte) 33
+        CHARS[4523] = -19;
+        Arrays.fill(CHARS, 4524, 4526, (byte) 33 ); // Fill 2 of value (byte) 33
+        Arrays.fill(CHARS, 4526, 4528, (byte) -19 ); // Fill 2 of value (byte) -19
+        Arrays.fill(CHARS, 4528, 4535, (byte) 33 ); // Fill 7 of value (byte) 33
+        Arrays.fill(CHARS, 4535, 4537, (byte) -19 ); // Fill 2 of value (byte) -19
+        CHARS[4537] = 33;
+        CHARS[4538] = -19;
+        CHARS[4539] = 33;
+        Arrays.fill(CHARS, 4540, 4547, (byte) -19 ); // Fill 7 of value (byte) -19
+        Arrays.fill(CHARS, 4547, 4587, (byte) 33 ); // Fill 40 of value (byte) 33
+        CHARS[4587] = -19;
+        Arrays.fill(CHARS, 4588, 4592, (byte) 33 ); // Fill 4 of value (byte) 33
+        CHARS[4592] = -19;
+        Arrays.fill(CHARS, 4593, 4601, (byte) 33 ); // Fill 8 of value (byte) 33
+        CHARS[4601] = -19;
+        Arrays.fill(CHARS, 4602, 7680, (byte) 33 ); // Fill 3078 of value (byte) 33
+        Arrays.fill(CHARS, 7680, 7836, (byte) -19 ); // Fill 156 of value (byte) -19
+        Arrays.fill(CHARS, 7836, 7840, (byte) 33 ); // Fill 4 of value (byte) 33
+        Arrays.fill(CHARS, 7840, 7930, (byte) -19 ); // Fill 90 of value (byte) -19
+        Arrays.fill(CHARS, 7930, 7936, (byte) 33 ); // Fill 6 of value (byte) 33
+        Arrays.fill(CHARS, 7936, 7958, (byte) -19 ); // Fill 22 of value (byte) -19
+        Arrays.fill(CHARS, 7958, 7960, (byte) 33 ); // Fill 2 of value (byte) 33
+        Arrays.fill(CHARS, 7960, 7966, (byte) -19 ); // Fill 6 of value (byte) -19
+        Arrays.fill(CHARS, 7966, 7968, (byte) 33 ); // Fill 2 of value (byte) 33
+        Arrays.fill(CHARS, 7968, 8006, (byte) -19 ); // Fill 38 of value (byte) -19
+        Arrays.fill(CHARS, 8006, 8008, (byte) 33 ); // Fill 2 of value (byte) 33
+        Arrays.fill(CHARS, 8008, 8014, (byte) -19 ); // Fill 6 of value (byte) -19
+        Arrays.fill(CHARS, 8014, 8016, (byte) 33 ); // Fill 2 of value (byte) 33
+        Arrays.fill(CHARS, 8016, 8024, (byte) -19 ); // Fill 8 of value (byte) -19
+        CHARS[8024] = 33;
+        CHARS[8025] = -19;
+        CHARS[8026] = 33;
+        CHARS[8027] = -19;
+        CHARS[8028] = 33;
+        CHARS[8029] = -19;
+        CHARS[8030] = 33;
+        Arrays.fill(CHARS, 8031, 8062, (byte) -19 ); // Fill 31 of value (byte) -19
+        Arrays.fill(CHARS, 8062, 8064, (byte) 33 ); // Fill 2 of value (byte) 33
+        Arrays.fill(CHARS, 8064, 8117, (byte) -19 ); // Fill 53 of value (byte) -19
+        CHARS[8117] = 33;
+        Arrays.fill(CHARS, 8118, 8125, (byte) -19 ); // Fill 7 of value (byte) -19
+        CHARS[8125] = 33;
+        CHARS[8126] = -19;
+        Arrays.fill(CHARS, 8127, 8130, (byte) 33 ); // Fill 3 of value (byte) 33
+        Arrays.fill(CHARS, 8130, 8133, (byte) -19 ); // Fill 3 of value (byte) -19
+        CHARS[8133] = 33;
+        Arrays.fill(CHARS, 8134, 8141, (byte) -19 ); // Fill 7 of value (byte) -19
+        Arrays.fill(CHARS, 8141, 8144, (byte) 33 ); // Fill 3 of value (byte) 33
+        Arrays.fill(CHARS, 8144, 8148, (byte) -19 ); // Fill 4 of value (byte) -19
+        Arrays.fill(CHARS, 8148, 8150, (byte) 33 ); // Fill 2 of value (byte) 33
+        Arrays.fill(CHARS, 8150, 8156, (byte) -19 ); // Fill 6 of value (byte) -19
+        Arrays.fill(CHARS, 8156, 8160, (byte) 33 ); // Fill 4 of value (byte) 33
+        Arrays.fill(CHARS, 8160, 8173, (byte) -19 ); // Fill 13 of value (byte) -19
+        Arrays.fill(CHARS, 8173, 8178, (byte) 33 ); // Fill 5 of value (byte) 33
+        Arrays.fill(CHARS, 8178, 8181, (byte) -19 ); // Fill 3 of value (byte) -19
+        CHARS[8181] = 33;
+        Arrays.fill(CHARS, 8182, 8189, (byte) -19 ); // Fill 7 of value (byte) -19
+        Arrays.fill(CHARS, 8189, 8400, (byte) 33 ); // Fill 211 of value (byte) 33
+        Arrays.fill(CHARS, 8400, 8413, (byte) -87 ); // Fill 13 of value (byte) -87
+        Arrays.fill(CHARS, 8413, 8417, (byte) 33 ); // Fill 4 of value (byte) 33
+        CHARS[8417] = -87;
+        Arrays.fill(CHARS, 8418, 8486, (byte) 33 ); // Fill 68 of value (byte) 33
+        CHARS[8486] = -19;
+        Arrays.fill(CHARS, 8487, 8490, (byte) 33 ); // Fill 3 of value (byte) 33
+        Arrays.fill(CHARS, 8490, 8492, (byte) -19 ); // Fill 2 of value (byte) -19
+        Arrays.fill(CHARS, 8492, 8494, (byte) 33 ); // Fill 2 of value (byte) 33
+        CHARS[8494] = -19;
+        Arrays.fill(CHARS, 8495, 8576, (byte) 33 ); // Fill 81 of value (byte) 33
+        Arrays.fill(CHARS, 8576, 8579, (byte) -19 ); // Fill 3 of value (byte) -19
+        Arrays.fill(CHARS, 8579, 12293, (byte) 33 ); // Fill 3714 of value (byte) 33
+        CHARS[12293] = -87;
+        CHARS[12294] = 33;
+        CHARS[12295] = -19;
+        Arrays.fill(CHARS, 12296, 12321, (byte) 33 ); // Fill 25 of value (byte) 33
+        Arrays.fill(CHARS, 12321, 12330, (byte) -19 ); // Fill 9 of value (byte) -19
+        Arrays.fill(CHARS, 12330, 12336, (byte) -87 ); // Fill 6 of value (byte) -87
+        CHARS[12336] = 33;
+        Arrays.fill(CHARS, 12337, 12342, (byte) -87 ); // Fill 5 of value (byte) -87
+        Arrays.fill(CHARS, 12342, 12353, (byte) 33 ); // Fill 11 of value (byte) 33
+        Arrays.fill(CHARS, 12353, 12437, (byte) -19 ); // Fill 84 of value (byte) -19
+        Arrays.fill(CHARS, 12437, 12441, (byte) 33 ); // Fill 4 of value (byte) 33
+        Arrays.fill(CHARS, 12441, 12443, (byte) -87 ); // Fill 2 of value (byte) -87
+        Arrays.fill(CHARS, 12443, 12445, (byte) 33 ); // Fill 2 of value (byte) 33
+        Arrays.fill(CHARS, 12445, 12447, (byte) -87 ); // Fill 2 of value (byte) -87
+        Arrays.fill(CHARS, 12447, 12449, (byte) 33 ); // Fill 2 of value (byte) 33
+        Arrays.fill(CHARS, 12449, 12539, (byte) -19 ); // Fill 90 of value (byte) -19
+        CHARS[12539] = 33;
+        Arrays.fill(CHARS, 12540, 12543, (byte) -87 ); // Fill 3 of value (byte) -87
+        Arrays.fill(CHARS, 12543, 12549, (byte) 33 ); // Fill 6 of value (byte) 33
+        Arrays.fill(CHARS, 12549, 12589, (byte) -19 ); // Fill 40 of value (byte) -19
+        Arrays.fill(CHARS, 12589, 19968, (byte) 33 ); // Fill 7379 of value (byte) 33
+        Arrays.fill(CHARS, 19968, 40870, (byte) -19 ); // Fill 20902 of value (byte) -19
+        Arrays.fill(CHARS, 40870, 44032, (byte) 33 ); // Fill 3162 of value (byte) 33
+        Arrays.fill(CHARS, 44032, 55204, (byte) -19 ); // Fill 11172 of value (byte) -19
+        Arrays.fill(CHARS, 55204, 55296, (byte) 33 ); // Fill 92 of value (byte) 33
+        Arrays.fill(CHARS, 57344, 65534, (byte) 33 ); // Fill 8190 of value (byte) 33
+
+    } // <clinit>()
+
+    //
+    // Public static methods
+    //
+
+    /**
+     * Returns true if the specified character is a supplemental character.
+     *
+     * @param c The character to check.
+     */
+    public static boolean isSupplemental(int c) {
+        return (c >= 0x10000 && c <= 0x10FFFF);
+    }
+
+    /**
+     * Returns true the supplemental character corresponding to the given
+     * surrogates.
+     *
+     * @param h The high surrogate.
+     * @param l The low surrogate.
+     */
+    public static int supplemental(char h, char l) {
+        return (h - 0xD800) * 0x400 + (l - 0xDC00) + 0x10000;
+    }
+
+    /**
+     * Returns the high surrogate of a supplemental character
+     *
+     * @param c The supplemental character to "split".
+     */
+    public static char highSurrogate(int c) {
+        return (char) (((c - 0x00010000) >> 10) + 0xD800);
+    }
+
+    /**
+     * Returns the low surrogate of a supplemental character
+     *
+     * @param c The supplemental character to "split".
+     */
+    public static char lowSurrogate(int c) {
+        return (char) (((c - 0x00010000) & 0x3FF) + 0xDC00);
+    }
+
+    /**
+     * Returns whether the given character is a high surrogate
+     *
+     * @param c The character to check.
+     */
+    public static boolean isHighSurrogate(int c) {
+        return (0xD800 <= c && c <= 0xDBFF);
+    }
+
+    /**
+     * Returns whether the given character is a low surrogate
+     *
+     * @param c The character to check.
+     */
+    public static boolean isLowSurrogate(int c) {
+        return (0xDC00 <= c && c <= 0xDFFF);
+    }
+
+
+    /**
+     * Returns true if the specified character is valid. This method
+     * also checks the surrogate character range from 0x10000 to 0x10FFFF.
+     * <p>
+     * If the program chooses to apply the mask directly to the
+     * <code>CHARS</code> array, then they are responsible for checking
+     * the surrogate character range.
+     *
+     * @param c The character to check.
+     */
+    public static boolean isValid(int c) {
+        return (c < 0x10000 && (CHARS[c] & MASK_VALID) != 0) ||
+               (0x10000 <= c && c <= 0x10FFFF);
+    } // isValid(int):boolean
+
+    /**
+     * Returns true if the specified character is invalid.
+     *
+     * @param c The character to check.
+     */
+    public static boolean isInvalid(int c) {
+        return !isValid(c);
+    } // isInvalid(int):boolean
+
+    /**
+     * Returns true if the specified character can be considered content.
+     *
+     * @param c The character to check.
+     */
+    public static boolean isContent(int c) {
+        return (c < 0x10000 && (CHARS[c] & MASK_CONTENT) != 0) ||
+               (0x10000 <= c && c <= 0x10FFFF);
+    } // isContent(int):boolean
+
+    /**
+     * Returns true if the specified character can be considered markup.
+     * Markup characters include '&lt;', '&amp;', and '%'.
+     *
+     * @param c The character to check.
+     */
+    public static boolean isMarkup(int c) {
+        return c == '<' || c == '&' || c == '%';
+    } // isMarkup(int):boolean
+
+    /**
+     * Returns true if the specified character is a space character
+     * as defined by production [3] in the XML 1.0 specification.
+     *
+     * @param c The character to check.
+     */
+    public static boolean isSpace(int c) {
+        return c <= 0x20 && (CHARS[c] & MASK_SPACE) != 0;
+    } // isSpace(int):boolean
+
+    /**
+     * Returns true if the specified character is a valid name start
+     * character as defined by production [5] in the XML 1.0
+     * specification.
+     *
+     * @param c The character to check.
+     */
+    public static boolean isNameStart(int c) {
+        return c < 0x10000 && (CHARS[c] & MASK_NAME_START) != 0;
+    } // isNameStart(int):boolean
+
+    /**
+     * Returns true if the specified character is a valid name
+     * character as defined by production [4] in the XML 1.0
+     * specification.
+     *
+     * @param c The character to check.
+     */
+    public static boolean isName(int c) {
+        return c < 0x10000 && (CHARS[c] & MASK_NAME) != 0;
+    } // isName(int):boolean
+
+    /**
+     * Returns true if the specified character is a valid NCName start
+     * character as defined by production [4] in Namespaces in XML
+     * recommendation.
+     *
+     * @param c The character to check.
+     */
+    public static boolean isNCNameStart(int c) {
+        return c < 0x10000 && (CHARS[c] & MASK_NCNAME_START) != 0;
+    } // isNCNameStart(int):boolean
+
+    /**
+     * Returns true if the specified character is a valid NCName
+     * character as defined by production [5] in Namespaces in XML
+     * recommendation.
+     *
+     * @param c The character to check.
+     */
+    public static boolean isNCName(int c) {
+        return c < 0x10000 && (CHARS[c] & MASK_NCNAME) != 0;
+    } // isNCName(int):boolean
+
+    /**
+     * Returns true if the specified character is a valid Pubid
+     * character as defined by production [13] in the XML 1.0
+     * specification.
+     *
+     * @param c The character to check.
+     */
+    public static boolean isPubid(int c) {
+        return c < 0x10000 && (CHARS[c] & MASK_PUBID) != 0;
+    } // isPubid(int):boolean
+
+    /*
+     * [5] Name ::= (Letter | '_' | ':') (NameChar)*
+     */
+    /**
+     * Check to see if a string is a valid Name according to [5]
+     * in the XML 1.0 Recommendation
+     *
+     * @param name string to check
+     * @return true if name is a valid Name
+     */
+    public static boolean isValidName(String name) {
+        if (name.length() == 0)
+            return false;
+        char ch = name.charAt(0);
+        if( isNameStart(ch) == false)
+           return false;
+        for (int i = 1; i < name.length(); i++ ) {
+           ch = name.charAt(i);
+           if( isName( ch ) == false ){
+              return false;
+           }
+        }
+        return true;
+    } // isValidName(String):boolean
+    
+
+    /*
+     * from the namespace rec
+     * [4] NCName ::= (Letter | '_') (NCNameChar)*
+     */
+    /**
+     * Check to see if a string is a valid NCName according to [4]
+     * from the XML Namespaces 1.0 Recommendation
+     *
+     * @param ncName string to check
+     * @return true if name is a valid NCName
+     */
+    public static boolean isValidNCName(String ncName) {
+        if (ncName.length() == 0)
+            return false;
+        char ch = ncName.charAt(0);
+        if( isNCNameStart(ch) == false)
+           return false;
+        for (int i = 1; i < ncName.length(); i++ ) {
+           ch = ncName.charAt(i);
+           if( isNCName( ch ) == false ){
+              return false;
+           }
+        }
+        return true;
+    } // isValidNCName(String):boolean
+
+    /*
+     * [7] Nmtoken ::= (NameChar)+
+     */
+    /**
+     * Check to see if a string is a valid Nmtoken according to [7]
+     * in the XML 1.0 Recommendation
+     *
+     * @param nmtoken string to check
+     * @return true if nmtoken is a valid Nmtoken 
+     */
+    public static boolean isValidNmtoken(String nmtoken) {
+        if (nmtoken.length() == 0)
+            return false;
+        for (int i = 0; i < nmtoken.length(); i++ ) {
+           char ch = nmtoken.charAt(i);
+           if(  ! isName( ch ) ){
+              return false;
+           }
+        }
+        return true;
+    } // isValidName(String):boolean
+
+
+
+
+
+    // encodings
+
+    /**
+     * Returns true if the encoding name is a valid IANA encoding.
+     * This method does not verify that there is a decoder available
+     * for this encoding, only that the characters are valid for an
+     * IANA encoding name.
+     *
+     * @param ianaEncoding The IANA encoding name.
+     */
+    public static boolean isValidIANAEncoding(String ianaEncoding) {
+        if (ianaEncoding != null) {
+            int length = ianaEncoding.length();
+            if (length > 0) {
+                char c = ianaEncoding.charAt(0);
+                if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')) {
+                    for (int i = 1; i < length; i++) {
+                        c = ianaEncoding.charAt(i);
+                        if ((c < 'A' || c > 'Z') && (c < 'a' || c > 'z') &&
+                            (c < '0' || c > '9') && c != '.' && c != '_' &&
+                            c != '-') {
+                            return false;
+                        }
+                    }
+                    return true;
+                }
+            }
+        }
+        return false;
+    } // isValidIANAEncoding(String):boolean
+
+    /**
+     * Returns true if the encoding name is a valid Java encoding.
+     * This method does not verify that there is a decoder available
+     * for this encoding, only that the characters are valid for an
+     * Java encoding name.
+     *
+     * @param javaEncoding The Java encoding name.
+     */
+    public static boolean isValidJavaEncoding(String javaEncoding) {
+        if (javaEncoding != null) {
+            int length = javaEncoding.length();
+            if (length > 0) {
+                for (int i = 1; i < length; i++) {
+                    char c = javaEncoding.charAt(i);
+                    if ((c < 'A' || c > 'Z') && (c < 'a' || c > 'z') &&
+                        (c < '0' || c > '9') && c != '.' && c != '_' &&
+                        c != '-') {
+                        return false;
+                    }
+                }
+                return true;
+            }
+        }
+        return false;
+    } // isValidIANAEncoding(String):boolean
+
+
+} // class XMLChar

Added: branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/xmlparser/XMLEncodingDetector.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/xmlparser/XMLEncodingDetector.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/xmlparser/XMLEncodingDetector.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,1624 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation and was
+ * originally based on software copyright (c) 1999, International
+ * Business Machines, Inc., http://www.apache.org.  For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ */
+
+package org.apache.jasper.xmlparser;
+
+import java.io.EOFException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.IOException;
+import java.io.Reader;
+import java.util.Locale;
+import java.util.jar.JarFile;
+
+import org.apache.jasper.JasperException;
+import org.apache.jasper.JspCompilationContext;
+import org.apache.jasper.compiler.ErrorDispatcher;
+import org.apache.jasper.compiler.JspUtil;
+
+public class XMLEncodingDetector {
+    
+    private InputStream stream;
+    private String encoding;
+    private boolean isEncodingSetInProlog;
+    private Boolean isBigEndian;
+    private Reader reader;
+    
+    // org.apache.xerces.impl.XMLEntityManager fields
+    public static final int DEFAULT_BUFFER_SIZE = 2048;
+    public static final int DEFAULT_XMLDECL_BUFFER_SIZE = 64;
+    private boolean fAllowJavaEncodings;
+    private SymbolTable fSymbolTable;
+    private XMLEncodingDetector fCurrentEntity;
+    private int fBufferSize = DEFAULT_BUFFER_SIZE;
+    
+    // org.apache.xerces.impl.XMLEntityManager.ScannedEntity fields
+    private int lineNumber = 1;
+    private int columnNumber = 1;
+    private boolean literal;
+    private char[] ch = new char[DEFAULT_BUFFER_SIZE];
+    private int position;
+    private int count;
+    private boolean mayReadChunks = false;
+    
+    // org.apache.xerces.impl.XMLScanner fields
+    private XMLString fString = new XMLString();    
+    private XMLStringBuffer fStringBuffer = new XMLStringBuffer();
+    private XMLStringBuffer fStringBuffer2 = new XMLStringBuffer();
+    private final static String fVersionSymbol = "version";
+    private final static String fEncodingSymbol = "encoding";
+    private final static String fStandaloneSymbol = "standalone";
+    
+    // org.apache.xerces.impl.XMLDocumentFragmentScannerImpl fields
+    private int fMarkupDepth = 0;
+    private String[] fStrings = new String[3];
+
+    private ErrorDispatcher err;
+
+    /**
+     * Constructor
+     */
+    public XMLEncodingDetector() {
+        fSymbolTable = new SymbolTable();
+        fCurrentEntity = this;
+    }
+
+    /**
+     * Autodetects the encoding of the XML document supplied by the given
+     * input stream.
+     *
+     * Encoding autodetection is done according to the XML 1.0 specification,
+     * Appendix F.1: Detection Without External Encoding Information.
+     *
+     * @return Two-element array, where the first element (of type
+     * java.lang.String) contains the name of the (auto)detected encoding, and
+     * the second element (of type java.lang.Boolean) specifies whether the 
+     * encoding was specified using the 'encoding' attribute of an XML prolog
+     * (TRUE) or autodetected (FALSE).
+     */
+    public static Object[] getEncoding(String fname, JarFile jarFile,
+                                       JspCompilationContext ctxt,
+                                       ErrorDispatcher err)
+        throws IOException, JasperException
+    {
+        InputStream inStream = JspUtil.getInputStream(fname, jarFile, ctxt,
+                                                      err);
+        XMLEncodingDetector detector = new XMLEncodingDetector();
+        Object[] ret = detector.getEncoding(inStream, err);
+        inStream.close();
+
+        return ret;
+    }
+
+    private Object[] getEncoding(InputStream in, ErrorDispatcher err)
+        throws IOException, JasperException
+    {
+        this.stream = in;
+        this.err=err;
+        createInitialReader();
+        scanXMLDecl();
+	
+        return new Object[] { this.encoding,
+                              new Boolean(this.isEncodingSetInProlog) };
+    }
+    
+    // stub method
+    void endEntity() {
+    }
+    
+    // Adapted from:
+    // org.apache.xerces.impl.XMLEntityManager.startEntity()
+    private void createInitialReader() throws IOException, JasperException {
+
+	// wrap this stream in RewindableInputStream
+	stream = new RewindableInputStream(stream);
+
+	// perform auto-detect of encoding if necessary
+	if (encoding == null) {
+	    // read first four bytes and determine encoding
+	    final byte[] b4 = new byte[4];
+	    int count = 0;
+	    for (; count<4; count++ ) {
+		b4[count] = (byte)stream.read();
+	    }
+	    if (count == 4) {
+		Object [] encodingDesc = getEncodingName(b4, count);
+		encoding = (String)(encodingDesc[0]);
+		isBigEndian = (Boolean)(encodingDesc[1]);
+
+		stream.reset();
+		// Special case UTF-8 files with BOM created by Microsoft
+		// tools. It's more efficient to consume the BOM than make
+		// the reader perform extra checks. -Ac
+		if (count > 2 && encoding.equals("UTF-8")) {
+		    int b0 = b4[0] & 0xFF;
+		    int b1 = b4[1] & 0xFF;
+		    int b2 = b4[2] & 0xFF;
+		    if (b0 == 0xEF && b1 == 0xBB && b2 == 0xBF) {
+			// ignore first three bytes...
+			stream.skip(3);
+		    }
+		}
+		reader = createReader(stream, encoding, isBigEndian);
+	    } else {
+		reader = createReader(stream, encoding, isBigEndian);
+	    }
+	}
+    }
+
+    // Adapted from:
+    // org.apache.xerces.impl.XMLEntityManager.createReader
+    /**
+     * Creates a reader capable of reading the given input stream in
+     * the specified encoding.
+     *
+     * @param inputStream  The input stream.
+     * @param encoding     The encoding name that the input stream is
+     *                     encoded using. If the user has specified that
+     *                     Java encoding names are allowed, then the
+     *                     encoding name may be a Java encoding name;
+     *                     otherwise, it is an ianaEncoding name.
+     * @param isBigEndian   For encodings (like uCS-4), whose names cannot
+     *                      specify a byte order, this tells whether the order
+     *                      is bigEndian. null means unknown or not relevant.
+     *
+     * @return Returns a reader.
+     */
+    private Reader createReader(InputStream inputStream, String encoding,
+				Boolean isBigEndian)
+                throws IOException, JasperException {
+
+        // normalize encoding name
+        if (encoding == null) {
+            encoding = "UTF-8";
+        }
+
+        // try to use an optimized reader
+        String ENCODING = encoding.toUpperCase(Locale.ENGLISH);
+        if (ENCODING.equals("UTF-8")) {
+            return new UTF8Reader(inputStream, fBufferSize);
+        }
+        if (ENCODING.equals("US-ASCII")) {
+            return new ASCIIReader(inputStream, fBufferSize);
+        }
+        if (ENCODING.equals("ISO-10646-UCS-4")) {
+            if (isBigEndian != null) {
+                boolean isBE = isBigEndian.booleanValue();
+                if (isBE) {
+                    return new UCSReader(inputStream, UCSReader.UCS4BE);
+                } else {
+                    return new UCSReader(inputStream, UCSReader.UCS4LE);
+                }
+            } else {
+                err.jspError("jsp.error.xml.encodingByteOrderUnsupported",
+			     encoding);
+            }
+        }
+        if (ENCODING.equals("ISO-10646-UCS-2")) {
+            if (isBigEndian != null) { // sould never happen with this encoding...
+                boolean isBE = isBigEndian.booleanValue();
+                if (isBE) {
+                    return new UCSReader(inputStream, UCSReader.UCS2BE);
+                } else {
+                    return new UCSReader(inputStream, UCSReader.UCS2LE);
+                }
+            } else {
+                err.jspError("jsp.error.xml.encodingByteOrderUnsupported",
+			     encoding);
+            }
+        }
+
+        // check for valid name
+        boolean validIANA = XMLChar.isValidIANAEncoding(encoding);
+        boolean validJava = XMLChar.isValidJavaEncoding(encoding);
+        if (!validIANA || (fAllowJavaEncodings && !validJava)) {
+            err.jspError("jsp.error.xml.encodingDeclInvalid", encoding);
+            // NOTE: AndyH suggested that, on failure, we use ISO Latin 1
+            //       because every byte is a valid ISO Latin 1 character.
+            //       It may not translate correctly but if we failed on
+            //       the encoding anyway, then we're expecting the content
+            //       of the document to be bad. This will just prevent an
+            //       invalid UTF-8 sequence to be detected. This is only
+            //       important when continue-after-fatal-error is turned
+            //       on. -Ac
+            encoding = "ISO-8859-1";
+        }
+
+        // try to use a Java reader
+        String javaEncoding = EncodingMap.getIANA2JavaMapping(ENCODING);
+        if (javaEncoding == null) {
+            if (fAllowJavaEncodings) {
+		javaEncoding = encoding;
+            } else {
+                err.jspError("jsp.error.xml.encodingDeclInvalid", encoding);
+                // see comment above.
+                javaEncoding = "ISO8859_1";
+            }
+        }
+        return new InputStreamReader(inputStream, javaEncoding);
+
+    } // createReader(InputStream,String, Boolean): Reader
+
+    // Adapted from:
+    // org.apache.xerces.impl.XMLEntityManager.getEncodingName
+    /**
+     * Returns the IANA encoding name that is auto-detected from
+     * the bytes specified, with the endian-ness of that encoding where
+     * appropriate.
+     *
+     * @param b4    The first four bytes of the input.
+     * @param count The number of bytes actually read.
+     * @return a 2-element array:  the first element, an IANA-encoding string,
+     *  the second element a Boolean which is true iff the document is big
+     *  endian, false if it's little-endian, and null if the distinction isn't
+     *  relevant.
+     */
+    private Object[] getEncodingName(byte[] b4, int count) {
+
+        if (count < 2) {
+            return new Object[]{"UTF-8", null};
+        }
+
+        // UTF-16, with BOM
+        int b0 = b4[0] & 0xFF;
+        int b1 = b4[1] & 0xFF;
+        if (b0 == 0xFE && b1 == 0xFF) {
+            // UTF-16, big-endian
+            return new Object [] {"UTF-16BE", new Boolean(true)};
+        }
+        if (b0 == 0xFF && b1 == 0xFE) {
+            // UTF-16, little-endian
+            return new Object [] {"UTF-16LE", new Boolean(false)};
+        }
+
+        // default to UTF-8 if we don't have enough bytes to make a
+        // good determination of the encoding
+        if (count < 3) {
+            return new Object [] {"UTF-8", null};
+        }
+
+        // UTF-8 with a BOM
+        int b2 = b4[2] & 0xFF;
+        if (b0 == 0xEF && b1 == 0xBB && b2 == 0xBF) {
+            return new Object [] {"UTF-8", null};
+        }
+
+        // default to UTF-8 if we don't have enough bytes to make a
+        // good determination of the encoding
+        if (count < 4) {
+            return new Object [] {"UTF-8", null};
+        }
+
+        // other encodings
+        int b3 = b4[3] & 0xFF;
+        if (b0 == 0x00 && b1 == 0x00 && b2 == 0x00 && b3 == 0x3C) {
+            // UCS-4, big endian (1234)
+            return new Object [] {"ISO-10646-UCS-4", new Boolean(true)};
+        }
+        if (b0 == 0x3C && b1 == 0x00 && b2 == 0x00 && b3 == 0x00) {
+            // UCS-4, little endian (4321)
+            return new Object [] {"ISO-10646-UCS-4", new Boolean(false)};
+        }
+        if (b0 == 0x00 && b1 == 0x00 && b2 == 0x3C && b3 == 0x00) {
+            // UCS-4, unusual octet order (2143)
+            // REVISIT: What should this be?
+            return new Object [] {"ISO-10646-UCS-4", null};
+        }
+        if (b0 == 0x00 && b1 == 0x3C && b2 == 0x00 && b3 == 0x00) {
+            // UCS-4, unusual octect order (3412)
+            // REVISIT: What should this be?
+            return new Object [] {"ISO-10646-UCS-4", null};
+        }
+        if (b0 == 0x00 && b1 == 0x3C && b2 == 0x00 && b3 == 0x3F) {
+            // UTF-16, big-endian, no BOM
+            // (or could turn out to be UCS-2...
+            // REVISIT: What should this be?
+            return new Object [] {"UTF-16BE", new Boolean(true)};
+        }
+        if (b0 == 0x3C && b1 == 0x00 && b2 == 0x3F && b3 == 0x00) {
+            // UTF-16, little-endian, no BOM
+            // (or could turn out to be UCS-2...
+            return new Object [] {"UTF-16LE", new Boolean(false)};
+        }
+        if (b0 == 0x4C && b1 == 0x6F && b2 == 0xA7 && b3 == 0x94) {
+            // EBCDIC
+            // a la xerces1, return CP037 instead of EBCDIC here
+            return new Object [] {"CP037", null};
+        }
+
+        // default encoding
+        return new Object [] {"UTF-8", null};
+
+    }
+
+    // Adapted from:
+    // org.apache.xerces.impl.XMLEntityManager.EntityScanner.isExternal
+    /** Returns true if the current entity being scanned is external. */
+    public boolean isExternal() {
+	return true;
+    }
+
+    // Adapted from:
+    // org.apache.xerces.impl.XMLEntityManager.EntityScanner.peekChar
+    /**
+     * Returns the next character on the input.
+     * <p>
+     * <strong>Note:</strong> The character is <em>not</em> consumed.
+     *
+     * @throws IOException  Thrown if i/o error occurs.
+     * @throws EOFException Thrown on end of file.
+     */
+    public int peekChar() throws IOException {
+	
+	// load more characters, if needed
+	if (fCurrentEntity.position == fCurrentEntity.count) {
+	    load(0, true);
+	}
+	
+	// peek at character
+	int c = fCurrentEntity.ch[fCurrentEntity.position];
+
+	// return peeked character
+	if (fCurrentEntity.isExternal()) {
+	    return c != '\r' ? c : '\n';
+	}
+	else {
+	    return c;
+	}
+	
+    } // peekChar():int
+    
+    // Adapted from:
+    // org.apache.xerces.impl.XMLEntityManager.EntityScanner.scanChar
+    /**
+     * Returns the next character on the input.
+     * <p>
+     * <strong>Note:</strong> The character is consumed.
+     *
+     * @throws IOException  Thrown if i/o error occurs.
+     * @throws EOFException Thrown on end of file.
+     */
+    public int scanChar() throws IOException {
+
+	// load more characters, if needed
+	if (fCurrentEntity.position == fCurrentEntity.count) {
+	    load(0, true);
+	}
+
+	// scan character
+	int c = fCurrentEntity.ch[fCurrentEntity.position++];
+	boolean external = false;
+	if (c == '\n' ||
+	    (c == '\r' && (external = fCurrentEntity.isExternal()))) {
+	    fCurrentEntity.lineNumber++;
+	    fCurrentEntity.columnNumber = 1;
+	    if (fCurrentEntity.position == fCurrentEntity.count) {
+		fCurrentEntity.ch[0] = (char)c;
+		load(1, false);
+	    }
+	    if (c == '\r' && external) {
+		if (fCurrentEntity.ch[fCurrentEntity.position++] != '\n') {
+		    fCurrentEntity.position--;
+		}
+		c = '\n';
+	    }
+	}
+
+	// return character that was scanned
+	fCurrentEntity.columnNumber++;
+	return c;
+	
+    }
+
+    // Adapted from:
+    // org.apache.xerces.impl.XMLEntityManager.EntityScanner.scanName
+    /**
+     * Returns a string matching the Name production appearing immediately
+     * on the input as a symbol, or null if no Name string is present.
+     * <p>
+     * <strong>Note:</strong> The Name characters are consumed.
+     * <p>
+     * <strong>Note:</strong> The string returned must be a symbol. The
+     * SymbolTable can be used for this purpose.
+     *
+     * @throws IOException  Thrown if i/o error occurs.
+     * @throws EOFException Thrown on end of file.
+     *
+     * @see SymbolTable
+     * @see XMLChar#isName
+     * @see XMLChar#isNameStart
+     */
+    public String scanName() throws IOException {
+	
+	// load more characters, if needed
+	if (fCurrentEntity.position == fCurrentEntity.count) {
+	    load(0, true);
+	}
+	
+	// scan name
+	int offset = fCurrentEntity.position;
+	if (XMLChar.isNameStart(fCurrentEntity.ch[offset])) {
+	    if (++fCurrentEntity.position == fCurrentEntity.count) {
+		fCurrentEntity.ch[0] = fCurrentEntity.ch[offset];
+		offset = 0;
+		if (load(1, false)) {
+		    fCurrentEntity.columnNumber++;
+		    String symbol = fSymbolTable.addSymbol(fCurrentEntity.ch,
+							   0, 1);
+		    return symbol;
+		}
+	    }
+	    while (XMLChar.isName(fCurrentEntity.ch[fCurrentEntity.position])) {
+		if (++fCurrentEntity.position == fCurrentEntity.count) {
+		    int length = fCurrentEntity.position - offset;
+		    if (length == fBufferSize) {
+			// bad luck we have to resize our buffer
+			char[] tmp = new char[fBufferSize * 2];
+			System.arraycopy(fCurrentEntity.ch, offset,
+					 tmp, 0, length);
+			fCurrentEntity.ch = tmp;
+			fBufferSize *= 2;
+		    } else {
+			System.arraycopy(fCurrentEntity.ch, offset,
+					 fCurrentEntity.ch, 0, length);
+		    }
+		    offset = 0;
+		    if (load(length, false)) {
+			break;
+		    }
+		}
+	    }
+	}
+	int length = fCurrentEntity.position - offset;
+	fCurrentEntity.columnNumber += length;
+
+	// return name
+	String symbol = null;
+	if (length > 0) {
+	    symbol = fSymbolTable.addSymbol(fCurrentEntity.ch, offset, length);
+	}
+	return symbol;
+	
+    }
+
+    // Adapted from:
+    // org.apache.xerces.impl.XMLEntityManager.EntityScanner.scanLiteral
+    /**
+     * Scans a range of attribute value data, setting the fields of the
+     * XMLString structure, appropriately.
+     * <p>
+     * <strong>Note:</strong> The characters are consumed.
+     * <p>
+     * <strong>Note:</strong> This method does not guarantee to return
+     * the longest run of attribute value data. This method may return
+     * before the quote character due to reaching the end of the input
+     * buffer or any other reason.
+     * <p>
+     * <strong>Note:</strong> The fields contained in the XMLString
+     * structure are not guaranteed to remain valid upon subsequent calls
+     * to the entity scanner. Therefore, the caller is responsible for
+     * immediately using the returned character data or making a copy of
+     * the character data.
+     *
+     * @param quote   The quote character that signifies the end of the
+     *                attribute value data.
+     * @param content The content structure to fill.
+     *
+     * @return Returns the next character on the input, if known. This
+     *         value may be -1 but this does <em>note</em> designate
+     *         end of file.
+     *
+     * @throws IOException  Thrown if i/o error occurs.
+     * @throws EOFException Thrown on end of file.
+     */
+    public int scanLiteral(int quote, XMLString content)
+	throws IOException {
+
+	// load more characters, if needed
+	if (fCurrentEntity.position == fCurrentEntity.count) {
+	    load(0, true);
+	} else if (fCurrentEntity.position == fCurrentEntity.count - 1) {
+	    fCurrentEntity.ch[0] = fCurrentEntity.ch[fCurrentEntity.count - 1];
+	    load(1, false);
+	    fCurrentEntity.position = 0;
+	}
+
+	// normalize newlines
+	int offset = fCurrentEntity.position;
+	int c = fCurrentEntity.ch[offset];
+	int newlines = 0;
+	boolean external = fCurrentEntity.isExternal();
+	if (c == '\n' || (c == '\r' && external)) {
+	    do {
+		c = fCurrentEntity.ch[fCurrentEntity.position++];
+		if (c == '\r' && external) {
+		    newlines++;
+		    fCurrentEntity.lineNumber++;
+		    fCurrentEntity.columnNumber = 1;
+		    if (fCurrentEntity.position == fCurrentEntity.count) {
+			offset = 0;
+			fCurrentEntity.position = newlines;
+			if (load(newlines, false)) {
+			    break;
+			}
+		    }
+		    if (fCurrentEntity.ch[fCurrentEntity.position] == '\n') {
+			fCurrentEntity.position++;
+			offset++;
+		    }
+		    /*** NEWLINE NORMALIZATION ***/
+		    else {
+			newlines++;
+		    }
+		    /***/
+		}
+		else if (c == '\n') {
+		    newlines++;
+		    fCurrentEntity.lineNumber++;
+		    fCurrentEntity.columnNumber = 1;
+		    if (fCurrentEntity.position == fCurrentEntity.count) {
+			offset = 0;
+			fCurrentEntity.position = newlines;
+			if (load(newlines, false)) {
+			    break;
+			}
+		    }
+		    /*** NEWLINE NORMALIZATION ***
+			 if (fCurrentEntity.ch[fCurrentEntity.position] == '\r'
+			 && external) {
+			 fCurrentEntity.position++;
+			 offset++;
+			 }
+			 /***/
+		}
+		else {
+		    fCurrentEntity.position--;
+		    break;
+		}
+	    } while (fCurrentEntity.position < fCurrentEntity.count - 1);
+	    for (int i = offset; i < fCurrentEntity.position; i++) {
+		fCurrentEntity.ch[i] = '\n';
+	    }
+	    int length = fCurrentEntity.position - offset;
+	    if (fCurrentEntity.position == fCurrentEntity.count - 1) {
+		content.setValues(fCurrentEntity.ch, offset, length);
+		return -1;
+	    }
+	}
+
+	// scan literal value
+	while (fCurrentEntity.position < fCurrentEntity.count) {
+	    c = fCurrentEntity.ch[fCurrentEntity.position++];
+	    if ((c == quote &&
+		 (!fCurrentEntity.literal || external))
+		|| c == '%' || !XMLChar.isContent(c)) {
+		fCurrentEntity.position--;
+		break;
+	    }
+	}
+	int length = fCurrentEntity.position - offset;
+	fCurrentEntity.columnNumber += length - newlines;
+	content.setValues(fCurrentEntity.ch, offset, length);
+
+	// return next character
+	if (fCurrentEntity.position != fCurrentEntity.count) {
+	    c = fCurrentEntity.ch[fCurrentEntity.position];
+	    // NOTE: We don't want to accidentally signal the
+	    //       end of the literal if we're expanding an
+	    //       entity appearing in the literal. -Ac
+	    if (c == quote && fCurrentEntity.literal) {
+		c = -1;
+	    }
+	}
+	else {
+	    c = -1;
+	}
+	return c;
+
+    }
+
+    /**
+     * Scans a range of character data up to the specified delimiter,
+     * setting the fields of the XMLString structure, appropriately.
+     * <p>
+     * <strong>Note:</strong> The characters are consumed.
+     * <p>
+     * <strong>Note:</strong> This assumes that the internal buffer is
+     * at least the same size, or bigger, than the length of the delimiter
+     * and that the delimiter contains at least one character.
+     * <p>
+     * <strong>Note:</strong> This method does not guarantee to return
+     * the longest run of character data. This method may return before
+     * the delimiter due to reaching the end of the input buffer or any
+     * other reason.
+     * <p>
+     * <strong>Note:</strong> The fields contained in the XMLString
+     * structure are not guaranteed to remain valid upon subsequent calls
+     * to the entity scanner. Therefore, the caller is responsible for
+     * immediately using the returned character data or making a copy of
+     * the character data.
+     *
+     * @param delimiter The string that signifies the end of the character
+     *                  data to be scanned.
+     * @param buffer    The data structure to fill.
+     *
+     * @return Returns true if there is more data to scan, false otherwise.
+     *
+     * @throws IOException  Thrown if i/o error occurs.
+     * @throws EOFException Thrown on end of file.
+     */
+    public boolean scanData(String delimiter, XMLStringBuffer buffer)
+	throws IOException {
+
+	boolean done = false;
+	int delimLen = delimiter.length();
+	char charAt0 = delimiter.charAt(0);
+	boolean external = fCurrentEntity.isExternal();
+	do {
+    
+	    // load more characters, if needed
+    
+	    if (fCurrentEntity.position == fCurrentEntity.count) {
+		load(0, true);
+	    }
+	    else if (fCurrentEntity.position >= fCurrentEntity.count - delimLen) {
+		System.arraycopy(fCurrentEntity.ch, fCurrentEntity.position,
+				 fCurrentEntity.ch, 0, fCurrentEntity.count - fCurrentEntity.position);
+		load(fCurrentEntity.count - fCurrentEntity.position, false);
+		fCurrentEntity.position = 0;
+	    } 
+	    if (fCurrentEntity.position >= fCurrentEntity.count - delimLen) {
+		// something must be wrong with the input: e.g., file ends an
+		// unterminated comment
+		int length = fCurrentEntity.count - fCurrentEntity.position;
+		buffer.append (fCurrentEntity.ch, fCurrentEntity.position,
+			       length); 
+		fCurrentEntity.columnNumber += fCurrentEntity.count;
+		fCurrentEntity.position = fCurrentEntity.count;
+		load(0,true);
+		return false;
+	    }
+    
+	    // normalize newlines
+	    int offset = fCurrentEntity.position;
+	    int c = fCurrentEntity.ch[offset];
+	    int newlines = 0;
+	    if (c == '\n' || (c == '\r' && external)) {
+		do {
+		    c = fCurrentEntity.ch[fCurrentEntity.position++];
+		    if (c == '\r' && external) {
+			newlines++;
+			fCurrentEntity.lineNumber++;
+			fCurrentEntity.columnNumber = 1;
+			if (fCurrentEntity.position == fCurrentEntity.count) {
+			    offset = 0;
+			    fCurrentEntity.position = newlines;
+			    if (load(newlines, false)) {
+				break;
+			    }
+			}
+			if (fCurrentEntity.ch[fCurrentEntity.position] == '\n') {
+			    fCurrentEntity.position++;
+			    offset++;
+			}
+			/*** NEWLINE NORMALIZATION ***/
+			else {
+			    newlines++;
+			}
+		    }
+		    else if (c == '\n') {
+			newlines++;
+			fCurrentEntity.lineNumber++;
+			fCurrentEntity.columnNumber = 1;
+			if (fCurrentEntity.position == fCurrentEntity.count) {
+			    offset = 0;
+			    fCurrentEntity.position = newlines;
+			    fCurrentEntity.count = newlines;
+			    if (load(newlines, false)) {
+				break;
+			    }
+			}
+		    }
+		    else {
+			fCurrentEntity.position--;
+			break;
+		    }
+		} while (fCurrentEntity.position < fCurrentEntity.count - 1);
+		for (int i = offset; i < fCurrentEntity.position; i++) {
+		    fCurrentEntity.ch[i] = '\n';
+		}
+		int length = fCurrentEntity.position - offset;
+		if (fCurrentEntity.position == fCurrentEntity.count - 1) {
+		    buffer.append(fCurrentEntity.ch, offset, length);
+		    return true;
+		}
+	    }
+    
+	    // iterate over buffer looking for delimiter
+	OUTER: while (fCurrentEntity.position < fCurrentEntity.count) {
+	    c = fCurrentEntity.ch[fCurrentEntity.position++];
+	    if (c == charAt0) {
+		// looks like we just hit the delimiter
+		int delimOffset = fCurrentEntity.position - 1;
+		for (int i = 1; i < delimLen; i++) {
+		    if (fCurrentEntity.position == fCurrentEntity.count) {
+			fCurrentEntity.position -= i;
+			break OUTER;
+		    }
+		    c = fCurrentEntity.ch[fCurrentEntity.position++];
+		    if (delimiter.charAt(i) != c) {
+			fCurrentEntity.position--;
+			break;
+		    }
+		}
+		if (fCurrentEntity.position == delimOffset + delimLen) {
+		    done = true;
+		    break;
+		}
+	    }
+	    else if (c == '\n' || (external && c == '\r')) {
+		fCurrentEntity.position--;
+		break;
+	    }
+	    else if (XMLChar.isInvalid(c)) {
+		fCurrentEntity.position--;
+		int length = fCurrentEntity.position - offset;
+		fCurrentEntity.columnNumber += length - newlines;
+		buffer.append(fCurrentEntity.ch, offset, length); 
+		return true;
+	    }
+	}
+	    int length = fCurrentEntity.position - offset;
+	    fCurrentEntity.columnNumber += length - newlines;
+	    if (done) {
+		length -= delimLen;
+	    }
+	    buffer.append (fCurrentEntity.ch, offset, length);
+    
+	    // return true if string was skipped
+	} while (!done);
+	return !done;
+
+    }
+
+    // Adapted from:
+    // org.apache.xerces.impl.XMLEntityManager.EntityScanner.skipChar
+    /**
+     * Skips a character appearing immediately on the input.
+     * <p>
+     * <strong>Note:</strong> The character is consumed only if it matches
+     * the specified character.
+     *
+     * @param c The character to skip.
+     *
+     * @return Returns true if the character was skipped.
+     *
+     * @throws IOException  Thrown if i/o error occurs.
+     * @throws EOFException Thrown on end of file.
+     */
+    public boolean skipChar(int c) throws IOException {
+
+	// load more characters, if needed
+	if (fCurrentEntity.position == fCurrentEntity.count) {
+	    load(0, true);
+	}
+
+	// skip character
+	int cc = fCurrentEntity.ch[fCurrentEntity.position];
+	if (cc == c) {
+	    fCurrentEntity.position++;
+	    if (c == '\n') {
+		fCurrentEntity.lineNumber++;
+		fCurrentEntity.columnNumber = 1;
+	    }
+	    else {
+		fCurrentEntity.columnNumber++;
+	    }
+	    return true;
+	} else if (c == '\n' && cc == '\r' && fCurrentEntity.isExternal()) {
+	    // handle newlines
+	    if (fCurrentEntity.position == fCurrentEntity.count) {
+		fCurrentEntity.ch[0] = (char)cc;
+		load(1, false);
+	    }
+	    fCurrentEntity.position++;
+	    if (fCurrentEntity.ch[fCurrentEntity.position] == '\n') {
+		fCurrentEntity.position++;
+	    }
+	    fCurrentEntity.lineNumber++;
+	    fCurrentEntity.columnNumber = 1;
+	    return true;
+	}
+
+	// character was not skipped
+	return false;
+
+    }
+
+    // Adapted from:
+    // org.apache.xerces.impl.XMLEntityManager.EntityScanner.skipSpaces
+    /**
+     * Skips space characters appearing immediately on the input.
+     * <p>
+     * <strong>Note:</strong> The characters are consumed only if they are
+     * space characters.
+     *
+     * @return Returns true if at least one space character was skipped.
+     *
+     * @throws IOException  Thrown if i/o error occurs.
+     * @throws EOFException Thrown on end of file.
+     *
+     * @see XMLChar#isSpace
+     */
+    public boolean skipSpaces() throws IOException {
+
+	// load more characters, if needed
+	if (fCurrentEntity.position == fCurrentEntity.count) {
+	    load(0, true);
+	}
+
+	// skip spaces
+	int c = fCurrentEntity.ch[fCurrentEntity.position];
+	if (XMLChar.isSpace(c)) {
+	    boolean external = fCurrentEntity.isExternal();
+	    do {
+		boolean entityChanged = false;
+		// handle newlines
+		if (c == '\n' || (external && c == '\r')) {
+		    fCurrentEntity.lineNumber++;
+		    fCurrentEntity.columnNumber = 1;
+		    if (fCurrentEntity.position == fCurrentEntity.count - 1) {
+			fCurrentEntity.ch[0] = (char)c;
+			entityChanged = load(1, true);
+			if (!entityChanged)
+                                // the load change the position to be 1,
+                                // need to restore it when entity not changed
+			    fCurrentEntity.position = 0;
+		    }
+		    if (c == '\r' && external) {
+			// REVISIT: Does this need to be updated to fix the
+			//          #x0D ^#x0A newline normalization problem? -Ac
+			if (fCurrentEntity.ch[++fCurrentEntity.position] != '\n') {
+			    fCurrentEntity.position--;
+			}
+		    }
+		    /*** NEWLINE NORMALIZATION ***
+			 else {
+			 if (fCurrentEntity.ch[fCurrentEntity.position + 1] == '\r'
+			 && external) {
+			 fCurrentEntity.position++;
+			 }
+			 }
+			 /***/
+		}
+		else {
+		    fCurrentEntity.columnNumber++;
+		}
+		// load more characters, if needed
+		if (!entityChanged)
+		    fCurrentEntity.position++;
+		if (fCurrentEntity.position == fCurrentEntity.count) {
+		    load(0, true);
+		}
+	    } while (XMLChar.isSpace(c = fCurrentEntity.ch[fCurrentEntity.position]));
+	    return true;
+	}
+
+	// no spaces were found
+	return false;
+
+    }
+
+    /**
+     * Skips the specified string appearing immediately on the input.
+     * <p>
+     * <strong>Note:</strong> The characters are consumed only if they are
+     * space characters.
+     *
+     * @param s The string to skip.
+     *
+     * @return Returns true if the string was skipped.
+     *
+     * @throws IOException  Thrown if i/o error occurs.
+     * @throws EOFException Thrown on end of file.
+     */
+    public boolean skipString(String s) throws IOException {
+
+	// load more characters, if needed
+	if (fCurrentEntity.position == fCurrentEntity.count) {
+	    load(0, true);
+	}
+
+	// skip string
+	final int length = s.length();
+	for (int i = 0; i < length; i++) {
+	    char c = fCurrentEntity.ch[fCurrentEntity.position++];
+	    if (c != s.charAt(i)) {
+		fCurrentEntity.position -= i + 1;
+		return false;
+	    }
+	    if (i < length - 1 && fCurrentEntity.position == fCurrentEntity.count) {
+		System.arraycopy(fCurrentEntity.ch, fCurrentEntity.count - i - 1, fCurrentEntity.ch, 0, i + 1);
+		// REVISIT: Can a string to be skipped cross an
+		//          entity boundary? -Ac
+		if (load(i + 1, false)) {
+		    fCurrentEntity.position -= i + 1;
+		    return false;
+		}
+	    }
+	}
+	fCurrentEntity.columnNumber += length;
+	return true;
+
+    }
+
+    // Adapted from:
+    // org.apache.xerces.impl.XMLEntityManager.EntityScanner.load
+    /**
+     * Loads a chunk of text.
+     *
+     * @param offset       The offset into the character buffer to
+     *                     read the next batch of characters.
+     * @param changeEntity True if the load should change entities
+     *                     at the end of the entity, otherwise leave
+     *                     the current entity in place and the entity
+     *                     boundary will be signaled by the return
+     *                     value.
+     *
+     * @returns Returns true if the entity changed as a result of this
+     *          load operation.
+     */
+    final boolean load(int offset, boolean changeEntity)
+	throws IOException {
+
+	// read characters
+	int length = fCurrentEntity.mayReadChunks?
+	    (fCurrentEntity.ch.length - offset):
+	    (DEFAULT_XMLDECL_BUFFER_SIZE);
+	int count = fCurrentEntity.reader.read(fCurrentEntity.ch, offset,
+					       length);
+
+	// reset count and position
+	boolean entityChanged = false;
+	if (count != -1) {
+	    if (count != 0) {
+		fCurrentEntity.count = count + offset;
+		fCurrentEntity.position = offset;
+	    }
+	}
+
+	// end of this entity
+	else {
+	    fCurrentEntity.count = offset;
+	    fCurrentEntity.position = offset;
+	    entityChanged = true;
+	    if (changeEntity) {
+		endEntity();
+		if (fCurrentEntity == null) {
+		    throw new EOFException();
+		}
+		// handle the trailing edges
+		if (fCurrentEntity.position == fCurrentEntity.count) {
+		    load(0, false);
+		}
+	    }
+	}
+
+	return entityChanged;
+
+    }
+
+    // Adapted from:
+    // org.apache.xerces.impl.XMLEntityManager.RewindableInputStream
+    /**
+     * This class wraps the byte inputstreams we're presented with.
+     * We need it because java.io.InputStreams don't provide
+     * functionality to reread processed bytes, and they have a habit
+     * of reading more than one character when you call their read()
+     * methods.  This means that, once we discover the true (declared)
+     * encoding of a document, we can neither backtrack to read the
+     * whole doc again nor start reading where we are with a new
+     * reader.
+     *
+     * This class allows rewinding an inputStream by allowing a mark
+     * to be set, and the stream reset to that position.  <strong>The
+     * class assumes that it needs to read one character per
+     * invocation when it's read() method is inovked, but uses the
+     * underlying InputStream's read(char[], offset length) method--it
+     * won't buffer data read this way!</strong>
+     *
+     * @author Neil Graham, IBM
+     * @author Glenn Marcy, IBM
+     */
+    private final class RewindableInputStream extends InputStream {
+
+        private InputStream fInputStream;
+        private byte[] fData;
+        private int fStartOffset;
+        private int fEndOffset;
+        private int fOffset;
+        private int fLength;
+        private int fMark;
+
+        public RewindableInputStream(InputStream is) {
+            fData = new byte[DEFAULT_XMLDECL_BUFFER_SIZE];
+            fInputStream = is;
+            fStartOffset = 0;
+            fEndOffset = -1;
+            fOffset = 0;
+            fLength = 0;
+            fMark = 0;
+        }
+
+        public void setStartOffset(int offset) {
+            fStartOffset = offset;
+        }
+
+        public void rewind() {
+            fOffset = fStartOffset;
+        }
+
+        public int read() throws IOException {
+            int b = 0;
+            if (fOffset < fLength) {
+                return fData[fOffset++] & 0xff;
+            }
+            if (fOffset == fEndOffset) {
+                return -1;
+            }
+            if (fOffset == fData.length) {
+                byte[] newData = new byte[fOffset << 1];
+                System.arraycopy(fData, 0, newData, 0, fOffset);
+                fData = newData;
+            }
+            b = fInputStream.read();
+            if (b == -1) {
+                fEndOffset = fOffset;
+                return -1;
+            }
+            fData[fLength++] = (byte)b;
+            fOffset++;
+            return b & 0xff;
+        }
+
+        public int read(byte[] b, int off, int len) throws IOException {
+            int bytesLeft = fLength - fOffset;
+            if (bytesLeft == 0) {
+                if (fOffset == fEndOffset) {
+                    return -1;
+                }
+                // better get some more for the voracious reader...
+                if (fCurrentEntity.mayReadChunks) {
+                    return fInputStream.read(b, off, len);
+                }
+                int returnedVal = read();
+                if (returnedVal == -1) {
+                    fEndOffset = fOffset;
+                    return -1;
+                }
+                b[off] = (byte)returnedVal;
+                return 1;
+            }
+            if (len < bytesLeft) {
+                if (len <= 0) {
+                    return 0;
+                }
+            }
+            else {
+                len = bytesLeft;
+            }
+            if (b != null) {
+                System.arraycopy(fData, fOffset, b, off, len);
+            }
+            fOffset += len;
+            return len;
+        }
+
+        public long skip(long n)
+            throws IOException
+        {
+            int bytesLeft;
+            if (n <= 0) {
+                return 0;
+            }
+            bytesLeft = fLength - fOffset;
+            if (bytesLeft == 0) {
+                if (fOffset == fEndOffset) {
+                    return 0;
+                }
+                return fInputStream.skip(n);
+            }
+            if (n <= bytesLeft) {
+                fOffset += n;
+                return n;
+            }
+            fOffset += bytesLeft;
+            if (fOffset == fEndOffset) {
+                return bytesLeft;
+            }
+            n -= bytesLeft;
+	    /*
+	     * In a manner of speaking, when this class isn't permitting more
+	     * than one byte at a time to be read, it is "blocking".  The
+	     * available() method should indicate how much can be read without
+	     * blocking, so while we're in this mode, it should only indicate
+	     * that bytes in its buffer are available; otherwise, the result of
+	     * available() on the underlying InputStream is appropriate.
+	     */
+            return fInputStream.skip(n) + bytesLeft;
+        }
+
+        public int available() throws IOException {
+            int bytesLeft = fLength - fOffset;
+            if (bytesLeft == 0) {
+                if (fOffset == fEndOffset) {
+                    return -1;
+                }
+                return fCurrentEntity.mayReadChunks ? fInputStream.available()
+		    : 0;
+            }
+            return bytesLeft;
+        }
+
+        public void mark(int howMuch) {
+            fMark = fOffset;
+        }
+
+        public void reset() {
+            fOffset = fMark;
+        }
+
+        public boolean markSupported() {
+            return true;
+        }
+
+        public void close() throws IOException {
+            if (fInputStream != null) {
+                fInputStream.close();
+                fInputStream = null;
+            }
+        }
+    } // end of RewindableInputStream class
+
+    // Adapted from:
+    // org.apache.xerces.impl.XMLDocumentScannerImpl.dispatch
+    private void scanXMLDecl() throws IOException, JasperException {
+
+	if (skipString("<?xml")) {
+	    fMarkupDepth++;
+	    // NOTE: special case where document starts with a PI
+	    //       whose name starts with "xml" (e.g. "xmlfoo")
+	    if (XMLChar.isName(peekChar())) {
+		fStringBuffer.clear();
+		fStringBuffer.append("xml");
+		while (XMLChar.isName(peekChar())) {
+		    fStringBuffer.append((char)scanChar());
+		}
+		String target = fSymbolTable.addSymbol(fStringBuffer.ch,
+						       fStringBuffer.offset,
+						       fStringBuffer.length);
+		scanPIData(target, fString);
+	    }
+
+	    // standard XML declaration
+	    else {
+		scanXMLDeclOrTextDecl(false);
+	    }
+	}
+    }
+    
+    // Adapted from:
+    // org.apache.xerces.impl.XMLDocumentFragmentScannerImpl.scanXMLDeclOrTextDecl
+    /**
+     * Scans an XML or text declaration.
+     * <p>
+     * <pre>
+     * [23] XMLDecl ::= '&lt;?xml' VersionInfo EncodingDecl? SDDecl? S? '?>'
+     * [24] VersionInfo ::= S 'version' Eq (' VersionNum ' | " VersionNum ")
+     * [80] EncodingDecl ::= S 'encoding' Eq ('"' EncName '"' |  "'" EncName "'" )
+     * [81] EncName ::= [A-Za-z] ([A-Za-z0-9._] | '-')*
+     * [32] SDDecl ::= S 'standalone' Eq (("'" ('yes' | 'no') "'")
+     *                 | ('"' ('yes' | 'no') '"'))
+     *
+     * [77] TextDecl ::= '&lt;?xml' VersionInfo? EncodingDecl S? '?>'
+     * </pre>
+     *
+     * @param scanningTextDecl True if a text declaration is to
+     *                         be scanned instead of an XML
+     *                         declaration.
+     */
+    private void scanXMLDeclOrTextDecl(boolean scanningTextDecl) 
+        throws IOException, JasperException {
+
+        // scan decl
+        scanXMLDeclOrTextDecl(scanningTextDecl, fStrings);
+        fMarkupDepth--;
+
+        // pseudo-attribute values
+        String encodingPseudoAttr = fStrings[1];
+
+        // set encoding on reader
+        if (encodingPseudoAttr != null) {
+            isEncodingSetInProlog = true;
+	    encoding = encodingPseudoAttr;
+        }
+    }
+
+    // Adapted from:
+    // org.apache.xerces.impl.XMLScanner.scanXMLDeclOrTextDecl
+    /**
+     * Scans an XML or text declaration.
+     * <p>
+     * <pre>
+     * [23] XMLDecl ::= '<?xml' VersionInfo EncodingDecl? SDDecl? S? '?>'
+     * [24] VersionInfo ::= S 'version' Eq (' VersionNum ' | " VersionNum ")
+     * [80] EncodingDecl ::= S 'encoding' Eq ('"' EncName '"' |  "'" EncName "'" )
+     * [81] EncName ::= [A-Za-z] ([A-Za-z0-9._] | '-')*
+     * [32] SDDecl ::= S 'standalone' Eq (("'" ('yes' | 'no') "'")
+     *                 | ('"' ('yes' | 'no') '"'))
+     *
+     * [77] TextDecl ::= '<?xml' VersionInfo? EncodingDecl S? '?>'
+     * </pre>
+     *
+     * @param scanningTextDecl True if a text declaration is to
+     *                         be scanned instead of an XML
+     *                         declaration.
+     * @param pseudoAttributeValues An array of size 3 to return the version,
+     *                         encoding and standalone pseudo attribute values
+     *                         (in that order).
+     *
+     * <strong>Note:</strong> This method uses fString, anything in it
+     * at the time of calling is lost.
+     */
+    private void scanXMLDeclOrTextDecl(boolean scanningTextDecl,
+				       String[] pseudoAttributeValues) 
+                throws IOException, JasperException {
+
+        // pseudo-attribute values
+        String version = null;
+        String encoding = null;
+        String standalone = null;
+
+        // scan pseudo-attributes
+        final int STATE_VERSION = 0;
+        final int STATE_ENCODING = 1;
+        final int STATE_STANDALONE = 2;
+        final int STATE_DONE = 3;
+        int state = STATE_VERSION;
+
+        boolean dataFoundForTarget = false;
+        boolean sawSpace = skipSpaces();
+        while (peekChar() != '?') {
+            dataFoundForTarget = true;
+            String name = scanPseudoAttribute(scanningTextDecl, fString);
+            switch (state) {
+                case STATE_VERSION: {
+                    if (name == fVersionSymbol) {
+                        if (!sawSpace) {
+                            reportFatalError(scanningTextDecl
+                                       ? "jsp.error.xml.spaceRequiredBeforeVersionInTextDecl"
+                                       : "jsp.error.xml.spaceRequiredBeforeVersionInXMLDecl",
+                                             null);
+                        }
+                        version = fString.toString();
+                        state = STATE_ENCODING;
+                        if (!version.equals("1.0")) {
+                            // REVISIT: XML REC says we should throw an error
+			    // in such cases.
+                            // some may object the throwing of fatalError.
+                            err.jspError("jsp.error.xml.versionNotSupported",
+					 version);
+                        }
+                    } else if (name == fEncodingSymbol) {
+                        if (!scanningTextDecl) {
+                            err.jspError("jsp.error.xml.versionInfoRequired");
+                        }
+                        if (!sawSpace) {
+                            reportFatalError(scanningTextDecl
+                                      ? "jsp.error.xml.spaceRequiredBeforeEncodingInTextDecl"
+                                      : "jsp.error.xml.spaceRequiredBeforeEncodingInXMLDecl",
+                                             null);
+                        }
+                        encoding = fString.toString();
+                        state = scanningTextDecl ? STATE_DONE : STATE_STANDALONE;
+                    } else {
+                        if (scanningTextDecl) {
+                            err.jspError("jsp.error.xml.encodingDeclRequired");
+                        }
+                        else {
+                            err.jspError("jsp.error.xml.versionInfoRequired");
+                        }
+                    }
+                    break;
+                }
+                case STATE_ENCODING: {
+                    if (name == fEncodingSymbol) {
+                        if (!sawSpace) {
+                            reportFatalError(scanningTextDecl
+                                      ? "jsp.error.xml.spaceRequiredBeforeEncodingInTextDecl"
+                                      : "jsp.error.xml.spaceRequiredBeforeEncodingInXMLDecl",
+                                             null);
+                        }
+                        encoding = fString.toString();
+                        state = scanningTextDecl ? STATE_DONE : STATE_STANDALONE;
+                        // TODO: check encoding name; set encoding on
+                        //       entity scanner
+                    } else if (!scanningTextDecl && name == fStandaloneSymbol) {
+                        if (!sawSpace) {
+                            err.jspError("jsp.error.xml.spaceRequiredBeforeStandalone");
+                        }
+                        standalone = fString.toString();
+                        state = STATE_DONE;
+                        if (!standalone.equals("yes") && !standalone.equals("no")) {
+                            err.jspError("jsp.error.xml.sdDeclInvalid");
+                        }
+                    } else {
+                        err.jspError("jsp.error.xml.encodingDeclRequired");
+                    }
+                    break;
+                }
+                case STATE_STANDALONE: {
+                    if (name == fStandaloneSymbol) {
+                        if (!sawSpace) {
+                            err.jspError("jsp.error.xml.spaceRequiredBeforeStandalone");
+                        }
+                        standalone = fString.toString();
+                        state = STATE_DONE;
+                        if (!standalone.equals("yes") && !standalone.equals("no")) {
+                            err.jspError("jsp.error.xml.sdDeclInvalid");
+                        }
+                    } else {
+			err.jspError("jsp.error.xml.encodingDeclRequired");
+                    }
+                    break;
+                }
+                default: {
+                    err.jspError("jsp.error.xml.noMorePseudoAttributes");
+                }
+            }
+            sawSpace = skipSpaces();
+        }
+        // REVISIT: should we remove this error reporting?
+        if (scanningTextDecl && state != STATE_DONE) {
+            err.jspError("jsp.error.xml.morePseudoAttributes");
+        }
+        
+        // If there is no data in the xml or text decl then we fail to report
+	// error for version or encoding info above.
+        if (scanningTextDecl) {
+            if (!dataFoundForTarget && encoding == null) {
+                err.jspError("jsp.error.xml.encodingDeclRequired");
+            }
+        } else {
+            if (!dataFoundForTarget && version == null) {
+                err.jspError("jsp.error.xml.versionInfoRequired");
+            }
+        }
+
+        // end
+        if (!skipChar('?')) {
+            err.jspError("jsp.error.xml.xmlDeclUnterminated");
+        }
+        if (!skipChar('>')) {
+            err.jspError("jsp.error.xml.xmlDeclUnterminated");
+
+        }
+        
+        // fill in return array
+        pseudoAttributeValues[0] = version;
+        pseudoAttributeValues[1] = encoding;
+        pseudoAttributeValues[2] = standalone;
+    }
+
+    // Adapted from:
+    // org.apache.xerces.impl.XMLScanner.scanPseudoAttribute
+    /**
+     * Scans a pseudo attribute.
+     *
+     * @param scanningTextDecl True if scanning this pseudo-attribute for a
+     *                         TextDecl; false if scanning XMLDecl. This 
+     *                         flag is needed to report the correct type of
+     *                         error.
+     * @param value            The string to fill in with the attribute 
+     *                         value.
+     *
+     * @return The name of the attribute
+     *
+     * <strong>Note:</strong> This method uses fStringBuffer2, anything in it
+     * at the time of calling is lost.
+     */
+    public String scanPseudoAttribute(boolean scanningTextDecl, 
+                                      XMLString value) 
+                throws IOException, JasperException {
+
+        String name = scanName();
+        if (name == null) {
+            err.jspError("jsp.error.xml.pseudoAttrNameExpected");
+        }
+        skipSpaces();
+        if (!skipChar('=')) {
+            reportFatalError(scanningTextDecl ?
+			     "jsp.error.xml.eqRequiredInTextDecl"
+                             : "jsp.error.xml.eqRequiredInXMLDecl",
+			     name);
+        }
+        skipSpaces();
+        int quote = peekChar();
+        if (quote != '\'' && quote != '"') {
+            reportFatalError(scanningTextDecl ?
+			     "jsp.error.xml.quoteRequiredInTextDecl"
+                             : "jsp.error.xml.quoteRequiredInXMLDecl" ,
+			     name);
+        }
+        scanChar();
+        int c = scanLiteral(quote, value);
+        if (c != quote) {
+            fStringBuffer2.clear();
+            do {
+                fStringBuffer2.append(value);
+                if (c != -1) {
+                    if (c == '&' || c == '%' || c == '<' || c == ']') {
+                        fStringBuffer2.append((char)scanChar());
+                    }
+                    else if (XMLChar.isHighSurrogate(c)) {
+                        scanSurrogates(fStringBuffer2);
+                    }
+                    else if (XMLChar.isInvalid(c)) {
+                        String key = scanningTextDecl
+                            ? "jsp.error.xml.invalidCharInTextDecl"
+			    : "jsp.error.xml.invalidCharInXMLDecl";
+                        reportFatalError(key, Integer.toString(c, 16));
+                        scanChar();
+                    }
+                }
+                c = scanLiteral(quote, value);
+            } while (c != quote);
+            fStringBuffer2.append(value);
+            value.setValues(fStringBuffer2);
+        }
+        if (!skipChar(quote)) {
+            reportFatalError(scanningTextDecl ?
+			     "jsp.error.xml.closeQuoteMissingInTextDecl"
+                             : "jsp.error.xml.closeQuoteMissingInXMLDecl",
+			     name);
+        }
+
+        // return
+        return name;
+
+    }
+    
+    // Adapted from:
+    // org.apache.xerces.impl.XMLScanner.scanPIData
+    /**
+     * Scans a processing data. This is needed to handle the situation
+     * where a document starts with a processing instruction whose 
+     * target name <em>starts with</em> "xml". (e.g. xmlfoo)
+     *
+     * <strong>Note:</strong> This method uses fStringBuffer, anything in it
+     * at the time of calling is lost.
+     *
+     * @param target The PI target
+     * @param data The string to fill in with the data
+     */
+    private void scanPIData(String target, XMLString data) 
+        throws IOException, JasperException {
+
+        // check target
+        if (target.length() == 3) {
+            char c0 = Character.toLowerCase(target.charAt(0));
+            char c1 = Character.toLowerCase(target.charAt(1));
+            char c2 = Character.toLowerCase(target.charAt(2));
+            if (c0 == 'x' && c1 == 'm' && c2 == 'l') {
+                err.jspError("jsp.error.xml.reservedPITarget");
+            }
+        }
+
+        // spaces
+        if (!skipSpaces()) {
+            if (skipString("?>")) {
+                // we found the end, there is no data
+                data.clear();
+                return;
+            }
+            else {
+                // if there is data there should be some space
+                err.jspError("jsp.error.xml.spaceRequiredInPI");
+            }
+        }
+
+        fStringBuffer.clear();
+        // data
+        if (scanData("?>", fStringBuffer)) {
+            do {
+                int c = peekChar();
+                if (c != -1) {
+                    if (XMLChar.isHighSurrogate(c)) {
+                        scanSurrogates(fStringBuffer);
+                    } else if (XMLChar.isInvalid(c)) {
+                        err.jspError("jsp.error.xml.invalidCharInPI",
+				     Integer.toHexString(c));
+                        scanChar();
+                    }
+                }
+            } while (scanData("?>", fStringBuffer));
+        }
+        data.setValues(fStringBuffer);
+
+    }
+
+    // Adapted from:
+    // org.apache.xerces.impl.XMLScanner.scanSurrogates
+    /**
+     * Scans surrogates and append them to the specified buffer.
+     * <p>
+     * <strong>Note:</strong> This assumes the current char has already been
+     * identified as a high surrogate.
+     *
+     * @param buf The StringBuffer to append the read surrogates to.
+     * @returns True if it succeeded.
+     */
+    private boolean scanSurrogates(XMLStringBuffer buf)
+        throws IOException, JasperException {
+
+        int high = scanChar();
+        int low = peekChar();
+        if (!XMLChar.isLowSurrogate(low)) {
+            err.jspError("jsp.error.xml.invalidCharInContent",
+			 Integer.toString(high, 16));
+            return false;
+        }
+        scanChar();
+
+        // convert surrogates to supplemental character
+        int c = XMLChar.supplemental((char)high, (char)low);
+
+        // supplemental character must be a valid XML character
+        if (!XMLChar.isValid(c)) {
+            err.jspError("jsp.error.xml.invalidCharInContent",
+			 Integer.toString(c, 16)); 
+            return false;
+        }
+
+        // fill in the buffer
+        buf.append((char)high);
+        buf.append((char)low);
+
+        return true;
+
+    }
+
+    // Adapted from:
+    // org.apache.xerces.impl.XMLScanner.reportFatalError
+    /**
+     * Convenience function used in all XML scanners.
+     */
+    private void reportFatalError(String msgId, String arg)
+                throws JasperException {
+        err.jspError(msgId, arg);
+    }
+
+}
+
+

Added: branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/xmlparser/XMLString.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/xmlparser/XMLString.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/xmlparser/XMLString.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,196 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation and was
+ * originally based on software copyright (c) 1999, International
+ * Business Machines, Inc., http://www.apache.org.  For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ */
+
+package org.apache.jasper.xmlparser;
+
+/**
+ * This class is used as a structure to pass text contained in the underlying
+ * character buffer of the scanner. The offset and length fields allow the
+ * buffer to be re-used without creating new character arrays.
+ * <p>
+ * <strong>Note:</strong> Methods that are passed an XMLString structure
+ * should consider the contents read-only and not make any modifications
+ * to the contents of the buffer. The method receiving this structure
+ * should also not modify the offset and length if this structure (or
+ * the values of this structure) are passed to another method.
+ * <p>
+ * <strong>Note:</strong> Methods that are passed an XMLString structure
+ * are required to copy the information out of the buffer if it is to be
+ * saved for use beyond the scope of the method. The contents of the 
+ * structure are volatile and the contents of the character buffer cannot
+ * be assured once the method that is passed this structure returns.
+ * Therefore, methods passed this structure should not save any reference
+ * to the structure or the character array contained in the structure.
+ *
+ * @author Eric Ye, IBM
+ * @author Andy Clark, IBM
+ *
+ * @version $Id: XMLString.java 306086 2004-10-01 19:24:35Z luehe $
+ */
+public class XMLString {
+
+    //
+    // Data
+    //
+
+    /** The character array. */
+    public char[] ch;
+
+    /** The offset into the character array. */
+    public int offset;
+
+    /** The length of characters from the offset. */
+    public int length;
+
+    //
+    // Constructors
+    //
+
+    /** Default constructor. */
+    public XMLString() {
+    } // <init>()
+
+    /**
+     * Constructs an XMLString structure preset with the specified
+     * values.
+     * 
+     * @param ch     The character array.
+     * @param offset The offset into the character array.
+     * @param length The length of characters from the offset.
+     */
+    public XMLString(char[] ch, int offset, int length) {
+        setValues(ch, offset, length);
+    } // <init>(char[],int,int)
+
+    /**
+     * Constructs an XMLString structure with copies of the values in
+     * the given structure.
+     * <p>
+     * <strong>Note:</strong> This does not copy the character array;
+     * only the reference to the array is copied.
+     *
+     * @param string The XMLString to copy.
+     */
+    public XMLString(XMLString string) {
+        setValues(string);
+    } // <init>(XMLString)
+
+    //
+    // Public methods
+    //
+
+    /**
+     * Initializes the contents of the XMLString structure with the
+     * specified values.
+     * 
+     * @param ch     The character array.
+     * @param offset The offset into the character array.
+     * @param length The length of characters from the offset.
+     */
+    public void setValues(char[] ch, int offset, int length) {
+        this.ch = ch;
+        this.offset = offset;
+        this.length = length;
+    } // setValues(char[],int,int)
+
+    /**
+     * Initializes the contents of the XMLString structure with copies
+     * of the given string structure.
+     * <p>
+     * <strong>Note:</strong> This does not copy the character array;
+     * only the reference to the array is copied.
+     * 
+     * @param s
+     */
+    public void setValues(XMLString s) {
+        setValues(s.ch, s.offset, s.length);
+    } // setValues(XMLString)
+
+    /** Resets all of the values to their defaults. */
+    public void clear() {
+        this.ch = null;
+        this.offset = 0;
+        this.length = -1;
+    } // clear()
+
+    /**
+     * Returns true if the contents of this XMLString structure and
+     * the specified array are equal.
+     * 
+     * @param ch     The character array.
+     * @param offset The offset into the character array.
+     * @param length The length of characters from the offset.
+     */
+    public boolean equals(char[] ch, int offset, int length) {
+        if (ch == null) {
+            return false;
+        }
+        if (this.length != length) {
+            return false;
+        }
+
+        for (int i=0; i<length; i++) {
+            if (this.ch[this.offset+i] != ch[offset+i] ) {
+                return false;
+            }
+        }
+        return true;
+    } // equals(char[],int,int):boolean
+
+    /**
+     * Returns true if the contents of this XMLString structure and
+     * the specified string are equal.
+     * 
+     * @param s The string to compare.
+     */
+    public boolean equals(String s) {
+        if (s == null) {
+            return false;
+        }
+        if ( length != s.length() ) {
+            return false;
+        }
+
+        // is this faster than call s.toCharArray first and compare the 
+        // two arrays directly, which will possibly involve creating a
+        // new char array object.
+        for (int i=0; i<length; i++) {
+            if (ch[offset+i] != s.charAt(i)) {
+                return false;
+            }
+        }
+
+        return true;
+    } // equals(String):boolean
+
+    //
+    // Object methods
+    //
+
+    /** Returns a string representation of this object. */
+    public String toString() {
+        return length > 0 ? new String(ch, offset, length) : "";
+    } // toString():String
+
+} // class XMLString

Added: branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/xmlparser/XMLStringBuffer.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/xmlparser/XMLStringBuffer.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/jasper/src/share/org/apache/jasper/xmlparser/XMLStringBuffer.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,175 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation and was
+ * originally based on software copyright (c) 1999, International
+ * Business Machines, Inc., http://www.apache.org.  For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ */
+
+package org.apache.jasper.xmlparser;
+
+/**
+ * XMLString is a structure used to pass character arrays. However,
+ * XMLStringBuffer is a buffer in which characters can be appended
+ * and extends XMLString so that it can be passed to methods
+ * expecting an XMLString object. This is a safe operation because
+ * it is assumed that any callee will <strong>not</strong> modify
+ * the contents of the XMLString structure.
+ * <p> 
+ * The contents of the string are managed by the string buffer. As
+ * characters are appended, the string buffer will grow as needed.
+ * <p>
+ * <strong>Note:</strong> Never set the <code>ch</code>, 
+ * <code>offset</code>, and <code>length</code> fields directly.
+ * These fields are managed by the string buffer. In order to reset
+ * the buffer, call <code>clear()</code>.
+ * 
+ * @author Andy Clark, IBM
+ * @author Eric Ye, IBM
+ *
+ * @version $Id: XMLStringBuffer.java 306086 2004-10-01 19:24:35Z luehe $
+ */
+public class XMLStringBuffer
+    extends XMLString {
+
+    //
+    // Constants
+    //
+
+    /** Default buffer size (32). */
+    public static final int DEFAULT_SIZE = 32;
+
+    //
+    // Constructors
+    //
+
+    /**
+     * 
+     */
+    public XMLStringBuffer() {
+        this(DEFAULT_SIZE);
+    } // <init>()
+
+    /**
+     * 
+     * 
+     * @param size 
+     */
+    public XMLStringBuffer(int size) {
+        ch = new char[size];
+    } // <init>(int)
+
+    /** Constructs a string buffer from a char. */
+    public XMLStringBuffer(char c) {
+        this(1);
+        append(c);
+    } // <init>(char)
+
+    /** Constructs a string buffer from a String. */
+    public XMLStringBuffer(String s) {
+        this(s.length());
+        append(s);
+    } // <init>(String)
+
+    /** Constructs a string buffer from the specified character array. */
+    public XMLStringBuffer(char[] ch, int offset, int length) {
+        this(length);
+        append(ch, offset, length);
+    } // <init>(char[],int,int)
+
+    /** Constructs a string buffer from the specified XMLString. */
+    public XMLStringBuffer(XMLString s) {
+        this(s.length);
+        append(s);
+    } // <init>(XMLString)
+
+    //
+    // Public methods
+    //
+
+    /** Clears the string buffer. */
+    public void clear() {
+        offset = 0;
+        length = 0;
+    }
+
+    /**
+     * append
+     * 
+     * @param c 
+     */
+    public void append(char c) {
+        if (this.length + 1 > this.ch.length) {
+                    int newLength = this.ch.length*2;
+                    if (newLength < this.ch.length + DEFAULT_SIZE)
+                        newLength = this.ch.length + DEFAULT_SIZE;
+                    char[] newch = new char[newLength];
+                    System.arraycopy(this.ch, 0, newch, 0, this.length);
+                    this.ch = newch;
+        }
+        this.ch[this.length] = c;
+        this.length++;
+    } // append(char)
+
+    /**
+     * append
+     * 
+     * @param s 
+     */
+    public void append(String s) {
+        int length = s.length();
+        if (this.length + length > this.ch.length) {
+            int newLength = this.ch.length*2;
+            if (newLength < this.length + length + DEFAULT_SIZE)
+                newLength = this.ch.length + length + DEFAULT_SIZE;
+            char[] newch = new char[newLength];            
+            System.arraycopy(this.ch, 0, newch, 0, this.length);
+            this.ch = newch;
+        }
+        s.getChars(0, length, this.ch, this.length);
+        this.length += length;
+    } // append(String)
+
+    /**
+     * append
+     * 
+     * @param ch 
+     * @param offset 
+     * @param length 
+     */
+    public void append(char[] ch, int offset, int length) {
+        if (this.length + length > this.ch.length) {
+            char[] newch = new char[this.ch.length + length + DEFAULT_SIZE];
+            System.arraycopy(this.ch, 0, newch, 0, this.length);
+            this.ch = newch;
+        }
+        System.arraycopy(ch, offset, this.ch, this.length, length);
+        this.length += length;
+    } // append(char[],int,int)
+
+    /**
+     * append
+     * 
+     * @param s 
+     */
+    public void append(XMLString s) {
+        append(s.ch, s.offset, s.length);
+    } // append(XMLString)
+
+} // class XMLStringBuffer

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/BUILDING.txt
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/BUILDING.txt	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/BUILDING.txt	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,134 @@
+$Id: BUILDING.txt 266968 2002-08-13 16:20:53Z remm $
+
+
+               Building The Java Servlet and JSP API Classes
+               =============================================
+
+This subproject contains the source code for the implementation classes of the
+Java Servlet and JSP APIs (packages javax.servlet, javax.servlet.http,
+javax.servlet.jsp, and javax.servlet.jsp.tagext).  In order to build these
+sources successfully, you must do the following:
+
+
+(1) Download and Install the Ant Binary Distribution
+
+NOTE:  These instructions assume that you are using the Ant 1.3 release.
+Procedures for Ant 1.4 and later versions should be similar, but have not
+been tested.
+
+* Download a binary distribution of Ant 1.3 from:
+
+    http://jakarta.apache.org/builds/jakarta-ant/release/v1.3/bin/
+
+  On a Windows platform, you will need:
+    jakarta-ant-1.3-bin.zip
+    jakarta-ant-1.3-optional.jar
+
+  On a Unix platform, you will need:
+    jakarta-ant-1.3-bin.tar.gz
+    jakarta-ant-1.3-optional.jar
+
+* Unpack the binary distribution into a convenient location so that the
+  Ant release resides in its own directory (conventionally named
+  "jakarta-ant-1.3").  For the purposes of the remainder of this document,
+  the symbolic name "${ant.home}" is used to refer to the full pathname of
+  the release directory.
+
+* Copy the file "jakarta-ant-1.3-optional.jar", downloaded above, into
+  the directory "${ant.home}/lib".  This makes available several Ant
+  extension commands that are commonly required when building Jakarta
+  based projects.
+
+* Modify the PATH environment variable to include directory
+  "${ant.home}/bin" in its list.  This makes the "ant" command line script
+  available, which will be used to actually perform the build.
+
+
+(2) Download and Install the JAXP/1.1 Reference Implementation (OPTIONAL)
+
+NOTE:  Although this step is not required to build this particular subproject,
+it is commonly required to build other Jakarta projects.  Hence, the steps
+required are documented here.
+
+* Download a binary distribution of JAXP 1.1 (Final Version) from:
+
+    http://java.sun.com/xml/download.html
+
+* Unpack the binary distribution into a convenient location so that the
+  JAXP/1.1 release resides in its own directory (conventionally named
+  "jaxp-1.1".  For the purposes of the remainder of this document, the
+  symbolic name "${jaxp.home}" is used to refer to the full pathname of
+  the release directory.
+
+* Make the JAR files of this distribution ("crimson.jar", "jaxp.jar", and
+  "xalan.jar") available for use by performing ONE of the following options:
+
+  - Remove the existing "jaxp.jar" and "parser.jar" files found in the
+    "${ant.home}/lib" directory, and copy these JAR files into the
+    "${ant.home}/lib" directory (prefered option).
+
+  - Add these files to your CLASSPATH environment variable.
+
+
+(3) Download and Install Subproject Source Code
+
+* Use Anonymous CVS (as described on the Jakarta web site at
+  <http://jakarta.apache.org/site/cvsindex.html>, or
+  download a source distribution from:
+
+    http://jakarta.apache.org/builds/jakarta-servletapi-4/nightly/src/
+
+  On a Windows platform, you will need:
+    jakarta-servletapi-4-src-YYYYMMDD.zip
+
+  On a Unix platform, you will need:
+    jakarta-servletapi-4-src-YYYYMMDD.zip
+
+  (Alternatively, you can download the Servlet API source distribution
+  from the same directory as you find a released version of Tomcat 4.
+  Such distributions will contain exactly the Servlet API classes used
+  to build the "servlet.jar" file inside that Tomcat distribution.)
+
+* Unpack the source distribution into a convenient location so that the
+  distribution resides in its own directory (conventionally named
+  "jakarta-servletapi-4").  For the purposes of the remainder of this document,
+  the symbolic name "${servletapi.source}" is used to refer to the full
+  pathname of the release directory.
+
+
+(4) Customize Build Properties For This Subproject
+
+Most Jakarta subprojects allow you to customize Ant properties (with default
+values defined in the "build.xml" file.  This is done by creating a text file
+named "build.properties" in the source distribution directory (for property
+definitions local to this subproject) and/or your user home directory (for
+property definitions shared across subprojects).
+
+The "jakarta-servletapi-4" subproject does not define any customizable
+build properties.
+
+
+(5) Build A Binary Distribution
+
+Open a command line shell, and issue the following commands:
+
+  cd ${servletapi.source}
+  ant -projecthelp
+
+If everything is installed correctly, you should see a list of the Ant
+"targets" that represent different commands you might wish to build.  By
+convention, the "dist" target creates a complete binary distribution.  To
+execute it, type the following commands:
+
+  cd ${servletapi.source}
+  ant dist
+
+This will create a complete binary distribution of the subproject (equivalent
+in structure to the corresponding binary distribution downloadable from the
+Jakarta web site), in the "${servletapi.source}/dist" directory.  It will have
+the contents described in the corresponding "README.txt" file.
+
+The file most commonly required by other projects will be the "servlet.jar"
+file, found in "${servletapi.source}/lib/servlet.jar".  Make a note of the
+full pathname to this file, because you will need it when customizing build
+properties for other Jakarta subprojects that depend on these classes.

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/LICENSE
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/LICENSE	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/LICENSE	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,202 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed 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.

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/README.txt
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/README.txt	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/README.txt	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,28 @@
+$Id: README.txt 266968 2002-08-13 16:20:53Z remm $
+
+                      Java Servlet and JSP API Classes
+                      ================================
+
+This subproject contains the compiled code for the implementation classes of
+the Java Servlet and JSP APIs (packages javax.servlet, javax.servlet.http,
+javax.servlet.jsp, and javax.servlet.jsp.tagext).  It includes the following
+contents:
+
+
+  BUILDING.txt                Instructions for building from sources
+  LICENSE                     Apache Software License for this release
+  README.txt                  This document
+  docs/                       Documentation for this release
+      api/                    Javadocs for Servlet and JSP API classes
+  lib/                        Binary JAR files for this release
+      servlet.jar             Binary Servlet and JSP API classes
+  src/                        Sources for Servlet and JSP API classes
+
+In general, you will need to add the "servlet.jar" file (found in the "lib"
+subdirectory of this release) into the compilation class path for your
+projects that depend on these APIs.
+
+The compiled "servlet.jar" file included in this subproject is automatically
+included in binary distributions of Tomcat 4.0, so you need not download this
+subproject separately unless you wish to utilize the Javadocs, or peruse the
+source code to see how the API classes are implemented.

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/build.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/build.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/build.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,279 @@
+<project name="JSP API Classes" default="compile" basedir=".">
+
+
+  <!-- =================== Environmental Properties ======================= -->
+
+  <!-- Load user property definition overrides -->
+  <property file="build.properties"/>
+  <property file="${user.home}/build.properties"/>
+
+  <!-- Establish property definition defaults -->
+  <property name="compile.debug"       value="true"/>
+  <property name="compile.deprecation" value="false"/>
+  <property name="compile.optimize"    value="true"/>
+  <property name="implementation.revision" value="public_draft"/>
+  <property name="jsp-api.build"    value="build"/>
+  <property name="jsp-api.dist"     value="dist"/>
+  <property name="servlet-api.jar"  value="../jsr154/dist/lib/servlet-api.jar"/>
+  <property name="jsp-api.jar" value="${jsp-api.dist}/lib/jsp-api.jar"/>
+  <property name="jsp-anttask.jar" value="${jsp-api.build}/jsp-anttask.jar" />
+
+  <path id="examples.classpath">
+    <pathelement location="${jsp-api.build}/classes"/>
+    <pathelement location="${servlet-api.jar}"/>
+    <pathelement location="${mail.jar}"/>
+  </path>
+
+
+  <!-- ===================== Prepare Directories ========================= -->
+  <target name="prepare">
+
+    <!-- "Build" Hierarchy -->
+    <mkdir dir="${jsp-api.build}"/>
+    <mkdir dir="${jsp-api.build}/classes"/>
+    <mkdir dir="${jsp-api.build}/docs"/>
+    <mkdir dir="${jsp-api.build}/docs/api"/>
+    <mkdir dir="${jsp-api.build}/examples"/>
+    <mkdir dir="${jsp-api.build}/ant"/>
+
+    <!-- "Dist" Hierarchy -->
+    <mkdir dir="${jsp-api.dist}"/>
+    <mkdir dir="${jsp-api.dist}/docs"/>
+    <mkdir dir="${jsp-api.dist}/docs/api"/>
+    <mkdir dir="${jsp-api.dist}/lib"/>
+    <mkdir dir="${jsp-api.dist}/src"/>
+    <mkdir dir="${jsp-api.dist}/examples"/>
+
+    <uptodate property="docs.uptodate" targetfile="${jsp-api.build}/docs/api/index.html">
+      <srcfiles dir="src/share" includes="**/*.java" />
+    </uptodate>
+  </target>
+
+
+  <!-- ======================= Static Files ============================== -->
+  <target name="static" depends="prepare">
+
+    <!-- "Dist" Hierarchy -->
+    <copy todir="${jsp-api.dist}">
+      <fileset dir="." includes="BUILDING.txt"/>
+      <fileset dir="." includes="LICENSE"/>
+      <fileset dir="." includes="README.txt"/>
+    </copy>
+
+  </target>
+
+
+  <!-- ======================== Compile Classes ========================== -->
+  <target name="compile" depends="static"
+   description="Compile API classes (Default)">
+
+    <!-- Java classes -->
+    <javac srcdir="src/share" destdir="${jsp-api.build}/classes"
+           debug="${compile.debug}" deprecation="${compile.deprecation}"
+        optimize="${compile.optimize}"
+       classpath="${servlet-api.jar}" />
+
+    <!-- Associated property files -->
+    <copy todir="${jsp-api.build}/classes">
+        <fileset dir="src/share">
+          <include name="**/*.properties"/>
+        </fileset>
+    </copy>
+
+    <!-- JSP resources -->
+    <copy todir="${jsp-api.build}/classes/javax/servlet/jsp/resources">
+        <fileset dir="src/share/dtd">
+          <include name="jsp*.dtd"/>
+          <include name="jsp*.xsd"/>
+          <include name="web-jsp*.dtd"/>
+          <include name="web-jsp*.xsd"/>
+        </fileset>
+    </copy>
+
+  </target>
+
+
+  <!-- ======================== Build JavaDoc =========================== -->
+  <target name="javadoc" depends="prepare" unless="docs.uptodate">
+
+    <javadoc packagenames="javax.servlet.jsp.*"
+             sourcepath="${basedir}/src/share"
+             classpath="${servlet-api.jar}"
+             destdir="${jsp-api.build}/docs/api"
+             use="true"
+             windowtitle="JavaServer Pages API Documentation"
+             doctitle="JavaServer Pages API Documentation"
+             bottom="Copyright &amp;copy; 1999-2002 The Apache Software Foundation.  All Rights Reserved."/>
+
+  </target>
+
+
+  <!-- ======================== Build Examples =========================== -->
+  <target name="ant" depends="prepare">
+    <javac  srcdir="src/ant" destdir="${jsp-api.build}/ant"
+            debug="${compile.debug}" deprecation="${compile.deprecation}"
+            optimize="${compile.optimize}" 
+            classpath="${ant.home}/lib/ant.jar" />
+    <jar jarfile="${jsp-anttask.jar}"  basedir="${jsp-api.build}/ant"  />
+    <taskdef    name="txt2html" classname="task.Txt2Html"
+                classpath="${jsp-anttask.jar}" />
+  </target>
+  
+  <target name="examples" depends="prepare,ant">
+
+    <copy todir="${jsp-api.build}/examples">
+      <fileset dir="examples">
+        <exclude name="build.*"/>
+      </fileset>
+    </copy>
+
+    <txt2html todir="${jsp-api.build}/examples/jsp2/simpletag">
+      <fileset dir="examples/WEB-INF/classes/jsp2/examples">
+        <include name="BookBean.java"/>
+      </fileset>
+      <fileset dir="examples/WEB-INF/classes/jsp2/examples/simpletag">
+        <include name="FindBookSimpleTag.java"/>
+        <include name="RepeatSimpleTag.java"/>
+        <include name="HelloWorldSimpleTag.java"/>
+      </fileset>
+      <fileset dir="examples/WEB-INF/classes/jsp2/examples/el">
+        <include name="Functions.java"/>
+      </fileset>
+    </txt2html>
+
+    <txt2html todir="${jsp-api.build}/examples/jsp2/jspattribute">
+      <fileset dir="examples/WEB-INF/classes/jsp2/examples">
+        <include name="FooBean.java"/>
+      </fileset>
+      <fileset dir="examples/WEB-INF/classes/jsp2/examples/simpletag">
+        <include name="ShuffleSimpleTag.java"/>
+        <include name="TileSimpleTag.java"/>
+        <include name="HelloWorldSimpleTag.java"/>
+      </fileset>
+    </txt2html>
+
+    <txt2html todir="${jsp-api.build}/examples/cal">
+      <fileset dir="examples/WEB-INF/classes/cal">
+        <include name="Entries.java"/>
+        <include name="Entry.java"/>
+        <include name="JspCalendar.java"/>
+        <include name="TableBean.java"/>
+      </fileset>
+    </txt2html>
+
+    <txt2html todir="${jsp-api.build}/examples/jsptoserv">
+      <fileset dir="examples/WEB-INF/classes">
+        <include name="servletToJsp.java"/>
+      </fileset>
+    </txt2html>
+
+    <txt2html todir="${jsp-api.build}/examples/jsp2/el">
+      <fileset dir="examples/WEB-INF/classes/jsp2/examples/el">
+        <include name="Functions.java"/>
+      </fileset>
+    </txt2html>
+
+    <txt2html todir="${jsp-api.build}/examples/jsp2/misc">
+      <fileset dir="examples/WEB-INF/classes/jsp2/examples/simpletag">
+        <include name="EchoAttributesTag.java"/>
+      </fileset>
+    </txt2html>
+
+    <txt2html todir="${jsp-api.build}/examples/jsp2/tagfiles">
+      <fileset dir="examples/WEB-INF/tags">
+        <include name="**/*.tag" />
+      </fileset>
+    </txt2html>
+
+    <txt2html todir="${jsp-api.build}/examples">
+      <fileset dir="examples">
+        <include name="**/*.jsp" />
+        <include name="**/*.jspx" />
+        <include name="**/*.jspf" />
+        <exclude name="error/errorpge.jsp"/>
+        <exclude name="forward/one.jsp"/>
+        <exclude name="include/foo.jsp"/>
+        <exclude name="jsptoserv/hello.jsp"/>
+        <exclude name="security/protected/error.jsp"/>
+        <exclude name="security/protected/index.jsp"/>
+        <exclude name="security/protected/login.jsp"/>
+        <exclude name="source.jsp"/>
+      </fileset>
+    </txt2html>
+
+    <javac   srcdir="examples/WEB-INF/classes" 
+             destdir="${jsp-api.build}/examples/WEB-INF/classes"
+             debug="${compile.debug}" deprecation="${compile.deprecation}"
+             optimize="${compile.optimize}"
+             excludes="**/CVS/**">
+      <classpath refid="examples.classpath" />
+    </javac>
+
+    <javac   srcdir="examples/plugin/applet" 
+             destdir="${jsp-api.build}/examples/plugin/applet"
+             debug="${compile.debug}" deprecation="${compile.deprecation}"
+             optimize="${compile.optimize}"
+             excludes="**/CVS/**">
+      <classpath refid="examples.classpath" />
+    </javac>
+
+    <jar   jarfile="${jsp-api.dist}/examples/examples.war"
+           basedir="${jsp-api.build}/examples" includes="**"/>
+
+  </target>
+
+
+  <!-- ===================== Distribution Files ========================= -->
+  <target name="jar" depends="compile"
+          description="Create jar">
+
+    <!-- Prepare Manifest -->
+    <copy tofile="${jsp-api.build}/manifest"
+            file="src/etc/manifest" overwrite="yes">
+      <filterset>
+        <filter token="implementation.revision"
+                value="${implementation.revision}"/>
+      </filterset>
+    </copy>
+
+    <!-- Create JAR file -->
+    <jar jarfile="${jsp-api.jar}"
+         basedir="${jsp-api.build}/classes"
+         manifest="${jsp-api.build}/manifest">
+      <include name="javax/servlet/jsp/**" />
+    </jar>
+
+  </target>
+
+  <target name="dist" depends="compile,examples,javadoc,jar"
+   description="Create binary distribution">
+
+    <!-- Copy Javadocs -->
+    <copy todir="${jsp-api.dist}/docs/api">
+        <fileset dir="${jsp-api.build}/docs/api"/>
+    </copy>
+
+    <!-- Copy API source files -->
+    <copy todir="${jsp-api.dist}/src">
+        <fileset dir="src/share"/>
+    </copy>
+
+  </target>
+
+
+  <!-- ====================== Clean Generated Files ===================== -->
+  <target name="clean"
+   description="Clean previous build results">
+
+    <delete dir="${jsp-api.build}"/>
+    <delete dir="${jsp-api.dist}"/>
+
+  </target>
+
+
+  <!-- ========================= All In One Build ======================= -->
+  <target name="all" depends="clean,dist"
+   description="Clean, compile, and dist"/>
+
+
+</project>

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/cal/Entries.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/cal/Entries.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/cal/Entries.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,72 @@
+/*
+* Copyright 2004 The Apache Software Foundation
+*
+* Licensed 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 cal;
+
+import java.util.Enumeration;
+import java.util.Hashtable;
+import javax.servlet.http.*;
+
+public class Entries {
+
+  private Hashtable entries;
+  private static final String[] time = {"8am", "9am", "10am", "11am", "12pm", 
+					"1pm", "2pm", "3pm", "4pm", "5pm", "6pm",
+					"7pm", "8pm" };
+  public static final int rows = 12;
+
+  public Entries () {   
+   entries = new Hashtable (rows);
+   for (int i=0; i < rows; i++) {
+     entries.put (time[i], new Entry(time[i]));
+   }
+  }
+
+  public int getRows () {
+    return rows;
+  }
+
+  public Entry getEntry (int index) {
+    return (Entry)this.entries.get(time[index]);
+  }
+
+  public int getIndex (String tm) {
+    for (int i=0; i<rows; i++)
+      if(tm.equals(time[i])) return i;
+    return -1;
+  }
+
+  public void processRequest (HttpServletRequest request, String tm) {
+    int index = getIndex (tm);
+    if (index >= 0) {
+      String descr = request.getParameter ("description");
+      ((Entry)entries.get(time[index])).setDescription (descr);
+    }
+  }
+
+}
+
+
+
+
+
+
+
+
+
+
+
+
+

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/cal/Entry.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/cal/Entry.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/cal/Entry.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,54 @@
+/*
+* Copyright 2004 The Apache Software Foundation
+*
+* Licensed 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 cal;
+
+public class Entry {
+
+  String hour;
+  String description;
+  String color;
+
+  public Entry (String hour) {
+    this.hour = hour;
+    this.description = "";
+
+  }
+
+  public String getHour () {
+    return this.hour;
+  }
+
+  public String getColor () {
+    if (description.equals("")) return "lightblue";
+    else return "red";
+  }
+
+  public String getDescription () {
+    if (description.equals("")) return "None";
+    else return this.description;
+  }
+
+  public void setDescription (String descr) {
+    description = descr;
+  }
+ 
+}
+
+
+
+
+

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/cal/JspCalendar.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/cal/JspCalendar.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/cal/JspCalendar.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,154 @@
+/*
+* Copyright 2004 The Apache Software Foundation
+*
+* Licensed 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 cal;
+
+import java.text.DateFormat;
+import java.util.*;
+
+public class JspCalendar {
+    Calendar  calendar = null;
+    Date currentDate;
+
+    public JspCalendar() {
+	calendar = Calendar.getInstance();
+	Date trialTime = new Date();
+	calendar.setTime(trialTime);
+    }
+
+
+    public int getYear() {
+	return calendar.get(Calendar.YEAR);
+    }
+    
+    public String getMonth() {
+	int m = getMonthInt();
+	String[] months = new String [] { "January", "February", "March",
+					"April", "May", "June",
+					"July", "August", "September",
+					"October", "November", "December" };
+	if (m > 12)
+	    return "Unknown to Man";
+	
+	return months[m - 1];
+
+    }
+
+    public String getDay() {
+	int x = getDayOfWeek();
+	String[] days = new String[] {"Sunday", "Monday", "Tuesday", "Wednesday", 
+				      "Thursday", "Friday", "Saturday"};
+
+	if (x > 7)
+	    return "Unknown to Man";
+
+	return days[x - 1];
+
+    }
+    
+    public int getMonthInt() {
+	return 1 + calendar.get(Calendar.MONTH);
+    }
+
+    public String getDate() {
+	return getMonthInt() + "/" + getDayOfMonth() + "/" +  getYear();	
+    }
+
+    public String getCurrentDate() {
+        Date dt = new Date ();
+	calendar.setTime (dt);
+	return getMonthInt() + "/" + getDayOfMonth() + "/" +  getYear();
+
+    }
+
+    public String getNextDate() {
+        calendar.set (Calendar.DAY_OF_MONTH, getDayOfMonth() + 1);
+	return getDate ();
+    }
+
+    public String getPrevDate() {
+        calendar.set (Calendar.DAY_OF_MONTH, getDayOfMonth() - 1);
+	return getDate ();
+    }
+
+    public String getTime() {
+	return getHour() + ":" + getMinute() + ":" + getSecond();
+    }
+
+    public int getDayOfMonth() {
+	return calendar.get(Calendar.DAY_OF_MONTH);
+    }
+
+    public int getDayOfYear() {
+	return calendar.get(Calendar.DAY_OF_YEAR);
+    }
+
+    public int getWeekOfYear() {
+	return calendar.get(Calendar.WEEK_OF_YEAR);
+    }
+
+    public int getWeekOfMonth() {
+	return calendar.get(Calendar.WEEK_OF_MONTH);
+    }
+
+    public int getDayOfWeek() {
+	return calendar.get(Calendar.DAY_OF_WEEK);
+    }
+     
+    public int getHour() {
+	return calendar.get(Calendar.HOUR_OF_DAY);
+    }
+    
+    public int getMinute() {
+	return calendar.get(Calendar.MINUTE);
+    }
+
+
+    public int getSecond() {
+	return calendar.get(Calendar.SECOND);
+    }
+
+  
+    public int getEra() {
+	return calendar.get(Calendar.ERA);
+    }
+
+    public String getUSTimeZone() {
+	String[] zones = new String[] {"Hawaii", "Alaskan", "Pacific",
+				       "Mountain", "Central", "Eastern"};
+	
+	return zones[10 + getZoneOffset()];
+    }
+
+    public int getZoneOffset() {
+	return calendar.get(Calendar.ZONE_OFFSET)/(60*60*1000);
+    }
+
+
+    public int getDSTOffset() {
+	return calendar.get(Calendar.DST_OFFSET)/(60*60*1000);
+    }
+
+    
+    public int getAMPM() {
+	return calendar.get(Calendar.AM_PM);
+    }
+}
+
+
+
+
+

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/cal/TableBean.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/cal/TableBean.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/cal/TableBean.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,101 @@
+/*
+* Copyright 2004 The Apache Software Foundation
+*
+* Licensed 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 cal;
+
+import java.beans.*;
+import javax.servlet.http.*;
+import javax.servlet.*;
+import java.util.Hashtable;
+
+public class TableBean {
+
+  Hashtable table;
+  JspCalendar JspCal;
+  Entries entries;
+  String date;
+  String name = null;
+  String email = null;
+  boolean processError = false;
+
+  public TableBean () {
+    this.table = new Hashtable (10);
+    this.JspCal = new JspCalendar ();
+    this.date = JspCal.getCurrentDate ();
+  }
+
+  public void setName (String nm) {
+    this.name = nm;
+  }
+
+  public String getName () {
+    return this.name;
+  }
+  
+  public void setEmail (String mail) {
+    this.email = mail;
+  }
+
+  public String getEmail () {
+    return this.email;
+  }
+
+  public String getDate () {
+    return this.date;
+  }
+
+  public Entries getEntries () {
+    return this.entries;
+  }
+
+  public void processRequest (HttpServletRequest request) {
+
+    // Get the name and e-mail.
+    this.processError = false;
+    if (name == null || name.equals("")) setName(request.getParameter ("name"));  
+    if (email == null || email.equals("")) setEmail(request.getParameter ("email"));
+    if (name == null || email == null ||
+		name.equals("") || email.equals("")) {
+      this.processError = true;
+      return;
+    }
+
+    // Get the date.
+    String dateR = request.getParameter ("date");
+    if (dateR == null) date = JspCal.getCurrentDate ();
+    else if (dateR.equalsIgnoreCase("next")) date = JspCal.getNextDate ();
+    else if (dateR.equalsIgnoreCase("prev")) date = JspCal.getPrevDate ();
+
+    entries = (Entries) table.get (date);
+    if (entries == null) {
+      entries = new Entries ();
+      table.put (date, entries);
+    }
+
+    // If time is provided add the event.
+	String time = request.getParameter("time");
+    if (time != null) entries.processRequest (request, time);
+  }
+
+  public boolean getProcessError () {
+    return this.processError;
+  }
+}
+
+
+
+
+
+

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/checkbox/CheckTest.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/checkbox/CheckTest.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/checkbox/CheckTest.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,30 @@
+/*
+* Copyright 2004 The Apache Software Foundation
+*
+* Licensed 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 checkbox;
+
+public class CheckTest {
+
+    String b[] = new String[] { "1", "2", "3", "4" };
+
+    public String[] getFruit() {
+	return b;
+    }
+
+    public void setFruit(String [] b) {
+	this.b = b;
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/colors/ColorGameBean.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/colors/ColorGameBean.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/colors/ColorGameBean.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,114 @@
+/*
+* Copyright 2004 The Apache Software Foundation
+*
+* Licensed 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 colors;
+
+import javax.servlet.http.*;
+
+public class ColorGameBean {
+
+    private String background = "yellow";
+    private String foreground = "red";
+    private String color1 = foreground;
+    private String color2 = background;
+    private String hint = "no";
+    private int attempts = 0;
+	private int intval = 0;
+    private boolean tookHints = false;
+
+    public void processRequest(HttpServletRequest request) {
+
+	// background = "yellow";
+	// foreground = "red";
+
+	if (! color1.equals(foreground)) {
+	    if (color1.equalsIgnoreCase("black") ||
+			color1.equalsIgnoreCase("cyan")) {
+			background = color1;
+		}
+	}
+
+	if (! color2.equals(background)) {
+	    if (color2.equalsIgnoreCase("black") ||
+			color2.equalsIgnoreCase("cyan")) {
+			foreground = color2;
+	    }
+	}
+
+	attempts++;
+    }
+
+    public void setColor2(String x) {
+	color2 = x;
+    }
+
+    public void setColor1(String x) {
+	color1 = x;
+    }
+
+    public void setAction(String x) {
+	if (!tookHints)
+	    tookHints = x.equalsIgnoreCase("Hint");
+	hint = x;
+    }
+
+    public String getColor2() {
+	 return background;
+    }
+
+    public String getColor1() {
+	 return foreground;
+    }
+
+    public int getAttempts() {
+	return attempts;
+    }
+
+    public boolean getHint() {
+	return hint.equalsIgnoreCase("Hint");
+    }
+
+    public boolean getSuccess() {
+	if (background.equalsIgnoreCase("black") ||
+	    background.equalsIgnoreCase("cyan")) {
+	
+	    if (foreground.equalsIgnoreCase("black") ||
+		foreground.equalsIgnoreCase("cyan"))
+		return true;
+	    else
+		return false;
+	}
+
+	return false;
+    }
+
+    public boolean getHintTaken() {
+	return tookHints;
+    }
+
+    public void reset() {
+	foreground = "red";
+	background = "yellow";
+    }
+
+    public void setIntval(int value) {
+	intval = value;
+	}
+
+    public int getIntval() {
+	return intval;
+	}
+}
+

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/compressionFilters/CompressionFilter.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/compressionFilters/CompressionFilter.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/compressionFilters/CompressionFilter.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,219 @@
+/*
+* Copyright 2004 The Apache Software Foundation
+*
+* Licensed 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 compressionFilters;
+
+import java.io.IOException;
+import java.util.Enumeration;
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+
+/**
+ * Implementation of <code>javax.servlet.Filter</code> used to compress
+ * the ServletResponse if it is bigger than a threshold.
+ *
+ * @author Amy Roh
+ * @author Dmitri Valdin
+ * @version $Revision: 267129 $, $Date: 2004-03-18 10:40:35 -0600 (Thu, 18 Mar 2004) $
+ */
+
+public class CompressionFilter implements Filter{
+
+    /**
+     * The filter configuration object we are associated with.  If this value
+     * is null, this filter instance is not currently configured.
+     */
+    private FilterConfig config = null;
+
+    /**
+     * Minimal reasonable threshold
+     */
+    private int minThreshold = 128;
+
+
+    /**
+     * The threshold number to compress
+     */
+    protected int compressionThreshold;
+
+    /**
+     * Debug level for this filter
+     */
+    private int debug = 0;
+
+    /**
+     * Place this filter into service.
+     *
+     * @param filterConfig The filter configuration object
+     */
+
+    public void init(FilterConfig filterConfig) {
+
+        config = filterConfig;
+        if (filterConfig != null) {
+            String value = filterConfig.getInitParameter("debug");
+            if (value!=null) {
+                debug = Integer.parseInt(value);
+            } else {
+                debug = 0;
+            }
+            String str = filterConfig.getInitParameter("compressionThreshold");
+            if (str!=null) {
+                compressionThreshold = Integer.parseInt(str);
+                if (compressionThreshold != 0 && compressionThreshold < minThreshold) {
+                    if (debug > 0) {
+                        System.out.println("compressionThreshold should be either 0 - no compression or >= " + minThreshold);
+                        System.out.println("compressionThreshold set to " + minThreshold);
+                    }
+                    compressionThreshold = minThreshold;
+                }
+            } else {
+                compressionThreshold = 0;
+            }
+
+        } else {
+            compressionThreshold = 0;
+        }
+
+    }
+
+    /**
+    * Take this filter out of service.
+    */
+    public void destroy() {
+
+        this.config = null;
+
+    }
+
+    /**
+     * The <code>doFilter</code> method of the Filter is called by the container
+     * each time a request/response pair is passed through the chain due
+     * to a client request for a resource at the end of the chain.
+     * The FilterChain passed into this method allows the Filter to pass on the
+     * request and response to the next entity in the chain.<p>
+     * This method first examines the request to check whether the client support
+     * compression. <br>
+     * It simply just pass the request and response if there is no support for
+     * compression.<br>
+     * If the compression support is available, it creates a
+     * CompressionServletResponseWrapper object which compresses the content and
+     * modifies the header if the content length is big enough.
+     * It then invokes the next entity in the chain using the FilterChain object
+     * (<code>chain.doFilter()</code>), <br>
+     **/
+
+    public void doFilter ( ServletRequest request, ServletResponse response,
+                        FilterChain chain ) throws IOException, ServletException {
+
+        if (debug > 0) {
+            System.out.println("@doFilter");
+        }
+
+        if (compressionThreshold == 0) {
+            if (debug > 0) {
+                System.out.println("doFilter gets called, but compressionTreshold is set to 0 - no compression");
+            }
+            chain.doFilter(request, response);
+            return;
+        }
+
+        boolean supportCompression = false;
+        if (request instanceof HttpServletRequest) {
+            if (debug > 1) {
+                System.out.println("requestURI = " + ((HttpServletRequest)request).getRequestURI());
+            }
+
+            // Are we allowed to compress ?
+            String s = (String) ((HttpServletRequest)request).getParameter("gzip");
+            if ("false".equals(s)) {
+                if (debug > 0) {
+                    System.out.println("got parameter gzip=false --> don't compress, just chain filter");
+                }
+                chain.doFilter(request, response);
+                return;
+            }
+
+            Enumeration e =
+                ((HttpServletRequest)request).getHeaders("Accept-Encoding");
+            while (e.hasMoreElements()) {
+                String name = (String)e.nextElement();
+                if (name.indexOf("gzip") != -1) {
+                    if (debug > 0) {
+                        System.out.println("supports compression");
+                    }
+                    supportCompression = true;
+                } else {
+                    if (debug > 0) {
+                        System.out.println("no support for compresion");
+                    }
+                }
+            }
+        }
+
+        if (!supportCompression) {
+            if (debug > 0) {
+                System.out.println("doFilter gets called wo compression");
+            }
+            chain.doFilter(request, response);
+            return;
+        } else {
+            if (response instanceof HttpServletResponse) {
+                CompressionServletResponseWrapper wrappedResponse =
+                    new CompressionServletResponseWrapper((HttpServletResponse)response);
+                wrappedResponse.setDebugLevel(debug);
+                wrappedResponse.setCompressionThreshold(compressionThreshold);
+                if (debug > 0) {
+                    System.out.println("doFilter gets called with compression");
+                }
+                try {
+                    chain.doFilter(request, wrappedResponse);
+                } finally {
+                    wrappedResponse.finishResponse();
+                }
+                return;
+            }
+        }
+    }
+
+    /**
+     * Set filter config
+     * This function is equivalent to init. Required by Weblogic 6.1
+     *
+     * @param filterConfig The filter configuration object
+     */
+    public void setFilterConfig(FilterConfig filterConfig) {
+        init(filterConfig);
+    }
+
+    /**
+     * Return filter config
+     * Required by Weblogic 6.1
+     */
+    public FilterConfig getFilterConfig() {
+        return config;
+    }
+
+}
+

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/compressionFilters/CompressionFilterTestServlet.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/compressionFilters/CompressionFilterTestServlet.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/compressionFilters/CompressionFilterTestServlet.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,57 @@
+/*
+* Copyright 2004 The Apache Software Foundation
+*
+* Licensed 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 compressionFilters;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.Enumeration;
+import javax.servlet.*;
+import javax.servlet.http.*;
+
+/**
+ * Very Simple test servlet to test compression filter
+ * @author Amy Roh
+ * @version $Revision: 267129 $, $Date: 2004-03-18 10:40:35 -0600 (Thu, 18 Mar 2004) $
+ */
+
+public class CompressionFilterTestServlet extends HttpServlet {
+
+    public void doGet(HttpServletRequest request, HttpServletResponse response)
+        throws ServletException, IOException {
+
+        ServletOutputStream out = response.getOutputStream();
+        response.setContentType("text/plain");
+
+        Enumeration e = ((HttpServletRequest)request).getHeaders("Accept-Encoding");
+        while (e.hasMoreElements()) {
+            String name = (String)e.nextElement();
+            out.println(name);
+            if (name.indexOf("gzip") != -1) {
+                out.println("gzip supported -- able to compress");
+            }
+            else {
+                out.println("gzip not supported");
+            }
+        }
+
+
+        out.println("Compression Filter Test Servlet");
+        out.close();
+    }
+
+}
+

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/compressionFilters/CompressionResponseStream.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/compressionFilters/CompressionResponseStream.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/compressionFilters/CompressionResponseStream.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,318 @@
+/*
+* Copyright 2004 The Apache Software Foundation
+*
+* Licensed 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 compressionFilters;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.zip.GZIPOutputStream;
+import javax.servlet.ServletOutputStream;
+import javax.servlet.http.HttpServletResponse;
+
+
+/**
+ * Implementation of <b>ServletOutputStream</b> that works with
+ * the CompressionServletResponseWrapper implementation.
+ *
+ * @author Amy Roh
+ * @author Dmitri Valdin
+ * @version $Revision: 267129 $, $Date: 2004-03-18 10:40:35 -0600 (Thu, 18 Mar 2004) $
+ */
+
+public class CompressionResponseStream
+    extends ServletOutputStream {
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Construct a servlet output stream associated with the specified Response.
+     *
+     * @param response The associated response
+     */
+    public CompressionResponseStream(HttpServletResponse response) throws IOException{
+
+        super();
+        closed = false;
+        this.response = response;
+        this.output = response.getOutputStream();
+
+    }
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The threshold number which decides to compress or not.
+     * Users can configure in web.xml to set it to fit their needs.
+     */
+    protected int compressionThreshold = 0;
+
+    /**
+     * Debug level
+     */
+    private int debug = 0;
+
+    /**
+     * The buffer through which all of our output bytes are passed.
+     */
+    protected byte[] buffer = null;
+
+    /**
+     * The number of data bytes currently in the buffer.
+     */
+    protected int bufferCount = 0;
+
+    /**
+     * The underlying gzip output stream to which we should write data.
+     */
+    protected GZIPOutputStream gzipstream = null;
+
+    /**
+     * Has this stream been closed?
+     */
+    protected boolean closed = false;
+
+    /**
+     * The content length past which we will not write, or -1 if there is
+     * no defined content length.
+     */
+    protected int length = -1;
+
+    /**
+     * The response with which this servlet output stream is associated.
+     */
+    protected HttpServletResponse response = null;
+
+    /**
+     * The underlying servket output stream to which we should write data.
+     */
+    protected ServletOutputStream output = null;
+
+
+    // --------------------------------------------------------- Public Methods
+
+    /**
+     * Set debug level
+     */
+    public void setDebugLevel(int debug) {
+        this.debug = debug;
+    }
+
+
+    /**
+     * Set the compressionThreshold number and create buffer for this size
+     */
+    protected void setBuffer(int threshold) {
+        compressionThreshold = threshold;
+        buffer = new byte[compressionThreshold];
+        if (debug > 1) {
+            System.out.println("buffer is set to "+compressionThreshold);
+        }
+    }
+
+    /**
+     * Close this output stream, causing any buffered data to be flushed and
+     * any further output data to throw an IOException.
+     */
+    public void close() throws IOException {
+
+        if (debug > 1) {
+            System.out.println("close() @ CompressionResponseStream");
+        }
+        if (closed)
+            throw new IOException("This output stream has already been closed");
+
+        if (gzipstream != null) {
+            flushToGZip();
+            gzipstream.close();
+            gzipstream = null;
+        } else {
+            if (bufferCount > 0) {
+                if (debug > 2) {
+                    System.out.print("output.write(");
+                    System.out.write(buffer, 0, bufferCount);
+                    System.out.println(")");
+                }
+                output.write(buffer, 0, bufferCount);
+                bufferCount = 0;
+            }
+        }
+
+        output.close();
+        closed = true;
+
+    }
+
+
+    /**
+     * Flush any buffered data for this output stream, which also causes the
+     * response to be committed.
+     */
+    public void flush() throws IOException {
+
+        if (debug > 1) {
+            System.out.println("flush() @ CompressionResponseStream");
+        }
+        if (closed) {
+            throw new IOException("Cannot flush a closed output stream");
+        }
+
+        if (gzipstream != null) {
+            gzipstream.flush();
+        }
+
+    }
+
+    public void flushToGZip() throws IOException {
+
+        if (debug > 1) {
+            System.out.println("flushToGZip() @ CompressionResponseStream");
+        }
+        if (bufferCount > 0) {
+            if (debug > 1) {
+                System.out.println("flushing out to GZipStream, bufferCount = " + bufferCount);
+            }
+            writeToGZip(buffer, 0, bufferCount);
+            bufferCount = 0;
+        }
+
+    }
+
+    /**
+     * Write the specified byte to our output stream.
+     *
+     * @param b The byte to be written
+     *
+     * @exception IOException if an input/output error occurs
+     */
+    public void write(int b) throws IOException {
+
+        if (debug > 1) {
+            System.out.println("write "+b+" in CompressionResponseStream ");
+        }
+        if (closed)
+            throw new IOException("Cannot write to a closed output stream");
+
+        if (bufferCount >= buffer.length) {
+            flushToGZip();
+        }
+
+        buffer[bufferCount++] = (byte) b;
+
+    }
+
+
+    /**
+     * Write <code>b.length</code> bytes from the specified byte array
+     * to our output stream.
+     *
+     * @param b The byte array to be written
+     *
+     * @exception IOException if an input/output error occurs
+     */
+    public void write(byte b[]) throws IOException {
+
+        write(b, 0, b.length);
+
+    }
+
+
+    /**
+     * Write <code>len</code> bytes from the specified byte array, starting
+     * at the specified offset, to our output stream.
+     *
+     * @param b The byte array containing the bytes to be written
+     * @param off Zero-relative starting offset of the bytes to be written
+     * @param len The number of bytes to be written
+     *
+     * @exception IOException if an input/output error occurs
+     */
+    public void write(byte b[], int off, int len) throws IOException {
+
+        if (debug > 1) {
+            System.out.println("write, bufferCount = " + bufferCount + " len = " + len + " off = " + off);
+        }
+        if (debug > 2) {
+            System.out.print("write(");
+            System.out.write(b, off, len);
+            System.out.println(")");
+        }
+
+        if (closed)
+            throw new IOException("Cannot write to a closed output stream");
+
+        if (len == 0)
+            return;
+
+        // Can we write into buffer ?
+        if (len <= (buffer.length - bufferCount)) {
+            System.arraycopy(b, off, buffer, bufferCount, len);
+            bufferCount += len;
+            return;
+        }
+
+        // There is not enough space in buffer. Flush it ...
+        flushToGZip();
+
+        // ... and try again. Note, that bufferCount = 0 here !
+        if (len <= (buffer.length - bufferCount)) {
+            System.arraycopy(b, off, buffer, bufferCount, len);
+            bufferCount += len;
+            return;
+        }
+
+        // write direct to gzip
+        writeToGZip(b, off, len);
+    }
+
+    public void writeToGZip(byte b[], int off, int len) throws IOException {
+
+        if (debug > 1) {
+            System.out.println("writeToGZip, len = " + len);
+        }
+        if (debug > 2) {
+            System.out.print("writeToGZip(");
+            System.out.write(b, off, len);
+            System.out.println(")");
+        }
+        if (gzipstream == null) {
+            if (debug > 1) {
+                System.out.println("new GZIPOutputStream");
+            }
+            response.addHeader("Content-Encoding", "gzip");
+            gzipstream = new GZIPOutputStream(output);
+        }
+        gzipstream.write(b, off, len);
+
+    }
+
+
+    // -------------------------------------------------------- Package Methods
+
+
+    /**
+     * Has this response stream been closed?
+     */
+    public boolean closed() {
+
+        return (this.closed);
+
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/compressionFilters/CompressionServletResponseWrapper.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/compressionFilters/CompressionServletResponseWrapper.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/compressionFilters/CompressionServletResponseWrapper.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,277 @@
+/*
+* Copyright 2004 The Apache Software Foundation
+*
+* Licensed 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 compressionFilters;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+import java.util.Locale;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.ServletException;
+import javax.servlet.ServletOutputStream;
+import javax.servlet.ServletResponse;
+import javax.servlet.ServletResponseWrapper;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpServletResponseWrapper;
+
+/**
+ * Implementation of <b>HttpServletResponseWrapper</b> that works with
+ * the CompressionServletResponseStream implementation..
+ *
+ * @author Amy Roh
+ * @author Dmitri Valdin
+ * @version $Revision: 267129 $, $Date: 2004-03-18 10:40:35 -0600 (Thu, 18 Mar 2004) $
+ */
+
+public class CompressionServletResponseWrapper extends HttpServletResponseWrapper {
+
+    // ----------------------------------------------------- Constructor
+
+    /**
+     * Calls the parent constructor which creates a ServletResponse adaptor
+     * wrapping the given response object.
+     */
+
+    public CompressionServletResponseWrapper(HttpServletResponse response) {
+        super(response);
+        origResponse = response;
+        if (debug > 1) {
+            System.out.println("CompressionServletResponseWrapper constructor gets called");
+        }
+    }
+
+
+    // ----------------------------------------------------- Instance Variables
+
+    /**
+     * Original response
+     */
+
+    protected HttpServletResponse origResponse = null;
+
+    /**
+     * Descriptive information about this Response implementation.
+     */
+
+    protected static final String info = "CompressionServletResponseWrapper";
+
+    /**
+     * The ServletOutputStream that has been returned by
+     * <code>getOutputStream()</code>, if any.
+     */
+
+    protected ServletOutputStream stream = null;
+
+
+    /**
+     * The PrintWriter that has been returned by
+     * <code>getWriter()</code>, if any.
+     */
+
+    protected PrintWriter writer = null;
+
+    /**
+     * The threshold number to compress
+     */
+    protected int threshold = 0;
+
+    /**
+     * Debug level
+     */
+    private int debug = 0;
+
+    /**
+     * Content type
+     */
+    protected String contentType = null;
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Set content type
+     */
+    public void setContentType(String contentType) {
+        if (debug > 1) {
+            System.out.println("setContentType to "+contentType);
+        }
+        this.contentType = contentType;
+        origResponse.setContentType(contentType);
+    }
+
+
+    /**
+     * Set threshold number
+     */
+    public void setCompressionThreshold(int threshold) {
+        if (debug > 1) {
+            System.out.println("setCompressionThreshold to " + threshold);
+        }
+        this.threshold = threshold;
+    }
+
+
+    /**
+     * Set debug level
+     */
+    public void setDebugLevel(int debug) {
+        this.debug = debug;
+    }
+
+
+    /**
+     * Create and return a ServletOutputStream to write the content
+     * associated with this Response.
+     *
+     * @exception IOException if an input/output error occurs
+     */
+    public ServletOutputStream createOutputStream() throws IOException {
+        if (debug > 1) {
+            System.out.println("createOutputStream gets called");
+        }
+
+        CompressionResponseStream stream = new CompressionResponseStream(origResponse);
+        stream.setDebugLevel(debug);
+        stream.setBuffer(threshold);
+
+        return stream;
+
+    }
+
+
+    /**
+     * Finish a response.
+     */
+    public void finishResponse() {
+        try {
+            if (writer != null) {
+                writer.close();
+            } else {
+                if (stream != null)
+                    stream.close();
+            }
+        } catch (IOException e) {
+        }
+    }
+
+
+    // ------------------------------------------------ ServletResponse Methods
+
+
+    /**
+     * Flush the buffer and commit this response.
+     *
+     * @exception IOException if an input/output error occurs
+     */
+    public void flushBuffer() throws IOException {
+        if (debug > 1) {
+            System.out.println("flush buffer @ CompressionServletResponseWrapper");
+        }
+        ((CompressionResponseStream)stream).flush();
+
+    }
+
+    /**
+     * Return the servlet output stream associated with this Response.
+     *
+     * @exception IllegalStateException if <code>getWriter</code> has
+     *  already been called for this response
+     * @exception IOException if an input/output error occurs
+     */
+    public ServletOutputStream getOutputStream() throws IOException {
+
+        if (writer != null)
+            throw new IllegalStateException("getWriter() has already been called for this response");
+
+        if (stream == null)
+            stream = createOutputStream();
+        if (debug > 1) {
+            System.out.println("stream is set to "+stream+" in getOutputStream");
+        }
+
+        return (stream);
+
+    }
+
+    /**
+     * Return the writer associated with this Response.
+     *
+     * @exception IllegalStateException if <code>getOutputStream</code> has
+     *  already been called for this response
+     * @exception IOException if an input/output error occurs
+     */
+    public PrintWriter getWriter() throws IOException {
+
+        if (writer != null)
+            return (writer);
+
+        if (stream != null)
+            throw new IllegalStateException("getOutputStream() has already been called for this response");
+
+        stream = createOutputStream();
+        if (debug > 1) {
+            System.out.println("stream is set to "+stream+" in getWriter");
+        }
+        //String charset = getCharsetFromContentType(contentType);
+        String charEnc = origResponse.getCharacterEncoding();
+        if (debug > 1) {
+            System.out.println("character encoding is " + charEnc);
+        }
+        // HttpServletResponse.getCharacterEncoding() shouldn't return null
+        // according the spec, so feel free to remove that "if"
+        if (charEnc != null) {
+            writer = new PrintWriter(new OutputStreamWriter(stream, charEnc));
+        } else {
+            writer = new PrintWriter(stream);
+        }
+        
+        return (writer);
+
+    }
+
+
+    public void setContentLength(int length) {
+    }
+
+
+    /**
+     * Returns character from content type. This method was taken from tomcat.
+     * @author rajo
+     */
+    private static String getCharsetFromContentType(String type) {
+
+        if (type == null) {
+            return null;
+        }
+        int semi = type.indexOf(";");
+        if (semi == -1) {
+            return null;
+        }
+        String afterSemi = type.substring(semi + 1);
+        int charsetLocation = afterSemi.indexOf("charset=");
+        if(charsetLocation == -1) {
+            return null;
+        } else {
+            String afterCharset = afterSemi.substring(charsetLocation + 8);
+            String encoding = afterCharset.trim();
+            return encoding;
+        }
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/dates/JspCalendar.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/dates/JspCalendar.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/dates/JspCalendar.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,152 @@
+/*
+* Copyright 2004 The Apache Software Foundation
+*
+* Licensed 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 dates;
+
+import java.text.DateFormat;
+import java.util.*;
+
+public class JspCalendar {
+    Calendar  calendar = null;
+
+    public JspCalendar() {
+	calendar = Calendar.getInstance();
+	Date trialTime = new Date();
+	calendar.setTime(trialTime);
+    }
+
+    public int getYear() {
+	return calendar.get(Calendar.YEAR);
+    }
+    
+    public String getMonth() {
+	int m = getMonthInt();
+	String[] months = new String [] { "January", "February", "March",
+					"April", "May", "June",
+					"July", "August", "September",
+					"October", "November", "December" };
+	if (m > 12)
+	    return "Unknown to Man";
+	
+	return months[m - 1];
+
+    }
+
+    public String getDay() {
+	int x = getDayOfWeek();
+	String[] days = new String[] {"Sunday", "Monday", "Tuesday", "Wednesday", 
+				      "Thursday", "Friday", "Saturday"};
+
+	if (x > 7)
+	    return "Unknown to Man";
+
+	return days[x - 1];
+
+    }
+    
+    public int getMonthInt() {
+	return 1 + calendar.get(Calendar.MONTH);
+    }
+
+    public String getDate() {
+	return getMonthInt() + "/" + getDayOfMonth() + "/" +  getYear();
+
+    }
+
+    public String getTime() {
+	return getHour() + ":" + getMinute() + ":" + getSecond();
+    }
+
+    public int getDayOfMonth() {
+	return calendar.get(Calendar.DAY_OF_MONTH);
+    }
+
+    public int getDayOfYear() {
+	return calendar.get(Calendar.DAY_OF_YEAR);
+    }
+
+    public int getWeekOfYear() {
+	return calendar.get(Calendar.WEEK_OF_YEAR);
+    }
+
+    public int getWeekOfMonth() {
+	return calendar.get(Calendar.WEEK_OF_MONTH);
+    }
+
+    public int getDayOfWeek() {
+	return calendar.get(Calendar.DAY_OF_WEEK);
+    }
+     
+    public int getHour() {
+	return calendar.get(Calendar.HOUR_OF_DAY);
+    }
+    
+    public int getMinute() {
+	return calendar.get(Calendar.MINUTE);
+    }
+
+
+    public int getSecond() {
+	return calendar.get(Calendar.SECOND);
+    }
+
+    public static void main(String args[]) {
+	JspCalendar db = new JspCalendar();
+	p("date: " + db.getDayOfMonth());
+	p("year: " + db.getYear());
+	p("month: " + db.getMonth());
+	p("time: " + db.getTime());
+	p("date: " + db.getDate());
+	p("Day: " + db.getDay());
+	p("DayOfYear: " + db.getDayOfYear());
+	p("WeekOfYear: " + db.getWeekOfYear());
+	p("era: " + db.getEra());
+	p("ampm: " + db.getAMPM());
+	p("DST: " + db.getDSTOffset());
+	p("ZONE Offset: " + db.getZoneOffset());
+	p("TIMEZONE: " + db.getUSTimeZone());
+    }
+
+    private static void p(String x) {
+	System.out.println(x);
+    }
+
+
+    public int getEra() {
+	return calendar.get(Calendar.ERA);
+    }
+
+    public String getUSTimeZone() {
+	String[] zones = new String[] {"Hawaii", "Alaskan", "Pacific",
+				       "Mountain", "Central", "Eastern"};
+	
+	return zones[10 + getZoneOffset()];
+    }
+
+    public int getZoneOffset() {
+	return calendar.get(Calendar.ZONE_OFFSET)/(60*60*1000);
+    }
+
+
+    public int getDSTOffset() {
+	return calendar.get(Calendar.DST_OFFSET)/(60*60*1000);
+    }
+
+    
+    public int getAMPM() {
+	return calendar.get(Calendar.AM_PM);
+    }
+}
+

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/error/Smart.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/error/Smart.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/error/Smart.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,34 @@
+/*
+* Copyright 2004 The Apache Software Foundation
+*
+* Licensed 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 error;
+
+import java.io.*;
+import java.lang.*;
+
+public class Smart {
+
+  String name = "JSP";
+
+  public String getName () {
+	return name;
+  }	
+
+  public void setName (String name) {
+	this.name = name;
+  }	
+}

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/examples/ExampleTagBase.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/examples/ExampleTagBase.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/examples/ExampleTagBase.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,66 @@
+/*
+* Copyright 2004 The Apache Software Foundation
+*
+* Licensed 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 examples;
+
+import javax.servlet.jsp.*;
+import javax.servlet.jsp.tagext.*;
+
+public abstract class ExampleTagBase extends BodyTagSupport {
+
+    public void setParent(Tag parent) {
+        this.parent = parent;
+    }
+
+    public void setBodyContent(BodyContent bodyOut) {
+        this.bodyOut = bodyOut;
+    }
+
+    public void setPageContext(PageContext pageContext) {
+        this.pageContext = pageContext;
+    }
+
+    public Tag getParent() {
+        return this.parent;
+    }
+    
+    public int doStartTag() throws JspException {
+        return SKIP_BODY;
+    }
+
+    public int doEndTag() throws JspException {
+        return EVAL_PAGE;
+    }
+    
+
+    // Default implementations for BodyTag methods as well
+    // just in case a tag decides to implement BodyTag.
+    public void doInitBody() throws JspException {
+    }
+
+    public int doAfterBody() throws JspException {
+        return SKIP_BODY;
+    }
+
+    public void release() {
+        bodyOut = null;
+        pageContext = null;
+        parent = null;
+    }
+    
+    protected BodyContent bodyOut;
+    protected PageContext pageContext;
+    protected Tag parent;
+}

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/examples/FooTag.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/examples/FooTag.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/examples/FooTag.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,82 @@
+/*
+* Copyright 2004 The Apache Software Foundation
+*
+* Licensed 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 examples;
+
+import javax.servlet.jsp.*;
+import javax.servlet.jsp.tagext.*;
+import java.util.Hashtable;
+import java.io.Writer;
+import java.io.IOException;
+
+/**
+ * Example1: the simplest tag
+ * Collect attributes and call into some actions
+ *
+ * <foo att1="..." att2="...." att3="...." />
+ */
+
+public class FooTag 
+    extends ExampleTagBase 
+{
+    private String atts[] = new String[3];
+    int i = 0;
+    
+    private final void setAtt(int index, String value) {
+        atts[index] = value;
+    }
+    
+    public void setAtt1(String value) {
+        setAtt(0, value);
+    }
+    
+    public void setAtt2(String value) {
+        setAtt(1, value);
+    }
+
+    public void setAtt3(String value) {
+        setAtt(2, value);
+    }
+    
+    /**
+     * Process start tag
+     *
+     * @return EVAL_BODY_INCLUDE
+     */
+    public int doStartTag() throws JspException {
+        i = 0;
+	return EVAL_BODY_TAG;
+    }
+
+    public void doInitBody() throws JspException {
+        pageContext.setAttribute("member", atts[i]);
+        i++;
+    }
+    
+    public int doAfterBody() throws JspException {
+        try {
+            if (i == 3) {
+                bodyOut.writeOut(bodyOut.getEnclosingWriter());
+                return SKIP_BODY;
+            } else
+                pageContext.setAttribute("member", atts[i]);
+            i++;
+            return EVAL_BODY_TAG;
+        } catch (IOException ex) {
+            throw new JspTagException(ex.toString());
+        }
+    }
+}
+

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/examples/FooTagExtraInfo.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/examples/FooTagExtraInfo.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/examples/FooTagExtraInfo.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,32 @@
+/*
+* Copyright 2004 The Apache Software Foundation
+*
+* Licensed 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 examples;
+
+import javax.servlet.jsp.tagext.*;
+
+public class FooTagExtraInfo extends TagExtraInfo {
+    public VariableInfo[] getVariableInfo(TagData data) {
+        return new VariableInfo[] 
+            {
+                new VariableInfo("member",
+                                 "String",
+                                 true,
+                                 VariableInfo.NESTED)
+            };
+    }
+}
+
+        

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/examples/LogTag.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/examples/LogTag.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/examples/LogTag.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,60 @@
+/*
+* Copyright 2004 The Apache Software Foundation
+*
+* Licensed 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 examples;
+
+
+import javax.servlet.jsp.*;
+import javax.servlet.jsp.tagext.*;
+
+import java.io.IOException;
+
+/**
+ * Log the contents of the body. Could be used to handle errors etc. 
+ */
+public class LogTag 
+    extends ExampleTagBase
+{
+    boolean toBrowser = false;
+    
+    public void setToBrowser(String value) {
+        if (value == null)
+            toBrowser = false;
+        else if (value.equalsIgnoreCase("true"))
+            toBrowser = true;
+        else
+            toBrowser = false;
+    }
+
+    public int doStartTag() throws JspException {
+        return EVAL_BODY_TAG;
+    }
+    
+    public int doAfterBody() throws JspException {
+        try {
+            String s = bodyOut.getString();
+            System.err.println(s);
+            if (toBrowser)
+                bodyOut.writeOut(bodyOut.getEnclosingWriter());
+            return SKIP_BODY;
+        } catch (IOException ex) {
+            throw new JspTagException(ex.toString());
+        }
+    }
+}
+
+    
+        
+    

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/examples/ShowSource.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/examples/ShowSource.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/examples/ShowSource.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,72 @@
+/*
+* Copyright 2004 The Apache Software Foundation
+*
+* Licensed 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 examples;
+
+
+import javax.servlet.*;
+import javax.servlet.jsp.*;
+import javax.servlet.jsp.tagext.*;
+
+import java.io.*;
+
+/**
+ * Display the sources of the JSP file.
+ */
+public class ShowSource
+    extends TagSupport
+{
+    String jspFile;
+    
+    public void setJspFile(String jspFile) {
+        this.jspFile = jspFile;
+    }
+
+    public int doEndTag() throws JspException {
+	if ((jspFile.indexOf( ".." ) >= 0) ||
+            (jspFile.toUpperCase().indexOf("/WEB-INF/") != 0) ||
+            (jspFile.toUpperCase().indexOf("/META-INF/") != 0))
+	    throw new JspTagException("Invalid JSP file " + jspFile);
+
+        InputStream in
+            = pageContext.getServletContext().getResourceAsStream(jspFile);
+
+        if (in == null)
+            throw new JspTagException("Unable to find JSP file: "+jspFile);
+
+        InputStreamReader reader = new InputStreamReader(in);
+	JspWriter out = pageContext.getOut();
+
+
+        try {
+            out.println("<body>");
+            out.println("<pre>");
+            for(int ch = in.read(); ch != -1; ch = in.read())
+                if (ch == '<')
+                    out.print("&lt;");
+                else
+                    out.print((char) ch);
+            out.println("</pre>");
+            out.println("</body>");
+        } catch (IOException ex) {
+            throw new JspTagException("IOException: "+ex.toString());
+        }
+        return super.doEndTag();
+    }
+}
+
+    
+        
+    

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/filters/ExampleFilter.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/filters/ExampleFilter.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/filters/ExampleFilter.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,140 @@
+/*
+* Copyright 2004 The Apache Software Foundation
+*
+* Licensed 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 filters;
+
+
+import java.io.IOException;
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+
+
+/**
+ * Example filter that can be attached to either an individual servlet
+ * or to a URL pattern.  This filter performs the following functions:
+ * <ul>
+ * <li>Attaches itself as a request attribute, under the attribute name
+ *     defined by the value of the <code>attribute</code> initialization
+ *     parameter.</li>
+ * <li>Calculates the number of milliseconds required to perform the
+ *     servlet processing required by this request, including any
+ *     subsequently defined filters, and logs the result to the servlet
+ *     context log for this application.
+ * </ul>
+ *
+ * @author Craig McClanahan
+ * @version $Revision: 267129 $ $Date: 2004-03-18 10:40:35 -0600 (Thu, 18 Mar 2004) $
+ */
+
+public final class ExampleFilter implements Filter {
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The request attribute name under which we store a reference to ourself.
+     */
+    private String attribute = null;
+
+
+    /**
+     * The filter configuration object we are associated with.  If this value
+     * is null, this filter instance is not currently configured.
+     */
+    private FilterConfig filterConfig = null;
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Take this filter out of service.
+     */
+    public void destroy() {
+
+        this.attribute = null;
+        this.filterConfig = null;
+
+    }
+
+
+    /**
+     * Time the processing that is performed by all subsequent filters in the
+     * current filter stack, including the ultimately invoked servlet.
+     *
+     * @param request The servlet request we are processing
+     * @param result The servlet response we are creating
+     * @param chain The filter chain we are processing
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception ServletException if a servlet error occurs
+     */
+    public void doFilter(ServletRequest request, ServletResponse response,
+                         FilterChain chain)
+	throws IOException, ServletException {
+
+	// Store ourselves as a request attribute (if requested)
+	if (attribute != null)
+	    request.setAttribute(attribute, this);
+
+	// Time and log the subsequent processing
+	long startTime = System.currentTimeMillis();
+        chain.doFilter(request, response);
+	long stopTime = System.currentTimeMillis();
+	filterConfig.getServletContext().log
+	    (this.toString() + ": " + (stopTime - startTime) +
+	     " milliseconds");
+
+    }
+
+
+    /**
+     * Place this filter into service.
+     *
+     * @param filterConfig The filter configuration object
+     */
+    public void init(FilterConfig filterConfig) throws ServletException {
+
+	this.filterConfig = filterConfig;
+        this.attribute = filterConfig.getInitParameter("attribute");
+
+    }
+
+
+    /**
+     * Return a String representation of this object.
+     */
+    public String toString() {
+
+	if (filterConfig == null)
+	    return ("InvokerFilter()");
+	StringBuffer sb = new StringBuffer("InvokerFilter(");
+	sb.append(filterConfig);
+	sb.append(")");
+	return (sb.toString());
+
+    }
+
+
+}
+

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/filters/RequestDumperFilter.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/filters/RequestDumperFilter.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/filters/RequestDumperFilter.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,201 @@
+/*
+* Copyright 2004 The Apache Software Foundation
+*
+* Licensed 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 filters;
+
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.sql.Timestamp;
+import java.util.Enumeration;
+import java.util.Locale;
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletRequest;
+
+
+/**
+ * Example filter that dumps interesting state information about a request
+ * to the associated servlet context log file, before allowing the servlet
+ * to process the request in the usual way.  This can be installed as needed
+ * to assist in debugging problems.
+ *
+ * @author Craig McClanahan
+ * @version $Revision: 267129 $ $Date: 2004-03-18 10:40:35 -0600 (Thu, 18 Mar 2004) $
+ */
+
+public final class RequestDumperFilter implements Filter {
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The filter configuration object we are associated with.  If this value
+     * is null, this filter instance is not currently configured.
+     */
+    private FilterConfig filterConfig = null;
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Take this filter out of service.
+     */
+    public void destroy() {
+
+        this.filterConfig = null;
+
+    }
+
+
+    /**
+     * Time the processing that is performed by all subsequent filters in the
+     * current filter stack, including the ultimately invoked servlet.
+     *
+     * @param request The servlet request we are processing
+     * @param result The servlet response we are creating
+     * @param chain The filter chain we are processing
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception ServletException if a servlet error occurs
+     */
+    public void doFilter(ServletRequest request, ServletResponse response,
+                         FilterChain chain)
+	throws IOException, ServletException {
+
+        if (filterConfig == null)
+	    return;
+
+	// Render the generic servlet request properties
+	StringWriter sw = new StringWriter();
+	PrintWriter writer = new PrintWriter(sw);
+	writer.println("Request Received at " +
+		       (new Timestamp(System.currentTimeMillis())));
+	writer.println(" characterEncoding=" + request.getCharacterEncoding());
+	writer.println("     contentLength=" + request.getContentLength());
+	writer.println("       contentType=" + request.getContentType());
+	writer.println("            locale=" + request.getLocale());
+	writer.print("           locales=");
+	Enumeration locales = request.getLocales();
+	boolean first = true;
+	while (locales.hasMoreElements()) {
+	    Locale locale = (Locale) locales.nextElement();
+	    if (first)
+	        first = false;
+	    else
+	        writer.print(", ");
+	    writer.print(locale.toString());
+	}
+	writer.println();
+	Enumeration names = request.getParameterNames();
+	while (names.hasMoreElements()) {
+	    String name = (String) names.nextElement();
+	    writer.print("         parameter=" + name + "=");
+	    String values[] = request.getParameterValues(name);
+	    for (int i = 0; i < values.length; i++) {
+	        if (i > 0)
+		    writer.print(", ");
+		writer.print(values[i]);
+	    }
+	    writer.println();
+	}
+	writer.println("          protocol=" + request.getProtocol());
+	writer.println("        remoteAddr=" + request.getRemoteAddr());
+	writer.println("        remoteHost=" + request.getRemoteHost());
+	writer.println("            scheme=" + request.getScheme());
+	writer.println("        serverName=" + request.getServerName());
+	writer.println("        serverPort=" + request.getServerPort());
+	writer.println("          isSecure=" + request.isSecure());
+
+	// Render the HTTP servlet request properties
+	if (request instanceof HttpServletRequest) {
+	    writer.println("---------------------------------------------");
+	    HttpServletRequest hrequest = (HttpServletRequest) request;
+	    writer.println("       contextPath=" + hrequest.getContextPath());
+	    Cookie cookies[] = hrequest.getCookies();
+            if (cookies == null)
+                cookies = new Cookie[0];
+	    for (int i = 0; i < cookies.length; i++) {
+	        writer.println("            cookie=" + cookies[i].getName() +
+			       "=" + cookies[i].getValue());
+	    }
+	    names = hrequest.getHeaderNames();
+	    while (names.hasMoreElements()) {
+	        String name = (String) names.nextElement();
+		String value = hrequest.getHeader(name);
+	        writer.println("            header=" + name + "=" + value);
+	    }
+	    writer.println("            method=" + hrequest.getMethod());
+	    writer.println("          pathInfo=" + hrequest.getPathInfo());
+	    writer.println("       queryString=" + hrequest.getQueryString());
+	    writer.println("        remoteUser=" + hrequest.getRemoteUser());
+	    writer.println("requestedSessionId=" +
+			   hrequest.getRequestedSessionId());
+	    writer.println("        requestURI=" + hrequest.getRequestURI());
+	    writer.println("       servletPath=" + hrequest.getServletPath());
+	}
+	writer.println("=============================================");
+
+	// Log the resulting string
+	writer.flush();
+	filterConfig.getServletContext().log(sw.getBuffer().toString());
+
+	// Pass control on to the next filter
+        chain.doFilter(request, response);
+
+    }
+
+
+    /**
+     * Place this filter into service.
+     *
+     * @param filterConfig The filter configuration object
+     */
+    public void init(FilterConfig filterConfig) throws ServletException {
+
+	this.filterConfig = filterConfig;
+
+    }
+
+
+    /**
+     * Return a String representation of this object.
+     */
+    public String toString() {
+
+	if (filterConfig == null)
+	    return ("RequestDumperFilter()");
+	StringBuffer sb = new StringBuffer("RequestDumperFilter(");
+	sb.append(filterConfig);
+	sb.append(")");
+	return (sb.toString());
+
+    }
+
+
+}
+

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/filters/SetCharacterEncodingFilter.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/filters/SetCharacterEncodingFilter.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/filters/SetCharacterEncodingFilter.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,172 @@
+/*
+* Copyright 2004 The Apache Software Foundation
+*
+* Licensed 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 filters;
+
+
+import java.io.IOException;
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.UnavailableException;
+
+
+/**
+ * <p>Example filter that sets the character encoding to be used in parsing the
+ * incoming request, either unconditionally or only if the client did not
+ * specify a character encoding.  Configuration of this filter is based on
+ * the following initialization parameters:</p>
+ * <ul>
+ * <li><strong>encoding</strong> - The character encoding to be configured
+ *     for this request, either conditionally or unconditionally based on
+ *     the <code>ignore</code> initialization parameter.  This parameter
+ *     is required, so there is no default.</li>
+ * <li><strong>ignore</strong> - If set to "true", any character encoding
+ *     specified by the client is ignored, and the value returned by the
+ *     <code>selectEncoding()</code> method is set.  If set to "false,
+ *     <code>selectEncoding()</code> is called <strong>only</strong> if the
+ *     client has not already specified an encoding.  By default, this
+ *     parameter is set to "true".</li>
+ * </ul>
+ *
+ * <p>Although this filter can be used unchanged, it is also easy to
+ * subclass it and make the <code>selectEncoding()</code> method more
+ * intelligent about what encoding to choose, based on characteristics of
+ * the incoming request (such as the values of the <code>Accept-Language</code>
+ * and <code>User-Agent</code> headers, or a value stashed in the current
+ * user's session.</p>
+ *
+ * @author Craig McClanahan
+ * @version $Revision: 267129 $ $Date: 2004-03-18 10:40:35 -0600 (Thu, 18 Mar 2004) $
+ */
+
+public class SetCharacterEncodingFilter implements Filter {
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The default character encoding to set for requests that pass through
+     * this filter.
+     */
+    protected String encoding = null;
+
+
+    /**
+     * The filter configuration object we are associated with.  If this value
+     * is null, this filter instance is not currently configured.
+     */
+    protected FilterConfig filterConfig = null;
+
+
+    /**
+     * Should a character encoding specified by the client be ignored?
+     */
+    protected boolean ignore = true;
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Take this filter out of service.
+     */
+    public void destroy() {
+
+        this.encoding = null;
+        this.filterConfig = null;
+
+    }
+
+
+    /**
+     * Select and set (if specified) the character encoding to be used to
+     * interpret request parameters for this request.
+     *
+     * @param request The servlet request we are processing
+     * @param result The servlet response we are creating
+     * @param chain The filter chain we are processing
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception ServletException if a servlet error occurs
+     */
+    public void doFilter(ServletRequest request, ServletResponse response,
+                         FilterChain chain)
+	throws IOException, ServletException {
+
+        // Conditionally select and set the character encoding to be used
+        if (ignore || (request.getCharacterEncoding() == null)) {
+            String encoding = selectEncoding(request);
+            if (encoding != null)
+                request.setCharacterEncoding(encoding);
+        }
+
+	// Pass control on to the next filter
+        chain.doFilter(request, response);
+
+    }
+
+
+    /**
+     * Place this filter into service.
+     *
+     * @param filterConfig The filter configuration object
+     */
+    public void init(FilterConfig filterConfig) throws ServletException {
+
+	this.filterConfig = filterConfig;
+        this.encoding = filterConfig.getInitParameter("encoding");
+        String value = filterConfig.getInitParameter("ignore");
+        if (value == null)
+            this.ignore = true;
+        else if (value.equalsIgnoreCase("true"))
+            this.ignore = true;
+        else if (value.equalsIgnoreCase("yes"))
+            this.ignore = true;
+        else
+            this.ignore = false;
+
+    }
+
+
+    // ------------------------------------------------------ Protected Methods
+
+
+    /**
+     * Select an appropriate character encoding to be used, based on the
+     * characteristics of the current request and/or filter initialization
+     * parameters.  If no character encoding should be set, return
+     * <code>null</code>.
+     * <p>
+     * The default implementation unconditionally returns the value configured
+     * by the <strong>encoding</strong> initialization parameter for this
+     * filter.
+     *
+     * @param request The servlet request we are processing
+     */
+    protected String selectEncoding(ServletRequest request) {
+
+        return (this.encoding);
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/jsp2/examples/BookBean.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/jsp2/examples/BookBean.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/jsp2/examples/BookBean.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,43 @@
+/*
+* Copyright 2004 The Apache Software Foundation
+*
+* Licensed 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 jsp2.examples;
+
+public class BookBean {
+    private String title;
+    private String author;
+    private String isbn;
+    
+    public BookBean( String title, String author, String isbn ) {
+        this.title = title;
+        this.author = author;
+        this.isbn = isbn;
+    }
+
+    public String getTitle() {
+        return this.title;
+    }
+    
+    public String getAuthor() {
+        return this.author;
+    }
+    
+    public String getIsbn() {
+        return this.isbn;
+    }
+    
+}

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/jsp2/examples/FooBean.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/jsp2/examples/FooBean.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/jsp2/examples/FooBean.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,35 @@
+/*
+* Copyright 2004 The Apache Software Foundation
+*
+* Licensed 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 jsp2.examples;
+
+public class FooBean {
+    private String bar;
+    
+    public FooBean() {
+        bar = "Initial value";
+    }
+    
+    public String getBar() {
+        return this.bar;
+    }
+    
+    public void setBar(String bar) {
+        this.bar = bar;
+    }
+    
+}

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/jsp2/examples/el/Functions.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/jsp2/examples/el/Functions.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/jsp2/examples/el/Functions.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,44 @@
+/*
+* Copyright 2004 The Apache Software Foundation
+*
+* Licensed 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 jsp2.examples.el;
+
+import java.util.*;
+
+/**
+ * Defines the functions for the jsp2 example tag library.
+ * 
+ * <p>Each function is defined as a static method.</p>
+ */
+public class Functions {
+    public static String reverse( String text ) {
+        return new StringBuffer( text ).reverse().toString();
+    }
+
+    public static int numVowels( String text ) {
+        String vowels = "aeiouAEIOU";
+	int result = 0;
+        for( int i = 0; i < text.length(); i++ ) {
+	    if( vowels.indexOf( text.charAt( i ) ) != -1 ) {
+	        result++;
+	    }
+	}
+	return result;
+    }
+
+    public static String caps( String text ) {
+        return text.toUpperCase();
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/jsp2/examples/simpletag/EchoAttributesTag.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/jsp2/examples/simpletag/EchoAttributesTag.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/jsp2/examples/simpletag/EchoAttributesTag.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,54 @@
+/*
+* Copyright 2004 The Apache Software Foundation
+*
+* Licensed 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 jsp2.examples.simpletag;
+
+import javax.servlet.jsp.JspException;
+import javax.servlet.jsp.JspWriter;
+import javax.servlet.jsp.tagext.SimpleTagSupport;
+import javax.servlet.jsp.tagext.DynamicAttributes;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.io.IOException;
+
+/**
+ * SimpleTag handler that echoes all its attributes 
+ */
+public class EchoAttributesTag 
+    extends SimpleTagSupport
+    implements DynamicAttributes
+{
+    private ArrayList keys = new ArrayList();
+    private ArrayList values = new ArrayList();
+
+    public void doTag() throws JspException, IOException {
+	JspWriter out = getJspContext().getOut();
+	for( int i = 0; i < keys.size(); i++ ) {
+	    String key = (String)keys.get( i );
+	    Object value = values.get( i );
+	    out.println( "<li>" + key + " = " + value + "</li>" );
+        }
+    }
+
+    public void setDynamicAttribute( String uri, String localName, 
+	Object value ) 
+	throws JspException
+    {
+	keys.add( localName );
+	values.add( value );
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/jsp2/examples/simpletag/FindBookSimpleTag.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/jsp2/examples/simpletag/FindBookSimpleTag.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/jsp2/examples/simpletag/FindBookSimpleTag.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,44 @@
+/*
+* Copyright 2004 The Apache Software Foundation
+*
+* Licensed 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 jsp2.examples.simpletag;
+
+import javax.servlet.jsp.JspException;
+import javax.servlet.jsp.tagext.SimpleTagSupport;
+import java.util.HashMap;
+import jsp2.examples.BookBean;
+
+/**
+ * SimpleTag handler that pretends to search for a book, and stores
+ * the result in a scoped variable.
+ */
+public class FindBookSimpleTag extends SimpleTagSupport {
+    private String var;
+    
+    private static final String BOOK_TITLE = "The Lord of the Rings";
+    private static final String BOOK_AUTHOR = "J. R. R. Tolkein";
+    private static final String BOOK_ISBN = "0618002251";
+
+    public void doTag() throws JspException {
+        BookBean book = new BookBean( BOOK_TITLE, BOOK_AUTHOR, BOOK_ISBN );
+        getJspContext().setAttribute( this.var, book );
+    }
+
+    public void setVar( String var ) {
+	this.var = var;
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/jsp2/examples/simpletag/HelloWorldSimpleTag.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/jsp2/examples/simpletag/HelloWorldSimpleTag.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/jsp2/examples/simpletag/HelloWorldSimpleTag.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,31 @@
+/*
+* Copyright 2004 The Apache Software Foundation
+*
+* Licensed 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 jsp2.examples.simpletag;
+
+import javax.servlet.jsp.JspException;
+import javax.servlet.jsp.tagext.SimpleTagSupport;
+import java.io.IOException;
+
+/**
+ * SimpleTag handler that prints "Hello, world!"
+ */
+public class HelloWorldSimpleTag extends SimpleTagSupport {
+    public void doTag() throws JspException, IOException {
+	getJspContext().getOut().write( "Hello, world!" );
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/jsp2/examples/simpletag/RepeatSimpleTag.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/jsp2/examples/simpletag/RepeatSimpleTag.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/jsp2/examples/simpletag/RepeatSimpleTag.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,42 @@
+/*
+* Copyright 2004 The Apache Software Foundation
+*
+* Licensed 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 jsp2.examples.simpletag;
+
+import javax.servlet.jsp.JspException;
+import javax.servlet.jsp.tagext.SimpleTagSupport;
+import java.util.HashMap;
+import java.io.IOException;
+
+/**
+ * SimpleTag handler that accepts a num attribute and 
+ * invokes its body 'num' times.
+ */
+public class RepeatSimpleTag extends SimpleTagSupport {
+    private int num;
+
+    public void doTag() throws JspException, IOException {
+        for (int i=0; i<num; i++) {
+            getJspContext().setAttribute("count", String.valueOf( i + 1 ) );
+	    getJspBody().invoke(null);
+        }
+    }
+
+    public void setNum(int num) {
+	this.num = num;
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/jsp2/examples/simpletag/ShuffleSimpleTag.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/jsp2/examples/simpletag/ShuffleSimpleTag.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/jsp2/examples/simpletag/ShuffleSimpleTag.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,81 @@
+/*
+* Copyright 2004 The Apache Software Foundation
+*
+* Licensed 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 jsp2.examples.simpletag;
+
+import javax.servlet.jsp.JspException;
+import javax.servlet.jsp.tagext.JspFragment;
+import javax.servlet.jsp.tagext.SimpleTagSupport;
+import java.util.HashMap;
+import java.io.IOException;
+
+/**
+ * SimpleTag handler that accepts takes three attributes of type
+ * JspFragment and invokes then in a random order.
+ */
+public class ShuffleSimpleTag extends SimpleTagSupport {
+    private JspFragment fragment1;
+    private JspFragment fragment2;
+    private JspFragment fragment3;
+
+    public void doTag() throws JspException, IOException {
+        switch( (int)(Math.random() * 6) ) {
+            case 0:
+                fragment1.invoke( null );
+                fragment2.invoke( null );
+                fragment3.invoke( null );
+                break;
+            case 1:
+                fragment1.invoke( null );
+                fragment3.invoke( null );
+                fragment2.invoke( null );
+                break;
+            case 2:
+                fragment2.invoke( null );
+                fragment1.invoke( null );
+                fragment3.invoke( null );
+                break;
+            case 3:
+                fragment2.invoke( null );
+                fragment3.invoke( null );
+                fragment1.invoke( null );
+                break;
+            case 4:
+                fragment3.invoke( null );
+                fragment1.invoke( null );
+                fragment2.invoke( null );
+                break;
+            case 5:
+                fragment3.invoke( null );
+                fragment2.invoke( null );
+                fragment1.invoke( null );
+                break;
+        }
+    }
+
+    public void setFragment1( JspFragment fragment1 ) {
+        this.fragment1 = fragment1;
+    }
+    
+    public void setFragment2( JspFragment fragment2 ) {
+        this.fragment2 = fragment2;
+    }
+    
+    public void setFragment3( JspFragment fragment3 ) {
+        this.fragment3 = fragment3;
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/jsp2/examples/simpletag/TileSimpleTag.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/jsp2/examples/simpletag/TileSimpleTag.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/jsp2/examples/simpletag/TileSimpleTag.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,46 @@
+/*
+* Copyright 2004 The Apache Software Foundation
+*
+* Licensed 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 jsp2.examples.simpletag;
+
+import javax.servlet.jsp.JspException;
+import javax.servlet.jsp.tagext.SimpleTagSupport;
+import java.io.IOException;
+import java.util.HashMap;
+
+/**
+ * Displays a tile as a single cell in a table.
+ */
+public class TileSimpleTag extends SimpleTagSupport {
+    private String color;
+    private String label;
+
+    public void doTag() throws JspException, IOException {
+	getJspContext().getOut().write( 
+	    "<td width=\"32\" height=\"32\" bgcolor=\"" + this.color + 
+	    "\"><font color=\"#ffffff\"><center>" + this.label + 
+                "</center></font></td>" );
+    }
+
+    public void setColor( String color ) {
+        this.color = color;
+    }
+    
+    public void setLabel( String label ) {
+        this.label = label;
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/listeners/ContextListener.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/listeners/ContextListener.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/listeners/ContextListener.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,156 @@
+/*
+* Copyright 2004 The Apache Software Foundation
+*
+* Licensed 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 listeners;
+
+
+import javax.servlet.ServletContext;
+import javax.servlet.ServletContextAttributeEvent;
+import javax.servlet.ServletContextAttributeListener;
+import javax.servlet.ServletContextEvent;
+import javax.servlet.ServletContextListener;
+
+
+/**
+ * Example listener for context-related application events, which were
+ * introduced in the 2.3 version of the Servlet API.  This listener
+ * merely documents the occurrence of such events in the application log
+ * associated with our servlet context.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 267129 $ $Date: 2004-03-18 10:40:35 -0600 (Thu, 18 Mar 2004) $
+ */
+
+public final class ContextListener
+    implements ServletContextAttributeListener, ServletContextListener {
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The servlet context with which we are associated.
+     */
+    private ServletContext context = null;
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Record the fact that a servlet context attribute was added.
+     *
+     * @param event The servlet context attribute event
+     */
+    public void attributeAdded(ServletContextAttributeEvent event) {
+
+	log("attributeAdded('" + event.getName() + "', '" +
+	    event.getValue() + "')");
+
+    }
+
+
+    /**
+     * Record the fact that a servlet context attribute was removed.
+     *
+     * @param event The servlet context attribute event
+     */
+    public void attributeRemoved(ServletContextAttributeEvent event) {
+
+	log("attributeRemoved('" + event.getName() + "', '" +
+	    event.getValue() + "')");
+
+    }
+
+
+    /**
+     * Record the fact that a servlet context attribute was replaced.
+     *
+     * @param event The servlet context attribute event
+     */
+    public void attributeReplaced(ServletContextAttributeEvent event) {
+
+	log("attributeReplaced('" + event.getName() + "', '" +
+	    event.getValue() + "')");
+
+    }
+
+
+    /**
+     * Record the fact that this web application has been destroyed.
+     *
+     * @param event The servlet context event
+     */
+    public void contextDestroyed(ServletContextEvent event) {
+
+	log("contextDestroyed()");
+	this.context = null;
+
+    }
+
+
+    /**
+     * Record the fact that this web application has been initialized.
+     *
+     * @param event The servlet context event
+     */
+    public void contextInitialized(ServletContextEvent event) {
+
+	this.context = event.getServletContext();
+	log("contextInitialized()");
+
+    }
+
+
+    // -------------------------------------------------------- Private Methods
+
+
+    /**
+     * Log a message to the servlet context application log.
+     *
+     * @param message Message to be logged
+     */
+    private void log(String message) {
+
+	if (context != null)
+	    context.log("ContextListener: " + message);
+	else
+	    System.out.println("ContextListener: " + message);
+
+    }
+
+
+    /**
+     * Log a message and associated exception to the servlet context
+     * application log.
+     *
+     * @param message Message to be logged
+     * @param throwable Exception to be logged
+     */
+    private void log(String message, Throwable throwable) {
+
+	if (context != null)
+	    context.log("ContextListener: " + message, throwable);
+	else {
+	    System.out.println("ContextListener: " + message);
+	    throwable.printStackTrace(System.out);
+	}
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/listeners/SessionListener.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/listeners/SessionListener.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/listeners/SessionListener.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,183 @@
+/*
+* Copyright 2004 The Apache Software Foundation
+*
+* Licensed 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 listeners;
+
+
+import javax.servlet.ServletContext;
+import javax.servlet.ServletContextEvent;
+import javax.servlet.ServletContextListener;
+import javax.servlet.http.HttpSessionAttributeListener;
+import javax.servlet.http.HttpSessionBindingEvent;
+import javax.servlet.http.HttpSessionEvent;
+import javax.servlet.http.HttpSessionListener;
+
+
+/**
+ * Example listener for context-related application events, which were
+ * introduced in the 2.3 version of the Servlet API.  This listener
+ * merely documents the occurrence of such events in the application log
+ * associated with our servlet context.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 267129 $ $Date: 2004-03-18 10:40:35 -0600 (Thu, 18 Mar 2004) $
+ */
+
+public final class SessionListener
+    implements ServletContextListener,
+	       HttpSessionAttributeListener, HttpSessionListener {
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The servlet context with which we are associated.
+     */
+    private ServletContext context = null;
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Record the fact that a servlet context attribute was added.
+     *
+     * @param event The session attribute event
+     */
+    public void attributeAdded(HttpSessionBindingEvent event) {
+
+	log("attributeAdded('" + event.getSession().getId() + "', '" +
+	    event.getName() + "', '" + event.getValue() + "')");
+
+    }
+
+
+    /**
+     * Record the fact that a servlet context attribute was removed.
+     *
+     * @param event The session attribute event
+     */
+    public void attributeRemoved(HttpSessionBindingEvent event) {
+
+	log("attributeRemoved('" + event.getSession().getId() + "', '" +
+	    event.getName() + "', '" + event.getValue() + "')");
+
+    }
+
+
+    /**
+     * Record the fact that a servlet context attribute was replaced.
+     *
+     * @param event The session attribute event
+     */
+    public void attributeReplaced(HttpSessionBindingEvent event) {
+
+	log("attributeReplaced('" + event.getSession().getId() + "', '" +
+	    event.getName() + "', '" + event.getValue() + "')");
+
+    }
+
+
+    /**
+     * Record the fact that this web application has been destroyed.
+     *
+     * @param event The servlet context event
+     */
+    public void contextDestroyed(ServletContextEvent event) {
+
+	log("contextDestroyed()");
+	this.context = null;
+
+    }
+
+
+    /**
+     * Record the fact that this web application has been initialized.
+     *
+     * @param event The servlet context event
+     */
+    public void contextInitialized(ServletContextEvent event) {
+
+	this.context = event.getServletContext();
+	log("contextInitialized()");
+
+    }
+
+
+    /**
+     * Record the fact that a session has been created.
+     *
+     * @param event The session event
+     */
+    public void sessionCreated(HttpSessionEvent event) {
+
+	log("sessionCreated('" + event.getSession().getId() + "')");
+
+    }
+
+
+    /**
+     * Record the fact that a session has been destroyed.
+     *
+     * @param event The session event
+     */
+    public void sessionDestroyed(HttpSessionEvent event) {
+
+	log("sessionDestroyed('" + event.getSession().getId() + "')");
+
+    }
+
+
+    // -------------------------------------------------------- Private Methods
+
+
+    /**
+     * Log a message to the servlet context application log.
+     *
+     * @param message Message to be logged
+     */
+    private void log(String message) {
+
+	if (context != null)
+	    context.log("SessionListener: " + message);
+	else
+	    System.out.println("SessionListener: " + message);
+
+    }
+
+
+    /**
+     * Log a message and associated exception to the servlet context
+     * application log.
+     *
+     * @param message Message to be logged
+     * @param throwable Exception to be logged
+     */
+    private void log(String message, Throwable throwable) {
+
+	if (context != null)
+	    context.log("SessionListener: " + message, throwable);
+	else {
+	    System.out.println("SessionListener: " + message);
+	    throwable.printStackTrace(System.out);
+	}
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/num/NumberGuessBean.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/num/NumberGuessBean.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/num/NumberGuessBean.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,78 @@
+/*
+* Copyright 2004 The Apache Software Foundation
+*
+* Licensed 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.
+*/
+
+/*
+ * Originally written by Jason Hunter, http://www.servlets.com.
+ */
+
+package num;
+
+import java.util.*;
+
+public class NumberGuessBean {
+
+  int answer;
+  boolean success;
+  String hint;
+  int numGuesses;
+
+  public NumberGuessBean() {
+    reset();
+  }
+
+  public void setGuess(String guess) {
+    numGuesses++;
+
+    int g;
+    try {
+      g = Integer.parseInt(guess);
+    }
+    catch (NumberFormatException e) {
+      g = -1;
+    }
+
+    if (g == answer) {
+      success = true;
+    }
+    else if (g == -1) {
+      hint = "a number next time";
+    }
+    else if (g < answer) {
+      hint = "higher";
+    }
+    else if (g > answer) {
+      hint = "lower";
+    }
+  }
+
+  public boolean getSuccess() {
+    return success;
+  }
+
+  public String getHint() {
+    return "" + hint;
+  }
+
+  public int getNumGuesses() {
+    return numGuesses;
+  }
+
+  public void reset() {
+    answer = Math.abs(new Random().nextInt() % 100) + 1;
+    success = false;
+    numGuesses = 0;
+  }
+}

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/servletToJsp.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/servletToJsp.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/servletToJsp.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,32 @@
+/*
+* Copyright 2004 The Apache Software Foundation
+*
+* Licensed 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.
+*/
+import javax.servlet.*;
+import javax.servlet.http.*;
+
+public class servletToJsp extends HttpServlet {
+
+    public void doGet (HttpServletRequest request,
+		       HttpServletResponse response) {
+
+	try {
+	    // Set the attribute and Forward to hello.jsp
+	    request.setAttribute ("servletName", "servletToJsp");
+	    getServletConfig().getServletContext().getRequestDispatcher("/jsptoserv/hello.jsp").forward(request, response);
+	} catch (Exception ex) {
+	    ex.printStackTrace ();
+	}
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/sessions/DummyCart.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/sessions/DummyCart.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/sessions/DummyCart.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,69 @@
+/*
+* Copyright 2004 The Apache Software Foundation
+*
+* Licensed 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 sessions;
+
+import javax.servlet.http.*;
+import java.util.Vector;
+import java.util.Enumeration;
+
+public class DummyCart {
+    Vector v = new Vector();
+    String submit = null;
+    String item = null;
+    
+    private void addItem(String name) {
+	v.addElement(name);
+    }
+
+    private void removeItem(String name) {
+	v.removeElement(name);
+    }
+
+    public void setItem(String name) {
+	item = name;
+    }
+    
+    public void setSubmit(String s) {
+	submit = s;
+    }
+
+    public String[] getItems() {
+	String[] s = new String[v.size()];
+	v.copyInto(s);
+	return s;
+    }
+    
+    public void processRequest(HttpServletRequest request) {
+	// null value for submit - user hit enter instead of clicking on 
+	// "add" or "remove"
+	if (submit == null) 
+	    addItem(item);
+
+	if (submit.equals("add"))
+	    addItem(item);
+	else if (submit.equals("remove")) 
+	    removeItem(item);
+	
+	// reset at the end of the request
+	reset();
+    }
+
+    // reset
+    private void reset() {
+	submit = null;
+	item = null;
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/util/HTMLFilter.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/util/HTMLFilter.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/util/HTMLFilter.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,69 @@
+/*
+* Copyright 2004 The Apache Software Foundation
+*
+* Licensed 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 util;
+
+/**
+ * HTML filter utility.
+ *
+ * @author Craig R. McClanahan
+ * @author Tim Tye
+ * @version $Revision: 267129 $ $Date: 2004-03-18 10:40:35 -0600 (Thu, 18 Mar 2004) $
+ */
+
+public final class HTMLFilter {
+
+
+    /**
+     * Filter the specified message string for characters that are sensitive
+     * in HTML.  This avoids potential attacks caused by including JavaScript
+     * codes in the request URL that is often reported in error messages.
+     *
+     * @param message The message string to be filtered
+     */
+    public static String filter(String message) {
+
+        if (message == null)
+            return (null);
+
+        char content[] = new char[message.length()];
+        message.getChars(0, message.length(), content, 0);
+        StringBuffer result = new StringBuffer(content.length + 50);
+        for (int i = 0; i < content.length; i++) {
+            switch (content[i]) {
+            case '<':
+                result.append("&lt;");
+                break;
+            case '>':
+                result.append("&gt;");
+                break;
+            case '&':
+                result.append("&amp;");
+                break;
+            case '"':
+                result.append("&quot;");
+                break;
+            default:
+                result.append(content[i]);
+            }
+        }
+        return (result.toString());
+
+    }
+
+
+}
+

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/validators/DebugValidator.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/validators/DebugValidator.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/classes/validators/DebugValidator.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,83 @@
+/*
+* Copyright 2004 The Apache Software Foundation
+*
+* Licensed 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 validators;
+
+
+import java.io.InputStream;
+import java.io.IOException;
+import javax.servlet.jsp.tagext.PageData;
+import javax.servlet.jsp.tagext.TagLibraryValidator;
+import javax.servlet.jsp.tagext.ValidationMessage;
+
+
+/**
+ * Example tag library validator that simply dumps the XML version of each
+ * page to standard output (which will typically be sent to the file
+ * <code>$CATALINA_HOME/logs/catalina.out</code>).  To utilize it, simply
+ * include a <code>taglib</code> directive for this tag library at the top
+ * of your JSP page.
+ *
+ * @author Craig McClanahan
+ * @version $Revision: 267129 $ $Date: 2004-03-18 10:40:35 -0600 (Thu, 18 Mar 2004) $
+ */
+
+public class DebugValidator extends TagLibraryValidator {
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Validate a JSP page.  This will get invoked once per directive in the
+     * JSP page.  This method will return <code>null</code> if the page is
+     * valid; otherwise the method should return an array of
+     * <code>ValidationMessage</code> objects.  An array of length zero is
+     * also interpreted as no errors.
+     *
+     * @param prefix The value of the prefix argument in this directive
+     * @param uri The value of the URI argument in this directive
+     * @param page The page data for this page
+     */
+    public ValidationMessage[] validate(String prefix, String uri,
+                                        PageData page) {
+
+        System.out.println("---------- Prefix=" + prefix + " URI=" + uri +
+                           "----------");
+
+        InputStream is = page.getInputStream();
+        while (true) {
+            try {
+                int ch = is.read();
+                if (ch < 0)
+                    break;
+                System.out.print((char) ch);
+            } catch (IOException e) {
+                break;
+            }
+        }
+        System.out.println();
+        System.out.println("-----------------------------------------------");
+        return (null);
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/jsp/applet/Clock2.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/jsp/applet/Clock2.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/jsp/applet/Clock2.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,211 @@
+/*
+* Copyright 2004 The Apache Software Foundation
+*
+* Licensed 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.
+*/
+import java.util.*;
+import java.awt.*;
+import java.applet.*;
+import java.text.*;
+
+/**
+ * Time!
+ *
+ * @author Rachel Gollub
+ */
+
+public class Clock2 extends Applet implements Runnable {
+    Thread timer;                // The thread that displays clock
+    int lastxs, lastys, lastxm,
+        lastym, lastxh, lastyh;  // Dimensions used to draw hands 
+    SimpleDateFormat formatter;  // Formats the date displayed
+    String lastdate;             // String to hold date displayed
+    Font clockFaceFont;          // Font for number display on clock
+    Date currentDate;            // Used to get date to display
+    Color handColor;             // Color of main hands and dial
+    Color numberColor;           // Color of second hand and numbers
+
+    public void init() {
+        int x,y;
+        lastxs = lastys = lastxm = lastym = lastxh = lastyh = 0;
+        formatter = new SimpleDateFormat ("EEE MMM dd hh:mm:ss yyyy", Locale.getDefault());
+        currentDate = new Date();
+        lastdate = formatter.format(currentDate);
+        clockFaceFont = new Font("Serif", Font.PLAIN, 14);
+        handColor = Color.blue;
+        numberColor = Color.darkGray;
+
+        try {
+            setBackground(new Color(Integer.parseInt(getParameter("bgcolor"),16)));
+        } catch (Exception E) { }
+        try {
+            handColor = new Color(Integer.parseInt(getParameter("fgcolor1"),16));
+        } catch (Exception E) { }
+        try {
+            numberColor = new Color(Integer.parseInt(getParameter("fgcolor2"),16));
+        } catch (Exception E) { }
+        resize(300,300);              // Set clock window size
+    }
+
+    // Plotpoints allows calculation to only cover 45 degrees of the circle,
+    // and then mirror
+    public void plotpoints(int x0, int y0, int x, int y, Graphics g) {
+        g.drawLine(x0+x,y0+y,x0+x,y0+y);
+        g.drawLine(x0+y,y0+x,x0+y,y0+x);
+        g.drawLine(x0+y,y0-x,x0+y,y0-x);
+        g.drawLine(x0+x,y0-y,x0+x,y0-y);
+        g.drawLine(x0-x,y0-y,x0-x,y0-y);
+        g.drawLine(x0-y,y0-x,x0-y,y0-x);
+        g.drawLine(x0-y,y0+x,x0-y,y0+x);
+        g.drawLine(x0-x,y0+y,x0-x,y0+y);
+    }
+
+    // Circle is just Bresenham's algorithm for a scan converted circle
+    public void circle(int x0, int y0, int r, Graphics g) {
+        int x,y;
+        float d;
+        x=0;
+        y=r;
+        d=5/4-r;
+        plotpoints(x0,y0,x,y,g);
+
+        while (y>x){
+            if (d<0) {
+                d=d+2*x+3;
+                x++;
+            }
+            else {
+                d=d+2*(x-y)+5;
+                x++;
+                y--;
+            }
+            plotpoints(x0,y0,x,y,g);
+        }
+    }
+
+    // Paint is the main part of the program
+    public void paint(Graphics g) {
+        int xh, yh, xm, ym, xs, ys, s = 0, m = 10, h = 10, xcenter, ycenter;
+        String today;
+
+        currentDate = new Date();
+        SimpleDateFormat formatter = new SimpleDateFormat("s",Locale.getDefault());
+        try {
+            s = Integer.parseInt(formatter.format(currentDate));
+        } catch (NumberFormatException n) {
+            s = 0;
+        }
+        formatter.applyPattern("m");
+        try {
+            m = Integer.parseInt(formatter.format(currentDate));
+        } catch (NumberFormatException n) {
+            m = 10;
+        }    
+        formatter.applyPattern("h");
+        try {
+            h = Integer.parseInt(formatter.format(currentDate));
+        } catch (NumberFormatException n) {
+            h = 10;
+        }
+        formatter.applyPattern("EEE MMM dd HH:mm:ss yyyy");
+        today = formatter.format(currentDate);
+        xcenter=80;
+        ycenter=55;
+    
+    // a= s* pi/2 - pi/2 (to switch 0,0 from 3:00 to 12:00)
+    // x = r(cos a) + xcenter, y = r(sin a) + ycenter
+    
+        xs = (int)(Math.cos(s * 3.14f/30 - 3.14f/2) * 45 + xcenter);
+        ys = (int)(Math.sin(s * 3.14f/30 - 3.14f/2) * 45 + ycenter);
+        xm = (int)(Math.cos(m * 3.14f/30 - 3.14f/2) * 40 + xcenter);
+        ym = (int)(Math.sin(m * 3.14f/30 - 3.14f/2) * 40 + ycenter);
+        xh = (int)(Math.cos((h*30 + m/2) * 3.14f/180 - 3.14f/2) * 30 + xcenter);
+        yh = (int)(Math.sin((h*30 + m/2) * 3.14f/180 - 3.14f/2) * 30 + ycenter);
+    
+    // Draw the circle and numbers
+    
+        g.setFont(clockFaceFont);
+        g.setColor(handColor);
+        circle(xcenter,ycenter,50,g);
+        g.setColor(numberColor);
+        g.drawString("9",xcenter-45,ycenter+3); 
+        g.drawString("3",xcenter+40,ycenter+3);
+        g.drawString("12",xcenter-5,ycenter-37);
+        g.drawString("6",xcenter-3,ycenter+45);
+
+    // Erase if necessary, and redraw
+    
+        g.setColor(getBackground());
+        if (xs != lastxs || ys != lastys) {
+            g.drawLine(xcenter, ycenter, lastxs, lastys);
+            g.drawString(lastdate, 5, 125);
+        }
+        if (xm != lastxm || ym != lastym) {
+            g.drawLine(xcenter, ycenter-1, lastxm, lastym);
+            g.drawLine(xcenter-1, ycenter, lastxm, lastym); }
+        if (xh != lastxh || yh != lastyh) {
+            g.drawLine(xcenter, ycenter-1, lastxh, lastyh);
+            g.drawLine(xcenter-1, ycenter, lastxh, lastyh); }
+        g.setColor(numberColor);
+        g.drawString("", 5, 125);
+        g.drawString(today, 5, 125);    
+        g.drawLine(xcenter, ycenter, xs, ys);
+        g.setColor(handColor);
+        g.drawLine(xcenter, ycenter-1, xm, ym);
+        g.drawLine(xcenter-1, ycenter, xm, ym);
+        g.drawLine(xcenter, ycenter-1, xh, yh);
+        g.drawLine(xcenter-1, ycenter, xh, yh);
+        lastxs=xs; lastys=ys;
+        lastxm=xm; lastym=ym;
+        lastxh=xh; lastyh=yh;
+        lastdate = today;
+        currentDate=null;
+    }
+
+    public void start() {
+        timer = new Thread(this);
+        timer.start();
+    }
+
+    public void stop() {
+        timer = null;
+    }
+
+    public void run() {
+        Thread me = Thread.currentThread();
+        while (timer == me) {
+            try {
+                Thread.currentThread().sleep(100);
+            } catch (InterruptedException e) {
+            }
+            repaint();
+        }
+    }
+
+    public void update(Graphics g) {
+        paint(g);
+    }
+
+    public String getAppletInfo() {
+        return "Title: A Clock \nAuthor: Rachel Gollub, 1995 \nAn analog clock.";
+    }
+  
+    public String[][] getParameterInfo() {
+        String[][] info = {
+            {"bgcolor", "hexadecimal RGB number", "The background color. Default is the color of your browser."},
+            {"fgcolor1", "hexadecimal RGB number", "The color of the hands and dial. Default is blue."},
+            {"fgcolor2", "hexadecimal RGB number", "The color of the seconds hand and numbers. Default is dark gray."}
+        };
+        return info;
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/jsp/debug-taglib.tld
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/jsp/debug-taglib.tld	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/jsp/debug-taglib.tld	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="ISO-8859-1" ?>
+<!--
+  Copyright 2004 The Apache Software Foundation
+
+  Licensed 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.
+-->
+<!DOCTYPE taglib
+        PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN"
+	"http://java.sun.com/j2ee/dtd/web-jsptaglibrary_1_2.dtd">
+
+<!-- a tag library descriptor -->
+
+<taglib>
+  <tlib-version>1.0</tlib-version>
+  <jsp-version>1.2</jsp-version>
+  <short-name>debug</short-name>
+  <uri>http://jakarta.apache.org/tomcat/debug-taglib</uri>
+  <description>
+    This tag library defines no tags.  Instead, its purpose is encapsulated
+    in the TagLibraryValidator implementation that simply outputs the XML
+    version of a JSP page to standard output, whenever this tag library is
+    referenced in a "taglib" directive in a JSP page.
+  </description>
+  <validator>
+    <validator-class>validators.DebugValidator</validator-class>
+  </validator>
+
+  <!-- This is a dummy tag solely to satisfy DTD requirements -->  
+  <tag>
+    <name>log</name>
+    <tag-class>examples.LogTag</tag-class>
+    <body-content>TAGDEPENDENT</body-content>
+    <description>
+	Perform a server side action; Log the message.
+    </description>
+    <attribute>
+	<name>toBrowser</name>
+	<required>false</required>
+    </attribute>
+  </tag>
+  
+
+</taglib>

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/jsp/example-taglib.tld
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/jsp/example-taglib.tld	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/jsp/example-taglib.tld	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,82 @@
+<?xml version="1.0" encoding="ISO-8859-1" ?>
+<!--
+  Copyright 2004 The Apache Software Foundation
+
+  Licensed 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.
+-->
+<!DOCTYPE taglib
+        PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN"
+	"http://java.sun.com/j2ee/dtd/web-jsptaglibrary_1_2.dtd">
+
+<taglib>
+
+  <tlib-version>1.0</tlib-version>
+  <jsp-version>1.2</jsp-version>
+  <short-name>simple</short-name>
+  <uri>http://jakarta.apache.org/tomcat/example-taglib</uri>
+  <description>
+	A simple tab library for the examples
+  </description>
+
+  <tag>
+    <name>ShowSource</name>
+    <tag-class>examples.ShowSource</tag-class>
+    <description> Display JSP sources </description>
+    <attribute>
+       <name>jspFile</name>
+       <required>true</required>
+       <rtexprvalue>true</rtexprvalue>
+    </attribute>
+  </tag>       
+
+  <!-- A simple Tag -->
+  <!-- foo tag -->
+  <tag>
+    <name>foo</name>
+    <tag-class>examples.FooTag</tag-class>
+    <tei-class>examples.FooTagExtraInfo</tei-class>
+    <body-content>JSP</body-content>
+    <description>
+	Perform a server side action; uses 3 mandatory attributes
+    </description>
+
+    <attribute>
+      <name>att1</name>
+      <required>true</required>
+    </attribute>
+    <attribute>
+      <name>att2</name>
+      <required>true</required>
+    </attribute>
+    <attribute>
+      <name>att3</name>
+      <required>true</required>
+    </attribute>
+  </tag>
+
+  <!-- Another simple tag -->
+  <!-- log tag -->
+  <tag>
+    <name>log</name>
+    <tag-class>examples.LogTag</tag-class>
+    <body-content>TAGDEPENDENT</body-content>
+    <description>
+	Perform a server side action; Log the message.
+    </description>
+    <attribute>
+	<name>toBrowser</name>
+	<required>false</required>
+    </attribute>
+  </tag>
+  
+</taglib>

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/jsp2/jsp2-example-taglib.tld
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/jsp2/jsp2-example-taglib.tld	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/jsp2/jsp2-example-taglib.tld	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,123 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Copyright 2004 The Apache Software Foundation
+
+  Licensed 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.
+-->
+
+<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">
+    <description>A tag library exercising SimpleTag handlers.</description>
+    <tlib-version>1.0</tlib-version>
+    <short-name>SimpleTagLibrary</short-name>
+    <uri>/SimpleTagLibrary</uri>
+    <tag>
+	<description>Outputs Hello, World</description>
+        <name>helloWorld</name>
+	<tag-class>jsp2.examples.simpletag.HelloWorldSimpleTag</tag-class>
+	<body-content>empty</body-content>
+    </tag>
+    <tag>
+        <description>Repeats the body of the tag 'num' times</description>
+        <name>repeat</name>
+        <tag-class>jsp2.examples.simpletag.RepeatSimpleTag</tag-class>
+        <body-content>scriptless</body-content>
+        <variable>
+            <description>Current invocation count (1 to num)</description>
+            <name-given>count</name-given>
+        </variable>
+        <attribute>
+            <name>num</name>
+            <required>true</required>
+            <rtexprvalue>true</rtexprvalue>
+        </attribute>
+    </tag>
+    <tag>
+	<description>Populates the page context with a BookBean</description>
+        <name>findBook</name>
+	<tag-class>jsp2.examples.simpletag.FindBookSimpleTag</tag-class>
+	<body-content>empty</body-content>
+	<attribute>
+	    <name>var</name>
+	    <required>true</required>
+	    <rtexprvalue>true</rtexprvalue>
+	</attribute>
+    </tag>
+    <tag>
+        <description>
+            Takes 3 fragments and invokes them in a random order
+        </description>
+        <name>shuffle</name>
+        <tag-class>jsp2.examples.simpletag.ShuffleSimpleTag</tag-class>
+        <body-content>empty</body-content>
+        <attribute>
+            <name>fragment1</name>
+            <required>true</required>
+	    <fragment>true</fragment>
+        </attribute>
+        <attribute>
+            <name>fragment2</name>
+            <required>true</required>
+	    <fragment>true</fragment>
+        </attribute>
+        <attribute>
+            <name>fragment3</name>
+            <required>true</required>
+	    <fragment>true</fragment>
+        </attribute>
+    </tag>
+    <tag>
+        <description>Outputs a colored tile</description>
+        <name>tile</name>
+        <tag-class>jsp2.examples.simpletag.TileSimpleTag</tag-class>
+        <body-content>empty</body-content>
+        <attribute>
+            <name>color</name>
+            <required>true</required>
+        </attribute>
+        <attribute>
+            <name>label</name>
+            <required>true</required>
+        </attribute>
+    </tag>
+    <tag>
+	<description>
+	  Tag that echoes all its attributes and body content
+	</description>
+	<name>echoAttributes</name>
+	<tag-class>jsp2.examples.simpletag.EchoAttributesTag</tag-class>
+	<body-content>empty</body-content>
+	<dynamic-attributes>true</dynamic-attributes>
+    </tag>
+    <function>
+        <description>Reverses the characters in the given String</description>
+        <name>reverse</name>
+	<function-class>jsp2.examples.el.Functions</function-class>
+	<function-signature>java.lang.String reverse( java.lang.String )</function-signature>
+    </function>
+    <function>
+        <description>Counts the number of vowels (a,e,i,o,u) in the given String</description>
+        <name>countVowels</name>
+	<function-class>jsp2.examples.el.Functions</function-class>
+	<function-signature>java.lang.String numVowels( java.lang.String )</function-signature>
+    </function>
+    <function>
+	<description>Converts the string to all caps</description>
+        <name>caps</name>
+	<function-class>jsp2.examples.el.Functions</function-class>
+	<function-signature>java.lang.String caps( java.lang.String )</function-signature>
+    </function>
+</taglib>
+

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/lib/jstl.jar
===================================================================
(Binary files differ)


Property changes on: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/lib/jstl.jar
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/lib/standard.jar
===================================================================
(Binary files differ)


Property changes on: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/lib/standard.jar
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/tags/displayProducts.tag
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/tags/displayProducts.tag	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/tags/displayProducts.tag	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,54 @@
+<!--
+  Copyright 2004 The Apache Software Foundation
+
+  Licensed 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.
+-->
+<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
+<%@ attribute name="normalPrice" fragment="true" %>
+<%@ attribute name="onSale" fragment="true" %>
+<%@ variable name-given="name" %>
+<%@ variable name-given="price" %>
+<%@ variable name-given="origPrice" %>
+<%@ variable name-given="salePrice" %>
+
+<table border="1">
+  <tr>
+    <td> 
+      <c:set var="name" value="Hand-held Color PDA"/>
+      <c:set var="price" value="$298.86"/>
+      <jsp:invoke fragment="normalPrice"/>
+    </td>
+    <td> 
+      <c:set var="name" value="4-Pack 150 Watt Light Bulbs"/>
+      <c:set var="origPrice" value="$2.98"/>
+      <c:set var="salePrice" value="$2.32"/>
+      <jsp:invoke fragment="onSale"/>
+    </td>
+    <td> 
+      <c:set var="name" value="Digital Cellular Phone"/>
+      <c:set var="price" value="$68.74"/>
+      <jsp:invoke fragment="normalPrice"/>
+    </td>
+    <td> 
+      <c:set var="name" value="Baby Grand Piano"/>
+      <c:set var="price" value="$10,800.00"/>
+      <jsp:invoke fragment="normalPrice"/>
+    </td>
+    <td> 
+      <c:set var="name" value="Luxury Car w/ Leather Seats"/>
+      <c:set var="origPrice" value="$23,980.00"/>
+      <c:set var="salePrice" value="$21,070.00"/>
+      <jsp:invoke fragment="onSale"/>
+    </td>
+  </tr>
+</table>

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/tags/helloWorld.tag
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/tags/helloWorld.tag	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/tags/helloWorld.tag	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,16 @@
+<!--
+  Copyright 2004 The Apache Software Foundation
+
+  Licensed 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.
+-->
+Hello, world!

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/tags/panel.tag
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/tags/panel.tag	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/tags/panel.tag	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,28 @@
+<!--
+  Copyright 2004 The Apache Software Foundation
+
+  Licensed 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.
+-->
+<%@ attribute name="color" %>
+<%@ attribute name="bgcolor" %>
+<%@ attribute name="title" %>
+<table border="1" bgcolor="${color}">
+  <tr>
+    <td><b>${title}</b></td>
+  </tr>
+  <tr>
+    <td bgcolor="${bgcolor}">
+      <jsp:doBody/>
+    </td>
+  </tr>
+</table>

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/tags/xhtmlbasic.tag
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/tags/xhtmlbasic.tag	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/tags/xhtmlbasic.tag	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,20 @@
+<!--
+  Copyright 2004 The Apache Software Foundation
+
+  Licensed 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.
+-->
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML Basic 1.0//EN"
+"http://www.w3.org/TR/xhtml-basic/xhtml-basic10.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<jsp:doBody/>
+</html>

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/web.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/web.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/WEB-INF/web.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,258 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!--
+  Copyright 2004 The Apache Software Foundation
+
+  Licensed 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.
+-->
+
+<web-app 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-app_2_4.xsd"
+    version="2.4">
+
+    <description>
+      JSP 2.0 Examples.
+    </description>
+    <display-name>JSP 2.0 Examples</display-name>
+
+
+    <!-- Define servlet-mapped and path-mapped example filters -->
+    <filter>
+        <filter-name>Servlet Mapped Filter</filter-name>
+        <filter-class>filters.ExampleFilter</filter-class>
+	<init-param>
+	    <param-name>attribute</param-name>
+	    <param-value>filters.ExampleFilter.SERVLET_MAPPED</param-value>
+	</init-param>
+    </filter>
+    <filter>
+        <filter-name>Path Mapped Filter</filter-name>
+        <filter-class>filters.ExampleFilter</filter-class>
+	<init-param>
+	    <param-name>attribute</param-name>
+	    <param-value>filters.ExampleFilter.PATH_MAPPED</param-value>
+	</init-param>
+    </filter>
+    <filter>
+        <filter-name>Request Dumper Filter</filter-name>
+        <filter-class>filters.RequestDumperFilter</filter-class>
+    </filter>
+
+    <!-- Example filter to set character encoding on each request -->
+    <filter>
+        <filter-name>Set Character Encoding</filter-name>
+        <filter-class>filters.SetCharacterEncodingFilter</filter-class>
+        <init-param>
+            <param-name>encoding</param-name>
+            <param-value>EUC_JP</param-value>
+        </init-param>
+    </filter>
+
+    <filter>
+        <filter-name>Compression Filter</filter-name>
+        <filter-class>compressionFilters.CompressionFilter</filter-class>
+
+        <init-param>
+          <param-name>compressionThreshold</param-name>
+          <param-value>10</param-value>
+        </init-param>
+        <init-param>
+          <param-name>debug</param-name>
+          <param-value>0</param-value>
+        </init-param>
+    </filter>
+
+<!-- Example filter mapping to apply the "Set Character Encoding" filter
+     to *all* requests processed by this web application -->
+<!--
+    <filter-mapping>
+        <filter-name>Set Character Encoding</filter-name>
+        <url-pattern>/*</url-pattern>
+    </filter-mapping>
+-->
+
+<!--
+    <filter-mapping>
+      <filter-name>Compression Filter</filter-name>
+      <url-pattern>/CompressionTest</url-pattern>
+    </filter-mapping>
+-->
+
+<!--
+    <filter-mapping>
+        <filter-name>Request Dumper Filter</filter-name>
+        <url-pattern>/*</url-pattern>
+    </filter-mapping>
+-->
+
+    <!-- Define example application events listeners -->
+    <listener>
+        <listener-class>listeners.ContextListener</listener-class>
+    </listener>
+    <listener>
+        <listener-class>listeners.SessionListener</listener-class>
+    </listener>
+
+    <!-- Define servlets that are included in the example application -->
+
+    <servlet>
+      <servlet-name>
+          servletToJsp
+      </servlet-name>
+      <servlet-class>
+          servletToJsp
+      </servlet-class>
+    </servlet>
+
+    <servlet>
+        <servlet-name>
+            CompressionFilterTestServlet
+        </servlet-name>
+        <servlet-class>
+            compressionFilters.CompressionFilterTestServlet
+        </servlet-class>
+    </servlet>
+
+    <servlet-mapping>
+        <servlet-name>
+            CompressionFilterTestServlet
+        </servlet-name>
+        <url-pattern>
+            /CompressionTest
+        </url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>
+            servletToJsp
+        </servlet-name>
+        <url-pattern>
+            /servletToJsp
+        </url-pattern>
+    </servlet-mapping>
+
+    <jsp-config>
+        <taglib>
+	    <taglib-uri>
+	       http://jakarta.apache.org/tomcat/debug-taglib
+	    </taglib-uri>
+	    <taglib-location>
+	       /WEB-INF/jsp/debug-taglib.tld
+	    </taglib-location>
+	</taglib>
+
+	<taglib>
+	    <taglib-uri>
+	       http://jakarta.apache.org/tomcat/examples-taglib
+	    </taglib-uri>
+	    <taglib-location>
+	       /WEB-INF/jsp/example-taglib.tld
+	    </taglib-location>
+	</taglib>
+
+	<taglib>
+	    <taglib-uri>
+	       http://jakarta.apache.org/tomcat/jsp2-example-taglib
+	    </taglib-uri>
+	    <taglib-location>
+	       /WEB-INF/jsp2/jsp2-example-taglib.tld
+	    </taglib-location>
+	</taglib>
+
+	<jsp-property-group>
+	    <description>
+		Special property group for JSP Configuration JSP example.
+	    </description>
+	    <display-name>JSPConfiguration</display-name>
+	    <url-pattern>/jsp2/misc/config.jsp</url-pattern>
+	    <el-ignored>true</el-ignored>
+	    <page-encoding>ISO-8859-1</page-encoding>
+	    <scripting-invalid>true</scripting-invalid>
+	    <include-prelude>/jsp2/misc/prelude.jspf</include-prelude>
+	    <include-coda>/jsp2/misc/coda.jspf</include-coda>
+	</jsp-property-group>
+    </jsp-config>
+    
+   <security-constraint>
+      <display-name>Example Security Constraint</display-name>
+      <web-resource-collection>
+         <web-resource-name>Protected Area</web-resource-name>
+	 <!-- Define the context-relative URL(s) to be protected -->
+         <url-pattern>/security/protected/*</url-pattern>
+	 <!-- If you list http methods, only those methods are protected -->
+	 <http-method>DELETE</http-method>
+         <http-method>GET</http-method>
+         <http-method>POST</http-method>
+	 <http-method>PUT</http-method>
+      </web-resource-collection>
+      <auth-constraint>
+         <!-- Anyone with one of the listed roles may access this area -->
+         <role-name>tomcat</role-name>
+	 <role-name>role1</role-name>
+      </auth-constraint>
+    </security-constraint>
+
+    <!-- Default login configuration uses form-based authentication -->
+    <login-config>
+      <auth-method>FORM</auth-method>
+      <realm-name>Example Form-Based Authentication Area</realm-name>
+      <form-login-config>
+        <form-login-page>/security/protected/login.jsp</form-login-page>
+        <form-error-page>/security/protected/error.jsp</form-error-page>
+      </form-login-config>
+    </login-config>
+        
+    <!-- Security roles referenced by this web application -->
+    <security-role>
+      <role-name>role1</role-name>
+    </security-role>
+    <security-role>
+      <role-name>tomcat</role-name>
+    </security-role>    
+
+    <!-- Environment entry examples -->
+    <!--env-entry>
+      <env-entry-description>
+         The maximum number of tax exemptions allowed to be set.
+      </env-entry-description>
+      <env-entry-name>maxExemptions</env-entry-name>
+      <env-entry-type>java.lang.Integer</env-entry-type>
+      <env-entry-value>15</env-entry-value>
+    </env-entry-->
+    <env-entry>
+      <env-entry-name>minExemptions</env-entry-name>
+      <env-entry-type>java.lang.Integer</env-entry-type>
+      <env-entry-value>1</env-entry-value>
+    </env-entry>
+    <env-entry>
+      <env-entry-name>foo/name1</env-entry-name>
+      <env-entry-type>java.lang.String</env-entry-type>
+      <env-entry-value>value1</env-entry-value>
+    </env-entry>
+    <env-entry>
+      <env-entry-name>foo/bar/name2</env-entry-name>
+      <env-entry-type>java.lang.Boolean</env-entry-type>
+      <env-entry-value>true</env-entry-value>
+    </env-entry>
+    <env-entry>
+      <env-entry-name>name3</env-entry-name>
+      <env-entry-type>java.lang.Integer</env-entry-type>
+      <env-entry-value>1</env-entry-value>
+    </env-entry>
+    <env-entry>
+      <env-entry-name>foo/name4</env-entry-name>
+      <env-entry-type>java.lang.Integer</env-entry-type>
+      <env-entry-value>10</env-entry-value>
+    </env-entry>
+
+</web-app>

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/cal/cal1.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/cal/cal1.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/cal/cal1.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,94 @@
+<HTML>
+<!--
+  Copyright 2004 The Apache Software Foundation
+
+  Licensed 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><TITLE> 
+	Calendar: A JSP APPLICATION
+</TITLE></HEAD>
+
+
+<BODY BGCOLOR="white">
+
+<%@ page language="java" import="cal.*" %>
+<jsp:useBean id="table" scope="session" class="cal.TableBean" />
+
+<%
+	table.processRequest(request);
+	if (table.getProcessError() == false) {
+%>
+
+<!-- html table goes here -->
+<CENTER>
+<TABLE WIDTH=60% BGCOLOR=yellow CELLPADDING=15>
+<TR>
+<TD ALIGN=CENTER> <A HREF=cal1.jsp?date=prev> prev </A>
+<TD ALIGN=CENTER> Calendar:<%= table.getDate() %></TD>
+<TD ALIGN=CENTER> <A HREF=cal1.jsp?date=next> next </A>
+</TR>
+</TABLE>
+
+<!-- the main table -->
+<TABLE WIDTH=60% BGCOLOR=lightblue BORDER=1 CELLPADDING=10>
+<TR>
+<TH> Time </TH>
+<TH> Appointment </TH>
+</TR>
+<FORM METHOD=POST ACTION=cal1.jsp>
+<%
+	for(int i=0; i<table.getEntries().getRows(); i++) {
+	   cal.Entry entr = table.getEntries().getEntry(i);	
+%>
+	<TR>
+	<TD> 
+	<A HREF=cal2.jsp?time=<%= entr.getHour() %>>
+		<%= entr.getHour() %> </A>
+	</TD>
+	<TD BGCOLOR=<%= entr.getColor() %>>
+	<% out.print(util.HTMLFilter.filter(entr.getDescription())); %>
+	</TD> 
+	</TR>
+<%
+	}
+%>
+</FORM>
+</TABLE>
+<BR>
+
+<!-- footer -->
+<TABLE WIDTH=60% BGCOLOR=yellow CELLPADDING=15>
+<TR>
+<TD ALIGN=CENTER>  <% out.print(util.HTMLFilter.filter(table.getName())); %> : 
+		     <% out.print(util.HTMLFilter.filter(table.getEmail())); %> </TD>
+</TR>
+</TABLE>
+</CENTER>
+
+<%
+	} else {
+%>
+<font size=5>
+	You must enter your name and email address correctly.
+</font>
+<%
+	}
+%>
+
+
+</BODY>
+</HTML>
+
+
+
+

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/cal/cal2.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/cal/cal2.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/cal/cal2.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,44 @@
+<HTML>
+<!--
+  Copyright 2004 The Apache Software Foundation
+
+  Licensed 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><TITLE> 
+	Calendar: A JSP APPLICATION
+</TITLE></HEAD>
+
+
+<BODY BGCOLOR="white">
+<jsp:useBean id="table" scope="session" class="cal.TableBean" />
+
+<% 
+	String time = request.getParameter ("time");
+%>
+
+<FONT SIZE=5> Please add the following event:
+<BR> <h3> Date <%= table.getDate() %>
+<BR> Time <%= util.HTMLFilter.filter(time) %> </h3>
+</FONT>
+<FORM METHOD=POST ACTION=cal1.jsp>
+<BR> 
+<BR> <INPUT NAME="date" TYPE=HIDDEN VALUE="current">
+<BR> <INPUT NAME="time" TYPE=HIDDEN VALUE=<%= util.HTMLFilter.filter(time) %>
+<BR> <h2> Description of the event <INPUT NAME="description" TYPE=TEXT SIZE=20> </h2>
+<BR> <INPUT TYPE=SUBMIT VALUE="submit">
+</FORM>
+
+</BODY>
+</HTML>
+

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/cal/calendar.html
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/cal/calendar.html	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/cal/calendar.html	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,42 @@
+<html>
+<!--
+  Copyright 2004 The Apache Software Foundation
+
+  Licensed 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>
+<title>Untitled Document</title>
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+</head>
+
+<body bgcolor="#FFFFFF">
+<p><font color="#0000FF"><a href="login.html"><img src="../images/execute.gif" align="right" border="0"></a><a href="../index.html"><img src="../images/return.gif" width="24" height="24" align="right" border="0"></a></font></p>
+
+<h2> Source Code for Calendar Example. <br>
+<h3><a href="cal1.jsp.html">cal1.jsp<font color="#0000FF"></a>
+  </font> </h3>
+<h3><a href="cal2.jsp.html">cal2.jsp<font color="#0000FF"></a>
+  </font> </h3>
+
+<br>
+<h2> Beans.
+<h3><a href="TableBean.java.html">TableBean<font color="#0000FF"></a>
+  </font> </h3>
+<h3><a href="Entries.java.html">Entries<font color="#0000FF"></a>
+  </font> </h3>
+<h3><a href="Entry.java.html">Entry<font color="#0000FF"></a>
+  </font> </h3>
+
+</body>
+</html>

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/cal/login.html
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/cal/login.html	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/cal/login.html	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,46 @@
+<html>
+<!--
+  Copyright 2004 The Apache Software Foundation
+
+  Licensed 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>
+	<title> Login page for the calendar. </title>
+</head>
+
+<body bgcolor="white">
+<center>
+
+	<font size=7 color="red"> Please Enter the following information: </font>
+
+<br>
+	<form method=GET action=cal1.jsp>
+
+		<font size=5> Name <input type=text name="name" size=20>
+		</font>
+		<br>
+		<font size=5> Email <input type=text name="email" size=20>
+		</font>
+		<br>
+		<input type=submit name=action value="Submit">
+
+	</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>
+
+</center>
+</body>
+</html>

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/checkbox/CheckTest.html
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/checkbox/CheckTest.html	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/checkbox/CheckTest.html	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,55 @@
+<HTML>
+<!--
+  Copyright 2004 The Apache Software Foundation
+
+  Licensed 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>
+<title>
+checkbox.CheckTest Bean Properties
+</title>
+<BODY BGCOLOR="white">
+<H2>
+checkbox.CheckTest Bean Properties
+</H2>
+<HR>
+<DL>
+<DT>public class <B>CheckTest</B><DT>extends Object</DL>
+
+<P>
+<HR>
+
+<P>
+
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0">
+<TR BGCOLOR="#EEEEFF">
+<TD COLSPAN=3><FONT SIZE="+2">
+<B>Properties Summary</B></FONT></TD>
+</TR>
+<TR BGCOLOR="white">
+<td align="right" valign="top" width="1%">
+<FONT SIZE="-1">
+String
+</FONT></TD>
+<TD><B>CheckTest:fruit</B>
+<BR>
+       </TD>
+<td width="1%">
+<FONT SIZE="-1">
+Multi
+</FONT></TD>
+</TABLE>
+<HR>
+</BODY>
+</HTML>

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/checkbox/check.html
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/checkbox/check.html	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/checkbox/check.html	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,37 @@
+<HTML>
+<!--
+  Copyright 2004 The Apache Software Foundation
+
+  Licensed 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.
+-->
+
+<BODY bgcolor="white">
+
+
+<FORM TYPE=POST ACTION=checkresult.jsp>
+<BR>
+<font size=5 color="red">
+Check all Favorite fruits: <br>
+
+<input TYPE=checkbox name=fruit VALUE=apples> Apples <BR>
+<input TYPE=checkbox name=fruit VALUE=grapes> Grapes <BR>
+<input TYPE=checkbox name=fruit VALUE=oranges> Oranges <BR>
+<input TYPE=checkbox name=fruit VALUE=melons> Melons <BR>
+
+
+<br> <INPUT TYPE=submit name=submit Value="Submit">
+
+</font>
+</FORM>
+</BODY>
+</HTML>

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/checkbox/checkresult.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/checkbox/checkresult.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/checkbox/checkresult.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,63 @@
+<html>
+<!--
+  Copyright 2004 The Apache Software Foundation
+
+  Licensed 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.
+-->
+
+<body bgcolor="white">
+<font size=5 color="red">
+<%! String[] fruits; %>
+<jsp:useBean id="foo" scope="page" class="checkbox.CheckTest" />
+
+<jsp:setProperty name="foo" property="fruit" param="fruit" />
+<hr>
+The checked fruits (got using request) are: <br>
+<% 
+	fruits = request.getParameterValues("fruit");
+%>
+<ul>
+<%
+    if (fruits != null) {
+	  for (int i = 0; i < fruits.length; i++) {
+%>
+<li>
+<%
+	      out.println (util.HTMLFilter.filter(fruits[i]));
+	  }
+	} else out.println ("none selected");
+%>
+</ul>
+<br>
+<hr>
+
+The checked fruits (got using beans) are <br>
+
+<% 
+		fruits = foo.getFruit();
+%>
+<ul>
+<%
+    if (!fruits[0].equals("1")) {
+	  for (int i = 0; i < fruits.length; i++) {
+%>
+<li>
+<%
+		  out.println (util.HTMLFilter.filter(fruits[i]));
+	  }
+	} else out.println ("none selected");
+%>
+</ul>
+</font>
+</body>
+</html>

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/checkbox/cresult.html
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/checkbox/cresult.html	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/checkbox/cresult.html	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,33 @@
+<html>
+<!--
+  Copyright 2004 The Apache Software Foundation
+
+  Licensed 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>
+<title>Untitled Document</title>
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+</head>
+
+<body bgcolor="#FFFFFF">
+<p><font color="#0000FF"><a href="check.html"><img src="../images/execute.gif" align="right" border="0"></a><a href="../index.html"><img src="../images/return.gif" width="24" height="24" align="right" border="0"></a></font></p>
+
+<h3><a href="checkresult.jsp.html">Source Code for Checkbox Example<font color="#0000FF"></a>
+  </font> </h3>
+
+<h3><a href="CheckTest.html">Property Sheet for CheckTest
+<font color="#0000FF"></a> </font> </h3>
+
+</body>
+</html>

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/colors/ColorGameBean.html
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/colors/ColorGameBean.html	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/colors/ColorGameBean.html	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,115 @@
+<HTML>
+<!--
+  Copyright 2004 The Apache Software Foundation
+
+  Licensed 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>
+<title>
+colors.ColorGameBean Bean Properties
+</title>
+<BODY BGCOLOR="white">
+<H2>
+colors.ColorGameBean Bean Properties
+</H2>
+<HR>
+<DL>
+<DT>public class <B>ColorGameBean</B><DT>extends Object</DL>
+
+<P>
+<HR>
+
+<P>
+
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0">
+<TR BGCOLOR="#EEEEFF">
+<TD COLSPAN=3><FONT SIZE="+2">
+<B>Properties Summary</B></FONT></TD>
+</TR>
+<TR BGCOLOR="white">
+<td align="right" valign="top" width="1%">
+<FONT SIZE="-1">
+String
+</FONT></TD>
+<TD><B>ColorGameBean:color2</B>
+<BR>
+       </TD>
+<td width="1%">
+<FONT SIZE="-1">
+Single
+</FONT></TD>
+<TR BGCOLOR="white">
+<td align="right" valign="top" width="1%">
+<FONT SIZE="-1">
+String
+</FONT></TD>
+<TD><B>ColorGameBean:color1</B>
+<BR>
+       </TD>
+<td width="1%">
+<FONT SIZE="-1">
+Single
+</FONT></TD>
+<TR BGCOLOR="white">
+<td align="right" valign="top" width="1%">
+<FONT SIZE="-1">
+int
+</FONT></TD>
+<TD><B>ColorGameBean:attempts</B>
+<BR>
+       </TD>
+<td width="1%">
+<FONT SIZE="-1">
+Single
+</FONT></TD>
+<TR BGCOLOR="white">
+<td align="right" valign="top" width="1%">
+<FONT SIZE="-1">
+boolean
+</FONT></TD>
+<TD><B>ColorGameBean:hint</B>
+<BR>
+       </TD>
+<td width="1%">
+<FONT SIZE="-1">
+Single
+</FONT></TD>
+<TR BGCOLOR="white">
+<td align="right" valign="top" width="1%">
+<FONT SIZE="-1">
+boolean
+</FONT></TD>
+<TD><B>ColorGameBean:success</B>
+<BR>
+       </TD>
+<td width="1%">
+<FONT SIZE="-1">
+Single
+</FONT></TD>
+<TR BGCOLOR="white">
+<td align="right" valign="top" width="1%">
+<FONT SIZE="-1">
+boolean
+</FONT></TD>
+<TD><B>ColorGameBean:hintTaken</B>
+<BR>
+       </TD>
+<td width="1%">
+<FONT SIZE="-1">
+Single
+</FONT></TD>
+</TABLE>
+<HR>
+</BODY>
+</HTML>

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/colors/clr.html
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/colors/clr.html	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/colors/clr.html	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,33 @@
+<html>
+<!--
+  Copyright 2004 The Apache Software Foundation
+
+  Licensed 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>
+<title>Untitled Document</title>
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+</head>
+
+<body bgcolor="#FFFFFF">
+<p><font color="#0000FF"><a href="colors.html"><img src="../images/execute.gif" align="right" border="0"></a><a href="../index.html"><img src="../images/return.gif" width="24" height="24" align="right" border="0"></a></font></p>
+
+<h3><a href="colrs.jsp.html">Source Code for Color Example<font color="#0000FF"></a>
+  </font> </h3>
+
+<h3><a href="ColorGameBean.html">Property Sheet for ColorGameBean
+<font color="#0000FF"></a> </font> </h3>
+
+</body>
+</html>

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/colors/colors.html
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/colors/colors.html	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/colors/colors.html	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,46 @@
+<html>
+<!--
+  Copyright 2004 The Apache Software Foundation
+
+  Licensed 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.
+-->
+
+<body bgcolor= white>
+<font size=6 color=red>
+
+<hr>
+This web page is an example using JSP and BEANs. 
+<p>
+Guess my favorite two colors 
+
+<p> If you fail to guess both of them - you get yellow on red.
+
+<p> If you guess one of them right, either your foreground or 
+    your background will change to the color that was guessed right.
+
+<p> Guess them both right and your browser foreground/background 
+    will change to my two favorite colors to display this page.
+
+<hr>
+<form method=GET action=colrs.jsp>
+Color #1: <input type=text name= color1 size=16>
+<br>
+Color #2: <input type=text name= color2 size=16>
+<p>
+<input type=submit name=action value="Submit">
+<input type=submit name=action value="Hint">
+</form>
+
+</font>
+</body>
+</html>

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/colors/colrs.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/colors/colrs.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/colors/colrs.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,69 @@
+<html>
+<!--
+  Copyright 2004 The Apache Software Foundation
+
+  Licensed 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.
+-->
+
+<jsp:useBean id="cb" scope="session" class="colors.ColorGameBean" />
+<jsp:setProperty name="cb" property="*" />
+
+<%
+	cb.processRequest(request);
+%>
+
+<body bgcolor=<%= cb.getColor1() %>>
+<font size=6 color=<%= cb.getColor2() %>>
+<p>
+
+<% if (cb.getHint()==true) { %>
+	
+	<p> Hint #1: Vampires prey at night!
+	<p>  <p> Hint #2: Nancy without the n.
+
+<% } %>
+
+<% if  (cb.getSuccess()==true) { %>
+
+    <p> CONGRATULATIONS!!
+	<% if  (cb.getHintTaken()==true) { %>
+    
+        <p> ( although I know you cheated and peeked into the hints)
+
+	<% } %>
+
+<% } %>
+
+<p> Total attempts so far: <%= cb.getAttempts() %>
+<p>
+
+<p>
+
+<form method=POST action=colrs.jsp>
+
+Color #1: <input type=text name= color1 size=16>
+
+<br>
+
+Color #2: <input type=text name= color2 size=16>
+
+<p>
+
+<input type=submit name=action value="Submit">
+<input type=submit name=action value="Hint">
+
+</form>
+
+</font>
+</body>
+</html>

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/dates/date.html
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/dates/date.html	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/dates/date.html	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,30 @@
+<html>
+<!--
+  Copyright 2004 The Apache Software Foundation
+
+  Licensed 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>
+<title>Untitled Document</title>
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+</head>
+
+<body bgcolor="#FFFFFF">
+<p><font color="#0000FF"><a href="date.jsp"><img src="../images/execute.gif" align="right" border="0"></a><a href="../index.html"><img src="../images/return.gif" width="24" height="24" align="right" border="0"></a></font></p>
+
+<h3><a href="date.jsp.html">Source Code for Date Example<font color="#0000FF"></a>
+  </font> </h3>
+
+</body>
+</html>

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/dates/date.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/dates/date.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/dates/date.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,40 @@
+<html>
+<!--
+  Copyright 2004 The Apache Software Foundation
+
+  Licensed 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 session="false"%>
+
+<body bgcolor="white">
+<jsp:useBean id='clock' scope='page' class='dates.JspCalendar' type="dates.JspCalendar" />
+
+<font size=4>
+<ul>
+<li>	Day of month: is  <jsp:getProperty name="clock" property="dayOfMonth"/>
+<li>	Year: is  <jsp:getProperty name="clock" property="year"/>
+<li>	Month: is  <jsp:getProperty name="clock" property="month"/>
+<li>	Time: is  <jsp:getProperty name="clock" property="time"/>
+<li>	Date: is  <jsp:getProperty name="clock" property="date"/>
+<li>	Day: is  <jsp:getProperty name="clock" property="day"/>
+<li>	Day Of Year: is  <jsp:getProperty name="clock" property="dayOfYear"/>
+<li>	Week Of Year: is  <jsp:getProperty name="clock" property="weekOfYear"/>
+<li>	era: is  <jsp:getProperty name="clock" property="era"/>
+<li>	DST Offset: is  <jsp:getProperty name="clock" property="DSTOffset"/>
+<li>	Zone Offset: is  <jsp:getProperty name="clock" property="zoneOffset"/>
+</ul>
+</font>
+
+</body>
+</html>

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/error/er.html
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/error/er.html	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/error/er.html	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,30 @@
+<html>
+<!--
+  Copyright 2004 The Apache Software Foundation
+
+  Licensed 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>
+<title>Untitled Document</title>
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+</head>
+
+<body bgcolor="#FFFFFF">
+<p><font color="#0000FF"><a href="error.html"><img src="../images/execute.gif" align="right" border="0"></a><a href="../index.html"><img src="../images/return.gif" width="24" height="24" align="right" border="0"></a></font></p>
+
+<h3><a href="err.jsp.html">Source Code for Error Example<font color="#0000FF"></a>
+  </font> </h3>
+
+</body>
+</html>

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/error/err.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/error/err.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/error/err.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,43 @@
+<html>
+<!--
+  Copyright 2004 The Apache Software Foundation
+
+  Licensed 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.
+-->
+<body bgcolor="lightblue">
+
+	<%@ page errorPage="errorpge.jsp" %>
+	<jsp:useBean id="foo" scope="request" class="error.Smart" />
+	<% 
+		String name = null;
+
+		if (request.getParameter("name") == null) {
+	%>
+	<%@ include file="/error/error.html" %>
+	<%
+		} else {
+		  foo.setName(request.getParameter("name"));
+		  if (foo.getName().equalsIgnoreCase("integra"))
+		  	name = "acura";
+		  if (name.equalsIgnoreCase("acura")) {
+	%>
+
+	<H1> Yes!!! <a href="http://www.acura.com">Acura</a> is my favorite car.
+
+	<% 
+		  }
+		}	
+	%>	
+</body>
+</html>
+

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/error/error.html
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/error/error.html	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/error/error.html	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,36 @@
+<html>
+<!--
+  Copyright 2004 The Apache Software Foundation
+
+  Licensed 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.
+-->
+
+<body bgcolor="white">
+
+<h1> This example uses <b>errorpage</b> directive </h1>
+<br>
+<h3> Select my favourite car.</h3>
+<form method=get action=err.jsp>
+<!-- <br> Make a guess: -->
+<SELECT NAME="name" SIZE=5>
+<OPTION VALUE="integra"> Acura Integra <BR>
+<OPTION VALUE="bmw328i"> BMW 328I <BR>
+<OPTION VALUE="z3"> BMW Z3 <BR>
+<OPTION VALUE="infiniti"> InfinitiQ3 <BR>
+<OPTION VALUE="audi"> Audi A8 <BR>
+</SELECT>
+<br> <INPUT TYPE=submit name=submit Value="Submit">
+</form>
+
+</body>
+</html>

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/error/errorpge.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/error/errorpge.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/error/errorpge.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,24 @@
+<html>
+<!--
+  Copyright 2004 The Apache Software Foundation
+
+  Licensed 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.
+-->
+
+<body bgcolor="red">
+
+	<%@ page isErrorPage="true" %>
+	<h1> The exception <%= exception.getMessage() %> tells me you
+	     made a wrong choice. 
+</body>
+</html>

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/forward/forward.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/forward/forward.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/forward/forward.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,22 @@
+<html>
+<!--
+  Copyright (c) 1999 The Apache Software Foundation.  All rights 
+  reserved.
+-->
+
+<% 
+   double freeMem = Runtime.getRuntime().freeMemory();
+   double totlMem = Runtime.getRuntime().totalMemory();
+   double percent = freeMem/totlMem;
+   if (percent < 0.5) { 
+%>
+
+<jsp:forward page="/forward/one.jsp"/>
+
+<% } else { %>
+
+<jsp:forward page="two.html"/>
+
+<% } %>
+
+</html>

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/forward/fwd.html
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/forward/fwd.html	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/forward/fwd.html	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,18 @@
+<html>
+<!--
+  Copyright (c) 1999 The Apache Software Foundation.  All rights 
+  reserved.
+-->
+<head>
+<title>Untitled Document</title>
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+</head>
+
+<body bgcolor="#FFFFFF">
+<p><font color="#0000FF"><a href="forward.jsp"><img src="../images/execute.gif" align="right" border="0"></a><a href="../index.html"><img src="../images/return.gif" width="24" height="24" align="right" border="0"></a></font></p>
+
+<h3><a href="forward.jsp.html">Source Code for Forward Example<font color="#0000FF"></a>
+  </font> </h3>
+
+</body>
+</html>

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/forward/one.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/forward/one.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/forward/one.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,11 @@
+<html>
+<!--
+  Copyright (c) 1999 The Apache Software Foundation.  All rights 
+  reserved.
+-->
+
+<body bgcolor="white">
+<font color="red">
+
+VM Memory usage < 50%.
+</html>

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/forward/two.html
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/forward/two.html	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/forward/two.html	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,11 @@
+<html>
+<!--
+  Copyright (c) 1999 The Apache Software Foundation.  All rights 
+  reserved.
+-->
+
+<body bgcolor="white">
+<font color="red">
+
+VM Memory usage > 50%.
+</html>

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/images/code.gif
===================================================================
(Binary files differ)


Property changes on: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/images/code.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/images/execute.gif
===================================================================
(Binary files differ)


Property changes on: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/images/execute.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/images/read.gif
===================================================================
(Binary files differ)


Property changes on: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/images/read.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/images/return.gif
===================================================================
(Binary files differ)


Property changes on: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/images/return.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/include/foo.html
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/include/foo.html	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/include/foo.html	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,16 @@
+<!--
+  Copyright 2004 The Apache Software Foundation
+
+  Licensed 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.
+-->
+To get the current time in ms

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/include/foo.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/include/foo.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/include/foo.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,20 @@
+<!--
+  Copyright 2004 The Apache Software Foundation
+
+  Licensed 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.
+-->
+
+<body bgcolor="white">
+<font color="red">
+
+<%= System.currentTimeMillis() %>

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/include/inc.html
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/include/inc.html	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/include/inc.html	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,29 @@
+<html>
+<!--
+  Copyright 2004 The Apache Software Foundation
+
+  Licensed 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>
+<title>Untitled Document</title>
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+</head>
+
+<body bgcolor="#FFFFFF">
+<p><font color="#0000FF"><a href="include.jsp"><img src="../images/execute.gif" align="right" border="0"></a><a href="../index.html"><img src="../images/return.gif" width="24" height="24" align="right" border="0"></a></font></p>
+
+<h3><a href="include.jsp.html">Source Code for Include Example<font color="#0000FF"></a>
+  </font> </h3>
+
+</body>
+</html>

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/include/include.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/include/include.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/include/include.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,34 @@
+<html>
+<!--
+  Copyright 2004 The Apache Software Foundation
+
+  Licensed 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.
+-->
+
+<body bgcolor="white">
+
+<font color="red">
+
+<%@ page buffer="5kb" autoFlush="false" %>
+
+<p>In place evaluation of another JSP which gives you the current time:
+
+<%@ include file="foo.jsp" %>
+
+<p> <jsp:include page="/include/foo.html" flush="true"/> by including the output of another JSP:
+
+<jsp:include page="foo.jsp" flush="true"/>
+
+:-) 
+
+</html>

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/index.html
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/index.html	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/index.html	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,373 @@
+<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
+<html>
+\<!--
+  Copyright 2004 The Apache Software Foundation
+
+  Licensed 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>
+   <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+   <meta name="GENERATOR" content="Mozilla/4.61 [en] (WinNT; I) [Netscape]">
+   <meta name="Author" content="Anil K. Vijendran">
+   <title>JSP Examples</title>
+<!--
+  Copyright (c) 1999 The Apache Software Foundation.  All rights 
+  reserved.
+-->
+</head>
+<body bgcolor="#FFFFFF">
+<b><font face="Arial, Helvetica, sans-serif"><font size=+2>JSP
+Samples</font></font></b>
+<p>This is a collection of samples demonstrating the usage of different
+parts of the Java Server Pages (JSP) specification.  Both JSP 2.0 and
+JSP 1.2 examples are presented below.
+<p>These examples will only work when these pages are being served by a
+servlet engine; of course, we recommend
+<a href="http://jakarta.apache.org/tomcat/">Tomcat</a>.
+They will not work if you are viewing these pages via a
+"file://..." URL.
+<p>To navigate your way through the examples, the following icons will
+help:
+<br>&nbsp;
+<table BORDER=0 CELLSPACING=5 WIDTH="85%" >
+<tr VALIGN=TOP>
+<td WIDTH="30"><img SRC="images/execute.gif" ></td>
+
+<td>Execute the example</td>
+</tr>
+
+<tr VALIGN=TOP>
+<td WIDTH="30"><img SRC="images/code.gif" height=24 width=24></td>
+
+<td>Look at the source code for the example</td>
+</tr>
+
+<!--<tr VALIGN=TOP>
+<td WIDTH="30"><img SRC="images/read.gif" height=24 width=24></td>
+
+<td>Read more about this feature</td>
+-->
+
+</tr>
+<tr VALIGN=TOP>
+<td WIDTH="30"><img SRC="images/return.gif" height=24 width=24></td>
+
+<td>Return to this screen</td>
+</tr>
+</table>
+
+<p>Tip: For session scoped beans to work, the cookies must be enabled.
+This can be done using browser options.
+<br>&nbsp;
+<br>
+<b><u><font size="+1">JSP 2.0 Examples</font></u></b><br>
+
+<table BORDER=0 CELLSPACING=5 WIDTH="85%" >
+<tr valign=TOP>
+<td><b>Expression Language</b></td>
+</tr>
+
+<tr valign=TOP>
+<td>Basic Arithmetic</td>
+<td valign=TOP width="30%"><a href="jsp2/el/basic-arithmetic.jsp"><img src="images/execute.gif" hspace=4 border=0  align=top></a><a href="jsp2/el/basic-arithmetic.jsp">Execute</a></td>
+
+<td width="30%"><a href="jsp2/el/basic-arithmetic.html"><img SRC="images/code.gif" HSPACE=4 BORDER=0 height=24 width=24 align=TOP></a><a href="jsp2/el/basic-arithmetic.html">Source</a></td>
+</tr>
+
+<tr valign=TOP>
+<td>Basic Comparisons</td>
+<td valign=TOP width="30%"><a href="jsp2/el/basic-comparisons.jsp"><img src="images/execute.gif" hspace=4 border=0  align=top></a><a href="jsp2/el/basic-comparisons.jsp">Execute</a></td>
+
+<td width="30%"><a href="jsp2/el/basic-comparisons.html"><img SRC="images/code.gif" HSPACE=4 BORDER=0 height=24 width=24 align=TOP></a><a href="jsp2/el/basic-comparisons.html">Source</a></td>
+</tr>
+
+<tr valign=TOP>
+<td>Implicit Objects</td>
+<td valign=TOP width="30%"><a href="jsp2/el/implicit-objects.jsp?foo=bar"><img src="images/execute.gif" hspace=4 border=0  align=top></a><a href="jsp2/el/implicit-objects.jsp?foo=bar">Execute</a></td>
+
+<td width="30%"><a href="jsp2/el/implicit-objects.html"><img SRC="images/code.gif" HSPACE=4 BORDER=0 height=24 width=24 align=TOP></a><a href="jsp2/el/implicit-objects.html">Source</a></td>
+</tr>
+<tr valign=TOP>
+
+<td>Functions</td>
+<td valign=TOP width="30%"><a href="jsp2/el/functions.jsp?foo=JSP+2.0"><img src="images/execute.gif" hspace=4 border=0  align=top></a><a href="jsp2/el/functions.jsp?foo=JSP+2.0">Execute</a></td>
+
+<td width="30%"><a href="jsp2/el/functions.html"><img SRC="images/code.gif" HSPACE=4 BORDER=0 height=24 width=24 align=TOP></a><a href="jsp2/el/functions.html">Source</a></td>
+</tr>
+
+<tr valign=TOP>
+<td><br><b>SimpleTag Handlers and JSP Fragments</b></td>
+</tr>
+
+<tr valign=TOP>
+<td>Hello World Tag</td>
+<td valign=TOP width="30%"><a href="jsp2/simpletag/hello.jsp"><img src="images/execute.gif" hspace=4 border=0  align=top></a><a href="jsp2/simpletag/hello.jsp">Execute</a></td>
+
+<td width="30%"><a href="jsp2/simpletag/hello.html"><img SRC="images/code.gif" HSPACE=4 BORDER=0 height=24 width=24 align=TOP></a><a href="jsp2/simpletag/hello.html">Source</a></td>
+</tr>
+
+<tr valign=TOP>
+<td>Repeat Tag</td>
+<td valign=TOP width="30%"><a href="jsp2/simpletag/repeat.jsp"><img src="images/execute.gif" hspace=4 border=0  align=top></a><a href="jsp2/simpletag/repeat.jsp">Execute</a></td>
+
+<td width="30%"><a href="jsp2/simpletag/repeat.html"><img SRC="images/code.gif" HSPACE=4 BORDER=0 height=24 width=24 align=TOP></a><a href="jsp2/simpletag/repeat.html">Source</a></td>
+</tr>
+
+<tr valign=TOP>
+<td>Book Example</td>
+<td valign=TOP width="30%"><a href="jsp2/simpletag/book.jsp"><img src="images/execute.gif" hspace=4 border=0  align=top></a><a href="jsp2/simpletag/book.jsp">Execute</a></td>
+
+<td width="30%"><a href="jsp2/simpletag/book.html"><img SRC="images/code.gif" HSPACE=4 BORDER=0 height=24 width=24 align=TOP></a><a href="jsp2/simpletag/book.html">Source</a></td>
+</tr>
+
+<tr valign=TOP>
+<td><br><b>Tag Files</b></td>
+</tr>
+
+<tr valign=TOP>
+<td>Hello World Tag File</td>
+<td valign=TOP width="30%"><a href="jsp2/tagfiles/hello.jsp"><img src="images/execute.gif" hspace=4 border=0  align=top></a><a href="jsp2/tagfiles/hello.jsp">Execute</a></td>
+
+<td width="30%"><a href="jsp2/tagfiles/hello.html"><img SRC="images/code.gif" HSPACE=4 BORDER=0 height=24 width=24 align=TOP></a><a href="jsp2/tagfiles/hello.html">Source</a></td>
+</tr>
+
+<tr valign=TOP>
+<td>Panel Tag File</td>
+<td valign=TOP width="30%"><a href="jsp2/tagfiles/panel.jsp"><img src="images/execute.gif" hspace=4 border=0  align=top></a><a href="jsp2/tagfiles/panel.jsp">Execute</a></td>
+
+<td width="30%"><a href="jsp2/tagfiles/panel.html"><img SRC="images/code.gif" HSPACE=4 BORDER=0 height=24 width=24 align=TOP></a><a href="jsp2/tagfiles/panel.html">Source</a></td>
+</tr>
+
+<tr valign=TOP>
+<td>Display Products Example</td>
+<td valign=TOP width="30%"><a href="jsp2/tagfiles/products.jsp"><img src="images/execute.gif" hspace=4 border=0  align=top></a><a href="jsp2/tagfiles/products.jsp">Execute</a></td>
+
+<td width="30%"><a href="jsp2/tagfiles/products.html"><img SRC="images/code.gif" HSPACE=4 BORDER=0 height=24 width=24 align=TOP></a><a href="jsp2/tagfiles/products.html">Source</a></td>
+</tr>
+
+<tr valign=TOP>
+<td><br><b>New JSP XML Syntax (.jspx)</b></td>
+</tr>
+
+<tr valign=TOP>
+<td>XHTML Basic Example</td>
+<td valign=TOP width="30%"><a href="jsp2/jspx/basic.jspx"><img src="images/execute.gif" hspace=4 border=0  align=top></a><a href="jsp2/jspx/basic.jspx">Execute</a></td>
+
+<td width="30%"><a href="jsp2/jspx/basic.html"><img SRC="images/code.gif" HSPACE=4 BORDER=0 height=24 width=24 align=TOP></a><a href="jsp2/jspx/basic.html">Source</a></td>
+</tr>
+
+<tr valign=TOP>
+<td>SVG (Scalable Vector Graphics)</td>
+<td valign=TOP width="30%"><a href="jsp2/jspx/svgexample.html"><img src="images/execute.gif" hspace=4 border=0  align=top></a><a href="jsp2/jspx/svgexample.html">Execute</a></td>
+
+<td width="30%"><a href="jsp2/jspx/textRotate.html"><img SRC="images/code.gif" HSPACE=4 BORDER=0 height=24 width=24 align=TOP></a><a href="jsp2/jspx/textRotate.html">Source</a></td>
+</tr>
+
+<tr valign=TOP>
+<td><br><b>Other JSP 2.0 Features</b></td>
+</tr>
+
+<tr valign=TOP>
+<td>&lt;jsp:attribute&gt; and &lt;jsp:body&gt;</td>
+<td valign=TOP width="30%"><a href="jsp2/jspattribute/jspattribute.jsp"><img src="images/execute.gif" hspace=4 border=0  align=top></a><a href="jsp2/jspattribute/jspattribute.jsp">Execute</a></td>
+
+<td width="30%"><a href="jsp2/jspattribute/jspattribute.html"><img SRC="images/code.gif" HSPACE=4 BORDER=0 height=24 width=24 align=TOP></a><a href="jsp2/jspattribute/jspattribute.html">Source</a></td>
+</tr>
+
+<tr valign=TOP>
+<td>Shuffle Example</td>
+<td valign=TOP width="30%"><a href="jsp2/jspattribute/shuffle.jsp"><img src="images/execute.gif" hspace=4 border=0  align=top></a><a href="jsp2/jspattribute/shuffle.jsp">Execute</a></td>
+
+<td width="30%"><a href="jsp2/jspattribute/shuffle.html"><img SRC="images/code.gif" HSPACE=4 BORDER=0 height=24 width=24 align=TOP></a><a href="jsp2/jspattribute/shuffle.html">Source</a></td>
+</tr>
+
+<tr valign=TOP>
+<td>Attributes With Dynamic Names</td>
+<td valign=TOP width="30%"><a href="jsp2/misc/dynamicattrs.jsp"><img src="images/execute.gif" hspace=4 border=0  align=top></a><a href="jsp2/misc/dynamicattrs.jsp">Execute</a></td>
+
+<td width="30%"><a href="jsp2/misc/dynamicattrs.html"><img SRC="images/code.gif" HSPACE=4 BORDER=0 height=24 width=24 align=TOP></a><a href="jsp2/misc/dynamicattrs.html">Source</a></td>
+</tr>
+
+<tr valign=TOP>
+<td>JSP Configuration</td>
+<td valign=TOP width="30%"><a href="jsp2/misc/config.jsp"><img src="images/execute.gif" hspace=4 border=0  align=top></a><a href="jsp2/misc/config.jsp">Execute</a></td>
+
+<td width="30%"><a href="jsp2/misc/config.html"><img SRC="images/code.gif" HSPACE=4 BORDER=0 height=24 width=24 align=TOP></a><a href="jsp2/misc/config.html">Source</a></td>
+</tr>
+
+</table>
+
+<br>
+<b><u><font size="+1">JSP 1.2 Examples</font></u></b><br>
+<table BORDER=0 CELLSPACING=5 WIDTH="85%" >
+<tr VALIGN=TOP>
+<td>Numberguess&nbsp;</td>
+
+<td VALIGN=TOP WIDTH="30%"><a href="num/numguess.jsp"><img SRC="images/execute.gif" HSPACE=4 BORDER=0  align=TOP></a><a href="num/numguess.jsp">Execute</a></td>
+
+<td WIDTH="30%"><a href="num/numguess.html"><img SRC="images/code.gif" HSPACE=4 BORDER=0 height=24 width=24 align=TOP></a><a href="num/numguess.html">Source</a></td>
+</tr>
+
+<tr VALIGN=TOP>
+<td>Date&nbsp;</td>
+
+<td VALIGN=TOP WIDTH="30%"><a href="dates/date.jsp"><img SRC="images/execute.gif" HSPACE=4 BORDER=0  align=TOP></a><a href="dates/date.jsp">Execute</a></td>
+
+<td WIDTH="30%"><a href="dates/date.html"><img SRC="images/code.gif" HSPACE=4 BORDER=0 height=24 width=24 align=TOP></a><a href="dates/date.html">Source</a></td>
+</tr>
+
+<tr VALIGN=TOP>
+<td>Snoop</td>
+
+<td WIDTH="30%"><a href="snp/snoop.jsp"><img SRC="images/execute.gif" HSPACE=4 BORDER=0  align=TOP></a><a href="snp/snoop.jsp">Execute</a></td>
+
+<td WIDTH="30%"><a href="snp/snoop.html"><img SRC="images/code.gif" HSPACE=4 BORDER=0 height=24 width=24 align=TOP></a><a href="snp/snoop.html">Source</a></td>
+</tr>
+
+<tr VALIGN=TOP>
+<td>ErrorPage&nbsp;</td>
+
+<td WIDTH="30%"><a href="error/error.html"><img SRC="images/execute.gif" HSPACE=4 BORDER=0  align=TOP></a><a href="error/error.html">Execute</a></td>
+
+<td WIDTH="30%"><a href="error/er.html"><img SRC="images/code.gif" HSPACE=4 BORDER=0 height=24 width=24 align=TOP></a><a href="error/er.html">Source</a></td>
+</tr>
+
+<tr VALIGN=TOP>
+<td>Carts&nbsp;</td>
+
+<td VALIGN=TOP WIDTH="30%"><a href="sessions/carts.html"><img SRC="images/execute.gif" HSPACE=4 BORDER=0  align=TOP></a><a href="sessions/carts.html">Execute</a></td>
+
+<td WIDTH="30%"><a href="sessions/crt.html"><img SRC="images/code.gif" HSPACE=4 BORDER=0 height=24 width=24 align=TOP></a><a href="sessions/crt.html">Source</a></td>
+</tr>
+
+<tr VALIGN=TOP>
+<td>Checkbox&nbsp;</td>
+
+<td VALIGN=TOP WIDTH="30%"><a href="checkbox/check.html"><img SRC="images/execute.gif" HSPACE=4 BORDER=0  align=TOP></a><a href="checkbox/check.html">Execute</a></td>
+
+<td WIDTH="30%"><a href="checkbox/cresult.html"><img SRC="images/code.gif" HSPACE=4 BORDER=0 height=24 width=24 align=TOP></a><a href="checkbox/cresult.html">Source</a></td>
+</tr>
+
+<tr VALIGN=TOP>
+<td>Color&nbsp;</td>
+
+<td VALIGN=TOP WIDTH="30%"><a href="colors/colors.html"><img SRC="images/execute.gif" HSPACE=4 BORDER=0  align=TOP></a><a href="colors/colors.html">Execute</a></td>
+
+<td WIDTH="30%"><a href="colors/clr.html.html"><img SRC="images/code.gif" HSPACE=4 BORDER=0 height=24 width=24 align=TOP></a><a href="colors/clr.html">Source</a></td>
+</tr>
+
+<tr VALIGN=TOP>
+<td>Calendar&nbsp;</td>
+
+<td WIDTH="30%"><a href="cal/login.html"><img SRC="images/execute.gif" HSPACE=4 BORDER=0  align=TOP></a><a href="cal/login.html">Execute</a></td>
+
+<td WIDTH="30%"><a href="cal/calendar.html"><img SRC="images/code.gif" HSPACE=4 BORDER=0 height=24 width=24 align=TOP></a><a href="cal/calendar.html">Source</a></td>
+</tr>
+
+<tr VALIGN=TOP>
+<td>Include&nbsp;</td>
+
+<td VALIGN=TOP WIDTH="30%"><a href="/include/include.jsp"><img SRC="images/execute.gif" HSPACE=4 BORDER=0  align=TOP></a><a href="include/include.jsp">Execute</a></td>
+
+<td WIDTH="30%"><a href="include/inc.html"><img SRC="images/code.gif" HSPACE=4 BORDER=0 height=24 width=24 align=TOP></a><a href="include/inc.html">Source</a></td>
+</tr>
+
+<tr VALIGN=TOP>
+<td>Forward&nbsp;</td>
+
+<td VALIGN=TOP WIDTH="30%"><a href="forward/forward.jsp"><img SRC="images/execute.gif" HSPACE=4 BORDER=0  align=TOP></a><a href="forward/forward.jsp">Execute</a></td>
+
+<td WIDTH="30%"><a href="forward/fwd.html"><img SRC="images/code.gif" HSPACE=4 BORDER=0 height=24 width=24 align=TOP></a><a href="forward/fwd.html">Source</a></td>
+</tr>
+
+<tr VALIGN=TOP>
+<td>Plugin&nbsp;</td>
+
+<td VALIGN=TOP WIDTH="30%"><a href="plugin/plugin.jsp"><img SRC="images/execute.gif" HSPACE=4 BORDER=0  align=TOP></a><a href="plugin/plugin.jsp">Execute</a></td>
+
+<td WIDTH="30%"><a href="plugin/plugin.html"><img SRC="images/code.gif" HSPACE=4 BORDER=0 height=24 width=24 align=TOP></a><a href="plugin/plugin.html">Source</a></td>
+</tr>
+
+<tr VALIGN=TOP>
+<td>JSP-Servlet-JSP&nbsp;</td>
+
+<td VALIGN=TOP WIDTH="30%"><a href="jsptoserv/jsptoservlet.jsp"><img SRC="images/execute.gif" HSPACE=4 BORDER=0  align=TOP></a><a href="jsptoserv/jsptoservlet.jsp">Execute</a></td>
+
+<td WIDTH="30%"><a href="jsptoserv/jts.html"><img SRC="images/code.gif" HSPACE=4 BORDER=0 height=24 width=24 align=TOP></a><a href="jsptoserv/jts.html">Source</a></td>
+</tr>
+
+<tr VALIGN=TOP>
+<td>Custom tag example</td>
+
+<td VALIGN=TOP WIDTH="30%"><a href="simpletag/foo.jsp"><img SRC="images/execute.gif" HSPACE=4 BORDER=0  align=TOP></a><a href="simpletag/foo.jsp">Execute</a></td>
+
+<td WIDTH="30%"><a href="simpletag/foo.html"><img SRC="images/code.gif" HSPACE=4 BORDER=0 height=24 width=24 align=TOP></a><a href="simpletag/foo.html">Source</a></td>
+</tr>
+
+<tr valign=TOP>
+<td>XML syntax example</td>
+<td valign=TOP width="30%"><a href="xml/xml.jsp"><img src="images/execute.gif" hspace=4 border=0  align=top></a><a href="xml/xml.jsp">Execute</a></td>
+
+<td width="30%"><a href="xml/xml.html"><img SRC="images/code.gif" HSPACE=4 BORDER=0 height=24 width=24 align=TOP></a><a href="xml/xml.html">Source</a></td>
+</tr>
+
+</table>
+
+<br/>
+<b><u><font size="+1">Tag Plugins</font></u></b><br>
+<table BORDER=0 CELLSPACING=5 WIDTH="85%" >
+
+<tr VALIGN=TOP>
+  <td>If&nbsp;</td>
+  <td VALIGN=TOP WIDTH="30%">
+    <a href="tagplugin/if.jsp"><img SRC="images/execute.gif" HSPACE=4 BORDER=0  
+align=TOP></a>
+    <a href="tagplugin/if.jsp">Execute</a>
+  </td>
+  <td WIDTH="30%">
+    <a href="tagplugin/if.html"><img SRC="images/code.gif" HSPACE=4 BORDER=0 hei
+ght=24 width=24 align=TOP></a>
+    <a href="tagplugin/if.html">Source</a>
+  </td>
+</tr>
+
+<tr VALIGN=TOP>
+  <td>ForEach&nbsp;</td>
+  <td VALIGN=TOP WIDTH="30%">
+    <a href="tagplugin/foreach.jsp"><img SRC="images/execute.gif" HSPACE=4 BORDER=0  
+align=TOP></a>
+    <a href="tagplugin/foreach.jsp">Execute</a>
+  </td>
+  <td WIDTH="30%">
+    <a href="tagplugin/foreach.html"><img SRC="images/code.gif" HSPACE=4 BORDER=0 hei
+ght=24 width=24 align=TOP></a>
+    <a href="tagplugin/foreach.html">Source</a>
+  </td>
+</tr>
+
+<tr VALIGN=TOP>
+  <td>Choose&nbsp;</td>
+  <td VALIGN=TOP WIDTH="30%">
+    <a href="tagplugin/choose.jsp"><img SRC="images/execute.gif" HSPACE=4 BORDER=0  align=TOP></a>
+    <a href="tagplugin/choose.jsp">Execute</a>
+  </td>
+  <td WIDTH="30%">
+    <a href="tagplugin/choose.html"><img SRC="images/code.gif" HSPACE=4 BORDER=0 height=24 width=24 align=TOP></a>
+    <a href="tagplugin/choose.html">Source</a>
+  </td>
+</tr>
+
+</table>
+
+</body>
+</html>

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/el/basic-arithmetic.html
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/el/basic-arithmetic.html	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/el/basic-arithmetic.html	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,29 @@
+<html>
+<!--
+  Copyright 2004 The Apache Software Foundation
+
+  Licensed 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>
+<title>View Source Code</title>
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+</head>
+
+<body bgcolor="#FFFFFF">
+<p><font color="#0000FF"><a href="basic-arithmetic.jsp"><img src="../../images/execute.gif" align="right" border="0"></a><a href="../../index.html"><img src="../../images/return.gif" width="24" height="24" align="right" border="0"></a></font></p>
+
+<h3><a href="basic-arithmetic.jsp.html">Source Code for Basic Arithmetic Example<font color="#0000FF"></a>
+  </font> </h3>
+
+</body>
+</html>

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/el/basic-arithmetic.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/el/basic-arithmetic.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/el/basic-arithmetic.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,87 @@
+<!--
+  Copyright 2004 The Apache Software Foundation
+
+  Licensed 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.
+-->
+<html>
+  <head>
+    <title>JSP 2.0 Expression Language - Basic Arithmetic</title>
+  </head>
+  <body>
+    <h1>JSP 2.0 Expression Language - Basic Arithmetic</h1>
+    <hr>
+    This example illustrates basic Expression Language arithmetic.
+    Addition (+), subtraction (-), multiplication (*), division (/ or div), 
+    and modulus (% or mod) are all supported.  Error conditions, like
+    division by zero, are handled gracefully.
+    <br>
+    <blockquote>
+      <code>
+        <table border="1">
+          <thead>
+	    <td><b>EL Expression</b></td>
+	    <td><b>Result</b></td>
+	  </thead>
+	  <tr>
+	    <td>\${1}</td>
+	    <td>${1}</td>
+	  </tr>
+	  <tr>
+	    <td>\${1 + 2}</td>
+	    <td>${1 + 2}</td>
+	  </tr>
+	  <tr>
+	    <td>\${1.2 + 2.3}</td>
+	    <td>${1.2 + 2.3}</td>
+	  </tr>
+	  <tr>
+	    <td>\${1.2E4 + 1.4}</td>
+	    <td>${1.2E4 + 1.4}</td>
+	  </tr>
+	  <tr>
+	    <td>\${-4 - 2}</td>
+	    <td>${-4 - 2}</td>
+	  </tr>
+	  <tr>
+	    <td>\${21 * 2}</td>
+	    <td>${21 * 2}</td>
+	  </tr>
+	  <tr>
+	    <td>\${3/4}</td>
+	    <td>${3/4}</td>
+	  </tr>
+	  <tr>
+	    <td>\${3 div 4}</td>
+	    <td>${3 div 4}</td>
+	  </tr>
+	  <tr>
+	    <td>\${3/0}</td>
+	    <td>${3/0}</td>
+	  </tr>
+	  <tr>
+	    <td>\${10%4}</td>
+	    <td>${10%4}</td>
+	  </tr>
+	  <tr>
+	    <td>\${10 mod 4}</td>
+	    <td>${10 mod 4}</td>
+	  </tr>
+    <tr>
+      <td>\${(1==2) ? 3 : 4}</td>
+      <td>${(1==2) ? 3 : 4}</td>
+    </tr>
+	</table>
+      </code>
+    </blockquote>
+  </body>
+</html>

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/el/basic-comparisons.html
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/el/basic-comparisons.html	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/el/basic-comparisons.html	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,29 @@
+<html>
+<!--
+  Copyright 2004 The Apache Software Foundation
+
+  Licensed 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>
+<title>View Source Code</title>
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+</head>
+
+<body bgcolor="#FFFFFF">
+<p><font color="#0000FF"><a href="basic-comparisons.jsp"><img src="../../images/execute.gif" align="right" border="0"></a><a href="../../index.html"><img src="../../images/return.gif" width="24" height="24" align="right" border="0"></a></font></p>
+
+<h3><a href="basic-comparisons.jsp.html">Source Code for Basic Comparisons Example<font color="#0000FF"></a>
+  </font> </h3>
+
+</body>
+</html>

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/el/basic-comparisons.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/el/basic-comparisons.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/el/basic-comparisons.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,115 @@
+<!--
+  Copyright 2004 The Apache Software Foundation
+
+  Licensed 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.
+-->
+<html>
+  <head>
+    <title>JSP 2.0 Expression Language - Basic Comparisons</title>
+  </head>
+  <body>
+    <h1>JSP 2.0 Expression Language - Basic Comparisons</h1>
+    <hr>
+    This example illustrates basic Expression Language comparisons.
+    The following comparison operators are supported:
+    <ul>
+      <li>Less-than (&lt; or lt)</li>
+      <li>Greater-than (&gt; or gt)</li>
+      <li>Less-than-or-equal (&lt;= or le)</li>
+      <li>Greater-than-or-equal (&gt;= or ge)</li>
+      <li>Equal (== or eq)</li>
+      <li>Not Equal (!= or ne)</li>
+    </ul>
+    <blockquote>
+      <u><b>Numeric</b></u>
+      <code>
+        <table border="1">
+          <thead>
+	    <td><b>EL Expression</b></td>
+	    <td><b>Result</b></td>
+	  </thead>
+	  <tr>
+	    <td>\${1 &lt; 2}</td>
+	    <td>${1 < 2}</td>
+	  </tr>
+	  <tr>
+	    <td>\${1 lt 2}</td>
+	    <td>${1 lt 2}</td>
+	  </tr>
+	  <tr>
+	    <td>\${1 &gt; (4/2)}</td>
+	    <td>${1 > (4/2)}</td>
+	  </tr>
+	  <tr>
+	    <td>\${1 &gt; (4/2)}</td>
+	    <td>${1 > (4/2)}</td>
+	  </tr>
+	  <tr>
+	    <td>\${4.0 &gt;= 3}</td>
+	    <td>${4.0 >= 3}</td>
+	  </tr>
+	  <tr>
+	    <td>\${4.0 ge 3}</td>
+	    <td>${4.0 ge 3}</td>
+	  </tr>
+	  <tr>
+	    <td>\${4 &lt;= 3}</td>
+	    <td>${4 <= 3}</td>
+	  </tr>
+	  <tr>
+	    <td>\${4 le 3}</td>
+	    <td>${4 le 3}</td>
+	  </tr>
+	  <tr>
+	    <td>\${100.0 == 100}</td>
+	    <td>${100.0 == 100}</td>
+	  </tr>
+	  <tr>
+	    <td>\${100.0 eq 100}</td>
+	    <td>${100.0 eq 100}</td>
+	  </tr>
+	  <tr>
+	    <td>\${(10*10) != 100}</td>
+	    <td>${(10*10) != 100}</td>
+	  </tr>
+	  <tr>
+	    <td>\${(10*10) ne 100}</td>
+	    <td>${(10*10) ne 100}</td>
+	  </tr>
+	</table>
+      </code>
+      <br>
+      <u><b>Alphabetic</b></u>
+      <code>
+        <table border="1">
+          <thead>
+	    <td><b>EL Expression</b></td>
+	    <td><b>Result</b></td>
+	  </thead>
+	  <tr>
+	    <td>\${'a' &lt; 'b'}</td>
+	    <td>${'a' < 'b'}</td>
+	  </tr>
+	  <tr>
+	    <td>\${'hip' &gt; 'hit'}</td>
+	    <td>${'hip' > 'hit'}</td>
+	  </tr>
+	  <tr>
+	    <td>\${'4' &gt; 3}</td>
+	    <td>${'4' > 3}</td>
+	  </tr>
+	</table>
+      </code>
+    </blockquote>
+  </body>
+</html>

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/el/functions.html
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/el/functions.html	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/el/functions.html	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,31 @@
+<html>
+<!--
+  Copyright 2004 The Apache Software Foundation
+
+  Licensed 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>
+<title>View Source Code</title>
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+</head>
+
+<body bgcolor="#FFFFFF">
+<p><font color="#0000FF"><a href="functions.jsp?foo=JSP+2.0"><img src="../../images/execute.gif" align="right" border="0"></a><a href="../../index.html"><img src="../../images/return.gif" width="24" height="24" align="right" border="0"></a></font></p>
+
+<h3><a href="functions.jsp.html">Source Code for functions.jsp<font color="#0000FF"></a>
+  </font> </h3>
+<h3><a href="Functions.java.html">Source Code for Functions.java<font color="#0000FF"></a>
+  </font> </h3>
+
+</body>
+</html>

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/el/functions.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/el/functions.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/el/functions.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,65 @@
+<!--
+  Copyright 2004 The Apache Software Foundation
+
+  Licensed 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.
+-->
+<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
+<%@ taglib prefix="my" uri="http://jakarta.apache.org/tomcat/jsp2-example-taglib"%>
+
+<html>
+  <head>
+    <title>JSP 2.0 Expression Language - Functions</title>
+  </head>
+  <body>
+    <h1>JSP 2.0 Expression Language - Functions</h1>
+    <hr>
+    An upgrade from the JSTL expression language, the JSP 2.0 EL also
+    allows for simple function invocation.  Functions are defined
+    by tag libraries and are implemented by a Java programmer as 
+    static methods.
+
+    <blockquote>
+      <u><b>Change Parameter</b></u>
+      <form action="functions.jsp" method="GET">
+	  foo = <input type="text" name="foo" value="${fn:escapeXml(param["foo"])}">
+          <input type="submit">
+      </form>
+      <br>
+      <code>
+        <table border="1">
+          <thead>
+	    <td><b>EL Expression</b></td>
+	    <td><b>Result</b></td>
+	  </thead>
+	  <tr>
+	    <td>\${param["foo"]}</td>
+	    <td>${fn:escapeXml(param["foo"])}&nbsp;</td>
+	  </tr>
+	  <tr>
+	    <td>\${my:reverse(param["foo"])}</td>
+	    <td>${my:reverse(fn:escapeXml(param["foo"]))}&nbsp;</td>
+	  </tr>
+	  <tr>
+	    <td>\${my:reverse(my:reverse(param["foo"]))}</td>
+	    <td>${my:reverse(my:reverse(fn:escapeXml(param["foo"])))}&nbsp;</td>
+	  </tr>
+	  <tr>
+	    <td>\${my:countVowels(param["foo"])}</td>
+	    <td>${my:countVowels(fn:escapeXml(param["foo"]))}&nbsp;</td>
+	  </tr>
+	</table>
+      </code>
+    </blockquote>
+  </body>
+</html>
+

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/el/implicit-objects.html
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/el/implicit-objects.html	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/el/implicit-objects.html	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,19 @@
+<html>
+<!--
+  Copyright (c) 1999 The Apache Software Foundation.  All rights 
+  reserved.
+-->
+<head>
+<title>View Source Code</title>
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+</head>
+
+<body bgcolor="#FFFFFF">
+<p><font color="#0000FF"><a href="implicit-objects.jsp?foo=bar"><img src="../../images/execute.gif" align="right" border="0"></a><a href="../../index.html">
+<img src="../../images/return.gif" width="24" height="24" align="right" border="0"></a></font></p>
+
+<h3><a href="implicit-objects.jsp.html">Source Code for Implicit Objects Example<font color="#0000FF"></a>
+  </font> </h3>
+
+</body>
+</html>

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/el/implicit-objects.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/el/implicit-objects.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/el/implicit-objects.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,88 @@
+<!--
+  Copyright 2004 The Apache Software Foundation
+
+  Licensed 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.
+-->
+<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
+
+<html>
+  <head>
+    <title>JSP 2.0 Expression Language - Implicit Objects</title>
+  </head>
+  <body>
+    <h1>JSP 2.0 Expression Language - Implicit Objects</h1>
+    <hr>
+    This example illustrates some of the implicit objects available 
+    in the Expression Lanaguage.  The following implicit objects are 
+    available (not all illustrated here):
+    <ul>
+      <li>pageContext - the PageContext object</li>
+      <li>pageScope - a Map that maps page-scoped attribute names to 
+          their values</li>
+      <li>requestScope - a Map that maps request-scoped attribute names 
+          to their values</li>
+      <li>sessionScope - a Map that maps session-scoped attribute names 
+          to their values</li>
+      <li>applicationScope - a Map that maps application-scoped attribute 
+          names to their values</li>
+      <li>param - a Map that maps parameter names to a single String 
+          parameter value</li>
+      <li>paramValues - a Map that maps parameter names to a String[] of 
+          all values for that parameter</li>
+      <li>header - a Map that maps header names to a single String 
+          header value</li>
+      <li>headerValues - a Map that maps header names to a String[] of 
+          all values for that header</li>
+      <li>initParam - a Map that maps context initialization parameter 
+          names to their String parameter value</li>
+      <li>cookie - a Map that maps cookie names to a single Cookie object.</li>
+    </ul>
+
+    <blockquote>
+      <u><b>Change Parameter</b></u>
+      <form action="implicit-objects.jsp" method="GET">
+	  foo = <input type="text" name="foo" value="${fn:escapeXml(param["foo"])}">
+          <input type="submit">
+      </form>
+      <br>
+      <code>
+        <table border="1">
+          <thead>
+	    <td><b>EL Expression</b></td>
+	    <td><b>Result</b></td>
+	  </thead>
+	  <tr>
+	    <td>\${param.foo}</td>
+	    <td>${fn:escapeXml(param["foo"])}&nbsp;</td>
+	  </tr>
+	  <tr>
+	    <td>\${param["foo"]}</td>
+	    <td>${fn:escapeXml(param["foo"])}&nbsp;</td>
+	  </tr>
+	  <tr>
+	    <td>\${header["host"]}</td>
+	    <td>${fn:escapeXml(header["host"])}&nbsp;</td>
+	  </tr>
+	  <tr>
+	    <td>\${header["accept"]}</td>
+	    <td>${fn:escapeXml(header["accept"])}&nbsp;</td>
+	  </tr>
+	  <tr>
+	    <td>\${header["user-agent"]}</td>
+	    <td>${fn:escapeXml(header["user-agent"])}&nbsp;</td>
+	  </tr>
+	</table>
+      </code>
+    </blockquote>
+  </body>
+</html>

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/jspattribute/jspattribute.html
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/jspattribute/jspattribute.html	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/jspattribute/jspattribute.html	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,36 @@
+<html>
+<!--
+  Copyright 2004 The Apache Software Foundation
+
+  Licensed 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>
+<title>View Source Code</title>
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+</head>
+
+<body bgcolor="#FFFFFF">
+<p><font color="#0000FF"><a href="jspattribute.jsp"><img src="../../images/execute.gif" align="right" border="0"></a>
+<a href="../../index.html"><img src="../../images/return.gif" width="24" height="24" align="right" border="0"></a></font></p>
+
+<h3><a href="jspattribute.jsp.html">Source Code for jspattribute.jsp<font color="#0000FF"></a>
+  </font> </h3>
+
+<h3><a href="HelloWorldSimpleTag.java.html">Source Code for HelloWorldSimpleTag.java<font color="#0000FF"></a>
+  </font> </h3>
+
+<h3><a href="FooBean.java.html">Source Code for FooBean.java<font color="#0000FF"></a>
+  </font> </h3>
+
+</body>
+</html>

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/jspattribute/jspattribute.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/jspattribute/jspattribute.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/jspattribute/jspattribute.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,45 @@
+<!--
+  Copyright 2004 The Apache Software Foundation
+
+  Licensed 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.
+-->
+<%@ taglib prefix="my" uri="http://jakarta.apache.org/tomcat/jsp2-example-taglib"%>
+
+<html>
+  <head>
+    <title>JSP 2.0 Examples - jsp:attribute and jsp:body</title>
+  </head>
+  <body>
+    <h1>JSP 2.0 Examples - jsp:attribute and jsp:body</h1>
+    <hr>
+    <p>The new &lt;jsp:attribute&gt; and &lt;jsp:body&gt; 
+    standard actions can be used to specify the value of any standard
+    action or custom action attribute.</p>
+    <p>This example uses the &lt;jsp:attribute&gt;
+    standard action to use the output of a custom action invocation
+    (one that simply outputs "Hello, World!") to set the value of a
+    bean property.  This would normally require an intermediary
+    step, such as using JSTL's &lt;c:set&gt; action.</p>
+    <br>
+    <jsp:useBean id="foo" class="jsp2.examples.FooBean">
+      Bean created!  Setting foo.bar...<br>
+      <jsp:setProperty name="foo" property="bar">
+        <jsp:attribute name="value">
+	  <my:helloWorld/>
+        </jsp:attribute>
+      </jsp:setProperty>
+    </jsp:useBean>
+    <br>
+    Result: ${foo.bar}
+  </body>
+</html>

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/jspattribute/shuffle.html
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/jspattribute/shuffle.html	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/jspattribute/shuffle.html	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,36 @@
+<html>
+<!--
+  Copyright 2004 The Apache Software Foundation
+
+  Licensed 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>
+<title>View Source Code</title>
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+</head>
+
+<body bgcolor="#FFFFFF">
+<p><font color="#0000FF"><a href="shuffle.jsp"><img src="../../images/execute.gif" align="right" border="0"></a>
+<a href="../../index.html"><img src="../../images/return.gif" width="24" height="24" align="right" border="0"></a></font></p>
+
+<h3><a href="shuffle.jsp.html">Source Code for shuffle.jsp<font color="#0000FF"></a>
+  </font> </h3>
+
+<h3><a href="ShuffleSimpleTag.java.html">Source Code for ShuffleSimpleTag.java<font color="#0000FF"></a>
+  </font> </h3>
+
+<h3><a href="TileSimpleTag.java.html">Source Code for TileSimpleTag.java<font color="#0000FF"></a>
+  </font> </h3>
+
+</body>
+</html>

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/jspattribute/shuffle.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/jspattribute/shuffle.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/jspattribute/shuffle.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,89 @@
+<!--
+  Copyright 2004 The Apache Software Foundation
+
+  Licensed 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.
+-->
+<%@ taglib prefix="my" uri="http://jakarta.apache.org/tomcat/jsp2-example-taglib"%>
+
+<html>
+  <head>
+    <title>JSP 2.0 Examples - Shuffle Example</title>
+  </head>
+  <body>
+    <h1>JSP 2.0 Examples - Shuffle Example</h1>
+    <hr>
+    <p>Try reloading the page a few times.  Both the rows and the columns
+    are shuffled and appear different each time.</p>
+    <p>Here's how the code works.  The SimpleTag handler called 
+    &lt;my:shuffle&gt; accepts three attributes.  Each attribute is a 
+    JSP Fragment, meaning it is a fragment of JSP code that can be
+    dynamically executed by the shuffle tag handler on demand.  The 
+    shuffle tag handler executes the three fragments in a random order.
+    To shuffle both the rows and the columns, the shuffle tag is used
+    with itself as a parameter.</p>
+    <hr>
+    <blockquote>
+     <font color="#ffffff">
+      <table>
+        <my:shuffle>
+          <jsp:attribute name="fragment1">
+            <tr>
+              <my:shuffle>
+                <jsp:attribute name="fragment1">
+                  <my:tile color="#ff0000" label="A"/>
+                </jsp:attribute>
+                <jsp:attribute name="fragment2">
+                  <my:tile color="#00ff00" label="B"/>
+                </jsp:attribute>
+                <jsp:attribute name="fragment3">
+                  <my:tile color="#0000ff" label="C"/>
+                </jsp:attribute>
+              </my:shuffle>
+            </tr>
+          </jsp:attribute>
+          <jsp:attribute name="fragment2">
+            <tr>
+              <my:shuffle>
+                <jsp:attribute name="fragment1">
+                  <my:tile color="#ff0000" label="1"/>
+                </jsp:attribute>
+                <jsp:attribute name="fragment2">
+                  <my:tile color="#00ff00" label="2"/>
+                </jsp:attribute>
+                <jsp:attribute name="fragment3">
+                  <my:tile color="#0000ff" label="3"/>
+                </jsp:attribute>
+              </my:shuffle>
+            </tr>
+          </jsp:attribute>
+          <jsp:attribute name="fragment3">
+            <tr>
+              <my:shuffle>
+                <jsp:attribute name="fragment1">
+                  <my:tile color="#ff0000" label="!"/>
+                </jsp:attribute>
+                <jsp:attribute name="fragment2">
+                  <my:tile color="#00ff00" label="@"/>
+                </jsp:attribute>
+                <jsp:attribute name="fragment3">
+                  <my:tile color="#0000ff" label="#"/>
+                </jsp:attribute>
+              </my:shuffle>
+            </tr>
+          </jsp:attribute>
+        </my:shuffle>
+      </table>
+     </font>
+    </blockquote>
+  </body>
+</html>

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/jspx/basic.html
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/jspx/basic.html	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/jspx/basic.html	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,30 @@
+<html>
+<!--
+  Copyright 2004 The Apache Software Foundation
+
+  Licensed 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>
+<title>View Source Code</title>
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+</head>
+
+<body bgcolor="#FFFFFF">
+<p><font color="#0000FF"><a href="basic.jspx"><img src="../../images/execute.gif" align="right" border="0"></a><a
+href="../../index.html"><img src="../../images/return.gif" width="24" height="24" align="right" border="0"></a></font></p>
+
+<h3><a href="basic.jspx.html">Source Code for XHTML Basic Example<font color="#0000FF"></a>
+  </font> </h3>
+
+</body>
+</html>

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/jspx/basic.jspx
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/jspx/basic.jspx	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/jspx/basic.jspx	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,30 @@
+<tags:xhtmlbasic xmlns:tags="urn:jsptagdir:/WEB-INF/tags"
+                 xmlns:jsp="http://java.sun.com/JSP/Page"
+                 xmlns:fmt="http://java.sun.com/jsp/jstl/fmt"
+		 xmlns="http://www.w3.org/1999/xhtml">
+  <jsp:directive.page contentType="text/html" />
+  <head>
+    <title>JSPX - XHTML Basic Example</title>
+  </head>
+  <body>
+    <h1>JSPX - XHTML Basic Example</h1>
+    <hr/>
+    This example illustrates how to use JSPX to produce an XHTML basic
+    document suitable for use with mobile phones, televisions, 
+    PDAs, vending machines, pagers, car navigation systems,
+    mobile game machines, digital book readers, smart watches, etc.
+    <p/>
+    JSPX lets you create dynamic documents in a pure XML syntax compatible
+    with existing XML tools.  The XML syntax in JSP 1.2 was awkward and
+    required &amp;lt;jsp:root&amp;gt; to be the root element of the document.
+    This is no longer the case in JSP 2.0.
+    <p/>
+    This particular example uses a tag file to produce the DOCTYPE and
+    namespace declarations to make the output of this page a valid XHTML
+    Basic document.
+    <p/>
+    Just to prove this is live, here's some dynamic content:
+    <jsp:useBean id="now" class="java.util.Date" />
+    <fmt:formatDate value="${now}" pattern="MMMM d, yyyy, H:mm:ss"/>
+  </body>
+</tags:xhtmlbasic>

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/jspx/svgexample.html
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/jspx/svgexample.html	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/jspx/svgexample.html	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,51 @@
+<!--
+  Copyright 2004 The Apache Software Foundation
+
+  Licensed 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.
+-->
+<html>
+  <head>
+    <title>JSP 2.0 SVG Example</title>
+  </head>
+  <body>
+    <h1>JSP 2.0 SVG Example</h1>
+    <hr>
+    This example uses JSP 2.0's new, simplified JSPX syntax to render a
+    Scalable Vector Graphics (SVG) document.  When you view the source,
+    notice the lack of a &lt;jsp:root&gt; element!  The text to be rendered 
+    can be modified by changing the value of the name parameter.
+    <p>
+    SVG has many potential uses, such as searchable images, or images
+    customized with the name of your site's visitor (e.g. a "Susan's Store"
+    tab image).  JSPX is a natural fit for generating dynamic XML content
+    such as SVG.
+    <p>
+    To execute this example, follow these steps:
+    <ol>
+      <li>Download <a href="http://xml.apache.org/batik/index.html">Batik</a>,
+          or any other SVG viewer.</li>
+      <li>Copy the following URL:
+      <a href="http://localhost:8080/jsp-examples/jsp2/jspx/textRotate.jspx?name=JSPX">
+      http://localhost:8080/jsp-examples/jsp2/jspx/textRotate.jspx?name=JSPX</a>
+      </li>
+      <li>Paste the URL into Batik's Location field and press Enter</li>
+      <li>Customize by changing the name=JSPX parameter</li>
+    </ol>
+    <br>
+    The following is a screenshot of the resulting image, for those that
+    don't have an SVG viewer:
+    <blockquote>
+      <img src="textRotate.jpg" border="1">
+    </blockquote>
+  </body>
+</html>

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/jspx/textRotate.html
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/jspx/textRotate.html	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/jspx/textRotate.html	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,31 @@
+<html>
+<!--
+  Copyright 2004 The Apache Software Foundation
+
+  Licensed 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>
+<title>View Source Code</title>
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+</head>
+
+<body bgcolor="#FFFFFF">
+<p><font color="#0000FF"><a href="textRotate.jspx"><img src="../../images/execute.gif" align="right" border="0"></a><a
+href="../../index.html"><img src="../../images/return.gif" width="24" height="24" align="right" border="0"></a></font></p>
+
+<h3><a href="textRotate.jspx.html">Source Code for SVG (Scalable Vector Graphics)
+Example<font color="#0000FF"></a>
+  </font> </h3>
+
+</body>
+</html>

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/jspx/textRotate.jpg
===================================================================
(Binary files differ)


Property changes on: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/jspx/textRotate.jpg
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/jspx/textRotate.jspx
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/jspx/textRotate.jspx	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/jspx/textRotate.jspx	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,36 @@
+<!-- 
+  - This example is based off the textRotate.svg example that comes
+  - with Batik.  The original example was written by Bill Haneman.
+  - This version by Mark Roth.
+  -->
+<svg xmlns="http://www.w3.org/2000/svg"
+     width="450" height="500" viewBox="0 0 450 500"
+     xmlns:c="http://java.sun.com/jsp/jstl/core"
+     xmlns:fn="http://java.sun.com/jsp/jstl/functions"
+     xmlns:jsp="http://java.sun.com/JSP/Page">
+  <jsp:directive.page contentType="image/svg+xml" />
+  <title>JSP 2.0 JSPX</title>
+  <!-- select name parameter, or default to JSPX -->
+  <c:set var="name" value='${empty fn:escapeXml(param["name"]) ? "JSPX" : fn:escapeXml(param["name"])}'/>
+  <g id="testContent">
+    <text class="title" x="50%" y="10%" font-size="15" text-anchor="middle" >
+            JSP 2.0 XML Syntax (.jspx) Demo</text>
+    <text class="title" x="50%" y="15%" font-size="15" text-anchor="middle" >
+            Try changing the name parameter!</text>
+    <g opacity="1.0" transform="translate(225, 250)" id="rotatedText">
+      <c:forEach var="i" begin="1" end="24">
+        <jsp:text>
+          <![CDATA[<g opacity="0.95" transform="scale(1.05) rotate(15)">]]>
+        </jsp:text>
+        <text x="0" y="0" transform="scale(1.6, 1.6)" fill="DarkSlateBlue" 
+              text-anchor="middle" font-size="40" font-family="Serif" 
+              id="words">${name}</text>
+      </c:forEach>
+      <c:forEach var="i" begin="1" end="24">
+        <jsp:text><![CDATA[</g>]]></jsp:text>
+      </c:forEach>
+      <text style="font-size:75;font-family:Serif;fill:white" 
+            text-anchor="middle">${name}</text>
+    </g>
+  </g>
+</svg>

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/misc/coda.jspf
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/misc/coda.jspf	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/misc/coda.jspf	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,5 @@
+<hr>
+<center>
+This banner included with &lt;include-coda&gt;
+</center>
+<hr>

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/misc/config.html
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/misc/config.html	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/misc/config.html	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,34 @@
+<html>
+<!--
+  Copyright 2004 The Apache Software Foundation
+
+  Licensed 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>
+<title>View Source Code</title>
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+</head>
+
+<body bgcolor="#FFFFFF">
+<p><font color="#0000FF"><a href="config.jsp"><img src="../../images/execute.gif" align="right" border="0"></a>
+<a href="../../index.html"><img src="../../images/return.gif" width="24" height="24" align="right" border="0"></a></font></p>
+
+<h3><a href="config.jsp.html">Source Code for config.jsp<font color="#0000FF"></a>
+  </font> </h3>
+<h3><a href="prelude.jspf.html">Source Code for prelude.jspf<font color="#0000FF"></a>
+  </font> </h3>
+<h3><a href="coda.jspf.html">Source Code for coda.jspf<font color="#0000FF"></a>
+  </font> </h3>
+
+</body>
+</html>

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/misc/config.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/misc/config.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/misc/config.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,31 @@
+<!--
+  Copyright 2004 The Apache Software Foundation
+
+  Licensed 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.
+-->
+<%@ taglib prefix="my" uri="http://jakarta.apache.org/tomcat/jsp2-example-taglib"%>
+    <h1>JSP 2.0 Examples - JSP Configuration</h1>
+    <hr>
+    <p>Using a &lt;jsp-property-group&gt; element in the web.xml 
+    deployment descriptor, this JSP page has been configured in the
+    following ways:</p>
+    <ul>
+      <li>Uses &lt;include-prelude&gt; to include the top banner.</li>
+      <li>Uses &lt;include-coda&gt; to include the bottom banner.</li>
+      <li>Uses &lt;scripting-invalid&gt; true to disable 
+	  &lt;% scripting %&gt; elements</li>
+      <li>Uses &lt;el-ignored&gt; true to disable ${EL} elements</li>
+      <li>Uses &lt;page-encoding&gt; ISO-8859-1 to set the page encoding (though this is the default anyway)</li>
+    </ul>
+    There are various other configuration options that can be used.
+

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/misc/dynamicattrs.html
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/misc/dynamicattrs.html	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/misc/dynamicattrs.html	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,32 @@
+<html>
+<!--
+  Copyright 2004 The Apache Software Foundation
+
+  Licensed 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>
+<title>View Source Code</title>
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+</head>
+
+<body bgcolor="#FFFFFF">
+<p><font color="#0000FF"><a href="dynamicattrs.jsp"><img src="../../images/execute.gif" align="right" border="0"></a>
+<a href="../../index.html"><img src="../../images/return.gif" width="24" height="24" align="right" border="0"></a></font></p>
+
+<h3><a href="dynamicattrs.jsp.html">Source Code for dynamicattrs.jsp<font color="#0000FF"></a>
+  </font> </h3>
+<h3><a href="EchoAttributesTag.java.html">Source Code for EchoAttributesTag.java<font color="#0000FF"></a>
+  </font> </h3>
+
+</body>
+</html>

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/misc/dynamicattrs.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/misc/dynamicattrs.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/misc/dynamicattrs.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,43 @@
+<!--
+  Copyright 2004 The Apache Software Foundation
+
+  Licensed 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.
+-->
+<%@ taglib prefix="my" uri="http://jakarta.apache.org/tomcat/jsp2-example-taglib"%>
+<html>
+  <head>
+    <title>JSP 2.0 Examples - Dynamic Attributes</title>
+  </head>
+  <body>
+    <h1>JSP 2.0 Examples - Dynamic Attributes</h1>
+    <hr>
+    <p>This JSP page invokes a custom tag that accepts a dynamic set 
+    of attributes.  The tag echoes the name and value of all attributes
+    passed to it.</p>
+    <hr>
+    <h2>Invocation 1 (six attributes)</h2>
+    <ul>
+      <my:echoAttributes x="1" y="2" z="3" r="red" g="green" b="blue"/>
+    </ul>
+    <h2>Invocation 2 (zero attributes)</h2>
+    <ul>
+      <my:echoAttributes/>
+    </ul>
+    <h2>Invocation 3 (three attributes)</h2>
+    <ul>
+      <my:echoAttributes dogName="Scruffy" 
+	   		 catName="Fluffy" 
+			 blowfishName="Puffy"/>
+    </ul>
+  </body>
+</html>

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/misc/prelude.jspf
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/misc/prelude.jspf	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/misc/prelude.jspf	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,5 @@
+<hr>
+<center>
+This banner included with &lt;include-prelude&gt;
+</center>
+<hr>

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/simpletag/book.html
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/simpletag/book.html	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/simpletag/book.html	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,36 @@
+<html>
+<!--
+  Copyright 2004 The Apache Software Foundation
+
+  Licensed 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>
+<title>View Source Code</title>
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+</head>
+
+<body bgcolor="#FFFFFF">
+<p><font color="#0000FF"><a href="book.jsp"><img src="../../images/execute.gif" align="right" border="0"></a>
+<a href="../../index.html"><img src="../../images/return.gif" width="24" height="24" align="right" border="0"></a></font></p>
+
+<h3><a href="book.jsp.html">Source Code for the Book Example JSP<font color="#0000FF"></a>
+  </font> </h3>
+<h3><a href="FindBookSimpleTag.java.html">Source Code for the FindBook SimpleTag Handler<font color="#0000FF"></a>
+  </font> </h3>
+<h3><a href="BookBean.java.html">Source Code for BookBean<font color="#0000FF"></a>
+  </font> </h3>
+<h3><a href="Functions.java.html">Source Code for the EL Functions<font color="#0000FF"></a>
+  </font> </h3>
+
+</body>
+</html>

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/simpletag/book.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/simpletag/book.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/simpletag/book.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,54 @@
+<!--
+  Copyright 2004 The Apache Software Foundation
+
+  Licensed 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.
+-->
+<%@ taglib prefix="my" uri="/WEB-INF/jsp2/jsp2-example-taglib.tld" %>
+<html>
+  <head>
+    <title>JSP 2.0 Examples - Book SimpleTag Handler</title>
+  </head>
+  <body>
+    <h1>JSP 2.0 Examples - Book SimpleTag Handler</h1>
+    <hr>
+    <p>Illustrates a semi-realistic use of SimpleTag and the Expression 
+    Language.  First, a &lt;my:findBook&gt; tag is invoked to populate 
+    the page context with a BookBean.  Then, the books fields are printed 
+    in all caps.</p>
+    <br>
+    <b><u>Result:</u></b><br>
+    <my:findBook var="book"/>
+    <table border="1">
+        <thead>
+	    <td><b>Field</b></td>
+	    <td><b>Value</b></td>
+	    <td><b>Capitalized</b></td>
+	</thead>
+	<tr>
+	    <td>Title</td>
+	    <td>${book.title}</td>
+	    <td>${my:caps(book.title)}</td>
+	</tr>
+	<tr>
+	    <td>Author</td>
+	    <td>${book.author}</td>
+	    <td>${my:caps(book.author)}</td>
+	</tr>
+	<tr>
+	    <td>ISBN</td>
+	    <td>${book.isbn}</td>
+	    <td>${my:caps(book.isbn)}</td>
+	</tr>
+    </table>
+  </body>
+</html>

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/simpletag/hello.html
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/simpletag/hello.html	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/simpletag/hello.html	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,32 @@
+<html>
+<!--
+  Copyright 2004 The Apache Software Foundation
+
+  Licensed 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>
+<title>View Source Code</title>
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+</head>
+
+<body bgcolor="#FFFFFF">
+<p><font color="#0000FF"><a href="hello.jsp"><img src="../../images/execute.gif" align="right" border="0"></a>
+<a href="../../index.html"><img src="../../images/return.gif" width="24" height="24" align="right" border="0"></a></font></p>
+
+<h3><a href="hello.jsp.html">Source Code for the Hello World Tag Example JSP<font color="#0000FF"></a>
+  </font> </h3>
+<h3><a href="HelloWorldSimpleTag.java.html">Source Code for the Hello World SimpleTag Handler<font color="#0000FF"></a>
+  </font> </h3>
+
+</body>
+</html>

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/simpletag/hello.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/simpletag/hello.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/simpletag/hello.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,30 @@
+<!--
+  Copyright 2004 The Apache Software Foundation
+
+  Licensed 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.
+-->
+<%@ taglib prefix="mytag" uri="/WEB-INF/jsp2/jsp2-example-taglib.tld" %>
+<html>
+  <head>
+    <title>JSP 2.0 Examples - Hello World SimpleTag Handler</title>
+  </head>
+  <body>
+    <h1>JSP 2.0 Examples - Hello World SimpleTag Handler</h1>
+    <hr>
+    <p>This tag handler simply echos "Hello, World!"  It's an example of
+    a very basic SimpleTag handler with no body.</p>
+    <br>
+    <b><u>Result:</u></b>
+    <mytag:helloWorld/>
+  </body>
+</html>

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/simpletag/repeat.html
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/simpletag/repeat.html	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/simpletag/repeat.html	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,32 @@
+<html>
+<!--
+  Copyright 2004 The Apache Software Foundation
+
+  Licensed 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>
+<title>View Source Code</title>
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+</head>
+
+<body bgcolor="#FFFFFF">
+<p><font color="#0000FF"><a href="repeat.jsp"><img src="../../images/execute.gif" align="right" border="0"></a>
+<a href="../../index.html"><img src="../../images/return.gif" width="24" height="24" align="right" border="0"></a></font></p>
+
+<h3><a href="repeat.jsp.html">Source Code for the Repeat Tag Example JSP<font color="#0000FF"></a>
+  </font> </h3>
+<h3><a href="RepeatSimpleTag.java.html">Source Code for the Repeat SimpleTag Handler<font color="#0000FF"></a>
+  </font> </h3>
+
+</body>
+</html>

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/simpletag/repeat.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/simpletag/repeat.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/simpletag/repeat.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,38 @@
+<!--
+  Copyright 2004 The Apache Software Foundation
+
+  Licensed 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.
+-->
+<%@ taglib prefix="mytag" uri="/WEB-INF/jsp2/jsp2-example-taglib.tld" %>
+<html>
+  <head>
+    <title>JSP 2.0 Examples - Repeat SimpleTag Handler</title>
+  </head>
+  <body>
+    <h1>JSP 2.0 Examples - Repeat SimpleTag Handler</h1>
+    <hr>
+    <p>This tag handler accepts a "num" parameter and repeats the body of the
+    tag "num" times.  It's a simple example, but the implementation of 
+    such a tag in JSP 2.0 is substantially simpler than the equivalent 
+    JSP 1.2-style classic tag handler.</p>
+    <p>The body of the tag is encapsulated in a "JSP Fragment" and passed
+    to the tag handler, which then executes it five times, inside a 
+    for loop.  The tag handler passes in the current invocation in a
+    scoped variable called count, which can be accessed using the EL.</p>
+    <br>
+    <b><u>Result:</u></b><br>
+    <mytag:repeat num="5">
+      Invocation ${count} of 5<br>
+    </mytag:repeat>
+  </body>
+</html>

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/tagfiles/hello.html
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/tagfiles/hello.html	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/tagfiles/hello.html	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,32 @@
+<html>
+<!--
+  Copyright 2004 The Apache Software Foundation
+
+  Licensed 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>
+<title>View Source Code</title>
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+</head>
+
+<body bgcolor="#FFFFFF">
+<p><font color="#0000FF"><a href="hello.jsp"><img src="../../images/execute.gif" align="right" border="0"></a>
+<a href="../../index.html"><img src="../../images/return.gif" width="24" height="24" align="right" border="0"></a></font></p>
+
+<h3><a href="hello.jsp.html">Source Code for hello.jsp<font color="#0000FF"></a>
+  </font> </h3>
+<h3><a href="helloWorld.tag.html">Source Code for helloWorld.tag<font color="#0000FF"></a>
+  </font> </h3>
+
+</body>
+</html>

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/tagfiles/hello.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/tagfiles/hello.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/tagfiles/hello.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,34 @@
+<!--
+  Copyright 2004 The Apache Software Foundation
+
+  Licensed 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.
+-->
+<%@ taglib prefix="tags" tagdir="/WEB-INF/tags" %>
+<html>
+  <head>
+    <title>JSP 2.0 Examples - Hello World Using a Tag File</title>
+  </head>
+  <body>
+    <h1>JSP 2.0 Examples - Hello World Using a Tag File</h1>
+    <hr>
+    <p>This JSP page invokes a custom tag that simply echos "Hello, World!"  
+    The custom tag is generated from a tag file in the /WEB-INF/tags
+    directory.</p>
+    <p>Notice that we did not need to write a TLD for this tag.  We just
+    created /WEB-INF/tags/helloWorld.tag, imported it using the taglib
+    directive, and used it!</p>
+    <br>
+    <b><u>Result:</u></b>
+    <tags:helloWorld/>
+  </body>
+</html>

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/tagfiles/panel.html
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/tagfiles/panel.html	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/tagfiles/panel.html	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,32 @@
+<html>
+<!--
+  Copyright 2004 The Apache Software Foundation
+
+  Licensed 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>
+<title>View Source Code</title>
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+</head>
+
+<body bgcolor="#FFFFFF">
+<p><font color="#0000FF"><a href="panel.jsp"><img src="../../images/execute.gif" align="right" border="0"></a>
+<a href="../../index.html"><img src="../../images/return.gif" width="24" height="24" align="right" border="0"></a></font></p>
+
+<h3><a href="panel.jsp.html">Source Code for panel.jsp<font color="#0000FF"></a>
+  </font> </h3>
+<h3><a href="panel.tag.html">Source Code for panel.tag<font color="#0000FF"></a>
+  </font> </h3>
+
+</body>
+</html>

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/tagfiles/panel.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/tagfiles/panel.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/tagfiles/panel.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,57 @@
+<!--
+  Copyright 2004 The Apache Software Foundation
+
+  Licensed 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.
+-->
+<%@ taglib prefix="tags" tagdir="/WEB-INF/tags" %>
+<html>
+  <head>
+    <title>JSP 2.0 Examples - Panels using Tag Files</title>
+  </head>
+  <body>
+    <h1>JSP 2.0 Examples - Panels using Tag Files</h1>
+    <hr>
+    <p>This JSP page invokes a custom tag that draws a 
+    panel around the contents of the tag body.  Normally, such a tag 
+    implementation would require a Java class with many println() statements,
+    outputting HTML.  Instead, we can use a .tag file as a template,
+    and we don't need to write a single line of Java or even a TLD!</p>
+    <hr>
+    <table border="0">
+      <tr valign="top">
+        <td>
+          <tags:panel color="#ff8080" bgcolor="#ffc0c0" title="Panel 1">
+	    First panel.<br/>
+	  </tags:panel>
+        </td>
+        <td>
+          <tags:panel color="#80ff80" bgcolor="#c0ffc0" title="Panel 2">
+	    Second panel.<br/>
+	    Second panel.<br/>
+	    Second panel.<br/>
+	    Second panel.<br/>
+	  </tags:panel>
+        </td>
+        <td>
+          <tags:panel color="#8080ff" bgcolor="#c0c0ff" title="Panel 3">
+	    Third panel.<br/>
+            <tags:panel color="#ff80ff" bgcolor="#ffc0ff" title="Inner">
+	      A panel in a panel.
+	    </tags:panel>
+	    Third panel.<br/>
+	  </tags:panel>
+        </td>
+      </tr>
+    </table>
+  </body>
+</html>

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/tagfiles/products.html
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/tagfiles/products.html	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/tagfiles/products.html	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,21 @@
+<html>
+<!--
+  Copyright (c) 1999 The Apache Software Foundation.  All rights 
+  reserved.
+-->
+<head>
+<title>View Source Code</title>
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+</head>
+
+<body bgcolor="#FFFFFF">
+<p><font color="#0000FF"><a href="products.jsp"><img src="../../images/execute.gif" align="right" border="0"></a>
+<a href="../../index.html"><img src="../../images/return.gif" width="24" height="24" align="right" border="0"></a></font></p>
+
+<h3><a href="products.jsp.html">Source Code for products.jsp<font color="#0000FF"></a>
+  </font> </h3>
+<h3><a href="displayProducts.tag.html">Source Code for displayProducts.tag<font color="#0000FF"></a>
+  </font> </h3>
+
+</body>
+</html>

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/tagfiles/products.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/tagfiles/products.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsp2/tagfiles/products.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,53 @@
+<!--
+  Copyright 2004 The Apache Software Foundation
+
+  Licensed 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.
+-->
+<%@ taglib prefix="tags" tagdir="/WEB-INF/tags" %>
+<html>
+  <head>
+    <title>JSP 2.0 Examples - Display Products Tag File</title>
+  </head>
+  <body>
+    <h1>JSP 2.0 Examples - Display Products Tag File</h1>
+    <hr>
+    <p>This JSP page invokes a tag file that displays a listing of 
+    products.  The custom tag accepts two fragments that enable
+    customization of appearance.  One for when the product is on sale
+    and one for normal price.</p>
+    <p>The tag is invoked twice, using different styles</p>
+    <hr>
+    <h2>Products</h2>
+    <tags:displayProducts>
+      <jsp:attribute name="normalPrice">
+	Item: ${name}<br/>
+	Price: ${price}
+      </jsp:attribute>
+      <jsp:attribute name="onSale">
+	Item: ${name}<br/>
+	<font color="red"><strike>Was: ${origPrice}</strike></font><br/>
+	<b>Now: ${salePrice}</b>
+      </jsp:attribute>
+    </tags:displayProducts>
+    <hr>
+    <h2>Products (Same tag, alternate style)</h2>
+    <tags:displayProducts>
+      <jsp:attribute name="normalPrice">
+	<b>${name}</b> @ ${price} ea.
+      </jsp:attribute>
+      <jsp:attribute name="onSale">
+	<b>${name}</b> @ ${salePrice} ea. (was: ${origPrice})
+      </jsp:attribute>
+    </tags:displayProducts>
+  </body>
+</html>

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsptoserv/hello.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsptoserv/hello.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsptoserv/hello.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,25 @@
+<html>
+<!--
+  Copyright 2004 The Apache Software Foundation
+
+  Licensed 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.
+-->
+<body bgcolor="white">
+
+<h1>
+I have been invoked by
+<% out.print (request.getAttribute("servletName").toString()); %>
+Servlet.
+</h1>
+
+</html>

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsptoserv/jsptoservlet.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsptoserv/jsptoservlet.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsptoserv/jsptoservlet.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,22 @@
+<html>
+<!--
+  Copyright 2004 The Apache Software Foundation
+
+  Licensed 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.
+-->
+<body bgcolor="white">
+
+<!-- Forward to a servlet -->
+<jsp:forward page="/servletToJsp" />
+
+</html>

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsptoserv/jts.html
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsptoserv/jts.html	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/jsptoserv/jts.html	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,33 @@
+<html>
+<!--
+  Copyright 2004 The Apache Software Foundation
+
+  Licensed 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>
+<title>Untitled Document</title>
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+</head>
+
+<body bgcolor="#FFFFFF">
+<p><font color="#0000FF"><a href="jsptoservlet.jsp"><img src="../images/execute.gif" align="right" border="0"></a><a href="../index.html"><img src="../images/return.gif" width="24" height="24" align="right" border="0"></a></font></p>
+
+<h3><a href="jsptoservlet.jsp.html">Source Code for JSP calling servlet <font color="#0000FF"></a>
+  </font> </h3>
+
+<h3><a href="servletToJsp.java.html">Source Code for Servlet calling JSP 
+<font color="#0000FF"></a> </font> </h3>
+
+</body>
+</html>

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/num/numguess.html
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/num/numguess.html	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/num/numguess.html	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,33 @@
+<html>
+<!--
+  Copyright 2004 The Apache Software Foundation
+
+  Licensed 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.
+
+  Number Guess Game
+  Written by Jason Hunter, CTO, K&A Software
+  http://www.servlets.com
+-->
+<head>
+<title>Untitled Document</title>
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+</head>
+
+<body bgcolor="#FFFFFF">
+<p><font color="#0000FF"><a href="numguess.jsp"><img src="../images/execute.gif" align="right" border="0"></a><a href="../index.html"><img src="../images/return.gif" width="24" height="24" align="right" border="0"></a></font></p>
+
+<h3><a href="numguess.jsp.html">Source Code for Numguess Example<font color="#0000FF"></a>
+  </font> </h3>
+
+</body>
+</html>

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/num/numguess.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/num/numguess.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/num/numguess.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,68 @@
+<!--
+  Copyright 2004 The Apache Software Foundation
+
+  Licensed 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.
+
+  Number Guess Game
+  Written by Jason Hunter, CTO, K&A Software
+  http://www.servlets.com
+-->
+
+<%@ page import = "num.NumberGuessBean" %>
+
+<jsp:useBean id="numguess" class="num.NumberGuessBean" scope="session"/>
+<jsp:setProperty name="numguess" property="*"/>
+
+<html>
+<head><title>Number Guess</title></head>
+<body bgcolor="white">
+<font size=4>
+
+<% if (numguess.getSuccess()) { %>
+
+  Congratulations!  You got it.
+  And after just <%= numguess.getNumGuesses() %> tries.<p>
+
+  <% numguess.reset(); %>
+
+  Care to <a href="numguess.jsp">try again</a>?
+
+<% } else if (numguess.getNumGuesses() == 0) { %>
+
+  Welcome to the Number Guess game.<p>
+
+  I'm thinking of a number between 1 and 100.<p>
+
+  <form method=get>
+  What's your guess? <input type=text name=guess>
+  <input type=submit value="Submit">
+  </form>
+
+<% } else { %>
+
+  Good guess, but nope.  Try <b><%= numguess.getHint() %></b>.
+
+  You have made <%= numguess.getNumGuesses() %> guesses.<p>
+
+  I'm thinking of a number between 1 and 100.<p>
+
+  <form method=get>
+  What's your guess? <input type=text name=guess>
+  <input type=submit value="Submit">
+  </form>
+
+<% } %>
+
+</font>
+</body>
+</html>

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/plugin/applet/Clock2.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/plugin/applet/Clock2.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/plugin/applet/Clock2.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,212 @@
+/*
+* Copyright 2004 The Apache Software Foundation
+*
+* Licensed 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.
+*/
+
+import java.util.*;
+import java.awt.*;
+import java.applet.*;
+import java.text.*;
+
+/**
+ * Time!
+ *
+ * @author Rachel Gollub
+ */
+
+public class Clock2 extends Applet implements Runnable {
+    Thread timer;                // The thread that displays clock
+    int lastxs, lastys, lastxm,
+        lastym, lastxh, lastyh;  // Dimensions used to draw hands 
+    SimpleDateFormat formatter;  // Formats the date displayed
+    String lastdate;             // String to hold date displayed
+    Font clockFaceFont;          // Font for number display on clock
+    Date currentDate;            // Used to get date to display
+    Color handColor;             // Color of main hands and dial
+    Color numberColor;           // Color of second hand and numbers
+
+    public void init() {
+        int x,y;
+        lastxs = lastys = lastxm = lastym = lastxh = lastyh = 0;
+        formatter = new SimpleDateFormat ("EEE MMM dd hh:mm:ss yyyy", Locale.getDefault());
+        currentDate = new Date();
+        lastdate = formatter.format(currentDate);
+        clockFaceFont = new Font("Serif", Font.PLAIN, 14);
+        handColor = Color.blue;
+        numberColor = Color.darkGray;
+
+        try {
+            setBackground(new Color(Integer.parseInt(getParameter("bgcolor"),16)));
+        } catch (Exception E) { }
+        try {
+            handColor = new Color(Integer.parseInt(getParameter("fgcolor1"),16));
+        } catch (Exception E) { }
+        try {
+            numberColor = new Color(Integer.parseInt(getParameter("fgcolor2"),16));
+        } catch (Exception E) { }
+        resize(300,300);              // Set clock window size
+    }
+
+    // Plotpoints allows calculation to only cover 45 degrees of the circle,
+    // and then mirror
+    public void plotpoints(int x0, int y0, int x, int y, Graphics g) {
+        g.drawLine(x0+x,y0+y,x0+x,y0+y);
+        g.drawLine(x0+y,y0+x,x0+y,y0+x);
+        g.drawLine(x0+y,y0-x,x0+y,y0-x);
+        g.drawLine(x0+x,y0-y,x0+x,y0-y);
+        g.drawLine(x0-x,y0-y,x0-x,y0-y);
+        g.drawLine(x0-y,y0-x,x0-y,y0-x);
+        g.drawLine(x0-y,y0+x,x0-y,y0+x);
+        g.drawLine(x0-x,y0+y,x0-x,y0+y);
+    }
+
+    // Circle is just Bresenham's algorithm for a scan converted circle
+    public void circle(int x0, int y0, int r, Graphics g) {
+        int x,y;
+        float d;
+        x=0;
+        y=r;
+        d=5/4-r;
+        plotpoints(x0,y0,x,y,g);
+
+        while (y>x){
+            if (d<0) {
+                d=d+2*x+3;
+                x++;
+            }
+            else {
+                d=d+2*(x-y)+5;
+                x++;
+                y--;
+            }
+            plotpoints(x0,y0,x,y,g);
+        }
+    }
+
+    // Paint is the main part of the program
+    public void paint(Graphics g) {
+        int xh, yh, xm, ym, xs, ys, s = 0, m = 10, h = 10, xcenter, ycenter;
+        String today;
+
+        currentDate = new Date();
+        SimpleDateFormat formatter = new SimpleDateFormat("s",Locale.getDefault());
+        try {
+            s = Integer.parseInt(formatter.format(currentDate));
+        } catch (NumberFormatException n) {
+            s = 0;
+        }
+        formatter.applyPattern("m");
+        try {
+            m = Integer.parseInt(formatter.format(currentDate));
+        } catch (NumberFormatException n) {
+            m = 10;
+        }    
+        formatter.applyPattern("h");
+        try {
+            h = Integer.parseInt(formatter.format(currentDate));
+        } catch (NumberFormatException n) {
+            h = 10;
+        }
+        formatter.applyPattern("EEE MMM dd HH:mm:ss yyyy");
+        today = formatter.format(currentDate);
+        xcenter=80;
+        ycenter=55;
+    
+    // a= s* pi/2 - pi/2 (to switch 0,0 from 3:00 to 12:00)
+    // x = r(cos a) + xcenter, y = r(sin a) + ycenter
+    
+        xs = (int)(Math.cos(s * 3.14f/30 - 3.14f/2) * 45 + xcenter);
+        ys = (int)(Math.sin(s * 3.14f/30 - 3.14f/2) * 45 + ycenter);
+        xm = (int)(Math.cos(m * 3.14f/30 - 3.14f/2) * 40 + xcenter);
+        ym = (int)(Math.sin(m * 3.14f/30 - 3.14f/2) * 40 + ycenter);
+        xh = (int)(Math.cos((h*30 + m/2) * 3.14f/180 - 3.14f/2) * 30 + xcenter);
+        yh = (int)(Math.sin((h*30 + m/2) * 3.14f/180 - 3.14f/2) * 30 + ycenter);
+    
+    // Draw the circle and numbers
+    
+        g.setFont(clockFaceFont);
+        g.setColor(handColor);
+        circle(xcenter,ycenter,50,g);
+        g.setColor(numberColor);
+        g.drawString("9",xcenter-45,ycenter+3); 
+        g.drawString("3",xcenter+40,ycenter+3);
+        g.drawString("12",xcenter-5,ycenter-37);
+        g.drawString("6",xcenter-3,ycenter+45);
+
+    // Erase if necessary, and redraw
+    
+        g.setColor(getBackground());
+        if (xs != lastxs || ys != lastys) {
+            g.drawLine(xcenter, ycenter, lastxs, lastys);
+            g.drawString(lastdate, 5, 125);
+        }
+        if (xm != lastxm || ym != lastym) {
+            g.drawLine(xcenter, ycenter-1, lastxm, lastym);
+            g.drawLine(xcenter-1, ycenter, lastxm, lastym); }
+        if (xh != lastxh || yh != lastyh) {
+            g.drawLine(xcenter, ycenter-1, lastxh, lastyh);
+            g.drawLine(xcenter-1, ycenter, lastxh, lastyh); }
+        g.setColor(numberColor);
+        g.drawString("", 5, 125);
+        g.drawString(today, 5, 125);    
+        g.drawLine(xcenter, ycenter, xs, ys);
+        g.setColor(handColor);
+        g.drawLine(xcenter, ycenter-1, xm, ym);
+        g.drawLine(xcenter-1, ycenter, xm, ym);
+        g.drawLine(xcenter, ycenter-1, xh, yh);
+        g.drawLine(xcenter-1, ycenter, xh, yh);
+        lastxs=xs; lastys=ys;
+        lastxm=xm; lastym=ym;
+        lastxh=xh; lastyh=yh;
+        lastdate = today;
+        currentDate=null;
+    }
+
+    public void start() {
+        timer = new Thread(this);
+        timer.start();
+    }
+
+    public void stop() {
+        timer = null;
+    }
+
+    public void run() {
+        Thread me = Thread.currentThread();
+        while (timer == me) {
+            try {
+                Thread.currentThread().sleep(100);
+            } catch (InterruptedException e) {
+            }
+            repaint();
+        }
+    }
+
+    public void update(Graphics g) {
+        paint(g);
+    }
+
+    public String getAppletInfo() {
+        return "Title: A Clock \nAuthor: Rachel Gollub, 1995 \nAn analog clock.";
+    }
+  
+    public String[][] getParameterInfo() {
+        String[][] info = {
+            {"bgcolor", "hexadecimal RGB number", "The background color. Default is the color of your browser."},
+            {"fgcolor1", "hexadecimal RGB number", "The color of the hands and dial. Default is blue."},
+            {"fgcolor2", "hexadecimal RGB number", "The color of the seconds hand and numbers. Default is dark gray."}
+        };
+        return info;
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/plugin/plugin.html
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/plugin/plugin.html	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/plugin/plugin.html	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,29 @@
+<html>
+<!--
+  Copyright 2004 The Apache Software Foundation
+
+  Licensed 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>
+<title>Untitled Document</title>
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+</head>
+
+<body bgcolor="#FFFFFF">
+<p><font color="#0000FF"><a href="plugin.jsp"><img src="../images/execute.gif" align="right" border="0"></a><a href="../index.html"><img src="../images/return.gif" width="24" height="24" align="right" border="0"></a></font></p>
+
+<h3><a href="plugin.jsp.html">Source Code for Plugin Example<font color="#0000FF"></a>
+  </font> </h3>
+
+</body>
+</html>

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/plugin/plugin.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/plugin/plugin.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/plugin/plugin.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,33 @@
+<html>
+<!--
+  Copyright 2004 The Apache Software Foundation
+
+  Licensed 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.
+-->
+<title> Plugin example </title>
+<body bgcolor="white">
+<h3> Current time is : </h3>
+<jsp:plugin type="applet" code="Clock2.class" codebase="applet" jreversion="1.2" width="160" height="150" >
+    <jsp:fallback>
+        Plugin tag OBJECT or EMBED not supported by browser.
+    </jsp:fallback>
+</jsp:plugin>
+<p>
+<h4>
+<font color=red> 
+The above applet is loaded using the Java Plugin from a jsp page using the
+plugin tag.
+</font>
+</h4>
+</body>
+</html>

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/security/protected/error.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/security/protected/error.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/security/protected/error.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,24 @@
+<!--
+  Copyright 2004 The Apache Software Foundation
+
+  Licensed 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.
+-->
+<html>
+<head>
+<title>Error Page For Examples</title>
+</head>
+<body bgcolor="white">
+Invalid username and/or password, please try
+<a href='<%= response.encodeURL("login.jsp") %>'>again</a>.
+</body>
+</html>

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/security/protected/index.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/security/protected/index.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/security/protected/index.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,78 @@
+<!--
+  Copyright 2004 The Apache Software Foundation
+
+  Licensed 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.
+-->
+<%
+  if (request.getParameter("logoff") != null) {
+    session.invalidate();
+    response.sendRedirect("index.jsp");
+    return;
+  }
+%>
+<html>
+<head>
+<title>Protected Page for Examples</title>
+</head>
+<body bgcolor="white">
+
+You are logged in as remote user <b><%= request.getRemoteUser() %></b>
+in session <b><%= session.getId() %></b><br><br>
+
+<%
+  if (request.getUserPrincipal() != null) {
+%>
+    Your user principal name is
+    <b><%= request.getUserPrincipal().getName() %></b><br><br>
+<%
+  } else {
+%>
+    No user principal could be identified.<br><br>
+<%
+  }
+%>
+
+<%
+  String role = request.getParameter("role");
+  if (role == null)
+    role = "";
+  if (role.length() > 0) {
+    if (request.isUserInRole(role)) {
+%>
+      You have been granted role
+      <b><%= util.HTMLFilter.filter(role) %></b><br><br>
+<%
+    } else {
+%>
+      You have <i>not</i> been granted role
+      <b><%= util.HTMLFilter.filter(role) %></b><br><br>
+<%
+    }
+  }
+%>
+
+To check whether your username has been granted a particular role,
+enter it here:
+<form method="GET" action='<%= response.encodeURL("index.jsp") %>'>
+<input type="text" name="role" value="<%= util.HTMLFilter.filter(role) %>">
+</form>
+<br><br>
+
+If you have configured this app for form-based authentication, you can log
+off by clicking
+<a href='<%= response.encodeURL("index.jsp?logoff=true") %>'>here</a>.
+This should cause you to be returned to the logon page after the redirect
+that is performed.
+
+</body>
+</html>

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/security/protected/login.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/security/protected/login.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/security/protected/login.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,37 @@
+<!--
+  Copyright 2004 The Apache Software Foundation
+
+  Licensed 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.
+-->
+<html>
+<head>
+<title>Login Page for Examples</title>
+<body bgcolor="white">
+<form method="POST" action='<%= response.encodeURL("j_security_check") %>' >
+  <table border="0" cellspacing="5">
+    <tr>
+      <th align="right">Username:</th>
+      <td align="left"><input type="text" name="j_username"></td>
+    </tr>
+    <tr>
+      <th align="right">Password:</th>
+      <td align="left"><input type="password" name="j_password"></td>
+    </tr>
+    <tr>
+      <td align="right"><input type="submit" value="Log In"></td>
+      <td align="left"><input type="reset"></td>
+    </tr>
+  </table>
+</form>
+</body>
+</html>

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/sessions/DummyCart.html
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/sessions/DummyCart.html	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/sessions/DummyCart.html	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,55 @@
+<HTML>
+<!--
+  Copyright 2004 The Apache Software Foundation
+
+  Licensed 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>
+<title>
+sessions.DummyCart Bean Properties
+</title>
+<BODY BGCOLOR="white">
+<H2>
+sessions.DummyCart Bean Properties
+</H2>
+<HR>
+<DL>
+<DT>public class <B>DummyCart</B><DT>extends Object</DL>
+
+<P>
+<HR>
+
+<P>
+
+<TABLE BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0">
+<TR BGCOLOR="#EEEEFF">
+<TD COLSPAN=3><FONT SIZE="+2">
+<B>Properties Summary</B></FONT></TD>
+</TR>
+<TR BGCOLOR="white">
+<td align="right" valign="top" width="1%">
+<FONT SIZE="-1">
+String
+</FONT></TD>
+<TD><B>DummyCart:items</B>
+<BR>
+       </TD>
+<td width="1%">
+<FONT SIZE="-1">
+Multi
+</FONT></TD>
+</TABLE>
+<HR>
+</BODY>
+</HTML>

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/sessions/carts.html
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/sessions/carts.html	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/sessions/carts.html	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,52 @@
+<html>
+<!--
+  Copyright 2004 The Apache Software Foundation
+
+  Licensed 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>
+    <title>carts</title>
+</head>
+
+ <body bgcolor="white">
+<font size = 5 color="#CC0000">
+
+<form type=POST action=carts.jsp>
+<BR>
+Please enter item to add or remove:
+<br>
+Add Item:
+
+<SELECT NAME="item">
+<OPTION>Beavis & Butt-head Video collection
+<OPTION>X-files movie
+<OPTION>Twin peaks tapes
+<OPTION>NIN CD
+<OPTION>JSP Book
+<OPTION>Concert tickets
+<OPTION>Love life
+<OPTION>Switch blade
+<OPTION>Rex, Rugs & Rock n' Roll
+</SELECT>
+
+
+<br> <br>
+<INPUT TYPE=submit name="submit" value="add">
+<INPUT TYPE=submit name="submit" value="remove">
+
+</form>
+       
+</FONT>
+</body>
+</html>

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/sessions/carts.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/sessions/carts.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/sessions/carts.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,43 @@
+<html>
+<!--
+  Copyright 2004 The Apache Software Foundation
+
+  Licensed 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.
+-->
+
+<jsp:useBean id="cart" scope="session" class="sessions.DummyCart" />
+
+<jsp:setProperty name="cart" property="*" />
+<%
+	cart.processRequest(request);
+%>
+
+
+<FONT size = 5 COLOR="#CC0000">
+<br> You have the following items in your cart:
+<ol>
+<% 
+	String[] items = cart.getItems();
+	for (int i=0; i<items.length; i++) {
+%>
+<li> <% out.print(util.HTMLFilter.filter(items[i])); %> 
+<%
+	}
+%>
+</ol>
+
+</FONT>
+
+<hr>
+<%@ include file ="/sessions/carts.html" %>
+</html>

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/sessions/crt.html
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/sessions/crt.html	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/sessions/crt.html	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,33 @@
+<html>
+<!--
+  Copyright 2004 The Apache Software Foundation
+
+  Licensed 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>
+<title>Untitled Document</title>
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+</head>
+
+<body bgcolor="#FFFFFF">
+<p><font color="#0000FF"><a href="carts.html"><img src="../images/execute.gif" align="right" border="0"></a><a href="../index.html"><img src="../images/return.gif" width="24" height="24" align="right" border="0"></a></font></p>
+
+<h3><a href="carts.jsp.html">Source Code for Cart Example<font color="#0000FF"></a>
+  </font> </h3>
+
+<h3><a href="DummyCart.html">Property Sheet for DummyCart
+<font color="#0000FF"></a> </font> </h3>
+
+</body>
+</html>

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/simpletag/foo.html
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/simpletag/foo.html	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/simpletag/foo.html	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,29 @@
+<html>
+<!--
+  Copyright 2004 The Apache Software Foundation
+
+  Licensed 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>
+<title>Untitled Document</title>
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+</head>
+
+<body bgcolor="#FFFFFF">
+<p><font color="#0000FF"><a href="foo.jsp"><img src="../images/execute.gif" align="right" border="0"></a><a href="../index.html"><img src="../images/return.gif" width="24" height="24" align="right" border="0"></a></font></p>
+
+<h3><a href="foo.jsp.html">Source Code for the Simple Tag Example<font color="#0000FF"></a>
+  </font> </h3>
+
+</body>
+</html>

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/simpletag/foo.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/simpletag/foo.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/simpletag/foo.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,37 @@
+<html>
+<!--
+  Copyright 2004 The Apache Software Foundation
+
+  Licensed 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.
+-->
+<body>
+<%@ taglib uri="http://jakarta.apache.org/tomcat/examples-taglib" prefix="eg"%>
+
+Radio stations that rock:
+
+<ul>
+<eg:foo att1="98.5" att2="92.3" att3="107.7">
+<li><%= member %></li>
+</eg:foo>
+</ul>
+
+<eg:log>
+Did you see me on the stderr window?
+</eg:log>
+
+<eg:log toBrowser="true">
+Did you see me on the browser window as well?
+</eg:log>
+
+</body>
+</html>

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/snp/snoop.html
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/snp/snoop.html	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/snp/snoop.html	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,30 @@
+<html>
+<!--
+  Copyright 2004 The Apache Software Foundation
+
+  Licensed 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>
+<title>Untitled Document</title>
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+</head>
+
+<body bgcolor="#FFFFFF">
+<p><font color="#0000FF"><a href="snoop.jsp"><img src="../images/execute.gif" align="right" border="0"></a><a href="../index.html"><img src="../images/return.gif" width="24" height="24" align="right" border="0"></a></font></p>
+
+<h3><a href="snoop.jsp.html">Source Code for Request Parameters Example<font color="#0000FF"></a>
+  </font> </h3>
+
+</body>
+</html>

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/snp/snoop.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/snp/snoop.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/snp/snoop.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,55 @@
+<html>
+<!--
+  Copyright 2004 The Apache Software Foundation
+
+  Licensed 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.
+-->
+
+<body bgcolor="white">
+<h1> Request Information </h1>
+<font size="4">
+JSP Request Method: <% out.print(util.HTMLFilter.filter(request.getMethod())); %>
+<br>
+Request URI: <%= request.getRequestURI() %>
+<br>
+Request Protocol: <%= request.getProtocol() %>
+<br>
+Servlet path: <%= request.getServletPath() %>
+<br>
+Path info: <% out.print(util.HTMLFilter.filter(request.getPathInfo())); %>
+<br>
+Query string: <% out.print(util.HTMLFilter.filter(request.getQueryString())); %>
+<br>
+Content length: <%= request.getContentLength() %>
+<br>
+Content type: <% out.print(util.HTMLFilter.filter(request.getContentType())); %>
+<br>
+Server name: <%= request.getServerName() %>
+<br>
+Server port: <%= request.getServerPort() %>
+<br>
+Remote user: <%= request.getRemoteUser() %>
+<br>
+Remote address: <%= request.getRemoteAddr() %>
+<br>
+Remote host: <%= request.getRemoteHost() %>
+<br>
+Authorization scheme: <%= request.getAuthType() %> 
+<br>
+Locale: <%= request.getLocale() %>
+<hr>
+The browser you are using is <% out.print(util.HTMLFilter.filter(request.getHeader("User-Agent"))); %>
+<hr>
+</font>
+</body>
+</html>

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/source.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/source.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/source.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,19 @@
+<!--
+  Copyright 2004 The Apache Software Foundation
+
+  Licensed 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.
+-->
+<%@ taglib uri="http://jakarta.apache.org/tomcat/examples-taglib"
+        prefix="eg" %>
+
+<eg:ShowSource jspFile="<%= request.getQueryString() %>"/>

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/tagplugin/choose.html
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/tagplugin/choose.html	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/tagplugin/choose.html	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,35 @@
+<!--
+  Copyright 2004 The Apache Software Foundation
+
+  Licensed 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.
+-->
+<html>
+<head>
+<title>View Source Code</title>
+</head>
+
+<body bgcolor="#FFFFFF">
+<p><font color="#0000FF">
+  <a href="choose.jsp">
+    <img src="../images/execute.gif" align="right" border="0"></a>
+  <a href="../index.html">
+    <img src="../images/return.gif" width="24" height="24" align="right" border="0">
+  </a></font>
+</p>
+
+<h3>
+  <a href="choose.jsp.html">Source Code for choose.jsp<font color="#0000FF"/></a>
+</h3>
+
+</body>
+</html>

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/tagplugin/choose.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/tagplugin/choose.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/tagplugin/choose.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,57 @@
+<!--
+  Copyright 2004 The Apache Software Foundation
+
+  Licensed 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.
+-->
+<html>
+  <head>
+    <title>Tag Examples - choose</title>
+  </head>
+  <body>
+    <h1>Tag Plugin Examples - &lt;c:choose></h1>
+
+    <hr>
+    </br>
+    <a href="notes.html">Plugin Introductory Notes<font <font color="#0000FF"></
+a>
+    <br/>
+    <a href="howto.html">Brief Instructions for Writing Plugins<font color="#000
+0
+FF"></a>
+    <br/> <br/>
+    <hr>
+
+    <font color="#000000"/>
+    </br>
+
+    <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
+
+    <c:forEach var="index" begin="0" end="4">
+      # ${index}: 
+      <c:choose>
+	<c:when test="${index == 1}">
+          One!</br>
+	</c:when>
+	<c:when test="${index == 4}">
+          Four!</br>
+	</c:when>
+	<c:when test="${index == 3}">
+          Three!</br>
+	</c:when>
+	<c:otherwise>
+          Huh?</br>
+	</c:otherwise>
+      </c:choose>
+    </c:forEach>
+  </body>
+</html> 

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/tagplugin/foreach.html
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/tagplugin/foreach.html	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/tagplugin/foreach.html	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,35 @@
+<!--
+  Copyright 2004 The Apache Software Foundation
+
+  Licensed 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.
+-->
+<html>
+<head>
+<title>View Source Code</title>
+</head>
+
+<body bgcolor="#FFFFFF">
+<p><font color="#0000FF">
+  <a href="foreach.jsp">
+    <img src="../images/execute.gif" align="right" border="0"></a>
+  <a href="../index.html">
+    <img src="../images/return.gif" width="24" height="24" align="right" border="0">
+  </a></font>
+</p>
+
+<h3>
+  <a href="foreach.jsp.html">Source Code for foreach.jsp<font color="#0000FF"/></a>
+</h3>
+
+</body>
+</html>

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/tagplugin/foreach.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/tagplugin/foreach.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/tagplugin/foreach.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,56 @@
+<!--
+  Copyright 2004 The Apache Software Foundation
+
+  Licensed 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.
+-->
+<html>
+  <head>
+    <title>Tag Plugin Examples: forEach</title>
+  </head>
+  <body>
+    <h1>Tag Plugin Examples - &lt;c:forEach></h1>
+
+    <hr>
+    </br>
+    <a href="notes.html">Plugin Introductory Notes<font <font color="#0000FF"></
+a>
+    <br/>
+    <a href="howto.html">Brief Instructions for Writing Plugins<font color="#0000
+FF"></a>
+    <br/> <br/>
+    <hr>
+
+    <font color="#000000"/>
+    </br>
+
+    <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
+    <%@ page import="java.util.Vector" %>
+
+    <h3>Iterating over a range</h3>
+    <c:forEach var="item" begin="1" end="10">
+        ${item}
+    </c:forEach>
+
+    <% Vector v = new Vector();
+	v.add("One"); v.add("Two"); v.add("Three"); v.add("Four");
+
+	pageContext.setAttribute("vector", v);
+    %>
+
+    <h3>Iterating over a Vector</h3>
+
+    <c:forEach items="${vector}" var="item" >
+	${item}
+    </c:forEach>
+  </body>
+</html> 

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/tagplugin/howto.html
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/tagplugin/howto.html	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/tagplugin/howto.html	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,42 @@
+<!--
+  Copyright 2004 The Apache Software Foundation
+
+  Licensed 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.
+-->
+<html>
+  <head>
+    <title>Tag Plugin Implementation</title>
+    <h2>How to write tag plugins</h2>
+    <p>
+      To write a plugin, you'll need to download the source for Tomcat 5.
+      There are two steps:
+    <ol>
+      <li>
+        Implement the plugin class.<p/>
+        This class, which implements 
+        <tt>org.apache.jasper.compiler.tagplugin.TagPlugin</tt>
+        instructs Jasper what Java codes to generate in place of the tag
+        handler calls.
+        See Javadoc for <tt>org.apache.jasper.compiler.tagplugin.TagPlugin</tt>
+        for details.
+      </li>
+
+      <li>
+        Create the plugin descriptor file <tt> WEB-INF/tagPlugins.xml</tt><p/>
+        This file
+        specifies the plugin classes and their corresponding tag handler
+        classes.
+      </li>
+    </ol>
+  </head>
+</html>

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/tagplugin/if.html
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/tagplugin/if.html	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/tagplugin/if.html	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,35 @@
+<!--
+  Copyright 2004 The Apache Software Foundation
+
+  Licensed 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.
+-->
+<html>
+<head>
+<title>View Source Code</title>
+</head>
+
+<body bgcolor="#FFFFFF">
+<p><font color="#0000FF">
+  <a href="if.jsp">
+    <img src="../images/execute.gif" align="right" border="0"></a>
+  <a href="../index.html">
+    <img src="../images/return.gif" width="24" height="24" align="right" border="0">
+  </a></font>
+</p>
+
+<h3>
+  <a href="if.jsp.html">Source Code for if.jsp<font color="#0000FF"/></a>
+</h3>
+
+</body>
+</html>

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/tagplugin/if.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/tagplugin/if.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/tagplugin/if.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,44 @@
+<!--
+  Copyright 2004 The Apache Software Foundation
+
+  Licensed 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.
+-->
+<html>
+  <head>
+    <title>Tag Plugin Examples: if</title>
+  </head>
+  <body>
+    <h1>Tag Plugin Examples - &lt;c:if></h1>
+
+    <hr>
+    </br>
+    <a href="notes.html">Plugin Introductory Notes<font <font color="#0000FF"></a>
+    <br/>
+    <a href="howto.html">Brief Instructions for Wrieting Plugins<font color="#0000FF"></a>
+    <br/> <br/>
+    <hr>
+
+    <font color="#000000"/>
+    </br>
+    <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
+
+    <h3>Set the test result to a variable</h3>
+    <c:if test="${1==1}" var="theTruth" scope="session"/>
+    The result of testing for (1==1) is: ${theTruth}
+
+    <h3>Conditionally execute the body</h3>
+    <c:if test="${2>0}">
+	It's true that (2>0)!
+    </c:if>
+  </body>
+</html> 

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/tagplugin/notes.html
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/tagplugin/notes.html	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/tagplugin/notes.html	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,38 @@
+<!--
+  Copyright 2004 The Apache Software Foundation
+
+  Licensed 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.
+-->
+<html>
+  <head>
+    <title>Tag Plugin Introduction</title>
+    <h2>Tag Plugins: Introductory Notes</h2>
+    <p>
+      Tomcat 5 provides a framework for implementing tag plugins.  The
+      plugins instruct Jasper, at translation time, to replace tag handler
+      calls with Java scriptlets.
+      The framework allows tag library authors to implement plugins for
+      their tags.
+    </p>
+    <p>
+      Tomcat 5 is released with plugins for several JSTL tags.  Note
+      that these plugins work with JSTL 1.1 as well as JSTL 1.0, though
+      the examples uses JSTL 1.1 and JSP 2.0.  
+      These plugins are not complete (for instance, some item types not
+      handled in &lt;c:if>).
+      They do serve as examples to show plugins in action (just
+      examine the generated Java files), and how they can be implemented.
+    </p>
+  </head>
+</html>
+

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/xml/xml.html
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/xml/xml.html	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/xml/xml.html	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,30 @@
+<html>
+<!--
+  Copyright 2004 The Apache Software Foundation
+
+  Licensed 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>
+<title>Untitled Document</title>
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+</head>
+
+<body bgcolor="#FFFFFF">
+<p><font color="#0000FF"><a href="xml.jsp"><img src="../images/execute.gif" align="right" border="0"></a><a href="../index.html"><img src="../images/return.gif" width="24" height="24" align="right" border="0"></a></font></p>
+
+<h3><a href="xml.jsp.html">Source Code for XML syntax Example<font color="#0000FF"></a>
+  </font> </h3>
+
+</body>
+</html>

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/xml/xml.jsp
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/xml/xml.jsp	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/examples/xml/xml.jsp	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,69 @@
+<?xml version="1.0"?>
+<!--
+  Copyright 2004 The Apache Software Foundation
+
+  Licensed 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.
+-->
+<jsp:root xmlns:jsp="http://java.sun.com/JSP/Page"
+  version="1.2">
+<jsp:directive.page contentType="text/html"/>
+<jsp:directive.page import="java.util.Date, java.util.Locale"/>
+<jsp:directive.page import="java.text.*"/>
+
+<jsp:declaration>
+  String getDateTimeStr(Locale l) {
+    DateFormat df = SimpleDateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.MEDIUM, l);
+    return df.format(new Date());
+  }
+</jsp:declaration>
+
+<html>
+<head>
+  <title>Example JSP in XML format</title>
+</head>
+
+<body>
+This is the output of a simple JSP using XML format. 
+<br />
+
+<div>Use a jsp:scriptlet to loop from 1 to 10: </div>
+<jsp:scriptlet>
+// Note we need to declare CDATA because we don't escape the less than symbol
+<![CDATA[
+  for (int i = 1; i<=10; i++) {
+    out.println(i);
+    if (i < 10) {
+      out.println(", ");
+    }
+  }
+]]>
+</jsp:scriptlet>
+
+<!-- Because I omit br's end tag, declare it as CDATA -->
+<![CDATA[
+  <br><br>
+]]>
+
+<div align="left">
+  Use a jsp:expression to write the date and time in the browser's locale: 
+  <jsp:expression>getDateTimeStr(request.getLocale())</jsp:expression>
+</div>
+
+
+<jsp:text>
+  &lt;p&gt;This sentence is enclosed in a jsp:text element.&lt;/p&gt;
+</jsp:text>
+
+</body>
+</html>
+</jsp:root>

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/ant/task/Txt2Html.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/ant/task/Txt2Html.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/ant/task/Txt2Html.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,163 @@
+/*
+* Copyright 2004 The Apache Software Foundation
+*
+* Licensed 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 task;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.DirectoryScanner;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.types.FileSet;
+
+/**
+ * Ant task to convert a given set of files from Text to HTML.
+ * Inserts an HTML header including pre tags and replaces special characters
+ * with their HTML escaped equivalents.
+ *
+ * <p>This task is currently used by the ant script to build our examples</p>
+ *
+ * @author Mark Roth
+ */
+public class Txt2Html 
+    extends Task 
+{
+    
+    /** The directory to contain the resulting files */
+    private File todir;
+    
+    /** The file to be converted into HTML */
+    private List filesets = new LinkedList();
+    
+    /**
+     * Sets the directory to contain the resulting files
+     *
+     * @param todir The directory
+     */
+    public void setTodir( File todir ) {
+        this.todir = todir;
+    }
+    
+    /**
+     * Sets the files to be converted into HTML
+     *
+     * @param fileset The fileset to be converted.
+     */
+    public void addFileset( FileSet fs ) {
+        filesets.add( fs );
+    }
+    
+    /**
+     * Perform the conversion
+     *
+     * @param BuildException Thrown if an error occurs during execution of
+     *    this task.
+     */
+    public void execute() 
+        throws BuildException 
+    {
+        int count = 0;
+        
+        // Step through each file and convert.
+        Iterator iter = filesets.iterator();
+        while( iter.hasNext() ) {
+            FileSet fs = (FileSet)iter.next();
+            DirectoryScanner ds = fs.getDirectoryScanner( project );
+            File basedir = ds.getBasedir();
+            String[] files = ds.getIncludedFiles();
+            for( int i = 0; i < files.length; i++ ) {
+                File from = new File( basedir, files[i] );
+                File to = new File( todir, files[i] + ".html" );
+                if( !to.exists() || 
+                    (from.lastModified() > to.lastModified()) ) 
+                {
+                    log( "Converting file '" + from.getAbsolutePath() + 
+                        "' to '" + to.getAbsolutePath(), Project.MSG_VERBOSE );
+                    try {
+                        convert( from, to );
+                    }
+                    catch( IOException e ) {
+                        throw new BuildException( "Could not convert '" + 
+                            from.getAbsolutePath() + "' to '" + 
+                            to.getAbsolutePath() + "'", e );
+                    }
+                    count++;
+                }
+            }
+            if( count > 0 ) {
+                log( "Converted " + count + " file" + (count > 1 ? "s" : "") + 
+                    " to " + todir.getAbsolutePath() );
+            }
+        }
+    }
+    
+    /**
+     * Perform the actual copy and conversion
+     *
+     * @param from The input file
+     * @param to The output file
+     * @throws IOException Thrown if an error occurs during the conversion
+     */
+    private void convert( File from, File to )
+        throws IOException
+    {
+        // Open files:
+        BufferedReader in = new BufferedReader( new FileReader( from ) );
+        PrintWriter out = new PrintWriter( new FileWriter( to ) );
+        
+        // Output header:
+        out.println( "<html><body><pre>" );
+        
+        // Convert, line-by-line:
+        String line;
+        while( (line = in.readLine()) != null ) {
+            StringBuffer result = new StringBuffer();
+            int len = line.length();
+            for( int i = 0; i < len; i++ ) {
+                char c = line.charAt( i );
+                switch( c ) {
+                    case '&':
+                        result.append( "&amp;" );
+                        break;
+                    case '<':
+                        result.append( "&lt;" );
+                        break;
+                    default:
+                        result.append( c );
+                }
+            }
+            out.println( result.toString() );
+        }
+        
+        // Output footer:
+        out.println( "</pre></body></html>" );
+        
+        // Close streams:
+        out.close();
+        in.close();
+    }
+    
+}
+
+

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/etc/manifest
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/etc/manifest	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/etc/manifest	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,10 @@
+Manifest-version: 1.0
+
+Name: javax/servlet/jsp/
+Specification-Title: Java API for JavaServer Pages
+Specification-Version: 2.0
+Specification-Vendor: Sun Microsystems, Inc.
+Implementation-Title: javax.servlet.jsp
+Implementation-Version: 2.0. at implementation.revision@
+Implementation-Vendor: Apache Software Foundation
+

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/dtd/jsp_2_0.xsd
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/dtd/jsp_2_0.xsd	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/dtd/jsp_2_0.xsd	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,322 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Copyright 2004 The Apache Software Foundation
+
+  Licensed 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.
+-->
+<xsd:schema xmlns="http://www.w3.org/2001/XMLSchema"
+	    targetNamespace="http://java.sun.com/xml/ns/j2ee"
+	    xmlns:j2ee="http://java.sun.com/xml/ns/j2ee"
+	    xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+	    elementFormDefault="qualified"
+	    attributeFormDefault="unqualified"
+	    version="2.0">
+  <xsd:annotation>
+    <xsd:documentation>
+      @(#)jsp_2_0.xsds	1.17 03/18/03
+    </xsd:documentation>
+  </xsd:annotation>
+
+  <xsd:annotation>
+    <xsd:documentation>
+
+      Copyright 2002 Sun Microsystems, Inc., 901 San Antonio
+      Road, Palo Alto, California 94303, U.S.A. All rights
+      reserved.
+
+      Sun Microsystems, Inc. has intellectual property rights
+      relating to technology described in this document. In
+      particular, and without limitation, these intellectual
+      property rights may include one or more of the U.S. patents
+      listed at http://www.sun.com/patents and one or more
+      additional patents or pending patent applications in the
+      U.S. and other countries.
+
+      This document and the technology which it describes are
+      distributed under licenses restricting their use, copying,
+      distribution, and decompilation. No part of this document
+      may be reproduced in any form by any means without prior
+      written authorization of Sun and its licensors, if any.
+
+      Third-party software, including font technology, is
+      copyrighted and licensed from Sun suppliers.
+
+      Sun, Sun Microsystems, the Sun logo, Solaris, Java, J2EE,
+      JavaServer Pages, Enterprise JavaBeans and the Java Coffee
+      Cup logo are trademarks or registered trademarks of Sun
+      Microsystems, Inc. in the U.S. and other countries.
+
+      Federal Acquisitions: Commercial Software - Government Users
+      Subject to Standard License Terms and Conditions.
+
+    </xsd:documentation>
+  </xsd:annotation>
+
+  <xsd:annotation>
+    <xsd:documentation>
+
+      This is the XML Schema for the JSP 2.0 deployment descriptor
+      types.  The JSP 2.0 schema contains all the special
+      structures and datatypes that are necessary to use JSP files
+      from a web application.
+
+      The contents of this schema is used by the web-app_2_4.xsd
+      file to define JSP specific content.
+
+    </xsd:documentation>
+  </xsd:annotation>
+
+  <xsd:annotation>
+    <xsd:documentation>
+
+      The following conventions apply to all J2EE
+      deployment descriptor elements unless indicated otherwise.
+
+      - In elements that specify a pathname to a file within the
+	same JAR file, relative filenames (i.e., those not
+	starting with "/") are considered relative to the root of
+	the JAR file's namespace.  Absolute filenames (i.e., those
+	starting with "/") also specify names in the root of the
+	JAR file's namespace.  In general, relative names are
+	preferred.  The exception is .war files where absolute
+	names are preferred for consistency with the Servlet API.
+
+    </xsd:documentation>
+  </xsd:annotation>
+
+  <xsd:include schemaLocation="j2ee_1_4.xsd"/>
+
+
+<!-- **************************************************** -->
+
+  <xsd:complexType name="jsp-configType">
+    <xsd:annotation>
+      <xsd:documentation>
+
+	The jsp-configType is used to provide global configuration
+	information for the JSP files in a web application. It has
+	two subelements, taglib and jsp-property-group.
+
+      </xsd:documentation>
+    </xsd:annotation>
+
+    <xsd:sequence>
+      <xsd:element name="taglib"
+		   type="j2ee:taglibType"
+		   minOccurs="0"
+		   maxOccurs="unbounded"/>
+      <xsd:element name="jsp-property-group"
+		   type="j2ee:jsp-property-groupType"
+		   minOccurs="0"
+		   maxOccurs="unbounded"/>
+    </xsd:sequence>
+    <xsd:attribute name="id" type="xsd:ID"/>
+  </xsd:complexType>
+
+<!-- **************************************************** -->
+
+  <xsd:complexType name="jsp-fileType">
+    <xsd:annotation>
+      <xsd:documentation>
+
+	The jsp-file element contains the full path to a JSP file
+	within the web application beginning with a `/'.
+
+      </xsd:documentation>
+    </xsd:annotation>
+
+    <xsd:simpleContent>
+      <xsd:restriction base="j2ee:pathType"/>
+    </xsd:simpleContent>
+  </xsd:complexType>
+
+<!-- **************************************************** -->
+
+  <xsd:complexType name="jsp-property-groupType">
+    <xsd:annotation>
+      <xsd:documentation>
+
+	The jsp-property-groupType is used to group a number of
+	files so they can be given global property information.
+	All files so described are deemed to be JSP files.  The
+	following additional properties can be described:
+
+	    - Control whether EL is ignored
+	    - Control whether scripting elements are invalid
+	    - Indicate pageEncoding information.
+	    - Indicate that a resource is a JSP document (XML)
+	    - Prelude and Coda automatic includes.
+
+      </xsd:documentation>
+    </xsd:annotation>
+
+    <xsd:sequence>
+      <xsd:group ref="j2ee:descriptionGroup"/>
+      <xsd:element name="url-pattern"
+		   type="j2ee:url-patternType"
+		   maxOccurs="unbounded"/>
+      <xsd:element name="el-ignored"
+		   type="j2ee:true-falseType"
+		   minOccurs="0">
+	<xsd:annotation>
+	  <xsd:documentation>
+
+	    Can be used to easily set the isELIgnored
+	    property of a group of JSP pages.  By default, the
+	    EL evaluation is enabled for Web Applications using
+	    a Servlet 2.4 or greater web.xml, and disabled
+	    otherwise.
+
+	  </xsd:documentation>
+	</xsd:annotation>
+      </xsd:element>
+      <xsd:element name="page-encoding"
+		   type="j2ee:string"
+		   minOccurs="0">
+	<xsd:annotation>
+	  <xsd:documentation>
+
+	    The valid values of page-encoding are those of the
+	    pageEncoding page directive.  It is a
+	    translation-time error to name different encodings
+	    in the pageEncoding attribute of the page directive
+	    of a JSP page and in a JSP configuration element
+	    matching the page.  It is also a translation-time
+	    error to name different encodings in the prolog
+	    or text declaration of a document in XML syntax and
+	    in a JSP configuration element matching the document.
+	    It is legal to name the same encoding through
+	    mulitple mechanisms.
+
+	  </xsd:documentation>
+	</xsd:annotation>
+      </xsd:element>
+      <xsd:element name="scripting-invalid"
+		   type="j2ee:true-falseType"
+		   minOccurs="0">
+	<xsd:annotation>
+	  <xsd:documentation>
+
+	    Can be used to easily disable scripting in a
+	    group of JSP pages.  By default, scripting is
+	    enabled.
+
+	  </xsd:documentation>
+	</xsd:annotation>
+      </xsd:element>
+      <xsd:element name="is-xml"
+		   type="j2ee:true-falseType"
+		   minOccurs="0">
+	<xsd:annotation>
+	  <xsd:documentation>
+
+	    If true, denotes that the group of resources
+	    that match the URL pattern are JSP documents,
+	    and thus must be interpreted as XML documents.
+	    If false, the resources are assumed to not
+	    be JSP documents, unless there is another
+	    property group that indicates otherwise.
+
+	  </xsd:documentation>
+	</xsd:annotation>
+      </xsd:element>
+      <xsd:element name="include-prelude"
+		   type="j2ee:pathType"
+		   minOccurs="0"
+		   maxOccurs="unbounded">
+	<xsd:annotation>
+	  <xsd:documentation>
+
+	    The include-prelude element is a context-relative
+	    path that must correspond to an element in the
+	    Web Application.  When the element is present,
+	    the given path will be automatically included (as
+	    in an include directive) at the beginning of each
+	    JSP page in this jsp-property-group.
+
+	  </xsd:documentation>
+	</xsd:annotation>
+      </xsd:element>
+      <xsd:element name="include-coda"
+		   type="j2ee:pathType"
+		   minOccurs="0"
+		   maxOccurs="unbounded">
+	<xsd:annotation>
+	  <xsd:documentation>
+
+	    The include-coda element is a context-relative
+	    path that must correspond to an element in the
+	    Web Application.  When the element is present,
+	    the given path will be automatically included (as
+	    in an include directive) at the end of each
+	    JSP page in this jsp-property-group.
+
+	  </xsd:documentation>
+	</xsd:annotation>
+      </xsd:element>
+    </xsd:sequence>
+    <xsd:attribute name="id" type="xsd:ID"/>
+  </xsd:complexType>
+
+<!-- **************************************************** -->
+
+  <xsd:complexType name="taglibType">
+    <xsd:annotation>
+      <xsd:documentation>
+
+	The taglibType defines the syntax for declaring in
+	the deployment descriptor that a tag library is
+	available to the application.  This can be done
+	to override implicit map entries from TLD files and
+	from the container.
+
+      </xsd:documentation>
+    </xsd:annotation>
+
+    <xsd:sequence>
+      <xsd:element name="taglib-uri"
+		   type="j2ee:string">
+	<xsd:annotation>
+	  <xsd:documentation>
+
+	    A taglib-uri element describes a URI identifying a
+	    tag library used in the web application.  The body
+	    of the taglib-uri element may be either an
+	    absolute URI specification, or a relative URI.
+	    There should be no entries in web.xml with the
+	    same taglib-uri value.
+
+	  </xsd:documentation>
+	</xsd:annotation>
+      </xsd:element>
+
+      <xsd:element name="taglib-location"
+		   type="j2ee:pathType">
+	<xsd:annotation>
+	  <xsd:documentation>
+
+	    the taglib-location element contains the location
+	    (as a resource relative to the root of the web
+	    application) where to find the Tag Library
+	    Description file for the tag library.
+
+	  </xsd:documentation>
+	</xsd:annotation>
+      </xsd:element>
+
+    </xsd:sequence>
+    <xsd:attribute name="id" type="xsd:ID"/>
+  </xsd:complexType>
+
+</xsd:schema>
+

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/dtd/jspxml.dtd
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/dtd/jspxml.dtd	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/dtd/jspxml.dtd	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,189 @@
+<!--
+  Copyright 2004 The Apache Software Foundation
+
+  Licensed 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.
+-->
+<!-- DTD for JSP 2.0
+     thanks to Bob Foster, WebGain
+-->
+
+<!-- 
+     This DTD is not conditional on any parameter entities in the internal
+     subset and does not export any general entities.
+-->
+
+<!--================== Constrained Names ====================================-->
+
+<!ENTITY % URI "CDATA">
+    <!-- a Uniform Resource Identifier, see [RFC2396] -->
+
+<!ENTITY % UriList "CDATA">
+    <!-- a space separated list of Uniform Resource Identifiers -->
+
+<!ENTITY % URL "CDATA">
+    <!-- a relative urlSpec is as in Section 2.10.2. -->
+
+<!ENTITY % BeanID "IDREF">
+    <!-- a previously declared bean ID in the current scope. -->
+
+<!ENTITY % Prefix "CDATA">
+    <!-- a Name that contains no : characters. -->
+
+<!ENTITY % ClassName "CDATA">
+    <!-- a fully qualified class name. -->
+
+<!ENTITY % TypeName "CDATA">
+    <!-- a fully qualified class or interface name. -->
+
+<!ENTITY % BeanName "CDATA">
+    <!-- a bean name as expected by java.beans.Beans instantiate(). -->
+
+<!ENTITY % Content "CDATA">
+    <!-- a MIME type followed by an IANA charset, as " type [; S? ['charset='] charset] " -->
+
+<!ENTITY % Length "CDATA">
+    <!-- nn for pixels or nn% for percentage length -->
+
+<!ENTITY % Pixels "CDATA">
+    <!-- integer representing length in pixels -->
+
+<!ENTITY % Bool "(true|false|yes|no)">
+    <!-- boolean -->
+
+<!-- used for object, applet, img, input and iframe -->
+<!ENTITY % ImgAlign "(top|middle|bottom|left|right)">
+
+<!--=================== Element Groups ====================================-->
+
+<!ENTITY % Directives "jsp:directive.page|jsp:directive.include">
+
+<!ENTITY % Scripts "jsp:scriptlet|jsp:declaration|jsp:expression">
+
+<!ENTITY % Actions
+    "jsp:useBean
+    |jsp:setProperty
+    |jsp:getProperty
+    |jsp:include
+    |jsp:forward
+    |jsp:plugin"
+>
+
+<!ENTITY % Body "(jsp:text|%Directives;|%Scripts;|%Actions;)*">
+
+
+<!-- ============================ Elements ============================ -->
+
+<!--    Root element of a JSP page.
+-->
+<!ELEMENT jsp:root %Body;>
+<!ATTLIST jsp:root
+    xmlns:jsp       CDATA           "http://java.sun.com/JSP/Page"
+    version         CDATA           #REQUIRED
+>
+
+<!ELEMENT jsp:directive.page EMPTY>
+<!ATTLIST jsp:directive.page
+    language        CDATA           "java"
+    extends         %ClassName;     #IMPLIED
+    contentType     %Content;       "text/html; ISO-8859-1"
+    import          CDATA           #IMPLIED
+    session         %Bool;          "true"
+    buffer          CDATA           "8kb"
+    autoFlush       %Bool;          "true"
+    isThreadSafe    %Bool;          "true"
+    info            CDATA           #IMPLIED
+    errorPage       %URL;           #IMPLIED
+    isErrorPage     %Bool;          "false"
+    pageEncoding    CDATA           #IMPLIED
+    isELIgnored     %Bool;          #IMPLIED
+>
+
+<!-- the jsp:directive.include only appears in JSP documents and does
+     not appear in the XML views of JSP pages.
+-->
+
+<!ELEMENT jsp:directive.include EMPTY>
+<!ATTLIST jsp:directive.include
+    file            %URI;           #REQUIRED
+>
+
+<!ELEMENT jsp:scriptlet (#PCDATA)>
+
+<!ELEMENT jsp:declaration (#PCDATA)>
+
+<!ELEMENT jsp:expression (#PCDATA)>
+
+<!ELEMENT jsp:useBean %Body;>
+<!ATTLIST jsp:useBean
+    id              ID              #REQUIRED
+    class           %ClassName;     #IMPLIED
+    type            %TypeName;      #IMPLIED
+    beanName        %BeanName;      #IMPLIED
+    scope           (page
+                    |session
+                    |request
+                    |application)   "page"
+>
+
+<!ELEMENT jsp:setProperty EMPTY>
+<!ATTLIST jsp:setProperty
+    name            %BeanID;        #REQUIRED
+    property        CDATA           #REQUIRED
+    value           CDATA           #IMPLIED
+    param           CDATA           #IMPLIED
+>
+
+<!ELEMENT jsp:getProperty EMPTY>
+<!ATTLIST jsp:getProperty
+    name            %BeanID;        #REQUIRED
+    property        CDATA           #REQUIRED
+>
+
+<!ELEMENT jsp:include (jsp:param*)>
+<!ATTLIST jsp:include
+    flush           %Bool;          "false"
+    page            %URL;           #REQUIRED
+>
+
+<!ELEMENT jsp:forward (jsp:param*)>
+<!ATTLIST jsp:forward
+    page            %URL;           #REQUIRED
+>
+
+<!ELEMENT jsp:plugin (jsp:params?, jsp:fallback?)>
+<!ATTLIST jsp:plugin
+    type            (bean|applet)   #REQUIRED
+    code            %URI;           #IMPLIED
+    codebase        %URI;           #IMPLIED
+    align           %ImgAlign;      #IMPLIED
+    archive         %UriList;       #IMPLIED
+    height          %Length;        #IMPLIED
+    hspace          %Pixels;        #IMPLIED
+    jreversion      CDATA           "1.2"
+    name            NMTOKEN         #IMPLIED
+    vspace          %Pixels;        #IMPLIED
+    width           %Length;        #IMPLIED
+    nspluginurl     %URI;           #IMPLIED
+    iepluginurl     %URI;           #IMPLIED
+>
+
+<!ELEMENT jsp:params (jsp:param+)>
+
+<!ELEMENT jsp:param EMPTY>
+<!ATTLIST jsp:param
+    name            CDATA           #REQUIRED
+    value           CDATA           #REQUIRED
+>
+
+<!ELEMENT jsp:text #PCDATA>
+

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/dtd/jspxml.xsd
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/dtd/jspxml.xsd	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/dtd/jspxml.xsd	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,513 @@
+<?xml version ="1.0"?>
+<!--
+  Copyright 2004 The Apache Software Foundation
+
+  Licensed 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.
+-->
+<!DOCTYPE schema [
+<!-- Patterns -->
+<!ENTITY Identifier   "(\p{L}|_|$)(\p{N}|\p{L}|_|$)*">
+<!ENTITY TypeName     "&Identifier;(\.&Identifier;)*">
+<!ENTITY WS       "\s*">
+<!ENTITY Import     "&TypeName;(\.\*)?">
+<!ENTITY ImportList   "&Import;(&WS;,&WS;&Import;)*">
+<!ENTITY SetProp    "(&Identifier;|\*)">
+<!ENTITY RelativeURL  "[^:#/\?]*(:{0,0}|[#/\?].*)">
+<!ENTITY Length     "[0-9]*&#x25;?">
+<!ENTITY AsciiName    "[A-Za-z0-9_-]*">
+<!ENTITY ValidContentType  "&AsciiName;/&AsciiName;(;&WS;(charset=)?&AsciiName;)?">
+<!ENTITY ValidPageEncoding  "&AsciiName;/&AsciiName;">
+<!ENTITY Buffer     "[0-9]+kb">
+<!ENTITY RTexpr     "&#x25;=.*&#x25;">
+]>
+
+
+<!--Conforms to w3c http://www.w3.org/2001/XMLSchema -->
+
+<xsd:schema
+    xmlns = "http://java.sun.com/JSP/Page"
+    xmlns:xsd = "http://www.w3.org/2001/XMLSchema"
+    xmlns:jsp = "http://java.sun.com/JSP/Page"
+    targetNamespace = "http://java.sun.com/JSP/Page"
+    elementFormDefault = "qualified"
+    attributeFormDefault = "unqualified">
+
+  <xsd:annotation>
+    <xsd:documentation>
+      XML Schema for JSP 2.0.
+
+      This schema is based upon the recent (May 5th, 2001)
+      W3C recommendation for XML Schema.
+
+      A JSP translator should reject an XML-format file that is
+      not strictly valid according to this schema or does not observe
+      the constraints documented here. A translator is not required
+      to use this schema for validation or to use a validating parser.
+    </xsd:documentation>
+  </xsd:annotation>
+
+
+  <!-- Complex Types -->
+
+  <xsd:complexType name = "Body">
+    <xsd:annotation>
+      <xsd:documentation>
+        Body defines the "top-level" elements in root and beanInfo.
+        There are probably other elements that should use it.
+      </xsd:documentation>
+    </xsd:annotation>
+    <xsd:group ref = "Bodygroup" minOccurs = "0" maxOccurs = "unbounded"/>
+  </xsd:complexType>
+
+  <!-- groups -->
+
+  <xsd:group name = "Bodygroup">
+    <xsd:choice>
+      <xsd:element ref = "directive.page"/>
+      <xsd:element ref = "directive.include"/>
+      <xsd:element ref = "scriptlet"/>
+      <xsd:element ref = "declaration"/>
+      <xsd:element ref = "expression"/>
+      <xsd:element ref = "useBean"/>
+      <xsd:element ref = "setProperty"/>
+      <xsd:element ref = "getProperty"/>
+      <xsd:element ref = "include"/>
+      <xsd:element ref = "forward"/>
+      <xsd:element ref = "plugin"/>
+      <xsd:element ref = "text"/>
+      <xsd:any namespace="##other" processContents = "lax"/>
+    </xsd:choice>
+  </xsd:group>
+
+
+  <!-- Simple types are next -->
+
+  <xsd:simpleType name = "RTE">
+    <xsd:annotation>
+      <xsd:documentation>
+        A request-time expression value
+      </xsd:documentation>
+    </xsd:annotation>
+    <xsd:restriction base = "xsd:string">
+      <xsd:pattern value = "&RTexpr;"/>
+    </xsd:restriction>
+  </xsd:simpleType>
+
+  <xsd:simpleType name = "Bool">
+    <xsd:annotation>
+      <xsd:documentation>
+        Bool would be boolean except it does not accept 1 and 0.
+      </xsd:documentation>
+    </xsd:annotation>
+    <xsd:restriction base = "xsd:NMTOKEN" >
+      <xsd:enumeration value = "true"/>
+      <xsd:enumeration value = "false"/>
+      <xsd:enumeration value = "yes"/>
+      <xsd:enumeration value = "no"/>
+    </xsd:restriction>     
+  </xsd:simpleType>
+
+  <xsd:simpleType name = "Identifier">
+    <xsd:annotation>
+      <xsd:documentation>
+        Identifier is an unqualified Java identifier.
+      </xsd:documentation>
+    </xsd:annotation>
+    <xsd:restriction base = "xsd:string">
+      <xsd:pattern value = "&Identifier;"/>
+    </xsd:restriction>
+  </xsd:simpleType>
+  
+  <xsd:simpleType name = "TypeName">
+    <xsd:annotation>
+      <xsd:documentation>
+        TypeName is one or more Java identifiers separated by dots
+        with no whitespace.
+      </xsd:documentation>
+    </xsd:annotation>
+    <xsd:restriction base = "xsd:string">
+      <xsd:pattern value = "&TypeName;"/>
+    </xsd:restriction>
+  </xsd:simpleType>
+  
+  <xsd:simpleType name = "ImportList">
+    <xsd:annotation>
+      <xsd:documentation>
+        ImportList is one or more typeNames separated by commas.
+        Whitespace is allowed before and after the comma.
+      </xsd:documentation>
+    </xsd:annotation>
+    <xsd:restriction base = "xsd:string">
+      <xsd:pattern value = "&ImportList;"/>
+    </xsd:restriction>
+  </xsd:simpleType>
+  
+  <xsd:simpleType name = "SetProp">
+    <xsd:annotation>
+      <xsd:documentation>
+        SetProp is an Identifier or *.
+      </xsd:documentation>
+    </xsd:annotation>
+    <xsd:restriction base = "xsd:string">
+      <xsd:pattern value = "&SetProp;"/>
+    </xsd:restriction>
+  </xsd:simpleType>
+  
+  <xsd:simpleType name = "RelativeURL">
+    <xsd:annotation>
+      <xsd:documentation>
+        RelativeURL is a uriReference with no colon character
+        before the first /, ? or #, if any (RFC2396).
+      </xsd:documentation>
+    </xsd:annotation>
+	<xsd:restriction base = "xsd:anyURI">
+      <xsd:pattern value = "&RelativeURL;"/>
+    </xsd:restriction>
+  </xsd:simpleType>
+
+  <xsd:simpleType name = "RTERelativeURL">
+    <xsd:union memberTypes = "RelativeURL RTE"/>
+  </xsd:simpleType>
+
+  <xsd:simpleType name = "Length">
+    <xsd:annotation>
+      <xsd:documentation>
+        Length is nn or nn%.
+      </xsd:documentation>
+    </xsd:annotation>
+    <xsd:restriction base = "xsd:string">
+      <xsd:pattern value = "&Length;"/>
+    </xsd:restriction>
+  </xsd:simpleType>
+  
+
+  <xsd:simpleType name = "ExplicitBufferSize">
+    <xsd:annotation>
+      <xsd:documentation>
+         Buffer Size with an explicit value
+      </xsd:documentation>
+    </xsd:annotation> 
+    <xsd:restriction base = "xsd:string">
+      <xsd:pattern value = "&Buffer;"/>
+    </xsd:restriction>
+  </xsd:simpleType>
+
+  <xsd:simpleType name = "NoneBufferSize">
+    <xsd:annotation>
+      <xsd:documentation>
+         Buffer Size with a "none" value
+      </xsd:documentation>
+    </xsd:annotation> 
+       <xsd:restriction base = "xsd:string">
+         <xsd:enumeration value = "none"/>
+       </xsd:restriction>
+  </xsd:simpleType>
+
+  <xsd:simpleType name = "BufferSize">
+    <xsd:annotation>
+      <xsd:documentation>
+        Buffer size is xkb or none.
+      </xsd:documentation>
+    </xsd:annotation>
+    <xsd:union memberTypes = "ExplicitBufferSize NoneBufferSize"/>
+  </xsd:simpleType>
+  
+  <xsd:simpleType name = "ContentType">
+    <xsd:annotation>
+      <xsd:documentation>
+        Content type and character encoding for this page.
+      </xsd:documentation>
+    </xsd:annotation>
+    <xsd:restriction base = "xsd:string">
+      <xsd:pattern value = "&ValidContentType;"/>
+    </xsd:restriction>
+  </xsd:simpleType>
+
+  <xsd:simpleType name = "PageEncoding">
+    <xsd:annotation>
+      <xsd:documentation>
+        Page Encoding for this page.
+      </xsd:documentation>
+    </xsd:annotation>
+    <xsd:restriction base = "xsd:string">
+      <xsd:pattern value = "&ValidPageEncoding;"/>
+    </xsd:restriction>
+  </xsd:simpleType>
+
+  <xsd:simpleType name = "Scope">
+    <xsd:annotation>
+      <xsd:documentation>
+        valid scope values
+      </xsd:documentation>
+    </xsd:annotation>
+    <xsd:restriction base = "xsd:NMTOKEN">
+      <xsd:enumeration value = "page"/>
+      <xsd:enumeration value = "session"/>
+      <xsd:enumeration value = "request"/>
+      <xsd:enumeration value = "application"/>
+    </xsd:restriction>
+  </xsd:simpleType>
+
+  <xsd:simpleType name = "PlugInType">
+    <xsd:annotation>
+      <xsd:documentation>
+        valid values for a plugin type
+      </xsd:documentation>
+    </xsd:annotation>
+    <xsd:restriction base = "xsd:NMTOKEN">
+      <xsd:enumeration value = "bean"/>
+      <xsd:enumeration value = "applet"/>
+    </xsd:restriction>
+  </xsd:simpleType>
+
+  <xsd:simpleType name = "AlignType">
+    <xsd:annotation>
+      <xsd:documentation>
+        Buffer size is xkb.
+      </xsd:documentation>
+    </xsd:annotation>
+    <xsd:restriction base = "xsd:NMTOKEN">
+      <xsd:enumeration value = "top"/>
+      <xsd:enumeration value = "middle"/>
+      <xsd:enumeration value = "bottom"/>
+      <xsd:enumeration value = "left"/>
+      <xsd:enumeration value = "right"/>
+    </xsd:restriction>
+  </xsd:simpleType>
+
+  <!-- Elements follow -->
+
+  <xsd:element name = "root">
+    <xsd:annotation>
+      <xsd:documentation>
+        The root element of all JSP documents is named root.
+        
+        Authors may, if they wish, include schema location information.
+        If specified, the information may appear as attributes of
+        the root element as follows:
+
+        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+        xsi:schemaLocation="http://java.sun.com/JSP/Page xsd-file-location"
+
+        Documents should not specify the system identifier of a DTD
+        in a DOCTYPE declaration.
+      </xsd:documentation>
+    </xsd:annotation>
+    <xsd:complexType>
+      <xsd:complexContent>
+        <xsd:extension base = "Body">
+          <xsd:attribute name = "version" fixed = "2.0" type = "xsd:string"/>
+        </xsd:extension>
+      </xsd:complexContent>
+    </xsd:complexType>
+  </xsd:element>
+  
+  <xsd:element name = "directive.page">
+    <xsd:annotation>
+      <xsd:documentation>
+        directive.page is the "page directive".
+      </xsd:documentation>
+    </xsd:annotation>
+    <xsd:complexType>
+      <xsd:attribute name = "language" default = "java" type = "xsd:string"/>
+      <xsd:attribute name = "extends" type = "TypeName"/>
+      <xsd:attribute name = "contentType" default = "text/html; ISO-8859-1" type = "ContentType"/>
+      <xsd:attribute name = "pageEncoding" use = "optional" type = "PageEncoding"/>
+      <xsd:attribute name = "import" type = "ImportList"/>
+      <xsd:attribute name = "session" default = "true" type = "Bool"/>
+      <xsd:attribute name = "buffer" default = "8kb" type = "BufferSize"/>
+      <xsd:attribute name = "autoFlush" default = "true" type = "Bool"/>
+      <xsd:attribute name = "isThreadSafe" default = "true" type = "Bool"/>
+      <xsd:attribute name = "info" type = "xsd:string"/>
+      <xsd:attribute name = "errorPage" type = "RelativeURL"/>
+      <xsd:attribute name = "isErrorPage" default = "false" type = "Bool"/>
+      <xsd:attribute name = "isELIgnored" type = "Bool"/>
+    </xsd:complexType>
+  </xsd:element>
+  
+  <xsd:element name = "directive.include">
+    <xsd:annotation>
+      <xsd:documentation>
+        directive.include is the "include directive".
+	This element does not appear on XML views of JSP pages.
+      </xsd:documentation>
+    </xsd:annotation>
+    <xsd:complexType>
+      <xsd:attribute name = "file" use = "required" type = "RelativeURL"/>
+    </xsd:complexType>
+  </xsd:element>
+
+  <xsd:element name = "scriptlet" type = "xsd:string">
+    <xsd:annotation>
+      <xsd:documentation>
+        The representation of a scriplet.
+      </xsd:documentation>
+    </xsd:annotation>
+  </xsd:element>
+  
+  <xsd:element name = "declaration" type = "xsd:string">
+    <xsd:annotation>
+      <xsd:documentation>
+        The reprsentation of a declaration.
+      </xsd:documentation>
+    </xsd:annotation>
+  </xsd:element>
+  
+  <xsd:element name = "expression" type = "xsd:string">
+    <xsd:annotation>
+      <xsd:documentation>
+        The representation of an expression.
+      </xsd:documentation>
+    </xsd:annotation>
+  </xsd:element>
+ 
+  <xsd:element name = "text" type = "xsd:string">
+    <xsd:annotation>
+      <xsd:documentation>
+        Verbatim template text.
+      </xsd:documentation>
+    </xsd:annotation>
+  </xsd:element>
+
+  <xsd:element name = "useBean">
+    <xsd:annotation>
+      <xsd:documentation>
+        useBean instantiates or accesses a bean in the specified scope.
+        
+        Constraint: The allowed combinations of attributes are:
+        
+          class [type] | type [( class | beanName)]
+        
+      </xsd:documentation>
+    </xsd:annotation>
+    <xsd:complexType>
+      <xsd:complexContent>
+        <xsd:extension base="Body">
+          <xsd:attribute name = "id" use = "required" type = "Identifier"/>
+          <xsd:attribute name = "class" type = "TypeName"/>
+          <xsd:attribute name = "type" type = "TypeName"/>
+          <xsd:attribute name = "beanName" type = "TypeName"/>
+          <xsd:attribute name = "scope" default = "page" type = "Scope"/>
+        </xsd:extension>
+      </xsd:complexContent>
+    </xsd:complexType>
+  </xsd:element>
+  
+  <xsd:element name = "setProperty">
+    <xsd:annotation>
+      <xsd:documentation>
+        setProperty changes the value of an object property.
+        
+        Constraint: The object named by the name must have been
+        "introduced" to the JSP processor using either the
+        jsp:useBean action or a custom action with an associated
+        VariableInfo entry for this name.
+
+        Exact valid combinations are not expressable in XML Schema.
+        They are:
+
+        name="Identifier" property="*"
+        name="Identifier" property="Identfiier" param="string"
+        name="Identifier" property="Identifier" value="string"
+                
+      </xsd:documentation>
+    </xsd:annotation>
+    <xsd:complexType>
+      <xsd:attribute name = "name" use = "required" type = "Identifier"/>
+      <xsd:attribute name = "property" use = "required" type = "SetProp"/>
+      <xsd:attribute name = "param" type = "xsd:string"/>
+      <xsd:attribute name = "value" type = "xsd:string"/>
+    </xsd:complexType>
+  </xsd:element>
+
+  <xsd:element name = "getProperty">
+    <xsd:annotation>
+      <xsd:documentation>
+        getProperty obtains the value of an object property.
+        
+        Constraint: The object named by the name must have been
+        "introduced" to the JSP processor using either the
+        jsp:useBean action or a custom action with an associated
+        VariableInfo entry for this name.
+        
+        ???The spec is interpreted as restricting the values of
+        property to Identifier.
+      </xsd:documentation>
+    </xsd:annotation>
+    <xsd:complexType>
+      <xsd:attribute name = "name" use = "required" type = "Identifier"/>
+      <xsd:attribute name = "property" use = "required" type = "Identifier"/>
+    </xsd:complexType>
+  </xsd:element>
+  
+  <xsd:element name = "include">
+    <xsd:complexType>
+      <xsd:sequence>
+        <xsd:element ref = "param" minOccurs = "0" maxOccurs = "unbounded"/>
+      </xsd:sequence>
+      <xsd:attribute name = "flush" default = "false" type = "Bool"/>
+      <xsd:attribute name = "page" use = "required" type = "RTERelativeURL"/>
+    </xsd:complexType>
+  </xsd:element>
+
+  <xsd:element name = "forward">
+    <xsd:complexType>
+      <xsd:sequence>
+        <xsd:element ref = "param" minOccurs = "0" maxOccurs = "unbounded"/>
+      </xsd:sequence>
+      <xsd:attribute name = "page" use = "required" type = "RTERelativeURL"/>
+     </xsd:complexType>
+  </xsd:element>
+  
+  <xsd:element name = "plugin">
+    <xsd:complexType> <!-- content only! -->
+      <xsd:sequence>
+        <xsd:element ref = "params" minOccurs = "0" maxOccurs = "1"/>
+        <xsd:element name = "fallback" minOccurs = "0" maxOccurs = "1" type = "Body"/>
+      </xsd:sequence>
+      <xsd:attribute name = "type" use = "required" type = "PlugInType"/>
+      <xsd:attribute name = "code" type = "xsd:anyURI"/>
+      <xsd:attribute name = "codebase" type = "xsd:anyURI"/>
+      <xsd:attribute name = "align" type = "AlignType"/>
+      <xsd:attribute name = "archive">
+        <xsd:simpleType>
+           <xsd:list itemType="xsd:anyURI"/>
+        </xsd:simpleType>
+      </xsd:attribute>
+      <xsd:attribute name = "height" type = "Length"/>
+      <xsd:attribute name = "hspace" type = "xsd:int"/>
+      <xsd:attribute name = "jreversion" default = "1.2" type = "xsd:string"/>
+      <xsd:attribute name = "name" type = "xsd:NMTOKEN"/>
+      <xsd:attribute name = "vspace" type = "xsd:int"/>
+      <xsd:attribute name = "width" type = "Length"/>
+      <xsd:attribute name = "nspluginurl" type = "xsd:anyURI"/>
+      <xsd:attribute name = "iepluginurl" type = "xsd:anyURI"/>
+    </xsd:complexType>
+  </xsd:element>
+  
+  <xsd:element name = "params">
+    <xsd:complexType>
+       <xsd:sequence>
+         <xsd:element ref = "param" minOccurs = "1" maxOccurs = "unbounded"/>
+       </xsd:sequence>
+    </xsd:complexType>
+  </xsd:element>
+
+  <xsd:element name = "param">
+    <xsd:complexType>
+      <xsd:attribute name = "name" use = "required" type = "xsd:NMTOKEN"/>
+      <xsd:attribute name = "value" use = "required" type = "xsd:string"/>
+    </xsd:complexType>
+  </xsd:element>
+  
+</xsd:schema>

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/dtd/web-jsptaglibrary_1_1.dtd
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/dtd/web-jsptaglibrary_1_1.dtd	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/dtd/web-jsptaglibrary_1_1.dtd	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,206 @@
+<!--
+  Copyright 2004 The Apache Software Foundation
+
+  Licensed 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.
+-->
+<!--
+
+   This is the DTD defining the JavaServer Pages 1.1 Tag Library
+   descriptor (.tld) (XML) file format/syntax.
+
+   A Tag Library is a JAR file containing a valid instance of a Tag Library
+   Descriptor (taglib.tld) file in the META-INF subdirectory, along with the
+   appropriate implementing classes, and other resources required to
+   implement the tags defined therein.
+
+   Use is subject to license terms.
+  -->
+
+<!--
+The taglib tag is the document root, it defines:
+
+tlibversion	the version of the tag library implementation
+jspversion	the version of JSP the tag library depends upon
+
+shortname	a simple default short name that could be used by
+		a JSP authoring tool to create names with a mnemonic
+		value; for example, the it may be used as the prefered
+		prefix value in taglib directives
+uri		a uri uniquely identifying this taglib
+info		a simple string describing the "use" of this taglib,
+		should be user discernable
+-->
+
+<!ELEMENT taglib (tlibversion, jspversion?, shortname, uri?, info?, tag+) >
+<!ATTLIST taglib id ID #IMPLIED
+	  xmlns CDATA #FIXED
+		"http://java.sun.com/j2ee/dtds/web-jsptaglibrary_1_1.dtd"
+>
+
+<!--
+Describes this version (number) of the taglibrary (dewey decimal)
+
+#PCDATA ::= [0-9]*{ "."[0-9] }0..3
+-->
+
+<!ELEMENT tlibversion (#PCDATA) >
+
+<!--
+Describes the JSP version (number) this taglibrary requires in
+order to function (dewey decimal)
+
+The default is 1.1
+
+#PCDATA ::= [0-9]*{ "."[0-9] }0..3
+-->
+
+<!ELEMENT jspversion  (#PCDATA) >
+
+<!--
+Defines a short (default) shortname to be used for tags and
+variable names used/created by this tag library.  Do not use
+white space, and do not start with digits or underscore.
+
+#PCDATA ::= NMTOKEN
+-->
+
+<!ELEMENT shortname      (#PCDATA) >
+
+<!--
+Defines a public URI that uniquely identifies this version of
+the taglibrary Leave it empty if it does not apply.
+-->
+
+<!ELEMENT uri	 (#PCDATA) >
+
+<!--
+Defines an arbitrary text string descirbing the tag library
+-->
+
+<!ELEMENT info	(#PCDATA) >
+
+<!--
+The tag defines a unique tag in this tag library, defining:
+
+- the unique tag/element name
+- the subclass of javax.servlet.jsp.tagext.Tag implementation class
+- an optional subclass of javax.servlet.jsp.tagext.TagExtraInfo
+- the body content type (hint)
+- optional tag-specific information
+- any attributes
+-->
+
+<!ELEMENT tag (name, tagclass, teiclass?, bodycontent?, info?, attribute*) >
+
+<!--
+Defines the subclass of javax.serlvet.jsp.tagext.Tag that implements
+the request time semantics for this tag. (required)
+
+#PCDATA ::= fully qualified Java class name
+-->
+
+<!ELEMENT tagclass (#PCDATA) >
+
+<!--
+Defines the subclass of javax.servlet.jsp.tagext.TagExtraInfo for
+this tag. (optional)
+
+If this is not given, the class is not consulted at translation time.
+
+#PCDATA ::= fully qualified Java class name
+-->
+
+<!ELEMENT teiclass (#PCDATA) >
+
+<!--
+Provides a hint as to the content of the body of this tag. Primarily
+intended for use by page composition tools.
+
+There are currently three values specified:
+
+tagdependent	The body of the tag is interpreted by the tag
+		implementation itself, and is most likely in a
+		different "langage", e.g embedded SQL statements.
+
+JSP		The body of the tag contains nested JSP syntax
+
+empty		The body must be empty
+
+The default (if not defined) is JSP
+
+#PCDATA ::=  tagdependent | JSP | empty
+
+-->
+
+<!ELEMENT bodycontent (#PCDATA) >
+
+<!--
+The attribute tag defines an attribute for the nesting tag
+
+An attribute definition is composed of:
+
+- the attributes name (required)
+- if the attribute is required or optional (optional)
+- if the attributes value may be dynamically calculated at runtime
+  by a scriptlet expression (optional)
+
+-->
+
+<!ELEMENT attribute (name, required? , rtexprvalue?) >
+
+<!--
+Defines the canonical name of a tag or attribute being defined
+
+#PCDATA ::= NMTOKEN
+-->
+
+<!ELEMENT name	(#PCDATA) >
+
+<!--
+Defines if the nesting attribute is required or optional.
+
+#PCDATA ::= true | false | yes | no
+
+If not present then the default is "false", i.e the attribute
+is optional.
+-->
+
+<!ELEMENT required    (#PCDATA) >
+
+<!--
+Defines if the nesting attribute can have scriptlet expressions as
+a value, i.e the value of the attribute may be dynamically calculated
+at request time, as opposed to a static value determined at translation
+time.
+
+#PCDATA ::= true | false | yes | no
+
+If not present then the default is "false", i.e the attribute
+has a static value
+-->
+
+<!ELEMENT rtexprvalue (#PCDATA) >
+
+<!ATTLIST tlibversion id ID #IMPLIED>
+<!ATTLIST jspversion id ID #IMPLIED>
+<!ATTLIST shortname id ID #IMPLIED>
+<!ATTLIST uri id ID #IMPLIED>
+<!ATTLIST info id ID #IMPLIED>
+<!ATTLIST tag id ID #IMPLIED>
+<!ATTLIST tagclass id ID #IMPLIED>
+<!ATTLIST teiclass id ID #IMPLIED>
+<!ATTLIST bodycontent id ID #IMPLIED>
+<!ATTLIST attribute id ID #IMPLIED>
+<!ATTLIST name id ID #IMPLIED>
+<!ATTLIST required id ID #IMPLIED>
+<!ATTLIST rtexprvalue id ID #IMPLIED>

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/dtd/web-jsptaglibrary_1_2.dtd
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/dtd/web-jsptaglibrary_1_2.dtd	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/dtd/web-jsptaglibrary_1_2.dtd	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,477 @@
+<!--
+  Copyright 2004 The Apache Software Foundation
+
+  Licensed 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.
+-->
+<!--
+
+   This is the DTD defining the JavaServer Pages 1.2 Tag Library
+   descriptor (.tld) (XML) file format/syntax.
+
+   A Tag Library is a JAR file containing a valid instance of a Tag Library
+   Descriptor (taglib.tld) file in the META-INF subdirectory, along with the
+   appropriate implementing classes, and other resources required to
+   implement the tags defined therein.
+
+   Use is subject to license terms.
+  -->
+
+<!NOTATION WEB-JSPTAGLIB.1_2 PUBLIC
+          "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN">
+
+<!--
+This is the XML DTD for the JSP 1.2 Tag Library Descriptor.
+All JSP 1.2 tag library descriptors must include a DOCTYPE
+of the following form:
+
+  <!DOCTYPE taglib
+        PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN"
+	"http://java.sun.com/dtd/web-jsptaglibrary_1_2.dtd">
+
+-->
+
+<!--
+The taglib tag is the document root, it defines:
+
+tlib-version	the version of the tag library implementation
+
+jsp-version	the version of JSP the tag library depends upon
+
+short-name	a simple default short name that could be used by
+		a JSP authoring tool to create names with a mnemonic
+		value; for example, the it may be used as the prefered
+		prefix value in taglib directives
+
+uri		a uri uniquely identifying this taglib
+
+display-name    the display-name element contains a short name that
+                is intended to be displayed by tools
+small-icon      optional small-icon that can be used by tools
+
+large-icon      optional large-icon that can be used by tools
+
+description	a simple string describing the "use" of this taglib,
+		should be user discernable
+
+validator       optional TagLibraryValidator information
+
+listener        optional event listener specification
+
+
+-->
+
+<!ELEMENT taglib (tlib-version, jsp-version, short-name, uri?,
+                  display-name?, small-icon?, large-icon?, description?,
+                  validator?, listener*, tag+) >
+
+<!ATTLIST taglib id ID #IMPLIED
+	  xmlns CDATA #FIXED
+		"http://java.sun.com/JSP/TagLibraryDescriptor"
+>
+
+<!--
+Describes this version (number) of the taglibrary (dewey decimal)
+
+#PCDATA ::= [0-9]*{ "."[0-9] }0..3
+-->
+
+<!ELEMENT tlib-version (#PCDATA) >
+
+<!--
+Describes the JSP version (number) this taglibrary requires in
+order to function (dewey decimal)
+
+The default is 1.2
+
+#PCDATA ::= [0-9]*{ "."[0-9] }0..3
+-->
+
+<!ELEMENT jsp-version  (#PCDATA) >
+
+<!--
+Defines a short (default) short-name to be used for tags and
+variable names used/created by this tag library.  Do not use
+white space, and do not start with digits or underscore.
+
+#PCDATA ::= NMTOKEN
+-->
+
+<!ELEMENT short-name      (#PCDATA) >
+
+<!--
+Defines a public URI that uniquely identifies this version of
+the taglibrary.  Leave it empty if it does not apply.
+-->
+
+<!ELEMENT uri	 (#PCDATA) >
+
+<!--
+Defines an arbitrary text string descirbing the tag library
+-->
+
+<!ELEMENT description	(#PCDATA) >
+
+<!--
+
+Defines an optional validator that can be used to
+validate the conformance of a JSP page to using this tag library.
+-->
+
+<!ELEMENT validator (validator-class, init-param*, description?) >
+
+
+<!--
+
+Defines the TagLibraryValidator class that can be used to
+validate the conformance of a JSP page to using this tag library.
+-->
+
+<!ELEMENT validator-class (#PCDATA) >
+
+
+<!--
+
+The init-param element contains a name/value pair as an
+initialization param
+-->
+
+<!ELEMENT init-param (param-name, param-value, description?)>
+
+<!--
+
+The param-name element contains the name of a parameter.
+-->
+
+<!ELEMENT param-name (#PCDATA)>
+
+<!--
+
+The param-value element contains the value of a parameter.
+-->
+
+<!ELEMENT param-value (#PCDATA)>
+
+
+<!--
+
+Defines an optional event listener object to be instantiated and
+registered automatically.
+-->
+
+<!ELEMENT listener (listener-class) >
+
+<!--
+
+The listener-class element declares a class in the application that
+must be registered as a web application listener bean.  See the
+Servlet 2.3 specification for details.
+-->
+
+<!ELEMENT listener-class (#PCDATA) >
+
+
+<!--
+The tag defines a unique tag in this tag library.  It has one
+attribute, id.
+
+The tag element may have several subelements defining:
+
+name              The unique action name
+
+tag-class         The tag handler class implementing
+                  javax.servlet.jsp.tagext.Tag
+
+tei-class         An optional subclass of
+                  javax.servlet.jsp.tagext.TagExtraInfo
+
+body-content      The body content type
+
+display-name      A short name that is intended to be displayed
+                  by tools
+
+small-icon        Optional small-icon that can be used by tools
+
+large-icon        Optional large-icon that can be used by tools
+
+description       Optional tag-specific information
+
+variable          Optional scripting variable information
+
+attribute         All attributes of this action
+
+example           Optional informal description of an example of a
+                  use of this tag
+
+-->
+
+<!ELEMENT tag (name, tag-class, tei-class?, body-content?, display-name?,
+               small-icon?, large-icon?, description?, variable*, attribute*,
+               example?) >
+
+<!--
+Defines the subclass of javax.serlvet.jsp.tagext.Tag that implements
+the request time semantics for this tag. (required)
+
+#PCDATA ::= fully qualified Java class name
+-->
+
+<!ELEMENT tag-class (#PCDATA) >
+
+<!--
+Defines the subclass of javax.servlet.jsp.tagext.TagExtraInfo for
+this tag. (optional)
+
+If this is not given, the class is not consulted at translation time.
+
+#PCDATA ::= fully qualified Java class name
+-->
+
+<!ELEMENT tei-class (#PCDATA) >
+
+<!--
+Provides a hint as to the content of the body of this tag. Primarily
+intended for use by page composition tools.
+
+There are currently three values specified:
+
+tagdependent	The body of the tag is interpreted by the tag
+		implementation itself, and is most likely in a
+		different "langage", e.g embedded SQL statements.
+
+JSP		The body of the tag contains nested JSP syntax
+
+empty		The body must be empty
+
+The default (if not defined) is JSP
+
+#PCDATA ::=  tagdependent | JSP | empty
+
+-->
+
+<!ELEMENT body-content (#PCDATA) >
+
+<!--
+
+The display-name element contains a short name that is intended
+to be displayed by tools.
+-->
+
+<!ELEMENT display-name (#PCDATA) >
+
+
+<!--
+
+The large-icon element contains the name of a file containing a large
+(32 x 32) icon image.  The file name is a relative path within the
+tag library.  The image must be either in the JPEG or GIF format, and
+the file name must end with the suffix ".jpg" or ".gif" respectively.
+The icon can be used by tools.
+-->
+
+<!ELEMENT large-icon (#PCDATA) >
+
+<!--
+
+The small-icon element contains the name of a file containing a large
+(32 x 32) icon image.  The file name is a relative path within the
+tag library.  The image must be either in the JPEG or GIF format, and
+the file name must end with the suffix ".jpg" or ".gif" respectively.
+The icon can be used by tools.
+-->
+
+<!ELEMENT small-icon (#PCDATA) >
+
+<!--
+
+The example element contains an informal description of an example
+of the use of a tag.
+-->
+
+<!ELEMENT example (#PCDATA) >
+
+<!--
+
+The variable tag provides information on the scripting variables
+defined by this tag.  It is a (translation time) error for a tag
+that has one or more variable subelements to have a TagExtraInfo
+class that returns a non-null object.
+
+The subelements of variable are of the form:
+
+name-given               The variable name as a constant
+
+name-from-attribute      The name of an attribute whose (translation
+                         time) value will give the name of the
+                         variable.  One of name-given or
+                         name-from-attribute is required.
+
+variable-class           Name of the class of the variable.
+                         java.lang.String is default.
+
+declare                  Whether the variable is declared or not.
+                         True is the default.
+
+scope                    The scope of the scripting varaible
+                         defined.  NESTED is default.
+
+description              Optional description of this variable
+
+-->
+
+<!ELEMENT variable ( (name-given | name-from-attribute), variable-class?,
+                    declare?, scope?, description?) >
+
+<!--
+
+The name for the scripting variable.  One of name-given or
+name-from-attribute is required.
+-->
+
+<!ELEMENT name-given (#PCDATA) >
+
+<!--
+
+The name of an attribute whose (translation-time) value will give
+the name of the variable.  One of name-given or name-from-attribute
+is required.
+-->
+
+<!ELEMENT name-from-attribute (#PCDATA) >
+
+<!--
+
+The optional name of the class for the scripting variable.  The
+default is java.lang.String.
+-->
+
+<!ELEMENT variable-class (#PCDATA) >
+
+<!--
+
+Whether the scripting variable is to be defined or not.  See
+TagExtraInfo for details.  This element is optional and "true"
+is the default.
+-->
+
+<!ELEMENT declare (#PCDATA) >
+
+<!--
+
+The scope of the scripting variable.  See TagExtraInfo for details.
+The element is optional and "NESTED" is the default.  Other legal
+values are "AT_BEGIN" and "AT_END".
+-->
+
+<!ELEMENT scope (#PCDATA) >
+
+<!--
+
+The attribute tag defines an attribute for the nesting tag
+
+An attribute definition is composed of:
+	
+- the attributes name (required)
+- if the attribute is required or optional (optional)
+- if the attributes value may be dynamically calculated at runtime
+  by a scriptlet expression (optional)
+- the type of the attributes value (optional)
+- an informal description of the meaning of the attribute (optional)
+
+-->
+
+
+<!--
+The attribute tag defines an attribute for the nesting tag
+
+An attribute definition is composed of:
+
+- the attributes name (required)
+
+- if the attribute is required or optional (optional)
+
+- if the attributes value may be dynamically calculated at runtime
+  by a scriptlet expression (optional)
+
+- the type of the attributes value (optional)
+
+- an informal description of the meaning of the attribute (optional)
+-->
+
+<!ELEMENT attribute (name, required? , rtexprvalue?, type?, description?) >
+
+<!--
+Defines the canonical name of a tag or attribute being defined
+
+#PCDATA ::= NMTOKEN
+-->
+
+<!ELEMENT name	(#PCDATA) >
+
+<!--
+Defines if the nesting attribute is required or optional.
+
+#PCDATA ::= true | false | yes | no
+
+If not present then the default is "false", i.e the attribute
+is optional.
+-->
+
+<!ELEMENT required    (#PCDATA) >
+
+<!--
+Defines if the nesting attribute can have scriptlet expressions as
+a value, i.e the value of the attribute may be dynamically calculated
+at request time, as opposed to a static value determined at translation
+time.
+
+#PCDATA ::= true | false | yes | no
+
+If not present then the default is "false", i.e the attribute
+has a static value
+-->
+
+<!ELEMENT rtexprvalue (#PCDATA) >
+
+
+<!--
+
+Defines the Java type of the attributes value.  For static values
+(those determined at translation time) the type is always
+java.lang.String.
+-->
+
+<!ELEMENT type (#PCDATA) >
+
+
+<!-- ID attributes -->
+
+<!ATTLIST tlib-version id ID #IMPLIED>
+<!ATTLIST jsp-version id ID #IMPLIED>
+<!ATTLIST short-name id ID #IMPLIED>
+<!ATTLIST uri id ID #IMPLIED>
+<!ATTLIST description id ID #IMPLIED>
+<!ATTLIST example id ID #IMPLIED>
+<!ATTLIST tag id ID #IMPLIED>
+<!ATTLIST tag-class id ID #IMPLIED>
+<!ATTLIST tei-class id ID #IMPLIED>
+<!ATTLIST body-content id ID #IMPLIED>
+<!ATTLIST attribute id ID #IMPLIED>
+<!ATTLIST name id ID #IMPLIED>
+<!ATTLIST required id ID #IMPLIED>
+<!ATTLIST rtexprvalue id ID #IMPLIED>
+
+
+<!ATTLIST param-name id ID #IMPLIED>
+<!ATTLIST param-value id ID #IMPLIED>
+<!ATTLIST listener id ID #IMPLIED>
+<!ATTLIST listener-class id ID #IMPLIED>

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/dtd/web-jsptaglibrary_2_0.xsd
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/dtd/web-jsptaglibrary_2_0.xsd	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/dtd/web-jsptaglibrary_2_0.xsd	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,1025 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Copyright 2004 The Apache Software Foundation
+
+  Licensed 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.
+-->
+<xsd:schema
+     targetNamespace="http://java.sun.com/xml/ns/j2ee"
+     xmlns:j2ee="http://java.sun.com/xml/ns/j2ee"
+     xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+     elementFormDefault="qualified"
+     attributeFormDefault="unqualified"
+     version="2.0">
+
+  <xsd:annotation>
+    <xsd:documentation>
+      %W% %G%
+    </xsd:documentation>
+  </xsd:annotation>
+
+  <xsd:annotation>
+    <xsd:documentation>
+
+      Copyright 2003 Sun Microsystems, Inc., 901 San Antonio
+      Road, Palo Alto, California 94303, U.S.A. All rights
+      reserved.
+
+      Sun Microsystems, Inc. has intellectual property rights
+      relating to technology described in this document. In
+      particular, and without limitation, these intellectual
+      property rights may include one or more of the U.S. patents
+      listed at http://www.sun.com/patents and one or more
+      additional patents or pending patent applications in the
+      U.S. and other countries.
+
+      This document and the technology which it describes are
+      distributed under licenses restricting their use, copying,
+      distribution, and decompilation. No part of this document
+      may be reproduced in any form by any means without prior
+      written authorization of Sun and its licensors, if any.
+
+      Third-party software, including font technology, is
+      copyrighted and licensed from Sun suppliers.
+
+      Sun, Sun Microsystems, the Sun logo, Solaris, Java, J2EE,
+      JavaServer Pages, Enterprise JavaBeans and the Java Coffee
+      Cup logo are trademarks or registered trademarks of Sun
+      Microsystems, Inc. in the U.S. and other countries.
+
+      Federal Acquisitions: Commercial Software - Government Users
+      Subject to Standard License Terms and Conditions.
+
+    </xsd:documentation>
+  </xsd:annotation>
+
+  <xsd:annotation>
+    <xsd:documentation>
+      <![CDATA[
+
+	This is the XML Schema for the JSP Taglibrary
+	descriptor.  All Taglibrary descriptors must
+	indicate the tag library schema by using the Taglibrary
+	namespace:
+
+	http://java.sun.com/xml/ns/j2ee
+
+	and by indicating the version of the schema by
+	using the version element as shown below:
+
+	    <taglib xmlns="http://java.sun.com/xml/ns/j2ee"
+	      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	      xsi:schemaLocation="..."
+	      version="2.0">
+	      ...
+	    </taglib>
+
+	The instance documents may indicate the published
+	version of the schema using xsi:schemaLocation attribute
+	for J2EE namespace with the following location:
+
+	http://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd
+
+	]]>
+    </xsd:documentation>
+  </xsd:annotation>
+
+  <xsd:include schemaLocation="j2ee_1_4.xsd"/>
+
+
+<!-- **************************************************** -->
+
+
+  <xsd:element name="taglib" type="j2ee:tldTaglibType">
+    <xsd:annotation>
+      <xsd:documentation>
+
+	The taglib tag is the document root.
+	The definition of taglib is provided
+	by the tldTaglibType.
+
+      </xsd:documentation>
+    </xsd:annotation>
+    <xsd:unique name="tag-name-uniqueness">
+      <xsd:annotation>
+	<xsd:documentation>
+
+	  The taglib element contains, among other things, tag and
+	  tag-file elements.
+	  The name subelements of these elements must each be unique.
+
+	</xsd:documentation>
+      </xsd:annotation>
+      <xsd:selector xpath="j2ee:tag|j2ee:tag-file"/>
+      <xsd:field    xpath="j2ee:name"/>
+    </xsd:unique>
+
+    <xsd:unique name="function-name-uniqueness">
+      <xsd:annotation>
+	<xsd:documentation>
+
+	  The taglib element contains function elements.
+	  The name subelements of these elements must each be unique.
+
+	</xsd:documentation>
+      </xsd:annotation>
+      <xsd:selector xpath="j2ee:function"/>
+      <xsd:field    xpath="j2ee:name"/>
+    </xsd:unique>
+
+  </xsd:element>
+
+
+<!-- **************************************************** -->
+
+  <xsd:complexType name="body-contentType">
+    <xsd:annotation>
+      <xsd:documentation>
+
+        Specifies the type of body that is valid for a tag.
+	This value is used by the JSP container to validate
+	that a tag invocation has the correct body syntax and
+	by page composition tools to assist the page author
+	in providing a valid tag body.
+
+	There are currently four values specified:
+
+	tagdependent    The body of the tag is interpreted by the tag
+			implementation itself, and is most likely
+			in a different "language", e.g embedded SQL
+			statements.
+
+	JSP             The body of the tag contains nested JSP
+			syntax.
+
+	empty           The body must be empty
+
+	scriptless      The body accepts only template text, EL
+			Expressions, and JSP action elements.  No
+			scripting elements are allowed.
+
+      </xsd:documentation>
+    </xsd:annotation>
+
+    <xsd:simpleContent>
+      <xsd:restriction base="j2ee:string">
+	<xsd:enumeration value="tagdependent"/>
+	<xsd:enumeration value="JSP"/>
+	<xsd:enumeration value="empty"/>
+	<xsd:enumeration value="scriptless"/>
+      </xsd:restriction>
+    </xsd:simpleContent>
+  </xsd:complexType>
+
+<!-- **************************************************** -->
+
+  <xsd:complexType name="extensibleType" abstract="true">
+    <xsd:annotation>
+      <xsd:documentation>
+
+	The extensibleType is an abstract base type that is used to
+	define the type of extension-elements. Instance documents
+	must substitute a known type to define the extension by
+	using xsi:type attribute to define the actual type of
+	extension-elements.
+
+      </xsd:documentation>
+    </xsd:annotation>
+    <xsd:attribute name="id" type="xsd:ID"/>
+  </xsd:complexType>
+
+<!-- **************************************************** -->
+
+  <xsd:complexType name="functionType">
+    <xsd:annotation>
+      <xsd:documentation>
+
+	The function element is used to provide information on each
+	function in the tag library that is to be exposed to the EL.
+
+	The function element may have several subelements defining:
+
+	description         Optional tag-specific information
+
+	display-name        A short name that is intended to be
+			    displayed by tools
+
+	icon                Optional icon element that can be used
+			    by tools
+
+	name                A unique name for this function
+
+	function-class      Provides the name of the Java class that
+			    implements the function
+
+	function-signature  Provides the signature, as in the Java
+			    Language Specification, of the Java
+			    method that is to be used to implement
+			    the function.
+
+	example             Optional informal description of an
+			    example of a use of this function
+
+	function-extension  Zero or more extensions that provide extra
+			    information about this function, for tool
+			    consumption
+
+      </xsd:documentation>
+    </xsd:annotation>
+
+    <xsd:sequence>
+      <xsd:group ref="j2ee:descriptionGroup"/>
+      <xsd:element name="name"
+		   type="j2ee:tld-canonical-nameType">
+	<xsd:annotation>
+	  <xsd:documentation>
+
+	    A unique name for this function.
+
+	  </xsd:documentation>
+	</xsd:annotation>
+      </xsd:element>
+      <xsd:element name="function-class"
+		   type="j2ee:fully-qualified-classType">
+	<xsd:annotation>
+	  <xsd:documentation>
+
+	    Provides the fully-qualified class name of the Java
+	    class containing the static method that implements
+	    the function.
+
+	  </xsd:documentation>
+	</xsd:annotation>
+
+      </xsd:element>
+      <xsd:element name="function-signature"
+		   type="j2ee:string">
+	<xsd:annotation>
+	  <xsd:documentation>
+
+	    Provides the signature, of the static Java method that is
+	    to be used to implement the function.  The syntax of the
+	    function-signature element is as follows:
+
+		FunctionSignature ::= ReturnType S MethodName S?
+				      '(' S? Parameters? S? ')'
+
+                ReturnType        ::= Type
+
+		MethodName        ::= Identifier
+
+		Parameters        ::=   Parameter
+				      | ( Parameter S? ',' S? Parameters )
+
+                Parameter         ::= Type
+
+		Where:
+
+ 		    * Type is a basic type or a fully qualified
+		      Java class name (including package name),
+		      as per the 'Type' production in the Java
+		      Language Specification, Second Edition,
+		      Chapter 18.
+
+                    * Identifier is a Java identifier, as per
+		      the 'Identifier' production in the Java
+		      Language Specification, Second
+		      Edition, Chapter 18.
+
+	    Example:
+
+	    java.lang.String nickName( java.lang.String, int )
+
+	  </xsd:documentation>
+	</xsd:annotation>
+
+      </xsd:element>
+      <xsd:element name="example"
+		   type="j2ee:xsdStringType"
+		   minOccurs="0">
+	<xsd:annotation>
+	  <xsd:documentation>
+
+	    The example element contains an informal description
+	    of an example of the use of this function.
+
+	  </xsd:documentation>
+	</xsd:annotation>
+
+      </xsd:element>
+      <xsd:element name="function-extension"
+		   type="j2ee:tld-extensionType"
+		   minOccurs="0"
+		   maxOccurs="unbounded">
+	<xsd:annotation>
+	  <xsd:documentation>
+
+	    Function extensions are for tool use only and must not affect
+	    the behavior of a container.
+
+	  </xsd:documentation>
+	</xsd:annotation>
+      </xsd:element>
+    </xsd:sequence>
+    <xsd:attribute name="id" type="xsd:ID"/>
+  </xsd:complexType>
+
+<!-- **************************************************** -->
+
+  <xsd:complexType name="tagFileType">
+    <xsd:annotation>
+      <xsd:documentation>
+
+	Defines an action in this tag library that is implemented
+	as a .tag file.
+
+	The tag-file element has two required subelements:
+
+	description       Optional tag-specific information
+
+	display-name      A short name that is intended to be
+			  displayed by tools
+
+	icon              Optional icon element that can be used
+			  by tools
+
+	name              The unique action name
+
+	path              Where to find the .tag file implementing this
+			  action, relative to the root of the web
+			  application or the root of the JAR file for a
+			  tag library packaged in a JAR.  This must
+			  begin with /WEB-INF/tags if the .tag file
+			  resides in the WAR, or /META-INF/tags if the
+			  .tag file resides in a JAR.
+
+	example           Optional informal description of an
+			  example of a use of this tag
+
+	tag-extension     Zero or more extensions that provide extra
+			  information about this tag, for tool
+			  consumption
+
+      </xsd:documentation>
+    </xsd:annotation>
+
+    <xsd:sequence>
+      <xsd:group ref="j2ee:descriptionGroup"/>
+      <xsd:element name="name"
+		   type="j2ee:tld-canonical-nameType"/>
+      <xsd:element name="path"
+		   type="j2ee:pathType"/>
+      <xsd:element name="example"
+		   type="j2ee:xsdStringType"
+		   minOccurs="0">
+	<xsd:annotation>
+	  <xsd:documentation>
+
+	    The example element contains an informal description
+	    of an example of the use of a tag.
+
+	  </xsd:documentation>
+	</xsd:annotation>
+
+      </xsd:element>
+      <xsd:element name="tag-extension"
+		   type="j2ee:tld-extensionType"
+		   minOccurs="0"
+		   maxOccurs="unbounded">
+	<xsd:annotation>
+	  <xsd:documentation>
+
+	    Tag extensions are for tool use only and must not affect
+	    the behavior of a container.
+
+	  </xsd:documentation>
+	</xsd:annotation>
+      </xsd:element>
+    </xsd:sequence>
+    <xsd:attribute name="id" type="xsd:ID"/>
+  </xsd:complexType>
+
+<!-- **************************************************** -->
+
+  <xsd:complexType name="tagType">
+    <xsd:annotation>
+      <xsd:documentation>
+
+	The tag defines a unique tag in this tag library.  It has one
+	attribute, id.
+
+	The tag element may have several subelements defining:
+
+	description       Optional tag-specific information
+
+	display-name      A short name that is intended to be
+			  displayed by tools
+
+	icon              Optional icon element that can be used
+			  by tools
+
+	name              The unique action name
+
+	tag-class         The tag handler class implementing
+			  javax.servlet.jsp.tagext.JspTag
+
+	tei-class         An optional subclass of
+			  javax.servlet.jsp.tagext.TagExtraInfo
+
+	body-content      The body content type
+
+	variable          Optional scripting variable information
+
+	attribute         All attributes of this action that are
+			  evaluated prior to invocation.
+
+	dynamic-attributes Whether this tag supports additional
+			   attributes with dynamic names.  If
+			   true, the tag-class must implement the
+			   javax.servlet.jsp.tagext.DynamicAttributes
+			   interface.  Defaults to false.
+
+	example           Optional informal description of an
+			  example of a use of this tag
+
+	tag-extension     Zero or more extensions that provide extra
+			  information about this tag, for tool
+			  consumption
+
+      </xsd:documentation>
+    </xsd:annotation>
+
+    <xsd:sequence>
+      <xsd:group ref="j2ee:descriptionGroup"/>
+      <xsd:element name="name"
+		   type="j2ee:tld-canonical-nameType"/>
+      <xsd:element name="tag-class"
+		   type="j2ee:fully-qualified-classType">
+	<xsd:annotation>
+	  <xsd:documentation>
+
+	    Defines the subclass of javax.serlvet.jsp.tagext.JspTag
+	    that implements the request time semantics for
+	    this tag. (required)
+
+	  </xsd:documentation>
+	</xsd:annotation>
+
+      </xsd:element>
+      <xsd:element name="tei-class"
+		   type="j2ee:fully-qualified-classType"
+		   minOccurs="0">
+	<xsd:annotation>
+	  <xsd:documentation>
+
+	    Defines the subclass of javax.servlet.jsp.tagext.TagExtraInfo
+	    for this tag. (optional)
+
+	    If this is not given, the class is not consulted at
+	    translation time.
+
+	  </xsd:documentation>
+	</xsd:annotation>
+      </xsd:element>
+      <xsd:element name="body-content"
+		   type="j2ee:body-contentType">
+	<xsd:annotation>
+	  <xsd:documentation>
+
+	    Specifies the format for the body of this tag.
+	    The default in JSP 1.2 was "JSP" but because this
+	    is an invalid setting for simple tag handlers, there
+	    is no longer a default in JSP 2.0.  A reasonable
+	    default for simple tag handlers is "scriptless" if
+	    the tag can have a body.
+
+	  </xsd:documentation>
+	</xsd:annotation>
+      </xsd:element>
+      <xsd:element name="variable"
+		   type="j2ee:variableType"
+		   minOccurs="0" maxOccurs="unbounded"/>
+      <xsd:element name="attribute"
+		   type="j2ee:tld-attributeType"
+		   minOccurs="0" maxOccurs="unbounded"/>
+      <xsd:element name="dynamic-attributes"
+		   type="j2ee:generic-booleanType"
+		   minOccurs="0"/>
+      <xsd:element name="example"
+		   type="j2ee:xsdStringType"
+		   minOccurs="0">
+	<xsd:annotation>
+	  <xsd:documentation>
+
+	    The example element contains an informal description
+	    of an example of the use of a tag.
+
+	  </xsd:documentation>
+	</xsd:annotation>
+
+      </xsd:element>
+      <xsd:element name="tag-extension"
+		   type="j2ee:tld-extensionType"
+		   minOccurs="0"
+		   maxOccurs="unbounded">
+	<xsd:annotation>
+	  <xsd:documentation>
+
+	    Tag extensions are for tool use only and must not affect
+	    the behavior of a container.
+
+	  </xsd:documentation>
+	</xsd:annotation>
+      </xsd:element>
+    </xsd:sequence>
+    <xsd:attribute name="id" type="xsd:ID"/>
+  </xsd:complexType>
+
+<!-- **************************************************** -->
+
+  <xsd:complexType name="tld-attributeType">
+    <xsd:annotation>
+      <xsd:documentation>
+
+	The attribute element defines an attribute for the nesting
+	tag.  The attributre element may have several subelements
+	defining:
+
+	description     a description of the attribute
+
+	name            the name of the attribute
+
+	required        whether the attribute is required or
+			optional
+
+	rtexprvalue     whether the attribute is a runtime attribute
+
+	type            the type of the attributes
+
+	fragment        whether this attribute is a fragment
+
+      </xsd:documentation>
+    </xsd:annotation>
+    <xsd:sequence>
+      <xsd:element name="description"
+		   type="j2ee:descriptionType"
+		   minOccurs="0" maxOccurs="unbounded"/>
+      <xsd:element name="name"
+		   type="j2ee:java-identifierType"/>
+      <xsd:element name="required"
+		   type="j2ee:generic-booleanType"
+		   minOccurs="0">
+	<xsd:annotation>
+	  <xsd:documentation>
+
+	    Defines if the nesting attribute is required or
+	    optional.
+
+	    If not present then the default is "false", i.e
+	    the attribute is optional.
+
+	  </xsd:documentation>
+	</xsd:annotation>
+      </xsd:element>
+
+      <xsd:choice>
+	<xsd:sequence>
+	  <xsd:element name="rtexprvalue"
+		       type="j2ee:generic-booleanType"
+		       minOccurs="0">
+	    <xsd:annotation>
+	      <xsd:documentation>
+
+		Defines if the nesting attribute can have scriptlet
+		expressions as a value, i.e the value of the
+		attribute may be dynamically calculated at request
+		time, as opposed to a static value determined at
+		translation time.
+
+		If not present then the default is "false", i.e the
+		attribute has a static value
+
+	      </xsd:documentation>
+	    </xsd:annotation>
+
+	  </xsd:element>
+	  <xsd:element name="type"
+		       type="j2ee:fully-qualified-classType"
+		       minOccurs="0">
+	    <xsd:annotation>
+	      <xsd:documentation>
+
+		Defines the Java type of the attributes value.  For
+		static values (those determined at translation time)
+		the type is always java.lang.String.
+
+	      </xsd:documentation>
+	    </xsd:annotation>
+	  </xsd:element>
+	</xsd:sequence>
+	<xsd:element name="fragment"
+		     type="j2ee:generic-booleanType"
+		     minOccurs="0">
+	  <xsd:annotation>
+	    <xsd:documentation>
+
+	      "true" if this attribute is of type
+	      javax.jsp.tagext.JspFragment, representing dynamic
+	      content that can be re-evaluated as many times
+	      as needed by the tag handler.  If omitted or "false",
+	      the default is still type="java.lang.String"
+
+	    </xsd:documentation>
+	  </xsd:annotation>
+	</xsd:element>
+      </xsd:choice>
+    </xsd:sequence>
+    <xsd:attribute name="id" type="xsd:ID"/>
+  </xsd:complexType>
+
+<!-- **************************************************** -->
+
+  <xsd:complexType name="tld-canonical-nameType">
+
+    <xsd:annotation>
+      <xsd:documentation>
+
+	Defines the canonical name of a tag or attribute being
+	defined.
+
+	The name must conform to the lexical rules for an NMTOKEN.
+
+      </xsd:documentation>
+    </xsd:annotation>
+
+    <xsd:simpleContent>
+      <xsd:restriction base="j2ee:xsdNMTOKENType"/>
+    </xsd:simpleContent>
+  </xsd:complexType>
+
+<!-- **************************************************** -->
+
+  <xsd:complexType name="tld-extensionType">
+    <xsd:annotation>
+      <xsd:documentation>
+
+	The tld-extensionType is used to indicate
+	extensions to a specific TLD element.
+
+	It is used by elements to designate an extension block
+	that is targeted to a specific extension designated by
+	a set of extension elements that are declared by a
+	namespace. The namespace identifies the extension to
+	the tool that processes the extension.
+
+	The type of the extension-element is abstract. Therefore,
+	a concrete type must be specified by the TLD using
+	xsi:type attribute for each extension-element.
+
+      </xsd:documentation>
+    </xsd:annotation>
+
+    <xsd:sequence>
+      <xsd:element name="extension-element"
+		   type="j2ee:extensibleType"
+		   maxOccurs="unbounded"/>
+    </xsd:sequence>
+
+    <xsd:attribute name="namespace"
+		   use="required"
+		   type="xsd:anyURI"/>
+    <xsd:attribute name="id" type="xsd:ID"/>
+
+  </xsd:complexType>
+
+<!-- **************************************************** -->
+
+  <xsd:complexType name="tldTaglibType">
+    <xsd:annotation>
+      <xsd:documentation>
+
+	The taglib tag is the document root, it defines:
+
+	description     a simple string describing the "use" of this
+			taglib, should be user discernable
+
+	display-name    the display-name element contains a
+			short name that is intended to be displayed
+			by tools
+
+	icon            optional icon that can be used by tools
+
+	tlib-version    the version of the tag library implementation
+
+	short-name      a simple default short name that could be
+			used by a JSP authoring tool to create
+			names with a mnemonic value; for example,
+			the it may be used as the prefered prefix
+			value in taglib directives
+
+	uri             a uri uniquely identifying this taglib
+
+	validator       optional TagLibraryValidator information
+
+	listener        optional event listener specification
+
+	tag             tags in this tag library
+
+	tag-file        tag files in this tag library
+
+	function        zero or more EL functions defined in this
+			tag library
+
+	taglib-extension zero or more extensions that provide extra
+			information about this taglib, for tool
+			consumption
+
+      </xsd:documentation>
+    </xsd:annotation>
+    <xsd:sequence>
+      <xsd:group ref="j2ee:descriptionGroup"/>
+      <xsd:element name="tlib-version"
+		   type="j2ee:dewey-versionType">
+	<xsd:annotation>
+	  <xsd:documentation>
+
+	    Describes this version (number) of the taglibrary.
+	    It is described as a dewey decimal.
+
+	  </xsd:documentation>
+	</xsd:annotation>
+
+      </xsd:element>
+
+      <xsd:element name="short-name"
+		   type="j2ee:tld-canonical-nameType">
+	<xsd:annotation>
+	  <xsd:documentation>
+
+	    Defines a simple default name that could be used by
+	    a JSP authoring tool to create names with a
+	    mnemonicvalue; for example, it may be used as the
+	    preferred prefix value in taglib directives.  Do
+	    not use white space, and do not start with digits
+	    or underscore.
+
+	  </xsd:documentation>
+	</xsd:annotation>
+
+      </xsd:element>
+      <xsd:element name="uri"
+		   type="j2ee:xsdAnyURIType"
+		   minOccurs="0">
+	<xsd:annotation>
+	  <xsd:documentation>
+
+	    Defines a public URI that uniquely identifies this
+	    version of the taglibrary.  Leave it empty if it
+	    does not apply.
+
+	  </xsd:documentation>
+	</xsd:annotation>
+
+      </xsd:element>
+      <xsd:element name="validator"
+		   type="j2ee:validatorType"
+		   minOccurs="0">
+      </xsd:element>
+      <xsd:element name="listener"
+		   type="j2ee:listenerType"
+		   minOccurs="0" maxOccurs="unbounded">
+      </xsd:element>
+      <xsd:element name="tag"
+		   type="j2ee:tagType"
+		   minOccurs="0"
+		   maxOccurs="unbounded"/>
+      <xsd:element name="tag-file"
+		   type="j2ee:tagFileType"
+		   minOccurs="0"
+		   maxOccurs="unbounded"/>
+      <xsd:element name="function"
+		   type="j2ee:functionType"
+		   minOccurs="0"
+		   maxOccurs="unbounded"/>
+      <xsd:element name="taglib-extension"
+		   type="j2ee:tld-extensionType"
+		   minOccurs="0"
+		   maxOccurs="unbounded">
+	<xsd:annotation>
+	  <xsd:documentation>
+
+	    Taglib extensions are for tool use only and must not affect
+	    the behavior of a container.
+
+	  </xsd:documentation>
+	</xsd:annotation>
+      </xsd:element>
+    </xsd:sequence>
+    <xsd:attribute name="version"
+		   type="j2ee:dewey-versionType"
+		   fixed="2.0"
+		   use="required">
+      <xsd:annotation>
+	<xsd:documentation>
+
+	  Describes the JSP version (number) this taglibrary
+	  requires in order to function (dewey decimal)
+
+	</xsd:documentation>
+      </xsd:annotation>
+
+    </xsd:attribute>
+    <xsd:attribute name="id" type="xsd:ID"/>
+  </xsd:complexType>
+
+<!-- **************************************************** -->
+
+  <xsd:complexType name="validatorType">
+    <xsd:annotation>
+      <xsd:documentation>
+
+	A validator that can be used to validate
+	the conformance of a JSP page to using this tag library is
+	defined by a validatorType.
+
+      </xsd:documentation>
+    </xsd:annotation>
+
+    <xsd:sequence>
+      <xsd:element name="description"
+		   type="j2ee:descriptionType"
+		   minOccurs="0"
+		   maxOccurs="unbounded"/>
+      <xsd:element name="validator-class"
+		   type="j2ee:fully-qualified-classType">
+	<xsd:annotation>
+	  <xsd:documentation>
+
+	    Defines the TagLibraryValidator class that can be used
+	    to validate the conformance of a JSP page to using this
+	    tag library.
+
+	  </xsd:documentation>
+	</xsd:annotation>
+      </xsd:element>
+      <xsd:element name="init-param"
+		   type="j2ee:param-valueType"
+		   minOccurs="0" maxOccurs="unbounded">
+	<xsd:annotation>
+	  <xsd:documentation>
+
+	    The init-param element contains a name/value pair as an
+	    initialization param.
+
+	  </xsd:documentation>
+	</xsd:annotation>
+
+      </xsd:element>
+
+    </xsd:sequence>
+    <xsd:attribute name="id" type="xsd:ID"/>
+  </xsd:complexType>
+
+<!-- **************************************************** -->
+
+  <xsd:complexType name="variable-scopeType">
+    <xsd:annotation>
+      <xsd:documentation>
+
+	This type defines scope of the scripting variable.  See
+	TagExtraInfo for details.  The allowed values are,
+	"NESTED", "AT_BEGIN" and "AT_END".
+
+      </xsd:documentation>
+    </xsd:annotation>
+
+    <xsd:simpleContent>
+      <xsd:restriction base="j2ee:string">
+	<xsd:enumeration value="NESTED"/>
+	<xsd:enumeration value="AT_BEGIN"/>
+	<xsd:enumeration value="AT_END"/>
+      </xsd:restriction>
+    </xsd:simpleContent>
+  </xsd:complexType>
+
+<!-- **************************************************** -->
+
+  <xsd:complexType name="variableType">
+    <xsd:annotation>
+      <xsd:documentation>
+
+	The variableType provides information on the scripting
+	variables defined by using this tag.  It is a (translation
+	time) error for a tag that has one or more variable
+	subelements to have a TagExtraInfo class that returns a
+	non-null value from a call to getVariableInfo().
+
+	The subelements of variableType are of the form:
+
+	description              Optional description of this
+				 variable
+
+	name-given               The variable name as a constant
+
+	name-from-attribute      The name of an attribute whose
+				 (translation time) value will
+				 give the name of the
+				 variable.  One of name-given or
+				 name-from-attribute is required.
+
+	variable-class           Name of the class of the variable.
+				 java.lang.String is default.
+
+	declare                  Whether the variable is declared
+				 or not.  True is the default.
+
+	scope                    The scope of the scripting varaible
+				 defined.  NESTED is default.
+
+      </xsd:documentation>
+    </xsd:annotation>
+
+    <xsd:sequence>
+      <xsd:element name="description"
+		   type="j2ee:descriptionType"
+		   minOccurs="0" maxOccurs="unbounded"/>
+      <xsd:choice>
+	<xsd:element name="name-given"
+		     type="j2ee:java-identifierType">
+	  <xsd:annotation>
+	    <xsd:documentation>
+
+	      The name for the scripting variable.
+
+	    </xsd:documentation>
+	  </xsd:annotation>
+	</xsd:element>
+
+	<xsd:element name="name-from-attribute"
+		     type="j2ee:java-identifierType">
+	  <xsd:annotation>
+	    <xsd:documentation>
+
+	      The name of an attribute whose
+	      (translation-time) value will give the name of
+	      the variable.
+
+	    </xsd:documentation>
+	  </xsd:annotation>
+	</xsd:element>
+      </xsd:choice>
+      <xsd:element name="variable-class"
+		   type="j2ee:fully-qualified-classType"
+		   minOccurs="0">
+	<xsd:annotation>
+	  <xsd:documentation>
+
+	    The optional name of the class for the scripting
+	    variable.  The default is java.lang.String.
+
+	  </xsd:documentation>
+	</xsd:annotation>
+
+      </xsd:element>
+
+      <xsd:element name="declare"
+		   type="j2ee:generic-booleanType"
+		   minOccurs="0">
+
+	<xsd:annotation>
+	  <xsd:documentation>
+
+	    Whether the scripting variable is to be defined
+	    or not.  See TagExtraInfo for details.  This
+	    element is optional and "true" is the default.
+
+	  </xsd:documentation>
+	</xsd:annotation>
+      </xsd:element>
+      <xsd:element name="scope"
+		   type="j2ee:variable-scopeType"
+		   minOccurs="0">
+	<xsd:annotation>
+	  <xsd:documentation>
+
+	    The element is optional and "NESTED" is the default.
+
+	  </xsd:documentation>
+	</xsd:annotation>
+      </xsd:element>
+    </xsd:sequence>
+    <xsd:attribute name="id" type="xsd:ID"/>
+  </xsd:complexType>
+
+</xsd:schema>
+

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/ErrorData.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/ErrorData.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/ErrorData.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,88 @@
+/*
+* Copyright 2004 The Apache Software Foundation
+*
+* Licensed 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.jsp;
+
+/**
+ * Contains information about an error, for error pages.
+ * The information contained in this instance is meaningless if not used
+ * in the context of an error page.  To indicate a JSP is an error page,
+ * the page author must set the isErrorPage attribute of the page directive
+ * to "true".
+ *
+ * @see PageContext#getErrorData
+ * @since 2.0
+ */
+
+public final class ErrorData {
+
+    private Throwable throwable;
+    private int statusCode;
+    private String uri;
+    private String servletName;
+
+    /**
+     * Creates a new ErrorData object.
+     *
+     * @param throwable The Throwable that is the cause of the error
+     * @param statusCode The status code of the error
+     * @param uri The request URI
+     * @param servletName The name of the servlet invoked
+     */
+    public ErrorData( Throwable throwable, int statusCode, String uri, 
+	String servletName )
+    {
+	this.throwable = throwable;
+	this.statusCode = statusCode;
+	this.uri = uri;
+	this.servletName = servletName;
+    }
+
+    /**
+     * Returns the Throwable that caused the error.
+     *
+     * @return The Throwable that caused the error
+     */
+    public Throwable getThrowable() {
+	return this.throwable;
+    }
+
+    /**
+     * Returns the status code of the error.
+     *
+     * @return The status code of the error
+     */
+    public int getStatusCode() {
+	return this.statusCode;
+    }
+
+    /**
+     * Returns the request URI.
+     *
+     * @return The request URI
+     */
+    public String getRequestURI() {
+	return this.uri;
+    }
+
+    /**
+     * Returns the name of the servlet invoked.
+     *
+     * @return The name of the servlet invoked
+     */
+    public String getServletName() {
+	return this.servletName;
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/HttpJspPage.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/HttpJspPage.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/HttpJspPage.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,57 @@
+/*
+* Copyright 2004 The Apache Software Foundation
+*
+* Licensed 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.jsp;
+
+import javax.servlet.*;
+import javax.servlet.http.*;
+import java.io.IOException;
+
+/**
+ * The HttpJspPage interface describes the interaction that a JSP Page
+ * Implementation Class must satisfy when using the HTTP protocol.
+ *
+ * <p>
+ * The behaviour is identical to that of the JspPage, except for the signature
+ * of the _jspService method, which is now expressible in the Java type
+ * system and included explicitly in the interface.
+ * 
+ * @see JspPage
+ */
+
+public interface HttpJspPage extends JspPage {
+
+    /** The _jspService()method corresponds to the body of the JSP page. This
+     * method is defined automatically by the JSP container and should never
+     * be defined by the JSP page author.
+     * <p>
+     * If a superclass is specified using the extends attribute, that
+     * superclass may choose to perform some actions in its service() method
+     * before or after calling the _jspService() method.  See using the extends
+     * attribute in the JSP_Engine chapter of the JSP specification.
+     *
+     * @param request Provides client request information to the JSP.
+     * @param response Assists the JSP in sending a response to the client.
+     * @throws ServletException Thrown if an error occurred during the 
+     *     processing of the JSP and that the container should take 
+     *     appropriate action to clean up the request.
+     * @throws IOException Thrown if an error occurred while writing the
+     *     response for this page.
+     */
+    public void _jspService(HttpServletRequest request,
+                            HttpServletResponse response)
+       throws ServletException, IOException;
+}

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/JspContext.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/JspContext.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/JspContext.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,270 @@
+/*
+* Copyright 2004 The Apache Software Foundation
+*
+* Licensed 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.jsp;
+
+import java.util.Enumeration;
+
+import javax.servlet.jsp.el.ExpressionEvaluator;
+import javax.servlet.jsp.el.VariableResolver;
+
+/**
+ * <p>
+ * <code>JspContext</code> serves as the base class for the 
+ * PageContext class and abstracts all information that is not specific
+ * to servlets.  This allows for Simple Tag Extensions to be used
+ * outside of the context of a request/response Servlet.
+ * <p>
+ * The JspContext provides a number of facilities to the 
+ * page/component author and page implementor, including:
+ * <ul>
+ * <li>a single API to manage the various scoped namespaces
+ * <li>a mechanism to obtain the JspWriter for output
+ * <li>a mechanism to expose page directive attributes to the 
+ *     scripting environment
+ * </ul>
+ *
+ * <p><B>Methods Intended for Container Generated Code</B>
+ * <p>
+ * The following methods enable the <B>management of nested</B> JspWriter 
+ * streams to implement Tag Extensions: <code>pushBody()</code> and
+ * <code>popBody()</code>
+ *
+ * <p><B>Methods Intended for JSP authors</B>
+ * <p>
+ * Some methods provide <B>uniform access</B> to the diverse objects
+ * representing scopes.
+ * The implementation must use the underlying machinery
+ * corresponding to that scope, so information can be passed back and
+ * forth between the underlying environment (e.g. Servlets) and JSP pages.
+ * The methods are:
+ * <code>setAttribute()</code>,  <code>getAttribute()</code>,
+ * <code>findAttribute()</code>,  <code>removeAttribute()</code>,
+ * <code>getAttributesScope()</code> and 
+ * <code>getAttributeNamesInScope()</code>.
+ * 
+ * <p>
+ * The following methods provide <B>convenient access</B> to implicit objects:
+ * <code>getOut()</code>
+ *
+ * <p>
+ * The following methods provide <B>programmatic access</b> to the 
+ * Expression Language evaluator:
+ * <code>getExpressionEvaluator()</code>, <code>getVariableResolver()</code>
+ *
+ * @since 2.0
+ */
+
+public abstract class JspContext {
+
+    /**
+     * Sole constructor. (For invocation by subclass constructors, 
+     * typically implicit.)
+     */
+    public JspContext() {
+    }
+    
+    /** 
+     * Register the name and value specified with page scope semantics.
+     * If the value passed in is <code>null</code>, this has the same 
+     * effect as calling 
+     * <code>removeAttribute( name, PageContext.PAGE_SCOPE )</code>.
+     *
+     * @param name the name of the attribute to set
+     * @param value the value to associate with the name, or null if the
+     *     attribute is to be removed from the page scope.
+     * @throws NullPointerException if the name is null
+     */
+
+    abstract public void setAttribute(String name, Object value);
+
+    /**
+     * Register the name and value specified with appropriate 
+     * scope semantics.  If the value passed in is <code>null</code>, 
+     * this has the same effect as calling
+     * <code>removeAttribute( name, scope )</code>.
+     * 
+     * @param name the name of the attribute to set
+     * @param value the object to associate with the name, or null if
+     *     the attribute is to be removed from the specified scope.
+     * @param scope the scope with which to associate the name/object
+     * 
+     * @throws NullPointerException if the name is null
+     * @throws IllegalArgumentException if the scope is invalid
+     * @throws IllegalStateException if the scope is 
+     *     PageContext.SESSION_SCOPE but the page that was requested
+     *     does not participate in a session or the session has been
+     *     invalidated.
+     */
+
+    abstract public void setAttribute(String name, Object value, int scope);
+
+    /**
+     * Returns the object associated with the name in the page scope or null
+     * if not found.
+     *
+     * @param name the name of the attribute to get
+     * @return the object associated with the name in the page scope 
+     *     or null if not found.
+     * 
+     * @throws NullPointerException if the name is null
+     */
+
+    abstract public Object getAttribute(String name);
+
+    /**
+     * Return the object associated with the name in the specified
+     * scope or null if not found.
+     *
+     * @param name the name of the attribute to set
+     * @param scope the scope with which to associate the name/object
+     * @return the object associated with the name in the specified
+     *     scope or null if not found.
+     * 
+     * @throws NullPointerException if the name is null
+     * @throws IllegalArgumentException if the scope is invalid 
+     * @throws IllegalStateException if the scope is 
+     *     PageContext.SESSION_SCOPE but the page that was requested
+     *     does not participate in a session or the session has been
+     *     invalidated.
+     */
+
+    abstract public Object getAttribute(String name, int scope);
+
+    /**
+     * Searches for the named attribute in page, request, session (if valid),
+     * and application scope(s) in order and returns the value associated or
+     * null.
+     *
+     * @param name the name of the attribute to search for
+     * @return the value associated or null
+     * @throws NullPointerException if the name is null
+     */
+
+    abstract public Object findAttribute(String name);
+
+    /**
+     * Remove the object reference associated with the given name
+     * from all scopes.  Does nothing if there is no such object.
+     *
+     * @param name The name of the object to remove.
+     * @throws NullPointerException if the name is null
+     */
+
+    abstract public void removeAttribute(String name);
+
+    /**
+     * Remove the object reference associated with the specified name
+     * in the given scope.  Does nothing if there is no such object.
+     *
+     * @param name The name of the object to remove.
+     * @param scope The scope where to look.
+     * @throws IllegalArgumentException if the scope is invalid
+     * @throws IllegalStateException if the scope is 
+     *     PageContext.SESSION_SCOPE but the page that was requested
+     *     does not participate in a session or the session has been
+     *     invalidated.
+     * @throws NullPointerException if the name is null
+     */
+
+    abstract public void removeAttribute(String name, int scope);
+
+    /**
+     * Get the scope where a given attribute is defined.
+     *
+     * @param name the name of the attribute to return the scope for
+     * @return the scope of the object associated with the name specified or 0
+     * @throws NullPointerException if the name is null
+     */
+
+    abstract public int getAttributesScope(String name);
+
+    /**
+     * Enumerate all the attributes in a given scope.
+     *
+     * @param scope the scope to enumerate all the attributes for
+     * @return an enumeration of names (java.lang.String) of all the 
+     *     attributes the specified scope
+     * @throws IllegalArgumentException if the scope is invalid
+     * @throws IllegalStateException if the scope is 
+     *     PageContext.SESSION_SCOPE but the page that was requested
+     *     does not participate in a session or the session has been
+     *     invalidated.
+     */
+
+    abstract public Enumeration getAttributeNamesInScope(int scope);
+
+    /**
+     * The current value of the out object (a JspWriter).
+     *
+     * @return the current JspWriter stream being used for client response
+     */
+    abstract public JspWriter getOut();
+    
+    /**
+     * Provides programmatic access to the ExpressionEvaluator.
+     * The JSP Container must return a valid instance of an 
+     * ExpressionEvaluator that can parse EL expressions.
+     *
+     * @return A valid instance of an ExpressionEvaluator.
+     * @since 2.0
+     */
+    public abstract ExpressionEvaluator getExpressionEvaluator();
+    
+    /**
+     * Returns an instance of a VariableResolver that provides access to the
+     * implicit objects specified in the JSP specification using this JspContext
+     * as the context object.
+     *
+     * @return A valid instance of a VariableResolver.
+     * @since 2.0
+     */
+    public abstract VariableResolver getVariableResolver();
+    
+    /**
+     * Return a new JspWriter object that sends output to the
+     * provided Writer.  Saves the current "out" JspWriter,
+     * and updates the value of the "out" attribute in the
+     * page scope attribute namespace of the JspContext.
+     * <p>The returned JspWriter must implement all methods and
+     * behave as though it were unbuffered.  More specifically:
+     * <ul>
+     *   <li>clear() must throw an IOException</li>
+     *   <li>clearBuffer() does nothing</li>
+     *   <li>getBufferSize() always returns 0</li>
+     *   <li>getRemaining() always returns 0</li>
+     * </ul>
+     * </p>
+     *
+     * @param writer The Writer for the returned JspWriter to send
+     *     output to.
+     * @return a new JspWriter that writes to the given Writer.
+     * @since 2.0
+     */
+    public JspWriter pushBody( java.io.Writer writer ) {
+        return null; // XXX to implement
+    }
+    
+    /**
+     * Return the previous JspWriter "out" saved by the matching
+     * pushBody(), and update the value of the "out" attribute in
+     * the page scope attribute namespace of the JspContext.
+     *
+     * @return the saved JspWriter.
+     */
+    public JspWriter popBody() {
+        return null; // XXX to implement
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/JspEngineInfo.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/JspEngineInfo.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/JspEngineInfo.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,47 @@
+/*
+* Copyright 2004 The Apache Software Foundation
+*
+* Licensed 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.jsp;
+
+/**
+ * The JspEngineInfo is an abstract class that provides information on the
+ * current JSP engine.
+ */
+
+public abstract class JspEngineInfo {
+
+    /**
+     * Sole constructor. (For invocation by subclass constructors, 
+     * typically implicit.)
+     */
+    public JspEngineInfo() {
+    }
+    
+    /**
+     * Return the version number of the JSP specification that is supported by
+     * this JSP engine.
+     * <p>
+     * Specification version numbers that consists of positive decimal integers
+     * separated by periods ".", for example, "2.0" or "1.2.3.4.5.6.7".
+     * This allows an extensible number to be used to
+     * represent major, minor, micro, etc versions.
+     * The version number must begin with a number.
+     * </p>
+     *
+     * @return the specification version, null is returned if it is not known
+     */
+
+    public abstract String getSpecificationVersion();
+}

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/JspException.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/JspException.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/JspException.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,112 @@
+/*
+* Copyright 2004 The Apache Software Foundation
+*
+* Licensed 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.jsp;
+
+/**
+ * A generic exception known to the JSP engine; uncaught
+ * JspExceptions will result in an invocation of the errorpage
+ * machinery.
+ */
+
+public class JspException extends Exception {
+
+    private Throwable rootCause;
+
+
+    /**
+     * Construct a JspException.
+     */
+    public JspException() {
+    }
+
+
+    /**
+     * Constructs a new JSP exception with the
+     * specified message. The message can be written 
+     * to the server log and/or displayed for the user. 
+     *
+     * @param msg 		a <code>String</code> 
+     *				specifying the text of 
+     *				the exception message
+     *
+     */
+    public JspException(String msg) {
+	super(msg);
+    }
+
+
+    /**
+     * Constructs a new JSP exception when the JSP 
+     * needs to throw an exception and include a message 
+     * about the "root cause" exception that interfered with its 
+     * normal operation, including a description message.
+     *
+     *
+     * @param message 		a <code>String</code> containing 
+     *				the text of the exception message
+     *
+     * @param rootCause		the <code>Throwable</code> exception 
+     *				that interfered with the servlet's
+     *				normal operation, making this servlet
+     *				exception necessary
+     *
+     */
+    
+    public JspException(String message, Throwable rootCause) {
+	super(message);
+	this.rootCause = rootCause;
+    }
+
+
+    /**
+     * Constructs a new JSP exception when the JSP 
+     * needs to throw an exception and include a message
+     * about the "root cause" exception that interfered with its
+     * normal operation.  The exception's message is based on the localized
+     * message of the underlying exception.
+     *
+     * <p>This method calls the <code>getLocalizedMessage</code> method
+     * on the <code>Throwable</code> exception to get a localized exception
+     * message. When subclassing <code>JspException</code>, 
+     * this method can be overridden to create an exception message 
+     * designed for a specific locale.
+     *
+     * @param rootCause 	the <code>Throwable</code> exception
+     * 				that interfered with the JSP's
+     *				normal operation, making the JSP exception
+     *				necessary
+     *
+     */
+
+    public JspException(Throwable rootCause) {
+	super(rootCause.getLocalizedMessage());
+	this.rootCause = rootCause;
+    }
+
+    
+    /**
+     * Returns the exception that caused this JSP exception.
+     *
+     *
+     * @return			the <code>Throwable</code> 
+     *				that caused this JSP exception
+     *
+     */
+    
+    public Throwable getRootCause() {
+	return rootCause;
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/JspFactory.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/JspFactory.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/JspFactory.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,142 @@
+/*
+* Copyright 2004 The Apache Software Foundation
+*
+* Licensed 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.jsp;
+
+import javax.servlet.Servlet;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.jsp.PageContext;
+
+/**
+ * <p>
+ * The JspFactory is an abstract class that defines a number of factory
+ * methods available to a JSP page at runtime for the purposes of creating
+ * instances of various interfaces and classes used to support the JSP 
+ * implementation.
+ * <p>
+ * A conformant JSP Engine implementation will, during it's initialization
+ * instantiate an implementation dependent subclass of this class, and make 
+ * it globally available for use by JSP implementation classes by registering
+ * the instance created with this class via the
+ * static <code> setDefaultFactory() </code> method.
+ * <p>
+ * The PageContext and the JspEngineInfo classes are the only implementation-dependent
+ * classes that can be created from the factory.
+ * <p>
+ * JspFactory objects should not be used by JSP page authors.
+ */
+
+public abstract class JspFactory {
+
+    private static JspFactory deflt = null;
+    
+    /**
+     * Sole constructor. (For invocation by subclass constructors, 
+     * typically implicit.)
+     */
+    public JspFactory() {
+    }
+
+    /**
+     * <p>
+     * set the default factory for this implementation. It is illegal for
+     * any principal other than the JSP Engine runtime to call this method.
+     * </p>
+     *
+     * @param deflt	The default factory implementation
+     */
+
+    public static synchronized void setDefaultFactory(JspFactory deflt) {
+	JspFactory.deflt = deflt;
+    }
+
+    /**
+     * Returns the default factory for this implementation.
+     *
+     * @return the default factory for this implementation
+     */
+
+    public static synchronized JspFactory getDefaultFactory() {
+	return deflt;
+    }
+
+    /**
+     * <p>
+     * obtains an instance of an implementation dependent 
+     * javax.servlet.jsp.PageContext abstract class for the calling Servlet
+     * and currently pending request and response.
+     * </p>
+     *
+     * <p>
+     * This method is typically called early in the processing of the 
+     * _jspService() method of a JSP implementation class in order to 
+     * obtain a PageContext object for the request being processed.
+     * </p>
+     * <p>
+     * Invoking this method shall result in the PageContext.initialize()
+     * method being invoked. The PageContext returned is properly initialized.
+     * </p>
+     * <p>
+     * All PageContext objects obtained via this method shall be released
+     * by invoking releasePageContext().
+     * </p>
+     *
+     * @param servlet   the requesting servlet
+     * @param request	the current request pending on the servlet
+     * @param response	the current response pending on the servlet
+     * @param errorPageURL the URL of the error page for the requesting JSP, or null
+     * @param needsSession true if the JSP participates in a session
+     * @param buffer	size of buffer in bytes, PageContext.NO_BUFFER if no buffer,
+     *			PageContext.DEFAULT_BUFFER if implementation default.
+     * @param autoflush	should the buffer autoflush to the output stream on buffer
+     *			overflow, or throw an IOException?
+     *
+     * @return the page context
+     *
+     * @see javax.servlet.jsp.PageContext
+     */
+
+    public abstract PageContext getPageContext(Servlet	       servlet,
+				    	       ServletRequest  request,
+				    	       ServletResponse response,
+				    	       String	       errorPageURL,
+				    	       boolean         needsSession,
+				    	       int             buffer,
+				    	       boolean         autoflush);
+
+    /**
+     * <p>
+     * called to release a previously allocated PageContext object.
+     * Results in PageContext.release() being invoked.
+     * This method should be invoked prior to returning from the _jspService() method of a JSP implementation
+     * class.
+     * </p>
+     *
+     * @param pc A PageContext previously obtained by getPageContext()
+     */
+
+    public abstract void releasePageContext(PageContext pc);
+
+    /**
+     * <p>
+     * called to get implementation-specific information on the current JSP engine.
+     * </p>
+     *
+     * @return a JspEngineInfo object describing the current JSP engine
+     */
+    
+    public abstract JspEngineInfo getEngineInfo();
+}

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/JspPage.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/JspPage.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/JspPage.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,89 @@
+/*
+* Copyright 2004 The Apache Software Foundation
+*
+* Licensed 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.jsp;
+
+import javax.servlet.*;
+
+/**
+ * The JspPage interface describes the generic interaction that a JSP Page
+ * Implementation class must satisfy; pages that use the HTTP protocol
+ * are described by the HttpJspPage interface.
+ *
+ * <p><B>Two plus One Methods</B>
+ * <p>
+ * The interface defines a protocol with 3 methods; only two of
+ * them: jspInit() and jspDestroy() are part of this interface as
+ * the signature of the third method: _jspService() depends on
+ * the specific protocol used and cannot be expressed in a generic
+ * way in Java.
+ * <p>
+ * A class implementing this interface is responsible for invoking
+ * the above methods at the appropriate time based on the
+ * corresponding Servlet-based method invocations.
+ * <p>
+ * The jspInit() and jspDestroy() methods can be defined by a JSP
+ * author, but the _jspService() method is defined automatically
+ * by the JSP processor based on the contents of the JSP page.
+ *
+ * <p><B>_jspService()</B>
+ * <p>
+ * The _jspService()method corresponds to the body of the JSP page. This
+ * method is defined automatically by the JSP container and should never
+ * be defined by the JSP page author.
+ * <p>
+ * If a superclass is specified using the extends attribute, that
+ * superclass may choose to perform some actions in its service() method
+ * before or after calling the _jspService() method.  See using the extends
+ * attribute in the JSP_Engine chapter of the JSP specification.
+ * <p>
+ * The specific signature depends on the protocol supported by the JSP page.
+ *
+ * <pre>
+ * public void _jspService(<em>ServletRequestSubtype</em> request,
+ *                             <em>ServletResponseSubtype</em> response)
+ *        throws ServletException, IOException;
+ * </pre>
+ */
+
+
+public interface JspPage extends Servlet {
+
+    /**
+     * The jspInit() method is invoked when the JSP page is initialized. It
+     * is the responsibility of the JSP implementation (and of the class
+     * mentioned by the extends attribute, if present) that at this point
+     * invocations to the getServletConfig() method will return the desired
+     * value.
+     *
+     * A JSP page can override this method by including a definition for it
+     * in a declaration element.
+     *
+     * A JSP page should redefine the init() method from Servlet.
+     */
+    public void jspInit();
+
+    /**
+     * The jspDestroy() method is invoked when the JSP page is about to be
+     * destroyed.
+     * 
+     * A JSP page can override this method by including a definition for it
+     * in a declaration element.
+     *
+     * A JSP page should redefine the destroy() method from Servlet.
+     */
+    public void jspDestroy();
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/JspTagException.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/JspTagException.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/JspTagException.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,92 @@
+/*
+* Copyright 2004 The Apache Software Foundation
+*
+* Licensed 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.jsp;
+
+/**
+ * Exception to be used by a Tag Handler to indicate some unrecoverable
+ * error.
+ * This error is to be caught by the top level of the JSP page and will result
+ * in an error page.
+ */
+
+public class JspTagException extends JspException {
+    /**
+     * Constructs a new JspTagException with the specified message.
+     * The message can be written to the server log and/or displayed
+     * for the user.
+     * 
+     * @param msg a <code>String</code> specifying the text of 
+     *     the exception message
+     */
+    public JspTagException(String msg) {
+	super( msg );
+    }
+
+    /**
+     * Constructs a new JspTagException with no message.
+     */
+    public JspTagException() {
+	super();
+    }
+
+    /**
+     * Constructs a new JspTagException when the JSP Tag
+     * needs to throw an exception and include a message 
+     * about the "root cause" exception that interfered with its 
+     * normal operation, including a description message.
+     *
+     *
+     * @param message 		a <code>String</code> containing 
+     *				the text of the exception message
+     *
+     * @param rootCause		the <code>Throwable</code> exception 
+     *				that interfered with the JSP Tag's
+     *				normal operation, making this JSP Tag
+     *				exception necessary
+     *
+     * @since 2.0
+     */
+    public JspTagException(String message, Throwable rootCause) {
+	super( message, rootCause );
+    }
+
+
+    /**
+     * Constructs a new JSP Tag exception when the JSP Tag
+     * needs to throw an exception and include a message
+     * about the "root cause" exception that interfered with its
+     * normal operation.  The exception's message is based on the localized
+     * message of the underlying exception.
+     *
+     * <p>This method calls the <code>getLocalizedMessage</code> method
+     * on the <code>Throwable</code> exception to get a localized exception
+     * message. When subclassing <code>JspTagException</code>, 
+     * this method can be overridden to create an exception message 
+     * designed for a specific locale.
+     *
+     * @param rootCause 	the <code>Throwable</code> exception
+     * 				that interfered with the JSP Tag's
+     *				normal operation, making the JSP Tag 
+     *                          exception necessary
+     *
+     * @since 2.0
+     */
+
+    public JspTagException(Throwable rootCause) {
+	super( rootCause );
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/JspWriter.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/JspWriter.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/JspWriter.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,442 @@
+/*
+* Copyright 2004 The Apache Software Foundation
+*
+* Licensed 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.jsp;
+
+import java.io.IOException;
+
+/**
+ * <p>
+ * The actions and template data in a JSP page is written using the
+ * JspWriter object that is referenced by the implicit variable out which
+ * is initialized automatically using methods in the PageContext object.
+ *<p>
+ * This abstract class emulates some of the functionality found in the
+ * java.io.BufferedWriter and java.io.PrintWriter classes,
+ * however it differs in that it throws java.io.IOException from the print
+ * methods while PrintWriter does not.
+ * <p><B>Buffering</B>
+ * <p>
+ * The initial JspWriter object is associated with the PrintWriter object
+ * of the ServletResponse in a way that depends on whether the page is or
+ * is not buffered. If the page is not buffered, output written to this
+ * JspWriter object will be written through to the PrintWriter directly,
+ * which will be created if necessary by invoking the getWriter() method
+ * on the response object. But if the page is buffered, the PrintWriter
+ * object will not be created until the buffer is flushed and
+ * operations like setContentType() are legal. Since this flexibility
+ * simplifies programming substantially, buffering is the default for JSP
+ * pages.
+ * <p>
+ * Buffering raises the issue of what to do when the buffer is
+ * exceeded. Two approaches can be taken:
+ * <ul>
+ * <li>
+ * Exceeding the buffer is not a fatal error; when the buffer is
+ * exceeded, just flush the output.
+ * <li>
+ * Exceeding the buffer is a fatal error; when the buffer is exceeded,
+ * raise an exception.
+ * </ul>
+ * <p>
+ * Both approaches are valid, and thus both are supported in the JSP
+ * technology. The behavior of a page is controlled by the autoFlush
+ * attribute, which defaults to true. In general, JSP pages that need to
+ * be sure that correct and complete data has been sent to their client
+ * may want to set autoFlush to false, with a typical case being that
+ * where the client is an application itself. On the other hand, JSP
+ * pages that send data that is meaningful even when partially
+ * constructed may want to set autoFlush to true; such as when the
+ * data is sent for immediate display through a browser. Each application
+ * will need to consider their specific needs.
+ * <p>
+ * An alternative considered was to make the buffer size unbounded; but,
+ * this had the disadvantage that runaway computations would consume an
+ * unbounded amount of resources.
+ * <p>
+ * The "out" implicit variable of a JSP implementation class is of this type.
+ * If the page directive selects autoflush="true" then all the I/O operations
+ * on this class shall automatically flush the contents of the buffer if an
+ * overflow condition would result if the current operation were performed
+ * without a flush. If autoflush="false" then all the I/O operations on this
+ * class shall throw an IOException if performing the current operation would
+ * result in a buffer overflow condition.
+ *
+ * @see java.io.Writer
+ * @see java.io.BufferedWriter
+ * @see java.io.PrintWriter
+ */
+
+abstract public class JspWriter extends java.io.Writer {
+
+    /**
+     * Constant indicating that the Writer is not buffering output.
+     */
+
+    public static final int	NO_BUFFER = 0;
+
+    /**
+     * Constant indicating that the Writer is buffered and is using the
+     * implementation default buffer size.
+     */
+
+    public static final int	DEFAULT_BUFFER = -1;
+
+    /**
+     * Constant indicating that the Writer is buffered and is unbounded; this
+     * is used in BodyContent.
+     */
+
+    public static final int	UNBOUNDED_BUFFER = -2;
+
+    /**
+     * Protected constructor.
+     *
+     * @param bufferSize the size of the buffer to be used by the JspWriter
+     * @param autoFlush whether the JspWriter should be autoflushing
+     */
+
+    protected JspWriter(int bufferSize, boolean autoFlush) {
+	this.bufferSize = bufferSize;
+	this.autoFlush  = autoFlush;
+    }
+
+    /**
+     * Write a line separator.  The line separator string is defined by the
+     * system property <tt>line.separator</tt>, and is not necessarily a single
+     * newline ('\n') character.
+     *
+     * @exception  IOException  If an I/O error occurs
+     */
+
+    abstract public void newLine() throws IOException;
+
+    /**
+     * Print a boolean value.  The string produced by <code>{@link
+     * java.lang.String#valueOf(boolean)}</code> is written to the
+     * JspWriter's buffer or, if no buffer is used, directly to the 
+     * underlying writer.
+     *
+     * @param      b   The <code>boolean</code> to be printed
+     * @throws	   java.io.IOException If an error occured while writing
+     */
+
+    abstract public void print(boolean b) throws IOException;
+
+    /**
+     * Print a character.  The character is written to the
+     * JspWriter's buffer or, if no buffer is used, directly to the
+     * underlying writer.
+     *
+     * @param      c   The <code>char</code> to be printed
+     * @throws	   java.io.IOException If an error occured while writing
+     */
+
+    abstract public void print(char c) throws IOException;
+
+    /**
+     * Print an integer.  The string produced by <code>{@link
+     * java.lang.String#valueOf(int)}</code> is written to the
+     * JspWriter's buffer or, if no buffer is used, directly to the
+     * underlying writer.
+     *
+     * @param      i   The <code>int</code> to be printed
+     * @see        java.lang.Integer#toString(int)
+     * @throws	   java.io.IOException If an error occured while writing
+     */
+
+    abstract public void print(int i) throws IOException;
+
+    /**
+     * Print a long integer.  The string produced by <code>{@link
+     * java.lang.String#valueOf(long)}</code> is written to the
+     * JspWriter's buffer or, if no buffer is used, directly to the
+     * underlying writer.
+     *
+     * @param      l   The <code>long</code> to be printed
+     * @see        java.lang.Long#toString(long)
+     * @throws	   java.io.IOException If an error occured while writing
+     */
+
+    abstract public void print(long l) throws IOException;
+
+    /**
+     * Print a floating-point number.  The string produced by <code>{@link
+     * java.lang.String#valueOf(float)}</code> is written to the
+     * JspWriter's buffer or, if no buffer is used, directly to the
+     * underlying writer.
+     *
+     * @param      f   The <code>float</code> to be printed
+     * @see        java.lang.Float#toString(float)
+     * @throws	   java.io.IOException If an error occured while writing
+     */
+
+    abstract public void print(float f) throws IOException;
+
+    /**
+     * Print a double-precision floating-point number.  The string produced by
+     * <code>{@link java.lang.String#valueOf(double)}</code> is written to
+     * the JspWriter's buffer or, if no buffer is used, directly to the
+     * underlying writer.
+     *
+     * @param      d   The <code>double</code> to be printed
+     * @see        java.lang.Double#toString(double)
+     * @throws	   java.io.IOException If an error occured while writing
+     */
+
+    abstract public void print(double d) throws IOException;
+
+    /**
+     * Print an array of characters.  The characters are written to the
+     * JspWriter's buffer or, if no buffer is used, directly to the
+     * underlying writer.
+     *
+     * @param      s   The array of chars to be printed
+     *
+     * @throws  NullPointerException  If <code>s</code> is <code>null</code>
+     * @throws	   java.io.IOException If an error occured while writing
+     */
+
+    abstract public void print(char s[]) throws IOException;
+
+    /**
+     * Print a string.  If the argument is <code>null</code> then the string
+     * <code>"null"</code> is printed.  Otherwise, the string's characters are
+     * written to the JspWriter's buffer or, if no buffer is used, directly
+     * to the underlying writer.
+     *
+     * @param      s   The <code>String</code> to be printed
+     * @throws	   java.io.IOException If an error occured while writing
+     */
+
+    abstract public void print(String s) throws IOException;
+
+    /**
+     * Print an object.  The string produced by the <code>{@link
+     * java.lang.String#valueOf(Object)}</code> method is written to the
+     * JspWriter's buffer or, if no buffer is used, directly to the
+     * underlying writer.
+     *
+     * @param      obj   The <code>Object</code> to be printed
+     * @see        java.lang.Object#toString()
+     * @throws	   java.io.IOException If an error occured while writing
+     */
+
+    abstract public void print(Object obj) throws IOException;
+
+    /**
+     * Terminate the current line by writing the line separator string.  The
+     * line separator string is defined by the system property
+     * <code>line.separator</code>, and is not necessarily a single newline
+     * character (<code>'\n'</code>).
+     * @throws	   java.io.IOException If an error occured while writing
+     */
+
+    abstract public void println() throws IOException;
+
+    /**
+     * Print a boolean value and then terminate the line.  This method behaves
+     * as though it invokes <code>{@link #print(boolean)}</code> and then
+     * <code>{@link #println()}</code>.
+     *
+     * @param      x the boolean to write
+     * @throws	   java.io.IOException If an error occured while writing
+     */
+
+    abstract public void println(boolean x) throws IOException;
+
+    /**
+     * Print a character and then terminate the line.  This method behaves as
+     * though it invokes <code>{@link #print(char)}</code> and then <code>{@link
+     * #println()}</code>.
+     *
+     * @param      x the char to write
+     * @throws	   java.io.IOException If an error occured while writing
+     */
+
+    abstract public void println(char x) throws IOException;
+
+    /**
+     * Print an integer and then terminate the line.  This method behaves as
+     * though it invokes <code>{@link #print(int)}</code> and then <code>{@link
+     * #println()}</code>.
+     *
+     * @param      x the int to write
+     * @throws	   java.io.IOException If an error occured while writing
+     */
+
+    abstract public void println(int x) throws IOException;
+
+    /**
+     * Print a long integer and then terminate the line.  This method behaves
+     * as though it invokes <code>{@link #print(long)}</code> and then
+     * <code>{@link #println()}</code>.
+     *
+     * @param      x the long to write
+     * @throws	   java.io.IOException If an error occured while writing
+     */
+
+    abstract public void println(long x) throws IOException;
+
+    /**
+     * Print a floating-point number and then terminate the line.  This method
+     * behaves as though it invokes <code>{@link #print(float)}</code> and then
+     * <code>{@link #println()}</code>.
+     *
+     * @param      x the float to write
+     * @throws	   java.io.IOException If an error occured while writing
+     */
+
+    abstract public void println(float x) throws IOException;
+
+    /**
+     * Print a double-precision floating-point number and then terminate the
+     * line.  This method behaves as though it invokes <code>{@link
+     * #print(double)}</code> and then <code>{@link #println()}</code>.
+     *
+     * @param      x the double to write
+     * @throws	   java.io.IOException If an error occured while writing
+     */
+
+    abstract public void println(double x) throws IOException;
+
+    /**
+     * Print an array of characters and then terminate the line.  This method
+     * behaves as though it invokes <code>print(char[])</code> and then
+     * <code>println()</code>.
+     *
+     * @param      x the char[] to write
+     * @throws	   java.io.IOException If an error occured while writing
+     */
+
+    abstract public void println(char x[]) throws IOException;
+
+    /**
+     * Print a String and then terminate the line.  This method behaves as
+     * though it invokes <code>{@link #print(String)}</code> and then
+     * <code>{@link #println()}</code>.
+     *
+     * @param      x the String to write
+     * @throws	   java.io.IOException If an error occured while writing
+     */
+
+    abstract public void println(String x) throws IOException;
+
+    /**
+     * Print an Object and then terminate the line.  This method behaves as
+     * though it invokes <code>{@link #print(Object)}</code> and then
+     * <code>{@link #println()}</code>.
+     *
+     * @param      x the Object to write
+     * @throws	   java.io.IOException If an error occured while writing
+     */
+
+    abstract public void println(Object x) throws IOException;
+
+
+    /**
+     * Clear the contents of the buffer. If the buffer has been already
+     * been flushed then the clear operation shall throw an IOException
+     * to signal the fact that some data has already been irrevocably 
+     * written to the client response stream.
+     *
+     * @throws IOException		If an I/O error occurs
+     */
+
+    abstract public void clear() throws IOException;
+
+    /**
+     * Clears the current contents of the buffer. Unlike clear(), this
+     * method will not throw an IOException if the buffer has already been
+     * flushed. It merely clears the current content of the buffer and
+     * returns.
+     *
+     * @throws IOException		If an I/O error occurs
+     */
+
+    abstract public void clearBuffer() throws IOException;
+
+    /**
+     * Flush the stream.  If the stream has saved any characters from the
+     * various write() methods in a buffer, write them immediately to their
+     * intended destination.  Then, if that destination is another character or
+     * byte stream, flush it.  Thus one flush() invocation will flush all the
+     * buffers in a chain of Writers and OutputStreams.
+     * <p>
+     * The method may be invoked indirectly if the buffer size is exceeded.
+     * <p>
+     * Once a stream has been closed,
+     * further write() or flush() invocations will cause an IOException to be
+     * thrown.
+     *
+     * @exception  IOException  If an I/O error occurs
+     */
+
+    abstract public void flush() throws IOException;
+
+    /**
+     * Close the stream, flushing it first.
+     * <p>
+     * This method needs not be invoked explicitly for the initial JspWriter
+     * as the code generated by the JSP container will automatically
+     * include a call to close().
+     * <p>
+     * Closing a previously-closed stream, unlike flush(), has no effect.
+     *
+     * @exception  IOException  If an I/O error occurs
+     */
+
+    abstract public void close() throws IOException;
+
+    /**
+     * This method returns the size of the buffer used by the JspWriter.
+     *
+     * @return the size of the buffer in bytes, or 0 is unbuffered.
+     */
+
+    public int getBufferSize() { return bufferSize; }
+
+    /**
+     * This method returns the number of unused bytes in the buffer.
+     *
+     * @return the number of bytes unused in the buffer
+     */
+
+    abstract public int getRemaining();
+
+    /**
+     * This method indicates whether the JspWriter is autoFlushing.
+     *
+     * @return if this JspWriter is auto flushing or throwing IOExceptions 
+     *     on buffer overflow conditions
+     */
+
+    public boolean isAutoFlush() { return autoFlush; }
+
+    /*
+     * fields
+     */
+
+    /**
+     * The size of the buffer used by the JspWriter.
+     */
+    protected int     bufferSize;
+    
+    /**
+     * Whether the JspWriter is autoflushing.
+     */
+    protected boolean autoFlush;
+}

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/PageContext.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/PageContext.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/PageContext.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,522 @@
+/*
+* Copyright 2004 The Apache Software Foundation
+*
+* Licensed 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.jsp;
+
+import java.io.IOException;
+
+import javax.servlet.Servlet;
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+
+import javax.servlet.http.HttpSession;
+
+import javax.servlet.jsp.tagext.BodyContent;
+
+/**
+ * <p>
+ * PageContext extends JspContext to provide useful context information for
+ * when JSP technology is used in a Servlet environment.
+ * <p>
+ * A PageContext instance provides access to all the namespaces associated
+ * with a JSP page, provides access to several page attributes, as well as
+ * a layer above the implementation details.  Implicit objects are added
+ * to the pageContext automatically.
+ *
+ * <p> The <code> PageContext </code> class is an abstract class, designed to be
+ * extended to provide implementation dependent implementations thereof, by
+ * conformant JSP engine runtime environments. A PageContext instance is 
+ * obtained by a JSP implementation class by calling the
+ * JspFactory.getPageContext() method, and is released by calling
+ * JspFactory.releasePageContext().
+ *
+ * <p> An example of how PageContext, JspFactory, and other classes can be
+ * used  within a JSP Page Implementation object is given elsewhere.
+ *
+ * <p>
+ * The PageContext provides a number of facilities to the page/component 
+ * author and page implementor, including:
+ * <ul>
+ * <li>a single API to manage the various scoped namespaces
+ * <li>a number of convenience API's to access various public objects
+ * <li>a mechanism to obtain the JspWriter for output
+ * <li>a mechanism to manage session usage by the page
+ * <li>a mechanism to expose page directive attributes to the scripting 
+ *     environment
+ * <li>mechanisms to forward or include the current request to other active 
+ *     components in the application
+ * <li>a mechanism to handle errorpage exception processing
+ * </ul>
+ *
+ * <p><B>Methods Intended for Container Generated Code</B>
+ * <p>Some methods are intended to be used by the code generated by the
+ * container, not by code written by JSP page authors, or JSP tag library 
+ * authors.
+ * <p>The methods supporting <B>lifecycle</B> are <code>initialize()</code>
+ * and <code>release()</code>
+ *
+ * <p>
+ * The following methods enable the <B>management of nested</B> JspWriter 
+ * streams to implement Tag Extensions: <code>pushBody()</code>
+ *
+ * <p><B>Methods Intended for JSP authors</B>
+ * <p>
+ * The following methods provide <B>convenient access</B> to implicit objects:
+ * <code>getException()</code>,  <code>getPage()</code>
+ * <code>getRequest()</code>,  <code>getResponse()</code>,
+ * <code>getSession()</code>,  <code>getServletConfig()</code>
+ * and <code>getServletContext()</code>.
+ *
+ * <p>
+ * The following methods provide support for <B>forwarding, inclusion
+ * and error handling</B>:
+ * <code>forward()</code>,  <code>include()</code>,
+ * and  <code>handlePageException()</code>.
+ */
+
+abstract public class PageContext 
+    extends JspContext
+{
+    
+    /**
+     * Sole constructor. (For invocation by subclass constructors, 
+     * typically implicit.)
+     */
+    public PageContext() {
+    }
+    
+    /**
+     * Page scope: (this is the default) the named reference remains available
+     * in this PageContext until the return from the current Servlet.service()
+     * invocation.
+     */
+
+    public static final int PAGE_SCOPE		= 1;
+
+    /**
+     * Request scope: the named reference remains available from the 
+     * ServletRequest associated with the Servlet until the current request 
+     * is completed.
+     */
+
+    public static final int REQUEST_SCOPE	= 2;
+
+    /**
+     * Session scope (only valid if this page participates in a session):
+     * the named reference remains available from the HttpSession (if any)
+     * associated with the Servlet until the HttpSession is invalidated.
+     */
+
+    public static final int SESSION_SCOPE	= 3;
+
+    /**
+     * Application scope: named reference remains available in the 
+     * ServletContext until it is reclaimed.
+     */
+
+    public static final int APPLICATION_SCOPE	= 4;
+
+    /**
+     * Name used to store the Servlet in this PageContext's nametables.
+     */
+
+    public static final String PAGE = "javax.servlet.jsp.jspPage";
+
+    /**
+     * Name used to store this PageContext in it's own name table.
+     */
+
+    public static final String PAGECONTEXT = "javax.servlet.jsp.jspPageContext";
+
+    /**
+     * Name used to store ServletRequest in PageContext name table.
+     */
+
+    public static final String REQUEST = "javax.servlet.jsp.jspRequest";
+
+    /**
+     * Name used to store ServletResponse in PageContext name table.
+     */
+
+    public static final String RESPONSE = "javax.servlet.jsp.jspResponse";
+
+    /**
+     * Name used to store ServletConfig in PageContext name table.
+     */
+
+    public static final String CONFIG = "javax.servlet.jsp.jspConfig";
+
+    /**
+     * Name used to store HttpSession in PageContext name table.
+     */
+
+    public static final String SESSION = "javax.servlet.jsp.jspSession";
+    /**
+     * Name used to store current JspWriter in PageContext name table.
+     */
+
+    public static final String OUT = "javax.servlet.jsp.jspOut";
+
+    /**
+     * Name used to store ServletContext in PageContext name table.
+     */
+
+    public static final String APPLICATION = "javax.servlet.jsp.jspApplication";
+
+    /**
+     * Name used to store uncaught exception in ServletRequest attribute 
+     * list and PageContext name table.
+     */
+
+    public static final String EXCEPTION = "javax.servlet.jsp.jspException";
+
+    /**
+     * <p>
+     * The initialize method is called to initialize an uninitialized PageContext
+     * so that it may be used by a JSP Implementation class to service an
+     * incoming request and response within it's _jspService() method.
+     *
+     * <p>
+     * This method is typically called from JspFactory.getPageContext() in
+     * order to initialize state.
+     *
+     * <p>
+     * This method is required to create an initial JspWriter, and associate
+     * the "out" name in page scope with this newly created object.
+     *
+     * <p>
+     * This method should not be used by page  or tag library authors.
+     *
+     * @param servlet The Servlet that is associated with this PageContext
+     * @param request The currently pending request for this Servlet
+     * @param response The currently pending response for this Servlet
+     * @param errorPageURL The value of the errorpage attribute from the page 
+     *     directive or null
+     * @param needsSession The value of the session attribute from the 
+     *     page directive
+     * @param bufferSize The value of the buffer attribute from the page 
+     *     directive
+     * @param autoFlush The value of the autoflush attribute from the page 
+     *     directive
+     *
+     * @throws IOException during creation of JspWriter
+     * @throws IllegalStateException if out not correctly initialized
+     * @throws IllegalArgumentException If one of the given parameters
+     *     is invalid
+     */
+ 
+    abstract public void initialize(Servlet servlet, ServletRequest request, 
+        ServletResponse response, String errorPageURL, boolean needsSession, 
+        int bufferSize, boolean autoFlush)  
+        throws IOException, IllegalStateException, IllegalArgumentException;
+
+    /**
+     * <p>
+     * This method shall "reset" the internal state of a PageContext, releasing
+     * all internal references, and preparing the PageContext for potential
+     * reuse by a later invocation of initialize(). This method is typically
+     * called from JspFactory.releasePageContext().
+     *
+     * <p>
+     * Subclasses shall envelope this method.
+     *
+     * <p>
+     * This method should not be used by page  or tag library authors.
+     *
+     */
+
+    abstract public void release();
+
+    /**
+     * The current value of the session object (an HttpSession).
+     *
+     * @return the HttpSession for this PageContext or null
+     */
+
+    abstract public HttpSession getSession();
+
+    /**
+     * The current value of the page object (In a Servlet environment, 
+     * this is an instance of javax.servlet.Servlet).
+     *
+     * @return the Page implementation class instance associated 
+     *     with this PageContext
+     */
+
+    abstract public Object getPage();
+
+
+    /**
+     * The current value of the request object (a ServletRequest).
+     *
+     * @return The ServletRequest for this PageContext
+     */
+
+    abstract public ServletRequest getRequest();
+
+    /**
+     * The current value of the response object (a ServletResponse).
+     *
+     * @return the ServletResponse for this PageContext
+     */
+
+    abstract public ServletResponse getResponse();
+
+    /**
+     * The current value of the exception object (an Exception).
+     *
+     * @return any exception passed to this as an errorpage
+     */
+
+    abstract public Exception getException();
+
+    /**
+     * The ServletConfig instance.
+     *
+     * @return the ServletConfig for this PageContext
+     */
+
+    abstract public ServletConfig getServletConfig();
+
+    /**
+     * The ServletContext instance.
+     * 
+     * @return the ServletContext for this PageContext
+     */
+
+    abstract public ServletContext getServletContext();
+
+    /**
+     * <p>
+     * This method is used to re-direct, or "forward" the current 
+     * ServletRequest and ServletResponse to another active component in 
+     * the application.
+     * </p>
+     * <p>
+     * If the <I> relativeUrlPath </I> begins with a "/" then the URL specified
+     * is calculated relative to the DOCROOT of the <code> ServletContext </code>
+     * for this JSP. If the path does not begin with a "/" then the URL 
+     * specified is calculated relative to the URL of the request that was
+     * mapped to the calling JSP.
+     * </p>
+     * <p>
+     * It is only valid to call this method from a <code> Thread </code>
+     * executing within a <code> _jspService(...) </code> method of a JSP.
+     * </p>
+     * <p>
+     * Once this method has been called successfully, it is illegal for the
+     * calling <code> Thread </code> to attempt to modify the <code>
+     * ServletResponse </code> object.  Any such attempt to do so, shall result
+     * in undefined behavior. Typically, callers immediately return from 
+     * <code> _jspService(...) </code> after calling this method.
+     * </p>
+     *
+     * @param relativeUrlPath specifies the relative URL path to the target 
+     *     resource as described above
+     *
+     * @throws IllegalStateException if <code> ServletResponse </code> is not 
+     *     in a state where a forward can be performed
+     * @throws ServletException if the page that was forwarded to throws
+     *     a ServletException
+     * @throws IOException if an I/O error occurred while forwarding
+     */
+
+    abstract public void forward(String relativeUrlPath) 
+        throws ServletException, IOException;
+
+    /**
+     * <p>
+     * Causes the resource specified to be processed as part of the current
+     * ServletRequest and ServletResponse being processed by the calling Thread.
+     * The output of the target resources processing of the request is written
+     * directly to the ServletResponse output stream.
+     * </p>
+     * <p>
+     * The current JspWriter "out" for this JSP is flushed as a side-effect
+     * of this call, prior to processing the include.
+     * </p>
+     * <p>
+     * If the <I> relativeUrlPath </I> begins with a "/" then the URL specified
+     * is calculated relative to the DOCROOT of the <code>ServletContext</code>
+     * for this JSP. If the path does not begin with a "/" then the URL 
+     * specified is calculated relative to the URL of the request that was
+     * mapped to the calling JSP.
+     * </p>
+     * <p>
+     * It is only valid to call this method from a <code> Thread </code>
+     * executing within a <code> _jspService(...) </code> method of a JSP.
+     * </p>
+     *
+     * @param relativeUrlPath specifies the relative URL path to the target 
+     *     resource to be included
+     *
+     * @throws ServletException if the page that was forwarded to throws
+     *     a ServletException
+     * @throws IOException if an I/O error occurred while forwarding
+     */
+    abstract public void include(String relativeUrlPath) 
+        throws ServletException, IOException;
+
+    /**
+     * <p>
+     * Causes the resource specified to be processed as part of the current
+     * ServletRequest and ServletResponse being processed by the calling Thread.
+     * The output of the target resources processing of the request is written
+     * directly to the current JspWriter returned by a call to getOut().
+     * </p>
+     * <p>
+     * If flush is true, The current JspWriter "out" for this JSP 
+     * is flushed as a side-effect of this call, prior to processing 
+     * the include.  Otherwise, the JspWriter "out" is not flushed.
+     * </p>
+     * <p>
+     * If the <i>relativeUrlPath</i> begins with a "/" then the URL specified
+     * is calculated relative to the DOCROOT of the <code>ServletContext</code>
+     * for this JSP. If the path does not begin with a "/" then the URL 
+     * specified is calculated relative to the URL of the request that was
+     * mapped to the calling JSP.
+     * </p>
+     * <p>
+     * It is only valid to call this method from a <code> Thread </code>
+     * executing within a <code> _jspService(...) </code> method of a JSP.
+     * </p>
+     *
+     * @param relativeUrlPath specifies the relative URL path to the 
+     *     target resource to be included
+     * @param flush True if the JspWriter is to be flushed before the include,
+     *     or false if not.
+     *
+     * @throws ServletException if the page that was forwarded to throws
+     *     a ServletException
+     * @throws IOException if an I/O error occurred while forwarding
+     * @since 2.0
+     */
+    abstract public void include(String relativeUrlPath, boolean flush) 
+	throws ServletException, IOException;
+
+    /**
+     * <p>
+     * This method is intended to process an unhandled 'page' level
+     * exception by forwarding the exception to the specified
+     * error page for this JSP.  If forwarding is not possible (for
+     * example because the response has already been committed), an
+     * implementation dependent mechanism should be used to invoke
+     * the error page (e.g. "including" the error page instead).
+     *
+     * <p>
+     * If no error page is defined in the page, the exception should
+     * be rethrown so that the standard servlet error handling
+     * takes over.
+     *
+     * <p>
+     * A JSP implementation class shall typically clean up any local state
+     * prior to invoking this and will return immediately thereafter. It is
+     * illegal to generate any output to the client, or to modify any 
+     * ServletResponse state after invoking this call.
+     *
+     * <p>
+     * This method is kept for backwards compatiblity reasons.  Newly
+     * generated code should use PageContext.handlePageException(Throwable).
+     *
+     * @param e the exception to be handled
+     *
+     * @throws ServletException if an error occurs while invoking the error page
+     * @throws IOException if an I/O error occurred while invoking the error
+     *     page
+     * @throws NullPointerException if the exception is null
+     *
+     * @see #handlePageException(Throwable)
+     */
+
+    abstract public void handlePageException(Exception e) 
+        throws ServletException, IOException;
+
+    /**
+     * <p>
+     * This method is intended to process an unhandled 'page' level
+     * exception by forwarding the exception to the specified
+     * error page for this JSP.  If forwarding is not possible (for
+     * example because the response has already been committed), an
+     * implementation dependent mechanism should be used to invoke
+     * the error page (e.g. "including" the error page instead).
+     *
+     * <p>
+     * If no error page is defined in the page, the exception should
+     * be rethrown so that the standard servlet error handling
+     * takes over.
+     *
+     * <p>
+     * This method is intended to process an unhandled "page" level exception
+     * by redirecting the exception to either the specified error page for this
+     * JSP, or if none was specified, to perform some implementation dependent
+     * action.
+     *
+     * <p>
+     * A JSP implementation class shall typically clean up any local state
+     * prior to invoking this and will return immediately thereafter. It is
+     * illegal to generate any output to the client, or to modify any 
+     * ServletResponse state after invoking this call.
+     *
+     * @param t the throwable to be handled
+     *
+     * @throws ServletException if an error occurs while invoking the error page
+     * @throws IOException if an I/O error occurred while invoking the error
+     *     page
+     * @throws NullPointerException if the exception is null
+     *
+     * @see #handlePageException(Exception)
+     */
+
+    abstract public void handlePageException(Throwable t) 
+        throws ServletException, IOException;
+
+    /**
+     * Return a new BodyContent object, save the current "out" JspWriter,
+     * and update the value of the "out" attribute in the page scope
+     * attribute namespace of the PageContext.
+     *
+     * @return the new BodyContent
+     */
+
+    public BodyContent pushBody() {
+        return null; // XXX to implement
+    }
+         
+
+    /**
+     * Provides convenient access to error information.
+     *
+     * @return an ErrorData instance containing information about the 
+     * error, as obtained from the request attributes, as per the 
+     * Servlet specification.  If this is not an error page (that is,
+     * if the isErrorPage attribute of the page directive is not set
+     * to "true"), the information is meaningless.
+     *
+     * @since 2.0
+     */
+    public ErrorData getErrorData() {
+	return new ErrorData( 
+	    (Throwable)getRequest().getAttribute( "javax.servlet.error.exception" ),
+	    ((Integer)getRequest().getAttribute( 
+		"javax.servlet.error.status_code" )).intValue(),
+	    (String)getRequest().getAttribute( "javax.servlet.error.request_uri" ),
+	    (String)getRequest().getAttribute( "javax.servlet.error.servlet_name" ) );
+    }
+    
+}

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/SkipPageException.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/SkipPageException.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/SkipPageException.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,75 @@
+/*
+* Copyright 2004 The Apache Software Foundation
+*
+* Licensed 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.jsp;
+
+/**
+ * Exception to indicate the calling page must cease evaluation.
+ * Thrown by a simple tag handler to indicate that the remainder of 
+ * the page must not be evaluated.  The result is propagated back to
+ * the pagein the case where one tag invokes another (as can be
+ * the case with tag files).  The effect is similar to that of a 
+ * Classic Tag Handler returning Tag.SKIP_PAGE from doEndTag().
+ * Jsp Fragments may also throw this exception.  This exception
+ * should not be thrown manually in a JSP page or tag file - the behavior is
+ * undefined.  The exception is intended to be thrown inside 
+ * SimpleTag handlers and in JSP fragments.
+ * 
+ * @see javax.servlet.jsp.tagext.SimpleTag#doTag
+ * @see javax.servlet.jsp.tagext.JspFragment#invoke
+ * @see javax.servlet.jsp.tagext.Tag#doEndTag
+ * @since 2.0
+ */
+public class SkipPageException
+    extends JspException
+{
+    /**
+     * Creates a SkipPageException with no message.
+     */
+    public SkipPageException() {
+        super();
+    }
+    
+    /**
+     * Creates a SkipPageException with the provided message.
+     *
+     * @param message the detail message
+     */
+    public SkipPageException( String message ) {
+        super( message );
+    }
+
+    /**
+     * Creates a SkipPageException with the provided message and root cause.
+     *
+     * @param message the detail message
+     * @param rootCause the originating cause of this exception
+     */
+    public SkipPageException( String message, Throwable rootCause ) {
+	super( message, rootCause );
+    }
+
+    /**
+     * Creates a SkipPageException with the provided root cause.
+     *
+     * @param rootCause the originating cause of this exception
+     */
+    public SkipPageException( Throwable rootCause ) {
+	super( rootCause );
+    }
+    
+}
+
+

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/el/ELException.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/el/ELException.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/el/ELException.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,91 @@
+/*
+* Copyright 2004 The Apache Software Foundation
+*
+* Licensed 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.jsp.el;
+
+
+/**
+ * Represents any of the exception conditions that arise during the
+ * operation evaluation of the evaluator.
+ *
+ * @since 2.0
+ */
+public class ELException
+  extends Exception
+{
+  //-------------------------------------
+  // Member variables
+  //-------------------------------------
+
+  private Throwable mRootCause;
+
+  //-------------------------------------
+  /**
+   * Creates an ELException with no detail message.
+   **/
+  public ELException ()
+  {
+    super ();
+  }
+
+  //-------------------------------------
+  /**
+   * Creates an ELException with the provided detail message.
+   *
+   * @param pMessage the detail message
+   **/
+  public ELException (String pMessage)
+  {
+    super (pMessage);
+  }
+
+  //-------------------------------------
+  /**
+   * Creates an ELException with the given root cause.
+   *
+   * @param pRootCause the originating cause of this exception
+   **/
+  public ELException (Throwable pRootCause)
+  {
+    super( pRootCause.getLocalizedMessage() );
+    mRootCause = pRootCause;
+  }
+
+  //-------------------------------------
+  /**
+   * Creates an ELException with the given detail message and root cause.
+   *
+   * @param pMessage the detail message
+   * @param pRootCause the originating cause of this exception
+   **/
+  public ELException (String pMessage,
+		      Throwable pRootCause)
+  {
+    super (pMessage);
+    mRootCause = pRootCause;
+  }
+
+  //-------------------------------------
+  /**
+   * Returns the root cause.
+   *
+   * @return the root cause of this exception
+   */
+  public Throwable getRootCause ()
+  {
+    return mRootCause;
+  }
+}

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/el/ELParseException.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/el/ELParseException.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/el/ELParseException.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,49 @@
+/*
+* Copyright 2004 The Apache Software Foundation
+*
+* Licensed 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.jsp.el;
+
+
+/**
+ * Represents a parsing error encountered while parsing an EL expression.
+ *
+ * @since 2.0
+ */
+
+public class ELParseException extends ELException {
+
+ //-------------------------------------
+  /**
+   * Creates an ELParseException with no detail message.
+   */
+  public ELParseException ()
+  {
+    super ();
+  }
+
+  //-------------------------------------
+  /**
+   * Creates an ELParseException with the provided detail message.
+   *
+   * @param pMessage the detail message
+   **/
+  public ELParseException (String pMessage)
+  {
+    super (pMessage);
+  }
+
+  //-------------------------------------
+}

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/el/Expression.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/el/Expression.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/el/Expression.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,51 @@
+/*
+* Copyright 2004 The Apache Software Foundation
+*
+* Licensed 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.jsp.el;
+
+
+/**
+ * <p>The abstract class for a prepared expression.</p>
+ *
+ * <p>An instance of an Expression can be obtained via from an 
+ * ExpressionEvaluator instance.</p>
+ *
+ * <p>An Expression may or not have done a syntactic parse of the expression.
+ * A client invoking the evaluate() method should be ready for the case 
+ * where ELParseException exceptions are raised. </p>
+ *
+ * @since 2.0
+ */
+public abstract class Expression {
+
+    /** 
+     * Evaluates an expression that was previously prepared.  In some 
+     * implementations preparing an expression involves full syntactic 
+     * validation, but others may not do so.  Evaluating the expression may 
+     * raise an ELParseException as well as other ELExceptions due to 
+     * run-time evaluation.
+     *
+     * @param vResolver A VariableResolver instance that can be used at 
+     *   runtime to resolve the name of implicit objects into Objects.
+     * @return The result of the expression evaluation.
+     *
+     * @exception ELException Thrown if the expression evaluation failed.
+     */ 
+    public abstract Object evaluate( VariableResolver vResolver )
+        throws ELException;
+}
+

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/el/ExpressionEvaluator.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/el/ExpressionEvaluator.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/el/ExpressionEvaluator.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,106 @@
+/*
+* Copyright 2004 The Apache Software Foundation
+*
+* Licensed 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.jsp.el;
+
+
+/**
+ * <p>The abstract base class for an expression-language evaluator.
+ * Classes that implement an expression language expose their functionality
+ * via this abstract class.</p>
+ *
+ * <p>An instance of the ExpressionEvaluator can be obtained via the 
+ * JspContext / PageContext</p>
+ *
+ * <p>The parseExpression() and evaluate() methods must be thread-safe.  
+ * That is, multiple threads may call these methods on the same 
+ * ExpressionEvaluator object simultaneously.  Implementations should 
+ * synchronize access if they depend on transient state.  Implementations 
+ * should not, however, assume that only one object of each 
+ * ExpressionEvaluator type will be instantiated; global caching should 
+ * therefore be static.</p>
+ *
+ * <p>Only a single EL expression, starting with '${' and ending with
+ * '}', can be parsed or evaluated at a time.  EL expressions 
+ * cannot be mixed with static text.  For example, attempting to 
+ * parse or evaluate "<code>abc${1+1}def${1+1}ghi</code>" or even
+ * "<code>${1+1}${1+1}</code>" will cause an <code>ELException</code> to
+ * be thrown.</p>
+ *
+ * <p>The following are examples of syntactically legal EL expressions:
+ *
+ * <ul>
+ *   <li><code>${person.lastName}</code></li>
+ *   <li><code>${8 * 8}</code></li>
+ *   <li><code>${my:reverse('hello')}</code></li>
+ * </ul>
+ * </p>
+ *
+ * @since 2.0
+ */
+public abstract class ExpressionEvaluator {
+
+    /**
+     * Prepare an expression for later evaluation.  This method should perform
+     * syntactic validation of the expression; if in doing so it detects 
+     * errors, it should raise an ELParseException.
+     *
+     * @param expression The expression to be evaluated.
+     * @param expectedType The expected type of the result of the evaluation
+     * @param fMapper A FunctionMapper to resolve functions found in 
+     *     the expression.  It can be null, in which case no functions 
+     *     are supported for this invocation.  The ExpressionEvaluator 
+     *     must not hold on to the FunctionMapper reference after 
+     *     returning from <code>parseExpression()</code>.  The 
+     *     <code>Expression</code> object returned must invoke the same 
+     *     functions regardless of whether the mappings in the 
+     *     provided <code>FunctionMapper</code> instance change between 
+     *     calling <code>ExpressionEvaluator.parseExpression()</code>
+     *     and <code>Expression.evaluate()</code>.
+     * @return The Expression object encapsulating the arguments.
+     *
+     * @exception ELException Thrown if parsing errors were found.
+     */ 
+    public abstract Expression parseExpression( String expression, 
+				       Class expectedType, 
+				       FunctionMapper fMapper ) 
+      throws ELException; 
+
+
+    /** 
+     * Evaluates an expression.  This method may perform some syntactic 
+     * validation and, if so, it should raise an ELParseException error if 
+     * it encounters syntactic errors.  EL evaluation errors should cause 
+     * an ELException to be raised.
+     *
+     * @param expression The expression to be evaluated.
+     * @param expectedType The expected type of the result of the evaluation
+     * @param vResolver A VariableResolver instance that can be used at 
+     *     runtime to resolve the name of implicit objects into Objects.
+     * @param fMapper A FunctionMapper to resolve functions found in 
+     *     the expression.  It can be null, in which case no functions 
+     *     are supported for this invocation.  
+     * @return The result of the expression evaluation.
+     *
+     * @exception ELException Thrown if the expression evaluation failed.
+     */ 
+    public abstract Object evaluate( String expression, 
+			    Class expectedType, 
+			    VariableResolver vResolver,
+			    FunctionMapper fMapper ) 
+      throws ELException; 
+}
+

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/el/FunctionMapper.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/el/FunctionMapper.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/el/FunctionMapper.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,38 @@
+/*
+* Copyright 2004 The Apache Software Foundation
+*
+* Licensed 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.jsp.el;
+
+/**
+ * <p>The interface to a map between EL function names and methods.</p>
+ *
+ * <p>Classes implementing this interface may, for instance, consult tag library
+ * information to resolve the map. </p>
+ *
+ * @since 2.0
+ */
+public interface FunctionMapper {
+  /**
+   * Resolves the specified local name and prefix into a Java.lang.Method.
+   * Returns null if the prefix and local name are not found.
+   * 
+   * @param prefix the prefix of the function, or "" if no prefix.
+   * @param localName the short name of the function
+   * @return the result of the method mapping.  Null means no entry found.
+   **/
+  public java.lang.reflect.Method resolveFunction(String prefix, 
+      String localName);
+}

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/el/VariableResolver.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/el/VariableResolver.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/el/VariableResolver.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,49 @@
+/*
+* Copyright 2004 The Apache Software Foundation
+*
+* Licensed 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.jsp.el;
+
+/**
+ * <p>This class is used to customize the way an ExpressionEvaluator resolves
+ * variable references at evaluation time.  For example, instances of this class can
+ * implement their own variable lookup mechanisms, or introduce the
+ * notion of "implicit variables" which override any other variables.
+ * An instance of this class should be passed when evaluating
+ * an expression.</p>
+ *
+ * <p>An instance of this class includes the context against which resolution
+ * will happen</p>
+ *
+ * @since 2.0
+ */
+public interface VariableResolver
+{
+  //-------------------------------------
+  /**
+   * Resolves the specified variable.
+   * Returns null if the variable is not found.
+   * 
+   * @param pName the name of the variable to resolve
+   * @return the result of the variable resolution
+   *
+   * @throws ELException if a failure occurred while trying to resolve
+   *     the given variable
+   **/
+  public Object resolveVariable (String pName)
+    throws ELException;
+					
+  //-------------------------------------
+}

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/el/package.html
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/el/package.html	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/el/package.html	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,75 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<!--
+  - The Apache Software License, Version 1.1
+  -
+  - Copyright (c) 1999 The Apache Software Foundation.  All rights 
+  - reserved.
+  -
+  - Redistribution and use in source and binary forms, with or without
+  - modification, are permitted provided that the following conditions
+  - are met:
+  -
+  - 1. Redistributions of source code must retain the above copyright
+  -    notice, this list of conditions and the following disclaimer. 
+  -
+  - 2. Redistributions in binary form must reproduce the above copyright
+  -    notice, this list of conditions and the following disclaimer in
+  -    the documentation and/or other materials provided with the
+  -    distribution.
+  -
+  - 3. The end-user documentation included with the redistribution, if
+  -    any, must include the following acknowlegement:  
+  -       "This product includes software developed by the 
+  -        Apache Software Foundation (http://www.apache.org/)."
+  -    Alternately, this acknowlegement may appear in the software itself,
+  -    if and wherever such third-party acknowlegements normally appear.
+  -
+  - 4. The names "The Jakarta Project", "Tomcat", and "Apache Software
+  -    Foundation" must not be used to endorse or promote products derived
+  -    from this software without prior written permission. For written 
+  -    permission, please contact apache at apache.org.
+  -
+  - 5. Products derived from this software may not be called "Apache"
+  -    nor may "Apache" appear in their names without prior written
+  -    permission of the Apache Group.
+  -
+  - THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+  - WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+  - OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+  - DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+  - ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+  - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+  - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+  - USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+  - ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+  - OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+  - OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+  - SUCH DAMAGE.
+  - ====================================================================
+  -
+  - This software consists of voluntary contributions made by many
+  - individuals on behalf of the Apache Software Foundation.  For more
+  - information on the Apache Software Foundation, please see
+  - <http://www.apache.org/>.
+  -
+  -->
+</head>
+<body bgcolor="white">
+
+Classes and interfaces for the JSP 2.0 Expression Language API.
+
+<p>
+The JavaServer Pages(tm) (JSP) 2.0 specification provides a portable
+API for evaluating "EL Expressions".  As of JSP 2.0, EL expressions can
+be placed directly in the template text of JSP pages and tag files.
+<p>
+This package contains a number of classes and interfaces that describe 
+and define programmatic access to the Expression Language evaluator. 
+This API can also be used by an implementation of JSP to evaluate the 
+expressions, but other implementations, like open-coding into Java 
+bytecodes, are allowed.  This package is intended to have no dependencies 
+on other portions of the JSP 2.0 specification. 
+</body>
+</html>

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/package.html
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/package.html	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/package.html	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,67 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<!--
+  - The Apache Software License, Version 1.1
+  -
+  - Copyright (c) 1999 The Apache Software Foundation.  All rights 
+  - reserved.
+  -
+  - Redistribution and use in source and binary forms, with or without
+  - modification, are permitted provided that the following conditions
+  - are met:
+  -
+  - 1. Redistributions of source code must retain the above copyright
+  -    notice, this list of conditions and the following disclaimer. 
+  -
+  - 2. Redistributions in binary form must reproduce the above copyright
+  -    notice, this list of conditions and the following disclaimer in
+  -    the documentation and/or other materials provided with the
+  -    distribution.
+  -
+  - 3. The end-user documentation included with the redistribution, if
+  -    any, must include the following acknowlegement:  
+  -       "This product includes software developed by the 
+  -        Apache Software Foundation (http://www.apache.org/)."
+  -    Alternately, this acknowlegement may appear in the software itself,
+  -    if and wherever such third-party acknowlegements normally appear.
+  -
+  - 4. The names "The Jakarta Project", "Tomcat", and "Apache Software
+  -    Foundation" must not be used to endorse or promote products derived
+  -    from this software without prior written permission. For written 
+  -    permission, please contact apache at apache.org.
+  -
+  - 5. Products derived from this software may not be called "Apache"
+  -    nor may "Apache" appear in their names without prior written
+  -    permission of the Apache Group.
+  -
+  - THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+  - WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+  - OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+  - DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+  - ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+  - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+  - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+  - USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+  - ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+  - OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+  - OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+  - SUCH DAMAGE.
+  - ====================================================================
+  -
+  - This software consists of voluntary contributions made by many
+  - individuals on behalf of the Apache Software Foundation.  For more
+  - information on the Apache Software Foundation, please see
+  - <http://www.apache.org/>.
+  -
+  -->
+</head>
+<body bgcolor="white">
+Classes and interfaces for the Core JSP 2.0 API.
+<p>
+The javax.servlet.jsp package contains a number of classes and
+interfaces that describe and define the contracts between a JSP page
+implementation class and the runtime environment provided for an
+instance of such a class by a conforming JSP container.
+</body>
+</html>

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/tagext/BodyContent.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/tagext/BodyContent.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/tagext/BodyContent.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,138 @@
+/*
+* Copyright 2004 The Apache Software Foundation
+*
+* Licensed 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.jsp.tagext;
+
+import java.io.Reader;
+import java.io.Writer;
+import java.io.IOException;
+import javax.servlet.jsp.*;
+
+/**
+ * An encapsulation of the evaluation of the body of an action so it is
+ * available to a tag handler.  BodyContent is a subclass of JspWriter.
+ *
+ * <p>
+ * Note that the content of BodyContent is the result of evaluation, so
+ * it will not contain actions and the like, but the result of their
+ * invocation.
+ * 
+ * <p>
+ * BodyContent has methods to convert its contents into
+ * a String, to read its contents, and to clear the contents.
+ *
+ * <p>
+ * The buffer size of a BodyContent object is unbounded.  A
+ * BodyContent object cannot be in autoFlush mode.  It is not possible to
+ * invoke flush on a BodyContent object, as there is no backing stream.
+ *
+ * <p>
+ * Instances of BodyContent are created by invoking the pushBody and
+ * popBody methods of the PageContext class.  A BodyContent is enclosed
+ * within another JspWriter (maybe another BodyContent object) following
+ * the structure of their associated actions.
+ *
+ * <p>
+ * A BodyContent is made available to a BodyTag through a setBodyContent()
+ * call.  The tag handler can use the object until after the call to
+ * doEndTag().
+ */
+
+public abstract class BodyContent extends JspWriter {
+    
+    /**
+     * Protected constructor.
+     *
+     * Unbounded buffer, no autoflushing.
+     *
+     * @param e the enclosing JspWriter
+     */
+
+    protected BodyContent(JspWriter e) {
+	super(UNBOUNDED_BUFFER , false);
+	this.enclosingWriter = e;
+    }
+
+    /**
+     * Redefined flush() so it is not legal.
+     *
+     * <p>
+     * It is not valid to flush a BodyContent because there is no backing
+     * stream behind it.
+     *
+     * @throws IOException always thrown
+     */
+
+    public void flush() throws IOException {
+	throw new IOException("Illegal to flush within a custom tag");
+    }
+
+    /**
+     * Clear the body without throwing any exceptions.
+     */
+    
+    public void clearBody() {
+	try {
+	    this.clear();
+	} catch (IOException ex) {
+	    // TODO -- clean this one up.
+	    throw new Error("internal error!;");
+	}
+    }
+
+    /**
+     * Return the value of this BodyContent as a Reader.
+     *
+     * @return the value of this BodyContent as a Reader
+     */
+    public abstract Reader getReader();
+
+
+    /**
+     * Return the value of the BodyContent as a String.
+     *
+     * @return the value of the BodyContent as a String
+     */
+    public abstract String getString();
+	
+
+    /**
+     * Write the contents of this BodyContent into a Writer.
+     * Subclasses may optimize common invocation patterns.
+     *
+     * @param out The writer into which to place the contents of
+     *     this body evaluation
+     * @throws IOException if an I/O error occurred while writing the
+     *     contents of this BodyContent to the given Writer
+     */
+
+    public abstract void writeOut(Writer out) throws IOException;
+
+
+    /**
+     * Get the enclosing JspWriter.
+     *
+     * @return the enclosing JspWriter passed at construction time
+     */
+
+    public JspWriter getEnclosingWriter() {
+	return enclosingWriter;
+    }
+
+
+    // private fields
+
+    private JspWriter enclosingWriter;
+ }

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/tagext/BodyTag.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/tagext/BodyTag.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/tagext/BodyTag.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,185 @@
+/*
+* Copyright 2004 The Apache Software Foundation
+*
+* Licensed 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.jsp.tagext;
+
+import javax.servlet.jsp.*;
+
+/**
+ * The BodyTag interface extends IterationTag by defining additional
+ * methods that let a tag handler manipulate the content of evaluating its body.
+ *
+ * <p>
+ * It is the responsibility of the tag handler to manipulate the body
+ * content.  For example the tag handler may take the body content,
+ * convert it into a String using the bodyContent.getString
+ * method and then use it.  Or the tag handler may take the body
+ * content and write it out into its enclosing JspWriter using
+ * the bodyContent.writeOut method.
+ *
+ * <p> A tag handler that implements BodyTag is treated as one that
+ * implements IterationTag, except that the doStartTag method can
+ * return SKIP_BODY, EVAL_BODY_INCLUDE or EVAL_BODY_BUFFERED.
+ *
+ * <p>
+ * If EVAL_BODY_INCLUDE is returned, then evaluation happens
+ * as in IterationTag.
+ *
+ * <p>
+ * If EVAL_BODY_BUFFERED is returned, then a BodyContent object will be
+ * created (by code generated by the JSP compiler) to capture the body
+ * evaluation.
+ * The code generated by the JSP compiler obtains the BodyContent object by
+ * calling the pushBody method of the current pageContext, which
+ * additionally has the effect of saving the previous out value.
+ * The page compiler returns this object by calling the popBody
+ * method of the PageContext class;
+ * the call also restores the value of out.
+ *
+ * <p>
+ * The interface provides one new property with a setter method and one
+ * new action method.
+ *
+ * <p><B>Properties</B>
+ * <p> There is a new property: bodyContent, to contain the BodyContent
+ * object, where the JSP Page implementation object will place the
+ * evaluation (and reevaluation, if appropriate) of the body.  The setter
+ * method (setBodyContent) will only be invoked if doStartTag() returns
+ * EVAL_BODY_BUFFERED and the corresponding action element does not have
+ * an empty body.
+ *
+ * <p><B>Methods</B>
+ * <p> In addition to the setter method for the bodyContent property, there
+ * is a new action method: doInitBody(), which is invoked right after
+ * setBodyContent() and before the body evaluation.  This method is only
+ * invoked if doStartTag() returns EVAL_BODY_BUFFERED.
+ *
+ * <p><B>Lifecycle</B>
+ * <p> Lifecycle details are described by the transition diagram below.
+ * Exceptions that are thrown during the computation of doStartTag(),
+ * setBodyContent(), doInitBody(), BODY, doAfterBody() interrupt the
+ * execution sequence and are propagated up the stack, unless the
+ * tag handler implements the TryCatchFinally interface; see that
+ * interface for details.
+ * <p>
+ * <IMG src="doc-files/BodyTagProtocol.gif"
+ *      alt="Lifecycle Details Transition Diagram for BodyTag"/>
+ *
+ * <p><B>Empty and Non-Empty Action</B>
+ * <p> If the TagLibraryDescriptor file indicates that the action must
+ * always have an empty element body, by an &lt;body-content&gt; entry 
+ * of "empty", then the doStartTag() method must return SKIP_BODY.
+ * Otherwise, the doStartTag() method may return SKIP_BODY,
+ * EVAL_BODY_INCLUDE, or EVAL_BODY_BUFFERED.
+ *
+ * <p>Note that which methods are invoked after the doStartTag() depends on 
+ * both the return value and on if the custom action element is empty
+ * or not in the JSP page, not how it's declared in the TLD.
+ *
+ * <p>
+ * If SKIP_BODY is returned the body is not evaluated, and doEndTag() is
+ * invoked.
+ *
+ * <p>
+ * If EVAL_BODY_INCLUDE is returned, and the custom action element is not
+ * empty, setBodyContent() is not invoked,
+ * doInitBody() is not invoked, the body is evaluated and
+ * "passed through" to the current out, doAfterBody() is invoked
+ * and then, after zero or more iterations, doEndTag() is invoked.
+ * If the custom action element is empty, only doStart() and 
+ * doEndTag() are invoked.
+ *
+ * <p>
+ * If EVAL_BODY_BUFFERED is returned, and the custom action element is not
+ * empty, setBodyContent() is invoked,
+ * doInitBody() is invoked, the body is evaluated, doAfterBody() is
+ * invoked, and then, after zero or more iterations, doEndTag() is invoked.
+ * If the custom action element is empty, only doStart() and doEndTag() 
+ * are invoked.
+ */
+
+public interface BodyTag extends IterationTag {
+
+    /**
+     * Deprecated constant that has the same value as EVAL_BODY_BUFFERED
+     * and EVAL_BODY_AGAIN.  This name has been marked as deprecated
+     * to encourage the use of the two different terms, which are much
+     * more descriptive.
+     *
+     * @deprecated	As of Java JSP API 1.2, use BodyTag.EVAL_BODY_BUFFERED
+     * or IterationTag.EVAL_BODY_AGAIN.
+     */
+ 
+    public final static int EVAL_BODY_TAG = 2;
+
+    /**
+     * Request the creation of new buffer, a BodyContent on which to
+     * evaluate the body of this tag.
+     *
+     * Returned from doStartTag when it implements BodyTag.
+     * This is an illegal return value for doStartTag when the class
+     * does not implement BodyTag.
+     */
+
+    public final static int EVAL_BODY_BUFFERED = 2;
+
+
+    /**
+     * Set the bodyContent property.
+     * This method is invoked by the JSP page implementation object at
+     * most once per action invocation.
+     * This method will be invoked before doInitBody.
+     * This method will not be invoked for empty tags or for non-empty
+     * tags whose doStartTag() method returns SKIP_BODY or EVAL_BODY_INCLUDE.
+     *
+     * <p>
+     * When setBodyContent is invoked, the value of the implicit object out
+     * has already been changed in the pageContext object.  The BodyContent
+     * object passed will have not data on it but may have been reused
+     * (and cleared) from some previous invocation.
+     *
+     * <p>
+     * The BodyContent object is available and with the appropriate content
+     * until after the invocation of the doEndTag method, at which case it
+     * may be reused.
+     *
+     * @param b the BodyContent
+     * @see #doInitBody
+     * @see #doAfterBody
+     */
+
+    void setBodyContent(BodyContent b);
+
+
+    /**
+     * Prepare for evaluation of the body.
+     * This method is invoked by the JSP page implementation object
+     * after setBodyContent and before the first time
+     * the body is to be evaluated.
+     * This method will not be invoked for empty tags or for non-empty
+     * tags whose doStartTag() method returns SKIP_BODY or EVAL_BODY_INCLUDE.
+     *
+     * <p>
+     * The JSP container will resynchronize the values of any AT_BEGIN and
+     * NESTED variables (defined by the associated TagExtraInfo or TLD) after
+     * the invocation of doInitBody().
+     *
+     * @throws JspException if an error occurred while processing this tag
+     * @see #doAfterBody
+     */
+
+    void doInitBody() throws JspException;
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/tagext/BodyTagSupport.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/tagext/BodyTagSupport.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/tagext/BodyTagSupport.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,159 @@
+/*
+* Copyright 2004 The Apache Software Foundation
+*
+* Licensed 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.jsp.tagext;
+
+import javax.servlet.jsp.JspException;
+import javax.servlet.jsp.JspWriter;
+
+/**
+ * A base class for defining tag handlers implementing BodyTag.
+ *
+ * <p>
+ * The BodyTagSupport class implements the BodyTag interface and adds
+ * additional convenience methods including getter methods for the
+ * bodyContent property and methods to get at the previous out JspWriter.
+ *
+ * <p>
+ * Many tag handlers will extend BodyTagSupport and only redefine a
+ * few methods.
+ */
+
+public class BodyTagSupport extends TagSupport implements BodyTag {
+
+    /**
+     * Default constructor, all subclasses are required to only define
+     * a public constructor with the same signature, and to call the
+     * superclass constructor.
+     *
+     * This constructor is called by the code generated by the JSP
+     * translator.
+     */
+
+    public BodyTagSupport() {
+	super();
+    }
+
+    /**
+     * Default processing of the start tag returning EVAL_BODY_BUFFERED.
+     *
+     * @return EVAL_BODY_BUFFERED
+     * @throws JspException if an error occurred while processing this tag
+     * @see BodyTag#doStartTag
+     */
+ 
+    public int doStartTag() throws JspException {
+        return EVAL_BODY_BUFFERED;
+    }
+
+
+    /**
+     * Default processing of the end tag returning EVAL_PAGE.
+     *
+     * @return EVAL_PAGE
+     * @throws JspException if an error occurred while processing this tag
+     * @see Tag#doEndTag
+     */
+
+    public int doEndTag() throws JspException {
+	return super.doEndTag();
+    }
+
+
+    // Actions related to body evaluation
+
+    /**
+     * Prepare for evaluation of the body: stash the bodyContent away.
+     *
+     * @param b the BodyContent
+     * @see #doAfterBody
+     * @see #doInitBody()
+     * @see BodyTag#setBodyContent
+     */
+
+    public void setBodyContent(BodyContent b) {
+	this.bodyContent = b;
+    }
+
+
+    /**
+     * Prepare for evaluation of the body just before the first body evaluation:
+     * no action.
+     *
+     * @throws JspException if an error occurred while processing this tag
+     * @see #setBodyContent
+     * @see #doAfterBody
+     * @see BodyTag#doInitBody
+     */
+
+    public void doInitBody() throws JspException {
+    }
+
+
+    /**
+     * After the body evaluation: do not reevaluate and continue with the page.
+     * By default nothing is done with the bodyContent data (if any).
+     *
+     * @return SKIP_BODY
+     * @throws JspException if an error occurred while processing this tag
+     * @see #doInitBody
+     * @see BodyTag#doAfterBody
+     */
+
+    public int doAfterBody() throws JspException {
+ 	return SKIP_BODY;
+    }
+
+
+    /**
+     * Release state.
+     *
+     * @see Tag#release
+     */
+
+    public void release() {
+	bodyContent = null;
+
+	super.release();
+    }
+
+    /**
+     * Get current bodyContent.
+     *
+     * @return the body content.
+     */
+    
+    public BodyContent getBodyContent() {
+	return bodyContent;
+    }
+
+
+    /**
+     * Get surrounding out JspWriter.
+     *
+     * @return the enclosing JspWriter, from the bodyContent.
+     */
+
+    public JspWriter getPreviousOut() {
+	return bodyContent.getEnclosingWriter();
+    }
+
+    // protected fields
+
+    /**
+     * The current BodyContent for this BodyTag.
+     */
+    protected BodyContent   bodyContent;
+}

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/tagext/DynamicAttributes.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/tagext/DynamicAttributes.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/tagext/DynamicAttributes.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,51 @@
+/*
+* Copyright 2004 The Apache Software Foundation
+*
+* Licensed 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.jsp.tagext;
+
+import javax.servlet.jsp.JspException;
+
+/**
+ * For a tag to declare that it accepts dynamic attributes, it must implement
+ * this interface.  The entry for the tag in the Tag Library Descriptor must 
+ * also be configured to indicate dynamic attributes are accepted.
+ * <br>
+ * For any attribute that is not declared in the Tag Library Descriptor for
+ * this tag, instead of getting an error at translation time, the 
+ * <code>setDynamicAttribute()</code> method is called, with the name and
+ * value of the attribute.  It is the responsibility of the tag to 
+ * remember the names and values of the dynamic attributes.
+ *
+ * @since 2.0
+ */
+public interface DynamicAttributes {
+    
+    /**
+     * Called when a tag declared to accept dynamic attributes is passed
+     * an attribute that is not declared in the Tag Library Descriptor.
+     * 
+     * @param uri the namespace of the attribute, or null if in the default
+     *     namespace.
+     * @param localName the name of the attribute being set.
+     * @param value the value of the attribute
+     * @throws JspException if the tag handler wishes to
+     *     signal that it does not accept the given attribute.  The 
+     *     container must not call doStartTag() or doTag() for this tag.
+     */
+    public void setDynamicAttribute(
+        String uri, String localName, Object value ) 
+        throws JspException;
+    
+}

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/tagext/FunctionInfo.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/tagext/FunctionInfo.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/tagext/FunctionInfo.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,80 @@
+/*
+* Copyright 2004 The Apache Software Foundation
+*
+* Licensed 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.jsp.tagext;
+
+/**
+ * Information for a function in a Tag Library.
+ * This class is instantiated from the Tag Library Descriptor file (TLD)
+ * and is available only at translation time.
+ * 
+ * @since 2.0
+ */
+public class FunctionInfo {
+
+    /**
+     * Constructor for FunctionInfo.
+     *
+     * @param name The name of the function
+     * @param klass The class of the function
+     * @param signature The signature of the function
+     */
+
+    public FunctionInfo(String name, String klass, String signature) {
+
+	this.name = name;
+        this.functionClass = klass;
+        this.functionSignature = signature;
+    }
+
+    /**
+     * The name of the function.
+     *
+     * @return The name of the function
+     */
+
+    public String getName() {
+	return name;
+    }
+
+    /**
+     * The class of the function.
+     *
+     * @return The class of the function
+     */
+
+    public String getFunctionClass() {
+        return functionClass;
+    }
+
+    /**
+     * The signature of the function.
+     *
+     * @return The signature of the function
+     */
+
+    public String getFunctionSignature() {
+        return functionSignature;
+    }
+
+    /*
+     * fields
+     */
+
+    private String name;
+    private String functionClass;
+    private String functionSignature;
+}

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/tagext/IterationTag.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/tagext/IterationTag.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/tagext/IterationTag.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,119 @@
+/*
+* Copyright 2004 The Apache Software Foundation
+*
+* Licensed 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.jsp.tagext;
+
+import javax.servlet.jsp.*;
+
+/**
+ * The IterationTag interface extends Tag by defining one additional
+ * method that controls the reevaluation of its body.
+ *
+ * <p> A tag handler that implements IterationTag is treated as one that
+ * implements Tag regarding  the doStartTag() and doEndTag() methods.
+ * IterationTag provides a new method: <code>doAfterBody()</code>.
+ *
+ * <p> The doAfterBody() method is invoked after every body evaluation
+ * to control whether the body will be reevaluated or not.  If doAfterBody()
+ * returns IterationTag.EVAL_BODY_AGAIN, then the body will be reevaluated.
+ * If doAfterBody() returns Tag.SKIP_BODY, then the body will be skipped
+ * and doEndTag() will be evaluated instead.
+ *
+ * <p><B>Properties</B>
+ * There are no new properties in addition to those in Tag.
+ *
+ * <p><B>Methods</B>
+ * There is one new methods: doAfterBody().
+ *
+ * <p><B>Lifecycle</B>
+ *
+ * <p> Lifecycle details are described by the transition diagram
+ * below.  Exceptions that are thrown during the computation of
+ * doStartTag(), BODY and doAfterBody() interrupt the execution
+ * sequence and are propagated up the stack, unless the tag handler
+ * implements the TryCatchFinally interface; see that interface for
+ * details.
+ *
+ * <p>
+ * <IMG src="doc-files/IterationTagProtocol.gif"
+ *      alt="Lifecycle Details Transition Diagram for IterationTag"/>
+ *
+ * <p><B>Empty and Non-Empty Action</B>
+ * <p> If the TagLibraryDescriptor file indicates that the action must
+ * always have an empty element body, by a &lt;body-content&gt; entry of 
+ * "empty", then the doStartTag() method must return SKIP_BODY.
+ *
+ * <p>Note that which methods are invoked after the doStartTag() depends on
+ * both the return value and on if the custom action element is empty
+ * or not in the JSP page, not on how it's declared in the TLD.
+ *
+ * <p>
+ * If SKIP_BODY is returned the body is not evaluated, and then doEndTag()
+ * is invoked.
+ *
+ * <p>
+ * If EVAL_BODY_INCLUDE is returned, and the custom action element is not
+ * empty, the body is evaluated and "passed through" to the current out, 
+ * then doAfterBody() is invoked and, after zero or more iterations, 
+ * doEndTag() is invoked.
+ */
+
+public interface IterationTag extends Tag {
+
+    /**
+     * Request the reevaluation of some body.
+     * Returned from doAfterBody.
+     *
+     * For compatibility with JSP 1.1, the value is carefully selected
+     * to be the same as the, now deprecated, BodyTag.EVAL_BODY_TAG,
+     * 
+     */
+ 
+    public final static int EVAL_BODY_AGAIN = 2;
+
+    /**
+     * Process body (re)evaluation.  This method is invoked by the
+     * JSP Page implementation object after every evaluation of
+     * the body into the BodyEvaluation object. The method is
+     * not invoked if there is no body evaluation.
+     *
+     * <p>
+     * If doAfterBody returns EVAL_BODY_AGAIN, a new evaluation of the
+     * body will happen (followed by another invocation of doAfterBody).
+     * If doAfterBody returns SKIP_BODY, no more body evaluations will occur,
+     * and the doEndTag method will be invoked.
+     *
+     * <p>
+     * If this tag handler implements BodyTag and doAfterBody returns
+     * SKIP_BODY, the value of out will be restored using the popBody 
+     * method in pageContext prior to invoking doEndTag.
+     *
+     * <p>
+     * The method re-invocations may be lead to different actions because
+     * there might have been some changes to shared state, or because
+     * of external computation.
+     *
+     * <p>
+     * The JSP container will resynchronize the values of any AT_BEGIN and
+     * NESTED variables (defined by the associated TagExtraInfo or TLD) after
+     * the invocation of doAfterBody().
+     *
+     * @return whether additional evaluations of the body are desired
+     * @throws JspException if an error occurred while processing this tag
+     */
+
+    int doAfterBody() throws JspException;
+}

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/tagext/JspFragment.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/tagext/JspFragment.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/tagext/JspFragment.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,82 @@
+/*
+* Copyright 2004 The Apache Software Foundation
+*
+* Licensed 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.jsp.tagext;
+
+import java.io.IOException;
+import java.io.Writer;
+import javax.servlet.jsp.*;
+
+/**
+ * Encapsulates a portion of JSP code in an object that 
+ * can be invoked as many times as needed.  JSP Fragments are defined 
+ * using JSP syntax as the body of a tag for an invocation to a SimpleTag 
+ * handler, or as the body of a &lt;jsp:attribute&gt; standard action
+ * specifying the value of an attribute that is declared as a fragment,
+ * or to be of type JspFragment in the TLD.
+ * <p>
+ * The definition of the JSP fragment must only contain template 
+ * text and JSP action elements.  In other words, it must not contain
+ * scriptlets or scriptlet expressions.  At translation time, the 
+ * container generates an implementation of the JspFragment abstract class
+ * capable of executing the defined fragment.
+ * <p>
+ * A tag handler can invoke the fragment zero or more times, or 
+ * pass it along to other tags, before returning.  To communicate values
+ * to/from a JSP fragment, tag handlers store/retrieve values in 
+ * the JspContext associated with the fragment.
+ * <p>
+ * Note that tag library developers and page authors should not generate
+ * JspFragment implementations manually.
+ * <p>
+ * <i>Implementation Note</i>: It is not necessary to generate a 
+ * separate class for each fragment.  One possible implementation is 
+ * to generate a single helper class for each page that implements 
+ * JspFragment. Upon construction, a discriminator can be passed to 
+ * select which fragment that instance will execute.
+ *
+ * @since 2.0
+ */
+public abstract class JspFragment {
+
+    /**
+     * Executes the fragment and directs all output to the given Writer,
+     * or the JspWriter returned by the getOut() method of the JspContext
+     * associated with the fragment if out is null.
+     *
+     * @param out The Writer to output the fragment to, or null if 
+     *     output should be sent to JspContext.getOut().
+     * @throws javax.servlet.jsp.JspException Thrown if an error occured
+     *     while invoking this fragment.
+     * @throws javax.servlet.jsp.SkipPageException Thrown if the page
+     *     that (either directly or indirectly) invoked the tag handler that
+     *     invoked this fragment is to cease evaluation.  The container
+     *     must throw this exception if a Classic Tag Handler returned
+     *     Tag.SKIP_PAGE or if a Simple Tag Handler threw SkipPageException.
+     * @throws java.io.IOException If there was an error writing to the 
+     *     stream.
+     */
+    public abstract void invoke( Writer out )
+        throws JspException, IOException;
+
+    /**
+     * Returns the JspContext that is bound to this JspFragment.
+     *
+     * @return The JspContext used by this fragment at invocation time.
+     */
+    public abstract JspContext getJspContext();
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/tagext/JspTag.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/tagext/JspTag.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/tagext/JspTag.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,25 @@
+/*
+* Copyright 2004 The Apache Software Foundation
+*
+* Licensed 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.jsp.tagext;
+
+/**
+ * Serves as a base class for Tag and SimpleTag.  
+ * This is mostly for organizational and type-safety purposes.
+ *
+ * @since 2.0
+ */
+public interface JspTag {
+}

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/tagext/PageData.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/tagext/PageData.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/tagext/PageData.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,48 @@
+/*
+* Copyright 2004 The Apache Software Foundation
+*
+* Licensed 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.jsp.tagext;
+
+import java.io.InputStream;
+
+/**
+ * Translation-time information on a JSP page.  The information
+ * corresponds to the XML view of the JSP page.
+ *
+ * <p>
+ * Objects of this type are generated by the JSP translator, e.g.
+ * when being pased to a TagLibraryValidator instance.
+ */
+
+abstract public class PageData {
+
+    /**
+     * Sole constructor. (For invocation by subclass constructors, 
+     * typically implicit.)
+     */
+    public PageData() {
+    }
+    
+    /**
+     * Returns an input stream on the XML view of a JSP page.
+     * The stream is encoded in UTF-8.  Recall tht the XML view of a 
+     * JSP page has the include directives expanded.
+     * 
+     * @return An input stream on the document.
+     */
+   abstract public InputStream getInputStream();
+}

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/tagext/SimpleTag.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/tagext/SimpleTag.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/tagext/SimpleTag.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,139 @@
+/*
+* Copyright 2004 The Apache Software Foundation
+*
+* Licensed 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.jsp.tagext;
+
+import javax.servlet.jsp.JspContext;
+
+/**
+ * Interface for defining Simple Tag Handlers.
+ * 
+ * <p>Simple Tag Handlers differ from Classic Tag Handlers in that instead 
+ * of supporting <code>doStartTag()</code> and <code>doEndTag()</code>, 
+ * the <code>SimpleTag</code> interface provides a simple 
+ * <code>doTag()</code> method, which is called once and only once for any 
+ * given tag invocation.  All tag logic, iteration, body evaluations, etc. 
+ * are to be performed in this single method.  Thus, simple tag handlers 
+ * have the equivalent power of <code>BodyTag</code>, but with a much 
+ * simpler lifecycle and interface.</p>
+ *
+ * <p>To support body content, the <code>setJspBody()</code> 
+ * method is provided.  The container invokes the <code>setJspBody()</code> 
+ * method with a <code>JspFragment</code> object encapsulating the body of 
+ * the tag.  The tag handler implementation can call 
+ * <code>invoke()</code> on that fragment to evaluate the body as
+ * many times as it needs.</p>
+ *
+ * <p>A SimpleTag handler must have a public no-args constructor.  Most
+ * SimpleTag handlers should extend SimpleTagSupport.</p>
+ * 
+ * <p><b>Lifecycle</b></p>
+ *
+ * <p>The following is a non-normative, brief overview of the 
+ * SimpleTag lifecycle.  Refer to the JSP Specification for details.</p>
+ *
+ * <ol>
+ *   <li>A new tag handler instance is created each time by the container 
+ *       by calling the provided zero-args constructor.  Unlike classic
+ *       tag handlers, simple tag handlers are never cached and reused by
+ *       the JSP container.</li>
+ *   <li>The <code>setJspContext()</code> and <code>setParent()</code> 
+ *       methods are called by the container.  The <code>setParent()</code>
+ *       method is only called if the element is nested within another tag 
+ *       invocation.</li>
+ *   <li>The setters for each attribute defined for this tag are called
+ *       by the container.</li>
+ *   <li>If a body exists, the <code>setJspBody()</code> method is called 
+ *       by the container to set the body of this tag, as a 
+ *       <code>JspFragment</code>.  If the action element is empty in
+ *       the page, this method is not called at all.</li>
+ *   <li>The <code>doTag()</code> method is called by the container.  All
+ *       tag logic, iteration, body evaluations, etc. occur in this 
+ *       method.</li>
+ *   <li>The <code>doTag()</code> method returns and all variables are
+ *       synchronized.</li>
+ * </ol>
+ * 
+ * @see SimpleTagSupport
+ * @since 2.0
+ */
+public interface SimpleTag extends JspTag {
+    
+    /** 
+     * Called by the container to invoke this tag.
+     * The implementation of this method is provided by the tag library
+     * developer, and handles all tag processing, body iteration, etc.
+     *
+     * <p>
+     * The JSP container will resynchronize any AT_BEGIN and AT_END
+     * variables (defined by the associated tag file, TagExtraInfo, or TLD)
+     * after the invocation of doTag().
+     * 
+     * @throws javax.servlet.jsp.JspException If an error occurred 
+     *     while processing this tag.
+     * @throws javax.servlet.jsp.SkipPageException If the page that
+     *     (either directly or indirectly) invoked this tag is to
+     *     cease evaluation.  A Simple Tag Handler generated from a 
+     *     tag file must throw this exception if an invoked Classic 
+     *     Tag Handler returned SKIP_PAGE or if an invoked Simple
+     *     Tag Handler threw SkipPageException or if an invoked Jsp Fragment
+     *     threw a SkipPageException.
+     * @throws java.io.IOException If there was an error writing to the
+     *     output stream.
+     */ 
+    public void doTag() 
+        throws javax.servlet.jsp.JspException, java.io.IOException;
+    
+    /**
+     * Sets the parent of this tag, for collaboration purposes.
+     * <p>
+     * The container invokes this method only if this tag invocation is 
+     * nested within another tag invocation.
+     *
+     * @param parent the tag that encloses this tag
+     */
+    public void setParent( JspTag parent );
+    
+    /**
+     * Returns the parent of this tag, for collaboration purposes.
+     *
+     * @return the parent of this tag
+     */ 
+    public JspTag getParent();
+    
+    /**
+     * Called by the container to provide this tag handler with
+     * the <code>JspContext</code> for this invocation.
+     * An implementation should save this value.
+     * 
+     * @param pc the page context for this invocation
+     * @see Tag#setPageContext
+     */
+    public void setJspContext( JspContext pc );
+                
+    /** 
+     * Provides the body of this tag as a JspFragment object, able to be 
+     * invoked zero or more times by the tag handler. 
+     * <p>
+     * This method is invoked by the JSP page implementation 
+     * object prior to <code>doTag()</code>.  If the action element is
+     * empty in the page, this method is not called at all.
+     * 
+     * @param jspBody The fragment encapsulating the body of this tag.
+     */ 
+    public void setJspBody( JspFragment jspBody );
+
+    
+}

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/tagext/SimpleTagSupport.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/tagext/SimpleTagSupport.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/tagext/SimpleTagSupport.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,212 @@
+/*
+* Copyright 2004 The Apache Software Foundation
+*
+* Licensed 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.jsp.tagext;
+
+import javax.servlet.jsp.JspContext;
+import javax.servlet.jsp.JspException;
+import java.io.IOException;
+
+/**
+ * A base class for defining tag handlers implementing SimpleTag.
+ * <p>
+ * The SimpleTagSupport class is a utility class intended to be used
+ * as the base class for new simple tag handlers.  The SimpleTagSupport
+ * class implements the SimpleTag interface and adds additional
+ * convenience methods including getter methods for the properties in
+ * SimpleTag.
+ *
+ * @since 2.0
+ */
+public class SimpleTagSupport 
+    implements SimpleTag
+{
+    /** Reference to the enclosing tag. */
+    private JspTag parentTag;
+    
+    /** The JSP context for the upcoming tag invocation. */
+    private JspContext jspContext;
+    
+    /** The body of the tag. */
+    private JspFragment jspBody;
+    
+    /**
+     * Sole constructor. (For invocation by subclass constructors, 
+     * typically implicit.)
+     */
+    public SimpleTagSupport() {
+    }
+    
+    /** 
+     * Default processing of the tag does nothing.
+     *
+     * @throws JspException Subclasses can throw JspException to indicate
+     *     an error occurred while processing this tag.
+     * @throws javax.servlet.jsp.SkipPageException If the page that
+     *     (either directly or indirectly) invoked this tag is to
+     *     cease evaluation.  A Simple Tag Handler generated from a 
+     *     tag file must throw this exception if an invoked Classic 
+     *     Tag Handler returned SKIP_PAGE or if an invoked Simple
+     *     Tag Handler threw SkipPageException or if an invoked Jsp Fragment
+     *     threw a SkipPageException.
+     * @throws IOException Subclasses can throw IOException if there was
+     *     an error writing to the output stream
+     * @see SimpleTag#doTag()
+     */ 
+    public void doTag() 
+        throws JspException, IOException
+    {
+    }
+    
+    /**
+     * Sets the parent of this tag, for collaboration purposes.
+     * <p>
+     * The container invokes this method only if this tag invocation is
+     * nested within another tag invocation.
+     *
+     * @param parent the tag that encloses this tag
+     */
+    public void setParent( JspTag parent ) {
+        this.parentTag = parent;
+    }
+    
+    /**
+     * Returns the parent of this tag, for collaboration purposes.
+     *
+     * @return the parent of this tag
+     */ 
+    public JspTag getParent() {
+        return this.parentTag;
+    }
+    
+    /**
+     * Stores the provided JSP context in the private jspContext field.
+     * Subclasses can access the <code>JspContext</code> via 
+     * <code>getJspContext()</code>.
+     * 
+     * @param pc the page context for this invocation
+     * @see SimpleTag#setJspContext
+     */
+    public void setJspContext( JspContext pc ) {
+        this.jspContext = pc;
+    }
+    
+    /**
+     * Returns the page context passed in by the container via 
+     * setJspContext.
+     *
+     * @return the page context for this invocation
+     */
+    protected JspContext getJspContext() {
+        return this.jspContext;
+    }
+                
+    /** 
+     * Stores the provided JspFragment.
+     *
+     * @param jspBody The fragment encapsulating the body of this tag.
+     *     If the action element is empty in the page, this method is 
+     *     not called at all.
+     * @see SimpleTag#setJspBody
+     */ 
+    public void setJspBody( JspFragment jspBody ) {
+        this.jspBody = jspBody;
+    }
+    
+    /**
+     * Returns the body passed in by the container via setJspBody.
+     *
+     * @return the fragment encapsulating the body of this tag, or
+     *    null if the action element is empty in the page.
+     */
+    protected JspFragment getJspBody() {
+        return this.jspBody;
+    }
+
+    /**
+     * Find the instance of a given class type that is closest to a given
+     * instance.
+     * This method uses the getParent method from the Tag and/or SimpleTag
+     * interfaces.  This method is used for coordination among 
+     * cooperating tags.
+     *
+     * <p> For every instance of TagAdapter
+     * encountered while traversing the ancestors, the tag handler returned by
+     * <tt>TagAdapter.getAdaptee()</tt> - instead of the TagAdpater itself -
+     * is compared to <tt>klass</tt>. If the tag handler matches, it - and
+     * not its TagAdapter - is returned.
+     *
+     * <p>
+     * The current version of the specification only provides one formal
+     * way of indicating the observable type of a tag handler: its
+     * tag handler implementation class, described in the tag-class
+     * subelement of the tag element.  This is extended in an
+     * informal manner by allowing the tag library author to
+     * indicate in the description subelement an observable type.
+     * The type should be a subtype of the tag handler implementation
+     * class or void.
+     * This addititional constraint can be exploited by a
+     * specialized container that knows about that specific tag library,
+     * as in the case of the JSP standard tag library.
+     *
+     * <p>
+     * When a tag library author provides information on the
+     * observable type of a tag handler, client programmatic code
+     * should adhere to that constraint.  Specifically, the Class
+     * passed to findAncestorWithClass should be a subtype of the
+     * observable type.
+     * 
+     *
+     * @param from The instance from where to start looking.
+     * @param klass The subclass of JspTag or interface to be matched
+     * @return the nearest ancestor that implements the interface
+     * or is an instance of the class specified
+     */
+    public static final JspTag findAncestorWithClass(
+	JspTag from, Class klass) 
+    {
+	boolean isInterface = false;
+
+	if (from == null || klass == null
+	        || (!JspTag.class.isAssignableFrom(klass)
+		    && !(isInterface = klass.isInterface()))) {
+	    return null;
+	}
+
+	for (;;) {
+	    JspTag parent = null;
+	    if( from instanceof SimpleTag ) {
+		parent = ((SimpleTag)from).getParent();
+	    }
+	    else if( from instanceof Tag ) {
+		parent = ((Tag)from).getParent();
+	    }
+	    if (parent == null) {
+		return null;
+	    }
+
+	    if (parent instanceof TagAdapter) {
+		parent = ((TagAdapter) parent).getAdaptee();
+	    }
+
+	    if ((isInterface && klass.isInstance(parent))
+		    || klass.isAssignableFrom(parent.getClass())) {
+		return parent;
+	    }
+
+	    from = parent;
+	}
+    }    
+}

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/tagext/Tag.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/tagext/Tag.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/tagext/Tag.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,262 @@
+/*
+* Copyright 2004 The Apache Software Foundation
+*
+* Licensed 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.jsp.tagext;
+
+import javax.servlet.jsp.*;
+
+
+/**
+ * The interface of a classic tag handler that does not want to manipulate 
+ * its body.  The Tag interface defines the basic protocol between a Tag 
+ * handler and JSP page implementation class.  It defines the life cycle 
+ * and the methods to be invoked at start and end tag.
+ *
+ * <p><B>Properties</B></p>
+ *
+ * <p>The Tag interface specifies the setter and getter methods for the core
+ * pageContext and parent properties.</p>
+ *
+ * <p>The JSP page implementation object invokes setPageContext and
+ * setParent, in that order, before invoking doStartTag() or doEndTag().</p>
+ *
+ * <p><B>Methods</B></p>
+ *
+ * <p>There are two main actions: doStartTag and doEndTag.  Once all
+ * appropriate properties have been initialized, the doStartTag and
+ * doEndTag methods can be invoked on the tag handler.  Between these
+ * invocations, the tag handler is assumed to hold a state that must
+ * be preserved.  After the doEndTag invocation, the tag handler is
+ * available for further invocations (and it is expected to have
+ * retained its properties).</p>
+ *
+ * <p><B>Lifecycle</B></p>
+ *
+ * <p>Lifecycle details are described by the transition diagram below,
+ * with the following comments:
+ * <ul>
+ * <li> [1] This transition is intended to be for releasing long-term data.
+ * no guarantees are assumed on whether any properties have been retained
+ * or not.
+ * <li> [2] This transition happens if and only if the tag ends normally
+ * without raising an exception
+ * <li> [3] Some setters may be called again before a tag handler is 
+ * reused.  For instance, <code>setParent()</code> is called if it's 
+ * reused within the same page but at a different level, 
+ * <code>setPageContext()</code> is called if it's used in another page, 
+ * and attribute setters are called if the values differ or are expressed 
+ * as request-time attribute values.
+ * <li> Check the TryCatchFinally interface for additional details related
+ * to exception handling and resource management.
+ * </ul></p>
+ *
+ * <IMG src="doc-files/TagProtocol.gif"
+ *      alt="Lifecycle Details Transition Diagram for Tag"/>
+ * 
+ * <p>Once all invocations on the tag handler
+ * are completed, the release method is invoked on it.  Once a release
+ * method is invoked <em>all</em> properties, including parent and
+ * pageContext, are assumed to have been reset to an unspecified value.
+ * The page compiler guarantees that release() will be invoked on the Tag
+ * handler before the handler is released to the GC.</p>
+ *
+ * <p><B>Empty and Non-Empty Action</B></p>
+ * <p>If the TagLibraryDescriptor file indicates that the action must
+ * always have an empty action, by an &lt;body-content&gt; entry of "empty",
+ * then the doStartTag() method must return SKIP_BODY.</p>
+ *
+ * <p>Otherwise, the doStartTag() method may return SKIP_BODY or
+ * EVAL_BODY_INCLUDE.</p>
+ *
+ * <p>If SKIP_BODY is returned the body, if present, is not evaluated.</p>
+ * 
+ * <p>If EVAL_BODY_INCLUDE is returned, the body is evaluated and
+ * "passed through" to the current out.</p>
+*/
+
+public interface Tag extends JspTag {
+
+    /**
+     * Skip body evaluation.
+     * Valid return value for doStartTag and doAfterBody.
+     */
+ 
+    public final static int SKIP_BODY = 0;
+ 
+    /**
+     * Evaluate body into existing out stream.
+     * Valid return value for doStartTag.
+     */
+ 
+    public final static int EVAL_BODY_INCLUDE = 1;
+
+    /**
+     * Skip the rest of the page.
+     * Valid return value for doEndTag.
+     */
+
+    public final static int SKIP_PAGE = 5;
+
+    /**
+     * Continue evaluating the page.
+     * Valid return value for doEndTag().
+     */
+
+    public final static int EVAL_PAGE = 6;
+
+    // Setters for Tag handler data
+
+
+    /**
+     * Set the current page context.
+     * This method is invoked by the JSP page implementation object
+     * prior to doStartTag().
+     * <p>
+     * This value is *not* reset by doEndTag() and must be explicitly reset
+     * by a page implementation if it changes between calls to doStartTag().
+     *
+     * @param pc The page context for this tag handler.
+     */
+
+    void setPageContext(PageContext pc);
+
+
+    /**
+     * Set the parent (closest enclosing tag handler) of this tag handler.
+     * Invoked by the JSP page implementation object prior to doStartTag().
+     * <p>
+     * This value is *not* reset by doEndTag() and must be explicitly reset
+     * by a page implementation.
+     *
+     * @param t The parent tag, or null.
+     */
+
+
+    void setParent(Tag t);
+
+
+    /**
+     * Get the parent (closest enclosing tag handler) for this tag handler.
+     *
+     * <p>
+     * The getParent() method can be used to navigate the nested tag
+     * handler structure at runtime for cooperation among custom actions;
+     * for example, the findAncestorWithClass() method in TagSupport
+     * provides a convenient way of doing this.
+     *
+     * <p>
+     * The current version of the specification only provides one formal
+     * way of indicating the observable type of a tag handler: its
+     * tag handler implementation class, described in the tag-class
+     * subelement of the tag element.  This is extended in an
+     * informal manner by allowing the tag library author to
+     * indicate in the description subelement an observable type.
+     * The type should be a subtype of the tag handler implementation
+     * class or void.
+     * This addititional constraint can be exploited by a
+     * specialized container that knows about that specific tag library,
+     * as in the case of the JSP standard tag library.
+     *
+     * @return the current parent, or null if none.
+     * @see TagSupport#findAncestorWithClass
+     */
+
+    Tag getParent();
+
+
+    // Actions for basic start/end processing.
+
+
+    /**
+     * Process the start tag for this instance.
+     * This method is invoked by the JSP page implementation object.
+     *
+     * <p>
+     * The doStartTag method assumes that the properties pageContext and
+     * parent have been set. It also assumes that any properties exposed as
+     * attributes have been set too.  When this method is invoked, the body
+     * has not yet been evaluated.
+     *
+     * <p>
+     * This method returns Tag.EVAL_BODY_INCLUDE or
+     * BodyTag.EVAL_BODY_BUFFERED to indicate
+     * that the body of the action should be evaluated or SKIP_BODY to
+     * indicate otherwise.
+     *
+     * <p>
+     * When a Tag returns EVAL_BODY_INCLUDE the result of evaluating
+     * the body (if any) is included into the current "out" JspWriter as it
+     * happens and then doEndTag() is invoked.
+     *
+     * <p>
+     * BodyTag.EVAL_BODY_BUFFERED is only valid  if the tag handler
+     * implements BodyTag.
+     *
+     * <p>
+     * The JSP container will resynchronize the values of any AT_BEGIN and
+     * NESTED variables (defined by the associated TagExtraInfo or TLD)
+     * after the invocation of doStartTag(), except for a tag handler
+     * implementing BodyTag whose doStartTag() method returns
+     * BodyTag.EVAL_BODY_BUFFERED.
+     *
+     * @return EVAL_BODY_INCLUDE if the tag wants to process body, SKIP_BODY 
+     *     if it does not want to process it.
+     * @throws JspException if an error occurred while processing this tag
+     * @see BodyTag
+     */
+ 
+    int doStartTag() throws JspException;
+ 
+
+    /**
+     * Process the end tag for this instance.
+     * This method is invoked by the JSP page implementation object
+     * on all Tag handlers.
+     *
+     * <p>
+     * This method will be called after returning from doStartTag. The
+     * body of the action may or may not have been evaluated, depending on
+     * the return value of doStartTag.
+     *
+     * <p>
+     * If this method returns EVAL_PAGE, the rest of the page continues
+     * to be evaluated.  If this method returns SKIP_PAGE, the rest of
+     * the page is not evaluated, the request is completed, and 
+     * the doEndTag() methods of enclosing tags are not invoked.  If this
+     * request was forwarded or included from another page (or Servlet),
+     * only the current page evaluation is stopped.
+     *
+     * <p>
+     * The JSP container will resynchronize the values of any AT_BEGIN and
+     * AT_END variables (defined by the associated TagExtraInfo or TLD)
+     * after the invocation of doEndTag().
+     *
+     * @return indication of whether to continue evaluating the JSP page.
+     * @throws JspException if an error occurred while processing this tag
+     */
+
+    int doEndTag() throws JspException;
+
+    /**
+     * Called on a Tag handler to release state.
+     * The page compiler guarantees that JSP page implementation
+     * objects will invoke this method on all tag handlers,
+     * but there may be multiple invocations on doStartTag and doEndTag in between.
+     */
+
+    void release();
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/tagext/TagAdapter.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/tagext/TagAdapter.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/tagext/TagAdapter.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,158 @@
+/*
+* Copyright 2004 The Apache Software Foundation
+*
+* Licensed 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.jsp.tagext;
+
+import javax.servlet.jsp.*;
+
+
+/**
+ * Wraps any SimpleTag and exposes it using a Tag interface.  This is used
+ * to allow collaboration between classic Tag handlers and SimpleTag
+ * handlers.
+ * <p>
+ * Because SimpleTag does not extend Tag, and because Tag.setParent()
+ * only accepts a Tag instance, a classic tag handler (one
+ * that implements Tag) cannot have a SimpleTag as its parent.  To remedy
+ * this, a TagAdapter is created to wrap the SimpleTag parent, and the
+ * adapter is passed to setParent() instead.  A classic Tag Handler can
+ * call getAdaptee() to retrieve the encapsulated SimpleTag instance.
+ *
+ * @since 2.0
+ */
+public class TagAdapter 
+    implements Tag
+{
+    /** The simple tag that's being adapted. */
+    private SimpleTag simpleTagAdaptee;
+
+    /** The parent, of this tag, converted (if necessary) to be of type Tag. */
+    private Tag parent;
+
+    // Flag indicating whether we have already determined the parent
+    private boolean parentDetermined;
+
+    /**
+     * Creates a new TagAdapter that wraps the given SimpleTag and 
+     * returns the parent tag when getParent() is called.
+     *
+     * @param adaptee The SimpleTag being adapted as a Tag.
+     */
+    public TagAdapter( SimpleTag adaptee ) {
+        if( adaptee == null ) {
+	    // Cannot wrap a null adaptee.
+	    throw new IllegalArgumentException();
+        }
+        this.simpleTagAdaptee = adaptee;
+    }
+    
+    /**
+     * Must not be called.
+     *
+     * @param pc ignored.
+     * @throws UnsupportedOperationException Must not be called
+     */
+    public void setPageContext(PageContext pc) {
+        throw new UnsupportedOperationException( 
+            "Illegal to invoke setPageContext() on TagAdapter wrapper" );
+    }
+
+
+    /**
+     * Must not be called.  The parent of this tag is always 
+     * getAdaptee().getParent().
+     *
+     * @param parentTag ignored.
+     * @throws UnsupportedOperationException Must not be called.
+     */
+    public void setParent( Tag parentTag ) {
+        throw new UnsupportedOperationException( 
+            "Illegal to invoke setParent() on TagAdapter wrapper" );
+    }
+
+
+    /**
+     * Returns the parent of this tag, which is always
+     * getAdaptee().getParent().  
+     *
+     * This will either be the enclosing Tag (if getAdaptee().getParent()
+     * implements Tag), or an adapter to the enclosing Tag (if 
+     * getAdaptee().getParent() does not implement Tag).
+     *
+     * @return The parent of the tag being adapted.
+     */
+    public Tag getParent() {
+	if (!parentDetermined) {
+	    JspTag adapteeParent = simpleTagAdaptee.getParent();
+	    if (adapteeParent != null) {
+		if (adapteeParent instanceof Tag) {
+		    this.parent = (Tag) adapteeParent;
+		} else {
+		    // Must be SimpleTag - no other types defined.
+		    this.parent = new TagAdapter((SimpleTag) adapteeParent);
+		}
+	    }
+	    parentDetermined = true;
+	}
+
+	return this.parent;
+    }
+    
+    /**
+     * Gets the tag that is being adapted to the Tag interface.
+     * This should be an instance of SimpleTag in JSP 2.0, but room
+     * is left for other kinds of tags in future spec versions.
+     *
+     * @return the tag that is being adapted
+     */
+    public JspTag getAdaptee() {
+        return this.simpleTagAdaptee;
+    }
+
+    /**
+     * Must not be called.
+     *
+     * @return always throws UnsupportedOperationException
+     * @throws UnsupportedOperationException Must not be called
+     * @throws JspException never thrown
+     */
+    public int doStartTag() throws JspException {
+        throw new UnsupportedOperationException( 
+            "Illegal to invoke doStartTag() on TagAdapter wrapper" );
+    }
+ 
+    /**
+     * Must not be called.
+     *
+     * @return always throws UnsupportedOperationException
+     * @throws UnsupportedOperationException Must not be called
+     * @throws JspException never thrown
+     */
+    public int doEndTag() throws JspException {
+        throw new UnsupportedOperationException( 
+            "Illegal to invoke doEndTag() on TagAdapter wrapper" );
+    }
+
+    /**
+     * Must not be called.
+     *
+     * @throws UnsupportedOperationException Must not be called
+     */
+    public void release() {
+        throw new UnsupportedOperationException( 
+            "Illegal to invoke release() on TagAdapter wrapper" );
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/tagext/TagAttributeInfo.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/tagext/TagAttributeInfo.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/tagext/TagAttributeInfo.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,177 @@
+/*
+* Copyright 2004 The Apache Software Foundation
+*
+* Licensed 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.jsp.tagext;
+
+/**
+ * Information on the attributes of a Tag, available at translation time.
+ * This class is instantiated from the Tag Library Descriptor file (TLD).
+ *
+ * <p>
+ * Only the information needed to generate code is included here.  Other information
+ * like SCHEMA for validation belongs elsewhere.
+ */
+
+public class TagAttributeInfo {
+    /**
+     * "id" is wired in to be ID.  There is no real benefit in having it be something else
+     * IDREFs are not handled any differently.
+     */
+
+    public static final String ID = "id";
+
+    /**
+     * Constructor for TagAttributeInfo.
+     * This class is to be instantiated only from the
+     * TagLibrary code under request from some JSP code that is parsing a
+     * TLD (Tag Library Descriptor).
+     *
+     * @param name The name of the attribute.
+     * @param required If this attribute is required in tag instances.
+     * @param type The name of the type of the attribute.
+     * @param reqTime Whether this attribute holds a request-time Attribute.
+     */
+
+    public TagAttributeInfo(String name, boolean required,
+                            String type, boolean reqTime)
+    {
+	this.name = name;
+        this.required = required;
+        this.type = type;
+	this.reqTime = reqTime;
+    }
+
+    /**
+     * JSP 2.0 Constructor for TagAttributeInfo.
+     * This class is to be instantiated only from the
+     * TagLibrary code under request from some JSP code that is parsing a
+     * TLD (Tag Library Descriptor).
+     *
+     * @param name The name of the attribute.
+     * @param required If this attribute is required in tag instances.
+     * @param type The name of the type of the attribute.
+     * @param reqTime Whether this attribute holds a request-time Attribute.
+     * @param fragment Whether this attribute is of type JspFragment
+     *
+     * @since 2.0
+     */
+
+    public TagAttributeInfo(String name, boolean required,
+                            String type, boolean reqTime,
+			    boolean fragment)
+    {
+	this( name, required, type, reqTime );
+	this.fragment = fragment;
+    }
+
+    /**
+     * The name of this attribute.
+     *
+     * @return the name of the attribute
+     */
+
+    public String getName() {
+	return name;
+    }
+
+    /**
+     * The type (as a String) of this attribute.
+     *
+     * @return the type of the attribute
+     */
+
+    public String getTypeName() {
+	return type;
+    }
+
+    /**
+     * Whether this attribute can hold a request-time value.
+     *
+     * @return if the attribute can hold a request-time value.
+     */
+
+    public boolean canBeRequestTime() {
+	return reqTime;
+    }
+
+    /**
+     * Whether this attribute is required.
+     *
+     * @return if the attribute is required.
+     */
+    public boolean isRequired() {
+        return required;
+    }
+
+    /**
+     * Convenience static method that goes through an array of TagAttributeInfo
+     * objects and looks for "id".
+     *
+     * @param a An array of TagAttributeInfo
+     * @return The TagAttributeInfo reference with name "id"
+     */
+    public static TagAttributeInfo getIdAttribute(TagAttributeInfo a[]) {
+	for (int i=0; i<a.length; i++) {
+	    if (a[i].getName().equals(ID)) {
+		return a[i];
+	    }
+	}
+	return null;		// no such attribute
+    }
+
+    /**
+     * Whether this attribute is of type JspFragment.
+     *
+     * @return if the attribute is of type JspFragment
+     *
+     * @since 2.0
+     */
+    public boolean isFragment() {
+	return fragment;
+    }
+
+
+    
+    /**
+     * Returns a String representation of this TagAttributeInfo, suitable
+     * for debugging purposes.
+     *
+     * @return a String representation of this TagAttributeInfo
+     */
+    public String toString() {
+        StringBuffer b = new StringBuffer();
+        b.append("name = "+name+" ");
+        b.append("type = "+type+" ");
+	b.append("reqTime = "+reqTime+" ");
+        b.append("required = "+required+" ");
+        b.append("fragment = "+fragment+" ");
+        return b.toString();
+    }
+
+    /*
+     * private fields
+     */
+    private String name;
+    private String type;
+    private boolean reqTime;
+    private boolean required;
+
+    /*
+     * private fields for JSP 2.0
+     */
+    private boolean fragment;
+}

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/tagext/TagData.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/tagext/TagData.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/tagext/TagData.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,153 @@
+/*
+* Copyright 2004 The Apache Software Foundation
+*
+* Licensed 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.jsp.tagext;
+
+import java.util.Hashtable;
+
+/**
+ * The (translation-time only) attribute/value information for a tag instance.
+ *
+ * <p>
+ * TagData is only used as an argument to the isValid, validate, and 
+ * getVariableInfo methods of TagExtraInfo, which are invoked at 
+ * translation time.
+ */
+
+public class TagData implements Cloneable {
+
+    /**
+     * Distinguished value for an attribute to indicate its value
+     * is a request-time expression (which is not yet available because
+     * TagData instances are used at translation-time).
+     */
+
+    public static final Object REQUEST_TIME_VALUE = new Object();
+
+
+    /**
+     * Constructor for TagData.
+     *
+     * <p>
+     * A typical constructor may be
+     * <pre>
+     * static final Object[][] att = {{"connection", "conn0"}, {"id", "query0"}};
+     * static final TagData td = new TagData(att);
+     * </pre>
+     *
+     * All values must be Strings except for those holding the
+     * distinguished object REQUEST_TIME_VALUE.
+
+     * @param atts the static attribute and values.  May be null.
+     */
+    public TagData(Object[] atts[]) {
+	if (atts == null) {
+	    attributes = new Hashtable();
+	} else {
+	    attributes = new Hashtable(atts.length);
+	}
+
+	if (atts != null) {
+	    for (int i = 0; i < atts.length; i++) {
+		attributes.put(atts[i][0], atts[i][1]);
+	    }
+	}
+    }
+
+    /**
+     * Constructor for a TagData.
+     *
+     * If you already have the attributes in a hashtable, use this
+     * constructor. 
+     *
+     * @param attrs A hashtable to get the values from.
+     */
+    public TagData(Hashtable attrs) {
+        this.attributes = attrs;
+    }
+
+    /**
+     * The value of the tag's id attribute.
+     *
+     * @return the value of the tag's id attribute, or null if no such
+     *     attribute was specified.
+     */
+
+    public String getId() {
+	return getAttributeString(TagAttributeInfo.ID);
+    }
+
+    /**
+     * The value of the attribute.
+     * If a static value is specified for an attribute that accepts a
+     * request-time attribute expression then that static value is returned,
+     * even if the value is provided in the body of a <jsp:attribute> action.
+     * The distinguished object REQUEST_TIME_VALUE is only returned if
+     * the value is specified as a request-time attribute expression
+     * or via the &lt;jsp:attribute&gt; action with a body that contains
+     * dynamic content (scriptlets, scripting expressions, EL expressions, 
+     * standard actions, or custom actions).  Returns null if the attribute 
+     * is not set. 
+     *
+     * @param attName the name of the attribute
+     * @return the attribute's value
+     */
+
+    public Object getAttribute(String attName) {
+	return attributes.get(attName);
+    }
+
+    /**
+     * Set the value of an attribute.
+     *
+     * @param attName the name of the attribute
+     * @param value the value.
+     */
+    public void setAttribute(String attName,
+			     Object value) {
+	attributes.put(attName, value);
+    }
+
+    /**
+     * Get the value for a given attribute.
+     *
+     * @param attName the name of the attribute
+     * @return the attribute value string
+     * @throws ClassCastException if attribute value is not a String
+     */
+
+    public String getAttributeString(String attName) {
+	Object o = attributes.get(attName);
+	if (o == null) {
+	    return null;
+	} else {
+	    return (String) o;
+	}	
+    }
+
+    /**
+     * Enumerates the attributes.
+     *
+     *@return An enumeration of the attributes in a TagData
+     */
+    public java.util.Enumeration getAttributes() {
+        return attributes.keys();
+    };
+
+    // private data
+
+    private Hashtable attributes;	// the tagname/value map
+}

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/tagext/TagExtraInfo.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/tagext/TagExtraInfo.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/tagext/TagExtraInfo.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,143 @@
+/*
+* Copyright 2004 The Apache Software Foundation
+*
+* Licensed 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.jsp.tagext;
+
+/**
+ * Optional class provided by the tag library author to describe additional
+ * translation-time information not described in the TLD.
+ * The TagExtraInfo class is mentioned in the Tag Library Descriptor file (TLD).
+ *
+ * <p>
+ * This class can be used:
+ * <ul>
+ * <li> to indicate that the tag defines scripting variables
+ * <li> to perform translation-time validation of the tag attributes.
+ * </ul>
+ *
+ * <p>
+ * It is the responsibility of the JSP translator that the initial value
+ * to be returned by calls to getTagInfo() corresponds to a TagInfo
+ * object for the tag being translated. If an explicit call to
+ * setTagInfo() is done, then the object passed will be returned in
+ * subsequent calls to getTagInfo().
+ * 
+ * <p>
+ * The only way to affect the value returned by getTagInfo()
+ * is through a setTagInfo() call, and thus, TagExtraInfo.setTagInfo() is
+ * to be called by the JSP translator, with a TagInfo object that
+ * corresponds to the tag being translated. The call should happen before
+ * any invocation on validate() and before any invocation on
+ * getVariableInfo().
+ *
+ * <p>
+ * <tt>NOTE:</tt> It is a (translation time) error for a tag definition
+ * in a TLD with one or more variable subelements to have an associated
+ * TagExtraInfo implementation that returns a VariableInfo array with
+ * one or more elements from a call to getVariableInfo().
+ */
+
+public abstract class TagExtraInfo {
+
+    /**
+     * Sole constructor. (For invocation by subclass constructors, 
+     * typically implicit.)
+     */
+    public TagExtraInfo() {
+    }
+    
+    /**
+     * information on scripting variables defined by the tag associated with
+     * this TagExtraInfo instance.
+     * Request-time attributes are indicated as such in the TagData parameter.
+     *
+     * @param data The TagData instance.
+     * @return An array of VariableInfo data, or null or a zero length array
+     *         if no scripting variables are to be defined.
+     */
+    public VariableInfo[] getVariableInfo(TagData data) {
+	return ZERO_VARIABLE_INFO;
+    }
+
+    /**
+     * Translation-time validation of the attributes. 
+     * Request-time attributes are indicated as such in the TagData parameter.
+     * Note that the preferred way to do validation is with the validate()
+     * method, since it can return more detailed information.
+     *
+     * @param data The TagData instance.
+     * @return Whether this tag instance is valid.
+     * @see TagExtraInfo#validate
+     */
+
+    public boolean isValid(TagData data) {
+	return true;
+    }
+
+    /**
+     * Translation-time validation of the attributes.
+     * Request-time attributes are indicated as such in the TagData parameter.
+     * Because of the higher quality validation messages possible, 
+     * this is the preferred way to do validation (although isValid() 
+     * still works).  
+     * 
+     * <p>JSP 2.0 and higher containers call validate() instead of isValid().
+     * The default implementation of this method is to call isValid().  If 
+     * isValid() returns false, a generic ValidationMessage[] is returned
+     * indicating isValid() returned false.</p>
+     *
+     * @param data The TagData instance.
+     * @return A null object, or zero length array if no errors, an 
+     *     array of ValidationMessages otherwise.
+     * @since 2.0
+     */
+    public ValidationMessage[] validate( TagData data ) {
+	ValidationMessage[] result = null;
+
+	if( !isValid( data ) ) {
+	    result = new ValidationMessage[] {
+		new ValidationMessage( data.getId(), "isValid() == false" ) };
+	}
+
+	return result;
+    }
+
+    /**
+     * Set the TagInfo for this class.
+     *
+     * @param tagInfo The TagInfo this instance is extending
+     */
+    public final void setTagInfo(TagInfo tagInfo) {
+	this.tagInfo = tagInfo;
+    }
+
+    /**
+     * Get the TagInfo for this class.
+     *
+     * @return the taginfo instance this instance is extending
+     */
+    public final TagInfo getTagInfo() {
+	return tagInfo;
+    }
+    
+    // private data
+    private TagInfo tagInfo;
+
+    // zero length VariableInfo array
+    private static final VariableInfo[] ZERO_VARIABLE_INFO = { };
+}
+

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/tagext/TagFileInfo.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/tagext/TagFileInfo.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/tagext/TagFileInfo.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,85 @@
+/*
+* Copyright 2004 The Apache Software Foundation
+*
+* Licensed 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.jsp.tagext;
+
+/**
+ * Tag information for a tag file in a Tag Library;
+ * This class is instantiated from the Tag Library Descriptor file (TLD)
+ * and is available only at translation time.
+ *
+ * @since 2.0
+ */
+public class TagFileInfo {
+
+    /**
+     * Constructor for TagFileInfo from data in the JSP 2.0 format for TLD.
+     * This class is to be instantiated only from the TagLibrary code
+     * under request from some JSP code that is parsing a
+     * TLD (Tag Library Descriptor).
+     *
+     * Note that, since TagLibibraryInfo reflects both TLD information
+     * and taglib directive information, a TagFileInfo instance is
+     * dependent on a taglib directive.  This is probably a
+     * design error, which may be fixed in the future.
+     *
+     * @param name The unique action name of this tag
+     * @param path Where to find the .tag file implementing this 
+     *     action, relative to the location of the TLD file.
+     * @param tagInfo The detailed information about this tag, as parsed
+     *     from the directives in the tag file.
+     */
+    public TagFileInfo( String name, String path, TagInfo tagInfo ) {
+        this.name = name;
+        this.path = path;
+        this.tagInfo = tagInfo;
+    }
+
+    /**
+     * The unique action name of this tag.
+     *
+     * @return The (short) name of the tag.
+     */
+    public String getName() {
+        return name;
+    }
+
+    /**
+     * Where to find the .tag file implementing this action.
+     *
+     * @return The path of the tag file, relative to the TLD, or "." if 
+     *     the tag file was defined in an implicit tag file.
+     */
+    public String getPath() {
+        return path;
+    }
+
+    /**
+     * Returns information about this tag, parsed from the directives 
+     * in the tag file.
+     *
+     * @return a TagInfo object containing information about this tag
+     */
+    public TagInfo getTagInfo() {
+        return tagInfo;
+    }
+
+    // private fields for 2.0 info
+    private String name;
+    private String path;
+    private TagInfo tagInfo;
+}

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/tagext/TagInfo.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/tagext/TagInfo.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/tagext/TagInfo.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,446 @@
+/*
+* Copyright 2004 The Apache Software Foundation
+*
+* Licensed 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.jsp.tagext;
+
+/**
+ * Tag information for a tag in a Tag Library;
+ * This class is instantiated from the Tag Library Descriptor file (TLD)
+ * and is available only at translation time.
+ *
+ * 
+*/
+
+public class TagInfo {
+
+    /**
+     * Static constant for getBodyContent() when it is JSP.
+     */
+
+    public static final String BODY_CONTENT_JSP = "JSP";
+
+    /**
+     * Static constant for getBodyContent() when it is Tag dependent.
+     */
+
+    public static final String BODY_CONTENT_TAG_DEPENDENT = "TAGDEPENDENT";
+
+
+    /**
+     * Static constant for getBodyContent() when it is empty.
+     */
+
+    public static final String BODY_CONTENT_EMPTY = "EMPTY";
+    
+    /**
+     * Static constant for getBodyContent() when it is scriptless.
+     * 
+     * @since 2.0
+     */ 
+    public static final String BODY_CONTENT_SCRIPTLESS = "SCRIPTLESS";
+
+    /**
+     * Constructor for TagInfo from data in the JSP 1.1 format for TLD.
+     * This class is to be instantiated only from the TagLibrary code
+     * under request from some JSP code that is parsing a
+     * TLD (Tag Library Descriptor).
+     *
+     * Note that, since TagLibibraryInfo reflects both TLD information
+     * and taglib directive information, a TagInfo instance is
+     * dependent on a taglib directive.  This is probably a
+     * design error, which may be fixed in the future.
+     *
+     * @param tagName The name of this tag
+     * @param tagClassName The name of the tag handler class
+     * @param bodycontent Information on the body content of these tags
+     * @param infoString The (optional) string information for this tag
+     * @param taglib The instance of the tag library that contains us.
+     * @param tagExtraInfo The instance providing extra Tag info.  May be null
+     * @param attributeInfo An array of AttributeInfo data from descriptor.
+     * May be null;
+     *
+     */
+    public TagInfo(String tagName,
+	    String tagClassName,
+	    String bodycontent,
+	    String infoString,
+	    TagLibraryInfo taglib,
+	    TagExtraInfo tagExtraInfo,
+	    TagAttributeInfo[] attributeInfo) {
+	this.tagName       = tagName;
+	this.tagClassName  = tagClassName;
+	this.bodyContent   = bodycontent;
+	this.infoString    = infoString;
+	this.tagLibrary    = taglib;
+	this.tagExtraInfo  = tagExtraInfo;
+	this.attributeInfo = attributeInfo;
+
+	if (tagExtraInfo != null)
+            tagExtraInfo.setTagInfo(this);
+    }
+			 
+    /**
+     * Constructor for TagInfo from data in the JSP 1.2 format for TLD.
+     * This class is to be instantiated only from the TagLibrary code
+     * under request from some JSP code that is parsing a
+     * TLD (Tag Library Descriptor).
+     *
+     * Note that, since TagLibibraryInfo reflects both TLD information
+     * and taglib directive information, a TagInfo instance is
+     * dependent on a taglib directive.  This is probably a
+     * design error, which may be fixed in the future.
+     *
+     * @param tagName The name of this tag
+     * @param tagClassName The name of the tag handler class
+     * @param bodycontent Information on the body content of these tags
+     * @param infoString The (optional) string information for this tag
+     * @param taglib The instance of the tag library that contains us.
+     * @param tagExtraInfo The instance providing extra Tag info.  May be null
+     * @param attributeInfo An array of AttributeInfo data from descriptor.
+     * May be null;
+     * @param displayName A short name to be displayed by tools
+     * @param smallIcon Path to a small icon to be displayed by tools
+     * @param largeIcon Path to a large icon to be displayed by tools
+     * @param tvi An array of a TagVariableInfo (or null)
+     */
+    public TagInfo(String tagName,
+	    String tagClassName,
+	    String bodycontent,
+	    String infoString,
+	    TagLibraryInfo taglib,
+	    TagExtraInfo tagExtraInfo,
+	    TagAttributeInfo[] attributeInfo,
+	    String displayName,
+	    String smallIcon,
+	    String largeIcon,
+	    TagVariableInfo[] tvi) {
+	this.tagName       = tagName;
+	this.tagClassName  = tagClassName;
+	this.bodyContent   = bodycontent;
+	this.infoString    = infoString;
+	this.tagLibrary    = taglib;
+	this.tagExtraInfo  = tagExtraInfo;
+	this.attributeInfo = attributeInfo;
+	this.displayName = displayName;
+	this.smallIcon = smallIcon;
+	this.largeIcon = largeIcon;
+	this.tagVariableInfo = tvi;
+
+	if (tagExtraInfo != null)
+            tagExtraInfo.setTagInfo(this);
+    }
+			 
+    /**
+     * Constructor for TagInfo from data in the JSP 2.0 format for TLD.
+     * This class is to be instantiated only from the TagLibrary code
+     * under request from some JSP code that is parsing a
+     * TLD (Tag Library Descriptor).
+     *
+     * Note that, since TagLibibraryInfo reflects both TLD information
+     * and taglib directive information, a TagInfo instance is
+     * dependent on a taglib directive.  This is probably a
+     * design error, which may be fixed in the future.
+     *
+     * @param tagName The name of this tag
+     * @param tagClassName The name of the tag handler class
+     * @param bodycontent Information on the body content of these tags
+     * @param infoString The (optional) string information for this tag
+     * @param taglib The instance of the tag library that contains us.
+     * @param tagExtraInfo The instance providing extra Tag info.  May be null
+     * @param attributeInfo An array of AttributeInfo data from descriptor.
+     * May be null;
+     * @param displayName A short name to be displayed by tools
+     * @param smallIcon Path to a small icon to be displayed by tools
+     * @param largeIcon Path to a large icon to be displayed by tools
+     * @param tvi An array of a TagVariableInfo (or null)
+     * @param dynamicAttributes True if supports dynamic attributes
+     *
+     * @since 2.0
+     */
+    public TagInfo(String tagName,
+            String tagClassName,
+            String bodycontent,
+            String infoString,
+            TagLibraryInfo taglib,
+            TagExtraInfo tagExtraInfo,
+            TagAttributeInfo[] attributeInfo,
+            String displayName,
+            String smallIcon,
+            String largeIcon,
+            TagVariableInfo[] tvi,
+            boolean dynamicAttributes) {
+        this.tagName       = tagName;
+        this.tagClassName  = tagClassName;
+        this.bodyContent   = bodycontent;
+        this.infoString    = infoString;
+        this.tagLibrary    = taglib;
+        this.tagExtraInfo  = tagExtraInfo;
+        this.attributeInfo = attributeInfo;
+        this.displayName = displayName;
+        this.smallIcon = smallIcon;
+        this.largeIcon = largeIcon;
+        this.tagVariableInfo = tvi;
+        this.dynamicAttributes = dynamicAttributes;
+
+        if (tagExtraInfo != null)
+            tagExtraInfo.setTagInfo(this);
+    }
+
+    /**
+     * The name of the Tag.
+     *
+     * @return The (short) name of the tag.
+     */
+
+    public String getTagName() {
+	return tagName;
+    }
+
+    /**
+     * Attribute information (in the TLD) on this tag.
+     * The return is an array describing the attributes of this tag, as
+     * indicated in the TLD.
+     *
+     * @return The array of TagAttributeInfo for this tag, or a
+     *         zero-length array if the tag has no attributes.
+     */
+
+   public TagAttributeInfo[] getAttributes() {
+       return attributeInfo;
+   }
+
+    /**
+     * Information on the scripting objects created by this tag at runtime.
+     * This is a convenience method on the associated TagExtraInfo class.
+     *
+     * @param data TagData describing this action.
+     * @return if a TagExtraInfo object is associated with this TagInfo, the
+     *     result of getTagExtraInfo().getVariableInfo( data ), otherwise
+     *     null.
+     */
+   public VariableInfo[] getVariableInfo(TagData data) {
+       VariableInfo[] result = null;
+       TagExtraInfo tei = getTagExtraInfo();
+       if (tei != null) {
+	   result = tei.getVariableInfo( data );
+       }
+       return result;
+   }
+
+    /**
+     * Translation-time validation of the attributes. 
+     * This is a convenience method on the associated TagExtraInfo class.
+     *
+     * @param data The translation-time TagData instance.
+     * @return Whether the data is valid.
+     */
+    public boolean isValid(TagData data) {
+        TagExtraInfo tei = getTagExtraInfo();
+        if (tei == null) {
+	    return true;
+        }
+        return tei.isValid(data);
+    }
+
+    /**
+     * Translation-time validation of the attributes.
+     * This is a convenience method on the associated TagExtraInfo class.
+     *
+     * @param data The translation-time TagData instance.
+     * @return A null object, or zero length array if no errors, an
+     *     array of ValidationMessages otherwise.
+     * @since 2.0
+     */
+    public ValidationMessage[] validate( TagData data ) {
+	TagExtraInfo tei = getTagExtraInfo();
+	if( tei == null ) {
+	    return null;
+	}
+	return tei.validate( data );
+    }
+
+    /**
+     * Set the instance for extra tag information.
+     * 
+     * @param tei the TagExtraInfo instance
+     */
+    public void setTagExtraInfo(TagExtraInfo tei) {
+	tagExtraInfo = tei;
+    }
+
+
+    /**
+     * The instance (if any) for extra tag information.
+     * 
+     * @return The TagExtraInfo instance, if any.
+     */
+    public TagExtraInfo getTagExtraInfo() {
+	return tagExtraInfo;
+    }
+
+
+    /**
+     * Name of the class that provides the handler for this tag.
+     *
+     * @return The name of the tag handler class.
+     */
+    
+    public String getTagClassName() {
+	return tagClassName;
+    }
+
+
+    /**
+     * The bodycontent information for this tag.
+     * If the bodycontent is not defined for this
+     * tag, the default of JSP will be returned.
+     *
+     * @return the body content string.
+     */
+
+    public String getBodyContent() {
+	return bodyContent;
+    }
+
+
+    /**
+     * The information string for the tag.
+     *
+     * @return the info string, or null if 
+     *         not defined
+     */
+
+    public String getInfoString() {
+	return infoString;
+    }
+
+
+    /**
+     * Set the TagLibraryInfo property.
+     *
+     * Note that a TagLibraryInfo element is dependent
+     * not just on the TLD information but also on the
+     * specific taglib instance used.  This means that
+     * a fair amount of work needs to be done to construct
+     * and initialize TagLib objects.
+     *
+     * If used carefully, this setter can be used to avoid having to
+     * create new TagInfo elements for each taglib directive.
+     *
+     * @param tl the TagLibraryInfo to assign
+     */
+
+    public void setTagLibrary(TagLibraryInfo tl) {
+	tagLibrary = tl;
+    }
+
+    /**
+     * The instance of TabLibraryInfo we belong to.
+     *
+     * @return the tag library instance we belong to
+     */
+
+    public TagLibraryInfo getTagLibrary() {
+	return tagLibrary;
+    }
+
+
+    // ============== JSP 2.0 TLD Information ========
+
+
+    /**
+     * Get the displayName.
+     *
+     * @return A short name to be displayed by tools,
+     *         or null if not defined
+     */
+
+    public String getDisplayName() {
+	return displayName;
+    }
+
+    /**
+     * Get the path to the small icon.
+     *
+     * @return Path to a small icon to be displayed by tools,
+     *         or null if not defined
+     */
+
+    public String getSmallIcon() {
+	return smallIcon;
+    }
+
+    /**
+     * Get the path to the large icon.
+     *
+     * @return Path to a large icon to be displayed by tools,
+     *         or null if not defined
+     */
+
+    public String getLargeIcon() {
+	return largeIcon;
+    }
+
+    /**
+     * Get TagVariableInfo objects associated with this TagInfo.
+     *
+     * @return Array of TagVariableInfo objects corresponding to
+     *         variables declared by this tag, or a zero length
+     *         array if no variables have been declared
+     */
+
+    public TagVariableInfo[] getTagVariableInfos() {
+	return tagVariableInfo;
+    }
+
+
+    // ============== JSP 2.0 TLD Information ========
+
+    /**
+     * Get dynamicAttributes associated with this TagInfo.
+     *
+     * @return True if tag handler supports dynamic attributes
+     * @since 2.0
+     */
+    public boolean hasDynamicAttributes() {
+        return dynamicAttributes;
+    }
+
+    /*
+     * private fields for 1.1 info
+     */
+    private String             tagName; // the name of the tag
+    private String             tagClassName;
+    private String             bodyContent;
+    private String             infoString;
+    private TagLibraryInfo     tagLibrary;
+    private TagExtraInfo       tagExtraInfo; // instance of TagExtraInfo
+    private TagAttributeInfo[] attributeInfo;
+
+    /*
+     * private fields for 1.2 info
+     */
+    private String             displayName;
+    private String             smallIcon;
+    private String             largeIcon;
+    private TagVariableInfo[]  tagVariableInfo;
+
+    /*
+     * Additional private fields for 2.0 info
+     */
+    private boolean dynamicAttributes;
+}

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/tagext/TagLibraryInfo.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/tagext/TagLibraryInfo.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/tagext/TagLibraryInfo.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,286 @@
+/*
+* Copyright 2004 The Apache Software Foundation
+*
+* Licensed 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.jsp.tagext;
+
+import javax.servlet.jsp.tagext.TagInfo;
+import javax.servlet.jsp.tagext.TagFileInfo;
+
+/**
+ * Translation-time information associated with a taglib directive, and its
+ * underlying TLD file.
+ *
+ * Most of the information is directly from the TLD, except for
+ * the prefix and the uri values used in the taglib directive
+ *
+ *
+ */
+
+abstract public class TagLibraryInfo {
+
+    /**
+     * Constructor.
+     *
+     * This will invoke the constructors for TagInfo, and TagAttributeInfo
+     * after parsing the TLD file.
+     *
+     * @param prefix the prefix actually used by the taglib directive
+     * @param uri the URI actually used by the taglib directive
+     */
+    protected TagLibraryInfo(String prefix, String uri) {
+	this.prefix = prefix;
+	this.uri    = uri;
+    }
+
+    // ==== methods accessing taglib information =======
+
+    /**
+     * The value of the uri attribute from the taglib directive for 
+     * this library.
+     *
+     * @return the value of the uri attribute
+     */
+   
+    public String getURI() {
+        return uri;
+    }
+
+    /**
+     * The prefix assigned to this taglib from the taglib directive
+     *
+     * @return the prefix assigned to this taglib from the taglib directive
+     */
+
+    public String getPrefixString() {
+	return prefix;
+    }
+
+    // ==== methods using the TLD data =======
+
+    /**
+     * The preferred short name (prefix) as indicated in the TLD.
+     * This may be used by authoring tools as the preferred prefix
+     * to use when creating an taglib directive for this library.
+     *
+     * @return the preferred short name for the library
+     */
+    public String getShortName() {
+        return shortname;
+    }
+
+    /**
+     * The "reliable" URN indicated in the TLD (the uri element).
+     * This may be used by authoring tools as a global identifier
+     * to use when creating a taglib directive for this library.
+     *
+     * @return a reliable URN to a TLD like this
+     */
+    public String getReliableURN() {
+        return urn;
+    }
+
+
+    /**
+     * Information (documentation) for this TLD.
+     *
+     * @return the info string for this tag lib
+     */
+   
+    public String getInfoString() {
+        return info;
+    }
+
+
+    /**
+     * A string describing the required version of the JSP container.
+     * 
+     * @return the (minimal) required version of the JSP container.
+     * @see javax.servlet.jsp.JspEngineInfo
+     */
+   
+    public String getRequiredVersion() {
+        return jspversion;
+    }
+
+
+    /**
+     * An array describing the tags that are defined in this tag library.
+     *
+     * @return the TagInfo objects corresponding to the tags defined by this
+     *         tag library, or a zero length array if this tag library
+     *         defines no tags
+     */
+    public TagInfo[] getTags() {
+        return tags;
+    }
+
+    /**
+     * An array describing the tag files that are defined in this tag library.
+     *
+     * @return the TagFileInfo objects corresponding to the tag files defined
+     *         by this tag library, or a zero length array if this
+     *         tag library defines no tags files
+     * @since 2.0
+     */
+    public TagFileInfo[] getTagFiles() {
+        return tagFiles;
+    }
+
+
+    /**
+     * Get the TagInfo for a given tag name, looking through all the
+     * tags in this tag library.
+     *
+     * @param shortname The short name (no prefix) of the tag
+     * @return the TagInfo for the tag with the specified short name, or
+     *         null if no such tag is found
+     */
+
+    public TagInfo getTag(String shortname) {
+        TagInfo tags[] = getTags();
+
+        if (tags == null || tags.length == 0) {
+            return null;
+        }
+
+        for (int i=0; i < tags.length; i++) {
+            if (tags[i].getTagName().equals(shortname)) {
+                return tags[i];
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Get the TagFileInfo for a given tag name, looking through all the
+     * tag files in this tag library.
+     *
+     * @param shortname The short name (no prefix) of the tag
+     * @return the TagFileInfo for the specified Tag file, or null
+     *         if no Tag file is found
+     * @since 2.0
+     */
+    public TagFileInfo getTagFile(String shortname) {
+        TagFileInfo tagFiles[] = getTagFiles();
+
+        if (tagFiles == null || tagFiles.length == 0) {
+            return null;
+        }
+
+        for (int i=0; i < tagFiles.length; i++) {
+            if (tagFiles[i].getName().equals(shortname)) {
+                return tagFiles[i];
+            }
+        }
+        return null;
+    }
+
+    /**
+     * An array describing the functions that are defined in this tag library.
+     *
+     * @return the functions defined in this tag library, or a zero
+     *         length array if the tag library defines no functions.
+     * @since 2.0
+     */
+    public FunctionInfo[] getFunctions() {
+        return functions;
+    }
+
+
+    /**
+     * Get the FunctionInfo for a given function name, looking through all the
+     * functions in this tag library.
+     *
+     * @param name The name (no prefix) of the function
+     * @return the FunctionInfo for the function with the given name, or null
+     *         if no such function exists
+     * @since 2.0
+     */
+    public FunctionInfo getFunction(String name) {
+
+        if (functions == null || functions.length == 0) {
+            System.err.println("No functions");
+            return null;
+        }
+
+        for (int i=0; i < functions.length; i++) {
+            if (functions[i].getName().equals(name)) {
+                return functions[i];
+            }
+        }
+        return null;
+    }
+
+
+    // Protected fields
+
+    /**
+     * The prefix assigned to this taglib from the taglib directive.
+     */
+    protected String        prefix;
+    
+    /**
+     * The value of the uri attribute from the taglib directive for 
+     * this library.
+     */
+    protected String        uri;
+    
+    /**
+     * An array describing the tags that are defined in this tag library.
+     */
+    protected TagInfo[]     tags;
+    
+    /**
+     * An array describing the tag files that are defined in this tag library.
+     *
+     * @since 2.0
+     */
+    protected TagFileInfo[] tagFiles;
+    
+    /**
+     * An array describing the functions that are defined in this tag library.
+     *
+     * @since 2.0
+     */
+    protected FunctionInfo[] functions;
+
+    // Tag Library Data
+    
+    /**
+     * The version of the tag library.
+     */
+    protected String tlibversion; // required
+    
+    /**
+     * The version of the JSP specification this tag library is written to.
+     */
+    protected String jspversion;  // required
+    
+    /**
+     * The preferred short name (prefix) as indicated in the TLD.
+     */
+    protected String shortname;   // required
+    
+    /**
+     * The "reliable" URN indicated in the TLD.
+     */
+    protected String urn;         // required
+    
+    /**
+     * Information (documentation) for this TLD.
+     */
+    protected String info;        // optional
+}

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/tagext/TagLibraryValidator.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/tagext/TagLibraryValidator.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/tagext/TagLibraryValidator.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,143 @@
+/*
+* Copyright 2004 The Apache Software Foundation
+*
+* Licensed 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.jsp.tagext;
+
+import java.util.Map;
+
+/**
+ * Translation-time validator class for a JSP page. 
+ * A validator operates on the XML view associated with the JSP page.
+ *
+ * <p>
+ * The TLD file associates a TagLibraryValidator class and some init
+ * arguments with a tag library.
+ *
+ * <p>
+ * The JSP container is reponsible for locating an appropriate
+ * instance of the appropriate subclass by
+ *
+ * <ul>
+ * <li> new a fresh instance, or reuse an available one
+ * <li> invoke the setInitParams(Map) method on the instance
+ * </ul>
+ *
+ * once initialized, the validate(String, String, PageData) method will
+ * be invoked, where the first two arguments are the prefix
+ * and uri for this tag library in the XML View.  The prefix is intended
+ * to make it easier to produce an error message.  However, it is not
+ * always accurate.  In the case where a single URI is mapped to more 
+ * than one prefix in the XML view, the prefix of the first URI is provided.
+ * Therefore, to provide high quality error messages in cases where the 
+ * tag elements themselves are checked, the prefix parameter should be 
+ * ignored and the actual prefix of the element should be used instead.  
+ * TagLibraryValidators should always use the uri to identify elements 
+ * as beloning to the tag library, not the prefix.
+ *
+ * <p>
+ * A TagLibraryValidator instance
+ * may create auxiliary objects internally to perform
+ * the validation (e.g. an XSchema validator) and may reuse it for all
+ * the pages in a given translation run.
+ *
+ * <p>
+ * The JSP container is not guaranteed to serialize invocations of
+ * validate() method, and TagLibraryValidators should perform any
+ * synchronization they may require.
+ *
+ * <p>
+ * As of JSP 2.0, a JSP container must provide a jsp:id attribute to
+ * provide higher quality validation errors.
+ * The container will track the JSP pages
+ * as passed to the container, and will assign to each element
+ * a unique "id", which is passed as the value of the jsp:id
+ * attribute.  Each XML element in the XML view available will
+ * be extended with this attribute.  The TagLibraryValidator
+ * can then use the attribute in one or more ValidationMessage
+ * objects.  The container then, in turn, can use these
+ * values to provide more precise information on the location
+ * of an error.
+ *
+ * <p>
+ * The actual prefix of the <code>id</code> attribute may or may not be 
+ * <code>jsp</code> but it will always map to the namespace
+ * <code>http://java.sun.com/JSP/Page</code>.  A TagLibraryValidator
+ * implementation must rely on the uri, not the prefix, of the <code>id</code>
+ * attribute.
+ */
+
+abstract public class TagLibraryValidator {
+
+    /**
+     * Sole constructor. (For invocation by subclass constructors, 
+     * typically implicit.)
+     */
+    public TagLibraryValidator() {
+    }
+    
+    /**
+     * Set the init data in the TLD for this validator.
+     * Parameter names are keys, and parameter values are the values.
+     *
+     * @param map A Map describing the init parameters
+     */
+    public void setInitParameters(Map map) {
+	initParameters = map;
+    }
+
+
+    /**
+     * Get the init parameters data as an immutable Map.
+     * Parameter names are keys, and parameter values are the values.
+     *
+     * @return The init parameters as an immutable map.
+     */
+    public Map getInitParameters() {
+	return initParameters;
+    }
+
+    /**
+     * Validate a JSP page.
+     * This will get invoked once per unique tag library URI in the
+     * XML view.  This method will return null if the page is valid; otherwise
+     * the method should return an array of ValidationMessage objects.
+     * An array of length zero is also interpreted as no errors.
+     *
+     * @param prefix the first prefix with which the tag library is 
+     *     associated, in the XML view.  Note that some tags may use 
+     *     a different prefix if the namespace is redefined.
+     * @param uri the tag library's unique identifier
+     * @param page the JspData page object
+     * @return A null object, or zero length array if no errors, an array
+     * of ValidationMessages otherwise.
+     */
+    public ValidationMessage[] validate(String prefix, String uri, 
+        PageData page) 
+    {
+	return null;
+    }
+
+    /**
+     * Release any data kept by this instance for validation purposes.
+     */
+    public void release() {
+	initParameters = null;
+    }
+
+    // Private data
+    private Map initParameters;
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/tagext/TagSupport.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/tagext/TagSupport.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/tagext/TagSupport.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,293 @@
+/*
+* Copyright 2004 The Apache Software Foundation
+*
+* Licensed 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.jsp.tagext;
+
+import java.io.Serializable;
+import java.util.Enumeration;
+import java.util.Hashtable;
+
+import javax.servlet.jsp.JspException;
+import javax.servlet.jsp.PageContext;
+
+/**
+ * A base class for defining new tag handlers implementing Tag.
+ *
+ * <p> The TagSupport class is a utility class intended to be used as
+ * the base class for new tag handlers.  The TagSupport class
+ * implements the Tag and IterationTag interfaces and adds additional
+ * convenience methods including getter methods for the properties in
+ * Tag.  TagSupport has one static method that is included to
+ * facilitate coordination among cooperating tags.
+ *
+ * <p> Many tag handlers will extend TagSupport and only redefine a
+ * few methods. 
+ */
+
+public class TagSupport implements IterationTag, Serializable {
+
+    /**
+     * Find the instance of a given class type that is closest to a given
+     * instance.
+     * This method uses the getParent method from the Tag
+     * interface.
+     * This method is used for coordination among cooperating tags.
+     *
+     * <p>
+     * The current version of the specification only provides one formal
+     * way of indicating the observable type of a tag handler: its
+     * tag handler implementation class, described in the tag-class
+     * subelement of the tag element.  This is extended in an
+     * informal manner by allowing the tag library author to
+     * indicate in the description subelement an observable type.
+     * The type should be a subtype of the tag handler implementation
+     * class or void.
+     * This addititional constraint can be exploited by a
+     * specialized container that knows about that specific tag library,
+     * as in the case of the JSP standard tag library.
+     *
+     * <p>
+     * When a tag library author provides information on the
+     * observable type of a tag handler, client programmatic code
+     * should adhere to that constraint.  Specifically, the Class
+     * passed to findAncestorWithClass should be a subtype of the
+     * observable type.
+     * 
+     *
+     * @param from The instance from where to start looking.
+     * @param klass The subclass of Tag or interface to be matched
+     * @return the nearest ancestor that implements the interface
+     * or is an instance of the class specified
+     */
+
+    public static final Tag findAncestorWithClass(Tag from, Class klass) {
+	boolean isInterface = false;
+
+	if (from == null ||
+	    klass == null ||
+	    (!Tag.class.isAssignableFrom(klass) &&
+	     !(isInterface = klass.isInterface()))) {
+	    return null;
+	}
+
+	for (;;) {
+	    Tag tag = from.getParent();
+
+	    if (tag == null) {
+		return null;
+	    }
+
+	    if ((isInterface && klass.isInstance(tag)) ||
+	        klass.isAssignableFrom(tag.getClass()))
+		return tag;
+	    else
+		from = tag;
+	}
+    }
+
+    /**
+     * Default constructor, all subclasses are required to define only
+     * a public constructor with the same signature, and to call the
+     * superclass constructor.
+     *
+     * This constructor is called by the code generated by the JSP
+     * translator.
+     */
+
+    public TagSupport() { }
+
+    /**
+     * Default processing of the start tag, returning SKIP_BODY.
+     *
+     * @return SKIP_BODY
+     * @throws JspException if an error occurs while processing this tag
+     *
+     * @see Tag#doStartTag()
+     */
+ 
+    public int doStartTag() throws JspException {
+        return SKIP_BODY;
+    }
+
+    /**
+     * Default processing of the end tag returning EVAL_PAGE.
+     *
+     * @return EVAL_PAGE
+     * @throws JspException if an error occurs while processing this tag
+     *
+     * @see Tag#doEndTag()
+     */
+
+    public int doEndTag() throws JspException {
+	return EVAL_PAGE;
+    }
+
+
+    /**
+     * Default processing for a body.
+     *
+     * @return SKIP_BODY
+     * @throws JspException if an error occurs while processing this tag
+     *
+     * @see IterationTag#doAfterBody()
+     */
+    
+    public int doAfterBody() throws JspException {
+	return SKIP_BODY;
+    }
+
+    // Actions related to body evaluation
+
+
+    /**
+     * Release state.
+     *
+     * @see Tag#release()
+     */
+
+    public void release() {
+	parent = null;
+	id = null;
+	if( values != null ) {
+	    values.clear();
+	}
+	values = null;
+    }
+
+    /**
+     * Set the nesting tag of this tag.
+     *
+     * @param t The parent Tag.
+     * @see Tag#setParent(Tag)
+     */
+
+    public void setParent(Tag t) {
+	parent = t;
+    }
+
+    /**
+     * The Tag instance most closely enclosing this tag instance.
+     * @see Tag#getParent()
+     *
+     * @return the parent tag instance or null
+     */
+
+    public Tag getParent() {
+	return parent;
+    }
+
+    /**
+     * Set the id attribute for this tag.
+     *
+     * @param id The String for the id.
+     */
+
+    public void setId(String id) {
+	this.id = id;
+    }
+
+    /**
+     * The value of the id attribute of this tag; or null.
+     *
+     * @return the value of the id attribute, or null
+     */
+    
+    public String getId() {
+	return id;
+    }
+
+    /**
+     * Set the page context.
+     *
+     * @param pageContext The PageContext.
+     * @see Tag#setPageContext
+     */
+
+    public void setPageContext(PageContext pageContext) {
+	this.pageContext = pageContext;
+    }
+
+    /**
+     * Associate a value with a String key.
+     *
+     * @param k The key String.
+     * @param o The value to associate.
+     */
+
+    public void setValue(String k, Object o) {
+	if (values == null) {
+	    values = new Hashtable();
+	}
+	values.put(k, o);
+    }
+
+    /**
+     * Get a the value associated with a key.
+     *
+     * @param k The string key.
+     * @return The value associated with the key, or null.
+     */
+
+    public Object getValue(String k) {
+	if (values == null) {
+	    return null;
+	} else {
+	    return values.get(k);
+	}
+    }
+
+    /**
+     * Remove a value associated with a key.
+     *
+     * @param k The string key.
+     */
+
+    public void removeValue(String k) {
+	if (values != null) {
+	    values.remove(k);
+	}
+    }
+
+    /**
+     * Enumerate the keys for the values kept by this tag handler.
+     *
+     * @return An enumeration of all the keys for the values set,
+     *     or null or an empty Enumeration if no values have been set.
+     */
+
+    public Enumeration getValues() {
+	if (values == null) {
+	    return null;
+	}
+	return values.keys();
+    }
+
+    // private fields
+
+    private   Tag         parent;
+    private   Hashtable   values;
+    /**
+     * The value of the id attribute of this tag; or null.
+     */
+    protected String	  id;
+
+    // protected fields
+
+    /**
+     * The PageContext.
+     */
+    protected PageContext pageContext;
+}
+

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/tagext/TagVariableInfo.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/tagext/TagVariableInfo.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/tagext/TagVariableInfo.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,120 @@
+/*
+* Copyright 2004 The Apache Software Foundation
+*
+* Licensed 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.jsp.tagext;
+
+/**
+ * Variable information for a tag in a Tag Library;
+ * This class is instantiated from the Tag Library Descriptor file (TLD)
+ * and is available only at translation time.
+ *
+ * This object should be immutable.
+ *
+ * This information is only available in JSP 1.2 format TLDs or above.
+ */
+
+public class TagVariableInfo {
+
+    /**
+     * Constructor for TagVariableInfo.
+     *
+     * @param nameGiven value of &lt;name-given&gt;
+     * @param nameFromAttribute value of &lt;name-from-attribute&gt;
+     * @param className value of &lt;variable-class&gt;
+     * @param declare value of &lt;declare&gt;
+     * @param scope value of &lt;scope&gt;
+     */
+    public TagVariableInfo(
+	    String nameGiven,
+	    String nameFromAttribute,
+	    String className,
+	    boolean declare,
+	    int scope) {
+	this.nameGiven         = nameGiven;
+	this.nameFromAttribute = nameFromAttribute;
+	this.className         = className;
+	this.declare           = declare;
+	this.scope             = scope;
+    }
+
+    /**
+     * The body of the &lt;name-given&gt; element.
+     *
+     * @return The variable name as a constant
+     */
+
+    public String getNameGiven() {
+	return nameGiven;
+    }
+
+    /**
+     * The body of the &lt;name-from-attribute&gt; element.
+     * This is the name of an attribute whose (translation-time)
+     * value will give the name of the variable.  One of
+     * &lt;name-given&gt; or &lt;name-from-attribute&gt; is required.
+     *
+     * @return The attribute whose value defines the variable name
+     */
+
+    public String getNameFromAttribute() {
+	return nameFromAttribute;
+    }
+
+    /**
+     * The body of the &lt;variable-class&gt; element.  
+     *
+     * @return The name of the class of the variable or
+     *         'java.lang.String' if not defined in the TLD.
+     */
+
+    public String getClassName() {
+	return className;
+    }
+
+    /**
+     * The body of the &lt;declare&gt; element.
+     *
+     * @return Whether the variable is to be declared or not.
+     *         If not defined in the TLD, 'true' will be returned.
+     */
+
+    public boolean getDeclare() {
+	return declare;
+    }
+
+    /**
+     * The body of the &lt;scope&gt; element.
+     *
+     * @return The scope to give the variable.  NESTED
+     *         scope will be returned if not defined in 
+     *         the TLD.
+     */
+
+    public int getScope() {
+	return scope;
+    }
+
+
+    /*
+     * private fields
+     */
+    private String   nameGiven;         // <name-given>
+    private String   nameFromAttribute; // <name-from-attribute>
+    private String   className;         // <class>
+    private boolean  declare;           // <declare>
+    private int      scope;             // <scope>
+}

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/tagext/TryCatchFinally.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/tagext/TryCatchFinally.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/tagext/TryCatchFinally.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,98 @@
+/*
+* Copyright 2004 The Apache Software Foundation
+*
+* Licensed 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.jsp.tagext;
+
+
+
+/**
+ * The auxiliary interface of a Tag, IterationTag or BodyTag tag
+ * handler that wants additional hooks for managing resources.
+ *
+ * <p>This interface provides two new methods: doCatch(Throwable)
+ * and doFinally().  The prototypical invocation is as follows:
+ *
+ * <pre>
+ * h = get a Tag();  // get a tag handler, perhaps from pool
+ *
+ * h.setPageContext(pc);  // initialize as desired
+ * h.setParent(null);
+ * h.setFoo("foo");
+ * 
+ * // tag invocation protocol; see Tag.java
+ * try {
+ *   doStartTag()...
+ *   ....
+ *   doEndTag()...
+ * } catch (Throwable t) {
+ *   // react to exceptional condition
+ *   h.doCatch(t);
+ * } finally {
+ *   // restore data invariants and release per-invocation resources
+ *   h.doFinally();
+ * }
+ * 
+ * ... other invocations perhaps with some new setters
+ * ...
+ * h.release();  // release long-term resources
+ * </pre>
+ */
+
+public interface TryCatchFinally {
+
+    /**
+     * Invoked if a Throwable occurs while evaluating the BODY
+     * inside a tag or in any of the following methods:
+     * Tag.doStartTag(), Tag.doEndTag(),
+     * IterationTag.doAfterBody() and BodyTag.doInitBody().
+     *
+     * <p>This method is not invoked if the Throwable occurs during
+     * one of the setter methods.
+     *
+     * <p>This method may throw an exception (the same or a new one)
+     * that will be propagated further up the nest chain.  If an exception
+     * is thrown, doFinally() will be invoked.
+     *
+     * <p>This method is intended to be used to respond to an exceptional
+     * condition.
+     *
+     * @param t The throwable exception navigating through this tag.
+     * @throws Throwable if the exception is to be rethrown further up 
+     *     the nest chain.
+     */
+ 
+    void doCatch(Throwable t) throws Throwable;
+
+    /**
+     * Invoked in all cases after doEndTag() for any class implementing
+     * Tag, IterationTag or BodyTag.  This method is invoked even if
+     * an exception has occurred in the BODY of the tag,
+     * or in any of the following methods:
+     * Tag.doStartTag(), Tag.doEndTag(),
+     * IterationTag.doAfterBody() and BodyTag.doInitBody().
+     *
+     * <p>This method is not invoked if the Throwable occurs during
+     * one of the setter methods.
+     *
+     * <p>This method should not throw an Exception.
+     *
+     * <p>This method is intended to maintain per-invocation data
+     * integrity and resource management actions.
+     */
+
+    void doFinally();
+}

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/tagext/ValidationMessage.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/tagext/ValidationMessage.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/tagext/ValidationMessage.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,85 @@
+/*
+* Copyright 2004 The Apache Software Foundation
+*
+* Licensed 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.jsp.tagext;
+
+
+/**
+ * A validation message from either TagLibraryValidator or TagExtraInfo.
+ * <p>
+ * As of JSP 2.0, a JSP container must support a jsp:id attribute
+ * to provide higher quality validation errors.
+ * The container will track the JSP pages
+ * as passed to the container, and will assign to each element
+ * a unique "id", which is passed as the value of the jsp:id
+ * attribute.  Each XML element in the XML view available will
+ * be extended with this attribute.  The TagLibraryValidator
+ * can then use the attribute in one or more ValidationMessage
+ * objects.  The container then, in turn, can use these
+ * values to provide more precise information on the location
+ * of an error.
+ *  
+ * <p>
+ * The actual prefix of the <code>id</code> attribute may or may not be 
+ * <code>jsp</code> but it will always map to the namespace
+ * <code>http://java.sun.com/JSP/Page</code>.  A TagLibraryValidator
+ * implementation must rely on the uri, not the prefix, of the <code>id</code>
+ * attribute.
+ */
+
+public class ValidationMessage {
+
+    /**
+     * Create a ValidationMessage.  The message String should be
+     * non-null.  The value of id may be null, if the message
+     * is not specific to any XML element, or if no jsp:id
+     * attributes were passed on.  If non-null, the value of
+     * id must be the value of a jsp:id attribute for the PageData
+     * passed into the validate() method.
+     *
+     * @param id Either null, or the value of a jsp:id attribute.
+     * @param message A localized validation message.
+     */
+    public ValidationMessage(String id, String message) {
+	this.id = id;
+	this.message = message;
+    }
+
+
+    /**
+     * Get the jsp:id.
+     * Null means that there is no information available.
+     *
+     * @return The jsp:id information.
+     */
+    public String getId() {
+	return id;
+    }
+
+    /**
+     * Get the localized validation message.
+     *
+     * @return A validation message
+     */
+    public String getMessage(){
+	return message;
+    }
+
+    // Private data
+    private String id;
+    private String message;
+}

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/tagext/VariableInfo.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/tagext/VariableInfo.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/tagext/VariableInfo.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,283 @@
+/*
+* Copyright 2004 The Apache Software Foundation
+*
+* Licensed 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.jsp.tagext;
+
+/**
+ * Information on the scripting variables that are created/modified by
+ * a tag (at run-time). This information is provided by TagExtraInfo
+ * classes and it is used by the translation phase of JSP.
+ *
+ * <p>
+ * Scripting variables generated by a custom action have an associated 
+ * scope of either AT_BEGIN, NESTED, or AT_END.
+ *
+ * <p>
+ * The class name (VariableInfo.getClassName) in the returned objects
+ * is used to determine the types of the scripting variables.
+ * Note that because scripting variables are assigned their values
+ * from scoped attributes which cannot be of primitive types,
+ * &quot;boxed&quot; types such as <code>java.lang.Integer</code> must 
+ * be used instead of primitives.
+ *
+ * <p>
+ * The class name may be a Fully Qualified Class Name, or a short
+ * class name.
+ *
+ * <p>
+ * If a Fully Qualified Class Name is provided, it should refer to a
+ * class that should be in the CLASSPATH for the Web Application (see
+ * Servlet 2.4 specification - essentially it is WEB-INF/lib and
+ * WEB-INF/classes). Failure to be so will lead to a translation-time
+ * error.
+ *
+ * <p>
+ * If a short class name is given in the VariableInfo objects, then
+ * the class name must be that of a public class in the context of the
+ * import directives of the page where the custom action appears. 
+ * The class must also be in the CLASSPATH for the Web Application 
+ * (see Servlet 2.4 specification - essentially it is WEB-INF/lib and
+ * WEB-INF/classes). Failure to be so will lead to a translation-time
+ * error.
+ *
+ * <p><B>Usage Comments</B>
+ * <p>
+ * Frequently a fully qualified class name will refer to a class that
+ * is known to the tag library and thus, delivered in the same JAR
+ * file as the tag handlers. In most other remaining cases it will
+ * refer to a class that is in the platform on which the JSP processor
+ * is built (like J2EE). Using fully qualified class names in this
+ * manner makes the usage relatively resistant to configuration
+ * errors.
+ *
+ * <p>
+ * A short name is usually generated by the tag library based on some
+ * attributes passed through from the custom action user (the author),
+ * and it is thus less robust: for instance a missing import directive
+ * in the referring JSP page will lead to an invalid short name class
+ * and a translation error.
+ *
+ * <p><B>Synchronization Protocol</B>
+ *
+ * <p>
+ * The result of the invocation on getVariableInfo is an array of
+ * VariableInfo objects.  Each such object describes a scripting
+ * variable by providing its name, its type, whether the variable is
+ * new or not, and what its scope is.  Scope is best described through
+ * a picture:
+ *
+ * <p>
+ * <IMG src="doc-files/VariableInfo-1.gif"
+ *      alt="NESTED, AT_BEGIN and AT_END Variable Scopes"/>
+ *
+ *<p>
+ * The JSP 2.0 specification defines the interpretation of 3 values:
+ * 
+ * <ul>
+ * <li> NESTED, if the scripting variable is available between
+ * the start tag and the end tag of the action that defines it.
+ * <li>
+ * AT_BEGIN, if the scripting variable is available from the start tag
+ * of the action that defines it until the end of the scope.
+ * <li> AT_END, if the scripting variable is available after the end tag
+ * of the action that defines it until the end of the scope.
+ * </ul>
+ *
+ * The scope value for a variable implies what methods may affect its
+ * value and thus where synchronization is needed as illustrated by
+ * the table below.  <b>Note:</b> the synchronization of the variable(s)
+ * will occur <em>after</em> the respective method has been called.
+ *
+ * <blockquote>
+ * <table cellpadding="2" cellspacing="2" border="0" width="55%"
+ *        bgcolor="#999999" summary="Variable Synchronization Points">
+ * <tbody>
+ *   <tr align="center">
+ *     <td valign="top" colspan="6" bgcolor="#999999"><u><b>Variable Synchronization
+ *     Points</b></u><br>
+ *     </td>
+ *   </tr>
+ *   <tr>
+ *     <th valign="top" bgcolor="#c0c0c0">&nbsp;</th>
+ *     <th valign="top" bgcolor="#c0c0c0" align="center">doStartTag()</th>
+ *     <th valign="top" bgcolor="#c0c0c0" align="center">doInitBody()</th>
+ *     <th valign="top" bgcolor="#c0c0c0" align="center">doAfterBody()</th>
+ *     <th valign="top" bgcolor="#c0c0c0" align="center">doEndTag()</th>
+ *     <th valign="top" bgcolor="#c0c0c0" align="center">doTag()</th>
+ *   </tr>
+ *   <tr>
+ *     <td valign="top" bgcolor="#c0c0c0"><b>Tag<br>
+ *     </b></td>
+ *     <td valign="top" align="center" bgcolor="#ffffff">AT_BEGIN, NESTED<br>
+ *     </td>
+ *     <td valign="top" align="center" bgcolor="#ffffff"><br>
+ *     </td>
+ *     <td valign="top" align="center" bgcolor="#ffffff"><br>
+ *     </td>
+ *     <td valign="top" align="center" bgcolor="#ffffff">AT_BEGIN, AT_END<br>
+ *     </td>
+ *     <td valign="top" align="center" bgcolor="#ffffff"><br>
+ *     </td>
+ *   </tr>
+ *   <tr>
+ *     <td valign="top" bgcolor="#c0c0c0"><b>IterationTag<br>
+ *     </b></td>
+ *     <td valign="top" align="center" bgcolor="#ffffff">AT_BEGIN, NESTED<br>
+ *     </td>
+ *     <td valign="top" align="center" bgcolor="#ffffff"><br>
+ *     </td>
+ *     <td valign="top" align="center" bgcolor="#ffffff">AT_BEGIN, NESTED<br>
+ *     </td>
+ *     <td valign="top" align="center" bgcolor="#ffffff">AT_BEGIN, AT_END<br>
+ *     </td>
+ *     <td valign="top" align="center" bgcolor="#ffffff"><br>
+ *     </td>
+ *   </tr>
+ *   <tr>
+ *     <td valign="top" bgcolor="#c0c0c0"><b>BodyTag<br>
+ *     </b></td>
+ *     <td valign="top" align="center" bgcolor="#ffffff">AT_BEGIN, NESTED<sup>1</sup><br>
+ *     </td>
+ *     <td valign="top" align="center" bgcolor="#ffffff">AT_BEGIN, NESTED<sup>1</sup><br>
+ *     </td>
+ *     <td valign="top" align="center" bgcolor="#ffffff">AT_BEGIN, NESTED<br>
+ *     </td>
+ *     <td valign="top" align="center" bgcolor="#ffffff">AT_BEGIN, AT_END<br>
+ *     </td>
+ *     <td valign="top" align="center" bgcolor="#ffffff"><br>
+ *     </td>
+ *   </tr>
+ *   <tr>
+ *     <td valign="top" bgcolor="#c0c0c0"><b>SimpleTag<br>
+ *     </b></td>
+ *     <td valign="top" align="center" bgcolor="#ffffff"><br>
+ *     </td>
+ *     <td valign="top" align="center" bgcolor="#ffffff"><br>
+ *     </td>
+ *     <td valign="top" align="center" bgcolor="#ffffff"><br>
+ *     </td>
+ *     <td valign="top" align="center" bgcolor="#ffffff"><br>
+ *     </td>
+ *     <td valign="top" align="center" bgcolor="#ffffff">AT_BEGIN, AT_END<br>
+ *     </td>
+ *   </tr>
+ * </tbody>
+ * </table>
+ * <sup>1</sup> Called after <code>doStartTag()</code> if 
+ * <code>EVAL_BODY_INCLUDE</code> is returned, or after 
+ * <code>doInitBody()</code> otherwise.
+ * </blockquote>
+ *
+ * <p><B>Variable Information in the TLD</B>
+ * <p>
+ * Scripting variable information can also be encoded directly for most cases
+ * into the Tag Library Descriptor using the &lt;variable&gt; subelement of the
+ * &lt;tag&gt; element.  See the JSP specification.
+ */
+
+public class VariableInfo {
+
+    /**
+     * Scope information that scripting variable is visible only within the
+     * start/end tags.
+     */
+    public static final int NESTED = 0;
+
+    /**
+     * Scope information that scripting variable is visible after start tag.
+     */
+    public static final int AT_BEGIN = 1;
+
+    /**
+     * Scope information that scripting variable is visible after end tag.
+     */
+    public static final int AT_END = 2;
+
+
+    /**
+     * Constructor
+     * These objects can be created (at translation time) by the TagExtraInfo
+     * instances.
+     *
+     * @param varName The name of the scripting variable
+     * @param className The type of this variable
+     * @param declare If true, it is a new variable (in some languages this will
+     *     require a declaration)
+     * @param scope Indication on the lexical scope of the variable
+     */
+
+    public VariableInfo(String varName,
+			String className,
+			boolean declare,
+			int scope) {
+	this.varName = varName;
+	this.className = className;
+	this.declare = declare;
+	this.scope = scope;
+    }
+
+    // Accessor methods
+    
+    /**
+     * Returns the name of the scripting variable.
+     *
+     * @return the name of the scripting variable
+     */
+    public String getVarName() { 
+        return varName; 
+    }
+    
+    /**
+     * Returns the type of this variable.
+     *
+     * @return the type of this variable
+     */
+    public String getClassName() { 
+        return className; 
+    }
+    
+    /**
+     * Returns whether this is a new variable.
+     * If so, in some languages this will require a declaration.
+     *
+     * @return whether this is a new variable.
+     */
+    public boolean getDeclare() { 
+        return declare; 
+    }
+    
+    /**
+     * Returns the lexical scope of the variable.
+     * 
+     * @return the lexical scope of the variable, either AT_BEGIN, AT_END,
+     *    or NESTED.
+     * @see #AT_BEGIN
+     * @see #AT_END
+     * @see #NESTED
+     */
+    public int getScope() { 
+        return scope; 
+    }
+
+
+    // == private data
+    private String varName;
+    private String className;
+    private boolean declare;
+    private int scope;
+}
+

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/tagext/doc-files/BodyTagProtocol.gif
===================================================================
(Binary files differ)


Property changes on: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/tagext/doc-files/BodyTagProtocol.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/tagext/doc-files/IterationTagProtocol.gif
===================================================================
(Binary files differ)


Property changes on: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/tagext/doc-files/IterationTagProtocol.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/tagext/doc-files/TagProtocol.gif
===================================================================
(Binary files differ)


Property changes on: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/tagext/doc-files/TagProtocol.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/tagext/doc-files/VariableInfo-1.gif
===================================================================
(Binary files differ)


Property changes on: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/tagext/doc-files/VariableInfo-1.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/tagext/package.html
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/tagext/package.html	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr152/src/share/javax/servlet/jsp/tagext/package.html	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,85 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<!--
+  - The Apache Software License, Version 1.1
+  -
+  - Copyright (c) 1999 The Apache Software Foundation.  All rights 
+  - reserved.
+  -
+  - Redistribution and use in source and binary forms, with or without
+  - modification, are permitted provided that the following conditions
+  - are met:
+  -
+  - 1. Redistributions of source code must retain the above copyright
+  -    notice, this list of conditions and the following disclaimer. 
+  -
+  - 2. Redistributions in binary form must reproduce the above copyright
+  -    notice, this list of conditions and the following disclaimer in
+  -    the documentation and/or other materials provided with the
+  -    distribution.
+  -
+  - 3. The end-user documentation included with the redistribution, if
+  -    any, must include the following acknowlegement:  
+  -       "This product includes software developed by the 
+  -        Apache Software Foundation (http://www.apache.org/)."
+  -    Alternately, this acknowlegement may appear in the software itself,
+  -    if and wherever such third-party acknowlegements normally appear.
+  -
+  - 4. The names "The Jakarta Project", "Tomcat", and "Apache Software
+  -    Foundation" must not be used to endorse or promote products derived
+  -    from this software without prior written permission. For written 
+  -    permission, please contact apache at apache.org.
+  -
+  - 5. Products derived from this software may not be called "Apache"
+  -    nor may "Apache" appear in their names without prior written
+  -    permission of the Apache Group.
+  -
+  - THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+  - WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+  - OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+  - DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+  - ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+  - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+  - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+  - USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+  - ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+  - OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+  - OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+  - SUCH DAMAGE.
+  - ====================================================================
+  -
+  - This software consists of voluntary contributions made by many
+  - individuals on behalf of the Apache Software Foundation.  For more
+  - information on the Apache Software Foundation, please see
+  - <http://www.apache.org/>.
+  -
+  -->
+</head>
+<body bgcolor="white">
+
+Classes and interfaces for the definition of JavaServer Pages Tag Libraries.
+
+<p>
+The JavaServer Pages(tm) (JSP) 2.0 specification provides a portable
+mechanism for the description of tag libraries.
+<p>
+A JSP tag library contains
+<ul>
+<li>A Tag Library Descriptor</li>
+<li>A number of Tag Files or Tag handler classes defining 
+    request-time behavior</li>
+<li>Additional classes and resources used at runtime</li>
+<li>Possibly some additional classes to provide extra translation 
+    information</li>
+</ul>
+<p>
+The JSP 2.0 specification and the reference implementation both contain
+simple and moderately complex examples of actions defined using this
+mechanism.  These are available at JSP's web site, at
+<a href="http://java.sun.com/products/jsp">http://java.sun.com/products/jsp</a>.
+Some readers may want to consult those to get a quick feel for how
+the mechanisms work together.
+
+</body>
+</html>

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/BUILDING.txt
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/BUILDING.txt	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/BUILDING.txt	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,134 @@
+$Id: BUILDING.txt 266968 2002-08-13 16:20:53Z remm $
+
+
+               Building The Java Servlet and JSP API Classes
+               =============================================
+
+This subproject contains the source code for the implementation classes of the
+Java Servlet and JSP APIs (packages javax.servlet, javax.servlet.http,
+javax.servlet.jsp, and javax.servlet.jsp.tagext).  In order to build these
+sources successfully, you must do the following:
+
+
+(1) Download and Install the Ant Binary Distribution
+
+NOTE:  These instructions assume that you are using the Ant 1.3 release.
+Procedures for Ant 1.4 and later versions should be similar, but have not
+been tested.
+
+* Download a binary distribution of Ant 1.3 from:
+
+    http://jakarta.apache.org/builds/jakarta-ant/release/v1.3/bin/
+
+  On a Windows platform, you will need:
+    jakarta-ant-1.3-bin.zip
+    jakarta-ant-1.3-optional.jar
+
+  On a Unix platform, you will need:
+    jakarta-ant-1.3-bin.tar.gz
+    jakarta-ant-1.3-optional.jar
+
+* Unpack the binary distribution into a convenient location so that the
+  Ant release resides in its own directory (conventionally named
+  "jakarta-ant-1.3").  For the purposes of the remainder of this document,
+  the symbolic name "${ant.home}" is used to refer to the full pathname of
+  the release directory.
+
+* Copy the file "jakarta-ant-1.3-optional.jar", downloaded above, into
+  the directory "${ant.home}/lib".  This makes available several Ant
+  extension commands that are commonly required when building Jakarta
+  based projects.
+
+* Modify the PATH environment variable to include directory
+  "${ant.home}/bin" in its list.  This makes the "ant" command line script
+  available, which will be used to actually perform the build.
+
+
+(2) Download and Install the JAXP/1.1 Reference Implementation (OPTIONAL)
+
+NOTE:  Although this step is not required to build this particular subproject,
+it is commonly required to build other Jakarta projects.  Hence, the steps
+required are documented here.
+
+* Download a binary distribution of JAXP 1.1 (Final Version) from:
+
+    http://java.sun.com/xml/download.html
+
+* Unpack the binary distribution into a convenient location so that the
+  JAXP/1.1 release resides in its own directory (conventionally named
+  "jaxp-1.1".  For the purposes of the remainder of this document, the
+  symbolic name "${jaxp.home}" is used to refer to the full pathname of
+  the release directory.
+
+* Make the JAR files of this distribution ("crimson.jar", "jaxp.jar", and
+  "xalan.jar") available for use by performing ONE of the following options:
+
+  - Remove the existing "jaxp.jar" and "parser.jar" files found in the
+    "${ant.home}/lib" directory, and copy these JAR files into the
+    "${ant.home}/lib" directory (prefered option).
+
+  - Add these files to your CLASSPATH environment variable.
+
+
+(3) Download and Install Subproject Source Code
+
+* Use Anonymous CVS (as described on the Jakarta web site at
+  <http://jakarta.apache.org/site/cvsindex.html>, or
+  download a source distribution from:
+
+    http://jakarta.apache.org/builds/jakarta-servletapi-4/nightly/src/
+
+  On a Windows platform, you will need:
+    jakarta-servletapi-4-src-YYYYMMDD.zip
+
+  On a Unix platform, you will need:
+    jakarta-servletapi-4-src-YYYYMMDD.zip
+
+  (Alternatively, you can download the Servlet API source distribution
+  from the same directory as you find a released version of Tomcat 4.
+  Such distributions will contain exactly the Servlet API classes used
+  to build the "servlet.jar" file inside that Tomcat distribution.)
+
+* Unpack the source distribution into a convenient location so that the
+  distribution resides in its own directory (conventionally named
+  "jakarta-servletapi-4").  For the purposes of the remainder of this document,
+  the symbolic name "${servletapi.source}" is used to refer to the full
+  pathname of the release directory.
+
+
+(4) Customize Build Properties For This Subproject
+
+Most Jakarta subprojects allow you to customize Ant properties (with default
+values defined in the "build.xml" file.  This is done by creating a text file
+named "build.properties" in the source distribution directory (for property
+definitions local to this subproject) and/or your user home directory (for
+property definitions shared across subprojects).
+
+The "jakarta-servletapi-4" subproject does not define any customizable
+build properties.
+
+
+(5) Build A Binary Distribution
+
+Open a command line shell, and issue the following commands:
+
+  cd ${servletapi.source}
+  ant -projecthelp
+
+If everything is installed correctly, you should see a list of the Ant
+"targets" that represent different commands you might wish to build.  By
+convention, the "dist" target creates a complete binary distribution.  To
+execute it, type the following commands:
+
+  cd ${servletapi.source}
+  ant dist
+
+This will create a complete binary distribution of the subproject (equivalent
+in structure to the corresponding binary distribution downloadable from the
+Jakarta web site), in the "${servletapi.source}/dist" directory.  It will have
+the contents described in the corresponding "README.txt" file.
+
+The file most commonly required by other projects will be the "servlet.jar"
+file, found in "${servletapi.source}/lib/servlet.jar".  Make a note of the
+full pathname to this file, because you will need it when customizing build
+properties for other Jakarta subprojects that depend on these classes.

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/LICENSE
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/LICENSE	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/LICENSE	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,202 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed 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.

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/README.txt
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/README.txt	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/README.txt	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,28 @@
+$Id: README.txt 266968 2002-08-13 16:20:53Z remm $
+
+                      Java Servlet and JSP API Classes
+                      ================================
+
+This subproject contains the compiled code for the implementation classes of
+the Java Servlet and JSP APIs (packages javax.servlet, javax.servlet.http,
+javax.servlet.jsp, and javax.servlet.jsp.tagext).  It includes the following
+contents:
+
+
+  BUILDING.txt                Instructions for building from sources
+  LICENSE                     Apache Software License for this release
+  README.txt                  This document
+  docs/                       Documentation for this release
+      api/                    Javadocs for Servlet and JSP API classes
+  lib/                        Binary JAR files for this release
+      servlet.jar             Binary Servlet and JSP API classes
+  src/                        Sources for Servlet and JSP API classes
+
+In general, you will need to add the "servlet.jar" file (found in the "lib"
+subdirectory of this release) into the compilation class path for your
+projects that depend on these APIs.
+
+The compiled "servlet.jar" file included in this subproject is automatically
+included in binary distributions of Tomcat 4.0, so you need not download this
+subproject separately unless you wish to utilize the Javadocs, or peruse the
+source code to see how the API classes are implemented.

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/build.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/build.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/build.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,178 @@
+<project name="Servlet API Classes" default="compile" basedir=".">
+
+
+  <!-- =================== Environmental Properties ======================= -->
+
+  <!-- Load user property definition overrides -->
+  <property file="build.properties"/>
+  <property file="${user.home}/build.properties"/>
+
+  <!-- Establish property definition defaults -->
+  <property name="compile.debug"       value="true"/>
+  <property name="compile.deprecation" value="false"/>
+  <property name="compile.optimize"    value="true"/>
+  <property name="implementation.revision" value="public_draft"/>
+  <property name="servlet-api.build"    value="build"/>
+  <property name="servlet-api.dist"     value="dist"/>
+  <property name="servlet-api.jar" value="${servlet-api.dist}/lib/servlet-api.jar"/>
+  <path id="examples.classpath">
+    <pathelement location="${servlet-api.build}/classes"/>
+  </path>
+
+
+  <!-- ===================== Prepare Directories ========================= -->
+  <target name="prepare">
+
+    <!-- "Build" Hierarchy -->
+    <mkdir dir="${servlet-api.build}"/>
+    <mkdir dir="${servlet-api.build}/classes"/>
+    <mkdir dir="${servlet-api.build}/docs"/>
+    <mkdir dir="${servlet-api.build}/docs/api"/>
+    <mkdir dir="${servlet-api.build}/examples"/>
+
+    <!-- "Dist" Hierarchy -->
+    <mkdir dir="${servlet-api.dist}"/>
+    <mkdir dir="${servlet-api.dist}/docs"/>
+    <mkdir dir="${servlet-api.dist}/docs/api"/>
+    <mkdir dir="${servlet-api.dist}/lib"/>
+    <mkdir dir="${servlet-api.dist}/src"/>
+    <mkdir dir="${servlet-api.dist}/examples"/>
+
+    <uptodate property="docs.uptodate" targetfile="${servlet-api.build}/docs/api/index.html">
+      <srcfiles dir="src/share" includes="**/*.java" />
+    </uptodate>
+  </target>
+
+
+  <!-- ======================= Static Files ============================== -->
+  <target name="static" depends="prepare">
+
+    <!-- "Dist" Hierarchy -->
+    <copy todir="${servlet-api.dist}">
+      <fileset dir="." includes="BUILDING.txt"/>
+      <fileset dir="." includes="LICENSE"/>
+      <fileset dir="." includes="README.txt"/>
+    </copy>
+
+  </target>
+
+
+  <!-- ======================== Compile Classes ========================== -->
+  <target name="compile" depends="static"
+   description="Compile API classes (Default)">
+
+    <!-- Java classes -->
+    <javac srcdir="src/share" destdir="${servlet-api.build}/classes"
+           debug="${compile.debug}" deprecation="${compile.deprecation}"
+        optimize="${compile.optimize}"/>
+
+    <!-- Associated property files -->
+    <copy todir="${servlet-api.build}/classes">
+        <fileset dir="src/share">
+          <include name="**/*.properties"/>
+        </fileset>
+    </copy>
+
+    <!-- Servlet resources -->
+    <copy todir="${servlet-api.build}/classes/javax/servlet/resources">
+        <fileset dir="src/share/dtd" includes="*.dtd,*.xsd">
+          <exclude name="jsp*.dtd"/>
+          <exclude name="web-jsp*.dtd"/>
+        </fileset>
+    </copy>
+
+  </target>
+
+
+  <!-- ======================== Build JavaDoc =========================== -->
+  <target name="javadoc" depends="prepare" unless="docs.uptodate">
+
+    <javadoc packagenames="javax.servlet.*"
+             sourcepath="${basedir}/src/share"
+             destdir="${servlet-api.build}/docs/api"
+             use="true"
+             windowtitle="Servlet API Documentation"
+             doctitle="Servlet API Documentation"
+             bottom="Copyright &amp;copy; 1999-2002 The Apache Software Foundation.  All Rights Reserved."/>
+
+  </target>
+
+
+  <!-- ======================== Build JavaDoc =========================== -->
+  <target name="examples" depends="prepare">
+
+    <copy todir="${servlet-api.build}/examples">
+      <fileset dir="examples">
+        <exclude name="build.*"/>
+      </fileset>
+    </copy>
+
+    <javac   srcdir="examples/WEB-INF/classes" 
+             destdir="${servlet-api.build}/examples/WEB-INF/classes"
+             debug="${compile.debug}" deprecation="${compile.deprecation}"
+             optimize="${compile.optimize}"
+             excludes="**/CVS/**">
+      <classpath refid="examples.classpath" />
+    </javac>
+
+    <jar   jarfile="${servlet-api.dist}/examples/examples.war"
+           basedir="${servlet-api.build}/examples" includes="**"/>
+
+  </target>
+
+
+  <!-- ===================== Distribution Files ========================= -->
+  <target name="jar" depends="compile"
+          description="Create the jar">
+
+    <!-- Prepare Manifest -->
+    <copy tofile="${servlet-api.build}/manifest"
+            file="src/etc/manifest" overwrite="yes">
+      <filterset>
+        <filter token="implementation.revision"
+                value="${implementation.revision}"/>
+      </filterset>
+    </copy>
+
+    <!-- Create JAR file -->
+    <jar jarfile="${servlet-api.jar}"
+         basedir="${servlet-api.build}/classes"
+         manifest="${servlet-api.build}/manifest">
+      <include name="javax/servlet/**"/>
+      <exclude name="javax/servlet/jsp/**"/>
+    </jar>
+
+  </target>
+
+  <target name="dist" depends="compile,examples,javadoc,jar"
+          description="Create binary distribution">
+
+    <!-- Copy Javadocs -->
+    <copy todir="${servlet-api.dist}/docs/api">
+        <fileset dir="${servlet-api.build}/docs/api"/>
+    </copy>
+
+    <!-- Copy API source files -->
+    <copy todir="${servlet-api.dist}/src">
+        <fileset dir="src/share"/>
+    </copy>
+
+  </target>
+
+
+  <!-- ====================== Clean Generated Files ===================== -->
+  <target name="clean"
+   description="Clean previous build results">
+
+    <delete dir="${servlet-api.build}"/>
+    <delete dir="${servlet-api.dist}"/>
+
+  </target>
+
+
+  <!-- ========================= All In One Build ======================= -->
+  <target name="all" depends="clean,dist"
+   description="Clean, compile, and dist"/>
+
+
+</project>

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/examples/WEB-INF/classes/CookieExample.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/examples/WEB-INF/classes/CookieExample.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/examples/WEB-INF/classes/CookieExample.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,121 @@
+/*
+* Copyright 2004 The Apache Software Foundation
+*
+* Licensed 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.
+*/
+/* $Id: CookieExample.java 267129 2004-03-18 16:40:35Z jfarcand $
+ *
+ */
+
+import java.io.*;
+import java.text.*;
+import java.util.*;
+import javax.servlet.*;
+import javax.servlet.http.*;
+
+import util.HTMLFilter;
+
+/**
+ * Example servlet showing request headers
+ *
+ * @author James Duncan Davidson <duncan at eng.sun.com>
+ */
+
+public class CookieExample extends HttpServlet {
+
+    ResourceBundle rb = ResourceBundle.getBundle("LocalStrings");
+    
+    public void doGet(HttpServletRequest request,
+                      HttpServletResponse response)
+        throws IOException, ServletException
+    {
+        response.setContentType("text/html");
+
+        PrintWriter out = response.getWriter();
+        out.println("<html>");
+        out.println("<body bgcolor=\"white\">");
+        out.println("<head>");
+
+        String title = rb.getString("cookies.title");
+        out.println("<title>" + title + "</title>");
+        out.println("</head>");
+        out.println("<body>");
+
+	// relative links
+
+        // XXX
+        // making these absolute till we work out the
+        // addition of a PathInfo issue 
+	
+        out.println("<a href=\"../cookies.html\">");
+        out.println("<img src=\"../images/code.gif\" height=24 " +
+                    "width=24 align=right border=0 alt=\"view code\"></a>");
+        out.println("<a href=\"../index.html\">");
+        out.println("<img src=\"../images/return.gif\" height=24 " +
+                    "width=24 align=right border=0 alt=\"return\"></a>");
+
+        out.println("<h3>" + title + "</h3>");
+
+        Cookie[] cookies = request.getCookies();
+        if ((cookies != null) && (cookies.length > 0)) {
+            out.println(rb.getString("cookies.cookies") + "<br>");
+            for (int i = 0; i < cookies.length; i++) {
+                Cookie cookie = cookies[i];
+                out.print("Cookie Name: " + HTMLFilter.filter(cookie.getName())
+                          + "<br>");
+                out.println("  Cookie Value: " 
+                            + HTMLFilter.filter(cookie.getValue())
+                            + "<br><br>");
+            }
+        } else {
+            out.println(rb.getString("cookies.no-cookies"));
+        }
+
+        String cookieName = request.getParameter("cookiename");
+        String cookieValue = request.getParameter("cookievalue");
+        if (cookieName != null && cookieValue != null) {
+            Cookie cookie = new Cookie(cookieName, cookieValue);
+            response.addCookie(cookie);
+            out.println("<P>");
+            out.println(rb.getString("cookies.set") + "<br>");
+            out.print(rb.getString("cookies.name") + "  " 
+                      + HTMLFilter.filter(cookieName) + "<br>");
+            out.print(rb.getString("cookies.value") + "  " 
+                      + HTMLFilter.filter(cookieValue));
+        }
+        
+        out.println("<P>");
+        out.println(rb.getString("cookies.make-cookie") + "<br>");
+        out.print("<form action=\"");
+        out.println("CookieExample\" method=POST>");
+        out.print(rb.getString("cookies.name") + "  ");
+        out.println("<input type=text length=20 name=cookiename><br>");
+        out.print(rb.getString("cookies.value") + "  ");
+        out.println("<input type=text length=20 name=cookievalue><br>");
+        out.println("<input type=submit></form>");
+            
+            
+        out.println("</body>");
+        out.println("</html>");
+    }
+
+    public void doPost(HttpServletRequest request,
+                      HttpServletResponse response)
+        throws IOException, ServletException
+    {
+        doGet(request, response);
+    }
+
+}
+
+

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/examples/WEB-INF/classes/HelloWorldExample.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/examples/WEB-INF/classes/HelloWorldExample.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/examples/WEB-INF/classes/HelloWorldExample.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,75 @@
+/*
+* Copyright 2004 The Apache Software Foundation
+*
+* Licensed 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.
+*/
+/* $Id: HelloWorldExample.java 267129 2004-03-18 16:40:35Z jfarcand $
+ *
+ */
+
+import java.io.*;
+import java.text.*;
+import java.util.*;
+import javax.servlet.*;
+import javax.servlet.http.*;
+
+/**
+ * The simplest possible servlet.
+ *
+ * @author James Duncan Davidson
+ */
+
+public class HelloWorldExample extends HttpServlet {
+
+
+    public void doGet(HttpServletRequest request,
+                      HttpServletResponse response)
+        throws IOException, ServletException
+    {
+        ResourceBundle rb =
+            ResourceBundle.getBundle("LocalStrings",request.getLocale());
+        response.setContentType("text/html");
+        PrintWriter out = response.getWriter();
+
+        out.println("<html>");
+        out.println("<head>");
+
+	    String title = rb.getString("helloworld.title");
+
+	    out.println("<title>" + title + "</title>");
+        out.println("</head>");
+        out.println("<body bgcolor=\"white\">");
+
+	// note that all links are created to be relative. this
+	// ensures that we can move the web application that this
+	// servlet belongs to to a different place in the url
+	// tree and not have any harmful side effects.
+
+        // XXX
+        // making these absolute till we work out the
+        // addition of a PathInfo issue
+
+	    out.println("<a href=\"../helloworld.html\">");
+        out.println("<img src=\"../images/code.gif\" height=24 " +
+                    "width=24 align=right border=0 alt=\"view code\"></a>");
+        out.println("<a href=\"../index.html\">");
+        out.println("<img src=\"../images/return.gif\" height=24 " +
+                    "width=24 align=right border=0 alt=\"return\"></a>");
+        out.println("<h1>" + title + "</h1>");
+        out.println("</body>");
+        out.println("</html>");
+    }
+}
+
+
+

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/examples/WEB-INF/classes/LocalStrings.properties
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/examples/WEB-INF/classes/LocalStrings.properties	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/examples/WEB-INF/classes/LocalStrings.properties	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,52 @@
+# Copyright 2004 The Apache Software Foundation
+#
+# Licensed 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.
+
+# $Id: LocalStrings.properties 267129 2004-03-18 16:40:35Z jfarcand $
+
+# Default localized resources for example servlets
+# This locale is en_US
+
+helloworld.title=Hello World!
+
+requestinfo.title=Request Information Example
+requestinfo.label.method=Method:
+requestinfo.label.requesturi=Request URI:
+requestinfo.label.protocol=Protocol:
+requestinfo.label.pathinfo=Path Info:
+requestinfo.label.remoteaddr=Remote Address:
+
+requestheader.title=Request Header Example
+
+requestparams.title=Request Parameters Example
+requestparams.params-in-req=Parameters in this request:
+requestparams.no-params=No Parameters, Please enter some
+requestparams.firstname=First Name:
+requestparams.lastname=Last Name:
+
+cookies.title=Cookies Example
+cookies.cookies=Your browser is sending the following cookies:
+cookies.no-cookies=Your browser isn't sending any cookies
+cookies.make-cookie=Create a cookie to send to your browser
+cookies.name=Name:
+cookies.value=Value:
+cookies.set=You just sent the following cookie to your browser:
+
+sessions.title=Sessions Example
+sessions.id=Session ID:
+sessions.created=Created:
+sessions.lastaccessed=Last Accessed:
+sessions.data=The following data is in your session:
+sessions.adddata=Add data to your session
+sessions.dataname=Name of Session Attribute:
+sessions.datavalue=Value of Session Attribute:

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/examples/WEB-INF/classes/LocalStrings_en.properties
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/examples/WEB-INF/classes/LocalStrings_en.properties	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/examples/WEB-INF/classes/LocalStrings_en.properties	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,52 @@
+# Copyright 2004 The Apache Software Foundation
+#
+# Licensed 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.
+
+# $Id: LocalStrings_en.properties 267129 2004-03-18 16:40:35Z jfarcand $
+
+# Default localized resources for example servlets
+# This locale is en_US
+
+helloworld.title=Hello World!
+
+requestinfo.title=Request Information Example
+requestinfo.label.method=Method:
+requestinfo.label.requesturi=Request URI:
+requestinfo.label.protocol=Protocol:
+requestinfo.label.pathinfo=Path Info:
+requestinfo.label.remoteaddr=Remote Address:
+
+requestheader.title=Request Header Example
+
+requestparams.title=Request Parameters Example
+requestparams.params-in-req=Parameters in this request:
+requestparams.no-params=No Parameters, Please enter some
+requestparams.firstname=First Name:
+requestparams.lastname=Last Name:
+
+cookies.title=Cookies Example
+cookies.cookies=Your browser is sending the following cookies:
+cookies.no-cookies=Your browser isn't sending any cookies
+cookies.make-cookie=Create a cookie to send to your browser
+cookies.name=Name:
+cookies.value=Value:
+cookies.set=You just sent the following cookie to your browser:
+
+sessions.title=Sessions Example
+sessions.id=Session ID:
+sessions.created=Created:
+sessions.lastaccessed=Last Accessed:
+sessions.data=The following data is in your session:
+sessions.adddata=Add data to your session
+sessions.dataname=Name of Session Attribute:
+sessions.datavalue=Value of Session Attribute:

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/examples/WEB-INF/classes/LocalStrings_es.properties
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/examples/WEB-INF/classes/LocalStrings_es.properties	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/examples/WEB-INF/classes/LocalStrings_es.properties	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,52 @@
+# Copyright 2004 The Apache Software Foundation
+#
+# Licensed 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.
+
+# $Id: LocalStrings_es.properties 267129 2004-03-18 16:40:35Z jfarcand $
+#
+# Default localized string information
+# Localized para Locale es_ES
+
+helloworld.title=Hola Mundo!
+
+requestinfo.title=Ejemplo de Informacion de Request
+requestinfo.label.method=Metodo:
+requestinfo.label.requesturi=Request URI:
+requestinfo.label.protocol=Protocolo:
+requestinfo.label.pathinfo=Path Info:
+requestinfo.label.remoteaddr=Direccion Remota:
+
+requestheader.title=Ejemplo de Cabecera de Request
+
+requestparams.title=Ejemplo de parametros de Request
+requestparams.params-in-req=Parametros en este Request:
+requestparams.no-params=No hay parametro. por favor usa alguno
+requestparams.firstname=Nombre:
+requestparams.lastname=Apellidos:
+
+cookies.title=Ejemplo de Cookies
+cookies.cookies=Tu navegador esta enviando los siguientes cookies:
+cookies.no-cookies=Tu navegador no esta enviando cookies
+cookies.make-cookie=Crea un cookie para enviarlo a tu navegador
+cookies.name=Nombre:
+cookies.value=Valor:
+cookies.set=Acabas de enviar a tu navegador estos cookies:
+
+sessions.title=ejemplo de Sesiones
+sessions.id=ID de Sesion:
+sessions.created=Creado:
+sessions.lastaccessed=Ultimo Acceso:
+sessions.data=Lo siguientes datos estan en tu sesion:
+sessions.adddata=Añade datos a tu sesion:
+sessions.dataname=Nombre del atributo de sesion:
+sessions.datavalue=Valor del atributo de sesion:

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/examples/WEB-INF/classes/LocalStrings_fr.properties
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/examples/WEB-INF/classes/LocalStrings_fr.properties	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/examples/WEB-INF/classes/LocalStrings_fr.properties	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,52 @@
+# Copyright 2004 The Apache Software Foundation
+#
+# Licensed 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.
+
+# $Id: LocalStrings_fr.properties 267129 2004-03-18 16:40:35Z jfarcand $
+
+# Default localized resources for example servlets
+# This locale is fr_FR
+
+helloworld.title=Salut le Monde!
+
+requestinfo.title=Exemple d''information sur la requête
+requestinfo.label.method=Méthode:
+requestinfo.label.requesturi=URI de requête:
+requestinfo.label.protocol=Protocole:
+requestinfo.label.pathinfo=Info de chemin:
+requestinfo.label.remoteaddr=Adresse distante:
+
+requestheader.title=Exemple d''information sur les entête de requête
+
+requestparams.title=Exemple de requête avec paramêtres
+requestparams.params-in-req=Paramêtres dans la requête:
+requestparams.no-params=Pas de paramêtre, merci dans saisir quelqu'uns
+requestparams.firstname=Prénom:
+requestparams.lastname=Nom:
+
+cookies.title=Exemple d''utilisation de Cookies
+cookies.cookies=Votre navigateur retourne les cookies suivant:
+cookies.no-cookies=Votre navigateur ne retourne aucun cookie
+cookies.make-cookie=Création d''un cookie à retourner à votre navigateur
+cookies.name=Nom:
+cookies.value=Valeur:
+cookies.set=Vous venez d''envoyer le cookie suivant à votre navigateur:
+
+sessions.title=Exemple de Sessions
+sessions.id=ID de Session:
+sessions.created=Crée le:
+sessions.lastaccessed=Dernier accès:
+sessions.data=Les données existantes dans votre session:
+sessions.adddata=Ajouter des données à votre session
+sessions.dataname=Nom de l''Attribut de Session:
+sessions.datavalue=Valeur de l''Attribut de Session:

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/examples/WEB-INF/classes/LocalStrings_pt.properties
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/examples/WEB-INF/classes/LocalStrings_pt.properties	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/examples/WEB-INF/classes/LocalStrings_pt.properties	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,52 @@
+# Copyright 2004 The Apache Software Foundation
+#
+# Licensed 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.
+
+# $Id: LocalStrings_pt.properties 267143 2004-08-24 18:38:35Z jfarcand $
+
+# Default localized resources for example servlets
+# This locale is pt_PT
+
+helloworld.title=Ola Mundo!
+
+requestinfo.title=Exemplo da Informacao do Pedido
+requestinfo.label.method=Metodo:
+requestinfo.label.requesturi=URI do Pedido:
+requestinfo.label.protocol=Protocolo:
+requestinfo.label.pathinfo=Informacao do Caminho:
+requestinfo.label.remoteaddr=Endereco Remoto:
+
+requestheader.title=Exemplo da Cebeceira do Pedido
+
+requestparams.title=Examplo de Parametros do Pedido
+requestparams.params-in-req=Parametros neste pedido:
+requestparams.no-params=Sem Parametros, Por favor entre alguns
+requestparams.firstname=Primeiro Nome:
+requestparams.lastname=Apelido:
+
+cookies.title=CExamplo de Cookies
+cookies.cookies=O se browser esta a enviar os seguintes cookies:
+cookies.no-cookies=O seu browser nao esta a enviar nenhuns cookies
+cookies.make-cookie=Crie um cookie para enviar para o seu browser
+cookies.name=Nome:
+cookies.value=Valor:
+cookies.set=Acabou de enviar o seguinte cookie para o seu browser:
+
+sessions.title=Examplo de sessoes
+sessions.id=Identificador da Sessao:
+sessions.created=Criada:
+sessions.lastaccessed=Ultima vez acedida:
+sessions.data=Os seguintes dados fazem parte da sua sessao:
+sessions.adddata=Adicione data a sua sessao
+sessions.dataname=Nome do atributo da sessao:
+sessions.datavalue=Valor do atributo da Sessao:

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/examples/WEB-INF/classes/RequestHeaderExample.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/examples/WEB-INF/classes/RequestHeaderExample.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/examples/WEB-INF/classes/RequestHeaderExample.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,90 @@
+/*
+* Copyright 2004 The Apache Software Foundation
+*
+* Licensed 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.
+*/
+/* $Id: RequestHeaderExample.java 267129 2004-03-18 16:40:35Z jfarcand $
+ *
+ */
+
+import java.io.*;
+import java.text.*;
+import java.util.*;
+import javax.servlet.*;
+import javax.servlet.http.*;
+
+import util.HTMLFilter;
+
+/**
+ * Example servlet showing request headers
+ *
+ * @author James Duncan Davidson <duncan at eng.sun.com>
+ */
+
+public class RequestHeaderExample extends HttpServlet {
+
+    ResourceBundle rb = ResourceBundle.getBundle("LocalStrings");
+    
+    public void doGet(HttpServletRequest request,
+                      HttpServletResponse response)
+        throws IOException, ServletException
+    {
+        response.setContentType("text/html");
+
+        PrintWriter out = response.getWriter();
+        out.println("<html>");
+        out.println("<body bgcolor=\"white\">");
+        out.println("<head>");
+
+        String title = rb.getString("requestheader.title");
+        out.println("<title>" + title + "</title>");
+        out.println("</head>");
+        out.println("<body>");
+
+	// all links relative
+
+        // XXX
+        // making these absolute till we work out the
+        // addition of a PathInfo issue 
+	
+        out.println("<a href=\"../reqheaders.html\">");
+        out.println("<img src=\"../images/code.gif\" height=24 " +
+                    "width=24 align=right border=0 alt=\"view code\"></a>");
+        out.println("<a href=\"../index.html\">");
+        out.println("<img src=\"../images/return.gif\" height=24 " +
+                    "width=24 align=right border=0 alt=\"return\"></a>");
+
+        out.println("<h3>" + title + "</h3>");
+        out.println("<table border=0>");
+        Enumeration e = request.getHeaderNames();
+        while (e.hasMoreElements()) {
+            String headerName = (String)e.nextElement();
+            String headerValue = request.getHeader(headerName);
+            out.println("<tr><td bgcolor=\"#CCCCCC\">");
+            out.println(HTMLFilter.filter(headerName));
+            out.println("</td><td>");
+            out.println(HTMLFilter.filter(headerValue));
+            out.println("</td></tr>");
+        }
+        out.println("</table>");
+    }
+
+    public void doPost(HttpServletRequest request,
+                      HttpServletResponse response)
+        throws IOException, ServletException
+    {
+        doGet(request, response);
+    }
+
+}
+

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/examples/WEB-INF/classes/RequestInfoExample.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/examples/WEB-INF/classes/RequestInfoExample.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/examples/WEB-INF/classes/RequestInfoExample.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,114 @@
+/*
+* Copyright 2004 The Apache Software Foundation
+*
+* Licensed 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.
+*/
+/* $Id: RequestInfoExample.java 267129 2004-03-18 16:40:35Z jfarcand $
+ *
+ */
+
+import java.io.*;
+import java.text.*;
+import java.util.*;
+import javax.servlet.*;
+import javax.servlet.http.*;
+
+import util.HTMLFilter;
+
+/**
+ * Example servlet showing request information.
+ *
+ * @author James Duncan Davidson <duncan at eng.sun.com>
+ */
+
+public class RequestInfoExample extends HttpServlet {
+
+
+    ResourceBundle rb = ResourceBundle.getBundle("LocalStrings");
+
+    public void doGet(HttpServletRequest request,
+                      HttpServletResponse response)
+        throws IOException, ServletException
+    {
+        response.setContentType("text/html");
+
+        PrintWriter out = response.getWriter();
+        out.println("<html>");
+        out.println("<body>");
+        out.println("<head>");
+
+        String title = rb.getString("requestinfo.title");
+        out.println("<title>" + title + "</title>");
+        out.println("</head>");
+        out.println("<body bgcolor=\"white\">");
+
+        // img stuff not req'd for source code html showing
+	// all links relative!
+
+        // XXX
+        // making these absolute till we work out the
+        // addition of a PathInfo issue
+	
+        out.println("<a href=\"../reqinfo.html\">");
+        out.println("<img src=\"../images/code.gif\" height=24 " +
+                    "width=24 align=right border=0 alt=\"view code\"></a>");
+        out.println("<a href=\"../index.html\">");
+        out.println("<img src=\"../images/return.gif\" height=24 " +
+                    "width=24 align=right border=0 alt=\"return\"></a>");
+
+        out.println("<h3>" + title + "</h3>");
+        out.println("<table border=0><tr><td>");
+        out.println(rb.getString("requestinfo.label.method"));
+        out.println("</td><td>");
+        out.println(request.getMethod());
+        out.println("</td></tr><tr><td>");
+        out.println(rb.getString("requestinfo.label.requesturi"));
+        out.println("</td><td>");        
+        out.println(HTMLFilter.filter(request.getRequestURI()));
+        out.println("</td></tr><tr><td>");        
+        out.println(rb.getString("requestinfo.label.protocol"));
+        out.println("</td><td>");        
+        out.println(request.getProtocol());
+        out.println("</td></tr><tr><td>");
+        out.println(rb.getString("requestinfo.label.pathinfo"));
+        out.println("</td><td>");        
+        out.println(HTMLFilter.filter(request.getPathInfo()));
+        out.println("</td></tr><tr><td>");
+        out.println(rb.getString("requestinfo.label.remoteaddr"));
+
+ 	String cipherSuite=
+ 	    (String)request.getAttribute("javax.servlet.request.cipher_suite");
+        out.println("</td><td>");                
+        out.println(request.getRemoteAddr());
+        out.println("</table>");
+
+ 	if(cipherSuite!=null){
+ 	    out.println("</td></tr><tr><td>");	
+ 	    out.println("SSLCipherSuite:");
+ 	    out.println("</td>");
+ 	    out.println("<td>");	    
+ 	    out.println(request.getAttribute("javax.servlet.request.cipher_suite"));
+	    out.println("</td>");	    
+ 	}
+	
+    }
+
+    public void doPost(HttpServletRequest request,
+                      HttpServletResponse response)
+        throws IOException, ServletException
+    {
+        doGet(request, response);
+    }
+
+}
+

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/examples/WEB-INF/classes/RequestParamExample.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/examples/WEB-INF/classes/RequestParamExample.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/examples/WEB-INF/classes/RequestParamExample.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,106 @@
+/*
+* Copyright 2004 The Apache Software Foundation
+*
+* Licensed 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.
+*/
+/* $Id: RequestParamExample.java 267129 2004-03-18 16:40:35Z jfarcand $
+ *
+ */
+
+import java.io.*;
+import java.text.*;
+import java.util.*;
+import javax.servlet.*;
+import javax.servlet.http.*;
+
+import util.HTMLFilter;
+
+/**
+ * Example servlet showing request headers
+ *
+ * @author James Duncan Davidson <duncan at eng.sun.com>
+ */
+
+public class RequestParamExample extends HttpServlet {
+
+
+    ResourceBundle rb = ResourceBundle.getBundle("LocalStrings");
+    
+    public void doGet(HttpServletRequest request,
+                      HttpServletResponse response)
+        throws IOException, ServletException
+    {
+        response.setContentType("text/html");
+
+        PrintWriter out = response.getWriter();
+        out.println("<html>");
+        out.println("<body>");
+        out.println("<head>");
+
+        String title = rb.getString("requestparams.title");
+        out.println("<title>" + title + "</title>");
+        out.println("</head>");
+        out.println("<body bgcolor=\"white\">");
+
+        // img stuff not req'd for source code html showing
+
+	// all links relative
+
+        // XXX
+        // making these absolute till we work out the
+        // addition of a PathInfo issue 
+	
+        out.println("<a href=\"../reqparams.html\">");
+        out.println("<img src=\"../images/code.gif\" height=24 " +
+                    "width=24 align=right border=0 alt=\"view code\"></a>");
+        out.println("<a href=\"../index.html\">");
+        out.println("<img src=\"../images/return.gif\" height=24 " +
+                    "width=24 align=right border=0 alt=\"return\"></a>");
+
+        out.println("<h3>" + title + "</h3>");
+        String firstName = request.getParameter("firstname");
+        String lastName = request.getParameter("lastname");
+        out.println(rb.getString("requestparams.params-in-req") + "<br>");
+        if (firstName != null || lastName != null) {
+            out.println(rb.getString("requestparams.firstname"));
+            out.println(" = " + HTMLFilter.filter(firstName) + "<br>");
+            out.println(rb.getString("requestparams.lastname"));
+            out.println(" = " + HTMLFilter.filter(lastName));
+        } else {
+            out.println(rb.getString("requestparams.no-params"));
+        }
+        out.println("<P>");
+        out.print("<form action=\"");
+        out.print("RequestParamExample\" ");
+        out.println("method=POST>");
+        out.println(rb.getString("requestparams.firstname"));
+        out.println("<input type=text size=20 name=firstname>");
+        out.println("<br>");
+        out.println(rb.getString("requestparams.lastname"));
+        out.println("<input type=text size=20 name=lastname>");
+        out.println("<br>");
+        out.println("<input type=submit>");
+        out.println("</form>");
+
+        out.println("</body>");
+        out.println("</html>");
+    }
+
+    public void doPost(HttpServletRequest request,
+                      HttpServletResponse response)
+        throws IOException, ServletException
+    {
+        doGet(request, response);
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/examples/WEB-INF/classes/SessionExample.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/examples/WEB-INF/classes/SessionExample.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/examples/WEB-INF/classes/SessionExample.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,140 @@
+/*
+* Copyright 2004 The Apache Software Foundation
+*
+* Licensed 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.
+*/
+/* $Id: SessionExample.java 267129 2004-03-18 16:40:35Z jfarcand $
+ *
+ */
+
+import java.io.*;
+import java.text.*;
+import java.util.*;
+import javax.servlet.*;
+import javax.servlet.http.*;
+
+import util.HTMLFilter;
+
+/**
+ * Example servlet showing request headers
+ *
+ * @author James Duncan Davidson <duncan at eng.sun.com>
+ */
+
+public class SessionExample extends HttpServlet {
+
+    ResourceBundle rb = ResourceBundle.getBundle("LocalStrings");
+    
+    public void doGet(HttpServletRequest request,
+                      HttpServletResponse response)
+        throws IOException, ServletException
+    {
+        response.setContentType("text/html");
+
+        PrintWriter out = response.getWriter();
+        out.println("<html>");
+        out.println("<body bgcolor=\"white\">");
+        out.println("<head>");
+
+        String title = rb.getString("sessions.title");
+        out.println("<title>" + title + "</title>");
+        out.println("</head>");
+        out.println("<body>");
+
+        // img stuff not req'd for source code html showing
+	// relative links everywhere!
+
+        // XXX
+        // making these absolute till we work out the
+        // addition of a PathInfo issue 
+	
+        out.println("<a href=\"../sessions.html\">");
+        out.println("<img src=\"../images/code.gif\" height=24 " +
+                    "width=24 align=right border=0 alt=\"view code\"></a>");
+        out.println("<a href=\"../index.html\">");
+        out.println("<img src=\"../images/return.gif\" height=24 " +
+                    "width=24 align=right border=0 alt=\"return\"></a>");
+
+        out.println("<h3>" + title + "</h3>");
+
+        HttpSession session = request.getSession(true);
+        out.println(rb.getString("sessions.id") + " " + session.getId());
+        out.println("<br>");
+        out.println(rb.getString("sessions.created") + " ");
+        out.println(new Date(session.getCreationTime()) + "<br>");
+        out.println(rb.getString("sessions.lastaccessed") + " ");
+        out.println(new Date(session.getLastAccessedTime()));
+
+        String dataName = request.getParameter("dataname");
+        String dataValue = request.getParameter("datavalue");
+        if (dataName != null && dataValue != null) {
+            session.setAttribute(dataName, dataValue);
+        }
+
+        out.println("<P>");
+        out.println(rb.getString("sessions.data") + "<br>");
+        Enumeration names = session.getAttributeNames();
+        while (names.hasMoreElements()) {
+            String name = (String) names.nextElement(); 
+            String value = session.getAttribute(name).toString();
+            out.println(HTMLFilter.filter(name) + " = " 
+                        + HTMLFilter.filter(value) + "<br>");
+        }
+
+        out.println("<P>");
+        out.print("<form action=\"");
+	out.print(response.encodeURL("SessionExample"));
+        out.print("\" ");
+        out.println("method=POST>");
+        out.println(rb.getString("sessions.dataname"));
+        out.println("<input type=text size=20 name=dataname>");
+        out.println("<br>");
+        out.println(rb.getString("sessions.datavalue"));
+        out.println("<input type=text size=20 name=datavalue>");
+        out.println("<br>");
+        out.println("<input type=submit>");
+        out.println("</form>");
+
+        out.println("<P>GET based form:<br>");
+        out.print("<form action=\"");
+	out.print(response.encodeURL("SessionExample"));
+        out.print("\" ");
+        out.println("method=GET>");
+        out.println(rb.getString("sessions.dataname"));
+        out.println("<input type=text size=20 name=dataname>");
+        out.println("<br>");
+        out.println(rb.getString("sessions.datavalue"));
+        out.println("<input type=text size=20 name=datavalue>");
+        out.println("<br>");
+        out.println("<input type=submit>");
+        out.println("</form>");
+
+        out.print("<p><a href=\"");
+	out.print(response.encodeURL("SessionExample?dataname=foo&datavalue=bar"));
+	out.println("\" >URL encoded </a>");
+	
+        out.println("</body>");
+        out.println("</html>");
+        
+        out.println("</body>");
+        out.println("</html>");
+    }
+
+    public void doPost(HttpServletRequest request,
+                      HttpServletResponse response)
+        throws IOException, ServletException
+    {
+        doGet(request, response);
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/examples/WEB-INF/classes/compressionFilters/CompressionFilter.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/examples/WEB-INF/classes/compressionFilters/CompressionFilter.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/examples/WEB-INF/classes/compressionFilters/CompressionFilter.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,218 @@
+/*
+* Copyright 2004 The Apache Software Foundation
+*
+* Licensed 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 compressionFilters;
+
+import java.io.IOException;
+import java.util.Enumeration;
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+
+/**
+ * Implementation of <code>javax.servlet.Filter</code> used to compress
+ * the ServletResponse if it is bigger than a threshold.
+ *
+ * @author Amy Roh
+ * @author Dmitri Valdin
+ * @version $Revision: 267129 $, $Date: 2004-03-18 10:40:35 -0600 (Thu, 18 Mar 2004) $
+ */
+
+public class CompressionFilter implements Filter{
+
+    /**
+     * The filter configuration object we are associated with.  If this value
+     * is null, this filter instance is not currently configured.
+     */
+    private FilterConfig config = null;
+
+    /**
+     * Minimal reasonable threshold
+     */
+    private int minThreshold = 128;
+
+
+    /**
+     * The threshold number to compress
+     */
+    protected int compressionThreshold;
+
+    /**
+     * Debug level for this filter
+     */
+    private int debug = 0;
+
+    /**
+     * Place this filter into service.
+     *
+     * @param filterConfig The filter configuration object
+     */
+
+    public void init(FilterConfig filterConfig) {
+
+        config = filterConfig;
+        if (filterConfig != null) {
+            String value = filterConfig.getInitParameter("debug");
+            if (value!=null) {
+                debug = Integer.parseInt(value);
+            } else {
+                debug = 0;
+            }
+            String str = filterConfig.getInitParameter("compressionThreshold");
+            if (str!=null) {
+                compressionThreshold = Integer.parseInt(str);
+                if (compressionThreshold != 0 && compressionThreshold < minThreshold) {
+                    if (debug > 0) {
+                        System.out.println("compressionThreshold should be either 0 - no compression or >= " + minThreshold);
+                        System.out.println("compressionThreshold set to " + minThreshold);
+                    }
+                    compressionThreshold = minThreshold;
+                }
+            } else {
+                compressionThreshold = 0;
+            }
+
+        } else {
+            compressionThreshold = 0;
+        }
+
+    }
+
+    /**
+    * Take this filter out of service.
+    */
+    public void destroy() {
+
+        this.config = null;
+
+    }
+
+    /**
+     * The <code>doFilter</code> method of the Filter is called by the container
+     * each time a request/response pair is passed through the chain due
+     * to a client request for a resource at the end of the chain.
+     * The FilterChain passed into this method allows the Filter to pass on the
+     * request and response to the next entity in the chain.<p>
+     * This method first examines the request to check whether the client support
+     * compression. <br>
+     * It simply just pass the request and response if there is no support for
+     * compression.<br>
+     * If the compression support is available, it creates a
+     * CompressionServletResponseWrapper object which compresses the content and
+     * modifies the header if the content length is big enough.
+     * It then invokes the next entity in the chain using the FilterChain object
+     * (<code>chain.doFilter()</code>), <br>
+     **/
+
+    public void doFilter ( ServletRequest request, ServletResponse response,
+                        FilterChain chain ) throws IOException, ServletException {
+
+        if (debug > 0) {
+            System.out.println("@doFilter");
+        }
+
+        if (compressionThreshold == 0) {
+            if (debug > 0) {
+                System.out.println("doFilter gets called, but compressionTreshold is set to 0 - no compression");
+            }
+            chain.doFilter(request, response);
+            return;
+        }
+
+        boolean supportCompression = false;
+        if (request instanceof HttpServletRequest) {
+            if (debug > 1) {
+                System.out.println("requestURI = " + ((HttpServletRequest)request).getRequestURI());
+            }
+
+            // Are we allowed to compress ?
+            String s = (String) ((HttpServletRequest)request).getParameter("gzip");
+            if ("false".equals(s)) {
+                if (debug > 0) {
+                    System.out.println("got parameter gzip=false --> don't compress, just chain filter");
+                }
+                chain.doFilter(request, response);
+                return;
+            }
+
+            Enumeration e =
+                ((HttpServletRequest)request).getHeaders("Accept-Encoding");
+            while (e.hasMoreElements()) {
+                String name = (String)e.nextElement();
+                if (name.indexOf("gzip") != -1) {
+                    if (debug > 0) {
+                        System.out.println("supports compression");
+                    }
+                    supportCompression = true;
+                } else {
+                    if (debug > 0) {
+                        System.out.println("no support for compresion");
+                    }
+                }
+            }
+        }
+
+        if (!supportCompression) {
+            if (debug > 0) {
+                System.out.println("doFilter gets called wo compression");
+            }
+            chain.doFilter(request, response);
+            return;
+        } else {
+            if (response instanceof HttpServletResponse) {
+                CompressionServletResponseWrapper wrappedResponse =
+                    new CompressionServletResponseWrapper((HttpServletResponse)response);
+                wrappedResponse.setDebugLevel(debug);
+                wrappedResponse.setCompressionThreshold(compressionThreshold);
+                if (debug > 0) {
+                    System.out.println("doFilter gets called with compression");
+                }
+                try {
+                    chain.doFilter(request, wrappedResponse);
+                } finally {
+                    wrappedResponse.finishResponse();
+                }
+                return;
+            }
+        }
+    }
+
+    /**
+     * Set filter config
+     * This function is equivalent to init. Required by Weblogic 6.1
+     *
+     * @param filterConfig The filter configuration object
+     */
+    public void setFilterConfig(FilterConfig filterConfig) {
+        init(filterConfig);
+    }
+
+    /**
+     * Return filter config
+     * Required by Weblogic 6.1
+     */
+    public FilterConfig getFilterConfig() {
+        return config;
+    }
+
+}
+

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/examples/WEB-INF/classes/compressionFilters/CompressionFilterTestServlet.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/examples/WEB-INF/classes/compressionFilters/CompressionFilterTestServlet.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/examples/WEB-INF/classes/compressionFilters/CompressionFilterTestServlet.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,57 @@
+/*
+* Copyright 2004 The Apache Software Foundation
+*
+* Licensed 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 compressionFilters;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.Enumeration;
+import javax.servlet.*;
+import javax.servlet.http.*;
+
+/**
+ * Very Simple test servlet to test compression filter
+ * @author Amy Roh
+ * @version $Revision: 267129 $, $Date: 2004-03-18 10:40:35 -0600 (Thu, 18 Mar 2004) $
+ */
+
+public class CompressionFilterTestServlet extends HttpServlet {
+
+    public void doGet(HttpServletRequest request, HttpServletResponse response)
+        throws ServletException, IOException {
+
+        ServletOutputStream out = response.getOutputStream();
+        response.setContentType("text/plain");
+
+        Enumeration e = ((HttpServletRequest)request).getHeaders("Accept-Encoding");
+        while (e.hasMoreElements()) {
+            String name = (String)e.nextElement();
+            out.println(name);
+            if (name.indexOf("gzip") != -1) {
+                out.println("gzip supported -- able to compress");
+            }
+            else {
+                out.println("gzip not supported");
+            }
+        }
+
+
+        out.println("Compression Filter Test Servlet");
+        out.close();
+    }
+
+}
+

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/examples/WEB-INF/classes/compressionFilters/CompressionResponseStream.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/examples/WEB-INF/classes/compressionFilters/CompressionResponseStream.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/examples/WEB-INF/classes/compressionFilters/CompressionResponseStream.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,317 @@
+/*
+* Copyright 2004 The Apache Software Foundation
+*
+* Licensed 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 compressionFilters;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.zip.GZIPOutputStream;
+import javax.servlet.ServletOutputStream;
+import javax.servlet.http.HttpServletResponse;
+
+
+/**
+ * Implementation of <b>ServletOutputStream</b> that works with
+ * the CompressionServletResponseWrapper implementation.
+ *
+ * @author Amy Roh
+ * @author Dmitri Valdin
+ * @version $Revision: 267129 $, $Date: 2004-03-18 10:40:35 -0600 (Thu, 18 Mar 2004) $
+ */
+
+public class CompressionResponseStream
+    extends ServletOutputStream {
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Construct a servlet output stream associated with the specified Response.
+     *
+     * @param response The associated response
+     */
+    public CompressionResponseStream(HttpServletResponse response) throws IOException{
+
+        super();
+        closed = false;
+        this.response = response;
+        this.output = response.getOutputStream();
+
+    }
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The threshold number which decides to compress or not.
+     * Users can configure in web.xml to set it to fit their needs.
+     */
+    protected int compressionThreshold = 0;
+
+    /**
+     * Debug level
+     */
+    private int debug = 0;
+
+    /**
+     * The buffer through which all of our output bytes are passed.
+     */
+    protected byte[] buffer = null;
+
+    /**
+     * The number of data bytes currently in the buffer.
+     */
+    protected int bufferCount = 0;
+
+    /**
+     * The underlying gzip output stream to which we should write data.
+     */
+    protected GZIPOutputStream gzipstream = null;
+
+    /**
+     * Has this stream been closed?
+     */
+    protected boolean closed = false;
+
+    /**
+     * The content length past which we will not write, or -1 if there is
+     * no defined content length.
+     */
+    protected int length = -1;
+
+    /**
+     * The response with which this servlet output stream is associated.
+     */
+    protected HttpServletResponse response = null;
+
+    /**
+     * The underlying servket output stream to which we should write data.
+     */
+    protected ServletOutputStream output = null;
+
+
+    // --------------------------------------------------------- Public Methods
+
+    /**
+     * Set debug level
+     */
+    public void setDebugLevel(int debug) {
+        this.debug = debug;
+    }
+
+
+    /**
+     * Set the compressionThreshold number and create buffer for this size
+     */
+    protected void setBuffer(int threshold) {
+        compressionThreshold = threshold;
+        buffer = new byte[compressionThreshold];
+        if (debug > 1) {
+            System.out.println("buffer is set to "+compressionThreshold);
+        }
+    }
+
+    /**
+     * Close this output stream, causing any buffered data to be flushed and
+     * any further output data to throw an IOException.
+     */
+    public void close() throws IOException {
+
+        if (debug > 1) {
+            System.out.println("close() @ CompressionResponseStream");
+        }
+        if (closed)
+            throw new IOException("This output stream has already been closed");
+
+        if (gzipstream != null) {
+            flushToGZip();
+            gzipstream.close();
+            gzipstream = null;
+        } else {
+            if (bufferCount > 0) {
+                if (debug > 2) {
+                    System.out.print("output.write(");
+                    System.out.write(buffer, 0, bufferCount);
+                    System.out.println(")");
+                }
+                output.write(buffer, 0, bufferCount);
+                bufferCount = 0;
+            }
+        }
+
+        output.close();
+        closed = true;
+
+    }
+
+
+    /**
+     * Flush any buffered data for this output stream, which also causes the
+     * response to be committed.
+     */
+    public void flush() throws IOException {
+
+        if (debug > 1) {
+            System.out.println("flush() @ CompressionResponseStream");
+        }
+        if (closed) {
+            throw new IOException("Cannot flush a closed output stream");
+        }
+
+        if (gzipstream != null) {
+            gzipstream.flush();
+        }
+
+    }
+
+    public void flushToGZip() throws IOException {
+
+        if (debug > 1) {
+            System.out.println("flushToGZip() @ CompressionResponseStream");
+        }
+        if (bufferCount > 0) {
+            if (debug > 1) {
+                System.out.println("flushing out to GZipStream, bufferCount = " + bufferCount);
+            }
+            writeToGZip(buffer, 0, bufferCount);
+            bufferCount = 0;
+        }
+
+    }
+
+    /**
+     * Write the specified byte to our output stream.
+     *
+     * @param b The byte to be written
+     *
+     * @exception IOException if an input/output error occurs
+     */
+    public void write(int b) throws IOException {
+
+        if (debug > 1) {
+            System.out.println("write "+b+" in CompressionResponseStream ");
+        }
+        if (closed)
+            throw new IOException("Cannot write to a closed output stream");
+
+        if (bufferCount >= buffer.length) {
+            flushToGZip();
+        }
+
+        buffer[bufferCount++] = (byte) b;
+
+    }
+
+
+    /**
+     * Write <code>b.length</code> bytes from the specified byte array
+     * to our output stream.
+     *
+     * @param b The byte array to be written
+     *
+     * @exception IOException if an input/output error occurs
+     */
+    public void write(byte b[]) throws IOException {
+
+        write(b, 0, b.length);
+
+    }
+
+
+    /**
+     * Write <code>len</code> bytes from the specified byte array, starting
+     * at the specified offset, to our output stream.
+     *
+     * @param b The byte array containing the bytes to be written
+     * @param off Zero-relative starting offset of the bytes to be written
+     * @param len The number of bytes to be written
+     *
+     * @exception IOException if an input/output error occurs
+     */
+    public void write(byte b[], int off, int len) throws IOException {
+
+        if (debug > 1) {
+            System.out.println("write, bufferCount = " + bufferCount + " len = " + len + " off = " + off);
+        }
+        if (debug > 2) {
+            System.out.print("write(");
+            System.out.write(b, off, len);
+            System.out.println(")");
+        }
+
+        if (closed)
+            throw new IOException("Cannot write to a closed output stream");
+
+        if (len == 0)
+            return;
+
+        // Can we write into buffer ?
+        if (len <= (buffer.length - bufferCount)) {
+            System.arraycopy(b, off, buffer, bufferCount, len);
+            bufferCount += len;
+            return;
+        }
+
+        // There is not enough space in buffer. Flush it ...
+        flushToGZip();
+
+        // ... and try again. Note, that bufferCount = 0 here !
+        if (len <= (buffer.length - bufferCount)) {
+            System.arraycopy(b, off, buffer, bufferCount, len);
+            bufferCount += len;
+            return;
+        }
+
+        // write direct to gzip
+        writeToGZip(b, off, len);
+    }
+
+    public void writeToGZip(byte b[], int off, int len) throws IOException {
+
+        if (debug > 1) {
+            System.out.println("writeToGZip, len = " + len);
+        }
+        if (debug > 2) {
+            System.out.print("writeToGZip(");
+            System.out.write(b, off, len);
+            System.out.println(")");
+        }
+        if (gzipstream == null) {
+            if (debug > 1) {
+                System.out.println("new GZIPOutputStream");
+            }
+            response.addHeader("Content-Encoding", "gzip");
+            gzipstream = new GZIPOutputStream(output);
+        }
+        gzipstream.write(b, off, len);
+
+    }
+
+
+    // -------------------------------------------------------- Package Methods
+
+
+    /**
+     * Has this response stream been closed?
+     */
+    public boolean closed() {
+
+        return (this.closed);
+
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/examples/WEB-INF/classes/compressionFilters/CompressionServletResponseWrapper.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/examples/WEB-INF/classes/compressionFilters/CompressionServletResponseWrapper.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/examples/WEB-INF/classes/compressionFilters/CompressionServletResponseWrapper.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,276 @@
+/*
+* Copyright 2004 The Apache Software Foundation
+*
+* Licensed 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 compressionFilters;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+import java.util.Locale;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.ServletException;
+import javax.servlet.ServletOutputStream;
+import javax.servlet.ServletResponse;
+import javax.servlet.ServletResponseWrapper;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpServletResponseWrapper;
+
+/**
+ * Implementation of <b>HttpServletResponseWrapper</b> that works with
+ * the CompressionServletResponseStream implementation..
+ *
+ * @author Amy Roh
+ * @author Dmitri Valdin
+ * @version $Revision: 267129 $, $Date: 2004-03-18 10:40:35 -0600 (Thu, 18 Mar 2004) $
+ */
+
+public class CompressionServletResponseWrapper extends HttpServletResponseWrapper {
+
+    // ----------------------------------------------------- Constructor
+
+    /**
+     * Calls the parent constructor which creates a ServletResponse adaptor
+     * wrapping the given response object.
+     */
+
+    public CompressionServletResponseWrapper(HttpServletResponse response) {
+        super(response);
+        origResponse = response;
+        if (debug > 1) {
+            System.out.println("CompressionServletResponseWrapper constructor gets called");
+        }
+    }
+
+
+    // ----------------------------------------------------- Instance Variables
+
+    /**
+     * Original response
+     */
+
+    protected HttpServletResponse origResponse = null;
+
+    /**
+     * Descriptive information about this Response implementation.
+     */
+
+    protected static final String info = "CompressionServletResponseWrapper";
+
+    /**
+     * The ServletOutputStream that has been returned by
+     * <code>getOutputStream()</code>, if any.
+     */
+
+    protected ServletOutputStream stream = null;
+
+
+    /**
+     * The PrintWriter that has been returned by
+     * <code>getWriter()</code>, if any.
+     */
+
+    protected PrintWriter writer = null;
+
+    /**
+     * The threshold number to compress
+     */
+    protected int threshold = 0;
+
+    /**
+     * Debug level
+     */
+    private int debug = 0;
+
+    /**
+     * Content type
+     */
+    protected String contentType = null;
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Set content type
+     */
+    public void setContentType(String contentType) {
+        if (debug > 1) {
+            System.out.println("setContentType to "+contentType);
+        }
+        this.contentType = contentType;
+        origResponse.setContentType(contentType);
+    }
+
+
+    /**
+     * Set threshold number
+     */
+    public void setCompressionThreshold(int threshold) {
+        if (debug > 1) {
+            System.out.println("setCompressionThreshold to " + threshold);
+        }
+        this.threshold = threshold;
+    }
+
+
+    /**
+     * Set debug level
+     */
+    public void setDebugLevel(int debug) {
+        this.debug = debug;
+    }
+
+
+    /**
+     * Create and return a ServletOutputStream to write the content
+     * associated with this Response.
+     *
+     * @exception IOException if an input/output error occurs
+     */
+    public ServletOutputStream createOutputStream() throws IOException {
+        if (debug > 1) {
+            System.out.println("createOutputStream gets called");
+        }
+
+        CompressionResponseStream stream = new CompressionResponseStream(origResponse);
+        stream.setDebugLevel(debug);
+        stream.setBuffer(threshold);
+
+        return stream;
+
+    }
+
+
+    /**
+     * Finish a response.
+     */
+    public void finishResponse() {
+        try {
+            if (writer != null) {
+                writer.close();
+            } else {
+                if (stream != null)
+                    stream.close();
+            }
+        } catch (IOException e) {
+        }
+    }
+
+
+    // ------------------------------------------------ ServletResponse Methods
+
+
+    /**
+     * Flush the buffer and commit this response.
+     *
+     * @exception IOException if an input/output error occurs
+     */
+    public void flushBuffer() throws IOException {
+        if (debug > 1) {
+            System.out.println("flush buffer @ CompressionServletResponseWrapper");
+        }
+        ((CompressionResponseStream)stream).flush();
+
+    }
+
+    /**
+     * Return the servlet output stream associated with this Response.
+     *
+     * @exception IllegalStateException if <code>getWriter</code> has
+     *  already been called for this response
+     * @exception IOException if an input/output error occurs
+     */
+    public ServletOutputStream getOutputStream() throws IOException {
+
+        if (writer != null)
+            throw new IllegalStateException("getWriter() has already been called for this response");
+
+        if (stream == null)
+            stream = createOutputStream();
+        if (debug > 1) {
+            System.out.println("stream is set to "+stream+" in getOutputStream");
+        }
+
+        return (stream);
+
+    }
+
+    /**
+     * Return the writer associated with this Response.
+     *
+     * @exception IllegalStateException if <code>getOutputStream</code> has
+     *  already been called for this response
+     * @exception IOException if an input/output error occurs
+     */
+    public PrintWriter getWriter() throws IOException {
+
+        if (writer != null)
+            return (writer);
+
+        if (stream != null)
+            throw new IllegalStateException("getOutputStream() has already been called for this response");
+
+        stream = createOutputStream();
+        if (debug > 1) {
+            System.out.println("stream is set to "+stream+" in getWriter");
+        }
+        //String charset = getCharsetFromContentType(contentType);
+        String charEnc = origResponse.getCharacterEncoding();
+        if (debug > 1) {
+            System.out.println("character encoding is " + charEnc);
+        }
+        // HttpServletResponse.getCharacterEncoding() shouldn't return null
+        // according the spec, so feel free to remove that "if"
+        if (charEnc != null) {
+            writer = new PrintWriter(new OutputStreamWriter(stream, charEnc));
+        } else {
+            writer = new PrintWriter(stream);
+        }
+        
+        return (writer);
+
+    }
+
+
+    public void setContentLength(int length) {
+    }
+
+
+    /**
+     * Returns character from content type. This method was taken from tomcat.
+     * @author rajo
+     */
+    private static String getCharsetFromContentType(String type) {
+
+        if (type == null) {
+            return null;
+        }
+        int semi = type.indexOf(";");
+        if (semi == -1) {
+            return null;
+        }
+        String afterSemi = type.substring(semi + 1);
+        int charsetLocation = afterSemi.indexOf("charset=");
+        if(charsetLocation == -1) {
+            return null;
+        } else {
+            String afterCharset = afterSemi.substring(charsetLocation + 8);
+            String encoding = afterCharset.trim();
+            return encoding;
+        }
+    }
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/examples/WEB-INF/classes/filters/ExampleFilter.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/examples/WEB-INF/classes/filters/ExampleFilter.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/examples/WEB-INF/classes/filters/ExampleFilter.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,139 @@
+/*
+* Copyright 2004 The Apache Software Foundation
+*
+* Licensed 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 filters;
+
+
+import java.io.IOException;
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+
+
+/**
+ * Example filter that can be attached to either an individual servlet
+ * or to a URL pattern.  This filter performs the following functions:
+ * <ul>
+ * <li>Attaches itself as a request attribute, under the attribute name
+ *     defined by the value of the <code>attribute</code> initialization
+ *     parameter.</li>
+ * <li>Calculates the number of milliseconds required to perform the
+ *     servlet processing required by this request, including any
+ *     subsequently defined filters, and logs the result to the servlet
+ *     context log for this application.
+ * </ul>
+ *
+ * @author Craig McClanahan
+ * @version $Revision: 267129 $ $Date: 2004-03-18 10:40:35 -0600 (Thu, 18 Mar 2004) $
+ */
+
+public final class ExampleFilter implements Filter {
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The request attribute name under which we store a reference to ourself.
+     */
+    private String attribute = null;
+
+
+    /**
+     * The filter configuration object we are associated with.  If this value
+     * is null, this filter instance is not currently configured.
+     */
+    private FilterConfig filterConfig = null;
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Take this filter out of service.
+     */
+    public void destroy() {
+
+        this.attribute = null;
+        this.filterConfig = null;
+
+    }
+
+
+    /**
+     * Time the processing that is performed by all subsequent filters in the
+     * current filter stack, including the ultimately invoked servlet.
+     *
+     * @param request The servlet request we are processing
+     * @param result The servlet response we are creating
+     * @param chain The filter chain we are processing
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception ServletException if a servlet error occurs
+     */
+    public void doFilter(ServletRequest request, ServletResponse response,
+                         FilterChain chain)
+	throws IOException, ServletException {
+
+	// Store ourselves as a request attribute (if requested)
+	if (attribute != null)
+	    request.setAttribute(attribute, this);
+
+	// Time and log the subsequent processing
+	long startTime = System.currentTimeMillis();
+        chain.doFilter(request, response);
+	long stopTime = System.currentTimeMillis();
+	filterConfig.getServletContext().log
+	    (this.toString() + ": " + (stopTime - startTime) +
+	     " milliseconds");
+
+    }
+
+
+    /**
+     * Place this filter into service.
+     *
+     * @param filterConfig The filter configuration object
+     */
+    public void init(FilterConfig filterConfig) throws ServletException {
+
+	this.filterConfig = filterConfig;
+        this.attribute = filterConfig.getInitParameter("attribute");
+
+    }
+
+
+    /**
+     * Return a String representation of this object.
+     */
+    public String toString() {
+
+	if (filterConfig == null)
+	    return ("InvokerFilter()");
+	StringBuffer sb = new StringBuffer("InvokerFilter(");
+	sb.append(filterConfig);
+	sb.append(")");
+	return (sb.toString());
+
+    }
+
+
+}
+

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/examples/WEB-INF/classes/filters/RequestDumperFilter.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/examples/WEB-INF/classes/filters/RequestDumperFilter.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/examples/WEB-INF/classes/filters/RequestDumperFilter.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,200 @@
+/*
+* Copyright 2004 The Apache Software Foundation
+*
+* Licensed 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 filters;
+
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.sql.Timestamp;
+import java.util.Enumeration;
+import java.util.Locale;
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletRequest;
+
+
+/**
+ * Example filter that dumps interesting state information about a request
+ * to the associated servlet context log file, before allowing the servlet
+ * to process the request in the usual way.  This can be installed as needed
+ * to assist in debugging problems.
+ *
+ * @author Craig McClanahan
+ * @version $Revision: 267129 $ $Date: 2004-03-18 10:40:35 -0600 (Thu, 18 Mar 2004) $
+ */
+
+public final class RequestDumperFilter implements Filter {
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The filter configuration object we are associated with.  If this value
+     * is null, this filter instance is not currently configured.
+     */
+    private FilterConfig filterConfig = null;
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Take this filter out of service.
+     */
+    public void destroy() {
+
+        this.filterConfig = null;
+
+    }
+
+
+    /**
+     * Time the processing that is performed by all subsequent filters in the
+     * current filter stack, including the ultimately invoked servlet.
+     *
+     * @param request The servlet request we are processing
+     * @param result The servlet response we are creating
+     * @param chain The filter chain we are processing
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception ServletException if a servlet error occurs
+     */
+    public void doFilter(ServletRequest request, ServletResponse response,
+                         FilterChain chain)
+	throws IOException, ServletException {
+
+        if (filterConfig == null)
+	    return;
+
+	// Render the generic servlet request properties
+	StringWriter sw = new StringWriter();
+	PrintWriter writer = new PrintWriter(sw);
+	writer.println("Request Received at " +
+		       (new Timestamp(System.currentTimeMillis())));
+	writer.println(" characterEncoding=" + request.getCharacterEncoding());
+	writer.println("     contentLength=" + request.getContentLength());
+	writer.println("       contentType=" + request.getContentType());
+	writer.println("            locale=" + request.getLocale());
+	writer.print("           locales=");
+	Enumeration locales = request.getLocales();
+	boolean first = true;
+	while (locales.hasMoreElements()) {
+	    Locale locale = (Locale) locales.nextElement();
+	    if (first)
+	        first = false;
+	    else
+	        writer.print(", ");
+	    writer.print(locale.toString());
+	}
+	writer.println();
+	Enumeration names = request.getParameterNames();
+	while (names.hasMoreElements()) {
+	    String name = (String) names.nextElement();
+	    writer.print("         parameter=" + name + "=");
+	    String values[] = request.getParameterValues(name);
+	    for (int i = 0; i < values.length; i++) {
+	        if (i > 0)
+		    writer.print(", ");
+		writer.print(values[i]);
+	    }
+	    writer.println();
+	}
+	writer.println("          protocol=" + request.getProtocol());
+	writer.println("        remoteAddr=" + request.getRemoteAddr());
+	writer.println("        remoteHost=" + request.getRemoteHost());
+	writer.println("            scheme=" + request.getScheme());
+	writer.println("        serverName=" + request.getServerName());
+	writer.println("        serverPort=" + request.getServerPort());
+	writer.println("          isSecure=" + request.isSecure());
+
+	// Render the HTTP servlet request properties
+	if (request instanceof HttpServletRequest) {
+	    writer.println("---------------------------------------------");
+	    HttpServletRequest hrequest = (HttpServletRequest) request;
+	    writer.println("       contextPath=" + hrequest.getContextPath());
+	    Cookie cookies[] = hrequest.getCookies();
+            if (cookies == null)
+                cookies = new Cookie[0];
+	    for (int i = 0; i < cookies.length; i++) {
+	        writer.println("            cookie=" + cookies[i].getName() +
+			       "=" + cookies[i].getValue());
+	    }
+	    names = hrequest.getHeaderNames();
+	    while (names.hasMoreElements()) {
+	        String name = (String) names.nextElement();
+		String value = hrequest.getHeader(name);
+	        writer.println("            header=" + name + "=" + value);
+	    }
+	    writer.println("            method=" + hrequest.getMethod());
+	    writer.println("          pathInfo=" + hrequest.getPathInfo());
+	    writer.println("       queryString=" + hrequest.getQueryString());
+	    writer.println("        remoteUser=" + hrequest.getRemoteUser());
+	    writer.println("requestedSessionId=" +
+			   hrequest.getRequestedSessionId());
+	    writer.println("        requestURI=" + hrequest.getRequestURI());
+	    writer.println("       servletPath=" + hrequest.getServletPath());
+	}
+	writer.println("=============================================");
+
+	// Log the resulting string
+	writer.flush();
+	filterConfig.getServletContext().log(sw.getBuffer().toString());
+
+	// Pass control on to the next filter
+        chain.doFilter(request, response);
+
+    }
+
+
+    /**
+     * Place this filter into service.
+     *
+     * @param filterConfig The filter configuration object
+     */
+    public void init(FilterConfig filterConfig) throws ServletException {
+
+	this.filterConfig = filterConfig;
+
+    }
+
+
+    /**
+     * Return a String representation of this object.
+     */
+    public String toString() {
+
+	if (filterConfig == null)
+	    return ("RequestDumperFilter()");
+	StringBuffer sb = new StringBuffer("RequestDumperFilter(");
+	sb.append(filterConfig);
+	sb.append(")");
+	return (sb.toString());
+
+    }
+
+
+}
+

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/examples/WEB-INF/classes/filters/SetCharacterEncodingFilter.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/examples/WEB-INF/classes/filters/SetCharacterEncodingFilter.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/examples/WEB-INF/classes/filters/SetCharacterEncodingFilter.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,171 @@
+/*
+* Copyright 2004 The Apache Software Foundation
+*
+* Licensed 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 filters;
+
+
+import java.io.IOException;
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.UnavailableException;
+
+
+/**
+ * <p>Example filter that sets the character encoding to be used in parsing the
+ * incoming request, either unconditionally or only if the client did not
+ * specify a character encoding.  Configuration of this filter is based on
+ * the following initialization parameters:</p>
+ * <ul>
+ * <li><strong>encoding</strong> - The character encoding to be configured
+ *     for this request, either conditionally or unconditionally based on
+ *     the <code>ignore</code> initialization parameter.  This parameter
+ *     is required, so there is no default.</li>
+ * <li><strong>ignore</strong> - If set to "true", any character encoding
+ *     specified by the client is ignored, and the value returned by the
+ *     <code>selectEncoding()</code> method is set.  If set to "false,
+ *     <code>selectEncoding()</code> is called <strong>only</strong> if the
+ *     client has not already specified an encoding.  By default, this
+ *     parameter is set to "true".</li>
+ * </ul>
+ *
+ * <p>Although this filter can be used unchanged, it is also easy to
+ * subclass it and make the <code>selectEncoding()</code> method more
+ * intelligent about what encoding to choose, based on characteristics of
+ * the incoming request (such as the values of the <code>Accept-Language</code>
+ * and <code>User-Agent</code> headers, or a value stashed in the current
+ * user's session.</p>
+ *
+ * @author Craig McClanahan
+ * @version $Revision: 267129 $ $Date: 2004-03-18 10:40:35 -0600 (Thu, 18 Mar 2004) $
+ */
+
+public class SetCharacterEncodingFilter implements Filter {
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The default character encoding to set for requests that pass through
+     * this filter.
+     */
+    protected String encoding = null;
+
+
+    /**
+     * The filter configuration object we are associated with.  If this value
+     * is null, this filter instance is not currently configured.
+     */
+    protected FilterConfig filterConfig = null;
+
+
+    /**
+     * Should a character encoding specified by the client be ignored?
+     */
+    protected boolean ignore = true;
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Take this filter out of service.
+     */
+    public void destroy() {
+
+        this.encoding = null;
+        this.filterConfig = null;
+
+    }
+
+
+    /**
+     * Select and set (if specified) the character encoding to be used to
+     * interpret request parameters for this request.
+     *
+     * @param request The servlet request we are processing
+     * @param result The servlet response we are creating
+     * @param chain The filter chain we are processing
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception ServletException if a servlet error occurs
+     */
+    public void doFilter(ServletRequest request, ServletResponse response,
+                         FilterChain chain)
+	throws IOException, ServletException {
+
+        // Conditionally select and set the character encoding to be used
+        if (ignore || (request.getCharacterEncoding() == null)) {
+            String encoding = selectEncoding(request);
+            if (encoding != null)
+                request.setCharacterEncoding(encoding);
+        }
+
+	// Pass control on to the next filter
+        chain.doFilter(request, response);
+
+    }
+
+
+    /**
+     * Place this filter into service.
+     *
+     * @param filterConfig The filter configuration object
+     */
+    public void init(FilterConfig filterConfig) throws ServletException {
+
+	this.filterConfig = filterConfig;
+        this.encoding = filterConfig.getInitParameter("encoding");
+        String value = filterConfig.getInitParameter("ignore");
+        if (value == null)
+            this.ignore = true;
+        else if (value.equalsIgnoreCase("true"))
+            this.ignore = true;
+        else if (value.equalsIgnoreCase("yes"))
+            this.ignore = true;
+        else
+            this.ignore = false;
+
+    }
+
+
+    // ------------------------------------------------------ Protected Methods
+
+
+    /**
+     * Select an appropriate character encoding to be used, based on the
+     * characteristics of the current request and/or filter initialization
+     * parameters.  If no character encoding should be set, return
+     * <code>null</code>.
+     * <p>
+     * The default implementation unconditionally returns the value configured
+     * by the <strong>encoding</strong> initialization parameter for this
+     * filter.
+     *
+     * @param request The servlet request we are processing
+     */
+    protected String selectEncoding(ServletRequest request) {
+
+        return (this.encoding);
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/examples/WEB-INF/classes/listeners/ContextListener.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/examples/WEB-INF/classes/listeners/ContextListener.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/examples/WEB-INF/classes/listeners/ContextListener.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,155 @@
+/*
+* Copyright 2004 The Apache Software Foundation
+*
+* Licensed 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 listeners;
+
+
+import javax.servlet.ServletContext;
+import javax.servlet.ServletContextAttributeEvent;
+import javax.servlet.ServletContextAttributeListener;
+import javax.servlet.ServletContextEvent;
+import javax.servlet.ServletContextListener;
+
+
+/**
+ * Example listener for context-related application events, which were
+ * introduced in the 2.3 version of the Servlet API.  This listener
+ * merely documents the occurrence of such events in the application log
+ * associated with our servlet context.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 267129 $ $Date: 2004-03-18 10:40:35 -0600 (Thu, 18 Mar 2004) $
+ */
+
+public final class ContextListener
+    implements ServletContextAttributeListener, ServletContextListener {
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The servlet context with which we are associated.
+     */
+    private ServletContext context = null;
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Record the fact that a servlet context attribute was added.
+     *
+     * @param event The servlet context attribute event
+     */
+    public void attributeAdded(ServletContextAttributeEvent event) {
+
+	log("attributeAdded('" + event.getName() + "', '" +
+	    event.getValue() + "')");
+
+    }
+
+
+    /**
+     * Record the fact that a servlet context attribute was removed.
+     *
+     * @param event The servlet context attribute event
+     */
+    public void attributeRemoved(ServletContextAttributeEvent event) {
+
+	log("attributeRemoved('" + event.getName() + "', '" +
+	    event.getValue() + "')");
+
+    }
+
+
+    /**
+     * Record the fact that a servlet context attribute was replaced.
+     *
+     * @param event The servlet context attribute event
+     */
+    public void attributeReplaced(ServletContextAttributeEvent event) {
+
+	log("attributeReplaced('" + event.getName() + "', '" +
+	    event.getValue() + "')");
+
+    }
+
+
+    /**
+     * Record the fact that this web application has been destroyed.
+     *
+     * @param event The servlet context event
+     */
+    public void contextDestroyed(ServletContextEvent event) {
+
+	log("contextDestroyed()");
+	this.context = null;
+
+    }
+
+
+    /**
+     * Record the fact that this web application has been initialized.
+     *
+     * @param event The servlet context event
+     */
+    public void contextInitialized(ServletContextEvent event) {
+
+	this.context = event.getServletContext();
+	log("contextInitialized()");
+
+    }
+
+
+    // -------------------------------------------------------- Private Methods
+
+
+    /**
+     * Log a message to the servlet context application log.
+     *
+     * @param message Message to be logged
+     */
+    private void log(String message) {
+
+	if (context != null)
+	    context.log("ContextListener: " + message);
+	else
+	    System.out.println("ContextListener: " + message);
+
+    }
+
+
+    /**
+     * Log a message and associated exception to the servlet context
+     * application log.
+     *
+     * @param message Message to be logged
+     * @param throwable Exception to be logged
+     */
+    private void log(String message, Throwable throwable) {
+
+	if (context != null)
+	    context.log("ContextListener: " + message, throwable);
+	else {
+	    System.out.println("ContextListener: " + message);
+	    throwable.printStackTrace(System.out);
+	}
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/examples/WEB-INF/classes/listeners/SessionListener.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/examples/WEB-INF/classes/listeners/SessionListener.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/examples/WEB-INF/classes/listeners/SessionListener.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,182 @@
+/*
+* Copyright 2004 The Apache Software Foundation
+*
+* Licensed 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 listeners;
+
+
+import javax.servlet.ServletContext;
+import javax.servlet.ServletContextEvent;
+import javax.servlet.ServletContextListener;
+import javax.servlet.http.HttpSessionAttributeListener;
+import javax.servlet.http.HttpSessionBindingEvent;
+import javax.servlet.http.HttpSessionEvent;
+import javax.servlet.http.HttpSessionListener;
+
+
+/**
+ * Example listener for context-related application events, which were
+ * introduced in the 2.3 version of the Servlet API.  This listener
+ * merely documents the occurrence of such events in the application log
+ * associated with our servlet context.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision: 267129 $ $Date: 2004-03-18 10:40:35 -0600 (Thu, 18 Mar 2004) $
+ */
+
+public final class SessionListener
+    implements ServletContextListener,
+	       HttpSessionAttributeListener, HttpSessionListener {
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The servlet context with which we are associated.
+     */
+    private ServletContext context = null;
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Record the fact that a servlet context attribute was added.
+     *
+     * @param event The session attribute event
+     */
+    public void attributeAdded(HttpSessionBindingEvent event) {
+
+	log("attributeAdded('" + event.getSession().getId() + "', '" +
+	    event.getName() + "', '" + event.getValue() + "')");
+
+    }
+
+
+    /**
+     * Record the fact that a servlet context attribute was removed.
+     *
+     * @param event The session attribute event
+     */
+    public void attributeRemoved(HttpSessionBindingEvent event) {
+
+	log("attributeRemoved('" + event.getSession().getId() + "', '" +
+	    event.getName() + "', '" + event.getValue() + "')");
+
+    }
+
+
+    /**
+     * Record the fact that a servlet context attribute was replaced.
+     *
+     * @param event The session attribute event
+     */
+    public void attributeReplaced(HttpSessionBindingEvent event) {
+
+	log("attributeReplaced('" + event.getSession().getId() + "', '" +
+	    event.getName() + "', '" + event.getValue() + "')");
+
+    }
+
+
+    /**
+     * Record the fact that this web application has been destroyed.
+     *
+     * @param event The servlet context event
+     */
+    public void contextDestroyed(ServletContextEvent event) {
+
+	log("contextDestroyed()");
+	this.context = null;
+
+    }
+
+
+    /**
+     * Record the fact that this web application has been initialized.
+     *
+     * @param event The servlet context event
+     */
+    public void contextInitialized(ServletContextEvent event) {
+
+	this.context = event.getServletContext();
+	log("contextInitialized()");
+
+    }
+
+
+    /**
+     * Record the fact that a session has been created.
+     *
+     * @param event The session event
+     */
+    public void sessionCreated(HttpSessionEvent event) {
+
+	log("sessionCreated('" + event.getSession().getId() + "')");
+
+    }
+
+
+    /**
+     * Record the fact that a session has been destroyed.
+     *
+     * @param event The session event
+     */
+    public void sessionDestroyed(HttpSessionEvent event) {
+
+	log("sessionDestroyed('" + event.getSession().getId() + "')");
+
+    }
+
+
+    // -------------------------------------------------------- Private Methods
+
+
+    /**
+     * Log a message to the servlet context application log.
+     *
+     * @param message Message to be logged
+     */
+    private void log(String message) {
+
+	if (context != null)
+	    context.log("SessionListener: " + message);
+	else
+	    System.out.println("SessionListener: " + message);
+
+    }
+
+
+    /**
+     * Log a message and associated exception to the servlet context
+     * application log.
+     *
+     * @param message Message to be logged
+     * @param throwable Exception to be logged
+     */
+    private void log(String message, Throwable throwable) {
+
+	if (context != null)
+	    context.log("SessionListener: " + message, throwable);
+	else {
+	    System.out.println("SessionListener: " + message);
+	    throwable.printStackTrace(System.out);
+	}
+
+    }
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/examples/WEB-INF/classes/util/HTMLFilter.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/examples/WEB-INF/classes/util/HTMLFilter.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/examples/WEB-INF/classes/util/HTMLFilter.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,68 @@
+/*
+* Copyright 2004 The Apache Software Foundation
+*
+* Licensed 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 util;
+
+/**
+ * HTML filter utility.
+ *
+ * @author Craig R. McClanahan
+ * @author Tim Tye
+ * @version $Revision: 267129 $ $Date: 2004-03-18 10:40:35 -0600 (Thu, 18 Mar 2004) $
+ */
+
+public final class HTMLFilter {
+
+
+    /**
+     * Filter the specified message string for characters that are sensitive
+     * in HTML.  This avoids potential attacks caused by including JavaScript
+     * codes in the request URL that is often reported in error messages.
+     *
+     * @param message The message string to be filtered
+     */
+    public static String filter(String message) {
+
+        if (message == null)
+            return (null);
+
+        char content[] = new char[message.length()];
+        message.getChars(0, message.length(), content, 0);
+        StringBuffer result = new StringBuffer(content.length + 50);
+        for (int i = 0; i < content.length; i++) {
+            switch (content[i]) {
+            case '<':
+                result.append("&lt;");
+                break;
+            case '>':
+                result.append("&gt;");
+                break;
+            case '&':
+                result.append("&amp;");
+                break;
+            case '"':
+                result.append("&quot;");
+                break;
+            default:
+                result.append(content[i]);
+            }
+        }
+        return (result.toString());
+
+    }
+
+
+}
+

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/examples/WEB-INF/web.xml
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/examples/WEB-INF/web.xml	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/examples/WEB-INF/web.xml	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,249 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!--
+  Copyright 2004 The Apache Software Foundation
+
+  Licensed 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.
+-->
+
+<!DOCTYPE web-app
+    PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
+    "http://java.sun.com/dtd/web-app_2_3.dtd">
+
+<web-app>
+
+    <display-name>Servlet 2.4 Examples</display-name>
+    <description>
+      Servlet 2.4 Examples.
+    </description>
+
+    <!-- Define servlet-mapped and path-mapped example filters -->
+    <filter>
+        <filter-name>Servlet Mapped Filter</filter-name>
+        <filter-class>filters.ExampleFilter</filter-class>
+	<init-param>
+	    <param-name>attribute</param-name>
+	    <param-value>filters.ExampleFilter.SERVLET_MAPPED</param-value>
+	</init-param>
+    </filter>
+    <filter>
+        <filter-name>Path Mapped Filter</filter-name>
+        <filter-class>filters.ExampleFilter</filter-class>
+	<init-param>
+	    <param-name>attribute</param-name>
+	    <param-value>filters.ExampleFilter.PATH_MAPPED</param-value>
+	</init-param>
+    </filter>
+    <filter>
+        <filter-name>Request Dumper Filter</filter-name>
+        <filter-class>filters.RequestDumperFilter</filter-class>
+    </filter>
+
+    <!-- Example filter to set character encoding on each request -->
+    <filter>
+        <filter-name>Set Character Encoding</filter-name>
+        <filter-class>filters.SetCharacterEncodingFilter</filter-class>
+        <init-param>
+            <param-name>encoding</param-name>
+            <param-value>EUC_JP</param-value>
+        </init-param>
+    </filter>
+
+    <filter>
+        <filter-name>Compression Filter</filter-name>
+        <filter-class>compressionFilters.CompressionFilter</filter-class>
+
+        <init-param>
+          <param-name>compressionThreshold</param-name>
+          <param-value>10</param-value>
+        </init-param>
+        <init-param>
+          <param-name>debug</param-name>
+          <param-value>0</param-value>
+        </init-param>
+    </filter>
+
+    <!-- Define filter mappings for the defined filters -->
+    <filter-mapping>
+        <filter-name>Servlet Mapped Filter</filter-name>
+	<servlet-name>invoker</servlet-name>
+    </filter-mapping>
+    <filter-mapping>
+        <filter-name>Path Mapped Filter</filter-name>
+	<url-pattern>/servlet/*</url-pattern>
+    </filter-mapping>
+
+
+<!-- Example filter mapping to apply the "Set Character Encoding" filter
+     to *all* requests processed by this web application -->
+<!--
+    <filter-mapping>
+        <filter-name>Set Character Encoding</filter-name>
+        <url-pattern>/*</url-pattern>
+    </filter-mapping>
+-->
+
+<!--
+    <filter-mapping>
+      <filter-name>Compression Filter</filter-name>
+      <url-pattern>/CompressionTest</url-pattern>
+    </filter-mapping>
+-->
+
+<!--
+    <filter-mapping>
+        <filter-name>Request Dumper Filter</filter-name>
+        <url-pattern>/*</url-pattern>
+    </filter-mapping>
+-->
+
+    <!-- Define example application events listeners -->
+    <listener>
+        <listener-class>listeners.ContextListener</listener-class>
+    </listener>
+    <listener>
+        <listener-class>listeners.SessionListener</listener-class>
+    </listener>
+
+    <!-- Define servlets that are included in the example application -->
+
+    <servlet>
+        <servlet-name>CompressionFilterTestServlet</servlet-name>
+        <servlet-class>compressionFilters.CompressionFilterTestServlet</servlet-class>
+    </servlet>
+    <servlet>
+        <servlet-name>HelloWorldExample</servlet-name>
+        <servlet-class>HelloWorldExample</servlet-class>
+    </servlet>
+    <servlet>
+        <servlet-name>RequestInfoExample</servlet-name>
+        <servlet-class>RequestInfoExample</servlet-class>
+    </servlet>
+    <servlet>
+        <servlet-name>RequestHeaderExample</servlet-name>
+        <servlet-class>RequestHeaderExample</servlet-class>
+    </servlet>
+    <servlet>
+        <servlet-name>RequestParamExample</servlet-name>
+        <servlet-class>RequestParamExample</servlet-class>
+    </servlet>
+    <servlet>
+        <servlet-name>CookieExample</servlet-name>
+        <servlet-class>CookieExample</servlet-class>
+    </servlet>
+    <servlet>
+        <servlet-name>SessionExample</servlet-name>
+        <servlet-class>SessionExample</servlet-class>
+    </servlet>
+
+    <servlet-mapping>
+        <servlet-name>CompressionFilterTestServlet</servlet-name>
+        <url-pattern>/CompressionTest</url-pattern>
+    </servlet-mapping>
+    <servlet-mapping>
+        <servlet-name>HelloWorldExample</servlet-name>
+        <url-pattern>/servlet/HelloWorldExample</url-pattern>
+    </servlet-mapping>
+    <servlet-mapping>
+        <servlet-name>RequestInfoExample</servlet-name>
+        <url-pattern>/servlet/RequestInfoExample/*</url-pattern>
+    </servlet-mapping>
+    <servlet-mapping>
+        <servlet-name>RequestHeaderExample</servlet-name>
+        <url-pattern>/servlet/RequestHeaderExample</url-pattern>
+    </servlet-mapping>
+    <servlet-mapping>
+        <servlet-name>RequestParamExample</servlet-name>
+        <url-pattern>/servlet/RequestParamExample</url-pattern>
+    </servlet-mapping>
+    <servlet-mapping>
+        <servlet-name>CookieExample</servlet-name>
+        <url-pattern>/servlet/CookieExample</url-pattern>
+    </servlet-mapping>
+    <servlet-mapping>
+        <servlet-name>SessionExample</servlet-name>
+        <url-pattern>/servlet/SessionExample</url-pattern>
+    </servlet-mapping>
+
+    <security-constraint>
+      <display-name>Example Security Constraint</display-name>
+      <web-resource-collection>
+         <web-resource-name>Protected Area</web-resource-name>
+	 <!-- Define the context-relative URL(s) to be protected -->
+         <url-pattern>/jsp/security/protected/*</url-pattern>
+	 <!-- If you list http methods, only those methods are protected -->
+	 <http-method>DELETE</http-method>
+         <http-method>GET</http-method>
+         <http-method>POST</http-method>
+	 <http-method>PUT</http-method>
+      </web-resource-collection>
+      <auth-constraint>
+         <!-- Anyone with one of the listed roles may access this area -->
+         <role-name>tomcat</role-name>
+	 <role-name>role1</role-name>
+      </auth-constraint>
+    </security-constraint>
+
+    <!-- Default login configuration uses form-based authentication -->
+    <login-config>
+      <auth-method>FORM</auth-method>
+      <realm-name>Example Form-Based Authentication Area</realm-name>
+      <form-login-config>
+        <form-login-page>/jsp/security/protected/login.jsp</form-login-page>
+        <form-error-page>/jsp/security/protected/error.jsp</form-error-page>
+      </form-login-config>
+    </login-config>
+
+    <!-- Security roles referenced by this web application -->
+    <security-role>
+      <role-name>role1</role-name>
+    </security-role>
+    <security-role>
+      <role-name>tomcat</role-name>
+    </security-role>
+
+    <!-- Environment entry examples -->
+    <!--env-entry>
+      <env-entry-description>
+         The maximum number of tax exemptions allowed to be set.
+      </env-entry-description>
+      <env-entry-name>maxExemptions</env-entry-name>
+      <env-entry-value>15</env-entry-value>
+      <env-entry-type>java.lang.Integer</env-entry-type>
+    </env-entry-->
+    <env-entry>
+      <env-entry-name>minExemptions</env-entry-name>
+      <env-entry-value>1</env-entry-value>
+      <env-entry-type>java.lang.Integer</env-entry-type>
+    </env-entry>
+    <env-entry>
+      <env-entry-name>foo/name1</env-entry-name>
+      <env-entry-value>value1</env-entry-value>
+      <env-entry-type>java.lang.String</env-entry-type>
+    </env-entry>
+    <env-entry>
+      <env-entry-name>foo/bar/name2</env-entry-name>
+      <env-entry-value>true</env-entry-value>
+      <env-entry-type>java.lang.Boolean</env-entry-type>
+    </env-entry>
+    <env-entry>
+      <env-entry-name>name3</env-entry-name>
+      <env-entry-value>1</env-entry-value>
+      <env-entry-type>java.lang.Integer</env-entry-type>
+    </env-entry>
+    <env-entry>
+      <env-entry-name>foo/name4</env-entry-name>
+      <env-entry-value>10</env-entry-value>
+      <env-entry-type>java.lang.Integer</env-entry-type>
+    </env-entry>
+
+</web-app>

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/examples/cookies.html
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/examples/cookies.html	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/examples/cookies.html	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,60 @@
+<!--
+  Copyright 2004 The Apache Software Foundation
+
+  Licensed 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.
+-->
+<html>
+<head>
+<title>Untitled Document</title>
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+</head>
+
+<body bgcolor="#FFFFFF">
+<p><font color="#0000FF"><a href="servlet/CookieExample"><img src="images/execute.gif" align="right" border="0"></a><a href="index.html"><img src="images/return.gif" width="24" height="24" align="right" border="0"></a></font></p>
+<h3>Source Code for Cookie Example<font color="#0000FF"><br>
+  </font> </h3>
+<font color="#0000FF"></font> 
+<pre><font color="#0000FF">import</font> java.io.*;
+<font color="#0000FF">import</font> javax.servlet.*;
+<font color="#0000FF">import</font> javax.servlet.http.*;
+
+<font color="#0000FF">public class</font> CookieExample <font color="#0000FF">extends</font> HttpServlet {
+
+    <font color="#0000FF">public void</font> doGet(HttpServletRequest request, HttpServletResponse response)
+    <font color="#0000FF">throws</font> IOException, ServletException
+    {
+        response.setContentType(&quot;<font color="#009900">text/html</font>&quot;);
+        PrintWriter out = response.getWriter();
+        
+        <font color="#CC0000">// print out cookies</font>
+
+        Cookie[] cookies = request.getCookies();
+        for (int i = 0; i &lt; cookies.length; i++) {
+            Cookie c = cookies[i];
+            String name = c.getName();
+            String value = c.getValue();
+            out.println(name + &quot;<font color="#009900"> = </font>&quot; + value);
+        }
+
+        <font color="#CC0000">// set a cookie</font>
+
+        String name = request.getParameter(&quot;<font color="#009900">cookieName</font>&quot;);
+        if (name != null &amp;&amp; name.length() &gt; 0) {
+            String value = request.getParameter(&quot;<font color="#009900">cookieValue</font>&quot;);
+            Cookie c = new Cookie(name, value);
+            response.addCookie(c);
+        }
+    }
+}</pre>
+</body>
+</html>

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/examples/helloworld.html
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/examples/helloworld.html	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/examples/helloworld.html	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,49 @@
+<!--
+  Copyright 2004 The Apache Software Foundation
+
+  Licensed 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.
+-->
+<html>
+<head>
+<title>Untitled Document</title>
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+</head>
+
+<body bgcolor="#FFFFFF">
+<p><font color="#0000FF"><a href="servlet/HelloWorldExample"><img src="images/execute.gif" align="right" border="0"></a><a href="index.html"><img src="images/return.gif" width="24" height="24" align="right" border="0"></a></font></p>
+<h3>Source Code for HelloWorld Example<font color="#0000FF"><br>
+  </font> </h3>
+<font color="#0000FF"></font>
+<pre><font color="#0000FF">import</font> java.io.*;
+<font color="#0000FF">import</font> javax.servlet.*;
+<font color="#0000FF">import</font> javax.servlet.http.*;
+
+<font color="#0000FF">public class</font> HelloWorld <font color="#0000FF">extends</font> HttpServlet {
+
+    <font color="#0000FF">public void</font> doGet(HttpServletRequest request, HttpServletResponse response)
+    <font color="#0000FF">throws</font> IOException, ServletException
+    {
+        response.setContentType(&quot;<font color="#009900">text/html</font>&quot;);
+        PrintWriter out = response.getWriter();
+        out.println(&quot;<font color="#009900">&lt;html&gt;</font>&quot;);
+        out.println(&quot;<font color="#009900">&lt;head&gt;</font>&quot;);
+        out.println(&quot;<font color="#009900">&lt;title&gt;Hello World!&lt;/title&gt;</font>&quot;);
+        out.println(&quot;<font color="#009900">&lt;/head&gt;</font>&quot;);
+        out.println(&quot;<font color="#009900">&lt;body&gt;</font>&quot;);
+        out.println(&quot;<font color="#009900">&lt;h1&gt;Hello World!&lt;/h1&gt;</font>&quot;);
+        out.println(&quot;<font color="#009900">&lt;/body&gt;</font>&quot;);
+        out.println(&quot;<font color="#009900">&lt;/html&gt;</font>&quot;);
+    }
+}</pre>
+</body>
+</html>

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/examples/images/code.gif
===================================================================
(Binary files differ)


Property changes on: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/examples/images/code.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/examples/images/execute.gif
===================================================================
(Binary files differ)


Property changes on: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/examples/images/execute.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/examples/images/return.gif
===================================================================
(Binary files differ)


Property changes on: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/examples/images/return.gif
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/examples/index.html
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/examples/index.html	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/examples/index.html	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,120 @@
+<!--
+  Copyright 2004 The Apache Software Foundation
+
+  Licensed 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.
+-->
+<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
+<html>
+<head>
+   <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+   <meta name="GENERATOR" content="Mozilla/4.61 [en] (WinNT; I) [Netscape]">
+   <meta name="Author" content="Anil K. Vijendran">
+   <title>Servlet Examples</title>
+</head>
+<body bgcolor="#FFFFFF">
+<b><font face="Arial, Helvetica, sans-serif"><font size=+2>Servlet
+Examples with Code</font></font></b>
+<p>This is a collection of examples which demonstrate some of the more
+frequently used parts of the Servlet API. Familiarity with the Java(tm)
+Programming Language is assumed.
+<p>These examples will only work when viewed via an http URL. They will
+not work if you are viewing these pages via a "file://..." URL. Please
+refer to the <i>README</i> file provide with this Tomcat release regarding
+how to configure and start the provided web server.
+<p>Wherever you see a form, enter some data and see how the servlet reacts.
+When playing with the Cookie and Session Examples, jump back to the Headers
+Example to see exactly what your browser is sending the server.
+<p>To navigate your way through the examples, the following icons will
+help:
+<br>&nbsp;
+<table BORDER=0 CELLSPACING=5 WIDTH="85%" >
+<tr VALIGN=TOP>
+<td WIDTH="30"><img SRC="images/execute.gif" ></td>
+
+<td>Execute the example</td>
+</tr>
+
+<tr VALIGN=TOP>
+<td WIDTH="30"><img SRC="images/code.gif" height=24 width=24></td>
+
+<td>Look at the source code for the example</td>
+</tr>
+
+<tr VALIGN=TOP>
+<td WIDTH="30"><img SRC="images/return.gif" height=24 width=24></td>
+
+<td>Return to this screen</td>
+</tr>
+</table>
+
+<p>Tip: To see the cookie interactions with your browser, try turning on
+the "notify when setting a cookie" option in your browser preferences.
+This will let you see when a session is created and give some feedback
+when looking at the cookie demo.
+<br>&nbsp;
+<table BORDER=0 CELLSPACING=5 WIDTH="85%" >
+<tr VALIGN=TOP>
+<td>Hello World</td>
+
+<td VALIGN=TOP WIDTH="30%"><a href="servlet/HelloWorldExample"><img SRC="images/execute.gif" HSPACE=4 BORDER=0  align=TOP></a><a href="servlet/HelloWorldExample">Execute</a></td>
+
+<td WIDTH="30%"><a href="helloworld.html"><img SRC="images/code.gif" HSPACE=4 BORDER=0 height=24 width=24 align=TOP></a><a href="helloworld.html">Source</a></td>
+</tr>
+
+<tr VALIGN=TOP>
+<td>Request Info</td>
+
+<td WIDTH="30%"><a href="servlet/RequestInfoExample"><img SRC="images/execute.gif" HSPACE=4 BORDER=0  align=TOP></a><a href="servlet/RequestInfoExample">Execute</a></td>
+
+<td WIDTH="30%"><a href="reqinfo.html"><img SRC="images/code.gif" HSPACE=4 BORDER=0 height=24 width=24 align=TOP></a><a href="reqinfo.html">Source</a></td>
+</tr>
+
+<tr VALIGN=TOP>
+<td>Request Headers</td>
+
+<td WIDTH="30%"><a href="servlet/RequestHeaderExample"><img SRC="images/execute.gif" HSPACE=4 BORDER=0  align=TOP></a><a href="servlet/RequestHeaderExample">Execute</a></td>
+
+<td WIDTH="30%"><a href="reqheaders.html"><img SRC="images/code.gif" HSPACE=4 BORDER=0 height=24 width=24 align=TOP></a><a href="reqheaders.html">Source</a></td>
+</tr>
+
+<tr VALIGN=TOP>
+<td>Request Parameters</td>
+
+<td WIDTH="30%"><a href="servlet/RequestParamExample"><img SRC="images/execute.gif" HSPACE=4 BORDER=0  align=TOP></a><a href="servlet/RequestParamExample">Execute</a></td>
+
+<td WIDTH="30%"><a href="reqparams.html"><img SRC="images/code.gif" HSPACE=4 BORDER=0 height=24 width=24 align=TOP></a><a href="reqparams.html">Source</a></td>
+</tr>
+
+<tr VALIGN=TOP>
+<td>Cookies</td>
+
+<td WIDTH="30%"><a href="servlet/CookieExample"><img SRC="images/execute.gif" HSPACE=4 BORDER=0  align=TOP></a><a href="servlet/CookieExample">Execute</a></td>
+
+<td WIDTH="30%"><a href="cookies.html"><img SRC="images/code.gif" HSPACE=4 BORDER=0 height=24 width=24 align=TOP></a><a href="cookies.html">Source</a></td>
+</tr>
+
+<tr VALIGN=TOP>
+<td>Sessions</td>
+
+<td WIDTH="30%"><a href="servlet/SessionExample"><img SRC="images/execute.gif" HSPACE=4 BORDER=0  align=TOP></a><a href="servlet/SessionExample">Execute</a></td>
+
+<td WIDTH="30%"><a href="sessions.html"><img SRC="images/code.gif" HSPACE=4 BORDER=0 height=24 width=24 align=TOP></a><a href="sessions.html">Source</a></td>
+</tr>
+</table>
+
+<p>Note: The source code for these examples does not contain all of the
+source code that is actually in the example, only the important sections
+of code. Code not important to understand the example has been removed
+for clarity.
+</body>
+</html>

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/examples/reqheaders.html
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/examples/reqheaders.html	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/examples/reqheaders.html	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,48 @@
+<!--
+  Copyright 2004 The Apache Software Foundation
+
+  Licensed 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.
+-->
+<html>
+<head>
+<title>Untitled Document</title>
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+</head>
+
+<body bgcolor="#FFFFFF">
+<p><font color="#0000FF"><a href="servlet/RequestHeaderExample"><img src="images/execute.gif" align="right" border="0"></a><a href="index.html"><img src="images/return.gif" width="24" height="24" align="right" border="0"></a></font></p>
+<h3>Source Code for RequestHeader Example<font color="#0000FF"><br>
+  </font> </h3>
+<font color="#0000FF"></font>
+<pre><font color="#0000FF">import</font> java.io.*;
+<font color="#0000FF">import</font> java.util.*;
+<font color="#0000FF">import</font> javax.servlet.*;
+<font color="#0000FF">import</font> javax.servlet.http.*;
+
+<font color="#0000FF">public class</font> RequestHeaderExample <font color="#0000FF">extends</font> HttpServlet {
+
+    <font color="#0000FF">public void</font> doGet(HttpServletRequest request, HttpServletResponse response)
+    <font color="#0000FF">throws</font> IOException, ServletException
+    {
+        response.setContentType(&quot;<font color="#009900">text/html</font>&quot;);
+        PrintWriter out = response.getWriter();
+        Enumeration e = request.getHeaderNames();
+        while (e.hasMoreElements()) {
+            String name = (String)e.nextElement();
+            String value = request.getHeader(name);
+            out.println(name + &quot;<font color="#009900"> = </font>&quot; + value);
+        }
+    }
+}</pre>
+</body>
+</html>

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/examples/reqinfo.html
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/examples/reqinfo.html	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/examples/reqinfo.html	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,67 @@
+<!--
+  Copyright 2004 The Apache Software Foundation
+
+  Licensed 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.
+-->
+<html>
+<head>
+<title>Untitled Document</title>
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+</head>
+
+<body bgcolor="#FFFFFF">
+<p><font color="#0000FF"><a href="servlet/RequestInfoExample"><img src="images/execute.gif" align="right" border="0"></a><a href="index.html"><img src="images/return.gif" width="24" height="24" align="right" border="0"></a></font></p>
+<h3>Source Code for Request Info Example<font color="#0000FF"><br>
+  </font> </h3>
+<font color="#0000FF"></font> 
+<pre><font color="#0000FF">import</font> java.io.*;
+<font color="#0000FF">import</font> javax.servlet.*;
+<font color="#0000FF">import</font> javax.servlet.http.*;
+
+<font color="#0000FF">public class</font> RequestInfo <font color="#0000FF">extends</font> HttpServlet {
+
+    <font color="#0000FF">public void</font> doGet(HttpServletRequest request, HttpServletResponse response)
+    <font color="#0000FF">throws</font> IOException, ServletException
+    {
+        response.setContentType(&quot;<font color="#009900">text/html</font>&quot;);
+        PrintWriter out = response.getWriter();
+        out.println(&quot;<font color="#009900">&lt;html&gt;</font>&quot;);
+        out.println(&quot;<font color="#009900">&lt;body&gt;</font>&quot;);
+        out.println(&quot;<font color="#009900">&lt;head&gt;</font>&quot;);
+        out.println(&quot;<font color="#009900">&lt;title&gt;Request Information Example&lt;/title&gt;</font>&quot;);
+        out.println(&quot;<font color="#009900">&lt;/head&gt;</font>&quot;);
+        out.println(&quot;<font color="#009900">&lt;body&gt;</font>&quot;);
+        out.println(&quot;<font color="#009900">&lt;h3&gt;Request Information Example&lt;/h3&gt;</font>&quot;);
+        out.println(&quot;<font color="#009900">Method: </font>&quot; + request.getMethod());
+        out.println(&quot;<font color="#009900">Request URI: </font>&quot; + request.getRequestURI());
+        out.println(&quot;<font color="#009900">Protocol: </font>&quot; + request.getProtocol());
+        out.println(&quot;<font color="#009900">PathInfo: </font>&quot; + request.getPathInfo());
+        out.println(&quot;<font color="#009900">Remote Address: </font>&quot; + request.getRemoteAddr());
+        out.println(&quot;<font color="#009900">&lt;/body&gt;</font>&quot;);
+        out.println(&quot;<font color="#009900">&lt;/html&gt;</font>&quot;);
+    }
+
+<font color="#FF0000">    /**
+     * We are going to perform the same operations for POST requests
+     * as for GET methods, so this method just sends the request to
+     * the doGet method.
+     */</font>
+
+    <font color="#0000FF">public void</font> doPost(HttpServletRequest request, HttpServletResponse response)
+    <font color="#0000FF">throws</font> IOException, ServletException
+    {
+        doGet(request, response);
+    }
+}</pre>
+</body>
+</html>

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/examples/reqparams.html
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/examples/reqparams.html	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/examples/reqparams.html	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,77 @@
+<!--
+  Copyright 2004 The Apache Software Foundation
+
+  Licensed 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.
+-->
+<html>
+<head>
+<title>Untitled Document</title>
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+</head>
+
+<body bgcolor="#FFFFFF">
+<p><font color="#0000FF"><a href="servlet/RequestParamExample"><img src="images/execute.gif" align="right" border="0"></a><a href="index.html"><img src="images/return.gif" width="24" height="24" align="right" border="0"></a></font></p>
+<h3>Source Code for Request Parameter Example<font color="#0000FF"><br>
+  </font> </h3>
+<font color="#0000FF"></font> 
+<pre><font color="#0000FF">import</font> java.io.*;
+<font color="#0000FF">import</font> java.util.*;
+<font color="#0000FF">import</font> javax.servlet.*;
+<font color="#0000FF">import</font> javax.servlet.http.*;
+
+<font color="#0000FF">public class</font> RequestParamExample <font color="#0000FF">extends</font> HttpServlet {
+
+    <font color="#0000FF">public void</font> doGet(HttpServletRequest request, HttpServletResponse response)
+    <font color="#0000FF">throws</font> IOException, ServletException
+    {
+        response.setContentType(&quot;<font color="#009900">text/html</font>&quot;);
+        PrintWriter out = response.getWriter();
+        out.println(&quot;<font color="#009900">&lt;html&gt;</font>&quot;);
+        out.println(&quot;<font color="#009900">&lt;head&gt;</font>&quot;);
+        out.println(&quot;<font color="#009900">&lt;title&gt;Request Parameters Example&lt;/title&gt;</font>&quot;);
+        out.println(&quot;<font color="#009900">&lt;/head&gt;</font>&quot;);
+        out.println(&quot;<font color="#009900">&lt;body&gt;</font>&quot;);
+        out.println(&quot;<font color="#009900">&lt;h3&gt;Request Parameters Example&lt;/h3&gt;</font>&quot;);
+        out.println(&quot;<font color="#009900">Parameters in this request:&lt;br&gt;</font>&quot;);
+        if (firstName != null || lastName != null) {
+            out.println(&quot;<font color="#009900">First Name:</font>&quot;);
+            out.println(&quot;<font color="#009900"> = </font>&quot; + HTMLFilter.filter(firstName) + &quot;<font color="#009900">&lt;br&gt;</font>&quot;);
+            out.println(&quot;<font color="#009900">Last Name:</font>&quot;);
+            out.println(&quot;<font color="#009900"> = </font>&quot; + HTMLFilter.filter(lastName));
+        } else {
+            out.println(&quot;<font color="#009900">No Parameters, Please enter some</font>&quot;);
+        }
+        out.println(&quot;<font color="#009900">&lt;P&gt;</font>&quot;);
+        out.print(&quot;<font color="#009900">&lt;form action=\"</font>&quot;);
+        out.print(&quot;<font color="#009900">RequestParamExample\" </font>&quot;);
+        out.println(&quot;<font color="#009900">method=POST&gt;</font>&quot;);
+        out.println(&quot;<font color="#009900">First Name:</font>&quot;);
+        out.println(&quot;<font color="#009900">&lt;input type=text size=20 name=firstname&gt;</font>&quot;);
+        out.println(&quot;<font color="#009900">&lt;br&gt;</font>&quot;);
+        out.println(&quot;<font color="#009900">Last Name:</font>&quot;);
+        out.println(&quot;<font color="#009900">&lt;input type=text size=20 name=lastname&gt;</font>&quot;);
+        out.println(&quot;<font color="#009900">&lt;br&gt;</font>&quot;);
+        out.println(&quot;<font color="#009900">&lt;input type=submit&gt;</font>&quot;);
+        out.println(&quot;<font color="#009900">&lt;/form&gt;</font>&quot;);
+        out.println(&quot;<font color="#009900">&lt;/body&gt;</font>&quot;);
+        out.println(&quot;<font color="#009900">&lt;/html&gt;</font>&quot;);
+    }
+
+    <font color="#0000FF">public void</font> doPost(HttpServletRequest request, HttpServletResponse res)
+    <font color="#0000FF">throws</font> IOException, ServletException
+    {
+        doGet(request, response);
+    }
+}</pre>
+</body>
+</html>

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/examples/sessions.html
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/examples/sessions.html	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/examples/sessions.html	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,69 @@
+<!--
+  Copyright 2004 The Apache Software Foundation
+
+  Licensed 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.
+-->
+<html>
+<head>
+<title>Untitled Document</title>
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+</head>
+
+<body bgcolor="#FFFFFF">
+<p><font color="#0000FF"><a href="servlet/SessionExample"><img src="images/execute.gif" align="right" border="0"></a><a href="index.html"><img src="images/return.gif" width="24" height="24" align="right" border="0"></a></font></p>
+<h3>Source Code for Session Example<font color="#0000FF"><br>
+  </font> </h3>
+<font color="#0000FF"></font> 
+<pre><font color="#0000FF">import</font> java.io.*;
+<font color="#0000FF">import</font> java.util.*;
+<font color="#0000FF">import</font> javax.servlet.*;
+<font color="#0000FF">import</font> javax.servlet.http.*;
+
+<font color="#0000FF">public class</font> SessionExample <font color="#0000FF">extends</font> HttpServlet {
+
+    <font color="#0000FF">public void</font> doGet(HttpServletRequest request, HttpServletResponse response)
+    <font color="#0000FF">throws</font> IOException, ServletException
+    {
+        response.setContentType(&quot;<font color="#009900">text/html</font>&quot;);
+        PrintWriter out = response.getWriter();
+        
+        HttpSession session = request.getSession(true);
+
+        <font color="#CC0000">// print session info</font>
+
+        Date created = new Date(session.getCreationTime());
+        Date accessed = new Date(session.getLastAccessedTime());
+        out.println(&quot;<font color="#009900">ID </font>&quot; + session.getId());
+        out.println(&quot;<font color="#009900">Created: </font>&quot; + created);
+        out.println(&quot;<font color="#009900">Last Accessed: </font>&quot; + accessed);
+
+        <font color="#CC0000">// set session info if needed</font>
+
+        String dataName = request.getParameter(&quot;<font color="#009900">dataName</font>&quot;);
+        if (dataName != null &amp;&amp; dataName.length() &gt; 0) {
+            String dataValue = request.getParameter(&quot;<font color="#009900">dataValue</font>&quot;);
+            session.setAttribute(dataName, dataValue);
+        }
+
+        // print session contents
+
+        Enumeration e = session.getAttributeNames();
+        while (e.hasMoreElements()) {
+            String name = (String)e.nextElement();
+            String value = session.getAttribute(name).toString();
+            out.println(name + &quot; <font color="#009900">= </font>&quot; + value);
+        }
+    }
+}</pre>
+</body>
+</html>

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/etc/manifest
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/etc/manifest	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/etc/manifest	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,10 @@
+Manifest-version: 1.0
+
+Name: javax/servlet/
+Specification-Title: Java API for Servlets
+Specification-Version: 2.4
+Specification-Vendor: Sun Microsystems, Inc.
+Implementation-Title: javax.servlet
+Implementation-Version: 2.4. at implementation.revision@
+Implementation-Vendor: Apache Software Foundation
+

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/dtd/XMLSchema.dtd
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/dtd/XMLSchema.dtd	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/dtd/XMLSchema.dtd	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,417 @@
+<!--
+  Copyright 2004 The Apache Software Foundation
+
+  Licensed 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.
+-->
+<!-- DTD for XML Schemas: Part 1: Structures
+     Public Identifier: "-//W3C//DTD XMLSCHEMA 200102//EN"
+     Official Location: http://www.w3.org/2001/XMLSchema.dtd -->
+<!-- $Id: XMLSchema.dtd 267129 2004-03-18 16:40:35Z jfarcand $ -->
+<!-- Note this DTD is NOT normative, or even definitive. -->           <!--d-->
+<!-- prose copy in the structures REC is the definitive version -->    <!--d-->
+<!-- (which shouldn't differ from this one except for this -->         <!--d-->
+<!-- comment and entity expansions, but just in case) -->              <!--d-->
+<!-- With the exception of cases with multiple namespace
+     prefixes for the XML Schema namespace, any XML document which is
+     not valid per this DTD given redefinitions in its internal subset of the
+     'p' and 's' parameter entities below appropriate to its namespace
+     declaration of the XML Schema namespace is almost certainly not
+     a valid schema. -->
+
+<!-- The simpleType element and its constituent parts
+     are defined in XML Schema: Part 2: Datatypes -->
+<!ENTITY % xs-datatypes PUBLIC 'datatypes' 'datatypes.dtd' >
+
+<!ENTITY % p 'xs:'> <!-- can be overriden in the internal subset of a
+                         schema document to establish a different
+                         namespace prefix -->
+<!ENTITY % s ':xs'> <!-- if %p is defined (e.g. as foo:) then you must
+                         also define %s as the suffix for the appropriate
+                         namespace declaration (e.g. :foo) -->
+<!ENTITY % nds 'xmlns%s;'>
+
+<!-- Define all the element names, with optional prefix -->
+<!ENTITY % schema "%p;schema">
+<!ENTITY % complexType "%p;complexType">
+<!ENTITY % complexContent "%p;complexContent">
+<!ENTITY % simpleContent "%p;simpleContent">
+<!ENTITY % extension "%p;extension">
+<!ENTITY % element "%p;element">
+<!ENTITY % unique "%p;unique">
+<!ENTITY % key "%p;key">
+<!ENTITY % keyref "%p;keyref">
+<!ENTITY % selector "%p;selector">
+<!ENTITY % field "%p;field">
+<!ENTITY % group "%p;group">
+<!ENTITY % all "%p;all">
+<!ENTITY % choice "%p;choice">
+<!ENTITY % sequence "%p;sequence">
+<!ENTITY % any "%p;any">
+<!ENTITY % anyAttribute "%p;anyAttribute">
+<!ENTITY % attribute "%p;attribute">
+<!ENTITY % attributeGroup "%p;attributeGroup">
+<!ENTITY % include "%p;include">
+<!ENTITY % import "%p;import">
+<!ENTITY % redefine "%p;redefine">
+<!ENTITY % notation "%p;notation">
+
+<!-- annotation elements -->
+<!ENTITY % annotation "%p;annotation">
+<!ENTITY % appinfo "%p;appinfo">
+<!ENTITY % documentation "%p;documentation">
+
+<!-- Customisation entities for the ATTLIST of each element type.
+     Define one of these if your schema takes advantage of the
+     anyAttribute='##other' in the schema for schemas -->
+
+<!ENTITY % schemaAttrs ''>
+<!ENTITY % complexTypeAttrs ''>
+<!ENTITY % complexContentAttrs ''>
+<!ENTITY % simpleContentAttrs ''>
+<!ENTITY % extensionAttrs ''>
+<!ENTITY % elementAttrs ''>
+<!ENTITY % groupAttrs ''>
+<!ENTITY % allAttrs ''>
+<!ENTITY % choiceAttrs ''>
+<!ENTITY % sequenceAttrs ''>
+<!ENTITY % anyAttrs ''>
+<!ENTITY % anyAttributeAttrs ''>
+<!ENTITY % attributeAttrs ''>
+<!ENTITY % attributeGroupAttrs ''>
+<!ENTITY % uniqueAttrs ''>
+<!ENTITY % keyAttrs ''>
+<!ENTITY % keyrefAttrs ''>
+<!ENTITY % selectorAttrs ''>
+<!ENTITY % fieldAttrs ''>
+<!ENTITY % includeAttrs ''>
+<!ENTITY % importAttrs ''>
+<!ENTITY % redefineAttrs ''>
+<!ENTITY % notationAttrs ''>
+<!ENTITY % annotationAttrs ''>
+<!ENTITY % appinfoAttrs ''>
+<!ENTITY % documentationAttrs ''>
+
+<!ENTITY % complexDerivationSet "CDATA">
+      <!-- #all or space-separated list drawn from derivationChoice -->
+<!ENTITY % blockSet "CDATA">
+      <!-- #all or space-separated list drawn from
+                      derivationChoice + 'substitution' -->
+
+<!ENTITY % mgs '%all; | %choice; | %sequence;'>
+<!ENTITY % cs '%choice; | %sequence;'>
+<!ENTITY % formValues '(qualified|unqualified)'>
+
+
+<!ENTITY % attrDecls    '((%attribute;| %attributeGroup;)*,(%anyAttribute;)?)'>
+
+<!ENTITY % particleAndAttrs '((%mgs; | %group;)?, %attrDecls;)'>
+
+<!-- This is used in part2 -->
+<!ENTITY % restriction1 '((%mgs; | %group;)?)'>
+
+%xs-datatypes;
+
+<!-- the duplication below is to produce an unambiguous content model
+     which allows annotation everywhere -->
+<!ELEMENT %schema; ((%include; | %import; | %redefine; | %annotation;)*,
+                    ((%simpleType; | %complexType;
+                      | %element; | %attribute;
+                      | %attributeGroup; | %group;
+                      | %notation; ),
+                     (%annotation;)*)* )>
+<!ATTLIST %schema;
+   targetNamespace      %URIref;               #IMPLIED
+   version              CDATA                  #IMPLIED
+   %nds;                %URIref;               #FIXED 'http://www.w3.org/2001/XMLSchema'
+   xmlns                CDATA                  #IMPLIED
+   finalDefault         %complexDerivationSet; ''
+   blockDefault         %blockSet;             ''
+   id                   ID                     #IMPLIED
+   elementFormDefault   %formValues;           'unqualified'
+   attributeFormDefault %formValues;           'unqualified'
+   xml:lang             CDATA                  #IMPLIED
+   %schemaAttrs;>
+<!-- Note the xmlns declaration is NOT in the Schema for Schemas,
+     because at the Infoset level where schemas operate,
+     xmlns(:prefix) is NOT an attribute! -->
+<!-- The declaration of xmlns is a convenience for schema authors -->
+ 
+<!-- The id attribute here and below is for use in external references
+     from non-schemas using simple fragment identifiers.
+     It is NOT used for schema-to-schema reference, internal or
+     external. -->
+
+<!-- a type is a named content type specification which allows attribute
+     declarations-->
+<!-- -->
+
+<!ELEMENT %complexType; ((%annotation;)?,
+                         (%simpleContent;|%complexContent;|
+                          %particleAndAttrs;))>
+
+<!ATTLIST %complexType;
+          name      %NCName;                        #IMPLIED
+          id        ID                              #IMPLIED
+          abstract  %boolean;                       #IMPLIED
+          final     %complexDerivationSet;          #IMPLIED
+          block     %complexDerivationSet;          #IMPLIED
+          mixed (true|false) 'false'
+          %complexTypeAttrs;>
+
+<!-- particleAndAttrs is shorthand for a root type -->
+<!-- mixed is disallowed if simpleContent, overriden if complexContent
+     has one too. -->
+
+<!-- If anyAttribute appears in one or more referenced attributeGroups
+     and/or explicitly, the intersection of the permissions is used -->
+
+<!ELEMENT %complexContent; ((%annotation;)?, (%restriction;|%extension;))>
+<!ATTLIST %complexContent;
+          mixed (true|false) #IMPLIED
+          id    ID           #IMPLIED
+          %complexContentAttrs;>
+
+<!-- restriction should use the branch defined above, not the simple
+     one from part2; extension should use the full model  -->
+
+<!ELEMENT %simpleContent; ((%annotation;)?, (%restriction;|%extension;))>
+<!ATTLIST %simpleContent;
+          id    ID           #IMPLIED
+          %simpleContentAttrs;>
+
+<!-- restriction should use the simple branch from part2, not the 
+     one defined above; extension should have no particle  -->
+
+<!ELEMENT %extension; ((%annotation;)?, (%particleAndAttrs;))>
+<!ATTLIST %extension;
+          base  %QName;      #REQUIRED
+          id    ID           #IMPLIED
+          %extensionAttrs;>
+
+<!-- an element is declared by either:
+ a name and a type (either nested or referenced via the type attribute)
+ or a ref to an existing element declaration -->
+
+<!ELEMENT %element; ((%annotation;)?, (%complexType;| %simpleType;)?,
+                     (%unique; | %key; | %keyref;)*)>
+<!-- simpleType or complexType only if no type|ref attribute -->
+<!-- ref not allowed at top level -->
+<!ATTLIST %element;
+            name               %NCName;               #IMPLIED
+            id                 ID                     #IMPLIED
+            ref                %QName;                #IMPLIED
+            type               %QName;                #IMPLIED
+            minOccurs          %nonNegativeInteger;   #IMPLIED
+            maxOccurs          CDATA                  #IMPLIED
+            nillable           %boolean;              #IMPLIED
+            substitutionGroup  %QName;                #IMPLIED
+            abstract           %boolean;              #IMPLIED
+            final              %complexDerivationSet; #IMPLIED
+            block              %blockSet;             #IMPLIED
+            default            CDATA                  #IMPLIED
+            fixed              CDATA                  #IMPLIED
+            form               %formValues;           #IMPLIED
+            %elementAttrs;>
+<!-- type and ref are mutually exclusive.
+     name and ref are mutually exclusive, one is required -->
+<!-- In the absence of type AND ref, type defaults to type of
+     substitutionGroup, if any, else the ur-type, i.e. unconstrained -->
+<!-- default and fixed are mutually exclusive -->
+
+<!ELEMENT %group; ((%annotation;)?,(%mgs;)?)>
+<!ATTLIST %group; 
+          name        %NCName;               #IMPLIED
+          ref         %QName;                #IMPLIED
+          minOccurs   %nonNegativeInteger;   #IMPLIED
+          maxOccurs   CDATA                  #IMPLIED
+          id          ID                     #IMPLIED
+          %groupAttrs;>
+
+<!ELEMENT %all; ((%annotation;)?, (%element;)*)>
+<!ATTLIST %all;
+          minOccurs   (1)                    #IMPLIED
+          maxOccurs   (1)                    #IMPLIED
+          id          ID                     #IMPLIED
+          %allAttrs;>
+
+<!ELEMENT %choice; ((%annotation;)?, (%element;| %group;| %cs; | %any;)*)>
+<!ATTLIST %choice;
+          minOccurs   %nonNegativeInteger;   #IMPLIED
+          maxOccurs   CDATA                  #IMPLIED
+          id          ID                     #IMPLIED
+          %choiceAttrs;>
+
+<!ELEMENT %sequence; ((%annotation;)?, (%element;| %group;| %cs; | %any;)*)>
+<!ATTLIST %sequence;
+          minOccurs   %nonNegativeInteger;   #IMPLIED
+          maxOccurs   CDATA                  #IMPLIED
+          id          ID                     #IMPLIED
+          %sequenceAttrs;>
+
+<!-- an anonymous grouping in a model, or
+     a top-level named group definition, or a reference to same -->
+
+<!-- Note that if order is 'all', group is not allowed inside.
+     If order is 'all' THIS group must be alone (or referenced alone) at
+     the top level of a content model -->
+<!-- If order is 'all', minOccurs==maxOccurs==1 on element/any inside -->
+<!-- Should allow minOccurs=0 inside order='all' . . . -->
+
+<!ELEMENT %any; (%annotation;)?>
+<!ATTLIST %any;
+            namespace       CDATA                  '##any'
+            processContents (skip|lax|strict)      'strict'
+            minOccurs       %nonNegativeInteger;   '1'
+            maxOccurs       CDATA                  '1'
+            id              ID                     #IMPLIED
+            %anyAttrs;>
+
+<!-- namespace is interpreted as follows:
+                  ##any      - - any non-conflicting WFXML at all
+
+                  ##other    - - any non-conflicting WFXML from namespace other
+                                  than targetNamespace
+
+                  ##local    - - any unqualified non-conflicting WFXML/attribute
+                  one or     - - any non-conflicting WFXML from
+                  more URI        the listed namespaces
+                  references
+
+                  ##targetNamespace ##local may appear in the above list,
+                    with the obvious meaning -->
+
+<!ELEMENT %anyAttribute; (%annotation;)?>
+<!ATTLIST %anyAttribute;
+            namespace       CDATA              '##any'
+            processContents (skip|lax|strict)  'strict'
+            id              ID                 #IMPLIED
+            %anyAttributeAttrs;>
+<!-- namespace is interpreted as for 'any' above -->
+
+<!-- simpleType only if no type|ref attribute -->
+<!-- ref not allowed at top level, name iff at top level -->
+<!ELEMENT %attribute; ((%annotation;)?, (%simpleType;)?)>
+<!ATTLIST %attribute;
+          name      %NCName;      #IMPLIED
+          id        ID            #IMPLIED
+          ref       %QName;       #IMPLIED
+          type      %QName;       #IMPLIED
+          use       (prohibited|optional|required) #IMPLIED
+          default   CDATA         #IMPLIED
+          fixed     CDATA         #IMPLIED
+          form      %formValues;  #IMPLIED
+          %attributeAttrs;>
+<!-- type and ref are mutually exclusive.
+     name and ref are mutually exclusive, one is required -->
+<!-- default for use is optional when nested, none otherwise -->
+<!-- default and fixed are mutually exclusive -->
+<!-- type attr and simpleType content are mutually exclusive -->
+
+<!-- an attributeGroup is a named collection of attribute decls, or a
+     reference thereto -->
+<!ELEMENT %attributeGroup; ((%annotation;)?,
+                       (%attribute; | %attributeGroup;)*,
+                       (%anyAttribute;)?) >
+<!ATTLIST %attributeGroup;
+                 name       %NCName;       #IMPLIED
+                 id         ID             #IMPLIED
+                 ref        %QName;        #IMPLIED
+                 %attributeGroupAttrs;>
+
+<!-- ref iff no content, no name.  ref iff not top level -->
+
+<!-- better reference mechanisms -->
+<!ELEMENT %unique; ((%annotation;)?, %selector;, (%field;)+)>
+<!ATTLIST %unique;
+          name     %NCName;       #REQUIRED
+	  id       ID             #IMPLIED
+	  %uniqueAttrs;>
+
+<!ELEMENT %key;    ((%annotation;)?, %selector;, (%field;)+)>
+<!ATTLIST %key;
+          name     %NCName;       #REQUIRED
+	  id       ID             #IMPLIED
+	  %keyAttrs;>
+
+<!ELEMENT %keyref; ((%annotation;)?, %selector;, (%field;)+)>
+<!ATTLIST %keyref;
+          name     %NCName;       #REQUIRED
+	  refer    %QName;        #REQUIRED
+	  id       ID             #IMPLIED
+	  %keyrefAttrs;>
+
+<!ELEMENT %selector; ((%annotation;)?)>
+<!ATTLIST %selector;
+          xpath %XPathExpr; #REQUIRED
+          id    ID          #IMPLIED
+          %selectorAttrs;>
+<!ELEMENT %field; ((%annotation;)?)>
+<!ATTLIST %field;
+          xpath %XPathExpr; #REQUIRED
+          id    ID          #IMPLIED
+          %fieldAttrs;>
+
+<!-- Schema combination mechanisms -->
+<!ELEMENT %include; (%annotation;)?>
+<!ATTLIST %include;
+          schemaLocation %URIref; #REQUIRED
+          id             ID       #IMPLIED
+          %includeAttrs;>
+
+<!ELEMENT %import; (%annotation;)?>
+<!ATTLIST %import;
+          namespace      %URIref; #IMPLIED
+          schemaLocation %URIref; #IMPLIED
+          id             ID       #IMPLIED
+          %importAttrs;>
+
+<!ELEMENT %redefine; (%annotation; | %simpleType; | %complexType; |
+                      %attributeGroup; | %group;)*>
+<!ATTLIST %redefine;
+          schemaLocation %URIref; #REQUIRED
+          id             ID       #IMPLIED
+          %redefineAttrs;>
+
+<!ELEMENT %notation; (%annotation;)?>
+<!ATTLIST %notation;
+	  name        %NCName;    #REQUIRED
+	  id          ID          #IMPLIED
+	  public      CDATA       #REQUIRED
+	  system      %URIref;    #IMPLIED
+	  %notationAttrs;>
+
+<!-- Annotation is either application information or documentation -->
+<!-- By having these here they are available for datatypes as well
+     as all the structures elements -->
+
+<!ELEMENT %annotation; (%appinfo; | %documentation;)*>
+<!ATTLIST %annotation; %annotationAttrs;>
+
+<!-- User must define annotation elements in internal subset for this
+     to work -->
+<!ELEMENT %appinfo; ANY>   <!-- too restrictive -->
+<!ATTLIST %appinfo;
+          source     %URIref;      #IMPLIED
+          id         ID         #IMPLIED
+          %appinfoAttrs;>
+<!ELEMENT %documentation; ANY>   <!-- too restrictive -->
+<!ATTLIST %documentation;
+          source     %URIref;   #IMPLIED
+          id         ID         #IMPLIED
+          xml:lang   CDATA      #IMPLIED
+          %documentationAttrs;>
+
+<!NOTATION XMLSchemaStructures PUBLIC
+           'structures' 'http://www.w3.org/2001/XMLSchema.xsd' >
+<!NOTATION XML PUBLIC
+           'REC-xml-1998-0210' 'http://www.w3.org/TR/1998/REC-xml-19980210' >

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/dtd/datatypes.dtd
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/dtd/datatypes.dtd	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/dtd/datatypes.dtd	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,218 @@
+<!--
+  Copyright 2004 The Apache Software Foundation
+
+  Licensed 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.
+-->
+<!--
+        DTD for XML Schemas: Part 2: Datatypes
+        $Id: datatypes.dtd 267129 2004-03-18 16:40:35Z jfarcand $
+        Note this DTD is NOT normative, or even definitive. - - the
+        prose copy in the datatypes REC is the definitive version
+        (which shouldn't differ from this one except for this comment
+        and entity expansions, but just in case)
+  -->
+
+<!--
+        This DTD cannot be used on its own, it is intended
+        only for incorporation in XMLSchema.dtd, q.v.
+  -->
+
+<!-- Define all the element names, with optional prefix -->
+<!ENTITY % simpleType "%p;simpleType">
+<!ENTITY % restriction "%p;restriction">
+<!ENTITY % list "%p;list">
+<!ENTITY % union "%p;union">
+<!ENTITY % maxExclusive "%p;maxExclusive">
+<!ENTITY % minExclusive "%p;minExclusive">
+<!ENTITY % maxInclusive "%p;maxInclusive">
+<!ENTITY % minInclusive "%p;minInclusive">
+<!ENTITY % totalDigits "%p;totalDigits">
+<!ENTITY % fractionDigits "%p;fractionDigits">
+<!ENTITY % length "%p;length">
+<!ENTITY % minLength "%p;minLength">
+<!ENTITY % maxLength "%p;maxLength">
+<!ENTITY % enumeration "%p;enumeration">
+<!ENTITY % whiteSpace "%p;whiteSpace">
+<!ENTITY % pattern "%p;pattern">
+
+<!--
+        Customisation entities for the ATTLIST of each element
+        type. Define one of these if your schema takes advantage
+        of the anyAttribute='##other' in the schema for schemas
+  -->
+
+<!ENTITY % simpleTypeAttrs "">
+<!ENTITY % restrictionAttrs "">
+<!ENTITY % listAttrs "">
+<!ENTITY % unionAttrs "">
+<!ENTITY % maxExclusiveAttrs "">
+<!ENTITY % minExclusiveAttrs "">
+<!ENTITY % maxInclusiveAttrs "">
+<!ENTITY % minInclusiveAttrs "">
+<!ENTITY % totalDigitsAttrs "">
+<!ENTITY % fractionDigitsAttrs "">
+<!ENTITY % lengthAttrs "">
+<!ENTITY % minLengthAttrs "">
+<!ENTITY % maxLengthAttrs "">
+<!ENTITY % enumerationAttrs "">
+<!ENTITY % whiteSpaceAttrs "">
+<!ENTITY % patternAttrs "">
+
+<!-- Define some entities for informative use as attribute
+        types -->
+<!ENTITY % URIref "CDATA">
+<!ENTITY % XPathExpr "CDATA">
+<!ENTITY % QName "NMTOKEN">
+<!ENTITY % QNames "NMTOKENS">
+<!ENTITY % NCName "NMTOKEN">
+<!ENTITY % nonNegativeInteger "NMTOKEN">
+<!ENTITY % boolean "(true|false)">
+<!ENTITY % simpleDerivationSet "CDATA">
+<!--
+        #all or space-separated list drawn from derivationChoice
+  -->
+
+<!--
+        Note that the use of 'facet' below is less restrictive
+        than is really intended:  There should in fact be no
+        more than one of each of minInclusive, minExclusive,
+        maxInclusive, maxExclusive, totalDigits, fractionDigits,
+        length, maxLength, minLength within datatype,
+        and the min- and max- variants of Inclusive and Exclusive
+        are mutually exclusive. On the other hand,  pattern and
+        enumeration may repeat.
+  -->
+<!ENTITY % minBound "(%minInclusive; | %minExclusive;)">
+<!ENTITY % maxBound "(%maxInclusive; | %maxExclusive;)">
+<!ENTITY % bounds "%minBound; | %maxBound;">
+<!ENTITY % numeric "%totalDigits; | %fractionDigits;">
+<!ENTITY % ordered "%bounds; | %numeric;">
+<!ENTITY % unordered
+   "%pattern; | %enumeration; | %whiteSpace; | %length; |
+   %maxLength; | %minLength;">
+<!ENTITY % facet "%ordered; | %unordered;">
+<!ENTITY % facetAttr 
+        "value CDATA #REQUIRED
+        id ID #IMPLIED">
+<!ENTITY % fixedAttr "fixed %boolean; #IMPLIED">
+<!ENTITY % facetModel "(%annotation;)?">
+<!ELEMENT %simpleType;
+        ((%annotation;)?, (%restriction; | %list; | %union;))>
+<!ATTLIST %simpleType;
+    name      %NCName; #IMPLIED
+    final     %simpleDerivationSet; #IMPLIED
+    id        ID       #IMPLIED
+    %simpleTypeAttrs;>
+<!-- name is required at top level -->
+<!ELEMENT %restriction; ((%annotation;)?,
+                         (%restriction1; |
+                          ((%simpleType;)?,(%facet;)*)),
+                         (%attrDecls;))>
+<!ATTLIST %restriction;
+    base      %QName;                  #IMPLIED
+    id        ID       #IMPLIED
+    %restrictionAttrs;>
+<!--
+        base and simpleType child are mutually exclusive,
+        one is required.
+
+        restriction is shared between simpleType and
+        simpleContent and complexContent (in XMLSchema.xsd).
+        restriction1 is for the latter cases, when this
+        is restricting a complex type, as is attrDecls.
+  -->
+<!ELEMENT %list; ((%annotation;)?,(%simpleType;)?)>
+<!ATTLIST %list;
+    itemType      %QName;             #IMPLIED
+    id        ID       #IMPLIED
+    %listAttrs;>
+<!--
+        itemType and simpleType child are mutually exclusive,
+        one is required
+  -->
+<!ELEMENT %union; ((%annotation;)?,(%simpleType;)*)>
+<!ATTLIST %union;
+    id            ID       #IMPLIED
+    memberTypes   %QNames;            #IMPLIED
+    %unionAttrs;>
+<!--
+        At least one item in memberTypes or one simpleType
+        child is required
+  -->
+
+<!ELEMENT %maxExclusive; %facetModel;>
+<!ATTLIST %maxExclusive;
+        %facetAttr;
+        %fixedAttr;
+        %maxExclusiveAttrs;>
+<!ELEMENT %minExclusive; %facetModel;>
+<!ATTLIST %minExclusive;
+        %facetAttr;
+        %fixedAttr;
+        %minExclusiveAttrs;>
+
+<!ELEMENT %maxInclusive; %facetModel;>
+<!ATTLIST %maxInclusive;
+        %facetAttr;
+        %fixedAttr;
+        %maxInclusiveAttrs;>
+<!ELEMENT %minInclusive; %facetModel;>
+<!ATTLIST %minInclusive;
+        %facetAttr;
+        %fixedAttr;
+        %minInclusiveAttrs;>
+
+<!ELEMENT %totalDigits; %facetModel;>
+<!ATTLIST %totalDigits;
+        %facetAttr;
+        %fixedAttr;
+        %totalDigitsAttrs;>
+<!ELEMENT %fractionDigits; %facetModel;>
+<!ATTLIST %fractionDigits;
+        %facetAttr;
+        %fixedAttr;
+        %fractionDigitsAttrs;>
+
+<!ELEMENT %length; %facetModel;>
+<!ATTLIST %length;
+        %facetAttr;
+        %fixedAttr;
+        %lengthAttrs;>
+<!ELEMENT %minLength; %facetModel;>
+<!ATTLIST %minLength;
+        %facetAttr;
+        %fixedAttr;
+        %minLengthAttrs;>
+<!ELEMENT %maxLength; %facetModel;>
+<!ATTLIST %maxLength;
+        %facetAttr;
+        %fixedAttr;
+        %maxLengthAttrs;>
+
+<!-- This one can be repeated -->
+<!ELEMENT %enumeration; %facetModel;>
+<!ATTLIST %enumeration;
+        %facetAttr;
+        %enumerationAttrs;>
+
+<!ELEMENT %whiteSpace; %facetModel;>
+<!ATTLIST %whiteSpace;
+        %facetAttr;
+        %fixedAttr;
+        %whiteSpaceAttrs;>
+
+<!-- This one can be repeated -->
+<!ELEMENT %pattern; %facetModel;>
+<!ATTLIST %pattern;
+        %facetAttr;
+        %patternAttrs;>

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/dtd/j2ee_1_4.xsd
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/dtd/j2ee_1_4.xsd	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/dtd/j2ee_1_4.xsd	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,1621 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Copyright 2004 The Apache Software Foundation
+
+  Licensed 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.
+-->
+<xsd:schema
+     targetNamespace="http://java.sun.com/xml/ns/j2ee"
+     xmlns:j2ee="http://java.sun.com/xml/ns/j2ee"
+     xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+     elementFormDefault="qualified"
+     attributeFormDefault="unqualified"
+     version="1.4">
+  <xsd:annotation>
+    <xsd:documentation>
+      @(#)j2ee_1_4.xsds	1.43 03/09/16
+    </xsd:documentation>
+  </xsd:annotation>
+
+  <xsd:annotation>
+    <xsd:documentation>
+
+      Copyright 2002 Sun Microsystems, Inc., 901 San Antonio
+      Road, Palo Alto, California 94303, U.S.A. All rights
+      reserved.
+
+      Sun Microsystems, Inc. has intellectual property rights
+      relating to technology described in this document. In
+      particular, and without limitation, these intellectual
+      property rights may include one or more of the U.S. patents
+      listed at http://www.sun.com/patents and one or more
+      additional patents or pending patent applications in the
+      U.S. and other countries.
+
+      This document and the technology which it describes are
+      distributed under licenses restricting their use, copying,
+      distribution, and decompilation. No part of this document
+      may be reproduced in any form by any means without prior
+      written authorization of Sun and its licensors, if any.
+
+      Third-party software, including font technology, is
+      copyrighted and licensed from Sun suppliers.
+
+      Sun, Sun Microsystems, the Sun logo, Solaris, Java, J2EE,
+      JavaServer Pages, Enterprise JavaBeans and the Java Coffee
+      Cup logo are trademarks or registered trademarks of Sun
+      Microsystems, Inc. in the U.S. and other countries.
+
+      Federal Acquisitions: Commercial Software - Government Users
+      Subject to Standard License Terms and Conditions.
+
+    </xsd:documentation>
+  </xsd:annotation>
+<xsd:annotation>
+<xsd:documentation>
+
+The following definitions that appear in the common
+shareable schema(s) of J2EE deployment descriptors should be
+interpreted with respect to the context they are included:
+
+Deployment Component may indicate one of the following:
+    j2ee application;
+    application client;
+    web application;
+    enterprise bean;
+    resource adapter;
+
+Deployment File may indicate one of the following:
+    ear file;
+    war file;
+    jar file;
+    rar file;
+
+</xsd:documentation>
+</xsd:annotation>
+
+  <xsd:import namespace="http://www.w3.org/XML/1998/namespace"
+	      schemaLocation="http://www.w3.org/2001/xml.xsd"/>
+
+  <xsd:include schemaLocation=
+	"http://www.ibm.com/webservices/xsd/j2ee_web_services_client_1_1.xsd"/>
+
+
+<!-- **************************************************** -->
+
+  <xsd:group name="descriptionGroup">
+    <xsd:annotation>
+      <xsd:documentation>
+
+	This group keeps the usage of the contained description related
+	elements consistent across J2EE deployment descriptors.
+
+	All elements may occur multiple times with different languages,
+	to support localization of the content.
+
+      </xsd:documentation>
+    </xsd:annotation>
+    <xsd:sequence>
+      <xsd:element name="description"
+		   type="j2ee:descriptionType"
+		   minOccurs="0"
+		   maxOccurs="unbounded"/>
+      <xsd:element name="display-name"
+		   type="j2ee:display-nameType"
+		   minOccurs="0"
+		   maxOccurs="unbounded"/>
+      <xsd:element name="icon"
+		   type="j2ee:iconType"
+		   minOccurs="0"
+		   maxOccurs="unbounded"/>
+    </xsd:sequence>
+  </xsd:group>
+
+<!-- **************************************************** -->
+
+  <xsd:complexType name="descriptionType">
+    <xsd:annotation>
+      <xsd:documentation>
+
+	The description type is used by a description element to
+	provide text describing the parent element.  The elements
+	that use this type should include any information that the
+	Deployment Component's Deployment File file producer wants
+	to provide to the consumer of the Deployment Component's
+	Deployment File (i.e., to the Deployer). Typically, the
+	tools used by such a Deployment File consumer will display
+	the description when processing the parent element that
+	contains the description.
+
+	The lang attribute defines the language that the
+	description is provided in. The default value is "en" (English).
+
+      </xsd:documentation>
+    </xsd:annotation>
+    <xsd:simpleContent>
+      <xsd:extension base="j2ee:xsdStringType">
+	<xsd:attribute ref="xml:lang"/>
+      </xsd:extension>
+    </xsd:simpleContent>
+  </xsd:complexType>
+
+<!-- **************************************************** -->
+
+  <xsd:simpleType name="dewey-versionType">
+    <xsd:annotation>
+      <xsd:documentation>
+
+	This type defines a dewey decimal which is used
+	to describe versions of documents.
+
+      </xsd:documentation>
+    </xsd:annotation>
+
+    <xsd:restriction base="xsd:decimal">
+      <xsd:whiteSpace value="collapse"/>
+    </xsd:restriction>
+
+  </xsd:simpleType>
+
+<!-- **************************************************** -->
+
+  <xsd:complexType name="display-nameType">
+    <xsd:annotation>
+      <xsd:documentation>
+	<![CDATA[
+
+	  The display-name type contains a short name that is intended
+	  to be displayed by tools. It is used by display-name
+	  elements.  The display name need not be unique.
+
+	  Example:
+
+	  ...
+	     <display-name xml:lang="en">Employee Self Service</display-name>
+
+	  The value of the xml:lang attribute is "en" (English) by default.
+
+	  ]]>
+      </xsd:documentation>
+    </xsd:annotation>
+    <xsd:simpleContent>
+      <xsd:extension base="j2ee:string">
+	<xsd:attribute ref="xml:lang"/>
+      </xsd:extension>
+    </xsd:simpleContent>
+  </xsd:complexType>
+
+<!-- **************************************************** -->
+
+  <xsd:complexType name="ejb-linkType">
+    <xsd:annotation>
+      <xsd:documentation>
+	<![CDATA[
+
+	  The ejb-linkType is used by ejb-link
+	  elements in the ejb-ref or ejb-local-ref elements to specify
+	  that an EJB reference is linked to enterprise bean.
+
+	  The value of the ejb-link element must be the ejb-name of an
+	  enterprise bean in the same ejb-jar file or in another ejb-jar
+	  file in the same J2EE application unit.
+
+	  Alternatively, the name in the ejb-link element may be
+	  composed of a path name specifying the ejb-jar containing the
+	  referenced enterprise bean with the ejb-name of the target
+	  bean appended and separated from the path name by "#".  The
+	  path name is relative to the Deployment File containing
+	  Deployment Component that is referencing the enterprise
+	  bean.  This allows multiple enterprise beans with the same
+	  ejb-name to be uniquely identified.
+
+	  Examples:
+
+	      <ejb-link>EmployeeRecord</ejb-link>
+
+	      <ejb-link>../products/product.jar#ProductEJB</ejb-link>
+
+	  ]]>
+      </xsd:documentation>
+    </xsd:annotation>
+    <xsd:simpleContent>
+      <xsd:restriction base="j2ee:string"/>
+    </xsd:simpleContent>
+  </xsd:complexType>
+
+<!-- **************************************************** -->
+
+  <xsd:complexType name="ejb-local-refType">
+    <xsd:annotation>
+      <xsd:documentation>
+
+	The ejb-local-refType is used by ejb-local-ref elements for
+	the declaration of a reference to an enterprise bean's local
+	home. The declaration consists of:
+
+	    - an optional description
+	    - the EJB reference name used in the code of the Deployment
+	      Component that's referencing the enterprise bean
+	    - the expected type of the referenced enterprise bean
+	    - the expected local home and local interfaces of the
+	      referenced enterprise bean
+	    - optional ejb-link information, used to specify the
+	      referenced enterprise bean
+
+      </xsd:documentation>
+    </xsd:annotation>
+
+    <xsd:sequence>
+      <xsd:element name="description"
+		   type="j2ee:descriptionType"
+		   minOccurs="0"
+		   maxOccurs="unbounded"/>
+      <xsd:element name="ejb-ref-name"
+		   type="j2ee:ejb-ref-nameType"/>
+      <xsd:element name="ejb-ref-type"
+		   type="j2ee:ejb-ref-typeType"/>
+      <xsd:element name="local-home"
+		   type="j2ee:local-homeType"/>
+      <xsd:element name="local"
+		   type="j2ee:localType"/>
+      <xsd:element name="ejb-link"
+		   type="j2ee:ejb-linkType"
+		   minOccurs="0"/>
+    </xsd:sequence>
+    <xsd:attribute name="id" type="xsd:ID"/>
+  </xsd:complexType>
+
+<!-- **************************************************** -->
+
+  <xsd:complexType name="ejb-ref-nameType">
+    <xsd:annotation>
+      <xsd:documentation>
+	<![CDATA[
+
+	  The ejb-ref-name element contains the name of an EJB
+	  reference. The EJB reference is an entry in the
+	  Deployment Component's environment and is relative to the
+	  java:comp/env context.  The name must be unique within the
+	  Deployment Component.
+
+	  It is recommended that name is prefixed with "ejb/".
+
+	  Example:
+
+	  <ejb-ref-name>ejb/Payroll</ejb-ref-name>
+
+	  ]]>
+      </xsd:documentation>
+    </xsd:annotation>
+    <xsd:simpleContent>
+      <xsd:restriction base="j2ee:jndi-nameType"/>
+    </xsd:simpleContent>
+  </xsd:complexType>
+
+<!-- **************************************************** -->
+
+  <xsd:complexType name="ejb-ref-typeType">
+    <xsd:annotation>
+      <xsd:documentation>
+
+	The ejb-ref-typeType contains the expected type of the
+	referenced enterprise bean.
+
+	The ejb-ref-type designates a value
+	that must be one of the following:
+
+	    Entity
+	    Session
+
+      </xsd:documentation>
+    </xsd:annotation>
+    <xsd:simpleContent>
+      <xsd:restriction base="j2ee:string">
+	<xsd:enumeration value="Entity"/>
+	<xsd:enumeration value="Session"/>
+      </xsd:restriction>
+    </xsd:simpleContent>
+  </xsd:complexType>
+
+<!-- **************************************************** -->
+
+  <xsd:complexType name="ejb-refType">
+    <xsd:annotation>
+      <xsd:documentation>
+
+	The ejb-refType is used by ejb-ref elements for the
+	declaration of a reference to an enterprise bean's home. The
+	declaration consists of:
+
+	    - an optional description
+	    - the EJB reference name used in the code of
+	      the Deployment Component that's referencing the enterprise
+	      bean
+	    - the expected type of the referenced enterprise bean
+	    - the expected home and remote interfaces of the referenced
+	      enterprise bean
+	    - optional ejb-link information, used to specify the
+	      referenced enterprise bean
+
+      </xsd:documentation>
+    </xsd:annotation>
+
+    <xsd:sequence>
+      <xsd:element name="description"
+		   type="j2ee:descriptionType"
+		   minOccurs="0"
+		   maxOccurs="unbounded"/>
+      <xsd:element name="ejb-ref-name"
+		   type="j2ee:ejb-ref-nameType"/>
+      <xsd:element name="ejb-ref-type"
+		   type="j2ee:ejb-ref-typeType"/>
+
+      <xsd:element name="home"
+		   type="j2ee:homeType"/>
+      <xsd:element name="remote"
+		   type="j2ee:remoteType"/>
+      <xsd:element name="ejb-link"
+		   type="j2ee:ejb-linkType"
+		   minOccurs="0"/>
+    </xsd:sequence>
+    <xsd:attribute name="id" type="xsd:ID"/>
+  </xsd:complexType>
+
+<!-- **************************************************** -->
+
+  <xsd:complexType name="emptyType">
+    <xsd:annotation>
+      <xsd:documentation>
+
+	This type is used to designate an empty
+	element when used.
+
+      </xsd:documentation>
+    </xsd:annotation>
+    <xsd:attribute name="id" type="xsd:ID"/>
+  </xsd:complexType>
+
+<!-- **************************************************** -->
+
+  <xsd:complexType name="env-entry-type-valuesType">
+    <xsd:annotation>
+      <xsd:documentation>
+	<![CDATA[
+
+	  This type contains the fully-qualified Java type of the
+	  environment entry value that is expected by the
+	  application's code.
+
+	  The following are the legal values of env-entry-type-valuesType:
+
+	      java.lang.Boolean
+	      java.lang.Byte
+	      java.lang.Character
+	      java.lang.String
+	      java.lang.Short
+	      java.lang.Integer
+	      java.lang.Long
+	      java.lang.Float
+	      java.lang.Double
+
+	  Example:
+
+	  <env-entry-type>java.lang.Boolean</env-entry-type>
+
+	  ]]>
+      </xsd:documentation>
+    </xsd:annotation>
+    <xsd:simpleContent>
+      <xsd:restriction base="j2ee:string">
+	<xsd:enumeration value="java.lang.Boolean"/>
+	<xsd:enumeration value="java.lang.Byte"/>
+	<xsd:enumeration value="java.lang.Character"/>
+	<xsd:enumeration value="java.lang.String"/>
+	<xsd:enumeration value="java.lang.Short"/>
+	<xsd:enumeration value="java.lang.Integer"/>
+	<xsd:enumeration value="java.lang.Long"/>
+	<xsd:enumeration value="java.lang.Float"/>
+	<xsd:enumeration value="java.lang.Double"/>
+      </xsd:restriction>
+    </xsd:simpleContent>
+  </xsd:complexType>
+
+<!-- **************************************************** -->
+
+  <xsd:complexType name="env-entryType">
+    <xsd:annotation>
+      <xsd:documentation>
+
+	The env-entryType is used to declare an application's
+	environment entry. The declaration consists of an optional
+	description, the name of the environment entry, and an
+	optional value.  If a value is not specified, one must be
+	supplied during deployment.
+
+	It is used by env-entry elements.
+
+      </xsd:documentation>
+    </xsd:annotation>
+
+    <xsd:sequence>
+      <xsd:element name="description"
+		   type="j2ee:descriptionType"
+		   minOccurs="0"
+		   maxOccurs="unbounded"/>
+      <xsd:element name="env-entry-name"
+		   type="j2ee:jndi-nameType">
+	<xsd:annotation>
+	  <xsd:documentation>
+	    <![CDATA[
+
+	      The env-entry-name element contains the name of a
+	      Deployment Component's environment entry.  The name
+	      is a JNDI name relative to the java:comp/env
+	      context.  The name must be unique within a
+	      Deployment Component. The uniqueness
+	      constraints must be defined within the declared
+	      context.
+
+	      Example:
+
+	      <env-entry-name>minAmount</env-entry-name>
+
+	      ]]>
+	  </xsd:documentation>
+	</xsd:annotation>
+      </xsd:element>
+
+      <xsd:element name="env-entry-type"
+		   type="j2ee:env-entry-type-valuesType"/>
+
+      <xsd:element name="env-entry-value"
+		   type="j2ee:xsdStringType"
+		   minOccurs="0">
+	<xsd:annotation>
+	  <xsd:documentation>
+	    <![CDATA[
+
+	      The env-entry-value designates the value of a
+	      Deployment Component's environment entry. The value
+	      must be a String that is valid for the
+	      constructor of the specified type that takes a
+	      single String parameter, or for java.lang.Character,
+	      a single character.
+
+	      Example:
+
+	      <env-entry-value>100.00</env-entry-value>
+
+	      ]]>
+	  </xsd:documentation>
+	</xsd:annotation>
+      </xsd:element>
+
+    </xsd:sequence>
+    <xsd:attribute name="id" type="xsd:ID"/>
+  </xsd:complexType>
+
+<!-- **************************************************** -->
+
+  <xsd:complexType name="fully-qualified-classType">
+    <xsd:annotation>
+      <xsd:documentation>
+
+	The elements that use this type designate the name of a
+	Java class or interface.  The name is in the form of a
+	"binary name", as defined in the JLS.  This is the form
+	of name used in Class.forName().  Tools that need the
+	canonical name (the name used in source code) will need
+	to convert this binary name to the canonical name.
+
+      </xsd:documentation>
+    </xsd:annotation>
+    <xsd:simpleContent>
+      <xsd:restriction base="j2ee:string"/>
+    </xsd:simpleContent>
+  </xsd:complexType>
+
+<!-- **************************************************** -->
+
+  <xsd:complexType name="generic-booleanType">
+    <xsd:annotation>
+      <xsd:documentation>
+
+	This type defines four different values which can designate
+	boolean values. This includes values yes and no which are
+	not designated by xsd:boolean
+
+      </xsd:documentation>
+    </xsd:annotation>
+    <xsd:simpleContent>
+      <xsd:restriction base="j2ee:string">
+	<xsd:enumeration value="true"/>
+	<xsd:enumeration value="false"/>
+	<xsd:enumeration value="yes"/>
+	<xsd:enumeration value="no"/>
+      </xsd:restriction>
+    </xsd:simpleContent>
+  </xsd:complexType>
+
+<!-- **************************************************** -->
+
+  <xsd:complexType name="homeType">
+    <xsd:annotation>
+      <xsd:documentation>
+	<![CDATA[
+
+	  The homeType defines the fully-qualified name of
+	  an enterprise bean's home interface.
+
+	  Example:
+
+	      <home>com.aardvark.payroll.PayrollHome</home>
+
+	  ]]>
+      </xsd:documentation>
+    </xsd:annotation>
+    <xsd:simpleContent>
+      <xsd:restriction base="j2ee:fully-qualified-classType"/>
+    </xsd:simpleContent>
+  </xsd:complexType>
+
+<!-- **************************************************** -->
+
+  <xsd:complexType name="iconType">
+    <xsd:annotation>
+      <xsd:documentation>
+
+	The icon type contains small-icon and large-icon elements
+	that specify the file names for small and large GIF or
+	JPEG icon images used to represent the parent element in a
+	GUI tool.
+
+	The xml:lang attribute defines the language that the
+	icon file names are provided in. Its value is "en" (English)
+	by default.
+
+      </xsd:documentation>
+    </xsd:annotation>
+
+    <xsd:sequence>
+      <xsd:element name="small-icon" type="j2ee:pathType"
+		   minOccurs="0">
+	<xsd:annotation>
+	  <xsd:documentation>
+	    <![CDATA[
+
+	      The small-icon element contains the name of a file
+	      containing a small (16 x 16) icon image. The file
+	      name is a relative path within the Deployment
+	      Component's Deployment File.
+
+	      The image may be either in the JPEG or GIF format.
+	      The icon can be used by tools.
+
+	      Example:
+
+	      <small-icon>employee-service-icon16x16.jpg</small-icon>
+
+	      ]]>
+	  </xsd:documentation>
+	</xsd:annotation>
+      </xsd:element>
+      <xsd:element name="large-icon" type="j2ee:pathType"
+		   minOccurs="0">
+	<xsd:annotation>
+	  <xsd:documentation>
+	    <![CDATA[
+
+	      The large-icon element contains the name of a file
+	      containing a large
+	      (32 x 32) icon image. The file name is a relative
+	      path within the Deployment Component's Deployment
+	      File.
+
+	      The image may be either in the JPEG or GIF format.
+	      The icon can be used by tools.
+
+	      Example:
+
+	      <large-icon>employee-service-icon32x32.jpg</large-icon>
+
+	      ]]>
+	  </xsd:documentation>
+	</xsd:annotation>
+      </xsd:element>
+
+    </xsd:sequence>
+
+    <xsd:attribute ref="xml:lang"/>
+    <xsd:attribute name="id" type="xsd:ID"/>
+
+  </xsd:complexType>
+
+<!-- **************************************************** -->
+
+  <xsd:complexType name="java-identifierType">
+    <xsd:annotation>
+      <xsd:documentation>
+
+	The java-identifierType defines a Java identifier.
+	The users of this type should further verify that
+	the content does not contain Java reserved keywords.
+
+      </xsd:documentation>
+    </xsd:annotation>
+    <xsd:simpleContent>
+      <xsd:restriction base="j2ee:string">
+	<xsd:pattern value="($|_|\p{L})(\p{L}|\p{Nd}|_|$)*"/>
+      </xsd:restriction>
+    </xsd:simpleContent>
+  </xsd:complexType>
+
+<!-- **************************************************** -->
+
+  <xsd:complexType name="java-typeType">
+    <xsd:annotation>
+      <xsd:documentation>
+
+	This is a generic type that designates a Java primitive
+	type or a fully qualified name of a Java interface/type,
+	or an array of such types.
+
+      </xsd:documentation>
+    </xsd:annotation>
+    <xsd:simpleContent>
+      <xsd:restriction base="j2ee:string">
+	<xsd:pattern value="[^\p{Z}]*"/>
+      </xsd:restriction>
+    </xsd:simpleContent>
+  </xsd:complexType>
+
+<!-- **************************************************** -->
+
+  <xsd:complexType name="jndi-nameType">
+    <xsd:annotation>
+      <xsd:documentation>
+
+	The jndi-nameType type designates a JNDI name in the
+	Deployment Component's environment and is relative to the
+	java:comp/env context.  A JNDI name must be unique within the
+	Deployment Component.
+
+      </xsd:documentation>
+    </xsd:annotation>
+    <xsd:simpleContent>
+      <xsd:restriction base="j2ee:string"/>
+    </xsd:simpleContent>
+  </xsd:complexType>
+
+<!-- **************************************************** -->
+
+  <xsd:group name="jndiEnvironmentRefsGroup">
+    <xsd:annotation>
+      <xsd:documentation>
+
+	This group keeps the usage of the contained JNDI environment
+	reference elements consistent across J2EE deployment descriptors.
+
+      </xsd:documentation>
+    </xsd:annotation>
+    <xsd:sequence>
+      <xsd:element name="env-entry"
+		   type="j2ee:env-entryType"
+		   minOccurs="0" maxOccurs="unbounded"/>
+      <xsd:element name="ejb-ref"
+		   type="j2ee:ejb-refType"
+		   minOccurs="0" maxOccurs="unbounded"/>
+      <xsd:element name="ejb-local-ref"
+		   type="j2ee:ejb-local-refType"
+		   minOccurs="0" maxOccurs="unbounded"/>
+      <xsd:group ref="j2ee:service-refGroup"/>
+      <xsd:element name="resource-ref"
+		   type="j2ee:resource-refType"
+		   minOccurs="0" maxOccurs="unbounded"/>
+      <xsd:element name="resource-env-ref"
+		   type="j2ee:resource-env-refType"
+		   minOccurs="0" maxOccurs="unbounded"/>
+      <xsd:element name="message-destination-ref"
+		   type="j2ee:message-destination-refType"
+		   minOccurs="0" maxOccurs="unbounded"/>
+    </xsd:sequence>
+  </xsd:group>
+
+<!-- **************************************************** -->
+
+  <xsd:complexType name="listenerType">
+    <xsd:annotation>
+      <xsd:documentation>
+
+	The listenerType indicates the deployment properties for a web
+	application listener bean.
+
+      </xsd:documentation>
+    </xsd:annotation>
+
+    <xsd:sequence>
+      <xsd:group ref="j2ee:descriptionGroup"/>
+      <xsd:element name="listener-class"
+		   type="j2ee:fully-qualified-classType">
+	<xsd:annotation>
+	  <xsd:documentation>
+
+	    The listener-class element declares a class in the
+	    application must be registered as a web
+	    application listener bean. The value is the fully
+	    qualified classname of the listener class.
+
+	  </xsd:documentation>
+	</xsd:annotation>
+      </xsd:element>
+    </xsd:sequence>
+    <xsd:attribute name="id" type="xsd:ID"/>
+  </xsd:complexType>
+
+<!-- **************************************************** -->
+
+  <xsd:complexType name="local-homeType">
+    <xsd:annotation>
+      <xsd:documentation>
+
+	The local-homeType defines the fully-qualified
+	name of an enterprise bean's local home interface.
+
+      </xsd:documentation>
+    </xsd:annotation>
+    <xsd:simpleContent>
+      <xsd:restriction base="j2ee:fully-qualified-classType"/>
+    </xsd:simpleContent>
+  </xsd:complexType>
+
+<!-- **************************************************** -->
+
+  <xsd:complexType name="localType">
+    <xsd:annotation>
+      <xsd:documentation>
+
+	The localType defines the fully-qualified name of an
+	enterprise bean's local interface.
+
+      </xsd:documentation>
+    </xsd:annotation>
+    <xsd:simpleContent>
+      <xsd:restriction base="j2ee:fully-qualified-classType"/>
+    </xsd:simpleContent>
+  </xsd:complexType>
+
+<!-- **************************************************** -->
+
+  <xsd:complexType name="message-destination-linkType">
+    <xsd:annotation>
+      <xsd:documentation>
+
+	The message-destination-linkType is used to link a message
+	destination reference or message-driven bean to a message
+	destination.
+
+	The Assembler sets the value to reflect the flow of messages
+	between producers and consumers in the application.
+
+	The value must be the message-destination-name of a message
+	destination in the same Deployment File or in another
+	Deployment File in the same J2EE application unit.
+
+	Alternatively, the value may be composed of a path name
+	specifying a Deployment File containing the referenced
+	message destination with the message-destination-name of the
+	destination appended and separated from the path name by
+	"#". The path name is relative to the Deployment File
+	containing Deployment Component that is referencing the
+	message destination.  This allows multiple message
+	destinations with the same name to be uniquely identified.
+
+      </xsd:documentation>
+    </xsd:annotation>
+    <xsd:simpleContent>
+      <xsd:restriction base="j2ee:string"/>
+    </xsd:simpleContent>
+  </xsd:complexType>
+
+<!-- **************************************************** -->
+
+  <xsd:complexType name="message-destination-refType">
+    <xsd:annotation>
+      <xsd:documentation>
+	<![CDATA[
+
+	  The message-destination-ref element contains a declaration
+	  of Deployment Component's reference to a message destination
+	  associated with a resource in Deployment Component's
+	  environment. It consists of:
+
+		  - an optional description
+		  - the message destination reference name
+		  - the message destination type
+		  - a specification as to whether the
+		    destination is used for
+		    consuming or producing messages, or both
+		  - a link to the message destination
+
+	  Examples:
+
+	  <message-destination-ref>
+		  <message-destination-ref-name>jms/StockQueue
+		  </message-destination-ref-name>
+		  <message-destination-type>javax.jms.Queue
+		  </message-destination-type>
+		  <message-destination-usage>Consumes
+		  </message-destination-usage>
+		  <message-destination-link>CorporateStocks
+		  </message-destination-link>
+	  </message-destination-ref>
+
+	  ]]>
+      </xsd:documentation>
+    </xsd:annotation>
+    <xsd:sequence>
+      <xsd:element name="description"
+		   type="j2ee:descriptionType"
+		   minOccurs="0"
+		   maxOccurs="unbounded"/>
+      <xsd:element name="message-destination-ref-name"
+		   type="j2ee:jndi-nameType">
+	<xsd:annotation>
+	  <xsd:documentation>
+
+	    The message-destination-ref-name element specifies
+	    the name of a message destination reference; its
+	    value is the environment entry name used in
+	    Deployment Component code.  The name is a JNDI name
+	    relative to the java:comp/env context and must be
+	    unique within an ejb-jar (for enterprise beans) or a
+	    Deployment File (for others).
+
+	  </xsd:documentation>
+	</xsd:annotation>
+      </xsd:element>
+      <xsd:element name="message-destination-type"
+		   type="j2ee:message-destination-typeType"/>
+      <xsd:element name="message-destination-usage"
+		   type="j2ee:message-destination-usageType"/>
+      <xsd:element name="message-destination-link"
+		   type="j2ee:message-destination-linkType"
+		   minOccurs="0"/>
+    </xsd:sequence>
+    <xsd:attribute name="id" type="xsd:ID"/>
+
+  </xsd:complexType>
+
+<!-- **************************************************** -->
+
+  <xsd:complexType name="message-destination-typeType">
+    <xsd:annotation>
+      <xsd:documentation>
+	<![CDATA[
+
+	  The message-destination-typeType specifies the type of
+	  the destination. The type is specified by the Java interface
+	  expected to be implemented by the destination.
+
+	  Example:
+
+	    <message-destination-type>javax.jms.Queue
+	    </message-destination-type>
+
+	  ]]>
+      </xsd:documentation>
+    </xsd:annotation>
+    <xsd:simpleContent>
+      <xsd:restriction base="j2ee:fully-qualified-classType"/>
+    </xsd:simpleContent>
+  </xsd:complexType>
+
+<!-- **************************************************** -->
+
+  <xsd:complexType name="message-destination-usageType">
+    <xsd:annotation>
+      <xsd:documentation>
+
+	The message-destination-usageType specifies the use of the
+	message destination indicated by the reference.  The value
+	indicates whether messages are consumed from the message
+	destination, produced for the destination, or both.  The
+	Assembler makes use of this information in linking producers
+	of a destination with its consumers.
+
+	The value of the message-destination-usage element must be
+	one of the following:
+	    Consumes
+	    Produces
+	    ConsumesProduces
+
+      </xsd:documentation>
+    </xsd:annotation>
+    <xsd:simpleContent>
+      <xsd:restriction base="j2ee:string">
+	<xsd:enumeration value="Consumes"/>
+	<xsd:enumeration value="Produces"/>
+	<xsd:enumeration value="ConsumesProduces"/>
+      </xsd:restriction>
+    </xsd:simpleContent>
+  </xsd:complexType>
+
+<!-- **************************************************** -->
+
+  <xsd:complexType name="message-destinationType">
+    <xsd:annotation>
+      <xsd:documentation>
+	<![CDATA[
+
+	  The message-destinationType specifies a message
+	  destination. The logical destination described by this
+	  element is mapped to a physical destination by the Deployer.
+
+	  The message destination element contains:
+
+		  - an optional description
+		  - an optional display-name
+		  - an optional icon
+		  - a message destination name which must be unique
+		    among message destination names within the same
+		    Deployment File.
+
+	  Example:
+
+	  <message-destination>
+		  <message-destination-name>CorporateStocks
+		  </message-destination-name>
+	  </message-destination>
+
+	  ]]>
+      </xsd:documentation>
+    </xsd:annotation>
+    <xsd:sequence>
+      <xsd:group ref="j2ee:descriptionGroup"/>
+      <xsd:element name="message-destination-name"
+		   type="j2ee:string">
+	<xsd:annotation>
+	  <xsd:documentation>
+
+	    The message-destination-name element specifies a
+	    name for a message destination.  This name must be
+	    unique among the names of message destinations
+	    within the Deployment File.
+
+	  </xsd:documentation>
+	</xsd:annotation>
+      </xsd:element>
+    </xsd:sequence>
+    <xsd:attribute name="id" type="xsd:ID"/>
+  </xsd:complexType>
+
+<!-- **************************************************** -->
+
+  <xsd:complexType name="param-valueType">
+    <xsd:annotation>
+      <xsd:documentation>
+
+	This type is a general type that can be used to declare
+	parameter/value lists.
+
+      </xsd:documentation>
+    </xsd:annotation>
+
+    <xsd:sequence>
+      <xsd:element name="description"
+		   type="j2ee:descriptionType"
+		   minOccurs="0"
+		   maxOccurs="unbounded"/>
+      <xsd:element name="param-name"
+		   type="j2ee:string">
+	<xsd:annotation>
+	  <xsd:documentation>
+
+	    The param-name element contains the name of a
+	    parameter.
+
+	  </xsd:documentation>
+	</xsd:annotation>
+      </xsd:element>
+
+      <xsd:element name="param-value"
+		   type="j2ee:xsdStringType">
+	<xsd:annotation>
+	  <xsd:documentation>
+
+	    The param-value element contains the value of a
+	    parameter.
+
+	  </xsd:documentation>
+	</xsd:annotation>
+      </xsd:element>
+    </xsd:sequence>
+    <xsd:attribute name="id" type="xsd:ID"/>
+  </xsd:complexType>
+
+<!-- **************************************************** -->
+
+  <xsd:complexType name="pathType">
+    <xsd:annotation>
+      <xsd:documentation>
+
+	The elements that use this type designate either a relative
+	path or an absolute path starting with a "/".
+
+	In elements that specify a pathname to a file within the
+	same Deployment File, relative filenames (i.e., those not
+	starting with "/") are considered relative to the root of
+	the Deployment File's namespace.  Absolute filenames (i.e.,
+	those starting with "/") also specify names in the root of
+	the Deployment File's namespace.  In general, relative names
+	are preferred.  The exception is .war files where absolute
+	names are preferred for consistency with the Servlet API.
+
+      </xsd:documentation>
+    </xsd:annotation>
+    <xsd:simpleContent>
+      <xsd:restriction base="j2ee:string"/>
+    </xsd:simpleContent>
+  </xsd:complexType>
+
+<!-- **************************************************** -->
+
+  <xsd:complexType name="remoteType">
+    <xsd:annotation>
+      <xsd:documentation>
+	<![CDATA[
+
+	  The remote element contains the fully-qualified name
+	  of the enterprise bean's remote interface.
+
+	  Example:
+
+	      <remote>com.wombat.empl.EmployeeService</remote>
+
+	  ]]>
+      </xsd:documentation>
+    </xsd:annotation>
+    <xsd:simpleContent>
+      <xsd:restriction base="j2ee:fully-qualified-classType"/>
+    </xsd:simpleContent>
+  </xsd:complexType>
+
+<!-- **************************************************** -->
+
+  <xsd:complexType name="res-authType">
+    <xsd:annotation>
+      <xsd:documentation>
+
+	The res-authType specifies whether the Deployment Component
+	code signs on programmatically to the resource manager, or
+	whether the Container will sign on to the resource manager
+	on behalf of the Deployment Component. In the latter case,
+	the Container uses information that is supplied by the
+	Deployer.
+
+	The value must be one of the two following:
+
+	    Application
+	    Container
+
+      </xsd:documentation>
+    </xsd:annotation>
+    <xsd:simpleContent>
+      <xsd:restriction base="j2ee:string">
+	<xsd:enumeration value="Application"/>
+	<xsd:enumeration value="Container"/>
+      </xsd:restriction>
+    </xsd:simpleContent>
+  </xsd:complexType>
+
+<!-- **************************************************** -->
+
+  <xsd:complexType name="res-sharing-scopeType">
+    <xsd:annotation>
+      <xsd:documentation>
+
+	The res-sharing-scope type specifies whether connections
+	obtained through the given resource manager connection
+	factory reference can be shared. The value, if specified,
+	must be one of the two following:
+
+	    Shareable
+	    Unshareable
+
+	The default value is Shareable.
+
+      </xsd:documentation>
+    </xsd:annotation>
+    <xsd:simpleContent>
+      <xsd:restriction base="j2ee:string">
+	<xsd:enumeration value="Shareable"/>
+	<xsd:enumeration value="Unshareable"/>
+      </xsd:restriction>
+    </xsd:simpleContent>
+  </xsd:complexType>
+
+<!-- **************************************************** -->
+
+  <xsd:complexType name="resource-env-refType">
+    <xsd:annotation>
+      <xsd:documentation>
+	<![CDATA[
+
+	  The resource-env-refType is used to define
+	  resource-env-type elements.  It contains a declaration of a
+	  Deployment Component's reference to an administered object
+	  associated with a resource in the Deployment Component's
+	  environment.  It consists of an optional description, the
+	  resource environment reference name, and an indication of
+	  the resource environment reference type expected by the
+	  Deployment Component code.
+
+	  Example:
+
+	  <resource-env-ref>
+	      <resource-env-ref-name>jms/StockQueue
+	      </resource-env-ref-name>
+	      <resource-env-ref-type>javax.jms.Queue
+	      </resource-env-ref-type>
+	  </resource-env-ref>
+
+	  ]]>
+      </xsd:documentation>
+    </xsd:annotation>
+
+    <xsd:sequence>
+      <xsd:element name="description"
+		   type="j2ee:descriptionType"
+		   minOccurs="0"
+		   maxOccurs="unbounded"/>
+      <xsd:element name="resource-env-ref-name"
+		   type="j2ee:jndi-nameType">
+	<xsd:annotation>
+	  <xsd:documentation>
+
+	    The resource-env-ref-name element specifies the name
+	    of a resource environment reference; its value is
+	    the environment entry name used in
+	    the Deployment Component code.  The name is a JNDI
+	    name relative to the java:comp/env context and must
+	    be unique within a Deployment Component.
+
+	  </xsd:documentation>
+	</xsd:annotation>
+      </xsd:element>
+
+      <xsd:element name="resource-env-ref-type"
+		   type="j2ee:fully-qualified-classType">
+	<xsd:annotation>
+	  <xsd:documentation>
+
+	    The resource-env-ref-type element specifies the type
+	    of a resource environment reference.  It is the
+	    fully qualified name of a Java language class or
+	    interface.
+
+	  </xsd:documentation>
+	</xsd:annotation>
+      </xsd:element>
+
+    </xsd:sequence>
+    <xsd:attribute name="id" type="xsd:ID"/>
+  </xsd:complexType>
+
+<!-- **************************************************** -->
+
+  <xsd:complexType name="resource-refType">
+    <xsd:annotation>
+      <xsd:documentation>
+	<![CDATA[
+
+	  The resource-refType contains a declaration of a
+	  Deployment Component's reference to an external resource. It
+	  consists of an optional description, the resource manager
+	  connection factory reference name, the indication of the
+	  resource manager connection factory type expected by the
+	  Deployment Component code, the type of authentication
+	  (Application or Container), and an optional specification of
+	  the shareability of connections obtained from the resource
+	  (Shareable or Unshareable).
+
+	  Example:
+
+	  <resource-ref>
+	      <res-ref-name>jdbc/EmployeeAppDB</res-ref-name>
+	      <res-type>javax.sql.DataSource</res-type>
+	      <res-auth>Container</res-auth>
+	      <res-sharing-scope>Shareable</res-sharing-scope>
+	  </resource-ref>
+
+	  ]]>
+      </xsd:documentation>
+    </xsd:annotation>
+
+    <xsd:sequence>
+      <xsd:element name="description"
+		   type="j2ee:descriptionType"
+		   minOccurs="0"
+		   maxOccurs="unbounded"/>
+      <xsd:element name="res-ref-name"
+		   type="j2ee:jndi-nameType">
+	<xsd:annotation>
+	  <xsd:documentation>
+
+	    The res-ref-name element specifies the name of a
+	    resource manager connection factory reference.
+	    The name is a JNDI name relative to the
+	    java:comp/env context.
+	    The name must be unique within a Deployment File.
+
+	  </xsd:documentation>
+	</xsd:annotation>
+      </xsd:element>
+
+      <xsd:element name="res-type"
+		   type="j2ee:fully-qualified-classType">
+	<xsd:annotation>
+	  <xsd:documentation>
+
+	    The res-type element specifies the type of the data
+	    source. The type is specified by the fully qualified
+	    Java language class or interface
+	    expected to be implemented by the data source.
+
+	  </xsd:documentation>
+	</xsd:annotation>
+      </xsd:element>
+
+      <xsd:element name="res-auth"
+		   type="j2ee:res-authType"/>
+
+      <xsd:element name="res-sharing-scope"
+		   type="j2ee:res-sharing-scopeType"
+		   minOccurs="0"/>
+    </xsd:sequence>
+    <xsd:attribute name="id" type="xsd:ID"/>
+  </xsd:complexType>
+
+<!-- **************************************************** -->
+
+  <xsd:complexType name="role-nameType">
+    <xsd:annotation>
+      <xsd:documentation>
+
+	The role-nameType designates the name of a security role.
+
+	The name must conform to the lexical rules for a token.
+
+      </xsd:documentation>
+    </xsd:annotation>
+
+    <xsd:simpleContent>
+      <xsd:restriction base="j2ee:string"/>
+    </xsd:simpleContent>
+  </xsd:complexType>
+
+<!-- **************************************************** -->
+
+  <xsd:complexType name="run-asType">
+    <xsd:annotation>
+      <xsd:documentation>
+
+	The run-asType specifies the run-as identity to be
+	used for the execution of a component. It contains an
+	optional description, and the name of a security role.
+
+      </xsd:documentation>
+    </xsd:annotation>
+
+    <xsd:sequence>
+      <xsd:element name="description"
+		   type="j2ee:descriptionType"
+		   minOccurs="0"
+		   maxOccurs="unbounded"/>
+      <xsd:element name="role-name"
+		   type="j2ee:role-nameType"/>
+    </xsd:sequence>
+    <xsd:attribute name="id" type="xsd:ID"/>
+  </xsd:complexType>
+
+<!-- **************************************************** -->
+
+  <xsd:complexType name="security-role-refType">
+    <xsd:annotation>
+      <xsd:documentation>
+
+	The security-role-refType contains the declaration of a
+	security role reference in a component's or a
+	Deployment Component's code. The declaration consists of an
+	optional description, the security role name used in the
+	code, and an optional link to a security role. If the
+	security role is not specified, the Deployer must choose an
+	appropriate security role.
+
+      </xsd:documentation>
+    </xsd:annotation>
+
+    <xsd:sequence>
+      <xsd:element name="description"
+		   type="j2ee:descriptionType"
+		   minOccurs="0"
+		   maxOccurs="unbounded"/>
+      <xsd:element name="role-name"
+		   type="j2ee:role-nameType">
+	<xsd:annotation>
+	  <xsd:documentation>
+
+	    The value of the role-name element must be the String used
+	    as the parameter to the
+	    EJBContext.isCallerInRole(String roleName) method or the
+	    HttpServletRequest.isUserInRole(String role) method.
+
+	  </xsd:documentation>
+	</xsd:annotation>
+      </xsd:element>
+
+      <xsd:element name="role-link"
+		   type="j2ee:role-nameType"
+		   minOccurs="0">
+	<xsd:annotation>
+	  <xsd:documentation>
+
+	    The role-link element is a reference to a defined
+	    security role. The role-link element must contain
+	    the name of one of the security roles defined in the
+	    security-role elements.
+
+	  </xsd:documentation>
+	</xsd:annotation>
+      </xsd:element>
+    </xsd:sequence>
+    <xsd:attribute name="id" type="xsd:ID"/>
+  </xsd:complexType>
+
+<!-- **************************************************** -->
+
+  <xsd:complexType name="security-roleType">
+    <xsd:annotation>
+      <xsd:documentation>
+	<![CDATA[
+
+	  The security-roleType contains the definition of a security
+	  role. The definition consists of an optional description of the
+	  security role, and the security role name.
+
+	  Example:
+
+	      <security-role>
+	      <description>
+		  This role includes all employees who are authorized
+		  to access the employee service application.
+	      </description>
+	      <role-name>employee</role-name>
+	      </security-role>
+
+	  ]]>
+      </xsd:documentation>
+    </xsd:annotation>
+
+    <xsd:sequence>
+      <xsd:element name="description"
+		   type="j2ee:descriptionType"
+		   minOccurs="0"
+		   maxOccurs="unbounded"/>
+      <xsd:element name="role-name"
+		   type="j2ee:role-nameType"/>
+    </xsd:sequence>
+    <xsd:attribute name="id" type="xsd:ID"/>
+  </xsd:complexType>
+
+<!-- **************************************************** -->
+
+  <xsd:complexType name="string">
+    <xsd:annotation>
+      <xsd:documentation>
+
+	This is a special string datatype that is defined by J2EE as
+	a base type for defining collapsed strings. When schemas
+	require trailing/leading space elimination as well as
+	collapsing the existing whitespace, this base type may be
+	used.
+
+      </xsd:documentation>
+    </xsd:annotation>
+    <xsd:simpleContent>
+      <xsd:extension base="xsd:token">
+	<xsd:attribute name="id" type="xsd:ID"/>
+      </xsd:extension>
+    </xsd:simpleContent>
+  </xsd:complexType>
+
+<!-- **************************************************** -->
+
+  <xsd:complexType name="true-falseType">
+    <xsd:annotation>
+      <xsd:documentation>
+
+	This simple type designates a boolean with only two
+	permissible values
+
+	- true
+	- false
+
+      </xsd:documentation>
+    </xsd:annotation>
+    <xsd:simpleContent>
+      <xsd:restriction base="j2ee:xsdBooleanType">
+	<xsd:pattern value="(true|false)"/>
+      </xsd:restriction>
+    </xsd:simpleContent>
+  </xsd:complexType>
+
+<!-- **************************************************** -->
+
+  <xsd:complexType name="url-patternType">
+    <xsd:annotation>
+      <xsd:documentation>
+
+	The url-patternType contains the url pattern of the mapping.
+	It must follow the rules specified in Section 11.2 of the
+	Servlet API Specification. This pattern is assumed to be in
+	URL-decoded form and must not contain CR(#xD) or LF(#xA).
+	If it contains those characters, the container must inform
+	the developer with a descriptive error message.
+	The container must preserve all characters including whitespaces.
+
+      </xsd:documentation>
+    </xsd:annotation>
+    <xsd:simpleContent>
+      <xsd:extension base="xsd:string"/>
+    </xsd:simpleContent>
+  </xsd:complexType>
+
+<!-- **************************************************** -->
+
+  <xsd:complexType name="xsdAnyURIType">
+    <xsd:annotation>
+      <xsd:documentation>
+
+	This type adds an "id" attribute to xsd:anyURI.
+
+      </xsd:documentation>
+    </xsd:annotation>
+    <xsd:simpleContent>
+      <xsd:extension base="xsd:anyURI">
+	<xsd:attribute name="id" type="xsd:ID"/>
+      </xsd:extension>
+    </xsd:simpleContent>
+  </xsd:complexType>
+
+<!-- **************************************************** -->
+
+  <xsd:complexType name="xsdBooleanType">
+    <xsd:annotation>
+      <xsd:documentation>
+
+	This type adds an "id" attribute to xsd:boolean.
+
+      </xsd:documentation>
+    </xsd:annotation>
+    <xsd:simpleContent>
+      <xsd:extension base="xsd:boolean">
+	<xsd:attribute name="id" type="xsd:ID"/>
+      </xsd:extension>
+    </xsd:simpleContent>
+  </xsd:complexType>
+
+<!-- **************************************************** -->
+
+  <xsd:complexType name="xsdIntegerType">
+    <xsd:annotation>
+      <xsd:documentation>
+
+	This type adds an "id" attribute to xsd:integer.
+
+      </xsd:documentation>
+    </xsd:annotation>
+    <xsd:simpleContent>
+      <xsd:extension base="xsd:integer">
+	<xsd:attribute name="id" type="xsd:ID"/>
+      </xsd:extension>
+    </xsd:simpleContent>
+  </xsd:complexType>
+
+<!-- **************************************************** -->
+
+  <xsd:complexType name="xsdNMTOKENType">
+    <xsd:annotation>
+      <xsd:documentation>
+
+	This type adds an "id" attribute to xsd:NMTOKEN.
+
+      </xsd:documentation>
+    </xsd:annotation>
+    <xsd:simpleContent>
+      <xsd:extension base="xsd:NMTOKEN">
+	<xsd:attribute name="id" type="xsd:ID"/>
+      </xsd:extension>
+    </xsd:simpleContent>
+  </xsd:complexType>
+
+<!-- **************************************************** -->
+
+  <xsd:complexType name="xsdNonNegativeIntegerType">
+    <xsd:annotation>
+      <xsd:documentation>
+
+	This type adds an "id" attribute to xsd:nonNegativeInteger.
+
+      </xsd:documentation>
+    </xsd:annotation>
+    <xsd:simpleContent>
+      <xsd:extension base="xsd:nonNegativeInteger">
+	<xsd:attribute name="id" type="xsd:ID"/>
+      </xsd:extension>
+    </xsd:simpleContent>
+  </xsd:complexType>
+
+<!-- **************************************************** -->
+
+  <xsd:complexType name="xsdPositiveIntegerType">
+    <xsd:annotation>
+      <xsd:documentation>
+
+	This type adds an "id" attribute to xsd:positiveInteger.
+
+      </xsd:documentation>
+    </xsd:annotation>
+    <xsd:simpleContent>
+      <xsd:extension base="xsd:positiveInteger">
+	<xsd:attribute name="id" type="xsd:ID"/>
+      </xsd:extension>
+    </xsd:simpleContent>
+  </xsd:complexType>
+
+<!-- **************************************************** -->
+
+  <xsd:complexType name="xsdQNameType">
+    <xsd:annotation>
+      <xsd:documentation>
+
+	This type adds an "id" attribute to xsd:QName.
+
+      </xsd:documentation>
+    </xsd:annotation>
+    <xsd:simpleContent>
+      <xsd:extension base="xsd:QName">
+	<xsd:attribute name="id" type="xsd:ID"/>
+      </xsd:extension>
+    </xsd:simpleContent>
+  </xsd:complexType>
+
+<!-- **************************************************** -->
+
+  <xsd:complexType name="xsdStringType">
+    <xsd:annotation>
+      <xsd:documentation>
+
+	This type adds an "id" attribute to xsd:string.
+
+      </xsd:documentation>
+    </xsd:annotation>
+    <xsd:simpleContent>
+      <xsd:extension base="xsd:string">
+	<xsd:attribute name="id" type="xsd:ID"/>
+      </xsd:extension>
+    </xsd:simpleContent>
+  </xsd:complexType>
+
+</xsd:schema>
+

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/dtd/j2ee_web_services_1_1.xsd
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/dtd/j2ee_web_services_1_1.xsd	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/dtd/j2ee_web_services_1_1.xsd	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,504 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Copyright 2004 The Apache Software Foundation
+
+  Licensed 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.
+-->
+<xsd:schema xmlns="http://www.w3.org/2001/XMLSchema"
+	    targetNamespace="http://java.sun.com/xml/ns/j2ee"
+	    xmlns:j2ee="http://java.sun.com/xml/ns/j2ee"
+	    xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+	    elementFormDefault="qualified"
+	    attributeFormDefault="unqualified"
+	    version="1.1">
+  <xsd:annotation>
+    <xsd:documentation>
+      @(#)j2ee_web_services_1_1.xsds	1.11 02/11/03
+    </xsd:documentation>
+  </xsd:annotation>
+
+  <xsd:annotation>
+    <xsd:documentation>
+
+      Copyright 2002 Sun Microsystems, Inc., 901 San Antonio
+      Road, Palo Alto, California 94303, U.S.A. All rights
+      reserved.
+
+      Sun Microsystems, Inc. has intellectual property rights
+      relating to technology described in this document. In
+      particular, and without limitation, these intellectual
+      property rights may include one or more of the U.S. patents
+      listed at http://www.sun.com/patents and one or more
+      additional patents or pending patent applications in the
+      U.S. and other countries.
+
+      This document and the technology which it describes are
+      distributed under licenses restricting their use, copying,
+      distribution, and decompilation. No part of this document
+      may be reproduced in any form by any means without prior
+      written authorization of Sun and its licensors, if any.
+
+      Third-party software, including font technology, is
+      copyrighted and licensed from Sun suppliers.
+
+      Sun, Sun Microsystems, the Sun logo, Solaris, Java, J2EE,
+      JavaServer Pages, Enterprise JavaBeans and the Java Coffee
+      Cup logo are trademarks or registered trademarks of Sun
+      Microsystems, Inc. in the U.S. and other countries.
+
+      Federal Acquisitions: Commercial Software - Government Users
+      Subject to Standard License Terms and Conditions.
+
+    </xsd:documentation>
+  </xsd:annotation>
+  <xsd:annotation>
+    <xsd:documentation>
+
+      (C) Copyright International Business Machines Corporation 2002
+
+    </xsd:documentation>
+  </xsd:annotation>
+
+  <xsd:annotation>
+    <xsd:documentation>
+      <![CDATA[
+
+	The webservices element is the root element for the web services
+	deployment descriptor.  It specifies the set of web service
+	descriptions that are to be deployed into the J2EE Application
+	Server and the dependencies they have on container resources and
+	services.  The deployment descriptor must be named
+	"META-INF/webservices.xml" in the web services' jar file.
+
+	Used in: webservices.xml
+
+	All webservices deployment descriptors must indicate the
+	webservices schema by using the J2EE namespace:
+
+	http://java.sun.com/xml/ns/j2ee
+
+	and by indicating the version of the schema by using the version
+	element as shown below:
+
+	    <webservices 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://www.ibm.com/webservices/xsd/j2ee_web_services_1_1.xsd"
+	      version="1.1">
+	      ...
+	    </webservices>
+
+	The instance documents may indicate the published version of the
+	schema using the xsi:schemaLocation attribute for the J2EE
+	namespace with the following location:
+
+	http://www.ibm.com/webservices/xsd/j2ee_web_services_1_1.xsd
+
+	]]>
+    </xsd:documentation>
+  </xsd:annotation>
+
+  <xsd:annotation>
+    <xsd:documentation>
+
+      The following conventions apply to all J2EE
+      deployment descriptor elements unless indicated otherwise.
+
+      - In elements that specify a pathname to a file within the
+	same JAR file, relative filenames (i.e., those not
+	starting with "/") are considered relative to the root of
+	the JAR file's namespace.  Absolute filenames (i.e., those
+	starting with "/") also specify names in the root of the
+	JAR file's namespace.  In general, relative names are
+	preferred.  The exception is .war files where absolute
+	names are preferred for consistency with the Servlet API.
+
+    </xsd:documentation>
+  </xsd:annotation>
+
+  <xsd:include schemaLocation="j2ee_1_4.xsd"/>
+
+
+<!-- **************************************************** -->
+
+
+  <xsd:element name="webservices" type="j2ee:webservicesType">
+    <xsd:annotation>
+      <xsd:documentation>
+
+	The webservices element is the root element for the web services
+	deployment descriptor.  It specifies the set of web service
+	descriptions that are to be deployed into the J2EE Application Server
+	and the dependencies they have on container resources and services.
+
+	Used in: webservices.xml
+
+      </xsd:documentation>
+    </xsd:annotation>
+
+    <xsd:key name="webservice-description-name-key">
+      <xsd:annotation>
+	<xsd:documentation>
+
+	  The webservice-description-name identifies the collection of
+	  port-components associated with a WSDL file and JAX-RPC mapping. The
+	  name must be unique within the deployment descriptor.
+
+	</xsd:documentation>
+      </xsd:annotation>
+      <xsd:selector xpath="j2ee:webservice-description"/>
+      <xsd:field xpath="j2ee:webservice-description-name"/>
+    </xsd:key>
+  </xsd:element>
+
+<!-- **************************************************** -->
+
+  <xsd:complexType name="port-componentType">
+    <xsd:annotation>
+      <xsd:documentation>
+
+	The port-component element associates a WSDL port with a web service
+	interface and implementation.  It defines the name of the port as a
+	component, optional description, optional display name, optional iconic
+	representations, WSDL port QName, Service Endpoint Interface, Service
+	Implementation Bean.
+
+      </xsd:documentation>
+    </xsd:annotation>
+
+    <xsd:sequence>
+      <xsd:element name="description"
+		   type="j2ee:descriptionType"
+		   minOccurs="0" maxOccurs="1"/>
+      <xsd:element name="display-name"
+		   type="j2ee:display-nameType"
+		   minOccurs="0" maxOccurs="1"/>
+      <xsd:element name="icon"
+		   type="j2ee:iconType"
+		   minOccurs="0" maxOccurs="1"/>
+      <xsd:element name="port-component-name"
+		   type="j2ee:string">
+	<xsd:annotation>
+	  <xsd:documentation>
+	    <![CDATA[
+
+	      The port-component-name element specifies a port component's
+	      name.  This name is assigned by the module producer to name
+	      the service implementation bean in the module's deployment
+	      descriptor. The name must be unique among the port component
+	      names defined in the same module.
+
+	      Used in: port-component
+
+	      Example:
+		      <port-component-name>EmployeeService
+		      </port-component-name>
+
+	      ]]>
+	  </xsd:documentation>
+	</xsd:annotation>
+      </xsd:element>
+      <xsd:element name="wsdl-port"
+		   type="j2ee:xsdQNameType">
+	<xsd:annotation>
+	  <xsd:documentation>
+
+	    Defines the name space and local name part of the WSDL port QName.
+
+	  </xsd:documentation>
+	</xsd:annotation>
+      </xsd:element>
+      <xsd:element name="service-endpoint-interface"
+		   type="j2ee:fully-qualified-classType">
+	<xsd:annotation>
+	  <xsd:documentation>
+	    <![CDATA[
+
+	      The service-endpoint-interface element contains the
+	      fully-qualified name of the port component's Service Endpoint
+	      Interface.
+
+	      Used in: port-component
+
+	      Example:
+		      <remote>com.wombat.empl.EmployeeService</remote>
+
+	      ]]>
+	  </xsd:documentation>
+	</xsd:annotation>
+      </xsd:element>
+      <xsd:element name="service-impl-bean"
+		   type="j2ee:service-impl-beanType"/>
+
+      <xsd:element name="handler"
+		   type="j2ee:port-component_handlerType"
+		   minOccurs="0" maxOccurs="unbounded"/>
+    </xsd:sequence>
+    <xsd:attribute name="id" type="xsd:ID"/>
+  </xsd:complexType>
+
+<!-- **************************************************** -->
+
+  <xsd:complexType name="port-component_handlerType">
+    <xsd:annotation>
+      <xsd:documentation>
+
+	Declares the handler for a port-component. Handlers can access the
+	init-param name/value pairs using the HandlerInfo interface.
+
+	Used in: port-component
+
+      </xsd:documentation>
+    </xsd:annotation>
+    <xsd:sequence>
+      <xsd:group ref="j2ee:descriptionGroup"/>
+      <xsd:element name="handler-name"
+		   type="j2ee:string">
+	<xsd:annotation>
+	  <xsd:documentation>
+
+	    Defines the name of the handler. The name must be unique within the
+	    module.
+
+	  </xsd:documentation>
+	</xsd:annotation>
+      </xsd:element>
+      <xsd:element name="handler-class"
+		   type="j2ee:fully-qualified-classType">
+	<xsd:annotation>
+	  <xsd:documentation>
+
+	    Defines a fully qualified class name for the handler implementation.
+
+	  </xsd:documentation>
+	</xsd:annotation>
+      </xsd:element>
+      <xsd:element name="init-param"
+		   type="j2ee:param-valueType"
+		   minOccurs="0" maxOccurs="unbounded"/>
+
+      <xsd:element name="soap-header"
+		   type="j2ee:xsdQNameType"
+		   minOccurs="0" maxOccurs="unbounded">
+	<xsd:annotation>
+	  <xsd:documentation>
+
+	    Defines the QName of a SOAP header that will be processed by the
+	    handler.
+
+	  </xsd:documentation>
+	</xsd:annotation>
+      </xsd:element>
+      <xsd:element name="soap-role"
+		   type="j2ee:string"
+		   minOccurs="0" maxOccurs="unbounded">
+	<xsd:annotation>
+	  <xsd:documentation>
+
+	    The soap-role element contains a SOAP actor definition that the
+	    Handler will play as a role.
+
+	  </xsd:documentation>
+	</xsd:annotation>
+      </xsd:element>
+    </xsd:sequence>
+    <xsd:attribute name="id" type="xsd:ID"/>
+  </xsd:complexType>
+
+<!-- **************************************************** -->
+
+  <xsd:complexType name="service-impl-beanType">
+    <xsd:annotation>
+      <xsd:documentation>
+
+	The service-impl-bean element defines the web service implementation.
+	A service implementation can be an EJB bean class or JAX-RPC web
+	component.  Existing EJB implementations are exposed as a web service
+	using an ejb-link.
+
+	Used in: port-component
+
+      </xsd:documentation>
+    </xsd:annotation>
+    <xsd:choice>
+      <xsd:element name="ejb-link"
+		   type="j2ee:ejb-linkType"/>
+      <xsd:element name="servlet-link"
+		   type="j2ee:servlet-linkType"/>
+    </xsd:choice>
+    <xsd:attribute name="id" type="xsd:ID"/>
+  </xsd:complexType>
+
+<!-- **************************************************** -->
+
+  <xsd:complexType name="servlet-linkType">
+    <xsd:annotation>
+      <xsd:documentation>
+	<![CDATA[
+
+	  The servlet-link element is used in the service-impl-bean element
+	  to specify that a Service Implementation Bean is defined as a
+	  JAX-RPC Service Endpoint.
+
+	  The value of the servlet-link element must be the servlet-name of
+	  a JAX-RPC Service Endpoint in the same WAR file.
+
+	  Used in: service-impl-bean
+
+	  Example:
+		  <servlet-link>StockQuoteService</servlet-link>
+
+	  ]]>
+      </xsd:documentation>
+    </xsd:annotation>
+    <xsd:simpleContent>
+      <xsd:restriction base="j2ee:string"/>
+    </xsd:simpleContent>
+  </xsd:complexType>
+
+<!-- **************************************************** -->
+
+  <xsd:complexType name="webservice-descriptionType">
+    <xsd:annotation>
+      <xsd:documentation>
+
+	The webservice-description element defines a WSDL document file
+	and the set of Port components associated with the WSDL ports
+	defined in the WSDL document.  There may be multiple
+	webservice-descriptions defined within a module.
+
+	All WSDL file ports must have a corresponding port-component element
+	defined.
+
+	Used in: webservices
+
+      </xsd:documentation>
+    </xsd:annotation>
+
+    <xsd:sequence>
+      <xsd:element name="description"
+		   type="j2ee:descriptionType"
+		   minOccurs="0" maxOccurs="1"/>
+      <xsd:element name="display-name"
+		   type="j2ee:display-nameType"
+		   minOccurs="0" maxOccurs="1"/>
+      <xsd:element name="icon"
+		   type="j2ee:iconType"
+		   minOccurs="0" maxOccurs="1"/>
+      <xsd:element name="webservice-description-name"
+		   type="j2ee:string">
+	<xsd:annotation>
+	  <xsd:documentation>
+
+	    The webservice-description-name identifies the collection of
+	    port-components associated with a WSDL file and JAX-RPC
+	    mapping. The name must be unique within the deployment descriptor.
+
+	  </xsd:documentation>
+	</xsd:annotation>
+      </xsd:element>
+      <xsd:element name="wsdl-file"
+		   type="j2ee:pathType">
+	<xsd:annotation>
+	  <xsd:documentation>
+
+	    The wsdl-file element contains the name of a WSDL file in the
+	    module.  The file name is a relative path within the module.
+
+	  </xsd:documentation>
+	</xsd:annotation>
+      </xsd:element>
+      <xsd:element name="jaxrpc-mapping-file"
+		   type="j2ee:pathType">
+	<xsd:annotation>
+	  <xsd:documentation>
+
+	    The jaxrpc-mapping-file element contains the name of a file that
+	    describes the JAX-RPC mapping between the Java interaces used by
+	    the application and the WSDL description in the wsdl-file.  The
+	    file name is a relative path within the module.
+
+	  </xsd:documentation>
+	</xsd:annotation>
+      </xsd:element>
+      <xsd:element name="port-component"
+		   type="j2ee:port-componentType"
+		   minOccurs="1" maxOccurs="unbounded">
+	<xsd:key name="port-component_handler-name-key">
+	  <xsd:annotation>
+	    <xsd:documentation>
+
+	      Defines the name of the handler. The name must be unique
+	      within the module.
+
+	    </xsd:documentation>
+	  </xsd:annotation>
+	  <xsd:selector xpath="j2ee:handler"/>
+	  <xsd:field xpath="j2ee:handler-name"/>
+	</xsd:key>
+      </xsd:element>
+    </xsd:sequence>
+    <xsd:attribute name="id" type="xsd:ID"/>
+  </xsd:complexType>
+
+<!-- **************************************************** -->
+
+  <xsd:complexType name="webservicesType">
+    <xsd:sequence>
+      <xsd:group ref="j2ee:descriptionGroup"/>
+      <xsd:element name="webservice-description"
+		   type="j2ee:webservice-descriptionType"
+		   minOccurs="1" maxOccurs="unbounded">
+	<xsd:key name="port-component-name-key">
+	  <xsd:annotation>
+	    <xsd:documentation>
+	      <![CDATA[
+
+		The port-component-name element specifies a port
+		component's name.  This name is assigned by the module
+		producer to name the service implementation bean in the
+		module's deployment descriptor. The name must be unique
+		among the port component names defined in the same module.
+
+		Used in: port-component
+
+		Example:
+			<port-component-name>EmployeeService
+			</port-component-name>
+
+		]]>
+	    </xsd:documentation>
+	  </xsd:annotation>
+	  <xsd:selector xpath="j2ee:port-component"/>
+	  <xsd:field xpath="j2ee:port-component-name"/>
+	</xsd:key>
+      </xsd:element>
+    </xsd:sequence>
+
+    <xsd:attribute name="version"
+		   type="j2ee:dewey-versionType"
+		   fixed="1.1"
+		   use="required">
+      <xsd:annotation>
+	<xsd:documentation>
+
+	  The required value for the version is 1.1.
+
+	</xsd:documentation>
+      </xsd:annotation>
+    </xsd:attribute>
+    <xsd:attribute name="id" type="xsd:ID"/>
+  </xsd:complexType>
+
+</xsd:schema>
+

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/dtd/j2ee_web_services_client_1_1.xsd
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/dtd/j2ee_web_services_client_1_1.xsd	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/dtd/j2ee_web_services_client_1_1.xsd	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,358 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Copyright 2004 The Apache Software Foundation
+
+  Licensed 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.
+-->
+<xsd:schema xmlns="http://www.w3.org/2001/XMLSchema"
+	    targetNamespace="http://java.sun.com/xml/ns/j2ee"
+	    xmlns:j2ee="http://java.sun.com/xml/ns/j2ee"
+	    xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+	    elementFormDefault="qualified"
+	    attributeFormDefault="unqualified"
+	    version="1.1">
+  <xsd:annotation>
+    <xsd:documentation>
+      @(#)j2ee_web_services_client_1_1.xsds	1.10 02/11/03
+    </xsd:documentation>
+  </xsd:annotation>
+
+  <xsd:annotation>
+    <xsd:documentation>
+
+      Copyright 2002 Sun Microsystems, Inc., 901 San Antonio
+      Road, Palo Alto, California 94303, U.S.A. All rights
+      reserved.
+
+      Sun Microsystems, Inc. has intellectual property rights
+      relating to technology described in this document. In
+      particular, and without limitation, these intellectual
+      property rights may include one or more of the U.S. patents
+      listed at http://www.sun.com/patents and one or more
+      additional patents or pending patent applications in the
+      U.S. and other countries.
+
+      This document and the technology which it describes are
+      distributed under licenses restricting their use, copying,
+      distribution, and decompilation. No part of this document
+      may be reproduced in any form by any means without prior
+      written authorization of Sun and its licensors, if any.
+
+      Third-party software, including font technology, is
+      copyrighted and licensed from Sun suppliers.
+
+      Sun, Sun Microsystems, the Sun logo, Solaris, Java, J2EE,
+      JavaServer Pages, Enterprise JavaBeans and the Java Coffee
+      Cup logo are trademarks or registered trademarks of Sun
+      Microsystems, Inc. in the U.S. and other countries.
+
+      Federal Acquisitions: Commercial Software - Government Users
+      Subject to Standard License Terms and Conditions.
+
+    </xsd:documentation>
+  </xsd:annotation>
+  <xsd:annotation>
+    <xsd:documentation>
+
+      (C) Copyright International Business Machines Corporation 2002
+
+    </xsd:documentation>
+  </xsd:annotation>
+
+
+<!-- **************************************************** -->
+
+  <xsd:complexType name="port-component-refType">
+    <xsd:annotation>
+      <xsd:documentation>
+
+	The port-component-ref element declares a client dependency
+	on the container for resolving a Service Endpoint Interface
+	to a WSDL port. It optionally associates the Service Endpoint
+	Interface with a particular port-component. This is only used
+	by the container for a Service.getPort(Class) method call.
+
+      </xsd:documentation>
+    </xsd:annotation>
+
+    <xsd:sequence>
+      <xsd:element name="service-endpoint-interface"
+		   type="j2ee:fully-qualified-classType">
+	<xsd:annotation>
+	  <xsd:documentation>
+
+	    The service-endpoint-interface element defines a fully qualified
+	    Java class that represents the Service Endpoint Interface of a
+	    WSDL port.
+
+	  </xsd:documentation>
+	</xsd:annotation>
+      </xsd:element>
+
+      <xsd:element name="port-component-link"
+		   type="j2ee:string"
+		   minOccurs="0" maxOccurs="1">
+	<xsd:annotation>
+	  <xsd:documentation>
+
+	    The port-component-link element links a port-component-ref
+	    to a specific port-component required to be made available
+	    by a service reference.
+
+	    The value of a port-component-link must be the
+	    port-component-name of a port-component in the same module
+	    or another module in the same application unit. The syntax
+	    for specification follows the syntax defined for ejb-link
+	    in the EJB 2.0 specification.
+
+	  </xsd:documentation>
+	</xsd:annotation>
+      </xsd:element>
+    </xsd:sequence>
+    <xsd:attribute name="id" type="xsd:ID"/>
+  </xsd:complexType>
+
+<!-- **************************************************** -->
+
+  <xsd:group name="service-refGroup">
+    <xsd:sequence>
+      <xsd:element name="service-ref"
+		   type="j2ee:service-refType"
+		   minOccurs="0" maxOccurs="unbounded">
+	<xsd:key name="service-ref_handler-name-key">
+	  <xsd:annotation>
+	    <xsd:documentation>
+
+	      Defines the name of the handler. The name must be unique
+	      within the module.
+
+	    </xsd:documentation>
+	  </xsd:annotation>
+	  <xsd:selector xpath="j2ee:handler"/>
+	  <xsd:field xpath="j2ee:handler-name"/>
+	</xsd:key>
+      </xsd:element>
+    </xsd:sequence>
+  </xsd:group>
+
+<!-- **************************************************** -->
+
+  <xsd:complexType name="service-refType">
+    <xsd:annotation>
+      <xsd:documentation>
+
+	The service-ref element declares a reference to a Web
+	service. It contains optional description, display name and
+	icons, a declaration of the required Service interface,
+	an optional WSDL document location, an optional set
+	of JAX-RPC mappings, an optional QName for the service element,
+	an optional set of Service Endpoint Interfaces to be resolved
+	by the container to a WSDL port, and an optional set of handlers.
+
+      </xsd:documentation>
+    </xsd:annotation>
+
+    <xsd:sequence>
+      <xsd:group ref="j2ee:descriptionGroup"/>
+      <xsd:element name="service-ref-name"
+		   type="j2ee:jndi-nameType">
+	<xsd:annotation>
+	  <xsd:documentation>
+
+	    The service-ref-name element declares logical name that the
+	    components in the module use to look up the Web service. It
+	    is recommended that all service reference names start with
+	    "service/".
+
+	  </xsd:documentation>
+	</xsd:annotation>
+      </xsd:element>
+
+      <xsd:element name="service-interface"
+		   type="j2ee:fully-qualified-classType">
+	<xsd:annotation>
+	  <xsd:documentation>
+
+	    The service-interface element declares the fully qualified class
+	    name of the JAX-RPC Service interface the client depends on.
+	    In most cases the value will be javax.xml.rpc.Service.  A JAX-RPC
+	    generated Service Interface class may also be specified.
+
+	  </xsd:documentation>
+	</xsd:annotation>
+      </xsd:element>
+
+      <xsd:element name="wsdl-file"
+		   type="j2ee:xsdAnyURIType"
+		   minOccurs="0" maxOccurs="1">
+	<xsd:annotation>
+	  <xsd:documentation>
+
+	    The wsdl-file element contains the URI location of a WSDL
+	    file. The location is relative to the root of the module.
+
+	  </xsd:documentation>
+	</xsd:annotation>
+      </xsd:element>
+
+      <xsd:element name="jaxrpc-mapping-file"
+		   type="j2ee:pathType"
+		   minOccurs="0" maxOccurs="1">
+	<xsd:annotation>
+	  <xsd:documentation>
+
+	    The jaxrpc-mapping-file element contains the name of a file that
+	    describes the JAX-RPC mapping between the Java interaces used by
+	    the application and the WSDL description in the wsdl-file.  The
+	    file name is a relative path within the module file.
+
+	  </xsd:documentation>
+	</xsd:annotation>
+      </xsd:element>
+
+      <xsd:element name="service-qname"
+		   type="j2ee:xsdQNameType"
+		   minOccurs="0" maxOccurs="1">
+	<xsd:annotation>
+	  <xsd:documentation>
+
+	    The service-qname element declares the specific WSDL service
+	    element that is being refered to.  It is not specified if no
+	    wsdl-file is declared.
+
+	  </xsd:documentation>
+	</xsd:annotation>
+      </xsd:element>
+
+      <xsd:element name="port-component-ref"
+		   type="j2ee:port-component-refType"
+		   minOccurs="0" maxOccurs="unbounded">
+	<xsd:annotation>
+	  <xsd:documentation>
+
+	    The port-component-ref element declares a client dependency
+	    on the container for resolving a Service Endpoint Interface
+	    to a WSDL port. It optionally associates the Service Endpoint
+	    Interface with a particular port-component. This is only used
+	    by the container for a Service.getPort(Class) method call.
+
+	  </xsd:documentation>
+	</xsd:annotation>
+      </xsd:element>
+
+      <xsd:element name="handler"
+		   type="j2ee:service-ref_handlerType"
+		   minOccurs="0" maxOccurs="unbounded">
+	<xsd:annotation>
+	  <xsd:documentation>
+
+	    Declares the handler for a port-component. Handlers can
+	    access the init-param name/value pairs using the
+	    HandlerInfo interface. If port-name is not specified, the
+	    handler is assumed to be associated with all ports of the
+	    service.
+
+	  </xsd:documentation>
+	</xsd:annotation>
+      </xsd:element>
+    </xsd:sequence>
+    <xsd:attribute name="id" type="xsd:ID"/>
+  </xsd:complexType>
+
+<!-- **************************************************** -->
+
+  <xsd:complexType name="service-ref_handlerType">
+    <xsd:annotation>
+      <xsd:documentation>
+
+	Declares the handler for a port-component. Handlers can access the
+	init-param name/value pairs using the HandlerInfo interface. If
+	port-name is not specified, the handler is assumed to be associated
+	with all ports of the service.
+
+	Used in: service-ref
+
+      </xsd:documentation>
+    </xsd:annotation>
+    <xsd:sequence>
+      <xsd:group ref="j2ee:descriptionGroup"/>
+      <xsd:element name="handler-name"
+		   type="j2ee:string">
+	<xsd:annotation>
+	  <xsd:documentation>
+
+	    Defines the name of the handler. The name must be unique
+	    within the module.
+
+	  </xsd:documentation>
+	</xsd:annotation>
+      </xsd:element>
+      <xsd:element name="handler-class"
+		   type="j2ee:fully-qualified-classType">
+	<xsd:annotation>
+	  <xsd:documentation>
+
+	    Defines a fully qualified class name for the handler
+	    implementation.
+
+	  </xsd:documentation>
+	</xsd:annotation>
+      </xsd:element>
+      <xsd:element name="init-param"
+		   type="j2ee:param-valueType"
+		   minOccurs="0" maxOccurs="unbounded"/>
+
+      <xsd:element name="soap-header"
+		   type="j2ee:xsdQNameType"
+		   minOccurs="0" maxOccurs="unbounded">
+	<xsd:annotation>
+	  <xsd:documentation>
+
+	    Defines the QName of a SOAP header that will be processed
+	    by the handler.
+
+	  </xsd:documentation>
+	</xsd:annotation>
+      </xsd:element>
+
+      <xsd:element name="soap-role"
+		   type="j2ee:string"
+		   minOccurs="0" maxOccurs="unbounded">
+	<xsd:annotation>
+	  <xsd:documentation>
+
+	    The soap-role element contains a SOAP actor definition that
+	    the Handler will play as a role.
+
+	  </xsd:documentation>
+	</xsd:annotation>
+      </xsd:element>
+
+      <xsd:element name="port-name"
+		   type="j2ee:string"
+		   minOccurs="0" maxOccurs="unbounded">
+	<xsd:annotation>
+	  <xsd:documentation>
+
+	    The port-name element defines the WSDL port-name that a
+	    handler should be associated with.
+
+	  </xsd:documentation>
+	</xsd:annotation>
+      </xsd:element>
+    </xsd:sequence>
+    <xsd:attribute name="id" type="xsd:ID"/>
+  </xsd:complexType>
+
+</xsd:schema>
+

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/dtd/jsp_2_0.xsd
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/dtd/jsp_2_0.xsd	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/dtd/jsp_2_0.xsd	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,322 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Copyright 2004 The Apache Software Foundation
+
+  Licensed 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.
+-->
+<xsd:schema xmlns="http://www.w3.org/2001/XMLSchema"
+	    targetNamespace="http://java.sun.com/xml/ns/j2ee"
+	    xmlns:j2ee="http://java.sun.com/xml/ns/j2ee"
+	    xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+	    elementFormDefault="qualified"
+	    attributeFormDefault="unqualified"
+	    version="2.0">
+  <xsd:annotation>
+    <xsd:documentation>
+      @(#)jsp_2_0.xsds	1.17 03/18/03
+    </xsd:documentation>
+  </xsd:annotation>
+
+  <xsd:annotation>
+    <xsd:documentation>
+
+      Copyright 2002 Sun Microsystems, Inc., 901 San Antonio
+      Road, Palo Alto, California 94303, U.S.A. All rights
+      reserved.
+
+      Sun Microsystems, Inc. has intellectual property rights
+      relating to technology described in this document. In
+      particular, and without limitation, these intellectual
+      property rights may include one or more of the U.S. patents
+      listed at http://www.sun.com/patents and one or more
+      additional patents or pending patent applications in the
+      U.S. and other countries.
+
+      This document and the technology which it describes are
+      distributed under licenses restricting their use, copying,
+      distribution, and decompilation. No part of this document
+      may be reproduced in any form by any means without prior
+      written authorization of Sun and its licensors, if any.
+
+      Third-party software, including font technology, is
+      copyrighted and licensed from Sun suppliers.
+
+      Sun, Sun Microsystems, the Sun logo, Solaris, Java, J2EE,
+      JavaServer Pages, Enterprise JavaBeans and the Java Coffee
+      Cup logo are trademarks or registered trademarks of Sun
+      Microsystems, Inc. in the U.S. and other countries.
+
+      Federal Acquisitions: Commercial Software - Government Users
+      Subject to Standard License Terms and Conditions.
+
+    </xsd:documentation>
+  </xsd:annotation>
+
+  <xsd:annotation>
+    <xsd:documentation>
+
+      This is the XML Schema for the JSP 2.0 deployment descriptor
+      types.  The JSP 2.0 schema contains all the special
+      structures and datatypes that are necessary to use JSP files
+      from a web application.
+
+      The contents of this schema is used by the web-app_2_4.xsd
+      file to define JSP specific content.
+
+    </xsd:documentation>
+  </xsd:annotation>
+
+  <xsd:annotation>
+    <xsd:documentation>
+
+      The following conventions apply to all J2EE
+      deployment descriptor elements unless indicated otherwise.
+
+      - In elements that specify a pathname to a file within the
+	same JAR file, relative filenames (i.e., those not
+	starting with "/") are considered relative to the root of
+	the JAR file's namespace.  Absolute filenames (i.e., those
+	starting with "/") also specify names in the root of the
+	JAR file's namespace.  In general, relative names are
+	preferred.  The exception is .war files where absolute
+	names are preferred for consistency with the Servlet API.
+
+    </xsd:documentation>
+  </xsd:annotation>
+
+  <xsd:include schemaLocation="j2ee_1_4.xsd"/>
+
+
+<!-- **************************************************** -->
+
+  <xsd:complexType name="jsp-configType">
+    <xsd:annotation>
+      <xsd:documentation>
+
+	The jsp-configType is used to provide global configuration
+	information for the JSP files in a web application. It has
+	two subelements, taglib and jsp-property-group.
+
+      </xsd:documentation>
+    </xsd:annotation>
+
+    <xsd:sequence>
+      <xsd:element name="taglib"
+		   type="j2ee:taglibType"
+		   minOccurs="0"
+		   maxOccurs="unbounded"/>
+      <xsd:element name="jsp-property-group"
+		   type="j2ee:jsp-property-groupType"
+		   minOccurs="0"
+		   maxOccurs="unbounded"/>
+    </xsd:sequence>
+    <xsd:attribute name="id" type="xsd:ID"/>
+  </xsd:complexType>
+
+<!-- **************************************************** -->
+
+  <xsd:complexType name="jsp-fileType">
+    <xsd:annotation>
+      <xsd:documentation>
+
+	The jsp-file element contains the full path to a JSP file
+	within the web application beginning with a `/'.
+
+      </xsd:documentation>
+    </xsd:annotation>
+
+    <xsd:simpleContent>
+      <xsd:restriction base="j2ee:pathType"/>
+    </xsd:simpleContent>
+  </xsd:complexType>
+
+<!-- **************************************************** -->
+
+  <xsd:complexType name="jsp-property-groupType">
+    <xsd:annotation>
+      <xsd:documentation>
+
+	The jsp-property-groupType is used to group a number of
+	files so they can be given global property information.
+	All files so described are deemed to be JSP files.  The
+	following additional properties can be described:
+
+	    - Control whether EL is ignored
+	    - Control whether scripting elements are invalid
+	    - Indicate pageEncoding information.
+	    - Indicate that a resource is a JSP document (XML)
+	    - Prelude and Coda automatic includes.
+
+      </xsd:documentation>
+    </xsd:annotation>
+
+    <xsd:sequence>
+      <xsd:group ref="j2ee:descriptionGroup"/>
+      <xsd:element name="url-pattern"
+		   type="j2ee:url-patternType"
+		   maxOccurs="unbounded"/>
+      <xsd:element name="el-ignored"
+		   type="j2ee:true-falseType"
+		   minOccurs="0">
+	<xsd:annotation>
+	  <xsd:documentation>
+
+	    Can be used to easily set the isELIgnored
+	    property of a group of JSP pages.  By default, the
+	    EL evaluation is enabled for Web Applications using
+	    a Servlet 2.4 or greater web.xml, and disabled
+	    otherwise.
+
+	  </xsd:documentation>
+	</xsd:annotation>
+      </xsd:element>
+      <xsd:element name="page-encoding"
+		   type="j2ee:string"
+		   minOccurs="0">
+	<xsd:annotation>
+	  <xsd:documentation>
+
+	    The valid values of page-encoding are those of the
+	    pageEncoding page directive.  It is a
+	    translation-time error to name different encodings
+	    in the pageEncoding attribute of the page directive
+	    of a JSP page and in a JSP configuration element
+	    matching the page.  It is also a translation-time
+	    error to name different encodings in the prolog
+	    or text declaration of a document in XML syntax and
+	    in a JSP configuration element matching the document.
+	    It is legal to name the same encoding through
+	    mulitple mechanisms.
+
+	  </xsd:documentation>
+	</xsd:annotation>
+      </xsd:element>
+      <xsd:element name="scripting-invalid"
+		   type="j2ee:true-falseType"
+		   minOccurs="0">
+	<xsd:annotation>
+	  <xsd:documentation>
+
+	    Can be used to easily disable scripting in a
+	    group of JSP pages.  By default, scripting is
+	    enabled.
+
+	  </xsd:documentation>
+	</xsd:annotation>
+      </xsd:element>
+      <xsd:element name="is-xml"
+		   type="j2ee:true-falseType"
+		   minOccurs="0">
+	<xsd:annotation>
+	  <xsd:documentation>
+
+	    If true, denotes that the group of resources
+	    that match the URL pattern are JSP documents,
+	    and thus must be interpreted as XML documents.
+	    If false, the resources are assumed to not
+	    be JSP documents, unless there is another
+	    property group that indicates otherwise.
+
+	  </xsd:documentation>
+	</xsd:annotation>
+      </xsd:element>
+      <xsd:element name="include-prelude"
+		   type="j2ee:pathType"
+		   minOccurs="0"
+		   maxOccurs="unbounded">
+	<xsd:annotation>
+	  <xsd:documentation>
+
+	    The include-prelude element is a context-relative
+	    path that must correspond to an element in the
+	    Web Application.  When the element is present,
+	    the given path will be automatically included (as
+	    in an include directive) at the beginning of each
+	    JSP page in this jsp-property-group.
+
+	  </xsd:documentation>
+	</xsd:annotation>
+      </xsd:element>
+      <xsd:element name="include-coda"
+		   type="j2ee:pathType"
+		   minOccurs="0"
+		   maxOccurs="unbounded">
+	<xsd:annotation>
+	  <xsd:documentation>
+
+	    The include-coda element is a context-relative
+	    path that must correspond to an element in the
+	    Web Application.  When the element is present,
+	    the given path will be automatically included (as
+	    in an include directive) at the end of each
+	    JSP page in this jsp-property-group.
+
+	  </xsd:documentation>
+	</xsd:annotation>
+      </xsd:element>
+    </xsd:sequence>
+    <xsd:attribute name="id" type="xsd:ID"/>
+  </xsd:complexType>
+
+<!-- **************************************************** -->
+
+  <xsd:complexType name="taglibType">
+    <xsd:annotation>
+      <xsd:documentation>
+
+	The taglibType defines the syntax for declaring in
+	the deployment descriptor that a tag library is
+	available to the application.  This can be done
+	to override implicit map entries from TLD files and
+	from the container.
+
+      </xsd:documentation>
+    </xsd:annotation>
+
+    <xsd:sequence>
+      <xsd:element name="taglib-uri"
+		   type="j2ee:string">
+	<xsd:annotation>
+	  <xsd:documentation>
+
+	    A taglib-uri element describes a URI identifying a
+	    tag library used in the web application.  The body
+	    of the taglib-uri element may be either an
+	    absolute URI specification, or a relative URI.
+	    There should be no entries in web.xml with the
+	    same taglib-uri value.
+
+	  </xsd:documentation>
+	</xsd:annotation>
+      </xsd:element>
+
+      <xsd:element name="taglib-location"
+		   type="j2ee:pathType">
+	<xsd:annotation>
+	  <xsd:documentation>
+
+	    the taglib-location element contains the location
+	    (as a resource relative to the root of the web
+	    application) where to find the Tag Library
+	    Description file for the tag library.
+
+	  </xsd:documentation>
+	</xsd:annotation>
+      </xsd:element>
+
+    </xsd:sequence>
+    <xsd:attribute name="id" type="xsd:ID"/>
+  </xsd:complexType>
+
+</xsd:schema>
+

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/dtd/jspxml.dtd
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/dtd/jspxml.dtd	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/dtd/jspxml.dtd	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,189 @@
+<!--
+  Copyright 2004 The Apache Software Foundation
+
+  Licensed 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.
+-->
+<!-- DTD for JSP 2.0
+     thanks to Bob Foster, WebGain
+-->
+
+<!-- 
+     This DTD is not conditional on any parameter entities in the internal
+     subset and does not export any general entities.
+-->
+
+<!--================== Constrained Names ====================================-->
+
+<!ENTITY % URI "CDATA">
+    <!-- a Uniform Resource Identifier, see [RFC2396] -->
+
+<!ENTITY % UriList "CDATA">
+    <!-- a space separated list of Uniform Resource Identifiers -->
+
+<!ENTITY % URL "CDATA">
+    <!-- a relative urlSpec is as in Section 2.10.2. -->
+
+<!ENTITY % BeanID "IDREF">
+    <!-- a previously declared bean ID in the current scope. -->
+
+<!ENTITY % Prefix "CDATA">
+    <!-- a Name that contains no : characters. -->
+
+<!ENTITY % ClassName "CDATA">
+    <!-- a fully qualified class name. -->
+
+<!ENTITY % TypeName "CDATA">
+    <!-- a fully qualified class or interface name. -->
+
+<!ENTITY % BeanName "CDATA">
+    <!-- a bean name as expected by java.beans.Beans instantiate(). -->
+
+<!ENTITY % Content "CDATA">
+    <!-- a MIME type followed by an IANA charset, as " type [; S? ['charset='] charset] " -->
+
+<!ENTITY % Length "CDATA">
+    <!-- nn for pixels or nn% for percentage length -->
+
+<!ENTITY % Pixels "CDATA">
+    <!-- integer representing length in pixels -->
+
+<!ENTITY % Bool "(true|false|yes|no)">
+    <!-- boolean -->
+
+<!-- used for object, applet, img, input and iframe -->
+<!ENTITY % ImgAlign "(top|middle|bottom|left|right)">
+
+<!--=================== Element Groups ====================================-->
+
+<!ENTITY % Directives "jsp:directive.page|jsp:directive.include">
+
+<!ENTITY % Scripts "jsp:scriptlet|jsp:declaration|jsp:expression">
+
+<!ENTITY % Actions
+    "jsp:useBean
+    |jsp:setProperty
+    |jsp:getProperty
+    |jsp:include
+    |jsp:forward
+    |jsp:plugin"
+>
+
+<!ENTITY % Body "(jsp:text|%Directives;|%Scripts;|%Actions;)*">
+
+
+<!-- ============================ Elements ============================ -->
+
+<!--    Root element of a JSP page.
+-->
+<!ELEMENT jsp:root %Body;>
+<!ATTLIST jsp:root
+    xmlns:jsp       CDATA           "http://java.sun.com/JSP/Page"
+    version         CDATA           #REQUIRED
+>
+
+<!ELEMENT jsp:directive.page EMPTY>
+<!ATTLIST jsp:directive.page
+    language        CDATA           "java"
+    extends         %ClassName;     #IMPLIED
+    contentType     %Content;       "text/html; ISO-8859-1"
+    import          CDATA           #IMPLIED
+    session         %Bool;          "true"
+    buffer          CDATA           "8kb"
+    autoFlush       %Bool;          "true"
+    isThreadSafe    %Bool;          "true"
+    info            CDATA           #IMPLIED
+    errorPage       %URL;           #IMPLIED
+    isErrorPage     %Bool;          "false"
+    pageEncoding    CDATA           #IMPLIED
+    isELIgnored     %Bool;          #IMPLIED
+>
+
+<!-- the jsp:directive.include only appears in JSP documents and does
+     not appear in the XML views of JSP pages.
+-->
+
+<!ELEMENT jsp:directive.include EMPTY>
+<!ATTLIST jsp:directive.include
+    file            %URI;           #REQUIRED
+>
+
+<!ELEMENT jsp:scriptlet (#PCDATA)>
+
+<!ELEMENT jsp:declaration (#PCDATA)>
+
+<!ELEMENT jsp:expression (#PCDATA)>
+
+<!ELEMENT jsp:useBean %Body;>
+<!ATTLIST jsp:useBean
+    id              ID              #REQUIRED
+    class           %ClassName;     #IMPLIED
+    type            %TypeName;      #IMPLIED
+    beanName        %BeanName;      #IMPLIED
+    scope           (page
+                    |session
+                    |request
+                    |application)   "page"
+>
+
+<!ELEMENT jsp:setProperty EMPTY>
+<!ATTLIST jsp:setProperty
+    name            %BeanID;        #REQUIRED
+    property        CDATA           #REQUIRED
+    value           CDATA           #IMPLIED
+    param           CDATA           #IMPLIED
+>
+
+<!ELEMENT jsp:getProperty EMPTY>
+<!ATTLIST jsp:getProperty
+    name            %BeanID;        #REQUIRED
+    property        CDATA           #REQUIRED
+>
+
+<!ELEMENT jsp:include (jsp:param*)>
+<!ATTLIST jsp:include
+    flush           %Bool;          "false"
+    page            %URL;           #REQUIRED
+>
+
+<!ELEMENT jsp:forward (jsp:param*)>
+<!ATTLIST jsp:forward
+    page            %URL;           #REQUIRED
+>
+
+<!ELEMENT jsp:plugin (jsp:params?, jsp:fallback?)>
+<!ATTLIST jsp:plugin
+    type            (bean|applet)   #REQUIRED
+    code            %URI;           #IMPLIED
+    codebase        %URI;           #IMPLIED
+    align           %ImgAlign;      #IMPLIED
+    archive         %UriList;       #IMPLIED
+    height          %Length;        #IMPLIED
+    hspace          %Pixels;        #IMPLIED
+    jreversion      CDATA           "1.2"
+    name            NMTOKEN         #IMPLIED
+    vspace          %Pixels;        #IMPLIED
+    width           %Length;        #IMPLIED
+    nspluginurl     %URI;           #IMPLIED
+    iepluginurl     %URI;           #IMPLIED
+>
+
+<!ELEMENT jsp:params (jsp:param+)>
+
+<!ELEMENT jsp:param EMPTY>
+<!ATTLIST jsp:param
+    name            CDATA           #REQUIRED
+    value           CDATA           #REQUIRED
+>
+
+<!ELEMENT jsp:text #PCDATA>
+

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/dtd/jspxml.xsd
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/dtd/jspxml.xsd	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/dtd/jspxml.xsd	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,513 @@
+<?xml version ="1.0"?>
+<!--
+  Copyright 2004 The Apache Software Foundation
+
+  Licensed 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.
+-->
+<!DOCTYPE schema [
+<!-- Patterns -->
+<!ENTITY Identifier   "(\p{L}|_|$)(\p{N}|\p{L}|_|$)*">
+<!ENTITY TypeName     "&Identifier;(\.&Identifier;)*">
+<!ENTITY WS       "\s*">
+<!ENTITY Import     "&TypeName;(\.\*)?">
+<!ENTITY ImportList   "&Import;(&WS;,&WS;&Import;)*">
+<!ENTITY SetProp    "(&Identifier;|\*)">
+<!ENTITY RelativeURL  "[^:#/\?]*(:{0,0}|[#/\?].*)">
+<!ENTITY Length     "[0-9]*&#x25;?">
+<!ENTITY AsciiName    "[A-Za-z0-9_-]*">
+<!ENTITY ValidContentType  "&AsciiName;/&AsciiName;(;&WS;(charset=)?&AsciiName;)?">
+<!ENTITY ValidPageEncoding  "&AsciiName;/&AsciiName;">
+<!ENTITY Buffer     "[0-9]+kb">
+<!ENTITY RTexpr     "&#x25;=.*&#x25;">
+]>
+
+
+<!--Conforms to w3c http://www.w3.org/2001/XMLSchema -->
+
+<xsd:schema
+    xmlns = "http://java.sun.com/JSP/Page"
+    xmlns:xsd = "http://www.w3.org/2001/XMLSchema"
+    xmlns:jsp = "http://java.sun.com/JSP/Page"
+    targetNamespace = "http://java.sun.com/JSP/Page"
+    elementFormDefault = "qualified"
+    attributeFormDefault = "unqualified">
+
+  <xsd:annotation>
+    <xsd:documentation>
+      XML Schema for JSP 2.0.
+
+      This schema is based upon the recent (May 5th, 2001)
+      W3C recommendation for XML Schema.
+
+      A JSP translator should reject an XML-format file that is
+      not strictly valid according to this schema or does not observe
+      the constraints documented here. A translator is not required
+      to use this schema for validation or to use a validating parser.
+    </xsd:documentation>
+  </xsd:annotation>
+
+
+  <!-- Complex Types -->
+
+  <xsd:complexType name = "Body">
+    <xsd:annotation>
+      <xsd:documentation>
+        Body defines the "top-level" elements in root and beanInfo.
+        There are probably other elements that should use it.
+      </xsd:documentation>
+    </xsd:annotation>
+    <xsd:group ref = "Bodygroup" minOccurs = "0" maxOccurs = "unbounded"/>
+  </xsd:complexType>
+
+  <!-- groups -->
+
+  <xsd:group name = "Bodygroup">
+    <xsd:choice>
+      <xsd:element ref = "directive.page"/>
+      <xsd:element ref = "directive.include"/>
+      <xsd:element ref = "scriptlet"/>
+      <xsd:element ref = "declaration"/>
+      <xsd:element ref = "expression"/>
+      <xsd:element ref = "useBean"/>
+      <xsd:element ref = "setProperty"/>
+      <xsd:element ref = "getProperty"/>
+      <xsd:element ref = "include"/>
+      <xsd:element ref = "forward"/>
+      <xsd:element ref = "plugin"/>
+      <xsd:element ref = "text"/>
+      <xsd:any namespace="##other" processContents = "lax"/>
+    </xsd:choice>
+  </xsd:group>
+
+
+  <!-- Simple types are next -->
+
+  <xsd:simpleType name = "RTE">
+    <xsd:annotation>
+      <xsd:documentation>
+        A request-time expression value
+      </xsd:documentation>
+    </xsd:annotation>
+    <xsd:restriction base = "xsd:string">
+      <xsd:pattern value = "&RTexpr;"/>
+    </xsd:restriction>
+  </xsd:simpleType>
+
+  <xsd:simpleType name = "Bool">
+    <xsd:annotation>
+      <xsd:documentation>
+        Bool would be boolean except it does not accept 1 and 0.
+      </xsd:documentation>
+    </xsd:annotation>
+    <xsd:restriction base = "xsd:NMTOKEN" >
+      <xsd:enumeration value = "true"/>
+      <xsd:enumeration value = "false"/>
+      <xsd:enumeration value = "yes"/>
+      <xsd:enumeration value = "no"/>
+    </xsd:restriction>     
+  </xsd:simpleType>
+
+  <xsd:simpleType name = "Identifier">
+    <xsd:annotation>
+      <xsd:documentation>
+        Identifier is an unqualified Java identifier.
+      </xsd:documentation>
+    </xsd:annotation>
+    <xsd:restriction base = "xsd:string">
+      <xsd:pattern value = "&Identifier;"/>
+    </xsd:restriction>
+  </xsd:simpleType>
+  
+  <xsd:simpleType name = "TypeName">
+    <xsd:annotation>
+      <xsd:documentation>
+        TypeName is one or more Java identifiers separated by dots
+        with no whitespace.
+      </xsd:documentation>
+    </xsd:annotation>
+    <xsd:restriction base = "xsd:string">
+      <xsd:pattern value = "&TypeName;"/>
+    </xsd:restriction>
+  </xsd:simpleType>
+  
+  <xsd:simpleType name = "ImportList">
+    <xsd:annotation>
+      <xsd:documentation>
+        ImportList is one or more typeNames separated by commas.
+        Whitespace is allowed before and after the comma.
+      </xsd:documentation>
+    </xsd:annotation>
+    <xsd:restriction base = "xsd:string">
+      <xsd:pattern value = "&ImportList;"/>
+    </xsd:restriction>
+  </xsd:simpleType>
+  
+  <xsd:simpleType name = "SetProp">
+    <xsd:annotation>
+      <xsd:documentation>
+        SetProp is an Identifier or *.
+      </xsd:documentation>
+    </xsd:annotation>
+    <xsd:restriction base = "xsd:string">
+      <xsd:pattern value = "&SetProp;"/>
+    </xsd:restriction>
+  </xsd:simpleType>
+  
+  <xsd:simpleType name = "RelativeURL">
+    <xsd:annotation>
+      <xsd:documentation>
+        RelativeURL is a uriReference with no colon character
+        before the first /, ? or #, if any (RFC2396).
+      </xsd:documentation>
+    </xsd:annotation>
+	<xsd:restriction base = "xsd:anyURI">
+      <xsd:pattern value = "&RelativeURL;"/>
+    </xsd:restriction>
+  </xsd:simpleType>
+
+  <xsd:simpleType name = "RTERelativeURL">
+    <xsd:union memberTypes = "RelativeURL RTE"/>
+  </xsd:simpleType>
+
+  <xsd:simpleType name = "Length">
+    <xsd:annotation>
+      <xsd:documentation>
+        Length is nn or nn%.
+      </xsd:documentation>
+    </xsd:annotation>
+    <xsd:restriction base = "xsd:string">
+      <xsd:pattern value = "&Length;"/>
+    </xsd:restriction>
+  </xsd:simpleType>
+  
+
+  <xsd:simpleType name = "ExplicitBufferSize">
+    <xsd:annotation>
+      <xsd:documentation>
+         Buffer Size with an explicit value
+      </xsd:documentation>
+    </xsd:annotation> 
+    <xsd:restriction base = "xsd:string">
+      <xsd:pattern value = "&Buffer;"/>
+    </xsd:restriction>
+  </xsd:simpleType>
+
+  <xsd:simpleType name = "NoneBufferSize">
+    <xsd:annotation>
+      <xsd:documentation>
+         Buffer Size with a "none" value
+      </xsd:documentation>
+    </xsd:annotation> 
+       <xsd:restriction base = "xsd:string">
+         <xsd:enumeration value = "none"/>
+       </xsd:restriction>
+  </xsd:simpleType>
+
+  <xsd:simpleType name = "BufferSize">
+    <xsd:annotation>
+      <xsd:documentation>
+        Buffer size is xkb or none.
+      </xsd:documentation>
+    </xsd:annotation>
+    <xsd:union memberTypes = "ExplicitBufferSize NoneBufferSize"/>
+  </xsd:simpleType>
+  
+  <xsd:simpleType name = "ContentType">
+    <xsd:annotation>
+      <xsd:documentation>
+        Content type and character encoding for this page.
+      </xsd:documentation>
+    </xsd:annotation>
+    <xsd:restriction base = "xsd:string">
+      <xsd:pattern value = "&ValidContentType;"/>
+    </xsd:restriction>
+  </xsd:simpleType>
+
+  <xsd:simpleType name = "PageEncoding">
+    <xsd:annotation>
+      <xsd:documentation>
+        Page Encoding for this page.
+      </xsd:documentation>
+    </xsd:annotation>
+    <xsd:restriction base = "xsd:string">
+      <xsd:pattern value = "&ValidPageEncoding;"/>
+    </xsd:restriction>
+  </xsd:simpleType>
+
+  <xsd:simpleType name = "Scope">
+    <xsd:annotation>
+      <xsd:documentation>
+        valid scope values
+      </xsd:documentation>
+    </xsd:annotation>
+    <xsd:restriction base = "xsd:NMTOKEN">
+      <xsd:enumeration value = "page"/>
+      <xsd:enumeration value = "session"/>
+      <xsd:enumeration value = "request"/>
+      <xsd:enumeration value = "application"/>
+    </xsd:restriction>
+  </xsd:simpleType>
+
+  <xsd:simpleType name = "PlugInType">
+    <xsd:annotation>
+      <xsd:documentation>
+        valid values for a plugin type
+      </xsd:documentation>
+    </xsd:annotation>
+    <xsd:restriction base = "xsd:NMTOKEN">
+      <xsd:enumeration value = "bean"/>
+      <xsd:enumeration value = "applet"/>
+    </xsd:restriction>
+  </xsd:simpleType>
+
+  <xsd:simpleType name = "AlignType">
+    <xsd:annotation>
+      <xsd:documentation>
+        Buffer size is xkb.
+      </xsd:documentation>
+    </xsd:annotation>
+    <xsd:restriction base = "xsd:NMTOKEN">
+      <xsd:enumeration value = "top"/>
+      <xsd:enumeration value = "middle"/>
+      <xsd:enumeration value = "bottom"/>
+      <xsd:enumeration value = "left"/>
+      <xsd:enumeration value = "right"/>
+    </xsd:restriction>
+  </xsd:simpleType>
+
+  <!-- Elements follow -->
+
+  <xsd:element name = "root">
+    <xsd:annotation>
+      <xsd:documentation>
+        The root element of all JSP documents is named root.
+        
+        Authors may, if they wish, include schema location information.
+        If specified, the information may appear as attributes of
+        the root element as follows:
+
+        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+        xsi:schemaLocation="http://java.sun.com/JSP/Page xsd-file-location"
+
+        Documents should not specify the system identifier of a DTD
+        in a DOCTYPE declaration.
+      </xsd:documentation>
+    </xsd:annotation>
+    <xsd:complexType>
+      <xsd:complexContent>
+        <xsd:extension base = "Body">
+          <xsd:attribute name = "version" fixed = "2.0" type = "xsd:string"/>
+        </xsd:extension>
+      </xsd:complexContent>
+    </xsd:complexType>
+  </xsd:element>
+  
+  <xsd:element name = "directive.page">
+    <xsd:annotation>
+      <xsd:documentation>
+        directive.page is the "page directive".
+      </xsd:documentation>
+    </xsd:annotation>
+    <xsd:complexType>
+      <xsd:attribute name = "language" default = "java" type = "xsd:string"/>
+      <xsd:attribute name = "extends" type = "TypeName"/>
+      <xsd:attribute name = "contentType" default = "text/html; ISO-8859-1" type = "ContentType"/>
+      <xsd:attribute name = "pageEncoding" use = "optional" type = "PageEncoding"/>
+      <xsd:attribute name = "import" type = "ImportList"/>
+      <xsd:attribute name = "session" default = "true" type = "Bool"/>
+      <xsd:attribute name = "buffer" default = "8kb" type = "BufferSize"/>
+      <xsd:attribute name = "autoFlush" default = "true" type = "Bool"/>
+      <xsd:attribute name = "isThreadSafe" default = "true" type = "Bool"/>
+      <xsd:attribute name = "info" type = "xsd:string"/>
+      <xsd:attribute name = "errorPage" type = "RelativeURL"/>
+      <xsd:attribute name = "isErrorPage" default = "false" type = "Bool"/>
+      <xsd:attribute name = "isELIgnored" type = "Bool"/>
+    </xsd:complexType>
+  </xsd:element>
+  
+  <xsd:element name = "directive.include">
+    <xsd:annotation>
+      <xsd:documentation>
+        directive.include is the "include directive".
+	This element does not appear on XML views of JSP pages.
+      </xsd:documentation>
+    </xsd:annotation>
+    <xsd:complexType>
+      <xsd:attribute name = "file" use = "required" type = "RelativeURL"/>
+    </xsd:complexType>
+  </xsd:element>
+
+  <xsd:element name = "scriptlet" type = "xsd:string">
+    <xsd:annotation>
+      <xsd:documentation>
+        The representation of a scriplet.
+      </xsd:documentation>
+    </xsd:annotation>
+  </xsd:element>
+  
+  <xsd:element name = "declaration" type = "xsd:string">
+    <xsd:annotation>
+      <xsd:documentation>
+        The reprsentation of a declaration.
+      </xsd:documentation>
+    </xsd:annotation>
+  </xsd:element>
+  
+  <xsd:element name = "expression" type = "xsd:string">
+    <xsd:annotation>
+      <xsd:documentation>
+        The representation of an expression.
+      </xsd:documentation>
+    </xsd:annotation>
+  </xsd:element>
+ 
+  <xsd:element name = "text" type = "xsd:string">
+    <xsd:annotation>
+      <xsd:documentation>
+        Verbatim template text.
+      </xsd:documentation>
+    </xsd:annotation>
+  </xsd:element>
+
+  <xsd:element name = "useBean">
+    <xsd:annotation>
+      <xsd:documentation>
+        useBean instantiates or accesses a bean in the specified scope.
+        
+        Constraint: The allowed combinations of attributes are:
+        
+          class [type] | type [( class | beanName)]
+        
+      </xsd:documentation>
+    </xsd:annotation>
+    <xsd:complexType>
+      <xsd:complexContent>
+        <xsd:extension base="Body">
+          <xsd:attribute name = "id" use = "required" type = "Identifier"/>
+          <xsd:attribute name = "class" type = "TypeName"/>
+          <xsd:attribute name = "type" type = "TypeName"/>
+          <xsd:attribute name = "beanName" type = "TypeName"/>
+          <xsd:attribute name = "scope" default = "page" type = "Scope"/>
+        </xsd:extension>
+      </xsd:complexContent>
+    </xsd:complexType>
+  </xsd:element>
+  
+  <xsd:element name = "setProperty">
+    <xsd:annotation>
+      <xsd:documentation>
+        setProperty changes the value of an object property.
+        
+        Constraint: The object named by the name must have been
+        "introduced" to the JSP processor using either the
+        jsp:useBean action or a custom action with an associated
+        VariableInfo entry for this name.
+
+        Exact valid combinations are not expressable in XML Schema.
+        They are:
+
+        name="Identifier" property="*"
+        name="Identifier" property="Identfiier" param="string"
+        name="Identifier" property="Identifier" value="string"
+                
+      </xsd:documentation>
+    </xsd:annotation>
+    <xsd:complexType>
+      <xsd:attribute name = "name" use = "required" type = "Identifier"/>
+      <xsd:attribute name = "property" use = "required" type = "SetProp"/>
+      <xsd:attribute name = "param" type = "xsd:string"/>
+      <xsd:attribute name = "value" type = "xsd:string"/>
+    </xsd:complexType>
+  </xsd:element>
+
+  <xsd:element name = "getProperty">
+    <xsd:annotation>
+      <xsd:documentation>
+        getProperty obtains the value of an object property.
+        
+        Constraint: The object named by the name must have been
+        "introduced" to the JSP processor using either the
+        jsp:useBean action or a custom action with an associated
+        VariableInfo entry for this name.
+        
+        ???The spec is interpreted as restricting the values of
+        property to Identifier.
+      </xsd:documentation>
+    </xsd:annotation>
+    <xsd:complexType>
+      <xsd:attribute name = "name" use = "required" type = "Identifier"/>
+      <xsd:attribute name = "property" use = "required" type = "Identifier"/>
+    </xsd:complexType>
+  </xsd:element>
+  
+  <xsd:element name = "include">
+    <xsd:complexType>
+      <xsd:sequence>
+        <xsd:element ref = "param" minOccurs = "0" maxOccurs = "unbounded"/>
+      </xsd:sequence>
+      <xsd:attribute name = "flush" default = "false" type = "Bool"/>
+      <xsd:attribute name = "page" use = "required" type = "RTERelativeURL"/>
+    </xsd:complexType>
+  </xsd:element>
+
+  <xsd:element name = "forward">
+    <xsd:complexType>
+      <xsd:sequence>
+        <xsd:element ref = "param" minOccurs = "0" maxOccurs = "unbounded"/>
+      </xsd:sequence>
+      <xsd:attribute name = "page" use = "required" type = "RTERelativeURL"/>
+     </xsd:complexType>
+  </xsd:element>
+  
+  <xsd:element name = "plugin">
+    <xsd:complexType> <!-- content only! -->
+      <xsd:sequence>
+        <xsd:element ref = "params" minOccurs = "0" maxOccurs = "1"/>
+        <xsd:element name = "fallback" minOccurs = "0" maxOccurs = "1" type = "Body"/>
+      </xsd:sequence>
+      <xsd:attribute name = "type" use = "required" type = "PlugInType"/>
+      <xsd:attribute name = "code" type = "xsd:anyURI"/>
+      <xsd:attribute name = "codebase" type = "xsd:anyURI"/>
+      <xsd:attribute name = "align" type = "AlignType"/>
+      <xsd:attribute name = "archive">
+        <xsd:simpleType>
+           <xsd:list itemType="xsd:anyURI"/>
+        </xsd:simpleType>
+      </xsd:attribute>
+      <xsd:attribute name = "height" type = "Length"/>
+      <xsd:attribute name = "hspace" type = "xsd:int"/>
+      <xsd:attribute name = "jreversion" default = "1.2" type = "xsd:string"/>
+      <xsd:attribute name = "name" type = "xsd:NMTOKEN"/>
+      <xsd:attribute name = "vspace" type = "xsd:int"/>
+      <xsd:attribute name = "width" type = "Length"/>
+      <xsd:attribute name = "nspluginurl" type = "xsd:anyURI"/>
+      <xsd:attribute name = "iepluginurl" type = "xsd:anyURI"/>
+    </xsd:complexType>
+  </xsd:element>
+  
+  <xsd:element name = "params">
+    <xsd:complexType>
+       <xsd:sequence>
+         <xsd:element ref = "param" minOccurs = "1" maxOccurs = "unbounded"/>
+       </xsd:sequence>
+    </xsd:complexType>
+  </xsd:element>
+
+  <xsd:element name = "param">
+    <xsd:complexType>
+      <xsd:attribute name = "name" use = "required" type = "xsd:NMTOKEN"/>
+      <xsd:attribute name = "value" use = "required" type = "xsd:string"/>
+    </xsd:complexType>
+  </xsd:element>
+  
+</xsd:schema>

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/dtd/web-app_2_2.dtd
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/dtd/web-app_2_2.dtd	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/dtd/web-app_2_2.dtd	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,580 @@
+<!--
+  Copyright 2004 The Apache Software Foundation
+
+  Licensed 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.
+-->
+
+<!--
+The web-app element is the root of the deployment descriptor for
+a web application
+-->
+
+<!ELEMENT web-app (icon?, display-name?, description?, distributable?,
+context-param*, servlet*, servlet-mapping*, session-config?,
+mime-mapping*, welcome-file-list?, error-page*, taglib*,
+resource-ref*, security-constraint*, login-config?, security-role*,
+env-entry*, ejb-ref*)>
+
+<!--
+The icon element contains a small-icon and a large-icon element
+which specify the location within the web application for a small and
+large image used to represent the web application in a GUI tool. At a
+minimum, tools must accept GIF and JPEG format images.
+-->
+
+<!ELEMENT icon (small-icon?, large-icon?)>
+
+<!--
+The small-icon element contains the location within the web
+application of a file containing a small (16x16 pixel) icon image.
+-->
+
+<!ELEMENT small-icon (#PCDATA)>
+
+<!--
+The large-icon element contains the location within the web
+application of a file containing a large (32x32 pixel) icon image.
+-->
+
+<!ELEMENT large-icon (#PCDATA)>
+
+<!--
+The display-name element contains a short name that is intended
+to be displayed by GUI tools
+-->
+
+<!ELEMENT display-name (#PCDATA)>
+
+<!--
+The description element is used to provide descriptive text about
+the parent element.
+-->
+
+<!ELEMENT description (#PCDATA)>
+
+<!--
+The distributable element, by its presence in a web application
+deployment descriptor, indicates that this web application is
+programmed appropriately to be deployed into a distributed servlet
+container
+-->
+
+<!ELEMENT distributable EMPTY>
+
+<!--
+The context-param element contains the declaration of a web
+application's servlet context initialization parameters.
+-->
+
+<!ELEMENT context-param (param-name, param-value, description?)>
+
+<!--
+The param-name element contains the name of a parameter.
+-->
+
+<!ELEMENT param-name (#PCDATA)>
+
+<!--
+The param-value element contains the value of a parameter.
+-->
+
+<!ELEMENT param-value (#PCDATA)>
+
+<!--
+The servlet element contains the declarative data of a
+servlet. If a jsp-file is specified and the load-on-startup element is
+present, then the JSP should be precompiled and loaded.
+-->
+
+<!ELEMENT servlet (icon?, servlet-name, display-name?, description?,
+(servlet-class|jsp-file), init-param*, load-on-startup?, security-role-ref*)>
+
+<!--
+The servlet-name element contains the canonical name of the
+servlet.
+-->
+
+<!ELEMENT servlet-name (#PCDATA)>
+
+<!--
+The servlet-class element contains the fully qualified class name
+of the servlet.
+-->
+
+<!ELEMENT servlet-class (#PCDATA)>
+
+<!--
+The jsp-file element contains the full path to a JSP file within
+the web application.
+-->
+
+<!ELEMENT jsp-file (#PCDATA)>
+
+<!--
+The init-param element contains a name/value pair as an
+initialization param of the servlet
+-->
+
+<!ELEMENT init-param (param-name, param-value, description?)>
+
+<!--
+The load-on-startup element indicates that this servlet should be
+loaded on the startup of the web application. The optional contents of
+these element must be a positive integer indicating the order in which
+the servlet should be loaded. Lower integers are loaded before higher
+integers. If no value is specified, or if the value specified is not a
+positive integer, the container is free to load it at any time in the
+startup sequence.
+-->
+
+<!ELEMENT load-on-startup (#PCDATA)>
+
+<!--
+The servlet-mapping element defines a mapping between a servlet
+and a url pattern
+-->
+
+<!ELEMENT servlet-mapping (servlet-name, url-pattern)>
+
+<!--
+The url-pattern element contains the url pattern of the
+mapping. Must follow the rules specified in Section 10 of the Servlet
+API Specification.
+-->
+
+<!ELEMENT url-pattern (#PCDATA)>
+
+<!--
+The session-config element defines the session parameters for
+this web application.
+-->
+
+<!ELEMENT session-config (session-timeout?)>
+
+<!--
+The session-timeout element defines the default session timeout
+interval for all sessions created in this web application. The
+specified timeout must be expressed in a whole number of minutes.
+-->
+
+<!ELEMENT session-timeout (#PCDATA)>
+
+<!--
+The mime-mapping element defines a mapping between an extension
+and a mime type.
+-->
+
+<!ELEMENT mime-mapping (extension, mime-type)>
+
+<!--
+The extension element contains a string describing an
+extension. example: "txt"
+-->
+
+<!ELEMENT extension (#PCDATA)>
+
+<!--
+The mime-type element contains a defined mime type. example:
+"text/plain"
+-->
+
+<!ELEMENT mime-type (#PCDATA)>
+
+<!--
+The welcome-file-list contains an ordered list of welcome files
+elements.
+-->
+
+<!ELEMENT welcome-file-list (welcome-file+)>
+
+<!--
+The welcome-file element contains file name to use as a default
+welcome file, such as index.html
+-->
+
+<!ELEMENT welcome-file (#PCDATA)>
+
+<!--
+The taglib element is used to describe a JSP tag library.
+-->
+
+<!ELEMENT taglib (taglib-uri, taglib-location)>
+
+<!--
+The taglib-uri element describes a URI, relative to the location
+of the web.xml document, identifying a Tag Library used in the Web
+Application.
+-->
+
+<!ELEMENT taglib-uri (#PCDATA)>
+
+<!--
+the taglib-location element contains the location (as a resource
+relative to the root of the web application) where to find the Tag
+Libary Description file for the tag library.
+-->
+
+<!ELEMENT taglib-location (#PCDATA)>
+
+<!--
+The error-page element contains a mapping between an error code
+or exception type to the path of a resource in the web application
+-->
+
+<!ELEMENT error-page ((error-code | exception-type), location)>
+
+<!--
+The error-code contains an HTTP error code, ex: 404
+-->
+
+<!ELEMENT error-code (#PCDATA)>
+
+<!--
+The exception type contains a fully qualified class name of a
+Java exception type.
+-->
+
+<!ELEMENT exception-type (#PCDATA)>
+
+<!--
+The location element contains the location of the resource in the
+web application
+-->
+
+<!ELEMENT location (#PCDATA)>
+
+<!--
+The resource-ref element contains a declaration of a Web
+Application's reference to an external resource.
+-->
+
+<!ELEMENT resource-ref (description?, res-ref-name, res-type, res-auth)>
+
+<!--
+The res-ref-name element specifies the name of the resource
+factory reference name.
+-->
+
+<!ELEMENT res-ref-name (#PCDATA)>
+
+<!--
+The res-type element specifies the (Java class) type of the data
+source.
+-->
+
+<!ELEMENT res-type (#PCDATA)>
+
+<!--
+The res-auth element indicates whether the application component
+code performs resource signon programmatically or whether the
+container signs onto the resource based on the principle mapping
+information supplied by the deployer. Must be CONTAINER or SERVLET
+-->
+
+<!ELEMENT res-auth (#PCDATA)>
+
+<!--
+The security-constraint element is used to associate security
+constraints with one or more web resource collections
+-->
+
+<!ELEMENT security-constraint (web-resource-collection+,
+auth-constraint?, user-data-constraint?)>
+
+<!--
+The web-resource-collection element is used to identify a subset
+of the resources and HTTP methods on those resources within a web
+application to which a security constraint applies. If no HTTP methods
+are specified, then the security constraint applies to all HTTP
+methods.
+-->
+
+<!ELEMENT web-resource-collection (web-resource-name, description?,
+url-pattern*, http-method*)>
+
+<!--
+The web-resource-name contains the name of this web resource
+collection
+-->
+
+<!ELEMENT web-resource-name (#PCDATA)>
+
+<!--
+The http-method contains an HTTP method (GET | POST |...)
+-->
+
+<!ELEMENT http-method (#PCDATA)>
+
+<!--
+The user-data-constraint element is used to indicate how data
+communicated between the client and container should be protected
+-->
+
+<!ELEMENT user-data-constraint (description?, transport-guarantee)>
+
+<!--
+The transport-guarantee element specifies that the communication
+between client and server should be NONE, INTEGRAL, or
+CONFIDENTIAL. NONE means that the application does not require any
+transport guarantees. A value of INTEGRAL means that the application
+requires that the data sent between the client and server be sent in
+such a way that it can't be changed in transit. CONFIDENTIAL means
+that the application requires that the data be transmitted in a
+fashion that prevents other entities from observing the contents of
+the transmission. In most cases, the presence of the INTEGRAL or
+CONFIDENTIAL flag will indicate that the use of SSL is required.
+-->
+
+<!ELEMENT transport-guarantee (#PCDATA)>
+
+<!--
+The auth-constraint element indicates the user roles that should
+be permitted access to this resource collection. The role used here
+must appear in a security-role-ref element.
+-->
+
+<!ELEMENT auth-constraint (description?, role-name*)>
+
+<!--
+The role-name element contains the name of a security role.
+-->
+
+<!ELEMENT role-name (#PCDATA)>
+
+<!--
+The login-config element is used to configure the authentication
+method that should be used, the realm name that should be used for
+this application, and the attributes that are needed by the form login
+mechanism.
+-->
+
+<!ELEMENT login-config (auth-method?, realm-name?, form-login-config?)>
+
+<!--
+The realm name element specifies the realm name to use in HTTP
+Basic authorization
+-->
+
+<!ELEMENT realm-name (#PCDATA)>
+
+<!--
+The form-login-config element specifies the login and error pages
+that should be used in form based login. If form based authentication
+is not used, these elements are ignored.
+-->
+
+<!ELEMENT form-login-config (form-login-page, form-error-page)>
+
+<!--
+The form-login-page element defines the location in the web app
+where the page that can be used for login can be found
+-->
+
+<!ELEMENT form-login-page (#PCDATA)>
+
+<!--
+The form-error-page element defines the location in the web app
+where the error page that is displayed when login is not successful
+can be found
+-->
+
+<!ELEMENT form-error-page (#PCDATA)>
+
+<!--
+The auth-method element is used to configure the authentication
+mechanism for the web application. As a prerequisite to gaining access
+to any web resources which are protected by an authorization
+constraint, a user must have authenticated using the configured
+mechanism. Legal values for this element are "BASIC", "DIGEST",
+"FORM", or "CLIENT-CERT".
+-->
+
+<!ELEMENT auth-method (#PCDATA)>
+
+<!--
+The security-role element contains the declaration of a security
+role which is used in the security-constraints placed on the web
+application.
+-->
+
+<!ELEMENT security-role (description?, role-name)>
+
+<!--
+The role-name element contains the name of a role. This element
+must contain a non-empty string.
+-->
+
+<!ELEMENT security-role-ref (description?, role-name, role-link)>
+
+<!--
+The role-link element is used to link a security role reference
+to a defined security role. The role-link element must contain the
+name of one of the security roles defined in the security-role
+elements.
+-->
+
+<!ELEMENT role-link (#PCDATA)>
+
+<!--
+The env-entry element contains the declaration of an
+application's environment entry. This element is required to be
+honored on in J2EE compliant servlet containers.
+-->
+
+<!ELEMENT env-entry (description?, env-entry-name, env-entry-value?,
+env-entry-type)>
+
+<!--
+The env-entry-name contains the name of an application's
+environment entry
+-->
+
+<!ELEMENT env-entry-name (#PCDATA)>
+
+<!--
+The env-entry-value element contains the value of an
+application's environment entry
+-->
+
+<!ELEMENT env-entry-value (#PCDATA)>
+
+<!--
+The env-entry-type element contains the fully qualified Java type
+of the environment entry value that is expected by the application
+code. The following are the legal values of env-entry-type:
+java.lang.Boolean, java.lang.String, java.lang.Integer,
+java.lang.Double, java.lang.Float.
+-->
+
+<!ELEMENT env-entry-type (#PCDATA)>
+
+<!--
+The ejb-ref element is used to declare a reference to an
+enterprise bean. 
+-->
+
+<!ELEMENT ejb-ref (description?, ejb-ref-name, ejb-ref-type, home, remote,
+ejb-link?)>
+
+<!--
+The ejb-ref-name element contains the name of an EJB
+reference. This is the JNDI name that the servlet code uses to get a
+reference to the enterprise bean.
+-->
+
+<!ELEMENT ejb-ref-name (#PCDATA)>
+
+<!--
+The ejb-ref-type element contains the expected java class type of
+the referenced EJB.
+-->
+
+<!ELEMENT ejb-ref-type (#PCDATA)>
+
+<!--
+The ejb-home element contains the fully qualified name of the
+EJB's home interface
+-->
+
+<!ELEMENT home (#PCDATA)>
+
+<!--
+The ejb-remote element contains the fully qualified name of the
+EJB's remote interface
+-->
+
+<!ELEMENT remote (#PCDATA)>
+
+<!--
+The ejb-link element is used in the ejb-ref element to specify
+that an EJB reference is linked to an EJB in an encompassing Java2
+Enterprise Edition (J2EE) application package. The value of the
+ejb-link element must be the ejb-name of and EJB in the J2EE
+application package.
+-->
+
+<!ELEMENT ejb-link (#PCDATA)>
+
+<!--
+The ID mechanism is to allow tools to easily make tool-specific
+references to the elements of the deployment descriptor. This allows
+tools that produce additional deployment information (i.e information
+beyond the standard deployment descriptor information) to store the
+non-standard information in a separate file, and easily refer from
+these tools-specific files to the information in the standard web-app
+deployment descriptor.
+-->
+
+<!ATTLIST web-app id ID #IMPLIED>
+<!ATTLIST icon id ID #IMPLIED>
+<!ATTLIST small-icon id ID #IMPLIED>
+<!ATTLIST large-icon id ID #IMPLIED>
+<!ATTLIST display-name id ID #IMPLIED>
+<!ATTLIST description id ID #IMPLIED>
+<!ATTLIST distributable id ID #IMPLIED>
+<!ATTLIST context-param id ID #IMPLIED>
+<!ATTLIST param-name id ID #IMPLIED>
+<!ATTLIST param-value id ID #IMPLIED>
+<!ATTLIST servlet id ID #IMPLIED>
+<!ATTLIST servlet-name id ID #IMPLIED>
+<!ATTLIST servlet-class id ID #IMPLIED>
+<!ATTLIST jsp-file id ID #IMPLIED>
+<!ATTLIST init-param id ID #IMPLIED>
+<!ATTLIST load-on-startup id ID #IMPLIED>
+<!ATTLIST servlet-mapping id ID #IMPLIED>
+<!ATTLIST url-pattern id ID #IMPLIED>
+<!ATTLIST session-config id ID #IMPLIED>
+<!ATTLIST session-timeout id ID #IMPLIED>
+<!ATTLIST mime-mapping id ID #IMPLIED>
+<!ATTLIST extension id ID #IMPLIED>
+<!ATTLIST mime-type id ID #IMPLIED>
+<!ATTLIST welcome-file-list id ID #IMPLIED>
+<!ATTLIST welcome-file id ID #IMPLIED>
+<!ATTLIST taglib id ID #IMPLIED>
+<!ATTLIST taglib-uri id ID #IMPLIED>
+<!ATTLIST taglib-location id ID #IMPLIED>
+<!ATTLIST error-page id ID #IMPLIED>
+<!ATTLIST error-code id ID #IMPLIED>
+<!ATTLIST exception-type id ID #IMPLIED>
+<!ATTLIST location id ID #IMPLIED>
+<!ATTLIST resource-ref id ID #IMPLIED>
+<!ATTLIST res-ref-name id ID #IMPLIED>
+<!ATTLIST res-type id ID #IMPLIED>
+<!ATTLIST res-auth id ID #IMPLIED>
+<!ATTLIST security-constraint id ID #IMPLIED>
+<!ATTLIST web-resource-collection id ID #IMPLIED>
+<!ATTLIST web-resource-name id ID #IMPLIED>
+<!ATTLIST http-method id ID #IMPLIED>
+<!ATTLIST user-data-constraint id ID #IMPLIED>
+<!ATTLIST transport-guarantee id ID #IMPLIED>
+<!ATTLIST auth-constraint id ID #IMPLIED>
+<!ATTLIST role-name id ID #IMPLIED>
+<!ATTLIST login-config id ID #IMPLIED>
+<!ATTLIST realm-name id ID #IMPLIED>
+<!ATTLIST form-login-config id ID #IMPLIED>
+<!ATTLIST form-login-page id ID #IMPLIED>
+<!ATTLIST form-error-page id ID #IMPLIED>
+<!ATTLIST auth-method id ID #IMPLIED>
+<!ATTLIST security-role id ID #IMPLIED>
+<!ATTLIST security-role-ref id ID #IMPLIED>
+<!ATTLIST role-link id ID #IMPLIED>
+<!ATTLIST env-entry id ID #IMPLIED>
+<!ATTLIST env-entry-name id ID #IMPLIED>
+<!ATTLIST env-entry-value id ID #IMPLIED>
+<!ATTLIST env-entry-type id ID #IMPLIED>
+<!ATTLIST ejb-ref id ID #IMPLIED>
+<!ATTLIST ejb-ref-name id ID #IMPLIED>
+<!ATTLIST ejb-ref-type id ID #IMPLIED>
+<!ATTLIST home id ID #IMPLIED>
+<!ATTLIST remote id ID #IMPLIED>
+<!ATTLIST ejb-link id ID #IMPLIED>

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/dtd/web-app_2_3.dtd
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/dtd/web-app_2_3.dtd	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/dtd/web-app_2_3.dtd	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,1074 @@
+<!--
+  Copyright 2004 The Apache Software Foundation
+
+  Licensed 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.
+-->
+<!--
+Copyright 2000-2001 Sun Microsystems, Inc. 901 San Antonio Road,
+Palo Alto, CA  94303, U.S.A.  All rights reserved.
+
+This product or document is protected by copyright and distributed
+under licenses restricting its use, copying, distribution, and
+decompilation.  No part of this product or documentation may be
+reproduced in any form by any means without prior written authorization
+of Sun and its licensors, if any.
+
+Third party software, including font technology, is copyrighted and
+licensed from Sun suppliers.
+
+Sun, Sun Microsystems, the Sun Logo, Solaris, Java, JavaServer Pages, Java
+Naming and Directory Interface, JDBC, JDK, JavaMail and Enterprise JavaBeans,
+are trademarks or registered trademarks of Sun Microsystems, Inc in the U.S.
+and other countries.
+
+All SPARC trademarks are used under license and are trademarks
+or registered trademarks of SPARC International, Inc.
+in the U.S. and other countries. Products bearing SPARC
+trademarks are based upon an architecture developed by Sun Microsystems, Inc.
+
+PostScript is a registered trademark of Adobe Systems, Inc.
+
+Federal Acquisitions: Commercial Software - Government Users Subject to
+Standard License Terms and Conditions.
+
+DOCUMENTATION IS PROVIDED "AS IS" AND ALL EXPRESS OR IMPLIED
+CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING ANY
+IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+PURPOSE OR NON-INFRINGEMENT, ARE DISCLAIMED, EXCEPT
+TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD TO BE LEGALLY
+INVALID.
+
+_________________________________________________________________________
+
+Copyright 2000-2001 Sun Microsystems, Inc.,
+901 San Antonio Road, Palo Alto, CA  94303, Etats-Unis.
+Tous droits re'serve's.
+
+
+Ce produit ou document est prote'ge' par un copyright et distribue' avec
+des licences qui en restreignent l'utilisation, la copie, la distribution,
+et la de'compilation.  Aucune partie de ce produit ou de sa documentation
+associe'e ne peut e^tre reproduite sous aucune forme, par quelque moyen
+que ce soit, sans l'autorisation pre'alable et e'crite de Sun et de ses
+bailleurs de licence, s'il y en a.
+
+Le logiciel de'tenu par des tiers, et qui comprend la technologie
+relative aux polices de caracte`res, est prote'ge' par un copyright
+et licencie' par des fournisseurs de Sun.
+
+Sun, Sun Microsystems, le logo Sun, Solaris, Java, JavaServer Pages, Java
+Naming and Directory Interface, JDBC, JDK, JavaMail, et Enterprise JavaBeans,
+sont des marques de fabrique ou des marques de'pose'es de Sun
+Microsystems, Inc. aux Etats-Unis et dans d'autres pays.
+
+Toutes les marques SPARC sont utilise'es sous licence et sont
+des marques de fabrique ou des marques de'pose'es de SPARC
+International, Inc. aux Etats-Unis et  dans
+d'autres pays. Les produits portant les marques SPARC sont
+base's sur une architecture de'veloppe'e par Sun Microsystems, Inc.
+
+Postcript est une marque enregistre'e d'Adobe Systems Inc.
+
+LA DOCUMENTATION EST FOURNIE "EN L'ETAT" ET TOUTES AUTRES CONDITIONS,
+DECLARATIONS ET GARANTIES EXPRESSES OU TACITES SONT FORMELLEMENT EXCLUES,
+DANS LA MESURE AUTORISEE PAR LA LOI APPLICABLE, Y COMPRIS NOTAMMENT
+TOUTE GARANTIE IMPLICITE RELATIVE A LA QUALITE MARCHANDE, A L'APTITUDE
+A UNE UTILISATION PARTICULIERE OU A L'ABSENCE DE CONTREFACON.
+-->
+
+<!--
+This is the XML DTD for the Servlet 2.3 deployment descriptor.
+All Servlet 2.3 deployment descriptors must include a DOCTYPE
+of the following form:
+
+  <!DOCTYPE web-app PUBLIC
+	"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
+	"http://java.sun.com/dtd/web-app_2_3.dtd">
+
+-->
+
+<!--
+The following conventions apply to all J2EE deployment descriptor
+elements unless indicated otherwise.
+
+- In elements that contain PCDATA, leading and trailing whitespace
+  in the data may be ignored.
+
+- In elements whose value is an "enumerated type", the value is
+  case sensitive.
+
+- In elements that specify a pathname to a file within the same
+  JAR file, relative filenames (i.e., those not starting with "/")
+  are considered relative to the root of the JAR file's namespace.
+  Absolute filenames (i.e., those starting with "/") also specify
+  names in the root of the JAR file's namespace.  In general, relative
+  names are preferred.  The exception is .war files where absolute
+  names are preferred for consistency with the servlet API.
+-->
+
+
+<!--
+The web-app element is the root of the deployment descriptor for
+a web application.
+-->
+<!ELEMENT web-app (icon?, display-name?, description?, distributable?,
+context-param*, filter*, filter-mapping*, listener*, servlet*,
+servlet-mapping*, session-config?, mime-mapping*, welcome-file-list?,
+error-page*, taglib*, resource-env-ref*, resource-ref*, security-constraint*,
+login-config?, security-role*, env-entry*, ejb-ref*,  ejb-local-ref*)>
+
+<!--
+The auth-constraint element indicates the user roles that should
+be permitted access to this resource collection. The role-name
+used here must either correspond to the role-name of one of the
+security-role elements defined for this web application, or be
+the specially reserved role-name "*" that is a compact syntax for
+indicating all roles in the web application. If both "*" and
+rolenames appear, the container interprets this as all roles.
+If no roles are defined, no user is allowed access to the portion of
+the web application described by the containing security-constraint.
+The container matches role names case sensitively when determining
+access.
+
+
+Used in: security-constraint
+-->
+<!ELEMENT auth-constraint (description?, role-name*)>
+
+<!--
+The auth-method element is used to configure the authentication
+mechanism for the web application. As a prerequisite to gaining access to any web resources which are protected by an authorization
+constraint, a user must have authenticated using the configured
+mechanism. Legal values for this element are "BASIC", "DIGEST",
+"FORM", or "CLIENT-CERT".
+
+Used in: login-config
+-->
+<!ELEMENT auth-method (#PCDATA)>
+
+<!--
+The context-param element contains the declaration of a web
+application's servlet context initialization parameters.
+
+Used in: web-app
+-->
+<!ELEMENT context-param (param-name, param-value, description?)>
+
+<!--
+The description element is used to provide text describing the parent
+element.  The description element should include any information that
+the web application war file producer wants to provide to the consumer of
+the web application war file (i.e., to the Deployer). Typically, the tools
+used by the web application war file consumer will display the description
+when processing the parent element that contains the description.
+
+Used in: auth-constraint, context-param, ejb-local-ref, ejb-ref,
+env-entry, filter, init-param, resource-env-ref, resource-ref, run-as,
+security-role, security-role-ref, servlet, user-data-constraint,
+web-app, web-resource-collection
+-->
+<!ELEMENT description (#PCDATA)>
+
+<!--
+The display-name element contains a short name that is intended to be
+displayed by tools.  The display name need not be unique.
+
+Used in: filter, security-constraint, servlet, web-app
+
+Example:
+
+<display-name>Employee Self Service</display-name>
+-->
+<!ELEMENT display-name (#PCDATA)>
+
+<!--
+The distributable element, by its presence in a web application
+deployment descriptor, indicates that this web application is
+programmed appropriately to be deployed into a distributed servlet
+container
+
+Used in: web-app
+-->
+<!ELEMENT distributable EMPTY>
+
+<!--
+The ejb-link element is used in the ejb-ref or ejb-local-ref
+elements to specify that an EJB reference is linked to an
+enterprise bean.
+
+The name in the ejb-link element is composed of a
+path name specifying the ejb-jar containing the referenced enterprise
+bean with the ejb-name of the target bean appended and separated from
+the path name by "#".  The path name is relative to the war file
+containing the web application that is referencing the enterprise bean.
+This allows multiple enterprise beans with the same ejb-name to be
+uniquely identified.
+
+Used in: ejb-local-ref, ejb-ref
+
+Examples:
+
+	<ejb-link>EmployeeRecord</ejb-link>
+
+	<ejb-link>../products/product.jar#ProductEJB</ejb-link>
+
+-->
+<!ELEMENT ejb-link (#PCDATA)>
+
+<!--
+The ejb-local-ref element is used for the declaration of a reference to
+an enterprise bean's local home. The declaration consists of:
+
+	- an optional description
+	- the EJB reference name used in the code of the web application
+	  that's referencing the enterprise bean
+	- the expected type of the referenced enterprise bean
+	- the expected local home and local interfaces of the referenced
+	  enterprise bean
+	- optional ejb-link information, used to specify the referenced
+	  enterprise bean
+
+Used in: web-app
+-->
+<!ELEMENT ejb-local-ref (description?, ejb-ref-name, ejb-ref-type,
+		local-home, local, ejb-link?)>
+
+<!--
+The ejb-ref element is used for the declaration of a reference to
+an enterprise bean's home. The declaration consists of:
+
+	- an optional description
+	- the EJB reference name used in the code of
+	  the web application that's referencing the enterprise bean
+	- the expected type of the referenced enterprise bean
+	- the expected home and remote interfaces of the referenced
+	  enterprise bean
+	- optional ejb-link information, used to specify the referenced
+	  enterprise bean
+
+Used in: web-app
+-->
+<!ELEMENT ejb-ref (description?, ejb-ref-name, ejb-ref-type,
+		home, remote, ejb-link?)>
+
+<!--
+The ejb-ref-name element contains the name of an EJB reference. The
+EJB reference is an entry in the web application's environment and is
+relative to the java:comp/env context.  The name must be unique
+within the web application.
+
+It is recommended that name is prefixed with "ejb/".
+
+Used in: ejb-local-ref, ejb-ref
+
+Example:
+
+<ejb-ref-name>ejb/Payroll</ejb-ref-name>
+-->
+<!ELEMENT ejb-ref-name (#PCDATA)>
+
+<!--
+The ejb-ref-type element contains the expected type of the
+referenced enterprise bean.
+
+The ejb-ref-type element must be one of the following:
+
+	<ejb-ref-type>Entity</ejb-ref-type>
+	<ejb-ref-type>Session</ejb-ref-type>
+
+Used in: ejb-local-ref, ejb-ref
+-->
+<!ELEMENT ejb-ref-type (#PCDATA)>
+
+<!--
+The env-entry element contains the declaration of a web application's
+environment entry. The declaration consists of an optional
+description, the name of the environment entry, and an optional
+value.  If a value is not specified, one must be supplied
+during deployment.
+-->
+<!ELEMENT env-entry (description?, env-entry-name, env-entry-value?,
+env-entry-type)>
+
+<!--
+The env-entry-name element contains the name of a web applications's
+environment entry.  The name is a JNDI name relative to the
+java:comp/env context.  The name must be unique within a web application.
+
+Example:
+
+<env-entry-name>minAmount</env-entry-name>
+
+Used in: env-entry
+-->
+<!ELEMENT env-entry-name (#PCDATA)>
+
+<!--
+The env-entry-type element contains the fully-qualified Java type of
+the environment entry value that is expected by the web application's
+code.
+
+The following are the legal values of env-entry-type:
+
+	java.lang.Boolean
+	java.lang.Byte
+	java.lang.Character
+	java.lang.String
+	java.lang.Short
+	java.lang.Integer
+	java.lang.Long
+	java.lang.Float
+	java.lang.Double
+
+Used in: env-entry
+-->
+<!ELEMENT env-entry-type (#PCDATA)>
+
+<!--
+The env-entry-value element contains the value of a web application's
+environment entry. The value must be a String that is valid for the
+constructor of the specified type that takes a single String
+parameter, or for java.lang.Character, a single character.
+
+Example:
+
+<env-entry-value>100.00</env-entry-value>
+
+Used in: env-entry
+-->
+<!ELEMENT env-entry-value (#PCDATA)>
+
+<!--
+The error-code contains an HTTP error code, ex: 404
+
+Used in: error-page
+-->
+<!ELEMENT error-code (#PCDATA)>
+
+<!--
+The error-page element contains a mapping between an error code
+or exception type to the path of a resource in the web application
+
+Used in: web-app
+-->
+<!ELEMENT error-page ((error-code | exception-type), location)>
+
+<!--
+The exception type contains a fully qualified class name of a
+Java exception type.
+
+Used in: error-page
+-->
+<!ELEMENT exception-type (#PCDATA)>
+
+<!--
+The extension element contains a string describing an
+extension. example: "txt"
+
+Used in: mime-mapping
+-->
+<!ELEMENT extension (#PCDATA)>
+
+<!--
+Declares a filter in the web application. The filter is mapped to
+either a servlet or a URL pattern in the filter-mapping element, using
+the filter-name value to reference. Filters can access the
+initialization parameters declared in the deployment descriptor at
+runtime via the FilterConfig interface.
+
+Used in: web-app
+-->
+<!ELEMENT filter (icon?, filter-name, display-name?, description?,
+filter-class, init-param*)>
+
+<!--
+The fully qualified classname of the filter.
+
+Used in: filter
+-->
+<!ELEMENT filter-class (#PCDATA)>
+
+<!--
+Declaration of the filter mappings in this web application. The
+container uses the filter-mapping declarations to decide which filters
+to apply to a request, and in what order. The container matches the
+request URI to a Servlet in the normal way. To determine which filters
+to apply it matches filter-mapping declarations either on servlet-name,
+or on url-pattern for each filter-mapping element, depending on which
+style is used. The order in which filters are invoked is the order in
+which filter-mapping declarations that match a request URI for a
+servlet appear in the list of filter-mapping elements.The filter-name
+value must be the value of the <filter-name> sub-elements of one of the
+<filter> declarations in the deployment descriptor.
+
+Used in: web-app
+-->
+<!ELEMENT filter-mapping (filter-name, (url-pattern | servlet-name))>
+
+<!--
+The logical name of the filter. This name is used to map the filter.
+Each filter name is unique within the web application.
+
+Used in: filter, filter-mapping
+-->
+<!ELEMENT filter-name (#PCDATA)>
+
+<!--
+The form-error-page element defines the location in the web app
+where the error page that is displayed when login is not successful
+can be found. The path begins with a leading / and is interpreted
+relative to the root of the WAR.
+
+Used in: form-login-config
+-->
+<!ELEMENT form-error-page (#PCDATA)>
+
+<!--
+The form-login-config element specifies the login and error pages
+that should be used in form based login. If form based authentication
+is not used, these elements are ignored.
+
+Used in: login-config
+-->
+<!ELEMENT form-login-config (form-login-page, form-error-page)>
+
+<!--
+The form-login-page element defines the location in the web app
+where the page that can be used for login can be found. The path
+begins with a leading / and is interpreted relative to the root of the WAR.
+
+Used in: form-login-config
+-->
+<!ELEMENT form-login-page (#PCDATA)>
+
+<!--
+The home element contains the fully-qualified name of the enterprise
+bean's home interface.
+
+Used in: ejb-ref
+
+Example:
+
+<home>com.aardvark.payroll.PayrollHome</home>
+-->
+<!ELEMENT home (#PCDATA)>
+
+<!--
+The http-method contains an HTTP method (GET | POST |...).
+
+Used in: web-resource-collection
+-->
+<!ELEMENT http-method (#PCDATA)>
+
+<!--
+The icon element contains small-icon and large-icon elements that
+specify the file names for small and a large GIF or JPEG icon images
+used to represent the parent element in a GUI tool.
+
+Used in: filter, servlet, web-app
+-->
+<!ELEMENT icon (small-icon?, large-icon?)>
+
+<!--
+The init-param element contains a name/value pair as an
+initialization param of the servlet
+
+Used in: filter, servlet
+-->
+<!ELEMENT init-param (param-name, param-value, description?)>
+
+<!--
+The jsp-file element contains the full path to a JSP file within
+the web application beginning with a `/'.
+
+Used in: servlet
+-->
+<!ELEMENT jsp-file (#PCDATA)>
+
+<!--
+The large-icon element contains the name of a file
+containing a large (32 x 32) icon image. The file
+name is a relative path within the web application's
+war file.
+
+The image may be either in the JPEG or GIF format.
+The icon can be used by tools.
+
+Used in: icon
+
+Example:
+
+<large-icon>employee-service-icon32x32.jpg</large-icon>
+-->
+<!ELEMENT large-icon (#PCDATA)>
+
+<!--
+The listener element indicates the deployment properties for a web
+application listener bean.
+
+Used in: web-app
+-->
+<!ELEMENT listener (listener-class)>
+
+<!--
+The listener-class element declares a class in the application must be
+registered as a web application listener bean. The value is the fully qualified classname of the listener class.
+
+
+Used in: listener
+-->
+<!ELEMENT listener-class (#PCDATA)>
+
+<!--
+The load-on-startup element indicates that this servlet should be
+loaded (instantiated and have its init() called) on the startup
+of the web application. The optional contents of
+these element must be an integer indicating the order in which
+the servlet should be loaded. If the value is a negative integer,
+or the element is not present, the container is free to load the
+servlet whenever it chooses. If the value is a positive integer
+or 0, the container must load and initialize the servlet as the
+application is deployed. The container must guarantee that
+servlets marked with lower integers are loaded before servlets
+marked with higher integers. The container may choose the order
+of loading of servlets with the same load-on-start-up value.
+
+Used in: servlet
+-->
+<!ELEMENT load-on-startup (#PCDATA)>
+
+<!--
+
+The local element contains the fully-qualified name of the
+enterprise bean's local interface.
+
+Used in: ejb-local-ref
+
+-->
+<!ELEMENT local (#PCDATA)>
+
+<!--
+
+The local-home element contains the fully-qualified name of the
+enterprise bean's local home interface.
+
+Used in: ejb-local-ref
+-->
+<!ELEMENT local-home (#PCDATA)>
+
+<!--
+The location element contains the location of the resource in the web
+application relative to the root of the web application. The value of
+the location must have a leading `/'.
+
+Used in: error-page
+-->
+<!ELEMENT location (#PCDATA)>
+
+<!--
+The login-config element is used to configure the authentication
+method that should be used, the realm name that should be used for
+this application, and the attributes that are needed by the form login
+mechanism.
+
+Used in: web-app
+-->
+<!ELEMENT login-config (auth-method?, realm-name?, form-login-config?)>
+
+<!--
+The mime-mapping element defines a mapping between an extension
+and a mime type.
+
+Used in: web-app
+-->
+<!ELEMENT mime-mapping (extension, mime-type)>
+
+<!--
+The mime-type element contains a defined mime type. example:
+"text/plain"
+
+Used in: mime-mapping
+-->
+<!ELEMENT mime-type (#PCDATA)>
+
+<!--
+The param-name element contains the name of a parameter. Each parameter
+name must be unique in the web application.
+
+
+Used in: context-param, init-param
+-->
+<!ELEMENT param-name (#PCDATA)>
+
+<!--
+The param-value element contains the value of a parameter.
+
+Used in: context-param, init-param
+-->
+<!ELEMENT param-value (#PCDATA)>
+
+<!--
+The realm name element specifies the realm name to use in HTTP
+Basic authorization.
+
+Used in: login-config
+-->
+<!ELEMENT realm-name (#PCDATA)>
+
+<!--
+The remote element contains the fully-qualified name of the enterprise
+bean's remote interface.
+
+Used in: ejb-ref
+
+Example:
+
+<remote>com.wombat.empl.EmployeeService</remote>
+-->
+<!ELEMENT remote (#PCDATA)>
+
+<!--
+The res-auth element specifies whether the web application code signs
+on programmatically to the resource manager, or whether the Container
+will sign on to the resource manager on behalf of the web application. In the
+latter case, the Container uses information that is supplied by the
+Deployer.
+
+The value of this element must be one of the two following:
+
+	<res-auth>Application</res-auth>
+	<res-auth>Container</res-auth>
+
+Used in: resource-ref
+-->
+<!ELEMENT res-auth (#PCDATA)>
+
+<!--
+The res-ref-name element specifies the name of a resource manager
+connection factory reference.  The name is a JNDI name relative to the
+java:comp/env context.  The name must be unique within a web application.
+
+Used in: resource-ref
+-->
+<!ELEMENT res-ref-name (#PCDATA)>
+
+<!--
+The res-sharing-scope element specifies whether connections obtained
+through the given resource manager connection factory reference can be
+shared. The value of this element, if specified, must be one of the
+two following:
+
+	<res-sharing-scope>Shareable</res-sharing-scope>
+	<res-sharing-scope>Unshareable</res-sharing-scope>
+
+The default value is Shareable.
+
+Used in: resource-ref
+-->
+<!ELEMENT res-sharing-scope (#PCDATA)>
+
+<!--
+The res-type element specifies the type of the data source. The type
+is specified by the fully qualified Java language class or interface
+expected to be implemented by the data source.
+
+Used in: resource-ref
+-->
+<!ELEMENT res-type (#PCDATA)>
+
+<!--
+The resource-env-ref element contains a declaration of a web application's
+reference to an administered object associated with a resource
+in the web application's environment.  It consists of an optional
+description, the resource environment reference name, and an
+indication of the resource environment reference type expected by
+the web application code.
+
+Used in: web-app
+
+Example:
+
+<resource-env-ref>
+    <resource-env-ref-name>jms/StockQueue</resource-env-ref-name>
+    <resource-env-ref-type>javax.jms.Queue</resource-env-ref-type>
+</resource-env-ref>
+-->
+<!ELEMENT resource-env-ref (description?, resource-env-ref-name,
+		resource-env-ref-type)>
+
+<!--
+The resource-env-ref-name element specifies the name of a resource
+environment reference; its value is the environment entry name used in
+the web application code.  The name is a JNDI name relative to the
+java:comp/env context and must be unique within a web application.
+
+Used in: resource-env-ref
+-->
+<!ELEMENT resource-env-ref-name (#PCDATA)>
+
+<!--
+The resource-env-ref-type element specifies the type of a resource
+environment reference.  It is the fully qualified name of a Java
+language class or interface.
+
+Used in: resource-env-ref
+-->
+<!ELEMENT resource-env-ref-type (#PCDATA)>
+
+<!--
+The resource-ref element contains a declaration of a web application's
+reference to an external resource. It consists of an optional
+description, the resource manager connection factory reference name,
+the indication of the resource manager connection factory type
+expected by the web application code, the type of authentication
+(Application or Container), and an optional specification of the
+shareability of connections obtained from the resource (Shareable or
+Unshareable).
+
+Used in: web-app
+
+Example:
+
+    <resource-ref>
+	<res-ref-name>jdbc/EmployeeAppDB</res-ref-name>
+	<res-type>javax.sql.DataSource</res-type>
+	<res-auth>Container</res-auth>
+	<res-sharing-scope>Shareable</res-sharing-scope>
+    </resource-ref>
+-->
+<!ELEMENT resource-ref (description?, res-ref-name, res-type, res-auth,
+		res-sharing-scope?)>
+
+<!--
+The role-link element is a reference to a defined security role. The
+role-link element must contain the name of one of the security roles
+defined in the security-role elements.
+
+Used in: security-role-ref
+-->
+<!ELEMENT role-link (#PCDATA)>
+
+<!--
+The role-name element contains the name of a security role.
+
+The name must conform to the lexical rules for an NMTOKEN.
+
+Used in: auth-constraint, run-as, security-role, security-role-ref
+-->
+<!ELEMENT role-name (#PCDATA)>
+
+<!--
+The run-as element specifies the run-as identity to be used for the
+execution of the web application. It contains an optional description, and
+the name of a security role.
+
+Used in: servlet
+-->
+<!ELEMENT run-as (description?, role-name)>
+
+<!--
+The security-constraint element is used to associate security
+constraints with one or more web resource collections
+
+Used in: web-app
+-->
+<!ELEMENT security-constraint (display-name?, web-resource-collection+,
+auth-constraint?, user-data-constraint?)>
+
+<!--
+The security-role element contains the definition of a security
+role. The definition consists of an optional description of the
+security role, and the security role name.
+
+Used in: web-app
+
+Example:
+
+    <security-role>
+	<description>
+	    This role includes all employees who are authorized
+	    to access the employee service application.
+	</description>
+	<role-name>employee</role-name>
+    </security-role>
+-->
+<!ELEMENT security-role (description?, role-name)>
+
+<!--
+The security-role-ref element contains the declaration of a security
+role reference in the web application's code. The declaration consists
+of an optional description, the security role name used in the code,
+and an optional link to a security role. If the security role is not
+specified, the Deployer must choose an appropriate security role.
+
+The value of the role-name element must be the String used as the
+parameter to the EJBContext.isCallerInRole(String roleName) method
+or the HttpServletRequest.isUserInRole(String role) method.
+
+Used in: servlet
+
+-->
+<!ELEMENT security-role-ref (description?, role-name, role-link?)>
+
+<!--
+The servlet element contains the declarative data of a
+servlet. If a jsp-file is specified and the load-on-startup element is
+present, then the JSP should be precompiled and loaded.
+
+Used in: web-app
+-->
+<!ELEMENT servlet (icon?, servlet-name, display-name?, description?,
+(servlet-class|jsp-file), init-param*, load-on-startup?, run-as?, security-role-ref*)>
+
+<!--
+The servlet-class element contains the fully qualified class name
+of the servlet.
+
+Used in: servlet
+-->
+<!ELEMENT servlet-class (#PCDATA)>
+
+<!--
+The servlet-mapping element defines a mapping between a servlet
+and a url pattern
+
+Used in: web-app
+-->
+<!ELEMENT servlet-mapping (servlet-name, url-pattern)>
+
+<!--
+The servlet-name element contains the canonical name of the
+servlet. Each servlet name is unique within the web application.
+
+Used in: filter-mapping, servlet, servlet-mapping
+-->
+<!ELEMENT servlet-name (#PCDATA)>
+
+<!--
+The session-config element defines the session parameters for
+this web application.
+
+Used in: web-app
+-->
+<!ELEMENT session-config (session-timeout?)>
+
+<!--
+The session-timeout element defines the default session timeout
+interval for all sessions created in this web application. The
+specified timeout must be expressed in a whole number of minutes.
+If the timeout is 0 or less, the container ensures the default
+behaviour of sessions is never to time out.
+
+Used in: session-config
+-->
+<!ELEMENT session-timeout (#PCDATA)>
+
+<!--
+The small-icon element contains the name of a file
+containing a small (16 x 16) icon image. The file
+name is a relative path within the web application's
+war file.
+
+The image may be either in the JPEG or GIF format.
+The icon can be used by tools.
+
+Used in: icon
+
+Example:
+
+<small-icon>employee-service-icon16x16.jpg</small-icon>
+-->
+<!ELEMENT small-icon (#PCDATA)>
+
+<!--
+The taglib element is used to describe a JSP tag library.
+
+Used in: web-app
+-->
+<!ELEMENT taglib (taglib-uri, taglib-location)>
+
+<!--
+the taglib-location element contains the location (as a resource
+relative to the root of the web application) where to find the Tag
+Libary Description file for the tag library.
+
+Used in: taglib
+-->
+<!ELEMENT taglib-location (#PCDATA)>
+
+<!--
+The taglib-uri element describes a URI, relative to the location
+of the web.xml document, identifying a Tag Library used in the Web
+Application.
+
+Used in: taglib
+-->
+<!ELEMENT taglib-uri (#PCDATA)>
+
+<!--
+The transport-guarantee element specifies that the communication
+between client and server should be NONE, INTEGRAL, or
+CONFIDENTIAL. NONE means that the application does not require any
+transport guarantees. A value of INTEGRAL means that the application
+requires that the data sent between the client and server be sent in
+such a way that it can't be changed in transit. CONFIDENTIAL means
+that the application requires that the data be transmitted in a
+fashion that prevents other entities from observing the contents of
+the transmission. In most cases, the presence of the INTEGRAL or
+CONFIDENTIAL flag will indicate that the use of SSL is required.
+
+Used in: user-data-constraint
+-->
+<!ELEMENT transport-guarantee (#PCDATA)>
+
+<!--
+The url-pattern element contains the url pattern of the mapping. Must
+follow the rules specified in Section 11.2 of the Servlet API
+Specification.
+
+Used in: filter-mapping, servlet-mapping, web-resource-collection
+-->
+<!ELEMENT url-pattern (#PCDATA)>
+
+<!--
+The user-data-constraint element is used to indicate how data
+communicated between the client and container should be protected.
+
+Used in: security-constraint
+-->
+<!ELEMENT user-data-constraint (description?, transport-guarantee)>
+
+<!--
+The web-resource-collection element is used to identify a subset
+of the resources and HTTP methods on those resources within a web
+application to which a security constraint applies. If no HTTP methods
+are specified, then the security constraint applies to all HTTP
+methods.
+
+Used in: security-constraint
+-->
+<!ELEMENT web-resource-collection (web-resource-name, description?,
+url-pattern*, http-method*)>
+
+<!--
+The web-resource-name contains the name of this web resource
+collection.
+
+Used in: web-resource-collection
+-->
+<!ELEMENT web-resource-name (#PCDATA)>
+
+<!--
+The welcome-file element contains file name to use as a default
+welcome file, such as index.html
+
+Used in: welcome-file-list
+-->
+<!ELEMENT welcome-file (#PCDATA)>
+
+<!--
+The welcome-file-list contains an ordered list of welcome files
+elements.
+
+Used in: web-app
+-->
+<!ELEMENT welcome-file-list (welcome-file+)>
+
+<!--
+The ID mechanism is to allow tools that produce additional deployment
+information (i.e., information beyond the standard deployment
+descriptor information) to store the non-standard information in a
+separate file, and easily refer from these tool-specific files to the
+information in the standard deployment descriptor.
+
+Tools are not allowed to add the non-standard information into the
+standard deployment descriptor.
+-->
+
+<!ATTLIST auth-constraint id ID #IMPLIED>
+<!ATTLIST auth-method id ID #IMPLIED>
+<!ATTLIST context-param id ID #IMPLIED>
+<!ATTLIST description id ID #IMPLIED>
+<!ATTLIST display-name id ID #IMPLIED>
+<!ATTLIST distributable id ID #IMPLIED>
+<!ATTLIST ejb-link id ID #IMPLIED>
+<!ATTLIST ejb-local-ref id ID #IMPLIED>
+<!ATTLIST ejb-ref id ID #IMPLIED>
+<!ATTLIST ejb-ref-name id ID #IMPLIED>
+<!ATTLIST ejb-ref-type id ID #IMPLIED>
+<!ATTLIST env-entry id ID #IMPLIED>
+<!ATTLIST env-entry-name id ID #IMPLIED>
+<!ATTLIST env-entry-type id ID #IMPLIED>
+<!ATTLIST env-entry-value id ID #IMPLIED>
+<!ATTLIST error-code id ID #IMPLIED>
+<!ATTLIST error-page id ID #IMPLIED>
+<!ATTLIST exception-type id ID #IMPLIED>
+<!ATTLIST extension id ID #IMPLIED>
+<!ATTLIST filter id ID #IMPLIED>
+<!ATTLIST filter-class id ID #IMPLIED>
+<!ATTLIST filter-mapping id ID #IMPLIED>
+<!ATTLIST filter-name id ID #IMPLIED>
+<!ATTLIST form-error-page id ID #IMPLIED>
+<!ATTLIST form-login-config id ID #IMPLIED>
+<!ATTLIST form-login-page id ID #IMPLIED>
+<!ATTLIST home id ID #IMPLIED>
+<!ATTLIST http-method id ID #IMPLIED>
+<!ATTLIST icon id ID #IMPLIED>
+<!ATTLIST init-param id ID #IMPLIED>
+<!ATTLIST jsp-file id ID #IMPLIED>
+<!ATTLIST large-icon id ID #IMPLIED>
+<!ATTLIST listener id ID #IMPLIED>
+<!ATTLIST listener-class id ID #IMPLIED>
+<!ATTLIST load-on-startup id ID #IMPLIED>
+<!ATTLIST local id ID #IMPLIED>
+<!ATTLIST local-home id ID #IMPLIED>
+<!ATTLIST location id ID #IMPLIED>
+<!ATTLIST login-config id ID #IMPLIED>
+<!ATTLIST mime-mapping id ID #IMPLIED>
+<!ATTLIST mime-type id ID #IMPLIED>
+<!ATTLIST param-name id ID #IMPLIED>
+<!ATTLIST param-value id ID #IMPLIED>
+<!ATTLIST realm-name id ID #IMPLIED>
+<!ATTLIST remote id ID #IMPLIED>
+<!ATTLIST res-auth id ID #IMPLIED>
+<!ATTLIST res-ref-name id ID #IMPLIED>
+<!ATTLIST res-sharing-scope id ID #IMPLIED>
+<!ATTLIST res-type id ID #IMPLIED>
+<!ATTLIST resource-env-ref id ID #IMPLIED>
+<!ATTLIST resource-env-ref-name id ID #IMPLIED>
+<!ATTLIST resource-env-ref-type id ID #IMPLIED>
+<!ATTLIST resource-ref id ID #IMPLIED>
+<!ATTLIST role-link id ID #IMPLIED>
+<!ATTLIST role-name id ID #IMPLIED>
+<!ATTLIST run-as id ID #IMPLIED>
+<!ATTLIST security-constraint id ID #IMPLIED>
+<!ATTLIST security-role id ID #IMPLIED>
+<!ATTLIST security-role-ref id ID #IMPLIED>
+<!ATTLIST servlet id ID #IMPLIED>
+<!ATTLIST servlet-class id ID #IMPLIED>
+<!ATTLIST servlet-mapping id ID #IMPLIED>
+<!ATTLIST servlet-name id ID #IMPLIED>
+<!ATTLIST session-config id ID #IMPLIED>
+<!ATTLIST session-timeout id ID #IMPLIED>
+<!ATTLIST small-icon id ID #IMPLIED>
+<!ATTLIST taglib id ID #IMPLIED>
+<!ATTLIST taglib-location id ID #IMPLIED>
+<!ATTLIST taglib-uri id ID #IMPLIED>
+<!ATTLIST transport-guarantee id ID #IMPLIED>
+<!ATTLIST url-pattern id ID #IMPLIED>
+<!ATTLIST user-data-constraint id ID #IMPLIED>
+<!ATTLIST web-app id ID #IMPLIED>
+<!ATTLIST web-resource-collection id ID #IMPLIED>
+<!ATTLIST web-resource-name id ID #IMPLIED>
+<!ATTLIST welcome-file id ID #IMPLIED>
+<!ATTLIST welcome-file-list id ID #IMPLIED>

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/dtd/web-app_2_4.xsd
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/dtd/web-app_2_4.xsd	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/dtd/web-app_2_4.xsd	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,1248 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Copyright 2004 The Apache Software Foundation
+
+  Licensed 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.
+-->
+<xsd:schema xmlns="http://www.w3.org/2001/XMLSchema"
+	    targetNamespace="http://java.sun.com/xml/ns/j2ee"
+	    xmlns:j2ee="http://java.sun.com/xml/ns/j2ee"
+	    xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+	    elementFormDefault="qualified"
+	    attributeFormDefault="unqualified"
+	    version="2.4">
+  <xsd:annotation>
+    <xsd:documentation>
+      %W% %E%
+    </xsd:documentation>
+  </xsd:annotation>
+
+  <xsd:annotation>
+    <xsd:documentation>
+
+      Copyright 2004 Sun Microsystems, Inc., 901 San Antonio
+      Road, Palo Alto, California 94303, U.S.A. All rights
+      reserved.
+
+      Sun Microsystems, Inc. has intellectual property rights
+      relating to technology described in this document. In
+      particular, and without limitation, these intellectual
+      property rights may include one or more of the U.S. patents
+      listed at http://www.sun.com/patents and one or more
+      additional patents or pending patent applications in the
+      U.S. and other countries.
+
+      This document and the technology which it describes are
+      distributed under licenses restricting their use, copying,
+      distribution, and decompilation. No part of this document
+      may be reproduced in any form by any means without prior
+      written authorization of Sun and its licensors, if any.
+
+      Third-party software, including font technology, is
+      copyrighted and licensed from Sun suppliers.
+
+      Sun, Sun Microsystems, the Sun logo, Solaris, Java, J2EE,
+      JavaServer Pages, Enterprise JavaBeans and the Java Coffee
+      Cup logo are trademarks or registered trademarks of Sun
+      Microsystems, Inc. in the U.S. and other countries.
+
+      Federal Acquisitions: Commercial Software - Government Users
+      Subject to Standard License Terms and Conditions.
+
+    </xsd:documentation>
+  </xsd:annotation>
+
+  <xsd:annotation>
+    <xsd:documentation>
+      <![CDATA[
+
+	This is the XML Schema for the Servlet 2.4 deployment descriptor.
+	The deployment descriptor must be named "WEB-INF/web.xml" in the
+	web application's war file.  All Servlet deployment descriptors
+	must indicate the web application schema by using the J2EE
+	namespace:
+
+	http://java.sun.com/xml/ns/j2ee
+
+	and by indicating the version of the schema by
+	using the version element as shown below:
+
+	    <web-app xmlns="http://java.sun.com/xml/ns/j2ee"
+	      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	      xsi:schemaLocation="..."
+	      version="2.4">
+	      ...
+	    </web-app>
+
+	The instance documents may indicate the published version of
+	the schema using the xsi:schemaLocation attribute for J2EE
+	namespace with the following location:
+
+	http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd
+
+	]]>
+    </xsd:documentation>
+  </xsd:annotation>
+
+  <xsd:annotation>
+    <xsd:documentation>
+
+      The following conventions apply to all J2EE
+      deployment descriptor elements unless indicated otherwise.
+
+      - In elements that specify a pathname to a file within the
+	same JAR file, relative filenames (i.e., those not
+	starting with "/") are considered relative to the root of
+	the JAR file's namespace.  Absolute filenames (i.e., those
+	starting with "/") also specify names in the root of the
+	JAR file's namespace.  In general, relative names are
+	preferred.  The exception is .war files where absolute
+	names are preferred for consistency with the Servlet API.
+
+    </xsd:documentation>
+  </xsd:annotation>
+
+  <xsd:include schemaLocation="j2ee_1_4.xsd"/>
+  <xsd:include schemaLocation="jsp_2_0.xsd"/>
+
+
+<!-- **************************************************** -->
+
+
+  <xsd:element name="web-app" type="j2ee:web-appType">
+    <xsd:annotation>
+      <xsd:documentation>
+
+	The web-app element is the root of the deployment
+	descriptor for a web application.  Note that the sub-elements
+	of this element can be in the arbitrary order. Because of
+	that, the multiplicity of the elements of distributable,
+	session-config, welcome-file-list, jsp-config, login-config,
+	and locale-encoding-mapping-list was changed from "?" to "*"
+	in this schema.  However, the deployment descriptor instance
+	file must not contain multiple elements of session-config,
+	jsp-config, and login-config. When there are multiple elements of
+	welcome-file-list or locale-encoding-mapping-list, the container
+	must concatinate the element contents.  The multiple occurance
+	of the element distributable is redundant and the container
+	treats that case exactly in the same way when there is only
+	one distributable.
+
+      </xsd:documentation>
+    </xsd:annotation>
+
+    <xsd:unique name="web-app-servlet-name-uniqueness">
+      <xsd:annotation>
+	<xsd:documentation>
+
+	  The servlet element contains the name of a servlet.
+	  The name must be unique within the web application.
+
+	</xsd:documentation>
+      </xsd:annotation>
+      <xsd:selector xpath="j2ee:servlet"/>
+      <xsd:field    xpath="j2ee:servlet-name"/>
+    </xsd:unique>
+
+    <xsd:unique name="web-app-filter-name-uniqueness">
+      <xsd:annotation>
+	<xsd:documentation>
+
+	  The filter element contains the name of a filter.
+	  The name must be unique within the web application.
+
+	</xsd:documentation>
+      </xsd:annotation>
+      <xsd:selector xpath="j2ee:filter"/>
+      <xsd:field    xpath="j2ee:filter-name"/>
+    </xsd:unique>
+
+    <xsd:unique name="web-app-ejb-local-ref-name-uniqueness">
+      <xsd:annotation>
+	<xsd:documentation>
+
+	  The ejb-local-ref-name element contains the name of an EJB
+	  reference. The EJB reference is an entry in the web
+	  application's environment and is relative to the
+	  java:comp/env context.  The name must be unique within
+	  the web application.
+
+	  It is recommended that name is prefixed with "ejb/".
+
+	</xsd:documentation>
+      </xsd:annotation>
+      <xsd:selector xpath="j2ee:ejb-local-ref"/>
+      <xsd:field    xpath="j2ee:ejb-ref-name"/>
+    </xsd:unique>
+
+    <xsd:unique name="web-app-ejb-ref-name-uniqueness">
+      <xsd:annotation>
+	<xsd:documentation>
+
+	  The ejb-ref-name element contains the name of an EJB
+	  reference. The EJB reference is an entry in the web
+	  application's environment and is relative to the
+	  java:comp/env context.  The name must be unique within
+	  the web application.
+
+	  It is recommended that name is prefixed with "ejb/".
+
+	</xsd:documentation>
+      </xsd:annotation>
+      <xsd:selector xpath="j2ee:ejb-ref"/>
+      <xsd:field    xpath="j2ee:ejb-ref-name"/>
+    </xsd:unique>
+
+    <xsd:unique name="web-app-resource-env-ref-uniqueness">
+      <xsd:annotation>
+	<xsd:documentation>
+
+	  The resource-env-ref-name element specifies the name of
+	  a resource environment reference; its value is the
+	  environment entry name used in the web application code.
+	  The name is a JNDI name relative to the java:comp/env
+	  context and must be unique within a web application.
+
+	</xsd:documentation>
+      </xsd:annotation>
+      <xsd:selector xpath="j2ee:resource-env-ref"/>
+      <xsd:field    xpath="j2ee:resource-env-ref-name"/>
+    </xsd:unique>
+
+    <xsd:unique name="web-app-message-destination-ref-uniqueness">
+      <xsd:annotation>
+	<xsd:documentation>
+
+	  The message-destination-ref-name element specifies the name of
+	  a message destination reference; its value is the
+	  environment entry name used in the web application code.
+	  The name is a JNDI name relative to the java:comp/env
+	  context and must be unique within a web application.
+
+	</xsd:documentation>
+      </xsd:annotation>
+      <xsd:selector xpath="j2ee:message-destination-ref"/>
+      <xsd:field    xpath="j2ee:message-destination-ref-name"/>
+    </xsd:unique>
+
+    <xsd:unique name="web-app-res-ref-name-uniqueness">
+      <xsd:annotation>
+	<xsd:documentation>
+
+	  The res-ref-name element specifies the name of a
+	  resource manager connection factory reference.  The name
+	  is a JNDI name relative to the java:comp/env context.
+	  The name must be unique within a web application.
+
+	</xsd:documentation>
+      </xsd:annotation>
+      <xsd:selector xpath="j2ee:resource-ref"/>
+      <xsd:field    xpath="j2ee:res-ref-name"/>
+    </xsd:unique>
+
+    <xsd:unique name="web-app-env-entry-name-uniqueness">
+      <xsd:annotation>
+	<xsd:documentation>
+
+	  The env-entry-name element contains the name of a web
+	  application's environment entry.  The name is a JNDI
+	  name relative to the java:comp/env context.  The name
+	  must be unique within a web application.
+
+	</xsd:documentation>
+      </xsd:annotation>
+
+      <xsd:selector xpath="j2ee:env-entry"/>
+      <xsd:field    xpath="j2ee:env-entry-name"/>
+    </xsd:unique>
+
+    <xsd:key name="web-app-role-name-key">
+      <xsd:annotation>
+	<xsd:documentation>
+
+	  A role-name-key is specified to allow the references
+	  from the security-role-refs.
+
+	</xsd:documentation>
+      </xsd:annotation>
+      <xsd:selector xpath="j2ee:security-role"/>
+      <xsd:field    xpath="j2ee:role-name"/>
+    </xsd:key>
+
+    <xsd:keyref name="web-app-role-name-references"
+		refer="j2ee:web-app-role-name-key">
+      <xsd:annotation>
+	<xsd:documentation>
+
+	  The keyref indicates the references from
+	  security-role-ref to a specified role-name.
+
+	</xsd:documentation>
+      </xsd:annotation>
+      <xsd:selector xpath="j2ee:servlet/j2ee:security-role-ref"/>
+      <xsd:field    xpath="j2ee:role-link"/>
+    </xsd:keyref>
+  </xsd:element>
+
+
+<!-- **************************************************** -->
+
+  <xsd:complexType name="auth-constraintType">
+    <xsd:annotation>
+      <xsd:documentation>
+
+	The auth-constraintType indicates the user roles that
+	should be permitted access to this resource
+	collection. The role-name used here must either correspond
+	to the role-name of one of the security-role elements
+	defined for this web application, or be the specially
+	reserved role-name "*" that is a compact syntax for
+	indicating all roles in the web application. If both "*"
+	and rolenames appear, the container interprets this as all
+	roles.  If no roles are defined, no user is allowed access
+	to the portion of the web application described by the
+	containing security-constraint.  The container matches
+	role names case sensitively when determining access.
+
+      </xsd:documentation>
+    </xsd:annotation>
+
+    <xsd:sequence>
+      <xsd:element name="description"
+		   type="j2ee:descriptionType"
+		   minOccurs="0" maxOccurs="unbounded"/>
+      <xsd:element name="role-name"
+		   type="j2ee:role-nameType"
+		   minOccurs="0" maxOccurs="unbounded"/>
+    </xsd:sequence>
+    <xsd:attribute name="id" type="xsd:ID"/>
+  </xsd:complexType>
+
+<!-- **************************************************** -->
+
+  <xsd:complexType name="auth-methodType">
+    <xsd:annotation>
+      <xsd:documentation>
+
+	The auth-methodType is used to configure the authentication
+	mechanism for the web application. As a prerequisite to
+	gaining access to any web resources which are protected by
+	an authorization constraint, a user must have authenticated
+	using the configured mechanism. Legal values are "BASIC",
+	"DIGEST", "FORM", "CLIENT-CERT", or a vendor-specific
+	authentication scheme.
+
+	Used in: login-config
+
+      </xsd:documentation>
+    </xsd:annotation>
+
+    <xsd:simpleContent>
+      <xsd:restriction base="j2ee:string"/>
+    </xsd:simpleContent>
+  </xsd:complexType>
+
+<!-- **************************************************** -->
+
+  <xsd:complexType name="dispatcherType">
+    <xsd:annotation>
+      <xsd:documentation>
+
+	The dispatcher has four legal values: FORWARD, REQUEST, INCLUDE,
+	and ERROR. A value of FORWARD means the Filter will be applied
+	under RequestDispatcher.forward() calls.  A value of REQUEST
+	means the Filter will be applied under ordinary client calls to
+	the path or servlet. A value of INCLUDE means the Filter will be
+	applied under RequestDispatcher.include() calls.  A value of
+	ERROR means the Filter will be applied under the error page
+	mechanism.  The absence of any dispatcher elements in a
+	filter-mapping indicates a default of applying filters only under
+	ordinary client calls to the path or servlet.
+
+      </xsd:documentation>
+    </xsd:annotation>
+
+    <xsd:simpleContent>
+      <xsd:restriction base="j2ee:string">
+	<xsd:enumeration value="FORWARD"/>
+	<xsd:enumeration value="INCLUDE"/>
+	<xsd:enumeration value="REQUEST"/>
+	<xsd:enumeration value="ERROR"/>
+      </xsd:restriction>
+    </xsd:simpleContent>
+  </xsd:complexType>
+
+<!-- **************************************************** -->
+
+  <xsd:simpleType name="encodingType">
+    <xsd:annotation>
+      <xsd:documentation>
+
+	The encodingType defines IANA character sets.
+
+      </xsd:documentation>
+    </xsd:annotation>
+
+    <xsd:restriction base="xsd:string">
+      <xsd:pattern value="[^\s]+"/>
+    </xsd:restriction>
+  </xsd:simpleType>
+
+<!-- **************************************************** -->
+
+  <xsd:complexType name="error-codeType">
+    <xsd:annotation>
+      <xsd:documentation>
+
+	The error-code contains an HTTP error code, ex: 404
+
+	Used in: error-page
+
+      </xsd:documentation>
+    </xsd:annotation>
+
+    <xsd:simpleContent>
+      <xsd:restriction base="j2ee:xsdPositiveIntegerType">
+	<xsd:pattern value="\d{3}"/>
+	<xsd:attribute name="id" type="xsd:ID"/>
+      </xsd:restriction>
+    </xsd:simpleContent>
+  </xsd:complexType>
+
+<!-- **************************************************** -->
+
+  <xsd:complexType name="error-pageType">
+    <xsd:annotation>
+      <xsd:documentation>
+
+	The error-pageType contains a mapping between an error code
+	or exception type to the path of a resource in the web
+	application.
+
+	Used in: web-app
+
+      </xsd:documentation>
+    </xsd:annotation>
+
+    <xsd:sequence>
+      <xsd:choice>
+	<xsd:element name="error-code"
+		     type="j2ee:error-codeType"/>
+
+	<xsd:element name="exception-type"
+		     type="j2ee:fully-qualified-classType">
+	  <xsd:annotation>
+	    <xsd:documentation>
+
+	      The exception-type contains a fully qualified class
+	      name of a Java exception type.
+
+	    </xsd:documentation>
+	  </xsd:annotation>
+	</xsd:element>
+      </xsd:choice>
+
+      <xsd:element name="location"
+		   type="j2ee:war-pathType">
+	<xsd:annotation>
+	  <xsd:documentation>
+
+	    The location element contains the location of the
+	    resource in the web application relative to the root of
+	    the web application. The value of the location must have
+	    a leading `/'.
+
+	  </xsd:documentation>
+	</xsd:annotation>
+      </xsd:element>
+    </xsd:sequence>
+    <xsd:attribute name="id" type="xsd:ID"/>
+  </xsd:complexType>
+
+<!-- **************************************************** -->
+
+  <xsd:complexType name="filter-mappingType">
+    <xsd:annotation>
+      <xsd:documentation>
+
+	Declaration of the filter mappings in this web
+	application is done by using filter-mappingType.
+	The container uses the filter-mapping
+	declarations to decide which filters to apply to a request,
+	and in what order. The container matches the request URI to
+	a Servlet in the normal way. To determine which filters to
+	apply it matches filter-mapping declarations either on
+	servlet-name, or on url-pattern for each filter-mapping
+	element, depending on which style is used. The order in
+	which filters are invoked is the order in which
+	filter-mapping declarations that match a request URI for a
+	servlet appear in the list of filter-mapping elements.The
+	filter-name value must be the value of the filter-name
+	sub-elements of one of the filter declarations in the
+	deployment descriptor.
+
+      </xsd:documentation>
+    </xsd:annotation>
+
+    <xsd:sequence>
+      <xsd:element name="filter-name"
+		   type="j2ee:filter-nameType"/>
+      <xsd:choice>
+	<xsd:element name="url-pattern"
+		     type="j2ee:url-patternType"/>
+	<xsd:element name="servlet-name"
+		     type="j2ee:servlet-nameType"/>
+      </xsd:choice>
+      <xsd:element name="dispatcher"
+		   type="j2ee:dispatcherType"
+		   minOccurs="0" maxOccurs="4"/>
+    </xsd:sequence>
+    <xsd:attribute name="id" type="xsd:ID"/>
+  </xsd:complexType>
+
+<!-- **************************************************** -->
+
+  <xsd:complexType name="filter-nameType">
+    <xsd:annotation>
+      <xsd:documentation>
+
+	The logical name of the filter is declare
+	by using filter-nameType. This name is used to map the
+	filter.  Each filter name is unique within the web
+	application.
+
+	Used in: filter, filter-mapping
+
+      </xsd:documentation>
+    </xsd:annotation>
+
+    <xsd:simpleContent>
+      <xsd:extension base="j2ee:nonEmptyStringType"/>
+    </xsd:simpleContent>
+  </xsd:complexType>
+
+<!-- **************************************************** -->
+
+  <xsd:complexType name="filterType">
+    <xsd:annotation>
+      <xsd:documentation>
+
+	The filterType is used to declare a filter in the web
+	application. The filter is mapped to either a servlet or a
+	URL pattern in the filter-mapping element, using the
+	filter-name value to reference. Filters can access the
+	initialization parameters declared in the deployment
+	descriptor at runtime via the FilterConfig interface.
+
+	Used in: web-app
+
+      </xsd:documentation>
+    </xsd:annotation>
+
+    <xsd:sequence>
+      <xsd:group ref="j2ee:descriptionGroup"/>
+      <xsd:element name="filter-name"
+		   type="j2ee:filter-nameType"/>
+      <xsd:element name="filter-class"
+		   type="j2ee:fully-qualified-classType">
+	<xsd:annotation>
+	  <xsd:documentation>
+
+	    The fully qualified classname of the filter.
+
+	  </xsd:documentation>
+	</xsd:annotation>
+      </xsd:element>
+
+      <xsd:element name="init-param"
+		   type="j2ee:param-valueType"
+		   minOccurs="0" maxOccurs="unbounded">
+	<xsd:annotation>
+	  <xsd:documentation>
+
+	    The init-param element contains a name/value pair as
+	    an initialization param of a servlet filter
+
+	  </xsd:documentation>
+	</xsd:annotation>
+      </xsd:element>
+    </xsd:sequence>
+    <xsd:attribute name="id" type="xsd:ID"/>
+  </xsd:complexType>
+
+<!-- **************************************************** -->
+
+  <xsd:complexType name="form-login-configType">
+    <xsd:annotation>
+      <xsd:documentation>
+
+	The form-login-configType specifies the login and error
+	pages that should be used in form based login. If form based
+	authentication is not used, these elements are ignored.
+
+	Used in: login-config
+
+      </xsd:documentation>
+    </xsd:annotation>
+
+    <xsd:sequence>
+
+      <xsd:element name="form-login-page"
+		   type="j2ee:war-pathType">
+	<xsd:annotation>
+	  <xsd:documentation>
+
+	    The form-login-page element defines the location in the web
+	    app where the page that can be used for login can be
+	    found.  The path begins with a leading / and is interpreted
+	    relative to the root of the WAR.
+
+	  </xsd:documentation>
+	</xsd:annotation>
+      </xsd:element>
+
+      <xsd:element name="form-error-page"
+		   type="j2ee:war-pathType">
+	<xsd:annotation>
+	  <xsd:documentation>
+
+	    The form-error-page element defines the location in
+	    the web app where the error page that is displayed
+	    when login is not successful can be found.
+	    The path begins with a leading / and is interpreted
+	    relative to the root of the WAR.
+
+	  </xsd:documentation>
+	</xsd:annotation>
+      </xsd:element>
+
+    </xsd:sequence>
+    <xsd:attribute name="id" type="xsd:ID"/>
+  </xsd:complexType>
+
+<!-- **************************************************** -->
+
+  <xsd:complexType name="http-methodType">
+    <xsd:annotation>
+
+      <xsd:documentation>
+
+	The http-method contains an HTTP method recognized by the
+	web-app, for example GET, POST, ...
+
+      </xsd:documentation>
+    </xsd:annotation>
+
+    <xsd:simpleContent>
+      <xsd:restriction base="j2ee:string">
+	<xsd:enumeration value="GET"/>
+	<xsd:enumeration value="POST"/>
+	<xsd:enumeration value="PUT"/>
+	<xsd:enumeration value="DELETE"/>
+	<xsd:enumeration value="HEAD"/>
+	<xsd:enumeration value="OPTIONS"/>
+	<xsd:enumeration value="TRACE"/>
+      </xsd:restriction>
+    </xsd:simpleContent>
+  </xsd:complexType>
+
+<!-- **************************************************** -->
+
+  <xsd:complexType name="locale-encoding-mapping-listType">
+    <xsd:annotation>
+      <xsd:documentation>
+
+	The locale-encoding-mapping-list contains one or more
+	locale-encoding-mapping(s).
+
+      </xsd:documentation>
+    </xsd:annotation>
+
+    <xsd:sequence>
+      <xsd:element name="locale-encoding-mapping"
+		   type="j2ee:locale-encoding-mappingType"
+		   maxOccurs="unbounded"/>
+    </xsd:sequence>
+    <xsd:attribute name="id" type="xsd:ID"/>
+  </xsd:complexType>
+
+<!-- **************************************************** -->
+
+  <xsd:complexType name="locale-encoding-mappingType">
+    <xsd:annotation>
+      <xsd:documentation>
+
+	The locale-encoding-mapping contains locale name and
+	encoding name. The locale name must be either "Language-code",
+	such as "ja", defined by ISO-639 or "Language-code_Country-code",
+	such as "ja_JP".  "Country code" is defined by ISO-3166.
+
+      </xsd:documentation>
+    </xsd:annotation>
+
+    <xsd:sequence>
+      <xsd:element name="locale"
+		   type="j2ee:localeType"/>
+      <xsd:element name="encoding"
+		   type="j2ee:encodingType"/>
+    </xsd:sequence>
+    <xsd:attribute name="id" type="xsd:ID"/>
+  </xsd:complexType>
+
+<!-- **************************************************** -->
+
+  <xsd:simpleType name="localeType">
+    <xsd:annotation>
+      <xsd:documentation>
+
+	The localeType defines valid locale defined by ISO-639-1
+	and ISO-3166.
+
+      </xsd:documentation>
+    </xsd:annotation>
+
+    <xsd:restriction base="xsd:string">
+      <xsd:pattern value="[a-z]{2}(_|-)?([\p{L}\-\p{Nd}]{2})?"/>
+    </xsd:restriction>
+  </xsd:simpleType>
+
+<!-- **************************************************** -->
+
+  <xsd:complexType name="login-configType">
+    <xsd:annotation>
+      <xsd:documentation>
+
+	The login-configType is used to configure the authentication
+	method that should be used, the realm name that should be
+	used for this application, and the attributes that are
+	needed by the form login mechanism.
+
+	Used in: web-app
+
+      </xsd:documentation>
+    </xsd:annotation>
+
+    <xsd:sequence>
+      <xsd:element name="auth-method"
+		   type="j2ee:auth-methodType"
+		   minOccurs="0"/>
+      <xsd:element name="realm-name"
+		   type="j2ee:string" minOccurs="0">
+	<xsd:annotation>
+	  <xsd:documentation>
+
+	    The realm name element specifies the realm name to
+	    use in HTTP Basic authorization.
+
+	  </xsd:documentation>
+	</xsd:annotation>
+      </xsd:element>
+      <xsd:element name="form-login-config"
+		   type="j2ee:form-login-configType"
+		   minOccurs="0"/>
+    </xsd:sequence>
+    <xsd:attribute name="id" type="xsd:ID"/>
+  </xsd:complexType>
+
+<!-- **************************************************** -->
+
+  <xsd:complexType name="mime-mappingType">
+    <xsd:annotation>
+      <xsd:documentation>
+
+	The mime-mappingType defines a mapping between an extension
+	and a mime type.
+
+	Used in: web-app
+
+      </xsd:documentation>
+    </xsd:annotation>
+
+    <xsd:sequence>
+      <xsd:annotation>
+	<xsd:documentation>
+
+	  The extension element contains a string describing an
+	  extension. example: "txt"
+
+	</xsd:documentation>
+      </xsd:annotation>
+
+      <xsd:element name="extension"
+		   type="j2ee:string"/>
+      <xsd:element name="mime-type"
+		   type="j2ee:mime-typeType"/>
+    </xsd:sequence>
+    <xsd:attribute name="id" type="xsd:ID"/>
+  </xsd:complexType>
+
+<!-- **************************************************** -->
+
+  <xsd:complexType name="mime-typeType">
+    <xsd:annotation>
+      <xsd:documentation>
+
+	The mime-typeType is used to indicate a defined mime type.
+
+	Example:
+	"text/plain"
+
+	Used in: mime-mapping
+
+      </xsd:documentation>
+    </xsd:annotation>
+
+    <xsd:simpleContent>
+      <xsd:restriction base="j2ee:string">
+          <xsd:pattern value="[^\p{Cc}^\s]+/[^\p{Cc}^\s]+"/>
+      </xsd:restriction>
+    </xsd:simpleContent>
+  </xsd:complexType>
+
+<!-- **************************************************** -->
+
+  <xsd:complexType name="nonEmptyStringType">
+    <xsd:annotation>
+      <xsd:documentation>
+	This type defines a string which contains at least one
+	character.
+      </xsd:documentation>
+    </xsd:annotation>
+    <xsd:simpleContent>
+      <xsd:restriction base="j2ee:string">
+	<xsd:minLength value="1"/>
+      </xsd:restriction>
+    </xsd:simpleContent>
+  </xsd:complexType>
+
+<!-- **************************************************** -->
+
+  <xsd:complexType name="security-constraintType">
+    <xsd:annotation>
+      <xsd:documentation>
+
+	The security-constraintType is used to associate
+	security constraints with one or more web resource
+	collections
+
+	Used in: web-app
+
+      </xsd:documentation>
+    </xsd:annotation>
+
+    <xsd:sequence>
+      <xsd:element name="display-name"
+		   type="j2ee:display-nameType"
+		   minOccurs="0"
+		   maxOccurs="unbounded"/>
+      <xsd:element name="web-resource-collection"
+		   type="j2ee:web-resource-collectionType"
+		   maxOccurs="unbounded"/>
+      <xsd:element name="auth-constraint"
+		   type="j2ee:auth-constraintType"
+		   minOccurs="0"/>
+      <xsd:element name="user-data-constraint"
+		   type="j2ee:user-data-constraintType"
+		   minOccurs="0"/>
+    </xsd:sequence>
+    <xsd:attribute name="id" type="xsd:ID"/>
+  </xsd:complexType>
+
+<!-- **************************************************** -->
+
+  <xsd:complexType name="servlet-mappingType">
+    <xsd:annotation>
+      <xsd:documentation>
+
+	The servlet-mappingType defines a mapping between a
+	servlet and a url pattern.
+
+	Used in: web-app
+
+      </xsd:documentation>
+    </xsd:annotation>
+
+    <xsd:sequence>
+      <xsd:element name="servlet-name"
+		   type="j2ee:servlet-nameType"/>
+      <xsd:element name="url-pattern"
+		   type="j2ee:url-patternType"/>
+    </xsd:sequence>
+    <xsd:attribute name="id" type="xsd:ID"/>
+  </xsd:complexType>
+
+<!-- **************************************************** -->
+
+  <xsd:complexType name="servlet-nameType">
+    <xsd:annotation>
+      <xsd:documentation>
+
+	The servlet-name element contains the canonical name of the
+	servlet. Each servlet name is unique within the web
+	application.
+
+      </xsd:documentation>
+    </xsd:annotation>
+
+    <xsd:simpleContent>
+      <xsd:extension base="j2ee:nonEmptyStringType"/>
+    </xsd:simpleContent>
+  </xsd:complexType>
+
+<!-- **************************************************** -->
+
+  <xsd:complexType name="servletType">
+    <xsd:annotation>
+      <xsd:documentation>
+
+	The servletType is used to declare a servlet.
+	It contains the declarative data of a
+	servlet. If a jsp-file is specified and the load-on-startup
+	element is present, then the JSP should be precompiled and
+	loaded.
+
+	Used in: web-app
+
+      </xsd:documentation>
+    </xsd:annotation>
+
+    <xsd:sequence>
+      <xsd:group ref="j2ee:descriptionGroup"/>
+      <xsd:element name="servlet-name"
+		   type="j2ee:servlet-nameType"/>
+      <xsd:choice>
+	<xsd:element name="servlet-class"
+		     type="j2ee:fully-qualified-classType">
+	  <xsd:annotation>
+	    <xsd:documentation>
+
+	      The servlet-class element contains the fully
+	      qualified class name of the servlet.
+
+	    </xsd:documentation>
+	  </xsd:annotation>
+	</xsd:element>
+
+	<xsd:element name="jsp-file"
+		     type="j2ee:jsp-fileType"/>
+
+      </xsd:choice>
+
+      <xsd:element name="init-param"
+		   type="j2ee:param-valueType"
+		   minOccurs="0" maxOccurs="unbounded"/>
+      <xsd:element name="load-on-startup"
+		   type="j2ee:xsdIntegerType"
+		   minOccurs="0">
+	<xsd:annotation>
+	  <xsd:documentation>
+
+	    The load-on-startup element indicates that this
+	    servlet should be loaded (instantiated and have
+	    its init() called) on the startup of the web
+	    application. The optional contents of these
+	    element must be an integer indicating the order in
+	    which the servlet should be loaded. If the value
+	    is a negative integer, or the element is not
+	    present, the container is free to load the servlet
+	    whenever it chooses. If the value is a positive
+	    integer or 0, the container must load and
+	    initialize the servlet as the application is
+	    deployed. The container must guarantee that
+	    servlets marked with lower integers are loaded
+	    before servlets marked with higher integers. The
+	    container may choose the order of loading of
+	    servlets with the same load-on-start-up value.
+
+	  </xsd:documentation>
+	</xsd:annotation>
+      </xsd:element>
+      <xsd:element name="run-as"
+		   type="j2ee:run-asType"
+		   minOccurs="0"/>
+      <xsd:element name="security-role-ref"
+		   type="j2ee:security-role-refType"
+		   minOccurs="0" maxOccurs="unbounded"/>
+    </xsd:sequence>
+    <xsd:attribute name="id" type="xsd:ID"/>
+  </xsd:complexType>
+
+<!-- **************************************************** -->
+
+  <xsd:complexType name="session-configType">
+    <xsd:annotation>
+      <xsd:documentation>
+
+	The session-configType defines the session parameters
+	for this web application.
+
+	Used in: web-app
+
+      </xsd:documentation>
+    </xsd:annotation>
+
+    <xsd:sequence>
+      <xsd:element name="session-timeout"
+		   type="j2ee:xsdIntegerType"
+		   minOccurs="0">
+	<xsd:annotation>
+	  <xsd:documentation>
+
+	    The session-timeout element defines the default
+	    session timeout interval for all sessions created
+	    in this web application. The specified timeout
+	    must be expressed in a whole number of minutes.
+	    If the timeout is 0 or less, the container ensures
+	    the default behaviour of sessions is never to time
+	    out. If this element is not specified, the container
+	    must set its default timeout period.
+
+	  </xsd:documentation>
+	</xsd:annotation>
+      </xsd:element>
+    </xsd:sequence>
+    <xsd:attribute name="id" type="xsd:ID"/>
+  </xsd:complexType>
+
+<!-- **************************************************** -->
+
+  <xsd:complexType name="transport-guaranteeType">
+    <xsd:annotation>
+      <xsd:documentation>
+
+	The transport-guaranteeType specifies that the communication
+	between client and server should be NONE, INTEGRAL, or
+	CONFIDENTIAL. NONE means that the application does not
+	require any transport guarantees. A value of INTEGRAL means
+	that the application requires that the data sent between the
+	client and server be sent in such a way that it can't be
+	changed in transit. CONFIDENTIAL means that the application
+	requires that the data be transmitted in a fashion that
+	prevents other entities from observing the contents of the
+	transmission. In most cases, the presence of the INTEGRAL or
+	CONFIDENTIAL flag will indicate that the use of SSL is
+	required.
+
+	Used in: user-data-constraint
+
+      </xsd:documentation>
+    </xsd:annotation>
+
+    <xsd:simpleContent>
+      <xsd:restriction base="j2ee:string">
+	<xsd:enumeration value="NONE"/>
+	<xsd:enumeration value="INTEGRAL"/>
+	<xsd:enumeration value="CONFIDENTIAL"/>
+      </xsd:restriction>
+    </xsd:simpleContent>
+  </xsd:complexType>
+
+<!-- **************************************************** -->
+
+  <xsd:complexType name="user-data-constraintType">
+    <xsd:annotation>
+      <xsd:documentation>
+
+	The user-data-constraintType is used to indicate how
+	data communicated between the client and container should be
+	protected.
+
+	Used in: security-constraint
+
+      </xsd:documentation>
+    </xsd:annotation>
+
+    <xsd:sequence>
+      <xsd:element name="description"
+		   type="j2ee:descriptionType"
+		   minOccurs="0"
+		   maxOccurs="unbounded"/>
+      <xsd:element name="transport-guarantee"
+		   type="j2ee:transport-guaranteeType"/>
+    </xsd:sequence>
+    <xsd:attribute name="id" type="xsd:ID"/>
+  </xsd:complexType>
+
+<!-- **************************************************** -->
+
+  <xsd:complexType name="war-pathType">
+    <xsd:annotation>
+      <xsd:documentation>
+
+	The elements that use this type designate a path starting
+	with a "/" and interpreted relative to the root of a WAR
+	file.
+
+      </xsd:documentation>
+    </xsd:annotation>
+    <xsd:simpleContent>
+      <xsd:restriction base="j2ee:string">
+	<xsd:pattern value="/.*"/>
+      </xsd:restriction>
+    </xsd:simpleContent>
+  </xsd:complexType>
+
+<!-- **************************************************** -->
+
+  <xsd:simpleType name="web-app-versionType">
+    <xsd:annotation>
+      <xsd:documentation>
+
+	This type contains the recognized versions of
+	web-application supported. It is used to designate the
+	version of the web application.
+
+      </xsd:documentation>
+    </xsd:annotation>
+    <xsd:restriction base="xsd:token">
+      <xsd:enumeration value="2.4"/>
+    </xsd:restriction>
+  </xsd:simpleType>
+
+<!-- **************************************************** -->
+
+  <xsd:complexType name="web-appType">
+
+    <xsd:choice minOccurs="0" maxOccurs="unbounded">
+      <xsd:group ref="j2ee:descriptionGroup"/>
+      <xsd:element name="distributable"
+		   type="j2ee:emptyType"/>
+      <xsd:element name="context-param"
+		   type="j2ee:param-valueType">
+
+	<xsd:annotation>
+	  <xsd:documentation>
+
+	    The context-param element contains the declaration
+	    of a web application's servlet context
+	    initialization parameters.
+
+	  </xsd:documentation>
+	</xsd:annotation>
+      </xsd:element>
+
+      <xsd:element name="filter"
+		   type="j2ee:filterType"/>
+      <xsd:element name="filter-mapping"
+		   type="j2ee:filter-mappingType"/>
+      <xsd:element name="listener"
+		   type="j2ee:listenerType"/>
+      <xsd:element name="servlet"
+		   type="j2ee:servletType"/>
+      <xsd:element name="servlet-mapping"
+		   type="j2ee:servlet-mappingType"/>
+      <xsd:element name="session-config"
+		   type="j2ee:session-configType"/>
+      <xsd:element name="mime-mapping"
+		   type="j2ee:mime-mappingType"/>
+      <xsd:element name="welcome-file-list"
+		   type="j2ee:welcome-file-listType"/>
+      <xsd:element name="error-page"
+		   type="j2ee:error-pageType"/>
+      <xsd:element name="jsp-config"
+		   type="j2ee:jsp-configType"/>
+      <xsd:element name="security-constraint"
+		   type="j2ee:security-constraintType"/>
+      <xsd:element name="login-config"
+		   type="j2ee:login-configType"/>
+      <xsd:element name="security-role"
+		   type="j2ee:security-roleType"/>
+      <xsd:group ref="j2ee:jndiEnvironmentRefsGroup"/>
+      <xsd:element name="message-destination"
+		   type="j2ee:message-destinationType"/>
+      <xsd:element name="locale-encoding-mapping-list"
+		   type="j2ee:locale-encoding-mapping-listType"/>
+    </xsd:choice>
+
+    <xsd:attribute name="version"
+		   type="j2ee:web-app-versionType"
+		   use="required"/>
+    <xsd:attribute name="id" type="xsd:ID"/>
+  </xsd:complexType>
+
+<!-- **************************************************** -->
+
+  <xsd:complexType name="web-resource-collectionType">
+    <xsd:annotation>
+      <xsd:documentation>
+
+	The web-resource-collectionType is used to identify a subset
+	of the resources and HTTP methods on those resources within
+	a web application to which a security constraint applies. If
+	no HTTP methods are specified, then the security constraint
+	applies to all HTTP methods.
+
+	Used in: security-constraint
+
+      </xsd:documentation>
+    </xsd:annotation>
+
+    <xsd:sequence>
+      <xsd:element name="web-resource-name"
+		   type="j2ee:string">
+	<xsd:annotation>
+	  <xsd:documentation>
+
+	    The web-resource-name contains the name of this web
+	    resource collection.
+
+	  </xsd:documentation>
+	</xsd:annotation>
+      </xsd:element>
+      <xsd:element name="description"
+		   type="j2ee:descriptionType"
+		   minOccurs="0"
+		   maxOccurs="unbounded"/>
+      <xsd:element name="url-pattern"
+		   type="j2ee:url-patternType"
+		   maxOccurs="unbounded"/>
+      <xsd:element name="http-method"
+		   type="j2ee:http-methodType"
+		   minOccurs="0" maxOccurs="unbounded"/>
+    </xsd:sequence>
+    <xsd:attribute name="id" type="xsd:ID"/>
+  </xsd:complexType>
+
+<!-- **************************************************** -->
+
+  <xsd:complexType name="welcome-file-listType">
+    <xsd:annotation>
+      <xsd:documentation>
+
+	The welcome-file-list contains an ordered list of welcome
+	files elements.
+
+	Used in: web-app
+
+      </xsd:documentation>
+    </xsd:annotation>
+
+    <xsd:sequence>
+      <xsd:element name="welcome-file"
+		   type="xsd:string"
+		   maxOccurs="unbounded">
+	<xsd:annotation>
+	  <xsd:documentation>
+
+	    The welcome-file element contains file name to use
+	    as a default welcome file, such as index.html
+
+	  </xsd:documentation>
+	</xsd:annotation>
+      </xsd:element>
+    </xsd:sequence>
+    <xsd:attribute name="id" type="xsd:ID"/>
+  </xsd:complexType>
+
+</xsd:schema>
+

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/dtd/web-jsptaglibrary_1_1.dtd
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/dtd/web-jsptaglibrary_1_1.dtd	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/dtd/web-jsptaglibrary_1_1.dtd	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,206 @@
+<!--
+  Copyright 2004 The Apache Software Foundation
+
+  Licensed 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.
+-->
+<!--
+
+   This is the DTD defining the JavaServer Pages 1.1 Tag Library
+   descriptor (.tld) (XML) file format/syntax.
+
+   A Tag Library is a JAR file containing a valid instance of a Tag Library
+   Descriptor (taglib.tld) file in the META-INF subdirectory, along with the
+   appropriate implementing classes, and other resources required to
+   implement the tags defined therein.
+
+   Use is subject to license terms.
+  -->
+
+<!--
+The taglib tag is the document root, it defines:
+
+tlibversion	the version of the tag library implementation
+jspversion	the version of JSP the tag library depends upon
+
+shortname	a simple default short name that could be used by
+		a JSP authoring tool to create names with a mnemonic
+		value; for example, the it may be used as the prefered
+		prefix value in taglib directives
+uri		a uri uniquely identifying this taglib
+info		a simple string describing the "use" of this taglib,
+		should be user discernable
+-->
+
+<!ELEMENT taglib (tlibversion, jspversion?, shortname, uri?, info?, tag+) >
+<!ATTLIST taglib id ID #IMPLIED
+	  xmlns CDATA #FIXED
+		"http://java.sun.com/j2ee/dtds/web-jsptaglibrary_1_1.dtd"
+>
+
+<!--
+Describes this version (number) of the taglibrary (dewey decimal)
+
+#PCDATA ::= [0-9]*{ "."[0-9] }0..3
+-->
+
+<!ELEMENT tlibversion (#PCDATA) >
+
+<!--
+Describes the JSP version (number) this taglibrary requires in
+order to function (dewey decimal)
+
+The default is 1.1
+
+#PCDATA ::= [0-9]*{ "."[0-9] }0..3
+-->
+
+<!ELEMENT jspversion  (#PCDATA) >
+
+<!--
+Defines a short (default) shortname to be used for tags and
+variable names used/created by this tag library.  Do not use
+white space, and do not start with digits or underscore.
+
+#PCDATA ::= NMTOKEN
+-->
+
+<!ELEMENT shortname      (#PCDATA) >
+
+<!--
+Defines a public URI that uniquely identifies this version of
+the taglibrary Leave it empty if it does not apply.
+-->
+
+<!ELEMENT uri	 (#PCDATA) >
+
+<!--
+Defines an arbitrary text string descirbing the tag library
+-->
+
+<!ELEMENT info	(#PCDATA) >
+
+<!--
+The tag defines a unique tag in this tag library, defining:
+
+- the unique tag/element name
+- the subclass of javax.servlet.jsp.tagext.Tag implementation class
+- an optional subclass of javax.servlet.jsp.tagext.TagExtraInfo
+- the body content type (hint)
+- optional tag-specific information
+- any attributes
+-->
+
+<!ELEMENT tag (name, tagclass, teiclass?, bodycontent?, info?, attribute*) >
+
+<!--
+Defines the subclass of javax.serlvet.jsp.tagext.Tag that implements
+the request time semantics for this tag. (required)
+
+#PCDATA ::= fully qualified Java class name
+-->
+
+<!ELEMENT tagclass (#PCDATA) >
+
+<!--
+Defines the subclass of javax.servlet.jsp.tagext.TagExtraInfo for
+this tag. (optional)
+
+If this is not given, the class is not consulted at translation time.
+
+#PCDATA ::= fully qualified Java class name
+-->
+
+<!ELEMENT teiclass (#PCDATA) >
+
+<!--
+Provides a hint as to the content of the body of this tag. Primarily
+intended for use by page composition tools.
+
+There are currently three values specified:
+
+tagdependent	The body of the tag is interpreted by the tag
+		implementation itself, and is most likely in a
+		different "langage", e.g embedded SQL statements.
+
+JSP		The body of the tag contains nested JSP syntax
+
+empty		The body must be empty
+
+The default (if not defined) is JSP
+
+#PCDATA ::=  tagdependent | JSP | empty
+
+-->
+
+<!ELEMENT bodycontent (#PCDATA) >
+
+<!--
+The attribute tag defines an attribute for the nesting tag
+
+An attribute definition is composed of:
+
+- the attributes name (required)
+- if the attribute is required or optional (optional)
+- if the attributes value may be dynamically calculated at runtime
+  by a scriptlet expression (optional)
+
+-->
+
+<!ELEMENT attribute (name, required? , rtexprvalue?) >
+
+<!--
+Defines the canonical name of a tag or attribute being defined
+
+#PCDATA ::= NMTOKEN
+-->
+
+<!ELEMENT name	(#PCDATA) >
+
+<!--
+Defines if the nesting attribute is required or optional.
+
+#PCDATA ::= true | false | yes | no
+
+If not present then the default is "false", i.e the attribute
+is optional.
+-->
+
+<!ELEMENT required    (#PCDATA) >
+
+<!--
+Defines if the nesting attribute can have scriptlet expressions as
+a value, i.e the value of the attribute may be dynamically calculated
+at request time, as opposed to a static value determined at translation
+time.
+
+#PCDATA ::= true | false | yes | no
+
+If not present then the default is "false", i.e the attribute
+has a static value
+-->
+
+<!ELEMENT rtexprvalue (#PCDATA) >
+
+<!ATTLIST tlibversion id ID #IMPLIED>
+<!ATTLIST jspversion id ID #IMPLIED>
+<!ATTLIST shortname id ID #IMPLIED>
+<!ATTLIST uri id ID #IMPLIED>
+<!ATTLIST info id ID #IMPLIED>
+<!ATTLIST tag id ID #IMPLIED>
+<!ATTLIST tagclass id ID #IMPLIED>
+<!ATTLIST teiclass id ID #IMPLIED>
+<!ATTLIST bodycontent id ID #IMPLIED>
+<!ATTLIST attribute id ID #IMPLIED>
+<!ATTLIST name id ID #IMPLIED>
+<!ATTLIST required id ID #IMPLIED>
+<!ATTLIST rtexprvalue id ID #IMPLIED>

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/dtd/web-jsptaglibrary_1_2.dtd
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/dtd/web-jsptaglibrary_1_2.dtd	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/dtd/web-jsptaglibrary_1_2.dtd	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,477 @@
+<!--
+  Copyright 2004 The Apache Software Foundation
+
+  Licensed 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.
+-->
+<!--
+
+   This is the DTD defining the JavaServer Pages 1.2 Tag Library
+   descriptor (.tld) (XML) file format/syntax.
+
+   A Tag Library is a JAR file containing a valid instance of a Tag Library
+   Descriptor (taglib.tld) file in the META-INF subdirectory, along with the
+   appropriate implementing classes, and other resources required to
+   implement the tags defined therein.
+
+   Use is subject to license terms.
+  -->
+
+<!NOTATION WEB-JSPTAGLIB.1_2 PUBLIC
+          "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN">
+
+<!--
+This is the XML DTD for the JSP 1.2 Tag Library Descriptor.
+All JSP 1.2 tag library descriptors must include a DOCTYPE
+of the following form:
+
+  <!DOCTYPE taglib
+        PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN"
+	"http://java.sun.com/dtd/web-jsptaglibrary_1_2.dtd">
+
+-->
+
+<!--
+The taglib tag is the document root, it defines:
+
+tlib-version	the version of the tag library implementation
+
+jsp-version	the version of JSP the tag library depends upon
+
+short-name	a simple default short name that could be used by
+		a JSP authoring tool to create names with a mnemonic
+		value; for example, the it may be used as the prefered
+		prefix value in taglib directives
+
+uri		a uri uniquely identifying this taglib
+
+display-name    the display-name element contains a short name that
+                is intended to be displayed by tools
+small-icon      optional small-icon that can be used by tools
+
+large-icon      optional large-icon that can be used by tools
+
+description	a simple string describing the "use" of this taglib,
+		should be user discernable
+
+validator       optional TagLibraryValidator information
+
+listener        optional event listener specification
+
+
+-->
+
+<!ELEMENT taglib (tlib-version, jsp-version, short-name, uri?,
+                  display-name?, small-icon?, large-icon?, description?,
+                  validator?, listener*, tag+) >
+
+<!ATTLIST taglib id ID #IMPLIED
+	  xmlns CDATA #FIXED
+		"http://java.sun.com/JSP/TagLibraryDescriptor"
+>
+
+<!--
+Describes this version (number) of the taglibrary (dewey decimal)
+
+#PCDATA ::= [0-9]*{ "."[0-9] }0..3
+-->
+
+<!ELEMENT tlib-version (#PCDATA) >
+
+<!--
+Describes the JSP version (number) this taglibrary requires in
+order to function (dewey decimal)
+
+The default is 1.2
+
+#PCDATA ::= [0-9]*{ "."[0-9] }0..3
+-->
+
+<!ELEMENT jsp-version  (#PCDATA) >
+
+<!--
+Defines a short (default) short-name to be used for tags and
+variable names used/created by this tag library.  Do not use
+white space, and do not start with digits or underscore.
+
+#PCDATA ::= NMTOKEN
+-->
+
+<!ELEMENT short-name      (#PCDATA) >
+
+<!--
+Defines a public URI that uniquely identifies this version of
+the taglibrary.  Leave it empty if it does not apply.
+-->
+
+<!ELEMENT uri	 (#PCDATA) >
+
+<!--
+Defines an arbitrary text string descirbing the tag library
+-->
+
+<!ELEMENT description	(#PCDATA) >
+
+<!--
+
+Defines an optional validator that can be used to
+validate the conformance of a JSP page to using this tag library.
+-->
+
+<!ELEMENT validator (validator-class, init-param*, description?) >
+
+
+<!--
+
+Defines the TagLibraryValidator class that can be used to
+validate the conformance of a JSP page to using this tag library.
+-->
+
+<!ELEMENT validator-class (#PCDATA) >
+
+
+<!--
+
+The init-param element contains a name/value pair as an
+initialization param
+-->
+
+<!ELEMENT init-param (param-name, param-value, description?)>
+
+<!--
+
+The param-name element contains the name of a parameter.
+-->
+
+<!ELEMENT param-name (#PCDATA)>
+
+<!--
+
+The param-value element contains the value of a parameter.
+-->
+
+<!ELEMENT param-value (#PCDATA)>
+
+
+<!--
+
+Defines an optional event listener object to be instantiated and
+registered automatically.
+-->
+
+<!ELEMENT listener (listener-class) >
+
+<!--
+
+The listener-class element declares a class in the application that
+must be registered as a web application listener bean.  See the
+Servlet 2.3 specification for details.
+-->
+
+<!ELEMENT listener-class (#PCDATA) >
+
+
+<!--
+The tag defines a unique tag in this tag library.  It has one
+attribute, id.
+
+The tag element may have several subelements defining:
+
+name              The unique action name
+
+tag-class         The tag handler class implementing
+                  javax.servlet.jsp.tagext.Tag
+
+tei-class         An optional subclass of
+                  javax.servlet.jsp.tagext.TagExtraInfo
+
+body-content      The body content type
+
+display-name      A short name that is intended to be displayed
+                  by tools
+
+small-icon        Optional small-icon that can be used by tools
+
+large-icon        Optional large-icon that can be used by tools
+
+description       Optional tag-specific information
+
+variable          Optional scripting variable information
+
+attribute         All attributes of this action
+
+example           Optional informal description of an example of a
+                  use of this tag
+
+-->
+
+<!ELEMENT tag (name, tag-class, tei-class?, body-content?, display-name?,
+               small-icon?, large-icon?, description?, variable*, attribute*,
+               example?) >
+
+<!--
+Defines the subclass of javax.serlvet.jsp.tagext.Tag that implements
+the request time semantics for this tag. (required)
+
+#PCDATA ::= fully qualified Java class name
+-->
+
+<!ELEMENT tag-class (#PCDATA) >
+
+<!--
+Defines the subclass of javax.servlet.jsp.tagext.TagExtraInfo for
+this tag. (optional)
+
+If this is not given, the class is not consulted at translation time.
+
+#PCDATA ::= fully qualified Java class name
+-->
+
+<!ELEMENT tei-class (#PCDATA) >
+
+<!--
+Provides a hint as to the content of the body of this tag. Primarily
+intended for use by page composition tools.
+
+There are currently three values specified:
+
+tagdependent	The body of the tag is interpreted by the tag
+		implementation itself, and is most likely in a
+		different "langage", e.g embedded SQL statements.
+
+JSP		The body of the tag contains nested JSP syntax
+
+empty		The body must be empty
+
+The default (if not defined) is JSP
+
+#PCDATA ::=  tagdependent | JSP | empty
+
+-->
+
+<!ELEMENT body-content (#PCDATA) >
+
+<!--
+
+The display-name element contains a short name that is intended
+to be displayed by tools.
+-->
+
+<!ELEMENT display-name (#PCDATA) >
+
+
+<!--
+
+The large-icon element contains the name of a file containing a large
+(32 x 32) icon image.  The file name is a relative path within the
+tag library.  The image must be either in the JPEG or GIF format, and
+the file name must end with the suffix ".jpg" or ".gif" respectively.
+The icon can be used by tools.
+-->
+
+<!ELEMENT large-icon (#PCDATA) >
+
+<!--
+
+The small-icon element contains the name of a file containing a large
+(32 x 32) icon image.  The file name is a relative path within the
+tag library.  The image must be either in the JPEG or GIF format, and
+the file name must end with the suffix ".jpg" or ".gif" respectively.
+The icon can be used by tools.
+-->
+
+<!ELEMENT small-icon (#PCDATA) >
+
+<!--
+
+The example element contains an informal description of an example
+of the use of a tag.
+-->
+
+<!ELEMENT example (#PCDATA) >
+
+<!--
+
+The variable tag provides information on the scripting variables
+defined by this tag.  It is a (translation time) error for a tag
+that has one or more variable subelements to have a TagExtraInfo
+class that returns a non-null object.
+
+The subelements of variable are of the form:
+
+name-given               The variable name as a constant
+
+name-from-attribute      The name of an attribute whose (translation
+                         time) value will give the name of the
+                         variable.  One of name-given or
+                         name-from-attribute is required.
+
+variable-class           Name of the class of the variable.
+                         java.lang.String is default.
+
+declare                  Whether the variable is declared or not.
+                         True is the default.
+
+scope                    The scope of the scripting varaible
+                         defined.  NESTED is default.
+
+description              Optional description of this variable
+
+-->
+
+<!ELEMENT variable ( (name-given | name-from-attribute), variable-class?,
+                    declare?, scope?, description?) >
+
+<!--
+
+The name for the scripting variable.  One of name-given or
+name-from-attribute is required.
+-->
+
+<!ELEMENT name-given (#PCDATA) >
+
+<!--
+
+The name of an attribute whose (translation-time) value will give
+the name of the variable.  One of name-given or name-from-attribute
+is required.
+-->
+
+<!ELEMENT name-from-attribute (#PCDATA) >
+
+<!--
+
+The optional name of the class for the scripting variable.  The
+default is java.lang.String.
+-->
+
+<!ELEMENT variable-class (#PCDATA) >
+
+<!--
+
+Whether the scripting variable is to be defined or not.  See
+TagExtraInfo for details.  This element is optional and "true"
+is the default.
+-->
+
+<!ELEMENT declare (#PCDATA) >
+
+<!--
+
+The scope of the scripting variable.  See TagExtraInfo for details.
+The element is optional and "NESTED" is the default.  Other legal
+values are "AT_BEGIN" and "AT_END".
+-->
+
+<!ELEMENT scope (#PCDATA) >
+
+<!--
+
+The attribute tag defines an attribute for the nesting tag
+
+An attribute definition is composed of:
+	
+- the attributes name (required)
+- if the attribute is required or optional (optional)
+- if the attributes value may be dynamically calculated at runtime
+  by a scriptlet expression (optional)
+- the type of the attributes value (optional)
+- an informal description of the meaning of the attribute (optional)
+
+-->
+
+
+<!--
+The attribute tag defines an attribute for the nesting tag
+
+An attribute definition is composed of:
+
+- the attributes name (required)
+
+- if the attribute is required or optional (optional)
+
+- if the attributes value may be dynamically calculated at runtime
+  by a scriptlet expression (optional)
+
+- the type of the attributes value (optional)
+
+- an informal description of the meaning of the attribute (optional)
+-->
+
+<!ELEMENT attribute (name, required? , rtexprvalue?, type?, description?) >
+
+<!--
+Defines the canonical name of a tag or attribute being defined
+
+#PCDATA ::= NMTOKEN
+-->
+
+<!ELEMENT name	(#PCDATA) >
+
+<!--
+Defines if the nesting attribute is required or optional.
+
+#PCDATA ::= true | false | yes | no
+
+If not present then the default is "false", i.e the attribute
+is optional.
+-->
+
+<!ELEMENT required    (#PCDATA) >
+
+<!--
+Defines if the nesting attribute can have scriptlet expressions as
+a value, i.e the value of the attribute may be dynamically calculated
+at request time, as opposed to a static value determined at translation
+time.
+
+#PCDATA ::= true | false | yes | no
+
+If not present then the default is "false", i.e the attribute
+has a static value
+-->
+
+<!ELEMENT rtexprvalue (#PCDATA) >
+
+
+<!--
+
+Defines the Java type of the attributes value.  For static values
+(those determined at translation time) the type is always
+java.lang.String.
+-->
+
+<!ELEMENT type (#PCDATA) >
+
+
+<!-- ID attributes -->
+
+<!ATTLIST tlib-version id ID #IMPLIED>
+<!ATTLIST jsp-version id ID #IMPLIED>
+<!ATTLIST short-name id ID #IMPLIED>
+<!ATTLIST uri id ID #IMPLIED>
+<!ATTLIST description id ID #IMPLIED>
+<!ATTLIST example id ID #IMPLIED>
+<!ATTLIST tag id ID #IMPLIED>
+<!ATTLIST tag-class id ID #IMPLIED>
+<!ATTLIST tei-class id ID #IMPLIED>
+<!ATTLIST body-content id ID #IMPLIED>
+<!ATTLIST attribute id ID #IMPLIED>
+<!ATTLIST name id ID #IMPLIED>
+<!ATTLIST required id ID #IMPLIED>
+<!ATTLIST rtexprvalue id ID #IMPLIED>
+
+
+<!ATTLIST param-name id ID #IMPLIED>
+<!ATTLIST param-value id ID #IMPLIED>
+<!ATTLIST listener id ID #IMPLIED>
+<!ATTLIST listener-class id ID #IMPLIED>

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/dtd/web-jsptaglibrary_2_0.xsd
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/dtd/web-jsptaglibrary_2_0.xsd	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/dtd/web-jsptaglibrary_2_0.xsd	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,1023 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Copyright 2004 The Apache Software Foundation
+
+  Licensed 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.
+-->
+<xsd:schema
+     targetNamespace="http://java.sun.com/xml/ns/j2ee"
+     xmlns:j2ee="http://java.sun.com/xml/ns/j2ee"
+     xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+     xmlns:xml="http://www.w3.org/XML/1998/namespace"
+     elementFormDefault="qualified"
+     attributeFormDefault="unqualified"
+     version="2.0">
+
+  <xsd:annotation>
+    <xsd:documentation>
+      %W% %G%
+    </xsd:documentation>
+  </xsd:annotation>
+  <xsd:annotation>
+    <xsd:documentation>
+
+      Copyright 2002 Sun Microsystems, Inc., 901 San Antonio
+      Road, Palo Alto, California 94303, U.S.A. All rights
+      reserved.
+
+      Sun Microsystems, Inc. has intellectual property rights
+      relating to technology described in this document. In
+      particular, and without limitation, these intellectual
+      property rights may include one or more of the U.S. patents
+      listed at http://www.sun.com/patents and one or more
+      additional patents or pending patent applications in the
+      U.S. and other countries.
+
+      This document and the technology which it describes are
+      distributed under licenses restricting their use, copying,
+      distribution, and decompilation. No part of this document
+      may be reproduced in any form by any means without prior
+      written authorization of Sun and its licensors, if any.
+
+      Third-party software, including font technology, is
+      copyrighted and licensed from Sun suppliers.
+
+      Sun, Sun Microsystems, the Sun logo, Solaris, Java, J2EE,
+      JavaServer Pages, Enterprise JavaBeans and the Java Coffee
+      Cup logo are trademarks or registered trademarks of Sun
+      Microsystems, Inc. in the U.S. and other countries.
+
+      Federal Acquisitions: Commercial Software - Government Users
+      Subject to Standard License Terms and Conditions.
+
+    </xsd:documentation>
+  </xsd:annotation>
+
+  <xsd:annotation>
+    <xsd:documentation>
+      <![CDATA[
+
+	This is the XML Schema for the JSP Taglibrary
+	descriptor.  All Taglibrary descriptors must
+	indicate the tag library schema by using the Taglibrary
+	namespace:
+
+	http://java.sun.com/xml/ns/j2ee
+
+	and by indicating the version of the schema by
+	using the version element as shown below:
+
+	    <taglib xmlns="http://java.sun.com/xml/ns/j2ee"
+	      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	      xsi:schemaLocation="..."
+	      version="2.0">
+	      ...
+	    </taglib>
+
+	The instance documents may indicate the published
+	version of the schema using xsi:schemaLocation attribute
+	for J2EE namespace with the following location:
+
+	http://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd
+
+	]]>
+    </xsd:documentation>
+  </xsd:annotation>
+
+  <xsd:include schemaLocation="j2ee_1_4.xsd"/>
+
+
+<!-- **************************************************** -->
+
+
+  <xsd:element name="taglib" type="j2ee:tldTaglibType">
+    <xsd:annotation>
+      <xsd:documentation>
+
+	The taglib tag is the document root.
+	The definition of taglib is provided
+	by the tldTaglibType.
+
+      </xsd:documentation>
+    </xsd:annotation>
+    <xsd:unique name="tag-name-uniqueness">
+      <xsd:annotation>
+	<xsd:documentation>
+
+	  The taglib element contains, among other things, tag and
+	  tag-file elements.
+	  The name subelements of these elements must each be unique.
+
+	</xsd:documentation>
+      </xsd:annotation>
+      <xsd:selector xpath="j2ee:tag|j2ee:tag-file"/>
+      <xsd:field    xpath="j2ee:name"/>
+    </xsd:unique>
+
+    <xsd:unique name="function-name-uniqueness">
+      <xsd:annotation>
+	<xsd:documentation>
+
+	  The taglib element contains function elements.
+	  The name subelements of these elements must each be unique.
+
+	</xsd:documentation>
+      </xsd:annotation>
+      <xsd:selector xpath="j2ee:function"/>
+      <xsd:field    xpath="j2ee:name"/>
+    </xsd:unique>
+
+  </xsd:element>
+
+
+<!-- **************************************************** -->
+
+  <xsd:complexType name="body-contentType">
+    <xsd:annotation>
+      <xsd:documentation>
+
+        Specifies the type of body that is valid for a tag.
+	This value is used by the JSP container to validate
+	that a tag invocation has the correct body syntax and
+	by page composition tools to assist the page author
+	in providing a valid tag body.
+
+	There are currently four values specified:
+
+	tagdependent    The body of the tag is interpreted by the tag
+			implementation itself, and is most likely
+			in a different "language", e.g embedded SQL
+			statements.
+
+	JSP             The body of the tag contains nested JSP
+			syntax.
+
+	empty           The body must be empty
+
+	scriptless      The body accepts only template text, EL
+			Expressions, and JSP action elements.  No
+			scripting elements are allowed.
+
+      </xsd:documentation>
+    </xsd:annotation>
+
+    <xsd:simpleContent>
+      <xsd:restriction base="j2ee:string">
+	<xsd:enumeration value="tagdependent"/>
+	<xsd:enumeration value="JSP"/>
+	<xsd:enumeration value="empty"/>
+	<xsd:enumeration value="scriptless"/>
+      </xsd:restriction>
+    </xsd:simpleContent>
+  </xsd:complexType>
+
+<!-- **************************************************** -->
+
+  <xsd:complexType name="extensibleType" abstract="true">
+    <xsd:annotation>
+      <xsd:documentation>
+
+	The extensibleType is an abstract base type that is used to
+	define the type of extension-elements. Instance documents
+	must substitute a known type to define the extension by
+	using xsi:type attribute to define the actual type of
+	extension-elements.
+
+      </xsd:documentation>
+    </xsd:annotation>
+    <xsd:attribute name="id" type="xsd:ID"/>
+  </xsd:complexType>
+
+<!-- **************************************************** -->
+
+  <xsd:complexType name="functionType">
+    <xsd:annotation>
+      <xsd:documentation>
+
+	The function element is used to provide information on each
+	function in the tag library that is to be exposed to the EL.
+
+	The function element may have several subelements defining:
+
+	description         Optional tag-specific information
+
+	display-name        A short name that is intended to be
+			    displayed by tools
+
+	icon                Optional icon element that can be used
+			    by tools
+
+	name                A unique name for this function
+
+	function-class      Provides the name of the Java class that
+			    implements the function
+
+	function-signature  Provides the signature, as in the Java
+			    Language Specification, of the Java
+			    method that is to be used to implement
+			    the function.
+
+	example             Optional informal description of an
+			    example of a use of this function
+
+	function-extension  Zero or more extensions that provide extra
+			    information about this function, for tool
+			    consumption
+
+      </xsd:documentation>
+    </xsd:annotation>
+
+    <xsd:sequence>
+      <xsd:group ref="j2ee:descriptionGroup"/>
+      <xsd:element name="name"
+		   type="j2ee:tld-canonical-nameType">
+	<xsd:annotation>
+	  <xsd:documentation>
+
+	    A unique name for this function.
+
+	  </xsd:documentation>
+	</xsd:annotation>
+      </xsd:element>
+      <xsd:element name="function-class"
+		   type="j2ee:fully-qualified-classType">
+	<xsd:annotation>
+	  <xsd:documentation>
+
+	    Provides the fully-qualified class name of the Java
+	    class containing the static method that implements
+	    the function.
+
+	  </xsd:documentation>
+	</xsd:annotation>
+
+      </xsd:element>
+      <xsd:element name="function-signature"
+		   type="j2ee:string">
+	<xsd:annotation>
+	  <xsd:documentation>
+
+	    Provides the signature, of the static Java method that is
+	    to be used to implement the function.  The syntax of the
+	    function-signature element is as follows:
+
+		FunctionSignature ::= ReturnType S MethodName S?
+				      '(' S? Parameters? S? ')'
+
+                ReturnType        ::= Type
+
+		MethodName        ::= Identifier
+
+		Parameters        ::=   Parameter
+				      | ( Parameter S? ',' S? Parameters )
+
+                Parameter         ::= Type
+
+		Where:
+
+ 		    * Type is a basic type or a fully qualified Java class name
+		      (including package name), as per the 'Type' production
+		      in the Java Language Specification, Second Edition,
+		      Chapter 18.
+
+                    * Identifier is a Java identifier, as per the 'Identifier'
+		      production in the Java Language Specification, Second
+		      Edition, Chapter 18.
+
+	    Example:
+
+	    java.lang.String nickName( java.lang.String, int )
+
+	  </xsd:documentation>
+	</xsd:annotation>
+
+      </xsd:element>
+      <xsd:element name="example"
+		   type="j2ee:xsdStringType"
+		   minOccurs="0">
+	<xsd:annotation>
+	  <xsd:documentation>
+
+	    The example element contains an informal description
+	    of an example of the use of this function.
+
+	  </xsd:documentation>
+	</xsd:annotation>
+
+      </xsd:element>
+      <xsd:element name="function-extension"
+		   type="j2ee:tld-extensionType"
+		   minOccurs="0"
+		   maxOccurs="unbounded">
+	<xsd:annotation>
+	  <xsd:documentation>
+
+	    Function extensions are for tool use only and must not affect
+	    the behavior of a container.
+
+	  </xsd:documentation>
+	</xsd:annotation>
+      </xsd:element>
+    </xsd:sequence>
+    <xsd:attribute name="id" type="xsd:ID"/>
+  </xsd:complexType>
+
+<!-- **************************************************** -->
+
+  <xsd:complexType name="tagFileType">
+    <xsd:annotation>
+      <xsd:documentation>
+
+	Defines an action in this tag library that is implemented
+	as a .tag file.
+
+	The tag-file element has two required subelements:
+
+	description       Optional tag-specific information
+
+	display-name      A short name that is intended to be
+			  displayed by tools
+
+	icon              Optional icon element that can be used
+			  by tools
+
+	name              The unique action name
+
+	path              Where to find the .tag file implementing this
+			  action, relative to the root of the web
+			  application or the root of the JAR file for a
+			  tag library packaged in a JAR.  This must
+			  begin with /WEB-INF/tags if the .tag file
+			  resides in the WAR, or /META-INF/tags if the
+			  .tag file resides in a JAR.
+
+	example           Optional informal description of an
+			  example of a use of this tag
+
+	tag-extension     Zero or more extensions that provide extra
+			  information about this tag, for tool
+			  consumption
+
+      </xsd:documentation>
+    </xsd:annotation>
+
+    <xsd:sequence>
+      <xsd:group ref="j2ee:descriptionGroup"/>
+      <xsd:element name="name"
+		   type="j2ee:tld-canonical-nameType"/>
+      <xsd:element name="path"
+		   type="j2ee:pathType"/>
+      <xsd:element name="example"
+		   type="j2ee:xsdStringType"
+		   minOccurs="0">
+	<xsd:annotation>
+	  <xsd:documentation>
+
+	    The example element contains an informal description
+	    of an example of the use of a tag.
+
+	  </xsd:documentation>
+	</xsd:annotation>
+
+      </xsd:element>
+      <xsd:element name="tag-extension"
+		   type="j2ee:tld-extensionType"
+		   minOccurs="0"
+		   maxOccurs="unbounded">
+	<xsd:annotation>
+	  <xsd:documentation>
+
+	    Tag extensions are for tool use only and must not affect
+	    the behavior of a container.
+
+	  </xsd:documentation>
+	</xsd:annotation>
+      </xsd:element>
+    </xsd:sequence>
+    <xsd:attribute name="id" type="xsd:ID"/>
+  </xsd:complexType>
+
+<!-- **************************************************** -->
+
+  <xsd:complexType name="tagType">
+    <xsd:annotation>
+      <xsd:documentation>
+
+	The tag defines a unique tag in this tag library.  It has one
+	attribute, id.
+
+	The tag element may have several subelements defining:
+
+	description       Optional tag-specific information
+
+	display-name      A short name that is intended to be
+			  displayed by tools
+
+	icon              Optional icon element that can be used
+			  by tools
+
+	name              The unique action name
+
+	tag-class         The tag handler class implementing
+			  javax.servlet.jsp.tagext.JspTag
+
+	tei-class         An optional subclass of
+			  javax.servlet.jsp.tagext.TagExtraInfo
+
+	body-content      The body content type
+
+	variable          Optional scripting variable information
+
+	attribute         All attributes of this action that are
+			  evaluated prior to invocation.
+
+	dynamic-attributes Whether this tag supports additional
+			   attributes with dynamic names.  If
+			   true, the tag-class must implement the
+			   javax.servlet.jsp.tagext.DynamicAttributes
+			   interface.  Defaults to false.
+
+	example           Optional informal description of an
+			  example of a use of this tag
+
+	tag-extension     Zero or more extensions that provide extra
+			  information about this tag, for tool
+			  consumption
+
+      </xsd:documentation>
+    </xsd:annotation>
+
+    <xsd:sequence>
+      <xsd:group ref="j2ee:descriptionGroup"/>
+      <xsd:element name="name"
+		   type="j2ee:tld-canonical-nameType"/>
+      <xsd:element name="tag-class"
+		   type="j2ee:fully-qualified-classType">
+	<xsd:annotation>
+	  <xsd:documentation>
+
+	    Defines the subclass of javax.serlvet.jsp.tagext.JspTag
+	    that implements the request time semantics for
+	    this tag. (required)
+
+	  </xsd:documentation>
+	</xsd:annotation>
+
+      </xsd:element>
+      <xsd:element name="tei-class"
+		   type="j2ee:fully-qualified-classType"
+		   minOccurs="0">
+	<xsd:annotation>
+	  <xsd:documentation>
+
+	    Defines the subclass of javax.servlet.jsp.tagext.TagExtraInfo
+	    for this tag. (optional)
+
+	    If this is not given, the class is not consulted at
+	    translation time.
+
+	  </xsd:documentation>
+	</xsd:annotation>
+      </xsd:element>
+      <xsd:element name="body-content"
+		   type="j2ee:body-contentType">
+	<xsd:annotation>
+	  <xsd:documentation>
+
+	    Specifies the format for the body of this tag.
+	    The default in JSP 1.2 was "JSP" but because this
+	    is an invalid setting for simple tag handlers, there
+	    is no longer a default in JSP 2.0.  A reasonable
+	    default for simple tag handlers is "scriptless" if
+	    the tag can have a body.
+
+	  </xsd:documentation>
+	</xsd:annotation>
+      </xsd:element>
+      <xsd:element name="variable"
+		   type="j2ee:variableType"
+		   minOccurs="0" maxOccurs="unbounded"/>
+      <xsd:element name="attribute"
+		   type="j2ee:tld-attributeType"
+		   minOccurs="0" maxOccurs="unbounded"/>
+      <xsd:element name="dynamic-attributes"
+		   type="j2ee:generic-booleanType"
+		   minOccurs="0"/>
+      <xsd:element name="example"
+		   type="j2ee:xsdStringType"
+		   minOccurs="0">
+	<xsd:annotation>
+	  <xsd:documentation>
+
+	    The example element contains an informal description
+	    of an example of the use of a tag.
+
+	  </xsd:documentation>
+	</xsd:annotation>
+
+      </xsd:element>
+      <xsd:element name="tag-extension"
+		   type="j2ee:tld-extensionType"
+		   minOccurs="0"
+		   maxOccurs="unbounded">
+	<xsd:annotation>
+	  <xsd:documentation>
+
+	    Tag extensions are for tool use only and must not affect
+	    the behavior of a container.
+
+	  </xsd:documentation>
+	</xsd:annotation>
+      </xsd:element>
+    </xsd:sequence>
+    <xsd:attribute name="id" type="xsd:ID"/>
+  </xsd:complexType>
+
+<!-- **************************************************** -->
+
+  <xsd:complexType name="tld-attributeType">
+    <xsd:annotation>
+      <xsd:documentation>
+
+	The attribute element defines an attribute for the nesting
+	tag.  The attributre element may have several subelements
+	defining:
+
+	description     a description of the attribute
+
+	name            the name of the attribute
+
+	required        whether the attribute is required or
+			optional
+
+	rtexprvalue     whether the attribute is a runtime attribute
+
+	type            the type of the attributes
+
+	fragment        whether this attribute is a fragment
+
+      </xsd:documentation>
+    </xsd:annotation>
+    <xsd:sequence>
+      <xsd:element name="description"
+		   type="j2ee:descriptionType"
+		   minOccurs="0" maxOccurs="unbounded"/>
+      <xsd:element name="name"
+		   type="j2ee:java-identifierType"/>
+      <xsd:element name="required"
+		   type="j2ee:generic-booleanType"
+		   minOccurs="0">
+	<xsd:annotation>
+	  <xsd:documentation>
+
+	    Defines if the nesting attribute is required or
+	    optional.
+
+	    If not present then the default is "false", i.e
+	    the attribute is optional.
+
+	  </xsd:documentation>
+	</xsd:annotation>
+      </xsd:element>
+
+      <xsd:choice>
+	<xsd:sequence>
+	  <xsd:element name="rtexprvalue"
+		       type="j2ee:generic-booleanType"
+		       minOccurs="0">
+	    <xsd:annotation>
+	      <xsd:documentation>
+
+		Defines if the nesting attribute can have scriptlet
+		expressions as a value, i.e the value of the
+		attribute may be dynamically calculated at request
+		time, as opposed to a static value determined at
+		translation time.
+
+		If not present then the default is "false", i.e the
+		attribute has a static value
+
+	      </xsd:documentation>
+	    </xsd:annotation>
+
+	  </xsd:element>
+	  <xsd:element name="type"
+		       type="j2ee:fully-qualified-classType"
+		       minOccurs="0">
+	    <xsd:annotation>
+	      <xsd:documentation>
+
+		Defines the Java type of the attributes value.  For
+		static values (those determined at translation time)
+		the type is always java.lang.String.
+
+	      </xsd:documentation>
+	    </xsd:annotation>
+	  </xsd:element>
+	</xsd:sequence>
+	<xsd:element name="fragment"
+		     type="j2ee:generic-booleanType"
+		     minOccurs="0">
+	  <xsd:annotation>
+	    <xsd:documentation>
+
+	      "true" if this attribute is of type
+	      javax.jsp.tagext.JspFragment, representing dynamic
+	      content that can be re-evaluated as many times
+	      as needed by the tag handler.  If omitted or "false",
+	      the default is still type="java.lang.String"
+
+	    </xsd:documentation>
+	  </xsd:annotation>
+	</xsd:element>
+      </xsd:choice>
+    </xsd:sequence>
+    <xsd:attribute name="id" type="xsd:ID"/>
+  </xsd:complexType>
+
+<!-- **************************************************** -->
+
+  <xsd:complexType name="tld-canonical-nameType">
+
+    <xsd:annotation>
+      <xsd:documentation>
+
+	Defines the canonical name of a tag or attribute being
+	defined.
+
+	The name must conform to the lexical rules for an NMTOKEN.
+
+      </xsd:documentation>
+    </xsd:annotation>
+
+    <xsd:simpleContent>
+      <xsd:restriction base="j2ee:xsdNMTOKENType"/>
+    </xsd:simpleContent>
+  </xsd:complexType>
+
+<!-- **************************************************** -->
+
+  <xsd:complexType name="tld-extensionType">
+    <xsd:annotation>
+      <xsd:documentation>
+
+	The tld-extensionType is used to indicate
+	extensions to a specific TLD element.
+
+	It is used by elements to designate an extension block
+	that is targeted to a specific extension designated by
+	a set of extension elements that are declared by a
+	namespace. The namespace identifies the extension to
+	the tool that processes the extension.
+
+	The type of the extension-element is abstract. Therefore,
+	a concrete type must be specified by the TLD using
+	xsi:type attribute for each extension-element.
+
+      </xsd:documentation>
+    </xsd:annotation>
+
+    <xsd:sequence>
+      <xsd:element name="extension-element"
+		   type="j2ee:extensibleType"
+		   maxOccurs="unbounded"/>
+    </xsd:sequence>
+
+    <xsd:attribute name="namespace"
+		   use="required"
+		   type="xsd:anyURI"/>
+    <xsd:attribute name="id" type="xsd:ID"/>
+
+  </xsd:complexType>
+
+<!-- **************************************************** -->
+
+  <xsd:complexType name="tldTaglibType">
+    <xsd:annotation>
+      <xsd:documentation>
+
+	The taglib tag is the document root, it defines:
+
+	description     a simple string describing the "use" of this taglib,
+			should be user discernable
+
+	display-name    the display-name element contains a
+			short name that is intended to be displayed
+			by tools
+
+	icon            optional icon that can be used by tools
+
+	tlib-version    the version of the tag library implementation
+
+	short-name      a simple default short name that could be
+			used by a JSP authoring tool to create
+			names with a mnemonic value; for example,
+			the it may be used as the prefered prefix
+			value in taglib directives
+
+	uri             a uri uniquely identifying this taglib
+
+	validator       optional TagLibraryValidator information
+
+	listener        optional event listener specification
+
+	tag             tags in this tag library
+
+	tag-file        tag files in this tag library
+
+	function        zero or more EL functions defined in this
+			tag library
+
+	taglib-extension zero or more extensions that provide extra
+			information about this taglib, for tool
+			consumption
+
+      </xsd:documentation>
+    </xsd:annotation>
+    <xsd:sequence>
+      <xsd:group ref="j2ee:descriptionGroup"/>
+      <xsd:element name="tlib-version"
+		   type="j2ee:dewey-versionType">
+	<xsd:annotation>
+	  <xsd:documentation>
+
+	    Describes this version (number) of the taglibrary.
+	    It is described as a dewey decimal.
+
+	  </xsd:documentation>
+	</xsd:annotation>
+
+      </xsd:element>
+
+      <xsd:element name="short-name"
+		   type="j2ee:tld-canonical-nameType">
+	<xsd:annotation>
+	  <xsd:documentation>
+
+	    Defines a simple default name that could be used by
+	    a JSP authoring tool to create names with a
+	    mnemonicvalue; for example, it may be used as the
+	    preferred prefix value in taglib directives.  Do
+	    not use white space, and do not start with digits
+	    or underscore.
+
+	  </xsd:documentation>
+	</xsd:annotation>
+
+      </xsd:element>
+      <xsd:element name="uri"
+		   type="j2ee:xsdAnyURIType"
+		   minOccurs="0">
+	<xsd:annotation>
+	  <xsd:documentation>
+
+	    Defines a public URI that uniquely identifies this
+	    version of the taglibrary.  Leave it empty if it
+	    does not apply.
+
+	  </xsd:documentation>
+	</xsd:annotation>
+
+      </xsd:element>
+      <xsd:element name="validator"
+		   type="j2ee:validatorType"
+		   minOccurs="0">
+      </xsd:element>
+      <xsd:element name="listener"
+		   type="j2ee:listenerType"
+		   minOccurs="0" maxOccurs="unbounded">
+      </xsd:element>
+      <xsd:element name="tag"
+		   type="j2ee:tagType"
+		   minOccurs="0"
+		   maxOccurs="unbounded"/>
+      <xsd:element name="tag-file"
+		   type="j2ee:tagFileType"
+		   minOccurs="0"
+		   maxOccurs="unbounded"/>
+      <xsd:element name="function"
+		   type="j2ee:functionType"
+		   minOccurs="0"
+		   maxOccurs="unbounded"/>
+      <xsd:element name="taglib-extension"
+		   type="j2ee:tld-extensionType"
+		   minOccurs="0"
+		   maxOccurs="unbounded">
+	<xsd:annotation>
+	  <xsd:documentation>
+
+	    Taglib extensions are for tool use only and must not affect
+	    the behavior of a container.
+
+	  </xsd:documentation>
+	</xsd:annotation>
+      </xsd:element>
+    </xsd:sequence>
+    <xsd:attribute name="version"
+		   type="j2ee:dewey-versionType"
+		   fixed="2.0"
+		   use="required">
+      <xsd:annotation>
+	<xsd:documentation>
+
+	  Describes the JSP version (number) this taglibrary
+	  requires in order to function (dewey decimal)
+
+	</xsd:documentation>
+      </xsd:annotation>
+
+    </xsd:attribute>
+    <xsd:attribute name="id" type="xsd:ID"/>
+  </xsd:complexType>
+
+<!-- **************************************************** -->
+
+  <xsd:complexType name="validatorType">
+    <xsd:annotation>
+      <xsd:documentation>
+
+	A validator that can be used to validate
+	the conformance of a JSP page to using this tag library is
+	defined by a validatorType.
+
+      </xsd:documentation>
+    </xsd:annotation>
+
+    <xsd:sequence>
+      <xsd:element name="description"
+		   type="j2ee:descriptionType"
+		   minOccurs="0"
+		   maxOccurs="unbounded"/>
+      <xsd:element name="validator-class"
+		   type="j2ee:fully-qualified-classType">
+	<xsd:annotation>
+	  <xsd:documentation>
+
+	    Defines the TagLibraryValidator class that can be used
+	    to validate the conformance of a JSP page to using this
+	    tag library.
+
+	  </xsd:documentation>
+	</xsd:annotation>
+      </xsd:element>
+      <xsd:element name="init-param"
+		   type="j2ee:param-valueType"
+		   minOccurs="0" maxOccurs="unbounded">
+	<xsd:annotation>
+	  <xsd:documentation>
+
+	    The init-param element contains a name/value pair as an
+	    initialization param.
+
+	  </xsd:documentation>
+	</xsd:annotation>
+
+      </xsd:element>
+
+    </xsd:sequence>
+    <xsd:attribute name="id" type="xsd:ID"/>
+  </xsd:complexType>
+
+<!-- **************************************************** -->
+
+  <xsd:complexType name="variable-scopeType">
+    <xsd:annotation>
+      <xsd:documentation>
+
+	This type defines scope of the scripting variable.  See
+	TagExtraInfo for details.  The allowed values are,
+	"NESTED", "AT_BEGIN" and "AT_END".
+
+      </xsd:documentation>
+    </xsd:annotation>
+
+    <xsd:simpleContent>
+      <xsd:restriction base="j2ee:string">
+	<xsd:enumeration value="NESTED"/>
+	<xsd:enumeration value="AT_BEGIN"/>
+	<xsd:enumeration value="AT_END"/>
+      </xsd:restriction>
+    </xsd:simpleContent>
+  </xsd:complexType>
+
+<!-- **************************************************** -->
+
+  <xsd:complexType name="variableType">
+    <xsd:annotation>
+      <xsd:documentation>
+
+	The variableType provides information on the scripting
+	variables defined by using this tag.  It is a (translation
+	time) error for a tag that has one or more variable
+	subelements to have a TagExtraInfo class that returns a
+	non-null value from a call to getVariableInfo().
+
+	The subelements of variableType are of the form:
+
+	description              Optional description of this
+				 variable
+
+	name-given               The variable name as a constant
+
+	name-from-attribute      The name of an attribute whose
+				 (translation time) value will
+				 give the name of the
+				 variable.  One of name-given or
+				 name-from-attribute is required.
+
+	variable-class           Name of the class of the variable.
+				 java.lang.String is default.
+
+	declare                  Whether the variable is declared
+				 or not.  True is the default.
+
+	scope                    The scope of the scripting varaible
+				 defined.  NESTED is default.
+
+      </xsd:documentation>
+    </xsd:annotation>
+
+    <xsd:sequence>
+      <xsd:element name="description"
+		   type="j2ee:descriptionType"
+		   minOccurs="0" maxOccurs="unbounded"/>
+      <xsd:choice>
+	<xsd:element name="name-given"
+		     type="j2ee:java-identifierType">
+	  <xsd:annotation>
+	    <xsd:documentation>
+
+	      The name for the scripting variable.
+
+	    </xsd:documentation>
+	  </xsd:annotation>
+	</xsd:element>
+
+	<xsd:element name="name-from-attribute"
+		     type="j2ee:java-identifierType">
+	  <xsd:annotation>
+	    <xsd:documentation>
+
+	      The name of an attribute whose
+	      (translation-time) value will give the name of
+	      the variable.
+
+	    </xsd:documentation>
+	  </xsd:annotation>
+	</xsd:element>
+      </xsd:choice>
+      <xsd:element name="variable-class"
+		   type="j2ee:fully-qualified-classType"
+		   minOccurs="0">
+	<xsd:annotation>
+	  <xsd:documentation>
+
+	    The optional name of the class for the scripting
+	    variable.  The default is java.lang.String.
+
+	  </xsd:documentation>
+	</xsd:annotation>
+
+      </xsd:element>
+
+      <xsd:element name="declare"
+		   type="j2ee:generic-booleanType"
+		   minOccurs="0">
+
+	<xsd:annotation>
+	  <xsd:documentation>
+
+	    Whether the scripting variable is to be defined
+	    or not.  See TagExtraInfo for details.  This
+	    element is optional and "true" is the default.
+
+	  </xsd:documentation>
+	</xsd:annotation>
+      </xsd:element>
+      <xsd:element name="scope"
+		   type="j2ee:variable-scopeType"
+		   minOccurs="0">
+	<xsd:annotation>
+	  <xsd:documentation>
+
+	    The element is optional and "NESTED" is the default.
+
+	  </xsd:documentation>
+	</xsd:annotation>
+      </xsd:element>
+    </xsd:sequence>
+    <xsd:attribute name="id" type="xsd:ID"/>
+  </xsd:complexType>
+
+</xsd:schema>
+

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/dtd/xml.xsd
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/dtd/xml.xsd	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/dtd/xml.xsd	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,96 @@
+<?xml version='1.0'?>
+<!--
+  Copyright 2004 The Apache Software Foundation
+
+  Licensed 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.
+-->
+<!DOCTYPE xs:schema PUBLIC "-//W3C//DTD XMLSCHEMA 200102//EN" "XMLSchema.dtd" >
+<xs:schema targetNamespace="http://www.w3.org/XML/1998/namespace" xmlns:xs="http://www.w3.org/2001/XMLSchema" xml:lang="en">
+
+ <xs:annotation>
+  <xs:documentation>
+   See http://www.w3.org/XML/1998/namespace.html and
+   http://www.w3.org/TR/REC-xml for information about this namespace.
+  </xs:documentation>
+ </xs:annotation>
+
+ <xs:annotation>
+  <xs:documentation>This schema defines attributes and an attribute group
+        suitable for use by
+        schemas wishing to allow xml:base, xml:lang or xml:space attributes
+        on elements they define.
+
+        To enable this, such a schema must import this schema
+        for the XML namespace, e.g. as follows:
+        &lt;schema . . .>
+         . . .
+         &lt;import namespace="http://www.w3.org/XML/1998/namespace"
+                    schemaLocation="http://www.w3.org/2001/03/xml.xsd"/>
+
+        Subsequently, qualified reference to any of the attributes
+        or the group defined below will have the desired effect, e.g.
+
+        &lt;type . . .>
+         . . .
+         &lt;attributeGroup ref="xml:specialAttrs"/>
+ 
+         will define a type which will schema-validate an instance
+         element with any of those attributes</xs:documentation>
+ </xs:annotation>
+
+ <xs:annotation>
+  <xs:documentation>In keeping with the XML Schema WG's standard versioning
+   policy, this schema document will persist at
+   http://www.w3.org/2001/03/xml.xsd.
+   At the date of issue it can also be found at
+   http://www.w3.org/2001/xml.xsd.
+   The schema document at that URI may however change in the future,
+   in order to remain compatible with the latest version of XML Schema
+   itself.  In other words, if the XML Schema namespace changes, the version
+   of this document at
+   http://www.w3.org/2001/xml.xsd will change
+   accordingly; the version at
+   http://www.w3.org/2001/03/xml.xsd will not change.
+  </xs:documentation>
+ </xs:annotation>
+
+ <xs:attribute name="lang" type="xs:language">
+  <xs:annotation>
+   <xs:documentation>In due course, we should install the relevant ISO 2- and 3-letter
+         codes as the enumerated possible values . . .</xs:documentation>
+  </xs:annotation>
+ </xs:attribute>
+
+ <xs:attribute name="space" default="preserve">
+  <xs:simpleType>
+   <xs:restriction base="xs:NCName">
+    <xs:enumeration value="default"/>
+    <xs:enumeration value="preserve"/>
+   </xs:restriction>
+  </xs:simpleType>
+ </xs:attribute>
+
+ <xs:attribute name="base" type="xs:anyURI">
+  <xs:annotation>
+   <xs:documentation>See http://www.w3.org/TR/xmlbase/ for
+                     information about this attribute.</xs:documentation>
+  </xs:annotation>
+ </xs:attribute>
+
+ <xs:attributeGroup name="specialAttrs">
+  <xs:attribute ref="xml:base"/>
+  <xs:attribute ref="xml:lang"/>
+  <xs:attribute ref="xml:space"/>
+ </xs:attributeGroup>
+
+</xs:schema>

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/Filter.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/Filter.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/Filter.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,91 @@
+/*
+* Copyright 2004 The Apache Software Foundation
+*
+* Licensed 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;
+
+import java.io.IOException;
+
+	/** 
+	* A filter is an object that performs filtering tasks on either the request to a resource (a servlet or static content), or on the response from a resource, or both.
+        * <br><br>
+	* Filters perform filtering in the <code>doFilter</code> method. Every Filter has access to 
+	** a FilterConfig object from which it can obtain its initialization parameters, a
+	** reference to the ServletContext which it can use, for example, to load resources
+	** needed for filtering tasks.
+	** <p>
+	** Filters are configured in the deployment descriptor of a web application
+	** <p>
+	** Examples that have been identified for this design are<br>
+	** 1) Authentication Filters <br>
+	** 2) Logging and Auditing Filters <br>
+	** 3) Image conversion Filters <br>
+    	** 4) Data compression Filters <br>
+	** 5) Encryption Filters <br>
+	** 6) Tokenizing Filters <br>
+	** 7) Filters that trigger resource access events <br>
+	** 8) XSL/T filters <br>
+	** 9) Mime-type chain Filter <br>
+	 * @since	Servlet 2.3
+	*/
+
+public interface Filter {
+
+	/** 
+	* Called by the web container to indicate to a filter that it is being placed into
+	* service. The servlet container calls the init method exactly once after instantiating the
+	* filter. The init method must complete successfully before the filter is asked to do any
+	* filtering work. <br><br>
+
+     	* The web container cannot place the filter into service if the init method either<br>
+        * 1.Throws a ServletException <br>
+        * 2.Does not return within a time period defined by the web container 
+	*/
+	public void init(FilterConfig filterConfig) throws ServletException;
+	
+	
+	/**
+	* The <code>doFilter</code> method of the Filter is called by the container
+	* each time a request/response pair is passed through the chain due
+	* to a client request for a resource at the end of the chain. The FilterChain passed in to this
+	* method allows the Filter to pass on the request and response to the next entity in the
+	* chain.<p>
+	* A typical implementation of this method would follow the following pattern:- <br>
+	* 1. Examine the request<br>
+	* 2. Optionally wrap the request object with a custom implementation to
+	* filter content or headers for input filtering <br>
+	* 3. Optionally wrap the response object with a custom implementation to
+	* filter content or headers for output filtering <br>
+	* 4. a) <strong>Either</strong> invoke the next entity in the chain using the FilterChain object (<code>chain.doFilter()</code>), <br>   
+	** 4. b) <strong>or</strong> not pass on the request/response pair to the next entity in the filter chain to block the request processing<br>
+	** 5. Directly set headers on the response after invocation of the next entity in the filter chain.
+	**/
+    public void doFilter ( ServletRequest request, ServletResponse response, FilterChain chain ) throws IOException, ServletException;
+
+	/**
+	* Called by the web container to indicate to a filter that it is being taken out of service. This 
+	* method is only called once all threads within the filter's doFilter method have exited or after
+	* a timeout period has passed. After the web container calls this method, it will not call the
+	* doFilter method again on this instance of the filter. <br><br>
+	* 
+     	* This method gives the filter an opportunity to clean up any resources that are being held (for
+	* example, memory, file handles, threads) and make sure that any persistent state is synchronized
+	* with the filter's current state in memory.
+	*/
+
+	public void destroy();
+
+
+}
+

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/FilterChain.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/FilterChain.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/FilterChain.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,45 @@
+/*
+* Copyright 2004 The Apache Software Foundation
+*
+* Licensed 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;
+
+import java.io.IOException;
+
+    /**
+    * A FilterChain is an object provided by the servlet container to the developer
+    * giving a view into the invocation chain of a filtered request for a resource. Filters
+    * use the FilterChain to invoke the next filter in the chain, or if the calling filter
+    * is the last filter in the chain, to invoke the resource at the end of the chain.
+    *
+    * @see Filter
+    * @since Servlet 2.3
+    **/
+
+public interface FilterChain {
+	
+	/**
+	* Causes the next filter in the chain to be invoked, or if the calling filter is the last filter
+	* in the chain, causes the resource at the end of the chain to be invoked.
+	*
+	* @param request the request to pass along the chain.
+	* @param response the response to pass along the chain.
+	*
+	* @since 2.3
+	*/
+	
+    public void doFilter ( ServletRequest request, ServletResponse response ) throws IOException, ServletException;
+
+}
+

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/FilterConfig.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/FilterConfig.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/FilterConfig.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,91 @@
+/*
+* Copyright 2004 The Apache Software Foundation
+*
+* Licensed 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;
+
+
+import java.util.Enumeration;
+
+	 /** 
+	 *
+	 * A filter configuration object used by a servlet container
+	 * to pass information to a filter during initialization.
+	 * @see Filter 
+	  * @since	Servlet 2.3
+	 *
+	 */
+
+
+public interface FilterConfig {
+
+	/** 
+	* Returns the filter-name of this filter as defined in the deployment descriptor. 
+	*/
+	
+	public String getFilterName();
+
+
+ /**
+     * Returns a reference to the {@link ServletContext} in which the caller
+     * is executing.
+     *
+     *
+     * @return		a {@link ServletContext} object, used
+     *			by the caller to interact with its servlet 
+     *                  container
+     * 
+     * @see		ServletContext
+     *
+     */
+
+    public ServletContext getServletContext();
+    
+    /**
+     * Returns a <code>String</code> containing the value of the 
+     * named initialization parameter, or <code>null</code> if 
+     * the parameter does not exist.
+     *
+     * @param name	a <code>String</code> specifying the name
+     *			of the initialization parameter
+     *
+     * @return		a <code>String</code> containing the value 
+     *			of the initialization parameter
+     *
+     */
+
+    public String getInitParameter(String name);
+
+
+    /**
+     * Returns the names of the filter's initialization parameters
+     * as an <code>Enumeration</code> of <code>String</code> objects, 
+     * or an empty <code>Enumeration</code> if the filter has
+     * no initialization parameters.
+     *
+     * @return		an <code>Enumeration</code> of <code>String</code> 
+     *			objects containing the names of the filter's 
+     *			initialization parameters
+     *
+     *
+     *
+     */
+
+    public Enumeration getInitParameterNames();
+
+
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/GenericServlet.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/GenericServlet.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/GenericServlet.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,323 @@
+/*
+* Copyright 2004 The Apache Software Foundation
+*
+* Licensed 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;
+
+import java.io.IOException;
+import java.util.Enumeration;
+
+/**
+ *
+ * Defines a generic, protocol-independent
+ * servlet. To write an HTTP servlet for use on the
+ * Web, extend {@link javax.servlet.http.HttpServlet} instead.
+ *
+ * <p><code>GenericServlet</code> implements the <code>Servlet</code>
+ * and <code>ServletConfig</code> interfaces. <code>GenericServlet</code>
+ * may be directly extended by a servlet, although it's more common to extend
+ * a protocol-specific subclass such as <code>HttpServlet</code>.
+ *
+ * <p><code>GenericServlet</code> makes writing servlets
+ * easier. It provides simple versions of the lifecycle methods 
+ * <code>init</code> and <code>destroy</code> and of the methods 
+ * in the <code>ServletConfig</code> interface. <code>GenericServlet</code>
+ * also implements the <code>log</code> method, declared in the
+ * <code>ServletContext</code> interface. 
+ *
+ * <p>To write a generic servlet, you need only
+ * override the abstract <code>service</code> method. 
+ *
+ *
+ * @author 	Various
+ * @version 	$Version$
+ *
+ *
+ *
+ */
+
+ 
+public abstract class GenericServlet 
+    implements Servlet, ServletConfig, java.io.Serializable
+{
+
+    private transient ServletConfig config;
+    
+
+    /**
+     *
+     * Does nothing. All of the servlet initialization
+     * is done by one of the <code>init</code> methods.
+     *
+     */
+
+    public GenericServlet() { }
+    
+    
+    
+   /**
+     * Called by the servlet container to indicate to a servlet that the
+     * servlet is being taken out of service.  See {@link Servlet#destroy}.
+     *
+     * 
+     */
+
+    public void destroy() {
+    }
+    
+    
+    
+    /**
+     * Returns a <code>String</code> containing the value of the named
+     * initialization parameter, or <code>null</code> if the parameter does
+     * not exist.  See {@link ServletConfig#getInitParameter}.
+     *
+     * <p>This method is supplied for convenience. It gets the 
+     * value of the named parameter from the servlet's 
+     * <code>ServletConfig</code> object.
+     *
+     * @param name 		a <code>String</code> specifying the name 
+     *				of the initialization parameter
+     *
+     * @return String 		a <code>String</code> containing the value
+     *				of the initialization parameter
+     *
+     */ 
+
+    public String getInitParameter(String name) {
+	return getServletConfig().getInitParameter(name);
+    }
+    
+    
+
+   /**
+    * Returns the names of the servlet's initialization parameters 
+    * as an <code>Enumeration</code> of <code>String</code> objects,
+    * or an empty <code>Enumeration</code> if the servlet has no
+    * initialization parameters.  See {@link
+    * ServletConfig#getInitParameterNames}.
+    *
+    * <p>This method is supplied for convenience. It gets the 
+    * parameter names from the servlet's <code>ServletConfig</code> object. 
+    *
+    *
+    * @return Enumeration 	an enumeration of <code>String</code>
+    *				objects containing the names of 
+    *				the servlet's initialization parameters
+    *
+    */
+
+    public Enumeration getInitParameterNames() {
+	return getServletConfig().getInitParameterNames();
+    }   
+    
+     
+ 
+     
+
+    /**
+     * Returns this servlet's {@link ServletConfig} object.
+     *
+     * @return ServletConfig 	the <code>ServletConfig</code> object
+     *				that initialized this servlet
+     *
+     */
+    
+    public ServletConfig getServletConfig() {
+	return config;
+    }
+    
+    
+ 
+    
+    /**
+     * Returns a reference to the {@link ServletContext} in which this servlet
+     * is running.  See {@link ServletConfig#getServletContext}.
+     *
+     * <p>This method is supplied for convenience. It gets the 
+     * context from the servlet's <code>ServletConfig</code> object.
+     *
+     *
+     * @return ServletContext 	the <code>ServletContext</code> object
+     *				passed to this servlet by the <code>init</code>
+     *				method
+     *
+     */
+
+    public ServletContext getServletContext() {
+	return getServletConfig().getServletContext();
+    }
+
+
+
+ 
+
+    /**
+     * Returns information about the servlet, such as 
+     * author, version, and copyright. 
+     * By default, this method returns an empty string.  Override this method
+     * to have it return a meaningful value.  See {@link
+     * Servlet#getServletInfo}.
+     *
+     *
+     * @return String 		information about this servlet, by default an
+     * 				empty string
+     *
+     */
+    
+    public String getServletInfo() {
+	return "";
+    }
+
+
+
+
+    /**
+     *
+     * Called by the servlet container to indicate to a servlet that the
+     * servlet is being placed into service.  See {@link Servlet#init}.
+     *
+     * <p>This implementation stores the {@link ServletConfig}
+     * object it receives from the servlet container for later use.
+     * When overriding this form of the method, call 
+     * <code>super.init(config)</code>.
+     *
+     * @param config 			the <code>ServletConfig</code> object
+     *					that contains configutation
+     *					information for this servlet
+     *
+     * @exception ServletException 	if an exception occurs that
+     *					interrupts the servlet's normal
+     *					operation
+     *
+     * 
+     * @see 				UnavailableException
+     *
+     */
+
+    public void init(ServletConfig config) throws ServletException {
+	this.config = config;
+	this.init();
+    }
+
+
+
+
+
+    /**
+     *
+     * A convenience method which can be overridden so that there's no need
+     * to call <code>super.init(config)</code>.
+     *
+     * <p>Instead of overriding {@link #init(ServletConfig)}, simply override
+     * this method and it will be called by
+     * <code>GenericServlet.init(ServletConfig config)</code>.
+     * The <code>ServletConfig</code> object can still be retrieved via {@link
+     * #getServletConfig}. 
+     *
+     * @exception ServletException 	if an exception occurs that
+     *					interrupts the servlet's
+     *					normal operation
+     *
+     */
+    
+    public void init() throws ServletException {
+
+    }
+    
+
+
+
+    /**
+     * 
+     * Writes the specified message to a servlet log file, prepended by the
+     * servlet's name.  See {@link ServletContext#log(String)}.
+     *
+     * @param msg 	a <code>String</code> specifying
+     *			the message to be written to the log file
+     *
+     */
+     
+    public void log(String msg) {
+	getServletContext().log(getServletName() + ": "+ msg);
+    }
+   
+   
+   
+   
+    /**
+     * Writes an explanatory message and a stack trace
+     * for a given <code>Throwable</code> exception
+     * to the servlet log file, prepended by the servlet's name.
+     * See {@link ServletContext#log(String, Throwable)}.
+     *
+     *
+     * @param message 		a <code>String</code> that describes
+     *				the error or exception
+     *
+     * @param t			the <code>java.lang.Throwable</code> error
+     * 				or exception
+     *
+     *
+     */
+   
+    public void log(String message, Throwable t) {
+	getServletContext().log(getServletName() + ": " + message, t);
+    }
+    
+    
+    
+    /**
+     * Called by the servlet container to allow the servlet to respond to
+     * a request.  See {@link Servlet#service}.
+     * 
+     * <p>This method is declared abstract so subclasses, such as 
+     * <code>HttpServlet</code>, must override it.
+     *
+     *
+     *
+     * @param req 	the <code>ServletRequest</code> object
+     *			that contains the client's request
+     *
+     * @param res 	the <code>ServletResponse</code> object
+     *			that will contain the servlet's response
+     *
+     * @exception ServletException 	if an exception occurs that
+     *					interferes with the servlet's
+     *					normal operation occurred
+     *
+     * @exception IOException 		if an input or output
+     *					exception occurs
+     *
+     */
+
+    public abstract void service(ServletRequest req, ServletResponse res)
+	throws ServletException, IOException;
+    
+
+
+    /**
+     * Returns the name of this servlet instance.
+     * See {@link ServletConfig#getServletName}.
+     *
+     * @return          the name of this servlet instance
+     *
+     *
+     *
+     */
+
+    public String getServletName() {
+        return config.getServletName();
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/LocalStrings.properties
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/LocalStrings.properties	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/LocalStrings.properties	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,20 @@
+# Copyright 2004 The Apache Software Foundation
+#
+# Licensed 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.
+
+# Default localized string information
+# Localized for Locale en_US
+
+err.not_iso8859_1=Not an ISO 8859-1 character: {0}
+value.true=true
+value.false=false

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/LocalStrings_fr.properties
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/LocalStrings_fr.properties	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/LocalStrings_fr.properties	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,22 @@
+# Copyright 2004 The Apache Software Foundation
+#
+# Licensed 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.
+
+# Default localized string information
+# Localized for Locale fr_FR
+
+err.not_iso8859_1={0} n''est pas un caractère ISO 8859-1
+value.true=true
+value.false=false 
+
+

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/LocalStrings_ja.properties
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/LocalStrings_ja.properties	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/LocalStrings_ja.properties	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,20 @@
+# Copyright 2004 The Apache Software Foundation
+#
+# Licensed 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.
+
+# Default localized string information
+# Localized for Locale ja_JP
+
+err.not_iso8859_1=ISO 8859-1 \u306e\u6587\u5b57\u3067\u306f\u3042\u308a\u307e\u305b\u3093: {0}
+value.true=true
+value.false=false

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/RequestDispatcher.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/RequestDispatcher.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/RequestDispatcher.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,138 @@
+/*
+* Copyright 2004 The Apache Software Foundation
+*
+* Licensed 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;
+
+import java.io.IOException;
+
+
+/**
+ * Defines an object that receives requests from the client
+ * and sends them to any resource (such as a servlet, 
+ * HTML file, or JSP file) on the server. The servlet
+ * container creates the <code>RequestDispatcher</code> object,
+ * which is used as a wrapper around a server resource located
+ * at a particular path or given by a particular name.
+ *
+ * <p>This interface is intended to wrap servlets,
+ * but a servlet container can create <code>RequestDispatcher</code>
+ * objects to wrap any type of resource.
+ *
+ * @author 	Various
+ * @version 	$Version$
+ *
+ * @see 	ServletContext#getRequestDispatcher(java.lang.String)
+ * @see 	ServletContext#getNamedDispatcher(java.lang.String)
+ * @see 	ServletRequest#getRequestDispatcher(java.lang.String)
+ *
+ */
+ 
+public interface RequestDispatcher {
+
+
+
+
+
+/**
+ * Forwards a request from
+ * a servlet to another resource (servlet, JSP file, or
+ * HTML file) on the server. This method allows
+ * one servlet to do preliminary processing of
+ * a request and another resource to generate
+ * the response.
+ *
+ * <p>For a <code>RequestDispatcher</code> obtained via 
+ * <code>getRequestDispatcher()</code>, the <code>ServletRequest</code> 
+ * object has its path elements and parameters adjusted to match
+ * the path of the target resource.
+ *
+ * <p><code>forward</code> should be called before the response has been 
+ * committed to the client (before response body output has been flushed).  
+ * If the response already has been committed, this method throws
+ * an <code>IllegalStateException</code>.
+ * Uncommitted output in the response buffer is automatically cleared 
+ * before the forward.
+ *
+ * <p>The request and response parameters must be either the same
+ * objects as were passed to the calling servlet's service method or be
+ * subclasses of the {@link ServletRequestWrapper} or {@link ServletResponseWrapper} classes
+ * that wrap them.
+ *
+ *
+ * @param request		a {@link ServletRequest} object
+ *				that represents the request the client
+ * 				makes of the servlet
+ *
+ * @param response		a {@link ServletResponse} object
+ *				that represents the response the servlet
+ *				returns to the client
+ *
+ * @exception ServletException	if the target resource throws this exception
+ *
+ * @exception IOException	if the target resource throws this exception
+ *
+ * @exception IllegalStateException	if the response was already committed
+ *
+ */
+
+    public void forward(ServletRequest request, ServletResponse response)
+	throws ServletException, IOException;
+
+
+
+
+    /**
+     *
+     * Includes the content of a resource (servlet, JSP page,
+     * HTML file) in the response. In essence, this method enables 
+     * programmatic server-side includes.
+     *
+     * <p>The {@link ServletResponse} object has its path elements
+     * and parameters remain unchanged from the caller's. The included
+     * servlet cannot change the response status code or set headers;
+     * any attempt to make a change is ignored.
+     *
+     * <p>The request and response parameters must be either the same
+     * objects as were passed to the calling servlet's service method or be
+     * subclasses of the {@link ServletRequestWrapper} or {@link ServletResponseWrapper} classes
+     * that wrap them.
+     * 
+     *
+     *
+     * @param request 			a {@link ServletRequest} object 
+     *					that contains the client's request
+     *
+     * @param response 			a {@link ServletResponse} object 
+     * 					that contains the servlet's response
+     *
+     * @exception ServletException 	if the included resource throws this exception
+     *
+     * @exception IOException 		if the included resource throws this exception
+     *
+     *
+     */
+     
+    public void include(ServletRequest request, ServletResponse response)
+	throws ServletException, IOException;
+}
+
+
+
+
+
+
+
+

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/Servlet.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/Servlet.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/Servlet.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,192 @@
+/*
+* Copyright 2004 The Apache Software Foundation
+*
+* Licensed 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;
+
+import java.io.IOException;
+
+
+/**
+ * Defines methods that all servlets must implement.
+ *
+ * <p>A servlet is a small Java program that runs within a Web server.
+ * Servlets receive and respond to requests from Web clients,
+ * usually across HTTP, the HyperText Transfer Protocol. 
+ *
+ * <p>To implement this interface, you can write a generic servlet
+ * that extends
+ * <code>javax.servlet.GenericServlet</code> or an HTTP servlet that
+ * extends <code>javax.servlet.http.HttpServlet</code>.
+ *
+ * <p>This interface defines methods to initialize a servlet,
+ * to service requests, and to remove a servlet from the server.
+ * These are known as life-cycle methods and are called in the
+ * following sequence:
+ * <ol>
+ * <li>The servlet is constructed, then initialized with the <code>init</code> method.
+ * <li>Any calls from clients to the <code>service</code> method are handled.
+ * <li>The servlet is taken out of service, then destroyed with the 
+ * <code>destroy</code> method, then garbage collected and finalized.
+ * </ol>
+ *
+ * <p>In addition to the life-cycle methods, this interface
+ * provides the <code>getServletConfig</code> method, which the servlet 
+ * can use to get any startup information, and the <code>getServletInfo</code>
+ * method, which allows the servlet to return basic information about itself,
+ * such as author, version, and copyright.
+ *
+ * @author 	Various
+ * @version 	$Version$
+ *
+ * @see 	GenericServlet
+ * @see 	javax.servlet.http.HttpServlet
+ *
+ */
+
+
+public interface Servlet {
+
+    /**
+     * Called by the servlet container to indicate to a servlet that the 
+     * servlet is being placed into service.
+     *
+     * <p>The servlet container calls the <code>init</code>
+     * method exactly once after instantiating the servlet.
+     * The <code>init</code> method must complete successfully
+     * before the servlet can receive any requests.
+     *
+     * <p>The servlet container cannot place the servlet into service
+     * if the <code>init</code> method
+     * <ol>
+     * <li>Throws a <code>ServletException</code>
+     * <li>Does not return within a time period defined by the Web server
+     * </ol>
+     *
+     *
+     * @param config			a <code>ServletConfig</code> object 
+     *					containing the servlet's
+     * 					configuration and initialization parameters
+     *
+     * @exception ServletException 	if an exception has occurred that
+     *					interferes with the servlet's normal
+     *					operation
+     *
+     * @see 				UnavailableException
+     * @see 				#getServletConfig
+     *
+     */
+
+    public void init(ServletConfig config) throws ServletException;
+    
+    
+
+    /**
+     *
+     * Returns a {@link ServletConfig} object, which contains
+     * initialization and startup parameters for this servlet.
+     * The <code>ServletConfig</code> object returned is the one 
+     * passed to the <code>init</code> method. 
+     *
+     * <p>Implementations of this interface are responsible for storing the 
+     * <code>ServletConfig</code> object so that this 
+     * method can return it. The {@link GenericServlet}
+     * class, which implements this interface, already does this.
+     *
+     * @return		the <code>ServletConfig</code> object
+     *			that initializes this servlet
+     *
+     * @see 		#init
+     *
+     */
+
+    public ServletConfig getServletConfig();
+    
+    
+
+    /**
+     * Called by the servlet container to allow the servlet to respond to 
+     * a request.
+     *
+     * <p>This method is only called after the servlet's <code>init()</code>
+     * method has completed successfully.
+     * 
+     * <p>  The status code of the response always should be set for a servlet 
+     * that throws or sends an error.
+     *
+     * 
+     * <p>Servlets typically run inside multithreaded servlet containers
+     * that can handle multiple requests concurrently. Developers must 
+     * be aware to synchronize access to any shared resources such as files,
+     * network connections, and as well as the servlet's class and instance 
+     * variables. 
+     * More information on multithreaded programming in Java is available in 
+     * <a href="http://java.sun.com/Series/Tutorial/java/threads/multithreaded.html">
+     * the Java tutorial on multi-threaded programming</a>.
+     *
+     *
+     * @param req 	the <code>ServletRequest</code> object that contains
+     *			the client's request
+     *
+     * @param res 	the <code>ServletResponse</code> object that contains
+     *			the servlet's response
+     *
+     * @exception ServletException 	if an exception occurs that interferes
+     *					with the servlet's normal operation 
+     *
+     * @exception IOException 		if an input or output exception occurs
+     *
+     */
+
+    public void service(ServletRequest req, ServletResponse res)
+	throws ServletException, IOException;
+	
+	
+
+    /**
+     * Returns information about the servlet, such
+     * as author, version, and copyright.
+     * 
+     * <p>The string that this method returns should
+     * be plain text and not markup of any kind (such as HTML, XML,
+     * etc.).
+     *
+     * @return 		a <code>String</code> containing servlet information
+     *
+     */
+
+    public String getServletInfo();
+    
+    
+
+    /**
+     *
+     * Called by the servlet container to indicate to a servlet that the
+     * servlet is being taken out of service.  This method is
+     * only called once all threads within the servlet's
+     * <code>service</code> method have exited or after a timeout
+     * period has passed. After the servlet container calls this 
+     * method, it will not call the <code>service</code> method again
+     * on this servlet.
+     *
+     * <p>This method gives the servlet an opportunity 
+     * to clean up any resources that are being held (for example, memory,
+     * file handles, threads) and make sure that any persistent state is
+     * synchronized with the servlet's current state in memory.
+     *
+     */
+
+    public void destroy();
+}

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/ServletConfig.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/ServletConfig.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/ServletConfig.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,94 @@
+/*
+* Copyright 2004 The Apache Software Foundation
+*
+* Licensed 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;
+
+import java.util.Enumeration;
+
+
+
+/**
+ * 
+ * A servlet configuration object used by a servlet container
+ * to pass information to a servlet during initialization. 
+ *
+ */
+ 
+public interface ServletConfig {
+    
+
+    /**
+     * Returns the name of this servlet instance.
+     * The name may be provided via server administration, assigned in the 
+     * web application deployment descriptor, or for an unregistered (and thus
+     * unnamed) servlet instance it will be the servlet's class name.
+     *
+     * @return		the name of the servlet instance
+     *
+     *
+     *
+     */
+
+    public String getServletName();
+
+    /**
+     * Returns a reference to the {@link ServletContext} in which the caller
+     * is executing.
+     *
+     *
+     * @return		a {@link ServletContext} object, used
+     *			by the caller to interact with its servlet 
+     *                  container
+     * 
+     * @see		ServletContext
+     *
+     */
+
+    public ServletContext getServletContext();
+    
+    /**
+     * Returns a <code>String</code> containing the value of the 
+     * named initialization parameter, or <code>null</code> if 
+     * the parameter does not exist.
+     *
+     * @param name	a <code>String</code> specifying the name
+     *			of the initialization parameter
+     *
+     * @return		a <code>String</code> containing the value 
+     *			of the initialization parameter
+     *
+     */
+
+    public String getInitParameter(String name);
+
+
+    /**
+     * Returns the names of the servlet's initialization parameters
+     * as an <code>Enumeration</code> of <code>String</code> objects, 
+     * or an empty <code>Enumeration</code> if the servlet has
+     * no initialization parameters.
+     *
+     * @return		an <code>Enumeration</code> of <code>String</code> 
+     *			objects containing the names of the servlet's 
+     *			initialization parameters
+     *
+     *
+     *
+     */
+
+    public Enumeration getInitParameterNames();
+
+
+}

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/ServletContext.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/ServletContext.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/ServletContext.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,643 @@
+/*
+* Copyright 2004 The Apache Software Foundation
+*
+* Licensed 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;
+
+import java.io.InputStream;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.Enumeration;
+import java.util.Set;
+
+
+/**
+ * 
+ * Defines a set of methods that a servlet uses to communicate with its
+ * servlet container, for example, to get the MIME type of a file, dispatch
+ * requests, or write to a log file.
+ *
+ * <p>There is one context per "web application" per Java Virtual Machine.  (A
+ * "web application" is a collection of servlets and content installed under a
+ * specific subset of the server's URL namespace such as <code>/catalog</code>
+ * and possibly installed via a <code>.war</code> file.) 
+ *
+ * <p>In the case of a web
+ * application marked "distributed" in its deployment descriptor, there will
+ * be one context instance for each virtual machine.  In this situation, the 
+ * context cannot be used as a location to share global information (because
+ * the information won't be truly global).  Use an external resource like 
+ * a database instead.
+ *
+ * <p>The <code>ServletContext</code> object is contained within 
+ * the {@link ServletConfig} object, which the Web server provides the
+ * servlet when the servlet is initialized.
+ *
+ * @author 	Various
+ * @version 	$Version$
+ *
+ * @see 	Servlet#getServletConfig
+ * @see 	ServletConfig#getServletContext
+ *
+ */
+
+public interface ServletContext {
+
+
+    /**
+     * Returns a <code>ServletContext</code> object that 
+     * corresponds to a specified URL on the server.
+     *
+     * <p>This method allows servlets to gain
+     * access to the context for various parts of the server, and as
+     * needed obtain {@link RequestDispatcher} objects from the context.
+     * The given path must be begin with "/", is interpreted relative 
+     * to the server's document root and is matched against the context roots of
+     * other web applications hosted on this container.
+     * 
+     * <p>In a security conscious environment, the servlet container may
+     * return <code>null</code> for a given URL.
+     *       
+     * @param uripath 	a <code>String</code> specifying the context path of
+     *			another web application in the container.
+     * @return		the <code>ServletContext</code> object that
+     *			corresponds to the named URL, or null if either
+			none exists or the container wishes to restrict 
+     * 			this access.
+     *
+     * @see 		RequestDispatcher
+     *
+     */
+
+    public ServletContext getContext(String uripath);
+    
+    
+
+    /**
+     * Returns the major version of the Java Servlet API that this
+     * servlet container supports. All implementations that comply
+     * with Version 2.4 must have this method
+     * return the integer 2.
+     *
+     * @return 		2
+     *
+     */
+    
+    public int getMajorVersion();
+    
+    
+
+    /**
+     * Returns the minor version of the Servlet API that this
+     * servlet container supports. All implementations that comply
+     * with Version 2.4 must have this method
+     * return the integer 4.
+     *
+     * @return 		4
+     *
+     */
+
+    public int getMinorVersion();
+    
+    
+
+    /**
+     * Returns the MIME type of the specified file, or <code>null</code> if 
+     * the MIME type is not known. The MIME type is determined
+     * by the configuration of the servlet container, and may be specified
+     * in a web application deployment descriptor. Common MIME
+     * types are <code>"text/html"</code> and <code>"image/gif"</code>.
+     *
+     *
+     * @param   file    a <code>String</code> specifying the name
+     *			of a file
+     *
+     * @return 		a <code>String</code> specifying the file's MIME type
+     *
+     */
+
+    public String getMimeType(String file);
+    
+    /**
+    * Returns a directory-like listing of all the paths to resources within the web application whose longest sub-path
+    * matches the supplied path argument. Paths indicating subdirectory paths end with a '/'. The returned paths are all 
+    * relative to the root of the web application and have a leading '/'. For example, for a web application 
+    * containing<br><br>
+
+    * /welcome.html<br>
+    * /catalog/index.html<br>
+    * /catalog/products.html<br>
+    * /catalog/offers/books.html<br>
+    * /catalog/offers/music.html<br>
+    * /customer/login.jsp<br>
+    * /WEB-INF/web.xml<br>
+    * /WEB-INF/classes/com.acme.OrderServlet.class,<br><br>
+    *
+    * getResourcePaths("/") returns {"/welcome.html", "/catalog/", "/customer/", "/WEB-INF/"}<br>
+    * getResourcePaths("/catalog/") returns {"/catalog/index.html", "/catalog/products.html", "/catalog/offers/"}.<br>
+	   
+
+
+    *@param path		the partial path used to match the resources,
+    *				which must start with a /
+    *@return a Set containing the directory listing, or null if there are no resources in the web application whose path
+	* begins with the supplied path.
+
+    * @since Servlet 2.3
+    */
+    
+    public Set getResourcePaths(String path);
+    
+    
+
+    /**
+     * Returns a URL to the resource that is mapped to a specified
+     * path. The path must begin with a "/" and is interpreted
+     * as relative to the current context root.
+     *
+     * <p>This method allows the servlet container to make a resource 
+     * available to servlets from any source. Resources 
+     * can be located on a local or remote
+     * file system, in a database, or in a <code>.war</code> file. 
+     *
+     * <p>The servlet container must implement the URL handlers
+     * and <code>URLConnection</code> objects that are necessary
+     * to access the resource.
+     *
+     * <p>This method returns <code>null</code>
+     * if no resource is mapped to the pathname.
+     *
+     * <p>Some containers may allow writing to the URL returned by
+     * this method using the methods of the URL class.
+     *
+     * <p>The resource content is returned directly, so be aware that 
+     * requesting a <code>.jsp</code> page returns the JSP source code.
+     * Use a <code>RequestDispatcher</code> instead to include results of 
+     * an execution.
+     *
+     * <p>This method has a different purpose than
+     * <code>java.lang.Class.getResource</code>,
+     * which looks up resources based on a class loader. This
+     * method does not use class loaders.
+     * 
+     * @param path 				a <code>String</code> specifying
+     *						the path to the resource
+     *
+     * @return 					the resource located at the named path,
+     * 						or <code>null</code> if there is no resource
+     *						at that path
+     *
+     * @exception MalformedURLException 	if the pathname is not given in 
+     * 						the correct form
+     *
+     */
+    
+    public URL getResource(String path) throws MalformedURLException;
+    
+    
+
+    /**
+     * Returns the resource located at the named path as
+     * an <code>InputStream</code> object.
+     *
+     * <p>The data in the <code>InputStream</code> can be 
+     * of any type or length. The path must be specified according
+     * to the rules given in <code>getResource</code>.
+     * This method returns <code>null</code> if no resource exists at
+     * the specified path. 
+     * 
+     * <p>Meta-information such as content length and content type
+     * that is available via <code>getResource</code>
+     * method is lost when using this method.
+     *
+     * <p>The servlet container must implement the URL handlers
+     * and <code>URLConnection</code> objects necessary to access
+     * the resource.
+     *
+     * <p>This method is different from 
+     * <code>java.lang.Class.getResourceAsStream</code>,
+     * which uses a class loader. This method allows servlet containers 
+     * to make a resource available
+     * to a servlet from any location, without using a class loader.
+     * 
+     *
+     * @param path 	a <code>String</code> specifying the path
+     *			to the resource
+     *
+     * @return 		the <code>InputStream</code> returned to the 
+     *			servlet, or <code>null</code> if no resource
+     *			exists at the specified path 
+     *
+     *
+     */
+
+    public InputStream getResourceAsStream(String path);
+    
+
+
+
+    /**
+     * 
+     * Returns a {@link RequestDispatcher} object that acts
+     * as a wrapper for the resource located at the given path.
+     * A <code>RequestDispatcher</code> object can be used to forward 
+     * a request to the resource or to include the resource in a response.
+     * The resource can be dynamic or static.
+     *
+     * <p>The pathname must begin with a "/" and is interpreted as relative
+     * to the current context root.  Use <code>getContext</code> to obtain
+     * a <code>RequestDispatcher</code> for resources in foreign contexts.
+     * This method returns <code>null</code> if the <code>ServletContext</code>
+     * cannot return a <code>RequestDispatcher</code>.
+     *
+     * @param path 	a <code>String</code> specifying the pathname
+     *			to the resource
+     *
+     * @return 		a <code>RequestDispatcher</code> object
+     *			that acts as a wrapper for the resource
+     *			at the specified path, or <code>null</code> if 
+     *			the <code>ServletContext</code> cannot return
+     *			a <code>RequestDispatcher</code>
+     *
+     * @see 		RequestDispatcher
+     * @see 		ServletContext#getContext
+     *
+     */
+
+    public RequestDispatcher getRequestDispatcher(String path);
+
+
+
+    /**
+     * Returns a {@link RequestDispatcher} object that acts
+     * as a wrapper for the named servlet.
+     *
+     * <p>Servlets (and JSP pages also) may be given names via server 
+     * administration or via a web application deployment descriptor.
+     * A servlet instance can determine its name using 
+     * {@link ServletConfig#getServletName}.
+     *
+     * <p>This method returns <code>null</code> if the 
+     * <code>ServletContext</code>
+     * cannot return a <code>RequestDispatcher</code> for any reason.
+     *
+     * @param name 	a <code>String</code> specifying the name
+     *			of a servlet to wrap
+     *
+     * @return 		a <code>RequestDispatcher</code> object
+     *			that acts as a wrapper for the named servlet,
+     *			or <code>null</code> if the <code>ServletContext</code>
+     *			cannot return a <code>RequestDispatcher</code>
+     *
+     * @see 		RequestDispatcher
+     * @see 		ServletContext#getContext
+     * @see 		ServletConfig#getServletName
+     *
+     */
+
+    public RequestDispatcher getNamedDispatcher(String name);
+    
+    
+    
+    
+    /**
+     *
+     * @deprecated	As of Java Servlet API 2.1, with no direct replacement.
+     *
+     * <p>This method was originally defined to retrieve a servlet
+     * from a <code>ServletContext</code>. In this version, this method 
+     * always returns <code>null</code> and remains only to preserve 
+     * binary compatibility. This method will be permanently removed 
+     * in a future version of the Java Servlet API.
+     *
+     * <p>In lieu of this method, servlets can share information using the 
+     * <code>ServletContext</code> class and can perform shared business logic
+     * by invoking methods on common non-servlet classes.
+     *
+     */
+
+    public Servlet getServlet(String name) throws ServletException;
+    
+  
+  
+  
+    
+
+    /**
+     *
+     * @deprecated	As of Java Servlet API 2.0, with no replacement.
+     *
+     * <p>This method was originally defined to return an <code>Enumeration</code>
+     * of all the servlets known to this servlet context. In this
+     * version, this method always returns an empty enumeration and
+     * remains only to preserve binary compatibility. This method
+     * will be permanently removed in a future version of the Java
+     * Servlet API.
+     *
+     */
+    
+    public Enumeration getServlets();
+    
+    
+    
+    
+    
+
+    /**
+     * @deprecated	As of Java Servlet API 2.1, with no replacement.
+     *
+     * <p>This method was originally defined to return an 
+     * <code>Enumeration</code>
+     * of all the servlet names known to this context. In this version,
+     * this method always returns an empty <code>Enumeration</code> and 
+     * remains only to preserve binary compatibility. This method will 
+     * be permanently removed in a future version of the Java Servlet API.
+     *
+     */
+ 
+    public Enumeration getServletNames();
+    
+  
+  
+    
+    
+    /**
+     *
+     * Writes the specified message to a servlet log file, usually
+     * an event log. The name and type of the servlet log file is 
+     * specific to the servlet container.
+     *
+     *
+     * @param msg 	a <code>String</code> specifying the 
+     *			message to be written to the log file
+     *
+     */
+     
+    public void log(String msg);
+    
+    
+    
+    
+
+    /**
+     * @deprecated	As of Java Servlet API 2.1, use
+     * 			{@link #log(String message, Throwable throwable)} 
+     *			instead.
+     *
+     * <p>This method was originally defined to write an 
+     * exception's stack trace and an explanatory error message
+     * to the servlet log file.
+     *
+     */
+
+    public void log(Exception exception, String msg);
+    
+    
+    
+    
+
+    /**
+     * Writes an explanatory message and a stack trace
+     * for a given <code>Throwable</code> exception
+     * to the servlet log file. The name and type of the servlet log 
+     * file is specific to the servlet container, usually an event log.
+     *
+     *
+     * @param message 		a <code>String</code> that 
+     *				describes the error or exception
+     *
+     * @param throwable 	the <code>Throwable</code> error 
+     *				or exception
+     *
+     */
+    
+    public void log(String message, Throwable throwable);
+    
+    
+    
+    
+    
+    /**
+     * Returns a <code>String</code> containing the real path 
+     * for a given virtual path. For example, the path "/index.html"
+     * returns the absolute file path on the server's filesystem would be
+     * served by a request for "http://host/contextPath/index.html",
+     * where contextPath is the context path of this ServletContext..
+     *
+     * <p>The real path returned will be in a form
+     * appropriate to the computer and operating system on
+     * which the servlet container is running, including the
+     * proper path separators. This method returns <code>null</code>
+     * if the servlet container cannot translate the virtual path
+     * to a real path for any reason (such as when the content is
+     * being made available from a <code>.war</code> archive).
+     *
+     *
+     * @param path 	a <code>String</code> specifying a virtual path
+     *
+     *
+     * @return 		a <code>String</code> specifying the real path,
+     *                  or null if the translation cannot be performed
+     *			
+     *
+     */
+
+    public String getRealPath(String path);
+    
+    
+
+
+    /**
+     * Returns the name and version of the servlet container on which
+     * the servlet is running. 
+     *
+     * <p>The form of the returned string is 
+     * <i>servername</i>/<i>versionnumber</i>.
+     * For example, the JavaServer Web Development Kit may return the string
+     * <code>JavaServer Web Dev Kit/1.0</code>.
+     *
+     * <p>The servlet container may return other optional information 
+     * after the primary string in parentheses, for example,
+     * <code>JavaServer Web Dev Kit/1.0 (JDK 1.1.6; Windows NT 4.0 x86)</code>.
+     *
+     *
+     * @return 		a <code>String</code> containing at least the 
+     *			servlet container name and version number
+     *
+     */
+
+    public String getServerInfo();
+    
+    
+
+
+    /**
+     * Returns a <code>String</code> containing the value of the named
+     * context-wide initialization parameter, or <code>null</code> if the 
+     * parameter does not exist.
+     *
+     * <p>This method can make available configuration information useful
+     * to an entire "web application".  For example, it can provide a 
+     * webmaster's email address or the name of a system that holds 
+     * critical data.
+     *
+     * @param	name	a <code>String</code> containing the name of the
+     *                  parameter whose value is requested
+     * 
+     * @return 		a <code>String</code> containing at least the 
+     *			servlet container name and version number
+     *
+     * @see ServletConfig#getInitParameter
+     */
+
+    public String getInitParameter(String name);
+    
+    
+
+
+    /**
+     * Returns the names of the context's initialization parameters as an
+     * <code>Enumeration</code> of <code>String</code> objects, or an
+     * empty <code>Enumeration</code> if the context has no initialization
+     * parameters.
+     *
+     * @return 		an <code>Enumeration</code> of <code>String</code> 
+     *                  objects containing the names of the context's
+     *                  initialization parameters
+     *
+     * @see ServletConfig#getInitParameter
+     */
+
+    public Enumeration getInitParameterNames();
+    
+    
+
+    /**
+     * Returns the servlet container attribute with the given name, 
+     * or <code>null</code> if there is no attribute by that name.
+     * An attribute allows a servlet container to give the
+     * servlet additional information not
+     * already provided by this interface. See your
+     * server documentation for information about its attributes.
+     * A list of supported attributes can be retrieved using
+     * <code>getAttributeNames</code>.
+     *
+     * <p>The attribute is returned as a <code>java.lang.Object</code>
+     * or some subclass.
+     * Attribute names should follow the same convention as package
+     * names. The Java Servlet API specification reserves names
+     * matching <code>java.*</code>, <code>javax.*</code>,
+     * and <code>sun.*</code>.
+     *
+     *
+     * @param name 	a <code>String</code> specifying the name 
+     *			of the attribute
+     *
+     * @return 		an <code>Object</code> containing the value 
+     *			of the attribute, or <code>null</code>
+     *			if no attribute exists matching the given
+     *			name
+     *
+     * @see 		ServletContext#getAttributeNames
+     *
+     */
+  
+    public Object getAttribute(String name);
+    
+    
+    
+
+    /**
+     * Returns an <code>Enumeration</code> containing the 
+     * attribute names available
+     * within this servlet context. Use the
+     * {@link #getAttribute} method with an attribute name
+     * to get the value of an attribute.
+     *
+     * @return 		an <code>Enumeration</code> of attribute 
+     *			names
+     *
+     * @see		#getAttribute
+     *
+     */
+
+    public Enumeration getAttributeNames();
+    
+    
+    
+    
+    /**
+     *
+     * Binds an object to a given attribute name in this servlet context. If
+     * the name specified is already used for an attribute, this
+     * method will replace the attribute with the new to the new attribute.
+     * <p>If listeners are configured on the <code>ServletContext</code> the  
+     * container notifies them accordingly.
+     * <p>
+     * If a null value is passed, the effect is the same as calling 
+     * <code>removeAttribute()</code>.
+     * 
+     * <p>Attribute names should follow the same convention as package
+     * names. The Java Servlet API specification reserves names
+     * matching <code>java.*</code>, <code>javax.*</code>, and
+     * <code>sun.*</code>.
+     *
+     *
+     * @param name 	a <code>String</code> specifying the name 
+     *			of the attribute
+     *
+     * @param object 	an <code>Object</code> representing the
+     *			attribute to be bound
+     *
+     *
+     *
+     */
+    
+    public void setAttribute(String name, Object object);
+    
+    
+
+
+
+    /**
+     * Removes the attribute with the given name from 
+     * the servlet context. After removal, subsequent calls to
+     * {@link #getAttribute} to retrieve the attribute's value
+     * will return <code>null</code>.
+
+     * <p>If listeners are configured on the <code>ServletContext</code> the 
+     * container notifies them accordingly.
+
+     *
+     *
+     * @param name	a <code>String</code> specifying the name 
+     * 			of the attribute to be removed
+     *
+     */
+
+    public void removeAttribute(String name);
+    
+    /**
+     * Returns the name of this web application corresponding to this ServletContext as specified in the deployment
+     * descriptor for this web application by the display-name element.
+     *
+     *
+     * @return	    The name of the web application or null if no name has been declared in the deployment descriptor.
+     * @since Servlet 2.3
+     */
+    
+    public String getServletContextName();
+}
+
+

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/ServletContextAttributeEvent.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/ServletContextAttributeEvent.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/ServletContextAttributeEvent.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,59 @@
+/*
+* Copyright 2004 The Apache Software Foundation
+*
+* Licensed 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;
+
+
+	/** 
+	* This is the event class for notifications about changes to the attributes of the
+	*  servlet context of a web application.
+	* @see ServletContextAttributeListener
+	 * @since	v 2.3
+	*/
+
+public class ServletContextAttributeEvent extends ServletContextEvent { 
+	private String name;
+	private Object value;
+
+	/** Construct a ServletContextAttributeEvent from the given context for the
+	** given attribute name and attribute value. 
+	*/
+	public ServletContextAttributeEvent(ServletContext source, String name, Object value) {
+	    super(source);
+	    this.name = name;
+	    this.value = value;
+	}
+	
+	/**
+	* Return the name of the attribute that changed on the ServletContext.
+	*
+	*/
+	public String getName() {
+		return this.name;
+	}
+	
+	/**
+	* Returns the value of the attribute that has been added, removed, or replaced.
+	* If the attribute was added, this is the value of the attribute. If the attribute was
+	* removed, this is the value of the removed attribute. If the attribute was replaced, this
+	* is the old value of the attribute.
+	*
+	*/
+	
+	public Object getValue() {
+	    return this.value;   
+	}
+}
+

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/ServletContextAttributeListener.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/ServletContextAttributeListener.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/ServletContextAttributeListener.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,36 @@
+/*
+* Copyright 2004 The Apache Software Foundation
+*
+* Licensed 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;
+
+import java.util.EventListener;
+
+	/** Implementations of this interface receive notifications of
+	** changes to the attribute list on the servlet context of a web application. 
+	* To receive notification events, the implementation class
+	* must be configured in the deployment descriptor for the web application.
+	* @see ServletContextAttributeEvent
+	 * @since	v 2.3
+	*/
+
+public interface ServletContextAttributeListener extends EventListener {
+	/** Notification that a new attribute was added to the servlet context. Called after the attribute is added.*/
+public void attributeAdded(ServletContextAttributeEvent scab);
+	/** Notification that an existing attribute has been removed from the servlet context. Called after the attribute is removed.*/
+public void attributeRemoved(ServletContextAttributeEvent scab);
+	/** Notification that an attribute on the servlet context has been replaced. Called after the attribute is replaced. */
+public void attributeReplaced(ServletContextAttributeEvent scab);
+}
+

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/ServletContextEvent.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/ServletContextEvent.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/ServletContextEvent.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,46 @@
+/*
+* Copyright 2004 The Apache Software Foundation
+*
+* Licensed 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;
+
+
+	/** 
+	 * This is the event class for notifications about changes to
+	 * the servlet context of a web application.
+	 * @see ServletContextListener
+	 * @since	v 2.3
+	 */
+
+public class ServletContextEvent extends java.util.EventObject { 
+
+	/** Construct a ServletContextEvent from the given context.
+	 *
+	 * @param source - the ServletContext that is sending the event.
+	 */
+    public ServletContextEvent(ServletContext source) {
+	super(source);
+    }
+    
+	/**
+	 * Return the ServletContext that changed.
+	 *
+	 * @return the ServletContext that sent the event.
+	 */
+    public ServletContext getServletContext () { 
+	return (ServletContext) super.getSource();
+    }
+    
+}
+

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/ServletContextListener.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/ServletContextListener.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/ServletContextListener.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,50 @@
+/*
+* Copyright 2004 The Apache Software Foundation
+*
+* Licensed 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;
+
+import java.util.EventListener;
+
+	/** 
+	 * Implementations of this interface receive notifications about
+	 * changes to the servlet context of the web application they are
+	 * part of.
+	 * To receive notification events, the implementation class
+	 * must be configured in the deployment descriptor for the web
+	 * application.
+	 * @see ServletContextEvent
+	 * @since	v 2.3
+	 */
+
+public interface ServletContextListener extends EventListener {
+	/**
+	 ** Notification that the web application initialization
+	 ** process is starting.
+	 ** All ServletContextListeners are notified of context
+	 ** initialization before any filter or servlet in the web
+	 ** application is initialized.
+	 */
+
+    public void contextInitialized ( ServletContextEvent sce );
+
+	/**
+	 ** Notification that the servlet context is about to be shut down.
+	 ** All servlets and filters have been destroy()ed before any
+	 ** ServletContextListeners are notified of context
+	 ** destruction.
+	 */
+    public void contextDestroyed ( ServletContextEvent sce );
+}
+

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/ServletException.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/ServletException.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/ServletException.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,141 @@
+/*
+* Copyright 2004 The Apache Software Foundation
+*
+* Licensed 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;
+
+
+/**
+ * Defines a general exception a servlet can throw when it
+ * encounters difficulty.
+ *
+ * @author 	Various
+ * @version 	$Version$
+ *
+ */
+
+
+public class ServletException extends Exception {
+
+    private Throwable rootCause;
+
+
+
+
+
+    /**
+     * Constructs a new servlet exception.
+     *
+     */
+
+    public ServletException() {
+	super();
+    }
+    
+   
+
+    
+
+    /**
+     * Constructs a new servlet exception with the
+     * specified message. The message can be written 
+     * to the server log and/or displayed for the user. 
+     *
+     * @param message 		a <code>String</code> 
+     *				specifying the text of 
+     *				the exception message
+     *
+     */
+
+    public ServletException(String message) {
+	super(message);
+    }
+    
+   
+   
+    
+
+    /**
+     * Constructs a new servlet exception when the servlet 
+     * needs to throw an exception and include a message 
+     * about the "root cause" exception that interfered with its 
+     * normal operation, including a description message.
+     *
+     *
+     * @param message 		a <code>String</code> containing 
+     *				the text of the exception message
+     *
+     * @param rootCause		the <code>Throwable</code> exception 
+     *				that interfered with the servlet's
+     *				normal operation, making this servlet
+     *				exception necessary
+     *
+     */
+    
+    public ServletException(String message, Throwable rootCause) {
+	super(message);
+	this.rootCause = rootCause;
+    }
+
+
+
+
+
+    /**
+     * Constructs a new servlet exception when the servlet 
+     * needs to throw an exception and include a message
+     * about the "root cause" exception that interfered with its
+     * normal operation.  The exception's message is based on the localized
+     * message of the underlying exception.
+     *
+     * <p>This method calls the <code>getLocalizedMessage</code> method
+     * on the <code>Throwable</code> exception to get a localized exception
+     * message. When subclassing <code>ServletException</code>, 
+     * this method can be overridden to create an exception message 
+     * designed for a specific locale.
+     *
+     * @param rootCause 	the <code>Throwable</code> exception
+     * 				that interfered with the servlet's
+     *				normal operation, making the servlet exception
+     *				necessary
+     *
+     */
+
+    public ServletException(Throwable rootCause) {
+	super(rootCause.getLocalizedMessage());
+	this.rootCause = rootCause;
+    }
+  
+  
+ 
+ 
+    
+    /**
+     * Returns the exception that caused this servlet exception.
+     *
+     *
+     * @return			the <code>Throwable</code> 
+     *				that caused this servlet exception
+     *
+     */
+    
+    public Throwable getRootCause() {
+	return rootCause;
+    }
+}
+
+
+
+
+

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/ServletInputStream.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/ServletInputStream.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/ServletInputStream.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,105 @@
+/*
+* Copyright 2004 The Apache Software Foundation
+*
+* Licensed 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;
+
+import java.io.InputStream;
+import java.io.IOException;
+
+/**
+ * 
+ * Provides an input stream for reading binary data from a client
+ * request, including an efficient <code>readLine</code> method
+ * for reading data one line at a time. With some protocols, such
+ * as HTTP POST and PUT, a <code>ServletInputStream</code>
+ * object can be used to read data sent from the client.
+ *
+ * <p>A <code>ServletInputStream</code> object is normally retrieved via
+ * the {@link ServletRequest#getInputStream} method.
+ *
+ *
+ * <p>This is an abstract class that a servlet container implements.
+ * Subclasses of this class
+ * must implement the <code>java.io.InputStream.read()</code> method.
+ *
+ *
+ * @author 	Various
+ * @version 	$Version$
+ *
+ * @see		ServletRequest 
+ *
+ */
+
+public abstract class ServletInputStream extends InputStream {
+
+
+
+    /**
+     * Does nothing, because this is an abstract class.
+     *
+     */
+
+    protected ServletInputStream() { }
+
+  
+  
+    
+    /**
+     *
+     * Reads the input stream, one line at a time. Starting at an
+     * offset, reads bytes into an array, until it reads a certain number
+     * of bytes or reaches a newline character, which it reads into the
+     * array as well.
+     *
+     * <p>This method returns -1 if it reaches the end of the input
+     * stream before reading the maximum number of bytes.
+     *
+     *
+     *
+     * @param b 		an array of bytes into which data is read
+     *
+     * @param off 		an integer specifying the character at which
+     *				this method begins reading
+     *
+     * @param len		an integer specifying the maximum number of 
+     *				bytes to read
+     *
+     * @return			an integer specifying the actual number of bytes 
+     *				read, or -1 if the end of the stream is reached
+     *
+     * @exception IOException	if an input or output exception has occurred
+     *
+     */
+     
+    public int readLine(byte[] b, int off, int len) throws IOException {
+
+	if (len <= 0) {
+	    return 0;
+	}
+	int count = 0, c;
+
+	while ((c = read()) != -1) {
+	    b[off++] = (byte)c;
+	    count++;
+	    if (c == '\n' || count == len) {
+		break;
+	    }
+	}
+	return count > 0 ? count : -1;
+    }
+}
+
+
+

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/ServletOutputStream.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/ServletOutputStream.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/ServletOutputStream.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,363 @@
+/*
+* Copyright 2004 The Apache Software Foundation
+*
+* Licensed 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;
+
+import java.io.OutputStream;
+import java.io.IOException;
+import java.io.CharConversionException;
+import java.text.MessageFormat;
+import java.util.ResourceBundle;
+
+/**
+ * Provides an output stream for sending binary data to the
+ * client. A <code>ServletOutputStream</code> object is normally retrieved 
+ * via the {@link ServletResponse#getOutputStream} method.
+ *
+ * <p>This is an abstract class that the servlet container implements.
+ * Subclasses of this class
+ * must implement the <code>java.io.OutputStream.write(int)</code>
+ * method.
+ *
+ * 
+ * @author 	Various
+ * @version 	$Version$
+ *
+ * @see 	ServletResponse
+ *
+ */
+
+public abstract class ServletOutputStream extends OutputStream {
+
+    private static final String LSTRING_FILE = "javax.servlet.LocalStrings";
+    private static ResourceBundle lStrings =
+	ResourceBundle.getBundle(LSTRING_FILE);
+
+
+    
+    /**
+     *
+     * Does nothing, because this is an abstract class.
+     *
+     */
+
+    protected ServletOutputStream() { }
+
+
+    /**
+     * Writes a <code>String</code> to the client, 
+     * without a carriage return-line feed (CRLF) 
+     * character at the end.
+     *
+     *
+     * @param s			the <code>String</code> to send to the client
+     *
+     * @exception IOException 	if an input or output exception occurred
+     *
+     */
+
+    public void print(String s) throws IOException {
+	if (s==null) s="null";
+	int len = s.length();
+	for (int i = 0; i < len; i++) {
+	    char c = s.charAt (i);
+
+	    //
+	    // XXX NOTE:  This is clearly incorrect for many strings,
+	    // but is the only consistent approach within the current
+	    // servlet framework.  It must suffice until servlet output
+	    // streams properly encode their output.
+	    //
+	    if ((c & 0xff00) != 0) {	// high order byte must be zero
+		String errMsg = lStrings.getString("err.not_iso8859_1");
+		Object[] errArgs = new Object[1];
+		errArgs[0] = new Character(c);
+		errMsg = MessageFormat.format(errMsg, errArgs);
+		throw new CharConversionException(errMsg);
+	    }
+	    write (c);
+	}
+    }
+
+
+
+    /**
+     * Writes a <code>boolean</code> value to the client,
+     * with no carriage return-line feed (CRLF) 
+     * character at the end.
+     *
+     * @param b			the <code>boolean</code> value 
+     *				to send to the client
+     *
+     * @exception IOException 	if an input or output exception occurred
+     *
+     */
+
+    public void print(boolean b) throws IOException {
+	String msg;
+	if (b) {
+	    msg = lStrings.getString("value.true");
+	} else {
+	    msg = lStrings.getString("value.false");
+	}
+	print(msg);
+    }
+
+
+
+    /**
+     * Writes a character to the client,
+     * with no carriage return-line feed (CRLF) 
+     * at the end.
+     *
+     * @param c			the character to send to the client
+     *
+     * @exception IOException 	if an input or output exception occurred
+     *
+     */
+
+    public void print(char c) throws IOException {
+	print(String.valueOf(c));
+    }
+
+
+
+
+    /**
+     *
+     * Writes an int to the client,
+     * with no carriage return-line feed (CRLF) 
+     * at the end.
+     *
+     * @param i			the int to send to the client
+     *
+     * @exception IOException 	if an input or output exception occurred
+     *
+     */  
+
+    public void print(int i) throws IOException {
+	print(String.valueOf(i));
+    }
+
+
+
+ 
+    /**
+     * 
+     * Writes a <code>long</code> value to the client,
+     * with no carriage return-line feed (CRLF) at the end.
+     *
+     * @param l			the <code>long</code> value 
+     *				to send to the client
+     *
+     * @exception IOException 	if an input or output exception 
+     *				occurred
+     * 
+     */
+
+    public void print(long l) throws IOException {
+	print(String.valueOf(l));
+    }
+
+
+
+    /**
+     *
+     * Writes a <code>float</code> value to the client,
+     * with no carriage return-line feed (CRLF) at the end.
+     *
+     * @param f			the <code>float</code> value
+     *				to send to the client
+     *
+     * @exception IOException	if an input or output exception occurred
+     *
+     *
+     */
+
+    public void print(float f) throws IOException {
+	print(String.valueOf(f));
+    }
+
+
+
+    /**
+     *
+     * Writes a <code>double</code> value to the client,
+     * with no carriage return-line feed (CRLF) at the end.
+     * 
+     * @param d			the <code>double</code> value
+     *				to send to the client
+     *
+     * @exception IOException 	if an input or output exception occurred
+     *
+     */
+
+    public void print(double d) throws IOException {
+	print(String.valueOf(d));
+    }
+
+
+
+    /**
+     * Writes a carriage return-line feed (CRLF)
+     * to the client.
+     *
+     *
+     *
+     * @exception IOException 	if an input or output exception occurred
+     *
+     */
+
+    public void println() throws IOException {
+	print("\r\n");
+    }
+
+
+
+    /**
+     * Writes a <code>String</code> to the client, 
+     * followed by a carriage return-line feed (CRLF).
+     *
+     *
+     * @param s			the <code>String</code> to write to the client
+     *
+     * @exception IOException 	if an input or output exception occurred
+     *
+     */
+
+    public void println(String s) throws IOException {
+	print(s);
+	println();
+    }
+
+
+
+
+    /**
+     *
+     * Writes a <code>boolean</code> value to the client, 
+     * followed by a 
+     * carriage return-line feed (CRLF).
+     *
+     *
+     * @param b			the <code>boolean</code> value 
+     *				to write to the client
+     *
+     * @exception IOException 	if an input or output exception occurred
+     *
+     */
+
+    public void println(boolean b) throws IOException {
+	print(b);
+	println();
+    }
+
+
+
+    /**
+     *
+     * Writes a character to the client, followed by a carriage
+     * return-line feed (CRLF).
+     *
+     * @param c			the character to write to the client
+     *
+     * @exception IOException 	if an input or output exception occurred
+     *
+     */
+
+    public void println(char c) throws IOException {
+	print(c);
+	println();
+    }
+
+
+
+    /**
+     *
+     * Writes an int to the client, followed by a 
+     * carriage return-line feed (CRLF) character.
+     *
+     *
+     * @param i			the int to write to the client
+     *
+     * @exception IOException 	if an input or output exception occurred
+     *
+     */
+
+    public void println(int i) throws IOException {
+	print(i);
+	println();
+    }
+
+
+
+    /**  
+     *
+     * Writes a <code>long</code> value to the client, followed by a 
+     * carriage return-line feed (CRLF).
+     *
+     *
+     * @param l			the <code>long</code> value to write to the client
+     *
+     * @exception IOException 	if an input or output exception occurred
+     *
+     */  
+
+    public void println(long l) throws IOException {
+	print(l);
+	println();
+    }
+
+
+
+    /**
+     *
+     * Writes a <code>float</code> value to the client, 
+     * followed by a carriage return-line feed (CRLF).
+     *
+     * @param f			the <code>float</code> value 
+     *				to write to the client
+     *
+     *
+     * @exception IOException 	if an input or output exception 
+     *				occurred
+     *
+     */
+
+    public void println(float f) throws IOException {
+	print(f);
+	println();
+    }
+
+
+
+    /**
+     *
+     * Writes a <code>double</code> value to the client, 
+     * followed by a carriage return-line feed (CRLF).
+     *
+     *
+     * @param d			the <code>double</code> value
+     *				to write to the client
+     *
+     * @exception IOException 	if an input or output exception occurred
+     *
+     */
+
+    public void println(double d) throws IOException {
+	print(d);
+	println();
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/ServletRequest.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/ServletRequest.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/ServletRequest.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,597 @@
+/*
+* Copyright 2004 The Apache Software Foundation
+*
+* Licensed 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;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.util.Enumeration;
+import java.util.Locale;
+import java.util.Map;
+
+
+
+/**
+ * Defines an object to provide client request information to a servlet.  The
+ * servlet container creates a <code>ServletRequest</code> object and passes
+ * it as an argument to the servlet's <code>service</code> method.
+ *
+ * <p>A <code>ServletRequest</code> object provides data including
+ * parameter name and values, attributes, and an input stream.
+ * Interfaces that extend <code>ServletRequest</code> can provide
+ * additional protocol-specific data (for example, HTTP data is
+ * provided by {@link javax.servlet.http.HttpServletRequest}.
+ * 
+ * @author 	Various
+ * @version 	$Version$
+ *
+ * @see 	javax.servlet.http.HttpServletRequest
+ *
+ */
+
+public interface ServletRequest {
+
+
+
+
+    /**
+     *
+     * Returns the value of the named attribute as an <code>Object</code>,
+     * or <code>null</code> if no attribute of the given name exists. 
+     *
+     * <p> Attributes can be set two ways.  The servlet container may set
+     * attributes to make available custom information about a request.
+     * For example, for requests made using HTTPS, the attribute
+     * <code>javax.servlet.request.X509Certificate</code> can be used to
+     * retrieve information on the certificate of the client.  Attributes
+     * can also be set programatically using 
+     * {@link ServletRequest#setAttribute}.  This allows information to be
+     * embedded into a request before a {@link RequestDispatcher} call.
+     *
+     * <p>Attribute names should follow the same conventions as package
+     * names. This specification reserves names matching <code>java.*</code>,
+     * <code>javax.*</code>, and <code>sun.*</code>. 
+     *
+     * @param name	a <code>String</code> specifying the name of 
+     *			the attribute
+     *
+     * @return		an <code>Object</code> containing the value 
+     *			of the attribute, or <code>null</code> if
+     *			the attribute does not exist
+     *
+     */
+
+    public Object getAttribute(String name);
+    
+    
+
+    /**
+     * Returns an <code>Enumeration</code> containing the
+     * names of the attributes available to this request. 
+     * This method returns an empty <code>Enumeration</code>
+     * if the request has no attributes available to it.
+     * 
+     *
+     * @return		an <code>Enumeration</code> of strings 
+     *			containing the names 
+     * 			of the request's attributes
+     *
+     */
+
+    public Enumeration getAttributeNames();
+    
+    
+    
+    
+    /**
+     * Returns the name of the character encoding used in the body of this
+     * request. This method returns <code>null</code> if the request
+     * does not specify a character encoding
+     * 
+     *
+     * @return		a <code>String</code> containing the name of 
+     *			the character encoding, or <code>null</code>
+     *			if the request does not specify a character encoding
+     *
+     */
+
+    public String getCharacterEncoding();
+
+ /**
+     * Overrides the name of the character encoding used in the body of this
+     * request. This method must be called prior to reading request parameters
+     * or reading input using getReader().
+     * 
+     *
+     * @param env	a <code>String</code> containing the name of 
+     *			the character encoding.
+     * @throws		java.io.UnsupportedEncodingException if this is not a valid encoding
+     */
+
+    public void setCharacterEncoding(String env) throws java.io.UnsupportedEncodingException;
+
+    
+    
+    
+    
+    /**
+     * Returns the length, in bytes, of the request body 
+     * and made available by the input stream, or -1 if the
+     * length is not known. For HTTP servlets, same as the value
+     * of the CGI variable CONTENT_LENGTH.
+     *
+     * @return		an integer containing the length of the 
+     * 			request body or -1 if the length is not known
+     *
+     */
+
+    public int getContentLength();
+    
+    
+    
+
+    /**
+     * Returns the MIME type of the body of the request, or 
+     * <code>null</code> if the type is not known. For HTTP servlets, 
+     * same as the value of the CGI variable CONTENT_TYPE.
+     *
+     * @return		a <code>String</code> containing the name 
+     *			of the MIME type of 
+     * 			the request, or null if the type is not known
+     *
+     */
+
+    public String getContentType();
+    
+    
+    
+
+    /**
+     * Retrieves the body of the request as binary data using
+     * a {@link ServletInputStream}.  Either this method or 
+     * {@link #getReader} may be called to read the body, not both.
+     *
+     * @return			a {@link ServletInputStream} object containing
+     * 				the body of the request
+     *
+     * @exception IllegalStateException  if the {@link #getReader} method
+     * 					 has already been called for this request
+     *
+     * @exception IOException    	if an input or output exception occurred
+     *
+     */
+
+    public ServletInputStream getInputStream() throws IOException; 
+     
+    
+    
+
+    /**
+     * Returns the value of a request parameter as a <code>String</code>,
+     * or <code>null</code> if the parameter does not exist. Request parameters
+     * are extra information sent with the request.  For HTTP servlets,
+     * parameters are contained in the query string or posted form data.
+     *
+     * <p>You should only use this method when you are sure the
+     * parameter has only one value. If the parameter might have
+     * more than one value, use {@link #getParameterValues}.
+     *
+     * <p>If you use this method with a multivalued
+     * parameter, the value returned is equal to the first value
+     * in the array returned by <code>getParameterValues</code>.
+     *
+     * <p>If the parameter data was sent in the request body, such as occurs
+     * with an HTTP POST request, then reading the body directly via {@link
+     * #getInputStream} or {@link #getReader} can interfere
+     * with the execution of this method.
+     *
+     * @param name 	a <code>String</code> specifying the 
+     *			name of the parameter
+     *
+     * @return		a <code>String</code> representing the 
+     *			single value of the parameter
+     *
+     * @see 		#getParameterValues
+     *
+     */
+
+    public String getParameter(String name);
+    
+    
+    
+
+    /**
+     *
+     * Returns an <code>Enumeration</code> of <code>String</code>
+     * objects containing the names of the parameters contained
+     * in this request. If the request has 
+     * no parameters, the method returns an 
+     * empty <code>Enumeration</code>. 
+     *
+     * @return		an <code>Enumeration</code> of <code>String</code>
+     *			objects, each <code>String</code> containing
+     * 			the name of a request parameter; or an 
+     *			empty <code>Enumeration</code> if the
+     *			request has no parameters
+     *
+     */
+     
+    public Enumeration getParameterNames();
+    
+    
+    
+
+    /**
+     * Returns an array of <code>String</code> objects containing 
+     * all of the values the given request parameter has, or 
+     * <code>null</code> if the parameter does not exist.
+     *
+     * <p>If the parameter has a single value, the array has a length
+     * of 1.
+     *
+     * @param name	a <code>String</code> containing the name of 
+     *			the parameter whose value is requested
+     *
+     * @return		an array of <code>String</code> objects 
+     *			containing the parameter's values
+     *
+     * @see		#getParameter
+     *
+     */
+
+    public String[] getParameterValues(String name);
+ 
+    /** Returns a java.util.Map of the parameters of this request.
+     * Request parameters
+     * are extra information sent with the request.  For HTTP servlets,
+     * parameters are contained in the query string or posted form data.
+     *
+     * @return an immutable java.util.Map containing parameter names as 
+     * keys and parameter values as map values. The keys in the parameter
+     * map are of type String. The values in the parameter map are of type
+     * String array.
+     *
+     */
+
+    public Map getParameterMap();
+    
+    
+
+    /**
+     * Returns the name and version of the protocol the request uses
+     * in the form <i>protocol/majorVersion.minorVersion</i>, for 
+     * example, HTTP/1.1. For HTTP servlets, the value
+     * returned is the same as the value of the CGI variable 
+     * <code>SERVER_PROTOCOL</code>.
+     *
+     * @return		a <code>String</code> containing the protocol 
+     *			name and version number
+     *
+     */
+    
+    public String getProtocol();
+    
+    
+    
+
+    /**
+     * Returns the name of the scheme used to make this request, 
+     * for example,
+     * <code>http</code>, <code>https</code>, or <code>ftp</code>.
+     * Different schemes have different rules for constructing URLs,
+     * as noted in RFC 1738.
+     *
+     * @return		a <code>String</code> containing the name 
+     *			of the scheme used to make this request
+     *
+     */
+
+    public String getScheme();
+    
+    
+    
+
+    /**
+     * Returns the host name of the server to which the request was sent.
+     * It is the value of the part before ":" in the <code>Host</code>
+     * header value, if any, or the resolved server name, or the server IP address.
+     *
+     * @return		a <code>String</code> containing the name 
+     *			of the server
+     */
+
+    public String getServerName();
+    
+    
+    
+
+    /**
+     * Returns the port number to which the request was sent.
+     * It is the value of the part after ":" in the <code>Host</code>
+     * header value, if any, or the server port where the client connection
+     * was accepted on.
+     *
+     * @return		an integer specifying the port number
+     *
+     */
+
+    public int getServerPort();
+    
+    
+    
+    /**
+     * Retrieves the body of the request as character data using
+     * a <code>BufferedReader</code>.  The reader translates the character
+     * data according to the character encoding used on the body.
+     * Either this method or {@link #getInputStream} may be called to read the
+     * body, not both.
+     * 
+     *
+     * @return					a <code>BufferedReader</code>
+     *						containing the body of the request	
+     *
+     * @exception UnsupportedEncodingException 	if the character set encoding
+     * 						used is not supported and the 
+     *						text cannot be decoded
+     *
+     * @exception IllegalStateException   	if {@link #getInputStream} method
+     * 						has been called on this request
+     *
+     * @exception IOException  			if an input or output exception occurred
+     *
+     * @see 					#getInputStream
+     *
+     */
+
+    public BufferedReader getReader() throws IOException;
+    
+    
+    
+
+    /**
+     * Returns the Internet Protocol (IP) address of the client 
+     * or last proxy that sent the request.
+     * For HTTP servlets, same as the value of the 
+     * CGI variable <code>REMOTE_ADDR</code>.
+     *
+     * @return		a <code>String</code> containing the 
+     *			IP address of the client that sent the request
+     *
+     */
+    
+    public String getRemoteAddr();
+    
+    
+    
+
+    /**
+     * Returns the fully qualified name of the client
+     * or the last proxy that sent the request.
+     * If the engine cannot or chooses not to resolve the hostname 
+     * (to improve performance), this method returns the dotted-string form of 
+     * the IP address. For HTTP servlets, same as the value of the CGI variable 
+     * <code>REMOTE_HOST</code>.
+     *
+     * @return		a <code>String</code> containing the fully 
+     *			qualified name of the client
+     *
+     */
+
+    public String getRemoteHost();
+    
+    
+    
+
+    /**
+     *
+     * Stores an attribute in this request.
+     * Attributes are reset between requests.  This method is most
+     * often used in conjunction with {@link RequestDispatcher}.
+     *
+     * <p>Attribute names should follow the same conventions as
+     * package names. Names beginning with <code>java.*</code>,
+     * <code>javax.*</code>, and <code>com.sun.*</code>, are
+     * reserved for use by Sun Microsystems.
+     *<br> If the object passed in is null, the effect is the same as
+     * calling {@link #removeAttribute}.
+     * <br> It is warned that when the request is dispatched from the
+     * servlet resides in a different web application by
+     * <code>RequestDispatcher</code>, the object set by this method
+     * may not be correctly retrieved in the caller servlet.
+     *
+     *
+     * @param name			a <code>String</code> specifying 
+     *					the name of the attribute
+     *
+     * @param o				the <code>Object</code> to be stored
+     *
+     */
+
+    public void setAttribute(String name, Object o);
+    
+    
+    
+
+    /**
+     *
+     * Removes an attribute from this request.  This method is not
+     * generally needed as attributes only persist as long as the request
+     * is being handled.
+     *
+     * <p>Attribute names should follow the same conventions as
+     * package names. Names beginning with <code>java.*</code>,
+     * <code>javax.*</code>, and <code>com.sun.*</code>, are
+     * reserved for use by Sun Microsystems.
+     *
+     *
+     * @param name			a <code>String</code> specifying 
+     *					the name of the attribute to remove
+     *
+     */
+
+    public void removeAttribute(String name);
+    
+    
+    
+
+    /**
+     *
+     * Returns the preferred <code>Locale</code> that the client will 
+     * accept content in, based on the Accept-Language header.
+     * If the client request doesn't provide an Accept-Language header,
+     * this method returns the default locale for the server.
+     *
+     *
+     * @return		the preferred <code>Locale</code> for the client
+     *
+     */
+
+    public Locale getLocale();
+    
+    
+    
+
+    /**
+     *
+     * Returns an <code>Enumeration</code> of <code>Locale</code> objects
+     * indicating, in decreasing order starting with the preferred locale, the
+     * locales that are acceptable to the client based on the Accept-Language
+     * header.
+     * If the client request doesn't provide an Accept-Language header,
+     * this method returns an <code>Enumeration</code> containing one 
+     * <code>Locale</code>, the default locale for the server.
+     *
+     *
+     * @return		an <code>Enumeration</code> of preferred 
+     *                  <code>Locale</code> objects for the client
+     *
+     */
+
+    public Enumeration getLocales();
+    
+    
+    
+
+    /**
+     *
+     * Returns a boolean indicating whether this request was made using a
+     * secure channel, such as HTTPS.
+     *
+     *
+     * @return		a boolean indicating if the request was made using a
+     *                  secure channel
+     *
+     */
+
+    public boolean isSecure();
+    
+    
+    
+
+    /**
+     *
+     * Returns a {@link RequestDispatcher} object that acts as a wrapper for
+     * the resource located at the given path.  
+     * A <code>RequestDispatcher</code> object can be used to forward
+     * a request to the resource or to include the resource in a response.
+     * The resource can be dynamic or static.
+     *
+     * <p>The pathname specified may be relative, although it cannot extend
+     * outside the current servlet context.  If the path begins with 
+     * a "/" it is interpreted as relative to the current context root.  
+     * This method returns <code>null</code> if the servlet container
+     * cannot return a <code>RequestDispatcher</code>.
+     *
+     * <p>The difference between this method and {@link
+     * ServletContext#getRequestDispatcher} is that this method can take a
+     * relative path.
+     *
+     * @param path      a <code>String</code> specifying the pathname
+     *                  to the resource. If it is relative, it must be
+     *                  relative against the current servlet.
+     *
+     * @return          a <code>RequestDispatcher</code> object
+     *                  that acts as a wrapper for the resource
+     *                  at the specified path, or <code>null</code>
+     *                  if the servlet container cannot return a
+     *                  <code>RequestDispatcher</code>
+     *
+     * @see             RequestDispatcher
+     * @see             ServletContext#getRequestDispatcher
+     *
+     */
+
+    public RequestDispatcher getRequestDispatcher(String path);
+    
+    
+    
+
+    /**
+     * 
+     * @deprecated 	As of Version 2.1 of the Java Servlet API,
+     * 			use {@link ServletContext#getRealPath} instead.
+     *
+     */
+
+    public String getRealPath(String path);
+    
+    
+    /**
+     * Returns the Internet Protocol (IP) source port of the client
+     * or last proxy that sent the request.
+     *
+     * @return	an integer specifying the port number
+     *
+     * @since 2.4
+     */    
+    public int getRemotePort();
+
+
+    /**
+     * Returns the host name of the Internet Protocol (IP) interface on
+     * which the request was received.
+     *
+     * @return	a <code>String</code> containing the host
+     *		name of the IP on which the request was received.
+     *
+     * @since 2.4
+     */
+    public String getLocalName();
+
+    /**
+     * Returns the Internet Protocol (IP) address of the interface on
+     * which the request  was received.
+     *
+     * @return	a <code>String</code> containing the
+     *		IP address on which the request was received. 
+     *
+     * @since 2.4
+     *
+     */       
+    public String getLocalAddr();
+
+
+    /**
+     * Returns the Internet Protocol (IP) port number of the interface
+     * on which the request was received.
+     *
+     * @return an integer specifying the port number
+     *
+     * @since 2.4
+     */
+    public int getLocalPort();
+
+}
+

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/ServletRequestAttributeEvent.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/ServletRequestAttributeEvent.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/ServletRequestAttributeEvent.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,66 @@
+/*
+* Copyright 2004 The Apache Software Foundation
+*
+* Licensed 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;
+
+
+    /** 
+      * This is the event class for notifications of changes to the 
+      * attributes of the servlet request in an application.
+      * @see ServletRequestAttributeListener
+      * @since	Servlet 2.4
+      */
+
+public class ServletRequestAttributeEvent extends ServletRequestEvent { 
+    private String name;
+    private Object value;
+
+     /** Construct a ServletRequestAttributeEvent giving the servlet context
+      * of this web application, the ServletRequest whose attributes are
+      * changing and the name and value of the attribute.
+      *
+      * @param sc		the ServletContext that is sending the event.
+      * @param request		the ServletRequest that is sending the event.
+      * @param name		the name of the request attribute.
+      * @param value		the value of the request attribute.
+      */
+    public ServletRequestAttributeEvent(ServletContext sc, ServletRequest request, String name, Object value) {
+        super(sc, request);
+        this.name = name;
+        this.value = value;
+    }
+
+    /**
+      * Return the name of the attribute that changed on the ServletRequest.
+      *
+      * @return		the name of the changed request attribute
+      */
+    public String getName() {
+        return this.name;
+    }
+
+    /**
+      * Returns the value of the attribute that has been added, removed or 
+      * replaced. If the attribute was added, this is the value of the 
+      * attribute. If the attribute was removed, this is the value of the 
+      * removed attribute. If the attribute was replaced, this is the old 
+      * value of the attribute.
+      *
+      * @return		the value of the changed request attribute
+      */
+    public Object getValue() {
+        return this.value;   
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/ServletRequestAttributeListener.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/ServletRequestAttributeListener.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/ServletRequestAttributeListener.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,49 @@
+/*
+* Copyright 2004 The Apache Software Foundation
+*
+* Licensed 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;
+
+import java.util.EventListener;
+
+    /**
+     * A ServletRequestAttributeListener can be implemented by the
+     * developer interested in being notified of request attribute
+     * changes. Notifications will be generated while the request
+     * is within the scope of the web application in which the listener
+     * is registered. A request is defined as coming into scope when
+     * it is about to enter the first servlet or filter in each web
+     * application, as going out of scope when it exits the last servlet
+     * or the first filter in the chain.
+     *
+     * @since Servlet 2.4
+     */
+
+public interface ServletRequestAttributeListener extends EventListener {
+    /** Notification that a new attribute was added to the
+     ** servlet request. Called after the attribute is added.
+     */
+    public void attributeAdded(ServletRequestAttributeEvent srae);
+
+    /** Notification that an existing attribute has been removed from the
+     ** servlet request. Called after the attribute is removed.
+     */
+    public void attributeRemoved(ServletRequestAttributeEvent srae);
+
+    /** Notification that an attribute was replaced on the
+     ** servlet request. Called after the attribute is replaced.
+     */
+    public void attributeReplaced(ServletRequestAttributeEvent srae);
+}
+

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/ServletRequestEvent.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/ServletRequestEvent.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/ServletRequestEvent.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,55 @@
+/*
+* Copyright 2004 The Apache Software Foundation
+*
+* Licensed 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;
+
+
+    /** 
+      * Events of this kind indicate lifecycle
+      * events for a ServletRequest.
+      * The source of the event
+      * is the ServletContext of this web application.
+      * @see ServletRequestListener
+      * @since	Servlet 2.4
+      */
+
+public class ServletRequestEvent extends java.util.EventObject { 
+    private ServletRequest request;
+
+    /** Construct a ServletRequestEvent for the given ServletContext
+      * and ServletRequest.
+      *
+      * @param sc		the ServletContext of the web application.
+      * @param request		the ServletRequest that is sending the event.
+      */
+    public ServletRequestEvent(ServletContext sc, ServletRequest request) {
+        super(sc);
+        this.request = request;
+    }
+    
+    /**
+      * Returns the ServletRequest that is changing.
+      */
+    public ServletRequest getServletRequest () { 
+        return this.request;
+    }
+
+    /**
+      * Returns the ServletContext of this web application.
+      */
+    public ServletContext getServletContext () { 
+        return (ServletContext) super.getSource();
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/ServletRequestListener.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/ServletRequestListener.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/ServletRequestListener.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,39 @@
+/*
+* Copyright 2004 The Apache Software Foundation
+*
+* Licensed 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;
+
+import java.util.EventListener;
+
+    /**
+     * A ServletRequestListener can be implemented by the developer
+     * interested in being notified of requests coming in and out of
+     * scope in a web component. A request is defined as coming into
+     * scope when it is about to enter the first servlet or filter
+     * in each web application, as going out of scope when it exits
+     * the last servlet or the first filter in the chain.
+     *
+     * @since Servlet 2.4
+     */
+
+
+public interface ServletRequestListener extends EventListener {
+
+    /** The request is about to go out of scope of the web application. */
+    public void requestDestroyed ( ServletRequestEvent sre );
+
+    /** The request is about to come into scope of the web application. */
+    public void requestInitialized ( ServletRequestEvent sre );
+}

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/ServletRequestWrapper.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/ServletRequestWrapper.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/ServletRequestWrapper.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,400 @@
+/*
+* Copyright 2004 The Apache Software Foundation
+*
+* Licensed 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;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.util.Enumeration;
+import java.util.Locale;
+import java.util.Map;
+
+
+
+/**
+ * 
+ * Provides a convenient implementation of the ServletRequest interface that
+ * can be subclassed by developers wishing to adapt the request to a Servlet.
+ * This class implements the Wrapper or Decorator pattern. Methods default to
+ * calling through to the wrapped request object.
+  * @since	v 2.3
+ * 
+ * 
+ *
+ * @see 	javax.servlet.ServletRequest
+ *
+ */
+
+public class ServletRequestWrapper implements ServletRequest {
+    private ServletRequest request;
+
+	/**
+	* Creates a ServletRequest adaptor wrapping the given request object. 
+	* @throws java.lang.IllegalArgumentException if the request is null
+	*/
+
+    public ServletRequestWrapper(ServletRequest request) {
+	if (request == null) {
+	    throw new IllegalArgumentException("Request cannot be null");   
+	}
+	this.request = request;
+    }
+
+	/**
+	* Return the wrapped request object.
+	*/
+	public ServletRequest getRequest() {
+		return this.request;
+	}
+	
+	/**
+	* Sets the request object being wrapped. 
+	* @throws java.lang.IllegalArgumentException if the request is null.
+	*/
+	
+	public void setRequest(ServletRequest request) {
+	    if (request == null) {
+		throw new IllegalArgumentException("Request cannot be null");
+	    }
+	    this.request = request;
+	}
+
+    /**
+     *
+     * The default behavior of this method is to call getAttribute(String name)
+     * on the wrapped request object.
+     */
+
+    public Object getAttribute(String name) {
+	return this.request.getAttribute(name);
+	}
+    
+    
+
+    /**
+     * The default behavior of this method is to return getAttributeNames()
+     * on the wrapped request object.
+     */
+
+    public Enumeration getAttributeNames() {
+	return this.request.getAttributeNames();
+	}    
+    
+    
+    
+    /**
+      * The default behavior of this method is to return getCharacterEncoding()
+     * on the wrapped request object.
+     */
+
+    public String getCharacterEncoding() {
+	return this.request.getCharacterEncoding();
+	}
+	
+    /**
+      * The default behavior of this method is to set the character encoding
+     * on the wrapped request object.
+     */
+
+    public void setCharacterEncoding(String enc) throws java.io.UnsupportedEncodingException {
+	this.request.setCharacterEncoding(enc);
+	}
+    
+    
+    /**
+      * The default behavior of this method is to return getContentLength()
+     * on the wrapped request object.
+     */
+
+    public int getContentLength() {
+	return this.request.getContentLength();
+    }
+    
+    
+    
+
+       /**
+      * The default behavior of this method is to return getContentType()
+     * on the wrapped request object.
+     */
+    public String getContentType() {
+	return this.request.getContentType();
+    }
+    
+    
+    
+
+     /**
+      * The default behavior of this method is to return getInputStream()
+     * on the wrapped request object.
+     */
+
+    public ServletInputStream getInputStream() throws IOException {
+	return this.request.getInputStream();
+	}
+     
+    
+    
+
+    /**
+      * The default behavior of this method is to return getParameter(String name)
+     * on the wrapped request object.
+     */
+
+    public String getParameter(String name) {
+	return this.request.getParameter(name);
+    }
+    
+    /**
+      * The default behavior of this method is to return getParameterMap()
+     * on the wrapped request object.
+     */
+    public Map getParameterMap() {
+	return this.request.getParameterMap();
+    }
+    
+    
+    
+
+    /**
+      * The default behavior of this method is to return getParameterNames()
+     * on the wrapped request object.
+     */
+     
+    public Enumeration getParameterNames() {
+	return this.request.getParameterNames();
+    }
+    
+    
+    
+
+       /**
+      * The default behavior of this method is to return getParameterValues(String name)
+     * on the wrapped request object.
+     */
+    public String[] getParameterValues(String name) {
+	return this.request.getParameterValues(name);
+	}
+    
+    
+    
+
+     /**
+      * The default behavior of this method is to return getProtocol()
+     * on the wrapped request object.
+     */
+    
+    public String getProtocol() {
+	return this.request.getProtocol();
+	}
+    
+    
+    
+
+    /**
+      * The default behavior of this method is to return getScheme()
+     * on the wrapped request object.
+     */
+    
+
+    public String getScheme() {
+	return this.request.getScheme();
+	}
+    
+    
+    
+
+    /**
+      * The default behavior of this method is to return getServerName()
+     * on the wrapped request object.
+     */
+    public String getServerName() {
+	return this.request.getServerName();
+	}
+    
+    
+    
+
+   /**
+      * The default behavior of this method is to return getServerPort()
+     * on the wrapped request object.
+     */
+
+    public int getServerPort() {
+	return this.request.getServerPort();
+	}
+    
+    
+    
+  /**
+      * The default behavior of this method is to return getReader()
+     * on the wrapped request object.
+     */
+
+    public BufferedReader getReader() throws IOException {
+	return this.request.getReader();
+	}
+    
+    
+    
+
+    /**
+      * The default behavior of this method is to return getRemoteAddr()
+     * on the wrapped request object.
+     */
+    
+    public String getRemoteAddr() {
+	return this.request.getRemoteAddr();
+    }
+    
+    
+    
+
+      /**
+      * The default behavior of this method is to return getRemoteHost()
+     * on the wrapped request object.
+     */
+
+    public String getRemoteHost() {
+	return this.request.getRemoteHost();
+    }
+    
+    
+    
+
+    /**
+      * The default behavior of this method is to return setAttribute(String name, Object o)
+     * on the wrapped request object.
+     */
+
+    public void setAttribute(String name, Object o) {
+	this.request.setAttribute(name, o);
+    }
+    
+    
+    
+
+    /**
+      * The default behavior of this method is to call removeAttribute(String name)
+     * on the wrapped request object.
+     */
+    public void removeAttribute(String name) {
+	this.request.removeAttribute(name);
+    }
+    
+    
+    
+
+   /**
+      * The default behavior of this method is to return getLocale()
+     * on the wrapped request object.
+     */
+
+    public Locale getLocale() {
+	return this.request.getLocale();
+    }
+    
+    
+    
+
+     /**
+      * The default behavior of this method is to return getLocales()
+     * on the wrapped request object.
+     */
+
+    public Enumeration getLocales() {
+	return this.request.getLocales();
+    }
+    
+    
+    
+
+    /**
+      * The default behavior of this method is to return isSecure()
+     * on the wrapped request object.
+     */
+
+    public boolean isSecure() {
+	return this.request.isSecure();
+    }
+    
+    
+    
+
+    /**
+      * The default behavior of this method is to return getRequestDispatcher(String path)
+     * on the wrapped request object.
+     */
+
+    public RequestDispatcher getRequestDispatcher(String path) {
+	return this.request.getRequestDispatcher(path);
+    }
+    
+    
+    
+
+    /**
+      * The default behavior of this method is to return getRealPath(String path)
+     * on the wrapped request object.
+     */
+
+    public String getRealPath(String path) {
+	return this.request.getRealPath(path);
+    }
+    
+    /**
+     * The default behavior of this method is to return
+     * getRemotePort() on the wrapped request object.
+     *
+     * @since 2.4
+     */    
+    public int getRemotePort(){
+        return this.request.getRemotePort();
+    }
+
+
+    /**
+     * The default behavior of this method is to return
+     * getLocalName() on the wrapped request object.
+     *
+     * @since 2.4
+     */
+    public String getLocalName(){
+        return this.request.getLocalName();
+    }
+
+    /**
+     * The default behavior of this method is to return
+     * getLocalAddr() on the wrapped request object.
+     *
+     * @since 2.4
+     */       
+    public String getLocalAddr(){
+        return this.request.getLocalAddr();
+    }
+
+
+    /**
+     * The default behavior of this method is to return
+     * getLocalPort() on the wrapped request object.
+     *
+     * @since 2.4
+     */
+    public int getLocalPort(){
+        return this.request.getLocalPort();
+    }
+    
+}
+

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/ServletResponse.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/ServletResponse.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/ServletResponse.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,452 @@
+/*
+* Copyright 2004 The Apache Software Foundation
+*
+* Licensed 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;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.Locale;
+
+
+/**
+ * Defines an object to assist a servlet in sending a response to the client.
+ * The servlet container creates a <code>ServletResponse</code> object and
+ * passes it as an argument to the servlet's <code>service</code> method.
+ *
+ * <p>To send binary data in a MIME body response, use
+ * the {@link ServletOutputStream} returned by {@link #getOutputStream}.
+ * To send character data, use the <code>PrintWriter</code> object 
+ * returned by {@link #getWriter}. To mix binary and text data,
+ * for example, to create a multipart response, use a
+ * <code>ServletOutputStream</code> and manage the character sections
+ * manually.
+ *
+ * <p>The charset for the MIME body response can be specified
+ * explicitly using the {@link #setCharacterEncoding} and
+ * {@link #setContentType} methods, or implicitly
+ * using the {@link #setLocale} method.
+ * Explicit specifications take precedence over
+ * implicit specifications. If no charset is specified, ISO-8859-1 will be
+ * used. The <code>setCharacterEncoding</code>,
+ * <code>setContentType</code>, or <code>setLocale</code> method must
+ * be called before <code>getWriter</code> and before committing
+ * the response for the character encoding to be used.
+ * 
+ * <p>See the Internet RFCs such as 
+ * <a href="http://www.ietf.org/rfc/rfc2045.txt">
+ * RFC 2045</a> for more information on MIME. Protocols such as SMTP
+ * and HTTP define profiles of MIME, and those standards
+ * are still evolving.
+ *
+ * @author 	Various
+ * @version 	$Version$
+ *
+ * @see		ServletOutputStream
+ *
+ */
+ 
+public interface ServletResponse {
+
+
+    
+    /**
+     * Returns the name of the character encoding (MIME charset)
+     * used for the body sent in this response.
+     * The character encoding may have been specified explicitly
+     * using the {@link #setCharacterEncoding} or
+     * {@link #setContentType} methods, or implicitly using the
+     * {@link #setLocale} method. Explicit specifications take
+     * precedence over implicit specifications. Calls made
+     * to these methods after <code>getWriter</code> has been
+     * called or after the response has been committed have no
+     * effect on the character encoding. If no character encoding
+     * has been specified, <code>ISO-8859-1</code> is returned.
+     * <p>See RFC 2047 (http://www.ietf.org/rfc/rfc2047.txt)
+     * for more information about character encoding and MIME.
+     *
+     * @return		a <code>String</code> specifying the
+     *			name of the character encoding, for
+     *			example, <code>UTF-8</code>
+     *
+     */
+  
+    public String getCharacterEncoding();
+    
+    
+
+    /**
+     * Returns the content type used for the MIME body
+     * sent in this response. The content type proper must
+     * have been specified using {@link #setContentType}
+     * before the response is committed. If no content type
+     * has been specified, this method returns null.
+     * If a content type has been specified and a
+     * character encoding has been explicitly or implicitly
+     * specified as described in {@link #getCharacterEncoding},
+     * the charset parameter is included in the string returned.
+     * If no character encoding has been specified, the
+     * charset parameter is omitted.
+     *
+     * @return		a <code>String</code> specifying the
+     *			content type, for example,
+     *			<code>text/html; charset=UTF-8</code>,
+     *			or null
+     *
+     * @since 2.4
+     */
+  
+    public String getContentType();
+    
+    
+
+    /**
+     * Returns a {@link ServletOutputStream} suitable for writing binary 
+     * data in the response. The servlet container does not encode the
+     * binary data.  
+     
+     * <p> Calling flush() on the ServletOutputStream commits the response.
+     
+     * Either this method or {@link #getWriter} may 
+     * be called to write the body, not both.
+     *
+     * @return				a {@link ServletOutputStream} for writing binary data	
+     *
+     * @exception IllegalStateException if the <code>getWriter</code> method
+     * 					has been called on this response
+     *
+     * @exception IOException 		if an input or output exception occurred
+     *
+     * @see 				#getWriter
+     *
+     */
+
+    public ServletOutputStream getOutputStream() throws IOException;
+    
+    
+
+    /**
+     * Returns a <code>PrintWriter</code> object that
+     * can send character text to the client.
+     * The <code>PrintWriter</code> uses the character
+     * encoding returned by {@link #getCharacterEncoding}.
+     * If the response's character encoding has not been
+     * specified as described in <code>getCharacterEncoding</code>
+     * (i.e., the method just returns the default value 
+     * <code>ISO-8859-1</code>), <code>getWriter</code>
+     * updates it to <code>ISO-8859-1</code>.
+     * <p>Calling flush() on the <code>PrintWriter</code>
+     * commits the response.
+     * <p>Either this method or {@link #getOutputStream} may be called
+     * to write the body, not both.
+     *
+     * 
+     * @return 		a <code>PrintWriter</code> object that 
+     *			can return character data to the client 
+     *
+     * @exception UnsupportedEncodingException
+     *			if the character encoding returned
+     *			by <code>getCharacterEncoding</code> cannot be used
+     *
+     * @exception IllegalStateException
+     *			if the <code>getOutputStream</code>
+     * 			method has already been called for this 
+     *			response object
+     *
+     * @exception IOException
+     *			if an input or output exception occurred
+     *
+     * @see 		#getOutputStream
+     * @see 		#setCharacterEncoding
+     *
+     */
+
+    public PrintWriter getWriter() throws IOException;
+    
+    
+    
+    
+    /**
+     * Sets the character encoding (MIME charset) of the response
+     * being sent to the client, for example, to UTF-8.
+     * If the character encoding has already been set by
+     * {@link #setContentType} or {@link #setLocale},
+     * this method overrides it.
+     * Calling {@link #setContentType} with the <code>String</code>
+     * of <code>text/html</code> and calling
+     * this method with the <code>String</code> of <code>UTF-8</code>
+     * is equivalent with calling
+     * <code>setContentType</code> with the <code>String</code> of
+     * <code>text/html; charset=UTF-8</code>.
+     * <p>This method can be called repeatedly to change the character
+     * encoding.
+     * This method has no effect if it is called after
+     * <code>getWriter</code> has been
+     * called or after the response has been committed.
+     * <p>Containers must communicate the character encoding used for
+     * the servlet response's writer to the client if the protocol
+     * provides a way for doing so. In the case of HTTP, the character
+     * encoding is communicated as part of the <code>Content-Type</code>
+     * header for text media types. Note that the character encoding
+     * cannot be communicated via HTTP headers if the servlet does not
+     * specify a content type; however, it is still used to encode text
+     * written via the servlet response's writer.
+     *
+     * @param charset 	a String specifying only the character set
+     * 			defined by IANA Character Sets
+     *			(http://www.iana.org/assignments/character-sets)
+     *
+     * @see		#setContentType
+     * 			#setLocale
+     *
+     * @since 2.4
+     *
+     */
+
+    public void setCharacterEncoding(String charset);
+    
+    
+
+
+    /**
+     * Sets the length of the content body in the response
+     * In HTTP servlets, this method sets the HTTP Content-Length header.
+     *
+     *
+     * @param len 	an integer specifying the length of the 
+     * 			content being returned to the client; sets
+     *			the Content-Length header
+     *
+     */
+
+    public void setContentLength(int len);
+    
+    
+
+    /**
+     * Sets the content type of the response being sent to
+     * the client, if the response has not been committed yet.
+     * The given content type may include a character encoding
+     * specification, for example, <code>text/html;charset=UTF-8</code>.
+     * The response's character encoding is only set from the given
+     * content type if this method is called before <code>getWriter</code>
+     * is called.
+     * <p>This method may be called repeatedly to change content type and
+     * character encoding.
+     * This method has no effect if called after the response
+     * has been committed. It does not set the response's character
+     * encoding if it is called after <code>getWriter</code>
+     * has been called or after the response has been committed.
+     * <p>Containers must communicate the content type and the character
+     * encoding used for the servlet response's writer to the client if
+     * the protocol provides a way for doing so. In the case of HTTP,
+     * the <code>Content-Type</code> header is used.
+     *
+     * @param type 	a <code>String</code> specifying the MIME 
+     *			type of the content
+     *
+     * @see 		#setLocale
+     * @see 		#setCharacterEncoding
+     * @see 		#getOutputStream
+     * @see 		#getWriter
+     *
+     */
+
+    public void setContentType(String type);
+    
+
+    /**
+     * Sets the preferred buffer size for the body of the response.  
+     * The servlet container will use a buffer at least as large as 
+     * the size requested.  The actual buffer size used can be found
+     * using <code>getBufferSize</code>.
+     *
+     * <p>A larger buffer allows more content to be written before anything is
+     * actually sent, thus providing the servlet with more time to set
+     * appropriate status codes and headers.  A smaller buffer decreases 
+     * server memory load and allows the client to start receiving data more
+     * quickly.
+     *
+     * <p>This method must be called before any response body content is
+     * written; if content has been written or the response object has
+     * been committed, this method throws an 
+     * <code>IllegalStateException</code>.
+     *
+     * @param size 	the preferred buffer size
+     *
+     * @exception  IllegalStateException  	if this method is called after
+     *						content has been written
+     *
+     * @see 		#getBufferSize
+     * @see 		#flushBuffer
+     * @see 		#isCommitted
+     * @see 		#reset
+     *
+     */
+
+    public void setBufferSize(int size);
+    
+    
+
+    /**
+     * Returns the actual buffer size used for the response.  If no buffering
+     * is used, this method returns 0.
+     *
+     * @return	 	the actual buffer size used
+     *
+     * @see 		#setBufferSize
+     * @see 		#flushBuffer
+     * @see 		#isCommitted
+     * @see 		#reset
+     *
+     */
+
+    public int getBufferSize();
+    
+    
+
+    /**
+     * Forces any content in the buffer to be written to the client.  A call
+     * to this method automatically commits the response, meaning the status 
+     * code and headers will be written.
+     *
+     * @see 		#setBufferSize
+     * @see 		#getBufferSize
+     * @see 		#isCommitted
+     * @see 		#reset
+     *
+     */
+
+    public void flushBuffer() throws IOException;
+    
+    
+    
+    /**
+     * Clears the content of the underlying buffer in the response without
+     * clearing headers or status code. If the 
+     * response has been committed, this method throws an 
+     * <code>IllegalStateException</code>.
+     *
+     * @see 		#setBufferSize
+     * @see 		#getBufferSize
+     * @see 		#isCommitted
+     * @see 		#reset
+     *
+     * @since 2.3
+     */
+
+    public void resetBuffer();
+    
+
+    /**
+     * Returns a boolean indicating if the response has been
+     * committed.  A committed response has already had its status 
+     * code and headers written.
+     *
+     * @return		a boolean indicating if the response has been
+     *  		committed
+     *
+     * @see 		#setBufferSize
+     * @see 		#getBufferSize
+     * @see 		#flushBuffer
+     * @see 		#reset
+     *
+     */
+
+    public boolean isCommitted();
+    
+    
+
+    /**
+     * Clears any data that exists in the buffer as well as the status code and
+     * headers.  If the response has been committed, this method throws an 
+     * <code>IllegalStateException</code>.
+     *
+     * @exception IllegalStateException  if the response has already been
+     *                                   committed
+     *
+     * @see 		#setBufferSize
+     * @see 		#getBufferSize
+     * @see 		#flushBuffer
+     * @see 		#isCommitted
+     *
+     */
+
+    public void reset();
+    
+    
+
+    /**
+     * Sets the locale of the response, if the response has not been
+     * committed yet. It also sets the response's character encoding
+     * appropriately for the locale, if the character encoding has not
+     * been explicitly set using {@link #setContentType} or
+     * {@link #setCharacterEncoding}, <code>getWriter</code> hasn't
+     * been called yet, and the response hasn't been committed yet.
+     * If the deployment descriptor contains a 
+     * <code>locale-encoding-mapping-list</code> element, and that
+     * element provides a mapping for the given locale, that mapping
+     * is used. Otherwise, the mapping from locale to character
+     * encoding is container dependent.
+     * <p>This method may be called repeatedly to change locale and
+     * character encoding. The method has no effect if called after the
+     * response has been committed. It does not set the response's
+     * character encoding if it is called after {@link #setContentType}
+     * has been called with a charset specification, after
+     * {@link #setCharacterEncoding} has been called, after
+     * <code>getWriter</code> has been called, or after the response
+     * has been committed.
+     * <p>Containers must communicate the locale and the character encoding
+     * used for the servlet response's writer to the client if the protocol
+     * provides a way for doing so. In the case of HTTP, the locale is
+     * communicated via the <code>Content-Language</code> header,
+     * the character encoding as part of the <code>Content-Type</code>
+     * header for text media types. Note that the character encoding
+     * cannot be communicated via HTTP headers if the servlet does not
+     * specify a content type; however, it is still used to encode text
+     * written via the servlet response's writer.
+     * 
+     * @param loc  the locale of the response
+     *
+     * @see 		#getLocale
+     * @see 		#setContentType
+     * @see 		#setCharacterEncoding
+     *
+     */
+
+    public void setLocale(Locale loc);
+    
+    
+
+    /**
+     * Returns the locale specified for this response
+     * using the {@link #setLocale} method. Calls made to
+     * <code>setLocale</code> after the response is committed
+     * have no effect. If no locale has been specified,
+     * the container's default locale is returned.
+     * 
+     * @see 		#setLocale
+     *
+     */
+
+    public Locale getLocale();
+
+
+
+}
+
+
+
+
+

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/ServletResponseWrapper.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/ServletResponseWrapper.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/ServletResponseWrapper.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,217 @@
+/*
+* Copyright 2004 The Apache Software Foundation
+*
+* Licensed 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;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.Locale;
+
+/**
+ * 
+ * Provides a convenient implementation of the ServletResponse interface that
+ * can be subclassed by developers wishing to adapt the response from a Servlet.
+ * This class implements the Wrapper or Decorator pattern. Methods default to
+ * calling through to the wrapped response object.
+ * 
+ * @author 	Various
+ * @version 	$Version$
+ * @since	v 2.3
+ *
+ * @see 	javax.servlet.ServletResponse
+ *
+ */
+
+ 
+public class ServletResponseWrapper implements ServletResponse {
+	private ServletResponse response;
+	/**
+	* Creates a ServletResponse adaptor wrapping the given response object.
+	* @throws java.lang.IllegalArgumentException if the response is null.
+	*/
+
+
+	public ServletResponseWrapper(ServletResponse response) {
+	    if (response == null) {
+		throw new IllegalArgumentException("Response cannot be null");
+	    }
+	    this.response = response;
+	}
+
+	/**
+	* Return the wrapped ServletResponse object.
+	*/
+
+	public ServletResponse getResponse() {
+		return this.response;
+	}	
+	
+	
+	/**
+	* Sets the response being wrapped. 
+	* @throws java.lang.IllegalArgumentException if the response is null.
+	*/
+	
+	public void setResponse(ServletResponse response) {
+	    if (response == null) {
+		throw new IllegalArgumentException("Response cannot be null");
+	    }
+	    this.response = response;
+	}
+
+    /**
+     * The default behavior of this method is to call setCharacterEncoding(String charset)
+     * on the wrapped response object.
+     *
+     * @since 2.4
+     */
+
+    public void setCharacterEncoding(String charset) {
+	this.response.setCharacterEncoding(charset);
+    }
+
+    /**
+     * The default behavior of this method is to return getCharacterEncoding()
+     * on the wrapped response object.
+     */
+
+    public String getCharacterEncoding() {
+	return this.response.getCharacterEncoding();
+	}
+    
+    
+	  /**
+     * The default behavior of this method is to return getOutputStream()
+     * on the wrapped response object.
+     */
+
+    public ServletOutputStream getOutputStream() throws IOException {
+	return this.response.getOutputStream();
+    }  
+      
+     /**
+     * The default behavior of this method is to return getWriter()
+     * on the wrapped response object.
+     */
+
+
+    public PrintWriter getWriter() throws IOException {
+	return this.response.getWriter();
+	}
+    
+    /**
+     * The default behavior of this method is to call setContentLength(int len)
+     * on the wrapped response object.
+     */
+
+    public void setContentLength(int len) {
+	this.response.setContentLength(len);
+    }
+    
+    /**
+     * The default behavior of this method is to call setContentType(String type)
+     * on the wrapped response object.
+     */
+
+    public void setContentType(String type) {
+	this.response.setContentType(type);
+    }
+
+    /**
+     * The default behavior of this method is to return getContentType()
+     * on the wrapped response object.
+     *
+     * @since 2.4
+     */
+
+    public String getContentType() {
+	return this.response.getContentType();
+    }
+    
+    /**
+     * The default behavior of this method is to call setBufferSize(int size)
+     * on the wrapped response object.
+     */
+    public void setBufferSize(int size) {
+	this.response.setBufferSize(size);
+    }
+    
+    /**
+     * The default behavior of this method is to return getBufferSize()
+     * on the wrapped response object.
+     */
+    public int getBufferSize() {
+	return this.response.getBufferSize();
+    }
+
+    /**
+     * The default behavior of this method is to call flushBuffer()
+     * on the wrapped response object.
+     */
+
+    public void flushBuffer() throws IOException {
+	this.response.flushBuffer();
+    }
+    
+    /**
+     * The default behavior of this method is to return isCommitted()
+     * on the wrapped response object.
+     */
+    public boolean isCommitted() {
+	return this.response.isCommitted();
+    }
+
+    /**
+     * The default behavior of this method is to call reset()
+     * on the wrapped response object.
+     */
+
+    public void reset() {
+	this.response.reset();
+    }
+    
+    /**
+     * The default behavior of this method is to call resetBuffer()
+     * on the wrapped response object.
+     */
+     
+    public void resetBuffer() {
+	this.response.resetBuffer();
+    }
+    
+    /**
+     * The default behavior of this method is to call setLocale(Locale loc)
+     * on the wrapped response object.
+     */
+
+    public void setLocale(Locale loc) {
+	this.response.setLocale(loc);
+    }
+    
+    /**
+     * The default behavior of this method is to return getLocale()
+     * on the wrapped response object.
+     */
+    public Locale getLocale() {
+	return this.response.getLocale();
+    }
+
+
+}
+
+
+
+
+

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/SingleThreadModel.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/SingleThreadModel.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/SingleThreadModel.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,48 @@
+/*
+* Copyright 2004 The Apache Software Foundation
+*
+* Licensed 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;
+
+/**
+ * Ensures that servlets handle
+ * only one request at a time. This interface has no methods.
+ *
+ * <p>If a servlet implements this interface, you are <i>guaranteed</i>
+ * that no two threads will execute concurrently in the
+ * servlet's <code>service</code> method. The servlet container
+ * can make this guarantee by synchronizing access to a single
+ * instance of the servlet, or by maintaining a pool of servlet
+ * instances and dispatching each new request to a free servlet.
+ *
+ * <p>Note that SingleThreadModel does not solve all thread safety
+ * issues.  For example, session attributes and static variables can
+ * still be accessed by multiple requests on multiple threads
+ * at the same time, even when SingleThreadModel servlets are used.
+ * It is recommended that a developer take other means to resolve
+ * those issues instead of implementing this interface, such as
+ * avoiding the usage of an instance variable or synchronizing
+ * the block of the code accessing those resources.
+ * This interface is deprecated in Servlet API version 2.4.
+ *
+ *
+ * @author	Various
+ * @version	$Version$
+ *
+ * @deprecated	As of Java Servlet API 2.4, with no direct
+ *	replacement.
+ */
+
+public interface SingleThreadModel {
+}

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/UnavailableException.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/UnavailableException.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/UnavailableException.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,205 @@
+/*
+* Copyright 2004 The Apache Software Foundation
+*
+* Licensed 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;
+
+
+/**
+ * Defines an exception that a servlet or filter throws to indicate
+ * that it is permanently or temporarily unavailable. 
+ *
+ * <p>When a servlet or filter is permanently unavailable, something is wrong
+ * with it, and it cannot handle
+ * requests until some action is taken. For example, a servlet
+ * might be configured incorrectly, or a filter's state may be corrupted.
+ * The component should log both the error and the corrective action
+ * that is needed.
+ *
+ * <p>A servlet or filter is temporarily unavailable if it cannot handle
+ * requests momentarily due to some system-wide problem. For example,
+ * a third-tier server might not be accessible, or there may be 
+ * insufficient memory or disk storage to handle requests. A system
+ * administrator may need to take corrective action.
+ *
+ * <p>Servlet containers can safely treat both types of unavailable
+ * exceptions in the same way. However, treating temporary unavailability
+ * effectively makes the servlet container more robust. Specifically,
+ * the servlet container might block requests to the servlet or filter for a period
+ * of time suggested by the exception, rather than rejecting them until
+ * the servlet container restarts.
+ *
+ *
+ * @author 	Various
+ * @version 	$Version$
+ *
+ */
+
+public class UnavailableException
+extends ServletException {
+
+    private Servlet     servlet;           // what's unavailable
+    private boolean     permanent;         // needs admin action?
+    private int         seconds;           // unavailability estimate
+
+    /**
+     * 
+     * @deprecated	As of Java Servlet API 2.2, use {@link
+     * 			#UnavailableException(String)} instead.
+     *
+     * @param servlet 	the <code>Servlet</code> instance that is
+     *                  unavailable
+     *
+     * @param msg 	a <code>String</code> specifying the
+     *                  descriptive message
+     *
+     */
+
+    public UnavailableException(Servlet servlet, String msg) {
+	super(msg);
+	this.servlet = servlet;
+	permanent = true;
+    }
+ 
+    /**
+     * @deprecated	As of Java Servlet API 2.2, use {@link
+     *			#UnavailableException(String, int)} instead.
+     *
+     * @param seconds	an integer specifying the number of seconds
+     * 			the servlet expects to be unavailable; if
+     *			zero or negative, indicates that the servlet
+     *			can't make an estimate
+     *
+     * @param servlet	the <code>Servlet</code> that is unavailable
+     * 
+     * @param msg	a <code>String</code> specifying the descriptive 
+     *			message, which can be written to a log file or 
+     *			displayed for the user.
+     *
+     */
+    
+    public UnavailableException(int seconds, Servlet servlet, String msg) {
+	super(msg);
+	this.servlet = servlet;
+	if (seconds <= 0)
+	    this.seconds = -1;
+	else
+	    this.seconds = seconds;
+	permanent = false;
+    }
+
+    /**
+     * 
+     * Constructs a new exception with a descriptive
+     * message indicating that the servlet is permanently
+     * unavailable.
+     *
+     * @param msg 	a <code>String</code> specifying the
+     *                  descriptive message
+     *
+     */
+
+    public UnavailableException(String msg) {
+	super(msg);
+
+	permanent = true;
+    }
+
+    /**
+     * Constructs a new exception with a descriptive message
+     * indicating that the servlet is temporarily unavailable
+     * and giving an estimate of how long it will be unavailable.
+     * 
+     * <p>In some cases, the servlet cannot make an estimate. For
+     * example, the servlet might know that a server it needs is
+     * not running, but not be able to report how long it will take
+     * to be restored to functionality. This can be indicated with
+     * a negative or zero value for the <code>seconds</code> argument.
+     *
+     * @param msg	a <code>String</code> specifying the
+     *                  descriptive message, which can be written
+     *                  to a log file or displayed for the user.
+     *
+     * @param seconds	an integer specifying the number of seconds
+     * 			the servlet expects to be unavailable; if
+     *			zero or negative, indicates that the servlet
+     *			can't make an estimate
+     *
+     */
+    
+    public UnavailableException(String msg, int seconds) {
+	super(msg);
+
+	if (seconds <= 0)
+	    this.seconds = -1;
+	else
+	    this.seconds = seconds;
+
+	permanent = false;
+    }
+
+    /**
+     *
+     * Returns a <code>boolean</code> indicating
+     * whether the servlet is permanently unavailable.
+     * If so, something is wrong with the servlet, and the
+     * system administrator must take some corrective action.
+     *
+     * @return		<code>true</code> if the servlet is
+     *			permanently unavailable; <code>false</code>
+     *			if the servlet is available or temporarily
+     *			unavailable
+     *
+     */
+     
+    public boolean isPermanent() {
+	return permanent;
+    }
+  
+    /**
+     * @deprecated	As of Java Servlet API 2.2, with no replacement.
+     *
+     * Returns the servlet that is reporting its unavailability.
+     * 
+     * @return		the <code>Servlet</code> object that is 
+     *			throwing the <code>UnavailableException</code>
+     *
+     */
+     
+    public Servlet getServlet() {
+	return servlet;
+    }
+
+    /**
+     * Returns the number of seconds the servlet expects to 
+     * be temporarily unavailable.  
+     *
+     * <p>If this method returns a negative number, the servlet
+     * is permanently unavailable or cannot provide an estimate of
+     * how long it will be unavailable. No effort is
+     * made to correct for the time elapsed since the exception was
+     * first reported.
+     *
+     * @return		an integer specifying the number of seconds
+     *			the servlet will be temporarily unavailable,
+     *			or a negative number if the servlet is permanently
+     *			unavailable or cannot make an estimate
+     *
+     */
+     
+    public int getUnavailableSeconds() {
+	return permanent ? -1 : seconds;
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/http/Cookie.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/http/Cookie.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/http/Cookie.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,536 @@
+/*
+* Copyright 2004 The Apache Software Foundation
+*
+* Licensed 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.text.MessageFormat;
+import java.util.ResourceBundle;
+
+/**
+ *
+ * Creates a cookie, a small amount of information sent by a servlet to 
+ * a Web browser, saved by the browser, and later sent back to the server.
+ * A cookie's value can uniquely 
+ * identify a client, so cookies are commonly used for session management.
+ * 
+ * <p>A cookie has a name, a single value, and optional attributes
+ * such as a comment, path and domain qualifiers, a maximum age, and a
+ * version number. Some Web browsers have bugs in how they handle the 
+ * optional attributes, so use them sparingly to improve the interoperability 
+ * of your servlets.
+ *
+ * <p>The servlet sends cookies to the browser by using the
+ * {@link HttpServletResponse#addCookie} method, which adds
+ * fields to HTTP response headers to send cookies to the 
+ * browser, one at a time. The browser is expected to 
+ * support 20 cookies for each Web server, 300 cookies total, and
+ * may limit cookie size to 4 KB each.
+ * 
+ * <p>The browser returns cookies to the servlet by adding 
+ * fields to HTTP request headers. Cookies can be retrieved
+ * from a request by using the {@link HttpServletRequest#getCookies} method.
+ * Several cookies might have the same name but different path attributes.
+ * 
+ * <p>Cookies affect the caching of the Web pages that use them. 
+ * HTTP 1.0 does not cache pages that use cookies created with
+ * this class. This class does not support the cache control
+ * defined with HTTP 1.1.
+ *
+ * <p>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$
+ *
+ */
+
+// XXX would implement java.io.Serializable too, but can't do that
+// so long as sun.servlet.* must run on older JDK 1.02 JVMs which
+// don't include that support.
+
+public class Cookie implements Cloneable {
+
+    private static final String LSTRING_FILE =
+	"javax.servlet.http.LocalStrings";
+    private static ResourceBundle lStrings =
+	ResourceBundle.getBundle(LSTRING_FILE);
+    
+    //
+    // The value of the cookie itself.
+    //
+    
+    private String name;	// NAME= ... "$Name" style is reserved
+    private String value;	// value of NAME
+
+    //
+    // Attributes encoded in the header's cookie fields.
+    //
+    
+    private String comment;	// ;Comment=VALUE ... describes cookie's use
+				// ;Discard ... implied by maxAge < 0
+    private String domain;	// ;Domain=VALUE ... domain that sees cookie
+    private int maxAge = -1;	// ;Max-Age=VALUE ... cookies auto-expire
+    private String path;	// ;Path=VALUE ... URLs that see the cookie
+    private boolean secure;	// ;Secure ... e.g. use SSL
+    private int version = 0;	// ;Version=1 ... means RFC 2109++ style
+    
+    
+
+    /**
+     * Constructs a cookie with a specified name and value.
+     *
+     * <p>The name must conform to RFC 2109. That means it can contain 
+     * only ASCII alphanumeric characters and cannot contain commas, 
+     * semicolons, or white space or begin with a $ character. The cookie's
+     * name cannot be changed after creation.
+     *
+     * <p>The value can be anything the server chooses to send. Its
+     * value is probably of interest only to the server. The cookie's
+     * value can be changed after creation with the
+     * <code>setValue</code> method.
+     *
+     * <p>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			a <code>String</code> specifying the value of the cookie
+     *
+     * @throws IllegalArgumentException	if the cookie name contains illegal characters
+     *					(for example, a comma, space, or semicolon)
+     *					or it is one of the tokens reserved for use
+     *					by the cookie protocol
+     * @see #setValue
+     * @see #setVersion
+     *
+     */
+
+    public Cookie(String name, String value) {
+	if (!isToken(name)
+		|| name.equalsIgnoreCase("Comment")	// rfc2019
+		|| name.equalsIgnoreCase("Discard")	// 2019++
+		|| name.equalsIgnoreCase("Domain")
+		|| name.equalsIgnoreCase("Expires")	// (old cookies)
+		|| name.equalsIgnoreCase("Max-Age")	// rfc2019
+		|| name.equalsIgnoreCase("Path")
+		|| name.equalsIgnoreCase("Secure")
+		|| name.equalsIgnoreCase("Version")
+		|| name.startsWith("$")
+	    ) {
+	    String errMsg = lStrings.getString("err.cookie_name_is_token");
+	    Object[] errArgs = new Object[1];
+	    errArgs[0] = name;
+	    errMsg = MessageFormat.format(errMsg, errArgs);
+	    throw new IllegalArgumentException(errMsg);
+	}
+
+	this.name = name;
+	this.value = value;
+    }
+
+
+
+
+
+    /**
+     *
+     * 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
+     *
+     * @see #getComment
+     *
+     */
+
+    public void setComment(String purpose) {
+	comment = purpose;
+    }
+    
+    
+    
+
+    /**
+     * 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
+     *
+     */ 
+
+    public String getComment() {
+	return comment;
+    }
+    
+    
+    
+
+
+    /**
+     *
+     * Specifies the domain within which this cookie should be presented.
+     *
+     * <p>The form of the domain name is specified by RFC 2109. A domain
+     * name begins with a dot (<code>.foo.com</code>) and means that
+     * the cookie is 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
+     *
+     * @see #getDomain
+     *
+     */
+
+    public void setDomain(String pattern) {
+	domain = pattern.toLowerCase();	// IE allegedly needs this
+    }
+    
+    
+    
+    
+
+    /**
+     * 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
+     *
+     */ 
+
+    public String getDomain() {
+	return domain;
+    }
+
+
+
+
+    /**
+     * Sets the maximum age of the cookie in seconds.
+     *
+     * <p>A positive value indicates that the cookie will expire
+     * after that many seconds have passed. Note that the value is
+     * the <i>maximum</i> age when the cookie will expire, not the cookie's
+     * current age.
+     *
+     * <p>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, deletes
+     *				the cookie
+     *
+     *
+     * @see #getMaxAge
+     *
+     */
+
+    public void setMaxAge(int expiry) {
+	maxAge = expiry;
+    }
+
+
+
+
+    /**
+     * 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
+     *
+     */
+
+    public int getMaxAge() {
+	return maxAge;
+    }
+    
+    
+    
+
+    /**
+     * Specifies a path for the cookie
+     * to which the client should return the cookie.
+     *
+     * <p>The cookie is visible to all the pages in the directory
+     * you specify, and all the pages in that directory's subdirectories. 
+     * A cookie's path must include the servlet that set the cookie,
+     * for example, <i>/catalog</i>, which makes the cookie
+     * visible to all directories on the server under <i>/catalog</i>.
+     *
+     * <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
+     *
+     */
+
+    public void setPath(String uri) {
+	path = uri;
+    }
+
+
+
+
+    /**
+     * 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
+     *
+     */ 
+
+    public String getPath() {
+	return path;
+    }
+
+
+
+
+
+    /**
+     * Indicates to the browser whether the cookie should only be sent
+     * using a 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 <code>false</code>, sent on any protocol
+     *
+     * @see #getSecure
+     *
+     */
+ 
+    public void setSecure(boolean flag) {
+	secure = flag;
+    }
+
+
+
+
+    /**
+     * 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
+     *
+     */
+
+    public boolean getSecure() {
+	return secure;
+    }
+
+
+
+
+
+    /**
+     * 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() {
+	return name;
+    }
+
+
+
+
+
+    /**
+     *
+     * Assigns a new value to a cookie after the cookie is created.
+     * If you use a binary value, you may want to use BASE64 encoding.
+     *
+     * <p>With Version 0 cookies, values should not contain white 
+     * space, brackets, 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
+     * @see Cookie
+     *
+     */
+
+    public void setValue(String newValue) {
+	value = newValue;
+    }
+
+
+
+
+    /**
+     * Returns the value of the cookie.
+     *
+     * @return			a <code>String</code> containing the cookie's
+     *				present value
+     *
+     * @see #setValue
+     * @see Cookie
+     *
+     */
+
+    public String getValue() {
+	return value;
+    }
+
+
+
+
+    /**
+     * Returns the version of the protocol this cookie complies 
+     * with. Version 1 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
+     *
+     */
+
+    public int getVersion() {
+	return version;
+    }
+
+
+
+
+    /**
+     * Sets the version of the cookie protocol this cookie complies
+     * with. Version 0 complies with the original Netscape cookie
+     * specification. Version 1 complies with RFC 2109.
+     *
+     * <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
+     *
+     * @see #getVersion
+     *
+     */
+
+    public void setVersion(int v) {
+	version = v;
+    }
+
+    // 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 = ",; ";
+    
+    
+    
+
+    /*
+     * Tests a string and returns true if the string counts as a 
+     * reserved token in the Java language.
+     * 
+     * @param value		the <code>String</code> to be tested
+     *
+     * @return			<code>true</code> if the <code>String</code> is
+     *				a reserved token; <code>false</code>
+     *				if it is not			
+     */
+
+    private boolean isToken(String value) {
+	int len = value.length();
+
+	for (int i = 0; i < len; i++) {
+	    char c = value.charAt(i);
+
+	    if (c < 0x20 || c >= 0x7f || tspecials.indexOf(c) != -1)
+		return false;
+	}
+	return true;
+    }
+
+
+
+
+
+
+    /**
+     *
+     * Overrides the standard <code>java.lang.Object.clone</code> 
+     * method to return a copy of this cookie.
+     *		
+     *
+     */
+
+    public Object clone() {
+	try {
+	    return super.clone();
+	} catch (CloneNotSupportedException e) {
+	    throw new RuntimeException(e.getMessage());
+	}
+    }
+}
+

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/http/HttpServlet.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/http/HttpServlet.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/http/HttpServlet.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,1018 @@
+/*
+* Copyright 2004 The Apache Software Foundation
+*
+* Licensed 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.io.PrintWriter;
+import java.io.OutputStreamWriter;
+import java.io.UnsupportedEncodingException;
+import java.lang.reflect.Method;
+import java.text.MessageFormat;
+import java.util.Enumeration;
+import java.util.Locale;
+import java.util.ResourceBundle;
+
+import javax.servlet.GenericServlet;
+import javax.servlet.ServletException;
+import javax.servlet.ServletOutputStream;
+import javax.servlet.ServletRequest;
+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 
+ * one method, usually one of these:
+ *
+ * <ul>
+ * <li> <code>doGet</code>, if the servlet supports HTTP GET requests
+ * <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>, 
+ * 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 
+ * </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>
+ * methods listed above).
+ *
+ * <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 
+ * connections.
+ * See the
+ * <a href="http://java.sun.com/Series/Tutorial/java/threads/multithreaded.html">
+ * Java Tutorial on Multithreaded Programming</a> for more
+ * information on handling multiple threads in a Java program.
+ *
+ * @author	Various
+ * @version	$Version$
+ *
+ */
+
+
+
+public abstract class HttpServlet extends GenericServlet
+    implements java.io.Serializable
+{
+    private static final String METHOD_DELETE = "DELETE";
+    private static final String METHOD_HEAD = "HEAD";
+    private static final String METHOD_GET = "GET";
+    private static final String METHOD_OPTIONS = "OPTIONS";
+    private static final String METHOD_POST = "POST";
+    private static final String METHOD_PUT = "PUT";
+    private static final String METHOD_TRACE = "TRACE";
+
+    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() { }
+    
+    
+
+    /**
+     *
+     * Called by the server (via the <code>service</code> method) to
+     * 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
+     * request is a GET request that returns no body in the
+     * 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 
+     * 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,
+     * 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 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 return its response to the client, improving performance.
+     * The content length is automatically set if the entire response fits
+     * 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.
+     *
+     * <p>The GET method should be safe, that is, without
+     * any side effects for which users are held responsible.
+     * For example, most form queries have no side effects.
+     * If a client request is intended to change stored data,
+     * the request should use some other HTTP method.
+     *
+     * <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, 
+     * repeating queries is both safe and idempotent, but
+     * buying a product online or modifying data is neither
+     * safe nor idempotent. 
+     *
+     * <p>If the request is incorrectly formatted, <code>doGet</code>
+     * returns an HTTP "Bad Request" message.
+     * 
+     *
+     * @param req	an {@link HttpServletRequest} object that
+     *			contains the request the client has made
+     *			of the servlet
+     *
+     * @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 
+     *				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)
+	throws ServletException, IOException
+    {
+	String protocol = req.getProtocol();
+	String msg = lStrings.getString("http.method_get_not_supported");
+	if (protocol.endsWith("1.1")) {
+	    resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, msg);
+	} else {
+	    resp.sendError(HttpServletResponse.SC_BAD_REQUEST, msg);
+	}
+    }
+
+
+
+
+
+    /**
+     *
+     * Returns the time the <code>HttpServletRequest</code>
+     * object was last modified,
+     * in milliseconds since midnight January 1, 1970 GMT.
+     * If the time is unknown, this method returns a negative
+     * number (the default).
+     *
+     * <p>Servlets that support HTTP GET requests and can quickly determine
+     * their last modification time should override this method.
+     * This makes browser and proxy caches work more effectively,
+     * reducing the load on server and network resources.
+     *
+     *
+     * @param req	the <code>HttpServletRequest</code> 
+     *			object that is sent to the servlet
+     *
+     * @return		a <code>long</code> integer specifying
+     *			the time the <code>HttpServletRequest</code>
+     *			object was last modified, in milliseconds
+     *			since midnight, January 1, 1970 GMT, or
+     *			-1 if the time is not known
+     *
+     */
+
+    protected long getLastModified(HttpServletRequest req) {
+	return -1;
+    }
+
+
+
+
+    /**
+     * 
+     *
+     * <p>Receives an HTTP HEAD request from the protected
+     * <code>service</code> method and handles the
+     * request.
+     * The client sends a HEAD request when it wants
+     * to see only the headers of a response, such as
+     * Content-Type or Content-Length. The HTTP HEAD
+     * method counts the output bytes in the response
+     * to set the Content-Length header accurately.
+     *
+     * <p>If you override this method, you can avoid computing
+     * the response body and just set the response headers
+     * directly to improve performance. Make sure that the
+     * <code>doHead</code> method you write is both safe
+     * and idempotent (that is, protects itself from being
+     * called multiple times for one HTTP HEAD request).
+     *
+     * <p>If the HTTP HEAD request is incorrectly formatted,
+     * <code>doHead</code> returns an HTTP "Bad Request"
+     * message.
+     *
+     *
+     * @param req	the request object that is passed
+     *			to the servlet
+     *			
+     * @param resp	the response object that the servlet
+     *			uses to return the headers to the clien
+     *
+     * @exception IOException		if an input or output error occurs
+     *
+     * @exception ServletException	if the request for the HEAD
+     *					could not be handled
+     */
+
+    protected void doHead(HttpServletRequest req, HttpServletResponse resp)
+	throws ServletException, IOException
+    {
+	NoBodyResponse response = new NoBodyResponse(resp);
+	
+	doGet(req, response);
+	response.setContentLength();
+    }
+    
+
+
+
+
+    /**
+     *
+     * Called by the server (via the <code>service</code> method)
+     * to allow a servlet to handle a POST request.
+     *
+     * The HTTP POST method allows the client to send
+     * data of unlimited length to the Web server a single time
+     * and is useful when posting information such as
+     * credit card numbers.
+     *
+     * <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 
+     * 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. 
+     *
+     * <p>The servlet container must write the headers before committing 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 return its response to the client, improving performance.
+     * The content length is automatically set if the entire response fits
+     * 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. 
+     *
+     * <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, 
+     * updating stored data or buying items online.
+     *
+     * <p>If the HTTP POST request is incorrectly formatted,
+     * <code>doPost</code> returns an HTTP "Bad Request" message.
+     *
+     *
+     * @param req	an {@link HttpServletRequest} object that
+     *			contains the request the client has made
+     *			of the servlet
+     *
+     * @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 
+     *				detected when the servlet handles
+     *				the request
+     *
+     * @exception ServletException	if the request for the POST
+     *					could not be handled
+     *
+     *
+     * @see javax.servlet.ServletOutputStream
+     * @see javax.servlet.ServletResponse#setContentType
+     *
+     *
+     */
+
+    protected void doPost(HttpServletRequest req, HttpServletResponse resp)
+	throws ServletException, IOException
+    {
+	String protocol = req.getProtocol();
+	String msg = lStrings.getString("http.method_post_not_supported");
+	if (protocol.endsWith("1.1")) {
+	    resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, msg);
+	} else {
+	    resp.sendError(HttpServletResponse.SC_BAD_REQUEST, msg);
+	}
+    }
+
+
+
+
+    /**
+     * 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 
+     * sending a file by FTP.
+     *
+     * <p>When overriding this method, leave intact
+     * any content headers sent with the request (including
+     * Content-Length, Content-Type, Content-Transfer-Encoding,
+     * Content-Encoding, Content-Base, Content-Language, Content-Location,
+     * Content-MD5, and Content-Range). If your method cannot
+     * handle a content header, it must issue an error message
+     * (HTTP 501 - Not Implemented) and discard the request.
+     * For more information on HTTP 1.1, see RFC 2616
+     * <a href="http://www.ietf.org/rfc/rfc2616.txt"></a>.
+     *
+     * <p>This method does not need to be either safe or idempotent.
+     * Operations that <code>doPut</code> performs can have side
+     * effects for which the user can be held accountable. When using
+     * this method, it may be useful to save a copy of the
+     * affected URL in temporary storage.
+     *
+     * <p>If the HTTP PUT request is incorrectly formatted,
+     * <code>doPut</code> returns an HTTP "Bad Request" message.
+     *
+     *
+     * @param req	the {@link HttpServletRequest} object that
+     *			contains the request the client made of
+     *			the servlet
+     *
+     * @param resp	the {@link HttpServletResponse} object that
+     *			contains the response the servlet returns
+     *			to the client
+     *
+     * @exception IOException	if an input or output error occurs
+     *				while the servlet is handling the
+     *				PUT request
+     *
+     * @exception ServletException	if the request for the PUT
+     *					cannot be handled
+     *
+     */
+  
+    protected void doPut(HttpServletRequest req, HttpServletResponse resp)
+	throws ServletException, IOException
+    {
+	String protocol = req.getProtocol();
+	String msg = lStrings.getString("http.method_put_not_supported");
+	if (protocol.endsWith("1.1")) {
+	    resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, msg);
+	} else {
+	    resp.sendError(HttpServletResponse.SC_BAD_REQUEST, msg);
+	}
+    }
+
+
+
+
+    /**
+     * 
+     * Called by the server (via the <code>service</code> method)
+     * to allow a servlet to handle a DELETE request.
+     *
+     * 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
+     * can be held accountable. When using
+     * this method, it may be useful to save a copy of the
+     * affected URL in temporary storage.
+     *
+     * <p>If the HTTP DELETE request is incorrectly formatted,
+     * <code>doDelete</code> returns an HTTP "Bad Request"
+     * message.
+     *
+     *
+     * @param req	the {@link HttpServletRequest} object that
+     *			contains the request the client made of
+     *			the servlet
+     *
+     *
+     * @param resp	the {@link HttpServletResponse} object that
+     *			contains the response the servlet returns
+     *			to the client				
+     *
+     *
+     * @exception IOException	if an input or output error occurs
+     *				while the servlet is handling the
+     *				DELETE request
+     *
+     * @exception ServletException	if the request for the
+     *					DELETE cannot be handled
+     *
+     */
+     
+    protected void doDelete(HttpServletRequest req,
+			    HttpServletResponse resp)
+	throws ServletException, IOException
+    {
+	String protocol = req.getProtocol();
+	String msg = lStrings.getString("http.method_delete_not_supported");
+	if (protocol.endsWith("1.1")) {
+	    resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, msg);
+	} else {
+	    resp.sendError(HttpServletResponse.SC_BAD_REQUEST, msg);
+	}
+    }
+    
+
+    private static Method[] getAllDeclaredMethods(Class c) {
+
+        if (c.equals(javax.servlet.http.HttpServlet.class)) {
+            return null;
+        }
+
+        Method[] parentMethods = getAllDeclaredMethods(c.getSuperclass());
+        Method[] thisMethods = c.getDeclaredMethods();
+	
+        if ((parentMethods != null) && (parentMethods.length > 0)) {
+            Method[] allMethods =
+                new Method[parentMethods.length + thisMethods.length];
+	    System.arraycopy(parentMethods, 0, allMethods, 0,
+                             parentMethods.length);
+	    System.arraycopy(thisMethods, 0, allMethods, parentMethods.length,
+                             thisMethods.length);
+
+	    thisMethods = allMethods;
+	}
+
+	return thisMethods;
+    }
+
+
+    /**
+     * 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 server supports and
+     * returns an appropriate header. For example, if a servlet
+     * overrides <code>doGet</code>, this method returns the
+     * following header:
+     *
+     * <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 
+     * implemented by HTTP 1.1.
+     *
+     * @param req	the {@link HttpServletRequest} object that
+     *			contains the request the client made of
+     *			the servlet
+     *
+     *
+     * @param resp	the {@link HttpServletResponse} object that
+     *			contains the response the servlet returns
+     *			to the client				
+     *
+     *
+     * @exception IOException	if an input or output error occurs
+     *				while the servlet is handling the
+     *				OPTIONS request
+     *
+     * @exception ServletException	if the request for the
+     *					OPTIONS cannot be handled
+     *
+     */
+         
+    protected void doOptions(HttpServletRequest req, HttpServletResponse resp)
+	throws ServletException, IOException
+    {
+	Method[] methods = getAllDeclaredMethods(this.getClass());
+	
+	boolean ALLOW_GET = false;
+	boolean ALLOW_HEAD = false;
+	boolean ALLOW_POST = false;
+	boolean ALLOW_PUT = false;
+	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")) 
+		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)
+	    if (allow==null) allow=METHOD_GET;
+	if (ALLOW_HEAD)
+	    if (allow==null) allow=METHOD_HEAD;
+	    else allow += ", " + METHOD_HEAD;
+	if (ALLOW_POST)
+	    if (allow==null) allow=METHOD_POST;
+	    else allow += ", " + METHOD_POST;
+	if (ALLOW_PUT)
+	    if (allow==null) allow=METHOD_PUT;
+	    else allow += ", " + METHOD_PUT;
+	if (ALLOW_DELETE)
+	    if (allow==null) allow=METHOD_DELETE;
+	    else allow += ", " + METHOD_DELETE;
+	if (ALLOW_TRACE)
+	    if (allow==null) allow=METHOD_TRACE;
+	    else allow += ", " + METHOD_TRACE;
+	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. 
+     *
+     *
+     *
+     * @param req	the {@link HttpServletRequest} object that
+     *			contains the request the client made of
+     *			the servlet
+     *
+     *
+     * @param resp	the {@link HttpServletResponse} object that
+     *			contains the response the servlet returns
+     *			to the client				
+     *
+     *
+     * @exception IOException	if an input or output error occurs
+     *				while the servlet is handling the
+     *				TRACE request
+     *
+     * @exception ServletException	if the request for the
+     *					TRACE cannot be handled
+     *
+     */
+
+    protected void doTrace(HttpServletRequest req, HttpServletResponse resp) 
+	throws ServletException, IOException
+    {
+	
+	int responseLength;
+	
+	String CRLF = "\r\n";
+	String responseString = "TRACE "+ req.getRequestURI()+
+	    " " + req.getProtocol();
+	
+	Enumeration reqHeaderEnum = req.getHeaderNames();
+	
+	while( reqHeaderEnum.hasMoreElements() ) {
+	    String headerName = (String)reqHeaderEnum.nextElement();
+	    responseString += CRLF + headerName + ": " +
+		req.getHeader(headerName); 
+	}
+	
+	responseString += CRLF;
+	
+	responseLength = responseString.length();
+	
+	resp.setContentType("message/http");
+	resp.setContentLength(responseLength);
+	ServletOutputStream out = resp.getOutputStream();
+	out.print(responseString);	
+	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 
+     * {@link javax.servlet.Servlet#service} 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 resp	the {@link HttpServletResponse} object that
+     *			contains the response the servlet returns
+     *			to the client				
+     *
+     *
+     * @exception IOException	if an input or output error occurs
+     *				while the servlet is handling the
+     *				HTTP request
+     *
+     * @exception ServletException	if the HTTP request
+     *					cannot be handled
+     * 
+     * @see 				javax.servlet.Servlet#service
+     *
+     */
+
+    protected void service(HttpServletRequest req, HttpServletResponse resp)
+	throws ServletException, IOException
+    {
+	String method = req.getMethod();
+
+	if (method.equals(METHOD_GET)) {
+	    long lastModified = getLastModified(req);
+	    if (lastModified == -1) {
+		// servlet doesn't support if-modified-since, no reason
+		// to go through further expensive logic
+		doGet(req, resp);
+	    } else {
+		long ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE);
+		if (ifModifiedSince < (lastModified / 1000 * 1000)) {
+		    // If the servlet mod time is later, call doGet()
+                    // Round down to the nearest second for a proper compare
+                    // A ifModifiedSince of -1 will always be less
+		    maybeSetLastModified(resp, lastModified);
+		    doGet(req, resp);
+		} else {
+		    resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
+		}
+	    }
+
+	} else if (method.equals(METHOD_HEAD)) {
+	    long lastModified = getLastModified(req);
+	    maybeSetLastModified(resp, lastModified);
+	    doHead(req, resp);
+
+	} else if (method.equals(METHOD_POST)) {
+	    doPost(req, resp);
+	    
+	} else if (method.equals(METHOD_PUT)) {
+	    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
+	    // method was requested, anywhere on this server.
+	    //
+
+	    String errMsg = lStrings.getString("http.method_not_implemented");
+	    Object[] errArgs = new Object[1];
+	    errArgs[0] = method;
+	    errMsg = MessageFormat.format(errMsg, errArgs);
+	    
+	    resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, errMsg);
+	}
+    }
+    
+
+
+
+
+    /*
+     * Sets the Last-Modified entity header field, if it has not
+     * already been set and if the value is meaningful.  Called before
+     * doGet, to ensure that headers are set before response data is
+     * written.  A subclass might have set this header already, so we
+     * check.
+     */
+
+    private void maybeSetLastModified(HttpServletResponse resp,
+				      long lastModified) {
+	if (resp.containsHeader(HEADER_LASTMOD))
+	    return;
+	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				
+     *
+     *
+     * @exception IOException	if an input or output error occurs
+     *				while the servlet is handling the
+     *				HTTP request
+     *
+     * @exception ServletException	if the HTTP request cannot
+     *					be handled
+     *
+     * 
+     * @see javax.servlet.Servlet#service
+     *
+     */
+
+    public void service(ServletRequest req, ServletResponse res)
+	throws ServletException, IOException
+    {
+	HttpServletRequest	request;
+	HttpServletResponse	response;
+	
+	try {
+	    request = (HttpServletRequest) req;
+	    response = (HttpServletResponse) res;
+	} catch (ClassCastException e) {
+	    throw new ServletException("non-HTTP request or response");
+	}
+	service(request, response);
+    }
+}
+
+
+
+
+/*
+ * A response that includes no body, for use in (dumb) "HEAD" support.
+ * This just swallows that body, counting the bytes in order to set
+ * the content length appropriately.  All other methods delegate directly
+ * to the HTTP Servlet Response object used to construct this one.
+ */
+// file private
+class NoBodyResponse implements HttpServletResponse {
+    private HttpServletResponse		resp;
+    private NoBodyOutputStream		noBody;
+    private PrintWriter			writer;
+    private boolean			didSetContentLength;
+
+    // file private
+    NoBodyResponse(HttpServletResponse r) {
+	resp = r;
+	noBody = new NoBodyOutputStream();
+    }
+
+    // file private
+    void setContentLength() {
+	if (!didSetContentLength)
+	  resp.setContentLength(noBody.getContentLength());
+    }
+
+
+    // SERVLET RESPONSE interface methods
+
+    public void setContentLength(int len) {
+	resp.setContentLength(len);
+	didSetContentLength = true;
+    }
+
+    public void setCharacterEncoding(String charset)
+      { resp.setCharacterEncoding(charset); }
+
+    public void setContentType(String type)
+      { resp.setContentType(type); }
+
+    public String getContentType()
+      { return resp.getContentType(); }
+
+    public ServletOutputStream getOutputStream() throws IOException
+      { return noBody; }
+
+    public String getCharacterEncoding()
+	{ return resp.getCharacterEncoding(); }
+
+    public PrintWriter getWriter() throws UnsupportedEncodingException
+    {
+	if (writer == null) {
+	    OutputStreamWriter	w;
+
+	    w = new OutputStreamWriter(noBody, getCharacterEncoding());
+	    writer = new PrintWriter(w);
+	}
+	return writer;
+    }
+
+    public void setBufferSize(int size) throws IllegalStateException
+      { resp.setBufferSize(size); }
+
+    public int getBufferSize()
+      { return resp.getBufferSize(); }
+
+    public void reset() throws IllegalStateException
+      { resp.reset(); }
+      
+      public void resetBuffer() throws IllegalStateException
+      { resp.resetBuffer(); }
+
+    public boolean isCommitted()
+      { return resp.isCommitted(); }
+
+    public void flushBuffer() throws IOException
+      { resp.flushBuffer(); }
+
+    public void setLocale(Locale loc)
+      { resp.setLocale(loc); }
+
+    public Locale getLocale()
+      { return resp.getLocale(); }
+
+
+    // HTTP SERVLET RESPONSE interface methods
+
+    public void addCookie(Cookie cookie)
+      { resp.addCookie(cookie); }
+
+    public boolean containsHeader(String name)
+      { return resp.containsHeader(name); }
+
+    /** @deprecated */
+    public void setStatus(int sc, String sm)
+      { resp.setStatus(sc, sm); }
+
+    public void setStatus(int sc)
+      { resp.setStatus(sc); }
+
+    public void setHeader(String name, String value)
+      { resp.setHeader(name, value); }
+
+    public void setIntHeader(String name, int value)
+      { resp.setIntHeader(name, value); }
+
+    public void setDateHeader(String name, long date)
+      { resp.setDateHeader(name, date); }
+
+    public void sendError(int sc, String msg) throws IOException
+      { resp.sendError(sc, msg); }
+
+    public void sendError(int sc) throws IOException
+      { resp.sendError(sc); }
+
+    public void sendRedirect(String location) throws IOException
+      { resp.sendRedirect(location); }
+    
+    public String encodeURL(String url) 
+      { return resp.encodeURL(url); }
+
+    public String encodeRedirectURL(String url)
+      { return resp.encodeRedirectURL(url); }
+      
+    public void addHeader(String name, String value)
+      { resp.addHeader(name, value); }
+      
+    public void addDateHeader(String name, long value)
+      { resp.addDateHeader(name, value); }
+      
+    public void addIntHeader(String name, int value)
+      { resp.addIntHeader(name, value); }
+      
+      
+      
+
+    /**
+     * @deprecated	As of Version 2.1, replaced by
+     * 			{@link HttpServletResponse#encodeURL}.
+     *
+     */
+     
+     
+    public String encodeUrl(String url) 
+      { return this.encodeURL(url); }
+      
+      
+      
+      
+      
+      
+      
+
+    /**
+     * @deprecated	As of Version 2.1, replaced by
+     *			{@link HttpServletResponse#encodeRedirectURL}.
+     *
+     */
+     
+     
+    public String encodeRedirectUrl(String url)
+      { return this.encodeRedirectURL(url); }
+
+}
+
+
+
+
+
+
+
+/*
+ * Servlet output stream that gobbles up all its data.
+ */
+ 
+// file private
+class NoBodyOutputStream extends ServletOutputStream {
+
+    private static final String LSTRING_FILE =
+	"javax.servlet.http.LocalStrings";
+    private static ResourceBundle lStrings =
+	ResourceBundle.getBundle(LSTRING_FILE);
+
+    private int		contentLength = 0;
+
+    // file private
+    NoBodyOutputStream() {}
+
+    // file private
+    int getContentLength() {
+	return contentLength;
+    }
+
+    public void write(int b) {
+	contentLength++;
+    }
+
+    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("negative length");
+	}
+    }
+}

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/http/HttpServletRequest.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/http/HttpServletRequest.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/http/HttpServletRequest.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,660 @@
+/*
+* Copyright 2004 The Apache Software Foundation
+*
+* Licensed 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 javax.servlet.ServletRequest;
+import java.util.Enumeration;
+
+/**
+ *
+ * Extends the {@link javax.servlet.ServletRequest} interface
+ * to provide request 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$
+ *
+ *
+ */
+
+public interface HttpServletRequest extends ServletRequest {
+
+    /**
+    * String identifier for Basic authentication. Value "BASIC"
+    */
+    public static final String BASIC_AUTH = "BASIC";
+    /**
+    * String identifier for Form authentication. Value "FORM"
+    */
+    public static final String FORM_AUTH = "FORM";
+    /**
+    * String identifier for Client Certificate authentication. Value "CLIENT_CERT"
+    */
+    public static final String CLIENT_CERT_AUTH = "CLIENT_CERT";
+    /**
+    * String identifier for Digest authentication. Value "DIGEST"
+    */
+    public static final String DIGEST_AUTH = "DIGEST";
+
+    /**
+     * Returns the name of the authentication scheme used to protect
+     * the servlet. All servlet containers support basic, form and client 
+     * certificate authentication, and may additionally support digest 
+     * authentication.
+     * If the servlet is not authenticated <code>null</code> is returned. 
+     *
+     * <p>Same as the value of the CGI variable AUTH_TYPE.
+     *
+     *
+     * @return		one of the static members BASIC_AUTH, 
+     *			FORM_AUTH, CLIENT_CERT_AUTH, DIGEST_AUTH
+     *			(suitable for == comparison) or
+     *			the container-specific string indicating
+     *			the authentication scheme, or
+     *			<code>null</code> if the request was 
+     *			not authenticated.     
+     *
+     */
+   
+    public String getAuthType();
+    
+   
+    
+
+    /**
+     *
+     * Returns an array containing all of the <code>Cookie</code>
+     * objects the client sent with this request.
+     * This method returns <code>null</code> if no cookies were sent.
+     *
+     * @return		an array of all the <code>Cookies</code>
+     *			included with this request, or <code>null</code>
+     *			if the request has no cookies
+     *
+     *
+     */
+
+    public Cookie[] getCookies();
+    
+    
+    
+
+    /**
+     *
+     * Returns the value of the specified request header
+     * as a <code>long</code> value that represents a 
+     * <code>Date</code> object. Use this method with
+     * headers that contain dates, such as
+     * <code>If-Modified-Since</code>. 
+     *
+     * <p>The date is returned as
+     * the number of milliseconds since January 1, 1970 GMT.
+     * The header name is case insensitive.
+     *
+     * <p>If the request did not have a header of the
+     * specified name, this method returns -1. If the header
+     * can't be converted to a date, the method throws
+     * an <code>IllegalArgumentException</code>.
+     *
+     * @param name		a <code>String</code> specifying the
+     *				name of the header
+     *
+     * @return			a <code>long</code> value
+     *				representing the date specified
+     *				in the header expressed as
+     *				the number of milliseconds
+     *				since January 1, 1970 GMT,
+     *				or -1 if the named header
+     *				was not included with the
+     *				request
+     *
+     * @exception	IllegalArgumentException	If the header value
+     *							can't be converted
+     *							to a date
+     *
+     */
+
+    public long getDateHeader(String name);
+    
+    
+    
+
+    /**
+     *
+     * Returns the value of the specified request header
+     * as a <code>String</code>. If the request did not include a header
+     * of the specified name, this method returns <code>null</code>.
+     * If there are multiple headers with the same name, this method
+     * returns the first head in the request.
+     * The header name is case insensitive. You can use
+     * this method with any request header.
+     *
+     * @param name		a <code>String</code> specifying the
+     *				header name
+     *
+     * @return			a <code>String</code> containing the
+     *				value of the requested
+     *				header, or <code>null</code>
+     *				if the request does not
+     *				have a header of that name
+     *
+     */			
+
+    public String getHeader(String name); 
+
+
+
+
+    /**
+     *
+     * Returns all the values of the specified request header
+     * as an <code>Enumeration</code> of <code>String</code> objects.
+     *
+     * <p>Some headers, such as <code>Accept-Language</code> can be sent
+     * by clients as several headers each with a different value rather than
+     * sending the header as a comma separated list.
+     *
+     * <p>If the request did not include any headers
+     * of the specified name, this method returns an empty
+     * <code>Enumeration</code>.
+     * The header name is case insensitive. You can use
+     * this method with any request header.
+     *
+     * @param name		a <code>String</code> specifying the
+     *				header name
+     *
+     * @return			an <code>Enumeration</code> containing
+     *                  	the values of the requested header. If
+     *                  	the request does not have any headers of
+     *                  	that name return an empty
+     *                  	enumeration. If 
+     *                  	the container does not allow access to
+     *                  	header information, return null
+     *
+     */			
+
+    public Enumeration getHeaders(String name); 
+    
+    
+    
+    
+
+    /**
+     *
+     * Returns an enumeration of all the header names
+     * this request contains. If the request has no
+     * headers, this method returns an empty enumeration.
+     *
+     * <p>Some servlet containers do not allow
+     * servlets to access headers using this method, in
+     * which case this method returns <code>null</code>
+     *
+     * @return			an enumeration of all the
+     *				header names sent with this
+     *				request; if the request has
+     *				no headers, an empty enumeration;
+     *				if the servlet container does not
+     *				allow servlets to use this method,
+     *				<code>null</code>
+     *				
+     *
+     */
+
+    public Enumeration getHeaderNames();
+    
+    
+    
+
+    /**
+     *
+     * Returns the value of the specified request header
+     * as an <code>int</code>. If the request does not have a header
+     * of the specified name, this method returns -1. If the
+     * header cannot be converted to an integer, this method
+     * throws a <code>NumberFormatException</code>.
+     *
+     * <p>The header name is case insensitive.
+     *
+     * @param name		a <code>String</code> specifying the name
+     *				of a request header
+     *
+     * @return			an integer expressing the value 
+     * 				of the request header or -1
+     *				if the request doesn't have a
+     *				header of this name
+     *
+     * @exception	NumberFormatException		If the header value
+     *							can't be converted
+     *							to an <code>int</code>
+     */
+
+    public int getIntHeader(String name);
+    
+    
+    
+
+    /**
+     *
+     * Returns the name of the HTTP method with which this 
+     * request was made, for example, GET, POST, or PUT.
+     * Same as the value of the CGI variable REQUEST_METHOD.
+     *
+     * @return			a <code>String</code> 
+     *				specifying the name
+     *				of the method with which
+     *				this request was made
+     *
+     */
+ 
+    public String getMethod();
+    
+    
+    
+
+    /**
+     *
+     * Returns any extra path information associated with
+     * the URL the client sent when it made this request.
+     * The extra path information follows the servlet path
+     * but precedes the query string and will start with
+     * a "/" character.
+     *
+     * <p>This method returns <code>null</code> if there
+     * was no extra path information.
+     *
+     * <p>Same as the value of the CGI variable PATH_INFO.
+     *
+     *
+     * @return		a <code>String</code>, decoded by the
+     *			web container, specifying 
+     *			extra path information that comes
+     *			after the servlet path but before
+     *			the query string in the request URL;
+     *			or <code>null</code> if the URL does not have
+     *			any extra path information
+     *
+     */
+     
+    public String getPathInfo();
+    
+
+ 
+
+    /**
+     *
+     * Returns any extra path information after the servlet name
+     * but before the query string, and translates it to a real
+     * path. Same as the value of the CGI variable PATH_TRANSLATED.
+     *
+     * <p>If the URL does not have any extra path information,
+     * this method returns <code>null</code> or the servlet container
+     * cannot translate the virtual path to a real path for any reason
+     * (such as when the web application is executed from an archive).
+     *
+     * The web container does not decode this string.
+     *
+     *
+     * @return		a <code>String</code> specifying the
+     *			real path, or <code>null</code> if
+     *			the URL does not have any extra path
+     *			information
+     *
+     *
+     */
+
+    public String getPathTranslated();
+    
+
+ 
+
+    /**
+     *
+     * Returns the portion of the request URI that indicates the context
+     * of the request.  The context path always comes first in a request
+     * URI.  The path starts with a "/" character but does not end with a "/"
+     * character.  For servlets in the default (root) context, this method
+     * returns "". The container does not decode this string.
+     *
+     *
+     * @return		a <code>String</code> specifying the
+     *			portion of the request URI that indicates the context
+     *			of the request
+     *
+     *
+     */
+
+    public String getContextPath();
+    
+    
+    
+
+    /**
+     *
+     * Returns the query string that is contained in the request
+     * URL after the path. This method returns <code>null</code>
+     * if the URL does not have a query string. Same as the value
+     * of the CGI variable QUERY_STRING. 
+     *
+     * @return		a <code>String</code> containing the query
+     *			string or <code>null</code> if the URL 
+     *			contains no query string. The value is not
+     *			decoded by the container.
+     *
+     */
+
+    public String getQueryString();
+    
+    
+    
+
+    /**
+     *
+     * Returns the login of the user making this request, if the
+     * user has been authenticated, or <code>null</code> if the user 
+     * has not been authenticated.
+     * Whether the user name is sent with each subsequent request
+     * depends on the browser and type of authentication. Same as the 
+     * value of the CGI variable REMOTE_USER.
+     *
+     * @return		a <code>String</code> specifying the login
+     *			of the user making this request, or <code>null</code>
+     *			if the user login is not known
+     *
+     */
+
+    public String getRemoteUser();
+    
+    
+    
+
+    /**
+     *
+     * Returns a boolean indicating whether the authenticated user is included
+     * in the specified logical "role".  Roles and role membership can be
+     * defined using deployment descriptors.  If the user has not been
+     * authenticated, the method returns <code>false</code>.
+     *
+     * @param role		a <code>String</code> specifying the name
+     *				of the role
+     *
+     * @return		a <code>boolean</code> indicating whether
+     *			the user making this request belongs to a given role;
+     *			<code>false</code> if the user has not been 
+     *			authenticated
+     *
+     */
+
+    public boolean isUserInRole(String role);
+    
+    
+    
+
+    /**
+     *
+     * Returns a <code>java.security.Principal</code> object containing
+     * the name of the current authenticated user. If the user has not been
+     * authenticated, the method returns <code>null</code>.
+     *
+     * @return		a <code>java.security.Principal</code> containing
+     *			the name of the user making this request;
+     *			<code>null</code> if the user has not been 
+     *			authenticated
+     *
+     */
+
+    public java.security.Principal getUserPrincipal();
+    
+    
+    
+
+    /**
+     *
+     * Returns the session ID specified by the client. This may
+     * not be the same as the ID of the current valid session
+     * for this request.
+     * If the client did not specify a session ID, this method returns
+     * <code>null</code>.
+     *
+     *
+     * @return		a <code>String</code> specifying the session
+     *			ID, or <code>null</code> if the request did
+     *			not specify a session ID
+     *
+     * @see		#isRequestedSessionIdValid
+     *
+     */
+
+    public String getRequestedSessionId();
+    
+    
+    
+    
+    /**
+     *
+     * Returns the part of this request's URL from the protocol
+     * name up to the query string in the first line of the HTTP request.
+     * The web container does not decode this String.
+     * For example:
+     *
+     * 
+
+     * <table summary="Examples of Returned Values">
+     * <tr align=left><th>First line of HTTP request      </th>
+     * <th>     Returned Value</th>
+     * <tr><td>POST /some/path.html HTTP/1.1<td><td>/some/path.html
+     * <tr><td>GET http://foo.bar/a.html HTTP/1.0
+     * <td><td>/a.html
+     * <tr><td>HEAD /xyz?a=b HTTP/1.1<td><td>/xyz
+     * </table>
+     *
+     * <p>To reconstruct an URL with a scheme and host, use
+     * {@link HttpUtils#getRequestURL}.
+     *
+     * @return		a <code>String</code> containing
+     *			the part of the URL from the 
+     *			protocol name up to the query string
+     *
+     * @see		HttpUtils#getRequestURL
+     *
+     */
+
+    public String getRequestURI();
+    
+    /**
+     *
+     * Reconstructs the URL the client used to make the request.
+     * The returned URL contains a protocol, server name, port
+     * number, and server path, but it does not include query
+     * string parameters.
+     *
+     * <p>Because this method returns a <code>StringBuffer</code>,
+     * not a string, you can modify the URL easily, for example,
+     * to append query parameters.
+     *
+     * <p>This method is useful for creating redirect messages
+     * and for reporting errors.
+     *
+     * @return		a <code>StringBuffer</code> object containing
+     *			the reconstructed URL
+     *
+     */
+    public StringBuffer getRequestURL();
+    
+
+    /**
+     *
+     * Returns the part of this request's URL that calls
+     * the servlet. This path starts with a "/" character
+     * and includes either the servlet name or a path to
+     * the servlet, but does not include any extra path
+     * information or a query string. Same as the value of
+     * the CGI variable SCRIPT_NAME.
+     *
+     * <p>This method will return an empty string ("") if the
+     * servlet used to process this request was matched using
+     * the "/*" pattern.
+     *
+     * @return		a <code>String</code> containing
+     *			the name or path of the servlet being
+     *			called, as specified in the request URL,
+     *			decoded, or an empty string if the servlet
+     *			used to process the request is matched
+     *			using the "/*" pattern.
+     *
+     */
+
+    public String getServletPath();
+    
+    
+    
+
+    /**
+     *
+     * Returns the current <code>HttpSession</code>
+     * associated with this request or, if there is no
+     * current session and <code>create</code> is true, returns 
+     * a new session.
+     *
+     * <p>If <code>create</code> is <code>false</code>
+     * and the request has no valid <code>HttpSession</code>,
+     * this method returns <code>null</code>.
+     *
+     * <p>To make sure the session is properly maintained,
+     * you must call this method before 
+     * the response is committed. If the container is using cookies
+     * to maintain session integrity and is asked to create a new session
+     * when the response is committed, an IllegalStateException is thrown.
+     *
+     *
+     *
+     *
+     * @param create	<code>true</code> to create
+     *			a new session for this request if necessary; 
+     *			<code>false</code> to return <code>null</code>
+     *			if there's no current session
+     *			
+     *
+     * @return 		the <code>HttpSession</code> associated 
+     *			with this request or <code>null</code> if
+     * 			<code>create</code> is <code>false</code>
+     *			and the request has no valid session
+     *
+     * @see	#getSession()
+     *
+     *
+     */
+
+    public HttpSession getSession(boolean create);
+    
+    
+    
+   
+
+    /**
+     *
+     * Returns the current session associated with this request,
+     * or if the request does not have a session, creates one.
+     * 
+     * @return		the <code>HttpSession</code> associated
+     *			with this request
+     *
+     * @see	#getSession(boolean)
+     *
+     */
+
+    public HttpSession getSession();
+    
+    
+    
+    
+    
+
+    /**
+     *
+     * Checks whether the requested session ID is still valid.
+     *
+     * @return			<code>true</code> if this
+     *				request has an id for a valid session
+     *				in the current session context;
+     *				<code>false</code> otherwise
+     *
+     * @see			#getRequestedSessionId
+     * @see			#getSession
+     * @see			HttpSessionContext
+     *
+     */
+
+    public boolean isRequestedSessionIdValid();
+    
+    
+    
+
+    /**
+     *
+     * Checks whether the requested session ID came in as a cookie.
+     *
+     * @return			<code>true</code> if the session ID
+     *				came in as a
+     *				cookie; otherwise, <code>false</code>
+     *
+     *
+     * @see			#getSession
+     *
+     */ 
+
+    public boolean isRequestedSessionIdFromCookie();
+    
+    
+    
+
+    /**
+     *
+     * Checks whether the requested session ID came in as part of the 
+     * request URL.
+     *
+     * @return			<code>true</code> if the session ID
+     *				came in as part of a URL; otherwise,
+     *				<code>false</code>
+     *
+     *
+     * @see			#getSession
+     *
+     */
+    
+    public boolean isRequestedSessionIdFromURL();
+    
+    
+    
+    
+    
+    /**
+     *
+     * @deprecated		As of Version 2.1 of the Java Servlet
+     *				API, use {@link #isRequestedSessionIdFromURL}
+     *				instead.
+     *
+     */
+
+    public boolean isRequestedSessionIdFromUrl();
+
+
+    
+}

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/http/HttpServletRequestWrapper.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/http/HttpServletRequestWrapper.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/http/HttpServletRequestWrapper.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,262 @@
+/*
+* Copyright 2004 The Apache Software Foundation
+*
+* Licensed 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 javax.servlet.ServletRequestWrapper;
+import java.util.Enumeration;
+
+/**
+ * 
+ * Provides a convenient implementation of the HttpServletRequest interface that
+ * can be subclassed by developers wishing to adapt the request to a Servlet.
+ * This class implements the Wrapper or Decorator pattern. Methods default to
+ * calling through to the wrapped request object.
+ * 
+ *
+ * @see 	javax.servlet.http.HttpServletRequest
+  * @since	v 2.3
+ *
+ */
+
+
+public class HttpServletRequestWrapper extends ServletRequestWrapper implements HttpServletRequest {
+
+	/** 
+	* Constructs a request object wrapping the given request.
+	* @throws java.lang.IllegalArgumentException if the request is null
+	*/
+    public HttpServletRequestWrapper(HttpServletRequest request) {
+	    super(request);
+    }
+    
+    private HttpServletRequest _getHttpServletRequest() {
+	return (HttpServletRequest) super.getRequest();
+    }
+
+    /**
+     * The default behavior of this method is to return getAuthType()
+     * on the wrapped request object.
+     */
+
+    public String getAuthType() {
+	return this._getHttpServletRequest().getAuthType();
+    }
+   
+    /**
+     * The default behavior of this method is to return getCookies()
+     * on the wrapped request object.
+     */
+    public Cookie[] getCookies() {
+	return this._getHttpServletRequest().getCookies();
+    }
+
+    /**
+     * The default behavior of this method is to return getDateHeader(String name)
+     * on the wrapped request object.
+     */
+    public long getDateHeader(String name) {
+	return this._getHttpServletRequest().getDateHeader(name);
+    }
+        	
+    /**
+     * The default behavior of this method is to return getHeader(String name)
+     * on the wrapped request object.
+     */
+    public String getHeader(String name) {
+	return this._getHttpServletRequest().getHeader(name);
+    }
+    
+    /**
+     * The default behavior of this method is to return getHeaders(String name)
+     * on the wrapped request object.
+     */
+    public Enumeration getHeaders(String name) {
+	return this._getHttpServletRequest().getHeaders(name);
+    }  
+
+    /**
+     * The default behavior of this method is to return getHeaderNames()
+     * on the wrapped request object.
+     */
+  
+    public Enumeration getHeaderNames() {
+	return this._getHttpServletRequest().getHeaderNames();
+    }
+    
+    /**
+     * The default behavior of this method is to return getIntHeader(String name)
+     * on the wrapped request object.
+     */
+
+     public int getIntHeader(String name) {
+	return this._getHttpServletRequest().getIntHeader(name);
+    }
+    
+    /**
+     * The default behavior of this method is to return getMethod()
+     * on the wrapped request object.
+     */
+    public String getMethod() {
+	return this._getHttpServletRequest().getMethod();
+    }
+    
+    /**
+     * The default behavior of this method is to return getPathInfo()
+     * on the wrapped request object.
+     */
+    public String getPathInfo() {
+	return this._getHttpServletRequest().getPathInfo();
+    }
+
+    /**
+     * The default behavior of this method is to return getPathTranslated()
+     * on the wrapped request object.
+     */
+
+     public String getPathTranslated() {
+	return this._getHttpServletRequest().getPathTranslated();
+    }
+
+    /**
+     * The default behavior of this method is to return getContextPath()
+     * on the wrapped request object.
+     */
+    public String getContextPath() {
+	return this._getHttpServletRequest().getContextPath();
+    }
+    
+    /**
+     * The default behavior of this method is to return getQueryString()
+     * on the wrapped request object.
+     */
+    public String getQueryString() {
+	return this._getHttpServletRequest().getQueryString();
+    }
+    
+    /**
+     * The default behavior of this method is to return getRemoteUser()
+     * on the wrapped request object.
+     */
+    public String getRemoteUser() {
+	return this._getHttpServletRequest().getRemoteUser();
+    }
+    
+ 
+    /**
+     * The default behavior of this method is to return isUserInRole(String role)
+     * on the wrapped request object.
+     */
+    public boolean isUserInRole(String role) {
+	return this._getHttpServletRequest().isUserInRole(role);
+    }
+    
+    
+    
+    /**
+     * The default behavior of this method is to return getUserPrincipal()
+     * on the wrapped request object.
+     */
+    public java.security.Principal getUserPrincipal() {
+	return this._getHttpServletRequest().getUserPrincipal();
+    }
+    
+   
+    /**
+     * The default behavior of this method is to return getRequestedSessionId()
+     * on the wrapped request object.
+     */
+    public String getRequestedSessionId() {
+	return this._getHttpServletRequest().getRequestedSessionId();
+    }
+    
+    /**
+     * The default behavior of this method is to return getRequestURI()
+     * on the wrapped request object.
+     */
+    public String getRequestURI() {
+	return this._getHttpServletRequest().getRequestURI();
+    }
+	/**
+     * The default behavior of this method is to return getRequestURL()
+     * on the wrapped request object.
+     */
+    public StringBuffer getRequestURL() {
+	return this._getHttpServletRequest().getRequestURL();
+    }
+	
+    
+    /**
+     * The default behavior of this method is to return getServletPath()
+     * on the wrapped request object.
+     */
+    public String getServletPath() {
+	return this._getHttpServletRequest().getServletPath();
+    }
+    
+    
+    /**
+     * The default behavior of this method is to return getSession(boolean create)
+     * on the wrapped request object.
+     */
+    public HttpSession getSession(boolean create) {
+	return this._getHttpServletRequest().getSession(create);
+    }
+    
+    /**
+     * The default behavior of this method is to return getSession()
+     * on the wrapped request object.
+     */
+    public HttpSession getSession() {
+	return this._getHttpServletRequest().getSession();
+    }
+    
+    /**
+     * The default behavior of this method is to return isRequestedSessionIdValid()
+     * on the wrapped request object.
+     */ 
+
+    public boolean isRequestedSessionIdValid() {
+	return this._getHttpServletRequest().isRequestedSessionIdValid();
+    }
+     
+    
+    /**
+     * The default behavior of this method is to return isRequestedSessionIdFromCookie()
+     * on the wrapped request object.
+     */
+    public boolean isRequestedSessionIdFromCookie() {
+	return this._getHttpServletRequest().isRequestedSessionIdFromCookie();
+    }
+    
+    	  /**
+     * The default behavior of this method is to return isRequestedSessionIdFromURL()
+     * on the wrapped request object.
+     */ 
+    public boolean isRequestedSessionIdFromURL() {
+	return this._getHttpServletRequest().isRequestedSessionIdFromURL();
+    }
+    
+    /**
+     * The default behavior of this method is to return isRequestedSessionIdFromUrl()
+     * on the wrapped request object.
+     */
+    public boolean isRequestedSessionIdFromUrl() {
+	return this._getHttpServletRequest().isRequestedSessionIdFromUrl();
+    }
+
+
+    
+}

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/http/HttpServletResponse.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/http/HttpServletResponse.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/http/HttpServletResponse.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,636 @@
+/*
+* Copyright 2004 The Apache Software Foundation
+*
+* Licensed 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 javax.servlet.ServletResponse;
+
+/**
+ *
+ * Extends the {@link ServletResponse} interface to provide HTTP-specific
+ * functionality in sending a response.  For example, it has methods
+ * to access HTTP headers and cookies.
+ *
+ * <p>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 {
+
+    /**
+     * Adds the specified cookie to the response.  This method can be called
+     * multiple times to set more than one cookie.
+     *
+     * @param cookie the Cookie to return to the client
+     *
+     */
+
+    public void addCookie(Cookie cookie);
+
+    /**
+     * Returns a boolean indicating whether the named response header 
+     * has already been set.
+     * 
+     * @param	name	the header name
+     * @return		<code>true</code> if the named response header 
+     *			has already been set; 
+     * 			<code>false</code> otherwise
+     */
+
+    public boolean containsHeader(String name);
+
+    /**
+     * Encodes the specified URL by including the session ID in it,
+     * or, if encoding is not needed, returns the URL unchanged.
+     * The implementation of this method includes the logic to
+     * determine whether the session ID needs to be encoded in the URL.
+     * For example, if the browser supports cookies, or session
+     * tracking is turned off, URL encoding is unnecessary.
+     * 
+     * <p>For robust session tracking, all URLs emitted by a servlet 
+     * should be run through this
+     * method.  Otherwise, URL rewriting cannot be used with browsers
+     * which do not support cookies.
+     *
+     * @param	url	the url to be encoded.
+     * @return		the encoded URL if encoding is needed;
+     * 			the unchanged URL otherwise.
+     */
+
+    public String encodeURL(String url);
+
+    /**
+     * Encodes the specified URL for use in the
+     * <code>sendRedirect</code> method or, if encoding is not needed,
+     * returns the URL unchanged.  The implementation of this method
+     * includes the logic to determine whether the session ID
+     * needs to be encoded in the URL.  Because the rules for making
+     * this determination can differ from those used to decide whether to
+     * encode a normal link, this method is separated from the
+     * <code>encodeURL</code> method.
+     * 
+     * <p>All URLs sent to the <code>HttpServletResponse.sendRedirect</code>
+     * method should be run through this method.  Otherwise, URL
+     * rewriting cannot be used with browsers which do not support
+     * cookies.
+     *
+     * @param	url	the url to be encoded.
+     * @return		the encoded URL if encoding is needed;
+     * 			the unchanged URL otherwise.
+     *
+     * @see #sendRedirect
+     * @see #encodeUrl
+     */
+
+    public String encodeRedirectURL(String url);
+
+    /**
+     * @deprecated	As of version 2.1, use encodeURL(String url) instead
+     *
+     * @param	url	the url to be encoded.
+     * @return		the encoded URL if encoding is needed; 
+     * 			the unchanged URL otherwise.
+     */
+
+    public String encodeUrl(String url);
+    
+    /**
+     * @deprecated	As of version 2.1, use 
+     *			encodeRedirectURL(String url) instead
+     *
+     * @param	url	the url to be encoded.
+     * @return		the encoded URL if encoding is needed; 
+     * 			the unchanged URL otherwise.
+     */
+
+    public String encodeRedirectUrl(String url);
+
+    /**
+     * Sends an error response to the client using the specified
+     * status.  The server defaults to creating the
+     * response to look like an HTML-formatted server error page
+     * containing the specified message, setting the content type
+     * to "text/html", leaving cookies and other headers unmodified.
+     *
+     * If an error-page declaration has been made for the web application
+     * corresponding to the status code passed in, it will be served back in 
+     * preference to the suggested msg parameter. 
+     *
+     * <p>If the response has already been committed, this method throws 
+     * an IllegalStateException.
+     * After using this method, the response should be considered
+     * to be committed and should not be written to.
+     *
+     * @param	sc	the error status code
+     * @param	msg	the descriptive message
+     * @exception	IOException	If an input or output exception occurs
+     * @exception	IllegalStateException	If the response was committed
+     */
+   
+    public void sendError(int sc, String msg) throws IOException;
+
+    /**
+     * Sends an error response to the client using the specified status
+     * code and clearing the buffer. 
+     * <p>If the response has already been committed, this method throws 
+     * an IllegalStateException.
+     * After using this method, the response should be considered
+     * to be committed and should not be written to.
+     *
+     * @param	sc	the error status code
+     * @exception	IOException	If an input or output exception occurs
+     * @exception	IllegalStateException	If the response was committed
+     *						before this method call
+     */
+
+    public void sendError(int sc) throws IOException;
+
+    /**
+     * Sends a temporary redirect response to the client using the
+     * specified redirect location URL.  This method can accept relative URLs;
+     * the servlet container must convert the relative URL to an absolute URL
+     * before sending the response to the client. If the location is relative 
+     * without a leading '/' the container interprets it as relative to
+     * the current request URI. If the location is relative with a leading
+     * '/' the container interprets it as relative to the servlet container root.
+     *
+     * <p>If the response has already been committed, this method throws 
+     * an IllegalStateException.
+     * After using this method, the response should be considered
+     * to be committed and should not be written to.
+     *
+     * @param		location	the redirect location URL
+     * @exception	IOException	If an input or output exception occurs
+     * @exception	IllegalStateException	If the response was committed or
+ if a partial URL is given and cannot be converted into a valid URL
+     */
+
+    public void sendRedirect(String location) throws IOException;
+    
+    /**
+     * 
+     * Sets a response header with the given name and
+     * date-value.  The date is specified in terms of
+     * milliseconds since the epoch.  If the header had already
+     * been set, the new value overwrites the previous one.  The
+     * <code>containsHeader</code> method can be used to test for the
+     * presence of a header before setting its value.
+     * 
+     * @param	name	the name of the header to set
+     * @param	date	the assigned date value
+     * 
+     * @see #containsHeader
+     * @see #addDateHeader
+     */
+
+    public void setDateHeader(String name, long date);
+    
+    /**
+     * 
+     * Adds a response header with the given name and
+     * date-value.  The date is specified in terms of
+     * milliseconds since the epoch.  This method allows response headers 
+     * to have multiple values.
+     * 
+     * @param	name	the name of the header to set
+     * @param	date	the additional date value
+     * 
+     * @see #setDateHeader
+     */
+
+    public void addDateHeader(String name, long date);
+    
+    /**
+     *
+     * Sets a response header with the given name and value.
+     * If the header had already been set, the new value overwrites the
+     * previous one.  The <code>containsHeader</code> method can be
+     * used to test for the presence of a header before setting its
+     * value.
+     * 
+     * @param	name	the name of the header
+     * @param	value	the header value  If it contains octet string,
+     *		it should be encoded according to RFC 2047
+     *		(http://www.ietf.org/rfc/rfc2047.txt)
+     *
+     * @see #containsHeader
+     * @see #addHeader
+     */
+
+    public void setHeader(String name, String value);
+    
+    /**
+     * Adds a response header with the given name and value.
+     * This method allows response headers to have multiple values.
+     * 
+     * @param	name	the name of the header
+     * @param	value	the additional header value   If it contains
+     *		octet string, it should be encoded
+     *		according to RFC 2047
+     *		(http://www.ietf.org/rfc/rfc2047.txt)
+     *
+     * @see #setHeader
+     */
+
+    public void addHeader(String name, String value);
+
+    /**
+     * Sets a response header with the given name and
+     * integer value.  If the header had already been set, the new value
+     * overwrites the previous one.  The <code>containsHeader</code>
+     * method can be used to test for the presence of a header before
+     * setting its value.
+     *
+     * @param	name	the name of the header
+     * @param	value	the assigned integer value
+     *
+     * @see #containsHeader
+     * @see #addIntHeader
+     */
+
+    public void setIntHeader(String name, int value);
+
+    /**
+     * Adds a response header with the given name and
+     * integer value.  This method allows response headers to have multiple
+     * values.
+     *
+     * @param	name	the name of the header
+     * @param	value	the assigned integer value
+     *
+     * @see #setIntHeader
+     */
+
+    public void addIntHeader(String name, int value);
+
+
+    
+    /**
+     * Sets the status code for this response.  This method is used to
+     * set the return status code when there is no error (for example,
+     * for the status codes SC_OK or SC_MOVED_TEMPORARILY).  If there
+     * is an error, and the caller wishes to invoke an error-page defined
+     * in the web application, the <code>sendError</code> method should be used
+     * instead.
+     * <p> The container clears the buffer and sets the Location header, preserving
+     * cookies and other headers.
+     *
+     * @param	sc	the status code
+     *
+     * @see #sendError
+     */
+
+    public void setStatus(int sc);
+  
+    /**
+     * @deprecated As of version 2.1, due to ambiguous meaning of the 
+     * message parameter. To set a status code 
+     * use <code>setStatus(int)</code>, to send an error with a description
+     * use <code>sendError(int, String)</code>.
+     *
+     * Sets the status code and message for this response.
+     * 
+     * @param	sc	the status code
+     * @param	sm	the status message
+     */
+
+    public void setStatus(int sc, String sm);
+
+    
+    /*
+     * Server status codes; see RFC 2068.
+     */
+
+    /**
+     * Status code (100) indicating the client can continue.
+     */
+
+    public static final int SC_CONTINUE = 100;
+
+    
+    /**
+     * Status code (101) indicating the server is switching protocols
+     * according to Upgrade header.
+     */
+
+    public static final int SC_SWITCHING_PROTOCOLS = 101;
+
+    /**
+     * Status code (200) indicating the request succeeded normally.
+     */
+
+    public static final int SC_OK = 200;
+
+    /**
+     * Status code (201) indicating the request succeeded and created
+     * a new resource on the server.
+     */
+
+    public static final int SC_CREATED = 201;
+
+    /**
+     * Status code (202) indicating that a request was accepted for
+     * processing, but was not completed.
+     */
+
+    public static final int SC_ACCEPTED = 202;
+
+    /**
+     * Status code (203) indicating that the meta information presented
+     * by the client did not originate from the server.
+     */
+
+    public static final int SC_NON_AUTHORITATIVE_INFORMATION = 203;
+
+    /**
+     * Status code (204) indicating that the request succeeded but that
+     * there was no new information to return.
+     */
+
+    public static final int SC_NO_CONTENT = 204;
+
+    /**
+     * Status code (205) indicating that the agent <em>SHOULD</em> reset
+     * the document view which caused the request to be sent.
+     */
+
+    public static final int SC_RESET_CONTENT = 205;
+
+    /**
+     * Status code (206) indicating that the server has fulfilled
+     * the partial GET request for the resource.
+     */
+
+    public static final int SC_PARTIAL_CONTENT = 206;
+
+    /**
+     * Status code (300) indicating that the requested resource
+     * corresponds to any one of a set of representations, each with
+     * its own specific location.
+     */
+
+    public static final int SC_MULTIPLE_CHOICES = 300;
+
+    /**
+     * Status code (301) indicating that the resource has permanently
+     * moved to a new location, and that future references should use a
+     * new URI with their requests.
+     */
+
+    public static final int SC_MOVED_PERMANENTLY = 301;
+
+    /**
+     * Status code (302) indicating that the resource has temporarily
+     * moved to another location, but that future references should
+     * still use the original URI to access the resource.
+     *
+     * This definition is being retained for backwards compatibility.
+     * SC_FOUND is now the preferred definition.
+     */
+
+    public static final int SC_MOVED_TEMPORARILY = 302;
+
+    /**
+    * Status code (302) indicating that the resource reside
+    * temporarily under a different URI. Since the redirection might
+    * be altered on occasion, the client should continue to use the
+    * Request-URI for future requests.(HTTP/1.1) To represent the
+    * status code (302), it is recommended to use this variable.
+    */
+
+    public static final int SC_FOUND = 302;
+
+    /**
+     * Status code (303) indicating that the response to the request
+     * can be found under a different URI.
+     */
+
+    public static final int SC_SEE_OTHER = 303;
+
+    /**
+     * Status code (304) indicating that a conditional GET operation
+     * found that the resource was available and not modified.
+     */
+
+    public static final int SC_NOT_MODIFIED = 304;
+
+    /**
+     * Status code (305) indicating that the requested resource
+     * <em>MUST</em> be accessed through the proxy given by the
+     * <code><em>Location</em></code> field.
+     */
+
+    public static final int SC_USE_PROXY = 305;
+
+     /**
+     * Status code (307) indicating that the requested resource 
+     * resides temporarily under a different URI. The temporary URI
+     * <em>SHOULD</em> be given by the <code><em>Location</em></code> 
+     * field in the response.
+     */
+
+     public static final int SC_TEMPORARY_REDIRECT = 307;
+
+    /**
+     * Status code (400) indicating the request sent by the client was
+     * syntactically incorrect.
+     */
+
+    public static final int SC_BAD_REQUEST = 400;
+
+    /**
+     * Status code (401) indicating that the request requires HTTP
+     * authentication.
+     */
+
+    public static final int SC_UNAUTHORIZED = 401;
+
+    /**
+     * Status code (402) reserved for future use.
+     */
+
+    public static final int SC_PAYMENT_REQUIRED = 402;
+
+    /**
+     * Status code (403) indicating the server understood the request
+     * but refused to fulfill it.
+     */
+
+    public static final int SC_FORBIDDEN = 403;
+
+    /**
+     * Status code (404) indicating that the requested resource is not
+     * available.
+     */
+
+    public static final int SC_NOT_FOUND = 404;
+
+    /**
+     * Status code (405) indicating that the method specified in the
+     * <code><em>Request-Line</em></code> is not allowed for the resource
+     * identified by the <code><em>Request-URI</em></code>.
+     */
+
+    public static final int SC_METHOD_NOT_ALLOWED = 405;
+
+    /**
+     * Status code (406) indicating that the resource identified by the
+     * request is only capable of generating response entities which have
+     * content characteristics not acceptable according to the accept
+     * headers sent in the request.
+     */
+
+    public static final int SC_NOT_ACCEPTABLE = 406;
+
+    /**
+     * Status code (407) indicating that the client <em>MUST</em> first
+     * authenticate itself with the proxy.
+     */
+
+    public static final int SC_PROXY_AUTHENTICATION_REQUIRED = 407;
+
+    /**
+     * Status code (408) indicating that the client did not produce a
+     * request within the time that the server was prepared to wait.
+     */
+
+    public static final int SC_REQUEST_TIMEOUT = 408;
+
+    /**
+     * Status code (409) indicating that the request could not be
+     * completed due to a conflict with the current state of the
+     * resource.
+     */
+
+    public static final int SC_CONFLICT = 409;
+
+    /**
+     * Status code (410) indicating that the resource is no longer
+     * available at the server and no forwarding address is known.
+     * This condition <em>SHOULD</em> be considered permanent.
+     */
+
+    public static final int SC_GONE = 410;
+
+    /**
+     * Status code (411) indicating that the request cannot be handled
+     * without a defined <code><em>Content-Length</em></code>.
+     */
+
+    public static final int SC_LENGTH_REQUIRED = 411;
+
+    /**
+     * Status code (412) indicating that the precondition given in one
+     * or more of the request-header fields evaluated to false when it
+     * was tested on the server.
+     */
+
+    public static final int SC_PRECONDITION_FAILED = 412;
+
+    /**
+     * Status code (413) indicating that the server is refusing to process
+     * the request because the request entity is larger than the server is
+     * willing or able to process.
+     */
+
+    public static final int SC_REQUEST_ENTITY_TOO_LARGE = 413;
+
+    /**
+     * Status code (414) indicating that the server is refusing to service
+     * the request because the <code><em>Request-URI</em></code> is longer
+     * than the server is willing to interpret.
+     */
+
+    public static final int SC_REQUEST_URI_TOO_LONG = 414;
+
+    /**
+     * Status code (415) indicating that the server is refusing to service
+     * the request because the entity of the request is in a format not
+     * supported by the requested resource for the requested method.
+     */
+
+    public static final int SC_UNSUPPORTED_MEDIA_TYPE = 415;
+
+    /**
+     * Status code (416) indicating that the server cannot serve the
+     * requested byte range.
+     */
+
+    public static final int SC_REQUESTED_RANGE_NOT_SATISFIABLE = 416;
+
+    /**
+     * Status code (417) indicating that the server could not meet the
+     * expectation given in the Expect request header.
+     */
+
+    public static final int SC_EXPECTATION_FAILED = 417;
+
+    /**
+     * Status code (500) indicating an error inside the HTTP server
+     * which prevented it from fulfilling the request.
+     */
+
+    public static final int SC_INTERNAL_SERVER_ERROR = 500;
+
+    /**
+     * Status code (501) indicating the HTTP server does not support
+     * the functionality needed to fulfill the request.
+     */
+
+    public static final int SC_NOT_IMPLEMENTED = 501;
+
+    /**
+     * Status code (502) indicating that the HTTP server received an
+     * invalid response from a server it consulted when acting as a
+     * proxy or gateway.
+     */
+
+    public static final int SC_BAD_GATEWAY = 502;
+
+    /**
+     * Status code (503) indicating that the HTTP server is
+     * temporarily overloaded, and unable to handle the request.
+     */
+
+    public static final int SC_SERVICE_UNAVAILABLE = 503;
+
+    /**
+     * Status code (504) indicating that the server did not receive
+     * a timely response from the upstream server while acting as
+     * a gateway or proxy.
+     */
+
+    public static final int SC_GATEWAY_TIMEOUT = 504;
+
+    /**
+     * Status code (505) indicating that the server does not support
+     * or refuses to support the HTTP protocol version that was used
+     * in the request message.
+     */
+
+    public static final int SC_HTTP_VERSION_NOT_SUPPORTED = 505;
+}

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/http/HttpServletResponseWrapper.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/http/HttpServletResponseWrapper.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/http/HttpServletResponseWrapper.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,195 @@
+/*
+* Copyright 2004 The Apache Software Foundation
+*
+* Licensed 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 javax.servlet.ServletResponseWrapper;
+
+/**
+ * 
+ * Provides a convenient implementation of the HttpServletResponse interface that
+ * can be subclassed by developers wishing to adapt the response from a Servlet.
+ * This class implements the Wrapper or Decorator pattern. Methods default to
+ * calling through to the wrapped response object.
+ * 
+ * @author 	Various
+ * @version 	$Version$
+  * @since	v 2.3
+ *
+ * @see 	javax.servlet.http.HttpServletResponse
+ *
+ */
+
+public class HttpServletResponseWrapper extends ServletResponseWrapper implements HttpServletResponse {
+
+
+    /** 
+    * Constructs a response adaptor wrapping the given response.
+    * @throws java.lang.IllegalArgumentException if the response is null
+    */
+    public HttpServletResponseWrapper(HttpServletResponse response) {
+	    super(response);
+    }
+    
+    private HttpServletResponse _getHttpServletResponse() {
+	return (HttpServletResponse) super.getResponse();
+    }
+    
+    /**
+     * The default behavior of this method is to call addCookie(Cookie cookie)
+     * on the wrapped response object.
+     */
+    public void addCookie(Cookie cookie) {
+	this._getHttpServletResponse().addCookie(cookie);
+    }
+
+    /**
+     * The default behavior of this method is to call containsHeader(String name)
+     * on the wrapped response object.
+     */
+
+ 
+    public boolean containsHeader(String name) {
+	return this._getHttpServletResponse().containsHeader(name);
+    }
+    
+    /**
+     * The default behavior of this method is to call encodeURL(String url)
+     * on the wrapped response object.
+     */
+    public String encodeURL(String url) {
+	return this._getHttpServletResponse().encodeURL(url);
+    }
+
+    /**
+     * The default behavior of this method is to return encodeRedirectURL(String url)
+     * on the wrapped response object.
+     */
+    public String encodeRedirectURL(String url) {
+	return this._getHttpServletResponse().encodeRedirectURL(url);
+    }
+
+    /**
+     * The default behavior of this method is to call encodeUrl(String url)
+     * on the wrapped response object.
+     */
+    public String encodeUrl(String url) {
+	return this._getHttpServletResponse().encodeUrl(url);
+    }
+    
+    /**
+     * The default behavior of this method is to return encodeRedirectUrl(String url)
+     * on the wrapped response object.
+     */
+    public String encodeRedirectUrl(String url) {
+	return this._getHttpServletResponse().encodeRedirectUrl(url);
+    }
+    
+    /**
+     * The default behavior of this method is to call sendError(int sc, String msg)
+     * on the wrapped response object.
+     */
+    public void sendError(int sc, String msg) throws IOException {
+	this._getHttpServletResponse().sendError(sc, msg);
+    }
+
+    /**
+     * The default behavior of this method is to call sendError(int sc)
+     * on the wrapped response object.
+     */
+
+
+    public void sendError(int sc) throws IOException {
+	this._getHttpServletResponse().sendError(sc);
+    }
+
+    /**
+     * The default behavior of this method is to return sendRedirect(String location)
+     * on the wrapped response object.
+     */
+    public void sendRedirect(String location) throws IOException {
+	this._getHttpServletResponse().sendRedirect(location);
+    }
+    
+    /**
+     * The default behavior of this method is to call setDateHeader(String name, long date)
+     * on the wrapped response object.
+     */
+    public void setDateHeader(String name, long date) {
+	this._getHttpServletResponse().setDateHeader(name, date);
+    }
+    
+    /**
+     * The default behavior of this method is to call addDateHeader(String name, long date)
+     * on the wrapped response object.
+     */
+   public void addDateHeader(String name, long date) {
+	this._getHttpServletResponse().addDateHeader(name, date);
+    }
+    
+    /**
+     * The default behavior of this method is to return setHeader(String name, String value)
+     * on the wrapped response object.
+     */
+    public void setHeader(String name, String value) {
+	this._getHttpServletResponse().setHeader(name, value);
+    }
+    
+    /**
+     * The default behavior of this method is to return addHeader(String name, String value)
+     * on the wrapped response object.
+     */
+     public void addHeader(String name, String value) {
+	this._getHttpServletResponse().addHeader(name, value);
+    }
+    
+    /**
+     * The default behavior of this method is to call setIntHeader(String name, int value)
+     * on the wrapped response object.
+     */
+    public void setIntHeader(String name, int value) {
+	this._getHttpServletResponse().setIntHeader(name, value);
+    }
+    
+    /**
+     * The default behavior of this method is to call addIntHeader(String name, int value)
+     * on the wrapped response object.
+     */
+    public void addIntHeader(String name, int value) {
+	this._getHttpServletResponse().addIntHeader(name, value);
+    }
+
+    /**
+     * The default behavior of this method is to call setStatus(int sc)
+     * on the wrapped response object.
+     */
+
+
+    public void setStatus(int sc) {
+	this._getHttpServletResponse().setStatus(sc);
+    }
+    
+    /**
+     * The default behavior of this method is to call setStatus(int sc, String sm)
+     * on the wrapped response object.
+     */
+     public void setStatus(int sc, String sm) {
+	this._getHttpServletResponse().setStatus(sc, sm);
+    }
+
+   
+}

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/http/HttpSession.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/http/HttpSession.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/http/HttpSession.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,423 @@
+/*
+* Copyright 2004 The Apache Software Foundation
+*
+* Licensed 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.util.Enumeration;
+import javax.servlet.ServletContext;
+
+/**
+ *
+ * Provides a way to identify a user across more than one page
+ * request or visit to a Web site and to store information about that user.
+ *
+ * <p>The servlet container uses this interface to create a session
+ * between an HTTP client and an HTTP server. The session persists
+ * for a specified time period, across more than one connection or
+ * page request from the user. A session usually corresponds to one 
+ * user, who may visit a site many times. The server can maintain a 
+ * session in many ways such as using cookies or rewriting URLs.
+ *
+ * <p>This interface allows servlets to 
+ * <ul>
+ * <li>View and manipulate information about a session, such as
+ *     the session identifier, creation time, and last accessed time
+ * <li>Bind objects to sessions, allowing user information to persist 
+ *     across multiple user connections
+ * </ul>
+ *
+ * <p>When an application stores an object in or removes an object from a
+ * session, the session checks whether the object implements
+ * {@link HttpSessionBindingListener}. If it does, 
+ * the servlet notifies the object that it has been bound to or unbound 
+ * from the session. Notifications are sent after the binding methods complete. 
+ * For session that are invalidated or expire, notifications are sent after
+ * the session has been invalidated or expired.
+ *
+ * <p> When container migrates a session between VMs in a distributed container
+ * setting, all session attributes implementing the {@link HttpSessionActivationListener}
+ * interface are notified.
+ * 
+ * <p>A servlet should be able to handle cases in which
+ * the client does not choose to join a session, such as when cookies are
+ * intentionally turned off. Until the client joins the session,
+ * <code>isNew</code> returns <code>true</code>.  If the client chooses 
+ * not to join
+ * the session, <code>getSession</code> will return a different session
+ * on each request, and <code>isNew</code> will always return
+ * <code>true</code>.
+ *
+ * <p>Session information is scoped only to the current web application
+ * (<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 {
+
+
+
+
+    /**
+     *
+     * Returns the time when this session was created, measured
+     * in milliseconds since midnight January 1, 1970 GMT.
+     *
+     * @return				a <code>long</code> specifying
+     * 					when this session was created,
+     *					expressed in 
+     *					milliseconds since 1/1/1970 GMT
+     *
+     * @exception IllegalStateException	if this method is called on an
+     *					invalidated session
+     *
+     */
+
+    public long getCreationTime();
+    
+    
+    
+    
+    /**
+     *
+     * Returns a string containing the unique identifier assigned 
+     * to this session. The identifier is assigned 
+     * by the servlet container and is implementation dependent.
+     * 
+     * @return				a string specifying the identifier
+     *					assigned to this session
+     *
+     * @exception IllegalStateException	if this method is called on an
+     *					invalidated session
+     *
+     */
+
+    public String getId();
+    
+    
+    
+
+    /**
+     *
+     * Returns the last time the client sent a request associated with
+     * this session, as the number of milliseconds since midnight
+     * January 1, 1970 GMT, and marked by the time the container received the request. 
+     *
+     * <p>Actions that your application takes, such as getting or setting
+     * a value associated with the session, do not affect the access
+     * time.
+     *
+     * @return				a <code>long</code>
+     *					representing the last time 
+     *					the client sent a request associated
+     *					with this session, expressed in 
+     *					milliseconds since 1/1/1970 GMT
+     *
+     * @exception IllegalStateException	if this method is called on an
+     *					invalidated session
+     *
+     */
+
+    public long getLastAccessedTime();
+    
+    
+    /**
+    * Returns the ServletContext to which this session belongs.
+    *    
+    * @return The ServletContext object for the web application
+    * @since 2.3
+    */
+
+    public ServletContext getServletContext();
+
+
+    /**
+     *
+     * Specifies the time, in seconds, between client requests before the 
+     * servlet container will invalidate this session.  A negative time
+     * indicates the session should never timeout.
+     *
+     * @param interval		An integer specifying the number
+     * 				of seconds 
+     *
+     */
+    
+    public void setMaxInactiveInterval(int interval);
+
+
+
+
+   /**
+    * Returns the maximum time interval, in seconds, that 
+    * the servlet container will keep this session open between 
+    * client accesses. After this interval, the servlet container
+    * will invalidate the session.  The maximum time interval can be set
+    * with the <code>setMaxInactiveInterval</code> method.
+    * A negative time indicates the session should never timeout.
+    *  
+    *
+    * @return		an integer specifying the number of
+    *			seconds this session remains open
+    *			between client requests
+    *
+    * @see		#setMaxInactiveInterval
+    *
+    *
+    */
+
+    public int getMaxInactiveInterval();
+    
+    
+
+
+   /**
+    *
+    * @deprecated 	As of Version 2.1, this method is
+    *			deprecated and has no replacement.
+    *			It will be removed in a future
+    *			version of the Java Servlet API.
+    *
+    */
+
+    public HttpSessionContext getSessionContext();
+    
+    
+    
+    
+    /**
+     *
+     * Returns the object bound with the specified name in this session, or
+     * <code>null</code> if no object is bound under the name.
+     *
+     * @param name		a string specifying the name of the object
+     *
+     * @return			the object with the specified name
+     *
+     * @exception IllegalStateException	if this method is called on an
+     *					invalidated session
+     *
+     */
+  
+    public Object getAttribute(String name);
+    
+    
+    
+    
+    /**
+     *
+     * @deprecated 	As of Version 2.2, this method is
+     * 			replaced by {@link #getAttribute}.
+     *
+     * @param name		a string specifying the name of the object
+     *
+     * @return			the object with the specified name
+     *
+     * @exception IllegalStateException	if this method is called on an
+     *					invalidated session
+     *
+     */
+  
+    public Object getValue(String name);
+    
+    
+    
+
+    /**
+     *
+     * Returns an <code>Enumeration</code> of <code>String</code> objects
+     * containing the names of all the objects bound to this session. 
+     *
+     * @return			an <code>Enumeration</code> of 
+     *				<code>String</code> objects specifying the
+     *				names of all the objects bound to
+     *				this session
+     *
+     * @exception IllegalStateException	if this method is called on an
+     *					invalidated session
+     *
+     */
+    
+    public Enumeration getAttributeNames();
+    
+    
+    
+
+    /**
+     *
+     * @deprecated 	As of Version 2.2, this method is
+     * 			replaced by {@link #getAttributeNames}
+     *
+     * @return				an array of <code>String</code>
+     *					objects specifying the
+     *					names of all the objects bound to
+     *					this session
+     *
+     * @exception IllegalStateException	if this method is called on an
+     *					invalidated session
+     *
+     */
+    
+    public String[] getValueNames();
+    
+    
+    
+
+    /**
+     * Binds an object to this session, using the name specified.
+     * If an object of the same name is already bound to the session,
+     * the object is replaced.
+     *
+     * <p>After this method executes, and if the new object
+     * implements <code>HttpSessionBindingListener</code>,
+     * the container calls 
+     * <code>HttpSessionBindingListener.valueBound</code>. The container then   
+     * notifies any <code>HttpSessionAttributeListener</code>s in the web 
+     * application.
+     
+     * <p>If an object was already bound to this session of this name
+     * that implements <code>HttpSessionBindingListener</code>, its 
+     * <code>HttpSessionBindingListener.valueUnbound</code> method is called.
+     *
+     * <p>If the value passed in is null, this has the same effect as calling 
+     * <code>removeAttribute()<code>.
+     *
+     *
+     * @param name			the name to which the object is bound;
+     *					cannot be null
+     *
+     * @param value			the object to be bound
+     *
+     * @exception IllegalStateException	if this method is called on an
+     *					invalidated session
+     *
+     */
+ 
+    public void setAttribute(String name, Object value);
+    
+
+
+
+    
+    /**
+     *
+     * @deprecated 	As of Version 2.2, this method is
+     * 			replaced by {@link #setAttribute}
+     *
+     * @param name			the name to which the object is bound;
+     *					cannot be null
+     *
+     * @param value			the object to be bound; cannot be null
+     *
+     * @exception IllegalStateException	if this method is called on an
+     *					invalidated session
+     *
+     */
+ 
+    public void putValue(String name, Object value);
+
+
+
+
+
+    /**
+     *
+     * Removes the object bound with the specified name from
+     * this session. If the session does not have an object
+     * bound with the specified name, this method does nothing.
+     *
+     * <p>After this method executes, and if the object
+     * implements <code>HttpSessionBindingListener</code>,
+     * the container calls 
+     * <code>HttpSessionBindingListener.valueUnbound</code>. The container
+     * then notifies any <code>HttpSessionAttributeListener</code>s in the web 
+     * application.
+     * 
+     * 
+     *
+     * @param name				the name of the object to
+     *						remove from this session
+     *
+     * @exception IllegalStateException	if this method is called on an
+     *					invalidated session
+     */
+
+    public void removeAttribute(String name);
+
+
+
+
+
+    /**
+     *
+     * @deprecated 	As of Version 2.2, this method is
+     * 			replaced by {@link #removeAttribute}
+     *
+     * @param name				the name of the object to
+     *						remove from this session
+     *
+     * @exception IllegalStateException	if this method is called on an
+     *					invalidated session
+     */
+
+    public void removeValue(String name);
+
+
+
+
+    /**
+     *
+     * Invalidates this session then unbinds any objects bound
+     * to it. 
+     *
+     * @exception IllegalStateException	if this method is called on an
+     *					already invalidated session
+     *
+     */
+
+    public void invalidate();
+    
+    
+    
+    
+    /**
+     *
+     * Returns <code>true</code> if the client does not yet know about the
+     * session or if the client chooses not to join the session.  For 
+     * example, if the server used only cookie-based sessions, and
+     * the client had disabled the use of cookies, then a session would
+     * be new on each request.
+     *
+     * @return 				<code>true</code> if the 
+     *					server has created a session, 
+     *					but the client has not yet joined
+     *
+     * @exception IllegalStateException	if this method is called on an
+     *					already invalidated session
+     *
+     */
+
+    public boolean isNew();
+
+
+
+}
+

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/http/HttpSessionActivationListener.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/http/HttpSessionActivationListener.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/http/HttpSessionActivationListener.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,36 @@
+/*
+* Copyright 2004 The Apache Software Foundation
+*
+* Licensed 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.util.EventListener;
+
+    /** Objects that are bound to a session may listen to container
+    ** events notifying them that sessions will be passivated and that
+    ** session will be activated. A container that migrates session between VMs
+    ** or persists sessions is required to notify all attributes bound to sessions
+    ** implementing HttpSessionActivationListener.
+    **
+    * @since 2.3
+    */
+    
+public interface HttpSessionActivationListener extends EventListener { 
+
+    /** Notification that the session is about to be passivated.*/
+    public void sessionWillPassivate(HttpSessionEvent se); 
+    /** Notification that the session has just been activated.*/
+    public void sessionDidActivate(HttpSessionEvent se);
+} 
+

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/http/HttpSessionAttributeListener.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/http/HttpSessionAttributeListener.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/http/HttpSessionAttributeListener.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,35 @@
+/*
+* Copyright 2004 The Apache Software Foundation
+*
+* Licensed 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.util.EventListener;
+
+	/** This listener interface can be implemented in order to
+	* get notifications of changes to the attribute lists of sessions within
+	* this web application.
+	* @since	v 2.3
+*/
+
+public interface HttpSessionAttributeListener extends EventListener {
+	/** Notification that an attribute has been added to a session. Called after the attribute is added.*/
+    public void attributeAdded ( HttpSessionBindingEvent se );
+	/** Notification that an attribute has been removed from a session. Called after the attribute is removed. */
+    public void attributeRemoved ( HttpSessionBindingEvent se );
+	/** Notification that an attribute has been replaced in a session. Called after the attribute is replaced. */
+    public void attributeReplaced ( HttpSessionBindingEvent se );
+
+}
+

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/http/HttpSessionBindingEvent.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/http/HttpSessionBindingEvent.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/http/HttpSessionBindingEvent.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,151 @@
+/*
+* Copyright 2004 The Apache Software Foundation
+*
+* Licensed 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;
+
+
+
+/**
+ *
+ * Events of this type are either sent to an object that implements
+ * {@link HttpSessionBindingListener} when it is bound or 
+ * unbound from a session, or to a {@link HttpSessionAttributeListener} 
+ * that has been configured in the deployment descriptor when any attribute is
+ * bound, unbound or replaced in a session.
+ *
+ * <p>The session binds the object by a call to
+ * <code>HttpSession.setAttribute</code> and unbinds the object
+ * by a call to <code>HttpSession.removeAttribute</code>.
+ *
+ *
+ *
+ * @author		Various
+ * @version		$Version$
+ * 
+ * @see 		HttpSession
+ * @see 		HttpSessionBindingListener
+ * @see			HttpSessionAttributeListener
+ */
+
+public class HttpSessionBindingEvent extends HttpSessionEvent {
+
+
+
+
+    /* The name to which the object is being bound or unbound */
+
+    private String name;
+    
+    /* The object is being bound or unbound */
+
+    private Object value;
+    
+  
+
+    /**
+     *
+     * Constructs an event that notifies an object that it
+     * has been bound to or unbound from a session. 
+     * To receive the event, the object must implement
+     * {@link HttpSessionBindingListener}.
+     *
+     *
+     *
+     * @param session 	the session to which the object is bound or unbound
+     *
+     * @param name 	the name with which the object is bound or unbound
+     *
+     * @see			#getName
+     * @see			#getSession
+     *
+     */
+
+    public HttpSessionBindingEvent(HttpSession session, String name) {
+	super(session);
+	this.name = name;
+    }
+    
+    /**
+     *
+     * Constructs an event that notifies an object that it
+     * has been bound to or unbound from a session. 
+     * To receive the event, the object must implement
+     * {@link HttpSessionBindingListener}.
+     *
+     *
+     *
+     * @param session 	the session to which the object is bound or unbound
+     *
+     * @param name 	the name with which the object is bound or unbound
+     *
+     * @see			#getName
+     * @see			#getSession
+     *
+     */
+    
+    public HttpSessionBindingEvent(HttpSession session, String name, Object value) {
+	super(session);
+	this.name = name;
+	this.value = value;
+    }
+    
+    
+   	/** Return the session that changed. */
+    public HttpSession getSession () { 
+	return super.getSession();
+    }
+ 
+   
+  
+    
+    /**
+     *
+     * Returns the name with which the attribute is bound to or
+     * unbound from the session.
+     *
+     *
+     * @return		a string specifying the name with which
+     *			the object is bound to or unbound from
+     *			the session
+     *
+     *
+     */
+
+    public String getName() {
+	return name;
+    }
+    
+    /**
+	* Returns the value of the attribute that has been added, removed or replaced.
+	* If the attribute was added (or bound), this is the value of the attribute. If the attribute was
+	* removed (or unbound), this is the value of the removed attribute. If the attribute was replaced, this
+	* is the old value of the attribute.
+	*
+        * @since 2.3
+	*/
+	
+	public Object getValue() {
+	    return this.value;   
+	}
+    
+}
+
+
+
+
+
+
+

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/http/HttpSessionBindingListener.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/http/HttpSessionBindingListener.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/http/HttpSessionBindingListener.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,77 @@
+/*
+* Copyright 2004 The Apache Software Foundation
+*
+* Licensed 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.util.EventListener;
+
+
+ 
+ 
+
+/**
+ * Causes an object to be notified when it is bound to
+ * or unbound from a session. The object is notified
+ * by an {@link HttpSessionBindingEvent} object. This may be as a result
+ * of a servlet programmer explicitly unbinding an attribute from a session,
+ * due to a session being invalidated, or due to a session timing out.
+ *
+ *
+ * @author		Various
+ * @version		$Version$
+ *
+ * @see HttpSession
+ * @see HttpSessionBindingEvent
+ *
+ */
+
+public interface HttpSessionBindingListener extends EventListener {
+
+
+
+    /**
+     *
+     * Notifies the object that it is being bound to
+     * a session and identifies the session.
+     *
+     * @param event		the event that identifies the
+     *				session 
+     *
+     * @see #valueUnbound
+     *
+     */ 
+
+    public void valueBound(HttpSessionBindingEvent event);
+    
+    
+
+    /**
+     *
+     * Notifies the object that it is being unbound
+     * from a session and identifies the session.
+     *
+     * @param event		the event that identifies
+     *				the session 
+     *	
+     * @see #valueBound
+     *
+     */
+
+    public void valueUnbound(HttpSessionBindingEvent event);
+    
+    
+}
+

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/http/HttpSessionContext.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/http/HttpSessionContext.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/http/HttpSessionContext.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,70 @@
+/*
+* Copyright 2004 The Apache Software Foundation
+*
+* Licensed 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.util.Enumeration;
+
+/**
+ *
+ * @author		Various
+ * @version		$Version$
+ *
+ * @deprecated		As of Java(tm) Servlet API 2.1
+ *			for security reasons, with no replacement.
+ *			This interface will be removed in a future
+ *			version of this API.
+ *
+ * @see			HttpSession
+ * @see			HttpSessionBindingEvent
+ * @see			HttpSessionBindingListener
+ *
+ */
+
+
+public interface HttpSessionContext {
+
+    /**
+     *
+     * @deprecated 	As of Java Servlet API 2.1 with
+     *			no replacement. This method must 
+     *			return null and will be removed in
+     *			a future version of this API.
+     *
+     */
+
+    public HttpSession getSession(String sessionId);
+    
+    
+    
+  
+    /**
+     *
+     * @deprecated	As of Java Servlet API 2.1 with
+     *			no replacement. This method must return 
+     *			an empty <code>Enumeration</code> and will be removed
+     *			in a future version of this API.
+     *
+     */
+
+    public Enumeration getIds();
+}
+
+
+
+
+

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/http/HttpSessionEvent.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/http/HttpSessionEvent.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/http/HttpSessionEvent.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,33 @@
+/*
+* Copyright 2004 The Apache Software Foundation
+*
+* Licensed 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;
+
+
+	/** This is the class representing event notifications for
+	* changes to sessions within a web application.
+	 * @since	v 2.3
+	*/
+public class HttpSessionEvent extends java.util.EventObject {
+	/** Construct a session event from the given source.*/
+	 public HttpSessionEvent(HttpSession source) {
+		super(source);
+}
+	/** Return the session that changed.*/
+    public HttpSession getSession () { 
+	return (HttpSession) super.getSource();
+    }
+}
+

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/http/HttpSessionListener.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/http/HttpSessionListener.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/http/HttpSessionListener.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,44 @@
+/*
+* Copyright 2004 The Apache Software Foundation
+*
+* Licensed 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.util.EventListener;
+
+	/** 
+	* Implementations of this interface are notified of changes to the 
+	* list of active sessions in a web application.
+	* To receive notification events, the implementation class
+	* must be configured in the deployment descriptor for the web application.
+	* @see HttpSessionEvent
+	 * @since	v 2.3
+	*/
+
+public interface HttpSessionListener extends EventListener {
+    
+	/** 
+	* Notification that a session was created.
+	* @param se the notification event
+	*/
+    public void sessionCreated ( HttpSessionEvent se );
+    
+	/** 
+	* Notification that a session is about to be invalidated.
+	* @param se the notification event
+	*/
+    public void sessionDestroyed ( HttpSessionEvent se );
+    
+}
+

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/http/HttpUtils.java
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/http/HttpUtils.java	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/http/HttpUtils.java	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,306 @@
+/*
+* Copyright 2004 The Apache Software Foundation
+*
+* Licensed 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 javax.servlet.ServletInputStream;
+import java.util.Hashtable;
+import java.util.ResourceBundle;
+import java.util.StringTokenizer;
+import java.io.IOException;
+
+/**
+ * @deprecated		As of Java(tm) Servlet API 2.3. 
+ *			These methods were only useful
+ *			with the default encoding and have been moved
+ *			to the request interfaces.
+ *
+*/
+
+
+public class HttpUtils {
+
+    private static final String LSTRING_FILE =
+	"javax.servlet.http.LocalStrings";
+    private static ResourceBundle lStrings =
+	ResourceBundle.getBundle(LSTRING_FILE);
+        
+    
+    
+    /**
+     * Constructs an empty <code>HttpUtils</code> object.
+     *
+     */
+
+    public HttpUtils() {}
+    
+    
+    
+    
+
+    /**
+     *
+     * Parses a query string passed from the client to the
+     * server and builds a <code>HashTable</code> object
+     * with key-value pairs. 
+     * The query string should be in the form of a string
+     * packaged by the GET or POST method, that is, it
+     * should have key-value pairs in the form <i>key=value</i>,
+     * with each pair separated from the next by a &amp; character.
+     *
+     * <p>A key can appear more than once in the query string
+     * with different values. However, the key appears only once in 
+     * the hashtable, with its value being
+     * an array of strings containing the multiple values sent
+     * by the query string.
+     * 
+     * <p>The keys and values in the hashtable are stored in their
+     * decoded form, so
+     * any + characters are converted to spaces, and characters
+     * sent in hexadecimal notation (like <i>%xx</i>) are
+     * converted to ASCII characters.
+     *
+     * @param s		a string containing the query to be parsed
+     *
+     * @return		a <code>HashTable</code> object built
+     * 			from the parsed key-value pairs
+     *
+     * @exception IllegalArgumentException	if the query string 
+     *						is invalid
+     *
+     */
+
+    static public Hashtable parseQueryString(String s) {
+
+	String valArray[] = null;
+	
+	if (s == null) {
+	    throw new IllegalArgumentException();
+	}
+	Hashtable ht = new Hashtable();
+	StringBuffer sb = new StringBuffer();
+	StringTokenizer st = new StringTokenizer(s, "&");
+	while (st.hasMoreTokens()) {
+	    String pair = (String)st.nextToken();
+	    int pos = pair.indexOf('=');
+	    if (pos == -1) {
+		// XXX
+		// should give more detail about the illegal argument
+		throw new IllegalArgumentException();
+	    }
+	    String key = parseName(pair.substring(0, pos), sb);
+	    String val = parseName(pair.substring(pos+1, pair.length()), sb);
+	    if (ht.containsKey(key)) {
+		String oldVals[] = (String []) ht.get(key);
+		valArray = new String[oldVals.length + 1];
+		for (int i = 0; i < oldVals.length; i++) 
+		    valArray[i] = oldVals[i];
+		valArray[oldVals.length] = val;
+	    } else {
+		valArray = new String[1];
+		valArray[0] = val;
+	    }
+	    ht.put(key, valArray);
+	}
+	return ht;
+    }
+
+
+
+
+    /**
+     *
+     * Parses data from an HTML form that the client sends to 
+     * the server using the HTTP POST method and the 
+     * <i>application/x-www-form-urlencoded</i> MIME type.
+     *
+     * <p>The data sent by the POST method contains key-value
+     * pairs. A key can appear more than once in the POST data
+     * with different values. However, the key appears only once in 
+     * the hashtable, with its value being
+     * an array of strings containing the multiple values sent
+     * by the POST method.
+     *
+     * <p>The keys and values in the hashtable are stored in their
+     * decoded form, so
+     * any + characters are converted to spaces, and characters
+     * sent in hexadecimal notation (like <i>%xx</i>) are
+     * converted to ASCII characters.
+     *
+     *
+     *
+     * @param len	an integer specifying the length,
+     *			in characters, of the 
+     *			<code>ServletInputStream</code>
+     *			object that is also passed to this
+     *			method
+     *
+     * @param in	the <code>ServletInputStream</code>
+     *			object that contains the data sent
+     *			from the client
+     * 
+     * @return		a <code>HashTable</code> object built
+     *			from the parsed key-value pairs
+     *
+     *
+     * @exception IllegalArgumentException	if the data
+     *			sent by the POST method is invalid
+     *
+     */
+     
+
+    static public Hashtable parsePostData(int len, 
+					  ServletInputStream in)
+    {
+	// XXX
+	// should a length of 0 be an IllegalArgumentException
+	
+	if (len <=0)
+	    return new Hashtable(); // cheap hack to return an empty hash
+
+	if (in == null) {
+	    throw new IllegalArgumentException();
+	}
+	
+	//
+	// Make sure we read the entire POSTed body.
+	//
+        byte[] postedBytes = new byte [len];
+        try {
+            int offset = 0;
+       
+	    do {
+		int inputLen = in.read (postedBytes, offset, len - offset);
+		if (inputLen <= 0) {
+		    String msg = lStrings.getString("err.io.short_read");
+		    throw new IllegalArgumentException (msg);
+		}
+		offset += inputLen;
+	    } while ((len - offset) > 0);
+
+	} catch (IOException e) {
+	    throw new IllegalArgumentException(e.getMessage());
+	}
+
+        // XXX we shouldn't assume that the only kind of POST body
+        // is FORM data encoded using ASCII or ISO Latin/1 ... or
+        // that the body should always be treated as FORM data.
+        //
+
+        try {
+            String postedBody = new String(postedBytes, 0, len, "8859_1");
+            return parseQueryString(postedBody);
+        } catch (java.io.UnsupportedEncodingException e) {
+            // XXX function should accept an encoding parameter & throw this
+            // exception.  Otherwise throw something expected.
+            throw new IllegalArgumentException(e.getMessage());
+        }
+    }
+
+
+
+
+    /*
+     * Parse a name in the query string.
+     */
+
+    static private String parseName(String s, StringBuffer sb) {
+	sb.setLength(0);
+	for (int i = 0; i < s.length(); i++) {
+	    char c = s.charAt(i); 
+	    switch (c) {
+	    case '+':
+		sb.append(' ');
+		break;
+	    case '%':
+		try {
+		    sb.append((char) Integer.parseInt(s.substring(i+1, i+3), 
+						      16));
+		    i += 2;
+		} catch (NumberFormatException e) {
+		    // XXX
+		    // need to be more specific about illegal arg
+		    throw new IllegalArgumentException();
+		} catch (StringIndexOutOfBoundsException e) {
+		    String rest  = s.substring(i);
+		    sb.append(rest);
+		    if (rest.length()==2)
+			i++;
+		}
+		
+		break;
+	    default:
+		sb.append(c);
+		break;
+	    }
+	}
+	return sb.toString();
+    }
+
+
+
+
+    /**
+     *
+     * Reconstructs the URL the client used to make the request,
+     * using information in the <code>HttpServletRequest</code> object.
+     * The returned URL contains a protocol, server name, port
+     * number, and server path, but it does not include query
+     * string parameters.
+     * 
+     * <p>Because this method returns a <code>StringBuffer</code>,
+     * not a string, you can modify the URL easily, for example,
+     * to append query parameters.
+     *
+     * <p>This method is useful for creating redirect messages
+     * and for reporting errors.
+     *
+     * @param req	a <code>HttpServletRequest</code> object
+     *			containing the client's request
+     * 
+     * @return		a <code>StringBuffer</code> object containing
+     *			the reconstructed URL
+     *
+     */
+
+    public static StringBuffer getRequestURL (HttpServletRequest req) {
+	StringBuffer url = new StringBuffer ();
+	String scheme = req.getScheme ();
+	int port = req.getServerPort ();
+	String urlPath = req.getRequestURI();
+	
+	//String		servletPath = req.getServletPath ();
+	//String		pathInfo = req.getPathInfo ();
+
+	url.append (scheme);		// http, https
+	url.append ("://");
+	url.append (req.getServerName ());
+	if ((scheme.equals ("http") && port != 80)
+		|| (scheme.equals ("https") && port != 443)) {
+	    url.append (':');
+	    url.append (req.getServerPort ());
+	}
+	//if (servletPath != null)
+	//    url.append (servletPath);
+	//if (pathInfo != null)
+	//    url.append (pathInfo);
+	url.append(urlPath);
+	return url;
+    }
+}
+
+
+

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/http/LocalStrings.properties
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/http/LocalStrings.properties	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/http/LocalStrings.properties	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,27 @@
+# Copyright 2004 The Apache Software Foundation
+#
+# Licensed 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.
+
+# Default localized string information
+# Localized for Locale en_US
+
+err.cookie_name_is_token=Cookie name \"{0}\" is a reserved token
+err.io.negativelength=Negative Length given in write method
+err.io.short_read=Short Read
+
+http.method_not_implemented=Method {0} is not defined in RFC 2068 and is not supported by the Servlet API 
+
+http.method_get_not_supported=HTTP method GET is not supported by this URL
+http.method_post_not_supported=HTTP method POST is not supported by this URL
+http.method_put_not_supported=HTTP method PUT is not supported by this URL
+http.method_delete_not_supported=Http method DELETE is not supported by this URL

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/http/LocalStrings_es.properties
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/http/LocalStrings_es.properties	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/http/LocalStrings_es.properties	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,29 @@
+# Copyright 2004 The Apache Software Foundation
+#
+# Licensed 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.
+
+# $Id: LocalStrings_es.properties 267129 2004-03-18 16:40:35Z jfarcand $
+#
+# Default localized string information
+# Localized para Locale es_ES
+
+err.cookie_name_is_token=El Nombre de Cookie {0} es una palabra reservada
+err.io.negativelength=Longitud Negativa en el metodo write
+err.io.short_read=Lectura Corta
+
+http.method_not_implemented=El Metodo {0} no esta definido en la especificacion RFC 2068 y no es soportado por la API Servlet 
+
+http.method_get_not_supported=El Metodo HTTP GET no es soportado por esta URL
+http.method_post_not_supported=El Metodo HTTP POST no es soportado por esta URL
+http.method_put_not_supported=El Metodo HTTP PUT no es soportado por esta URL
+http.method_delete_not_supported=El Metodo HTTP DELETE no es soportado por esta URL

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/http/LocalStrings_fr.properties
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/http/LocalStrings_fr.properties	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/http/LocalStrings_fr.properties	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,27 @@
+# Copyright 2004 The Apache Software Foundation
+#
+# Licensed 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.
+
+# Default localized string information
+# Localized for Locale fr_FR
+
+err.cookie_name_is_token=Le nom de cookie \"{0}\" est un \"token\" réservé
+err.io.negativelength=Taille négative donnée dans la méthode \"write\"
+err.io.short_read=Lecture partielle
+
+http.method_not_implemented=Le méthode {0} n''est pas définie dans la RFC 2068 et n''est pas supportée par l''API Servlet
+
+http.method_get_not_supported=La méthode HTTP GET n''est pas supportée par cette URL
+http.method_post_not_supported=La méthode HTTP POST n''est pas supportée par cette URL
+http.method_put_not_supported=La méthode HTTP PUT n''est pas supportée par cette URL
+http.method_delete_not_supported=La méthode HTTP DELETE n''est pas supportée par cette URL 

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/http/LocalStrings_ja.properties
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/http/LocalStrings_ja.properties	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/http/LocalStrings_ja.properties	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,27 @@
+# Copyright 2004 The Apache Software Foundation
+#
+# Licensed 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.
+
+# Default localized string information
+# Localized for Locale ja_JP
+
+err.cookie_name_is_token=\u30af\u30c3\u30ad\u30fc\u540d \"{0}\" \u306f\u4e88\u7d04\u6e08\u306e\u30c8\u30fc\u30af\u30f3\u3067\u3059\u3002
+err.io.negativelength=write\u30e1\u30bd\u30c3\u30c9\u306b\u8ca0\u306e\u9577\u3055\u304c\u6307\u5b9a\u3055\u308c\u307e\u3057\u305f\u3002
+err.io.short_read=\u8aad\u307f\u8fbc\u307f\u304c\u3059\u3050\u306b\u7d42\u308f\u308a\u307e\u3057\u305f\u3002
+
+http.method_not_implemented=\u30e1\u30bd\u30c3\u30c9 {0} \u306fRFC 2068\u306b\u306f\u5b9a\u7fa9\u3055\u308c\u3066\u304a\u3089\u305a\u3001\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8API\u3067\u306f\u30b5\u30dd\u30fc\u30c8\u3055\u308c\u307e\u305b\u3093\u3002
+
+http.method_get_not_supported=HTTP\u306eGET\u30e1\u30bd\u30c3\u30c9\u306f\u3001\u3053\u306eURL\u3067\u306f\u30b5\u30dd\u30fc\u30c8\u3055\u308c\u3066\u3044\u307e\u305b\u3093\u3002
+http.method_post_not_supported=HTTP\u306ePOST\u30e1\u30bd\u30c3\u30c9\u306f\u3001\u3053\u306eURL\u3067\u306f\u30b5\u30dd\u30fc\u30c8\u3055\u308c\u3066\u3044\u307e\u305b\u3093\u3002
+http.method_put_not_supported=HTTP\u306ePUT\u30e1\u30bd\u30c3\u30c9\u306f\u3001\u3053\u306eURL\u3067\u306f\u30b5\u30dd\u30fc\u30c8\u3055\u308c\u3066\u3044\u307e\u305b\u3093\u3002
+http.method_delete_not_supported=HTTP\u306eDELETE\u30e1\u30bd\u30c3\u30c9\u306f\u3001\u3053\u306eURL\u3067\u306f\u30b5\u30dd\u30fc\u30c8\u3055\u308c\u3066\u3044\u307e\u305b\u3093\u3002

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/http/package.html
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/http/package.html	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/http/package.html	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,23 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<HTML>
+<HEAD>
+<!--
+
+  Copyright 2001 Sun Microsystems, Inc. All Rights Reserved.
+
+  This software is the proprietary information of Sun Microsystems, Inc.  
+  Use is subject to license terms.
+
+-->
+
+</HEAD>
+<BODY BGCOLOR="white">
+
+The javax.servlet.http package contains a number of classes and interfaces
+that describe and define the contracts between a servlet class
+running under the HTTP protocol and the runtime environment provided
+for an instance of such a class by a conforming servlet container.
+
+
+</BODY>
+</HTML>

Added: branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/package.html
===================================================================
--- branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/package.html	2006-11-12 10:26:35 UTC (rev 2738)
+++ branches/tomcat5.5/upstream/5.5.20/servletapi/jsr154/src/share/javax/servlet/package.html	2006-11-14 14:47:19 UTC (rev 2739)
@@ -0,0 +1,23 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<HTML>
+<HEAD>
+<!--
+
+  Copyright 2001 Sun Microsystems, Inc. All Rights Reserved.
+
+  This software is the proprietary information of Sun Microsystems, Inc.  
+  Use is subject to license terms.
+
+-->
+
+</HEAD>
+<BODY BGCOLOR="white">
+
+The javax.servlet package contains a number of classes and interfaces that
+describe and define the contracts between a servlet class and the
+runtime environment provided for an instance of such a class by a
+conforming servlet container.
+
+
+</BODY>
+</HTML>




More information about the pkg-java-commits mailing list